diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3ade2f3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,43 @@ + SOURCE 1 SDK LICENSE + +Source SDK Copyright(c) Valve Corp. + +THIS DOCUMENT DESCRIBES A CONTRACT BETWEEN YOU AND VALVE +CORPORATION ("Valve"). PLEASE READ IT BEFORE DOWNLOADING OR USING +THE SOURCE ENGINE SDK ("SDK"). BY DOWNLOADING AND/OR USING THE +SOURCE ENGINE SDK YOU ACCEPT THIS LICENSE. IF YOU DO NOT AGREE TO +THE TERMS OF THIS LICENSE PLEASE DONT DOWNLOAD OR USE THE SDK. + + You may, free of charge, download and use the SDK to develop a modified Valve game +running on the Source engine. You may distribute your modified Valve game in source and +object code form, but only for free. Terms of use for Valve games are found in the Steam +Subscriber Agreement located here: http://store.steampowered.com/subscriber_agreement/ + + You may copy, modify, and distribute the SDK and any modifications you make to the +SDK in source and object code form, but only for free. Any distribution of this SDK must +include this LICENSE file and thirdpartylegalnotices.txt. + + Any distribution of the SDK or a substantial portion of the SDK must include the above +copyright notice and the following: + + DISCLAIMER OF WARRANTIES. THE SOURCE SDK AND ANY + OTHER MATERIAL DOWNLOADED BY LICENSEE IS PROVIDED + "AS IS". VALVE AND ITS SUPPLIERS DISCLAIM ALL + WARRANTIES WITH RESPECT TO THE SDK, EITHER EXPRESS + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED + WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, + TITLE AND FITNESS FOR A PARTICULAR PURPOSE. + + LIMITATION OF LIABILITY. IN NO EVENT SHALL VALVE OR + ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER + (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF + BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF + BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) + ARISING OUT OF THE USE OF OR INABILITY TO USE THE + ENGINE AND/OR THE SDK, EVEN IF VALVE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + +If you would like to use the SDK for a commercial purpose, please contact Valve at +sourceengine@valvesoftware.com. diff --git a/common/GameUI/IGameUI.h b/common/GameUI/IGameUI.h new file mode 100644 index 0000000..99967f4 --- /dev/null +++ b/common/GameUI/IGameUI.h @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IGAMEUI_H +#define IGAMEUI_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "vgui/IPanel.h" + +#if !defined( _X360 ) +#include "xbox/xboxstubs.h" +#endif + +// reasons why the user can't connect to a game server +enum ESteamLoginFailure +{ + STEAMLOGINFAILURE_NONE, + STEAMLOGINFAILURE_BADTICKET, + STEAMLOGINFAILURE_NOSTEAMLOGIN, + STEAMLOGINFAILURE_VACBANNED, + STEAMLOGINFAILURE_LOGGED_IN_ELSEWHERE +}; + +enum ESystemNotify +{ + SYSTEMNOTIFY_STORAGEDEVICES_CHANGED, + SYSTEMNOTIFY_USER_SIGNEDIN, + SYSTEMNOTIFY_USER_SIGNEDOUT, + SYSTEMNOTIFY_XUIOPENING, + SYSTEMNOTIFY_XUICLOSED, + SYSTEMNOTIFY_INVITE_SHUTDOWN, // Cross-game invite is causing us to shutdown +}; + +//----------------------------------------------------------------------------- +// Purpose: contains all the functions that the GameUI dll exports +//----------------------------------------------------------------------------- +abstract_class IGameUI +{ +public: + // initialization/shutdown + virtual void Initialize( CreateInterfaceFn appFactory ) = 0; + virtual void PostInit() = 0; + + // connect to other interfaces at the same level (gameui.dll/server.dll/client.dll) + virtual void Connect( CreateInterfaceFn gameFactory ) = 0; + + virtual void Start() = 0; + virtual void Shutdown() = 0; + virtual void RunFrame() = 0; + + // notifications + virtual void OnGameUIActivated() = 0; + virtual void OnGameUIHidden() = 0; + + // OLD: Use OnConnectToServer2 + virtual void OLD_OnConnectToServer(const char *game, int IP, int port) = 0; + + virtual void OnDisconnectFromServer_OLD( uint8 eSteamLoginFailure, const char *username ) = 0; + virtual void OnLevelLoadingStarted(bool bShowProgressDialog) = 0; + virtual void OnLevelLoadingFinished(bool bError, const char *failureReason, const char *extendedReason) = 0; + + // level loading progress, returns true if the screen needs updating + virtual bool UpdateProgressBar(float progress, const char *statusText) = 0; + // Shows progress desc, returns previous setting... (used with custom progress bars ) + virtual bool SetShowProgressText( bool show ) = 0; + + // !!!!!!!!!members added after "GameUI011" initial release!!!!!!!!!!!!!!!!!!! + virtual void ShowNewGameDialog( int chapter ) = 0; + + // Xbox 360 + virtual void SessionNotification( const int notification, const int param = 0 ) = 0; + virtual void SystemNotification( const int notification ) = 0; + virtual void ShowMessageDialog( const uint nType, vgui::Panel *pOwner ) = 0; + virtual void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost ) = 0; + virtual void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping ) = 0; + virtual void OnCreditsFinished( void ) = 0; + + // inserts specified panel as background for level load dialog + virtual void SetLoadingBackgroundDialog( vgui::VPANEL panel ) = 0; + + // Bonus maps interfaces + virtual void BonusMapUnlock( const char *pchFileName = NULL, const char *pchMapName = NULL ) = 0; + virtual void BonusMapComplete( const char *pchFileName = NULL, const char *pchMapName = NULL ) = 0; + virtual void BonusMapChallengeUpdate( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest ) = 0; + virtual void BonusMapChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName ) = 0; + virtual void BonusMapChallengeObjectives( int &iBronze, int &iSilver, int &iGold ) = 0; + virtual void BonusMapDatabaseSave( void ) = 0; + virtual int BonusMapNumAdvancedCompleted( void ) = 0; + virtual void BonusMapNumMedals( int piNumMedals[ 3 ] ) = 0; + + virtual void OnConnectToServer2(const char *game, int IP, int connectionPort, int queryPort) = 0; + + // X360 Storage device validation: + // returns true right away if storage device has been previously selected. + // otherwise returns false and will set the variable pointed by pStorageDeviceValidated to 1 + // once the storage device is selected by user. + virtual bool ValidateStorageDevice( int *pStorageDeviceValidated ) = 0; + + virtual void SetProgressOnStart() = 0; + virtual void OnDisconnectFromServer( uint8 eSteamLoginFailure ) = 0; + + virtual void OnConfirmQuit( void ) = 0; + + virtual bool IsMainMenuVisible( void ) = 0; + + // Client DLL is providing us with a panel that it wants to replace the main menu with + virtual void SetMainMenuOverride( vgui::VPANEL panel ) = 0; + // Client DLL is telling us that a main menu command was issued, probably from its custom main menu panel + virtual void SendMainMenuCommand( const char *pszCommand ) = 0; +}; + +#define GAMEUI_INTERFACE_VERSION "GameUI011" + +#endif // IGAMEUI_H diff --git a/common/SteamCommon.h b/common/SteamCommon.h new file mode 100644 index 0000000..fee2887 --- /dev/null +++ b/common/SteamCommon.h @@ -0,0 +1,703 @@ + +//========= Copyright Valve Corporation, All rights reserved. ============// +/* +** The copyright to the contents herein is the property of Valve Corporation. +** The contents may be used and/or copied only with the written permission of +** Valve, or in accordance with the terms and conditions stipulated in +** the agreement/contract under which the contents have been supplied. +** +******************************************************************************* +** +** Contents: +** +** Common types used in the Steam DLL interface. +** +** This file is distributed to Steam application developers. +** +** +** +*******************************************************************************/ + +#ifndef INCLUDED_STEAM_COMMON_STEAMCOMMON_H +#define INCLUDED_STEAM_COMMON_STEAMCOMMON_H + +#if defined(_MSC_VER) && (_MSC_VER > 1000) +#pragma once +#endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Applications should not define STEAM_EXPORTS. */ + +#if defined ( _WIN32 ) + +#ifdef STEAM_EXPORTS +#define STEAM_API __declspec(dllexport) +#else +#define STEAM_API __declspec(dllimport) +#endif + +#define STEAM_CALL __cdecl + +#else + +#define STEAM_API /* */ +#define STEAM_CALL /* */ + +#endif + +typedef void (STEAM_CALL *KeyValueIteratorCallback_t )(const char *Key, const char *Val, void *pvParam); + + +/****************************************************************************** +** +** Exported macros and constants +** +******************************************************************************/ + +/* DEPRECATED -- these are ignored now, all API access is granted on SteamStartup */ +#define STEAM_USING_FILESYSTEM (0x00000001) +#define STEAM_USING_LOGGING (0x00000002) +#define STEAM_USING_USERID (0x00000004) +#define STEAM_USING_ACCOUNT (0x00000008) +#define STEAM_USING_ALL (0x0000000f) +/* END DEPRECATED */ + +#define STEAM_MAX_PATH (255) +#define STEAM_QUESTION_MAXLEN (255) +#define STEAM_SALT_SIZE (8) +#define STEAM_PROGRESS_PERCENT_SCALE (0x00001000) + +/* These are maximum significant string lengths, excluding nul-terminator. */ +#define STEAM_CARD_NUMBER_SIZE (17) +#define STEAM_CARD_HOLDERNAME_SIZE (100) +#define STEAM_CARD_EXPYEAR_SIZE (4) +#define STEAM_CARD_EXPMONTH_SIZE (2) +#define STEAM_CARD_CVV2_SIZE (5) +#define STEAM_BILLING_ADDRESS1_SIZE (128) +#define STEAM_BILLING_ADDRESS2_SIZE (128) +#define STEAM_BILLING_CITY_SIZE (50) +#define STEAM_BILLING_ZIP_SIZE (16) +#define STEAM_BILLING_STATE_SIZE (32) +#define STEAM_BILLING_COUNTRY_SIZE (32) +#define STEAM_BILLING_PHONE_SIZE (20) +#define STEAM_BILLING_EMAIL_ADDRESS_SIZE (100) +#define STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE (20) +#define STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE (200) +#define STEAM_EXTERNAL_ACCOUNTNAME_SIZE (100) +#define STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE (80) +#define STEAM_BILLING_CONFIRMATION_CODE_SIZE (22) +#define STEAM_BILLING_CARD_APPROVAL_CODE_SIZE (100) +#define STEAM_BILLING_TRANS_DATE_SIZE (9) // mm/dd/yy +#define STEAM_BILLING_TRANS_TIME_SIZE (9) // hh:mm:ss + +/****************************************************************************** +** +** Scalar type and enumerated type definitions. +** +******************************************************************************/ + + +typedef unsigned int SteamHandle_t; + +typedef void * SteamUserIDTicketValidationHandle_t; + +typedef unsigned int SteamCallHandle_t; + +#if defined(_MSC_VER) +typedef unsigned __int64 SteamUnsigned64_t; +#else +typedef unsigned long long SteamUnsigned64_t; +#endif + +typedef enum +{ + eSteamSeekMethodSet = 0, + eSteamSeekMethodCur = 1, + eSteamSeekMethodEnd = 2 +} ESteamSeekMethod; + +typedef enum +{ + eSteamBufferMethodFBF = 0, + eSteamBufferMethodNBF = 1 +} ESteamBufferMethod; + +typedef enum +{ + eSteamErrorNone = 0, + eSteamErrorUnknown = 1, + eSteamErrorLibraryNotInitialized = 2, + eSteamErrorLibraryAlreadyInitialized = 3, + eSteamErrorConfig = 4, + eSteamErrorContentServerConnect = 5, + eSteamErrorBadHandle = 6, + eSteamErrorHandlesExhausted = 7, + eSteamErrorBadArg = 8, + eSteamErrorNotFound = 9, + eSteamErrorRead = 10, + eSteamErrorEOF = 11, + eSteamErrorSeek = 12, + eSteamErrorCannotWriteNonUserConfigFile = 13, + eSteamErrorCacheOpen = 14, + eSteamErrorCacheRead = 15, + eSteamErrorCacheCorrupted = 16, + eSteamErrorCacheWrite = 17, + eSteamErrorCacheSession = 18, + eSteamErrorCacheInternal = 19, + eSteamErrorCacheBadApp = 20, + eSteamErrorCacheVersion = 21, + eSteamErrorCacheBadFingerPrint = 22, + + eSteamErrorNotFinishedProcessing = 23, + eSteamErrorNothingToDo = 24, + eSteamErrorCorruptEncryptedUserIDTicket = 25, + eSteamErrorSocketLibraryNotInitialized = 26, + eSteamErrorFailedToConnectToUserIDTicketValidationServer = 27, + eSteamErrorBadProtocolVersion = 28, + eSteamErrorReplayedUserIDTicketFromClient = 29, + eSteamErrorReceiveResultBufferTooSmall = 30, + eSteamErrorSendFailed = 31, + eSteamErrorReceiveFailed = 32, + eSteamErrorReplayedReplyFromUserIDTicketValidationServer = 33, + eSteamErrorBadSignatureFromUserIDTicketValidationServer = 34, + eSteamErrorValidationStalledSoAborted = 35, + eSteamErrorInvalidUserIDTicket = 36, + eSteamErrorClientLoginRateTooHigh = 37, + eSteamErrorClientWasNeverValidated = 38, + eSteamErrorInternalSendBufferTooSmall = 39, + eSteamErrorInternalReceiveBufferTooSmall = 40, + eSteamErrorUserTicketExpired = 41, + eSteamErrorCDKeyAlreadyInUseOnAnotherClient = 42, + + eSteamErrorNotLoggedIn = 101, + eSteamErrorAlreadyExists = 102, + eSteamErrorAlreadySubscribed = 103, + eSteamErrorNotSubscribed = 104, + eSteamErrorAccessDenied = 105, + eSteamErrorFailedToCreateCacheFile = 106, + eSteamErrorCallStalledSoAborted = 107, + eSteamErrorEngineNotRunning = 108, + eSteamErrorEngineConnectionLost = 109, + eSteamErrorLoginFailed = 110, + eSteamErrorAccountPending = 111, + eSteamErrorCacheWasMissingRetry = 112, + eSteamErrorLocalTimeIncorrect = 113, + eSteamErrorCacheNeedsDecryption = 114, + eSteamErrorAccountDisabled = 115, + eSteamErrorCacheNeedsRepair = 116, + eSteamErrorRebootRequired = 117, + + eSteamErrorNetwork = 200, + eSteamErrorOffline = 201 + + +} ESteamError; + + +typedef enum +{ + eNoDetailedErrorAvailable, + eStandardCerrno, + eWin32LastError, + eWinSockLastError, + eDetailedPlatformErrorCount +} EDetailedPlatformErrorType; + +typedef enum /* Filter elements returned by SteamFind{First,Next} */ +{ + eSteamFindLocalOnly, /* limit search to local filesystem */ + eSteamFindRemoteOnly, /* limit search to remote repository */ + eSteamFindAll /* do not limit search (duplicates allowed) */ +} ESteamFindFilter; + + +/****************************************************************************** +** +** Exported structure and complex type definitions. +** +******************************************************************************/ + + +typedef struct +{ + ESteamError eSteamError; + EDetailedPlatformErrorType eDetailedErrorType; + int nDetailedErrorCode; + char szDesc[STEAM_MAX_PATH]; +} TSteamError; + + + +typedef struct +{ + int bIsDir; /* If non-zero, element is a directory; if zero, element is a file */ + unsigned int uSizeOrCount; /* If element is a file, this contains size of file in bytes */ + int bIsLocal; /* If non-zero, reported item is a standalone element on local filesystem */ + char cszName[STEAM_MAX_PATH]; /* Base element name (no path) */ + long lLastAccessTime; /* Seconds since 1/1/1970 (like time_t) when element was last accessed */ + long lLastModificationTime; /* Seconds since 1/1/1970 (like time_t) when element was last modified */ + long lCreationTime; /* Seconds since 1/1/1970 (like time_t) when element was created */ +} TSteamElemInfo; + + +typedef struct +{ + unsigned int uNumSubscriptions; + unsigned int uMaxNameChars; + unsigned int uMaxApps; + +} TSteamSubscriptionStats; + + +typedef struct +{ + unsigned int uNumApps; + unsigned int uMaxNameChars; + unsigned int uMaxInstallDirNameChars; + unsigned int uMaxVersionLabelChars; + unsigned int uMaxLaunchOptions; + unsigned int uMaxLaunchOptionDescChars; + unsigned int uMaxLaunchOptionCmdLineChars; + unsigned int uMaxNumIcons; + unsigned int uMaxIconSize; + unsigned int uMaxDependencies; + +} TSteamAppStats; + +typedef struct +{ + char *szLabel; + unsigned int uMaxLabelChars; + unsigned int uVersionId; + int bIsNotAvailable; +} TSteamAppVersion; + +typedef struct +{ + char *szDesc; + unsigned int uMaxDescChars; + char *szCmdLine; + unsigned int uMaxCmdLineChars; + unsigned int uIndex; + unsigned int uIconIndex; + int bNoDesktopShortcut; + int bNoStartMenuShortcut; + int bIsLongRunningUnattended; + +} TSteamAppLaunchOption; + + +typedef struct +{ + char *szName; + unsigned int uMaxNameChars; + char *szLatestVersionLabel; + unsigned int uMaxLatestVersionLabelChars; + char *szCurrentVersionLabel; + unsigned int uMaxCurrentVersionLabelChars; + char *szInstallDirName; + unsigned int uMaxInstallDirNameChars; + unsigned int uId; + unsigned int uLatestVersionId; + unsigned int uCurrentVersionId; + unsigned int uMinCacheFileSizeMB; + unsigned int uMaxCacheFileSizeMB; + unsigned int uNumLaunchOptions; + unsigned int uNumIcons; + unsigned int uNumVersions; + unsigned int uNumDependencies; + +} TSteamApp; + +typedef enum +{ + eNoCost = 0, + eBillOnceOnly = 1, + eBillMonthly = 2, + eProofOfPrepurchaseOnly = 3, + eGuestPass = 4, + eHardwarePromo = 5, + eNumBillingTypes, +} EBillingType; + +typedef struct +{ + char *szName; + unsigned int uMaxNameChars; + unsigned int *puAppIds; + unsigned int uMaxAppIds; + unsigned int uId; + unsigned int uNumApps; + EBillingType eBillingType; + unsigned int uCostInCents; + unsigned int uNumDiscounts; + int bIsPreorder; + int bRequiresShippingAddress; + unsigned int uDomesticShippingCostInCents; + unsigned int uInternationalShippingCostInCents; + bool bIsCyberCafeSubscription; + unsigned int uGameCode; + char szGameCodeDesc[STEAM_MAX_PATH]; + bool bIsDisabled; + bool bRequiresCD; + unsigned int uTerritoryCode; + bool bIsSteam3Subscription; + +} TSteamSubscription; + +typedef struct +{ + char szName[STEAM_MAX_PATH]; + unsigned int uDiscountInCents; + unsigned int uNumQualifiers; + +} TSteamSubscriptionDiscount; + +typedef struct +{ + char szName[STEAM_MAX_PATH]; + unsigned int uRequiredSubscription; + int bIsDisqualifier; + +} TSteamDiscountQualifier; + +typedef struct TSteamProgress +{ + int bValid; /* non-zero if call provides progress info */ + unsigned int uPercentDone; /* 0 to 100 * STEAM_PROGRESS_PERCENT_SCALE if bValid */ + char szProgress[STEAM_MAX_PATH]; /* additional progress info */ +} TSteamProgress; + +typedef enum +{ + eSteamNotifyTicketsWillExpire, + eSteamNotifyAccountInfoChanged, + eSteamNotifyContentDescriptionChanged, + eSteamNotifyPleaseShutdown, + eSteamNotifyNewContentServer, + eSteamNotifySubscriptionStatusChanged, + eSteamNotifyContentServerConnectionLost, + eSteamNotifyCacheLoadingCompleted, + eSteamNotifyCacheNeedsDecryption, + eSteamNotifyCacheNeedsRepair +} ESteamNotificationCallbackEvent; + + +typedef void(*SteamNotificationCallback_t)(ESteamNotificationCallbackEvent eEvent, unsigned int nData); + + +typedef char SteamPersonalQuestion_t[ STEAM_QUESTION_MAXLEN + 1 ]; + +typedef struct +{ + unsigned char uchSalt[STEAM_SALT_SIZE]; +} SteamSalt_t; + +typedef enum +{ + eVisa = 1, + eMaster = 2, + eAmericanExpress = 3, + eDiscover = 4, + eDinnersClub = 5, + eJCB = 6 +} ESteamPaymentCardType; + +typedef struct +{ + ESteamPaymentCardType eCardType; + char szCardNumber[ STEAM_CARD_NUMBER_SIZE +1 ]; + char szCardHolderName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szCardExpYear[ STEAM_CARD_EXPYEAR_SIZE + 1 ]; + char szCardExpMonth[ STEAM_CARD_EXPMONTH_SIZE+ 1 ]; + char szCardCVV2[ STEAM_CARD_CVV2_SIZE + 1 ]; + char szBillingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szBillingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szBillingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szBillingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szBillingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szBillingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + char szBillingPhone[ STEAM_BILLING_PHONE_SIZE + 1 ]; + char szBillingEmailAddress[ STEAM_BILLING_EMAIL_ADDRESS_SIZE + 1 ]; + unsigned int uExpectedCostInCents; + unsigned int uExpectedTaxInCents; + /* If the TSteamSubscription says that shipping info is required, */ + /* then the following fields must be filled out. */ + /* If szShippingName is empty, then assumes so are the rest. */ + char szShippingName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szShippingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szShippingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szShippingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szShippingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szShippingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szShippingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + char szShippingPhone[ STEAM_BILLING_PHONE_SIZE + 1 ]; + unsigned int uExpectedShippingCostInCents; + +} TSteamPaymentCardInfo; + +typedef struct +{ + char szTypeOfProofOfPurchase[ STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1 ]; + + /* A ProofOfPurchase token is not necessarily a nul-terminated string; it may be binary data + (perhaps encrypted). Hence we need a length and an array of bytes. */ + unsigned int uLengthOfBinaryProofOfPurchaseToken; + char cBinaryProofOfPurchaseToken[ STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE + 1 ]; +} TSteamPrepurchaseInfo; + +typedef struct +{ + char szAccountName[ STEAM_EXTERNAL_ACCOUNTNAME_SIZE + 1 ]; + char szPassword[ STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE + 1 ]; +} TSteamExternalBillingInfo; + +typedef enum +{ + ePaymentCardInfo = 1, + ePrepurchasedInfo = 2, + eAccountBillingInfo = 3, + eExternalBillingInfo = 4, /* indirect billing via ISP etc (not supported yet) */ + ePaymentCardReceipt = 5, + ePrepurchaseReceipt = 6, + eEmptyReceipt = 7 +} ESteamSubscriptionBillingInfoType; + +typedef struct +{ + ESteamSubscriptionBillingInfoType eBillingInfoType; + union { + TSteamPaymentCardInfo PaymentCardInfo; + TSteamPrepurchaseInfo PrepurchaseInfo; + TSteamExternalBillingInfo ExternalBillingInfo; + char bUseAccountBillingInfo; + }; + +} TSteamSubscriptionBillingInfo; + +typedef enum +{ + /* Subscribed */ + eSteamSubscriptionOK = 0, /* Subscribed */ + eSteamSubscriptionPending = 1, /* Awaiting transaction completion */ + eSteamSubscriptionPreorder = 2, /* Is currently a pre-order */ + eSteamSubscriptionPrepurchaseTransferred = 3, /* hop to this account */ + /* Unusbscribed */ + eSteamSubscriptionPrepurchaseInvalid = 4, /* Invalid cd-key */ + eSteamSubscriptionPrepurchaseRejected = 5, /* hopped out / banned / etc */ + eSteamSubscriptionPrepurchaseRevoked = 6, /* hop away from this account */ + eSteamSubscriptionPaymentCardDeclined = 7, /* CC txn declined */ + eSteamSubscriptionCancelledByUser = 8, /* Cancelled by client */ + eSteamSubscriptionCancelledByVendor = 9, /* Cancelled by us */ + eSteamSubscriptionPaymentCardUseLimit = 10, /* Card used too many times, potential fraud */ + eSteamSubscriptionPaymentCardAlert = 11, /* Got a "pick up card" or the like from bank */ + eSteamSubscriptionFailed = 12, /* Other Error in subscription data or transaction failed/lost */ + eSteamSubscriptionPaymentCardAVSFailure = 13, /* Card failed Address Verification check */ + eSteamSubscriptionPaymentCardInsufficientFunds = 14, /* Card failed due to insufficient funds */ + eSteamSubscriptionRestrictedCountry = 15 /* The subscription is not available in the user's country */ + +} ESteamSubscriptionStatus; + +typedef struct +{ + ESteamPaymentCardType eCardType; + char szCardLastFourDigits[ 4 + 1 ]; + char szCardHolderName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szBillingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szBillingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szBillingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szBillingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szBillingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szBillingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + + // The following are only available after the subscription leaves "pending" status + char szCardApprovalCode[ STEAM_BILLING_CARD_APPROVAL_CODE_SIZE + 1]; + char szTransDate[ STEAM_BILLING_TRANS_DATE_SIZE + 1]; /* mm/dd/yy */ + char szTransTime[ STEAM_BILLING_TRANS_TIME_SIZE + 1]; /* hh:mm:ss */ + unsigned int uPriceWithoutTax; + unsigned int uTaxAmount; + unsigned int uShippingCost; + +} TSteamPaymentCardReceiptInfo; + +typedef struct +{ + char szTypeOfProofOfPurchase[ STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1 ]; +} TSteamPrepurchaseReceiptInfo; + +typedef struct +{ + ESteamSubscriptionStatus eStatus; + ESteamSubscriptionStatus ePreviousStatus; + ESteamSubscriptionBillingInfoType eReceiptInfoType; + char szConfirmationCode[ STEAM_BILLING_CONFIRMATION_CODE_SIZE + 1]; + union { + TSteamPaymentCardReceiptInfo PaymentCardReceiptInfo; + TSteamPrepurchaseReceiptInfo PrepurchaseReceiptInfo; + }; + +} TSteamSubscriptionReceipt; + +typedef enum +{ + ePhysicalBytesReceivedThisSession = 1, + eAppReadyToLaunchStatus = 2, + eAppPreloadStatus = 3, + eAppEntireDepot = 4, + eCacheBytesPresent = 5 +} ESteamAppUpdateStatsQueryType; + +typedef struct +{ + SteamUnsigned64_t uBytesTotal; + SteamUnsigned64_t uBytesPresent; +} TSteamUpdateStats; + +typedef enum +{ + eSteamUserAdministrator = 0x00000001, /* May subscribe, unsubscribe, etc */ + eSteamUserDeveloper = 0x00000002, /* Steam or App developer */ + eSteamUserCyberCafe = 0x00000004 /* CyberCafe, school, etc -- UI should ask for password */ + /* before allowing logout, unsubscribe, etc */ +} ESteamUserTypeFlags; + +typedef enum +{ + eSteamAccountStatusDefault = 0x00000000, + eSteamAccountStatusEmailVerified = 0x00000001, + /* Note: Mask value 0x2 is reserved for future use. (Some, but not all, public accounts already have this set.) */ + eSteamAccountDisabled = 0x00000004 +} ESteamAccountStatusBitFields ; + + +typedef enum +{ + eSteamBootstrapperError = -1, + eSteamBootstrapperDontCheckForUpdate = 0, + eSteamBootstrapperCheckForUpdateAndRerun = 7 + +} ESteamBootStrapperClientAppResult; + +typedef enum +{ + eSteamOnline = 0, + eSteamOffline = 1, + eSteamNoAuthMode = 2, + eSteamBillingOffline = 3 +} eSteamOfflineStatus; + +typedef struct +{ + int eOfflineNow; + int eOfflineNextSession; +} TSteamOfflineStatus; + +typedef struct +{ + unsigned int uAppId; + int bIsSystemDefined; + char szMountPath[STEAM_MAX_PATH]; +} TSteamAppDependencyInfo; + +typedef enum +{ + eSteamOpenFileRegular = 0x0, + eSteamOpenFileIgnoreLocal = 0x1, + eSteamOpenFileChecksumReads = 0x2 +} ESteamOpenFileFlags; + +typedef enum +{ + eSteamValveCDKeyValidationServer = 0, + eSteamHalfLifeMasterServer = 1, + eSteamFriendsServer = 2, + eSteamCSERServer = 3, + eSteamHalfLife2MasterServer = 4, + eSteamRDKFMasterServer = 5, + eMaxServerTypes = 6 +} ESteamServerType; + +/****************************************************************************** +** +** More exported constants +** +******************************************************************************/ + + +#ifdef __cplusplus + +const SteamHandle_t STEAM_INVALID_HANDLE = 0; +const SteamCallHandle_t STEAM_INVALID_CALL_HANDLE = 0; +const SteamUserIDTicketValidationHandle_t STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE = 0; +const unsigned int STEAM_USE_LATEST_VERSION = 0xFFFFFFFF; + +#else + +#define STEAM_INVALID_HANDLE ((SteamHandle_t)(0)) +#define STEAM_INVALID_CALL_HANDLE ((SteamCallHandle_t)(0)) +#define STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE ((SteamUserIDTicketValidationHandle_t)(0)) +#define STEAM_USE_LATEST_VERSION (0xFFFFFFFFu); + +#endif + + +/****************************************************************************** +** Each Steam instance (licensed Steam Service Provider) has a unique SteamInstanceID_t. +** +** Each Steam instance as its own DB of users. +** Each user in the DB has a unique SteamLocalUserID_t (a serial number, with possible +** rare gaps in the sequence). +** +******************************************************************************/ + +typedef unsigned short SteamInstanceID_t; // MUST be 16 bits + + +#if defined ( _WIN32 ) +typedef unsigned __int64 SteamLocalUserID_t; // MUST be 64 bits +#else +typedef unsigned long long SteamLocalUserID_t; // MUST be 64 bits +#endif + +/****************************************************************************** +** +** Applications need to be able to authenticate Steam users from ANY instance. +** So a SteamIDTicket contains SteamGlobalUserID, which is a unique combination of +** instance and user id. +** +** SteamLocalUserID is an unsigned 64-bit integer. +** For platforms without 64-bit int support, we provide access via a union that splits it into +** high and low unsigned 32-bit ints. Such platforms will only need to compare LocalUserIDs +** for equivalence anyway - not perform arithmetic with them. +** +********************************************************************************/ +typedef struct +{ + unsigned int Low32bits; + unsigned int High32bits; +} TSteamSplitLocalUserID; + +typedef struct +{ + SteamInstanceID_t m_SteamInstanceID; + + union + { + SteamLocalUserID_t As64bits; + TSteamSplitLocalUserID Split; + } m_SteamLocalUserID; + +} TSteamGlobalUserID; + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/common/hl2orange.spa.h b/common/hl2orange.spa.h new file mode 100644 index 0000000..ad84b65 --- /dev/null +++ b/common/hl2orange.spa.h @@ -0,0 +1,370 @@ +//////////////////////////////////////////////////////////////////// +// +// hl2orange.spa.h +// +// Auto-generated on Thursday, 13 September 2007 at 16:59:17 +// XLAST project version 1.0.402.0 +// SPA Compiler version 2.0.6274.0 +// +//////////////////////////////////////////////////////////////////// + +#ifndef __THE_ORANGE_BOX_SPA_H__ +#define __THE_ORANGE_BOX_SPA_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Title info +// + +#define TITLEID_THE_ORANGE_BOX 0x4541080F + +// +// Context ids +// +// These values are passed as the dwContextId to XUserSetContext. +// + +#define CONTEXT_CHAPTER_HL2 0 +#define CONTEXT_SCENARIO 1 +#define CONTEXT_GAME 2 +#define CONTEXT_CHAPTER_EP1 3 +#define CONTEXT_CHAPTER_EP2 4 +#define CONTEXT_CHAPTER_PORTAL 5 + +// +// Context values +// +// These values are passed as the dwContextValue to XUserSetContext. +// + +// Values for CONTEXT_CHAPTER_HL2 + +#define CONTEXT_CHAPTER_HL2_POINT_INSERTION 0 +#define CONTEXT_CHAPTER_HL2_A_RED_LETTER_DAY 1 +#define CONTEXT_CHAPTER_HL2_ROUTE_KANAL 2 +#define CONTEXT_CHAPTER_HL2_WATER_HAZARD 3 +#define CONTEXT_CHAPTER_HL2_BLACK_MESA_EAST 4 +#define CONTEXT_CHAPTER_HL2_RAVENHOLM 5 +#define CONTEXT_CHAPTER_HL2_HIGHWAY_17 6 +#define CONTEXT_CHAPTER_HL2_SANDTRAPS 7 +#define CONTEXT_CHAPTER_HL2_NOVA_PROSPEKT 8 +#define CONTEXT_CHAPTER_HL2_ENTANGLEMENT 9 +#define CONTEXT_CHAPTER_HL2_ANTICITIZEN_ONE 10 +#define CONTEXT_CHAPTER_HL2_FOLLOW_FREEMAN 11 +#define CONTEXT_CHAPTER_HL2_OUR_BENEFACTORS 12 +#define CONTEXT_CHAPTER_HL2_DARK_ENERGY 13 + +// Values for CONTEXT_SCENARIO + +#define CONTEXT_SCENARIO_CTF_2FORT 0 +#define CONTEXT_SCENARIO_CP_DUSTBOWL 1 +#define CONTEXT_SCENARIO_CP_GRANARY 2 +#define CONTEXT_SCENARIO_CP_WELL 3 +#define CONTEXT_SCENARIO_CP_GRAVELPIT 4 +#define CONTEXT_SCENARIO_TC_HYDRO 5 +#define CONTEXT_SCENARIO_CTF_CLOAK 6 +#define CONTEXT_SCENARIO_CP_CLOAK 7 + +// Values for CONTEXT_GAME + +#define CONTEXT_GAME_GAME_HALF_LIFE_2 0 +#define CONTEXT_GAME_GAME_EPISODE_ONE 1 +#define CONTEXT_GAME_GAME_EPISODE_TWO 2 +#define CONTEXT_GAME_GAME_PORTAL 3 +#define CONTEXT_GAME_GAME_TEAM_FORTRESS 4 + +// Values for CONTEXT_CHAPTER_EP1 + +#define CONTEXT_CHAPTER_EP1_UNDUE_ALARM 0 +#define CONTEXT_CHAPTER_EP1_DIRECT_INTERVENTION 1 +#define CONTEXT_CHAPTER_EP1_LOWLIFE 2 +#define CONTEXT_CHAPTER_EP1_URBAN_FLIGHT 3 +#define CONTEXT_CHAPTER_EP1_EXIT_17 4 + +// Values for CONTEXT_CHAPTER_EP2 + +#define CONTEXT_CHAPTER_EP2_TO_THE_WHITE_FOREST 0 +#define CONTEXT_CHAPTER_EP2_THIS_VORTAL_COIL 1 +#define CONTEXT_CHAPTER_EP2_FREEMAN_PONTIFEX 2 +#define CONTEXT_CHAPTER_EP2_RIDING_SHOTGUN 3 +#define CONTEXT_CHAPTER_EP2_UNDER_THE_RADAR 4 +#define CONTEXT_CHAPTER_EP2_OUR_MUTUAL_FIEND 5 +#define CONTEXT_CHAPTER_EP2_T_MINUS_ONE 6 + +// Values for CONTEXT_CHAPTER_PORTAL + +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_00 0 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_04 1 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_08 2 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_10 3 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_13 4 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_14 5 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_15 6 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_16 7 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_17 8 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_18 9 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_19 10 + +// Values for X_CONTEXT_PRESENCE + +#define CONTEXT_PRESENCE_TF_CP 0 +#define CONTEXT_PRESENCE_TF_CTF_LOSING 1 +#define CONTEXT_PRESENCE_TF_CTF_TIED 2 +#define CONTEXT_PRESENCE_TF_CTF_WINNING 3 +#define CONTEXT_PRESENCE_APPCHOOSER 4 +#define CONTEXT_PRESENCE_MENU 5 +#define CONTEXT_PRESENCE_EP1_INGAME 6 +#define CONTEXT_PRESENCE_HL2_INGAME 7 +#define CONTEXT_PRESENCE_EP2_INGAME 8 +#define CONTEXT_PRESENCE_PORTAL_INGAME 9 +#define CONTEXT_PRESENCE_COMMENTARY 10 +#define CONTEXT_PRESENCE_IDLE 11 + +// Values for X_CONTEXT_GAME_MODE + +#define CONTEXT_GAME_MODE_MULTIPLAYER 0 +#define CONTEXT_GAME_MODE_SINGLEPLAYER 1 + +// +// Property ids +// +// These values are passed as the dwPropertyId value to XUserSetProperty +// and as the dwPropertyId value in the XUSER_PROPERTY structure. +// + +#define PROPERTY_CAPS_OWNED 0x10000000 +#define PROPERTY_CAPS_TOTAL 0x10000001 +#define PROPERTY_PLAYER_TEAM_SCORE 0x10000002 +#define PROPERTY_OPPONENT_TEAM_SCORE 0x10000003 +#define PROPERTY_FLAG_CAPTURE_LIMIT 0x1000000B +#define PROPERTY_NUMBER_OF_ROUNDS 0x1000000C +#define PROPERTY_GAME_SIZE 0x1000000D +#define PROPERTY_AUTOBALANCE 0x1000000E +#define PROPERTY_PRIVATE_SLOTS 0x1000000F +#define PROPERTY_MAX_GAME_TIME 0x10000010 +#define PROPERTY_NUMBER_OF_KILLS 0x10000011 +#define PROPERTY_DAMAGE_DEALT 0x10000012 +#define PROPERTY_PLAY_TIME 0x10000013 +#define PROPERTY_POINT_CAPTURES 0x10000014 +#define PROPERTY_POINT_DEFENSES 0x10000015 +#define PROPERTY_DOMINATIONS 0x10000016 +#define PROPERTY_REVENGE 0x10000017 +#define PROPERTY_BUILDINGS_DESTROYED 0x10000019 +#define PROPERTY_HEADSHOTS 0x1000001A +#define PROPERTY_HEALTH_POINTS_HEALED 0x1000001B +#define PROPERTY_INVULNS 0x1000001C +#define PROPERTY_KILL_ASSISTS 0x1000001D +#define PROPERTY_BACKSTABS 0x1000001E +#define PROPERTY_HEALTH_POINTS_LEACHED 0x1000001F +#define PROPERTY_BUILDINGS_BUILT 0x10000020 +#define PROPERTY_SENTRY_KILLS 0x10000021 +#define PROPERTY_TELEPORTS 0x10000022 +#define PROPERTY_KILLS 0x10000023 +#define PROPERTY_NUMBER_OF_TEAMS 0x10000025 +#define PROPERTY_TEAM_RED 0x10000026 +#define PROPERTY_TEAM_BLUE 0x10000027 +#define PROPERTY_TEAM_SPECTATOR 0x10000028 +#define PROPERTY_TEAM 0x10000029 +#define PROPERTY_WIN_LIMIT 0x1000002A +#define PROPERTY_RANKING_TEST 0x2000000A +#define PROPERTY_POINTS_SCORED 0x20000018 + +// +// Achievement ids +// +// These values are used in the dwAchievementId member of the +// XUSER_ACHIEVEMENT structure that is used with +// XUserWriteAchievements and XUserCreateAchievementEnumerator. +// + +#define ACHIEVEMENT_HLX_KILL_ENEMIES_WITHPHYSICS 43 +#define ACHIEVEMENT_HLX_KILL_ENEMY_WITHHOPPERMINE 44 +#define ACHIEVEMENT_HLX_KILL_ENEMIES_WITHMANHACK 45 +#define ACHIEVEMENT_HLX_KILL_SOLDIER_WITHHISGRENADE 46 +#define ACHIEVEMENT_HLX_KILL_ENEMIES_WITHONEENERGYBALL 47 +#define ACHIEVEMENT_HLX_KILL_ELITESOLDIER_WITHHISENERGYBALL 48 +#define ACHIEVEMENT_EPX_GET_ZOMBINEGRENADE 50 +#define ACHIEVEMENT_EPX_KILL_ZOMBIES_WITHFLARES 51 +#define ACHIEVEMENT_HL2_HIT_CANCOP_WITHCAN 52 +#define ACHIEVEMENT_HL2_PUT_CANINTRASH 53 +#define ACHIEVEMENT_HL2_ESCAPE_APARTMENTRAID 54 +#define ACHIEVEMENT_HL2_BREAK_MINITELEPORTER 55 +#define ACHIEVEMENT_HL2_GET_CROWBAR 56 +#define ACHIEVEMENT_HL2_KILL_BARNACLESWITHBARREL 57 +#define ACHIEVEMENT_HL2_GET_AIRBOAT 58 +#define ACHIEVEMENT_HL2_GET_AIRBOATGUN 60 +#define ACHIEVEMENT_HL2_FIND_VORTIGAUNTCAVE 61 +#define ACHIEVEMENT_HL2_KILL_CHOPPER 62 +#define ACHIEVEMENT_HL2_FIND_HEVFACEPLATE 63 +#define ACHIEVEMENT_HL2_GET_GRAVITYGUN 64 +#define ACHIEVEMENT_HL2_MAKEABASKET 65 +#define ACHIEVEMENT_HL2_BEAT_RAVENHOLM_NOWEAPONS 66 +#define ACHIEVEMENT_HL2_BEAT_CEMETERY 67 +#define ACHIEVEMENT_HL2_KILL_ENEMIES_WITHCRANE 68 +#define ACHIEVEMENT_HL2_PIN_SOLDIER_TOBILLBOARD 69 +#define ACHIEVEMENT_HL2_KILL_ODESSAGUNSHIP 70 +#define ACHIEVEMENT_HL2_KILL_THREEGUNSHIPS 71 +#define ACHIEVEMENT_HL2_BEAT_DONTTOUCHSAND 72 +#define ACHIEVEMENT_HL2_KILL_ENEMIES_WITHANTLIONS 74 +#define ACHIEVEMENT_HL2_KILL_ENEMY_WITHTOILET 75 +#define ACHIEVEMENT_HL2_BEAT_TURRETSTANDOFF2 76 +#define ACHIEVEMENT_HL2_BEAT_TOXICTUNNEL 78 +#define ACHIEVEMENT_HL2_BEAT_PLAZASTANDOFF 79 +#define ACHIEVEMENT_HL2_KILL_ALLC1709SNIPERS 80 +#define ACHIEVEMENT_HL2_BEAT_SUPRESSIONDEVICE 81 +#define ACHIEVEMENT_HL2_BEAT_C1713STRIDERSTANDOFF 82 +#define ACHIEVEMENT_HL2_BEAT_GAME 84 +#define ACHIEVEMENT_HL2_FIND_ALLLAMBDAS 86 +#define ACHIEVEMENT_EP1_BEAT_MAINELEVATOR 87 +#define ACHIEVEMENT_EP1_BEAT_CITADELCORE 88 +#define ACHIEVEMENT_EP1_BEAT_CITADELCORE_NOSTALKERKILLS 89 +#define ACHIEVEMENT_EP1_KILL_ANTLIONS_WITHCARS 90 +#define ACHIEVEMENT_EP1_BEAT_GARAGEELEVATORSTANDOFF 91 +#define ACHIEVEMENT_EP1_KILL_ENEMIES_WITHSNIPERALYX 92 +#define ACHIEVEMENT_EP1_BEAT_HOSPITALATTICGUNSHIP 93 +#define ACHIEVEMENT_EP1_BEAT_CITIZENESCORT_NOCITIZENDEATHS 94 +#define ACHIEVEMENT_EP1_BEAT_GAME 95 +#define ACHIEVEMENT_EP1_BEAT_GAME_ONEBULLET 96 +#define ACHIEVEMENT_EP2_KILL_POISONANTLION 97 +#define ACHIEVEMENT_EP2_KILL_ALLGRUBS 98 +#define ACHIEVEMENT_EP2_BREAK_ALLWEBS 99 +#define ACHIEVEMENT_EP2_BEAT_ANTLIONINVASION 100 +#define ACHIEVEMENT_EP2_BEAT_ANTLIONGUARDS 101 +#define ACHIEVEMENT_EP2_KILL_ENEMIES_WITHCAR 102 +#define ACHIEVEMENT_EP2_BEAT_HUNTERAMBUSH 103 +#define ACHIEVEMENT_EP2_KILL_CHOPPER_NOMISSES 104 +#define ACHIEVEMENT_EP2_KILL_COMBINECANNON 105 +#define ACHIEVEMENT_EP2_FIND_ALLRADARCACHES 106 +#define ACHIEVEMENT_EP2_BEAT_ROCKETCACHEPUZZLE 107 +#define ACHIEVEMENT_EP2_BEAT_RACEWITHDOG 108 +#define ACHIEVEMENT_EP2_BEAT_WHITEFORESTINN 109 +#define ACHIEVEMENT_EP2_PUT_ITEMINROCKET 110 +#define ACHIEVEMENT_EP2_BEAT_MISSILESILO2 111 +#define ACHIEVEMENT_EP2_BEAT_OUTLAND12_NOBUILDINGSDESTROYED 112 +#define ACHIEVEMENT_EP2_BEAT_GAME 113 +#define ACHIEVEMENT_EP2_KILL_HUNTER_WITHFLECHETTES 114 +#define ACHIEVEMENT_PORTAL_GET_PORTALGUNS 115 +#define ACHIEVEMENT_PORTAL_KILL_COMPANIONCUBE 116 +#define ACHIEVEMENT_PORTAL_ESCAPE_TESTCHAMBERS 117 +#define ACHIEVEMENT_PORTAL_BEAT_GAME 118 +#define ACHIEVEMENT_PORTAL_INFINITEFALL 119 +#define ACHIEVEMENT_PORTAL_LONGJUMP 120 +#define ACHIEVEMENT_PORTAL_BEAT_2ADVANCEDMAPS 121 +#define ACHIEVEMENT_PORTAL_BEAT_4ADVANCEDMAPS 122 +#define ACHIEVEMENT_PORTAL_BEAT_6ADVANCEDMAPS 123 +#define ACHIEVEMENT_PORTAL_GET_ALLBRONZE 124 +#define ACHIEVEMENT_PORTAL_GET_ALLSILVER 125 +#define ACHIEVEMENT_PORTAL_GET_ALLGOLD 126 +#define ACHIEVEMENT_TF_GET_TURRETKILLS 127 +#define ACHIEVEMENT_TF_KILL_NEMESIS 128 +#define ACHIEVEMENT_TF_GET_CONSECUTIVEKILLS_NODEATHS 129 +#define ACHIEVEMENT_TF_GET_HEALED_BYENEMY 130 +#define ACHIEVEMENT_TF_PLAY_GAME_FRIENDSONLY 131 +#define ACHIEVEMENT_TF_WIN_MULTIPLEGAMES 132 +#define ACHIEVEMENT_TF_GET_MULTIPLEKILLS 133 +#define ACHIEVEMENT_TF_WIN_2FORT_NOENEMYCAPS 134 +#define ACHIEVEMENT_TF_WIN_WELL_MINIMUMTIME 135 +#define ACHIEVEMENT_TF_WIN_HYDRO_NOENEMYCAPS 136 +#define ACHIEVEMENT_TF_WIN_DUSTBOWL_NOENEMYCAPS 137 +#define ACHIEVEMENT_TF_WIN_GRAVELPIT_NOENEMYCAPS 138 +#define ACHIEVEMENT_TF_PLAY_GAME_EVERYCLASS 139 +#define ACHIEVEMENT_TF_PLAY_GAME_EVERYMAP 140 +#define ACHIEVEMENT_TF_GET_HEALPOINTS 141 +#define ACHIEVEMENT_TF_BURN_PLAYERSINMINIMIMTIME 142 +#define ACHIEVEMENT_HL2_DISINTEGRATE_SOLDIERSINFIELD 143 +#define ACHIEVEMENT_HL2_FOLLOW_FREEMAN 144 +#define ACHIEVEMENT_TF_GET_HEADSHOTS 145 +#define ACHIEVEMENT_PORTAL_DETACH_ALL_CAMERAS 146 +#define ACHIEVEMENT_PORTAL_HIT_TURRET_WITH_TURRET 148 + +#ifndef _XBOX +#define ACHIEVEMENT_PORTAL_TRANSMISSION_RECEIVED 149 +#define ACHIEVEMENT_TF_GENERAL_KILL_ENEMIES_AFTER_TELEPORTING 150 +#endif // _XBOX + +#define ACHIEVEMENT_TF_LAST_ORANGEBOX 150 + +// +// Stats view ids +// +// These are used in the dwViewId member of the XUSER_STATS_SPEC structure +// passed to the XUserReadStats* and XUserCreateStatsEnumerator* functions. +// + +// Skill leaderboards for ranked game modes + +#define STATS_VIEW_SKILL_RANKED_MULTIPLAYER 0xFFFF0000 +#define STATS_VIEW_SKILL_RANKED_SINGLEPLAYER 0xFFFF0001 + +// Skill leaderboards for unranked (standard) game modes + +#define STATS_VIEW_SKILL_STANDARD_MULTIPLAYER 0xFFFE0000 +#define STATS_VIEW_SKILL_STANDARD_SINGLEPLAYER 0xFFFE0001 + +// Title defined leaderboards + +#define STATS_VIEW_PLAYER_MAX_UNRANKED 1 +#define STATS_VIEW_PLAYER_MAX_RANKED 2 + +// +// Stats view column ids +// +// These ids are used to read columns of stats views. They are specified in +// the rgwColumnIds array of the XUSER_STATS_SPEC structure. Rank, rating +// and gamertag are not retrieved as custom columns and so are not included +// in the following definitions. They can be retrieved from each row's +// header (e.g., pStatsResults->pViews[x].pRows[y].dwRank, etc.). +// + +// Column ids for PLAYER_MAX_UNRANKED + +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_POINTS_SCORED 2 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_KILLS 3 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_POINTS_CAPPED 1 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_DAMAGE_DEALT 4 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_PLAY_TIME 5 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_POINT_DEFENSES 6 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_DOMINATIONS 7 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_REVENGE 8 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_BUILDINGS_DESTROYED 9 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_HEADSHOTS 10 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_HEALTH_POINTS_HEALED 11 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_INVULNS 12 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_KILL_ASSISTS 13 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_BACKSTABS 14 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_HEALTH_POINTS_LEACHED 15 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_BUILDINGS_BUILT 16 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_SENTRY_KILLS 17 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_TELEPORTS 18 + +// Column ids for PLAYER_MAX_RANKED + +#define STATS_COLUMN_PLAYER_MAX_RANKED_POINTS_SCORED 2 + +// +// Matchmaking queries +// +// These values are passed as the dwProcedureIndex parameter to +// XSessionSearch to indicate which matchmaking query to run. +// + +#define SESSION_MATCH_QUERY_PLAYER_MATCH 0 + +// +// Gamer pictures +// +// These ids are passed as the dwPictureId parameter to XUserAwardGamerTile. +// + + + +#ifdef __cplusplus +} +#endif + +#endif // __THE_ORANGE_BOX_SPA_H__ + + diff --git a/common/language.h b/common/language.h new file mode 100644 index 0000000..b16c492 --- /dev/null +++ b/common/language.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: represent a canonical list of the languages we support, +// +//============================================================================= + +#ifndef LANG_H +#define LANG_H +#ifdef _WIN32 +#pragma once +#endif + +// if you change this enum also change language.cpp:s_LanguageNames +enum ELanguage +{ + k_Lang_None = -1, + k_Lang_First = 0, + k_Lang_English = 0, + k_Lang_German, + k_Lang_French, + k_Lang_Italian, + k_Lang_Korean, + k_Lang_Spanish, + k_Lang_Simplified_Chinese, + k_Lang_Traditional_Chinese, + k_Lang_Russian, + k_Lang_Thai, + k_Lang_Japanese, + k_Lang_Portuguese, + k_Lang_Polish, + k_Lang_Danish, + k_Lang_Dutch, + k_Lang_Finnish, + k_Lang_Norwegian, + k_Lang_Swedish, + k_Lang_Romanian, + k_Lang_Turkish, + k_Lang_Hungarian, + k_Lang_Czech, + k_Lang_Brazilian, + k_Lang_Bulgarian, + k_Lang_Greek, + k_Lang_Ukrainian, + k_Lang_MAX +}; + +#define FOR_EACH_LANGUAGE( eLang ) for ( int eLang = (int)k_Lang_First; eLang < k_Lang_MAX; ++eLang ) + +ELanguage PchLanguageToELanguage(const char *pchShortName, ELanguage eDefault = k_Lang_English); +ELanguage PchLanguageICUCodeToELanguage( const char *pchICUCode, ELanguage eDefault = k_Lang_English ); +const char *GetLanguageShortName( ELanguage eLang ); +const char *GetLanguageICUName( ELanguage eLang ); +const char *GetLanguageVGUILocalization( ELanguage eLang ); +const char *GetLanguageName( ELanguage eLang ); + +#endif /* LANG_H */ diff --git a/common/lzma/lzma.h b/common/lzma/lzma.h new file mode 100644 index 0000000..01bd1ef --- /dev/null +++ b/common/lzma/lzma.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: LZMA Glue. Designed for Tool time Encoding/Decoding. +// +// LZMA Codec interface for engine. Based largely on LzmaUtil.c in SDK +// +// LZMA SDK 9.38 beta +// 2015-01-03 : Igor Pavlov : Public domain +// http://www.7-zip.org/ +// +//====================================================================================// + +#ifndef LZMA_H +#define LZMA_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// These routines are designed for TOOL TIME encoding/decoding on the PC! +// They have not been made to encode/decode on the PPC and lack big endian awarnesss. +// Lightweight GAME TIME Decoding is part of tier1.lib, via CLZMA. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Encoding glue. Returns non-null Compressed buffer if successful. +// Caller must free. +//----------------------------------------------------------------------------- +unsigned char *LZMA_Compress( +unsigned char *pInput, +unsigned int inputSize, +unsigned int *pOutputSize ); + +//----------------------------------------------------------------------------- +// Decoding glue. Returns TRUE if succesful. +//----------------------------------------------------------------------------- +bool LZMA_Uncompress( +unsigned char *pInput, +unsigned char **ppOutput, +unsigned int *pOutputSize ); + +//----------------------------------------------------------------------------- +// Decoding helper, returns TRUE if buffer is LZMA compressed. +//----------------------------------------------------------------------------- +bool LZMA_IsCompressed( unsigned char *pInput ); + +//----------------------------------------------------------------------------- +// Decoding helper, returns non-zero size of data when uncompressed, otherwise 0. +//----------------------------------------------------------------------------- +unsigned int LZMA_GetActualSize( unsigned char *pInput ); + +#endif diff --git a/common/proto_version.h b/common/proto_version.h new file mode 100644 index 0000000..c4e7ca0 --- /dev/null +++ b/common/proto_version.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( PROTO_VERSION_H ) +#define PROTO_VERSION_H +#ifdef _WIN32 +#pragma once +#endif + +// The current network protocol version. Changing this makes clients and servers incompatible +#define PROTOCOL_VERSION 24 + +#define DEMO_BACKWARDCOMPATABILITY + +// For backward compatibility of demo files (NET_MAX_PAYLOAD_BITS went away) +#define PROTOCOL_VERSION_23 23 + +// For backward compatibility of demo files (sound index bits used to = 13 ) +#define PROTOCOL_VERSION_22 22 + +// For backward compatibility of demo files (before the special DSP was shipped to public) +#define PROTOCOL_VERSION_21 21 + +// For backward compatibility of demo files (old-style dynamic model loading) +#define PROTOCOL_VERSION_20 20 + +// For backward compatibility of demo files (post Halloween sound flag extra bit) +#define PROTOCOL_VERSION_19 19 + +// For backward compatibility of demo files (pre Halloween sound flag extra bit) +#define PROTOCOL_VERSION_18 18 + +// For backward compatibility of demo files (MD5 in map version) +#define PROTOCOL_VERSION_17 17 + +// For backward compatibility of demo files (create string tables compression flag) +#define PROTOCOL_VERSION_14 14 + +// For backward compatibility of demo files +#define PROTOCOL_VERSION_12 12 + +// The PROTOCOL_VERSION when replay shipped to public +#define PROTOCOL_VERSION_REPLAY 16 + +#endif diff --git a/common/qlimits.h b/common/qlimits.h new file mode 100644 index 0000000..205053a --- /dev/null +++ b/common/qlimits.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef QLIMITS_H +#define QLIMITS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +// DATA STRUCTURE INFO + +#define MAX_NUM_ARGVS 50 + +// SYSTEM INFO +#define MAX_QPATH 96 // max length of a game pathname +#define MAX_OSPATH 260 // max length of a filesystem pathname + +#define ON_EPSILON 0.1 // point on plane side epsilon + + +// Resource counts; +#define MAX_MODEL_INDEX_BITS 12 // sent as a short +#define MAX_MODELS (1<GetReplay() + virtual IReplayManager *GetReplayManager() = 0; + virtual IReplayMovieRenderer *GetMovieRenderer() = 0; + virtual IReplayMovieManager *GetMovieManager() = 0; + virtual IReplayScreenshotManager *GetScreenshotManager() = 0; + virtual IReplayPerformanceManager *GetPerformanceManager() = 0; + virtual IReplayPerformanceController *GetPerformanceController() = 0; + virtual IReplayRenderQueue *GetRenderQueue() = 0; + virtual void SetMovieRenderer( IReplayMovieRenderer *pRenderer ) = 0; // Set to be the panel that renders replay movies, or NULL when nothing is rendering + virtual void OnSignonStateFull() = 0; + virtual void OnClientSideDisconnect() = 0; // Called when client disconnects + virtual void PlayReplay( ReplayHandle_t hReplay, int iPerformance, bool bPlaySound ) = 0; // Play the given replay, from spawn tick to death tick + virtual bool ReconstructReplayIfNecessary( CReplay *pReplay ) = 0; + virtual void OnPlayerSpawn() = 0; // Called on the client when player is spawned + virtual void OnPlayerClassChanged() = 0; // Called when the player's class changes - we use this instead of an event for immediacy + virtual void GetPlaybackTimes( float &flOutTime, float &flOutLength, const CReplay *pReplay, const CReplayPerformance *pPerformance ) = 0; // Calculate the current time and length of a replay or performance - takes in tick and out tick into account for performances - flCurTime should be gpGlobals->curtime. pPerformance can be NULL. + virtual uint64 GetServerSessionId( ReplayHandle_t hReplay ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // ICLIENTREPLAYCONTEXT_H diff --git a/common/replay/iclientreplayhistorymanager.h b/common/replay/iclientreplayhistorymanager.h new file mode 100644 index 0000000..8013ca0 --- /dev/null +++ b/common/replay/iclientreplayhistorymanager.h @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef ICLIENTREPLAYHISTORYMANAGER_H +#define ICLIENTREPLAYHISTORYMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "replay/replayhandle.h" +#include "replay/screenshot.h" +#include "interface.h" +#include "qlimits.h" +#include "convar.h" +#include "engine/http.h" +#include "tier1/utllinkedlist.h" +#include "tier1/checksum_crc.h" +#include + +//---------------------------------------------------------------------------------------- + +class IReplayDownloadGroup; +class IReplayDownloadGroupHelper; +class CDmxElement; +class KeyValues; +struct CaptureScreenshotParams_t; +struct RenderMovieParams_t; +class CBaseReplay; +class CReplay; +class IReplayMovieRenderer; +class IReplayMovieManager; +class IReplayMovie; +class IReplayPerformanceManager; +class IGameEvent; + +//---------------------------------------------------------------------------------------- + +class IClientReplayHistoryManager : public IBaseInterface +{ +public: + virtual bool Init( CreateInterfaceFn fnCreateFactory ) = 0; + virtual void Shutdown() = 0; + virtual void Think() = 0; + + virtual bool IsInitialized() const = 0; + virtual bool Commit( CBaseReplay *pNewReplay ) = 0; + + virtual void Save() = 0; // Write the entire index and any replays/groups/movies that are marked as dirty + virtual void FlagReplayForFlush( CBaseReplay *pReplay, bool bForceImmediateWrite ) = 0; // Mark the given replay as dirty - flush to disk at the next opportunity (see CBaseReplayHistoryManager::FlushThink()) + + virtual void Nuke() = 0; + + virtual void DeleteReplay( ReplayHandle_t hReplay, bool bNotifyUI ) = 0; + virtual CBaseReplay *GetReplay( ReplayHandle_t hReplay ) = 0; + + virtual const char *GetBaseDirectory() = 0; // Returns full directory to wherever replays.dmx lives, e.g. c:\program files (x86)\steam\steamapps\someuser\team fortress 2\game\tf\replays\client\ (or server\) - NOTE: includes trailing slash + virtual const char *GetReplaysSubDir() = 0; // Returns "client" or "server" + + // For loop through all replays - indices should not be cached + virtual int GetReplayCount() const = 0; +// virtual CBaseReplay *GetReplayAtIndex( int nIndex ) = 0; + + virtual const char *GetFullReplayPath() = 0; // Get c:\...\game\tf\replays\\ + + // Client-specific + virtual int GetAdjustedDeathTick( CReplay *pReplay ) = 0; + virtual void FlagDownloadGroupForFlush( IReplayDownloadGroup *pGroup, bool bForceImmediate ) = 0; + virtual void FlagMovieForFlush( IReplayMovie *pMovie, bool bForceImmediate ) = 0; // Flag the movie for flush - if pMovie is NULL, mark the index for flush + virtual void SetMovieRenderer( IReplayMovieRenderer *pRenderer ) = 0; // Set to be the panel that renders replay movies, or NULL when nothing is rendering + virtual bool ShouldGameRenderView() = 0; // Called from V_RenderView() to determine whether the game should render - used during movie rendering + virtual int GetUnrenderedReplayCount() = 0; // Get the number of unrendered replays + virtual void UpdateCurrentReplayDataFromServer() = 0; // Updates start tick, current file url, demo filename + virtual void LinkReplayToDownloadGroup() = 0; + virtual void CaptureScreenshot( CaptureScreenshotParams_t ¶ms ) = 0; // Schedules a screenshot capture at flDelay seconds in the future + virtual void DoCaptureScreenshot() = 0; // Takes the screenshot right now + virtual bool ShouldCaptureScreenshot() = 0; // Is screenshot scheduled to be taken right now? + virtual void GetUnpaddedScreenshotSize( int &nWidth, int &nHeight ) = 0; // Get the dimensions for a screenshot if we take one right now, based on replay_screenshotresolution and the current aspect ratio + virtual void DeleteScreenshotsForReplay( CReplay *pReplay ) = 0; // Deletes all screenshots associated with the given replay + virtual void PlayReplay( ReplayHandle_t hReplay ) = 0; // Play the given replay, from spawn tick to death tick + virtual void RenderMovie( RenderMovieParams_t const& params ) = 0; // Renders the given replay - or if params.hReplay is -1, render all unrendered replays + virtual void CompleteRender( bool bSuccess ) = 0; + virtual void OnClientSideDisconnect() = 0; // Called when client disconnects + virtual void OnSignonStateFull() = 0; + virtual void OnPlayerSpawn() = 0; // Called on the client when player is spawned + virtual void OnPlayerClassChanged() = 0; // Called when the player's class changes - we use this instead of an event for immediacy + virtual void OnReplayRecordingCvarChanged() = 0; // Called (on client only) when replay_recording is set to 1 + virtual void OnGroupDeleted() = 0; + virtual CReplay *GetPlayingReplay() = 0; // Get the currently playing replay, otherwise NULL if one isn't playing + virtual CReplay *GetReplayForCurrentLife() = 0; // Gets the current replay (constant from local player spawn until next spawn/disconnect/exit) + virtual bool IsRendering() = 0; // Are we currently rendering a movie? + virtual void CancelRender() = 0; // If we're currently rendering, cancel + virtual IReplayMovieManager *GetMovieManager() = 0; + virtual IReplayMovieRenderer *GetMovieRenderer() = 0; + virtual const RenderMovieParams_t *GetRenderSettings() = 0; + virtual IReplayDownloadGroupHelper *GetDownloadGroupHelper() = 0; + virtual IReplayPerformanceManager *GetPerformanceManager() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // ICLIENTREPLAYHISTORYMANAGER_H diff --git a/common/replay/ienginereplay.h b/common/replay/ienginereplay.h new file mode 100644 index 0000000..98de949 --- /dev/null +++ b/common/replay/ienginereplay.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IENGINEREPLAY_H +#define IENGINEREPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +#define ENGINE_REPLAY_INTERFACE_VERSION "EngineReplay001" + +#if !defined( DEDICATED ) +# define ENGINE_REPLAY_CLIENT_INTERFACE_VERSION "EngineClientReplay001" +#endif + +//---------------------------------------------------------------------------------------- + +class IServer; +class INetChannel; +class IReplayServer; +class IClientEntityList; +class IClientReplay; +struct demoheader_t; +class CGlobalVarsBase; +class IDemoBuffer; +class CBaseRecordingSessionBlock; + +//---------------------------------------------------------------------------------------- + +// +// Allows the replay, client & server DLL's to talk to the engine +// +class IEngineReplay : public IBaseInterface +{ +public: + virtual bool IsSupportedModAndPlatform() = 0; + + virtual float GetHostTime() = 0; + virtual int GetHostTickCount() = 0; + virtual int TimeToTicks( float flTime ) = 0; + virtual float TicksToTime( int nTick ) = 0; + + virtual bool ReadDemoHeader( const char *pFilename, demoheader_t &header ) = 0; + virtual const char *GetGameDir() = 0; + virtual void Cbuf_AddText( const char *pCmd ) = 0; + virtual void Cbuf_Execute() = 0; + virtual void Host_Disconnect( bool bShowMainMenu ) = 0; + virtual void HostState_Shutdown() = 0; + virtual const char *GetModDir() = 0; + + virtual bool CopyFile( const char *pSource, const char *pDest ) = 0; + + virtual bool LZSS_Compress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen ) = 0; + virtual bool LZSS_Decompress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen ) = 0; + + virtual bool MD5_HashBuffer( unsigned char pDigest[16], const unsigned char *pBuffer, int nSize, unsigned int pSeed[4] ) = 0; + + // Server-specific + virtual IReplayServer *GetReplayServer() = 0; + virtual IServer *GetReplayServerAsIServer() = 0; + virtual IServer *GetGameServer() = 0; + virtual bool GetSessionRecordBuffer( uint8 **ppSessionBuffer, int *pSize ) = 0; + virtual bool IsDedicated() = 0; + virtual void ResetReplayRecordBuffer() = 0; + virtual demoheader_t *GetReplayDemoHeader() = 0; + virtual void RecalculateTags() = 0; + virtual bool NET_GetHostnameAsIP( const char *pHostname, char *pOut, int nOutSize ) = 0; +}; + +// +// Allows the replay and client DLL's to talk to the engine +// +#if !defined( DEDICATED ) +class IEngineClientReplay : public IBaseInterface +{ +public: + virtual INetChannel *GetNetChannel() = 0; + virtual bool IsConnected() = 0; + virtual bool IsListenServer() = 0; + virtual float GetLastServerTickTime() = 0; + virtual const char *GetLevelName() = 0; + virtual const char *GetLevelNameShort() = 0; + virtual int GetPlayerSlot() = 0; + virtual bool IsPlayingReplayDemo() = 0; + virtual IClientEntityList *GetClientEntityList() = 0; + virtual IClientReplay *GetClientReplayInt() = 0; + virtual uint32 GetClientSteamID() = 0; + virtual void Con_NPrintf( int nPos, PRINTF_FORMAT_STRING const char *pFormat, ... ) = 0; + virtual CGlobalVarsBase *GetClientGlobalVars() = 0; + virtual void VGui_PlaySound( const char *pSound ) = 0; + virtual void EngineVGui_ConfirmQuit() = 0; + virtual int GetScreenWidth() = 0; + virtual int GetScreenHeight() = 0; + virtual bool IsDemoPlayingBack() = 0; + virtual bool IsGamePathValidAndSafeForDownload( const char *pGamePath ) = 0; + virtual bool IsInGame() = 0; + + virtual void InitSoundRecord() = 0; + + virtual void Wave_CreateTmpFile( const char *pFilename ) = 0; + virtual void Wave_AppendTmpFile( const char *pFilename, void *pBuffer, int nNumSamples ) = 0; + virtual void Wave_FixupTmpFile( const char *pFilename ) = 0; + +}; +#endif // !defined( DEDICATED ) + +//---------------------------------------------------------------------------------------- + +#endif // IENGINEREPLAY_H \ No newline at end of file diff --git a/common/replay/iqueryablereplayitem.h b/common/replay/iqueryablereplayitem.h new file mode 100644 index 0000000..6e3d3f3 --- /dev/null +++ b/common/replay/iqueryablereplayitem.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IQUERYABLEREPLAYITEM_H +#define IQUERYABLEREPLAYITEM_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "iqueryablereplayitem.h" +#include "replay/replayhandle.h" +#include "replay/replaytime.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; + +//---------------------------------------------------------------------------------------- + +typedef int QueryableReplayItemHandle_t; + +//---------------------------------------------------------------------------------------- + +abstract_class IQueryableReplayItem : public IBaseInterface +{ +public: + virtual const CReplayTime &GetItemDate() const = 0; + virtual bool IsItemRendered() const = 0; + virtual CReplay *GetItemReplay() = 0; + virtual ReplayHandle_t GetItemReplayHandle() const = 0; + virtual QueryableReplayItemHandle_t GetItemHandle() const = 0; // Get the handle of this item + virtual const wchar_t *GetItemTitle() const = 0; + virtual void SetItemTitle( const wchar_t *pTitle ) = 0; + virtual float GetItemLength() const = 0; + virtual void *GetUserData() = 0; + virtual void SetUserData( void *pUserData ) = 0; + virtual bool IsItemAMovie() const = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IQUERYABLEREPLAYITEM_H \ No newline at end of file diff --git a/common/replay/irecordingsession.h b/common/replay/irecordingsession.h new file mode 100644 index 0000000..4b0046d --- /dev/null +++ b/common/replay/irecordingsession.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IRECORDINGSESSION_H +#define IRECORDINGSESSION_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CBaseRecordingSessionBlock; + +class IRecordingSession : public IBaseInterface +{ +public: + virtual void AddBlock( CBaseRecordingSessionBlock *pBlock ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IRECORDINGSESSION_H diff --git a/common/replay/irecordingsessionblockmanager.h b/common/replay/irecordingsessionblockmanager.h new file mode 100644 index 0000000..e2a6a82 --- /dev/null +++ b/common/replay/irecordingsessionblockmanager.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IRECORDINGSESSIONBLOCKMANAGER_H +#define IRECORDINGSESSIONBLOCKMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replayhandle.h" + +//---------------------------------------------------------------------------------------- + +class IRecordingSessionBlockManager : public IBaseInterface +{ +public: + virtual CBaseRecordingSessionBlock *GetBlock( ReplayHandle_t hBlock ) = 0; + virtual void DeleteBlock( CBaseRecordingSessionBlock *pBlock ) = 0; + virtual void UnloadBlock( CBaseRecordingSessionBlock *pBlock ) = 0; + virtual const char *GetBlockPath() const = 0; + virtual void LoadBlockFromFileName( const char *pFilename, IRecordingSession *pSession ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IRECORDINGSESSIONBLOCKMANAGER_H diff --git a/common/replay/irecordingsessionmanager.h b/common/replay/irecordingsessionmanager.h new file mode 100644 index 0000000..23cdf65 --- /dev/null +++ b/common/replay/irecordingsessionmanager.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IRECORDINGSESSIONMANAGER_H +#define IRECORDINGSESSIONMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replayhandle.h" + +//---------------------------------------------------------------------------------------- + +class CBaseRecordingSession; + +//---------------------------------------------------------------------------------------- + +class IRecordingSessionManager : public IBaseInterface +{ +public: + virtual CBaseRecordingSession *FindSession( ReplayHandle_t hSession ) = 0; + virtual const CBaseRecordingSession *FindSession( ReplayHandle_t hSession ) const = 0; + virtual void FlagSessionForFlush( CBaseRecordingSession *pSession, bool bForceImmediate ) = 0; + virtual int GetServerStartTickForSession( ReplayHandle_t hSession ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IRECORDINGSESSIONMANAGER_H \ No newline at end of file diff --git a/common/replay/ireplaycamera.h b/common/replay/ireplaycamera.h new file mode 100644 index 0000000..24ccb91 --- /dev/null +++ b/common/replay/ireplaycamera.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef IREPLAYCAMERA_H +#define IREPLAYCAMERA_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayCamera : public IBaseInterface +{ +public: + virtual void ClearOverrideView() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYCAMERA_H diff --git a/common/replay/ireplaycontext.h b/common/replay/ireplaycontext.h new file mode 100644 index 0000000..f4fda37 --- /dev/null +++ b/common/replay/ireplaycontext.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYCONTEXT_H +#define IREPLAYCONTEXT_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replayhandle.h" + +//---------------------------------------------------------------------------------------- + +class IRecordingSessionManager; +class IRecordingSessionBlockManager; +class IRecordingSession; +class IReplayErrorSystem; + +//---------------------------------------------------------------------------------------- + +class IReplayContext : public IBaseInterface +{ +public: + virtual bool Init( CreateInterfaceFn fnCreateFactory ) = 0; + virtual void Shutdown() = 0; + + virtual void Think() = 0; + + virtual bool IsInitialized() const = 0; + + virtual const char *GetRelativeBaseDir() const = 0; // Returns path to wherever the index .dmx lives relative to the game path, e.g. "replay\client\" + virtual const char *GetBaseDir() const = 0; // Returns full directory to wherever the index .dmx lives, e.g. c:\program files (x86)\steam\steamapps\\team fortress 2\tf\replays\\ -- NOTE: includes trailing slash + virtual const char *GetReplaySubDir() const = 0; // Returns "client" or "server" + + virtual IReplayErrorSystem *GetErrorSystem() = 0; + virtual IRecordingSessionManager *GetRecordingSessionManager() = 0; + virtual IRecordingSessionBlockManager *GetRecordingSessionBlockManager() = 0; + virtual IRecordingSession *GetRecordingSession( ReplayHandle_t hSession ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYCONTEXT_H diff --git a/common/replay/ireplaydemoplayer.h b/common/replay/ireplaydemoplayer.h new file mode 100644 index 0000000..1a8a1d5 --- /dev/null +++ b/common/replay/ireplaydemoplayer.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYDEMOPLAYER_H +#define IREPLAYDEMOPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replay.h" + +//---------------------------------------------------------------------------------------- + +#define INTERFACEVERSION_REPLAYDEMOPLAYER "ReplayDemoPlayer001" + +//---------------------------------------------------------------------------------------- + +// +// Interface for replay demo player +// +class IReplayDemoPlayer : public IBaseInterface +{ +public: + virtual void PlayReplay( ReplayHandle_t hReplay, int iPerformance ) = 0; + virtual void PlayNextReplay() = 0; + virtual void ClearReplayList() = 0; + virtual void AddReplayToList( ReplayHandle_t hReplay, int iPerformance ) = 0; + virtual CReplay *GetCurrentReplay() = 0; + virtual CReplayPerformance *GetCurrentPerformance() = 0; // The playing replay, or NULL if playing the original replay + virtual void PauseReplay() = 0; + virtual bool IsReplayPaused() = 0; + virtual void ResumeReplay() = 0; + virtual void OnSignonStateFull() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYDEMOPLAYER_H \ No newline at end of file diff --git a/common/replay/ireplayerrorsystem.h b/common/replay/ireplayerrorsystem.h new file mode 100644 index 0000000..cc39b7e --- /dev/null +++ b/common/replay/ireplayerrorsystem.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYERRORSYSYTEM_H +#define IREPLAYERRORSYSYTEM_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class KeyValues; + +//---------------------------------------------------------------------------------------- + +// +// Replay error system +// +class IReplayErrorSystem : public IBaseInterface +{ +public: + virtual void AddErrorFromTokenName( const char *pToken ) = 0; + virtual void AddFormattedErrorFromTokenName( const char *pFormatToken, KeyValues *pFormatArgs ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYERRORSYSYTEM_H \ No newline at end of file diff --git a/common/replay/ireplayfactory.h b/common/replay/ireplayfactory.h new file mode 100644 index 0000000..0aad205 --- /dev/null +++ b/common/replay/ireplayfactory.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYFACTORY_H +#define IREPLAYFACTORY_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayFactory : public IBaseInterface +{ +public: + virtual CReplay *Create() = 0; +}; + +#define INTERFACE_VERSION_REPLAY_FACTORY "IReplayFactory001" + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYFACTORY_H \ No newline at end of file diff --git a/common/replay/ireplaymanager.h b/common/replay/ireplaymanager.h new file mode 100644 index 0000000..bf6ffd7 --- /dev/null +++ b/common/replay/ireplaymanager.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYMANAGER_H +#define IREPLAYMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replayhandle.h" +#include "utllinkedlist.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; +class IQueryableReplayItem; + +//---------------------------------------------------------------------------------------- + +class IReplayManager : public IBaseInterface +{ +public: + virtual CReplay *GetReplay( ReplayHandle_t hReplay ) = 0; + virtual CReplay *GetPlayingReplay() = 0; + virtual CReplay *GetReplayForCurrentLife() = 0; + virtual void FlagReplayForFlush( CReplay *pReplay, bool bForceImmediate ) = 0; + virtual void DeleteReplay( ReplayHandle_t hReplay, bool bNotifyUI ) = 0; + virtual int GetReplayCount() const = 0; + virtual int GetUnrenderedReplayCount() = 0; // Get the number of unrendered replays + virtual void GetReplays( CUtlLinkedList< CReplay *, int > &lstReplays ) = 0; + virtual void GetReplaysAsQueryableItems( CUtlLinkedList< IQueryableReplayItem *, int > &lstReplays ) = 0; + virtual float GetDownloadProgress( const CReplay *pReplay ) = 0; + virtual const char *GetReplaysDir() const = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYMANAGER_H diff --git a/common/replay/ireplaymovie.h b/common/replay/ireplaymovie.h new file mode 100644 index 0000000..2a2caee --- /dev/null +++ b/common/replay/ireplaymovie.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYMOVIE_H +#define IREPLAYMOVIE_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "iqueryablereplayitem.h" +#include "replay/rendermovieparams.h" + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayMovie : public IQueryableReplayItem +{ +public: + virtual ReplayHandle_t GetMovieHandle() const = 0; + virtual ReplayHandle_t GetReplayHandle() const = 0; + virtual const ReplayRenderSettings_t &GetRenderSettings() = 0; + virtual void GetFrameDimensions( int &nWidth, int &nHeight ) = 0; + virtual void SetIsRendered( bool bIsRendered ) = 0; + virtual void SetMovieFilename( const char *pFilename ) = 0; + virtual const char *GetMovieFilename() const = 0; + virtual void SetMovieTitle( const wchar_t *pTitle ) = 0; + virtual void SetRenderTime( float flRenderTime ) = 0; + virtual float GetRenderTime() const = 0; + virtual void CaptureRecordTime() = 0; + virtual void SetLength( float flLength ) = 0; + + virtual bool IsUploaded() const = 0; + virtual void SetUploaded( bool bUploaded ) = 0; + virtual void SetUploadURL( const char *pURL ) = 0; + virtual const char *GetUploadURL() const = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYMOVIE_H \ No newline at end of file diff --git a/common/replay/ireplaymoviemanager.h b/common/replay/ireplaymoviemanager.h new file mode 100644 index 0000000..40f605f --- /dev/null +++ b/common/replay/ireplaymoviemanager.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYMOVIEMANAGER_H +#define IREPLAYMOVIEMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "utlstring.h" +#include "utllinkedlist.h" +#include "replay/replayhandle.h" + +//---------------------------------------------------------------------------------------- + +class IReplayMovie; +class CReplay; +struct RenderMovieParams_t; +class IQueryableReplayItem; + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayMovieManager : public IBaseInterface +{ +public: + virtual int GetMovieCount() = 0; + virtual void GetMovieList( CUtlLinkedList< IReplayMovie * > &list ) = 0; // Fills the list with all movies + virtual IReplayMovie *GetMovie( ReplayHandle_t hMovie ) = 0; + virtual IReplayMovie *CreateAndAddMovie( ReplayHandle_t hReplay ) = 0; // Creates and adds a movie based on the given replay + virtual void DeleteMovie( ReplayHandle_t hMovie ) = 0; // Delete a movie + virtual int GetNumMoviesDependentOnReplay( const CReplay *pReplay ) = 0; // Get the number of movies that depend on the given replay + virtual void GetCachedMovieTitleAndClear( wchar_t *pOut, int nOutBufLength ) = 0; // TODO: This is a hack - fix this + virtual void SetPendingMovie( IReplayMovie *pMovie ) = 0; + virtual IReplayMovie *GetPendingMovie() = 0; + virtual void FlagMovieForFlush( IReplayMovie *pMovie, bool bImmediate ) = 0; + virtual void GetMoviesAsQueryableItems( CUtlLinkedList< IQueryableReplayItem *, int > &lstMovies ) = 0; + virtual const char *GetRenderDir() const = 0; + virtual const char *GetRawExportDir() const = 0; + + // TODO: Is this the best place for code that actually manages rendering? + virtual bool IsRendering() const = 0; + virtual bool RenderingCancelled() const = 0; + virtual void RenderMovie( RenderMovieParams_t const& params ) = 0; // Renders the given replay - or if params.hReplay is -1, render all unrendered replays + virtual void RenderNextMovie() = 0; + virtual void CompleteRender( bool bSuccess, bool bShowBrowser ) = 0; + virtual void CancelRender() = 0; + virtual void ClearRenderCancelledFlag() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYMOVIEMANAGER_H \ No newline at end of file diff --git a/common/replay/ireplaymovierenderer.h b/common/replay/ireplaymovierenderer.h new file mode 100644 index 0000000..e70835a --- /dev/null +++ b/common/replay/ireplaymovierenderer.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYMOVIERENDERER_H +#define IREPLAYMOVIERENDERER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +class IReplayMovie; +struct RenderMovieParams_t; + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayMovieRenderer : public IBaseInterface +{ +public: + virtual bool SetupRenderer( RenderMovieParams_t ¶ms, IReplayMovie *pMovie ) = 0; + virtual void ShutdownRenderer() = 0; + virtual void RenderVideo() = 0; + virtual void RenderAudio( unsigned char *pBuffer, int nSize, int nNumSamples ) = 0; + + virtual void SetAudioSyncFrame( bool isSync = false ) = 0; + virtual bool IsAudioSyncFrame() = 0; + virtual float GetRecordingFrameDuration() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYMOVIERENDERER_H diff --git a/common/replay/ireplayperformancecontroller.h b/common/replay/ireplayperformancecontroller.h new file mode 100644 index 0000000..70a119e --- /dev/null +++ b/common/replay/ireplayperformancecontroller.h @@ -0,0 +1,107 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYPERFORMANCECONTROLLER_H +#define IREPLAYPERFORMANCECONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "tier1/strtools.h" + +//---------------------------------------------------------------------------------------- + +class IReplayPerformanceEditor; +class CReplay; +class Vector; +class QAngle; +class CReplayPerformance; + +//---------------------------------------------------------------------------------------- + +// These values are what we use to represent + +struct SetViewParams_t +{ + SetViewParams_t() { V_memset( this, 0, sizeof( SetViewParams_t ) ); } + SetViewParams_t( float flTime, Vector *pOrigin, QAngle *pAngles, float flFov, float flAccel, + float flSpeed, float flRotFilter ) + : m_flTime( flTime ), + m_pOrigin( pOrigin ), + m_pAngles( pAngles ), + m_flFov( flFov ), + m_flAccel( flAccel ), + m_flSpeed( flSpeed ), + m_flRotationFilter( flRotFilter ) + { + } + + float m_flTime; + Vector *m_pOrigin; + QAngle *m_pAngles; + float m_flFov; + + // Right now only used for updating UI during playback: + float m_flAccel; + float m_flSpeed; + float m_flRotationFilter; +}; + +//---------------------------------------------------------------------------------------- + +class IReplayPerformanceController : public IBaseInterface +{ +public: + virtual void SetEditor( IReplayPerformanceEditor *pEditor ) = 0; + + virtual bool IsPlaybackDataLeft() = 0; + + virtual void StartRecording( CReplay *pReplay, bool bSnip ) = 0; + virtual void NotifyRewinding() = 0; + + virtual void Stop() = 0; + virtual bool SaveAsync() = 0; + virtual bool SaveAsAsync( const wchar *pTitle ) = 0; + + virtual bool IsSaving() const = 0; + + virtual void SaveThink() = 0; + + virtual bool GetLastSaveStatus() const = 0; + + virtual bool IsRecording() const = 0; + virtual bool IsPlaying() const = 0; + + virtual bool IsDirty() const = 0; + virtual void NotifyDirty() = 0; + + virtual CReplayPerformance *GetPerformance() = 0; + virtual CReplayPerformance *GetSavedPerformance() = 0; + virtual bool HasSavedPerformance() = 0; + + virtual void NotifyPauseState( bool bPaused ) = 0; + + virtual void ClearRewinding() = 0; + + virtual void OnSignonStateFull() = 0; + + virtual float GetPlaybackTimeScale() const = 0; + + // + // Recorder-specific: + // + virtual void AddEvent_Camera_Change_FirstPerson( float flTime, int nEntityIndex ) = 0; + virtual void AddEvent_Camera_Change_ThirdPerson( float flTime, int nEntityIndex ) = 0; + virtual void AddEvent_Camera_Change_Free( float flTime ) = 0; + virtual void AddEvent_Camera_ChangePlayer( float flTime, int nEntIndex ) = 0; + virtual void AddEvent_Camera_SetView( const SetViewParams_t ¶ms ) = 0; + virtual void AddEvent_TimeScale( float flTime, float flScale ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPERFORMANCECONTROLLER_H diff --git a/common/replay/ireplayperformanceeditor.h b/common/replay/ireplayperformanceeditor.h new file mode 100644 index 0000000..d1eff85 --- /dev/null +++ b/common/replay/ireplayperformanceeditor.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYPERFORMANCEEDITOR_H +#define IREPLAYPERFORMANCEEDITOR_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; + +//---------------------------------------------------------------------------------------- + +// +// Interface to allow the replay DLL to talk to the actual UI. +// +class IReplayPerformanceEditor : public IBaseInterface +{ +public: + virtual CReplay *GetReplay() = 0; + virtual void OnRewindComplete() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPERFORMANCEEDITOR_H diff --git a/common/replay/ireplayperformancemanager.h b/common/replay/ireplayperformancemanager.h new file mode 100644 index 0000000..67852dd --- /dev/null +++ b/common/replay/ireplayperformancemanager.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYPERFORMANCEMANAGER_H +#define IREPLAYPERFORMANCEMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CReplayPerformance; +class CReplay; + +//---------------------------------------------------------------------------------------- + +class IReplayPerformanceManager : public IBaseInterface +{ +public: + virtual CReplayPerformance *CreatePerformance( CReplay *pReplay ) = 0; + virtual void DeletePerformance( CReplayPerformance *pPerformance ) = 0; + + virtual const char *GetRelativePath() const = 0; + virtual const char *GetFullPath() const = 0; + + virtual const char *GeneratePerformanceFilename( CReplay *pReplay ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPERFORMANCEMANAGER_H diff --git a/common/replay/ireplayperformanceplaybackhandler.h b/common/replay/ireplayperformanceplaybackhandler.h new file mode 100644 index 0000000..2d3146f --- /dev/null +++ b/common/replay/ireplayperformanceplaybackhandler.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYPERFORMANCEPLAYBACKHANDLER_H +#define IREPLAYPERFORMANCEPLAYBACKHANDLER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/ireplayperformancecontroller.h" + +//---------------------------------------------------------------------------------------- + +class Vector; +class QAngle; + +//---------------------------------------------------------------------------------------- + +class IReplayPerformancePlaybackHandler : public IBaseInterface +{ +public: + virtual void OnEvent_Camera_Change_FirstPerson( float flTime, int nEntityIndex ) = 0; + virtual void OnEvent_Camera_Change_ThirdPerson( float flTime, int nEntityIndex ) = 0; + virtual void OnEvent_Camera_Change_Free( float flTime ) = 0; + virtual void OnEvent_Camera_ChangePlayer( float flTime, int nEntIndex ) = 0; + virtual void OnEvent_Camera_SetView( const SetViewParams_t ¶ms ) = 0; + virtual void OnEvent_TimeScale( float flTime, float flScale ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPERFORMANCEPLAYBACKHANDLER_H diff --git a/common/replay/ireplayperformanceplayer.h b/common/replay/ireplayperformanceplayer.h new file mode 100644 index 0000000..5739b18 --- /dev/null +++ b/common/replay/ireplayperformanceplayer.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYPERFORMANCEPLAYER_H +#define IREPLAYPERFORMANCEPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; +class CReplayPerformance; + +//---------------------------------------------------------------------------------------- + +class IReplayPerformancePlayer : public IBaseInterface +{ +public: + virtual void BeginPerformancePlay( CReplayPerformance *pPerformance ) = 0; + virtual void EndPerformancePlay() = 0; + + virtual bool IsPlaying() const = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPERFORMANCEPLAYER_H diff --git a/common/replay/ireplayperformancerecorder.h b/common/replay/ireplayperformancerecorder.h new file mode 100644 index 0000000..1274ab0 --- /dev/null +++ b/common/replay/ireplayperformancerecorder.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYPERFORMANCERECORDER_H +#define IREPLAYPERFORMANCERECORDER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; +class Vector; +class QAngle; +class CReplayPerformance; + +//---------------------------------------------------------------------------------------- + +class IReplayPerformanceRecorder : public IBaseInterface +{ +public: + virtual void BeginPerformanceRecord( CReplay *pReplay ) = 0; + virtual void EndPerformanceRecord() = 0; + + virtual void NotifyPauseState( bool bPaused ) = 0; + + virtual CReplayPerformance *GetPerformance() = 0; + virtual bool IsRecording() const = 0; + + virtual void SnipAtTime( float flTime ) = 0; + virtual void NotifySkipping() = 0; + virtual void ClearSkipping() = 0; + + virtual void AddEvent_Camera_Change_FirstPerson( float flTime, int nEntityIndex ) = 0; + virtual void AddEvent_Camera_Change_ThirdPerson( float flTime, int nEntityIndex ) = 0; + virtual void AddEvent_Camera_Change_Free( float flTime ) = 0; + virtual void AddEvent_Camera_ChangePlayer( float flTime, int nEntIndex ) = 0; + virtual void AddEvent_Camera_SetView( float flTime, const Vector& origin, const QAngle &angles, float fov ) = 0; + virtual void AddEvent_Slowmo( float flTime, float flScale ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPERFORMANCERECORDER_H diff --git a/common/replay/ireplayplayercache.h b/common/replay/ireplayplayercache.h new file mode 100644 index 0000000..c1a816f --- /dev/null +++ b/common/replay/ireplayplayercache.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef IREPLAYPLAYERCACHE_H +#define IREPLAYPLAYERCACHE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +#define REPLAYPLAYERCACHE_INTERFACE_VERSION "VENGINE_REPLAY_PLAYER_CACHE_001" + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayPlayerCache : public IBaseInterface +{ +public: + virtual bool Init() = 0; + virtual void Shutdown() = 0; + + virtual void SetupPlayer( int nEntIndex ) = 0; + virtual void DeletePlayerEntry( int nEntIndex ) = 0; + + virtual bool PlayerHasCacheEntry( int nEntIndex ) = 0; + + virtual void SetPlayerClass( int nEntIndex, const char *pPlayerClass ) = 0; + virtual void SetPlayerSpawnTick( int nEntIndex, int nTick ) = 0; + virtual void SetPlayerDeathTick( int nEntIndex, int nTick ) = 0; + + virtual const char *GetPlayerClass( int nEntIndex ) = 0; + virtual int GetPlayerSpawnTick( int nEntIndex ) = 0; + virtual int GetPlayerDeathTick( int nEntIndex ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYPLAYERCACHE_H diff --git a/common/replay/ireplayrenderqueue.h b/common/replay/ireplayrenderqueue.h new file mode 100644 index 0000000..320d90e --- /dev/null +++ b/common/replay/ireplayrenderqueue.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYRENDERQUEUE_H +#define IREPLAYRENDERQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replayhandle.h" + +//---------------------------------------------------------------------------------------- + +abstract_class IReplayRenderQueue : IBaseInterface +{ +public: + virtual void Add( ReplayHandle_t hReplay, int iPerformance ) = 0; + virtual void Remove( ReplayHandle_t hReplay, int iPerformance ) = 0; + virtual void Clear() = 0; + + virtual int GetCount() const = 0; + virtual bool GetEntryData( int iIndex, ReplayHandle_t *pHandleOut, int *pPerformanceOut ) const = 0; + virtual bool IsInQueue( ReplayHandle_t hReplay, int iPerformance ) const = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYRENDERQUEUE_H \ No newline at end of file diff --git a/common/replay/ireplayscreenshotmanager.h b/common/replay/ireplayscreenshotmanager.h new file mode 100644 index 0000000..8d73ac4 --- /dev/null +++ b/common/replay/ireplayscreenshotmanager.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYSCREENSHOTMANAGER_H +#define IREPLAYSCREENSHOTMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; +struct CaptureScreenshotParams_t; + +//---------------------------------------------------------------------------------------- + +class IReplayScreenshotManager : public IBaseInterface +{ +public: + virtual void CaptureScreenshot( CaptureScreenshotParams_t& params ) = 0; + virtual void GetUnpaddedScreenshotSize( int &nOutWidth, int &nOutHeight ) = 0; + virtual void DeleteScreenshotsForReplay( CReplay *pReplay ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYSCREENSHOTMANAGER_H diff --git a/common/replay/ireplayscreenshotsystem.h b/common/replay/ireplayscreenshotsystem.h new file mode 100644 index 0000000..82166a4 --- /dev/null +++ b/common/replay/ireplayscreenshotsystem.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYSCREENSHOTSYSTEM_H +#define IREPLAYSCREENSHOTSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +struct WriteReplayScreenshotParams_t; + +//---------------------------------------------------------------------------------------- + +// +// Implementation lives in the client - allows replay to tell the client to grab a +// screenshot or update the cache. +// +class IReplayScreenshotSystem : public IBaseInterface +{ +public: + virtual void WriteReplayScreenshot( WriteReplayScreenshotParams_t ¶ms ) = 0; + virtual void UpdateReplayScreenshotCache() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYSCREENSHOTSYSTEM_H \ No newline at end of file diff --git a/common/replay/ireplayserializeable.h b/common/replay/ireplayserializeable.h new file mode 100644 index 0000000..cc94628 --- /dev/null +++ b/common/replay/ireplayserializeable.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYSERIALIIZEABLE_H +#define IREPLAYSERIALIIZEABLE_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" +#include "replay/replayhandle.h" + +//---------------------------------------------------------------------------------------- + +class KeyValues; + +//---------------------------------------------------------------------------------------- + +class IReplaySerializeable : public IBaseInterface +{ +public: + virtual void SetHandle( ReplayHandle_t h ) = 0; + virtual ReplayHandle_t GetHandle() const = 0; + + virtual bool Read( KeyValues *pIn ) = 0; + virtual void Write( KeyValues *pOut ) = 0; + + virtual const char *GetSubKeyTitle() const = 0; + virtual const char *GetFilename() const = 0; + virtual const char *GetPath() const = 0; + + virtual const char *GetFullFilename() const = 0; + + virtual void SetLocked( bool bLocked ) = 0; + virtual bool IsLocked() const = 0; + + virtual void OnDelete() = 0; + virtual void OnUnload() = 0; + + virtual const char *GetDebugName() const = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYSERIALIIZEABLE_H \ No newline at end of file diff --git a/common/replay/ireplayserver.h b/common/replay/ireplayserver.h new file mode 100644 index 0000000..f2f4bf2 --- /dev/null +++ b/common/replay/ireplayserver.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef IREPLAYSERVER_H +#define IREPLAYSERVER_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "interface.h" + +//----------------------------------------------------------------------------- + +class IServer; +class IReplayDirector; +class IGameEvent; +struct netadr_s; +class CServerReplay; + +//----------------------------------------------------------------------------- +// Interface the Replay module exposes to the engine +//----------------------------------------------------------------------------- +#define INTERFACEVERSION_REPLAYSERVER "ReplayServer001" + +class IReplayServer : public IBaseInterface +{ +public: + virtual ~IReplayServer() {} + + virtual IServer *GetBaseServer() = 0; // get Replay base server interface + virtual IReplayDirector *GetDirector() = 0; // get director interface + virtual int GetReplaySlot() = 0; // return entity index-1 of Replay in game + virtual float GetOnlineTime() = 0; // seconds since broadcast started + virtual void BroadcastEvent(IGameEvent *event) = 0; // send a director command to all specs + virtual bool IsRecording() = 0; + virtual void StartRecording() = 0; + virtual void StopRecording() = 0; +}; + +#endif diff --git a/common/replay/ireplaysessionrecorder.h b/common/replay/ireplaysessionrecorder.h new file mode 100644 index 0000000..6c5f905 --- /dev/null +++ b/common/replay/ireplaysessionrecorder.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYSESSIONRECORDER_H +#define IREPLAYSESSIONRECORDER_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class IReplaySessionRecorder : public IBaseInterface +{ +public: + virtual void StartRecording() = 0; + virtual void StopRecording( bool bAborting ) = 0; + virtual void SetCurrentRecordingStartTick( int nStartTick ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYSESSIONRECORDER_H \ No newline at end of file diff --git a/common/replay/ireplaysystem.h b/common/replay/ireplaysystem.h new file mode 100644 index 0000000..0f46883 --- /dev/null +++ b/common/replay/ireplaysystem.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef IREPLAYSYSTEM_H +#define IREPLAYSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "appframework/IAppSystem.h" + +//---------------------------------------------------------------------------------------- + +class IClientReplayContext; +class IServerReplayContext; +class IGameEvent; + +//---------------------------------------------------------------------------------------- + +abstract_class IReplaySystem : public IAppSystem +{ +public: + // IAppSystem: + virtual bool Connect( CreateInterfaceFn fnFactory ) = 0; + virtual void Disconnect() = 0; + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + // To be called client- & server-side + virtual void Think() = 0; + virtual bool IsReplayEnabled() = 0; + virtual bool IsRecording() = 0; + + // To be called client-side only - on dedicated servers, only subs defined + virtual bool CL_Init( CreateInterfaceFn fnClientFactory ) = 0; + virtual void CL_Shutdown() = 0; + virtual void CL_Render() = 0; + virtual IClientReplayContext *CL_GetContext() = 0; + + // To be called server-side only + virtual bool SV_Init( CreateInterfaceFn fnFactory ) = 0; + virtual void SV_Shutdown() = 0; + virtual void SV_EndRecordingSession( bool bForceSynchronousPublish = false ) = 0; + virtual void SV_SendReplayEvent( const char *pEventName, int nClientSlot ) = 0; + virtual void SV_SendReplayEvent( IGameEvent *pEvent, int nClientSlot ) = 0; + virtual bool SV_ShouldBeginRecording( bool bIsInWaitingForPlayers ) = 0; + virtual void SV_NotifyReplayRequested() = 0; + virtual IServerReplayContext *SV_GetContext() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#define REPLAY_INTERFACE_VERSION "ReplaySystem001" + +//---------------------------------------------------------------------------------------- + +#endif // IREPLAYSYSTEM_H \ No newline at end of file diff --git a/common/replay/iserverengine.h b/common/replay/iserverengine.h new file mode 100644 index 0000000..f4cd329 --- /dev/null +++ b/common/replay/iserverengine.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef ISERVERENGINE_H +#define ISERVERENGINE_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +class IReplayServerEngine : public IBaseInterface +{ +public: + virtual void EndReplayRecordingSession() = 0; + virtual bool IsReplayRecording() = 0; + virtual bool IsReplay() = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // ISERVERENGINE_H \ No newline at end of file diff --git a/common/replay/iserverreplay.h b/common/replay/iserverreplay.h new file mode 100644 index 0000000..3ab5c7f --- /dev/null +++ b/common/replay/iserverreplay.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef ISERVERREPLAY_H +#define ISERVERREPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "interface.h" + +//---------------------------------------------------------------------------------------- + +#define SERVER_REPLAY_INTERFACE_VERSION "ServerReplay001" + +//---------------------------------------------------------------------------------------- + +class IReplayFactory; +class KeyValues; + +//---------------------------------------------------------------------------------------- + +// +// Allows the replay DLL to talk to the server +// +class IServerReplay : public IBaseInterface +{ +public: + virtual void UploadOgsData( KeyValues *pData, bool bIncludeTimeField ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // ISERVERREPLAY_H \ No newline at end of file diff --git a/common/replay/iserverreplaycontext.h b/common/replay/iserverreplaycontext.h new file mode 100644 index 0000000..2437c76 --- /dev/null +++ b/common/replay/iserverreplaycontext.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef ISERVERREPLAYCONTEXT_H +#define ISERVERREPLAYCONTEXT_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "replay/ireplaycontext.h" + +//---------------------------------------------------------------------------------------- + +class IGameEvent; +class IReplaySessionRecorder; + +//---------------------------------------------------------------------------------------- + +#define REPLAYHISTORYMANAGER_INTERFACE_VERSION_SERVER "VENGINE_SERVER_REPLAY_HISTORY_MANAGER_001" + +//---------------------------------------------------------------------------------------- + +class IServerReplayContext : public IReplayContext +{ +public: + virtual void FlagForConVarSanityCheck() = 0; // Checks replay_enable / replay_local_fileserver_path / replay_downloadurlport / replay_downloadurlpath + virtual IGameEvent *CreateReplaySessionInfoEvent() = 0; // Create "replay_sessioninfo" event w/ appropriate fields filled in + virtual IReplaySessionRecorder *GetSessionRecorder() = 0; + virtual const char *GetLocalFileServerPath() const = 0; // Returns the local path where session blocks and such should be published for download + virtual void CreateSessionOnClient( int nClientSlot ) = 0; +}; + +//---------------------------------------------------------------------------------------- + +#endif // ISERVERREPLAYCONTEXT_H diff --git a/common/replay/performance.h b/common/replay/performance.h new file mode 100644 index 0000000..a38e116 --- /dev/null +++ b/common/replay/performance.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYPERFORMANCE_H +#define REPLAYPERFORMANCE_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "shared_defs.h" +#include "qlimits.h" + +//---------------------------------------------------------------------------------------- + +class CReplay; +class KeyValues; + +//---------------------------------------------------------------------------------------- + +class CReplayPerformance +{ +public: + CReplayPerformance( CReplay *pReplay ); + + inline bool HasInTick() const { return m_nTickIn >= 0; } + inline bool HasOutTick() const { return m_nTickOut >= 0; } + + inline int GetTickIn() const { return m_nTickIn; } + inline int GetTickOut() const { return m_nTickOut; } + + void Copy( const CReplayPerformance *pSrc ); + void CopyTicks( const CReplayPerformance *pSrc ); + + void SetFilename( const char *pFilename ); + const char *GetFullPerformanceFilename(); + + void AutoNameIfHasNoTitle( const char *pMapName ); + void SetTitle( const wchar_t *pTitle ); + + // NOTE: Doesn't copy exactly - gets a valid filename for the returned performance. + CReplayPerformance *MakeCopy() const; + + void Read( KeyValues *pIn ); + void Write( KeyValues *pOut ); + + // NOTE: Any changes made here should be reflected in the copy constructor + // (which is called from MakeCopy()). + wchar_t m_wszTitle[MAX_TAKE_TITLE_LENGTH]; + char m_szBaseFilename[ MAX_OSPATH ]; + CReplay *m_pReplay; + int m_nTickIn; + int m_nTickOut; + +private: + CReplayPerformance( const CReplayPerformance *pPerformance ); +}; + +//---------------------------------------------------------------------------------------- + +#endif // REPLAYPERFORMANCE_H \ No newline at end of file diff --git a/common/replay/rendermovieparams.h b/common/replay/rendermovieparams.h new file mode 100644 index 0000000..2a344d5 --- /dev/null +++ b/common/replay/rendermovieparams.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef RENDERMOVIEPARAMS_H +#define RENDERMOVIEPARAMS_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "tier1/utlstring.h" +#include "tier1/strtools.h" +#include "replay/replayhandle.h" +#include "replay/shared_defs.h" +#include "video/ivideoservices.h" + +//---------------------------------------------------------------------------------------- + +typedef unsigned int MovieHandle_t; + +struct RenderMovieParams_t +{ + inline RenderMovieParams_t() : m_iPerformance( -1 ) { V_memset( this, 0, sizeof( RenderMovieParams_t ) ); m_Settings.m_FPS.SetFPS( 0, false ); } + + ReplayHandle_t m_hReplay; + int m_iPerformance; // -1 for default view, otherwise this is an index into the replay's m_vecPerformances vector. + wchar_t m_wszTitle[MAX_REPLAY_TITLE_LENGTH]; + char m_szVideoPreset[64]; + char m_szExtension[16]; // File extension + bool m_bQuitWhenFinished; + bool m_bExportRaw; // Export movie as raw TGA frames and a .WAV + float m_flEngineFps; + + struct ReplayRenderSettings_t + { + uint16 m_nWidth; + uint16 m_nHeight; + int8 m_nMotionBlurQuality; // [0,MAX_MOTION_BLUR_QUALITY] + VideoFrameRate_t m_FPS; // Actual framerate can be calculated with m_FPS.GetFps() + VideoEncodeCodec_t m_Codec; + bool m_bMotionBlurEnabled; // Motion blur enabled? + bool m_bAAEnabled; // Antialiasing enabled? + int8 m_nEncodingQuality; // [0,100] + bool m_bRaw; // This movie was exported as raw TGA frames and a .WAV file? + } + m_Settings; +}; + +typedef RenderMovieParams_t::ReplayRenderSettings_t ReplayRenderSettings_t; + +//---------------------------------------------------------------------------------------- + +#define MAX_DOF_QUALITY 2 +#define MAX_MOTION_BLUR_QUALITY 3 +#define SUBPIXEL_JITTER_SAMPLES 16 +#define CHEAP_DOF_SAMPLES 4 + +//---------------------------------------------------------------------------------------- + +#endif // RENDERMOVIEPARAMS_H diff --git a/common/replay/replay.h b/common/replay/replay.h new file mode 100644 index 0000000..a0d1cb3 --- /dev/null +++ b/common/replay/replay.h @@ -0,0 +1,146 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAY_H +#define REPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "replay/iqueryablereplayitem.h" +#include "replay/replaytime.h" +#include "replay/basereplayserializeable.h" +#include "qlimits.h" +#include "utlstring.h" +#include "utlvector.h" +#include "replay/shared_defs.h" + +//---------------------------------------------------------------------------------------- + +class IReplayDownloadEventHandler; +class CReplayScreenshot; +class CReplayPerformance; + +//---------------------------------------------------------------------------------------- + +class CReplay : public CBaseReplaySerializeable, + public IQueryableReplayItem +{ + typedef CBaseReplaySerializeable BaseClass; + +public: + enum ReplayStatus_t + { + REPLAYSTATUS_INVALID, + REPLAYSTATUS_ERROR, + REPLAYSTATUS_DOWNLOADPHASE, // Multiple sub-states during download state + REPLAYSTATUS_READYTOCONVERT, // Download is complete, ready to convert + REPLAYSTATUS_RENDERING, // Currently rendering the file + REPLAYSTATUS_RENDERED, + REPLAYSTATUS_MAX + }; + + CReplay(); + virtual ~CReplay() {} + + // + // IReplaySerializeable + // + virtual const char *GetSubKeyTitle() const; + virtual const char *GetPath() const; + virtual void OnDelete(); + virtual bool Read( KeyValues *pIn ); + virtual void Write( KeyValues *pOut ); + + virtual void DumpGameSpecificData() const {} + + virtual void Update() {} + + // Hooks to allow replays to setup event listeners, etc. + virtual void OnBeginRecording() {} + virtual void OnEndRecording() {} + + // Called when a replay is "completed" + virtual void OnComplete(); + + // Should we allow this replay to be deleted? + virtual bool ShouldAllowDelete() const { return true; } + + void AutoNameTitleIfEmpty(); + + void AddScreenshot( int nWidth, int nHeight, const char *pBaseFilename ); + + bool HasReconstructedReplay() const; + bool IsSignificantBlock( int iBlockReconstruction ) const; // Does this replay care about the given block? + + CReplayPerformance *AddNewPerformance( bool bGenTitle = true, bool bGenFilename = true ); + void AddPerformance( KeyValues *pIn ); + void AddPerformance( CReplayPerformance *pPerformance ); + + // Accessors: + inline int GetScreenshotCount() const { return m_vecScreenshots.Count(); } + inline const CReplayScreenshot *GetScreenshot( int i ) const { return m_vecScreenshots[ i ]; } + bool IsDownloaded() const; + inline int GetPerformanceCount() const { return m_vecPerformances.Count(); } + CReplayPerformance *GetPerformance( int i ); + const CReplayPerformance *GetPerformance( int i ) const; + inline bool HasPerformance( CReplayPerformance *pPerformance ) { return m_vecPerformances.Find( pPerformance ) != m_vecPerformances.InvalidIndex(); } + bool FindPerformance( CReplayPerformance *pPerformance, int &iResult ); + CReplayPerformance *GetPerformanceWithTitle( const wchar_t *pTitle ); + inline const char *GetMapName() const { return m_szMapName; } + inline int GetSpawnTick() const { return m_nSpawnTick; } + inline int GetDeathTick() const { return m_nDeathTick; } + + // IQueryableReplayItem implementation: + virtual const CReplayTime &GetItemDate() const; + virtual bool IsItemRendered() const; + virtual CReplay *GetItemReplay(); + virtual ReplayHandle_t GetItemReplayHandle() const; + virtual QueryableReplayItemHandle_t GetItemHandle() const; + virtual const wchar_t *GetItemTitle() const; + virtual void SetItemTitle( const wchar_t *pTitle ); + virtual float GetItemLength() const; + virtual void *GetUserData(); + virtual void SetUserData( void* pUserData ); + virtual bool IsItemAMovie() const; + + // Non-persistent data + mutable IReplayDownloadEventHandler *m_pDownloadEventHandler; // Implemented by replay browser - the reason we've got one per replay rather than + // one per download group is because the browser needs to receive events per-thumbnail + bool m_bSaved; // True as soon as the replay is saved to disk for the first time + bool m_bRequestedByUser; // Did the user request to save this replay? + bool m_bComplete; // Indicates whether the replay is done recording - this should be false + // until the player dies, the round ends, or the level changes + void *m_pUserData; + float m_flNextUpdateTime; + bool m_bDirty; + + // Persistent data + ReplayHandle_t m_hSession; // The recording session in which this replay was recorded + char m_szMapName[MAX_OSPATH]; + ReplayStatus_t m_nStatus; + const char* m_pFileURL; // In the form ://:/path/file - points to the string in the download group + wchar_t m_wszTitle[MAX_REPLAY_TITLE_LENGTH]; + CUtlString m_strKilledBy; // Name of player who killed, if any + int m_nDeathTime; + int m_nSpawnTick; + int m_nDeathTick; + float m_flLength; // The length of the entire replay, including the post-death time, in seconds + bool m_bRendered; // Has the replay been rendered yet? + int m_nPlayerSlot; // Player slot (+1), used to determine which player recorded the demo during playback + int m_nPostDeathRecordTime; // replay_postdeathrecordtime at the time of record + CUtlVector< CReplayScreenshot * > m_vecScreenshots; + CUtlVector< CReplayPerformance * > m_vecPerformances; + int m_iMaxSessionBlockRequired; // The maximum session block required to reconstruct a viewable .dem file from spawn tick until length + CReplayTime m_RecordTime; // Contains time/date when spawn tick was recorded + float m_flStartTime; // Start time (uses engine's host_time) + CUtlString m_strReconstructedFilename; + bool m_bSavedDuringThisSession; +}; + +//---------------------------------------------------------------------------------------- + +#endif // REPLAY_H \ No newline at end of file diff --git a/common/replay/replayhandle.h b/common/replay/replayhandle.h new file mode 100644 index 0000000..2dd8414 --- /dev/null +++ b/common/replay/replayhandle.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYHANDLE_H +#define REPLAYHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "platform.h" + +//---------------------------------------------------------------------------------------- + +typedef uint32 ReplayHandle_t; + +//---------------------------------------------------------------------------------------- + +#define REPLAY_HANDLE_INVALID ( (ReplayHandle_t)-1 ) + +//---------------------------------------------------------------------------------------- + +#endif // REPLAYHANDLE_H \ No newline at end of file diff --git a/common/replay/replaylib.h b/common/replay/replaylib.h new file mode 100644 index 0000000..9f30980 --- /dev/null +++ b/common/replay/replaylib.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYLIB_H +#define REPLAYLIB_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +class IClientReplayContext; + +//---------------------------------------------------------------------------------------- + +bool ReplayLib_Init( const char *pGameDir, IClientReplayContext *pClientReplayContext ); + +//---------------------------------------------------------------------------------------- + +#endif // REPLAYLIB_H \ No newline at end of file diff --git a/common/replay/replaytime.h b/common/replay/replaytime.h new file mode 100644 index 0000000..eb1c329 --- /dev/null +++ b/common/replay/replaytime.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYTIME_H +#define REPLAYTIME_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +class KeyValues; + +//---------------------------------------------------------------------------------------- + +#include "vgui/ILocalize.h" + +//---------------------------------------------------------------------------------------- + +class CReplayTime +{ +public: + CReplayTime(); + + void InitDateAndTimeToNow(); + + void Read( KeyValues *pIn ); + void Write( KeyValues *pOut ); + + // Modifiers: + void SetDate( int nDay, int nMonth, int nYear ); + void SetTime( int nHour, int nMin, int nSec ); + inline void SetRawDate( int nRawDate ) { m_fDate = nRawDate; } + inline void SetRawTime( int nRawTime ) { m_fTime = nRawTime; } + + // Accessors: + void GetTime( int &nHour, int &nMin, int &nSec ) const; + void GetDate( int &nDay, int &nMonth, int &nYear ) const; + + static const char *FormatTimeString( int nSecs ); + static const char *FormatPreciseTimeString( float flSecs ); + static const wchar_t *GetLocalizedMonth( vgui::ILocalize *pLocalize, int nMonth ); + static const wchar_t *GetLocalizedDay( vgui::ILocalize *pLocalize, int nDay ); + static const wchar_t *GetLocalizedYear( vgui::ILocalize *pLocalize, int nYear ); + static const wchar_t *GetLocalizedTime( vgui::ILocalize *pLocalize, int nHour, int nMin, int nSec ); + static const wchar_t *GetLocalizedDate( vgui::ILocalize *pLocalize, int nDay, int nMonth, int nYear, + int *pHour = NULL, int *pMin = NULL, int *pSec = NULL, bool bForceFullFormat = false ); // bForceFullFormat true will keep from returning "today" or "yesterday" + static const wchar_t *GetLocalizedDate( vgui::ILocalize *pLocalize, const CReplayTime &t, bool bForceFullFormat = false ); + + int m_fDate; // Representation of a date (bitfield) + int m_fTime; // Representation of time (bitfield) +}; + +//---------------------------------------------------------------------------------------- + +#endif // REPLAYTIME_H \ No newline at end of file diff --git a/common/replay/replayutils.h b/common/replay/replayutils.h new file mode 100644 index 0000000..0add85a --- /dev/null +++ b/common/replay/replayutils.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef REPLAYUTILS_H +#define REPLAYUTILS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlstring.h" + +void Replay_GetFirstAvailableFilename( char *pDst, int nDstLen, const char *pIdealFilename, const char *pExt, + const char *pFilePath, int nStartIndex ); + +void Replay_ConstructReplayFilenameString( CUtlString &strOut, const char *pReplaySubDir, const char *pFilename, const char *pGameDir ); + +//---------------------------------------------------------------------------------------- +// Util function, copied from src/engine/common.cpp +//---------------------------------------------------------------------------------------- +char *Replay_va( PRINTF_FORMAT_STRING const char *format, ... ); + +//---------------------------------------------------------------------------------------- +// Return the base dir, e.g. "c:\...\game\tf\replays\" +//---------------------------------------------------------------------------------------- +const char *Replay_GetBaseDir(); + +//---------------------------------------------------------------------------------------- +// Set the game directory (only to be called from ReplayLib_Init()) +//---------------------------------------------------------------------------------------- +void Replay_SetGameDir( const char *pGameDir ); + +//---------------------------------------------------------------------------------------- +// Return the base dir, e.g. "c:\...\game\tf\replays\" +//---------------------------------------------------------------------------------------- +const char *Replay_GetGameDir(); + +//---------------------------------------------------------------------------------------- +// Get a name of the format ": " - used for replays and takes. +//---------------------------------------------------------------------------------------- +void Replay_GetAutoName( OUT_Z_BYTECAP(nDestSizeInBytes) wchar_t *pDest, int nDestSizeInBytes, const char *pMapName ); + +#endif // REPLAY_H diff --git a/common/replay/screenshot.h b/common/replay/screenshot.h new file mode 100644 index 0000000..c71bbe1 --- /dev/null +++ b/common/replay/screenshot.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef SCREENSHOT_H +#define SCREENSHOT_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "replay/basereplayserializeable.h" +#include "mathlib/vector.h" +#include "qlimits.h" +#include "strtools.h" + +//---------------------------------------------------------------------------------------- + +#define SUBDIR_SCREENSHOTS "screenshots" + +//---------------------------------------------------------------------------------------- + +class CReplayScreenshot : public CBaseReplaySerializeable +{ +public: + inline CReplayScreenshot( int nWidth = 0, int nHeight = 0, const char *pBaseFilename = NULL ) + : m_nWidth( nWidth ), m_nHeight( nHeight ) + { + if ( pBaseFilename ) + { + V_strncpy( m_szBaseFilename, pBaseFilename, sizeof( m_szBaseFilename ) ); + } + } + + virtual bool Read( KeyValues *pIn ); + virtual void Write( KeyValues *pOut ); + virtual const char *GetSubKeyTitle() const; + virtual const char *GetPath() const; + + int m_nWidth; // Screenshot width (does not include power-of-2 padding) + int m_nHeight; // Screenshot height (does not include power-of-2 padding) + char m_szBaseFilename[ MAX_OSPATH ]; +}; + +//---------------------------------------------------------------------------------------- + +struct CaptureScreenshotParams_t // To be passed from the client into IReplayHistoryManager::CaptureScreenshot() +{ + float m_flDelay; // Delay from now (in seconds) when we will take the screenshot + int m_nEntity; // Should be 0 if no camera adjustment is needed, otherwise should be the index of the entity index from which m_posCamera will be based + Vector m_posCamera; // Local position, relative to entity's index (if m_nEntity > 0) for camera position + QAngle m_angCamera; // World angles of camera - used if m_bUseCameraAngles is true + bool m_bUseCameraAngles; // Should we use m_angCamera - m_nEntity can't be 0 + bool m_bIgnoreMinTimeBetweenScreenshots; // Force screenshot, regardless of replay_mintimebetweenscreenshots? + bool m_bPrimary; // Only set to true for the primary screenshot, which is taken when the user saves their replay +}; + +//---------------------------------------------------------------------------------------- + +struct WriteReplayScreenshotParams_t // Passed from the engine into the client to take a screenshot +{ + const char *m_pFilename; + int m_nWidth; + int m_nHeight; + Vector *m_pOrigin; // Perspective origin from which to render. Can be NULL + QAngle *m_pAngles; // Perspective angles from which to render. Can be NULL +}; + +//---------------------------------------------------------------------------------------- + +#endif // SCREENSHOT_H diff --git a/common/replay/shared_defs.h b/common/replay/shared_defs.h new file mode 100644 index 0000000..fa4b0b7 --- /dev/null +++ b/common/replay/shared_defs.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef SHARED_DEFS_H +#define SHARED_DEFS_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "platform.h" + +//---------------------------------------------------------------------------------------- + +#define SUBDIR_REPLAY "replay" +#define SUBDIR_REPLAYS "replays" +#define SUBDIR_SESSIONS "sessions" +#define SUBDIR_BLOCKS "blocks" +#define SUBDIR_CLIENT "client" +#define SUBDIR_MOVIES "movies" +#define SUBDIR_PERFORMANCES "edits" +#define SUBDIR_SERVER "server" +#define SUBDIR_RENDERED "rendered" +#define SUBDIR_TMP "tmp" + +//---------------------------------------------------------------------------------------- + +#define BLOCK_FILE_EXTENSION "block" +#define GENERIC_FILE_EXTENSION "dmx" +#define DEMO_FILE_EXTENSION "dem" + +//---------------------------------------------------------------------------------------- + +#define MOVIE_HANDLE_BASE 10000 // 10,000 + +//---------------------------------------------------------------------------------------- + +#define BUILD_CURL ( defined( WIN32 ) && !defined( _X360 ) ) || defined( POSIX ) + +//---------------------------------------------------------------------------------------- + +#define MIN_SERVER_DUMP_INTERVAL 10 +#define MAX_SERVER_DUMP_INTERVAL 30 + +#define DOWNLOAD_TIMEOUT_THRESHOLD 90 // Timeout for a replay download - if no blocks + // are added or updated after this many seconds, + // the replay will be put in the error state. + +//---------------------------------------------------------------------------------------- + +#define MAX_TIMES_TO_SHOW_REPLAY_WELCOME_DLG 1 + +//---------------------------------------------------------------------------------------- + +#define MAX_SESSIONNAME_LENGTH 260 +#define MAX_REPLAY_TITLE_LENGTH 256 +#define MAX_TAKE_TITLE_LENGTH 256 + +//---------------------------------------------------------------------------------------- + +#define DEFAULT_COMPRESSOR_TYPE COMPRESSORTYPE_BZ2 + +//---------------------------------------------------------------------------------------- + +#define JOB_FAILED ( (JobStatus_t) -1 ) + +#define DOWNLOAD_MAX_SIZE ( 8 * 1024 * 1024 ) // 8 MB + +//---------------------------------------------------------------------------------------- + +#endif // SHARED_DEFS_H diff --git a/common/studiobyteswap.h b/common/studiobyteswap.h new file mode 100644 index 0000000..3bec9ea --- /dev/null +++ b/common/studiobyteswap.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: StudioMDL byteswapping functions. +// +// $NoKeywords: $ +//============================================================================= +#ifndef STUDIOBYTESWAP_H +#define STUDIOBYTESWAP_H + +#if defined(_WIN32) +#pragma once +#endif + +#include "byteswap.h" +struct studiohdr_t; +class IPhysicsCollision; + +namespace StudioByteSwap +{ +typedef bool (*CompressFunc_t)( const void *pInput, int inputSize, void **pOutput, int *pOutputSize ); + +//void SetTargetBigEndian( bool bigEndian ); +void ActivateByteSwapping( bool bActivate ); +void SourceIsNative( bool bActivate ); +void SetVerbose( bool bVerbose ); +void SetCollisionInterface( IPhysicsCollision *pPhysicsCollision ); + +int ByteswapStudioFile( const char *pFilename, void *pOutBase, const void *pFileBase, int fileSize, studiohdr_t *pHdr, CompressFunc_t pCompressFunc = NULL ); +int ByteswapPHY( void *pOutBase, const void *pFileBase, int fileSize ); +int ByteswapANI( studiohdr_t* pHdr, void *pOutBase, const void *pFileBase, int filesize ); +int ByteswapVVD( void *pOutBase, const void *pFileBase, int fileSize ); +int ByteswapVTX( void *pOutBase, const void *pFileBase, int fileSize ); +int ByteswapMDL( void *pOutBase, const void *pFileBase, int fileSize ); + +#define BYTESWAP_ALIGNMENT_PADDING 4096 +} + +#endif // STUDIOBYTESWAP_H \ No newline at end of file diff --git a/common/userid.h b/common/userid.h new file mode 100644 index 0000000..6152f20 --- /dev/null +++ b/common/userid.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef USERID_H +#define USERID_H +#ifdef _WIN32 +#pragma once +#endif + +#include "strtools.h" +#include "steam/steamclientpublic.h" +#if !defined( INCLUDED_STEAM_STEAMUSERIDTYPES_H ) +#define INCLUDED_STEAM2_USERID_STRUCTS +#include "SteamCommon.h" +#endif + +#define IDTYPE_WON 0 +#define IDTYPE_STEAM 1 +#define IDTYPE_VALVE 2 +#define IDTYPE_HLTV 3 +#define IDTYPE_REPLAY 4 +typedef struct USERID_s +{ + int idtype; + CSteamID steamid; +} USERID_t; + +#endif // USERID_H diff --git a/common/xbox/xboxstubs.h b/common/xbox/xboxstubs.h new file mode 100644 index 0000000..fa3448f --- /dev/null +++ b/common/xbox/xboxstubs.h @@ -0,0 +1,237 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Win32 replacements for XBox. +// +//============================================================================= + +#if !defined( XBOXSTUBS_H ) && !defined( _X360 ) +#define XBOXSTUBS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// Content creation/open flags +#define XCONTENTFLAG_NONE 0x00 +#define XCONTENTFLAG_CREATENEW 0x00 +#define XCONTENTFLAG_CREATEALWAYS 0x00 +#define XCONTENTFLAG_OPENEXISTING 0x00 +#define XCONTENTFLAG_OPENALWAYS 0x00 +#define XCONTENTFLAG_TRUNCATEEXISTING 0x00 + +// Content attributes +#define XCONTENTFLAG_NOPROFILE_TRANSFER 0x00 +#define XCONTENTFLAG_NODEVICE_TRANSFER 0x00 +#define XCONTENTFLAG_STRONG_SIGNED 0x00 +#define XCONTENTFLAG_ALLOWPROFILE_TRANSFER 0x00 +#define XCONTENTFLAG_MOVEONLY_TRANSFER 0x00 + +// Console device ports +#define XDEVICE_PORT0 0 +#define XDEVICE_PORT1 1 +#define XDEVICE_PORT2 2 +#define XDEVICE_PORT3 3 +#define XUSER_MAX_COUNT 4 +#define XUSER_INDEX_NONE 0x000000FE + +#define XBX_CLR_DEFAULT 0xFF000000 +#define XBX_CLR_WARNING 0x0000FFFF +#define XBX_CLR_ERROR 0x000000FF + +#define XBOX_MINBORDERSAFE 0 +#define XBOX_MAXBORDERSAFE 0 + +typedef enum +{ + XK_NULL, + XK_BUTTON_UP, + XK_BUTTON_DOWN, + XK_BUTTON_LEFT, + XK_BUTTON_RIGHT, + XK_BUTTON_START, + XK_BUTTON_BACK, + XK_BUTTON_STICK1, + XK_BUTTON_STICK2, + XK_BUTTON_A, + XK_BUTTON_B, + XK_BUTTON_X, + XK_BUTTON_Y, + XK_BUTTON_LEFT_SHOULDER, + XK_BUTTON_RIGHT_SHOULDER, + XK_BUTTON_LTRIGGER, + XK_BUTTON_RTRIGGER, + XK_STICK1_UP, + XK_STICK1_DOWN, + XK_STICK1_LEFT, + XK_STICK1_RIGHT, + XK_STICK2_UP, + XK_STICK2_DOWN, + XK_STICK2_LEFT, + XK_STICK2_RIGHT, + XK_MAX_KEYS, +} xKey_t; + +//typedef enum +//{ +// XVRB_NONE, // off +// XVRB_ERROR, // fatal error +// XVRB_ALWAYS, // no matter what +// XVRB_WARNING, // non-fatal warnings +// XVRB_STATUS, // status reports +// XVRB_ALL, +//} xverbose_e; + +typedef unsigned short WORD; +#ifndef POSIX +typedef unsigned long DWORD; +typedef void* HANDLE; +typedef unsigned __int64 ULONGLONG; +#endif + +#ifdef POSIX +typedef DWORD COLORREF; +#endif + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#endif + +// typedef struct { +// IN_ADDR ina; // IP address (zero if not static/DHCP) +// IN_ADDR inaOnline; // Online IP address (zero if not online) +// WORD wPortOnline; // Online port +// BYTE abEnet[6]; // Ethernet MAC address +// BYTE abOnline[20]; // Online identification +// } XNADDR; + +typedef int XNADDR; +typedef uint64 XUID; + +typedef struct { + BYTE ab[8]; // xbox to xbox key identifier +} XNKID; + +typedef struct { + BYTE ab[16]; // xbox to xbox key exchange key +} XNKEY; + +typedef struct _XSESSION_INFO +{ + XNKID sessionID; // 8 bytes + XNADDR hostAddress; // 36 bytes + XNKEY keyExchangeKey; // 16 bytes +} XSESSION_INFO, *PXSESSION_INFO; + +typedef struct _XUSER_DATA +{ + BYTE type; + + union + { + int nData; // XUSER_DATA_TYPE_INT32 + int64 i64Data; // XUSER_DATA_TYPE_INT64 + double dblData; // XUSER_DATA_TYPE_DOUBLE + struct // XUSER_DATA_TYPE_UNICODE + { + uint cbData; // Includes null-terminator + char * pwszData; + } string; + float fData; // XUSER_DATA_TYPE_FLOAT + struct // XUSER_DATA_TYPE_BINARY + { + uint cbData; + char * pbData; + } binary; + }; +} XUSER_DATA, *PXUSER_DATA; + +typedef struct _XUSER_PROPERTY +{ + DWORD dwPropertyId; + XUSER_DATA value; +} XUSER_PROPERTY, *PXUSER_PROPERTY; + +typedef struct _XUSER_CONTEXT +{ + DWORD dwContextId; + DWORD dwValue; +} XUSER_CONTEXT, *PXUSER_CONTEXT; + +typedef struct _XSESSION_SEARCHRESULT +{ + XSESSION_INFO info; + DWORD dwOpenPublicSlots; + DWORD dwOpenPrivateSlots; + DWORD dwFilledPublicSlots; + DWORD dwFilledPrivateSlots; + DWORD cProperties; + DWORD cContexts; + PXUSER_PROPERTY pProperties; + PXUSER_CONTEXT pContexts; +} XSESSION_SEARCHRESULT, *PXSESSION_SEARCHRESULT; + +typedef struct _XSESSION_SEARCHRESULT_HEADER +{ + DWORD dwSearchResults; + XSESSION_SEARCHRESULT *pResults; +} XSESSION_SEARCHRESULT_HEADER, *PXSESSION_SEARCHRESULT_HEADER; + +typedef struct _XSESSION_REGISTRANT +{ + uint64 qwMachineID; + DWORD bTrustworthiness; + DWORD bNumUsers; + XUID *rgUsers; + +} XSESSION_REGISTRANT; + +typedef struct _XSESSION_REGISTRATION_RESULTS +{ + DWORD wNumRegistrants; + XSESSION_REGISTRANT *rgRegistrants; +} XSESSION_REGISTRATION_RESULTS, *PXSESSION_REGISTRATION_RESULTS; + +typedef struct { + BYTE bFlags; + BYTE bReserved; + WORD cProbesXmit; + WORD cProbesRecv; + WORD cbData; + BYTE * pbData; + WORD wRttMinInMsecs; + WORD wRttMedInMsecs; + DWORD dwUpBitsPerSec; + DWORD dwDnBitsPerSec; +} XNQOSINFO; + +typedef struct { + uint cxnqos; + uint cxnqosPending; + XNQOSINFO axnqosinfo[1]; +} XNQOS; + +#define XSESSION_CREATE_HOST 0 +#define XUSER_DATA_TYPE_INT32 0 +#define XSESSION_CREATE_USES_ARBITRATION 0 +#define XNET_QOS_LISTEN_ENABLE 0 +#define XNET_QOS_LISTEN_DISABLE 0 +#define XNET_QOS_LISTEN_SET_DATA 0 + +FORCEINLINE void XBX_ProcessEvents() {} +FORCEINLINE unsigned int XBX_GetSystemTime() { return 0; } +FORCEINLINE int XBX_GetPrimaryUserId() { return 0; } +FORCEINLINE void XBX_SetPrimaryUserId( DWORD idx ) {} +FORCEINLINE int XBX_GetStorageDeviceId() { return 0; } +FORCEINLINE void XBX_SetStorageDeviceId( DWORD idx ) {} +FORCEINLINE const char *XBX_GetLanguageString() { return ""; } +FORCEINLINE bool XBX_IsLocalized() { return false; } + +#define XCONTENT_MAX_DISPLAYNAME_LENGTH 128 +#define XCONTENT_MAX_FILENAME_LENGTH 42 + +#define XBX_INVALID_STORAGE_ID ((DWORD) -1) +#define XBX_STORAGE_DECLINED ((DWORD) -2) + +#endif // XBOXSTUBS_H diff --git a/game/client/C_Env_Projected_Texture.h b/game/client/C_Env_Projected_Texture.h new file mode 100644 index 0000000..b15ea6e --- /dev/null +++ b/game/client/C_Env_Projected_Texture.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENVPROJECTEDTEXTURE_H +#define C_ENVPROJECTEDTEXTURE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "basetypes.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_EnvProjectedTexture : public C_BaseEntity +{ + DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_EnvProjectedTexture(); + ~C_EnvProjectedTexture(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + void ShutDownLightHandle( void ); + + virtual void Simulate(); + + void UpdateLight( bool bForceUpdate ); + + bool ShadowsEnabled(); + + float GetFOV(); + +private: + + ClientShadowHandle_t m_LightHandle; + + EHANDLE m_hTargetEntity; + + bool m_bState; + float m_flLightFOV; + bool m_bEnableShadows; + bool m_bLightOnlyTarget; + bool m_bLightWorld; + bool m_bCameraSpace; + color32 m_cLightColor; + float m_flAmbient; + char m_SpotlightTextureName[ MAX_PATH ]; + int m_nSpotlightTextureFrame; + int m_nShadowQuality; + bool m_bCurrentShadow; + +public: + C_EnvProjectedTexture *m_pNext; +}; + +C_EnvProjectedTexture* GetEnvProjectedTextureList(); + +#endif // C_ENVPROJECTEDTEXTURE_H diff --git a/game/client/ScreenSpaceEffects.h b/game/client/ScreenSpaceEffects.h new file mode 100644 index 0000000..a93fa22 --- /dev/null +++ b/game/client/ScreenSpaceEffects.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=====================================================================================// + +#ifndef SCREENSPACEEFFECTS_H +#define SCREENSPACEEFFECTS_H + +#ifdef _WIN32 +#pragma once +#endif + +class KeyValues; + + +//------------------------------------------------------------------------------ +// Simple base class for screen space post-processing effects +//------------------------------------------------------------------------------ +abstract_class IScreenSpaceEffect +{ +public: + + virtual void Init( ) = 0; + virtual void Shutdown( ) = 0; + + virtual void SetParameters( KeyValues *params ) = 0; + + virtual void Render( int x, int y, int w, int h ) = 0; + + virtual void Enable( bool bEnable ) = 0; + virtual bool IsEnabled( ) = 0; +}; + + +//------------------------------------------------------------------------------ +// Interface class for managing screen space post-processing effects +//------------------------------------------------------------------------------ +abstract_class IScreenSpaceEffectManager +{ +public: + + virtual void InitScreenSpaceEffects( ) = 0; + virtual void ShutdownScreenSpaceEffects( ) = 0; + + virtual IScreenSpaceEffect *GetScreenSpaceEffect( const char *pEffectName ) = 0; + + virtual void SetScreenSpaceEffectParams( const char *pEffectName, KeyValues *params ) = 0; + virtual void SetScreenSpaceEffectParams( IScreenSpaceEffect *pEffect, KeyValues *params ) = 0; + + virtual void EnableScreenSpaceEffect( const char *pEffectName ) = 0; + virtual void EnableScreenSpaceEffect( IScreenSpaceEffect *pEffect ) = 0; + + virtual void DisableScreenSpaceEffect( const char *pEffectName ) = 0; + virtual void DisableScreenSpaceEffect( IScreenSpaceEffect *pEffect ) = 0; + + virtual void DisableAllScreenSpaceEffects( ) = 0; + + virtual void RenderEffects( int x, int y, int w, int h ) = 0; +}; + +extern IScreenSpaceEffectManager *g_pScreenSpaceEffects; + + +//------------------------------------------------------------------------------------- +// Registration class for adding screen space effects to the IScreenSpaceEffectManager +//------------------------------------------------------------------------------------- +class CScreenSpaceEffectRegistration +{ +public: + CScreenSpaceEffectRegistration( const char *pName, IScreenSpaceEffect *pEffect ); + + const char *m_pEffectName; + IScreenSpaceEffect *m_pEffect; + + CScreenSpaceEffectRegistration *m_pNext; + + static CScreenSpaceEffectRegistration *s_pHead; +}; + +#define ADD_SCREENSPACE_EFFECT( CEffect, pEffectName ) CEffect pEffectName##_effect; \ + CScreenSpaceEffectRegistration pEffectName##_reg( #pEffectName, &pEffectName##_effect ); + + + +#endif \ No newline at end of file diff --git a/game/client/TeamBitmapImage.h b/game/client/TeamBitmapImage.h new file mode 100644 index 0000000..5039698 --- /dev/null +++ b/game/client/TeamBitmapImage.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which is rendered image on top of an entity +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEAMBITMAPIMAGE_H +#define TEAMBITMAPIMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +//#include "tf_shareddefs.h" + +#include + +namespace vgui +{ + class Panel; +} + +class BitmapImage; +class C_BaseEntity; +class KeyValues; + +//----------------------------------------------------------------------------- +// A multiplexer bitmap that chooses a bitmap based on team +//----------------------------------------------------------------------------- +class CTeamBitmapImage +{ +public: + // construction, destruction + CTeamBitmapImage(); + ~CTeamBitmapImage(); + + // initialization + bool Init( vgui::Panel *pParent, KeyValues* pInitData, C_BaseEntity* pEntity ); + + // Alpha override... + void SetAlpha( float alpha ); + + // Paint the sucka. Paint it the size of the parent panel + void Paint( float yaw = 0.0f ); + +protected: + // Wrapper so we can implement this with EHANDLES some day + C_BaseEntity *GetEntity() { return m_pEntity; } + +private: + enum + { + // NOTE: Was MAX_TF_TEAMS not 4, but I don't like the dependency here. + BITMAP_COUNT = 4 + 1 + }; + + BitmapImage *m_ppImage[ BITMAP_COUNT ]; + C_BaseEntity *m_pEntity; + float m_Alpha; + bool m_bRelativeTeams; +}; + + +//----------------------------------------------------------------------------- +// Helper method to initialize a team image from KeyValues data.. +// KeyValues contains the bitmap data. pSectionName, if it exists, +// indicates which subsection of pInitData should be looked at to get at the +// image data. The final argument is the bitmap image to initialize. +// The function returns true if it succeeded. +// +// NOTE: This function looks for the key values 'material' and 'color' +// and uses them to set up the material + modulation color of the image +//----------------------------------------------------------------------------- +bool InitializeTeamImage( KeyValues *pInitData, const char* pSectionName, + vgui::Panel *pParent, C_BaseEntity *pEntity, CTeamBitmapImage* pBitmapImage ); + + +#endif // TEAMBITMAPIMAGE_H \ No newline at end of file diff --git a/game/client/ViewConeImage.h b/game/client/ViewConeImage.h new file mode 100644 index 0000000..cfa2ea1 --- /dev/null +++ b/game/client/ViewConeImage.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which draws a viewcone +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VIEWCONEIMAGE_H +#define VIEWCONEIMAGE_H + +#include "shareddefs.h" +#include "vgui_bitmapimage.h" + +namespace vgui +{ + class Panel; +} + +class C_BaseEntity; +class KeyValues; + +//----------------------------------------------------------------------------- +// A bitmap that renders a view cone based on angles +//----------------------------------------------------------------------------- +class CViewConeImage +{ +public: + // initialization + bool Init( vgui::Panel *pParent, KeyValues* pInitData ); + + // Paint the sucka + void Paint( float yaw ); + + void SetColor( int r, int g, int b ); + +private: + BitmapImage m_Image; +}; + + +//----------------------------------------------------------------------------- +// Helper method to initialize a view cone image from KeyValues data.. +// KeyValues contains the bitmap data, pSectionName, if it exists, +// indicates which subsection of pInitData should be looked at to get at the +// image data. The final argument is the bitmap image to initialize. +// The function returns true if it succeeded. +// +// NOTE: This function looks for the key values 'material' and 'color' +// and uses them to set up the material + modulation color of the image +//----------------------------------------------------------------------------- +bool InitializeViewConeImage( KeyValues *pInitData, const char* pSectionName, + vgui::Panel *pParent, CViewConeImage* pViewConeImage ); + + +#endif // VIEWCONEIMAGE_H \ No newline at end of file diff --git a/game/client/achievement_notification_panel.h b/game/client/achievement_notification_panel.h new file mode 100644 index 0000000..2af9f10 --- /dev/null +++ b/game/client/achievement_notification_panel.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ACHIEVEMENT_NOTIFICATION_PANEL_H +#define ACHIEVEMENT_NOTIFICATION_PANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "hudelement.h" + +using namespace vgui; + +class CAchievementNotificationPanel : public CHudElement, public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CAchievementNotificationPanel, EditablePanel ); + +public: + CAchievementNotificationPanel( const char *pElementName ); + + virtual void Init(); + virtual void ApplySchemeSettings( IScheme *scheme ); + virtual bool ShouldDraw( void ); + virtual void PerformLayout( void ); + virtual void LevelInit( void ) { m_flHideTime = 0; } + virtual void FireGameEvent( IGameEvent * event ); + virtual void OnTick( void ); + + void AddNotification( const char *szIconBaseName, const wchar_t *pHeading, const wchar_t *pTitle ); + +private: + void ShowNextNotification(); + void SetXAndWide( Panel *pPanel, int x, int wide ); + + float m_flHideTime; + + Label *m_pLabelHeading; + Label *m_pLabelTitle; + EditablePanel *m_pPanelBackground; + ImagePanel *m_pIcon; + + struct Notification_t + { + char szIconBaseName[255]; + wchar_t szHeading[255]; + wchar_t szTitle[255]; + }; + + CUtlLinkedList m_queueNotification; +}; + +#endif // ACHIEVEMENT_NOTIFICATION_PANEL_H \ No newline at end of file diff --git a/game/client/animationlayer.h b/game/client/animationlayer.h new file mode 100644 index 0000000..4ac3563 --- /dev/null +++ b/game/client/animationlayer.h @@ -0,0 +1,213 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ANIMATIONLAYER_H +#define ANIMATIONLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "rangecheckedvar.h" +#include "lerp_functions.h" +#include "networkvar.h" + +class C_AnimationLayer +{ +public: + + // This allows the datatables to access private members. + ALLOW_DATATABLES_PRIVATE_ACCESS(); + + C_AnimationLayer(); + void Reset(); + + void SetOrder( int order ); + +public: + + bool IsActive( void ); + + CRangeCheckedVar m_nSequence; + CRangeCheckedVar m_flPrevCycle; + CRangeCheckedVar m_flWeight; + int m_nOrder; + + // used for automatic crossfades between sequence changes + CRangeCheckedVar m_flPlaybackRate; + CRangeCheckedVar m_flCycle; + + float GetFadeout( float flCurTime ); + + void BlendWeight(); + + float m_flLayerAnimtime; + float m_flLayerFadeOuttime; + + float m_flBlendIn; + float m_flBlendOut; + + bool m_bClientBlend; +}; +#ifdef CLIENT_DLL + #define CAnimationLayer C_AnimationLayer +#endif + +inline C_AnimationLayer::C_AnimationLayer() +{ + Reset(); +} + +inline void C_AnimationLayer::Reset() +{ + m_nSequence = 0; + m_flPrevCycle = 0; + m_flWeight = 0; + m_flPlaybackRate = 0; + m_flCycle = 0; + m_flLayerAnimtime = 0; + m_flLayerFadeOuttime = 0; + m_flBlendIn = 0; + m_flBlendOut = 0; + m_bClientBlend = false; +} + + +inline void C_AnimationLayer::SetOrder( int order ) +{ + m_nOrder = order; +} + +inline float C_AnimationLayer::GetFadeout( float flCurTime ) +{ + float s; + + if (m_flLayerFadeOuttime <= 0.0f) + { + s = 0; + } + else + { + // blend in over 0.2 seconds + s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime; + if (s > 0 && s <= 1.0) + { + // do a nice spline curve + s = 3 * s * s - 2 * s * s * s; + } + else if ( s > 1.0f ) + { + // Shouldn't happen, but maybe curtime is behind animtime? + s = 1.0f; + } + } + return s; +} + + +inline C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer& from, C_AnimationLayer& to ) +{ + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = LoopingLerp( flPercent, (float)from.m_flCycle, (float)to.m_flCycle ); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight ); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; + return output; +} + +inline C_AnimationLayer Lerp( float flPercent, const C_AnimationLayer& from, const C_AnimationLayer& to ) +{ + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = Lerp( flPercent, from.m_flCycle, to.m_flCycle ); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight ); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; + return output; +} + +inline C_AnimationLayer LoopingLerp_Hermite( float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to ) +{ + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = LoopingLerp_Hermite( flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle ); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight ); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; + return output; +} + +// YWB: Specialization for interpolating euler angles via quaternions... +inline C_AnimationLayer Lerp_Hermite( float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to ) +{ + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = Lerp_Hermite( flPercent, prev.m_flCycle, from.m_flCycle, to.m_flCycle ); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight ); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; + return output; +} + +inline void Lerp_Clamp( C_AnimationLayer &val ) +{ + Lerp_Clamp( val.m_nSequence ); + Lerp_Clamp( val.m_flCycle ); + Lerp_Clamp( val.m_flPrevCycle ); + Lerp_Clamp( val.m_flWeight ); + Lerp_Clamp( val.m_nOrder ); + Lerp_Clamp( val.m_flLayerAnimtime ); + Lerp_Clamp( val.m_flLayerFadeOuttime ); +} + +inline void C_AnimationLayer::BlendWeight() +{ + if ( !m_bClientBlend ) + return; + + m_flWeight = 1; + + // blend in? + if ( m_flBlendIn != 0.0f ) + { + if (m_flCycle < m_flBlendIn) + { + m_flWeight = m_flCycle / m_flBlendIn; + } + } + + // blend out? + if ( m_flBlendOut != 0.0f ) + { + if (m_flCycle > 1.0 - m_flBlendOut) + { + m_flWeight = (1.0 - m_flCycle) / m_flBlendOut; + } + } + + m_flWeight = 3.0 * m_flWeight * m_flWeight - 2.0 * m_flWeight * m_flWeight * m_flWeight; + if (m_nSequence == 0) + m_flWeight = 0; +} + +#endif // ANIMATIONLAYER_H diff --git a/game/client/baseanimatedtextureproxy.h b/game/client/baseanimatedtextureproxy.h new file mode 100644 index 0000000..fe6a5e5 --- /dev/null +++ b/game/client/baseanimatedtextureproxy.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEANIMATEDTEXTUREPROXY +#define BASEANIMATEDTEXTUREPROXY + +#include "materialsystem/imaterialproxy.h" + +class IMaterial; +class IMaterialVar; + +#pragma warning (disable : 4100) + +class CBaseAnimatedTextureProxy : public IMaterialProxy +{ +public: + CBaseAnimatedTextureProxy(); + virtual ~CBaseAnimatedTextureProxy(); + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pC_BaseEntity ); + virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); + +protected: + // derived classes must implement this; it returns the time + // that the animation began + virtual float GetAnimationStartTime( void* pBaseEntity ) = 0; + + // Derived classes may implement this if they choose; + // this method is called whenever the animation wraps... + virtual void AnimationWrapped( void* pBaseEntity ) {} + +protected: + void Cleanup(); + + IMaterialVar *m_AnimatedTextureVar; + IMaterialVar *m_AnimatedTextureFrameNumVar; + float m_FrameRate; + bool m_WrapAnimation; +}; + +#endif // BASEANIMATEDTEXTUREPROXY \ No newline at end of file diff --git a/game/client/baseclientrendertargets.h b/game/client/baseclientrendertargets.h new file mode 100644 index 0000000..a4c84d8 --- /dev/null +++ b/game/client/baseclientrendertargets.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Has init functions for all the standard render targets used by most games. +// Mods who wish to make their own render targets can inherit from this class +// and in the 'InitClientRenderTargets' interface called by the engine, set up +// their own render targets as well as calling the init functions for various +// common render targets provided by this class. +// +// Note: Unless the client defines a singleton interface by inheriting from +// this class and exposing the singleton instance, these init and shutdown +// functions WILL NOT be called by the engine. +// +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#ifndef CLIENTRENDERTARTETS_H_ +#define CLIENTRENDERTARTETS_H_ +#ifdef _WIN32 +#pragma once +#endif + +#include "game/client/iclientrendertargets.h" // base class with interfaces called by the engine +#include "materialsystem/imaterialsystem.h" // for material system classes and interfaces + + +// Externs +class IMaterialSystem; +class IMaterialSystemHardwareConfig; + +class CBaseClientRenderTargets : public IClientRenderTargets +{ + // no networked vars + DECLARE_CLASS_GAMEROOT( CBaseClientRenderTargets, IClientRenderTargets ); +public: + // Interface called by engine during material system startup. + virtual void InitClientRenderTargets ( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize = 1024, int iCameraTextureSize = 256 ); + // Shutdown all custom render targets here. + virtual void ShutdownClientRenderTargets ( void ); + +protected: + + // Standard render textures used by most mods-- Classes inheriting from + // this can choose to init these or not depending on their needs. + + // For reflective and refracting water + CTextureReference m_WaterReflectionTexture; + CTextureReference m_WaterRefractionTexture; + + // Used for monitors + CTextureReference m_CameraTexture; + + // Used for the HUD in stereo and head tracking mode + CTextureReference m_UITexture; + + // Init functions for the common render targets + ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); + ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); + ITexture* CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize = 256 ); + +}; + +#endif // CLIENTRENDERTARTETS_H_ \ No newline at end of file diff --git a/game/client/basepresence.h b/game/client/basepresence.h new file mode 100644 index 0000000..c23a33c --- /dev/null +++ b/game/client/basepresence.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base implementation of the IPresence interface +// +//============================================================================= + +#ifndef BASEPRESENCE_H +#define BASEPRESENCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ipresence.h" +#include "igamesystem.h" + +//----------------------------------------------------------------------------- +// Purpose: Common implementation for setting user contexts and properties. +// Each client should inherit from this to implement mod-specific presence info. +//----------------------------------------------------------------------------- +class CBasePresence : public IPresence, public CAutoGameSystemPerFrame +{ +public: + // CBaseGameSystemPerFrame overrides + virtual bool Init( void ); + virtual void Shutdown( void ); + virtual void Update( float frametime ); + virtual char const *Name( void ) { return "presence"; } + + // IPresence Interface + virtual void UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync = false ); + virtual void UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync = false ); + virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ); + virtual uint GetPresenceID( const char *pIdName ); + virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ); + virtual const char *GetPropertyIdString( const uint id ); + + // Stats reporting + virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ); + virtual void SetStat( uint iPropertyId, int iPropertyValue, int dataType ); + virtual void UploadStats(); + +protected: + bool m_bArbitrated; + bool m_bReportingStats; + HANDLE m_hSession; + CUtlVector< XUSER_PROPERTY > m_PlayerStats; + + //--------------------------------------------------------- + // Debug support + //--------------------------------------------------------- + CON_COMMAND_MEMBER_F( CBasePresence, "user_context", DebugUserSetContext, "Set a Rich Presence Context: user_context ", 0 ) + CON_COMMAND_MEMBER_F( CBasePresence, "user_property", DebugUserSetProperty, "Set a Rich Presence Property: user_property ", 0 ) +}; + +#endif // BASEPRESENCE_H diff --git a/game/client/beamdraw.h b/game/client/beamdraw.h new file mode 100644 index 0000000..c4a0e6e --- /dev/null +++ b/game/client/beamdraw.h @@ -0,0 +1,173 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#if !defined( BEAMDRAW_H ) +#define BEAMDRAW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "mathlib/vector.h" +#include "tier2/beamsegdraw.h" +#include "c_pixel_visibility.h" + +#define NOISE_DIVISIONS 128 + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +struct model_t; +struct BeamTrail_t; + +//----------------------------------------------------------------------------- +// Purpose: Beams fill out this data structure +// This is also used for rendering +//----------------------------------------------------------------------------- + +class Beam_t : public CDefaultClientRenderable +{ +public: + Beam_t(); + + // Methods of IClientRenderable + virtual const Vector& GetRenderOrigin( void ); + virtual const QAngle& GetRenderAngles( void ); + virtual const matrix3x4_t &RenderableToWorldTransform(); + virtual void GetRenderBounds( Vector& mins, Vector& maxs ); + virtual bool ShouldDraw( void ); + virtual bool IsTransparent( void ); + virtual int DrawModel( int flags ); + virtual void ComputeFxBlend( ); + virtual int GetFxBlend( ); + + // Resets the beam state + void Reset(); + + // Method to computing the bounding box + void ComputeBounds(); + + // Bounding box... + Vector m_Mins; + Vector m_Maxs; + pixelvis_handle_t *m_queryHandleHalo; + float m_haloProxySize; + + // Data is below.. + + // Next beam in list + Beam_t* next; + + // Type of beam + int type; + int flags; + + // Control points for the beam + int numAttachments; + Vector attachment[MAX_BEAM_ENTS]; + Vector delta; + + // 0 .. 1 over lifetime of beam + float t; + float freq; + + // Time when beam should die + float die; + float width; + float endWidth; + float fadeLength; + float amplitude; + float life; + + // Color + float r, g, b; + float brightness; + + // Speed + float speed; + + // Animation + float frameRate; + float frame; + int segments; + + // Attachment entities for the beam + EHANDLE entity[MAX_BEAM_ENTS]; + int attachmentIndex[MAX_BEAM_ENTS]; + + // Model info + int modelIndex; + int haloIndex; + + float haloScale; + int frameCount; + + float rgNoise[NOISE_DIVISIONS+1]; + + // Popcorn trail for beam follows to use + BeamTrail_t* trail; + + // for TE_BEAMRINGPOINT + float start_radius; + float end_radius; + + // for FBEAM_ONLYNOISEONCE + bool m_bCalculatedNoise; + + float m_flHDRColorScale; + +#ifdef PORTAL + bool m_bDrawInMainRender; + bool m_bDrawInPortalRender; +#endif //#ifdef PORTAL +}; + + +int ScreenTransform( const Vector& point, Vector& screen ); + +void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, const Vector& delta, + float startWidth, float endWidth, float scale, float freq, float speed, int segments, + int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f ); +void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, const Vector& delta, + float startWidth, float endWidth, float scale, float freq, float speed, int segments, + int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f ); +void DrawSplineSegs( int noise_divisions, float *prgNoise, + const model_t* beammodel, const model_t* halomodel, float flHaloScale, + float frame, int rendermode, int numAttachments, Vector* attachment, + float startWidth, float endWidth, float scale, float freq, float speed, int segments, + int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f ); +void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale = 1.0f ); +void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode, const Vector& source, + float scale, float* color, float flHDRColorScale = 1.0f ); +void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, const Vector& delta, + float width, float scale, float freq, float speed, + int segments, float* color, float flHDRColorScale = 1.0f ); +void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, + const Vector& delta, float width, float scale, float freq, + float speed, int segments, float* color, float flHDRColorScale = 1.0f ); +void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ), + const model_t* spritemodel, float frame, int rendermode, + const Vector& source, const Vector& delta, float width, float amplitude, + float freq, float speed, int segments, float* color, float flHDRColorScale = 1.0f ); +void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode, Vector& delta, + Vector& screen, Vector& screenLast, float die, const Vector& source, + int flags, float width, float amplitude, float freq, float* color, float flHDRColorScale = 1.0f ); + +void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale = 1.0f ); +class CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode ); + +//----------------------------------------------------------------------------- +// Assumes the material has already been bound +//----------------------------------------------------------------------------- +void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ); + +#endif // BEAMDRAW_H \ No newline at end of file diff --git a/game/client/bone_merge_cache.h b/game/client/bone_merge_cache.h new file mode 100644 index 0000000..6123c9b --- /dev/null +++ b/game/client/bone_merge_cache.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BONE_MERGE_CACHE_H +#define BONE_MERGE_CACHE_H +#ifdef _WIN32 +#pragma once +#endif + + +class C_BaseAnimating; +class CStudioHdr; + + +#include "mathlib/vector.h" + + +class CBoneMergeCache +{ +public: + + CBoneMergeCache(); + + void Init( C_BaseAnimating *pOwner ); + + // Updates the lookups that let it merge bones quickly. + void UpdateCache(); + + // This copies the transform from all bones in the followed entity that have + // names that match our bones. + void MergeMatchingBones( int boneMask ); + + // copy bones instead of matrices + void CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask ); + void CopyChildToParent( const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask ); + + // Returns true if the specified bone is one that gets merged in MergeMatchingBones. + int IsBoneMerged( int iBone ) const; + + // Gets the origin for the first merge bone on the parent. + bool GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles ); + + bool GetRootBone( matrix3x4_t &rootBone ); + +private: + + // This is the entity that we're keeping the cache updated for. + C_BaseAnimating *m_pOwner; + + // All the cache data is based off these. When they change, the cache data is regenerated. + // These are either all valid pointers or all NULL. + C_BaseAnimating *m_pFollow; + CStudioHdr *m_pFollowHdr; + const studiohdr_t *m_pFollowRenderHdr; + CStudioHdr *m_pOwnerHdr; + + // This is the mask we need to use to set up bones on the followed entity to do the bone merge + int m_nFollowBoneSetupMask; + + // Cache data. + class CMergedBone + { + public: + unsigned short m_iMyBone; + unsigned short m_iParentBone; + }; + + CUtlVector m_MergedBones; + CUtlVector m_BoneMergeBits; // One bit for each bone. The bit is set if the bone gets merged. +}; + + +inline int CBoneMergeCache::IsBoneMerged( int iBone ) const +{ + if ( m_pOwnerHdr ) + return m_BoneMergeBits[iBone >> 3] & ( 1 << ( iBone & 7 ) ); + else + return 0; +} + + +#endif // BONE_MERGE_CACHE_H diff --git a/game/client/bonetoworldarray.h b/game/client/bonetoworldarray.h new file mode 100644 index 0000000..ce3486b --- /dev/null +++ b/game/client/bonetoworldarray.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef BONETOWORLDARRAY_H +#define BONETOWORLDARRAY_H + +#include "tier0/tslist.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier0/memdbgon.h" // for _aligned_malloc usage below +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +template +class CBoneToWorldArrays +{ +public: + enum + { + ALIGNMENT = 128, + }; + + CBoneToWorldArrays() + { + const int SIZE_ARRAY = AlignValue( sizeof(matrix3x4_t) * MAXSTUDIOBONES, ALIGNMENT ); + m_pBase = (matrix3x4_t *)_aligned_malloc( SIZE_ARRAY * NUM_ARRAYS, ALIGNMENT ); + for ( int i = 0; i < NUM_ARRAYS; i++ ) + { + matrix3x4_t *pArray = (matrix3x4_t *)((byte *)m_pBase + SIZE_ARRAY * i); + Assert( (size_t)pArray % ALIGNMENT == 0 ); + Free( pArray ); + } + } + + ~CBoneToWorldArrays() + { + _aligned_free( m_pBase ); + } + + int NumArrays() + { + return NUM_ARRAYS; + } + + matrix3x4_t *Alloc( bool bBlock = true ) + { + TSLNodeBase_t *p; + while ( ( p = m_Free.Pop() ) == NULL && bBlock ) + { + ThreadPause(); + } + return (matrix3x4_t *)p; + } + + void Free( matrix3x4_t *p ) + { + m_Free.Push( (TSLNodeBase_t *) p ); + } + +private: + CTSListBase m_Free; + matrix3x4_t *m_pBase; +}; + +#endif // BONETOWORLDARRAY_H diff --git a/game/client/bsp_utils.h b/game/client/bsp_utils.h new file mode 100644 index 0000000..1cdfaf5 --- /dev/null +++ b/game/client/bsp_utils.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Exposes bsp tools to game for e.g. workshop use +// +// $NoKeywords: $ +//===========================================================================// + +#include "../utils/common/bsplib.h" +#include "ibsppack.h" + +// Loads bsppack module (IBSPPack) and calls RepackBSP() +bool BSP_SyncRepack( const char *pszInputMapFile, + const char *pszOutputMapFile, + IBSPPack::eRepackBSPFlags eRepackFlags = (IBSPPack::eRepackBSPFlags) ( IBSPPack::eRepackBSP_CompressLumps | + IBSPPack::eRepackBSP_CompressPackfile ) ); + +// Helper to spawn a background thread that runs SyncRepack +void BSP_BackgroundRepack( const char *pszInputMapFile, + const char *pszOutputMapFile, + IBSPPack::eRepackBSPFlags eRepackFlags = (IBSPPack::eRepackBSPFlags) ( IBSPPack::eRepackBSP_CompressLumps | + IBSPPack::eRepackBSP_CompressPackfile ) ); diff --git a/game/client/c_ai_basenpc.h b/game/client/c_ai_basenpc.h new file mode 100644 index 0000000..834be64 --- /dev/null +++ b/game/client/c_ai_basenpc.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_AI_BASENPC_H +#define C_AI_BASENPC_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_basecombatcharacter.h" + +// NOTE: Moved all controller code into c_basestudiomodel +class C_AI_BaseNPC : public C_BaseCombatCharacter +{ + DECLARE_CLASS( C_AI_BaseNPC, C_BaseCombatCharacter ); + +public: + DECLARE_CLIENTCLASS(); + + C_AI_BaseNPC(); + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + virtual bool IsNPC( void ) { return true; } + bool IsMoving( void ){ return m_bIsMoving; } + bool ShouldAvoidObstacle( void ){ return m_bPerformAvoidance; } + virtual bool AddRagdollToFadeQueue( void ) { return m_bFadeCorpse; } + + virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) OVERRIDE; + + int GetDeathPose( void ) { return m_iDeathPose; } + + bool ShouldModifyPlayerSpeed( void ) { return m_bSpeedModActive; } + int GetSpeedModifyRadius( void ) { return m_iSpeedModRadius; } + int GetSpeedModifySpeed( void ) { return m_iSpeedModSpeed; } + + void ClientThink( void ); + void OnDataChanged( DataUpdateType_t type ); + bool ImportantRagdoll( void ) { return m_bImportanRagdoll; } + +private: + C_AI_BaseNPC( const C_AI_BaseNPC & ); // not defined, not accessible + float m_flTimePingEffect; + int m_iDeathPose; + int m_iDeathFrame; + + int m_iSpeedModRadius; + int m_iSpeedModSpeed; + + bool m_bPerformAvoidance; + bool m_bIsMoving; + bool m_bFadeCorpse; + bool m_bSpeedModActive; + bool m_bImportanRagdoll; +}; + + +#endif // C_AI_BASENPC_H diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h new file mode 100644 index 0000000..f1b0467 --- /dev/null +++ b/game/client/c_baseanimating.h @@ -0,0 +1,813 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#ifndef C_BASEANIMATING_H +#define C_BASEANIMATING_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "studio.h" +#include "utlvector.h" +#include "ragdoll.h" +#include "mouthinfo.h" +// Shared activities +#include "ai_activity.h" +#include "animationlayer.h" +#include "sequence_Transitioner.h" +#include "bone_accessor.h" +#include "bone_merge_cache.h" +#include "ragdoll_shared.h" +#include "tier0/threadtools.h" +#include "datacache/idatacache.h" + +#define LIPSYNC_POSEPARAM_NAME "mouth" +#define NUM_HITBOX_FIRES 10 + +/* +class C_BaseClientShader +{ + virtual void RenderMaterial( C_BaseEntity *pEntity, int count, const vec4_t *verts, const vec4_t *normals, const vec2_t *texcoords, vec4_t *lightvalues ); +}; +*/ + +class IRagdoll; +class CIKContext; +class CIKState; +class ConVar; +class C_RopeKeyframe; +class CBoneBitList; +class CBoneList; +class KeyValues; +class CJiggleBones; +class IBoneSetup; +FORWARD_DECLARE_HANDLE( memhandle_t ); +typedef unsigned short MDLHandle_t; + +extern ConVar vcollide_wireframe; + + +struct ClientModelRenderInfo_t : public ModelRenderInfo_t +{ + // Added space for lighting origin override. Just allocated space, need to set base pointer + matrix3x4_t lightingOffset; + + // Added space for model to world matrix. Just allocated space, need to set base pointer + matrix3x4_t modelToWorld; +}; + +struct RagdollInfo_t +{ + bool m_bActive; + float m_flSaveTime; + int m_nNumBones; + Vector m_rgBonePos[MAXSTUDIOBONES]; + Quaternion m_rgBoneQuaternion[MAXSTUDIOBONES]; +}; + + +class CAttachmentData +{ +public: + matrix3x4_t m_AttachmentToWorld; + QAngle m_angRotation; + Vector m_vOriginVelocity; + int m_nLastFramecount : 31; + int m_bAnglesComputed : 1; +}; + + +typedef unsigned int ClientSideAnimationListHandle_t; + +#define INVALID_CLIENTSIDEANIMATION_LIST_HANDLE (ClientSideAnimationListHandle_t)~0 + + +class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback +{ +public: + DECLARE_CLASS( C_BaseAnimating, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + enum + { + NUM_POSEPAREMETERS = 24, + NUM_BONECTRLS = 4 + }; + + C_BaseAnimating(); + ~C_BaseAnimating(); + + virtual C_BaseAnimating* GetBaseAnimating() { return this; } + + bool UsesPowerOfTwoFrameBufferTexture( void ); + + virtual bool Interpolate( float currentTime ); + virtual void Simulate(); + virtual void Release(); + + float GetAnimTimeInterval( void ) const; + + virtual unsigned char GetClientSideFade( void ); + + // Get bone controller values. + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); + virtual float SetBoneController ( int iController, float flValue ); + + LocalFlexController_t GetNumFlexControllers( void ); + const char *GetFlexDescFacs( int iFlexDesc ); + const char *GetFlexControllerName( LocalFlexController_t iFlexController ); + const char *GetFlexControllerType( LocalFlexController_t iFlexController ); + + virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + // Computes a box that surrounds all hitboxes + bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Gets the hitbox-to-world transforms, returns false if there was a problem + bool HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXSTUDIOBONES] ); + + // base model functionality + float ClampCycle( float cycle, bool isLooping ); + virtual void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); + virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); + virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform ); + virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + + // model specific + virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); + virtual void UpdateIKLocks( float currentTime ); + virtual void CalculateIKLocks( float currentTime ); + virtual bool ShouldDraw(); + virtual int DrawModel( int flags ); + virtual int InternalDrawModel( int flags ); + virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ); + virtual bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo ); + void DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray = NULL ); + + // + virtual CMouthInfo *GetMouth(); + virtual void ControlMouth( CStudioHdr *pStudioHdr ); + + // override in sub-classes + virtual void DoAnimationEvents( CStudioHdr *pStudio ); + virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + virtual void FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + virtual const char* ModifyEventParticles( const char* token ) { return token; } + + // Parses and distributes muzzle flash events + virtual bool DispatchMuzzleEffect( const char *options, bool isFirstPerson ); + + // virtual void AllocateMaterials( void ); + // virtual void FreeMaterials( void ); + + virtual void ValidateModelIndex( void ); + virtual CStudioHdr *OnNewModel( void ); + CStudioHdr *GetModelPtr() const; + void InvalidateMdlCache(); + + virtual void SetPredictable( bool state ); + void UseClientSideAnimation(); + + // C_BaseClientShader **p_ClientShaders; + + virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + void UnragdollBlend( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime ); + + void MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, Vector pos[], Quaternion q[] ); + virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); + + virtual void ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + // Attachments + int LookupAttachment( const char *pAttachmentName ); + int LookupRandomAttachment( const char *pAttachmentNameSubstring ); + + int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); + inline int LookupPoseParameter( const char *szName ) { return LookupPoseParameter(GetModelPtr(), szName); } + + float SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue ); + inline float SetPoseParameter( const char *szName, float flValue ) { return SetPoseParameter( GetModelPtr(), szName, flValue ); } + float SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); + inline float SetPoseParameter( int iParameter, float flValue ) { return SetPoseParameter( GetModelPtr(), iParameter, flValue ); } + + float GetPoseParameter( int iPoseParameter ); + + bool GetPoseParameterRange( int iPoseParameter, float &minValue, float &maxValue ); + + int LookupBone( const char *szName ); + void GetBonePosition( int iBone, Vector &origin, QAngle &angles ); + void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ); + + //============================================================================= + // HPE_BEGIN: + // [menglish] Finds the bone associated with the given hitbox + //============================================================================= + + int GetHitboxBone( int hitboxIndex ); + + //============================================================================= + // HPE_END + //============================================================================= + + // Bone attachments + virtual void AttachEntityToBone( C_BaseAnimating* attachTarget, int boneIndexAttached=-1, Vector bonePosition=Vector(0,0,0), QAngle boneAngles=QAngle(0,0,0) ); + void AddBoneAttachment( C_BaseAnimating* newBoneAttachment ); + void RemoveBoneAttachment( C_BaseAnimating* boneAttachment ); + void RemoveBoneAttachments(); + void DestroyBoneAttachments(); + void MoveBoneAttachments( C_BaseAnimating* attachTarget ); + int GetNumBoneAttachments(); + C_BaseAnimating* GetBoneAttachment( int i ); + virtual void NotifyBoneAttached( C_BaseAnimating* attachTarget ); + virtual void UpdateBoneAttachments( void ); + + //bool solveIK(float a, float b, const Vector &Foot, const Vector &Knee1, Vector &Knee2); + //void DebugIK( mstudioikchain_t *pikchain ); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual int RestoreData( const char *context, int slot, int type ); + + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void AddEntity( void ); + + // This can be used to force client side animation to be on. Only use if you know what you're doing! + // Normally, the server entity should set this. + void ForceClientSideAnimationOn(); + + void AddToClientSideAnimationList(); + void RemoveFromClientSideAnimationList( bool bBeingDestroyed = false ); + + virtual bool IsSelfAnimating(); + virtual void ResetLatched(); + + // implements these so ragdolls can handle frustum culling & leaf visibility + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + virtual const Vector& GetRenderOrigin( void ); + virtual const QAngle& GetRenderAngles( void ); + + virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); + + // Attachments. + bool GetAttachment( const char *szName, Vector &absOrigin ); + bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ); + + // Inherited from C_BaseEntity + virtual bool GetAttachment( int number, Vector &origin ); + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); + virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); + + // Returns the attachment in local space + bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal ); + bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles ); + bool GetAttachmentLocal( int iAttachment, Vector &origin ); + + bool GetRootBone( matrix3x4_t &rootBone ); + + // Should this object cast render-to-texture shadows? + virtual ShadowType_t ShadowCastType(); + + // Should we collide? + virtual CollideType_t GetCollideType( void ); + + virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + + // returns true if we're currently being ragdolled + bool IsRagdoll() const; + bool IsAboutToRagdoll() const; + virtual C_BaseAnimating *BecomeRagdollOnClient(); + C_BaseAnimating *CreateRagdollCopy(); + bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints=false ); + void IgniteRagdoll( C_BaseAnimating *pSource ); + void TransferDissolveFrom( C_BaseAnimating *pSource ); + virtual void SaveRagdollInfo( int numbones, const matrix3x4_t &cameraTransform, CBoneAccessor &pBoneToWorld ); + virtual bool RetrieveRagdollInfo( Vector *pos, Quaternion *q ); + virtual void Clear( void ); + void ClearRagdoll(); + void CreateUnragdollInfo( C_BaseAnimating *pRagdoll ); + bool ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ); + virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + + // For shadows rendering the correct body + sequence... + virtual int GetBody() { return m_nBody; } + virtual int GetSkin() { return m_nSkin; } + + bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); } + + inline float GetPlaybackRate(); + inline void SetPlaybackRate( float rate ); + + void SetModelScale( float scale, float change_duration = 0.0f ); + float GetModelScale() const { return m_flModelScale; } + inline bool IsModelScaleFractional() const; /// very fast way to ask if the model scale is < 1.0f (faster than if (GetModelScale() < 1.0f) ) + inline bool IsModelScaled() const; + void UpdateModelScale( void ); + virtual void RefreshCollisionBounds( void ); + + int GetSequence(); + virtual void SetSequence(int nSequence); + inline void ResetSequence(int nSequence); + float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); } + bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence ); + inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); } + float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence ); + void GetSequenceLinearMotion( int iSequence, Vector *pVec ); + void GetBlendedLinearVelocity( Vector *pVec ); + int LookupSequence ( const char *label ); + int LookupActivity( const char *label ); + char const *GetSequenceName( int iSequence ); + char const *GetSequenceActivityName( int iSequence ); + Activity GetSequenceActivity( int iSequence ); + KeyValues *GetSequenceKeyValues( int iSequence ); + virtual void StudioFrameAdvance(); // advance animation frame to some time in the future + + // Clientside animation + virtual float FrameAdvance( float flInterval = 0.0f ); + virtual float GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence ); + virtual void UpdateClientSideAnimation(); + void ClientSideAnimationChanged(); + virtual unsigned int ComputeClientSideAnimationFlags(); + + virtual void ResetClientsideFrame( void ) { SetCycle( 0 ); } + + void SetCycle( float flCycle ); + float GetCycle() const; + + void SetBodygroup( int iGroup, int iValue ); + int GetBodygroup( int iGroup ); + + const char *GetBodygroupName( int iGroup ); + int FindBodygroupByName( const char *name ); + int GetBodygroupCount( int iGroup ); + int GetNumBodyGroups( void ); + + class CBoneCache *GetBoneCache( CStudioHdr *pStudioHdr ); + void SetHitboxSet( int setnum ); + void SetHitboxSetByName( const char *setname ); + int GetHitboxSet( void ); + char const *GetHitboxSetName( void ); + int GetHitboxSetCount( void ); + void DrawClientHitboxes( float duration = 0.0f, bool monocolor = false ); + + C_BaseAnimating* FindFollowedEntity(); + + virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; } + inline bool IsSequenceFinished( void ); + inline bool SequenceLoops( void ) { return m_bSequenceLoops; } + + // All view model attachments origins are stretched so you can place entities at them and + // they will match up with where the attachment winds up being drawn on the view model, since + // the view models are drawn with a different FOV. + // + // If you're drawing something inside of a view model's DrawModel() function, then you want the + // original attachment origin instead of the adjusted one. To get that, call this on the + // adjusted attachment origin. + virtual void UncorrectViewModelAttachment( Vector &vOrigin ) {} + + // Call this if SetupBones() has already been called this frame but you need to move the + // entity and rerender. + void InvalidateBoneCache(); + bool IsBoneCacheValid() const; // Returns true if the bone cache is considered good for this frame. + void GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out ); + + // Wrappers for CBoneAccessor. + const matrix3x4_t& GetBone( int iBone ) const; + matrix3x4_t& GetBoneForWrite( int iBone ); + + // Used for debugging. Will produce asserts if someone tries to setup bones or + // attachments before it's allowed. + // Use the "AutoAllowBoneAccess" class to auto push/pop bone access. + // Use a distinct "tag" when pushing/popping - asserts when push/pop tags do not match. + struct AutoAllowBoneAccess + { + AutoAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ); + ~AutoAllowBoneAccess( void ); + }; + static void PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush ); + static void PopBoneAccess( char const *tagPop ); + static void ThreadedBoneSetup(); + static void InitBoneSetupThreadPool(); + static void ShutdownBoneSetupThreadPool(); + + // Invalidate bone caches so all SetupBones() calls force bone transforms to be regenerated. + static void InvalidateBoneCaches(); + + // Purpose: My physics object has been updated, react or extract data + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + + void DisableMuzzleFlash(); // Turn off the muzzle flash (ie: signal that we handled the server's event). + virtual void DoMuzzleFlash(); // Force a muzzle flash event. Note: this only QUEUES an event, so + // ProcessMuzzleFlashEvent will get called later. + bool ShouldMuzzleFlash() const; // Is the muzzle flash event on? + + // This is called to do the actual muzzle flash effect. + virtual void ProcessMuzzleFlashEvent(); + + // Update client side animations + static void UpdateClientSideAnimations(); + + // Load the model's keyvalues section and create effects listed inside it + void InitModelEffects( void ); + + // Sometimes the server wants to update the client's cycle to get the two to run in sync (for proper hit detection) + virtual void SetServerIntendedCycle( float intended ) { (void)intended; } + virtual float GetServerIntendedCycle( void ) { return -1.0f; } + + // For prediction + int SelectWeightedSequence ( int activity ); + int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount ); + void ResetSequenceInfo( void ); + float SequenceDuration( void ); + float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence ); + inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); } + int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir ); + + void RagdollMoved( void ); + + virtual void GetToolRecordingState( KeyValues *msg ); + virtual void CleanupToolRecordingState( KeyValues *msg ); + + void SetReceivedSequence( void ); + virtual bool ShouldResetSequenceOnNewModel( void ); + + virtual bool IsViewModel() const; + virtual void UpdateOnRemove( void ); + +protected: + // View models scale their attachment positions to account for FOV. To get the unmodified + // attachment position (like if you're rendering something else during the view model's DrawModel call), + // use TransformViewModelAttachmentToWorld. + virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) {} + + // View models say yes to this. + bool IsBoneAccessAllowed() const; + CMouthInfo& MouthInfo(); + + // Models used in a ModelPanel say yes to this + virtual bool IsMenuModel() const; + + // Allow studio models to tell C_BaseEntity what their m_nBody value is + virtual int GetStudioBody( void ) { return m_nBody; } + + virtual bool CalcAttachments(); + +private: + // This method should return true if the bones have changed + SetupBones needs to be called + virtual float LastBoneChangedTime() { return FLT_MAX; } + + CBoneList* RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneState ); + + bool PutAttachment( int number, const matrix3x4_t &attachmentToWorld ); + void TermRopes(); + + void DelayedInitModelEffects( void ); + + void UpdateRelevantInterpolatedVars(); + void AddBaseAnimatingInterpolatedVars(); + void RemoveBaseAnimatingInterpolatedVars(); + +public: + CRagdoll *m_pRagdoll; + + // Texture group to use + int m_nSkin; + + // Object bodygroup + int m_nBody; + + // Hitbox set to use (default 0) + int m_nHitboxSet; + + CSequenceTransitioner m_SequenceTransitioner; + +protected: + CIKContext *m_pIk; + + int m_iEyeAttachment; + + // Animation playback framerate + float m_flPlaybackRate; + + // Decomposed ragdoll info + bool m_bStoreRagdollInfo; + RagdollInfo_t *m_pRagdollInfo; + Vector m_vecForce; + int m_nForceBone; + + // Is bone cache valid + // bone transformation matrix + unsigned long m_iMostRecentModelBoneCounter; + unsigned long m_iMostRecentBoneSetupRequest; + int m_iPrevBoneMask; + int m_iAccumulatedBoneMask; + + CBoneAccessor m_BoneAccessor; + CThreadFastMutex m_BoneSetupLock; + + ClientSideAnimationListHandle_t m_ClientSideAnimationListHandle; + + // Client-side animation + bool m_bClientSideFrameReset; + + // Bone attachments. Used for attaching one BaseAnimating to another's bones. + // Client side only. + CUtlVector > m_BoneAttachments; + int m_boneIndexAttached; + Vector m_bonePosition; + QAngle m_boneAngles; + CHandle m_pAttachedTo; + +protected: + + float m_fadeMinDist; + float m_fadeMaxDist; + float m_flFadeScale; + +private: + + float m_flGroundSpeed; // computed linear movement rate for current sequence + float m_flLastEventCheck; // cycle index of when events were last checked + bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry + bool m_bSequenceLoops; // true if the sequence loops + + // Mouth lipsync/envelope following values + CMouthInfo m_mouth; + + CNetworkVar( float, m_flModelScale ); + + // Animation blending factors + float m_flPoseParameter[MAXSTUDIOPOSEPARAM]; + CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter; + float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM]; + + int m_nPrevSequence; + int m_nRestoreSequence; + + // Ropes that got spawned when the model was created. + CUtlLinkedList m_Ropes; + + // event processing info + float m_flPrevEventCycle; + int m_nEventSequence; + + float m_flEncodedController[MAXSTUDIOBONECTRLS]; + CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS > m_iv_flEncodedController; + float m_flOldEncodedController[MAXSTUDIOBONECTRLS]; + + // Clientside animation + bool m_bClientSideAnimation; + bool m_bLastClientSideFrameReset; + + int m_nNewSequenceParity; + int m_nResetEventsParity; + + int m_nPrevNewSequenceParity; + int m_nPrevResetEventsParity; + + bool m_builtRagdoll; + Vector m_vecPreRagdollMins; + Vector m_vecPreRagdollMaxs; + + // Current animation sequence + int m_nSequence; + bool m_bReceivedSequence; + + // Current cycle location from server +protected: + float m_flCycle; + CInterpolatedVar< float > m_iv_flCycle; + float m_flOldCycle; + bool m_bNoModelParticles; + +private: + float m_flOldModelScale; + int m_nOldSequence; + CBoneMergeCache *m_pBoneMergeCache; // This caches the strcmp lookups that it has to do + // when merg + + CUtlVector< matrix3x4_t > m_CachedBoneData; // never access this directly. Use m_BoneAccessor. + memhandle_t m_hitboxBoneCacheHandle; + float m_flLastBoneSetupTime; + CJiggleBones *m_pJiggleBones; + + // Calculated attachment points + CUtlVector m_Attachments; + + bool SetupBones_AttachmentHelper( CStudioHdr *pStudioHdr ); + + EHANDLE m_hLightingOrigin; + EHANDLE m_hLightingOriginRelative; + + // These are compared against each other to determine if the entity should muzzle flash. + CNetworkVar( unsigned char, m_nMuzzleFlashParity ); + unsigned char m_nOldMuzzleFlashParity; + + bool m_bInitModelEffects; + + // Dynamic models + bool m_bDynamicModelAllowed; + bool m_bDynamicModelPending; + bool m_bResetSequenceInfoOnLoad; + CRefCountedModelIndex m_AutoRefModelIndex; +public: + void EnableDynamicModels() { m_bDynamicModelAllowed = true; } + bool IsDynamicModelLoading() const { return m_bDynamicModelPending; } +private: + virtual void OnModelLoadComplete( const model_t* pModel ); + +private: + void LockStudioHdr(); + void UnlockStudioHdr(); + mutable CStudioHdr *m_pStudioHdr; + mutable MDLHandle_t m_hStudioHdr; + CThreadFastMutex m_StudioHdrInitLock; +}; + +enum +{ + RAGDOLL_FRICTION_OFF = -2, + RAGDOLL_FRICTION_NONE, + RAGDOLL_FRICTION_IN, + RAGDOLL_FRICTION_HOLD, + RAGDOLL_FRICTION_OUT, +}; + +class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify +{ + +public: + C_ClientRagdoll( bool bRestoring = true ); + DECLARE_CLASS( C_ClientRagdoll, C_BaseAnimating ); + DECLARE_DATADESC(); + + // inherited from IPVSNotify + virtual void OnPVSStatusChanged( bool bInPVS ); + + virtual void Release( void ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + void ClientThink( void ); + void ReleaseRagdoll( void ) { m_bReleaseRagdoll = true; } + bool ShouldSavePhysics( void ) { return true; } + virtual void OnSave(); + virtual void OnRestore(); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_SAVE_NON_NETWORKABLE; } + virtual IPVSNotify* GetPVSNotifyInterface() { return this; } + + void HandleAnimatedFriction( void ); + virtual void SUB_Remove( void ); + + void FadeOut( void ); + virtual float LastBoneChangedTime(); + + bool m_bFadeOut; + bool m_bImportant; + float m_flEffectTime; + +private: + int m_iCurrentFriction; + int m_iMinFriction; + int m_iMaxFriction; + float m_flFrictionModTime; + float m_flFrictionTime; + + int m_iFrictionAnimState; + bool m_bReleaseRagdoll; + + bool m_bFadingOut; + + float m_flScaleEnd[NUM_HITBOX_FIRES]; + float m_flScaleTimeStart[NUM_HITBOX_FIRES]; + float m_flScaleTimeEnd[NUM_HITBOX_FIRES]; +}; + +//----------------------------------------------------------------------------- +// Purpose: Serves the 90% case of calling SetSequence / ResetSequenceInfo. +//----------------------------------------------------------------------------- +inline void C_BaseAnimating::ResetSequence(int nSequence) +{ + SetSequence( nSequence ); + ResetSequenceInfo(); +} + +inline float C_BaseAnimating::GetPlaybackRate() +{ + return m_flPlaybackRate; +} + +inline void C_BaseAnimating::SetPlaybackRate( float rate ) +{ + m_flPlaybackRate = rate; +} + +inline const matrix3x4_t& C_BaseAnimating::GetBone( int iBone ) const +{ + return m_BoneAccessor.GetBone( iBone ); +} + +inline matrix3x4_t& C_BaseAnimating::GetBoneForWrite( int iBone ) +{ + return m_BoneAccessor.GetBoneForWrite( iBone ); +} + + +inline bool C_BaseAnimating::ShouldMuzzleFlash() const +{ + return m_nOldMuzzleFlashParity != m_nMuzzleFlashParity; +} + +inline float C_BaseAnimating::GetCycle() const +{ + return m_flCycle; +} + +//----------------------------------------------------------------------------- +// Purpose: return a pointer to an updated studiomdl cache cache +//----------------------------------------------------------------------------- + +inline CStudioHdr *C_BaseAnimating::GetModelPtr() const +{ + if ( IsDynamicModelLoading() ) + return NULL; + +#ifdef _DEBUG + // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. +// static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" ); +// AssertOnce( pModelCache->IsFrameLocking() ); +#endif + if ( !m_pStudioHdr ) + { + const_cast(this)->LockStudioHdr(); + } + Assert( m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID ); + return m_pStudioHdr; +} + + +inline void C_BaseAnimating::InvalidateMdlCache() +{ + UnlockStudioHdr(); +} + +inline bool C_BaseAnimating::IsModelScaleFractional() const +{ + return ( m_flModelScale < 1.0f ); +} + +inline bool C_BaseAnimating::IsModelScaled() const +{ + return ( m_flModelScale > 1.0f+FLT_EPSILON || m_flModelScale < 1.0f-FLT_EPSILON ); +} + +//----------------------------------------------------------------------------- +// Sequence access +//----------------------------------------------------------------------------- +inline int C_BaseAnimating::GetSequence() +{ + return m_nSequence; +} + +inline bool C_BaseAnimating::IsSequenceFinished( void ) +{ + return m_bSequenceFinished; +} + +inline float C_BaseAnimating::SequenceDuration( void ) +{ + return SequenceDuration( GetSequence() ); +} + + +//----------------------------------------------------------------------------- +// Mouth +//----------------------------------------------------------------------------- +inline CMouthInfo& C_BaseAnimating::MouthInfo() +{ + return m_mouth; +} + + +// FIXME: move these to somewhere that makes sense +void GetColumn( matrix3x4_t& src, int column, Vector &dest ); +void SetColumn( Vector &src, int column, matrix3x4_t& dest ); + +EXTERN_RECV_TABLE(DT_BaseAnimating); + + +extern void DevMsgRT( PRINTF_FORMAT_STRING char const* pMsg, ... ); + +#endif // C_BASEANIMATING_H diff --git a/game/client/c_baseanimatingoverlay.h b/game/client/c_baseanimatingoverlay.h new file mode 100644 index 0000000..de0067d --- /dev/null +++ b/game/client/c_baseanimatingoverlay.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef C_BASEANIMATINGOVERLAY_H +#define C_BASEANIMATINGOVERLAY_H +#pragma once + +#include "c_baseanimating.h" + +// For shared code. +#define CBaseAnimatingOverlay C_BaseAnimatingOverlay + + +class C_BaseAnimatingOverlay : public C_BaseAnimating +{ +public: + DECLARE_CLASS( C_BaseAnimatingOverlay, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + + C_BaseAnimatingOverlay(); + + virtual CStudioHdr *OnNewModel(); + + C_AnimationLayer* GetAnimOverlay( int i ); + void SetNumAnimOverlays( int num ); // This makes sure there is space for this # of layers. + int GetNumAnimOverlays() const; + + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + + void CheckForLayerChanges( CStudioHdr *hdr, float currentTime ); + + // model specific + virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); + virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); + + enum + { + MAX_OVERLAYS = 15, + }; + + CUtlVector < C_AnimationLayer > m_AnimOverlay; + + CUtlVector < CInterpolatedVar< C_AnimationLayer > > m_iv_AnimOverlay; + + float m_flOverlayPrevEventCycle[ MAX_OVERLAYS ]; + +private: + C_BaseAnimatingOverlay( const C_BaseAnimatingOverlay & ); // not defined, not accessible +}; + + +EXTERN_RECV_TABLE(DT_BaseAnimatingOverlay); + + +#endif // C_BASEANIMATINGOVERLAY_H + + + + diff --git a/game/client/c_basecombatcharacter.h b/game/client/c_basecombatcharacter.h new file mode 100644 index 0000000..0a135b0 --- /dev/null +++ b/game/client/c_basecombatcharacter.h @@ -0,0 +1,199 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the client-side representation of CBaseCombatCharacter. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_BASECOMBATCHARACTER_H +#define C_BASECOMBATCHARACTER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "c_baseflex.h" +#ifdef GLOWS_ENABLE +#include "glow_outline_effect.h" +#endif // GLOWS_ENABLE + +class C_BaseCombatWeapon; +class C_WeaponCombatShield; + +#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f + +class C_BaseCombatCharacter : public C_BaseFlex +{ + DECLARE_CLASS( C_BaseCombatCharacter, C_BaseFlex ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_BaseCombatCharacter( void ); + virtual ~C_BaseCombatCharacter( void ); + + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + virtual bool IsBaseCombatCharacter( void ) { return true; }; + virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return this; } + + // ----------------------- + // Vision + // ----------------------- + enum FieldOfViewCheckType { USE_FOV, DISREGARD_FOV }; + bool IsAbleToSee( const CBaseEntity *entity, FieldOfViewCheckType checkFOV ); // Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo... + bool IsAbleToSee( C_BaseCombatCharacter *pBCC, FieldOfViewCheckType checkFOV ); // Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo... + + virtual bool IsLookingTowards( const CBaseEntity *target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED. + virtual bool IsLookingTowards( const Vector &target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED. + + virtual bool IsInFieldOfView( CBaseEntity *entity ) const; // Calls IsLookingAt with the current field of view. + virtual bool IsInFieldOfView( const Vector &pos ) const; + + enum LineOfSightCheckType + { + IGNORE_NOTHING, + IGNORE_ACTORS + }; + virtual bool IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType = IGNORE_NOTHING ) const;// strictly LOS check with no other considerations + virtual bool IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity *entityToIgnore = NULL ) const; + + + // ----------------------- + // Ammo + // ----------------------- + void RemoveAmmo( int iCount, int iAmmoIndex ); + void RemoveAmmo( int iCount, const char *szName ); + void RemoveAllAmmo( ); + int GetAmmoCount( int iAmmoIndex ) const; + int GetAmmoCount( char *szName ) const; + + C_BaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class + virtual bool Weapon_Switch( C_BaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); + virtual bool Weapon_CanSwitchTo(C_BaseCombatWeapon *pWeapon); + + // I can't use my current weapon anymore. Switch me to the next best weapon. + bool SwitchToNextBestWeapon(C_BaseCombatWeapon *pCurrent); + + virtual C_BaseCombatWeapon *GetActiveWeapon( void ) const; + int WeaponCount() const; + C_BaseCombatWeapon *GetWeapon( int i ) const; + + // This is a sort of hack back-door only used by physgun! + void SetAmmoCount( int iCount, int iAmmoIndex ); + + float GetNextAttack() const { return m_flNextAttack; } + void SetNextAttack( float flWait ) { m_flNextAttack = flWait; } + + virtual int BloodColor(); + + // Blood color (see BLOOD_COLOR_* macros in baseentity.h) + void SetBloodColor( int nBloodColor ); + + virtual void DoMuzzleFlash(); + +#ifdef GLOWS_ENABLE + CGlowObject *GetGlowObject( void ){ return m_pGlowEffect; } + virtual void GetGlowEffectColor( float *r, float *g, float *b ); +// void EnableGlowEffect( float r, float g, float b ); + + void SetClientSideGlowEnabled( bool bEnabled ){ m_bClientSideGlowEnabled = bEnabled; UpdateGlowEffect(); } + bool IsClientSideGlowEnabled( void ){ return m_bClientSideGlowEnabled; } +#endif // GLOWS_ENABLE + +public: + + float m_flNextAttack; + +protected: + +#ifdef GLOWS_ENABLE + virtual void UpdateGlowEffect( void ); + virtual void DestroyGlowEffect( void ); +#endif // GLOWS_ENABLE + + int m_bloodColor; // color of blood particless + +private: + bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const; + + CNetworkArray( int, m_iAmmo, MAX_AMMO_TYPES ); + + CHandle m_hMyWeapons[MAX_WEAPONS]; + CHandle< C_BaseCombatWeapon > m_hActiveWeapon; + +#ifdef GLOWS_ENABLE + bool m_bClientSideGlowEnabled; // client-side only value used for spectator + bool m_bGlowEnabled; // networked value + bool m_bOldGlowEnabled; + CGlowObject *m_pGlowEffect; +#endif // GLOWS_ENABLE + +private: + C_BaseCombatCharacter( const C_BaseCombatCharacter & ); // not defined, not accessible + + +//----------------------- +#ifdef INVASION_CLIENT_DLL +public: + virtual void Release( void ); + virtual void SetDormant( bool bDormant ); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + + // TF2 Powerups + virtual bool CanBePoweredUp( void ) { return true; } + bool HasPowerup( int iPowerup ) { return ( m_iPowerups & (1 << iPowerup) ) != 0; }; + virtual void PowerupStart( int iPowerup, bool bInitial ); + virtual void PowerupEnd( int iPowerup ); + void RemoveAllPowerups( void ); + + // Powerup effects + void AddEMPEffect( float flSize ); + void AddBuffEffect( float flSize ); + + C_WeaponCombatShield *GetShield( void ); + +public: + int m_iPowerups; + int m_iPrevPowerups; +#endif + +}; + +inline C_BaseCombatCharacter *ToBaseCombatCharacter( C_BaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsBaseCombatCharacter() ) + return NULL; + +#if _DEBUG + return dynamic_cast( pEntity ); +#else + return static_cast( pEntity ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline int C_BaseCombatCharacter::WeaponCount() const +{ + return MAX_WEAPONS; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : i - +//----------------------------------------------------------------------------- +inline C_BaseCombatWeapon *C_BaseCombatCharacter::GetWeapon( int i ) const +{ + Assert( (i >= 0) && (i < MAX_WEAPONS) ); + return m_hMyWeapons[i].Get(); +} + +EXTERN_RECV_TABLE(DT_BaseCombatCharacter); + +#endif // C_BASECOMBATCHARACTER_H diff --git a/game/client/c_basecombatweapon.h b/game/client/c_basecombatweapon.h new file mode 100644 index 0000000..1523bd0 --- /dev/null +++ b/game/client/c_basecombatweapon.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's CBaseCombatWeapon entity +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#ifndef C_BASECOMBATWEAPON_H +#define C_BASECOMBATWEAPON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basecombatweapon_shared.h" +#include "weapons_resource.h" + +class CViewSetup; +class C_BaseViewModel; + +// Accessors for local weapons +C_BaseCombatWeapon *GetActiveWeapon( void ); + + +#endif // C_BASECOMBATWEAPON \ No newline at end of file diff --git a/game/client/c_basedoor.h b/game/client/c_basedoor.h new file mode 100644 index 0000000..852f2de --- /dev/null +++ b/game/client/c_basedoor.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_BASEDOOR_H ) +#define C_BASEDOOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" + +#if defined( CLIENT_DLL ) +#define CBaseDoor C_BaseDoor +#endif + +class C_BaseDoor : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_BaseDoor, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_BaseDoor( void ); + ~C_BaseDoor( void ); + +public: + float m_flWaveHeight; +}; + +#endif // C_BASEDOOR_H \ No newline at end of file diff --git a/game/client/c_baseentity.h b/game/client/c_baseentity.h new file mode 100644 index 0000000..f2e3a06 --- /dev/null +++ b/game/client/c_baseentity.h @@ -0,0 +1,2265 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A base class for the client-side representation of entities. +// +// This class encompasses both entities that are created on the server +// and networked to the client AND entities that are created on the +// client. +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef C_BASEENTITY_H +#define C_BASEENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "icliententityinternal.h" +#include "engine/ivmodelinfo.h" +#include "engine/ivmodelrender.h" +#include "client_class.h" +#include "iclientshadowmgr.h" +#include "ehandle.h" +#include "iclientunknown.h" +#include "client_thinklist.h" +#if !defined( NO_ENTITY_PREDICTION ) +#include "predictableid.h" +#endif +#include "soundflags.h" +#include "shareddefs.h" +#include "networkvar.h" +#include "interpolatedvar.h" +#include "collisionproperty.h" +#include "particle_property.h" +#include "toolframework/itoolentity.h" +#include "tier0/threadtools.h" + +class C_Team; +class IPhysicsObject; +class IClientVehicle; +class CPredictionCopy; +class C_BasePlayer; +struct studiohdr_t; +class CStudioHdr; +class CDamageModifier; +class IRecipientFilter; +class CUserCmd; +struct solid_t; +class ISave; +class IRestore; +class C_BaseAnimating; +class C_AI_BaseNPC; +struct EmitSound_t; +class C_RecipientFilter; +class CTakeDamageInfo; +class C_BaseCombatCharacter; +class CEntityMapData; +class ConVar; +class CDmgAccumulator; +class IHasAttributes; +class ILuaObject; +struct gamevcollisionevent_t; + +struct CSoundParameters; + +typedef unsigned int AimEntsListHandle_t; + +#define INVALID_AIMENTS_LIST_HANDLE (AimEntsListHandle_t)~0 + +extern void RecvProxy_IntToColor32( const CRecvProxyData *pData, void *pStruct, void *pOut ); +extern void RecvProxy_LocalVelocity( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +enum CollideType_t +{ + ENTITY_SHOULD_NOT_COLLIDE = 0, + ENTITY_SHOULD_COLLIDE, + ENTITY_SHOULD_RESPOND +}; + +class VarMapEntry_t +{ + + +public: + unsigned short type; + unsigned short m_bNeedsToInterpolate; // Set to false when this var doesn't + // need Interpolate() called on it anymore. + void *data; + IInterpolatedVar *watcher; +}; + +struct VarMapping_t +{ + VarMapping_t() + { + m_nInterpolatedEntries = 0; + } + + CUtlVector< VarMapEntry_t > m_Entries; + int m_nInterpolatedEntries; + float m_lastInterpolationTime; +}; + + + +#define DECLARE_INTERPOLATION() + + +// How many data slots to use when in multiplayer. +#define MULTIPLAYER_BACKUP 90 + + +struct serialentity_t; + +typedef CHandle EHANDLE; // The client's version of EHANDLE. + +typedef void (C_BaseEntity::*BASEPTR)(void); +typedef void (C_BaseEntity::*ENTITYFUNCPTR)(C_BaseEntity *pOther ); + +// For entity creation on the client +typedef C_BaseEntity* (*DISPATCHFUNCTION)( void ); + +#include "touchlink.h" +#include "groundlink.h" + +#if !defined( NO_ENTITY_PREDICTION ) +//----------------------------------------------------------------------------- +// Purpose: For fully client side entities we use this information to determine +// authoritatively if the server has acknowledged creating this entity, etc. +//----------------------------------------------------------------------------- +struct PredictionContext +{ + PredictionContext() + { + m_bActive = false; + m_nCreationCommandNumber = -1; + m_pszCreationModule = NULL; + m_nCreationLineNumber = 0; + m_hServerEntity = NULL; + } + + // The command_number of the usercmd which created this entity + bool m_bActive; + int m_nCreationCommandNumber; + char const *m_pszCreationModule; + int m_nCreationLineNumber; + // The entity to whom we are attached + CHandle< C_BaseEntity > m_hServerEntity; +}; +#endif + +//----------------------------------------------------------------------------- +// Purpose: think contexts +//----------------------------------------------------------------------------- +struct thinkfunc_t +{ + BASEPTR m_pfnThink; + string_t m_iszContext; + int m_nNextThinkTick; + int m_nLastThinkTick; +}; + +#define CREATE_PREDICTED_ENTITY( className ) \ + C_BaseEntity::CreatePredictedEntityByName( className, __FILE__, __LINE__ ); + + + +// Entity flags that only exist on the client. +#define ENTCLIENTFLAG_GETTINGSHADOWRENDERBOUNDS 0x0001 // Tells us if we're getting the real ent render bounds or the shadow render bounds. +#define ENTCLIENTFLAG_DONTUSEIK 0x0002 // Don't use IK on this entity even if its model has IK. +#define ENTCLIENTFLAG_ALWAYS_INTERPOLATE 0x0004 // Used by view models. + +//----------------------------------------------------------------------------- +// Purpose: Base client side entity object +//----------------------------------------------------------------------------- +class C_BaseEntity : public IClientEntity +{ +// Construction + DECLARE_CLASS_NOBASE( C_BaseEntity ); + + friend class CPrediction; + friend void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float flOldValue ); + +public: + DECLARE_DATADESC(); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_BaseEntity(); + virtual ~C_BaseEntity(); + + static C_BaseEntity *CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist = false ); + + // FireBullets uses shared code for prediction. + virtual void FireBullets( const FireBulletsInfo_t &info ); + virtual void ModifyFireBulletsDamage( CTakeDamageInfo* dmgInfo ) {} + virtual bool ShouldDrawUnderwaterBulletBubbles(); + virtual bool ShouldDrawWaterImpacts( void ) { return true; } + virtual bool HandleShotImpactingWater( const FireBulletsInfo_t &info, + const Vector &vecEnd, ITraceFilter *pTraceFilter, Vector *pVecTracerDest ); + virtual ITraceFilter* GetBeamTraceFilter( void ); + virtual void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL ); + virtual void DoImpactEffect( trace_t &tr, int nDamageType ); + virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + virtual int GetTracerAttachment( void ); + void ComputeTracerStartPosition( const Vector &vecShotSrc, Vector *pVecTracerStart ); + void TraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType ); + virtual int BloodColor(); + virtual const char* GetTracerType(); + + virtual void Spawn( void ); + virtual void SpawnClientEntity( void ); + virtual void Precache( void ); + virtual void Activate(); + + virtual void ParseMapData( CEntityMapData *mapData ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual bool KeyValue( const char *szKeyName, float flValue ); + virtual bool KeyValue( const char *szKeyName, const Vector &vecValue ); + virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); + + // Entities block Line-Of-Sight for NPCs by default. + // Set this to false if you want to change this behavior. + void SetBlocksLOS( bool bBlocksLOS ); + bool BlocksLOS( void ); + void SetAIWalkable( bool bBlocksLOS ); + bool IsAIWalkable( void ); + + + void Interp_SetupMappings( VarMapping_t *map ); + + // Returns 1 if there are no more changes (ie: we could call RemoveFromInterpolationList). + int Interp_Interpolate( VarMapping_t *map, float currentTime ); + + void Interp_RestoreToLastNetworked( VarMapping_t *map ); + void Interp_UpdateInterpolationAmounts( VarMapping_t *map ); + void Interp_HierarchyUpdateInterpolationAmounts(); + + // Called by the CLIENTCLASS macros. + virtual bool Init( int entnum, int iSerialNum ); + + // Called in the destructor to shutdown everything. + void Term(); + + // memory handling, uses calloc so members are zero'd out on instantiation + void *operator new( size_t stAllocateBlock ); + void *operator new[]( size_t stAllocateBlock ); + void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); + void *operator new[]( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); + void operator delete( void *pMem ); + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete( pMem ); } + + // This just picks one of the routes to IClientUnknown. + IClientUnknown* GetIClientUnknown() { return this; } + virtual C_BaseAnimating* GetBaseAnimating() { return NULL; } + virtual void SetClassname( const char *className ); + + string_t m_iClassname; + +// IClientUnknown overrides. +public: + + virtual void SetRefEHandle( const CBaseHandle &handle ); + virtual const CBaseHandle& GetRefEHandle() const; + + void SetToolHandle( HTOOLHANDLE handle ); + HTOOLHANDLE GetToolHandle() const; + + void EnableInToolView( bool bEnable ); + bool IsEnabledInToolView() const; + + void SetToolRecording( bool recording ); + bool IsToolRecording() const; + bool HasRecordedThisFrame() const; + virtual void RecordToolMessage(); + + // used to exclude entities from being recorded in the SFM tools + void DontRecordInTools(); + bool ShouldRecordInTools() const; + + virtual void Release(); + virtual ICollideable* GetCollideable() { return &m_Collision; } + virtual IClientNetworkable* GetClientNetworkable() { return this; } + virtual IClientRenderable* GetClientRenderable() { return this; } + virtual IClientEntity* GetIClientEntity() { return this; } + virtual C_BaseEntity* GetBaseEntity() { return this; } + virtual IClientThinkable* GetClientThinkable() { return this; } + + +// Methods of IClientRenderable +public: + + virtual const Vector& GetRenderOrigin( void ); + virtual const QAngle& GetRenderAngles( void ); + virtual Vector GetObserverCamOrigin( void ) { return GetRenderOrigin(); } // Return the origin for player observers tracking this target + virtual const matrix3x4_t & RenderableToWorldTransform(); + virtual bool IsTransparent( void ); + virtual bool IsTwoPass( void ); + virtual bool UsesPowerOfTwoFrameBufferTexture(); + virtual bool UsesFullFrameBufferTexture(); + virtual bool IgnoresZBuffer( void ) const; + virtual const model_t *GetModel( void ) const; + virtual int DrawModel( int flags ); + virtual void ComputeFxBlend( void ); + virtual int GetFxBlend( void ); + virtual bool LODTest() { return true; } // NOTE: UNUSED + virtual void GetRenderBounds( Vector& mins, Vector& maxs ); + virtual IPVSNotify* GetPVSNotifyInterface(); + virtual void GetRenderBoundsWorldspace( Vector& absMins, Vector& absMaxs ); + + virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType ); + + // Determine the color modulation amount + virtual void GetColorModulation( float* color ); + + virtual void OnThreadedDrawSetup() {} +public: + virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + + // To mimic server call convention + C_BaseEntity *GetOwnerEntity( void ) const; + void SetOwnerEntity( C_BaseEntity *pOwner ); + + C_BaseEntity *GetEffectEntity( void ) const; + void SetEffectEntity( C_BaseEntity *pEffectEnt ); + + // This function returns a value that scales all damage done by this entity. + // Use CDamageModifier to hook in damage modifiers on a guy. + virtual float GetAttackDamageScale( void ); + +// IClientNetworkable implementation. +public: + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + + // save out interpolated values + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataUnchangedInPVS(); + + virtual void ValidateModelIndex( void ); + + // pvs info. NOTE: Do not override these!! + virtual void SetDormant( bool bDormant ); + virtual bool IsDormant( void ); + + // Tells the entity that it's about to be destroyed due to the client receiving + // an uncompressed update that's caused it to destroy all entities & recreate them. + virtual void SetDestroyedOnRecreateEntities( void ); + + virtual int GetEFlags() const; + virtual void SetEFlags( int iEFlags ); + void AddEFlags( int nEFlagMask ); + void RemoveEFlags( int nEFlagMask ); + bool IsEFlagSet( int nEFlagMask ) const; + + // checks to see if the entity is marked for deletion + bool IsMarkedForDeletion( void ); + + virtual int entindex( void ) const; + + // This works for client-only entities and returns the GetEntryIndex() of the entity's handle, + // so the sound system can get an IClientEntity from it. + int GetSoundSourceIndex() const; + + // Server to client message received + virtual void ReceiveMessage( int classID, bf_read &msg ); + + virtual void* GetDataTableBasePtr(); + +// IClientThinkable. +public: + // Called whenever you registered for a think message (with SetNextClientThink). + virtual void ClientThink(); + + virtual ClientThinkHandle_t GetThinkHandle(); + virtual void SetThinkHandle( ClientThinkHandle_t hThink ); + + +public: + + void AddVar( void *data, IInterpolatedVar *watcher, int type, bool bSetup=false ); + void RemoveVar( void *data, bool bAssert=true ); + VarMapping_t* GetVarMapping(); + + VarMapping_t m_VarMap; + + +public: + // An inline version the game code can use + CCollisionProperty *CollisionProp(); + const CCollisionProperty*CollisionProp() const; + CParticleProperty *ParticleProp(); + const CParticleProperty *ParticleProp() const; + + // Simply here for game shared + bool IsFloating(); + + virtual bool ShouldSavePhysics(); + +// save/restore stuff + virtual void OnSave(); + virtual void OnRestore(); + // capabilities for save/restore + virtual int ObjectCaps( void ); + // only overload these if you have special data to serialize + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + +private: + + int SaveDataDescBlock( ISave &save, datamap_t *dmap ); + int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); + + // Called after restoring data into prediction slots. This function is used in place of proxies + // on the variables, so if some variable like m_nModelIndex needs to update other state (like + // the model pointer), it is done here. + void OnPostRestoreData(); + +public: + + // Called after spawn, and in the case of self-managing objects, after load + virtual bool CreateVPhysics(); + + // Convenience routines to init the vphysics simulation for this object. + // This creates a static object. Something that behaves like world geometry - solid, but never moves + IPhysicsObject *VPhysicsInitStatic( void ); + + // This creates a normal vphysics simulated object + IPhysicsObject *VPhysicsInitNormal( SolidType_t solidType, int nSolidFlags, bool createAsleep, solid_t *pSolid = NULL ); + + // This creates a vphysics object with a shadow controller that follows the AI + // Move the object to where it should be and call UpdatePhysicsShadowToCurrentPosition() + IPhysicsObject *VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation, solid_t *pSolid = NULL ); + +private: + // called by all vphysics inits + bool VPhysicsInitSetup(); +public: + + void VPhysicsSetObject( IPhysicsObject *pPhysics ); + // destroy and remove the physics object for this entity + virtual void VPhysicsDestroyObject( void ); + + // Purpose: My physics object has been updated, react or extract data + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + inline IPhysicsObject *VPhysicsGetObject( void ) const { return m_pPhysicsObject; } + virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + virtual bool VPhysicsIsFlesh( void ); + +// IClientEntity implementation. +public: + virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual bool UsesFlexDelayedWeights() { return false; } + virtual void DoAnimationEvents( void ); + + // Add entity to visible entities list? + virtual void AddEntity( void ); + + virtual const Vector& GetAbsOrigin( void ) const; + virtual const QAngle& GetAbsAngles( void ) const; + + const Vector& GetNetworkOrigin() const; + const QAngle& GetNetworkAngles() const; + + void SetNetworkOrigin( const Vector& org ); + void SetNetworkAngles( const QAngle& ang ); + + const Vector& GetLocalOrigin( void ) const; + void SetLocalOrigin( const Vector& origin ); + vec_t GetLocalOriginDim( int iDim ) const; // You can use the X_INDEX, Y_INDEX, and Z_INDEX defines here. + void SetLocalOriginDim( int iDim, vec_t flValue ); + + const QAngle& GetLocalAngles( void ) const; + void SetLocalAngles( const QAngle& angles ); + vec_t GetLocalAnglesDim( int iDim ) const; // You can use the X_INDEX, Y_INDEX, and Z_INDEX defines here. + void SetLocalAnglesDim( int iDim, vec_t flValue ); + + virtual const Vector& GetPrevLocalOrigin() const; + virtual const QAngle& GetPrevLocalAngles() const; + + void SetLocalTransform( const matrix3x4_t &localTransform ); + + void SetModelName( string_t name ); + string_t GetModelName( void ) const; + + int GetModelIndex( void ) const; + void SetModelIndex( int index ); + virtual int CalcOverrideModelIndex() { return -1; } + + // These methods return a *world-aligned* box relative to the absorigin of the entity. + // This is used for collision purposes and is *not* guaranteed + // to surround the entire entity's visual representation + // NOTE: It is illegal to ask for the world-aligned bounds for + // SOLID_BSP objects + virtual const Vector& WorldAlignMins( ) const; + virtual const Vector& WorldAlignMaxs( ) const; + + // This defines collision bounds *in whatever space is currently defined by the solid type* + // SOLID_BBOX: World Align + // SOLID_OBB: Entity space + // SOLID_BSP: Entity space + // SOLID_VPHYSICS Not used + void SetCollisionBounds( const Vector& mins, const Vector &maxs ); + + // NOTE: These use the collision OBB to compute a reasonable center point for the entity + virtual const Vector& WorldSpaceCenter( ) const; + + // FIXME: Do we want this? + const Vector& WorldAlignSize( ) const; + bool IsPointSized() const; + + // Returns a radius of a sphere + // *centered at the world space center* bounding the collision representation + // of the entity. NOTE: The world space center *may* move when the entity rotates. + float BoundingRadius() const; + + // Used when the collision prop is told to ask game code for the world-space surrounding box + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + virtual float GetHealthBarHeightOffset() const { return 0.f; } + + // Returns the entity-to-world transform + matrix3x4_t &EntityToWorldTransform(); + const matrix3x4_t &EntityToWorldTransform() const; + + // Some helper methods that transform a point from entity space to world space + back + void EntityToWorldSpace( const Vector &in, Vector *pOut ) const; + void WorldToEntitySpace( const Vector &in, Vector *pOut ) const; + + // This function gets your parent's transform. If you're parented to an attachment, + // this calculates the attachment's transform and gives you that. + // + // You must pass in tempMatrix for scratch space - it may need to fill that in and return it instead of + // pointing you right at a variable in your parent. + matrix3x4_t& GetParentToWorldTransform( matrix3x4_t &tempMatrix ); + + void GetVectors(Vector* forward, Vector* right, Vector* up) const; + + // Sets abs angles, but also sets local angles to be appropriate + void SetAbsOrigin( const Vector& origin ); + void SetAbsAngles( const QAngle& angles ); + + void AddFlag( int flags ); + void RemoveFlag( int flagsToRemove ); + void ToggleFlag( int flagToToggle ); + int GetFlags( void ) const; + void ClearFlags(); + + MoveType_t GetMoveType( void ) const; + MoveCollide_t GetMoveCollide( void ) const; + virtual SolidType_t GetSolid( void ) const; + + virtual int GetSolidFlags( void ) const; + bool IsSolidFlagSet( int flagMask ) const; + void SetSolidFlags( int nFlags ); + void AddSolidFlags( int nFlags ); + void RemoveSolidFlags( int nFlags ); + bool IsSolid() const; + + virtual class CMouthInfo *GetMouth( void ); + + // Retrieve sound spatialization info for the specified sound on this entity + // Return false to indicate sound is not audible + virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); + + // Attachments + virtual int LookupAttachment( const char *pAttachmentName ) { return -1; } + virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachment( int number, Vector &origin ); + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); + + // Team handling + virtual C_Team *GetTeam( void ); + virtual int GetTeamNumber( void ) const; + virtual void ChangeTeam( int iTeamNum ); // Assign this entity to a team. + virtual int GetRenderTeamNumber( void ); + virtual bool InSameTeam( C_BaseEntity *pEntity ); // Returns true if the specified entity is on the same team as this one + virtual bool InLocalTeam( void ); + + // ID Target handling + virtual bool IsValidIDTarget( void ) { return false; } + virtual const char *GetIDString( void ) { return ""; }; + + // See CSoundEmitterSystem + virtual void ModifyEmitSoundParams( EmitSound_t ¶ms ); + + void EmitSound( const char *soundname, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. ); + void EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. ); + void StopSound( const char *soundname ); + void StopSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle ); + void GenderExpandString( char const *in, char *out, int maxlen ); + + static float GetSoundDuration( const char *soundname, char const *actormodel ); + + static bool GetParametersForSound( const char *soundname, CSoundParameters ¶ms, const char *actormodel ); + static bool GetParametersForSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, CSoundParameters ¶ms, const char *actormodel ); + + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, const Vector *pOrigin = NULL, float soundtime = 0.0f, float *duration = NULL ); + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, HSOUNDSCRIPTHANDLE& handle, const Vector *pOrigin = NULL, float soundtime = 0.0f, float *duration = NULL ); + static void StopSound( int iEntIndex, const char *soundname ); + static soundlevel_t LookupSoundLevel( const char *soundname ); + static soundlevel_t LookupSoundLevel( const char *soundname, HSOUNDSCRIPTHANDLE& handle ); + + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params ); + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params, HSOUNDSCRIPTHANDLE& handle ); + + static void StopSound( int iEntIndex, int iChannel, const char *pSample ); + + static void EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, int flags = 0, float soundtime = 0.0f, float *duration = NULL ); + + // These files need to be listed in scripts/game_sounds_manifest.txt + static HSOUNDSCRIPTHANDLE PrecacheScriptSound( const char *soundname ); + static void PrefetchScriptSound( const char *soundname ); + + // For each client who appears to be a valid recipient, checks the client has disabled CC and if so, removes them from + // the recipient list. + static void RemoveRecipientsIfNotCloseCaptioning( C_RecipientFilter& filter ); + static void EmitCloseCaption( IRecipientFilter& filter, int entindex, char const *token, CUtlVector< Vector >& soundorigins, float duration, bool warnifmissing = false ); + + // Moves all aiments into their correct position for the frame + static void MarkAimEntsDirty(); + static void CalcAimEntPositions(); + + static bool IsPrecacheAllowed(); + static void SetAllowPrecache( bool allow ); + + static bool m_bAllowPrecache; + + static bool IsSimulatingOnAlternateTicks(); + +// C_BaseEntity local functions +public: + + void UpdatePartitionListEntry(); + + // This can be used to setup the entity as a client-only entity. + // Override this to perform per-entity clientside setup + virtual bool InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup ); + + + + + + // This function gets called on all client entities once per simulation phase. + // It dispatches events like OnDataChanged(), and calls the legacy function AddEntity(). + virtual void Simulate(); + + + // This event is triggered during the simulation phase if an entity's data has changed. It is + // better to hook this instead of PostDataUpdate() because in PostDataUpdate(), server entity origins + // are incorrect and attachment points can't be used. + virtual void OnDataChanged( DataUpdateType_t type ); + + // This is called once per frame before any data is read in from the server. + virtual void OnPreDataChanged( DataUpdateType_t type ); + + bool IsStandable() const; + bool IsBSPModel() const; + + + // If this is a vehicle, returns the vehicle interface + virtual IClientVehicle* GetClientVehicle() { return NULL; } + + // Returns the aiment render origin + angles + virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + // get network origin from previous update + virtual const Vector& GetOldOrigin(); + + // Methods relating to traversing hierarchy + C_BaseEntity *GetMoveParent( void ) const; + C_BaseEntity *GetRootMoveParent(); + C_BaseEntity *FirstMoveChild( void ) const; + C_BaseEntity *NextMovePeer( void ) const; + + inline ClientEntityHandle_t GetClientHandle() const { return ClientEntityHandle_t( m_RefEHandle ); } + inline bool IsServerEntity( void ); + + virtual RenderGroup_t GetRenderGroup(); + + virtual void GetToolRecordingState( KeyValues *msg ); + virtual void CleanupToolRecordingState( KeyValues *msg ); + + // The value returned by here determines whether or not (and how) the entity + // is put into the spatial partition. + virtual CollideType_t GetCollideType( void ); + + virtual bool ShouldDraw(); + inline bool IsVisible() const { return m_hRender != INVALID_CLIENT_RENDER_HANDLE; } + virtual void UpdateVisibility(); + + // Returns true if the entity changes its position every frame on the server but it doesn't + // set animtime. In that case, the client returns true here so it copies the server time to + // animtime in OnDataChanged and the position history is correct for interpolation. + virtual bool IsSelfAnimating(); + + // Set appropriate flags and store off data when these fields are about to change + virtual void OnLatchInterpolatedVariables( int flags ); + // For predictable entities, stores last networked value + void OnStoreLastNetworkedValue(); + + // Initialize things given a new model. + virtual CStudioHdr *OnNewModel(); + virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect ); + + bool IsSimulatedEveryTick() const; + bool IsAnimatedEveryTick() const; + void SetSimulatedEveryTick( bool sim ); + void SetAnimatedEveryTick( bool anim ); + + void Interp_Reset( VarMapping_t *map ); + virtual void ResetLatched(); + + float GetInterpolationAmount( int flags ); + float GetLastChangeTime( int flags ); + + // Interpolate the position for rendering + virtual bool Interpolate( float currentTime ); + + // Did the object move so far that it shouldn't interpolate? + bool Teleported( void ); + // Is this a submodel of the world ( *1 etc. in name ) ( brush models only ) + virtual bool IsSubModel( void ); + // Deal with EF_* flags + virtual void CreateLightEffects( void ); + + void AddToAimEntsList(); + void RemoveFromAimEntsList(); + + // Reset internal fields + virtual void Clear( void ); + // Helper to draw raw brush models + virtual int DrawBrushModel( bool bTranslucent, int nFlags, bool bTwoPass ); + + // returns the material animation start time + virtual float GetTextureAnimationStartTime(); + // Indicates that a texture animation has wrapped + virtual void TextureAnimationWrapped(); + + // Set the next think time. Pass in CLIENT_THINK_ALWAYS to have Think() called each frame. + virtual void SetNextClientThink( float nextThinkTime ); + + // anything that has health can override this... + virtual void SetHealth(int iHealth) {} + virtual int GetHealth() const { return 0; } + virtual int GetMaxHealth() const { return 1; } + virtual bool IsVisibleToTargetID( void ) const { return false; } + virtual bool IsHealthBarVisible( void ) const { return false; } + + // Returns the health fraction + float HealthFraction() const; + + // Should this object cast shadows? + virtual ShadowType_t ShadowCastType(); + + // Should this object receive shadows? + virtual bool ShouldReceiveProjectedTextures( int flags ); + + // Shadow-related methods + virtual bool IsShadowDirty( ); + virtual void MarkShadowDirty( bool bDirty ); + virtual IClientRenderable *GetShadowParent(); + virtual IClientRenderable *FirstShadowChild(); + virtual IClientRenderable *NextShadowPeer(); + + // Sets up a render handle so the leaf system will draw this entity. + void AddToLeafSystem(); + void AddToLeafSystem( RenderGroup_t group ); + // remove entity form leaf system again + void RemoveFromLeafSystem(); + + // A method to apply a decal to an entity + virtual void AddDecal( const Vector& rayStart, const Vector& rayEnd, + const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); + + virtual void AddColoredDecal( const Vector& rayStart, const Vector& rayEnd, + const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); + + // A method to remove all decals from an entity + void RemoveAllDecals( void ); + + // Is this a brush model? + bool IsBrushModel() const; + + // A random value 0-1 used by proxies to make sure they're not all in sync + float ProxyRandomValue() const { return m_flProxyRandomValue; } + + // The spawn time of this entity + float SpawnTime() const { return m_flSpawnTime; } + + virtual bool IsClientCreated( void ) const; + + virtual void UpdateOnRemove( void ); + + virtual void SUB_Remove( void ); + + // Prediction stuff + ///////////////// + void CheckInitPredictable( const char *context ); + + void AllocateIntermediateData( void ); + void DestroyIntermediateData( void ); + void ShiftIntermediateDataForward( int slots_to_remove, int previous_last_slot ); + + void *GetPredictedFrame( int framenumber ); + void *GetOriginalNetworkDataObject( void ); + bool IsIntermediateDataAllocated( void ) const; + + void InitPredictable( void ); + void ShutdownPredictable( void ); + + virtual void SetPredictable( bool state ); + bool GetPredictable( void ) const; + void PreEntityPacketReceived( int commands_acknowledged ); + void PostEntityPacketReceived( void ); + bool PostNetworkDataReceived( int commands_acknowledged ); + bool GetPredictionEligible( void ) const; + void SetPredictionEligible( bool canpredict ); + + enum + { + SLOT_ORIGINALDATA = -1, + }; + + int SaveData( const char *context, int slot, int type ); + virtual int RestoreData( const char *context, int slot, int type ); + + virtual char const * DamageDecal( int bitsDamageType, int gameMaterial ); + virtual void DecalTrace( trace_t *pTrace, char const *decalName ); + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + + virtual bool ShouldPredict( void ) { return false; }; + // interface function pointers + void (C_BaseEntity::*m_pfnThink)(void); + virtual void Think( void ) + { + AssertMsg( m_pfnThink != &C_BaseEntity::Think, "Infinite recursion is infinitely bad." ); + + if ( m_pfnThink ) + { + ( this->*m_pfnThink )(); + } + } + + void PhysicsDispatchThink( BASEPTR thinkFunc ); + + // Toggle the visualization of the entity's abs/bbox + enum + { + VISUALIZE_COLLISION_BOUNDS = 0x1, + VISUALIZE_SURROUNDING_BOUNDS = 0x2, + VISUALIZE_RENDER_BOUNDS = 0x4, + }; + + void ToggleBBoxVisualization( int fVisFlags ); + void DrawBBoxVisualizations( void ); + +// Methods implemented on both client and server +public: + void SetSize( const Vector &vecMin, const Vector &vecMax ); // UTIL_SetSize( pev, mins, maxs ); + char const *GetClassname( void ); + char const *GetDebugName( void ); + static int PrecacheModel( const char *name ); + static bool PrecacheSound( const char *name ); + static void PrefetchSound( const char *name ); + void Remove( ); // UTIL_Remove( this ); + +public: + + // Returns the attachment point index on our parent that our transform is relative to. + // 0 if we're relative to the parent's absorigin and absangles. + unsigned char GetParentAttachment() const; + + // Externalized data objects ( see sharreddefs.h for DataObjectType_t ) + bool HasDataObjectType( int type ) const; + void AddDataObjectType( int type ); + void RemoveDataObjectType( int type ); + + void *GetDataObject( int type ); + void *CreateDataObject( int type ); + void DestroyDataObject( int type ); + void DestroyAllDataObjects( void ); + + // Determine approximate velocity based on updates from server + void EstimateAbsVelocity( Vector& vel ); + +#if !defined( NO_ENTITY_PREDICTION ) + // The player drives simulation of this entity + void SetPlayerSimulated( C_BasePlayer *pOwner ); + bool IsPlayerSimulated( void ) const; + CBasePlayer *GetSimulatingPlayer( void ); + void UnsetPlayerSimulated( void ); +#endif + + // Sorry folks, here lies TF2-specific stuff that really has no other place to go + virtual bool CanBePoweredUp( void ) { return false; } + virtual bool AttemptToPowerup( int iPowerup, float flTime, float flAmount = 0, C_BaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL ) { return false; } + + void SetCheckUntouch( bool check ); + bool GetCheckUntouch() const; + + virtual bool IsCurrentlyTouching( void ) const; + + virtual void StartTouch( C_BaseEntity *pOther ); + virtual void Touch( C_BaseEntity *pOther ); + virtual void EndTouch( C_BaseEntity *pOther ); + + void (C_BaseEntity ::*m_pfnTouch)( C_BaseEntity *pOther ); + + void PhysicsStep( void ); + +protected: + static bool sm_bDisableTouchFuncs; // Disables PhysicsTouch and PhysicsStartTouch function calls + +public: + touchlink_t *PhysicsMarkEntityAsTouched( C_BaseEntity *other ); + void PhysicsTouch( C_BaseEntity *pentOther ); + void PhysicsStartTouch( C_BaseEntity *pentOther ); + + // HACKHACK:Get the trace_t from the last physics touch call (replaces the even-hackier global trace vars) + static const trace_t &GetTouchTrace( void ); + + // FIXME: Should be private, but I can't make em private just yet + void PhysicsImpact( C_BaseEntity *other, trace_t &trace ); + void PhysicsMarkEntitiesAsTouching( C_BaseEntity *other, trace_t &trace ); + void PhysicsMarkEntitiesAsTouchingEventDriven( C_BaseEntity *other, trace_t &trace ); + + // Physics helper + static void PhysicsRemoveTouchedList( C_BaseEntity *ent ); + static void PhysicsNotifyOtherOfUntouch( C_BaseEntity *ent, C_BaseEntity *other ); + static void PhysicsRemoveToucher( C_BaseEntity *other, touchlink_t *link ); + + groundlink_t *AddEntityToGroundList( CBaseEntity *other ); + void PhysicsStartGroundContact( CBaseEntity *pentOther ); + + static void PhysicsNotifyOtherOfGroundRemoval( CBaseEntity *ent, CBaseEntity *other ); + static void PhysicsRemoveGround( CBaseEntity *other, groundlink_t *link ); + static void PhysicsRemoveGroundList( CBaseEntity *ent ); + + void StartGroundContact( CBaseEntity *ground ); + void EndGroundContact( CBaseEntity *ground ); + + void SetGroundChangeTime( float flTime ); + float GetGroundChangeTime( void ); + + // Remove this as ground entity for all object resting on this object + void WakeRestingObjects(); + bool HasNPCsOnIt(); + + bool PhysicsCheckWater( void ); + void PhysicsCheckVelocity( void ); + void PhysicsAddHalfGravity( float timestep ); + void PhysicsAddGravityMove( Vector &move ); + + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + + void SetGroundEntity( C_BaseEntity *ground ); + C_BaseEntity *GetGroundEntity( void ); + + void PhysicsPushEntity( const Vector& push, trace_t *pTrace ); + void PhysicsCheckWaterTransition( void ); + + // Performs the collision resolution for fliers. + void PerformFlyCollisionResolution( trace_t &trace, Vector &move ); + void ResolveFlyCollisionBounce( trace_t &trace, Vector &vecVelocity, float flMinTotalElasticity = 0.0f ); + void ResolveFlyCollisionSlide( trace_t &trace, Vector &vecVelocity ); + void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ); + + void PhysicsCheckForEntityUntouch( void ); + + // Creates the shadow (if it doesn't already exist) based on shadow cast type + void CreateShadow(); + + // Destroys the shadow; causes its type to be recomputed if the entity doesn't go away immediately. + void DestroyShadow(); + +protected: + // think function handling + enum thinkmethods_t + { + THINK_FIRE_ALL_FUNCTIONS, + THINK_FIRE_BASE_ONLY, + THINK_FIRE_ALL_BUT_BASE, + }; +public: + + // Unlinks from hierarchy + // Set the movement parent. Your local origin and angles will become relative to this parent. + // If iAttachment is a valid attachment on the parent, then your local origin and angles + // are relative to the attachment on this entity. + void SetParent( C_BaseEntity *pParentEntity, int iParentAttachment=0 ); + + bool PhysicsRunThink( thinkmethods_t thinkMethod = THINK_FIRE_ALL_FUNCTIONS ); + bool PhysicsRunSpecificThink( int nContextIndex, BASEPTR thinkFunc ); + + virtual void PhysicsSimulate( void ); + virtual bool IsAlive( void ); + + bool IsInWorld( void ) { return true; } + + bool IsWorld() { return entindex() == 0; } + ///////////////// + + virtual bool IsPlayer( void ) const { return false; }; + virtual bool IsBaseCombatCharacter( void ) { return false; }; + virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; } + virtual bool IsNPC( void ) { return false; } + C_AI_BaseNPC *MyNPCPointer( void ); + virtual bool IsNextBot() { return false; } + // TF2 specific + virtual bool IsBaseObject( void ) const { return false; } + virtual bool IsBaseCombatWeapon( void ) const { return false; } + virtual class C_BaseCombatWeapon *MyCombatWeaponPointer() { return NULL; } + virtual bool IsCombatItem( void ) const { return false; } + + virtual bool IsBaseTrain( void ) const { return false; } + + // Returns the eye point + angles (used for viewing + shooting) + virtual Vector EyePosition( void ); + virtual const QAngle& EyeAngles( void ); // Direction of eyes + virtual const QAngle& LocalEyeAngles( void ); // Direction of eyes in local space (pl.v_angle) + + // position of ears + virtual Vector EarPosition( void ); + + Vector EyePosition( void ) const; // position of eyes + const QAngle &EyeAngles( void ) const; // Direction of eyes in world space + const QAngle &LocalEyeAngles( void ) const; // Direction of eyes + Vector EarPosition( void ) const; // position of ears + + // Called by physics to see if we should avoid a collision test.... + virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const; + + // Sets physics parameters + void SetFriction( float flFriction ); + + void SetGravity( float flGravity ); + float GetGravity( void ) const; + + // Sets the model from a model index + void SetModelByIndex( int nModelIndex ); + + // Set model... (NOTE: Should only be used by client-only entities + // Returns false if the model name is bogus or otherwise can't be loaded + bool SetModel( const char *pModelName ); + + void SetModelPointer( const model_t *pModel ); + + + // Access movetype and solid. + void SetMoveType( MoveType_t val, MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT ); // Set to one of the MOVETYPE_ defines. + void SetMoveCollide( MoveCollide_t val ); // Set to one of the MOVECOLLIDE_ defines. + void SetSolid( SolidType_t val ); // Set to one of the SOLID_ defines. + + // NOTE: Setting the abs velocity in either space will cause a recomputation + // in the other space, so setting the abs velocity will also set the local vel + void SetLocalVelocity( const Vector &vecVelocity ); + void SetAbsVelocity( const Vector &vecVelocity ); + const Vector& GetLocalVelocity() const; + const Vector& GetAbsVelocity( ) const; + + void ApplyLocalVelocityImpulse( const Vector &vecImpulse ); + void ApplyAbsVelocityImpulse( const Vector &vecImpulse ); + void ApplyLocalAngularVelocityImpulse( const AngularImpulse &angImpulse ); + + // NOTE: Setting the abs velocity in either space will cause a recomputation + // in the other space, so setting the abs velocity will also set the local vel + void SetLocalAngularVelocity( const QAngle &vecAngVelocity ); + const QAngle& GetLocalAngularVelocity( ) const; + +// void SetAbsAngularVelocity( const QAngle &vecAngAbsVelocity ); +// const QAngle& GetAbsAngularVelocity( ) const; + + const Vector& GetBaseVelocity() const; + void SetBaseVelocity( const Vector& v ); + + virtual const Vector &GetViewOffset() const; + virtual void SetViewOffset( const Vector& v ); + +#ifdef SIXENSE + const Vector& GetEyeOffset() const; + void SetEyeOffset( const Vector& v ); + + const QAngle & GetEyeAngleOffset() const; + void SetEyeAngleOffset( const QAngle & qa ); +#endif + + // Invalidates the abs state of all children + void InvalidatePhysicsRecursive( int nChangeFlags ); + + ClientRenderHandle_t GetRenderHandle() const; + + void SetRemovalFlag( bool bRemove ); + + // Effects... + bool IsEffectActive( int nEffectMask ) const; + void AddEffects( int nEffects ); + void RemoveEffects( int nEffects ); + int GetEffects( void ) const; + void ClearEffects( void ); + void SetEffects( int nEffects ); + + // Computes the abs position of a point specified in local space + void ComputeAbsPosition( const Vector &vecLocalPosition, Vector *pAbsPosition ); + + // Computes the abs position of a direction specified in local space + void ComputeAbsDirection( const Vector &vecLocalDirection, Vector *pAbsDirection ); + + // These methods encapsulate MOVETYPE_FOLLOW, which became obsolete + void FollowEntity( CBaseEntity *pBaseEntity, bool bBoneMerge = true ); + void StopFollowingEntity( ); // will also change to MOVETYPE_NONE + bool IsFollowingEntity(); + CBaseEntity *GetFollowedEntity(); + + // For shadows rendering the correct body + sequence... + virtual int GetBody() { return 0; } + virtual int GetSkin() { return 0; } + + // Stubs on client + void NetworkStateManualMode( bool activate ) { } + void NetworkStateChanged() { } + void NetworkStateChanged( void *pVar ) { } + void NetworkStateSetUpdateInterval( float N ) { } + void NetworkStateForceUpdate() { } + + // Think functions with contexts + int RegisterThinkContext( const char *szContext ); + BASEPTR ThinkSet( BASEPTR func, float flNextThinkTime = 0, const char *szContext = NULL ); + void SetNextThink( float nextThinkTime, const char *szContext = NULL ); + float GetNextThink( const char *szContext = NULL ); + float GetLastThink( const char *szContext = NULL ); + int GetNextThinkTick( const char *szContext = NULL ); + int GetLastThinkTick( const char *szContext = NULL ); + + // These set entity flags (EFL_*) to help optimize queries + void CheckHasThinkFunction( bool isThinkingHint = false ); + void CheckHasGamePhysicsSimulation(); + bool WillThink(); + bool WillSimulateGamePhysics(); + int GetFirstThinkTick(); // get first tick thinking on any context + + float GetAnimTime() const; + void SetAnimTime( float at ); + + float GetSimulationTime() const; + void SetSimulationTime( float st ); + + float GetCreateTime() { return m_flCreateTime; } + void SetCreateTime( float flCreateTime ) { m_flCreateTime = flCreateTime; } + + int GetCreationTick() const; + +#ifdef _DEBUG + void FunctionCheck( void *pFunction, const char *name ); + + ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) + { + //COMPILE_TIME_ASSERT( sizeof(func) == 4 ); + m_pfnTouch = func; + //FunctionCheck( *(reinterpret_cast(&m_pfnTouch)), name ); + return func; + } +#endif + + // Gets the model instance + shadow handle + virtual ModelInstanceHandle_t GetModelInstance() { return m_ModelInstance; } + void SetModelInstance( ModelInstanceHandle_t hInstance) { m_ModelInstance = hInstance; } + bool SnatchModelInstance( C_BaseEntity * pToEntity ); + virtual ClientShadowHandle_t GetShadowHandle() const { return m_ShadowHandle; } + virtual ClientRenderHandle_t& RenderHandle(); + + void CreateModelInstance(); + + // Sets the origin + angles to match the last position received + void MoveToLastReceivedPosition( bool force = false ); + + // Return the IHasAttributes interface for this base entity. Removes the need for: + // dynamic_cast< IHasAttributes * >( pEntity ); + // Which is remarkably slow. + // GetAttribInterface( CBaseEntity *pEntity ) in attribute_manager.h uses + // this function, tests for NULL, and Asserts m_pAttributes == dynamic_cast. + inline IHasAttributes *GetHasAttributesInterfacePtr() const { return m_pAttributes; } + +protected: + // NOTE: m_pAttributes needs to be set in the leaf class constructor. + IHasAttributes *m_pAttributes; + + // Only meant to be called from subclasses + void DestroyModelInstance(); + + // Interpolate entity + static void ProcessTeleportList(); + static void ProcessInterpolatedList(); + static void CheckInterpolatedVarParanoidMeasurement(); + + // overrideable rules if an entity should interpolate + virtual bool ShouldInterpolate(); + + // Call this in OnDataChanged if you don't chain it down! + void MarkMessageReceived(); + + // Gets the last message time + float GetLastMessageTime() const { return m_flLastMessageTime; } + + // For non-players + int PhysicsClipVelocity (const Vector& in, const Vector& normal, Vector& out, float overbounce ); + + // Allow entities to perform client-side fades + virtual unsigned char GetClientSideFade() { return 255; } + +protected: + // Two part guts of Interpolate(). Shared with C_BaseAnimating. + enum + { + INTERPOLATE_STOP=0, + INTERPOLATE_CONTINUE + }; + + // Returns INTERPOLATE_STOP or INTERPOLATE_CONTINUE. + // bNoMoreChanges is set to 1 if you can call RemoveFromInterpolationList on the entity. + int BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int &bNoMoreChanges ); + void BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int nChangeFlags ); + + +public: + // Accessors for above + static int GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime = false ); + static void SetPredictionRandomSeed( const CUserCmd *cmd ); + static C_BasePlayer *GetPredictionPlayer( void ); + static void SetPredictionPlayer( C_BasePlayer *player ); + static void CheckCLInterpChanged(); + + // Collision group accessors + int GetCollisionGroup() const; + void SetCollisionGroup( int collisionGroup ); + void CollisionRulesChanged(); + + static C_BaseEntity *Instance( int iEnt ); + // Doesn't do much, but helps with trace results + static C_BaseEntity *Instance( IClientEntity *ent ); + static C_BaseEntity *Instance( CBaseHandle hEnt ); + // For debugging shared code + static bool IsServer( void ); + static bool IsClient( void ); + static char const *GetDLLType( void ); + static void SetAbsQueriesValid( bool bValid ); + static bool IsAbsQueriesValid( void ); + + // Enable/disable abs recomputations on a stack. + static void PushEnableAbsRecomputations( bool bEnable ); + static void PopEnableAbsRecomputations(); + + // This requires the abs recomputation stack to be empty and just sets the global state. + // It should only be used at the scope of the frame loop. + static void EnableAbsRecomputations( bool bEnable ); + + static bool IsAbsRecomputationsEnabled( void ); + + + // Bloat the culling bbox past the parent ent's bbox in local space if EF_BONEMERGE_FASTCULL is set. + virtual void BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const; + + + // Accessors for color. + const color32 GetRenderColor() const; + void SetRenderColor( byte r, byte g, byte b ); + void SetRenderColor( byte r, byte g, byte b, byte a ); + void SetRenderColorR( byte r ); + void SetRenderColorG( byte g ); + void SetRenderColorB( byte b ); + void SetRenderColorA( byte a ); + + void SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate = false ); + RenderMode_t GetRenderMode() const; + +public: + + // Determine what entity this corresponds to + int index; + + // Render information + unsigned char m_nRenderFX; + unsigned char m_nRenderFXBlend; + + // Entity flags that are only for the client (ENTCLIENTFLAG_ defines). + unsigned short m_EntClientFlags; + + CNetworkColor32( m_clrRender ); + +private: + + // Model for rendering + const model_t *model; + +public: + // Time animation sequence or frame was last changed + float m_flAnimTime; + float m_flOldAnimTime; + + float m_flSimulationTime; + float m_flOldSimulationTime; + + float m_flCreateTime; + + byte m_ubInterpolationFrame; + byte m_ubOldInterpolationFrame; + +private: + // Effects to apply + int m_fEffects; + unsigned char m_nRenderMode; + unsigned char m_nOldRenderMode; + +public: + // Used to store the state we were added to the BSP as, so it can + // reinsert the entity if the state changes. + ClientRenderHandle_t m_hRender; // link into spatial partition + + // Interpolation says don't draw yet + bool m_bReadyToDraw; + + // Should we be interpolating? + static bool IsInterpolationEnabled(); + + // Should we interpolate this tick? (Used to be EF_NOINTERP) + bool IsNoInterpolationFrame(); + + // + int m_nNextThinkTick; + int m_nLastThinkTick; + + // Object model index + short m_nModelIndex; + +#ifdef TF_CLIENT_DLL + int m_nModelIndexOverrides[MAX_VISION_MODES]; +#endif + + char m_takedamage; + char m_lifeState; + + int m_iHealth; + + // was pev->speed + float m_flSpeed; + + // Team Handling + int m_iTeamNum; + +#if !defined( NO_ENTITY_PREDICTION ) + // Certain entities (projectiles) can be created on the client + CPredictableId m_PredictableID; + PredictionContext *m_pPredictionContext; +#endif + + // used so we know when things are no longer touching + int touchStamp; + + // Called after predicted entity has been acknowledged so that no longer needed entity can + // be deleted + // Return true to force deletion right now, regardless of isbeingremoved + virtual bool OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted ); + + bool IsDormantPredictable( void ) const; + bool BecameDormantThisPacket( void ) const; + void SetDormantPredictable( bool dormant ); + + int GetWaterLevel() const; + void SetWaterLevel( int nLevel ); + int GetWaterType() const; + void SetWaterType( int nType ); + + float GetElasticity( void ) const; + + int GetTextureFrameIndex( void ); + void SetTextureFrameIndex( int iIndex ); + + virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const; + virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const; + virtual C_BaseEntity *GetShadowUseOtherEntity( void ) const; + virtual void SetShadowUseOtherEntity( C_BaseEntity *pEntity ); + + CInterpolatedVar< QAngle >& GetRotationInterpolator(); + CInterpolatedVar< Vector >& GetOriginInterpolator(); + virtual bool AddRagdollToFadeQueue( void ) { return true; } + + // Dirty bits + void MarkRenderHandleDirty(); + + // used by SourceTV since move-parents may be missing when child spawns. + void HierarchyUpdateMoveParent(); + + virtual bool IsDeflectable() { return false; } + + bool IsCombatCharacter() { return MyCombatCharacterPointer() == NULL ? false : true; } +protected: + int m_nFXComputeFrame; + + // FIXME: Should I move the functions handling these out of C_ClientEntity + // and into C_BaseEntity? Then we could make these private. + // Client handle + CBaseHandle m_RefEHandle; // Reference ehandle. Used to generate ehandles off this entity. + +private: + // Set by tools if this entity should route "info" to various tools listening to HTOOLENTITIES +#ifndef NO_TOOLFRAMEWORK + bool m_bEnabledInToolView; + bool m_bToolRecording; + HTOOLHANDLE m_ToolHandle; + int m_nLastRecordedFrame; + bool m_bRecordInTools; // should this entity be recorded in the tools (we exclude some things like models for menus) +#endif + +protected: + // pointer to the entity's physics object (vphysics.dll) + IPhysicsObject *m_pPhysicsObject; + +#if !defined( NO_ENTITY_PREDICTION ) + bool m_bPredictionEligible; +#endif + + int m_nSimulationTick; + + // Think contexts + int GetIndexForThinkContext( const char *pszContext ); + CUtlVector< thinkfunc_t > m_aThinkFunctions; + int m_iCurrentThinkContext; + + // Object eye position + Vector m_vecViewOffset; + +#if defined(SIXENSE) + Vector m_vecEyeOffset; + QAngle m_EyeAngleOffset; +#endif + // Allow studio models to tell us what their m_nBody value is + virtual int GetStudioBody( void ) { return 0; } + +public: + // This can be used to setup the entity as a client-only entity. It gets an entity handle, + // a render handle, and is put into the spatial partition. + bool InitializeAsClientEntityByIndex( int iIndex, RenderGroup_t renderGroup ); + + void TrackAngRotation( bool bTrack ); + +private: + friend void OnRenderStart(); + + // Figure out the smoothly interpolated origin for all server entities. Happens right before + // letting all entities simulate. + static void InterpolateServerEntities(); + + // Check which entities want to be drawn and add them to the leaf system. + static void AddVisibleEntities(); + + // For entities marked for recording, post bone messages to IToolSystems + static void ToolRecordEntities(); + + // Computes the base velocity + void UpdateBaseVelocity( void ); + + // Physics-related private methods + void PhysicsPusher( void ); + void PhysicsNone( void ); + void PhysicsNoclip( void ); + void PhysicsParent( void ); + void PhysicsStepRunTimestep( float timestep ); + void PhysicsToss( void ); + void PhysicsCustom( void ); + + // Simulation in local space of rigid children + void PhysicsRigidChild( void ); + + // Computes absolute position based on hierarchy + void CalcAbsolutePosition( ); + void CalcAbsoluteVelocity(); + + // Computes new angles based on the angular velocity + void SimulateAngles( float flFrameTime ); + + // Implement this if you use MOVETYPE_CUSTOM + virtual void PerformCustomPhysics( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity ); + + // methods related to decal adding + void AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); + void AddColoredStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal ); + void AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter, int decalIndex, bool doTrace, trace_t& tr ); + + void ComputePackedOffsets( void ); + int ComputePackedSize_R( datamap_t *map ); + int GetIntermediateDataSize( void ); + + void UnlinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild ); + void LinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild ); + void HierarchySetParent( C_BaseEntity *pNewParent ); + void UnlinkFromHierarchy(); + + // Computes the water level + type + void UpdateWaterState(); + + // Checks a sweep without actually performing the move + void PhysicsCheckSweep( const Vector& vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace ); + + // FIXME: REMOVE!!! + void MoveToAimEnt( ); + + // Sets/Gets the next think based on context index + void SetNextThink( int nContextIndex, float thinkTime ); + void SetLastThink( int nContextIndex, float thinkTime ); + float GetNextThink( int nContextIndex ) const; + int GetNextThinkTick( int nContextIndex ) const; + + // Object velocity + Vector m_vecVelocity; + CInterpolatedVar< Vector > m_iv_vecVelocity; + + Vector m_vecAbsVelocity; + + // was pev->avelocity + QAngle m_vecAngVelocity; + +// QAngle m_vecAbsAngVelocity; + +#if !defined( NO_ENTITY_PREDICTION ) + // It's still in the list for "fixup purposes" and simulation, but don't try to render it any more... + bool m_bDormantPredictable; + + // So we can clean it up + int m_nIncomingPacketEntityBecameDormant; +#endif + + // The spawn time of the entity + float m_flSpawnTime; + + // Timestamp of message arrival + float m_flLastMessageTime; + + // Base velocity + Vector m_vecBaseVelocity; + + // Gravity multiplier + float m_flGravity; + + // Model instance data.. + ModelInstanceHandle_t m_ModelInstance; + + // Shadow data + ClientShadowHandle_t m_ShadowHandle; + + // A random value used by material proxies for each model instance. + float m_flProxyRandomValue; + + ClientThinkHandle_t m_hThink; + + int m_iEFlags; // entity flags EFL_* + + // Object movetype + unsigned char m_MoveType; + unsigned char m_MoveCollide; + unsigned char m_iParentAttachment; // 0 if we're relative to the parent's absorigin and absangles. + unsigned char m_iOldParentAttachment; + + unsigned char m_nWaterLevel; + unsigned char m_nWaterType; + // For client/server entities, true if the entity goes outside the PVS. + // Unused for client only entities. + bool m_bDormant; + // Prediction system + bool m_bPredictable; + + + // Hierarchy + CHandle m_pMoveParent; + CHandle m_pMoveChild; + CHandle m_pMovePeer; + CHandle m_pMovePrevPeer; + + // The moveparent received from networking data + CHandle m_hNetworkMoveParent; + CHandle m_hOldMoveParent; + + string_t m_ModelName; + + CNetworkVarEmbedded( CCollisionProperty, m_Collision ); + CNetworkVarEmbedded( CParticleProperty, m_Particles ); + + // Physics state + float m_flElasticity; + + float m_flShadowCastDistance; + EHANDLE m_ShadowDirUseOtherEntity; + + EHANDLE m_hGroundEntity; + float m_flGroundChangeTime; + + + // Friction. + float m_flFriction; + + Vector m_vecAbsOrigin; + + // Object orientation + QAngle m_angAbsRotation; + + Vector m_vecOldOrigin; + QAngle m_vecOldAngRotation; + + Vector m_vecOrigin; + CInterpolatedVar< Vector > m_iv_vecOrigin; + QAngle m_angRotation; + CInterpolatedVar< QAngle > m_iv_angRotation; + + // Specifies the entity-to-world transform + matrix3x4_t m_rgflCoordinateFrame; + + // Last values to come over the wire. Used for interpolation. + Vector m_vecNetworkOrigin; + QAngle m_angNetworkAngles; + + // Behavior flags + int m_fFlags; + + // used to cull collision tests + int m_CollisionGroup; + +#if !defined( NO_ENTITY_PREDICTION ) + // For storing prediction results and pristine network state + byte *m_pIntermediateData[ MULTIPLAYER_BACKUP ]; + byte *m_pOriginalData; + int m_nIntermediateDataCount; + + bool m_bIsPlayerSimulated; +#endif + + CNetworkVar( bool, m_bSimulatedEveryTick ); + CNetworkVar( bool, m_bAnimatedEveryTick ); + CNetworkVar( bool, m_bAlternateSorting ); + + //Adrian + unsigned char m_iTextureFrameIndex; + + // Bbox visualization + unsigned char m_fBBoxVisFlags; + + // The list that holds OnDataChanged events uses this to make sure we don't get multiple + // OnDataChanged calls in the same frame if the client receives multiple packets. + int m_DataChangeEventRef; + +#if !defined( NO_ENTITY_PREDICTION ) + // Player who is driving my simulation + CHandle< CBasePlayer > m_hPlayerSimulationOwner; +#endif + + // The owner! + EHANDLE m_hOwnerEntity; + EHANDLE m_hEffectEntity; + + // This is a random seed used by the networking code to allow client - side prediction code + // randon number generators to spit out the same random numbers on both sides for a particular + // usercmd input. + static int m_nPredictionRandomSeed; + static C_BasePlayer *m_pPredictionPlayer; + static bool s_bAbsQueriesValid; + static bool s_bAbsRecomputationEnabled; + + static bool s_bInterpolate; + + int m_fDataObjectTypes; + + AimEntsListHandle_t m_AimEntsListHandle; + int m_nCreationTick; + + +public: + float m_fRenderingClipPlane[4]; //world space clip plane when drawing + bool m_bEnableRenderingClipPlane; //true to use the custom clip plane when drawing + virtual float * GetRenderClipPlane( void ); // Rendering clip plane, should be 4 floats, return value of NULL indicates a disabled render clip plane + +protected: + + void AddToInterpolationList(); + void RemoveFromInterpolationList(); + unsigned short m_InterpolationListEntry; // Entry into g_InterpolationList (or g_InterpolationList.InvalidIndex if not in the list). + + void AddToTeleportList(); + void RemoveFromTeleportList(); + unsigned short m_TeleportListEntry; + + CThreadFastMutex m_CalcAbsolutePositionMutex; + CThreadFastMutex m_CalcAbsoluteVelocityMutex; + +#ifdef TF_CLIENT_DLL + // TF prevents drawing of any entity attached to players that aren't items in the inventory of the player. + // This is to prevent servers creating fake cosmetic items and attaching them to players. +public: + virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry ); + bool EntityDeemedInvalid( void ) { return (m_bValidatedOwner && m_bDeemedInvalid); } +protected: + bool m_bValidatedOwner; + bool m_bDeemedInvalid; + bool m_bWasDeemedInvalid; + RenderMode_t m_PreviousRenderMode; + color32 m_PreviousRenderColor; +#endif + +public: + virtual void OnOwnerChanged(); + virtual void *VPhysicsGetElement( int ); + virtual bool IsARagdoll(); + virtual void SetMaterialOverride( const char * ); + virtual void SetMaterialOverridePointer( IMaterial * ); + virtual IMaterial *GetMaterialOverridePointer(); + virtual const char *GetMaterialOverride(); + virtual void StartMaterialOverride(); + virtual void EndMaterialOverride(); + virtual double GetCreationTime(); + virtual bool IsPredicted() const; + virtual bool IsWeapon() const; + virtual bool IsVehicle() const; + virtual bool IsJeep() const; + virtual bool UsesLua(); + virtual int GetLuaEntityType(); + virtual void PushEntity(); + virtual void Push_This_Entity(); + virtual void SetEntity( const char *, C_BaseEntity * ); + virtual int GetParentPhysicsNum(); + virtual void SetParentPhysicsNum( int ); + virtual void StartMotionController(); + virtual void StopMotionController(); + virtual void AttachObjectToMotionController( IPhysicsObject * ); + virtual void DetachObjectFromMotionController( IPhysicsObject * ); + virtual void GetCustomisedRenderBounds( Vector &, Vector & ); + virtual void SetCustomisedRenderBounds( Vector *, Vector * ); + virtual const char *GetLuaScriptName(); + virtual void SpawnedViaLua(); + virtual void OverridePosition(); + virtual void InitializeScriptedEntity( const char * ); + virtual void ClearLuaData(); + virtual ILuaObject *GetLuaTable(); + virtual void *GetLuaEntity(); + virtual void SetLuaTable( ILuaObject * ); + virtual void Lua_OnEntityInitialized(); + virtual bool HasLuaTable(); + virtual void LuaEntityInitialized(); + virtual void ForcePhysicsDropObject(); + virtual void StartDriving( C_BasePlayer * ); + virtual void FinishDriving( C_BasePlayer * ); + virtual bool GMod_ShouldRenderEntity(); + virtual void OnClientsideLuaRestored(); + virtual void *Lua_GetLuaClass(); + virtual void VPhysicsCollision( int, gamevcollisionevent_t * ); +}; + +EXTERN_RECV_TABLE(DT_BaseEntity); + +inline bool FClassnameIs( C_BaseEntity *pEntity, const char *szClassname ) +{ + Assert( pEntity ); + if ( pEntity == NULL ) + return false; + + return !strcmp( pEntity->GetClassname(), szClassname ) ? true : false; +} + +#define SetThink( a ) ThinkSet( static_cast (a), 0, NULL ) +#define SetContextThink( a, b, context ) ThinkSet( static_cast (a), (b), context ) + +#ifdef _DEBUG +#define SetTouch( a ) TouchSet( static_cast (a), #a ) + +#else +#define SetTouch( a ) m_pfnTouch = static_cast (a) + +#endif + + +//----------------------------------------------------------------------------- +// An inline version the game code can use +//----------------------------------------------------------------------------- +inline CCollisionProperty *C_BaseEntity::CollisionProp() +{ + return &m_Collision; +} + +inline const CCollisionProperty *C_BaseEntity::CollisionProp() const +{ + return &m_Collision; +} + +//----------------------------------------------------------------------------- +// An inline version the game code can use +//----------------------------------------------------------------------------- +inline CParticleProperty *C_BaseEntity::ParticleProp() +{ + return &m_Particles; +} + +inline const CParticleProperty *C_BaseEntity::ParticleProp() const +{ + return &m_Particles; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns whether this entity was created on the client. +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::IsServerEntity( void ) +{ + return index != -1; +} + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline matrix3x4_t &C_BaseEntity::EntityToWorldTransform() +{ + Assert( s_bAbsQueriesValid ); + CalcAbsolutePosition(); + return m_rgflCoordinateFrame; +} + +inline const matrix3x4_t &C_BaseEntity::EntityToWorldTransform() const +{ + Assert( s_bAbsQueriesValid ); + const_cast(this)->CalcAbsolutePosition(); + return m_rgflCoordinateFrame; +} + +inline const Vector& C_BaseEntity::GetNetworkOrigin() const +{ + return m_vecNetworkOrigin; +} + +inline const QAngle& C_BaseEntity::GetNetworkAngles() const +{ + return m_angNetworkAngles; +} + +inline const model_t *C_BaseEntity::GetModel( void ) const +{ + return model; +} + +inline int C_BaseEntity::GetModelIndex( void ) const +{ + return m_nModelIndex; +} + +//----------------------------------------------------------------------------- +// Some helper methods that transform a point from entity space to world space + back +//----------------------------------------------------------------------------- +inline void C_BaseEntity::EntityToWorldSpace( const Vector &in, Vector *pOut ) const +{ + if ( GetAbsAngles() == vec3_angle ) + { + VectorAdd( in, GetAbsOrigin(), *pOut ); + } + else + { + VectorTransform( in, EntityToWorldTransform(), *pOut ); + } +} + +inline void C_BaseEntity::WorldToEntitySpace( const Vector &in, Vector *pOut ) const +{ + if ( GetAbsAngles() == vec3_angle ) + { + VectorSubtract( in, GetAbsOrigin(), *pOut ); + } + else + { + VectorITransform( in, EntityToWorldTransform(), *pOut ); + } +} + +inline const Vector &C_BaseEntity::GetAbsVelocity( ) const +{ + Assert( s_bAbsQueriesValid ); + const_cast(this)->CalcAbsoluteVelocity(); + return m_vecAbsVelocity; +} + +inline C_BaseEntity *C_BaseEntity::Instance( IClientEntity *ent ) +{ + return ent ? ent->GetBaseEntity() : NULL; +} + +// For debugging shared code +inline bool C_BaseEntity::IsServer( void ) +{ + return false; +} + +inline bool C_BaseEntity::IsClient( void ) +{ + return true; +} + +inline const char *C_BaseEntity::GetDLLType( void ) +{ + return "client"; +} + + +//----------------------------------------------------------------------------- +// Methods relating to solid type + flags +//----------------------------------------------------------------------------- +inline void C_BaseEntity::SetSolidFlags( int nFlags ) +{ + CollisionProp()->SetSolidFlags( nFlags ); +} + +inline bool C_BaseEntity::IsSolidFlagSet( int flagMask ) const +{ + return CollisionProp()->IsSolidFlagSet( flagMask ); +} + +inline int C_BaseEntity::GetSolidFlags( void ) const +{ + return CollisionProp()->GetSolidFlags( ); +} + +inline void C_BaseEntity::AddSolidFlags( int nFlags ) +{ + CollisionProp()->AddSolidFlags( nFlags ); +} + +inline void C_BaseEntity::RemoveSolidFlags( int nFlags ) +{ + CollisionProp()->RemoveSolidFlags( nFlags ); +} + +inline bool C_BaseEntity::IsSolid() const +{ + return CollisionProp()->IsSolid( ); +} + +inline void C_BaseEntity::SetSolid( SolidType_t val ) +{ + CollisionProp()->SetSolid( val ); +} + +inline SolidType_t C_BaseEntity::GetSolid( ) const +{ + return CollisionProp()->GetSolid( ); +} + +inline void C_BaseEntity::SetCollisionBounds( const Vector& mins, const Vector &maxs ) +{ + CollisionProp()->SetCollisionBounds( mins, maxs ); +} + + +//----------------------------------------------------------------------------- +// Methods relating to bounds +//----------------------------------------------------------------------------- +inline const Vector& C_BaseEntity::WorldAlignMins( ) const +{ + Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); + Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); + return CollisionProp()->OBBMins(); +} + +inline const Vector& C_BaseEntity::WorldAlignMaxs( ) const +{ + Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); + Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); + return CollisionProp()->OBBMaxs(); +} + +inline const Vector& C_BaseEntity::WorldAlignSize( ) const +{ + Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); + Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); + return CollisionProp()->OBBSize(); +} + +inline float CBaseEntity::BoundingRadius() const +{ + return CollisionProp()->BoundingRadius(); +} + +inline bool CBaseEntity::IsPointSized() const +{ + return CollisionProp()->BoundingRadius() == 0.0f; +} + + +//----------------------------------------------------------------------------- +// Methods relating to traversing hierarchy +//----------------------------------------------------------------------------- +inline C_BaseEntity *C_BaseEntity::GetMoveParent( void ) const +{ + return m_pMoveParent; +} + +inline C_BaseEntity *C_BaseEntity::FirstMoveChild( void ) const +{ + return m_pMoveChild; +} + +inline C_BaseEntity *C_BaseEntity::NextMovePeer( void ) const +{ + return m_pMovePeer; +} + +//----------------------------------------------------------------------------- +// Velocity +//----------------------------------------------------------------------------- +inline const Vector& C_BaseEntity::GetLocalVelocity() const +{ + return m_vecVelocity; +} + +inline const QAngle& C_BaseEntity::GetLocalAngularVelocity( ) const +{ + return m_vecAngVelocity; +} + +inline const Vector& C_BaseEntity::GetBaseVelocity() const +{ + return m_vecBaseVelocity; +} + +inline void C_BaseEntity::SetBaseVelocity( const Vector& v ) +{ + m_vecBaseVelocity = v; +} + +inline void C_BaseEntity::SetFriction( float flFriction ) +{ + m_flFriction = flFriction; +} + +inline void C_BaseEntity::SetGravity( float flGravity ) +{ + m_flGravity = flGravity; +} + +inline float C_BaseEntity::GetGravity( void ) const +{ + return m_flGravity; +} + +inline int C_BaseEntity::GetWaterLevel() const +{ + return m_nWaterLevel; +} + +inline void C_BaseEntity::SetWaterLevel( int nLevel ) +{ + m_nWaterLevel = nLevel; +} + +inline float C_BaseEntity::GetElasticity( void ) const +{ + return m_flElasticity; +} + +inline const color32 CBaseEntity::GetRenderColor() const +{ + return m_clrRender.Get(); +} + +inline void C_BaseEntity::SetRenderColor( byte r, byte g, byte b ) +{ + color32 clr = { r, g, b, m_clrRender->a }; + m_clrRender = clr; +} + +inline void C_BaseEntity::SetRenderColor( byte r, byte g, byte b, byte a ) +{ + color32 clr = { r, g, b, a }; + m_clrRender = clr; +} + +inline void C_BaseEntity::SetRenderColorR( byte r ) +{ + SetRenderColor( r, GetRenderColor().g, GetRenderColor().b ); +} + +inline void C_BaseEntity::SetRenderColorG( byte g ) +{ + SetRenderColor( GetRenderColor().r, g, GetRenderColor().b ); +} + +inline void C_BaseEntity::SetRenderColorB( byte b ) +{ + SetRenderColor( GetRenderColor().r, GetRenderColor().g, b ); +} + +inline void C_BaseEntity::SetRenderColorA( byte a ) +{ + SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, a ); +} + +inline RenderMode_t CBaseEntity::GetRenderMode() const +{ + return (RenderMode_t)m_nRenderMode; +} + +//----------------------------------------------------------------------------- +// checks to see if the entity is marked for deletion +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::IsMarkedForDeletion( void ) +{ + return (m_iEFlags & EFL_KILLME); +} + +inline void C_BaseEntity::AddEFlags( int nEFlagMask ) +{ + m_iEFlags |= nEFlagMask; +} + +inline void C_BaseEntity::RemoveEFlags( int nEFlagMask ) +{ + m_iEFlags &= ~nEFlagMask; +} + +inline bool CBaseEntity::IsEFlagSet( int nEFlagMask ) const +{ + return (m_iEFlags & nEFlagMask) != 0; +} + +inline unsigned char CBaseEntity::GetParentAttachment() const +{ + return m_iParentAttachment; +} + +inline ClientRenderHandle_t CBaseEntity::GetRenderHandle() const +{ + return m_hRender; +} + +inline ClientRenderHandle_t& CBaseEntity::RenderHandle() +{ + return m_hRender; +} + +#ifdef SIXENSE + +inline const Vector& CBaseEntity::GetEyeOffset() const +{ + return m_vecEyeOffset; +} + +inline void CBaseEntity::SetEyeOffset( const Vector& v ) +{ + m_vecEyeOffset = v; +} + +inline const QAngle & CBaseEntity::GetEyeAngleOffset() const +{ + return m_EyeAngleOffset; +} + +inline void CBaseEntity::SetEyeAngleOffset( const QAngle & qa ) +{ + m_EyeAngleOffset = qa; +} + +#endif + +//----------------------------------------------------------------------------- +// Methods to cast away const +//----------------------------------------------------------------------------- +inline Vector C_BaseEntity::EyePosition( void ) const +{ + return const_cast(this)->EyePosition(); +} + +inline const QAngle &C_BaseEntity::EyeAngles( void ) const // Direction of eyes in world space +{ + return const_cast(this)->EyeAngles(); +} + +inline const QAngle &C_BaseEntity::LocalEyeAngles( void ) const // Direction of eyes +{ + return const_cast(this)->LocalEyeAngles(); +} + +inline Vector C_BaseEntity::EarPosition( void ) const // position of ears +{ + return const_cast(this)->EarPosition(); +} + +inline VarMapping_t* C_BaseEntity::GetVarMapping() +{ + return &m_VarMap; +} + +//----------------------------------------------------------------------------- +// Should we be interpolating? +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::IsInterpolationEnabled() +{ + return s_bInterpolate; +} + +//----------------------------------------------------------------------------- +// Should we be interpolating during this frame? (was EF_NOINTERP) +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::IsNoInterpolationFrame() +{ + return m_ubOldInterpolationFrame != m_ubInterpolationFrame; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : handle - +// Output : inline void +//----------------------------------------------------------------------------- +inline void C_BaseEntity::SetToolHandle( HTOOLHANDLE handle ) +{ +#ifndef NO_TOOLFRAMEWORK + m_ToolHandle = handle; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +// Output : inline HTOOLHANDLE +//----------------------------------------------------------------------------- +inline HTOOLHANDLE C_BaseEntity::GetToolHandle() const +{ +#ifndef NO_TOOLFRAMEWORK + return m_ToolHandle; +#else + return (HTOOLHANDLE)0; +#endif +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::IsEnabledInToolView() const +{ +#ifndef NO_TOOLFRAMEWORK + return m_bEnabledInToolView; +#else + return false; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +// Output : inline bool +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::ShouldRecordInTools() const +{ +#ifndef NO_TOOLFRAMEWORK + return m_bRecordInTools; +#else + return true; +#endif +} + +C_BaseEntity *CreateEntityByName( const char *className ); + +#endif // C_BASEENTITY_H diff --git a/game/client/c_baseflex.h b/game/client/c_baseflex.h new file mode 100644 index 0000000..71cee3d --- /dev/null +++ b/game/client/c_baseflex.h @@ -0,0 +1,341 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +// Client-side CBasePlayer + +#ifndef C_STUDIOFLEX_H +#define C_STUDIOFLEX_H +#pragma once + + +#include "c_baseanimating.h" +#include "c_baseanimatingoverlay.h" +#include "sceneentity_shared.h" + +#include "utlvector.h" + +//----------------------------------------------------------------------------- +// Purpose: Item in list of loaded scene files +//----------------------------------------------------------------------------- +class CFlexSceneFile +{ +public: + enum + { + MAX_FLEX_FILENAME = 128, + }; + + char filename[ MAX_FLEX_FILENAME ]; + void *buffer; +}; + +// For phoneme emphasis track +struct Emphasized_Phoneme; +class CSentence; + +enum +{ + PHONEME_CLASS_WEAK = 0, + PHONEME_CLASS_NORMAL, + PHONEME_CLASS_STRONG, + + NUM_PHONEME_CLASSES +}; + +// Mapping for each loaded scene file used by this actor +struct FS_LocalToGlobal_t +{ + explicit FS_LocalToGlobal_t() : + m_Key( 0 ), + m_nCount( 0 ), + m_Mapping( 0 ) + { + } + + explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) : + m_Key( key ), + m_nCount( 0 ), + m_Mapping( 0 ) + { + } + + void SetCount( int count ) + { + Assert( !m_Mapping ); + Assert( count > 0 ); + m_nCount = count; + m_Mapping = new int[ m_nCount ]; + Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) ); + } + + FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src ) + { + m_Key = src.m_Key; + delete m_Mapping; + m_Mapping = new int[ src.m_nCount ]; + Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) ); + + m_nCount = src.m_nCount; + } + + ~FS_LocalToGlobal_t() + { + delete m_Mapping; + m_nCount = 0; + m_Mapping = 0; + } + + const flexsettinghdr_t *m_Key; + int m_nCount; + int *m_Mapping; +}; + +bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ); + +class IHasLocalToGlobalFlexSettings +{ +public: + virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct Emphasized_Phoneme +{ + // Global fields, setup at start + char classname[ 64 ]; + bool required; + // Global fields setup first time tracks played + bool basechecked; + const flexsettinghdr_t *base; + const flexsetting_t *exp; + + // Local fields, processed for each sentence + bool valid; + float amount; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings +{ + DECLARE_CLASS( C_BaseFlex, C_BaseAnimatingOverlay ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + C_BaseFlex(); + virtual ~C_BaseFlex(); + + virtual void Spawn(); + + virtual void InitPhonemeMappings(); + + void SetupMappings( char const *pchFileRoot ); + + virtual CStudioHdr *OnNewModel( void ); + + virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + virtual void OnThreadedDrawSetup(); + + // model specific + virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); + static void LinkToGlobalFlexControllers( CStudioHdr *hdr ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual bool SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + static void RunFlexDelay( int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights, float &flFlexDelayTime ); + virtual void SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual bool UsesFlexDelayedWeights(); + + static void RunFlexRules( CStudioHdr *pStudioHdr, float *dest ); + + virtual Vector SetViewTarget( CStudioHdr *pStudioHdr ); + + virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); + + virtual void GetToolRecordingState( KeyValues *msg ); + + // Called at the lowest level to actually apply a flex animation + void AddFlexAnimation( CSceneEventInfo *info ); + + void SetFlexWeight( LocalFlexController_t index, float value ); + float GetFlexWeight( LocalFlexController_t index ); + + // Look up flex controller index by global name + LocalFlexController_t FindFlexController( const char *szName ); + +public: + Vector m_viewtarget; + CInterpolatedVar< Vector > m_iv_viewtarget; + // indexed by model local flexcontroller + float m_flexWeight[MAXSTUDIOFLEXCTRL]; + CInterpolatedVarArray< float, MAXSTUDIOFLEXCTRL > m_iv_flexWeight; + + int m_blinktoggle; + + static int AddGlobalFlexController( const char *szName ); + static char const *GetGlobalFlexControllerName( int idx ); + + // bah, this should be unified with all prev/current stuff. + +public: + + // Keep track of what scenes are being played + void StartChoreoScene( CChoreoScene *scene ); + void RemoveChoreoScene( CChoreoScene *scene ); + + // Start the specifics of an scene event + virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, C_BaseEntity *pTarget ); + + // Manipulation of events for the object + // Should be called by think function to process all scene events + // The default implementation resets m_flexWeight array and calls + // AddSceneEvents + virtual void ProcessSceneEvents( bool bFlexEvents ); + + // Assumes m_flexWeight array has been set up, this adds the actual currently playing + // expressions to the flex weights and adds other scene events as needed + virtual bool ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + + virtual bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + + // Remove all playing events + void ClearSceneEvents( CChoreoScene *scene, bool canceled ); + + // Stop specifics of event + virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled ); + + // Add the event to the queue for this actor + void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false ); + + // Remove the event from the queue for this actor + void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill ); + + // Checks to see if the event should be considered "completed" + bool CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + // Checks to see if a event should be considered "completed" + virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + int FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key ); + + // IHasLocalToGlobalFlexSettings + virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ); + + // For handling scene files + void *FindSceneFile( const char *filename ); + +private: + + bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + + bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + void AddFlexSetting( const char *expr, float scale, + const flexsettinghdr_t *pSettinghdr, bool newexpression ); + + // Array of active SceneEvents, in order oldest to newest + CUtlVector < CSceneEventInfo > m_SceneEvents; + CUtlVector < CChoreoScene * > m_ActiveChoreoScenes; + + bool HasSceneEvents() const; + +private: + CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal; + + float m_blinktime; + int m_prevblinktoggle; + + int m_iBlink; + LocalFlexController_t m_iEyeUpdown; + LocalFlexController_t m_iEyeRightleft; + bool m_bSearchedForEyeFlexes; + int m_iMouthAttachment; + + float m_flFlexDelayTime; + float *m_flFlexDelayedWeight; + int m_cFlexDelayedWeight; + + // shared flex controllers + static int g_numflexcontrollers; + static char *g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; // room for global set of flexcontrollers + static float g_flexweight[MAXSTUDIOFLEXDESC]; + +protected: + + Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ]; + +private: + + C_BaseFlex( const C_BaseFlex & ); // not defined, not accessible + + const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr ); + + void ProcessVisemes( Emphasized_Phoneme *classes ); + void AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ); + void AddViseme( Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression ); + bool SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ); + void ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity ); + +#ifdef HL2_CLIENT_DLL +public: + + Vector m_vecLean; + CInterpolatedVar< Vector > m_iv_vecLean; + Vector m_vecShift; + CInterpolatedVar< Vector > m_iv_vecShift; +#endif +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CFlexSceneFileManager : CAutoGameSystem +{ +public: + + CFlexSceneFileManager() : CAutoGameSystem( "CFlexSceneFileManager" ) + { + } + + virtual bool Init(); + virtual void Shutdown(); + + void EnsureTranslations( IHasLocalToGlobalFlexSettings *instance, const flexsettinghdr_t *pSettinghdr ); + void *FindSceneFile( IHasLocalToGlobalFlexSettings *instance, const char *filename, bool allowBlockingIO ); + +private: + void DeleteSceneFiles(); + + CUtlVector< CFlexSceneFile * > m_FileList; +}; + + +//----------------------------------------------------------------------------- +// Do we have active expressions? +//----------------------------------------------------------------------------- +inline bool C_BaseFlex::HasSceneEvents() const +{ + return m_SceneEvents.Count() != 0; +} + + +EXTERN_RECV_TABLE(DT_BaseFlex); + +float *GetVisemeWeights( int phoneme ); + + +#endif // C_STUDIOFLEX_H + + + + diff --git a/game/client/c_baseplayer.h b/game/client/c_baseplayer.h new file mode 100644 index 0000000..5e4372b --- /dev/null +++ b/game/client/c_baseplayer.h @@ -0,0 +1,699 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client-side CBasePlayer. +// +// - Manages the player's flashlight effect. +// +//=============================================================================// + +#ifndef C_BASEPLAYER_H +#define C_BASEPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_playerlocaldata.h" +#include "c_basecombatcharacter.h" +#include "PlayerState.h" +#include "usercmd.h" +#include "shareddefs.h" +#include "timedevent.h" +#include "smartptr.h" +#include "fx_water.h" +#include "hintsystem.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "c_env_fog_controller.h" +#include "igameevents.h" +#include "GameEventListener.h" + +#if defined USES_ECON_ITEMS +#include "econ_item.h" +#include "game_item_schema.h" +#include "econ_item_view.h" +#endif + +class C_BaseCombatWeapon; +class C_BaseViewModel; +class C_FuncLadder; +class CFlashlightEffect; +class C_EconWearable; + +extern int g_nKillCamMode; +extern int g_nKillCamTarget1; +extern int g_nKillCamTarget2; + +class C_CommandContext +{ +public: + bool needsprocessing; + + CUserCmd cmd; + int command_number; +}; + +class C_PredictionError +{ +public: + float time; + Vector error; +}; + +#define CHASE_CAM_DISTANCE_MIN 16.0f +#define CHASE_CAM_DISTANCE_MAX 96.0f +#define WALL_OFFSET 6.0f + + +bool IsInFreezeCam( void ); + +//----------------------------------------------------------------------------- +// Purpose: Base Player class +//----------------------------------------------------------------------------- +class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener +{ +public: + DECLARE_CLASS( C_BasePlayer, C_BaseCombatCharacter ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + C_BasePlayer(); + virtual ~C_BasePlayer(); + + virtual void Spawn( void ); + virtual void SharedSpawn(); // Shared between client and server. + virtual bool GetSteamID( CSteamID *pID ); + + // IClientEntity overrides. + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + virtual void ReceiveMessage( int classID, bf_read &msg ); + + virtual void OnRestore(); + + virtual void AddEntity( void ); + + virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + + virtual void GetToolRecordingState( KeyValues *msg ); + + virtual float GetPlayerMaxSpeed(); + + void SetAnimationExtension( const char *pExtension ); + + C_BaseViewModel *GetViewModel( int viewmodelindex = 0, bool bObserverOK=true ); + C_BaseCombatWeapon *GetActiveWeapon( void ) const; + const char *GetTracerType( void ); + + // View model prediction setup + virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov ); + virtual void CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles); + + + // Handle view smoothing when going up stairs + void SmoothViewOnStairs( Vector& eyeOrigin ); + virtual float CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed); + void CalcViewRoll( QAngle& eyeAngles ); + void CreateWaterEffects( void ); + + virtual void SetPlayerUnderwater( bool state ); + void UpdateUnderwaterState( void ); + bool IsPlayerUnderwater( void ) { return m_bPlayerUnderwater; } + + virtual Vector Weapon_ShootPosition(); + virtual void Weapon_DropPrimary( void ) {} + + virtual Vector GetAutoaimVector( float flScale ); + void SetSuitUpdate(const char *name, int fgroup, int iNoRepeat); + + // Input handling + virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + virtual void AvoidPhysicsProps( CUserCmd *pCmd ); + + virtual void PlayerUse( void ); + CBaseEntity *FindUseEntity( void ); + virtual bool IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps ); + + // Data handlers + virtual bool IsPlayer( void ) const { return true; } + virtual int GetHealth() const { return m_iHealth; } + + int GetBonusProgress() const { return m_iBonusProgress; } + int GetBonusChallenge() const { return m_iBonusChallenge; } + + // observer mode + virtual int GetObserverMode() const; + void SetObserverMode ( int iNewMode ); + virtual CBaseEntity *GetObserverTarget() const; + void SetObserverTarget( EHANDLE hObserverTarget ); + + bool AudioStateIsUnderwater( Vector vecMainViewOrigin ); + + bool IsObserver() const; + bool IsHLTV() const; + bool IsReplay() const; + void ResetObserverMode(); + bool IsBot( void ) const { return false; } + + // Eye position.. + virtual Vector EyePosition(); + virtual const QAngle &EyeAngles(); // Direction of eyes + void EyePositionAndVectors( Vector *pPosition, Vector *pForward, Vector *pRight, Vector *pUp ); + virtual const QAngle &LocalEyeAngles(); // Direction of eyes + + // This can be overridden to return something other than m_pRagdoll if the mod uses separate + // entities for ragdolls. + virtual IRagdoll* GetRepresentativeRagdoll() const; + + // override the initial bone position for ragdolls + virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) OVERRIDE; + + // Returns eye vectors + void EyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL ); + void CacheVehicleView( void ); // Calculate and cache the position of the player in the vehicle + + + bool IsSuitEquipped( void ) { return m_Local.m_bWearingSuit; }; + + // Team handlers + virtual void TeamChange( int iNewTeam ); + + // Flashlight + void Flashlight( void ); + void UpdateFlashlight( void ); + + // Weapon selection code + virtual bool IsAllowedToSwitchWeapons( void ) { return !IsObserver(); } + virtual C_BaseCombatWeapon *GetActiveWeaponForSelection( void ); + + // Returns the view model if this is the local player. If you're in third person or + // this is a remote player, it returns the active weapon + // (and its appropriate left/right weapon if this is TF2). + virtual C_BaseAnimating* GetRenderedWeaponModel(); + + virtual bool IsOverridingViewmodel( void ) { return false; }; + virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ) { return 0; }; + + virtual float GetDefaultAnimSpeed( void ) { return 1.0; } + + void SetMaxSpeed( float flMaxSpeed ) { m_flMaxspeed = flMaxSpeed; } + float MaxSpeed() const { return m_flMaxspeed; } + + // Should this object cast shadows? + virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } + + virtual bool ShouldReceiveProjectedTextures( int flags ) + { + return false; + } + + + bool IsLocalPlayer( void ) const; + + // Global/static methods + virtual void ThirdPersonSwitch( bool bThirdperson ); + static bool LocalPlayerInFirstPersonView(); + static bool ShouldDrawLocalPlayer(); + static C_BasePlayer *GetLocalPlayer( void ); + int GetUserID( void ); + virtual bool CanSetSoundMixer( void ); + virtual int GetVisionFilterFlags( bool bWeaponsCheck = false ) { return 0x00; } + bool HasVisionFilterFlags( int nFlags, bool bWeaponsCheck = false ) { return ( GetVisionFilterFlags( bWeaponsCheck ) & nFlags ) == nFlags; } + virtual void CalculateVisionUsingCurrentFlags( void ) {} + void BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, const char *pchHeadBoneName ); + + // Specific queries about this player. + bool InFirstPersonView(); + bool ShouldDrawThisPlayer(); + + // Called by the view model if its rendering is being overridden. + virtual bool ViewModel_IsTransparent( void ); + virtual bool ViewModel_IsUsingFBTexture( void ); + +#if !defined( NO_ENTITY_PREDICTION ) + void AddToPlayerSimulationList( C_BaseEntity *other ); + void SimulatePlayerSimulatedEntities( void ); + void RemoveFromPlayerSimulationList( C_BaseEntity *ent ); + void ClearPlayerSimulationList( void ); +#endif + + virtual void PhysicsSimulate( void ); + virtual unsigned int PhysicsSolidMaskForEntity( void ) const { return MASK_PLAYERSOLID; } + + // Prediction stuff + virtual bool ShouldPredict( void ); + + virtual void PreThink( void ); + virtual void PostThink( void ); + + virtual void ItemPreFrame( void ); + virtual void ItemPostFrame( void ); + virtual void AbortReload( void ); + + virtual void SelectLastItem(void); + virtual void Weapon_SetLast( C_BaseCombatWeapon *pWeapon ); + virtual bool Weapon_ShouldSetLast( C_BaseCombatWeapon *pOldWeapon, C_BaseCombatWeapon *pNewWeapon ) { return true; } + virtual bool Weapon_ShouldSelectItem( C_BaseCombatWeapon *pWeapon ); + virtual bool Weapon_Switch( C_BaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); // Switch to given weapon if has ammo (false if failed) + virtual C_BaseCombatWeapon *GetLastWeapon( void ) { return m_hLastWeapon.Get(); } + void ResetAutoaim( void ); + virtual void SelectItem( const char *pstr, int iSubType = 0 ); + + virtual void UpdateClientData( void ); + + virtual float GetFOV( void ); + int GetDefaultFOV( void ) const; + virtual bool IsZoomed( void ) { return false; } + bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0 ); + void ClearZoomOwner( void ); + + float GetFOVDistanceAdjustFactor(); + + virtual void ViewPunch( const QAngle &angleOffset ); + void ViewPunchReset( float tolerance = 0 ); + + void UpdateButtonState( int nUserCmdButtonMask ); + int GetImpulse( void ) const; + + virtual void Simulate(); + + virtual bool ShouldInterpolate(); + + virtual bool ShouldDraw(); + virtual int DrawModel( int flags ); + + // Called when not in tactical mode. Allows view to be overriden for things like driving a tank. + virtual void OverrideView( CViewSetup *pSetup ); + + // returns the player name + const char * GetPlayerName(); + virtual const Vector GetPlayerMins( void ) const; // uses local player + virtual const Vector GetPlayerMaxs( void ) const; // uses local player + + // Is the player dead? + bool IsPlayerDead(); + bool IsPoisoned( void ) { return m_Local.m_bPoisoned; } + + C_BaseEntity *GetUseEntity(); + + // Vehicles... + IClientVehicle *GetVehicle(); + + bool IsInAVehicle() const { return ( NULL != m_hVehicle.Get() ) ? true : false; } + virtual void SetVehicleRole( int nRole ); + void LeaveVehicle( void ); + + bool UsingStandardWeaponsInVehicle( void ); + + virtual void SetAnimation( PLAYER_ANIM playerAnim ); + + float GetTimeBase( void ) const; + float GetFinalPredictedTime() const; + + bool IsInVGuiInputMode() const; + bool IsInViewModelVGuiInputMode() const; + + C_CommandContext *GetCommandContext(); + + // Get the command number associated with the current usercmd we're running (if in predicted code). + int CurrentCommandNumber() const; + const CUserCmd *GetCurrentUserCommand() const; + + const QAngle& GetPunchAngle(); + void SetPunchAngle( const QAngle &angle ); + + float GetWaterJumpTime() const; + void SetWaterJumpTime( float flWaterJumpTime ); + float GetSwimSoundTime( void ) const; + void SetSwimSoundTime( float flSwimSoundTime ); + + float GetDeathTime( void ) { return m_flDeathTime; } + + void SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin ); + const Vector &GetPreviouslyPredictedOrigin() const; + + // CS wants to allow small FOVs for zoomed-in AWPs. + virtual float GetMinFOV() const; + + virtual void DoMuzzleFlash(); + virtual void PlayPlayerJingle(); + + virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity ); + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); + virtual surfacedata_t * GetFootstepSurface( const Vector &origin, const char *surfaceName ); + virtual void GetStepSoundVelocities( float *velwalk, float *velrun ); + virtual void SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking ); + virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ) { return pszBaseStepSoundName; } + + virtual void OnEmitFootstepSound( const CSoundParameters& params, const Vector& vecOrigin, float fVolume ) {} + + // Called by prediction when it detects a prediction correction. + // vDelta is the line from where the client had predicted the player to at the usercmd in question, + // to where the server says the client should be at said usercmd. + void NotePredictionError( const Vector &vDelta ); + + // Called by the renderer to apply the prediction error smoothing. + void GetPredictionErrorSmoothingVector( Vector &vOffset ); + + virtual void ExitLadder() {} + surfacedata_t *GetLadderSurface( const Vector &origin ); + + surfacedata_t *GetSurfaceData( void ) { return m_pSurfaceData; } + + void SetLadderNormal( Vector vecLadderNormal ) { m_vecLadderNormal = vecLadderNormal; } + + // Hints + virtual CHintSystem *Hints( void ) { return NULL; } + bool ShouldShowHints( void ) { return Hints() ? Hints()->ShouldShowHints() : false; } + bool HintMessage( int hint, bool bForce = false, bool bOnlyIfClear = false ) { return Hints() ? Hints()->HintMessage( hint, bForce, bOnlyIfClear ) : false; } + void HintMessage( const char *pMessage ) { if (Hints()) Hints()->HintMessage( pMessage ); } + + virtual IMaterial *GetHeadLabelMaterial( void ); + + // Fog + fogparams_t *GetFogParams( void ) { return &m_CurrentFog; } + void FogControllerChanged( bool bSnap ); + void UpdateFogController( void ); + void UpdateFogBlend( void ); + + float GetFOVTime( void ){ return m_flFOVTime; } + + virtual void OnAchievementAchieved( int iAchievement ) {} + + bool ShouldAnnounceAchievement( void ){ return m_flNextAchievementAnnounceTime < gpGlobals->curtime; } + void SetNextAchievementAnnounceTime( float flTime ){ m_flNextAchievementAnnounceTime = flTime; } + +#if defined USES_ECON_ITEMS + // Wearables + virtual void UpdateWearables(); + C_EconWearable *GetWearable( int i ) { return m_hMyWearables[i]; } + int GetNumWearables( void ) { return m_hMyWearables.Count(); } +#endif + + bool HasFiredWeapon( void ) { return m_bFiredWeapon; } + void SetFiredWeapon( bool bFlag ) { m_bFiredWeapon = bFlag; } + + virtual bool CanUseFirstPersonCommand( void ){ return true; } + +protected: + fogparams_t m_CurrentFog; + EHANDLE m_hOldFogController; + +public: + int m_StuckLast; + + // Data for only the local player + CNetworkVarEmbedded( CPlayerLocalData, m_Local ); + +#if defined USES_ECON_ITEMS + CNetworkVarEmbedded( CAttributeList, m_AttributeList ); +#endif + + // Data common to all other players, too + CPlayerState pl; + + // Player FOV values + int m_iFOV; // field of view + int m_iFOVStart; // starting value of the FOV changing over time (client only) + float m_flFOVTime; // starting time of the FOV zoom + int m_iDefaultFOV; // default FOV if no other zooms are occurring + EHANDLE m_hZoomOwner; // This is a pointer to the entity currently controlling the player's zoom + // Only this entity can change the zoom state once it has ownership + + // For weapon prediction + bool m_fOnTarget; //Is the crosshair on a target? + + char m_szAnimExtension[32]; + + int m_afButtonLast; + int m_afButtonPressed; + int m_afButtonReleased; + + int m_nButtons; + + CUserCmd *m_pCurrentCommand; + + // Movement constraints + EHANDLE m_hConstraintEntity; + Vector m_vecConstraintCenter; + float m_flConstraintRadius; + float m_flConstraintWidth; + float m_flConstraintSpeedFactor; + +protected: + + void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcVehicleView(IClientVehicle *pVehicle, Vector& eyeOrigin, QAngle& eyeAngles, + float& zNear, float& zFar, float& fov ); + virtual void CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual Vector GetChaseCamViewOffset( CBaseEntity *target ); + void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + + virtual float GetDeathCamInterpolationTime(); + + virtual void CalcDeathCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual void CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + + // Check to see if we're in vgui input mode... + void DetermineVguiInputMode( CUserCmd *pCmd ); + + // Used by prediction, sets the view angles for the player + virtual void SetLocalViewAngles( const QAngle &viewAngles ); + virtual void SetViewAngles( const QAngle& ang ); + + // used by client side player footsteps + surfacedata_t* GetGroundSurface(); + + virtual void FireGameEvent( IGameEvent *event ); + +protected: + // Did we just enter a vehicle this frame? + bool JustEnteredVehicle(); + +// DATA + int m_iObserverMode; // if in spectator mode != 0 + EHANDLE m_hObserverTarget; // current observer target + float m_flObserverChaseDistance; // last distance to observer traget + Vector m_vecFreezeFrameStart; + float m_flFreezeFrameStartTime; // Time at which we entered freeze frame observer mode + float m_flFreezeFrameDistance; + bool m_bWasFreezeFraming; + float m_flDeathTime; // last time player died + + float m_flStepSoundTime; + bool m_IsFootprintOnLeft; + +private: + // Make sure no one calls this... + C_BasePlayer& operator=( const C_BasePlayer& src ); + C_BasePlayer( const C_BasePlayer & ); // not defined, not accessible + + // Vehicle stuff. + EHANDLE m_hVehicle; + EHANDLE m_hOldVehicle; + EHANDLE m_hUseEntity; + + float m_flMaxspeed; + + int m_iBonusProgress; + int m_iBonusChallenge; + + CInterpolatedVar< Vector > m_iv_vecViewOffset; + + // Not replicated + Vector m_vecWaterJumpVel; + float m_flWaterJumpTime; // used to be called teleport_time + int m_nImpulse; + + float m_flSwimSoundTime; + Vector m_vecLadderNormal; + + QAngle m_vecOldViewAngles; + + bool m_bWasFrozen; + int m_flPhysics; + + int m_nTickBase; + int m_nFinalPredictedTick; + + EHANDLE m_pCurrentVguiScreen; + + bool m_bFiredWeapon; + + + // Player flashlight dynamic light pointers + CFlashlightEffect *m_pFlashlight; + + typedef CHandle CBaseCombatWeaponHandle; + CNetworkVar( CBaseCombatWeaponHandle, m_hLastWeapon ); + +#if !defined( NO_ENTITY_PREDICTION ) + CUtlVector< CHandle< C_BaseEntity > > m_SimulatedByThisPlayer; +#endif + + // players own view models, left & right hand + CHandle< C_BaseViewModel > m_hViewModel[ MAX_VIEWMODELS ]; + + float m_flOldPlayerZ; + float m_flOldPlayerViewOffsetZ; + + Vector m_vecVehicleViewOrigin; // Used to store the calculated view of the player while riding in a vehicle + QAngle m_vecVehicleViewAngles; // Vehicle angles + float m_flVehicleViewFOV; + int m_nVehicleViewSavedFrame; // Used to mark which frame was the last one the view was calculated for + + // For UI purposes... + int m_iOldAmmo[ MAX_AMMO_TYPES ]; + + C_CommandContext m_CommandContext; + + // For underwater effects + float m_flWaterSurfaceZ; + bool m_bResampleWaterSurface; + TimedEvent m_tWaterParticleTimer; + CSmartPtr m_pWaterEmitter; + + bool m_bPlayerUnderwater; + + friend class CPrediction; + + // HACK FOR TF2 Prediction + friend class CTFGameMovementRecon; + friend class CGameMovement; + friend class CTFGameMovement; + friend class CHL1GameMovement; + friend class CCSGameMovement; + friend class CHL2GameMovement; + friend class CDODGameMovement; + friend class CPortalGameMovement; + + // Accessors for gamemovement + float GetStepSize( void ) const { return m_Local.m_flStepSize; } + + float m_flNextAvoidanceTime; + float m_flAvoidanceRight; + float m_flAvoidanceForward; + float m_flAvoidanceDotForward; + float m_flAvoidanceDotRight; + +protected: + virtual bool IsDucked( void ) const { return m_Local.m_bDucked; } + virtual bool IsDucking( void ) const { return m_Local.m_bDucking; } + virtual float GetFallVelocity( void ) { return m_Local.m_flFallVelocity; } + bool ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ); + + float m_flLaggedMovementValue; + + // These are used to smooth out prediction corrections. They're most useful when colliding with + // vphysics objects. The server will be sending constant prediction corrections, and these can help + // the errors not be so jerky. + Vector m_vecPredictionError; + float m_flPredictionErrorTime; + + Vector m_vecPreviouslyPredictedOrigin; // Used to determine if non-gamemovement game code has teleported, or tweaked the player's origin + + char m_szLastPlaceName[MAX_PLACE_NAME_LENGTH]; // received from the server + + // Texture names and surface data, used by CGameMovement + int m_surfaceProps; + surfacedata_t* m_pSurfaceData; + float m_surfaceFriction; + char m_chTextureType; + + bool m_bSentFreezeFrame; + float m_flFreezeZOffset; + + float m_flNextAchievementAnnounceTime; + + int m_nForceVisionFilterFlags; // Force our vision filter to a specific setting + int m_nLocalPlayerVisionFlags; + +#if defined USES_ECON_ITEMS + // Wearables + CUtlVector > m_hMyWearables; +#endif + +private: + + struct StepSoundCache_t + { + StepSoundCache_t() : m_usSoundNameIndex( 0 ) {} + CSoundParameters m_SoundParameters; + unsigned short m_usSoundNameIndex; + }; + // One for left and one for right side of step + StepSoundCache_t m_StepSoundCache[ 2 ]; + +public: + + const char *GetLastKnownPlaceName( void ) const { return m_szLastPlaceName; } // return the last nav place name the player occupied + + float GetLaggedMovementValue( void ){ return m_flLaggedMovementValue; } + bool ShouldGoSouth( Vector vNPCForward, Vector vNPCRight ); //Such a bad name. + + void SetOldPlayerZ( float flOld ) { m_flOldPlayerZ = flOld; } +}; + +EXTERN_RECV_TABLE(DT_BasePlayer); + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline C_BasePlayer *ToBasePlayer( C_BaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + +#if _DEBUG + Assert( dynamic_cast( pEntity ) != NULL ); +#endif + + return static_cast( pEntity ); +} + +inline C_BaseEntity *C_BasePlayer::GetUseEntity() +{ + return m_hUseEntity; +} + + +inline IClientVehicle *C_BasePlayer::GetVehicle() +{ + C_BaseEntity *pVehicleEnt = m_hVehicle.Get(); + return pVehicleEnt ? pVehicleEnt->GetClientVehicle() : NULL; +} + +inline bool C_BasePlayer::IsObserver() const +{ + return (GetObserverMode() != OBS_MODE_NONE); +} + +inline int C_BasePlayer::GetImpulse( void ) const +{ + return m_nImpulse; +} + + +inline C_CommandContext* C_BasePlayer::GetCommandContext() +{ + return &m_CommandContext; +} + +inline int CBasePlayer::CurrentCommandNumber() const +{ + Assert( m_pCurrentCommand ); + return m_pCurrentCommand->command_number; +} + +inline const CUserCmd *CBasePlayer::GetCurrentUserCommand() const +{ + Assert( m_pCurrentCommand ); + return m_pCurrentCommand; +} + +#endif // C_BASEPLAYER_H diff --git a/game/client/c_basetempentity.h b/game/client/c_basetempentity.h new file mode 100644 index 0000000..2f3740e --- /dev/null +++ b/game/client/c_basetempentity.h @@ -0,0 +1,122 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_BASETEMPENTITY_H +#define C_BASETEMPENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "client_class.h" +#include "iclientnetworkable.h" +#include "c_recipientfilter.h" + + +//----------------------------------------------------------------------------- +// Purpose: Base class for TEs. All TEs should derive from this and at +// least implement OnDataChanged to be notified when the TE has been received +// from the server +//----------------------------------------------------------------------------- +class C_BaseTempEntity : public IClientUnknown, public IClientNetworkable + +{ +public: + DECLARE_CLASS_NOBASE( C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + + C_BaseTempEntity( void ); + virtual ~C_BaseTempEntity( void ); + + +// IClientUnknown implementation. +public: + + virtual void SetRefEHandle( const CBaseHandle &handle ) { Assert( false ); } + virtual const CBaseHandle& GetRefEHandle() const { return *((CBaseHandle*)0); } + + virtual IClientUnknown* GetIClientUnknown() { return this; } + virtual ICollideable* GetCollideable() { return 0; } + virtual IClientNetworkable* GetClientNetworkable() { return this; } + virtual IClientRenderable* GetClientRenderable() { return 0; } + virtual IClientEntity* GetIClientEntity() { return 0; } + virtual C_BaseEntity* GetBaseEntity() { return 0; } + virtual IClientThinkable* GetClientThinkable() { return 0; } + + +// IClientNetworkable overrides. +public: + + virtual void Release(); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataUnchangedInPVS( void ) { } + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void SetDormant( bool bDormant ); + virtual bool IsDormant( void ); + virtual int entindex( void ) const; + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void* GetDataTableBasePtr(); + virtual void SetDestroyedOnRecreateEntities( void ); + +public: + + // Dummy for CNetworkVars. + void NetworkStateChanged() {} + void NetworkStateChanged( void *pVar ) {} + + virtual bool Init(int entnum, int iSerialNum); + + virtual void Precache( void ); + + // For dynamic entities, return true to allow destruction + virtual bool ShouldDestroy( void ) { return false; }; + + C_BaseTempEntity *GetNext( void ); + + // Get list of tempentities + static C_BaseTempEntity *GetList( void ); + + C_BaseTempEntity *GetNextDynamic( void ); + + // Determine the color modulation amount + void GetColorModulation( float* color ) + { + assert(color); + color[0] = color[1] = color[2] = 1.0f; + } + + // Should this object be able to have shadows cast onto it? + virtual bool ShouldReceiveProjectedTextures( int flags ) { return false; } + +// Static members +public: + // List of dynamically allocated temp entis + static C_BaseTempEntity *GetDynamicList(); + + // Called at startup to allow temp entities to precache any models/sounds that they need + static void PrecacheTempEnts( void ); + + static void ClearDynamicTempEnts( void ); + + static void CheckDynamicTempEnts( void ); + +private: + + // Next in chain + C_BaseTempEntity *m_pNext; + C_BaseTempEntity *m_pNextDynamic; + + // TEs add themselves to this list for the executable. + static C_BaseTempEntity *s_pTempEntities; + static C_BaseTempEntity *s_pDynamicEntities; +}; + + +#endif // C_BASETEMPENTITY_H diff --git a/game/client/c_baseviewmodel.h b/game/client/c_baseviewmodel.h new file mode 100644 index 0000000..fa59176 --- /dev/null +++ b/game/client/c_baseviewmodel.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side view model implementation. Responsible for drawing +// the view model. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_BASEVIEWMODEL_H +#define C_BASEVIEWMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseanimating.h" +#include "utlvector.h" +#include "baseviewmodel_shared.h" + +#endif // C_BASEVIEWMODEL_H diff --git a/game/client/c_breakableprop.h b/game/client/c_breakableprop.h new file mode 100644 index 0000000..666d9a3 --- /dev/null +++ b/game/client/c_breakableprop.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_BREAKABLEPROP_H +#define C_BREAKABLEPROP_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_BreakableProp : public C_BaseAnimating +{ + typedef C_BaseAnimating BaseClass; +public: + DECLARE_CLIENTCLASS(); + + C_BreakableProp(); + + virtual void SetFadeMinMax( float fademin, float fademax ); + + // Copy fade from another breakable prop + void CopyFadeFrom( C_BreakableProp *pSource ); +}; + +#endif // C_BREAKABLEPROP_H diff --git a/game/client/c_effects.h b/game/client/c_effects.h new file mode 100644 index 0000000..27bb501 --- /dev/null +++ b/game/client/c_effects.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_EFFECTS_H +#define C_EFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + + +// Draw rain effects. +void DrawPrecipitation(); + + +#endif // C_EFFECTS_H diff --git a/game/client/c_entitydissolve.h b/game/client/c_entitydissolve.h new file mode 100644 index 0000000..d440e0b --- /dev/null +++ b/game/client/c_entitydissolve.h @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENTITY_DISSOLVE_H +#define C_ENTITY_DISSOLVE_H + +#include "cbase.h" + +//----------------------------------------------------------------------------- +// Entity Dissolve, client-side implementation +//----------------------------------------------------------------------------- +class C_EntityDissolve : public C_BaseEntity, public IMotionEvent +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_EntityDissolve, C_BaseEntity ); + + C_EntityDissolve( void ); + + // Inherited from C_BaseEntity + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + virtual int DrawModel( int flags ); + virtual bool ShouldDraw() { return true; } + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void UpdateOnRemove( void ); + + virtual Vector GetEffectColor( void ) { return m_vEffectColor; } + virtual void SetEffectColor( Vector v ) { m_vEffectColor = v; } + + // Inherited from IMotionEvent + virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ); + + void SetupEmitter( void ); + + void ClientThink( void ); + + void SetServerLinkState( bool state ) { m_bLinkedToServerEnt = state; } + + float m_flStartTime; + float m_flFadeOutStart; + float m_flFadeOutLength; + float m_flFadeOutModelStart; + float m_flFadeOutModelLength; + float m_flFadeInStart; + float m_flFadeInLength; + int m_nDissolveType; + float m_flNextSparkTime; + + Vector m_vEffectColor; + + Vector m_vDissolverOrigin; + int m_nMagnitude; + + bool m_bCoreExplode; + +protected: + + float GetFadeInPercentage( void ); // Fade in amount (entity fading to black) + float GetFadeOutPercentage( void ); // Fade out amount (particles fading away) + float GetModelFadeOutPercentage( void );// Mode fade out amount + + // Compute the bounding box's center, size, and basis + void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, + Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec ); + void BuildTeslaEffect( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, bool bRandom, float flYawOffset ); + + void DoSparks( mstudiohitboxset_t *set, matrix3x4_t *hitboxbones[MAXSTUDIOBONES] ); + +private: + + CSmartPtr m_pEmitter; + + bool m_bLinkedToServerEnt; + IPhysicsMotionController *m_pController; +}; + +#endif // C_ENTITY_DISSOLVE_H + diff --git a/game/client/c_env_fog_controller.h b/game/client/c_env_fog_controller.h new file mode 100644 index 0000000..d91c97d --- /dev/null +++ b/game/client/c_env_fog_controller.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENV_FOG_CONTROLLER_H +#define C_ENV_FOG_CONTROLLER_H + +#define CFogController C_FogController + +//============================================================================= +// +// Class Fog Controller: +// Compares a set of integer inputs to the one main input +// Outputs true if they are all equivalant, false otherwise +// +class C_FogController : public C_BaseEntity +{ +public: + DECLARE_NETWORKCLASS(); + DECLARE_CLASS( C_FogController, C_BaseEntity ); + + C_FogController(); + +public: + + fogparams_t m_fog; +}; + + +#endif // C_ENV_FOG_CONTROLLER_H \ No newline at end of file diff --git a/game/client/c_fire_smoke.h b/game/client/c_fire_smoke.h new file mode 100644 index 0000000..9f7a94e --- /dev/null +++ b/game/client/c_fire_smoke.h @@ -0,0 +1,302 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef C_FIRE_SMOKE_H +#define C_FIRE_SMOKE_H + +#include "particles_simple.h" +#include "tempent.h" +#include "glow_overlay.h" +#include "view.h" +#include "particle_litsmokeemitter.h" + +class CFireOverlay; + +class C_FireSprite : public C_Sprite +{ + DECLARE_CLASS( C_FireSprite, C_Sprite ); + +private: + virtual int DrawModel( int flags ) + { + if ( m_bFadeFromAbove ) + { + // The sprites become less visible the more you look down or up at them + Vector vToPos = GetLocalOrigin() - CurrentViewOrigin(); + VectorNormalize( vToPos ); + + float fUpAmount = vToPos.z; + + int iAlpha = 255; + + if ( fUpAmount < -0.75f ) + iAlpha = 0; + else if ( fUpAmount < -0.65f ) + iAlpha = 255 - (int)( ( fUpAmount + 0.65f ) * 10.0f * -255.0f ); + else if ( fUpAmount > 0.85f ) + iAlpha = 0; + else if ( fUpAmount > 0.75f ) + iAlpha = 255 - (int)( ( fUpAmount - 0.75f ) * 10.0f * 255.0f ); + + SetColor( iAlpha, iAlpha, iAlpha ); + } + + return BaseClass::DrawModel( flags ); + } + +public: + Vector m_vecMoveDir; + bool m_bFadeFromAbove; +}; + +class C_FireFromAboveSprite : public C_Sprite +{ + DECLARE_CLASS( C_FireFromAboveSprite, C_Sprite ); + + virtual int DrawModel( int flags ) + { + // The sprites become more visible the more you look down or up at them + Vector vToPos = GetLocalOrigin() - CurrentViewOrigin(); + VectorNormalize( vToPos ); + + float fUpAmount = vToPos.z; + + int iAlpha = 0; + + if ( fUpAmount < -0.85f ) + iAlpha = 255; + else if ( fUpAmount < -0.65f ) + iAlpha = (int)( ( fUpAmount + 0.65f ) * 5.0f * -255.0f ); + else if ( fUpAmount > 0.75f ) + iAlpha = 255; + else if ( fUpAmount > 0.55f ) + iAlpha = (int)( ( fUpAmount - 0.55f ) * 5.0f * 255.0f ); + + SetColor( iAlpha, iAlpha, iAlpha ); + + return BaseClass::DrawModel( flags ); + } +}; + +#ifdef _XBOX +// XBox reduces the flame count +#define NUM_CHILD_FLAMES 1 +#else +#define NUM_CHILD_FLAMES 4 +#endif + +#define SMOKE_RISE_RATE 92.0f +#define SMOKE_LIFETIME 2.0f +#define EMBER_LIFETIME 2.0f + +#define FLAME_CHILD_SPREAD 64.0f +#define FLAME_SOURCE_HEIGHT 128.0f +#define FLAME_FROM_ABOVE_SOURCE_HEIGHT 32.0f + +//================================================== +// C_FireSmoke +//================================================== + +//NOTENOTE: Mirrored in dlls/fire_smoke.h +#define bitsFIRESMOKE_NONE 0x00000000 +#define bitsFIRESMOKE_ACTIVE 0x00000001 +#define bitsFIRESMOKE_SMOKE 0x00000002 +#define bitsFIRESMOKE_SMOKE_COLLISION 0x00000004 +#define bitsFIRESMOKE_GLOW 0x00000008 +#define bitsFIRESMOKE_VISIBLE_FROM_ABOVE 0x00000010 + +#define OVERLAY_MAX_VISIBLE_RANGE 512.0f + + +class C_FireSmoke : public C_BaseEntity +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_FireSmoke, C_BaseEntity ); + + C_FireSmoke(); + ~C_FireSmoke(); + + void Start( void ); + void Simulate( void ); + + void StartClientOnly( void ); + void RemoveClientOnly( void ); + +protected: + void Update( void ); + void UpdateAnimation( void ); + void UpdateScale( void ); + void UpdateFlames( void ); + void AddFlames( void ); + void SpawnSmoke( void ); + void FindClipPlane( void ); + +//C_BaseEntity +public: + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual bool ShouldDraw(); + + float GetScale( void ) const { return m_flScaleRegister; } + +//From the server +public: + float m_flStartScale; + float m_flScale; + float m_flScaleTime; + int m_nFlags; + int m_nFlameModelIndex; + int m_nFlameFromAboveModelIndex; + +//Client-side only +public: + float m_flScaleRegister; + float m_flScaleStart; + float m_flScaleEnd; + float m_flScaleTimeStart; + float m_flScaleTimeEnd; + float m_flChildFlameSpread; + + VPlane m_planeClip; + float m_flClipPerc; + bool m_bClipTested; + + bool m_bFadingOut; + +protected: + + void UpdateEffects( void ); + + //CSmartPtr m_pEmberEmitter; + CSmartPtr m_pSmokeEmitter; + + C_FireSprite m_entFlames[NUM_CHILD_FLAMES]; + C_FireFromAboveSprite m_entFlamesFromAbove[NUM_CHILD_FLAMES]; + float m_entFlameScales[NUM_CHILD_FLAMES]; + + TimedEvent m_tParticleSpawn; + + CFireOverlay *m_pFireOverlay; + + // New Particle Fire Effect + CNewParticleEffect *m_hEffect; +private: + C_FireSmoke( const C_FireSmoke & ); +}; + +//Fire overlay +class CFireOverlay : public CGlowOverlay +{ +public: + + //Constructor + CFireOverlay( C_FireSmoke *owner ) + { + m_pOwner = owner; + m_flScale = 0.0f; + m_nGUID = random->RandomInt( -999999, 999999 ); + } + + //----------------------------------------------------------------------------- + // Purpose: Generate a flicker value + // Output : scalar value + //----------------------------------------------------------------------------- + float GetFlickerScale( void ) + { + float result = 0.0f; + + float time = Helper_GetTime() + m_nGUID; + + result = sin( time * 1000.0f ); + result += 0.5f * sin( time * 2000.0f ); + result -= 0.5f * cos( time * 8000.0f ); + + return result; + } + + //----------------------------------------------------------------------------- + // Purpose: Update the overlay + //----------------------------------------------------------------------------- + virtual bool Update( void ) + { + if ( m_pOwner == NULL ) + return false; + + float scale = m_pOwner->GetScale(); + float dscale = scale - m_flScale; + + m_vPos[2] += dscale * FLAME_SOURCE_HEIGHT; + m_flScale = scale; + + scale *= 0.75f; + + float flickerScale = GetFlickerScale(); + + float newScale = scale + ( scale * flickerScale * 0.1f ); + + m_Sprites[0].m_flHorzSize = ( newScale * 0.2f ) + ( m_Sprites[0].m_flHorzSize * 0.8f ); + m_Sprites[0].m_flVertSize = m_Sprites[0].m_flHorzSize * 1.5f; + + float cameraDistance = ( CurrentViewOrigin() - (m_pOwner->GetAbsOrigin())).Length(); + + C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); + if ( local ) + { + cameraDistance *= local->GetFOVDistanceAdjustFactor(); + } + + if ( cameraDistance > OVERLAY_MAX_VISIBLE_RANGE ) + cameraDistance = OVERLAY_MAX_VISIBLE_RANGE; + + float alpha = 1.0f - ( cameraDistance / OVERLAY_MAX_VISIBLE_RANGE ); + + Vector newColor = m_vBaseColors[0] + ( m_vBaseColors[0] * flickerScale * 0.5f ); + m_Sprites[0].m_vColor = ( newColor * 0.1f ) + ( m_Sprites[0].m_vColor * 0.9f ) * alpha; + + return true; + } + +public: + + C_FireSmoke *m_pOwner; + Vector m_vBaseColors[MAX_SUN_LAYERS]; + float m_flScale; + int m_nGUID; +}; + +// +// Entity flame, client-side implementation +// + +#define NUM_FLAMELETS 5 + +class C_EntityFlame : public C_BaseEntity +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_EntityFlame, C_BaseEntity ); + + C_EntityFlame( void ); + ~C_EntityFlame( void ); + + virtual void Simulate( void ); + virtual void UpdateOnRemove( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + + CNewParticleEffect *m_hEffect; + EHANDLE m_hEntAttached; // The entity that we are burning (attached to). + EHANDLE m_hOldAttached; + +protected: + + void CreateEffect( void ); + void StopEffect( void ); +}; + +#endif //C_FIRE_SMOKE_H \ No newline at end of file diff --git a/game/client/c_func_dust.h b/game/client/c_func_dust.h new file mode 100644 index 0000000..31ff061 --- /dev/null +++ b/game/client/c_func_dust.h @@ -0,0 +1,112 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_FUNC_DUST_H +#define C_FUNC_DUST_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_baseentity.h" +#include "particles_simple.h" +#include "particle_util.h" +#include "bspflags.h" + + + +// ------------------------------------------------------------------------------------ // +// CDustEffect particle renderer. +// ------------------------------------------------------------------------------------ // + +class C_Func_Dust; + +class CFuncDustParticle : public Particle +{ +public: + Vector m_vVelocity; + float m_flLifetime; + float m_flDieTime; + float m_flSize; + color32 m_Color; +}; + +class CDustEffect : public CParticleEffect +{ +public: + CDustEffect( const char *pDebugName ) : CParticleEffect( pDebugName ) {} + + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + C_Func_Dust *m_pDust; + +private: + CDustEffect( const CDustEffect & ); // not defined, not accessible +}; + + +// ------------------------------------------------------------------------------------ // +// C_Func_Dust class. +// ------------------------------------------------------------------------------------ // + +class C_Func_Dust : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_Func_Dust, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_Func_Dust(); + virtual ~C_Func_Dust(); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink(); + virtual bool ShouldDraw(); + + +private: + + void AttemptSpawnNewParticle(); + + + +// Vars from server. +public: + + color32 m_Color; + int m_SpawnRate; + + float m_flSizeMin; + float m_flSizeMax; + + int m_SpeedMax; + + int m_LifetimeMin; + int m_LifetimeMax; + + int m_DistMax; + + float m_FallSpeed; // extra 'gravity' + + +public: + + int m_DustFlags; // Combination of DUSTFLAGS_ + + + +public: + CDustEffect m_Effect; + PMaterialHandle m_hMaterial; + TimedEvent m_Spawner; + +private: + C_Func_Dust( const C_Func_Dust & ); // not defined, not accessible +}; + + + +#endif // C_FUNC_DUST_H diff --git a/game/client/c_func_reflective_glass.h b/game/client/c_func_reflective_glass.h new file mode 100644 index 0000000..48e1491 --- /dev/null +++ b/game/client/c_func_reflective_glass.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef C_FUNC_REFLECTIVE_GLASS +#define C_FUNC_REFLECTIVE_GLASS + +#ifdef _WIN32 +#pragma once +#endif + +struct cplane_t; +class CViewSetup; + + +//----------------------------------------------------------------------------- +// Do we have reflective glass in view? If so, what's the reflection plane? +//----------------------------------------------------------------------------- +bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane ); + + +#endif // C_FUNC_REFLECTIVE_GLASS + + diff --git a/game/client/c_gib.h b/game/client/c_gib.h new file mode 100644 index 0000000..16d53e4 --- /dev/null +++ b/game/client/c_gib.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_GIB_H +#define C_GIB_H +#ifdef _WIN32 +#pragma once +#endif + +#define DEFAULT_GIB_LIFETIME 4.0f + +// Base client gibs + +class C_Gib : public C_BaseAnimating +{ + typedef C_BaseAnimating BaseClass; +public: + + ~C_Gib( void ); + + static C_Gib *CreateClientsideGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime = DEFAULT_GIB_LIFETIME ); + + bool InitializeGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime = DEFAULT_GIB_LIFETIME ); + void ClientThink( void ); + void StartTouch( C_BaseEntity *pOther ); + + virtual void HitSurface( C_BaseEntity *pOther ); + +protected: + + float m_flTouchDelta; // Amount of time that must pass before another touch function can be called +}; + +#ifdef HL2_CLIENT_DLL +class CAntlionGibManager : public CAutoGameSystemPerFrame +{ +public: + CAntlionGibManager( char const *name ) : CAutoGameSystemPerFrame( name ) + { + } + + // Methods of IGameSystem + virtual void Update( float frametime ); + virtual void LevelInitPreEntity( void ); + + void AddGib( C_BaseEntity *pEntity ); + void RemoveGib( C_BaseEntity *pEntity ); + +private: + typedef CHandle CGibHandle; + CUtlLinkedList< CGibHandle > m_LRU; + +}; + + +extern CAntlionGibManager s_AntlionGibManager; + +#endif + + +#endif // C_GIB_H diff --git a/game/client/c_impact_effects.h b/game/client/c_impact_effects.h new file mode 100644 index 0000000..aaeddbe --- /dev/null +++ b/game/client/c_impact_effects.h @@ -0,0 +1,108 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_IMPACT_EFFECTS_H +#define C_IMPACT_EFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: DustParticle emitter +//----------------------------------------------------------------------------- +class CDustParticle : public CSimpleEmitter +{ +public: + + CDustParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + //Create + static CDustParticle *Create( const char *pDebugName="dust" ) + { + return new CDustParticle( pDebugName ); + } + + //Roll + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f ); + +#ifdef _XBOX + //Cap the minimum roll + if ( fabs( pParticle->m_flRollDelta ) < 0.1f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.1f : -0.1f; + } +#else + if ( fabs( pParticle->m_flRollDelta ) < 0.5f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f; + } +#endif // _XBOX + + return pParticle->m_flRoll; + } + + //Velocity + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + Vector saveVelocity = pParticle->m_vecVelocity; + + //Decellerate + static float dtime; + static float decay; + + if ( dtime != timeDelta ) + { + dtime = timeDelta; + float expected = 0.5; + decay = exp( log( 0.0001f ) * dtime / expected ); + } + + pParticle->m_vecVelocity = pParticle->m_vecVelocity * decay; + +#ifdef _XBOX + //Cap the minimum speed + if ( pParticle->m_vecVelocity.LengthSqr() < (8.0f*8.0f) ) + { + VectorNormalize( saveVelocity ); + pParticle->m_vecVelocity = saveVelocity * 8.0f; + } +#else + if ( pParticle->m_vecVelocity.LengthSqr() < (32.0f*32.0f) ) + { + VectorNormalize( saveVelocity ); + pParticle->m_vecVelocity = saveVelocity * 32.0f; + } +#endif // _XBOX + } + + //Alpha + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime; + float ramp = 1.0f - tLifetime; + + //Non-linear fade + if ( ramp < 0.75f ) + ramp *= ramp; + + return ramp; + } + +private: + CDustParticle( const CDustParticle & ); // not defined, not accessible +}; + +void GetColorForSurface( trace_t *trace, Vector *color ); + +#include "tier0/memdbgoff.h" + +#endif // C_IMPACT_EFFECTS_H diff --git a/game/client/c_physbox.h b/game/client/c_physbox.h new file mode 100644 index 0000000..c42a3a9 --- /dev/null +++ b/game/client/c_physbox.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + + + +// Client-side CBasePlayer + +#ifndef C_PHYSBOX_H +#define C_PHYSBOX_H +#pragma once + + +#include "c_baseentity.h" + + +class C_PhysBox : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_PhysBox, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_PhysBox(); + virtual ~C_PhysBox(); + virtual ShadowType_t ShadowCastType(); + +public: + float m_mass; // TEST.. +}; + + +#endif + + + diff --git a/game/client/c_physicsprop.h b/game/client/c_physicsprop.h new file mode 100644 index 0000000..9c8804e --- /dev/null +++ b/game/client/c_physicsprop.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_PHYSICSPROP_H +#define C_PHYSICSPROP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_breakableprop.h" +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_PhysicsProp : public C_BreakableProp +{ + typedef C_BreakableProp BaseClass; +public: + DECLARE_CLIENTCLASS(); + + C_PhysicsProp(); + ~C_PhysicsProp(); + + virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ); + +protected: + // Networked vars. + bool m_bAwake; + bool m_bAwakeLastTime; +}; + +#endif // C_PHYSICSPROP_H diff --git a/game/client/c_pixel_visibility.h b/game/client/c_pixel_visibility.h new file mode 100644 index 0000000..3c07514 --- /dev/null +++ b/game/client/c_pixel_visibility.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_PIXEL_VISIBILITY_H +#define C_PIXEL_VISIBILITY_H +#ifdef _WIN32 +#pragma once +#endif + + +const float PIXELVIS_DEFAULT_PROXY_SIZE = 2.0f; +const float PIXELVIS_DEFAULT_FADE_TIME = 0.0625f; + +typedef int pixelvis_handle_t; +struct pixelvis_queryparams_t +{ + pixelvis_queryparams_t() + { + bSetup = false; + } + + void Init( const Vector &origin, float proxySizeIn = PIXELVIS_DEFAULT_PROXY_SIZE, float proxyAspectIn = 1.0f, float fadeTimeIn = PIXELVIS_DEFAULT_FADE_TIME ) + { + position = origin; + proxySize = proxySizeIn; + proxyAspect = proxyAspectIn; + fadeTime = fadeTimeIn; + bSetup = true; + bSizeInScreenspace = false; + } + + Vector position; + float proxySize; + float proxyAspect; + float fadeTime; + bool bSetup; + bool bSizeInScreenspace; +}; + +float PixelVisibility_FractionVisible( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle ); +float StandardGlowBlend( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle, int rendermode, int renderfx, int alpha, float *pscale ); + +void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //mainly needed by portal mod to avoid a pop in visibility when teleporting the player + +void PixelVisibility_EndCurrentView(); +void PixelVisibility_EndScene(); +float GlowSightDistance( const Vector &glowOrigin, bool bShouldTrace ); + +// returns true if the video hardware is doing the tests, false is traceline is doing so. +bool PixelVisibility_IsAvailable(); + +#endif // C_PIXEL_VISIBILITY_H diff --git a/game/client/c_playerlocaldata.h b/game/client/c_playerlocaldata.h new file mode 100644 index 0000000..95b6d48 --- /dev/null +++ b/game/client/c_playerlocaldata.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the player specific data that is sent only to the player +// to whom it belongs. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_PLAYERLOCALDATA_H +#define C_PLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "mathlib/vector.h" +#include "playernet_vars.h" + +//----------------------------------------------------------------------------- +// Purpose: Player specific data ( sent only to local player, too ) +//----------------------------------------------------------------------------- +class CPlayerLocalData +{ +public: + DECLARE_PREDICTABLE(); + DECLARE_CLASS_NOBASE( CPlayerLocalData ); + DECLARE_EMBEDDED_NETWORKVAR(); + + CPlayerLocalData() : + m_iv_vecPunchAngle( "CPlayerLocalData::m_iv_vecPunchAngle" ), + m_iv_vecPunchAngleVel( "CPlayerLocalData::m_iv_vecPunchAngleVel" ) + { + m_iv_vecPunchAngle.Setup( &m_vecPunchAngle.m_Value, LATCH_SIMULATION_VAR ); + m_iv_vecPunchAngleVel.Setup( &m_vecPunchAngleVel.m_Value, LATCH_SIMULATION_VAR ); + m_flFOVRate = 0; + } + + unsigned char m_chAreaBits[MAX_AREA_STATE_BYTES]; // Area visibility flags. + unsigned char m_chAreaPortalBits[MAX_AREA_PORTAL_STATE_BYTES];// Area portal visibility flags. + + int m_iHideHUD; // bitfields containing sections of the HUD to hide + + float m_flFOVRate; // rate at which the FOV changes + + + bool m_bDucked; + bool m_bDucking; + bool m_bInDuckJump; + float m_flDucktime; + float m_flDuckJumpTime; + float m_flJumpTime; + int m_nStepside; + float m_flFallVelocity; + int m_nOldButtons; + // Base velocity that was passed in to server physics so + // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. + Vector m_vecClientBaseVelocity; + CNetworkQAngle( m_vecPunchAngle ); // auto-decaying view angle adjustment + CInterpolatedVar< QAngle > m_iv_vecPunchAngle; + + CNetworkQAngle( m_vecPunchAngleVel ); // velocity of auto-decaying view angle adjustment + CInterpolatedVar< QAngle > m_iv_vecPunchAngleVel; + bool m_bDrawViewmodel; + bool m_bWearingSuit; + bool m_bPoisoned; + float m_flStepSize; + bool m_bAllowAutoMovement; + + // 3d skybox + sky3dparams_t m_skybox3d; + // fog params + fogplayerparams_t m_PlayerFog; + // audio environment + audioparams_t m_audio; + + bool m_bSlowMovement; + +}; + +#endif // C_PLAYERLOCALDATA_H diff --git a/game/client/c_playerresource.h b/game/client/c_playerresource.h new file mode 100644 index 0000000..d13f923 --- /dev/null +++ b/game/client/c_playerresource.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Entity that propagates general data needed by clients for every player. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_PLAYERRESOURCE_H +#define C_PLAYERRESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "const.h" +#include "c_baseentity.h" +#include + +#define PLAYER_UNCONNECTED_NAME "unconnected" +#define PLAYER_ERROR_NAME "ERRORNAME" + +class C_PlayerResource : public C_BaseEntity, public IGameResources +{ + DECLARE_CLASS( C_PlayerResource, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_PlayerResource(); + virtual ~C_PlayerResource(); + +public : // IGameResources intreface + + // Team data access + virtual int GetTeamScore( int index ); + virtual const char *GetTeamName( int index ); + virtual const Color&GetTeamColor( int index ); + + // Player data access + virtual bool IsConnected( int index ); + virtual bool IsAlive( int index ); + virtual bool IsFakePlayer( int index ); + virtual bool IsLocalPlayer( int index ); + virtual bool IsHLTV(int index); + virtual bool IsReplay(int index); + + virtual const char *GetPlayerName( int index ); + virtual int GetPing( int index ); +// virtual int GetPacketloss( int index ); + virtual int GetPlayerScore( int index ); + virtual int GetDeaths( int index ); + virtual int GetTeam( int index ); + virtual int GetFrags( int index ); + virtual int GetHealth( int index ); + + virtual void ClientThink(); + virtual void OnDataChanged(DataUpdateType_t updateType); + +protected: + void UpdatePlayerName( int slot ); + + // Data for each player that's propagated to all clients + // Stored in individual arrays so they can be sent down via datatables + string_t m_szName[MAX_PLAYERS+1]; + int m_iPing[MAX_PLAYERS+1]; + int m_iScore[MAX_PLAYERS+1]; + int m_iDeaths[MAX_PLAYERS+1]; + bool m_bConnected[MAX_PLAYERS+1]; + int m_iTeam[MAX_PLAYERS+1]; + bool m_bAlive[MAX_PLAYERS+1]; + int m_iHealth[MAX_PLAYERS+1]; + Color m_Colors[MAX_TEAMS]; + string_t m_szUnconnectedName; + +}; + +extern C_PlayerResource *g_PR; + +#endif // C_PLAYERRESOURCE_H diff --git a/game/client/c_point_camera.h b/game/client/c_point_camera.h new file mode 100644 index 0000000..8bca63a --- /dev/null +++ b/game/client/c_point_camera.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_POINTCAMERA_H +#define C_POINTCAMERA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "basetypes.h" + +class C_PointCamera : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_PointCamera, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +public: + C_PointCamera(); + ~C_PointCamera(); + + bool IsActive(); + + // C_BaseEntity. + virtual bool ShouldDraw(); + + float GetFOV(); + float GetResolution(); + bool IsFogEnabled(); + void GetFogColor( unsigned char &r, unsigned char &g, unsigned char &b ); + float GetFogStart(); + float GetFogMaxDensity(); + float GetFogEnd(); + bool UseScreenAspectRatio() const { return m_bUseScreenAspectRatio; } + + virtual void GetToolRecordingState( KeyValues *msg ); + +private: + float m_FOV; + float m_Resolution; + bool m_bFogEnable; + color32 m_FogColor; + float m_flFogStart; + float m_flFogEnd; + float m_flFogMaxDensity; + bool m_bActive; + bool m_bUseScreenAspectRatio; + +public: + C_PointCamera *m_pNext; +}; + +C_PointCamera *GetPointCameraList(); + +#endif // C_POINTCAMERA_H diff --git a/game/client/c_prop_vehicle.h b/game/client/c_prop_vehicle.h new file mode 100644 index 0000000..1fb699e --- /dev/null +++ b/game/client/c_prop_vehicle.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_PROP_VEHICLE_H +#define C_PROP_VEHICLE_H +#pragma once + +#include "iclientvehicle.h" +#include "vehicle_viewblend_shared.h" +class C_PropVehicleDriveable : public C_BaseAnimating, public IClientVehicle +{ + + DECLARE_CLASS( C_PropVehicleDriveable, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + DECLARE_DATADESC(); + + C_PropVehicleDriveable(); + ~C_PropVehicleDriveable(); + +// IVehicle overrides. +public: + + virtual C_BaseCombatCharacter* GetPassenger( int nRole ); + virtual int GetPassengerRole( C_BaseCombatCharacter *pEnt ); + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); + + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {} + virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {} + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {} + + virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {} + +// IClientVehicle overrides. +public: + + virtual void GetVehicleFOV( float &flFOV ) { flFOV = m_flFOV; } + virtual void DrawHudElements(); + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + virtual void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); + virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const; + +#ifdef HL2_CLIENT_DLL + virtual int GetPrimaryAmmoType() const { return -1; } + virtual int GetPrimaryAmmoCount() const { return -1; } + virtual int GetPrimaryAmmoClip() const { return -1; } + virtual bool PrimaryAmmoUsesClips() const { return false; } +#endif + + virtual bool IsPredicted() const { return false; } + virtual int GetJoystickResponseCurve() const; + +// C_BaseEntity overrides. +public: + + virtual IClientVehicle* GetClientVehicle() { return this; } + virtual C_BaseEntity *GetVehicleEnt() { return this; } + virtual bool IsSelfAnimating() { return false; }; + + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + // Should this object cast render-to-texture shadows? + virtual ShadowType_t ShadowCastType(); + + // Mark the shadow as dirty while the vehicle is being driven + virtual void ClientThink( void ); + +// C_PropVehicleDriveable +public: + + bool IsRunningEnterExitAnim( void ) { return m_bEnterAnimOn || m_bExitAnimOn; } + // NVNT added to check if the vehicle needs to aim + virtual bool HasGun(void){return m_bHasGun;} + +protected: + + virtual void OnEnteredVehicle( C_BaseCombatCharacter *pPassenger ); + // NVNT added to notify haptics system of vehicle exit. + virtual void OnExitedVehicle( C_BaseCombatCharacter *pPassenger ); + + virtual void RestrictView( float *pYawBounds, float *pPitchBounds, float *pRollBounds, QAngle &vecViewAngles ); + virtual void SetVehicleFOV( float flFOV ) { m_flFOV = flFOV; } + +protected: + + CHandle m_hPlayer; + int m_nSpeed; + int m_nRPM; + float m_flThrottle; + int m_nBoostTimeLeft; + int m_nHasBoost; + int m_nScannerDisabledWeapons; + int m_nScannerDisabledVehicle; + + // timers/flags for flashing icons on hud + int m_iFlashTimer; + bool m_bLockedDim; + bool m_bLockedIcon; + + int m_iScannerWepFlashTimer; + bool m_bScannerWepDim; + bool m_bScannerWepIcon; + + int m_iScannerVehicleFlashTimer; + bool m_bScannerVehicleDim; + bool m_bScannerVehicleIcon; + + float m_flSequenceChangeTime; + bool m_bEnterAnimOn; + bool m_bExitAnimOn; + float m_flFOV; + + Vector m_vecGunCrosshair; + CInterpolatedVar m_iv_vecGunCrosshair; + Vector m_vecEyeExitEndpoint; + bool m_bHasGun; + bool m_bUnableToFire; + + // Used to smooth view entry + CHandle m_hPrevPlayer; + + ViewSmoothingData_t m_ViewSmoothingData; +}; + + +#endif // C_PROP_VEHICLE_H diff --git a/game/client/c_props.h b/game/client/c_props.h new file mode 100644 index 0000000..bb8af27 --- /dev/null +++ b/game/client/c_props.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef C_PROPS_H +#define C_PROPS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_breakableprop.h" +#include "props_shared.h" + +#define CDynamicProp C_DynamicProp + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_DynamicProp : public C_BreakableProp +{ + DECLARE_CLASS( C_DynamicProp, C_BreakableProp ); +public: + DECLARE_NETWORKCLASS(); + + // constructor, destructor + C_DynamicProp( void ); + ~C_DynamicProp( void ); + + void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + unsigned int ComputeClientSideAnimationFlags(); + bool TestBoneFollowers( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + +private: + C_DynamicProp( const C_DynamicProp & ); + + bool m_bUseHitboxesForRenderBox; + int m_iCachedFrameCount; + Vector m_vecCachedRenderMins; + Vector m_vecCachedRenderMaxs; +}; + +#endif // C_PROPS_H diff --git a/game/client/c_recipientfilter.h b/game/client/c_recipientfilter.h new file mode 100644 index 0000000..d501452 --- /dev/null +++ b/game/client/c_recipientfilter.h @@ -0,0 +1,189 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_RECIPIENTFILTER_H +#define C_RECIPIENTFILTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "irecipientfilter.h" +#include "utlvector.h" +#include "c_baseentity.h" +#include "soundflags.h" +#include "bitvec.h" + +class C_BasePlayer; +class C_Team; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_RecipientFilter : public IRecipientFilter +{ +public: + C_RecipientFilter(); + virtual ~C_RecipientFilter(); + + virtual bool IsReliable( void ) const; + + virtual int GetRecipientCount( void ) const; + virtual int GetRecipientIndex( int slot ) const; + + virtual bool IsInitMessage( void ) const { return false; }; + +public: + + void CopyFrom( const C_RecipientFilter& src ); + + void Reset( void ); + + void MakeReliable( void ); + + void AddAllPlayers( void ); + void AddRecipientsByPVS( const Vector& origin ); + void AddRecipientsByPAS( const Vector& origin ); + void AddRecipient( C_BasePlayer *player ); + void RemoveRecipient( C_BasePlayer *player ); + void AddRecipientsByTeam( C_Team *team ); + void RemoveRecipientsByTeam( C_Team *team ); + + void UsePredictionRules( void ); + bool IsUsingPredictionRules( void ) const; + + bool IgnorePredictionCull( void ) const; + void SetIgnorePredictionCull( bool ignore ); + + void AddPlayersFromBitMask( CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ); + +//private: + + bool m_bReliable; + bool m_bInitMessage; + CUtlVector< int > m_Recipients; + // If using prediction rules, the filter itself suppresses local player + bool m_bUsingPredictionRules; + // If ignoring prediction cull, then external systems can determine + // whether this is a special case where culling should not occur + bool m_bIgnorePredictionCull; +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for a single player +//----------------------------------------------------------------------------- +class CSingleUserRecipientFilter : public C_RecipientFilter +{ +public: + CSingleUserRecipientFilter( C_BasePlayer *player ) + { + AddRecipient( player ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for all players, unreliable +//----------------------------------------------------------------------------- +class CBroadcastRecipientFilter : public C_RecipientFilter +{ +public: + CBroadcastRecipientFilter( void ) + { + AddAllPlayers(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for all players, reliable +//----------------------------------------------------------------------------- +class CReliableBroadcastRecipientFilter : public CBroadcastRecipientFilter +{ +public: + CReliableBroadcastRecipientFilter( void ) + { + MakeReliable(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for a single player +//----------------------------------------------------------------------------- +class CPASFilter : public C_RecipientFilter +{ +public: + CPASFilter( const Vector& origin ) + { + AddRecipientsByPAS( origin ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPASAttenuationFilter : public CPASFilter +{ +public: + CPASAttenuationFilter( C_BaseEntity *entity, float attenuation = ATTN_NORM ) : + CPASFilter( entity->GetAbsOrigin() ) + { + } + + CPASAttenuationFilter( const Vector& origin, float attenuation = ATTN_NORM ) : + CPASFilter( origin ) + { + } + + CPASAttenuationFilter( C_BaseEntity *entity, const char *lookupSound ) : + CPASFilter( entity->GetAbsOrigin() ) + { + } + + CPASAttenuationFilter( const Vector& origin, const char *lookupSound ) : + CPASFilter( origin ) + { + } + + CPASAttenuationFilter( C_BaseEntity *entity, const char *lookupSound, HSOUNDSCRIPTHANDLE& handle ) : + CPASFilter( entity->GetAbsOrigin() ) + { + } + + CPASAttenuationFilter( const Vector& origin, const char *lookupSound, HSOUNDSCRIPTHANDLE& handle ) : + CPASFilter( origin ) + { + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for a single player +//----------------------------------------------------------------------------- +class CPVSFilter : public C_RecipientFilter +{ +public: + CPVSFilter( const Vector& origin ) + { + AddRecipientsByPVS( origin ); + } +}; + +class CLocalPlayerFilter : public C_RecipientFilter +{ +public: + CLocalPlayerFilter( void ); +}; + +class CUIFilter : public C_RecipientFilter +{ +public: + CUIFilter( void ) + { + m_Recipients.AddToTail( 1 ); +// AddRecipient( 0 ); + } +}; + + +#endif // C_RECIPIENTFILTER_H diff --git a/game/client/c_rope.h b/game/client/c_rope.h new file mode 100644 index 0000000..f04372f --- /dev/null +++ b/game/client/c_rope.h @@ -0,0 +1,261 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ROPE_H +#define C_ROPE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "rope_physics.h" +#include "materialsystem/imaterial.h" +#include "rope_shared.h" +#include "bitvec.h" + + +class KeyValues; +class C_BaseAnimating; +struct RopeSegData_t; + +#define MAX_ROPE_SUBDIVS 8 +#define MAX_ROPE_SEGMENTS (ROPE_MAX_SEGMENTS+(ROPE_MAX_SEGMENTS-1)*MAX_ROPE_SUBDIVS) + +//============================================================================= +class C_RopeKeyframe : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_RopeKeyframe, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + +private: + + class CPhysicsDelegate : public CSimplePhysics::IHelper + { + public: + virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ); + virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ); + + C_RopeKeyframe *m_pKeyframe; + }; + + friend class CPhysicsDelegate; + + +public: + + C_RopeKeyframe(); + ~C_RopeKeyframe(); + + // This can be used for client-only ropes. + static C_RopeKeyframe* Create( + C_BaseEntity *pStartEnt, + C_BaseEntity *pEndEnt, + int iStartAttachment=0, + int iEndAttachment=0, + float ropeWidth = 2, + const char *pMaterialName = "cable/cable", // Note: whoever creates the rope must + // use PrecacheModel for whatever material + // it specifies here. + int numSegments = 5, + int ropeFlags = ROPE_SIMULATE + ); + + // Create a client-only rope and initialize it with the parameters from the KeyValues. + static C_RopeKeyframe* CreateFromKeyValues( C_BaseAnimating *pEnt, KeyValues *pValues ); + + // Find ropes (with both endpoints connected) that intersect this AABB. This is just an approximation. + static int GetRopesIntersectingAABB( C_RopeKeyframe **pRopes, int nMaxRopes, const Vector &vAbsMin, const Vector &vAbsMax ); + + // Set the slack. + void SetSlack( int slack ); + + void SetRopeFlags( int flags ); + int GetRopeFlags() const; + + void SetupHangDistance( float flHangDist ); + + // Change which entities the rope is connected to. + void SetStartEntity( C_BaseEntity *pEnt ); + void SetEndEntity( C_BaseEntity *pEnt ); + + C_BaseEntity* GetStartEntity() const; + C_BaseEntity* GetEndEntity() const; + + // Hook the physics. Pass in your own implementation of CSimplePhysics::IHelper. The + // default implementation is returned so you can call through to it if you want. + CSimplePhysics::IHelper* HookPhysics( CSimplePhysics::IHelper *pHook ); + + // Attach to things (you can also just lock the endpoints down yourself if you hook the physics). + + // Client-only right now. This could be moved to the server if there was a good reason. + void SetColorMod( const Vector &vColorMod ); + + // Use this when rope length and slack change to recompute the spring length. + void RecomputeSprings(); + + void ShakeRope( const Vector &vCenter, float flRadius, float flMagnitude ); + + // Get the attachment position of one of the endpoints. + bool GetEndPointPos( int iPt, Vector &vPos ); + + // Get the rope material data. + IMaterial *GetSolidMaterial( void ); + IMaterial *GetBackMaterial( void ); + + struct BuildRopeQueuedData_t + { + Vector *m_pPredictedPositions; + Vector *m_pLightValues; + int m_iNodeCount; + Vector m_vColorMod; + float m_RopeLength; + float m_Slack; + }; + + void BuildRope( RopeSegData_t *pRopeSegment, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, BuildRopeQueuedData_t *pQueuedData, bool bQueued ); + +// C_BaseEntity overrides. +public: + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink(); + virtual int DrawModel( int flags ); + virtual bool ShouldDraw(); + virtual const Vector& WorldSpaceCenter() const; + + // Specify ROPE_ATTACHMENT_START_POINT or ROPE_ATTACHMENT_END_POINT for the attachment. + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); + virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachment( int number, Vector &origin ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); + +private: + + void FinishInit( const char *pMaterialName ); + + void RunRopeSimulation( float flSeconds ); + Vector ConstrainNode( const Vector &vNormal, const Vector &vNodePosition, const Vector &vMidpiont, float fNormalLength ); + void ConstrainNodesBetweenEndpoints( void ); + + bool AnyPointsMoved(); + + bool DidEndPointMove( int iPt ); + bool DetectRestingState( bool &bApplyWind ); + + void UpdateBBox(); + bool InitRopePhysics(); + + bool GetEndPointAttachment( int iPt, Vector &vPos, QAngle &angle ); + + Vector *GetRopeSubdivVectors( int *nSubdivs ); + void CalcLightValues(); + + void ReceiveMessage( int classID, bf_read &msg ); + bool CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle *pAngles ); + + +private: + // Track which links touched something last frame. Used to prevent wind from gusting on them. + CBitVec m_LinksTouchingSomething; + int m_nLinksTouchingSomething; + bool m_bApplyWind; + int m_fPrevLockedPoints; // Which points are locked down. + int m_iForcePointMoveCounter; + + // Used to control resting state. + bool m_bPrevEndPointPos[2]; + Vector m_vPrevEndPointPos[2]; + + float m_flCurScroll; // for scrolling texture. + float m_flScrollSpeed; + + int m_RopeFlags; // Combo of ROPE_ flags. + int m_iRopeMaterialModelIndex; // Index of sprite model with the rope's material. + + CRopePhysics m_RopePhysics; + Vector m_LightValues[ROPE_MAX_SEGMENTS]; // light info when the rope is created. + + int m_nSegments; // Number of segments. + + EHANDLE m_hStartPoint; // StartPoint/EndPoint are entities + EHANDLE m_hEndPoint; + short m_iStartAttachment; // StartAttachment/EndAttachment are attachment points. + short m_iEndAttachment; + + unsigned char m_Subdiv; // Number of subdivions in between segments. + + int m_RopeLength; // Length of the rope, used for tension. + int m_Slack; // Extra length the rope is given. + float m_TextureScale; // pixels per inch + + int m_fLockedPoints; // Which points are locked down. + + float m_Width; + + CPhysicsDelegate m_PhysicsDelegate; + + IMaterial *m_pMaterial; + IMaterial *m_pBackMaterial; // Optional translucent background material for the rope to help reduce aliasing. + + int m_TextureHeight; // Texture height, for texture scale calculations. + + // Instantaneous force + Vector m_flImpulse; + Vector m_flPreviousImpulse; + + // Simulated wind gusts. + float m_flCurrentGustTimer; + float m_flCurrentGustLifetime; // How long will the current gust last? + + float m_flTimeToNextGust; // When will the next wind gust be? + Vector m_vWindDir; // What direction does the current gust go in? + + Vector m_vColorMod; // Color modulation on all verts? + + Vector m_vCachedEndPointAttachmentPos[2]; + QAngle m_vCachedEndPointAttachmentAngle[2]; + + // In network table, can't bit-compress + bool m_bConstrainBetweenEndpoints; // Simulated segment points won't stretch beyond the endpoints + + bool m_bEndPointAttachmentPositionsDirty : 1; + bool m_bEndPointAttachmentAnglesDirty : 1; + bool m_bNewDataThisFrame : 1; // Set to true in OnDataChanged so that we simulate that frame + bool m_bPhysicsInitted : 1; // It waits until all required entities are + // present to start simulating and rendering. + + friend class CRopeManager; +}; + + +// Profiling info. +void Rope_ResetCounters(); +//void Rope_ShowRSpeeds(); + +//============================================================================= +// +// Rope Manager +// +abstract_class IRopeManager +{ +public: + virtual ~IRopeManager() {} + virtual void ResetRenderCache( void ) = 0; + virtual void AddToRenderCache( C_RopeKeyframe *pRope ) = 0; + virtual void DrawRenderCache( bool bShadowDepth ) = 0; + virtual void OnRenderStart( void ) = 0; + virtual void SetHolidayLightMode( bool bHoliday ) = 0; + virtual bool IsHolidayLightMode( void ) = 0; + virtual int GetHolidayLightStyle( void ) = 0; +}; + +IRopeManager *RopeManager(); + +#endif // C_ROPE_H diff --git a/game/client/c_rumble.h b/game/client/c_rumble.h new file mode 100644 index 0000000..3772bfb --- /dev/null +++ b/game/client/c_rumble.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Rumble effects mixer for XBox +// +// $NoKeywords: $ +// +//=============================================================================// +#pragma once +#ifndef C_RUMBLE_H +#define C_RUMBLE_H + +extern void RumbleEffect( unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ); +extern void UpdateRumbleEffects(); +extern void UpdateScreenShakeRumble( float shake, float balance = 0 ); +extern void EnableRumbleOutput( bool bEnable ); + +#endif//C_RUMBLE_H + diff --git a/game/client/c_sceneentity.h b/game/client/c_sceneentity.h new file mode 100644 index 0000000..28efcd1 --- /dev/null +++ b/game/client/c_sceneentity.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SCENEENTITY_H +#define C_SCENEENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ichoreoeventcallback.h" +#include "choreoscene.h" + +class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback +{ + friend class CChoreoEventCallback; + +public: + DECLARE_CLASS( C_SceneEntity, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_SceneEntity( void ); + ~C_SceneEntity( void ); + + // From IChoreoEventCallback + virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + virtual void EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + virtual void ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + virtual bool CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + + virtual void StopClientOnlyScene(); + virtual void SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *pOwner = NULL , bool bMultiplayer = false ); + + virtual void ClientThink(); + + void OnResetClientTime(); + + CHandle< C_BaseFlex > GetActor( int i ){ return ( i < m_hActorList.Count() ) ? m_hActorList[i] : NULL; } + + virtual void DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel ); + virtual void DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + + bool IsClientOnly( void ){ return m_bClientOnly; } + +private: + + void ResetActorFlexesForScene(); + + // Scene load/unload + CChoreoScene *LoadScene( const char *filename ); + void LoadSceneFromFile( const char *filename ); + void UnloadScene( void ); + void PrefetchAnimBlocks( CChoreoScene *pScene ); + + C_BaseFlex *FindNamedActor( CChoreoActor *pChoreoActor ); + + virtual void DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchStartSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchProcessSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + void DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event ); + + char const *GetSceneFileName(); + + void DoThink( float frametime ); + + void ClearSceneEvents( CChoreoScene *scene, bool canceled ); + void SetCurrentTime( float t, bool forceClientSync ); + + bool GetHWMorphSceneFileName( const char *pFilename, char *pHWMFilename ); + +private: + + void CheckQueuedEvents(); + void WipeQueuedEvents(); + void QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event ); + + bool m_bIsPlayingBack; + bool m_bPaused; + bool m_bMultiplayer; + float m_flCurrentTime; + float m_flForceClientTime; + int m_nSceneStringIndex; + bool m_bClientOnly; + + CHandle< C_BaseFlex > m_hOwner; // if set, this overrides the m_hActorList in FindNamedActor() + + CUtlVector< CHandle< C_BaseFlex > > m_hActorList; + +private: + bool m_bWasPlaying; + + CChoreoScene *m_pScene; + + struct QueuedEvents_t + { + float starttime; + CChoreoScene *scene; + CChoreoEvent *event; + }; + + CUtlVector< QueuedEvents_t > m_QueuedEvents; +}; + +//----------------------------------------------------------------------------- +// Binary compiled VCDs get their strings from a pool +//----------------------------------------------------------------------------- +class CChoreoStringPool : public IChoreoStringPool +{ +public: + short FindOrAddString( const char *pString ) + { + // huh?, no compilation at run time, only fetches + Assert( 0 ); + return -1; + } + + bool GetString( short stringId, char *buff, int buffSize ); +}; + +#endif // C_SCENEENTITY_H diff --git a/game/client/c_slideshow_display.h b/game/client/c_slideshow_display.h new file mode 100644 index 0000000..0a88d57 --- /dev/null +++ b/game/client/c_slideshow_display.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef C_SLIDESHOW_DISPLAY_H +#define C_SLIDESHOW_DISPLAY_H + +#include "cbase.h" +#include "utlvector.h" + + +struct SlideMaterialList_t +{ + char szSlideKeyword[64]; + CUtlVector iSlideMaterials; + CUtlVector iSlideIndex; +}; + + +class C_SlideshowDisplay : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_SlideshowDisplay, CBaseEntity ); + DECLARE_CLIENTCLASS(); + + C_SlideshowDisplay(); + virtual ~C_SlideshowDisplay(); + + void Spawn( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void ClientThink( void ); + + bool IsEnabled( void ) { return m_bEnabled; } + + void GetDisplayText( char *pchText ) { Q_strcpy( pchText, m_szDisplayText ); } + int CurrentMaterialIndex( void ) { return m_iCurrentMaterialIndex; } + int GetMaterialIndex( int iSlideIndex ); + int NumMaterials( void ); + int CurrentSlideIndex( void ) { return m_iCurrentSlideIndex; } + +private: + + void BuildSlideShowImagesList( void ); + +private: + + bool m_bEnabled; + + char m_szDisplayText[ 128 ]; + + char m_szSlideshowDirectory[ 128 ]; + + CUtlVector m_SlideMaterialLists; + unsigned char m_chCurrentSlideLists[ 16 ]; + int m_iCurrentMaterialIndex; + int m_iCurrentSlideIndex; + + float m_fMinSlideTime; + float m_fMaxSlideTime; + + float m_NextSlideTime; + + int m_iCycleType; + bool m_bNoListRepeats; + int m_iCurrentSlideList; + int m_iCurrentSlide; +}; + +extern CUtlVector< C_SlideshowDisplay* > g_SlideshowDisplays; + +#endif //C_SLIDESHOW_STATS_DISPLAY_H \ No newline at end of file diff --git a/game/client/c_smoke_trail.h b/game/client/c_smoke_trail.h new file mode 100644 index 0000000..501ab73 --- /dev/null +++ b/game/client/c_smoke_trail.h @@ -0,0 +1,390 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +// This defines the client-side SmokeTrail entity. It can also be used without +// an entity, in which case you must pass calls to it and set its position each frame. + +#ifndef PARTICLE_SMOKETRAIL_H +#define PARTICLE_SMOKETRAIL_H + +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "particles_simple.h" +#include "c_baseentity.h" +#include "baseparticleentity.h" + +#include "fx_trail.h" + +// +// Smoke Trail +// + +class C_SmokeTrail : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_SmokeTrail, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_SmokeTrail(); + virtual ~C_SmokeTrail(); + +public: + + //For attachments + void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + // Enable/disable emission. + void SetEmit(bool bEmit); + + // Change the spawn rate. + void SetSpawnRate(float rate); + + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + + virtual void CleanupToolRecordingState( KeyValues *msg ); + +// IPrototypeAppEffect. +public: + virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs); + +// IParticleEffect. +public: + virtual void Update(float fTimeDelta); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + +public: + // Effect parameters. These will assume default values but you can change them. + float m_SpawnRate; // How many particles per second. + + Vector m_StartColor; // Fade between these colors. + Vector m_EndColor; + float m_Opacity; + + float m_ParticleLifetime; // How long do the particles live? + float m_StopEmitTime; // When do I stop emitting particles? (-1 = never) + + float m_MinSpeed; // Speed range. + float m_MaxSpeed; + + float m_MinDirectedSpeed; // Directed speed range. + float m_MaxDirectedSpeed; + + float m_StartSize; // Size ramp. + float m_EndSize; + + float m_SpawnRadius; + + Vector m_VelocityOffset; // Emit the particles in a certain direction. + + bool m_bEmit; // Keep emitting particles? + + int m_nAttachment; + +private: + C_SmokeTrail( const C_SmokeTrail & ); + + PMaterialHandle m_MaterialHandle[2]; + TimedEvent m_ParticleSpawn; + + CParticleMgr *m_pParticleMgr; + CSmartPtr m_pSmokeEmitter; +}; + +//================================================== +// C_RocketTrail +//================================================== + +class C_RocketTrail : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_RocketTrail, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_RocketTrail(); + virtual ~C_RocketTrail(); + +public: + + //For attachments + void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + // Enable/disable emission. + void SetEmit(bool bEmit); + + // Change the spawn rate. + void SetSpawnRate(float rate); + + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + +// IPrototypeAppEffect. +public: + virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs); + +// IParticleEffect. +public: + virtual void Update(float fTimeDelta); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + +public: + // Effect parameters. These will assume default values but you can change them. + float m_SpawnRate; // How many particles per second. + + Vector m_StartColor; // Fade between these colors. + Vector m_EndColor; + float m_Opacity; + + float m_ParticleLifetime; // How long do the particles live? + float m_StopEmitTime; // When do I stop emitting particles? (-1 = never) + + float m_MinSpeed; // Speed range. + float m_MaxSpeed; + + float m_StartSize; // Size ramp. + float m_EndSize; + + float m_SpawnRadius; + + Vector m_VelocityOffset; // Emit the particles in a certain direction. + + bool m_bEmit; // Keep emitting particles? + bool m_bDamaged; // Has been shot down (should be on fire, etc) + + int m_nAttachment; + + Vector m_vecLastPosition; // Last known position of the rocket + float m_flFlareScale; // Size of the flare + +private: + C_RocketTrail( const C_RocketTrail & ); + + PMaterialHandle m_MaterialHandle[2]; + TimedEvent m_ParticleSpawn; + + CParticleMgr *m_pParticleMgr; + CSmartPtr m_pRocketEmitter; +}; + +class SporeSmokeEffect; + + +//================================================== +// SporeEffect +//================================================== + +class SporeEffect : public CSimpleEmitter +{ +public: + SporeEffect( const char *pDebugName ); + static SporeEffect* Create( const char *pDebugName ); + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + virtual Vector UpdateColor( const SimpleParticle *pParticle ); + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + +private: + SporeEffect( const SporeEffect & ); +}; + +//================================================== +// C_SporeExplosion +//================================================== + +class C_SporeExplosion : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_SporeExplosion, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_SporeExplosion( void ); + virtual ~C_SporeExplosion( void ); + +public: + +// C_BaseEntity +public: + virtual void OnDataChanged( DataUpdateType_t updateType ); + +// IPrototypeAppEffect +public: + virtual void Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs ); + +// IParticleEffect +public: + virtual void Update( float fTimeDelta ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + +public: + float m_flSpawnRate; + float m_flParticleLifetime; + float m_flStartSize; + float m_flEndSize; + float m_flSpawnRadius; + float m_flPreviousSpawnRate; + + bool m_bEmit; + bool m_bDontRemove; + +private: + C_SporeExplosion( const C_SporeExplosion & ); + + void AddParticles( void ); + + PMaterialHandle m_hMaterial; + TimedEvent m_teParticleSpawn; + + SporeEffect *m_pSporeEffect; + CParticleMgr *m_pParticleMgr; +}; + +// +// Particle trail +// + +class CSmokeParticle; + +class C_FireTrail : public C_ParticleTrail +{ +public: + DECLARE_CLASS( C_FireTrail, C_ParticleTrail ); + DECLARE_CLIENTCLASS(); + + C_FireTrail( void ); + virtual ~C_FireTrail( void ); + + virtual void Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs ); + virtual void Update( float fTimeDelta ); + +private: + + enum + { + // Smoke + FTRAIL_SMOKE1, + FTRAIL_SMOKE2, + + // Large flame + FTRAIL_FLAME1, + FTRAIL_FLAME2, + FTRAIL_FLAME3, + FTRAIL_FLAME4, + FTRAIL_FLAME5, + + NUM_FTRAIL_MATERIALS + }; + + CSmartPtr m_pTrailEmitter; + CSmartPtr m_pSmokeEmitter; + + PMaterialHandle m_hMaterial[NUM_FTRAIL_MATERIALS]; + + Vector m_vecLastPosition; + + C_FireTrail( const C_FireTrail & ); +}; + + + + + + + + + + + + + +//================================================== +// C_DustTrail +//================================================== + +class C_DustTrail : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_DustTrail, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_DustTrail(); + virtual ~C_DustTrail(); + +public: + + // Enable/disable emission. + void SetEmit(bool bEmit); + + // Change the spawn rate. + void SetSpawnRate(float rate); + + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + + virtual void CleanupToolRecordingState( KeyValues *msg ); + +// IPrototypeAppEffect. +public: + virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs); + +// IParticleEffect. +public: + virtual void Update(float fTimeDelta); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + +public: + // Effect parameters. These will assume default values but you can change them. + float m_SpawnRate; // How many particles per second. + + Vector m_Color; + float m_Opacity; + + float m_ParticleLifetime; // How long do the particles live? + float m_StartEmitTime; // When did I start emitting particles? + float m_StopEmitTime; // When do I stop emitting particles? (-1 = never) + + float m_MinSpeed; // Speed range. + float m_MaxSpeed; + + float m_MinDirectedSpeed; // Directed speed range. + float m_MaxDirectedSpeed; + + float m_StartSize; // Size ramp. + float m_EndSize; + + float m_SpawnRadius; + + Vector m_VelocityOffset; // Emit the particles in a certain direction. + + bool m_bEmit; // Keep emitting particles? + +private: + C_DustTrail( const C_DustTrail & ); + +#define DUSTTRAIL_MATERIALS 16 + PMaterialHandle m_MaterialHandle[DUSTTRAIL_MATERIALS]; + TimedEvent m_ParticleSpawn; + + CParticleMgr *m_pParticleMgr; + CSmartPtr m_pDustEmitter; +}; + +#endif diff --git a/game/client/c_soundscape.h b/game/client/c_soundscape.h new file mode 100644 index 0000000..8c5f45e --- /dev/null +++ b/game/client/c_soundscape.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SOUNDSCAPE_H +#define C_SOUNDSCAPE_H +#ifdef _WIN32 +#pragma once +#endif + + +class IGameSystem; +struct audioparams_t; + +extern IGameSystem *ClientSoundscapeSystem(); + +// call when audio params may have changed +extern void Soundscape_Update( audioparams_t &audio ); + +// Called on round restart, otherwise the soundscape system thinks all its +// sounds are still playing when they're not. +void Soundscape_OnStopAllSounds(); + +#endif // C_SOUNDSCAPE_H diff --git a/game/client/c_sprite.h b/game/client/c_sprite.h new file mode 100644 index 0000000..d367eae --- /dev/null +++ b/game/client/c_sprite.h @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_SPRITE_H ) +#define C_SPRITE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "Sprite.h" +#include "c_pixel_visibility.h" + +#endif // C_SPRITE_H diff --git a/game/client/c_sun.h b/game/client/c_sun.h new file mode 100644 index 0000000..5f15e35 --- /dev/null +++ b/game/client/c_sun.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SUN_H +#define C_SUN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "utllinkedlist.h" +#include "glow_overlay.h" +#include "sun_shared.h" + +// +// Special glow overlay +// + +class C_SunGlowOverlay : public CGlowOverlay +{ + virtual void CalcSpriteColorAndSize( float flDot, CGlowSprite *pSprite, float *flHorzSize, float *flVertSize, Vector *vColor ) + { + if ( m_bModulateByDot ) + { + float alpha = RemapVal( flDot, 1.0f, 0.9f, 0.75f, 0.0f ); + alpha = clamp( alpha, 0.0f, 0.75f ); + + *flHorzSize = pSprite->m_flHorzSize * 6.0f; + *flVertSize = pSprite->m_flVertSize * 6.0f; + *vColor = pSprite->m_vColor * alpha * m_flGlowObstructionScale; + } + else + { + *flHorzSize = pSprite->m_flHorzSize; + *flVertSize = pSprite->m_flVertSize; + *vColor = pSprite->m_vColor * m_flGlowObstructionScale; + } + } + +public: + + void SetModulateByDot( bool state = true ) + { + m_bModulateByDot = state; + } + +protected: + + bool m_bModulateByDot; +}; + +// +// Sun entity +// + +class C_Sun : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_Sun, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_Sun(); + ~C_Sun(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + +public: + C_SunGlowOverlay m_Overlay; + C_SunGlowOverlay m_GlowOverlay; + + color32 m_clrOverlay; + int m_nSize; + int m_nOverlaySize; + Vector m_vDirection; + bool m_bOn; + + int m_nMaterial; + int m_nOverlayMaterial; +}; + + +#endif // C_SUN_H diff --git a/game/client/c_te_basebeam.h b/game/client/c_te_basebeam.h new file mode 100644 index 0000000..1fd17b2 --- /dev/null +++ b/game/client/c_te_basebeam.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_TE_BASEBEAM_H ) +#define C_TE_BASEBEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_basetempentity.h" + +//----------------------------------------------------------------------------- +// Purpose: Base entity for beam te's +//----------------------------------------------------------------------------- +class C_TEBaseBeam : public C_BaseTempEntity +{ +public: + DECLARE_CLASS( C_TEBaseBeam, C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + +private: + +public: + + C_TEBaseBeam( void ); + virtual ~C_TEBaseBeam( void ); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + +public: + int m_nModelIndex; + int m_nHaloIndex; + int m_nStartFrame; + int m_nFrameRate; + float m_fLife; + float m_fWidth; + float m_fEndWidth; + int m_nFadeLength; + float m_fAmplitude; + int r, g, b, a; + int m_nSpeed; + int m_nFlags; +}; + +EXTERN_RECV_TABLE(DT_BaseBeam); + +#endif // C_TE_BASEBEAM_H \ No newline at end of file diff --git a/game/client/c_te_effect_dispatch.h b/game/client/c_te_effect_dispatch.h new file mode 100644 index 0000000..63fa617 --- /dev/null +++ b/game/client/c_te_effect_dispatch.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TE_EFFECT_DISPATCH_H +#define C_TE_EFFECT_DISPATCH_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "effect_dispatch_data.h" + + +typedef void (*ClientEffectCallback)( const CEffectData &data ); + + +class CClientEffectRegistration +{ +public: + CClientEffectRegistration( const char *pEffectName, ClientEffectCallback fn ); + +public: + const char *m_pEffectName; + ClientEffectCallback m_pFunction; + CClientEffectRegistration *m_pNext; + + static CClientEffectRegistration *s_pHead; +}; + + +// +// Use this macro to register a client effect callback. +// If you do DECLARE_CLIENT_EFFECT( "MyEffectName", MyCallback ), then MyCallback will be +// called when the server does DispatchEffect( "MyEffect", data ) +// +#define DECLARE_CLIENT_EFFECT( effectName, callbackFunction ) \ + static CClientEffectRegistration ClientEffectReg_##callbackFunction( effectName, callbackFunction ); + +void DispatchEffectToCallback( const char *pEffectName, const CEffectData &m_EffectData ); +void DispatchEffect( const char *pName, const CEffectData &data ); + +#endif // C_TE_EFFECT_DISPATCH_H diff --git a/game/client/c_te_legacytempents.h b/game/client/c_te_legacytempents.h new file mode 100644 index 0000000..038eecc --- /dev/null +++ b/game/client/c_te_legacytempents.h @@ -0,0 +1,221 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_TE_LEGACYTEMPENTS_H ) +#define C_TE_LEGACYTEMPENTS_H +#ifdef _WIN32 +#pragma once +#endif + +class C_BaseEntity; +class C_LocalTempEntity; +struct model_t; + +#include "mempool.h" +#include "utllinkedlist.h" + +#if defined( CSTRIKE_DLL ) || defined( SDK_DLL ) +enum +{ + CS_SHELL_9MM = 0, + CS_SHELL_57, + CS_SHELL_12GAUGE, + CS_SHELL_556, + CS_SHELL_762NATO, + CS_SHELL_338MAG +}; +#endif + +//----------------------------------------------------------------------------- +// Purpose: Interface for lecacy temp entities +//----------------------------------------------------------------------------- +abstract_class ITempEnts +{ +public: + virtual ~ITempEnts() {} + + virtual void Init( void ) = 0; + virtual void Shutdown( void ) = 0; + virtual void LevelInit() = 0; + virtual void LevelShutdown() = 0; + + virtual void Update( void ) = 0; + virtual void Clear( void ) = 0; + + virtual C_LocalTempEntity *FindTempEntByID( int nID, int nSubID ) = 0; + + virtual void BloodSprite( const Vector &org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size ) = 0; + virtual void RicochetSprite( const Vector &pos, model_t *pmodel, float duration, float scale ) = 0; + virtual void MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson ) = 0; + virtual void MuzzleFlash( const Vector &pos1, const QAngle &angles, int type, ClientEntityHandle_t hEntity, bool firstPerson ) = 0; + virtual void EjectBrass( const Vector& pos1, const QAngle& angles, const QAngle& gunAngles, int type ) = 0; + virtual C_LocalTempEntity *SpawnTempModel( const model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ) = 0; + virtual void BreakModel( const Vector &pos, const QAngle &angles, const Vector &size, const Vector &dir, float random, float life, int count, int modelIndex, char flags) = 0; + virtual void Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed ) = 0; + virtual void BubbleTrail( const Vector &start, const Vector &end, float flWaterZ, int modelIndex, int count, float speed ) = 0; + virtual void Sprite_Explode( C_LocalTempEntity *pTemp, float scale, int flags ) = 0; + virtual void FizzEffect( C_BaseEntity *pent, int modelIndex, int density, int current ) = 0; + virtual C_LocalTempEntity *DefaultSprite( const Vector &pos, int spriteIndex, float framerate ) = 0; + virtual void Sprite_Smoke( C_LocalTempEntity *pTemp, float scale ) = 0; + virtual C_LocalTempEntity *TempSprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags, const Vector &normal = vec3_origin ) = 0; + virtual void AttachTentToPlayer( int client, int modelIndex, float zoffset, float life ) = 0; + virtual void KillAttachedTents( int client ) = 0; + virtual void Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand ) = 0; + virtual void Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ) = 0; + virtual void RocketFlare( const Vector& pos ) = 0; + virtual void HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ) = 0; + virtual void CSEjectBrass( const Vector &vecPosition, const QAngle &angVelocity, int nType, int nShellType, CBasePlayer *pShooter ) = 0; + + virtual void PlaySound ( C_LocalTempEntity *pTemp, float damp ) = 0; + virtual void PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects = 0 ) = 0; + virtual C_LocalTempEntity *ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAccel, int modelindex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Default implementation of the temp entity interface +//----------------------------------------------------------------------------- +class CTempEnts : public ITempEnts +{ +// Construction +public: + CTempEnts( void ); + virtual ~CTempEnts( void ); +// Exposed interface +public: + virtual void Init( void ); + virtual void Shutdown( void ); + + virtual void LevelInit(); + + virtual void LevelShutdown(); + + virtual void Update( void ); + virtual void Clear( void ); + + virtual C_LocalTempEntity *FindTempEntByID( int nID, int nSubID ); + + // Legacy temp entities still supported + virtual void BloodSprite( const Vector &org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size ); + virtual void RicochetSprite( const Vector &pos, model_t *pmodel, float duration, float scale ); + + virtual void MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson ); + virtual void MuzzleFlash( const Vector &pos1, const QAngle &angles, int type, ClientEntityHandle_t hEntity, bool firstPerson = false ); + + virtual void BreakModel(const Vector &pos, const QAngle &angles, const Vector &size, const Vector &dir, float random, float life, int count, int modelIndex, char flags); + virtual void Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed ); + virtual void BubbleTrail( const Vector &start, const Vector &end, float height, int modelIndex, int count, float speed ); + virtual void Sprite_Explode( C_LocalTempEntity *pTemp, float scale, int flags ); + virtual void FizzEffect( C_BaseEntity *pent, int modelIndex, int density, int current ); + virtual C_LocalTempEntity *DefaultSprite( const Vector &pos, int spriteIndex, float framerate ); + virtual void Sprite_Smoke( C_LocalTempEntity *pTemp, float scale ); + virtual C_LocalTempEntity *TempSprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags, const Vector &normal = vec3_origin ); + virtual void AttachTentToPlayer( int client, int modelIndex, float zoffset, float life ); + virtual void KillAttachedTents( int client ); + virtual void Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand ); + void Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ); + + virtual void PlaySound ( C_LocalTempEntity *pTemp, float damp ); + virtual void EjectBrass( const Vector &pos1, const QAngle &angles, const QAngle &gunAngles, int type ); + virtual C_LocalTempEntity *SpawnTempModel( const model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ); + void RocketFlare( const Vector& pos ); + void HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ); + void CSEjectBrass( const Vector &vecPosition, const QAngle &angAngles, int nType, int nShellType, CBasePlayer *pShooter ); + void PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects = 0 ); + C_LocalTempEntity *ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelindex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ); + +// Data +public: + enum + { + MAX_TEMP_ENTITIES = 500, + MAX_TEMP_ENTITY_SPRITES = 200, + MAX_TEMP_ENTITY_STUDIOMODEL = 50, + }; + +private: + // Global temp entity pool + CClassMemoryPool< C_LocalTempEntity > m_TempEntsPool; + CUtlLinkedList< C_LocalTempEntity *, unsigned short > m_TempEnts; + + // Muzzle flash sprites + struct model_t *m_pSpriteMuzzleFlash[10]; + struct model_t *m_pSpriteAR2Flash[4]; + struct model_t *m_pShells[3]; + struct model_t *m_pSpriteCombineFlash[2]; + +#if defined( HL1_CLIENT_DLL ) + struct model_t *m_pHL1Shell; + struct model_t *m_pHL1ShotgunShell; +#endif + +#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL ) + struct model_t *m_pCS_9MMShell; + struct model_t *m_pCS_57Shell; + struct model_t *m_pCS_12GaugeShell; + struct model_t *m_pCS_556Shell; + struct model_t *m_pCS_762NATOShell; + struct model_t *m_pCS_338MAGShell; +#endif + +// Internal methods also available to children +protected: + C_LocalTempEntity *TempEntAlloc( const Vector& org, const model_t *model ); + C_LocalTempEntity *TempEntAllocHigh( const Vector& org, const model_t *model ); + +// Material handle caches +private: + + inline void CacheMuzzleFlashes( void ); + PMaterialHandle m_Material_MuzzleFlash_Player[4]; + PMaterialHandle m_Material_MuzzleFlash_NPC[4]; + PMaterialHandle m_Material_Combine_MuzzleFlash_Player[2]; + PMaterialHandle m_Material_Combine_MuzzleFlash_NPC[2]; + +// Internal methods +private: + CTempEnts( const CTempEnts & ); + + void TempEntFree( int index ); + C_LocalTempEntity *TempEntAlloc(); + bool FreeLowPriorityTempEnt(); + + int AddVisibleTempEntity( C_LocalTempEntity *pEntity ); + + // AR2 + void MuzzleFlash_AR2_Player( const Vector &origin, const QAngle &angles, ClientEntityHandle_t hEntity ); + void MuzzleFlash_AR2_NPC( const Vector &origin, const QAngle &angles, ClientEntityHandle_t hEntity ); + + // SMG1 + void MuzzleFlash_SMG1_Player( ClientEntityHandle_t hEntity, int attachmentIndex ); + void MuzzleFlash_SMG1_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ); + + // Shotgun + void MuzzleFlash_Shotgun_Player( ClientEntityHandle_t hEntity, int attachmentIndex ); + void MuzzleFlash_Shotgun_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ); + + // Pistol + void MuzzleFlash_Pistol_Player( ClientEntityHandle_t hEntity, int attachmentIndex ); + void MuzzleFlash_Pistol_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ); + + // Combine + void MuzzleFlash_Combine_Player( ClientEntityHandle_t hEntity, int attachmentIndex ); + void MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ); + + // 357 + void MuzzleFlash_357_Player( ClientEntityHandle_t hEntity, int attachmentIndex ); + + // RPG + void MuzzleFlash_RPG_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ); +}; + + +extern ITempEnts *tempents; + + +#endif // C_TE_LEGACYTEMPENTS_H diff --git a/game/client/c_te_particlesystem.h b/game/client/c_te_particlesystem.h new file mode 100644 index 0000000..7bd7b4b --- /dev/null +++ b/game/client/c_te_particlesystem.h @@ -0,0 +1,133 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// This file defines the C_TEParticleSystem class, which handles most of the +// interfacing with the particle manager, simulation, and rendering. + +// NOTE: most tempents are singletons. + +#ifndef C_TE_PARTICLESYSTEM_H +#define C_TE_PARTICLESYSTEM_H + + +#include "particlemgr.h" +#include "c_basetempentity.h" +#include "particles_simple.h" + + +#define SIMSHIFT 10 + + +typedef enum { + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_snow, + pt_rain, + pt_clientcustom // Must have callback function specified +} ptype_t; + + + +class C_TEParticleSystem : public C_BaseTempEntity +{ +public: + + DECLARE_CLASS( C_TEParticleSystem, C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + + C_TEParticleSystem(); + + +public: + + // particle effect sort origin + Vector m_vecOrigin; +}; + + +// This is the class that legacy tempents use to emit particles. +// They use it in this pattern: +// CTEParticleRenderer *pRen = CTEParticleRenderer::Create(); +// pRen->AddParticle.... +// pRen->Release(); + +class CTEParticleRenderer : public CParticleEffect +{ +public: + DECLARE_CLASS( CTEParticleRenderer, CParticleEffect ); + virtual ~CTEParticleRenderer(); + + // Create a CTEParticleRenderer. Pass in your sort origin (m_vecOrigin). + static CSmartPtr Create( const char *pDebugName, const Vector &vOrigin ); + + StandardParticle_t* AddParticle(); + + CParticleMgr* GetParticleMgr(); + + void SetParticleType( StandardParticle_t *pParticle, ptype_t type ); + ptype_t GetParticleType( StandardParticle_t *pParticle ); + + // Get/set lifetime. Note: lifetime here is a counter. You set it to a value and it + // counts down and disappears after that long. + void SetParticleLifetime( StandardParticle_t *pParticle, float lifetime ); + float GetParticleLifetime( StandardParticle_t *pParticle ); + + +// IParticleEffect overrides. +public: + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + +private: + CTEParticleRenderer( const char *pDebugName ); + CTEParticleRenderer( const CTEParticleRenderer & ); // not defined, not accessible + + int m_nActiveParticles; + float m_ParticleSize; + PMaterialHandle m_MaterialHandle; +}; + + + +// ------------------------------------------------------------------------ // +// Inlines. +// ------------------------------------------------------------------------ // +inline void CTEParticleRenderer::SetParticleType(StandardParticle_t *pParticle, ptype_t type) +{ + pParticle->m_EffectData = (unsigned char)type; +} + +inline ptype_t CTEParticleRenderer::GetParticleType(StandardParticle_t *pParticle) +{ + return (ptype_t)pParticle->m_EffectData; +} + +// Get/set lifetime. Note that +inline void CTEParticleRenderer::SetParticleLifetime(StandardParticle_t *pParticle, float lifetime) +{ + pParticle->m_Lifetime = lifetime; +} + +inline float CTEParticleRenderer::GetParticleLifetime(StandardParticle_t *pParticle) +{ + return pParticle->m_Lifetime; +} + + +#endif + + + diff --git a/game/client/c_team.h b/game/client/c_team.h new file mode 100644 index 0000000..5f26917 --- /dev/null +++ b/game/client/c_team.h @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side CTeam class +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_TEAM_H +#define C_TEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "utlvector.h" +#include "client_thinklist.h" + + +class C_BasePlayer; + +class C_Team : public C_BaseEntity +{ + DECLARE_CLASS( C_Team, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_Team(); + virtual ~C_Team(); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + + // Data Handling + virtual char *Get_Name( void ); + virtual int Get_Score( void ); + virtual int Get_Deaths( void ); + virtual int Get_Ping( void ); + + // Player Handling + virtual int Get_Number_Players( void ); + virtual bool ContainsPlayer( int iPlayerIndex ); + C_BasePlayer* GetPlayer( int idx ); + + // for shared code, use the same function name + virtual int GetNumPlayers( void ) { return Get_Number_Players(); } + + int GetTeamNumber() const; + + int GetRoundsWon(void) { return m_iRoundsWon; } + + void RemoveAllPlayers(); + + +// IClientThinkable overrides. +public: + + virtual void ClientThink(); + + +public: + + // Data received from the server + CUtlVector< int > m_aPlayers; + char m_szTeamname[ MAX_TEAM_NAME_LENGTH ]; + int m_iScore; + int m_iRoundsWon; + + // Data for the scoreboard + int m_iDeaths; + int m_iPing; + int m_iPacketloss; + int m_iTeamNum; +}; + + +// Global list of client side team entities +extern CUtlVector< C_Team * > g_Teams; + +// Global team handling functions +C_Team *GetLocalTeam( void ); +C_Team *GetGlobalTeam( int iTeamNumber ); +C_Team *GetPlayersTeam( int iPlayerIndex ); +C_Team *GetPlayersTeam( C_BasePlayer *pPlayer ); +bool ArePlayersOnSameTeam( int iPlayerIndex1, int iPlayerIndex2 ); +extern int GetNumberOfTeams( void ); + +#endif // C_TEAM_H diff --git a/game/client/c_team_objectiveresource.h b/game/client/c_team_objectiveresource.h new file mode 100644 index 0000000..9cc431e --- /dev/null +++ b/game/client/c_team_objectiveresource.h @@ -0,0 +1,347 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef C_TEAM_OBJECTIVERESOURCE_H +#define C_TEAM_OBJECTIVERESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "const.h" +#include "c_baseentity.h" +#include + +#define TEAM_ARRAY( index, team ) (index + (team * MAX_CONTROL_POINTS)) + +//----------------------------------------------------------------------------- +// Purpose: An entity that networks the state of the game's objectives. +// May contain data for objectives that aren't used by your mod, but +// the extra data will never be networked as long as it's zeroed out. +//----------------------------------------------------------------------------- +class C_BaseTeamObjectiveResource : public C_BaseEntity +{ + DECLARE_CLASS( C_BaseTeamObjectiveResource, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_BaseTeamObjectiveResource(); + virtual ~C_BaseTeamObjectiveResource(); + +public: + virtual void ClientThink(); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void UpdateControlPoint( const char *pszEvent, int index = -1 ); + float GetCPCapPercentage( int index ); + int GetNumControlPoints( void ) { return m_iNumControlPoints; } + int GetNumControlPointsOwned( void ); + void SetOwningTeam( int index, int team ); + virtual void SetCappingTeam( int index, int team ); + void SetCapLayout( const char *pszLayout ); + + // Is the point visible in the objective display + bool IsCPVisible( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_bCPIsVisible[index]; + } + + bool IsCPBlocked( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_bBlocked[index]; + } + + // Get the world location of this control point + Vector& GetCPPosition( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_vCPPositions[index]; + } + + int GetOwningTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iOwner[index]; + } + + int GetCappingTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iCappingTeam[index]; + } + + int GetTeamInZone( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iTeamInZone[index]; + } + + // Icons + int GetCPCurrentOwnerIcon( int index, int iOwner ) + { + Assert( index < m_iNumControlPoints ); + + return GetIconForTeam( index, iOwner ); + } + + int GetCPCappingIcon( int index ) + { + Assert( index < m_iNumControlPoints ); + + int iCapper = GetCappingTeam(index); + + Assert( iCapper != TEAM_UNASSIGNED ); + + return GetIconForTeam( index, iCapper ); + } + + // Icon for the specified team + int GetIconForTeam( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iTeamIcons[ TEAM_ARRAY(index,team) ]; + } + + // Overlay for the specified team + int GetOverlayForTeam( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iTeamOverlays[ TEAM_ARRAY(index,team) ]; + } + + // Number of players in the area + int GetNumPlayersInArea( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iNumTeamMembers[ TEAM_ARRAY(index,team) ]; + } + + // get the required cappers for the passed team + int GetRequiredCappers( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iTeamReqCappers[ TEAM_ARRAY(index,team) ]; + } + + // Base Icon for the specified team + int GetBaseIconForTeam( int team ) + { + Assert( team < MAX_TEAMS ); + return m_iTeamBaseIcons[ team ]; + } + + int GetBaseControlPointForTeam( int iTeam ) + { + Assert( iTeam < MAX_TEAMS ); + return m_iBaseControlPoints[iTeam]; + } + + int GetPreviousPointForPoint( int index, int team, int iPrevIndex ) + { + Assert( index < m_iNumControlPoints ); + Assert( iPrevIndex >= 0 && iPrevIndex < MAX_PREVIOUS_POINTS ); + int iIntIndex = iPrevIndex + (index * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS); + return m_iPreviousPoints[ iIntIndex ]; + } + + bool TeamCanCapPoint( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_bTeamCanCap[ TEAM_ARRAY( index, team ) ]; + } + + const char *GetCapLayoutInHUD( void ) { return m_pszCapLayoutInHUD; } + void GetCapLayoutCustomPosition( float& flCustomPositionX, float& flCustomPositionY ) { flCustomPositionX = m_flCustomPositionX; flCustomPositionY = m_flCustomPositionY; } + + bool PlayingMiniRounds( void ){ return m_bPlayingMiniRounds; } + bool IsInMiniRound( int index ) { return m_bInMiniRound[index]; } + + int GetCapWarningLevel( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_iWarnOnCap[index]; + } + + int GetCPGroup( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_iCPGroup[index]; + } + + const char *GetWarnSound( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_iszWarnSound[index]; + } + + virtual const char *GetGameSpecificCPCappingSwipe( int index, int iCappingTeam ) + { + // You need to implement this in your game's objective resource. + Assert(0); + return NULL; + } + virtual const char *GetGameSpecificCPBarFG( int index, int iOwningTeam ) + { + // You need to implement this in your game's objective resource. + Assert(0); + return NULL; + } + virtual const char *GetGameSpecificCPBarBG( int index, int iCappingTeam ) + { + // You need to implement this in your game's objective resource. + Assert(0); + return NULL; + } + + bool CapIsBlocked( int index ); + + int GetTimerToShowInHUD( void ) { return m_iTimerToShowInHUD; } + int GetStopWatchTimer( void ) { return m_iStopWatchTimer; } + + float GetPathDistance( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_flPathDistance[index]; + } + + bool GetCPLocked( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_bCPLocked[index]; + } + + bool GetTrackAlarm( int index ) + { + Assert( index < TEAM_TRAIN_MAX_TEAMS ); + return m_bTrackAlarm[index]; + } + + int GetNumNodeHillData( int team ){ return ( team < TEAM_TRAIN_MAX_TEAMS ) ? m_nNumNodeHillData[team] : 0; } + + void GetHillData( int team, int hill, float &flStart, float &flEnd ) + { + if ( hill < TEAM_TRAIN_MAX_HILLS && team < TEAM_TRAIN_MAX_TEAMS ) + { + int index = ( hill * TEAM_TRAIN_FLOATS_PER_HILL ) + ( team * TEAM_TRAIN_MAX_HILLS * TEAM_TRAIN_FLOATS_PER_HILL ); + if ( index < TEAM_TRAIN_HILLS_ARRAY_SIZE - 1 ) // - 1 because we want to look at 2 entries + { + flStart = m_flNodeHillData[index]; + flEnd = m_flNodeHillData[index+1]; + } + } + } + + void SetTrainOnHill( int team, int hill, bool state ) + { + if ( team < TEAM_TRAIN_MAX_TEAMS && hill < TEAM_TRAIN_MAX_HILLS ) + { + int index = hill + ( team * TEAM_TRAIN_MAX_HILLS ); + m_bTrainOnHill[index] = state; + } + } + + bool IsTrainOnHill( int team, int hill ) + { + if ( team < TEAM_TRAIN_MAX_TEAMS && hill < TEAM_TRAIN_MAX_HILLS ) + { + return m_bTrainOnHill[hill + ( team * TEAM_TRAIN_MAX_HILLS )]; + } + + return false; + } + + bool IsHillDownhill( int team, int hill ) + { + if ( team < TEAM_TRAIN_MAX_TEAMS && hill < TEAM_TRAIN_MAX_HILLS ) + { + return m_bHillIsDownhill[hill + ( team * TEAM_TRAIN_MAX_HILLS )]; + } + + return true; + } + +protected: + int m_iTimerToShowInHUD; + int m_iStopWatchTimer; + + int m_iNumControlPoints; + int m_iPrevNumControlPoints; + bool m_bPlayingMiniRounds; + bool m_bControlPointsReset; + bool m_bOldControlPointsReset; + int m_iUpdateCapHudParity; + int m_iOldUpdateCapHudParity; + + // data variables + Vector m_vCPPositions[MAX_CONTROL_POINTS]; + bool m_bCPIsVisible[MAX_CONTROL_POINTS]; + float m_flLazyCapPerc[MAX_CONTROL_POINTS]; + float m_flOldLazyCapPerc[MAX_CONTROL_POINTS]; + int m_iTeamIcons[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iTeamOverlays[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iTeamReqCappers[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + float m_flTeamCapTime[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iPreviousPoints[ MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS * MAX_PREVIOUS_POINTS ]; + bool m_bTeamCanCap[ MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ]; + int m_iTeamBaseIcons[MAX_TEAMS]; + int m_iBaseControlPoints[MAX_TEAMS]; + bool m_bInMiniRound[MAX_CONTROL_POINTS]; + int m_iWarnOnCap[MAX_CONTROL_POINTS]; + char m_iszWarnSound[MAX_CONTROL_POINTS][255]; + float m_flPathDistance[MAX_CONTROL_POINTS]; + int m_iCPGroup[MAX_CONTROL_POINTS]; + bool m_bCPLocked[MAX_CONTROL_POINTS]; + float m_flUnlockTimes[MAX_CONTROL_POINTS]; + float m_flOldUnlockTimes[MAX_CONTROL_POINTS]; + float m_flCPTimerTimes[MAX_CONTROL_POINTS]; + float m_flOldCPTimerTimes[MAX_CONTROL_POINTS]; + + // state variables + int m_iNumTeamMembers[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iCappingTeam[MAX_CONTROL_POINTS]; + int m_iTeamInZone[MAX_CONTROL_POINTS]; + bool m_bBlocked[MAX_CONTROL_POINTS]; + int m_iOwner[MAX_CONTROL_POINTS]; + bool m_bCPCapRateScalesWithPlayers[MAX_CONTROL_POINTS]; + + // client calculated state + float m_flCapTimeLeft[MAX_CONTROL_POINTS]; + float m_flCapLastThinkTime[MAX_CONTROL_POINTS]; + + bool m_bWarnedOnFinalCap[MAX_CONTROL_POINTS]; + float m_flLastCapWarningTime[MAX_CONTROL_POINTS]; + char m_pszCapLayoutInHUD[MAX_CAPLAYOUT_LENGTH]; + float m_flOldCustomPositionX; + float m_flOldCustomPositionY; + float m_flCustomPositionX; + float m_flCustomPositionY; + + // hill data for multi-escort payload maps + int m_nNumNodeHillData[TEAM_TRAIN_MAX_TEAMS]; + float m_flNodeHillData[TEAM_TRAIN_HILLS_ARRAY_SIZE]; + bool m_bTrainOnHill[TEAM_TRAIN_MAX_HILLS*TEAM_TRAIN_MAX_TEAMS]; + + bool m_bTrackAlarm[TEAM_TRAIN_MAX_TEAMS]; + bool m_bHillIsDownhill[TEAM_TRAIN_MAX_HILLS*TEAM_TRAIN_MAX_TEAMS]; +}; + +extern C_BaseTeamObjectiveResource *g_pObjectiveResource; + +inline C_BaseTeamObjectiveResource *ObjectiveResource() +{ + return g_pObjectiveResource; +} + +#endif // C_TEAM_OBJECTIVERESOURCE_H diff --git a/game/client/c_team_train_watcher.h b/game/client/c_team_train_watcher.h new file mode 100644 index 0000000..8887d22 --- /dev/null +++ b/game/client/c_team_train_watcher.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef C_TEAM_TRAIN_WATCHER_H +#define C_TEAM_TRAIN_WATCHER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "c_physicsprop.h" +#ifdef GLOWS_ENABLE +#include "glow_outline_effect.h" +#endif // GLOWS_ENABLE + +class C_TeamTrainWatcher : public C_BaseEntity +{ + DECLARE_CLASS( C_TeamTrainWatcher, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_TeamTrainWatcher(); + ~C_TeamTrainWatcher(); + + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + virtual void Spawn( void ); + virtual void UpdateOnRemove( void ); + + float GetTotalProgress( void ) { return m_flTotalProgress; } + int GetSpeedLevel( void ) { return m_iTrainSpeedLevel; } + + // IClientThinkable overrides. +public: + virtual void ClientThink(); + +#ifdef GLOWS_ENABLE +private: + void UpdateGlowEffect( void ); + void DestroyGlowEffect( void ); +#endif // GLOWS_ENABLE + +private: + + // === Networked Data === + + // percent distance to cp1, distance to cp2, etc + // adds up to 1.0 + //CNetworkArray( float, m_flDistances, MAX_CONTROL_POINTS ); + + // current total progress, percentage + CNetworkVar( float, m_flTotalProgress ); + float m_flOldProgress; + + CNetworkVar( int, m_iTrainSpeedLevel ); + int m_iOldTrainSpeedLevel; + + CNetworkVar( float, m_flRecedeTime ); + float m_flOldRecedeTime; + + CNetworkVar( int, m_nNumCappers ); + int m_nOldNumCappers; + +#ifdef GLOWS_ENABLE + EHANDLE m_hGlowEnt; + EHANDLE m_hOldGlowEnt; + CGlowObject *m_pGlowEffect; +#endif // GLOWS_ENABLE +}; + +extern CUtlVector< CHandle > g_hTrainWatchers; + +#endif //C_TEAM_TRAIN_WATCHER_H \ No newline at end of file diff --git a/game/client/c_tesla.h b/game/client/c_tesla.h new file mode 100644 index 0000000..5fce189 --- /dev/null +++ b/game/client/c_tesla.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_TESLA_H +#define C_TESLA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_baseentity.h" +#include "fx.h" +#include "utllinkedlist.h" + + +class C_Tesla : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_Tesla, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_Tesla(); + + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void ClientThink(); + + +public: + + CUtlLinkedList m_QueuedCommands; + char m_SoundName[64]; + char m_iszSpriteName[256]; +}; + + +#endif // C_TESLA_H diff --git a/game/client/c_tracer.h b/game/client/c_tracer.h new file mode 100644 index 0000000..bb9e13f --- /dev/null +++ b/game/client/c_tracer.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef C_TRACER_H +#define C_TRACER_H + +class Vector; +class ParticleDraw; +class CMeshBuilder; + +//----------------------------------------------------------------------------- +// Tracer_Draw(): draws a tracer, assuming the modelview matrix is identity +// This function accepts all arguments in CAMERA (pre-projected) space +// +// arguments +// [in] Vector& : The origin of the tracer (CAMERA space) +// [in] Vector& : The direction and length of the tracer (CAMERA space) +// [in] float : The tracer width (CAMERA space) +// [in] float* : r, g, b, a (0 - 1) +//----------------------------------------------------------------------------- +void Tracer_Draw( ParticleDraw* pDraw, Vector& start, Vector& delta, + float width, float* color, float startV = 0.0, float endV = 1.0 ); + +void Tracer_Draw( CMeshBuilder *pMeshBuilder, Vector& start, Vector& delta, float width, float* color, float startV = 0.0, float endV = 1.0 ); + + +//----------------------------------------------------------------------------- +// Computes the four verts to draw the tracer with, in the following order: +// start vertex left side, start vertex right side +// end vertex left side, end vertex right side +// returne false if the tracer is offscreen +//----------------------------------------------------------------------------- +bool Tracer_ComputeVerts( const Vector &start, const Vector &delta, float width, Vector *pVerts ); + +#endif // C_TRACER_H \ No newline at end of file diff --git a/game/client/c_user_message_register.h b/game/client/c_user_message_register.h new file mode 100644 index 0000000..bf4c4d6 --- /dev/null +++ b/game/client/c_user_message_register.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_USER_MESSAGE_REGISTER_H +#define C_USER_MESSAGE_REGISTER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "usermessages.h" + +// This provides an alternative to HOOK_MESSAGE, where you can declare it globally +// instead of finding a place to run it. +// It registers a function called __MsgFunc_ +#define USER_MESSAGE_REGISTER( msgName ) \ + static CUserMessageRegister userMessageRegister_##msgName( #msgName, __MsgFunc_##msgName ); + + +class CUserMessageRegister +{ +public: + CUserMessageRegister( const char *pMessageName, pfnUserMsgHook pHookFn ); + + // This is called at startup to register all the user messages. + static void RegisterAll(); + + +private: + const char *m_pMessageName; + pfnUserMsgHook m_pHookFn; + + // Linked list of all the CUserMessageRegisters. + static CUserMessageRegister *s_pHead; + CUserMessageRegister *m_pNext; +}; + + +#endif // C_USER_MESSAGE_REGISTER_H diff --git a/game/client/c_vehicle_jeep.h b/game/client/c_vehicle_jeep.h new file mode 100644 index 0000000..d7e53c1 --- /dev/null +++ b/game/client/c_vehicle_jeep.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#ifndef C_VEHICLE_JEEP_H +#define C_VEHICLE_JEEP_H +#pragma once + +#include "cbase.h" +#include "c_prop_vehicle.h" +//#include "movevars_shared.h" +//#include "view.h" +#include "flashlighteffect.h" +//#include "c_baseplayer.h" +//#include "c_te_effect_dispatch.h" + +// memdbgon must be the last include file in a .cpp file!!! +//#include "tier0/memdbgon.h" + +//============================================================================= +// +// Client-side Jeep Class +// +class C_PropJeep : public C_PropVehicleDriveable +{ + + DECLARE_CLASS( C_PropJeep, C_PropVehicleDriveable ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + + C_PropJeep(); + ~C_PropJeep(); + +public: + + void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); + + void OnEnteredVehicle( C_BasePlayer *pPlayer ); + void Simulate( void ); + +private: + + void DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ); + void DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ); + void ComputePDControllerCoefficients( float *pCoefficientsOut, float flFrequency, float flDampening, float flDeltaTime ); + +private: + + Vector m_vecLastEyePos; + Vector m_vecLastEyeTarget; + Vector m_vecEyeSpeed; + Vector m_vecTargetSpeed; + + float m_flViewAngleDeltaTime; + + float m_flJeepFOV; + CHeadlightEffect *m_pHeadlight; + bool m_bHeadlightIsOn; +}; + +#endif // C_VEHICLE_JEEP_H diff --git a/game/client/c_vguiscreen.h b/game/client/c_vguiscreen.h new file mode 100644 index 0000000..d304f5c --- /dev/null +++ b/game/client/c_vguiscreen.h @@ -0,0 +1,187 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_VGUISCREEN_H +#define C_VGUISCREEN_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "c_baseentity.h" +#include "panelmetaclassmgr.h" + +class KeyValues; + + +//----------------------------------------------------------------------------- +// Helper macro to make overlay factories one line of code. Use like this: +// DECLARE_VGUI_SCREEN_FACTORY( CVguiScreenPanel, "image" ); +//----------------------------------------------------------------------------- +struct VGuiScreenInitData_t +{ + C_BaseEntity *m_pEntity; + + VGuiScreenInitData_t() : m_pEntity(NULL) {} + VGuiScreenInitData_t( C_BaseEntity *pEntity ) : m_pEntity(pEntity) {} +}; + +#define DECLARE_VGUI_SCREEN_FACTORY( _PanelClass, _nameString ) \ + DECLARE_PANEL_FACTORY( _PanelClass, VGuiScreenInitData_t, _nameString ) + + +//----------------------------------------------------------------------------- +// Base class for vgui screen panels +//----------------------------------------------------------------------------- +class CVGuiScreenPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_GAMEROOT( CVGuiScreenPanel, vgui::EditablePanel ); + +public: + CVGuiScreenPanel( vgui::Panel *parent, const char *panelName ); + CVGuiScreenPanel( vgui::Panel *parent, const char *panelName, vgui::HScheme hScheme ); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + vgui::Panel *CreateControlByName(const char *controlName); + virtual void OnCommand( const char *command ); + +protected: + C_BaseEntity *GetEntity() const { return m_hEntity.Get(); } + +private: + EHANDLE m_hEntity; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VGuiScreen : public C_BaseEntity +{ + DECLARE_CLASS( C_VGuiScreen, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_VGuiScreen(); + ~C_VGuiScreen(); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t type ); + virtual int DrawModel( int flags ); + virtual bool ShouldDraw( void ); + virtual void ClientThink( ); + virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ); + virtual bool IsVisibleToPlayer( C_BasePlayer *pViewingPlayer ); + virtual bool IsTransparent( void ); + + const char *PanelName() const; + + // The view screen has the cursor pointing at it + void GainFocus( ); + void LoseFocus(); + + // Button state... + void SetButtonState( int nButtonState ); + + // Is the screen backfaced given a view position? + bool IsBackfacing( const Vector &viewOrigin ); + + // Return intersection point of ray with screen in barycentric coords + bool IntersectWithRay( const Ray_t &ray, float *u, float *v, float *t ); + + // Is the screen turned on? + bool IsActive() const; + + // Are we only visible to teammates? + bool IsVisibleOnlyToTeammates() const; + + // Are we visible to someone on this team? + bool IsVisibleToTeam( int nTeam ); + + bool IsAttachedToViewModel() const; + + virtual RenderGroup_t GetRenderGroup(); + + bool AcceptsInput() const; + void SetAcceptsInput( bool acceptsinput ); + + C_BasePlayer *GetPlayerOwner( void ); + bool IsInputOnlyToOwner( void ); + +private: + // Vgui screen management + void CreateVguiScreen( const char *pTypeName ); + void DestroyVguiScreen( ); + + // Computes the panel to world transform + void ComputePanelToWorld(); + + // Computes control points of the quad describing the screen + void ComputeEdges( Vector *pUpperLeft, Vector *pUpperRight, Vector *pLowerLeft ); + + // Writes the z buffer + void DrawScreenOverlay(); + +private: + int m_nPixelWidth; + int m_nPixelHeight; + float m_flWidth; + float m_flHeight; + int m_nPanelName; // The name of the panel + int m_nButtonState; + int m_nButtonPressed; + int m_nButtonReleased; + int m_nOldPx; + int m_nOldPy; + int m_nOldButtonState; + int m_nAttachmentIndex; + int m_nOverlayMaterial; + int m_fScreenFlags; + + int m_nOldPanelName; + int m_nOldOverlayMaterial; + + bool m_bLoseThinkNextFrame; + + bool m_bAcceptsInput; + + CMaterialReference m_WriteZMaterial; + CMaterialReference m_OverlayMaterial; + + VMatrix m_PanelToWorld; + + CPanelWrapper m_PanelWrapper; + + CHandle m_hPlayerOwner; +}; + + +//----------------------------------------------------------------------------- +// Returns an entity that is the nearby vgui screen; NULL if there isn't one +//----------------------------------------------------------------------------- +C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &viewAngle, int nTeam = -1 ); + + +//----------------------------------------------------------------------------- +// Activates/Deactivates vgui screen +//----------------------------------------------------------------------------- +void ActivateVguiScreen( C_BaseEntity *pVguiScreen ); +void DeactivateVguiScreen( C_BaseEntity *pVguiScreen ); + + +//----------------------------------------------------------------------------- +// Updates vgui screen button state +//----------------------------------------------------------------------------- +void SetVGuiScreenButtonState( C_BaseEntity *pVguiScreen, int nButtonState ); + + +// Called at shutdown. +void ClearKeyValuesCache(); + + +#endif // C_VGUISCREEN_H + diff --git a/game/client/c_vote_controller.h b/game/client/c_vote_controller.h new file mode 100644 index 0000000..5c1a4c5 --- /dev/null +++ b/game/client/c_vote_controller.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client VoteController +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_VoteController_H +#define C_VoteController_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "GameEventListener.h" + +class C_VoteController : public C_BaseEntity, public CGameEventListener +{ + DECLARE_CLASS( C_VoteController, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_VoteController(); + virtual ~C_VoteController(); + + virtual void Spawn( void ); + virtual void ClientThink( void ); + + static void RecvProxy_VoteType( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_VoteOption( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + void FireGameEvent( IGameEvent *event ); +protected: + void ResetData(); + + int m_iActiveIssueIndex; + int m_iOnlyTeamToVote; + int m_nVoteOptionCount[MAX_VOTE_OPTIONS]; + int m_iVoteChoiceIndex; + int m_nPotentialVotes; + bool m_bVotesDirty; // Received a vote, so remember to tell the Hud + bool m_bTypeDirty; // Vote type changed, so show or hide the Hud + bool m_bIsYesNoVote; +}; + +#endif // C_VoteController_H diff --git a/game/client/c_weapon__stubs.h b/game/client/c_weapon__stubs.h new file mode 100644 index 0000000..9b48d12 --- /dev/null +++ b/game/client/c_weapon__stubs.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_WEAPON__STUBS_H +#define C_WEAPON__STUBS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "client_class.h" + +// This is an ugly hack to link client classes to weapons for now +// these will be removed once we predict all weapons, especially TF2 weapons +#define STUB_WEAPON_CLASS_IMPLEMENT( entityName, className ) \ + BEGIN_PREDICTION_DATA( className ) \ + END_PREDICTION_DATA() \ + LINK_ENTITY_TO_CLASS( entityName, className ); + + +#define STUB_WEAPON_CLASS( entityName, className, baseClassName ) \ + class C_##className : public baseClassName \ + { \ + DECLARE_CLASS( C_##className, baseClassName ); \ + public: \ + DECLARE_PREDICTABLE(); \ + DECLARE_CLIENTCLASS(); \ + C_##className() {}; \ + private: \ + C_##className( const C_##className & ); \ + }; \ + STUB_WEAPON_CLASS_IMPLEMENT( entityName, C_##className ); \ + IMPLEMENT_CLIENTCLASS_DT( C_##className, DT_##className, C##className ) \ + END_RECV_TABLE() + +#endif // C_WEAPON__STUBS_H diff --git a/game/client/c_world.h b/game/client/c_world.h new file mode 100644 index 0000000..3cdbd6a --- /dev/null +++ b/game/client/c_world.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_WORLD_H ) +#define C_WORLD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" + +#if defined( CLIENT_DLL ) +#define CWorld C_World +#endif + +class C_World : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_World, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_World( void ); + ~C_World( void ); + + // Override the factory create/delete functions since the world is a singleton. + virtual bool Init( int entnum, int iSerialNum ); + virtual void Release(); + + virtual void Precache(); + virtual void Spawn(); + + // Don't worry about adding the world to the collision list; it's already there + virtual CollideType_t GetCollideType( void ) { return ENTITY_SHOULD_NOT_COLLIDE; } + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + + float GetWaveHeight() const; + const char *GetDetailSpriteMaterial() const; + +public: + enum + { + MAX_DETAIL_SPRITE_MATERIAL_NAME_LENGTH = 256, + }; + + float m_flWaveHeight; + Vector m_WorldMins; + Vector m_WorldMaxs; + bool m_bStartDark; + float m_flMaxOccludeeArea; + float m_flMinOccluderArea; + float m_flMinPropScreenSpaceWidth; + float m_flMaxPropScreenSpaceWidth; + bool m_bColdWorld; + +private: + void RegisterSharedActivities( void ); + char m_iszDetailSpriteMaterial[MAX_DETAIL_SPRITE_MATERIAL_NAME_LENGTH]; +}; + +inline float C_World::GetWaveHeight() const +{ + return m_flWaveHeight; +} + +inline const char *C_World::GetDetailSpriteMaterial() const +{ + return m_iszDetailSpriteMaterial; +} + +void ClientWorldFactoryInit(); +void ClientWorldFactoryShutdown(); +C_World* GetClientWorldEntity(); + +#endif // C_WORLD_H \ No newline at end of file diff --git a/game/client/cbase.h b/game/client/cbase.h new file mode 100644 index 0000000..57e3260 --- /dev/null +++ b/game/client/cbase.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CBASE_H +#define CBASE_H +#ifdef _WIN32 +#pragma once +#endif + +struct studiohdr_t; + +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "string_t.h" + +// These two have to be included very early +#include +#include + +#include "cdll_util.h" +#include + +#include +#include + + +// This is a precompiled header. Include a bunch of common stuff. +// This is kind of ugly in that it adds a bunch of dependency where it isn't needed. +// But on balance, the compile time is much lower (even incrementally) once the precompiled +// headers contain these headers. +#include "precache_register.h" +#include "c_basecombatweapon.h" +#include "c_basecombatcharacter.h" +#include "gamerules.h" +#include "c_baseplayer.h" +#include "itempents.h" +#include "vphysics_interface.h" +#include "physics.h" +#include "c_recipientfilter.h" +#include "cdll_client_int.h" +#include "worldsize.h" +#include "engine/ivmodelinfo.h" + +#endif // CBASE_H diff --git a/game/client/cdll_bounded_cvars.h b/game/client/cdll_bounded_cvars.h new file mode 100644 index 0000000..1b08f00 --- /dev/null +++ b/game/client/cdll_bounded_cvars.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Provides access to cvars that are bounded in the client DLL. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CDLL_BOUNDED_CVARS_H +#define CDLL_BOUNDED_CVARS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "convar_serverbounded.h" + + +extern ConVar_ServerBounded *cl_predict; +extern ConVar_ServerBounded *cl_interp; + +// Returns cl_interp_ratio / cl_updaterate. +float GetClientInterpAmount(); + + +#if !defined( NO_ENTITY_PREDICTION ) +extern bool g_bForceCLPredictOff; // If this is set to true, then prediction is forced off. Used temporarily for kill cam. +#endif + + + +#endif // CDLL_BOUNDED_CVARS_H + diff --git a/game/client/cdll_client_int.h b/game/client/cdll_client_int.h new file mode 100644 index 0000000..c245633 --- /dev/null +++ b/game/client/cdll_client_int.h @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef CDLL_CLIENT_INT_H +#define CDLL_CLIENT_INT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iclientnetworkable.h" +#include "utllinkedlist.h" +#include "cdll_int.h" +#include "eiface.h" + + +class IVModelRender; +class IVEngineClient; +class IVModelRender; +class IVEfx; +class IVRenderView; +class IVDebugOverlay; +class IMaterialSystem; +class IMaterialSystemStub; +class IDataCache; +class IMDLCache; +class IVModelInfoClient; +class IEngineVGui; +class ISpatialPartition; +class IBaseClientDLL; +class ISpatialPartition; +class IFileSystem; +class IStaticPropMgrClient; +class IShadowMgr; +class IEngineSound; +class IMatSystemSurface; +class IMaterialSystemHardwareConfig; +class ISharedGameRules; +class IEngineTrace; +class IGameUIFuncs; +class IGameEventManager2; +class IPhysicsGameTrace; +class CGlobalVarsBase; +class IClientTools; +class C_BaseAnimating; +class IColorCorrectionSystem; +class IInputSystem; +class ISceneFileCache; +class IXboxSystem; // Xbox 360 only +class IMatchmaking; +class IVideoServices; +class CSteamAPIContext; +class IClientReplayContext; +class IReplayManager; +class IEngineReplay; +class IEngineClientReplay; +class IReplayScreenshotManager; +class CSteamID; + +//============================================================================= +// HPE_BEGIN +// [dwenger] Necessary for stats display +//============================================================================= + +class AchievementsAndStatsInterface; + +//============================================================================= +// HPE_END +//============================================================================= + +extern IVModelRender *modelrender; +extern IVEngineClient *engine; +extern IVModelRender *modelrender; +extern IVEfx *effects; +extern IVRenderView *render; +extern IVDebugOverlay *debugoverlay; +extern IMaterialSystem *materials; +extern IMaterialSystemStub *materials_stub; +extern IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig; +extern IDataCache *datacache; +extern IMDLCache *mdlcache; +extern IVModelInfoClient *modelinfo; +extern IEngineVGui *enginevgui; +extern ISpatialPartition* partition; +extern IBaseClientDLL *clientdll; +extern IFileSystem *filesystem; +extern IStaticPropMgrClient *staticpropmgr; +extern IShadowMgr *shadowmgr; +extern IEngineSound *enginesound; +extern IMatSystemSurface *g_pMatSystemSurface; +extern IEngineTrace *enginetrace; +extern IGameUIFuncs *gameuifuncs; +extern IGameEventManager2 *gameeventmanager; +extern IPhysicsGameTrace *physgametrace; +extern CGlobalVarsBase *gpGlobals; +extern IClientTools *clienttools; +extern IInputSystem *inputsystem; +extern ISceneFileCache *scenefilecache; +extern IXboxSystem *xboxsystem; // Xbox 360 only +extern IMatchmaking *matchmaking; +extern IVideoServices *g_pVideo; +extern IUploadGameStats *gamestatsuploader; +extern CSteamAPIContext *steamapicontext; +extern IReplaySystem *g_pReplay; +extern IClientReplayContext *g_pClientReplayContext; +extern IReplayManager *g_pReplayManager; +extern IReplayScreenshotManager *g_pReplayScreenshotManager; +extern IEngineReplay *g_pEngineReplay; +extern IEngineClientReplay *g_pEngineClientReplay; + +//============================================================================= +// HPE_BEGIN +// [dwenger] Necessary for stats display +//============================================================================= + +extern AchievementsAndStatsInterface* g_pAchievementsAndStatsInterface; + +//============================================================================= +// HPE_END +//============================================================================= + +// Set to true between LevelInit and LevelShutdown. +extern bool g_bLevelInitialized; +extern bool g_bTextMode; + +// Kyle says: this is here to obsfucate our accessing of the g_bTextMode variable and for no other purpose. +// See the mess of TF_ANTI_IDLEBOT_VERIFICATION code. If that code doesn't exist anymore, this +// probably also doesn't need to exist anymore. +// +// On a suggestion from Joe, we also point it to an incomplete type. +extern class IClientPurchaseInterfaceV2 *g_pClientPurchaseInterface; + + +// Returns true if a new OnDataChanged event is registered for this frame. +bool AddDataChangeEvent( IClientNetworkable *ent, DataUpdateType_t updateType, int *pStoredEvent ); + +void ClearDataChangedEvent( int iStoredEvent ); + +//----------------------------------------------------------------------------- +// Precaches a material +//----------------------------------------------------------------------------- +void PrecacheMaterial( const char *pMaterialName ); + +//----------------------------------------------------------------------------- +// Converts a previously precached material into an index +//----------------------------------------------------------------------------- +int GetMaterialIndex( const char *pMaterialName ); + +//----------------------------------------------------------------------------- +// Converts precached material indices into strings +//----------------------------------------------------------------------------- +const char *GetMaterialNameFromIndex( int nIndex ); + +//----------------------------------------------------------------------------- +// Precache-related methods for particle systems +//----------------------------------------------------------------------------- +void PrecacheParticleSystem( const char *pParticleSystemName ); +int GetParticleSystemIndex( const char *pParticleSystemName ); +const char *GetParticleSystemNameFromIndex( int nIndex ); + + +//----------------------------------------------------------------------------- +// Called during bone setup to test perf +//----------------------------------------------------------------------------- +void TrackBoneSetupEnt( C_BaseAnimating *pEnt ); + +bool IsEngineThreaded(); + +#ifndef NO_STEAM + +/// Returns Steam ID, given player index. Returns an invalid SteamID upon +/// failure +extern CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex ); + +#endif + +#endif // CDLL_CLIENT_INT_H diff --git a/game/client/cdll_util.h b/game/client/cdll_util.h new file mode 100644 index 0000000..64beb5f --- /dev/null +++ b/game/client/cdll_util.h @@ -0,0 +1,181 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( UTIL_H ) +#define UTIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "mathlib/vector.h" +#include + +#include "shake.h" +#include "bitmap/imageformat.h" +#include "ispatialpartition.h" +#include "materialsystem/MaterialSystemUtil.h" + +class Vector; +class QAngle; +class IMaterial; +class ITexture; +class IClientEntity; +class CHudTexture; +class CGameTrace; +class C_BaseEntity; + +struct Ray_t; +struct client_textmessage_t; +typedef CGameTrace trace_t; + +namespace vgui +{ + typedef unsigned long HFont; +}; + + + +extern bool g_MakingDevShots; + +// ScreenHeight returns the height of the screen, in pixels +int ScreenHeight( void ); +// ScreenWidth returns the width of the screen, in pixels +int ScreenWidth( void ); + +#define XRES(x) ( x * ( ( float )ScreenWidth() / 640.0 ) ) +#define YRES(y) ( y * ( ( float )ScreenHeight() / 480.0 ) ) + +int UTIL_ComputeStringWidth( vgui::HFont& font, const char *str ); +int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str ); +float UTIL_AngleDiff( float destAngle, float srcAngle ); +void UTIL_Bubbles( const Vector& mins, const Vector& maxs, int count ); +void UTIL_Smoke( const Vector &origin, const float scale, const float framerate ); +void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName = NULL ); +int UTIL_PrecacheDecal( const char *name, bool preload = false ); +void UTIL_EmitAmbientSound( C_BaseEntity *entity, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch ); +void UTIL_SetOrigin( C_BaseEntity *entity, const Vector &vecOrigin ); +void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake=false ); +byte *UTIL_LoadFileForMe( const char *filename, int *pLength ); +void UTIL_FreeFile( byte *buffer ); +void UTIL_MakeSafeName( const char *oldName, OUT_Z_CAP(newNameBufSize) char *newName, int newNameBufSize ); ///< Cleans up player names for putting in vgui controls (cleaned names can be up to original*2+1 in length) +const char *UTIL_SafeName( const char *oldName ); ///< Wraps UTIL_MakeSafeName, and returns a static buffer +void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BYTECAP(outbufsizebytes) wchar_t *outbuf, int outbufsizebytes ); + +// Fade out an entity based on distance fades +unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist, float flFadeScale ); + +client_textmessage_t *TextMessageGet( const char *pName ); + +char *VarArgs( PRINTF_FORMAT_STRING const char *format, ... ); + + +// Get the entity the local player is spectating (can be a player or a ragdoll entity). +int GetSpectatorTarget(); +int GetSpectatorMode( void ); +bool IsPlayerIndex( int index ); +int GetLocalPlayerIndex( void ); +int GetLocalPlayerVisionFilterFlags( bool bWeaponsCheck = false ); +bool IsLocalPlayerUsingVisionFilterFlags( int nFlags, bool bWeaponsCheck = false ); +int GetLocalPlayerTeam( void ); +bool IsLocalPlayerSpectator( void ); +void NormalizeAngles( QAngle& angles ); +void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac ); +void InterpolateVector( float frac, const Vector& src, const Vector& dest, Vector& output ); + +const char *nexttoken(char *token, const char *str, char sep); + +//----------------------------------------------------------------------------- +// Base light indices to avoid index collision +//----------------------------------------------------------------------------- + +enum +{ + LIGHT_INDEX_TE_DYNAMIC = 0x10000000, + LIGHT_INDEX_PLAYER_BRIGHT = 0x20000000, + LIGHT_INDEX_MUZZLEFLASH = 0x40000000, +}; + +void UTIL_PrecacheOther( const char *szClassname ); + +void UTIL_SetTrace(trace_t& tr, const Ray_t& ray, C_BaseEntity *edict, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept ); + +bool GetVectorInScreenSpace( Vector pos, int& iX, int& iY, Vector *vecOffset = NULL ); +bool GetVectorInHudSpace( Vector pos, int& iX, int& iY, Vector *vecOffset = NULL ); +bool GetTargetInScreenSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset = NULL ); +bool GetTargetInHudSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset = NULL ); + +// prints messages through the HUD (stub in client .dll right now ) +class C_BasePlayer; +void ClientPrint( C_BasePlayer *player, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); + +// Pass in an array of pointers and an array size, it fills the array and returns the number inserted +int UTIL_EntitiesInBox( C_BaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); +int UTIL_EntitiesInSphere( C_BaseEntity **pList, int listMax, const Vector ¢er, float radius, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); +int UTIL_EntitiesAlongRay( C_BaseEntity **pList, int listMax, const Ray_t &ray, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); + +// make this a fixed size so it just sits on the stack +#define MAX_SPHERE_QUERY 256 +class CEntitySphereQuery +{ +public: + // currently this builds the list in the constructor + // UNDONE: make an iterative query of ISpatialPartition so we could + // make queries like this optimal + CEntitySphereQuery( const Vector ¢er, float radius, int flagMask=0, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); + C_BaseEntity *GetCurrentEntity(); + inline void NextEntity() { m_listIndex++; } + +private: + int m_listIndex; + int m_listCount; + C_BaseEntity *m_pList[MAX_SPHERE_QUERY]; +}; + +C_BaseEntity *CreateEntityByName( const char *className ); +// creates an entity by name, and ensure it's correctness +// does not spawn the entity +// use the CREATE_ENTITY() macro which wraps this, instead of using it directly +template< class T > +T *_CreateEntity( T *newClass, const char *className ) +{ + T *newEnt = dynamic_cast( CreateEntityByName(className) ); + if ( !newEnt ) + { + Warning( "classname %s used to create wrong class type\n", className ); + Assert(0); + } + + return newEnt; +} + +#define CREATE_ENTITY( newClass, className ) _CreateEntity( (newClass*)NULL, className ) +#define CREATE_UNSAVED_ENTITY( newClass, className ) _CreateEntityTemplate( (newClass*)NULL, className ) + +// Misc useful +inline bool FStrEq(const char *sz1, const char *sz2) +{ + return (sz1 == sz2 || V_stricmp(sz1, sz2) == 0); +} + +// Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h +void UTIL_BoundToWorldSize( Vector *pVecPos ); + +// Increments the passed key for the current map, eg "viewed" if TF holds the number of times the player has +// viewed the intro movie for this map +void UTIL_IncrementMapKey( const char *pszCustomKey ); + +// Gets the value of the passed key for the current map, eg "viewed" for number of times the player has viewed +// the intro movie for this map +int UTIL_GetMapKeyCount( const char *pszCustomKey ); + +// Returns true if the user has loaded any maps, false otherwise. +bool UTIL_HasLoadedAnyMap(); + +#endif // !UTIL_H diff --git a/game/client/cl_animevent.h b/game/client/cl_animevent.h new file mode 100644 index 0000000..29c95b7 --- /dev/null +++ b/game/client/cl_animevent.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hold definitions for all client animation events +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( CL_ANIMEVENT_H ) +#define CL_ANIMEVENT_H +#ifdef _WIN32 +#pragma once +#endif + +//Animation event codes +#define CL_EVENT_MUZZLEFLASH0 5001 // Muzzleflash on attachment 0 +#define CL_EVENT_MUZZLEFLASH1 5011 // Muzzleflash on attachment 1 +#define CL_EVENT_MUZZLEFLASH2 5021 // Muzzleflash on attachment 2 +#define CL_EVENT_MUZZLEFLASH3 5031 // Muzzleflash on attachment 3 +#define CL_EVENT_SPARK0 5002 // Spark on attachment 0 +#define CL_EVENT_NPC_MUZZLEFLASH0 5003 // Muzzleflash on attachment 0 for third person views +#define CL_EVENT_NPC_MUZZLEFLASH1 5013 // Muzzleflash on attachment 1 for third person views +#define CL_EVENT_NPC_MUZZLEFLASH2 5023 // Muzzleflash on attachment 2 for third person views +#define CL_EVENT_NPC_MUZZLEFLASH3 5033 // Muzzleflash on attachment 3 for third person views +#define CL_EVENT_SOUND 5004 // Emit a sound // NOTE THIS MUST MATCH THE DEFINE AT CBaseEntity::PrecacheModel on the server!!!!! +#define CL_EVENT_EJECTBRASS1 6001 // Eject a brass shell from attachment 1 + +#define CL_EVENT_DISPATCHEFFECT0 9001 // Hook into a DispatchEffect on attachment 0 +#define CL_EVENT_DISPATCHEFFECT1 9011 // Hook into a DispatchEffect on attachment 1 +#define CL_EVENT_DISPATCHEFFECT2 9021 // Hook into a DispatchEffect on attachment 2 +#define CL_EVENT_DISPATCHEFFECT3 9031 // Hook into a DispatchEffect on attachment 3 +#define CL_EVENT_DISPATCHEFFECT4 9041 // Hook into a DispatchEffect on attachment 4 +#define CL_EVENT_DISPATCHEFFECT5 9051 // Hook into a DispatchEffect on attachment 5 +#define CL_EVENT_DISPATCHEFFECT6 9061 // Hook into a DispatchEffect on attachment 6 +#define CL_EVENT_DISPATCHEFFECT7 9071 // Hook into a DispatchEffect on attachment 7 +#define CL_EVENT_DISPATCHEFFECT8 9081 // Hook into a DispatchEffect on attachment 8 +#define CL_EVENT_DISPATCHEFFECT9 9091 // Hook into a DispatchEffect on attachment 9 + +// These two events are used by c_env_spritegroup. +// FIXME: Should this be local to c_env_spritegroup? +#define CL_EVENT_SPRITEGROUP_CREATE 6002 +#define CL_EVENT_SPRITEGROUP_DESTROY 6003 +#define CL_EVENT_FOOTSTEP_LEFT 6004 +#define CL_EVENT_FOOTSTEP_RIGHT 6005 +#define CL_EVENT_MFOOTSTEP_LEFT 6006 // Footstep sounds based on material underfoot. +#define CL_EVENT_MFOOTSTEP_RIGHT 6007 +#define CL_EVENT_MFOOTSTEP_LEFT_LOUD 6008 // Loud material impact sounds from feet attachments +#define CL_EVENT_MFOOTSTEP_RIGHT_LOUD 6009 + + +#endif // CL_ANIMEVENT_H \ No newline at end of file diff --git a/game/client/cl_mat_stub.h b/game/client/cl_mat_stub.h new file mode 100644 index 0000000..8b0951d --- /dev/null +++ b/game/client/cl_mat_stub.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MAT_STUB_H +#define MAT_STUB_H +#ifdef _WIN32 +#pragma once +#endif + + +class IMaterialSystem; + + +// To stub out the material system in a block of code (if mat_stub is 1), +// make an instance of this class. You can unstub it by calling End() or +// it will automatically unstub in its destructor. +class CMatStubHandler +{ +public: + CMatStubHandler(); + ~CMatStubHandler(); + + void End(); + +public: + + IMaterialSystem *m_pOldMaterialSystem; +}; + + +// Returns true if mat_stub is 1. +bool IsMatStubEnabled(); + + +#endif // MAT_STUB_H diff --git a/game/client/client_factorylist.h b/game/client/client_factorylist.h new file mode 100644 index 0000000..6cb27b1 --- /dev/null +++ b/game/client/client_factorylist.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef CLIENT_FACTORYLIST_H +#define CLIENT_FACTORYLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +struct factorylist_t +{ + CreateInterfaceFn appSystemFactory; + CreateInterfaceFn physicsFactory; +}; + +// Store off the factories +void FactoryList_Store( const factorylist_t &sourceData ); + +// retrieve the stored factories +void FactoryList_Retrieve( factorylist_t &destData ); + +#endif // CLIENT_FACTORYLIST_H diff --git a/game/client/client_thinklist.h b/game/client/client_thinklist.h new file mode 100644 index 0000000..3d3e174 --- /dev/null +++ b/game/client/client_thinklist.h @@ -0,0 +1,135 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CLIENT_THINKLIST_H +#define CLIENT_THINKLIST_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "igamesystem.h" +#include "utllinkedlist.h" +#include "cliententitylist.h" +#include "iclientthinkable.h" +#include "utlrbtree.h" + + +#define CLIENT_THINK_ALWAYS -1293 +#define CLIENT_THINK_NEVER -1 + + +#define INVALID_THINK_HANDLE ClientThinkList()->GetInvalidThinkHandle() + + +class CClientThinkList : public IGameSystemPerFrame +{ +public: + + CClientThinkList(); + virtual ~CClientThinkList(); + + virtual char const *Name() { return "CClientThinkList"; } + virtual bool IsPerFrame() { return true; } + + // Set the next time at which you want to think. You can also use + // one of the CLIENT_THINK_ defines. + void SetNextClientThink( ClientEntityHandle_t hEnt, float nextTime ); + + // Remove an entity from the think list. + void RemoveThinkable( ClientEntityHandle_t hEnt ); + + // Use to initialize your think handles in IClientThinkables. + ClientThinkHandle_t GetInvalidThinkHandle(); + + // This is called after network updating and before rendering. + void PerformThinkFunctions(); + + // Call this to destroy a thinkable object - deletes the object post think. + void AddToDeleteList( ClientEntityHandle_t hEnt ); + void RemoveFromDeleteList( ClientEntityHandle_t hEnt ); + +// IClientSystem implementation. +public: + + virtual bool Init(); + virtual void PostInit() {}; + virtual void Shutdown(); + virtual void LevelInitPreEntity(); + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreEntity(); + virtual void LevelShutdownPostEntity(); + virtual void PreRender(); + virtual void PostRender() { } + virtual void Update( float frametime ); + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + +private: + struct ThinkEntry_t + { + ClientEntityHandle_t m_hEnt; + float m_flNextClientThink; + float m_flLastClientThink; + int m_nIterEnum; + }; + + struct ThinkListChanges_t + { + ClientEntityHandle_t m_hEnt; + ClientThinkHandle_t m_hThink; + float m_flNextTime; + }; + +// Internal stuff. +private: + void SetNextClientThink( ClientThinkHandle_t hThink, float nextTime ); + void RemoveThinkable( ClientThinkHandle_t hThink ); + void PerformThinkFunction( ThinkEntry_t *pEntry, float curtime ); + ThinkEntry_t* GetThinkEntry( ClientThinkHandle_t hThink ); + void CleanUpDeleteList(); + + // Add entity to frame think list + void AddEntityToFrameThinkList( ThinkEntry_t *pEntry, bool bAlwaysChain, int &nCount, ThinkEntry_t **ppFrameThinkList ); + +private: + CUtlLinkedList m_ThinkEntries; + + CUtlVector m_aDeleteList; + CUtlVector m_aChangeList; + + // Makes sure the entries are thinked once per frame in the face of hierarchy + int m_nIterEnum; + bool m_bInThinkLoop; +}; + + +// -------------------------------------------------------------------------------- // +// Inlines. +// -------------------------------------------------------------------------------- // + +inline ClientThinkHandle_t CClientThinkList::GetInvalidThinkHandle() +{ + return (ClientThinkHandle_t)(uintp)m_ThinkEntries.InvalidIndex(); +} + + +inline CClientThinkList::ThinkEntry_t* CClientThinkList::GetThinkEntry( ClientThinkHandle_t hThink ) +{ + return &m_ThinkEntries[ (unsigned long)hThink ]; +} + + +inline CClientThinkList* ClientThinkList() +{ + extern CClientThinkList g_ClientThinkList; + return &g_ClientThinkList; +} + + +#endif // CLIENT_THINKLIST_H diff --git a/game/client/client_virtualreality.h b/game/client/client_virtualreality.h new file mode 100644 index 0000000..9aadfeb --- /dev/null +++ b/game/client/client_virtualreality.h @@ -0,0 +1,165 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The implementation of ISourceVirtualReality, which provides utility +// functions for VR including head tracking, window/viewport information, +// rendering information, and distortion +// +//============================================================================= + +#ifndef CLIENTVIRTUALREALITY_H +#define CLIENTVIRTUALREALITY_H +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier3/tier3.h" +#include "iclientvirtualreality.h" +#include "view_shared.h" + +enum HeadtrackMovementMode_t +{ + HMM_SHOOTFACE_MOVEFACE = 0, // Shoot from your face, move along your face. + HMM_SHOOTFACE_MOVETORSO, // Shoot from your face, move the direction your torso is facing. + HMM_SHOOTMOUSE_MOVEFACE, // Shoot from the mouse cursor which moves within the HUD, move along your face. + HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEFACE, // Shoot from the mouse cursor which moves, bounded within the HUD, move along your face. + HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEMOUSE, // Shoot from the mouse cursor which moves, bounded within the HUD, move along your weapon (the "mouse") + + // The following are not intended to be user-selectable modes, they are used by e.g. followcam stuff. + HMM_SHOOTMOVELOOKMOUSEFACE, // Shoot & move & look along the mouse cursor (i.e. original unchanged gameplay), face just looks on top of that. + HMM_SHOOTMOVEMOUSE_LOOKFACE, // Shoot & move along the mouse cursor (i.e. original unchanged gameplay), face just looks. + HMM_SHOOTMOVELOOKMOUSE, // Shoot, move and look along the mouse cursor - HMD orientation is completely ignored! + + HMM_LAST, + + HMM_NOOVERRIDE = HMM_LAST // Used as a retrun from ShouldOverrideHeadtrackControl(), not an actual mode. +}; + + +//----------------------------------------------------------------------------- +// The implementation +//----------------------------------------------------------------------------- + + +class CClientVirtualReality: public CTier3AppSystem< IClientVirtualReality > +{ + typedef CTier3AppSystem< IClientVirtualReality > BaseClass; + +public: + + CClientVirtualReality(); + ~CClientVirtualReality(); + + //--------------------------------------------------------- + // Initialization and shutdown + //--------------------------------------------------------- + + // + // IAppSystem + // + virtual bool Connect( CreateInterfaceFn factory ); + virtual void Disconnect(); + virtual void * QueryInterface( const char *pInterfaceName ); + + // these will come from the engine + virtual InitReturnVal_t Init(); + virtual void Shutdown(); + + // Called when startup is complete + void StartupComplete(); + + //--------------------------------------------------------- + // IClientVirtualReality implementation + //--------------------------------------------------------- + virtual void DrawMainMenu() OVERRIDE; + + + //--------------------------------------------------------- + // VR utilities for use in the client + //--------------------------------------------------------- + bool OverrideView ( CViewSetup *pViewMiddle, Vector *pViewModelOrigin, QAngle *pViewModelAngles, HeadtrackMovementMode_t hmmMovementOverride ); + bool OverrideStereoView( CViewSetup *pViewMiddle, CViewSetup *pViewLeft, CViewSetup *pViewRight ); + bool OverridePlayerMotion( float flInputSampleFrametime, const QAngle &oldAngles, const QAngle &curAngles, const Vector &curMotion, QAngle *pNewAngles, Vector *pNewMotion ); + bool OverrideWeaponHudAimVectors ( Vector *pAimOrigin, Vector *pAimDirection ); + bool CurrentlyZoomed(); + void OverrideTorsoTransform( const Vector & position, const QAngle & angles ) ; + void CancelTorsoTransformOverride( ) ; + bool CanOverlayHudQuad(); + void GetHUDBounds( Vector *pViewer, Vector *pUL, Vector *pUR, Vector *pLL, Vector *pLR ); + void RenderHUDQuad( bool bBlackout, bool bTranslucent ); + float GetZoomedModeMagnification(); + bool ProcessCurrentTrackingState( float fGameFOV ); + const VMatrix &GetHudProjectionFromWorld(); + void GetTorsoRelativeAim( Vector *pPosition, QAngle *pAngles ); + float GetHUDDistance(); + bool ShouldRenderHUDInWorld(); + const VMatrix & GetWorldFromMidEye() const { return m_WorldFromMidEyeNoDebugCam; } + void OverrideViewModelTransform( Vector & vmorigin, QAngle & vmangles, bool bUseLargeOverride ); + void AlignTorsoAndViewToWeapon(); + void PostProcessFrame( StereoEye_t eEye ); + void OverlayHUDQuadWithUndistort( const CViewSetup &view, bool bDoUndistort, bool bBlackout, bool bTranslucent ); + + //--------------------------------------------------------- + // Enter/leave VR mode + //--------------------------------------------------------- + void Activate(); + void Deactivate(); + +private: + HeadtrackMovementMode_t m_hmmMovementActual; + + // Where the current mideye is relative to the (game)world. + VMatrix m_WorldFromMidEye; + + // used for drawing the HUD + float m_fHudHorizontalFov; + VMatrix m_WorldFromHud; + VMatrix m_HudProjectionFromWorld; + float m_fHudHalfWidth; + float m_fHudHalfHeight; + + // Where the current mideye is relative to the zero (torso) (currently always the same as m_MideyeZeroFromMideyeCurrent!) + VMatrix m_TorsoFromMideye; + + // The debug cam will play with the above, but some things want the non-debug view. + VMatrix m_WorldFromMidEyeNoDebugCam; + + // Where the weapon is currently pointing (note the translation will be zero - this is just orientation) + VMatrix m_WorldFromWeapon; + + // The player's current torso angles/pos in the world. + QAngle m_PlayerTorsoAngle; + Vector m_PlayerTorsoOrigin; + Vector m_PlayerLastMovement; + + // The player's current view angles/pos in the world. + QAngle m_PlayerViewAngle; + Vector m_PlayerViewOrigin; + + // The amount of zoom to apply to the view of the world (but NOT to the HUD!). Used for sniper weapons, etc. + float m_WorldZoomScale; + + // for overriding torso position in vehicles + QAngle m_OverrideTorsoAngle; + QAngle m_OverrideTorsoOffset; + bool m_bOverrideTorsoAngle; + + // While this is >0, we keep forcing the torso (and maybe view) to the weapon. + int m_iAlignTorsoAndViewToWeaponCountdown; + + bool m_bMotionUpdated; + + RTime32 m_rtLastMotionSample; + + // video mode we had before we entered VR mode + bool m_bNonVRWindowed; + int m_nNonVRWidth; + int m_nNonVRHeight; +#if defined( USE_SDL ) + int m_nNonVRSDLDisplayIndex; +#endif + bool m_bNonVRRawInput; +}; + +extern CClientVirtualReality g_ClientVirtualReality; + +#endif // CLIENTVIRTUALREALITY_H diff --git a/game/client/clienteffectprecachesystem.h b/game/client/clienteffectprecachesystem.h new file mode 100644 index 0000000..e05a500 --- /dev/null +++ b/game/client/clienteffectprecachesystem.h @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Deals with singleton +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( CLIENTEFFECTPRECACHESYSTEM_H ) +#define CLIENTEFFECTPRECACHESYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include "commonmacros.h" +#include "utlvector.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imaterial.h" + +//----------------------------------------------------------------------------- +// Interface to automated system for precaching materials +//----------------------------------------------------------------------------- +class IClientEffect +{ +public: + virtual void Cache( bool precache = true ) = 0; +}; + +//----------------------------------------------------------------------------- +// Responsible for managing precaching of particles +//----------------------------------------------------------------------------- + +class CClientEffectPrecacheSystem : public IGameSystem +{ +public: + virtual char const *Name() { return "CCLientEffectPrecacheSystem"; } + + virtual bool IsPerFrame() { return false; } + + // constructor, destructor + CClientEffectPrecacheSystem() {} + virtual ~CClientEffectPrecacheSystem() {} + + // Init, shutdown + virtual bool Init() { return true; } + virtual void PostInit() {} + virtual void Shutdown(); + + // Level init, shutdown + virtual void LevelInitPreEntity(); + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreEntity(); + virtual void LevelShutdownPostEntity(); + + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + + void Register( IClientEffect *effect ); + +protected: + + CUtlVector< IClientEffect * > m_Effects; +}; + +//Singleton accessor +extern CClientEffectPrecacheSystem *ClientEffectPrecacheSystem(); + +//----------------------------------------------------------------------------- +// Deals with automated registering and precaching of materials for effects +//----------------------------------------------------------------------------- + +class CClientEffect : public IClientEffect +{ +public: + + CClientEffect( void ) + { + //Register with the main effect system + ClientEffectPrecacheSystem()->Register( this ); + } + +//----------------------------------------------------------------------------- +// Purpose: Precache a material by artificially incrementing its reference counter +// Input : *materialName - name of the material +// : increment - whether to increment or decrement the reference counter +//----------------------------------------------------------------------------- + + inline void ReferenceMaterial( const char *materialName, bool increment = true ) + { + IMaterial *material = materials->FindMaterial( materialName, TEXTURE_GROUP_CLIENT_EFFECTS ); + if ( !IsErrorMaterial( material ) ) + { + if ( increment ) + { + material->IncrementReferenceCount(); + } + else + { + material->DecrementReferenceCount(); + } + } + } +}; + +//Automatic precache macros + +//Beginning +#define CLIENTEFFECT_REGISTER_BEGIN( className ) \ +namespace className { \ +class ClientEffectRegister : public CClientEffect \ +{ \ +private: \ + static const char *m_pszMaterials[]; \ +public: \ + void Cache( bool precache = true ); \ +}; \ +const char *ClientEffectRegister::m_pszMaterials[] = { + +//Material definitions +#define CLIENTEFFECT_MATERIAL( materialName ) materialName, + +//End +#define CLIENTEFFECT_REGISTER_END( ) }; \ +void ClientEffectRegister::Cache( bool precache ) \ +{ \ + for ( int i = 0; i < ARRAYSIZE( m_pszMaterials ); i++ ) \ + { \ + ReferenceMaterial( m_pszMaterials[i], precache ); \ + } \ +} \ +ClientEffectRegister register_ClientEffectRegister; \ +} + +#define CLIENTEFFECT_REGISTER_END_CONDITIONAL(condition ) }; \ +void ClientEffectRegister::Cache( bool precache ) \ +{ \ + if ( condition) \ + { \ + for ( int i = 0; i < ARRAYSIZE( m_pszMaterials ); i++ ) \ + { \ + ReferenceMaterial( m_pszMaterials[i], precache ); \ + } \ + } \ +} \ +ClientEffectRegister register_ClientEffectRegister; \ +} + +#endif //CLIENTEFFECTPRECACHESYSTEM_H diff --git a/game/client/cliententitylist.h b/game/client/cliententitylist.h new file mode 100644 index 0000000..f09b891 --- /dev/null +++ b/game/client/cliententitylist.h @@ -0,0 +1,308 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// +#if !defined( CLIENTENTITYLIST_H ) +#define CLIENTENTITYLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "icliententitylist.h" +#include "iclientunknown.h" +#include "utllinkedlist.h" +#include "utlvector.h" +#include "icliententityinternal.h" +#include "ispatialpartition.h" +#include "cdll_util.h" +#include "entitylist_base.h" +#include "utlmap.h" + +class C_Beam; +class C_BaseViewModel; +class C_BaseEntity; + + +#define INPVS_YES 0x0001 // The entity thinks it's in the PVS. +#define INPVS_THISFRAME 0x0002 // Accumulated as different views are rendered during the frame and used to notify the entity if + // it is not in the PVS anymore (at the end of the frame). +#define INPVS_NEEDSNOTIFY 0x0004 // The entity thinks it's in the PVS. + +class IClientEntityListener; + +abstract_class C_BaseEntityClassList +{ +public: + C_BaseEntityClassList(); + ~C_BaseEntityClassList(); + virtual void LevelShutdown() = 0; + + C_BaseEntityClassList *m_pNextClassList; +}; + +template< class T > +class C_EntityClassList : public C_BaseEntityClassList +{ +public: + virtual void LevelShutdown() { m_pClassList = NULL; } + + void Insert( T *pEntity ) + { + pEntity->m_pNext = m_pClassList; + m_pClassList = pEntity; + } + + void Remove( T *pEntity ) + { + T **pPrev = &m_pClassList; + T *pCur = *pPrev; + while ( pCur ) + { + if ( pCur == pEntity ) + { + *pPrev = pCur->m_pNext; + return; + } + pPrev = &pCur->m_pNext; + pCur = *pPrev; + } + } + + static T *m_pClassList; +}; + + +// Maximum size of entity list +#define INVALID_CLIENTENTITY_HANDLE CBaseHandle( INVALID_EHANDLE_INDEX ) + + +// +// This is the IClientEntityList implemenation. It serves two functions: +// +// 1. It converts server entity indices into IClientNetworkables for the engine. +// +// 2. It provides a place to store IClientUnknowns and gives out ClientEntityHandle_t's +// so they can be indexed and retreived. For example, this is how static props are referenced +// by the spatial partition manager - it doesn't know what is being inserted, so it's +// given ClientEntityHandle_t's, and the handlers for spatial partition callbacks can +// use the client entity list to look them up and check for supported interfaces. +// +class CClientEntityList : public CBaseEntityList, public IClientEntityList +{ +friend class C_BaseEntityIterator; +friend class C_AllBaseEntityIterator; + +public: + // Constructor, destructor + CClientEntityList( void ); + virtual ~CClientEntityList( void ); + + void Release(); // clears everything and releases entities + + +// Implement IClientEntityList +public: + + virtual IClientNetworkable* GetClientNetworkable( int entnum ); + virtual IClientEntity* GetClientEntity( int entnum ); + + virtual int NumberOfEntities( bool bIncludeNonNetworkable = false ); + + virtual IClientUnknown* GetClientUnknownFromHandle( ClientEntityHandle_t hEnt ); + virtual IClientNetworkable* GetClientNetworkableFromHandle( ClientEntityHandle_t hEnt ); + virtual IClientEntity* GetClientEntityFromHandle( ClientEntityHandle_t hEnt ); + + virtual int GetHighestEntityIndex( void ); + + virtual void SetMaxEntities( int maxents ); + virtual int GetMaxEntities( ); + + +// CBaseEntityList overrides. +protected: + + virtual void OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle ); + virtual void OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle ); + + +// Internal to client DLL. +public: + + // All methods of accessing specialized IClientUnknown's go through here. + IClientUnknown* GetListedEntity( int entnum ); + + // Simple wrappers for convenience.. + C_BaseEntity* GetBaseEntity( int entnum ); + ICollideable* GetCollideable( int entnum ); + + IClientRenderable* GetClientRenderableFromHandle( ClientEntityHandle_t hEnt ); + C_BaseEntity* GetBaseEntityFromHandle( ClientEntityHandle_t hEnt ); + ICollideable* GetCollideableFromHandle( ClientEntityHandle_t hEnt ); + IClientThinkable* GetClientThinkableFromHandle( ClientEntityHandle_t hEnt ); + + // Convenience methods to convert between entindex + ClientEntityHandle_t + ClientEntityHandle_t EntIndexToHandle( int entnum ); + int HandleToEntIndex( ClientEntityHandle_t handle ); + + // Is a handle valid? + bool IsHandleValid( ClientEntityHandle_t handle ) const; + + // For backwards compatibility... + C_BaseEntity* GetEnt( int entnum ) { return GetBaseEntity( entnum ); } + + void RecomputeHighestEntityUsed( void ); + + + // Use this to iterate over all the C_BaseEntities. + C_BaseEntity* FirstBaseEntity() const; + C_BaseEntity* NextBaseEntity( C_BaseEntity *pEnt ) const; + + class CPVSNotifyInfo + { + public: + IPVSNotify *m_pNotify; + IClientRenderable *m_pRenderable; + unsigned char m_InPVSStatus; // Combination of the INPVS_ flags. + unsigned short m_PVSNotifiersLink; // Into m_PVSNotifyInfos. + }; + + // Get the list of all PVS notifiers. + CUtlLinkedList& GetPVSNotifiers(); + + CUtlVector m_entityListeners; + + // add a class that gets notified of entity events + void AddListenerEntity( IClientEntityListener *pListener ); + void RemoveListenerEntity( IClientEntityListener *pListener ); + + void NotifyCreateEntity( C_BaseEntity *pEnt ); + void NotifyRemoveEntity( C_BaseEntity *pEnt ); + +private: + + // Cached info for networked entities. + struct EntityCacheInfo_t + { + // Cached off because GetClientNetworkable is called a *lot* + IClientNetworkable *m_pNetworkable; + unsigned short m_BaseEntitiesIndex; // Index into m_BaseEntities (or m_BaseEntities.InvalidIndex() if none). + }; + + // Current count + int m_iNumServerEnts; + // Max allowed + int m_iMaxServerEnts; + + int m_iNumClientNonNetworkable; + + // Current last used slot + int m_iMaxUsedServerIndex; + + // This holds fast lookups for special edicts. + EntityCacheInfo_t m_EntityCacheInfo[NUM_ENT_ENTRIES]; + + // For fast iteration. + CUtlLinkedList m_BaseEntities; + + +private: + + void AddPVSNotifier( IClientUnknown *pUnknown ); + void RemovePVSNotifier( IClientUnknown *pUnknown ); + + // These entities want to know when they enter and leave the PVS (server entities + // already can get the equivalent notification with NotifyShouldTransmit, but client + // entities have to get it this way). + CUtlLinkedList m_PVSNotifyInfos; + CUtlMap m_PVSNotifierMap; // Maps IClientUnknowns to indices into m_PVSNotifyInfos. +}; + + +// Use this to iterate over *all* (even dormant) the C_BaseEntities in the client entity list. +class C_AllBaseEntityIterator +{ +public: + C_AllBaseEntityIterator(); + + void Restart(); + C_BaseEntity* Next(); // keep calling this until it returns null. + +private: + unsigned short m_CurBaseEntity; +}; + +class C_BaseEntityIterator +{ +public: + C_BaseEntityIterator(); + + void Restart(); + C_BaseEntity* Next(); // keep calling this until it returns null. + +private: + unsigned short m_CurBaseEntity; +}; + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline bool CClientEntityList::IsHandleValid( ClientEntityHandle_t handle ) const +{ + return handle.Get() != 0; +} + +inline IClientUnknown* CClientEntityList::GetListedEntity( int entnum ) +{ + return (IClientUnknown*)LookupEntityByNetworkIndex( entnum ); +} + +inline IClientUnknown* CClientEntityList::GetClientUnknownFromHandle( ClientEntityHandle_t hEnt ) +{ + return (IClientUnknown*)LookupEntity( hEnt ); +} + +inline CUtlLinkedList& CClientEntityList::GetPVSNotifiers() +{ + return m_PVSNotifyInfos; +} + + +//----------------------------------------------------------------------------- +// Convenience methods to convert between entindex + ClientEntityHandle_t +//----------------------------------------------------------------------------- +inline ClientEntityHandle_t CClientEntityList::EntIndexToHandle( int entnum ) +{ + if ( entnum < -1 ) + return INVALID_EHANDLE_INDEX; + IClientUnknown *pUnk = GetListedEntity( entnum ); + return pUnk ? pUnk->GetRefEHandle() : INVALID_EHANDLE_INDEX; +} + + +//----------------------------------------------------------------------------- +// Returns the client entity list +//----------------------------------------------------------------------------- +extern CClientEntityList *cl_entitylist; + +inline CClientEntityList& ClientEntityList() +{ + return *cl_entitylist; +} + +// Implement this class and register with entlist to receive entity create/delete notification +class IClientEntityListener +{ +public: + virtual void OnEntityCreated( C_BaseEntity *pEntity ) {}; + //virtual void OnEntitySpawned( C_BaseEntity *pEntity ) {}; + virtual void OnEntityDeleted( C_BaseEntity *pEntity ) {}; +}; + + +#endif // CLIENTENTITYLIST_H + diff --git a/game/client/clientleafsystem.h b/game/client/clientleafsystem.h new file mode 100644 index 0000000..dd48ec0 --- /dev/null +++ b/game/client/clientleafsystem.h @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +// +// This file contains code to allow us to associate client data with bsp leaves. +// +//===========================================================================// + +#if !defined( CLIENTLEAFSYSTEM_H ) +#define CLIENTLEAFSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include "engine/IClientLeafSystem.h" +#include "cdll_int.h" +#include "ivrenderview.h" +#include "tier1/mempool.h" +#include "tier1/refcount.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct WorldListInfo_t; +class IClientRenderable; +class Vector; +class CGameTrace; +typedef CGameTrace trace_t; +struct Ray_t; +class Vector2D; +class CStaticProp; + + +//----------------------------------------------------------------------------- +// Handle to an renderables in the client leaf system +//----------------------------------------------------------------------------- +enum +{ + DETAIL_PROP_RENDER_HANDLE = (ClientRenderHandle_t)0xfffe +}; + + +class CClientRenderablesList : public CRefCounted<> +{ + DECLARE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList ); + +public: + enum + { + MAX_GROUP_ENTITIES = 4096 + }; + + struct CEntry + { + IClientRenderable *m_pRenderable; + unsigned short m_iWorldListInfoLeaf; // NOTE: this indexes WorldListInfo_t's leaf list. + unsigned short m_TwoPass; + ClientRenderHandle_t m_RenderHandle; + }; + + // The leaves for the entries are in the order of the leaves you call CollateRenderablesInLeaf in. + CEntry m_RenderGroups[RENDER_GROUP_COUNT][MAX_GROUP_ENTITIES]; + int m_RenderGroupCounts[RENDER_GROUP_COUNT]; +}; + + +//----------------------------------------------------------------------------- +// Used by CollateRenderablesInLeaf +//----------------------------------------------------------------------------- +struct SetupRenderInfo_t +{ + WorldListInfo_t *m_pWorldListInfo; + CClientRenderablesList *m_pRenderList; + Vector m_vecRenderOrigin; + Vector m_vecRenderForward; + int m_nRenderFrame; + int m_nDetailBuildFrame; // The "render frame" for detail objects + float m_flRenderDistSq; + bool m_bDrawDetailObjects : 1; + bool m_bDrawTranslucentObjects : 1; + + SetupRenderInfo_t() + { + m_bDrawDetailObjects = true; + m_bDrawTranslucentObjects = true; + } +}; + + +//----------------------------------------------------------------------------- +// A handle associated with shadows managed by the client leaf system +//----------------------------------------------------------------------------- +typedef unsigned short ClientLeafShadowHandle_t; +enum +{ + CLIENT_LEAF_SHADOW_INVALID_HANDLE = (ClientLeafShadowHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// The client leaf system +//----------------------------------------------------------------------------- +abstract_class IClientLeafShadowEnum +{ +public: + // The user ID is the id passed into CreateShadow + virtual void EnumShadow( ClientShadowHandle_t userId ) = 0; +}; + + +// subclassed by things which wish to add per-leaf data managed by the client leafsystem +class CClientLeafSubSystemData +{ +public: + virtual ~CClientLeafSubSystemData( void ) + { + } +}; + + +// defines for subsystem ids. each subsystem id uses up one pointer in each leaf +#define CLSUBSYSTEM_DETAILOBJECTS 0 +#define N_CLSUBSYSTEMS 1 + + + +//----------------------------------------------------------------------------- +// The client leaf system +//----------------------------------------------------------------------------- +abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameSystemPerFrame +{ +public: + // Adds and removes renderables from the leaf lists + virtual void AddRenderable( IClientRenderable* pRenderable, RenderGroup_t group ) = 0; + + // This tells if the renderable is in the current PVS. It assumes you've updated the renderable + // with RenderableChanged() calls + virtual bool IsRenderableInPVS( IClientRenderable *pRenderable ) = 0; + + virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ) =0; + virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ) =0; + + + virtual void SetDetailObjectsInLeaf( int leaf, int firstDetailObject, int detailObjectCount ) = 0; + virtual void GetDetailObjectsInLeaf( int leaf, int& firstDetailObject, int& detailObjectCount ) = 0; + + // Indicates which leaves detail objects should be rendered from, returns the detais objects in the leaf + virtual void DrawDetailObjectsInLeaf( int leaf, int frameNumber, int& firstDetailObject, int& detailObjectCount ) = 0; + + // Should we draw detail objects (sprites or models) in this leaf (because it's close enough to the view) + // *and* are there any objects in the leaf? + virtual bool ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber ) = 0; + + // Call this when a renderable origin/angles/bbox parameters has changed + virtual void RenderableChanged( ClientRenderHandle_t handle ) = 0; + + // Set a render group + virtual void SetRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ) = 0; + + // Computes which leaf translucent objects should be rendered in + virtual void ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ) = 0; + + // Put renderables into their appropriate lists. + virtual void BuildRenderablesList( const SetupRenderInfo_t &info ) = 0; + + // Put renderables in the leaf into their appropriate lists. + virtual void CollateViewModelRenderables( CUtlVector< IClientRenderable * >& opaqueList, CUtlVector< IClientRenderable * >& translucentList ) = 0; + + // Call this to deactivate static prop rendering.. + virtual void DrawStaticProps( bool enable ) = 0; + + // Call this to deactivate small object rendering + virtual void DrawSmallEntities( bool enable ) = 0; + + // The following methods are related to shadows... + virtual ClientLeafShadowHandle_t AddShadow( ClientShadowHandle_t userId, unsigned short flags ) = 0; + virtual void RemoveShadow( ClientLeafShadowHandle_t h ) = 0; + + // Project a shadow + virtual void ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0; + + // Project a projected texture spotlight + virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0; + + // Find all shadow casters in a set of leaves + virtual void EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum ) = 0; + + // Fill in a list of the leaves this renderable is in. + // Returns -1 if the handle is invalid. + virtual int GetRenderableLeaves( ClientRenderHandle_t handle, int leaves[128] ) = 0; + + // Get leaves this renderable is in + virtual bool GetRenderableLeaf ( ClientRenderHandle_t handle, int* pOutLeaf, const int* pInIterator = 0, int* pOutIterator = 0 ) = 0; + + // Use alternate translucent sorting algorithm (draw translucent objects in the furthest leaf they lie in) + virtual void EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Singleton accessor +//----------------------------------------------------------------------------- +extern IClientLeafSystem *g_pClientLeafSystem; +inline IClientLeafSystem* ClientLeafSystem() +{ + return g_pClientLeafSystem; +} + + +#endif // CLIENTLEAFSYSTEM_H + + diff --git a/game/client/clientmode.h b/game/client/clientmode.h new file mode 100644 index 0000000..b4d9350 --- /dev/null +++ b/game/client/clientmode.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef CLIENTMODE_H +#define CLIENTMODE_H + +#include "iclientmode.h" + +typedef struct +{ + char *name; + bool draw; +} ModeElements; + +#endif diff --git a/game/client/clientmode_normal.h b/game/client/clientmode_normal.h new file mode 100644 index 0000000..49fa61d --- /dev/null +++ b/game/client/clientmode_normal.h @@ -0,0 +1,8 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// delete \ No newline at end of file diff --git a/game/client/clientmode_shared.h b/game/client/clientmode_shared.h new file mode 100644 index 0000000..beef0ad --- /dev/null +++ b/game/client/clientmode_shared.h @@ -0,0 +1,162 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENTMODE_NORMAL_H ) +#define CLIENTMODE_NORMAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iclientmode.h" +#include "GameEventListener.h" +#include + +class CBaseHudChat; +class CBaseHudWeaponSelection; +class CViewSetup; +class C_BaseEntity; +class C_BasePlayer; + +namespace vgui +{ +class Panel; +} + +//============================================================================= +// HPE_BEGIN: +// [tj] Moved this from the .cpp file so derived classes could access it +//============================================================================= + +#define ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME 10 + +//============================================================================= +// HPE_END +//============================================================================= + +class CReplayReminderPanel; + +#define USERID2PLAYER(i) ToBasePlayer( ClientEntityList().GetEnt( engine->GetPlayerForUserID( i ) ) ) + +extern IClientMode *GetClientModeNormal(); // must be implemented + +// This class implements client mode functionality common to HL2 and TF2. +class ClientModeShared : public IClientMode, public CGameEventListener +{ +// IClientMode overrides. +public: + DECLARE_CLASS_NOBASE( ClientModeShared ); + + ClientModeShared(); + virtual ~ClientModeShared(); + + virtual void Init(); + virtual void InitViewport(); + virtual void VGui_Shutdown(); + virtual void Shutdown(); + + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); + + virtual void Enable(); + virtual void Disable(); + virtual void Layout(); + + virtual void ReloadScheme( bool flushLowLevel ); + virtual void OverrideView( CViewSetup *pSetup ); + virtual bool ShouldDrawDetailObjects( ); + virtual bool ShouldDrawEntity(C_BaseEntity *pEnt); + virtual bool ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ); + virtual bool ShouldDrawViewModel(); + virtual bool ShouldDrawParticles( ); + virtual bool ShouldDrawCrosshair( void ); + virtual bool ShouldBlackoutAroundHUD() OVERRIDE; + virtual HeadtrackMovementMode_t ShouldOverrideHeadtrackControl() OVERRIDE; + virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ); + virtual void PreRender(CViewSetup *pSetup); + virtual void PostRender(); + virtual void PostRenderVGui(); + virtual void ProcessInput(bool bActive); + virtual bool CreateMove( float flInputSampleTime, CUserCmd *cmd ); + virtual void Update(); + + // Input + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual void OverrideMouseInput( float *x, float *y ); + virtual void StartMessageMode( int iMessageModeType ); + virtual vgui::Panel *GetMessagePanel(); + + virtual void ActivateInGameVGuiContext( vgui::Panel *pPanel ); + virtual void DeactivateInGameVGuiContext(); + + // The mode can choose to not draw fog + virtual bool ShouldDrawFog( void ); + + virtual float GetViewModelFOV( void ); + virtual vgui::Panel* GetViewport() { return m_pViewport; } + // Gets at the viewports vgui panel animation controller, if there is one... + virtual vgui::AnimationController *GetViewportAnimationController() + { return m_pViewport->GetAnimationController(); } + + virtual void FireGameEvent( IGameEvent *event ); + + virtual bool CanRecordDemo( char *errorMsg, int length ) const { return true; } + + virtual int HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + virtual void ComputeVguiResConditions( KeyValues *pkvConditions ) OVERRIDE; + + //============================================================================= + // HPE_BEGIN: + // [menglish] Save server information shown to the client in a persistent place + //============================================================================= + + virtual wchar_t* GetServerName() { return NULL; } + virtual void SetServerName(wchar_t* name) {}; + virtual wchar_t* GetMapName() { return NULL; } + virtual void SetMapName(wchar_t* name) {}; + + //============================================================================= + // HPE_END + //============================================================================= + + virtual bool DoPostScreenSpaceEffects( const CViewSetup *pSetup ); + + virtual void DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent, + const char *pSound, bool bDlg ); + + virtual bool IsInfoPanelAllowed() OVERRIDE { return true; } + virtual void InfoPanelDisplayed() OVERRIDE { } + virtual bool IsHTMLInfoPanelAllowed() OVERRIDE { return true; } + +protected: + CBaseViewport *m_pViewport; + + void DisplayReplayReminder(); + +private: + virtual void UpdateReplayMessages(); + + void ClearReplayMessageList(); + +#if defined( REPLAY_ENABLED ) + float m_flReplayStartRecordTime; + float m_flReplayStopRecordTime; + CReplayReminderPanel *m_pReplayReminderPanel; +#endif + + // Message mode handling + // All modes share a common chat interface + CBaseHudChat *m_pChatElement; + vgui::HCursor m_CursorNone; + CBaseHudWeaponSelection *m_pWeaponSelection; + int m_nRootSize[2]; +}; + +#endif // CLIENTMODE_NORMAL_H + diff --git a/game/client/clientsideeffects.h b/game/client/clientsideeffects.h new file mode 100644 index 0000000..fd74956 --- /dev/null +++ b/game/client/clientsideeffects.h @@ -0,0 +1,98 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CLIENTSIDEEFFECTS_H +#define CLIENTSIDEEFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + +class Vector; +struct FXQuadData_t; +struct FXLineData_t; +//----------------------------------------------------------------------------- +// Purpose: Base class for client side effects +//----------------------------------------------------------------------------- +abstract_class CClientSideEffect +{ +public: + // Constructs the named effect + CClientSideEffect( const char *name ); + virtual ~CClientSideEffect( void ); + + // Update/Draw the effect + // Derived classes must implement this method! + virtual void Draw( double frametime ) = 0; + // Returns name of effect + virtual const char *GetName( void ); + // Retuns whether the effect is still active + virtual bool IsActive( void ); + // Sets the effect to inactive so it can be destroed + virtual void Destroy( void ); + + // Sets the effect name (useful for debugging). + virtual void SetEffectName( const char *pszName ); + +private: + // Name of effect ( static data ) + const char *m_pszName; + // Is the effect active + bool m_bActive; +}; + +//----------------------------------------------------------------------------- +// Purpose: Base interface to effects list +//----------------------------------------------------------------------------- +abstract_class IEffectsList +{ +public: + virtual ~IEffectsList( void ) {} + + // Add an effect to the list of effects + virtual void AddEffect( CClientSideEffect *effect ) = 0; + // Remove the specified effect + virtual void RemoveEffect( CClientSideEffect *effect ) = 0; + // Simulate/Update/Draw effects on list + virtual void DrawEffects( double frametime ) = 0; + // Flush out all effects fbrom the list + virtual void Flush( void ) = 0; +}; + +extern IEffectsList *clienteffects; + +class IMaterialSystem; +extern IMaterialSystem *materials; + +//Actual function references +void FX_AddCube( const Vector &mins, const Vector &maxs, const Vector &vColor, float life, const char *materialName ); +void FX_AddCenteredCube( const Vector ¢er, float size, const Vector &vColor, float life, const char *materialName ); +void FX_AddStaticLine( const Vector& start, const Vector& end, float scale, float life, const char *materialName, unsigned char flags ); +void FX_AddDiscreetLine( const Vector& start, const Vector& direction, float velocity, float length, float clipLength, float scale, float life, const char *shader ); + +void FX_AddLine( const FXLineData_t &data ); + +void FX_AddQuad( const FXQuadData_t &data ); + +void FX_AddQuad( const Vector &origin, + const Vector &normal, + float startSize, + float endSize, + float sizeBias, + float startAlpha, + float endAlpha, + float alphaBias, + float yaw, + float deltaYaw, + const Vector &color, + float lifeTime, + const char *shader, + unsigned int flags ); + +// For safe addition of client effects +void SetFXCreationAllowed( bool state ); +bool FXCreationAllowed( void ); + +#endif // CLIENTSIDEEFFECTS_H diff --git a/game/client/clientsteamcontext.h b/game/client/clientsteamcontext.h new file mode 100644 index 0000000..07a4bcd --- /dev/null +++ b/game/client/clientsteamcontext.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#if !defined( CLIENTSTEAMCONTEXT_H ) +#define CLIENTSTEAMCONTEXT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam/steam_api.h" +#include "utldelegate.h" + +struct SteamLoggedOnChange_t +{ + bool bPreviousLoggedOn; + bool bLoggedOn; +}; + +class CClientSteamContext : public CSteamAPIContext +{ +public: + CClientSteamContext(); + ~CClientSteamContext(); + + void Activate(); + void Shutdown(); + +#if !defined(NO_STEAM) + STEAM_CALLBACK( CClientSteamContext, OnSteamServersDisconnected, SteamServersDisconnected_t, m_CallbackSteamServersDisconnected ); + STEAM_CALLBACK( CClientSteamContext, OnSteamServerConnectFailure, SteamServerConnectFailure_t, m_CallbackSteamServerConnectFailure ); + STEAM_CALLBACK( CClientSteamContext, OnSteamServersConnected, SteamServersConnected_t, m_CallbackSteamServersConnected ); +#endif + + bool BLoggedOn() { return m_bLoggedOn; } + EUniverse GetConnectedUniverse() { return m_nUniverse; } + uint32 GetAppID() { return m_nAppID; } + const CSteamID & GetLocalPlayerSteamID() { return m_SteamIDLocalPlayer; } + + // Allow others to register for a callback when the Steam logged on status changes + void InstallCallback( CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > delegate ); + void RemoveCallback( CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > delegate ); + +private: + void UpdateLoggedOnState(); + void InvokeCallbacks( const SteamLoggedOnChange_t &loggedOnStatus ); + + bool m_bActive; + bool m_bLoggedOn; + CSteamID m_SteamIDLocalPlayer; + EUniverse m_nUniverse; + uint32 m_nAppID; + + CUtlVector< CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > > m_LoggedOnCallbacks; +}; + +CClientSteamContext &ClientSteamContext(); // singleton accessor + +#endif // CLIENTSTEAMCONTEXT_H \ No newline at end of file diff --git a/game/client/colorcorrectionmgr.h b/game/client/colorcorrectionmgr.h new file mode 100644 index 0000000..3d5271d --- /dev/null +++ b/game/client/colorcorrectionmgr.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose : Singleton manager for color correction on the client +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef COLORCORRECTIONMGR_H +#define COLORCORRECTIONMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" + + +//------------------------------------------------------------------------------ +// Purpose : Singleton manager for color correction on the client +//------------------------------------------------------------------------------ +DECLARE_POINTER_HANDLE( ClientCCHandle_t ); +#define INVALID_CLIENT_CCHANDLE ( (ClientCCHandle_t)0 ) + +class CColorCorrectionMgr : public CBaseGameSystem +{ + // Inherited from IGameSystemPerFrame +public: + virtual char const *Name() { return "Color Correction Mgr"; } + + // Other public methods +public: + CColorCorrectionMgr(); + + // Create, destroy color correction + ClientCCHandle_t AddColorCorrection( const char *pName, const char *pFileName = NULL ); + void RemoveColorCorrection( ClientCCHandle_t ); + + // Modify color correction weights + void SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ); + void ResetColorCorrectionWeights(); + void SetResetable( ClientCCHandle_t h, bool bResetable ); + + // Is color correction active? + bool HasNonZeroColorCorrectionWeights() const; + +private: + int m_nActiveWeightCount; +}; + + +//------------------------------------------------------------------------------ +// Singleton access +//------------------------------------------------------------------------------ +extern CColorCorrectionMgr *g_pColorCorrectionMgr; + + +#endif // COLORCORRECTIONMGR_H diff --git a/game/client/commentary_modelviewer.h b/game/client/commentary_modelviewer.h new file mode 100644 index 0000000..1fd1d41 --- /dev/null +++ b/game/client/commentary_modelviewer.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMMENTARY_MODELVIEWER_H +#define COMMENTARY_MODELVIEWER_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "basemodelpanel.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCommentaryModelPanel : public CModelPanel +{ +public: + DECLARE_CLASS_SIMPLE( CCommentaryModelPanel, CModelPanel ); + + CCommentaryModelPanel( vgui::Panel *parent, const char *name ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCommentaryModelViewer : public vgui::Frame, public IViewPortPanel +{ + DECLARE_CLASS_SIMPLE( CCommentaryModelViewer, vgui::Frame ); +public: + CCommentaryModelViewer(IViewPort *pViewPort); + virtual ~CCommentaryModelViewer(); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void PerformLayout( void ); + virtual void OnCommand( const char *command ); + virtual void OnKeyCodePressed( vgui::KeyCode code ); + virtual void OnThink( void ); + + void SetModel( const char *pszName, const char *pszAttached ); + + void HandleMovementInput( void ); + + // IViewPortPanel +public: + virtual const char *GetName( void ) { return PANEL_COMMENTARY_MODELVIEWER; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset() {}; + virtual void Update() {}; + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +private: + IViewPort *m_pViewPort; + CCommentaryModelPanel *m_pModelPanel; + + Vector m_vecResetPos; + Vector m_vecResetAngles; + bool m_bTranslating; + float m_flYawSpeed; + float m_flZoomSpeed; +}; + +#endif // COMMENTARY_MODELVIEWER_H diff --git a/game/client/detailobjectsystem.h b/game/client/detailobjectsystem.h new file mode 100644 index 0000000..11bb696 --- /dev/null +++ b/game/client/detailobjectsystem.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Deals with singleton +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( DETAILOBJECTSYSTEM_H ) +#define DETAILOBJECTSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include "icliententityinternal.h" +#include "engine/ivmodelrender.h" +#include "mathlib/vector.h" +#include "ivrenderview.h" + +struct model_t; + + +//----------------------------------------------------------------------------- +// Responsible for managing detail objects +//----------------------------------------------------------------------------- +abstract_class IDetailObjectSystem : public IGameSystem +{ +public: + // Gets a particular detail object + virtual IClientRenderable* GetDetailModel( int idx ) = 0; + + // Gets called each view + virtual void BuildDetailObjectRenderLists( const Vector &vViewOrigin ) = 0; + + // Renders all opaque detail objects in a particular set of leaves + virtual void RenderOpaqueDetailObjects( int nLeafCount, LeafIndex_t *pLeafList ) = 0; + + // Call this before rendering translucent detail objects + virtual void BeginTranslucentDetailRendering( ) = 0; + + // Renders all translucent detail objects in a particular set of leaves + virtual void RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t *pLeafList ) =0; + + // Renders all translucent detail objects in a particular leaf up to a particular point + virtual void RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint ) = 0; +}; + + +//----------------------------------------------------------------------------- +// System for dealing with detail objects +//----------------------------------------------------------------------------- +IDetailObjectSystem* DetailObjectSystem(); + + +#endif // DETAILOBJECTSYSTEM_H + diff --git a/game/client/enginesprite.h b/game/client/enginesprite.h new file mode 100644 index 0000000..6735bde --- /dev/null +++ b/game/client/enginesprite.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ENGINESPRITE_H +#define ENGINESPRITE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "video/ivideoservices.h" +#include "const.h" +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class IMaterialVar; +typedef struct wrect_s wrect_t; + + +//----------------------------------------------------------------------------- +// Purpose: Sprite Models +//----------------------------------------------------------------------------- +class CEngineSprite +{ + // NOTE: don't define a constructor or destructor so that this can be allocated + // as before. +public: + int GetWidth() { return m_width; } + int GetHeight() { return m_height; } + int GetNumFrames() { return m_numFrames; } + IMaterial *GetMaterial( RenderMode_t nRenderMode ) { return m_material[nRenderMode]; } + IMaterial *GetMaterial( RenderMode_t nRenderMode, int nFrame ); + void SetFrame( RenderMode_t nRenderMode, int nFrame ); + bool Init( const char *name ); + void Shutdown( void ); + void UnloadMaterial(); + void SetColor( float r, float g, float b ); + int GetOrientation( void ); + void GetHUDSpriteColor( float* color ); + float GetUp() { return up; } + float GetDown() { return down; } + float GetLeft() { return left; } + float GetRight() { return right; } + void DrawFrame( RenderMode_t nRenderMode, int frame, int x, int y, const wrect_t *prcSubRect ); + void DrawFrameOfSize( RenderMode_t nRenderMode, int frame, int x, int y, int iWidth, int iHeight, const wrect_t *prcSubRect); + bool IsVideo(); + void GetTexCoordRange( float *pMinU, float *pMinV, float *pMaxU, float *pMaxV ); + +private: + IVideoMaterial *m_VideoMaterial; + int m_width; + int m_height; + int m_numFrames; + IMaterial *m_material[kRenderModeCount]; + int m_orientation; + float m_hudSpriteColor[3]; + float up, down, left, right; +}; + +#endif // ENGINESPRITE_H diff --git a/game/client/episodic/episodic_screenspaceeffects.h b/game/client/episodic/episodic_screenspaceeffects.h new file mode 100644 index 0000000..ff5bc71 --- /dev/null +++ b/game/client/episodic/episodic_screenspaceeffects.h @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef EPISODIC_SCREENSPACEEFFECTS_H +#define EPISODIC_SCREENSPACEEFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ScreenSpaceEffects.h" + +class CStunEffect : public IScreenSpaceEffect +{ +public: + CStunEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) {}; + virtual bool IsEnabled( ) { return true; } + + virtual void Render( int x, int y, int w, int h ); + +private: + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; +}; + +ADD_SCREENSPACE_EFFECT( CStunEffect, episodic_stun ); + +// +// EP1 Intro Blur +// + +class CEP1IntroEffect : public IScreenSpaceEffect +{ +public: + CEP1IntroEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ), + m_bEnabled( false ), + m_bFadeOut( false ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; } + virtual bool IsEnabled( ) { return m_bEnabled; } + + virtual void Render( int x, int y, int w, int h ); + +private: + + inline unsigned char GetFadeAlpha( void ); + + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; + bool m_bEnabled; + bool m_bFadeOut; +}; + +ADD_SCREENSPACE_EFFECT( CEP1IntroEffect, episodic_intro ); + +// +// EP2 Player Stunned Effect +// + +// +// EP1 Intro Blur +// + +class CEP2StunEffect : public IScreenSpaceEffect +{ +public: + CEP2StunEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ), + m_bEnabled( false ), + m_bFadeOut( false ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; } + virtual bool IsEnabled( ) { return m_bEnabled; } + + virtual void Render( int x, int y, int w, int h ); + +private: + + inline unsigned char GetFadeAlpha( void ); + + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; + bool m_bEnabled; + bool m_bFadeOut; +}; + +ADD_SCREENSPACE_EFFECT( CEP2StunEffect, ep2_groggy ); + +#endif // EPISODIC_SCREENSPACEEFFECTS_H diff --git a/game/client/flashlighteffect.h b/game/client/flashlighteffect.h new file mode 100644 index 0000000..d291c38 --- /dev/null +++ b/game/client/flashlighteffect.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FLASHLIGHTEFFECT_H +#define FLASHLIGHTEFFECT_H +#ifdef _WIN32 +#pragma once +#endif + +struct dlight_t; + + +class CFlashlightEffect +{ +public: + + CFlashlightEffect(int nEntIndex = 0); + virtual ~CFlashlightEffect(); + + virtual void UpdateLight(const Vector &vecPos, const Vector &vecDir, const Vector &vecRight, const Vector &vecUp, int nDistance); + void TurnOn(); + void TurnOff(); + bool IsOn( void ) { return m_bIsOn; } + + ClientShadowHandle_t GetFlashlightHandle( void ) { return m_FlashlightHandle; } + void SetFlashlightHandle( ClientShadowHandle_t Handle ) { m_FlashlightHandle = Handle; } + +protected: + + void LightOff(); + void LightOffOld(); + void LightOffNew(); + + void UpdateLightNew(const Vector &vecPos, const Vector &vecDir, const Vector &vecRight, const Vector &vecUp); + void UpdateLightOld(const Vector &vecPos, const Vector &vecDir, int nDistance); + + bool m_bIsOn; + int m_nEntIndex; + ClientShadowHandle_t m_FlashlightHandle; + + // Vehicle headlight dynamic light pointer + dlight_t *m_pPointLight; + float m_flDistMod; + + // Texture for flashlight + CTextureReference m_FlashlightTexture; +}; + +class CHeadlightEffect : public CFlashlightEffect +{ +public: + + CHeadlightEffect(); + ~CHeadlightEffect(); + + virtual void UpdateLight(const Vector &vecPos, const Vector &vecDir, const Vector &vecRight, const Vector &vecUp, int nDistance); +}; + + + +#endif // FLASHLIGHTEFFECT_H diff --git a/game/client/fontabc.h b/game/client/fontabc.h new file mode 100644 index 0000000..bdf4b49 --- /dev/null +++ b/game/client/fontabc.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FONTABC_H +#define FONTABC_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct +{ + int abcA, abcB, abcC; + int total; +} FONTABC; + +#endif // FONTABC_H diff --git a/game/client/functionproxy.h b/game/client/functionproxy.h new file mode 100644 index 0000000..22bb818 --- /dev/null +++ b/game/client/functionproxy.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: These are a couple of base proxy classes to help us with +// getting/setting source/result material vars +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNCTIONPROXY_H +#define FUNCTIONPROXY_H + +#include "materialsystem/imaterialproxy.h" +#include "materialsystem/imaterialvar.h" + +class IMaterialVar; +class C_BaseEntity; + + +//----------------------------------------------------------------------------- +// Helper class to deal with floating point inputs +//----------------------------------------------------------------------------- +class CFloatInput +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues, const char *pKeyName, float flDefault = 0.0f ); + float GetFloat() const; + +private: + float m_flValue; + IMaterialVar *m_pFloatVar; + int m_FloatVecComp; +}; + + +//----------------------------------------------------------------------------- +// Result proxy; a result (with vector friendliness) +//----------------------------------------------------------------------------- +class CResultProxy : public IMaterialProxy +{ +public: + CResultProxy(); + virtual ~CResultProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); + +protected: + C_BaseEntity *BindArgToEntity( void *pArg ); + void SetFloatResult( float result ); + + IMaterialVar* m_pResult; + int m_ResultVecComp; +}; + + +//----------------------------------------------------------------------------- +// Base functional proxy; two sources (one is optional) and a result +//----------------------------------------------------------------------------- +class CFunctionProxy : public CResultProxy +{ +public: + CFunctionProxy(); + virtual ~CFunctionProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + +protected: + void ComputeResultType( MaterialVarType_t& resultType, int& vecSize ); + + IMaterialVar* m_pSrc1; + IMaterialVar* m_pSrc2; +}; + +#endif // FUNCTIONPROXY_H + diff --git a/game/client/fx.h b/game/client/fx.h new file mode 100644 index 0000000..3b5e4e9 --- /dev/null +++ b/game/client/fx.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// +#if !defined( FX_H ) +#define FX_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "particles_simple.h" +#include "c_pixel_visibility.h" + +class Vector; +class CGameTrace; +typedef CGameTrace trace_t; +//struct trace_t; + +enum +{ + FX_ENERGYSPLASH_EXPLOSIVE = 0x1, + FX_ENERGYSPLASH_SMOKE = 0x2, + FX_ENERGYSPLASH_LITTLESPARKS = 0x4, + FX_ENERGYSPLASH_BIGSPARKS = 0x8, + FX_ENERGYSPLASH_BIGSPARKSCOLLIDE = 0x10, + FX_ENERGYSPLASH_ENERGYBALLS = 0x20, + FX_ENERGYSPLASH_DLIGHT = 0x40, + + FX_ENERGYSPLASH_DEFAULT = ~FX_ENERGYSPLASH_EXPLOSIVE, + FX_ENERGYSPLASH_DEFAULT_EXPLOSIVE = ~0, +}; + +bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, matrix3x4_t &transform ); +bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, Vector *origin, QAngle *angles ); + +void FX_RicochetSound( const Vector& pos ); + +void FX_AntlionImpact( const Vector &pos, trace_t *tr ); +void FX_DebrisFlecks( const Vector& origin, trace_t *trace, char materialType, int iScale, bool bNoFlecks = false ); +void FX_Tracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); +void FX_GunshipTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); +void FX_StriderTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); +void FX_HunterTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); +void FX_PlayerTracer( Vector& start, Vector& end ); +void FX_BulletPass( Vector& start, Vector& end ); +void FX_MetalSpark( const Vector &position, const Vector &direction, const Vector &surfaceNormal, int iScale = 1 ); +void FX_MetalScrape( Vector &position, Vector &normal ); +void FX_Sparks( const Vector &pos, int nMagnitude, int nTrailLength, const Vector &vecDir, float flWidth, float flMinSpeed, float flMaxSpeed, char *pSparkMaterial = NULL ); +void FX_ElectricSpark( const Vector &pos, int nMagnitude, int nTrailLength, const Vector *vecDir ); +void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMaxs ); +void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a ); +void FX_CreateImpactDust( Vector &origin, Vector &normal ); +void FX_EnergySplash( const Vector &pos, const Vector &normal, int nFlags = FX_ENERGYSPLASH_DEFAULT ); +void FX_MicroExplosion( Vector &position, Vector &normal ); +void FX_Explosion( Vector& origin, Vector& normal, char materialType ); +void FX_ConcussiveExplosion( Vector& origin, Vector& normal ); +void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ); +void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ); +void FX_MuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor = NULL, bool bOneFrame = false ); +void FX_MuzzleEffectAttached( float scale, ClientEntityHandle_t hEntity, int attachmentIndex, unsigned char *pFlashColor = NULL, bool bOneFrame = false ); +void FX_StriderMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor = NULL ); +void FX_GunshipMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor = NULL ); +CSmartPtr FX_Smoke( const Vector &origin, const Vector &velocity, float scale, int numParticles, float flDietime, unsigned char *pColor, int iAlpha, const char *pMaterial, float flRoll, float flRollDelta ); +void FX_Smoke( const Vector &origin, const QAngle &angles, float scale, int numParticles, unsigned char *pColor = NULL, int iAlpha = -1 ); +void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, float flSpeed ); +void FX_CreateGaussExplosion( const Vector &pos, const Vector &dir, int type ); +void FX_GaussTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); +void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType ); + +// Lighting information utility +void UTIL_GetNormalizedColorTintAndLuminosity( const Vector &color, Vector *tint = NULL, float *luminosity = NULL ); + +// Useful function for testing whether to draw noZ effects +bool EffectOccluded( const Vector &pos, pixelvis_handle_t *queryHandle = 0 ); + +class CTeslaInfo +{ +public: + Vector m_vPos; + QAngle m_vAngles; + int m_nEntIndex; + const char *m_pszSpriteName; + float m_flBeamWidth; + int m_nBeams; + Vector m_vColor; + float m_flTimeVisible; + float m_flRadius; +}; + +void FX_Tesla( const CTeslaInfo &teslaInfo ); +extern ConVar r_decals; + +extern void FX_CacheMaterialHandles( void ); + +extern PMaterialHandle g_Mat_Fleck_Wood[2]; +extern PMaterialHandle g_Mat_Fleck_Cement[2]; +extern PMaterialHandle g_Mat_Fleck_Antlion[2]; +extern PMaterialHandle g_Mat_Fleck_Tile[2]; +extern PMaterialHandle g_Mat_DustPuff[2]; +extern PMaterialHandle g_Mat_BloodPuff[2]; +extern PMaterialHandle g_Mat_Fleck_Glass[2]; +extern PMaterialHandle g_Mat_SMG_Muzzleflash[4]; +extern PMaterialHandle g_Mat_Combine_Muzzleflash[3]; +#endif // FX_H diff --git a/game/client/fx_blood.h b/game/client/fx_blood.h new file mode 100644 index 0000000..4fed5fb --- /dev/null +++ b/game/client/fx_blood.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_BLOOD_H +#define FX_BLOOD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/memdbgon.h" + +class CBloodSprayEmitter : public CSimpleEmitter +{ +public: + + CBloodSprayEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static CBloodSprayEmitter *Create( const char *pDebugName ) + { + return new CBloodSprayEmitter( pDebugName ); + } + + inline void SetGravity( float flGravity ) + { + m_flGravity = flGravity; + } + + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -4.0f ); + + //Cap the minimum roll + /* + if ( fabs( pParticle->m_flRollDelta ) < 0.5f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f; + } + */ + + return pParticle->m_flRoll; + } + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + if ( !( pParticle->m_iFlags & SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY ) ) + { + //Decelerate + static float dtime; + static float decay; + + if ( dtime != timeDelta ) + { + decay = ExponentialDecay( 0.1, 0.4f, dtime ); + dtime = timeDelta; + } + + pParticle->m_vecVelocity *= decay; + pParticle->m_vecVelocity[2] -= ( m_flGravity * timeDelta ); + } + } + +private: + + float m_flGravity; + + CBloodSprayEmitter( const CBloodSprayEmitter & ); +}; + +#include "tier0/memdbgoff.h" + +#endif // FX_BLOOD_H diff --git a/game/client/fx_discreetline.h b/game/client/fx_discreetline.h new file mode 100644 index 0000000..316bfdb --- /dev/null +++ b/game/client/fx_discreetline.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined( FXDISCREETLINE_H ) +#define FXDISCREETLINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "clientsideeffects.h" + +class IMaterial; + +class CFXDiscreetLine : public CClientSideEffect +{ +public: + + CFXDiscreetLine ( const char *name, const Vector& start, const Vector& direction, float velocity, + float length, float clipLength, float scale, float life, const char *shader ); + ~CFXDiscreetLine ( void ); + + virtual void Draw( double frametime ); + virtual bool IsActive( void ); + virtual void Destroy( void ); + virtual void Update( double frametime ); + +protected: + + IMaterial *m_pMaterial; + float m_fLife; + Vector m_vecOrigin, m_vecDirection; + float m_fVelocity; + float m_fStartTime; + float m_fClipLength; + float m_fScale; + float m_fLength; +}; + +#endif //FXDISCREETLINE_H \ No newline at end of file diff --git a/game/client/fx_envelope.h b/game/client/fx_envelope.h new file mode 100644 index 0000000..3f1997f --- /dev/null +++ b/game/client/fx_envelope.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_ENVELOPE_H +#define FX_ENVELOPE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" +#include "fx.h" +#include "view.h" +#include "view_scene.h" +#include "materialsystem/imaterialvar.h" + +class C_EnvelopeFX : public CDefaultClientRenderable +{ +public: + typedef CDefaultClientRenderable BaseClass; + + C_EnvelopeFX(); + virtual ~C_EnvelopeFX(); + + virtual void Update( void ); + + // IClientRenderable + virtual const Vector& GetRenderOrigin( void ) { return m_worldPosition; } + virtual void SetRenderOrigin( const Vector &origin ) { m_worldPosition = origin; } + virtual const QAngle& GetRenderAngles( void ) { return vec3_angle; } + virtual const matrix3x4_t & RenderableToWorldTransform(); + virtual bool ShouldDraw( void ) { return true; } + virtual bool IsTransparent( void ) { return true; } + virtual bool ShouldReceiveProjectedTextures( int flags ) { return false; } + + void SetTime( float t ) { m_t = t; } + void LimitTime( float tmax ) { m_tMax = tmax; } + void SetActive( bool state = true ) { m_active = state; } + bool IsActive( void ) const { return m_active; } + + virtual void EffectInit( int entityIndex, int attachment ); + virtual void EffectShutdown( void ); + +protected: + + void RemoveRenderable(); + + + int m_entityIndex; + int m_attachment; + bool m_active; + float m_t; + float m_tMax; + Vector m_worldPosition; +}; + +#endif // FX_ENVELOPE_H diff --git a/game/client/fx_explosion.h b/game/client/fx_explosion.h new file mode 100644 index 0000000..5aa147a --- /dev/null +++ b/game/client/fx_explosion.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FX_EXPLOSION_H +#define FX_EXPLOSION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particle_collision.h" +#include "glow_overlay.h" + +//JDW: For now we're clamping this value +#define EXPLOSION_FORCE_MAX 2 +#define EXPLOSION_FORCE_MIN 2 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_BaseExplosionEffect +{ +private: + static C_BaseExplosionEffect m_instance; + +public: + ~C_BaseExplosionEffect( void ) {} + + static C_BaseExplosionEffect &Instance( void ) { return m_instance; } + + virtual void Create( const Vector &position, float force, float scale, int flags ); + +protected: + C_BaseExplosionEffect( void ); + + virtual void PlaySound( void ); + + virtual void CreateCore( void ); + virtual void CreateDebris( void ); + virtual void CreateMisc( void ); + virtual void CreateDynamicLight( void ); + + float ScaleForceByDeviation( Vector &deviant, Vector &source, float spread, float *force = NULL ); + + float Probe( const Vector &origin, Vector *direction, float strength ); + void GetForceDirection( const Vector &origin, float magnitude, Vector *resultDirection, float *resultForce ); + +protected: + + Vector m_vecOrigin; + Vector m_vecDirection; + float m_flForce; + int m_fFlags; + + PMaterialHandle m_Material_Smoke; + PMaterialHandle m_Material_Embers[2]; + PMaterialHandle m_Material_FireCloud; +}; + +//Singleton accessor +extern C_BaseExplosionEffect &BaseExplosionEffect( void ); + + +// +// CExplosionOverlay +// + +class CExplosionOverlay : public CWarpOverlay +{ +public: + + virtual bool Update( void ); + +public: + + float m_flLifetime; + Vector m_vBaseColors[MAX_SUN_LAYERS]; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Water explosion +//----------------------------------------------------------------------------- +class C_WaterExplosionEffect : public C_BaseExplosionEffect +{ + typedef C_BaseExplosionEffect BaseClass; +public: + static C_WaterExplosionEffect &Instance( void ) { return m_waterinstance; } + + virtual void Create( const Vector &position, float force, float scale, int flags ); + +protected: + virtual void CreateCore( void ); + virtual void CreateDebris( void ); + virtual void CreateMisc( void ); + virtual void PlaySound( void ); + +private: + Vector m_vecWaterSurface; + float m_flDepth; // Depth below the water surface (used for surface effect) + Vector m_vecColor; // Lighting tint information + float m_flLuminosity; // Luminosity information + + static C_WaterExplosionEffect m_waterinstance; +}; + +//Singleton accessor +extern C_WaterExplosionEffect &WaterExplosionEffect( void ); + +//----------------------------------------------------------------------------- +// Purpose: Water explosion +//----------------------------------------------------------------------------- +class C_MegaBombExplosionEffect : public C_BaseExplosionEffect +{ + typedef C_BaseExplosionEffect BaseClass; +public: + static C_MegaBombExplosionEffect &Instance( void ) { return m_megainstance; } + +protected: + virtual void CreateCore( void ); + + virtual void CreateDebris( void ) { }; + virtual void CreateMisc( void ) { }; + virtual void PlaySound( void ) { }; + +private: + static C_MegaBombExplosionEffect m_megainstance; +}; + +//Singleton accessor +extern C_MegaBombExplosionEffect &MegaBombExplosionEffect( void ); + +#endif // FX_EXPLOSION_H diff --git a/game/client/fx_fleck.h b/game/client/fx_fleck.h new file mode 100644 index 0000000..bd9396b --- /dev/null +++ b/game/client/fx_fleck.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined( FXFLECKS_H ) +#define FXFLECKS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particles_simple.h" +#include "particlemgr.h" +#include "particle_collision.h" + +// FleckParticle + +class FleckParticle : public Particle +{ +public: + Vector m_vecVelocity; + float m_flRoll; + float m_flRollDelta; + float m_flDieTime; // How long it lives for. + float m_flLifetime; // How long it has been alive for so far. + byte m_uchColor[3]; + byte m_uchSize; +}; + +// +// CFleckParticles +// + +class CFleckParticles : public CSimpleEmitter +{ +public: + + CFleckParticles( const char *pDebugName ); + ~CFleckParticles(); + static CSmartPtr Create( const char *pDebugName, const Vector &vCenter, const Vector &extents ); + + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + //Setup for point emission + virtual void Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags = 0 ); + + CParticleCollision m_ParticleCollision; + + CFleckParticles *m_pNextParticleSystem; +private: + CFleckParticles( const CFleckParticles & ); // not defined, not accessible +}; + +#endif //FXFLECKS_H \ No newline at end of file diff --git a/game/client/fx_impact.h b/game/client/fx_impact.h new file mode 100644 index 0000000..ad57f7e --- /dev/null +++ b/game/client/fx_impact.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_IMPACT_H +#define FX_IMPACT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_te_effect_dispatch.h" +#include "istudiorender.h" + +// Parse the impact data from the server's data block +C_BaseEntity *ParseImpactData( const CEffectData &data, Vector *vecOrigin, Vector *vecStart, Vector *vecShotDir, short &nSurfaceProp, int &iMaterial, int &iDamageType, int &iHitbox ); + +// Get the decal name to use based on an impact with the specified entity, surface material, and damage type +char const *GetImpactDecal( C_BaseEntity *pEntity, int iMaterial, int iDamageType ); + +// Basic decal handling +// Returns true if it hit something +enum +{ + IMPACT_NODECAL = 0x1, + IMPACT_REPORT_RAGDOLL_IMPACTS = 0x2, +}; + +bool Impact( Vector &vecOrigin, Vector &vecStart, int iMaterial, int iDamageType, int iHitbox, C_BaseEntity *pEntity, trace_t &tr, int nFlags = 0, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); + +// Flags for PerformCustomEffects +enum +{ + FLAGS_CUSTIOM_EFFECTS_NOFLECKS = 0x1, +}; + +// Do spiffy things according to the material hit +void PerformCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &shotDir, int iMaterial, int iScale, int nFlags = 0 ); + +// Play the correct impact sound according to the material hit +void PlayImpactSound( C_BaseEntity *pServerEntity, trace_t &tr, Vector &vecServerOrigin, int nServerSurfaceProp ); + +// This can be used to hook impact sounds and play them at a later time. +// Shotguns do this so it doesn't play 10 identical sounds in the same spot. +typedef void (*ImpactSoundRouteFn)( const char *pSoundName, const Vector &vEndPos ); +void SetImpactSoundRoute( ImpactSoundRouteFn fn ); + +//----------------------------------------------------------------------------- +// Purpose: Enumerator class for ragdolls being affected by bullet forces +//----------------------------------------------------------------------------- +class CRagdollEnumerator : public IPartitionEnumerator +{ +public: + // Forced constructor + CRagdollEnumerator( Ray_t& shot, int iDamageType ); + + // Actual work code + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + + bool Hit( void ) const { return m_bHit; } + +private: + Ray_t m_rayShot; + int m_iDamageType; + bool m_bHit; +}; + +#endif // FX_IMPACT_H diff --git a/game/client/fx_interpvalue.h b/game/client/fx_interpvalue.h new file mode 100644 index 0000000..a274ffe --- /dev/null +++ b/game/client/fx_interpvalue.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef FX_INTERPVALUE_H +#define FX_INTERPVALUE_H +#ifdef _WIN32 +#pragma once +#endif + +// Types of supported interpolation +enum InterpType_t +{ + INTERP_LINEAR = 0, + INTERP_SPLINE, +}; + +class CInterpolatedValue +{ +public: + CInterpolatedValue( void ); + CInterpolatedValue( float startTime, float endTime, float startValue, float endValue, InterpType_t type ); + + void SetTime( float start, float end ); + void SetRange( float start, float end ); + void SetType( InterpType_t type ); + + // Set the value with no range + void SetAbsolute( float value ); + + // Set the value with range and time supplied + void Init( float startValue, float endValue, float dt, InterpType_t type = INTERP_LINEAR ); + + // Start from the current value and move towards the end value + void InitFromCurrent( float endValue, float dt, InterpType_t type = INTERP_LINEAR ); + + // Find our interpolated value at the given point in time + float Interp( float curTime ); + +private: + + float m_flStartTime; + float m_flEndTime; + float m_flStartValue; + float m_flEndValue; + + int m_nInterpType; +}; + +#endif // FX_INTERPVALUE_H \ No newline at end of file diff --git a/game/client/fx_line.h b/game/client/fx_line.h new file mode 100644 index 0000000..5975271 --- /dev/null +++ b/game/client/fx_line.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined( FXLINE_H ) +#define FXLINE_H +#ifdef _WIN32 +#pragma once +#endif + +struct FXLineData_t +{ + Vector m_vecStart; + Vector m_vecEnd; + Vector m_vecStartVelocity; + Vector m_vecEndVelocity; + float m_flStartAlpha; + float m_flEndAlpha; + float m_flStartScale; + float m_flEndScale; + float m_flDieTime; + float m_flLifeTime; + + IMaterial *m_pMaterial; +}; + +#include "fx_staticline.h" + +class CFXLine : public CClientSideEffect +{ +public: + + CFXLine( const char *name, const FXLineData_t &data ); + + ~CFXLine( void ); + + virtual void Draw( double frametime ); + virtual bool IsActive( void ); + virtual void Destroy( void ); + virtual void Update( double frametime ); + +protected: + + FXLineData_t m_FXData; +}; + +void FX_DrawLine( const Vector &start, const Vector &end, float scale, IMaterial *pMaterial, const color32 &color ); +void FX_DrawLineFade( const Vector &start, const Vector &end, float scale, IMaterial *pMaterial, const color32 &color, float fadeDist ); + +#endif //FXLINE_H \ No newline at end of file diff --git a/game/client/fx_quad.h b/game/client/fx_quad.h new file mode 100644 index 0000000..638547e --- /dev/null +++ b/game/client/fx_quad.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "clientsideeffects.h" + +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" + +#ifndef FX_QUAD_H +#define FX_QUAD_H +#ifdef _WIN32 +#pragma once +#endif + +// Flags +#define FXQUAD_BIAS_SCALE 0x0001 //Bias the scale's interpolation function +#define FXQUAD_BIAS_ALPHA 0x0002 //Bias the alpha's interpolation function +#define FXQUAD_COLOR_FADE 0x0004 //Blend the color towards black via the alpha (overcomes additive ignoring alpha) + +struct FXQuadData_t +{ + FXQuadData_t( void ) + { + m_flLifeTime = 0.0f; + m_flDieTime = 0.0f; + m_uiFlags = 0; + } + + void SetFlags( unsigned int flags ) { m_uiFlags |= flags; } + void SetOrigin( const Vector &origin ) { m_vecOrigin = origin; } + void SetNormal( const Vector &normal ) { m_vecNormal = normal; } + void SetScale( float start, float end ) { m_flStartScale = start; m_flEndScale = end; } + void SetAlpha( float start, float end ) { m_flStartAlpha = start; m_flEndAlpha = end; } + void SetLifeTime( float lifetime ) { m_flDieTime = lifetime; } + void SetColor( float r, float g, float b ) { m_Color = Vector( r, g, b ); } + void SetAlphaBias( float bias ) { m_flAlphaBias = bias; } + void SetScaleBias( float bias ) { m_flScaleBias = bias; } + void SetYaw( float yaw, float delta = 0.0f ){ m_flYaw = yaw; m_flDeltaYaw = delta; } + + void SetMaterial( const char *shader ) + { + m_pMaterial = materials->FindMaterial( shader, TEXTURE_GROUP_CLIENT_EFFECTS ); + + if ( m_pMaterial != NULL ) + { + m_pMaterial->IncrementReferenceCount(); + } + } + + unsigned int m_uiFlags; + IMaterial *m_pMaterial; + Vector m_vecOrigin; + Vector m_vecNormal; + float m_flStartScale; + float m_flEndScale; + float m_flDieTime; + float m_flLifeTime; + float m_flStartAlpha; + float m_flEndAlpha; + Vector m_Color; + float m_flYaw; + float m_flDeltaYaw; + + // Only used with FXQUAD_BIAS_ALPHA and FXQUAD_BIAS_SCALE + float m_flScaleBias; + float m_flAlphaBias; +}; + +class CFXQuad : public CClientSideEffect +{ +public: + + CFXQuad( const FXQuadData_t &data ); + + ~CFXQuad( void ); + + virtual void Draw( double frametime ); + virtual bool IsActive( void ); + virtual void Destroy( void ); + virtual void Update( double frametime ); + + FXQuadData_t m_FXData; +}; + +#endif // FX_QUAD_H diff --git a/game/client/fx_sparks.h b/game/client/fx_sparks.h new file mode 100644 index 0000000..bdfbe43 --- /dev/null +++ b/game/client/fx_sparks.h @@ -0,0 +1,168 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#include "particles_simple.h" +#include "particlemgr.h" +#include "c_pixel_visibility.h" +#include "fx_fleck.h" + +#include "tier0/memdbgon.h" + +#define bitsPARTICLE_TRAIL_VELOCITY_DAMPEN 0x00000001 //Dampen the velocity as the particles move +#define bitsPARTICLE_TRAIL_COLLIDE 0x00000002 //Do collision with simulation +#define bitsPARTICLE_TRAIL_FADE 0x00000004 //Fade away +#define bitsPARTICLE_TRAIL_FADE_IN 0x00000008 //Fade in + +class TrailParticle : public Particle +{ +public: + + Vector m_vecVelocity; + color32 m_color; // Particle color + float m_flDieTime; // How long it lives for. + float m_flLifetime; // How long it has been alive for so far. + float m_flLength; // Length of the tail (in seconds!) + float m_flWidth; // Width of the spark +}; + +inline void Color32ToFloat4( float colorOut[4], const color32 & colorIn ) +{ + colorOut[0] = colorIn.r * (1.0f/255.0f); + colorOut[1] = colorIn.g * (1.0f/255.0f); + colorOut[2] = colorIn.b * (1.0f/255.0f); + colorOut[3] = colorIn.a * (1.0f/255.0f); +} + +inline void FloatToColor32( color32 &out, float r, float g, float b, float a ) +{ + out.r = r * 255; + out.g = g * 255; + out.b = b * 255; + out.a = a * 255; +} + +inline void Float4ToColor32( color32 &out, float colorIn[4] ) +{ + out.r = colorIn[0] * 255; + out.g = colorIn[1] * 255; + out.b = colorIn[2] * 255; + out.a = colorIn[3] * 255; +} + +inline void Color32Init( color32 &out, int r, int g, int b, int a ) +{ + out.r = r; + out.g = g; + out.b = b; + out.a = a; +} +// +// CTrailParticles +// + +class CTrailParticles : public CSimpleEmitter +{ + DECLARE_CLASS( CTrailParticles, CSimpleEmitter ); +public: + CTrailParticles( const char *pDebugName ); + + static CTrailParticles *Create( const char *pDebugName ) { return new CTrailParticles( pDebugName ); } + + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + //Setup for point emission + virtual void Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags, bool bNotCollideable = false ); + + void SetFlag( int flags ) { m_fFlags |= flags; } + void SetVelocityDampen( float dampen ) { m_flVelocityDampen = dampen; } + void SetGravity( float gravity ) { m_ParticleCollision.SetGravity( gravity ); } + void SetCollisionDamped( float dampen ) { m_ParticleCollision.SetCollisionDampen( dampen ); } + void SetAngularCollisionDampen( float dampen ) { m_ParticleCollision.SetAngularCollisionDampen( dampen ); } + + CParticleCollision m_ParticleCollision; + +protected: + + int m_fFlags; + float m_flVelocityDampen; + +private: + CTrailParticles( const CTrailParticles & ); // not defined, not accessible +}; + +// +// Sphere trails +// + +class CSphereTrails : public CSimpleEmitter +{ + DECLARE_CLASS( CSphereTrails, CSimpleEmitter ); +public: + CSphereTrails( const char *pDebugName, const Vector &origin, float innerRadius, float outerRadius, float speed, int entityIndex, int attachment ); + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void Update( float flTimeDelta ); + virtual void StartRender(); + + void AddStreaks( float count ); + Vector m_particleOrigin; + float m_life; + float m_outerRadius; + float m_innerRadius; + float m_effectSpeed; + float m_streakSpeed; + float m_count; + float m_growth; + int m_entityIndex; + int m_attachment; + PMaterialHandle m_hMaterial; + Vector m_boneOrigin; + float m_dieTime; + +private: + CSphereTrails( const CSphereTrails & ); // not defined, not accessible +}; + + +// Simple glow emitter won't draw any of it's particles until/unless the pixel visibility test succeeds +class CSimpleGlowEmitter : public CSimpleEmitter +{ + DECLARE_CLASS( CSimpleGlowEmitter, CSimpleEmitter ); +public: + CSimpleGlowEmitter( const char *pDebugName, const Vector &sortOrigin, float flDeathTime ); + static CSimpleGlowEmitter *Create( const char *pDebugName, const Vector &sortOrigin, float flDeathTime ); + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); +protected: + + bool WasTestedInView( unsigned char viewMask ); + bool IsVisibleInView( unsigned char viewMask ); + void SetTestedInView( unsigned char viewMask, bool bTested ); + void SetVisibleInView( unsigned char viewMask, bool bVisible ); + unsigned char CurrentViewMask() const; + + float m_flDeathTime; // How long it has been alive for so far. + float m_startTime; + pixelvis_handle_t m_queryHandle; +private: + unsigned char m_wasTested; + unsigned char m_isVisible; + +private: + CSimpleGlowEmitter( const CSimpleGlowEmitter & ); // not defined, not accessible +}; + +#include "tier0/memdbgoff.h" diff --git a/game/client/fx_staticline.h b/game/client/fx_staticline.h new file mode 100644 index 0000000..2beeb99 --- /dev/null +++ b/game/client/fx_staticline.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include "clientsideeffects.h" + +#if !defined( FXSTATICLINE_H ) +#define FXSTATICLINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" + +class IMaterial; + +#define FXSTATICLINE_FLIP_HORIZONTAL 0x00000001 //Swaps the TC's so the texture is flipped horizontally +#define FXSTATICLINE_FLIP_VERTICAL 0x00000002 //Swaps the TC's so the texture is flipped vertically + +class CFXStaticLine : public CClientSideEffect +{ +public: + + CFXStaticLine( const char *name, const Vector& start, const Vector& end, float scale, float life, const char *shader, unsigned int flags ); + ~CFXStaticLine( void ); + + virtual void Draw( double frametime ); + virtual bool IsActive( void ); + virtual void Destroy( void ); + virtual void Update( double frametime ); + +protected: + + IMaterial *m_pMaterial; + Vector m_vecStart, m_vecEnd; + unsigned int m_uiFlags; + float m_fLife; + float m_fScale; +}; + +#endif diff --git a/game/client/fx_trail.h b/game/client/fx_trail.h new file mode 100644 index 0000000..e618fd0 --- /dev/null +++ b/game/client/fx_trail.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_TRAIL_H +#define FX_TRAIL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particle_util.h" +#include "baseparticleentity.h" +#include "particle_prototype.h" + +class C_ParticleTrail : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + + DECLARE_CLASS( C_ParticleTrail, C_BaseParticleEntity ); + + C_ParticleTrail( void ); + virtual ~C_ParticleTrail( void ); + + void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + void SetEmit( bool bEmit ); + bool ShouldEmit( void ) { return m_bEmit; } + + void SetSpawnRate( float rate ); + + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + + virtual void Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs ); + + int m_nAttachment; + float m_flLifetime; // How long this effect will last + +private: + + float m_SpawnRate; // How many particles per second. + bool m_bEmit; // Keep emitting particles? + + TimedEvent m_ParticleSpawn; + CParticleMgr *m_pParticleMgr; + +private: + + C_ParticleTrail( const C_ParticleTrail & ); +}; + +#endif // FX_TRAIL_H diff --git a/game/client/fx_water.h b/game/client/fx_water.h new file mode 100644 index 0000000..a1e623a --- /dev/null +++ b/game/client/fx_water.h @@ -0,0 +1,103 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_WATER_H +#define FX_WATER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particles_simple.h" +#include "fx.h" + +#include "tier0/memdbgon.h" + +class CSplashParticle : public CSimpleEmitter +{ +public: + + CSplashParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ), m_bUseClipHeight( false ) {} + + // Create + static CSplashParticle *Create( const char *pDebugName ) + { + return new CSplashParticle( pDebugName ); + } + + // Roll + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ); + + // Velocity + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + + // Alpha + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + + void SetClipHeight( float flClipHeight ); + + // Simulation + void SimulateParticles( CParticleSimulateIterator *pIterator ); + +private: + CSplashParticle( const CSplashParticle & ); + + float m_flClipHeight; + bool m_bUseClipHeight; +}; + +class WaterDebrisEffect : public CSimpleEmitter +{ +public: + WaterDebrisEffect( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static WaterDebrisEffect* Create( const char *pDebugName ); + + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + +private: + WaterDebrisEffect( const WaterDebrisEffect & ); +}; + +extern void FX_WaterRipple( const Vector &origin, float scale, Vector *pColor, float flLifetime=1.5, float flAlpha=1 ); +extern void FX_GunshotSplash( const Vector &origin, const Vector &normal, float scale ); +extern void FX_GunshotSlimeSplash( const Vector &origin, const Vector &normal, float scale ); + +//----------------------------------------------------------------------------- +// Purpose: Retrieve and alter lighting for splashes +// Input : position - point to check +// *color - tint of the lighting at this point +// *luminosity - adjusted luminosity at this point +//----------------------------------------------------------------------------- +inline void FX_GetSplashLighting( Vector position, Vector *color, float *luminosity ) +{ + // Compute our lighting at our position + Vector totalColor = engine->GetLightForPoint( position, true ); + + // Get our lighting information + UTIL_GetNormalizedColorTintAndLuminosity( totalColor, color, luminosity ); + + // Fake a specular highlight (too dim otherwise) + if ( luminosity != NULL ) + { + *luminosity = MIN( 1.0f, (*luminosity) * 4.0f ); + + // Clamp so that we never go completely translucent + if ( *luminosity < 0.25f ) + { + *luminosity = 0.25f; + } + } + + // Only take a quarter of the tint, mostly we want to be white + if ( color != NULL ) + { + (*color) = ( (*color) * 0.25f ) + Vector( 0.75f, 0.75f, 0.75f ); + } +} + +#include "tier0/memdbgoff.h" + +#endif // FX_WATER_H diff --git a/game/client/game_controls/IconPanel.h b/game/client/game_controls/IconPanel.h new file mode 100644 index 0000000..f9dcb24 --- /dev/null +++ b/game/client/game_controls/IconPanel.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICONPANEL_H +#define ICONPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +using namespace vgui; + +class CIconPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CIconPanel, vgui::Panel ); + +public: + CIconPanel( vgui::Panel *parent, const char *name ); + + void Init( void ); + virtual void Paint(); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + void SetIcon( const char *szIcon ); + void SetIconColor( Color cColor ) { m_IconColor = cColor; } + +private: + CHudTexture *m_icon; + char m_szIcon[128]; + + bool m_bScaleImage; + + CPanelAnimationVar( Color, m_IconColor, "iconColor", "255 255 255 255" ); +}; + +#endif //ICONPANEL_H \ No newline at end of file diff --git a/game/client/game_controls/NavProgress.h b/game/client/game_controls/NavProgress.h new file mode 100644 index 0000000..9cae369 --- /dev/null +++ b/game/client/game_controls/NavProgress.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef NAVPROGRESS_H +#define NAVPROGRESS_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +#include + +class CNavProgress : public vgui::Frame, public IViewPortPanel +{ +private: + DECLARE_CLASS_SIMPLE( CNavProgress, vgui::Frame ); + +public: + CNavProgress(IViewPort *pViewPort); + virtual ~CNavProgress(); + + virtual const char *GetName( void ) { return PANEL_NAV_PROGRESS; } + virtual void SetData(KeyValues *data); + virtual void Reset(); + virtual void Update(); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +public: + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void PerformLayout(); + void Init( const char *title, int numTicks, int currentTick ); + +protected: + IViewPort *m_pViewPort; + + int m_numTicks; + int m_currentTick; + + vgui::Label * m_pTitle; + vgui::Label * m_pText; + vgui::Panel * m_pProgressBarBorder; + vgui::Panel * m_pProgressBar; + vgui::Panel * m_pProgressBarSizer; +}; + +#endif // NAVPROGRESS_H diff --git a/game/client/game_controls/basemodel_panel.h b/game/client/game_controls/basemodel_panel.h new file mode 100644 index 0000000..a71bb7a --- /dev/null +++ b/game/client/game_controls/basemodel_panel.h @@ -0,0 +1,246 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#ifndef BASEMODEL_PANEL_H +#define BASEMODEL_PANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "matsys_controls/mdlpanel.h" + +//----------------------------------------------------------------------------- +// Resource file data used in posing the model inside of the model panel. +//----------------------------------------------------------------------------- +struct BMPResAnimData_t +{ + const char *m_pszName; + const char *m_pszSequence; + const char *m_pszActivity; + KeyValues *m_pPoseParameters; + bool m_bDefault; + + BMPResAnimData_t() + { + m_pszName = NULL; + m_pszSequence = NULL; + m_pszActivity = NULL; + m_pPoseParameters = NULL; + m_bDefault = false; + } + + ~BMPResAnimData_t() + { + if ( m_pszName && m_pszName[0] ) + { + delete [] m_pszName; + m_pszName = NULL; + } + + if ( m_pszSequence && m_pszSequence[0] ) + { + delete [] m_pszSequence; + m_pszSequence = NULL; + } + + if ( m_pszActivity && m_pszActivity[0] ) + { + delete [] m_pszActivity; + m_pszActivity = NULL; + } + + if ( m_pPoseParameters ) + { + m_pPoseParameters->deleteThis(); + m_pPoseParameters = NULL; + } + } +}; + +struct BMPResAttachData_t +{ + const char *m_pszModelName; + int m_nSkin; + + BMPResAttachData_t() + { + m_pszModelName = NULL; + m_nSkin = 0; + } + + ~BMPResAttachData_t() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + } +}; + +struct BMPResData_t +{ + float m_flFOV; + + const char *m_pszModelName; + const char *m_pszModelName_HWM; + const char *m_pszVCD; + QAngle m_angModelPoseRot; + Vector m_vecOriginOffset; + Vector m_vecFramedOriginOffset; + Vector2D m_vecViewportOffset; + int m_nSkin; + bool m_bUseSpotlight; + + CUtlVector m_aAnimations; + CUtlVector m_aAttachModels; + + BMPResData_t() + { + m_flFOV = 0.0f; + + m_pszModelName = NULL; + m_pszModelName_HWM = NULL; + m_pszVCD = NULL; + m_angModelPoseRot.Init(); + m_vecOriginOffset.Init(); + m_vecFramedOriginOffset.Init(); + m_vecViewportOffset.Init(); + m_nSkin = 0; + m_bUseSpotlight = false; + } + + ~BMPResData_t() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + + if ( m_pszModelName_HWM && m_pszModelName_HWM[0] ) + { + delete [] m_pszModelName_HWM; + m_pszModelName_HWM = NULL; + } + + if ( m_pszVCD && m_pszVCD[0] ) + { + delete [] m_pszVCD; + m_pszVCD = NULL; + } + + m_aAnimations.Purge(); + m_aAttachModels.Purge(); + } +}; + +//----------------------------------------------------------------------------- +// Base Model Panel +// +// ...vgui::Panel |--> vgui +// +->vgui::EditablePanel | +// +->PotterWheelPanel |--> matsys_controls +// +->MDLPanel | +// +->BaseModelPanel |--> game_controls, client.dll +// +//----------------------------------------------------------------------------- +class CBaseModelPanel : public CMDLPanel +{ + DECLARE_CLASS_SIMPLE( CBaseModelPanel, CMDLPanel ); + +public: + + // Constructor, Destructor. + CBaseModelPanel( vgui::Panel *pParent, const char *pName ); + virtual ~CBaseModelPanel(); + + // Overridden mdlpanel.h + virtual void SetMDL( MDLHandle_t handle, void *pProxyData = NULL ); + virtual void SetMDL( const char *pMDLName, void *pProxyData = NULL ); + virtual void SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos ); + + // Overridden methods of vgui::Panel + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void PerformLayout(); + + // Animation. + int FindDefaultAnim( void ); + int FindAnimByName( const char *pszName ); + void SetModelAnim( int iAnim ); + + // Manipulation. + virtual void OnKeyCodePressed ( vgui::KeyCode code ); + virtual void OnKeyCodeReleased( vgui::KeyCode code ); + virtual void OnMousePressed ( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + virtual void OnCursorMoved( int x, int y ); + virtual void OnMouseWheeled( int delta ); + + studiohdr_t* GetStudioHdr( void ) { return m_RootMDL.m_MDL.GetStudioHdr(); } + void SetBody( unsigned int nBody ) { m_RootMDL.m_MDL.m_nBody = nBody; } + + void RotateYaw( float flDelta ); + void RotatePitch( float flDelta ); + + Vector GetPlayerPos() const; + QAngle GetPlayerAngles() const; + + void LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax ); + + // Set to true if external code has set a specific camera position that shouldn't be clobbered by layout + void SetForcedCameraPosition( bool bForcedCameraPosition ) { m_bForcedCameraPosition = bForcedCameraPosition; } + + int FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity ); + +protected: + + // Resource file data. + void ParseModelResInfo( KeyValues *inResourceData ); + void ParseModelAnimInfo( KeyValues *inResourceData ); + void ParseModelAttachInfo( KeyValues *inResourceData ); + + void SetupModelDefaults( void ); + void SetupModelAnimDefaults( void ); + +public: + BMPResData_t m_BMPResData; // Base model panel data set in the .res file. + QAngle m_angPlayer; + Vector m_vecPlayerPos; + +protected: + bool m_bForcePos; + bool m_bMousePressed; + bool m_bAllowRotation; + bool m_bAllowPitch; + bool m_bAllowFullManipulation; + bool m_bApplyManipulators; + bool m_bForcedCameraPosition; + + // VGUI script accessible variables. + CPanelAnimationVar( bool, m_bStartFramed, "start_framed", "0" ); + CPanelAnimationVar( bool, m_bDisableManipulation, "disable_manipulation", "0" ); + CPanelAnimationVar( bool, m_bUseParticle, "use_particle", "0" ); + CPanelAnimationVar( float, m_flMaxPitch, "max_pitch", "90" ); + + struct particle_data_t + { + ~particle_data_t(); + + void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone = 0, const Vector& vecParticleOffset = vec3_origin ); + + bool m_bIsUpdateToDate; + CParticleCollection *m_pParticleSystem; + }; + CUtlVector< particle_data_t* > m_particleList; + + particle_data_t *CreateParticleData( const char *pszParticleName ); + bool SafeDeleteParticleData( particle_data_t **pData ); + + virtual void PrePaint3D( IMatRenderContext *pRenderContext ) OVERRIDE; + virtual void PostPaint3D( IMatRenderContext *pRenderContext ) OVERRIDE; +}; + +#endif // BASEMODEL_PANEL_H \ No newline at end of file diff --git a/game/client/game_controls/basemodelpanel.h b/game/client/game_controls/basemodelpanel.h new file mode 100644 index 0000000..76c0058 --- /dev/null +++ b/game/client/game_controls/basemodelpanel.h @@ -0,0 +1,233 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEMODELPANEL_H +#define BASEMODELPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include "GameEventListener.h" +#include "KeyValues.h" + +class C_SceneEntity; + + +class CModelPanelModel : public C_BaseFlex +{ +public: + CModelPanelModel(){} + DECLARE_CLASS( CModelPanelModel, C_BaseFlex ); + + virtual bool IsMenuModel() const{ return true; } +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanelModelAnimation +{ +public: + CModelPanelModelAnimation() + { + m_pszName = NULL; + m_pszSequence = NULL; + m_pszActivity = NULL; + m_pPoseParameters = NULL; + m_bDefault = false; + } + + ~CModelPanelModelAnimation() + { + if ( m_pszName && m_pszName[0] ) + { + delete [] m_pszName; + m_pszName = NULL; + } + + if ( m_pszSequence && m_pszSequence[0] ) + { + delete [] m_pszSequence; + m_pszSequence = NULL; + } + + if ( m_pszActivity && m_pszActivity[0] ) + { + delete [] m_pszActivity; + m_pszActivity = NULL; + } + + if ( m_pPoseParameters ) + { + m_pPoseParameters->deleteThis(); + m_pPoseParameters = NULL; + } + } + +public: + const char *m_pszName; + const char *m_pszSequence; + const char *m_pszActivity; + KeyValues *m_pPoseParameters; + bool m_bDefault; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanelAttachedModelInfo +{ +public: + CModelPanelAttachedModelInfo() + { + m_pszModelName = NULL; + m_nSkin = 0; + } + + ~CModelPanelAttachedModelInfo() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + } + +public: + const char *m_pszModelName; + int m_nSkin; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanelModelInfo +{ +public: + CModelPanelModelInfo() + { + m_pszModelName = NULL; + m_pszModelName_HWM = NULL; + m_nSkin = -1; + m_vecAbsAngles.Init(); + m_vecOriginOffset.Init(); + m_vecFramedOriginOffset.Init(); + m_bUseSpotlight = false; + } + + ~CModelPanelModelInfo() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + + if ( m_pszModelName_HWM && m_pszModelName_HWM[0] ) + { + delete [] m_pszModelName_HWM; + m_pszModelName_HWM = NULL; + } + + if ( m_pszVCD && m_pszVCD[0] ) + { + delete [] m_pszVCD; + m_pszVCD = NULL; + } + + m_Animations.PurgeAndDeleteElements(); + m_AttachedModelsInfo.PurgeAndDeleteElements(); + } + +public: + const char *m_pszModelName; + const char *m_pszModelName_HWM; + int m_nSkin; + const char *m_pszVCD; + Vector m_vecAbsAngles; + Vector m_vecOriginOffset; + Vector2D m_vecViewportOffset; + Vector m_vecFramedOriginOffset; + bool m_bUseSpotlight; + + CUtlVector m_Animations; + CUtlVector m_AttachedModelsInfo; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanel : public vgui::EditablePanel, public CGameEventListener +{ +public: + DECLARE_CLASS_SIMPLE( CModelPanel, vgui::EditablePanel ); + + CModelPanel( vgui::Panel *parent, const char *name ); + virtual ~CModelPanel(); + + virtual void Paint(); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void DeleteVCDData( void ); + virtual void DeleteModelData( void ); + + virtual void SetFOV( int nFOV ){ m_nFOV = nFOV; } + virtual void SetPanelDirty( void ){ m_bPanelDirty = true; } + virtual bool SetSequence( const char *pszSequence ); + + MESSAGE_FUNC_PARAMS( OnAddAnimation, "AddAnimation", data ); + MESSAGE_FUNC_PARAMS( OnSetAnimation, "SetAnimation", data ); + + void SetDefaultAnimation( const char *pszName ); + void SwapModel( const char *pszName, const char *pszAttached = NULL ); + + virtual void ParseModelInfo( KeyValues *inResourceData ); + + void ClearAttachedModelInfos( void ); + + void CalculateFrameDistance( void ); + void ZoomToFrameDistance( void ); + + void UpdateModel(); +public: // IGameEventListener: + virtual void FireGameEvent( IGameEvent * event ); + +protected: + virtual void SetupModel( void ); + virtual void SetupVCD( void ); + virtual const char *GetModelName( void ); + +private: + void InitCubeMaps(); + int FindAnimByName( const char *pszName ); + void CalculateFrameDistanceInternal( const model_t *pModel ); + +public: + int m_nFOV; + float m_flFrameDistance; + bool m_bStartFramed; + CModelPanelModelInfo *m_pModelInfo; + + CHandle m_hModel; + CUtlVector > m_AttachedModels; + + CHandle m_hScene; + +private: + bool m_bPanelDirty; + int m_iDefaultAnimation; + + bool m_bAllowOffscreen; + + CTextureReference m_DefaultEnvCubemap; + CTextureReference m_DefaultHDREnvCubemap; +}; + + +#endif // BASEMODELPANEL_H diff --git a/game/client/game_controls/baseviewport.h b/game/client/game_controls/baseviewport.h new file mode 100644 index 0000000..4e4c64e --- /dev/null +++ b/game/client/game_controls/baseviewport.h @@ -0,0 +1,148 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEAMFORTRESSVIEWPORT_H +#define TEAMFORTRESSVIEWPORT_H + +// viewport interface for the rest of the dll +#include + +#include // a vector based queue template to manage our VGUI menu queue +#include +#include "vguitextwindow.h" +#include "vgui/ISurface.h" +#include "commandmenu.h" +#include + +using namespace vgui; + +class IBaseFileSystem; +class IGameUIFuncs; +class IGameEventManager; + +//============================================================================== +class CBaseViewport : public vgui::EditablePanel, public IViewPort, public IGameEventListener2 +{ + DECLARE_CLASS_SIMPLE( CBaseViewport, vgui::EditablePanel ); + +public: + CBaseViewport(); + virtual ~CBaseViewport(); + + virtual IViewPortPanel* CreatePanelByName(const char *szPanelName); + virtual IViewPortPanel* FindPanelByName(const char *szPanelName); + virtual IViewPortPanel* GetActivePanel( void ); + virtual void RemoveAllPanels( void); + + virtual void ShowPanel( const char *pName, bool state ); + virtual void ShowPanel( IViewPortPanel* pPanel, bool state ); + virtual bool AddNewPanel( IViewPortPanel* pPanel, char const *pchDebugName ); + virtual void CreateDefaultPanels( void ); + virtual void UpdateAllPanels( void ); + virtual void PostMessageToPanel( const char *pName, KeyValues *pKeyValues ); + + virtual void Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 *pGameEventManager ); + virtual void SetParent(vgui::VPANEL parent); + + virtual void ReloadScheme(const char *fromFile); + virtual void ActivateClientUI(); + virtual void HideClientUI(); + virtual bool AllowedToPrintText( void ); + +#ifndef _XBOX + virtual int GetViewPortScheme() { return m_pBackGround->GetScheme(); } + virtual VPANEL GetViewPortPanel() { return m_pBackGround->GetVParent(); } +#endif + virtual AnimationController *GetAnimationController() { return m_pAnimController; } + + virtual void ShowBackGround(bool bShow) + { +#ifndef _XBOX + m_pBackGround->SetVisible( bShow ); +#endif + } + + virtual int GetDeathMessageStartHeight( void ); + + // virtual void ChatInputPosition( int *x, int *y ); + +public: // IGameEventListener: + virtual void FireGameEvent( IGameEvent * event); + + +protected: + + bool LoadHudAnimations( void ); + +#ifndef _XBOX + class CBackGroundPanel : public vgui::Frame + { + private: + typedef vgui::Frame BaseClass; + public: + CBackGroundPanel( vgui::Panel *parent) : Frame( parent, "ViewPortBackGround" ) + { + SetScheme("ClientScheme"); + + SetTitleBarVisible( false ); + SetMoveable(false); + SetSizeable(false); + SetProportional(true); + } + private: + + virtual void ApplySchemeSettings(IScheme *pScheme) + { + BaseClass::ApplySchemeSettings(pScheme); + SetBgColor(pScheme->GetColor("ViewportBG", Color( 0,0,0,0 ) )); + } + + virtual void PerformLayout() + { + int w,h; + GetHudSize(w, h); + + // fill the screen + SetBounds(0,0,w,h); + + BaseClass::PerformLayout(); + } + + virtual void OnMousePressed(MouseCode code) { }// don't respond to mouse clicks + virtual vgui::VPANEL IsWithinTraverse( int x, int y, bool traversePopups ) + { + return ( vgui::VPANEL )0; + } + + }; +#endif +protected: + + virtual void Paint(); + virtual void OnThink(); + virtual void OnScreenSizeChanged(int iOldWide, int iOldTall); + void PostMessageToPanel( IViewPortPanel* pPanel, KeyValues *pKeyValues ); + +protected: + IGameUIFuncs* m_GameuiFuncs; // for key binding details + IGameEventManager2* m_GameEventManager; +#ifndef _XBOX + CBackGroundPanel *m_pBackGround; +#endif + CUtlVector m_Panels; + + bool m_bHasParent; // Used to track if child windows have parents or not. + bool m_bInitialized; + IViewPortPanel *m_pActivePanel; + IViewPortPanel *m_pLastActivePanel; + vgui::HCursor m_hCursorNone; + vgui::AnimationController *m_pAnimController; + int m_OldSize[2]; +}; + + +#endif diff --git a/game/client/game_controls/buymenu.h b/game/client/game_controls/buymenu.h new file mode 100644 index 0000000..bdaff26 --- /dev/null +++ b/game/client/game_controls/buymenu.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BUYMENU_H +#define BUYMENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "vgui/KeyCode.h" + +class CBuySubMenu; + +namespace vgui +{ + class Panel; +} + +//----------------------------------------------------------------------------- +// Purpose: Draws the class menu +//----------------------------------------------------------------------------- +class CBuyMenu : public vgui::WizardPanel, public IViewPortPanel +{ +private: + DECLARE_CLASS_SIMPLE( CBuyMenu, vgui::WizardPanel ); + +public: + CBuyMenu(IViewPort *pViewPort); + ~CBuyMenu(); + + virtual const char *GetName( void ) { return PANEL_BUY; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset() {}; + virtual void Update(); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + + virtual void OnKeyCodePressed( vgui::KeyCode code ); + virtual void OnKeyCodeTyped( vgui::KeyCode code ); + +public: + virtual void OnClose(); + +protected: + + CBuySubMenu *m_pMainMenu; + IViewPort *m_pViewPort; + + int m_iTeam; + int m_iClass; +}; + + +#endif // BUYMENU_H diff --git a/game/client/game_controls/buysubmenu.h b/game/client/game_controls/buysubmenu.h new file mode 100644 index 0000000..f3b8c25 --- /dev/null +++ b/game/client/game_controls/buysubmenu.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BUYSUBMENU_H +#define BUYSUBMENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include "mouseoverpanelbutton.h" + +class CBuyMenu; + +//----------------------------------------------------------------------------- +// Purpose: Draws the class menu +//----------------------------------------------------------------------------- +class CBuySubMenu : public vgui::WizardSubPanel +{ +private: + DECLARE_CLASS_SIMPLE( CBuySubMenu, vgui::WizardSubPanel ); + +public: + CBuySubMenu(vgui::Panel *parent,const char *name = "BuySubMenu"); + ~CBuySubMenu(); + + virtual void SetVisible( bool state ); + virtual void DeleteSubPanels(); + +protected: + + // command callbacks + virtual void OnCommand( const char *command ); + virtual vgui::WizardSubPanel *GetNextSubPanel(); // this is the last menu in the list + virtual vgui::Panel *CreateControlByName(const char *controlName); + virtual CBuySubMenu* CreateNewSubMenu(); + virtual MouseOverPanelButton* CreateNewMouseOverPanelButton(vgui::EditablePanel *panel); + + typedef struct + { + char filename[_MAX_PATH]; + CBuySubMenu *panel; + } SubMenuEntry_t; + + vgui::EditablePanel *m_pPanel; + MouseOverPanelButton *m_pFirstButton; + + CUtlVector m_SubMenus; // a cache of buy submenus, so we don't need to construct them each time + + vgui::WizardSubPanel *m_NextPanel; +}; + +#endif // BUYSUBMENU_H diff --git a/game/client/game_controls/classmenu.h b/game/client/game_controls/classmenu.h new file mode 100644 index 0000000..1698855 --- /dev/null +++ b/game/client/game_controls/classmenu.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CLASSMENU_H +#define CLASSMENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "mouseoverpanelbutton.h" + +namespace vgui +{ + class TextEntry; +} + +//----------------------------------------------------------------------------- +// Purpose: Draws the class menu +//----------------------------------------------------------------------------- +class CClassMenu : public vgui::Frame, public IViewPortPanel +{ +private: + DECLARE_CLASS_SIMPLE( CClassMenu, vgui::Frame ); + +public: + CClassMenu(IViewPort *pViewPort); + CClassMenu(IViewPort *pViewPort, const char *panelName ); + virtual ~CClassMenu(); + + virtual const char *GetName( void ) { return PANEL_CLASS; } + virtual void SetData(KeyValues *data); + virtual void Reset(); + virtual void Update() {}; + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +protected: + + virtual vgui::Panel *CreateControlByName(const char *controlName); + virtual MouseOverPanelButton* CreateNewMouseOverPanelButton(vgui::EditablePanel *panel); + + //vgui2 overrides + virtual void OnKeyCodePressed(vgui::KeyCode code); + + // helper functions + void SetLabelText(const char *textEntryName, const char *text); + void SetVisibleButton(const char *textEntryName, bool state); + + // command callbacks + void OnCommand( const char *command ); + + IViewPort *m_pViewPort; + ButtonCode_t m_iScoreBoardKey; + int m_iTeam; + vgui::EditablePanel *m_pPanel; + + CUtlVector< MouseOverPanelButton * > m_mouseoverButtons; +}; + + +#endif // CLASSMENU_H diff --git a/game/client/game_controls/clientscoreboarddialog.h b/game/client/game_controls/clientscoreboarddialog.h new file mode 100644 index 0000000..210934d --- /dev/null +++ b/game/client/game_controls/clientscoreboarddialog.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CLIENTSCOREBOARDDIALOG_H +#define CLIENTSCOREBOARDDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "GameEventListener.h" + +#define TYPE_NOTEAM 0 // NOTEAM must be zero :) +#define TYPE_TEAM 1 // a section for a single team +#define TYPE_PLAYERS 2 +#define TYPE_SPECTATORS 3 // a section for a spectator group +#define TYPE_BLANK 4 + + +//----------------------------------------------------------------------------- +// Purpose: Game ScoreBoard +//----------------------------------------------------------------------------- +class CClientScoreBoardDialog : public vgui::EditablePanel, public IViewPortPanel, public CGameEventListener +{ +private: + DECLARE_CLASS_SIMPLE( CClientScoreBoardDialog, vgui::EditablePanel ); + +protected: +// column widths at 640 + enum { NAME_WIDTH = 160, SCORE_WIDTH = 60, DEATH_WIDTH = 60, PING_WIDTH = 80, VOICE_WIDTH = 0, FRIENDS_WIDTH = 0 }; + // total = 340 + +public: + CClientScoreBoardDialog( IViewPort *pViewPort ); + ~CClientScoreBoardDialog(); + + virtual const char *GetName( void ) { return PANEL_SCOREBOARD; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset(); + virtual void Update(); + virtual bool NeedsUpdate( void ); + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + virtual bool ShowAvatars() + { +#ifdef CSS_PERF_TEST + return false; +#endif + return IsPC(); + } + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + + // IGameEventListener interface: + virtual void FireGameEvent( IGameEvent *event); + + virtual void UpdatePlayerAvatar( int playerIndex, KeyValues *kv ); + +protected: + MESSAGE_FUNC_INT( OnPollHideCode, "PollHideCode", code ); + + // functions to override + virtual bool GetPlayerScoreInfo(int playerIndex, KeyValues *outPlayerInfo); + virtual void InitScoreboardSections(); + virtual void UpdateTeamInfo(); + virtual void UpdatePlayerInfo(); + virtual void OnThink(); + virtual void AddHeader(); // add the start header of the scoreboard + virtual void AddSection(int teamType, int teamNumber); // add a new section header for a team + virtual int GetAdditionalHeight() { return 0; } + + // sorts players within a section + static bool StaticPlayerSortFunc(vgui::SectionedListPanel *list, int itemID1, int itemID2); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + virtual void PostApplySchemeSettings( vgui::IScheme *pScheme ); + + // finds the player in the scoreboard + int FindItemIDForPlayerIndex(int playerIndex); + + int m_iNumTeams; + + vgui::SectionedListPanel *m_pPlayerList; + int m_iSectionId; // the current section we are entering into + + int s_VoiceImage[5]; + int TrackerImage; + int m_HLTVSpectators; + int m_ReplaySpectators; + float m_fNextUpdateTime; + + void MoveLabelToFront(const char *textEntryName); + void MoveToCenterOfScreen(); + + vgui::ImageList *m_pImageList; + CUtlMap m_mapAvatarsToImageList; + + CPanelAnimationVar( int, m_iAvatarWidth, "avatar_width", "34" ); // Avatar width doesn't scale with resolution + CPanelAnimationVarAliasType( int, m_iNameWidth, "name_width", "136", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iClassWidth, "class_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iScoreWidth, "score_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iDeathWidth, "death_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iPingWidth, "ping_width", "23", "proportional_int" ); + +private: + int m_iPlayerIndexSymbol; + int m_iDesiredHeight; + IViewPort *m_pViewPort; + ButtonCode_t m_nCloseKey; + + + // methods + void FillScoreBoard(); +}; + + +#endif // CLIENTSCOREBOARDDIALOG_H diff --git a/game/client/game_controls/commandmenu.h b/game/client/game_controls/commandmenu.h new file mode 100644 index 0000000..9f80049 --- /dev/null +++ b/game/client/game_controls/commandmenu.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + + +#ifndef COMMANDMENU_H +#define COMMANDMENU_H + +#include +#include +#include +#include "utlstack.h" +#include "utlvector.h" +#include + +using namespace vgui; + +class CommandMenu : public Menu +{ +private: + DECLARE_CLASS_SIMPLE( CommandMenu, Menu ); + + typedef struct + { + Menu * menu; + int itemnr; + } CommandMenuItem; + + public: + CommandMenu( Panel *parent, const char *panelName, IViewPort * viewport ); + ~CommandMenu(); + + bool LoadFromFile(const char * fileName); // load menu from file (via KeyValues) + void UpdateMenu(); // call to update all menu items, check buttons etc + void RebuildMenu(); // rebuilds menu respecting changed game state (map, team etc) + void ClearMenu(); // destroy menu + + public: + // overwrite these in your derived class + // virtual CommandMenu * CommandMenu::Factory(Panel *parent, const char *panelName, IViewPort * viewport = NULL, IFileSystem * pFileSytem = NULL); // overwrite + virtual int AddCustomItem(KeyValues * params, Menu * menu) {return 0;} // return MenuItem nr + virtual void UpdateCustomItem(KeyValues * params, MenuItem * item ) {}; // maybe change your item + virtual void OnCustomItem(KeyValues * params) {}; // a custom item was pressed + virtual bool CheckRules(const char *rule, const char *ruledata); // check a menu item rule + virtual void SetVisible(bool state); + + // DON'T touch anything below ! + + protected: + + void OnMessage(const KeyValues *params, VPANEL fromPanel); + void StartNewSubMenu(KeyValues * params); + void FinishSubMenu(); + void AddMenuCommandItem(KeyValues * params); + void AddMenuCustomItem(KeyValues * params); + void AddMenuToggleItem(KeyValues * params); + bool LoadFromKeyValuesInternal(KeyValues * key, int depth); + bool LoadFromKeyValues( KeyValues * key); // + + KeyValues * GetKeyValues(); // returns keyValues for current menu or NULL + + + IViewPort * m_ViewPort; // viewport interface + Menu * m_CurrentMenu; // Current menu while building CommandComoboBox + char m_CurrentTeam[4]; + char m_CurrentMap[256]; + + KeyValues* m_MenuKeys; + + CUtlStackm_pMenuStack; + CUtlVectorm_MenuItems; +}; + +#endif // COMMANDMENU_H \ No newline at end of file diff --git a/game/client/game_controls/imagemouseoverbutton.h b/game/client/game_controls/imagemouseoverbutton.h new file mode 100644 index 0000000..9dee5d7 --- /dev/null +++ b/game/client/game_controls/imagemouseoverbutton.h @@ -0,0 +1,256 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMAGE_MOUSE_OVER_BUTTON_H +#define IMAGE_MOUSE_OVER_BUTTON_H + +#include "vgui/ISurface.h" +#include "vgui/IScheme.h" +#include "mouseoverpanelbutton.h" + +//=============================================== +// CImageMouseOverButton - used for class images +//=============================================== + +template +class CImageMouseOverButton : public MouseOverButton +{ +private: + //DECLARE_CLASS_SIMPLE( CImageMouseOverButton, MouseOverButton ); + +public: + CImageMouseOverButton( vgui::Panel *parent, const char *panelName, T *templatePanel ); + + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnSizeChanged( int newWide, int newTall ); + + void RecalculateImageSizes( void ); + void SetActiveImage( const char *imagename ); + void SetInactiveImage( const char *imagename ); + void SetActiveImage( vgui::IImage *image ); + void SetInactiveImage( vgui::IImage *image ); + +public: + virtual void Paint(); + virtual void ShowPage( void ); + virtual void HidePage( void ); + +private: + vgui::IImage *m_pActiveImage; + char *m_pszActiveImageName; + + vgui::IImage *m_pInactiveImage; + char *m_pszInactiveImageName; + + bool m_bScaleImage; +}; + +template +CImageMouseOverButton::CImageMouseOverButton( vgui::Panel *parent, const char *panelName, T *templatePanel ) : + MouseOverButton( parent, panelName, templatePanel ) +{ + m_pszActiveImageName = NULL; + m_pszInactiveImageName = NULL; + + m_pActiveImage = NULL; + m_pInactiveImage = NULL; +} + +template +void CImageMouseOverButton::ApplySettings( KeyValues *inResourceData ) +{ + m_bScaleImage = inResourceData->GetInt( "scaleImage", 0 ); + + // Active Image + delete [] m_pszActiveImageName; + m_pszActiveImageName = NULL; + + const char *activeImageName = inResourceData->GetString( "activeimage", "" ); + if ( *activeImageName ) + { + this->SetActiveImage( activeImageName ); + } + + // Inactive Image + delete [] m_pszInactiveImageName; + m_pszInactiveImageName = NULL; + + const char *inactiveImageName = inResourceData->GetString( "inactiveimage", "" ); + if ( *inactiveImageName ) + { + this->SetInactiveImage( inactiveImageName ); + } + + MouseOverButton::ApplySettings( inResourceData ); + + this->InvalidateLayout( false, true ); // force applyschemesettings to run +} + +template +void CImageMouseOverButton::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + MouseOverButton::ApplySchemeSettings( pScheme ); + + if ( m_pszActiveImageName && strlen( m_pszActiveImageName ) > 0 ) + { + this->SetActiveImage( vgui::scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) ); + } + + if ( m_pszInactiveImageName && strlen( m_pszInactiveImageName ) > 0 ) + { + this->SetInactiveImage( vgui::scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) ); + } + + vgui::IBorder *pBorder = pScheme->GetBorder( "NoBorder" ); + this->SetDefaultBorder( pBorder); + this->SetDepressedBorder( pBorder ); + this->SetKeyFocusBorder( pBorder ); + + Color blank(0,0,0,0); + this->SetDefaultColor( this->GetButtonFgColor(), blank ); + this->SetArmedColor( this->GetButtonArmedFgColor(), blank ); + this->SetDepressedColor( this->GetButtonDepressedFgColor(), blank ); +} + +template +void CImageMouseOverButton::RecalculateImageSizes( void ) +{ + // Reset our images, which will force them to recalculate their size. + // Necessary for images shared with other scaling buttons. + this->SetActiveImage( m_pActiveImage ); + this->SetInactiveImage( m_pInactiveImage ); +} + +template +void CImageMouseOverButton::SetActiveImage( const char *imagename ) +{ + int len = Q_strlen( imagename ) + 1; + m_pszActiveImageName = new char[ len ]; + Q_strncpy( m_pszActiveImageName, imagename, len ); +} + +template +void CImageMouseOverButton::SetInactiveImage( const char *imagename ) +{ + int len = Q_strlen( imagename ) + 1; + m_pszInactiveImageName = new char[ len ]; + Q_strncpy( m_pszInactiveImageName, imagename, len ); +} + +template +void CImageMouseOverButton::SetActiveImage( vgui::IImage *image ) +{ + m_pActiveImage = image; + + if ( m_pActiveImage ) + { + int wide, tall; + if ( m_bScaleImage ) + { + // scaling, force the image size to be our size + this->GetSize( wide, tall ); + m_pActiveImage->SetSize( wide, tall ); + } + else + { + // not scaling, so set our size to the image size + m_pActiveImage->GetSize( wide, tall ); + this->SetSize( wide, tall ); + } + } + + this->Repaint(); +} + +template +void CImageMouseOverButton::SetInactiveImage( vgui::IImage *image ) +{ + m_pInactiveImage = image; + + if ( m_pInactiveImage ) + { + int wide, tall; + if ( m_bScaleImage) + { + // scaling, force the image size to be our size + this->GetSize( wide, tall ); + m_pInactiveImage->SetSize( wide, tall ); + } + else + { + // not scaling, so set our size to the image size + m_pInactiveImage->GetSize( wide, tall ); + this->SetSize( wide, tall ); + } + } + + this->Repaint(); +} + +template +void CImageMouseOverButton::OnSizeChanged( int newWide, int newTall ) +{ + if ( m_bScaleImage ) + { + // scaling, force the image size to be our size + + if ( m_pActiveImage ) + m_pActiveImage->SetSize( newWide, newTall ); + + if ( m_pInactiveImage ) + m_pInactiveImage->SetSize( newWide, newTall ); + } + MouseOverButton::OnSizeChanged( newWide, newTall ); +} + +template +void CImageMouseOverButton::Paint() +{ + this->SetActiveImage( m_pActiveImage ); + this->SetInactiveImage( m_pInactiveImage ); + + if ( this->IsArmed() ) + { + // draw the active image + if ( m_pActiveImage ) + { + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + m_pActiveImage->SetPos( 0, 0 ); + m_pActiveImage->Paint(); + } + } + else + { + // draw the inactive image + if ( m_pInactiveImage ) + { + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + m_pInactiveImage->SetPos( 0, 0 ); + m_pInactiveImage->Paint(); + } + } + + MouseOverButton::Paint(); +} + +template +void CImageMouseOverButton::ShowPage( void ) +{ + MouseOverButton::ShowPage(); + + // send message to parent that we triggered something + this->PostActionSignal( new KeyValues( "ShowPage", "page", this->GetName() ) ); +} + +template +void CImageMouseOverButton::HidePage( void ) +{ + MouseOverButton::HidePage(); +} + +#endif //IMAGE_MOUSE_OVER_BUTTON_H \ No newline at end of file diff --git a/game/client/game_controls/intromenu.h b/game/client/game_controls/intromenu.h new file mode 100644 index 0000000..02043ec --- /dev/null +++ b/game/client/game_controls/intromenu.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef INTROMENU_H +#define INTROMENU_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include +#include + +#include + +namespace vgui +{ + class TextEntry; +} + +class CIntroMenu : public vgui::Frame, public IViewPortPanel +{ +private: + DECLARE_CLASS_SIMPLE( CIntroMenu, vgui::Frame ); + +public: + CIntroMenu( IViewPort *pViewPort ); + virtual ~CIntroMenu(); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + virtual const char *GetName( void ){ return PANEL_INTRO; } + virtual void SetData( KeyValues *data ){ return; } + virtual void Reset(); + virtual void Update(); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +protected: + // vgui overrides + virtual void OnCommand( const char *command ); + + IViewPort *m_pViewPort; + vgui::Label *m_pTitleLabel; +}; + +#endif // INTROMENU_H diff --git a/game/client/game_controls/mapoverview.h b/game/client/game_controls/mapoverview.h new file mode 100644 index 0000000..edaa2d1 --- /dev/null +++ b/game/client/game_controls/mapoverview.h @@ -0,0 +1,275 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: MiniMap.h: interface for the CMiniMap class. +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined HLTVPANEL_H +#define HLTVPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "mathlib/vector.h" +#include +#include +#include +#include "hudelement.h" + +class IMapOverviewPanel +{ +public: + virtual void SetMode( int mode ) = 0; + virtual int GetMode( void ) = 0; + virtual void FlashEntity( int entityID ) = 0; + virtual void SetPlayerPositions(int index, const Vector &position, const QAngle &angle) = 0; + virtual void SetVisible(bool state) = 0; + virtual float GetZoom( void ) = 0; + virtual vgui::Panel *GetAsPanel() = 0; + virtual bool AllowConCommandsWhileAlive() = 0; + virtual void SetPlayerPreferredMode( int mode ) = 0; + virtual void SetPlayerPreferredViewSize( float viewSize ) = 0; + virtual bool IsVisible() = 0; + virtual void GetBounds(int &x, int &y, int &wide, int &tall) = 0; + virtual float GetFullZoom( void ) = 0; + virtual float GetMapScale( void ) = 0; +}; + +#define MAX_TRAIL_LENGTH 30 +#define OVERVIEW_MAP_SIZE 1024 // an overview map is 1024x1024 pixels + +typedef bool ( *FnCustomMapOverviewObjectPaint )( int textureID, Vector pos, float scale, float angle, const char *text, Color *textColor, float status, Color *statusColor ); + + +class CMapOverview : public CHudElement, public vgui::Panel, public IMapOverviewPanel +{ + DECLARE_CLASS_SIMPLE( CMapOverview, vgui::Panel ); + +public: + + enum + { + MAP_MODE_OFF = 0, // Totally off + MAP_MODE_INSET, // A little map up in a corner + MAP_MODE_FULL, // Full screen, full map + MAP_MODE_RADAR // In game radar, extra functionality + }; + + CMapOverview( const char *pElementName ); + virtual ~CMapOverview(); + + virtual bool ShouldDraw( void ); + vgui::Panel *GetAsPanel(){ return this; } + virtual bool AllowConCommandsWhileAlive(){return true;} + virtual void SetPlayerPreferredMode( int mode ){} + virtual void SetPlayerPreferredViewSize( float viewSize ){}; + +protected: // private structures & types + + float GetViewAngle( void ); // The angle that determines the viewport twist from map texture to panel drawing. + + // list of game events the hLTV takes care of + + typedef struct { + int xpos; + int ypos; + } FootStep_t; + + typedef struct MapPlayer_s { + int index; // player's index + int userid; // user ID on server + int icon; // players texture icon ID + Color color; // players team color + char name[MAX_PLAYER_NAME_LENGTH]; + int team; // N,T,CT + int health; // 0..100, 7 bit + Vector position; // current x,y pos + QAngle angle; // view origin 0..360 + Vector2D trail[MAX_TRAIL_LENGTH]; // save 1 footstep each second for 1 minute + } MapPlayer_t; + + typedef struct MapObject_s { + int objectID; // unique object ID + int index; // entity index if any + int icon; // players texture icon ID + Color color; // players team color + char name[MAX_PLAYER_NAME_LENGTH]; // show text under icon + Vector position; // current x,y pos + QAngle angle; // view origin 0..360 + float endtime; // time stop showing object + float size; // object size + float status; // green status bar [0..1], -1 = disabled + Color statusColor; // color of status bar + int flags; // MAB_OBJECT_* + const char *text; // text to draw underneath the icon + } MapObject_t; + +#define MAP_OBJECT_ALIGN_TO_MAP (1<<0) + +public: // IViewPortPanel interface: + + virtual const char *GetName( void ) { return PANEL_OVERVIEW; } + virtual void SetData(KeyValues *data); + virtual void Reset(); + virtual void OnThink(); + virtual void Update(); + virtual bool NeedsUpdate( void ); + virtual bool HasInputElements( void ) { return false; } + virtual void ShowPanel( bool bShow ); + virtual void Init( void ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void GetBounds(int &x, int &y, int &wide, int &tall) { BaseClass::GetBounds(x, y, wide, tall); } + virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); } + +public: // IGameEventListener + + virtual void FireGameEvent( IGameEvent *event); + +public: // VGUI overrides + + virtual void Paint(); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void ApplySchemeSettings(vgui::IScheme *scheme); + virtual void SetVisible(bool state){BaseClass::SetVisible(state);} + +public: + + virtual float GetZoom( void ); + virtual int GetMode( void ); + virtual float GetFullZoom( void ){ return m_fFullZoom; } + virtual float GetMapScale( void ){ return m_fMapScale; } + + // Player settings: + virtual void ShowPlayerNames(bool state); + virtual void ShowPlayerHealth(bool state); + virtual void ShowPlayerTracks(float seconds); + virtual void SetPlayerPositions(int index, const Vector &position, const QAngle &angle); + + // general settings: + virtual void SetMap(const char * map); + virtual void SetTime( float time ); + virtual void SetMode( int mode ); + virtual bool SetTeamColor(int team, Color color); + virtual void SetFollowAngle(bool state); + virtual void SetFollowEntity(int entindex); // 0 = off + virtual void SetCenter( const Vector2D &mappos); + virtual void SetAngle( float angle); + virtual Vector2D WorldToMap( const Vector &worldpos ); + + // Object settings + virtual int AddObject( const char *icon, int entity, float timeToLive ); // returns object ID, 0 = no entity, -1 = forever + virtual void SetObjectIcon( int objectID, const char *icon, float size ); // icon world size + virtual void SetObjectText( int objectID, const char *text, Color color ); // text under icon + virtual void SetObjectStatus( int objectID, float value, Color statusColor ); // status bar under icon + virtual void SetObjectPosition( int objectID, const Vector &position, const QAngle &angle ); // world pos/angles + virtual void AddObjectFlags( int objectID, int flags ); + virtual void SetObjectFlags( int objectID, int flags ); + virtual void RemoveObject( int objectID ); + virtual void RemoveObjectByIndex( int index ); + virtual void FlashEntity( int entityID ){} + + // rules that define if you can see a player on the overview or not + virtual bool CanPlayerBeSeen(MapPlayer_t *player); + + /// allows mods to restrict health + virtual bool CanPlayerHealthBeSeen(MapPlayer_t *player); + + /// allows mods to restrict names (e.g. CS when mp_playerid is non-zero) + virtual bool CanPlayerNameBeSeen(MapPlayer_t *player); + + virtual int GetIconNumberFromTeamNumber( int teamNumber ){return teamNumber;} + +protected: + + virtual void DrawCamera(); + virtual void DrawObjects(); + virtual void DrawMapTexture(); + virtual void DrawMapPlayers(); + virtual void DrawMapPlayerTrails(); + virtual void UpdatePlayerTrails(); + virtual void ResetRound(); + virtual void InitTeamColorsAndIcons(); + virtual void UpdateSizeAndPosition(); + virtual bool RunHudAnimations(){ return true; } + + bool IsInPanel(Vector2D &pos); + MapPlayer_t* GetPlayerByUserID( int userID ); + int AddIconTexture(const char *filename); + Vector2D MapToPanel( const Vector2D &mappos ); + int GetPixelOffset( float height ); + void UpdateFollowEntity(); + virtual void UpdatePlayers(); + void UpdateObjects(); // objects bound to entities + MapObject_t* FindObjectByID(int objectID); + virtual bool IsRadarLocked() {return false;} + + virtual bool DrawIcon( MapObject_t *obj ); + + /*virtual bool DrawIcon( int textureID, + int offscreenTextureID, + Vector pos, + float scale, + float angle, + int alpha = 255, + const char *text = NULL, + Color *textColor = NULL, + float status = -1, + Color *statusColor = NULL, + int objectType = OBJECT_TYPE_NORMAL );*/ + + int m_nMode; + Vector2D m_vPosition; + Vector2D m_vSize; + float m_flChangeSpeed; + float m_flIconSize; + + + IViewPort * m_pViewPort; + MapPlayer_t m_Players[MAX_PLAYERS]; + CUtlDict< int, int> m_TextureIDs; + CUtlVector m_Objects; + + Color m_TeamColors[MAX_TEAMS]; + int m_TeamIcons[MAX_TEAMS]; + int m_ObjectIcons[64]; + int m_ObjectCounterID; + vgui::HFont m_hIconFont; + + + bool m_bShowNames; + bool m_bShowTrails; + bool m_bShowHealth; + + int m_nMapTextureID; // texture id for current overview image + + KeyValues * m_MapKeyValues; // keyvalues describing overview parameters + + Vector m_MapOrigin; // read from KeyValues files + float m_fMapScale; // origin and scale used when screenshot was made + bool m_bRotateMap; // if true roatate map around 90 degress, so it fits better to 4:3 screen ratio + + int m_nFollowEntity;// entity number to follow, 0 = off + CPanelAnimationVar( float, m_fZoom, "zoom", "1.0" ); // current zoom n = overview panel shows 1/n^2 of whole map' + float m_fFullZoom; // best zoom factor for full map view (1.0 is map is a square) + Vector2D m_ViewOrigin; // map coordinates that are in the center of the pverview panel + Vector2D m_MapCenter; // map coordinates that are in the center of the pverview panel + + float m_fNextUpdateTime; + float m_fViewAngle; // rotation of overview map + float m_fWorldTime; // current world time + float m_fNextTrailUpdate; // next time to update player trails + float m_fTrailUpdateInterval; // if -1 don't show trails + bool m_bFollowAngle; // if true, map rotates with view angle + + +}; + +extern IMapOverviewPanel *g_pMapOverview; + +#endif // diff --git a/game/client/game_controls/mouseoverhtmlbutton.h b/game/client/game_controls/mouseoverhtmlbutton.h new file mode 100644 index 0000000..e380083 --- /dev/null +++ b/game/client/game_controls/mouseoverhtmlbutton.h @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MOUSEOVERHTMLBUTTON_H +#define MOUSEOVERHTMLBUTTON_H +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Purpose: Triggers a new html page when the mouse goes over the button +//----------------------------------------------------------------------------- +class MouseOverHTMLButton : public vgui::Button +{ +public: + MouseOverHTMLButton(vgui::Panel *parent, const char *panelName, vgui::HTML *html, const char *page) : + Button( parent, panelName, "MouseOverHTMLButton") + { + m_pHTML = html; + m_iClass = 0; + m_iIndex = -1; + m_bAddShortCut = true; + if ( page ) + { + Q_strncpy( m_sPage, page, sizeof( m_sPage ) ); + } + else + { + memset(m_sPage, 0x0, sizeof( m_sPage ) ); + } + } + + void SetClass(int pClass, int index) { m_iClass = pClass; m_iIndex = index;} + int GetClass() { return m_iClass; } + + void SetAddHotKey( bool state ) { m_bAddShortCut = state; } + + void SetPage( const char *page ) + { + if ( page ) + { + Q_strncpy( m_sPage, page, sizeof( m_sPage ) ); + } + else + { + memset(m_sPage, 0x0, sizeof( m_sPage ) ); + } + } + + void SetHTML( vgui::HTML *html) + { + m_pHTML = html; + } + + +private: + + virtual void OnCursorEntered() + { + Button::OnCursorEntered(); + if ( m_pHTML && strlen(m_sPage) > 0 ) + { + m_pHTML->OpenURL(m_sPage); + } + } + + virtual void SetText(const char *text) + { + if ( m_iIndex != -1 ) + { + wchar_t newText[ 128 ]; + wchar_t localizeText[ 128 ]; + wchar_t *ansiLocal; + if ( text[0] == '#' && ( ansiLocal = g_pVGuiLocalize->Find( text ) ) ) + { + // wcsncpy will crash if ansiLocal is null... *sigh* + wcsncpy(localizeText, ansiLocal, sizeof(localizeText)/sizeof(wchar_t)); + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( text, localizeText, sizeof( localizeText ) ); + } + + if ( m_bAddShortCut ) + { +#ifdef WIN32 + _snwprintf( newText, sizeof( newText )/ sizeof( wchar_t ), L"&%i %s", m_iIndex, localizeText); +#else + _snwprintf( newText, sizeof( newText )/ sizeof( wchar_t ), L"&%i %S", m_iIndex, localizeText); +#endif + + } + else + { + memcpy( newText, localizeText, sizeof( newText ) ); + } + + Button::SetText( newText ); + } + else + { + Button::SetText( text ); + } + } + + vgui::HTML *m_pHTML; + char m_sPage[ 255 ]; + int m_iClass; + int m_iIndex; + bool m_bAddShortCut; +}; + + +#endif // MOUSEOVERHTMLBUTTON_H diff --git a/game/client/game_controls/mouseoverpanelbutton.h b/game/client/game_controls/mouseoverpanelbutton.h new file mode 100644 index 0000000..9e4e245 --- /dev/null +++ b/game/client/game_controls/mouseoverpanelbutton.h @@ -0,0 +1,186 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MOUSEOVERPANELBUTTON_H +#define MOUSEOVERPANELBUTTON_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include + +extern vgui::Panel *g_lastPanel; +extern vgui::Button *g_lastButton; + +//----------------------------------------------------------------------------- +// Purpose: Triggers a new panel when the mouse goes over the button +// +// the new panel has the same dimensions as the passed templatePanel and is of +// the same class. +// +// must at least inherit from vgui::EditablePanel to support LoadControlSettings +//----------------------------------------------------------------------------- +template +class MouseOverButton : public vgui::Button +{ +private: + DECLARE_CLASS_SIMPLE( MouseOverButton, vgui::Button ); + +public: + MouseOverButton(vgui::Panel *parent, const char *panelName, T *templatePanel ) : + Button( parent, panelName, "MouseOverButton") + { + m_pPanel = new T( parent, NULL ); + m_pPanel ->SetVisible( false ); + + // copy size&pos from template panel + int x,y,wide,tall; + templatePanel->GetBounds( x, y, wide, tall ); + m_pPanel->SetBounds( x, y, wide, tall ); + int px, py; + templatePanel->GetPinOffset( px, py ); + int rx, ry; + templatePanel->GetResizeOffset( rx, ry ); + // Apply pin settings from template, too + m_pPanel->SetAutoResize( templatePanel->GetPinCorner(), templatePanel->GetAutoResize(), px, py, rx, ry ); + + m_bPreserveArmedButtons = false; + m_bUpdateDefaultButtons = false; + } + + virtual void SetPreserveArmedButtons( bool bPreserve ){ m_bPreserveArmedButtons = bPreserve; } + virtual void SetUpdateDefaultButtons( bool bUpdate ){ m_bUpdateDefaultButtons = bUpdate; } + + virtual void ShowPage() + { + if( m_pPanel ) + { + m_pPanel->SetVisible( true ); + m_pPanel->MoveToFront(); + g_lastPanel = m_pPanel; + } + } + + virtual void HidePage() + { + if ( m_pPanel ) + { + m_pPanel->SetVisible( false ); + } + } + + const char *GetClassPage( const char *className ) + { + static char classPanel[ _MAX_PATH ]; + Q_snprintf( classPanel, sizeof( classPanel ), "classes/%s.res", className); + + if ( g_pFullFileSystem->FileExists( classPanel, IsX360() ? "MOD" : "GAME" ) ) + { + } + else if (g_pFullFileSystem->FileExists( "classes/default.res", IsX360() ? "MOD" : "GAME" ) ) + { + Q_snprintf ( classPanel, sizeof( classPanel ), "classes/default.res" ); + } + else + { + return NULL; + } + + return classPanel; + } + +#ifdef REFRESH_CLASSMENU_TOOL + + void RefreshClassPage( void ) + { + m_pPanel->LoadControlSettings( GetClassPage( GetName() ) ); + } + +#endif + + virtual void ApplySettings( KeyValues *resourceData ) + { + BaseClass::ApplySettings( resourceData ); + + // name, position etc of button is set, now load matching + // resource file for associated info panel: + m_pPanel->LoadControlSettings( GetClassPage( GetName() ) ); + } + + T *GetClassPanel( void ) { return m_pPanel; } + + virtual void OnCursorExited() + { + if ( !m_bPreserveArmedButtons ) + { + BaseClass::OnCursorExited(); + } + } + + virtual void OnCursorEntered() + { + BaseClass::OnCursorEntered(); + + if ( !IsEnabled() ) + return; + + // are we updating the default buttons? + if ( m_bUpdateDefaultButtons ) + { + SetAsDefaultButton( 1 ); + } + + // are we preserving the armed state (and need to turn off the old button)? + if ( m_bPreserveArmedButtons ) + { + if ( g_lastButton && g_lastButton != this ) + { + g_lastButton->SetArmed( false ); + } + + g_lastButton = this; + } + + // turn on our panel (if it isn't already) + if ( m_pPanel && ( !m_pPanel->IsVisible() ) ) + { + // turn off the previous panel + if ( g_lastPanel && g_lastPanel->IsVisible() ) + { + g_lastPanel->SetVisible( false ); + } + + ShowPage(); + } + } + + virtual void OnKeyCodeReleased( vgui::KeyCode code ) + { + BaseClass::OnKeyCodeReleased( code ); + + if ( m_bPreserveArmedButtons ) + { + if ( g_lastButton ) + { + g_lastButton->SetArmed( true ); + } + } + } + +private: + + T *m_pPanel; + bool m_bPreserveArmedButtons; + bool m_bUpdateDefaultButtons; +}; + +#define MouseOverPanelButton MouseOverButton + +#endif // MOUSEOVERPANELBUTTON_H diff --git a/game/client/game_controls/spectatorgui.h b/game/client/game_controls/spectatorgui.h new file mode 100644 index 0000000..2962608 --- /dev/null +++ b/game/client/game_controls/spectatorgui.h @@ -0,0 +1,154 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SPECTATORGUI_H +#define SPECTATORGUI_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "GameEventListener.h" + +#include + +class KeyValues; + +namespace vgui +{ + class TextEntry; + class Button; + class Panel; + class ImagePanel; + class ComboBox; +} + +#define BLACK_BAR_COLOR Color(0, 0, 0, 196) + +class IBaseFileSystem; + +//----------------------------------------------------------------------------- +// Purpose: Spectator UI +//----------------------------------------------------------------------------- +class CSpectatorGUI : public vgui::EditablePanel, public IViewPortPanel +{ + DECLARE_CLASS_SIMPLE( CSpectatorGUI, vgui::EditablePanel ); + +public: + CSpectatorGUI( IViewPort *pViewPort ); + virtual ~CSpectatorGUI(); + + virtual const char *GetName( void ) { return PANEL_SPECGUI; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset() {}; + virtual void Update(); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return false; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); } + virtual void OnThink(); + + virtual int GetTopBarHeight() { return m_pTopBar->GetTall(); } + virtual int GetBottomBarHeight() { return m_pBottomBarBlank->GetTall(); } + + virtual bool ShouldShowPlayerLabel( int specmode ); + + virtual Color GetBlackBarColor( void ) { return BLACK_BAR_COLOR; } + + virtual const char *GetResFile( void ) { return "Resource/UI/Spectator.res"; } + +protected: + + void SetLabelText(const char *textEntryName, const char *text); + void SetLabelText(const char *textEntryName, wchar_t *text); + void MoveLabelToFront(const char *textEntryName); + void UpdateTimer(); + void SetLogoImage(const char *image); + +protected: + enum { INSET_OFFSET = 2 } ; + + // vgui overrides + virtual void PerformLayout(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +// virtual void OnCommand( const char *command ); + + vgui::Panel *m_pTopBar; + vgui::Panel *m_pBottomBarBlank; + + vgui::ImagePanel *m_pBannerImage; + vgui::Label *m_pPlayerLabel; + + IViewPort *m_pViewPort; + + // bool m_bHelpShown; + // bool m_bInsetVisible; + bool m_bSpecScoreboard; +}; + + +//----------------------------------------------------------------------------- +// Purpose: the bottom bar panel, this is a separate panel because it +// wants mouse input and the main window doesn't +//---------------------------------------------------------------------------- +class CSpectatorMenu : public vgui::Frame, public IViewPortPanel, public CGameEventListener +{ + DECLARE_CLASS_SIMPLE( CSpectatorMenu, vgui::Frame ); + +public: + CSpectatorMenu( IViewPort *pViewPort ); + ~CSpectatorMenu() {} + + virtual const char *GetName( void ) { return PANEL_SPECMENU; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset( void ) { m_pPlayerList->DeleteAllItems(); } + virtual void Update( void ); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + virtual void FireGameEvent( IGameEvent *event ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + virtual bool IsVisible() { return BaseClass::IsVisible(); } + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); } + +private: + // VGUI2 overrides + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + virtual void OnCommand( const char *command ); + virtual void OnKeyCodePressed(vgui::KeyCode code); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void PerformLayout(); + + void SetViewModeText( const char *text ) { m_pViewOptions->SetText( text ); } + void SetPlayerFgColor( Color c1 ) { m_pPlayerList->SetFgColor(c1); } + + vgui::ComboBox *m_pPlayerList; + vgui::ComboBox *m_pViewOptions; + vgui::ComboBox *m_pConfigSettings; + + vgui::Button *m_pLeftButton; + vgui::Button *m_pRightButton; + + IViewPort *m_pViewPort; + ButtonCode_t m_iDuckKey; +}; + +extern CSpectatorGUI * g_pSpectatorGUI; + +#endif // SPECTATORGUI_H diff --git a/game/client/game_controls/teammenu.h b/game/client/game_controls/teammenu.h new file mode 100644 index 0000000..a1eab0f --- /dev/null +++ b/game/client/game_controls/teammenu.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEAMMENU_H +#define TEAMMENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +#include + +#include +#include + +namespace vgui +{ + class RichText; + class HTML; +} +class TeamFortressViewport; + + +//----------------------------------------------------------------------------- +// Purpose: Displays the team menu +//----------------------------------------------------------------------------- +class CTeamMenu : public vgui::Frame, public IViewPortPanel +{ +private: + DECLARE_CLASS_SIMPLE( CTeamMenu, vgui::Frame ); + +public: + CTeamMenu(IViewPort *pViewPort); + virtual ~CTeamMenu(); + + virtual const char *GetName( void ) { return PANEL_TEAM; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset() {}; + virtual void Update(); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +public: + + void AutoAssign(); + +protected: + + // int GetNumTeams() { return m_iNumTeams; } + + // VGUI2 overrides + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void OnKeyCodePressed(vgui::KeyCode code); + + // helper functions + virtual void SetLabelText(const char *textEntryName, const char *text); + virtual void LoadMapPage( const char *mapName ); + // virtual void MakeTeamButtons( void ); + + // command callbacks + // MESSAGE_FUNC_INT( OnTeamButton, "TeamButton", team ); + + IViewPort *m_pViewPort; + vgui::RichText *m_pMapInfo; + vgui::HTML *m_pMapInfoHTML; +// int m_iNumTeams; + ButtonCode_t m_iJumpKey; + ButtonCode_t m_iScoreBoardKey; + + char m_szMapName[ MAX_PATH ]; +}; + + +#endif // TEAMMENU_H diff --git a/game/client/game_controls/vguitextwindow.h b/game/client/game_controls/vguitextwindow.h new file mode 100644 index 0000000..4557c7b --- /dev/null +++ b/game/client/game_controls/vguitextwindow.h @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUITEXTWINDOW_H +#define VGUITEXTWINDOW_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +#include +#include "shareddefs.h" + +namespace vgui +{ + class TextEntry; +} + +//----------------------------------------------------------------------------- +// Purpose: displays the MOTD +//----------------------------------------------------------------------------- + +class CTextWindow : public vgui::Frame, public IViewPortPanel +{ +private: + DECLARE_CLASS_SIMPLE( CTextWindow, vgui::Frame ); + +public: + CTextWindow(IViewPort *pViewPort); + virtual ~CTextWindow(); + + virtual const char *GetName( void ) { return PANEL_INFO; } + virtual void SetData(KeyValues *data); + virtual void Reset(); + virtual void Update(); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +public: + + virtual void SetData( int type, const char *title, const char *message, const char *message_fallback, int command, bool bUnload ); + virtual void ShowFile( const char *filename ); + virtual void ShowText( const char *text ); + virtual void ShowURL( const char *URL, bool bAllowUserToDisable = true ); + virtual void ShowIndex( const char *entry ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +protected: + // vgui overrides + virtual void OnCommand( const char *command ); + + void OnKeyCodePressed( vgui::KeyCode code ); + + IViewPort *m_pViewPort; + char m_szTitle[255]; + char m_szMessage[2048]; + char m_szMessageFallback[2048]; + //============================================================================= + // HPE_BEGIN: + // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration + // of options. Passing a command string is dangerous and allowed a server network + // message to run arbitrary commands on the client. + //============================================================================= + int m_nExitCommand; + //============================================================================= + // HPE_END + //============================================================================= + int m_nContentType; + bool m_bShownURL; + bool m_bUnloadOnDismissal; + + vgui::TextEntry *m_pTextMessage; + + class CMOTDHTML : public vgui::HTML + { + private: + DECLARE_CLASS_SIMPLE( CMOTDHTML, vgui::HTML ); + + public: + CMOTDHTML( Panel *parent, const char *pchName ) : vgui::HTML( parent, pchName ) {} + virtual bool OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect ) OVERRIDE; + }; + CMOTDHTML *m_pHTMLMessage; + + vgui::Button *m_pOK; + vgui::Label *m_pTitleLabel; +}; + + +#endif // VGUITEXTWINDOW_H diff --git a/game/client/glow_outline_effect.h b/game/client/glow_outline_effect.h new file mode 100644 index 0000000..aac399d --- /dev/null +++ b/game/client/glow_outline_effect.h @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Functionality to render a glowing outline around client renderable objects. +// +//=============================================================================== + +#ifndef GLOW_OUTLINE_EFFECT_H +#define GLOW_OUTLINE_EFFECT_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "utlvector.h" +#include "mathlib/vector.h" + +#ifdef GLOWS_ENABLE + +class C_BaseEntity; +class CViewSetup; +class CMatRenderContextPtr; + +static const int GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS = -1; + +class CGlowObjectManager +{ +public: + CGlowObjectManager() : + m_nFirstFreeSlot( GlowObjectDefinition_t::END_OF_FREE_LIST ) + { + } + + int RegisterGlowObject( C_BaseEntity *pEntity, const Vector &vGlowColor, float flGlowAlpha, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded, int nSplitScreenSlot ) + { + int nIndex; + if ( m_nFirstFreeSlot == GlowObjectDefinition_t::END_OF_FREE_LIST ) + { + nIndex = m_GlowObjectDefinitions.AddToTail(); + } + else + { + nIndex = m_nFirstFreeSlot; + m_nFirstFreeSlot = m_GlowObjectDefinitions[nIndex].m_nNextFreeSlot; + } + + m_GlowObjectDefinitions[nIndex].m_hEntity = pEntity; + m_GlowObjectDefinitions[nIndex].m_vGlowColor = vGlowColor; + m_GlowObjectDefinitions[nIndex].m_flGlowAlpha = flGlowAlpha; + m_GlowObjectDefinitions[nIndex].m_bRenderWhenOccluded = bRenderWhenOccluded; + m_GlowObjectDefinitions[nIndex].m_bRenderWhenUnoccluded = bRenderWhenUnoccluded; + m_GlowObjectDefinitions[nIndex].m_nSplitScreenSlot = nSplitScreenSlot; + m_GlowObjectDefinitions[nIndex].m_nNextFreeSlot = GlowObjectDefinition_t::ENTRY_IN_USE; + + return nIndex; + } + + void UnregisterGlowObject( int nGlowObjectHandle ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + + m_GlowObjectDefinitions[nGlowObjectHandle].m_nNextFreeSlot = m_nFirstFreeSlot; + m_GlowObjectDefinitions[nGlowObjectHandle].m_hEntity = NULL; + m_nFirstFreeSlot = nGlowObjectHandle; + } + + void SetEntity( int nGlowObjectHandle, C_BaseEntity *pEntity ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + m_GlowObjectDefinitions[nGlowObjectHandle].m_hEntity = pEntity; + } + + void SetColor( int nGlowObjectHandle, const Vector &vGlowColor ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + m_GlowObjectDefinitions[nGlowObjectHandle].m_vGlowColor = vGlowColor; + } + + void SetAlpha( int nGlowObjectHandle, float flAlpha ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + m_GlowObjectDefinitions[nGlowObjectHandle].m_flGlowAlpha = flAlpha; + } + + void SetRenderFlags( int nGlowObjectHandle, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + m_GlowObjectDefinitions[nGlowObjectHandle].m_bRenderWhenOccluded = bRenderWhenOccluded; + m_GlowObjectDefinitions[nGlowObjectHandle].m_bRenderWhenUnoccluded = bRenderWhenUnoccluded; + } + + bool IsRenderingWhenOccluded( int nGlowObjectHandle ) const + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + return m_GlowObjectDefinitions[nGlowObjectHandle].m_bRenderWhenOccluded; + } + + bool IsRenderingWhenUnoccluded( int nGlowObjectHandle ) const + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + return m_GlowObjectDefinitions[nGlowObjectHandle].m_bRenderWhenUnoccluded; + } + + bool HasGlowEffect( C_BaseEntity *pEntity ) const + { + for ( int i = 0; i < m_GlowObjectDefinitions.Count(); ++ i ) + { + if ( !m_GlowObjectDefinitions[i].IsUnused() && m_GlowObjectDefinitions[i].m_hEntity.Get() == pEntity ) + { + return true; + } + } + + return false; + } + + void RenderGlowEffects( const CViewSetup *pSetup, int nSplitScreenSlot ); + +private: + + void RenderGlowModels( const CViewSetup *pSetup, int nSplitScreenSlot, CMatRenderContextPtr &pRenderContext ); + void ApplyEntityGlowEffects( const CViewSetup *pSetup, int nSplitScreenSlot, CMatRenderContextPtr &pRenderContext, float flBloomScale, int x, int y, int w, int h ); + + struct GlowObjectDefinition_t + { + bool ShouldDraw( int nSlot ) const + { + return m_hEntity.Get() && + ( m_nSplitScreenSlot == GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS || m_nSplitScreenSlot == nSlot ) && + ( m_bRenderWhenOccluded || m_bRenderWhenUnoccluded ) && + m_hEntity->ShouldDraw() && + !m_hEntity->IsDormant(); + } + + bool IsUnused() const { return m_nNextFreeSlot != GlowObjectDefinition_t::ENTRY_IN_USE; } + void DrawModel(); + + EHANDLE m_hEntity; + Vector m_vGlowColor; + float m_flGlowAlpha; + + bool m_bRenderWhenOccluded; + bool m_bRenderWhenUnoccluded; + int m_nSplitScreenSlot; + + // Linked list of free slots + int m_nNextFreeSlot; + + // Special values for GlowObjectDefinition_t::m_nNextFreeSlot + static const int END_OF_FREE_LIST = -1; + static const int ENTRY_IN_USE = -2; + }; + + CUtlVector< GlowObjectDefinition_t > m_GlowObjectDefinitions; + int m_nFirstFreeSlot; +}; + +extern CGlowObjectManager g_GlowObjectManager; + +class CGlowObject +{ +public: + CGlowObject( C_BaseEntity *pEntity, const Vector &vGlowColor = Vector( 1.0f, 1.0f, 1.0f ), float flGlowAlpha = 1.0f, bool bRenderWhenOccluded = false, bool bRenderWhenUnoccluded = false, int nSplitScreenSlot = GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS ) + { + m_nGlowObjectHandle = g_GlowObjectManager.RegisterGlowObject( pEntity, vGlowColor, flGlowAlpha, bRenderWhenOccluded, bRenderWhenUnoccluded, nSplitScreenSlot ); + } + + ~CGlowObject() + { + g_GlowObjectManager.UnregisterGlowObject( m_nGlowObjectHandle ); + } + + void SetEntity( C_BaseEntity *pEntity ) + { + g_GlowObjectManager.SetEntity( m_nGlowObjectHandle, pEntity ); + } + + void SetColor( const Vector &vGlowColor ) + { + g_GlowObjectManager.SetColor( m_nGlowObjectHandle, vGlowColor ); + } + + void SetAlpha( float flAlpha ) + { + g_GlowObjectManager.SetAlpha( m_nGlowObjectHandle, flAlpha ); + } + + void SetRenderFlags( bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + g_GlowObjectManager.SetRenderFlags( m_nGlowObjectHandle, bRenderWhenOccluded, bRenderWhenUnoccluded ); + } + + bool IsRenderingWhenOccluded() const + { + return g_GlowObjectManager.IsRenderingWhenOccluded( m_nGlowObjectHandle ); + } + + bool IsRenderingWhenUnoccluded() const + { + return g_GlowObjectManager.IsRenderingWhenUnoccluded( m_nGlowObjectHandle ); + } + + bool IsRendering() const + { + return IsRenderingWhenOccluded() || IsRenderingWhenUnoccluded(); + } + + // Add more accessors/mutators here as needed + +private: + int m_nGlowObjectHandle; + + // Assignment & copy-construction disallowed + CGlowObject( const CGlowObject &other ); + CGlowObject& operator=( const CGlowObject &other ); +}; + +#endif // GLOWS_ENABLE + +#endif // GLOW_OUTLINE_EFFECT_H \ No newline at end of file diff --git a/game/client/glow_overlay.h b/game/client/glow_overlay.h new file mode 100644 index 0000000..14de906 --- /dev/null +++ b/game/client/glow_overlay.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GLOW_OVERLAY_H +#define GLOW_OVERLAY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "materialsystem/imaterial.h" +#include "sun_shared.h" +#include "c_pixel_visibility.h" + +#ifdef PORTAL +#include "c_prop_portal.h" //MAX_PORTAL_RECURSIVE_VIEWS +#endif + +extern float g_flOverlayRange; + +class CGlowSprite +{ +public: + Vector m_vColor; // 0-1 + float m_flHorzSize; // Horizontal and vertical sizes. + float m_flVertSize; // 1 = size of the sun + IMaterial *m_pMaterial; // Material to use +}; + + +class CGlowOverlay +{ +public: + + CGlowOverlay(); + virtual ~CGlowOverlay(); + + // Return false to remove (and delete) the overlay. + virtual bool Update(); + + +// Data the creator should fill in. +public: + + // Position of the light source. If m_bDirectional is set, then it ignores + // this and uses m_vDirection as the direction of the light source. + Vector m_vPos; + + // Optional direction. Used for really far away things like the sun. + // The direction should point AT the light source. + bool m_bDirectional; + Vector m_vDirection; + + // If this is set, then the overlay is only visible if the ray to it hits the sky. + bool m_bInSky; + float m_skyObstructionScale; +#ifdef PORTAL + float m_skyObstructionScaleBackups[MAX_PORTAL_RECURSIVE_VIEWS]; //used in portal mod during stencil rendering to maintain obstructions while rendering recursive views +#endif + + CGlowSprite m_Sprites[MAX_SUN_LAYERS]; + int m_nSprites; + + float m_flProxyRadius; + + float m_flHDRColorScale; + +public: + + // After creating the overlay, call this to add it to the active list. + // You can also call Activate and Deactivate as many times as you want. + void Activate(); + void Deactivate(); + + // Render all the active overlays. + static void DrawOverlays( bool bCacheFullSceneState ); + static void UpdateSkyOverlays( float zFar, bool bCacheFullSceneState ); + +#ifdef PORTAL + static void BackupSkyOverlayData( int iBackupToSlot ); + static void RestoreSkyOverlayData( int iRestoreFromSlot ); +#endif + +protected: + + void UpdateGlowObstruction( const Vector &vToGlow, bool bCacheFullSceneState ); + void UpdateSkyGlowObstruction( float zFar, bool bCacheFullSceneState ); + + virtual void CalcSpriteColorAndSize( + float flDot, + CGlowSprite *pSprite, + float *flHorzSize, + float *flVertSize, + Vector *vColor ); + + virtual void CalcBasis( + const Vector &vToGlow, + float flHorzSize, + float flVertSize, + Vector &vBasePt, + Vector &vUp, + Vector &vRight ); + + virtual void Draw( bool bCacheFullSceneState ); + float CalcGlowAspect(); + + float m_flGlowObstructionScale; + bool m_bCacheGlowObstruction; // Flags to cache obstruction scales + bool m_bCacheSkyObstruction; // Used in IFM poster rendering + +private: + short m_bActivated; + unsigned short m_ListIndex; // index into s_GlowOverlays. + pixelvis_handle_t m_queryHandle; +}; + +//Override for warping +class CWarpOverlay : public CGlowOverlay +{ +protected: + + virtual void Draw( bool bCacheFullSceneState ); +}; + +#endif // GLOW_OVERLAY_H diff --git a/game/client/history_resource.h b/game/client/history_resource.h new file mode 100644 index 0000000..962b168 --- /dev/null +++ b/game/client/history_resource.h @@ -0,0 +1,96 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Item pickup history displayed onscreen when items are picked up. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HISTORY_RESOURCE_H +#define HISTORY_RESOURCE_H +#pragma once + +#include "hudelement.h" +#include "ehandle.h" + +#include + +enum +{ + HISTSLOT_EMPTY, + HISTSLOT_AMMO, + HISTSLOT_WEAP, + HISTSLOT_ITEM, + HISTSLOT_AMMODENIED, +}; + +namespace vgui +{ + class IScheme; +} + +class C_BaseCombatWeapon; + +//----------------------------------------------------------------------------- +// Purpose: Used to draw the history of ammo / weapon / item pickups by the player +//----------------------------------------------------------------------------- +class CHudHistoryResource : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudHistoryResource, vgui::Panel ); +private: + struct HIST_ITEM + { + HIST_ITEM() + { + // init this here, because the code that overwrites previous history items will use this + // to check to see if the item is empty + DisplayTime = 0.0f; + } + int type; + float DisplayTime; // the time at which this item should be removed from the history + int iCount; + int iId; + CHandle< C_BaseCombatWeapon > m_hWeapon; + + CHudTexture *icon; + }; + + CUtlVector m_PickupHistory; + +public: + + CHudHistoryResource( const char *pElementName ); + + // CHudElement overrides + virtual void Init( void ); + virtual void Reset( void ); + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + void AddToHistory( int iType, int iId, int iCount = 0 ); + void AddToHistory( int iType, const char *szName, int iCount = 0 ); + void AddToHistory( C_BaseCombatWeapon *weapon ); + void MsgFunc_ItemPickup( bf_read &msg ); + void MsgFunc_AmmoDenied( bf_read &msg ); + + void CheckClearHistory( void ); + void SetHistoryGap( int iNewHistoryGap ); + void AddIconToHistory( int iType, int iId, C_BaseCombatWeapon *weapon, int iCount, CHudTexture *icon ); + +private: + // these vars are for hl1-port compatibility + int m_iHistoryGap; + int m_iCurrentHistorySlot; + bool m_bDoNotDraw; + wchar_t m_wcsAmmoFullMsg[16]; + bool m_bNeedsDraw; + + CPanelAnimationVarAliasType( float, m_flHistoryGap, "history_gap", "42", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconInset, "icon_inset", "28", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flTextInset, "text_inset", "26", "proportional_float" ); + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudNumbersSmall" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); +}; + +#endif // HISTORY_RESOURCE_H diff --git a/game/client/hl2/c_basehelicopter.h b/game/client/hl2/c_basehelicopter.h new file mode 100644 index 0000000..6ef2d93 --- /dev/null +++ b/game/client/hl2/c_basehelicopter.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_BASEHELICOPTER_H +#define C_BASEHELICOPTER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_ai_basenpc.h" + + +class C_BaseHelicopter : public C_AI_BaseNPC +{ +public: + DECLARE_CLASS( C_BaseHelicopter, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + + C_BaseHelicopter(); + + float StartupTime() const { return m_flStartupTime; } + +private: + C_BaseHelicopter( const C_BaseHelicopter &other ) {} + float m_flStartupTime; +}; + + +#endif // C_BASEHELICOPTER_H diff --git a/game/client/hl2/c_basehlcombatweapon.h b/game/client/hl2/c_basehlcombatweapon.h new file mode 100644 index 0000000..72440cc --- /dev/null +++ b/game/client/hl2/c_basehlcombatweapon.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basehlcombatweapon_shared.h" + +#ifndef C_BASEHLCOMBATWEAPON_H +#define C_BASEHLCOMBATWEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +class C_HLMachineGun : public C_BaseHLCombatWeapon +{ +public: + DECLARE_CLASS( C_HLMachineGun, C_BaseHLCombatWeapon ); + DECLARE_CLIENTCLASS(); +}; + +class C_HLSelectFireMachineGun : public C_HLMachineGun +{ +public: + DECLARE_CLASS( C_HLSelectFireMachineGun, C_HLMachineGun ); + DECLARE_CLIENTCLASS(); +}; + +class C_BaseHLBludgeonWeapon : public C_BaseHLCombatWeapon +{ +public: + DECLARE_CLASS( C_BaseHLBludgeonWeapon, C_BaseHLCombatWeapon ); + DECLARE_CLIENTCLASS(); +}; + +#endif // C_BASEHLCOMBATWEAPON_H diff --git a/game/client/hl2/c_basehlplayer.h b/game/client/hl2/c_basehlplayer.h new file mode 100644 index 0000000..c6507e9 --- /dev/null +++ b/game/client/hl2/c_basehlplayer.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( C_BASEHLPLAYER_H ) +#define C_BASEHLPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_baseplayer.h" +#include "c_hl2_playerlocaldata.h" + +class C_BaseHLPlayer : public C_BasePlayer +{ +public: + DECLARE_CLASS( C_BaseHLPlayer, C_BasePlayer ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_BaseHLPlayer(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void Weapon_DropPrimary( void ); + + float GetFOV(); + void Zoom( float FOVOffset, float time ); + float GetZoom( void ); + bool IsZoomed( void ) { return m_HL2Local.m_bZooming; } + + bool IsSprinting( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_SPRINT; } + bool IsFlashlightActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_FLASHLIGHT; } + bool IsBreatherActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_BREATHER; } + + virtual int DrawModel( int flags ); + virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); + + LadderMove_t *GetLadderMove() { return &m_HL2Local.m_LadderMove; } + virtual void ExitLadder(); + bool IsSprinting() const { return m_fIsSprinting; } + + // Input handling + virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + void PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ); + void PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd ); + + bool IsWeaponLowered( void ) { return m_HL2Local.m_bWeaponLowered; } + +public: + + C_HL2PlayerLocalData m_HL2Local; + EHANDLE m_hClosestNPC; + float m_flSpeedModTime; + bool m_fIsSprinting; + +private: + C_BaseHLPlayer( const C_BaseHLPlayer & ); // not defined, not accessible + + bool TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir ); + + float m_flZoomStart; + float m_flZoomEnd; + float m_flZoomRate; + float m_flZoomStartTime; + + bool m_bPlayUseDenySound; // Signaled by PlayerUse, but can be unset by HL2 ladder code... + float m_flSpeedMod; + float m_flExitSpeedMod; + + +friend class CHL2GameMovement; +}; + + +#endif diff --git a/game/client/hl2/c_corpse.h b/game/client/hl2/c_corpse.h new file mode 100644 index 0000000..1bd4a09 --- /dev/null +++ b/game/client/hl2/c_corpse.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_CORPSE_H ) +#define C_CORPSE_H +#ifdef _WIN32 +#pragma once +#endif + +class C_Corpse : public C_BaseAnimating +{ +public: + DECLARE_CLASS( C_Corpse, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + + C_Corpse( void ); + + virtual int DrawModel( int flags ); + +public: + // The player whom we are copying our data from + int m_nReferencePlayer; + +private: + C_Corpse( const C_Corpse & ); +}; + + +#endif // C_CORPSE_H \ No newline at end of file diff --git a/game/client/hl2/c_hl2_playerlocaldata.h b/game/client/hl2/c_hl2_playerlocaldata.h new file mode 100644 index 0000000..8001991 --- /dev/null +++ b/game/client/hl2/c_hl2_playerlocaldata.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( C_HL2_PLAYERLOCALDATA_H ) +#define C_HL2_PLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "dt_recv.h" + +#include "hl2/hl_movedata.h" + +EXTERN_RECV_TABLE( DT_HL2Local ); + + +class C_HL2PlayerLocalData +{ +public: + DECLARE_PREDICTABLE(); + DECLARE_CLASS_NOBASE( C_HL2PlayerLocalData ); + DECLARE_EMBEDDED_NETWORKVAR(); + + C_HL2PlayerLocalData(); + + float m_flSuitPower; + bool m_bZooming; + int m_bitsActiveDevices; + int m_iSquadMemberCount; + int m_iSquadMedicCount; + bool m_fSquadInFollowMode; + bool m_bWeaponLowered; + EHANDLE m_hAutoAimTarget; + Vector m_vecAutoAimPoint; + bool m_bDisplayReticle; + bool m_bStickyAutoAim; + bool m_bAutoAimTarget; +#ifdef HL2_EPISODIC + float m_flFlashBattery; + Vector m_vecLocatorOrigin; +#endif + + // Ladder related data + EHANDLE m_hLadder; + LadderMove_t m_LadderMove; +}; + + +#endif diff --git a/game/client/hl2/c_prop_combine_ball.h b/game/client/hl2/c_prop_combine_ball.h new file mode 100644 index 0000000..04e8e47 --- /dev/null +++ b/game/client/hl2/c_prop_combine_ball.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CPROPCOMBINEBALL_H_ +#define CPROPCOMBINEBALL_H_ + +#ifdef _WIN32 +#pragma once +#endif + +class C_PropCombineBall : public C_BaseAnimating +{ + DECLARE_CLASS( C_PropCombineBall, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); +public: + + C_PropCombineBall( void ); + + virtual RenderGroup_t GetRenderGroup( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual int DrawModel( int flags ); + +protected: + + void DrawMotionBlur( void ); + void DrawFlicker( void ); + virtual bool InitMaterials( void ); + + Vector m_vecLastOrigin; + bool m_bEmit; + float m_flRadius; + bool m_bHeld; + bool m_bLaunched; + + IMaterial *m_pFlickerMaterial; + IMaterial *m_pBodyMaterial; + IMaterial *m_pBlurMaterial; +}; + + +#endif \ No newline at end of file diff --git a/game/client/hl2/c_vehicle_crane.h b/game/client/hl2/c_vehicle_crane.h new file mode 100644 index 0000000..81ca6d1 --- /dev/null +++ b/game/client/hl2/c_vehicle_crane.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "iclientvehicle.h" +#include "vehicle_viewblend_shared.h" + +#ifndef C_VEHICLE_CRANE_H +#define C_VEHICLE_CRANE_H +#pragma once + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_PropCrane : public C_BaseAnimating, public IClientVehicle +{ + + DECLARE_CLASS( C_PropCrane, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + + C_PropCrane(); + + void PreDataUpdate( DataUpdateType_t updateType ); + void PostDataUpdate( DataUpdateType_t updateType ); + + bool IsMagnetOn( void ) { return m_bMagnetOn; } + +public: + + // IClientVehicle overrides. + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV =NULL ); + virtual void GetVehicleFOV( float &flFOV ) { flFOV = 0.0f; } + virtual void DrawHudElements(); + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) {} + virtual C_BaseCombatCharacter* GetPassenger( int nRole ); + virtual int GetPassengerRole( C_BaseCombatCharacter *pPassenger ); + virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const; + virtual int GetPrimaryAmmoType() const { return -1; } + virtual int GetPrimaryAmmoCount() const { return -1; } + virtual int GetPrimaryAmmoClip() const { return -1; } + virtual bool PrimaryAmmoUsesClips() const { return false; } + virtual int GetJoystickResponseCurve() const { return 0; } + +public: + + // C_BaseEntity overrides. + virtual IClientVehicle* GetClientVehicle() { return this; } + virtual C_BaseEntity *GetVehicleEnt() { return this; } + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {} + virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {} + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {} + virtual bool IsPredicted() const { return false; } + virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {} + virtual bool IsSelfAnimating() { return false; }; + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + +private: + + CHandle m_hPlayer; + CHandle m_hPrevPlayer; + + bool m_bEnterAnimOn; + bool m_bExitAnimOn; + Vector m_vecEyeExitEndpoint; + + bool m_bMagnetOn; + + Vector m_vecOldShadowDir; + + ViewSmoothingData_t m_ViewSmoothingData; +}; + +#endif // C_VEHICLE_CRANE_H diff --git a/game/client/hl2/clientmode_hlnormal.h b/game/client/hl2/clientmode_hlnormal.h new file mode 100644 index 0000000..623da43 --- /dev/null +++ b/game/client/hl2/clientmode_hlnormal.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENTMODE_HLNORMAL_H ) +#define CLIENTMODE_HLNORMAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_shared.h" +#include +#include + +class CHudViewport; + +namespace vgui +{ + typedef unsigned long HScheme; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class ClientModeHLNormal : public ClientModeShared +{ +public: + DECLARE_CLASS( ClientModeHLNormal, ClientModeShared ); + + ClientModeHLNormal(); + ~ClientModeHLNormal(); + + virtual void Init(); + virtual bool ShouldDrawCrosshair( void ); +}; + +extern IClientMode *GetClientModeNormal(); +extern vgui::HScheme g_hVGuiCombineScheme; + +#endif // CLIENTMODE_HLNORMAL_H diff --git a/game/client/hl2/hud_radar.h b/game/client/hl2/hud_radar.h new file mode 100644 index 0000000..81134ca --- /dev/null +++ b/game/client/hl2/hud_radar.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_RADAR_H +#define HUD_RADAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "hl2_vehicle_radar.h" +#include "c_vguiscreen.h" + +class CRadarContact +{ +public: + Vector m_vecOrigin; + int m_iType; + float m_flTimeToRemove; +}; + +class CHudRadar : public CVGuiScreenPanel +{ +public: + DECLARE_CLASS_SIMPLE( CHudRadar, CVGuiScreenPanel ); + + + CHudRadar( vgui::Panel *parent, const char *panelName ); + ~CHudRadar(); + + virtual void Paint(); + void VidInit(void); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void SetVisible(bool state); + + void MsgFunc_UpdateRadar(bf_read &msg ); + void SetVehicle( C_BaseEntity *pVehicle ) { m_pVehicle = pVehicle; } + + void AddRadarContact( const Vector &vecOrigin, int iType, float flTimeToLive ); + int FindRadarContact( const Vector &vecOrigin ); + void MaintainRadarContacts(); + + + void ClearAllRadarContacts() { m_iNumRadarContacts = 0; } + +public: + bool m_bUseFastUpdate; + int m_ghostAlpha; // How intense the alpha channel is for CRT ghosts + float m_flTimeStopGhosting; + float m_flTimeStartGhosting; + +private: + + bool WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta, float &scale ); + + void DrawPositionOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ); + void DrawIconOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ); + + void FillRect( int x, int y, int w, int h ); + void DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a ); + + CRadarContact m_radarContacts[RADAR_MAX_CONTACTS]; + int m_iNumRadarContacts; + C_BaseEntity *m_pVehicle; + int m_iImageID; + int m_textureID_IconLambda; + int m_textureID_IconBuster; + int m_textureID_IconStrider; + int m_textureID_IconDog; + int m_textureID_IconBase; +}; + +extern CHudRadar *GetHudRadar(); +#endif // HUD_RADAR_H diff --git a/game/client/hl2/hud_suitpower.h b/game/client/hl2/hud_suitpower.h new file mode 100644 index 0000000..83af2be --- /dev/null +++ b/game/client/hl2/hud_suitpower.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( HUD_SUITPOWER_H ) +#define HUD_SUITPOWER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include "hud_numericdisplay.h" +#include + +//----------------------------------------------------------------------------- +// Purpose: Shows the sprint power bar +//----------------------------------------------------------------------------- +class CHudSuitPower : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudSuitPower, vgui::Panel ); + +public: + CHudSuitPower( const char *pElementName ); + virtual void Init( void ); + virtual void Reset( void ); + virtual void OnThink( void ); + bool ShouldDraw( void ); + +protected: + virtual void Paint(); + +private: + CPanelAnimationVar( Color, m_AuxPowerColor, "AuxPowerColor", "255 0 0 255" ); + CPanelAnimationVar( int, m_iAuxPowerDisabledAlpha, "AuxPowerDisabledAlpha", "70" ); + + CPanelAnimationVarAliasType( float, m_flBarInsetX, "BarInsetX", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarInsetY, "BarInsetY", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarWidth, "BarWidth", "80", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarHeight, "BarHeight", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarChunkWidth, "BarChunkWidth", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarChunkGap, "BarChunkGap", "2", "proportional_float" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + CPanelAnimationVarAliasType( float, text_xpos, "text_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text_ypos, "text_ypos", "20", "proportional_float" ); + CPanelAnimationVarAliasType( float, text2_xpos, "text2_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text2_ypos, "text2_ypos", "40", "proportional_float" ); + CPanelAnimationVarAliasType( float, text2_gap, "text2_gap", "10", "proportional_float" ); + + float m_flSuitPower; + int m_nSuitPowerLow; + int m_iActiveSuitDevices; +}; + +#endif // HUD_SUITPOWER_H diff --git a/game/client/hl2mp/c_hl2mp_player.h b/game/client/hl2mp/c_hl2mp_player.h new file mode 100644 index 0000000..bac4197 --- /dev/null +++ b/game/client/hl2mp/c_hl2mp_player.h @@ -0,0 +1,173 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef HL2MP_PLAYER_H +#define HL2MP_PLAYER_H +#pragma once + +class C_HL2MP_Player; +#include "c_basehlplayer.h" +#include "hl2mp_player_shared.h" +#include "beamdraw.h" + +//============================================================================= +// >> HL2MP_Player +//============================================================================= +class C_HL2MP_Player : public C_BaseHLPlayer +{ +public: + DECLARE_CLASS( C_HL2MP_Player, C_BaseHLPlayer ); + + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + + C_HL2MP_Player(); + ~C_HL2MP_Player( void ); + + void ClientThink( void ); + + static C_HL2MP_Player* GetLocalHL2MPPlayer(); + + virtual int DrawModel( int flags ); + virtual void AddEntity( void ); + + QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles; } + Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL ); + + + // Should this object cast shadows? + virtual ShadowType_t ShadowCastType( void ); + virtual C_BaseAnimating *BecomeRagdollOnClient(); + virtual const QAngle& GetRenderAngles(); + virtual bool ShouldDraw( void ); + virtual void OnDataChanged( DataUpdateType_t type ); + virtual float GetFOV( void ); + virtual CStudioHdr *OnNewModel( void ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + virtual void ItemPreFrame( void ); + virtual void ItemPostFrame( void ); + virtual float GetMinFOV() const { return 5.0f; } + virtual Vector GetAutoaimVector( float flDelta ); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void CreateLightEffects( void ) {} + virtual bool ShouldReceiveProjectedTextures( int flags ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); + virtual void PreThink( void ); + virtual void DoImpactEffect( trace_t &tr, int nDamageType ); + IRagdoll* GetRepresentativeRagdoll() const; + virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov ); + virtual const QAngle& EyeAngles( void ); + + + bool CanSprint( void ); + void StartSprinting( void ); + void StopSprinting( void ); + void HandleSpeedChanges( void ); + void UpdateLookAt( void ); + void Initialize( void ); + int GetIDTarget() const; + void UpdateIDTarget( void ); + void PrecacheFootStepSounds( void ); + const char *GetPlayerModelSoundPrefix( void ); + + HL2MPPlayerState State_Get() const; + + // Walking + void StartWalking( void ); + void StopWalking( void ); + bool IsWalking( void ) { return m_fIsWalking; } + + virtual void PostThink( void ); + +private: + + C_HL2MP_Player( const C_HL2MP_Player & ); + + CPlayerAnimState m_PlayerAnimState; + + QAngle m_angEyeAngles; + + CInterpolatedVar< QAngle > m_iv_angEyeAngles; + + EHANDLE m_hRagdoll; + + int m_headYawPoseParam; + int m_headPitchPoseParam; + float m_headYawMin; + float m_headYawMax; + float m_headPitchMin; + float m_headPitchMax; + + bool m_isInit; + Vector m_vLookAtTarget; + + float m_flLastBodyYaw; + float m_flCurrentHeadYaw; + float m_flCurrentHeadPitch; + + int m_iIDEntIndex; + + CountdownTimer m_blinkTimer; + + int m_iSpawnInterpCounter; + int m_iSpawnInterpCounterCache; + + int m_iPlayerSoundType; + + void ReleaseFlashlight( void ); + Beam_t *m_pFlashlightBeam; + + CNetworkVar( HL2MPPlayerState, m_iPlayerState ); + + bool m_fIsWalking; +}; + +inline C_HL2MP_Player *ToHL2MPPlayer( CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + + return dynamic_cast( pEntity ); +} + + +class C_HL2MPRagdoll : public C_BaseAnimatingOverlay +{ +public: + DECLARE_CLASS( C_HL2MPRagdoll, C_BaseAnimatingOverlay ); + DECLARE_CLIENTCLASS(); + + C_HL2MPRagdoll(); + ~C_HL2MPRagdoll(); + + virtual void OnDataChanged( DataUpdateType_t type ); + + int GetPlayerEntIndex() const; + IRagdoll* GetIRagdoll() const; + + void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + void UpdateOnRemove( void ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + +private: + + C_HL2MPRagdoll( const C_HL2MPRagdoll & ) {} + + void Interp_Copy( C_BaseAnimatingOverlay *pDestinationEntity ); + void CreateHL2MPRagdoll( void ); + +private: + + EHANDLE m_hPlayer; + CNetworkVector( m_vecRagdollVelocity ); + CNetworkVector( m_vecRagdollOrigin ); +}; + +#endif //HL2MP_PLAYER_H diff --git a/game/client/hl2mp/clientmode_hl2mpnormal.h b/game/client/hl2mp/clientmode_hl2mpnormal.h new file mode 100644 index 0000000..2b06a6f --- /dev/null +++ b/game/client/hl2mp/clientmode_hl2mpnormal.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENTMODE_HLNORMAL_H ) +#define CLIENTMODE_HLNORMAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_shared.h" +#include +#include + +class CHudViewport; + +namespace vgui +{ + typedef unsigned long HScheme; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class ClientModeHL2MPNormal : public ClientModeShared +{ +public: + DECLARE_CLASS( ClientModeHL2MPNormal, ClientModeShared ); + + ClientModeHL2MPNormal(); + ~ClientModeHL2MPNormal(); + + virtual void Init(); + virtual int GetDeathMessageStartHeight( void ); +}; + +extern IClientMode *GetClientModeNormal(); +extern vgui::HScheme g_hVGuiCombineScheme; + +extern ClientModeHL2MPNormal* GetClientModeHL2MPNormal(); + +#endif // CLIENTMODE_HLNORMAL_H diff --git a/game/client/hl2mp/hl2mp_hud_chat.h b/game/client/hl2mp/hl2mp_hud_chat.h new file mode 100644 index 0000000..5eb2157 --- /dev/null +++ b/game/client/hl2mp/hl2mp_hud_chat.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CS_HUD_CHAT_H +#define CS_HUD_CHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +class CHudChatLine : public CBaseHudChatLine +{ + DECLARE_CLASS_SIMPLE( CHudChatLine, CBaseHudChatLine ); + +public: + CHudChatLine( vgui::Panel *parent, const char *panelName ) : CBaseHudChatLine( parent, panelName ) {} + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + void MsgFunc_SayText(bf_read &msg); + + + +private: + CHudChatLine( const CHudChatLine & ); // not defined, not accessible +}; + +//----------------------------------------------------------------------------- +// Purpose: The prompt and text entry area for chat messages +//----------------------------------------------------------------------------- +class CHudChatInputLine : public CBaseHudChatInputLine +{ + DECLARE_CLASS_SIMPLE( CHudChatInputLine, CBaseHudChatInputLine ); + +public: + CHudChatInputLine( CBaseHudChat *parent, char const *panelName ) : CBaseHudChatInputLine( parent, panelName ) {} + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +}; + +class CHudChat : public CBaseHudChat +{ + DECLARE_CLASS_SIMPLE( CHudChat, CBaseHudChat ); + +public: + CHudChat( const char *pElementName ); + + virtual void CreateChatInputLine( void ); + virtual void CreateChatLines( void ); + + virtual void Init( void ); + virtual void Reset( void ); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + int GetChatInputOffset( void ); + + virtual Color GetClientColor( int clientIndex ); +}; + +#endif //CS_HUD_CHAT_H \ No newline at end of file diff --git a/game/client/hl2mp/ui/backgroundpanel.h b/game/client/hl2mp/ui/backgroundpanel.h new file mode 100644 index 0000000..54cb2ca --- /dev/null +++ b/game/client/hl2mp/ui/backgroundpanel.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CSBACKGROUND_H +#define CSBACKGROUND_H + +#include +#include + +//----------------------------------------------------------------------------- +// Purpose: Creates background image panels +//----------------------------------------------------------------------------- +void CreateBackground( vgui::EditablePanel *pWindow ); + +//----------------------------------------------------------------------------- +// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and +// centers them on the screen. Sub-controls are also resized and moved. +//----------------------------------------------------------------------------- +void LayoutBackgroundPanel( vgui::EditablePanel *pWindow ); + +//----------------------------------------------------------------------------- +// Purpose: Sets colors etc for background image panels +//----------------------------------------------------------------------------- +void ApplyBackgroundSchemeSettings( vgui::EditablePanel *pWindow, vgui::IScheme *pScheme ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ResizeWindowControls( vgui::EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY ); + +//----------------------------------------------------------------------------- +// Purpose: transform a standard scaled value into one that is scaled based the minimum +// of the horizontal and vertical ratios +//----------------------------------------------------------------------------- +int GetAlternateProportionalValueFromScaled( vgui::HScheme hScheme, int scaledValue ); + +//----------------------------------------------------------------------------- + +#endif // CSBACKGROUND_H diff --git a/game/client/hl2mp/ui/hl2mpclientscoreboard.h b/game/client/hl2mp/ui/hl2mpclientscoreboard.h new file mode 100644 index 0000000..d933658 --- /dev/null +++ b/game/client/hl2mp/ui/hl2mpclientscoreboard.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CHL2MPCLIENTSCOREBOARDDIALOG_H +#define CHL2MPCLIENTSCOREBOARDDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +//----------------------------------------------------------------------------- +// Purpose: Game ScoreBoard +//----------------------------------------------------------------------------- +class CHL2MPClientScoreBoardDialog : public CClientScoreBoardDialog +{ +private: + DECLARE_CLASS_SIMPLE(CHL2MPClientScoreBoardDialog, CClientScoreBoardDialog); + +public: + CHL2MPClientScoreBoardDialog(IViewPort *pViewPort); + ~CHL2MPClientScoreBoardDialog(); + + +protected: + // scoreboard overrides + virtual void InitScoreboardSections(); + virtual void UpdateTeamInfo(); + virtual bool GetPlayerScoreInfo(int playerIndex, KeyValues *outPlayerInfo); + virtual void UpdatePlayerInfo(); + + // vgui overrides for rounded corner background + virtual void PaintBackground(); + virtual void PaintBorder(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +private: + virtual void AddHeader(); // add the start header of the scoreboard + virtual void AddSection(int teamType, int teamNumber); // add a new section header for a team + + int GetSectionFromTeamNumber( int teamNumber ); + enum + { + CSTRIKE_NAME_WIDTH = 320, + CSTRIKE_CLASS_WIDTH = 56, + CSTRIKE_SCORE_WIDTH = 40, + CSTRIKE_DEATH_WIDTH = 46, + CSTRIKE_PING_WIDTH = 46, +// CSTRIKE_VOICE_WIDTH = 40, +// CSTRIKE_FRIENDS_WIDTH = 24, + }; + + // rounded corners + Color m_bgColor; + Color m_borderColor; +}; + + +#endif // CHL2MPCLIENTSCOREBOARDDIALOG_H diff --git a/game/client/hl2mp/ui/hl2mptextwindow.h b/game/client/hl2mp/ui/hl2mptextwindow.h new file mode 100644 index 0000000..55e378f --- /dev/null +++ b/game/client/hl2mp/ui/hl2mptextwindow.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CSTEXTWINDOW_H +#define CSTEXTWINDOW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vguitextwindow.h" +#include + +//----------------------------------------------------------------------------- +// Purpose: displays the MOTD +//----------------------------------------------------------------------------- + +class CHL2MPTextWindow : public CTextWindow +{ +private: + DECLARE_CLASS_SIMPLE( CHL2MPTextWindow, CTextWindow ); + +public: + CHL2MPTextWindow(IViewPort *pViewPort); + virtual ~CHL2MPTextWindow(); + + virtual void Update(); + virtual void SetVisible(bool state); + virtual void ShowPanel( bool bShow ); + virtual void OnKeyCodePressed(vgui::KeyCode code); + +protected: + ButtonCode_t m_iScoreBoardKey; + + // Background panel ------------------------------------------------------- + +public: + virtual void PaintBackground(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + bool m_backgroundLayoutFinished; + + // End background panel --------------------------------------------------- +}; + +class CHL2MPSpectatorGUI : public CSpectatorGUI +{ +private: + DECLARE_CLASS_SIMPLE( CHL2MPSpectatorGUI, CSpectatorGUI ); + +public: + CHL2MPSpectatorGUI( IViewPort *pViewPort ); + + virtual void Update( void ); + virtual bool NeedsUpdate( void ); + +protected: + int m_nLastSpecMode; + CBaseEntity *m_nLastSpecTarget; +}; + + + +#endif // CSTEXTWINDOW_H diff --git a/game/client/hltvcamera.h b/game/client/hltvcamera.h new file mode 100644 index 0000000..c98c9b7 --- /dev/null +++ b/game/client/hltvcamera.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HLTVCAMERA_H +#define HLTVCAMERA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "GameEventListener.h" + +class C_HLTVCamera : CGameEventListener +{ +public: + C_HLTVCamera(); + virtual ~C_HLTVCamera(); + + void Init(); + void Reset(); + + void CalcView(Vector& origin, QAngle& angles, float& fov); + void FireGameEvent( IGameEvent *event ); + + void SetMode(int iMode); + void SetChaseCamParams( float flOffset, float flDistance, float flTheta, float flPhi ); + void SpecNextPlayer( bool bInverse ); + void SpecNamedPlayer( const char *szPlayerName ); + void ToggleChaseAsFirstPerson(); + bool IsPVSLocked(); + void SetAutoDirector( bool bActive ); + + int GetMode(); // returns current camera mode + C_BaseEntity *GetPrimaryTarget(); // return primary target + void SetPrimaryTarget( int nEntity); // set the primary obs target + C_BaseEntity *GetCameraMan(); // return camera entity if any + + void CreateMove(CUserCmd *cmd); + void FixupMovmentParents(); + void PostEntityPacketReceived(); + const char* GetTitleText() { return m_szTitleText; } + int GetNumSpectators() { return m_nNumSpectators; } + +protected: + + void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcFixedView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + + void SmoothCameraAngle( QAngle& targetAngle ); + void SetCameraAngle( QAngle& targetAngle ); + void Accelerate( Vector& wishdir, float wishspeed, float accel ); + + int m_nCameraMode; // current camera mode + int m_iCameraMan; // camera man entindex or 0 + Vector m_vCamOrigin; //current camera origin + QAngle m_aCamAngle; //current camera angle + int m_iTraget1; // first tracked target or 0 + int m_iTraget2; // second tracked target or 0 + float m_flFOV; // current FOV + float m_flOffset; // z-offset from target origin + float m_flDistance; // distance to traget origin+offset + float m_flLastDistance; // too smooth distance + float m_flTheta; // view angle horizontal + float m_flPhi; // view angle vertical + float m_flInertia; // camera inertia 0..100 + float m_flLastAngleUpdateTime; + bool m_bEntityPacketReceived; // true after a new packet was received + int m_nNumSpectators; + char m_szTitleText[64]; + CUserCmd m_LastCmd; + Vector m_vecVelocity; +}; + + +extern C_HLTVCamera *HLTVCamera(); // get Singleton + + + +#endif // HLTVCAMERA_H diff --git a/game/client/hud.h b/game/client/hud.h new file mode 100644 index 0000000..b623a3e --- /dev/null +++ b/game/client/hud.h @@ -0,0 +1,206 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: CHud handles the message, calculation, and drawing the HUD +// +// $NoKeywords: $ +//=============================================================================// +#ifndef HUD_H +#define HUD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utldict.h" +#include "convar.h" +#include +#include +#include + +namespace vgui +{ + class IScheme; +} + +// basic rectangle struct used for drawing +typedef struct wrect_s +{ + int left; + int right; + int top; + int bottom; +} wrect_t; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudTexture +{ +public: + CHudTexture(); + CHudTexture& operator =( const CHudTexture& src ); + virtual ~CHudTexture(); + + int Width() const + { + return rc.right - rc.left; + } + + int Height() const + { + return rc.bottom - rc.top; + } + + // causes the font manager to generate the glyph, prevents run time hitches on platforms that have slow font managers + void Precache( void ); + + // returns width & height of icon with scale applied (scale is ignored if font is used to render) + int EffectiveWidth( float flScale ) const; + int EffectiveHeight( float flScale ) const; + + void DrawSelf( int x, int y, const Color& clr ) const; + void DrawSelf( int x, int y, int w, int h, const Color& clr ) const; + void DrawSelfCropped( int x, int y, int cropx, int cropy, int cropw, int croph, Color clr ) const; + // new version to scale the texture over a finalWidth and finalHeight passed in + void DrawSelfCropped( int x, int y, int cropx, int cropy, int cropw, int croph, int finalWidth, int finalHeight, Color clr ) const; + + char szShortName[ 64 ]; + char szTextureFile[ 64 ]; + + bool bRenderUsingFont; + bool bPrecached; + char cCharacterInFont; + vgui::HFont hFont; + + // vgui texture Id assigned to this item + int textureId; + // s0, t0, s1, t1 + float texCoords[ 4 ]; + + // Original bounds + wrect_t rc; +}; + +#include "hudtexturehandle.h" + +class CHudElement; +class CHudRenderGroup; + +//----------------------------------------------------------------------------- +// Purpose: Main hud manager +//----------------------------------------------------------------------------- +class CHud +{ +public: + //For progress bar orientations + static const int HUDPB_HORIZONTAL; + static const int HUDPB_VERTICAL; + static const int HUDPB_HORIZONTAL_INV; + +public: + CHud(); + ~CHud(); + + // Init's called when the HUD's created at DLL load + void Init( void ); + // VidInit's called when the video mode's changed + void VidInit( void ); + // Shutdown's called when the engine's shutting down + void Shutdown( void ); + // LevelInit's called whenever a new level is starting + void LevelInit( void ); + // LevelShutdown's called whenever a level is finishing + void LevelShutdown( void ); + + void ResetHUD( void ); + + // A saved game has just been loaded + void OnRestore(); + + void Think(); + + void ProcessInput( bool bActive ); + void UpdateHud( bool bActive ); + + void InitColors( vgui::IScheme *pScheme ); + + // Hud element registration + void AddHudElement( CHudElement *pHudElement ); + void RemoveHudElement( CHudElement *pHudElement ); + // Search list for "name" and return the hud element if it exists + CHudElement *FindElement( const char *pName ); + + bool IsHidden( int iHudFlags ); + + float GetSensitivity(); + float GetFOVSensitivityAdjust(); + + void DrawProgressBar( int x, int y, int width, int height, float percentage, Color& clr, unsigned char type ); + void DrawIconProgressBar( int x, int y, CHudTexture *icon, CHudTexture *icon2, float percentage, Color& clr, int type ); + + CHudTexture *GetIcon( const char *szIcon ); + + // loads a new icon into the list, without duplicates + CHudTexture *AddUnsearchableHudIconToList( CHudTexture& texture ); + CHudTexture *AddSearchableHudIconToList( CHudTexture& texture ); + + void RefreshHudTextures(); + + // User messages + void MsgFunc_ResetHUD(bf_read &msg); + void MsgFunc_SendAudio(bf_read &msg); + + // Hud Render group + int LookupRenderGroupIndexByName( const char *pszGroupName ); + bool LockRenderGroup( int iGroupIndex, CHudElement *pLocker = NULL ); + bool UnlockRenderGroup( int iGroupIndex, CHudElement *pLocker = NULL ); + bool IsRenderGroupLockedFor( CHudElement *pHudElement, int iGroupIndex ); + int RegisterForRenderGroup( const char *pszGroupName ); + int AddHudRenderGroup( const char *pszGroupName ); + bool DoesRenderGroupExist( int iGroupIndex ); + + void SetScreenShotTime( float flTime ){ m_flScreenShotTime = flTime; } + +public: + + int m_iKeyBits; +#ifndef _XBOX + float m_flMouseSensitivity; + float m_flMouseSensitivityFactor; +#endif + float m_flFOVSensitivityAdjust; + + Color m_clrNormal; + Color m_clrCaution; + Color m_clrYellowish; + + CUtlVector< CHudElement * > m_HudList; + +private: + void InitFonts(); + + void SetupNewHudTexture( CHudTexture *t ); + + bool m_bHudTexturesLoaded; + + // Global list of known icons + CUtlDict< CHudTexture *, int > m_Icons; + + CUtlVector< const char * > m_RenderGroupNames; + CUtlMap< int, CHudRenderGroup * > m_RenderGroups; + + float m_flScreenShotTime; // used to take end-game screenshots +}; + +extern CHud gHUD; + +//----------------------------------------------------------------------------- +// Global fonts used in the client DLL +//----------------------------------------------------------------------------- +extern vgui::HFont g_hFontTrebuchet24; + +void LoadHudTextures( CUtlDict< CHudTexture *, int >& list, const char *szFilenameWithoutExtension, const unsigned char *pICEKey ); + +void GetHudSize( int& w, int &h ); + +#endif // HUD_H diff --git a/game/client/hud_base_account.h b/game/client/hud_base_account.h new file mode 100644 index 0000000..b65e354 --- /dev/null +++ b/game/client/hud_base_account.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_BASE_ACCOUNT_H +#define HUD_BASE_ACCOUNT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include "hud_numericdisplay.h" + +using namespace vgui; + +class CHudBaseAccount : public CHudElement, public CHudNumericDisplay +{ +public: + DECLARE_CLASS_SIMPLE( CHudBaseAccount, CHudNumericDisplay ); + + CHudBaseAccount( const char *name ); + + virtual bool ShouldDraw(); + virtual void Paint(); + virtual void LevelInit( void ); + virtual void Reset( void ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + int GetNumberWidth(HFont font, int number); + + // How much money does the player have + virtual int GetPlayerAccount( void ) { return 0; } + + // Requires game-specific g_pClientMode call, push to derived class + virtual vgui::AnimationController *GetAnimationController( void ) { Assert( 0 ); return NULL; } + +private: + int m_iPreviousAccount; + int m_iPreviousDelta; + CHudTexture *m_pAccountIcon; + CHudTexture *m_pMinusIcon; + CHudTexture *m_pPlusIcon; + + Color m_clrRed; + Color m_clrGreen; + Color m_clrDeltaColor; + + CPanelAnimationVarAliasType( float, icon_xpos, "icon_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, icon_ypos, "icon_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, icon2_xpos, "icon2_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, icon2_ypos, "icon2_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_xpos, "digit_xpos", "50", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_ypos, "digit_ypos", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_xpos, "digit2_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_ypos, "digit2_ypos", "0", "proportional_float" ); + CPanelAnimationVar( Color, m_Ammo2Color, "Ammo2Color", "0 0 0 0" ); + + CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudNumbers" ); + + float m_flLastAnimationEnd; + const char *m_pszLastAnimationName; + const char *m_pszQueuedAnimationName; + + float icon_tall; + float icon_wide; +}; + + +#endif // HUD_BASE_ACCOUNT_H + + + diff --git a/game/client/hud_basechat.h b/game/client/hud_basechat.h new file mode 100644 index 0000000..cf5c3f1 --- /dev/null +++ b/game/client/hud_basechat.h @@ -0,0 +1,439 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_BASECHAT_H +#define HUD_BASECHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include +#include "vgui_basepanel.h" +#include "vgui_controls/Frame.h" +#include +#include +#include +#include + +class CBaseHudChatInputLine; +class CBaseHudChatEntry; +class CHudChatFilterPanel; + +namespace vgui +{ + class IScheme; +}; + +#define CHATLINE_NUM_FLASHES 8.0f +#define CHATLINE_FLASH_TIME 5.0f +#define CHATLINE_FADE_TIME 1.0f + +#define CHAT_HISTORY_FADE_TIME 0.25f +#define CHAT_HISTORY_IDLE_TIME 15.0f +#define CHAT_HISTORY_IDLE_FADE_TIME 2.5f +#define CHAT_HISTORY_ALPHA 127 + +extern Color g_ColorBlue; +extern Color g_ColorRed; +extern Color g_ColorGreen; +extern Color g_ColorDarkGreen; +extern Color g_ColorYellow; +extern Color g_ColorGrey; + +extern ConVar cl_showtextmsg; + +enum ChatFilters +{ + CHAT_FILTER_NONE = 0, + CHAT_FILTER_JOINLEAVE = 0x000001, + CHAT_FILTER_NAMECHANGE = 0x000002, + CHAT_FILTER_PUBLICCHAT = 0x000004, + CHAT_FILTER_SERVERMSG = 0x000008, + CHAT_FILTER_TEAMCHANGE = 0x000010, + //============================================================================= + // HPE_BEGIN: + // [tj]Added a filter for achievement announce + //============================================================================= + + CHAT_FILTER_ACHIEVEMENT = 0x000020, + + //============================================================================= + // HPE_END + //============================================================================= +}; + + +//----------------------------------------------------------------------------- +enum TextColor +{ + COLOR_NORMAL = 1, + COLOR_USEOLDCOLORS = 2, + COLOR_PLAYERNAME = 3, + COLOR_LOCATION = 4, + COLOR_ACHIEVEMENT = 5, + COLOR_CUSTOM = 6, // Will use the most recently SetCustomColor() + COLOR_HEXCODE = 7, // Reads the color from the next six characters + COLOR_HEXCODE_ALPHA = 8,// Reads the color and alpha from the next eight characters + COLOR_MAX +}; + +//-------------------------------------------------------------------------------------------------------------- +struct TextRange +{ + TextRange() { preserveAlpha = false; } + int start; + int end; + Color color; + bool preserveAlpha; +}; + +void StripEndNewlineFromString( char *str ); +void StripEndNewlineFromString( wchar_t *str ); + +char* ConvertCRtoNL( char *str ); +wchar_t* ConvertCRtoNL( wchar_t *str ); +wchar_t* ReadLocalizedString( bf_read &msg, OUT_Z_BYTECAP(outSizeInBytes) wchar_t *pOut, int outSizeInBytes, bool bStripNewline, OUT_Z_CAP(originalSize) char *originalString = NULL, int originalSize = 0 ); +wchar_t* ReadChatTextString( bf_read &msg, OUT_Z_BYTECAP(outSizeInBytes) wchar_t *pOut, int outSizeInBytes ); +char* RemoveColorMarkup( char *str ); + +//-------------------------------------------------------------------------------------------------------- +/** + * Simple utility function to allocate memory and duplicate a wide string + */ +inline wchar_t *CloneWString( const wchar_t *str ) +{ + const int nLen = V_wcslen(str)+1; + wchar_t *cloneStr = new wchar_t [ nLen ]; + const int nSize = nLen * sizeof( wchar_t ); + V_wcsncpy( cloneStr, str, nSize ); + return cloneStr; +} + +//----------------------------------------------------------------------------- +// Purpose: An output/display line of the chat interface +//----------------------------------------------------------------------------- +class CBaseHudChatLine : public vgui::RichText +{ + typedef vgui::RichText BaseClass; + +public: + CBaseHudChatLine( vgui::Panel *parent, const char *panelName ); + ~CBaseHudChatLine(); + + void SetExpireTime( void ); + + bool IsReadyToExpire( void ); + + void Expire( void ); + + float GetStartTime( void ); + + int GetCount( void ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + vgui::HFont GetFont() { return m_hFont; } + + Color GetTextColor( void ) { return m_clrText; } + void SetNameLength( int iLength ) { m_iNameLength = iLength; } + void SetNameColor( Color cColor ){ m_clrNameColor = cColor; } + + virtual void PerformFadeout( void ); + virtual void InsertAndColorizeText( wchar_t *buf, int clientIndex ); + virtual void Colorize( int alpha = 255 ); ///< Re-inserts the text in the appropriate colors at the given alpha + + + void SetNameStart( int iStart ) { m_iNameStart = iStart; } + +protected: + int m_iNameLength; + vgui::HFont m_hFont; + + Color m_clrText; + Color m_clrNameColor; + + float m_flExpireTime; + + CUtlVector< TextRange > m_textRanges; + wchar_t *m_text; + + int m_iNameStart; + +private: + float m_flStartTime; + int m_nCount; + + vgui::HFont m_hFontMarlett; + + +private: + CBaseHudChatLine( const CBaseHudChatLine & ); // not defined, not accessible +}; + + +class CHudChatHistory : public vgui::RichText +{ + DECLARE_CLASS_SIMPLE( CHudChatHistory, vgui::RichText ); +public: + + CHudChatHistory( vgui::Panel *pParent, const char *panelName ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +}; + +class CHudChatFilterButton : public vgui::Button +{ + DECLARE_CLASS_SIMPLE( CHudChatFilterButton, vgui::Button ); + +public: + + CHudChatFilterButton( vgui::Panel *pParent, const char *pName, const char *pText ); + + virtual void DoClick( void ); +}; + +class CHudChatFilterCheckButton : public vgui::CheckButton +{ + DECLARE_CLASS_SIMPLE( CHudChatFilterCheckButton, vgui::CheckButton ); + +public: + + CHudChatFilterCheckButton( vgui::Panel *pParent, const char *pName, const char *pText, int iFlag ); + + int GetFilterFlag( void ) { return m_iFlag; } + +private: + + int m_iFlag; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBaseHudChat : public CHudElement, public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CBaseHudChat, vgui::EditablePanel ); +public: + DECLARE_MULTIPLY_INHERITED(); + + enum + { + CHAT_INTERFACE_LINES = 6, + MAX_CHARS_PER_LINE = 128 + }; + + CBaseHudChat( const char *pElementName ); + + virtual void CreateChatInputLine( void ); + virtual void CreateChatLines( void ); + + virtual void Init( void ); + + void LevelInit( const char *newmap ); + void LevelShutdown( void ); + + void MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); + + virtual void Printf( int iFilter, PRINTF_FORMAT_STRING const char *fmt, ... ); + virtual void ChatPrintf( int iPlayerIndex, int iFilter, PRINTF_FORMAT_STRING const char *fmt, ... ) FMTFUNCTION( 4, 5 ); + + virtual void StartMessageMode( int iMessageModeType ); + virtual void StopMessageMode( void ); + void Send( void ); + + MESSAGE_FUNC( OnChatEntrySend, "ChatEntrySend" ); + MESSAGE_FUNC( OnChatEntryStopMessageMode, "ChatEntryStopMessageMode" ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void Paint( void ); + virtual void OnTick( void ); + virtual void Reset(); +#ifdef _XBOX + virtual bool ShouldDraw(); +#endif + vgui::Panel *GetInputPanel( void ); + + static int m_nLineCounter; + + virtual int GetChatInputOffset( void ); + + // IGameEventListener interface: + virtual void FireGameEvent( IGameEvent *event); + + CHudChatHistory *GetChatHistory(); + + void FadeChatHistory(); + float m_flHistoryFadeTime; + float m_flHistoryIdleTime; + + virtual void MsgFunc_SayText( bf_read &msg ); + virtual void MsgFunc_SayText2( bf_read &msg ); + virtual void MsgFunc_TextMsg( bf_read &msg ); + virtual void MsgFunc_VoiceSubtitle( bf_read &msg ); + + + CBaseHudChatInputLine *GetChatInput( void ) { return m_pChatInput; } + CHudChatFilterPanel *GetChatFilterPanel( void ); + + virtual int GetFilterFlags( void ) { return m_iFilterFlags; } + void SetFilterFlag( int iFilter ); + + //----------------------------------------------------------------------------- + virtual Color GetDefaultTextColor( void ); + virtual Color GetTextColorForClient( TextColor colorNum, int clientIndex ); + virtual Color GetClientColor( int clientIndex ); + + virtual int GetFilterForString( const char *pString ); + + virtual const char *GetDisplayedSubtitlePlayerName( int clientIndex ); + + bool IsVoiceSubtitle( void ) { return m_bEnteringVoice; } + void SetVoiceSubtitleState( bool bState ) { m_bEnteringVoice = bState; } + int GetMessageMode( void ) { return m_nMessageMode; } + + void SetCustomColor( Color colNew ) { m_ColorCustom = colNew; } + void SetCustomColor( const char *pszColorName ); + +protected: + CBaseHudChatLine *FindUnusedChatLine( void ); + + CBaseHudChatInputLine *m_pChatInput; + CBaseHudChatLine *m_ChatLine; + int m_iFontHeight; + + CHudChatHistory *m_pChatHistory; + + CHudChatFilterButton *m_pFiltersButton; + CHudChatFilterPanel *m_pFilterPanel; + + Color m_ColorCustom; + +private: + void Clear( void ); + + int ComputeBreakChar( int width, const char *text, int textlen ); + + int m_nMessageMode; + + int m_nVisibleHeight; + + vgui::HFont m_hChatFont; + + int m_iFilterFlags; + bool m_bEnteringVoice; + +}; + +class CBaseHudChatEntry : public vgui::TextEntry +{ + typedef vgui::TextEntry BaseClass; +public: + CBaseHudChatEntry( vgui::Panel *parent, char const *panelName, vgui::Panel *pChat ) + : BaseClass( parent, panelName ) + { + SetCatchEnterKey( true ); + SetAllowNonAsciiCharacters( true ); + SetDrawLanguageIDAtLeft( true ); + m_pHudChat = pChat; + } + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) + { + BaseClass::ApplySchemeSettings(pScheme); + + SetPaintBorderEnabled( false ); + } + + virtual void OnKeyCodeTyped(vgui::KeyCode code) + { + if ( code == KEY_ENTER || code == KEY_PAD_ENTER || code == KEY_ESCAPE ) + { + if ( code != KEY_ESCAPE ) + { + if ( m_pHudChat ) + { + PostMessage( m_pHudChat, new KeyValues("ChatEntrySend") ); + } + } + + // End message mode. + if ( m_pHudChat ) + { + PostMessage( m_pHudChat, new KeyValues("ChatEntryStopMessageMode") ); + } + } + else if ( code == KEY_TAB ) + { + // Ignore tab, otherwise vgui will screw up the focus. + return; + } + else + { + BaseClass::OnKeyCodeTyped( code ); + } + } + +private: + vgui::Panel *m_pHudChat; +}; + +//----------------------------------------------------------------------------- +// Purpose: The prompt and text entry area for chat messages +//----------------------------------------------------------------------------- +class CBaseHudChatInputLine : public vgui::Panel +{ + typedef vgui::Panel BaseClass; + +public: + CBaseHudChatInputLine( vgui::Panel *parent, char const *panelName ); + + void SetPrompt( const wchar_t *prompt ); + void ClearEntry( void ); + void SetEntry( const wchar_t *entry ); + void GetMessageText( OUT_Z_BYTECAP(buffersizebytes) wchar_t *buffer, int buffersizebytes ); + + virtual void PerformLayout(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + vgui::Panel *GetInputPanel( void ); + virtual vgui::VPANEL GetCurrentKeyFocus() { return m_pInput->GetVPanel(); } + + virtual void Paint() + { + BaseClass::Paint(); + } + + vgui::Label *GetPrompt( void ) { return m_pPrompt; } + +protected: + vgui::Label *m_pPrompt; + CBaseHudChatEntry *m_pInput; +}; + + +class CHudChatFilterPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CHudChatFilterPanel, vgui::EditablePanel ); + +public: + + CHudChatFilterPanel( vgui::Panel *pParent, const char *pName ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + MESSAGE_FUNC_PTR( OnFilterButtonChecked, "CheckButtonChecked", panel ); + + CBaseHudChat *GetChatParent( void ) { return dynamic_cast < CBaseHudChat * > ( GetParent() ); } + + virtual void SetVisible(bool state); + +private: + +}; + +#endif // HUD_BASECHAT_H diff --git a/game/client/hud_basedeathnotice.h b/game/client/hud_basedeathnotice.h new file mode 100644 index 0000000..b4f34eb --- /dev/null +++ b/game/client/hud_basedeathnotice.h @@ -0,0 +1,141 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_BASEDEATHNOTICE_H +#define HUD_BASEDEATHNOTICE_H +#ifdef _WIN32 +#pragma once +#endif + +// Player entries in a death notice +struct DeathNoticePlayer +{ + DeathNoticePlayer() + { + szName[0] = 0; + iTeam = TEAM_UNASSIGNED; + } + char szName[MAX_PLAYER_NAME_LENGTH*2]; // big enough for player name and additional information + int iTeam; // team # +}; + +// Contents of each entry in our list of death notices +struct DeathNoticeItem +{ + DeathNoticeItem() + { + szIcon[0]=0; + wzInfoText[0]=0; + wzInfoTextEnd[0]=0; + iconDeath = NULL; + iconCritDeath = NULL; + bSelfInflicted = false; + bLocalPlayerInvolved = false; + bCrit = false; + flCreationTime = 0; + iCount = 0; + iWeaponID = -1; + iKillerID = -1; + iVictimID = -1; + + iconPreKillerName = NULL; + iconPostKillerName = NULL; + wzPreKillerText[0] = 0; + iconPostVictimName = NULL; + } + + float GetExpiryTime(); + + DeathNoticePlayer Killer; + DeathNoticePlayer Victim; + char szIcon[32]; // name of icon to display + wchar_t wzInfoText[32]; // any additional text to display next to icon + wchar_t wzInfoTextEnd[32]; // any additional text to display next to victim name + CHudTexture *iconDeath; + CHudTexture *iconCritDeath; // crit background icon + + CHudTexture *iconPreKillerName; + + CHudTexture *iconPostKillerName; + wchar_t wzPreKillerText[32]; + + CHudTexture *iconPostVictimName; + + bool bSelfInflicted; + bool bLocalPlayerInvolved; + bool bCrit; + float flCreationTime; + int iWeaponID; + int iKillerID; + int iVictimID; + int iCount; +}; + +#define NUM_CORNER_COORD 10 +#define NUM_BACKGROUND_COORD NUM_CORNER_COORD*4 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudBaseDeathNotice : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudBaseDeathNotice, vgui::Panel ); +public: + CHudBaseDeathNotice( const char *pElementName ); + + void VidInit( void ); + virtual void Init( void ); + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + void RetireExpiredDeathNotices( void ); + + virtual void FireGameEvent( IGameEvent *event ); + virtual bool ShouldShowDeathNotice( IGameEvent *event ){ return true; } + +protected: + virtual Color GetTeamColor( int iTeamNumber, bool bLocalPlayerInvolved = false ); + virtual void OnGameEvent( IGameEvent *event, int iDeathNoticeMsg ) {}; + void DrawText( int x, int y, vgui::HFont hFont, Color clr, const wchar_t *szText ); + int AddDeathNoticeItem(); + void GetBackgroundPolygonVerts( int x0, int y0, int x1, int y1, int iVerts, vgui::Vertex_t vert[] ); + void CalcRoundedCorners(); + + enum EDeathNoticeIconFormat + { + kDeathNoticeIcon_Standard, + kDeathNoticeIcon_Inverted, // used for display on lighter background when kill involved the local player + }; + + CHudTexture *GetIcon( const char *szIcon, EDeathNoticeIconFormat eIconFormat ); + + virtual bool EventIsPlayerDeath( const char *eventName ); + + virtual int UseExistingNotice( IGameEvent *event ) { return -1; } + + void GetLocalizedControlPointName( IGameEvent *event, char *namebuf, int namelen ); + virtual Color GetInfoTextColor( int iDeathNoticeMsg ){ return Color( 255, 255, 255, 255 ); } + virtual Color GetBackgroundColor ( int iDeathNoticeMsg ) { return m_DeathNotices[iDeathNoticeMsg].bLocalPlayerInvolved ? m_clrLocalBGColor : m_clrBaseBGColor; } + + CPanelAnimationVarAliasType( float, m_flLineHeight, "LineHeight", "16", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flLineSpacing, "LineSpacing", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flCornerRadius, "CornerRadius", "3", "proportional_float" ); + CPanelAnimationVar( float, m_flMaxDeathNotices, "MaxDeathNotices", "4" ); + CPanelAnimationVar( bool, m_bRightJustify, "RightJustify", "1" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + CPanelAnimationVar( Color, m_clrIcon, "IconColor", "255 80 0 255" ); + CPanelAnimationVar( Color, m_clrBaseBGColor, "BaseBackgroundColor", "46 43 42 220" ); + CPanelAnimationVar( Color, m_clrLocalBGColor, "LocalBackgroundColor", "245 229 196 200" ); + CPanelAnimationVar( Color, m_clrKillStreakBg, "KillStreakBackgroundColor", "224 223 219 200" ); + + CUtlVector m_DeathNotices; + + Vector2D m_CornerCoord[NUM_CORNER_COORD]; +}; + +#endif // HUD_BASEDEATHNOTICE_H diff --git a/game/client/hud_basetimer.h b/game/client/hud_basetimer.h new file mode 100644 index 0000000..f407b13 --- /dev/null +++ b/game/client/hud_basetimer.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_BASETIMER_H +#define HUD_BASETIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_numericdisplay.h" + +//----------------------------------------------------------------------------- +// Purpose: Base class for all the hud elements that are just a numeric display +// with some options for text and icons +//----------------------------------------------------------------------------- +class CHudBaseTimer : public CHudNumericDisplay +{ + DECLARE_CLASS_SIMPLE( CHudBaseTimer, CHudNumericDisplay ); + +public: + CHudBaseTimer(vgui::Panel *parent, const char *name); + + void SetMinutes( int minutes ); + void SetSeconds( int seconds ); + +protected: + // vgui overrides + virtual void Paint(); + + void SetToPrimaryColor(); + void SetToSecondaryColor(); + +private: + void PaintTime(vgui::HFont font, int xpos, int ypos, int mins, int secs); + + int m_iMinutes; + int m_iSeconds; + wchar_t m_LabelText[32]; + + CPanelAnimationVar( float, m_flBlur, "Blur", "0" ); + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); + CPanelAnimationVar( Color, m_FlashColor, "SecondaryColor", "FgColor" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudNumbers" ); + CPanelAnimationVar( vgui::HFont, m_hNumberGlowFont, "NumberGlowFont", "HudNumbersGlow" ); + CPanelAnimationVar( vgui::HFont, m_hSmallNumberFont, "SmallNumberFont", "HudNumbersSmall" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + + CPanelAnimationVarAliasType( float, text_xpos, "text_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text_ypos, "text_ypos", "20", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_xpos, "digit_xpos", "50", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_ypos, "digit_ypos", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_xpos, "digit2_xpos", "98", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_ypos, "digit2_ypos", "16", "proportional_float" ); +}; + + +#endif // HUD_BASETIMER_H diff --git a/game/client/hud_bitmapnumericdisplay.h b/game/client/hud_bitmapnumericdisplay.h new file mode 100644 index 0000000..f35d753 --- /dev/null +++ b/game/client/hud_bitmapnumericdisplay.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_BITMAPNUMERICDISPLAY_H +#define HUD_BITMAPNUMERICDISPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_numericdisplay.h" + +class CHudBitmapNumericDisplay : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudBitmapNumericDisplay, vgui::Panel ); + +public: + CHudBitmapNumericDisplay(vgui::Panel *parent, const char *name); + + void SetDisplayValue(int value); + void SetShouldDisplayValue(bool state); + +protected: + // vgui overrides + virtual void PaintBackground( void ); + virtual void Paint(); + void PaintNumbers(int xpos, int ypos, int value, Color col, int numSigDigits); + virtual void PaintNumbers(int xpos, int ypos, int value, Color col) + { + PaintNumbers(xpos, ypos, value, col, 1); + } + + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); + CPanelAnimationVar( float, m_flBlur, "Blur", "0" ); + + CPanelAnimationVarAliasType( float, digit_xpos, "digit_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_ypos, "digit_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_height, "digit_height", "16", "proportional_float" ); + +private: + + CHudTexture *m_pNumbers[10]; + + int m_iValue; + bool m_bDisplayValue; +}; + +#endif //HUD_BITMAPNUMERICDISPLAY_H \ No newline at end of file diff --git a/game/client/hud_chat.h b/game/client/hud_chat.h new file mode 100644 index 0000000..ff968fd --- /dev/null +++ b/game/client/hud_chat.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_CHAT_H +#define HUD_CHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +class CHudChat : public CBaseHudChat +{ + DECLARE_CLASS_SIMPLE( CHudChat, CBaseHudChat ); + +public: + CHudChat( const char *pElementName ); + + virtual void Init( void ); + + void MsgFunc_SayText(bf_read &msg); + void MsgFunc_SayText2( bf_read &msg ); + void MsgFunc_TextMsg(bf_read &msg); +}; + +#endif //HUD_CHAT_H \ No newline at end of file diff --git a/game/client/hud_closecaption.h b/game/client/hud_closecaption.h new file mode 100644 index 0000000..180afe9 --- /dev/null +++ b/game/client/hud_closecaption.h @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_CLOSECAPTION_H +#define HUD_CLOSECAPTION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include +#include "captioncompiler.h" +#include "tier1/UtlSortVector.h" +#include "tier1/utlsymbol.h" + +class CSentence; +class C_BaseFlex; +class CCloseCaptionItem; +struct WorkUnitParams; +class CAsyncCaption; + +typedef CUtlSortVector< CaptionLookup_t, CCaptionLookupLess > CaptionDictionary_t; +struct AsyncCaptionData_t; +struct AsyncCaption_t +{ + AsyncCaption_t() : + m_DataBaseFile( UTL_INVAL_SYMBOL ), + m_RequestedBlocks( 0, 0, BlockInfo_t::Less ) + { + Q_memset( &m_Header, 0, sizeof( m_Header ) ); + } + + struct BlockInfo_t + { + int fileindex; + int blocknum; + memhandle_t handle; + + static bool Less( const BlockInfo_t& lhs, const BlockInfo_t& rhs ) + { + if ( lhs.fileindex != rhs.fileindex ) + return lhs.fileindex < rhs.fileindex; + + return lhs.blocknum < rhs.blocknum; + } + }; + + AsyncCaption_t& operator =( const AsyncCaption_t& rhs ) + { + if ( this == &rhs ) + return *this; + + m_CaptionDirectory = rhs.m_CaptionDirectory; + m_Header = rhs.m_Header; + m_DataBaseFile = rhs.m_DataBaseFile; + + for ( int i = rhs.m_RequestedBlocks.FirstInorder(); i != rhs.m_RequestedBlocks.InvalidIndex(); i = rhs.m_RequestedBlocks.NextInorder( i ) ) + { + m_RequestedBlocks.Insert( rhs.m_RequestedBlocks[ i ] ); + } + + return *this; + } + + CUtlRBTree< BlockInfo_t, unsigned short > m_RequestedBlocks; + + CaptionDictionary_t m_CaptionDirectory; + CompiledCaptionHeader_t m_Header; + CUtlSymbol m_DataBaseFile; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudCloseCaption : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudCloseCaption, vgui::Panel ); +public: + DECLARE_MULTIPLY_INHERITED(); + + CHudCloseCaption( const char *pElementName ); + virtual ~CHudCloseCaption(); + + // Expire lingering items + virtual void OnTick( void ); + + virtual void LevelInit( void ); + + virtual void LevelShutdown( void ) + { + Reset(); + } + + // Painting methods + virtual void Paint(); + + void MsgFunc_CloseCaption(bf_read &msg); + + // Clear all CC data + void Reset( void ); + void Process( const wchar_t *stream, float duration, char const *tokenstream, bool fromplayer, bool direct = false ); + + bool ProcessCaption( char const *tokenname, float duration, bool fromplayer = false, bool direct = false ); + void ProcessCaptionDirect( char const *tokenname, float duration, bool fromplayer = false ); + + void ProcessSentenceCaptionStream( char const *tokenstream ); + void PlayRandomCaption(); + + void InitCaptionDictionary( char const *dbfile ); + void OnFinishAsyncLoad( int nFileIndex, int nBlockNum, AsyncCaptionData_t *pData ); + + void Flush(); + void TogglePaintDebug(); + + enum + { + CCFONT_NORMAL = 0, + CCFONT_ITALIC, + CCFONT_BOLD, + CCFONT_ITALICBOLD, + CCFONT_SMALL, + CCFONT_MAX + }; + + static int GetFontNumber( bool bold, bool italic ); + + void Lock( void ); + void Unlock( void ); + + void FindSound( char const *pchANSI ); + +public: + + struct CaptionRepeat + { + CaptionRepeat() : + m_nTokenIndex( 0 ), + m_flLastEmitTime( 0 ), + m_flInterval( 0 ), + m_nLastEmitTick( 0 ) + { + } + int m_nTokenIndex; + int m_nLastEmitTick; + float m_flLastEmitTime; + float m_flInterval; + }; + +private: + + void ClearAsyncWork(); + void ProcessAsyncWork(); + bool AddAsyncWork( char const *tokenstream, bool bIsStream, float duration, bool fromplayer, bool direct = false ); + + void _ProcessSentenceCaptionStream( int wordCount, char const *tokenstream, const wchar_t *caption_full ); + void _ProcessCaption( const wchar_t *caption, char const *tokenname, float duration, bool fromplayer, bool direct = false ); + + CUtlLinkedList< CAsyncCaption *, unsigned short > m_AsyncWork; + + CUtlRBTree< CaptionRepeat, int > m_CloseCaptionRepeats; + +private: + + static bool CaptionTokenLessFunc( const CaptionRepeat &lhs, const CaptionRepeat &rhs ); + + void DrawStream( wrect_t& rect, wrect_t &rcWindow, CCloseCaptionItem *item, int iFadeLine, float flFadeLineAlpha ); + void ComputeStreamWork( int available_width, CCloseCaptionItem *item ); + bool SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t *args ) const; + + bool StreamHasCommand( const wchar_t *stream, const wchar_t *findcmd ) const; + bool GetFloatCommandValue( const wchar_t *stream, const wchar_t *findcmd, float& value ) const; + + bool GetNoRepeatValue( const wchar_t *caption, float &retval ); + + void ParseCloseCaptionStream( const wchar_t *in, int available_width ); + bool StreamHasCommand( const wchar_t *stream, const wchar_t *search ); + + void DumpWork( CCloseCaptionItem *item ); + + void AddWorkUnit( + CCloseCaptionItem *item, + WorkUnitParams& params ); + + CUtlVector< CCloseCaptionItem * > m_Items; + + vgui::HFont m_hFonts[CCFONT_MAX]; + + void CreateFonts( void ); + + int m_nLineHeight; + + int m_nGoalHeight; + int m_nCurrentHeight; + float m_flGoalAlpha; + float m_flCurrentAlpha; + float m_flGoalHeightStartTime; + float m_flGoalHeightFinishTime; + + CPanelAnimationVar( float, m_flBackgroundAlpha, "BgAlpha", "192" ); + CPanelAnimationVar( float, m_flGrowTime, "GrowTime", "0.25" ); + CPanelAnimationVar( float, m_flItemHiddenTime, "ItemHiddenTime", "0.2" ); + CPanelAnimationVar( float, m_flItemFadeInTime, "ItemFadeInTime", "0.15" ); + CPanelAnimationVar( float, m_flItemFadeOutTime, "ItemFadeOutTime", "0.3" ); + CPanelAnimationVar( int, m_nTopOffset, "topoffset", "40" ); + + CUtlVector< AsyncCaption_t > m_AsyncCaptions; + bool m_bLocked; + bool m_bVisibleDueToDirect; + bool m_bPaintDebugInfo; + CUtlSymbol m_CurrentLanguage; +}; + +#endif // HUD_CLOSECAPTION_H diff --git a/game/client/hud_controlpointicons.h b/game/client/hud_controlpointicons.h new file mode 100644 index 0000000..c660ca7 --- /dev/null +++ b/game/client/hud_controlpointicons.h @@ -0,0 +1,438 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef HUD_CONTROLPOINTICONS_H +#define HUD_CONTROLPOINTICONS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" +#include "hudelement.h" +#include +#include +#include +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/CircularProgressBar.h" +#include +#include "tf_controls.h" +#include "IconPanel.h" + +#define PULSE_TIME_PER_ICON 1.5f + +#define PULSE_RAMP_TIME 0.5 +#define PULSE_REMAP_SIZE 6.0 +#define FAKE_CAPTURE_TIME 5.0 +#define FAKE_CAPTURE_POST_PAUSE 2.0 + +extern ConVar mp_capstyle; +extern ConVar mp_blockstyle; + +#define STARTCAPANIM_SWOOP_LENGTH 0.4 +#define STARTCAPANIM_ICON_SWITCH 0.15 +#define FINISHCAPANIM_SWOOP_LENGTH 0.2 + +#define CAP_BOX_INDENT_X XRES(2) +#define CAP_BOX_INDENT_Y YRES(2) + +#define CP_TEXTURE_COUNT 8 + +class CControlPointIcon; + +// Options for how the cap progress teardrop positions itself around the cap point icon +enum +{ + CP_DIR_N, + CP_DIR_NW, + CP_DIR_NE, +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CControlPointCountdown : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CControlPointCountdown, vgui::EditablePanel ); + +public: + CControlPointCountdown(Panel *parent, const char *name); + + virtual void ApplySchemeSettings( IScheme *scheme ); + virtual void PerformLayout(); + virtual void OnTick( void ); + + void SetUnlockTime( float flTime ); + float GetUnlockTime( void ){ return m_flUnlockTime; } + +private: + + bool m_bFire5SecRemain; + bool m_bFire4SecRemain; + bool m_bFire3SecRemain; + bool m_bFire2SecRemain; + bool m_bFire1SecRemain; + bool m_bFire0SecRemain; + + int m_flUnlockTime; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CControlPointProgressBar : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CControlPointProgressBar, vgui::EditablePanel ); +public: + CControlPointProgressBar(Panel *parent); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout( void ); + virtual void Paint( void ); + virtual bool IsVisible( void ); + virtual void Reset( void ); + + void SetupForPoint( CControlPointIcon *pIcon ); + void UpdateBarText( void ); + +private: + CControlPointIcon *m_pAttachedToIcon; + vgui::CircularProgressBar *m_pBar; + vgui::Label *m_pBarText; + CIconPanel *m_pTeardrop; + CIconPanel *m_pTeardropSide; + CIconPanel *m_pBlocked; + int m_iOrgHeight; + int m_iMidGroupIndex; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CControlPointIconSwoop : public vgui::ImagePanel, public CGameEventListener +{ + DECLARE_CLASS_SIMPLE( CControlPointIconSwoop, vgui::ImagePanel ); +public: + CControlPointIconSwoop(Panel *parent, const char *name) : vgui::ImagePanel( parent, name ) + { + SetImage( "../sprites/obj_icons/capture_highlight" ); + SetShouldScaleImage( true ); + ListenForGameEvent( "localplayer_changeteam" ); + } + + virtual void PaintBackground( void ) + { + float flElapsedTime = (gpGlobals->curtime - m_flStartCapAnimStart); + + if (GetImage()) + { + surface()->DrawSetColor(255, 255, 255, 255); + int iYPos = RemapValClamped( flElapsedTime, 0, STARTCAPANIM_SWOOP_LENGTH, 0, GetTall() ); + GetImage()->SetPos( 0, iYPos ); + GetImage()->Paint(); + } + + // Once we've finished the swoop, go away + if ( flElapsedTime >= STARTCAPANIM_SWOOP_LENGTH ) + { + SetVisible( false ); + } + } + + virtual bool IsVisible( void ) + { + if ( IsInFreezeCam() == true ) + return false; + + return BaseClass::IsVisible(); + } + + void StartSwoop( void ) + { + m_flStartCapAnimStart = gpGlobals->curtime; + } + + void FireGameEvent( IGameEvent * event ) + { + if ( FStrEq( "localplayer_changeteam", event->GetName() ) ) + { + SetVisible( false ); + } + } + +private: + float m_flStartCapAnimStart; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CControlPointIconCapArrow : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CControlPointIconCapArrow, vgui::Panel ); +public: + CControlPointIconCapArrow( CControlPointIcon *pIcon, Panel *parent, const char *name); + + virtual void Paint( void ); + virtual bool IsVisible( void ); + + void SetImage( const char *pszImage ) + { + m_pArrowMaterial = materials->FindMaterial( pszImage, TEXTURE_GROUP_VGUI ); + } + +private: + IMaterial *m_pArrowMaterial; + CControlPointIcon *m_pAttachedToIcon; + +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CControlPointIconCapturePulse : public vgui::ImagePanel +{ + DECLARE_CLASS_SIMPLE( CControlPointIconCapturePulse, vgui::ImagePanel ); +public: + CControlPointIconCapturePulse(Panel *parent, const char *name) : vgui::ImagePanel( parent, name ) + { + SetImage( "../sprites/obj_icons/icon_obj_white" ); + SetShouldScaleImage( true ); + } + + virtual void PaintBackground( void ) + { + if ( m_flFinishCapAnimStart && gpGlobals->curtime > m_flFinishCapAnimStart ) + { + float flElapsedTime = MAX( 0, (gpGlobals->curtime - m_flFinishCapAnimStart) ); + if (GetImage()) + { + surface()->DrawSetColor(255, 255, 255, 255); + int iSize = RemapValClamped( flElapsedTime, 0, FINISHCAPANIM_SWOOP_LENGTH, GetWide(), m_iShrinkSize ); + GetImage()->SetPos( (GetWide() - iSize)*0.5, (GetTall() - iSize)*0.5 ); + GetImage()->SetSize( iSize, iSize ); + GetImage()->Paint(); + } + + // Once we've finished the swoop, go away + if ( flElapsedTime >= FINISHCAPANIM_SWOOP_LENGTH ) + { + SetVisible( false ); + } + } + } + + void StartPulse( float flTime, int iShrinkSize ) + { + m_flFinishCapAnimStart = flTime; + m_iShrinkSize = iShrinkSize; + + if ( GetWide() < m_iShrinkSize ) + { + SetWide( m_iShrinkSize ); + } + } + + virtual bool IsVisible( void ) + { + if ( IsInFreezeCam() == true ) + return false; + + return BaseClass::IsVisible(); + } + +private: + float m_flFinishCapAnimStart; + int m_iShrinkSize; +}; + +//----------------------------------------------------------------------------- +// Purpose: The base image in the cap point icons that pulses. +//----------------------------------------------------------------------------- +class CControlPointIconPulseable : public vgui::ImagePanel +{ + DECLARE_CLASS_SIMPLE( CControlPointIconPulseable, vgui::ImagePanel ); +public: + CControlPointIconPulseable(Panel *parent, const char *name, int iIndex) : vgui::ImagePanel( parent, name ) + { + SetShouldScaleImage( true ); + m_pPulseImage = NULL; + m_iCPIndex = iIndex; + } + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void OnSizeChanged(int newWide, int newTall); + virtual void PaintBackground( void ); + + void StartPulsing( float flDelay, float flPulseTime, bool bAccelerate ); + void StopPulsing( void ); + + virtual bool IsVisible( void ) + { + if ( IsInFreezeCam() == true ) + return false; + + return BaseClass::IsVisible(); + } + +private: + int m_iCPIndex; + float m_flStartCapAnimStart; + float m_flPulseTime; + bool m_bAccelerateOverCapture; + IImage *m_pPulseImage; +}; + +//----------------------------------------------------------------------------- +// Purpose: A single icon that shows the state of one control point +//----------------------------------------------------------------------------- +class CControlPointIcon : public vgui::EditablePanel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CControlPointIcon, vgui::EditablePanel ); +public: + CControlPointIcon( Panel *parent, const char *pName, int iIndex ); + ~CControlPointIcon( void ); + + virtual void ApplySchemeSettings( IScheme *scheme ); + virtual void PerformLayout( void ); + + void UpdateImage( void ); + void UpdateCapImage( void ); + bool IsPointLocked( void ); + int GetCapIndex( void ) { return m_iCPIndex; } + void SetSwipeUp( bool bUp ) { m_bSwipeUp = bUp; } + bool ShouldSwipeUp( void ) { return m_bSwipeUp; } + int GetCapProgressDir( void ) { return m_iCapProgressDir; } + void SetCapProgressDir( int iDir ) { m_iCapProgressDir = iDir; } + void FakePulse( float flTime ); + bool IsVisible( void ); + virtual void Paint( void ); + bool IsPointUnlockCountdownRunning( void ); + + virtual void FireGameEvent( IGameEvent *event ); + + void SetUnlockTime( float flTime ) + { + if ( m_pCountdown ) + { + m_pCountdown->SetUnlockTime( flTime ); + } + } + + void SetTimerTime( float flTime ); // used to display CCPTimerLogic countdowns + +private: + virtual void OnTick(); + +private: + int m_iCPIndex; + vgui::ImagePanel *m_pOverlayImage; + CControlPointIconPulseable *m_pBaseImage; + CControlPointIconCapArrow *m_pCapImage; + DHANDLE< CControlPointIconSwoop > m_pCapHighlightImage; + DHANDLE< CControlPointIconCapturePulse > m_pCapPulseImage; + vgui::ImagePanel *m_pCapPlayerImage; + vgui::Label *m_pCapNumPlayers; + bool m_bSwipeUp; + float m_flStartCapAnimStart; + int m_iCapProgressDir; + int m_iPrevCappers; + bool m_bCachedLockedState; + + bool m_bCachedCountdownState; + CControlPointCountdown *m_pCountdown; + + DHANDLE< CExLabel > m_pCPTimerLabel; // used to display CCPTimerLogic countdowns + DHANDLE< vgui::ImagePanel > m_pCPTimerBG; // used to display CCPTimerLogic countdowns + float m_flCPTimerTime; + bool m_bRedText; + Color m_cRegularColor; + Color m_cHighlightColor; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudControlPointIcons : public CHudElement, public vgui::Panel +{ +public: + DECLARE_CLASS_SIMPLE( CHudControlPointIcons, vgui::Panel ); + + CHudControlPointIcons( const char *pName ); + virtual ~CHudControlPointIcons( void ); + + virtual void ApplySchemeSettings( IScheme *scheme ); + virtual void PerformLayout( void ); + virtual void Paint(); + virtual void Init(); + virtual void Reset(); + virtual bool IsVisible( void ); + virtual void LevelShutdown( void ); + + virtual bool ShouldDraw( void ) + { + return IsVisible(); + } + + virtual void FireGameEvent( IGameEvent *event ); + + void UpdateProgressBarFor( int iIndex ); + void InitIcons(); + void ShutdownIcons(); + void DrawBackgroundBox( int xpos, int ypos, int nBoxWidth, int nBoxHeight, bool bCutCorner ); + bool PaintTeamBaseIcon( int index, float flXPos, float flYPos, float flIconSize ); + + bool IsFakingCapture( int index = -1, bool *bMult = NULL, float *flFakeTime = NULL ) + { + if ( m_bFakingCapture && m_flFakeCaptureTime < gpGlobals->curtime ) + { + m_iCurrentCP = -1; + m_bFakingCapture = false; + m_bFakingCaptureMult = false; + } + + if ( bMult) *bMult = m_bFakingCaptureMult; + if ( flFakeTime ) *flFakeTime = m_flFakeCaptureTime; + return (m_bFakingCapture && (index == -1 || index == m_iCurrentCP)); + } + +private: + int m_iCPTextures[CP_TEXTURE_COUNT]; + int m_iCPCappingTextures[CP_TEXTURE_COUNT]; + int m_iTeamBaseTextures[MAX_TEAMS]; + + int m_iBackgroundTexture; + Color m_clrBackground; + Color m_clrBorder; + + int m_iCurrentCP; // the index of the control point the local is currently in + int m_iLastCP; // the index of the control point the local player was last in + + // Capture faking for Intros + float m_flPulseTime; + bool m_bFakingCapture; + bool m_bFakingCaptureMult; + float m_flFakeCaptureTime; + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "ChatFont", "Default" ); + + CPanelAnimationVarAliasType( int, m_nCornerCutSize, "CornerCutSize", "5", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_nBackgroundOverlap, "BackgroundOverlap", "5", "proportional_int" ); + + CPanelAnimationVarAliasType( int, m_iIconStartX, "icon_start_x", "10", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconStartY, "icon_start_y", "10", "proportional_int" ); + CPanelAnimationVarAliasType( float, m_flIconExpand, "icon_expand", "0", "proportional_float" ); + CPanelAnimationVarAliasType( int, m_iIconSize, "iconsize", "24", "proportional_int" ); + + + CPanelAnimationVarAliasType( int, m_iIconGapWidth, "separator_width", "7", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconGapHeight, "separator_height", "9", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_nHeightOffset, "height_offset", "0", "proportional_int" ); + + CUtlVector m_Icons; +}; + +#endif // HUD_CONTROLPOINTICONS_H diff --git a/game/client/hud_crosshair.h b/game/client/hud_crosshair.h new file mode 100644 index 0000000..7952db2 --- /dev/null +++ b/game/client/hud_crosshair.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_CROSSHAIR_H +#define HUD_CROSSHAIR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include + +namespace vgui +{ + class IScheme; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudCrosshair : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudCrosshair, vgui::Panel ); +public: + CHudCrosshair( const char *pElementName ); + virtual ~CHudCrosshair(); + + virtual void SetCrosshairAngle( const QAngle& angle ); + virtual void SetCrosshair( CHudTexture *texture, const Color& clr ); + virtual void ResetCrosshair(); + virtual void DrawCrosshair( void ) {} + virtual bool HasCrosshair( void ) { return ( m_pCrosshair != NULL ); } + virtual bool ShouldDraw(); + + // any UI element that wants to be at the aim point can use this to figure out where to draw + static void GetDrawPosition ( float *pX, float *pY, bool *pbBehindCamera, QAngle angleCrosshairOffset = vec3_angle ); +protected: + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + virtual void Paint(); + + // Crosshair sprite and colors + CHudTexture *m_pCrosshair; + CHudTexture *m_pDefaultCrosshair; + Color m_clrCrosshair; + QAngle m_vecCrossHairOffsetAngle; + + CPanelAnimationVar( bool, m_bHideCrosshair, "never_draw", "false" ); +}; + + +// Enable/disable crosshair rendering. +extern ConVar crosshair; + + +#endif // HUD_CROSSHAIR_H diff --git a/game/client/hud_element_helper.h b/game/client/hud_element_helper.h new file mode 100644 index 0000000..848a23e --- /dev/null +++ b/game/client/hud_element_helper.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Helper for the CHudElement class to add themselves to the list of hud elements +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_ELEMENT_HELPER_H +#define HUD_ELEMENT_HELPER_H +#ifdef _WIN32 +#pragma once +#endif + +class CHudElement; + +//----------------------------------------------------------------------------- +// Purpose: Used by DECLARE_HUDELEMENT macro to create a linked list of +// instancing functions +//----------------------------------------------------------------------------- +class CHudElementHelper +{ +public: + // Static list of helpers + static CHudElementHelper *m_sHelpers; + // Create all the hud elements + static void CreateAllElements( void ); + +public: + // Construction + CHudElementHelper( CHudElement *( *pfnCreate )( void ), int depth ); + + // Accessors + CHudElementHelper *GetNext( void ); + +private: + // Next factory in list + CHudElementHelper *m_pNext; + // Creation function to use for this technology + CHudElement *( *m_pfnCreate )( void ); + + //Depth used to determine hud panel ordering + int m_iDepth; +}; + +// This is the macro which implements creation of each hud element +// It creates a function which instances an object of the specified type +// It them hooks that function up to the helper list so that the CHud objects can create +// the elements by name, with no header file dependency, etc. +#define DECLARE_HUDELEMENT( className ) \ + static CHudElement *Create_##className( void ) \ + { \ + return new className( #className ); \ + }; \ + static CHudElementHelper g_##className##_Helper( Create_##className, 50 ); + +#define DECLARE_HUDELEMENT_DEPTH( className, depth ) \ + static CHudElement *Create_##className( void ) \ + { \ + return new className( #className ); \ + }; \ + static CHudElementHelper g_##className##_Helper( Create_##className, depth ); + +#define DECLARE_NAMED_HUDELEMENT( className, panelName ) \ + static CHudElement *Create_##panelName( void ) \ + { \ + return new className( #panelName ); \ + }; \ + static CHudElementHelper g_##panelName##_Helper( Create_##panelName, 50 ); + +// This macro can be used to get a pointer to a specific hud element +#define GET_HUDELEMENT( className ) \ + ( className *)gHUD.FindElement( #className ) + +#define GET_NAMED_HUDELEMENT( className, panelName ) \ + ( className *)gHUD.FindElement( #panelName ) + + +// Things that inherit from vgui::Panel, too, will have ambiguous new operators +// so this should disambiguate them +#define DECLARE_MULTIPLY_INHERITED() \ + void *operator new( size_t stAllocateBlock ) \ + { \ + return CHudElement::operator new ( stAllocateBlock ); \ + } \ + void* operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ) \ + { \ + return CHudElement::operator new ( stAllocateBlock, nBlockUse, pFileName, nLine ); \ + } \ + void operator delete( void *pMem ) \ + { \ + CHudElement::operator delete ( pMem ); \ + } \ + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) \ + { \ + CHudElement::operator delete ( pMem, nBlockUse, pFileName, nLine ); \ + } + +// Alias for base hud element +#define IMPLEMENT_OPERATORS_NEW_AND_DELETE DECLARE_MULTIPLY_INHERITED + +#endif // HUD_ELEMENT_HELPER_H diff --git a/game/client/hud_lcd.h b/game/client/hud_lcd.h new file mode 100644 index 0000000..f7fd4c9 --- /dev/null +++ b/game/client/hud_lcd.h @@ -0,0 +1,273 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: CLCD Manages the Logitech G-Series Gaming Keyboard LCD +// +// $NoKeywords: $ +//=============================================================================// +#ifndef HUD_LCD_H +#define HUD_LCD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" +#include "tier1/utldict.h" + +#include "ihudlcd.h" + +class KeyValues; +class IG15; +class C_BasePlayer; + +enum +{ + LCDITEM_UNKNOWN = 0, + LCDITEM_PAGE, + LCDITEM_TEXT, + LCDITEM_ICON, + LCDITEM_AGGREGATE, // Made up of subitems +}; + +// Aggregate item types +enum +{ + AGGTYPE_UNKNOWN = 0, + AGGTYPE_PERPLAYER, + AGGTYPE_PERTEAM, +}; + +class CLCDItem +{ +public: + CLCDItem() : + m_bActive( true ), + m_nSubPage( 0 ), + m_Type( LCDITEM_UNKNOWN ), + m_Handle( 0 ), + x( 0 ), + y( 0 ), + w( 0 ), + h( 0 ) + { + } + + virtual ~CLCDItem() {} + + virtual void Create( IG15 *lcd ) = 0; + virtual void Wipe( IG15 *lcd ); + + bool m_bActive; + int m_Type; + void *m_Handle; + int x, y, w, h; + + int m_nSubPage; + + CUtlVector< CLCDItem * > m_Children; +}; + +class CLCDItemText : public CLCDItem +{ + typedef CLCDItem BaseClass; +public: + CLCDItemText() : + m_bHasWildcard( false ), + m_iSize( 0 ), + m_iAlign( 0 ) + { + m_Type = LCDITEM_TEXT; + } + + virtual void Create( IG15 *lcd ); + + CUtlString m_OriginalText; + bool m_bHasWildcard; + int m_iSize; + int m_iAlign; +}; + +class CLCDItemIcon : public CLCDItem +{ + typedef CLCDItem BaseClass; + +public: + CLCDItemIcon() : + m_icon( NULL ) + { + m_Type = LCDITEM_ICON; + } + + virtual void Create( IG15 *lcd ); + + CUtlString m_IconName; + void *m_icon; +}; + +class CLCDItemAggregate : public CLCDItem +{ + typedef CLCDItem BaseClass; + +public: + CLCDItemAggregate() : + m_AggType( AGGTYPE_UNKNOWN ), + m_dwNextUpdateTime( 0 ), + m_yincrement( 0 ) + { + m_Type = LCDITEM_AGGREGATE; + } + + virtual void Create( IG15 *lcd ); + virtual void Wipe( IG15 *lcd ); + + void WipeChildrenOnly( IG15 *lcd ); + + unsigned int m_dwNextUpdateTime; + int m_AggType; + + int m_yincrement; + + // Representative row + CUtlVector< CLCDItem * > m_Definition; +}; + +class CLCDPage : public CLCDItem +{ +public: + CLCDPage() : + m_bSubItem( false ), + m_bTitlePage( false ), + m_bRequiresPlayer( false ), + m_nSubPageCount( 1 ) + { + m_Type = LCDITEM_PAGE; + } + + ~CLCDPage() + { + } + + virtual void Create( IG15 *lcd ) + { + } + + CLCDItem *Alloc( int type ) + { + CLCDItem *item = NULL; + + switch ( type ) + { + default: + break; + case LCDITEM_PAGE: + // This shouldn't occur + break; + case LCDITEM_TEXT: + item = new CLCDItemText(); + break; + case LCDITEM_ICON: + item = new CLCDItemIcon(); + break; + case LCDITEM_AGGREGATE: + item = new CLCDItemAggregate(); + break; + } + + if ( item ) + { + return item; + } + + Assert( 0 ); + return NULL; + } + + void InitFromKeyValues( KeyValues *kv ); + + bool m_bSubItem; + bool m_bTitlePage; + bool m_bRequiresPlayer; + int m_nSubPageCount; +}; + +//----------------------------------------------------------------------------- +// Purpose: Manages the Logitech G-Series Gaming Keyboard LCD +//----------------------------------------------------------------------------- +class CLCD : public IHudLCD +{ +public: + CLCD(); + ~CLCD(); + + // Implement IHudLCD + virtual void SetGlobalStat( char const *name, char const *value ); + virtual void AddChatLine( char const *txt ); + + // Exposed as a ConCommand + void Reload(); + void DumpPlayer(); + +public: + + // Init's called when the HUD's created at DLL load + void Init( void ); + void Shutdown(); + void Update( void ); + bool IsConnected() const; + +private: + + CLCDItemIcon *ParseItemIcon( CLCDPage *page, bool bCreateHandles, KeyValues *sub ); + CLCDItemText *ParseItemText( CLCDPage *page, bool bCreateHandles, KeyValues *sub ); + void ParseItems_R( CLCDPage *page, bool bCreateHandles, KeyValues *kv, CUtlVector< CLCDItem * >& list ); + + void ParsePage( KeyValues *kv ); + void ParseIconMappings( KeyValues *kv ); + void ParseReplacements( KeyValues *kv ); + void DisplayCurrentPage( unsigned int dwCurTime ); + + void ShowItems_R( CLCDPage *page, unsigned int dwCurTime, CUtlVector< CLCDItem * >& list, bool show ); + + int FindTitlePage(); + void BuildUpdatedText( char const *in, CUtlString& out ); + void LookupToken( char const *token, CUtlString& value ); + bool ExtractArrayIndex( char *str, size_t bufsize, int *index ); + + bool Replace( CUtlString& str, char const *search, char const *replace ); + void DoGlobalReplacements( CUtlString& str ); + void ReduceParentheses( CUtlString& str ); + + bool IsPageValid( int currentPage, C_BasePlayer *player ); + void UpdateChat(); + + IG15 *m_lcd ; + + CUtlString m_Title; + int m_Size[ 2 ]; + CUtlVector< CLCDPage * > m_Pages; + int m_nCurrentPage; + int m_nSubPage; + int m_nMaxChatHistory; + + CUtlDict< int, int > m_TextSizes; + CUtlDict< int, int > m_TextAlignments; + + struct IconInfo_t + { + void *m_handle; + }; + + CUtlDict< IconInfo_t, int > m_Icons; + bool m_bHadPlayer; + + CUtlDict< CUtlString, int > m_GlobalStats; + CUtlVector< CUtlString > m_ChatHistory; + + unsigned int m_dwNextUpdateTime; + CSysModule *m_pG15Module; + CreateInterfaceFn m_G15Factory; +}; + +extern CLCD gLCD; + +#endif // HUD_LCD_H diff --git a/game/client/hud_macros.h b/game/client/hud_macros.h new file mode 100644 index 0000000..667ef64 --- /dev/null +++ b/game/client/hud_macros.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( HUD_MACROS_H ) +#define HUD_MACROS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "usermessages.h" + +// Macros to hook function calls into the HUD object +#define HOOK_MESSAGE(x) usermessages->HookMessage(#x, __MsgFunc_##x ); +#define HOOK_HUD_MESSAGE(y, x) usermessages->HookMessage(#x, __MsgFunc_##y##_##x ); +// Message declaration for non-CHudElement classes +#define DECLARE_MESSAGE(y, x) void __MsgFunc_##y##_##x(bf_read &msg) \ + { \ + y.MsgFunc_##x( msg ); \ + } +// Message declaration for CHudElement classes that use the hud element factory for creation +#define DECLARE_HUD_MESSAGE(y, x) void __MsgFunc_##y##_##x(bf_read &msg) \ + { \ + CHudElement *pElement = gHUD.FindElement( #y ); \ + if ( pElement ) \ + { \ + ((y *)pElement)->MsgFunc_##x( msg ); \ + } \ + } + +#define DECLARE_HUD_MESSAGE_BASECLASS(name, basename, msgname) void __MsgFunc_##msgname(const char *pszName, int iSize, void *pbuf) \ + { \ + CHudElement *pElement = gHUD.FindElement( #name ); \ + if ( pElement ) \ + { \ + ((basename *)pElement)->MsgFunc_##msgname(pszName, iSize, pbuf ); \ + } \ + } + +// Commands +#define HOOK_COMMAND(x, y) static ConCommand x( #x, __CmdFunc_##y, "", FCVAR_SERVER_CAN_EXECUTE ); +// Command declaration for non CHudElement classes +#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + y.UserCmd_##x( ); \ + } +// Command declaration for CHudElement classes that use the hud element factory for creation +#define DECLARE_HUD_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + CHudElement *pElement = gHUD.FindElement( #y ); \ + { \ + ((y *)pElement)->UserCmd_##x( ); \ + } \ + } + +#define DECLARE_HUD_COMMAND_NAME(y, x, name) void __CmdFunc_##x( void ) \ + { \ + CHudElement *pElement = gHUD.FindElement( name ); \ + { \ + ((y *)pElement)->UserCmd_##x( ); \ + } \ + } + + +#endif // HUD_MACROS_H diff --git a/game/client/hud_numericdisplay.h b/game/client/hud_numericdisplay.h new file mode 100644 index 0000000..b004f91 --- /dev/null +++ b/game/client/hud_numericdisplay.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_NUMERICDISPLAY_H +#define HUD_NUMERICDISPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +//----------------------------------------------------------------------------- +// Purpose: Base class for all the hud elements that are just a numeric display +// with some options for text and icons +//----------------------------------------------------------------------------- +class CHudNumericDisplay : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudNumericDisplay, vgui::Panel ); + +public: + CHudNumericDisplay(vgui::Panel *parent, const char *name); + + void SetDisplayValue(int value); + void SetSecondaryValue(int value); + void SetShouldDisplayValue(bool state); + void SetShouldDisplaySecondaryValue(bool state); + void SetLabelText(const wchar_t *text); + void SetIndent(bool state); + void SetIsTime(bool state); + + bool ShouldDisplayValue( void ) { return m_bDisplayValue; } + bool ShouldDisplaySecondaryValue( void ) { return m_bDisplaySecondaryValue; } + + virtual void Reset(); + +protected: + // vgui overrides + virtual void Paint(); + virtual void PaintLabel(); + + virtual void PaintNumbers(vgui::HFont font, int xpos, int ypos, int value); + +protected: + + int m_iValue; + int m_iSecondaryValue; + wchar_t m_LabelText[32]; + bool m_bDisplayValue, m_bDisplaySecondaryValue; + bool m_bIndent; + bool m_bIsTime; + + CPanelAnimationVar( float, m_flBlur, "Blur", "0" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); + CPanelAnimationVar( Color, m_Ammo2Color, "Ammo2Color", "FgColor" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudNumbers" ); + CPanelAnimationVar( vgui::HFont, m_hNumberGlowFont, "NumberGlowFont", "HudNumbersGlow" ); + CPanelAnimationVar( vgui::HFont, m_hSmallNumberFont, "SmallNumberFont", "HudNumbersSmall" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + + CPanelAnimationVarAliasType( float, text_xpos, "text_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text_ypos, "text_ypos", "20", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_xpos, "digit_xpos", "50", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit_ypos, "digit_ypos", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_xpos, "digit2_xpos", "98", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_ypos, "digit2_ypos", "16", "proportional_float" ); +}; + + +#endif // HUD_NUMERICDISPLAY_H diff --git a/game/client/hud_pdump.h b/game/client/hud_pdump.h new file mode 100644 index 0000000..83af436 --- /dev/null +++ b/game/client/hud_pdump.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_PDUMP_H +#define HUD_PDUMP_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "hudelement.h" + +namespace vgui +{ + class IScheme; +}; + +class CPDumpPanel : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CPDumpPanel, vgui::Panel ); + +public: + enum + { + DUMP_CLASSNAME_SIZE = 128, + DUMP_STRING_SIZE = 128, + }; + + CPDumpPanel( const char *pElementName ); + ~CPDumpPanel(); + + DECLARE_MULTIPLY_INHERITED(); + + virtual void ApplySettings( KeyValues *inResourceData ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void Paint( void ); + + virtual bool ShouldDraw(); + + // Remove dump info + void Clear(); + void DumpEntity( C_BaseEntity *ent, int commands_acknowledged ); + + void DumpComparision( const char *classname, const char *fieldname, const char *fieldtype, + bool networked, bool noterrorchecked, bool differs, bool withintolerance, const char *value ); +private: + + void PredictionDumpColor( bool networked, bool errorchecked, bool differs, bool withintolerance, + int& r, int& g, int& b, int& a ); + //----------------------------------------------------------------------------- + // Purpose: Stores some info about the various fields of an entity for display + //----------------------------------------------------------------------------- + struct DumpInfo + { + char classname[ DUMP_CLASSNAME_SIZE ]; + bool networked; + char fieldstring[ DUMP_STRING_SIZE ]; + bool differs; + bool withintolerance; + bool noterrorchecked; + }; + + CUtlVector< DumpInfo > m_DumpEntityInfo; + + EHANDLE m_hDumpEntity; + + CPanelAnimationVar( vgui::HFont, m_FontSmall, "ItemFont", "DefaultVerySmall" ); + CPanelAnimationVar( vgui::HFont, m_FontMedium, "LabelFont", "DefaultSmall" ); + CPanelAnimationVar( vgui::HFont, m_FontBig, "TitleFont", "Trebuchet24" ); +}; + +CPDumpPanel *GetPDumpPanel(); + +#endif // HUD_PDUMP_H diff --git a/game/client/hud_vehicle.h b/game/client/hud_vehicle.h new file mode 100644 index 0000000..8dddf88 --- /dev/null +++ b/game/client/hud_vehicle.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_CROSSHAIR_H +#define HUD_CROSSHAIR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include + +namespace vgui +{ + class IScheme; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudVehicle : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudVehicle, vgui::Panel ); +public: + CHudVehicle( const char *pElementName ); + + virtual bool ShouldDraw(); + + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + virtual void Paint( void ); + +private: + + IClientVehicle *GetLocalPlayerVehicle(); +}; + +#endif // HUD_CROSSHAIR_H diff --git a/game/client/hud_vote.h b/game/client/hud_vote.h new file mode 100644 index 0000000..3895636 --- /dev/null +++ b/game/client/hud_vote.h @@ -0,0 +1,189 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_VOTE_H +#define HUD_VOTE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include +#include +#include +#include +#include + +extern INetworkStringTable *g_pStringTableServerMapCycle; + +#ifdef TF_CLIENT_DLL +extern INetworkStringTable *g_pStringTableServerPopFiles; +extern INetworkStringTable *g_pStringTableServerMapCycleMvM; +#endif + +static const int k_MAX_VOTE_NAME_LENGTH = 256; + +namespace vgui +{ + class SectionedListPanel; + class ComboBox; + class ImageList; +}; + +struct VoteIssue_t +{ + char szName[k_MAX_VOTE_NAME_LENGTH]; + char szNameString[k_MAX_VOTE_NAME_LENGTH]; + bool bIsActive; +}; + +class VoteBarPanel : public vgui::Panel, public CGameEventListener +{ + DECLARE_CLASS_SIMPLE( VoteBarPanel, vgui::Panel ); + + VoteBarPanel( vgui::Panel *parent, const char *panelName ); + + virtual void Paint( void ); + virtual void FireGameEvent( IGameEvent *event ); + +private: + int m_nVoteOptionCount[MAX_VOTE_OPTIONS]; // Vote options counter + int m_nPotentialVotes; // If set, draw a line at this point to show the required bar length + + CPanelAnimationVarAliasType( int, m_iBoxSize, "box_size", "16", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iSpacer, "spacer", "4", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBoxInset, "box_inset", "1", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_nYesTextureId, "yes_texture", "vgui/hud/vote_yes", "textureid" ); + CPanelAnimationVarAliasType( int, m_nNoTextureId, "no_texture", "vgui/hud/vote_no", "textureid" ); +}; + +//----------------------------------------------------------------------------- +// Purpose: A selection UI for votes that require additional parameters - such as players, maps +//----------------------------------------------------------------------------- + +class CVoteSetupDialog : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CVoteSetupDialog, vgui::Frame ); + +public: + CVoteSetupDialog( vgui::Panel *parent ); + ~CVoteSetupDialog(); + + virtual void Activate(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void PostApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void ApplySettings(KeyValues *inResourceData); + + void InitializeIssueList( void ); + void UpdateCurrentMap( void ); + void AddVoteIssues( CUtlVector< VoteIssue_t > &m_VoteSetupIssues ); + void AddVoteIssueParams_MapCycle( CUtlStringList &m_VoteSetupMapCycle ); + +#ifdef TF_CLIENT_DLL + void AddVoteIssueParams_PopFiles( CUtlStringList &m_VoteSetupPopFiles ); +#endif + +private: + //MESSAGE_FUNC( OnItemSelected, "ItemSelected" ); + MESSAGE_FUNC_PTR( OnItemSelected, "ItemSelected", panel ); + + virtual void OnCommand( const char *command ); + virtual void OnClose( void ); + + void RefreshIssueParameters( void ); + void ResetData( void ); + + vgui::ComboBox *m_pComboBox; + + vgui::SectionedListPanel *m_pVoteSetupList; + vgui::SectionedListPanel *m_pVoteParameterList; + vgui::Button *m_pCallVoteButton; + vgui::ImageList *m_pImageList; + + CUtlVector< VoteIssue_t > m_VoteIssues; + CUtlVector m_VoteIssuesMapCycle; + +#ifdef TF_CLIENT_DLL + CUtlVector m_VoteIssuesPopFiles; +#endif + + CPanelAnimationVarAliasType( int, m_iIssueWidth, "issue_width", "100", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iParameterWidth, "parameter_width", "150", "proportional_int" ); + + bool m_bVoteButtonEnabled; + char m_szCurrentMap[MAX_MAP_NAME]; + + vgui::HFont m_hHeaderFont; + Color m_HeaderFGColor; + vgui::HFont m_hIssueFont; + Color m_IssueFGColor; + Color m_IssueFGColorDisabled; +}; + + +class CHudVote : public vgui::EditablePanel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CHudVote, vgui::EditablePanel ); + + CHudVote( const char *pElementName ); + + virtual void LevelInit( void ); + virtual void Init( void ); + virtual bool ShouldDraw( void ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void FireGameEvent( IGameEvent *event ); + virtual void OnThink(); + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + // NOTE: Any MsgFunc_*() methods added here need to check IsPlayingDemo(). + void MsgFunc_CallVoteFailed( bf_read &msg ); + void MsgFunc_VoteStart( bf_read &msg ); + void MsgFunc_VotePass( bf_read &msg ); + void MsgFunc_VoteFailed( bf_read &msg ); + void MsgFunc_VoteSetup( bf_read &msg ); + + void PropagateOptionParameters( void ); + void ShowVoteUI( bool bShow ) { m_bShowVoteActivePanel = bShow; } + bool IsVoteUIActive( void ); + bool IsVoteSystemActive( void ) { return m_bVoteSystemActive; } + +private: + bool IsPlayingDemo() const; + + EditablePanel *m_pVoteActive; + VoteBarPanel *m_voteBar; + EditablePanel *m_pVoteFailed; + EditablePanel *m_pVotePassed; + EditablePanel *m_pCallVoteFailed; + CVoteSetupDialog *m_pVoteSetupDialog; + + CUtlVector< VoteIssue_t > m_VoteSetupIssues; + CUtlStringList m_VoteSetupMapCycle; + +#ifdef TF_CLIENT_DLL + CUtlStringList m_VoteSetupPopFiles; +#endif + + CUtlStringList m_VoteSetupChoices; + + bool m_bVotingActive; + bool m_bVoteSystemActive; + float m_flVoteResultCycleTime; // what time will we cycle to the result + float m_flHideTime; // what time will we hide + bool m_bVotePassed; // what mode are we going to cycle to + int m_nVoteOptionCount[MAX_VOTE_OPTIONS]; // Vote options counter + int m_nPotentialVotes; // If set, draw a line at this point to show the required bar length + bool m_bIsYesNoVote; + int m_nVoteChoicesCount; + bool m_bPlayerVoted; + float m_flPostVotedHideTime; + bool m_bShowVoteActivePanel; + int m_iVoteCallerIdx; + int m_nVoteTeamIndex; // If defined, only players on this team will see/vote on the issue +}; + +#endif // HUD_VOTE_H diff --git a/game/client/hudelement.h b/game/client/hudelement.h new file mode 100644 index 0000000..b903de5 --- /dev/null +++ b/game/client/hudelement.h @@ -0,0 +1,152 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( HUDELEMENT_H ) +#define HUDELEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud.h" +#include "hud_element_helper.h" +#include "networkvar.h" +#include "GameEventListener.h" +#include "tier0/memdbgon.h" +#undef new + +//----------------------------------------------------------------------------- +// Purpose: Base class for all hud elements +//----------------------------------------------------------------------------- +class CHudElement : public CGameEventListener +{ +public: + DECLARE_CLASS_NOBASE( CHudElement ); + + // constructor - registers object in global list + CHudElement( const char *pElementName ); + // destructor - removes object from the global list + virtual ~CHudElement(); + + // called when the Hud is initialised (whenever the DLL is loaded) + virtual void Init( void ) { return; } + + // called whenever the video mode changes, and whenever Init() would be called, so the hud can vid init itself + virtual void VidInit( void ) { return; } + + // LevelInit's called whenever a new level is starting + virtual void LevelInit( void ) { return; }; + // LevelShutdown's called whenever a level is finishing + virtual void LevelShutdown( void ) { return; }; + + // called whenever the hud receives "reset" message, which is (usually) every time the client respawns after getting killed + virtual void Reset( void ) { return; } + + // Called once per frame for visible elements before general key processing + virtual void ProcessInput( void ) { return; } + // + virtual const char *GetName( void ) const { return m_pElementName; }; + + // Return true if this hud element should be visible in the current hud state + virtual bool ShouldDraw( void ); + + virtual bool IsActive( void ) { return m_bActive; }; + virtual void SetActive( bool bActive ); + + // Hidden bits. + // HIDEHUD_ flags that note when this element should be hidden in the HUD + virtual void SetHiddenBits( int iBits ); + + bool IsParentedToClientDLLRootPanel() const; + void SetParentedToClientDLLRootPanel( bool parented ); + + // memory handling, uses calloc so members are zero'd out on instantiation + void *operator new( size_t stAllocateBlock ) + { + Assert( stAllocateBlock != 0 ); + void *pMem = malloc( stAllocateBlock ); + memset( pMem, 0, stAllocateBlock ); + return pMem; + } + + void* operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ) + { + Assert( stAllocateBlock != 0 ); + void *pMem = MemAlloc_Alloc( stAllocateBlock, pFileName, nLine ); + memset( pMem, 0, stAllocateBlock ); + return pMem; + } + + void operator delete( void *pMem ) + { +#if defined( _DEBUG ) + int size = _msize( pMem ); + memset( pMem, 0xcd, size ); +#endif + free( pMem ); + } + + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) + { + operator delete( pMem ); + } + + void SetNeedsRemove( bool needsremove ); + + void RegisterForRenderGroup( const char *pszName ); + void UnregisterForRenderGroup( const char *pszGroupName ); + void HideLowerPriorityHudElementsInGroup( const char *pszGroupName ); + void UnhideLowerPriorityHudElementsInGroup( const char *pszGroupName ); + + // For now, CHUdElements declare a single priority value. They will only be hidden + // by panels with a lower priority and will only lock out panels with a lower priority + virtual int GetRenderGroupPriority(); + +public: // IGameEventListener Interface + + virtual void FireGameEvent( IGameEvent * event ) {} + +public: + + // True if this element is visible, and should think + bool m_bActive; + +protected: + int m_iHiddenBits; + +private: + const char *m_pElementName; + bool m_bNeedsRemove; + bool m_bIsParentedToClientDLLRootPanel; + + CUtlVector< int > m_HudRenderGroups; +}; + +#include "utlpriorityqueue.h" + +inline bool RenderGroupLessFunc( CHudElement * const &lhs, CHudElement * const &rhs ) +{ + return ( lhs->GetRenderGroupPriority() < rhs->GetRenderGroupPriority() ); +} + +// hud elements declare themselves to be part of a hud render group, by name +// we register with each hudelement a list of indeces of groups they are in +// then they can query by index the state of their render group +class CHudRenderGroup +{ +public: + CHudRenderGroup() + { + m_pLockingElements.SetLessFunc( RenderGroupLessFunc ); + bHidden = false; + } + + bool bHidden; + CUtlPriorityQueue< CHudElement * > m_pLockingElements; +}; + +#include "tier0/memdbgoff.h" + +#endif // HUDELEMENT_H diff --git a/game/client/hudtexturehandle.h b/game/client/hudtexturehandle.h new file mode 100644 index 0000000..2e1ef79 --- /dev/null +++ b/game/client/hudtexturehandle.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUDTEXTUREHANDLE_H +#define HUDTEXTUREHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + +class CHudTexture; + +class CHudTextureHandle +{ +public: + CHudTextureHandle() + { + m_pValue = NULL; + } + + // Assign a value to the handle. + const CHudTextureHandle& operator=( const CHudTexture *t ) + { + m_pValue = (CHudTexture *)t; + return *this; + } + + void Set( CHudTexture *t ) + { + m_pValue = t; + } + + CHudTexture *Get() + { + return m_pValue; + } + + operator CHudTexture*() + { + return m_pValue; + } + + operator CHudTexture*() const + { + return m_pValue; + } + + CHudTexture *operator->() const + { + return m_pValue; + } + +private: + CHudTexture *m_pValue; +}; + +#endif // HUDTEXTUREHANDLE_H diff --git a/game/client/iclassmap.h b/game/client/iclassmap.h new file mode 100644 index 0000000..78ac84c --- /dev/null +++ b/game/client/iclassmap.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLASSMAP_H +#define ICLASSMAP_H +#ifdef _WIN32 +#pragma once +#endif + +class C_BaseEntity; +typedef C_BaseEntity* (*DISPATCHFUNCTION)( void ); + +abstract_class IClassMap +{ +public: + virtual ~IClassMap() {} + + virtual void Add( const char *mapname, const char *classname, int size, DISPATCHFUNCTION factory = 0 ) = 0; + virtual char const *Lookup( const char *classname ) = 0; + virtual C_BaseEntity *CreateEntity( const char *mapname ) = 0; + virtual int GetClassSize( const char *classname ) = 0; +}; + +extern IClassMap& GetClassMap(); + + +#endif // ICLASSMAP_H diff --git a/game/client/icliententityinternal.h b/game/client/icliententityinternal.h new file mode 100644 index 0000000..be4dfc9 --- /dev/null +++ b/game/client/icliententityinternal.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef ICLIENTENTITYINTERNAL_H +#define ICLIENTENTITYINTERNAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "icliententity.h" +#include "clientleafsystem.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +class ClientClass; + + +//----------------------------------------------------------------------------- +// represents a handle used only by the client DLL +//----------------------------------------------------------------------------- + +typedef CBaseHandle ClientEntityHandle_t; +typedef unsigned short SpatialPartitionHandle_t; + + + +#endif // ICLIENTENTITYINTERNAL_H \ No newline at end of file diff --git a/game/client/iclientmode.h b/game/client/iclientmode.h new file mode 100644 index 0000000..2b74f62 --- /dev/null +++ b/game/client/iclientmode.h @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLIENTMODE_H +#define ICLIENTMODE_H + +#include +#include "client_virtualreality.h" + +class CViewSetup; +class C_BaseEntity; +class C_BasePlayer; +class CUserCmd; + +namespace vgui +{ + class Panel; + class AnimationController; +} + +// Message mode types +enum +{ + MM_NONE = 0, + MM_SAY, + MM_SAY_TEAM, +}; + +abstract_class IClientMode +{ +// Misc. +public: + + virtual ~IClientMode() {} + + // Called before the HUD is initialized. + virtual void InitViewport()=0; + + // One time init when .dll is first loaded. + virtual void Init()=0; + + // Called when vgui is shutting down. + virtual void VGui_Shutdown() = 0; + + // One time call when dll is shutting down + virtual void Shutdown()=0; + + // Called when switching from one IClientMode to another. + // This can re-layout the view and such. + // Note that Enable and Disable are called when the DLL initializes and shuts down. + virtual void Enable()=0; + + // Called when it's about to go into another client mode. + virtual void Disable()=0; + + // Called when initializing or when the view changes. + // This should move the viewport into the correct position. + virtual void Layout()=0; + + // Gets at the viewport, if there is one... + virtual vgui::Panel *GetViewport() = 0; + + // Gets at the viewports vgui panel animation controller, if there is one... + virtual vgui::AnimationController *GetViewportAnimationController() = 0; + + // called every time shared client dll/engine data gets changed, + // and gives the cdll a chance to modify the data. + virtual void ProcessInput( bool bActive ) = 0; + + // The mode can choose to draw/not draw entities. + virtual bool ShouldDrawDetailObjects( ) = 0; + virtual bool ShouldDrawEntity(C_BaseEntity *pEnt) = 0; + virtual bool ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ) = 0; + virtual bool ShouldDrawParticles( ) = 0; + + // The mode can choose to not draw fog + virtual bool ShouldDrawFog( void ) = 0; + + virtual void OverrideView( CViewSetup *pSetup ) = 0; + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) = 0; + virtual void StartMessageMode( int iMessageModeType ) = 0; + virtual vgui::Panel *GetMessagePanel() = 0; + virtual void OverrideMouseInput( float *x, float *y ) = 0; + virtual bool CreateMove( float flInputSampleTime, CUserCmd *cmd ) = 0; + + virtual void LevelInit( const char *newmap ) = 0; + virtual void LevelShutdown( void ) = 0; + + // Certain modes hide the view model + virtual bool ShouldDrawViewModel( void ) = 0; + virtual bool ShouldDrawCrosshair( void ) = 0; + + // Let mode override viewport for engine + virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ) = 0; + + // Called before rendering a view. + virtual void PreRender( CViewSetup *pSetup ) = 0; + + // Called after everything is rendered. + virtual void PostRender( void ) = 0; + + virtual void PostRenderVGui() = 0; + + virtual void ActivateInGameVGuiContext( vgui::Panel *pPanel ) = 0; + virtual void DeactivateInGameVGuiContext() = 0; + virtual float GetViewModelFOV( void ) = 0; + + virtual bool CanRecordDemo( char *errorMsg, int length ) const = 0; + + virtual void ComputeVguiResConditions( KeyValues *pkvConditions ) = 0; + + //============================================================================= + // HPE_BEGIN: + // [menglish] Save server information shown to the client in a persistent place + //============================================================================= + + virtual wchar_t* GetServerName() = 0; + virtual void SetServerName(wchar_t* name) = 0; + virtual wchar_t* GetMapName() = 0; + virtual void SetMapName(wchar_t* name) = 0; + + //============================================================================= + // HPE_END + //============================================================================= + + virtual bool DoPostScreenSpaceEffects( const CViewSetup *pSetup ) = 0; + + virtual void DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent, + const char *pSound, bool bDlg ) = 0; + +// Updates. +public: + + // Called every frame. + virtual void Update()=0; + + // Returns true if VR mode should black out everything around the UI + virtual bool ShouldBlackoutAroundHUD() = 0; + + // Returns true if VR mode should black out everything around the UI + virtual HeadtrackMovementMode_t ShouldOverrideHeadtrackControl() = 0; + + virtual bool IsInfoPanelAllowed() = 0; + virtual void InfoPanelDisplayed() = 0; + virtual bool IsHTMLInfoPanelAllowed() = 0; +}; + +extern IClientMode *g_pClientMode; + +#endif diff --git a/game/client/iclientshadowmgr.h b/game/client/iclientshadowmgr.h new file mode 100644 index 0000000..174f57a --- /dev/null +++ b/game/client/iclientshadowmgr.h @@ -0,0 +1,112 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ICLIENTSHADOWMGR_H +#define ICLIENTSHADOWMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include "icliententityinternal.h" +#include "engine/ishadowmgr.h" +#include "ivrenderview.h" +#include "toolframework/itoolentity.h" + +//----------------------------------------------------------------------------- +// Forward decls +//----------------------------------------------------------------------------- +struct FlashlightState_t; + + +//----------------------------------------------------------------------------- +// Handles to a client shadow +//----------------------------------------------------------------------------- +enum ShadowReceiver_t +{ + SHADOW_RECEIVER_BRUSH_MODEL = 0, + SHADOW_RECEIVER_STATIC_PROP, + SHADOW_RECEIVER_STUDIO_MODEL, +}; + + +//----------------------------------------------------------------------------- +// The class responsible for dealing with shadows on the client side +//----------------------------------------------------------------------------- +abstract_class IClientShadowMgr : public IGameSystemPerFrame +{ +public: + // Create, destroy shadows + virtual ClientShadowHandle_t CreateShadow( ClientEntityHandle_t entity, int flags ) = 0; + virtual void DestroyShadow( ClientShadowHandle_t handle ) = 0; + + // Create flashlight. + // FLASHLIGHTFIXME: need to rename all of the shadow stuff to projectedtexture and have flashlights and shadows as instances. + virtual ClientShadowHandle_t CreateFlashlight( const FlashlightState_t &lightState ) = 0; + virtual void UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &lightState ) = 0; + virtual void DestroyFlashlight( ClientShadowHandle_t handle ) = 0; + + // Indicate that the shadow should be recomputed due to a change in + // the client entity + virtual void UpdateProjectedTexture( ClientShadowHandle_t handle, bool force = false ) = 0; + + // Used to cause shadows to be re-projected against the world. + virtual void AddToDirtyShadowList( ClientShadowHandle_t handle, bool force = false ) = 0; + virtual void AddToDirtyShadowList( IClientRenderable *pRenderable, bool force = false ) = 0; + + // deals with shadows being added to shadow receivers + virtual void AddShadowToReceiver( ClientShadowHandle_t handle, + IClientRenderable* pRenderable, ShadowReceiver_t type ) = 0; + + virtual void RemoveAllShadowsFromReceiver( + IClientRenderable* pRenderable, ShadowReceiver_t type ) = 0; + + // Re-renders all shadow textures for shadow casters that lie in the leaf list + virtual void ComputeShadowTextures( const CViewSetup &view, int leafCount, LeafIndex_t* pLeafList ) = 0; + + // Frees shadow depth textures for use in subsequent view/frame + virtual void UnlockAllShadowDepthTextures() = 0; + + // Renders the shadow texture to screen... + virtual void RenderShadowTexture( int w, int h ) = 0; + + // Sets the shadow direction + color + virtual void SetShadowDirection( const Vector& dir ) = 0; + virtual const Vector &GetShadowDirection() const = 0; + + virtual void SetShadowColor( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void SetShadowDistance( float flMaxDistance ) = 0; + virtual void SetShadowBlobbyCutoffArea( float flMinArea ) = 0; + virtual void SetFalloffBias( ClientShadowHandle_t handle, unsigned char ucBias ) = 0; + + // Marks the render-to-texture shadow as needing to be re-rendered + virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t handle ) = 0; + + // Advance the frame + virtual void AdvanceFrame() = 0; + + // Set and clear flashlight target renderable + virtual void SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity ) = 0; + + // Set flashlight light world flag + virtual void SetFlashlightLightWorld( ClientShadowHandle_t shadowHandle, bool bLightWorld ) = 0; + + virtual void SetShadowsDisabled( bool bDisabled ) = 0; + + virtual void ComputeShadowDepthTextures( const CViewSetup &pView ) = 0; + +}; + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +extern IClientShadowMgr* g_pClientShadowMgr; + +#endif // ICLIENTSHADOWMGR_H diff --git a/game/client/iclientvehicle.h b/game/client/iclientvehicle.h new file mode 100644 index 0000000..d5d526d --- /dev/null +++ b/game/client/iclientvehicle.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef ICLIENTVEHICLE_H +#define ICLIENTVEHICLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "IVehicle.h" + +class C_BasePlayer; +class Vector; +class QAngle; +class C_BaseEntity; + + +//----------------------------------------------------------------------------- +// Purpose: All client vehicles must implement this interface. +//----------------------------------------------------------------------------- +abstract_class IClientVehicle : public IVehicle +{ +public: + // When a player is in a vehicle, here's where the camera will be + virtual void GetVehicleFOV( float &flFOV ) = 0; + + // Allows the vehicle to restrict view angles, blend, etc. + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) = 0; + + // Hud redraw... + virtual void DrawHudElements() = 0; + + // Is this predicted? + virtual bool IsPredicted() const = 0; + + // Get the entity associated with the vehicle. + virtual C_BaseEntity *GetVehicleEnt() = 0; + + // Allows the vehicle to change the near clip plane + virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const = 0; + + // Allows vehicles to choose their own curves for players using joysticks + virtual int GetJoystickResponseCurve() const = 0; + +#ifdef HL2_CLIENT_DLL + // Ammo in the vehicles + virtual int GetPrimaryAmmoType() const = 0; + virtual int GetPrimaryAmmoClip() const = 0; + virtual bool PrimaryAmmoUsesClips() const = 0; + virtual int GetPrimaryAmmoCount() const = 0; +#endif +}; + + +#endif // ICLIENTVEHICLE_H diff --git a/game/client/iconsole.h b/game/client/iconsole.h new file mode 100644 index 0000000..fad7fcc --- /dev/null +++ b/game/client/iconsole.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( ICONSOLE_H ) +#define ICONSOLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +abstract_class IConsole +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; +}; + +extern IConsole *console; + +#endif // ICONSOLE_H \ No newline at end of file diff --git a/game/client/idebugoverlaypanel.h b/game/client/idebugoverlaypanel.h new file mode 100644 index 0000000..dc06948 --- /dev/null +++ b/game/client/idebugoverlaypanel.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IDEBUGOVERLAYPANEL_H ) +#define IDEBUGOVERLAYPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +abstract_class IDebugOverlayPanel +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; +}; + +extern IDebugOverlayPanel *debugoverlaypanel; + +#endif // IDEBUGOVERLAYPANEL_H \ No newline at end of file diff --git a/game/client/ifpspanel.h b/game/client/ifpspanel.h new file mode 100644 index 0000000..cc5fb0f --- /dev/null +++ b/game/client/ifpspanel.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IFPSPANEL_H ) +#define IFPSPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +abstract_class IFPSPanel +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; +}; + +abstract_class IShowBlockingPanel +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; +}; + + +extern IFPSPanel *fps; +extern IShowBlockingPanel *iopanel; + +#endif // IFPSPANEL_H \ No newline at end of file diff --git a/game/client/ihudlcd.h b/game/client/ihudlcd.h new file mode 100644 index 0000000..ff1d819 --- /dev/null +++ b/game/client/ihudlcd.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IHUDLCD_H +#define IHUDLCD_H +#ifdef _WIN32 +#pragma once +#endif + +class IHudLCD +{ +public: + virtual void SetGlobalStat( char const *name, char const *value ) = 0; + virtual void AddChatLine( char const *txt ) = 0; +}; + +extern IHudLCD *hudlcd; + +#endif // IHUDLCD_H diff --git a/game/client/iinput.h b/game/client/iinput.h new file mode 100644 index 0000000..0a2aa70 --- /dev/null +++ b/game/client/iinput.h @@ -0,0 +1,118 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( IINPUT_H ) +#define IINPUT_H +#ifdef _WIN32 +#pragma once +#endif + +class bf_write; +class bf_read; +class CUserCmd; +class C_BaseCombatWeapon; +struct kbutton_t; + +struct CameraThirdData_t +{ + float m_flPitch; + float m_flYaw; + float m_flDist; + float m_flLag; + Vector m_vecHullMin; + Vector m_vecHullMax; +}; + +abstract_class IInput +{ +public: + // Initialization/shutdown of the subsystem + virtual void Init_All( void ) = 0; + virtual void Shutdown_All( void ) = 0; + // Latching button states + virtual int GetButtonBits( int ) = 0; + // Create movement command + virtual void CreateMove ( int sequence_number, float input_sample_frametime, bool active ) = 0; + virtual void ExtraMouseSample( float frametime, bool active ) = 0; + virtual bool WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand ) = 0; + virtual void EncodeUserCmdToBuffer( bf_write& buf, int slot ) = 0; + virtual void DecodeUserCmdFromBuffer( bf_read& buf, int slot ) = 0; + + virtual CUserCmd *GetUserCmd( int sequence_number ) = 0; + + virtual void MakeWeaponSelection( C_BaseCombatWeapon *weapon ) = 0; + + // Retrieve key state + virtual float KeyState ( kbutton_t *key ) = 0; + // Issue key event + virtual int KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding ) = 0; + // Look for key + virtual kbutton_t *FindKey( const char *name ) = 0; + + // Issue commands from controllers + virtual void ControllerCommands( void ) = 0; + // Extra initialization for some joysticks + virtual void Joystick_Advanced( void ) = 0; + virtual void Joystick_SetSampleTime( float frametime ) = 0; + virtual void IN_SetSampleTime( float frametime ) = 0; + + // Accumulate mouse delta + virtual void AccumulateMouse( void ) = 0; + // Activate/deactivate mouse + virtual void ActivateMouse( void ) = 0; + virtual void DeactivateMouse( void ) = 0; + + // Clear mouse state data + virtual void ClearStates( void ) = 0; + // Retrieve lookspring setting + virtual float GetLookSpring( void ) = 0; + + // Retrieve mouse position + virtual void GetFullscreenMousePos( int *mx, int *my, int *unclampedx = 0, int *unclampedy = 0 ) = 0; + virtual void SetFullscreenMousePos( int mx, int my ) = 0; + virtual void ResetMouse( void ) = 0; + virtual float GetLastForwardMove( void ) = 0; + virtual float Joystick_GetForward( void ) = 0; + virtual float Joystick_GetSide( void ) = 0; + virtual float Joystick_GetPitch( void ) = 0; + virtual float Joystick_GetYaw( void ) = 0; + + // Third Person camera ( TODO/FIXME: Move this to a separate interface? ) + virtual void CAM_Think( void ) = 0; + virtual int CAM_IsThirdPerson( void ) = 0; + virtual void CAM_ToThirdPerson(void) = 0; + virtual void CAM_ToFirstPerson(void) = 0; + virtual void CAM_StartMouseMove(void) = 0; + virtual void CAM_EndMouseMove(void) = 0; + virtual void CAM_StartDistance(void) = 0; + virtual void CAM_EndDistance(void) = 0; + virtual int CAM_InterceptingMouse( void ) = 0; + + // orthographic camera info ( TODO/FIXME: Move this to a separate interface? ) + virtual void CAM_ToOrthographic() = 0; + virtual bool CAM_IsOrthographic() const = 0; + virtual void CAM_OrthographicSize( float& w, float& h ) const = 0; + +#if defined( HL2_CLIENT_DLL ) + // IK back channel info + virtual void AddIKGroundContactInfo( int entindex, float minheight, float maxheight ) = 0; +#endif + + virtual void LevelInit( void ) = 0; + + // Causes an input to have to be re-pressed to become active + virtual void ClearInputButton( int bits ) = 0; + + virtual void CAM_SetCameraThirdData( CameraThirdData_t *pCameraData, const QAngle &vecCameraOffset ) = 0; + virtual void CAM_CameraThirdThink( void ) = 0; + + virtual bool EnableJoystickMode() = 0; +}; + +extern ::IInput *input; + +#endif // IINPUT_H \ No newline at end of file diff --git a/game/client/iloadingdisc.h b/game/client/iloadingdisc.h new file mode 100644 index 0000000..5929b49 --- /dev/null +++ b/game/client/iloadingdisc.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef ILOADINGDISC_H +#define ILOADINGDISC_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +abstract_class ILoadingDisc +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; + + // loading disc + virtual void SetLoadingVisible( bool bVisible ) = 0; + + // paused disc + virtual void SetPausedVisible( bool bVisible ) = 0; +}; + +extern ILoadingDisc *loadingdisc; + +#endif // ILOADINGDISC_H \ No newline at end of file diff --git a/game/client/imessagechars.h b/game/client/imessagechars.h new file mode 100644 index 0000000..af39090 --- /dev/null +++ b/game/client/imessagechars.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IMESSAGECHARS_H ) +#define IMESSAGECHARS_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ +class Panel; +typedef unsigned long HFont; +} + +abstract_class IMessageChars +{ +public: + enum + { + MESSAGESTRINGID_NONE = -1, + MESSAGESTRINGID_BASE = 0 + }; + + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; + + // messageID can be MESSAGESTRINGID_NONE or MESSAGESTRINGID_BASE plus some offset. You can refer to the message by + // its ID later. + virtual int DrawString( vgui::HFont pCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... ) = 0; + virtual int DrawString( vgui::HFont pCustomFont, int x, int y, const char *fmt, int messageID, ... ) = 0; + + virtual int DrawStringForTime( float flTime, vgui::HFont pCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... ) = 0; + virtual int DrawStringForTime( float flTime, vgui::HFont pCustomFont, int x, int y, const char *fmt, int messageID, ... ) = 0; + + // Remove all messages with the specified ID (passed into DrawStringForTime). + virtual void RemoveStringsByID( int messageID ) = 0; + + virtual void GetStringLength( vgui::HFont pCustomFont, int *width, int *height, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + virtual void Clear( void ) = 0; +}; + +extern IMessageChars *messagechars; + +#endif // IMESSAGECHARS_H \ No newline at end of file diff --git a/game/client/in_main.h b/game/client/in_main.h new file mode 100644 index 0000000..2e8fb9a --- /dev/null +++ b/game/client/in_main.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IN_MAIN_H +#define IN_MAIN_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "kbutton.h" + + +extern kbutton_t in_commandermousemove; +extern kbutton_t in_ducktoggle; + +#endif // IN_MAIN_H diff --git a/game/client/inetgraphpanel.h b/game/client/inetgraphpanel.h new file mode 100644 index 0000000..f53d238 --- /dev/null +++ b/game/client/inetgraphpanel.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( INETGRAPHPANEL_H ) +#define INETGRAPHPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +abstract_class INetGraphPanel +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; +}; + +extern INetGraphPanel *netgraphpanel; + +#endif // INETGRAPHPANEL_H \ No newline at end of file diff --git a/game/client/initializer.h b/game/client/initializer.h new file mode 100644 index 0000000..949368c --- /dev/null +++ b/game/client/initializer.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// Initializers are a way to register your object to be initialized at startup time. +// They're a good way to have global variables without worrying about dependent +// constructors being called. They also make it so init code doesn't depend on the +// global objects it's initializing. + +// To use initializers, just use REGISTER_INITIALIZER to register your global variable like this: +// class SomeClass {....} +// SomeClass *g_pSomeClassSingleton = NULL; +// REGISTER_INITIALIZER(SomeClass, &g_pSomeClassSingleton); + +#ifndef INITIALIZER_H +#define INITIALIZER_H + + +typedef void* (*CreateInitializerObjectFn)(); +typedef void (*DeleteInitializerObjectFn)(void *ptr); + +class Initializer +{ +public: + Initializer(void **pVar, CreateInitializerObjectFn createFn, DeleteInitializerObjectFn deleteFn); + + // Allocates all the global objects. + static bool InitializeAllObjects(); + + // Free all the global objects. + static void FreeAllObjects(); + + +private: + static Initializer *s_pInitializers; + + void **m_pVar; + CreateInitializerObjectFn m_CreateFn; + DeleteInitializerObjectFn m_DeleteFn; + Initializer *m_pNext; +}; + + +#define REGISTER_INITIALIZER(className, varPointer) \ + static void* __Initializer__Create##className##Fn() {return new className;} \ + static void* __Initializer__Delete##className##Fn(void *ptr) {delete (className*)ptr;} \ + static Initializer g_Initializer_##className##(varPointer, __Initializer__Create##className##Fn, __Initializer__Delete##className##Fn); + +#define REGISTER_FUNCTION_INITIALIZER(functionName) \ + static void* __Initializer__Create##functionName##Fn() { functionName(); return 0; } \ + static Initializer g_Initializer_##functionName##(0, __Initializer__Create##functionName##Fn, 0); + +#endif + diff --git a/game/client/input.h b/game/client/input.h new file mode 100644 index 0000000..2fa2cec --- /dev/null +++ b/game/client/input.h @@ -0,0 +1,291 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#if !defined( INPUT_H ) +#define INPUT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iinput.h" +#include "mathlib/vector.h" +#include "kbutton.h" +#include "ehandle.h" +#include "inputsystem/AnalogCode.h" + +typedef unsigned int CRC32_t; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CKeyboardKey +{ +public: + // Name for key + char name[ 32 ]; + // Pointer to the underlying structure + kbutton_t *pkey; + // Next key in key list. + CKeyboardKey *next; +}; + +class ConVar; + +class CInput : public IInput +{ +// Interface +public: + CInput( void ); + ~CInput( void ); + + virtual void Init_All( void ); + virtual void Shutdown_All( void ); + virtual int GetButtonBits( int ); + virtual void CreateMove ( int sequence_number, float input_sample_frametime, bool active ); + virtual void ExtraMouseSample( float frametime, bool active ); + virtual bool WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand ); + virtual void EncodeUserCmdToBuffer( bf_write& buf, int slot ); + virtual void DecodeUserCmdFromBuffer( bf_read& buf, int slot ); + + virtual CUserCmd *GetUserCmd( int sequence_number ); + + virtual void MakeWeaponSelection( C_BaseCombatWeapon *weapon ); + + virtual float KeyState( kbutton_t *key ); + virtual int KeyEvent( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual kbutton_t *FindKey( const char *name ); + + virtual void ControllerCommands( void ); + virtual void Joystick_Advanced( void ); + virtual void Joystick_SetSampleTime(float frametime); + virtual void IN_SetSampleTime( float frametime ); + + virtual void AccumulateMouse( void ); + virtual void ActivateMouse( void ); + virtual void DeactivateMouse( void ); + + virtual void ClearStates( void ); + virtual float GetLookSpring( void ); + + virtual void GetFullscreenMousePos( int *mx, int *my, int *unclampedx = NULL, int *unclampedy = NULL ); + virtual void SetFullscreenMousePos( int mx, int my ); + virtual void ResetMouse( void ); + +// virtual bool IsNoClipping( void ); + virtual float GetLastForwardMove( void ); + virtual float Joystick_GetForward( void ); + virtual float Joystick_GetSide( void ); + virtual float Joystick_GetPitch( void ); + virtual float Joystick_GetYaw( void ); + virtual void ClearInputButton( int bits ); + + virtual void CAM_Think( void ); + virtual int CAM_IsThirdPerson( void ); + virtual void CAM_ToThirdPerson(void); + virtual void CAM_ToFirstPerson(void); + virtual void CAM_StartMouseMove(void); + virtual void CAM_EndMouseMove(void); + virtual void CAM_StartDistance(void); + virtual void CAM_EndDistance(void); + virtual int CAM_InterceptingMouse( void ); + + // orthographic camera info + virtual void CAM_ToOrthographic(); + virtual bool CAM_IsOrthographic() const; + virtual void CAM_OrthographicSize( float& w, float& h ) const; + + virtual float CAM_CapYaw( float fVal ) const { return fVal; } + virtual float CAM_CapPitch( float fVal ) const { return fVal; } + +#if defined( HL2_CLIENT_DLL ) + // IK back channel info + virtual void AddIKGroundContactInfo( int entindex, float minheight, float maxheight ); +#endif + virtual void LevelInit( void ); + + virtual void CAM_SetCameraThirdData( CameraThirdData_t *pCameraData, const QAngle &vecCameraOffset ); + virtual void CAM_CameraThirdThink( void ); + + virtual bool EnableJoystickMode(); + +// Private Implementation +protected: + // Implementation specific initialization + void Init_Camera( void ); + void Init_Keyboard( void ); + void Init_Mouse( void ); + void Shutdown_Keyboard( void ); + // Add a named key to the list queryable by the engine + void AddKeyButton( const char *name, kbutton_t *pkb ); + // Mouse/keyboard movement input helpers + void ScaleMovements( CUserCmd *cmd ); + void ComputeForwardMove( CUserCmd *cmd ); + void ComputeUpwardMove( CUserCmd *cmd ); + void ComputeSideMove( CUserCmd *cmd ); + void AdjustAngles ( float frametime ); + void ClampAngles( QAngle& viewangles ); + void AdjustPitch( float speed, QAngle& viewangles ); + virtual void AdjustYaw( float speed, QAngle& viewangles ); + float DetermineKeySpeed( float frametime ); + void GetAccumulatedMouseDeltasAndResetAccumulators( float *mx, float *my ); + void GetMouseDelta( float inmousex, float inmousey, float *pOutMouseX, float *pOutMouseY ); + void ScaleMouse( float *x, float *y ); + virtual void ApplyMouse( QAngle& viewangles, CUserCmd *cmd, float mouse_x, float mouse_y ); + virtual void MouseMove ( CUserCmd *cmd ); + + // Joystick movement input helpers + void ControllerMove ( float frametime, CUserCmd *cmd ); + void JoyStickMove ( float frametime, CUserCmd *cmd ); + float ScaleAxisValue( const float axisValue, const float axisThreshold ); + virtual float JoyStickAdjustYaw( float flSpeed ) { return flSpeed; } + + // Call this to get the cursor position. The call will be logged in the VCR file if there is one. + void GetMousePos(int &x, int &y); + void SetMousePos(int x, int y); + void GetWindowCenter( int&x, int& y ); + // Called once per frame to allow convar overrides to acceleration settings when mouse is active + void CheckMouseAcclerationVars(); + + void ValidateUserCmd( CUserCmd *usercmd, int sequence_number ); + +// Private Data +private: + typedef struct + { + unsigned int AxisFlags; + unsigned int AxisMap; + unsigned int ControlMap; + } joy_axis_t; + + void DescribeJoystickAxis( char const *axis, joy_axis_t *mapping ); + char const *DescribeAxis( int index ); + + enum + { + GAME_AXIS_NONE = 0, + GAME_AXIS_FORWARD, + GAME_AXIS_PITCH, + GAME_AXIS_SIDE, + GAME_AXIS_YAW, + MAX_GAME_AXES + }; + + enum + { + CAM_COMMAND_NONE = 0, + CAM_COMMAND_TOTHIRDPERSON = 1, + CAM_COMMAND_TOFIRSTPERSON = 2 + }; + + enum + { + MOUSE_ACCEL_THRESHHOLD1 = 0, // if mouse moves > this many mickey's double it + MOUSE_ACCEL_THRESHHOLD2, // if mouse moves > this many mickey's double it a second time + MOUSE_SPEED_FACTOR, // 0 = disabled, 1 = threshold 1 enabled, 2 = threshold 2 enabled + + NUM_MOUSE_PARAMS, + }; + + // Has the mouse been initialized? + bool m_fMouseInitialized; + // Is the mosue active? + bool m_fMouseActive; + // Has the joystick advanced initialization been run? + bool m_fJoystickAdvancedInit; + // Used to support hotplugging by reinitializing the advanced joystick system when we toggle between some/none joysticks. + bool m_fHadJoysticks; + + // Accumulated mouse deltas + float m_flAccumulatedMouseXMovement; + float m_flAccumulatedMouseYMovement; + float m_flPreviousMouseXPosition; + float m_flPreviousMouseYPosition; + float m_flRemainingJoystickSampleTime; + float m_flKeyboardSampleTime; + + // Flag to restore systemparameters when exiting + bool m_fRestoreSPI; + // Original mouse parameters + int m_rgOrigMouseParms[ NUM_MOUSE_PARAMS ]; + // Current mouse parameters. + int m_rgNewMouseParms[ NUM_MOUSE_PARAMS ]; + bool m_rgCheckMouseParam[ NUM_MOUSE_PARAMS ]; + // Are the parameters valid + bool m_fMouseParmsValid; + // Joystick Axis data + joy_axis_t m_rgAxes[ MAX_JOYSTICK_AXES ]; + // List of queryable keys + CKeyboardKey *m_pKeys; + + // Is the 3rd person camera using the mouse? + bool m_fCameraInterceptingMouse; + // Are we in 3rd person view? + bool m_fCameraInThirdPerson; + // Should we move view along with mouse? + bool m_fCameraMovingWithMouse; + + + // Is the camera in distance moving mode? + bool m_fCameraDistanceMove; + // Old and current mouse position readings. + int m_nCameraOldX; + int m_nCameraOldY; + int m_nCameraX; + int m_nCameraY; + + // orthographic camera settings + bool m_CameraIsOrthographic; + + QAngle m_angPreviousViewAngles; + + float m_flLastForwardMove; + + float m_flPreviousJoystickForward; + float m_flPreviousJoystickSide; + float m_flPreviousJoystickPitch; + float m_flPreviousJoystickYaw; + + class CVerifiedUserCmd + { + public: + CUserCmd m_cmd; + CRC32_t m_crc; + }; + + CUserCmd *m_pCommands; + CVerifiedUserCmd *m_pVerifiedCommands; + + CameraThirdData_t *m_pCameraThirdData; + + // Set until polled by CreateMove and cleared + CHandle< C_BaseCombatWeapon > m_hSelectedWeapon; + +#if defined( HL2_CLIENT_DLL ) + CUtlVector< CEntityGroundContact > m_EntityGroundContact; +#endif +}; + +extern kbutton_t in_strafe; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; +extern kbutton_t in_graph; +extern kbutton_t in_moveleft; +extern kbutton_t in_moveright; +extern kbutton_t in_forward; +extern kbutton_t in_back; +extern kbutton_t in_joyspeed; + +extern class ConVar in_joystick; +extern class ConVar joy_autosprint; + +extern void KeyDown( kbutton_t *b, const char *c ); +extern void KeyUp( kbutton_t *b, const char *c ); + + +#endif // INPUT_H + \ No newline at end of file diff --git a/game/client/interpolatedvar.h b/game/client/interpolatedvar.h new file mode 100644 index 0000000..f0edb58 --- /dev/null +++ b/game/client/interpolatedvar.h @@ -0,0 +1,1591 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef INTERPOLATEDVAR_H +#define INTERPOLATEDVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utllinkedlist.h" +#include "rangecheckedvar.h" +#include "lerp_functions.h" +#include "animationlayer.h" +#include "convar.h" + + +#include "tier0/memdbgon.h" + +#define COMPARE_HISTORY(a,b) \ + ( memcmp( m_VarHistory[a].GetValue(), m_VarHistory[b].GetValue(), sizeof(Type)*GetMaxCount() ) == 0 ) + +// Define this to have it measure whether or not the interpolated entity list +// is accurate. +//#define INTERPOLATEDVAR_PARANOID_MEASUREMENT + + +#define LATCH_ANIMATION_VAR (1<<0) // use AnimTime as sample basis +#define LATCH_SIMULATION_VAR (1<<1) // use SimulationTime as sample basis + +#define EXCLUDE_AUTO_LATCH (1<<2) +#define EXCLUDE_AUTO_INTERPOLATE (1<<3) + +#define INTERPOLATE_LINEAR_ONLY (1<<4) // don't do hermite interpolation +#define INTERPOLATE_OMIT_UPDATE_LAST_NETWORKED (1<<5) + + + +#define EXTRA_INTERPOLATION_HISTORY_STORED 0.05f // It stores this much extra interpolation history, + // so you can always call Interpolate() this far + // in the past from your last call and be able to + // get an interpolated value. + +// this global keeps the last known server packet tick (to avoid calling engine->GetLastTimestamp() all the time) +extern float g_flLastPacketTimestamp; + +inline void Interpolation_SetLastPacketTimeStamp( float timestamp) +{ + Assert( timestamp > 0 ); + g_flLastPacketTimestamp = timestamp; +} + + +// Before calling Interpolate(), you can use this use this to setup the context if +// you want to enable extrapolation. +class CInterpolationContext +{ +public: + + CInterpolationContext() + { + m_bOldAllowExtrapolation = s_bAllowExtrapolation; + m_flOldLastTimeStamp = s_flLastTimeStamp; + + // By default, disable extrapolation unless they call EnableExtrapolation. + s_bAllowExtrapolation = false; + + // this is the context stack + m_pNext = s_pHead; + s_pHead = this; + } + + ~CInterpolationContext() + { + // restore values from prev stack element + s_bAllowExtrapolation = m_bOldAllowExtrapolation; + s_flLastTimeStamp = m_flOldLastTimeStamp; + + Assert( s_pHead == this ); + s_pHead = m_pNext; + } + + static void EnableExtrapolation(bool state) + { + s_bAllowExtrapolation = state; + } + + static bool IsThereAContext() + { + return s_pHead != NULL; + } + + static bool IsExtrapolationAllowed() + { + return s_bAllowExtrapolation; + } + + static void SetLastTimeStamp(float timestamp) + { + s_flLastTimeStamp = timestamp; + } + + static float GetLastTimeStamp() + { + return s_flLastTimeStamp; + } + + +private: + + CInterpolationContext *m_pNext; + bool m_bOldAllowExtrapolation; + float m_flOldLastTimeStamp; + + static CInterpolationContext *s_pHead; + static bool s_bAllowExtrapolation; + static float s_flLastTimeStamp; +}; + + +extern ConVar cl_extrapolate_amount; + + +template< class T > +inline T ExtrapolateInterpolatedVarType( const T &oldVal, const T &newVal, float divisor, float flExtrapolationAmount ) +{ + return newVal; +} + +inline Vector ExtrapolateInterpolatedVarType( const Vector &oldVal, const Vector &newVal, float divisor, float flExtrapolationAmount ) +{ + return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal ); +} + +inline float ExtrapolateInterpolatedVarType( const float &oldVal, const float &newVal, float divisor, float flExtrapolationAmount ) +{ + return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal ); +} + +inline QAngle ExtrapolateInterpolatedVarType( const QAngle &oldVal, const QAngle &newVal, float divisor, float flExtrapolationAmount ) +{ + return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal ); +} + + +// -------------------------------------------------------------------------------------------------------------- // +// IInterpolatedVar interface. +// -------------------------------------------------------------------------------------------------------------- // + +abstract_class IInterpolatedVar +{ +public: + virtual ~IInterpolatedVar() {} + + virtual void Setup( void *pValue, int type ) = 0; + virtual void SetInterpolationAmount( float seconds ) = 0; + + // Returns true if the new value is different from the prior most recent value. + virtual void NoteLastNetworkedValue() = 0; + virtual bool NoteChanged( float changetime, bool bUpdateLastNetworkedValue ) = 0; + virtual void Reset() = 0; + + // Returns 1 if the value will always be the same if currentTime is always increasing. + virtual int Interpolate( float currentTime ) = 0; + + virtual int GetType() const = 0; + virtual void RestoreToLastNetworked() = 0; + virtual void Copy( IInterpolatedVar *pSrc ) = 0; + + virtual const char *GetDebugName() = 0; + virtual void SetDebugName( const char* pName ) = 0; + + virtual void SetDebug( bool bDebug ) = 0; +}; + +template< typename Type, bool IS_ARRAY > +struct CInterpolatedVarEntryBase +{ + CInterpolatedVarEntryBase() + { + value = NULL; + count = 0; + changetime = 0; + } + ~CInterpolatedVarEntryBase() + { + delete[] value; + value = NULL; + } + + // This will transfer the data from another varentry. This is used to avoid allocation + // pointers can be transferred (only one varentry has a copy), but not trivially copied + void FastTransferFrom( CInterpolatedVarEntryBase &src ) + { + Assert(!value); + value = src.value; + count = src.count; + changetime = src.changetime; + src.value = 0; + src.count = 0; + } + + CInterpolatedVarEntryBase& operator=( const CInterpolatedVarEntryBase& src ) + { + delete[] value; + value = NULL; + count = 0; + if ( src.value ) + { + count = src.count; + value = new Type[count]; + for ( int i = 0; i < count; i++ ) + { + value[i] = src.value[i]; + } + } + return *this; + } + + Type *GetValue() { return value; } + const Type *GetValue() const { return value; } + + void Init(int maxCount) + { + if ( !maxCount ) + { + DeleteEntry(); + } + else + { + // resize + if ( maxCount != count ) + { + DeleteEntry(); + } + + if ( !value ) + { + count = maxCount; + value = new Type[maxCount]; + } + } + Assert(count==maxCount); + } + Type *NewEntry( const Type *pValue, int maxCount, float time ) + { + changetime = time; + Init(maxCount); + if ( value && maxCount) + { + memcpy( value, pValue, maxCount*sizeof(Type) ); + } + return value; + } + + void DeleteEntry() + { + delete[] value; + value = NULL; + count = 0; + } + + float changetime; + int count; + Type * value; + +private: + CInterpolatedVarEntryBase( const CInterpolatedVarEntryBase &src ); +}; + +template +struct CInterpolatedVarEntryBase +{ + CInterpolatedVarEntryBase() {} + ~CInterpolatedVarEntryBase() {} + + const Type *GetValue() const { return &value; } + Type *GetValue() { return &value; } + + void Init(int maxCount) + { + Assert(maxCount==1); + } + Type *NewEntry( const Type *pValue, int maxCount, float time ) + { + Assert(maxCount==1); + changetime = time; + memcpy( &value, pValue, maxCount*sizeof(Type) ); + return &value; + } + void FastTransferFrom( CInterpolatedVarEntryBase &src ) + { + *this = src; + } + + void DeleteEntry() {} + + float changetime; + Type value; +}; + +template +class CSimpleRingBuffer +{ +public: + CSimpleRingBuffer( int startSize = 4 ) + { + m_pElements = 0; + m_maxElement = 0; + m_firstElement = 0; + m_count = 0; + m_growSize = 16; + EnsureCapacity(startSize); + } + ~CSimpleRingBuffer() + { + delete[] m_pElements; + m_pElements = NULL; + } + + inline int Count() const { return m_count; } + + int Head() const { return (m_count>0) ? 0 : InvalidIndex(); } + + bool IsIdxValid( int i ) const { return (i >= 0 && i < m_count) ? true : false; } + bool IsValidIndex(int i) const { return IsIdxValid(i); } + static int InvalidIndex() { return -1; } + + T& operator[]( int i ) + { + Assert( IsIdxValid(i) ); + i += m_firstElement; + i = WrapRange(i); + return m_pElements[i]; + } + + const T& operator[]( int i ) const + { + Assert( IsIdxValid(i) ); + i += m_firstElement; + i = WrapRange(i); + return m_pElements[i]; + } + + void EnsureCapacity( int capSize ) + { + if ( capSize > m_maxElement ) + { + int newMax = m_maxElement + ((capSize+m_growSize-1)/m_growSize) * m_growSize; + T *pNew = new T[newMax]; + for ( int i = 0; i < m_maxElement; i++ ) + { + // ------------ + // If you wanted to make this a more generic container you'd probably want this code + // instead - since FastTransferFrom() is an optimization dependent on types stored + // here defining this operation. + //pNew[i] = m_pElements[WrapRange(i+m_firstElement)]; + pNew[i].FastTransferFrom( m_pElements[WrapRange(i+m_firstElement)] ); + // ------------ + } + m_firstElement = 0; + m_maxElement = newMax; + delete[] m_pElements; + m_pElements = pNew; + } + } + + int AddToHead() + { + EnsureCapacity( m_count + 1 ); + int i = m_firstElement + m_maxElement - 1; + m_count++; + i = WrapRange(i); + m_firstElement = i; + return 0; + } + + int AddToHead( const T &elem ) + { + AddToHead(); + m_pElements[m_firstElement] = elem; + return 0; + } + + int AddToTail() + { + EnsureCapacity( m_count + 1 ); + m_count++; + return WrapRange(m_firstElement+m_count-1); + } + + void RemoveAll() + { + m_count = 0; + m_firstElement = 0; + } + + void RemoveAtHead() + { + if ( m_count > 0 ) + { + m_firstElement = WrapRange(m_firstElement+1); + m_count--; + } + } + + void Truncate( int newLength ) + { + if ( newLength < m_count ) + { + Assert(newLength>=0); + m_count = newLength; + } + } + +private: + inline int WrapRange( int i ) const + { + return ( i >= m_maxElement ) ? (i - m_maxElement) : i; + } + + T *m_pElements; + unsigned short m_maxElement; + unsigned short m_firstElement; + unsigned short m_count; + unsigned short m_growSize; +}; + +// -------------------------------------------------------------------------------------------------------------- // +// CInterpolatedVarArrayBase - the main implementation of IInterpolatedVar. +// -------------------------------------------------------------------------------------------------------------- // + +template< typename Type, bool IS_ARRAY> +class CInterpolatedVarArrayBase : public IInterpolatedVar +{ +public: + friend class CInterpolatedVarPrivate; + + CInterpolatedVarArrayBase( const char *pDebugName="no debug name" ); + virtual ~CInterpolatedVarArrayBase(); + + + // IInterpolatedVar overrides. +public: + + virtual void Setup( void *pValue, int type ); + virtual void SetInterpolationAmount( float seconds ); + virtual void NoteLastNetworkedValue(); + virtual bool NoteChanged( float changetime, bool bUpdateLastNetworkedValue ); + virtual void Reset(); + virtual int Interpolate( float currentTime ); + virtual int GetType() const; + virtual void RestoreToLastNetworked(); + virtual void Copy( IInterpolatedVar *pInSrc ); + virtual const char *GetDebugName() { return m_pDebugName; } + + +public: + + // Just like the IInterpolatedVar functions, but you can specify an interpolation amount. + bool NoteChanged( float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue ); + int Interpolate( float currentTime, float interpolation_amount ); + + void DebugInterpolate( Type *pOut, float currentTime ); + + void GetDerivative( Type *pOut, float currentTime ); + void GetDerivative_SmoothVelocity( Type *pOut, float currentTime ); // See notes on ::Derivative_HermiteLinearVelocity for info. + + void ClearHistory(); + void AddToHead( float changeTime, const Type* values, bool bFlushNewer ); + const Type& GetPrev( int iArrayIndex=0 ) const; + const Type& GetCurrent( int iArrayIndex=0 ) const; + + // Returns the time difference betweem the most recent sample and its previous sample. + float GetInterval() const; + bool IsValidIndex( int i ); + Type *GetHistoryValue( int index, float& changetime, int iArrayIndex=0 ); + int GetHead() { return 0; } + int GetNext( int i ) + { + int next = i + 1; + if ( !m_VarHistory.IsValidIndex(next) ) + return m_VarHistory.InvalidIndex(); + return next; + } + + void SetHistoryValuesForItem( int item, Type& value ); + void SetLooping( bool looping, int iArrayIndex=0 ); + + void SetMaxCount( int newmax ); + int GetMaxCount() const; + + // Get the time of the oldest entry. + float GetOldestEntry(); + + // set a debug name (if not provided by constructor) + void SetDebugName(const char *pName ) { m_pDebugName = pName; } + virtual void SetDebug( bool bDebug ) { m_bDebug = bDebug; } + bool GetInterpolationInfo( float currentTime, int *pNewer, int *pOlder, int *pOldest ); + +protected: + + typedef CInterpolatedVarEntryBase CInterpolatedVarEntry; + typedef CSimpleRingBuffer< CInterpolatedVarEntry > CVarHistory; + friend class CInterpolationInfo; + + class CInterpolationInfo + { + public: + bool m_bHermite; + int oldest; // Only set if using hermite. + int older; + int newer; + float frac; + }; + + +protected: + + void RemoveOldEntries( float oldesttime ); + void RemoveEntriesPreviousTo( float flTime ); + + bool GetInterpolationInfo( + CInterpolationInfo *pInfo, + float currentTime, + float interpolation_amount, + int *pNoMoreChanges ); + + void TimeFixup_Hermite( + CInterpolatedVarEntry &fixup, + CInterpolatedVarEntry*& prev, + CInterpolatedVarEntry*& start, + CInterpolatedVarEntry*& end ); + + // Force the time between prev and start to be dt (and extend prev out farther if necessary). + void TimeFixup2_Hermite( + CInterpolatedVarEntry &fixup, + CInterpolatedVarEntry*& prev, + CInterpolatedVarEntry*& start, + float dt + ); + + void _Extrapolate( + Type *pOut, + CInterpolatedVarEntry *pOld, + CInterpolatedVarEntry *pNew, + float flDestinationTime, + float flMaxExtrapolationAmount + ); + + void _Interpolate( Type *out, float frac, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end ); + void _Interpolate_Hermite( Type *out, float frac, CInterpolatedVarEntry *pOriginalPrev, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end, bool looping = false ); + + void _Derivative_Hermite( Type *out, float frac, CInterpolatedVarEntry *pOriginalPrev, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end ); + void _Derivative_Hermite_SmoothVelocity( Type *out, float frac, CInterpolatedVarEntry *b, CInterpolatedVarEntry *c, CInterpolatedVarEntry *d ); + void _Derivative_Linear( Type *out, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end ); + + bool ValidOrder(); + +protected: + // The underlying data element + Type *m_pValue; + CVarHistory m_VarHistory; + // Store networked values so when we latch we can detect which values were changed via networking + Type * m_LastNetworkedValue; + float m_LastNetworkedTime; + byte m_fType; + byte m_nMaxCount; + byte * m_bLooping; + float m_InterpolationAmount; + const char * m_pDebugName; + bool m_bDebug : 1; +}; + + +template< typename Type, bool IS_ARRAY > +inline CInterpolatedVarArrayBase::CInterpolatedVarArrayBase( const char *pDebugName ) +{ + m_pDebugName = pDebugName; + m_pValue = NULL; + m_fType = LATCH_ANIMATION_VAR; + m_InterpolationAmount = 0.0f; + m_nMaxCount = 0; + m_LastNetworkedTime = 0; + m_LastNetworkedValue = NULL; + m_bLooping = NULL; + m_bDebug = false; +} + +template< typename Type, bool IS_ARRAY > +inline CInterpolatedVarArrayBase::~CInterpolatedVarArrayBase() +{ + ClearHistory(); + delete [] m_bLooping; + delete [] m_LastNetworkedValue; +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::Setup( void *pValue, int type ) +{ + m_pValue = ( Type * )pValue; + m_fType = type; +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetInterpolationAmount( float seconds ) +{ + m_InterpolationAmount = seconds; +} + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::GetType() const +{ + return m_fType; +} + +template< typename Type, bool IS_ARRAY > +void CInterpolatedVarArrayBase::NoteLastNetworkedValue() +{ + memcpy( m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof( Type ) ); + m_LastNetworkedTime = g_flLastPacketTimestamp; +} + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::NoteChanged( float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue ) +{ + Assert( m_pValue ); + + // This is a big optimization where it can potentially avoid expensive interpolation + // involving this variable if it didn't get an actual new value in here. + bool bRet = true; + if ( m_VarHistory.Count() ) + { + if ( memcmp( m_pValue, m_VarHistory[0].GetValue(), sizeof( Type ) * m_nMaxCount ) == 0 ) + { + bRet = false; + } + } + + if ( m_bDebug ) + { + char const *pDiffString = bRet ? "differs" : "identical"; + + Msg( "%s LatchChanged at %f changetime %f: %s\n", GetDebugName(), gpGlobals->curtime, changetime, pDiffString ); + } + + AddToHead( changetime, m_pValue, true ); + + if ( bUpdateLastNetworkedValue ) + { + NoteLastNetworkedValue(); + } + +#if 0 + // Since we don't clean out the old entries until Interpolate(), make sure that there + // aren't any super old entries hanging around. + RemoveOldEntries( gpGlobals->curtime - interpolation_amount - 2.0f ); +#else + // JAY: It doesn't seem like the above code is correct. This is keeping more than two seconds of history + // for variables that aren't being interpolated for some reason. For example, the player model isn't drawn + // in first person, so the history is only truncated here and will accumulate ~40 entries instead of 2 or 3 + // changing over to the method in Interpolate() means that we always have a 3-sample neighborhood around + // any data we're going to need. Unless gpGlobals->curtime is different when samples are added vs. when + // they are interpolated I can't see this having any ill effects. + RemoveEntriesPreviousTo( gpGlobals->curtime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED ); +#endif + + return bRet; +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::NoteChanged( float changetime, bool bUpdateLastNetworkedValue ) +{ + return NoteChanged( changetime, m_InterpolationAmount, bUpdateLastNetworkedValue ); +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::RestoreToLastNetworked() +{ + Assert( m_pValue ); + memcpy( m_pValue, m_LastNetworkedValue, m_nMaxCount * sizeof( Type ) ); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::ClearHistory() +{ + for ( int i = 0; i < m_VarHistory.Count(); i++ ) + { + m_VarHistory[i].DeleteEntry(); + } + m_VarHistory.RemoveAll(); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::AddToHead( float changeTime, const Type* values, bool bFlushNewer ) +{ + MEM_ALLOC_CREDIT_CLASS(); + int newslot; + + if ( bFlushNewer ) + { + // Get rid of anything that has a timestamp after this sample. The server might have + // corrected our clock and moved us back, so our current changeTime is less than a + // changeTime we added samples during previously. + while ( m_VarHistory.Count() ) + { + if ( (m_VarHistory[0].changetime+0.0001f) > changeTime ) + { + m_VarHistory.RemoveAtHead(); + } + else + { + break; + } + } + + newslot = m_VarHistory.AddToHead(); + } + else + { + newslot = m_VarHistory.AddToHead(); + for ( int i = 1; i < m_VarHistory.Count(); i++ ) + { + if ( m_VarHistory[i].changetime <= changeTime ) + break; + m_VarHistory[newslot].FastTransferFrom( m_VarHistory[i] ); + newslot = i; + } + } + + CInterpolatedVarEntry *e = &m_VarHistory[ newslot ]; + e->NewEntry( values, m_nMaxCount, changeTime ); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::Reset() +{ + ClearHistory(); + + if ( m_pValue ) + { + AddToHead( gpGlobals->curtime, m_pValue, false ); + AddToHead( gpGlobals->curtime, m_pValue, false ); + AddToHead( gpGlobals->curtime, m_pValue, false ); + + memcpy( m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof( Type ) ); + } +} + + +template< typename Type, bool IS_ARRAY > +inline float CInterpolatedVarArrayBase::GetOldestEntry() +{ + float lastVal = 0; + if ( m_VarHistory.Count() ) + { + lastVal = m_VarHistory[m_VarHistory.Count()-1].changetime; + } + return lastVal; +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::RemoveOldEntries( float oldesttime ) +{ + int newCount = m_VarHistory.Count(); + for ( int i = m_VarHistory.Count(); --i > 2; ) + { + if ( m_VarHistory[i].changetime > oldesttime ) + break; + newCount = i; + } + m_VarHistory.Truncate(newCount); +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::RemoveEntriesPreviousTo( float flTime ) +{ + for ( int i = 0; i < m_VarHistory.Count(); i++ ) + { + if ( m_VarHistory[i].changetime < flTime ) + { + // We need to preserve this sample (ie: the one right before this timestamp) + // and the sample right before it (for hermite blending), and we can get rid + // of everything else. + m_VarHistory.Truncate( i + 3 ); + break; + } + } +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::GetInterpolationInfo( + typename CInterpolatedVarArrayBase::CInterpolationInfo *pInfo, + float currentTime, + float interpolation_amount, + int *pNoMoreChanges + ) +{ + Assert( m_pValue ); + + CVarHistory &varHistory = m_VarHistory; + + float targettime = currentTime - interpolation_amount; + + pInfo->m_bHermite = false; + pInfo->frac = 0; + pInfo->oldest = pInfo->older = pInfo->newer = varHistory.InvalidIndex(); + + for ( int i = 0; i < varHistory.Count(); i++ ) + { + pInfo->older = i; + + float older_change_time = m_VarHistory[ i ].changetime; + if ( older_change_time == 0.0f ) + break; + + if ( targettime < older_change_time ) + { + pInfo->newer = pInfo->older; + continue; + } + + if ( pInfo->newer == varHistory.InvalidIndex() ) + { + // Have it linear interpolate between the newest 2 entries. + pInfo->newer = pInfo->older; + + // Since the time given is PAST all of our entries, then as long + // as time continues to increase, we'll be returning the same value. + if ( pNoMoreChanges ) + *pNoMoreChanges = 1; + return true; + } + + float newer_change_time = varHistory[ pInfo->newer ].changetime; + float dt = newer_change_time - older_change_time; + if ( dt > 0.0001f ) + { + pInfo->frac = ( targettime - older_change_time ) / ( newer_change_time - older_change_time ); + pInfo->frac = MIN( pInfo->frac, 2.0f ); + + int oldestindex = i+1; + + if ( !(m_fType & INTERPOLATE_LINEAR_ONLY) && varHistory.IsIdxValid(oldestindex) ) + { + pInfo->oldest = oldestindex; + float oldest_change_time = varHistory[ oldestindex ].changetime; + float dt2 = older_change_time - oldest_change_time; + if ( dt2 > 0.0001f ) + { + pInfo->m_bHermite = true; + } + } + + // If pInfo->newer is the most recent entry we have, and all 2 or 3 other + // entries are identical, then we're always going to return the same value + // if currentTime increases. + if ( pNoMoreChanges && pInfo->newer == m_VarHistory.Head() ) + { + if ( COMPARE_HISTORY( pInfo->newer, pInfo->older ) ) + { + if ( !pInfo->m_bHermite || COMPARE_HISTORY( pInfo->newer, pInfo->oldest ) ) + *pNoMoreChanges = 1; + } + } + } + return true; + } + + // Didn't find any, return last entry??? + if ( pInfo->newer != varHistory.InvalidIndex() ) + { + pInfo->older = pInfo->newer; + return true; + } + + + // This is the single-element case + pInfo->newer = pInfo->older; + return (pInfo->older != varHistory.InvalidIndex()); +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::GetInterpolationInfo( float currentTime, int *pNewer, int *pOlder, int *pOldest ) +{ + CInterpolationInfo info; + bool result = GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL ); + + if (pNewer) + *pNewer = (int)info.newer; + + if (pOlder) + *pOlder = (int)info.older; + + if (pOldest) + *pOldest = (int)info.oldest; + + return result; +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::DebugInterpolate( Type *pOut, float currentTime ) +{ + float interpolation_amount = m_InterpolationAmount; + + int noMoreChanges = 0; + + CInterpolationInfo info; + GetInterpolationInfo( &info, currentTime, interpolation_amount, &noMoreChanges ); + + CVarHistory &history = m_VarHistory; + + if ( info.m_bHermite ) + { + // base cast, we have 3 valid sample point + _Interpolate_Hermite( pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] ); + } + else if ( info.newer == info.older ) + { + // This means the server clock got way behind the client clock. Extrapolate the value here based on its + // previous velocity (out to a certain amount). + int realOlder = info.newer+1; + if ( CInterpolationContext::IsExtrapolationAllowed() && + IsValidIndex( realOlder ) && + history[realOlder].changetime != 0.0 && + interpolation_amount > 0.000001f && + CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime ) + { + // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with. + // + // However, we only want to extraploate if the server is choking. We don't want to extrapolate if + // the object legimately stopped moving and the server stopped sending updates for it. + // + // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while. + // The server's update interval should be at least as often as our interpolation amount (otherwise, + // we wouldn't have the ability to interpolate). + // + // So right here, if we see that we haven't gotten any server updates since the last interpolation + // history update to this entity (and since we're in here, we know that we're out of interpolation data), + // then we can assume that the server is choking and decide to extrapolate. + // + // The End + + // Use the velocity here (extrapolate up to 1/4 of a second). + _Extrapolate( pOut, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat() ); + } + else + { + _Interpolate( pOut, info.frac, &history[info.older], &history[info.newer] ); + } + } + else + { + _Interpolate( pOut, info.frac, &history[info.older], &history[info.newer] ); + } +} + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::Interpolate( float currentTime, float interpolation_amount ) +{ + int noMoreChanges = 0; + + CInterpolationInfo info; + if (!GetInterpolationInfo( &info, currentTime, interpolation_amount, &noMoreChanges )) + return noMoreChanges; + + + CVarHistory &history = m_VarHistory; + + if ( m_bDebug ) + { + // "value will hold" means we are either extrapolating, or the samples in GetInterpolationInfo are all the same... In either case there are no more "changes" until we latch a new + // value and we can remove this var from the interpolated var list (bit perf optimization) + Msg( "%s Interpolate at %f%s\n", GetDebugName(), currentTime, noMoreChanges ? " [value will hold]" : "" ); + } + + +#ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT + Type *backupValues = (Type*)_alloca( m_nMaxCount * sizeof(Type) ); + memcpy( backupValues, m_pValue, sizeof( Type ) * m_nMaxCount ); +#endif + + if ( info.m_bHermite ) + { + // base cast, we have 3 valid sample point + _Interpolate_Hermite( m_pValue, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] ); + } + else if ( info.newer == info.older ) + { + // This means the server clock got way behind the client clock. Extrapolate the value here based on its + // previous velocity (out to a certain amount). + int realOlder = info.newer+1; + if ( CInterpolationContext::IsExtrapolationAllowed() && + IsValidIndex( realOlder ) && + history[realOlder].changetime != 0.0 && + interpolation_amount > 0.000001f && + CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime ) + { + // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with. + // + // However, we only want to extraploate if the server is choking. We don't want to extrapolate if + // the object legimately stopped moving and the server stopped sending updates for it. + // + // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while. + // The server's update interval should be at least as often as our interpolation amount (otherwise, + // we wouldn't have the ability to interpolate). + // + // So right here, if we see that we haven't gotten any server updates since the last interpolation + // history update to this entity (and since we're in here, we know that we're out of interpolation data), + // then we can assume that the server is choking and decide to extrapolate. + // + // The End + + // Use the velocity here (extrapolate up to 1/4 of a second). + _Extrapolate( m_pValue, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat() ); + } + else + { + _Interpolate( m_pValue, info.frac, &history[info.older], &history[info.newer] ); + } + } + else + { + _Interpolate( m_pValue, info.frac, &history[info.older], &history[info.newer] ); + } + +#ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT + if ( memcmp( backupValues, m_pValue, sizeof( Type ) * m_nMaxCount ) != 0 ) + { + extern int g_nInterpolatedVarsChanged; + extern bool g_bRestoreInterpolatedVarValues; + + ++g_nInterpolatedVarsChanged; + + // This undoes the work that we do in here so if someone is in the debugger, they + // can find out which variable changed. + if ( g_bRestoreInterpolatedVarValues ) + { + memcpy( m_pValue, backupValues, sizeof( Type ) * m_nMaxCount ); + return noMoreChanges; + } + } +#endif + + // Clear out all entries before the oldest since we should never access them again. + // Usually, Interpolate() calls never go backwards in time, but C_BaseAnimating::BecomeRagdollOnClient for one + // goes slightly back in time + RemoveEntriesPreviousTo( currentTime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED ); + return noMoreChanges; +} + + +template< typename Type, bool IS_ARRAY > +void CInterpolatedVarArrayBase::GetDerivative( Type *pOut, float currentTime ) +{ + CInterpolationInfo info; + if (!GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL )) + return; + + if ( info.m_bHermite ) + { + _Derivative_Hermite( pOut, info.frac, &m_VarHistory[info.oldest], &m_VarHistory[info.older], &m_VarHistory[info.newer] ); + } + else + { + _Derivative_Linear( pOut, &m_VarHistory[info.older], &m_VarHistory[info.newer] ); + } +} + + +template< typename Type, bool IS_ARRAY > +void CInterpolatedVarArrayBase::GetDerivative_SmoothVelocity( Type *pOut, float currentTime ) +{ + CInterpolationInfo info; + if (!GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL )) + return; + + CVarHistory &history = m_VarHistory; + bool bExtrapolate = false; + int realOlder = 0; + + if ( info.m_bHermite ) + { + _Derivative_Hermite_SmoothVelocity( pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] ); + return; + } + else if ( info.newer == info.older && CInterpolationContext::IsExtrapolationAllowed() ) + { + // This means the server clock got way behind the client clock. Extrapolate the value here based on its + // previous velocity (out to a certain amount). + realOlder = info.newer+1; + if ( IsValidIndex( realOlder ) && history[realOlder].changetime != 0.0 ) + { + // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with. + // + // However, we only want to extraploate if the server is choking. We don't want to extrapolate if + // the object legimately stopped moving and the server stopped sending updates for it. + // + // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while. + // The server's update interval should be at least as often as our interpolation amount (otherwise, + // we wouldn't have the ability to interpolate). + // + // So right here, if we see that we haven't gotten any server updates for a whole interpolation + // interval, then we know the server is choking. + // + // The End + if ( m_InterpolationAmount > 0.000001f && + CInterpolationContext::GetLastTimeStamp() <= (currentTime - m_InterpolationAmount) ) + { + bExtrapolate = true; + } + } + } + + if ( bExtrapolate ) + { + // Get the velocity from the last segment. + _Derivative_Linear( pOut, &history[realOlder], &history[info.newer] ); + + // Now ramp it to zero after cl_extrapolate_amount.. + float flDestTime = currentTime - m_InterpolationAmount; + float diff = flDestTime - history[info.newer].changetime; + diff = clamp( diff, 0.f, cl_extrapolate_amount.GetFloat() * 2 ); + if ( diff > cl_extrapolate_amount.GetFloat() ) + { + float scale = 1 - (diff - cl_extrapolate_amount.GetFloat()) / cl_extrapolate_amount.GetFloat(); + for ( int i=0; i < m_nMaxCount; i++ ) + { + pOut[i] *= scale; + } + } + } + else + { + _Derivative_Linear( pOut, &history[info.older], &history[info.newer] ); + } + +} + + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::Interpolate( float currentTime ) +{ + return Interpolate( currentTime, m_InterpolationAmount ); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::Copy( IInterpolatedVar *pInSrc ) +{ + CInterpolatedVarArrayBase *pSrc = dynamic_cast< CInterpolatedVarArrayBase* >( pInSrc ); + + if ( !pSrc || pSrc->m_nMaxCount != m_nMaxCount ) + { + if ( pSrc ) + { + AssertMsg3( false, "pSrc->m_nMaxCount (%i) != m_nMaxCount (%i) for %s.", pSrc->m_nMaxCount, m_nMaxCount, m_pDebugName); + } + else + { + AssertMsg( false, "pSrc was null in CInterpolatedVarArrayBase::Copy."); + } + + return; + } + + Assert( (m_fType & ~EXCLUDE_AUTO_INTERPOLATE) == (pSrc->m_fType & ~EXCLUDE_AUTO_INTERPOLATE) ); + Assert( m_pDebugName == pSrc->GetDebugName() ); + + for ( int i=0; i < m_nMaxCount; i++ ) + { + m_LastNetworkedValue[i] = pSrc->m_LastNetworkedValue[i]; + m_bLooping[i] = pSrc->m_bLooping[i]; + } + + m_LastNetworkedTime = pSrc->m_LastNetworkedTime; + + // Copy the entries. + m_VarHistory.RemoveAll(); + + for ( int i = 0; i < pSrc->m_VarHistory.Count(); i++ ) + { + int newslot = m_VarHistory.AddToTail(); + + CInterpolatedVarEntry *dest = &m_VarHistory[newslot]; + CInterpolatedVarEntry *src = &pSrc->m_VarHistory[i]; + dest->NewEntry( src->GetValue(), m_nMaxCount, src->changetime ); + } +} + +template< typename Type, bool IS_ARRAY > +inline const Type& CInterpolatedVarArrayBase::GetPrev( int iArrayIndex ) const +{ + Assert( m_pValue ); + Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount ); + + if ( m_VarHistory.Count() > 1 ) + { + return m_VarHistory[1].GetValue()[iArrayIndex]; + } + return m_pValue[ iArrayIndex ]; +} + +template< typename Type, bool IS_ARRAY > +inline const Type& CInterpolatedVarArrayBase::GetCurrent( int iArrayIndex ) const +{ + Assert( m_pValue ); + Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount ); + + if ( m_VarHistory.Count() > 0 ) + { + return m_VarHistory[0].GetValue()[iArrayIndex]; + } + return m_pValue[ iArrayIndex ]; +} + +template< typename Type, bool IS_ARRAY > +inline float CInterpolatedVarArrayBase::GetInterval() const +{ + if ( m_VarHistory.Count() > 1 ) + { + return m_VarHistory[0].changetime - m_VarHistory[1].changetime; + } + + return 0.0f; +} + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::IsValidIndex( int i ) +{ + return m_VarHistory.IsValidIndex( i ); +} + +template< typename Type, bool IS_ARRAY > +inline Type *CInterpolatedVarArrayBase::GetHistoryValue( int index, float& changetime, int iArrayIndex ) +{ + Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount ); + if ( m_VarHistory.IsIdxValid(index) ) + { + CInterpolatedVarEntry *entry = &m_VarHistory[ index ]; + changetime = entry->changetime; + return &entry->GetValue()[ iArrayIndex ]; + } + else + { + changetime = 0.0f; + return NULL; + } +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetHistoryValuesForItem( int item, Type& value ) +{ + Assert( item >= 0 && item < m_nMaxCount ); + + for ( int i = 0; i < m_VarHistory.Count(); i++ ) + { + CInterpolatedVarEntry *entry = &m_VarHistory[ i ]; + entry->GetValue()[ item ] = value; + } +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetLooping( bool looping, int iArrayIndex ) +{ + Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount ); + m_bLooping[ iArrayIndex ] = looping; +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetMaxCount( int newmax ) +{ + bool changed = ( newmax != m_nMaxCount ) ? true : false; + + // BUGBUG: Support 0 length properly? + newmax = MAX(1,newmax); + + m_nMaxCount = newmax; + // Wipe everything any time this changes!!! + if ( changed ) + { + delete [] m_bLooping; + delete [] m_LastNetworkedValue; + m_bLooping = new byte[m_nMaxCount]; + m_LastNetworkedValue = new Type[m_nMaxCount]; + memset( m_bLooping, 0, sizeof(byte) * m_nMaxCount); + memset( m_LastNetworkedValue, 0, sizeof(Type) * m_nMaxCount); + + Reset(); + } +} + + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::GetMaxCount() const +{ + return m_nMaxCount; +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Interpolate( Type *out, float frac, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end ) +{ + Assert( start ); + Assert( end ); + + if ( start == end ) + { + // quick exit + for ( int i = 0; i < m_nMaxCount; i++ ) + { + out[i] = end->GetValue()[i]; + Lerp_Clamp( out[i] ); + } + return; + } + + Assert( frac >= 0.0f && frac <= 1.0f ); + + // Note that QAngle has a specialization that will do quaternion interpolation here... + for ( int i = 0; i < m_nMaxCount; i++ ) + { + if ( m_bLooping[ i ] ) + { + out[i] = LoopingLerp( frac, start->GetValue()[i], end->GetValue()[i] ); + } + else + { + out[i] = Lerp( frac, start->GetValue()[i], end->GetValue()[i] ); + } + Lerp_Clamp( out[i] ); + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Extrapolate( + Type *pOut, + CInterpolatedVarEntry *pOld, + CInterpolatedVarEntry *pNew, + float flDestinationTime, + float flMaxExtrapolationAmount + ) +{ + if ( fabs( pOld->changetime - pNew->changetime ) < 0.001f || flDestinationTime <= pNew->changetime ) + { + for ( int i=0; i < m_nMaxCount; i++ ) + pOut[i] = pNew->GetValue()[i]; + } + else + { + float flExtrapolationAmount = MIN( flDestinationTime - pNew->changetime, flMaxExtrapolationAmount ); + + float divisor = 1.0f / (pNew->changetime - pOld->changetime); + for ( int i=0; i < m_nMaxCount; i++ ) + { + pOut[i] = ExtrapolateInterpolatedVarType( pOld->GetValue()[i], pNew->GetValue()[i], divisor, flExtrapolationAmount ); + } + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::TimeFixup2_Hermite( + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry &fixup, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& prev, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& start, + float dt1 + ) +{ + float dt2 = start->changetime - prev->changetime; + + // If times are not of the same interval renormalize the earlier sample to allow for uniform hermite spline interpolation + if ( fabs( dt1 - dt2 ) > 0.0001f && + dt2 > 0.0001f ) + { + // Renormalize + float frac = dt1 / dt2; + + // Fixed interval into past + fixup.changetime = start->changetime - dt1; + + for ( int i = 0; i < m_nMaxCount; i++ ) + { + if ( m_bLooping[i] ) + { + fixup.GetValue()[i] = LoopingLerp( 1-frac, prev->GetValue()[i], start->GetValue()[i] ); + } + else + { + fixup.GetValue()[i] = Lerp( 1-frac, prev->GetValue()[i], start->GetValue()[i] ); + } + } + + // Point previous sample at fixed version + prev = &fixup; + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::TimeFixup_Hermite( + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry &fixup, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& prev, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& start, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& end ) +{ + TimeFixup2_Hermite( fixup, prev, start, end->changetime - start->changetime ); +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Interpolate_Hermite( + Type *out, + float frac, + CInterpolatedVarEntry *prev, + CInterpolatedVarEntry *start, + CInterpolatedVarEntry *end, + bool looping ) +{ + Assert( start ); + Assert( end ); + + // Disable range checks because we can produce weird values here and it's not an error. + // After interpolation, we will clamp the values. + CDisableRangeChecks disableRangeChecks; + + CInterpolatedVarEntry fixup; + fixup.Init(m_nMaxCount); + TimeFixup_Hermite( fixup, prev, start, end ); + + for( int i = 0; i < m_nMaxCount; i++ ) + { + // Note that QAngle has a specialization that will do quaternion interpolation here... + if ( m_bLooping[ i ] ) + { + out[ i ] = LoopingLerp_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] ); + } + else + { + out[ i ] = Lerp_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] ); + } + + // Clamp the output from interpolation. There are edge cases where something like m_flCycle + // can get set to a really high or low value when we set it to zero after a really small + // time interval (the hermite blender will think it's got a really high velocity and + // skyrocket it off into la-la land). + Lerp_Clamp( out[i] ); + } +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Derivative_Hermite( + Type *out, + float frac, + CInterpolatedVarEntry *prev, + CInterpolatedVarEntry *start, + CInterpolatedVarEntry *end ) +{ + Assert( start ); + Assert( end ); + + // Disable range checks because we can produce weird values here and it's not an error. + // After interpolation, we will clamp the values. + CDisableRangeChecks disableRangeChecks; + + CInterpolatedVarEntry fixup; + fixup.value = (Type*)_alloca( sizeof(Type) * m_nMaxCount ); + TimeFixup_Hermite( fixup, prev, start, end ); + + float divisor = 1.0f / (end->changetime - start->changetime); + + for( int i = 0; i < m_nMaxCount; i++ ) + { + Assert( !m_bLooping[ i ] ); + out[i] = Derivative_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] ); + out[i] *= divisor; + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Derivative_Hermite_SmoothVelocity( + Type *out, + float frac, + CInterpolatedVarEntry *b, + CInterpolatedVarEntry *c, + CInterpolatedVarEntry *d ) +{ + CInterpolatedVarEntry fixup; + fixup.Init(m_nMaxCount); + TimeFixup_Hermite( fixup, b, c, d ); + for ( int i=0; i < m_nMaxCount; i++ ) + { + Type prevVel = (c->GetValue()[i] - b->GetValue()[i]) / (c->changetime - b->changetime); + Type curVel = (d->GetValue()[i] - c->GetValue()[i]) / (d->changetime - c->changetime); + out[i] = Lerp( frac, prevVel, curVel ); + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Derivative_Linear( + Type *out, + CInterpolatedVarEntry *start, + CInterpolatedVarEntry *end ) +{ + if ( start == end || fabs( start->changetime - end->changetime ) < 0.0001f ) + { + for( int i = 0; i < m_nMaxCount; i++ ) + { + out[ i ] = start->GetValue()[i] * 0; + } + } + else + { + float divisor = 1.0f / (end->changetime - start->changetime); + for( int i = 0; i < m_nMaxCount; i++ ) + { + out[ i ] = (end->GetValue()[i] - start->GetValue()[i]) * divisor; + } + } +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::ValidOrder() +{ + float newestchangetime = 0.0f; + bool first = true; + for ( int i = 0; i < m_VarHistory.Count(); i++ ) + { + CInterpolatedVarEntry *entry = &m_VarHistory[ i ]; + if ( first ) + { + first = false; + newestchangetime = entry->changetime; + continue; + } + + // They should get older as wel walk backwards + if ( entry->changetime > newestchangetime ) + { + Assert( 0 ); + return false; + } + + newestchangetime = entry->changetime; + } + + return true; +} + +template< typename Type, int COUNT > +class CInterpolatedVarArray : public CInterpolatedVarArrayBase +{ +public: + CInterpolatedVarArray( const char *pDebugName = "no debug name" ) + : CInterpolatedVarArrayBase( pDebugName ) + { + this->SetMaxCount( COUNT ); + } +}; + + +// -------------------------------------------------------------------------------------------------------------- // +// CInterpolatedVar. +// -------------------------------------------------------------------------------------------------------------- // + +template< typename Type > +class CInterpolatedVar : public CInterpolatedVarArrayBase< Type, false > +{ +public: + CInterpolatedVar( const char *pDebugName = NULL ) + : CInterpolatedVarArrayBase< Type, false >(pDebugName) + { + this->SetMaxCount( 1 ); + } +}; + +#include "tier0/memdbgoff.h" + +#endif // INTERPOLATEDVAR_H diff --git a/game/client/ipresence.h b/game/client/ipresence.h new file mode 100644 index 0000000..e61cb31 --- /dev/null +++ b/game/client/ipresence.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Interface for setting Rich Presence contexts and properties. +// +//============================================================================= + +#ifndef IPRESENCE_H +#define IPRESENCE_H +#ifdef _WIN32 +#pragma once +#endif + +//-------------------------------------------------------------------- +// Purpose: Rich Presence interface +//-------------------------------------------------------------------- +class IPresence +{ +public: + virtual void UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync = false ) = 0; + virtual void UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync = false ) = 0; + virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) = 0; + virtual uint GetPresenceID( const char *pIDName ) = 0; + virtual const char *GetPropertyIdString( const uint id ) = 0; + virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) = 0; + + // Stats reporting + virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ) = 0; + virtual void SetStat( uint iPropertyId, int iPropertyValue, int dataType ) = 0; + virtual void UploadStats() = 0; +}; + +extern IPresence *presence; + +#endif // IPRESENCE_H diff --git a/game/client/iprofiling.h b/game/client/iprofiling.h new file mode 100644 index 0000000..76237d1 --- /dev/null +++ b/game/client/iprofiling.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IPROFILING_H ) +#define IPROFILING_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +abstract_class IProfiling +{ +public: + virtual void Create( vgui::VPANEL parent ) = 0; + virtual void Destroy( void ) = 0; +}; + +extern IProfiling *profiling; + +#endif // IPROFILING_H \ No newline at end of file diff --git a/game/client/itextmessage.h b/game/client/itextmessage.h new file mode 100644 index 0000000..6117d50 --- /dev/null +++ b/game/client/itextmessage.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( ITEXTMESSAGE_H ) +#define ITEXTMESSAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui/VGUI.h" +#include "fontabc.h" + +abstract_class ITextMessage +{ +public: + virtual void SetPosition( int x, int y ) = 0; + virtual void AddChar( int r, int g, int b, int a, wchar_t ch ) = 0; + + virtual void GetLength( int *wide, int *tall, const char *string ) = 0; + virtual int GetFontInfo( FONTABC *pABCs, vgui::HFont hFont ) = 0; + + virtual void SetFont( vgui::HFont hCustomFont ) = 0; + virtual void SetDefaultFont( void ) = 0; +}; + +extern ITextMessage *textmessage; + +#endif // ITEXTMESSAGE_H \ No newline at end of file diff --git a/game/client/ivieweffects.h b/game/client/ivieweffects.h new file mode 100644 index 0000000..77b772e --- /dev/null +++ b/game/client/ivieweffects.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IVIEWEFFECTS_H ) +#define IVIEWEFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + +class Vector; +class QAngle; +class bf_read; + +//----------------------------------------------------------------------------- +// Purpose: Apply effects to view origin/angles, etc. Screen fade and shake +//----------------------------------------------------------------------------- +abstract_class IViewEffects +{ +public: + // Initialize subsystem + virtual void Init( void ) = 0; + // Initialize after each level change + virtual void LevelInit( void ) = 0; + // Called each frame to determine the current view fade parameters ( color and alpha ) + virtual void GetFadeParams( unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a, bool *blend ) = 0; + // Apply directscreen shake + virtual void Shake( ScreenShake_t &data ) = 0; + // Apply direct screen fade + virtual void Fade( ScreenFade_t &data ) = 0; + // Clear all permanent fades in our fade list + virtual void ClearPermanentFades( void ) = 0; + // Clear all fades in our fade list + virtual void ClearAllFades( void ) = 0; + // Compute screen shake values for this frame + virtual void CalcShake( void ) = 0; + // Apply those values to the passed in vector(s). + virtual void ApplyShake( Vector& origin, QAngle& angles, float factor ) = 0; + // Save / Restore + virtual void Save( ISave *pSave ) = 0; + virtual void Restore( IRestore *pRestore, bool ) = 0; +}; + +extern IViewEffects *vieweffects; + +#endif // IVIEWEFFECTS_H \ No newline at end of file diff --git a/game/client/iviewrender.h b/game/client/iviewrender.h new file mode 100644 index 0000000..c66061a --- /dev/null +++ b/game/client/iviewrender.h @@ -0,0 +1,145 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// +#if !defined( IVIEWRENDER_H ) +#define IVIEWRENDER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ivrenderview.h" + + +// These are set as it draws reflections, refractions, etc, so certain effects can avoid +// drawing themselves in reflections. +enum DrawFlags_t +{ + DF_RENDER_REFRACTION = 0x1, + DF_RENDER_REFLECTION = 0x2, + + DF_CLIP_Z = 0x4, + DF_CLIP_BELOW = 0x8, + + DF_RENDER_UNDERWATER = 0x10, + DF_RENDER_ABOVEWATER = 0x20, + DF_RENDER_WATER = 0x40, + + DF_SSAO_DEPTH_PASS = 0x100, + DF_WATERHEIGHT = 0x200, + DF_DRAW_SSAO = 0x400, + DF_DRAWSKYBOX = 0x800, + + DF_FUDGE_UP = 0x1000, + + DF_DRAW_ENTITITES = 0x2000, + DF_UNUSED3 = 0x4000, + + DF_UNUSED4 = 0x8000, + + DF_UNUSED5 = 0x10000, + DF_SAVEGAMESCREENSHOT = 0x20000, + DF_CLIP_SKYBOX = 0x40000, + + DF_SHADOW_DEPTH_MAP = 0x100000 // Currently rendering a shadow depth map +}; + + +//----------------------------------------------------------------------------- +// Purpose: View setup and rendering +//----------------------------------------------------------------------------- +class CViewSetup; +class C_BaseEntity; +struct vrect_t; +class C_BaseViewModel; +struct WriteReplayScreenshotParams_t; +class IReplayScreenshotSystem; + +abstract_class IViewRender +{ +public: + // SETUP + // Initialize view renderer + virtual void Init( void ) = 0; + + // Clear any systems between levels + virtual void LevelInit( void ) = 0; + virtual void LevelShutdown( void ) = 0; + + // Shutdown + virtual void Shutdown( void ) = 0; + + // RENDERING + // Called right before simulation. It must setup the view model origins and angles here so + // the correct attachment points can be used during simulation. + virtual void OnRenderStart() = 0; + + // Called to render the entire scene + virtual void Render( vrect_t *rect ) = 0; + + // Called to render just a particular setup ( for timerefresh and envmap creation ) + virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) = 0; + + // What are we currently rendering? Returns a combination of DF_ flags. + virtual int GetDrawFlags() = 0; + + // MISC + // Start and stop pitch drifting logic + virtual void StartPitchDrift( void ) = 0; + virtual void StopPitchDrift( void ) = 0; + + // This can only be called during rendering (while within RenderView). + virtual VPlane* GetFrustum() = 0; + + virtual bool ShouldDrawBrushModels( void ) = 0; + + virtual const CViewSetup *GetPlayerViewSetup( void ) const = 0; + virtual const CViewSetup *GetViewSetup( void ) const = 0; + + virtual void DisableVis( void ) = 0; + + virtual int BuildWorldListsNumber() const = 0; + + virtual void SetCheapWaterStartDistance( float flCheapWaterStartDistance ) = 0; + virtual void SetCheapWaterEndDistance( float flCheapWaterEndDistance ) = 0; + + virtual void GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance ) = 0; + + virtual void DriftPitch (void) = 0; + + virtual void SetScreenOverlayMaterial( IMaterial *pMaterial ) = 0; + virtual IMaterial *GetScreenOverlayMaterial( ) = 0; + + virtual void WriteSaveGameScreenshot( const char *pFilename ) = 0; + virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded = false, bool bWriteVTF = false ) = 0; + + virtual void WriteReplayScreenshot( WriteReplayScreenshotParams_t ¶ms ) = 0; + virtual void UpdateReplayScreenshotCache() = 0; + + // Draws another rendering over the top of the screen + virtual void QueueOverlayRenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) = 0; + + // Returns znear and zfar + virtual float GetZNear() = 0; + virtual float GetZFar() = 0; + + virtual void GetScreenFadeDistances( float *min, float *max ) = 0; + + virtual C_BaseEntity *GetCurrentlyDrawingEntity() = 0; + virtual void SetCurrentlyDrawingEntity( C_BaseEntity *pEnt ) = 0; + + virtual bool UpdateShadowDepthTexture( ITexture *pRenderTarget, ITexture *pDepthTexture, const CViewSetup &shadowView ) = 0; + + virtual void FreezeFrame( float flFreezeTime ) = 0; + + virtual IReplayScreenshotSystem *GetReplayScreenshotSystem() = 0; +}; + +extern IViewRender *view; + +#endif // IVIEWRENDER_H diff --git a/game/client/iviewrender_beams.h b/game/client/iviewrender_beams.h new file mode 100644 index 0000000..9718e3b --- /dev/null +++ b/game/client/iviewrender_beams.h @@ -0,0 +1,171 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( IVIEWRENDER_BEAMS_H ) +#define IVIEWRENDER_BEAMS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +// common to server, too +#include "beam_flags.h" +#include "tempentity.h" + +extern void SetBeamCreationAllowed( bool state ); +extern bool BeamCreationAllowed( void ); + +//----------------------------------------------------------------------------- +// beam flags +//----------------------------------------------------------------------------- + + +class C_Beam; +class Beam_t; + +//----------------------------------------------------------------------------- +// Purpose: Popcorn trail for Beam Follow rendering... +//----------------------------------------------------------------------------- + +struct BeamTrail_t +{ + // NOTE: Don't add user defined fields except after these four fields. + BeamTrail_t* next; + float die; + Vector org; + Vector vel; +}; + +//----------------------------------------------------------------------------- +// Data type for beams. +//----------------------------------------------------------------------------- +struct BeamInfo_t +{ + int m_nType; + + // Entities + C_BaseEntity* m_pStartEnt; + int m_nStartAttachment; + C_BaseEntity* m_pEndEnt; + int m_nEndAttachment; + + // Points + Vector m_vecStart; + Vector m_vecEnd; + + int m_nModelIndex; + const char *m_pszModelName; + + int m_nHaloIndex; + const char *m_pszHaloName; + float m_flHaloScale; + + float m_flLife; + float m_flWidth; + float m_flEndWidth; + float m_flFadeLength; + float m_flAmplitude; + + float m_flBrightness; + float m_flSpeed; + + int m_nStartFrame; + float m_flFrameRate; + + float m_flRed; + float m_flGreen; + float m_flBlue; + + bool m_bRenderable; + + int m_nSegments; + + int m_nFlags; + + // Rings + Vector m_vecCenter; + float m_flStartRadius; + float m_flEndRadius; + + BeamInfo_t() + { + m_nType = TE_BEAMPOINTS; + m_nSegments = -1; + m_pszModelName = NULL; + m_pszHaloName = NULL; + m_nModelIndex = -1; + m_nHaloIndex = -1; + m_bRenderable = true; + m_nFlags = 0; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Declare client .dll beam entity interface +//----------------------------------------------------------------------------- + +abstract_class IViewRenderBeams +{ +public: + virtual void InitBeams( void ) = 0; + virtual void ShutdownBeams( void ) = 0; + virtual void ClearBeams( void ) = 0; + + // Updates the state of the temp ent beams + virtual void UpdateTempEntBeams() = 0; + + virtual void DrawBeam( C_Beam* pbeam, ITraceFilter *pEntityBeamTraceFilter = NULL ) = 0; + virtual void DrawBeam( Beam_t *pbeam ) = 0; + + virtual void KillDeadBeams( CBaseEntity *pEnt ) = 0; + + // New interfaces! + virtual Beam_t *CreateBeamEnts( BeamInfo_t &beamInfo ) = 0; + virtual Beam_t *CreateBeamEntPoint( BeamInfo_t &beamInfo ) = 0; + virtual Beam_t *CreateBeamPoints( BeamInfo_t &beamInfo ) = 0; + virtual Beam_t *CreateBeamRing( BeamInfo_t &beamInfo ) = 0; + virtual Beam_t *CreateBeamRingPoint( BeamInfo_t &beamInfo ) = 0; + virtual Beam_t *CreateBeamCirclePoints( BeamInfo_t &beamInfo ) = 0; + virtual Beam_t *CreateBeamFollow( BeamInfo_t &beamInfo ) = 0; + + virtual void FreeBeam( Beam_t *pBeam ) = 0; + virtual void UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo ) = 0; + + // These will go away! + virtual void CreateBeamEnts( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale, + float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude, + float brightness, float speed, int startFrame, + float framerate, float r, float g, float b, int type = -1 ) = 0; + virtual void CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, const Vector* pEnd, + int modelIndex, int haloIndex, float haloScale, + float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude, + float brightness, float speed, int startFrame, + float framerate, float r, float g, float b ) = 0; + virtual void CreateBeamPoints( Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale, + float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude, + float brightness, float speed, int startFrame, + float framerate, float r, float g, float b ) = 0; + virtual void CreateBeamRing( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale, + float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude, + float brightness, float speed, int startFrame, + float framerate, float r, float g, float b, int flags = 0 ) = 0; + virtual void CreateBeamRingPoint( const Vector& center, float start_radius, float end_radius, int modelIndex, int haloIndex, float haloScale, + float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude, + float brightness, float speed, int startFrame, + float framerate, float r, float g, float b, int flags = 0 ) = 0; + virtual void CreateBeamCirclePoints( int type, Vector& start, Vector& end, + int modelIndex, int haloIndex, float haloScale, float life, float width, + float m_nEndWidth, float m_nFadeLength, float amplitude, float brightness, float speed, + int startFrame, float framerate, float r, float g, float b ) = 0; + virtual void CreateBeamFollow( int startEnt, int modelIndex, int haloIndex, float haloScale, + float life, float width, float m_nEndWidth, float m_nFadeLength, float r, float g, float b, + float brightness ) = 0; +}; + +extern IViewRenderBeams *beams; + +#endif // VIEWRENDER_BEAMS_H \ No newline at end of file diff --git a/game/client/ivmodemanager.h b/game/client/ivmodemanager.h new file mode 100644 index 0000000..69d2799 --- /dev/null +++ b/game/client/ivmodemanager.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IVMODEMANAGER_H ) +#define IVMODEMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +abstract_class IVModeManager +{ +public: + virtual void Init( void ) = 0; + // HL2 will ignore, TF2 will change modes. + virtual void SwitchMode( bool commander, bool force ) = 0; + virtual void LevelInit( const char *newmap ) = 0; + virtual void LevelShutdown( void ) = 0; +}; + +extern IVModeManager *modemanager; + +#endif // IVMODEMANAGER_H \ No newline at end of file diff --git a/game/client/kbutton.h b/game/client/kbutton.h new file mode 100644 index 0000000..c3dc2ab --- /dev/null +++ b/game/client/kbutton.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( KBUTTON_H ) +#define KBUTTON_H +#ifdef _WIN32 +#pragma once +#endif + +struct kbutton_t +{ + // key nums holding it down + int down[ 2 ]; + // low bit is down state + int state; +}; + +#endif // KBUTTON_H \ No newline at end of file diff --git a/game/client/lerp_functions.h b/game/client/lerp_functions.h new file mode 100644 index 0000000..198cb67 --- /dev/null +++ b/game/client/lerp_functions.h @@ -0,0 +1,165 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef LERP_FUNCTIONS_H +#define LERP_FUNCTIONS_H +#ifdef _WIN32 +#pragma once +#endif + + +template +inline T LoopingLerp( float flPercent, T flFrom, T flTo ) +{ + T s = flTo * flPercent + flFrom * (1.0f - flPercent); + return s; +} + +template <> +inline float LoopingLerp( float flPercent, float flFrom, float flTo ) +{ + if ( fabs( flTo - flFrom ) >= 0.5f ) + { + if (flFrom < flTo) + flFrom += 1.0f; + else + flTo += 1.0f; + } + + float s = flTo * flPercent + flFrom * (1.0f - flPercent); + + s = s - (int)(s); + if (s < 0.0f) + s = s + 1.0f; + + return s; +} + +template +inline T Lerp_Hermite( float t, const T& p0, const T& p1, const T& p2 ) +{ + T d1 = p1 - p0; + T d2 = p2 - p1; + + T output; + float tSqr = t*t; + float tCube = t*tSqr; + + output = p1 * (2*tCube-3*tSqr+1); + output += p2 * (-2*tCube+3*tSqr); + output += d1 * (tCube-2*tSqr+t); + output += d2 * (tCube-tSqr); + + return output; +} + + +template +inline T Derivative_Hermite( float t, const T& p0, const T& p1, const T& p2 ) +{ + T d1 = p1 - p0; + T d2 = p2 - p1; + + T output; + float tSqr = t*t; + + output = p1 * (6*tSqr - 6*t); + output += p2 * (-6*tSqr + 6*t); + output += d1 * (3*tSqr - 4*t + 1); + output += d2 * (3*tSqr - 2*t); + + return output; +} + + +inline void Lerp_Clamp( int val ) +{ +} + +inline void Lerp_Clamp( float val ) +{ +} + +inline void Lerp_Clamp( const Vector &val ) +{ +} + +inline void Lerp_Clamp( const QAngle &val ) +{ +} + + +// If we have a range checked var, then we can clamp to its limits. +template< class T, int minValue, int maxValue, int startValue > +inline void Lerp_Clamp( CRangeCheckedVar &val ) +{ + val.Clamp(); +} + + +template<> +inline QAngle Lerp_Hermite( float t, const QAngle& p0, const QAngle& p1, const QAngle& p2 ) +{ + // Can't do hermite with QAngles, get discontinuities, just do a regular interpolation + return Lerp( t, p1, p2 ); +} + +template +inline T LoopingLerp_Hermite( float t, T p0, T p1, T p2 ) +{ + return Lerp_Hermite( t, p0, p1, p2 ); +} + +template <> +inline float LoopingLerp_Hermite( float t, float p0, float p1, float p2 ) +{ + if ( fabs( p1 - p0 ) > 0.5f ) + { + if ( p0 < p1 ) + p0 += 1.0f; + else + p1 += 1.0f; + } + + if ( fabs( p2 - p1 ) > 0.5f ) + { + if ( p1 < p2 ) + { + p1 += 1.0f; + + // see if we need to fix up p0 + // important for vars that are decreasing from p0->p1->p2 where + // p1 is fixed up relative to p2, eg p0 = 0.2, p1 = 0.1, p2 = 0.9 + if ( abs( p1 - p0 ) > 0.5 ) + { + if ( p0 < p1 ) + p0 += 1.0f; + else + p1 += 1.0f; + } + } + else + { + p2 += 1.0f; + } + } + + float s = Lerp_Hermite( t, p0, p1, p2 ); + + s = s - (int)(s); + if (s < 0.0f) + { + s = s + 1.0f; + } + + return s; +} + + +// NOTE: C_AnimationLayer has its own versions of these functions in animationlayer.h. + + +#endif // LERP_FUNCTIONS_H diff --git a/game/client/menu.h b/game/client/menu.h new file mode 100644 index 0000000..0b3ae9a --- /dev/null +++ b/game/client/menu.h @@ -0,0 +1,89 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_MENU_H +#define HUD_MENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "hudelement.h" +#include + +#define MENU_SELECTION_TIMEOUT 5.0f + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudMenu : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudMenu, vgui::Panel ); +public: + CHudMenu( const char *pElementName ); + void Init( void ); + void VidInit( void ); + void Reset( void ); + virtual bool ShouldDraw( void ); + void MsgFunc_ShowMenu( bf_read &msg ); + void HideMenu( void ); + void ShowMenu( const char * menuName, int keySlot ); + void ShowMenu_KeyValueItems( KeyValues *pKV ); + + bool IsMenuOpen( void ); + void SelectMenuItem( int menu_item ); + +private: + virtual void OnThink(); + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +private: + void ProcessText( void ); + + void PaintString( const wchar_t *text, int textlen, vgui::HFont& font, int x, int y ); + + struct ProcessedLine + { + int menuitem; // -1 for just text + int startchar; + int length; + int pixels; + int height; + }; + + CUtlVector< ProcessedLine > m_Processed; + + int m_nMaxPixels; + int m_nHeight; + + bool m_bMenuDisplayed; + int m_bitsValidSlots; + float m_flShutoffTime; + int m_fWaitingForMore; + int m_nSelectedItem; + bool m_bMenuTakesInput; + + float m_flSelectionTime; + + CPanelAnimationVar( float, m_flOpenCloseTime, "OpenCloseTime", "1" ); + + CPanelAnimationVar( float, m_flBlur, "Blur", "0" ); + CPanelAnimationVar( float, m_flTextScan, "TextScane", "1" ); + + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255.0" ); + CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255.0" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "MenuTextFont" ); + CPanelAnimationVar( vgui::HFont, m_hItemFont, "ItemFont", "MenuItemFont" ); + CPanelAnimationVar( vgui::HFont, m_hItemFontPulsing, "ItemFontPulsing", "MenuItemFontPulsing" ); + + CPanelAnimationVar( Color, m_MenuColor, "MenuColor", "MenuColor" ); + CPanelAnimationVar( Color, m_ItemColor, "MenuItemColor", "ItemColor" ); + CPanelAnimationVar( Color, m_BoxColor, "MenuBoxColor", "MenuBoxBg" ); +}; + +#endif // HUD_MENU_H diff --git a/game/client/movehelper_client.h b/game/client/movehelper_client.h new file mode 100644 index 0000000..f711b11 --- /dev/null +++ b/game/client/movehelper_client.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MOVEHELPER_CLIENT_H +#define MOVEHELPER_CLIENT_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "imovehelper.h" + +#endif // MOVEHELPER_CLIENT_H diff --git a/game/client/mp3player.h b/game/client/mp3player.h new file mode 100644 index 0000000..aaaee91 --- /dev/null +++ b/game/client/mp3player.h @@ -0,0 +1,385 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef MP3PLAYER_H +#define MP3PLAYER_H + +#ifdef _WIN32 +#pragma once +#endif + +// +// The MP3 player has a menu button for setting options, opening files, etc. +// it has a tree control to show the high level categories +// It has a property sheet to switch between the file view and the current playlist +// it has a list view to show the actual files in either view + +#include "vgui_controls/Frame.h" +#include "filesystem.h" +#include "utlsymbol.h" + +// Forward declarations +namespace vgui +{ + class MenuButton; + class Button; + class Slider; + class IScheme; + class FileOpenDialog; + class DirectorySelectDialog; +}; + +class CMP3FileSheet; +class CMP3TreeControl; +class CMP3SongProgress; + +//----------------------------------------------------------------------------- +// Purpose: This is the core MP3 file element +//----------------------------------------------------------------------------- +struct MP3File_t +{ + enum + { + FLAG_UNKNOWN = 0, + // File came from steam cache/game data, rather than the user's "My Music" folder... + FLAG_FROMGAME, + // File came from directory outside of game data directory + FLAG_FROMFS + }; + + MP3File_t() + { + filename = 0; + playbackfilename = 0; + flags = FLAG_UNKNOWN; + dirnum = -1; + shortname = UTL_INVAL_SYMBOL; + } + + int flags; + FileNameHandle_t filename; + FileNameHandle_t playbackfilename; // in case we had to make a local copy somewhere else... + CUtlSymbol shortname; + int dirnum; +}; + +//----------------------------------------------------------------------------- +// Purpose: A directory has a name, 0 or more subdirectories and 0 or more mp3 files in it +//----------------------------------------------------------------------------- +struct MP3Dir_t +{ + MP3Dir_t() : + m_DirName( UTL_INVAL_SYMBOL ), + m_FullDirPath( UTL_INVAL_SYMBOL ) + { + } + + ~MP3Dir_t() + { + DeleteSubdirectories(); + } + + void DeleteSubdirectories() + { + int i, c; + + c = m_Subdirectories.Count(); + for ( i = c - 1; i >= 0 ; --i ) + { + delete m_Subdirectories[ i ]; + } + m_Subdirectories.RemoveAll(); + } + + MP3Dir_t( const MP3Dir_t& src ) + { + m_DirName = src.m_DirName; + m_FullDirPath = src.m_FullDirPath; + + int i, c; + + c = src.m_Subdirectories.Count(); + for ( i = 0; i < c; ++i ) + { + MP3Dir_t *subCopy = new MP3Dir_t( *src.m_Subdirectories[ i ] ); + m_Subdirectories.AddToTail( subCopy ); + } + + c = src.m_FilesInDirectory.Count(); + for ( i = 0; i < c; ++i ) + { + m_FilesInDirectory.AddToTail( src.m_FilesInDirectory[ i ] ); + } + } + + MP3Dir_t &operator =( const MP3Dir_t& src ) + { + if ( this == &src ) + { + return *this; + } + + m_DirName = src.m_DirName; + m_FullDirPath = src.m_FullDirPath; + + DeleteSubdirectories(); + + m_FilesInDirectory.RemoveAll(); + + int i, c; + + c = src.m_Subdirectories.Count(); + for ( i = 0; i < c; ++i ) + { + // make a copy + MP3Dir_t *subCopy = new MP3Dir_t( *src.m_Subdirectories[ i ] ); + m_Subdirectories.AddToTail( subCopy ); + } + + c = src.m_FilesInDirectory.Count(); + for ( i = 0; i < c; ++i ) + { + m_FilesInDirectory.AddToTail( src.m_FilesInDirectory[ i ] ); + } + + return *this; + } + + void AddSubDirectory( MP3Dir_t *sub ) + { + m_Subdirectories.AddToTail( sub ); + } + + CUtlSymbol m_DirName; // "artist" + CUtlSymbol m_FullDirPath; // "artist/album + CUtlVector< MP3Dir_t * > m_Subdirectories; + CUtlVector< int > m_FilesInDirectory; +}; + +//----------------------------------------------------------------------------- +// Purpose: A sound directory is a root directory which is recursed looking for .mp3 +// We assume that the folders under the sound directory are configured as artist/album/filename.mp3... +//----------------------------------------------------------------------------- +struct SoundDirectory_t +{ + explicit SoundDirectory_t( int index ) : + m_nIndex( index ), + m_Root( UTL_INVAL_SYMBOL ), + m_pTree( 0 ), + m_bGameSound( false ) + { + } + + ~SoundDirectory_t() + { + delete m_pTree; + } + + void SetTree( MP3Dir_t *tree ) + { + if ( m_pTree ) + { + delete m_pTree; + } + m_pTree = tree; + } + + int GetIndex() const { return m_nIndex; } + + int m_nIndex; + CUtlSymbol m_Root; + MP3Dir_t *m_pTree; + bool m_bGameSound; +}; + +//----------------------------------------------------------------------------- +// Purpose: A VGui based .mp3 player +//----------------------------------------------------------------------------- +class CMP3Player : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CMP3Player, vgui::Frame ); + +public: + + // Construction + CMP3Player( vgui::VPANEL parent, char const *panelName ); + ~CMP3Player(); + + virtual void SetVisible( bool ); + + // Lookup data + MP3File_t *GetSongInfo( int songIndex ); + + // Static singleton accessor + static CMP3Player *GetMP3Player(); + + void AddToPlayList( int songIndex, bool playNow ); + void RemoveFromPlayList( int songIndex ); + + void ClearPlayList(); + void OnLoadPlayList(); + void OnSavePlayList(); + void OnSavePlayListAs(); + + void SetPlayListSong( int listIndex ); + + typedef enum + { + SONG_FROM_UNKNOWN = 0, + SONG_FROM_TREE, + SONG_FROM_FILELIST, + SONG_FROM_PLAYLIST + } SongListSource_t; + + void SelectedSongs( SongListSource_t from, CUtlVector< int >& songIndexList ); + + void EnableAutoAdvance( bool state ); + +protected: + virtual void OnCommand( char const *cmd ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnTick(); + + MESSAGE_FUNC( OnTreeViewItemSelected, "TreeViewItemSelected" ); + MESSAGE_FUNC( OnSliderMoved, "SliderMoved" ); + + void PopulateTree(); + void PopulateLists(); + void RecursiveAddToTree( MP3Dir_t *current, int parentIndex ); + void DeleteSoundDirectories(); + // Leave root objects, clear all subdirs + void WipeSoundDirectories(); + + // Remove the _mp3/a45ef65a.mp3 style temp sounds + void RemoveTempSounds(); + + void SplitFile( CUtlVector< CUtlSymbol >& splitList, char const *relative ); + int AddSplitFileToDirectoryTree_R( int songIndex, MP3Dir_t *parent, CUtlVector< CUtlSymbol >& splitList, int level ); + + MP3Dir_t *FindOrAddSubdirectory( MP3Dir_t *parent, char const *dirname ); + + int AddFileToDirectoryTree( SoundDirectory_t *dir, char const *relative ); + void RecursiveFindMP3Files( SoundDirectory_t *root, char const *current, char const *pathID ); + + int AddSong( char const *relative, int dirnum ); + void RemoveFSSongs(); // Remove all non-built-in .mp3s + int FindSong( char const *relative ); + + void PlaySong( int songIndex, float skipTime = 0.0f ); + void GetLocalCopyOfSong( const MP3File_t &mp3, char *outsong, size_t outlen ); + float GetMP3Duration( char const *songname ); + void OnNextTrack(); + void OnPrevTrack(); + + void OnPlay(); + void OnStop(); + void OnChangeVolume( float newVol ); + + void AddGameSounds( bool recurse ); + SoundDirectory_t *AddSoundDirectory( char const *fullpath, bool recurse ); + int FindSoundDirectory( char const *fullpath ); + + bool RestoreDb( char const *filename ); + void SaveDb( char const *filename ); + + void SaveDbFile( int level, CUtlBuffer& buf, MP3File_t *file, int filenumber ); + void FlattenDirectoryFileList_R( MP3Dir_t *dir, CUtlVector< int >& list ); + void SaveDbDirectory( int level, CUtlBuffer& buf, SoundDirectory_t *sd ); + + void RestoreSongs( KeyValues *songs ); + void RestoreDirectories( KeyValues *dirs ); + void RestoreDirectory( KeyValues *dir, SoundDirectory_t *sd ); + + void LoadPlayList( char const *filename ); + void SavePlayList( char const *filename ); + + void SetMostRecentPlayList( char const *filename ); + + void SaveSettings(); + void LoadSettings(); + + // Refresh all directories, built-in sounds + void OnRefresh(); + void OnSave(); + + MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); + void ShowFileOpenDialog( bool saving ); + MESSAGE_FUNC_PARAMS( OnDirectorySelected, "DirectorySelected", params ); + void ShowDirectorySelectDialog(); + + void GoToNextSong( int skip ); + +// Data +private: + +// UI elements + vgui::MenuButton *m_pOptions; + CMP3TreeControl *m_pTree; + CMP3FileSheet *m_pFileSheet; + vgui::Label *m_pCurrentSong; + vgui::Label *m_pDuration; + CMP3SongProgress *m_pSongProgress; + vgui::Button *m_pPlay; + vgui::Button *m_pStop; + vgui::Button *m_pNext, *m_pPrev; // moving between tracks + vgui::CheckButton *m_pMute; + vgui::CheckButton *m_pShuffle; + vgui::Slider *m_pVolume; + +// Raw list of all known files + CUtlVector< MP3File_t > m_Files; + int m_nFilesAdded; +// Indices into m_Files for currently playing songs + CUtlVector< int > m_PlayList; +// Where in the list we are... + int m_nCurrentPlaylistSong; + CUtlSymbol m_PlayListFileName; + + int m_nCurrentFile; +// Flag for one-time init + bool m_bFirstTime; + int m_nCurrentSong; + FileNameHandle_t m_LastSong; + float m_flCurrentVolume; + bool m_bMuted; + +// Currently playing a song? + bool m_bPlaying; + int m_nSongGuid; +// Song start time + float m_SongStart; +// Estimated song diration + float m_flSongDuration; +// For the UI + int m_nSongMinutes; + int m_nSongSeconds; + +// List of all added directories + CUtlVector< SoundDirectory_t * > m_SoundDirectories; + +// Selection set + CUtlVector< int > m_SelectedSongs; + SongListSource_t m_SelectionFrom; + +// Is database dirty? + bool m_bDirty; +// Are settings dirty? + bool m_bSettingsDirty; + +// File dialog + vgui::DHANDLE< vgui::FileOpenDialog > m_hSaveLoadPlaylist; +// Type of dialog + bool m_bSavingFile; + +// Directory selection dialog + vgui::DHANDLE< vgui::DirectorySelectDialog > m_hDirectorySelect; + + bool m_bEnableAutoAdvance; +}; + +#endif // !MP3PLAYER_H \ No newline at end of file diff --git a/game/client/mumble.h b/game/client/mumble.h new file mode 100644 index 0000000..114353b --- /dev/null +++ b/game/client/mumble.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains an interface to enable positional audio support in Mumble +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef MUMBLE_H +#define MUMBLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include "GameEventListener.h" + +class CMumbleSystem : public CBaseGameSystemPerFrame, public CGameEventListener +{ +public: + // Methods of IGameSystem + virtual bool Init(); + virtual void LevelInitPostEntity(); + virtual void LevelShutdownPreEntity(); + virtual void PostRender(); + + // Methods of IGameSystem + virtual void FireGameEvent( IGameEvent *event ); + +private: + char m_szSteamIDCurrentServer[32]; + int m_cubSteamIDCurrentServer; + bool m_bHasSetPlayerUniqueId; + int m_nTeamSetInUniqueId; +}; + +IGameSystem *MumbleSystem(); + +#endif // MUMBLE_H \ No newline at end of file diff --git a/game/client/networkstringtable_clientdll.h b/game/client/networkstringtable_clientdll.h new file mode 100644 index 0000000..006817c --- /dev/null +++ b/game/client/networkstringtable_clientdll.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef NETWORKSTRINGTABLE_CLIENTDLL_H +#define NETWORKSTRINGTABLE_CLIENTDLL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkstringtabledefs.h" + +extern INetworkStringTableContainer *networkstringtable; + +// String tables used by the client DLL +// (see InstallStringTableCallback for where they're initialized) +extern INetworkStringTable *g_StringTableVguiScreen; +extern INetworkStringTable *g_StringTableEffectDispatch; +extern INetworkStringTable *g_StringTableMaterials; +extern INetworkStringTable *g_pStringTableInfoPanel; +extern INetworkStringTable *g_pStringTableClientSideChoreoScenes; +extern INetworkStringTable *g_pStringTableServerMapCycle; + +#ifdef TF_CLIENT_DLL +extern INetworkStringTable *g_pStringTableServerPopFiles; +extern INetworkStringTable *g_pStringTableServerMapCycleMvM; +#endif + +#endif // NETWORKSTRINGTABLE_CLIENTDLL_H diff --git a/game/client/panelmetaclassmgr.h b/game/client/panelmetaclassmgr.h new file mode 100644 index 0000000..a1f938e --- /dev/null +++ b/game/client/panelmetaclassmgr.h @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A panel "metaclass" is a name given to a particular type of +// panel with particular instance data. Such panels tend to be dynamically +// added and removed from their parent panels. +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( PANELMETACLASSMGR_H ) +#define PANELMETACLASSMGR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "basetypes.h" +#include + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class KeyValues; +class Color; + +namespace vgui +{ + class Panel; +} + + +//----------------------------------------------------------------------------- +// Class factory interface for metaclasses +//----------------------------------------------------------------------------- +abstract_class IPanelFactory +{ +public: + // Creation, destruction methods + virtual vgui::Panel *Create( const char *pMetaClassName, KeyValues* pKeyValues, void *pInitData, vgui::Panel *pParent ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Singleton class responsible for managing vgui panel metaclasses +// A metaclass is simply an association of panel implementation class with +// various initialization data +//----------------------------------------------------------------------------- +abstract_class IPanelMetaClassMgr +{ +public: + // Call this to load up a file containing metaclass definitions + virtual void LoadMetaClassDefinitionFile( const char *pFileName ) = 0; + + // Call this to install a new panel type + // MetaClasses will refer to the panel type to create along with + // various initialization data + virtual void InstallPanelType( const char *pPanelName, IPanelFactory *pFactory ) = 0; + + // Creates a metaclass panel with the specified parent panel. + // Chain name is used as a filter of the metaclass data; if specified, + // it recursively iterates through the keyvalue sections and calls + // chainKeyValue on sections whose name matches the chain name + virtual vgui::Panel *CreatePanelMetaClass( const char *pMetaClassType, + int sortorder, void *pInitData, vgui::Panel *pParent, const char *pChainName = NULL ) = 0; + + // removes a particular panel meta class + virtual void DestroyPanelMetaClass( vgui::Panel *pPanel ) = 0; + +protected: + // Don't delete me! + virtual ~IPanelMetaClassMgr() {} +}; + + +//----------------------------------------------------------------------------- +// Returns the panel meta class manager +//----------------------------------------------------------------------------- +IPanelMetaClassMgr *PanelMetaClassMgr(); + + +//----------------------------------------------------------------------------- +// Helper class for simple construction of planel class factories +// This class is expected to be a singleton +// Note the panel must have a constructor of the following form: +// CPanel( vgui::Panel* ); +// and it must have the following member function: +// bool CPanel::Init( KeyValues* pInitData ) +// which returns true if the panel initialized successfully +//----------------------------------------------------------------------------- + +#include "tier0/memdbgon.h" + +template< class CPanel, class CInitData > +class CPanelFactory : public IPanelFactory +{ +public: + CPanelFactory( const char *pTypeName ) + { + // Hook us up baby + Assert( pTypeName ); + PanelMetaClassMgr()->InstallPanelType( pTypeName, this ); + } + + // Creation, destruction methods + virtual vgui::Panel *Create( const char *pMetaClassName, KeyValues* pKeyValues, void *pVoidInitData, vgui::Panel *pParent ) + { + // NOTE: make sure this matches the panel allocation pattern; + // it will break if panels are deleted differently + CPanel* pPanel = new CPanel( pParent, pMetaClassName ); + if (pPanel) + { + // Set parent before Init; it may be needed there... + CInitData* pInitData = (CInitData*)(pVoidInitData); + if (!pPanel->Init( pKeyValues, pInitData )) + { + delete pPanel; + pPanel = NULL; + } + } + return pPanel; + } +}; + +#include "tier0/memdbgoff.h" + +//----------------------------------------------------------------------------- +// Helper macro to make panel factories one line of code. Use like this: +// DECLARE_PANEL_FACTORY( CEntityImagePanel, CInitData, "image" ); +// The type string is used in a panel script file to specify the type. +// CInitData is the type of the data to pass to the init function +//----------------------------------------------------------------------------- +#define DECLARE_PANEL_FACTORY( _PanelClass, _InitData, _nameString ) \ + CPanelFactory< _PanelClass, _InitData > g_ ## _PanelClass ## Factory( _nameString ) + + + +//----------------------------------------------------------------------------- +// Helper class to make meta class panels +//----------------------------------------------------------------------------- +class CPanelWrapper +{ +public: + CPanelWrapper(); + ~CPanelWrapper(); + void Activate( char const* pMetaClassName, vgui::Panel *pParent, int sortorder, void *pVoidInitData ); + void Deactivate( void ); + vgui::Panel *GetPanel( ); + +private: + vgui::Panel *m_pPanel; +}; + + +//----------------------------------------------------------------------------- +// Macros for help with simple registration of panel metaclass +// Put DECLARE_METACLASS_PANEL() in your class definition +// and CONSTRUCT_METACLASS_PANEL() in your class constructor +//----------------------------------------------------------------------------- +#define DECLARE_METACLASS_PANEL( _memberName ) CPanelWrapper _memberName +#define CONSTRUCT_METACLASS_PANEL( _memberName, _metaClassName, _parentPanel, _sortorder, _initData ) \ + _memberName.Activate( _metaClassName, _parentPanel, _sortorder, _initData ) +#define DESTRUCT_METACLASS_PANEL( _memberName ) \ + _memberName.Deactivate() + + +//----------------------------------------------------------------------------- +// Helper KeyValues parsing methods +//----------------------------------------------------------------------------- +bool ParseRGBA( KeyValues* pValues, const char* pFieldName, int& r, int& g, int& b, int& a ); +bool ParseRGBA( KeyValues* pValues, const char* pFieldName, Color& c ); +bool ParseCoord( KeyValues* pValues, const char* pFieldName, int& x, int& y ); +bool ParseRect( KeyValues* pValues, const char* pFieldName, int& x, int& y, int& w, int& h ); + + +/* FIXME: Why do we have KeyValues too!?!??! Bleah +bool ParseRGBA( KeyValues *pValues, const char* pFieldName, int& r, int& g, int& b, int& a ); +bool ParseRGBA( KeyValues* pValues, const char* pFieldName, vgui::Color& c ); */ + +#endif // PANELMETACLASSMGR_H \ No newline at end of file diff --git a/game/client/particle_collision.h b/game/client/particle_collision.h new file mode 100644 index 0000000..159a7a3 --- /dev/null +++ b/game/client/particle_collision.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined( PARTICLE_COLLISION_H ) +#define PARTICLE_COLLISION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particles_simple.h" +#include "particlemgr.h" + +#define MAX_COLLISION_PLANES 6 + +// +// CBaseSimpleCollision +// + +class CBaseSimpleCollision +{ +public: + + CBaseSimpleCollision( void ); + + static CBaseSimpleCollision *Create( void ) { return new CBaseSimpleCollision; } + + virtual void Setup( const Vector &origin, float speed, float gravity ); + virtual void TraceLine( const Vector &start, const Vector &end, trace_t *pTrace, bool coarse = true ); + + void ClearActivePlanes( void ); + +protected: + + virtual void TestForPlane( const Vector &start, const Vector &dir, float speed, float gravity ); + virtual void ConsiderPlane( cplane_t *plane ); + + VPlane m_collisionPlanes[MAX_COLLISION_PLANES]; + int m_nActivePlanes; +}; + +// +// CParticleCollision +// + +class CParticleCollision : public CBaseSimpleCollision +{ +public: + + CParticleCollision( void ); + + static CParticleCollision *Create( void ) { return new CParticleCollision; } + + virtual void Setup( const Vector &origin, const Vector *dir, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen ); + virtual bool MoveParticle( Vector &origin, Vector &velocity, float *rollDelta, float timeDelta, trace_t *pTrace ); + + void SetGravity( float gravity ) { m_flGravity = gravity; } + void SetCollisionDampen( float dampen ) { m_flCollisionDampen = dampen; } + void SetAngularCollisionDampen( float dampen ) { m_flAngularCollisionDampen = dampen;} + +protected: + + float m_flGravity; + float m_flCollisionDampen; + float m_flAngularCollisionDampen; +}; + +#endif //PARTICLE_COLLISION_H \ No newline at end of file diff --git a/game/client/particle_iterators.h b/game/client/particle_iterators.h new file mode 100644 index 0000000..f38e4c4 --- /dev/null +++ b/game/client/particle_iterators.h @@ -0,0 +1,270 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side CTFTeam class +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PARTICLE_ITERATORS_H +#define PARTICLE_ITERATORS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "materialsystem/imesh.h" +#include "particledraw.h" + + +#define NUM_PARTICLES_PER_BATCH 200 +#ifndef _XBOX +#define MAX_TOTAL_PARTICLES 2048 // Max particles in the world +#else +#define MAX_TOTAL_PARTICLES 1024 +#endif + + +// +// Iterate the particles like this: +// +// Particle *pCur = pIterator->GetFirst(); +// while ( pCur ) +// { +// ... render the particle here and figure out the sort key and position +// pCur = pIterator->GetNext( sortKey, pCur->m_Pos ); +// } +// +class CParticleRenderIterator +{ +friend class CParticleMgr; +friend class CParticleEffectBinding; +public: + CParticleRenderIterator(); + + // The sort key is used to sort the particles incrementally as they're rendered. + // They only get sorted in the main rendered view (ie: not in reflections or monitors). + // These return const because you should only modify particles during their simulation. + const Particle* GetFirst(); + const Particle* GetNext( float sortKey ); + + // Use this to render. This can return NULL, in which case you shouldn't render. + // This being NULL is a carryover from when particles rendered and simulated together and + // it should GO AWAY SOON! + ParticleDraw* GetParticleDraw() const; + + +private: + + void TestFlushBatch(); + + +private: + // Set by CParticleMgr. + CParticleEffectBinding *m_pEffectBinding; + CEffectMaterial *m_pMaterial; + ParticleDraw *m_pParticleDraw; + CMeshBuilder *m_pMeshBuilder; + IMesh *m_pMesh; + bool m_bBucketSort; + + // Output after rendering. + float m_MinZ; + float m_MaxZ; + float m_zCoords[MAX_TOTAL_PARTICLES]; + int m_nZCoords; + + Particle *m_pCur; + bool m_bGotFirst; + float m_flPrevZ; + int m_nParticlesInCurrentBatch; +}; + + +// +// Iterate the particles like this: +// +// Particle *pCur = pIterator->GetFirst(); +// while ( pCur ) +// { +// ... simulate here.. call pIterator->RemoveParticle if you want the particle to go away +// pCur = pIterator->GetNext(); +// } +// +class CParticleSimulateIterator +{ +friend class CParticleMgr; +friend class CParticleEffectBinding; +public: + CParticleSimulateIterator(); + + // Iterate through the particles, simulate them, and remove them if necessary. + Particle* GetFirst(); + Particle* GetNext(); + float GetTimeDelta() const; + + void RemoveParticle( Particle *pParticle ); + void RemoveAllParticles(); + +private: + CParticleEffectBinding *m_pEffectBinding; + CEffectMaterial *m_pMaterial; + float m_flTimeDelta; + + bool m_bGotFirst; + Particle *m_pNextParticle; +}; + + +// -------------------------------------------------------------------------------------------------------- // +// CParticleRenderIterator inlines +// -------------------------------------------------------------------------------------------------------- // + +inline CParticleRenderIterator::CParticleRenderIterator() +{ + m_pCur = NULL; + m_bGotFirst = false; + m_flPrevZ = 0; + m_nParticlesInCurrentBatch = 0; + m_MinZ = 1e24; + m_MaxZ = -1e24; + m_nZCoords = 0; +} + +inline const Particle* CParticleRenderIterator::GetFirst() +{ + Assert( !m_bGotFirst ); + m_bGotFirst = true; + + m_pCur = m_pMaterial->m_Particles.m_pNext; + if ( m_pCur == &m_pMaterial->m_Particles ) + return NULL; + + m_pParticleDraw->m_pSubTexture = m_pCur->m_pSubTexture; + return m_pCur; +} + +inline void CParticleRenderIterator::TestFlushBatch() +{ + ++m_nParticlesInCurrentBatch; + if( m_nParticlesInCurrentBatch >= NUM_PARTICLES_PER_BATCH ) + { + m_pMeshBuilder->End( false, true ); + m_pMeshBuilder->Begin( m_pMesh, MATERIAL_QUADS, NUM_PARTICLES_PER_BATCH * 4 ); + + m_nParticlesInCurrentBatch = 0; + } +} + +inline const Particle* CParticleRenderIterator::GetNext( float sortKey ) +{ + Assert( m_bGotFirst ); + Assert( m_pCur ); + + TestFlushBatch(); + + Particle *pNext = m_pCur->m_pNext; + + // Update the incremental sort. + if( m_bBucketSort ) + { + m_MinZ = MIN( sortKey, m_MinZ ); + m_MaxZ = MAX( sortKey, m_MaxZ ); + + m_zCoords[m_nZCoords] = sortKey; + ++m_nZCoords; + } + else + { + // Swap with the previous particle (incremental sort)? + if( m_pCur != m_pMaterial->m_Particles.m_pNext && m_flPrevZ > sortKey ) + { + SwapParticles( m_pCur->m_pPrev, m_pCur ); + } + else + { + m_flPrevZ = sortKey; + } + } + + m_pCur = pNext; + if ( m_pCur == &m_pMaterial->m_Particles ) + return NULL; + + m_pParticleDraw->m_pSubTexture = m_pCur->m_pSubTexture; + return m_pCur; +} + +inline ParticleDraw* CParticleRenderIterator::GetParticleDraw() const +{ + return m_pParticleDraw; +} + + +// -------------------------------------------------------------------------------------------------------- // +// CParticleSimulateIterator inlines +// -------------------------------------------------------------------------------------------------------- // + +inline CParticleSimulateIterator::CParticleSimulateIterator() +{ + m_pNextParticle = NULL; +#ifdef _DEBUG + m_bGotFirst = false; +#endif +} + +inline Particle* CParticleSimulateIterator::GetFirst() +{ +#ifdef _DEBUG + // Make sure they're either starting out fresh or that the previous guy iterated through all the particles. + if ( m_bGotFirst ) + { + Assert( m_pNextParticle == &m_pMaterial->m_Particles ); + } +#endif + + Particle *pRet = m_pMaterial->m_Particles.m_pNext; + if ( pRet == &m_pMaterial->m_Particles ) + return NULL; + +#ifdef _DEBUG + m_bGotFirst = true; +#endif + + m_pNextParticle = pRet->m_pNext; + return pRet; +} + +inline Particle* CParticleSimulateIterator::GetNext() +{ + Particle *pRet = m_pNextParticle; + + if ( pRet == &m_pMaterial->m_Particles ) + return NULL; + + m_pNextParticle = pRet->m_pNext; + return pRet; +} + +inline void CParticleSimulateIterator::RemoveParticle( Particle *pParticle ) +{ + m_pEffectBinding->RemoveParticle( pParticle ); +} + +inline void CParticleSimulateIterator::RemoveAllParticles() +{ + Particle *pParticle = GetFirst(); + while ( pParticle ) + { + RemoveParticle( pParticle ); + pParticle = GetNext(); + } +} + +inline float CParticleSimulateIterator::GetTimeDelta() const +{ + return m_flTimeDelta; +} + + +#endif // PARTICLE_ITERATORS_H + diff --git a/game/client/particle_litsmokeemitter.h b/game/client/particle_litsmokeemitter.h new file mode 100644 index 0000000..4c65cfe --- /dev/null +++ b/game/client/particle_litsmokeemitter.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PARTICLE_LITSMOKEEMITTER_H +#define PARTICLE_LITSMOKEEMITTER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "particles_simple.h" + +#include "tier0/memdbgon.h" + +//================================================== +// CLitSmokeEmitter +//================================================== + +class CLitSmokeEmitter : public CSimpleEmitter +{ +public: + CLitSmokeEmitter( const char *pDebugName ); + + virtual void Update( float flTimeDelta ); + virtual void StartRender( VMatrix &effectMatrix ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + virtual void Init( const char *materialName, Vector sortOrigin ); + + // Get the material we were initialized with. + PMaterialHandle GetSmokeMaterial() const; + + // Color values are 0-1. + virtual void SetDirectionalLight( Vector position, Vector color, float intensity ); + virtual void SetLight( Vector position, Vector color, float intensity ); + + static CSmartPtr Create( const char *pDebugName ) + { + return new CLitSmokeEmitter( pDebugName ); + } + + CParticleSphereRenderer m_Renderer; + + class LitSmokeParticle : public Particle + { + public: + Vector m_vecVelocity; + byte m_uchColor[4]; + float m_flLifetime; + float m_flDieTime; + byte m_uchStartSize; + byte m_uchEndSize; + }; + +private: + + CLitSmokeEmitter( const CLitSmokeEmitter & ); // not defined, not accessible + +private: + + bool m_bInitted; + PMaterialHandle m_hSmokeMaterial; +}; + + +inline PMaterialHandle CLitSmokeEmitter::GetSmokeMaterial() const +{ + return m_hSmokeMaterial; +} + +#include "tier0/memdbgoff.h" + +#endif // PARTICLE_LITSMOKEEMITTER_H diff --git a/game/client/particle_prototype.h b/game/client/particle_prototype.h new file mode 100644 index 0000000..ff4d690 --- /dev/null +++ b/game/client/particle_prototype.h @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// This defines things that allow particle effects to hook into the particle app. +#ifndef PARTICLE_PROTOTYPE_H +#define PARTICLE_PROTOTYPE_H + + +class CParticleMgr; +class RecvTable; + + +// Command-line args can be passed in to set state or options in the effects. +class IPrototypeArgAccess +{ +public: + virtual const char* FindArg(const char *pName, const char *pDefault=0)=0; +}; + + + +// You must implement this interface for the prototype app to be able to run your effect. +class IPrototypeAppEffect +{ +public: + virtual ~IPrototypeAppEffect() {} + + // Start the effect. You can get command-line args with pArgs. + virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs)=0; + + // Return false if you don't allow properties to be edited in the prototype app. + virtual bool GetPropEditInfo(RecvTable **ppTable, void **ppObj) {return false;} +}; + + + +// Used internally. +typedef IPrototypeAppEffect* (*PrototypeEffectCreateFn)(); +class PrototypeEffectLink +{ +public: + PrototypeEffectLink(PrototypeEffectCreateFn fn, const char *pName); + + PrototypeEffectCreateFn m_CreateFn; + const char *m_pEffectName; + PrototypeEffectLink *m_pNext; +}; + + +#ifdef PARTICLEPROTOTYPE_APP + extern PrototypeEffectLink *g_pPrototypeEffects; // The list of prototype effects.. + + + // Expose your effect with this macro. + #define EXPOSE_PROTOTYPE_EFFECT(effectName, className) \ + static IPrototypeAppEffect* ___Create##effectName##() {return new className;} \ + static PrototypeEffectLink ___effectlink_##effectName##(___Create##effectName##, #effectName); +#else + #define EXPOSE_PROTOTYPE_EFFECT(effectName, className) +#endif + + +#endif + + diff --git a/game/client/particle_simple3d.h b/game/client/particle_simple3d.h new file mode 100644 index 0000000..177ea42 --- /dev/null +++ b/game/client/particle_simple3d.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined( SIMPLE3D_H ) +#define SIMPLE3D_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particles_simple.h" +#include "particle_collision.h" + +// Particle3D + +class Particle3D : public Particle +{ +public: + Vector m_vecVelocity; + QAngle m_vAngles; + float m_flAngSpeed; // Is same on all axis + + // NOTE: This particle already takes the full 64-bytes. So fade over a hardcoded 2 seconds instead of the entire lifetime + float GetFadeFraction() const { return m_flLifeRemaining >= 2.0f ? 1 : (m_flLifeRemaining * 0.5f); } + bool IsDead() const { return m_flLifeRemaining >= 0 ? false : true; } + + float m_flLifeRemaining; // How long it lives for. +public: + + byte m_uchFrontColor[3]; + byte m_uchSize; + byte m_uchBackColor[3]; + byte m_pad; // Pad to 8 bytes. +}; + +// +// CSimple3DEmitter +// + +class CSimple3DEmitter : public CSimpleEmitter +{ +public: + CSimple3DEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static CSmartPtr Create( const char *pDebugName ); + + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + CParticleCollision m_ParticleCollision; + +private: + CSimple3DEmitter( const CSimple3DEmitter & ); + +}; + +#endif //SIMPLE3D_H \ No newline at end of file diff --git a/game/client/particle_util.h b/game/client/particle_util.h new file mode 100644 index 0000000..d96ef3f --- /dev/null +++ b/game/client/particle_util.h @@ -0,0 +1,435 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef PARTICLE_UTIL_H +#define PARTICLE_UTIL_H + +#include "materialsystem/imesh.h" +#include "particledraw.h" +#include "particlemgr.h" +#include "cdll_client_int.h" +#include "timedevent.h" + +// Lerp between two floating point numbers. +inline float FLerp(float minVal, float maxVal, float t) +{ + return minVal + (maxVal - minVal) * t; +} + +inline Vector VecLerp(const Vector &minVal, const Vector &maxVal, float t) +{ + return minVal + (maxVal - minVal) * t; +} + +// Get a random floating point number between the two specified numbers. +inline float FRand(float minVal, float maxVal) +{ + return minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); +} + +// Apply velocity and acceleration to position and acceleration to velocity. +// If you're going to keep acceleration around, you should zero it out after calling this. +inline void PhysicallySimulate(Vector &pos, Vector &velocity, const Vector &acceleration, const float fTimeDelta) +{ + pos = pos + (velocity + (acceleration*fTimeDelta*0.5f)) * fTimeDelta; + velocity = velocity + acceleration * fTimeDelta; +} + + +inline Vector GetGravityVector() +{ + return Vector(0, 0, -150); +} + + +// Render a quad on the screen where you pass in color and size. +// Color and alpha range is 0 to 254.9 +// You also get an extra texture coordinate to pass in. +inline void RenderParticle_Color255SizeSpecularTCoord3( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size, + const unsigned char *specular, + const float tCoord + ) +{ + // Don't render totally transparent particles. + if( alpha < 0.5f ) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha ); + + // Add the 4 corner vertices. + pBuilder->Position3f( pos.x-size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord3f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1], tCoord ); + pBuilder->Specular3ubv( specular ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x-size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord3f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1], tCoord ); + pBuilder->Specular3ubv( specular ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord3f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1], tCoord ); + pBuilder->Specular3ubv( specular ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord3f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1], tCoord ); + pBuilder->Specular3ubv( specular ); + pBuilder->AdvanceVertex(); +} + + +// Render a quad on the screen where you pass in color and size. +// Color and alpha range is 0 to 254.9 +inline void RenderParticle_Color255Size( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size) +{ + // Don't render totally transparent particles. + if( alpha < 0.5f ) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha ); + + // Add the 4 corner vertices. + pBuilder->Position3f( pos.x-size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x-size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); +} + + +// Render a quad on the screen where you pass in color and size. +// Color and alpha range is 0 to 254.9 +inline void RenderParticle_Color255SizeNormal( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size, + const Vector &vNormal ) +{ + // Don't render totally transparent particles. + if( alpha < 0.5f ) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha ); + + // Add the 4 corner vertices. + pBuilder->Position3f( pos.x-size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x-size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); +} + + +// Render a quad on the screen where you pass in color and size. +// Color and alpha range is 0 to 254.9 +// Angle is in radians. +inline void RenderParticle_Color255SizeNormalAngle( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size, + const Vector &vNormal, + const float angle ) +{ + // Don't render totally transparent particles. + if( alpha < 0.5f ) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha ); + + float ca = (float)cos(angle); + float sa = (float)sin(angle); + + // Add the 4 corner vertices. + pBuilder->Position3f( pos.x + (-ca + sa) * size, pos.y + (-sa - ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x + (-ca - sa) * size, pos.y + (-sa + ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x + (ca - sa) * size, pos.y + (sa + ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x + (ca + sa) * size, pos.y + (sa - ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->Normal3fv( (float*)&vNormal ); + pBuilder->AdvanceVertex(); +} + + +// Render a quad on the screen where you pass in color and size. +inline void RenderParticle_ColorSize( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size + ) +{ + // Don't render totally transparent particles. + if( alpha < 0.001f ) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x * 254.9f ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y * 254.9f ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z * 254.9f ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha * 254.9f ); + + // Add the 4 corner vertices. + pBuilder->Position3f( pos.x-size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x-size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y+size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x+size, pos.y-size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); +} + + +inline void RenderParticle_ColorSizeAngle( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size, + const float angle) +{ + // Don't render totally transparent particles. + if(alpha < 0.001f) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x * 254.9f ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y * 254.9f ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z * 254.9f ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha * 254.9f ); + + float sa, ca; + SinCos(angle, &sa, &ca ); + + pBuilder->Position3f( pos.x + (-ca + sa) * size, pos.y + (-sa - ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x + (-ca - sa) * size, pos.y + (-sa + ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x + (ca - sa) * size, pos.y + (sa + ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f( pos.x + (ca + sa) * size, pos.y + (sa - ca) * size, pos.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); +} + +inline void RenderParticle_ColorSizeAngles( + ParticleDraw* pDraw, + const Vector &pos, + const Vector &color, + const float alpha, + const float size, + const QAngle &angles) +{ + // Don't render totally transparent particles. + if(alpha < 0.001f) + return; + + CMeshBuilder *pBuilder = pDraw->GetMeshBuilder(); + if( !pBuilder ) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt( color.x * 254.9f ); + ubColor[1] = (unsigned char)RoundFloatToInt( color.y * 254.9f ); + ubColor[2] = (unsigned char)RoundFloatToInt( color.z * 254.9f ); + ubColor[3] = (unsigned char)RoundFloatToInt( alpha * 254.9f ); + + Vector vNorm,vWidth,vHeight; + AngleVectors(angles,&vNorm,&vWidth,&vHeight); + + Vector vVertex = pos; + pBuilder->Position3f( vVertex.x , vVertex.y , vVertex.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->Normal3f( VectorExpand(vNorm) ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); + + vVertex = vVertex + vWidth*size; + pBuilder->Position3f( vVertex.x, vVertex.y, vVertex.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->Normal3f( VectorExpand(vNorm) ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + vVertex = vVertex + vHeight*size; + pBuilder->Position3f( vVertex.x, vVertex.y , vVertex.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->Normal3f( VectorExpand(vNorm) ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1] ); + pBuilder->AdvanceVertex(); + + vVertex = vVertex - vWidth*size; + pBuilder->Position3f( vVertex.x, vVertex.y, vVertex.z ); + pBuilder->Color4ubv( ubColor ); + pBuilder->Normal3f( VectorExpand(vNorm) ); + pBuilder->TexCoord2f( 0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1] ); + pBuilder->AdvanceVertex(); +} + +inline float GetAlphaDistanceFade( + const Vector &pos, + const float fadeNearDist, + const float fadeFarDist) +{ + if(-pos.z > fadeFarDist) + { + return 1; + } + else if(-pos.z > fadeNearDist) + { + return (-pos.z - fadeNearDist) / (fadeFarDist - fadeNearDist); + } + else + { + return 0; + } +} + + +inline Vector WorldGetLightForPoint(const Vector &vPos, bool bClamp) +{ + #if defined(PARTICLEPROTOTYPE_APP) + return Vector(1,1,1); + #else + return engine->GetLightForPoint(vPos, bClamp); + #endif +} + +#endif + + + diff --git a/game/client/particledraw.h b/game/client/particledraw.h new file mode 100644 index 0000000..e52788b --- /dev/null +++ b/game/client/particledraw.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// FIXME: Should we just pass the Particle draw members directly as +// arguments to IParticleEffect::SimulateAndRender? + +// This file defines and implements the ParticleDraw class, which is used +// by ParticleEffects to render particles. It simply stores render + simulation +// state +// + +#ifndef PARTICLEDRAW_H +#define PARTICLEDRAW_H + + +class IMaterial; +class CMeshBuilder; +class CParticleSubTexture; + + +class ParticleDraw +{ +friend class CParticleEffectBinding; + +public: + + ParticleDraw(); + + void Init( CMeshBuilder *pMeshBuilder, IMaterial *pMaterial, float fTimeDelta ); + + // Time delta.. + float GetTimeDelta() const; + + // Get the material being used (mostly useful for getting the tcoord padding). + //IMaterial* GetPMaterial(); + + // This can return NULL if the particle system is only being simulated. + CMeshBuilder* GetMeshBuilder(); + + CParticleSubTexture *m_pSubTexture; + +private: + CMeshBuilder *m_pMeshBuilder; + IMaterial *m_pMaterial; + float m_fTimeDelta; +}; + + + +// ------------------------------------------------------------------------- // +// Inlines +// ------------------------------------------------------------------------- // + +inline ParticleDraw::ParticleDraw() +{ + m_pMaterial = 0; +} + +inline void ParticleDraw::Init( CMeshBuilder *pMeshBuilder, IMaterial *pMaterial, float fTimeDelta ) +{ + m_pMeshBuilder = pMeshBuilder; + m_pMaterial = pMaterial; + m_fTimeDelta = fTimeDelta; +} + +inline float ParticleDraw::GetTimeDelta() const +{ + return m_fTimeDelta; +} + +inline CMeshBuilder* ParticleDraw::GetMeshBuilder() +{ + return m_pMeshBuilder; +} + +#endif + diff --git a/game/client/particlemgr.h b/game/client/particlemgr.h new file mode 100644 index 0000000..d4537f3 --- /dev/null +++ b/game/client/particlemgr.h @@ -0,0 +1,919 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +// +// This module implements the particle manager for the client DLL. +// In a nutshell, to create your own effect, implement the ParticleEffect +// interface and call CParticleMgr::AddEffect to add your effect. Then you can +// add particles and simulate and render them. + +/* + +Particle manager documentation +----------------------------------------------------------------------------- + +All particle effects are managed by a class called CParticleMgr. It tracks +the list of particles, manages their materials, sorts the particles, and +has callbacks to render them. + +Conceptually, CParticleMgr is NOT part of VEngine's entity system. It does +not care about entities, only particle effects. Usually, the two are implemented +together, but you should be aware the CParticleMgr talks to you through its +own interfaces and does not talk to entities. Thus, it is possible to have +particle effects that are not entities. + +To make a particle effect, you need two things: + +1. An implementation of the IParticleEffect interface. This is how CParticleMgr + talks to you for things like rendering and updating your effect. + +2. A (member) variable of type CParticleEffectBinding. This allows CParticleMgr to + store its internal data associated with your effect. + +Once you have those two things, you call CParticleMgr::AddEffect and pass them +both in. You will then get updates through IParticleEffect::Update, and you will +be asked to render your particles with IParticleEffect::SimulateAndRender. + +When you want to remove the effect, call CParticleEffectBinding::SetRemoveFlag(), which +tells CParticleMgr to remove the effect next chance it gets. + +Example class: + + class CMyEffect : public IParticleEffect + { + public: + // Call this to start the effect by adding it to the particle manager. + void Start() + { + ParticleMgr()->AddEffect( &m_ParticleEffect, this ); + } + + // implementation of IParticleEffect functions go here... + + public: + CParticleEffectBinding m_ParticleEffect; + }; + + + +How the particle effects are integrated with the entity system +----------------------------------------------------------------------------- + +There are two helper classes that you can use to create particles for your +entities. Each one is useful under different conditions. + +1. CSimpleEmitter is a class that does some of the dirty work of using particles. + If you want, you can just instantiate one of these with CSimpleEmitter::Create + and call its AddParticle functions to add particles. When you are done and + want to 'free' it, call its Release function rather than deleting it, and it + will wait until all of its particles have gone away before removing itself + (so you don't have to write code to wait for all of the particles to go away). + + In most cases, it is the easiest and most clear to use CSimpleEmitter or + derive a class from it, then use that class from inside an entity that wants + to make particles. + + CSimpleEmitter and derived classes handle adding themselves to the particle + manager, tracking how many particles in the effect are active, and + rendering the particles. + + CSimpleEmitter has code to simulate and render particles in a generic fashion, + but if you derive a class from it, you can override some of its behavior + with virtuals like UpdateAlpha, UpdateScale, UpdateColor, etc.. + + Example code: + CSimpleEmitter *pEmitter = CSimpleEmitter::Create(); + + CEffectMaterialHandle hMaterial = pEmitter->GetCEffectMaterial( "mymaterial" ); + + for( int i=0; i < 100; i++ ) + pEmitter->AddParticle( hMaterial, RandomVector(0,10), 4 ); + + pEmitter->Release(); + +2. Some older effects derive from C_BaseParticleEffect and implement an entity + and a particle system at the same time. This gets nasty and is not encouraged anymore. + +*/ + + +#ifndef PARTICLEMGR_H +#define PARTICLEMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include "mathlib/vector.h" +#include "mathlib/vmatrix.h" +#include "mathlib/mathlib.h" +#include "iclientrenderable.h" +#include "clientleafsystem.h" +#include "tier0/fasttimer.h" +#include "utllinkedlist.h" +#include "utldict.h" +#ifdef WIN32 +#include +#else +#include +#endif +#include "tier1/utlintrusivelist.h" +#include "tier1/utlstring.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class IParticleEffect; +class IClientParticleListener; +struct Particle; +class ParticleDraw; +class CMeshBuilder; +class CUtlMemoryPool; +class CEffectMaterial; +class CParticleSimulateIterator; +class CParticleRenderIterator; +class IThreadPool; +class CParticleSystemDefinition; +class CParticleMgr; +class CNewParticleEffect; +class CParticleCollection; + +#define INVALID_MATERIAL_HANDLE NULL + + +// Various stats, disabled +// extern int g_nParticlesDrawn; +// extern CCycleCount g_ParticleTimer; + + +class CParticleSubTexture; +class CParticleSubTextureGroup; + + +//----------------------------------------------------------------------------- +// The basic particle description; all particles need to inherit from this. +//----------------------------------------------------------------------------- + +struct Particle +{ + Particle *m_pPrev, *m_pNext; + + // Which sub texture this particle uses (so we can get at the tcoord mins and maxs). + CParticleSubTexture *m_pSubTexture; + + // If m_Pos isn't used to store the world position, then implement IParticleEffect::GetParticlePosition() + Vector m_Pos; // Position of the particle in world space +}; + + +//----------------------------------------------------------------------------- +// This is the CParticleMgr's reference to a material in the material system. +// Particles are sorted by material. +//----------------------------------------------------------------------------- + +// This indexes CParticleMgr::m_SubTextures. +typedef CParticleSubTexture* PMaterialHandle; + +// Each effect stores a list of particles associated with each material. The list is +// hashed on the IMaterial pointer. +class CEffectMaterial +{ +public: + CEffectMaterial(); + +public: + // This provides the material that gets bound for this material in this effect. + // There can be multiple subtextures all within the same CEffectMaterial. + CParticleSubTextureGroup *m_pGroup; + + Particle m_Particles; + CEffectMaterial *m_pHashedNext; +}; + + +class CParticleSubTextureGroup +{ +public: + CParticleSubTextureGroup(); + ~CParticleSubTextureGroup(); + + // Even though each of the subtextures has its own material, they should all basically be + // the same exact material and just use different texture coordinates, so this is the + // material of the first subtexture that is bound. + // + // This is gotten from GetMaterialPage(). + IMaterial *m_pPageMaterial; +}; + +// Precalculated data for each material used for particles. +// This allows us to put multiple subtextures into one VTF and sort them against each other. +class CParticleSubTexture +{ +public: + CParticleSubTexture(); + + float m_tCoordMins[2]; // bbox in texel space that this particle material uses. + float m_tCoordMaxs[2]; // Specified in the SubTextureMins/SubTextureMaxs parameter in the materials. + + // Which group does this subtexture belong to? + CParticleSubTextureGroup *m_pGroup; + CParticleSubTextureGroup m_DefaultGroup; // This is used as the group if a particle's material + // isn't using a group. + +#ifdef _DEBUG + char *m_szDebugName; +#endif + + IMaterial *m_pMaterial; +}; + +// Particle simulation list, used to determine what particles to simulate and how. +struct ParticleSimListEntry_t +{ + CNewParticleEffect* m_pNewParticleEffect; + bool m_bBoundingBoxOnly; +}; + + +//----------------------------------------------------------------------------- +// interface IParticleEffect: +// +// This is the interface that particles effects must implement. The effect is +// responsible for starting itself and calling CParticleMgr::AddEffect, then it +// will get the callbacks it needs to simulate and render the particles. +//----------------------------------------------------------------------------- + +abstract_class IParticleEffect +{ +// Overridables. +public: + + virtual ~IParticleEffect() {} + + // Called at the beginning of a frame to precalculate data for rendering + // the particles. If you manage your own list of particles and want to + // simulate them all at once, you can do that here and just render them in + // the SimulateAndRender call. + virtual void Update( float fTimeDelta ) {} + + // Called once for the entire effect before the batch of SimulateAndRender() calls. + // For particle systems using FLAGS_CAMERASPACE (the default), effectMatrix transforms the particles from + // world space into camera space. You can change this matrix if you want your particles relative to something + // else like an attachment's space. + virtual void StartRender( VMatrix &effectMatrix ) {} + + // Simulate the particles. + virtual bool ShouldSimulate() const = 0; + virtual void SetShouldSimulate( bool bSim ) = 0; + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ) = 0; + + // Render the particles. + virtual void RenderParticles( CParticleRenderIterator *pIterator ) = 0; + + // Implementing this is optional. It is called when an effect is removed. It is useful if + // you hold onto pointers to the particles you created (so when this is called, you should + // clean up your data so you don't reference the particles again). + // NOTE: after calling this, the particle manager won't touch the IParticleEffect + // or its associated CParticleEffectBinding anymore. + virtual void NotifyRemove() {} + + // This method notifies the effect a particle is about to be deallocated. + // Implementations should *not* actually deallocate it. + // NOTE: The particle effect's GetNumActiveParticles is updated BEFORE this is called + // so if GetNumActiveParticles returns 0, then you know this is the last particle + // in the system being removed. + virtual void NotifyDestroyParticle( Particle* pParticle ) {} + + // Fill in the origin used to sort this entity. + // This is a world space position. + virtual const Vector &GetSortOrigin() = 0; + + // Fill in the origin used to sort this entity. +// TODO: REMOVE THIS. ALL PARTICLE SYSTEMS SHOULD EITHER SET m_Pos IN CONJUNCTION WITH THE +// PARTICLE_LOCALSPACE FLAG, OR DO SETBBOX THEMSELVES. + virtual const Vector *GetParticlePosition( Particle *pParticle ) { return &pParticle->m_Pos; } + + virtual const char *GetEffectName() { return "???"; } +}; + +#define REGISTER_EFFECT( effect ) \ + IParticleEffect* effect##_Factory() \ + { \ + return new effect; \ + } \ + struct effect##_RegistrationHelper \ + { \ + effect##_RegistrationHelper() \ + { \ + ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \ + } \ + }; \ + static effect##_RegistrationHelper g_##effect##_RegistrationHelper + +#define REGISTER_EFFECT_USING_CREATE( effect ) \ + IParticleEffect* effect##_Factory() \ + { \ + return effect::Create( #effect ).GetObject(); \ + } \ + struct effect##_RegistrationHelper \ + { \ + effect##_RegistrationHelper() \ + { \ + ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \ + } \ + }; \ + static effect##_RegistrationHelper g_##effect##_RegistrationHelper + + +// In order to create a particle effect, you must have one of these around and +// implement IParticleEffect. Pass them both into CParticleMgr::AddEffect and you +// are good to go. +class CParticleEffectBinding : public CDefaultClientRenderable +{ + friend class CParticleMgr; + friend class CParticleSimulateIterator; + friend class CNewParticleEffect; + +public: + CParticleEffectBinding(); + ~CParticleEffectBinding(); + + +// Helper functions to setup, add particles, etc.. +public: + + // Simulate all the particles. + void SimulateParticles( float flTimeDelta ); + + // Use this to specify materials when adding particles. + // Returns the index of the material it found or added. + // Returns INVALID_MATERIAL_HANDLE if it couldn't find or add a material. + PMaterialHandle FindOrAddMaterial( const char *pMaterialName ); + + // Allocate particles. The Particle manager will automagically + // deallocate them when the IParticleEffect SimulateAndRender() method + // returns false. The first argument is the size of the particle + // structure in bytes + Particle* AddParticle( int sizeInBytes, PMaterialHandle pMaterial ); + + // This is an optional call you can make if you want to manually manage the effect's + // bounding box. Normally, the bounding box is managed automatically, but in certain + // cases it is more efficient to set it manually. + // + // Note: this is a WORLD SPACE bounding box, even if you've used SetLocalSpaceTransform. + // + // After you make this call, the particle manager will no longer update the bounding + // box automatically if bDisableAutoUpdate is true. + void SetBBox( const Vector &bbMin, const Vector &bbMax, bool bDisableAutoUpdate = true ); + // gets a copy of the current bbox mins/maxs in worldspace + void GetWorldspaceBounds( Vector *pMins, Vector *pMaxs ); + + // This tells the particle manager that your particles are transformed by the specified matrix. + // That way, it can transform the bbox defined by Particle::m_Pos into world space correctly. + // + // It also sets up the matrix returned by CParticleMgr::GetModelView() to include this matrix, so you + // can do TransformParticle with it like any other particle system. + const matrix3x4_t& GetLocalSpaceTransform() const; + void SetLocalSpaceTransform( const matrix3x4_t &transform ); + + // This expands the bbox to contain the specified point. Returns true if bbox changed + bool EnlargeBBoxToContain( const Vector &pt ); + + // The EZ particle singletons use this - they don't want to be added to all the leaves and drawn through the + // leaf system - they are specifically told to draw each frame at a certain point. + void SetDrawThruLeafSystem( int bDraw ); + + // Some view model particle effects want to be drawn right before the view model (after everything else is + // drawn). + void SetDrawBeforeViewModel( int bDraw ); + + // Call this to have the effect removed whenever it safe to do so. + // This is a lot safer than calling CParticleMgr::RemoveEffect. + int GetRemoveFlag() { return GetFlag( FLAGS_REMOVE ); } + void SetRemoveFlag() { SetFlag( FLAGS_REMOVE, 1 ); } + + // Set this flag to tell the particle manager to simulate your particles even + // if the particle system isn't visible. Tempents and fast effects can always use + // this if they want since they want to simulate their particles until they go away. + // This flag is ON by default. + int GetAlwaysSimulate() { return GetFlag( FLAGS_ALWAYSSIMULATE ); } + void SetAlwaysSimulate( int bAlwaysSimulate ) { SetFlag( FLAGS_ALWAYSSIMULATE, bAlwaysSimulate ); } + + void SetIsNewParticleSystem( void ) { SetFlag( FLAGS_NEW_PARTICLE_SYSTEM, 1 ); } + // Set if the effect was drawn the previous frame. + // This can be used by particle effect classes + // to decide whether or not they want to spawn + // new particles - if they weren't drawn, then + // they can 'freeze' the particle system to avoid + // overhead. + int WasDrawnPrevFrame() { return GetFlag( FLAGS_DRAWN_PREVFRAME ); } + void SetWasDrawnPrevFrame( int bWasDrawnPrevFrame ) { SetFlag( FLAGS_DRAWN_PREVFRAME, bWasDrawnPrevFrame ); } + + // When the effect is in camera space mode, then the transforms are setup such that + // the particle vertices are specified in camera space (in CParticleDraw) rather than world space. + // + // This makes it faster to specify the particles - you only have to transform the center + // by CParticleMgr::GetModelView then add to X and Y to build the quad. + // + // Effects that want to specify verts (in CParticleDraw) in world space should set this to false and + // ignore CParticleMgr::GetModelView. + // + // Camera space mode is ON by default. + int IsEffectCameraSpace() { return GetFlag( FLAGS_CAMERASPACE ); } + void SetEffectCameraSpace( int bCameraSpace ) { SetFlag( FLAGS_CAMERASPACE, bCameraSpace ); } + + // This tells it whether or not to apply the local transform to the matrix returned by CParticleMgr::GetModelView(). + // Usually, you'll want this, so you can just say TransformParticle( pMgr->GetModelView(), vPos ), but you may want + // to manually apply your local transform before saying TransformParticle. + // + // This is ON by default. + int GetAutoApplyLocalTransform() const { return GetFlag( FLAGS_AUTOAPPLYLOCALTRANSFORM ); } + void SetAutoApplyLocalTransform( int b ) { SetFlag( FLAGS_AUTOAPPLYLOCALTRANSFORM, b ); } + + // If this is true, then the bbox is calculated from particle positions. This works + // fine if you always simulate (SetAlwaysSimulateFlag) so the system can become visible + // if it moves into the PVS. If you don't use this, then you should call SetBBox at + // least once to tell the particle manager where your entity is. + int GetAutoUpdateBBox() { return GetFlag( FLAGS_AUTOUPDATEBBOX ); } + void SetAutoUpdateBBox( int bAutoUpdate ) { SetFlag( FLAGS_AUTOUPDATEBBOX, bAutoUpdate ); } + + // Get the current number of particles in the effect. + int GetNumActiveParticles(); + + // The is the max size of the particles for use in bounding computation + void SetParticleCullRadius( float flMaxParticleRadius ); + + // Build a list of all active particles, returns actual count filled in + int GetActiveParticleList( int nCount, Particle **ppParticleList ); + + // detect origin/bbox changes and update leaf system if necessary + void DetectChanges(); + +private: + // Change flags.. + void SetFlag( int flag, int bOn ) { if( bOn ) m_Flags |= flag; else m_Flags &= ~flag; } + int GetFlag( int flag ) const { return m_Flags & flag; } + + void Init( CParticleMgr *pMgr, IParticleEffect *pSim ); + void Term(); + + // Get rid of the specified particle. + void RemoveParticle( Particle *pParticle ); + + void StartDrawMaterialParticles( + CEffectMaterial *pMaterial, + float flTimeDelta, + IMesh* &pMesh, + CMeshBuilder &builder, + ParticleDraw &particleDraw, + bool bWireframe ); + + int DrawMaterialParticles( + bool bBucketSort, + CEffectMaterial *pMaterial, + float flTimeDelta, + bool bWireframe + ); + + void GrowBBoxFromParticlePositions( CEffectMaterial *pMaterial, bool &bboxSet, Vector &bbMin, Vector &bbMax ); + + void RenderStart( VMatrix &mTempModel, VMatrix &mTempView ); + void RenderEnd( VMatrix &mModel, VMatrix &mView ); + + void BBoxCalcStart( Vector &bbMin, Vector &bbMax ); + void BBoxCalcEnd( bool bboxSet, Vector &bbMin, Vector &bbMax ); + + void DoBucketSort( + CEffectMaterial *pMaterial, + float *zCoords, + int nZCoords, + float minZ, + float maxZ ); + + int GetRemovalInProgressFlag() { return GetFlag( FLAGS_REMOVALINPROGRESS ); } + void SetRemovalInProgressFlag() { SetFlag( FLAGS_REMOVALINPROGRESS, 1 ); } + + // BBox is recalculated before it's put into the tree for the first time. + int GetNeedsBBoxUpdate() { return GetFlag( FLAGS_NEEDS_BBOX_UPDATE ); } + void SetNeedsBBoxUpdate( int bFirstUpdate ) { SetFlag( FLAGS_NEEDS_BBOX_UPDATE, bFirstUpdate ); } + + // Set on creation and cleared after the first PostRender (whether or not the system was rendered). + int GetFirstFrameFlag() { return GetFlag( FLAGS_FIRST_FRAME ); } + void SetFirstFrameFlag( int bFirstUpdate ) { SetFlag( FLAGS_FIRST_FRAME, bFirstUpdate ); } + + int WasDrawn() { return GetFlag( FLAGS_DRAWN ); } + void SetDrawn( int bDrawn ) { SetFlag( FLAGS_DRAWN, bDrawn ); } + + // Update m_Min/m_Max. Returns false and sets the bbox to the sort origin if there are no particles. + bool RecalculateBoundingBox(); + + CEffectMaterial* GetEffectMaterial( CParticleSubTexture *pSubTexture ); + +// IClientRenderable overrides. +public: + + virtual const Vector& GetRenderOrigin( void ); + virtual const QAngle& GetRenderAngles( void ); + virtual const matrix3x4_t & RenderableToWorldTransform(); + virtual void GetRenderBounds( Vector& mins, Vector& maxs ); + virtual bool ShouldDraw( void ); + virtual bool IsTransparent( void ); + virtual int DrawModel( int flags ); + + +private: + + enum + { + FLAGS_REMOVE = (1<<0), // Set in SetRemoveFlag + FLAGS_REMOVALINPROGRESS = (1<<1), // Set while the effect is being removed to prevent + // infinite recursion. + FLAGS_NEEDS_BBOX_UPDATE = (1<<2), // This is set until the effect's bbox has been updated once. + FLAGS_AUTOUPDATEBBOX = (1<<3), // Update bbox automatically? Cleared in SetBBox. + FLAGS_ALWAYSSIMULATE = (1<<4), // See SetAlwaysSimulate. + FLAGS_DRAWN = (1<<5), // Set if the effect is drawn through the leaf system. + FLAGS_DRAWN_PREVFRAME = (1<<6), // Set if the effect was drawn the previous frame. + // This can be used by particle effect classes + // to decide whether or not they want to spawn + // new particles - if they weren't drawn, then + // they can 'freeze' the particle system to avoid + // overhead. + FLAGS_CAMERASPACE = (1<<7), // See SetEffectCameraSpace. + FLAGS_DRAW_THRU_LEAF_SYSTEM=(1<<8), // This is the default - do the effect's visibility through the leaf system. + FLAGS_DRAW_BEFORE_VIEW_MODEL=(1<<9),// Draw before the view model? If this is set, it assumes FLAGS_DRAW_THRU_LEAF_SYSTEM goes off. + FLAGS_AUTOAPPLYLOCALTRANSFORM=(1<<10), // Automatically apply the local transform to CParticleMgr::GetModelView()'s matrix. + FLAGS_FIRST_FRAME = (1<<11), // Cleared after the first frame that this system exists (so it can simulate after rendering once). + FLAGS_NEW_PARTICLE_SYSTEM= (1<<12) // uses new particle system + }; + + + VMatrix m_LocalSpaceTransform; + bool m_bLocalSpaceTransformIdentity; // If this is true, then m_LocalSpaceTransform is assumed to be identity. + + // Bounding box. Stored in WORLD space. + Vector m_Min; + Vector m_Max; + + // paramter copies to detect changes + Vector m_LastMin; + Vector m_LastMax; + + // The particle cull size + float m_flParticleCullRadius; + + // Number of active particles. + unsigned short m_nActiveParticles; + + // See CParticleMgr::m_FrameCode. + unsigned short m_FrameCode; + + // For CParticleMgr's list index. + unsigned short m_ListIndex; + + IParticleEffect *m_pSim; + CParticleMgr *m_pParticleMgr; + + // Combination of the CParticleEffectBinding::FLAGS_ flags. + int m_Flags; + + // Materials this effect is using. + enum { EFFECT_MATERIAL_HASH_SIZE = 8 }; + CEffectMaterial *m_EffectMaterialHash[EFFECT_MATERIAL_HASH_SIZE]; + + // For faster iteration. + CUtlLinkedList m_Materials; + + // auto updates the bbox after N frames + unsigned short m_UpdateBBoxCounter; +}; + + +class CParticleLightInfo +{ +public: + Vector m_vPos; + Vector m_vColor; // 0-1 + float m_flIntensity; +}; + +typedef IParticleEffect* (*CreateParticleEffectFN)(); + +enum +{ + TOOLPARTICLESYSTEMID_INVALID = -1, +}; + + +class CParticleMgr +{ + friend class CParticleEffectBinding; + friend class CParticleCollection; + +public: + + CParticleMgr(); + virtual ~CParticleMgr(); + + // Call at init time to preallocate the bucket of particles. + bool Init(unsigned long nPreallocatedParticles, IMaterialSystem *pMaterial); + + // Shutdown - free everything. + void Term(); + + void LevelInit(); + + void RegisterEffect( const char *pEffectType, CreateParticleEffectFN func ); + IParticleEffect *CreateEffect( const char *pEffectType ); + + // Add and remove effects from the active list. + // Note: once you call AddEffect, CParticleEffectBinding will automatically call + // RemoveEffect in its destructor. + // Note: it's much safer to call CParticleEffectBinding::SetRemoveFlag instead of + // CParticleMgr::RemoveEffect. + bool AddEffect( CParticleEffectBinding *pEffect, IParticleEffect *pSim ); + void RemoveEffect( CParticleEffectBinding *pEffect ); + + void AddEffect( CNewParticleEffect *pEffect ); + void RemoveEffect( CNewParticleEffect *pEffect ); + + // Called at level shutdown to free all the lingering particle effects (usually + // CParticleEffect-derived effects that can linger with noone holding onto them). + void RemoveAllEffects(); + + // This should be called at the start of the frame. + void IncrementFrameCode(); + + // This updates all the particle effects and inserts them into the leaves. + void Simulate( float fTimeDelta ); + + // This just marks effects that were drawn so during their next simulation they can know + // if they were drawn in the previous frame. + void PostRender(); + + // Draw the effects marked with SetDrawBeforeViewModel. + void DrawBeforeViewModelEffects(); + + // Returns the modelview matrix + VMatrix& GetModelView(); + + Particle *AllocParticle( int size ); + void FreeParticle( Particle * ); + + PMaterialHandle GetPMaterial( const char *pMaterialName ); + IMaterial* PMaterialToIMaterial( PMaterialHandle hMaterial ); + + //HACKHACK: quick fix that compensates for the fact that this system was designed to never release materials EVER. + void RepairPMaterial( PMaterialHandle hMaterial ); + + // Particles drawn with the ParticleSphere material will use this info. + // This should be set in IParticleEffect. + void GetDirectionalLightInfo( CParticleLightInfo &info ) const; + void SetDirectionalLightInfo( const CParticleLightInfo &info ); + + // add a class that gets notified of entity events + void AddEffectListener( IClientParticleListener *pListener ); + void RemoveEffectListener( IClientParticleListener *pListener ); + + // Tool effect ids + int AllocateToolParticleEffectId(); + + // Remove all new effects + void RemoveAllNewEffects(); + + // Should particle effects be rendered? + void RenderParticleSystems( bool bEnable ); + bool ShouldRenderParticleSystems() const; + + // Quick profiling (counts only, not clock cycles). + bool m_bStatsRunning; + int m_nStatsFramesSinceLastAlert; + + void StatsAccumulateActiveParticleSystems(); + void StatsReset(); + void StatsSpewResults(); + void StatsNewParticleEffectDrawn ( CNewParticleEffect *pParticles ); + void StatsOldParticleEffectDrawn ( CParticleEffectBinding *pParticles ); + +private: + struct RetireInfo_t + { + CParticleCollection *m_pCollection; + float m_flScreenArea; + bool m_bFirstFrame; + }; + + // Call Update() on all the effects. + void UpdateAllEffects( float flTimeDelta ); + + void UpdateNewEffects( float flTimeDelta ); // update new particle effects + + CParticleSubTextureGroup* FindOrAddSubTextureGroup( IMaterial *pPageMaterial ); + + int ComputeParticleDefScreenArea( int nInfoCount, RetireInfo_t *pInfo, float *pTotalArea, CParticleSystemDefinition* pDef, + const CViewSetup& view, const VMatrix &worldToPixels, float flFocalDist ); + + bool RetireParticleCollections( CParticleSystemDefinition* pDef, int nCount, RetireInfo_t *pInfo, float flScreenArea, float flMaxTotalArea ); + + void BuildParticleSimList( CUtlVector< ParticleSimListEntry_t > &list ); + bool EarlyRetireParticleSystems( int nCount, ParticleSimListEntry_t *ppEffects ); + static int RetireSort( const void *p1, const void *p2 ); + +private: + + int m_nCurrentParticlesAllocated; + + // Directional lighting info. + CParticleLightInfo m_DirectionalLight; + + // Frame code, used to prevent CParticleEffects from simulating multiple times per frame. + // Their DrawModel can be called multiple times per frame because of water reflections, + // but we only want to simulate the particles once. + unsigned short m_FrameCode; + + bool m_bUpdatingEffects; + bool m_bRenderParticleEffects; + + // All the active effects. + CUtlLinkedList m_Effects; + + // all the active effects using the new particle interface + CUtlIntrusiveDList< CNewParticleEffect > m_NewEffects; + + + CUtlVector< IClientParticleListener *> m_effectListeners; + + IMaterialSystem *m_pMaterialSystem; + + // Store the concatenated modelview matrix + VMatrix m_mModelView; + + CUtlVector m_SubTextureGroups; // lookup by group name + CUtlDict m_SubTextures; // lookup by material name + CParticleSubTexture m_DefaultInvalidSubTexture; // Used when they specify an invalid material name. + + CUtlMap< const char*, CreateParticleEffectFN > m_effectFactories; + + int m_nToolParticleEffectId; + + IThreadPool *m_pThreadPool[2]; +}; + +inline int CParticleMgr::AllocateToolParticleEffectId() +{ + return m_nToolParticleEffectId++; +} + +// Implement this class and register with CParticleMgr to receive particle effect add/remove notification +class IClientParticleListener +{ +public: + virtual void OnParticleEffectAdded( IParticleEffect *pEffect ) = 0; + virtual void OnParticleEffectRemoved( IParticleEffect *pEffect ) = 0; +}; + + + +// Helper functions to abstract out the particle testbed app. +float Helper_GetTime(); +float Helper_GetFrameTime(); +float Helper_RandomFloat( float minVal, float maxVal ); +int Helper_RandomInt( int minVal, int maxVal ); + + + +// ------------------------------------------------------------------------ // +// CParticleMgr inlines +// ------------------------------------------------------------------------ // + +inline VMatrix& CParticleMgr::GetModelView() +{ + return m_mModelView; +} + + + +// ------------------------------------------------------------------------ // +// CParticleEffectBinding inlines. +// ------------------------------------------------------------------------ // + +inline const matrix3x4_t& CParticleEffectBinding::GetLocalSpaceTransform() const +{ + return m_LocalSpaceTransform.As3x4(); +} + + + +// ------------------------------------------------------------------------ // +// GLOBALS +// ------------------------------------------------------------------------ // + +CParticleMgr *ParticleMgr(); + + + + +//----------------------------------------------------------------------------- +// StandardParticle_t; this is just one type of particle +// effects may implement their own particle data structures +//----------------------------------------------------------------------------- + +struct StandardParticle_t : public Particle +{ + // Color and alpha values are 0 - 1 + void SetColor(float r, float g, float b); + void SetAlpha(float a); + + Vector m_Velocity; + + // How this is used is up to the effect's discretion. Some use it for how long it has been alive + // and others use it to count down until the particle disappears. + float m_Lifetime; + + unsigned char m_EffectData; // Data specific to the IParticleEffect. This can be used to distinguish between + // different types of particles the effect is simulating. + unsigned short m_EffectDataWord; + + unsigned char m_Color[4]; // RGBA - not all effects need to use this. +}; + + +// ------------------------------------------------------------------------ // +// Transform a particle. +// ------------------------------------------------------------------------ // + +inline void TransformParticle(const VMatrix &vMat, const Vector &vIn, Vector &vOut) +{ + //vOut = vMat.VMul4x3(vIn); + vOut.x = vMat.m[0][0]*vIn.x + vMat.m[0][1]*vIn.y + vMat.m[0][2]*vIn.z + vMat.m[0][3]; + vOut.y = vMat.m[1][0]*vIn.x + vMat.m[1][1]*vIn.y + vMat.m[1][2]*vIn.z + vMat.m[1][3]; + vOut.z = vMat.m[2][0]*vIn.x + vMat.m[2][1]*vIn.y + vMat.m[2][2]*vIn.z + vMat.m[2][3]; +} + + +// ------------------------------------------------------------------------ // +// CEffectMaterial inlines +// ------------------------------------------------------------------------ // + +inline void StandardParticle_t::SetColor(float r, float g, float b) +{ + m_Color[0] = (unsigned char)(r * 255.9f); + m_Color[1] = (unsigned char)(g * 255.9f); + m_Color[2] = (unsigned char)(b * 255.9f); +} + +inline void StandardParticle_t::SetAlpha(float a) +{ + m_Color[3] = (unsigned char)(a * 255.9f); +} + + + +//----------------------------------------------------------------------------- +// List functions. +//----------------------------------------------------------------------------- + +inline void UnlinkParticle( Particle *pParticle ) +{ + pParticle->m_pPrev->m_pNext = pParticle->m_pNext; + pParticle->m_pNext->m_pPrev = pParticle->m_pPrev; +} + +inline void InsertParticleBefore( Particle *pInsert, Particle *pNext ) +{ + // link pCur before pPrev + pInsert->m_pNext = pNext; + pInsert->m_pPrev = pNext->m_pPrev; + pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert; +} + +inline void InsertParticleAfter( Particle *pInsert, Particle *pPrev ) +{ + pInsert->m_pPrev = pPrev; + pInsert->m_pNext = pPrev->m_pNext; + + pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert; +} + +inline void SwapParticles( Particle *pPrev, Particle *pCur ) +{ + // unlink pCur + UnlinkParticle( pCur ); + InsertParticleBefore( pCur, pPrev ); +} + + +#include "particle_iterators.h" + + +#endif + + diff --git a/game/client/particles_attractor.h b/game/client/particles_attractor.h new file mode 100644 index 0000000..077376f --- /dev/null +++ b/game/client/particles_attractor.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PARTICLES_ATTRACTOR_H +#define PARTICLES_ATTRACTOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particles_simple.h" + +class CParticleAttractor : public CSimpleEmitter +{ +public: + + CParticleAttractor( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + //Create + static CParticleAttractor *Create( const Vector ¢er, const char *pDebugName = "attractor" ); + + void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + float UpdateScale( const SimpleParticle *pParticle ); + float UpdateAlpha( const SimpleParticle *pParticle ); + void SetAttractorOrigin( const Vector &origin ); + +private: + + CParticleAttractor( const CParticleAttractor & ); // not defined, not accessible + + Vector m_vecAttractorOrigin; +}; + +#endif // PARTICLES_ATTRACTOR_H diff --git a/game/client/particles_ez.h b/game/client/particles_ez.h new file mode 100644 index 0000000..cb82198 --- /dev/null +++ b/game/client/particles_ez.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PARTICLES_EZ_H +#define PARTICLES_EZ_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "particles_simple.h" +#include "particle_litsmokeemitter.h" + + +// Use these to fire and forget particles. +// pParticle should be ON THE STACK - ie: don't allocate it from a CSimpleEmitter or from the particle manager. +// Just make one on the stack, fill in its parameters, and pass it in here. +void AddSimpleParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox=false ); +void AddEmberParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox=false ); +void AddFireSmokeParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox=false ); +void AddFireParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox=false ); + + +// Called by the renderer to draw all the particles. +void DrawParticleSingletons( bool bInSkybox ); + + +#endif // PARTICLES_EZ_H diff --git a/game/client/particles_localspace.h b/game/client/particles_localspace.h new file mode 100644 index 0000000..8b2a5a4 --- /dev/null +++ b/game/client/particles_localspace.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PARTICLES_LOCALSPACE_H +#define PARTICLES_LOCALSPACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particles_simple.h" + +#define FLE_VIEWMODEL 0x00000001 + +class CLocalSpaceEmitter : public CSimpleEmitter +{ +public: + + DECLARE_CLASS( CLocalSpaceEmitter, CParticleEffect ); + + static CSmartPtr Create( const char *pDebugName, ClientEntityHandle_t hEntity, int nAttachment, int flags = 0 ); + + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + virtual void SetupTransformMatrix( void ); + virtual void Update( float flTimeDelta ); + + const matrix3x4_t& GetTransformMatrix() const; + +protected: + + CLocalSpaceEmitter( const char *pDebugName ); + + ClientEntityHandle_t m_hEntity; + int m_nAttachment; + int m_fFlags; + +private: + + CLocalSpaceEmitter( const CLocalSpaceEmitter & ); // not defined, not accessible + + // This is stored in the ParticleEffectBinding now. + //matrix3x4_t m_matTransform; + + //FIXME: Bones here as well... +}; + +#endif // PARTICLES_LOCALSPACE_H diff --git a/game/client/particles_new.h b/game/client/particles_new.h new file mode 100644 index 0000000..06d98c9 --- /dev/null +++ b/game/client/particles_new.h @@ -0,0 +1,337 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: provide client-side access to the new particle system, with similar +// usage to CSimpleEmitter +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PARTICLES_NEW_H +#define PARTICLES_NEW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particlemgr.h" +#include "particles/particles.h" +#include "particlesphererenderer.h" +#include "smartptr.h" +#include "particles_simple.h" +#include "tier1/utlobjectreference.h" + + +//----------------------------------------------------------------------------- +// Particle effect +//----------------------------------------------------------------------------- +class CNewParticleEffect : public IParticleEffect, public CParticleCollection, public CDefaultClientRenderable +{ +public: + DECLARE_CLASS_NOBASE( CNewParticleEffect ); + DECLARE_REFERENCED_CLASS( CNewParticleEffect ); + +public: + friend class CRefCountAccessor; + + // list management + CNewParticleEffect *m_pNext; + CNewParticleEffect *m_pPrev; + + // Call this before adding a bunch of particles to give it a rough estimate of where + // your particles are for sorting amongst other translucent entities. + void SetSortOrigin( const Vector &vSortOrigin ); + bool ShouldDraw( void ); + virtual bool IsTransparent( void ); + virtual bool IsTwoPass( void ); + virtual bool UsesPowerOfTwoFrameBufferTexture( void ); + virtual bool UsesFullFrameBufferTexture( void ); + const QAngle& GetRenderAngles( void ); + const matrix3x4_t& RenderableToWorldTransform(); + void GetRenderBounds( Vector& mins, Vector& maxs ); + + // check if the new bounds of the particle system needs its client-leaf info needs to be updated + void DetectChanges( void ); + const Vector &GetRenderOrigin( void ); + PMaterialHandle GetPMaterial( const char *name ); + bool RecalculateBoundingBox(); + Particle* AddParticle( unsigned int particleSize, PMaterialHandle material, const Vector &origin ); + const char *GetEffectName(); + void SetDontRemove( bool bSet ); + void SetDrawn( bool bDrawn ); + void SetFirstFrameFlag( bool bFirst ); + void SetNeedsBBoxUpdate( bool bNeedsUpdate ); + void SetAutoUpdateBBox( bool bNeedsUpdate ); + void SetRemoveFlag( void ); + bool GetRemoveFlag( void ); + bool GetFirstFrameFlag( void ); + bool GetNeedsBBoxUpdate( void ); + bool GetAutoUpdateBBox( void ); + bool ShouldPerformCullCheck() const; + void MarkShouldPerformCullCheck( bool bEnable ); + CBaseEntity *GetOwner( void ) { return m_hOwner; } + void SetOwner( CBaseEntity *pOwner ) { m_hOwner = pOwner; } + CNewParticleEffect* ReplaceWith( const char *pParticleSystemName ); + + static CSmartPtr Create( CBaseEntity *pOwner, const char *pParticleSystemName, + const char *pDebugName = NULL ); + static CSmartPtr Create( CBaseEntity *pOwner, CParticleSystemDefinition *pDef, + const char *pDebugName = NULL ); + virtual int DrawModel( int flags ); + + void DebugDrawBbox ( bool bCulled ); + + // CParticleCollection overrides +public: + void StopEmission( bool bInfiniteOnly = false, bool bRemoveAllParticles = false, bool bWakeOnStop = false ); + void SetDormant( bool bDormant ); + void SetControlPoint( int nWhichPoint, const Vector &v ); + void SetControlPointEntity( int nWhichPoint, CBaseEntity *pEntity ); + void SetControlPointOrientation( int nWhichPoint, const Quaternion &q ); + void SetControlPointOrientation( int nWhichPoint, const Vector &forward, const Vector &right, const Vector &up ); + void SetControlPointForwardVector( int nWhichPoint, const Vector &v ); + void SetControlPointUpVector( int nWhichPoint, const Vector &v ); + void SetControlPointRightVector( int nWhichPoint, const Vector &v ); + + void SetIsViewModelEffect ( bool bIsViewModelEffect ) { m_bViewModelEffect = bIsViewModelEffect; } + bool GetIsViewModelEffect () { return m_bViewModelEffect; } + + FORCEINLINE EHANDLE const &GetControlPointEntity( int nWhichPoint ) + { + return m_hControlPointOwners[ nWhichPoint ]; + } + + +// IParticleEffect overrides +public: + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ) + { + } + virtual void RenderParticles( CParticleRenderIterator *pIterator ) + { + } + + virtual void SetParticleCullRadius( float radius ); + virtual void NotifyRemove( void ); + virtual const Vector & GetSortOrigin( void ); + +// virtual void NotifyDestroyParticle( Particle* pParticle ); + virtual void Update( float flTimeDelta ); + + // All Create() functions should call this so the effect deletes itself + // when it is removed from the particle manager. + void SetDynamicallyAllocated( bool bDynamic = true ); + + virtual bool ShouldSimulate() const { return m_bSimulate; } + virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; } + + int AllocateToolParticleEffectId(); + int GetToolParticleEffectId() const; + CNewParticleEffect( CBaseEntity *pOwner, const char *pEffectName ); + CNewParticleEffect( CBaseEntity *pOwner, CParticleSystemDefinition *pEffect ); + virtual ~CNewParticleEffect(); + +protected: + // Returns nonzero if Release() has been called. + int IsReleased(); + + // Used to track down bugs. + const char *m_pDebugName; + + bool m_bDontRemove : 1; + bool m_bRemove : 1; + bool m_bDrawn : 1; + bool m_bNeedsBBoxUpdate : 1; + bool m_bIsFirstFrame : 1; + bool m_bAutoUpdateBBox : 1; + bool m_bAllocated : 1; + bool m_bSimulate : 1; + bool m_bShouldPerformCullCheck : 1; + + int m_nToolParticleEffectId; + Vector m_vSortOrigin; + EHANDLE m_hOwner; + EHANDLE m_hControlPointOwners[MAX_PARTICLE_CONTROL_POINTS]; + + // holds the min/max bounds used to manage this thing in the client leaf system + Vector m_LastMin; + Vector m_LastMax; + + bool m_bViewModelEffect; + +private: + // Update the reference count. + void AddRef(); + void Release(); + void RecordControlPointOrientation( int nWhichPoint ); + void Construct(); + + int m_RefCount; // When this goes to zero and the effect has no more active + // particles, (and it's dynamically allocated), it will delete itself. + + CNewParticleEffect( const CNewParticleEffect & ); // not defined, not accessible +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline int CNewParticleEffect::GetToolParticleEffectId() const +{ + return m_nToolParticleEffectId; +} + +inline int CNewParticleEffect::AllocateToolParticleEffectId() +{ + m_nToolParticleEffectId = ParticleMgr()->AllocateToolParticleEffectId(); + return m_nToolParticleEffectId; +} + +// Call this before adding a bunch of particles to give it a rough estimate of where +// your particles are for sorting amongst other translucent entities. +inline void CNewParticleEffect::SetSortOrigin( const Vector &vSortOrigin ) +{ + m_vSortOrigin = vSortOrigin; +} + +inline const Vector &CNewParticleEffect::GetSortOrigin( void ) +{ + return m_vSortOrigin; +} + +inline bool CNewParticleEffect::ShouldDraw( void ) +{ + return true; +} + +inline bool CNewParticleEffect::IsTransparent( void ) +{ + return CParticleCollection::IsTranslucent(); +} + +inline const QAngle& CNewParticleEffect::GetRenderAngles( void ) +{ + return vec3_angle; +} + +inline const matrix3x4_t & CNewParticleEffect::RenderableToWorldTransform() +{ + static matrix3x4_t mat; + SetIdentityMatrix( mat ); + PositionMatrix( GetRenderOrigin(), mat ); + return mat; +} + +inline Vector const &CNewParticleEffect::GetRenderOrigin( void ) +{ + return m_vSortOrigin; +} + +inline PMaterialHandle CNewParticleEffect::GetPMaterial(const char *name) +{ + //!! + Assert( 0 ); + return NULL; +} + +inline Particle* CNewParticleEffect::AddParticle( unsigned int particleSize, PMaterialHandle material, const Vector &origin ) +{ + //!! + Assert( 0 ); + return NULL; +} + + +inline const char *CNewParticleEffect::GetEffectName() +{ + return GetName(); +} + +inline void CNewParticleEffect::SetDontRemove( bool bSet ) +{ + m_bDontRemove = bSet; +} + +inline void CNewParticleEffect::SetDrawn( bool bDrawn ) +{ + m_bDrawn = bDrawn; +} + +inline void CNewParticleEffect::SetFirstFrameFlag( bool bFirst ) +{ + m_bIsFirstFrame = bFirst; +} + +inline void CNewParticleEffect::SetDynamicallyAllocated( bool bDynamic ) +{ + m_bAllocated = bDynamic; +} + +inline void CNewParticleEffect::SetNeedsBBoxUpdate( bool bNeedsUpdate ) +{ + m_bNeedsBBoxUpdate = bNeedsUpdate; +} + +inline void CNewParticleEffect::SetAutoUpdateBBox( bool bNeedsUpdate ) +{ + m_bAutoUpdateBBox = bNeedsUpdate; +} + +inline void CNewParticleEffect::SetRemoveFlag( void ) +{ + m_bRemove = true; +} + +inline bool CNewParticleEffect::GetRemoveFlag( void ) +{ + return m_bRemove; +} + +inline bool CNewParticleEffect::GetFirstFrameFlag( void ) +{ + return m_bIsFirstFrame; +} + +inline bool CNewParticleEffect::GetNeedsBBoxUpdate( void ) +{ + return m_bNeedsBBoxUpdate; +} + +inline bool CNewParticleEffect::GetAutoUpdateBBox( void ) +{ + return m_bAutoUpdateBBox; +} + +inline bool CNewParticleEffect::ShouldPerformCullCheck() const +{ + return m_bShouldPerformCullCheck; +} + +inline void CNewParticleEffect::MarkShouldPerformCullCheck( bool bEnable ) +{ + m_bShouldPerformCullCheck = bEnable; +} + +inline CSmartPtr CNewParticleEffect::Create( CBaseEntity *pOwner, const char *pParticleSystemName, const char *pDebugName ) +{ + CNewParticleEffect *pRet = new CNewParticleEffect( pOwner, pParticleSystemName ); + pRet->m_pDebugName = pDebugName ? pDebugName : pParticleSystemName; + pRet->SetDynamicallyAllocated( true ); + return pRet; +} + +inline CSmartPtr CNewParticleEffect::Create( CBaseEntity *pOwner, CParticleSystemDefinition *pDef, const char *pDebugName ) +{ + CNewParticleEffect *pRet = new CNewParticleEffect( pOwner, pDef ); + pRet->m_pDebugName = pDebugName ? pDebugName : pDef->GetName(); + pRet->SetDynamicallyAllocated( true ); + return pRet; +} + +//-------------------------------------------------------------------------------- +// If you use an HPARTICLEFFECT instead of a cnewparticleeffect *, you get a pointer +// which will go to null when the effect is deleted +//-------------------------------------------------------------------------------- +typedef CUtlReference HPARTICLEFFECT; + + +#endif // PARTICLES_NEW_H diff --git a/game/client/particles_simple.h b/game/client/particles_simple.h new file mode 100644 index 0000000..4b30f11 --- /dev/null +++ b/game/client/particles_simple.h @@ -0,0 +1,255 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PARTICLES_SIMPLE_H +#define PARTICLES_SIMPLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particlemgr.h" +#include "particlesphererenderer.h" +#include "smartptr.h" + + +// ------------------------------------------------------------------------------------------------ // +// CParticleEffect is the base class that you can derive from to make a particle effect. +// These can be used two ways: +// +// 1. Allocate a CParticleEffect-based object using the class's static Create() function. This gives +// you back a smart pointer that handles the reference counting for you. +// +// 2. Contain a CParticleEffect object in your class. +// ------------------------------------------------------------------------------------------------ // + +class CParticleEffect : public IParticleEffect +{ +public: + DECLARE_CLASS_NOBASE( CParticleEffect ); + + friend class CRefCountAccessor; + + // Call this before adding a bunch of particles to give it a rough estimate of where + // your particles are for sorting amongst other translucent entities. + void SetSortOrigin( const Vector &vSortOrigin ); + + PMaterialHandle GetPMaterial(const char *name); + + Particle* AddParticle( unsigned int particleSize, PMaterialHandle material, const Vector &origin ); + + CParticleEffectBinding& GetBinding() { return m_ParticleEffect; } + + const char *GetEffectName(); + + void AddFlags( int iFlags ) { m_Flags |= iFlags; } + void RemoveFlags( int iFlags ) { m_Flags &= ~iFlags; } + + void SetDontRemove( bool bSet ) + { + if( bSet ) + AddFlags( FLAG_DONT_REMOVE ); + else + RemoveFlags( FLAG_DONT_REMOVE ); + } + +// IParticleEffect overrides +public: + + virtual void SetParticleCullRadius( float radius ); + virtual void NotifyRemove( void ); + virtual const Vector & GetSortOrigin(); + virtual void NotifyDestroyParticle( Particle* pParticle ); + virtual void Update( float flTimeDelta ); + + // All Create() functions should call this so the effect deletes itself + // when it is removed from the particle manager. + void SetDynamicallyAllocated( bool bDynamic=true ); + + virtual bool ShouldSimulate() const { return m_bSimulate; } + virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; } + + int AllocateToolParticleEffectId(); + int GetToolParticleEffectId() const; +protected: + CParticleEffect( const char *pDebugName ); + virtual ~CParticleEffect(); + + // Returns nonzero if Release() has been called. + int IsReleased(); + + enum + { + FLAG_ALLOCATED = (1<<1), // Most of the CParticleEffects are dynamically allocated but + // some are member variables of a class. If they're member variables. + FLAG_DONT_REMOVE = (1<<2), + }; + + // Used to track down bugs. + char const *m_pDebugName; + + CParticleEffectBinding m_ParticleEffect; + Vector m_vSortOrigin; + + int m_Flags; // Combination of CParticleEffect::FLAG_ + + bool m_bSimulate; + int m_nToolParticleEffectId; + +private: + // Update the reference count. + void AddRef(); + void Release(); + + int m_RefCount; // When this goes to zero and the effect has no more active + // particles, (and it's dynamically allocated), it will delete itself. + + CParticleEffect( const CParticleEffect & ); // not defined, not accessible +}; + +inline int CParticleEffect::GetToolParticleEffectId() const +{ + return m_nToolParticleEffectId; +} + +inline int CParticleEffect::AllocateToolParticleEffectId() +{ + m_nToolParticleEffectId = ParticleMgr()->AllocateToolParticleEffectId(); + return m_nToolParticleEffectId; +} + + +//----------------------------------------------------------------------------- +// Particle flags +//----------------------------------------------------------------------------- +enum SimpleParticleFlag_t +{ + SIMPLE_PARTICLE_FLAG_WINDBLOWN = 0x1, + SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY = 0x2 // Used by the blood spray emitter. By default, it decays the + // particle velocity. +}; + +class SimpleParticle : public Particle +{ +public: + SimpleParticle() : m_iFlags(0) {} + + // AddSimpleParticle automatically initializes these fields. + Vector m_vecVelocity; + float m_flRoll; + float m_flDieTime; // How long it lives for. + float m_flLifetime; // How long it has been alive for so far. + unsigned char m_uchColor[3]; + unsigned char m_uchStartAlpha; + unsigned char m_uchEndAlpha; + unsigned char m_uchStartSize; + unsigned char m_uchEndSize; + unsigned char m_iFlags; // See SimpleParticleFlag_t above + float m_flRollDelta; +}; + + + +// CSimpleEmitter implements a common way to simulate and render particles. +// +// Effects can add particles to the particle manager and point at CSimpleEmitter +// for the effect so they don't have to implement the simulation code. It simulates +// velocity, and fades their alpha from invisible to solid and back to invisible over their lifetime. +// +// Particles you add using this effect must use the class CParticleSimple::Particle. +class CSimpleEmitter : public CParticleEffect +{ +// IParticleEffect overrides. +public: + + DECLARE_CLASS( CSimpleEmitter, CParticleEffect ); + + static CSmartPtr Create( const char *pDebugName ); + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + + void SetNearClip( float nearClipMin, float nearClipMax ); + + void SetDrawBeforeViewModel( bool state = true ); + + SimpleParticle* AddSimpleParticle( PMaterialHandle hMaterial, const Vector &vOrigin, float flDieTime=3, unsigned char uchSize=10 ); + +// Overridables for variants like CEmberEffect. +protected: + CSimpleEmitter( const char *pDebugName = NULL ); + virtual ~CSimpleEmitter(); + + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + virtual float UpdateScale( const SimpleParticle *pParticle ); + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ); + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + virtual Vector UpdateColor( const SimpleParticle *pParticle ); + + float m_flNearClipMin; + float m_flNearClipMax; + +private: + CSimpleEmitter( const CSimpleEmitter & ); // not defined, not accessible +}; + +//================================================== +// EmberEffect +//================================================== + +class CEmberEffect : public CSimpleEmitter +{ +public: + CEmberEffect( const char *pDebugName ); + static CSmartPtr Create( const char *pDebugName ); + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + virtual Vector UpdateColor( const SimpleParticle *pParticle ); + +private: + CEmberEffect( const CEmberEffect & ); // not defined, not accessible +}; + + +//================================================== +// FireSmokeEffect +//================================================== + +class CFireSmokeEffect : public CSimpleEmitter +{ +public: + CFireSmokeEffect( const char *pDebugName ); + static CSmartPtr Create( const char *pDebugName ); + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + +protected: + VPlane m_planeClip; + +private: + CFireSmokeEffect( const CFireSmokeEffect & ); // not defined, not accessible +}; + + +//================================================== +// CFireParticle +//================================================== + +class CFireParticle : public CSimpleEmitter +{ +public: + CFireParticle( const char *pDebugName ); + static CSmartPtr Create( const char *pDebugName ); + + virtual Vector UpdateColor( const SimpleParticle *pParticle ); + +private: + CFireParticle( const CFireParticle & ); // not defined, not accessible +}; + + +#endif // PARTICLES_SIMPLE_H diff --git a/game/client/particlesphererenderer.h b/game/client/particlesphererenderer.h new file mode 100644 index 0000000..ac0f96b --- /dev/null +++ b/game/client/particlesphererenderer.h @@ -0,0 +1,229 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PARTICLESPHERERENDERER_H +#define PARTICLESPHERERENDERER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "particlemgr.h" +#include "particle_util.h" + + +class CParticleSphereRenderer +{ +public: + + CParticleSphereRenderer(); + + // Initialize and tell it the material you'll be using. + void Init( CParticleMgr *pParticleMgr, IMaterial *pMaterial ); + + // Pass this call through from your particle system too. + void StartRender( VMatrix &effectMatrix ); + + // Call this to render a spherical particle. + void RenderParticle( + ParticleDraw *pDraw, + const Vector &vOriginalPos, + const Vector &vTransformedPos, + float flAlpha, // value 0 - 255.4 + float flParticleSize, + float flAngle = 0.0f ); + + void RenderParticle_AddColor( + ParticleDraw *pDraw, + const Vector &vOriginalPos, + const Vector &vTransformedPos, + float flAlpha, // value 0 - 255.4 + float flParticleSize, + const Vector &vToAdd0to1 // Add this to the color (value 0-1) + ); + + + // Lighting is (base color) + (ambient / dist^2) + bump(directional / dist^2) + const Vector& GetBaseColor() const; // Specified as 0-1 + void SetBaseColor( const Vector &vColor ); + + const CParticleLightInfo& GetAmbientLight() const; + void SetAmbientLight( const CParticleLightInfo &info ); + + const CParticleLightInfo& GetDirectionalLight() const; + void SetDirectionalLight( const CParticleLightInfo &info ); + + +private: + + void AddLightColor( + Vector const *pPos, + Vector const *pLightPos, + Vector const *pLightColor, + float flLightIntensity, + Vector *pOutColor ); + + inline void ClampColor( Vector &vColor ); + + +private: + + int m_iLastTickStartRenderCalled; // Used for debugging. + + CParticleMgr *m_pParticleMgr; + + Vector m_vBaseColor; + CParticleLightInfo m_AmbientLight; + CParticleLightInfo m_DirectionalLight; + bool m_bUsingPixelShaders; +}; + + +// ------------------------------------------------------------------------ // +// Inlines. +// ------------------------------------------------------------------------ // + +inline void CParticleSphereRenderer::AddLightColor( + Vector const *pPos, + Vector const *pLightPos, + Vector const *pLightColor, + float flLightIntensity, + Vector *pOutColor ) +{ + if( flLightIntensity ) + { + float fDist = pPos->DistToSqr( *pLightPos ); + float fAmt; + if( fDist > 0.0001f ) + fAmt = flLightIntensity / fDist; + else + fAmt = 1000.f; + + *pOutColor += *pLightColor * fAmt; + } +} + + +inline void CParticleSphereRenderer::ClampColor( Vector &vColor ) +{ + float flMax = MAX( vColor.x, MAX( vColor.y, vColor.z ) ); + if( flMax > 1 ) + { + vColor *= 255.0f / flMax; + } + else + { + vColor *= 255.0; + } +} + + +inline const Vector& CParticleSphereRenderer::GetBaseColor() const +{ + return m_vBaseColor; +} + +inline void CParticleSphereRenderer::SetBaseColor( const Vector &vColor ) +{ + m_vBaseColor = vColor; +} + +inline const CParticleLightInfo& CParticleSphereRenderer::GetAmbientLight() const +{ + return m_AmbientLight; +} + +inline void CParticleSphereRenderer::SetAmbientLight( const CParticleLightInfo &info ) +{ + m_AmbientLight = info; +} + +inline const CParticleLightInfo& CParticleSphereRenderer::GetDirectionalLight() const +{ + return m_DirectionalLight; +} + +inline void CParticleSphereRenderer::SetDirectionalLight( const CParticleLightInfo &info ) +{ + m_DirectionalLight = info; +} + +inline void CParticleSphereRenderer::RenderParticle( + ParticleDraw *pDraw, + const Vector &vOriginalPos, + const Vector &vTransformedPos, + float flAlpha, + float flParticleSize, + float flAngle ) +{ + // Make sure they called StartRender on us so we were able to set the directional light parameters. +#ifdef _DEBUG + if ( pDraw->GetMeshBuilder() ) + { + Assert( m_iLastTickStartRenderCalled == gpGlobals->tickcount ); + } +#endif + + Vector vColor = m_vBaseColor; + AddLightColor( &vOriginalPos, &m_AmbientLight.m_vPos, &m_AmbientLight.m_vColor, m_AmbientLight.m_flIntensity, &vColor ); + + // If the DX8 shader isn't going to handle the directional light color, then add its contribution here. + if( !m_bUsingPixelShaders ) + { + AddLightColor( &vOriginalPos, &m_DirectionalLight.m_vPos, &m_DirectionalLight.m_vColor, m_DirectionalLight.m_flIntensity, &vColor ); + } + + ClampColor( vColor ); + + RenderParticle_Color255SizeNormalAngle( + pDraw, + vTransformedPos, + vColor, // ambient color + flAlpha, // alpha + flParticleSize, + vec3_origin, + flAngle ); +} + +inline void CParticleSphereRenderer::RenderParticle_AddColor( + ParticleDraw *pDraw, + const Vector &vOriginalPos, + const Vector &vTransformedPos, + float flAlpha, + float flParticleSize, + const Vector &vToAdd0to1 + ) +{ + // Make sure they called StartRender on us so we were able to set the directional light parameters. +#ifdef _DEBUG + if ( pDraw->GetMeshBuilder() ) + { + Assert( m_iLastTickStartRenderCalled == gpGlobals->tickcount ); + } +#endif + + Vector vColor = m_vBaseColor + vToAdd0to1; + AddLightColor( &vOriginalPos, &m_AmbientLight.m_vPos, &m_AmbientLight.m_vColor, m_AmbientLight.m_flIntensity, &vColor ); + + // If the DX8 shader isn't going to handle the directional light color, then add its contribution here. + if( !m_bUsingPixelShaders ) + { + AddLightColor( &vOriginalPos, &m_DirectionalLight.m_vPos, &m_DirectionalLight.m_vColor, m_DirectionalLight.m_flIntensity, &vColor ); + } + + ClampColor( vColor ); + + RenderParticle_Color255Size( + pDraw, + vTransformedPos, + vColor, // ambient color + flAlpha, // alpha + flParticleSize ); +} + + +#endif // PARTICLESPHERERENDERER_H diff --git a/game/client/perfvisualbenchmark.h b/game/client/perfvisualbenchmark.h new file mode 100644 index 0000000..7714b52 --- /dev/null +++ b/game/client/perfvisualbenchmark.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined PERFVISUALBENCHMARK_H +#define PERFVISUALBENCHMARK_H + +#define FPS_STABILIZE_TIME 1.5 +#define FPS_STABILIZE_TIME_RELOAD_MATERIALS 10.0 +#define FPS_MEASURE_TIME 2.0 + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +class CPerfVisualBenchmark : public CBaseGameSystemPerFrame +{ + +public: + CPerfVisualBenchmark(); + virtual ~CPerfVisualBenchmark(); + +public: // CBaseGameSystem overrides + + virtual char const *Name() { return "CPerfVisualBenchmark"; } + + virtual bool Init(); + virtual void PreRender( ); + + void Start(); + void Stop(); + +private: + void Print(); + struct RunInfo_t + { + const char *m_pVarName; + const char *m_pOnVal; + const char *m_pOffVal; + const char *m_pDescription; + float m_flStabilizeTime; + float m_flFPS; + }; + +private: + CUtlVector m_RunInfo; + bool m_bIsOn; //is this thing on? + int m_iCurVar; //what convar are we at? + float m_flTimer; //time since we started measuring the current convar + float m_flStartMeasureTime; + int m_nStartFrameCount; + bool m_bSaveMouseEnable; // remember this so that we can reset it after the benchmark + bool m_bWaiting; +}; + +extern IGameSystem* PerfVisualBenchmark(); + +#endif // PERFVISUALBENCHMARK_H diff --git a/game/client/physics.h b/game/client/physics.h new file mode 100644 index 0000000..9da17e0 --- /dev/null +++ b/game/client/physics.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: insulates client DLL from dependencies on vphysics +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHYSICS_H +#define PHYSICS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "interface.h" +#include "physics_shared.h" + +struct objectparams_t; +struct solid_t; + +// HACKHACK: Make this part of IClientSystem somehow??? +extern bool PhysicsDLLInit( CreateInterfaceFn physicsFactory ); +extern void PhysicsReset(); +extern void PhysicsSimulate(); +extern float PhysGetSyncCreateTime(); + +#endif // PHYSICS_H diff --git a/game/client/physpropclientside.h b/game/client/physpropclientside.h new file mode 100644 index 0000000..b305fbf --- /dev/null +++ b/game/client/physpropclientside.h @@ -0,0 +1,167 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSPROPCLIENTSIDE_H +#define PHYSPROPCLIENTSIDE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_breakableprop.h" +#include "props_shared.h" + +class C_FuncPhysicsRespawnZone; + +class C_PhysPropClientside : public C_BreakableProp, public IBreakableWithPropData, public IMultiplayerPhysics +{ + +public: + DECLARE_CLASS( C_PhysPropClientside, C_BreakableProp ); + + C_PhysPropClientside(); + virtual ~C_PhysPropClientside(); + + bool Initialize(); + void Spawn(); + int ParsePropData( void ); + virtual bool IsDormant( void ) { return false; } // we could add a PVS check here + virtual void ClientThink( void ); + virtual CollideType_t GetCollideType( void ) { return ENTITY_SHOULD_RESPOND; } + virtual void StartTouch( C_BaseEntity *pOther ); + virtual void HitSurface( C_BaseEntity *pOther ); + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + virtual bool IsClientCreated( void ) const { return true; } + virtual int GetMultiplayerPhysicsMode() { return m_iPhysicsMode; } + virtual float GetMass(); + virtual bool IsAsleep(); + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual void OnTakeDamage( int iDamage ); // very simple version + virtual void Break(); + virtual void Clone( Vector &velocity ); + virtual void StartFadeOut( float fTime ); + virtual void SetHealth(int iHealth) { m_iHealth = iHealth; } + virtual int GetHealth() const { return m_iHealth; } + int GetNumBreakableChunks( void ) { return m_iNumBreakableChunks; } + + void SetRespawnZone( C_FuncPhysicsRespawnZone *pZone ); + +// IBreakableWithPropData interface: +public: +// IBreakableWithPropData + void SetDmgModBullet( float flDmgMod ) { m_flDmgModBullet = flDmgMod; } + void SetDmgModClub( float flDmgMod ) { m_flDmgModClub = flDmgMod; } + void SetDmgModExplosive( float flDmgMod ) { m_flDmgModExplosive = flDmgMod; } + float GetDmgModBullet( void ) { return m_flDmgModBullet; } + float GetDmgModClub( void ) { return m_flDmgModClub; } + float GetDmgModExplosive( void ) { return m_flDmgModExplosive; } + void SetExplosiveRadius( float flRadius ) { m_explodeRadius = flRadius; } + void SetExplosiveDamage( float flDamage ) { m_explodeDamage = flDamage; } + float GetExplosiveRadius( void ) { return m_explodeRadius; } + float GetExplosiveDamage( void ) { return m_explodeDamage; } + void SetPhysicsDamageTable( string_t iszTableName ) { m_iszPhysicsDamageTableName = iszTableName; } + string_t GetPhysicsDamageTable( void ) { return m_iszPhysicsDamageTableName; } + void SetBreakableModel( string_t iszModel ) { m_iszBreakableModel = iszModel; } + string_t GetBreakableModel( void ) { return m_iszBreakableModel; } + void SetBreakableSkin( int iSkin ) { m_iBreakableSkin = iSkin; } + int GetBreakableSkin( void ) { return m_iBreakableSkin; } + void SetBreakableCount( int iCount ) { m_iBreakableCount = iCount; } + int GetBreakableCount( void ) { return m_iBreakableCount; } + void SetMaxBreakableSize( int iSize ) { m_iMaxBreakableSize = iSize; } + int GetMaxBreakableSize( void ) { return m_iMaxBreakableSize; } + void SetPropDataBlocksLOS( bool bBlocksLOS ) { m_bBlockLOSSetByPropData = true; SetBlocksLOS( bBlocksLOS ); } + void SetPropDataIsAIWalkable( bool b ) { m_bIsWalkableSetByPropData = true; SetAIWalkable( b ); } + void SetBasePropData( string_t iszBase ) { m_iszBasePropData = iszBase; } + string_t GetBasePropData( void ) { return m_iszBasePropData; } + void SetInteraction( propdata_interactions_t Interaction ) { m_iInteractions |= (1 << Interaction); } + bool HasInteraction( propdata_interactions_t Interaction ) { return ( m_iInteractions & (1 << Interaction) ) != 0; } + void SetPhysicsMode(int iMode); + int GetPhysicsMode() { return m_iPhysicsMode; } + void SetMultiplayerBreakMode( mp_break_t mode ) {} + mp_break_t GetMultiplayerBreakMode( void ) const { return MULTIPLAYER_BREAK_DEFAULT; } + + +// static management fucntions: + static void RecreateAll(); // recreate all clientside props in map + static void DestroyAll(); // clear all clientside created phys props + static C_PhysPropClientside *CreateNew(bool bForce = false); + +protected: + + static void ParseAllEntities(const char *pMapData); + static const char *ParseEntity( const char *pEntData ); + static void InitializePropRespawnZones(void); + +public: + + int m_iPhysicsMode; // should always be PHYSICS_MULTIPLAYER_CLIENTSIDE + float m_flTouchDelta; // Amount of time that must pass before another touch function can be called + float m_fDeathTime; // Point at which this object self destructs. + // The default of -1 indicates the object shouldn't destruct. + +// properties from serverclass CPhysicsProp + float m_impactEnergyScale; + int m_spawnflags; + float m_inertiaScale; + +protected: +// Prop data storage + float m_flDmgModBullet; + float m_flDmgModClub; + float m_flDmgModExplosive; + string_t m_iszPhysicsDamageTableName; + string_t m_iszBreakableModel; + int m_iBreakableSkin; + int m_iBreakableCount; + int m_iMaxBreakableSize; + string_t m_iszBasePropData; + int m_iInteractions; + float m_explodeDamage; + float m_explodeRadius; + bool m_bBlockLOSSetByPropData; + bool m_bIsWalkableSetByPropData; + + // Count of how many pieces we'll break into, custom or generic + int m_iNumBreakableChunks; + + C_FuncPhysicsRespawnZone *m_pRespawnZone; +}; + +//----------------------------------------------------------------------------- +// Purpose: A clientside zone that respawns physics props in it when the player leaves the PVS +//----------------------------------------------------------------------------- +class C_FuncPhysicsRespawnZone : public C_BaseEntity +{ + DECLARE_CLASS( C_FuncPhysicsRespawnZone, C_BaseEntity ); +public: + + C_FuncPhysicsRespawnZone( void ); + ~C_FuncPhysicsRespawnZone( void ); + + bool KeyValue( const char *szKeyName, const char *szValue ); + bool Initialize( void ); + void InitializePropsWithin( void ); + void PropDestroyed( C_PhysPropClientside *pProp ); + bool CanMovePropAt( Vector vecOrigin, const Vector &vecMins, const Vector &vecMaxs ); + void RespawnProps( void ); + void ClientThink( void ); + +private: + struct clientsideproprespawn_t + { + string_t iszModelName; + Vector vecOrigin; + QAngle vecAngles; + int iSkin; + int iHealth; + int iSpawnFlags; + ClientEntityHandle_t hClientEntity; + }; + CUtlVector m_PropList; +}; + +#endif // PHYSPROPCLIENTSIDE_H diff --git a/game/client/playerandobjectenumerator.h b/game/client/playerandobjectenumerator.h new file mode 100644 index 0000000..0f6fa2d --- /dev/null +++ b/game/client/playerandobjectenumerator.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERANDOBJECTENUMERATOR_H +#define PLAYERANDOBJECTENUMERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "ehandle.h" +#include "ispatialpartition.h" + +class C_BaseEntity; +class C_BasePlayer; + +// Enumator class for finding other players and objects close to the +// local player +class CPlayerAndObjectEnumerator : public IPartitionEnumerator +{ + DECLARE_CLASS_NOBASE( CPlayerAndObjectEnumerator ); +public: + //Forced constructor + CPlayerAndObjectEnumerator( float radius ); + + //Actual work code + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + + int GetObjectCount(); + C_BaseEntity *GetObject( int index ); + +public: + //Data members + float m_flRadiusSquared; + + CUtlVector< CHandle< C_BaseEntity > > m_Objects; + C_BasePlayer *m_pLocal; +}; + +#endif // PLAYERANDOBJECTENUMERATOR_H diff --git a/game/client/playerenumerator.h b/game/client/playerenumerator.h new file mode 100644 index 0000000..974fb7d --- /dev/null +++ b/game/client/playerenumerator.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERENUMERATOR_H +#define PLAYERENUMERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "ehandle.h" +#include "ispatialpartition.h" + +class C_BaseEntity; + +class CPlayerEnumerator : public IPartitionEnumerator +{ + DECLARE_CLASS_NOBASE( CPlayerEnumerator ); +public: + //Forced constructor + CPlayerEnumerator( float radius, Vector vecOrigin ) + { + m_flRadiusSquared = radius * radius; + m_vecOrigin = vecOrigin; + m_Objects.RemoveAll(); + } + + int GetObjectCount() { return m_Objects.Size(); } + + C_BaseEntity *GetObject( int index ) + { + if ( index < 0 || index >= GetObjectCount() ) + return NULL; + + return m_Objects[ index ]; + } + + //Actual work code + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) + { + C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); + if ( pEnt == NULL ) + return ITERATION_CONTINUE; + + if ( !pEnt->IsPlayer() ) + return ITERATION_CONTINUE; + + Vector deltaPos = pEnt->GetAbsOrigin() - m_vecOrigin; + if ( deltaPos.LengthSqr() > m_flRadiusSquared ) + return ITERATION_CONTINUE; + + CHandle< C_BaseEntity > h; + h = pEnt; + m_Objects.AddToTail( h ); + + return ITERATION_CONTINUE; + } + +public: + //Data members + float m_flRadiusSquared; + Vector m_vecOrigin; + + CUtlVector< CHandle< C_BaseEntity > > m_Objects; +}; + +#endif // PLAYERENUMERATOR_H \ No newline at end of file diff --git a/game/client/playerspawncache.h b/game/client/playerspawncache.h new file mode 100644 index 0000000..0669c56 --- /dev/null +++ b/game/client/playerspawncache.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef PLAYERSPAWNCACHE_H +#define PLAYERSPAWNCACHE_H +#ifdef _WIN32 +#pragma once +#endif + +//-------------------------------------------------------------------------------- + +#include "GameEventListener.h" + +//-------------------------------------------------------------------------------- + +// +// Im not sure if player spawn cache is the most descriptive name, but essentially +// there is a singleton instance of CPlayerSpawnCache for the local player which has +// a set of counters/pointers/etc. that get cleared every time a map loads. This +// can be useful for situations where a players net connection chokes and they get +// a full update, which recreates their C_TF_Player entirely or otherwise invalidates +// a bunch of data in the local player. I believe its already known that there is +// a class of bugs stemming from this behavior. +// +// Right now the cache is used as a way to display a message to the player if they +// connect to a server thats recording replays. As soon as they choose their player +// class, a counter is checked, and if its zero the message is displayed. The counter +// is then incremented. This is a sort of odd use for it actually. A better example +// would be what Im going to do next, which is that if the players net connection +// chokes (or if you host_timescale at too great a speed and cause a full update on the +// client), the replay system will think that youve already saved a replay for that life. +// So this example will be a perfect time to use the player spawn cache because you can +// maintain some level of persistence in the face of your entire local player getting +// nuked. +// +// Just add any data members you'd like to access to the CPlayerSpawnCache::Data_t +// struct and it will be cleared automatically (via a memset) whenever a new map is +// loaded. +// +// It's possible that PreReset()/PostReset() or the like will be necessary for this +// class to reach its full potential. +// +class CPlayerSpawnCache : public CGameEventListener +{ +public: + static CPlayerSpawnCache &Instance(); + + // Counters + struct Data_t + { + int m_nDisplayedConnectedRecording; + int m_nDisplaySaveReplay; // Don't display the "Press [f6] to save this life" the first time the spectator GUI is shown + } m_Data; + +private: + CPlayerSpawnCache(); + + virtual void FireGameEvent( IGameEvent *pEvent ); + + void Reset(); +}; + +//-------------------------------------------------------------------------------- + +#endif // PLAYERSPAWNCACHE_H diff --git a/game/client/prediction.h b/game/client/prediction.h new file mode 100644 index 0000000..1a77f0a --- /dev/null +++ b/game/client/prediction.h @@ -0,0 +1,151 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( PREDICTION_H ) +#define PREDICTION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "iprediction.h" +#include "c_baseplayer.h" +#include "cdll_bounded_cvars.h" + +class CMoveData; +class CUserCmd; + +//----------------------------------------------------------------------------- +// Purpose: Implements prediction in the client .dll +//----------------------------------------------------------------------------- +class CPrediction : public IPrediction +{ +// Construction +public: + DECLARE_CLASS_GAMEROOT( CPrediction, IPrediction ); + + CPrediction( void ); + virtual ~CPrediction( void ); + + virtual void Init( void ); + virtual void Shutdown( void ); + +// Implement IPrediction +public: + + virtual void Update + ( + int startframe, // World update ( un-modded ) most recently received + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ); + + virtual void OnReceivedUncompressedPacket( void ); + + virtual void PreEntityPacketReceived( int commands_acknowledged, int current_world_update_packet ); + virtual void PostEntityPacketReceived( void ); + virtual void PostNetworkDataReceived( int commands_acknowledged ); + + virtual bool InPrediction( void ) const; + virtual bool IsFirstTimePredicted( void ) const; + +#if !defined( NO_ENTITY_PREDICTION ) + virtual int GetIncomingPacketNumber( void ) const; +#endif + + float GetIdealPitch( void ) const + { + return m_flIdealPitch; + } + + // The engine needs to be able to access a few predicted values + virtual void GetViewOrigin( Vector& org ); + virtual void SetViewOrigin( Vector& org ); + virtual void GetViewAngles( QAngle& ang ); + virtual void SetViewAngles( QAngle& ang ); + + virtual void GetLocalViewAngles( QAngle& ang ); + virtual void SetLocalViewAngles( QAngle& ang ); + + virtual void RunCommand( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *moveHelper ); + +// Internal +protected: + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ); + virtual void SetIdealPitch ( C_BasePlayer *player, const Vector& origin, const QAngle& angles, const Vector& viewheight ); + + void CheckError( int commands_acknowledged ); + + // Called before and after any movement processing + void StartCommand( C_BasePlayer *player, CUserCmd *cmd ); + void FinishCommand( C_BasePlayer *player ); + + // Helpers to call pre and post think for player, and to call think if a think function is set + void RunPreThink( C_BasePlayer *player ); + void RunThink (C_BasePlayer *ent, double frametime ); + void RunPostThink( C_BasePlayer *player ); + +private: + virtual void _Update + ( + bool received_new_world_update, + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ); + + // Actually does the prediction work, returns false if an error occurred + bool PerformPrediction( bool received_new_world_update, C_BasePlayer *localPlayer, int incoming_acknowledged, int outgoing_command ); + + void ShiftIntermediateDataForward( int slots_to_remove, int previous_last_slot ); + void RestoreEntityToPredictedFrame( int predicted_frame ); + int ComputeFirstCommandToExecute( bool received_new_world_update, int incoming_acknowledged, int outgoing_command ); + + void DumpEntity( C_BaseEntity *ent, int commands_acknowledged ); + + void ShutdownPredictables( void ); + void ReinitPredictables( void ); + + void RemoveStalePredictedEntities( int last_command_packet ); + void RestoreOriginalEntityState( void ); + void RunSimulation( int current_command, float curtime, CUserCmd *cmd, C_BasePlayer *localPlayer ); + void Untouch( void ); + void StorePredictionResults( int predicted_frame ); + bool ShouldDumpEntity( C_BaseEntity *ent ); + + void SmoothViewOnMovingPlatform( C_BasePlayer *pPlayer, Vector& offset ); + +#if !defined( NO_ENTITY_PREDICTION ) +// Data +protected: + // Last object the player was standing on + CHandle< C_BaseEntity > m_hLastGround; +private: + bool m_bInPrediction; + bool m_bFirstTimePredicted; + bool m_bOldCLPredictValue; + bool m_bEnginePaused; + + // Last network origin for local player + int m_nPreviousStartFrame; + + int m_nCommandsPredicted; + int m_nServerCommandsAcknowledged; + int m_bPreviousAckHadErrors; + int m_nIncomingPacketNumber; + +#endif + float m_flIdealPitch; + +}; + +extern CPrediction *prediction; + +#endif // PREDICTION_H \ No newline at end of file diff --git a/game/client/prediction_private.h b/game/client/prediction_private.h new file mode 100644 index 0000000..9f1832c --- /dev/null +++ b/game/client/prediction_private.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( PREDICTION_PRIVATE_H ) +#define PREDICTION_PRIVATE_H +#ifdef _WIN32 +#pragma once +#endif + +// point on plane side epsilon +#define ON_EPSILON 0.1 + +#define MAX_FORWARD 6 + +// Use smoothing if error is > this +#define MIN_CORRECTION_DISTANCE 0.25f + +// Complain if error is > this and we have cl_showerror set +#define MIN_PREDICTION_EPSILON 0.5f + +// Above this is assumed to be a teleport, don't smooth, etc. +#define MAX_PREDICTION_ERROR 64.0f + +#endif // PREDICTION_PRIVATE_H \ No newline at end of file diff --git a/game/client/proxyentity.h b/game/client/proxyentity.h new file mode 100644 index 0000000..5084a4e --- /dev/null +++ b/game/client/proxyentity.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A base class for all material proxies in the client dll +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROXY_ENTITY_H +#define PROXY_ENTITY_H + +#include "materialsystem/imaterialproxy.h" + + +class IMaterialVar; + +//----------------------------------------------------------------------------- +// Base class all material proxies should inherit from +//----------------------------------------------------------------------------- +abstract_class CEntityMaterialProxy : public IMaterialProxy +{ +public: + virtual void Release( void ); + virtual void OnBind( void *pC_BaseEntity ); + +protected: + // base classes should implement these + virtual void OnBind( C_BaseEntity *pBaseEntity ) = 0; +}; + + +#endif // PROXY_ENTITY_H + diff --git a/game/client/ragdoll.h b/game/client/ragdoll.h new file mode 100644 index 0000000..6f5056f --- /dev/null +++ b/game/client/ragdoll.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef RAGDOLL_H +#define RAGDOLL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "ragdoll_shared.h" + +#define RAGDOLL_VISUALIZE 0 + +class C_BaseEntity; +class CStudioHdr; +struct mstudiobone_t; +class Vector; +class IPhysicsObject; +class CBoneAccessor; + +abstract_class IRagdoll +{ +public: + virtual ~IRagdoll() {} + + virtual void RagdollBone( C_BaseEntity *ent, mstudiobone_t *pbones, int boneCount, bool *boneSimulated, CBoneAccessor &pBoneToWorld ) = 0; + virtual const Vector& GetRagdollOrigin( ) = 0; + virtual void GetRagdollBounds( Vector &mins, Vector &maxs ) = 0; + virtual int RagdollBoneCount() const = 0; + virtual IPhysicsObject *GetElement( int elementNum ) = 0; + virtual void DrawWireframe( void ) = 0; + virtual void VPhysicsUpdate( IPhysicsObject *pObject ) = 0; + virtual bool TransformVectorToWorld(int boneIndex, const Vector *vTemp, Vector *vOut) = 0; +}; + +class CRagdoll : public IRagdoll +{ +public: + CRagdoll(); + ~CRagdoll( void ); + + DECLARE_SIMPLE_DATADESC(); + + void Init( + C_BaseEntity *ent, + CStudioHdr *pstudiohdr, + const Vector &forceVector, + int forceBone, + const matrix3x4_t *pDeltaBones0, + const matrix3x4_t *pDeltaBones1, + const matrix3x4_t *pCurrentBonePosition, + float boneDt, + bool bFixedConstraints=false ); + + virtual void RagdollBone( C_BaseEntity *ent, mstudiobone_t *pbones, int boneCount, bool *boneSimulated, CBoneAccessor &pBoneToWorld ); + virtual const Vector& GetRagdollOrigin( ); + virtual void GetRagdollBounds( Vector &theMins, Vector &theMaxs ); + void BuildRagdollBounds( C_BaseEntity *ent ); + + virtual IPhysicsObject *GetElement( int elementNum ); + virtual IPhysicsConstraintGroup *GetConstraintGroup() { return m_ragdoll.pGroup; } + virtual void DrawWireframe(); + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + virtual int RagdollBoneCount() const { return m_ragdoll.listCount; } + //============================================================================= + // HPE_BEGIN: + // [menglish] Transforms a vector from the given bone's space to world space + //============================================================================= + + virtual bool TransformVectorToWorld(int iBoneIndex, const Vector *vTemp, Vector *vOut); + + //============================================================================= + // HPE_END + //============================================================================= + + + void SetInitialBonePosition( CStudioHdr *pstudiohdr, const CBoneAccessor &pDesiredBonePosition ); + + bool IsValid() { return m_ragdoll.listCount > 0; } + + void ResetRagdollSleepAfterTime( void ); + float GetLastVPhysicsUpdateTime() const { return m_lastUpdate; } + +private: + + void CheckSettleStationaryRagdoll(); + void PhysForceRagdollToSleep(); + + ragdoll_t m_ragdoll; + Vector m_mins, m_maxs; + Vector m_origin; + float m_radius; + float m_lastUpdate; + bool m_allAsleep; + Vector m_vecLastOrigin; + float m_flLastOriginChangeTime; + +#if RAGDOLL_VISUALIZE + matrix3x4_t m_savedBone1[MAXSTUDIOBONES]; + matrix3x4_t m_savedBone2[MAXSTUDIOBONES]; + matrix3x4_t m_savedBone3[MAXSTUDIOBONES]; +#endif + +public: + + ragdoll_t *GetRagdoll( void ){ return &m_ragdoll; } +}; + + +CRagdoll *CreateRagdoll( + C_BaseEntity *ent, + CStudioHdr *pstudiohdr, + const Vector &forceVector, + int forceBone, + const matrix3x4_t *pDeltaBones0, + const matrix3x4_t *pDeltaBones1, + const matrix3x4_t *pCurrentBonePosition, + float boneDt, + bool bFixedConstraints=false ); + + +// save this ragdoll's creation as the current tick +void NoteRagdollCreationTick( C_BaseEntity *pRagdoll ); +// returns true if the ragdoll was created on this tick +bool WasRagdollCreatedOnCurrentTick( C_BaseEntity *pRagdoll ); + +#endif // RAGDOLL_H \ No newline at end of file diff --git a/game/client/ragdollexplosionenumerator.h b/game/client/ragdollexplosionenumerator.h new file mode 100644 index 0000000..a027e19 --- /dev/null +++ b/game/client/ragdollexplosionenumerator.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RAGDOLLEXPLOSIONENUMERATOR_H +#define RAGDOLLEXPLOSIONENUMERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ispatialpartition.h" + +//Enumator class for ragdolls being affected by explosive forces +class CRagdollExplosionEnumerator : public IPartitionEnumerator +{ + DECLARE_CLASS_GAMEROOT( CRagdollExplosionEnumerator, IPartitionEnumerator ); +public: + //Forced constructor + CRagdollExplosionEnumerator( Vector origin, float radius, float magnitude ); + ~CRagdollExplosionEnumerator(); + + //Actual work code + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + +public: + //Data members + CUtlVector m_Entities; + Vector m_vecOrigin; + float m_flMagnitude; + float m_flRadius; +}; + +#endif // RAGDOLLEXPLOSIONENUMERATOR_H diff --git a/game/client/recvproxy.h b/game/client/recvproxy.h new file mode 100644 index 0000000..67d5d52 --- /dev/null +++ b/game/client/recvproxy.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: implements various common send proxies +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RECVPROXY_H +#define RECVPROXY_H + + +#include "dt_recv.h" + +class CRecvProxyData; + + +// This converts the int stored in pData to an EHANDLE in pOut. +void RecvProxy_IntToEHandle( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +void RecvProxy_IntToMoveParent( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_IntToColor32( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_IntSubOne( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_ShortSubOne( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_InterpolationAmountChanged( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_IntToModelIndex16_BackCompatible( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_IntToModelIndex32_BackCompatible( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +RecvProp RecvPropTime( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE ); + +#if !defined( NO_ENTITY_PREDICTION ) +RecvProp RecvPropPredictableId( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE ); +#endif + +RecvProp RecvPropEHandle( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, + RecvVarProxyFn proxyFn=RecvProxy_IntToEHandle ); + +RecvProp RecvPropBool( + const char *pVarName, + int offset, + int sizeofVar ); + +RecvProp RecvPropIntWithMinusOneFlag( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, + RecvVarProxyFn proxyFn=RecvProxy_IntSubOne ); + +#endif // RECVPROXY_H + diff --git a/game/client/rendertexture.h b/game/client/rendertexture.h new file mode 100644 index 0000000..2afdc6a --- /dev/null +++ b/game/client/rendertexture.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// Define local cl_dll hooks to the renderable textures in material system +// +//=============================================================================// + +#ifndef RENDERTARGETS_H +#define RENDERTARGETS_H + +ITexture *GetPowerOfTwoFrameBufferTexture( void ); +ITexture *GetFullFrameFrameBufferTexture( int textureIndex ); +ITexture *GetWaterReflectionTexture( void ); +ITexture *GetWaterRefractionTexture( void ); +ITexture *GetFullscreenTexture( void ); +ITexture *GetCameraTexture( void ); +ITexture *GetFullFrameDepthTexture( void ); + +// SmallBufferHDRx=r16g16b16a16 quarter-sized texture +ITexture *GetSmallBufferHDR0( void ); +ITexture *GetSmallBufferHDR1( void ); + +ITexture *GetSmallBuffer0( void ); // quarter-sized texture, same fmt as screen +ITexture *GetSmallBuffer1( void ); // quarter-sized texture, same fmt as screen + +#define MAX_TEENY_TEXTURES 3 + +ITexture *GetTeenyTexture(int which); // tiny 32x32 texture, always 8888 + +void ReleaseRenderTargets( void ); + +#endif // RENDERTARGETS_H diff --git a/game/client/replay/cdll_replay.h b/game/client/replay/cdll_replay.h new file mode 100644 index 0000000..a7c7438 --- /dev/null +++ b/game/client/replay/cdll_replay.h @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//=======================================================================================// + +#ifndef CDLL_REPLAY_H +#define CDLL_REPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +class IReplayEngineClient; + +//---------------------------------------------------------------------------------------- + +#endif \ No newline at end of file diff --git a/game/client/replay/gamedefs.h b/game/client/replay/gamedefs.h new file mode 100644 index 0000000..439bb14 --- /dev/null +++ b/game/client/replay/gamedefs.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef GAMEDEFS_H +#define GAMEDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( TF_CLIENT_DLL ) + +# include "tf_gamestats_shared.h" + +# define REPLAY_GAMESTATS_UNDEFINED TFSTAT_UNDEFINED +# define REPLAY_GAMESTATS_REVENGE TFSTAT_REVENGE +# define REPLAY_GAMESTATS_DEATHS TFSTAT_DEATHS +# define REPLAY_GAMESTATS_DOMINATIONS TFSTAT_DOMINATIONS +# define REPLAY_GAMESTATS_POINTSSCORED TFSTAT_POINTSSCORED +# define REPLAY_GAMESTATS_MAX TFSTAT_TOTAL + +# define REPLAY_TEAM_TEAM0 TF_TEAM_RED +# define REPLAY_TEAM_TEAM1 TF_TEAM_BLUE + +# define REPLAY_CLASS_UNDEFINED TF_CLASS_UNDEFINED +# define REPLAY_NUM_CLASSES TF_CLASS_MENU_BUTTONS + +# define REPLAY_DEATH_DOMINATION TF_DEATH_DOMINATION +# define REPLAY_DEATH_ASSISTER_DOMINATION TF_DEATH_ASSISTER_DOMINATION +# define REPLAY_DEATH_REVENGE TF_DEATH_REVENGE +# define REPLAY_DEATH_ASSISTER_REVENGE TF_DEATH_ASSISTER_REVENGE + +# define C_ReplayGame_PlayerResource +# include "c_tf_playerresource.h" +typedef C_TF_PlayerResource C_ReplayGame_PlayerResource_t; + +# define ReplayStatType_t TFStatType_t + +# define REPLAY_MAX_DISPLAY_GAMESTATS 23 + +#elif defined( CSTRIKE_DLL ) + +# include "cs_gamestats_shared.h" + +# define REPLAY_GAMESTATS_UNDEFINED CSSTAT_UNDEFINED +# define REPLAY_GAMESTATS_REVENGE CSSTAT_REVENGES +# define REPLAY_GAMESTATS_DEATHS CSSTAT_DEATHS +# define REPLAY_GAMESTATS_DOMINATIONS CSSTAT_DOMINATIONS +# define REPLAY_GAMESTATS_POINTSSCORED CSSTAT_UNDEFINED // Sheeeeeeeeeit +# define REPLAY_GAMESTATS_MAX CSSTAT_MAX + +# define REPLAY_TEAM_TEAM0 TEAM_TERRORIST +# define REPLAY_TEAM_TEAM1 TEAM_CT + +# define REPLAY_CLASS_UNDEFINED CS_CLASS_NONE +# define REPLAY_NUM_CLASSES CS_NUM_CLASSES + +# define REPLAY_DEATH_DOMINATION CS_DEATH_DOMINATION +# define REPLAY_DEATH_REVENGE CS_DEATH_REVENGE + +# include "c_cs_playerresource.h" +typedef C_CS_PlayerResource C_ReplayGame_PlayerResource_t; + +# define ReplayStatType_t CSStatType_t +# define RoundStats_t StatsCollection_t + +# define REPLAY_MAX_DISPLAY_GAMESTATS 3 + +#endif + +struct StatInfo_t +{ + ReplayStatType_t m_nStat; + const char *m_pStatLocalizationToken; +}; + +extern StatInfo_t g_pReplayDisplayGameStats[REPLAY_MAX_DISPLAY_GAMESTATS]; + +#endif // GAMEDEFS_H \ No newline at end of file diff --git a/game/client/replay/genericclassbased_replay.h b/game/client/replay/genericclassbased_replay.h new file mode 100644 index 0000000..02c5e70 --- /dev/null +++ b/game/client/replay/genericclassbased_replay.h @@ -0,0 +1,178 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//=======================================================================================// + +#if defined( REPLAY_ENABLED ) + +#ifndef GENERICCLASSBASED_REPLAY_H +#define GENERICCLASSBASED_REPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +//---------------------------------------------------------------------------------------- + +#include "replay/replay.h" +#include "replay/iclientreplaycontext.h" +#include "GameEventListener.h" + +// For RoundStats_t +#include "replay/gamedefs.h" + +//---------------------------------------------------------------------------------------- + +extern IClientReplayContext *g_pClientReplayContext; + +//---------------------------------------------------------------------------------------- + +class CGenericClassBasedReplay : public CReplay, + public CGameEventListener +{ + typedef CReplay BaseClass; +public: + CGenericClassBasedReplay(); + ~CGenericClassBasedReplay(); + + virtual void OnBeginRecording(); + virtual void OnEndRecording(); + virtual void OnComplete(); + virtual bool ShouldAllowDelete() const; + virtual void OnDelete(); + + virtual void FireGameEvent( IGameEvent *pEvent ); + + virtual bool Read( KeyValues *pIn ); + virtual void Write( KeyValues *pOut ); + + virtual void DumpGameSpecificData() const; + + void SetPlayerClass( int nPlayerClass ); + void SetPlayerTeam( int nPlayerTeam ); + + void RecordPlayerDeath( const char *pKillerName, int nKillerClass ); + + // Add a new kill to the list + void AddKill( const char *pPlayerName, int nPlayerClass ); + + // Get the player class as a string + virtual const char *GetPlayerClass() const; + + // Get the player team as a string + virtual const char *GetPlayerTeam() const = 0; + + // Utility to get the material-friendly player class (demoman->demo, heavyweapons->heavy) + virtual const char *GetMaterialFriendlyPlayerClass() const; + + // Was there a killer? + inline bool WasKilled() const { return m_szKillerName[0] != 0; } + + // Get killer name + const char *GetKillerName() const; + + // Get the killer class, if there was a killer + const char *GetKillerClass() const; + + int GetDownloadStatus() const; + + // Kill info + struct KillData_t + { + char m_szPlayerName[MAX_OSPATH]; + int m_nPlayerClass; + }; + + inline int GetKillCount() const { return m_vecKills.Count(); } + inline const KillData_t *GetKill( int nKillIndex ) { return m_vecKills[ nKillIndex ]; } + + // A generic info struct used for dominations, assisted dominations, revenges, assisted revenged... + // Not all data members are necessarily used + struct GenericStatInfo_t + { + GenericStatInfo_t() : m_nVictimFriendId( 0 ), m_nAssisterFriendId( 0 ) {} + uint32 m_nVictimFriendId; + uint32 m_nAssisterFriendId; + }; + + inline int GetDominationCount() const { return m_vecDominations.Count(); } + inline const GenericStatInfo_t *GetDomination( int nIndex ) const { return m_vecDominations[ nIndex ]; } + + inline int GetAssisterDominationCount() const { return m_vecAssisterDominations.Count(); } + inline const GenericStatInfo_t *GetAssisterDomination( int nIndex ) const { return m_vecAssisterDominations[ nIndex ]; } + + inline int GetRevengeCount() const { return m_vecRevenges.Count(); } + inline const GenericStatInfo_t *GetRevenge( int nIndex ) const { return m_vecRevenges[ nIndex ]; } + + inline int GetAssisterRevengeCount() const { return m_vecAssisterRevenges.Count(); } + inline const GenericStatInfo_t *GetAssisterRevenge( int nIndex ) const { return m_vecAssisterRevenges[ nIndex ]; } + + RoundStats_t const &GetStats() const { return m_lifeStats; } + +protected: + int m_nPlayerClass; + int m_nPlayerTeam; + int m_nStatUndefined; + + char m_szKillerName[ MAX_OSPATH ]; + int m_nKillerClass; + + virtual bool IsValidClass( int nClass ) const = 0; + virtual bool IsValidTeam( int iTeam ) const = 0; + virtual bool GetCurrentStats( RoundStats_t &out ) = 0; + virtual const char *GetStatString( int iStat ) const = 0; + virtual const char *GetPlayerClass( int iClass ) const = 0; + + virtual void Update(); + + // Domination + void AddDomination( int nVictimID ); + void AddAssisterDomination( int nVictimID, int nAssiterID ); + + void AddRevenge( int nVictimID ); + void AddAssisterRevenge( int nVictimID, int nAssiterID ); + + float GetKillScreenshotDelay(); + + RoundStats_t m_refStats; // Reference stats, used to compute current stats + RoundStats_t m_lifeStats; // Stats for this life, based on reference stats (m_refStats) + +private: + void MedicUpdate(); + + bool GetFriendIdFromUserId( int nPlayerIndex, uint32 &nFriendIdOut ) const; // Get a friend ID based on player index. Returns true on success + void AddKillStatFromUserIds( CUtlVector< GenericStatInfo_t * > &vec, int nVictimId, int nAssisterId = 0 ); + void AddKillStatFromFriendIds( CUtlVector< GenericStatInfo_t * > &vec, uint32 nVictimFriendId, uint32 nAssisterFriendId = 0 ); + void WriteKillStatVector( CUtlVector< GenericStatInfo_t * > const &vec, const char *pSubKeyName, const char *pElementKeyName, + KeyValues *pRootKey, int nNumMembersToWrite ) const; + void AddKillStats( CUtlVector< GenericStatInfo_t * > &vecKillStats, KeyValues *pIn, const char *pSubKeyName, int iStatIndex ); + void RecordUpdatedStats(); + + CUtlVector< KillData_t * > m_vecKills; + CUtlVector< GenericStatInfo_t * > m_vecDominations; + CUtlVector< GenericStatInfo_t * > m_vecAssisterDominations; + CUtlVector< GenericStatInfo_t * > m_vecRevenges; + CUtlVector< GenericStatInfo_t * > m_vecAssisterRevenges; + + // TODO... dominations, achievements, etc. +}; + +//---------------------------------------------------------------------------------------- + +inline CGenericClassBasedReplay *ToGenericClassBasedReplay( CReplay *pClientReplay ) +{ + return static_cast< CGenericClassBasedReplay * >( pClientReplay ); +} + +inline const CGenericClassBasedReplay *ToGenericClassBasedReplay( const CReplay *pClientReplay ) +{ + return static_cast< const CGenericClassBasedReplay * >( pClientReplay ); +} + +inline CGenericClassBasedReplay *GetGenericClassBasedReplay( ReplayHandle_t hReplay ) +{ + return ToGenericClassBasedReplay( g_pClientReplayContext->GetReplay( hReplay ) ); +} + +//---------------------------------------------------------------------------------------- + +#endif // GENERICCLASSBASED_REPLAY_H + +#endif \ No newline at end of file diff --git a/game/client/replay/replay_ragdoll.h b/game/client/replay/replay_ragdoll.h new file mode 100644 index 0000000..1011203 --- /dev/null +++ b/game/client/replay/replay_ragdoll.h @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef REPLAY_RAGDOLL_H +#define REPLAY_RAGDOLL_H +#ifdef _WIN32 +#pragma once +#endif + +//-------------------------------------------------------------------------------- + +class C_BaseAnimating; + +//-------------------------------------------------------------------------------- + +struct RagdollSimulationFrame_t +{ + RagdollSimulationFrame_t() : pPositions(NULL), pAngles(NULL), nTick(-1) {} + + static RagdollSimulationFrame_t* Alloc( int nNumBones ); + + int nTick; + Vector* pPositions; + QAngle* pAngles; + Vector vRootPosition; + QAngle angRootAngles; +}; + +//-------------------------------------------------------------------------------- + +struct RagdollSimulationData_t +{ + RagdollSimulationData_t( C_BaseAnimating* pEntity = NULL, int nStartTick = 0, int nNumBones = 0 ); + + void Record(); + + int m_nEntityIndex; + int m_nStartTick; + int m_nDuration; + int m_nNumBones; + + typedef unsigned short Iterator_t; + + CUtlLinkedList< RagdollSimulationFrame_t*, Iterator_t > m_lstFrames; + C_BaseAnimating* m_pEntity; +}; + +//-------------------------------------------------------------------------------- + +// TODO: Refactor this into an interface and hide implementation in cpp file + +class CReplayRagdollRecorder +{ +private: + CReplayRagdollRecorder(); + ~CReplayRagdollRecorder(); + +public: + static CReplayRagdollRecorder& Instance(); + + void Init(); + void Shutdown(); + + void Think(); + + void AddEntry( C_BaseAnimating* pEntity, int nStartTick, int nNumBones ); + void StopRecordingRagdoll( C_BaseAnimating* pEntity ); + + void CleanupStartupTicksAndDurations( int nStartTick ); + bool DumpRagdollsToDisk( char const* pszFilename ) const; + + bool IsRecording() const { return m_bIsRecording; } + +private: + typedef unsigned short Iterator_t; + + void StopRecordingRagdollAtIndex( Iterator_t nIndex ); + + void StopRecordingSleepingRagdolls(); + void Record(); + + bool FindEntryInRecordingList( C_BaseAnimating* pEntity, Iterator_t& nOutIndex ); + + void PrintDebug(); + + CUtlLinkedList< RagdollSimulationData_t*, Iterator_t > m_lstRagdolls; + CUtlLinkedList< RagdollSimulationData_t*, Iterator_t > m_lstRagdollsToRecord; // Contains some of the elements from m_lstRagdolls - + // the ones which are still recording + bool m_bIsRecording; +}; + +//-------------------------------------------------------------------------------- + +class CReplayRagdollCache +{ +private: + CReplayRagdollCache(); + +public: + static CReplayRagdollCache& Instance(); + + bool Init( char const* pszFilename ); + void Shutdown(); + + void Think(); + + bool IsInitialized() const { return m_bInit; } + + // + // Returns false is no frame exists for the given entity at the given tick. + // Otherwise, returns a + // + bool GetFrame( C_BaseAnimating* pEntity, int nTick, bool* pBoneSimulated, CBoneAccessor* pBoneAccessor ) const; + +private: + RagdollSimulationData_t* FindRagdollEntry( C_BaseAnimating* pEntity, int nTick ); + const RagdollSimulationData_t* FindRagdollEntry( C_BaseAnimating* pEntity, int nTick ) const; + + bool FindFrame( RagdollSimulationFrame_t*& pFrameOut, RagdollSimulationFrame_t*& pNextFrameOut, + const RagdollSimulationData_t* pRagdollEntry, int nTick ); + bool FindFrame( RagdollSimulationFrame_t*& pFrameOut, RagdollSimulationFrame_t*& pNextFrameOut, + const RagdollSimulationData_t* pRagdollEntry, int nTick ) const; + + typedef unsigned short Iterator_t; + bool m_bInit; + + CUtlLinkedList< RagdollSimulationData_t*, Iterator_t > m_lstRagdolls; +}; + +//-------------------------------------------------------------------------------- + +bool Replay_CacheRagdolls( const char* pFilename, int nStartTick ); + +//-------------------------------------------------------------------------------- + +inline const RagdollSimulationData_t* CReplayRagdollCache::FindRagdollEntry( C_BaseAnimating* pEntity, int nTick ) const +{ + return const_cast< CReplayRagdollCache* >( this )->FindRagdollEntry( pEntity, nTick ); +} + +inline bool CReplayRagdollCache::FindFrame( RagdollSimulationFrame_t*& pFrameOut, RagdollSimulationFrame_t*& pNextFrameOut, + const RagdollSimulationData_t* pRagdollEntry, int nTick ) const +{ + return const_cast< CReplayRagdollCache* >( this )->FindFrame( pFrameOut, pNextFrameOut, pRagdollEntry, nTick ); +} + +//-------------------------------------------------------------------------------- + +#endif // REPLAY_RAGDOLL_H diff --git a/game/client/replay/replay_screenshot.h b/game/client/replay/replay_screenshot.h new file mode 100644 index 0000000..4c95a56 --- /dev/null +++ b/game/client/replay/replay_screenshot.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#if !defined( REPLAY_SCREENSHOT_H ) +#define REPLAY_SCREENSHOT_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "replay/screenshot.h" + +//----------------------------------------------------------------------------- + +class IViewRender; + +//----------------------------------------------------------------------------- + +// +// Takes screenshots as VTF's for the replay system - allocates enough +// memory up-front as opposed to every frame. Should be destroyed and recreated +// any time the cvar "replay_screenshotresolution" changes OR the actual screen +// resolution. +// +class CReplayScreenshotTaker +{ +public: + CReplayScreenshotTaker( IViewRender *pViewRender, CViewSetup &view ); + ~CReplayScreenshotTaker(); + + void TakeScreenshot( WriteReplayScreenshotParams_t ¶ms ); + + static void CreateRenderTarget( IMaterialSystem *pMaterialSystem ); + +private: + IViewRender *m_pViewRender; + CViewSetup &m_View; + uint8 *m_pUnpaddedPixels; + uint8 *m_pPaddedPixels; + IVTFTexture *m_pVTFTexture; + uint8 *m_pVTFPixels; + + int m_aUnpaddedDims[2]; // Width & height of m_pUnpaddedPixels + int m_aPaddedDims[2]; // Width & height of m_pPaddedPixels + + CUtlBuffer *m_pBuffer; + + + static ITexture *m_pScreenshotTarget; +}; + +#endif // REPLAY_SCREENSHOT_H diff --git a/game/client/replay/replaycamera.h b/game/client/replay/replaycamera.h new file mode 100644 index 0000000..842c6ac --- /dev/null +++ b/game/client/replay/replaycamera.h @@ -0,0 +1,158 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#if defined( REPLAY_ENABLED ) + +#ifndef REPLAYCAMERA_H +#define REPLAYCAMERA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "replay/ireplaycamera.h" +#include "GameEventListener.h" + +class C_ReplayCamera : public CGameEventListener, + public IReplayCamera +{ +public: + C_ReplayCamera(); + virtual ~C_ReplayCamera(); + + void Init(); + void Reset(); + + // + // IReplayCamera: + // + virtual void ClearOverrideView(); + + void EnableInput( bool bEnable ); + + void OverrideView( const Vector *pOrigin, const QAngle *pAngles, float flFov ); + void GetCachedView( Vector &origin, QAngle &angles, float &fov ); + + void CalcView(Vector& origin, QAngle& angles, float& fov); + void FireGameEvent( IGameEvent *event ); + + void SetMode(int iMode); + void SetChaseCamParams( float flOffset, float flDistance, float flTheta, float flPhi ); + void SpecNextPlayer( bool bInverse ); + void SpecNamedPlayer( const char *szPlayerName ); + bool IsPVSLocked(); + void SetAutoDirector( bool bActive ); + + int GetMode(); // returns current camera mode + C_BaseEntity *GetPrimaryTarget(); // return primary target + inline int GetPrimaryTargetIndex() { return m_iTarget1; } + void SetPrimaryTarget( int nEntity); // set the primary obs target + + void CreateMove(CUserCmd *cmd); + void FixupMovmentParents(); + void PostEntityPacketReceived(); + const char* GetTitleText() { return m_szTitleText; } + int GetNumSpectators() { return m_nNumSpectators; } + + void SmoothFov( float flDelta ); + + float m_flRoamingAccel; + float m_flRoamingSpeed; + float m_flRoamingFov[2]; // FOV for roaming only - current and target - smoothing done by replay editor + float m_flRoamingRotFilterFactor; + float m_flRoamingShakeAmount; + float m_flRoamingShakeSpeed; + float m_flRoamingShakeDir; + +protected: + void InitRoamingKeys(); + bool ShouldUseDefaultRoamingSettings() const; + + void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov, float flDelta ); + void CalcFixedView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov, float flDelta ); + void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov, float flDelta ); + void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov, float flDelta); + + void SmoothCameraAngle( QAngle& targetAngle ); + void SetCameraAngle( QAngle& targetAngle ); + void Accelerate( Vector& wishdir, float wishspeed, float accel, float flDelta ); + + bool ShouldOverrideView( Vector& origin, QAngle& angles, float& fov ); // Fills with override data if m_bOverrideView is set + + struct View_t + { + Vector origin; + QAngle angles; + float fov; + }; + + bool m_bInputEnabled; + bool m_bOverrideView; + View_t m_OverrideViewData; + View_t m_CachedView; + float m_flOldTime; // Time of last CalcView() (uses gpGlobals->realtime) + int m_nCameraMode; // current camera mode + Vector m_vCamOrigin; //current camera origin + QAngle m_aCamAngle; //current camera angle + QAngle m_aSmoothedRoamingAngles; + int m_iTarget1; // first tracked target or 0 + int m_iTarget2; // second tracked target or 0 + float m_flFOV; // current FOV + float m_flOffset; // z-offset from target origin + float m_flDistance; // distance to traget origin+offset + float m_flLastDistance; // too smooth distance + float m_flTheta; // view angle horizontal + float m_flPhi; // view angle vertical + float m_flInertia; // camera inertia 0..100 + float m_flLastAngleUpdateTime; + bool m_bEntityPacketReceived; // true after a new packet was received + int m_nNumSpectators; + char m_szTitleText[64]; + CUserCmd m_LastCmd; + Vector m_vecVelocity; + + enum Dir_t + { + DIR_FWD, + DIR_BACK, + DIR_LEFT, + DIR_RIGHT, + + DIR_UP, + DIR_DOWN, + + NUM_DIRS + }; + ButtonCode_t m_aMovementButtons[NUM_DIRS]; + + float m_flNoiseSample; +}; + +//----------------------------------------------------------------------------- + +C_ReplayCamera *ReplayCamera(); + +//----------------------------------------------------------------------------- + +#define FREE_CAM_ACCEL_MIN 1.1f +#define FREE_CAM_ACCEL_MAX 10.0f +#define FREE_CAM_SPEED_MIN 0.1f +#define FREE_CAM_SPEED_MAX 20.0f +#define FREE_CAM_FOV_MIN 10.0f +#define FREE_CAM_FOV_MAX 130.0f +#define FREE_CAM_ROT_FILTER_MIN 30.0f +#define FREE_CAM_ROT_FILTER_MAX 5.0f +#define FREE_CAM_SHAKE_SPEED_MIN 0.1f +#define FREE_CAM_SHAKE_SPEED_MAX 15.0f +#define FREE_CAM_SHAKE_AMOUNT_MIN 0.0f +#define FREE_CAM_SHAKE_AMOUNT_MAX 35.0f +#define FREE_CAM_SHAKE_DIR_MIN -1.0f +#define FREE_CAM_SHAKE_DIR_MAX 1.0f + +//----------------------------------------------------------------------------- + +#endif // REPLAYCAMERA_H + +#endif \ No newline at end of file diff --git a/game/client/replay/replayperformanceplaybackhandler.h b/game/client/replay/replayperformanceplaybackhandler.h new file mode 100644 index 0000000..13767c6 --- /dev/null +++ b/game/client/replay/replayperformanceplaybackhandler.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYPERFORMANCEPLAYER_H +#define REPLAYPERFORMANCEPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "replay/ireplayperformanceplaybackhandler.h" + +//----------------------------------------------------------------------------- + +extern IReplayPerformancePlaybackHandler *g_pReplayPerformancePlaybackHandler; + +//----------------------------------------------------------------------------- + +#endif // REPLAYPERFORMANCEPLAYER_H diff --git a/game/client/replay/replayrenderer.h b/game/client/replay/replayrenderer.h new file mode 100644 index 0000000..5c2a530 --- /dev/null +++ b/game/client/replay/replayrenderer.h @@ -0,0 +1,111 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYRENDERER_H +#define REPLAYRENDERER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "replay/ireplaymovierenderer.h" +#include "replay/rendermovieparams.h" +#include "movieobjects/timeutils.h" +#include "fmtstr.h" + +//----------------------------------------------------------------------------- + +class CReplay; +class CReplayPerformance; +class IQuickTimeMovieMaker; +class CReplayRenderOverlay; +class IVideoRecorder; + +//----------------------------------------------------------------------------- + +class CReplayRenderer : public IReplayMovieRenderer +{ +public: + CReplayRenderer( CReplayRenderOverlay *pOverlay ); + ~CReplayRenderer(); + + const CReplayPerformance *GetPerformance() const; + const char *GetMovieFilename() const; + static int GetNumMotionBlurTimeSteps( int nQuality ); + + // + // IReplayMovieRenderer interface + // + virtual bool SetupRenderer( RenderMovieParams_t ¶ms, IReplayMovie *pMovie ); + virtual void ShutdownRenderer(); + virtual void RenderVideo(); + virtual void RenderAudio( unsigned char *pBuffer, int nSize, int nNumSamples ); + + virtual void SetAudioSyncFrame( bool isSync = false ); + virtual bool IsAudioSyncFrame(); + virtual float GetRecordingFrameDuration(); + + +private: + bool IsDepthOfFieldEnabled() const; + bool IsAntialiasingEnabled() const; + bool IsHDR() const; + bool IsMotionBlurEnabled() const; + int GetMotionBlurQuality() const; + int GetDepthOfFieldQuality() const; + int NumMotionBlurTimeSteps() const; + float GetFramerate() const; + void ComputeSampleCounts( int *pNSamplesPerTimeStep, int *pNTotalSamples ) const; + float GetViewModelFOVOffset(); + void SetupDOFMatrixSkewView( const Vector &pos, const QAngle &angles, int nSample, CViewSetup& viewSetup ); + void BeginRenderingSample( int nSample, int x, int y, int nWidth, int nHeight, float fTonemapScale ); + void EndRendering(); + void SetupSampleView( int x, int y, int w, int h, int nSample, CViewSetup& viewSetup ); + void InitBuffers( const RenderMovieParams_t ¶ms ); + void DrawResolvingQuad( int nWidth, int nHeight ); + float GetRenderLength( const CReplay *pReplay ); + void CompositeAndLayoffFrame( int nFrame ); + void RenderLayoffFrame( DmeTime_t time, int nCurSample, int nNumTotalSamples ); + void ResolveSamples( int nSample, DmeTime_t frametime, int x, int y, int nWidth, int nHeight, bool bShowUser, float flBloomScale ); + void LayoffFrame( int nFrame ); + double GetShutterSpeed() const; + void ClearToBlack( CTextureReference &buf, int x, int y, int nWidth, int nHeight ); + bool SetupJitterTable(); + void GetViewSetup( CViewSetup &viewsetup ); + + bool m_bIsAudioSyncFrame; + + const Vector2D *m_pJitterTable; + int m_nNumJitterSamples; + IVideoRecorder *m_pMovieMaker; + bool m_bCacheFullSceneState; + BGRA8888_t *m_pLayoffBuf; + IReplayMovie *m_pMovie; + RenderMovieParams_t m_RenderParams; + CTextureReference m_AccumBuffSample; + CTextureReference m_LayoffResult; + CTextureReference m_AccumBuffPingPong[2]; // Buffers and materials for ping-pong accumulation buffer + CMaterialReference m_FourSampleResolveMatRef; + bool m_bForceCheapDoF; + bool m_bShutterClosed; + int m_nCurrentPingPong; + int m_nFrame; + + ConVar *m_pViewmodelFov; + ConVar *m_pDefaultFov; + + int m_nTimeStep; + int m_nCurSample; + DmeTime_t m_curSampleTime; + + int m_iTgaFrame; + CFmtStr m_fmtTgaRenderDirName; + + CReplayRenderOverlay *m_pRenderOverlay; +}; + +//----------------------------------------------------------------------------- + +#endif // REPLAYRENDERER_H diff --git a/game/client/replay/replayvideo.h b/game/client/replay/replayvideo.h new file mode 100644 index 0000000..b6ac266 --- /dev/null +++ b/game/client/replay/replayvideo.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYVIDEO_H +#define REPLAYVIDEO_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "video/ivideoservices.h" + +//----------------------------------------------------------------------------- + +struct ReplayVideoMode_t +{ + int m_nWidth; + int m_nHeight; + int m_nBaseFPS; + bool m_bNTSCRate; + const char *m_pName; // Can be a localization token, e.g. "#Replay_Blah" +}; + +struct ReplayQualityPreset_t +{ + const char *m_pName; + VideoEncodeCodec::EVideoEncodeCodec_t m_nCodecId; + int m_iQuality; + bool m_bMotionBlurEnabled; + int m_iMotionBlurQuality; +}; + +struct ReplayCodec_t +{ + VideoEncodeCodec::EVideoEncodeCodec_t m_nCodecId; + const char *m_pName; +}; + +//----------------------------------------------------------------------------- + +int ReplayVideo_GetVideoModeCount(); +const ReplayVideoMode_t &ReplayVideo_GetVideoMode( int i ); + +int ReplayVideo_GetDefaultQualityPreset(); +int ReplayVideo_GetQualityInterval(); // TODO: Wtf is this? +int ReplayVideo_GetQualityRange(); +int ReplayVideo_GetQualityPresetCount(); +const ReplayQualityPreset_t &ReplayVideo_GetQualityPreset( int i ); + +int ReplayVideo_GetCodecCount(); +const ReplayCodec_t &ReplayVideo_GetCodec( int i ); + +int ReplayVideo_FindCodecPresetFromCodec( VideoEncodeCodec_t nCodec ); + +//----------------------------------------------------------------------------- + +#endif // REPLAYVIDEO_H diff --git a/game/client/replay/replayyoutubeapi.h b/game/client/replay/replayyoutubeapi.h new file mode 100644 index 0000000..a4acd8a --- /dev/null +++ b/game/client/replay/replayyoutubeapi.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef REPLAYYOUTUBEAPI_H +#define REPLAYYOUTUBEAPI_H +#ifdef _WIN32 +#pragma once +#endif + +class IReplayMovie; +namespace vgui { class Panel; }; + +/** + * Show the YouTube login dialog and attempt to upload the movie if login was successful + * @param pMovie + * @param pParent + */ +void YouTube_ShowLoginDialog( IReplayMovie *pMovie, vgui::Panel *pParent ); + +/** + * + * Show the YouTube upload dialog and upload the movie + * @param pMovie + * @param pParent + */ +void YouTube_ShowUploadDialog( IReplayMovie *pMovie, vgui::Panel *pParent ); + +#endif // REPLAYYOUTUBEAPI_H diff --git a/game/client/replay/vgui/replaybrowserbasepage.h b/game/client/replay/vgui/replaybrowserbasepage.h new file mode 100644 index 0000000..58af944 --- /dev/null +++ b/game/client/replay/vgui/replaybrowserbasepage.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef REPLAYBROWSER_BASEPAGE_H +#define REPLAYBROWSER_BASEPAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/PropertyPage.h" +#include "replaybrowseritemmanager.h" +#include "replay/genericclassbased_replay.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CReplayListPanel; +class CExLabel; +class CReplayDetailsPanel; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CReplayBrowserBasePage : public PropertyPage +{ + DECLARE_CLASS_SIMPLE( CReplayBrowserBasePage, PropertyPage ); +public: + CReplayBrowserBasePage( Panel *pParent ); + virtual ~CReplayBrowserBasePage(); + + void DeleteDetailsPanelAndShowReplayList(); + bool IsDetailsViewOpen(); + void GoBack(); + + // Movie-only stuff + void FreeDetailsPanelMovieLock(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void OnCommand( const char *pCommand ); + virtual void PerformLayout(); + + MESSAGE_FUNC( OnPageShow, "PageShow" ); + MESSAGE_FUNC( OnSelectionStarted, "SelectionStarted" ); + MESSAGE_FUNC( OnSelectionEnded, "SelectionEnded" ); + MESSAGE_FUNC( OnCancelSelection, "CancelSelection" ); + MESSAGE_FUNC_PARAMS( OnReplayItemDeleted, "ReplayItemDeleted", pParams ); + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + + void AddReplay( ReplayHandle_t hReplay ); + void DeleteReplay( ReplayHandle_t hReplay ); + + void OnTick(); + + virtual void CleanupUIForReplayItem( ReplayItemHandle_t hReplayItem ); + + vgui::TextEntry *m_pSearchTextEntry; + CReplayListPanel *m_pReplayList; + DHANDLE< CReplayDetailsPanel > m_hReplayDetailsPanel; +}; + +#endif // REPLAYBROWSER_BASEPAGE_H diff --git a/game/client/replay/vgui/replaybrowserbasepanel.h b/game/client/replay/vgui/replaybrowserbasepanel.h new file mode 100644 index 0000000..2268b8b --- /dev/null +++ b/game/client/replay/vgui/replaybrowserbasepanel.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYBASEPANEL_H +#define REPLAYBASEPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" + +//----------------------------------------------------------------------------- +// Purpose: Base panel for replay panels +//----------------------------------------------------------------------------- +class CReplayBasePanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CReplayBasePanel, vgui::EditablePanel ); +public: + CReplayBasePanel( Panel *pParent, const char *pName ); + + void GetPosRelativeToAncestor( Panel *pAncestor, int &nXOut, int &nYOut ); +}; + +#endif // REPLAYBASEPANEL_H diff --git a/game/client/replay/vgui/replaybrowserdetailspanel.h b/game/client/replay/vgui/replaybrowserdetailspanel.h new file mode 100644 index 0000000..850d102 --- /dev/null +++ b/game/client/replay/vgui/replaybrowserdetailspanel.h @@ -0,0 +1,462 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef REPLAYBROWSER_DETAILSPANEL_H +#define REPLAYBROWSER_DETAILSPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/ScrollableEditablePanel.h" +#include "replay/iqueryablereplayitem.h" +#include "replay/ireplaymovie.h" +#include "replay/replayhandle.h" +#include "replay/gamedefs.h" +#include "econ/econ_controls.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- + +#define NUM_CLASSES_IN_LOADOUT_PANEL (TF_LAST_NORMAL_CLASS-1) // We don't allow unlockables for the civilian + +//----------------------------------------------------------------------------- +// Purpose: Forward declarations +//----------------------------------------------------------------------------- +class CExLabel; +class CExButton; +class CTFReplay; +class CReplayPerformance; +class IReplayItemManager; + +//----------------------------------------------------------------------------- +// Purpose: A panel containing 2 labels: one key, one value +//----------------------------------------------------------------------------- +class CKeyValueLabelPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CKeyValueLabelPanel, EditablePanel ); +public: + CKeyValueLabelPanel( Panel *pParent, const char *pKey, const char *pValue ); + CKeyValueLabelPanel( Panel *pParent, const char *pKey, const wchar_t *pValue ); + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + int GetHeight() const; + int GetValueHeight() const; + + void SetValue( const wchar_t *pValue ); + +private: + CExLabel *m_pLabels[2]; +}; + +//----------------------------------------------------------------------------- +// Purpose: Base details panel with left/top padding and black border +//----------------------------------------------------------------------------- +class CBaseDetailsPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CBaseDetailsPanel, EditablePanel ); +public: + CBaseDetailsPanel( Panel *pParent, const char *pName, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + int GetMarginSize() const { return XRES(6); } + + bool ShouldShow() const { return m_bShouldShow; } + +protected: + EditablePanel *GetInset() { return m_pInsetPanel; } + + ReplayHandle_t m_hReplay; + bool m_bShouldShow; + +private: + EditablePanel *m_pInsetPanel; // padding on left/top +}; + +//----------------------------------------------------------------------------- +// Purpose: Score panel - contains score & any records from the round +//----------------------------------------------------------------------------- +class CRecordsPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CRecordsPanel, CBaseDetailsPanel ); +public: + CRecordsPanel( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + +private: + ImagePanel *m_pClassImage; +}; + +//----------------------------------------------------------------------------- +// Purpose: Stats panel +//----------------------------------------------------------------------------- +class CStatsPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CStatsPanel, CBaseDetailsPanel ); +public: + CStatsPanel( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + +private: + CKeyValueLabelPanel *m_paStatLabels[ REPLAY_MAX_DISPLAY_GAMESTATS ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Dominations panel +//----------------------------------------------------------------------------- +class CDominationsPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CDominationsPanel, CBaseDetailsPanel ); +public: + CDominationsPanel( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + ImagePanel *m_pNumDominationsImage; + CUtlVector< ImagePanel * > m_vecDominationImages; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Kills panel +//----------------------------------------------------------------------------- +class CKillsPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CKillsPanel, CBaseDetailsPanel ); +public: + CKillsPanel( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + CKeyValueLabelPanel *m_pKillLabels; + CUtlVector< ImagePanel * > m_vecKillImages; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBasicLifeInfoPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CBasicLifeInfoPanel, CBaseDetailsPanel ); +public: + CBasicLifeInfoPanel( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + +private: + CKeyValueLabelPanel *m_pKilledByLabels; + CKeyValueLabelPanel *m_pMapLabels; + CKeyValueLabelPanel *m_pLifeLabels; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CMovieInfoPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CMovieInfoPanel, CBaseDetailsPanel ); +public: + CMovieInfoPanel( Panel *pParent, ReplayHandle_t hReplay, QueryableReplayItemHandle_t hMovie, + IReplayItemManager *pItemManager ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + +private: + CKeyValueLabelPanel *m_pRenderTimeLabels; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CYouTubeInfoPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CYouTubeInfoPanel, CBaseDetailsPanel ); +public: + CYouTubeInfoPanel( Panel *pParent ); + + virtual void PerformLayout(); + + void SetInfo( const wchar_t *pInfo ); + +private: + CKeyValueLabelPanel *m_pLabels; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTitleEditPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CTitleEditPanel, EditablePanel ); +public: + CTitleEditPanel( Panel *pParent, QueryableReplayItemHandle_t hReplayItem, IReplayItemManager *pItemManager ); + ~CTitleEditPanel(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + virtual void PaintBackground(); + + virtual void OnKeyCodeTyped(vgui::KeyCode code); + + virtual void OnTick(); + + bool m_bMouseOver; + TextEntry *m_pTitleEntry; + ImagePanel *m_pHeaderLine; + CExLabel *m_pClickToEditLabel; + CExLabel *m_pCaratLabel; + QueryableReplayItemHandle_t m_hReplayItem; + IReplayItemManager *m_pItemManager; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CReplayScreenshotSlideshowPanel; + +class CPlaybackPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CPlaybackPanel, EditablePanel ); +public: + CPlaybackPanel( Panel *pParent ); + ~CPlaybackPanel(); + + virtual void FreeMovieMaterial() {} + +protected: + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + inline int GetMarginSize() { return 9; } + inline int GetViewWidth() { return GetWide() - 2 * GetMarginSize(); } + inline int GetViewHeight() { return GetTall() - 2 * GetMarginSize(); } +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPlaybackPanelSlideshow : public CPlaybackPanel +{ + DECLARE_CLASS_SIMPLE( CPlaybackPanelSlideshow, CPlaybackPanel ); +public: + CPlaybackPanelSlideshow( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + +private: + ReplayHandle_t m_hReplay; + CExLabel *m_pNoScreenshotLabel; + CReplayScreenshotSlideshowPanel *m_pScreenshotImage; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CMoviePlayerPanel; + +class CPlaybackPanelMovie : public CPlaybackPanel +{ + DECLARE_CLASS_SIMPLE( CPlaybackPanelMovie, CPlaybackPanel ); +public: + CPlaybackPanelMovie( Panel *pParent, ReplayHandle_t hReplay ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + virtual void FreeMovieMaterial(); + +private: + CExLabel *m_pLoadingLabel; + CMoviePlayerPanel *m_pMoviePlayerPanel; + ReplayHandle_t m_hMovie; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCutImagePanel : public CExImageButton +{ + DECLARE_CLASS_SIMPLE( CCutImagePanel, CExImageButton ); +public: + CCutImagePanel( Panel *pParent, const char *pName ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + virtual void SetSelected( bool bState ); + +private: + virtual IBorder *GetBorder( bool bDepressed, bool bArmed, bool bSelected, bool bKeyFocus ); + + IBorder *m_pSelectedBorder; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CReplayDetailsPanel; + +class CCutsPanel : public CBaseDetailsPanel +{ + DECLARE_CLASS_SIMPLE( CCutsPanel, CBaseDetailsPanel ); +public: + CCutsPanel( Panel *pParent, ReplayHandle_t hReplay, int iPerformance ); + ~CCutsPanel(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + virtual void OnCommand( const char *pCommand ); + virtual void ApplySettings( KeyValues *pInResourceData ); + + void OnPerformanceDeleted( int iPerformance ); + + CPanelAnimationVarAliasType( int, m_nCutButtonWidth, "cut_button_width", "0", "proportional_xpos" ); + CPanelAnimationVarAliasType( int, m_nCutButtonHeight, "cut_button_height", "0", "proportional_ypos" ); + CPanelAnimationVarAliasType( int, m_nCutButtonBuffer, "cut_button_buffer", "0", "proportional_xpos" ); + CPanelAnimationVarAliasType( int, m_nCutButtonSpace, "cut_button_space", "0", "proportional_xpos" ); + CPanelAnimationVarAliasType( int, m_nCutButtonSpaceWide, "cut_button_space_wide", "0", "proportional_xpos" ); + CPanelAnimationVarAliasType( int, m_nTopMarginHeight, "top_margin_height", "0", "proportional_ypos" ); + CPanelAnimationVarAliasType( int, m_nNameLabelTopMargin, "name_label_top_margin", "0", "proportional_ypos" ); + CPanelAnimationVarAliasType( int, m_nButtonStartY, "button_start_y", "0", "proportional_ypos" ); + + void UpdateNameLabel( int iPerformance ); + +private: + void SelectButtonFromPerformance( int iPerformance ); + void SetPage( int iPage, int iButtonToSelect = 0 ); + int ButtonToPerformance( int iButton ) const; + int PerformanceToButton( int iPerformance ) const; + const CReplayPerformance *GetPerformance( int iPerformance ) const; + + virtual void OnTick(); + + struct ButtonInfo_t + { + CExImageButton *m_pButton; + CExButton *m_pAddToRenderQueueButton; + int m_iPerformance; + }; + + enum Consts_t + { + BUTTONS_PER_PAGE = 4 + }; + + ButtonInfo_t m_aButtons[ BUTTONS_PER_PAGE ]; + EditablePanel *m_pVerticalLine; + CExLabel *m_pNoCutsLabel; + CExLabel *m_pOriginalLabel; + CExLabel *m_pCutsLabel; + CExLabel *m_pNameLabel; + CExButton *m_pPrevButton; + CExButton *m_pNextButton; + int m_iPage; + int m_nVisibleButtons; + vgui::DHANDLE< CReplayDetailsPanel > m_hDetailsPanel; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class IReplayItemManager; +class CConfirmDialog; +class CYouTubeGetStatsHandler; + +class CReplayDetailsPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CReplayDetailsPanel, EditablePanel ); +public: + CReplayDetailsPanel( Panel *pParent, QueryableReplayItemHandle_t hReplayItem, int iPerformance, IReplayItemManager *pItemManager ); + ~CReplayDetailsPanel(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + virtual void OnMousePressed( MouseCode code ); + virtual void OnKeyCodeTyped( KeyCode code ); + + virtual void OnCommand( const char *pCommand ); + + virtual void OnMessage( const KeyValues* pParams, VPANEL hFromPanel ); + + EditablePanel *GetInset() { return m_pInsetPanel; } + + void ShowRenderDialog(); + void FreeMovieFileLock(); + void ShowExportDialog(); + + static void OnPlayerWarningDlgConfirm( bool bConfirmed, void *pContext ); + + enum eYouTubeStatus + { + kYouTubeStatus_Private, + kYouTubeStatus_RetrievingInfo, + kYouTubeStatus_RetrievedInfo, + kYouTubeStatus_CouldNotRetrieveInfo, + kYouTubeStatus_NotUploaded + }; + + void SetYouTubeStatus( eYouTubeStatus status ); + + EditablePanel *m_pInsetPanel; // Parent to most child panels listed here - narrower than screen width + EditablePanel *m_pInfoPanel; // Container for info panels + ScrollableEditablePanel *m_pScrollPanel; + + CPlaybackPanel *m_pPlaybackPanel; // Contains screenshot, playback button + CRecordsPanel *m_pRecordsPanel; // Contains score, records + CStatsPanel *m_pStatsPanel; // Contains stats + CDominationsPanel *m_pDominationsPanel; // Dominations + CBasicLifeInfoPanel *m_pBasicInfoPanel; // Killed by, map, life + CKillsPanel *m_pKillsPanel; // # kills, kill class icons + CYouTubeInfoPanel *m_pYouTubeInfoPanel; // YouTube Info + CCutsPanel *m_pCutsPanel; // Buttons for performances + CUtlVector< CBaseDetailsPanel* > m_vecInfoPanels; // List of panels on the right + CTitleEditPanel *m_pTitleEditPanel; + CExButton *m_pBackButton; + CExButton *m_pDeleteButton; + CExButton *m_pRenderButton; + CExButton *m_pPlayButton; + CExButton *m_pExportMovie; + CExButton *m_pYouTubeUpload; + CExButton *m_pYouTubeView; + CExButton *m_pYouTubeShareURL; + CExImageButton *m_pShowRenderInfoButton; + QueryableReplayItemHandle_t m_hReplayItem; + ReplayHandle_t m_hReplay; + IReplayItemManager *m_pItemManager; + int m_iSelectedPerformance; // Which performance to play/render/delete + CYouTubeGetStatsHandler *m_pYouTubeResponseHandler; + vgui::FileOpenDialog *m_hExportMovieDialog; + +private: + void ShowRenderInfo(); + + MESSAGE_FUNC_PARAMS( OnConfirmDisconnect, "ConfirmDlgResult", data ); + MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); + + CPanelAnimationVarAliasType( int, m_nMarginWidth, "margin_width", "0", "proportional_xpos" ); + + void GoBack(); + void ShowPlayConfirmationDialog(); +}; + +#endif // REPLAYBROWSER_DETAILSPANEL_H diff --git a/game/client/replay/vgui/replaybrowseritemmanager.h b/game/client/replay/vgui/replaybrowseritemmanager.h new file mode 100644 index 0000000..4468119 --- /dev/null +++ b/game/client/replay/vgui/replaybrowseritemmanager.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYBROWSER_ITEMMANAGER_H +#define REPLAYBROWSER_ITEMMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utllinkedlist.h" +#include + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +typedef int ReplayItemHandle_t; + +//----------------------------------------------------------------------------- +// Purpose: Layer of abstraction between UI and replay demos or rendered movies +//----------------------------------------------------------------------------- +class IQueryableReplayItem; + +abstract_class IReplayItemManager : public IBaseInterface +{ +public: + virtual int GetItemCount() = 0; + virtual void GetItems( CUtlLinkedList< IQueryableReplayItem *, int > &items ) = 0; + virtual IQueryableReplayItem *GetItem( ReplayItemHandle_t hItem ) = 0; + virtual bool AreItemsMovies() = 0; + virtual void DeleteItem( vgui::Panel *pPage, ReplayItemHandle_t hItem, bool bNotifyUI ) = 0; +}; + +IReplayItemManager *GetReplayItemManager(); +IReplayItemManager *GetReplayMovieItemManager(); + +// Find an item and put the item manager in ppItemManager +IQueryableReplayItem *FindReplayItem( ReplayItemHandle_t hItem, IReplayItemManager **ppItemManager ); + +#endif // REPLAYBROWSER_ITEMMANAGER_H diff --git a/game/client/replay/vgui/replaybrowserlistitempanel.h b/game/client/replay/vgui/replaybrowserlistitempanel.h new file mode 100644 index 0000000..004ae74 --- /dev/null +++ b/game/client/replay/vgui/replaybrowserlistitempanel.h @@ -0,0 +1,239 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYLISTITEMPANEL_H +#define REPLAYLISTITEMPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "replaybrowserbasepanel.h" +#include "replaybrowseritemmanager.h" +#include "replay/genericclassbased_replay.h" +#include "game_controls/slideshowpanel.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Slideshow panel that adds all screenshots associated +// with a given replay. +//----------------------------------------------------------------------------- +class CReplayScreenshotSlideshowPanel : public CSlideshowPanel +{ + DECLARE_CLASS_SIMPLE( CReplayScreenshotSlideshowPanel, CSlideshowPanel ); +public: + CReplayScreenshotSlideshowPanel( Panel *pParent, const char *pName, ReplayHandle_t hReplay ); + + virtual void PerformLayout(); + +private: + ReplayHandle_t m_hReplay; +}; + +//----------------------------------------------------------------------------- +// Purpose: An individual Replay thumbnail, with download button, title, etc. +//----------------------------------------------------------------------------- +class CExButton; +class CExLabel; +class IReplayItemManager; +class CMoviePlayerPanel; + +class CReplayBrowserThumbnail : public CReplayBasePanel +{ + DECLARE_CLASS_SIMPLE( CReplayBrowserThumbnail, CReplayBasePanel ); +public: + CReplayBrowserThumbnail( Panel *pParent, const char *pName, QueryableReplayItemHandle_t hReplayItem, IReplayItemManager *pReplayItemManager ); + ~CReplayBrowserThumbnail(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + virtual void OnMousePressed( MouseCode code ); + + virtual void OnTick(); + + virtual void OnCommand( const char *pCommand ); + + void UpdateTitleText(); + + void SetReplayItem( QueryableReplayItemHandle_t hReplayItem ); + + CGenericClassBasedReplay *GetReplay(); + IQueryableReplayItem *GetReplayItem(); + + MESSAGE_FUNC_PARAMS( OnDownloadClicked, "Download", pParams ); + MESSAGE_FUNC_PARAMS( OnDeleteReplay, "delete_replayitem", pParams ); + + CCrossfadableImagePanel *m_pScreenshotThumb; + QueryableReplayItemHandle_t m_hReplayItem; + +private: + void SetupReplayItemUserData( void *pUserData ); + void UpdateProgress( bool bDownloadPhase, const CReplay *pReplay ); + + Label *m_pTitle; + Label *m_pDownloadLabel; + Label *m_pRecordingInProgressLabel; + ProgressBar *m_pDownloadProgress; + CExButton *m_pDownloadButton; + CExButton *m_pDeleteButton; + Label *m_pErrorLabel; + CMoviePlayerPanel *m_pMoviePlayer; + Panel *m_pDownloadOverlay; + EditablePanel *m_pBorderPanel; + Color m_clrHighlight; + Color m_clrDefaultBg; + bool m_bMouseOver; + IReplayItemManager *m_pReplayItemManager; + float m_flLastMovieScrubTime; + float m_flHoverStartTime; + float m_flLastProgressChangeTime; +}; + +//----------------------------------------------------------------------------- +// Purpose: A row of Replay thumbnails (CReplayBrowserThumbnail's) +//----------------------------------------------------------------------------- +class CReplayBrowserThumbnailRow : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CReplayBrowserThumbnailRow, EditablePanel ); +public: + CReplayBrowserThumbnailRow( Panel *pParent, const char *pName, IReplayItemManager *pReplayItemManager ); + + void AddReplayThumbnail( const IQueryableReplayItem *pReplay ); + void AddReplayThumbnail( QueryableReplayItemHandle_t hReplayItem ); + void DeleteReplayItemThumbnail( const IQueryableReplayItem *pReplayItem ); + int GetNumReplayItems() const { return m_vecThumbnails.Count(); } + int GetNumVisibleReplayItems() const; + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + CReplayBrowserThumbnail *FindThumbnail( const IQueryableReplayItem *pReplay ); + + CUtlVector< CReplayBrowserThumbnail * > m_vecThumbnails; + IReplayItemManager *m_pReplayItemManager; +}; + +//----------------------------------------------------------------------------- +// Purpose: A collection of CReplayBrowserThumbnailRows containing replays +// recorded on a given day. +//----------------------------------------------------------------------------- +class CExLabel; +class CExButton; +class CReplayListPanel; + +class CBaseThumbnailCollection : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CBaseThumbnailCollection, EditablePanel ); +public: + CBaseThumbnailCollection( CReplayListPanel *pParent, const char *pName, IReplayItemManager *pReplayItemManager ); + + void AddReplay( const IQueryableReplayItem *pItem ); + + virtual bool IsMovieCollection() const = 0; + + void CleanupUIForReplayItem( ReplayItemHandle_t hReplayItem ); + + virtual void PerformLayout(); + virtual void ApplySchemeSettings( IScheme *pScheme ); + + void RemoveEmptyRows(); + void RemoveAll(); + + void OnUpdated(); + + void OnCommand( const char *pCommand ); + + CReplayBrowserThumbnailRow *FindReplayItemThumbnailRow( const IQueryableReplayItem *pReplayItem ); + + inline int GetNumRows() const { return m_vecRows.Count(); } + + typedef CUtlVector< CReplayBrowserThumbnailRow * > RowContainer_t; + RowContainer_t m_vecRows; + +protected: + // Called from PerformLayout() - layout any panels that should appear at the top (vertically)-most position + virtual void LayoutUpperPanels( int nStartY, int nBgWidth ) = 0; + virtual void LayoutBackgroundPanel( int nWide, int nTall ) {} + virtual Panel *GetLowestPanel( int &nVerticalBuffer ) = 0; + + void UpdateViewingPage( void ); + + int m_nStartX; + +protected: + CExLabel *m_pNoReplayItemsLabel; + IReplayItemManager *m_pReplayItemManager; + + CExButton *m_pShowNextButton; + CExButton *m_pShowPrevButton; + CUtlVector m_vecReplays; + int m_iViewingPage; + + int m_nReplayThumbnailsPerRow; + int m_nMaxRows; + + CExLabel *m_pCaratLabel; + CExLabel *m_pTitleLabel; + CExButton *m_pRenderAllButton; + +private: + int GetRowStartY(); + + CReplayListPanel *m_pParentListPanel; // Parent gets altered so we keep this cached ptr around +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CReplayThumbnailCollection : public CBaseThumbnailCollection +{ + DECLARE_CLASS_SIMPLE( CReplayThumbnailCollection, CBaseThumbnailCollection ); +public: + CReplayThumbnailCollection( CReplayListPanel *pParent, const char *pName, IReplayItemManager *pReplayItemManager ); + + virtual bool IsMovieCollection() const; + + virtual void PerformLayout(); + virtual void ApplySchemeSettings( IScheme *pScheme ); + + virtual void LayoutUpperPanels( int nStartY, int nBgWidth ); + virtual void LayoutBackgroundPanel( int nWide, int nTall ); + virtual Panel *GetLowestPanel( int &nVerticalBuffer ); + + Panel *m_pLinePanel; + CExLabel *m_pWarningLabel; + Panel *m_pUnconvertedBg; +}; + +#define OLDER_MOVIES_COLLECTION -2 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CMovieThumbnailCollection : public CBaseThumbnailCollection +{ + DECLARE_CLASS_SIMPLE( CMovieThumbnailCollection, CBaseThumbnailCollection ); +public: + CMovieThumbnailCollection( CReplayListPanel *pParent, const char *pName, IReplayItemManager *pReplayItemManager, + int nDay, int nMonth, int nYear, bool bShowSavedMoviesLabel ); + CMovieThumbnailCollection( CReplayListPanel *pParent, const char *pName, IReplayItemManager *pReplayItemManager, + bool bShowSavedMoviesLabel ); + + bool DoesDateMatch( int nDay, int nMonth, int nYear ); + virtual bool IsMovieCollection() const; + +private: + void Init( int nDay, int nMonth, int nYear, bool bShowSavedMoviesLabel ); + virtual void PerformLayout(); + virtual void ApplySchemeSettings( IScheme *pScheme ); + + Panel *GetLowestPanel( int &nVerticalBuffer ); + void LayoutUpperPanels( int nStartY, int nBgWidth ); + + int m_nDay, m_nMonth, m_nYear; + CExLabel *m_pDateLabel; + bool m_bShowSavedMoviesLabel; +}; + +#endif // REPLAYLISTITEMPANEL_H diff --git a/game/client/replay/vgui/replaybrowserlistpanel.h b/game/client/replay/vgui/replaybrowserlistpanel.h new file mode 100644 index 0000000..b30658b --- /dev/null +++ b/game/client/replay/vgui/replaybrowserlistpanel.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYBROWSER_LISTPANEL_H +#define REPLAYBROWSER_LISTPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "vgui_controls/PropertyPage.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/PanelListPanel.h" +#include "vgui_controls/EditablePanel.h" +#include "replaybrowseritemmanager.h" +#include "replay/genericclassbased_replay.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CBaseThumbnailCollection; +class CReplayPreviewPanelBase; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CReplayBrowserThumbnail; +class CExLabel; + +class CReplayListPanel : public PanelListPanel +{ + DECLARE_CLASS_SIMPLE( CReplayListPanel, PanelListPanel ); +public: + CReplayListPanel( Panel *pParent, const char *pName ); + ~CReplayListPanel(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + void AddReplayItem( ReplayItemHandle_t hItem ); + void CleanupUIForReplayItem( ReplayItemHandle_t hReplayItem ); + void AddReplaysToList(); + void RemoveCollection( CBaseThumbnailCollection *pCollection ); + + virtual void OnTick(); + + void OnItemPanelEntered( Panel *pPanel ); + void OnItemPanelExited( Panel *pPanel ); + + void SetupBorderArrow( bool bLeft ); + + void ClearPreviewPanel(); + + void ApplyFilter( const wchar_t *pFilterText ); + +protected: + virtual void OnMouseWheeled(int delta); + +private: + const IQueryableReplayItem *FindItem( ReplayItemHandle_t hItem, int *pItemManagerIndex ); + CBaseThumbnailCollection *FindOrAddReplayThumbnailCollection( const IQueryableReplayItem *pItem, IReplayItemManager *pItemManager ); + CReplayBrowserThumbnail *FindThumbnailAtCursor( int x, int y ); + bool PassesFilter( IQueryableReplayItem *pItem ); + + CBaseThumbnailCollection *m_pReplaysCollection; + CBaseThumbnailCollection *m_pMoviesCollection; + + CUtlVector< CBaseThumbnailCollection * > m_vecCollections; + CReplayPreviewPanelBase *m_pPreviewPanel; + Panel *m_pPrevHoverPanel; + + ImagePanel *m_pBorderArrowImg; + int m_aBorderArrowDims[2]; + wchar_t m_wszFilter[256]; +}; + +#endif // REPLAYBROWSER_LISTPANEL_H diff --git a/game/client/replay/vgui/replaybrowsermainpanel.h b/game/client/replay/vgui/replaybrowsermainpanel.h new file mode 100644 index 0000000..e34574b --- /dev/null +++ b/game/client/replay/vgui/replaybrowsermainpanel.h @@ -0,0 +1,89 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#if defined( REPLAY_ENABLED ) + +#ifndef REPLAYBROWSER_MAIN_PANEL_H +#define REPLAYBROWSER_MAIN_PANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/PropertyDialog.h" +#include "replay/replayhandle.h" +#include "GameEventListener.h" +#include "replaybrowseritemmanager.h" + +//----------------------------------------------------------------------------- + +class CReplayBrowserBasePage; +class CConfirmDeleteDialog; +class CExButton; + +//----------------------------------------------------------------------------- + +class CReplayBrowserPanel : public vgui::PropertyDialog, + public CGameEventListener +{ + DECLARE_CLASS_SIMPLE( CReplayBrowserPanel, vgui::PropertyDialog ); +public: + CReplayBrowserPanel( Panel *parent ); + virtual ~CReplayBrowserPanel(); + + void OnSaveReplay( ReplayHandle_t hNewReplay ); + void OnDeleteReplay( ReplayHandle_t hDeletedReplay ); + + void DeleteReplay( ReplayHandle_t hReplay ); + + virtual void CleanupUIForReplayItem( ReplayItemHandle_t hReplay ); // After a replay has been deleted - deletes all UI (thumbnail, but maybe also row and/or collection as well) + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void PerformLayout( void ); + virtual void OnCommand( const char *command ); + virtual void ShowPanel( bool bShow, ReplayHandle_t hReplayDetails = REPLAY_HANDLE_INVALID, int iPerformance = -1 ); + virtual void OnKeyCodeTyped(vgui::KeyCode code); + virtual void OnKeyCodePressed(vgui::KeyCode code); + + virtual void FireGameEvent( IGameEvent *event ); + + MESSAGE_FUNC_PARAMS( OnConfirmDelete, "ConfirmDlgResult", data ); + + void AttemptToDeleteReplayItem( Panel *pHandler, ReplayItemHandle_t hReplayItem, IReplayItemManager *pItemManager, int iPerformance ); + + CReplayBrowserBasePage *m_pReplaysPage; + CConfirmDeleteDialog *m_pConfirmDeleteDialog; + + struct DeleteInfo_t + { + ReplayItemHandle_t m_hReplayItem; + IReplayItemManager *m_pItemManager; + vgui::VPANEL m_hHandler; + int m_iPerformance; + }; + + DeleteInfo_t m_DeleteInfo; + + float GetTimeOpened( void ){ return m_flTimeOpened; } + +private: + void ShowDeleteReplayDenialDlg(); + void ConfirmReplayItemDelete( Panel *pHandler, ReplayItemHandle_t hReplayItem, IReplayItemManager *pItemManager, int iPerformance ); + + float m_flTimeOpened; +}; + +//----------------------------------------------------------------------------- + +CReplayBrowserPanel *ReplayUI_GetBrowserPanel(); +void ReplayUI_ReloadBrowser( ReplayHandle_t hReplay = REPLAY_HANDLE_INVALID, int iPerformance = -1 ); +void ReplayUI_CloseReplayBrowser(); + +//----------------------------------------------------------------------------- + +#endif // REPLAYBROWSER_MAIN_PANEL_H + +#endif \ No newline at end of file diff --git a/game/client/replay/vgui/replaybrowsermovieplayerpanel.h b/game/client/replay/vgui/replaybrowsermovieplayerpanel.h new file mode 100644 index 0000000..968ad58 --- /dev/null +++ b/game/client/replay/vgui/replaybrowsermovieplayerpanel.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYBROWSERMOVIEPLAYERPANEL_H +#define REPLAYBROWSERMOVIEPLAYERPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "replaybrowserbasepanel.h" +#include "video/ivideoservices.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: A panel that plays AVI's +//----------------------------------------------------------------------------- +class CMoviePlayerPanel : public CReplayBasePanel +{ + DECLARE_CLASS_SIMPLE( CMoviePlayerPanel, CReplayBasePanel ); +public: + CMoviePlayerPanel( Panel *pParent, const char *pName, const char *pMovieFilename ); + ~CMoviePlayerPanel(); + + virtual void Paint(); + + void Play(); + void SetLooping( bool bLooping ) { m_bLooping = bLooping; } + + bool IsPlaying() { return m_bPlaying; } + void SetScrubOnMouseOverMode( bool bOn ); + void FreeMaterial(); + void ToggleFullscreen(); + +private: + virtual void PerformLayout(); + virtual void OnMousePressed( MouseCode code ); + virtual void OnTick(); + + IVideoMaterial *m_pVideoMaterial; + + IMaterial *m_pMaterial; + float m_flCurFrame; + int m_nNumFrames; + bool m_bPlaying; + bool m_bLooping; + float m_flLastTime; + int m_nGlobalPos[2]; + int m_nLastMouseXPos; + bool m_bFullscreen; + Panel *m_pOldParent; + int m_aOldBounds[4]; + bool m_bMouseOverScrub; // In this mode, we don't playback, only scrub on mouse over +}; + +#endif // REPLAYBROWSERMOVIEPLAYERPANEL_H diff --git a/game/client/replay/vgui/replaybrowserpreviewpanel.h b/game/client/replay/vgui/replaybrowserpreviewpanel.h new file mode 100644 index 0000000..c1ba78b --- /dev/null +++ b/game/client/replay/vgui/replaybrowserpreviewpanel.h @@ -0,0 +1,120 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef REPLAYBROWSER_PREVIEWPANEL_H +#define REPLAYBROWSER_PREVIEWPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "vgui_controls/PropertyPage.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/PanelListPanel.h" +#include "vgui_controls/EditablePanel.h" +#include "replaybrowseritemmanager.h" +#include "replay/genericclassbased_replay.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CExLabel; +class CBaseThumbnailCollection; +class CReplayDetailsPanel; +class CReplayScreenshotSlideshowPanel; + +//----------------------------------------------------------------------------- +// Purpose: Preview balloon +//----------------------------------------------------------------------------- +class CGenericClassBasedReplay; +class CCrossfadableImagePanel; +class CSlideshowPanel; + +class CReplayPreviewPanelBase : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CReplayPreviewPanelBase, EditablePanel ); +public: + CReplayPreviewPanelBase( Panel *pParent, QueryableReplayItemHandle_t hItem, IReplayItemManager *pItemManager ); + ~CReplayPreviewPanelBase(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + ReplayHandle_t GetReplayHandle(); + +protected: + CGenericClassBasedReplay *GetReplay(); + + virtual bool ShoudlUseLargeClassImage() { return false; } + virtual void LayoutView( int &nWide, int &nTall, int &nCurY ); + +protected: + IReplayItemManager *m_pItemManager; + QueryableReplayItemHandle_t m_hItem; + +private: + ImagePanel *m_pClassImage; + vgui::EditablePanel *m_pInfoPanel; + + CExLabel *m_pMapLabel; + CExLabel *m_pDateTimeLabel; + + enum ELabels + { + LABEL_PLAYED_AS, + LABEL_KILLED_BY, + LABEL_LIFE_LENGTH, + NUM_INFO_LABELS + }; + CExLabel *m_pReplayInfoLabels[NUM_INFO_LABELS][2]; +}; + +//----------------------------------------------------------------------------- +// Purpose: Preview balloon for slideshows (actual replays) +//----------------------------------------------------------------------------- +class CReplayPreviewPanelSlideshow : public CReplayPreviewPanelBase +{ + DECLARE_CLASS_SIMPLE( CReplayPreviewPanelSlideshow, CReplayPreviewPanelBase ); +public: + CReplayPreviewPanelSlideshow( Panel *pParent, QueryableReplayItemHandle_t hItem, IReplayItemManager *pItemManager ); + +private: + virtual void PerformLayout(); + virtual void LayoutView( int &nWide, int &nTall, int &nCurY ); + + CReplayScreenshotSlideshowPanel *m_pScreenshotPanel; + CExLabel *m_pNoScreenshotLabel; +}; + +//----------------------------------------------------------------------------- +// Purpose: Preview balloon for movies (rendered replays) +//----------------------------------------------------------------------------- +class CMoviePlayerPanel; +class IReplayMovie; + +class CReplayPreviewPanelMovie : public CReplayPreviewPanelBase +{ + DECLARE_CLASS_SIMPLE( CReplayPreviewPanelMovie, CReplayPreviewPanelBase ); +public: + CReplayPreviewPanelMovie( Panel *pParent, QueryableReplayItemHandle_t hItem, IReplayItemManager *pItemManager ); + ~CReplayPreviewPanelMovie(); + +private: + virtual void OnTick(); + virtual void LayoutView( int &nWide, int &nTall, int &nCurY ); + + virtual IReplayMovie *GetReplayMovie(); + + CMoviePlayerPanel *m_pMoviePlayerPanel; + float m_flCreateTime; +}; + + + +#endif // REPLAYBROWSER_PREVIEWPANEL_H diff --git a/game/client/replay/vgui/replaybrowserrenderdialog.h b/game/client/replay/vgui/replaybrowserrenderdialog.h new file mode 100644 index 0000000..338115f --- /dev/null +++ b/game/client/replay/vgui/replaybrowserrenderdialog.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef REPLAYBROWSER_RENDERDIALOG_H +#define REPLAYBROWSER_RENDERDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "replaybrowserbasepanel.h" +#include "vgui/IScheme.h" +#include "vgui_controls/CheckButton.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/Slider.h" +#include "replay/replayhandle.h" + +using namespace vgui; + +class CExLabel; +class CExButton; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CReplayRenderDialog : public CReplayBasePanel +{ + DECLARE_CLASS_SIMPLE( CReplayRenderDialog, CReplayBasePanel ); +public: + CReplayRenderDialog( Panel *pParent, ReplayHandle_t hReplay, bool bSetQuit, int iPerformance ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + virtual void OnCommand( const char *pCommand ); + virtual void OnKeyCodeTyped( vgui::KeyCode code ); + virtual void OnThink(); + + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel ); + +private: + MESSAGE_FUNC( OnSetFocus, "SetFocus" ); + + void Close(); + void Render(); + void ValidateRenderData(); + void UpdateControlsValues(); + void AddControlToAutoLayout( Panel *pPanel, bool bAdvanced ); + void SetValuesFromQualityPreset(); + + bool m_bShowAdvancedOptions; + int m_iQualityPreset; + ReplayHandle_t m_hReplay; + bool m_bSetQuit; + int m_iPerformance; + CheckButton *m_pPlayVoiceCheck; + CheckButton *m_pShowAdvancedOptionsCheck; + CheckButton *m_pQuitWhenDoneCheck; + CheckButton *m_pExportRawCheck; + CExButton *m_pCancelButton; + CExButton *m_pRenderButton; + TextEntry *m_pTitleText; + ComboBox *m_pVideoModesCombo; + ComboBox *m_pCodecCombo; + CExLabel *m_pQualityPresetLabel; + ComboBox *m_pQualityPresetCombo; + CExLabel *m_pResolutionNoteLabel; + CExLabel *m_pEnterANameLabel; + CExLabel *m_pVideoModeLabel; + CExLabel *m_pTitleLabel; + CExLabel *m_pLockWarningLabel; + CExLabel *m_pCodecLabel; + CExLabel *m_pEstimateTimeLabel; + CExLabel *m_pEstimateFileLabel; + CheckButton *m_pMotionBlurCheck; + CExLabel *m_pMotionBlurLabel; + Slider *m_pMotionBlurSlider; + CExLabel *m_pQualityLabel; + Slider *m_pQualitySlider; + EditablePanel *m_pBgPanel; + Panel *m_pSeparator; + CheckButton *m_pGlowEnabledCheck; + + struct LayoutInfo_t + { + Panel *pPanel; + int nOffsetX; + int nOffsetY; + bool bAdvanced; + }; + + CUtlLinkedList< LayoutInfo_t * > m_lstControls; + CPanelAnimationVarAliasType( int, m_nStartY, "start_y", "0", "proportional_ypos" ); + CPanelAnimationVarAliasType( int, m_nVerticalBuffer, "vertical_buffer", "0", "proportional_ypos" ); + CPanelAnimationVarAliasType( int, m_nDefaultX, "default_x", "0", "proportional_xpos" ); + + friend class CReplayGameStatsHelper; +}; + +//----------------------------------------------------------------------------- + +void ReplayUI_ShowRenderDialog( Panel* pParent, ReplayHandle_t hReplay, bool bSetQuit, int iPerformance ); + +//----------------------------------------------------------------------------- + +#endif // REPLAYBROWSER_RENDERDIALOG_H diff --git a/game/client/replay/vgui/replayconfirmquitdlg.h b/game/client/replay/vgui/replayconfirmquitdlg.h new file mode 100644 index 0000000..29f2bbd --- /dev/null +++ b/game/client/replay/vgui/replayconfirmquitdlg.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef REPLAYBROWSER_CONFIRMQUITDLG_H +#define REPLAYBROWSER_CONFIRMQUITDLG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "replaybrowserbasepanel.h" +#include "vgui/IScheme.h" +#include "vgui_controls/CheckButton.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CExButton; + +class CReplayConfirmQuitDialog : public CReplayBasePanel +{ + DECLARE_CLASS_SIMPLE( CReplayConfirmQuitDialog, CReplayBasePanel ); +public: + CReplayConfirmQuitDialog( Panel *pParent ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnCommand( const char *pCommand ); + virtual void OnKeyCodeTyped( vgui::KeyCode code ); + virtual void OnKeyCodePressed( vgui::KeyCode code ); + +private: + vgui::CheckButton *m_pDontShowAgain; + CExButton *m_pQuitButton; +}; + +//----------------------------------------------------------------------------- + +bool ReplayUI_ShowConfirmQuitDlg(); + +//----------------------------------------------------------------------------- + +#endif // REPLAYBROWSER_CONFIRMQUITDLG_H diff --git a/game/client/replay/vgui/replayinputpanel.h b/game/client/replay/vgui/replayinputpanel.h new file mode 100644 index 0000000..142de01 --- /dev/null +++ b/game/client/replay/vgui/replayinputpanel.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAY_INPUT_PANEL_H +#define REPLAY_INPUT_PANEL_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "replay/replayhandle.h" + +//----------------------------------------------------------------------------- +// Purpose: Show Replay input panel for entering a title, etc. +//----------------------------------------------------------------------------- +void ShowReplayInputPanel( ReplayHandle_t hReplay ); + +//----------------------------------------------------------------------------- +// Purpose: Is the panel visible? +//----------------------------------------------------------------------------- +bool IsReplayInputPanelVisible(); + +#endif // REPLAY_INPUT_PANEL_H diff --git a/game/client/replay/vgui/replaymessagepanel.h b/game/client/replay/vgui/replaymessagepanel.h new file mode 100644 index 0000000..4e253c0 --- /dev/null +++ b/game/client/replay/vgui/replaymessagepanel.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//---------------------------------------------------------------------------------------- + +#ifndef REPLAYMESSAGEPANEL_H +#define REPLAYMESSAGEPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" + +using namespace vgui; + +//---------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------- +extern ConVar replay_msgduration_startrecord; +extern ConVar replay_msgduration_stoprecord; +extern ConVar replay_msgduration_replaysavailable; +extern ConVar replay_msgduration_error; +extern ConVar replay_msgduration_misc; +extern ConVar replay_msgduration_connectrecording; + +//---------------------------------------------------------------------------------------- +// Purpose: Forward declarations +//---------------------------------------------------------------------------------------- +class CExLabel; +class CExButton; + +class CReplayMessageDlg : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CReplayMessageDlg, EditablePanel ); +public: + CReplayMessageDlg( const char *pText ); + ~CReplayMessageDlg(); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + virtual void OnKeyCodeTyped( KeyCode nCode ); + virtual void OnCommand( const char *pCommand ); + +private: + void Close(); + + Panel *m_pDlg; + CExLabel *m_pMsgLabel; + CExButton *m_pOKButton; +}; + +//---------------------------------------------------------------------------------------- +// Purpose: A panel for display messages from the replay system during gameplay +//---------------------------------------------------------------------------------------- +class CReplayMessagePanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CReplayMessagePanel, EditablePanel ); +public: + CReplayMessagePanel( const char *pLocalizeName, float flDuration, bool bUrgent ); + virtual ~CReplayMessagePanel(); + + void Show(); + virtual void OnTick(); + + static int InstanceCount(); + static void RemoveAll(); + +private: + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + + + CExLabel *m_pMessageLabel; + CExLabel *m_pReplayLabel; + ImagePanel *m_pIcon; + float m_flShowStartTime; + float m_flShowDuration; + bool m_bUrgent; + +#if defined( TF_CLIENT_DLL ) + char m_szBorderName[ 64 ]; +#endif +}; + +#endif // REPLAYMESSAGEPANEL_H \ No newline at end of file diff --git a/game/client/replay/vgui/replayperformanceeditor.h b/game/client/replay/vgui/replayperformanceeditor.h new file mode 100644 index 0000000..034843a --- /dev/null +++ b/game/client/replay/vgui/replayperformanceeditor.h @@ -0,0 +1,241 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#if defined( REPLAY_ENABLED ) + +#ifndef REPLAYPERFORMANCEEDITOR_H +#define REPLAYPERFORMANCEEDITOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/ImagePanel.h" +#include "vgui_controls/ImageList.h" +#include "tf/vgui/tf_controls.h" +#include "replay/replayhandle.h" +#include "replay/ireplayperformanceeditor.h" +#include "replay/ireplayperformancecontroller.h" + +//----------------------------------------------------------------------------- + +class CPlayerCell; +class CCameraOptionsPanel; +class CRecLightPanel; +class CReplay; +class CReplayPerformance; +class CReplayTipLabel; +class CSavingDialog; + +//----------------------------------------------------------------------------- + +// NOTE: Should not change order here - if you do, you need to modify g_pCamNames. +enum CameraMode_t +{ + CAM_INVALID = -1, + CAM_FREE, + CAM_THIRD, + CAM_FIRST, + COMPONENT_TIMESCALE, + NCAMS +}; + +//----------------------------------------------------------------------------- + +class CReplayPerformanceEditorPanel : public vgui::EditablePanel, + public IReplayPerformanceEditor +{ + DECLARE_CLASS_SIMPLE( CReplayPerformanceEditorPanel, vgui::EditablePanel ); +public: + CReplayPerformanceEditorPanel( Panel *parent, ReplayHandle_t hReplay ); + virtual ~CReplayPerformanceEditorPanel(); + + virtual void ShowPanel( bool bShow ); + + bool OnEndOfReplayReached(); + void OnInGameMouseWheelEvent( int nDelta ); + void UpdateCameraSelectionPosition( CameraMode_t nCameraMode ); + void UpdateFreeCamSettings( const SetViewParams_t ¶ms ); + void UpdateTimeScale( float flScale ); + void HandleUiToggle(); + void Exit(); + void Exit_ShowDialogs(); + +private: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void ApplySettings( KeyValues *pInResourceData ); + virtual void PerformLayout(); + virtual void OnCommand( const char *command ); + virtual void OnMouseWheeled( int nDelta ); + virtual void OnTick(); + + void Achievements_Think( float flElapsed ); + void Achievements_OnSpaceBarPressed(); + void Achievements_Grant(); + + friend class CReplayButton; + friend class CSavingDialog; + + void SetButtonTip( wchar_t *pTipText, Panel *pContextPanel ); + void ShowButtonTip( bool bShow ); + + void ShowSavingDialog(); + + // + // IReplayPerformanceEditor: + // + virtual CReplay *GetReplay(); + virtual void OnRewindComplete(); + + // Called when the user attempts to change to a different camera, etc. + // Returns true if request is immediately granted - false means the event + // was queued and the user has been asked if they are OK with nuking any + // changes after the current time. + bool OnStateChangeRequested( const char *pEventStr ); + + void EnsureRecording( bool bShouldSnip = true ); // Start recording now if not already doing so + + bool IsPaused(); + + void UpdateCameraButtonImages( bool bForceUseUnselected = false ); + void LayoutPlayerCells(); + void SetupHighlightPanel( EditablePanel *pPanel, CPlayerCell *pPlayerCell ); + void UpdateTimeLabels(); + void ClearPlayerCellData(); + + void HandleMouseWheel( int nDelta ); + +private: + enum ControlButtons_t + { + CTRLBUTTON_IN, + CTRLBUTTON_GOTOBEGINNING, + CTRLBUTTON_REWIND, + CTRLBUTTON_PLAY, + CTRLBUTTON_FF, + CTRLBUTTON_GOTOEND, + CTRLBUTTON_OUT, + + NUM_CTRLBUTTONS + }; + + CReplayPerformance *GetPerformance() const; + CReplayPerformance *GetSavedPerformance() const; + + int GetCameraModeFromButtonIndex( CameraMode_t iCamera ); + void AddSetViewEvent(); + void AddTimeScaleEvent( float flTimeScale ); + void AddPanelKeyboardInputDisableList( vgui::Panel *pPanel ); + CameraMode_t IsMouseOverActiveCameraOptionsPanel( int nMouseX, int nMouseY ); + void SetOrRemoveInTick( int nTick, bool bRemoveIfSet ); + void SetOrRemoveOutTick( int nTick, bool bRemoveIfSet ); + void SetOrRemoveTick( int nTick, bool bUseInTick, bool bRemoveIfSet ); + void ToggleMenu(); + void OnMenuCommand_Save( bool bExitEditorWhenDone = false ); + void OnMenuCommand_SaveAs( bool bExitEditorWhenDone = false ); + void OnMenuCommand_Exit(); + void DisplaySavedTip( bool bSucceess ); + void OnSaveComplete(); + + void SaveAs( const wchar_t *pTitle ); + + void ShowRewindConfirmMessage(); + + static void OnConfirmSaveAs( bool bShouldSave, wchar_t *pTitle, void *pContext ); + static void OnConfirmDestroyChanges( bool bConfirmed, void *pContext ); + static void OnConfirmDiscard( bool bConfirmed, void *pContext ); + static void OnConfirmExit( bool bConfirmed, void *pContext ); + static void OnConfirmRewind( bool bConfirmed, void *pContext ); + + MESSAGE_FUNC_PARAMS( OnSliderMoved, "SliderMoved", pParams ); + + ReplayHandle_t m_hReplay; + + float m_flLastTime; // Can't use gpGlobals->frametime when playback is paused + float m_flOldFps; + + CExLabel *m_pCurTimeLabel; + CExLabel *m_pTotalTimeLabel; + CExLabel *m_pPlayerNameLabel; + + KeyValues *m_pPlayerCellData; + CPlayerCell *m_pPlayerCells[2][MAX_PLAYERS+1]; + vgui::ImageList *m_pImageList; + + EditablePanel *m_pMouseTargetPanel; + EditablePanel *m_pBottom; + CPlayerCell *m_pCurTargetCell; + + CExImageButton *m_pCameraButtons[NCAMS]; + CExImageButton *m_pCtrlButtons[NUM_CTRLBUTTONS]; + + float m_flTimeScaleProxy; + + EditablePanel *m_pPlayerCellsPanel; + + vgui::ImagePanel *m_pCameraSelection; + CameraMode_t m_iCameraSelection; // NOTE: Indexes into some arrays + + CReplayTipLabel *m_pButtonTip; + CSavingDialog *m_pSavingDlg; + + enum MenuItems_t + { + MENU_SAVE, + MENU_SAVEAS, + MENU_EXIT, + + NUM_MENUITEMS + }; + + CExImageButton *m_pMenuButton; + vgui::Menu *m_pMenu; + int m_aMenuItemIds[ NUM_MENUITEMS ]; + + CExButton *m_pSlowMoButton; + + CCameraOptionsPanel *m_pCameraOptionsPanels[NCAMS]; + + CUtlLinkedList< vgui::Panel *, int > m_lstDisableKeyboardInputPanels; + + int m_nRedBlueLabelRightX; + int m_nBottomPanelStartY; + int m_nBottomPanelHeight; + int m_nRedBlueSigns[2]; + int m_iCurPlayerTarget; + float m_flSpaceDownStart; // The time at which user started holding down space bar + bool m_bSpaceDown; + bool m_bSpacePressed; + int m_nLastRoundedTime; + bool m_bMousePressed; + bool m_bMouseDown; + float m_flDefaultFramerate; // host_framerate before perf editor started mucking about with it + CameraMode_t m_nMouseClickedOverCameraSettingsPanel; // Allows user to drag slider outside of camera settings panel w/o the panel disappearing + CRecLightPanel *m_pRecLightPanel; + bool m_bShownAtLeastOnce; // Has the replay editor shown at least once? In other words, has the user hit the space bar at all yet? + char m_szSuspendedEvent[128]; + + bool m_bAchievementAwarded; // Was an achievement awarded during this editing session? + float m_flLastTimeSpaceBarPressed; + float m_flActiveTimeInEditor; // Will be zero'd out if user is idle (ie if they don't press space bar often enough) + + CPanelAnimationVarAliasType( int, m_nRightMarginWidth, "right_margin_width", "0", "proportional_xpos" ); + + bool m_bCurrentTargetNeedsVisibilityUpdate; +}; + +//----------------------------------------------------------------------------- + +CReplayPerformanceEditorPanel *ReplayUI_InitPerformanceEditor( ReplayHandle_t hReplay ); +CReplayPerformanceEditorPanel *ReplayUI_GetPerformanceEditor(); +void ReplayUI_ClosePerformanceEditor(); + +//----------------------------------------------------------------------------- + +#endif // REPLAYPERFORMANCEEDITOR_H + +#endif \ No newline at end of file diff --git a/game/client/replay/vgui/replayperformancesavedlg.h b/game/client/replay/vgui/replayperformancesavedlg.h new file mode 100644 index 0000000..6650ee2 --- /dev/null +++ b/game/client/replay/vgui/replayperformancesavedlg.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAYPERFORMANCESAVEDLG_H +#define REPLAYPERFORMANCESAVEDLG_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +class CReplay; + +//----------------------------------------------------------------------------- + +typedef void (*OnConfirmSaveCallback)( bool bConfirmed, wchar_t *pTitle, void *pContext ); + +//----------------------------------------------------------------------------- + +void ReplayUI_ShowPerformanceSaveDlg( OnConfirmSaveCallback pfnCallback, void *pContext, CReplay *pReplay, + bool bExitEditorWhenDone ); +bool ReplayUI_IsPerformanceSaveDlgOpen(); + +//----------------------------------------------------------------------------- + +#endif // REPLAYPERFORMANCESAVEDLG_H diff --git a/game/client/replay/vgui/replayreminderpanel.h b/game/client/replay/vgui/replayreminderpanel.h new file mode 100644 index 0000000..ede6490 --- /dev/null +++ b/game/client/replay/vgui/replayreminderpanel.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef REPLAYREMINDERPANEL_H +#define REPLAYREMINDERPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include "hud.h" +#include "hudelement.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Replay reminder panel +//----------------------------------------------------------------------------- +class CReplayReminderPanel : public EditablePanel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CReplayReminderPanel, vgui::EditablePanel ); +public: + CReplayReminderPanel( const char *pElementName ); + + void Hide(); // To be used by HUD only + void Show(); // To be used by HUD only + + // CHudElement overrides + virtual bool ShouldDraw(); + virtual void OnThink(); + virtual int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + // EditablePanel overrides + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void SetVisible( bool bState ); + +private: + void SetupText(); + + float m_flShowTime; // Used by the HUD only, to display the panel only for a certain period of time + bool m_bShouldDraw; // Store this state for ShouldDraw(), which allows us to use a single panel for + // both the post-win reminder and the freezepanel reminder. +}; + +#endif // REPLAYREMINDERPANEL_H diff --git a/game/client/replay/vgui/replayrenderoverlay.h b/game/client/replay/vgui/replayrenderoverlay.h new file mode 100644 index 0000000..a6dbdab --- /dev/null +++ b/game/client/replay/vgui/replayrenderoverlay.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef REPLAY_RENDEROVERLAY_H +#define REPLAY_RENDEROVERLAY_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#include "vgui_controls/Frame.h" +#include "vgui_controls/ProgressBar.h" +#include "replay/rendermovieparams.h" + +//----------------------------------------------------------------------------- + +class CExButton; +class CExLabel; +class IQuickTimeMovieMaker; +class CReplay; +class CReplayRenderer; + +//----------------------------------------------------------------------------- + +class CReplayRenderOverlay : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CReplayRenderOverlay, vgui::Frame ); +public: + CReplayRenderOverlay( Panel *pParent ); + ~CReplayRenderOverlay(); + + void Show(); + void Hide(); + + CReplayRenderer *m_pRenderer; + +private: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void PerformLayout(); + virtual void OnTick(); + virtual void OnMousePressed( vgui::MouseCode nCode ); + virtual void OnKeyCodeTyped( vgui::KeyCode nCode ); + virtual void OnCommand( const char *pCommand ); + +private: + MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", pPanel ); + +#if _DEBUG + bool m_bReloadScheme; +#endif + + int m_unNumFrames; + float m_flStartTime; + float m_flPreviousTimeLeft; + EditablePanel *m_pBottom; + vgui::ProgressBar *m_pRenderProgress; + vgui::CheckButton *m_pPreviewCheckButton; + CExButton *m_pCancelButton; + CExLabel *m_pTitleLabel; + CExLabel *m_pFilenameLabel; + CExLabel *m_pProgressLabel; +}; + +//----------------------------------------------------------------------------- + +void ReplayUI_OpenReplayRenderOverlay(); +void ReplayUI_HideRenderOverlay(); + +//----------------------------------------------------------------------------- + +#endif // REPLAY_RENDEROVERLAY_H diff --git a/game/client/sdk/c_sdk_player.h b/game/client/sdk/c_sdk_player.h new file mode 100644 index 0000000..e4986b9 --- /dev/null +++ b/game/client/sdk/c_sdk_player.h @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_SDK_PLAYER_H +#define C_SDK_PLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "sdk_playeranimstate.h" +#include "c_baseplayer.h" +#include "sdk_shareddefs.h" +#include "baseparticleentity.h" + + +class C_SDKPlayer : public C_BasePlayer, public ISDKPlayerAnimStateHelpers +{ +public: + DECLARE_CLASS( C_SDKPlayer, C_BasePlayer ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + C_SDKPlayer(); + ~C_SDKPlayer(); + + static C_SDKPlayer* GetLocalSDKPlayer(); + + virtual const QAngle& GetRenderAngles(); + virtual void UpdateClientSideAnimation(); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + +// Called by shared code. +public: + + // ISDKPlayerAnimState overrides. + virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon(); + virtual bool SDKAnim_CanMove(); + + void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); + bool ShouldDraw(); + + ISDKPlayerAnimState *m_PlayerAnimState; + + QAngle m_angEyeAngles; + CInterpolatedVar< QAngle > m_iv_angEyeAngles; + + CNetworkVar( int, m_iThrowGrenadeCounter ); // used to trigger grenade throw animations. + CNetworkVar( int, m_iShotsFired ); // number of shots fired recently + + EHANDLE m_hRagdoll; + + CWeaponSDKBase *GetActiveSDKWeapon() const; + + C_BaseAnimating *BecomeRagdollOnClient(); + IRagdoll* C_SDKPlayer::GetRepresentativeRagdoll() const; + + void FireBullet( + Vector vecSrc, + const QAngle &shootAngles, + float vecSpread, + int iDamage, + int iBulletType, + CBaseEntity *pevAttacker, + bool bDoEffects, + float x, + float y ); + +private: + C_SDKPlayer( const C_SDKPlayer & ); +}; + + +inline C_SDKPlayer* ToSDKPlayer( CBaseEntity *pPlayer ) +{ + Assert( dynamic_cast< C_SDKPlayer* >( pPlayer ) != NULL ); + return static_cast< C_SDKPlayer* >( pPlayer ); +} + + +#endif // C_SDK_PLAYER_H diff --git a/game/client/sdk/c_sdk_team.h b/game/client/sdk/c_sdk_team.h new file mode 100644 index 0000000..4cd2702 --- /dev/null +++ b/game/client/sdk/c_sdk_team.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side CTFTeam class +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SDK_TEAM_H +#define C_SDK_TEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_team.h" +#include "shareddefs.h" + +class C_BaseEntity; +class C_BaseObject; +class CBaseTechnology; + +//----------------------------------------------------------------------------- +// Purpose: TF's Team manager +//----------------------------------------------------------------------------- +class C_SDKTeam : public C_Team +{ + DECLARE_CLASS( C_SDKTeam, C_Team ); + DECLARE_CLIENTCLASS(); + +public: + + C_SDKTeam(); + virtual ~C_SDKTeam(); +}; + + +#endif // C_SDK_TEAM_H diff --git a/game/client/sdk/clientmode_sdk.h b/game/client/sdk/clientmode_sdk.h new file mode 100644 index 0000000..cbe11cc --- /dev/null +++ b/game/client/sdk/clientmode_sdk.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_CLIENTMODE_H +#define SDK_CLIENTMODE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_shared.h" +#include "sdkviewport.h" + +class ClientModeSDKNormal : public ClientModeShared +{ +DECLARE_CLASS( ClientModeSDKNormal, ClientModeShared ); + +private: + +// IClientMode overrides. +public: + + ClientModeSDKNormal(); + virtual ~ClientModeSDKNormal(); + + virtual void InitViewport(); + + virtual float GetViewModelFOV( void ); + + int GetDeathMessageStartHeight( void ); + + virtual void PostRenderVGui(); + + +private: + + // void UpdateSpectatorMode( void ); + +}; + + +extern IClientMode *GetClientModeNormal(); +extern ClientModeSDKNormal* GetClientModeSDKNormal(); + + +#endif // SDK_CLIENTMODE_H diff --git a/game/client/sdk/sdk_hud_chat.h b/game/client/sdk/sdk_hud_chat.h new file mode 100644 index 0000000..26d3e58 --- /dev/null +++ b/game/client/sdk/sdk_hud_chat.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDK_HUD_CHAT_H +#define SDK_HUD_CHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +class CHudChatLine : public CBaseHudChatLine +{ + DECLARE_CLASS_SIMPLE( CHudChatLine, CBaseHudChatLine ); + +public: + CHudChatLine( vgui::Panel *parent, const char *panelName ) : CBaseHudChatLine( parent, panelName ) {} + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + void PerformFadeout( void ); + + void MsgFunc_SayText(bf_read &msg); + +private: + CHudChatLine( const CHudChatLine & ); // not defined, not accessible +}; + +//----------------------------------------------------------------------------- +// Purpose: The prompt and text entry area for chat messages +//----------------------------------------------------------------------------- +class CHudChatInputLine : public CBaseHudChatInputLine +{ + DECLARE_CLASS_SIMPLE( CHudChatInputLine, CBaseHudChatInputLine ); + +public: + CHudChatInputLine( CBaseHudChat *parent, char const *panelName ) : CBaseHudChatInputLine( parent, panelName ) {} + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +}; + +class CHudChat : public CBaseHudChat +{ + DECLARE_CLASS_SIMPLE( CHudChat, CBaseHudChat ); + +public: + CHudChat( const char *pElementName ); + + virtual void CreateChatInputLine( void ); + virtual void CreateChatLines( void ); + + virtual void Init( void ); + virtual void Reset( void ); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + void MsgFunc_SayText( bf_read &msg ); + void MsgFunc_TextMsg( bf_read &msg ); + + void ChatPrintf( int iPlayerIndex, PRINTF_FORMAT_STRING const char *fmt, ... ); + + int GetChatInputOffset( void ); +}; + +#endif //SDK_HUD_CHAT_H \ No newline at end of file diff --git a/game/client/sdk/vgui/sdkviewport.h b/game/client/sdk/vgui/sdkviewport.h new file mode 100644 index 0000000..159da39 --- /dev/null +++ b/game/client/sdk/vgui/sdkviewport.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDKVIEWPORT_H +#define SDKVIEWPORT_H + + +#include "sdk_shareddefs.h" +#include "baseviewport.h" + + +using namespace vgui; + +namespace vgui +{ + class Panel; +} + +class SDKViewport : public CBaseViewport +{ + +private: + DECLARE_CLASS_SIMPLE( SDKViewport, CBaseViewport ); + +public: + + IViewPortPanel* CreatePanelByName(const char *szPanelName); + void CreateDefaultPanels( void ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + int GetDeathMessageStartHeight( void ); +}; + + +#endif // SDKViewport_H diff --git a/game/client/sdk/vgui/vgui_rootpanel_sdk.h b/game/client/sdk/vgui/vgui_rootpanel_sdk.h new file mode 100644 index 0000000..448abbc --- /dev/null +++ b/game/client/sdk/vgui/vgui_rootpanel_sdk.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VGUI_ROOTPANEL_SDK_H +#define VGUI_ROOTPANEL_SDK_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include +#include "utlvector.h" + + +class CPanelEffect; + + +// Serial under of effect, for safe lookup +typedef unsigned int EFFECT_HANDLE; + +//----------------------------------------------------------------------------- +// Purpose: Sits between engine and client .dll panels +// Responsible for drawing screen overlays +//----------------------------------------------------------------------------- +class C_SDKRootPanel : public vgui::Panel +{ + typedef vgui::Panel BaseClass; +public: + C_SDKRootPanel( vgui::VPANEL parent ); + virtual ~C_SDKRootPanel( void ); + + // Draw Panel effects here + virtual void PostChildPaint(); + + // Clear list of Panel Effects + virtual void LevelInit( void ); + virtual void LevelShutdown( void ); + + // Run effects and let them decide whether to remove themselves + void OnTick( void ); + +private: + + // Render all panel effects + void RenderPanelEffects( void ); + + // List of current panel effects + CUtlVector< CPanelEffect *> m_Effects; +}; + + +#endif // VGUI_ROOTPANEL_SDK_H diff --git a/game/client/simple_keys.h b/game/client/simple_keys.h new file mode 100644 index 0000000..1f3f0cd --- /dev/null +++ b/game/client/simple_keys.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SIMPLE_KEYS_H +#define SIMPLE_KEYS_H +#ifdef _WIN32 +#pragma once +#endif + +enum simplekeyinterp_t +{ + KEY_LINEAR = 0, + KEY_SPLINE, + KEY_ACCELERATE, + KEY_DECELERATE, +}; + +class CSimpleKeyInterp : public Vector +{ +public: + CSimpleKeyInterp( float t, simplekeyinterp_t interp, float x, float y = 0, float z = 0 ) : Vector( x, y, z ) + { + m_interp = interp; + m_keyTime = t; + } + + float GetTime() const { return m_keyTime; } + + // out = t*start + (1-t) * end (may be splinear or linear) + static void Interp( Vector &out, float t, const CSimpleKeyInterp &start, const CSimpleKeyInterp &end ); + + float m_keyTime; + simplekeyinterp_t m_interp; +}; + + +class CSimpleKeyList +{ +public: + int Insert( const CSimpleKeyInterp &key ); + bool Interp( Vector &out, float t ); + + CUtlVector m_list; +}; + +#endif // SIMPLE_KEYS_H diff --git a/game/client/sixense/in_sixense.h b/game/client/sixense/in_sixense.h new file mode 100644 index 0000000..eb56a8a --- /dev/null +++ b/game/client/sixense/in_sixense.h @@ -0,0 +1,278 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef IN_SIXENSE_H +#define IN_SIXENSE_H + +#include "mathlib/vector.h" +#include "vgui_controls/Frame.h" +#include "vgui_controls/Label.h" +#include "vgui_video.h" +#include "convar.h" +#include "usercmd.h" +#include "tier1/utlstring.h" +#include "GameEventListener.h" +#include "in_sixense_gesture_bindings.h" + + +#if defined( CLIENT_DLL ) +class C_Portal_Player; +#define CPortal_Player C_Portal_Player +#else +class CPortal_Player; +#endif + +// forward declarations +namespace sixenseUtils { + class IFPSViewAngles; + class IFPSPlayerMovement; + class IFPSEvents; + class IFPSMeleeWeapon; + + class IDerivatives; + class IButtonStates; + class ILaserPointer; + + class IControllerManager; +}; + +class SixenseInput : public CGameEventListener +{ + +public: + bool LoadModules(); + bool UnloadModules(); + + SixenseInput(); + ~SixenseInput(); + + + void Init(); + void PostInit(); + void Shutdown(); +#ifdef PORTAL2 + bool IsBaseWarningUp(); + void PlayerPortalled( const VMatrix &PortalMatrix ); + void SetOneToOneMode( bool bOnOrOff ); + + inline QAngle GetAnglesToRightHand() { return m_AnglesToRightHand; } + inline QAngle GetAnglesToLeftHand() { return m_AnglesToLeftHand; } + + // If the right trigger is held and a melee weapon is selected, go to 1-to-1 melee mode + bool IsInOneToOneMode(); + bool IsInAlwaysOneToOneMode(); + + void FixPortalView(); + void SetPortalTweakingParameters( bool bIsTweaking ); + + bool IsHoldingObject(); + + C_BaseEntity *GetHeldObject(); +#endif + + bool IsEnabled(); + bool IsLeftHanded(); + + // SixenseFrame computes the view parameters from the controllers. Should be called once per frame + bool SixenseFrame( float flFrametime, CUserCmd *pCmd ); + void SixenseUpdateKeys( float flFrametime, CUserCmd *pCmd ); + + bool SendKeyToActiveWindow(ButtonCode_t key); + void SixenseUpdateMouseCursor(); + void SixenseUpdateControllerManager(); + void controllerManagerCallback( int ); + inline void ResetFrameTime( float flTime ) { m_fRemainingFrameTime = flTime; } + + // Set the engine's view angles + void SetView( float flInputSampleFrametime, CUserCmd *pCmd ); + void SetMode( int nMode ); + void ResetView( QAngle SpawnAngles ); + void SetEnabled( bool bEnabled ); + void LoadDefaultSettings( int nLevel ); + bool InMenuMode(); + + + QAngle GetViewAngles(); + QAngle GetViewAngleOffset(); + + void ForceViewAngles( QAngle angles ); + bool IsSixenseMap(); + void CreateGUI( vgui::VPANEL parent ); + void SwitchViewModes( CUserCmd *pCmd ); + + // playerIndex = (0 to 3), handIndex = (left = 0 or right = 1) + void Rumble( unsigned char nIndex, unsigned char nRumbleData, unsigned char nRumbleFlags ); + void Rumble( unsigned char nPlayerIndex, unsigned char nHandIndex, unsigned char nRumbleData, unsigned char nRumbleFlags ); + + void SetFilter( float f ); + void GetFOV( float *pHfov, float *pVfov ); + +#ifdef SIXENSE_PLAYER_DATA + void SetPlayerHandPositions( CUserCmd *pCmd, float flFrametime ); +#endif + + void SetBaseOffset(); + void SetFilterLevel( float flNearRange, float flNearVal, float flFarRange, float flFarVal ); + + static class SixenseGUIFrame *m_SixenseFrame; + + bool IsAimingForwards(); + + + + virtual void FireGameEvent( IGameEvent *pEvent ); + + void BlendView(); + + void DisableFreeAimSpin( int nDisable ); + void DisableGestures( int nDisable ); + void PlayerSpawn(); + bool AreBindingsDisabled(); + + void LeftPointGesture( bool start ); + void RightPointGesture( bool start ); + + void StartRatchet(); + void StopRatchet(); + + void CheckWeaponForScope(); + + SixenseGestureBindings *GetGestureBindings(); + + void InstallConvarCallbacks(); + void UpdateValuesFromConvars(); + void ConvarChanged(); + +private: + + bool m_bIsEnabled; // sixense.dll loaded + bool m_bIsActive; // controllers not docked + + bool m_bModulesLoaded; + + bool m_bWasInMenuMode; + +#ifdef PORTAL2 + bool m_bJustPortalled; + + bool m_bIsLeftTriggerDown; + bool m_bIsRightTriggerDown; + + bool m_bIsIn1to1Mode; + bool m_bIs1to1ModeLocked; + bool m_bIs1to1ModeScaling; + bool m_bIs1to1ModeRatcheting; + + bool m_bExitOneWhenAimingForwards; + bool m_bScalingLockedOneToOne; + + bool m_bIsTweaking; + + float m_fDisableJumpUntil; + + int m_nGlowIndex; + + float m_fLastHorizSpeedMult; + float m_fLastVertSpeedMult; + + QAngle m_AnglesToRightHand, m_AnglesToLeftHand; + + float m_fTweakSixenseAimFreeaimAccelBandExponent; + float m_fTweakSixenseAimFreeaimAutoLevelRate; + float m_fTweakSixenseAimFreeaimAccelBandSize; + float m_fTweakSixenseAimFreeaimMaxSpeed; + float m_fTweakSixenseAimFreeaimDeadZoneRadius; + float m_fTweakSixenseAimFreeaimHeadingMultiplier; + float m_fTweakSixenseAimFreeaimPitchMultiplier; + float m_fTweakSixenseAim1to1HeadingMultiplier; + float m_fTweakSixenseAim1to1PitchMultiplier; + + Vector3 m_GrabPos; +#endif + + bool m_bConvarChanged; + + bool m_bPlayerValid; + + float m_fRemainingFrameTime; + + bool m_bScopeSwitchedMode; + sixenseUtils::IFPSViewAngles::fps_mode m_nScopeSwitchedPrevMode; + int m_nScopeSwitchedPrevSpringViewEnabled; + + float m_fTeleportWaitToBlendTime; + + class ISixenseAPI *m_pSixenseAPI; + + struct _sixenseAllControllerData *m_pACD; + + class sixenseUtils::IFPSViewAngles *m_pFPSViewAngles; + class sixenseUtils::IFPSPlayerMovement *m_pFPSPlayerMovement; + class sixenseUtils::IFPSEvents *m_pFPSEvents; + + class sixenseUtils::IDerivatives *m_pLeftDeriv, *m_pRightDeriv; + class sixenseUtils::IButtonStates *m_pLeftButtonStates, *m_pRightButtonStates; + class sixenseUtils::ILaserPointer *m_pLaserPointer; + + class sixenseUtils::IControllerManager *m_pControllerManager; + + int m_LastViewMode; + int m_nLeftIndex, m_nRightIndex; + + void PlayerDroppedEntity( int entityID ); + void PlayerUsedEntity( int entityID ); + + bool m_bMoveMouseToCenter; + int m_nFilterLevel; + unsigned char m_nLastLeftSequence, m_nLastRightSequence; + bool m_bShouldSetBaseOffset; + bool m_bJustSpawned; + +#ifdef WATERMARK + class SixenseWatermarkFrame *m_WatermarkFrame; +#endif + + int m_nFreeaimSpinDisabled; + int m_nGesturesDisabled; + + bool m_nShouldUnduck; + + SixenseGestureBindings *m_pGestureBindings; +}; + +extern SixenseInput *g_pSixenseInput; + + +class SixenseGUIFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( SixenseGUIFrame, vgui::Frame ); + +public: + + // Construction + SixenseGUIFrame( vgui::VPANEL parent, char const *pPanelName ); + virtual ~SixenseGUIFrame(); + + void setImage( CUtlString img_name ); + + virtual void SetVisible( bool bState ); + +private: + + vgui::ImagePanel *m_ImagePanel; + +}; + +#ifdef PORTAL2 +class SixenseBaseWarning : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( SixenseBaseWarning, vgui::Frame ); +public: + SixenseBaseWarning( vgui::Panel *parent, char const *name ); + //virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); +protected: + //virtual void PaintBackground(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + vgui::Label *_label; +}; +#endif + +#endif diff --git a/game/client/sixense/in_sixense_gesture_bindings.h b/game/client/sixense/in_sixense_gesture_bindings.h new file mode 100644 index 0000000..d9e334e --- /dev/null +++ b/game/client/sixense/in_sixense_gesture_bindings.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef IN_SIXENSE_GESTURES_H +#define IN_SIXENSE_GESTURES_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +class SixenseGestureBindings { +public: + SixenseGestureBindings(); + + // Add a new binding. release_command can be empty. If press_command starts with '+', a release_command is generated with '-'. + void AddBinding( CUtlString hand, CUtlString action, CUtlString arg, CUtlString press_command, CUtlString release_command ); + + // Print bindings to console + void ListBindings(); + + // Write the bindings to a cfg file that can be loaded from the console or at startup (defaults to sixense_bindings.cfg) + void WriteBindings( CUtlString filename ); + + // Clear all bindings + void ClearBindings(); + + // Delete the nth binding + void DeleteBinding( int n ); + + // Create a set of default bindings appropriate for this game + void CreateDefaultBindings(); + + // Check to see if any bindings need to be triggered. disable_activations allows the caller to prevent new bindings from being triggered, while + // still allowing enabled gestures to disable. + void UpdateBindings( sixenseUtils::IButtonStates *pLeftButtonStates, sixenseUtils::IButtonStates *pRightButtonStates, bool bIsMenuVisible ); + + // How many bindings are there? + int GetNumBindings(); + + // Allow per-game authorization of commmands when the menu is up + bool AllowMenuCommand( char * ); + + // Allow per-game authorization of commmands in general + bool AllowCommand( char * ); + +protected: + typedef struct { + int m_Action; + int m_iHand; // 0=left, 1=right + int m_iArgument; + char *m_pActivateCommand; + char *m_pDeactivateCommand; + bool m_bAutoMirrored; + } GestureBinding; + + // some helpers for converting input strings + bool HandFromString( CUtlString hand_str, int *hand ); + bool ActionFromString( CUtlString action_str, sixenseUtils::IButtonStates::ActionType *action ); + bool ButtonMaskFromString( CUtlString button, unsigned short *button_token ); + bool DirectionFromString( CUtlString dir_str, sixenseUtils::IButtonStates::Direction *dir ); + bool ActionTokenToStr( sixenseUtils::IButtonStates::ActionType action, char *buf, int buflen ); + bool DirectionTokenToStr( int arg, char *buf, int buflen ); + bool ButtonTokenToStr( int arg, char *buf, int buflen ); + bool HandTokenToStr( int hand, char *buf, int buflen ); + + // Help deallocate a binding + void FreeStrings( GestureBinding binding ); + +private: + CUtlLinkedList m_GestureBindingList; + +}; + +#endif diff --git a/game/client/smoke_fog_overlay.h b/game/client/smoke_fog_overlay.h new file mode 100644 index 0000000..175e0ec --- /dev/null +++ b/game/client/smoke_fog_overlay.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef SMOKE_FOG_OVERLAY_H +#define SMOKE_FOG_OVERLAY_H + + +#include "basetypes.h" +#include "mathlib/vector.h" +#include "smoke_fog_overlay_shared.h" + + +#define ROTATION_SPEED 0.1 +#define TRADE_DURATION_MIN 10 +#define TRADE_DURATION_MAX 20 +#define SMOKEGRENADE_PARTICLERADIUS 80 + +#define SMOKESPHERE_EXPAND_TIME 1 // Take N seconds to expand to SMOKESPHERE_MAX_RADIUS. + +#define NUM_PARTICLES_PER_DIMENSION 4 +#define SMOKEPARTICLE_OVERLAP 20 + +#define SMOKEPARTICLE_SIZE 80 +#define NUM_MATERIAL_HANDLES 1 + + +void InitSmokeFogOverlay(); +void TermSmokeFogOverlay(); +void DrawSmokeFogOverlay(); + + +// Set these before calling DrawSmokeFogOverlay. +extern float g_SmokeFogOverlayAlpha; +extern Vector g_SmokeFogOverlayColor; + + +#endif + + diff --git a/game/client/splinepatch.h b/game/client/splinepatch.h new file mode 100644 index 0000000..31af0f0 --- /dev/null +++ b/game/client/splinepatch.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A little helper class that computes a spline patch +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SPLINEPATCH_H +#define SPLINEPATCH_H +#pragma once + +#include "mathlib/vector4d.h" + +//----------------------------------------------------------------------------- +// Spline patch: +//----------------------------------------------------------------------------- + +class CSplinePatch +{ +public: + // The last argument represents the number of float channels in addition to position + CSplinePatch( ); + ~CSplinePatch(); + + // Call this to initialize the patch + void Init( int w, int h, int extraChannels ); + + // 0 = linear, 1 = spliney! + void SetLinearBlend( float factor ); + + // Hooks the patch up to externally controlled data... + void SetControlPositions( Vector const** pPositions ); + void SetChannelData( int channel, float* pChannel ); + + // This interface isn't wonderful; it's limited by optimization issues... + + // Call this before querying the patch for data at (i,j) + void SetupPatchQuery( float i, float j ); + + // Gets the point and normal at (i,j) specified above + void GetPointAndNormal( Vector& position, Vector& normal ) const; + + // Gets at other channels + float GetChannel( int channel ) const; + + // Gets at the dimensions + int Width() const { return m_Width; } + int Height() const { return m_Height; } + +public: + // The integer + float values for the patch query + int m_is, m_it; + float m_fs, m_ft; + +private: + enum + { + MAX_CHANNELS = 4 + }; + + // no copy constructor + CSplinePatch( const CSplinePatch& ); + + // Computes indices of the samples to read for this interpolation + void ComputeIndices( ); + + // input data + int m_Width; + int m_Height; + int m_ChannelCount; + Vector const** m_ppPositions; + float const* m_pChannel[MAX_CHANNELS]; + + // temporary data used for a single patch query + int m_SampleIndices[4][4]; + Vector4D m_SVec; + Vector4D m_TVec; + + float m_LinearFactor; +}; + +#endif // SPLINEPATCH_H diff --git a/game/client/studio_stats.h b/game/client/studio_stats.h new file mode 100644 index 0000000..831bb7d --- /dev/null +++ b/game/client/studio_stats.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef __STUDIO_STATS_H +#define __STUDIO_STATS_H + +#ifdef _WIN32 +#pragma once +#endif + +void StudioStats_FindClosestEntity( CClientRenderablesList *pClientRenderablesList ); + +extern IClientRenderable *g_pStudioStatsEntity; + + +#endif // __STUDIO_STATS_H diff --git a/game/client/tempent.h b/game/client/tempent.h new file mode 100644 index 0000000..16b5653 --- /dev/null +++ b/game/client/tempent.h @@ -0,0 +1,148 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( TEMPENT_H ) +#define TEMPENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "c_baseanimating.h" +#include "c_sprite.h" + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SMOKEGROWANDFADE 0x00020000 // rapid grow and fade. Very specific for gunsmoke +#define FTENT_ATTACHTOTARGET 0x00040000 // attach to whatever we hit, and stay there until die time is up +#define FTENT_NOMODEL 0x00080000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00100000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) +#define FTENT_WINDBLOWN 0x00200000 // This is set when the temp entity is blown by the wind +#define FTENT_NEVERDIE 0x00400000 // Don't die as long as die != 0 +#define FTENT_BEOCCLUDED 0x00800000 // Don't draw if my specified normal's facing away from the view +#define FTENT_CHANGERENDERONCOLLIDE 0x01000000 //when we collide with something, change our rendergroup to RENDER_GROUP_OTHER +#define FTENT_COLLISIONGROUP 0x02000000 // if set, use the C_BaseEntity::GetCollisionGroup when doing collide trace +#define FTENT_ALIGNTOMOTION 0x04000000 // Change angles to always point in the direction of motion +#define FTENT_CLIENTSIDEPARTICLES 0x08000000 // The object has a clientside particle system. +#define FTENT_USEFASTCOLLISIONS 0x10000000 // Use fast collisions (cl_fasttempentcollision). +#define FTENT_COLLIDEPROPS 0x20000000 // Collide with the world and props + +class C_LocalTempEntity; + +typedef int (*pfnDrawHelper)( C_LocalTempEntity *entity, int flags ); + +//----------------------------------------------------------------------------- +// Purpose: Should this derive from some other class +//----------------------------------------------------------------------------- +class C_LocalTempEntity : public C_BaseAnimating, public C_SpriteRenderer +{ +public: + DECLARE_CLASS( C_LocalTempEntity, C_BaseAnimating ); + + C_LocalTempEntity(); + + virtual void Prepare( const model_t *pmodel, float time ); + + virtual bool IsActive( void ); + virtual bool Frame( float frametime, int framenumber ); + + // C_BaseAnimating , etc. override + virtual int DrawModel( int flags ); + + // Sets the velocity + void SetVelocity( const Vector &vecVelocity ); + const Vector &GetVelocity() const { return m_vecTempEntVelocity; } + + // Set the acceleration + void SetAcceleration( const Vector &vecAccel ); + const Vector &GetAcceleration() const { return m_vecTempEntAcceleration; } + + void SetDrawHelper( pfnDrawHelper helper ) { m_pfnDrawHelper = helper; } + void OnRemoveTempEntity(); + + void SetImpactEffect( const char *pszImpactEffect ) { m_pszImpactEffect = pszImpactEffect; } + CNewParticleEffect* AddParticleEffect( const char *pszParticleEffect ); + void SetParticleEffect( const char *pszParticleEffect ) { m_pszParticleEffect = pszParticleEffect; } + +protected: + + pfnDrawHelper m_pfnDrawHelper; + +public: + int flags; + float die; + float m_flFrameMax; + float x; + float y; + float fadeSpeed; + float bounceFactor; + int hitSound; + int priority; + // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + short clientIndex; + + // if attached, client origin + tentOffset = tent origin. + Vector tentOffset; + + // Used by temp entities. + QAngle m_vecTempEntAngVelocity; + int tempent_renderamt; + Vector m_vecNormal; + + float m_flSpriteScale; + int m_nFlickerFrame; + + // + float m_flFrameRate; + float m_flFrame; + + RenderGroup_t m_RenderGroup; + + const char *m_pszImpactEffect; + const char *m_pszParticleEffect; + bool m_bParticleCollision; + + int m_iLastCollisionFrame; + Vector m_vLastCollisionOrigin; + +private: + C_LocalTempEntity( const C_LocalTempEntity & ); + + Vector m_vecTempEntVelocity; + Vector m_vecPrevLocalOrigin; + + Vector m_vecTempEntAcceleration; + + // Draw tempent as a studio model + int DrawStudioModel( int flags ); + +}; + +#endif // TEMPENTITY_H \ No newline at end of file diff --git a/game/client/text_message.h b/game/client/text_message.h new file mode 100644 index 0000000..1572901 --- /dev/null +++ b/game/client/text_message.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( TEXT_MESSAGE_H ) +#define TEXT_MESSAGE_H +#ifdef _WIN32 +#pragma once +#endif + +abstract_class IHudTextMessage +{ +public: + virtual char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) = 0; + virtual char *BufferedLocaliseTextString( const char *msg ) = 0; + virtual char *LookupString( const char *msg_name, int *msg_dest = NULL ) = 0; +}; + +extern IHudTextMessage *hudtextmessage; +#endif // TEXT_MESSAGE_H \ No newline at end of file diff --git a/game/client/timedevent.h b/game/client/timedevent.h new file mode 100644 index 0000000..8c58be5 --- /dev/null +++ b/game/client/timedevent.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TIMEDEVENT_H +#define TIMEDEVENT_H +#ifdef _WIN32 +#pragma once +#endif + +// This class triggers events at a specified rate. Just call NextEvent() and do an event until it +// returns false. For example, if you want to spawn particles 10 times per second, do this: +// pTimer->SetRate(10); +// float tempDelta = fTimeDelta; +// while(pTimer->NextEvent(tempDelta)) +// spawn a particle + +class TimedEvent +{ +public: + TimedEvent() + { + m_TimeBetweenEvents = -1; + m_fNextEvent = 0; + } + + // Rate is in events per second (ie: rate of 15 will trigger 15 events per second). + inline void Init(float rate) + { + m_TimeBetweenEvents = 1.0f / rate; + m_fNextEvent = 0; + } + + inline void ResetRate(float rate) + { + m_TimeBetweenEvents = 1.0f / rate; + } + + inline bool NextEvent(float &curDelta) + { + // If this goes off, you didn't call Init(). + Assert( m_TimeBetweenEvents != -1 ); + + if(curDelta >= m_fNextEvent) + { + curDelta -= m_fNextEvent; + + m_fNextEvent = m_TimeBetweenEvents; + return true; + } + else + { + m_fNextEvent -= curDelta; + return false; + } + } + +private: + float m_TimeBetweenEvents; + float m_fNextEvent; // When the next event should be triggered. +}; + +#endif // TIMEDEVENT_H diff --git a/game/client/toggletextureproxy.h b/game/client/toggletextureproxy.h new file mode 100644 index 0000000..66bd828 --- /dev/null +++ b/game/client/toggletextureproxy.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TOGGLETEXTUREPROXY +#define TOGGLETEXTUREPROXY + +#include "materialsystem/imaterialproxy.h" + +class IMaterial; +class IMaterialVar; + +#pragma warning (disable : 4100) + +class CBaseToggleTextureProxy : public IMaterialProxy +{ +public: + CBaseToggleTextureProxy(); + virtual ~CBaseToggleTextureProxy(); + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( void *pC_BaseEntity ); + virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); + +private: + void Cleanup(); + + C_BaseEntity *BindArgToEntity( void *pArg ); + + IMaterialVar *m_TextureVar; + IMaterialVar *m_TextureFrameNumVar; + bool m_WrapAnimation; +}; + +#endif // TOGGLETEXTUREPROXY \ No newline at end of file diff --git a/game/client/toolframework_client.h b/game/client/toolframework_client.h new file mode 100644 index 0000000..0ef9760 --- /dev/null +++ b/game/client/toolframework_client.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef TOOLFRAMEWORK_CLIENT_H +#define TOOLFRAMEWORK_CLIENT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "toolframework/itoolentity.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class KeyValues; +struct AudioState_t; + + +//----------------------------------------------------------------------------- +// Posts a message to all tools +//----------------------------------------------------------------------------- +void ToolFramework_PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ); + + +//----------------------------------------------------------------------------- +// Should we render with a 3rd person camera? +//----------------------------------------------------------------------------- +bool ToolFramework_IsThirdPersonCamera( ); + + +//----------------------------------------------------------------------------- +// Are tools enabled? +//----------------------------------------------------------------------------- +#ifndef NO_TOOLFRAMEWORK +bool ToolsEnabled(); +#else +#define ToolsEnabled() 0 +#endif + + +//----------------------------------------------------------------------------- +// View manipulation +//----------------------------------------------------------------------------- +void ToolFramework_AdjustEngineViewport( int& x, int& y, int& width, int& height ); +bool ToolFramework_SetupEngineView( Vector &origin, QAngle &angles, float &fov ); +bool ToolFramework_SetupAudioState( AudioState_t &audioState ); + +//----------------------------------------------------------------------------- +// material recording - primarily for proxy materials +//----------------------------------------------------------------------------- +void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); + +//----------------------------------------------------------------------------- +// Recorded temp entity structures +//----------------------------------------------------------------------------- +enum TERecordingType_t +{ + TE_DYNAMIC_LIGHT = 0, + TE_WORLD_DECAL, + TE_DISPATCH_EFFECT, + TE_MUZZLE_FLASH, + TE_ARMOR_RICOCHET, + TE_METAL_SPARKS, + TE_SMOKE, + TE_SPARKS, + TE_BLOOD_SPRITE, + TE_BREAK_MODEL, + TE_GLOW_SPRITE, + TE_PHYSICS_PROP, + TE_SPRITE_SINGLE, + TE_SPRITE_SPRAY, + TE_CONCUSSIVE_EXPLOSION, + TE_BLOOD_STREAM, + TE_SHATTER_SURFACE, + TE_DECAL, + TE_PROJECT_DECAL, + TE_EXPLOSION, + + TE_RECORDING_TYPE_COUNT, +}; + + +//----------------------------------------------------------------------------- +// Helper class to indicate ownership of effects +//----------------------------------------------------------------------------- +class CRecordEffectOwner +{ +public: + CRecordEffectOwner( C_BaseEntity *pEntity, bool bIsViewModel = false ); + ~CRecordEffectOwner(); + +private: + bool m_bToolsEnabled; +}; + +#endif // TOOLFRAMEWORK_CLIENT_H \ No newline at end of file diff --git a/game/client/vgui_avatarimage.h b/game/client/vgui_avatarimage.h new file mode 100644 index 0000000..de4db42 --- /dev/null +++ b/game/client/vgui_avatarimage.h @@ -0,0 +1,254 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VGUI_AVATARIMAGE_H +#define VGUI_AVATARIMAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "steam/steam_api.h" +#include "c_baseplayer.h" + +// size of the friend background frame (see texture ico_friend_indicator_avatar) +#define FRIEND_ICON_SIZE_X (55) +#define FRIEND_ICON_SIZE_Y (34) + +// offset of avatar within the friend icon +#define FRIEND_ICON_AVATAR_INDENT_X (22) +#define FRIEND_ICON_AVATAR_INDENT_Y (1) + +// size of the standard avatar icon (unless override by SetAvatarSize) +#define DEFAULT_AVATAR_SIZE (32) + + +//============================================================================= +// HPE_CHANGE: +// [pfreese] Refactored these classes so that the CAvatarImage supports a +// default image to be used whenever the Steam avatar is not set or fails to +// be retrieved. +//============================================================================= + +struct AvatarImagePair_t +{ + AvatarImagePair_t() { m_iAvatar = 0; } + AvatarImagePair_t( CSteamID steamID, int av ) { m_SteamID = steamID; m_iAvatar = av; } + bool operator<( const AvatarImagePair_t &rhs ) const + { + return m_SteamID.ConvertToUint64() < rhs.m_SteamID.ConvertToUint64() || + ( m_SteamID.ConvertToUint64() == rhs.m_SteamID.ConvertToUint64() && m_iAvatar < rhs.m_iAvatar ); + } + + CSteamID m_SteamID; + int m_iAvatar; +}; + +//----------------------------------------------------------------------------- +// Purpose: avatar sizes, formerly used in ISteamFriends, but now only used in game code +//----------------------------------------------------------------------------- +enum EAvatarSize +{ + k_EAvatarSize32x32 = 0, + k_EAvatarSize64x64 = 1, + k_EAvatarSize184x184 = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAvatarImage : public vgui::IImage +{ +public: + CAvatarImage( void ); + + // Call this to set the steam ID associated with the avatar + //============================================================================= + // HPE_BEGIN: + // [tj] Added parameter to specify size. Default is 32x32. + //============================================================================= + bool SetAvatarSteamID( CSteamID steamIDUser, EAvatarSize avatarSize = k_EAvatarSize32x32 ); + //============================================================================= + // HPE_END + //============================================================================= + void UpdateFriendStatus( void ); + void ClearAvatarSteamID( void ); + + // Call to Paint the image + // Image will draw within the current panel context at the specified position + virtual void Paint( void ); + + // Set the position of the image + virtual void SetPos(int x, int y) + { + m_nX = x; + m_nY = y; + } + + // Gets the size of the content + virtual void GetContentSize(int &wide, int &tall) + { + wide = m_wide; + tall = m_tall; + } + + // Get the size the image will actually draw in (usually defaults to the content size) + virtual void GetSize(int &wide, int &tall) + { + GetContentSize( wide, tall ); + } + + // Sets the size of the image + virtual void SetSize(int wide, int tall); + + void SetAvatarSize(int wide, int tall); + + // Set the draw color + virtual void SetColor(Color col) + { + m_Color = col; + } + + bool IsValid() { return m_bValid; } + int GetWide() { return m_wide; } + int GetTall() { return m_tall; } + int GetAvatarWide() { return m_avatarWide; } + int GetAvatarTall() { return m_avatarTall; } + + //============================================================================= + // HPE_BEGIN: + //============================================================================= + + // [tj] simple setter for drawing friend icon + void SetDrawFriend(bool drawFriend) { m_bDrawFriend = drawFriend; } + + // [pmf] specify the default (fallback) image + void SetDefaultImage(vgui::IImage* pImage) { m_pDefaultImage = pImage; } + + //============================================================================= + // HPE_END + //============================================================================= + + virtual bool Evict(); + virtual int GetNumFrames(); + virtual void SetFrame( int nFrame ); + virtual vgui::HTexture GetID(); + virtual void SetRotation( int iRotation ) { return; } + +protected: + void InitFromRGBA( int iAvatar, const byte *rgba, int width, int height ); + +private: + void LoadAvatarImage(); + + Color m_Color; + int m_iTextureID; + int m_nX, m_nY; + int m_wide, m_tall; + int m_avatarWide, m_avatarTall; + bool m_bValid; + bool m_bFriend; + bool m_bLoadPending; + float m_fNextLoadTime; // used to throttle load attempts + + EAvatarSize m_AvatarSize; + CHudTexture *m_pFriendIcon; + CSteamID m_SteamID; + + //============================================================================= + // HPE_BEGIN: + //============================================================================= + + // [tj] Whether or not we should draw the friend icon + bool m_bDrawFriend; + + // [pmf] image to use as a fallback when get from steam fails (or not called) + vgui::IImage* m_pDefaultImage; + + //============================================================================= + // HPE_END + //============================================================================= + + static CUtlMap< AvatarImagePair_t, int > s_AvatarImageCache; + static bool m_sbInitializedAvatarCache; + + CCallback m_sPersonaStateChangedCallback; + + void OnPersonaStateChanged( PersonaStateChange_t *info ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAvatarImagePanel : public vgui::Panel +{ +public: + DECLARE_CLASS_SIMPLE( CAvatarImagePanel, vgui::Panel ); + + CAvatarImagePanel( vgui::Panel *parent, const char *name ); + + // Set the player that this Avatar should display for + //============================================================================= + // HPE_BEGIN: + // [menglish] Added default variable of scalable to allow the avatar to be drawn at sizes other than 32, 32 + // [tj] added a parameter for drawing the friend icon. Defaulted to true to maintain backward compatibility. + // [menglish] Added parameter to specify a default avatar + // [menglish] Added a function to set the avatar size of the AvatarImage + //============================================================================= + + // reset the image to its default value, clearing any info retrieved from Steam + void ClearAvatar(); + + void SetPlayer( C_BasePlayer *pPlayer, EAvatarSize avatarSize = k_EAvatarSize32x32 ); + + // [tj] Overloaded function to go straight to entity index + void SetPlayer( int entityIndex, EAvatarSize avatarSize = k_EAvatarSize32x32 ); + + // [tj] lower level function that expects a steam ID instead of a player + void SetPlayer(CSteamID steamIDForPlayer, EAvatarSize avatarSize ); + + // sets whether or not the image should scale to fit the size of the ImagePanel (defaults to false) + void SetShouldScaleImage( bool bScaleImage ); + + // sets whether to automatically draw the friend icon behind the avatar for Steam friends + void SetShouldDrawFriendIcon( bool bDrawFriend ); + + // specify the size of the avatar portion of the image (the actual image may be larger than this + // when it incorporates the friend icon) + void SetAvatarSize( int width, int height); + + // specify a fallback image to use + void SetDefaultAvatar(vgui::IImage* pDefaultAvatar); + + virtual void OnSizeChanged(int newWide, int newTall); + + //============================================================================= + // HPE_END + //============================================================================= + + virtual void OnMousePressed(vgui::MouseCode code); + + virtual void PaintBackground(); + bool IsValid() { return (m_pImage->IsValid()); } + + void SetClickable( bool bClickable ) { m_bClickable = bClickable; } + +protected: + CPanelAnimationVar( Color, m_clrOutline, "color_outline", "Black" ); + virtual void ApplySettings(KeyValues *inResourceData); + + void UpdateSize(); + +private: + CAvatarImage *m_pImage; + bool m_bScaleImage; + bool m_bSizeDirty; + bool m_bClickable; +}; + +#endif // VGUI_AVATARIMAGE_H diff --git a/game/client/vgui_basepanel.h b/game/client/vgui_basepanel.h new file mode 100644 index 0000000..daec845 --- /dev/null +++ b/game/client/vgui_basepanel.h @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( VGUI_BASEPANEL_H ) +#define VGUI_BASEPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +// Global interface allowing various rendering +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Purpose: Base Panel for engine vgui panels ( can handle some drawing stuff ) +//----------------------------------------------------------------------------- +class CBasePanel : public vgui::Panel +{ +public: + DECLARE_CLASS_GAMEROOT( CBasePanel, vgui::Panel ); + + CBasePanel( vgui::Panel *pParent, const char *panelName ); + CBasePanel( vgui::Panel *pParent, const char *panelName, int x, int y, int w, int h ); + virtual ~CBasePanel( void ); + + // should this panel be drawn this frame? + virtual bool ShouldDraw( void ) { return true;} + + virtual void PaintBackground( void ); + + virtual void SetTexture( const char *texname, bool tiled = false ); + + virtual void SetReflectMouse( bool reflect ); + // If reflect mouse is true, then pass these up to parent + virtual void OnCursorMoved(int x,int y); + virtual void OnMousePressed(vgui::MouseCode code); + virtual void OnMouseDoublePressed(vgui::MouseCode code); + virtual void OnMouseReleased(vgui::MouseCode code); + virtual void OnMouseWheeled(int delta); + + virtual void OnTick( void ); + +protected: + bool m_bTexturedBackground; + int m_nBackgroundMaterial; + char m_szBgTexture[ 256 ]; + bool m_bTiled; + int m_nTextureSize[ 2 ]; + + bool m_bReflectMouse; +}; + +//----------------------------------------------------------------------------- +// Purpose: Hud labels that use HUD scheme colors +//----------------------------------------------------------------------------- +class CHudLabel : public vgui::Label +{ + typedef vgui::Label BaseClass; +public: + CHudLabel( vgui::Panel *parent, const char *panelName, const char *text ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + // Selection highlight + void SetSelected( bool bSelected ); + + bool m_bSelected; + +private: + CHudLabel( const CHudLabel & ); // not defined, not accessible +}; + +#endif // VGUI_BASEPANEL_H diff --git a/game/client/vgui_bitmapbutton.h b/game/client/vgui_bitmapbutton.h new file mode 100644 index 0000000..a52e766 --- /dev/null +++ b/game/client/vgui_bitmapbutton.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which is rendered image on top of an entity +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_BITMAPBUTTON_H +#define VGUI_BITMAPBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "vgui_bitmapimage.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class KeyValues; + +//----------------------------------------------------------------------------- +// A button that renders images instead of standard vgui stuff... +//----------------------------------------------------------------------------- +class CBitmapButton : public vgui::Button +{ + typedef vgui::Button BaseClass; + +public: + enum ButtonImageType_t + { + BUTTON_ENABLED = 0, + BUTTON_ENABLED_MOUSE_OVER, + BUTTON_PRESSED, + BUTTON_DISABLED, + + BUTTON_STATE_COUNT + }; + + // constructor + CBitmapButton( vgui::Panel *pParent, const char *pName, const char *pText ); + ~CBitmapButton(); + + // initialization + bool Init( KeyValues* pInitData ); + + void SetImage( ButtonImageType_t type, const char *pMaterialName, color32 color ); + bool IsImageLoaded( ButtonImageType_t type ) const; + + // initialization from build-mode dialog style .res files + virtual void ApplySettings(KeyValues *inResourceData); + + virtual void Paint( void ); + virtual void PaintBackground( void ) {} + +private: + + BitmapImage m_pImage[BUTTON_STATE_COUNT]; + bool m_bImageLoaded[BUTTON_STATE_COUNT]; +}; + + +#endif // VGUI_BITMAPBUTTON_H \ No newline at end of file diff --git a/game/client/vgui_bitmapimage.h b/game/client/vgui_bitmapimage.h new file mode 100644 index 0000000..5a2525b --- /dev/null +++ b/game/client/vgui_bitmapimage.h @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_BITMAPIMAGE_H +#define VGUI_BITMAPIMAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + class Panel; +} + +class KeyValues; +struct Bitmap_t; + +//----------------------------------------------------------------------------- +// Purpose: Bitmap image +//----------------------------------------------------------------------------- +class BitmapImage : public vgui::Image +{ +public: + BitmapImage(); + BitmapImage( vgui::VPANEL pPanelSize, const char *pFileName ); + virtual ~BitmapImage(); + bool Init( vgui::VPANEL pParent, const char *pFileName ); + bool Init( vgui::VPANEL pParent, KeyValues* pInitData ); + + /* FIXME: Bleah!!! Don't want two different KeyValues + bool Init( vgui::VPANEL pParent, KeyValues* pInitData ); */ + + void DoPaint( vgui::VPANEL panel, float yaw = 0, float flAlphaModulate = 1.0f ); + void DoPaint( int x, int y, int w, int h, float yaw = 0, float flAlphaModulate = 1.0f ); + void Paint( ); + void SetColor( const Color& clr ); + Color GetColor( ); + void GetColor( int& r,int& g,int& b,int& a ); + void GetSize( int& wide, int& tall ); + void SetPos( int x, int y ); + void SetRenderSize( int x, int y ); + + void SetImageFile( const char *newImage ); + + // Pass NULL in to use the size set in SetSize + // otherwise it'll use the size of the panel + void UsePanelRenderSize( vgui::VPANEL pPanel ); + vgui::VPANEL GetRenderSizePanel( void ); + + void SetViewport( bool use, float left, float top, float right, float bottom ); + + /// Set raw bitmap data + void SetBitmap( const Bitmap_t &bitmap ); + + /// Clean up vgui resources + void DestroyTexture(); + +private: + int m_nTextureId; + Color m_clr; + int m_pos[2]; + int m_Size[2]; + vgui::VPANEL m_pPanelSize; + + bool m_bUseViewport; + float m_rgViewport[ 4 ]; + bool m_bProcedural; +}; + + +//----------------------------------------------------------------------------- +// Helper method to initialize a bitmap image from KeyValues data.. +// KeyValues contains the bitmap data. pSectionName, if it exists, +// indicates which subsection of pInitData should be looked at to get at the +// image data. The parent argument specifies which panel to use as parent, +// and the final argument is the bitmap image to initialize. +// The function returns true if it succeeded. +// +// NOTE: This function looks for the key values 'material' and 'color' +// and uses them to set up the material + modulation color of the image +//----------------------------------------------------------------------------- +bool InitializeImage( KeyValues *pInitData, const char* pSectionName, vgui::Panel *pParent, BitmapImage* pBitmapImage ); + +/* FIXME: How sad. We need to make KeyValues + vgui::KeyValues be the same. Bleah +bool InitializeImage( KeyValues *pInitData, const char* pSectionName, vgui::Panel *pParent, BitmapImage* pBitmapImage ); */ + + +#endif // VGUI_BITMAPIMAGE_H diff --git a/game/client/vgui_bitmappanel.h b/game/client/vgui_bitmappanel.h new file mode 100644 index 0000000..4ed1f43 --- /dev/null +++ b/game/client/vgui_bitmappanel.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which is rendered image on top of an entity +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_BITMAPPANEL_H +#define VGUI_BITMAPPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class KeyValues; +class BitmapImage; +struct Bitmap_t; + +//----------------------------------------------------------------------------- +// This is a base class for a panel which always is rendered on top of an entity +//----------------------------------------------------------------------------- +class CBitmapPanel : public vgui::Panel +{ + typedef vgui::Panel BaseClass; + +public: + // constructor + CBitmapPanel( ); + CBitmapPanel( vgui::Panel *pParent, const char *pName ); + ~CBitmapPanel(); + + // initialization + bool Init( KeyValues* pInitData ); + + // initialization from build-mode dialog style .res files + virtual void ApplySettings(KeyValues *inResourceData); + + virtual void Paint( void ); + virtual void PaintBackground( void ) {} + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + + // Setup for panels that aren't created by the commander overlay factory (i.e. aren't parsed from a keyvalues file) + virtual void SetImage( BitmapImage *pImage ); + + /// Set bitmap data directly + virtual void SetBitmap( const Bitmap_t &bitmap ); + + const char *GetMouseOverText( void ); + +private: + enum + { + MAX_ENTITY_MOUSEOVER = 256 + }; + // The bitmap to render + BitmapImage *m_pImage; + int m_r, m_g, m_b, m_a; + bool m_bOwnsImage; + + char m_szMouseOverText[ MAX_ENTITY_MOUSEOVER ]; + +}; + +#endif // VGUI_BITMAPPANEL_H \ No newline at end of file diff --git a/game/client/vgui_entityimagepanel.h b/game/client/vgui_entityimagepanel.h new file mode 100644 index 0000000..bb54525 --- /dev/null +++ b/game/client/vgui_entityimagepanel.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which is rendered image on top of an entity +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_ENTITYIMAGEPANEL_H +#define VGUI_ENTITYIMAGEPANEL_H + +#include "vgui_EntityPanel.h" +#include "shareddefs.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class C_BaseEntity; +class KeyValues; +class BitmapImage; + +//----------------------------------------------------------------------------- +// This is a base class for a panel which always is rendered on top of an entity +//----------------------------------------------------------------------------- + +class CEntityImagePanel : public CEntityPanel +{ + DECLARE_CLASS( CEntityImagePanel, CEntityPanel ); + +public: + // constructor + CEntityImagePanel( vgui::Panel* pParent, const char *panelName ); + ~CEntityImagePanel(); + + // initialization + virtual bool Init( KeyValues* pInitData, C_BaseEntity* pEntity ); + + bool ShouldDraw(); + + virtual void Paint( void ); + virtual void PaintBackground( void ) {} + +private: + // The bitmap to render + BitmapImage *m_pImage; + +protected: + int m_r, m_g, m_b, m_a; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Same as above, but understands how to parse color/material out of +// Team1/Team2 sections +//----------------------------------------------------------------------------- +class CEntityTeamImagePanel : public CEntityImagePanel +{ + DECLARE_CLASS( CEntityTeamImagePanel, CEntityImagePanel ); + +public: + CEntityTeamImagePanel( vgui::Panel* pParent, const char *panelName ); + ~CEntityTeamImagePanel( void ); + // initialization + virtual bool Init( KeyValues* pInitData, C_BaseEntity* pEntity ); + + virtual void Paint( void ); + +private: + struct TEAMIMAGE + { + BitmapImage *m_pImage; + int m_r, m_g, m_b, m_a; + }; + + TEAMIMAGE m_Images[ MAX_TEAMS ]; +}; + +#endif // VGUI_ENTITYIMAGEPANEL_H \ No newline at end of file diff --git a/game/client/vgui_entitypanel.h b/game/client/vgui_entitypanel.h new file mode 100644 index 0000000..69cfbb3 --- /dev/null +++ b/game/client/vgui_entitypanel.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which is rendered on top of an entity +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_ENTITYPANEL_H +#define VGUI_ENTITYPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include +#include "vgui_basepanel.h" + +// forward declarations +class KeyValues; + + +//----------------------------------------------------------------------------- +// This is a base class for a panel which always is rendered on top of an entity +//----------------------------------------------------------------------------- +class CEntityPanel : public CBasePanel +{ +public: + DECLARE_CLASS( CEntityPanel, CBasePanel ); + + // constructor + CEntityPanel( vgui::Panel *pParent, const char *panelName ); + + virtual void ComputeParent( void ); + virtual void ComputeAndSetSize( void ); + + // Initialize from key values + bool Init( KeyValues* pKeyValues, C_BaseEntity* pEntity ); + + // Determine where our entity is in screen space. + void GetEntityPosition( int& sx, int& sy ); + + // Base implementation of ShouldDraw + bool ShouldDraw(); + + // called when we're ticked (updates our position)... + virtual void OnTick( void ); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + + const char *GetMouseOverText( void ); + + C_BaseEntity* GetEntity() { return (C_BaseEntity*)m_pBaseEntity; } + + // Attach to a new entity + void SetEntity( C_BaseEntity* pEntity ); + +public: + enum + { + MAX_ENTITY_MOUSEOVER = 256 + }; + + // Offset from entity that we should draw + int m_OffsetX, m_OffsetY; + + char m_szMouseOverText[ MAX_ENTITY_MOUSEOVER ]; + + bool m_bShowInNormal; + + int m_iOrgWidth; + int m_iOrgHeight; + int m_iOrgOffsetX; + int m_iOrgOffsetY; + float m_flScale; + +private: + // This is the entity to which we're attached + EHANDLE m_pBaseEntity; +}; + +#endif // VGUI_ENTITYPANEL_H \ No newline at end of file diff --git a/game/client/vgui_game_viewport.h b/game/client/vgui_game_viewport.h new file mode 100644 index 0000000..e50da31 --- /dev/null +++ b/game/client/vgui_game_viewport.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VGUI_HL2_VIEWPORT +#define VGUI_HL2_VIEWPORT + + +#endif + + + + + + diff --git a/game/client/vgui_grid.h b/game/client/vgui_grid.h new file mode 100644 index 0000000..318344a --- /dev/null +++ b/game/client/vgui_grid.h @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_GRID_H +#define VGUI_GRID_H +#ifdef _WIN32 +#pragma once +#endif + + +#include + +namespace vgui +{ + +// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and +// configure and fill the panels however you want. +// To use this control, call SetDimensions, SetSpacing and fill the controls. +class CGrid : public Panel +{ +public: + CGrid(); + virtual ~CGrid(); + + bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. + void Term(); + + Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. + bool SetEntry(int x, int y, Panel *pPanel); + + int GetXSpacing(); + int GetYSpacing(); + void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. + + bool SetColumnWidth(int iColumn, int width); // Set a column's width. + bool SetRowHeight(int iRow, int height); // Set a row's height. + + int GetColumnWidth(int iColumn); + int GetRowHeight(int iRow); + + int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. + int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. + + int CalcDrawHeight(); // Returns how many pixels high the grid control should be + // for all of its contents to be visible (based on its row heights + // and y spacing). + + void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. + + bool GetEntryBox( // Returns the bounding box for the specified entry. + int col, int row, int &x, int &y, int &w, int &h); + + bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the + // column count is different. + + void RepositionContents(); // Sets the size and position of all the grid entries based + // on current spacings and row/column widths. + // You usually only want to call this while setting up the control + // if you want to get the position or dimensions of the child + // controls. This will set them. + + void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row + + // returns the true if found, false otherwise + bool GetCellAtPoint(int worldX, int worldY, int &row, int &col); + +// Panel overrides. +public: + + virtual void Paint(); + virtual void PaintBackground(); + +protected: + + class CGridEntry + { + public: + CGridEntry(); + ~CGridEntry(); + + Panel *m_pPanel; + + bool m_bUnderline; + short m_UnderlineColor[4]; + int m_iUnderlineOffset; + }; + + void Clear(); + CGridEntry* GridEntry(int x, int y); + + void CalcColOffsets(int iStart); + void CalcRowOffsets(int iStart); + + +protected: + + bool m_bDirty; // Set when controls will need to be repositioned. + + int m_xCols; + int m_yRows; + + int m_xSpacing; + int m_ySpacing; + + int *m_Widths; + int *m_Heights; + int *m_ColOffsets; + int *m_RowOffsets; + + CGridEntry *m_GridEntries; + +}; + +}; + + +#endif // VGUI_GRID_H diff --git a/game/client/vgui_helpers.h b/game/client/vgui_helpers.h new file mode 100644 index 0000000..ba0418e --- /dev/null +++ b/game/client/vgui_helpers.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_HELPERS_H +#define VGUI_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include + + +inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->GetBounds(x,y,w,h); return y;} +inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->GetBounds(x,y,w,h); return x;} +inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->GetBounds(x,y,w,h); return x+w;} +inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->GetBounds(x,y,w,h); return y+h;} +inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->GetBounds(x,y,w,h); return w;} +inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->GetBounds(x,y,w,h); return h;} + +// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. +void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); + + +#endif // VGUI_HELPERS_H + diff --git a/game/client/vgui_imagehealthpanel.h b/game/client/vgui_imagehealthpanel.h new file mode 100644 index 0000000..5b914a7 --- /dev/null +++ b/game/client/vgui_imagehealthpanel.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is a panel which is rendered image on top of an entity +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_IMAGEHEALTHPANEL_H +#define VGUI_IMAGEHEALTHPANEL_H + +#include "vgui_EntityPanel.h" +#include "vgui_EntityImagePanel.h" +#include "vgui_HealthBar.h" +#include "vgui_bitmappanel.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class C_BaseEntity; +class KeyValues; +class BitmapImage; + +//----------------------------------------------------------------------------- +// This is a base class for a panel which always is rendered on top of an entity +//----------------------------------------------------------------------------- + +class CEntityImageHealthPanel : public CEntityPanel +{ +public: + DECLARE_CLASS( CEntityImageHealthPanel, CEntityPanel ); + + // constructor + CEntityImageHealthPanel( vgui::Panel *parent, const char *panelName ); + ~CEntityImageHealthPanel(); + + // initialization + bool Init( KeyValues* pInitData, C_BaseEntity* pEntity ); + + // called when we're ticked... + virtual void OnTick(); + virtual bool ShouldDraw( void ); + virtual void ComputeAndSetSize( void ); + +private: + CHealthBarPanel *m_CommanderHealthBar; + CHealthBarPanel *m_NormalHealthBar; + CHealthBarPanel *m_ResourceLevelBar; + CEntityTeamImagePanel *m_pImagePanel; +}; + +#endif // VGUI_IMAGEHEALTHPANEL_H \ No newline at end of file diff --git a/game/client/vgui_int.h b/game/client/vgui_int.h new file mode 100644 index 0000000..ad95f01 --- /dev/null +++ b/game/client/vgui_int.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( VGUI_INT_H ) +#define VGUI_INT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +#include + +namespace vgui +{ + class Panel; +} + +bool VGui_Startup( CreateInterfaceFn appSystemFactory ); +void VGui_Shutdown( void ); +void VGui_CreateGlobalPanels( void ); +vgui::VPANEL VGui_GetClientDLLRootPanel( void ); +void VGUI_CreateClientDLLRootPanel( void ); +void VGUI_DestroyClientDLLRootPanel( void ); +void VGui_PreRender(); +void VGui_PostRender(); + +#endif // VGUI_INT_H \ No newline at end of file diff --git a/game/client/vgui_schemevisualizer.h b/game/client/vgui_schemevisualizer.h new file mode 100644 index 0000000..0c2d749 --- /dev/null +++ b/game/client/vgui_schemevisualizer.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef VGUI_CLIENTSCHEMEVISUALIZER_H +#define VGUI_CLIENTSCHEMEVISUALIZER_H + +//---------------------------------------------------------------------------------------- + +#include "vgui_controls/Frame.h" +#include "vgui_controls/PanelListPanel.h" + +//---------------------------------------------------------------------------------------- + +class CSchemeVisualizer : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CSchemeVisualizer, vgui::Frame ); + +public: + CSchemeVisualizer( vgui::Panel *pParent, vgui::IScheme *pViewScheme, const char *pSchemeName ); + virtual ~CSchemeVisualizer(); + +private: + virtual void PerformLayout(); + +private: + virtual void OnTick(); + + enum ListDataType_t + { + LISTDATATYPE_INVALID = -1, + LISTDATATYPE_BORDERS, + LISTDATATYPE_FONTS, + LISTDATATYPE_COLORS, + NUM_TYPES + }; + + int m_aComboDataTypeToItemIDMap[NUM_TYPES]; // [ data type ] = < item id > + + void UpdateList( ListDataType_t nType ); + void AddBordersToList(); + void AddFontsToList(); + void AddColorsToList(); + + vgui::PanelListPanel *m_pList; + ListDataType_t m_nListDataType; // Currently selected data type + int m_nSelectedComboItem; + + vgui::IScheme *m_pViewScheme; // The scheme we're visualizing + vgui::ComboBox *m_pListDataTypeCombo; +}; + +//---------------------------------------------------------------------------------------- + +#endif // VGUI_CLIENTSCHEMEVISUALIZER_H \ No newline at end of file diff --git a/game/client/vgui_video.h b/game/client/vgui_video.h new file mode 100644 index 0000000..61a980b --- /dev/null +++ b/game/client/vgui_video.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: VGUI panel which can play back video, in-engine +// +//============================================================================= + +#ifndef VGUI_VIDEO_H +#define VGUI_VIDEO_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +//#define QUICKTIME_VIDEO +//#define BINK_VIDEO + +#include "video/ivideoservices.h" + + +class VideoPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( VideoPanel, vgui::EditablePanel ); +public: + + VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHeight, unsigned int nWidth, bool allowAlternateMedia = true ); + + virtual ~VideoPanel( void ); + + virtual void Activate( void ); + virtual void Paint( void ); + virtual void DoModal( void ); + virtual void OnKeyCodeTyped( vgui::KeyCode code ); + virtual void OnKeyCodePressed( vgui::KeyCode code ); + virtual void OnClose( void ); + virtual void GetPanelPos( int &xpos, int &ypos ); + + void SetExitCommand( const char *pExitCommand ) + { + if ( pExitCommand && pExitCommand[0] ) + { + Q_strncpy( m_szExitCommand, pExitCommand, MAX_PATH ); + } + } + + bool BeginPlayback( const char *pFilename ); + + void SetBlackBackground( bool bBlack ){ m_bBlackBackground = bBlack; } + +protected: + + virtual void OnTick( void ) { BaseClass::OnTick(); } + virtual void OnCommand( const char *pcCommand ) { BaseClass::OnCommand( pcCommand ); } + virtual void OnVideoOver(){} + +protected: + IVideoMaterial *m_VideoMaterial; + + IMaterial *m_pMaterial; + int m_nPlaybackHeight; // Calculated to address ratio changes + int m_nPlaybackWidth; + char m_szExitCommand[MAX_PATH]; // This call is fired at the engine when the video finishes or is interrupted + + float m_flU; // U,V ranges for video on its sheet + float m_flV; + + bool m_bBlackBackground; + bool m_bAllowAlternateMedia; +}; + + +// Creates a VGUI panel which plays a video and executes a client command at its finish (if specified) +extern bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos, + unsigned int nWidth, unsigned int nHeight, + const char *pVideoFilename, + const char *pExitCommand = NULL ); + +#endif // VGUI_VIDEO_H diff --git a/game/client/vgui_video_player.h b/game/client/vgui_video_player.h new file mode 100644 index 0000000..3d8605d --- /dev/null +++ b/game/client/vgui_video_player.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// VGUI_VIDEO_PLAYER +// +// Creates a VGUI Panel that can play a video in engine with "media player like" +// functionality. vgui_video.h has a basic player panel, but this allows for +// much greater control over playback, etc +// +//============================================================================= + +#ifndef VGUI_VIDEO_PLAYER +#define VGUI_VIDEO_PLAYER + +#ifdef _WIN32 + #pragma once +#endif + +#include +#include "video/ivideoservices.h" + + +class VideoPlayerPanel : public vgui::Panel // Should this be EditablePanel ? +{ + public: + + DECLARE_CLASS_SIMPLE( VideoPlayerPanel, vgui::Panel ); + + VideoPlayerPanel( vgui::Panel *parent, const char *panelName, int nXpos, int nYpos, int nWidth, int nHeight, const char *pVideoFile = NULL ); + + virtual ~VideoPlayerPanel(); + + virtual void Activate( void ); + virtual void Paint( void ); + virtual void OnClose( void ); + + bool SetVideo( const char *pVideoFile ); + void ClearVideo(); + bool IsReady() { return m_VideoLoaded; } + + bool StartVideo(); + bool StopVideo(); + bool PauseVideo(); + bool UnpauseVideo(); + bool IsPlaying() { return m_VideoPlaying; } + bool IsPaused() { return m_VideoPaused; } + + float GetCurrentPlaybackTime(); + bool SetCurrentPlaybackTime( float newTime ); + + float GetVideoDuration() { return m_VideoDuration; } + bool HasAudio(); + + bool IsMuted(); + bool SetMute( bool muted ); + + float GetVolume(); + bool SetVolume( float newVolume ); + + + protected: + + virtual void OnTick( void ) { BaseClass::OnTick(); } + virtual void OnCommand( const char *pcCommand ) { BaseClass::OnCommand( pcCommand ); } + + private: + + IVideoMaterial *m_VideoMaterial; + IMaterial *m_pMaterial; + + bool m_VideoLoaded; + bool m_VideoPlaying; + bool m_VideoPaused; + + int m_nPlaybackHeight; // Calculated to address ratio changes + int m_nPlaybackWidth; + int m_letterBox; + + float m_flU, m_flV; + + char *m_VideoFileName; + float m_VideoDuration; + + + +}; + +#endif + diff --git a/game/client/vguicenterprint.h b/game/client/vguicenterprint.h new file mode 100644 index 0000000..f1a83a7 --- /dev/null +++ b/game/client/vguicenterprint.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( VGUICENTERPRINT_H ) +#define VGUICENTERPRINT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ivguicenterprint.h" +#include + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +namespace vgui +{ +class Panel; +} + +class CCenterStringLabel; +class CCenterPrint : public ICenterPrint +{ +private: + CCenterStringLabel *vguiCenterString; + +public: + CCenterPrint( void ); + + virtual void Create( vgui::VPANEL parent ); + virtual void Destroy( void ); + + virtual void SetTextColor( int r, int g, int b, int a ); + virtual void Print( char *text ); + virtual void Print( wchar_t *text ); + virtual void ColorPrint( int r, int g, int b, int a, char *text ); + virtual void ColorPrint( int r, int g, int b, int a, wchar_t *text ); + virtual void Clear( void ); +}; + +extern CCenterPrint *internalCenterPrint; + +#endif // VGUICENTERPRINT_H \ No newline at end of file diff --git a/game/client/view.h b/game/client/view.h new file mode 100644 index 0000000..7c41593 --- /dev/null +++ b/game/client/view.h @@ -0,0 +1,98 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( VIEW_H ) +#define VIEW_H +#ifdef _WIN32 +#pragma once +#endif + +#if _DEBUG +extern bool g_bRenderingCameraView; // For debugging (frustum fix for cameras)... +#endif + +class VMatrix; +class Vector; +class QAngle; +class VPlane; + + +// near and far Z it uses to render the world. +#ifndef HL1_CLIENT_DLL +#define VIEW_NEARZ 7 +#else +#define VIEW_NEARZ 3 +#endif +//#define VIEW_FARZ 28400 + + +//----------------------------------------------------------------------------- +// There's a difference between the 'current view' and the 'main view' +// The 'main view' is where the player is sitting. Current view is just +// what's currently being rendered, which, owing to monitors or water, +// could be just about anywhere. +//----------------------------------------------------------------------------- +const Vector &MainViewOrigin(); +const QAngle &MainViewAngles(); +const Vector &PrevMainViewOrigin(); +const QAngle &PrevMainViewAngles(); +const VMatrix &MainWorldToViewMatrix(); +const Vector &MainViewForward(); +const Vector &MainViewRight(); +const Vector &MainViewUp(); + +const Vector &CurrentViewOrigin(); +const QAngle &CurrentViewAngles(); +const VMatrix &CurrentWorldToViewMatrix(); +const Vector &CurrentViewForward(); +const Vector &CurrentViewRight(); +const Vector &CurrentViewUp(); + +void AllowCurrentViewAccess( bool allow ); +bool IsCurrentViewAccessAllowed(); + +// Returns true of the sphere is outside the frustum defined by pPlanes. +// (planes point inwards). +bool R_CullSphere( const VPlane *pPlanes, int nPlanes, const Vector *pCenter, float radius ); +float ScaleFOVByWidthRatio( float fovDegrees, float ratio ); + +extern ConVar mat_wireframe; + +extern const ConVar *sv_cheats; + + +static inline int WireFrameMode( void ) +{ + if ( !sv_cheats ) + { + sv_cheats = cvar->FindVar( "sv_cheats" ); + } + + if ( sv_cheats && sv_cheats->GetBool() ) + return mat_wireframe.GetInt(); + else + return 0; +} + +static inline bool ShouldDrawInWireFrameMode( void ) +{ + if ( !sv_cheats ) + { + sv_cheats = cvar->FindVar( "sv_cheats" ); + } + + if ( sv_cheats && sv_cheats->GetBool() ) + return ( mat_wireframe.GetInt() != 0 ); + else + return false; +} + +void ComputeCameraVariables( const Vector &vecOrigin, const QAngle &vecAngles, Vector *pVecForward, Vector *pVecRight, Vector *pVecUp, VMatrix *pMatCamInverse ); + +#endif // VIEW_H diff --git a/game/client/view_scene.h b/game/client/view_scene.h new file mode 100644 index 0000000..9126904 --- /dev/null +++ b/game/client/view_scene.h @@ -0,0 +1,166 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VIEW_SCENE_H +#define VIEW_SCENE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "convar.h" +#include "iviewrender.h" +#include "view_shared.h" +#include "rendertexture.h" +#include "materialsystem/itexture.h" + + +extern ConVar mat_wireframe; +extern ConVar building_cubemaps; + + +// Transform into view space (translate and rotate the camera into the origin). +void ViewTransform( const Vector &worldSpace, Vector &viewSpace ); + +// Transform a world point into normalized screen space (X and Y from -1 to 1). +// Returns 0 if the point is behind the viewer. +int ScreenTransform( const Vector& point, Vector& screen ); +int HudTransform( const Vector& point, Vector& screen ); + + +extern ConVar r_updaterefracttexture; +extern int g_viewscene_refractUpdateFrame; +extern bool g_bAllowMultipleRefractUpdatesPerScenePerFrame; +bool DrawingShadowDepthView( void ); +bool DrawingMainView(); + +inline void UpdateRefractTexture( int x, int y, int w, int h, bool bForceUpdate = false ) +{ + Assert( !DrawingShadowDepthView() ); + + if ( !IsRetail() && !r_updaterefracttexture.GetBool() ) + return; + + CMatRenderContextPtr pRenderContext( materials ); + ITexture *pTexture = GetPowerOfTwoFrameBufferTexture(); + if ( IsPC() || bForceUpdate || g_bAllowMultipleRefractUpdatesPerScenePerFrame || (gpGlobals->framecount != g_viewscene_refractUpdateFrame) ) + { + // forced or only once per frame + Rect_t rect; + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &rect, NULL ); + + g_viewscene_refractUpdateFrame = gpGlobals->framecount; + } + pRenderContext->SetFrameBufferCopyTexture( pTexture ); +} + +inline void UpdateRefractTexture( bool bForceUpdate = false ) +{ + Assert( !DrawingShadowDepthView() ); + + CMatRenderContextPtr pRenderContext( materials ); + + int x,y,w,h; + pRenderContext->GetViewport( x, y, w, h ); + UpdateRefractTexture( x, y, w, h, bForceUpdate ); +} + +inline void UpdateScreenEffectTexture( int textureIndex, int x, int y, int w, int h, bool bDestFullScreen = false, Rect_t *pActualRect = NULL ) +{ + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + + CMatRenderContextPtr pRenderContext( materials ); + ITexture *pTexture = GetFullFrameFrameBufferTexture( textureIndex ); + int nSrcWidth, nSrcHeight; + pRenderContext->GetRenderTargetDimensions( nSrcWidth, nSrcHeight ); + int nDestWidth = pTexture->GetActualWidth(); + int nDestHeight = pTexture->GetActualHeight(); + + Rect_t destRect = srcRect; + if( !bDestFullScreen && ( nSrcWidth > nDestWidth || nSrcHeight > nDestHeight ) ) + { + // the source and target sizes aren't necessarily the same (specifically in dx7 where + // nonpow2 rendertargets aren't supported), so lets figure it out here. + float scaleX = ( float )nDestWidth / ( float )nSrcWidth; + float scaleY = ( float )nDestHeight / ( float )nSrcHeight; + destRect.x = srcRect.x * scaleX; + destRect.y = srcRect.y * scaleY; + destRect.width = srcRect.width * scaleX; + destRect.height = srcRect.height * scaleY; + destRect.x = clamp( destRect.x, 0, nDestWidth ); + destRect.y = clamp( destRect.y, 0, nDestHeight ); + destRect.width = clamp( destRect.width, 0, nDestWidth - destRect.x ); + destRect.height = clamp( destRect.height, 0, nDestHeight - destRect.y ); + } + + pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, bDestFullScreen ? NULL : &destRect ); + pRenderContext->SetFrameBufferCopyTexture( pTexture, textureIndex ); + + if ( pActualRect ) + { + pActualRect->x = destRect.x; + pActualRect->y = destRect.y; + pActualRect->width = destRect.width; + pActualRect->height = destRect.height; + } +} + +//----------------------------------------------------------------------------- +// Draws the screen effect +//----------------------------------------------------------------------------- +inline void DrawScreenEffectMaterial( IMaterial *pMaterial, int x, int y, int w, int h ) +{ + Rect_t actualRect; + UpdateScreenEffectTexture( 0, x, y, w, h, false, &actualRect ); + ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 ); + + CMatRenderContextPtr pRenderContext( materials ); + + pRenderContext->DrawScreenSpaceRectangle( pMaterial, x, y, w, h, + actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1, + pTexture->GetActualWidth(), pTexture->GetActualHeight() ); +} + + +//intended for use by dynamic meshes to naively update front buffer textures needed by a material +inline void UpdateFrontBufferTexturesForMaterial( IMaterial *pMaterial, bool bForce = false ) +{ + Assert( !DrawingShadowDepthView() ); + + if( pMaterial->NeedsPowerOfTwoFrameBufferTexture() ) + { + UpdateRefractTexture( bForce ); + } + else if( pMaterial->NeedsFullFrameBufferTexture() ) + { + const CViewSetup *pView = view->GetViewSetup(); + UpdateScreenEffectTexture( 0, pView->x, pView->y, pView->width, pView->height ); + } +} + +inline void UpdateScreenEffectTexture( void ) +{ + Assert( !DrawingShadowDepthView() ); + + const CViewSetup *pViewSetup = view->GetViewSetup(); + UpdateScreenEffectTexture( 0, pViewSetup->x, pViewSetup->y, pViewSetup->width, pViewSetup->height); +} + +// reset the tonem apping to a constant value, and clear the filter bank +void ResetToneMapping(float value); + +void UpdateFullScreenDepthTexture( void ); + +#endif // VIEW_SCENE_H diff --git a/game/client/viewangleanim.h b/game/client/viewangleanim.h new file mode 100644 index 0000000..c5d08bc --- /dev/null +++ b/game/client/viewangleanim.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "utlvector.h" + +#define VIEWANIM_RELATIVE (1<<0) // angles in keyframe are relative, add anim to current angles +#define VIEWANIM_IGNORE_X (1<<1) // ignore the x component of this animation +#define VIEWANIM_IGNORE_Y (1<<2) // ditto for y +#define VIEWANIM_IGNORE_Z (1<<3) // ditto for z + +#define QAngleToVector(a,v) { v[0] = a[0]; v[1] = a[1]; v[2] = a[2]; } + +class CViewAngleKeyFrame +{ +public: + CViewAngleKeyFrame( QAngle vecAngles, float flTime, int iFlags ) + { + m_vecAngles = vecAngles; + m_flTime = flTime; + m_iFlags = iFlags; + } + + // the target angles for this keyframe in the view angle animation + QAngle m_vecAngles; + + // time position of this keyframe + float m_flTime; + + int m_iFlags; +}; + + +typedef void (*ViewAnimCompleteCallback)( void ); + +class CViewAngleAnimation : public C_BaseEntity +{ +public: + CViewAngleAnimation(); + ~CViewAngleAnimation(); + + virtual void Spawn(); + + void DeleteKeyFrames(); + + + void LoadViewAnimFile( const char *pKeyFrameFileName ); + void SaveAsAnimFile( const char *pKeyFrameFileName ); + + void AddKeyFrame( CViewAngleKeyFrame *pKeyFrame ); + bool IsFinished( void ); + void RunAnimation( QAngle angles ); + void ClientThink(); + + void SetAnimCompleteCallback( ViewAnimCompleteCallback pFunc ) + { + m_pAnimCompleteCallback = pFunc; + } + +private: + void SetAngles( QAngle vecCalculatedAngles ); + + float m_flAnimStartTime; // time this animation started + bool m_bFinished; + + CUtlVector m_KeyFrames; + + QAngle m_vecBaseAngles; + + int m_iFlags; + + ViewAnimCompleteCallback m_pAnimCompleteCallback; +}; \ No newline at end of file diff --git a/game/client/viewdebug.h b/game/client/viewdebug.h new file mode 100644 index 0000000..fe827f9 --- /dev/null +++ b/game/client/viewdebug.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VIEWDEBUG_H +#define VIEWDEBUG_H + +#if defined( _WIN32 ) +#pragma once +#endif + +class CViewSetup; + +//----------------------------------------------------------------------------- +// Purpose: Implements the debugging elements of view rendering +//----------------------------------------------------------------------------- +class CDebugViewRender +{ + DECLARE_CLASS_NOBASE( CDebugViewRender ); +public: + // Draws all the debugging info + static void Draw3DDebuggingInfo( const CViewSetup &view ); + static void Draw2DDebuggingInfo( const CViewSetup &view ); + static void GenerateOverdrawForTesting(); +}; + +#endif // VIEWDEBUG_H diff --git a/game/client/viewpostprocess.h b/game/client/viewpostprocess.h new file mode 100644 index 0000000..eb2ad9c --- /dev/null +++ b/game/client/viewpostprocess.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VIEWPOSTPROCESS_H +#define VIEWPOSTPROCESS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +void DoEnginePostProcessing( int x, int y, int w, int h, bool bFlashlightIsOn, bool bPostVGui = false ); +void DoImageSpaceMotionBlur( const CViewSetup &view, int x, int y, int w, int h ); +void DumpTGAofRenderTarget( const int width, const int height, const char *pFilename ); + +#endif // VIEWPOSTPROCESS_H diff --git a/game/client/viewrender.h b/game/client/viewrender.h new file mode 100644 index 0000000..723c322 --- /dev/null +++ b/game/client/viewrender.h @@ -0,0 +1,528 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#if !defined( VIEWRENDER_H ) +#define VIEWRENDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "tier1/utlstack.h" +#include "iviewrender.h" +#include "view_shared.h" +#include "replay/ireplayscreenshotsystem.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConVar; +class CClientRenderablesList; +class IClientVehicle; +class C_PointCamera; +class C_EnvProjectedTexture; +class IScreenSpaceEffect; +class CClientViewSetup; +class CViewRender; +struct ClientWorldListInfo_t; +class C_BaseEntity; +struct WriteReplayScreenshotParams_t; +class CReplayScreenshotTaker; + +#ifdef HL2_EPISODIC + class CStunEffect; +#endif // HL2_EPISODIC + +//----------------------------------------------------------------------------- +// Data specific to intro mode to control rendering. +//----------------------------------------------------------------------------- +struct IntroDataBlendPass_t +{ + int m_BlendMode; + float m_Alpha; // in [0.0f,1.0f] This needs to add up to 1.0 for all passes, unless you are fading out. +}; + +struct IntroData_t +{ + bool m_bDrawPrimary; + Vector m_vecCameraView; + QAngle m_vecCameraViewAngles; + float m_playerViewFOV; + CUtlVector m_Passes; + + // Fade overriding for the intro + float m_flCurrentFadeColor[4]; +}; + +// Robin, make this point at something to get intro mode. +extern IntroData_t *g_pIntroData; + +// This identifies the view for certain systems that are unique per view (e.g. pixel visibility) +// NOTE: This is identifying which logical part of the scene an entity is being redered in +// This is not identifying a particular render target necessarily. This is mostly needed for entities that +// can be rendered more than once per frame (pixel vis queries need to be identified per-render call) +enum view_id_t +{ + VIEW_ILLEGAL = -2, + VIEW_NONE = -1, + VIEW_MAIN = 0, + VIEW_3DSKY = 1, + VIEW_MONITOR = 2, + VIEW_REFLECTION = 3, + VIEW_REFRACTION = 4, + VIEW_INTRO_PLAYER = 5, + VIEW_INTRO_CAMERA = 6, + VIEW_SHADOW_DEPTH_TEXTURE = 7, + VIEW_SSAO = 8, + VIEW_ID_COUNT +}; +view_id_t CurrentViewID(); + +//----------------------------------------------------------------------------- +// Purpose: Stored pitch drifting variables +//----------------------------------------------------------------------------- +class CPitchDrift +{ +public: + float pitchvel; + bool nodrift; + float driftmove; + double laststop; +}; + + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +struct ViewCustomVisibility_t +{ + ViewCustomVisibility_t() + { + m_nNumVisOrigins = 0; + m_VisData.m_fDistToAreaPortalTolerance = FLT_MAX; + m_iForceViewLeaf = -1; + } + + void AddVisOrigin( const Vector& origin ) + { + // Don't allow them to write past array length + AssertMsg( m_nNumVisOrigins < MAX_VIS_LEAVES, "Added more origins than will fit in the array!" ); + + // If the vis origin count is greater than the size of our array, just fail to add this origin + if ( m_nNumVisOrigins >= MAX_VIS_LEAVES ) + return; + + m_rgVisOrigins[ m_nNumVisOrigins++ ] = origin; + } + + void ForceVisOverride( VisOverrideData_t& visData ) + { + m_VisData = visData; + } + + void ForceViewLeaf ( int iViewLeaf ) + { + m_iForceViewLeaf = iViewLeaf; + } + + // Set to true if you want to use multiple origins for doing client side map vis culling + // NOTE: In generaly, you won't want to do this, and by default the 3d origin of the camera, as above, + // will be used as the origin for vis, too. + int m_nNumVisOrigins; + // Array of origins + Vector m_rgVisOrigins[ MAX_VIS_LEAVES ]; + + // The view data overrides for visibility calculations with area portals + VisOverrideData_t m_VisData; + + // The starting leaf to determing which area to start in when performing area portal culling on the engine + // Default behavior is to use the leaf the camera position is in. + int m_iForceViewLeaf; +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +struct WaterRenderInfo_t +{ + bool m_bCheapWater : 1; + bool m_bReflect : 1; + bool m_bRefract : 1; + bool m_bReflectEntities : 1; + bool m_bDrawWaterSurface : 1; + bool m_bOpaqueWater : 1; + +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CBase3dView : public CRefCounted<>, + protected CViewSetup +{ + DECLARE_CLASS_NOBASE( CBase3dView ); +public: + CBase3dView( CViewRender *pMainView ); + + VPlane * GetFrustum(); + virtual int GetDrawFlags() { return 0; } + +#ifdef PORTAL + virtual void EnableWorldFog() {}; +#endif + +protected: + // @MULTICORE (toml 8/11/2006): need to have per-view frustum. Change when move view stack to client + VPlane *m_Frustum; + CViewRender *m_pMainView; +}; + +//----------------------------------------------------------------------------- +// Base class for 3d views +//----------------------------------------------------------------------------- +class CRendering3dView : public CBase3dView +{ + DECLARE_CLASS( CRendering3dView, CBase3dView ); +public: + CRendering3dView( CViewRender *pMainView ); + virtual ~CRendering3dView() { ReleaseLists(); } + + void Setup( const CViewSetup &setup ); + + // What are we currently rendering? Returns a combination of DF_ flags. + virtual int GetDrawFlags(); + + virtual void Draw() {}; + +protected: + + // Fog setup + void EnableWorldFog( void ); + void SetFogVolumeState( const VisibleFogVolumeInfo_t &fogInfo, bool bUseHeightFog ); + + // Draw setup + void SetupRenderablesList( int viewID ); + + void UpdateRenderablesOpacity(); + + // If iForceViewLeaf is not -1, then it uses the specified leaf as your starting area for setting up area portal culling. + // This is used by water since your reflected view origin is often in solid space, but we still want to treat it as though + // the first portal we're looking out of is a water portal, so our view effectively originates under the water. + void BuildWorldRenderLists( bool bDrawEntities, int iForceViewLeaf = -1, bool bUseCacheIfEnabled = true, bool bShadowDepth = false, float *pReflectionWaterHeight = NULL ); + + // Purpose: Builds render lists for renderables. Called once for refraction, once for over water + void BuildRenderableRenderLists( int viewID ); + + // More concise version of the above BuildRenderableRenderLists(). Called for shadow depth map rendering + void BuildShadowDepthRenderableRenderLists(); + + void DrawWorld( float waterZAdjust ); + + // Draws all opaque/translucent renderables in leaves that were rendered + void DrawOpaqueRenderables( ERenderDepthMode DepthMode ); + void DrawTranslucentRenderables( bool bInSkybox, bool bShadowDepth ); + + // Renders all translucent entities in the render list + void DrawTranslucentRenderablesNoWorld( bool bInSkybox ); + + // Draws translucent renderables that ignore the Z buffer + void DrawNoZBufferTranslucentRenderables( void ); + + // Renders all translucent world surfaces in a particular set of leaves + void DrawTranslucentWorldInLeaves( bool bShadowDepth ); + + // Renders all translucent world + detail objects in a particular set of leaves + void DrawTranslucentWorldAndDetailPropsInLeaves( int iCurLeaf, int iFinalLeaf, int nEngineDrawFlags, int &nDetailLeafCount, LeafIndex_t* pDetailLeafList, bool bShadowDepth ); + + // Purpose: Computes the actual world list info based on the render flags + void PruneWorldListInfo(); + +#ifdef PORTAL + virtual bool ShouldDrawPortals() { return true; } +#endif + + void ReleaseLists(); + + //----------------------------------------------- + // Combination of DF_ flags. + int m_DrawFlags; + int m_ClearFlags; + + IWorldRenderList *m_pWorldRenderList; + CClientRenderablesList *m_pRenderablesList; + ClientWorldListInfo_t *m_pWorldListInfo; + ViewCustomVisibility_t *m_pCustomVisibility; +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CRenderExecutor +{ + DECLARE_CLASS_NOBASE( CRenderExecutor ); +public: + virtual void AddView( CRendering3dView *pView ) = 0; + virtual void Execute() = 0; + +protected: + CRenderExecutor( CViewRender *pMainView ) : m_pMainView( pMainView ) {} + CViewRender *m_pMainView; +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CSimpleRenderExecutor : public CRenderExecutor +{ + DECLARE_CLASS( CSimpleRenderExecutor, CRenderExecutor ); +public: + CSimpleRenderExecutor( CViewRender *pMainView ) : CRenderExecutor( pMainView ) {} + + void AddView( CRendering3dView *pView ); + void Execute() {} +}; + +//----------------------------------------------------------------------------- +// Purpose: Implements the interface to view rendering for the client .dll +//----------------------------------------------------------------------------- + +class CViewRender : public IViewRender, + public IReplayScreenshotSystem +{ + DECLARE_CLASS_NOBASE( CViewRender ); +public: + virtual void Init( void ); + virtual void Shutdown( void ); + + const CViewSetup *GetPlayerViewSetup( ) const; + + virtual void StartPitchDrift( void ); + virtual void StopPitchDrift( void ); + + virtual float GetZNear(); + virtual float GetZFar(); + + virtual void OnRenderStart(); + void DriftPitch (void); + + static CViewRender * GetMainView() { return assert_cast( view ); } + + void AddViewToScene( CRendering3dView *pView ) { m_SimpleExecutor.AddView( pView ); } +protected: + // Sets up the view parameters for all views (left, middle and right eyes). + void SetUpViews(); + + // Sets up the view parameters of map overview mode (cl_leveloverview) + void SetUpOverView(); + + // generates a low-res screenshot for save games + virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded = false, bool bWriteVTF = false ); + void WriteSaveGameScreenshot( const char *filename ); + + virtual IReplayScreenshotSystem *GetReplayScreenshotSystem() { return this; } + + // IReplayScreenshot implementation + virtual void WriteReplayScreenshot( WriteReplayScreenshotParams_t ¶ms ); + virtual void UpdateReplayScreenshotCache(); + + StereoEye_t GetFirstEye() const; + StereoEye_t GetLastEye() const; + CViewSetup & GetView(StereoEye_t eEye); + const CViewSetup & GetView(StereoEye_t eEye) const ; + + + // This stores all of the view setup parameters that the engine needs to know about. + // Best way to pick the right one is with ::GetView(), rather than directly. + CViewSetup m_View; // mono <- in stereo mode, this will be between the two eyes and is the "main" view. + CViewSetup m_ViewLeft; // left (unused for mono) + CViewSetup m_ViewRight; // right (unused for mono) + + // Pitch drifting data + CPitchDrift m_PitchDrift; + +public: + CViewRender(); + virtual ~CViewRender( void ) {} + +// Implementation of IViewRender interface +public: + + void SetupVis( const CViewSetup& view, unsigned int &visFlags, ViewCustomVisibility_t *pCustomVisibility = NULL ); + + + // Render functions + virtual void Render( vrect_t *rect ); + virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ); + virtual void RenderPlayerSprites(); + virtual void Render2DEffectsPreHUD( const CViewSetup &view ); + virtual void Render2DEffectsPostHUD( const CViewSetup &view ); + + + void DisableFog( void ); + + // Called once per level change + void LevelInit( void ); + void LevelShutdown( void ); + + // Add entity to transparent entity queue + + bool ShouldDrawEntities( void ); + bool ShouldDrawBrushModels( void ); + + const CViewSetup *GetViewSetup( ) const; + + void DisableVis( void ); + + // Sets up the view model position relative to the local player + void MoveViewModels( ); + + // Gets the abs origin + angles of the view models + void GetViewModelPosition( int nIndex, Vector *pPos, QAngle *pAngle ); + + void SetCheapWaterStartDistance( float flCheapWaterStartDistance ); + void SetCheapWaterEndDistance( float flCheapWaterEndDistance ); + + void GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance ); + + virtual void QueueOverlayRenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ); + + virtual void GetScreenFadeDistances( float *min, float *max ); + + virtual C_BaseEntity *GetCurrentlyDrawingEntity(); + virtual void SetCurrentlyDrawingEntity( C_BaseEntity *pEnt ); + + virtual bool UpdateShadowDepthTexture( ITexture *pRenderTarget, ITexture *pDepthTexture, const CViewSetup &shadowView ); + + int GetBaseDrawFlags() { return m_BaseDrawFlags; } + virtual bool ShouldForceNoVis() { return m_bForceNoVis; } + int BuildRenderablesListsNumber() const { return m_BuildRenderableListsNumber; } + int IncRenderablesListsNumber() { return ++m_BuildRenderableListsNumber; } + + int BuildWorldListsNumber() const; + int IncWorldListsNumber() { return ++m_BuildWorldListsNumber; } + + virtual VPlane* GetFrustum() { return ( m_pActiveRenderer ) ? m_pActiveRenderer->GetFrustum() : m_Frustum; } + + // What are we currently rendering? Returns a combination of DF_ flags. + virtual int GetDrawFlags() { return ( m_pActiveRenderer ) ? m_pActiveRenderer->GetDrawFlags() : 0; } + + CBase3dView * GetActiveRenderer() { return m_pActiveRenderer; } + CBase3dView * SetActiveRenderer( CBase3dView *pActiveRenderer ) { CBase3dView *pPrevious = m_pActiveRenderer; m_pActiveRenderer = pActiveRenderer; return pPrevious; } + + void FreezeFrame( float flFreezeTime ); + + void SetWaterOverlayMaterial( IMaterial *pMaterial ) + { + m_UnderWaterOverlayMaterial.Init( pMaterial ); + } +private: + int m_BuildWorldListsNumber; + + + // General draw methods + // baseDrawFlags is a combination of DF_ defines. DF_MONITOR is passed into here while drawing a monitor. + void ViewDrawScene( bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &view, int nClearFlags, view_id_t viewID, bool bDrawViewModel = false, int baseDrawFlags = 0, ViewCustomVisibility_t *pCustomVisibility = NULL ); + + void DrawMonitors( const CViewSetup &cameraView ); + + bool DrawOneMonitor( ITexture *pRenderTarget, int cameraNum, C_PointCamera *pCameraEnt, const CViewSetup &cameraView, C_BasePlayer *localPlayer, + int x, int y, int width, int height ); + + // Drawing primitives + bool ShouldDrawViewModel( bool drawViewmodel ); + void DrawViewModels( const CViewSetup &view, bool drawViewmodel ); + + void PerformScreenSpaceEffects( int x, int y, int w, int h ); + + // Overlays + void SetScreenOverlayMaterial( IMaterial *pMaterial ); + IMaterial *GetScreenOverlayMaterial( ); + void PerformScreenOverlay( int x, int y, int w, int h ); + + void DrawUnderwaterOverlay( void ); + + // Water-related methods + void DrawWorldAndEntities( bool drawSkybox, const CViewSetup &view, int nClearFlags, ViewCustomVisibility_t *pCustomVisibility = NULL ); + + virtual void ViewDrawScene_Intro( const CViewSetup &view, int nClearFlags, const IntroData_t &introData ); + +#ifdef PORTAL + // Intended for use in the middle of another ViewDrawScene call, this allows stencils to be drawn after opaques but before translucents are drawn in the main view. + void ViewDrawScene_PortalStencil( const CViewSetup &view, ViewCustomVisibility_t *pCustomVisibility ); + void Draw3dSkyboxworld_Portal( const CViewSetup &view, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget = NULL ); +#endif // PORTAL + + // Determines what kind of water we're going to use + void DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVolumeInfo, WaterRenderInfo_t &info ); + + bool UpdateRefractIfNeededByList( CUtlVector< IClientRenderable * > &list ); + void DrawRenderablesInList( CUtlVector< IClientRenderable * > &list, int flags = 0 ); + + // Sets up, cleans up the main 3D view + void SetupMain3DView( const CViewSetup &view, int &nClearFlags ); + void CleanupMain3DView( const CViewSetup &view ); + + + // This stores the current view + CViewSetup m_CurrentView; + + // VIS Overrides + // Set to true to turn off client side vis ( !!!! rendering will be slow since everything will draw ) + bool m_bForceNoVis; + + // Some cvars needed by this system + const ConVar *m_pDrawEntities; + const ConVar *m_pDrawBrushModels; + + // Some materials used... + CMaterialReference m_TranslucentSingleColor; + CMaterialReference m_ModulateSingleColor; + CMaterialReference m_ScreenOverlayMaterial; + CMaterialReference m_UnderWaterOverlayMaterial; + + Vector m_vecLastFacing; + float m_flCheapWaterStartDistance; + float m_flCheapWaterEndDistance; + + CViewSetup m_OverlayViewSetup; + int m_OverlayClearFlags; + int m_OverlayDrawFlags; + bool m_bDrawOverlay; + + int m_BaseDrawFlags; // Set in ViewDrawScene and OR'd into m_DrawFlags as it goes. + C_BaseEntity *m_pCurrentlyDrawingEntity; + +#if defined( CSTRIKE_DLL ) + float m_flLastFOV; +#endif + +#ifdef PORTAL + friend class CPortalRender; //portal drawing needs muck with views in weird ways + friend class CPortalRenderable; +#endif + int m_BuildRenderableListsNumber; + + friend class CBase3dView; + + Frustum m_Frustum; + + CBase3dView *m_pActiveRenderer; + CSimpleRenderExecutor m_SimpleExecutor; + + bool m_rbTakeFreezeFrame[ STEREO_EYE_MAX ]; + float m_flFreezeFrameUntil; + +#if defined( REPLAY_ENABLED ) + CReplayScreenshotTaker *m_pReplayScreenshotTaker; +#endif +}; + +#endif // VIEWRENDER_H diff --git a/game/client/weapon_selection.h b/game/client/weapon_selection.h new file mode 100644 index 0000000..bca6840 --- /dev/null +++ b/game/client/weapon_selection.h @@ -0,0 +1,114 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Weapon selection handling +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( WEAPON_SELECTION_H ) +#define WEAPON_SELECTION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" + +class C_BaseCombatWeapon; +class C_BasePlayer; + +extern ConVar hud_fastswitch; + +// weapon switch types for Convar hud_fastswitch +#define HUDTYPE_BUCKETS 0 // PC buckets +#define HUDTYPE_FASTSWITCH 1 // PC fastswitch +#define HUDTYPE_PLUS 2 // console buckets +#define HUDTYPE_CAROUSEL 3 // console carousel scroll + +//----------------------------------------------------------------------------- +// Purpose: Base class for tf2 & hl2 weapon selection hud elements +//----------------------------------------------------------------------------- +abstract_class CBaseHudWeaponSelection : public CHudElement +{ + DECLARE_CLASS( CBaseHudWeaponSelection, CHudElement ); + +public: + CBaseHudWeaponSelection( const char *pElementName ); + virtual void Init( void ); + virtual void VidInit( void ); + virtual void ProcessInput(); + virtual void Reset(void); + virtual void OnThink(void); + + virtual void OpenSelection( void ); + virtual void HideSelection( void ); + + virtual void CancelWeaponSelection( void ); + + // Game specific overrides + virtual void CycleToNextWeapon( void ) = 0; + virtual void CycleToPrevWeapon( void ) = 0; + virtual void SwitchToLastWeapon( void ); + virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos ) = 0; + virtual void SelectWeaponSlot( int iSlot ) = 0; + virtual C_BaseCombatWeapon *GetFirstPos( int iSlot ); + virtual C_BaseCombatWeapon *GetNextActivePos( int iSlot, int iSlotPos ); + virtual void SetWeaponSelected( void ); + virtual void SelectWeapon( void ); + + virtual C_BaseCombatWeapon *GetSelectedWeapon( void ) = 0; + + virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon ); + virtual bool IsInSelectionMode(); + + void UserCmd_Slot1( void ); + void UserCmd_Slot2( void ); + void UserCmd_Slot3( void ); + void UserCmd_Slot4( void ); + void UserCmd_Slot5( void ); + void UserCmd_Slot6( void ); + void UserCmd_Slot7( void ); + void UserCmd_Slot8( void ); + void UserCmd_Slot9( void ); + void UserCmd_Slot0( void ); + void UserCmd_Slot10( void ); + void UserCmd_Close( void ); + void UserCmd_NextWeapon( void ); + void UserCmd_PrevWeapon( void ); + void UserCmd_LastWeapon( void ); + void UserCmd_DropPrimary( void ); + + virtual void SelectSlot( int iSlot ); + + virtual bool IsHudMenuTakingInput(); + virtual bool IsHudMenuPreventingWeaponSelection(); + + bool HandleHudMenuInput( int iSlot ); + + static CBaseHudWeaponSelection *GetInstance(); + + // these functions are exposed as virtual so that the tf_hints system can redraw the weapon selection + virtual void DrawWList( C_BasePlayer *pPlayer, C_BaseCombatWeapon *pSelectedWeapon, bool drawOutline = false, int ora = 0, int og = 0, int ob = 0, int oa = 0 ) {} + virtual bool ComputeRect( C_BasePlayer *pPlayer, C_BaseCombatWeapon *pSelectedWeapon, wrect_t *outrect ) { return false; } + + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + +protected: + // returns true if there is a weapon currently visible to select + virtual bool IsWeaponSelectable() { return IsInSelectionMode(); } + + bool CanBeSelectedInHUD( C_BaseCombatWeapon *pWeapon ); + + void UpdateSelectionTime( void ); + + float m_flSelectionTime; // most recent time at which weapon selection had input + + static CBaseHudWeaponSelection *s_pInstance; + + bool m_bSelectionVisible; + + CHandle< C_BaseCombatWeapon > m_hSelectedWeapon; +}; + +// accessor +CBaseHudWeaponSelection *GetHudWeaponSelection(); + +#endif // WEAPON_SELECTION_H \ No newline at end of file diff --git a/game/client/weapons_resource.h b/game/client/weapons_resource.h new file mode 100644 index 0000000..db787c2 --- /dev/null +++ b/game/client/weapons_resource.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONS_RESOURCE_H +#define WEAPONS_RESOURCE_H +#pragma once + +#include "shareddefs.h" +#include "weapon_parse.h" +#include "utldict.h" +#include "hud.h" + +class C_BaseCombatWeapon; +class CHudTexture; + +//----------------------------------------------------------------------------- +// Purpose: Stores data about the Weapon Definitions passed to the client when +// the client first connects to a server. +//----------------------------------------------------------------------------- +class WeaponsResource +{ +public: + WeaponsResource( void ); + ~WeaponsResource( void ); + + void Init( void ); + void Reset( void ); + + // Sprite handling + void LoadWeaponSprites( WEAPON_FILE_INFO_HANDLE hWeaponFileInfo ); + void LoadAllWeaponSprites( void ); + + // Ammo Handling + CHudTexture *GetAmmoIconFromWeapon( int iAmmoId ); + const FileWeaponInfo_t *GetWeaponFromAmmo( int iAmmoId ); +}; + +extern WeaponsResource gWR; + +#endif // WEAPONS_RESOURCE_H diff --git a/game/server/AI_Criteria.h b/game/server/AI_Criteria.h new file mode 100644 index 0000000..f10c2d0 --- /dev/null +++ b/game/server/AI_Criteria.h @@ -0,0 +1,239 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_CRITERIA_H +#define AI_CRITERIA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlrbtree.h" +#include "tier1/utlsymbol.h" +#include "interval.h" +#include "mathlib/compressed_vector.h" + +extern const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration ); + + +class AI_CriteriaSet +{ +public: + AI_CriteriaSet(); + AI_CriteriaSet( const AI_CriteriaSet& src ); + ~AI_CriteriaSet(); + + void AppendCriteria( const char *criteria, const char *value = "", float weight = 1.0f ); + void RemoveCriteria( const char *criteria ); + + void Describe(); + + int GetCount() const; + int FindCriterionIndex( const char *name ) const; + + const char *GetName( int index ) const; + const char *GetValue( int index ) const; + float GetWeight( int index ) const; + +private: + + struct CritEntry_t + { + CritEntry_t() : + criterianame( UTL_INVAL_SYMBOL ), + weight( 0.0f ) + { + value[ 0 ] = 0; + } + + CritEntry_t( const CritEntry_t& src ) + { + criterianame = src.criterianame; + value[ 0 ] = 0; + weight = src.weight; + SetValue( src.value ); + } + + CritEntry_t& operator=( const CritEntry_t& src ) + { + if ( this == &src ) + return *this; + + criterianame = src.criterianame; + weight = src.weight; + SetValue( src.value ); + + return *this; + } + + static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs ) + { + return Q_stricmp( lhs.criterianame.String(), rhs.criterianame.String() ) < 0 ? true : false; + } + + void SetValue( char const *str ) + { + if ( !str ) + { + value[ 0 ] = 0; + } + else + { + Q_strncpy( value, str, sizeof( value ) ); + } + } + + // We use CUtlRBTree CopyFrom() in ctor, so CritEntry_t must be POD. If you add + // CUtlString or something then you must change AI_CriteriaSet copy ctor. + CUtlSymbol criterianame; + char value[ 64 ]; + float weight; + }; + + CUtlRBTree< CritEntry_t, short > m_Lookup; +}; + +#pragma pack(1) +template +struct response_interval_t +{ + T start; + T range; + + interval_t &ToInterval( interval_t &dest ) const { dest.start = start; dest.range = range; return dest; } + void FromInterval( const interval_t &from ) { start = from.start; range = from.range; } + float Random() const { interval_t temp = { start, range }; return RandomInterval( temp ); } +}; + +typedef response_interval_t responseparams_interval_t; + +struct AI_ResponseParams +{ + DECLARE_SIMPLE_DATADESC(); + + enum + { + RG_DELAYAFTERSPEAK = (1<<0), + RG_SPEAKONCE = (1<<1), + RG_ODDS = (1<<2), + RG_RESPEAKDELAY = (1<<3), + RG_SOUNDLEVEL = (1<<4), + RG_DONT_USE_SCENE = (1<<5), + RG_STOP_ON_NONIDLE = (1<<6), + RG_WEAPONDELAY = (1<<7), + RG_DELAYBEFORESPEAK = (1<<8), + }; + + AI_ResponseParams() + { + flags = 0; + odds = 100; + delay.start = 0; + delay.range = 0; + respeakdelay.start = 0; + respeakdelay.range = 0; + weapondelay.start = 0; + weapondelay.range = 0; + soundlevel = 0; + predelay.start = 0; + predelay.range = 0; + } + + responseparams_interval_t delay; //4 + responseparams_interval_t respeakdelay; //8 + responseparams_interval_t weapondelay; //12 + + short odds; //14 + + short flags; //16 + byte soundlevel; //17 + + responseparams_interval_t predelay; //21 +}; +#pragma pack() + +//----------------------------------------------------------------------------- +// Purpose: Generic container for a response to a match to a criteria set +// This is what searching for a response returns +//----------------------------------------------------------------------------- +enum ResponseType_t +{ + RESPONSE_NONE = 0, + RESPONSE_SPEAK, + RESPONSE_SENTENCE, + RESPONSE_SCENE, + RESPONSE_RESPONSE, // A reference to another response by name + RESPONSE_PRINT, + + NUM_RESPONSES, +}; + +class AI_Response +{ +public: + DECLARE_SIMPLE_DATADESC(); + + AI_Response(); + AI_Response( const AI_Response &from ); + ~AI_Response(); + AI_Response &operator=( const AI_Response &from ); + + void Release(); + + const char * GetNamePtr() const; + const char * GetResponsePtr() const; + const AI_ResponseParams *GetParams() const { return &m_Params; } + ResponseType_t GetType() const { return (ResponseType_t)m_Type; } + soundlevel_t GetSoundLevel() const; + float GetRespeakDelay() const; + float GetWeaponDelay() const; + bool GetSpeakOnce() const; + bool ShouldntUseScene( ) const; + bool ShouldBreakOnNonIdle( void ) const; + int GetOdds() const; + float GetDelay() const; + float GetPreDelay() const; + + void SetContext( const char *context ); + const char * GetContext( void ) const { return m_szContext.Length() ? m_szContext.Get() : NULL; } + + bool IsApplyContextToWorld( void ) { return m_bApplyContextToWorld; } + + void Describe(); + + const AI_CriteriaSet* GetCriteria(); + + void Init( ResponseType_t type, + const char *responseName, + const AI_CriteriaSet& criteria, + const AI_ResponseParams& responseparams, + const char *matchingRule, + const char *applyContext, + bool bApplyContextToWorld ); + + static const char *DescribeResponse( ResponseType_t type ); + + enum + { + MAX_RESPONSE_NAME = 64, + MAX_RULE_NAME = 64 + }; + + +private: + byte m_Type; + char m_szResponseName[ MAX_RESPONSE_NAME ]; + char m_szMatchingRule[ MAX_RULE_NAME ]; + + // The initial criteria to which we are responsive + AI_CriteriaSet *m_pCriteria; + + AI_ResponseParams m_Params; + + CUtlString m_szContext; + bool m_bApplyContextToWorld; +}; + +#endif // AI_CRITERIA_H diff --git a/game/server/AI_Interest_Target.h b/game/server/AI_Interest_Target.h new file mode 100644 index 0000000..dd4cfe3 --- /dev/null +++ b/game/server/AI_Interest_Target.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hooks and classes for the support of humanoid NPCs with +// groovy facial animation capabilities, aka, "Actors" +// +//=============================================================================// + +#ifndef AI_INTEREST_TARGET_H +#define AI_INTEREST_TARGET_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// CAI_BaseActor +// +// Purpose: The base class for all facially expressive NPCS. +// +//----------------------------------------------------------------------------- + +class CAI_InterestTarget_t +{ +public: + enum CAI_InterestTarget_e + { + LOOKAT_ENTITY = 0, + LOOKAT_POSITION, + LOOKAT_BOTH + }; + +public: + bool IsThis( CBaseEntity *pThis ); + const Vector &GetPosition( void ); + bool IsActive( void ); + float Interest( void ); + +public: + CAI_InterestTarget_e m_eType; // ???? + + EHANDLE m_hTarget; + Vector m_vecPosition; + float m_flStartTime; + float m_flEndTime; + float m_flRamp; + float m_flInterest; + + DECLARE_SIMPLE_DATADESC(); +}; + + +class CAI_InterestTarget : public CUtlVector +{ +public: + void Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp ); + void Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp ); + void Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp ); + int Find( CBaseEntity *pTarget ) + { + int i; + for ( i = 0; i < Count(); i++) + { + if (pTarget == (*this)[i].m_hTarget) + return i; + } + return InvalidIndex(); + } + + void Cleanup( void ) + { + int i; + for (i = Count() - 1; i >= 0; i--) + { + if (!Element(i).IsActive()) + { + Remove( i ); + } + } + }; + +private: + void Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp ); +}; + + +//----------------------------------------------------------------------------- +#endif // AI_INTEREST_TARGET_H diff --git a/game/server/AI_ResponseSystem.h b/game/server/AI_ResponseSystem.h new file mode 100644 index 0000000..a7b3a79 --- /dev/null +++ b/game/server/AI_ResponseSystem.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_RESPONSESYSTEM_H +#define AI_RESPONSESYSTEM_H + +#include "utlvector.h" + +#ifdef _WIN32 +#pragma once +#endif + +#include "AI_Criteria.h" + +abstract_class IResponseFilter +{ +public: + virtual ~IResponseFilter(){} + virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ) = 0; +}; + +abstract_class IResponseSystem +{ +public: + virtual ~IResponseSystem() {} + + virtual bool FindBestResponse( const AI_CriteriaSet& set, AI_Response& response, IResponseFilter *pFilter = NULL ) = 0; + virtual void GetAllResponses( CUtlVector *pResponses ) = 0; + virtual void PrecacheResponses( bool bEnable ) = 0; +}; + +IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile ); +IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore ); +void DestroyCustomResponseSystems(); + +class ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler(); +class ISaveRestoreOps *GetResponseSystemSaveRestoreOps(); + +#endif // AI_RESPONSESYSTEM_H diff --git a/game/server/BaseAnimatingOverlay.h b/game/server/BaseAnimatingOverlay.h new file mode 100644 index 0000000..5184eac --- /dev/null +++ b/game/server/BaseAnimatingOverlay.h @@ -0,0 +1,232 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// #include "BaseAnimating.h" + +#ifndef BASE_ANIMATING_OVERLAY_H +#define BASE_ANIMATING_OVERLAY_H +#ifdef _WIN32 +#pragma once +#endif + +class CBaseAnimatingOverlay; + +class CAnimationLayer +{ +public: + DECLARE_CLASS_NOBASE( CAnimationLayer ); + + CAnimationLayer( void ); + void Init( CBaseAnimatingOverlay *pOverlay ); + + // float SetBlending( int iBlender, float flValue, CBaseAnimating *pOwner ); + void StudioFrameAdvance( float flInterval, CBaseAnimating *pOwner ); + void DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAnimating *pOwner ); + void SetOrder( int nOrder ); + + float GetFadeout( float flCurTime ); + + // For CNetworkVars. + void NetworkStateChanged(); + void NetworkStateChanged( void *pVar ); + +public: + +#define ANIM_LAYER_ACTIVE 0x0001 +#define ANIM_LAYER_AUTOKILL 0x0002 +#define ANIM_LAYER_KILLME 0x0004 +#define ANIM_LAYER_DONTRESTORE 0x0008 +#define ANIM_LAYER_CHECKACCESS 0x0010 +#define ANIM_LAYER_DYING 0x0020 + + int m_fFlags; + + bool m_bSequenceFinished; + bool m_bLooping; + + CNetworkVar( int, m_nSequence ); + CNetworkVar( float, m_flCycle ); + CNetworkVar( float, m_flPrevCycle ); + CNetworkVar( float, m_flWeight ); + + float m_flPlaybackRate; + + float m_flBlendIn; // start and end blend frac (0.0 for now blend) + float m_flBlendOut; + + float m_flKillRate; + float m_flKillDelay; + + float m_flLayerAnimtime; + float m_flLayerFadeOuttime; + + // For checking for duplicates + Activity m_nActivity; + + // order of layering on client + int m_nPriority; + CNetworkVar( int, m_nOrder ); + + bool IsActive( void ) { return ((m_fFlags & ANIM_LAYER_ACTIVE) != 0); } + bool IsAutokill( void ) { return ((m_fFlags & ANIM_LAYER_AUTOKILL) != 0); } + bool IsKillMe( void ) { return ((m_fFlags & ANIM_LAYER_KILLME) != 0); } + bool IsAutoramp( void ) { return (m_flBlendIn != 0.0 || m_flBlendOut != 0.0); } + void KillMe( void ) { m_fFlags |= ANIM_LAYER_KILLME; } + void Dying( void ) { m_fFlags |= ANIM_LAYER_DYING; } + bool IsDying( void ) { return ((m_fFlags & ANIM_LAYER_DYING) != 0); } + void Dead( void ) { m_fFlags &= ~ANIM_LAYER_DYING; } + + bool IsAbandoned( void ); + void MarkActive( void ); + + float m_flLastEventCheck; + + float m_flLastAccess; + + // Network state changes get forwarded here. + CBaseAnimatingOverlay *m_pOwnerEntity; + + DECLARE_SIMPLE_DATADESC(); +}; + +inline float CAnimationLayer::GetFadeout( float flCurTime ) +{ + float s; + + if (m_flLayerFadeOuttime <= 0.0f) + { + s = 0; + } + else + { + // blend in over 0.2 seconds + s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime; + if (s > 0 && s <= 1.0) + { + // do a nice spline curve + s = 3 * s * s - 2 * s * s * s; + } + else if ( s > 1.0f ) + { + // Shouldn't happen, but maybe curtime is behind animtime? + s = 1.0f; + } + } + return s; +} + + + +class CBaseAnimatingOverlay : public CBaseAnimating +{ + DECLARE_CLASS( CBaseAnimatingOverlay, CBaseAnimating ); + +public: + enum + { + MAX_OVERLAYS = 15, + }; + +private: + CUtlVector< CAnimationLayer > m_AnimOverlay; + //int m_nActiveLayers; + //int m_nActiveBaseLayers; + +public: + + virtual void OnRestore(); + + virtual void StudioFrameAdvance(); + virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); + virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask ); + + int AddGestureSequence( int sequence, bool autokill = true ); + int AddGestureSequence( int sequence, float flDuration, bool autokill = true ); + int AddGesture( Activity activity, bool autokill = true ); + int AddGesture( Activity activity, float flDuration, bool autokill = true ); + bool IsPlayingGesture( Activity activity ); + void RestartGesture( Activity activity, bool addifmissing = true, bool autokill = true ); + void RemoveGesture( Activity activity ); + void RemoveAllGestures( void ); + + int AddLayeredSequence( int sequence, int iPriority ); + + void SetLayerPriority( int iLayer, int iPriority ); + + bool IsValidLayer( int iLayer ); + + void SetLayerDuration( int iLayer, float flDuration ); + float GetLayerDuration( int iLayer ); + + void SetLayerCycle( int iLayer, float flCycle ); + void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle ); + void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle, float flLastEventCheck ); + float GetLayerCycle( int iLayer ); + + void SetLayerPlaybackRate( int iLayer, float flPlaybackRate ); + void SetLayerWeight( int iLayer, float flWeight ); + float GetLayerWeight( int iLayer ); + void SetLayerBlendIn( int iLayer, float flBlendIn ); + void SetLayerBlendOut( int iLayer, float flBlendOut ); + void SetLayerAutokill( int iLayer, bool bAutokill ); + void SetLayerLooping( int iLayer, bool bLooping ); + void SetLayerNoRestore( int iLayer, bool bNoRestore ); + + Activity GetLayerActivity( int iLayer ); + int GetLayerSequence( int iLayer ); + + int FindGestureLayer( Activity activity ); + + void RemoveLayer( int iLayer, float flKillRate = 0.2, float flKillDelay = 0.0 ); + void FastRemoveLayer( int iLayer ); + + CAnimationLayer *GetAnimOverlay( int iIndex ); + int GetNumAnimOverlays() const; + void SetNumAnimOverlays( int num ); + + void VerifyOrder( void ); + + bool HasActiveLayer( void ); + +private: + int AllocateLayer( int iPriority = 0 ); // lower priorities are processed first + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DECLARE_PREDICTABLE(); +}; + +EXTERN_SEND_TABLE(DT_BaseAnimatingOverlay); + +inline int CBaseAnimatingOverlay::GetNumAnimOverlays() const +{ + return m_AnimOverlay.Count(); +} + +// ------------------------------------------------------------------------------------------ // +// CAnimationLayer inlines. +// ------------------------------------------------------------------------------------------ // + +inline void CAnimationLayer::SetOrder( int nOrder ) +{ + m_nOrder = nOrder; +} + +inline void CAnimationLayer::NetworkStateChanged() +{ + if ( m_pOwnerEntity ) + m_pOwnerEntity->NetworkStateChanged(); +} + +inline void CAnimationLayer::NetworkStateChanged( void *pVar ) +{ + if ( m_pOwnerEntity ) + m_pOwnerEntity->NetworkStateChanged(); +} + +#endif // BASE_ANIMATING_OVERLAY_H diff --git a/game/server/BasePropDoor.h b/game/server/BasePropDoor.h new file mode 100644 index 0000000..1bfdc40 --- /dev/null +++ b/game/server/BasePropDoor.h @@ -0,0 +1,275 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A base class for model-based doors. The exact movement required to +// open or close the door is not dictated by this class, only that +// the door has open, closed, opening, and closing states. +// +// Doors must satisfy these requirements: +// +// - Derived classes must support being opened by NPCs. +// - Never autoclose in the face of a player. +// - Never close into an NPC. +// +//=============================================================================// + +#ifndef BASEPROPDOOR_H +#define BASEPROPDOOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "props.h" +#include "locksounds.h" +#include "entityoutput.h" + +extern ConVar g_debug_doors; + +struct opendata_t +{ + Vector vecStandPos; // Where the NPC should stand. + Vector vecFaceDir; // What direction the NPC should face. + Activity eActivity; // What activity the NPC should play. +}; + + +abstract_class CBasePropDoor : public CDynamicProp +{ +public: + + DECLARE_CLASS( CBasePropDoor, CDynamicProp ); + DECLARE_SERVERCLASS(); + + CBasePropDoor( void ); + + void Spawn(); + void Precache(); + void Activate(); + int ObjectCaps(); + + void HandleAnimEvent( animevent_t *pEvent ); + + // Base class services. + // Do not make the functions in this block virtual!! + // { + inline bool IsDoorOpen(); + inline bool IsDoorAjar(); + inline bool IsDoorOpening(); + inline bool IsDoorClosed(); + inline bool IsDoorClosing(); + inline bool IsDoorLocked(); + inline bool IsDoorBlocked() const; + inline bool IsNPCOpening(CAI_BaseNPC *pNPC); + inline bool IsPlayerOpening(); + inline bool IsOpener(CBaseEntity *pEnt); + + bool NPCOpenDoor(CAI_BaseNPC *pNPC); + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + // } + + // Implement these in your leaf class. + // { + virtual bool DoorCanClose( bool bAutoClose ) { return true; } + virtual bool DoorCanOpen( void ) { return true; } + + virtual void GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) = 0; + virtual float GetOpenInterval(void) = 0; + // } + +protected: + + enum DoorState_t + { + DOOR_STATE_CLOSED = 0, + DOOR_STATE_OPENING, + DOOR_STATE_OPEN, + DOOR_STATE_CLOSING, + DOOR_STATE_AJAR, + }; + + // dvs: FIXME: make these private + void DoorClose(); + + CBasePropDoor *GetMaster( void ) { return m_hMaster; } + bool HasSlaves( void ) { return ( m_hDoorList.Count() > 0 ); } + + inline void SetDoorState( DoorState_t eDoorState ); + + float m_flAutoReturnDelay; // How many seconds to wait before automatically closing, -1 never closes automatically. + CUtlVector< CHandle< CBasePropDoor > > m_hDoorList; // List of doors linked to us + + inline CBaseEntity *GetActivator(); + +private: + + // Implement these in your leaf class. + // { + // Called when the door becomes fully open. + virtual void OnDoorOpened() {} + + // Called when the door becomes fully closed. + virtual void OnDoorClosed() {} + + // Called to tell the door to start opening. + virtual void BeginOpening(CBaseEntity *pOpenAwayFrom) = 0; + + // Called to tell the door to start closing. + virtual void BeginClosing( void ) = 0; + + // Called when blocked to tell the door to stop moving. + virtual void DoorStop( void ) = 0; + + // Called when blocked to tell the door to continue moving. + virtual void DoorResume( void ) = 0; + + // Called to send the door instantly to its spawn positions. + virtual void DoorTeleportToSpawnPosition() = 0; + // } + +private: + + // Main entry points for the door base behaviors. + // Do not make the functions in this block virtual!! + // { + bool DoorActivate(); + void DoorOpen( CBaseEntity *pOpenAwayFrom ); + void OpenIfUnlocked(CBaseEntity *pActivator, CBaseEntity *pOpenAwayFrom); + + void DoorOpenMoveDone(); + void DoorCloseMoveDone(); + void DoorAutoCloseThink(); + + void Lock(); + void Unlock(); + + void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + void OnUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + inline bool WillAutoReturn() { return m_flAutoReturnDelay != -1; } + + void StartBlocked(CBaseEntity *pOther); + void OnStartBlocked( CBaseEntity *pOther ); + void MasterStartBlocked( CBaseEntity *pOther ); + + void Blocked(CBaseEntity *pOther); + void EndBlocked(void); + void OnEndBlocked( void ); + + void UpdateAreaPortals(bool bOpen); + + // Input handlers + void InputClose(inputdata_t &inputdata); + void InputLock(inputdata_t &inputdata); + void InputOpen(inputdata_t &inputdata); + void InputOpenAwayFrom(inputdata_t &inputdata); + void InputToggle(inputdata_t &inputdata); + void InputUnlock(inputdata_t &inputdata); + + void SetDoorBlocker( CBaseEntity *pBlocker ); + + void SetMaster( CBasePropDoor *pMaster ) { m_hMaster = pMaster; } + + void CalcDoorSounds(); + // } + + int m_nHardwareType; + + DoorState_t m_eDoorState; // Holds whether the door is open, closed, opening, or closing. + + locksound_t m_ls; // The sounds the door plays when being locked, unlocked, etc. + EHANDLE m_hActivator; + + bool m_bLocked; // True if the door is locked. + EHANDLE m_hBlocker; // Entity blocking the door currently + bool m_bFirstBlocked; // Marker for being the first door (in a group) to be blocked (needed for motion control) + + bool m_bForceClosed; // True if this door must close no matter what. + + string_t m_SoundMoving; + string_t m_SoundOpen; + string_t m_SoundClose; + + // dvs: FIXME: can we remove m_flSpeed from CBaseEntity? + //float m_flSpeed; // Rotation speed when opening or closing in degrees per second. + + DECLARE_DATADESC(); + + string_t m_SlaveName; + + CHandle< CBasePropDoor > m_hMaster; + + static void RegisterPrivateActivities(); + + // Outputs + COutputEvent m_OnBlockedClosing; // Triggered when the door becomes blocked while closing. + COutputEvent m_OnBlockedOpening; // Triggered when the door becomes blocked while opening. + COutputEvent m_OnUnblockedClosing; // Triggered when the door becomes unblocked while closing. + COutputEvent m_OnUnblockedOpening; // Triggered when the door becomes unblocked while opening. + COutputEvent m_OnFullyClosed; // Triggered when the door reaches the fully closed position. + COutputEvent m_OnFullyOpen; // Triggered when the door reaches the fully open position. + COutputEvent m_OnClose; // Triggered when the door is told to close. + COutputEvent m_OnOpen; // Triggered when the door is told to open. + COutputEvent m_OnLockedUse; // Triggered when the user tries to open a locked door. +}; + + +void CBasePropDoor::SetDoorState( DoorState_t eDoorState ) +{ + m_eDoorState = eDoorState; +} + +bool CBasePropDoor::IsDoorOpen() +{ + return m_eDoorState == DOOR_STATE_OPEN; +} + +bool CBasePropDoor::IsDoorAjar() +{ + return ( m_eDoorState == DOOR_STATE_AJAR ); +} + +bool CBasePropDoor::IsDoorOpening() +{ + return m_eDoorState == DOOR_STATE_OPENING; +} + +bool CBasePropDoor::IsDoorClosed() +{ + return m_eDoorState == DOOR_STATE_CLOSED; +} + +bool CBasePropDoor::IsDoorClosing() +{ + return m_eDoorState == DOOR_STATE_CLOSING; +} + +bool CBasePropDoor::IsDoorLocked() +{ + return m_bLocked; +} + +CBaseEntity *CBasePropDoor::GetActivator() +{ + return m_hActivator; +} + +bool CBasePropDoor::IsDoorBlocked() const +{ + return ( m_hBlocker != NULL ); +} + +bool CBasePropDoor::IsNPCOpening( CAI_BaseNPC *pNPC ) +{ + return ( pNPC == ( CAI_BaseNPC * )GetActivator() ); +} + +inline bool CBasePropDoor::IsPlayerOpening() +{ + return ( GetActivator() && GetActivator()->IsPlayer() ); +} + +inline bool CBasePropDoor::IsOpener(CBaseEntity *pEnt) +{ + return ( GetActivator() == pEnt ); +} + +#endif // BASEPROPDOOR_H diff --git a/game/server/CRagdollMagnet.h b/game/server/CRagdollMagnet.h new file mode 100644 index 0000000..b221172 --- /dev/null +++ b/game/server/CRagdollMagnet.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Used to influence the initial force for a dying NPC's ragdoll. +// Passive entity. Just represents position in the world, radius, force +// +// $NoKeywords: $ +//=============================================================================// +#pragma once + +#ifndef CRAGDOLLMAGNET_H +#define CRAGDOLLMAGNET_H + +#define SF_RAGDOLLMAGNET_BAR 0x00000002 // this is a bar magnet. + +class CRagdollMagnet : public CPointEntity +{ +public: + DECLARE_CLASS( CRagdollMagnet, CPointEntity ); + DECLARE_DATADESC(); + + Vector GetForceVector( CBaseEntity *pNPC ); + float GetRadius( void ) { return m_radius; } + Vector GetAxisVector( void ) { return m_axis - GetAbsOrigin(); } + float DistToPoint( const Vector &vecPoint ); + + bool IsEnabled( void ) { return !m_bDisabled; } + + int IsBarMagnet( void ) { return (m_spawnflags & SF_RAGDOLLMAGNET_BAR); } + + static CRagdollMagnet *FindBestMagnet( CBaseEntity *pNPC ); + + void Enable( bool bEnable ) { m_bDisabled = !bEnable; } + + // Inputs + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + +private: + bool m_bDisabled; + float m_radius; + float m_force; + Vector m_axis; +}; + +#endif //CRAGDOLLMAGNET_H \ No newline at end of file diff --git a/game/server/EntityDissolve.h b/game/server/EntityDissolve.h new file mode 100644 index 0000000..ae9e819 --- /dev/null +++ b/game/server/EntityDissolve.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYDISSOLVE_H +#define ENTITYDISSOLVE_H + +#ifdef _WIN32 +#pragma once +#endif + +class CEntityDissolve : public CBaseEntity +{ +public: + DECLARE_SERVERCLASS(); + DECLARE_CLASS( CEntityDissolve, CBaseEntity ); + + CEntityDissolve( void ); + ~CEntityDissolve( void ); + + static CEntityDissolve *Create( CBaseEntity *pTarget, const char *pMaterialName, + float flStartTime, int nDissolveType = 0, bool *pRagdollCreated = NULL ); + static CEntityDissolve *Create( CBaseEntity *pTarget, CBaseEntity *pSource ); + + void Precache(); + void Spawn(); + void AttachToEntity( CBaseEntity *pTarget ); + void SetStartTime( float flStartTime ); + void SetDissolverOrigin( Vector vOrigin ) { m_vDissolverOrigin = vOrigin; } + void SetMagnitude( int iMagnitude ){ m_nMagnitude = iMagnitude; } + void SetDissolveType( int iType ) { m_nDissolveType = iType; } + + Vector GetDissolverOrigin( void ) + { + Vector vReturn = m_vDissolverOrigin; + return vReturn; + } + int GetMagnitude( void ) { return m_nMagnitude; } + int GetDissolveType( void ) { return m_nDissolveType; } + + DECLARE_DATADESC(); + + CNetworkVar( float, m_flStartTime ); + CNetworkVar( float, m_flFadeInStart ); + CNetworkVar( float, m_flFadeInLength ); + CNetworkVar( float, m_flFadeOutModelStart ); + CNetworkVar( float, m_flFadeOutModelLength ); + CNetworkVar( float, m_flFadeOutStart ); + CNetworkVar( float, m_flFadeOutLength ); + +protected: + void InputDissolve( inputdata_t &inputdata ); + void DissolveThink( void ); + void ElectrocuteThink( void ); + + CNetworkVar( int, m_nDissolveType ); + CNetworkVector( m_vDissolverOrigin ); + CNetworkVar( int, m_nMagnitude ); +}; + +#endif // ENTITYDISSOLVE_H diff --git a/game/server/EntityFlame.h b/game/server/EntityFlame.h new file mode 100644 index 0000000..9ea1360 --- /dev/null +++ b/game/server/EntityFlame.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYFLAME_H +#define ENTITYFLAME_H +#ifdef _WIN32 +#pragma once +#endif + +#define FLAME_DAMAGE_INTERVAL 0.2f // How often to deal damage. +#define FLAME_DIRECT_DAMAGE_PER_SEC 5.0f +#define FLAME_RADIUS_DAMAGE_PER_SEC 4.0f + +#define FLAME_DIRECT_DAMAGE ( FLAME_DIRECT_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL ) +#define FLAME_RADIUS_DAMAGE ( FLAME_RADIUS_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL ) + +#define FLAME_MAX_LIFETIME_ON_DEAD_NPCS 10.0f + +class CEntityFlame : public CBaseEntity +{ +public: + DECLARE_SERVERCLASS(); + DECLARE_CLASS( CEntityFlame, CBaseEntity ); + + CEntityFlame( void ); + + static CEntityFlame *Create( CBaseEntity *pTarget, bool useHitboxes = true ); + + void AttachToEntity( CBaseEntity *pTarget ); + void SetLifetime( float lifetime ); + void SetUseHitboxes( bool use ); + void SetNumHitboxFires( int iNumHitBoxFires ); + void SetHitboxFireScale( float flHitboxFireScale ); + + float GetRemainingLife( void ); + int GetNumHitboxFires( void ); + float GetHitboxFireScale( void ); + + virtual void Precache(); + virtual void UpdateOnRemove(); + + void SetSize( float size ) { m_flSize = size; } + + DECLARE_DATADESC(); + +protected: + + void InputIgnite( inputdata_t &inputdata ); + + void FlameThink( void ); + + CNetworkHandle( CBaseEntity, m_hEntAttached ); // The entity that we are burning (attached to). + + CNetworkVar( float, m_flSize ); + CNetworkVar( bool, m_bUseHitboxes ); + CNetworkVar( int, m_iNumHitboxFires ); + CNetworkVar( float, m_flHitboxFireScale ); + + CNetworkVar( float, m_flLifetime ); + bool m_bPlayingSound; +}; + +#endif // ENTITYFLAME_H diff --git a/game/server/EntityParticleTrail.h b/game/server/EntityParticleTrail.h new file mode 100644 index 0000000..d22e0d4 --- /dev/null +++ b/game/server/EntityParticleTrail.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYPARTICLETRAIL_H +#define ENTITYPARTICLETRAIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "baseparticleentity.h" +#include "entityparticletrail_shared.h" + + +//----------------------------------------------------------------------------- +// Spawns particles after the entity +//----------------------------------------------------------------------------- +class CEntityParticleTrail : public CBaseParticleEntity +{ + DECLARE_DATADESC(); + DECLARE_CLASS( CEntityParticleTrail, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + +public: + static CEntityParticleTrail *Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraint ); + static void Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info ); + + void Spawn(); + virtual void UpdateOnRemove(); + + // Force our constraint entity to be trasmitted + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + // Clean up when the entity goes away. + virtual void NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t ¶ms ); + +private: + void AttachToEntity( CBaseEntity *pTarget ); + void IncrementRefCount(); + void DecrementRefCount(); + + CNetworkVar( int, m_iMaterialName ); + CNetworkVarEmbedded( EntityParticleTrailInfo_t, m_Info ); + CNetworkHandle( CBaseEntity, m_hConstraintEntity ); + + int m_nRefCount; +}; + +#endif // ENTITYPARTICLETRAIL_H diff --git a/game/server/EnvLaser.h b/game/server/EnvLaser.h new file mode 100644 index 0000000..7916504 --- /dev/null +++ b/game/server/EnvLaser.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENVLASER_H +#define ENVLASER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "beam_shared.h" +#include "entityoutput.h" + + +class CSprite; + + +class CEnvLaser : public CBeam +{ + DECLARE_CLASS( CEnvLaser, CBeam ); +public: + void Spawn( void ); + void Precache( void ); + bool KeyValue( const char *szKeyName, const char *szValue ); + + void TurnOn( void ); + void TurnOff( void ); + int IsOn( void ); + + void FireAtPoint( trace_t &point ); + void StrikeThink( void ); + + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + + string_t m_iszLaserTarget; // Name of entity or entities to strike at, randomly picked if more than one match. + CSprite *m_pSprite; + string_t m_iszSpriteName; + Vector m_firePosition; + + float m_flStartFrame; +}; + +#endif // ENVLASER_H diff --git a/game/server/EnvMessage.h b/game/server/EnvMessage.h new file mode 100644 index 0000000..cca710e --- /dev/null +++ b/game/server/EnvMessage.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENVMESSAGE_H +#define ENVMESSAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "entityoutput.h" + + +#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out +#define SF_MESSAGE_ALL 0x0002 // Send to all clients + +class CMessage : public CPointEntity +{ +public: + DECLARE_CLASS( CMessage, CPointEntity ); + + void Spawn( void ); + void Precache( void ); + + inline void SetMessage( string_t iszMessage ) { m_iszMessage = iszMessage; } + + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +private: + + void InputShowMessage( inputdata_t &inputdata ); + + string_t m_iszMessage; // Message to display. + float m_MessageVolume; + int m_MessageAttenuation; + float m_Radius; + + DECLARE_DATADESC(); + + string_t m_sNoise; + COutputEvent m_OnShowMessage; +}; + +#endif // ENVMESSAGE_H diff --git a/game/server/EventLog.h b/game/server/EventLog.h new file mode 100644 index 0000000..1bcbd01 --- /dev/null +++ b/game/server/EventLog.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined EVENTLOG_H +#define EVENTLOG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "GameEventListener.h" +#include + +class CEventLog : public CGameEventListener, public CBaseGameSystem +{ + +public: + CEventLog(); + virtual ~CEventLog(); + +public: // IGameEventListener Interface + + virtual void FireGameEvent( IGameEvent * event ); + +public: // CBaseGameSystem overrides + + virtual bool Init(); + virtual void Shutdown(); + +protected: + + virtual bool PrintEvent( IGameEvent * event ); + virtual bool PrintGameEvent( IGameEvent * event ); + virtual bool PrintPlayerEvent( IGameEvent * event ); + virtual bool PrintTeamEvent( IGameEvent * event ); + virtual bool PrintOtherEvent( IGameEvent * event ); +}; + +extern IGameSystem* GameLogSystem(); + +#endif // EVENTLOG_H diff --git a/game/server/RagdollBoogie.h b/game/server/RagdollBoogie.h new file mode 100644 index 0000000..cb52c95 --- /dev/null +++ b/game/server/RagdollBoogie.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef RAGDOLLBOOGIE_H +#define RAGDOLLBOOGIE_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Set this spawnflag before calling Spawn to get electrical effects +//----------------------------------------------------------------------------- +#define SF_RAGDOLL_BOOGIE_ELECTRICAL 0x10000 +#define SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM 0x20000 + + +//----------------------------------------------------------------------------- +// Makes ragdolls DANCE! +//----------------------------------------------------------------------------- +class CRagdollBoogie : public CBaseEntity +{ + DECLARE_DATADESC(); + DECLARE_CLASS( CRagdollBoogie, CBaseEntity ); + +public: + static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0 ); + static void IncrementSuppressionCount( CBaseEntity *pTarget ); + static void DecrementSuppressionCount( CBaseEntity *pTarget ); + + void Spawn(); + +private: + void AttachToEntity( CBaseEntity *pTarget ); + void SetBoogieTime( float flStartTime, float flLengthTime ); + void SetMagnitude( float flMagnitude ); + void BoogieThink( void ); + void ZapThink(); + + float m_flStartTime; + float m_flBoogieLength; + float m_flMagnitude; + int m_nSuppressionCount; +}; + +#endif // RAGDOLLBOOGIE_H diff --git a/game/server/ServerNetworkProperty.h b/game/server/ServerNetworkProperty.h new file mode 100644 index 0000000..cb4c386 --- /dev/null +++ b/game/server/ServerNetworkProperty.h @@ -0,0 +1,258 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef SERVERNETWORKPROPERTY_H +#define SERVERNETWORKPROPERTY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iservernetworkable.h" +#include "server_class.h" +#include "edict.h" +#include "timedeventmgr.h" + +// +// Lightweight base class for networkable data on the server. +// +class CServerNetworkProperty : public IServerNetworkable, public IEventRegisterCallback +{ +public: + DECLARE_CLASS_NOBASE( CServerNetworkProperty ); + DECLARE_DATADESC(); + +public: + CServerNetworkProperty(); + virtual ~CServerNetworkProperty(); + +public: +// IServerNetworkable implementation. + virtual IHandleEntity *GetEntityHandle( ); + virtual edict_t *GetEdict() const; + virtual CBaseNetworkable* GetBaseNetworkable(); + virtual CBaseEntity* GetBaseEntity(); + virtual ServerClass* GetServerClass(); + virtual const char* GetClassName() const; + virtual void Release(); + virtual int AreaNum() const; + virtual PVSInfo_t* GetPVSInfo(); + +public: + // Other public methods + void Init( CBaseEntity *pEntity ); + + void AttachEdict( edict_t *pRequiredEdict = NULL ); + + // Methods to get the entindex + edict + int entindex() const; + edict_t *edict(); + const edict_t *edict() const; + + // Sets the edict pointer (for swapping edicts) + void SetEdict( edict_t *pEdict ); + + // All these functions call through to CNetStateMgr. + // See CNetStateMgr for details about these functions. + void NetworkStateForceUpdate(); + void NetworkStateChanged(); + void NetworkStateChanged( unsigned short offset ); + + // Marks the PVS information dirty + void MarkPVSInformationDirty(); + + // Marks for deletion + void MarkForDeletion(); + bool IsMarkedForDeletion() const; + + // Sets the network parent + void SetNetworkParent( EHANDLE hParent ); + CServerNetworkProperty* GetNetworkParent(); + + // This is useful for entities that don't change frequently or that the client + // doesn't need updates on very often. If you use this mode, the server will only try to + // detect state changes every N seconds, so it will save CPU cycles and bandwidth. + // + // Note: N must be less than AUTOUPDATE_MAX_TIME_LENGTH. + // + // Set back to zero to disable the feature. + // + // This feature works on top of manual mode. + // - If you turn it on and manual mode is off, it will autodetect changes every N seconds. + // - If you turn it on and manual mode is on, then every N seconds it will only say there + // is a change if you've called NetworkStateChanged. + void SetUpdateInterval( float N ); + + // You can use this to override any entity's ShouldTransmit behavior. + // void SetTransmitProxy( CBaseTransmitProxy *pProxy ); + + // This version does a PVS check which also checks for connected areas + bool IsInPVS( const CCheckTransmitInfo *pInfo ); + + // This version doesn't do the area check + bool IsInPVS( const edict_t *pRecipient, const void *pvs, int pvssize ); + + // Called by the timed event manager when it's time to detect a state change. + virtual void FireEvent(); + + // Recomputes PVS information + void RecomputePVSInformation(); + +private: + // Detaches the edict.. should only be called by CBaseNetworkable's destructor. + void DetachEdict(); + CBaseEntity *GetOuter(); + + // Marks the networkable that it will should transmit + void SetTransmit( CCheckTransmitInfo *pInfo ); + +private: + CBaseEntity *m_pOuter; + // CBaseTransmitProxy *m_pTransmitProxy; + edict_t *m_pPev; + PVSInfo_t m_PVSInfo; + ServerClass *m_pServerClass; + + // NOTE: This state is 'owned' by the entity. It's only copied here + // also to help improve cache performance in networking code. + EHANDLE m_hParent; + + // Counters for SetUpdateInterval. + CEventRegister m_TimerEvent; + bool m_bPendingStateChange : 1; + +// friend class CBaseTransmitProxy; +}; + + +//----------------------------------------------------------------------------- +// inline methods // TODOMO does inline work on virtual functions ? +//----------------------------------------------------------------------------- +inline CBaseNetworkable* CServerNetworkProperty::GetBaseNetworkable() +{ + return NULL; +} + +inline CBaseEntity* CServerNetworkProperty::GetBaseEntity() +{ + return m_pOuter; +} + +inline CBaseEntity *CServerNetworkProperty::GetOuter() +{ + return m_pOuter; +} + +inline PVSInfo_t *CServerNetworkProperty::GetPVSInfo() +{ + return &m_PVSInfo; +} + + +//----------------------------------------------------------------------------- +// Marks the PVS information dirty +//----------------------------------------------------------------------------- +inline void CServerNetworkProperty::MarkPVSInformationDirty() +{ + if ( m_pPev ) + { + m_pPev->m_fStateFlags |= FL_EDICT_DIRTY_PVS_INFORMATION; + } +} + + +//----------------------------------------------------------------------------- +// Sets/gets the network parent +//----------------------------------------------------------------------------- +inline void CServerNetworkProperty::SetNetworkParent( EHANDLE hParent ) +{ + m_hParent = hParent; +} + + +//----------------------------------------------------------------------------- +// Methods related to the net state mgr +//----------------------------------------------------------------------------- +inline void CServerNetworkProperty::NetworkStateForceUpdate() +{ + if ( m_pPev ) + m_pPev->StateChanged(); +} + +inline void CServerNetworkProperty::NetworkStateChanged() +{ + // If we're using the timer, then ignore this call. + if ( m_TimerEvent.IsRegistered() ) + { + // If we're waiting for a timer event, then queue the change so it happens + // when the timer goes off. + m_bPendingStateChange = true; + } + else + { + if ( m_pPev ) + m_pPev->StateChanged(); + } +} + +inline void CServerNetworkProperty::NetworkStateChanged( unsigned short varOffset ) +{ + // If we're using the timer, then ignore this call. + if ( m_TimerEvent.IsRegistered() ) + { + // If we're waiting for a timer event, then queue the change so it happens + // when the timer goes off. + m_bPendingStateChange = true; + } + else + { + if ( m_pPev ) + m_pPev->StateChanged( varOffset ); + } +} + +//----------------------------------------------------------------------------- +// Methods to get the entindex + edict +//----------------------------------------------------------------------------- +inline int CServerNetworkProperty::entindex() const +{ + return ENTINDEX( m_pPev ); +} + +inline edict_t* CServerNetworkProperty::GetEdict() const +{ + // This one's virtual, that's why we have to two other versions + return m_pPev; +} + +inline edict_t *CServerNetworkProperty::edict() +{ + return m_pPev; +} + +inline const edict_t *CServerNetworkProperty::edict() const +{ + return m_pPev; +} + + +//----------------------------------------------------------------------------- +// Sets the edict pointer (for swapping edicts) +//----------------------------------------------------------------------------- +inline void CServerNetworkProperty::SetEdict( edict_t *pEdict ) +{ + m_pPev = pEdict; +} + + +inline int CServerNetworkProperty::AreaNum() const +{ + const_cast(this)->RecomputePVSInformation(); + return m_PVSInfo.m_nAreaNum; +} + + +#endif // SERVERNETWORKPROPERTY_H diff --git a/game/server/SkyCamera.h b/game/server/SkyCamera.h new file mode 100644 index 0000000..8032d8f --- /dev/null +++ b/game/server/SkyCamera.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Resource collection entity +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SKYCAMERA_H +#define SKYCAMERA_H + +#ifdef _WIN32 +#pragma once +#endif + +class CSkyCamera; + +//============================================================================= +// +// Sky Camera Class +// +class CSkyCamera : public CLogicalEntity +{ + DECLARE_CLASS( CSkyCamera, CLogicalEntity ); + +public: + + DECLARE_DATADESC(); + CSkyCamera(); + ~CSkyCamera(); + virtual void Spawn( void ); + virtual void Activate(); + +public: + sky3dparams_t m_skyboxData; + bool m_bUseAngles; + CSkyCamera *m_pNext; +}; + + +//----------------------------------------------------------------------------- +// Retrives the current skycamera +//----------------------------------------------------------------------------- +CSkyCamera* GetCurrentSkyCamera(); +CSkyCamera* GetSkyCameraList(); + + +#endif // SKYCAMERA_H diff --git a/game/server/TemplateEntities.h b/game/server/TemplateEntities.h new file mode 100644 index 0000000..6d0fa1b --- /dev/null +++ b/game/server/TemplateEntities.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Template entities are used by spawners to create copies of entities +// that were configured by the level designer. This allows us to spawn +// entities with arbitrary sets of key/value data and entity I/O +// connections. +// +//=============================================================================// + +#ifndef TEMPLATEENTITIES_H +#define TEMPLATEENTITIES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isaverestore.h" + +class CBaseEntity; +class CPointTemplate; + +int Templates_Add(CBaseEntity *pEntity, const char *pszMapData, int nLen); +string_t Templates_FindByIndex( int iIndex ); +int Templates_GetStringSize( int iIndex ); +string_t Templates_FindByTargetName(const char *pszName); +void Templates_ReconnectIOForGroup( CPointTemplate *pGroup ); + +// Some templates have Entity I/O connecting the entities within the template. +// Unique versions of these templates need to be created whenever they're instanced. +void Templates_StartUniqueInstance( void ); +bool Templates_IndexRequiresEntityIOFixup( int iIndex ); +char *Templates_GetEntityIOFixedMapData( int iIndex ); + +// Save / Restore +ISaveRestoreBlockHandler *GetTemplateSaveRestoreBlockHandler( void ); + +#endif // TEMPLATEENTITIES_H diff --git a/game/server/actanimating.h b/game/server/actanimating.h new file mode 100644 index 0000000..5aa2b93 --- /dev/null +++ b/game/server/actanimating.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ACTANIMATING_H +#define ACTANIMATING_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseanimating.h" + +class CActAnimating : public CBaseAnimating +{ +public: + DECLARE_CLASS( CActAnimating, CBaseAnimating ); + + void SetActivity( Activity act ); + inline Activity GetActivity( void ) { return m_Activity; } + + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + DECLARE_DATADESC(); + +private: + Activity m_Activity; +}; + + + +#endif // ACTANIMATING_H diff --git a/game/server/ai_baseactor.h b/game/server/ai_baseactor.h new file mode 100644 index 0000000..49caea5 --- /dev/null +++ b/game/server/ai_baseactor.h @@ -0,0 +1,304 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hooks and classes for the support of humanoid NPCs with +// groovy facial animation capabilities, aka, "Actors" +// +//=============================================================================// + +#ifndef AI_BASEACTOR_H +#define AI_BASEACTOR_H + +#include "ai_basehumanoid.h" +#include "ai_speech.h" +#include "AI_Interest_Target.h" +#include + + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// CAI_BaseActor +// +// Purpose: The base class for all head/body/eye expressive NPCS. +// +//----------------------------------------------------------------------------- +enum PoseParameter_t { POSE_END=INT_MAX }; +enum FlexWeight_t { FLEX_END=INT_MAX }; + +struct AILookTargetArgs_t +{ + EHANDLE hTarget; + Vector vTarget; + float flDuration; + float flInfluence; + float flRamp; + bool bExcludePlayers; + CAI_InterestTarget *pQueue; +}; + +class CAI_BaseActor : public CAI_ExpresserHost +{ + DECLARE_CLASS( CAI_BaseActor, CAI_ExpresserHost ); + + //friend CPoseParameter; + //friend CFlexWeight; + +public: + + // FIXME: this method is lame, isn't there some sort of template thing that would get rid of the Outer pointer? + + void Init( PoseParameter_t &index, const char *szName ) { index = (PoseParameter_t)LookupPoseParameter( szName ); }; + void Set( PoseParameter_t index, float flValue ) { SetPoseParameter( (int)index, flValue ); } + float Get( PoseParameter_t index ) { return GetPoseParameter( (int)index ); } + + float ClampWithBias( PoseParameter_t index, float value, float base ); + + // Note, you must add all names to this static function in order for Init to work + static bool IsServerSideFlexController( char const *szName ); + + void Init( FlexWeight_t &index, const char *szName ) + { + // Make this fatal!!! + if ( !IsServerSideFlexController( szName ) ) + { + Error( "You forgot to add flex controller %s to list in CAI_BaseActor::IsServerSideFlexController().", szName ); + } + + index = (FlexWeight_t)FindFlexController( szName ); + } + void Set( FlexWeight_t index, float flValue ) { SetFlexWeight( (LocalFlexController_t)index, flValue ); } + float Get( FlexWeight_t index ) { return GetFlexWeight( (LocalFlexController_t)index ); } + + +public: + CAI_BaseActor() + : m_fLatchedPositions( 0 ), + m_latchedEyeOrigin( vec3_origin ), + m_latchedEyeDirection( vec3_origin ), + m_latchedHeadDirection( vec3_origin ), + m_flBlinktime( 0 ), + m_hLookTarget( NULL ), + m_iszExpressionScene( NULL_STRING ), + m_iszIdleExpression( NULL_STRING ), + m_iszAlertExpression( NULL_STRING ), + m_iszCombatExpression( NULL_STRING ), + m_iszDeathExpression( NULL_STRING ), + m_iszExpressionOverride( NULL_STRING ) + { + memset( m_flextarget, 0, 64 * sizeof( m_flextarget[0] ) ); + } + + ~CAI_BaseActor() + { + delete m_pExpresser; + } + + virtual void StudioFrameAdvance(); + + virtual void Precache(); + + virtual void SetModel( const char *szModelName ); + + virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + virtual bool ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled ); + virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + Vector EyePosition( ); + virtual Vector HeadDirection2D( void ); + virtual Vector HeadDirection3D( void ); + virtual Vector EyeDirection2D( void ); + virtual Vector EyeDirection3D( void ); + + CBaseEntity *GetLooktarget() { return m_hLookTarget.Get(); } + virtual void OnNewLookTarget() {}; + + // CBaseFlex + virtual void SetViewtarget( const Vector &viewtarget ); + + // CAI_BaseNPC + virtual float PickLookTarget( bool bExcludePlayers = false, float minTime = 1.5, float maxTime = 2.5 ); + virtual float PickLookTarget( CAI_InterestTarget &queue, bool bExcludePlayers = false, float minTime = 1.5, float maxTime = 2.5 ); + virtual bool PickTacticalLookTarget( AILookTargetArgs_t *pArgs ); + virtual bool PickRandomLookTarget( AILookTargetArgs_t *pArgs ); + virtual void MakeRandomLookTarget( AILookTargetArgs_t *pArgs, float minTime, float maxTime ); + virtual bool HasActiveLookTargets( void ); + virtual void OnSelectedLookTarget( AILookTargetArgs_t *pArgs ) { return; } + virtual void ClearLookTarget( CBaseEntity *pTarget ); + virtual void ExpireCurrentRandomLookTarget() { m_flNextRandomLookTime = gpGlobals->curtime - 0.1f; } + + virtual void StartTaskRangeAttack1( const Task_t *pTask ); + + virtual void AddLookTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual void AddLookTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ); + + virtual void SetHeadDirection( const Vector &vTargetPos, float flInterval ); + + void UpdateBodyControl( void ); + void UpdateHeadControl( const Vector &vHeadTarget, float flHeadInfluence ); + virtual float GetHeadDebounce( void ) { return 0.3; } // how much of previous head turn to use + + virtual void MaintainLookTargets( float flInterval ); + virtual bool ValidEyeTarget(const Vector &lookTargetPos); + virtual bool ValidHeadTarget(const Vector &lookTargetPos); + virtual float HeadTargetValidity(const Vector &lookTargetPos); + + virtual bool ShouldBruteForceFailedNav() { return true; } + + void AccumulateIdealYaw( float flYaw, float flIntensity ); + bool SetAccumulatedYawAndUpdate( void ); + + float m_flAccumYawDelta; + float m_flAccumYawScale; + + //--------------------------------- + + virtual void OnStateChange( NPC_STATE OldState, NPC_STATE NewState ); + + //--------------------------------- + + virtual void PlayExpressionForState( NPC_STATE state ); + virtual const char *SelectRandomExpressionForState( NPC_STATE state ); + + float SetExpression( const char * ); + void ClearExpression(); + const char * GetExpression(); + + enum + { + SCENE_AI_BLINK = 1, + SCENE_AI_HOLSTER, + SCENE_AI_UNHOLSTER, + SCENE_AI_AIM, + SCENE_AI_RANDOMLOOK, + SCENE_AI_RANDOMFACEFLEX, + SCENE_AI_RANDOMHEADFLEX, + SCENE_AI_IGNORECOLLISION, + SCENE_AI_DISABLEAI + }; + + + DECLARE_DATADESC(); +private: + enum + { + HUMANOID_LATCHED_EYE = 0x0001, + HUMANOID_LATCHED_HEAD = 0x0002, + HUMANOID_LATCHED_ALL = 0x0003, + }; + + //--------------------------------- + + void UpdateLatchedValues( void ); + + // Input handlers. + void InputSetExpressionOverride( inputdata_t &inputdata ); + + //--------------------------------- + + int m_fLatchedPositions; + Vector m_latchedEyeOrigin; + Vector m_latchedEyeDirection; // direction eyes are looking + Vector m_latchedHeadDirection; // direction head is aiming + + void ClearHeadAdjustment( void ); + Vector m_goalHeadDirection; + float m_goalHeadInfluence; + + //--------------------------------- + + float m_goalSpineYaw; + float m_goalBodyYaw; + Vector m_goalHeadCorrection; + + //--------------------------------- + + float m_flBlinktime; + EHANDLE m_hLookTarget; + CAI_InterestTarget m_lookQueue; + CAI_InterestTarget m_syntheticLookQueue; + + CAI_InterestTarget m_randomLookQueue; + float m_flNextRandomLookTime; // FIXME: move to scene + + //--------------------------------- + + string_t m_iszExpressionScene; + EHANDLE m_hExpressionSceneEnt; + float m_flNextRandomExpressionTime; + + string_t m_iszExpressionOverride; + +protected: + string_t m_iszIdleExpression; + string_t m_iszAlertExpression; + string_t m_iszCombatExpression; + string_t m_iszDeathExpression; + +private: + //--------------------------------- + + //PoseParameter_t m_ParameterBodyTransY; // "body_trans_Y" + //PoseParameter_t m_ParameterBodyTransX; // "body_trans_X" + //PoseParameter_t m_ParameterBodyLift; // "body_lift" + PoseParameter_t m_ParameterBodyYaw; // "body_yaw" + //PoseParameter_t m_ParameterBodyPitch; // "body_pitch" + //PoseParameter_t m_ParameterBodyRoll; // "body_roll" + PoseParameter_t m_ParameterSpineYaw; // "spine_yaw" + //PoseParameter_t m_ParameterSpinePitch; // "spine_pitch" + //PoseParameter_t m_ParameterSpineRoll; // "spine_roll" + PoseParameter_t m_ParameterNeckTrans; // "neck_trans" + PoseParameter_t m_ParameterHeadYaw; // "head_yaw" + PoseParameter_t m_ParameterHeadPitch; // "head_pitch" + PoseParameter_t m_ParameterHeadRoll; // "head_roll" + + //FlexWeight_t m_FlexweightMoveRightLeft; // "move_rightleft" + //FlexWeight_t m_FlexweightMoveForwardBack;// "move_forwardback" + //FlexWeight_t m_FlexweightMoveUpDown; // "move_updown" + FlexWeight_t m_FlexweightBodyRightLeft; // "body_rightleft" + //FlexWeight_t m_FlexweightBodyUpDown; // "body_updown" + //FlexWeight_t m_FlexweightBodyTilt; // "body_tilt" + FlexWeight_t m_FlexweightChestRightLeft; // "chest_rightleft" + //FlexWeight_t m_FlexweightChestUpDown; // "chest_updown" + //FlexWeight_t m_FlexweightChestTilt; // "chest_tilt" + FlexWeight_t m_FlexweightHeadForwardBack;// "head_forwardback" + FlexWeight_t m_FlexweightHeadRightLeft; // "head_rightleft" + FlexWeight_t m_FlexweightHeadUpDown; // "head_updown" + FlexWeight_t m_FlexweightHeadTilt; // "head_tilt" + + PoseParameter_t m_ParameterGestureHeight; // "gesture_height" + PoseParameter_t m_ParameterGestureWidth; // "gesture_width" + FlexWeight_t m_FlexweightGestureUpDown; // "gesture_updown" + FlexWeight_t m_FlexweightGestureRightLeft; // "gesture_rightleft" + +private: + //--------------------------------- + bool RandomFaceFlex( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool RandomHeadFlex( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + float m_flextarget[64]; + +public: + virtual bool UseSemaphore( void ); + +protected: + bool m_bDontUseSemaphore; + +public: + //--------------------------------- + // + // Speech support + // + virtual CAI_Expresser *GetExpresser(); + +protected: + bool CreateComponents(); + virtual CAI_Expresser *CreateExpresser(); +private: + //--------------------------------- + CAI_Expresser *m_pExpresser; +}; + +//----------------------------------------------------------------------------- +#endif // AI_BASEACTOR_H diff --git a/game/server/ai_basehumanoid.h b/game/server/ai_basehumanoid.h new file mode 100644 index 0000000..86da44a --- /dev/null +++ b/game/server/ai_basehumanoid.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_BASEHUMANOID_H +#define AI_BASEHUMANOID_H + +#include "ai_behavior.h" +#include "ai_blended_movement.h" + +//----------------------------------------------------------------------------- +// CLASS: CAI_BaseHumanoid +//----------------------------------------------------------------------------- + +typedef CAI_BlendingHost< CAI_BehaviorHost > CAI_BaseHumanoidBase; + +class CAI_BaseHumanoid : public CAI_BaseHumanoidBase +{ + DECLARE_CLASS( CAI_BaseHumanoid, CAI_BaseHumanoidBase ); + +public: + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + // Tasks + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + virtual void BuildScheduleTestBits( ); + + // Navigation + bool OnMoveBlocked( AIMoveResult_t *pResult ); + + // Damage + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + // Various start tasks + virtual void StartTaskRangeAttack1( const Task_t *pTask ); + + // Various run tasks + virtual void RunTaskRangeAttack1( const Task_t *pTask ); + + // Purpose: check ammo + virtual void CheckAmmo( void ); +}; + +//----------------------------------------------------------------------------- + +#endif diff --git a/game/server/ai_basenpc.h b/game/server/ai_basenpc.h new file mode 100644 index 0000000..7c65c0c --- /dev/null +++ b/game/server/ai_basenpc.h @@ -0,0 +1,3124 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base NPC character with AI +// +//=============================================================================// + +#ifndef AI_BASENPC_H +#define AI_BASENPC_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "simtimer.h" +#include "basecombatcharacter.h" +#include "ai_debug.h" +#include "ai_default.h" +#include "ai_schedule.h" +#include "ai_condition.h" +#include "ai_component.h" +#include "ai_task.h" +#include "ai_movetypes.h" +#include "ai_navtype.h" +#include "ai_namespaces.h" +#include "ai_npcstate.h" +#include "ai_hull.h" +#include "ai_utils.h" +#include "ai_moveshoot.h" +#include "entityoutput.h" +#include "utlvector.h" +#include "activitylist.h" +#include "bitstring.h" +#include "ai_basenpc.h" +#include "ai_navgoaltype.h" //GoalType_t enum +#include "eventlist.h" +#include "soundent.h" +#include "ai_navigator.h" +#include "tier1/functors.h" + + +#define PLAYER_SQUADNAME "player_squad" + +class CAI_Schedule; +class CAI_Network; +class CAI_Route; +class CAI_Hint; +class CAI_Node; +class CAI_Navigator; +class CAI_Pathfinder; +class CAI_Senses; +class CAI_Enemies; +class CAI_Squad; +class CAI_Expresser; +class CAI_BehaviorBase; +class CAI_GoalEntity; +class CAI_Motor; +class CAI_MoveProbe; +class CAI_LocalNavigator; +class CAI_TacticalServices; +class CVarBitVec; +class CAI_ScriptedSequence; +class CSceneEntity; +class CBaseGrenade; +class CBaseDoor; +class CBasePropDoor; +struct AI_Waypoint_t; +class AI_Response; +class CBaseFilter; + +typedef CBitVec CAI_ScheduleBits; + +// Used to control optimizations mostly dealing with pathfinding for NPCs +extern ConVar ai_strong_optimizations; + +extern bool AIStrongOpt( void ); + +// AI_MONITOR_FOR_OSCILLATION defaults to OFF. If you build with this ON, you can flag +// NPC's and monitor them to detect oscillations in their schedule (circular logic and conditions bugs) +// DO NOT SHIP WITH THIS ON! +#undef AI_MONITOR_FOR_OSCILLATION + +//============================================================================= +// +// Constants & enumerations +// +//============================================================================= +#define TURRET_CLOSE_RANGE 200 +#define TURRET_MEDIUM_RANGE 500 + +#define COMMAND_GOAL_TOLERANCE 48 // 48 inches. +#define TIME_CARE_ABOUT_DAMAGE 3.0 + +#define ITEM_PICKUP_TOLERANCE 48.0f + +// Max's of the box used to search for a weapon to pick up. 45x45x~8 ft. +#define WEAPON_SEARCH_DELTA Vector( 540, 540, 100 ) + +enum Interruptability_t +{ + GENERAL_INTERRUPTABILITY, + DAMAGEORDEATH_INTERRUPTABILITY, + DEATH_INTERRUPTABILITY +}; + +//------------------------------------- +// Memory +//------------------------------------- + +#define MEMORY_CLEAR 0 +#define bits_MEMORY_PROVOKED ( 1 << 0 )// right now only used for houndeyes. +#define bits_MEMORY_INCOVER ( 1 << 1 )// npc knows it is in a covered position. +#define bits_MEMORY_SUSPICIOUS ( 1 << 2 )// Ally is suspicious of the player, and will move to provoked more easily +#define bits_MEMORY_TASK_EXPENSIVE ( 1 << 3 )// NPC has completed a task which is considered costly, so don't do another task this frame +//#define bits_MEMORY_ ( 1 << 4 ) +#define bits_MEMORY_PATH_FAILED ( 1 << 5 )// Failed to find a path +#define bits_MEMORY_FLINCHED ( 1 << 6 )// Has already flinched +//#define bits_MEMORY_ ( 1 << 7 ) +#define bits_MEMORY_TOURGUIDE ( 1 << 8 )// I have been acting as a tourguide. +//#define bits_MEMORY_ ( 1 << 9 )// +#define bits_MEMORY_LOCKED_HINT ( 1 << 10 )// +//#define bits_MEMORY_ ( 1 << 12 ) + +#define bits_MEMORY_TURNING ( 1 << 13 )// Turning, don't interrupt me. +#define bits_MEMORY_TURNHACK ( 1 << 14 ) + +#define bits_MEMORY_HAD_ENEMY ( 1 << 15 )// Had an enemy +#define bits_MEMORY_HAD_PLAYER ( 1 << 16 )// Had player +#define bits_MEMORY_HAD_LOS ( 1 << 17 )// Had LOS to enemy + +#define bits_MEMORY_MOVED_FROM_SPAWN ( 1 << 18 )// Has moved since spawning. + +#define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // NPC-specific memory +#define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // NPC-specific memory +#define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // NPC-specific memory +#define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // NPC-specific memory + +//------------------------------------- +// Spawn flags +//------------------------------------- +#define SF_NPC_WAIT_TILL_SEEN ( 1 << 0 ) // spawnflag that makes npcs wait until player can see them before attacking. +#define SF_NPC_GAG ( 1 << 1 ) // no idle noises from this npc +#define SF_NPC_FALL_TO_GROUND ( 1 << 2 ) // used my NPC_Maker +#define SF_NPC_DROP_HEALTHKIT ( 1 << 3 ) // Drop a healthkit upon death +#define SF_NPC_START_EFFICIENT ( 1 << 4 ) // Set into efficiency mode from spawn +// ( 1 << 5 ) +// ( 1 << 6 ) +#define SF_NPC_WAIT_FOR_SCRIPT ( 1 << 7 ) // spawnflag that makes npcs wait to check for attacking until the script is done or they've been attacked +#define SF_NPC_LONG_RANGE ( 1 << 8 ) // makes npcs look far and relaxes weapon range limit +#define SF_NPC_FADE_CORPSE ( 1 << 9 ) // Fade out corpse after death +#define SF_NPC_ALWAYSTHINK ( 1 << 10 ) // Simulate even when player isn't in PVS. +#define SF_NPC_TEMPLATE ( 1 << 11 ) // This NPC will be used as a template by an npc_maker -- do not spawn. +#define SF_NPC_ALTCOLLISION ( 1 << 12 ) +#define SF_NPC_NO_WEAPON_DROP ( 1 << 13 ) // This NPC will not actually drop a weapon that can be picked up +#define SF_NPC_NO_PLAYER_PUSHAWAY ( 1 << 14 ) +// ( 1 << 15 ) +// !! Flags above ( 1 << 15 ) are reserved for NPC sub-classes + +//------------------------------------- +// +// Return codes from CanPlaySequence. +// +//------------------------------------- + +enum CanPlaySequence_t +{ + CANNOT_PLAY = 0, // Can't play for any number of reasons. + CAN_PLAY_NOW, // Can play the script immediately. + CAN_PLAY_ENQUEUED, // Can play the script after I finish playing my current script. +}; + +//------------------------------------- +// Weapon holstering +//------------------------------------- +enum DesiredWeaponState_t +{ + DESIREDWEAPONSTATE_IGNORE = 0, + DESIREDWEAPONSTATE_HOLSTERED, + DESIREDWEAPONSTATE_HOLSTERED_DESTROYED, // Put the weapon away, then destroy it. + DESIREDWEAPONSTATE_UNHOLSTERED, + DESIREDWEAPONSTATE_CHANGING, + DESIREDWEAPONSTATE_CHANGING_DESTROY, // Destroy the weapon when this change is complete. +}; + +//------------------------------------- +// +// Efficiency modes +// +//------------------------------------- + +enum AI_Efficiency_t +{ + // Run at full tilt + AIE_NORMAL, + + // Run decision process less often + AIE_EFFICIENT, + + // Run decision process even less often, ignore other NPCs + AIE_VERY_EFFICIENT, + + // Run decision process even less often, ignore other NPCs + AIE_SUPER_EFFICIENT, + + // Don't run at all + AIE_DORMANT, +}; + +enum AI_MoveEfficiency_t +{ + AIME_NORMAL, + AIME_EFFICIENT, +}; + +//------------------------------------- +// +// Sleep state +// +//------------------------------------- + +enum AI_SleepState_t +{ + AISS_AWAKE, + AISS_WAITING_FOR_THREAT, + AISS_WAITING_FOR_PVS, + AISS_WAITING_FOR_INPUT, + AISS_AUTO_PVS, + AISS_AUTO_PVS_AFTER_PVS, // Same as AUTO_PVS, except doesn't activate until/unless the NPC is IN the player's PVS. +}; + +#define AI_SLEEP_FLAGS_NONE 0x00000000 +#define AI_SLEEP_FLAG_AUTO_PVS 0x00000001 +#define AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS 0x00000002 + + +//------------------------------------- +// +// Debug bits +// +//------------------------------------- + +enum DebugBaseNPCBits_e +{ + bits_debugDisableAI = 0x00000001, // disable AI + bits_debugStepAI = 0x00000002, // step AI + +}; + +//------------------------------------- +// +// Base Sentence index for behaviors +// +//------------------------------------- +enum SentenceIndex_t +{ + SENTENCE_BASE_BEHAVIOR_INDEX = 1000, +}; + +#ifdef AI_MONITOR_FOR_OSCILLATION +struct AIScheduleChoice_t +{ + float m_flTimeSelected; + CAI_Schedule *m_pScheduleSelected; +}; +#endif//AI_MONITOR_FOR_OSCILLATION + +#define MARK_TASK_EXPENSIVE() \ + if ( GetOuter() ) \ + { \ + GetOuter()->Remember( bits_MEMORY_TASK_EXPENSIVE ); \ + } + +//============================================================================= +// +// Types used by CAI_BaseNPC +// +//============================================================================= + +struct AIScheduleState_t +{ + int iCurTask; + TaskStatus_e fTaskStatus; + float timeStarted; + float timeCurTaskStarted; + AI_TaskFailureCode_t taskFailureCode; + int iTaskInterrupt; + bool bTaskRanAutomovement; + bool bTaskUpdatedYaw; + bool bScheduleWasInterrupted; + + DECLARE_SIMPLE_DATADESC(); +}; + +// ----------------------------------------- +// An entity that this NPC can't reach +// ----------------------------------------- + +struct UnreachableEnt_t +{ + EHANDLE hUnreachableEnt; // Entity that's unreachable + float fExpireTime; // Time to forget this information + Vector vLocationWhenUnreachable; + + DECLARE_SIMPLE_DATADESC(); +}; + +//============================================================================= +// SCRIPTED NPC INTERACTIONS +//============================================================================= +// ----------------------------------------- +// Scripted NPC interaction flags +// ----------------------------------------- +#define SCNPC_FLAG_TEST_OTHER_ANGLES ( 1 << 1 ) +#define SCNPC_FLAG_TEST_OTHER_VELOCITY ( 1 << 2 ) +#define SCNPC_FLAG_LOOP_IN_ACTION ( 1 << 3 ) +#define SCNPC_FLAG_NEEDS_WEAPON_ME ( 1 << 4 ) +#define SCNPC_FLAG_NEEDS_WEAPON_THEM ( 1 << 5 ) +#define SCNPC_FLAG_DONT_TELEPORT_AT_END_ME ( 1 << 6 ) +#define SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM ( 1 << 7 ) + +// ----------------------------------------- +// Scripted NPC interaction trigger methods +// ----------------------------------------- +enum +{ + SNPCINT_CODE = 0, + SNPCINT_AUTOMATIC_IN_COMBAT = 1, +}; + +// ----------------------------------------- +// Scripted NPC interaction loop breaking trigger methods +// ----------------------------------------- +#define SNPCINT_LOOPBREAK_ON_DAMAGE ( 1 << 1 ) +#define SNPCINT_LOOPBREAK_ON_FLASHLIGHT_ILLUM ( 1 << 2 ) + +// ----------------------------------------- +// Scripted NPC interaction anim phases +// ----------------------------------------- +enum +{ + SNPCINT_ENTRY = 0, + SNPCINT_SEQUENCE, + SNPCINT_EXIT, + + SNPCINT_NUM_PHASES +}; + +struct ScriptedNPCInteraction_Phases_t +{ + string_t iszSequence; + int iActivity; + + DECLARE_SIMPLE_DATADESC(); +}; + +// Allowable delta from the desired dynamic scripted sequence point +#define DSS_MAX_DIST 6 +#define DSS_MAX_ANGLE_DIFF 4 + +// Interaction Logic States +enum +{ + NPCINT_NOT_RUNNING = 0, + NPCINT_RUNNING_ACTIVE, // I'm in an interaction that I initiated + NPCINT_RUNNING_PARTNER, // I'm in an interaction that was initiated by the other NPC + NPCINT_MOVING_TO_MARK, // I'm moving to a position to do an interaction +}; + +#define NPCINT_NONE -1 + +#define MAXTACLAT_IGNORE -1 + +// ----------------------------------------- +// A scripted interaction between NPCs +// ----------------------------------------- +struct ScriptedNPCInteraction_t +{ + ScriptedNPCInteraction_t() + { + iszInteractionName = NULL_STRING; + iFlags = 0; + iTriggerMethod = SNPCINT_CODE; + iLoopBreakTriggerMethod = 0; + vecRelativeOrigin = vec3_origin; + bValidOnCurrentEnemy = false; + flDelay = 5.0; + flDistSqr = (DSS_MAX_DIST * DSS_MAX_DIST); + flNextAttemptTime = 0; + iszMyWeapon = NULL_STRING; + iszTheirWeapon = NULL_STRING; + + for ( int i = 0; i < SNPCINT_NUM_PHASES; i++) + { + sPhases[i].iszSequence = NULL_STRING; + sPhases[i].iActivity = ACT_INVALID; + } + } + + // Fill out these when passing to AddScriptedNPCInteraction + string_t iszInteractionName; + int iFlags; + int iTriggerMethod; + int iLoopBreakTriggerMethod; + Vector vecRelativeOrigin; // (forward, right, up) + QAngle angRelativeAngles; + Vector vecRelativeVelocity; // Desired relative velocity of the other NPC + float flDelay; // Delay before interaction can be used again + float flDistSqr; // Max distance sqr from the relative origin the NPC is allowed to be to trigger + string_t iszMyWeapon; // Classname of the weapon I'm holding, if any + string_t iszTheirWeapon; // Classname of the weapon my interaction partner is holding, if any + ScriptedNPCInteraction_Phases_t sPhases[SNPCINT_NUM_PHASES]; + + // These will be filled out for you in AddScriptedNPCInteraction + VMatrix matDesiredLocalToWorld; // Desired relative position / angles of the other NPC + bool bValidOnCurrentEnemy; + + float flNextAttemptTime; + + DECLARE_SIMPLE_DATADESC(); +}; + +//============================================================================= +// +// Utility functions +// +//============================================================================= + +Vector VecCheckToss ( CBaseEntity *pEdict, Vector vecSpot1, Vector vecSpot2, float flHeightMaxRatio, float flGravityAdj, bool bRandomize, Vector *vecMins = NULL, Vector *vecMaxs = NULL ); +Vector VecCheckToss ( CBaseEntity *pEntity, ITraceFilter *pFilter, Vector vecSpot1, Vector vecSpot2, float flHeightMaxRatio, float flGravityAdj, bool bRandomize, Vector *vecMins = NULL, Vector *vecMaxs = NULL ); +Vector VecCheckThrow( CBaseEntity *pEdict, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0f, Vector *vecMins = NULL, Vector *vecMaxs = NULL ); + +extern Vector g_vecAttackDir; + +bool FBoxVisible ( CBaseEntity *pLooker, CBaseEntity *pTarget ); +bool FBoxVisible ( CBaseEntity *pLooker, CBaseEntity *pTarget, Vector &vecTargetOrigin, float flSize = 0.0 ); + +// FIXME: move to utils? +float DeltaV( float v0, float v1, float d ); +float ChangeDistance( float flInterval, float flGoalDistance, float flGoalVelocity, float flCurVelocity, float flIdealVelocity, float flAccelRate, float &flNewDistance, float &flNewVelocity ); + +//============================================================================= +// +// class CAI_Manager +// +// Central location for components of the AI to operate across all AIs without +// iterating over the global list of entities. +// +//============================================================================= + +class CAI_Manager +{ +public: + CAI_Manager(); + + CAI_BaseNPC ** AccessAIs(); + int NumAIs(); + + void AddAI( CAI_BaseNPC *pAI ); + void RemoveAI( CAI_BaseNPC *pAI ); + + bool FindAI( CAI_BaseNPC *pAI ) { return ( m_AIs.Find( pAI ) != m_AIs.InvalidIndex() ); } + +private: + enum + { + MAX_AIS = 256 + }; + + typedef CUtlVector CAIArray; + + CAIArray m_AIs; + +}; + +//------------------------------------- + +extern CAI_Manager g_AI_Manager; + +//============================================================================= +// +// class CAI_BaseNPC +// +//============================================================================= + +class CAI_BaseNPC : public CBaseCombatCharacter, + public CAI_DefMovementSink +{ + DECLARE_CLASS( CAI_BaseNPC, CBaseCombatCharacter ); + +public: + //----------------------------------------------------- + // + // Initialization, cleanup, serialization, identity + // + + CAI_BaseNPC(); + ~CAI_BaseNPC(); + + //--------------------------------- + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + virtual void OnRestore(); + void SaveConditions( ISave &save, const CAI_ScheduleBits &conditions ); + void RestoreConditions( IRestore &restore, CAI_ScheduleBits *pConditions ); + + bool ShouldSavePhysics() { return false; } + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + //--------------------------------- + + virtual void PostConstructor( const char *szClassname ); + virtual void Activate( void ); + virtual void Precache( void ); // derived calls at start of Spawn() + virtual bool CreateVPhysics(); + virtual void NPCInit( void ); // derived calls after Spawn() + void NPCInitThink( void ); + virtual void PostNPCInit() {};// called after NPC_InitThink + virtual void StartNPC( void ); + virtual bool IsTemplate( void ); + + virtual void CleanupOnDeath( CBaseEntity *pCulprit = NULL, bool bFireDeathOutput = true ); + virtual void UpdateOnRemove( void ); + + virtual int UpdateTransmitState(); + + //--------------------------------- + // Component creation factories + // + + // The master call, override if you introduce new component types. Call base first + virtual bool CreateComponents(); + + // Components defined by the base AI class + virtual CAI_Senses * CreateSenses(); + virtual CAI_MoveProbe * CreateMoveProbe(); + virtual CAI_Motor * CreateMotor(); + virtual CAI_LocalNavigator *CreateLocalNavigator(); + virtual CAI_Navigator * CreateNavigator(); + virtual CAI_Pathfinder *CreatePathfinder(); + virtual CAI_TacticalServices *CreateTacticalServices(); + + //--------------------------------- + + virtual bool IsNPC( void ) const { return true; } + + //--------------------------------- + + void TestPlayerPushing( CBaseEntity *pPlayer ); + void CascadePlayerPush( const Vector &push, const Vector &pushOrigin ); + void NotifyPushMove(); + +public: + //----------------------------------------------------- + // + // AI processing - thinking, schedule selection and task running + // + //----------------------------------------------------- + void CallNPCThink( void ); + + // Thinking, including core thinking, movement, animation + virtual void NPCThink( void ); + + // Core thinking (schedules & tasks) + virtual void RunAI( void );// core ai function! + + // Called to gather up all relevant conditons + virtual void GatherConditions( void ); + + // Called immediately prior to schedule processing + virtual void PrescheduleThink( void ); + + // Called immediately after schedule processing + virtual void PostscheduleThink( void ) { return; }; + + // Notification that the current schedule, if any, is ending and a new one is being selected + virtual void OnScheduleChange( void ); + + // Notification that a new schedule is about to run its first task + virtual void OnStartSchedule( int scheduleType ) {}; + + // This function implements a decision tree for the NPC. It is responsible for choosing the next behavior (schedule) + // based on the current conditions and state. + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + + // After the schedule has been selected, it will be processed by this function so child NPC classes can + // remap base schedules into child-specific behaviors + virtual int TranslateSchedule( int scheduleType ); + + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + + void ClearTransientConditions(); + + virtual void HandleAnimEvent( animevent_t *pEvent ); + + virtual bool IsInterruptable(); + virtual void OnStartScene( void ) {} // Called when an NPC begins a cine scene (useful for clean-up) + virtual bool ShouldPlayerAvoid( void ); + virtual void SetPlayerAvoidState( void ); + virtual void PlayerPenetratingVPhysics( void ); + + virtual bool ShouldAlwaysThink(); + void ForceGatherConditions() { m_bForceConditionsGather = true; SetEfficiency( AIE_NORMAL ); } // Force an NPC out of PVS to call GatherConditions on next think + + virtual float LineOfSightDist( const Vector &vecDir = vec3_invalid, float zEye = FLT_MAX ); + + virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + virtual const char *GetTracerType( void ); + virtual void DoImpactEffect( trace_t &tr, int nDamageType ); + + enum + { + NEXT_SCHEDULE = LAST_SHARED_SCHEDULE, + NEXT_TASK = LAST_SHARED_TASK, + NEXT_CONDITION = LAST_SHARED_CONDITION, + }; + +protected: + // Used by derived classes to chain a task to a task that might not be the + // one they are currently handling: + void ChainStartTask( int task, float taskData = 0 ) { Task_t tempTask = { task, taskData }; StartTask( (const Task_t *)&tempTask ); } + void ChainRunTask( int task, float taskData = 0 ) { Task_t tempTask = { task, taskData }; RunTask( (const Task_t *) &tempTask ); } + + void StartTaskOverlay(); + void RunTaskOverlay(); + void EndTaskOverlay(); + + virtual void PostRunStopMoving(); + + bool CheckPVSCondition(); + +private: + bool CanThinkRebalance(); + void RebalanceThinks(); + + bool PreNPCThink(); + void PostNPCThink(); + + bool PreThink( void ); + void PerformSensing(); + void CheckOnGround( void ); + void MaintainSchedule( void ); + void RunAnimation( void ); + void PostRun( void ); + void PerformMovement(); + void PostMovement(); + + virtual int StartTask ( Task_t *pTask ) { DevMsg( "Called wrong StartTask()\n" ); StartTask( (const Task_t *)pTask ); return 0; } // to ensure correct signature in derived classes + virtual int RunTask ( Task_t *pTask ) { DevMsg( "Called wrong RunTask()\n" ); RunTask( (const Task_t *)pTask ); return 0; } // to ensure correct signature in derived classes + +public: + //----------------------------------------------------- + // + // Schedules & tasks + // + //----------------------------------------------------- + + void SetSchedule( CAI_Schedule *pNewSchedule ); + bool SetSchedule( int localScheduleID ); + + void SetDefaultFailSchedule( int failSchedule ) { m_failSchedule = failSchedule; } + + void ClearSchedule( const char *szReason ); + + CAI_Schedule * GetCurSchedule() { return m_pSchedule; } + bool IsCurSchedule( int schedId, bool fIdeal = true ); + virtual CAI_Schedule *GetSchedule(int localScheduleID); + virtual int GetLocalScheduleId( int globalScheduleID ) { return AI_IdIsLocal( globalScheduleID ) ? globalScheduleID : GetClassScheduleIdSpace()->ScheduleGlobalToLocal( globalScheduleID ); } + virtual int GetGlobalScheduleId( int localScheduleID ) { return AI_IdIsGlobal( localScheduleID ) ? localScheduleID : GetClassScheduleIdSpace()->ScheduleLocalToGlobal( localScheduleID ); } + + float GetTimeScheduleStarted() const { return m_ScheduleState.timeStarted; } + + //--------------------------------- + + const Task_t* GetTask( void ); + int TaskIsRunning( void ); + + virtual void TaskFail( AI_TaskFailureCode_t ); + void TaskFail( const char *pszGeneralFailText ) { TaskFail( MakeFailCode( pszGeneralFailText ) ); } + void TaskComplete( bool fIgnoreSetFailedCondition = false ); + + void TaskInterrupt() { m_ScheduleState.iTaskInterrupt++; } + void ClearTaskInterrupt() { m_ScheduleState.iTaskInterrupt = 0; } + int GetTaskInterrupt() const { return m_ScheduleState.iTaskInterrupt; } + + void TaskMovementComplete( void ); + inline int TaskIsComplete( void ) { return (GetTaskStatus() == TASKSTATUS_COMPLETE); } + + virtual const char *TaskName(int taskID); + + float GetTimeTaskStarted() const { return m_ScheduleState.timeCurTaskStarted; } + virtual int GetLocalTaskId( int globalTaskId) { return GetClassScheduleIdSpace()->TaskGlobalToLocal( globalTaskId ); } + + virtual const char *GetSchedulingErrorName() { return "CAI_BaseNPC"; } + +protected: + static bool LoadSchedules(void); + virtual bool LoadedSchedules(void); + virtual void BuildScheduleTestBits( void ); + + //--------------------------------- + + // This is the main call to select/translate a schedule + virtual CAI_Schedule *GetNewSchedule( void ); + virtual CAI_Schedule *GetFailSchedule( void ); + + //--------------------------------- + + virtual bool CanFlinch( void ); + virtual void CheckFlinches( void ); + virtual void PlayFlinchGesture( void ); + int SelectFlinchSchedule( void ); + + virtual bool IsAllowedToDodge( void ); + + bool IsInChoreo() const; + +private: + // This function maps the type through TranslateSchedule() and then retrieves the pointer + // to the actual CAI_Schedule from the database of schedules available to this class. + CAI_Schedule * GetScheduleOfType( int scheduleType ); + + bool FHaveSchedule( void ); + bool FScheduleDone ( void ); + CAI_Schedule * ScheduleInList( const char *pName, CAI_Schedule **pList, int listCount ); + + int GetScheduleCurTaskIndex() const { return m_ScheduleState.iCurTask; } + inline int IncScheduleCurTaskIndex(); + inline void ResetScheduleCurTaskIndex(); + void NextScheduledTask ( void ); + bool IsScheduleValid ( void ); + bool ShouldSelectIdealState( void ); + + // Selecting the ideal state + NPC_STATE SelectIdleIdealState(); + NPC_STATE SelectAlertIdealState(); + NPC_STATE SelectScriptIdealState(); + + // Various schedule selections based on NPC_STATE + int SelectIdleSchedule(); + int SelectAlertSchedule(); + int SelectCombatSchedule(); + virtual int SelectDeadSchedule(); + int SelectScriptSchedule(); + int SelectInteractionSchedule(); + + void OnStartTask( void ) { SetTaskStatus( TASKSTATUS_RUN_MOVE_AND_TASK ); } + void SetTaskStatus( TaskStatus_e status ) { m_ScheduleState.fTaskStatus = status; } + TaskStatus_e GetTaskStatus() const { return m_ScheduleState.fTaskStatus; } + + void DiscardScheduleState(); + + //--------------------------------- + + CAI_Schedule * m_pSchedule; + int m_IdealSchedule; + AIScheduleState_t m_ScheduleState; + int m_failSchedule; // Schedule type to choose if current schedule fails + bool m_bDoPostRestoreRefindPath; + + bool m_bUsingStandardThinkTime; + float m_flLastRealThinkTime; + int m_iFrameBlocked; + bool m_bInChoreo; + + static int gm_iNextThinkRebalanceTick; + static float gm_flTimeLastSpawn; + static int gm_nSpawnedThisFrame; + +protected: // pose parameters + int m_poseAim_Pitch; + int m_poseAim_Yaw; + int m_poseMove_Yaw; + virtual void PopulatePoseParameters( void ); + +public: + inline bool HasPoseMoveYaw() { return ( m_poseMove_Yaw >= 0 ); } + + // Return the stored pose parameter for "move_yaw" + inline int LookupPoseMoveYaw() { return m_poseMove_Yaw; } + + + //----------------------------------------------------- + // + // Hooks for CAI_Behaviors, *if* derived class supports them + // + //----------------------------------------------------- + template + bool GetBehavior( BEHAVIOR_TYPE **ppBehavior ) + { + CAI_BehaviorBase **ppBehaviors = AccessBehaviors(); + + *ppBehavior = NULL; + for ( int i = 0; i < NumBehaviors(); i++ ) + { + *ppBehavior = dynamic_cast(ppBehaviors[i]); + if ( *ppBehavior ) + return true; + } + return false; + } + + virtual CAI_BehaviorBase *GetRunningBehavior() { return NULL; } + + virtual bool ShouldAcceptGoal( CAI_BehaviorBase *pBehavior, CAI_GoalEntity *pGoal ) { return true; } + virtual void OnClearGoal( CAI_BehaviorBase *pBehavior, CAI_GoalEntity *pGoal ) {} + + // Notification that the status behavior ability to select schedules has changed. + // Return "true" to signal a schedule interrupt is desired + virtual bool OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule ) { return false; } + +private: + virtual CAI_BehaviorBase ** AccessBehaviors() { return NULL; } + virtual int NumBehaviors() { return 0; } + +public: + //----------------------------------------------------- + // + // Conditions + // + //----------------------------------------------------- + + virtual const char* ConditionName(int conditionID); + + virtual void RemoveIgnoredConditions ( void ); + void SetCondition( int iCondition /*, bool state = true*/ ); + bool HasCondition( int iCondition ); + bool HasCondition( int iCondition, bool bUseIgnoreConditions ); + bool HasInterruptCondition( int iCondition ); + bool HasConditionsToInterruptSchedule( int nLocalScheduleID ); + + void ClearCondition( int iCondition ); + void ClearConditions( int *pConditions, int nConditions ); + void SetIgnoreConditions( int *pConditions, int nConditions ); + void ClearIgnoreConditions( int *pConditions, int nConditions ); + bool ConditionInterruptsCurSchedule( int iCondition ); + bool ConditionInterruptsSchedule( int schedule, int iCondition ); + + void SetCustomInterruptCondition( int nCondition ); + bool IsCustomInterruptConditionSet( int nCondition ); + void ClearCustomInterruptCondition( int nCondition ); + void ClearCustomInterruptConditions( void ); + + bool ConditionsGathered() const { return m_bConditionsGathered; } + const CAI_ScheduleBits &AccessConditionBits() const { return m_Conditions; } + CAI_ScheduleBits & AccessConditionBits() { return m_Conditions; } + + bool DidChooseEnemy() const { return !m_bSkippedChooseEnemy; } + +private: + CAI_ScheduleBits m_Conditions; + CAI_ScheduleBits m_CustomInterruptConditions; //Bit string assembled by the schedule running, then + //modified by leaf classes to suit their needs + CAI_ScheduleBits m_ConditionsPreIgnore; + CAI_ScheduleBits m_InverseIgnoreConditions; + + bool m_bForceConditionsGather; + bool m_bConditionsGathered; + bool m_bSkippedChooseEnemy; + +public: + //----------------------------------------------------- + // + // NPC State + // + //----------------------------------------------------- + inline void SetIdealState( NPC_STATE eIdealState ); + inline NPC_STATE GetIdealState(); + virtual NPC_STATE SelectIdealState( void ); + + void SetState( NPC_STATE State ); + virtual bool ShouldGoToIdleState( void ) { return ( false ); } + virtual void OnStateChange( NPC_STATE OldState, NPC_STATE NewState ) {/*Base class doesn't care*/}; + + NPC_STATE GetState( void ) { return m_NPCState; } + + AI_Efficiency_t GetEfficiency() const { return m_Efficiency; } + void SetEfficiency( AI_Efficiency_t efficiency ) { m_Efficiency = efficiency; } + AI_MoveEfficiency_t GetMoveEfficiency() const { return m_MoveEfficiency; } + void SetMoveEfficiency( AI_MoveEfficiency_t efficiency ) { m_MoveEfficiency = efficiency; } + virtual void UpdateEfficiency( bool bInPVS ); + void ForceDecisionThink() { m_flNextDecisionTime = 0; SetEfficiency( AIE_NORMAL ); } + + bool IsFlaggedEfficient() const { return HasSpawnFlags( SF_NPC_START_EFFICIENT ); } + + AI_SleepState_t GetSleepState() const { return m_SleepState; } + void SetSleepState( AI_SleepState_t sleepState ) { m_SleepState = sleepState; } + void AddSleepFlags( int flags ) { m_SleepFlags |= flags; } + void RemoveSleepFlags( int flags ) { m_SleepFlags &= ~flags; } + bool HasSleepFlags( int flags ) { return (m_SleepFlags & flags) == flags; } + + void UpdateSleepState( bool bInPVS ); + virtual void Wake( bool bFireOutput = true ); + void Sleep(); + bool WokeThisTick() const; + + //--------------------------------- + + NPC_STATE m_NPCState; // npc's current state + float m_flLastStateChangeTime; + +private: + NPC_STATE m_IdealNPCState; // npc should change to this state + AI_Efficiency_t m_Efficiency; + AI_MoveEfficiency_t m_MoveEfficiency; + float m_flNextDecisionTime; + + AI_SleepState_t m_SleepState; + int m_SleepFlags; + float m_flWakeRadius; + bool m_bWakeSquad; + int m_nWakeTick; + +public: + //----------------------------------------------------- + // + // Activities + // + //----------------------------------------------------- + + Activity TranslateActivity( Activity idealActivity, Activity *pIdealWeaponActivity = NULL ); + Activity NPC_TranslateActivity( Activity eNewActivity ); + Activity GetActivity( void ) { return m_Activity; } + virtual void SetActivity( Activity NewActivity ); + Activity GetIdealActivity( void ) { return m_IdealActivity; } + void SetIdealActivity( Activity NewActivity ); + void ResetIdealActivity( Activity newIdealActivity ); + void SetSequenceByName( const char *szSequence ); + void SetSequenceById( int iSequence ); + Activity GetScriptCustomMoveActivity( void ); + int GetScriptCustomMoveSequence( void ); + Activity GetStoppedActivity( void ); + inline bool HaveSequenceForActivity( Activity activity ); + inline bool IsActivityStarted(void); + virtual bool IsActivityFinished( void ); + virtual bool IsActivityMovementPhased( Activity activity ); + virtual void OnChangeActivity( Activity eNewActivity ); + void MaintainActivity(void); + void ResetActivity(void) { m_Activity = ACT_RESET; } + + void SetActivityAndSequence(Activity NewActivity, int iSequence, Activity translatedActivity, Activity weaponActivity); + +private: + + void AdvanceToIdealActivity(void); + void ResolveActivityToSequence(Activity NewActivity, int &iSequence, Activity &translatedActivity, Activity &weaponActivity); + + Activity m_Activity; // Current animation state + Activity m_translatedActivity; // Current actual translated animation + + Activity m_IdealActivity; // Desired animation state + int m_nIdealSequence; // Desired animation sequence + Activity m_IdealTranslatedActivity; // Desired actual translated animation state + Activity m_IdealWeaponActivity; // Desired weapon animation state + + CNetworkVar(int, m_iDeathPose ); + CNetworkVar(int, m_iDeathFrame ); + +public: + //----------------------------------------------------- + // + // Senses + // + //----------------------------------------------------- + + CAI_Senses * GetSenses() { return m_pSenses; } + const CAI_Senses * GetSenses() const { return m_pSenses; } + + void SetDistLook( float flDistLook ); + + virtual bool QueryHearSound( CSound *pSound ); + virtual bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false ); + + virtual void OnLooked( int iDistance ); + virtual void OnListened(); + + virtual void OnSeeEntity( CBaseEntity *pEntity ) {} + + // If true, AI will try to see this entity regardless of distance. + virtual bool ShouldNotDistanceCull() { return false; } + + virtual int GetSoundInterests( void ); + virtual int GetSoundPriority( CSound *pSound ); + + CSound * GetLoudestSoundOfType( int iType ); + virtual CSound * GetBestSound( int validTypes = ALL_SOUNDS ); + virtual CSound * GetBestScent( void ); + virtual float HearingSensitivity( void ) { return 1.0; } + virtual bool ShouldIgnoreSound( CSound * ) { return false; } + bool SoundIsVisible( CSound *pSound ); + +protected: + virtual void ClearSenseConditions( void ); + +private: + void LockBestSound(); + void UnlockBestSound(); + + CAI_Senses * m_pSenses; + CSound * m_pLockedBestSound; + +public: + //----------------------------------------------------- + // + // Enemy and target + // + //----------------------------------------------------- + + Vector GetSmoothedVelocity( void ); + + CBaseEntity* GetEnemy() { return m_hEnemy.Get(); } + CBaseEntity* GetEnemy() const { return m_hEnemy.Get(); } + float GetTimeEnemyAcquired() { return m_flTimeEnemyAcquired; } + void SetEnemy( CBaseEntity *pEnemy, bool bSetCondNewEnemy = true ); + + const Vector & GetEnemyLKP() const; + float GetEnemyLastTimeSeen() const; + void MarkEnemyAsEluded(); + void ClearEnemyMemory(); + bool EnemyHasEludedMe() const; + + virtual CBaseEntity *BestEnemy(); // returns best enemy in memory list + virtual bool IsValidEnemy( CBaseEntity *pEnemy ); + virtual bool CanBeAnEnemyOf( CBaseEntity *pEnemy ); + + void ForceChooseNewEnemy() { m_EnemiesSerialNumber = -1; } + + bool ChooseEnemy(); + virtual bool ShouldChooseNewEnemy(); + virtual void GatherEnemyConditions( CBaseEntity *pEnemy ); + virtual float EnemyDistTolerance() { return 0; } // Enemy distances within this tolerance of each other are considered equivalent. + + float EnemyDistance( CBaseEntity *pEnemy ); + CBaseCombatCharacter *GetEnemyCombatCharacterPointer(); + void SetEnemyOccluder(CBaseEntity *pBlocker); + CBaseEntity *GetEnemyOccluder(void); + + virtual void StartTargetHandling( CBaseEntity *pTargetEnt ); + + //--------------------------------- + + CBaseEntity* GetTarget() { return m_hTargetEnt.Get(); } + void SetTarget( CBaseEntity *pTarget ); + void CheckTarget( CBaseEntity *pTarget ); + float GetAcceptableTimeSeenEnemy( void ) { return m_flAcceptableTimeSeenEnemy; } + virtual CAI_BaseNPC *CreateCustomTarget( const Vector &vecOrigin, float duration = -1 ); + + void SetDeathPose( const int &iDeathPose ) { m_iDeathPose = iDeathPose; } + void SetDeathPoseFrame( const int &iDeathPoseFrame ) { m_iDeathFrame = iDeathPoseFrame; } + + void SelectDeathPose( const CTakeDamageInfo &info ); + virtual bool ShouldPickADeathPose( void ) { return true; } + + virtual bool AllowedToIgnite( void ) { return false; } + +protected: + virtual float GetGoalRepathTolerance( CBaseEntity *pGoalEnt, GoalType_t type, const Vector &curGoal, const Vector &curTargetPos ); + +private: + void * CheckEnemy( CBaseEntity *pEnemy ) { return NULL; } // OBSOLETE, replaced by GatherEnemyConditions(), left here to make derived code not compile + + // Updates the goal position in case of GOALTYPE_ENEMY + void UpdateEnemyPos(); + + // Updates the goal position in case of GOALTYPE_TARGETENT + void UpdateTargetPos(); + + //--------------------------------- + + EHANDLE m_hEnemy; // the entity that the npc is fighting. + float m_flTimeEnemyAcquired; // The time at which the entity the NPC is fighting became the NPC's enemy. + EHANDLE m_hTargetEnt; // the entity that the npc is trying to reach + + CRandStopwatch m_GiveUpOnDeadEnemyTimer; + CSimpleSimTimer m_FailChooseEnemyTimer; + int m_EnemiesSerialNumber; + + float m_flAcceptableTimeSeenEnemy; + + CSimpleSimTimer m_UpdateEnemyPosTimer; + static CSimpleSimTimer m_AnyUpdateEnemyPosTimer; + +public: + //----------------------------------------------------- + // + // Commander mode stuff. + // + //----------------------------------------------------- + virtual bool IsCommandable() { return false; } + virtual bool IsPlayerAlly( CBasePlayer *pPlayer = NULL ); + virtual bool IsMedic() { return false; } + virtual bool IsCommandMoving() { return false; } + virtual bool ShouldAutoSummon() { return false; } + virtual void SetCommandGoal( const Vector &vecGoal ); + virtual void ClearCommandGoal(); + virtual void OnTargetOrder() {} + virtual void OnMoveOrder() {} + virtual bool IsValidCommandTarget( CBaseEntity *pTarget ) { return false; } + const Vector &GetCommandGoal() const { return m_vecCommandGoal; } + virtual void OnMoveToCommandGoalFailed() {} + string_t GetPlayerSquadName() const { Assert( gm_iszPlayerSquad != NULL_STRING ); return gm_iszPlayerSquad; } + bool IsInPlayerSquad() const; + virtual CAI_BaseNPC *GetSquadCommandRepresentative() { return NULL; } + + virtual bool TargetOrder( CBaseEntity *pTarget, CAI_BaseNPC **Allies, int numAllies ) { OnTargetOrder(); return true; } + virtual void MoveOrder( const Vector &vecDest, CAI_BaseNPC **Allies, int numAllies ) { SetCommandGoal( vecDest ); SetCondition( COND_RECEIVED_ORDERS ); OnMoveOrder(); } + + // Return true if you're willing to be idly talked to by other friends. + virtual bool CanBeUsedAsAFriend( void ); + + +private: + Vector m_vecCommandGoal; + static string_t gm_iszPlayerSquad; + +public: + CAI_MoveMonitor m_CommandMoveMonitor; + + //----------------------------------------------------- + // Dynamic scripted NPC interactions + //----------------------------------------------------- +public: + float GetInteractionYaw( void ) const { return m_flInteractionYaw; } + +protected: + void ParseScriptedNPCInteractions( void ); + void AddScriptedNPCInteraction( ScriptedNPCInteraction_t *pInteraction ); + const char *GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase ); + void StartRunningInteraction( CAI_BaseNPC *pOtherNPC, bool bActive ); + void StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedNPCInteraction_t *pInteraction, Vector vecOtherOrigin, QAngle angOtherAngles ); + void CheckForScriptedNPCInteractions( void ); + void CalculateValidEnemyInteractions( void ); + void CheckForcedNPCInteractions( void ); + bool InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInteraction_t *pInteraction, Vector &vecOrigin, QAngle &angAngles ); + virtual bool CanRunAScriptedNPCInteraction( bool bForced = false ); + bool IsRunningDynamicInteraction( void ) { return (m_iInteractionState != NPCINT_NOT_RUNNING && (m_hCine != NULL)); } + bool IsActiveDynamicInteraction( void ) { return (m_iInteractionState == NPCINT_RUNNING_ACTIVE && (m_hCine != NULL)); } + ScriptedNPCInteraction_t *GetRunningDynamicInteraction( void ) { return &(m_ScriptedInteractions[m_iInteractionPlaying]); } + void SetInteractionCantDie( bool bCantDie ) { m_bCannotDieDuringInteraction = bCantDie; } + bool HasInteractionCantDie( void ); + + void InputForceInteractionWithNPC( inputdata_t &inputdata ); + void StartForcedInteraction( CAI_BaseNPC *pNPC, int iInteraction ); + void CleanupForcedInteraction( void ); + void CalculateForcedInteractionPosition( void ); + CAI_BaseNPC *GetInteractionPartner( void ); + +private: + // Forced interactions + CHandle m_hForcedInteractionPartner; + Vector m_vecForcedWorldPosition; + float m_flForcedInteractionTimeout; // Abort the interaction if it hasn't started by this time. + + CHandle m_hInteractionPartner; + EHANDLE m_hLastInteractionTestTarget; + bool m_bCannotDieDuringInteraction; + int m_iInteractionState; + int m_iInteractionPlaying; + CUtlVector m_ScriptedInteractions; + + float m_flInteractionYaw; + + +public: + //----------------------------------------------------- + // + // Sounds + // + //----------------------------------------------------- + virtual CanPlaySequence_t CanPlaySequence( bool fDisregardState, int interruptLevel ); + + virtual bool CanPlaySentence( bool fDisregardState ) { return IsAlive(); } + virtual int PlaySentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, CBaseEntity *pListener = NULL ); + virtual int PlayScriptedSentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, bool bConcurrent, CBaseEntity *pListener ); + + virtual bool FOkToMakeSound( int soundPriority = 0 ); + virtual void JustMadeSound( int soundPriority = 0, float flSoundLength = 0.0f ); + + virtual void DeathSound( const CTakeDamageInfo &info ) { return; }; + virtual void AlertSound( void ) { return; }; + virtual void IdleSound( void ) { return; }; + virtual void PainSound( const CTakeDamageInfo &info ) { return; }; + virtual void FearSound( void ) { return; }; + virtual void LostEnemySound( void ) { return; }; + virtual void FoundEnemySound( void ) { return; }; + virtual void BarnacleDeathSound( void ) { CTakeDamageInfo info; PainSound( info ); } + + virtual void SpeakSentence( int sentenceType ) { return; }; + virtual bool ShouldPlayIdleSound( void ); + + virtual void MakeAIFootstepSound( float volume, float duration = 0.5f ); + + //--------------------------------- + + virtual CAI_Expresser *GetExpresser() { return NULL; } + const CAI_Expresser *GetExpresser() const { return const_cast(this)->GetExpresser(); } + + //--------------------------------- + // NPC Event Response System + virtual bool CanRespondToEvent( const char *ResponseConcept ) { return false; } + virtual bool RespondedTo( const char *ResponseConcept, bool bForce, bool bCancelScene ) { return false; } + + virtual void PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot ); + + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + +protected: + float SoundWaitTime() const { return m_flSoundWaitTime; } + +public: + //----------------------------------------------------- + // + // Capabilities report (from CBaseCombatCharacter) + // + //----------------------------------------------------- + virtual int CapabilitiesGet( void ) const; + + // local capabilities access + int CapabilitiesAdd( int capabilities ); + int CapabilitiesRemove( int capabilities ); + void CapabilitiesClear( void ); + +private: + int m_afCapability; // tells us what a npc can/can't do. + +public: + //----------------------------------------------------- + // + // Pathfinding, navigation & movement + // + //----------------------------------------------------- + + CAI_Navigator * GetNavigator() { return m_pNavigator; } + const CAI_Navigator *GetNavigator() const { return m_pNavigator; } + + CAI_LocalNavigator *GetLocalNavigator() { return m_pLocalNavigator; } + const CAI_LocalNavigator *GetLocalNavigator() const { return m_pLocalNavigator; } + + CAI_Pathfinder * GetPathfinder() { return m_pPathfinder; } + const CAI_Pathfinder *GetPathfinder() const { return m_pPathfinder; } + + CAI_MoveProbe * GetMoveProbe() { return m_pMoveProbe; } + const CAI_MoveProbe *GetMoveProbe() const { return m_pMoveProbe; } + + CAI_Motor * GetMotor() { return m_pMotor; } + const CAI_Motor * GetMotor() const { return m_pMotor; } + + //--------------------------------- + + static bool FindSpotForNPCInRadius( Vector *pResult, const Vector &vStartPos, CAI_BaseNPC *pNPC, float radius, bool bOutOfPlayerViewcone = false ); + + //--------------------------------- + + virtual bool IsNavigationUrgent(); + virtual bool ShouldFailNav( bool bMovementFailed ); + virtual bool ShouldBruteForceFailedNav() { return false; } + + // The current navigation (movement) mode (e.g. fly, swim, locomote, etc) + Navigation_t GetNavType() const; + void SetNavType( Navigation_t navType ); + + CBaseEntity * GetNavTargetEntity(void); + + bool IsMoving( void ); + virtual float GetTimeToNavGoal(); + + // NPCs can override this to tweak with how costly particular movements are + virtual bool MovementCost( int moveType, const Vector &vecStart, const Vector &vecEnd, float *pCost ); + + // Turns a directional vector into a yaw value that points down that vector. + float VecToYaw( const Vector &vecDir ); + + // Turning + virtual float CalcIdealYaw( const Vector &vecTarget ); + virtual float MaxYawSpeed( void ); // Get max yaw speed + bool FacingIdeal( void ); + void SetUpdatedYaw() { m_ScheduleState.bTaskUpdatedYaw = true; } + + // Add multiple facing goals while moving/standing still. + virtual void AddFacingTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual void AddFacingTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual void AddFacingTarget( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual float GetFacingDirection( Vector &vecDir ); + + // ------------ + // Methods used by motor to query properties/preferences/move-related state + // ------------ + virtual bool CanStandOn( CBaseEntity *pSurface ) const; + + virtual bool IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const; // Override for specific creature types + bool IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos, float maxUp, float maxDown, float maxDist ) const; + bool ShouldMoveWait(); + virtual float StepHeight() const { return 18.0f; } + float GetStepDownMultiplier() const; + virtual float GetMaxJumpSpeed() const { return 350.0f; } + virtual float GetJumpGravity() const { return 1.0f; } + + //--------------------------------- + + virtual bool OverrideMove( float flInterval ); // Override to take total control of movement (return true if done so) + virtual bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + + //--------------------------------- + + virtual bool IsUnusableNode(int iNodeID, CAI_Hint *pHint); // Override for special NPC behavior + virtual bool ValidateNavGoal(); + virtual bool IsCurTaskContinuousMove(); + virtual bool IsValidMoveAwayDest( const Vector &vecDest ) { return true; } + + //--------------------------------- + // + // Notifications from navigator + // + virtual void OnMovementFailed() {}; + virtual void OnMovementComplete() {}; + + //--------------------------------- + + bool FindNearestValidGoalPos( const Vector &vTestPoint, Vector *pResult ); + + void RememberUnreachable( CBaseEntity* pEntity, float duration = -1 ); // Remember that entity is unreachable + virtual bool IsUnreachable( CBaseEntity* pEntity ); // Is entity is unreachable? + + //--------------------------------- + // Inherited from IAI_MotorMovementServices + virtual float CalcYawSpeed( void ); + + virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + + virtual bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + + // Translations of the above into some useful game terms + virtual bool OnObstructingDoor( AILocalMoveGoal_t *pMoveGoal, + CBaseDoor *pDoor, + float distClear, + AIMoveResult_t *pResult ); + + virtual bool OnUpcomingPropDoor( AILocalMoveGoal_t *pMoveGoal, + CBasePropDoor *pDoor, + float distClear, + AIMoveResult_t *pResult ); + + void OpenPropDoorBegin( CBasePropDoor *pDoor ); + void OpenPropDoorNow( CBasePropDoor *pDoor ); + + //--------------------------------- + + void DelayMoveStart( float delay ) { m_flMoveWaitFinished = gpGlobals->curtime + delay; } + + float m_flMoveWaitFinished; + + + // + // Stuff for opening doors. + // + void OnDoorFullyOpen(CBasePropDoor *pDoor); + void OnDoorBlocked(CBasePropDoor *pDoor); + CHandle m_hOpeningDoor; // The CBasePropDoor that we are in the midst of opening for navigation. + +protected: + // BRJ 4/11 + // Semi-obsolete-looking Lars code I moved out of the engine and into here + int FlyMove( const Vector& vecPosition, unsigned int mask ); + int WalkMove( const Vector& vecPosition, unsigned int mask ); + + // Unreachable Entities + CUtlVector m_UnreachableEnts; // Array of unreachable entities + +private: + CAI_Navigator * m_pNavigator; + CAI_LocalNavigator *m_pLocalNavigator; + CAI_Pathfinder * m_pPathfinder; + CAI_MoveProbe * m_pMoveProbe; + CAI_Motor * m_pMotor; + + EHANDLE m_hGoalEnt; // path corner we are heading towards + + float m_flTimeLastMovement; + + + CSimpleSimTimer m_CheckOnGroundTimer; + +public: + //----------------------------------------------------- + // + // Eye position, view offset, head direction, eye direction + // + //----------------------------------------------------- + + void SetDefaultEyeOffset ( void ); + const Vector & GetDefaultEyeOffset( void ) { return m_vDefaultEyeOffset; } + virtual Vector GetNodeViewOffset() { return GetViewOffset(); } + + virtual Vector EyeOffset( Activity nActivity ); + virtual Vector EyePosition( void ); + + //--------------------------------- + + virtual Vector HeadDirection2D( void ); + virtual Vector HeadDirection3D( void ); + virtual Vector EyeDirection2D( void ); + virtual Vector EyeDirection3D( void ); + + virtual CBaseEntity *EyeLookTarget( void ); // Overridden by subclass to force look at an entity + virtual void AddLookTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp = 0.0 ) { }; + virtual void AddLookTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ) { }; + virtual void SetHeadDirection( const Vector &vTargetPos, float flInterval ); + virtual void MaintainLookTargets( float flInterval ); + virtual bool ValidEyeTarget(const Vector &lookTargetPos); + + virtual Vector FacingPosition( void ) { return EyePosition(); }; // position that other npc's use when facing you + + virtual void MaintainTurnActivity( void ); + + virtual bool FInAimCone( const Vector &vecSpot ); + virtual void AimGun(); + virtual void SetAim( const Vector &aimDir ); + virtual void RelaxAim( void ); + virtual CBaseEntity *GetAlternateMoveShootTarget() { return NULL; } + +protected: + Vector m_vDefaultEyeOffset; + float m_flNextEyeLookTime; // Next time a pick a new place to look + + float m_flEyeIntegRate; // How fast does eye move to target + +private: + Vector m_vEyeLookTarget; // Where I want to be looking + Vector m_vCurEyeTarget; // Direction I'm looking at + EHANDLE m_hEyeLookTarget; // What I want to be looking at + float m_flHeadYaw; // Current head yaw + float m_flHeadPitch; // Current head pitch +protected: + float m_flOriginalYaw; // This is the direction facing when the level designer placed the NPC in the level. + +public: + //----------------------------------------------------- + // Mapmaker Scripting + // + // Set when the NPC is being scripted by a mapmaker, and + // shouldn't be responding to external stimuli that would + // break him out of his "script". NOT a scripted sequence. + //----------------------------------------------------- + inline bool IsInAScript( void ) { return m_bInAScript; } + inline void SetInAScript( bool bScript ) { m_bInAScript = bScript; } + void InputStartScripting( inputdata_t &inputdata ) { m_bInAScript = true; } + void InputStopScripting( inputdata_t &inputdata ) { m_bInAScript = false; } + + void InputGagEnable( inputdata_t &inputdata ) { AddSpawnFlags(SF_NPC_GAG); } + void InputGagDisable( inputdata_t &inputdata ) { RemoveSpawnFlags(SF_NPC_GAG); } + + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + virtual void InputOutsideTransition( inputdata_t &inputdata ); + virtual void InputInsideTransition( inputdata_t &inputdata ); + + void CleanupScriptsOnTeleport( bool bEnrouteAsWell ); + + virtual void SetScriptedScheduleIgnoreConditions( Interruptability_t interrupt ); + +private: + bool m_bInAScript; + +public: + //----------------------------------------------------- + // + // Scripting + // + //----------------------------------------------------- + + // Scripted sequence Info + enum SCRIPTSTATE + { + SCRIPT_PLAYING = 0, // Playing the action animation. + SCRIPT_WAIT, // Waiting on everyone in the script to be ready. Plays the pre idle animation if there is one. + SCRIPT_POST_IDLE, // Playing the post idle animation after playing the action animation. + SCRIPT_CLEANUP, // Cancelling the script / cleaning up. + SCRIPT_WALK_TO_MARK, // Walking to the scripted sequence position. + SCRIPT_RUN_TO_MARK, // Running to the scripted sequence position. + SCRIPT_CUSTOM_MOVE_TO_MARK, // Moving to the scripted sequence position while playing a custom movement animation. + }; + + bool ExitScriptedSequence(); + bool CineCleanup(); + + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + + // forces movement and sets a new schedule + virtual bool ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity ); + virtual bool ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity ); + + static void ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun); + static void ForceSelectedGoRandom(void); + + bool AutoMovement( CBaseEntity *pTarget = NULL, AIMoveTrace_t *pTraceResult = NULL ); + bool AutoMovement( float flInterval, CBaseEntity *pTarget = NULL, AIMoveTrace_t *pTraceResult = NULL ); + bool TaskRanAutomovement( void ) { return m_ScheduleState.bTaskRanAutomovement; } + + SCRIPTSTATE m_scriptState; // internal cinematic state + CHandle m_hCine; + Activity m_ScriptArrivalActivity; + string_t m_strScriptArrivalSequence; + + //----------------------------------------------------- + // + // Scenes + // + //----------------------------------------------------- + + void AddSceneLock( float flDuration = 0.2f ) { m_flSceneTime = MAX( gpGlobals->curtime + flDuration, m_flSceneTime ); }; + void ClearSceneLock( float flDuration = 0.2f ) { m_flSceneTime = gpGlobals->curtime + flDuration; }; + bool IsInLockedScene( void ) { return m_flSceneTime > gpGlobals->curtime; }; + float m_flSceneTime; + string_t m_iszSceneCustomMoveSeq; + +public: + //----------------------------------------------------- + // + // Memory + // + //----------------------------------------------------- + + inline void Remember( int iMemory ) { m_afMemory |= iMemory; } + inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } + inline bool HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } + inline bool HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } + + virtual CAI_Enemies *GetEnemies( void ); + virtual void RemoveMemory( void ); + + virtual bool UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position, CBaseEntity *pInformer = NULL ); + virtual float GetReactionDelay( CBaseEntity *pEnemy ); + + void SetLastAttackTime( float time) { m_flLastAttackTime = time; } + + float GetLastAttackTime() const { return m_flLastAttackTime; } + float GetLastDamageTime() const { return m_flLastDamageTime; } + float GetLastPlayerDamageTime() const { return m_flLastPlayerDamageTime; } + float GetLastEnemyTime() const { return m_flLastEnemyTime; } + + // Set up the shot regulator based on the equipped weapon + virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + + // Weapon holstering + virtual bool CanHolsterWeapon( void ); + virtual int HolsterWeapon( void ); + virtual int UnholsterWeapon( void ); + void InputHolsterWeapon( inputdata_t &inputdata ); + void InputHolsterAndDestroyWeapon( inputdata_t &inputdata ); + void InputUnholsterWeapon( inputdata_t &inputdata ); + bool IsWeaponHolstered( void ); + bool IsWeaponStateChanging( void ); + void SetDesiredWeaponState( DesiredWeaponState_t iState ) { m_iDesiredWeaponState = iState; } + + // NOTE: The Shot Regulator is used to manage the RangeAttack1 weapon. + inline CAI_ShotRegulator* GetShotRegulator() { return &m_ShotRegulator; } + virtual void OnRangeAttack1(); + +protected: + // Shot regulator code + virtual void OnUpdateShotRegulator( ); + +protected: + CAI_Enemies * m_pEnemies; // Holds information about enemies / danger positions / shared between sqaud members + int m_afMemory; + EHANDLE m_hEnemyOccluder; // The entity my enemy is hiding behind. + + float m_flSumDamage; // How much consecutive damage I've received + float m_flLastDamageTime; // Last time I received damage + float m_flLastPlayerDamageTime; // Last time I received damage from the player + float m_flLastSawPlayerTime; // Last time I saw the player + float m_flLastAttackTime; // Last time that I attacked my current enemy + float m_flLastEnemyTime; + float m_flNextWeaponSearchTime; // next time to search for a better weapon + string_t m_iszPendingWeapon; // THe NPC should create and equip this weapon. + bool m_bIgnoreUnseenEnemies; + +private: + CAI_ShotRegulator m_ShotRegulator; // When should I shoot next? + + DesiredWeaponState_t m_iDesiredWeaponState; + +public: + //----------------------------------------------------- + // + // Squads & tactics + // + //----------------------------------------------------- + + virtual bool InitSquad( void ); + + virtual const char* SquadSlotName(int slotID) { return gm_SquadSlotNamespace.IdToSymbol(slotID); } + bool OccupyStrategySlot( int squadSlotID ); + bool OccupyStrategySlotRange( int slotIDStart, int slotIDEnd ); + bool HasStrategySlot( int squadSlotID ); + bool HasStrategySlotRange( int slotIDStart, int slotIDEnd ); + int GetMyStrategySlot() { return m_iMySquadSlot; } + void VacateStrategySlot( void ); + bool IsStrategySlotRangeOccupied( int slotIDStart, int slotIDEnd ); // Returns true if all in the range are occupied + + CAI_Squad * GetSquad() { return m_pSquad; } + virtual void SetSquad( CAI_Squad *pSquad ); + void AddToSquad( string_t name ); + void RemoveFromSquad(); + void CheckSquad(); + void SetSquadName( string_t name ) { m_SquadName = name; } + bool IsInSquad() const { return m_pSquad != NULL; } + virtual bool IsSilentSquadMember() const { return false; } + + int NumWeaponsInSquad( const char *pszWeaponClassname ); + + string_t GetHintGroup( void ) { return m_strHintGroup; } + void ClearHintGroup( void ) { SetHintGroup( NULL_STRING ); } + void SetHintGroup( string_t name, bool bHintGroupNavLimiting = false ); + bool IsLimitingHintGroups( void ) { return m_bHintGroupNavLimiting; } + + //--------------------------------- + + CAI_TacticalServices *GetTacticalServices() { return m_pTacticalServices; } + const CAI_TacticalServices *GetTacticalServices() const { return m_pTacticalServices; } + + //--------------------------------- + // Cover + + virtual bool FindCoverPos( CBaseEntity *pEntity, Vector *pResult ); + virtual bool FindCoverPosInRadius( CBaseEntity *pEntity, const Vector &goalPos, float coverRadius, Vector *pResult ); + virtual bool FindCoverPos( CSound *pSound, Vector *pResult ); + virtual bool IsValidCover ( const Vector &vecCoverLocation, CAI_Hint const *pHint ); + virtual bool IsValidShootPosition ( const Vector &vecCoverLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + virtual bool TestShootPosition(const Vector &vecShootPos, const Vector &targetPos ) { return WeaponLOSCondition( vecShootPos, targetPos, false ); } + virtual bool IsCoverPosition( const Vector &vecThreat, const Vector &vecPosition ); + virtual float CoverRadius( void ) { return 1024; } // Default cover radius + virtual float GetMaxTacticalLateralMovement( void ) { return MAXTACLAT_IGNORE; } + +protected: + virtual void OnChangeHintGroup( string_t oldGroup, string_t newGroup ) {} + + CAI_Squad * m_pSquad; // The squad that I'm on + string_t m_SquadName; + + int m_iMySquadSlot; // this is the behaviour slot that the npc currently holds in the squad. + +private: + string_t m_strHintGroup; + bool m_bHintGroupNavLimiting; + CAI_TacticalServices *m_pTacticalServices; + +public: + //----------------------------------------------------- + // + // Base schedule & task support; Miscellaneous + // + //----------------------------------------------------- + + void InitRelationshipTable( void ); + void AddRelationship( const char *pszRelationship, CBaseEntity *pActivator ); + + virtual void AddEntityRelationship( CBaseEntity *pEntity, Disposition_t nDisposition, int nPriority ); + virtual void AddClassRelationship( Class_T nClass, Disposition_t nDisposition, int nPriority ); + + void NPCUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + CBaseGrenade* IncomingGrenade(void); + + virtual bool ShouldFadeOnDeath( void ); + + void NPCInitDead( void ); // Call after animation/pose is set up + void CorpseFallThink( void ); + + float ThrowLimit( const Vector &vecStart, const Vector &vecEnd, float fGravity, float fArcSize, const Vector &mins, const Vector &maxs, CBaseEntity *pTarget, Vector *jumpVel, CBaseEntity **pBlocker); + + // these functions will survey conditions and set appropriate conditions bits for attack types. + virtual int RangeAttack1Conditions( float flDot, float flDist ); + virtual int RangeAttack2Conditions( float flDot, float flDist ); + virtual int MeleeAttack1Conditions( float flDot, float flDist ); + virtual int MeleeAttack2Conditions( float flDot, float flDist ); + + virtual float InnateRange1MinRange( void ) { return 0.0f; } + virtual float InnateRange1MaxRange( void ) { return FLT_MAX; } + + virtual bool OnBeginMoveAndShoot( void ) { return true; } + virtual void OnEndMoveAndShoot( void ) {} + + virtual bool UseAttackSquadSlots() { return false; } + + //--------------------------------- + + virtual CBaseEntity *FindNamedEntity( const char *pszName, IEntityFindFilter *pFilter = NULL ); + + //--------------------------------- + // States + //--------------------------------- + + virtual void ClearAttackConditions( void ); + void GatherAttackConditions( CBaseEntity *pTarget, float flDist ); + virtual bool ShouldLookForBetterWeapon(); + bool Weapon_IsBetterAvailable ( void ) ; + virtual Vector Weapon_ShootPosition( void ); + virtual void GiveWeapon( string_t iszWeaponName ); + virtual void OnGivenWeapon( CBaseCombatWeapon *pNewWeapon ) { } + bool IsMovingToPickupWeapon(); + virtual bool WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions); + virtual bool CurrentWeaponLOSCondition(const Vector &targetPos, bool bSetConditions) { return WeaponLOSCondition( GetAbsOrigin(), targetPos, bSetConditions ); } + virtual bool IsWaitingToRappel( void ) { return false; } + virtual void BeginRappel() {} + + // override to change the chase location of an enemy + // This is where your origin should go when you are chasing pEnemy when his origin is at chasePosition + // by default, leave this alone to make your origin coincide with his. + virtual void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition); + virtual float GetDefaultNavGoalTolerance() { return (GetHullWidth() * 2.0); } + + virtual bool FCanCheckAttacks ( void ); + virtual void CheckAmmo( void ) {} + + virtual bool FValidateHintType( CAI_Hint *pHint ); + virtual Activity GetHintActivity( short sHintType, Activity HintsActivity ); + virtual float GetHintDelay( short sHintType ); + virtual Activity GetCoverActivity( CAI_Hint* pHint ); + virtual Activity GetReloadActivity( CAI_Hint* pHint ); + + virtual void SetTurnActivity( void ); + bool UpdateTurnGesture( void ); + + // Returns the time when the door will be open + float OpenDoorAndWait( CBaseEntity *pDoor ); + + bool BBoxFlat( void ); + + //--------------------------------- + + virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false ); + virtual bool PassesDamageFilter( const CTakeDamageInfo &info ); + + //--------------------------------- + + void MakeDamageBloodDecal( int cCount, float flNoise, trace_t *ptr, Vector vecDir ); + virtual float GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + void DecalTrace( trace_t *pTrace, char const *decalName ); + void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + virtual bool PlayerInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter, bool ignoreHatedPlayers = true ); + CBaseEntity * PlayerInRange( const Vector &vecLocation, float flDist ); + bool PointInSpread( CBaseCombatCharacter *pCheckEntity, const Vector &sourcePos, const Vector &targetPos, const Vector &testPoint, float flSpread, float maxDistOffCenter ); + bool IsSquadmateInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter ); + + //--------------------------------- + // combat functions + //--------------------------------- + virtual bool InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + + virtual Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture ); + + virtual bool Event_Gibbed( const CTakeDamageInfo &info ); + virtual void Event_Killed( const CTakeDamageInfo &info ); + + virtual Vector GetShootEnemyDir( const Vector &shootOrigin, bool bNoisy = true ); +#ifdef HL2_DLL + virtual Vector GetActualShootPosition( const Vector &shootOrigin ); + virtual Vector GetActualShootTrajectory( const Vector &shootOrigin ); + virtual Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL ); + virtual float GetSpreadBias( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ); +#endif //HL2_DLL + virtual void CollectShotStats( const Vector &vecShootOrigin, const Vector &vecShootDir ); + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + virtual Vector GetAutoAimCenter() { return BodyTarget(vec3_origin, false); } + virtual void FireBullets( const FireBulletsInfo_t &info ); + + // OLD VERSION! Use the struct version + void FireBullets( int cShots, const Vector &vecSrc, const Vector &vecDirShooting, + const Vector &vecSpread, float flDistance, int iAmmoType, int iTracerFreq = 4, + int firingEntID = -1, int attachmentID = -1, int iDamage = 0, + CBaseEntity *pAttacker = NULL, bool bFirstShotAccurate = false ); + + virtual bool ShouldMoveAndShoot( void ); + + //--------------------------------- + // Damage + //--------------------------------- + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual int OnTakeDamage_Dying( const CTakeDamageInfo &info ); + virtual int OnTakeDamage_Dead( const CTakeDamageInfo &info ); + + virtual void NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity ); + virtual void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + + virtual bool IsLightDamage( const CTakeDamageInfo &info ); + virtual bool IsHeavyDamage( const CTakeDamageInfo &info ); + + void DoRadiusDamage( const CTakeDamageInfo &info, int iClassIgnore, CBaseEntity *pEntityIgnore ); + void DoRadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, int iClassIgnore, CBaseEntity *pEntityIgnore ); + + //--------------------------------- + + virtual void PickupWeapon( CBaseCombatWeapon *pWeapon ); + virtual void PickupItem( CBaseEntity *pItem ) { }; + CBaseEntity* DropItem( const char *pszItemName, Vector vecPos, QAngle vecAng );// drop an item. + + + //--------------------------------- + // Inputs + //--------------------------------- + void InputSetRelationship( inputdata_t &inputdata ); + void InputSetEnemyFilter( inputdata_t &inputdata ); + void InputSetHealth( inputdata_t &inputdata ); + void InputBeginRappel( inputdata_t &inputdata ); + void InputSetSquad( inputdata_t &inputdata ); + void InputWake( inputdata_t &inputdata ); + void InputForgetEntity( inputdata_t &inputdata ); + void InputIgnoreDangerSounds( inputdata_t &inputdata ); + void InputUpdateEnemyMemory( inputdata_t &inputdata ); + + //--------------------------------- + + virtual void NotifyDeadFriend( CBaseEntity *pFriend ) { return; } + + //--------------------------------- + // Utility methods + static Vector CalcThrowVelocity(const Vector &startPos, const Vector &endPos, float fGravity, float fArcSize); + + //--------------------------------- + + float SetWait( float minWait, float maxWait = 0.0 ); + void ClearWait(); + float GetWaitFinishTime() { return m_flWaitFinished; } + bool IsWaitFinished(); + bool IsWaitSet(); + + CBaseEntity* GetGoalEnt() { return m_hGoalEnt; } + void SetGoalEnt( CBaseEntity *pGoalEnt ) { m_hGoalEnt.Set( pGoalEnt ); } + + CAI_Hint *GetHintNode() { return m_pHintNode; } + const CAI_Hint *GetHintNode() const { return m_pHintNode; } + void SetHintNode( CAI_Hint *pHintNode ); + void ClearHintNode( float reuseDelay = 0.0 ); + + float m_flWaitFinished; // if we're told to wait, this is the time that the wait will be over. + + float m_flNextFlinchTime; // Time at which we'll flinch fully again (as opposed to just doing gesture flinches) + float m_flNextDodgeTime; // Time at which I can dodge again. Used so that the behavior doesn't happen over and over. + + CAI_MoveAndShootOverlay m_MoveAndShootOverlay; + + Vector m_vecLastPosition; // npc sometimes wants to return to where it started after an operation. + Vector m_vSavePosition; // position stored by code that called this schedules + Vector m_vInterruptSavePosition; // position stored by a task that was interrupted + +private: + CHandle m_pHintNode; // this is the hint that the npc is moving towards or performing active idle on. + +public: + int m_cAmmoLoaded; // how much ammo is in the weapon (used to trigger reload anim sequences) + float m_flDistTooFar; // if enemy farther away than this, bits_COND_ENEMY_TOOFAR set in GatherEnemyConditions + string_t m_spawnEquipment; + + bool m_fNoDamageDecal; + + EHANDLE m_hStoredPathTarget; // For TASK_SET_GOAL + Vector m_vecStoredPathGoal; // + GoalType_t m_nStoredPathType; // + int m_fStoredPathFlags; // + + CHandle m_hEnemyFilter; + string_t m_iszEnemyFilterName; + + bool m_bDidDeathCleanup; + + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_lifeState ); + + //--------------------------------- + // Outputs + //--------------------------------- + COutputEvent m_OnDamaged; + COutputEvent m_OnDeath; + COutputEvent m_OnHalfHealth; + COutputEHANDLE m_OnFoundEnemy; + COutputEvent m_OnLostEnemyLOS; + COutputEvent m_OnLostEnemy; + COutputEHANDLE m_OnFoundPlayer; + COutputEvent m_OnLostPlayerLOS; + COutputEvent m_OnLostPlayer; + COutputEvent m_OnHearWorld; + COutputEvent m_OnHearPlayer; + COutputEvent m_OnHearCombat; + COutputEvent m_OnDamagedByPlayer; + COutputEvent m_OnDamagedByPlayerSquad; + COutputEvent m_OnDenyCommanderUse; + COutputEvent m_OnRappelTouchdown; + COutputEvent m_OnSleep; + COutputEvent m_OnWake; + COutputEvent m_OnForcedInteractionStarted; + COutputEvent m_OnForcedInteractionAborted; + COutputEvent m_OnForcedInteractionFinished; + +public: + // use this to shrink the bbox temporarily + void SetHullSizeNormal( bool force = false ); + bool SetHullSizeSmall( bool force = false ); + + bool IsUsingSmallHull() const { return m_fIsUsingSmallHull; } + + const Vector & GetHullMins() const { return NAI_Hull::Mins(GetHullType()); } + const Vector & GetHullMaxs() const { return NAI_Hull::Maxs(GetHullType()); } + float GetHullWidth() const { return NAI_Hull::Width(GetHullType()); } + float GetHullHeight() const { return NAI_Hull::Height(GetHullType()); } + + void SetupVPhysicsHull(); + virtual void StartTouch( CBaseEntity *pOther ); + void CheckPhysicsContacts(); + +private: + void TryRestoreHull( void ); + bool m_fIsUsingSmallHull; + bool m_bCheckContacts; + +private: + // Task implementation helpers + void StartTurn( float flDeltaYaw ); + bool FindCoverFromEnemy( bool bNodesOnly = false, float flMinDistance = 0, float flMaxDistance = FLT_MAX ); + bool FindCoverFromBestSound( Vector *pCoverPos ); + void StartScriptMoveToTargetTask( int task ); + + void RunDieTask(); + void RunAttackTask( int task ); + +protected: + virtual float CalcReasonableFacing( bool bIgnoreOriginalFacing = false ); + virtual bool IsValidReasonableFacing( const Vector &vecSightDir, float sightDist ) { return true; } + virtual float GetReasonableFacingDist( void ); + +public: + inline int UsableNPCObjectCaps( int baseCaps ) + { + if ( IsAlive() ) + baseCaps |= FCAP_IMPULSE_USE; + return baseCaps; + } + + virtual int ObjectCaps() { return (BaseClass::ObjectCaps() | FCAP_NOTIFY_ON_TRANSITION); } + + //----------------------------------------------------- + // + // Core mapped data structures + // + // String Registries for default AI Shared by all CBaseNPCs + // These are used only during initialization and in debug + //----------------------------------------------------- + + static void InitSchedulingTables(); + + static CAI_GlobalScheduleNamespace *GetSchedulingSymbols() { return &gm_SchedulingSymbols; } + static CAI_ClassScheduleIdSpace &AccessClassScheduleIdSpaceDirect() { return gm_ClassScheduleIdSpace; } + virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace() { return &gm_ClassScheduleIdSpace; } + + static int GetScheduleID (const char* schedName); + static int GetActivityID (const char* actName); + static int GetConditionID (const char* condName); + static int GetTaskID (const char* taskName); + static int GetSquadSlotID (const char* slotName); + virtual const char* GetSquadSlotDebugName( int iSquadSlot ); + static const char* GetActivityName (int actID); + + static void AddActivityToSR(const char *actName, int conID); + + static void AddEventToSR(const char *eventName, int conID); + static const char* GetEventName (int actID); + static int GetEventID (const char* actName); + +public: + //----------------------------------------------------- + // Crouch handling + //----------------------------------------------------- + bool CrouchIsDesired( void ) const; + virtual bool IsCrouching( void ); + inline void ForceCrouch( void ); + inline void ClearForceCrouch( void ); + +protected: + virtual bool Crouch( void ); + virtual bool Stand( void ); + virtual void DesireCrouch( void ); + inline void DesireStand( void ); + bool CouldShootIfCrouching( CBaseEntity *pTarget ); + virtual bool IsCrouchedActivity( Activity activity ); + +protected: + // Override these in your derived NPC class + virtual Vector GetCrouchEyeOffset( void ) { return Vector(0,0,40); } + virtual Vector GetCrouchGunOffset( void ) { return Vector(0,0,36); } + +private: + bool m_bCrouchDesired; + bool m_bForceCrouch; + bool m_bIsCrouching; + //----------------------------------------------------- + + //----------------------------------------------------- + // ai_post_frame_navigation + //----------------------------------------------------- + +private: + bool m_bDeferredNavigation; // This NPCs has a navigation query that's being deferred until later in the frame + +public: + void SetNavigationDeferred( bool bState ) { m_bDeferredNavigation = bState; } + bool IsNavigationDeferred( void ) { return m_bDeferredNavigation; } + + //----------------------------------------------------- +protected: + static CAI_GlobalNamespace gm_SquadSlotNamespace; + static CAI_LocalIdSpace gm_SquadSlotIdSpace; + +private: + // Checks to see that the nav hull is valid for the NPC + bool IsNavHullValid() const; + + friend class CAI_SystemHook; + friend class CAI_SchedulesManager; + + static bool LoadDefaultSchedules(void); + + static void InitDefaultScheduleSR(void); + static void InitDefaultTaskSR(void); + static void InitDefaultConditionSR(void); + static void InitDefaultActivitySR(void); + static void InitDefaultSquadSlotSR(void); + + static CStringRegistry* m_pActivitySR; + static int m_iNumActivities; + + static CStringRegistry* m_pEventSR; + static int m_iNumEvents; + + static CAI_GlobalScheduleNamespace gm_SchedulingSymbols; + static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace; + +public: + //---------------------------------------------------- + // Debugging tools + // + + // ----------------------------- + // Debuging Fields and Methods + // ----------------------------- + const char* m_failText; // Text of why it failed + const char* m_interruptText; // Text of why schedule interrupted + CAI_Schedule* m_failedSchedule; // The schedule that failed last + CAI_Schedule* m_interuptSchedule; // The schedule that was interrupted last + int m_nDebugCurIndex; // Index used for stepping through AI + virtual void ReportAIState( void ); + virtual void ReportOverThinkLimit( float time ); + void DumpTaskTimings(); + void DrawDebugGeometryOverlays(void); + virtual int DrawDebugTextOverlays(void); + void ToggleFreeze(void); + + static void ClearAllSchedules(void); + + static int m_nDebugBits; + + static CAI_BaseNPC* m_pDebugNPC; + static int m_nDebugPauseIndex; // Current step + static inline void SetDebugNPC( CAI_BaseNPC *pNPC ) { m_pDebugNPC = pNPC; } + static inline bool IsDebugNPC( CAI_BaseNPC *pNPC ) { return( pNPC == m_pDebugNPC ); } + + float m_LastShootAccuracy; + int m_TotalShots; + int m_TotalHits; +#ifdef _DEBUG + bool m_bSelected; +#endif + + float m_flSoundWaitTime; // Time when I'm allowed to make another sound + int m_nSoundPriority; + float m_flIgnoreDangerSoundsUntil; + +#ifdef AI_MONITOR_FOR_OSCILLATION + CUtlVector m_ScheduleHistory; +#endif//AI_MONITOR_FOR_OSCILLATION + +private: + + // Break into pieces! + void Break( CBaseEntity *pBreaker ); + void InputBreak( inputdata_t &inputdata ); + + friend void CC_NPC_Go(); + friend void CC_NPC_GoRandom(); + friend void CC_NPC_Freeze( const CCommand &args ); + +public: + + CNetworkVar( bool, m_bPerformAvoidance ); + CNetworkVar( bool, m_bIsMoving ); + CNetworkVar( bool, m_bFadeCorpse ); + CNetworkVar( bool, m_bImportanRagdoll ); + + CNetworkVar( bool, m_bSpeedModActive ); + CNetworkVar( int, m_iSpeedModRadius ); + CNetworkVar( int, m_iSpeedModSpeed ); + CNetworkVar( float, m_flTimePingEffect ); // Display the pinged effect until this time + + void InputActivateSpeedModifier( inputdata_t &inputdata ) { m_bSpeedModActive = true; } + void InputDisableSpeedModifier( inputdata_t &inputdata ) { m_bSpeedModActive = false; } + void InputSetSpeedModifierRadius( inputdata_t &inputdata ); + void InputSetSpeedModifierSpeed( inputdata_t &inputdata ); + + virtual bool ShouldProbeCollideAgainstEntity( CBaseEntity *pEntity ); + + bool m_bPlayerAvoidState; + void GetPlayerAvoidBounds( Vector *pMins, Vector *pMaxs ); + + void StartPingEffect( void ) { m_flTimePingEffect = gpGlobals->curtime + 2.0f; DispatchUpdateTransmitState(); } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Returns whether our ideal activity has started. If not, we are in +// a transition sequence. +//----------------------------------------------------------------------------- +inline bool CAI_BaseNPC::IsActivityStarted(void) +{ + return (GetSequence() == m_nIdealSequence); +} + +//----------------------------------------------------------------------------- +// Bullet firing (legacy)... +//----------------------------------------------------------------------------- +inline void CAI_BaseNPC::FireBullets( int cShots, const Vector &vecSrc, + const Vector &vecDirShooting, const Vector &vecSpread, float flDistance, + int iAmmoType, int iTracerFreq, int firingEntID, int attachmentID, + int iDamage, CBaseEntity *pAttacker, bool bFirstShotAccurate ) +{ + FireBulletsInfo_t info; + info.m_iShots = cShots; + info.m_vecSrc = vecSrc; + info.m_vecDirShooting = vecDirShooting; + info.m_vecSpread = vecSpread; + info.m_flDistance = flDistance; + info.m_iAmmoType = iAmmoType; + info.m_iTracerFreq = iTracerFreq; + info.m_flDamage = iDamage; + info.m_pAttacker = pAttacker; + info.m_nFlags = bFirstShotAccurate ? FIRE_BULLETS_FIRST_SHOT_ACCURATE : 0; + + FireBullets( info ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the ideal state of this NPC. +//----------------------------------------------------------------------------- +inline void CAI_BaseNPC::SetIdealState( NPC_STATE eIdealState ) +{ + if (eIdealState != m_IdealNPCState) + { + /*switch (eIdealState) + { + case NPC_STATE_NONE: + Msg("%s.SetIdealState: NPC_STATE_NONE\n", GetDebugName()); + break; + + case NPC_STATE_IDLE: + Msg("%s.SetIdealState: NPC_STATE_IDLE\n", GetDebugName()); + break; + + case NPC_STATE_ALERT: + Msg("%s.SetIdealState: NPC_STATE_ALERT\n", GetDebugName()); + break; + + case NPC_STATE_COMBAT: + Msg("%s.SetIdealState: NPC_STATE_COMBAT\n", GetDebugName()); + break; + + case NPC_STATE_SCRIPT: + Msg("%s.SetIdealState: NPC_STATE_SCRIPT\n", GetDebugName()); + break; + + case NPC_STATE_PLAYDEAD: + Msg("%s.SetIdealState: NPC_STATE_PLAYDEAD\n", GetDebugName()); + break; + + case NPC_STATE_PRONE: + Msg("%s.SetIdealState: NPC_STATE_PRONE\n", GetDebugName()); + break; + + case NPC_STATE_DEAD: + Msg("%s.SetIdealState: NPC_STATE_DEAD\n", GetDebugName()); + break; + + default: + Msg("%s.SetIdealState: \n", GetDebugName()); + break; + }*/ + + m_IdealNPCState = eIdealState; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the current ideal state the NPC will try to achieve. +//----------------------------------------------------------------------------- +inline NPC_STATE CAI_BaseNPC::GetIdealState() +{ + return m_IdealNPCState; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CAI_BaseNPC::IncScheduleCurTaskIndex() +{ + m_ScheduleState.iTaskInterrupt = 0; + m_ScheduleState.bTaskRanAutomovement = false; + m_ScheduleState.bTaskUpdatedYaw = false; + return ++m_ScheduleState.iCurTask; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CAI_BaseNPC::ResetScheduleCurTaskIndex() +{ + m_ScheduleState.iCurTask = 0; + m_ScheduleState.iTaskInterrupt = 0; + m_ScheduleState.bTaskRanAutomovement = false; + m_ScheduleState.bTaskUpdatedYaw = false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline bool CAI_BaseNPC::CrouchIsDesired( void ) const +{ + return ( (CapabilitiesGet() & bits_CAP_DUCK) && (m_bCrouchDesired | m_bForceCrouch) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CAI_BaseNPC::DesireStand( void ) +{ + m_bCrouchDesired = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CAI_BaseNPC::ForceCrouch( void ) +{ + m_bForceCrouch = true; + Crouch(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CAI_BaseNPC::ClearForceCrouch( void ) +{ + m_bForceCrouch = false; + + if ( IsCrouching() ) + { + Stand(); + } +} + +inline bool CAI_BaseNPC::HaveSequenceForActivity( Activity activity ) +{ +#if STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW + return ( (GetModelPtr()) ? (SelectWeightedSequence( activity ) != ACTIVITY_NOT_AVAILABLE) : false ); +#else + return ( (GetModelPtr()) ? GetModelPtr()->HaveSequenceForActivity(activity) : false ); +#endif +} + +typedef CHandle AIHANDLE; + + +// ============================================================================ +// Macros for introducing new schedules in sub-classes +// +// Strings registries and schedules use unique ID's for each item, but +// sub-class enumerations are non-unique, so we translate between the +// enumerations and unique ID's +// ============================================================================ + +#define AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( derivedClass ) \ + IMPLEMENT_CUSTOM_SCHEDULE_PROVIDER(derivedClass ) \ + void derivedClass::InitCustomSchedules( void ) \ + { \ + typedef derivedClass CNpc; \ + const char *pszClassName = #derivedClass; \ + \ + CUtlVector schedulesToLoad; \ + CUtlVector reqiredOthers; \ + CAI_NamespaceInfos scheduleIds; \ + CAI_NamespaceInfos taskIds; \ + CAI_NamespaceInfos conditionIds; + + +//----------------- + +#define AI_BEGIN_CUSTOM_NPC( className, derivedClass ) \ + IMPLEMENT_CUSTOM_AI(className, derivedClass ) \ + void derivedClass::InitCustomSchedules( void ) \ + { \ + typedef derivedClass CNpc; \ + const char *pszClassName = #derivedClass; \ + \ + CUtlVector schedulesToLoad; \ + CUtlVector reqiredOthers; \ + CAI_NamespaceInfos scheduleIds; \ + CAI_NamespaceInfos taskIds; \ + CAI_NamespaceInfos conditionIds; \ + CAI_NamespaceInfos squadSlotIds; + +//----------------- + +#define EXTERN_SCHEDULE( id ) \ + scheduleIds.PushBack( #id, id ); \ + extern const char * g_psz##id; \ + schedulesToLoad.AddToTail( g_psz##id ); + +//----------------- + +#define DEFINE_SCHEDULE( id, text ) \ + scheduleIds.PushBack( #id, id ); \ + const char * g_psz##id = \ + "\n Schedule" \ + "\n " #id \ + text \ + "\n"; \ + schedulesToLoad.AddToTail( g_psz##id ); + +//----------------- + +#define DECLARE_CONDITION( id ) \ + conditionIds.PushBack( #id, id ); + +//----------------- + +#define DECLARE_TASK( id ) \ + taskIds.PushBack( #id, id ); + +//----------------- + +#define DECLARE_ACTIVITY( id ) \ + ADD_CUSTOM_ACTIVITY( CNpc, id ); + +//----------------- + +#define DECLARE_SQUADSLOT( id ) \ + squadSlotIds.PushBack( #id, id ); + +//----------------- + +#define DECLARE_INTERACTION( interaction ) \ + ADD_CUSTOM_INTERACTION( interaction ); + +//----------------- + +#define DECLARE_ANIMEVENT( id ) \ + ADD_CUSTOM_ANIMEVENT( CNpc, id ); + +//----------------- + +#define DECLARE_USES_SCHEDULE_PROVIDER( classname ) reqiredOthers.AddToTail( ScheduleLoadHelper(classname) ); + +//----------------- + +// IDs are stored and then added in order due to constraints in the namespace implementation +#define AI_END_CUSTOM_SCHEDULE_PROVIDER() \ + \ + int i; \ + \ + CNpc::AccessClassScheduleIdSpaceDirect().Init( pszClassName, BaseClass::GetSchedulingSymbols(), &BaseClass::AccessClassScheduleIdSpaceDirect() ); \ + \ + scheduleIds.Sort(); \ + taskIds.Sort(); \ + conditionIds.Sort(); \ + \ + for ( i = 0; i < scheduleIds.Count(); i++ ) \ + { \ + ADD_CUSTOM_SCHEDULE_NAMED( CNpc, scheduleIds[i].pszName, scheduleIds[i].localId ); \ + } \ + \ + for ( i = 0; i < taskIds.Count(); i++ ) \ + { \ + ADD_CUSTOM_TASK_NAMED( CNpc, taskIds[i].pszName, taskIds[i].localId ); \ + } \ + \ + for ( i = 0; i < conditionIds.Count(); i++ ) \ + { \ + if ( ValidateConditionLimits( conditionIds[i].pszName ) ) \ + { \ + ADD_CUSTOM_CONDITION_NAMED( CNpc, conditionIds[i].pszName, conditionIds[i].localId ); \ + } \ + } \ + \ + for ( i = 0; i < reqiredOthers.Count(); i++ ) \ + { \ + (*reqiredOthers[i])(); \ + } \ + \ + for ( i = 0; i < schedulesToLoad.Count(); i++ ) \ + { \ + if ( CNpc::gm_SchedLoadStatus.fValid ) \ + { \ + CNpc::gm_SchedLoadStatus.fValid = g_AI_SchedulesManager.LoadSchedulesFromBuffer( pszClassName, schedulesToLoad[i], &AccessClassScheduleIdSpaceDirect() ); \ + } \ + else \ + break; \ + } \ + } + +inline bool ValidateConditionLimits( const char *pszNewCondition ) +{ + int nGlobalConditions = CAI_BaseNPC::GetSchedulingSymbols()->NumConditions(); + if ( nGlobalConditions >= MAX_CONDITIONS ) + { + AssertMsg2( 0, "Exceeded max number of conditions (%d), ignoring condition %s\n", MAX_CONDITIONS, pszNewCondition ); + DevWarning( "Exceeded max number of conditions (%d), ignoring condition %s\n", MAX_CONDITIONS, pszNewCondition ); + return false; + } + return true; +} + + +//------------------------------------- + +// IDs are stored and then added in order due to constraints in the namespace implementation +#define AI_END_CUSTOM_NPC() \ + \ + int i; \ + \ + CNpc::AccessClassScheduleIdSpaceDirect().Init( pszClassName, BaseClass::GetSchedulingSymbols(), &BaseClass::AccessClassScheduleIdSpaceDirect() ); \ + CNpc::gm_SquadSlotIdSpace.Init( &BaseClass::gm_SquadSlotNamespace, &BaseClass::gm_SquadSlotIdSpace); \ + \ + scheduleIds.Sort(); \ + taskIds.Sort(); \ + conditionIds.Sort(); \ + squadSlotIds.Sort(); \ + \ + for ( i = 0; i < scheduleIds.Count(); i++ ) \ + { \ + ADD_CUSTOM_SCHEDULE_NAMED( CNpc, scheduleIds[i].pszName, scheduleIds[i].localId ); \ + } \ + \ + for ( i = 0; i < taskIds.Count(); i++ ) \ + { \ + ADD_CUSTOM_TASK_NAMED( CNpc, taskIds[i].pszName, taskIds[i].localId ); \ + } \ + \ + for ( i = 0; i < conditionIds.Count(); i++ ) \ + { \ + if ( ValidateConditionLimits( conditionIds[i].pszName ) ) \ + { \ + ADD_CUSTOM_CONDITION_NAMED( CNpc, conditionIds[i].pszName, conditionIds[i].localId ); \ + } \ + } \ + \ + for ( i = 0; i < squadSlotIds.Count(); i++ ) \ + { \ + ADD_CUSTOM_SQUADSLOT_NAMED( CNpc, squadSlotIds[i].pszName, squadSlotIds[i].localId ); \ + } \ + \ + for ( i = 0; i < reqiredOthers.Count(); i++ ) \ + { \ + (*reqiredOthers[i])(); \ + } \ + \ + for ( i = 0; i < schedulesToLoad.Count(); i++ ) \ + { \ + if ( CNpc::gm_SchedLoadStatus.fValid ) \ + { \ + CNpc::gm_SchedLoadStatus.fValid = g_AI_SchedulesManager.LoadSchedulesFromBuffer( pszClassName, schedulesToLoad[i], &AccessClassScheduleIdSpaceDirect() ); \ + } \ + else \ + break; \ + } \ + } + +//------------------------------------- + +struct AI_NamespaceAddInfo_t +{ + AI_NamespaceAddInfo_t( const char *pszName, int localId ) + : pszName( pszName ), + localId( localId ) + { + } + + const char *pszName; + int localId; +}; + +class CAI_NamespaceInfos : public CUtlVector +{ +public: + void PushBack( const char *pszName, int localId ) + { + AddToTail( AI_NamespaceAddInfo_t( pszName, localId ) ); + } + + void Sort() + { + CUtlVector::Sort( Compare ); + } + +private: + static int __cdecl Compare(const AI_NamespaceAddInfo_t *pLeft, const AI_NamespaceAddInfo_t *pRight ) + { + return pLeft->localId - pRight->localId; + } + +}; + +//------------------------------------- + +// Declares the static variables that hold the string registry offset for the new subclass +// as well as the initialization in schedule load functions + +struct AI_SchedLoadStatus_t +{ + bool fValid; + int signature; +}; + +// Load schedules pulled out to support stepping through with debugger +inline bool AI_DoLoadSchedules( bool (*pfnBaseLoad)(), void (*pfnInitCustomSchedules)(), + AI_SchedLoadStatus_t *pLoadStatus ) +{ + (*pfnBaseLoad)(); + + if (pLoadStatus->signature != g_AI_SchedulesManager.GetScheduleLoadSignature()) + { + (*pfnInitCustomSchedules)(); + pLoadStatus->fValid = true; + pLoadStatus->signature = g_AI_SchedulesManager.GetScheduleLoadSignature(); + } + return pLoadStatus->fValid; +} + +//------------------------------------- + +typedef bool (*AIScheduleLoadFunc_t)(); + +// @Note (toml 02-16-03): The following class exists to allow us to establish an anonymous friendship +// in DEFINE_CUSTOM_SCHEDULE_PROVIDER. The particulars of this implementation is almost entirely +// defined by bugs in MSVC 6.0 +class ScheduleLoadHelperImpl +{ +public: + template + static AIScheduleLoadFunc_t AccessScheduleLoadFunc(T *) + { + return (&T::LoadSchedules); + } +}; + +#define ScheduleLoadHelper( type ) (ScheduleLoadHelperImpl::AccessScheduleLoadFunc((type *)0)) + +//------------------------------------- + +#define DEFINE_CUSTOM_SCHEDULE_PROVIDER\ + static AI_SchedLoadStatus_t gm_SchedLoadStatus; \ + static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace; \ + static const char * gm_pszErrorClassName;\ + \ + static CAI_ClassScheduleIdSpace & AccessClassScheduleIdSpaceDirect() { return gm_ClassScheduleIdSpace; } \ + virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace() { return &gm_ClassScheduleIdSpace; } \ + virtual const char * GetSchedulingErrorName() { return gm_pszErrorClassName; } \ + \ + static void InitCustomSchedules(void);\ + \ + static bool LoadSchedules(void);\ + virtual bool LoadedSchedules(void); \ + \ + friend class ScheduleLoadHelperImpl; \ + \ + class CScheduleLoader \ + { \ + public: \ + CScheduleLoader(); \ + } m_ScheduleLoader; \ + \ + friend class CScheduleLoader; + +//------------------------------------- + +#define DEFINE_CUSTOM_AI\ + DEFINE_CUSTOM_SCHEDULE_PROVIDER \ + \ + static CAI_LocalIdSpace gm_SquadSlotIdSpace; \ + \ + const char* SquadSlotName (int squadSlotID); + +//------------------------------------- + +#define IMPLEMENT_CUSTOM_SCHEDULE_PROVIDER(derivedClass)\ + AI_SchedLoadStatus_t derivedClass::gm_SchedLoadStatus = { true, -1 }; \ + CAI_ClassScheduleIdSpace derivedClass::gm_ClassScheduleIdSpace; \ + const char * derivedClass::gm_pszErrorClassName = #derivedClass; \ + \ + derivedClass::CScheduleLoader::CScheduleLoader()\ + { \ + derivedClass::LoadSchedules(); \ + } \ + \ + /* --------------------------------------------- */ \ + /* Load schedules for this type of NPC */ \ + /* --------------------------------------------- */ \ + bool derivedClass::LoadSchedules(void)\ + {\ + return AI_DoLoadSchedules( derivedClass::BaseClass::LoadSchedules, \ + derivedClass::InitCustomSchedules, \ + &derivedClass::gm_SchedLoadStatus ); \ + }\ + \ + bool derivedClass::LoadedSchedules(void) \ + { \ + return derivedClass::gm_SchedLoadStatus.fValid;\ + } + + +//------------------------------------- + +// Initialize offsets and implement methods for loading and getting squad info for the subclass +#define IMPLEMENT_CUSTOM_AI(className, derivedClass)\ + IMPLEMENT_CUSTOM_SCHEDULE_PROVIDER(derivedClass)\ + \ + CAI_LocalIdSpace derivedClass::gm_SquadSlotIdSpace; \ + \ + /* -------------------------------------------------- */ \ + /* Given squadSlot enumeration return squadSlot name */ \ + /* -------------------------------------------------- */ \ + const char* derivedClass::SquadSlotName(int slotEN)\ + {\ + return gm_SquadSlotNamespace.IdToSymbol( derivedClass::gm_SquadSlotIdSpace.LocalToGlobal(slotEN) );\ + } + + +//------------------------------------- + +#define ADD_CUSTOM_SCHEDULE_NAMED(derivedClass,schedName,schedEN)\ + if ( !derivedClass::AccessClassScheduleIdSpaceDirect().AddSchedule( schedName, schedEN, derivedClass::gm_pszErrorClassName ) ) return; + +#define ADD_CUSTOM_SCHEDULE(derivedClass,schedEN) ADD_CUSTOM_SCHEDULE_NAMED(derivedClass,#schedEN,schedEN) + +#define ADD_CUSTOM_TASK_NAMED(derivedClass,taskName,taskEN)\ + if ( !derivedClass::AccessClassScheduleIdSpaceDirect().AddTask( taskName, taskEN, derivedClass::gm_pszErrorClassName ) ) return; + +#define ADD_CUSTOM_TASK(derivedClass,taskEN) ADD_CUSTOM_TASK_NAMED(derivedClass,#taskEN,taskEN) + +#define ADD_CUSTOM_CONDITION_NAMED(derivedClass,condName,condEN)\ + if ( !derivedClass::AccessClassScheduleIdSpaceDirect().AddCondition( condName, condEN, derivedClass::gm_pszErrorClassName ) ) return; + +#define ADD_CUSTOM_CONDITION(derivedClass,condEN) ADD_CUSTOM_CONDITION_NAMED(derivedClass,#condEN,condEN) + +//------------------------------------- + +#define INIT_CUSTOM_AI(derivedClass)\ + derivedClass::AccessClassScheduleIdSpaceDirect().Init( #derivedClass, BaseClass::GetSchedulingSymbols(), &BaseClass::AccessClassScheduleIdSpaceDirect() ); \ + derivedClass::gm_SquadSlotIdSpace.Init( &CAI_BaseNPC::gm_SquadSlotNamespace, &BaseClass::gm_SquadSlotIdSpace); + +#define ADD_CUSTOM_INTERACTION( interaction ) { interaction = CBaseCombatCharacter::GetInteractionID(); } + +#define ADD_CUSTOM_SQUADSLOT_NAMED(derivedClass,squadSlotName,squadSlotEN)\ + if ( !derivedClass::gm_SquadSlotIdSpace.AddSymbol( squadSlotName, squadSlotEN, "squadslot", derivedClass::gm_pszErrorClassName ) ) return; + +#define ADD_CUSTOM_SQUADSLOT(derivedClass,squadSlotEN) ADD_CUSTOM_SQUADSLOT_NAMED(derivedClass,#squadSlotEN,squadSlotEN) + +#define ADD_CUSTOM_ACTIVITY_NAMED(derivedClass,activityName,activityEnum)\ + REGISTER_PRIVATE_ACTIVITY(activityEnum);\ + CAI_BaseNPC::AddActivityToSR(activityName,activityEnum); + +#define ADD_CUSTOM_ACTIVITY(derivedClass,activityEnum) ADD_CUSTOM_ACTIVITY_NAMED(derivedClass,#activityEnum,activityEnum) + + +#define ADD_CUSTOM_ANIMEVENT_NAMED(derivedClass,eventName,eventEnum)\ + REGISTER_PRIVATE_ANIMEVENT(eventEnum);\ + CAI_BaseNPC::AddEventToSR(eventName,eventEnum); + +#define ADD_CUSTOM_ANIMEVENT(derivedClass,eventEnum) ADD_CUSTOM_ANIMEVENT_NAMED(derivedClass,#eventEnum,eventEnum) + + +//============================================================================= +// class CAI_Component +//============================================================================= + +inline const Vector &CAI_Component::GetLocalOrigin() const +{ + return GetOuter()->GetLocalOrigin(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetLocalOrigin(const Vector &origin) +{ + GetOuter()->SetLocalOrigin(origin); +} + +//----------------------------------------------------------------------------- + +inline const Vector &CAI_Component::GetAbsOrigin() const +{ + return GetOuter()->GetAbsOrigin(); +} + +//----------------------------------------------------------------------------- + +inline const QAngle &CAI_Component::GetAbsAngles() const +{ + return GetOuter()->GetAbsAngles(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetSolid( SolidType_t val ) +{ + GetOuter()->SetSolid(val); +} + +//----------------------------------------------------------------------------- + +inline SolidType_t CAI_Component::GetSolid() const +{ + return GetOuter()->GetSolid(); +} + +//----------------------------------------------------------------------------- + +inline const Vector &CAI_Component::WorldAlignMins() const +{ + return GetOuter()->WorldAlignMins(); +} + +//----------------------------------------------------------------------------- + +inline const Vector &CAI_Component::WorldAlignMaxs() const +{ + return GetOuter()->WorldAlignMaxs(); +} + +//----------------------------------------------------------------------------- + +inline Hull_t CAI_Component::GetHullType() const +{ + return GetOuter()->GetHullType(); +} + +//----------------------------------------------------------------------------- + +inline Vector CAI_Component::WorldSpaceCenter() const +{ + return GetOuter()->WorldSpaceCenter(); +} + +//----------------------------------------------------------------------------- + +inline float CAI_Component::GetGravity() const +{ + return GetOuter()->GetGravity(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetGravity( float flGravity ) +{ + GetOuter()->SetGravity( flGravity ); +} + +//----------------------------------------------------------------------------- + +inline float CAI_Component::GetHullWidth() const +{ + return NAI_Hull::Width(GetOuter()->GetHullType()); +} + +//----------------------------------------------------------------------------- + +inline float CAI_Component::GetHullHeight() const +{ + return NAI_Hull::Height(GetOuter()->GetHullType()); +} + +//----------------------------------------------------------------------------- + +inline const Vector &CAI_Component::GetHullMins() const +{ + return NAI_Hull::Mins(GetOuter()->GetHullType()); +} + +//----------------------------------------------------------------------------- + +inline const Vector &CAI_Component::GetHullMaxs() const +{ + return NAI_Hull::Maxs(GetOuter()->GetHullType()); +} + +//----------------------------------------------------------------------------- + +inline int CAI_Component::GetCollisionGroup() const +{ + return GetOuter()->GetCollisionGroup(); +} + +//----------------------------------------------------------------------------- + +inline CBaseEntity *CAI_Component::GetEnemy() +{ + return GetOuter()->GetEnemy(); +} + +//----------------------------------------------------------------------------- + +inline const Vector &CAI_Component::GetEnemyLKP() const +{ + return GetOuter()->GetEnemyLKP(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition ) +{ + GetOuter()->TranslateNavGoal( pEnemy, chasePosition ); +} + +//----------------------------------------------------------------------------- + +inline CBaseEntity *CAI_Component::GetTarget() +{ + return GetOuter()->GetTarget(); +} +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetTarget( CBaseEntity *pTarget ) +{ + GetOuter()->SetTarget( pTarget ); +} + +//----------------------------------------------------------------------------- + +inline const Task_t *CAI_Component::GetCurTask() +{ + return GetOuter()->GetTask(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::TaskFail( AI_TaskFailureCode_t code ) +{ + GetOuter()->TaskFail( code ); +} +//----------------------------------------------------------------------------- + +inline void CAI_Component::TaskFail( const char *pszGeneralFailText ) +{ + GetOuter()->TaskFail( pszGeneralFailText ); +} +//----------------------------------------------------------------------------- + +inline void CAI_Component::TaskComplete( bool fIgnoreSetFailedCondition ) +{ + GetOuter()->TaskComplete( fIgnoreSetFailedCondition ); +} +//----------------------------------------------------------------------------- + +inline int CAI_Component::TaskIsRunning() +{ + return GetOuter()->TaskIsRunning(); +} +//----------------------------------------------------------------------------- + +inline int CAI_Component::TaskIsComplete() +{ + return GetOuter()->TaskIsComplete(); +} + +//----------------------------------------------------------------------------- + +inline Activity CAI_Component::GetActivity() +{ + return GetOuter()->GetActivity(); +} +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetActivity( Activity NewActivity ) +{ + GetOuter()->SetActivity( NewActivity ); +} +//----------------------------------------------------------------------------- + +inline float CAI_Component::GetIdealSpeed() const +{ + return GetOuter()->GetIdealSpeed(); +} + +//----------------------------------------------------------------------------- + +inline float CAI_Component::GetIdealAccel() const +{ + return GetOuter()->GetIdealAccel(); +} + +//----------------------------------------------------------------------------- + +inline int CAI_Component::GetSequence() +{ + return GetOuter()->GetSequence(); +} + +//----------------------------------------------------------------------------- + +inline int CAI_Component::GetEntFlags() const +{ + return GetOuter()->GetFlags(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::AddEntFlag( int flags ) +{ + GetOuter()->AddFlag( flags ); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::RemoveEntFlag( int flagsToRemove ) +{ + GetOuter()->RemoveFlag( flagsToRemove ); +} + +//----------------------------------------------------------------------------- +// Purpose: Change the ground entity for the outer +// Input : *ground - +// Output : inline void +//----------------------------------------------------------------------------- +inline void CAI_Component::SetGroundEntity( CBaseEntity *ground ) +{ + GetOuter()->SetGroundEntity( ground ); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::ToggleEntFlag( int flagToToggle ) +{ + GetOuter()->ToggleFlag( flagToToggle ); +} + +//----------------------------------------------------------------------------- + +inline CBaseEntity* CAI_Component::GetGoalEnt() +{ + return GetOuter()->GetGoalEnt(); +} +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetGoalEnt( CBaseEntity *pGoalEnt ) +{ + GetOuter()->SetGoalEnt( pGoalEnt ); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::Remember( int iMemory ) +{ + GetOuter()->Remember( iMemory ); +} +//----------------------------------------------------------------------------- + +inline void CAI_Component::Forget( int iMemory ) +{ + GetOuter()->Forget( iMemory ); +} +//----------------------------------------------------------------------------- + +inline bool CAI_Component::HasMemory( int iMemory ) +{ + return GetOuter()->HasMemory( iMemory ); +} + +//----------------------------------------------------------------------------- + +inline CAI_Enemies *CAI_Component::GetEnemies() +{ + return GetOuter()->GetEnemies(); +} + +//----------------------------------------------------------------------------- + +inline const char *CAI_Component::GetEntClassname() +{ + return GetOuter()->GetClassname(); +} + +//----------------------------------------------------------------------------- + +inline int CAI_Component::CapabilitiesGet() +{ + return GetOuter()->CapabilitiesGet(); +} + +//----------------------------------------------------------------------------- + +inline void CAI_Component::SetLocalAngles( const QAngle& angles ) +{ + GetOuter()->SetLocalAngles( angles ); +} + +//----------------------------------------------------------------------------- + +inline const QAngle &CAI_Component::GetLocalAngles( void ) const +{ + return GetOuter()->GetLocalAngles(); +} + +//----------------------------------------------------------------------------- + +inline edict_t *CAI_Component::GetEdict() +{ + return GetOuter()->NetworkProp()->edict(); +} + +//----------------------------------------------------------------------------- + +inline float CAI_Component::GetLastThink( const char *szContext ) +{ + return GetOuter()->GetLastThink( szContext ); +} + +// ============================================================================ +abstract_class INPCInteractive +{ +public: + virtual bool CanInteractWith( CAI_BaseNPC *pUser ) = 0; + virtual bool HasBeenInteractedWith() = 0; + virtual void NotifyInteraction( CAI_BaseNPC *pUser ) = 0; + + // Alyx specific interactions + virtual void AlyxStartedInteraction( void ) = 0; + virtual void AlyxFinishedInteraction( void ) = 0; +}; + +// Base Class for any NPC that wants to be interactable by other NPCS (i.e. Alyx Hackable) +// NOTE: YOU MUST DEFINE THE OUTPUTS IN YOUR CLASS'S DATADESC! +// THE DO SO, INSERT THE FOLLOWING MACRO INTO YOUR CLASS'S DATADESC. +// +#define DEFINE_BASENPCINTERACTABLE_DATADESC() \ + DEFINE_OUTPUT( m_OnAlyxStartedInteraction, "OnAlyxStartedInteraction" ), \ + DEFINE_OUTPUT( m_OnAlyxFinishedInteraction, "OnAlyxFinishedInteraction" ), \ + DEFINE_INPUTFUNC( FIELD_VOID, "InteractivePowerDown", InputPowerdown ) + +template +class CNPCBaseInteractive : public NPC_CLASS, public INPCInteractive +{ + DECLARE_CLASS( CNPCBaseInteractive, NPC_CLASS ); +public: + virtual bool CanInteractWith( CAI_BaseNPC *pUser ) { return false; }; + virtual bool HasBeenInteractedWith() { return false; }; + virtual void NotifyInteraction( CAI_BaseNPC *pUser ) { return; }; + + virtual void InputPowerdown( inputdata_t &inputdata ) + { + + } + + // Alyx specific interactions + virtual void AlyxStartedInteraction( void ) + { + m_OnAlyxStartedInteraction.FireOutput( this, this ); + } + virtual void AlyxFinishedInteraction( void ) + { + m_OnAlyxFinishedInteraction.FireOutput( this, this ); + } + +public: + // Outputs + // Alyx specific interactions + COutputEvent m_OnAlyxStartedInteraction; + COutputEvent m_OnAlyxFinishedInteraction; +}; + +// +// Deferred Navigation calls go here +// + +extern ConVar ai_post_frame_navigation; + +class CPostFrameNavigationHook : public CBaseGameSystemPerFrame +{ +public: + virtual const char *Name( void ) { return "CPostFrameNavigationHook"; } + + virtual bool Init( void ); + virtual void FrameUpdatePostEntityThink( void ); + virtual void FrameUpdatePreEntityThink( void ); + + bool IsGameFrameRunning( void ) { return m_bGameFrameRunning; } + void SetGrameFrameRunning( bool bState ) { m_bGameFrameRunning = bState; } + + void EnqueueEntityNavigationQuery( CAI_BaseNPC *pNPC, CFunctor *functor ); + +private: + CUtlVector m_Functors; + bool m_bGameFrameRunning; +}; + +extern CPostFrameNavigationHook *PostFrameNavigationSystem( void ); + +#endif // AI_BASENPC_H diff --git a/game/server/ai_basenpc_flyer.h b/game/server/ai_basenpc_flyer.h new file mode 100644 index 0000000..127a669 --- /dev/null +++ b/game/server/ai_basenpc_flyer.h @@ -0,0 +1,132 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_BASENPC_FLYER_H +#define AI_BASENPC_FLYER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_navigator.h" + +//----------------------------------------------------------------------------- +// The combot. +//----------------------------------------------------------------------------- +abstract_class CAI_BaseFlyingBot : public CAI_BaseNPC +{ + DECLARE_CLASS( CAI_BaseFlyingBot, CAI_BaseNPC ); +public: + DECLARE_DATADESC(); + + void StartTask( const Task_t *pTask ); + void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity); + virtual QAngle BodyAngles(); + +protected: + + CAI_BaseFlyingBot(); + + Vector VelocityToAvoidObstacles(float flInterval); + virtual float MinGroundDist(void); + + void TurnHeadToTarget( float flInterval, const Vector &moveTarget ); + + void MoveInDirection( float flInterval, const Vector &targetDir, + float accelXY, float accelZ, float decay) + { + decay = ExponentialDecay( decay, 1.0, flInterval ); + accelXY *= flInterval; + accelZ *= flInterval; + + m_vCurrentVelocity.x = ( decay * m_vCurrentVelocity.x + accelXY * targetDir.x ); + m_vCurrentVelocity.y = ( decay * m_vCurrentVelocity.y + accelXY * targetDir.y ); + m_vCurrentVelocity.z = ( decay * m_vCurrentVelocity.z + accelZ * targetDir.z ); + } + + void MoveToLocation( float flInterval, const Vector &target, + float accelXY, float accelZ, float decay) + { + Vector targetDir = target - GetLocalOrigin(); + VectorNormalize(targetDir); + + MoveInDirection(flInterval, targetDir, accelXY, accelZ, decay); + } + + void Decelerate( float flInterval, float decay ) + { + decay *= flInterval; + m_vCurrentVelocity.x = (decay * m_vCurrentVelocity.x); + m_vCurrentVelocity.y = (decay * m_vCurrentVelocity.y); + m_vCurrentVelocity.z = (decay * m_vCurrentVelocity.z); + } + + void AddNoiseToVelocity( float noiseScale = 1.0 ) + { + if( m_vNoiseMod.x ) + { + m_vCurrentVelocity.x += noiseScale*sin(m_vNoiseMod.x * gpGlobals->curtime + m_vNoiseMod.x); + } + + if( m_vNoiseMod.y ) + { + m_vCurrentVelocity.y += noiseScale*cos(m_vNoiseMod.y * gpGlobals->curtime + m_vNoiseMod.y); + } + + if( m_vNoiseMod.z ) + { + m_vCurrentVelocity.z -= noiseScale*cos(m_vNoiseMod.z * gpGlobals->curtime + m_vNoiseMod.z); + } + } + + void LimitSpeed( float zLimit, float maxSpeed = -1 ) + { + if ( maxSpeed == -1 ) + maxSpeed = m_flSpeed; + if (m_vCurrentVelocity.Length() > maxSpeed) + { + VectorNormalize(m_vCurrentVelocity); + m_vCurrentVelocity *= maxSpeed; + } + // Limit fall speed + if (zLimit > 0 && m_vCurrentVelocity.z < -zLimit) + { + m_vCurrentVelocity.z = -zLimit; + } + } + + AI_NavPathProgress_t ProgressFlyPath( float flInterval, + const CBaseEntity *pNewTarget, + unsigned collisionMask, + bool bNewTrySimplify = true, + float strictPointTolerance = 32.0 ); + + virtual float GetHeadTurnRate( void ) { return 15.0f; } // Degrees per second + + const Vector &GetCurrentVelocity() const { return m_vCurrentVelocity; } + void SetCurrentVelocity(const Vector &vNewVel) { m_vCurrentVelocity = vNewVel; } + + const Vector &GetNoiseMod() const { return m_vNoiseMod; } + void SetNoiseMod( float x, float y, float z ) { m_vNoiseMod.Init( x, y, z ); } + void SetNoiseMod( const Vector &noise ) { m_vNoiseMod = noise; } + + virtual void MoveToTarget(float flInterval, const Vector &MoveTarget) = 0; + + void TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition ); + + // ------------------------------- + // Movement vars + // ------------------------------- + Vector m_vCurrentVelocity; + Vector m_vCurrentAngularVelocity; + Vector m_vCurrentBanking; + Vector m_vNoiseMod; + float m_fHeadYaw; + Vector m_vLastPatrolDir; +}; + +#endif // AI_BASENPC_FLYER_H diff --git a/game/server/ai_basenpc_flyer_new.h b/game/server/ai_basenpc_flyer_new.h new file mode 100644 index 0000000..ed99963 --- /dev/null +++ b/game/server/ai_basenpc_flyer_new.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_BASENPC_FLYER_NEW_H +#define AI_BASENPC_FLYER_NEW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_condition.h" + + +enum BaseNPCFlyerConditions_t +{ + COND_FLYER_MOVE_BLOCKED = LAST_SHARED_CONDITION, + COND_FLYER_MOVE_IMPOSSIBLE, + + // ====================================== + // IMPORTANT: This must be the last enum + // ====================================== + LAST_FLYER_SHARED_CONDITION +}; + + +//----------------------------------------------------------------------------- +// The combot. +//----------------------------------------------------------------------------- +class CAI_BaseNPCFlyerNew : public CAI_BaseNPC +{ + DECLARE_CLASS( CAI_BaseNPCFlyerNew, CAI_BaseNPC ); +public: +// DEFINE_CUSTOM_AI; + + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + + virtual float GetIdealSpeed( ) const; + virtual float MinGroundDist(void); + + CAI_BaseNPCFlyerNew(); + +protected: + // Call this to set up a flyer + void SpawnFlyer(); + + // Yarg! Must be chained down from leaf classes... + void ClearFlyerConditions(void); + + // Override this when we had to abort movement + virtual void AbortedMovement( void ) {} +}; + +#endif // AI_BASENPC_FLYER_NEW_H diff --git a/game/server/ai_basenpc_physicsflyer.h b/game/server/ai_basenpc_physicsflyer.h new file mode 100644 index 0000000..0928fd4 --- /dev/null +++ b/game/server/ai_basenpc_physicsflyer.h @@ -0,0 +1,149 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_BASENPC_PHYSICSFLYER_H +#define AI_BASENPC_PHYSICSFLYER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_navigator.h" + +//----------------------------------------------------------------------------- +// The combot. +//----------------------------------------------------------------------------- +abstract_class CAI_BasePhysicsFlyingBot : public CAI_BaseNPC, public IMotionEvent +{ + DECLARE_CLASS( CAI_BasePhysicsFlyingBot, CAI_BaseNPC ); +public: + DECLARE_DATADESC(); + + void StartTask( const Task_t *pTask ); + void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity); + virtual QAngle BodyAngles(); + + virtual bool ShouldSavePhysics() { return true; } + +protected: + + CAI_BasePhysicsFlyingBot(); + ~CAI_BasePhysicsFlyingBot(); + + Vector VelocityToAvoidObstacles(float flInterval); + virtual float MinGroundDist(void); + + virtual void TurnHeadToTarget( float flInterval, const Vector &moveTarget ); + + void MoveInDirection( float flInterval, const Vector &targetDir, + float accelXY, float accelZ, float decay) + { + decay = ExponentialDecay( decay, 1.0, flInterval ); + accelXY *= flInterval; + accelZ *= flInterval; + + m_vCurrentVelocity.x = ( decay * m_vCurrentVelocity.x + accelXY * targetDir.x ); + m_vCurrentVelocity.y = ( decay * m_vCurrentVelocity.y + accelXY * targetDir.y ); + m_vCurrentVelocity.z = ( decay * m_vCurrentVelocity.z + accelZ * targetDir.z ); + } + + void MoveToLocation( float flInterval, const Vector &target, + float accelXY, float accelZ, float decay) + { + Vector targetDir = target - GetLocalOrigin(); + VectorNormalize(targetDir); + + MoveInDirection(flInterval, targetDir, accelXY, accelZ, decay); + } + + void Decelerate( float flInterval, float decay ) + { + decay *= flInterval; + m_vCurrentVelocity.x = (decay * m_vCurrentVelocity.x); + m_vCurrentVelocity.y = (decay * m_vCurrentVelocity.y); + m_vCurrentVelocity.z = (decay * m_vCurrentVelocity.z); + } + + void AddNoiseToVelocity( float noiseScale = 1.0 ) + { + if( m_vNoiseMod.x ) + { + m_vCurrentVelocity.x += noiseScale*sin(m_vNoiseMod.x * gpGlobals->curtime + m_vNoiseMod.x); + } + + if( m_vNoiseMod.y ) + { + m_vCurrentVelocity.y += noiseScale*cos(m_vNoiseMod.y * gpGlobals->curtime + m_vNoiseMod.y); + } + + if( m_vNoiseMod.z ) + { + m_vCurrentVelocity.z -= noiseScale*cos(m_vNoiseMod.z * gpGlobals->curtime + m_vNoiseMod.z); + } + } + + void LimitSpeed( float zLimit, float maxSpeed = -1 ) + { + if ( maxSpeed == -1 ) + maxSpeed = m_flSpeed; + if (m_vCurrentVelocity.Length() > maxSpeed) + { + VectorNormalize(m_vCurrentVelocity); + m_vCurrentVelocity *= maxSpeed; + } + // Limit fall speed + if (zLimit > 0 && m_vCurrentVelocity.z < -zLimit) + { + m_vCurrentVelocity.z = -zLimit; + } + } + + AI_NavPathProgress_t ProgressFlyPath( float flInterval, + const CBaseEntity *pNewTarget, + unsigned collisionMask, + bool bNewTrySimplify = true, + float strictPointTolerance = 32.0 ); + + const Vector &GetCurrentVelocity() const { return m_vCurrentVelocity; } + void SetCurrentVelocity(const Vector &vNewVel) { m_vCurrentVelocity = vNewVel; } + + const Vector &GetNoiseMod() const { return m_vNoiseMod; } + void SetNoiseMod( float x, float y, float z ) { m_vNoiseMod.Init( x, y, z ); } + void SetNoiseMod( const Vector &noise ) { m_vNoiseMod = noise; } + + void TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition ); + + virtual void MoveToTarget(float flInterval, const Vector &MoveTarget) = 0; + + virtual float GetHeadTurnRate( void ) { return 15.0f; } // Degrees per second + + bool CreateVPhysics( void ); + IMotionEvent::simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ); + + virtual void ClampMotorForces( Vector &linear, AngularImpulse &angular ) + { + // limit reaction forces + linear.x = clamp( linear.x, -3000.f, 3000.f ); + linear.y = clamp( linear.y, -3000.f, 3000.f ); + linear.z = clamp( linear.z, -3000.f, 3000.f ); + + // add in weightlessness + linear.z += 800.f; + } + + // ------------------------------- + // Movement vars + // ------------------------------- + Vector m_vCurrentVelocity; + Vector m_vCurrentBanking; + Vector m_vNoiseMod; + float m_fHeadYaw; + Vector m_vLastPatrolDir; + IPhysicsMotionController *m_pMotionController; +}; + +#endif // AI_BASENPC_PHYSICSFLYER_H diff --git a/game/server/ai_behavior.h b/game/server/ai_behavior.h new file mode 100644 index 0000000..f88a0c4 --- /dev/null +++ b/game/server/ai_behavior.h @@ -0,0 +1,1973 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_BEHAVIOR_H +#define AI_BEHAVIOR_H + +#include "ai_component.h" +#include "ai_basenpc.h" +#include "ai_default.h" +#include "AI_Criteria.h" +#include "networkvar.h" + +#ifdef DEBUG +#pragma warning(push) +#include +#pragma warning(pop) +#pragma warning(disable:4290) +#endif + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// CAI_Behavior... +// +// Purpose: The core component that defines a behavior in an NPC by selecting +// schedules and running tasks +// +// Intended to be used as an organizational tool as well as a way +// for various NPCs to share behaviors without sharing an inheritance +// relationship, and without cramming those behaviors into the base +// NPC class. +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Purpose: Base class defines interface to behaviors and provides bridging +// methods +//----------------------------------------------------------------------------- + +class IBehaviorBackBridge; + +//------------------------------------- + +abstract_class CAI_BehaviorBase : public CAI_Component +{ + DECLARE_CLASS( CAI_BehaviorBase, CAI_Component ) +public: + CAI_BehaviorBase(CAI_BaseNPC *pOuter = NULL) + : CAI_Component(pOuter), + m_pBackBridge(NULL) + { + } + + virtual const char *GetName() = 0; + + virtual bool KeyValue( const char *szKeyName, const char *szValue ) + { + return false; + } + + bool IsRunning() { Assert( GetOuter() ); return ( GetOuter()->GetRunningBehavior() == this ); } + virtual bool CanSelectSchedule() { return true; } + virtual void BeginScheduleSelection() {} + virtual void EndScheduleSelection() {} + + void SetBackBridge( IBehaviorBackBridge *pBackBridge ) + { + Assert( m_pBackBridge == NULL || pBackBridge == NULL ); + m_pBackBridge = pBackBridge; + } + + void BridgePrecache() { Precache(); } + void BridgeSpawn() { Spawn(); } + void BridgeUpdateOnRemove() { UpdateOnRemove(); } + void BridgeEvent_Killed( const CTakeDamageInfo &info ) { Event_Killed( info ); } + void BridgeCleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ) { CleanupOnDeath( pCulprit, bFireDeathOutput ); } + + void BridgeOnChangeHintGroup( string_t oldGroup, string_t newGroup ) { OnChangeHintGroup( oldGroup, newGroup ); } + + void BridgeGatherConditions() { GatherConditions(); } + void BridgePrescheduleThink() { PrescheduleThink(); } + void BridgeOnScheduleChange() { OnScheduleChange(); } + void BridgeOnStartSchedule( int scheduleType ); + + int BridgeSelectSchedule(); + bool BridgeSelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode, int *pResult ); + bool BridgeStartTask( const Task_t *pTask ); + bool BridgeRunTask( const Task_t *pTask); + bool BridgeAimGun( void ); + int BridgeTranslateSchedule( int scheduleType ); + bool BridgeGetSchedule( int localScheduleID, CAI_Schedule **ppResult ); + bool BridgeTaskName(int taskID, const char **); + Activity BridgeNPC_TranslateActivity( Activity activity ); + void BridgeBuildScheduleTestBits() { BuildScheduleTestBits(); } + bool BridgeIsCurTaskContinuousMove( bool *pResult ); + void BridgeOnMovementFailed() { OnMovementFailed(); } + void BridgeOnMovementComplete() { OnMovementComplete(); } + float BridgeGetDefaultNavGoalTolerance(); + bool BridgeFValidateHintType( CAI_Hint *pHint, bool *pResult ); + bool BridgeIsValidEnemy( CBaseEntity *pEnemy ); + CBaseEntity *BridgeBestEnemy(); + bool BridgeIsValidCover( const Vector &vLocation, CAI_Hint const *pHint ); + bool BridgeIsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + float BridgeGetMaxTacticalLateralMovement( void ); + bool BridgeShouldIgnoreSound( CSound *pSound ); + void BridgeOnSeeEntity( CBaseEntity *pEntity ); + void BridgeOnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + bool BridgeIsInterruptable( void ); + bool BridgeIsNavigationUrgent( void ); + bool BridgeShouldPlayerAvoid( void ); + int BridgeOnTakeDamage_Alive( const CTakeDamageInfo &info ); + float BridgeGetReasonableFacingDist( void ); + bool BridgeShouldAlwaysThink( bool *pResult ); + void BridgeOnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + void BridgeOnRestore(); + virtual bool BridgeSpeakMapmakerInterruptConcept( string_t iszConcept ); + bool BridgeCanFlinch( void ); + bool BridgeIsCrouching( void ); + bool BridgeIsCrouchedActivity( Activity activity ); + bool BridgeQueryHearSound( CSound *pSound ); + bool BridgeCanRunAScriptedNPCInteraction( bool bForced ); + Activity BridgeGetFlinchActivity( bool bHeavyDamage, bool bGesture ); + bool BridgeOnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + void BridgeModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ); + void BridgeTeleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + void BridgeHandleAnimEvent( animevent_t *pEvent ); + + virtual void GatherConditions(); + virtual void GatherConditionsNotActive() { return; } // Override this and your behavior will call this in place of GatherConditions() when your behavior is NOT the active one. + virtual void OnUpdateShotRegulator() {} + + virtual CAI_ClassScheduleIdSpace *GetClassScheduleIdSpace(); + + virtual int DrawDebugTextOverlays( int text_offset ); + + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + + static void SaveBehaviors(ISave &save, CAI_BehaviorBase *pCurrentBehavior, CAI_BehaviorBase **ppBehavior, int nBehaviors ); + static int RestoreBehaviors(IRestore &restore, CAI_BehaviorBase **ppBehavior, int nBehaviors ); // returns index of "current" behavior, or -1 + +protected: + + int GetNpcState() { return GetOuter()->m_NPCState; } + + virtual void Precache() {} + virtual void Spawn() {} + virtual void UpdateOnRemove() {} + virtual void Event_Killed( const CTakeDamageInfo &info ) {} + virtual void CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ) {} + + virtual void PrescheduleThink(); + virtual void OnScheduleChange(); + virtual void OnStartSchedule( int scheduleType ); + + virtual int SelectSchedule(); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + virtual void AimGun( void ); + virtual int TranslateSchedule( int scheduleType ); + virtual CAI_Schedule *GetSchedule(int schedule); + virtual const char *GetSchedulingErrorName(); + virtual void BuildScheduleTestBits() {} + bool IsCurSchedule( int schedId, bool fIdeal = true ); + + + CAI_Hint * GetHintNode() { return GetOuter()->GetHintNode(); } + const CAI_Hint *GetHintNode() const { return GetOuter()->GetHintNode(); } + void SetHintNode( CAI_Hint *pHintNode ) { GetOuter()->SetHintNode( pHintNode ); } + void ClearHintNode( float reuseDelay = 0.0 ) { GetOuter()->ClearHintNode( reuseDelay ); } + +protected: + // Used by derived classes to chain a task to a task that might not be the + // one they are currently handling: + void ChainStartTask( int task, float taskData = 0 ); + void ChainRunTask( int task, float taskData = 0 ); + +protected: + + virtual Activity NPC_TranslateActivity( Activity activity ); + + virtual bool IsCurTaskContinuousMove(); + virtual void OnMovementFailed() {}; + virtual void OnMovementComplete() {}; + virtual float GetDefaultNavGoalTolerance(); + virtual bool FValidateHintType( CAI_Hint *pHint ); + + virtual bool IsValidEnemy( CBaseEntity *pEnemy ); + virtual CBaseEntity *BestEnemy(); + virtual bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ); + virtual bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + virtual float GetMaxTacticalLateralMovement( void ); + virtual bool ShouldIgnoreSound( CSound *pSound ); + virtual void OnSeeEntity( CBaseEntity *pEntity ); + virtual void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + virtual bool IsInterruptable( void ); + virtual bool IsNavigationUrgent( void ); + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual float GetReasonableFacingDist( void ); + virtual bool ShouldPlayerAvoid( void ); + virtual bool CanFlinch( void ); + virtual bool IsCrouching( void ); + virtual bool IsCrouchedActivity( Activity activity ); + virtual bool QueryHearSound( CSound *pSound ); + virtual bool CanRunAScriptedNPCInteraction( bool bForced ); + virtual Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture ); + virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ); + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + virtual void HandleAnimEvent( animevent_t *pEvent ); + + virtual bool ShouldAlwaysThink(); + + virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) {}; + virtual bool SpeakMapmakerInterruptConcept( string_t iszConcept ) { return false; }; + + virtual void OnRestore() {}; + + bool NotifyChangeBehaviorStatus( bool fCanFinishSchedule = false ); + + bool HaveSequenceForActivity( Activity activity ) { return GetOuter()->HaveSequenceForActivity( activity ); } + + //--------------------------------- + + string_t GetHintGroup() { return GetOuter()->GetHintGroup(); } + void ClearHintGroup() { GetOuter()->ClearHintGroup(); } + void SetHintGroup( string_t name ) { GetOuter()->SetHintGroup( name ); } + + virtual void OnChangeHintGroup( string_t oldGroup, string_t newGroup ) {} + + // + // These allow derived classes to implement custom schedules + // + static CAI_GlobalScheduleNamespace *GetSchedulingSymbols() { return CAI_BaseNPC::GetSchedulingSymbols(); } + static bool LoadSchedules() { return true; } + virtual bool IsBehaviorSchedule( int scheduleType ) { return false; } + + CAI_Navigator * GetNavigator() { return GetOuter()->GetNavigator(); } + CAI_Motor * GetMotor() { return GetOuter()->GetMotor(); } + CAI_TacticalServices * GetTacticalServices() { return GetOuter()->GetTacticalServices(); } + + bool m_fOverrode; + IBehaviorBackBridge *m_pBackBridge; + + DECLARE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: Template provides provides back bridge to owning class and +// establishes namespace settings +//----------------------------------------------------------------------------- + +template +class CAI_Behavior : public CAI_ComponentWithOuter +{ +public: + DECLARE_CLASS_NOFRIEND( CAI_Behavior, NPC_CLASS ); + + enum + { + NEXT_TASK = ID_SPACE_OFFSET, + NEXT_SCHEDULE = ID_SPACE_OFFSET, + NEXT_CONDITION = ID_SPACE_OFFSET + }; + + void SetCondition( int condition ) + { + if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us + condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition ); + this->GetOuter()->SetCondition( condition ); + } + + bool HasCondition( int condition ) + { + if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us + condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition ); + return this->GetOuter()->HasCondition( condition ); + } + + bool HasInterruptCondition( int condition ) + { + if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us + condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition ); + return this->GetOuter()->HasInterruptCondition( condition ); + } + + void ClearCondition( int condition ) + { + if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us + condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition ); + this->GetOuter()->ClearCondition( condition ); + } + +protected: + CAI_Behavior(NPC_CLASS *pOuter = NULL) + : CAI_ComponentWithOuter(pOuter) + { + } + + static CAI_GlobalScheduleNamespace *GetSchedulingSymbols() + { + return NPC_CLASS::GetSchedulingSymbols(); + } + virtual CAI_ClassScheduleIdSpace *GetClassScheduleIdSpace() + { + return this->GetOuter()->GetClassScheduleIdSpace(); + } + + static CAI_ClassScheduleIdSpace &AccessClassScheduleIdSpaceDirect() + { + return NPC_CLASS::AccessClassScheduleIdSpaceDirect(); + } + +private: + virtual bool IsBehaviorSchedule( int scheduleType ) { return ( scheduleType >= ID_SPACE_OFFSET && scheduleType < ID_SPACE_OFFSET + 10000 ); } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Some bridges a little more complicated to allow behavior to see +// what base class would do or control order in which it's donw +//----------------------------------------------------------------------------- + +abstract_class IBehaviorBackBridge +{ +public: + virtual void BackBridge_GatherConditions() = 0; + virtual int BackBridge_SelectSchedule() = 0; + virtual int BackBridge_TranslateSchedule( int scheduleType ) = 0; + virtual Activity BackBridge_NPC_TranslateActivity( Activity activity ) = 0; + virtual bool BackBridge_IsValidEnemy(CBaseEntity *pEnemy) = 0; + virtual CBaseEntity* BackBridge_BestEnemy(void) = 0; + virtual bool BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ) = 0; + virtual bool BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ) = 0; + virtual float BackBridge_GetMaxTacticalLateralMovement( void ) = 0; + virtual bool BackBridge_ShouldIgnoreSound( CSound *pSound ) = 0; + virtual void BackBridge_OnSeeEntity( CBaseEntity *pEntity ) = 0; + virtual void BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) = 0; + virtual bool BackBridge_IsInterruptable( void ) = 0; + virtual bool BackBridge_IsNavigationUrgent( void ) = 0; + virtual bool BackBridge_ShouldPlayerAvoid( void ) = 0; + virtual int BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info ) = 0; + virtual float BackBridge_GetDefaultNavGoalTolerance() = 0; + virtual float BackBridge_GetReasonableFacingDist( void ) = 0; + virtual bool BackBridge_CanFlinch( void ) = 0; + virtual bool BackBridge_IsCrouching( void ) = 0; + virtual bool BackBridge_IsCrouchedActivity( Activity activity ) = 0; + virtual bool BackBridge_QueryHearSound( CSound *pSound ) = 0; + virtual bool BackBridge_CanRunAScriptedNPCInteraction( bool bForced ) = 0; + virtual Activity BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture ) = 0; + virtual bool BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) = 0; + virtual void BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ) = 0; + virtual void BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) = 0; + + virtual void BackBridge_HandleAnimEvent( animevent_t *pEvent ) = 0; + +//------------------------------------- + +}; + +//----------------------------------------------------------------------------- +// Purpose: The common instantiation of the above template +//----------------------------------------------------------------------------- + +typedef CAI_Behavior<> CAI_SimpleBehavior; + +//----------------------------------------------------------------------------- +// Purpose: Base class for AIs that want to act as a host for CAI_Behaviors +// NPCs aren't required to use this, but probably want to. +//----------------------------------------------------------------------------- + +template +class CAI_BehaviorHost : public BASE_NPC, + private IBehaviorBackBridge +{ +public: + DECLARE_CLASS_NOFRIEND( CAI_BehaviorHost, BASE_NPC ); + + CAI_BehaviorHost() + : m_pCurBehavior(NULL) + { +#ifdef DEBUG + m_fDebugInCreateBehaviors = false; +#endif + } + + void CleanupOnDeath( CBaseEntity *pCulprit = NULL, bool bFireDeathOutput = true ); + + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + virtual bool CreateComponents(); + + // Automatically called during entity construction, derived class calls AddBehavior() + virtual bool CreateBehaviors() { return true; } + + // forces movement and sets a new schedule + virtual bool ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity ); + virtual bool ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity ); + virtual void ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun); + virtual void ForceSelectedGoRandom(void); + + // Bridges + void Precache(); + void NPCInit(); + void UpdateOnRemove(); + void Event_Killed( const CTakeDamageInfo &info ); + void GatherConditions(); + void PrescheduleThink(); + int SelectSchedule(); + void KeepRunningBehavior(); + int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + void OnScheduleChange(); + void OnStartSchedule( int scheduleType ); + int TranslateSchedule( int scheduleType ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void AimGun( void ); + CAI_Schedule * GetSchedule(int localScheduleID); + const char * TaskName(int taskID); + void BuildScheduleTestBits(); + + void OnChangeHintGroup( string_t oldGroup, string_t newGroup ); + + Activity NPC_TranslateActivity( Activity activity ); + + bool IsCurTaskContinuousMove(); + void OnMovementFailed(); + void OnMovementComplete(); + bool FValidateHintType( CAI_Hint *pHint ); + float GetDefaultNavGoalTolerance(); + + bool IsValidEnemy(CBaseEntity *pEnemy); + CBaseEntity* BestEnemy(void); + bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ); + bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + float GetMaxTacticalLateralMovement( void ); + bool ShouldIgnoreSound( CSound *pSound ); + void OnSeeEntity( CBaseEntity *pEntity ); + void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + bool IsInterruptable( void ); + bool IsNavigationUrgent( void ); + bool ShouldPlayerAvoid( void ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + float GetReasonableFacingDist( void ); + bool CanFlinch( void ); + bool IsCrouching( void ); + bool IsCrouchedActivity( Activity activity ); + bool QueryHearSound( CSound *pSound ); + bool CanRunAScriptedNPCInteraction( bool bForced ); + Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture ); + bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + void HandleAnimEvent( animevent_t *pEvent ); + + bool ShouldAlwaysThink(); + + void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + virtual bool SpeakMapmakerInterruptConcept( string_t iszConcept ); + + void OnRestore(); + + void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + + //--------------------------------- + + virtual bool OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule ); + virtual void OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ); + +protected: + void AddBehavior( CAI_BehaviorBase *pBehavior ); + + bool BehaviorSelectSchedule(); + virtual bool ShouldBehaviorSelectSchedule( CAI_BehaviorBase *pBehavior ) { return true; } + + bool IsRunningBehavior() const; + CAI_BehaviorBase *GetRunningBehavior(); + CAI_BehaviorBase *DeferSchedulingToBehavior( CAI_BehaviorBase *pNewBehavior ); + void ChangeBehaviorTo( CAI_BehaviorBase *pNewBehavior ); + + CAI_Schedule * GetNewSchedule(); + CAI_Schedule * GetFailSchedule(); +private: + void BackBridge_GatherConditions(); + int BackBridge_SelectSchedule(); + int BackBridge_TranslateSchedule( int scheduleType ); + Activity BackBridge_NPC_TranslateActivity( Activity activity ); + bool BackBridge_IsValidEnemy(CBaseEntity *pEnemy); + CBaseEntity* BackBridge_BestEnemy(void); + bool BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ); + bool BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + float BackBridge_GetMaxTacticalLateralMovement( void ); + bool BackBridge_ShouldIgnoreSound( CSound *pSound ); + void BackBridge_OnSeeEntity( CBaseEntity *pEntity ); + void BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + bool BackBridge_IsInterruptable( void ); + bool BackBridge_IsNavigationUrgent( void ); + bool BackBridge_ShouldPlayerAvoid( void ); + int BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info ); + float BackBridge_GetDefaultNavGoalTolerance(); + float BackBridge_GetReasonableFacingDist( void ); + bool BackBridge_CanFlinch( void ); + bool BackBridge_IsCrouching( void ); + bool BackBridge_IsCrouchedActivity( Activity activity ); + bool BackBridge_QueryHearSound( CSound *pSound ); + bool BackBridge_CanRunAScriptedNPCInteraction( bool bForced ); + Activity BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture ); + bool BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + void BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ); + void BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + + void BackBridge_HandleAnimEvent( animevent_t *pEvent ); + + CAI_BehaviorBase **AccessBehaviors(); + int NumBehaviors(); + + CAI_BehaviorBase * m_pCurBehavior; + CUtlVector m_Behaviors; + + bool m_bCalledBehaviorSelectSchedule; + +#ifdef DEBUG + bool m_fDebugInCreateBehaviors; +#endif + +}; + +//----------------------------------------------------------------------------- + +// The first frame a behavior begins schedule selection, it won't have had it's GatherConditions() +// called. To fix this, BeginScheduleSelection() manually calls the new behavior's GatherConditions(), +// but sets this global so that the baseclass GatherConditions() isn't called as well. +extern bool g_bBehaviorHost_PreventBaseClassGatherConditions; + +//----------------------------------------------------------------------------- + +inline void CAI_BehaviorBase::BridgeOnStartSchedule( int scheduleType ) +{ + int localId = AI_IdIsGlobal( scheduleType ) ? GetClassScheduleIdSpace()->ScheduleGlobalToLocal( scheduleType ) : scheduleType; + OnStartSchedule( localId ); +} + +//------------------------------------- + +inline int CAI_BehaviorBase::BridgeSelectSchedule() +{ + int result = SelectSchedule(); + + if ( IsBehaviorSchedule( result ) ) + return GetClassScheduleIdSpace()->ScheduleLocalToGlobal( result ); + + return result; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeSelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode, int *pResult ) +{ + m_fOverrode = true; + int result = SelectFailSchedule( failedSchedule, failedTask, taskFailCode ); + if ( m_fOverrode ) + { + if ( result != SCHED_NONE ) + { + if ( IsBehaviorSchedule( result ) ) + *pResult = GetClassScheduleIdSpace()->ScheduleLocalToGlobal( result ); + else + *pResult = result; + return true; + } + Warning( "An AI behavior is in control but has no recommended schedule\n" ); + } + return false; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeStartTask( const Task_t *pTask ) +{ + m_fOverrode = true; + StartTask( pTask ); + return m_fOverrode; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeRunTask( const Task_t *pTask) +{ + m_fOverrode = true; + RunTask( pTask ); + return m_fOverrode; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeAimGun( void ) +{ + m_fOverrode = true; + AimGun(); + return m_fOverrode; +} + +//------------------------------------- + +inline void CAI_BehaviorBase::ChainStartTask( int task, float taskData ) +{ + Task_t tempTask = { task, taskData }; + + bool fPrevOverride = m_fOverrode; + GetOuter()->StartTask( (const Task_t *)&tempTask ); + m_fOverrode = fPrevOverride;; +} + +//------------------------------------- + +inline void CAI_BehaviorBase::ChainRunTask( int task, float taskData ) +{ + Task_t tempTask = { task, taskData }; + bool fPrevOverride = m_fOverrode; + GetOuter()->RunTask( (const Task_t *) &tempTask ); + m_fOverrode = fPrevOverride;; +} + +//------------------------------------- + +inline int CAI_BehaviorBase::BridgeTranslateSchedule( int scheduleType ) +{ + int localId = AI_IdIsGlobal( scheduleType ) ? GetClassScheduleIdSpace()->ScheduleGlobalToLocal( scheduleType ) : scheduleType; + int result = TranslateSchedule( localId ); + + return result; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeGetSchedule( int localScheduleID, CAI_Schedule **ppResult ) +{ + *ppResult = GetSchedule( localScheduleID ); + return (*ppResult != NULL ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeTaskName( int taskID, const char **ppResult ) +{ + if ( AI_IdIsLocal( taskID ) ) + { + *ppResult = GetSchedulingSymbols()->TaskIdToSymbol( GetClassScheduleIdSpace()->TaskLocalToGlobal( taskID ) ); + return (*ppResult != NULL ); + } + return false; +} + +//------------------------------------- + +inline Activity CAI_BehaviorBase::BridgeNPC_TranslateActivity( Activity activity ) +{ + return NPC_TranslateActivity( activity ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsCurTaskContinuousMove( bool *pResult ) +{ + bool fPrevOverride = m_fOverrode; + m_fOverrode = true; + *pResult = IsCurTaskContinuousMove(); + bool result = m_fOverrode; + m_fOverrode = fPrevOverride; + return result; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeFValidateHintType( CAI_Hint *pHint, bool *pResult ) +{ + bool fPrevOverride = m_fOverrode; + m_fOverrode = true; + *pResult = FValidateHintType( pHint ); + bool result = m_fOverrode; + m_fOverrode = fPrevOverride; + return result; +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsValidEnemy( CBaseEntity *pEnemy ) +{ + return IsValidEnemy( pEnemy ); +} + +//------------------------------------- + +inline CBaseEntity *CAI_BehaviorBase::BridgeBestEnemy() +{ + return BestEnemy(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsValidCover( const Vector &vLocation, CAI_Hint const *pHint ) +{ + return IsValidCover( vLocation, pHint ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ) +{ + return IsValidShootPosition( vLocation, pNode, pHint ); +} + +//------------------------------------- + +inline float CAI_BehaviorBase::BridgeGetMaxTacticalLateralMovement( void ) +{ + return GetMaxTacticalLateralMovement(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeShouldIgnoreSound( CSound *pSound ) +{ + return ShouldIgnoreSound( pSound ); +} + +//------------------------------------- + +inline void CAI_BehaviorBase::BridgeOnSeeEntity( CBaseEntity *pEntity ) +{ + OnSeeEntity( pEntity ); +} + +//------------------------------------- + +inline void CAI_BehaviorBase::BridgeOnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) +{ + OnFriendDamaged( pSquadmate, pAttacker ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsInterruptable( void ) +{ + return IsInterruptable(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsNavigationUrgent( void ) +{ + return IsNavigationUrgent(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeCanFlinch( void ) +{ + return CanFlinch(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsCrouching( void ) +{ + return IsCrouching(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeIsCrouchedActivity( Activity activity ) +{ + return IsCrouchedActivity( activity ); +} + +inline bool CAI_BehaviorBase::BridgeQueryHearSound( CSound *pSound ) +{ + return QueryHearSound( pSound ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeCanRunAScriptedNPCInteraction( bool bForced ) +{ + return CanRunAScriptedNPCInteraction( bForced ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeShouldPlayerAvoid( void ) +{ + return ShouldPlayerAvoid(); +} + +//------------------------------------- + +inline int CAI_BehaviorBase::BridgeOnTakeDamage_Alive( const CTakeDamageInfo &info ) +{ + return OnTakeDamage_Alive( info ); +} + +//------------------------------------- + +inline float CAI_BehaviorBase::BridgeGetReasonableFacingDist( void ) +{ + return GetReasonableFacingDist(); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeShouldAlwaysThink( bool *pResult ) +{ + bool fPrevOverride = m_fOverrode; + m_fOverrode = true; + *pResult = ShouldAlwaysThink(); + bool result = m_fOverrode; + m_fOverrode = fPrevOverride; + return result; +} + +//------------------------------------- + +inline void CAI_BehaviorBase::BridgeOnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) +{ + OnChangeActiveWeapon( pOldWeapon, pNewWeapon ); +} + +//------------------------------------- + +inline bool CAI_BehaviorBase::BridgeSpeakMapmakerInterruptConcept( string_t iszConcept ) +{ + return SpeakMapmakerInterruptConcept( iszConcept ); +} + +//------------------------------------- + +inline void CAI_BehaviorBase::BridgeOnRestore() +{ + OnRestore(); +} + +//------------------------------------- + +inline float CAI_BehaviorBase::BridgeGetDefaultNavGoalTolerance() +{ + return GetDefaultNavGoalTolerance(); +} + +//----------------------------------------------------------------------------- + +inline Activity CAI_BehaviorBase::BridgeGetFlinchActivity( bool bHeavyDamage, bool bGesture ) +{ + return GetFlinchActivity( bHeavyDamage, bGesture ); +} + +//----------------------------------------------------------------------------- + +inline bool CAI_BehaviorBase::BridgeOnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + return OnCalcBaseMove( pMoveGoal, distClear, pResult ); +} + +//----------------------------------------------------------------------------- + +inline void CAI_BehaviorBase::BridgeModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ) +{ + ModifyOrAppendCriteria( criteriaSet ); +} + +//----------------------------------------------------------------------------- + +inline void CAI_BehaviorBase::BridgeTeleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) +{ + Teleport( newPosition, newAngles, newVelocity ); +} + +//----------------------------------------------------------------------------- + +inline void CAI_BehaviorBase::BridgeHandleAnimEvent( animevent_t *pEvent ) +{ + HandleAnimEvent( pEvent ); +} + +//----------------------------------------------------------------------------- + +template +inline void CAI_BehaviorHost::CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ) +{ + DeferSchedulingToBehavior( NULL ); + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeCleanupOnDeath( pCulprit, bFireDeathOutput ); + } + BaseClass::CleanupOnDeath( pCulprit, bFireDeathOutput ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::GatherConditions() +{ + // Iterate over behaviors and call GatherConditionsNotActive() on each behavior + // not currently active. + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + if( m_Behaviors[i] != m_pCurBehavior ) + { + m_Behaviors[i]->GatherConditionsNotActive(); + } + } + + if ( m_pCurBehavior ) + m_pCurBehavior->BridgeGatherConditions(); + else + BaseClass::GatherConditions(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BackBridge_GatherConditions() +{ + if ( g_bBehaviorHost_PreventBaseClassGatherConditions ) + return; + + BaseClass::GatherConditions(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnScheduleChange() +{ + if ( m_pCurBehavior ) + m_pCurBehavior->BridgeOnScheduleChange(); + BaseClass::OnScheduleChange(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnStartSchedule( int scheduleType ) +{ + if ( m_pCurBehavior ) + m_pCurBehavior->BridgeOnStartSchedule( scheduleType ); + BaseClass::OnStartSchedule( scheduleType ); +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::BackBridge_SelectSchedule() +{ + return BaseClass::SelectSchedule(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BehaviorSelectSchedule() +{ + for ( int i = 0; i < m_Behaviors.Count(); i++ ) + { + if ( m_Behaviors[i]->CanSelectSchedule() && ShouldBehaviorSelectSchedule( m_Behaviors[i] ) ) + { + DeferSchedulingToBehavior( m_Behaviors[i] ); + return true; + } + } + + DeferSchedulingToBehavior( NULL ); + return false; +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsRunningBehavior() const +{ + return ( m_pCurBehavior != NULL ); +} + +//------------------------------------- + +template +inline CAI_BehaviorBase *CAI_BehaviorHost::GetRunningBehavior() +{ + return m_pCurBehavior; +} + +//------------------------------------- + +template +inline CAI_Schedule *CAI_BehaviorHost::GetNewSchedule() +{ + m_bCalledBehaviorSelectSchedule = false; + CAI_Schedule *pResult = BaseClass::GetNewSchedule(); + if ( !m_bCalledBehaviorSelectSchedule && m_pCurBehavior ) + DeferSchedulingToBehavior( NULL ); + return pResult; +} + +//------------------------------------- + +template +inline CAI_Schedule *CAI_BehaviorHost::GetFailSchedule() +{ + m_bCalledBehaviorSelectSchedule = false; + CAI_Schedule *pResult = BaseClass::GetFailSchedule(); + if ( !m_bCalledBehaviorSelectSchedule && m_pCurBehavior ) + DeferSchedulingToBehavior( NULL ); + return pResult; +} + +//------------------------------------ + +template +inline void CAI_BehaviorHost::ChangeBehaviorTo( CAI_BehaviorBase *pNewBehavior ) +{ + bool change = ( m_pCurBehavior != pNewBehavior ); + CAI_BehaviorBase *pOldBehavior = m_pCurBehavior; + m_pCurBehavior = pNewBehavior; + + if ( change ) + { + if ( m_pCurBehavior ) + { + m_pCurBehavior->BeginScheduleSelection(); + + g_bBehaviorHost_PreventBaseClassGatherConditions = true; + m_pCurBehavior->GatherConditions(); + g_bBehaviorHost_PreventBaseClassGatherConditions = false; + } + + if ( pOldBehavior ) + { + pOldBehavior->EndScheduleSelection(); + this->VacateStrategySlot(); + } + + OnChangeRunningBehavior( pOldBehavior, pNewBehavior ); + } +} + +//------------------------------------- + +template +inline CAI_BehaviorBase *CAI_BehaviorHost::DeferSchedulingToBehavior( CAI_BehaviorBase *pNewBehavior ) +{ + CAI_BehaviorBase *pOldBehavior = m_pCurBehavior; + ChangeBehaviorTo( pNewBehavior ); + return pOldBehavior; +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::BackBridge_TranslateSchedule( int scheduleType ) +{ + return BaseClass::TranslateSchedule( scheduleType ); +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::TranslateSchedule( int scheduleType ) +{ + if ( m_pCurBehavior ) + { + return m_pCurBehavior->BridgeTranslateSchedule( scheduleType ); + } + return BaseClass::TranslateSchedule( scheduleType ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::PrescheduleThink() +{ + BaseClass::PrescheduleThink(); + if ( m_pCurBehavior ) + m_pCurBehavior->BridgePrescheduleThink(); +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::SelectSchedule() +{ + m_bCalledBehaviorSelectSchedule = true; + if ( m_pCurBehavior ) + { + return m_pCurBehavior->BridgeSelectSchedule(); + } + + return BaseClass::SelectSchedule(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::KeepRunningBehavior() +{ + if ( m_pCurBehavior ) + m_bCalledBehaviorSelectSchedule = true; +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ) +{ + m_bCalledBehaviorSelectSchedule = true; + int result = 0; + if ( m_pCurBehavior && m_pCurBehavior->BridgeSelectFailSchedule( failedSchedule, failedTask, taskFailCode, &result ) ) + return result; + return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::StartTask( const Task_t *pTask ) +{ + if ( m_pCurBehavior && m_pCurBehavior->BridgeStartTask( pTask ) ) + return; + BaseClass::StartTask( pTask ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::RunTask( const Task_t *pTask ) +{ + if ( m_pCurBehavior && m_pCurBehavior->BridgeRunTask( pTask ) ) + return; + BaseClass::RunTask( pTask ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::AimGun( void ) +{ + if ( m_pCurBehavior && m_pCurBehavior->BridgeAimGun() ) + return; + BaseClass::AimGun(); +} + +//------------------------------------- + +template +inline CAI_Schedule *CAI_BehaviorHost::GetSchedule(int localScheduleID) +{ + CAI_Schedule *pResult; + if ( m_pCurBehavior && m_pCurBehavior->BridgeGetSchedule( localScheduleID, &pResult ) ) + return pResult; + return BaseClass::GetSchedule( localScheduleID ); +} + +//------------------------------------- + +template +inline const char *CAI_BehaviorHost::TaskName(int taskID) +{ + const char *pszResult = NULL; + if ( m_pCurBehavior && m_pCurBehavior->BridgeTaskName( taskID, &pszResult ) ) + return pszResult; + return BaseClass::TaskName( taskID ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BuildScheduleTestBits() +{ + if ( m_pCurBehavior ) + m_pCurBehavior->BridgeBuildScheduleTestBits(); + BaseClass::BuildScheduleTestBits(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnChangeHintGroup( string_t oldGroup, string_t newGroup ) +{ + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeOnChangeHintGroup( oldGroup, newGroup ); + } + BaseClass::OnChangeHintGroup( oldGroup, newGroup ); +} + +//------------------------------------- + +template +inline Activity CAI_BehaviorHost::BackBridge_NPC_TranslateActivity( Activity activity ) +{ + return BaseClass::NPC_TranslateActivity( activity ); +} + +//------------------------------------- + +template +inline Activity CAI_BehaviorHost::NPC_TranslateActivity( Activity activity ) +{ + if ( m_pCurBehavior ) + { + return m_pCurBehavior->BridgeNPC_TranslateActivity( activity ); + } + return BaseClass::NPC_TranslateActivity( activity ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsCurTaskContinuousMove() +{ + bool result = false; + if ( m_pCurBehavior && m_pCurBehavior->BridgeIsCurTaskContinuousMove( &result ) ) + return result; + return BaseClass::IsCurTaskContinuousMove(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnMovementFailed() +{ + if ( m_pCurBehavior ) + m_pCurBehavior->BridgeOnMovementFailed(); + BaseClass::OnMovementFailed(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnMovementComplete() +{ + if ( m_pCurBehavior ) + m_pCurBehavior->BridgeOnMovementComplete(); + BaseClass::OnMovementComplete(); +} + +//------------------------------------- + +template +inline float CAI_BehaviorHost::GetDefaultNavGoalTolerance() +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeGetDefaultNavGoalTolerance(); + return BaseClass::GetDefaultNavGoalTolerance(); +} + +//------------------------------------- + +template +inline float CAI_BehaviorHost::BackBridge_GetDefaultNavGoalTolerance() +{ + return BaseClass::GetDefaultNavGoalTolerance(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::FValidateHintType( CAI_Hint *pHint ) +{ + bool result = false; + if ( m_pCurBehavior && m_pCurBehavior->BridgeFValidateHintType( pHint, &result ) ) + return result; + return BaseClass::FValidateHintType( pHint ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsValidEnemy(CBaseEntity *pEnemy) +{ + return BaseClass::IsValidEnemy( pEnemy ); +} + +//------------------------------------- + +template +inline CBaseEntity *CAI_BehaviorHost::BackBridge_BestEnemy(void) +{ + return BaseClass::BestEnemy(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ) +{ + return BaseClass::IsValidCover( vLocation, pHint ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ) +{ + return BaseClass::IsValidShootPosition( vLocation, pNode, pHint ); +} + +//------------------------------------- + +template +inline float CAI_BehaviorHost::BackBridge_GetMaxTacticalLateralMovement( void ) +{ + return BaseClass::GetMaxTacticalLateralMovement(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_ShouldIgnoreSound( CSound *pSound ) +{ + return BaseClass::ShouldIgnoreSound( pSound ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BackBridge_OnSeeEntity( CBaseEntity *pEntity ) +{ + BaseClass::OnSeeEntity( pEntity ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) +{ + BaseClass::OnFriendDamaged( pSquadmate, pAttacker ); +} + + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsInterruptable( void ) +{ + return BaseClass::IsInterruptable(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsNavigationUrgent( void ) +{ + return BaseClass::IsNavigationUrgent(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_CanFlinch( void ) +{ + return BaseClass::CanFlinch(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsCrouching( void ) +{ + return BaseClass::IsCrouching(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_IsCrouchedActivity( Activity activity ) +{ + return BaseClass::IsCrouchedActivity( activity ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_QueryHearSound( CSound *pSound ) +{ + return BaseClass::QueryHearSound( pSound ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_CanRunAScriptedNPCInteraction( bool bForced ) +{ + return BaseClass::CanRunAScriptedNPCInteraction( bForced ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_ShouldPlayerAvoid( void ) +{ + return BaseClass::ShouldPlayerAvoid(); +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info ) +{ + return BaseClass::OnTakeDamage_Alive( info ); +} + +//------------------------------------- + +template +inline float CAI_BehaviorHost::BackBridge_GetReasonableFacingDist( void ) +{ + return BaseClass::GetReasonableFacingDist(); +} + +//------------------------------------- + +template +inline Activity CAI_BehaviorHost::BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture ) +{ + return BaseClass::GetFlinchActivity( bHeavyDamage, bGesture ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + return BaseClass::OnCalcBaseMove( pMoveGoal, distClear, pResult ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet &criteriaSet ) +{ + BaseClass::ModifyOrAppendCriteria( criteriaSet ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) +{ + BaseClass::Teleport( newPosition, newAngles, newVelocity ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::BackBridge_HandleAnimEvent( animevent_t *pEvent ) +{ + BaseClass::HandleAnimEvent( pEvent ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsValidEnemy( CBaseEntity *pEnemy ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsValidEnemy( pEnemy ); + + return BaseClass::IsValidEnemy( pEnemy ); +} + +//------------------------------------- + +template +inline CBaseEntity *CAI_BehaviorHost::BestEnemy() +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeBestEnemy(); + + return BaseClass::BestEnemy(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::ShouldAlwaysThink() +{ + bool result = false; + if ( m_pCurBehavior && m_pCurBehavior->BridgeShouldAlwaysThink( &result ) ) + return result; + return BaseClass::ShouldAlwaysThink(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) +{ + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeOnChangeActiveWeapon( pOldWeapon, pNewWeapon ); + } + BaseClass::OnChangeActiveWeapon( pOldWeapon, pNewWeapon ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::SpeakMapmakerInterruptConcept( string_t iszConcept ) +{ + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + if ( m_Behaviors[i]->BridgeSpeakMapmakerInterruptConcept( iszConcept ) ) + return true; + } + + return false; +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnRestore() +{ + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeOnRestore(); + } + BaseClass::OnRestore(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsValidCover( vLocation, pHint ); + + return BaseClass::IsValidCover( vLocation, pHint ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsValidShootPosition( vLocation, pNode, pHint ); + + return BaseClass::IsValidShootPosition( vLocation, pNode, pHint ); +} + +//------------------------------------- + +template +inline float CAI_BehaviorHost::GetMaxTacticalLateralMovement( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeGetMaxTacticalLateralMovement(); + + return BaseClass::GetMaxTacticalLateralMovement(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::ShouldIgnoreSound( CSound *pSound ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeShouldIgnoreSound( pSound ); + + return BaseClass::ShouldIgnoreSound( pSound ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnSeeEntity( CBaseEntity *pEntity ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeOnSeeEntity( pEntity ); + + BaseClass::OnSeeEntity( pEntity ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeOnFriendDamaged( pSquadmate, pAttacker ); + + BaseClass::OnFriendDamaged( pSquadmate, pAttacker ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsInterruptable( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsInterruptable(); + + return BaseClass::IsInterruptable(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsNavigationUrgent( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsNavigationUrgent(); + + return BaseClass::IsNavigationUrgent(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::CanFlinch( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeCanFlinch(); + + return BaseClass::CanFlinch(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsCrouching( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsCrouching(); + + return BaseClass::IsCrouching(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::IsCrouchedActivity( Activity activity ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeIsCrouchedActivity( activity ); + + return BaseClass::IsCrouchedActivity( activity ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::QueryHearSound( CSound *pSound ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeQueryHearSound( pSound ); + + return BaseClass::QueryHearSound( pSound ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::CanRunAScriptedNPCInteraction( bool bForced ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeCanRunAScriptedNPCInteraction( bForced ); + + return BaseClass::CanRunAScriptedNPCInteraction( bForced ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::ShouldPlayerAvoid( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeShouldPlayerAvoid(); + + return BaseClass::ShouldPlayerAvoid(); +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::OnTakeDamage_Alive( const CTakeDamageInfo &info ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeOnTakeDamage_Alive( info ); + + return BaseClass::OnTakeDamage_Alive( info ); +} + +//------------------------------------- + +template +inline float CAI_BehaviorHost::GetReasonableFacingDist( void ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeGetReasonableFacingDist(); + + return BaseClass::GetReasonableFacingDist(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::Precache() +{ + BaseClass::Precache(); + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgePrecache(); + } +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity ) +{ + // If a behavior is active, we need to stop running it + ChangeBehaviorTo( NULL ); + + return BaseClass::ScheduledMoveToGoalEntity( scheduleType, pGoalEntity, movementActivity ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity ) +{ + // If a behavior is active, we need to stop running it + ChangeBehaviorTo( NULL ); + + return BaseClass::ScheduledFollowPath( scheduleType, pPathStart, movementActivity ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun) +{ + // If a behavior is active, we need to stop running it + ChangeBehaviorTo( NULL ); + + BaseClass::ForceSelectedGo(pPlayer, targetPos, traceDir, bRun); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::ForceSelectedGoRandom(void) +{ + // If a behavior is active, we need to stop running it + ChangeBehaviorTo( NULL ); + + BaseClass::ForceSelectedGoRandom(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::NPCInit() +{ + BaseClass::NPCInit(); + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeSpawn(); + } +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::UpdateOnRemove() +{ + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeUpdateOnRemove(); + } + BaseClass::UpdateOnRemove(); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::Event_Killed( const CTakeDamageInfo &info ) +{ + for( int i = 0; i < m_Behaviors.Count(); i++ ) + { + m_Behaviors[i]->BridgeEvent_Killed( info ); + } + BaseClass::Event_Killed( info ); +} + +//------------------------------------- + +template +inline Activity CAI_BehaviorHost::GetFlinchActivity( bool bHeavyDamage, bool bGesture ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeGetFlinchActivity( bHeavyDamage, bGesture ); + + return BaseClass::GetFlinchActivity( bHeavyDamage, bGesture ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeOnCalcBaseMove( pMoveGoal, distClear, pResult ); + + return BaseClass::OnCalcBaseMove( pMoveGoal, distClear, pResult ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::ModifyOrAppendCriteria( AI_CriteriaSet &criteriaSet ) +{ + BaseClass::ModifyOrAppendCriteria( criteriaSet ); + + if ( m_pCurBehavior ) + { + // Append active behavior name + criteriaSet.AppendCriteria( "active_behavior", GetRunningBehavior()->GetName() ); + + m_pCurBehavior->BridgeModifyOrAppendCriteria( criteriaSet ); + return; + } +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) +{ + if ( m_pCurBehavior ) + { + m_pCurBehavior->BridgeTeleport( newPosition, newAngles, newVelocity ); + return; + } + + BaseClass::Teleport( newPosition, newAngles, newVelocity ); +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::HandleAnimEvent( animevent_t *pEvent ) +{ + if ( m_pCurBehavior ) + return m_pCurBehavior->BridgeHandleAnimEvent( pEvent ); + + return BaseClass::HandleAnimEvent( pEvent ); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule ) +{ + if ( pBehavior == GetRunningBehavior() && !pBehavior->CanSelectSchedule() && !fCanFinishSchedule ) + { + DeferSchedulingToBehavior( NULL ); + return true; + } + return false; +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ) +{ +} + +//------------------------------------- + +template +inline void CAI_BehaviorHost::AddBehavior( CAI_BehaviorBase *pBehavior ) +{ +#ifdef DEBUG + Assert( m_Behaviors.Find( pBehavior ) == m_Behaviors.InvalidIndex() ); + Assert( m_fDebugInCreateBehaviors ); + for ( int i = 0; i < m_Behaviors.Count(); i++) + { + Assert( typeid(*m_Behaviors[i]) != typeid(*pBehavior) ); + } +#endif + m_Behaviors.AddToTail( pBehavior ); + pBehavior->SetOuter( this ); + pBehavior->SetBackBridge( this ); +} + +//------------------------------------- + +template +inline CAI_BehaviorBase **CAI_BehaviorHost::AccessBehaviors() +{ + if (m_Behaviors.Count()) + return m_Behaviors.Base(); + return NULL; +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::NumBehaviors() +{ + return m_Behaviors.Count(); +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::Save( ISave &save ) +{ + int result = BaseClass::Save( save ); + if ( result ) + CAI_BehaviorBase::SaveBehaviors( save, m_pCurBehavior, AccessBehaviors(), NumBehaviors() ); + return result; +} + +//------------------------------------- + +template +inline int CAI_BehaviorHost::Restore( IRestore &restore ) +{ + int result = BaseClass::Restore( restore ); + if ( result ) + { + int iCurrent = CAI_BehaviorBase::RestoreBehaviors( restore, AccessBehaviors(), NumBehaviors() ); + if ( iCurrent != -1 ) + m_pCurBehavior = AccessBehaviors()[iCurrent]; + else + m_pCurBehavior = NULL; + } + return result; +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::CreateComponents() +{ + if ( BaseClass::CreateComponents() ) + { +#ifdef DEBUG + m_fDebugInCreateBehaviors = true; +#endif + bool result = CreateBehaviors(); +#ifdef DEBUG + m_fDebugInCreateBehaviors = false; +#endif + return result; + } + return false; +} + +//----------------------------------------------------------------------------- + +#endif // AI_BEHAVIOR_H diff --git a/game/server/ai_behavior_assault.h b/game/server/ai_behavior_assault.h new file mode 100644 index 0000000..e927def --- /dev/null +++ b/game/server/ai_behavior_assault.h @@ -0,0 +1,299 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_ASSAULT_H +#define AI_BEHAVIOR_ASSAULT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "simtimer.h" +#include "ai_behavior.h" +#include "ai_goalentity.h" +#include "ai_moveshoot.h" +#include "ai_utils.h" + +#define CUE_POINT_TOLERANCE (3.0*12.0) + +enum RallySelectMethod_t +{ + RALLY_POINT_SELECT_DEFAULT = 0, + RALLY_POINT_SELECT_RANDOM, +}; + +enum AssaultCue_t +{ + CUE_NO_ASSAULT = 0, // used to indicate that no assault is being conducted presently + + CUE_ENTITY_INPUT = 1, + CUE_PLAYER_GUNFIRE, + CUE_DONT_WAIT, + CUE_COMMANDER, + CUE_NONE, +}; + +enum +{ + ASSAULT_SENTENCE_HIT_RALLY_POINT = SENTENCE_BASE_BEHAVIOR_INDEX, + ASSAULT_SENTENCE_HIT_ASSAULT_POINT, + ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_RALLY, + ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_ASSAULT, + ASSAULT_SENTENCE_COVER_NO_AMMO, + ASSAULT_SENTENCE_UNDER_ATTACK, +}; + +// Allow diversion from the assault up to this amount of time after last having an enemy +#define ASSAULT_DIVERSION_TIME 4 + +#define SF_ASSAULTPOINT_CLEARONARRIVAL 0x00000001 + +//============================================================================= +//============================================================================= +class CRallyPoint : public CPointEntity +{ + DECLARE_CLASS( CRallyPoint, CPointEntity ); + +public: + CRallyPoint() + { + m_hLockedBy.Set(NULL); + m_sExclusivity = RALLY_EXCLUSIVE_NOT_EVALUATED; + } + + bool Lock( CBaseEntity *pLocker ) + { + if( IsLocked() ) + { + // Already locked. + return false; + } + + m_hLockedBy.Set( pLocker ); + return true; + } + + bool Unlock( CBaseEntity *pUnlocker ) + { + if( IsLocked() ) + { + if( m_hLockedBy.Get() != pUnlocker ) + { + // Refuse! Only the locker may unlock. + return false; + } + } + + m_hLockedBy.Set( NULL ); + return true; + } + + bool IsLocked( void ) { return (m_hLockedBy.Get() != NULL); } + + int DrawDebugTextOverlays(); + bool IsExclusive(); + + enum + { + RALLY_EXCLUSIVE_NOT_EVALUATED = -1, + RALLY_EXCLUSIVE_NO, + RALLY_EXCLUSIVE_YES, + }; + + string_t m_AssaultPointName; + string_t m_RallySequenceName; + float m_flAssaultDelay; + int m_iPriority; + int m_iStrictness; + bool m_bForceCrouch; + bool m_bIsUrgent; + short m_sExclusivity; + + COutputEvent m_OnArrival; + + DECLARE_DATADESC(); + +private: + EHANDLE m_hLockedBy; +}; + +//============================================================================= +//============================================================================= +class CAssaultPoint : public CPointEntity +{ + DECLARE_CLASS( CAssaultPoint, CPointEntity ); + +public: + CAssaultPoint() + { + // This used to be a constant in code. Now it's a keyfield in hammer. + // So in the constructor, we set this value to the former constant + // default value, for legacy maps. (sjb) + m_flAssaultPointTolerance = CUE_POINT_TOLERANCE; + } + + void InputSetClearOnContact( inputdata_t &inputdata ) + { + m_bClearOnContact = inputdata.value.Bool(); + } + + void InputSetAllowDiversion( inputdata_t &inputdata ) + { + m_bAllowDiversion = inputdata.value.Bool(); + } + + void InputSetForceClear( inputdata_t &inputdata ) + { + m_bInputForcedClear = inputdata.value.Bool(); + } + +public: + string_t m_AssaultHintGroup; + string_t m_NextAssaultPointName; + COutputEvent m_OnAssaultClear; + float m_flAssaultTimeout; + bool m_bClearOnContact; + bool m_bAllowDiversion; + float m_flAllowDiversionRadius; + bool m_bNeverTimeout; + int m_iStrictness; + bool m_bForceCrouch; + bool m_bIsUrgent; + bool m_bInputForcedClear; + float m_flAssaultPointTolerance; + float m_flTimeLastUsed; + + COutputEvent m_OnArrival; + + DECLARE_DATADESC(); +}; + +//============================================================================= +//============================================================================= +class CAI_AssaultBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_AssaultBehavior, CAI_SimpleBehavior ); + +public: + CAI_AssaultBehavior(); + + virtual const char *GetName() { return "Assault"; } + virtual int DrawDebugTextOverlays( int text_offset ); + + virtual void OnRestore(); + + bool CanRunAScriptedNPCInteraction( bool bForced ); + + virtual bool CanSelectSchedule(); + virtual void BeginScheduleSelection(); + virtual void EndScheduleSelection(); + + bool HasHitRallyPoint() { return m_bHitRallyPoint; } + bool HasHitAssaultPoint() { return m_bHitAssaultPoint; } + + void ClearAssaultPoint( void ); + void OnHitAssaultPoint( void ); + bool PollAssaultCue( void ); + void ReceiveAssaultCue( AssaultCue_t cue ); + bool HasAssaultCue( void ) { return m_AssaultCue != CUE_NO_ASSAULT; } + bool AssaultHasBegun(); + + CAssaultPoint *FindAssaultPoint( string_t iszAssaultPointName ); + void SetAssaultPoint( CAssaultPoint *pAssaultPoint ); + + void GatherConditions( void ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void BuildScheduleTestBits(); + int TranslateSchedule( int scheduleType ); + void OnStartSchedule( int scheduleType ); + void ClearSchedule( const char *szReason ); + + void InitializeBehavior(); + void SetParameters( string_t rallypointname, AssaultCue_t assaultcue, int rallySelectMethod ); + void SetParameters( CBaseEntity *pRallyEnt, AssaultCue_t assaultcue ); + + bool IsAllowedToDivert( void ); + bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + float GetMaxTacticalLateralMovement( void ); + + void UpdateOnRemove(); + + bool OnStrictAssault( void ); + bool UpdateForceCrouch( void ); + bool IsForcingCrouch( void ); + bool IsUrgent( void ); + + CRallyPoint *FindBestRallyPointInRadius( const Vector &vecCenter, float flRadius );; + + void Disable( void ) { m_AssaultCue = CUE_NO_ASSAULT; m_bHitRallyPoint = false; m_bHitAssaultPoint = false; } + + enum + { + SCHED_MOVE_TO_RALLY_POINT = BaseClass::NEXT_SCHEDULE, // Try to get out of the player's way + SCHED_ASSAULT_FAILED_TO_MOVE, + SCHED_FAIL_MOVE_TO_RALLY_POINT, + SCHED_MOVE_TO_ASSAULT_POINT, + SCHED_AT_ASSAULT_POINT, + SCHED_HOLD_RALLY_POINT, + SCHED_HOLD_ASSAULT_POINT, + SCHED_WAIT_AND_CLEAR, + SCHED_ASSAULT_MOVE_AWAY, + SCHED_CLEAR_ASSAULT_POINT, + NEXT_SCHEDULE, + + TASK_GET_PATH_TO_RALLY_POINT = BaseClass::NEXT_TASK, + TASK_FACE_RALLY_POINT, + TASK_GET_PATH_TO_ASSAULT_POINT, + TASK_FACE_ASSAULT_POINT, + TASK_HIT_ASSAULT_POINT, + TASK_HIT_RALLY_POINT, + TASK_AWAIT_CUE, + TASK_AWAIT_ASSAULT_TIMEOUT, + TASK_ANNOUNCE_CLEAR, + TASK_WAIT_ASSAULT_DELAY, + TASK_ASSAULT_MOVE_AWAY_PATH, + TASK_ASSAULT_DEFER_SCHEDULE_SELECTION, + NEXT_TASK, + +/* + COND_PUT_CONDITIONS_HERE = BaseClass::NEXT_CONDITION, + NEXT_CONDITION, +*/ + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +public: + CHandle m_hAssaultPoint; + CHandle m_hRallyPoint; + +public: + void UnlockRallyPoint( void ); + +private: + void OnScheduleChange(); + virtual int SelectSchedule(); + + AssaultCue_t m_AssaultCue; // the cue we're waiting for to begin the assault + AssaultCue_t m_ReceivedAssaultCue; // the last assault cue we received from someone/thing external. + + bool m_bHitRallyPoint; + bool m_bHitAssaultPoint; + + // Diversion + bool m_bDiverting; + float m_flLastSawAnEnemyAt; + + float m_flTimeDeferScheduleSelection; + + string_t m_AssaultPointName; + + //--------------------------------- + + DECLARE_DATADESC(); +}; + +#endif // AI_BEHAVIOR_ASSAULT_H diff --git a/game/server/ai_behavior_fear.h b/game/server/ai_behavior_fear.h new file mode 100644 index 0000000..b13848c --- /dev/null +++ b/game/server/ai_behavior_fear.h @@ -0,0 +1,98 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Deal intelligently with an enemy that we're afraid of +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef AI_BEHAVIOR_FEAR_H +#define AI_BEHAVIOR_FEAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior.h" + +class CAI_FearBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_FearBehavior, CAI_SimpleBehavior ); + +public: + CAI_FearBehavior(); + + void Precache( void ); + virtual const char *GetName() { return "Fear"; } + + virtual bool CanSelectSchedule(); + void GatherConditions(); + + virtual void BeginScheduleSelection(); + virtual void EndScheduleSelection(); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + //void BuildScheduleTestBits(); + //int TranslateSchedule( int scheduleType ); + //void OnStartSchedule( int scheduleType ); + + //void InitializeBehavior(); + + bool EnemyDislikesMe(); + + void MarkAsUnsafe(); + bool IsInASafePlace(); + void SpoilSafePlace(); + void ReleaseAllHints(); + + CAI_Hint *FindFearWithdrawalDest(); + void BuildScheduleTestBits(); + int TranslateSchedule( int scheduleType ); + + + enum + { + SCHED_FEAR_MOVE_TO_SAFE_PLACE = BaseClass::NEXT_SCHEDULE, + SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY, + SCHED_FEAR_STAY_IN_SAFE_PLACE, + NEXT_SCHEDULE, + + TASK_FEAR_GET_PATH_TO_SAFETY_HINT = BaseClass::NEXT_TASK, + TASK_FEAR_WAIT_FOR_SAFETY, + TASK_FEAR_IN_SAFE_PLACE, + NEXT_TASK, + + COND_FEAR_ENEMY_CLOSE = BaseClass::NEXT_CONDITION, // within 30 feet + COND_FEAR_ENEMY_TOO_CLOSE, // within 5 feet + COND_FEAR_SEPARATED_FROM_PLAYER, + NEXT_CONDITION, + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +public: + +private: + virtual int SelectSchedule(); + + float m_flTimeToSafety; + float m_flTimePlayerLastVisible; + float m_flDeferUntil; + + CAI_MoveMonitor m_SafePlaceMoveMonitor; + CHandle m_hSafePlaceHint; + CHandle m_hMovingToHint; + + DECLARE_DATADESC(); +}; + +#endif // AI_BEHAVIOR_FEAR_H + + diff --git a/game/server/ai_behavior_follow.h b/game/server/ai_behavior_follow.h new file mode 100644 index 0000000..a0e4383 --- /dev/null +++ b/game/server/ai_behavior_follow.h @@ -0,0 +1,383 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_FOLLOW_H +#define AI_BEHAVIOR_FOLLOW_H + +#include "simtimer.h" +#include "ai_behavior.h" +#include "ai_goalentity.h" +#include "ai_utils.h" +#include "ai_moveshoot.h" + +#ifdef HL2_EPISODIC + #include "hl2_gamerules.h" +#endif + +#if defined( _WIN32 ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// NOTE: these must correspond with the AI_FollowFormation_t array in AI_Behavior_Follow.cpp!! +//----------------------------------------------------------------------------- +enum AI_Formations_t +{ + AIF_SIMPLE, + AIF_WIDE, + AIF_ANTLION, + AIF_COMMANDER, + AIF_TIGHT, + AIF_MEDIUM, + AIF_SIDEKICK, + AIF_HUNTER, + AIF_VORTIGAUNT, +}; + +enum AI_FollowFormationFlags_t +{ + AIFF_DEFAULT = 0, + AIFF_USE_FOLLOW_POINTS = 0x01, + AIFF_REQUIRE_LOS_OUTSIDE_COMBAT = 0x02, +}; + +//----------------------------------------------------------------------------- +// +// CAI_FollowGoal +// +// Purpose: A level tool to control the follow behavior. Use is not required +// in order to use behavior. +// +//----------------------------------------------------------------------------- + +class CAI_FollowGoal : public CAI_GoalEntity +{ + DECLARE_CLASS( CAI_FollowGoal, CAI_GoalEntity ); + +public: + + virtual void EnableGoal( CAI_BaseNPC *pAI ); + virtual void DisableGoal( CAI_BaseNPC *pAI ); +#ifdef HL2_EPISODIC + virtual void InputOutsideTransition( inputdata_t &inputdata ); +#endif + + int m_iFormation; + + DECLARE_DATADESC(); +}; + +//----------------------------------------------------------------------------- + +int AIGetNumFollowers( CBaseEntity *pEntity, string_t iszClassname = NULL_STRING ); + +//----------------------------------------------------------------------------- + +struct AI_FollowNavInfo_t +{ + int flags; + Vector position; + float range; + float Zrange; + float tolerance; + float followPointTolerance; + float targetMoveTolerance; + float repathOnRouteTolerance; + float walkTolerance; + float coverTolerance; + float enemyLOSTolerance; + float chaseEnemyTolerance; + + DECLARE_SIMPLE_DATADESC(); +}; + +struct AI_FollowGroup_t; + +struct AI_FollowManagerInfoHandle_t +{ + AI_FollowGroup_t *m_pGroup; + int m_hFollower; +}; + +//------------------------------------- + +struct AI_FollowParams_t +{ + AI_FollowParams_t( AI_Formations_t formation = AIF_SIMPLE, bool bNormalMemoryDiscard = false ) + : formation(formation), + bNormalMemoryDiscard( bNormalMemoryDiscard ) + { + } + + AI_Formations_t formation; + bool bNormalMemoryDiscard; + + DECLARE_SIMPLE_DATADESC(); +}; + +//------------------------------------- + +class CAI_FollowBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_FollowBehavior, CAI_SimpleBehavior ); +public: + CAI_FollowBehavior( const AI_FollowParams_t ¶ms = AIF_SIMPLE ); + ~CAI_FollowBehavior(); + + virtual int DrawDebugTextOverlays( int text_offset ); + virtual void DrawDebugGeometryOverlays(); + + // Returns true if the NPC is actively following a target. + bool IsActive( void ); + + void SetParameters( const AI_FollowParams_t ¶ms ); + + virtual const char *GetName() { return "Follow"; } + AI_Formations_t GetFormation() const { return m_params.formation; } + + virtual bool CanSelectSchedule(); + + const AI_FollowNavInfo_t &GetFollowGoalInfo(); + CBaseEntity * GetFollowTarget(); + void SetFollowTarget( CBaseEntity *pLeader, bool fFinishCurSchedule = false ); + + CAI_FollowGoal *GetFollowGoal() { return m_hFollowGoalEnt; } // if any + bool SetFollowGoal( CAI_FollowGoal *pGoal, bool fFinishCurSchedule = false ); + void ClearFollowGoal( CAI_FollowGoal *pGoal ); + void SetFollowGoalDirect( CAI_FollowGoal *pGoal ); + + virtual bool FarFromFollowTarget() { return ( m_hFollowTarget && (GetAbsOrigin() - m_hFollowTarget->GetAbsOrigin()).LengthSqr() > (75*12)*(75*12) ); } + + virtual bool TargetIsUnreachable() { return m_bTargetUnreachable; } + + int GetNumFailedFollowAttempts() { return m_nFailedFollowAttempts; } + float GetTimeFailFollowStarted() { return m_flTimeFailFollowStarted; } + bool FollowTargetVisible() { return HasCondition( COND_FOLLOW_TARGET_VISIBLE ); }; + + bool IsMovingToFollowTarget(); + + float GetGoalRange(); + float GetGoalZRange(); + + virtual Activity NPC_TranslateActivity( Activity activity ); + virtual int TranslateSchedule( int scheduleType ); + virtual void StartTask( const Task_t *pTask ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual void TaskComplete( bool fIgnoreSetFailedCondition = false ); + virtual void GatherConditions(); + +protected: + + const Vector &GetGoalPosition(); + + virtual bool ShouldFollow(); + + friend class CAI_FollowManager; + + virtual void BeginScheduleSelection(); + virtual void EndScheduleSelection(); + + virtual void CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ); + + virtual void Precache(); + virtual int SelectSchedule(); + virtual int FollowCallBaseSelectSchedule() { return BaseClass::SelectSchedule(); } + virtual void OnStartSchedule( int scheduleType ); + virtual void RunTask( const Task_t *pTask ); + void BuildScheduleTestBits(); + + bool IsCurScheduleFollowSchedule(); + + virtual bool IsCurTaskContinuousMove(); + virtual void OnMovementFailed(); + virtual void OnMovementComplete(); + virtual bool FValidateHintType( CAI_Hint *pHint ); + + bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ); + bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + bool FindCoverFromEnemyAtFollowTarget( float coverRadius, Vector *pResult ); + + bool ShouldAlwaysThink(); + + bool ShouldMoveToFollowTarget(); + + int SelectScheduleManagePosition(); + int SelectScheduleFollowPoints(); + int SelectScheduleMoveToFormation(); + + void GetFollowTargetViewLoc( Vector *pResult); + bool ValidateFaceTarget( Vector *pFaceTarget ); + + //---------------------------- + + bool ShouldUseFollowPoints(); + bool HasFollowPoint(); + void SetFollowPoint( CAI_Hint *pHintNode ); + void ClearFollowPoint(); + const Vector & GetFollowPoint(); + CAI_Hint * FindFollowPoint(); + bool IsFollowPointInRange(); + bool ShouldIgnoreFollowPointFacing(); + + //---------------------------- + + bool UpdateFollowPosition(); + const int GetGoalFlags(); + float GetGoalTolerance(); + bool PlayerIsPushing(); + + bool IsFollowTargetInRange( float rangeMultiplier = 1.0 ); + + bool IsFollowGoalInRange( float tolerance, float zTolerance, int flags ); + virtual bool IsChaseGoalInRange(); + + void NoteFailedFollow(); + void NoteSuccessfulFollow(); + + //---------------------------- + +protected: + + enum + { + SCHED_FOLLOWER_MOVE_AWAY_FAIL = BaseClass::NEXT_SCHEDULE, // Turn back toward player + SCHED_FOLLOWER_MOVE_AWAY_END, + SCHED_FOLLOW, + SCHED_FOLLOWER_IDLE_STAND, + SCHED_MOVE_TO_FACE_FOLLOW_TARGET, + SCHED_FACE_FOLLOW_TARGET, + SCHED_FOLLOWER_GO_TO_WAIT_POINT, + SCHED_FOLLOWER_GO_TO_WAIT_POINT_FAIL, + SCHED_FOLLOWER_STAND_AT_WAIT_POINT, + SCHED_FOLLOWER_COMBAT_FACE, + NEXT_SCHEDULE, + + TASK_CANT_FOLLOW = BaseClass::NEXT_TASK, + TASK_FACE_FOLLOW_TARGET, + TASK_MOVE_TO_FOLLOW_POSITION, + TASK_GET_PATH_TO_FOLLOW_POSITION, + TASK_SET_FOLLOW_TARGET_MARK, + TASK_FOLLOWER_FACE_TACTICAL, + TASK_SET_FOLLOW_DELAY, + TASK_GET_PATH_TO_FOLLOW_POINT, + TASK_ARRIVE_AT_FOLLOW_POINT, + TASK_SET_FOLLOW_POINT_STAND_SCHEDULE, + TASK_BEGIN_STAND_AT_WAIT_POINT, + NEXT_TASK, + + COND_TARGET_MOVED_FROM_MARK = BaseClass::NEXT_CONDITION, + COND_FOUND_WAIT_POINT, + COND_FOLLOW_DELAY_EXPIRED, + COND_FOLLOW_TARGET_VISIBLE, + COND_FOLLOW_TARGET_NOT_VISIBLE, + COND_FOLLOW_WAIT_POINT_INVALID, + COND_FOLLOW_PLAYER_IS_LIT, + COND_FOLLOW_PLAYER_IS_NOT_LIT, + NEXT_CONDITION, + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +protected: + + //---------------------------- + + EHANDLE m_hFollowTarget; + AI_FollowNavInfo_t m_FollowNavGoal; + float m_flTimeUpdatedFollowPosition; + bool m_bFirstFacing; + float m_flTimeFollowTargetVisible; + + CAI_MoveMonitor m_TargetMonitor; + bool m_bTargetUnreachable; + bool m_bFollowNavFailed; // Set when pathfinding fails to limit impact of m_FollowDelay on ShouldFollow + + int m_nFailedFollowAttempts; + float m_flTimeFailFollowStarted; + Vector m_vFollowMoveAnchor; + + bool m_bMovingToCover; + float m_flOriginalEnemyDiscardTime; + float m_SavedDistTooFar; + + CRandStopwatch m_FollowDelay; + CSimpleSimTimer m_RepathOnFollowTimer; + + //--------------------------------- + + Activity m_CurrentFollowActivity; + + //--------------------------------- + + CRandSimTimer m_TimeBlockUseWaitPoint; + CSimTimer m_TimeCheckForWaitPoint; + CAI_Hint * m_pInterruptWaitPoint; + + //--------------------------------- + + CRandSimTimer m_TimeBeforeSpreadFacing; + CRandSimTimer m_TimeNextSpreadFacing; + + //--------------------------------- + + AI_FollowManagerInfoHandle_t m_hFollowManagerInfo; + AI_FollowParams_t m_params; + + //--------------------------------- + + CHandle m_hFollowGoalEnt; + + //--------------------------------- + + DECLARE_DATADESC(); +}; + +//------------------------------------- + +inline const AI_FollowNavInfo_t &CAI_FollowBehavior::GetFollowGoalInfo() +{ + return m_FollowNavGoal; +} + +//------------------------------------- + +inline const int CAI_FollowBehavior::GetGoalFlags() +{ + return m_FollowNavGoal.flags; +} + +//------------------------------------- + +inline const Vector &CAI_FollowBehavior::GetGoalPosition() +{ + return m_FollowNavGoal.position; +} + +//------------------------------------- + +inline float CAI_FollowBehavior::GetGoalTolerance() +{ + return m_FollowNavGoal.tolerance; +} + +//------------------------------------- + +inline float CAI_FollowBehavior::GetGoalRange() +{ + return m_FollowNavGoal.range; +} + +//------------------------------------- + +inline float CAI_FollowBehavior::GetGoalZRange() +{ + return m_FollowNavGoal.Zrange; +} + +//----------------------------------------------------------------------------- + +#endif // AI_BEHAVIOR_FOLLOW_H diff --git a/game/server/ai_behavior_lead.h b/game/server/ai_behavior_lead.h new file mode 100644 index 0000000..d59a87d --- /dev/null +++ b/game/server/ai_behavior_lead.h @@ -0,0 +1,236 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_LEAD_H +#define AI_BEHAVIOR_LEAD_H + +#include "simtimer.h" +#include "ai_behavior.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +typedef const char *AIConcept_t; + +// Speak concepts +#define TLK_LEAD_START "TLK_LEAD_START" +#define TLK_LEAD_ARRIVAL "TLK_LEAD_ARRIVAL" +#define TLK_LEAD_SUCCESS "TLK_LEAD_SUCCESS" +#define TLK_LEAD_FAILURE "lead_fail" +#define TLK_LEAD_COMINGBACK "TLK_LEAD_COMINGBACK" +#define TLK_LEAD_CATCHUP "TLK_LEAD_CATCHUP" +#define TLK_LEAD_RETRIEVE "TLK_LEAD_RETRIEVE" +#define TLK_LEAD_ATTRACTPLAYER "TLK_LEAD_ATTRACTPLAYER" +#define TLK_LEAD_WAITOVER "TLK_LEAD_WAITOVER" +#define TLK_LEAD_MISSINGWEAPON "TLK_LEAD_MISSING_WEAPON" +#define TLK_LEAD_IDLE "TLK_LEAD_IDLE" + +//----------------------------------------------------------------------------- +// class CAI_LeadBehavior +// +// Purpose: +// +//----------------------------------------------------------------------------- + +enum LeadBehaviorEvents_t +{ + LBE_ARRIVAL, + LBE_ARRIVAL_DONE, + LBE_SUCCESS, + LBE_FAILURE, + LBE_DONE, +}; + +//------------------------------------- +// +// Handler class interface to listen to and modify actions of the lead behavior. +// Could be an NPC, or another entity (like a goal entity) +// + +class CAI_LeadBehaviorHandler +{ +public: + virtual void OnEvent( int event ) {} + virtual const char *GetConceptModifiers( const char *pszConcept ) { return NULL; } +}; + +//------------------------------------- + +enum AI_LeadFlags_t +{ + AILF_NO_DEF_SUCCESS = 0x01, + AILF_NO_DEF_FAILURE = 0x02, + AILF_USE_GOAL_FACING = 0x04, +}; + +struct AI_LeadArgs_t +{ + const char *pszGoal; + const char *pszWaitPoint; + unsigned flags; + float flWaitDistance; + float flLeadDistance; + float flRetrieveDistance; + float flSuccessDistance; + bool bRun; + int iRetrievePlayer; + int iRetrieveWaitForSpeak; + int iComingBackWaitForSpeak; + bool bStopScenesWhenPlayerLost; + bool bDontSpeakStart; + bool bLeadDuringCombat; + bool bGagLeader; + + DECLARE_SIMPLE_DATADESC(); +}; + + +class CAI_LeadBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_LeadBehavior, CAI_SimpleBehavior ); +public: + CAI_LeadBehavior() + : m_pSink(NULL), + m_LostTimer( 3.0, 4.0 ), + m_LostLOSTimer( 2.0, 3.0 ) + { + memset( &m_args, 0, sizeof(m_args) ); + ClearGoal(); + } + + virtual void OnRestore(); + + virtual const char *GetName() { return "Lead"; } + + virtual int DrawDebugTextOverlays( int text_offset ); + virtual bool IsNavigationUrgent(); + + void LeadPlayer( const AI_LeadArgs_t &leadArgs, CAI_LeadBehaviorHandler *pSink = NULL ); + void StopLeading( void ); + + virtual bool CanSelectSchedule(); + void BeginScheduleSelection(); + + virtual bool IsCurTaskContinuousMove(); + + bool SetGoal( const AI_LeadArgs_t &args ); + void ClearGoal() { m_goal = vec3_origin; m_waitpoint = vec3_origin; m_pSink = NULL; m_weaponname = NULL_STRING; } + bool HasGoal() const { return (m_goal != vec3_origin); } + bool HasWaitPoint() const { return (m_waitpoint != vec3_origin); } + + bool Connect( CAI_LeadBehaviorHandler *); + bool Disconnect( CAI_LeadBehaviorHandler *); + + void SetWaitForWeapon( string_t iszWeaponName ) { m_weaponname = iszWeaponName; m_flWeaponSafetyTimeOut = gpGlobals->curtime + 60; } + + enum + { + // Schedules + SCHED_LEAD_PLAYER = BaseClass::NEXT_SCHEDULE, + SCHED_LEAD_PAUSE, + SCHED_LEAD_PAUSE_COMBAT, + SCHED_LEAD_RETRIEVE, + SCHED_LEAD_RETRIEVE_WAIT, + SCHED_LEAD_SUCCEED, + SCHED_LEAD_AWAIT_SUCCESS, + SCHED_LEAD_WAITFORPLAYER, + SCHED_LEAD_WAITFORPLAYERIDLE, + SCHED_LEAD_PLAYERNEEDSWEAPON, + SCHED_LEAD_SPEAK_START, + SCHED_LEAD_SPEAK_THEN_RETRIEVE_PLAYER, + SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER, + NEXT_SCHEDULE, + + // Tasks + TASK_GET_PATH_TO_LEAD_GOAL = BaseClass::NEXT_TASK, + TASK_STOP_LEADING, + TASK_LEAD_FACE_GOAL, + TASK_LEAD_ARRIVE, + TASK_LEAD_SUCCEED, + TASK_LEAD_GET_PATH_TO_WAITPOINT, + TASK_LEAD_WAVE_TO_PLAYER, + TASK_LEAD_PLAYER_NEEDS_WEAPON, + TASK_LEAD_SPEAK_START, + TASK_LEAD_MOVE_TO_RANGE, + TASK_LEAD_RETRIEVE_WAIT, + TASK_LEAD_WALK_PATH, + NEXT_TASK, + + // Conditions + COND_LEAD_FOLLOWER_LOST = BaseClass::NEXT_CONDITION, + COND_LEAD_FOLLOWER_LAGGING, + COND_LEAD_FOLLOWER_NOT_LAGGING, + COND_LEAD_FOLLOWER_VERY_CLOSE, + COND_LEAD_SUCCESS, + COND_LEAD_HAVE_FOLLOWER_LOS, + COND_LEAD_FOLLOWER_MOVED_FROM_MARK, + COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME, + NEXT_CONDITION + + }; + +private: + + void GatherConditions(); + virtual int SelectSchedule(); + virtual int TranslateSchedule( int scheduleType ); + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + + bool GetClosestPointOnRoute( const Vector &targetPos, Vector *pVecClosestPoint ); + bool PlayerIsAheadOfMe( bool bForce = false ); + + bool Speak( AIConcept_t concept ); + bool IsSpeaking(); + + // -------------------------------- + // + // Sink notifiers. Isolated to limit exposure to actual sink storage, + // provide debugging pinch pount, and allow for class-local logic + // in addition to sink logic + // + void NotifyEvent( int event ) { if ( m_pSink ) m_pSink->OnEvent( event ) ; } + const char * GetConceptModifiers( const char *pszConcept ) { return ( m_pSink ) ? m_pSink->GetConceptModifiers( pszConcept ) : NULL; } + + // -------------------------------- + + AI_LeadArgs_t m_args; + CAI_LeadBehaviorHandler *m_pSink; + EHANDLE m_hSinkImplementor; + + // -------------------------------- + + Vector m_goal; + float m_goalyaw; + Vector m_waitpoint; + float m_waitdistance; + float m_leaddistance; + float m_retrievedistance; + float m_successdistance; + string_t m_weaponname; + bool m_run; + bool m_gagleader; + bool m_hasspokenstart; + bool m_hasspokenarrival; + bool m_hasPausedScenes; + float m_flSpeakNextNagTime; + float m_flWeaponSafetyTimeOut; + float m_flNextLeadIdle; + bool m_bInitialAheadTest; + CAI_MoveMonitor m_MoveMonitor; + + CRandStopwatch m_LostTimer; + CRandStopwatch m_LostLOSTimer; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + + DECLARE_DATADESC(); +}; + +//----------------------------------------------------------------------------- + +#endif // AI_BEHAVIOR_LEAD_H diff --git a/game/server/ai_behavior_passenger.h b/game/server/ai_behavior_passenger.h new file mode 100644 index 0000000..61e0d73 --- /dev/null +++ b/game/server/ai_behavior_passenger.h @@ -0,0 +1,245 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef AI_BEHAVIOR_PASSENGER_H +#define AI_BEHAVIOR_PASSENGER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_speech.h" +#include "ai_behavior.h" +#include "ai_utils.h" +#include "vehicle_jeep_episodic.h" + +#define STOPPED_VELOCITY_THRESHOLD 32.0f +#define STOPPED_VELOCITY_THRESHOLD_SQR (STOPPED_VELOCITY_THRESHOLD*STOPPED_VELOCITY_THRESHOLD) + +#define STARTED_VELOCITY_THRESHOLD 64.0f +#define STARTED_VELOCITY_THRESHOLD_SQR (STARTED_VELOCITY_THRESHOLD*STARTED_VELOCITY_THRESHOLD) + +// Custom activities +extern int ACT_PASSENGER_IDLE; +extern int ACT_PASSENGER_RANGE_ATTACK1; + +// --------------------------------------------- +// Vehicle state +// --------------------------------------------- +struct passengerVehicleState_t +{ + Vector m_vecLastLocalVelocity; + Vector m_vecDeltaVelocity; + QAngle m_vecLastAngles; + float m_flNextWarningTime; + float m_flLastSpeedSqr; + bool m_bPlayerInVehicle; + bool m_bWasBoosting; + bool m_bWasOverturned; + + DECLARE_SIMPLE_DATADESC(); +}; + +// --------------------------------------------- +// Passenger intent +// --------------------------------------------- +enum passesngerVehicleIntent_e +{ + PASSENGER_INTENT_NONE, + PASSENGER_INTENT_ENTER, // We want to be in the vehicle + PASSENGER_INTENT_EXIT, // We want to be outside the vehicle +}; + +// --------------------------------------------- +// Passenger state functions +// --------------------------------------------- +enum PassengerState_e +{ + PASSENGER_STATE_OUTSIDE = 0, // Not in the vehicle + PASSENGER_STATE_ENTERING, + PASSENGER_STATE_INSIDE, + PASSENGER_STATE_EXITING, +}; + +class CAI_PassengerBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_PassengerBehavior, CAI_SimpleBehavior ); + DECLARE_DATADESC() + +public: + + CAI_PassengerBehavior( void ); + + enum + { + // Schedules + SCHED_PASSENGER_IDLE = BaseClass::NEXT_SCHEDULE, + SCHED_PASSENGER_ENTER_VEHICLE, + SCHED_PASSENGER_EXIT_VEHICLE, + SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE, + SCHED_PASSENGER_ENTER_VEHICLE_PAUSE, + SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED, + SCHED_PASSENGER_PLAY_SCRIPTED_ANIM, + NEXT_SCHEDULE, + + // Tasks + TASK_PASSENGER_ENTER_VEHICLE = BaseClass::NEXT_TASK, + TASK_PASSENGER_EXIT_VEHICLE, + TASK_PASSENGER_ATTACH_TO_VEHICLE, + TASK_PASSENGER_DETACH_FROM_VEHICLE, + TASK_PASSENGER_SET_IDEAL_ENTRY_YAW, + NEXT_TASK, + + // Conditions + COND_PASSENGER_HARD_IMPACT = BaseClass::NEXT_CONDITION, + COND_PASSENGER_ENTERING, + COND_PASSENGER_EXITING, + COND_PASSENGER_VEHICLE_STARTED, + COND_PASSENGER_VEHICLE_STOPPED, + COND_PASSENGER_OVERTURNED, + COND_PASSENGER_CANCEL_ENTER, + COND_PASSENGER_ERRATIC_DRIVING, + COND_PASSENGER_PLAYER_ENTERED_VEHICLE, + COND_PASSENGER_PLAYER_EXITED_VEHICLE, + COND_PASSENGER_JOSTLE_SMALL, + + NEXT_CONDITION + }; + + bool ForceVehicleInteraction( const char *lpszInteractionName, CBaseCombatCharacter *pOther ); + + virtual bool CanSelectSchedule( void ); + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual void RunTask( const Task_t *pTask ); + virtual void StartTask( const Task_t *pTask ); + virtual void BuildScheduleTestBits( void ); + virtual int TranslateSchedule( int scheduleType ); + virtual void GetEntryTarget( Vector *vecOrigin, QAngle *vecAngles ); + virtual void GatherConditions( void ); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ); + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + virtual void ClearSchedule( const char *szReason ); + virtual bool IsInterruptable( void ); + virtual void PrescheduleThink( void ); + virtual void CancelEnterVehicle( void ); + + virtual const char *GetName( void ) { return "Passenger"; } + virtual string_t GetRoleName( void ) { return MAKE_STRING( "passenger" ); } + + // Enable/disable code + void Enable( CPropJeepEpisodic *pVehicle, bool bImmediateEntrance = false ); + void Disable( void ); + bool IsEnabled( void ) const { return m_bEnabled; } + + virtual void EnterVehicle( void ); + virtual void ExitVehicle( void ); + + void AddPhysicsPush( float force ); + + CPropVehicleDriveable *GetTargetVehicle( void ) const { return m_hVehicle; } + + PassengerState_e GetPassengerState( void ) const { return m_PassengerState; } + + virtual void OnRestore(); + +protected: + + virtual int SelectTransitionSchedule( void ); + + bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 ); + + bool CanExitVehicle( void ); + void SetTransitionSequence( int nSequence ); + void AttachToVehicle( void ); + + virtual void OnExitVehicleFailed( void ) { } // NPC attempted to leave vehicle, but was unable to + virtual void GatherVehicleStateConditions( void ); + + // ------------------------------------------ + // Entry/exit transition code + // ------------------------------------------ + + virtual void FinishEnterVehicle( void ); + virtual void FinishExitVehicle( void ); + + void DetachFromVehicle( void ); + void DrawDebugTransitionInfo( const Vector &vecIdealPos, const QAngle &vecIdealAngles, const Vector &vecAnimPos, const QAngle &vecAnimAngles ); + bool GetEntryPoint( int nSequence, Vector *vecEntryPoint, QAngle *vecEntryAngles = NULL ); + bool GetExitPoint( int nSequence, Vector *vecExitPoint, QAngle *vecExitAngles = NULL ); + bool PointIsNavigable( const Vector &vecTargetPos ); + bool ReserveEntryPoint( VehicleSeatQuery_e eSeatSearchType ); + bool ReserveExitPoint( void ); + bool FindGroundAtPosition( const Vector &in, float flUpDelta, float flDownDelta, Vector *out ); + bool DoTransitionMovement( void ); + bool GetSequenceBlendAmount( float flCycle, float *posBlend, float *angBlend ); + bool LocalIntervalMovement( float flInterval, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles ); + void GetTransitionAnimationIdeal( float flCycle, const Vector &vecTargetPos, const QAngle &vecTargetAngles, Vector *idealOrigin, QAngle *idealAngles ); + float GetNextCycleForInterval( int nSequence, float flInterval ); + void GetLocalVehicleVelocity( Vector *pOut ); + void CacheBlendTargets( void ); + + void InitVehicleState( void ); + int FindEntrySequence( bool bNearest = false ); + int FindExitSequence( void ); + bool IsValidTransitionPoint( const Vector &vecStartPos, const Vector &vecEndPos ); + + void SetPassengerState( PassengerState_e state ) { m_PassengerState = state; } + + PassengerState_e m_PassengerState; // State we're in, for the vehicle + + // --------------------------------------------- + + bool IsPassengerHostile( void ); + + passengerVehicleState_t m_vehicleState; // Internal vehicle state + + CHandle m_hVehicle; // The vehicle we're bound to + CHandle m_hBlocker; // Blocking entity for space reservation + Vector m_vecTargetPosition; // Target destination for exiting the vehicle + QAngle m_vecTargetAngles; // Target angles for exiting the vehicle + bool m_bEnabled; // If the behavior is running + passesngerVehicleIntent_e m_PassengerIntent; // Gives us information about whether we're meant to get in/out, etc. + + int m_nTransitionSequence; // Animation we're using to transition with + float m_flOriginStartFrame; + float m_flOriginEndFrame; + float m_flAnglesStartFrame; + float m_flAnglesEndFrame; + +protected: + DEFINE_CUSTOM_SCHEDULE_PROVIDER; +}; + +class CTraceFilterVehicleTransition : public CTraceFilterSkipTwoEntities +{ +public: + DECLARE_CLASS( CTraceFilterVehicleTransition, CTraceFilterSkipTwoEntities ); + + CTraceFilterVehicleTransition( const IHandleEntity *passentity, const IHandleEntity *passentity2, int collisionGroup ) : + CTraceFilterSkipTwoEntities( passentity, passentity2, collisionGroup ) {} + + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + bool bRet = BaseClass::ShouldHitEntity( pServerEntity, contentsMask ); + + CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); + if ( pEntity ) + { + IPhysicsObject *pPhys = pEntity->VPhysicsGetObject(); + if ( pPhys ) + { + // Ignore physics objects + // TODO: This will have to be fleshed out more as cases arise + if ( pPhys->IsMoveable() && pPhys->GetMass() < 80.0f ) + return false; + } + } + + return bRet; + } +}; + +#endif // AI_BEHAVIOR_PASSENGER_H diff --git a/game/server/ai_behavior_rappel.h b/game/server/ai_behavior_rappel.h new file mode 100644 index 0000000..ee16fc6 --- /dev/null +++ b/game/server/ai_behavior_rappel.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Deal with weapon being out +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef AI_BEHAVIOR_RAPPEL_H +#define AI_BEHAVIOR_RAPPEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior.h" + +class CBeam; + +class CAI_RappelBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_RappelBehavior, CAI_SimpleBehavior ); + +public: + CAI_RappelBehavior(); + + void Precache( void ); + virtual const char *GetName() { return "Rappel"; } + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual bool CanSelectSchedule(); + void GatherConditions(); + void CleanupOnDeath( CBaseEntity *pCulprit = NULL, bool bFireDeathOutput = true ); + + //virtual void BeginScheduleSelection(); + //virtual void EndScheduleSelection(); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + bool IsWaitingToRappel() { return m_bWaitingToRappel; } + void BeginRappel(); + void SetDescentSpeed(); + + void CreateZipline(); + void CutZipline(); + + //void BuildScheduleTestBits(); + //int TranslateSchedule( int scheduleType ); + //void OnStartSchedule( int scheduleType ); + + //void InitializeBehavior(); + + enum + { + SCHED_RAPPEL_WAIT = BaseClass::NEXT_SCHEDULE, + SCHED_RAPPEL, + SCHED_CLEAR_RAPPEL_POINT, // Get out of the way for the next guy + NEXT_SCHEDULE, + + TASK_RAPPEL = BaseClass::NEXT_TASK, + TASK_HIT_GROUND, + NEXT_TASK, + + COND_BEGIN_RAPPEL = BaseClass::NEXT_CONDITION, + NEXT_CONDITION, + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +public: + +private: + virtual int SelectSchedule(); + + //--------------------------------- + bool m_bWaitingToRappel; + bool m_bOnGround; + CHandle m_hLine; + Vector m_vecRopeAnchor; + + DECLARE_DATADESC(); +}; + +#endif // AI_BEHAVIOR_RAPPEL_H + + diff --git a/game/server/ai_behavior_standoff.h b/game/server/ai_behavior_standoff.h new file mode 100644 index 0000000..c08059e --- /dev/null +++ b/game/server/ai_behavior_standoff.h @@ -0,0 +1,232 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Combat behaviors for AIs in a relatively self-preservationist mode. +// Lots of cover taking and attempted shots out of cover. +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_STANDOFF_H +#define AI_BEHAVIOR_STANDOFF_H + +#include "utlvector.h" +#include "utlmap.h" + +#include "ai_behavior.h" +#include "ai_utils.h" +#include "ai_hint.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +enum AI_HintChangeReaction_t +{ + AIHCR_DEFAULT_AI, + AIHCR_MOVE_ON_COVER, + AIHCR_MOVE_IMMEDIATE, +}; + +struct AI_StandoffParams_t +{ + AI_HintChangeReaction_t hintChangeReaction; + bool fCoverOnReload; + bool fPlayerIsBattleline; + float minTimeShots; + float maxTimeShots; + int minShots; + int maxShots; + int oddsCover; + bool fStayAtCover; + float flAbandonTimeLimit; + + DECLARE_SIMPLE_DATADESC(); +}; + +//------------------------------------- + +enum AI_Posture_t +{ + AIP_INDIFFERENT, + AIP_STANDING, + AIP_CROUCHING, + AIP_PEEKING, +}; + +enum +{ + STANDOFF_SENTENCE_BEGIN_STANDOFF = SENTENCE_BASE_BEHAVIOR_INDEX, + STANDOFF_SENTENCE_END_STANDOFF, + STANDOFF_SENTENCE_OUT_OF_AMMO, + STANDOFF_SENTENCE_FORCED_TAKE_COVER, + STANDOFF_SENTENCE_STAND_CHECK_TARGET, +}; + +class CAI_MappedActivityBehavior_Temporary : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_MappedActivityBehavior_Temporary, CAI_SimpleBehavior ); +public: + CAI_MappedActivityBehavior_Temporary( CAI_BaseNPC *pOuter = NULL ) + : CAI_SimpleBehavior(pOuter) + { + SetDefLessFunc( m_ActivityMap ); + } + +protected: + Activity GetMappedActivity( AI_Posture_t posture, Activity activity ); + void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + + virtual void UpdateTranslateActivityMap(); + +private: + CUtlMap m_ActivityMap; +}; + +class CAI_StandoffBehavior : public CAI_MappedActivityBehavior_Temporary +{ + DECLARE_CLASS( CAI_StandoffBehavior, CAI_MappedActivityBehavior_Temporary ); +public: + CAI_StandoffBehavior( CAI_BaseNPC *pOuter = NULL ); + + virtual const char *GetName() { return "Standoff"; } + + void SetActive( bool fActive ); + void SetParameters( const AI_StandoffParams_t ¶ms, CAI_GoalEntity *pGoalEntity = NULL ); + + Vector GetStandoffGoalPosition(); + void SetStandoffGoalPosition( const Vector &vecPos ); + void ClearStandoffGoalPosition(); + + AI_Posture_t GetPosture(); + + bool IsActive( void ) { return m_fActive; } + void OnChangeTacticalConstraints(); + + bool CanSelectSchedule(); + bool IsBehindBattleLines( const Vector &point ); + +protected: + void Spawn(); + void BeginScheduleSelection(); + void EndScheduleSelection(); + void PrescheduleThink(); + void GatherConditions(); + int SelectSchedule(); + int TranslateSchedule( int scheduleType ); + void StartTask( const Task_t *pTask ); + void BuildScheduleTestBits(); + virtual void OnUpdateShotRegulator(); + + Activity NPC_TranslateActivity( Activity eNewActivity ); + + bool IsValidCover( const Vector &vecCoverLocation, CAI_Hint const *pHint ); + bool IsValidShootPosition( const Vector &vecCoverLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + + void SetPosture( AI_Posture_t posture ); + + void OnChangeHintGroup( string_t oldGroup, string_t newGroup ); + + virtual int SelectScheduleUpdateWeapon(); + virtual int SelectScheduleCheckCover(); + virtual int SelectScheduleEstablishAim(); + virtual int SelectScheduleAttack(); + + bool PlayerIsLeading(); + CBaseEntity *GetPlayerLeader(); + bool GetDirectionOfStandoff( Vector *pDir ); + + void UpdateBattleLines(); + + Hint_e GetHintType(); + void SetReuseCurrentCover(); + void UnlockHintNode(); + Activity GetCoverActivity(); + + void OnRestore(); + + void UpdateTranslateActivityMap(); + + // Standoff overrides base AI crouch handling + bool IsCrouching( void ) { return false; } + +private: + + //---------------------------- + + enum + { + NEXT_SCHEDULE = BaseClass::NEXT_SCHEDULE, + + NEXT_TASK = BaseClass::NEXT_TASK, + + COND_ABANDON_TIME_EXPIRED = BaseClass::NEXT_CONDITION, + NEXT_CONDITION + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + + //--------------------------------- + // @TODO (toml 07-30-03): replace all these booleans with a singe 32 bit unsigned & bit flags + + bool m_fActive; + bool m_fTestNoDamage; + + Vector m_vecStandoffGoalPosition; + + AI_Posture_t m_posture; + + AI_StandoffParams_t m_params; + EHANDLE m_hStandoffGoal; + + bool m_fTakeCover; + float m_SavedDistTooFar; + bool m_fForceNewEnemy; + CAI_MoveMonitor m_PlayerMoveMonitor; + + CSimTimer m_TimeForceCoverHint; + CSimTimer m_TimePreventForceNewEnemy; + CRandSimTimer m_RandomCoverChangeTimer; + + // FIXME: TEMPORARY! REMOVE + int m_nSavedMinShots, m_nSavedMaxShots; + float m_flSavedMinRest, m_flSavedMaxRest; + + //--------------------------------- + + struct BattleLine_t + { + Vector point; + Vector normal; + }; + + CThinkOnceSemaphore m_UpdateBattleLinesSemaphore; + CUtlVector m_BattleLines; + bool m_fIgnoreFronts; + + //--------------------------------- + + bool m_bHasLowCoverActivity; + + //--------------------------------- + + DECLARE_DATADESC(); +}; + +//------------------------------------- + +inline void CAI_StandoffBehavior::SetPosture( AI_Posture_t posture ) +{ + m_posture = posture; +} + +//------------------------------------- + +inline AI_Posture_t CAI_StandoffBehavior::GetPosture() +{ + return m_posture; +} + +//----------------------------------------------------------------------------- + +#endif // AI_BEHAVIOR_STANDOFF_H diff --git a/game/server/ai_blended_movement.h b/game/server/ai_blended_movement.h new file mode 100644 index 0000000..dab62be --- /dev/null +++ b/game/server/ai_blended_movement.h @@ -0,0 +1,260 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_BLENDED_MOVEMENT_H +#define AI_BLENDED_MOVEMENT_H + +#include "ai_basenpc.h" +#include "ai_motor.h" +#include "ai_navigator.h" + +struct AI_Waypoint_t; + +//----------------------------------------------------------------------------- +// CLASS: CAI_BlendedMotor +// +// Purpose: Home of fancy human animation transition code +// +//----------------------------------------------------------------------------- + +class CAI_BlendedMotor : public CAI_Motor +{ + typedef CAI_Motor BaseClass; +public: + CAI_BlendedMotor( CAI_BaseNPC *pOuter ) + : BaseClass( pOuter ) + { + m_iPrimaryLayer = -1; + m_nPrimarySequence = ACT_INVALID; + + m_iSecondaryLayer = -1; + m_nSecondarySequence = ACT_INVALID; + m_flSecondaryWeight = 0.0f; + + m_nSavedGoalActivity = ACT_INVALID; + m_nSavedTranslatedGoalActivity = ACT_INVALID; + m_nGoalSequence = ACT_INVALID; + + m_nPrevMovementSequence = ACT_INVALID; + m_nInteriorSequence = ACT_INVALID; + + m_bDeceleratingToGoal = false; + + m_flStartCycle = 0.0f; + + m_flPredictiveSpeedAdjust = 1.0f; + m_flReactiveSpeedAdjust = 1.0f; + m_vecPrevOrigin1.Init(); + m_vecPrevOrigin2.Init(); + + m_prevYaw = 0.0f; + m_doTurn = 0.0f; + m_doLeft = 0.0f; + m_doRight = 0.0f; + m_flNextTurnAct = 0.0f; + } + + void MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw ); + void MoveJumpStart( const Vector &velocity ); + + void ResetMoveCalculations(); + void MoveStart(); + void ResetGoalSequence(); + void MoveStop(); + void MovePaused(); + void MoveContinue(); + + float OverrideMaxYawSpeed( Activity activity ); + void UpdateYaw( int speed ); + void RecalculateYawSpeed(); + + bool IsDeceleratingToGoal() const { return m_bDeceleratingToGoal; } + float GetMoveScriptTotalTime(); + + void MaintainTurnActivity( void ); + bool AddTurnGesture( float flYD ); + + +private: + AIMotorMoveResult_t MoveGroundExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ); + AIMotorMoveResult_t MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ); + + + // -------------------------------- + + void BuildMoveScript( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ); + + void BuildVelocityScript( const AILocalMoveGoal_t &move ); + void InsertSlowdown( float distToObstruction, float idealAccel, bool bAlwaysSlowdown ); + + int BuildTurnScript( int i, int j ); + void BuildTurnScript( const AILocalMoveGoal_t &move ); + int BuildInsertNode( int i, float flTime ); + + Activity GetTransitionActivity( void ); + + // -------------------------------- + + // helpers to simplify code + float GetCycle() { return GetOuter()->GetCycle(); } + int AddLayeredSequence( int sequence, int iPriority ) { return GetOuter()->AddLayeredSequence( sequence, iPriority ); } + void SetLayerWeight( int iLayer, float flWeight ) { GetOuter()->SetLayerWeight( iLayer, flWeight ); } + void SetLayerPlaybackRate( int iLayer, float flPlaybackRate ) { GetOuter()->SetLayerPlaybackRate( iLayer, flPlaybackRate ); } + void SetLayerNoRestore( int iLayer, bool bNoRestore ) { GetOuter()->SetLayerNoRestore( iLayer, bNoRestore ); } + void SetLayerCycle( int iLayer, float flCycle ) { GetOuter()->SetLayerCycle( iLayer, flCycle ); } + void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle ) { GetOuter()->SetLayerCycle( iLayer, flCycle, flPrevCycle ); } + void RemoveLayer( int iLayer, float flKillRate, float flKillDelay ) { GetOuter()->RemoveLayer( iLayer, flKillRate, flKillDelay ); } + + // -------------------------------- + + struct AI_Movementscript_t + { + public: + AI_Movementscript_t( ) + { + Init( ); + }; + + void Init( void ) + { + memset( this, 0, sizeof(*this) ); + }; + + float flTime; // time till next entry + float flElapsedTime; // time since first entry + + float flDist; // distance to next entry + + float flMaxVelocity; + + // float flVelocity; + + float flYaw; + float flAngularVelocity; + + bool bLooping; + int nFlags; + + AI_Waypoint_t *pWaypoint; + + public: + AI_Movementscript_t *pNext; + AI_Movementscript_t *pPrev; + + Vector vecLocation; + + }; + + //--------------------------------- + + CUtlVector m_scriptMove; + CUtlVector m_scriptTurn; + + //--------------------------------- + + bool m_bDeceleratingToGoal; + + int m_iPrimaryLayer; + int m_iSecondaryLayer; + + int m_nPrimarySequence; + int m_nSecondarySequence; + float m_flSecondaryWeight; + + Activity m_nSavedGoalActivity; + Activity m_nSavedTranslatedGoalActivity; + int m_nGoalSequence; + + int m_nPrevMovementSequence; + int m_nInteriorSequence; + + float m_flStartCycle; + + float m_flCurrRate; + + float m_flPredictiveSpeedAdjust; // predictive speed adjust from probing slope + float m_flReactiveSpeedAdjust; // reactive speed adjust when slope movement detected + Vector m_vecPrevOrigin1; + Vector m_vecPrevOrigin2; + + //--------------------------------- + + float m_flNextTurnGesture; // next time for large turn gesture + + //--------------------------------- + float m_prevYaw; + float m_doTurn; + float m_doLeft; + float m_doRight; + float m_flNextTurnAct; // next time for small turn gesture + + + float GetMoveScriptDist( float &flNewSpeed ); + float GetMoveScriptYaw( void ); + void SetMoveScriptAnim( float flNewSpeed ); + + int GetInteriorSequence( int fromSequence ); + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// CLASS: CAI_BlendingHost +// +// Purpose: Bridge to the home of fancy human animation transition code +// +//----------------------------------------------------------------------------- + +template +class CAI_BlendingHost : public BASE_NPC +{ + DECLARE_CLASS_NOFRIEND( CAI_BlendingHost, BASE_NPC ); +public: + const CAI_BlendedMotor *GetBlendedMotor() const { return assert_cast(this->GetMotor()); } + CAI_BlendedMotor * GetBlendedMotor() { return assert_cast(this->GetMotor()); } + + CAI_Motor *CreateMotor() + { + MEM_ALLOC_CREDIT(); + return new CAI_BlendedMotor( this ); + } + + CAI_Navigator *CreateNavigator() + { + CAI_Navigator *pNavigator = BaseClass::CreateNavigator(); + pNavigator->SetValidateActivitySpeed( false ); + return pNavigator; + } + + float MaxYawSpeed( void ) + { + float override = GetBlendedMotor()->OverrideMaxYawSpeed( this->GetActivity() ); + if ( override != -1 ) + return override; + return BaseClass::MaxYawSpeed(); + } + + float GetTimeToNavGoal() + { + float result = GetBlendedMotor()->GetMoveScriptTotalTime(); + if ( result != -1 ) + return result; + return BaseClass::GetTimeToNavGoal(); + } + +}; + +//------------------------------------- +// to simplify basic usage: +class CAI_BlendedNPC : public CAI_BlendingHost +{ + DECLARE_CLASS( CAI_BlendedNPC, CAI_BlendingHost ); +}; + +//----------------------------------------------------------------------------- + +#endif diff --git a/game/server/ai_component.h b/game/server/ai_component.h new file mode 100644 index 0000000..2385d61 --- /dev/null +++ b/game/server/ai_component.h @@ -0,0 +1,171 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_COMPONENT_H +#define AI_COMPONENT_H + +#if defined( _WIN32 ) +#pragma once +#endif + +class CAI_BaseNPC; +class CAI_Enemies; +typedef int AI_TaskFailureCode_t; +struct Task_t; + +//----------------------------------------------------------------------------- +// CAI_Component +// +// Purpose: Shared functionality of all classes that assume some of the +// responsibilities of an owner AI. +//----------------------------------------------------------------------------- + +class CAI_Component +{ + DECLARE_CLASS_NOBASE( CAI_Component ); +protected: + CAI_Component( CAI_BaseNPC *pOuter = NULL ) + : m_pOuter(pOuter) + { + } + + virtual ~CAI_Component() {} + +public: + virtual void SetOuter( CAI_BaseNPC *pOuter ) { m_pOuter = pOuter; } + + CAI_BaseNPC * GetOuter() { return m_pOuter; } + const CAI_BaseNPC * GetOuter() const { return m_pOuter; } + + Hull_t GetHullType() const; + float GetHullWidth() const; + float GetHullHeight() const; + const Vector & GetHullMins() const; + const Vector & GetHullMaxs() const; + +protected: + // + // Common services provided by CAI_BaseNPC, Convenience methods to simplify derived code + // + edict_t * GetEdict(); + + const Vector & GetLocalOrigin() const; + void SetLocalOrigin( const Vector &origin ); + + const Vector & GetAbsOrigin() const; + const QAngle& GetAbsAngles() const; + + void SetLocalAngles( const QAngle& angles ); + const QAngle & GetLocalAngles( void ) const; + + const Vector& WorldAlignMins() const; + const Vector& WorldAlignMaxs() const; + Vector WorldSpaceCenter() const; + + int GetCollisionGroup() const; + + void SetSolid( SolidType_t val ); + SolidType_t GetSolid() const; + + float GetGravity() const; + void SetGravity( float ); + + CBaseEntity* GetEnemy(); + const Vector & GetEnemyLKP() const; + void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition); + + CBaseEntity* GetTarget(); + void SetTarget( CBaseEntity *pTarget ); + + const Task_t* GetCurTask( void ); + virtual void TaskFail( AI_TaskFailureCode_t ); + void TaskFail( const char *pszGeneralFailText ); + virtual void TaskComplete( bool fIgnoreSetFailedCondition = false ); + int TaskIsRunning(); + inline int TaskIsComplete(); + + Activity GetActivity(); + void SetActivity( Activity NewActivity ); + float GetIdealSpeed() const; + float GetIdealAccel() const; + int GetSequence(); + + int GetEntFlags() const; + void AddEntFlag( int flags ); + void RemoveEntFlag( int flagsToRemove ); + void ToggleEntFlag( int flagToToggle ); + + void SetGroundEntity( CBaseEntity *ground ); + + CBaseEntity* GetGoalEnt(); + void SetGoalEnt( CBaseEntity *pGoalEnt ); + + void Remember( int iMemory ); + void Forget( int iMemory ); + bool HasMemory( int iMemory ); + + CAI_Enemies * GetEnemies(); + + const char * GetEntClassname(); + + int CapabilitiesGet(); + + float GetLastThink( const char *szContext = NULL ); + +public: +#if defined(new) +#error +#endif + + void *operator new( size_t nBytes ) + { + MEM_ALLOC_CREDIT(); + void *pResult = MemAlloc_Alloc( nBytes ); + memset( pResult, 0, nBytes ); + return pResult; + }; + + void *operator new( size_t nBytes, int nBlockUse, const char *pFileName, int nLine ) + { + MEM_ALLOC_CREDIT(); + void *pResult = MemAlloc_Alloc( nBytes, pFileName, nLine ); + memset( pResult, 0, nBytes ); + return pResult; + } + +private: + CAI_BaseNPC *m_pOuter; +}; + +//----------------------------------------------------------------------------- + +template +class CAI_ComponentWithOuter : public BASE_COMPONENT +{ +protected: + CAI_ComponentWithOuter(NPC_CLASS *pOuter = NULL) + : BASE_COMPONENT(pOuter) + { + } + +public: + // Hides base version + void SetOuter( NPC_CLASS *pOuter ) { BASE_COMPONENT::SetOuter((CAI_BaseNPC *)pOuter); } + NPC_CLASS * GetOuter() { return (NPC_CLASS *)(BASE_COMPONENT::GetOuter()); } + const NPC_CLASS * GetOuter() const { return (NPC_CLASS *)(BASE_COMPONENT::GetOuter()); } +}; + +//----------------------------------------------------------------------------- + +#define DEFINE_AI_COMPONENT_OUTER( NPC_CLASS ) \ + void SetOuter( NPC_CLASS *pOuter ) { CAI_Component::SetOuter((CAI_BaseNPC *)pOuter); } \ + NPC_CLASS * GetOuter() { return (NPC_CLASS *)(CAI_Component::GetOuter()); } \ + const NPC_CLASS * GetOuter() const { return (NPC_CLASS *)(CAI_Component::GetOuter()); } + +//----------------------------------------------------------------------------- + +#endif // AI_COMPONENT_H diff --git a/game/server/ai_condition.h b/game/server/ai_condition.h new file mode 100644 index 0000000..e23185f --- /dev/null +++ b/game/server/ai_condition.h @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The default shared conditions +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CONDITION_H +#define CONDITION_H + +// NOTE: Changing this constant will break save files!!! (changes type of CAI_ScheduleBits) +#ifndef MAX_CONDITIONS +#define MAX_CONDITIONS 32*8 +#endif + +//========================================================= +// These are the default shared conditions +//========================================================= +enum SCOND_t +{ + COND_NONE, // A way for a function to return no condition to get + + COND_IN_PVS, + COND_IDLE_INTERRUPT, // The schedule in question is a low priority idle, and therefore a candidate for translation into something else + + COND_LOW_PRIMARY_AMMO, + COND_NO_PRIMARY_AMMO, + COND_NO_SECONDARY_AMMO, + COND_NO_WEAPON, + COND_SEE_HATE, + COND_SEE_FEAR, + COND_SEE_DISLIKE, + COND_SEE_ENEMY, + COND_LOST_ENEMY, + COND_ENEMY_WENT_NULL, // What most people think COND_LOST_ENEMY is: This condition is set in the edge case where you had an enemy last think, but don't have one this think. + COND_ENEMY_OCCLUDED, // Can't see m_hEnemy + COND_TARGET_OCCLUDED, // Can't see m_hTargetEnt + COND_HAVE_ENEMY_LOS, + COND_HAVE_TARGET_LOS, + COND_LIGHT_DAMAGE, + COND_HEAVY_DAMAGE, + COND_PHYSICS_DAMAGE, + COND_REPEATED_DAMAGE, // Damaged several times in a row + + COND_CAN_RANGE_ATTACK1, // Hitscan weapon only + COND_CAN_RANGE_ATTACK2, // Grenade weapon only + COND_CAN_MELEE_ATTACK1, + COND_CAN_MELEE_ATTACK2, + + COND_PROVOKED, + COND_NEW_ENEMY, + + COND_ENEMY_TOO_FAR, // Can we get rid of this one!?!? + COND_ENEMY_FACING_ME, + COND_BEHIND_ENEMY, + COND_ENEMY_DEAD, + COND_ENEMY_UNREACHABLE, // Not connected to me via node graph + + COND_SEE_PLAYER, + COND_LOST_PLAYER, + COND_SEE_NEMESIS, + COND_TASK_FAILED, + COND_SCHEDULE_DONE, + COND_SMELL, + COND_TOO_CLOSE_TO_ATTACK, // FIXME: most of this next group are meaningless since they're shared between all attack checks! + COND_TOO_FAR_TO_ATTACK, + COND_NOT_FACING_ATTACK, + COND_WEAPON_HAS_LOS, + COND_WEAPON_BLOCKED_BY_FRIEND, // Friend between weapon and target + COND_WEAPON_PLAYER_IN_SPREAD, // Player in shooting direction + COND_WEAPON_PLAYER_NEAR_TARGET, // Player near shooting position + COND_WEAPON_SIGHT_OCCLUDED, + COND_BETTER_WEAPON_AVAILABLE, + COND_HEALTH_ITEM_AVAILABLE, // There's a healthkit available. + COND_GIVE_WAY, // Another npc requested that I give way + COND_WAY_CLEAR, // I no longer have to give way + COND_HEAR_DANGER, + COND_HEAR_THUMPER, + COND_HEAR_BUGBAIT, + COND_HEAR_COMBAT, + COND_HEAR_WORLD, + COND_HEAR_PLAYER, + COND_HEAR_BULLET_IMPACT, + COND_HEAR_PHYSICS_DANGER, + COND_HEAR_MOVE_AWAY, + COND_HEAR_SPOOKY, // Zombies make this when Alyx is in darkness mode + + COND_NO_HEAR_DANGER, // Since we can't use ~CONDITION. Mutually exclusive with COND_HEAR_DANGER + + COND_FLOATING_OFF_GROUND, + + COND_MOBBED_BY_ENEMIES, // Surrounded by a large number of enemies melee attacking me. (Zombies or Antlions, usually). + + // Commander stuff + COND_RECEIVED_ORDERS, + COND_PLAYER_ADDED_TO_SQUAD, + COND_PLAYER_REMOVED_FROM_SQUAD, + + COND_PLAYER_PUSHING, + COND_NPC_FREEZE, // We received an npc_freeze command while we were unfrozen + COND_NPC_UNFREEZE, // We received an npc_freeze command while we were frozen + + // This is a talker condition, but done here because we need to handle it in base AI + // due to it's interaction with behaviors. + COND_TALKER_RESPOND_TO_QUESTION, + + COND_NO_CUSTOM_INTERRUPTS, // Don't call BuildScheduleTestBits for this schedule. Used for schedules that must strictly control their interruptibility. + + // ====================================== + // IMPORTANT: This must be the last enum + // ====================================== + LAST_SHARED_CONDITION +}; + +#endif //CONDITION_H diff --git a/game/server/ai_debug.h b/game/server/ai_debug.h new file mode 100644 index 0000000..3f5c47f --- /dev/null +++ b/game/server/ai_debug.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_DEBUG_H +#define AI_DEBUG_H + +#include "fmtstr.h" +#include "ai_debug_shared.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +// This dumps a summary result on exit +//#define PROFILE_AI 1 + +#define AI_PROFILE_SCOPE_BEGIN( tag ) if (0) ; else { AI_PROFILE_SCOPE( tag ) +#define AI_PROFILE_SCOPE_BEGIN_( pszName ) if (0) ; else { AI_PROFILE_SCOPE_( pszName ) +#define AI_PROFILE_SCOPE_END() } do {} while (0) + +#if defined(VPROF_AI) +#define VProfAI() true +#else +#define VProfAI() false +#endif +#if defined(VPROF_AI) +#include "tier0/vprof.h" +#define AI_PROFILE_SCOPE( tag ) VPROF( #tag ) +#define AI_PROFILE_SCOPE_( pszName ) VPROF( pszName ) +#define AI_PROFILE_MEASURE_SCOPE( tag ) VPROF( #tag ) +#elif defined(PROFILE_AI) +#include "tier0/fasttimer.h" +#define AI_PROFILE_SCOPE( tag ) PROFILE_SCOPE( tag ) +#define AI_PROFILE_MEASURE_SCOPE( tag ) PROFILE_SCOPE( tag ) +#else +#define AI_PROFILE_MEASURE_SCOPE( tag ) ((void)0) +#define AI_PROFILE_SCOPE( tag ) ((void)0) +#endif + +#ifndef AI_PROFILE_SCOPE_ +#define AI_PROFILE_SCOPE_( pszName ) ((void)0) +#endif + + +enum AIMsgFlags +{ + AIMF_IGNORE_SELECTED = 0x01 +}; + +void DevMsg( CAI_BaseNPC *pAI, unsigned flags, PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 3, 4 ); +void DevMsg( CAI_BaseNPC *pAI, PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 2, 3 ); + + +//----------------------------------------------------------------------------- +// Purpose: Use this to perform AI tracelines that are trying to determine LOS between points. +// LOS checks between entities should use FVisible. +//----------------------------------------------------------------------------- +void AI_TraceLOS( const Vector& vecAbsStart, const Vector& vecAbsEnd, CBaseEntity *pLooker, trace_t *ptr, ITraceFilter *pFilter = NULL ); + +//----------------------------------------------------------------------------- + +#ifdef DEBUG +extern bool g_fTestSteering; +#define TestingSteering() g_fTestSteering +#else +#define TestingSteering() false +#endif + +//----------------------------------------------------------------------------- + + +#ifdef _DEBUG +extern ConVar ai_debug_doors; +#define AIIsDebuggingDoors( pNPC ) ( ai_debug_doors.GetBool() && pNPC->m_bSelected ) +#define AIDoorDebugMsg( pNPC, msg ) if ( !AIIsDebuggingDoors( pNPC ) ) ; else Msg( msg ) +#else +#define AIIsDebuggingDoors( pNPC ) (false) +#define AIDoorDebugMsg( pNPC, msg ) ((void)(0)) +#endif + + +//----------------------------------------------------------------------------- + +#endif // AI_DEBUG_H diff --git a/game/server/ai_default.h b/game/server/ai_default.h new file mode 100644 index 0000000..662dd45 --- /dev/null +++ b/game/server/ai_default.h @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Default schedules. +// +//=============================================================================// + +#ifndef AI_DEFAULT_H +#define AI_DEFAULT_H +#ifdef _WIN32 +#pragma once +#endif + +//========================================================= +// These are the schedule types +//========================================================= +enum +{ + SCHED_NONE = 0, + SCHED_IDLE_STAND, + SCHED_IDLE_WALK, + SCHED_IDLE_WANDER, + SCHED_WAKE_ANGRY, + SCHED_ALERT_FACE, + SCHED_ALERT_FACE_BESTSOUND, + SCHED_ALERT_REACT_TO_COMBAT_SOUND, + SCHED_ALERT_SCAN, + SCHED_ALERT_STAND, + SCHED_ALERT_WALK, + SCHED_INVESTIGATE_SOUND, + SCHED_COMBAT_FACE, + SCHED_COMBAT_SWEEP, + SCHED_FEAR_FACE, + SCHED_COMBAT_STAND, + SCHED_COMBAT_WALK, + SCHED_CHASE_ENEMY, + SCHED_CHASE_ENEMY_FAILED, + SCHED_VICTORY_DANCE, + SCHED_TARGET_FACE, + SCHED_TARGET_CHASE, + SCHED_SMALL_FLINCH, + SCHED_BIG_FLINCH, + SCHED_BACK_AWAY_FROM_ENEMY, + SCHED_MOVE_AWAY_FROM_ENEMY, + SCHED_BACK_AWAY_FROM_SAVE_POSITION, + SCHED_TAKE_COVER_FROM_ENEMY, + SCHED_TAKE_COVER_FROM_BEST_SOUND, + SCHED_FLEE_FROM_BEST_SOUND, + SCHED_TAKE_COVER_FROM_ORIGIN, + SCHED_FAIL_TAKE_COVER, + SCHED_RUN_FROM_ENEMY, + SCHED_RUN_FROM_ENEMY_FALLBACK, + SCHED_MOVE_TO_WEAPON_RANGE, + SCHED_ESTABLISH_LINE_OF_FIRE, + SCHED_ESTABLISH_LINE_OF_FIRE_FALLBACK, + SCHED_PRE_FAIL_ESTABLISH_LINE_OF_FIRE, + SCHED_FAIL_ESTABLISH_LINE_OF_FIRE, + SCHED_SHOOT_ENEMY_COVER, + SCHED_COWER, // usually a last resort! + SCHED_MELEE_ATTACK1, + SCHED_MELEE_ATTACK2, + SCHED_RANGE_ATTACK1, + SCHED_RANGE_ATTACK2, + SCHED_SPECIAL_ATTACK1, + SCHED_SPECIAL_ATTACK2, + SCHED_STANDOFF, + SCHED_ARM_WEAPON, + SCHED_DISARM_WEAPON, + SCHED_HIDE_AND_RELOAD, + SCHED_RELOAD, + SCHED_AMBUSH, + SCHED_DIE, + SCHED_DIE_RAGDOLL, + SCHED_WAIT_FOR_SCRIPT, + SCHED_AISCRIPT, + SCHED_SCRIPTED_WALK, + SCHED_SCRIPTED_RUN, + SCHED_SCRIPTED_CUSTOM_MOVE, + SCHED_SCRIPTED_WAIT, + SCHED_SCRIPTED_FACE, + SCHED_SCENE_GENERIC, + SCHED_NEW_WEAPON, + SCHED_NEW_WEAPON_CHEAT, + SCHED_SWITCH_TO_PENDING_WEAPON, + SCHED_GET_HEALTHKIT, + SCHED_WAIT_FOR_SPEAK_FINISH, + + SCHED_MOVE_AWAY, + SCHED_MOVE_AWAY_FAIL, + SCHED_MOVE_AWAY_END, + SCHED_FORCED_GO, + SCHED_FORCED_GO_RUN, + SCHED_NPC_FREEZE, + SCHED_PATROL_WALK, + SCHED_COMBAT_PATROL, + SCHED_PATROL_RUN, + SCHED_RUN_RANDOM, + SCHED_FALL_TO_GROUND, + SCHED_DROPSHIP_DUSTOFF, + + SCHED_FLINCH_PHYSICS, + + SCHED_FAIL, + SCHED_FAIL_NOSTOP, + + SCHED_RUN_FROM_ENEMY_MOB, + + SCHED_DUCK_DODGE, + + SCHED_INTERACTION_MOVE_TO_PARTNER, + SCHED_INTERACTION_WAIT_FOR_PARTNER, + + SCHED_SLEEP, + + // ====================================== + // IMPORTANT: This must be the last enum + // ====================================== + LAST_SHARED_SCHEDULE + +}; + +#endif // AI_DEFAULT_H diff --git a/game/server/ai_dynamiclink.h b/game/server/ai_dynamiclink.h new file mode 100644 index 0000000..cefec66 --- /dev/null +++ b/game/server/ai_dynamiclink.h @@ -0,0 +1,125 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A link that can be turned on and off. Unlike normal links +// dyanimc links must be entities so they and receive messages. +// They update the state of the actual links. Allows us to save +// a lot of memory by not making all links into entities +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_DYNAMICLINK_H +#define AI_DYNAMICLINK_H +#pragma once + +enum DynamicLinkState_t +{ + LINK_OFF = 0, + LINK_ON = 1, +}; + +class CAI_Link; + +//============================================================================= +// >> CAI_DynanicLink +//============================================================================= +class CAI_DynamicLink : public CServerOnlyEntity +{ + DECLARE_CLASS( CAI_DynamicLink, CServerOnlyEntity ); +public: + static void InitDynamicLinks(void); + static void ResetDynamicLinks(void); + static void PurgeDynamicLinks(void); + static void GenerateControllerLinks(); + + static bool gm_bInitialized; + + static CAI_DynamicLink* GetDynamicLink(int nSrcID, int nDstID); + + static CAI_DynamicLink* m_pAllDynamicLinks; // A linked list of all dynamic link + CAI_DynamicLink* m_pNextDynamicLink; // The next dynamic link in the list of dynamic links + + int m_nSrcEditID; // the node that 'owns' this link + int m_nDestEditID; // the node on the other end of the link. + + int m_nSrcID; // the node that 'owns' this link + int m_nDestID; // the node on the other end of the link. + DynamicLinkState_t m_nLinkState; // + string_t m_strAllowUse; // Only this entity name or classname may use the link + bool m_bInvertAllow; // Instead of only allowing the m_strAllowUse entity, exclude only it + + bool m_bFixedUpIds; + bool m_bNotSaved; + int m_nLinkType; + + void SetLinkState( void ); + bool IsLinkValid( void ); + + CAI_Link * FindLink(); + + int ObjectCaps(); + + // ---------------- + // Inputs + // ---------------- + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + DECLARE_DATADESC(); + + CAI_DynamicLink(); + ~CAI_DynamicLink(); +}; + +//============================================================================= +// >> CAI_DynanicLinkVolume +//============================================================================= +class CAI_DynamicLinkController : public CServerOnlyEntity +{ + DECLARE_CLASS( CAI_DynamicLinkController, CServerOnlyEntity ); +public: + void GenerateLinksFromVolume(); + + // ---------------- + // Inputs + // ---------------- + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + void InputSetAllowed( inputdata_t &inputdata ); + void InputSetInvert( inputdata_t &inputdata ); + + CUtlVector< CHandle > m_ControlledLinks; + DynamicLinkState_t m_nLinkState; + string_t m_strAllowUse; // Only this entity name or classname may use the link + bool m_bInvertAllow; // Instead of only allowing the m_strAllowUse entity, exclude only it + bool m_bUseAirLinkRadius; + + DECLARE_DATADESC(); +}; + +//============================================================================= +//============================================================================= +class CAI_RadialLinkController : public CBaseEntity +{ + DECLARE_CLASS( CAI_RadialLinkController, CBaseEntity ); + +public: + void Spawn(); + void Activate(); + void PollMotionThink(); + void ModifyNodeLinks( bool bMakeStale ); + +public: + float m_flRadius; + Vector m_vecAtRestOrigin; + bool m_bAtRest; + + DECLARE_DATADESC(); +}; + +#endif // AI_DYNAMICLINK_H \ No newline at end of file diff --git a/game/server/ai_eventresponse.h b/game/server/ai_eventresponse.h new file mode 100644 index 0000000..fedc140 --- /dev/null +++ b/game/server/ai_eventresponse.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: AI system that makes NPCs verbally respond to game events +// +//=============================================================================// + +#ifndef AI_EVENTRESPONSE_H +#define AI_EVENTRESPONSE_H + +#include "utldict.h" + +#define NPCEVENTRESPONSE_DISTANCE_SQR (768 * 768) // Maximum distance for responding to NPCs +#define NPCEVENTRESPONSE_REFIRE_TIME 15.0 // Time after giving a response before giving any more +#define NPCEVENTRESPONSE_GIVEUP_TIME 4.0 // Time after a response trigger was fired before discarding it without responding + +//----------------------------------------------------------------------------- +// Purpose: AI system that makes NPCs verbally respond to game events +//----------------------------------------------------------------------------- +class CNPCEventResponseSystem : public CAutoGameSystemPerFrame +{ +public: + CNPCEventResponseSystem( char const *name ) : CAutoGameSystemPerFrame( name ) + { + } + + void LevelInitPreEntity(); + void FrameUpdatePreEntityThink(); + void TriggerEvent( const char *pResponse, bool bForce, bool bCancelScript ); + +private: + float m_flNextEventPoll; + + struct storedevent_t + { + float flEventTime; + float flNextResponseTime; + bool bForce; + bool bCancelScript; + bool bPreventExpiration; + }; + + typedef CUtlDict< storedevent_t, int > EventMap; + EventMap m_ActiveEvents; +}; + +CNPCEventResponseSystem *NPCEventResponse(); + +#endif // AI_EVENTRESPONSE_H \ No newline at end of file diff --git a/game/server/ai_goalentity.h b/game/server/ai_goalentity.h new file mode 100644 index 0000000..2a6805f --- /dev/null +++ b/game/server/ai_goalentity.h @@ -0,0 +1,194 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_GOALENTITY_H +#define AI_GOALENTITY_H + +#include "ai_basenpc.h" +#include "utlvector.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// +// CAI_GoalEntity +// +// Purpose: Serves as the base class for all entities the designer may place +// that establish an NPC goal. Provides standard input, output & +// fields common to all goals. +// + +class CAI_GoalEntity : public CBaseEntity, + public IEntityListener +{ + DECLARE_CLASS( CAI_GoalEntity, CBaseEntity ); +public: + CAI_GoalEntity() + : m_iszActor(NULL_STRING), + m_iszGoal(NULL_STRING), + m_fStartActive(false), + m_SearchType(ST_ENTNAME), + m_iszConceptModifiers(NULL_STRING), + m_hGoalEntity(NULL), + m_flags( 0 ) + { + } + + virtual int ObjectCaps() { return ((BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_NOTIFY_ON_TRANSITION); } + + virtual void Spawn(); + virtual void OnRestore(); + virtual int DrawDebugTextOverlays(); + + virtual void InputActivate( inputdata_t &inputdata ); + virtual void InputUpdateActors( inputdata_t &inputdata ); + virtual void InputDeactivate( inputdata_t &inputdata ); + + // Goal entities can become Dormant if they're left behind on previous maps. + // Transitioning back to the map with cause a dormant goal entity to reactivate itself. + void EnterDormant( void ); + void ExitDormant( void ); + + bool IsActive(); + + int NumActors(); + CAI_BaseNPC * GetActor( int iActor = 0 ); + + void SetGoalEntity( CBaseEntity *pGoalEntity ); + CBaseEntity * GetGoalEntity(); + const char * GetGoalEntityName(); + + const char * GetConceptModifiers(); + +protected: + virtual void UpdateOnRemove(); + + virtual void OnEntityCreated( CBaseEntity *pEntity ); + virtual void OnEntityDeleted( CBaseEntity *pEntity ); + + virtual void EnableGoal( CAI_BaseNPC *pAI ) {} + virtual void DisableGoal( CAI_BaseNPC *pAI ) {} + + void UpdateActors(); + + const CUtlVector &AccessActors() + { + return m_actors; + } + +private: + enum Flags_t + { + ACTIVE = 0x01, + RESOLVED_NAME = 0x02, + DORMANT = 0x04, + }; + + enum SearchType_t + { + ST_ENTNAME, + ST_CLASSNAME, + }; + + void DelayedRefresh(); + void PruneActors(); + void ResolveNames(); + + // From Worldcraft + string_t m_iszActor; + string_t m_iszGoal; + bool m_fStartActive; + SearchType_t m_SearchType; + string_t m_iszConceptModifiers; + + CUtlVector m_actors; + EHANDLE m_hGoalEntity; + unsigned m_flags; + + +protected: + DECLARE_DATADESC(); +}; + +//------------------------------------- + +// @TODO (toml 03-18-03): Efficiency wart -- make this an explicit duty of the client? +inline void CAI_GoalEntity::UpdateActors() +{ + if ( !( m_flags & ACTIVE ) || !( m_flags & RESOLVED_NAME ) ) + { + ResolveNames(); + m_flags |= RESOLVED_NAME; + } + else + PruneActors(); +} + +//------------------------------------- + +inline bool CAI_GoalEntity::IsActive() +{ + if ( m_flags & ACTIVE ) + { + UpdateActors(); + return ( m_actors.Count() != 0 ); + } + return false; +} + +//------------------------------------- + +inline int CAI_GoalEntity::NumActors() +{ + UpdateActors(); + return m_actors.Count(); +} + +//------------------------------------- + +inline CAI_BaseNPC *CAI_GoalEntity::GetActor( int iActor ) +{ + UpdateActors(); + if ( m_actors.Count() > iActor ) + return m_actors[iActor]; + return NULL; +} + +//------------------------------------- + +inline void CAI_GoalEntity::SetGoalEntity( CBaseEntity *pGoalEntity ) +{ + m_iszGoal = pGoalEntity->GetEntityName(); + m_hGoalEntity = pGoalEntity; +} + +//------------------------------------- + +inline CBaseEntity *CAI_GoalEntity::GetGoalEntity() +{ + UpdateActors(); + return m_hGoalEntity; +} + +//------------------------------------- + +inline const char *CAI_GoalEntity::GetGoalEntityName() +{ + return STRING( m_iszGoal ); +} + +//------------------------------------- + +inline const char *CAI_GoalEntity::GetConceptModifiers() +{ + return STRING( m_iszConceptModifiers ); +} + +//----------------------------------------------------------------------------- + +#endif // AI_GOALENTITY_H diff --git a/game/server/ai_hint.h b/game/server/ai_hint.h new file mode 100644 index 0000000..89daef3 --- /dev/null +++ b/game/server/ai_hint.h @@ -0,0 +1,341 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hint node utilities and functions. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_HINT_H +#define AI_HINT_H +#pragma once + +#include "ai_initutils.h" +#include "tier1/utlmap.h" + +//Flags for FindHintNode +#define bits_HINT_NODE_NONE 0x00000000 +#define bits_HINT_NODE_VISIBLE 0x00000001 +#define bits_HINT_NODE_NEAREST 0x00000002 // Choose the node nearest me +#define bits_HINT_NODE_RANDOM 0x00000004 // Find a random hintnode meeting other criteria +#define bits_HINT_NODE_CLEAR 0x00000008 // Only choose nodes that have clear room for my bounding box (requires NPC) +#define bits_HINT_NODE_USE_GROUP 0x00000010 // Use the NPC's hintgroup when searching for a node (requires NPC) +#define bits_HINT_NODE_VISIBLE_TO_PLAYER 0x00000020 +#define bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER 0x00000040 +#define bits_HINT_NODE_REPORT_FAILURES 0x00000080 +#define bits_HINT_NODE_IN_VIEWCONE 0x00000100 +#define bits_HINT_NODE_IN_AIMCONE 0x00000200 +#define bits_HINT_NPC_IN_NODE_FOV 0x00000400 // Is the searcher inside the hint node's FOV? +#define bits_HINT_NOT_CLOSE_TO_ENEMY 0x00000800 // Hint must not be within 30 feet of my enemy +#define bits_HINT_HAS_LOS_TO_PLAYER 0x00001000 // Like VISIBLE_TO_PLAYER but doesn't care about player's facing +#define bits_HAS_EYEPOSITION_LOS_TO_PLAYER 0x00002000 // Like HAS LOS TO PLAYER, but checks NPC's eye position at the node, not node origin. + +//----------------------------------------------------------------------------- +// +// hints - these MUST coincide with the HINTS listed under +// info_node in the FGD file! +// +// For debugging, they must also coincide with g_pszHintDescriptions. +// +//----------------------------------------------------------------------------- +enum Hint_e +{ + HINT_ANY = -1, + HINT_NONE = 0, + HINT_NOT_USED_WORLD_DOOR, + HINT_WORLD_WINDOW, + HINT_NOT_USED_WORLD_BUTTON, + HINT_NOT_USED_WORLD_MACHINERY, + HINT_NOT_USED_WORLD_LEDGE, + HINT_NOT_USED_WORLD_LIGHT_SOURCE, + HINT_NOT_USED_WORLD_HEAT_SOURCE, + HINT_NOT_USED_WORLD_BLINKING_LIGHT, + HINT_NOT_USED_WORLD_BRIGHT_COLORS, + HINT_NOT_USED_WORLD_HUMAN_BLOOD, + HINT_NOT_USED_WORLD_ALIEN_BLOOD, + + HINT_WORLD_WORK_POSITION, + HINT_WORLD_VISUALLY_INTERESTING, + HINT_WORLD_VISUALLY_INTERESTING_DONT_AIM, + HINT_WORLD_INHIBIT_COMBINE_MINES, + HINT_WORLD_VISUALLY_INTERESTING_STEALTH, + + HINT_TACTICAL_COVER_MED = 100, + HINT_TACTICAL_COVER_LOW, + HINT_TACTICAL_SPAWN, + HINT_TACTICAL_PINCH, // Exit / entrance to an arena + HINT_NOT_USED_TACTICAL_GUARD, + HINT_TACTICAL_ENEMY_DISADVANTAGED, //Disadvantageous position for the enemy + HINT_NOT_USED_HEALTH_KIT, + + HINT_NOT_USED_URBAN_STREETCORNER = 200, + HINT_NOT_USED_URBAN_STREETLAMP, + HINT_NOT_USED_URBAN_DARK_SPOT, + HINT_NOT_USED_URBAN_POSTER, + HINT_NOT_USED_URBAN_SHELTER, + + HINT_NOT_USED_ASSASSIN_SECLUDED = 300, + HINT_NOT_USED_ASSASSIN_RAFTERS, + HINT_NOT_USED_ASSASSIN_GROUND, + HINT_NOT_USED_ASSASSIN_MONKEYBARS, + + HINT_ANTLION_BURROW_POINT = 400, + HINT_ANTLION_THUMPER_FLEE_POINT, + + HINT_HEADCRAB_BURROW_POINT = 450, + HINT_HEADCRAB_EXIT_POD_POINT, + + HINT_NOT_USED_ROLLER_PATROL_POINT = 500, + HINT_NOT_USED_ROLLER_CLEANUP_POINT, + + HINT_NOT_USED_PSTORM_ROCK_SPAWN = 600, + + HINT_CROW_FLYTO_POINT = 700, + + // TF2 Hints + HINT_BUG_PATROL_POINT = 800, + + // HL2 Hints + HINT_FOLLOW_WAIT_POINT = 900, + HINT_JUMP_OVERRIDE = 901, + HINT_PLAYER_SQUAD_TRANSITON_POINT = 902, + HINT_NPC_EXIT_POINT = 903, + HINT_STRIDER_NODE = 904, + + HINT_PLAYER_ALLY_MOVE_AWAY_DEST = 950, + HINT_PLAYER_ALLY_FEAR_DEST, + + // HL1 port hints + HINT_HL1_WORLD_MACHINERY = 1000, + HINT_HL1_WORLD_BLINKING_LIGHT, + HINT_HL1_WORLD_HUMAN_BLOOD, + HINT_HL1_WORLD_ALIEN_BLOOD, + + // CS port hints + HINT_CSTRIKE_HOSTAGE_ESCAPE = 1100, +}; +const char *GetHintTypeDescription( Hint_e iHintType ); +const char *GetHintTypeDescription( CAI_Hint *pHint ); + +//----------------------------------------------------------------------------- +// CHintCriteria +//----------------------------------------------------------------------------- + +class CHintCriteria +{ +public: + + CHintCriteria(); + ~CHintCriteria(); + + bool HasFlag( int bitmask ) const { return ( m_iFlags & bitmask ) != 0; } + void SetFlag( int bitmask ); + void ClearFlag( int bitmask ); + + void SetGroup( string_t group ); + string_t GetGroup( void ) const { return m_strGroup; } + + int GetFirstHintType( void ) const { return m_iFirstHintType; } + int GetLastHintType( void ) const { return m_iLastHintType; } + bool MatchesHintType( int hintType ) const; + bool MatchesSingleHintType() const; + + bool HasIncludeZones( void ) const { return ( m_zoneInclude.Count() != 0 ); } + bool HasExcludeZones( void ) const { return ( m_zoneExclude.Count() != 0 ); } + + void AddIncludePosition( const Vector &position, float radius ); + void AddExcludePosition( const Vector &position, float radius ); + void SetHintType( int hintType ); + void SetHintTypeRange( int firstType, int lastType ); + void AddHintType( int hintType ); + + bool InIncludedZone( const Vector &testPosition ) const; + bool InExcludedZone( const Vector &testPosition ) const; + + int NumHintTypes() const; + int GetHintType( int idx ) const; + +private: + + struct hintZone_t + { + Vector position; + float radiussqr; + }; + + typedef CUtlVector < hintZone_t > zoneList_t; + + void AddZone( zoneList_t &list, const Vector &position, float radius ); + bool InZone( const zoneList_t &zone, const Vector &testPosition ) const; + + CUtlVector m_HintTypes; + + int m_iFlags; + int m_iFirstHintType; + int m_iLastHintType; + string_t m_strGroup; + + zoneList_t m_zoneInclude; + zoneList_t m_zoneExclude; +}; + +class CAI_Node; + +//----------------------------------------------------------------------------- +// CAI_HintManager +//----------------------------------------------------------------------------- + +DECLARE_POINTER_HANDLE(AIHintIter_t); + +class CAIHintVector : public CUtlVector< CAI_Hint * > +{ +public: + CAIHintVector() : CUtlVector< CAI_Hint * >( 1, 0 ) + { + } + + CAIHintVector( const CAIHintVector& src ) + { + CopyArray( src.Base(), src.Count() ); + } + + CAIHintVector &operator=( const CAIHintVector &src ) + { + CopyArray( src.Base(), src.Count() ); + return *this; + } +}; + +class CAI_HintManager +{ + friend class CAI_Hint; +public: + // Hint node creation + static CAI_Hint *CreateHint( HintNodeData *pNodeData, const char *pMapData = NULL ); + static void DrawHintOverlays(float flDrawDuration); + + static void AddHint( CAI_Hint *pTestHint ); + static void RemoveHint( CAI_Hint *pTestHint ); + static void AddHintByType( CAI_Hint *pHint ); + static void RemoveHintByType( CAI_Hint *pHintToRemove ); + + // Interface for searching the hint node list + static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria ); + static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria ); + static CAI_Hint *FindHint( const Vector &position, const CHintCriteria &hintCriteria ); + static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, Hint_e nHintType, int nFlags, float flMaxDist, const Vector *pMaxDistFrom = NULL ); + + // Purpose: Finds a random suitable hint within the requested radious of the npc + static CAI_Hint *FindHintRandom( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria ); + static int FindAllHints( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria, CUtlVector *pResult ); + static int FindAllHints( const Vector &position, const CHintCriteria &hintCriteria, CUtlVector *pResult ) { return FindAllHints( NULL, position, hintCriteria, pResult ); } + static int FindAllHints( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, CUtlVector *pResult ) { return FindAllHints( pNPC, pNPC->GetAbsOrigin(), hintCriteria, pResult ); } + static int GetFlags( const char *token ); + + static CAI_Hint *GetFirstHint( AIHintIter_t *pIter ); + static CAI_Hint *GetNextHint( AIHintIter_t *pIter ); + + static void DumpHints(); + + static void ValidateHints(); + +private: + enum + { + // MUST BE POWER OF 2 + HINT_HISTORY = (1<<3), + HINT_HISTORY_MASK = (HINT_HISTORY-1) + }; + + static CAI_Hint *AddFoundHint( CAI_Hint *hint ); + static int GetFoundHintCount(); + static CAI_Hint *GetFoundHint( int index ); + static CAI_Hint *GetLastFoundHint(); + static void ResetFoundHints(); + static bool IsInFoundHintList( CAI_Hint *hint ); + + static int gm_nFoundHintIndex; + static CAI_Hint *gm_pLastFoundHints[ HINT_HISTORY ]; // Last used hint + static CAIHintVector gm_AllHints; // A linked list of all hints + static CUtlMap< int, CAIHintVector > gm_TypedHints; +}; + +//----------------------------------------------------------------------------- +// CAI_Hint +//----------------------------------------------------------------------------- + +class CAI_Hint : public CServerOnlyEntity +{ + DECLARE_CLASS( CAI_Hint, CServerOnlyEntity ); +public: + CAI_Hint( void ); + ~CAI_Hint( void ); + + // Interface for specific nodes + bool Lock( CBaseEntity *pNPC ); // Makes unavailable for hints + void Unlock( float delay = 0.0 ); // Makes available for hints after delay + bool IsLocked(void); // Whether this node is available for use. + bool IsLockedBy( CBaseEntity *pNPC ); // Whether this node is available for use. + void GetPosition(CBaseCombatCharacter *pBCC, Vector *vPosition); + void GetPosition( Hull_t hull, Vector *vPosition ); + Vector GetDirection( void ); + float Yaw( void ); + CAI_Node *GetNode( void ); + string_t GetGroup( void ) const { return m_NodeData.strGroup; } + CBaseEntity *User( void ) const { return m_hHintOwner; }; + Hint_e HintType( void ) const { return (Hint_e)m_NodeData.nHintType; }; + void SetHintType( int hintType, bool force = false ); + string_t HintActivityName( void ) const { return m_NodeData.iszActivityName; } + int GetTargetNode( void ) const { return m_nTargetNodeID; } + bool IsDisabled( void ) const { return (m_NodeData.iDisabled != 0); } + void SetDisabled( bool bDisabled ) { m_NodeData.iDisabled = bDisabled; } + void DisableForSeconds( float flSeconds ); + void EnableThink(); + void FixupTargetNode(); + void NPCStartedUsing( CAI_BaseNPC *pNPC ); + void NPCStoppedUsing( CAI_BaseNPC *pNPC ); + + HintIgnoreFacing_t GetIgnoreFacing() const { return m_NodeData.fIgnoreFacing; } + + NPC_STATE GetMinState() const { return m_NodeData.minState; } + NPC_STATE GetMaxState() const { return m_NodeData.maxState; } + + int GetNodeId() { return m_NodeData.nNodeID; } + int GetWCId() { return m_NodeData.nWCNodeID; } + + bool HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock = false, bool bIgnoreHintType = false ); + bool IsInNodeFOV( CBaseEntity *pOther ); + +private: + void Spawn( void ); + virtual void Activate(); + virtual void UpdateOnRemove( void ); + int DrawDebugTextOverlays(void); + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + virtual void OnRestore(); + bool IsViewable( void ); + + // Input handlers + void InputEnableHint( inputdata_t &inputdata ); + void InputDisableHint( inputdata_t &inputdata ); + +private: + + HintNodeData m_NodeData; + int m_nTargetNodeID; + EHANDLE m_hHintOwner; // Is hint locked (being used by NPC / NPC en-route to use it) + float m_flNextUseTime; // When can I be used again? + COutputEHANDLE m_OnNPCStartedUsing; // Triggered when an NPC has actively begun to use the node. + COutputEHANDLE m_OnNPCStoppedUsing; // Triggered when an NPC has finished using this node. + float m_nodeFOV; + Vector m_vecForward; + + // The next hint in list of all hints + friend class CAI_HintManager; + + DECLARE_DATADESC(); +}; + +#define SF_ALLOW_JUMP_UP 65536 + + +#endif //AI_HINT_H diff --git a/game/server/ai_hull.h b/game/server/ai_hull.h new file mode 100644 index 0000000..348f730 --- /dev/null +++ b/game/server/ai_hull.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=============================================================================// + +#ifndef AI_HULL_H +#define AI_HULL_H +#pragma once + +class Vector; +//========================================================= +// Link Properties. These hulls must correspond to the hulls +// in AI_Hull.cpp! +//========================================================= +enum Hull_t +{ + HULL_HUMAN, // Combine, Stalker, Zombie... + HULL_SMALL_CENTERED, // Scanner + HULL_WIDE_HUMAN, // Vortigaunt + HULL_TINY, // Headcrab + HULL_WIDE_SHORT, // Bullsquid + HULL_MEDIUM, // Cremator + HULL_TINY_CENTERED, // Manhack + HULL_LARGE, // Antlion Guard + HULL_LARGE_CENTERED, // Mortar Synth + HULL_MEDIUM_TALL, // Hunter +//-------------------------------------------- + NUM_HULLS, + HULL_NONE // No Hull (appears after num hulls as we don't want to count it) +}; + +enum Hull_Bits_t +{ + bits_HUMAN_HULL = 0x00000001, + bits_SMALL_CENTERED_HULL = 0x00000002, + bits_WIDE_HUMAN_HULL = 0x00000004, + bits_TINY_HULL = 0x00000008, + bits_WIDE_SHORT_HULL = 0x00000010, + bits_MEDIUM_HULL = 0x00000020, + bits_TINY_CENTERED_HULL = 0x00000040, + bits_LARGE_HULL = 0x00000080, + bits_LARGE_CENTERED_HULL = 0x00000100, + bits_MEDIUM_TALL_HULL = 0x00000200, + bits_HULL_BITS_MASK = 0x000002ff, +}; + +inline int HullToBit( Hull_t hull ) +{ + return ( 1 << hull ); +} + + + +//============================================================================= +// >> CAI_Hull +//============================================================================= +namespace NAI_Hull +{ + const Vector &Mins(int id); + const Vector &Maxs(int id); + + const Vector &SmallMins(int id); + const Vector &SmallMaxs(int id); + + float Length(int id); + float Width(int id); + float Height(int id); + + int Bits(int id); + + const char* Name(int id); + + Hull_t LookupId(const char *szName); +}; + +#endif // AI_HULL_H diff --git a/game/server/ai_initutils.h b/game/server/ai_initutils.h new file mode 100644 index 0000000..22aaf5f --- /dev/null +++ b/game/server/ai_initutils.h @@ -0,0 +1,105 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: AI Utility classes for building the initial AI Networks +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_INITUTILS_H +#define AI_INITUTILS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ai_basenpc.h" +#include "ai_node.h" + +//########################################################### +// >> HintNodeData +// +// This is a chunk of data that's passed to a hint node entity +// when it's created from a CNodeEnt. +//########################################################### +enum HintIgnoreFacing_t +{ + HIF_NO, + HIF_YES, + HIF_DEFAULT, +}; + + +struct HintNodeData +{ + string_t strEntityName; + Vector vecPosition; + short nHintType; + int nNodeID; + string_t strGroup; + int iDisabled; + string_t iszActivityName; + int nTargetWCNodeID; + HintIgnoreFacing_t fIgnoreFacing; + NPC_STATE minState; + NPC_STATE maxState; + + int nWCNodeID; // Node ID assigned by worldcraft (not same as engine!) + + DECLARE_SIMPLE_DATADESC(); +}; + +//########################################################### +// >> CNodeEnt +// +// This is the entity that is loaded in from worldcraft. +// It is only used to build the network and is deleted +// immediately +//########################################################### +class CNodeEnt : public CServerOnlyPointEntity +{ + DECLARE_CLASS( CNodeEnt, CServerOnlyPointEntity ); + +public: + virtual void SetOwnerEntity( CBaseEntity* pOwner ) { BaseClass::SetOwnerEntity( NULL ); } + + static int m_nNodeCount; + + void Spawn( void ); + int Spawn( const char *pMapData ); + + DECLARE_DATADESC(); + + CNodeEnt(void); + +public: + HintNodeData m_NodeData; +}; + +//########################################################### +// >> CAI_TestHull +// +// a modelless clip hull that verifies reachable nodes by +// walking from every node to each of it's connections// +//########################################################### +class CAI_TestHull : public CAI_BaseNPC +{ + DECLARE_CLASS( CAI_TestHull, CAI_BaseNPC ); +private: + static CAI_TestHull* pTestHull; // Hull for testing connectivity + +public: + static CAI_TestHull* GetTestHull(void); // Get the test hull + static void ReturnTestHull(void); // Return the test hull + + bool bInUse; + virtual void Precache(); + void Spawn(void); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~(FCAP_ACROSS_TRANSITION|FCAP_DONT_SAVE); } + + virtual bool IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const; + + ~CAI_TestHull(void); +}; + + +#endif // AI_INITUTILS_H diff --git a/game/server/ai_link.h b/game/server/ai_link.h new file mode 100644 index 0000000..d9d5713 --- /dev/null +++ b/game/server/ai_link.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base combat character with no AI +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_LINK_H +#define AI_LINK_H +#pragma once + +#include "ai_hull.h" // For num hulls + +struct edict_t; + +enum Link_Info_t +{ + bits_LINK_STALE_SUGGESTED = 0x01, // NPC found this link to be blocked + bits_LINK_OFF = 0x02, // This link has been turned off +}; + +//============================================================================= +// >> CAI_Link +//============================================================================= + +class CAI_DynamicLink; + +#define AI_MOVE_TYPE_BITS ( bits_CAP_MOVE_GROUND | bits_CAP_MOVE_JUMP | bits_CAP_MOVE_FLY | bits_CAP_MOVE_CLIMB | bits_CAP_MOVE_SWIM | bits_CAP_MOVE_CRAWL ) + +class CAI_Link +{ +public: + + short m_iSrcID; // the node that 'owns' this link + short m_iDestID; // the node on the other end of the link. + + int DestNodeID(int srcID); // Given the source node ID, returns the destination ID + + byte m_iAcceptedMoveTypes[NUM_HULLS]; // Capability_T of motions acceptable for each hull type + + byte m_LinkInfo; // other information about this link + + float m_timeStaleExpires; + + CAI_DynamicLink *m_pDynamicLink; + + //edict_t *m_pLinkEnt; // the entity that blocks this connection (doors, etc) + + // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) + //char m_szLinkEntModelname[ 4 ];// the unique name of the brush model that blocks the connection (this is kept for save/restore) + + //float m_flWeight; // length of the link line segment + +private: + friend class CAI_Network; + CAI_Link(void); +}; + +#endif // AI_LINK_H diff --git a/game/server/ai_localnavigator.h b/game/server/ai_localnavigator.h new file mode 100644 index 0000000..a6f4801 --- /dev/null +++ b/game/server/ai_localnavigator.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_LOCALNAVIGATOR_H +#define AI_LOCALNAVIGATOR_H + +#include "simtimer.h" +#include "ai_component.h" +#include "ai_movetypes.h" +#include "ai_obstacle_type.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class CAI_PlaneSolver; +class CAI_MoveProbe; + +//----------------------------------------------------------------------------- +// CAI_LocalNavigator +// +// Purpose: Handles all the immediate tasks of navigation, independent of +// path. Implements steering. +//----------------------------------------------------------------------------- + +class CAI_LocalNavigator : public CAI_Component, + public CAI_ProxyMovementSink +{ +public: + CAI_LocalNavigator(CAI_BaseNPC *pOuter); + virtual ~CAI_LocalNavigator(); + + void Init( IAI_MovementSink *pMovementServices ); + + //--------------------------------- + + AIMoveResult_t MoveCalc( AILocalMoveGoal_t *pResult, bool bPreviouslyValidated = false ); + void ResetMoveCalculations(); + + //--------------------------------- + + void AddObstacle( const Vector &pos, float radius, AI_MoveSuggType_t type = AIMST_AVOID_OBJECT ); + bool HaveObstacles(); + +protected: + + AIMoveResult_t MoveCalcRaw( AILocalMoveGoal_t *pResult, bool bOnlyCurThink ); + bool MoveCalcDirect( AILocalMoveGoal_t *pMoveGoal, bool bOnlyCurThink, float *pDistClear, AIMoveResult_t *pResult ); + bool MoveCalcSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + bool MoveCalcStop( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + + CAI_MoveProbe * GetMoveProbe() { return m_pMoveProbe; } + const CAI_MoveProbe *GetMoveProbe() const { return m_pMoveProbe; } + +private: + + // -------------------------------- + + bool m_fLastWasClear; + AILocalMoveGoal_t m_LastMoveGoal; + CSimpleSimTimer m_FullDirectTimer; + + CAI_PlaneSolver * m_pPlaneSolver; + CAI_MoveProbe * m_pMoveProbe; + + DECLARE_SIMPLE_DATADESC(); +}; + +#endif // AI_LOCALNAVIGATOR_H diff --git a/game/server/ai_looktarget.h b/game/server/ai_looktarget.h new file mode 100644 index 0000000..a98ceb0 --- /dev/null +++ b/game/server/ai_looktarget.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#pragma once +#ifndef AI_LOOKTARGET_H +#define AI_LOOKTARGET_H + +#define SF_LOOKTARGET_ONLYONCE 0x00000001 + +//============================================================================= +//============================================================================= +class CAI_LookTarget : public CPointEntity +{ +public: + DECLARE_CLASS( CAI_LookTarget, CPointEntity ); + DECLARE_DATADESC(); + + CAI_LookTarget() { m_flTimeNextAvailable = -1; } + + // Debugging + int DrawDebugTextOverlays(void); + + // Accessors & Availability + bool IsEligible( CBaseEntity *pLooker ); + bool IsEnabled() { return !m_bDisabled; } + bool IsAvailable() { return (gpGlobals->curtime > m_flTimeNextAvailable); } + void Reserve( float flDuration ); + + // Searching + static CAI_LookTarget *GetFirstLookTarget(); + static CAI_LookTarget *GetNextLookTarget( CAI_LookTarget *pCurrentTarget ); + + int m_iContext; + int m_iPriority; + + void Enable() { m_bDisabled = false; } + void Disable() { m_bDisabled = true; } + +private: + bool m_bDisabled; + float m_flTimeNextAvailable; + float m_flMaxDist; +}; + +#endif//AI_LOOKTARGET_H \ No newline at end of file diff --git a/game/server/ai_memory.h b/game/server/ai_memory.h new file mode 100644 index 0000000..d348c53 --- /dev/null +++ b/game/server/ai_memory.h @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: An NPC's memory of potential enemies +// +//=============================================================================// + +#include "mempool.h" +#include "utlmap.h" + +#ifndef AI_MEMORY_H +#define AI_MEMORY_H +#pragma once + +class CAI_Network; + +DECLARE_POINTER_HANDLE(AIEnemiesIter_t); + +const float AI_DEF_ENEMY_DISCARD_TIME = 60.0; + +#define AI_UNKNOWN_ENEMY (((CBaseEntity *)NULL)+1) // use this to probe for unseen attackers +#define AI_INVALID_TIME (FLT_MAX * -1.0) + +//----------------------------------------------------------------------------- +// AI_EnemyInfo_t +// +// Purpose: Stores relevant tactical information about an enemy +// +//----------------------------------------------------------------------------- +struct AI_EnemyInfo_t +{ + AI_EnemyInfo_t(); + + EHANDLE hEnemy; // Pointer to the enemy + + Vector vLastKnownLocation; + Vector vLastSeenLocation; + float timeLastSeen; // Last time enemy was seen + float timeFirstSeen; // First time enemy was seen + float timeLastReacquired; + float timeValidEnemy; // First time can be selected (reaction delay) + float timeLastReceivedDamageFrom; + float timeAtFirstHand; // Time at which the enemy was seen firsthand + bool bDangerMemory; // Memory of danger position w/o Enemy pointer + bool bEludedMe; // True if enemy not at last known location + bool bUnforgettable; + bool bMobbedMe; // True if enemy was part of a mob at some point + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// CAI_Enemies +// +// Purpose: Stores a set of AI_EnemyInfo_t's +// +//----------------------------------------------------------------------------- +class CAI_Enemies +{ +public: + CAI_Enemies(void); + ~CAI_Enemies(); + + AI_EnemyInfo_t *GetFirst( AIEnemiesIter_t *pIter ); + AI_EnemyInfo_t *GetNext( AIEnemiesIter_t *pIter ); + AI_EnemyInfo_t *Find( CBaseEntity *pEntity, bool bTryDangerMemory = false ); + AI_EnemyInfo_t *GetDangerMemory(); + + int NumEnemies() const { return m_Map.Count(); } + int GetSerialNumber() const { return m_serial; } + + void RefreshMemories(void); + bool UpdateMemory( CAI_Network* pAINet, CBaseEntity *enemy, const Vector &vPosition, float reactionDelay, bool firstHand ); + void OnTookDamageFrom( CBaseEntity *pEnemy ); + + bool HasMemory( CBaseEntity *enemy ); + void ClearMemory( CBaseEntity *enemy ); + + const Vector & LastKnownPosition( CBaseEntity *pEnemy ); + const Vector & LastSeenPosition( CBaseEntity *pEnemy ); + + float TimeLastReacquired( CBaseEntity *pEnemy ); + float LastTimeSeen( CBaseEntity *pEnemy, bool bCheckDangerMemory = true ); + float FirstTimeSeen( CBaseEntity *pEnemy); + bool HasFreeKnowledgeOf( CBaseEntity *pEnemy ); + + float LastTimeTookDamageFrom( CBaseEntity *pEnemy); + + float TimeAtFirstHand( CBaseEntity *pEnemy ); + + void MarkAsEluded( CBaseEntity *enemy ); // Don't know where he is (whole squad) + bool HasEludedMe( CBaseEntity *pEnemy ); + + void SetTimeValidEnemy( CBaseEntity *pEnemy, float flTime ); + + void SetUnforgettable( CBaseEntity *pEnemy, bool bUnforgettable = true ); + void SetMobbedMe( CBaseEntity *pEnemy, bool bMobbedMe = true ); + + void SetFreeKnowledgeDuration( float flDuration ); + void SetEnemyDiscardTime( float flTime ); + float GetEnemyDiscardTime( void ) const { return m_flEnemyDiscardTime; } + + DECLARE_SIMPLE_DATADESC(); + + typedef CUtlMap CMemMap; + +private: + bool ShouldDiscardMemory( AI_EnemyInfo_t *pMemory ); + + CMemMap m_Map; + float m_flFreeKnowledgeDuration; + float m_flEnemyDiscardTime; + Vector m_vecDefaultLKP; + Vector m_vecDefaultLSP; + int m_serial; +}; + +//----------------------------------------------------------------------------- + +#endif // AI_MEMORY_H diff --git a/game/server/ai_motor.h b/game/server/ai_motor.h new file mode 100644 index 0000000..d7f1429 --- /dev/null +++ b/game/server/ai_motor.h @@ -0,0 +1,225 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_MOTOR_H +#define AI_MOTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "simtimer.h" +#include "ai_component.h" +#include "ai_navtype.h" +#include "ai_movetypes.h" +#include "AI_Interest_Target.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +enum Navigation_t; +class CAI_PlaneSolver; +class CAI_MoveProbe; +class CAI_Navigator; + +#define AI_CALC_YAW_SPEED -1 +#define AI_KEEP_YAW_SPEED -2 + +//----------------------------------------------------------------------------- + +float AI_ClampYaw( float yawSpeedPerSec, float current, float target, float time ); + +//----------------------------------------------------------------------------- +// CAI_Motor +// +// Purpose: Implements the primitive locomotion of AIs. +//----------------------------------------------------------------------------- + +class CAI_Motor : public CAI_Component, + public CAI_ProxyMovementSink +{ +public: + CAI_Motor(CAI_BaseNPC *pOuter); + virtual ~CAI_Motor(); + + void Init( IAI_MovementSink *pMovementServices ); + + // -------------------------------- + // The current timestep the motor is working on + // -------------------------------- + float GetMoveInterval() { return m_flMoveInterval; } + float SetMoveInterval( float flInterval ) { return (m_flMoveInterval = flInterval); } + + // ---------------------------------------------------- + // Translational movement + // ---------------------------------------------------- + AIMoveResult_t MoveNormalExecute( const AILocalMoveGoal_t &move ); + + virtual void MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw ); + virtual AIMoveResult_t MoveClimbExecute( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw, int climbNodesLeft ); + virtual void MoveClimbStop(); + + //--------------------------------- + + + virtual void MoveJumpStart( const Vector &velocity ); + virtual int MoveJumpExecute(); + virtual AIMoveResult_t MoveJumpStop(); + + virtual void ResetMoveCalculations(); + virtual void MoveStart(); + virtual void MoveStop(); + virtual void MovePaused(); + + //--------------------------------- + + float GetIdealSpeed() const; + float GetIdealAccel() const; + float GetCurSpeed() const { return m_vecVelocity.Length(); } + const Vector & GetCurVel() const { return m_vecVelocity; } + + virtual float OverrideMaxYawSpeed( Activity activity ) { return -1; } + bool IsDeceleratingToGoal() const { return false; } + + //--------------------------------- + // Raw ground step forward to the specifed position + // + + AIMotorMoveResult_t MoveGroundStep( const Vector &newPos, CBaseEntity *pMoveTarget = NULL, float yaw = -1, bool bAsFarAsCan = true, bool bTestZ = true, AIMoveTrace_t *pTraceResult = NULL ); + + // ---------------------------------------------------- + // Rotational movement (yaw); goal and speed + // ---------------------------------------------------- + + void SetYawSpeed( float yawSpeed ) { m_YawSpeed = yawSpeed; } + float GetYawSpeed() const { return m_YawSpeed; } + float GetIdealYaw() const { return m_IdealYaw; } + void SetIdealYaw( float idealYaw) { m_IdealYaw = idealYaw; } + + // Set ideal yaw specified as a vector + void SetIdealYaw( const Vector &vecFacing) { SetIdealYaw( UTIL_VecToYaw( vecFacing )); } + + // Set ideal yaw based on a specified target + void SetIdealYawToTarget( const Vector &target, float noise = 0.0, float offset = 0.0 ); + + // Set the ideal yaw and run the current or specified timestep worth of rotation. Note + // it is not correct to call any "update" variant of these methods more + // than once per think cycle + void SetIdealYawAndUpdate( float idealYaw, float yawSpeed = AI_CALC_YAW_SPEED ); + void SetIdealYawAndUpdate( const Vector &vecFacing, float yawSpeed = AI_CALC_YAW_SPEED ) { SetIdealYawAndUpdate( UTIL_VecToYaw( vecFacing ), yawSpeed ); } + void SetIdealYawToTargetAndUpdate( const Vector &target, float yawSpeed = AI_CALC_YAW_SPEED ); + + // Add multiple facing goals while moving/standing still. + virtual void AddFacingTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual void AddFacingTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual void AddFacingTarget( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ); + virtual float GetFacingDirection( Vector &vecDir ); + + // Force the heading to the ideal yaw + void SnapYaw() { UpdateYaw(360); } + + // Run the current or specified timestep worth of rotation + virtual void UpdateYaw( int speed = -1 ); + + // + virtual void RecalculateYawSpeed(); + + // Returns the difference ( in degrees ) between npc's current yaw and ideal_yaw + float DeltaIdealYaw(); + + // Issues turn gestures when needed due to turning + virtual void MaintainTurnActivity( void ) { }; + virtual bool AddTurnGesture( float flYD ) { return false; }; + + // -------------------------------- + // Move primitives + // -------------------------------- + virtual float MinStoppingDist( float flMinResult = 10.0 ); // how far before I can come to a complete stop? + virtual float MinCheckDist(); // how far should I look ahead in my route? + + //--------------------------------- + + CAI_Navigator *GetNavigator( void ); + int SelectWeightedSequence( Activity activity ); + float GetSequenceGroundSpeed( int iSequence ); + + float CalcIntervalMove(); + + // Yaw locking + bool IsYawLocked( void ) const { return m_bYawLocked; } + void SetYawLocked( bool state ) { m_bYawLocked = state; } + +protected: + + // + // Common services provided by CAI_BaseNPC, Convenience methods to simplify derived code + // + CAI_MoveProbe * GetMoveProbe() { return m_pMoveProbe; } + void SetSmoothedVelocity(const Vector &vecVelocity); + Vector GetSmoothedVelocity(); + float CalcIdealYaw( const Vector &vecTarget ); + float SetBoneController ( int iController, float flValue ); + float GetSequenceMoveYaw( int iSequence ); + void SetPlaybackRate( float flRate ); + float GetPlaybackRate(); //get + float SetPoseParameter( const char *szName, float flValue ); + float SetPoseParameter( int iParameter, float flValue ); + float GetPoseParameter( const char *szName ); + bool HasPoseParameter( int iSequence, const char *szName ); + bool HasPoseParameter( int iSequence, int iParameter ); + void SetMoveType( MoveType_t val, MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT ); + float StepHeight() const; + bool CanStandOn( CBaseEntity *pSurface ) const; + + // ---------------------------------------------------- + // Primitives + // ---------------------------------------------------- + + virtual void MoveFacing( const AILocalMoveGoal_t &move ); + + virtual AIMotorMoveResult_t MoveGroundExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ); + AIMotorMoveResult_t MoveGroundExecuteWalk( const AILocalMoveGoal_t &move, float speed, float dist, AIMoveTrace_t *pTraceResult ); + virtual AIMotorMoveResult_t MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult ); + +protected: // made protected while animation transition details worked out, private: + + // -------------------------------- + void SetMoveVel(const Vector &velocity) { m_vecVelocity = velocity; } + float IdealVelocity(); // how fast should I be moving in an ideal state? + + // -------------------------------- + float m_flMoveInterval; + + float m_IdealYaw; + float m_YawSpeed; + + Vector m_vecVelocity; + Vector m_vecAngularVelocity; + + // -------------------------------- + + int m_nDismountSequence; + Vector m_vecDismount; + + // -------------------------------- + + CAI_InterestTarget m_facingQueue; + + // -------------------------------- + + CAI_MoveProbe * m_pMoveProbe; + + bool m_bYawLocked; + + //--------------------------------- +public: + DECLARE_SIMPLE_DATADESC(); +}; + +//============================================================================= + +#endif // AI_MOTOR_H diff --git a/game/server/ai_moveprobe.h b/game/server/ai_moveprobe.h new file mode 100644 index 0000000..8bf1c7c --- /dev/null +++ b/game/server/ai_moveprobe.h @@ -0,0 +1,161 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_MOVEPROBE_H +#define AI_MOVEPROBE_H + +#include "ai_component.h" +#include "ai_navtype.h" +#include "ai_movetypes.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Set of basic tools for probing box movements through space. +// No moves actually take place +//----------------------------------------------------------------------------- + +enum AI_TestGroundMoveFlags_t +{ + AITGM_DEFAULT = 0, + AITGM_IGNORE_FLOOR = 0x01, + AITGM_IGNORE_INITIAL_STAND_POS = 0x02, + AITGM_2D = 0x04, + AITGM_DRAW_RESULTS = 0x08, +}; + +enum AI_MoveLimitFlags_t +{ + AIMLF_DEFAULT = 0, + AIMLF_2D = 0x01, + AIMLF_DRAW_RESULTS = 0x02, + AIMLF_IGNORE_TRANSIENTS = 0x04, + AIMLF_QUICK_REJECT = 0x08, +}; + +class CAI_MoveProbe : public CAI_Component +{ +public: + + CAI_MoveProbe( CAI_BaseNPC *pOuter ); + ~CAI_MoveProbe(); + + // ---------------------------------------------------- + // Queries & probes + // ---------------------------------------------------- + bool MoveLimit( Navigation_t navType, const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, AIMoveTrace_t* pMove = NULL ); + bool MoveLimit( Navigation_t navType, const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, float pctToCheckStandPositions, AIMoveTrace_t* pMove = NULL ); + bool MoveLimit( Navigation_t navType, const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, float pctToCheckStandPositions, unsigned flags, AIMoveTrace_t* pMove = NULL ); + + bool CheckStandPosition( const Vector &vecStart, unsigned int collisionMask ) const; + bool FloorPoint( const Vector &vecStart, unsigned int collisionMask, float flStartZ, float flEndZ, Vector *pVecResult ) const; + + // -------------------------------- + // Tracing tools + // -------------------------------- + void TraceLine( const Vector &vecStart, const Vector &vecEnd, unsigned int mask, + bool bUseCollisionGroup, trace_t *pResult ) const; + + void TraceHull( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, + const Vector &hullMax, unsigned int mask, + trace_t *ptr ) const; + + void TraceHull( const Vector &vecStart, const Vector &vecEnd, unsigned int mask, + trace_t *ptr ) const; + + // -------------------------------- + // Checks a ground-based movement + // -------------------------------- + bool TestGroundMove( const Vector &vecActualStart, const Vector &vecDesiredEnd, + unsigned int collisionMask, unsigned flags, AIMoveTrace_t *pMoveTrace ) const; + + bool TestGroundMove( const Vector &vecActualStart, const Vector &vecDesiredEnd, + unsigned int collisionMask, float pctToCheckStandPositions, unsigned flags, AIMoveTrace_t *pMoveTrace ) const; + + bool ShouldBrushBeIgnored( CBaseEntity *pEntity ); + + void ClearBlockingEntity() { m_hLastBlockingEnt = NULL; } + CBaseEntity * GetBlockingEntity() { return m_hLastBlockingEnt; } + +private: + struct CheckStepArgs_t + { + Vector vecStart; + Vector vecStepDir; + float stepSize; + float stepHeight; + float stepDownMultiplier; + float minStepLanding; + unsigned collisionMask; + StepGroundTest_t groundTest; + }; + + struct CheckStepResult_t + { + Vector endPoint; + Vector hitNormal; + bool fStartSolid; + CBaseEntity * pBlocker; + }; + + + bool CheckStep( const CheckStepArgs_t &args, CheckStepResult_t *pResult ) const; + void SetupCheckStepTraceListData( const CheckStepArgs_t &args ) const; + void ResetTraceListData() const { if ( m_pTraceListData ) const_cast(this)->m_pTraceListData->Reset(); } + bool OldCheckStandPosition( const Vector &vecStart, unsigned int collisionMask ) const; + + // these check connections between positions in space, regardless of routes + void GroundMoveLimit( const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, unsigned testGroundMoveFlags, float pctToCheckStandPositions, AIMoveTrace_t* pMoveTrace ) const; + void FlyMoveLimit( const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, AIMoveTrace_t* pMoveTrace) const; + void JumpMoveLimit( const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, AIMoveTrace_t* pMoveTrace) const; + void ClimbMoveLimit( const Vector &vecStart, const Vector &vecEnd, const CBaseEntity *pTarget, AIMoveTrace_t* pMoveTrace) const; + + // A floorPoint that is useful only in the contect of iterative movement + bool IterativeFloorPoint( const Vector &vecStart, unsigned int collisionMask, Vector *pVecResult ) const; + bool IterativeFloorPoint( const Vector &vecStart, unsigned int collisionMask, float flAddedStep, Vector *pVecResult ) const; + bool IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const; + +public: + Vector CalcJumpLaunchVelocity(const Vector &startPos, const Vector &endPos, float gravity, float *pminHeight, float maxHorzVelocity, Vector *vecApex ) const; +private: + + // Common services provided by CAI_BaseNPC, Convenience methods to simplify code + float StepHeight() const; + bool CanStandOn( CBaseEntity *pSurface ) const; + + bool m_bIgnoreTransientEntities; + + CTraceListData * m_pTraceListData; + + EHANDLE m_hLastBlockingEnt; + + DECLARE_SIMPLE_DATADESC(); +}; + +// ---------------------------------------------------------------------------- + +inline bool CAI_MoveProbe::MoveLimit( Navigation_t navType, const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, float pctToCheckStandPositions, AIMoveTrace_t* pMove) +{ + return MoveLimit( navType, vecStart, vecEnd, collisionMask, pTarget, pctToCheckStandPositions, AIMLF_DEFAULT, pMove); +} + +// ------------------------------------ + +inline bool CAI_MoveProbe::MoveLimit( Navigation_t navType, const Vector &vecStart, const Vector &vecEnd, unsigned int collisionMask, const CBaseEntity *pTarget, AIMoveTrace_t* pMove) +{ + return MoveLimit( navType, vecStart, vecEnd, collisionMask, pTarget, 100.0f, AIMLF_DEFAULT, pMove); +} + +// ------------------------------------ + +inline bool CAI_MoveProbe::TestGroundMove( const Vector &vecActualStart, const Vector &vecDesiredEnd, unsigned int collisionMask, unsigned flags, AIMoveTrace_t *pMoveTrace ) const +{ + return TestGroundMove( vecActualStart, vecDesiredEnd, collisionMask, 100, flags, pMoveTrace ); // floor ignore flag will override 100% +} + +#endif // AI_MOVEPROBE_H diff --git a/game/server/ai_moveshoot.h b/game/server/ai_moveshoot.h new file mode 100644 index 0000000..9fee000 --- /dev/null +++ b/game/server/ai_moveshoot.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_MOVESHOOT_H +#define AI_MOVESHOOT_H + +#include "ai_component.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// @TODO (toml 07-09-03): probably want to fold this into base NPC. evaluate when +// head above water + +class CAI_MoveAndShootOverlay : public CAI_Component +{ + typedef CAI_Component BaseClass; + +public: + CAI_MoveAndShootOverlay(); + + void StartShootWhileMove( ); + void NoShootWhileMove(); + void RunShootWhileMove(); + void EndShootWhileMove(); + void SuspendMoveAndShoot( float flDuration ); + bool IsSuspended() { return m_flSuspendUntilTime > gpGlobals->curtime; } + + void SetInitialDelay( float delay ); + + bool IsMovingAndShooting( void ) const { return m_bMovingAndShooting; } + +private: + + bool HasAvailableRangeAttack(); + bool CanAimAtEnemy(); + void UpdateMoveShootActivity( bool bMoveAimAtEnemy ); + + bool m_bMovingAndShooting; + bool m_bNoShootWhileMove; + float m_initialDelay; + float m_flSuspendUntilTime; + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- + +#endif // AI_MOVESHOOT_H diff --git a/game/server/ai_movesolver.h b/game/server/ai_movesolver.h new file mode 100644 index 0000000..8f6826b --- /dev/null +++ b/game/server/ai_movesolver.h @@ -0,0 +1,312 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: "Force-field" obstacle avoidance & steering +// +// @Note (toml 06-18-02): Currently only controls direction. Ultimately could +// also incorporate body facing (yaw), speed, and translational/rotational +// acceleration. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_MOVESOLVER_H +#define AI_MOVESOLVER_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "utlvector.h" +#include "ai_obstacle_type.h" + + +//----------------------------------------------------------------------------- + +inline float NormalizeAngle( float angle ) +{ + if ( angle < 0.0 ) + angle += 360.0; + else if ( angle >= 360.0 ) + angle -= 360.0; + return angle; +} + +//----------------------------------------------------------------------------- +// ENUMERATIONS +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// STRUCTURES +//----------------------------------------------------------------------------- + +//------------------------------------- +// AI_Arc_t +// +// Purpose: Represents an arc. +// +//------------------------------------- +struct AI_Arc_t +{ + AI_Arc_t() + : center( 0 ), + span( 0 ) + { + } + + // Set by center and span + void Set( float newCenter, float newSpan ); + + // Set by the right and left extremes (coordinates run counter clockwise) + void SetByLimits( float yawRight, float yawLeft ); + + // Center of the arc (as "yaw") + float center; + + // Span of the arc (in degrees) + float span; +}; + +//------------------------------------- +// AI_MoveSuggestion_t +// +// Purpose: Suggests a possible move/avoidance, with a range of acceptable alternatives +// +// @Note (toml 06-20-02): this probably will eventually want to incorporate facing and +// destination of the motivating goal. +// +//------------------------------------- + +enum AI_MoveSuggestionFlags_t +{ + AIMS_FAVOR_LEFT = 0x01, + AIMS_FAVOR_RIGHT = 0x02 +}; + +//----------------- + +struct AI_MoveSuggestion_t +{ + AI_MoveSuggestion_t(); + AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity = NULL ); + AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity = NULL ); + + void Set( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity = NULL ); + void Set( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity = NULL ); + + //--------------------------------- + + // The kind of suggestion + AI_MoveSuggType_t type; + + // The unadjusted weight of the suggestion [0..1], although [-1..1] within the solver + float weight; + + // The desired direction to move/avoid + AI_Arc_t arc; + + // The causing entity, if any + EHANDLE hObstacleEntity; + + // Flags + unsigned flags; + +}; + +//----------------- + +typedef CUtlVector CAI_MoveSuggestions; + +//------------------------------------- +// AI_MoveSolution_t +// +// Purpose: The result of resolving suggestions +// +// @Note (toml 06-18-02): Currently, this is a very dopey little structure. +// However, it will probably eventually incorporate much of the info +// passed or calculated piecemeal between Move...() and Move...Execute() +// functions. Once suggestions incorprate more information, the solution +// may want to include a copy of the winning suggestion, so that the +// caller need retain less state. If this is not the case, reduce it to just +// a yaw. +// +//------------------------------------- +struct AI_MoveSolution_t +{ + AI_MoveSolution_t() + : dir(0) + { + } + + // The direction to move + float dir; +}; + +//----------------------------------------------------------------------------- +// class CAI_MoveSolver +// +// Purpose: Given a set of precalculated "regulations" (typically negative), +// and a set of instantaneous suggestions (usually positive) +//----------------------------------------------------------------------------- + +class CAI_MoveSolver +{ +public: + CAI_MoveSolver(); + + //--------------------------------- + // Purpose: A regulation is a suggestion that is kept around as a rule until + // cleared. They are generally negative suggestions. + //--------------------------------- + void AddRegulation( const AI_MoveSuggestion_t &suggestion ); + void AddRegulations( const AI_MoveSuggestion_t *pSuggestion, int nSuggestions ); + + bool HaveRegulations() const; + void ClearRegulations(); + + //--------------------------------- + // Purpose: Solve the move, picking the best direction from a set of suggestions, + // after applying the regulations + //--------------------------------- + bool Solve( const AI_MoveSuggestion_t *pSuggestions, int nSuggestions, AI_MoveSolution_t *pResult ); + bool Solve( const AI_MoveSuggestion_t &suggestion, AI_MoveSolution_t *pResult ); + + //--------------------------------- + bool HaveRegulationForObstacle( CBaseEntity *pEntity); + + //--------------------------------- + // Visualization + void VisualizeRegulations( const Vector& origin ); + +private: + enum + { + REGS_RESERVE = 8, + }; + + //--------------------------------- + void NormalizeSuggestions( AI_MoveSuggestion_t *pBegin, AI_MoveSuggestion_t *pEnd ); + + //--------------------------------- + CAI_MoveSuggestions m_Regulations; +}; + +//----------------------------------------------------------------------------- +// AI_Arc_t inline methods +//----------------------------------------------------------------------------- + +inline void AI_Arc_t::Set( float newCenter, float newSpan ) +{ + center = NormalizeAngle( newCenter ); + span = NormalizeAngle( newSpan ); +} + +//------------------------------------- + +inline void AI_Arc_t::SetByLimits( float yawRight, float yawLeft ) +{ + // Yaw runs counter-clockwise + span = yawLeft - yawRight; + + if ( span < 0 ) + span += 360; + + center = yawRight + span * 0.5; + + if ( center >= 360 ) + center -= 360; +} + +//----------------------------------------------------------------------------- +// AI_MoveSuggestion_t inline methods +//----------------------------------------------------------------------------- + +inline void AI_MoveSuggestion_t::Set( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity ) +{ + type = newType; + weight = newWeight; + hObstacleEntity = pEntity; + flags = 0; + + arc.Set( newDir, newSpan ); +} + +//------------------------------------- + +inline AI_MoveSuggestion_t::AI_MoveSuggestion_t() + : type( AIMS_INVALID ), + weight( 0 ), + flags( 0 ) +{ +} + +//------------------------------------- + +inline AI_MoveSuggestion_t::AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity ) +{ + Set( newType, newWeight, newDir, newSpan, pEntity ); +} + +//------------------------------------- + +inline AI_MoveSuggestion_t::AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity ) +{ + Set( newType, newWeight, arc.center, arc.span, pEntity ); +} + +//------------------------------------- + +inline void AI_MoveSuggestion_t::Set( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity ) +{ + Set( newType, newWeight, arc.center, arc.span, pEntity ); +} + +//----------------------------------------------------------------------------- +// CAI_MoveSolver inline methods +//----------------------------------------------------------------------------- + +inline CAI_MoveSolver::CAI_MoveSolver() +{ + m_Regulations.EnsureCapacity( REGS_RESERVE ); +} + +//------------------------------------- + +inline void CAI_MoveSolver::AddRegulation( const AI_MoveSuggestion_t &suggestion ) +{ + m_Regulations.AddToTail( suggestion ); +} + +//------------------------------------- + +inline void CAI_MoveSolver::AddRegulations( const AI_MoveSuggestion_t *pSuggestions, int nSuggestions ) +{ + for (int i = 0; i < nSuggestions; ++i) + { + m_Regulations.AddToTail( pSuggestions[i] ); + } +} + +//------------------------------------- + +inline bool CAI_MoveSolver::HaveRegulations() const +{ + return (m_Regulations.Count() > 0); +} + +//------------------------------------- + +inline void CAI_MoveSolver::ClearRegulations() +{ + m_Regulations.RemoveAll(); +} + +//------------------------------------- + +inline bool CAI_MoveSolver::Solve( const AI_MoveSuggestion_t &suggestion, AI_MoveSolution_t *pResult) +{ + return Solve( &suggestion, 1, pResult); +} + +//============================================================================= + +#endif // AI_MOVESOLVER_H diff --git a/game/server/ai_movetypes.h b/game/server/ai_movetypes.h new file mode 100644 index 0000000..b255921 --- /dev/null +++ b/game/server/ai_movetypes.h @@ -0,0 +1,383 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_MOVETYPES_H +#define AI_MOVETYPES_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "ai_navtype.h" + +class CAI_Path; + +//----------------------------------------------------------------------------- +// Debugging code +// +// Use this function to set breakpoints to find out where movement is failing +// +#ifdef DEBUG +extern void DebugNoteMovementFailure(); +#define DebugNoteMovementFailureIfBlocked( moveResult ) if ( !IsMoveBlocked( moveResult ) ) ((void)0); else DebugNoteMovementFailure() +#else +#define DebugNoteMovementFailure() ((void)0) +#define DebugNoteMovementFailureIfBlocked( moveResult ) ((void)0) +#endif + +enum AIMoveResult_t +{ + AIMR_BLOCKED_ENTITY = -1, // Move was blocked by an entity + AIMR_BLOCKED_WORLD = -2, // Move was blocked by the world + AIMR_BLOCKED_NPC = -3, // Move was blocked by an NPC + AIMR_ILLEGAL = -4, // Move is illegal for some reason + + AIMR_OK = 0, + + AIMR_CHANGE_TYPE, // Locomotion method has changed +}; + + +#ifdef DEBUG +extern AIMoveResult_t DbgResult( AIMoveResult_t result ); +#else +inline AIMoveResult_t DbgResult( AIMoveResult_t result ) { return result; } // inline not macro for compiler typing +#endif + + +//----------------------------------------------------------------------------- +// Movement related constants and base types +//----------------------------------------------------------------------------- +#ifdef PHYSICS_NPC_SHADOW_DISCREPENCY +const float AI_EPS_CASTS = 0.3; // The amount physics and hull cast can disagree +#endif + + +inline bool IsMoveBlocked( AIMoveResult_t moveResult ) +{ + return (moveResult < AIMR_OK ); +} + +//------------------------------------- + +enum StepGroundTest_t +{ + STEP_DONT_CHECK_GROUND = 0, + STEP_ON_VALID_GROUND, + STEP_ON_INVALID_GROUND, +}; + + +//------------------------------------- + +struct AIMoveTrace_t +{ + AIMoveTrace_t() + { + memset( this, 0, sizeof(*this) ); + } + + AIMoveResult_t fStatus; // See AIMoveResult_t + Vector vEndPosition; // The last point that could be moved to + Vector vHitNormal; // The normal of a hit, if any. vec3_origin if none. Can be none even if "hit" + CBaseEntity* pObstruction; // The obstruction I bumped into (if any) + float flTotalDist; + float flDistObstructed; // FIXME: This is a strange number. In the case + // of calling MoveLimit with navtype NAV_GROUND, + // it represents a 2D distance to the obstruction. + // In the case of other navtypes, it represents a + // 3D distance to the obstruction + Vector vJumpVelocity; // FIXME: Remove this; it's bogus + // It's only returned by JumpMoveLimit + // which seems to be a bogus concept to begin with + float flStepUpDistance; +}; + +inline bool IsMoveBlocked( const AIMoveTrace_t &moveTrace ) +{ + return (moveTrace.fStatus < AIMR_OK ); +} + + +// Categorizes the blocker and sets the appropriate bits +AIMoveResult_t AIComputeBlockerMoveResult( CBaseEntity *pBlocker ); + + +//------------------------------------- +// Purpose: Specifies an immediate, localized, straight line movement goal +//------------------------------------- + +enum AILocalMoveGoalFlags_t +{ + AILMG_NONE, + AILMG_TARGET_IS_GOAL = 0x01, + AILMG_CONSUME_INTERVAL = 0x02, + AILMG_TARGET_IS_TRANSITION = 0x04, + AILMG_NO_STEER = 0x08, + AILMG_NO_AVOIDANCE_PATHS = 0x10, +}; + +struct AILocalMoveGoal_t +{ + AILocalMoveGoal_t() + { + memset( this, 0, sizeof(*this) ); + } + + // Object of the goal + Vector target; + + // The actual move. Note these need not always agree with "target" + Vector dir; + Vector facing; + float speed; + + // The distance maximum distance intended to travel in path length + float maxDist; + + // The distance expected to move this think + float curExpectedDist; + + Navigation_t navType; + CBaseEntity * pMoveTarget; + + unsigned flags; + + // The path from which this goal was derived + CAI_Path * pPath; + + // The result if a forward probing trace has been done + bool bHasTraced; + AIMoveTrace_t directTrace; + AIMoveTrace_t thinkTrace; + +#ifdef DEBUG + int solveCookie; +#endif +}; + +//------------------------------------- + +enum AIMotorMoveResult_t +{ + AIM_FAILED, + AIM_SUCCESS, + + // Partial successes + AIM_PARTIAL_HIT_NPC, + AIM_PARTIAL_HIT_WORLD, + AIM_PARTIAL_HIT_TARGET, + + AIM_NUM_RESULTS +}; + +//----------------------------------------------------------------------------- +// Purpose: The set of callbacks used by lower-level movement classes to +// notify and receive guidance from higher level-classes +//----------------------------------------------------------------------------- + +abstract_class IAI_MovementSink +{ +public: + //--------------------------------- + // + // Queries + // + virtual float CalcYawSpeed( void ) = 0; + + //--------------------------------- + // + // Local navigation notifications, each allows services provider to overridde default result + // + virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ) = 0; + + virtual bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ) = 0; + + virtual bool OnFailedSteer( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ) = 0; + + virtual bool OnFailedLocalNavigation( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ) = 0; + + virtual bool OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ) = 0; + + + virtual bool OnMoveBlocked( AIMoveResult_t *pResult ) = 0; + + //--------------------------------- + // + // Motor notifications, each allows services provider to overridde default result + // + virtual bool OnMoveStalled( const AILocalMoveGoal_t &move ) = 0; + virtual bool OnMoveExecuteFailed( const AILocalMoveGoal_t &move, + const AIMoveTrace_t &trace, + AIMotorMoveResult_t fMotorResult, + AIMoveResult_t *pResult ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Default implementations of IAI_MovementSink +//----------------------------------------------------------------------------- + +class CAI_DefMovementSink : public IAI_MovementSink +{ +public: + //--------------------------------- + // + // Queries + // + virtual float CalcYawSpeed( void ) { return -1.0; } + + + //--------------------------------- + // + // Local navigation notifications, each allows services provider to overridde default result + // + virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) { return false; } + virtual bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) { return false; } + virtual bool OnFailedSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) { return false; } + virtual bool OnFailedLocalNavigation( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) { return false; } + virtual bool OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) { return false; } + virtual bool OnMoveBlocked( AIMoveResult_t *pResult ) { return false; } + + //--------------------------------- + // + // Motor notifications, each allows services provider to overridde default result + // + virtual bool OnMoveStalled( const AILocalMoveGoal_t &move ) { return false; } + virtual bool OnMoveExecuteFailed( const AILocalMoveGoal_t &move, const AIMoveTrace_t &trace, AIMotorMoveResult_t fMotorResult, AIMoveResult_t *pResult ) { return false; } + +}; + +//------------------------------------- + +class CAI_ProxyMovementSink : public CAI_DefMovementSink +{ +public: + CAI_ProxyMovementSink() + : m_pProxied( NULL ) + { + } + + //--------------------------------- + + void Init( IAI_MovementSink *pMovementServices ) { m_pProxied = pMovementServices; } + + //--------------------------------- + // + // Queries + // + virtual float CalcYawSpeed( void ); + + //--------------------------------- + // + // Local navigation notifications, each allows services provider to overridde default result + // + virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + + virtual bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + virtual bool OnFailedSteer( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + virtual bool OnFailedLocalNavigation( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + virtual bool OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, + float distClear, + AIMoveResult_t *pResult ); + virtual bool OnMoveBlocked( AIMoveResult_t *pResult ); + + //--------------------------------- + // + // Motor notifications, each allows services provider to overridde default result + // + virtual bool OnMoveStalled( const AILocalMoveGoal_t &move ); + virtual bool OnMoveExecuteFailed( const AILocalMoveGoal_t &move, const AIMoveTrace_t &trace, AIMotorMoveResult_t fMotorResult, AIMoveResult_t *pResult ); + + IAI_MovementSink *m_pProxied; +}; + +// ---------------------------------------------------------------------------- + +inline float CAI_ProxyMovementSink::CalcYawSpeed( void ) +{ + float result; + if ( m_pProxied && ( result = m_pProxied->CalcYawSpeed() ) != -1.0 ) + return result; + return CAI_DefMovementSink::CalcYawSpeed(); +} + +inline bool CAI_ProxyMovementSink::OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnCalcBaseMove( pMoveGoal, distClear, pResult ) ) + return true; + return CAI_DefMovementSink::OnCalcBaseMove( pMoveGoal, distClear, pResult ); +} + +inline bool CAI_ProxyMovementSink::OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnObstructionPreSteer( pMoveGoal, distClear, pResult ) ) + return true; + return CAI_DefMovementSink::OnObstructionPreSteer( pMoveGoal, distClear, pResult ); +} + +inline bool CAI_ProxyMovementSink::OnFailedSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnFailedSteer( pMoveGoal, distClear, pResult ) ) + return true; + return CAI_DefMovementSink::OnFailedSteer( pMoveGoal, distClear, pResult ); +} + +inline bool CAI_ProxyMovementSink::OnFailedLocalNavigation( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnFailedLocalNavigation( pMoveGoal, distClear, pResult ) ) + return true; + return CAI_DefMovementSink::OnFailedLocalNavigation( pMoveGoal, distClear, pResult ); +} + +inline bool CAI_ProxyMovementSink::OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnInsufficientStopDist( pMoveGoal, distClear, pResult ) ) + return true; + return CAI_DefMovementSink::OnInsufficientStopDist( pMoveGoal, distClear, pResult ); +} + +inline bool CAI_ProxyMovementSink::OnMoveStalled( const AILocalMoveGoal_t &move ) +{ + if ( m_pProxied && m_pProxied->OnMoveStalled( move ) ) + return true; + return CAI_DefMovementSink::OnMoveStalled( move ); +} + +inline bool CAI_ProxyMovementSink::OnMoveExecuteFailed( const AILocalMoveGoal_t &move, const AIMoveTrace_t &trace, AIMotorMoveResult_t fMotorResult, AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnMoveExecuteFailed( move, trace, fMotorResult, pResult ) ) + return true; + return CAI_DefMovementSink::OnMoveExecuteFailed( move, trace, fMotorResult, pResult ); +} + +inline bool CAI_ProxyMovementSink::OnMoveBlocked( AIMoveResult_t *pResult ) +{ + if ( m_pProxied && m_pProxied->OnMoveBlocked( pResult ) ) + return true; + return CAI_DefMovementSink::OnMoveBlocked( pResult ); +} + +//============================================================================= + +#endif // AI_MOVETYPES_H diff --git a/game/server/ai_namespaces.h b/game/server/ai_namespaces.h new file mode 100644 index 0000000..8ea9053 --- /dev/null +++ b/game/server/ai_namespaces.h @@ -0,0 +1,287 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NAMESPACES_H +#define AI_NAMESPACES_H + +class CStringRegistry; + +#if defined( _WIN32 ) +#pragma once +#endif + +#define MAX_STRING_INDEX 9999 +const int GLOBAL_IDS_BASE = 1000000000; // decimal for debugging readability + +//----------------------------------------------------------------------------- + +inline bool AI_IdIsGlobal( int id ) { return ( id >= GLOBAL_IDS_BASE || id == -1 ); } +inline bool AI_IdIsLocal( int id ) { return ( id < GLOBAL_IDS_BASE || id == -1 ); } +inline int AI_RemapToGlobal( int id ) { return ( id != -1 ) ? id + GLOBAL_IDS_BASE : -1; } +inline int AI_RemapFromGlobal( int id ) { return ( id != -1 ) ? id - GLOBAL_IDS_BASE : -1; } + +inline int AI_MakeGlobal( int id ) { return AI_IdIsLocal( id ) ? AI_RemapToGlobal( id ) : id; } + +//----------------------------------------------------------------------------- +// CAI_GlobalNamespace +// +// Purpose: Symbol table for all symbols across a given namespace, a +// bi-directional mapping of "text" to global ID +// + +class CAI_GlobalNamespace +{ +public: + CAI_GlobalNamespace(); + ~CAI_GlobalNamespace(); + + void Clear(); + + void AddSymbol( const char *pszSymbol, int symbolID ); + int NextGlobalBase() const; + + const char *IdToSymbol( int symbolID ) const; + int SymbolToId( const char *pszSymbol ) const; + +private: + CStringRegistry * m_pSymbols; + int m_NextGlobalBase; +}; + +//----------------------------------------------------------------------------- +// CAI_LocalIdSpace +// +// Purpose: Maps per class IDs to global IDs, so that various classes can use +// the same integer in local space to represent different globally +// unique integers. Used for schedules, tasks, conditions and squads +// + +class CAI_LocalIdSpace +{ +public: + CAI_LocalIdSpace( bool fIsRoot = false ); + + bool Init( CAI_GlobalNamespace *pGlobalNamespace, CAI_LocalIdSpace *pParentIDSpace = NULL ); + bool IsGlobalBaseSet() const { return ( m_globalBase != -1 ); } + + bool AddSymbol( const char *pszSymbol, int localId, const char *pszDebugSymbolType = "", const char *pszDebugOwner = "" ); + + int GlobalToLocal( int globalID ) const; + int LocalToGlobal( int localID ) const; + + CAI_GlobalNamespace *GetGlobalNamespace() { return m_pGlobalNamespace; } + const CAI_GlobalNamespace *GetGlobalNamespace() const { return m_pGlobalNamespace; } + +private: + bool IsLocalBaseSet() const { return ( m_localBase != MAX_STRING_INDEX ); } + int GetLocalBase() const { return m_localBase; } + int GetGlobalBase() const { return m_globalBase; } + int GetLocalTop() const { return m_localTop; } + int GetGlobalTop() const { return m_globalTop; } + + bool SetLocalBase( int newBase ); + + // -------------------------------- + + int m_globalBase; + int m_localBase; + int m_localTop; + int m_globalTop; + + CAI_LocalIdSpace * m_pParentIDSpace; + CAI_GlobalNamespace * m_pGlobalNamespace; +}; + +//----------------------------------------------------------------------------- +// +// Namespaces used by CAI_BaseNPC +// +//----------------------------------------------------------------------------- + +class CAI_GlobalScheduleNamespace +{ +public: + void Clear() + { + m_ScheduleNamespace.Clear(); + m_TaskNamespace.Clear(); + m_ConditionNamespace.Clear(); + } + + void AddSchedule( const char *pszSchedule, int scheduleID ); + const char *ScheduleIdToSymbol( int scheduleID ) const; + int ScheduleSymbolToId( const char *pszSchedule ) const; + + void AddTask( const char *pszTask, int taskID ); + const char *TaskIdToSymbol( int taskID ) const; + int TaskSymbolToId( const char *pszTask ) const; + + void AddCondition( const char *pszCondition, int conditionID ); + const char *ConditionIdToSymbol( int conditionID ) const; + int ConditionSymbolToId( const char *pszCondition ) const; + int NumConditions() const; + +private: + friend class CAI_ClassScheduleIdSpace; + + CAI_GlobalNamespace m_ScheduleNamespace; + CAI_GlobalNamespace m_TaskNamespace; + CAI_GlobalNamespace m_ConditionNamespace; +}; + +//------------------------------------- + +class CAI_ClassScheduleIdSpace +{ +public: + CAI_ClassScheduleIdSpace( bool fIsRoot = false ) + : m_ScheduleIds( fIsRoot ), + m_TaskIds( fIsRoot ), + m_ConditionIds( fIsRoot ) + { + } + + bool Init( const char *pszClassName, CAI_GlobalScheduleNamespace *pGlobalNamespace, CAI_ClassScheduleIdSpace *pParentIDSpace = NULL ); + + const char *GetClassName() const { return m_pszClassName; } + + bool IsGlobalBaseSet() const; + + bool AddSchedule( const char *pszSymbol, int localId, const char *pszDebugOwner = "" ); + int ScheduleGlobalToLocal( int globalID ) const; + int ScheduleLocalToGlobal( int localID ) const; + + bool AddTask( const char *pszSymbol, int localId, const char *pszDebugOwner = "" ); + int TaskGlobalToLocal( int globalID ) const; + int TaskLocalToGlobal( int localID ) const; + + bool AddCondition( const char *pszSymbol, int localId, const char *pszDebugOwner = "" ); + int ConditionGlobalToLocal( int globalID ) const; + int ConditionLocalToGlobal( int localID ) const; + +private: + const char * m_pszClassName; + CAI_LocalIdSpace m_ScheduleIds; + CAI_LocalIdSpace m_TaskIds; + CAI_LocalIdSpace m_ConditionIds; +}; + +//----------------------------------------------------------------------------- + +inline void CAI_GlobalScheduleNamespace::AddSchedule( const char *pszSchedule, int scheduleID ) +{ + m_ScheduleNamespace.AddSymbol( pszSchedule, scheduleID); +} + +inline const char *CAI_GlobalScheduleNamespace::ScheduleIdToSymbol( int scheduleID ) const +{ + return m_ScheduleNamespace.IdToSymbol( scheduleID ); +} + +inline int CAI_GlobalScheduleNamespace::ScheduleSymbolToId( const char *pszSchedule ) const +{ + return m_ScheduleNamespace.SymbolToId( pszSchedule ); +} + +inline void CAI_GlobalScheduleNamespace::AddTask( const char *pszTask, int taskID ) +{ + m_TaskNamespace.AddSymbol( pszTask, taskID); +} + +inline const char *CAI_GlobalScheduleNamespace::TaskIdToSymbol( int taskID ) const +{ + return m_TaskNamespace.IdToSymbol( taskID ); +} + +inline int CAI_GlobalScheduleNamespace::TaskSymbolToId( const char *pszTask ) const +{ + return m_TaskNamespace.SymbolToId( pszTask ); +} + +inline void CAI_GlobalScheduleNamespace::AddCondition( const char *pszCondition, int conditionID ) +{ + m_ConditionNamespace.AddSymbol( pszCondition, conditionID); +} + +inline const char *CAI_GlobalScheduleNamespace::ConditionIdToSymbol( int conditionID ) const +{ + return m_ConditionNamespace.IdToSymbol( conditionID ); +} + +inline int CAI_GlobalScheduleNamespace::ConditionSymbolToId( const char *pszCondition ) const +{ + return m_ConditionNamespace.SymbolToId( pszCondition ); +} + +inline int CAI_GlobalScheduleNamespace::NumConditions() const +{ + return m_ConditionNamespace.NextGlobalBase() - GLOBAL_IDS_BASE; +} + +inline bool CAI_ClassScheduleIdSpace::Init( const char *pszClassName, CAI_GlobalScheduleNamespace *pGlobalNamespace, CAI_ClassScheduleIdSpace *pParentIDSpace ) +{ + m_pszClassName = pszClassName; + return ( m_ScheduleIds.Init( &pGlobalNamespace->m_ScheduleNamespace, ( pParentIDSpace ) ? &pParentIDSpace->m_ScheduleIds : NULL ) && + m_TaskIds.Init( &pGlobalNamespace->m_TaskNamespace, ( pParentIDSpace ) ? &pParentIDSpace->m_TaskIds : NULL ) && + m_ConditionIds.Init( &pGlobalNamespace->m_ConditionNamespace, ( pParentIDSpace ) ? &pParentIDSpace->m_ConditionIds : NULL ) ); +} + +//----------------------------------------------------------------------------- + +inline bool CAI_ClassScheduleIdSpace::IsGlobalBaseSet() const +{ + return m_ScheduleIds.IsGlobalBaseSet(); +} + +inline bool CAI_ClassScheduleIdSpace::AddSchedule( const char *pszSymbol, int localId, const char *pszDebugOwner ) +{ + return m_ScheduleIds.AddSymbol( pszSymbol, localId, "schedule", pszDebugOwner ); +} + +inline int CAI_ClassScheduleIdSpace::ScheduleGlobalToLocal( int globalID ) const +{ + return m_ScheduleIds.GlobalToLocal( globalID ); +} + +inline int CAI_ClassScheduleIdSpace::ScheduleLocalToGlobal( int localID ) const +{ + return m_ScheduleIds.LocalToGlobal( localID ); +} + +inline bool CAI_ClassScheduleIdSpace::AddTask( const char *pszSymbol, int localId, const char *pszDebugOwner ) +{ + return m_TaskIds.AddSymbol( pszSymbol, localId, "task", pszDebugOwner ); +} + +inline int CAI_ClassScheduleIdSpace::TaskGlobalToLocal( int globalID ) const +{ + return m_TaskIds.GlobalToLocal( globalID ); +} + +inline int CAI_ClassScheduleIdSpace::TaskLocalToGlobal( int localID ) const +{ + return m_TaskIds.LocalToGlobal( localID ); +} + +inline bool CAI_ClassScheduleIdSpace::AddCondition( const char *pszSymbol, int localId, const char *pszDebugOwner ) +{ + return m_ConditionIds.AddSymbol( pszSymbol, localId, "condition", pszDebugOwner ); +} + +inline int CAI_ClassScheduleIdSpace::ConditionGlobalToLocal( int globalID ) const +{ + return m_ConditionIds.GlobalToLocal( globalID ); +} + +inline int CAI_ClassScheduleIdSpace::ConditionLocalToGlobal( int localID ) const +{ + return m_ConditionIds.LocalToGlobal( localID ); +} + +//============================================================================= + +#endif // AI_NAMESPACES_H diff --git a/game/server/ai_navgoaltype.h b/game/server/ai_navgoaltype.h new file mode 100644 index 0000000..cd9ef1f --- /dev/null +++ b/game/server/ai_navgoaltype.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NAVGOALTYPE_H +#define AI_NAVGOALTYPE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +// ======================================= +// Movement goals +// Used both to store the current +// movment goal in m_routeGoalType +// and to or/and with route +// ======================================= +enum GoalType_t +{ + GOALTYPE_NONE, + GOALTYPE_TARGETENT, + GOALTYPE_ENEMY, + GOALTYPE_PATHCORNER, + GOALTYPE_LOCATION, + GOALTYPE_LOCATION_NEAREST_NODE, + GOALTYPE_FLANK, + GOALTYPE_COVER, + + GOALTYPE_INVALID +}; + +#endif // AI_NAVGOALTYPE_H diff --git a/game/server/ai_navigator.h b/game/server/ai_navigator.h new file mode 100644 index 0000000..c84932b --- /dev/null +++ b/game/server/ai_navigator.h @@ -0,0 +1,751 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NAVIGATOR_H +#define AI_NAVIGATOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "simtimer.h" +#include "ai_component.h" +#include "ai_navgoaltype.h" +#include "ai_navtype.h" +#include "ai_motor.h" + +class CAI_BaseNPC; +class CAI_Motor; +class CAI_Route; +class CAI_Path; +class CAI_Pathfinder; +class CAI_LocalNavigator; +struct AI_Waypoint_t; +class CAI_WaypointList; +class CAI_Network; +struct AIMoveTrace_t; +struct AILocalMoveGoal_t; +typedef int AI_TaskFailureCode_t; + +//----------------------------------------------------------------------------- +// Debugging tools +//----------------------------------------------------------------------------- + +#define DEBUG_AI_NAVIGATION 1 +#ifdef DEBUG_AI_NAVIGATION +extern ConVar ai_debug_nav; +#define DbgNav() ai_debug_nav.GetBool() +#define DbgNavMsg( pAI, pszMsg ) \ + do \ + { \ + if (DbgNav()) \ + DevMsg( pAI, "[Nav] %s", static_cast(pszMsg) ); \ + } while (0) +#define DbgNavMsg1( pAI, pszMsg, a ) DbgNavMsg( pAI, CFmtStr(static_cast(pszMsg), (a) ) ) +#define DbgNavMsg2( pAI, pszMsg, a, b ) DbgNavMsg( pAI, CFmtStr(static_cast(pszMsg), (a), (b) ) ) +#else +#define DbgNav() false +#define DbgNavMsg( pAI, pszMsg ) ((void)0) +#define DbgNavMsg1( pAI, pszMsg, a ) ((void)0) +#define DbgNavMsg2( pAI, pszMsg, a, b ) ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// STRUCTURES & ENUMERATIONS +//----------------------------------------------------------------------------- + +DECLARE_POINTER_HANDLE( AI_PathNode_t ); + +//------------------------------------- +// Purpose: Constants used to specify the properties of a requested navigation +// goal. +//------------------------------------- + +// Navigator should use the default or previously set tolerance +const float AIN_DEF_TOLERANCE = -1.0; + +// Navigator should use the hull size as the tolerance +const float AIN_HULL_TOLERANCE = -2.0; + +// Goal does not specify a new activity +const Activity AIN_DEF_ACTIVITY = ACT_INVALID; + +// Goal has no target +CBaseEntity * const AIN_NO_TARGET = NULL; + +// Goal does not specify a new target, use the existing one, if any +CBaseEntity * const AIN_DEF_TARGET = (AIN_NO_TARGET + 1); + +// Goal does not specify a vector location +extern const Vector AIN_NO_DEST; + +// Goal does not specify a node location +#define AIN_NO_NODE ((AI_PathNode_t)-1) + + +//------------------------------------- + +enum AI_NavGoalFlags_t +{ + // While navigating, try to face the destination point + AIN_YAW_TO_DEST = 0x01, + + // If I'm a goal of type GOALTYPE_TARGETENT, update my goal position every time I think + AIN_UPDATE_TARGET_POS = 0x02, + + // If navigating on a designer placed path, don't use pathfinder between waypoints, just do it + AIN_NO_PATHCORNER_PATHFINDING = 0x04, + + AIN_DEF_FLAGS = 0, +}; + +//------------------------------------- + +enum AI_NavSetGoalFlags_t +{ + // Reset the navigator's navigation to the default state + AIN_CLEAR_PREVIOUS_STATE = 0x01, + + // Clear out the target entity, while retaining other settings + AIN_CLEAR_TARGET = 0x02, + + // If the navigate fails, return navigation to the default state + AIN_DISCARD_IF_FAIL = 0x04, + + // Don't signal TaskFail() if the pathfind fails, just return the result + AIN_NO_PATH_TASK_FAIL = 0x08, +}; + +//------------------------------------- + +enum AI_NpcBlockHandling_t +{ + AISF_BLOCK, + AISF_AVOID, + AISF_IGNORE, +}; + +//------------------------------------- + +enum AI_NavPathProgress_t +{ + AINPP_NO_CHANGE, + AINPP_ADVANCED, + AINPP_COMPLETE, + AINPP_BLOCKED, +}; + +//------------------------------------- +// Purpose: Describes a navigation request. The various constructors simply +// allow ease of use in the common cases. +//------------------------------------- + +struct AI_NavGoal_t +{ + // Goal is unspecifed, or not a specific location + AI_NavGoal_t( GoalType_t type = GOALTYPE_INVALID, + Activity activity = AIN_DEF_ACTIVITY, + float tolerance = AIN_DEF_TOLERANCE, + unsigned flags = AIN_DEF_FLAGS, + CBaseEntity * pTarget = AIN_DEF_TARGET); + + // Goal is a specific location, and GOALTYPE_LOCATION + AI_NavGoal_t( const Vector &dest, + Activity activity = AIN_DEF_ACTIVITY, + float tolerance = AIN_DEF_TOLERANCE, + unsigned flags = AIN_DEF_FLAGS, + CBaseEntity * pTarget = AIN_DEF_TARGET); + + // Goal is a specific location and goal type + AI_NavGoal_t( GoalType_t type, + const Vector &dest, + Activity activity = AIN_DEF_ACTIVITY, + float tolerance = AIN_DEF_TOLERANCE, + unsigned flags = AIN_DEF_FLAGS, + CBaseEntity * pTarget = AIN_DEF_TARGET); + + // Goal is a specific node, and GOALTYPE_LOCATION + AI_NavGoal_t( AI_PathNode_t destNode, + Activity activity = AIN_DEF_ACTIVITY, + float tolerance = AIN_DEF_TOLERANCE, + unsigned flags = AIN_DEF_FLAGS, + CBaseEntity * pTarget = AIN_DEF_TARGET); + + // Goal is a specific location and goal type + AI_NavGoal_t( GoalType_t type, + AI_PathNode_t destNode, + Activity activity = AIN_DEF_ACTIVITY, + float tolerance = AIN_DEF_TOLERANCE, + unsigned flags = AIN_DEF_FLAGS, + CBaseEntity * pTarget = AIN_DEF_TARGET); + + //---------------------------------- + + // What type of goal is this + GoalType_t type; + + // The destination, either as a vector, or as a path node + Vector dest; + AI_PathNode_t destNode; + + // The activity to use, or none if a previosly set activity should be used + Activity activity; + + // The predicted activity used after arrival + Activity arrivalActivity; + int arrivalSequence; + + // The tolerance of success, or none if a previosly set tolerance should be used + float tolerance; + + // How far to permit an initial simplification of path + // (will use default if this value is less than the default) + float maxInitialSimplificationDist; + + // Optional flags specifying + unsigned flags; + + // The target of the navigation, primarily used to ignore the entity in hull and line traces + CBaseEntity * pTarget; +}; + +//------------------------------------- +// Purpose: Used to describe rules for advance on a (fly) path. There's nothing +// specifically "flying" about it, other than it came from an attempte +// to consolodate duplicated code in the various fliers. It may serve +// a more general purpose in the future. The constructor takes those +// arguments that can usually be specified just once (as in a +// local static constructor) +//------------------------------------- + +struct AI_ProgressFlyPathParams_t +{ + AI_ProgressFlyPathParams_t( unsigned _collisionMask, + float _strictPointTolerance = 32.0, float _blockTolerance = 0.0, + float _waypointTolerance = 100, float _goalTolerance = 12, + AI_NpcBlockHandling_t _blockHandling = AISF_BLOCK ) + : collisionMask( _collisionMask ), + strictPointTolerance( _strictPointTolerance ), + blockTolerance( _blockTolerance ), + waypointTolerance( _waypointTolerance ), + goalTolerance( _goalTolerance ), + blockHandling( _blockHandling ), + pTarget( NULL ), + bTrySimplify( true ) + { + } + + void SetCurrent( const CBaseEntity *pNewTarget, bool bNewTrySimplify = true ) + { + pTarget = pNewTarget; + bTrySimplify = bNewTrySimplify; + } + + //---------------------------------- + + // Fields that tend to stay constant + unsigned collisionMask; + float strictPointTolerance; + float blockTolerance; // @TODO (toml 07-03-02): rename "blockTolerance". This is specifically the "simplify" block tolerance. See SimplifyFlyPath() + float waypointTolerance; + float goalTolerance; // @TODO (toml 07-03-02): goalTolerance appears to have come into existence because + // noone had set a good tolerance in the path itself. It is therefore redundant, + // and more than likely should be excised + AI_NpcBlockHandling_t blockHandling; // @TODO (toml 07-03-02): rename "blockHandling". This is specifically the "simplify" block handling. See SimplifyFlyPath() + + // Fields that tend to change + const CBaseEntity * pTarget; + bool bTrySimplify; +}; + +//----------------------------------------------------------------------------- +// CAI_Navigator +// +// Purpose: Implements pathing and path navigaton logic +//----------------------------------------------------------------------------- + +class CAI_Navigator : public CAI_Component, + public CAI_DefMovementSink +{ + typedef CAI_Component BaseClass; +public: + // -------------------------------- + + CAI_Navigator(CAI_BaseNPC *pOuter); + virtual ~CAI_Navigator(); + + virtual void Init( CAI_Network *pNetwork ); + + // -------------------------------- + + void SetPathcornerPathfinding( bool fNewVal) { m_bNoPathcornerPathfinds = !fNewVal; } + void SetRememberStaleNodes( bool fNewVal) { m_fRememberStaleNodes = fNewVal; } + void SetValidateActivitySpeed( bool bValidateActivitySpeed ) { m_bValidateActivitySpeed = bValidateActivitySpeed; } + void SetLocalSucceedOnWithinTolerance( bool fNewVal ) { m_bLocalSucceedOnWithinTolerance = fNewVal; } + + // -------------------------------- + + void Save( ISave &save ); + void Restore( IRestore &restore ); + + // -------------------------------- + // Methods to issue movement directives + // -------------------------------- + + // Simple pathfind + virtual bool SetGoal( const AI_NavGoal_t &goal, unsigned flags = 0 ); + + // Change the target of the path + virtual bool SetGoalTarget( CBaseEntity *pEntity, const Vector &offset ); + + // Fancy pathing + bool SetRadialGoal( const Vector &destination, const Vector ¢er, float radius, float arc, float stepDist, bool bClockwise, bool bAirRoute = false ); + bool SetRandomGoal( float minPathLength, const Vector &dir = vec3_origin ); + bool SetRandomGoal( const Vector &from, float minPathLength, const Vector &dir = vec3_origin ); + bool SetDirectGoal( const Vector &goalPos, Navigation_t navType = NAV_GROUND ); + + bool SetWanderGoal( float minRadius, float maxRadius ); + bool SetVectorGoal( const Vector &dir, float targetDist, float minDist = 0, bool fShouldDeflect = false ); + bool SetVectorGoalFromTarget( const Vector &goalPos, float minDist = 0, bool fShouldDeflect = false ); + + bool FindVectorGoal( Vector *pResult, const Vector &dir, float targetDist, float minDist = 0, bool fShouldDeflect = false ); + + // Path manipulation + bool PrependLocalAvoidance( float distObstacle, const AIMoveTrace_t &directTrace ); + void PrependWaypoint( const Vector &newPoint, Navigation_t navType, unsigned waypointFlags = 0 ); + + // Query or change the movement activity + Activity GetMovementActivity() const; + Activity SetMovementActivity(Activity activity); + int GetMovementSequence(); + void SetMovementSequence( int sequence ); + + // Query or change the Arrival activity + Activity GetArrivalActivity() const; + void SetArrivalActivity( Activity activity ); + int GetArrivalSequence( int curSequence ); + void SetArrivalSequence( int sequence ); + + // Set the facing direction at arrival + void SetArrivalDirection( const Vector &goalDirection ); + void SetArrivalDirection( const QAngle &goalAngle ); + void SetArrivalDirection( CBaseEntity *pTarget ); + Vector GetArrivalDirection( ); + + // Set the speed to reach at arrival ( + void SetArrivalSpeed( float flSpeed ); + float GetArrivalSpeed(); + + // Set the estimated distance to stop before the actual goal + void SetArrivalDistance( float flDistance ); + float GetArrivalDistance( ) const; + + // Query or change the goal tolerance + float GetGoalTolerance() const; + void SetGoalTolerance(float tolerance); + + GoalType_t GetGoalType() const; + const Vector & GetGoalPos() const; + CBaseEntity * GetGoalTarget(); + int GetGoalFlags() const; + + const Vector & GetCurWaypointPos() const; + int GetCurWaypointFlags() const; + + bool CurWaypointIsGoal() const; + + bool GetPointAlongPath( Vector *pResult, float distance, bool fReducibleOnly = false ); + + float GetPathDistanceToGoal(); + float GetPathTimeToGoal(); + + // Query if there is a current goal + bool IsGoalSet() const; + + // Query if the current goal is active, meaning the navigator has a path in can progress on + bool IsGoalActive() const; + + // Update the goal position to reflect current conditions + bool RefindPathToGoal( bool fSignalTaskStatus = true, bool bDontIgnoreBadLinks = false ); + bool UpdateGoalPos( const Vector & ); + + // Wrap up current locomotion + void StopMoving( bool bImmediate = true ); + + // Discard the current goal, use StopMoving() if just executing a normal stop + bool ClearGoal(); + + // -------------------------------- + + void SetAllowBigStep( CBaseEntity *pEntToStepOff ) { if ( !pEntToStepOff || !pEntToStepOff->IsWorld() ) m_hBigStepGroundEnt = pEntToStepOff; } + + // -------------------------------- + bool SetGoalFromStoppingPath(); + void IgnoreStoppingPath(); + + // -------------------------------- + // Navigation mode + // -------------------------------- + Navigation_t GetNavType() const { return m_navType; } + void SetNavType( Navigation_t navType ); + + bool IsInterruptable() const { return ( m_navType != NAV_CLIMB && m_navType != NAV_JUMP ); } + + // -------------------------------- + // Pathing + // -------------------------------- + + AI_NavPathProgress_t ProgressFlyPath( const AI_ProgressFlyPathParams_t ¶ms); // note: will not return "blocked" + + AI_PathNode_t GetNearestNode(); + Vector GetNodePos( AI_PathNode_t ); + + CAI_Network * GetNetwork() { return m_pAINetwork; } + const CAI_Network * GetNetwork() const { return m_pAINetwork; } + void SetNetwork( CAI_Network *pNetwork ) { m_pAINetwork = pNetwork; } + + CAI_Path * GetPath() { return m_pPath; } + const CAI_Path * GetPath() const { return m_pPath; } + + void AdvancePath(); + + virtual bool SimplifyPath( bool bFirstForPath = false, float maxDist = -1 ); + void SimplifyFlyPath( unsigned collisionMask, const CBaseEntity *pTarget, + float strictPointTolerance = 32.0, float blockTolerance = 0.0, + AI_NpcBlockHandling_t blockHandling = AISF_BLOCK); + bool SimplifyFlyPath( const AI_ProgressFlyPathParams_t ¶ms ); + + bool CanFitAtNode(int nodeNum, unsigned int collisionMask = MASK_NPCSOLID_BRUSHONLY); + float MovementCost( int moveType, Vector &vecStart, Vector &vecEnd ); + + bool CanFitAtPosition( const Vector &vStartPos, unsigned int collisionMask, bool bIgnoreTransients = false, bool bAllowPlayerAvoid = true ); + bool IsOnNetwork() const { return !m_bNotOnNetwork; } + + void SetMaxRouteRebuildTime(float time) { m_timePathRebuildMax = time; } + + // -------------------------------- + void DrawDebugRouteOverlay( void ); + + // -------------------------------- + // Miscellany + // -------------------------------- + + float CalcYawSpeed(); + float GetStepDownMultiplier(); + CBaseEntity * GetNextPathcorner( CBaseEntity *pPathCorner ); + virtual void OnScheduleChange(); + + // -------------------------------- + + // See comments at CAI_BaseNPC::Move() + virtual bool Move( float flInterval = 0.1 ); + + // -------------------------------- + + CBaseEntity * GetBlockingEntity() { return m_hLastBlockingEnt; } + +protected: + // -------------------------------- + // + // Common services provided by CAI_BaseNPC + // + CBaseEntity * GetNavTargetEntity(); + void TaskMovementComplete(); + float MaxYawSpeed(); + void SetSpeed( float ); + + // -------------------------------- + + CAI_Motor * GetMotor() { return m_pMotor; } + const CAI_Motor * GetMotor() const { return m_pMotor; } + + CAI_MoveProbe * GetMoveProbe() { return m_pMoveProbe; } + const CAI_MoveProbe *GetMoveProbe() const { return m_pMoveProbe; } + + CAI_LocalNavigator *GetLocalNavigator() { return m_pLocalNavigator; } + const CAI_LocalNavigator *GetLocalNavigator() const { return m_pLocalNavigator; } + + CAI_Pathfinder * GetPathfinder(); + const CAI_Pathfinder *GetPathfinder() const; + + virtual void OnClearPath(void); + + // -------------------------------- + + virtual void OnNewGoal(); + virtual void OnNavComplete(); + void OnNavFailed( bool bMovement = false ); + void OnNavFailed( AI_TaskFailureCode_t code, bool bMovement = false ); + void OnNavFailed( const char *pszGeneralFailText, bool bMovement = false ); + + // -------------------------------- + + virtual AIMoveResult_t MoveNormal(); + + // Navigation execution + virtual AIMoveResult_t MoveClimb(); + virtual AIMoveResult_t MoveJump(); + + // -------------------------------- + + virtual AIMoveResult_t MoveEnact( const AILocalMoveGoal_t &baseMove ); + +protected: + // made this virtual so strider can implement hover behavior with a navigator + virtual void MoveCalcBaseGoal( AILocalMoveGoal_t *pMoveGoal); + +private: + virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + virtual bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + virtual bool OnFailedSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + virtual bool OnFailedLocalNavigation( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + virtual bool OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + virtual bool OnMoveStalled( const AILocalMoveGoal_t &move ); + virtual bool OnMoveExecuteFailed( const AILocalMoveGoal_t &move, const AIMoveTrace_t &trace, AIMotorMoveResult_t fMotorResult, AIMoveResult_t *pResult ); + virtual bool OnMoveBlocked( AIMoveResult_t *pResult ); + + void ResetCalculations(); + + // Methods shared between ground and fly movement + bool PreMove(); + virtual bool MoveUpdateWaypoint( AIMoveResult_t *pResult ); + bool IsMovingOutOfWay( const AILocalMoveGoal_t &moveGoal, float distClear ); + bool DelayNavigationFailure( const AIMoveTrace_t &trace ); + + static void CalculateDeflection( const Vector &start, const Vector &dir, const Vector &normal, Vector *pResult ); + + // -------------------------------- + // Pathfinding + // -------------------------------- + +public: + float GetPathDistToCurWaypoint() const; + float GetPathDistToGoal() const; + float BuildAndGetPathDistToGoal(); + + // -------------------------------- + + int GetNavFailCounter() const; + void ClearNavFailCounter(); + float GetLastNavFailTime() const; + bool TeleportAlongPath(); + +private: + bool DoFindPath( void ); // Find a route + bool DoFindPathToPathcorner( CBaseEntity *pPathCorner ); + +protected: + virtual bool DoFindPathToPos(void); + virtual bool ShouldOptimizeInitialPathSegment( AI_Waypoint_t * ) { return true; } + +private: + void ClearPath(void); + void SaveStoppingPath( void ); + +protected: + virtual bool GetStoppingPath( CAI_WaypointList *pClippedWaypoints ); + +private: + bool FindPath( const AI_NavGoal_t &goal, unsigned flags ); + bool FindPath( bool fSignalTaskStatus = true, bool bDontIgnoreBadLinks = false ); + bool MarkCurWaypointFailedLink( void ); // Call when route fails + + struct SimplifyForwardScanParams + { + float scanDist; + float radius; + float increment; + int maxSamples; + }; + + bool ShouldAttemptSimplifyTo( const Vector &pos ); + bool ShouldSimplifyTo( bool passedDetour, const Vector &pos ); + bool SimplifyPathForwardScan( const CAI_Navigator::SimplifyForwardScanParams ¶ms ); + bool SimplifyPathForwardScan( const SimplifyForwardScanParams ¶ms, AI_Waypoint_t *pCurWaypoint, const Vector &curPoint, float distRemaining, bool skip, bool passedDetour, int *pTestCount ); + bool SimplifyPathForward( float maxDist = -1 ); + bool SimplifyPathBacktrack(); + bool SimplifyPathQuick(); + void SimplifyPathInsertSimplification( AI_Waypoint_t *pSegmentStart, const Vector &point ); + + // --------------------------------- + + static bool ActivityIsLocomotive( Activity ); + + // --------------------------------- + + Navigation_t m_navType; // My current navigation type (walk,fly) + bool m_fNavComplete; + bool m_bLastNavFailed; + + // Cached pointers to other components, for efficiency + CAI_Motor * m_pMotor; + CAI_MoveProbe * m_pMoveProbe; + CAI_LocalNavigator *m_pLocalNavigator; + + // --------------------------------- + + CAI_Network* m_pAINetwork; // My current AINetwork + CAI_Path* m_pPath; // My current route + + CAI_WaypointList * m_pClippedWaypoints; + float m_flTimeClipped; + Activity m_PreviousMoveActivity; + Activity m_PreviousArrivalActivity; + + bool m_bValidateActivitySpeed; + bool m_bCalledStartMove; + + bool m_bNotOnNetwork; // This NPC has no reachable nodes! + + float m_flNextSimplifyTime; // next time we should try to simplify our route + bool m_bForcedSimplify; + float m_flLastSuccessfulSimplifyTime; + + float m_flTimeLastAvoidanceTriangulate; + + // -------------- + + float m_timePathRebuildMax; // How long to try rebuilding path before failing task + float m_timePathRebuildDelay; // How long to wait before trying to rebuild again + + float m_timePathRebuildFail; // Current global time when should fail building path + float m_timePathRebuildNext; // Global time to try rebuilding again + + // -------------- + + bool m_fRememberStaleNodes; + bool m_bNoPathcornerPathfinds; + bool m_bLocalSucceedOnWithinTolerance; + + // -------------- + + bool m_fPeerMoveWait; + EHANDLE m_hPeerWaitingOn; + CSimTimer m_PeerWaitMoveTimer; + CSimTimer m_PeerWaitClearTimer; + + CSimTimer m_NextSidestepTimer; + + // -------------- + + EHANDLE m_hBigStepGroundEnt; + EHANDLE m_hLastBlockingEnt; + + // -------------- + + Vector m_vPosBeginFailedSteer; + float m_timeBeginFailedSteer; + + // -------------- + + int m_nNavFailCounter; + float m_flLastNavFailTime; +public: + DECLARE_SIMPLE_DATADESC(); +}; + + +//----------------------------------------------------------------------------- +// AI_NavGoal_t inline methods +//----------------------------------------------------------------------------- + +inline AI_NavGoal_t::AI_NavGoal_t( GoalType_t type, + Activity activity, + float tolerance, + unsigned flags, + CBaseEntity *pTarget) + : type(type), + dest(AIN_NO_DEST), + destNode(AIN_NO_NODE), + activity(activity), + tolerance(tolerance), + maxInitialSimplificationDist(-1), + flags(flags), + pTarget(pTarget), + arrivalActivity( AIN_DEF_ACTIVITY ), + arrivalSequence( ACT_INVALID ) +{ +} + +inline AI_NavGoal_t::AI_NavGoal_t( const Vector &dest, + Activity activity, + float tolerance, + unsigned flags, + CBaseEntity *pTarget) + : type(GOALTYPE_LOCATION), + dest(dest), + destNode(AIN_NO_NODE), + activity(activity), + tolerance(tolerance), + maxInitialSimplificationDist(-1), + flags(flags), + pTarget(pTarget), + arrivalActivity( AIN_DEF_ACTIVITY ), + arrivalSequence( ACT_INVALID ) +{ +} + +inline AI_NavGoal_t::AI_NavGoal_t( GoalType_t type, + const Vector &dest, + Activity activity, + float tolerance, + unsigned flags, + CBaseEntity *pTarget) + : type(type), + dest(dest), + destNode(AIN_NO_NODE), + activity(activity), + tolerance(tolerance), + maxInitialSimplificationDist(-1), + flags(flags), + pTarget(pTarget), + arrivalActivity( AIN_DEF_ACTIVITY ), + arrivalSequence( ACT_INVALID ) +{ +} + +inline AI_NavGoal_t::AI_NavGoal_t( AI_PathNode_t destNode, + Activity activity, + float tolerance, + unsigned flags, + CBaseEntity * pTarget) + : type(GOALTYPE_LOCATION), + dest(AIN_NO_DEST), + destNode(destNode), + activity(activity), + tolerance(tolerance), + maxInitialSimplificationDist(-1), + flags(flags), + pTarget(pTarget), + arrivalActivity( AIN_DEF_ACTIVITY ), + arrivalSequence( ACT_INVALID ) +{ +} + +inline AI_NavGoal_t::AI_NavGoal_t( GoalType_t type, + AI_PathNode_t destNode, + Activity activity, + float tolerance, + unsigned flags, + CBaseEntity * pTarget) + : type(type), + dest(AIN_NO_DEST), + destNode(destNode), + activity(activity), + tolerance(tolerance), + maxInitialSimplificationDist(-1), + flags(flags), + pTarget(pTarget), + arrivalActivity( AIN_DEF_ACTIVITY ), + arrivalSequence( ACT_INVALID ) +{ +} + +//----------------------------------------------------------------------------- + +#endif // AI_NAVIGATOR_H diff --git a/game/server/ai_navtype.h b/game/server/ai_navtype.h new file mode 100644 index 0000000..8aa47e6 --- /dev/null +++ b/game/server/ai_navtype.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NAVTYPE_H +#define AI_NAVTYPE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +// --------------------------- +// Navigation Type Bits +// --------------------------- +enum Navigation_t +{ + NAV_NONE = -1, // error condition + NAV_GROUND = 0, // walk/run + NAV_JUMP, // jump/leap + NAV_FLY, // can fly, move all around + NAV_CLIMB, // climb ladders +}; + + +#endif // AI_NAVTYPE_H diff --git a/game/server/ai_network.h b/game/server/ai_network.h new file mode 100644 index 0000000..8cebd16 --- /dev/null +++ b/game/server/ai_network.h @@ -0,0 +1,221 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NETWORK_H +#define AI_NETWORK_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "ispatialpartition.h" +#include "utlpriorityqueue.h" + +// ------------------------------------ + +class CAI_Node; +class CVarBitVec; +class INodeListFilter; + +struct AI_Waypoint_t; +class CAI_BaseNPC; +class CAI_Link; +class CAI_DynamicLink; + +//----------------------------------------------------------------------------- + +class CAI_NetworkManager; + +//----------------------------------------------------------------------------- + +#define AI_MAX_NODE_LINKS 30 +#define MAX_NODES 1500 + +//----------------------------------------------------------------------------- +// +// Utility classes used by CAI_Network +// +//----------------------------------------------------------------------------- + +abstract_class INearestNodeFilter +{ +public: + virtual bool IsValid( CAI_Node *pNode ) = 0; + virtual bool ShouldContinue() = 0; +}; + +//------------------------------------- + +struct AI_NearNode_t +{ + AI_NearNode_t() {} + AI_NearNode_t( int index, float nodedist ) { dist = nodedist; nodeIndex = index; } + float dist; + int nodeIndex; +}; + +//------------------------------------- + +class CNodeList : public CUtlPriorityQueue +{ +public: + static bool IsLowerPriority( const AI_NearNode_t &node1, const AI_NearNode_t &node2 ) + { + // nodes with greater distance are lower priority + return node1.dist > node2.dist; + } + static bool RevIsLowerPriority( const AI_NearNode_t &node1, const AI_NearNode_t &node2 ) + { + // nodes with lower distance are lower priority + return node2.dist > node1.dist; + } + + CNodeList( int growSize = 0, int initSize = 0 ) : CUtlPriorityQueue( growSize, initSize, IsLowerPriority ) {} + CNodeList( AI_NearNode_t *pMemory, int count ) : CUtlPriorityQueue( pMemory, count, IsLowerPriority ) {} +}; + +//----------------------------------------------------------------------------- +// CAI_Network +// +// Purpose: Stores a node graph through which an AI may pathfind +//----------------------------------------------------------------------------- + +class CAI_Network : public IPartitionEnumerator +{ +public: + CAI_Network(); + ~CAI_Network(); + + CAI_Node * AddNode( const Vector &origin, float yaw ); // Returns a new node in the network + CAI_Link * CreateLink( int srcID, int destID, CAI_DynamicLink *pDynamicLink = NULL ); + + bool IsConnected(int srcID, int destID); // Use during run time + void TestIsConnected(int startID, int endID); // Use only for initialization! + + Vector GetNodePosition( CBaseCombatCharacter *pNPC, int nodeID ); + Vector GetNodePosition( Hull_t hull, int nodeID ); + float GetNodeYaw( int nodeID ); + + static int FindBSSmallest(CVarBitVec *bitString, float *float_array, int array_size); + + int NearestNodeToPoint( CAI_BaseNPC* pNPC, const Vector &vecOrigin, bool bCheckVisiblity, INearestNodeFilter *pFilter ); + int NearestNodeToPoint( CAI_BaseNPC* pNPC, const Vector &vecOrigin, bool bCheckVisiblity = true ) { return NearestNodeToPoint( pNPC, vecOrigin, bCheckVisiblity, NULL ); } + int NearestNodeToPoint(const Vector &vPosition, bool bCheckVisiblity = true ); + + int NumNodes() const { return m_iNumNodes; } + CAI_Node* GetNode( int id, bool bHandleError = true ) + { + if ( id >= 0 && + id < m_iNumNodes ) + { + return m_pAInode[id]; + } + + if ( bHandleError ) + { + static int warningCount = 0; + if ( ++warningCount < 10 ) + { + AssertMsg2( 0, "Node (%i) out of range (%i total)\n", id, m_iNumNodes ); + } + } + return NULL; + } + + CAI_Node** AccessNodes() const { return m_pAInode; } + +private: + friend class CAI_NetworkManager; + + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + + int GetCachedNearestNode(const Vector &checkPos, CAI_BaseNPC *pNPC, int *pCachePos ); + void SetCachedNearestNode(const Vector &checkPos, int nodeID, Hull_t nHull); + int GetCachedNode(const Vector &checkPos, Hull_t nHull, int *pCachePos); + + int ListNodesInBox( CNodeList &list, int maxListCount, const Vector &mins, const Vector &maxs, INodeListFilter *pFilter ); + + //--------------------------------- + + enum + { + NEARNODE_CACHE_SIZE = 32, + NEARNODE_CACHE_LIFE = 10, + }; + + struct NearNodeCache_T + { + Vector vTestPosition; + float expiration; // Time tested + int node; // Nearest Node to position + int hull; // Hull type tested (or HULL_NONE is only visibility tested) + + }; + + int m_iNumNodes; // Number of nodes in this network + CAI_Node** m_pAInode; // Array of all nodes in this network + + enum + { + PARTITION_NODE = ( 1 << 0 ) + }; + + NearNodeCache_T m_NearestCache[NEARNODE_CACHE_SIZE]; // Cache of nearest nodes + int m_iNearestCacheNext; // Oldest record in the cache + +#ifdef AI_NODE_TREE + ISpatialPartition * m_pNodeTree; + CUtlVector m_GatheredNodes; +#endif +}; + +//----------------------------------------------------------------------------- +// CAI_NetworkEditTools +// +// Purpose: Provides the operations used when building levels, whether in-game +// debugging tools or editor related items. +// +//----------------------------------------------------------------------------- + + +// ------------------------------------ +// Debug overlay bits + +enum DebugNetOverlayBits_e +{ + bits_debugOverlayNodes = 0x00000001, // show node + bits_debugOverlayNodesLev2 = 0x00000002, // show nodes and text + + bits_debugOverlayHulls = 0x00000004, // show hulls + bits_debugOverlayConnections = 0x00000008, // show connections + bits_debugOverlayVisibility = 0x00000010, // show visibility + bits_debugOverlayGraphConnect = 0x00000020, // show graph connectivity + bits_debugOverlayGrid = 0x00000040, // show grid + bits_debugOverlayHints = 0x00000080, // show hints + bits_debugOverlayJumpConnections= 0x00000100, // show jump connections + bits_debugOverlayFlyConnections = 0x00000200, // show fly connections + + bits_debugNeedRebuild = 0x10000000, // network needs rebuilding +}; + +// ------------------------------------ + +// ---------------- + +//----------------------------------------------------------------------------- +// Useful utility function defined by AI_network.cpp +Vector PointOnLineNearestPoint(const Vector& vStartPos, const Vector& vEndPos, const Vector& vPoint); + +//----------------------------------------------------------------------------- + +// For now just using one big AI network +extern CAI_NetworkManager * g_pAINetworkManager; +extern CAI_Network * g_pBigAINet; + +//============================================================================= + +#endif // AI_NETWORK_H diff --git a/game/server/ai_networkmanager.h b/game/server/ai_networkmanager.h new file mode 100644 index 0000000..e8e6130 --- /dev/null +++ b/game/server/ai_networkmanager.h @@ -0,0 +1,199 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_NETWORKMANAGER_H +#define AI_NETWORKMANAGER_H + +#include "utlvector.h" +#include "bitstring.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class CAI_NetworkEditTools; +class CAI_Network; +class CAI_Node; +class CAI_Link; +class CAI_TestHull; + +//----------------------------------------------------------------------------- +// CAI_NetworkManager +// +// Purpose: The entity in the level responsible for building the network if it +// isn't there, saving & loading of the network, and holding the +// CAI_Network instance. +// +//----------------------------------------------------------------------------- + +class CAI_NetworkManager : public CPointEntity +{ +public: + static void InitializeAINetworks(); + + DECLARE_DATADESC(); + + DECLARE_CLASS( CAI_NetworkManager, CPointEntity ); + +public: + CAI_NetworkManager(void); + virtual ~CAI_NetworkManager(void); + + void Spawn (); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_DONT_SAVE; } + void RebuildNetworkGraph(); // Used in WC edit mode + void StartRebuild(); // Used in WC edit mode + void LoadNetworkGraph(); + + static bool NetworksLoaded() { return gm_fNetworksLoaded; } + bool IsInitialized() { return m_fInitalized; } + + void BuildNetworkGraph(); + + static void DeleteAllAINetworks(); + + void FixupHints(); + void MarkDontSaveGraph(); + +public: + CAI_NetworkEditTools * GetEditOps() { return m_pEditOps; } + CAI_Network * GetNetwork() { return m_pNetwork; } + +private: + + void DelayedInit(); + void RebuildThink(); + void SaveNetworkGraph( void) ; + static bool IsAIFileCurrent( const char *szMapName ); + + static bool gm_fNetworksLoaded; // Have AINetworks been loaded + + bool m_bNeedGraphRebuild; + CAI_NetworkEditTools * m_pEditOps; + CAI_Network * m_pNetwork; + + + bool m_fInitalized; + bool m_bDontSaveGraph; +}; + +//----------------------------------------------------------------------------- + +abstract_class CAI_NetworkBuildHelper : public CLogicalEntity +{ + DECLARE_CLASS( CAI_NetworkBuildHelper, CLogicalEntity ); + +public: + virtual void PostInitNodePosition( CAI_Network *pNetwork, CAI_Node *pNode ) = 0; +}; + +//----------------------------------------------------------------------------- + +class CAI_NetworkBuilder +{ +public: + void Build( CAI_Network *pNetwork ); + void Rebuild( CAI_Network *pNetwork ); + + void InitNodePosition( CAI_Network *pNetwork, CAI_Node *pNode ); + + void InitZones( CAI_Network *pNetwork ); + +private: + void InitVisibility( CAI_Network *pNetwork, CAI_Node *pNode ); + void InitNeighbors( CAI_Network *pNetwork, CAI_Node *pNode ); + void InitClimbNodePosition( CAI_Network *pNetwork, CAI_Node *pNode ); + void InitGroundNodePosition( CAI_Network *pNetwork, CAI_Node *pNode ); + void InitLinks( CAI_Network *pNetwork, CAI_Node *pNode ); + void ForceDynamicLinkNeighbors(); + + void FloodFillZone( CAI_Node **ppNodes, CAI_Node *pNode, int zone ); + + int ComputeConnection( CAI_Node *pSrcNode, CAI_Node *pDestNode, Hull_t hull ); + + void BeginBuild(); + void EndBuild(); + + CUtlVector m_NeighborsTable; + CVarBitVec m_DidSetNeighborsTable; + CAI_TestHull * m_pTestHull; +}; + +extern CAI_NetworkBuilder g_AINetworkBuilder; + +//----------------------------------------------------------------------------- +// CAI_NetworkEditTools +// +// Purpose: Bridge class to Hammer node editing functionality +// +//----------------------------------------------------------------------------- + +class CAI_NetworkEditTools +{ +public: + CAI_NetworkEditTools(CAI_NetworkManager *); + ~CAI_NetworkEditTools(); + // ---------------------- + // Debug & Edit fields + // ---------------------- + static CAI_Node * m_pLastDeletedNode; // For undo in wc edit mode + static int m_iHullDrawNum; // Which hulls to draw + static int m_iVisibilityNode; // Node I'm showing visibility for + static int m_iGConnectivityNode; // Node I'm showing graph connectivity for + static bool m_bAirEditMode; // Editing Air Nodes + static bool m_bLinkEditMode; // Editing Links + static float m_flAirEditDistance; // Distance editing Air Nodes + + static void DrawHull(Hull_t eHull); + static void DrawNextHull(const char *ainet_name); // Draws next hull set for the named ai network + static void SetDebugBits(const char *ainet_name,int debug_bit); + + static CAI_Node * FindAINodeNearestFacing( const Vector &origin, const Vector &facing, float threshold, int nNodeType); + static CAI_Link * FindAILinkNearestFacing( const Vector &origin, const Vector &facing, float threshold); + + //--------------- + // WC Editing + //--------------- + int m_nNextWCIndex; // Next unused index used by WC + Vector * m_pWCPosition; // Array of vectors only used in wc edit mode + + //----------------- + // Debugging Tools + //----------------- + int m_debugNetOverlays; // Which network debug overlays to draw + void DrawAINetworkOverlay(void); // Draw network on the client + + void RecalcUsableNodesForHull(void); // Used only for debug drawing + + //----------------- + void OnInit(); + + int GetNodeIdFromWCId( int nWCId ); + int GetWCIdFromNodeId( int nNodeId ); + int * m_pNodeIndexTable; // Table of WC Id's to Engine Id's + + void ClearRebuildFlags(); + void SetRebuildFlags(); + void DrawEditInfoOverlay(); + +#ifdef AI_PERF_MON + //---------------------- + // Performance stats + //---------------------- + static int m_nPerfStatNN; + static int m_nPerfStatPB; + static float m_fNextPerfStatTime; +#endif + + CAI_NetworkManager *m_pManager; + CAI_Network * m_pNetwork; + + +}; + +//----------------------------------------------------------------------------- + +#endif // AI_NETWORKMANAGER_H diff --git a/game/server/ai_node.h b/game/server/ai_node.h new file mode 100644 index 0000000..6c79d9a --- /dev/null +++ b/game/server/ai_node.h @@ -0,0 +1,168 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base combat character with no AI +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NODE_H +#define AI_NODE_H +#pragma once + +#include "ai_hull.h" +#include "bitstring.h" +#include "utlvector.h" + +enum AI_ZoneIds_t +{ + AI_NODE_ZONE_UNKNOWN = 0, + AI_NODE_ZONE_SOLO = 1, + AI_NODE_ZONE_UNIVERSAL = 3, + AI_NODE_FIRST_ZONE = 4, +}; + +class CAI_Network; +class CAI_Link; +class CAI_Hint; +class CAI_BaseNPC; + +#define NOT_CACHED -2 // Returned if data not in cache +#define NO_NODE -1 // Returned when no node meets the qualification + +#define MAX_NODE_LINK_DIST 60*12 // Maximum connection length between nodes as well as furthest +#define MAX_NODE_LINK_DIST_SQ (MAX_NODE_LINK_DIST*MAX_NODE_LINK_DIST) // distance allowed to travel to node via local moves + +#define MAX_AIR_NODE_LINK_DIST 120*12 // Maximum connection length between air nodes as well as furthest +#define MAX_AIR_NODE_LINK_DIST_SQ (MAX_AIR_NODE_LINK_DIST*MAX_AIR_NODE_LINK_DIST) // distance allowed to travel to node via local moves + + + +#define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier) +#define NODE_CLIMB_OFFSET 8 + +#define HULL_TEST_STEP_SIZE 16 // how far the test hull moves on each step + +//========================================================= +// The type of node +//========================================================= +enum NodeType_e +{ + NODE_ANY, // Used to specify any type of node (for search) + NODE_DELETED, // Used in wc_edit mode to remove nodes during runtime + NODE_GROUND, + NODE_AIR, + NODE_CLIMB, + NODE_WATER +}; + +enum NodeInfoBits_e +{ + bits_NODE_CLIMB_BOTTOM = (1 << 0), // Node at bottom of ladder + bits_NODE_CLIMB_ON = (1 << 1), // Node on ladder somewhere + bits_NODE_CLIMB_OFF_FORWARD = (1 << 2), // Dismount climb by going forward + bits_NODE_CLIMB_OFF_LEFT = (1 << 3), // Dismount climb by going left + bits_NODE_CLIMB_OFF_RIGHT = (1 << 4), // Dismount climb by going right + + bits_NODE_CLIMB_EXIT = bits_NODE_CLIMB_OFF_FORWARD| bits_NODE_CLIMB_OFF_LEFT | bits_NODE_CLIMB_OFF_RIGHT, + + NODE_ENT_FLAGS_SHIFT = 5, + + //bits_HUMAN_HULL 5 + //bits_SMALL_CENTERED_HULL 6 + //bits_WIDE_HUMAN_HULL 7 + //bits_TINY_HULL 8 + //bits_WIDE_SHORT_HULL 9 + //bits_MEDIUM_HULL 10 + //bits_TINY_CENTERED_HULL 11 + //bits_LARGE_HULL 12 + //bits_LARGE_CENTERED_HULL 13 + + bits_DONT_DROP = ( 1 << 14 ), + + /****** NOTE: will need to change node graph save/load code if exceed 16 bits here ******/ + + + + bits_NODE_WC_NEED_REBUILD = 0x10000000, // Used to more nodes in WC edit mode + bits_NODE_WC_CHANGED = 0x20000000, // Node changed during WC edit + + bits_NODE_WONT_FIT_HULL = 0x40000000, // Used only for debug display + bits_NODE_FALLEN = 0x80000000, // Fell through the world during initialization +}; + + +//============================================================================= +// >> CAI_Node +//============================================================================= + +class CAI_Node +{ +public: + + CAI_Node( int id, const Vector &origin, float yaw ); + + CAI_Hint* GetHint() { return m_pHint; } + void SetHint( CAI_Hint *pHint ) { m_pHint = pHint; } + + int NumLinks() const { return m_Links.Count(); } + void ClearLinks() { m_Links.Purge(); } + CAI_Link * GetLink( int destNodeId ); + CAI_Link * GetLinkByIndex( int i ) { return m_Links[i]; } + + bool IsLocked() const { return ( m_flNextUseTime > gpGlobals->curtime ); } + void Lock( float duration ) { m_flNextUseTime = gpGlobals->curtime + duration; } + void Unlock() { m_flNextUseTime = gpGlobals->curtime; } + + int GetZone() const { return m_zone; } + void SetZone( int zone ) { m_zone = zone; } + + Vector GetPosition(int hull); // Hull specific position for a node + CAI_Link* HasLink(int nNodeID); // Return link to nNodeID or NULL + + void ShuffleLinks(); // Called before GetShuffeledLinks to reorder + CAI_Link* GetShuffeledLink(int nNum); // Used to get links in different order each time + + int GetId() const { return m_iID; } + + const Vector & GetOrigin() const { return m_vOrigin; } + Vector & AccessOrigin() { return m_vOrigin; } + float GetYaw() const { return m_flYaw; } + + NodeType_e SetType( NodeType_e type ) { return ( m_eNodeType = type ); } + NodeType_e GetType() const { return m_eNodeType; } + + void SetNeedsRebuild() { m_eNodeInfo |= bits_NODE_WC_NEED_REBUILD; } + void ClearNeedsRebuild() { m_eNodeInfo &= ~bits_NODE_WC_NEED_REBUILD; } + bool NeedsRebuild() const { return ( ( m_eNodeInfo & bits_NODE_WC_NEED_REBUILD ) != 0 ); } + + void AddLink(CAI_Link *newLink); + + int m_iID; // ID for this node + Vector m_vOrigin; // location of this node in space + + float m_flVOffset[NUM_HULLS]; // vertical offset for each hull type, assuming ground node, 0 otherwise + float m_flYaw; // NPC on this node should face this yaw to face the hint, or climb a ladder + + NodeType_e m_eNodeType; // The type of node + + int m_eNodeInfo; // bits that tell us more about this nodes + + int m_zone; + CUtlVector m_Links; // growable array of links to this node + + float m_flNextUseTime; // When can I be used again? + CAI_Hint* m_pHint; // hint attached to this node + int m_iFirstShuffledLink; // first link to check +}; + + +extern float GetFloorZ(const Vector &origin); +extern float GetFloorDistance(const Vector &origin); + +#endif // AI_NODE_H diff --git a/game/server/ai_npcstate.h b/game/server/ai_npcstate.h new file mode 100644 index 0000000..91834c4 --- /dev/null +++ b/game/server/ai_npcstate.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_NPCSTATE_H +#define AI_NPCSTATE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +enum NPC_STATE +{ + NPC_STATE_INVALID = -1, + NPC_STATE_NONE = 0, + NPC_STATE_IDLE, + NPC_STATE_ALERT, + NPC_STATE_COMBAT, + NPC_STATE_SCRIPT, + NPC_STATE_PLAYDEAD, + NPC_STATE_PRONE, // When in clutches of barnacle + NPC_STATE_DEAD + +}; + +#endif // AI_NPCSTATE_H diff --git a/game/server/ai_obstacle_type.h b/game/server/ai_obstacle_type.h new file mode 100644 index 0000000..5f5a382 --- /dev/null +++ b/game/server/ai_obstacle_type.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_OBSTACLE_TYPE_H +#define AI_OBSTACLE_TYPE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +//------------------------------------- +// AI_MoveSuggType_t +// +// Purpose: Specifies the type of suggestion. Different types have different weights +//------------------------------------- +enum AI_MoveSuggType_t +{ + // Positive suggestions + AIMST_MOVE, + + // Negative suggestions + AIMST_AVOID_DANGER, + AIMST_AVOID_OBJECT, + AIMST_AVOID_NPC, + AIMST_AVOID_WORLD, + + AIMST_NO_KNOWLEDGE, + AIMST_OSCILLATION_DETERRANCE, + + AIMS_INVALID +}; + +#endif // AI_OBSTACLE_TYPE_H diff --git a/game/server/ai_pathfinder.h b/game/server/ai_pathfinder.h new file mode 100644 index 0000000..615e7d7 --- /dev/null +++ b/game/server/ai_pathfinder.h @@ -0,0 +1,204 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_PATHFINDER_H +#define AI_PATHFINDER_H + +#include "ai_component.h" +#include "ai_navtype.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +struct AIMoveTrace_t; +struct OverlayLine_t; +struct AI_Waypoint_t; +class CAI_Link; +class CAI_Network; +class CAI_Node; + + +//----------------------------------------------------------------------------- +// The type of route to build +enum RouteBuildFlags_e +{ + bits_BUILD_GROUND = 0x00000001, // + bits_BUILD_JUMP = 0x00000002, // + bits_BUILD_FLY = 0x00000004, // + bits_BUILD_CLIMB = 0x00000008, // + bits_BUILD_GIVEWAY = 0x00000010, // + bits_BUILD_TRIANG = 0x00000020, // + bits_BUILD_IGNORE_NPCS = 0x00000040, // Ignore collisions with NPCs + bits_BUILD_COLLIDE_NPCS = 0x00000080, // Use collisions with NPCs (redundant for argument clarity) + bits_BUILD_GET_CLOSE = 0x00000100, // the route will be built even if it can't reach the destination +}; + +//----------------------------------------------------------------------------- +// CAI_Pathfinder +// +// Purpose: Executes pathfinds through an associated network. +// +//----------------------------------------------------------------------------- + +class CAI_Pathfinder : public CAI_Component +{ +public: + CAI_Pathfinder( CAI_BaseNPC *pOuter ) + : CAI_Component(pOuter), + m_flLastStaleLinkCheckTime( 0 ), + m_pNetwork( NULL ) + { + } + + void Init( CAI_Network *pNetwork ); + + //--------------------------------- + + int NearestNodeToNPC(); + int NearestNodeToPoint( const Vector &vecOrigin ); + + AI_Waypoint_t* FindBestPath (int startID, int endID); + AI_Waypoint_t* FindShortRandomPath (int startID, float minPathLength, const Vector &vDirection = vec3_origin); + + // -------------------------------- + + bool IsLinkUsable(CAI_Link *pLink, int startID); + + // -------------------------------- + + AI_Waypoint_t *BuildRoute( const Vector &vStart, const Vector &vEnd, CBaseEntity *pTarget, float goalTolerance, Navigation_t curNavType = NAV_NONE, bool bLocalSucceedOnWithinTolerance = false ); + void UnlockRouteNodes( AI_Waypoint_t * ); + + // -------------------------------- + + void SetIgnoreBadLinks() { m_bIgnoreStaleLinks = true; } // lasts only for the next pathfind + + // -------------------------------- + + virtual AI_Waypoint_t *BuildNodeRoute( const Vector &vStart, const Vector &vEnd, int buildFlags, float goalTolerance ); + virtual AI_Waypoint_t *BuildLocalRoute( const Vector &vStart, const Vector &vEnd, CBaseEntity const *pTarget, int endFlags, int nodeID, int buildFlags, float goalTolerance); + virtual AI_Waypoint_t *BuildRadialRoute( const Vector &vStartPos, const Vector &vCenterPos, const Vector &vGoalPos, float flRadius, float flArc, float flStepDist, bool bClockwise, float goalTolerance, bool bAirRoute ); + + virtual AI_Waypoint_t *BuildTriangulationRoute( const Vector &vStart, + const Vector &vEnd, CBaseEntity const *pTarget, int endFlags, int nodeID, + float flYaw, float flDistToBlocker, Navigation_t navType); + + virtual AI_Waypoint_t *BuildOBBAvoidanceRoute( const Vector &vStart, const Vector &vEnd, + const CBaseEntity *pObstruction, const CBaseEntity *pTarget, + Navigation_t navType ); + + // -------------------------------- + + bool Triangulate( Navigation_t navType, const Vector &vecStart, const Vector &vecEnd, + float flDistToBlocker, CBaseEntity const *pTargetEnt, Vector *pApex ); + + // -------------------------------- + + void DrawDebugGeometryOverlays( int m_debugOverlays ); + +protected: + virtual bool CanUseLocalNavigation() { return true; } + +private: + friend class CPathfindNearestNodeFilter; + + //--------------------------------- + + AI_Waypoint_t* RouteToNode(const Vector &vecOrigin, int buildFlags, int nodeID, float goalTolerance); + AI_Waypoint_t* RouteFromNode(const Vector &vecOrigin, int buildFlags, int nodeID, float goalTolerance); + + AI_Waypoint_t * BuildNearestNodeRoute( const Vector &vGoal, bool bToNode, int buildFlags, float goalTolerance, int *pNearestNode ); + + //--------------------------------- + + AI_Waypoint_t* MakeRouteFromParents(int *parentArray, int endID); + AI_Waypoint_t* CreateNodeWaypoint( Hull_t hullType, int nodeID, int nodeFlags = 0 ); + + AI_Waypoint_t* BuildRouteThroughPoints( Vector *vecPoints, int nNumPoints, int nDirection, int nStartIndex, int nEndIndex, Navigation_t navType, CBaseEntity *pTarget ); + + bool IsLinkStillStale(int moveType, CAI_Link *nodeLink); + + // -------------------------------- + + // Builds a simple route (no triangulation, no making way) + AI_Waypoint_t *BuildSimpleRoute( Navigation_t navType, const Vector &vStart, const Vector &vEnd, + const CBaseEntity *pTarget, int endFlags, int nodeID, int nodeTargetType, float flYaw); + + // Builds a complex route (triangulation, making way) + AI_Waypoint_t *BuildComplexRoute( Navigation_t navType, const Vector &vStart, + const Vector &vEnd, const CBaseEntity *pTarget, int endFlags, int nodeID, + int buildFlags, float flYaw, float goalTolerance, float maxLocalNavDistance ); + + AI_Waypoint_t *BuildGroundRoute( const Vector &vStart, const Vector &vEnd, CBaseEntity const *pTarget, int endFlags, int nodeID, int buildFlags, float flYaw, float goalTolerance ); + AI_Waypoint_t *BuildFlyRoute( const Vector &vStart, const Vector &vEnd, CBaseEntity const *pTarget, int endFlags, int nodeID, int buildFlags, float flYaw, float goalTolerance ); + AI_Waypoint_t *BuildJumpRoute( const Vector &vStart, const Vector &vEnd, CBaseEntity const *pTarget, int endFlags, int nodeID, int buildFlags, float flYaw ); + AI_Waypoint_t *BuildClimbRoute( const Vector &vStart, const Vector &vEnd, CBaseEntity const *pTarget, int endFlags, int nodeID, int buildFlags, float flYaw ); + + // Computes the link type + Navigation_t ComputeWaypointType( CAI_Node **ppNodes, int parentID, int destID ); + + // -------------------------------- + + bool TestTriangulationRoute( Navigation_t navType, const Vector& vecStart, + const Vector &vecApex, const Vector &vecEnd, const CBaseEntity *pTargetEnt, AIMoveTrace_t *pStartTrace ); + + // -------------------------------- + + bool CheckStaleRoute( const Vector &vStart, const Vector &vEnd, int moveTypes); + bool CheckStaleNavTypeRoute( Navigation_t navType, const Vector &vStart, const Vector &vEnd ); + + // -------------------------------- + + bool CanGiveWay( const Vector& vStart, const Vector& vEnd, CBaseEntity *pNPCBlocker ); + + // -------------------------------- + + bool UseStrongOptimizations(); + + // -------------------------------- + // Debugging fields and functions + + class CTriDebugOverlay + { + public: + CTriDebugOverlay() + : m_debugTriOverlayLine( NULL ) + { + } + void AddTriOverlayLines( const Vector &vecStart, const Vector &vecApex, const Vector &vecEnd, const AIMoveTrace_t &startTrace, const AIMoveTrace_t &endTrace, bool bPathClear ); + void ClearTriOverlayLines(void); + void FadeTriOverlayLines(void); + + void Draw(int npcDebugOverlays); + private: + void AddTriOverlayLine(const Vector &origin, const Vector &dest, int r, int g, int b, bool noDepthTest); + + OverlayLine_t **m_debugTriOverlayLine; + }; + + CTriDebugOverlay m_TriDebugOverlay; + + //--------------------------------- + + float m_flLastStaleLinkCheckTime; // Last time I check for a stale link + bool m_bIgnoreStaleLinks; + + //--------------------------------- + + CAI_Network *GetNetwork() { return m_pNetwork; } + const CAI_Network *GetNetwork() const { return m_pNetwork; } + + CAI_Network *m_pNetwork; + +public: + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- + +#endif // AI_PATHFINDER_H diff --git a/game/server/ai_planesolver.h b/game/server/ai_planesolver.h new file mode 100644 index 0000000..867d1e8 --- /dev/null +++ b/game/server/ai_planesolver.h @@ -0,0 +1,174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_PLANE_SOLVER_H +#define AI_PLANE_SOLVER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "ai_movesolver.h" +#include "ehandle.h" +#include "mathlib/vector.h" +#include "simtimer.h" +#include "ai_navtype.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class Vector2D; +class CBaseEntity; +struct edict_t; +class CAI_BaseNPC; +class CAI_Motor; +class CAI_Navigator; +struct AILocalMoveGoal_t; +struct AIMoveTrace_t; + +//------------------------------------- + +enum AI_SuggestorResult_t +{ + SR_NONE, + SR_OK, + SR_FAIL +}; + +class CAI_PlaneSolver +{ +public: + // constructor + CAI_PlaneSolver( CAI_BaseNPC *pNpc ); + + // Attempt to find a valid move direction for the specifed goal + bool Solve( const AILocalMoveGoal_t &goal, float distClear, Vector *pSolution ); + + float CalcProbeDist( float speed ); + + // Flush any cached results (e.g., hull changed, results not valid) + void Reset(); + + void AddObstacle( const Vector &pos, float radius, CBaseEntity *pEntity = NULL, AI_MoveSuggType_t type = AIMST_AVOID_OBJECT ); + bool HaveObstacles() { return ( m_Obstacles.Count() != 0 ); } + +private: + + enum + { + DEGREES_POSITIVE_ARC = 270, + DEGREES_POSITIVE_ARC_CLOSE_OBSTRUCTION = 340, + NUM_PROBES = 5 + }; + + // How far ahead does the ground solver look (seconds) + float GetLookaheadTime() { return 1.0; } + + // -------------------------------- + + // For debugging purposes + void VisualizeRegulations(); + void VisualizeSolution( const Vector &vecGoal, const Vector& vecActual ); + + // -------------------------------- + bool MoveLimit( Navigation_t navType, const Vector &target, bool ignoreTransients, bool fCheckStep, AIMoveTrace_t *pMoveTrace ); + bool MoveLimit( Navigation_t navType, const Vector &target, bool ignoreTransients, bool fCheckStep, int contents, AIMoveTrace_t *pMoveTrace ); + + //----------------------------------------------------------------------------- + // Adjust the solution for fliers + //----------------------------------------------------------------------------- + void AdjustSolutionForFliers( const AILocalMoveGoal_t &goal, float flSolutionYaw, Vector *pSolution ); + + // -------------------------------- + // Convenience accessors + + CAI_BaseNPC * GetNpc(); + CAI_Motor * GetMotor(); + const Vector & GetLocalOrigin(); + + // -------------------------------- + + void GenerateObstacleNpcs( const AILocalMoveGoal_t &goal, float probeDist ); + AI_SuggestorResult_t GenerateObstacleSuggestions( const AILocalMoveGoal_t &goal, const AIMoveTrace_t &directTrace, float distClear, float probeDist, float degreesToProbe, int nProbes ); + AI_SuggestorResult_t GenerateObstacleSuggestion( const AILocalMoveGoal_t &goal, float yawScanCenter, float probeDist, float spanPerProbe, int probeOffset ); + void GenerateSuggestionFromTrace( const AILocalMoveGoal_t &goal, + const AIMoveTrace_t &moveTrace, float probeDist, + float arcCenter, float arcSpan, int probeOffset ); + bool GenerateCircleObstacleSuggestions( const AILocalMoveGoal_t &moveGoal, float probeDist ); + + void CalcYawsFromOffset( float yawScanCenter, float spanPerProbe, int probeOffset, + float *pYawTest, float *pYawCenter ); + + float CalculateRegulationWeight( const AIMoveTrace_t &moveTrace, float pctBlockedt ); + float AdjustRegulationWeight( CBaseEntity *pEntity, float weight ); + unsigned ComputeTurnBiasFlags( const AILocalMoveGoal_t &goal, const AIMoveTrace_t &directTrace ); + + + bool RunMoveSolver( const AILocalMoveGoal_t &goal, const AIMoveTrace_t &directTrace, + float degreesPositiveArc, bool fDeterOscillation, + Vector *pResult ); + bool DetectUnsolvable( const AILocalMoveGoal_t &goal ); + + // -------------------------------- + + CAI_BaseNPC * m_pNpc; + + Vector m_PrevTarget; + bool m_fSolvedPrev; + float m_PrevSolution; + Vector m_PrevSolutionVector; + + float m_ClosestHaveBeenToCurrent; + float m_TimeLastProgress; + + bool m_fCannotSolveCurrent; + + CSimTimer m_RefreshSamplesTimer; + + // -------------------------------- + + struct CircleObstacles_t + { + CircleObstacles_t( const Vector ¢er, float radius, CBaseEntity *pEntity, AI_MoveSuggType_t type ) + : center(center), + radius(radius), + hEntity(pEntity), + type(type) + { + } + + Vector center; + float radius; + AI_MoveSuggType_t type; + EHANDLE hEntity; + }; + + CUtlVector m_Obstacles; + + // -------------------------------- + + CAI_MoveSolver m_Solver; +}; + +//------------------------------------- + +inline void CAI_PlaneSolver::Reset() +{ + m_RefreshSamplesTimer.Force(); + + m_fSolvedPrev = false; + m_PrevTarget.Init( FLT_MAX, FLT_MAX, FLT_MAX ), + m_PrevSolution = 0; + m_ClosestHaveBeenToCurrent = FLT_MAX; + m_TimeLastProgress = FLT_MAX; + m_fCannotSolveCurrent = false; +} + +//============================================================================= + +#endif // AI_PLANE_SOLVER_H diff --git a/game/server/ai_playerally.h b/game/server/ai_playerally.h new file mode 100644 index 0000000..bd1e5ab --- /dev/null +++ b/game/server/ai_playerally.h @@ -0,0 +1,481 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_PLAYERALLY_H +#define AI_PLAYERALLY_H + +#include "utlmap.h" +#include "simtimer.h" +#include "AI_Criteria.h" +#include "ai_baseactor.h" +#include "ai_speechfilter.h" +#ifndef _WIN32 +#undef min +#endif +#include "stdstring.h" +#ifndef _WIN32 +#undef MINMAX_H +#include "minmax.h" +#endif + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +#define TLK_ANSWER "TLK_ANSWER" +#define TLK_ANSWER_HELLO "TLK_ANSWER_HELLO" +#define TLK_QUESTION "TLK_QUESTION" +#define TLK_IDLE "TLK_IDLE" +#define TLK_STARE "TLK_STARE" +#define TLK_LOOK "TLK_LOOK" // player looking at player for a second +#define TLK_USE "TLK_USE" +#define TLK_STARTFOLLOW "TLK_STARTFOLLOW" +#define TLK_STOPFOLLOW "TLK_STOPFOLLOW" +#define TLK_JOINPLAYER "TLK_JOINPLAYER" +#define TLK_STOP "TLK_STOP" +#define TLK_NOSHOOT "TLK_NOSHOOT" +#define TLK_HELLO "TLK_HELLO" +#define TLK_PHELLO "TLK_PHELLO" +#define TLK_HELLO_NPC "TLK_HELLO_NPC" +#define TLK_PIDLE "TLK_PIDLE" +#define TLK_PQUESTION "TLK_PQUESTION" +#define TLK_PLHURT1 "TLK_PLHURT1" +#define TLK_PLHURT2 "TLK_PLHURT2" +#define TLK_PLHURT3 "TLK_PLHURT3" +#define TLK_PLHURT "TLK_PLHURT" +#define TLK_PLPUSH "TLK_PLPUSH" +#define TLK_PLRELOAD "TLK_PLRELOAD" +#define TLK_SMELL "TLK_SMELL" +#define TLK_SHOT "TLK_SHOT" +#define TLK_WOUND "TLK_WOUND" +#define TLK_MORTAL "TLK_MORTAL" +#define TLK_DANGER "TLK_DANGER" +#define TLK_SEE_COMBINE "TLK_SEE_COMBINE" +#define TLK_ENEMY_DEAD "TLK_ENEMY_DEAD" +#define TLK_ALYX_ENEMY_DEAD "TLK_ALYX_ENEMY_DEAD" +#define TLK_SELECTED "TLK_SELECTED" // selected by player in command mode. +#define TLK_COMMANDED "TLK_COMMANDED" // received orders from player in command mode +#define TLK_COMMAND_FAILED "TLK_COMMAND_FAILED" +#define TLK_DENY_COMMAND "TLK_DENY_COMMAND" // designer has asked this NPC to politely deny player commands to move the squad +#define TLK_BETRAYED "TLK_BETRAYED" // player killed an ally in front of me. +#define TLK_ALLY_KILLED "TLK_ALLY_KILLED" // witnessed an ally die some other way. +#define TLK_ATTACKING "TLK_ATTACKING" // about to fire my weapon at a target +#define TLK_HEAL "TLK_HEAL" // healing someone +#define TLK_GIVEAMMO "TLK_GIVEAMMO" // giving ammo to someone +#define TLK_DEATH "TLK_DEATH" // Death rattle +#define TLK_HELP_ME "TLK_HELP_ME" // call out to the player for help +#define TLK_PLYR_PHYSATK "TLK_PLYR_PHYSATK" // Player's attacked me with a thrown physics object +#define TLK_NEWWEAPON "TLK_NEWWEAPON" +#define TLK_PLDEAD "TLK_PLDEAD" +#define TLK_HIDEANDRELOAD "TLK_HIDEANDRELOAD" +#define TLK_STARTCOMBAT "TLK_STARTCOMBAT" +#define TLK_WATCHOUT "TLK_WATCHOUT" +#define TLK_MOBBED "TLK_MOBBED" +#define TLK_MANY_ENEMIES "TLK_MANY_ENEMIES" +#define TLK_FLASHLIGHT_ILLUM "TLK_FLASHLIGHT_ILLUM" +#define TLK_FLASHLIGHT_ON "TLK_FLASHLIGHT_ON" // player turned on flashlight +#define TLK_FLASHLIGHT_OFF "TLK_FLASHLIGHT_OFF" // player turned off flashlight +#define TLK_DARKNESS_LOSTPLAYER "TLK_DARKNESS_LOSTPLAYER" +#define TLK_DARKNESS_FOUNDPLAYER "TLK_DARKNESS_FOUNDPLAYER" +#define TLK_DARKNESS_UNKNOWN_WOUND "TLK_DARKNESS_UNKNOWN_WOUND" +#define TLK_DARKNESS_HEARDSOUND "TLK_DARKNESS_HEARDSOUND" +#define TLK_DARKNESS_LOSTENEMY_BY_FLASHLIGHT "TLK_DARKNESS_LOSTENEMY_BY_FLASHLIGHT" +#define TLK_DARKNESS_LOSTENEMY_BY_FLASHLIGHT_EXPIRED "TLK_DARKNESS_LOSTENEMY_BY_FLASHLIGHT_EXPIRED" +#define TLK_DARKNESS_FOUNDENEMY_BY_FLASHLIGHT "TLK_DARKNESS_FOUNDENEMY_BY_FLASHLIGHT" +#define TLK_DARKNESS_FLASHLIGHT_EXPIRED "TLK_DARKNESS_FLASHLIGHT_EXPIRED" // flashlight expired while not in combat +#define TLK_DARKNESS_ENEMY_IN_DARKNESS "TLK_DARKNESS_ENEMY_IN_DARKNESS" // have an enemy, but it's in the darkness +#define TLK_SPOTTED_INCOMING_HEADCRAB "TLK_SPOTTED_INCOMING_HEADCRAB" +#define TLK_CANT_INTERACT_NOW "TLK_CANT_INTERACT_NOW" // to busy to interact with an object the player is holding up to me +#define TLK_ALLY_IN_BARNACLE "TLK_ALLY_IN_BARNACLE" // Barnacle is lifting my buddy! +#define TLK_SELF_IN_BARNACLE "TLK_SELF_IN_BARNACLE" // I was grabbed by a barnacle! +#define TLK_FOUNDPLAYER "TLK_FOUNDPLAYER" +#define TLK_PLAYER_KILLED_NPC "TLK_PLAYER_KILLED_NPC" +#define TLK_ENEMY_BURNING "TLK_ENEMY_BURNING" +#define TLK_SPOTTED_ZOMBIE_WAKEUP "TLK_SPOTTED_ZOMBIE_WAKEUP" +#define TLK_SPOTTED_HEADCRAB_LEAVING_ZOMBIE "TLK_SPOTTED_HEADCRAB_LEAVING_ZOMBIE" +#define TLK_DANGER_ZOMBINE_GRENADE "TLK_DANGER_ZOMBINE_GRENADE" +#define TLK_BALLSOCKETED "TLK_BALLSOCKETED" + +// Vehicle passenger +#define TLK_PASSENGER_WARN_COLLISION "TLK_PASSENGER_WARN_COLLISION" // About to collide with something +#define TLK_PASSENGER_IMPACT "TLK_PASSENGER_IMPACT" // Just hit something +#define TLK_PASSENGER_OVERTURNED "TLK_PASSENGER_OVERTURNED" // Vehicle has just overturned +#define TLK_PASSENGER_REQUEST_UPRIGHT "TLK_PASSENGER_REQUEST_UPRIGHT" // Vehicle needs to be put upright +#define TLK_PASSENGER_ERRATIC_DRIVING "TLK_PASSENGER_ERRATIC_DRIVING" // Vehicle is moving erratically +#define TLK_PASSENGER_VEHICLE_STARTED "TLK_PASSENGER_VEHICLE_STARTED" // Vehicle has started moving +#define TLK_PASSENGER_VEHICLE_STOPPED "TLK_PASSENGER_VEHICLE_STOPPED" // Vehicle has stopped moving +#define TLK_PASSENGER_BEGIN_ENTRANCE "TLK_PASSENGER_BEGIN_ENTRANCE" // Passenger started entering +#define TLK_PASSENGER_FINISH_ENTRANCE "TLK_PASSENGER_FINISH_ENTRANCE" // Passenger finished entering (is in seat) +#define TLK_PASSENGER_BEGIN_EXIT "TLK_PASSENGER_BEGIN_EXIT" // Passenger started exiting +#define TLK_PASSENGER_FINISH_EXIT "TLK_PASSENGER_FINISH_EXIT" // Passenger finished exiting (seat is vacated) +#define TLK_PASSENGER_PLAYER_ENTERED "TLK_PASSENGER_PLAYER_ENTERED" // Player entered the vehicle +#define TLK_PASSENGER_PLAYER_EXITED "TLK_PASSENGER_PLAYER_EXITED" // Player exited the vehicle +#define TLK_PASSENGER_NEW_RADAR_CONTACT "TLK_PASSENGER_NEW_RADAR_CONTACT" // Noticed a brand new contact on the radar +#define TLK_PASSENGER_PUNTED "TLK_PASSENGER_PUNTED" // The player has punted us while we're sitting in the vehicle + +// Vortigaunt +#define TLK_VORTIGAUNT_DISPEL "TLK_VORTIGAUNT_DISPEL" // Dispel attack starting + +// resume is "as I was saying..." or "anyhow..." +#define TLK_RESUME "TLK_RESUME" + +// tourguide stuff below +#define TLK_TGSTAYPUT "TLK_TGSTAYPUT" +#define TLK_TGFIND "TLK_TGFIND" +#define TLK_TGSEEK "TLK_TGSEEK" +#define TLK_TGLOSTYOU "TLK_TGLOSTYOU" +#define TLK_TGCATCHUP "TLK_TGCATCHUP" +#define TLK_TGENDTOUR "TLK_TGENDTOUR" + +//----------------------------------------------------------------------------- + +#define TALKRANGE_MIN 500.0 // don't talk to anyone farther away than this + +//----------------------------------------------------------------------------- + +#define TALKER_STARE_DIST 128 // anyone closer than this and looking at me is probably staring at me. + +#define TALKER_DEFER_IDLE_SPEAK_MIN 10 +#define TALKER_DEFER_IDLE_SPEAK_MAX 20 + +//----------------------------------------------------------------------------- + +class CAI_PlayerAlly; + +//----------------------------------------------------------------------------- +// +// CLASS: CAI_AllySpeechManager +// +//----------------------------------------------------------------------------- + +enum ConceptCategory_t +{ + SPEECH_IDLE, + SPEECH_IMPORTANT, + SPEECH_PRIORITY, + + SPEECH_NUM_CATEGORIES +}; + +struct ConceptCategoryInfo_t +{ + float minGlobalDelay; + float maxGlobalDelay; + float minPersonalDelay; + float maxPersonalDelay; +}; + +enum AIConceptFlags_t +{ + AICF_DEFAULT = 0, + AICF_SPEAK_ONCE = 0x01, + AICF_PROPAGATE_SPOKEN = 0x02, + AICF_TARGET_PLAYER = 0x04, + AICF_QUESTION = 0x08, + AICF_ANSWER = 0x10, +}; + +struct ConceptInfo_t +{ + AIConcept_t concept; + ConceptCategory_t category; + float minGlobalCategoryDelay; + float maxGlobalCategoryDelay; + float minPersonalCategoryDelay; + float maxPersonalCategoryDelay; + float minConceptDelay; + float maxConceptDelay; + int flags; +}; + +//------------------------------------- + +class CAI_AllySpeechManager : public CLogicalEntity +{ + DECLARE_CLASS( CAI_AllySpeechManager, CLogicalEntity ); +public: + CAI_AllySpeechManager(); + ~CAI_AllySpeechManager(); + + void Spawn(); + + void AddCustomConcept( const ConceptInfo_t &conceptInfo ); + ConceptCategoryInfo_t *GetConceptCategoryInfo( ConceptCategory_t category ); + ConceptInfo_t *GetConceptInfo( AIConcept_t concept ); + void OnSpokeConcept( CAI_PlayerAlly *pPlayerAlly, AIConcept_t concept, AI_Response *response ); + + void SetCategoryDelay( ConceptCategory_t category, float minDelay, float maxDelay = 0.0 ); + bool CategoryDelayExpired( ConceptCategory_t category ); + bool ConceptDelayExpired( AIConcept_t concept ); + +private: + + CSimpleSimTimer m_ConceptCategoryTimers[SPEECH_NUM_CATEGORIES]; + + CUtlMap m_ConceptTimers; + + friend CAI_AllySpeechManager *GetAllySpeechManager(); + static CAI_AllySpeechManager *gm_pSpeechManager; + + DECLARE_DATADESC(); +}; + +//------------------------------------- + +CAI_AllySpeechManager *GetAllySpeechManager(); + +//----------------------------------------------------------------------------- +// +// CLASS: CAI_PlayerAlly +// +//----------------------------------------------------------------------------- + +class CAI_AllySpeechManager; + +enum AISpeechTargetSearchFlags_t +{ + AIST_PLAYERS = (1<<0), + AIST_NPCS = (1<<1), + AIST_IGNORE_RELATIONSHIP = (1<<2), + AIST_ANY_QUALIFIED = (1<<3), + AIST_FACING_TARGET = (1<<4), +}; + +struct AISpeechSelection_t +{ + std::string concept; + AI_Response Response; + EHANDLE hSpeechTarget; +}; + +//------------------------------------- + +class CAI_PlayerAlly : public CAI_BaseActor +{ + DECLARE_CLASS( CAI_PlayerAlly, CAI_BaseActor ); + +public: + //--------------------------------- + + int ObjectCaps( void ) { return UsableNPCObjectCaps(BaseClass::ObjectCaps()); } + void TalkInit( void ); + + //--------------------------------- + // Behavior + //--------------------------------- + void GatherConditions( void ); + void GatherEnemyConditions( CBaseEntity *pEnemy ); + void OnStateChange( NPC_STATE OldState, NPC_STATE NewState ); + void PrescheduleThink( void ); + int SelectSchedule( void ); + int SelectNonCombatSpeech( AISpeechSelection_t *pSelection ); + virtual int SelectNonCombatSpeechSchedule(); + int TranslateSchedule( int scheduleType ); + void OnStartSchedule( int scheduleType ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void TaskFail( AI_TaskFailureCode_t ); + void TaskFail( const char *pszGeneralFailText ) { BaseClass::TaskFail( pszGeneralFailText ); } + void ClearTransientConditions(); + void Touch( CBaseEntity *pOther ); + + //--------------------------------- + // Combat + //--------------------------------- + void OnKilledNPC( CBaseCombatCharacter *pKilled ); + + //--------------------------------- + // Damage handling + //--------------------------------- + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + int TakeHealth( float flHealth, int bitsDamageType ); + void Event_Killed( const CTakeDamageInfo &info ); + bool CreateVPhysics(); + + //--------------------------------- + + virtual void PainSound( const CTakeDamageInfo &info ); + + //--------------------------------- + // Speech & Acting + //--------------------------------- + CBaseEntity *EyeLookTarget( void ); // Override to look at talk target + CBaseEntity *FindNamedEntity( const char *pszName, IEntityFindFilter *pFilter = NULL ); + + CBaseEntity *FindSpeechTarget( int flags ); + virtual bool IsValidSpeechTarget( int flags, CBaseEntity *pEntity ); + + CBaseEntity *GetSpeechTarget() { return m_hTalkTarget.Get(); } + void SetSpeechTarget( CBaseEntity *pSpeechTarget ) { m_hTalkTarget = pSpeechTarget; } + + void SetSpeechFilter( CAI_SpeechFilter *pFilter ) { m_hSpeechFilter = pFilter; } + CAI_SpeechFilter *GetSpeechFilter( void ) { return m_hSpeechFilter; } + + //--------------------------------- + + virtual bool SelectIdleSpeech( AISpeechSelection_t *pSelection ); + virtual bool SelectAlertSpeech( AISpeechSelection_t *pSelection ); + + virtual bool SelectInterjection(); + virtual bool SelectPlayerUseSpeech(); + + //--------------------------------- + + virtual bool SelectQuestionAndAnswerSpeech( AISpeechSelection_t *pSelection ); + virtual void PostSpeakDispatchResponse( AIConcept_t concept, AI_Response *response ); + bool SelectQuestionFriend( CBaseEntity *pFriend, AISpeechSelection_t *pSelection ); + bool SelectAnswerFriend( CBaseEntity *pFriend, AISpeechSelection_t *pSelection, bool bRespondingToHello ); + + //--------------------------------- + + bool SelectSpeechResponse( AIConcept_t concept, const char *pszModifiers, CBaseEntity *pTarget, AISpeechSelection_t *pSelection ); + void SetPendingSpeech( AIConcept_t concept, AI_Response &Response ); + void ClearPendingSpeech(); + bool HasPendingSpeech() { return !m_PendingConcept.empty(); } + + //--------------------------------- + + bool CanPlaySentence( bool fDisregardState ); + int PlayScriptedSentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, bool bConcurrent, CBaseEntity *pListener ); + + //--------------------------------- + + void DeferAllIdleSpeech( float flDelay = -1, CAI_BaseNPC *pIgnore = NULL ); + + //--------------------------------- + + bool IsOkToSpeak( ConceptCategory_t category, bool fRespondingToPlayer = false ); + + //--------------------------------- + + bool IsOkToSpeak( void ); + bool IsOkToCombatSpeak( void ); + bool IsOkToSpeakInResponseToPlayer( void ); + + bool ShouldSpeakRandom( AIConcept_t concept, int iChance ); + bool IsAllowedToSpeak( AIConcept_t concept, bool bRespondingToPlayer = false ); + virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 ); + void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + + //--------------------------------- + + float GetTimePlayerStaring() { return ( m_flTimePlayerStartStare != 0 ) ? gpGlobals->curtime - m_flTimePlayerStartStare : 0; } + + //--------------------------------- + // NPC Event Response System + virtual bool CanRespondToEvent( const char *ResponseConcept ); + virtual bool RespondedTo( const char *ResponseConcept, bool bForce, bool bCancelScene ); + + //--------------------------------- + + void OnSpokeConcept( AIConcept_t concept, AI_Response *response ); + void OnStartSpeaking(); + + // Inputs + virtual void InputIdleRespond( inputdata_t &inputdata ) {}; + void InputSpeakResponseConcept( inputdata_t &inputdata ); + virtual bool SpeakMapmakerInterruptConcept( string_t iszConcept ); + + void DisplayDeathMessage( void ); + virtual const char *GetDeathMessageText( void ) { return "GAMEOVER_ALLY"; } + void InputMakeGameEndAlly( inputdata_t &inputdata ); + void InputMakeRegularAlly( inputdata_t &inputdata ); + void InputAnswerQuestion( inputdata_t &inputdata ); + void InputAnswerQuestionHello( inputdata_t &inputdata ); + void InputEnableSpeakWhileScripting( inputdata_t &inputdata ); + void InputDisableSpeakWhileScripting( inputdata_t &inputdata ); + + void AnswerQuestion( CAI_PlayerAlly *pQuestioner, int iQARandomNum, bool bAnsweringHello ); + +protected: + +#ifdef HL2_DLL + // Health regeneration for friendly allies + virtual bool ShouldRegenerateHealth( void ) { return ( Classify() == CLASS_PLAYER_ALLY_VITAL ); } +#endif + + inline bool CanSpeakWhileScripting(); + + // Whether we are a vital ally (useful for wrting Classify() for classes that are only sometimes vital, + // such as the Lone Vort in Ep2.) The usual means by which any other function should determine if a character + // is vital is to determine Classify() == CLASS_PLAYER_ALLY_VITAL. Do not use this function outside that + // context. + inline bool IsGameEndAlly( void ) { return m_bGameEndAlly; } + + //----------------------------------------------------- + // Conditions, Schedules, Tasks + //----------------------------------------------------- + enum + { + SCHED_TALKER_SPEAK_PENDING_IDLE = BaseClass::NEXT_SCHEDULE, + SCHED_TALKER_SPEAK_PENDING_ALERT, + SCHED_TALKER_SPEAK_PENDING_COMBAT, + NEXT_SCHEDULE, + + TASK_TALKER_SPEAK_PENDING = BaseClass::NEXT_TASK, + NEXT_TASK, + + COND_TALKER_CLIENTUNSEEN = BaseClass::NEXT_CONDITION, + COND_TALKER_PLAYER_DEAD, + COND_TALKER_PLAYER_STARING, + NEXT_CONDITION + }; + +private: + void SetCategoryDelay( ConceptCategory_t category, float minDelay, float maxDelay = 0.0 ) { m_ConceptCategoryTimers[category].Set( minDelay, maxDelay ); } + bool CategoryDelayExpired( ConceptCategory_t category ) { return m_ConceptCategoryTimers[category].Expired(); } + + friend class CAI_AllySpeechManager; + + //--------------------------------- + + AI_Response m_PendingResponse; + std::string m_PendingConcept; + float m_TimePendingSet; + + //--------------------------------- + + EHANDLE m_hTalkTarget; // who to look at while talking + float m_flNextRegenTime; + float m_flTimePlayerStartStare; + EHANDLE m_hPotentialSpeechTarget; // NPC to tell the response rules about when trying to find a response to talk to them with + float m_flNextIdleSpeechTime; + int m_iQARandomNumber; + + //--------------------------------- + + CSimpleSimTimer m_ConceptCategoryTimers[3]; + + //--------------------------------- + + CHandle m_hSpeechFilter; + + bool m_bGameEndAlly; + bool m_bCanSpeakWhileScripting; // Allows mapmakers to override NPC_STATE_SCRIPT or IsScripting() for responses. + + float m_flTimeLastRegen; // Last time I regenerated a bit of health. + float m_flHealthAccumulator; // Counterpart to the damage accumulator in CBaseCombatCharacter. So ally health regeneration is accurate over time. + +#ifdef _XBOX +protected: +#endif + DECLARE_DATADESC(); +protected: + DEFINE_CUSTOM_AI; +}; + + +bool CAI_PlayerAlly::CanSpeakWhileScripting() +{ + return m_bCanSpeakWhileScripting; +} + +//----------------------------------------------------------------------------- + +#endif // AI_PLAYERALLY_H diff --git a/game/server/ai_route.h b/game/server/ai_route.h new file mode 100644 index 0000000..9c481f0 --- /dev/null +++ b/game/server/ai_route.h @@ -0,0 +1,190 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_ROUTE_H +#define AI_ROUTE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "mathlib/vector.h" +#include "ai_network.h" +#include "ai_node.h" +#include "ai_waypoint.h" + +struct AI_Waypoint_t; +struct OverlayLine_t; + +class CAI_BaseNPC; + +//============================================================================= +// >> CAI_Path +//============================================================================= + +#define DEF_WAYPOINT_TOLERANCE (0.1) + +class CAI_Path +{ +//----------------------------------------------------------------- + +public: + + void SetWaypoints(AI_Waypoint_t* route, bool fSetGoalFromLast = false) ; + + void PrependWaypoints( AI_Waypoint_t *pWaypoints ); + void PrependWaypoint( const Vector &newPoint, Navigation_t navType, unsigned waypointFlags ); + + bool IsEmpty() const { return m_Waypoints.IsEmpty(); } + + AI_Waypoint_t * GetCurWaypoint() { return m_Waypoints.GetFirst(); } + const AI_Waypoint_t *GetCurWaypoint() const { return m_Waypoints.GetFirst(); } + + AI_Waypoint_t * GetGoalWaypoint() { return m_Waypoints.GetLast(); } + const AI_Waypoint_t *GetGoalWaypoint() const { return m_Waypoints.GetLast(); } + + const Vector & CurWaypointPos() const; + const Vector & NextWaypointPos() const; + float CurWaypointYaw() const; + int CurWaypointFlags() const; + Navigation_t CurWaypointNavType() const; + + AI_Waypoint_t * GetTransitionWaypoint(); + + //--------------------------------- + + float GetPathLength(); + float GetPathDistanceToGoal( const Vector &); + + float GetStartTime() const { return m_routeStartTime; } + + //--------------------------------- + // How close do we need to get to the goal + //--------------------------------- + void SetGoalTolerance(float tolerance) { m_goalTolerance = tolerance; } + float GetGoalTolerance() const { return m_goalTolerance; } + + void SetWaypointTolerance(float tolerance) { m_waypointTolerance = tolerance; } + float GetWaypointTolerance() const { return m_waypointTolerance; } + + //--------------------------------- + // The activity to use during motion + //--------------------------------- + Activity GetMovementActivity() const { return m_activity; } + Activity SetMovementActivity(Activity activity); + int GetMovementSequence() const { return m_sequence; } + int SetMovementSequence(int sequence) { return (m_sequence = sequence); } + + Activity GetArrivalActivity( ) const; + void SetArrivalActivity(Activity activity); + int GetArrivalSequence( ) const; + void SetArrivalSequence(int sequence); + + void SetGoalDirection( const Vector &goalDirection ); + void SetGoalDirection( CBaseEntity *pTarget ); + Vector GetGoalDirection( const Vector &startPos ); + + void SetGoalSpeed( float flSpeed ); + void SetGoalSpeed( CBaseEntity *pTarget ); + float GetGoalSpeed( const Vector &startPos ); + + void SetGoalStoppingDistance( float flDistance ); + float GetGoalStoppingDistance( ) const; + + //--------------------------------- + // Target of this path + //--------------------------------- + void SetTarget(CBaseEntity * pTarget ) { m_target = pTarget; } + void ClearTarget() { m_target = NULL; m_vecTargetOffset = vec3_origin; } + void SetTargetOffset( const Vector &vecOffset) { m_vecTargetOffset = vecOffset; } + CBaseEntity * GetTarget() { return m_target; } + + void SetGoalType(GoalType_t goalType); // Set the goal type + void SetGoalPosition(const Vector &goalPos); // Set the goal position + void SetLastNodeAsGoal(bool bReset = false); // Sets last node as goal and goal position + void ResetGoalPosition(const Vector &goalPos); // Reset the goal position + + // Returns the *base* goal position (without the offset applied) + const Vector& BaseGoalPosition() const; + + // Returns the *actual* goal position (with the offset applied) + const Vector & ActualGoalPosition(void) const; // Get the goal position + + GoalType_t GoalType(void) const; // Get the goal type + + void SetGoalFlags( unsigned flags ) { m_goalFlags = flags; } + unsigned GoalFlags( void ) const; // Get the goal flags + + void Advance( void ); // Advance to next waypoint if possible + + bool CurWaypointIsGoal(void) const; + + void Clear(void); + + CAI_Path(); + ~CAI_Path(); + + //--------------------------------- + + int GetLastNodeReached() { return m_iLastNodeReached; } + void ClearWaypoints() + { + m_Waypoints.RemoveAll(); + m_iLastNodeReached = NO_NODE; + } + +private: + + // Computes the goal distance for each waypoint along the route + static void ComputeRouteGoalDistances(AI_Waypoint_t *pGoalWaypoint); + + //--------------------------------- + CAI_WaypointList m_Waypoints; + + //--------------------------------- + float m_goalTolerance; // How close do we need to get to the goal + Activity m_activity; // The activity to use during motion + int m_sequence; // The sequence to use during motion + EHANDLE m_target; // Target of this path + Vector m_vecTargetOffset; // offset from the target in world space + float m_waypointTolerance; + + //--------------------------------- + Activity m_arrivalActivity; + int m_arrivalSequence; + + //--------------------------------- + int m_iLastNodeReached; // What was the last node that I reached + + bool m_bGoalPosSet; // Was goal position set (used to check for errors) + Vector m_goalPos; // Our ultimate goal position + + bool m_bGoalTypeSet; // Was goal position set (used to check for errors) + GoalType_t m_goalType; // Type of goal + + unsigned m_goalFlags; // Goal flags + + //--------------------------------- + float m_routeStartTime; + + //--------------------------------- + Vector m_goalDirection; + EHANDLE m_goalDirectionTarget; + + float m_goalSpeed; + EHANDLE m_goalSpeedTarget; + + float m_goalStoppingDistance; // Distance we want to stop before the goal + + //--------------------------------- + static AI_Waypoint_t gm_InvalidWaypoint; + + DECLARE_SIMPLE_DATADESC(); + +}; + +#endif // AI_ROUTE_H diff --git a/game/server/ai_routedist.h b/game/server/ai_routedist.h new file mode 100644 index 0000000..4820539 --- /dev/null +++ b/game/server/ai_routedist.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_ROUTEDIST_H +#define AI_ROUTEDIST_H + +#include "ai_navtype.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +// ---------------------------------------------------------------------------- +// Computes the route distance + route direction based on nav type +// FIXME: Where should this go? +// ---------------------------------------------------------------------------- +inline float ComputePathDistance( Navigation_t navType, const Vector &start, const Vector &end ) +{ + if (navType == NAV_GROUND) + { + return (end - start).Length2D(); + } + else + { + return (end - start).Length(); + } +} + +inline void ComputePathVector( Navigation_t navType, const Vector &start, const Vector &end, Vector *pDelta ) +{ + if (navType == NAV_GROUND) + { + Vector2DSubtract( end.AsVector2D(), start.AsVector2D(), pDelta->AsVector2D() ); + pDelta->z = 0.0f; + } + else + { + VectorSubtract( end, start, *pDelta ); + } +} + +inline float ComputePathDirection( Navigation_t navType, const Vector &start, const Vector &end, Vector *pDirection ) +{ + if (navType == NAV_GROUND) + { + VectorSubtract( end, start, *pDirection ); + pDirection->z = 0.0f; + return Vector2DNormalize( pDirection->AsVector2D() ); + } + else + { + VectorSubtract( end, start, *pDirection ); + return VectorNormalize( *pDirection ); + } +} + +#endif // AI_ROUTEDIST_H diff --git a/game/server/ai_saverestore.h b/game/server/ai_saverestore.h new file mode 100644 index 0000000..c2276c5 --- /dev/null +++ b/game/server/ai_saverestore.h @@ -0,0 +1,17 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SAVERESTORE_H +#define AI_SAVERESTORE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +ISaveRestoreBlockHandler *GetAISaveRestoreBlockHandler(); + +#endif // AI_SAVERESTORE_H diff --git a/game/server/ai_schedule.h b/game/server/ai_schedule.h new file mode 100644 index 0000000..2a2d96c --- /dev/null +++ b/game/server/ai_schedule.h @@ -0,0 +1,200 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A schedule +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#include "bitstring.h" + +#ifndef AI_SCHEDULE_H +#define AI_SCHEDULE_H + +#pragma once + +class CStringRegistry; +class CAI_ClassScheduleIdSpace; +class CAI_BaseNPC; + +struct Task_t; + +#ifndef MAX_CONDITIONS +#define MAX_CONDITIONS 32*8 +#endif +typedef CBitVec CAI_ScheduleBits; + +//================================================== +// goalType_t +//================================================== + +enum goalType_t +{ + GOAL_NONE = -1, + GOAL_ENEMY, //Our current enemy's position + GOAL_TARGET, //Our current target's position + GOAL_ENEMY_LKP, //Our current enemy's last known position + GOAL_SAVED_POSITION, //Our saved position +}; + +//================================================== +// pathType_t +//================================================== + +enum pathType_t +{ + PATH_NONE = -1, + PATH_TRAVEL, //Path that will take us to the goal + PATH_LOS, //Path that gives us line of sight to our goal + //PATH_FLANK, //Path that will take us to a flanking position of our goal + //PATH_FLANK_LOS, //Path that will take us to within line of sight to the flanking position of our goal + PATH_COVER, //Path that will give us cover from our goal + //PATH_COVER_LOS, //Path that will give us line of sight to cover from our goal +}; + +//============================================================================= +// >> CAI_Schedule +//============================================================================= + +class CAI_Schedule; + +class CAI_SchedulesManager +{ +public: + CAI_SchedulesManager() + { + allSchedules = NULL; + m_CurLoadSig = 0; // Note when schedules reset + } + + int GetScheduleLoadSignature() { return m_CurLoadSig; } + CAI_Schedule* GetScheduleFromID( int schedID ); // Function to return schedule from linked list + CAI_Schedule* GetScheduleByName( const char *name ); + + bool LoadAllSchedules(void); + + bool LoadSchedules( const char* prefix, CAI_ClassScheduleIdSpace *pIdSpace ); + bool LoadSchedulesFromBuffer( const char *prefix, const char *pfile, CAI_ClassScheduleIdSpace *pIdSpace ); + +private: + friend class CAI_SystemHook; + + int m_CurLoadSig; // Note when schedules reset + CAI_Schedule* allSchedules; // A linked list of all schedules + + CAI_Schedule * CreateSchedule(char *name, int schedule_id); + + void CreateStringRegistries( void ); + void DestroyStringRegistries( void ); + void DeleteAllSchedules(void); + + //static bool LoadSchedules( char* prefix, int taskIDOffset, int taskENOffset, + // int schedIDOffset, int schedENOffset, + // int condIDOffset, int condENOffset); + + // parsing helpers + int GetStateID(const char *state_name); + int GetMemoryID(const char *memory_name); + int GetPathID( const char *token ); + int GetGoalID( const char *token ); + +}; + +extern CAI_SchedulesManager g_AI_SchedulesManager; + +class CAI_Schedule +{ +// --------- +// Static +// --------- +// --------- +public: + int GetId() const + { + return m_iScheduleID; + } + + const Task_t *GetTaskList() const + { + return m_pTaskList; + } + + int NumTasks() const + { + return m_iNumTasks; + } + + void GetInterruptMask( CAI_ScheduleBits *pBits ) const + { + m_InterruptMask.CopyTo( pBits ); + } + + bool HasInterrupt( int condition ) const + { + return m_InterruptMask.IsBitSet( condition ); + } + + const char *GetName() const + { + return m_pName; + } + +private: + friend class CAI_SchedulesManager; + + int m_iScheduleID; // The id number of this schedule + + Task_t *m_pTaskList; + int m_iNumTasks; + + CAI_ScheduleBits m_InterruptMask; // a bit mask of conditions that can interrupt this schedule + char *m_pName; + + CAI_Schedule *nextSchedule; // The next schedule in the list of schedules + + CAI_Schedule(char *name,int schedule_id, CAI_Schedule *pNext); + ~CAI_Schedule( void ); +}; + +//----------------------------------------------------------------------------- +// +// In-memory schedules +// + +#define AI_DEFINE_SCHEDULE( name, text ) \ + const char * g_psz##name = \ + "\n Schedule" \ + "\n " #name \ + text \ + "\n" + + +#define AI_LOAD_SCHEDULE( classname, name ) \ + do \ + { \ + extern const char * g_psz##name; \ + if ( classname::gm_SchedLoadStatus.fValid ) \ + { \ + classname::gm_SchedLoadStatus.fValid = g_AI_SchedulesManager.LoadSchedulesFromBuffer( #classname,(char *)g_psz##name,&classname::gm_ClassScheduleIdSpace ); \ + } \ + } while (false) + + +// For loading default schedules in memory (see ai_default.cpp) +#define AI_LOAD_DEF_SCHEDULE( classname, name ) \ + do \ + { \ + extern const char * g_psz##name; \ + if (!g_AI_SchedulesManager.LoadSchedulesFromBuffer( #classname,(char *)g_psz##name,&classname::gm_ClassScheduleIdSpace )) \ + return false; \ + } while (false) + + +//----------------------------------------------------------------------------- + +#endif // AI_SCHEDULE_H diff --git a/game/server/ai_scriptconditions.h b/game/server/ai_scriptconditions.h new file mode 100644 index 0000000..8162c10 --- /dev/null +++ b/game/server/ai_scriptconditions.h @@ -0,0 +1,256 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SCRIPTCONDITIONS_H +#define AI_SCRIPTCONDITIONS_H + +#include "baseentity.h" +#include "entityoutput.h" +#include "simtimer.h" +#include "ai_npcstate.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +class CAI_ProxTester +{ +public: + CAI_ProxTester() + : m_distSq( 0 ), + m_fInside( false ) + { + } + + void Init( float dist ) + { + m_fInside = ( dist > 0 ); + m_distSq = dist * dist; + } + + bool Check( CBaseEntity *pEntity1, CBaseEntity *pEntity2 ) + { + if ( m_distSq != 0 ) + { + float distSq = ( pEntity1->GetAbsOrigin() - pEntity2->GetAbsOrigin() ).LengthSqr(); + bool fInside = ( distSq < m_distSq ); + + return ( m_fInside == fInside ); + } + return true; + } + + DECLARE_SIMPLE_DATADESC(); + +private: + + float m_distSq; + bool m_fInside; +}; + +//----------------------------------------------------------------------------- +class CAI_ScriptConditionsElement +{ +public: + + DECLARE_SIMPLE_DATADESC(); + + void SetActor( CBaseEntity *pEntity ) { m_hActor = pEntity; } + CBaseEntity *GetActor( void ){ return m_hActor.Get(); } + + void SetTimer( CSimTimer timer ) { m_Timer = timer; } + CSimTimer *GetTimer( void ) { return &m_Timer; } + + void SetTimeOut( CSimTimer timeout) { m_Timeout = timeout; } + CSimTimer *GetTimeOut( void ) { return &m_Timeout; } + +private: + EHANDLE m_hActor; + CSimTimer m_Timer; + CSimTimer m_Timeout; +}; + +//----------------------------------------------------------------------------- +// class CAI_ScriptConditions +// +// Purpose: Watches a set of conditions relative to a given NPC, and when they +// are all satisfied, fires the relevant output +//----------------------------------------------------------------------------- + +class CAI_ScriptConditions : public CBaseEntity, public IEntityListener +{ + DECLARE_CLASS( CAI_ScriptConditions, CBaseEntity ); + +public: + CAI_ScriptConditions() + : m_fDisabled( true ), + m_flRequiredTime( 0 ), + m_fMinState( NPC_STATE_IDLE ), + m_fMaxState( NPC_STATE_IDLE ), + m_fScriptStatus( TRS_NONE ), + m_fActorSeePlayer( TRS_NONE ), + m_flPlayerActorProximity( 0 ), + m_flPlayerActorFOV( -1 ), + m_fPlayerActorLOS( TRS_NONE ), + m_fActorSeeTarget( TRS_NONE ), + m_flActorTargetProximity( 0 ), + m_flPlayerTargetProximity( 0 ), + m_flPlayerTargetFOV( 0 ), + m_fPlayerTargetLOS( TRS_NONE ), + m_fPlayerBlockingActor( TRS_NONE ), + m_flMinTimeout( 0 ), + m_flMaxTimeout( 0 ), + m_fActorInPVS( TRS_NONE ), + m_fActorInVehicle( TRS_NONE ), + m_fPlayerInVehicle( TRS_NONE ) + { +#ifndef HL2_EPISODIC + m_hActor = NULL; +#endif + } + +private: + void Spawn(); + void Activate(); + + void EvaluationThink(); + + void Enable(); + void Disable(); + + void SetThinkTime() { SetNextThink( gpGlobals->curtime + 0.250 ); } + + // Evaluators + struct EvalArgs_t + { + CBaseEntity *pActor; + CBasePlayer *pPlayer; + CBaseEntity *pTarget; + }; + + bool EvalState( const EvalArgs_t &args ); + bool EvalActorSeePlayer( const EvalArgs_t &args ); + bool EvalPlayerActorLook( const EvalArgs_t &args ); + bool EvalPlayerTargetLook( const EvalArgs_t &args ); + bool EvalPlayerActorProximity( const EvalArgs_t &args ); + bool EvalPlayerTargetProximity( const EvalArgs_t &args ); + bool EvalActorTargetProximity( const EvalArgs_t &args ); + bool EvalActorSeeTarget( const EvalArgs_t &args ); + bool EvalPlayerActorLOS( const EvalArgs_t &args ); + bool EvalPlayerTargetLOS( const EvalArgs_t &args ); + bool EvalPlayerBlockingActor( const EvalArgs_t &args ); + bool EvalActorInPVS( const EvalArgs_t &args ); + bool EvalPlayerInVehicle( const EvalArgs_t &args ); + bool EvalActorInVehicle( const EvalArgs_t &args ); + + void OnEntitySpawned( CBaseEntity *pEntity ); + + int AddNewElement( CBaseEntity *pActor ); + + bool ActorInList( CBaseEntity *pActor ); + void UpdateOnRemove( void ); + + // Input handlers + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + // Output handlers + COutputEvent m_OnConditionsSatisfied; + COutputEvent m_OnConditionsTimeout; + COutputEvent m_NoValidActors; + + //--------------------------------- + +#ifndef HL2_EPISODIC + CBaseEntity *GetActor() { return m_hActor.Get(); } +#endif + CBasePlayer *GetPlayer() { return UTIL_GetLocalPlayer(); } + + //--------------------------------- + + // @Note (toml 07-17-02): At some point, it may be desireable to switch to using function objects instead of functions. Probably + // if support for NPCs addiing custom conditions becomes necessary + typedef bool (CAI_ScriptConditions::*EvaluationFunc_t)( const EvalArgs_t &args ); + + struct EvaluatorInfo_t + { + EvaluationFunc_t pfnEvaluator; + const char *pszName; + }; + + static EvaluatorInfo_t gm_Evaluators[]; + + //--------------------------------- + // Evaluation helpers + + static bool IsInFOV( CBaseEntity *pViewer, CBaseEntity *pViewed, float fov, bool bTrueCone ); + static bool PlayerHasLineOfSight( CBaseEntity *pViewer, CBaseEntity *pViewed, bool fNot ); + static bool ActorInPlayersPVS( CBaseEntity *pActor, bool bNot ); + + virtual void OnRestore( void ); + + //--------------------------------- + // General conditions info + + bool m_fDisabled; + bool m_bLeaveAsleep; + EHANDLE m_hTarget; + + float m_flRequiredTime; // How long should the conditions me true + +#ifndef HL2_EPISODIC + EHANDLE m_hActor; + CSimTimer m_Timer; // @TODO (toml 07-16-02): save/load of timer once Jay has save/load of contained objects + CSimTimer m_Timeout; +#endif + + //--------------------------------- + // Specific conditions data + NPC_STATE m_fMinState; + NPC_STATE m_fMaxState; + ThreeState_t m_fScriptStatus; + ThreeState_t m_fActorSeePlayer; + string_t m_Actor; + + float m_flPlayerActorProximity; + CAI_ProxTester m_PlayerActorProxTester; + + float m_flPlayerActorFOV; + bool m_bPlayerActorFOVTrueCone; + ThreeState_t m_fPlayerActorLOS; + ThreeState_t m_fActorSeeTarget; + + float m_flActorTargetProximity; + CAI_ProxTester m_ActorTargetProxTester; + + float m_flPlayerTargetProximity; + CAI_ProxTester m_PlayerTargetProxTester; + + float m_flPlayerTargetFOV; + bool m_bPlayerTargetFOVTrueCone; + ThreeState_t m_fPlayerTargetLOS; + ThreeState_t m_fPlayerBlockingActor; + ThreeState_t m_fActorInPVS; + + float m_flMinTimeout; + float m_flMaxTimeout; + + ThreeState_t m_fActorInVehicle; + ThreeState_t m_fPlayerInVehicle; + + CUtlVector< CAI_ScriptConditionsElement > m_ElementList; + + //--------------------------------- + + DECLARE_DATADESC(); +}; + +//============================================================================= + +#endif // AI_SCRIPTCONDITIONS_H \ No newline at end of file diff --git a/game/server/ai_senses.h b/game/server/ai_senses.h new file mode 100644 index 0000000..fed85eb --- /dev/null +++ b/game/server/ai_senses.h @@ -0,0 +1,169 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SENSES_H +#define AI_SENSES_H + +#include "tier1/utlvector.h" +#include "tier1/utlmap.h" +#include "simtimer.h" +#include "ai_component.h" +#include "soundent.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class CBaseEntity; +class CSound; + +//------------------------------------- + +DECLARE_POINTER_HANDLE( AISightIter_t ); +DECLARE_POINTER_HANDLE( AISoundIter_t ); + +// GetFirstSeenEntity can take these as optional parameters to search for +// a specific type of entity. +enum seentype_t +{ + SEEN_ALL = -1, // Default + SEEN_HIGH_PRIORITY = 0, + SEEN_NPCS, + SEEN_MISC +}; + +#define SENSING_FLAGS_NONE 0x00000000 +#define SENSING_FLAGS_DONT_LOOK 0x00000001 // Effectively makes the NPC blind +#define SENSING_FLAGS_DONT_LISTEN 0x00000002 // Effectively makes the NPC deaf + +//----------------------------------------------------------------------------- +// class CAI_ScriptConditions +// +// Purpose: +//----------------------------------------------------------------------------- + +class CAI_Senses : public CAI_Component +{ +public: + CAI_Senses() + : m_LookDist(2048), + m_LastLookDist(-1), + m_TimeLastLook(-1), + m_iAudibleList(0), + m_TimeLastLookHighPriority( -1 ), + m_TimeLastLookNPCs( -1 ), + m_TimeLastLookMisc( -1 ) + { + m_SeenArrays[0] = &m_SeenHighPriority; + m_SeenArrays[1] = &m_SeenNPCs; + m_SeenArrays[2] = &m_SeenMisc; + m_iSensingFlags = SENSING_FLAGS_NONE; + } + + float GetDistLook() const { return m_LookDist; } + void SetDistLook( float flDistLook ) { m_LookDist = flDistLook; } + + void PerformSensing(); + + void Listen( void ); + void Look( int iDistance );// basic sight function for npcs + + bool ShouldSeeEntity( CBaseEntity *pEntity ); // logical query + bool CanSeeEntity( CBaseEntity *pSightEnt ); // more expensive cone & raycast test +#ifdef PORTAL + bool CanSeeEntityThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pSightEnt ); // more expensive cone & raycast test +#endif + + bool DidSeeEntity( CBaseEntity *pSightEnt ) const; // a less expensive query that looks at cached results from recent conditionsa gathering + + CBaseEntity * GetFirstSeenEntity( AISightIter_t *pIter, seentype_t iSeenType = SEEN_ALL ) const; + CBaseEntity * GetNextSeenEntity( AISightIter_t *pIter ) const; + + CSound * GetFirstHeardSound( AISoundIter_t *pIter ); + CSound * GetNextHeardSound( AISoundIter_t *pIter ); + CSound * GetClosestSound( bool fScent = false, int validTypes = ALL_SOUNDS | ALL_SCENTS, bool bUsePriority = true ); + + bool CanHearSound( CSound *pSound ); + + //--------------------------------- + + float GetTimeLastUpdate( CBaseEntity *pEntity ); + + //--------------------------------- + + void AddSensingFlags( int iFlags ) { m_iSensingFlags |= iFlags; } + void RemoveSensingFlags( int iFlags ) { m_iSensingFlags &= ~iFlags; } + bool HasSensingFlags( int iFlags ) { return (m_iSensingFlags & iFlags) == iFlags; } + + DECLARE_SIMPLE_DATADESC(); + +private: + int GetAudibleList() const { return m_iAudibleList; } + + bool WaitingUntilSeen( CBaseEntity *pSightEnt ); + + void BeginGather(); + void NoteSeenEntity( CBaseEntity *pSightEnt ); + void EndGather( int nSeen, CUtlVector *pResult ); + + bool Look( CBaseEntity *pSightEnt ); +#ifdef PORTAL + bool LookThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pSightEnt ); +#endif + + int LookForHighPriorityEntities( int iDistance ); + int LookForNPCs( int iDistance ); + int LookForObjects( int iDistance ); + + bool SeeEntity( CBaseEntity *pEntity ); + + float m_LookDist; // distance npc sees (Default 2048) + float m_LastLookDist; + float m_TimeLastLook; + + int m_iAudibleList; // first index of a linked list of sounds that the npc can hear. + + CUtlVector m_SeenHighPriority; + CUtlVector m_SeenNPCs; + CUtlVector m_SeenMisc; + + CUtlVector *m_SeenArrays[3]; + + float m_TimeLastLookHighPriority; + float m_TimeLastLookNPCs; + float m_TimeLastLookMisc; + + int m_iSensingFlags; +}; + +//----------------------------------------------------------------------------- + +class CAI_SensedObjectsManager : public IEntityListener +{ +public: + void Init(); + void Term(); + + CBaseEntity * GetFirst( int *pIter ); + CBaseEntity * GetNext( int *pIter ); + + virtual void AddEntity( CBaseEntity *pEntity ); + +private: + virtual void OnEntitySpawned( CBaseEntity *pEntity ); + virtual void OnEntityDeleted( CBaseEntity *pEntity ); + + CUtlVector m_SensedObjects; +}; + +extern CAI_SensedObjectsManager g_AI_SensedObjectsManager; + +//----------------------------------------------------------------------------- + + + +#endif // AI_SENSES_H diff --git a/game/server/ai_sentence.h b/game/server/ai_sentence.h new file mode 100644 index 0000000..8099fce --- /dev/null +++ b/game/server/ai_sentence.h @@ -0,0 +1,172 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SENTENCE_H +#define AI_SENTENCE_H + +#include "ai_component.h" +#include "ai_basenpc.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" + + +//----------------------------------------------------------------------------- +// Sentence helper class used by humanoids sometimes. To use: +// 1) Include it into the leaf class +// 2) Use DEFINE_EMBEDDED to save/load its state +// 3) Call Init in the CreateComponents method +// 4) Use Speak() when it's time to speak +// 5) Add m_Sentences.UpdateSentenceQueue(); to the PrescheduleThink method of an NPC +// to get queued sentence support working +//----------------------------------------------------------------------------- +enum SentenceCriteria_t +{ + SENTENCE_CRITERIA_ALWAYS = 0, + SENTENCE_CRITERIA_NORMAL, // Obeys gag rules + SENTENCE_CRITERIA_IN_SQUAD, + SENTENCE_CRITERIA_SQUAD_LEADER, +}; + +enum SentencePriority_t +{ + SENTENCE_PRIORITY_INVALID = -1, + SENTENCE_PRIORITY_NORMAL = 0, + SENTENCE_PRIORITY_MEDIUM = 1, + SENTENCE_PRIORITY_HIGH = 2, +}; + + +//----------------------------------------------------------------------------- +// This is the met of the class +//----------------------------------------------------------------------------- +abstract_class CAI_SentenceBase : public CAI_Component +{ + DECLARE_CLASS_NOBASE( CAI_SentenceBase ); + DECLARE_SIMPLE_DATADESC(); + +public: + CAI_SentenceBase(); + + void SetVoicePitch( int voicePitch ); + int GetVoicePitch() const; + + // Check for queued-up-sentences + speak them + void UpdateSentenceQueue(); + + // Returns the sentence index played, which can be used to determine + // the sentence length of time using engine->SentenceLength + int Speak( const char *pSentence, SentencePriority_t nSoundPriority = SENTENCE_PRIORITY_NORMAL, SentenceCriteria_t nCriteria = SENTENCE_CRITERIA_IN_SQUAD ); + + // Returns the sentence index played, which can be used to determine + // the sentence length of time using engine->SentenceLength. If the sentence + // was queued, then -1 is returned, which is the same result as if the sound wasn't played + int SpeakQueued( const char *pSentence, SentencePriority_t nSoundPriority = SENTENCE_PRIORITY_NORMAL, SentenceCriteria_t nCriteria = SENTENCE_CRITERIA_IN_SQUAD ); + + // Clears the sentence queue + void ClearQueue(); + +protected: + virtual float GetVolume() = 0; + virtual soundlevel_t GetSoundLevel() = 0; + +private: + // Speech criteria + bool MatchesCriteria( SentenceCriteria_t nCriteria ); + + // Play the actual sentence + int PlaySentence( const char *pSentence ); + + // Debug output + void SentenceMsg( const char *pStatus, const char *pSentence ); + + int m_voicePitch; + int m_nQueuedSentenceIndex; + float m_flQueueTimeout; + int m_nQueueSoundPriority; +}; + + +//----------------------------------------------------------------------------- +// NOTE: This is a template class so each user has a different set of globals +//----------------------------------------------------------------------------- +template< class NPC_CLASS > +class CAI_Sentence : public CAI_SentenceBase +{ + DECLARE_CLASS_NOFRIEND( CAI_Sentence, CAI_SentenceBase ); + +public: + void Init( NPC_CLASS *pOuter, const char *pGameSound ); + +protected: + virtual float GetVolume() { return m_sentenceVolume; } + virtual soundlevel_t GetSoundLevel() { return m_sentenceSoundlevel; } + +private: + static float m_sentenceVolume; + static soundlevel_t m_sentenceSoundlevel; + static int m_voicePitchMin; + static int m_voicePitchMax; +}; + + +//----------------------------------------------------------------------------- +// Voice pitch +//----------------------------------------------------------------------------- +inline void CAI_SentenceBase::SetVoicePitch( int voicePitch ) +{ + m_voicePitch = voicePitch; +} + +inline int CAI_SentenceBase::GetVoicePitch() const +{ + return m_voicePitch; +} + + +//----------------------------------------------------------------------------- +// Set up the class's sentence information +//----------------------------------------------------------------------------- +template< class NPC_CLASS > +void CAI_Sentence< NPC_CLASS >::Init( NPC_CLASS *pOuter, const char *pGameSound ) +{ + SetOuter( pOuter ); + + if ( m_voicePitchMin <= 0 || m_voicePitchMax <= 0 ) + { + // init the sentence parameters using a dummy gamesounds entry + CSoundParameters params; + if ( GetOuter()->GetParametersForSound( pGameSound, params, NULL ) ) + { + m_sentenceVolume = params.volume; + m_sentenceSoundlevel = params.soundlevel; + m_voicePitchMin = params.pitchlow; + m_voicePitchMax = params.pitchhigh; + } + } + + // Select a voice pitch + if ( random->RandomInt(0,1) ) + { + SetVoicePitch( random->RandomInt( m_voicePitchMin, m_voicePitchMax ) ); + } + else + { + SetVoicePitch( 100 ); + } +} + + +//----------------------------------------------------------------------------- +// Global instantiation +//----------------------------------------------------------------------------- +template< class NPC_CLASS > float CAI_Sentence< NPC_CLASS >::m_sentenceVolume = 1.0f; +template< class NPC_CLASS > soundlevel_t CAI_Sentence< NPC_CLASS >::m_sentenceSoundlevel = SNDLVL_NORM; +template< class NPC_CLASS > int CAI_Sentence< NPC_CLASS >::m_voicePitchMin = 0; +template< class NPC_CLASS > int CAI_Sentence< NPC_CLASS >::m_voicePitchMax = 0; + + + +#endif // AI_SENTENCE_H diff --git a/game/server/ai_speech.h b/game/server/ai_speech.h new file mode 100644 index 0000000..fa173c1 --- /dev/null +++ b/game/server/ai_speech.h @@ -0,0 +1,401 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SPEECH_H +#define AI_SPEECH_H + +#include "utlmap.h" + +#include "soundflags.h" +#include "AI_ResponseSystem.h" +#include "utldict.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class KeyValues; +class AI_CriteriaSet; + +//----------------------------------------------------------------------------- +// Purpose: Used to share a global resource or prevent a system stepping on +// own toes. +//----------------------------------------------------------------------------- + +class CAI_TimedSemaphore +{ +public: + CAI_TimedSemaphore() + : m_ReleaseTime( 0 ) + { + m_hCurrentTalker = NULL; + } + + void Acquire( float time, CBaseEntity *pTalker ) { m_ReleaseTime = gpGlobals->curtime + time; m_hCurrentTalker = pTalker; } + void Release() { m_ReleaseTime = 0; m_hCurrentTalker = NULL; } + + // Current owner of the semaphore is always allowed to talk + bool IsAvailable( CBaseEntity *pTalker ) const { return ((gpGlobals->curtime > m_ReleaseTime) || (m_hCurrentTalker == pTalker)); } + float GetReleaseTime() const { return m_ReleaseTime; } + + CBaseEntity *GetOwner() { return m_hCurrentTalker; } + +private: + float m_ReleaseTime; + EHANDLE m_hCurrentTalker; +}; + +//----------------------------------------------------------------------------- + +extern CAI_TimedSemaphore g_AIFriendliesTalkSemaphore; +extern CAI_TimedSemaphore g_AIFoesTalkSemaphore; + +#define GetSpeechSemaphore( pNpc ) (((pNpc)->IsPlayerAlly()) ? &g_AIFriendliesTalkSemaphore : &g_AIFoesTalkSemaphore ) +//----------------------------------------------------------------------------- +// Basic speech system types +//----------------------------------------------------------------------------- + +//------------------------------------- +// Constants + + +const float AIS_DEF_MIN_DELAY = 2.8; // Minimum amount of time an NPCs will wait after someone has spoken before considering speaking again +const float AIS_DEF_MAX_DELAY = 3.2; // Maximum amount of time an NPCs will wait after someone has spoken before considering speaking again +const float AIS_NO_DELAY = 0; +const soundlevel_t AIS_DEF_SNDLVL = SNDLVL_TALKING; +#define AI_NULL_CONCEPT NULL + +#define AI_NULL_SENTENCE NULL + +// Sentence prefix constants +#define AI_SP_SPECIFIC_SENTENCE '!' +#define AI_SP_WAVFILE '^' +#define AI_SP_SCENE_GROUP '=' +#define AI_SP_SPECIFIC_SCENE '?' + +#define AI_SPECIFIC_SENTENCE(str_constant) "!" str_constant +#define AI_WAVFILE(str_constant) "^" str_constant +// @Note (toml 09-12-02): as scene groups are not currently implemented, the string is a semi-colon delimited list +#define AI_SCENE_GROUP(str_constant) "=" str_constant +#define AI_SPECIFIC_SCENE(str_constant) "?" str_constant + +// Designer overriding modifiers +#define AI_SPECIFIC_SCENE_MODIFIER "scene:" + +//------------------------------------- + +//------------------------------------- +// An id that represents the core meaning of a spoken phrase, +// eventually to be mapped to a sentence group or scene + +typedef const char *AIConcept_t; + +inline bool CompareConcepts( AIConcept_t c1, AIConcept_t c2 ) +{ + return ( (void *)c1 == (void *)c2 || ( c1 && c2 && Q_stricmp( c1, c2 ) == 0 ) ); +} + +//------------------------------------- +// Specifies and stores the base timing and attentuation values for concepts +// +class AI_Response; + +//----------------------------------------------------------------------------- +// CAI_Expresser +// +// Purpose: Provides the functionality of going from abstract concept ("hello") +// to specific sentence/scene/wave +// + +//------------------------------------- +// Sink supports behavior control and receives notifications of internal events + +class CAI_ExpresserSink +{ +public: + virtual void OnSpokeConcept( AIConcept_t concept, AI_Response *response ) {}; + virtual void OnStartSpeaking() {} + virtual bool UseSemaphore() { return true; } +}; + +struct ConceptHistory_t +{ + DECLARE_SIMPLE_DATADESC(); + + ConceptHistory_t(float timeSpoken = -1 ) + : timeSpoken( timeSpoken ), response( NULL ) + { + } + + ConceptHistory_t( const ConceptHistory_t& src ); + ConceptHistory_t& operator = ( const ConceptHistory_t& src ); + + ~ConceptHistory_t(); + + float timeSpoken; + AI_Response *response; +}; +//------------------------------------- + +class CAI_Expresser : public IResponseFilter +{ +public: + CAI_Expresser( CBaseFlex *pOuter = NULL ); + ~CAI_Expresser(); + + // -------------------------------- + + bool Connect( CAI_ExpresserSink *pSink ) { m_pSink = pSink; return true; } + bool Disconnect( CAI_ExpresserSink *pSink ) { m_pSink = NULL; return true;} + + void TestAllResponses(); + + // -------------------------------- + + bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + + // These two methods allow looking up a response and dispatching it to be two different steps + bool SpeakFindResponse( AI_Response &response, AIConcept_t concept, const char *modifiers = NULL ); + bool SpeakDispatchResponse( AIConcept_t concept, AI_Response &response, IRecipientFilter *filter = NULL ); + float GetResponseDuration( AI_Response &response ); + + virtual int SpeakRawSentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL ); + + bool SemaphoreIsAvailable( CBaseEntity *pTalker ); + float GetSemaphoreAvailableTime( CBaseEntity *pTalker ); + + // -------------------------------- + + virtual bool IsSpeaking(); + bool CanSpeak(); + bool CanSpeakAfterMyself(); + float GetTimeSpeechComplete() const { return m_flStopTalkTime; } + void BlockSpeechUntil( float time ); + + // -------------------------------- + + bool CanSpeakConcept( AIConcept_t concept ); + bool SpokeConcept( AIConcept_t concept ); + float GetTimeSpokeConcept( AIConcept_t concept ); // returns -1 if never + void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ); + void ClearSpokeConcept( AIConcept_t concept ); + + // -------------------------------- + + void SetVoicePitch( int voicePitch ) { m_voicePitch = voicePitch; } + int GetVoicePitch() const; + + void NoteSpeaking( float duration, float delay = 0 ); + + // Force the NPC to release the semaphore & clear next speech time + void ForceNotSpeaking( void ); + +protected: + CAI_TimedSemaphore *GetMySpeechSemaphore( CBaseEntity *pNpc ); + + bool SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter = NULL ); + // This will create a fake .vcd/CChoreoScene to wrap the sound to be played + bool SpeakAutoGeneratedScene( char const *soundname, float delay ); + + void DumpHistories(); + + void SpeechMsg( CBaseEntity *pFlex, PRINTF_FORMAT_STRING const char *pszFormat, ... ); + + // -------------------------------- + + CAI_ExpresserSink *GetSink() { return m_pSink; } + +private: + // -------------------------------- + + virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ); + + // -------------------------------- + + CAI_ExpresserSink *m_pSink; + + // -------------------------------- + // + // Speech concept data structures + // + + CUtlDict< ConceptHistory_t, int > m_ConceptHistories; + + // -------------------------------- + // + // Speaking states + // + + float m_flStopTalkTime; // when in the future that I'll be done saying this sentence. + float m_flStopTalkTimeWithoutDelay; // same as the above, but minus the delay before other people can speak + float m_flBlockedTalkTime; + int m_voicePitch; // pitch of voice for this head + float m_flLastTimeAcceptedSpeak; // because speech may not be blocked until NoteSpeaking called by scene ent, this handles in-think blocking + + DECLARE_SIMPLE_DATADESC(); + + // -------------------------------- + // +public: + virtual void SetOuter( CBaseFlex *pOuter ) { m_pOuter = pOuter; } + + CBaseFlex * GetOuter() { return m_pOuter; } + const CBaseFlex * GetOuter() const { return m_pOuter; } + +private: + CHandle m_pOuter; +}; + +class CMultiplayer_Expresser : public CAI_Expresser +{ +public: + CMultiplayer_Expresser( CBaseFlex *pOuter = NULL ); + //~CMultiplayer_Expresser(); + + virtual bool IsSpeaking(); + + void AllowMultipleScenes(); + void DisallowMultipleScenes(); + +private: + bool m_bAllowMultipleScenes; + +}; + +//----------------------------------------------------------------------------- +// +// An NPC base class to assist a branch of the inheritance graph +// in utilizing CAI_Expresser +// + +template +class CAI_ExpresserHost : public BASE_NPC, protected CAI_ExpresserSink +{ + DECLARE_CLASS_NOFRIEND( CAI_ExpresserHost, BASE_NPC ); + +public: + virtual void NoteSpeaking( float duration, float delay ); + + virtual bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + + // These two methods allow looking up a response and dispatching it to be two different steps + bool SpeakFindResponse( AI_Response& response, AIConcept_t concept, const char *modifiers = NULL ); + bool SpeakDispatchResponse( AIConcept_t concept, AI_Response& response ); + virtual void PostSpeakDispatchResponse( AIConcept_t concept, AI_Response& response ) { return; } + float GetResponseDuration( AI_Response& response ); + + float GetTimeSpeechComplete() const { return this->GetExpresser()->GetTimeSpeechComplete(); } + + bool IsSpeaking() { return this->GetExpresser()->IsSpeaking(); } + bool CanSpeak() { return this->GetExpresser()->CanSpeak(); } + bool CanSpeakAfterMyself() { return this->GetExpresser()->CanSpeakAfterMyself(); } + + void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ) { this->GetExpresser()->SetSpokeConcept( concept, response, bCallback ); } + float GetTimeSpokeConcept( AIConcept_t concept ) { return this->GetExpresser()->GetTimeSpokeConcept( concept ); } + bool SpokeConcept( AIConcept_t concept ) { return this->GetExpresser()->SpokeConcept( concept ); } + +protected: + int PlaySentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL ); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + + virtual IResponseSystem *GetResponseSystem(); + // Override of base entity response input handler + virtual void DispatchResponse( const char *conceptName ); +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CAI_ExpresserHost::NoteSpeaking( float duration, float delay ) +{ + this->GetExpresser()->NoteSpeaking( duration, delay ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::Speak( AIConcept_t concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /*=NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +{ + AssertOnce( this->GetExpresser()->GetOuter() == this ); + return this->GetExpresser()->Speak( concept, modifiers, pszOutResponseChosen, bufsize, filter ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline int CAI_ExpresserHost::PlaySentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, CBaseEntity *pListener ) +{ + return this->GetExpresser()->SpeakRawSentence( pszSentence, delay, volume, soundlevel, pListener ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +extern void CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( CAI_BaseNPC *pSpeaker, AI_CriteriaSet& criteriaSet ); + +template +inline void CAI_ExpresserHost::ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ) +{ + BaseClass::ModifyOrAppendCriteria( criteriaSet ); + + if ( this->MyNPCPointer() ) + { + CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( this->MyNPCPointer(), criteriaSet ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline IResponseSystem *CAI_ExpresserHost::GetResponseSystem() +{ + extern IResponseSystem *g_pResponseSystem; + // Expressive NPC's use the general response system + return g_pResponseSystem; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::SpeakFindResponse( AI_Response& response, AIConcept_t concept, const char *modifiers /*= NULL*/ ) +{ + return this->GetExpresser()->SpeakFindResponse( response, concept, modifiers ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::SpeakDispatchResponse( AIConcept_t concept, AI_Response& response ) +{ + if ( this->GetExpresser()->SpeakDispatchResponse( concept, response ) ) + { + PostSpeakDispatchResponse( concept, response ); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline float CAI_ExpresserHost::GetResponseDuration( AI_Response& response ) +{ + return this->GetExpresser()->GetResponseDuration( response ); +} + +//----------------------------------------------------------------------------- +// Override of base entity response input handler +//----------------------------------------------------------------------------- +template +inline void CAI_ExpresserHost::DispatchResponse( const char *conceptName ) + { + Speak( (AIConcept_t)conceptName ); + } + +//----------------------------------------------------------------------------- + +#endif // AI_SPEECH_H diff --git a/game/server/ai_speechfilter.h b/game/server/ai_speechfilter.h new file mode 100644 index 0000000..023a2aa --- /dev/null +++ b/game/server/ai_speechfilter.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_SPEECHFILTER_H +#define AI_SPEECHFILTER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAI_SpeechFilter : public CBaseEntity, public IEntityListener +{ + DECLARE_CLASS( CAI_SpeechFilter, CBaseEntity ); +public: + DECLARE_DATADESC(); + + void Spawn( void ); + void Activate( void ); + void UpdateOnRemove( void ); + + void Enable( bool bEnable ); + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputSetIdleModifier( inputdata_t &inputdata ); + + void PopulateSubjectList( bool purge = false ); + + + // Accessors for our NPC + float GetIdleModifier( void ) { return m_flIdleModifier; } + bool NeverSayHello( void ) { return m_bNeverSayHello; } + + void OnEntityCreated( CBaseEntity *pEntity ); + void OnEntityDeleted( CBaseEntity *pEntity ); + +protected: + string_t m_iszSubject; + float m_flIdleModifier; // Multiplier to the percentage chance that our NPC will idle speak + bool m_bNeverSayHello; // If set, the NPC never says hello to the player + bool m_bDisabled; +}; + +#endif // AI_SPEECHFILTER_H diff --git a/game/server/ai_squad.h b/game/server/ai_squad.h new file mode 100644 index 0000000..846e9a1 --- /dev/null +++ b/game/server/ai_squad.h @@ -0,0 +1,276 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Squad classes +// +//=============================================================================// + +#ifndef AI_SQUAD_H +#define AI_SQUAD_H + +#include "ai_memory.h" +#include "ai_squadslot.h" +#include "bitstring.h" + +class CAI_Squad; +typedef CHandle AIHANDLE; + +#define PER_ENEMY_SQUADSLOTS 1 + + +//----------------------------------------------------------------------------- + +DECLARE_POINTER_HANDLE(AISquadsIter_t); +DECLARE_POINTER_HANDLE(AISquadIter_t); + +#define MAX_SQUAD_MEMBERS 16 +#define MAX_SQUAD_DATA_SLOTS 4 + +//----------------------------------------------------------------------------- +// CAI_SquadManager +// +// Purpose: Manages all the squads in the system +// +//----------------------------------------------------------------------------- + +class CAI_SquadManager +{ +public: + CAI_SquadManager() + { + m_pSquads = NULL; + } + + CAI_Squad * GetFirstSquad( AISquadsIter_t *pIter ); + CAI_Squad * GetNextSquad( AISquadsIter_t *pIter ); + int NumSquads(); + + CAI_Squad * FindSquad( string_t squadName ); // Returns squad of the given name + CAI_Squad * CreateSquad( string_t squadName ); // Returns squad of the given name + CAI_Squad * FindCreateSquad( string_t squadName ); // Returns squad of the given name + CAI_Squad * FindCreateSquad( CAI_BaseNPC *pNPC, string_t squadName ); // Returns squad of the given name + + void DeleteSquad( CAI_Squad *pSquad ); + void DeleteAllSquads(void); + +private: + + CAI_Squad * m_pSquads; // A linked list of all squads + +}; + +//------------------------------------- + +extern CAI_SquadManager g_AI_SquadManager; + +//----------------------------------------------------------------------------- + +#ifdef PER_ENEMY_SQUADSLOTS + +struct AISquadEnemyInfo_t +{ + EHANDLE hEnemy; + CBitVec slots; // What squad slots are filled? + + DECLARE_SIMPLE_DATADESC(); +}; + +#endif + +//----------------------------------------------------------------------------- +// CAI_Squad +// +// Purpose: Tracks enemies, squad slots, squad members +// +//----------------------------------------------------------------------------- + +class CAI_Squad +{ +public: + + const char * GetName() const { return STRING(m_Name); } + + void RemoveFromSquad( CAI_BaseNPC *pNPC, bool bDeath = false ); + + CAI_BaseNPC * GetFirstMember( AISquadIter_t *pIter = NULL, bool bIgnoreSilentMembers = true ); + CAI_BaseNPC * GetNextMember( AISquadIter_t *pIter, bool bIgnoreSilentMembers = true ); + CAI_BaseNPC * GetAnyMember(); + int NumMembers( bool bIgnoreSilentMembers = true ); + int GetSquadIndex( CAI_BaseNPC * ); + + void SquadNewEnemy ( CBaseEntity *pEnemy ); + void UpdateEnemyMemory( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy, const Vector &position ); + + bool OccupyStrategySlotRange( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd, int *pSlot ); + void VacateStrategySlot( CBaseEntity *pEnemy, int slot); + bool IsStrategySlotRangeOccupied( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd ); + + CAI_BaseNPC * SquadMemberInRange( const Vector &vecLocation, float flDist ); + CAI_BaseNPC * NearestSquadMember( CAI_BaseNPC *pMember ); + int GetVisibleSquadMembers( CAI_BaseNPC *pMember ); + CAI_BaseNPC * GetSquadMemberNearestTo( const Vector &vecLocation ); + bool SquadIsMember( CBaseEntity *pMember ); + bool IsLeader( CAI_BaseNPC *pLeader ); + CAI_BaseNPC *GetLeader( void ); + + int BroadcastInteraction( int interactionType, void *data, CBaseCombatCharacter *sender = NULL ); + + void AddToSquad(CAI_BaseNPC *pNPC); + bool FOkToMakeSound( int soundPriority ); + void JustMadeSound( int soundPriority, float time ); + float GetSquadSoundWaitTime() const { return m_flSquadSoundWaitTime; } + void SetSquadSoundWaitTime( float time ) { m_flSquadSoundWaitTime = time; } + void SquadRemember( int iMemory ); + + void SetSquadInflictor( CBaseEntity *pInflictor ); + bool IsSquadInflictor( CBaseEntity *pInflictor ); + + static bool IsSilentMember( const CAI_BaseNPC *pNPC ); + + template + void SetSquadData( unsigned slot, const T &data ) + { + Assert( slot < MAX_SQUAD_DATA_SLOTS ); + if ( slot < MAX_SQUAD_DATA_SLOTS ) + { + m_SquadData[slot] = *((int *)&data); + } + } + + template + void GetSquadData( unsigned slot, T *pData ) + { + Assert( slot < MAX_SQUAD_DATA_SLOTS ); + if ( slot < MAX_SQUAD_DATA_SLOTS ) + { + *pData = *((T *)&m_SquadData[slot]); + } + } + + +private: + void OccupySlot( CBaseEntity *pEnemy, int i ); + void VacateSlot( CBaseEntity *pEnemy, int i ); + bool IsSlotOccupied( CBaseEntity *pEnemy, int i ) const; + +private: + friend class CAI_SaveRestoreBlockHandler; + friend class CAI_SquadManager; + + CAI_Squad(); + CAI_Squad(string_t squadName); + ~CAI_Squad(void); + + CAI_Squad* GetNext() { return m_pNextSquad; } + + void Init( string_t squadName ); + + CAI_Squad * m_pNextSquad; // The next squad is list of all squads + + string_t m_Name; + CUtlVectorFixed m_SquadMembers; + + float m_flSquadSoundWaitTime; // Time when I'm allowed to make another sound + int m_nSquadSoundPriority; // if we're still waiting, this is the priority of the current sound + + EHANDLE m_hSquadInflictor; + + int m_SquadData[MAX_SQUAD_DATA_SLOTS]; + +#ifdef PER_ENEMY_SQUADSLOTS + + AISquadEnemyInfo_t *FindEnemyInfo( CBaseEntity *pEnemy ); + const AISquadEnemyInfo_t *FindEnemyInfo( CBaseEntity *pEnemy ) const { return const_cast(this)->FindEnemyInfo( pEnemy ); } + + AISquadEnemyInfo_t * m_pLastFoundEnemyInfo; // Occupy/Vacate need to be reworked to not want this + + CUtlVector m_EnemyInfos; + float m_flEnemyInfoCleanupTime; + +#else + + CVarBitVec m_squadSlotsUsed; // What squad slots are filled? + +#endif + + //--------------------------------- +public: + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// +// Purpose: CAI_SquadManager inline functions +// +//----------------------------------------------------------------------------- + +inline CAI_Squad *CAI_SquadManager::GetFirstSquad( AISquadsIter_t *pIter ) +{ + *pIter = (AISquadsIter_t)m_pSquads; + return m_pSquads; +} + +//------------------------------------- + +inline CAI_Squad *CAI_SquadManager::GetNextSquad( AISquadsIter_t *pIter ) +{ + CAI_Squad *pSquad = (CAI_Squad *)*pIter; + if ( pSquad ) + pSquad = pSquad->m_pNextSquad; + *pIter = (AISquadsIter_t)pSquad; + return pSquad; +} + +//------------------------------------- +// Purpose: Returns squad of the given name or creates a new squad with the +// given name if none exists and add pNPC to the list of members +//------------------------------------- + +inline CAI_Squad *CAI_SquadManager::FindCreateSquad(CAI_BaseNPC *pNPC, string_t squadName) +{ + CAI_Squad* pSquad = FindSquad( squadName ); + + if ( !pSquad ) + pSquad = CreateSquad( squadName ); + + pSquad->AddToSquad( pNPC ); + + return pSquad; +} + +//----------------------------------------------------------------------------- + +inline CAI_Squad *CAI_SquadManager::FindCreateSquad(string_t squadName) +{ + CAI_Squad* pSquad = FindSquad( squadName ); + + if ( !pSquad ) + pSquad = CreateSquad( squadName ); + + return pSquad; +} + +//------------------------------------- + +inline CAI_BaseNPC *CAI_Squad::GetAnyMember() +{ + if ( m_SquadMembers.Count() ) + return m_SquadMembers[random->RandomInt( 0, m_SquadMembers.Count()-1 )]; + return NULL; +} + +//------------------------------------- + +inline int CAI_Squad::GetSquadIndex( CAI_BaseNPC *pAI ) +{ + for ( int i = 0; i < m_SquadMembers.Count(); i++ ) + { + if ( m_SquadMembers[i] == pAI ) + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- + +#endif // AI_SQUAD_H diff --git a/game/server/ai_squadslot.h b/game/server/ai_squadslot.h new file mode 100644 index 0000000..53e43a3 --- /dev/null +++ b/game/server/ai_squadslot.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The default shared conditions +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SQUADSLOT_H +#define SQUADSLOT_H + +#define MAX_SQUADSLOTS 32 + +//========================================================= +// These are the default shared squad slots +// +// NOTE: If you add a new squad slot here, make sure you +// update GetSquadSlotDebugName() +//========================================================= +enum SQUAD_SLOT_t { + + // Currently there are no shared squad slots + SQUAD_SLOT_NONE = -1, + + SQUAD_SLOT_ATTACK1 = 0, // reserve 2 attack slots for most squads + SQUAD_SLOT_ATTACK2, + + SQUAD_SLOT_INVESTIGATE_SOUND, + + SQUAD_SLOT_EXCLUSIVE_HANDSIGN, // only one person in a squad should do this! + SQUAD_SLOT_EXCLUSIVE_RELOAD, + + SQUAD_SLOT_PICKUP_WEAPON1, + SQUAD_SLOT_PICKUP_WEAPON2, + + SQUAD_SLOT_SPECIAL_ATTACK, // Combine Elite using the combine ball attack, for instance. + + // ====================================== + // IMPORTANT: This must be the last enum + // ====================================== + LAST_SHARED_SQUADSLOT, +}; + + +#endif //SQUADSLOT_H diff --git a/game/server/ai_tacticalservices.h b/game/server/ai_tacticalservices.h new file mode 100644 index 0000000..4ed844f --- /dev/null +++ b/game/server/ai_tacticalservices.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//============================================================================= + +#ifndef AI_TACTICALSERVICES_H +#define AI_TACTICALSERVICES_H + +#include "ai_component.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class CAI_Network; +class CAI_Pathfinder; + + +enum FlankType_t +{ + FLANKTYPE_NONE = 0, + FLANKTYPE_ARC, // Stay flFlankParam degrees of arc away from vecFlankRefPos + FLANKTYPE_RADIUS, // Stay flFlankParam units away from vecFlankRefPos +}; + + +//----------------------------------------------------------------------------- + +class CAI_TacticalServices : public CAI_Component +{ +public: + CAI_TacticalServices( CAI_BaseNPC *pOuter ) + : CAI_Component(pOuter), + m_pNetwork( NULL ) + { + m_bAllowFindLateralLos = true; + } + + void Init( CAI_Network *pNetwork ); + + bool FindLos( const Vector &threatPos, const Vector &threatEyePos, float minThreatDist, float maxThreatDist, float blockTime, Vector *pResult ); + bool FindLos( const Vector &threatPos, const Vector &threatEyePos, float minThreatDist, float maxThreatDist, float blockTime, FlankType_t eFlankType, const Vector &VecFlankRefPos, float flFlankParam, Vector *pResult ); + bool FindLateralLos( const Vector &threatPos, Vector *pResult ); + bool FindBackAwayPos( const Vector &vecThreat, Vector *pResult ); + bool FindCoverPos( const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinDist, float flMaxDist, Vector *pResult ); + bool FindCoverPos( const Vector &vNearPos, const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinDist, float flMaxDist, Vector *pResult ); + bool FindLateralCover( const Vector &vecThreat, float flMinDist, Vector *pResult ); + bool FindLateralCover( const Vector &vecThreat, float flMinDist, float distToCheck, int numChecksPerDir, Vector *pResult ); + bool FindLateralCover( const Vector &vNearPos, const Vector &vecThreat, float flMinDist, float distToCheck, int numChecksPerDir, Vector *pResult ); + + void AllowFindLateralLos( bool bAllow ) { m_bAllowFindLateralLos = bAllow; } + +private: + // Checks lateral cover + bool TestLateralCover( const Vector &vecCheckStart, const Vector &vecCheckEnd, float flMinDist ); + bool TestLateralLos( const Vector &vecCheckStart, const Vector &vecCheckEnd ); + + int FindBackAwayNode( const Vector &vecThreat ); + int FindCoverNode( const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinDist, float flMaxDist ); + int FindCoverNode( const Vector &vNearPos, const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinDist, float flMaxDist ); + int FindLosNode( const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinThreatDist, float flMaxThreatDist, float flBlockTime, FlankType_t eFlankType, const Vector &vThreatFacing, float flFlankParam ); + + Vector GetNodePos( int ); + + CAI_Network *GetNetwork() { return m_pNetwork; } + const CAI_Network *GetNetwork() const { return m_pNetwork; } + + CAI_Pathfinder *GetPathfinder() { return m_pPathfinder; } + const CAI_Pathfinder *GetPathfinder() const { return m_pPathfinder; } + + CAI_Network *m_pNetwork; + CAI_Pathfinder *m_pPathfinder; + + bool m_bAllowFindLateralLos; // Allows us to turn Lateral LOS checking on/off. + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- + +#endif // AI_TACTICALSERVICES_H diff --git a/game/server/ai_task.h b/game/server/ai_task.h new file mode 100644 index 0000000..43170a3 --- /dev/null +++ b/game/server/ai_task.h @@ -0,0 +1,504 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the tasks for default AI. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_TASK_H +#define AI_TASK_H +#ifdef _WIN32 +#pragma once +#endif + +class CStringRegistry; + +// ---------------------------------------------------------------------- +// Failure messages +// +// UNDONE: do this diffently so when not in developer mode we can +// not use any memory for these text strings +// ---------------------------------------------------------------------- + +// Codes are either one of the enumerated types below, or a string (similar to Windows resource IDs) +typedef int AI_TaskFailureCode_t; + +enum AI_BaseTaskFailureCodes_t +{ + NO_TASK_FAILURE, + FAIL_NO_TARGET, + FAIL_WEAPON_OWNED, + FAIL_ITEM_NO_FIND, + FAIL_NO_HINT_NODE, + FAIL_SCHEDULE_NOT_FOUND, + FAIL_NO_ENEMY, + FAIL_NO_BACKAWAY_NODE, + FAIL_NO_COVER, + FAIL_NO_FLANK, + FAIL_NO_SHOOT, + FAIL_NO_ROUTE, + FAIL_NO_ROUTE_GOAL, + FAIL_NO_ROUTE_BLOCKED, + FAIL_NO_ROUTE_ILLEGAL, + FAIL_NO_WALK, + FAIL_ALREADY_LOCKED, + FAIL_NO_SOUND, + FAIL_NO_SCENT, + FAIL_BAD_ACTIVITY, + FAIL_NO_GOAL, + FAIL_NO_PLAYER, + FAIL_NO_REACHABLE_NODE, + FAIL_NO_AI_NETWORK, + FAIL_BAD_POSITION, + FAIL_BAD_PATH_GOAL, + FAIL_STUCK_ONTOP, + FAIL_ITEM_TAKEN, + + NUM_FAIL_CODES, +}; + +inline bool IsPathTaskFailure( AI_TaskFailureCode_t code ) +{ + return ( code >= FAIL_NO_ROUTE && code <= FAIL_NO_ROUTE_ILLEGAL ); +} + +const char *TaskFailureToString( AI_TaskFailureCode_t code ); +inline int MakeFailCode( const char *pszGeneralError ) { return (int)pszGeneralError; } + + +enum TaskStatus_e +{ + TASKSTATUS_NEW = 0, // Just started + TASKSTATUS_RUN_MOVE_AND_TASK = 1, // Running task & movement + TASKSTATUS_RUN_MOVE = 2, // Just running movement + TASKSTATUS_RUN_TASK = 3, // Just running task + TASKSTATUS_COMPLETE = 4, // Completed, get next task +}; + +// an array of tasks is a task list +// an array of schedules is a schedule list +struct Task_t +{ + int iTask; + float flTaskData; +}; + +//========================================================= +// These are the shared tasks +//========================================================= +enum sharedtasks_e +{ + TASK_INVALID = 0, + + // Forces the activity to reset. + TASK_RESET_ACTIVITY, + + // Waits for the specified number of seconds. + TASK_WAIT, + + // Make announce attack sound + TASK_ANNOUNCE_ATTACK, + + // Waits for the specified number of seconds. Will constantly turn to + // face the enemy while waiting. + TASK_WAIT_FACE_ENEMY, + + // Waits up to the specified number of seconds. Will constantly turn to + // face the enemy while waiting. + TASK_WAIT_FACE_ENEMY_RANDOM, + + // Wait until the player enters the same PVS as this character. + TASK_WAIT_PVS, + + // DON'T use this, it needs to go away. + TASK_SUGGEST_STATE, + + // Set m_hTargetEnt to nearest player + TASK_TARGET_PLAYER, + + // Walk to m_hTargetEnt's location + TASK_SCRIPT_WALK_TO_TARGET, + + // Run to m_hTargetEnt's location + TASK_SCRIPT_RUN_TO_TARGET, + + // Move to m_hTargetEnt's location using the activity specified by m_hCine->m_iszCustomMove. + TASK_SCRIPT_CUSTOM_MOVE_TO_TARGET, + + // Move to within specified range of m_hTargetEnt + TASK_MOVE_TO_TARGET_RANGE, + + // Move to within specified range of our nav goal + TASK_MOVE_TO_GOAL_RANGE, + + // Path that moves the character a few steps forward of where it is. + TASK_MOVE_AWAY_PATH, + + TASK_GET_PATH_AWAY_FROM_BEST_SOUND, + + // Set the implied goal for TASK_GET_PATH_TO_GOAL + TASK_SET_GOAL, + + // Get the path to the goal specified by TASK_SET_GOAL + TASK_GET_PATH_TO_GOAL, + + // Path to the enemy's location. Even if the enemy is unseen! + TASK_GET_PATH_TO_ENEMY, + + // Path to the last place this character saw the enemy + TASK_GET_PATH_TO_ENEMY_LKP, + + // Path to the enemy's location or path to a LOS with the enemy's last known position, depending on range + TASK_GET_CHASE_PATH_TO_ENEMY, + + // Path to a LOS with the enemy's last known position + TASK_GET_PATH_TO_ENEMY_LKP_LOS, + + // Path to the dead enemy's carcass. + TASK_GET_PATH_TO_ENEMY_CORPSE, + + // Path to the player's origin + TASK_GET_PATH_TO_PLAYER, + + // Path to node with line of sight to enemy + TASK_GET_PATH_TO_ENEMY_LOS, + + // Path to node with line of sight to enemy, at least flTaskData units away from m_vSavePosition + TASK_GET_FLANK_RADIUS_PATH_TO_ENEMY_LOS, + + // Path to node with line of sight to enemy, at least flTaskData degrees away from m_vSavePosition from the enemy's POV + TASK_GET_FLANK_ARC_PATH_TO_ENEMY_LOS, + + // Path to the within shot range of last place this character saw the enemy + TASK_GET_PATH_TO_RANGE_ENEMY_LKP_LOS, + + // Build a path to m_hTargetEnt + TASK_GET_PATH_TO_TARGET, + + // Allow a little slop, and allow for some Z offset (like the target is a gun on a table). + TASK_GET_PATH_TO_TARGET_WEAPON, + + TASK_CREATE_PENDING_WEAPON, + + // Path to nodes[ m_pHintNode ] + TASK_GET_PATH_TO_HINTNODE, + + // Store current position for later reference + TASK_STORE_LASTPOSITION, + + // Clear stored position + TASK_CLEAR_LASTPOSITION, + + // Store current position for later reference + TASK_STORE_POSITION_IN_SAVEPOSITION, + + // Store best sound position for later reference + TASK_STORE_BESTSOUND_IN_SAVEPOSITION, + TASK_STORE_BESTSOUND_REACTORIGIN_IN_SAVEPOSITION, + + TASK_REACT_TO_COMBAT_SOUND, + + // Store current enemy position in saveposition + TASK_STORE_ENEMY_POSITION_IN_SAVEPOSITION, + + // Move to the goal specified by the player in command mode. + TASK_GET_PATH_TO_COMMAND_GOAL, + + TASK_MARK_COMMAND_GOAL_POS, + + TASK_CLEAR_COMMAND_GOAL, + + // Path to last position (Last position must be stored with TASK_STORE_LAST_POSITION) + TASK_GET_PATH_TO_LASTPOSITION, + + // Path to saved position (Save position must by set in code or by a task) + TASK_GET_PATH_TO_SAVEPOSITION, + + // Path to location that has line of sight to saved position (Save position must by set in code or by a task) + TASK_GET_PATH_TO_SAVEPOSITION_LOS, + + // Path to random node + TASK_GET_PATH_TO_RANDOM_NODE, + + // Path to source of loudest heard sound that I care about + TASK_GET_PATH_TO_BESTSOUND, + + // Path to source of the strongest scend that I care about + TASK_GET_PATH_TO_BESTSCENT, + + // Run the current path + TASK_RUN_PATH, + + // Walk the current path + TASK_WALK_PATH, + + // Walk the current path for a specified number of seconds + TASK_WALK_PATH_TIMED, + + // Walk the current path until you are x units from the goal. + TASK_WALK_PATH_WITHIN_DIST, + + // Walk the current path until for x units + TASK_WALK_PATH_FOR_UNITS, + + // Rung the current path until you are x units from the goal. + TASK_RUN_PATH_FLEE, + + // Run the current path for a specified number of seconds + TASK_RUN_PATH_TIMED, + + // Run the current path until for x units + TASK_RUN_PATH_FOR_UNITS, + + // Run the current path until you are x units from the goal. + TASK_RUN_PATH_WITHIN_DIST, + + // Walk the current path sideways (must be supported by animation) + TASK_STRAFE_PATH, + + // Clear m_flMoveWaitFinished (timer that inhibits movement) + TASK_CLEAR_MOVE_WAIT, + + // Decide on the appropriate small flinch animation, and play it. + TASK_SMALL_FLINCH, + + // Decide on the appropriate big flinch animation, and play it. + TASK_BIG_FLINCH, + + // Prevent dodging for a certain amount of time. + TASK_DEFER_DODGE, + + // Turn to face ideal yaw + TASK_FACE_IDEAL, + + // Find an interesting direction to face. Don't face into walls, corners if you can help it. + TASK_FACE_REASONABLE, + + // Turn to face the way I should walk or run + TASK_FACE_PATH, + + // Turn to face a player + TASK_FACE_PLAYER, + + // Turn to face the enemy + TASK_FACE_ENEMY, + + // Turn to face nodes[ m_pHintNode ] + TASK_FACE_HINTNODE, + + // Play activity associate with the current hint + TASK_PLAY_HINT_ACTIVITY, + + // Turn to face m_hTargetEnt + TASK_FACE_TARGET, + + // Turn to face stored last position (last position must be stored first!) + TASK_FACE_LASTPOSITION, + + // Turn to face stored save position (save position must be stored first!) + TASK_FACE_SAVEPOSITION, + + // Turn to face directly away from stored save position (save position must be stored first!) + TASK_FACE_AWAY_FROM_SAVEPOSITION, + + // Set the current facing to be the ideal + TASK_SET_IDEAL_YAW_TO_CURRENT, + + // Attack the enemy (should be facing the enemy) + TASK_RANGE_ATTACK1, + TASK_RANGE_ATTACK2, + TASK_MELEE_ATTACK1, + TASK_MELEE_ATTACK2, + + // Reload weapon + TASK_RELOAD, + + // Execute special attack (user-defined) + TASK_SPECIAL_ATTACK1, + TASK_SPECIAL_ATTACK2, + + TASK_FIND_HINTNODE, + TASK_FIND_LOCK_HINTNODE, + + TASK_CLEAR_HINTNODE, + + // Claim m_pHintNode exclusively for this NPC. + TASK_LOCK_HINTNODE, + + // Emit an angry sound + TASK_SOUND_ANGRY, + + // Emit a dying sound + TASK_SOUND_DEATH, + + // Emit an idle sound + TASK_SOUND_IDLE, + + // Emit a sound because you are pissed off because you just saw someone you don't like + TASK_SOUND_WAKE, + + // Emit a pain sound + TASK_SOUND_PAIN, + + // Emit a death sound + TASK_SOUND_DIE, + + // Speak a sentence + TASK_SPEAK_SENTENCE, + + // Wait for the current sentence I'm speaking to finish + TASK_WAIT_FOR_SPEAK_FINISH, + + // Set current animation activity to the specified activity + TASK_SET_ACTIVITY, + + // Adjust the framerate to plus/minus N% + TASK_RANDOMIZE_FRAMERATE, + + // Immediately change to a schedule of the specified type + TASK_SET_SCHEDULE, + + // Set the specified schedule to execute if the current schedule fails. + TASK_SET_FAIL_SCHEDULE, + + // How close to route goal do I need to get + TASK_SET_TOLERANCE_DISTANCE, + + // How many seconds should I spend search for a route + TASK_SET_ROUTE_SEARCH_TIME, + + // Return to use of default fail schedule + TASK_CLEAR_FAIL_SCHEDULE, + + // Play the specified animation sequence before continuing + TASK_PLAY_SEQUENCE, + + // Play the specified private animation sequence before continuing + TASK_PLAY_PRIVATE_SEQUENCE, + + // Turn to face the enemy while playing specified animation sequence + TASK_PLAY_PRIVATE_SEQUENCE_FACE_ENEMY, + TASK_PLAY_SEQUENCE_FACE_ENEMY, + TASK_PLAY_SEQUENCE_FACE_TARGET, + + // tries lateral cover first, then node cover + TASK_FIND_COVER_FROM_BEST_SOUND, + + // tries lateral cover first, then node cover + TASK_FIND_COVER_FROM_ENEMY, + + // Find a place to hide from the enemy, somewhere on either side of me + TASK_FIND_LATERAL_COVER_FROM_ENEMY, + + // Find a place further from the saved position + TASK_FIND_BACKAWAY_FROM_SAVEPOSITION, + + // Fine a place to hide from the enemy, anywhere. Use the node system. + TASK_FIND_NODE_COVER_FROM_ENEMY, + + // Find a place to hide from the enemy that's within the specified distance + TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY, + + // data for this one is there MINIMUM aceptable distance to the cover. + TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, + + // Find a place to go that can't see to where I am now. + TASK_FIND_COVER_FROM_ORIGIN, + + // Unhook from the AI system. + TASK_DIE, + + // Wait until scripted sequence plays + TASK_WAIT_FOR_SCRIPT, + + // Play scripted sequence animation + TASK_PUSH_SCRIPT_ARRIVAL_ACTIVITY, + TASK_PLAY_SCRIPT, + TASK_PLAY_SCRIPT_POST_IDLE, + TASK_ENABLE_SCRIPT, + TASK_PLANT_ON_SCRIPT, + TASK_FACE_SCRIPT, + + // Wait for scene to complete + TASK_PLAY_SCENE, + + // Wait for 0 to specified number of seconds + TASK_WAIT_RANDOM, + + // Wait forever (until this schedule is interrupted) + TASK_WAIT_INDEFINITE, + + TASK_STOP_MOVING, + + // Turn left the specified number of degrees + TASK_TURN_LEFT, + + // Turn right the specified number of degrees + TASK_TURN_RIGHT, + + // Remember the specified piece of data + TASK_REMEMBER, + + // Forget the specified piece of data + TASK_FORGET, + + // Wait until current movement is complete. + TASK_WAIT_FOR_MOVEMENT, + + // Wait until a single-step movement is complete. + TASK_WAIT_FOR_MOVEMENT_STEP, + + // Wait until I can't hear any danger sound. + TASK_WAIT_UNTIL_NO_DANGER_SOUND, + + // Pick up new weapons: + TASK_WEAPON_FIND, + TASK_WEAPON_PICKUP, + TASK_WEAPON_RUN_PATH, // run to weapon but break if someone else picks it up + TASK_WEAPON_CREATE, + + TASK_ITEM_PICKUP, + TASK_ITEM_RUN_PATH, + + // Use small hull for tight navigation + TASK_USE_SMALL_HULL, + + // wait until you are on ground + TASK_FALL_TO_GROUND, + + // Wander for a specfied amound of time + TASK_WANDER, + + TASK_FREEZE, + + // regather conditions at the start of a schedule (all conditions are cleared between schedules) + TASK_GATHER_CONDITIONS, + + // Require an enemy be seen after the task is run to be considered a candidate enemy + TASK_IGNORE_OLD_ENEMIES, + + TASK_DEBUG_BREAK, + + // Add a specified amount of health to this NPC + TASK_ADD_HEALTH, + + // Add a gesture layer and wait until it's finished + TASK_ADD_GESTURE_WAIT, + + // Add a gesture layer + TASK_ADD_GESTURE, + + // Get a path to my forced interaction partner + TASK_GET_PATH_TO_INTERACTION_PARTNER, + + // First task of all schedules for playing back scripted sequences + TASK_PRE_SCRIPT, + + // ====================================== + // IMPORTANT: This must be the last enum + // ====================================== + LAST_SHARED_TASK + +}; + +#endif // AI_TASK_H diff --git a/game/server/ai_trackpather.h b/game/server/ai_trackpather.h new file mode 100644 index 0000000..a2ce734 --- /dev/null +++ b/game/server/ai_trackpather.h @@ -0,0 +1,274 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_TRACKPATHER_H +#define AI_TRACKPATHER_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +#include "ai_basenpc.h" + + +class CPathTrack; + +//------------------------------------------------------------------------------ + +class CAI_TrackPather : public CAI_BaseNPC +{ + DECLARE_CLASS( CAI_TrackPather, CAI_BaseNPC ); + DECLARE_DATADESC(); +public: + + bool IsOnPathTrack() { return (m_pCurrentPathTarget != NULL); } + +protected: + void InitPathingData( float flTrackArrivalTolerance, float flTargetDistance, float flAvoidDistance ); + virtual bool GetTrackPatherTarget( Vector *pPos ) { return false; } + virtual CBaseEntity *GetTrackPatherTargetEnt() { return NULL; } + + const Vector & GetDesiredPosition() const { return m_vecDesiredPosition; } + void SetDesiredPosition( const Vector &v ) { m_vecDesiredPosition = v; } + const Vector & GetGoalOrientation() const { return m_vecGoalOrientation; } + void SetGoalOrientation( const Vector &v ) { m_vecGoalOrientation = v; } + + bool CurPathTargetIsDest() { return ( m_pDestPathTarget == m_pCurrentPathTarget ); } + + virtual bool HasReachedTarget( void ) { return (WorldSpaceCenter() - m_vecDesiredPosition).Length() < 128; } + + CPathTrack * GetDestPathTarget() { return m_pDestPathTarget; } + + bool IsInForcedMove() const { return m_bForcedMove; } + void ClearForcedMove() { m_bForcedMove = false; } + + float GetPathMaxSpeed() const { return m_flPathMaxSpeed; } + + void OnSave( IEntitySaveUtils *pUtils ); + void OnRestore( void ); + +protected: + enum PauseState_t + { + PAUSE_NO_PAUSE = 0, + PAUSED_AT_POSITION, + PAUSE_AT_NEXT_LOS_POSITION, + + PAUSE_FORCE_DWORD = 0xFFFFFFFF, + }; + + // Sets a track + void SetTrack( string_t strTrackName ); + void SetTrack( CBaseEntity *pGoalEnt ); + + // Fly to a particular track point via the path + virtual void InputFlyToPathTrack( inputdata_t &inputdata ); + + // Updates the nav target if we've reached it + void UpdateTrackNavigation( void ); + + // Computes distance + nearest point from the current path.. + float ClosestPointToCurrentPath( Vector *pVecPoint ) const; + + // Computes a "path" velocity at a particular point along the current path + void ComputePathTangent( float t, Vector *pVecTangent ) const; + + // Computes the *normalized* velocity at which the helicopter should approach the final point + void ComputeNormalizedDestVelocity( Vector *pVecVelocity ) const; + + // Sets the farthest path distance + void SetFarthestPathDist( float flMaxPathDist ); + + // Returns the next/previous path along our current path + CPathTrack *NextAlongCurrentPath( CPathTrack *pPath ) const; + CPathTrack *PreviousAlongCurrentPath( CPathTrack *pPath ) const; + + // Adjusts a "next"most node based on the current movement direction + CPathTrack *AdjustForMovementDirection( CPathTrack *pPath ) const; + + // Enemy visibility check + virtual CBaseEntity *FindTrackBlocker( const Vector &vecViewPoint, const Vector &vecTargetPos ); + + // Compute a point n units along a path + void ComputePointAlongPath( const Vector &vecStartPoint, float flDistance, Vector *pTarget ); + + // Are we leading? + bool IsLeading() const { return m_bLeading && !m_bForcedMove; } + + // Leading + leading distance + void EnableLeading( bool bEnable ); + void SetLeadingDistance( float flLeadDistance ); + float GetLeadingDistance( ) const; + + // Compute a point n units along the current path from our current position + // (but don't pass the desired target point) + void ComputePointAlongCurrentPath( float flDistance, float flPerpDist, Vector *pTarget ); + + // Returns the perpendicular distance of the target from the nearest path point + float TargetDistanceToPath() const { return m_flTargetDistFromPath; } + + // Returns the speed of the target relative to the path + float TargetSpeedAlongPath() const; + + // Returns the speed of the target *across* the path + float TargetSpeedAcrossPath() const; + + // Compute a path direction + void ComputePathDirection( CPathTrack *pPath, Vector *pVecPathDir ); + + // What's the current path direction? + void CurrentPathDirection( Vector *pVecPathDir ); + + // Returns the max distance we can be from the path + float MaxDistanceFromCurrentPath() const; + + // true to use farthest, false for nearest + void UseFarthestPathPoint( bool useFarthest ); + + // Moves to an explicit track point + void MoveToTrackPoint( CPathTrack *pTrack ); + + // Sets up a new current path target + void SetupNewCurrentTarget( CPathTrack *pTrack ); + + // Compute the distance to the leading position + float ComputeDistanceToLeadingPosition(); + + // Compute the distance to the target position + float ComputeDistanceToTargetPosition(); + + // Set the pause state. + void SetPauseState( PauseState_t pauseState ) { m_nPauseState = pauseState; } + + // Does this path track have LOS to the target? + bool HasLOSToTarget( CPathTrack *pTrack ); + + // FIXME: Work this back into the base class + virtual bool ShouldUseFixedPatrolLogic() { return false; } + + // Deal with teleportation + void Teleported(); + +private: + + CPathTrack *BestPointOnPath( CPathTrack *pPath, const Vector &targetPos, float avoidRadius, bool visible, bool bFarthestPointOnPath ); + + // Input methods + void InputSetTrack( inputdata_t &inputdata ); + void InputChooseFarthestPathPoint( inputdata_t &inputdata ); + void InputChooseNearestPathPoint( inputdata_t &inputdata ); + void InputStartBreakableMovement( inputdata_t &inputdata ); + void InputStopBreakableMovement( inputdata_t &inputdata ); + void InputStartPatrol( inputdata_t &inputdata ); + void InputStopPatrol( inputdata_t &inputdata ); + void InputStartLeading( inputdata_t &inputdata ); + void InputStopLeading( inputdata_t &inputdata ); + + // Obsolete, for backward compatibility + void InputStartPatrolBreakable( inputdata_t &inputdata ); + + // Flies to a point on a track + void FlyToPathTrack( string_t strTrackName ); + + // Selects a new destination target + void SelectNewDestTarget(); + + // Makes sure we've picked the right position along the path if we're chasing an enemy + void UpdateTargetPosition( ); + + // Moves to the track + void UpdateCurrentTarget(); + void UpdateCurrentTargetLeading(); + + // Track debugging info + void VisualizeDebugInfo( const Vector &vecNearestPoint, const Vector &vecTarget ); + + // Moves to the closest track point + void MoveToClosestTrackPoint( CPathTrack *pTrack ); + + // Are the two path tracks connected? + bool IsOnSameTrack( CPathTrack *pPath1, CPathTrack *pPath2 ) const; + + // Is pPathTest in "front" of pPath on the same path? (Namely, does GetNext() get us there?) + bool IsForwardAlongPath( CPathTrack *pPath, CPathTrack *pPathTest ) const; + + // Purpose: + void UpdateTargetPositionLeading( void ); + + // Compute a point n units along a path + CPathTrack *ComputeLeadingPointAlongPath( const Vector &vecStartPoint, CPathTrack *pFirstTrack, float flDistance, Vector *pTarget ); + + // Finds the closest point on the path, returns a signed perpendicular distance + CPathTrack *FindClosestPointOnPath( CPathTrack *pPath, const Vector &targetPos, Vector *pVecClosestPoint, Vector *pVecPathDir, float *pDistanceFromPath ); + + // Methods to find a signed perp distance from the track + // and to compute a point off the path based on the signed perp distance + float ComputePerpDistanceFromPath( const Vector &vecPointOnPath, const Vector &vecPathDir, const Vector &vecPointOffPath ); + void ComputePointFromPerpDistance( const Vector &vecPointOnPath, const Vector &vecPathDir, float flPerpDist, Vector *pResult ); + + // Returns the direction of the path at the closest point to the target + const Vector &TargetPathDirection() const; + const Vector &TargetPathAcrossDirection() const; + + // Returns distance along path to target, returns -1 if there's no path + float ComputePathDistance( CPathTrack *pStart, CPathTrack *pDest, bool bForward ) const; + + // Compute the distance to a particular point on the path + float ComputeDistanceAlongPathToPoint( CPathTrack *pStartTrack, CPathTrack *pDestTrack, const Vector &vecDestPosition, bool bMovingForward ); + +private: + //--------------------------------- + Vector m_vecDesiredPosition; + Vector m_vecGoalOrientation; // orientation of the goal entity. + + // NOTE: CurrentPathTarget changes meaning based on movement direction + // For this *after* means the "next" (m_pnext) side of the line segment + // and "before" means the "prev" (m_pprevious) side of the line segment + // CurrentPathTarget is *after* the desired point when moving forward, + // and *before* the desired point when moving backward. + // DestPathTarget + TargetNearestPath always represent points + // *after* the desired point. + CHandle m_pCurrentPathTarget; + CHandle m_pDestPathTarget; + CHandle m_pLastPathTarget; + CHandle m_pTargetNearestPath; // Used only by leading, it specifies the path point *after* where the target is + + string_t m_strCurrentPathName; + string_t m_strDestPathName; + string_t m_strLastPathName; + string_t m_strTargetNearestPathName; + + Vector m_vecLastGoalCheckPosition; // Last position checked for moving towards + float m_flEnemyPathUpdateTime; // Next time to update our enemies position + bool m_bForcedMove; // Means the destination point must be reached regardless of enemy position + bool m_bPatrolling; // If set, move back and forth along the current track until we see an enemy + bool m_bPatrolBreakable; // If set, I'll stop patrolling if I see an enemy + bool m_bLeading; // If set, we can lead our enemies + + // Derived class pathing data + float m_flTargetDistanceThreshold;// Distance threshold used to determine when a target has moved enough to update our navigation to it + float m_flAvoidDistance; // + + float m_flTargetTolerance; // How far from a path track do we need to be before we 'reached' it? + Vector m_vecSegmentStartPoint; // Starting point for the current segment + Vector m_vecSegmentStartSplinePoint; // Used to define a spline which is used to compute path velocity + bool m_bMovingForward; + bool m_bChooseFarthestPoint; + float m_flFarthestPathDist; // How far from a path track do we need to be before we 'reached' it? + + float m_flPathMaxSpeed; + float m_flTargetDistFromPath; // How far is the target from the closest point on the path? + float m_flLeadDistance; + Vector m_vecTargetPathDir; + Vector m_vecTargetPathPoint; // What point on the path is closest to the target? + + PauseState_t m_nPauseState; +}; + +//------------------------------------------------------------------------------ + +#endif // AI_TRACKPATHER_H diff --git a/game/server/ai_utils.h b/game/server/ai_utils.h new file mode 100644 index 0000000..8cdde7b --- /dev/null +++ b/game/server/ai_utils.h @@ -0,0 +1,298 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Simple, small, free-standing tools for building AIs +// +//=============================================================================// + +#ifndef AI_UTILS_H +#define AI_UTILS_H + +#include "simtimer.h" +#include "ai_component.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// +// Function to get the local player. AI does not want asserts or warnings, +// just NULL result +// +//----------------------------------------------------------------------------- + +inline CBasePlayer *AI_GetSinglePlayer() +{ + if ( gpGlobals->maxClients > 1 ) + { + return NULL; + } + + return UTIL_GetLocalPlayer(); +} + +inline bool AI_IsSinglePlayer() +{ + return ( gpGlobals->maxClients == 1 ); +} + + +//----------------------------------------------------------------------------- +// +// CAI_MoveMonitor +// +// Purpose: Watch an entity, trigger if moved more than a tolerance +// +//----------------------------------------------------------------------------- + +class CAI_MoveMonitor +{ +public: + CAI_MoveMonitor() + : m_vMark( 0, 0, 0 ), + m_flMarkTolerance( NO_MARK ) + { + } + + void SetMark( CBaseEntity *pEntity, float tolerance ) + { + if ( pEntity ) + { + m_vMark = pEntity->GetAbsOrigin(); + m_flMarkTolerance = tolerance; + } + } + + void ClearMark() + { + m_flMarkTolerance = NO_MARK; + } + + bool IsMarkSet() + { + return ( m_flMarkTolerance != NO_MARK ); + } + + bool TargetMoved( CBaseEntity *pEntity ) + { + if ( IsMarkSet() && pEntity != NULL ) + { + float distance = ( m_vMark - pEntity->GetAbsOrigin() ).Length(); + if ( distance > m_flMarkTolerance ) + return true; + } + return false; + } + + bool TargetMoved2D( CBaseEntity *pEntity ) + { + if ( IsMarkSet() && pEntity != NULL ) + { + float distance = ( m_vMark.AsVector2D() - pEntity->GetAbsOrigin().AsVector2D() ).Length(); + if ( distance > m_flMarkTolerance ) + return true; + } + return false; + } + + Vector GetMarkPos() { return m_vMark; } + +private: + enum + { + NO_MARK = -1 + }; + + Vector m_vMark; + float m_flMarkTolerance; + + DECLARE_SIMPLE_DATADESC(); +}; + + +//----------------------------------------------------------------------------- +// +// CAI_ShotRegulator +// +// Purpose: Assists in creating non-constant bursty shooting style +// +//----------------------------------------------------------------------------- +class CAI_ShotRegulator +{ +public: + CAI_ShotRegulator(); + + // Sets the various parameters for burst (this one's for backwards compatibility) + // NOTE: This will modify the next shot time + void SetParameters( int minShotsPerBurst, int maxShotsPerBurst, float minRestTime, float maxRestTime = 0.0 ); + + // NOTE: The next 3 methods will *not* modify the next shot time + // Sets the number of shots to shoot in a single burst + void SetBurstShotCountRange( int minShotsPerBurst, int maxShotsPerBurst ); + + // How much time should I rest between bursts? + void SetRestInterval( float flMinRestInterval, float flMaxRestInterval ); + + // How much time should I wait in between shots in a single burst? + void SetBurstInterval( float flMinBurstInterval, float flMaxBurstInterval ); + + // Poll the current parameters + void GetBurstShotCountRange( int *pMinShotsPerBurst, int *pMaxShotsPerBurst ) const; + void GetRestInterval( float *pMinRestInterval, float *pMaxRestInterval ) const; + void GetBurstInterval( float *pMinBurstInterval, float *pMaxBurstInterval ) const; + + // Reset the state. If true, the next burst time is set to now, + // otherwise it'll wait one rest interval before shooting + void Reset( bool bStartShooting = true ); + + // Should we shoot? + bool ShouldShoot() const; + + // When will I shoot next? + float NextShotTime() const; + + // Am I in the middle of a rest period? + bool IsInRestInterval() const; + + // NOTE: These will not modify the next shot time + int GetBurstShotsRemaining() const; + void SetBurstShotsRemaining( int shots ); + + // Call this when the NPC fired the weapon; + void OnFiredWeapon(); + + // Causes us to potentially delay our shooting time + void FireNoEarlierThan( float flTime ); + + // Prevent/Allow shooting + void EnableShooting( void ); + void DisableShooting( void ); + +private: + float m_flNextShotTime; + bool m_bInRestInterval; + unsigned short m_nBurstShotsRemaining; + unsigned short m_nMinBurstShots, m_nMaxBurstShots; + float m_flMinRestInterval, m_flMaxRestInterval; + float m_flMinBurstInterval, m_flMaxBurstInterval; + bool m_bDisabled; + + DECLARE_SIMPLE_DATADESC(); +}; + + +//----------------------------------------------------------------------------- +// +// CAI_AccelDecay +// +// Purpose: Maintain a smooth acceleration, deceleration curve +// +//----------------------------------------------------------------------------- + +class CAI_AccelDecay +{ +public: + CAI_AccelDecay(); + + void SetParameters( float minVelocity, float maxVelocity, float accelPercent, float decelPercent ); + float Update( float flCurrent, float flTarget, float flInterval ); + void ResetVelocity( float flVelocity = 0.0f ); + void SetMaxVelocity( float maxVelocity ); + +private: + float m_velocity; + + float m_maxVelocity; // = 300; + float m_minVelocity; // = 10; + + float m_invDecay; // 0.8 // maintain X percent of velocity when slowing down + float m_decayTime;// 0.4161 // Sum( 1..cycle, HEIGHTINVDECAY^cycle ) + float m_accel; // 0.5 // accel toward maxVelocity by X percent each cycle + + DECLARE_SIMPLE_DATADESC(); +}; + + + +//----------------------------------------------------------------------------- +// +// Purpose: Utility to allow place grace in cover +// +//----------------------------------------------------------------------------- + +struct AI_FreePassParams_t +{ + float timeToTrigger; // How long after not detected to issue pass + float duration; // How long in the open pass before revoked + float moveTolerance; // How far in open needed to move to revoke pass + float refillRate; // After hiding again during pass, how quickly to reinstitute pass(seconds per second) + float coverDist; // When hiding, how far from an obstructing object needed to be considered in cover + + float peekTime; // How long allowed to peek + float peekTimeAfterDamage; // How long allowed to peek after damaged by + float peekEyeDist; // how far spaced out the eyes are + float peekEyeDistZ; // how far below eye position to test eyes (handles peek up) + + DECLARE_SIMPLE_DATADESC(); +}; + +//------------------------------------- + +class CAI_FreePass : public CAI_Component +{ +public: + CAI_FreePass() + : m_FreePassTimeRemaining(0) + { + } + + void Reset( float passTime = -1, float moveTolerance = -1 ); + + void SetPassTarget( CBaseEntity *pTarget ) { m_hTarget = pTarget; m_FreePassTimeRemaining = 0; } + CBaseEntity * GetPassTarget() { return m_hTarget; } + + void SetParams( const AI_FreePassParams_t ¶ms ) { m_Params = params; } + const AI_FreePassParams_t &GetParams() const { return m_Params; } + + //--------------------------------- + // Free pass + //--------------------------------- + void Update(); + + bool HasPass(); + void Revoke( bool bUpdateMemory = false ); + + float GetTimeRemaining() { return m_FreePassTimeRemaining; } + void SetTimeRemaining( float passTime ) { m_FreePassTimeRemaining = passTime; } + + bool ShouldAllowFVisible( bool bBaseResult ); + +private: + EHANDLE m_hTarget; + + float m_FreePassTimeRemaining; + CAI_MoveMonitor m_FreePassMoveMonitor; + + AI_FreePassParams_t m_Params; + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- + +class CTraceFilterNav : public CTraceFilterSimple +{ +public: + CTraceFilterNav( CAI_BaseNPC *pProber, bool bIgnoreTransientEntities, const IServerEntity *passedict, int collisionGroup, bool m_bAllowPlayerAvoid = true ); + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ); + +private: + CAI_BaseNPC *m_pProber; + bool m_bIgnoreTransientEntities; + bool m_bCheckCollisionTable; + bool m_bAllowPlayerAvoid; +}; + +extern string_t g_iszFuncBrushClassname; + +#endif // AI_UTILS_H diff --git a/game/server/ai_waypoint.h b/game/server/ai_waypoint.h new file mode 100644 index 0000000..cc899b5 --- /dev/null +++ b/game/server/ai_waypoint.h @@ -0,0 +1,258 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_WAYPOINT_H +#define AI_WAYPOINT_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include + +// ---------------------------------------------------------------------------- +// Forward declarations +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// Flags used in the flags field in AI_Waypoint_T +// ---------------------------------------------------------------------------- +enum WaypointFlags_t +{ + // The type of waypoint + bits_WP_TO_DETOUR = 0x01, // move to detour point. + bits_WP_TO_PATHCORNER = 0x02, // move to a path corner + bits_WP_TO_NODE = 0x04, // move to a node + bits_WP_TO_GOAL = 0x08, // move to an arbitrary point + bits_WP_TO_DOOR = 0x10, // move to position to open a door + + // Other flags for waypoint + bits_WP_DONT_SIMPLIFY = 0x20, // Don't let the route code simplify this waypoint +}; + +// ---------------------------------------------------------------------------- +// Purpose: Waypoints that make up an NPC's route. +// ---------------------------------------------------------------------------- +struct AI_Waypoint_t +{ +public: + AI_Waypoint_t(); + AI_Waypoint_t( const Vector &vecPosition, float flYaw, Navigation_t navType, int fWaypointFlags, int nNodeID ); + AI_Waypoint_t( const AI_Waypoint_t &from ) + { + memcpy( this, &from, sizeof(*this) ); + flPathDistGoal = -1; + pNext = pPrev = NULL; + } + + AI_Waypoint_t &operator=( const AI_Waypoint_t &from ) + { + memcpy( this, &from, sizeof(*this) ); + flPathDistGoal = -1; + pNext = pPrev = NULL; + return *this; + } + + ~AI_Waypoint_t() + { + AssertValid(); + if ( pNext ) + { + pNext->AssertValid(); + pNext->pPrev = pPrev; + } + if ( pPrev ) + { + pPrev->AssertValid(); + pPrev->pNext = pNext; + } + } + + //--------------------------------- + + void AssertValid() const + { +#ifdef DEBUG + Assert( !pNext || pNext->pPrev == this ); + Assert( !pPrev || pPrev->pNext == this ); +#endif + } + + + //--------------------------------- + + int Flags() const; + Navigation_t NavType() const; + + // Flag modification method + void ModifyFlags( int fFlags, bool bEnable ); + + bool IsReducible() { return (pNext && m_iWPType == pNext->m_iWPType && !(m_fWaypointFlags & (bits_WP_TO_GOAL | bits_WP_TO_PATHCORNER | bits_WP_DONT_SIMPLIFY)) ); } + + //--------------------------------- + + void SetNext( AI_Waypoint_t *p ); + AI_Waypoint_t * GetNext() { return pNext; } + const AI_Waypoint_t *GetNext() const { return pNext; } + + AI_Waypoint_t * GetPrev() { return pPrev; } + const AI_Waypoint_t *GetPrev() const { return pPrev; } + + AI_Waypoint_t * GetLast(); + + //--------------------------------- + + const Vector & GetPos() const { return vecLocation; } + void SetPos(const Vector &newPos) { vecLocation = newPos; } + + EHANDLE GetEHandleData() { return m_hData; } + + //--------------------------------- + // + // Basic info + // + Vector vecLocation; + float flYaw; // Waypoint facing dir + int iNodeID; // If waypoint is a node, which one + + //--------------------------------- + // + // Precalculated distances + // + float flPathDistGoal; + + //--------------------------------- + // + // If following a designer laid path, the path-corner entity (if any) + // + EHANDLE hPathCorner; + + // Data specific to the waypoint type: + // + // PATHCORNER: The path corner entity. + // DOOR: If moving to position to open a door, the handle of the door to open. + EHANDLE m_hData; + +private: + int m_fWaypointFlags; // See WaypointFlags_t + Navigation_t m_iWPType; // The type of waypoint + + AI_Waypoint_t *pNext; + AI_Waypoint_t *pPrev; + + DECLARE_FIXEDSIZE_ALLOCATOR(AI_Waypoint_t); + +public: + DECLARE_SIMPLE_DATADESC(); +}; + + +// ---------------------------------------------------------------------------- +// Inline methods associated with AI_Waypoint_t +// ---------------------------------------------------------------------------- +inline int AI_Waypoint_t::Flags() const +{ + return m_fWaypointFlags; +} + +inline Navigation_t AI_Waypoint_t::NavType() const +{ + return m_iWPType; +} + +inline void AI_Waypoint_t::ModifyFlags( int fFlags, bool bEnable ) +{ + if (bEnable) + m_fWaypointFlags |= fFlags; + else + m_fWaypointFlags &= ~fFlags; +} + +inline void AI_Waypoint_t::SetNext( AI_Waypoint_t *p ) +{ + if (pNext) + { + pNext->pPrev = NULL; + } + + pNext = p; + + if ( pNext ) + { + if ( pNext->pPrev ) + pNext->pPrev->pNext = NULL; + + pNext->pPrev = this; + } +} + + +// ---------------------------------------------------------------------------- +// Purpose: Holds an maintains a chain of waypoints + +class CAI_WaypointList +{ +public: + CAI_WaypointList() + : m_pFirstWaypoint( NULL ) + { + } + + CAI_WaypointList( AI_Waypoint_t *pFirstWaypoint) + : m_pFirstWaypoint( pFirstWaypoint ) + { + } + + void Set(AI_Waypoint_t* route); + + void PrependWaypoints( AI_Waypoint_t *pWaypoints ); + void PrependWaypoint( const Vector &newPoint, Navigation_t navType, unsigned waypointFlags, float flYaw = 0 ); + + bool IsEmpty() const { return ( m_pFirstWaypoint == NULL ); } + + AI_Waypoint_t * GetFirst() { return m_pFirstWaypoint; } + const AI_Waypoint_t *GetFirst() const { return m_pFirstWaypoint; } + + AI_Waypoint_t * GetLast(); + const AI_Waypoint_t *GetLast() const; + + void RemoveAll(); + +private: + + AI_Waypoint_t* m_pFirstWaypoint; // Linked list of waypoints +}; + +// ---------------------------------------------------------------------------- +#ifdef DEBUG +void AssertRouteValid( AI_Waypoint_t* route ); +#else +#define AssertRouteValid( route ) ((void)0) +#endif + +// ---------------------------------------------------------------------------- +// Utilities + +void DeleteAll( AI_Waypoint_t *pWaypointList ); + +// ------------------------------------ + +inline void DeleteAll( AI_Waypoint_t **ppWaypointList ) +{ + DeleteAll( *ppWaypointList ); + *ppWaypointList = NULL; +} + +// ------------------------------------ + +void AddWaypointLists(AI_Waypoint_t *pLeft, AI_Waypoint_t *pRight); + +// ---------------------------------------------------------------------------- + + + +#endif // AI_WAYPOINT_H diff --git a/game/server/base_transmit_proxy.h b/game/server/base_transmit_proxy.h new file mode 100644 index 0000000..d319779 --- /dev/null +++ b/game/server/base_transmit_proxy.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASE_TRANSMIT_PROXY_H +#define BASE_TRANSMIT_PROXY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ehandle.h" + + +class CBaseEntity; + + +class CBaseTransmitProxy +{ +public: + + CBaseTransmitProxy( CBaseEntity *pEnt ); + virtual ~CBaseTransmitProxy(); + + // Override this to control the ShouldTransmit behavior of whatever entity the proxy is attached to. + // bPrevShouldTransmitResult is what the proxy's entity's ShouldTransmit() returned. + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo, int nPrevShouldTransmitResult ); + + + void AddRef(); + void Release(); + +private: + EHANDLE m_hEnt; + unsigned short m_refCount; +}; + + +#endif // BASE_TRANSMIT_PROXY_H diff --git a/game/server/baseanimating.h b/game/server/baseanimating.h new file mode 100644 index 0000000..0550683 --- /dev/null +++ b/game/server/baseanimating.h @@ -0,0 +1,536 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASEANIMATING_H +#define BASEANIMATING_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "entityoutput.h" +#include "studio.h" +#include "datacache/idatacache.h" +#include "tier0/threadtools.h" + + +struct animevent_t; +struct matrix3x4_t; +class CIKContext; +class KeyValues; +FORWARD_DECLARE_HANDLE( memhandle_t ); + +#define BCF_NO_ANIMATION_SKIP ( 1 << 0 ) // Do not allow PVS animation skipping (mostly for attachments being critical to an entity) +#define BCF_IS_IN_SPAWN ( 1 << 1 ) // Is currently inside of spawn, always evaluate animations + +class CBaseAnimating : public CBaseEntity +{ +public: + DECLARE_CLASS( CBaseAnimating, CBaseEntity ); + + CBaseAnimating(); + ~CBaseAnimating(); + + DECLARE_PREDICTABLE(); + + enum + { + NUM_POSEPAREMETERS = 24, + NUM_BONECTRLS = 4 + }; + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual void SetModel( const char *szModelName ); + virtual void Activate(); + virtual void Spawn(); + virtual void Precache(); + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + virtual int Restore( IRestore &restore ); + virtual void OnRestore(); + + CStudioHdr *GetModelPtr( void ); + void InvalidateMdlCache(); + + virtual CStudioHdr *OnNewModel(); + + virtual CBaseAnimating* GetBaseAnimating() { return this; } + + // Cycle access + void SetCycle( float flCycle ); + float GetCycle() const; + + float GetAnimTimeInterval( void ) const; + + // Call this in your constructor to tell it that you will not use animtime. Then the + // interpolation will be done correctly on the client. + // This defaults to off. + void UseClientSideAnimation(); + + // Tells whether or not we're using client-side animation. Used for controlling + // the transmission of animtime. + bool IsUsingClientSideAnimation() { return m_bClientSideAnimation; } + + + // Basic NPC Animation functions + virtual float GetIdealSpeed( ) const; + virtual float GetIdealAccel( ) const; + virtual void StudioFrameAdvance(); // advance animation frame to some time in the future + void StudioFrameAdvanceManual( float flInterval ); + bool IsValidSequence( int iSequence ); + + inline float GetPlaybackRate(); + inline void SetPlaybackRate( float rate ); + + inline int GetSequence() { return m_nSequence; } + virtual void SetSequence(int nSequence); + /* inline */ void ResetSequence(int nSequence); + // FIXME: push transitions support down into CBaseAnimating? + virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; } + inline bool IsSequenceFinished( void ) { return m_bSequenceFinished; } + inline bool SequenceLoops( void ) { return m_bSequenceLoops; } + bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence ); + inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); } + inline float SequenceDuration( void ) { return SequenceDuration( m_nSequence ); } + float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence ); + inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); } + float GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceCycleRate( int iSequence ) { return GetSequenceCycleRate(GetModelPtr(),iSequence); } + float GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence ); + virtual float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); } + void ResetActivityIndexes ( void ); + void ResetEventIndexes ( void ); + int SelectWeightedSequence ( Activity activity ); + int SelectWeightedSequence ( Activity activity, int curSequence ); + int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount ); + int SelectHeaviestSequence ( Activity activity ); + int LookupActivity( const char *label ); + int LookupSequence ( const char *label ); + KeyValues *GetSequenceKeyValues( int iSequence ); + + float GetSequenceMoveYaw( int iSequence ); + float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceMoveDist( int iSequence ) { return GetSequenceMoveDist(GetModelPtr(),iSequence);} + void GetSequenceLinearMotion( int iSequence, Vector *pVec ); + const char *GetSequenceName( int iSequence ); + const char *GetSequenceActivityName( int iSequence ); + Activity GetSequenceActivity( int iSequence ); + + void ResetSequenceInfo ( ); + // This will stop animation until you call ResetSequenceInfo() at some point in the future + inline void StopAnimation( void ) { m_flPlaybackRate = 0; } + + virtual void ClampRagdollForce( const Vector &vecForceIn, Vector *vecForceOut ) { *vecForceOut = vecForceIn; } // Base class does nothing. + virtual bool BecomeRagdollOnClient( const Vector &force ); + virtual bool IsRagdoll(); + virtual bool CanBecomeRagdoll( void ); //Check if this entity will ragdoll when dead. + + virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask ); + + virtual void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ); + virtual void SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ); + virtual void CalculateIKLocks( float currentTime ); + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + + bool HasAnimEvent( int nSequence, int nEvent ); + virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future + virtual void HandleAnimEvent( animevent_t *pEvent ); + + int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); + inline int LookupPoseParameter( const char *szName ) { return LookupPoseParameter(GetModelPtr(), szName); } + + float SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue ); + inline float SetPoseParameter( const char *szName, float flValue ) { return SetPoseParameter( GetModelPtr(), szName, flValue ); } + float SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); + inline float SetPoseParameter( int iParameter, float flValue ) { return SetPoseParameter( GetModelPtr(), iParameter, flValue ); } + + float GetPoseParameter( const char *szName ); + float GetPoseParameter( int iParameter ); + bool GetPoseParameterRange( int index, float &minValue, float &maxValue ); + bool HasPoseParameter( int iSequence, const char *szName ); + bool HasPoseParameter( int iSequence, int iParameter ); + float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f ); + +protected: + // The modus operandi for pose parameters is that you should not use the const char * version of the functions + // in general code -- it causes many many string comparisons, which is slower than you think. Better is to + // save off your pose parameters in member variables in your derivation of this function: + virtual void PopulatePoseParameters( void ); + + +public: + + int LookupBone( const char *szName ); + void GetBonePosition( const char *szName, Vector &origin, QAngle &angles ); + void GetBonePosition( int iBone, Vector &origin, QAngle &angles ); + int GetPhysicsBone( int boneIndex ); + + int GetNumBones ( void ); + + int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir ); + bool GotoSequence( int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &iNextSequence, float &flCycle, int &iDir ); + int GetEntryNode( int iSequence ); + int GetExitNode( int iSequence ); + + void GetEyeballs( Vector &origin, QAngle &angles ); // ?? remove ?? + + int LookupAttachment( const char *szName ); + + // These return the attachment in world space + bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ); + bool GetAttachment( int iAttachment, Vector &absOrigin, QAngle &absAngles ); + int GetAttachmentBone( int iAttachment ); + virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld ); + + // These return the attachment in the space of the entity + bool GetAttachmentLocal( const char *szName, Vector &origin, QAngle &angles ); + bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles ); + bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal ); + + // Non-angle versions of the attachments in world space + bool GetAttachment( const char *szName, Vector &absOrigin, Vector *forward = NULL, Vector *right = NULL, Vector *up = NULL ); + bool GetAttachment( int iAttachment, Vector &absOrigin, Vector *forward = NULL, Vector *right = NULL, Vector *up = NULL ); + + void SetBodygroup( int iGroup, int iValue ); + int GetBodygroup( int iGroup ); + + const char *GetBodygroupName( int iGroup ); + int FindBodygroupByName( const char *name ); + int GetBodygroupCount( int iGroup ); + int GetNumBodyGroups( void ); + + void SetHitboxSet( int setnum ); + void SetHitboxSetByName( const char *setname ); + int GetHitboxSet( void ); + char const *GetHitboxSetName( void ); + int GetHitboxSetCount( void ); + int GetHitboxBone( int hitboxIndex ); + bool LookupHitbox( const char *szName, int& outSet, int& outBox ); + + // Computes a box that surrounds all hitboxes + bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Clone a CBaseAnimating from another (copies model & sequence data) + void CopyAnimationDataFrom( CBaseAnimating *pSource ); + + int ExtractBbox( int sequence, Vector& mins, Vector& maxs ); + void SetSequenceBox( void ); + int RegisterPrivateActivity( const char *pszActivityName ); + + void ResetClientsideFrame( void ); + +// Controllers. + virtual void InitBoneControllers ( void ); + + // Return's the controller's angle/position in bone space. + float GetBoneController ( int iController ); + + // Maps the angle/position value you specify into the bone's start/end and sets the specified controller to the value. + float SetBoneController ( int iController, float flValue ); + + void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity); + + // these two need to move somewhere else + LocalFlexController_t GetNumFlexControllers( void ); + const char *GetFlexDescFacs( int iFlexDesc ); + const char *GetFlexControllerName( LocalFlexController_t iFlexController ); + const char *GetFlexControllerType( LocalFlexController_t iFlexController ); + + virtual Vector GetGroundSpeedVelocity( void ); + + bool GetIntervalMovement( float flIntervalUsed, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles ); + bool GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles ); + float GetInstantaneousVelocity( float flInterval = 0.0 ); + float GetEntryVelocity( int iSequence ); + float GetExitVelocity( int iSequence ); + float GetMovementFrame( float flDist ); + bool HasMovement( int iSequence ); + + void ReportMissingActivity( int iActivity ); + virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + class CBoneCache *GetBoneCache( void ); + void InvalidateBoneCache(); + void InvalidateBoneCacheIfOlderThan( float deltaTime ); + virtual int DrawDebugTextOverlays( void ); + + // See note in code re: bandwidth usage!!! + void DrawServerHitboxes( float duration = 0.0f, bool monocolor = false ); + void DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, bool noDepthTest = true, float duration = 0.0f, bool monocolor = false ); + + void SetModelScale( float scale, float change_duration = 0.0f ); + float GetModelScale() const { return m_flModelScale; } + + void UpdateModelScale(); + virtual void RefreshCollisionBounds( void ); + + // also calculate IK on server? (always done on client) + void EnableServerIK(); + void DisableServerIK(); + + // for ragdoll vs. car + int GetHitboxesFrontside( int *boxList, int boxMax, const Vector &normal, float dist ); + + void GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles ); + + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + + // Send a muzzle flash event to the client for this entity. + void DoMuzzleFlash(); + + // Fire + virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false ); + virtual void IgniteLifetime( float flFlameLifetime ); + virtual void IgniteNumHitboxFires( int iNumHitBoxFires ); + virtual void IgniteHitboxFireScale( float flHitboxFireScale ); + virtual void Extinguish() { RemoveFlag( FL_ONFIRE ); } + bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); } + void Scorch( int rate, int floor ); + void InputIgnite( inputdata_t &inputdata ); + void InputIgniteLifetime( inputdata_t &inputdata ); + void InputIgniteNumHitboxFires( inputdata_t &inputdata ); + void InputIgniteHitboxFireScale( inputdata_t &inputdata ); + void InputBecomeRagdoll( inputdata_t &inputdata ); + + // Dissolve, returns true if the ragdoll has been created + bool Dissolve( const char *pMaterialName, float flStartTime, bool bNPCOnly = true, int nDissolveType = 0, Vector vDissolverOrigin = vec3_origin, int iMagnitude = 0 ); + bool IsDissolving() { return ( (GetFlags() & FL_DISSOLVING) != 0 ); } + void TransferDissolveFrom( CBaseAnimating *pAnim ); + + // animation needs + float m_flGroundSpeed; // computed linear movement rate for current sequence + float m_flLastEventCheck; // cycle index of when events were last checked + + virtual void SetLightingOriginRelative( CBaseEntity *pLightingOriginRelative ); + void SetLightingOriginRelative( string_t strLightingOriginRelative ); + CBaseEntity *GetLightingOriginRelative(); + + virtual void SetLightingOrigin( CBaseEntity *pLightingOrigin ); + void SetLightingOrigin( string_t strLightingOrigin ); + CBaseEntity *GetLightingOrigin(); + + const float* GetPoseParameterArray() { return m_flPoseParameter.Base(); } + const float* GetEncodedControllerArray() { return m_flEncodedController.Base(); } + + void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles, + const Vector& origin, const Vector pos[MAXSTUDIOBONES], + const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], + CBaseAnimating *pParent, CBoneCache *pParentCache ); + + void SetFadeDistance( float minFadeDist, float maxFadeDist ); + + int GetBoneCacheFlags( void ) { return m_fBoneCacheFlags; } + inline void SetBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags |= fFlag; } + inline void ClearBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags &= ~fFlag; } + + bool PrefetchSequence( int iSequence ); + +private: + void LockStudioHdr(); + void UnlockStudioHdr(); + + void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval ); + void InputSetLightingOriginRelative( inputdata_t &inputdata ); + void InputSetLightingOrigin( inputdata_t &inputdata ); + void InputSetModelScale( inputdata_t &inputdata ); + + bool CanSkipAnimation( void ); + +public: + CNetworkVar( int, m_nForceBone ); + CNetworkVector( m_vecForce ); + + CNetworkVar( int, m_nSkin ); + CNetworkVar( int, m_nBody ); + CNetworkVar( int, m_nHitboxSet ); + + // For making things thin during barnacle swallowing, e.g. + CNetworkVar( float, m_flModelScale ); + + // was pev->framerate + CNetworkVar( float, m_flPlaybackRate ); + +public: + void InitStepHeightAdjust( void ); + void SetIKGroundContactInfo( float minHeight, float maxHeight ); + void UpdateStepOrigin( void ); + +protected: + float m_flIKGroundContactTime; + float m_flIKGroundMinHeight; + float m_flIKGroundMaxHeight; + + float m_flEstIkFloor; // debounced + float m_flEstIkOffset; + + CIKContext *m_pIk; + int m_iIKCounter; + +public: + Vector GetStepOrigin( void ) const; + QAngle GetStepAngles( void ) const; + +private: + bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry + bool m_bSequenceLoops; // true if the sequence loops + bool m_bResetSequenceInfoOnLoad; // true if a ResetSequenceInfo was queued up during dynamic load + float m_flDissolveStartTime; + + // was pev->frame + CNetworkVar( float, m_flCycle ); + CNetworkVar( int, m_nSequence ); + CNetworkArray( float, m_flPoseParameter, NUM_POSEPAREMETERS ); // must be private so manual mode works! + CNetworkArray( float, m_flEncodedController, NUM_BONECTRLS ); // bone controller setting (0..1) + + // Client-side animation (useful for looping animation objects) + CNetworkVar( bool, m_bClientSideAnimation ); + CNetworkVar( bool, m_bClientSideFrameReset ); + + CNetworkVar( int, m_nNewSequenceParity ); + CNetworkVar( int, m_nResetEventsParity ); + + // Incremented each time the entity is told to do a muzzle flash. + // The client picks up the change and draws the flash. + CNetworkVar( unsigned char, m_nMuzzleFlashParity ); + + CNetworkHandle( CBaseEntity, m_hLightingOrigin ); + CNetworkHandle( CBaseEntity, m_hLightingOriginRelative ); + + string_t m_iszLightingOriginRelative; // for reading from the file only + string_t m_iszLightingOrigin; // for reading from the file only + + memhandle_t m_boneCacheHandle; + unsigned short m_fBoneCacheFlags; // Used for bone cache state on model + +protected: + CNetworkVar( float, m_fadeMinDist ); // Point at which fading is absolute + CNetworkVar( float, m_fadeMaxDist ); // Point at which fading is inactive + CNetworkVar( float, m_flFadeScale ); // Scale applied to min / max + +public: + COutputEvent m_OnIgnite; + +private: + CStudioHdr *m_pStudioHdr; + CThreadFastMutex m_StudioHdrInitLock; + CThreadFastMutex m_BoneSetupMutex; + +// FIXME: necessary so that cyclers can hack m_bSequenceFinished +friend class CFlexCycler; +friend class CCycler; +friend class CBlendingCycler; +}; + +//----------------------------------------------------------------------------- +// Purpose: return a pointer to an updated studiomdl cache cache +//----------------------------------------------------------------------------- +inline CStudioHdr *CBaseAnimating::GetModelPtr( void ) +{ + if ( IsDynamicModelLoading() ) + return NULL; + +#ifdef _DEBUG + if ( !HushAsserts() ) + { + // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. + static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" ); + AssertOnce( pModelCache->IsFrameLocking() ); + } +#endif + + if ( !m_pStudioHdr && GetModel() ) + { + LockStudioHdr(); + } + return ( m_pStudioHdr && m_pStudioHdr->IsValid() ) ? m_pStudioHdr : NULL; +} + +inline void CBaseAnimating::InvalidateMdlCache() +{ + UnlockStudioHdr(); + if ( m_pStudioHdr != NULL ) + { + delete m_pStudioHdr; + m_pStudioHdr = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Serves the 90% case of calling SetSequence / ResetSequenceInfo. +//----------------------------------------------------------------------------- + +/* +inline void CBaseAnimating::ResetSequence(int nSequence) +{ + m_nSequence = nSequence; + ResetSequenceInfo(); +} +*/ + +inline float CBaseAnimating::GetPlaybackRate() +{ + return m_flPlaybackRate; +} + +inline void CBaseAnimating::SetPlaybackRate( float rate ) +{ + m_flPlaybackRate = rate; +} + +inline void CBaseAnimating::SetLightingOrigin( CBaseEntity *pLightingOrigin ) +{ + m_hLightingOrigin = pLightingOrigin; +} + +inline CBaseEntity *CBaseAnimating::GetLightingOrigin() +{ + return m_hLightingOrigin; +} + +inline void CBaseAnimating::SetLightingOriginRelative( CBaseEntity *pLightingOriginRelative ) +{ + m_hLightingOriginRelative = pLightingOriginRelative; +} + +inline CBaseEntity *CBaseAnimating::GetLightingOriginRelative() +{ + return m_hLightingOriginRelative; +} + +//----------------------------------------------------------------------------- +// Cycle access +//----------------------------------------------------------------------------- +inline float CBaseAnimating::GetCycle() const +{ + return m_flCycle; +} + +inline void CBaseAnimating::SetCycle( float flCycle ) +{ + m_flCycle = flCycle; +} + + +EXTERN_SEND_TABLE(DT_BaseAnimating); + + + +#define ANIMATION_SEQUENCE_BITS 12 // 4096 sequences +#define ANIMATION_SKIN_BITS 10 // 1024 body skin selections FIXME: this seems way high +#define ANIMATION_BODY_BITS 32 // body combinations +#define ANIMATION_HITBOXSET_BITS 2 // hit box sets +#if defined( TF_DLL ) +#define ANIMATION_POSEPARAMETER_BITS 8 // pose parameter resolution +#else +#define ANIMATION_POSEPARAMETER_BITS 11 // pose parameter resolution +#endif +#define ANIMATION_PLAYBACKRATE_BITS 8 // default playback rate, only used on leading edge detect sequence changes + +#endif // BASEANIMATING_H diff --git a/game/server/basebludgeonweapon.h b/game/server/basebludgeonweapon.h new file mode 100644 index 0000000..6f2a7ea --- /dev/null +++ b/game/server/basebludgeonweapon.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The class from which all bludgeon melee +// weapons are derived. +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include "basehlcombatweapon.h" + +#ifndef BASEBLUDGEONWEAPON_H +#define BASEBLUDGEONWEAPON_H + +//========================================================= +// CBaseHLBludgeonWeapon +//========================================================= +class CBaseHLBludgeonWeapon : public CBaseHLCombatWeapon +{ + DECLARE_CLASS( CBaseHLBludgeonWeapon, CBaseHLCombatWeapon ); +public: + CBaseHLBludgeonWeapon(); + + DECLARE_SERVERCLASS(); + + virtual void Spawn( void ); + virtual void Precache( void ); + + //Attack functions + virtual void PrimaryAttack( void ); + virtual void SecondaryAttack( void ); + + virtual void ItemPostFrame( void ); + + //Functions to select animation sequences + virtual Activity GetPrimaryAttackActivity( void ) { return ACT_VM_HITCENTER; } + virtual Activity GetSecondaryAttackActivity( void ) { return ACT_VM_HITCENTER2; } + + virtual float GetFireRate( void ) { return 0.2f; } + virtual float GetRange( void ) { return 32.0f; } + virtual float GetDamageForActivity( Activity hitActivity ) { return 1.0f; } + + virtual int CapabilitiesGet( void ); + virtual int WeaponMeleeAttack1Condition( float flDot, float flDist ); + +protected: + virtual void ImpactEffect( trace_t &trace ); + +private: + bool ImpactWater( const Vector &start, const Vector &end ); + void Swing( int bIsSecondary ); + void Hit( trace_t &traceHit, Activity nHitActivity, bool bIsSecondary ); + Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner ); +}; + +#endif \ No newline at end of file diff --git a/game/server/basecombatcharacter.h b/game/server/basecombatcharacter.h new file mode 100644 index 0000000..3e92332 --- /dev/null +++ b/game/server/basecombatcharacter.h @@ -0,0 +1,602 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base combat character with no AI +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASECOMBATCHARACTER_H +#define BASECOMBATCHARACTER_H + +#include +#include "weapon_proficiency.h" + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef INVASION_DLL +#include "tf_shareddefs.h" + +#define POWERUP_THINK_CONTEXT "PowerupThink" +#endif + +#include "cbase.h" +#include "baseentity.h" +#include "baseflex.h" +#include "damagemodifier.h" +#include "utllinkedlist.h" +#include "ai_hull.h" +#include "ai_utils.h" +#include "physics_impact_damage.h" + +class CNavArea; +class CScriptedTarget; +typedef CHandle CBaseCombatWeaponHandle; + +// ------------------------------------- +// Capability Bits +// ------------------------------------- + +enum Capability_t +{ + bits_CAP_MOVE_GROUND = 0x00000001, // walk/run + bits_CAP_MOVE_JUMP = 0x00000002, // jump/leap + bits_CAP_MOVE_FLY = 0x00000004, // can fly, move all around + bits_CAP_MOVE_CLIMB = 0x00000008, // climb ladders + bits_CAP_MOVE_SWIM = 0x00000010, // navigate in water // UNDONE - not yet implemented + bits_CAP_MOVE_CRAWL = 0x00000020, // crawl // UNDONE - not yet implemented + bits_CAP_MOVE_SHOOT = 0x00000040, // tries to shoot weapon while moving + bits_CAP_SKIP_NAV_GROUND_CHECK = 0x00000080, // optimization - skips ground tests while computing navigation + bits_CAP_USE = 0x00000100, // open doors/push buttons/pull levers + //bits_CAP_HEAR = 0x00000200, // can hear forced sounds + bits_CAP_AUTO_DOORS = 0x00000400, // can trigger auto doors + bits_CAP_OPEN_DOORS = 0x00000800, // can open manual doors + bits_CAP_TURN_HEAD = 0x00001000, // can turn head, always bone controller 0 + bits_CAP_WEAPON_RANGE_ATTACK1 = 0x00002000, // can do a weapon range attack 1 + bits_CAP_WEAPON_RANGE_ATTACK2 = 0x00004000, // can do a weapon range attack 2 + bits_CAP_WEAPON_MELEE_ATTACK1 = 0x00008000, // can do a weapon melee attack 1 + bits_CAP_WEAPON_MELEE_ATTACK2 = 0x00010000, // can do a weapon melee attack 2 + bits_CAP_INNATE_RANGE_ATTACK1 = 0x00020000, // can do a innate range attack 1 + bits_CAP_INNATE_RANGE_ATTACK2 = 0x00040000, // can do a innate range attack 1 + bits_CAP_INNATE_MELEE_ATTACK1 = 0x00080000, // can do a innate melee attack 1 + bits_CAP_INNATE_MELEE_ATTACK2 = 0x00100000, // can do a innate melee attack 1 + bits_CAP_USE_WEAPONS = 0x00200000, // can use weapons (non-innate attacks) + //bits_CAP_STRAFE = 0x00400000, // strafe ( walk/run sideways) + bits_CAP_ANIMATEDFACE = 0x00800000, // has animated eyes/face + bits_CAP_USE_SHOT_REGULATOR = 0x01000000, // Uses the shot regulator for range attack1 + bits_CAP_FRIENDLY_DMG_IMMUNE = 0x02000000, // don't take damage from npc's that are D_LI + bits_CAP_SQUAD = 0x04000000, // can form squads + bits_CAP_DUCK = 0x08000000, // cover and reload ducking + bits_CAP_NO_HIT_PLAYER = 0x10000000, // don't hit players + bits_CAP_AIM_GUN = 0x20000000, // Use arms to aim gun, not just body + bits_CAP_NO_HIT_SQUADMATES = 0x40000000, // none + bits_CAP_SIMPLE_RADIUS_DAMAGE = 0x80000000, // Do not use robust radius damage model on this character. +}; + +#define bits_CAP_DOORS_GROUP (bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS) +#define bits_CAP_RANGE_ATTACK_GROUP (bits_CAP_WEAPON_RANGE_ATTACK1 | bits_CAP_WEAPON_RANGE_ATTACK2) +#define bits_CAP_MELEE_ATTACK_GROUP (bits_CAP_WEAPON_MELEE_ATTACK1 | bits_CAP_WEAPON_MELEE_ATTACK2) + + +class CBaseCombatWeapon; + +#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f + +enum Disposition_t +{ + D_ER, // Undefined - error + D_HT, // Hate + D_FR, // Fear + D_LI, // Like + D_NU // Neutral +}; + +const int DEF_RELATIONSHIP_PRIORITY = INT_MIN; + +struct Relationship_t +{ + EHANDLE entity; // Relationship to a particular entity + Class_T classType; // Relationship to a class CLASS_NONE = not class based (Def. in baseentity.h) + Disposition_t disposition; // D_HT (Hate), D_FR (Fear), D_LI (Like), D_NT (Neutral) + int priority; // Relative importance of this relationship (higher numbers mean more important) + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: This should contain all of the combat entry points / functionality +// that are common between NPCs and players +//----------------------------------------------------------------------------- +class CBaseCombatCharacter : public CBaseFlex +{ + DECLARE_CLASS( CBaseCombatCharacter, CBaseFlex ); + +public: + CBaseCombatCharacter(void); + ~CBaseCombatCharacter(void); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DECLARE_PREDICTABLE(); + +public: + + virtual void Spawn( void ); + virtual void Precache(); + + virtual int Restore( IRestore &restore ); + + virtual const impactdamagetable_t &GetPhysicsImpactDamageTable( void ); + + int TakeHealth( float flHealth, int bitsDamageType ); + void CauseDeath( const CTakeDamageInfo &info ); + + virtual bool FVisible ( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); // true iff the parameter can be seen by me. + virtual bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ) { return BaseClass::FVisible( vecTarget, traceMask, ppBlocker ); } + static void ResetVisibilityCache( CBaseCombatCharacter *pBCC = NULL ); + +#ifdef PORTAL + virtual bool FVisibleThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); +#endif + + virtual bool FInViewCone( CBaseEntity *pEntity ); + virtual bool FInViewCone( const Vector &vecSpot ); + +#ifdef PORTAL + virtual CProp_Portal* FInViewConeThroughPortal( CBaseEntity *pEntity ); + virtual CProp_Portal* FInViewConeThroughPortal( const Vector &vecSpot ); +#endif + + virtual bool FInAimCone( CBaseEntity *pEntity ); + virtual bool FInAimCone( const Vector &vecSpot ); + + virtual bool ShouldShootMissTarget( CBaseCombatCharacter *pAttacker ); + virtual CBaseEntity *FindMissTarget( void ); + + // Do not call HandleInteraction directly, use DispatchInteraction + bool DispatchInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ) { return ( interactionType > 0 ) ? HandleInteraction( interactionType, data, sourceEnt ) : false; } + virtual bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ); + + virtual QAngle BodyAngles(); + virtual Vector BodyDirection2D( void ); + virtual Vector BodyDirection3D( void ); + virtual Vector HeadDirection2D( void ) { return BodyDirection2D( ); }; // No head motion so just return body dir + virtual Vector HeadDirection3D( void ) { return BodyDirection2D( ); }; // No head motion so just return body dir + virtual Vector EyeDirection2D( void ) { return HeadDirection2D( ); }; // No eye motion so just return head dir + virtual Vector EyeDirection3D( void ) { return HeadDirection3D( ); }; // No eye motion so just return head dir + + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + // ----------------------- + // Fog + // ----------------------- + virtual bool IsHiddenByFog( const Vector &target ) const; ///< return true if given target cant be seen because of fog + virtual bool IsHiddenByFog( CBaseEntity *target ) const; ///< return true if given target cant be seen because of fog + virtual bool IsHiddenByFog( float range ) const; ///< return true if given distance is too far to see through the fog + virtual float GetFogObscuredRatio( const Vector &target ) const;///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured + virtual float GetFogObscuredRatio( CBaseEntity *target ) const; ///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured + virtual float GetFogObscuredRatio( float range ) const; ///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured + + + // ----------------------- + // Vision + // ----------------------- + enum FieldOfViewCheckType { USE_FOV, DISREGARD_FOV }; + + // Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo... + bool IsAbleToSee( const CBaseEntity *entity, FieldOfViewCheckType checkFOV ); + bool IsAbleToSee( CBaseCombatCharacter *pBCC, FieldOfViewCheckType checkFOV ); + + virtual bool IsLookingTowards( const CBaseEntity *target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED. + virtual bool IsLookingTowards( const Vector &target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED. + + virtual bool IsInFieldOfView( CBaseEntity *entity ) const; // Calls IsLookingTowards with the current field of view. + virtual bool IsInFieldOfView( const Vector &pos ) const; + + enum LineOfSightCheckType + { + IGNORE_NOTHING, + IGNORE_ACTORS + }; + virtual bool IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType = IGNORE_NOTHING ) const;// strictly LOS check with no other considerations + virtual bool IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity *entityToIgnore = NULL ) const; + + // ----------------------- + // Ammo + // ----------------------- + virtual int GiveAmmo( int iCount, int iAmmoIndex, bool bSuppressSound = false ); + int GiveAmmo( int iCount, const char *szName, bool bSuppressSound = false ); + virtual void RemoveAmmo( int iCount, int iAmmoIndex ); + virtual void RemoveAmmo( int iCount, const char *szName ); + void RemoveAllAmmo( ); + virtual int GetAmmoCount( int iAmmoIndex ) const; + int GetAmmoCount( char *szName ) const; + + virtual Activity NPC_TranslateActivity( Activity baseAct ); + + // ----------------------- + // Weapons + // ----------------------- + CBaseCombatWeapon* Weapon_Create( const char *pWeaponName ); + virtual Activity Weapon_TranslateActivity( Activity baseAct, bool *pRequired = NULL ); + void Weapon_SetActivity( Activity newActivity, float duration ); + virtual void Weapon_FrameUpdate( void ); + virtual void Weapon_HandleAnimEvent( animevent_t *pEvent ); + CBaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class + virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); // True is allowed to use this class of weapon + virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); // Adds weapon to player + virtual bool Weapon_EquipAmmoOnly( CBaseCombatWeapon *pWeapon ); // Adds weapon ammo to player, leaves weapon + bool Weapon_Detach( CBaseCombatWeapon *pWeapon ); // Clear any pointers to the weapon. + virtual void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL ); + virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); // Switch to given weapon if has ammo (false if failed) + virtual Vector Weapon_ShootPosition( ); // gun position at current position/orientation + bool Weapon_IsOnGround( CBaseCombatWeapon *pWeapon ); + CBaseEntity* Weapon_FindUsable( const Vector &range ); // search for a usable weapon in this range + virtual bool Weapon_CanSwitchTo(CBaseCombatWeapon *pWeapon); + virtual bool Weapon_SlotOccupied( CBaseCombatWeapon *pWeapon ); + virtual CBaseCombatWeapon *Weapon_GetSlot( int slot ) const; + CBaseCombatWeapon *Weapon_GetWpnForAmmo( int iAmmoIndex ); + + + // For weapon strip + void Weapon_DropAll( bool bDisallowWeaponPickup = false ); + + virtual bool AddPlayerItem( CBaseCombatWeapon *pItem ) { return false; } + virtual bool RemovePlayerItem( CBaseCombatWeapon *pItem ) { return false; } + + virtual bool CanBecomeServerRagdoll( void ) { return true; } + + // ----------------------- + // Damage + // ----------------------- + // Don't override this for characters, override the per-life-state versions below + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + // Override these to control how your character takes damage in different states + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual int OnTakeDamage_Dying( const CTakeDamageInfo &info ); + virtual int OnTakeDamage_Dead( const CTakeDamageInfo &info ); + + virtual float GetAliveDuration( void ) const; // return time we have been alive (only valid when alive) + + virtual void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) {} + virtual void NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity ) {} + virtual bool HasEverBeenInjured( int team = TEAM_ANY ) const; // return true if we have ever been injured by a member of the given team + virtual float GetTimeSinceLastInjury( int team = TEAM_ANY ) const; // return time since we were hurt by a member of the given team + + + virtual void OnPlayerKilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) {} + + // utility function to calc damage force + Vector CalcDamageForceVector( const CTakeDamageInfo &info ); + + virtual int BloodColor(); + virtual Activity GetDeathActivity( void ); + + virtual bool CorpseGib( const CTakeDamageInfo &info ); + virtual void CorpseFade( void ); // Called instead of GibNPC() when gibs are disabled + virtual bool HasHumanGibs( void ); + virtual bool HasAlienGibs( void ); + virtual bool ShouldGib( const CTakeDamageInfo &info ) { return false; } // Always ragdoll, unless specified by the leaf class + + float GetDamageAccumulator() { return m_flDamageAccumulator; } + int GetDamageCount( void ) { return m_iDamageCount; } // # of times NPC has been damaged. used for tracking 1-shot kills. + + // Character killed (only fired once) + virtual void Event_Killed( const CTakeDamageInfo &info ); + + // Killed a character + void InputKilledNPC( inputdata_t &inputdata ); + virtual void OnKilledNPC( CBaseCombatCharacter *pKilled ) {}; + + // Exactly one of these happens immediately after killed (gibbed may happen later when the corpse gibs) + // Character gibbed or faded out (violence controls) (only fired once) + // returns true if gibs were spawned + virtual bool Event_Gibbed( const CTakeDamageInfo &info ); + // Character entered the dying state without being gibbed (only fired once) + virtual void Event_Dying( const CTakeDamageInfo &info ); + virtual void Event_Dying(); + // character died and should become a ragdoll now + // return true if converted to a ragdoll, false to use AI death + virtual bool BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector ); + virtual void FixupBurningServerRagdoll( CBaseEntity *pRagdoll ); + + virtual bool BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags ); + + CBaseEntity *FindHealthItem( const Vector &vecPosition, const Vector &range ); + + + virtual CBaseEntity *CheckTraceHullAttack( float flDist, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float forceScale = 1.0f, bool bDamageAnyNPC = false ); + virtual CBaseEntity *CheckTraceHullAttack( const Vector &vStart, const Vector &vEnd, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float flForceScale = 1.0f, bool bDamageAnyNPC = false ); + + virtual CBaseCombatCharacter *MyCombatCharacterPointer( void ) { return this; } + + // VPHYSICS + virtual void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent ); + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + float CalculatePhysicsStressDamage( vphysics_objectstress_t *pStressOut, IPhysicsObject *pPhysics ); + void ApplyStressDamage( IPhysicsObject *pPhysics, bool bRequireLargeObject ); + + virtual void PushawayTouch( CBaseEntity *pOther ) {} + + void SetImpactEnergyScale( float fScale ) { m_impactEnergyScale = fScale; } + + virtual void UpdateOnRemove( void ); + + virtual Disposition_t IRelationType( CBaseEntity *pTarget ); + virtual int IRelationPriority( CBaseEntity *pTarget ); + + virtual void SetLightingOriginRelative( CBaseEntity *pLightingOrigin ); + +protected: + Relationship_t *FindEntityRelationship( CBaseEntity *pTarget ); + +public: + + // Vehicle queries + virtual bool IsInAVehicle( void ) const { return false; } + virtual IServerVehicle *GetVehicle( void ) { return NULL; } + virtual CBaseEntity *GetVehicleEntity( void ) { return NULL; } + virtual bool ExitVehicle( void ) { return false; } + + // Blood color (see BLOOD_COLOR_* macros in baseentity.h) + void SetBloodColor( int nBloodColor ); + + // Weapons.. + CBaseCombatWeapon* GetActiveWeapon() const; + int WeaponCount() const; + CBaseCombatWeapon* GetWeapon( int i ) const; + bool RemoveWeapon( CBaseCombatWeapon *pWeapon ); + virtual void RemoveAllWeapons(); + WeaponProficiency_t GetCurrentWeaponProficiency() { return m_CurrentWeaponProficiency; } + void SetCurrentWeaponProficiency( WeaponProficiency_t iProficiency ) { m_CurrentWeaponProficiency = iProficiency; } + virtual WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); + virtual Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL ); + virtual float GetSpreadBias( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ); + virtual void DoMuzzleFlash(); + + // Interactions + static void InitInteractionSystem(); + + // Relationships + static void AllocateDefaultRelationships( ); + static void SetDefaultRelationship( Class_T nClass, Class_T nClassTarget, Disposition_t nDisposition, int nPriority ); + Disposition_t GetDefaultRelationshipDisposition( Class_T nClassTarget ); + virtual void AddEntityRelationship( CBaseEntity *pEntity, Disposition_t nDisposition, int nPriority ); + virtual bool RemoveEntityRelationship( CBaseEntity *pEntity ); + virtual void AddClassRelationship( Class_T nClass, Disposition_t nDisposition, int nPriority ); + + virtual void ChangeTeam( int iTeamNum ); + + // Nav hull type + Hull_t GetHullType() const { return m_eHull; } + void SetHullType( Hull_t hullType ) { m_eHull = hullType; } + + // FIXME: The following 3 methods are backdoor hack methods + + // This is a sort of hack back-door only used by physgun! + void SetAmmoCount( int iCount, int iAmmoIndex ); + + // This is a hack to blat out the current active weapon... + // Used by weapon_slam + game_ui + void SetActiveWeapon( CBaseCombatWeapon *pNewWeapon ); + void ClearActiveWeapon() { SetActiveWeapon( NULL ); } + virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) {} + + // I can't use my current weapon anymore. Switch me to the next best weapon. + bool SwitchToNextBestWeapon(CBaseCombatWeapon *pCurrent); + + // This is a hack to copy the relationship strings used by monstermaker + void SetRelationshipString( string_t theString ) { m_RelationshipString = theString; } + + float GetNextAttack() const { return m_flNextAttack; } + void SetNextAttack( float flWait ) { m_flNextAttack = flWait; } + + bool m_bForceServerRagdoll; + + // Pickup prevention + bool IsAllowedToPickupWeapons( void ) { return !m_bPreventWeaponPickup; } + void SetPreventWeaponPickup( bool bPrevent ) { m_bPreventWeaponPickup = bPrevent; } + bool m_bPreventWeaponPickup; + + virtual CNavArea *GetLastKnownArea( void ) const { return m_lastNavArea; } // return the last nav area the player occupied - NULL if unknown + virtual bool IsAreaTraversable( const CNavArea *area ) const; // return true if we can use the given area + virtual void ClearLastKnownArea( void ); + virtual void UpdateLastKnownArea( void ); // invoke this to update our last known nav area (since there is no think method chained to CBaseCombatCharacter) + virtual void OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea ) { } // invoked (by UpdateLastKnownArea) when we enter a new nav area (or it is reset to NULL) + virtual void OnNavAreaRemoved( CNavArea *removedArea ); + + // ----------------------- + // Notification from INextBots. + // ----------------------- + virtual void OnPursuedBy( INextBot * RESTRICT pPursuer ){} // called every frame while pursued by a bot in DirectChase. + +#ifdef GLOWS_ENABLE + // Glows + void AddGlowEffect( void ); + void RemoveGlowEffect( void ); + bool IsGlowEffectActive( void ); +#endif // GLOWS_ENABLE + +#ifdef INVASION_DLL +public: + + + // TF2 Powerups + virtual bool CanBePoweredUp( void ); + bool HasPowerup( int iPowerup ); + virtual bool CanPowerupNow( int iPowerup ); // Return true if I can be powered by this powerup right now + virtual bool CanPowerupEver( int iPowerup ); // Return true if I ever accept this powerup type + + void SetPowerup( int iPowerup, bool bState, float flTime = 0, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL ); + virtual bool AttemptToPowerup( int iPowerup, float flTime, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL ); + virtual float PowerupDuration( int iPowerup, float flTime ); + virtual void PowerupStart( int iPowerup, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL ); + virtual void PowerupEnd( int iPowerup ); + + void PowerupThink( void ); + virtual void PowerupThink( int iPowerup ); + +public: + + CNetworkVar( int, m_iPowerups ); + float m_flPowerupAttemptTimes[ MAX_POWERUPS ]; + float m_flPowerupEndTimes[ MAX_POWERUPS ]; + float m_flFractionalBoost; // POWERUP_BOOST health fraction - specific powerup data + +#endif + +public: + // returns the last body region that took damage + int LastHitGroup() const { return m_LastHitGroup; } +protected: + void SetLastHitGroup( int nHitGroup ) { m_LastHitGroup = nHitGroup; } + +public: + CNetworkVar( float, m_flNextAttack ); // cannot attack again until this time + +#ifdef GLOWS_ENABLE +protected: + CNetworkVar( bool, m_bGlowEnabled ); +#endif // GLOWS_ENABLE + +private: + Hull_t m_eHull; + + void UpdateGlowEffect( void ); + void DestroyGlowEffect( void ); + +protected: + int m_bloodColor; // color of blood particless + + // ------------------- + // combat ability data + // ------------------- + float m_flFieldOfView; // cosine of field of view for this character + Vector m_HackedGunPos; // HACK until we can query end of gun + string_t m_RelationshipString; // Used to load up relationship keyvalues + float m_impactEnergyScale;// scale the amount of energy used to calculate damage this ent takes due to physics + +public: + static int GetInteractionID(); // Returns the next interaction # + +protected: + // Visibility-related stuff + bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const; +private: + // For weapon strip + void ThrowDirForWeaponStrip( CBaseCombatWeapon *pWeapon, const Vector &vecForward, Vector *pVecThrowDir ); + void DropWeaponForWeaponStrip( CBaseCombatWeapon *pWeapon, const Vector &vecForward, const QAngle &vecAngles, float flDiameter ); + + friend class CScriptedTarget; // needs to access GetInteractionID() + + static int m_lastInteraction; // Last registered interaction # + static Relationship_t** m_DefaultRelationship; + + // attack/damage + int m_LastHitGroup; // the last body region that took damage + float m_flDamageAccumulator; // so very small amounts of damage do not get lost. + int m_iDamageCount; // # of times NPC has been damaged. used for tracking 1-shot kills. + + // Weapon proficiency gets calculated each time an NPC changes his weapon, and then + // cached off as the CurrentWeaponProficiency. + WeaponProficiency_t m_CurrentWeaponProficiency; + + // --------------- + // Relationships + // --------------- + CUtlVector m_Relationship; // Array of relationships + +protected: + // shared ammo slots + CNetworkArrayForDerived( int, m_iAmmo, MAX_AMMO_SLOTS ); + + // Usable character items + CNetworkArray( CBaseCombatWeaponHandle, m_hMyWeapons, MAX_WEAPONS ); + + CNetworkHandle( CBaseCombatWeapon, m_hActiveWeapon ); + + friend class CCleanupDefaultRelationShips; + + IntervalTimer m_aliveTimer; + + unsigned int m_hasBeenInjured; // bitfield corresponding to team ID that did the injury + + // we do this because MAX_TEAMS is 32, which is wasteful for most games + enum { MAX_DAMAGE_TEAMS = 4 }; + struct DamageHistory + { + int team; // which team hurt us (TEAM_INVALID means slot unused) + IntervalTimer interval; // how long has it been + }; + DamageHistory m_damageHistory[ MAX_DAMAGE_TEAMS ]; + + // last known navigation area of player - NULL if unknown + CNavArea *m_lastNavArea; + CAI_MoveMonitor m_NavAreaUpdateMonitor; + int m_registeredNavTeam; // ugly, but needed to clean up player team counts in nav mesh +}; + + +inline float CBaseCombatCharacter::GetAliveDuration( void ) const +{ + return m_aliveTimer.GetElapsedTime(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline int CBaseCombatCharacter::WeaponCount() const +{ + return MAX_WEAPONS; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : i - +//----------------------------------------------------------------------------- +inline CBaseCombatWeapon *CBaseCombatCharacter::GetWeapon( int i ) const +{ + Assert( (i >= 0) && (i < MAX_WEAPONS) ); + return m_hMyWeapons[i].Get(); +} + +#ifdef INVASION_DLL +// Powerup Inlines +inline bool CBaseCombatCharacter::CanBePoweredUp( void ) { return true; } +inline float CBaseCombatCharacter::PowerupDuration( int iPowerup, float flTime ) { return flTime; } +inline void CBaseCombatCharacter::PowerupEnd( int iPowerup ) { return; } +inline void CBaseCombatCharacter::PowerupThink( int iPowerup ) { return; } +#endif + +EXTERN_SEND_TABLE(DT_BaseCombatCharacter); + +void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTraceFilterMelee : public CTraceFilterEntitiesOnly +{ +public: + // It does have a base, but we'll never network anything below here.. + DECLARE_CLASS_NOBASE( CTraceFilterMelee ); + + CTraceFilterMelee( const IHandleEntity *passentity, int collisionGroup, CTakeDamageInfo *dmgInfo, float flForceScale, bool bDamageAnyNPC ) + : m_pPassEnt(passentity), m_collisionGroup(collisionGroup), m_dmgInfo(dmgInfo), m_pHit(NULL), m_flForceScale(flForceScale), m_bDamageAnyNPC(bDamageAnyNPC) + { + } + + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + +public: + const IHandleEntity *m_pPassEnt; + int m_collisionGroup; + CTakeDamageInfo *m_dmgInfo; + CBaseEntity *m_pHit; + float m_flForceScale; + bool m_bDamageAnyNPC; +}; + +#endif // BASECOMBATCHARACTER_H diff --git a/game/server/basecombatweapon.h b/game/server/basecombatweapon.h new file mode 100644 index 0000000..0af362c --- /dev/null +++ b/game/server/basecombatweapon.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMBATWEAPON_H +#define COMBATWEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "entityoutput.h" +#include "basecombatweapon_shared.h" + +//----------------------------------------------------------------------------- +// Bullet types +//----------------------------------------------------------------------------- + +// ----------------------------------------- +// Sounds +// ----------------------------------------- + +struct animevent_t; + +extern void SpawnBlood(Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage); + +#endif // COMBATWEAPON_H diff --git a/game/server/baseentity.h b/game/server/baseentity.h new file mode 100644 index 0000000..a168e73 --- /dev/null +++ b/game/server/baseentity.h @@ -0,0 +1,2737 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEENTITY_H +#define BASEENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#define TEAMNUM_NUM_BITS 6 + +#include "entitylist.h" +#include "entityoutput.h" +#include "networkvar.h" +#include "collisionproperty.h" +#include "ServerNetworkProperty.h" +#include "shareddefs.h" +#include "engine/ivmodelinfo.h" + +class CDamageModifier; +class CDmgAccumulator; + +struct CSoundParameters; + +class AI_CriteriaSet; +class IResponseSystem; +class IEntitySaveUtils; +class CRecipientFilter; +class CStudioHdr; +class ILuaObject; + +// Matching the high level concept is significantly better than other criteria +// FIXME: Could do this in the script file by making it required and bumping up weighting there instead... +#define CONCEPT_WEIGHT 5.0f + +typedef CHandle EHANDLE; + +#define MANUALMODE_GETSET_PROP(type, accessorName, varName) \ + private:\ + type varName;\ + public:\ + inline const type& Get##accessorName##() const { return varName; } \ + inline type& Get##accessorName##() { return varName; } \ + inline void Set##accessorName##( const type &val ) { varName = val; m_NetStateMgr.StateChanged(); } + +#define MANUALMODE_GETSET_EHANDLE(type, accessorName, varName) \ + private:\ + CHandle varName;\ + public:\ + inline type* Get##accessorName##() { return varName.Get(); } \ + inline void Set##accessorName##( type *pType ) { varName = pType; m_NetStateMgr.StateChanged(); } + + +// saverestore.h declarations +class CSaveRestoreData; +struct typedescription_t; +class ISave; +class IRestore; +class CBaseEntity; +class CEntityMapData; +class CBaseCombatWeapon; +class IPhysicsObject; +class IPhysicsShadowController; +class CBaseCombatCharacter; +class CTeam; +class Vector; +struct gamevcollisionevent_t; +class CBaseAnimating; +class CBasePlayer; +class IServerVehicle; +struct solid_t; +struct notify_system_event_params_t; +class CAI_BaseNPC; +class CAI_Senses; +class CSquadNPC; +class variant_t; +class CEventAction; +typedef struct KeyValueData_s KeyValueData; +class CUserCmd; +class CSkyCamera; +class CEntityMapData; +class INextBot; +class IHasAttributes; + +typedef CUtlVector< CBaseEntity* > EntityList_t; + +#if defined( HL2_DLL ) + +// For CLASSIFY +enum Class_T +{ + CLASS_NONE=0, + CLASS_PLAYER, + CLASS_PLAYER_ALLY, + CLASS_PLAYER_ALLY_VITAL, + CLASS_ANTLION, + CLASS_BARNACLE, + CLASS_BULLSEYE, + //CLASS_BULLSQUID, + CLASS_CITIZEN_PASSIVE, + CLASS_CITIZEN_REBEL, + CLASS_COMBINE, + CLASS_COMBINE_GUNSHIP, + CLASS_CONSCRIPT, + CLASS_HEADCRAB, + //CLASS_HOUNDEYE, + CLASS_MANHACK, + CLASS_METROPOLICE, + CLASS_MILITARY, + CLASS_SCANNER, + CLASS_STALKER, + CLASS_VORTIGAUNT, + CLASS_ZOMBIE, + CLASS_PROTOSNIPER, + CLASS_MISSILE, + CLASS_FLARE, + CLASS_EARTH_FAUNA, + CLASS_HACKED_ROLLERMINE, + CLASS_COMBINE_HUNTER, + + NUM_AI_CLASSES +}; + +#elif defined( HL1_DLL ) + +enum Class_T +{ + CLASS_NONE = 0, + CLASS_MACHINE, + CLASS_PLAYER, + CLASS_HUMAN_PASSIVE, + CLASS_HUMAN_MILITARY, + CLASS_ALIEN_MILITARY, + CLASS_ALIEN_MONSTER, + CLASS_ALIEN_PREY, + CLASS_ALIEN_PREDATOR, + CLASS_INSECT, + CLASS_PLAYER_ALLY, + CLASS_PLAYER_BIOWEAPON, + CLASS_ALIEN_BIOWEAPON, + + NUM_AI_CLASSES +}; + +#elif defined( INVASION_DLL ) + +enum Class_T +{ + CLASS_NONE = 0, + CLASS_PLAYER, + CLASS_PLAYER_ALLY, + CLASS_PLAYER_ALLY_VITAL, + CLASS_ANTLION, + CLASS_BARNACLE, + CLASS_BULLSEYE, + //CLASS_BULLSQUID, + CLASS_CITIZEN_PASSIVE, + CLASS_CITIZEN_REBEL, + CLASS_COMBINE, + CLASS_COMBINE_GUNSHIP, + CLASS_CONSCRIPT, + CLASS_HEADCRAB, + //CLASS_HOUNDEYE, + CLASS_MANHACK, + CLASS_METROPOLICE, + CLASS_MILITARY, + CLASS_SCANNER, + CLASS_STALKER, + CLASS_VORTIGAUNT, + CLASS_ZOMBIE, + CLASS_PROTOSNIPER, + CLASS_MISSILE, + CLASS_FLARE, + CLASS_EARTH_FAUNA, + NUM_AI_CLASSES +}; + +#elif defined( CSTRIKE_DLL ) + +enum Class_T +{ + CLASS_NONE = 0, + CLASS_PLAYER, + CLASS_PLAYER_ALLY, + NUM_AI_CLASSES +}; + +#else + +enum Class_T +{ + CLASS_NONE = 0, + CLASS_PLAYER, + CLASS_PLAYER_ALLY, + NUM_AI_CLASSES +}; + +#endif + +// +// Structure passed to input handlers. +// +struct inputdata_t +{ + CBaseEntity *pActivator; // The entity that initially caused this chain of output events. + CBaseEntity *pCaller; // The entity that fired this particular output. + variant_t value; // The data parameter for this output. + int nOutputID; // The unique ID of the output that was fired. +}; + +// Serializable list of context as set by entity i/o and used for deducing proper +// speech state, et al. +struct ResponseContext_t +{ + DECLARE_SIMPLE_DATADESC(); + + string_t m_iszName; + string_t m_iszValue; + float m_fExpirationTime; // when to expire context (0 == never) +}; + + +//----------------------------------------------------------------------------- +// Entity events... targetted to a particular entity +// Each event has a well defined structure to use for parameters +//----------------------------------------------------------------------------- +enum EntityEvent_t +{ + ENTITY_EVENT_WATER_TOUCH = 0, // No data needed + ENTITY_EVENT_WATER_UNTOUCH, // No data needed + ENTITY_EVENT_PARENT_CHANGED, // No data needed +}; + + +//----------------------------------------------------------------------------- + +typedef void (CBaseEntity::*BASEPTR)(void); +typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther ); +typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +#define DEFINE_THINKFUNC( function ) DEFINE_FUNCTION_RAW( function, BASEPTR ) +#define DEFINE_ENTITYFUNC( function ) DEFINE_FUNCTION_RAW( function, ENTITYFUNCPTR ) +#define DEFINE_USEFUNC( function ) DEFINE_FUNCTION_RAW( function, USEPTR ) + +// Things that toggle (buttons/triggers/doors) need this +enum TOGGLE_STATE +{ + TS_AT_TOP, + TS_AT_BOTTOM, + TS_GOING_UP, + TS_GOING_DOWN +}; + + +// Debug overlay bits +enum DebugOverlayBits_t +{ + OVERLAY_TEXT_BIT = 0x00000001, // show text debug overlay for this entity + OVERLAY_NAME_BIT = 0x00000002, // show name debug overlay for this entity + OVERLAY_BBOX_BIT = 0x00000004, // show bounding box overlay for this entity + OVERLAY_PIVOT_BIT = 0x00000008, // show pivot for this entity + OVERLAY_MESSAGE_BIT = 0x00000010, // show messages for this entity + OVERLAY_ABSBOX_BIT = 0x00000020, // show abs bounding box overlay + OVERLAY_RBOX_BIT = 0x00000040, // show the rbox overlay + OVERLAY_SHOW_BLOCKSLOS = 0x00000080, // show entities that block NPC LOS + OVERLAY_ATTACHMENTS_BIT = 0x00000100, // show attachment points + OVERLAY_AUTOAIM_BIT = 0x00000200, // Display autoaim radius + + OVERLAY_NPC_SELECTED_BIT = 0x00001000, // the npc is current selected + OVERLAY_NPC_NEAREST_BIT = 0x00002000, // show the nearest node of this npc + OVERLAY_NPC_ROUTE_BIT = 0x00004000, // draw the route for this npc + OVERLAY_NPC_TRIANGULATE_BIT = 0x00008000, // draw the triangulation for this npc + OVERLAY_NPC_ZAP_BIT = 0x00010000, // destroy the NPC + OVERLAY_NPC_ENEMIES_BIT = 0x00020000, // show npc's enemies + OVERLAY_NPC_CONDITIONS_BIT = 0x00040000, // show NPC's current conditions + OVERLAY_NPC_SQUAD_BIT = 0x00080000, // show npc squads + OVERLAY_NPC_TASK_BIT = 0x00100000, // show npc task details + OVERLAY_NPC_FOCUS_BIT = 0x00200000, // show line to npc's enemy and target + OVERLAY_NPC_VIEWCONE_BIT = 0x00400000, // show npc's viewcone + OVERLAY_NPC_KILL_BIT = 0x00800000, // kill the NPC, running all appropriate AI. + + OVERLAY_WC_CHANGE_ENTITY = 0x01000000, // object changed during WC edit + OVERLAY_BUDDHA_MODE = 0x02000000, // take damage but don't die + + OVERLAY_NPC_STEERING_REGULATIONS = 0x04000000, // Show the steering regulations associated with the NPC + + OVERLAY_TASK_TEXT_BIT = 0x08000000, // show task and schedule names when they start + + OVERLAY_PROP_DEBUG = 0x10000000, + + OVERLAY_NPC_RELATION_BIT = 0x20000000, // show relationships between target and all children + + OVERLAY_VIEWOFFSET = 0x40000000, // show view offset +}; + +struct TimedOverlay_t; + +/* ========= CBaseEntity ======== + + All objects in the game are derived from this. + +a list of all CBaseEntitys is kept in gEntList +================================ */ + +// creates an entity by string name, but does not spawn it +// If iForceEdictIndex is not -1, then it will use the edict by that index. If the index is +// invalid or there is already an edict using that index, it will error out. +CBaseEntity *CreateEntityByName( const char *className, int iForceEdictIndex = -1 ); +CBaseNetworkable *CreateNetworkableByName( const char *className ); + +// creates an entity and calls all the necessary spawn functions +extern void SpawnEntityByName( const char *className, CEntityMapData *mapData = NULL ); + +// calls the spawn functions for an entity +extern int DispatchSpawn( CBaseEntity *pEntity ); + +inline CBaseEntity *GetContainingEntity( edict_t *pent ); + +//----------------------------------------------------------------------------- +// Purpose: think contexts +//----------------------------------------------------------------------------- +struct thinkfunc_t +{ + BASEPTR m_pfnThink; + string_t m_iszContext; + int m_nNextThinkTick; + int m_nLastThinkTick; + + DECLARE_SIMPLE_DATADESC(); +}; + +struct EmitSound_t; +struct rotatingpushmove_t; + +#define CREATE_PREDICTED_ENTITY( className ) \ + CBaseEntity::CreatePredictedEntityByName( className, __FILE__, __LINE__ ); + +// +// Base Entity. All entity types derive from this +// +class CBaseEntity : public IServerEntity +{ +public: + DECLARE_CLASS_NOBASE( CBaseEntity ); + + //---------------------------------------- + // Class vars and functions + //---------------------------------------- + static inline void Debug_Pause(bool bPause); + static inline bool Debug_IsPaused(void); + static inline void Debug_SetSteps(int nSteps); + static inline bool Debug_ShouldStep(void); + static inline bool Debug_Step(void); + + static bool m_bInDebugSelect; + static int m_nDebugPlayer; + +protected: + + static bool m_bDebugPause; // Whether entity i/o is paused for debugging. + static int m_nDebugSteps; // Number of entity outputs to fire before pausing again. + + static bool sm_bDisableTouchFuncs; // Disables PhysicsTouch and PhysicsStartTouch function calls +public: + static bool sm_bAccurateTriggerBboxChecks; // SOLID_BBOX entities do a fully accurate trigger vs bbox check when this is set + +public: + // If bServerOnly is true, then the ent never goes to the client. This is used + // by logical entities. + CBaseEntity( bool bServerOnly=false ); + virtual ~CBaseEntity(); + + // prediction system + DECLARE_PREDICTABLE(); + // network data + DECLARE_SERVERCLASS(); + // data description + DECLARE_DATADESC(); + + // memory handling + void *operator new( size_t stAllocateBlock ); + void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); + void operator delete( void *pMem ); + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete(pMem); } + + // Class factory + static CBaseEntity *CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist = false ); + +// IHandleEntity overrides. +public: + virtual void SetRefEHandle( const CBaseHandle &handle ); + virtual const CBaseHandle& GetRefEHandle() const; + +// IServerUnknown overrides + virtual ICollideable *GetCollideable(); + virtual IServerNetworkable *GetNetworkable(); + virtual CBaseEntity *GetBaseEntity(); + +// IServerEntity overrides. +public: + virtual void SetModelIndex( int index ); + virtual int GetModelIndex( void ) const; + virtual string_t GetModelName( void ) const; + + void ClearModelIndexOverrides( void ); + virtual void SetModelIndexOverride( int index, int nValue ); + +public: + // virtual methods for derived classes to override + virtual bool TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace ); + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual void ComputeWorldSpaceSurroundingBox( Vector *pWorldMins, Vector *pWorldMaxs ); + + // non-virtual methods. Don't override these! +public: + // An inline version the game code can use + CCollisionProperty *CollisionProp(); + const CCollisionProperty*CollisionProp() const; + CServerNetworkProperty *NetworkProp(); + const CServerNetworkProperty *NetworkProp() const; + + bool IsCurrentlyTouching( void ) const; + const Vector& GetAbsOrigin( void ) const; + const QAngle& GetAbsAngles( void ) const; + + SolidType_t GetSolid() const; + int GetSolidFlags( void ) const; + + int GetEFlags() const; + void SetEFlags( int iEFlags ); + void AddEFlags( int nEFlagMask ); + void RemoveEFlags( int nEFlagMask ); + bool IsEFlagSet( int nEFlagMask ) const; + + // Quick way to ask if we have a player entity as a child anywhere in our hierarchy. + void RecalcHasPlayerChildBit(); + bool DoesHavePlayerChild(); + + bool IsTransparent() const; + + void SetNavIgnore( float duration = FLT_MAX ); + void ClearNavIgnore(); + bool IsNavIgnored() const; + + // Is the entity floating? + bool IsFloating(); + + // Called by physics to see if we should avoid a collision test.... + virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const; + + // Move type / move collide + MoveType_t GetMoveType() const; + MoveCollide_t GetMoveCollide() const; + void SetMoveType( MoveType_t val, MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT ); + void SetMoveCollide( MoveCollide_t val ); + + // Returns the entity-to-world transform + matrix3x4_t &EntityToWorldTransform(); + const matrix3x4_t &EntityToWorldTransform() const; + + // Some helper methods that transform a point from entity space to world space + back + void EntityToWorldSpace( const Vector &in, Vector *pOut ) const; + void WorldToEntitySpace( const Vector &in, Vector *pOut ) const; + + // This function gets your parent's transform. If you're parented to an attachment, + // this calculates the attachment's transform and gives you that. + // + // You must pass in tempMatrix for scratch space - it may need to fill that in and return it instead of + // pointing you right at a variable in your parent. + matrix3x4_t& GetParentToWorldTransform( matrix3x4_t &tempMatrix ); + + // Externalized data objects ( see sharreddefs.h for DataObjectType_t ) + bool HasDataObjectType( int type ) const; + void AddDataObjectType( int type ); + void RemoveDataObjectType( int type ); + + void *GetDataObject( int type ); + void *CreateDataObject( int type ); + void DestroyDataObject( int type ); + void DestroyAllDataObjects( void ); + +public: + void SetScaledPhysics( IPhysicsObject *pNewObject ); + + // virtual methods; you can override these +public: + // Owner entity. + // FIXME: These are virtual only because of CNodeEnt + CBaseEntity *GetOwnerEntity() const; + virtual void SetOwnerEntity( CBaseEntity* pOwner ); + void SetEffectEntity( CBaseEntity *pEffectEnt ); + CBaseEntity *GetEffectEntity() const; + + // Only CBaseEntity implements these. CheckTransmit calls the virtual ShouldTransmit to see if the + // entity wants to be sent. If so, it calls SetTransmit, which will mark any dependents for transmission too. + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + + // update the global transmit state if a transmission rule changed + int SetTransmitState( int nFlag); + int GetTransmitState( void ); + int DispatchUpdateTransmitState(); + + // Do NOT call this directly. Use DispatchUpdateTransmitState. + virtual int UpdateTransmitState(); + + // Entities (like ropes) use this to own the transmit state of another entity + // by forcing it to not call UpdateTransmitState. + void IncrementTransmitStateOwnedCounter(); + void DecrementTransmitStateOwnedCounter(); + + // This marks the entity for transmission and passes the SetTransmit call to any dependents. + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + // This function finds out if the entity is in the 3D skybox. If so, it sets the EFL_IN_SKYBOX + // flag so the entity gets transmitted to all the clients. + // Entities usually call this during their Activate(). + // Returns true if the entity is in the skybox (and EFL_IN_SKYBOX was set). + bool DetectInSkybox(); + + // Returns which skybox the entity is in + CSkyCamera *GetEntitySkybox(); + + bool IsSimulatedEveryTick() const; + bool IsAnimatedEveryTick() const; + void SetSimulatedEveryTick( bool sim ); + void SetAnimatedEveryTick( bool anim ); + +public: + + virtual const char *GetTracerType( void ); + + // returns a pointer to the entities edict, if it has one. should be removed! + inline edict_t *edict( void ) { return NetworkProp()->edict(); } + inline const edict_t *edict( void ) const { return NetworkProp()->edict(); } + inline int entindex( ) const { return m_Network.entindex(); }; + inline int GetSoundSourceIndex() const { return entindex(); } + + // These methods encapsulate MOVETYPE_FOLLOW, which became obsolete + void FollowEntity( CBaseEntity *pBaseEntity, bool bBoneMerge = true ); + void StopFollowingEntity( ); // will also change to MOVETYPE_NONE + bool IsFollowingEntity(); + CBaseEntity *GetFollowedEntity(); + + // initialization + virtual void Spawn( void ); + virtual void Precache( void ) {} + + virtual void SetModel( const char *szModelName ); + +protected: + // Notification on model load. May be called multiple times for dynamic models. + // Implementations must call BaseClass::OnNewModel and pass return value through. + virtual CStudioHdr *OnNewModel(); + +public: + virtual void PostConstructor( const char *szClassname ); + virtual void PostClientActive( void ); + virtual void ParseMapData( CEntityMapData *mapData ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual bool KeyValue( const char *szKeyName, float flValue ); + virtual bool KeyValue( const char *szKeyName, const Vector &vecValue ); + virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); + + void ValidateEntityConnections(); + void FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay = 0.0f ); + + // Activate - called for each entity after each load game and level load + virtual void Activate( void ); + + // Hierarchy traversal + CBaseEntity *GetMoveParent( void ); + CBaseEntity *GetRootMoveParent(); + CBaseEntity *FirstMoveChild( void ); + CBaseEntity *NextMovePeer( void ); + + void SetName( string_t newTarget ); + void SetParent( string_t newParent, CBaseEntity *pActivator, int iAttachment = -1 ); + + // Set the movement parent. Your local origin and angles will become relative to this parent. + // If iAttachment is a valid attachment on the parent, then your local origin and angles + // are relative to the attachment on this entity. If iAttachment == -1, it'll preserve the + // current m_iParentAttachment. + virtual void SetParent( CBaseEntity* pNewParent, int iAttachment = -1 ); + CBaseEntity* GetParent(); + int GetParentAttachment(); + + string_t GetEntityName(); + + bool NameMatches( const char *pszNameOrWildcard ); + bool ClassMatches( const char *pszClassOrWildcard ); + bool NameMatches( string_t nameStr ); + bool ClassMatches( string_t nameStr ); + +private: + bool NameMatchesComplex( const char *pszNameOrWildcard ); + bool ClassMatchesComplex( const char *pszClassOrWildcard ); + void TransformStepData_WorldToParent( CBaseEntity *pParent ); + void TransformStepData_ParentToParent( CBaseEntity *pOldParent, CBaseEntity *pNewParent ); + void TransformStepData_ParentToWorld( CBaseEntity *pParent ); + + +public: + int GetSpawnFlags( void ) const; + void AddSpawnFlags( int nFlags ); + void RemoveSpawnFlags( int nFlags ); + void ClearSpawnFlags( void ); + bool HasSpawnFlags( int nFlags ) const; + + int GetEffects( void ) const; + void AddEffects( int nEffects ); + void RemoveEffects( int nEffects ); + void ClearEffects( void ); + void SetEffects( int nEffects ); + bool IsEffectActive( int nEffects ) const; + + // makes the entity inactive + void MakeDormant( void ); + int IsDormant( void ); + + void RemoveDeferred( void ); // Sets the entity invisible, and makes it remove itself on the next frame + + // checks to see if the entity is marked for deletion + bool IsMarkedForDeletion( void ); + + // capabilities + virtual int ObjectCaps( void ); + + // Verifies that the data description is valid in debug builds. + #ifdef _DEBUG + void ValidateDataDescription(void); + #endif // _DEBUG + + // handles an input (usually caused by outputs) + // returns true if the the value in the pass in should be set, false if the input is to be ignored + virtual bool AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID ); + + // + // Input handlers. + // + void InputAlternativeSorting( inputdata_t &inputdata ); + void InputAlpha( inputdata_t &inputdata ); + void InputColor( inputdata_t &inputdata ); + void InputSetParent( inputdata_t &inputdata ); + void SetParentAttachment( const char *szInputName, const char *szAttachment, bool bMaintainOffset ); + void InputSetParentAttachment( inputdata_t &inputdata ); + void InputSetParentAttachmentMaintainOffset( inputdata_t &inputdata ); + void InputClearParent( inputdata_t &inputdata ); + void InputSetTeam( inputdata_t &inputdata ); + void InputUse( inputdata_t &inputdata ); + void InputKill( inputdata_t &inputdata ); + void InputKillHierarchy( inputdata_t &inputdata ); + void InputSetDamageFilter( inputdata_t &inputdata ); + void InputDispatchEffect( inputdata_t &inputdata ); + void InputEnableDamageForces( inputdata_t &inputdata ); + void InputDisableDamageForces( inputdata_t &inputdata ); + void InputAddContext( inputdata_t &inputdata ); + void InputRemoveContext( inputdata_t &inputdata ); + void InputClearContext( inputdata_t &inputdata ); + void InputDispatchResponse( inputdata_t& inputdata ); + void InputDisableShadow( inputdata_t &inputdata ); + void InputEnableShadow( inputdata_t &inputdata ); + void InputAddOutput( inputdata_t &inputdata ); + void InputFireUser1( inputdata_t &inputdata ); + void InputFireUser2( inputdata_t &inputdata ); + void InputFireUser3( inputdata_t &inputdata ); + void InputFireUser4( inputdata_t &inputdata ); + + // Returns the origin at which to play an inputted dispatcheffect + virtual void GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles ); + + // tries to read a field from the entities data description - result is placed in variant_t + bool ReadKeyField( const char *varName, variant_t *var ); + + // classname access + void SetClassname( const char *className ); + const char* GetClassname(); + + // Debug Overlays + void EntityText( int text_offset, const char *text, float flDuration, int r = 255, int g = 255, int b = 255, int a = 255 ); + const char *GetDebugName(void); // do not make this virtual -- designed to handle NULL this + virtual void DrawDebugGeometryOverlays(void); + virtual int DrawDebugTextOverlays(void); + void DrawTimedOverlays( void ); + void DrawBBoxOverlay( float flDuration = 0.0f ); + void DrawAbsBoxOverlay(); + void DrawRBoxOverlay(); + + void DrawInputOverlay(const char *szInputName, CBaseEntity *pCaller, variant_t Value); + void DrawOutputOverlay(CEventAction *ev); + void SendDebugPivotOverlay( void ); + void AddTimedOverlay( const char *msg, int endTime ); + + void SetSolid( SolidType_t val ); + + // save/restore + // only overload these if you have special data to serialize + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + virtual bool ShouldSavePhysics(); + + // handler to reset stuff before you are restored + // NOTE: Always chain to base class when implementing this! + virtual void OnSave( IEntitySaveUtils *pSaveUtils ); + + // handler to reset stuff after you are restored + // called after all entities have been loaded from all affected levels + // called before activate + // NOTE: Always chain to base class when implementing this! + virtual void OnRestore(); + + int GetTextureFrameIndex( void ); + void SetTextureFrameIndex( int iIndex ); + + // Entities block Line-Of-Sight for NPCs by default. + // Set this to false if you want to change this behavior. + void SetBlocksLOS( bool bBlocksLOS ); + bool BlocksLOS( void ); + + + void SetAIWalkable( bool bBlocksLOS ); + bool IsAIWalkable( void ); +private: + int SaveDataDescBlock( ISave &save, datamap_t *dmap ); + int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); + +public: + // Networking related methods + void NetworkStateChanged(); + void NetworkStateChanged( void *pVar ); + +public: + void CalcAbsolutePosition(); + + // returns the edict index the entity requires when used in save/restore (eg players, world) + // -1 means it doesn't require any special index + virtual int RequiredEdictIndex( void ) { return -1; } + + // interface function pts + void (CBaseEntity::*m_pfnMoveDone)(void); + virtual void MoveDone( void ) { if (m_pfnMoveDone) (this->*m_pfnMoveDone)();}; + + // Why do we have two separate static Instance functions? + static CBaseEntity *Instance( const CBaseHandle &hEnt ); + static CBaseEntity *Instance( const edict_t *pent ); + static CBaseEntity *Instance( edict_t *pent ); + static CBaseEntity* Instance( int iEnt ); + + // Think function handling + void (CBaseEntity::*m_pfnThink)(void); + virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)();}; + + // Think functions with contexts + int RegisterThinkContext( const char *szContext ); + BASEPTR ThinkSet( BASEPTR func, float flNextThinkTime = 0, const char *szContext = NULL ); + void SetNextThink( float nextThinkTime, const char *szContext = NULL ); + float GetNextThink( const char *szContext = NULL ); + float GetLastThink( const char *szContext = NULL ); + int GetNextThinkTick( const char *szContext = NULL ); + int GetLastThinkTick( const char *szContext = NULL ); + + float GetAnimTime() const; + void SetAnimTime( float at ); + + float GetSimulationTime() const; + void SetSimulationTime( float st ); + + void SetRenderMode( RenderMode_t nRenderMode ); + RenderMode_t GetRenderMode() const; + +private: + // NOTE: Keep this near vtable so it's in cache with vtable. + CServerNetworkProperty m_Network; + +public: + // members + string_t m_iClassname; // identifier for entity creation and save/restore + string_t m_iGlobalname; // identifier for carrying entity across level transitions + string_t m_iParent; // the name of the entities parent; linked into m_pParent during Activate() + + int m_iHammerID; // Hammer unique edit id number + +public: + // was pev->speed + float m_flSpeed; + // was pev->renderfx + CNetworkVar( unsigned char, m_nRenderFX ); + // was pev->rendermode + CNetworkVar( unsigned char, m_nRenderMode ); + CNetworkVar( short, m_nModelIndex ); + +#ifdef TF_DLL + CNetworkArray( int, m_nModelIndexOverrides, MAX_VISION_MODES ); // used to override the base model index on the client if necessary +#endif + + // was pev->rendercolor + CNetworkColor32( m_clrRender ); + const color32 GetRenderColor() const; + void SetRenderColor( byte r, byte g, byte b ); + void SetRenderColor( byte r, byte g, byte b, byte a ); + void SetRenderColorR( byte r ); + void SetRenderColorG( byte g ); + void SetRenderColorB( byte b ); + void SetRenderColorA( byte a ); + + // was pev->animtime: consider moving to CBaseAnimating + float m_flPrevAnimTime; + CNetworkVar( float, m_flAnimTime ); // this is the point in time that the client will interpolate to position,angle,frame,etc. + CNetworkVar( float, m_flSimulationTime ); + + void IncrementInterpolationFrame(); // Call this to cause a discontinuity (teleport) + + CNetworkVar( int, m_ubInterpolationFrame ); + + int m_nLastThinkTick; + +#if !defined( NO_ENTITY_PREDICTION ) + // Certain entities (projectiles) can be created on the client and thus need a matching id number + CNetworkVar( CPredictableId, m_PredictableID ); +#endif + + // used so we know when things are no longer touching + int touchStamp; + +protected: + + // think function handling + enum thinkmethods_t + { + THINK_FIRE_ALL_FUNCTIONS, + THINK_FIRE_BASE_ONLY, + THINK_FIRE_ALL_BUT_BASE, + }; + int GetIndexForThinkContext( const char *pszContext ); + CUtlVector< thinkfunc_t > m_aThinkFunctions; + +#ifdef _DEBUG + int m_iCurrentThinkContext; +#endif + + void RemoveExpiredConcepts( void ); + int GetContextCount() const; // Call RemoveExpiredConcepts to clean out expired concepts + const char *GetContextName( int index ) const; // note: context may be expired + const char *GetContextValue( int index ) const; // note: context may be expired + bool ContextExpired( int index ) const; + int FindContextByName( const char *name ) const; +public: + void AddContext( const char *nameandvalue ); + +protected: + CUtlVector< ResponseContext_t > m_ResponseContexts; + + // Map defined context sets + string_t m_iszResponseContext; + +private: + CBaseEntity( CBaseEntity& ); + + // list handling + friend class CGlobalEntityList; + friend class CThinkSyncTester; + + // was pev->nextthink + CNetworkVarForDerived( int, m_nNextThinkTick ); + // was pev->effects + CNetworkVar( int, m_fEffects ); + +//////////////////////////////////////////////////////////////////////////// + + +public: + + // Returns a CBaseAnimating if the entity is derived from CBaseAnimating. + virtual CBaseAnimating* GetBaseAnimating() { return 0; } + + virtual IResponseSystem *GetResponseSystem(); + virtual void DispatchResponse( const char *conceptName ); + +// Classify - returns the type of group (i.e, "houndeye", or "human military" so that NPCs with different classnames +// still realize that they are teammates. (overridden for NPCs that form groups) + virtual Class_T Classify ( void ); + virtual void DeathNotice ( CBaseEntity *pVictim ) {}// NPC maker children use this to tell the NPC maker that they have died. + virtual bool ShouldAttractAutoAim( CBaseEntity *pAimingEnt ) { return ((GetFlags() & FL_AIMTARGET) != 0); } + virtual float GetAutoAimRadius(); + virtual Vector GetAutoAimCenter() { return WorldSpaceCenter(); } + + virtual ITraceFilter* GetBeamTraceFilter( void ); + + // Call this to do a TraceAttack on an entity, performs filtering. Don't call TraceAttack() directly except when chaining up to base class + void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL ); + virtual bool PassesDamageFilter( const CTakeDamageInfo &info ); + + +protected: + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL ); + +public: + + virtual bool CanBeHitByMeleeAttack( CBaseEntity *pAttacker ) { return true; } + + // returns the amount of damage inflicted + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + // This is what you should call to apply damage to an entity. + int TakeDamage( const CTakeDamageInfo &info ); + virtual void AdjustDamageDirection( const CTakeDamageInfo &info, Vector &dir, CBaseEntity *pEnt ) {} + + virtual int TakeHealth( float flHealth, int bitsDamageType ); + + virtual bool IsAlive( void ); + // Entity killed (only fired once) + virtual void Event_Killed( const CTakeDamageInfo &info ); + + void SendOnKilledGameEvent( const CTakeDamageInfo &info ); + + // Notifier that I've killed some other entity. (called from Victim's Event_Killed). + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) { return; } + + // UNDONE: Make this data? + virtual int BloodColor( void ); + + void TraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType ); + virtual bool IsTriggered( CBaseEntity *pActivator ) {return true;} + virtual bool IsNPC( void ) const { return false; } + CAI_BaseNPC *MyNPCPointer( void ); + virtual CBaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; } + virtual INextBot *MyNextBotPointer( void ) { return NULL; } + virtual float GetDelay( void ) { return 0; } + virtual bool IsMoving( void ); + bool IsWorld() { return entindex() == 0; } + virtual char const *DamageDecal( int bitsDamageType, int gameMaterial ); + virtual void DecalTrace( trace_t *pTrace, char const *decalName ); + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName = NULL ); + + void AddPoints( int score, bool bAllowNegativeScore ); + void AddPointsToTeam( int score, bool bAllowNegativeScore ); + void RemoveAllDecals( void ); + + virtual bool OnControls( CBaseEntity *pControls ) { return false; } + virtual bool HasTarget( string_t targetname ); + virtual bool IsPlayer( void ) const { return false; } + virtual bool IsNetClient( void ) const { return false; } + virtual bool IsTemplate( void ) { return false; } + virtual bool IsBaseObject( void ) const { return false; } + virtual bool IsBaseTrain( void ) const { return false; } + bool IsBSPModel() const; + bool IsCombatCharacter() { return MyCombatCharacterPointer() == NULL ? false : true; } + bool IsInWorld( void ) const; + virtual bool IsCombatItem( void ) const { return false; } + + virtual bool IsBaseCombatWeapon( void ) const { return false; } + virtual bool IsWearable( void ) const { return false; } + virtual CBaseCombatWeapon *MyCombatWeaponPointer( void ) { return NULL; } + + // If this is a vehicle, returns the vehicle interface + virtual IServerVehicle* GetServerVehicle() { return NULL; } + + // UNDONE: Make this data instead of procedural? + virtual bool IsViewable( void ); // is this something that would be looked at (model, sprite, etc.)? + + // Team Handling + CTeam *GetTeam( void ) const; // Get the Team this entity is on + int GetTeamNumber( void ) const; // Get the Team number of the team this entity is on + virtual void ChangeTeam( int iTeamNum ); // Assign this entity to a team. + bool IsInTeam( CTeam *pTeam ) const; // Returns true if this entity's in the specified team + bool InSameTeam( CBaseEntity *pEntity ) const; // Returns true if the specified entity is on the same team as this one + bool IsInAnyTeam( void ) const; // Returns true if this entity is in any team + const char *TeamID( void ) const; // Returns the name of the team this entity is on. + + // Entity events... these are events targetted to a particular entity + // Each event defines its own well-defined event data structure + virtual void OnEntityEvent( EntityEvent_t event, void *pEventData ); + + // can stand on this entity? + bool IsStandable() const; + + // UNDONE: Do these three functions actually need to be virtual??? + virtual bool CanStandOn( CBaseEntity *pSurface ) const { return (pSurface && !pSurface->IsStandable()) ? false : true; } + virtual bool CanStandOn( edict_t *ent ) const { return CanStandOn( GetContainingEntity( ent ) ); } + virtual CBaseEntity *GetEnemy( void ) { return NULL; } + virtual CBaseEntity *GetEnemy( void ) const { return NULL; } + + + void ViewPunch( const QAngle &angleOffset ); + void VelocityPunch( const Vector &vecForce ); + + CBaseEntity *GetNextTarget( void ); + + // fundamental callbacks + void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther ); + void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther ); + + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void StartTouch( CBaseEntity *pOther ); + virtual void Touch( CBaseEntity *pOther ); + virtual void EndTouch( CBaseEntity *pOther ); + virtual void StartBlocked( CBaseEntity *pOther ) {} + virtual void Blocked( CBaseEntity *pOther ); + virtual void EndBlocked( void ) {} + + // Physics simulation + virtual void PhysicsSimulate( void ); + +public: + // HACKHACK:Get the trace_t from the last physics touch call (replaces the even-hackier global trace vars) + static const trace_t & GetTouchTrace( void ); + + // FIXME: Should be private, but I can't make em private just yet + void PhysicsImpact( CBaseEntity *other, trace_t &trace ); + void PhysicsMarkEntitiesAsTouching( CBaseEntity *other, trace_t &trace ); + void PhysicsMarkEntitiesAsTouchingEventDriven( CBaseEntity *other, trace_t &trace ); + void PhysicsTouchTriggers( const Vector *pPrevAbsOrigin = NULL ); + + // Physics helper + static void PhysicsRemoveTouchedList( CBaseEntity *ent ); + static void PhysicsNotifyOtherOfUntouch( CBaseEntity *ent, CBaseEntity *other ); + static void PhysicsRemoveToucher( CBaseEntity *other, touchlink_t *link ); + + groundlink_t *AddEntityToGroundList( CBaseEntity *other ); + void PhysicsStartGroundContact( CBaseEntity *pentOther ); + + static void PhysicsNotifyOtherOfGroundRemoval( CBaseEntity *ent, CBaseEntity *other ); + static void PhysicsRemoveGround( CBaseEntity *other, groundlink_t *link ); + static void PhysicsRemoveGroundList( CBaseEntity *ent ); + + void StartGroundContact( CBaseEntity *ground ); + void EndGroundContact( CBaseEntity *ground ); + + void SetGroundChangeTime( float flTime ); + float GetGroundChangeTime( void ); + + // Remove this as ground entity for all object resting on this object + void WakeRestingObjects(); + bool HasNPCsOnIt(); + + virtual void UpdateOnRemove( void ); + virtual void StopLoopingSounds( void ) {} + + // common member functions + void SUB_Remove( void ); + void SUB_DoNothing( void ); + void SUB_StartFadeOut( float delay = 10.0f, bool bNotSolid = true ); + void SUB_StartFadeOutInstant(); + void SUB_FadeOut ( void ); + void SUB_Vanish( void ); + void SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); } + void SUB_PerformFadeOut( void ); + virtual bool SUB_AllowedToFade( void ); + + // change position, velocity, orientation instantly + // passing NULL means no change + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + // notify that another entity (that you were watching) was teleported + virtual void NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t ¶ms ); + + int ShouldToggle( USE_TYPE useType, int currentState ); + + // UNDONE: Move these virtuals to CBaseCombatCharacter? + virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + virtual int GetTracerAttachment( void ); + virtual void FireBullets( const FireBulletsInfo_t &info ); + virtual void DoImpactEffect( trace_t &tr, int nDamageType ); // give shooter a chance to do a custom impact. + + // OLD VERSION! Use the struct version + void FireBullets( int cShots, const Vector &vecSrc, const Vector &vecDirShooting, + const Vector &vecSpread, float flDistance, int iAmmoType, int iTracerFreq = 4, + int firingEntID = -1, int attachmentID = -1, int iDamage = 0, + CBaseEntity *pAttacker = NULL, bool bFirstShotAccurate = false, bool bPrimaryAttack = true ); + virtual void ModifyFireBulletsDamage( CTakeDamageInfo* dmgInfo ) {} + + virtual CBaseEntity *Respawn( void ) { return NULL; } + + // Method used to deal with attacks passing through triggers + void TraceAttackToTriggers( const CTakeDamageInfo &info, const Vector& start, const Vector& end, const Vector& dir ); + + // Do the bounding boxes of these two intersect? + bool Intersects( CBaseEntity *pOther ); + virtual bool IsLockedByMaster( void ) { return false; } + + // Health accessors. + virtual int GetMaxHealth() const { return m_iMaxHealth; } + void SetMaxHealth( int amt ) { m_iMaxHealth = amt; } + + int GetHealth() const { return m_iHealth; } + void SetHealth( int amt ) { m_iHealth = amt; } + + float HealthFraction() const; + + // Ugly code to lookup all functions to make sure they are in the table when set. +#ifdef _DEBUG + +#ifdef GNUC +#define ENTITYFUNCPTR_SIZE 8 +#else +#define ENTITYFUNCPTR_SIZE 4 +#endif + + void FunctionCheck( void *pFunction, const char *name ); + ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) + { + COMPILE_TIME_ASSERT( sizeof(func) == ENTITYFUNCPTR_SIZE ); + m_pfnTouch = func; + FunctionCheck( *(reinterpret_cast(&m_pfnTouch)), name ); + return func; + } + USEPTR UseSet( USEPTR func, char *name ) + { + COMPILE_TIME_ASSERT( sizeof(func) == ENTITYFUNCPTR_SIZE ); + m_pfnUse = func; + FunctionCheck( *(reinterpret_cast(&m_pfnUse)), name ); + return func; + } + ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) + { + COMPILE_TIME_ASSERT( sizeof(func) == ENTITYFUNCPTR_SIZE ); + m_pfnBlocked = func; + FunctionCheck( *(reinterpret_cast(&m_pfnBlocked)), name ); + return func; + } + +#endif // _DEBUG + + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + void AppendContextToCriteria( AI_CriteriaSet& set, const char *prefix = "" ); + void DumpResponseCriteria( void ); + + // Return the IHasAttributes interface for this base entity. Removes the need for: + // dynamic_cast< IHasAttributes * >( pEntity ); + // Which is remarkably slow. + // GetAttribInterface( CBaseEntity *pEntity ) in attribute_manager.h uses + // this function, tests for NULL, and Asserts m_pAttributes == dynamic_cast. + inline IHasAttributes *GetHasAttributesInterfacePtr() const { return m_pAttributes; } + +protected: + // NOTE: m_pAttributes needs to be set in the leaf class constructor. + IHasAttributes *m_pAttributes; + +private: + friend class CAI_Senses; + CBaseEntity *m_pLink;// used for temporary link-list operations. + +public: + // variables promoted from edict_t + string_t m_target; + CNetworkVarForDerived( int, m_iMaxHealth ); // CBaseEntity doesn't care about changes to this variable, but there are derived classes that do. + CNetworkVarForDerived( int, m_iHealth ); + + CNetworkVarForDerived( char, m_lifeState ); + CNetworkVarForDerived( char , m_takedamage ); + + // Damage filtering + string_t m_iszDamageFilterName; // The name of the entity to use as our damage filter. + EHANDLE m_hDamageFilter; // The entity that controls who can damage us. + + // Debugging / devolopment fields + int m_debugOverlays; // For debug only (bitfields) + TimedOverlay_t* m_pTimedOverlay; // For debug only + + // virtual functions used by a few classes + + // creates an entity of a specified class, by name + static CBaseEntity *Create( const char *szName, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner = NULL ); + static CBaseEntity *CreateNoSpawn( const char *szName, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner = NULL ); + + // Collision group accessors + int GetCollisionGroup() const; + void SetCollisionGroup( int collisionGroup ); + void CollisionRulesChanged(); + + // Damage accessors + virtual int GetDamageType() const; + virtual float GetDamage() { return 0; } + virtual void SetDamage(float flDamage) {} + + virtual Vector EyePosition( void ); // position of eyes + virtual const QAngle &EyeAngles( void ); // Direction of eyes in world space + virtual const QAngle &LocalEyeAngles( void ); // Direction of eyes + virtual Vector EarPosition( void ); // position of ears + + Vector EyePosition( void ) const; // position of eyes + const QAngle &EyeAngles( void ) const; // Direction of eyes in world space + const QAngle &LocalEyeAngles( void ) const; // Direction of eyes + Vector EarPosition( void ) const; // position of ears + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true); // position to shoot at + virtual Vector HeadTarget( const Vector &posSrc ); + virtual void GetVectors(Vector* forward, Vector* right, Vector* up) const; + + virtual const Vector &GetViewOffset() const; + virtual void SetViewOffset( const Vector &v ); + + // NOTE: Setting the abs velocity in either space will cause a recomputation + // in the other space, so setting the abs velocity will also set the local vel + void SetLocalVelocity( const Vector &vecVelocity ); + void ApplyLocalVelocityImpulse( const Vector &vecImpulse ); + void SetAbsVelocity( const Vector &vecVelocity ); + void ApplyAbsVelocityImpulse( const Vector &vecImpulse ); + void ApplyLocalAngularVelocityImpulse( const AngularImpulse &angImpulse ); + + const Vector& GetLocalVelocity( ) const; + const Vector& GetAbsVelocity( ) const; + + // NOTE: Setting the abs velocity in either space will cause a recomputation + // in the other space, so setting the abs velocity will also set the local vel + void SetLocalAngularVelocity( const QAngle &vecAngVelocity ); + const QAngle& GetLocalAngularVelocity( ) const; + + // FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity + // representation, we can't actually solve this problem +// void SetAbsAngularVelocity( const QAngle &vecAngVelocity ); +// const QAngle& GetAbsAngularVelocity( ) const; + + const Vector& GetBaseVelocity() const; + void SetBaseVelocity( const Vector& v ); + + virtual Vector GetSmoothedVelocity( void ); + + // FIXME: Figure out what to do about this + virtual void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity = NULL); + + float GetGravity( void ) const; + void SetGravity( float gravity ); + float GetFriction( void ) const; + void SetFriction( float flFriction ); + + virtual bool FVisible ( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); + virtual bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); + + virtual bool CanBeSeenBy( CAI_BaseNPC *pNPC ) { return true; } // allows entities to be 'invisible' to NPC senses. + + // This function returns a value that scales all damage done by this entity. + // Use CDamageModifier to hook in damage modifiers on a guy. + virtual float GetAttackDamageScale( CBaseEntity *pVictim ); + // This returns a value that scales all damage done to this entity + // Use CDamageModifier to hook in damage modifiers on a guy. + virtual float GetReceivedDamageScale( CBaseEntity *pAttacker ); + + void SetCheckUntouch( bool check ); + bool GetCheckUntouch() const; + + void SetGroundEntity( CBaseEntity *ground ); + CBaseEntity *GetGroundEntity( void ); + CBaseEntity *GetGroundEntity( void ) const { return const_cast(this)->GetGroundEntity(); } + + // Gets the velocity we impart to a player standing on us + virtual void GetGroundVelocityToApply( Vector &vecGroundVel ) { vecGroundVel = vec3_origin; } + + int GetWaterLevel() const; + void SetWaterLevel( int nLevel ); + int GetWaterType() const; + void SetWaterType( int nType ); + + virtual bool PhysicsSplash( const Vector ¢erPoint, const Vector &normal, float rawSpeed, float scaledSpeed ) { return false; } + virtual void Splash() {} + + void ClearSolidFlags( void ); + void RemoveSolidFlags( int flags ); + void AddSolidFlags( int flags ); + bool IsSolidFlagSet( int flagMask ) const; + void SetSolidFlags( int flags ); + bool IsSolid() const; + + void SetModelName( string_t name ); + + model_t *GetModel( void ); + + // These methods return a *world-aligned* box relative to the absorigin of the entity. + // This is used for collision purposes and is *not* guaranteed + // to surround the entire entity's visual representation + // NOTE: It is illegal to ask for the world-aligned bounds for + // SOLID_BSP objects + const Vector& WorldAlignMins( ) const; + const Vector& WorldAlignMaxs( ) const; + + // This defines collision bounds in OBB space + void SetCollisionBounds( const Vector& mins, const Vector &maxs ); + + // NOTE: The world space center *may* move when the entity rotates. + virtual const Vector& WorldSpaceCenter( ) const; + const Vector& WorldAlignSize( ) const; + + // Returns a radius of a sphere + // *centered at the world space center* bounding the collision representation + // of the entity. NOTE: The world space center *may* move when the entity rotates. + float BoundingRadius() const; + bool IsPointSized() const; + + // NOTE: Setting the abs origin or angles will cause the local origin + angles to be set also + void SetAbsOrigin( const Vector& origin ); + void SetAbsAngles( const QAngle& angles ); + + // Origin and angles in local space ( relative to parent ) + // NOTE: Setting the local origin or angles will cause the abs origin + angles to be set also + void SetLocalOrigin( const Vector& origin ); + const Vector& GetLocalOrigin( void ) const; + + void SetLocalAngles( const QAngle& angles ); + const QAngle& GetLocalAngles( void ) const; + + void SetElasticity( float flElasticity ); + float GetElasticity( void ) const; + + void SetShadowCastDistance( float flDistance ); + float GetShadowCastDistance( void ) const; + void SetShadowCastDistance( float flDesiredDistance, float flDelay ); + + float GetLocalTime( void ) const; + void IncrementLocalTime( float flTimeDelta ); + float GetMoveDoneTime( ) const; + void SetMoveDoneTime( float flTime ); + + // Used by the PAS filters to ask the entity where in world space the sounds it emits come from. + // This is used right now because if you have something sitting on an incline, using our axis-aligned + // bounding boxes can return a position in solid space, so you won't hear sounds emitted by the object. + // For now, we're hacking around it by moving the sound emission origin up on certain objects like vehicles. + // + // When OBBs get in, this can probably go away. + virtual Vector GetSoundEmissionOrigin() const; + + void AddFlag( int flags ); + void RemoveFlag( int flagsToRemove ); + void ToggleFlag( int flagToToggle ); + int GetFlags( void ) const; + void ClearFlags( void ); + + // Sets the local position from a transform + void SetLocalTransform( const matrix3x4_t &localTransform ); + + // See CSoundEmitterSystem + void EmitSound( const char *soundname, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter filter( this ), and EmitSound( filter, entindex(), etc. ); + void EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter filter( this ), and EmitSound( filter, entindex(), etc. ); + void StopSound( const char *soundname ); + void StopSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle ); + void GenderExpandString( char const *in, char *out, int maxlen ); + + virtual void ModifyEmitSoundParams( EmitSound_t ¶ms ); + + static float GetSoundDuration( const char *soundname, char const *actormodel ); + + static bool GetParametersForSound( const char *soundname, CSoundParameters ¶ms, char const *actormodel ); + static bool GetParametersForSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, CSoundParameters ¶ms, char const *actormodel ); + + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, const Vector *pOrigin = NULL, float soundtime = 0.0f, float *duration = NULL ); + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, HSOUNDSCRIPTHANDLE& handle, const Vector *pOrigin = NULL, float soundtime = 0.0f, float *duration = NULL ); + static void StopSound( int iEntIndex, const char *soundname ); + static soundlevel_t LookupSoundLevel( const char *soundname ); + static soundlevel_t LookupSoundLevel( const char *soundname, HSOUNDSCRIPTHANDLE& handle ); + + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params ); + static void EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params, HSOUNDSCRIPTHANDLE& handle ); + + static void StopSound( int iEntIndex, int iChannel, const char *pSample ); + + static void EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, int flags = 0, float soundtime = 0.0f, float *duration = NULL ); + + // These files need to be listed in scripts/game_sounds_manifest.txt + static HSOUNDSCRIPTHANDLE PrecacheScriptSound( const char *soundname ); + static void PrefetchScriptSound( const char *soundname ); + + // For each client who appears to be a valid recipient, checks the client has disabled CC and if so, removes them from + // the recipient list. + static void RemoveRecipientsIfNotCloseCaptioning( CRecipientFilter& filter ); + static void EmitCloseCaption( IRecipientFilter& filter, int entindex, char const *token, CUtlVector< Vector >& soundorigins, float duration, bool warnifmissing = false ); + static void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex, + float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM, + const Vector *pOrigin = NULL, const Vector *pDirection = NULL, bool bUpdatePositions = true, float soundtime = 0.0f ); + + static bool IsPrecacheAllowed(); + static void SetAllowPrecache( bool allow ); + + static bool m_bAllowPrecache; + + static bool IsSimulatingOnAlternateTicks(); + + virtual bool IsDeflectable() { return false; } + virtual void Deflected( CBaseEntity *pDeflectedBy, Vector &vecDir ) {} + +// void Relink() {} + +public: + + // VPHYSICS Integration ----------------------------------------------- + // + // -------------------------------------------------------------------- + // UNDONE: Move to IEntityVPhysics? or VPhysicsProp() ? + // Called after spawn, and in the case of self-managing objects, after load + virtual bool CreateVPhysics(); + + // Convenience routines to init the vphysics simulation for this object. + // This creates a static object. Something that behaves like world geometry - solid, but never moves + IPhysicsObject *VPhysicsInitStatic( void ); + + // This creates a normal vphysics simulated object - physics determines where it goes (gravity, friction, etc) + // and the entity receives updates from vphysics. SetAbsOrigin(), etc do not affect the object! + IPhysicsObject *VPhysicsInitNormal( SolidType_t solidType, int nSolidFlags, bool createAsleep, solid_t *pSolid = NULL ); + + // This creates a vphysics object with a shadow controller that follows the AI + // Move the object to where it should be and call UpdatePhysicsShadowToCurrentPosition() + IPhysicsObject *VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation, solid_t *pSolid = NULL ); + + // Force a non-solid (ie. solid_trigger) physics object to collide with other entities. + virtual bool ForceVPhysicsCollide( CBaseEntity *pEntity ) { return false; } + +private: + // called by all vphysics inits + bool VPhysicsInitSetup(); +public: + + void VPhysicsSetObject( IPhysicsObject *pPhysics ); + // destroy and remove the physics object for this entity + virtual void VPhysicsDestroyObject( void ); + void VPhysicsSwapObject( IPhysicsObject *pSwap ); + + virtual bool GMOD_VPhysicsTest( IPhysicsObject *pPhysics ); + + inline IPhysicsObject *VPhysicsGetObject( void ) const { return m_pPhysicsObject; } + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + void VPhysicsUpdatePusher( IPhysicsObject *pPhysics ); + + // react physically to damage (called from CBaseEntity::OnTakeDamage() by default) + virtual int VPhysicsTakeDamage( const CTakeDamageInfo &info ); + virtual void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent ); + virtual void VPhysicsShadowUpdate( IPhysicsObject *pPhysics ) {} + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + virtual void GMOD_VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + virtual void VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ); + + // update the shadow so it will coincide with the current AI position at some time + // in the future (or 0 for now) + virtual void UpdatePhysicsShadowToCurrentPosition( float deltaTime ); + virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + virtual bool VPhysicsIsFlesh( void ); + // -------------------------------------------------------------------- + +public: +#if !defined( NO_ENTITY_PREDICTION ) + // The player drives simulation of this entity + void SetPlayerSimulated( CBasePlayer *pOwner ); + void UnsetPlayerSimulated( void ); + bool IsPlayerSimulated( void ) const; + CBasePlayer *GetSimulatingPlayer( void ); +#endif + // FIXME: Make these private! + void PhysicsCheckForEntityUntouch( void ); + bool PhysicsRunThink( thinkmethods_t thinkMethod = THINK_FIRE_ALL_FUNCTIONS ); + bool PhysicsRunSpecificThink( int nContextIndex, BASEPTR thinkFunc ); + bool PhysicsTestEntityPosition( CBaseEntity **ppEntity = NULL ); + void PhysicsPushEntity( const Vector& push, trace_t *pTrace ); + bool PhysicsCheckWater( void ); + void PhysicsCheckWaterTransition( void ); + void PhysicsStepRecheckGround(); + // Computes the water level + type + void UpdateWaterState(); + bool IsEdictFree() const { return edict()->IsFree(); } + + // Callbacks for the physgun/cannon picking up an entity + virtual CBasePlayer *HasPhysicsAttacker( float dt ) { return NULL; } + + // UNDONE: Make this data? + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + + // Computes the abs position of a point specified in local space + void ComputeAbsPosition( const Vector &vecLocalPosition, Vector *pAbsPosition ); + + // Computes the abs position of a direction specified in local space + void ComputeAbsDirection( const Vector &vecLocalDirection, Vector *pAbsDirection ); + + void SetPredictionEligible( bool canpredict ); + +protected: + // Invalidates the abs state of all children + void InvalidatePhysicsRecursive( int nChangeFlags ); + + int PhysicsClipVelocity (const Vector& in, const Vector& normal, Vector& out, float overbounce ); + void PhysicsRelinkChildren( float dt ); + + // Performs the collision resolution for fliers. + void PerformFlyCollisionResolution( trace_t &trace, Vector &move ); + void ResolveFlyCollisionBounce( trace_t &trace, Vector &vecVelocity, float flMinTotalElasticity = 0.0f ); + void ResolveFlyCollisionSlide( trace_t &trace, Vector &vecVelocity ); + virtual void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ); + +private: + // Physics-related private methods + void PhysicsStep( void ); + void PhysicsPusher( void ); + void PhysicsNone( void ); + void PhysicsNoclip( void ); + void PhysicsStepRunTimestep( float timestep ); + void PhysicsToss( void ); + void PhysicsCustom( void ); + void PerformPush( float movetime ); + + // Simulation in local space of rigid children + void PhysicsRigidChild( void ); + + // Computes the base velocity + void UpdateBaseVelocity( void ); + + // Implement this if you use MOVETYPE_CUSTOM + virtual void PerformCustomPhysics( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity ); + + void PhysicsDispatchThink( BASEPTR thinkFunc ); + + touchlink_t *PhysicsMarkEntityAsTouched( CBaseEntity *other ); + void PhysicsTouch( CBaseEntity *pentOther ); + void PhysicsStartTouch( CBaseEntity *pentOther ); + + CBaseEntity *PhysicsPushMove( float movetime ); + CBaseEntity *PhysicsPushRotate( float movetime ); + + CBaseEntity *PhysicsCheckRotateMove( rotatingpushmove_t &rotPushmove, CBaseEntity **pPusherList, int pusherListCount ); + CBaseEntity *PhysicsCheckPushMove( const Vector& move, CBaseEntity **pPusherList, int pusherListCount ); + int PhysicsTryMove( float flTime, trace_t *steptrace ); + + void PhysicsCheckVelocity( void ); + void PhysicsAddHalfGravity( float timestep ); + void PhysicsAddGravityMove( Vector &move ); + + void CalcAbsoluteVelocity(); + void CalcAbsoluteAngularVelocity(); + + // Checks a sweep without actually performing the move + void PhysicsCheckSweep( const Vector& vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace ); + + // Computes new angles based on the angular velocity + void SimulateAngles( float flFrameTime ); + + void CheckStepSimulationChanged(); + // Run regular think and latch off angle/origin changes so we can interpolate them on the server to fake simulation + void StepSimulationThink( float dt ); + + // Compute network origin +private: + void ComputeStepSimulationNetwork( StepSimulationData *step ); + +public: + bool UseStepSimulationNetworkOrigin( const Vector **out_v ); + bool UseStepSimulationNetworkAngles( const QAngle **out_a ); + +public: + // Add a discontinuity to a step + bool AddStepDiscontinuity( float flTime, const Vector &vecOrigin, const QAngle &vecAngles ); + int GetFirstThinkTick(); // get first tick thinking on any context +private: + // origin and angles to use in step calculations + virtual Vector GetStepOrigin( void ) const; + virtual QAngle GetStepAngles( void ) const; + + // These set entity flags (EFL_*) to help optimize queries + void CheckHasThinkFunction( bool isThinkingHint = false ); + void CheckHasGamePhysicsSimulation(); + bool WillThink(); + bool WillSimulateGamePhysics(); + + friend class CPushBlockerEnum; + + // Sets/Gets the next think based on context index + void SetNextThink( int nContextIndex, float thinkTime ); + void SetLastThink( int nContextIndex, float thinkTime ); + float GetNextThink( int nContextIndex ) const; + int GetNextThinkTick( int nContextIndex ) const; + + // Shot statistics + void UpdateShotStatistics( const trace_t &tr ); + + // Handle shot entering water + bool HandleShotImpactingWater( const FireBulletsInfo_t &info, const Vector &vecEnd, ITraceFilter *pTraceFilter, Vector *pVecTracerDest ); + + // Handle shot entering water + void HandleShotImpactingGlass( const FireBulletsInfo_t &info, const trace_t &tr, const Vector &vecDir, ITraceFilter *pTraceFilter ); + + // Should we draw bubbles underwater? + bool ShouldDrawUnderwaterBulletBubbles(); + + // Computes the tracer start position + void ComputeTracerStartPosition( const Vector &vecShotSrc, Vector *pVecTracerStart ); + + // Computes the tracer start position + void CreateBubbleTrailTracer( const Vector &vecShotSrc, const Vector &vecShotEnd, const Vector &vecShotDir ); + + virtual bool ShouldDrawWaterImpacts() { return true; } + + // Changes shadow cast distance over time + void ShadowCastDistThink( ); + + // Precache model sounds + particles + static void PrecacheModelComponents( int nModelIndex ); + static void PrecacheSoundHelper( const char *pName ); + +protected: + // Which frame did I simulate? + int m_nSimulationTick; + + // FIXME: Make this private! Still too many references to do so... + CNetworkVar( int, m_spawnflags ); + +private: + int m_iEFlags; // entity flags EFL_* + // was pev->flags + CNetworkVarForDerived( int, m_fFlags ); + + string_t m_iName; // name used to identify this entity + + // Damage modifiers + friend class CDamageModifier; + CUtlLinkedList m_DamageModifiers; + + EHANDLE m_pParent; // for movement hierarchy + byte m_nTransmitStateOwnedCounter; + CNetworkVar( unsigned char, m_iParentAttachment ); // 0 if we're relative to the parent's absorigin and absangles. + CNetworkVar( unsigned char, m_MoveType ); // One of the MOVETYPE_ defines. + CNetworkVar( unsigned char, m_MoveCollide ); + + // Our immediate parent in the movement hierarchy. + // FIXME: clarify m_pParent vs. m_pMoveParent + CNetworkHandle( CBaseEntity, m_hMoveParent ); + // cached child list + EHANDLE m_hMoveChild; + // generated from m_pMoveParent + EHANDLE m_hMovePeer; + + friend class CCollisionProperty; + friend class CServerNetworkProperty; + CNetworkVarEmbedded( CCollisionProperty, m_Collision ); + + CNetworkHandle( CBaseEntity, m_hOwnerEntity ); // only used to point to an edict it won't collide with + CNetworkHandle( CBaseEntity, m_hEffectEntity ); // Fire/Dissolve entity. + + CNetworkVar( int, m_CollisionGroup ); // used to cull collision tests + IPhysicsObject *m_pPhysicsObject; // pointer to the entity's physics object (vphysics.dll) + + CNetworkVar( float, m_flShadowCastDistance ); + float m_flDesiredShadowCastDistance; + + // Team handling + int m_iInitialTeamNum; // Team number of this entity's team read from file + CNetworkVar( int, m_iTeamNum ); // Team number of this entity's team. + + // Sets water type + level for physics objects + unsigned char m_nWaterTouch; + unsigned char m_nSlimeTouch; + unsigned char m_nWaterType; + CNetworkVarForDerived( unsigned char, m_nWaterLevel ); + float m_flNavIgnoreUntilTime; + + CNetworkHandleForDerived( CBaseEntity, m_hGroundEntity ); + float m_flGroundChangeTime; // Time that the ground entity changed + + string_t m_ModelName; + + // Velocity of the thing we're standing on (world space) + CNetworkVarForDerived( Vector, m_vecBaseVelocity ); + + // Global velocity + Vector m_vecAbsVelocity; + + // Local angular velocity + QAngle m_vecAngVelocity; + + // Global angular velocity +// QAngle m_vecAbsAngVelocity; + + // local coordinate frame of entity + matrix3x4_t m_rgflCoordinateFrame; + + // Physics state + EHANDLE m_pBlocker; + + // was pev->gravity; + float m_flGravity; // rename to m_flGravityScale; + // was pev->friction + CNetworkVarForDerived( float, m_flFriction ); + CNetworkVar( float, m_flElasticity ); + + // was pev->ltime + float m_flLocalTime; + // local time at the beginning of this frame + float m_flVPhysicsUpdateLocalTime; + // local time the movement has ended + float m_flMoveDoneTime; + + // A counter to help quickly build a list of potentially pushed objects for physics + int m_nPushEnumCount; + + Vector m_vecAbsOrigin; + CNetworkVector( m_vecVelocity ); + + //Adrian + CNetworkVar( unsigned char, m_iTextureFrameIndex ); + + CNetworkVar( bool, m_bSimulatedEveryTick ); + CNetworkVar( bool, m_bAnimatedEveryTick ); + CNetworkVar( bool, m_bAlternateSorting ); + + // User outputs. Fired when the "FireInputX" input is triggered. + COutputEvent m_OnUser1; + COutputEvent m_OnUser2; + COutputEvent m_OnUser3; + COutputEvent m_OnUser4; + + QAngle m_angAbsRotation; + + CNetworkVector( m_vecOrigin ); + CNetworkQAngle( m_angRotation ); + CBaseHandle m_RefEHandle; + + // was pev->view_ofs ( FIXME: Move somewhere up the hierarch, CBaseAnimating, etc. ) + CNetworkVectorForDerived( m_vecViewOffset ); + +private: + // dynamic model state tracking + bool m_bDynamicModelAllowed; + bool m_bDynamicModelPending; + bool m_bDynamicModelSetBounds; + void OnModelLoadComplete( const model_t* model ); + friend class CBaseEntityModelLoadProxy; + +protected: + void EnableDynamicModels() { m_bDynamicModelAllowed = true; } + +public: + bool IsDynamicModelLoading() const { return m_bDynamicModelPending; } + void SetCollisionBoundsFromModel(); + +#if !defined( NO_ENTITY_PREDICTION ) + CNetworkVar( bool, m_bIsPlayerSimulated ); + // Player who is driving my simulation + CHandle< CBasePlayer > m_hPlayerSimulationOwner; +#endif + + int m_fDataObjectTypes; + + // So it can get at the physics methods + friend class CCollisionEvent; + +// Methods shared by client and server +public: + void SetSize( const Vector &vecMin, const Vector &vecMax ); // UTIL_SetSize( this, mins, maxs ); + static int PrecacheModel( const char *name, bool bPreload = true ); + static bool PrecacheSound( const char *name ); + static void PrefetchSound( const char *name ); + void Remove( ); // UTIL_Remove( this ); + +private: + + // This is a random seed used by the networking code to allow client - side prediction code + // randon number generators to spit out the same random numbers on both sides for a particular + // usercmd input. + static int m_nPredictionRandomSeed; + static int m_nPredictionRandomSeedServer; + static CBasePlayer *m_pPredictionPlayer; + + // FIXME: Make hierarchy a member of CBaseEntity + // or a contained private class... + friend void UnlinkChild( CBaseEntity *pParent, CBaseEntity *pChild ); + friend void LinkChild( CBaseEntity *pParent, CBaseEntity *pChild ); + friend void ClearParent( CBaseEntity *pEntity ); + friend void UnlinkAllChildren( CBaseEntity *pParent ); + friend void UnlinkFromParent( CBaseEntity *pRemove ); + friend void TransferChildren( CBaseEntity *pOldParent, CBaseEntity *pNewParent ); + +public: + // Accessors for above + static int GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime = false ); + static void SetPredictionRandomSeed( const CUserCmd *cmd ); + static CBasePlayer *GetPredictionPlayer( void ); + static void SetPredictionPlayer( CBasePlayer *player ); + + + // For debugging shared code + static bool IsServer( void ) + { + return true; + } + + static bool IsClient( void ) + { + return false; + } + + static char const *GetDLLType( void ) + { + return "server"; + } + + // Used to access m_vecAbsOrigin during restore when it's unsafe to call GetAbsOrigin. + friend class CPlayerRestoreHelper; + + static bool s_bAbsQueriesValid; + + // Call this when hierarchy is not completely set up (such as during Restore) to throw asserts + // when people call GetAbsAnything. + static inline void SetAbsQueriesValid( bool bValid ) + { + s_bAbsQueriesValid = bValid; + } + + static inline bool IsAbsQueriesValid() + { + return s_bAbsQueriesValid; + } + + virtual bool ShouldBlockNav() const { return true; } + + virtual bool ShouldForceTransmitsForTeam( int team ); + + virtual void *VPhysicsGetElement( int element ); + + virtual void OnOwnerChanged(); + virtual bool IsARagdoll(); + virtual void SetMaterialOverride( const char * ); + virtual const char *GetMaterialOverride(); + virtual bool IsPredicted() const; + virtual bool IsWeapon() const; + virtual bool IsVehicle() const; + virtual bool IsJeep() const; + virtual bool UsesLua(); + virtual int GetLuaEntityType(); + virtual void PushEntity(); + virtual void Push_This_Entity(); + virtual void SetPhysObject( int, IPhysicsObject * ); + virtual void SetEntity( const char *, CBaseEntity * ); + virtual void DeleteOnRemove( CBaseEntity * ); + virtual void DontDeleteOnRemove( CBaseEntity * ); + virtual int GetParentPhysicsNum(); + virtual void SetParentPhysicsNum( int ); + virtual double GetCreationTime(); + virtual void StartMotionController(); + virtual void StopMotionController(); + virtual void AttachObjectToMotionController( IPhysicsObject * ); + virtual void DetachObjectFromMotionController( IPhysicsObject * ); + virtual void SaveLua( ISave & ); + virtual void LoadLua( IRestore & ); + virtual void SetUseType( int ); + virtual void UpdateBeforeRemove( int ); + virtual const char *GetLuaScriptName(); + virtual void SpawnedViaLua(); + virtual void OverridePosition(); + virtual void InitializeScriptedEntity( const char * ); + virtual void ClearLuaData(); + virtual ILuaObject *GetLuaTable(); + virtual void *GetLuaEntity(); + virtual void Lua_OnEntityInitialized(); + virtual void SetLuaTable( ILuaObject * ); + virtual bool HasLuaTable(); + virtual void ForcePhysicsDropObject(); + virtual void StartDriving( CBasePlayer * ); + virtual void FinishDriving( CBasePlayer * ); + virtual bool GMOD_ShouldPreventTransmitToPlayer( CBasePlayer * ); + virtual void GMOD_SetShouldPreventTransmitToPlayer( CBasePlayer *, bool ); + virtual bool GMOD_ShouldPlayPhysicsSounds(); + virtual void *Lua_GetLuaClass(); + virtual INextBot *GetNextBot(); +}; + +// Send tables exposed in this module. +EXTERN_SEND_TABLE(DT_Edict); +EXTERN_SEND_TABLE(DT_BaseEntity); + + + +// Ugly technique to override base member functions +// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a +// member function of a base class. static_cast is a sleezy way around that problem. + +#ifdef _DEBUG + +#define SetTouch( a ) TouchSet( static_cast (a), #a ) +#define SetUse( a ) UseSet( static_cast (a), #a ) +#define SetBlocked( a ) BlockedSet( static_cast (a), #a ) + +#else + +#define SetTouch( a ) m_pfnTouch = static_cast (a) +#define SetUse( a ) m_pfnUse = static_cast (a) +#define SetBlocked( a ) m_pfnBlocked = static_cast (a) + +#endif + +// handling entity/edict transforms +inline CBaseEntity *GetContainingEntity( edict_t *pent ) +{ + if ( pent && pent->GetUnknown() ) + { + return pent->GetUnknown()->GetBaseEntity(); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Pauses or resumes entity i/o events. When paused, no outputs will +// fire unless Debug_SetSteps is called with a nonzero step value. +// Input : bPause - true to pause, false to resume. +//----------------------------------------------------------------------------- +inline void CBaseEntity::Debug_Pause(bool bPause) +{ + CBaseEntity::m_bDebugPause = bPause; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if entity i/o is paused, false if not. +//----------------------------------------------------------------------------- +inline bool CBaseEntity::Debug_IsPaused(void) +{ + return(CBaseEntity::m_bDebugPause); +} + + +//----------------------------------------------------------------------------- +// Purpose: Decrements the debug step counter. Used when the entity i/o system +// is in single step mode, this is called every time an output is fired. +// Output : Returns true on to continue firing outputs, false to stop. +//----------------------------------------------------------------------------- +inline bool CBaseEntity::Debug_Step(void) +{ + if (CBaseEntity::m_nDebugSteps > 0) + { + CBaseEntity::m_nDebugSteps--; + } + return(CBaseEntity::m_nDebugSteps > 0); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the number of entity outputs to allow to fire before pausing +// the entity i/o system. +// Input : nSteps - Number of steps to execute. +//----------------------------------------------------------------------------- +inline void CBaseEntity::Debug_SetSteps(int nSteps) +{ + CBaseEntity::m_nDebugSteps = nSteps; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if we should allow outputs to be fired, false if not. +//----------------------------------------------------------------------------- +inline bool CBaseEntity::Debug_ShouldStep(void) +{ + return(!CBaseEntity::m_bDebugPause || CBaseEntity::m_nDebugSteps > 0); +} + +//----------------------------------------------------------------------------- +// Methods relating to traversing hierarchy +//----------------------------------------------------------------------------- +inline CBaseEntity *CBaseEntity::GetMoveParent( void ) +{ + return m_hMoveParent.Get(); +} + +inline CBaseEntity *CBaseEntity::FirstMoveChild( void ) +{ + return m_hMoveChild.Get(); +} + +inline CBaseEntity *CBaseEntity::NextMovePeer( void ) +{ + return m_hMovePeer.Get(); +} + +// FIXME: Remove this! There shouldn't be a difference between moveparent + parent +inline CBaseEntity* CBaseEntity::GetParent() +{ + return m_pParent.Get(); +} + +inline int CBaseEntity::GetParentAttachment() +{ + return m_iParentAttachment; +} + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline string_t CBaseEntity::GetEntityName() +{ + return m_iName; +} + +inline void CBaseEntity::SetName( string_t newName ) +{ + m_iName = newName; +} + + +inline bool CBaseEntity::NameMatches( const char *pszNameOrWildcard ) +{ + if ( IDENT_STRINGS(m_iName, pszNameOrWildcard) ) + return true; + return NameMatchesComplex( pszNameOrWildcard ); +} + +inline bool CBaseEntity::NameMatches( string_t nameStr ) +{ + if ( IDENT_STRINGS(m_iName, nameStr) ) + return true; + return NameMatchesComplex( STRING(nameStr) ); +} + +inline bool CBaseEntity::ClassMatches( const char *pszClassOrWildcard ) +{ + if ( IDENT_STRINGS(m_iClassname, pszClassOrWildcard ) ) + return true; + return ClassMatchesComplex( pszClassOrWildcard ); +} + +inline const char* CBaseEntity::GetClassname() +{ + return STRING(m_iClassname); +} + + +inline bool CBaseEntity::ClassMatches( string_t nameStr ) +{ + if ( IDENT_STRINGS(m_iClassname, nameStr ) ) + return true; + return ClassMatchesComplex( STRING(nameStr) ); +} + +inline int CBaseEntity::GetSpawnFlags( void ) const +{ + return m_spawnflags; +} + +inline void CBaseEntity::AddSpawnFlags( int nFlags ) +{ + m_spawnflags |= nFlags; +} +inline void CBaseEntity::RemoveSpawnFlags( int nFlags ) +{ + m_spawnflags &= ~nFlags; +} + +inline void CBaseEntity::ClearSpawnFlags( void ) +{ + m_spawnflags = 0; +} + +inline bool CBaseEntity::HasSpawnFlags( int nFlags ) const +{ + return (m_spawnflags & nFlags) != 0; +} + +//----------------------------------------------------------------------------- +// checks to see if the entity is marked for deletion +//----------------------------------------------------------------------------- +inline bool CBaseEntity::IsMarkedForDeletion( void ) +{ + return (m_iEFlags & EFL_KILLME); +} + +//----------------------------------------------------------------------------- +// EFlags +//----------------------------------------------------------------------------- +inline int CBaseEntity::GetEFlags() const +{ + return m_iEFlags; +} + +inline void CBaseEntity::SetEFlags( int iEFlags ) +{ + m_iEFlags = iEFlags; + + if ( iEFlags & ( EFL_FORCE_CHECK_TRANSMIT | EFL_IN_SKYBOX ) ) + { + DispatchUpdateTransmitState(); + } +} + +inline void CBaseEntity::AddEFlags( int nEFlagMask ) +{ + m_iEFlags |= nEFlagMask; + + if ( nEFlagMask & ( EFL_FORCE_CHECK_TRANSMIT | EFL_IN_SKYBOX ) ) + { + DispatchUpdateTransmitState(); + } +} + +inline void CBaseEntity::RemoveEFlags( int nEFlagMask ) +{ + m_iEFlags &= ~nEFlagMask; + + if ( nEFlagMask & ( EFL_FORCE_CHECK_TRANSMIT | EFL_IN_SKYBOX ) ) + DispatchUpdateTransmitState(); +} + +inline bool CBaseEntity::IsEFlagSet( int nEFlagMask ) const +{ + return (m_iEFlags & nEFlagMask) != 0; +} + +inline void CBaseEntity::SetNavIgnore( float duration ) +{ + float flNavIgnoreUntilTime = ( duration == FLT_MAX ) ? FLT_MAX : gpGlobals->curtime + duration; + if ( flNavIgnoreUntilTime > m_flNavIgnoreUntilTime ) + m_flNavIgnoreUntilTime = flNavIgnoreUntilTime; +} + +inline void CBaseEntity::ClearNavIgnore() +{ + m_flNavIgnoreUntilTime = 0; +} + +inline bool CBaseEntity::IsNavIgnored() const +{ + return ( gpGlobals->curtime <= m_flNavIgnoreUntilTime ); +} + +inline bool CBaseEntity::GetCheckUntouch() const +{ + return IsEFlagSet( EFL_CHECK_UNTOUCH ); +} + +//----------------------------------------------------------------------------- +// Network state optimization +//----------------------------------------------------------------------------- +inline CBaseCombatCharacter *ToBaseCombatCharacter( CBaseEntity *pEntity ) +{ + if ( !pEntity ) + return NULL; + + return pEntity->MyCombatCharacterPointer(); +} + + +//----------------------------------------------------------------------------- +// Physics state accessor methods +//----------------------------------------------------------------------------- +inline const Vector& CBaseEntity::GetLocalOrigin( void ) const +{ + return m_vecOrigin.Get(); +} + +inline const QAngle& CBaseEntity::GetLocalAngles( void ) const +{ + return m_angRotation.Get(); +} + +inline const Vector& CBaseEntity::GetAbsOrigin( void ) const +{ + Assert( CBaseEntity::IsAbsQueriesValid() ); + + if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) + { + const_cast(this)->CalcAbsolutePosition(); + } + return m_vecAbsOrigin; +} + +inline const QAngle& CBaseEntity::GetAbsAngles( void ) const +{ + Assert( CBaseEntity::IsAbsQueriesValid() ); + + if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) + { + const_cast(this)->CalcAbsolutePosition(); + } + return m_angAbsRotation; +} + + + +//----------------------------------------------------------------------------- +// Returns the entity-to-world transform +//----------------------------------------------------------------------------- +inline matrix3x4_t &CBaseEntity::EntityToWorldTransform() +{ + Assert( CBaseEntity::IsAbsQueriesValid() ); + + if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) + { + CalcAbsolutePosition(); + } + return m_rgflCoordinateFrame; +} + +inline const matrix3x4_t &CBaseEntity::EntityToWorldTransform() const +{ + Assert( CBaseEntity::IsAbsQueriesValid() ); + + if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) + { + const_cast(this)->CalcAbsolutePosition(); + } + return m_rgflCoordinateFrame; +} + + +//----------------------------------------------------------------------------- +// Some helper methods that transform a point from entity space to world space + back +//----------------------------------------------------------------------------- +inline void CBaseEntity::EntityToWorldSpace( const Vector &in, Vector *pOut ) const +{ + if ( GetAbsAngles() == vec3_angle ) + { + VectorAdd( in, GetAbsOrigin(), *pOut ); + } + else + { + VectorTransform( in, EntityToWorldTransform(), *pOut ); + } +} + +inline void CBaseEntity::WorldToEntitySpace( const Vector &in, Vector *pOut ) const +{ + if ( GetAbsAngles() == vec3_angle ) + { + VectorSubtract( in, GetAbsOrigin(), *pOut ); + } + else + { + VectorITransform( in, EntityToWorldTransform(), *pOut ); + } +} + + +//----------------------------------------------------------------------------- +// Velocity +//----------------------------------------------------------------------------- +inline Vector CBaseEntity::GetSmoothedVelocity( void ) +{ + Vector vel; + GetVelocity( &vel, NULL ); + return vel; +} + +inline const Vector &CBaseEntity::GetLocalVelocity( ) const +{ + return m_vecVelocity.Get(); +} + +inline const Vector &CBaseEntity::GetAbsVelocity( ) const +{ + Assert( CBaseEntity::IsAbsQueriesValid() ); + + if (IsEFlagSet(EFL_DIRTY_ABSVELOCITY)) + { + const_cast(this)->CalcAbsoluteVelocity(); + } + return m_vecAbsVelocity; +} + +inline const QAngle &CBaseEntity::GetLocalAngularVelocity( ) const +{ + return m_vecAngVelocity; +} + +/* +// FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity +// representation, we can't actually solve this problem +inline const QAngle &CBaseEntity::GetAbsAngularVelocity( ) const +{ + if (IsEFlagSet(EFL_DIRTY_ABSANGVELOCITY)) + { + const_cast(this)->CalcAbsoluteAngularVelocity(); + } + + return m_vecAbsAngVelocity; +} +*/ + +inline const Vector& CBaseEntity::GetBaseVelocity() const +{ + return m_vecBaseVelocity.Get(); +} + +inline void CBaseEntity::SetBaseVelocity( const Vector& v ) +{ + m_vecBaseVelocity = v; +} + +inline float CBaseEntity::GetGravity( void ) const +{ + return m_flGravity; +} + +inline void CBaseEntity::SetGravity( float gravity ) +{ + m_flGravity = gravity; +} + +inline float CBaseEntity::GetFriction( void ) const +{ + return m_flFriction; +} + +inline void CBaseEntity::SetFriction( float flFriction ) +{ + m_flFriction = flFriction; +} + +inline void CBaseEntity::SetElasticity( float flElasticity ) +{ + m_flElasticity = flElasticity; +} + +inline float CBaseEntity::GetElasticity( void ) const +{ + return m_flElasticity; +} + +inline void CBaseEntity::SetShadowCastDistance( float flDistance ) +{ + m_flShadowCastDistance = flDistance; +} + +inline float CBaseEntity::GetShadowCastDistance( void ) const +{ + return m_flShadowCastDistance; +} + +inline float CBaseEntity::GetLocalTime( void ) const +{ + return m_flLocalTime; +} + +inline void CBaseEntity::IncrementLocalTime( float flTimeDelta ) +{ + m_flLocalTime += flTimeDelta; +} + +inline float CBaseEntity::GetMoveDoneTime( ) const +{ + return (m_flMoveDoneTime >= 0) ? m_flMoveDoneTime - GetLocalTime() : -1; +} + +inline CBaseEntity *CBaseEntity::Instance( const edict_t *pent ) +{ + return GetContainingEntity( const_cast(pent) ); +} + +inline CBaseEntity *CBaseEntity::Instance( edict_t *pent ) +{ + if ( !pent ) + { + pent = INDEXENT(0); + } + return GetContainingEntity( pent ); +} + +inline CBaseEntity* CBaseEntity::Instance( int iEnt ) +{ + return Instance( INDEXENT( iEnt ) ); +} + +inline int CBaseEntity::GetWaterLevel() const +{ + return m_nWaterLevel; +} + +inline void CBaseEntity::SetWaterLevel( int nLevel ) +{ + m_nWaterLevel = nLevel; +} + +inline const color32 CBaseEntity::GetRenderColor() const +{ + return m_clrRender.Get(); +} + +inline void CBaseEntity::SetRenderColor( byte r, byte g, byte b ) +{ + m_clrRender.Init( r, g, b ); +} + +inline void CBaseEntity::SetRenderColor( byte r, byte g, byte b, byte a ) +{ + m_clrRender.Init( r, g, b, a ); +} + +inline void CBaseEntity::SetRenderColorR( byte r ) +{ + m_clrRender.SetR( r ); +} + +inline void CBaseEntity::SetRenderColorG( byte g ) +{ + m_clrRender.SetG( g ); +} + +inline void CBaseEntity::SetRenderColorB( byte b ) +{ + m_clrRender.SetB( b ); +} + +inline void CBaseEntity::SetRenderColorA( byte a ) +{ + m_clrRender.SetA( a ); +} + +inline void CBaseEntity::SetMoveCollide( MoveCollide_t val ) +{ + m_MoveCollide = val; +} + +inline bool CBaseEntity::IsTransparent() const +{ + return m_nRenderMode != kRenderNormal; +} + +inline int CBaseEntity::GetTextureFrameIndex( void ) +{ + return m_iTextureFrameIndex; +} + +inline void CBaseEntity::SetTextureFrameIndex( int iIndex ) +{ + m_iTextureFrameIndex = iIndex; +} + +//----------------------------------------------------------------------------- +// An inline version the game code can use +//----------------------------------------------------------------------------- +inline CCollisionProperty *CBaseEntity::CollisionProp() +{ + return &m_Collision; +} + +inline const CCollisionProperty *CBaseEntity::CollisionProp() const +{ + return &m_Collision; +} + +inline CServerNetworkProperty *CBaseEntity::NetworkProp() +{ + return &m_Network; +} + +inline const CServerNetworkProperty *CBaseEntity::NetworkProp() const +{ + return &m_Network; +} + +inline void CBaseEntity::ClearSolidFlags( void ) +{ + CollisionProp()->ClearSolidFlags(); +} + +inline void CBaseEntity::RemoveSolidFlags( int flags ) +{ + CollisionProp()->RemoveSolidFlags( flags ); +} + +inline void CBaseEntity::AddSolidFlags( int flags ) +{ + CollisionProp()->AddSolidFlags( flags ); +} + +inline int CBaseEntity::GetSolidFlags( void ) const +{ + return CollisionProp()->GetSolidFlags(); +} + +inline bool CBaseEntity::IsSolidFlagSet( int flagMask ) const +{ + return CollisionProp()->IsSolidFlagSet( flagMask ); +} + +inline bool CBaseEntity::IsSolid() const +{ + return CollisionProp()->IsSolid( ); +} + +inline void CBaseEntity::SetSolid( SolidType_t val ) +{ + CollisionProp()->SetSolid( val ); +} + +inline void CBaseEntity::SetSolidFlags( int flags ) +{ + CollisionProp()->SetSolidFlags( flags ); +} + +inline SolidType_t CBaseEntity::GetSolid() const +{ + return CollisionProp()->GetSolid(); +} + + +//----------------------------------------------------------------------------- +// Methods related to IServerUnknown +//----------------------------------------------------------------------------- +inline ICollideable *CBaseEntity::GetCollideable() +{ + return &m_Collision; +} + +inline IServerNetworkable *CBaseEntity::GetNetworkable() +{ + return &m_Network; +} + +inline CBaseEntity *CBaseEntity::GetBaseEntity() +{ + return this; +} + + +//----------------------------------------------------------------------------- +// Model related methods +//----------------------------------------------------------------------------- +inline void CBaseEntity::SetModelName( string_t name ) +{ + m_ModelName = name; + DispatchUpdateTransmitState(); +} + +inline string_t CBaseEntity::GetModelName( void ) const +{ + return m_ModelName; +} + +inline int CBaseEntity::GetModelIndex( void ) const +{ + return m_nModelIndex; +} + + + +//----------------------------------------------------------------------------- +// Methods relating to bounds +//----------------------------------------------------------------------------- +inline const Vector& CBaseEntity::WorldAlignMins( ) const +{ + Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); + Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); + return CollisionProp()->OBBMins(); +} + +inline const Vector& CBaseEntity::WorldAlignMaxs( ) const +{ + Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); + Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); + return CollisionProp()->OBBMaxs(); +} + +inline const Vector& CBaseEntity::WorldAlignSize( ) const +{ + Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); + Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); + return CollisionProp()->OBBSize(); +} + +// Returns a radius of a sphere *centered at the world space center* +// bounding the collision representation of the entity +inline float CBaseEntity::BoundingRadius() const +{ + return CollisionProp()->BoundingRadius(); +} + +inline bool CBaseEntity::IsPointSized() const +{ + return CollisionProp()->BoundingRadius() == 0.0f; +} + +inline void CBaseEntity::SetRenderMode( RenderMode_t nRenderMode ) +{ + m_nRenderMode = nRenderMode; +} + +inline RenderMode_t CBaseEntity::GetRenderMode() const +{ + return (RenderMode_t)m_nRenderMode.Get(); +} + + +//----------------------------------------------------------------------------- +// Methods to cast away const +//----------------------------------------------------------------------------- +inline Vector CBaseEntity::EyePosition( void ) const +{ + return const_cast(this)->EyePosition(); +} + +inline const QAngle &CBaseEntity::EyeAngles( void ) const // Direction of eyes in world space +{ + return const_cast(this)->EyeAngles(); +} + +inline const QAngle &CBaseEntity::LocalEyeAngles( void ) const // Direction of eyes +{ + return const_cast(this)->LocalEyeAngles(); +} + +inline Vector CBaseEntity::EarPosition( void ) const // position of ears +{ + return const_cast(this)->EarPosition(); +} + + +//----------------------------------------------------------------------------- +// Methods relating to networking +//----------------------------------------------------------------------------- +inline void CBaseEntity::NetworkStateChanged() +{ + NetworkProp()->NetworkStateChanged(); +} + + +inline void CBaseEntity::NetworkStateChanged( void *pVar ) +{ + // Make sure it's a semi-reasonable pointer. + Assert( (char*)pVar > (char*)this ); + Assert( (char*)pVar - (char*)this < 32768 ); + + // Good, they passed an offset so we can track this variable's change + // and avoid sending the whole entity. + NetworkProp()->NetworkStateChanged( (char*)pVar - (char*)this ); +} + + +//----------------------------------------------------------------------------- +// IHandleEntity overrides. +//----------------------------------------------------------------------------- +inline const CBaseHandle& CBaseEntity::GetRefEHandle() const +{ + return m_RefEHandle; +} + +inline void CBaseEntity::IncrementTransmitStateOwnedCounter() +{ + Assert( m_nTransmitStateOwnedCounter != 255 ); + m_nTransmitStateOwnedCounter++; +} + +inline void CBaseEntity::DecrementTransmitStateOwnedCounter() +{ + Assert( m_nTransmitStateOwnedCounter != 0 ); + m_nTransmitStateOwnedCounter--; +} + + +//----------------------------------------------------------------------------- +// Bullet firing (legacy)... +//----------------------------------------------------------------------------- +inline void CBaseEntity::FireBullets( int cShots, const Vector &vecSrc, + const Vector &vecDirShooting, const Vector &vecSpread, float flDistance, + int iAmmoType, int iTracerFreq, int firingEntID, int attachmentID, + int iDamage, CBaseEntity *pAttacker, bool bFirstShotAccurate, bool bPrimaryAttack ) +{ + FireBulletsInfo_t info; + info.m_iShots = cShots; + info.m_vecSrc = vecSrc; + info.m_vecDirShooting = vecDirShooting; + info.m_vecSpread = vecSpread; + info.m_flDistance = flDistance; + info.m_iAmmoType = iAmmoType; + info.m_iTracerFreq = iTracerFreq; + info.m_flDamage = iDamage; + info.m_pAttacker = pAttacker; + info.m_nFlags = bFirstShotAccurate ? FIRE_BULLETS_FIRST_SHOT_ACCURATE : 0; + info.m_bPrimaryAttack = bPrimaryAttack; + + FireBullets( info ); +} + +// Ugly technique to override base member functions +// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a +// member function of a base class. static_cast is a sleezy way around that problem. + +#define SetThink( a ) ThinkSet( static_cast (a), 0, NULL ) +#define SetContextThink( a, b, context ) ThinkSet( static_cast (a), (b), context ) + +#ifdef _DEBUG +#define SetMoveDone( a ) \ + do \ + { \ + m_pfnMoveDone = static_cast (a); \ + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnMoveDone)))), "BaseMoveFunc" ); \ + } while ( 0 ) +#else +#define SetMoveDone( a ) \ + (void)(m_pfnMoveDone = static_cast (a)) +#endif + + +inline bool FClassnameIs(CBaseEntity *pEntity, const char *szClassname) +{ + return pEntity->ClassMatches(szClassname); +} + +class CPointEntity : public CBaseEntity +{ +public: + DECLARE_CLASS( CPointEntity, CBaseEntity ); + + void Spawn( void ); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual bool KeyValue( const char *szKeyName, const char *szValue ); +private: +}; + +// Has a position + size +class CServerOnlyEntity : public CBaseEntity +{ + DECLARE_CLASS( CServerOnlyEntity, CBaseEntity ); +public: + CServerOnlyEntity() : CBaseEntity( true ) {} + + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } +}; + +// Has only a position, no size +class CServerOnlyPointEntity : public CServerOnlyEntity +{ + DECLARE_CLASS( CServerOnlyPointEntity, CServerOnlyEntity ); + +public: + virtual bool KeyValue( const char *szKeyName, const char *szValue ); +}; + +// Has no position or size +class CLogicalEntity : public CServerOnlyEntity +{ + DECLARE_CLASS( CLogicalEntity, CServerOnlyEntity ); + +public: + virtual bool KeyValue( const char *szKeyName, const char *szValue ); +}; + + +// Network proxy functions + +void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_OriginXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_OriginZ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); + + +#endif // BASEENTITY_H diff --git a/game/server/baseflex.h b/game/server/baseflex.h new file mode 100644 index 0000000..1f0009e --- /dev/null +++ b/game/server/baseflex.h @@ -0,0 +1,302 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEFLEX_H +#define BASEFLEX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "BaseAnimatingOverlay.h" +#include "utlvector.h" +#include "utlrbtree.h" +#include "sceneentity_shared.h" + +struct flexsettinghdr_t; +struct flexsetting_t; +class AI_Response; + +//----------------------------------------------------------------------------- +// Purpose: A .vfe referenced by a scene during .vcd playback +//----------------------------------------------------------------------------- +class CFlexSceneFile +{ +public: + enum + { + MAX_FLEX_FILENAME = 128, + }; + + char filename[ MAX_FLEX_FILENAME ]; + void *buffer; +}; + +//----------------------------------------------------------------------------- +// Purpose: Animated characters who have vertex flex capability (e.g., facial expressions) +//----------------------------------------------------------------------------- +class CBaseFlex : public CBaseAnimatingOverlay +{ + DECLARE_CLASS( CBaseFlex, CBaseAnimatingOverlay ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DECLARE_PREDICTABLE(); + + // Construction + CBaseFlex( void ); + ~CBaseFlex( void ); + + virtual void SetModel( const char *szModelName ); + + void Blink( ); + + virtual void SetViewtarget( const Vector &viewtarget ); + const Vector &GetViewtarget( void ) const; + + void SetFlexWeight( char *szName, float value ); + void SetFlexWeight( LocalFlexController_t index, float value ); + float GetFlexWeight( char *szName ); + float GetFlexWeight( LocalFlexController_t index ); + + // Look up flex controller index by global name + LocalFlexController_t FindFlexController( const char *szName ); + void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ); + + // Keep track of what scenes are being played + void StartChoreoScene( CChoreoScene *scene ); + void RemoveChoreoScene( CChoreoScene *scene, bool canceled = false ); + + // Start the specifics of an scene event + virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + + // Manipulation of events for the object + // Should be called by think function to process all scene events + // The default implementation resets m_flexWeight array and calls + // AddSceneEvents + virtual void ProcessSceneEvents( void ); + + // Assumes m_flexWeight array has been set up, this adds the actual currently playing + // expressions to the flex weights and adds other scene events as needed + virtual bool ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + + // Remove all playing events + void ClearSceneEvents( CChoreoScene *scene, bool canceled ); + + // Stop specifics of event + virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled ); + + // Add the event to the queue for this actor + void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget = NULL ); + + // Remove the event from the queue for this actor + void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill ); + + // Checks to see if the event should be considered "completed" + bool CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + // Checks to see if a event should be considered "completed" + virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + // Finds the layer priority of the current scene + int GetScenePriority( CChoreoScene *scene ); + + // Returns true if the actor is not currently in a scene OR if the actor + // is in a scene, but a PERMIT_RESPONSES event is active and the permit time + // period has enough time remaining to handle the response in full. + bool PermitResponse( float response_length ); + + // Set response end time (0 to clear response blocking) + void SetPermitResponse( float endtime ); + + void SentenceStop( void ) { EmitSound( "AI_BaseNPC.SentenceStop" ); } + + virtual float PlayScene( const char *pszScene, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL ); + virtual float PlayAutoGeneratedSoundScene( const char *soundname ); + + virtual int GetSpecialDSP( void ) { return 0; } + +protected: + // For handling .vfe files + // Search list, or add if not in list + const void *FindSceneFile( const char *filename ); + + // Find setting by name + const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr ); + + // Called at the lowest level to actually apply an expression + void AddFlexSetting( const char *expr, float scale, const flexsettinghdr_t *pSettinghdr, bool newexpression ); + + // Called at the lowest level to actually apply a flex animation + void AddFlexAnimation( CSceneEventInfo *info ); + + bool HasSceneEvents() const; + bool IsRunningSceneMoveToEvent(); + + LocalFlexController_t FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key ); + +private: + // Starting various expression types + + bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + bool RequestStartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + + bool HandleStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor ); + bool HandleStartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor ); + bool StartFacingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + bool StartMoveToSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + + // Processing various expression types + bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessFacingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessMoveToSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + bool ProcessLookAtSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + + // Set playing the scene sequence +public: + bool EnterSceneSequence( CChoreoScene *scene, CChoreoEvent *event, bool bRestart = false ); +private: + bool ExitSceneSequence( void ); + +private: + CNetworkArray( float, m_flexWeight, MAXSTUDIOFLEXCTRL ); // indexed by model local flexcontroller + + // Vector from actor to eye target + CNetworkVector( m_viewtarget ); + + // Blink state + CNetworkVar( int, m_blinktoggle ); + + // Array of active SceneEvents, in order oldest to newest + CUtlVector < CSceneEventInfo > m_SceneEvents; + + // Mapping for each loaded scene file used by this actor + struct FS_LocalToGlobal_t + { + explicit FS_LocalToGlobal_t() : + m_Key( 0 ), + m_nCount( 0 ), + m_Mapping( 0 ) + { + } + + explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) : + m_Key( key ), + m_nCount( 0 ), + m_Mapping( 0 ) + { + } + + void SetCount( int count ) + { + Assert( !m_Mapping ); + Assert( count > 0 ); + m_nCount = count; + m_Mapping = new LocalFlexController_t[ m_nCount ]; + Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) ); + } + + FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src ) + { + m_Key = src.m_Key; + delete m_Mapping; + m_Mapping = new LocalFlexController_t[ src.m_nCount ]; + Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) ); + + m_nCount = src.m_nCount; + } + + ~FS_LocalToGlobal_t() + { + delete m_Mapping; + m_nCount = 0; + m_Mapping = 0; + } + + const flexsettinghdr_t *m_Key; + int m_nCount; + LocalFlexController_t *m_Mapping; + }; + + static bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ); + + CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal; + + // The NPC is in a scene, but another .vcd (such as a short wave to say in response to the player doing something ) + // can be layered on top of this actor (assuming duration matches, etc. + float m_flAllowResponsesEndTime; + + // List of actively playing scenes + CUtlVector < CChoreoScene * > m_ActiveChoreoScenes; + bool m_bUpdateLayerPriorities; + +public: + bool IsSuppressedFlexAnimation( CSceneEventInfo *info ); + +private: + // last time a foreground flex animation was played + float m_flLastFlexAnimationTime; + + +public: + void DoBodyLean( void ); + + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + + +#ifdef HL2_DLL + Vector m_vecPrevOrigin; + Vector m_vecPrevVelocity; + CNetworkVector( m_vecLean ); + CNetworkVector( m_vecShift ); +#endif +}; + + +//----------------------------------------------------------------------------- +// For toggling blinking +//----------------------------------------------------------------------------- +inline void CBaseFlex::Blink() +{ + m_blinktoggle = !m_blinktoggle; +} + +//----------------------------------------------------------------------------- +// Do we have active expressions? +//----------------------------------------------------------------------------- +inline bool CBaseFlex::HasSceneEvents() const +{ + return m_SceneEvents.Count() != 0; +} + + +//----------------------------------------------------------------------------- +// Other inlines +//----------------------------------------------------------------------------- +inline const Vector &CBaseFlex::GetViewtarget( ) const +{ + return m_viewtarget.Get(); // bah +} + +inline void CBaseFlex::SetFlexWeight( char *szName, float value ) +{ + SetFlexWeight( FindFlexController( szName ), value ); +} + +inline float CBaseFlex::GetFlexWeight( char *szName ) +{ + return GetFlexWeight( FindFlexController( szName ) ); +} + + +EXTERN_SEND_TABLE(DT_BaseFlex); + + +#endif // BASEFLEX_H diff --git a/game/server/basemultiplayerplayer.h b/game/server/basemultiplayerplayer.h new file mode 100644 index 0000000..a1ea58f --- /dev/null +++ b/game/server/basemultiplayerplayer.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//============================================================================= +#ifndef BASEMULTIPLAYERPLAYER_H +#define BASEMULTIPLAYERPLAYER_H +#pragma once + +#include "player.h" +#include "ai_speech.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBaseMultiplayerPlayer : public CAI_ExpresserHost +{ + + DECLARE_CLASS( CBaseMultiplayerPlayer, CAI_ExpresserHost ); + +public: + + CBaseMultiplayerPlayer(); + ~CBaseMultiplayerPlayer(); + + virtual void Spawn( void ); + + virtual void PostConstructor( const char *szClassname ); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ); + + virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + virtual IResponseSystem *GetResponseSystem(); + bool SpeakConcept( AI_Response& response, int iConcept ); + virtual bool SpeakConceptIfAllowed( int iConcept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + + virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer ); + virtual bool CanSpeak( void ) { return true; } + virtual bool CanBeAutobalanced() { return true; } + + virtual void Precache( void ) + { + PrecacheParticleSystem( "achieved" ); + + BaseClass::Precache(); + } + + virtual bool ClientCommand( const CCommand &args ); + + virtual bool CanSpeakVoiceCommand( void ) { return true; } + virtual bool ShouldShowVoiceSubtitleToEnemy( void ); + virtual void NoteSpokeVoiceCommand( const char *pszScenePlayed ) {} + + virtual void OnAchievementEarned( int iAchievement ) {} + + enum + { + CHAT_IGNORE_NONE = 0, + CHAT_IGNORE_ALL, + CHAT_IGNORE_TEAM, + }; + + int m_iIgnoreGlobalChat; + + //--------------------------------- + // Speech support + virtual CAI_Expresser *GetExpresser() { return m_pExpresser; } + virtual CMultiplayer_Expresser *GetMultiplayerExpresser() { return m_pExpresser; } + + void SetLastForcedChangeTeamTimeToNow( void ) { m_flLastForcedChangeTeamTime = gpGlobals->curtime; } + float GetLastForcedChangeTeamTime( void ) { return m_flLastForcedChangeTeamTime; } + + void SetTeamBalanceScore( int iScore ) { m_iBalanceScore = iScore; } + int GetTeamBalanceScore( void ) { return m_iBalanceScore; } + + virtual int CalculateTeamBalanceScore( void ); + + void AwardAchievement( int iAchievement, int iCount = 1 ); + int GetPerLifeCounterKV( const char *name ); + void SetPerLifeCounterKV( const char *name, int value ); + void ResetPerLifeCounters( void ); + + KeyValues *GetPerLifeCounterKeys( void ) { return m_pAchievementKV; } + + void EscortScoringThink( void ); + void StartScoringEscortPoints( float flRate ); + void StopScoringEscortPoints( void ); + float m_flAreaCaptureScoreAccumulator; + float m_flCapPointScoreRate; + + float GetConnectionTime( void ) { return m_flConnectionTime; } + + // Command rate limiting. + bool ShouldRunRateLimitedCommand( const CCommand &args ); + bool ShouldRunRateLimitedCommand( const char *pszCommand ); + +protected: + virtual CAI_Expresser *CreateExpresser( void ); + + int m_iCurrentConcept; +private: + //--------------------------------- + CMultiplayer_Expresser *m_pExpresser; + + float m_flConnectionTime; + float m_flLastForcedChangeTeamTime; + + int m_iBalanceScore; // a score used to determine which players are switched to balance the teams + + KeyValues *m_pAchievementKV; + + // This lets us rate limit the commands the players can execute so they don't overflow things like reliable buffers. + CUtlDict m_RateLimitLastCommandTimes; +}; + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline CBaseMultiplayerPlayer *ToBaseMultiplayerPlayer( CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; +#if _DEBUG + return dynamic_cast( pEntity ); +#else + return static_cast( pEntity ); +#endif +} + +#endif // BASEMULTIPLAYERPLAYER_H diff --git a/game/server/basetempentity.h b/game/server/basetempentity.h new file mode 100644 index 0000000..bef0910 --- /dev/null +++ b/game/server/basetempentity.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( BASETEMPENTITY_H ) +#define BASETEMPENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "edict.h" + +// This is the base class for TEMP ENTITIES that use the +// event system to propagate +class CBaseTempEntity +{ +public: + DECLARE_CLASS_NOBASE( CBaseTempEntity ); + DECLARE_SERVERCLASS(); + + CBaseTempEntity( const char *name ); + virtual ~CBaseTempEntity( void ); + + const char *GetName( void ); + + // Force all derived classes to implement a test + virtual void Test( const Vector& current_origin, const QAngle& current_angles ); + + virtual void Create( IRecipientFilter& filter, float delay = 0.0 ); + + virtual void Precache( void ); + + CBaseTempEntity *GetNext( void ); + + // Get list of tempentities + static CBaseTempEntity *GetList( void ); + + // Called at startup to allow temp entities to precache any models/sounds that they need + static void PrecacheTempEnts( void ); + + void NetworkStateChanged() {} // TE's are sent out right away so we don't track whether state changes or not, + // but we want to allow CNetworkVars. + void NetworkStateChanged( void *pVar ) {} + +private: + // Descriptive name, for when running tests + const char *m_pszName; + + // Next in chain + CBaseTempEntity *m_pNext; + + // ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through + // all the console variables and registers them. + static CBaseTempEntity *s_pTempEntities; +}; + +#endif // BASETEMPENTITY_H diff --git a/game/server/basetoggle.h b/game/server/basetoggle.h new file mode 100644 index 0000000..877e48d --- /dev/null +++ b/game/server/basetoggle.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: For the slow removing of the CBaseToggle entity +// only old entities that need it for backwards-compatibility should +// include this file +//=============================================================================// + +#ifndef BASETOGGLE_H +#define BASETOGGLE_H +#pragma once + +#include "baseentity.h" + + +class CBaseToggle : public CBaseEntity +{ + DECLARE_CLASS( CBaseToggle, CBaseEntity ); +public: + CBaseToggle(); + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual bool KeyValue( const char *szKeyName, Vector vec ) { return BaseClass::KeyValue( szKeyName, vec ); }; + virtual bool KeyValue( const char *szKeyName, float flValue ) { return BaseClass::KeyValue( szKeyName, flValue ); }; + + TOGGLE_STATE m_toggle_state; + float m_flMoveDistance;// how far a door should slide or rotate + float m_flWait; + float m_flLip; + + Vector m_vecPosition1; + Vector m_vecPosition2; + + QAngle m_vecMoveAng; + QAngle m_vecAngle1; + QAngle m_vecAngle2; + + float m_flHeight; + EHANDLE m_hActivator; + Vector m_vecFinalDest; + QAngle m_vecFinalAngle; + + int m_movementType; + + DECLARE_DATADESC(); + + virtual float GetDelay( void ) { return m_flWait; } + + // common member functions + void LinearMove( const Vector &vecDest, float flSpeed ); + void LinearMoveDone( void ); + void AngularMove( const QAngle &vecDestAngle, float flSpeed ); + void AngularMoveDone( void ); + bool IsLockedByMaster( void ); + virtual void MoveDone( void ); + + static float AxisValue( int flags, const QAngle &angles ); + void AxisDir( void ); + static float AxisDelta( int flags, const QAngle &angle1, const QAngle &angle2 ); + + string_t m_sMaster; // If this button has a master switch, this is the targetname. + // A master switch must be of the multisource type. If all + // of the switches in the multisource have been triggered, then + // the button will be allowed to operate. Otherwise, it will be + // deactivated. +}; + + + +#endif // BASETOGGLE_H diff --git a/game/server/baseviewmodel.h b/game/server/baseviewmodel.h new file mode 100644 index 0000000..6560bbd --- /dev/null +++ b/game/server/baseviewmodel.h @@ -0,0 +1,17 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Server side view model object +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( BASEVIEWMODEL_H ) +#define BASEVIEWMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseviewmodel_shared.h" + +#endif // BASEVIEWMODEL_H \ No newline at end of file diff --git a/game/server/bitstring.h b/game/server/bitstring.h new file mode 100644 index 0000000..f3c063f --- /dev/null +++ b/game/server/bitstring.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Arbitrary length bit string +// ** NOTE: This class does NOT override the bitwise operators +// as doing so would require overriding the operators +// to allocate memory for the returned bitstring. This method +// would be prone to memory leaks as the calling party +// would have to remember to delete the memory. Funtions +// are used instead to require the calling party to allocate +// and destroy their own memory +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BITSTRING_H +#define BITSTRING_H +#pragma once + +#include "bitvec.h" + + +#endif // BITSTRING_H diff --git a/game/server/buttons.h b/game/server/buttons.h new file mode 100644 index 0000000..c78a865 --- /dev/null +++ b/game/server/buttons.h @@ -0,0 +1,172 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef BUTTONS_H +#define BUTTONS_H +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseButton : public CBaseToggle +{ +public: + + DECLARE_CLASS( CBaseButton, CBaseToggle ); + + void Spawn( void ); + virtual void Precache( void ); + bool CreateVPhysics(); + void RotSpawn( void ); + bool KeyValue( const char *szKeyName, const char *szValue ); + int DrawDebugTextOverlays(); + +protected: + + void ButtonActivate( ); + void SparkSoundCache( void ); + + void ButtonTouch( ::CBaseEntity *pOther ); + void ButtonSpark ( void ); + void TriggerAndWait( void ); + void ButtonReturn( void ); + void ButtonBackHome( void ); + void ButtonUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + bool OnUseLocked( CBaseEntity *pActivator ); + + virtual void Lock(); + virtual void Unlock(); + + // Input handlers + void InputLock( inputdata_t &inputdata ); + void InputUnlock( inputdata_t &inputdata ); + void InputPress( inputdata_t &inputdata ); + void InputPressIn( inputdata_t &inputdata ); + void InputPressOut( inputdata_t &inputdata ); + + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN, BUTTON_PRESS }; + + BUTTON_CODE ButtonResponseToTouch( void ); + void Press( CBaseEntity *pActivator, BUTTON_CODE eCode ); + + DECLARE_DATADESC(); + + virtual int ObjectCaps(void); + + Vector m_vecMoveDir; + + bool m_fStayPushed; // button stays pushed in until touched again? + bool m_fRotating; // a rotating button? default is a sliding button. + + locksound_t m_ls; // door lock sounds + + byte m_bLockedSound; // ordinals from entity selection + byte m_bLockedSentence; + byte m_bUnlockedSound; + byte m_bUnlockedSentence; + bool m_bLocked; + int m_sounds; + float m_flUseLockedTime; // Controls how often we fire the OnUseLocked output. + + bool m_bSolidBsp; + + string_t m_sNoise; // The actual WAV file name of the sound. + + COutputEvent m_OnDamaged; + COutputEvent m_OnPressed; + COutputEvent m_OnUseLocked; + COutputEvent m_OnIn; + COutputEvent m_OnOut; + + int m_nState; +}; + + +// +// Rotating button (aka "lever") +// +class CRotButton : public CBaseButton +{ +public: + DECLARE_CLASS( CRotButton, CBaseButton ); + + void Spawn( void ); + bool CreateVPhysics( void ); + +}; + + +class CMomentaryRotButton : public CRotButton +{ + DECLARE_CLASS( CMomentaryRotButton, CRotButton ); + +public: + void Spawn ( void ); + bool CreateVPhysics( void ); + virtual int ObjectCaps( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void UseMoveDone( void ); + void ReturnMoveDone( void ); + void OutputMovementComplete(void); + void SetPositionMoveDone(void); + void UpdateSelf( float value, bool bPlaySound ); + + void PlaySound( void ); + void UpdateTarget( float value, CBaseEntity *pActivator ); + + int DrawDebugTextOverlays(void); + + static CMomentaryRotButton *Instance( edict_t *pent ) { return (CMomentaryRotButton *)GetContainingEntity(pent); } + + float GetPos(const QAngle &vecAngles); + + DECLARE_DATADESC(); + + virtual void Lock(); + virtual void Unlock(); + + // Input handlers + void InputSetPosition( inputdata_t &inputdata ); + void InputSetPositionImmediately( inputdata_t &inputdata ); + void InputDisableUpdateTarget( inputdata_t &inputdata ); + void InputEnableUpdateTarget( inputdata_t &inputdata ); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + virtual void Enable( void ); + virtual void Disable( void ); + + bool m_bDisabled; + + COutputFloat m_Position; + COutputEvent m_OnUnpressed; + COutputEvent m_OnFullyOpen; + COutputEvent m_OnFullyClosed; + COutputEvent m_OnReachedPosition; + + int m_lastUsed; + QAngle m_start; + QAngle m_end; + float m_IdealYaw; + string_t m_sNoise; + + bool m_bUpdateTarget; // Used when jiggling so that we don't jiggle the target (door, etc) + + int m_direction; + float m_returnSpeed; + float m_flStartPosition; + +protected: + + void UpdateThink( void ); +}; + + +#endif // BUTTONS_H diff --git a/game/server/cbase.h b/game/server/cbase.h new file mode 100644 index 0000000..0d56ec3 --- /dev/null +++ b/game/server/cbase.h @@ -0,0 +1,154 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CBASE_H +#define CBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _WIN32 +// Silence certain warnings +#pragma warning(disable : 4244) // int or float down-conversion +#pragma warning(disable : 4305) // int or float data truncation +#pragma warning(disable : 4201) // nameless struct/union +#pragma warning(disable : 4511) // copy constructor could not be generated +#pragma warning(disable : 4675) // resolved overload was found by argument dependent lookup +#endif + +#ifdef _DEBUG +#define DEBUG 1 +#endif + +// Misc C-runtime library headers +#include + +#include + +// tier 0 +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "basetypes.h" + +// tier 1 +#include "tier1/strtools.h" +#include "utlvector.h" +#include "mathlib/vmatrix.h" + +// tier 2 +#include "string_t.h" + +// tier 3 +#include "vphysics_interface.h" + +// Shared engine/DLL constants +#include "const.h" +#include "edict.h" + +// Shared header describing protocol between engine and DLLs +#include "eiface.h" +#include "iserverentity.h" + +#include "dt_send.h" + +// Shared header between the client DLL and the game DLLs +#include "shareddefs.h" +#include "ehandle.h" + +// app +#if defined(_X360) +#define DISABLE_DEBUG_HISTORY 1 +#endif + + +#include "datamap.h" +#include "util.h" +#include "predictable_entity.h" +#include "predictableid.h" +#include "variant_t.h" +#include "takedamageinfo.h" +#include "utllinkedlist.h" +#include "touchlink.h" +#include "groundlink.h" +#include "base_transmit_proxy.h" +#include "soundflags.h" +#include "networkvar.h" +#include "baseentity_shared.h" +#include "basetoggle.h" +#include "igameevents.h" + +// saverestore.h declarations +class ISave; +class IRestore; + +// maximum number of targets a single multi_manager entity may be assigned. +#define MAX_MULTI_TARGETS 16 + +// NPCEvent.h declarations +struct animevent_t; + +struct studiohdr_t; +class CStudioHdr; + +extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +// people gib if their health is <= this at the time of death +#define GIB_HEALTH_VALUE -30 + +#define MAX_OLD_ENEMIES 4 // how many old enemies to remember + +// used by suit voice to indicate damage sustained and repaired type to player + +enum +{ + itbd_Paralyze = 0, + itbd_NerveGas, + itbd_PoisonRecover, + itbd_Radiation, + itbd_DrownRecover, + itbd_Acid, + itbd_SlowBurn, + itbd_SlowFreeze, + + // Must be last! + CDMG_TIMEBASED +}; + +// when calling KILLED(), a value that governs gib behavior is expected to be +// one of these three values +#define GIB_NORMAL 0// gib if entity was overkilled +#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc ) +#define GIB_ALWAYS 2// always gib + +class CAI_BaseNPC; +class CAI_ScriptedSequence; +class CSound; + +#ifdef _XBOX +//#define FUNCTANK_AUTOUSE We haven't made the decision to use this yet (sjb) +#else +#undef FUNCTANK_AUTOUSE +#endif//_XBOX + +// This is a precompiled header. Include a bunch of common stuff. +// This is kind of ugly in that it adds a bunch of dependency where it isn't needed. +// But on balance, the compile time is much lower (even incrementally) once the precompiled +// headers contain these headers. +#include "precache_register.h" +#include "baseanimating.h" +#include "basecombatweapon.h" +#include "basecombatcharacter.h" +#include "gamerules.h" +#include "entitylist.h" +#include "basetempentity.h" +#include "player.h" +#include "te.h" +#include "physics.h" +#include "ndebugoverlay.h" +#include "recipientfilter.h" + +#endif // CBASE_H diff --git a/game/server/client.h b/game/server/client.h new file mode 100644 index 0000000..076d6ca --- /dev/null +++ b/game/server/client.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef CLIENT_H +#define CLIENT_H + +#ifdef _WIN32 +#pragma once +#endif + + +class CCommand; +class CUserCmd; +class CBasePlayer; + + +void ClientActive( edict_t *pEdict, bool bLoadGame ); +void ClientPutInServer( edict_t *pEdict, const char *playername ); +void ClientCommand( CBasePlayer *pSender, const CCommand &args ); +void ClientPrecache( void ); +// Game specific precaches +void ClientGamePrecache( void ); +const char *GetGameDescription( void ); +void Host_Say( edict_t *pEdict, bool teamonly ); + + + +#endif // CLIENT_H diff --git a/game/server/cplane.h b/game/server/cplane.h new file mode 100644 index 0000000..98d5b45 --- /dev/null +++ b/game/server/cplane.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#pragma once + +#ifndef CPLANE_H +#define CPLANE_H + +//========================================================= +// Plane +//========================================================= +class CPlane +{ +public: + CPlane ( void ); + + //========================================================= + // InitializePlane - Takes a normal for the plane and a + // point on the plane and + //========================================================= + void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ); + + //========================================================= + // PointInFront - determines whether the given vector is + // in front of the plane. + //========================================================= + bool PointInFront ( const Vector &vecPoint ); + + //========================================================= + // How far off the plane is this point? + //========================================================= + float PointDist( const Vector &vecPoint ); + +private: + Vector m_vecNormal; + float m_flDist; + bool m_fInitialized; +}; + +#endif //CPLANE_H diff --git a/game/server/damagemodifier.h b/game/server/damagemodifier.h new file mode 100644 index 0000000..5123f63 --- /dev/null +++ b/game/server/damagemodifier.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DAMAGEMODIFIER_H +#define DAMAGEMODIFIER_H +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseEntity; + + +#include "ehandle.h" + +//----------------------------------------------------------------------------- +// Purpose: Class handling generic damage modification to & from a player +//----------------------------------------------------------------------------- +class CDamageModifier +{ +public: + CDamageModifier(); + + void AddModifierToEntity( CBaseEntity *pChar ); + void RemoveModifier(); + + void SetModifier( float flDamageScale ); + float GetModifier() const; + + void SetDoneToMe( bool bDoneToMe ); + bool IsDamageDoneToMe() const; + + CBaseEntity *GetCharacter() const; + +private: + float m_flModifier; + CHandle m_hEnt; + bool m_bDoneToMe; // True = modifies damage done to the entity, false = damage done by the entity +}; + + +#endif // DAMAGEMODIFIER_H diff --git a/game/server/data_collector.h b/game/server/data_collector.h new file mode 100644 index 0000000..ba1b9fd --- /dev/null +++ b/game/server/data_collector.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// data_collector.h +// Data collection system +// Author: Michael S. Booth, June 2004 + +#ifndef _DATA_COLLECTOR_H_ +#define _DATA_COLLECTOR_H_ + +#include +#include + +/** + * This class is used to monitor the event stream and + * store interesting events to disk for later analysis. + */ +class CDataCollector : public IGameEventListener +{ +public: + CDataCollector( void ); + ~CDataCollector(); + + // IGameEventListener + virtual void FireGameEvent( KeyValues *event ); +}; + + +extern void StartDataCollection( void ); +extern void StopDataCollection( void ); + + +#endif // _DATA_COLLECTOR_H_ diff --git a/game/server/doors.h b/game/server/doors.h new file mode 100644 index 0000000..9b485fe --- /dev/null +++ b/game/server/doors.h @@ -0,0 +1,164 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOORS_H +#define DOORS_H +#pragma once + + +#include "locksounds.h" +#include "entityoutput.h" + +//Since I'm here, might as well explain how these work. Base.fgd is the file that connects +//flags to entities. It is full of lines with this number, a label, and a default value. +//Voila, dynamicly generated checkboxes on the Flags tab of Entity Properties. + +// doors +#define SF_DOOR_ROTATE_YAW 0 // yaw by default +#define SF_DOOR_START_OPEN_OBSOLETE 1 +#define SF_DOOR_ROTATE_BACKWARDS 2 +#define SF_DOOR_NONSOLID_TO_PLAYER 4 +#define SF_DOOR_PASSABLE 8 +#define SF_DOOR_ONEWAY 16 +#define SF_DOOR_NO_AUTO_RETURN 32 +#define SF_DOOR_ROTATE_ROLL 64 +#define SF_DOOR_ROTATE_PITCH 128 +#define SF_DOOR_PUSE 256 // door can be opened by player's use button. +#define SF_DOOR_NONPCS 512 // NPC can't open +#define SF_DOOR_PTOUCH 1024 // player touch opens +#define SF_DOOR_LOCKED 2048 // Door is initially locked +#define SF_DOOR_SILENT 4096 // Door plays no audible sound, and does not alert NPCs when opened +#define SF_DOOR_USE_CLOSES 8192 // Door can be +used to close before its autoreturn delay has expired. +#define SF_DOOR_SILENT_TO_NPCS 16384 // Does not alert NPC's when opened. +#define SF_DOOR_IGNORE_USE 32768 // Completely ignores player +use commands. +#define SF_DOOR_NEW_USE_RULES 65536 // For func_door entities, behave more like prop_door_rotating with respect to +USE (changelist 242482) + + +enum FuncDoorSpawnPos_t +{ + FUNC_DOOR_SPAWN_CLOSED = 0, + FUNC_DOOR_SPAWN_OPEN, +}; + + +class CBaseDoor : public CBaseToggle +{ +public: + DECLARE_CLASS( CBaseDoor, CBaseToggle ); + + DECLARE_SERVERCLASS(); + + void Spawn( void ); + void Precache( void ); + bool CreateVPhysics(); + bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual void StartBlocked( CBaseEntity *pOther ); + virtual void Blocked( CBaseEntity *pOther ); + virtual void EndBlocked( void ); + + void Activate( void ); + + virtual int ObjectCaps( void ) + { + int flags = BaseClass::ObjectCaps(); + if ( HasSpawnFlags( SF_DOOR_PUSE ) ) + return flags | FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS; + + return flags; + }; + + DECLARE_DATADESC(); + + // This is ONLY used by the node graph to test movement through a door + void InputSetToggleState( inputdata_t &inputdata ); + virtual void SetToggleState( int state ); + + virtual bool IsRotatingDoor() { return false; } + virtual bool ShouldSavePhysics(); + // used to selectivly override defaults + void DoorTouch( CBaseEntity *pOther ); + + // local functions + int DoorActivate( ); + void DoorGoUp( void ); + void DoorGoDown( void ); + void DoorHitTop( void ); + void DoorHitBottom( void ); + void UpdateAreaPortals( bool isOpen ); + void Unlock( void ); + void Lock( void ); + int GetDoorMovementGroup( CBaseDoor *pDoorList[], int listMax ); + + // Input handlers + void InputClose( inputdata_t &inputdata ); + void InputLock( inputdata_t &inputdata ); + void InputOpen( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + void InputUnlock( inputdata_t &inputdata ); + void InputSetSpeed( inputdata_t &inputdata ); + + Vector m_vecMoveDir; // The direction of motion for linear moving doors. + + locksound_t m_ls; // door lock sounds + + byte m_bLockedSentence; + byte m_bUnlockedSentence; + + bool m_bForceClosed; // If set, always close, even if we're blocked. + bool m_bDoorGroup; + bool m_bLocked; // Whether the door is locked + bool m_bIgnoreDebris; + bool m_bIgnoreNonPlayerEntsOnBlock; // Non-player entities should never block. This variable needs more letters. + + FuncDoorSpawnPos_t m_eSpawnPosition; + + float m_flBlockDamage; // Damage inflicted when blocked. + string_t m_NoiseMoving; //Start/Looping sound + string_t m_NoiseArrived; //End sound + string_t m_NoiseMovingClosed; //Start/Looping sound + string_t m_NoiseArrivedClosed; //End sound + string_t m_ChainTarget; ///< Entity name to pass Touch and Use events to + + CNetworkVar( float, m_flWaveHeight ); + + // Outputs + COutputEvent m_OnBlockedClosing; // Triggered when the door becomes blocked while closing. + COutputEvent m_OnBlockedOpening; // Triggered when the door becomes blocked while opening. + COutputEvent m_OnUnblockedClosing; // Triggered when the door becomes unblocked while closing. + COutputEvent m_OnUnblockedOpening; // Triggered when the door becomes unblocked while opening. + COutputEvent m_OnFullyClosed; // Triggered when the door reaches the fully closed position. + COutputEvent m_OnFullyOpen; // Triggered when the door reaches the fully open position. + COutputEvent m_OnClose; // Triggered when the door is told to close. + COutputEvent m_OnOpen; // Triggered when the door is told to open. + COutputEvent m_OnLockedUse; // Triggered when the user tries to open a locked door. + + void StartMovingSound( void ); + virtual void StopMovingSound( void ); + void MovingSoundThink( void ); +#ifdef HL1_DLL + bool PassesBlockTouchFilter(CBaseEntity *pOther); + string_t m_iBlockFilterName; + EHANDLE m_hBlockFilter; +#endif + + bool ShouldLoopMoveSound( void ) { return m_bLoopMoveSound; } + bool m_bLoopMoveSound; // Move sound loops until stopped + + virtual bool ShouldBlockNav() const OVERRIDE { return false; } + +private: + void ChainUse( void ); ///< Chains +use on through to m_ChainTarget + void ChainTouch( CBaseEntity *pOther ); ///< Chains touch on through to m_ChainTarget + void SetChaining( bool chaining ) { m_isChaining = chaining; } ///< Latch to prevent recursion + bool m_isChaining; + + void CloseAreaPortalsThink( void ); ///< Delays turning off area portals when closing doors to prevent visual artifacts +}; + +#endif // DOORS_H diff --git a/game/server/effects.h b/game/server/effects.h new file mode 100644 index 0000000..364657f --- /dev/null +++ b/game/server/effects.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EFFECTS_H +#define EFFECTS_H + +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseEntity; +class Vector; + + +//----------------------------------------------------------------------------- +// The rotor wash shooter. It emits gibs when pushed by a rotor wash +//----------------------------------------------------------------------------- +abstract_class IRotorWashShooter +{ +public: + virtual CBaseEntity *DoWashPush( float flWashStartTime, const Vector &vecForce ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Gets at the interface if the entity supports it +//----------------------------------------------------------------------------- +IRotorWashShooter *GetRotorWashShooter( CBaseEntity *pEntity ); + +class CEnvQuadraticBeam : public CPointEntity +{ + DECLARE_CLASS( CEnvQuadraticBeam, CPointEntity ); + +public: + void Spawn(); + void SetSpline( const Vector &control, const Vector &target ) + { + m_targetPosition = target; + m_controlPosition = control; + } + void SetScrollRate( float rate ) + { + m_scrollRate = rate; + } + + void SetWidth( float width ) + { + m_flWidth = width; + } + +private: + CNetworkVector( m_targetPosition ); + CNetworkVector( m_controlPosition ); + CNetworkVar( float, m_scrollRate ); + CNetworkVar( float, m_flWidth ); + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); +}; +CEnvQuadraticBeam *CreateQuadraticBeam( const char *pSpriteName, const Vector &start, const Vector &control, const Vector &end, float width, CBaseEntity *pOwner ); + + +#endif // EFFECTS_H diff --git a/game/server/enginecallback.h b/game/server/enginecallback.h new file mode 100644 index 0000000..cce0786 --- /dev/null +++ b/game/server/enginecallback.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef ENGINECALLBACK_H +#define ENGINECALLBACK_H + +#ifndef EIFACE_H +#include "eiface.h" +#endif + +class IFileSystem; // include filesystem.h +class IEngineSound; // include engine/IEngineSound.h +class IVEngineServer; +class IVoiceServer; +class IStaticPropMgrServer; +class ISpatialPartition; +class IVModelInfo; +class IEngineTrace; +class IGameEventManager2; +class IVDebugOverlay; +class IDataCache; +class IMDLCache; +class IServerEngineTools; +class IXboxSystem; +class CSteamAPIContext; +class CSteamGameServerAPIContext; + +extern IVEngineServer *engine; +extern IVoiceServer *g_pVoiceServer; +extern IFileSystem *filesystem; +extern IStaticPropMgrServer *staticpropmgr; +extern ISpatialPartition *partition; +extern IEngineSound *enginesound; +extern IVModelInfo *modelinfo; +extern IEngineTrace *enginetrace; +extern IGameEventManager2 *gameeventmanager; +extern IVDebugOverlay *debugoverlay; +extern IDataCache *datacache; +extern IMDLCache *mdlcache; +extern IServerEngineTools *serverenginetools; +extern IXboxSystem *xboxsystem; // 360 only +extern CSteamAPIContext *steamapicontext; // available on game clients +extern CSteamGameServerAPIContext *steamgameserverapicontext; //available on game servers + + + +//----------------------------------------------------------------------------- +// Precaches a material +//----------------------------------------------------------------------------- +void PrecacheMaterial( const char *pMaterialName ); + +//----------------------------------------------------------------------------- +// Converts a previously precached material into an index +//----------------------------------------------------------------------------- +int GetMaterialIndex( const char *pMaterialName ); + +//----------------------------------------------------------------------------- +// Converts a previously precached material index into a string +//----------------------------------------------------------------------------- +const char *GetMaterialNameFromIndex( int nMaterialIndex ); + + +//----------------------------------------------------------------------------- +// Precache-related methods for particle systems +//----------------------------------------------------------------------------- +void PrecacheParticleSystem( const char *pParticleSystemName ); +int GetParticleSystemIndex( const char *pParticleSystemName ); +const char *GetParticleSystemNameFromIndex( int nIndex ); + + +class IRecipientFilter; +void EntityMessageBegin( CBaseEntity * entity, bool reliable = false ); +void UserMessageBegin( IRecipientFilter& filter, const char *messagename ); +void MessageEnd( void ); + +// bytewise +void MessageWriteByte( int iValue); +void MessageWriteChar( int iValue); +void MessageWriteShort( int iValue); +void MessageWriteWord( int iValue ); +void MessageWriteLong( int iValue); +void MessageWriteFloat( float flValue); +void MessageWriteAngle( float flValue); +void MessageWriteCoord( float flValue); +void MessageWriteVec3Coord( const Vector& rgflValue); +void MessageWriteVec3Normal( const Vector& rgflValue); +void MessageWriteAngles( const QAngle& rgflValue); +void MessageWriteString( const char *sz ); +void MessageWriteEntity( int iValue); +void MessageWriteEHandle( CBaseEntity *pEntity ); //encoded as a long + + +// bitwise +void MessageWriteBool( bool bValue ); +void MessageWriteUBitLong( unsigned int data, int numbits ); +void MessageWriteSBitLong( int data, int numbits ); +void MessageWriteBits( const void *pIn, int nBits ); + +#ifndef NO_STEAM + +/// Returns Steam ID, given player index. Returns an invalid SteamID upon +/// failure +extern CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex ); + +#endif + + +// Bytewise +#define WRITE_BYTE (MessageWriteByte) +#define WRITE_CHAR (MessageWriteChar) +#define WRITE_SHORT (MessageWriteShort) +#define WRITE_WORD (MessageWriteWord) +#define WRITE_LONG (MessageWriteLong) +#define WRITE_FLOAT (MessageWriteFloat) +#define WRITE_ANGLE (MessageWriteAngle) +#define WRITE_COORD (MessageWriteCoord) +#define WRITE_VEC3COORD (MessageWriteVec3Coord) +#define WRITE_VEC3NORMAL (MessageWriteVec3Normal) +#define WRITE_ANGLES (MessageWriteAngles) +#define WRITE_STRING (MessageWriteString) +#define WRITE_ENTITY (MessageWriteEntity) +#define WRITE_EHANDLE (MessageWriteEHandle) + +// Bitwise +#define WRITE_BOOL (MessageWriteBool) +#define WRITE_UBITLONG (MessageWriteUBitLong) +#define WRITE_SBITLONG (MessageWriteSBitLong) +#define WRITE_BITS (MessageWriteBits) + +#endif //ENGINECALLBACK_H diff --git a/game/server/entityapi.h b/game/server/entityapi.h new file mode 100644 index 0000000..234001d --- /dev/null +++ b/game/server/entityapi.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef ENTITYAPI_H +#define ENTITYAPI_H + + +class SendTable; + +extern void LoadMapEntities( const char *pMapEntities ); +extern void DispatchObjectCollisionBox( edict_t *pent ); +extern float DispatchObjectPhysicsVelocity( edict_t *pent, float moveTime ); +extern ServerClass* DispatchGetObjectServerClass(edict_t *pent); +extern ServerClass* GetAllServerClasses(); +extern void SaveWriteFields( CSaveRestoreData *pSaveData, const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); +extern void SaveReadFields( CSaveRestoreData *pSaveData, const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); +extern void SaveGlobalState( CSaveRestoreData *pSaveData ); +extern void RestoreGlobalState( CSaveRestoreData *pSaveData ); +extern void ResetGlobalState( void ); +extern CSaveRestoreData *SaveInit( int size ); +extern int CreateEntityTransitionList( CSaveRestoreData *pSaveData, int levelMask ); +extern void ClearEntities( void ); +extern void FreeContainingEntity( edict_t *ed ); + +class ISaveRestoreBlockHandler; +ISaveRestoreBlockHandler *GetEntitySaveRestoreBlockHandler(); + + +#endif // ENTITYAPI_H diff --git a/game/server/entityblocker.h b/game/server/entityblocker.h new file mode 100644 index 0000000..cc6c3fd --- /dev/null +++ b/game/server/entityblocker.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYBLOCKER_H +#define ENTITYBLOCKER_H +#ifdef _WIN32 +#pragma once +#endif + +//================================================================================================================== +// Entity Blocker +//================================================================================================================== +class CEntityBlocker : public CBaseEntity +{ + DECLARE_CLASS( CEntityBlocker, CBaseEntity ); + +public: + + static CEntityBlocker *Create( const Vector &origin, const Vector &mins, const Vector &maxs, CBaseEntity *pOwner = NULL, bool bBlockPhysics = false ); + + void Spawn( void ); + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); +}; + +#endif // ENTITYBLOCKER_H diff --git a/game/server/entityinput.h b/game/server/entityinput.h new file mode 100644 index 0000000..df6b69b --- /dev/null +++ b/game/server/entityinput.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef INPUTVAR_H +#define INPUTVAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "entitylist.h" + +//----------------------------------------------------------------------------- +// Purpose: Used to request a value, or a set of values, from a set of entities. +// used when a multi-input variable needs to refresh it's inputs +//----------------------------------------------------------------------------- +class CMultiInputVar +{ +public: + CMultiInputVar() : m_InputList(NULL) {} + ~CMultiInputVar(); + + struct inputitem_t + { + variant_t value; // local copy of variable (maybe make this a variant?) + int outputID; // the ID number of the output that sent this + inputitem_t *next; + + // allocate and free from MPool memory + static void *operator new( size_t stAllocBlock ); + static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); + static void operator delete( void *pMem ); + static void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete(pMem); } + }; + + inputitem_t *m_InputList; // list of data + int m_bUpdatedThisFrame; + + void AddValue( variant_t newVal, int outputID ); + + DECLARE_SIMPLE_DATADESC(); +}; + +#endif // INPUTVAR_H diff --git a/game/server/entitylist.h b/game/server/entitylist.h new file mode 100644 index 0000000..540e2d5 --- /dev/null +++ b/game/server/entitylist.h @@ -0,0 +1,363 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ENTITYLIST_H +#define ENTITYLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" + +class IEntityListener; + +abstract_class CBaseEntityClassList +{ +public: + CBaseEntityClassList(); + ~CBaseEntityClassList(); + virtual void LevelShutdownPostEntity() = 0; + + CBaseEntityClassList *m_pNextClassList; +}; + +template< class T > +class CEntityClassList : public CBaseEntityClassList +{ +public: + virtual void LevelShutdownPostEntity() { m_pClassList = NULL; } + + void Insert( T *pEntity ) + { + pEntity->m_pNext = m_pClassList; + m_pClassList = pEntity; + } + + void Remove( T *pEntity ) + { + T **pPrev = &m_pClassList; + T *pCur = *pPrev; + while ( pCur ) + { + if ( pCur == pEntity ) + { + *pPrev = pCur->m_pNext; + return; + } + pPrev = &pCur->m_pNext; + pCur = *pPrev; + } + } + + static T *m_pClassList; +}; + +// Derive a class from this if you want to filter entity list searches +abstract_class IEntityFindFilter +{ +public: + virtual bool ShouldFindEntity( CBaseEntity *pEntity ) = 0; + virtual CBaseEntity *GetFilterResult( void ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: a global list of all the entities in the game. All iteration through +// entities is done through this object. +//----------------------------------------------------------------------------- +class CGlobalEntityList : public CBaseEntityList +{ +public: +private: + int m_iHighestEnt; // the topmost used array index + int m_iNumEnts; + int m_iNumEdicts; + + bool m_bClearingEntities; + CUtlVector m_entityListeners; + +public: + IServerNetworkable* GetServerNetworkable( CBaseHandle hEnt ) const; + CBaseNetworkable* GetBaseNetworkable( CBaseHandle hEnt ) const; + CBaseEntity* GetBaseEntity( CBaseHandle hEnt ) const; + edict_t* GetEdict( CBaseHandle hEnt ) const; + + int NumberOfEntities( void ); + int NumberOfEdicts( void ); + + // mark an entity as deleted + void AddToDeleteList( IServerNetworkable *ent ); + // call this before and after each frame to delete all of the marked entities. + void CleanupDeleteList( void ); + int ResetDeleteList( void ); + + // frees all entities in the game + void Clear( void ); + + // Returns true while in the Clear() call. + bool IsClearingEntities() {return m_bClearingEntities;} + + // add a class that gets notified of entity events + void AddListenerEntity( IEntityListener *pListener ); + void RemoveListenerEntity( IEntityListener *pListener ); + + void ReportEntityFlagsChanged( CBaseEntity *pEntity, unsigned int flagsOld, unsigned int flagsNow ); + + // entity is about to be removed, notify the listeners + void NotifyCreateEntity( CBaseEntity *pEnt ); + void NotifySpawn( CBaseEntity *pEnt ); + void NotifyRemoveEntity( CBaseHandle hEnt ); + // iteration functions + + // returns the next entity after pCurrentEnt; if pCurrentEnt is NULL, return the first entity + CBaseEntity *NextEnt( CBaseEntity *pCurrentEnt ); + CBaseEntity *FirstEnt() { return NextEnt(NULL); } + + // returns the next entity of the specified class, using RTTI + template< class T > + T *NextEntByClass( T *start ) + { + for ( CBaseEntity *x = NextEnt( start ); x; x = NextEnt( x ) ) + { + start = dynamic_cast( x ); + if ( start ) + return start; + } + return NULL; + } + + // search functions + bool IsEntityPtr( void *pTest ); + CBaseEntity *FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ); + CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL ); + CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, string_t iszName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL ) + { + return FindEntityByName( pStartEntity, STRING(iszName), pSearchingEntity, pActivator, pCaller, pFilter ); + } + CBaseEntity *FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ); + CBaseEntity *FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName ); + CBaseEntity *FindEntityByModel( CBaseEntity *pStartEntity, const char *szModelName ); + + CBaseEntity *FindEntityByNameNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + CBaseEntity *FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + CBaseEntity *FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius ); + CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecSrc, float flRadius ); + CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecMins, const Vector &vecMaxs ); + + CBaseEntity *FindEntityGeneric( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + CBaseEntity *FindEntityGenericWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + CBaseEntity *FindEntityGenericNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + + CBaseEntity *FindEntityNearestFacing( const Vector &origin, const Vector &facing, float threshold); + CBaseEntity *FindEntityClassNearestFacing( const Vector &origin, const Vector &facing, float threshold, char *classname); + + CBaseEntity *FindEntityProcedural( const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + + CGlobalEntityList(); + +// CBaseEntityList overrides. +protected: + + virtual void OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle ); + virtual void OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle ); + +}; + +extern CGlobalEntityList gEntList; + + +//----------------------------------------------------------------------------- +// Inlines. +//----------------------------------------------------------------------------- +inline edict_t* CGlobalEntityList::GetEdict( CBaseHandle hEnt ) const +{ + IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); + if ( pUnk ) + return pUnk->GetNetworkable()->GetEdict(); + else + return NULL; +} + +inline CBaseNetworkable* CGlobalEntityList::GetBaseNetworkable( CBaseHandle hEnt ) const +{ + IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); + if ( pUnk ) + return pUnk->GetNetworkable()->GetBaseNetworkable(); + else + return NULL; +} + +inline IServerNetworkable* CGlobalEntityList::GetServerNetworkable( CBaseHandle hEnt ) const +{ + IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); + if ( pUnk ) + return pUnk->GetNetworkable(); + else + return NULL; +} + +inline CBaseEntity* CGlobalEntityList::GetBaseEntity( CBaseHandle hEnt ) const +{ + IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); + if ( pUnk ) + return pUnk->GetBaseEntity(); + else + return NULL; +} + + +//----------------------------------------------------------------------------- +// Common finds +#if 0 + +template +inline bool FindEntityByName( const char *pszName, ENT_TYPE **ppResult) +{ + CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName ); + + if ( pBaseEntity ) + *ppResult = dynamic_cast( pBaseEntity ); + else + *ppResult = NULL; + + return ( *ppResult != NULL ); +} + +template <> +inline bool FindEntityByName( const char *pszName, CBaseEntity **ppResult) +{ + *ppResult = gEntList.FindEntityByName( NULL, pszName ); + return ( *ppResult != NULL ); +} + +template <> +inline bool FindEntityByName( const char *pszName, CAI_BaseNPC **ppResult) +{ + CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName ); + + if ( pBaseEntity ) + *ppResult = pBaseEntity->MyNPCPointer(); + else + *ppResult = NULL; + + return ( *ppResult != NULL ); +} +#endif +//----------------------------------------------------------------------------- +// Purpose: Simple object for storing a list of objects +//----------------------------------------------------------------------------- +struct entitem_t +{ + EHANDLE hEnt; + struct entitem_t *pNext; + + // uses pool memory + static void* operator new( size_t stAllocateBlock ); + static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); + static void operator delete( void *pMem ); + static void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete( pMem ); } +}; + +class CEntityList +{ +public: + CEntityList(); + ~CEntityList(); + + int m_iNumItems; + entitem_t *m_pItemList; // null terminated singly-linked list + + void AddEntity( CBaseEntity * ); + void DeleteEntity( CBaseEntity * ); +}; + +enum notify_system_event_t +{ + NOTIFY_EVENT_TELEPORT = 0, + NOTIFY_EVENT_DESTROY, +}; + +struct notify_teleport_params_t +{ + Vector prevOrigin; + QAngle prevAngles; + bool physicsRotate; +}; + +struct notify_destroy_params_t +{ +}; + +struct notify_system_event_params_t +{ + union + { + const notify_teleport_params_t *pTeleport; + const notify_destroy_params_t *pDestroy; + }; + notify_system_event_params_t( const notify_teleport_params_t *pInTeleport ) { pTeleport = pInTeleport; } + notify_system_event_params_t( const notify_destroy_params_t *pInDestroy ) { pDestroy = pInDestroy; } +}; + + +abstract_class INotify +{ +public: + // Add notification for an entity + virtual void AddEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) = 0; + + // Remove notification for an entity + virtual void RemoveEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) = 0; + + // Call the named input in each entity who is watching pEvent's status + virtual void ReportNamedEvent( CBaseEntity *pEntity, const char *pEventName ) = 0; + + // System events don't make sense as inputs, so are handled through a generic notify function + virtual void ReportSystemEvent( CBaseEntity *pEntity, notify_system_event_t eventType, const notify_system_event_params_t ¶ms ) = 0; + + inline void ReportDestroyEvent( CBaseEntity *pEntity ) + { + notify_destroy_params_t destroy; + ReportSystemEvent( pEntity, NOTIFY_EVENT_DESTROY, notify_system_event_params_t(&destroy) ); + } + + inline void ReportTeleportEvent( CBaseEntity *pEntity, const Vector &prevOrigin, const QAngle &prevAngles, bool physicsRotate ) + { + notify_teleport_params_t teleport; + teleport.prevOrigin = prevOrigin; + teleport.prevAngles = prevAngles; + teleport.physicsRotate = physicsRotate; + ReportSystemEvent( pEntity, NOTIFY_EVENT_TELEPORT, notify_system_event_params_t(&teleport) ); + } + + // Remove this entity from the notify list + virtual void ClearEntity( CBaseEntity *pNotify ) = 0; +}; + +// Implement this class and register with gEntList to receive entity create/delete notification +class IEntityListener +{ +public: + virtual void OnEntityCreated( CBaseEntity *pEntity ) {}; + virtual void OnEntitySpawned( CBaseEntity *pEntity ) {}; + virtual void OnEntityDeleted( CBaseEntity *pEntity ) {}; +}; + +// singleton +extern INotify *g_pNotify; + +void EntityTouch_Add( CBaseEntity *pEntity ); +int AimTarget_ListCount(); +int AimTarget_ListCopy( CBaseEntity *pList[], int listMax ); +void AimTarget_ForceRepopulateList(); + +void SimThink_EntityChanged( CBaseEntity *pEntity ); +int SimThink_ListCount(); +int SimThink_ListCopy( CBaseEntity *pList[], int listMax ); + +#endif // ENTITYLIST_H diff --git a/game/server/entityoutput.h b/game/server/entityoutput.h new file mode 100644 index 0000000..6aeb738 --- /dev/null +++ b/game/server/entityoutput.h @@ -0,0 +1,195 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Declares basic entity communications classes, for input/output of data +// between entities +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENTITYOUTPUT_H +#define ENTITYOUTPUT_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" + + +#define EVENT_FIRE_ALWAYS -1 + + +//----------------------------------------------------------------------------- +// Purpose: A COutputEvent consists of an array of these CEventActions. +// Each CEventAction holds the information to fire a single input in +// a target entity, after a specific delay. +//----------------------------------------------------------------------------- +class CEventAction +{ +public: + CEventAction( const char *ActionData = NULL ); + + string_t m_iTarget; // name of the entity(s) to cause the action in + string_t m_iTargetInput; // the name of the action to fire + string_t m_iParameter; // parameter to send, 0 if none + float m_flDelay; // the number of seconds to wait before firing the action + int m_nTimesToFire; // The number of times to fire this event, or EVENT_FIRE_ALWAYS. + + int m_iIDStamp; // unique identifier stamp + + static int s_iNextIDStamp; + + CEventAction *m_pNext; + + // allocates memory from engine.MPool/g_EntityListPool + static void *operator new( size_t stAllocateBlock ); + static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); + static void operator delete( void *pMem ); + static void operator delete( void *pMem , int nBlockUse, const char *pFileName, int nLine ) { operator delete(pMem); } + + DECLARE_SIMPLE_DATADESC(); +}; + + +//----------------------------------------------------------------------------- +// Purpose: Stores a list of connections to other entities, for data/commands to be +// communicated along. +//----------------------------------------------------------------------------- +class CBaseEntityOutput +{ +public: + ~CBaseEntityOutput(); + + void ParseEventAction( const char *EventData ); + void AddEventAction( CEventAction *pEventAction ); + + int Save( ISave &save ); + int Restore( IRestore &restore, int elementCount ); + + int NumberOfElements( void ); + + float GetMaxDelay( void ); + + fieldtype_t ValueFieldType() { return m_Value.FieldType(); } + + void FireOutput( variant_t Value, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay = 0 ); + + /// Delete every single action in the action list. + void DeleteAllElements( void ) ; + +protected: + variant_t m_Value; + CEventAction *m_ActionList; + DECLARE_SIMPLE_DATADESC(); + + CBaseEntityOutput() {} // this class cannot be created, only it's children + +private: + CBaseEntityOutput( CBaseEntityOutput& ); // protect from accidental copying +}; + + +//----------------------------------------------------------------------------- +// Purpose: wraps variant_t data handling in convenient, compiler type-checked template +//----------------------------------------------------------------------------- +template< class Type, fieldtype_t fieldType > +class CEntityOutputTemplate : public CBaseEntityOutput +{ +public: + // + // Sets an initial value without firing the output. + // + void Init( Type value ) + { + m_Value.Set( fieldType, &value ); + } + + // + // Sets a value and fires the output. + // + void Set( Type value, CBaseEntity *pActivator, CBaseEntity *pCaller ) + { + m_Value.Set( fieldType, &value ); + FireOutput( m_Value, pActivator, pCaller ); + } + + // + // Returns the current value. + // + Type Get( void ) + { + return *((Type*)&m_Value); + } +}; + + +// +// Template specializations for type Vector, so we can implement Get, Set, and Init differently. +// +template<> +class CEntityOutputTemplate : public CBaseEntityOutput +{ +public: + void Init( const Vector &value ) + { + m_Value.SetVector3D( value ); + } + + void Set( const Vector &value, CBaseEntity *pActivator, CBaseEntity *pCaller ) + { + m_Value.SetVector3D( value ); + FireOutput( m_Value, pActivator, pCaller ); + } + + void Get( Vector &vec ) + { + m_Value.Vector3D(vec); + } +}; + + +template<> +class CEntityOutputTemplate : public CBaseEntityOutput +{ +public: + void Init( const Vector &value ) + { + m_Value.SetPositionVector3D( value ); + } + + void Set( const Vector &value, CBaseEntity *pActivator, CBaseEntity *pCaller ) + { + m_Value.SetPositionVector3D( value ); + FireOutput( m_Value, pActivator, pCaller ); + } + + void Get( Vector &vec ) + { + m_Value.Vector3D(vec); + } +}; + + +//----------------------------------------------------------------------------- +// Purpose: parameterless entity event +//----------------------------------------------------------------------------- +class COutputEvent : public CBaseEntityOutput +{ +public: + // void Firing, no parameter + void FireOutput( CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay = 0 ); +}; + + +// useful typedefs for allowed output data types +typedef CEntityOutputTemplate COutputVariant; +typedef CEntityOutputTemplate COutputInt; +typedef CEntityOutputTemplate COutputFloat; +typedef CEntityOutputTemplate COutputString; +typedef CEntityOutputTemplate COutputEHANDLE; +typedef CEntityOutputTemplate COutputVector; +typedef CEntityOutputTemplate COutputPositionVector; +typedef CEntityOutputTemplate COutputColor32; + +#endif // ENTITYOUTPUT_H diff --git a/game/server/env_debughistory.h b/game/server/env_debughistory.h new file mode 100644 index 0000000..7bce102 --- /dev/null +++ b/game/server/env_debughistory.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ENV_DEBUGHISTORY_H +#define ENV_DEBUGHISTORY_H +#ifdef _WIN32 +#pragma once +#endif + +enum debughistorycategories_t +{ + HISTORY_ENTITY_IO, + HISTORY_AI_DECISIONS, + HISTORY_SCENE_PRINT, + HISTORY_ALYX_BLIND, // TEMP: until we find and fix this bug + HISTORY_PLAYER_DAMAGE, // record all damage done to the player + + // Add new categories here + + MAX_HISTORY_CATEGORIES, +}; + +#define DISABLE_DEBUG_HISTORY + +#if defined(DISABLE_DEBUG_HISTORY) +#define ADD_DEBUG_HISTORY( category, line ) ((void)0) +#else +#define ADD_DEBUG_HISTORY( category, line ) AddDebugHistoryLine( category, line ) +void AddDebugHistoryLine( int iCategory, const char *pszLine ); +#endif + +#endif // ENV_DEBUGHISTORY_H diff --git a/game/server/env_player_surface_trigger.h b/game/server/env_player_surface_trigger.h new file mode 100644 index 0000000..96eb081 --- /dev/null +++ b/game/server/env_player_surface_trigger.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENV_PLAYER_SURFACE_TRIGGER_H +#define ENV_PLAYER_SURFACE_TRIGGER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "entityoutput.h" + +//----------------------------------------------------------------------------- +// Purpose: Entity that fires outputs whenever the player stands on a different surface +//----------------------------------------------------------------------------- +class CEnvPlayerSurfaceTrigger : public CPointEntity +{ + DECLARE_CLASS( CEnvPlayerSurfaceTrigger, CPointEntity ); +public: + DECLARE_DATADESC(); + + ~CEnvPlayerSurfaceTrigger( void ); + void Spawn( void ); + void OnRestore( void ); + + // Main interface to all surface triggers + static void SetPlayerSurface( CBasePlayer *pPlayer, char gameMaterial ); + + void UpdateMaterialThink( void ); + +private: + void PlayerSurfaceChanged( CBasePlayer *pPlayer, char gameMaterial ); + void InputDisable( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + +private: + int m_iTargetGameMaterial; + int m_iCurrentGameMaterial; + bool m_bDisabled; + + // Outputs + COutputEvent m_OnSurfaceChangedToTarget; + COutputEvent m_OnSurfaceChangedFromTarget; +}; + +#endif // ENV_PLAYER_SURFACE_TRIGGER_H diff --git a/game/server/env_zoom.h b/game/server/env_zoom.h new file mode 100644 index 0000000..1af1ef5 --- /dev/null +++ b/game/server/env_zoom.h @@ -0,0 +1,13 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENV_ZOOM_H +#define ENV_ZOOM_H + +bool CanOverrideEnvZoomOwner( CBaseEntity *pZoomOwner ); +float GetZoomOwnerDesiredFOV( CBaseEntity *pZoomOwner ); + +#endif //ENV_ZOOM_H \ No newline at end of file diff --git a/game/server/envmicrophone.h b/game/server/envmicrophone.h new file mode 100644 index 0000000..1cad076 --- /dev/null +++ b/game/server/envmicrophone.h @@ -0,0 +1,90 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENVMICROPHONE_H +#define ENVMICROPHONE_H +#ifdef _WIN32 +#pragma once +#endif + +class CBaseFilter; + + +const int SF_MICROPHONE_SOUND_COMBAT = 0x01; +const int SF_MICROPHONE_SOUND_WORLD = 0x02; +const int SF_MICROPHONE_SOUND_PLAYER = 0x04; +const int SF_MICROPHONE_SOUND_BULLET_IMPACT = 0x08; +const int SF_MICROPHONE_SWALLOW_ROUTED_SOUNDS = 0x10; +const int SF_MICROPHONE_SOUND_EXPLOSION = 0x20; +const int SF_MICROPHONE_IGNORE_NONATTENUATED = 0x40; + + +// Return codes from SoundPlayed +enum MicrophoneResult_t +{ + MicrophoneResult_Ok = 0, + MicrophoneResult_Swallow, // The microphone swallowed the sound. Don't play it. + MicrophoneResult_Remove, // The microphone should be removed from the list of microphones. +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CEnvMicrophone : public CPointEntity +{ + DECLARE_CLASS( CEnvMicrophone, CPointEntity ); + +public: + ~CEnvMicrophone(); + + void Spawn(void); + void Activate(void); + void OnRestore( void ); + void ActivateSpeaker( void ); + void Think(void); + bool CanHearSound(CSound *pSound, float &flVolume); + bool CanHearSound( int entindex, soundlevel_t soundlevel, float &flVolume, const Vector *pOrigin ); + + void SetSensitivity( float flSensitivity ); + void SetSpeakerName( string_t iszSpeakerName ); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputSetSpeakerName( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + + // Hook for the sound system to tell us when a sound's been played. Returns true if it's to swallow the passed in sound. + static bool OnSoundPlayed( int entindex, const char *soundname, soundlevel_t soundlevel, + float flVolume, int iFlags, int iPitch, const Vector *pOrigin, float soundtime, CUtlVector< Vector >& soundorigins ); + +private: + + // Per-microphone notification that a sound has played. + MicrophoneResult_t SoundPlayed( int entindex, const char *soundname, soundlevel_t soundlevel, + float flVolume, int iFlags, int iPitch, const Vector *pOrigin, float soundtime, CUtlVector< Vector >& soundorigins ); + + bool m_bDisabled; // If true, the microphone will not measure sound. + EHANDLE m_hMeasureTarget; // Point at which to measure sound level. + int m_nSoundMask; // Which sound types we are interested in. + float m_flSensitivity; // 0 = deaf, 1 = default, 10 = maximum sensitivity + float m_flSmoothFactor; // 0 = no smoothing of samples, 0.9 = maximum smoothing + float m_flMaxRange; // Maximum sound hearing range, irrelevant of attenuation + string_t m_iszSpeakerName; // Name of a speaker to output any heard sounds through + EHANDLE m_hSpeaker; // Speaker to output any heard sounds through + bool m_bAvoidFeedback; + int m_iSpeakerDSPPreset; // Speaker DSP preset to use when this microphone is enabled + string_t m_iszListenFilter; + CHandle m_hListenFilter; + + COutputFloat m_SoundLevel; // Fired when the sampled volume level changes. + COutputEvent m_OnRoutedSound; // Fired when a sound has been played through our speaker + COutputEvent m_OnHeardSound; // Heard sound. + + char m_szLastSound[256]; +}; + +#endif // ENVMICROPHONE_H diff --git a/game/server/envspark.h b/game/server/envspark.h new file mode 100644 index 0000000..b9d62df --- /dev/null +++ b/game/server/envspark.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A point entity that periodically emits sparks and "bzzt" sounds. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENVSPARK_H +#define ENVSPARK_H +#ifdef _WIN32 +#pragma once +#endif + +class CEnvSpark : public CPointEntity +{ + DECLARE_CLASS( CEnvSpark, CPointEntity ); + +public: + CEnvSpark( void ); + + void Spawn( void ); + void Precache( void ); + void SparkThink( void ); + + void StartSpark( void ); + void StopSpark( void ); + + // Input handlers + void InputStartSpark( inputdata_t &inputdata ); + void InputStopSpark( inputdata_t &inputdata ); + void InputToggleSpark( inputdata_t &inputdata ); + void InputSparkOnce( inputdata_t &inputdata ); + + bool IsSparking( void ){ return ( GetNextThink() != TICK_NEVER_THINK ); } + + DECLARE_DATADESC(); + + float m_flDelay; + int m_nGlowSpriteIndex; + int m_nMagnitude; + int m_nTrailLength; + + COutputEvent m_OnSpark; +}; + +#endif // ENVSPARK_H \ No newline at end of file diff --git a/game/server/episodic/ai_behavior_alyx_injured.h b/game/server/episodic/ai_behavior_alyx_injured.h new file mode 100644 index 0000000..2eb1ff1 --- /dev/null +++ b/game/server/episodic/ai_behavior_alyx_injured.h @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: FIXME: This will ultimately become a more generic implementation +// +//============================================================================= + +#ifndef AI_BEHAVIOR_ALYX_INJURED_H +#define AI_BEHAVIOR_ALYX_INJURED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmap.h" + +extern bool IsAlyxInInjuredMode( void ); + +// +// +// + +class CAI_InjuredFollowGoal : public CAI_FollowGoal +{ + DECLARE_CLASS( CAI_InjuredFollowGoal, CAI_FollowGoal ); + +public: + + virtual void EnableGoal( CAI_BaseNPC *pAI ); + virtual void DisableGoal( CAI_BaseNPC *pAI ); + + DECLARE_DATADESC(); +}; + +// +// +// + +class CAI_BehaviorAlyxInjured : public CAI_FollowBehavior +{ + DECLARE_CLASS( CAI_BehaviorAlyxInjured, CAI_FollowBehavior ); + DECLARE_DATADESC(); + +public: + CAI_BehaviorAlyxInjured( void ); + + virtual const char *GetName( void ) { return "AlyxInjuredFollow"; } + virtual Activity NPC_TranslateActivity( Activity nActivity ); + virtual int TranslateSchedule( int scheduleType ); + virtual void Spawn( void ); + virtual void OnRestore( void ); + virtual void StartTask( const Task_t *pTask ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual void GatherConditions( void ); + virtual Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture ); + + enum + { + // Schedules + SCHED_INJURED_COWER = BaseClass::NEXT_SCHEDULE, + SCHED_INJURED_FEAR_FACE, + SCHED_INJURED_RUN_FROM_ENEMY, + NEXT_SCHEDULE, + + // Tasks + TASK_FIND_INJURED_COVER_FROM_ENEMY = BaseClass::NEXT_TASK, + NEXT_TASK, + + // Conditions + COND_INJURED_TOO_FAR_FROM_PLAYER = BaseClass::NEXT_CONDITION, + COND_INJURED_OVERWHELMED, + NEXT_CONDITION + }; + + bool IsReadinessCapable( void ) { return ( IsInjured() == false ); } // Never use the readiness system when injured + bool IsInjured( void ) const; + +private: + + void SpeakIfAllowed( AIConcept_t concept ); + bool ShouldRunToCover( void ); + bool ShouldRunToFollowGoal( void ); + bool FindThreatDirection2D( const Vector &vecSource, Vector *vecOut ); + bool FindCoverFromEnemyBehindTarget( CBaseEntity *pTarget, float flRadius, Vector *vecOut ); + void PopulateActivityMap( void ); + int NumKnownEnemiesInRadius( const Vector &vecSource, float flRadius ); + + CUtlMap m_ActivityMap; + + float m_flNextWarnTime; + +protected: + DEFINE_CUSTOM_SCHEDULE_PROVIDER; +}; + + +#endif // AI_BEHAVIOR_ALYX_INJURED_H diff --git a/game/server/episodic/ai_behavior_passenger_companion.h b/game/server/episodic/ai_behavior_passenger_companion.h new file mode 100644 index 0000000..857254e --- /dev/null +++ b/game/server/episodic/ai_behavior_passenger_companion.h @@ -0,0 +1,168 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef AI_BEHAVIOR_PASSENGER_COMPANION_H +#define AI_BEHAVIOR_PASSENGER_COMPANION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior_passenger.h" + +class CNPC_PlayerCompanion; + +struct VehicleAvoidParams_t +{ + Vector vecStartPos; + Vector vecGoalPos; + Vector *pNodePositions; + int nNumNodes; + int nDirection; + int nStartNode; + int nEndNode; +}; + +struct FailPosition_t +{ + Vector vecPosition; + float flTime; + + DECLARE_SIMPLE_DATADESC(); +}; + +class CAI_PassengerBehaviorCompanion : public CAI_PassengerBehavior +{ + DECLARE_CLASS( CAI_PassengerBehaviorCompanion, CAI_PassengerBehavior ); + DECLARE_DATADESC() + +public: + + CAI_PassengerBehaviorCompanion( void ); + + enum + { + // Schedules + SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE = BaseClass::NEXT_SCHEDULE, + SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED, + SCHED_PASSENGER_ENTER_VEHICLE_PAUSE, + SCHED_PASSENGER_RANGE_ATTACK1, + SCHED_PASSENGER_RELOAD, + SCHED_PASSENGER_EXIT_STUCK_VEHICLE, + SCHED_PASSENGER_OVERTURNED, + SCHED_PASSENGER_IMPACT, + SCHED_PASSENGER_ENTER_VEHICLE_IMMEDIATELY, + SCHED_PASSENGER_COWER, + SCHED_PASSENGER_FIDGET, + NEXT_SCHEDULE, + + // Tasks + TASK_GET_PATH_TO_VEHICLE_ENTRY_POINT = BaseClass::NEXT_TASK, + TASK_GET_PATH_TO_NEAR_VEHICLE, + TASK_PASSENGER_RELOAD, + TASK_PASSENGER_EXIT_STUCK_VEHICLE, + TASK_PASSENGER_OVERTURNED, + TASK_PASSENGER_IMPACT, + TASK_RUN_TO_VEHICLE_ENTRANCE, + NEXT_TASK, + + // Conditions + + COND_PASSENGER_CAN_LEAVE_STUCK_VEHICLE = BaseClass::NEXT_CONDITION, + COND_PASSENGER_WARN_OVERTURNED, + COND_PASSENGER_WARN_COLLISION, + COND_PASSENGER_VEHICLE_MOVED_FROM_MARK, + COND_PASSENGER_CAN_FIDGET, + COND_PASSENGER_CAN_ENTER_IMMEDIATELY, + NEXT_CONDITION, + }; + + virtual bool CanSelectSchedule( void ); + virtual void Enable( CPropJeepEpisodic *pVehicle, bool bImmediateEnter = false); + virtual void GatherConditions( void ); + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + virtual void AimGun( void ); + virtual void EnterVehicle( void ); + virtual void ExitVehicle( void ); + virtual void FinishEnterVehicle( void ); + virtual void FinishExitVehicle( void ); + virtual void BuildScheduleTestBits( void ); + virtual Activity NPC_TranslateActivity( Activity activity ); + virtual bool CanExitVehicle( void ); + virtual bool IsValidEnemy( CBaseEntity *pEntity ); + virtual void OnUpdateShotRegulator( void ); + virtual bool IsNavigationUrgent( void ); + virtual bool IsCurTaskContinuousMove( void ); + virtual bool IsCrouching( void ); + +private: + + void SpeakVehicleConditions( void ); + virtual void OnExitVehicleFailed( void ); + + bool CanFidget( void ); + bool UseRadialRouteToEntryPoint( const Vector &vecEntryPoint ); + float GetArcToEntryPoint( const Vector &vecCenterPoint, const Vector &vecEntryPoint, bool &bClockwise ); + int SelectScheduleInsideVehicle( void ); + int SelectScheduleOutsideVehicle( void ); + bool FindPathToVehicleEntryPoint( void ); + bool CanEnterVehicleImmediately( int *pResultSequence, Vector *pResultPos, QAngle *pResultAngles ); + void EnterVehicleImmediately( void ); + + // ------------------------------------------ + // Passenger sensing + // ------------------------------------------ + + virtual void GatherVehicleStateConditions( void ); + + float GetVehicleSpeed( void ); + void GatherVehicleCollisionConditions( const Vector &localVelocity ); + + // ------------------------------------------ + // Overturned tracking + // ------------------------------------------ + void UpdateStuckStatus( void ); + bool CanExitAtPosition( const Vector &vecTestPos ); + bool GetStuckExitPos( Vector *vecResult ); + bool ExitStuckVehicle( void ); + + bool UpdateVehicleEntrancePath( void ); + bool PointIsWithinEntryFailureRadius( const Vector &vecPosition ); + void ResetVehicleEntryFailedState( void ); + void MarkVehicleEntryFailed( const Vector &vecPosition ); + virtual int FindEntrySequence( bool bNearest = false ); + void CalculateBodyLean( void ); + + float m_flNextJostleTime; + float m_flNextOverturnWarning; // The next time the NPC may complained about being upside-down + float m_flOverturnedDuration; // Amount of time we've been stuck in the vehicle (unable to exit) + float m_flUnseenDuration; // Amount of time we've been hidden from the player's view + + float m_flEnterBeginTime; // Time the NPC started to try and enter the vehicle + int m_nExitAttempts; // Number of times we've attempted to exit the vehicle but failed + int m_nVisibleEnemies; // Keeps a record of how many enemies I know about + float m_flLastLateralLean; // Our last lean value + + CAI_MoveMonitor m_VehicleMonitor; // Used to keep track of the vehicle's movement relative to a mark + CUtlVector m_FailedEntryPositions; // Used to keep track of the vehicle's movement relative to a mark + +protected: + virtual int SelectTransitionSchedule( void ); + + void ExtendFidgetDelay( float flDuration ); + bool CanPlayJostle( bool bLargeJostle ); + + float m_flEntraceUpdateTime; + float m_flNextEnterAttempt; + float m_flNextFidgetTime; + CHandle< CNPC_PlayerCompanion > m_hCompanion; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; +}; + +#endif // AI_BEHAVIOR_PASSENGER_COMPANION_H diff --git a/game/server/episodic/ai_behavior_passenger_zombie.h b/game/server/episodic/ai_behavior_passenger_zombie.h new file mode 100644 index 0000000..98b2ea0 --- /dev/null +++ b/game/server/episodic/ai_behavior_passenger_zombie.h @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Zombies on cars! +// +//============================================================================= + +#ifndef AI_BEHAVIOR_PASSENGER_ZOMBIE_H +#define AI_BEHAVIOR_PASSENGER_ZOMBIE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior_passenger.h" +#include "ai_utils.h" +#include "vehicle_base.h" + +extern impactdamagetable_t gZombiePassengerImpactDamageTable; + +class CAI_PassengerBehaviorZombie : public CAI_PassengerBehavior +{ + DECLARE_CLASS( CAI_PassengerBehaviorZombie, CAI_PassengerBehavior ); + DECLARE_DATADESC() + +public: + + CAI_PassengerBehaviorZombie( void ); + + enum + { + // Schedules + SCHED_PASSENGER_ZOMBIE_ENTER_VEHICLE = BaseClass::NEXT_SCHEDULE, + SCHED_PASSENGER_ZOMBIE_EXIT_VEHICLE, + SCHED_PASSENGER_ZOMBIE_MELEE_ATTACK1, + SCHED_PASSENGER_ZOMBIE_RANGE_ATTACK1, + SCHED_PASSENGER_ZOMBIE_ATTACH, + SCHED_PASSENGER_ZOMBIE_RUN_TO_VEHICLE, + NEXT_SCHEDULE, + + // Tasks + TASK_PASSENGER_ZOMBIE_RANGE_ATTACK1 = BaseClass::NEXT_TASK, + TASK_PASSENGER_ZOMBIE_DISMOUNT, + TASK_PASSENGER_ZOMBIE_ATTACH, + NEXT_TASK, + + // Conditions + COND_PASSENGER_ZOMBIE_CAN_ATTACH_TO_VEHICLE = BaseClass::NEXT_CONDITION, + NEXT_CONDITION + }; + + virtual const char *GetName( void ) { return "ZombiePassenger"; } + virtual string_t GetRoleName( void ) { return MAKE_STRING( "passenger_zombie" ); } + virtual int SelectSchedule( void ); + virtual int TranslateSchedule( int scheduleType ); + virtual void GatherConditions( void ); + virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual void BuildScheduleTestBits( void ); + virtual void RunTask( const Task_t *pTask ); + virtual void StartTask( const Task_t *pTask ); + virtual bool CanEnterVehicle( void ); + virtual void ExitVehicle( void ); + virtual void HandleAnimEvent( animevent_t *pEvent ); + virtual Activity NPC_TranslateActivity( Activity activity ); + + virtual bool AttachToVehicle( void ); + + void SuppressAttack( float flDuration ); + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +protected: + + int SelectOutsideSchedule( void ); + int SelectInsideSchedule( void ); + virtual int FindExitSequence( void ); + void StartDismount( void ); + void FinishDismount( void ); + virtual void CalculateBodyLean( void ); + virtual void GatherVehicleStateConditions( void ); + virtual int FindEntrySequence( bool bNearest = false ); + +private: + + void VehicleLeapAttackTouch( CBaseEntity *pOther ); + void VehicleLeapAttack( void ); + bool CanBeOnEnemyVehicle( void ); + float GetEntryPointCost( const Vector &vecEntryPos ); + bool EnemyInVehicle( void ); + void GetAttachmentPoint( Vector *vecPoint ); + bool CanJumpToAttachToVehicle( void ); + //bool WithinAttachRange( void ); + + float m_flLastLateralLean; + float m_flLastVerticalLean; + float m_flNextLeapTime; +}; + +#endif // AI_BEHAVIOR_PASSENGER_ZOMBIE_H diff --git a/game/server/episodic/ep1_gamestats.h b/game/server/episodic/ep1_gamestats.h new file mode 100644 index 0000000..5cd1356 --- /dev/null +++ b/game/server/episodic/ep1_gamestats.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef EP1_GAMESTATS_H +#define EP1_GAMESTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "gamestats.h" + +class CEP1GameStats : public CBaseGameStats +{ + typedef CBaseGameStats BaseClass; + +public: + CEP1GameStats( void ); + + virtual CBaseGameStats *OnInit( CBaseGameStats *pCurrentGameStats, char const *gamedir ); + + virtual bool StatTrackingEnabledForMod( void ) { return true; } + virtual bool UserPlayedAllTheMaps( void ); + + virtual const char *GetStatSaveFileName( void ); + virtual const char *GetStatUploadRegistryKeyName( void ); +}; + +#endif // EP1_GAMESTATS_H diff --git a/game/server/episodic/ep2_gamestats.h b/game/server/episodic/ep2_gamestats.h new file mode 100644 index 0000000..cef1f83 --- /dev/null +++ b/game/server/episodic/ep2_gamestats.h @@ -0,0 +1,532 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef EP2_GAMESTATS_H +#define EP2_GAMESTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ep1_gamestats.h" +#include "tier1/utlstring.h" + +// EP2 Game Stats +enum Ep2GameStatsVersions_t +{ + EP2_GAMESTATS_FILE_VERSION_01 = 001, + EP2_GAMESTATS_FILE_VERSION_02 = 002, + + EP2_GAMESTATS_CURRENT_VERSION = EP2_GAMESTATS_FILE_VERSION_02, +}; + +enum Ep2GameStatsLumpIds_t +{ + EP2STATS_LUMP_HEADER = 1, + EP2STATS_LUMP_DEATH, + EP2STATS_LUMP_NPC, + EP2STATS_LUMP_WEAPON, + EP2STATS_LUMP_SAVEGAMEINFO, + EP2STATS_LUMP_TAG, + EP2STATS_LUMP_GENERIC, + EP2_MAX_LUMP_COUNT +}; + +// EP2 Game Level Stats Data +struct Ep2LevelStats_t +{ +public: + enum FloatCounterTypes_t + { + COUNTER_DAMAGETAKEN = 0, + + NUM_FLOATCOUNTER_TYPES, + }; + + enum IntCounterTypes_t + { + COUNTER_CRATESSMASHED = 0, + COUNTER_OBJECTSPUNTED, + COUNTER_VEHICULARHOMICIDES, + COUNTER_DISTANCE_INVEHICLE, + COUNTER_DISTANCE_ONFOOT, + COUNTER_DISTANCE_ONFOOTSPRINTING, + COUNTER_FALLINGDEATHS, + COUNTER_VEHICLE_OVERTURNED, + COUNTER_LOADGAME_STILLALIVE, + COUNTER_LOADS, + COUNTER_SAVES, + COUNTER_GODMODES, + COUNTER_NOCLIPS, + + NUM_INTCOUNTER_TYPES, + }; + + Ep2LevelStats_t() : + m_bInitialized( false ), + m_flLevelStartTime( 0.0f ) + { + Q_memset( m_IntCounters, 0, sizeof( m_IntCounters ) ); + Q_memset( m_FloatCounters, 0, sizeof( m_FloatCounters ) ); + } + ~Ep2LevelStats_t() + { + } + + Ep2LevelStats_t( const Ep2LevelStats_t &other ) + { + m_bInitialized = other.m_bInitialized; + m_flLevelStartTime = other.m_flLevelStartTime; + m_Header = other.m_Header; + m_aPlayerDeaths = other.m_aPlayerDeaths; + Q_memcpy( m_IntCounters, other.m_IntCounters, sizeof( m_IntCounters ) ); + Q_memcpy( m_FloatCounters, other.m_FloatCounters, sizeof( m_FloatCounters ) ); + int i; + for ( i = other.m_dictEntityDeaths.First(); i != other.m_dictEntityDeaths.InvalidIndex(); i = other.m_dictEntityDeaths.Next( i ) ) + { + m_dictEntityDeaths.Insert( other.m_dictEntityDeaths.GetElementName( i ), other.m_dictEntityDeaths[ i ] ); + } + for ( i = other.m_dictWeapons.First(); i != other.m_dictWeapons.InvalidIndex(); i = other.m_dictWeapons.Next( i ) ) + { + m_dictWeapons.Insert( other.m_dictWeapons.GetElementName( i ), other.m_dictWeapons[ i ] ); + } + m_SaveGameInfo = other.m_SaveGameInfo; + } + + // Create and destroy. + void Init( const char *pszMapName, float flStartTime, char const *pchTag, int nMapVersion ) + { + // Initialize. + m_Header.m_iVersion = EP2_GAMESTATS_CURRENT_VERSION; + Q_strncpy( m_Header.m_szMapName, pszMapName, sizeof( m_Header.m_szMapName ) ); + m_Header.m_flTime = 0.0f; + + // Start the level timer. + m_flLevelStartTime = flStartTime; + + Q_strncpy( m_Tag.m_szTagText, pchTag, sizeof( m_Tag.m_szTagText ) ); + m_Tag.m_nMapVersion = nMapVersion; + } + + void Shutdown( float flEndTime ) + { + m_Header.m_flTime = flEndTime - m_flLevelStartTime; + } + + void AppendToBuffer( CUtlBuffer &SaveBuffer ) + { + // Always write out as current version + m_Header.m_iVersion = EP2_GAMESTATS_CURRENT_VERSION; + + // Write out the lumps. + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_HEADER, 1, sizeof( Ep2LevelStats_t::LevelHeader_t ), static_cast( &m_Header ) ); + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_TAG, 1, sizeof( Ep2LevelStats_t::Tag_t ), static_cast< void * >( &m_Tag ) ); + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_DEATH, m_aPlayerDeaths.Count(), sizeof( Ep2LevelStats_t::PlayerDeathsLump_t ), static_cast( m_aPlayerDeaths.Base() ) ); + { + CUtlBuffer buf; + buf.Put( (const void *)m_IntCounters, sizeof( m_IntCounters ) ); + buf.Put( (const void *)m_FloatCounters, sizeof( m_FloatCounters ) ); + buf.PutInt( m_dictEntityDeaths.Count() ); + for ( int i = m_dictEntityDeaths.First(); i != m_dictEntityDeaths.InvalidIndex(); i = m_dictEntityDeaths.Next( i ) ) + { + buf.PutString( m_dictEntityDeaths.GetElementName( i ) ); + buf.Put( (const void *)&m_dictEntityDeaths[ i ], sizeof( Ep2LevelStats_t::EntityDeathsLump_t ) ); + } + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_NPC, 1, buf.TellPut(), buf.Base() ); + } + { + CUtlBuffer buf; + buf.PutInt( m_dictWeapons.Count() ); + for ( int i = m_dictWeapons.First(); i != m_dictWeapons.InvalidIndex(); i = m_dictWeapons.Next( i ) ) + { + buf.PutString( m_dictWeapons.GetElementName( i ) ); + buf.Put( (const void *)&m_dictWeapons[ i ], sizeof( Ep2LevelStats_t::WeaponLump_t ) ); + } + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_WEAPON, 1, buf.TellPut(), buf.Base() ); + } + { + CUtlBuffer buf; + buf.PutString( m_SaveGameInfo.m_sCurrentSaveFile.String() ); + buf.PutInt( m_SaveGameInfo.m_nCurrentSaveFileTime ); + buf.PutInt( m_SaveGameInfo.m_Records.Count() ); + for ( int i = 0 ; i < m_SaveGameInfo.m_Records.Count(); ++i ) + { + buf.Put( (const void *)&m_SaveGameInfo.m_Records[ i ], sizeof( Ep2LevelStats_t::SaveGameInfoRecord2_t ) ); + } + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_SAVEGAMEINFO, 1, buf.TellPut(), buf.Base() ); + } + { + CUtlBuffer buf; + buf.PutShort( Ep2LevelStats_t::GenericStatsLump_t::LumpVersion ); + buf.PutInt( m_dictGeneric.Count() ); + for ( int i = m_dictGeneric.First(); i != m_dictGeneric.InvalidIndex(); i = m_dictGeneric.Next( i ) ) + { + buf.PutString( m_dictGeneric.GetElementName( i ) ); + buf.Put( (const void *)&m_dictGeneric[ i ], sizeof( Ep2LevelStats_t::GenericStatsLump_t ) ); + } + CBaseGameStats::AppendLump( EP2_MAX_LUMP_COUNT, SaveBuffer, EP2STATS_LUMP_GENERIC, 1, buf.TellPut(), buf.Base() ); + } + } + + static void LoadData( CUtlDict& items, CUtlBuffer &LoadBuffer ) + { + // Read the next lump. + unsigned short iLump = 0; + unsigned short iLumpCount = 0; + + Ep2LevelStats_t *pItem = NULL; + + while( CBaseGameStats::GetLumpHeader( EP2_MAX_LUMP_COUNT, LoadBuffer, iLump, iLumpCount, true ) ) + { + switch ( iLump ) + { + case EP2STATS_LUMP_HEADER: + { + Ep2LevelStats_t::LevelHeader_t header; + CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( Ep2LevelStats_t::LevelHeader_t ), &header ); + pItem = &items[ items.Insert( header.m_szMapName ) ]; + pItem->m_Header = header; + pItem->m_Tag.Clear(); + Assert( pItem ); + } + break; + case EP2STATS_LUMP_TAG: + { + Assert( pItem ); + CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( Ep2LevelStats_t::Tag_t ), &pItem->m_Tag ); + } + break; + case EP2STATS_LUMP_DEATH: + { + Assert( pItem ); + pItem->m_aPlayerDeaths.SetCount( iLumpCount ); + CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( Ep2LevelStats_t::PlayerDeathsLump_t ), static_cast( pItem->m_aPlayerDeaths.Base() ) ); + } + break; + case EP2STATS_LUMP_NPC: + { + Assert( pItem ); + LoadBuffer.Get( ( void * )pItem->m_IntCounters, sizeof( pItem->m_IntCounters ) ); + LoadBuffer.Get( ( void * )pItem->m_FloatCounters, sizeof( pItem->m_FloatCounters ) ); + int c = LoadBuffer.GetInt(); + for ( int i = 0 ; i < c; ++i ) + { + Ep2LevelStats_t::EntityDeathsLump_t data; + char npcName[ 512 ]; + LoadBuffer.GetString( npcName ); + LoadBuffer.Get( &data, sizeof( data ) ); + pItem->m_dictEntityDeaths.Insert( npcName, data ); + } + } + break; + case EP2STATS_LUMP_WEAPON: + { + Assert( pItem ); + int c = LoadBuffer.GetInt(); + for ( int i = 0 ; i < c; ++i ) + { + Ep2LevelStats_t::WeaponLump_t data; + char weaponName[ 512 ]; + LoadBuffer.GetString( weaponName ); + LoadBuffer.Get( &data, sizeof( data ) ); + pItem->m_dictWeapons.Insert( weaponName, data ); + } + } + break; + case EP2STATS_LUMP_SAVEGAMEINFO: + { + Assert( pItem ); + Ep2LevelStats_t::SaveGameInfo_t *info = &pItem->m_SaveGameInfo; + char sz[ 512 ]; + LoadBuffer.GetString( sz ); + info->m_sCurrentSaveFile = sz; + info->m_nCurrentSaveFileTime = LoadBuffer.GetInt(); + int c = LoadBuffer.GetInt(); + for ( int i = 0 ; i < c; ++i ) + { + Ep2LevelStats_t::SaveGameInfoRecord2_t rec; + if ( pItem->m_Header.m_iVersion >= EP2_GAMESTATS_FILE_VERSION_02 ) + { + LoadBuffer.Get( &rec, sizeof( rec ) ); + } + else + { + size_t s = sizeof( Ep2LevelStats_t::SaveGameInfoRecord_t ); + LoadBuffer.Get( &rec, s ); + } + info->m_Records.AddToTail( rec ); + } + info->m_pCurrentRecord = NULL; + if ( info->m_Records.Count() > 0 ) + { + info->m_pCurrentRecord = &info->m_Records[ info->m_Records.Count() - 1 ]; + } + } + break; + case EP2STATS_LUMP_GENERIC: + { + Assert( pItem ); + int version = LoadBuffer.GetShort(); + if ( version == Ep2LevelStats_t::GenericStatsLump_t::LumpVersion ) + { + int c = LoadBuffer.GetInt(); + Assert( c < 2 * 1024 * 1024 ); + for ( int i = 0 ; i < c; ++i ) + { + Ep2LevelStats_t::GenericStatsLump_t data; + char pchStatName[ 512 ]; + LoadBuffer.GetString( pchStatName ); + LoadBuffer.Get( &data, sizeof( data ) ); + pItem->m_dictGeneric.Insert( pchStatName, data ); + } + } + else + { + Error( "Unsupported GenericStatsLump_t::LumpVersion" ); + } + } + break; + } + } + } + +public: + // Level header data. + struct LevelHeader_t + { + static const unsigned short LumpId = EP2STATS_LUMP_HEADER; // Lump ids. + byte m_iVersion; // Version of the game stats file. + char m_szMapName[64]; // Name of the map. + float m_flTime; // Time spent in level. + }; + + // Simple "tag" applied to all data in database (e.g., "PLAYTEST") + struct Tag_t + { + static const unsigned short LumpId = EP2STATS_LUMP_TAG; + + void Clear() + { + Q_memset( m_szTagText, 0, sizeof( m_szTagText ) ); + m_nMapVersion = 0; + } + + char m_szTagText[ 8 ]; + int m_nMapVersion; + }; + + // Player deaths. + struct PlayerDeathsLump_t + { + static const unsigned short LumpId = EP2STATS_LUMP_DEATH; // Lump ids. + short nPosition[3]; // Position of death. +// short iWeapon; // Weapon that killed the player. +// byte iAttackClass; // Class that killed the player. +// byte iTargetClass; // Class of the player killed. + }; + + struct EntityDeathsLump_t + { + static const unsigned short LumpId = EP2STATS_LUMP_NPC; + + EntityDeathsLump_t() : + m_nBodyCount( 0u ), + m_nKilledPlayer( 0u ) + { + } + + EntityDeathsLump_t( const EntityDeathsLump_t &other ) + { + m_nBodyCount = other.m_nBodyCount; + m_nKilledPlayer = other.m_nKilledPlayer; + } + + unsigned int m_nBodyCount; // Number killed by player + unsigned int m_nKilledPlayer; // Number of times entity killed player + }; + + struct WeaponLump_t + { + static const unsigned short LumpId = EP2STATS_LUMP_WEAPON; + + WeaponLump_t() : + m_nShots( 0 ), + m_nHits( 0 ), + m_flDamageInflicted( 0.0 ) + { + } + + WeaponLump_t( const WeaponLump_t &other ) + { + m_nShots = other.m_nShots; + m_nHits = other.m_nHits; + m_flDamageInflicted = other.m_flDamageInflicted; + } + + unsigned int m_nShots; + unsigned int m_nHits; + double m_flDamageInflicted; + }; + + struct SaveGameInfoRecord_t + { + SaveGameInfoRecord_t() : + m_nFirstDeathIndex( -1 ), + m_nNumDeaths( 0 ), + m_nSaveHealth( -1 ) + { + Q_memset( m_nSavePos, 0, sizeof( m_nSavePos ) ); + } + + int m_nFirstDeathIndex; + int m_nNumDeaths; + // Health and player pos from the save file + short m_nSavePos[ 3 ]; + short m_nSaveHealth; + }; + +#pragma pack( 1 ) + // Adds save game type + struct SaveGameInfoRecord2_t : public SaveGameInfoRecord_t + { + enum SaveType_t + { + TYPE_UNKNOWN = 0, + TYPE_AUTOSAVE, + TYPE_USERSAVE + }; + + SaveGameInfoRecord2_t() : + m_SaveType( (byte)TYPE_UNKNOWN ) + { + } + + byte m_SaveType; + }; +#pragma pack() + + struct SaveGameInfo_t + { + static const unsigned short LumpId = EP2STATS_LUMP_SAVEGAMEINFO; + + SaveGameInfo_t() : + m_nCurrentSaveFileTime( 0 ), + m_pCurrentRecord( NULL ) + { + } + + void Latch( char const *pchSaveName, unsigned int uFileTime ) + { + m_pCurrentRecord = &m_Records[ m_Records.AddToTail() ]; + m_nCurrentSaveFileTime = uFileTime; + m_sCurrentSaveFile = pchSaveName; + } + + CUtlVector< SaveGameInfoRecord2_t > m_Records; + SaveGameInfoRecord2_t *m_pCurrentRecord; + unsigned int m_nCurrentSaveFileTime; + CUtlString m_sCurrentSaveFile; + }; + + struct GenericStatsLump_t + { + static const unsigned short LumpId = EP2STATS_LUMP_GENERIC; + static const unsigned short LumpVersion = 1; + + GenericStatsLump_t() : + m_unCount( 0u ), + m_flCurrentValue( 0.0 ) + { + m_Pos[ 0 ] = m_Pos[ 1 ] = m_Pos[ 2 ] = 0; + } + + short m_Pos[ 3 ]; + unsigned int m_unCount; + double m_flCurrentValue; + }; + + // Data. + LevelHeader_t m_Header; // Level header. + Tag_t m_Tag; + CUtlVector m_aPlayerDeaths; // List of player deaths. + CUtlDict< EntityDeathsLump_t, int > m_dictEntityDeaths; + CUtlDict< WeaponLump_t, int > m_dictWeapons; + CUtlDict< GenericStatsLump_t, int > m_dictGeneric; + + SaveGameInfo_t m_SaveGameInfo; + float m_FloatCounters[ NUM_FLOATCOUNTER_TYPES ]; + uint64 m_IntCounters[ NUM_INTCOUNTER_TYPES ]; + + // Temporary data. + bool m_bInitialized; // Has the map Map Stat Data been initialized. + float m_flLevelStartTime; +}; + +#if defined( GAME_DLL ) +class CEP2GameStats : public CEP1GameStats +{ + typedef CEP1GameStats BaseClass; + +public: + CEP2GameStats(); + virtual ~CEP2GameStats(); + + virtual CBaseGameStats *OnInit( CBaseGameStats *pCurrentGameStats, char const *gamedir ) { return pCurrentGameStats; } + + virtual bool UserPlayedAllTheMaps( void ); + virtual const char *GetStatSaveFileName( void ); + virtual const char *GetStatUploadRegistryKeyName( void ); + + // Buffers. + virtual void AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer ); + virtual void LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer ); + + // Events + virtual void Event_LevelInit( void ); + virtual void Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info ); + virtual void Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info ); + virtual void Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info ); + virtual void Event_CrateSmashed(); + virtual void Event_Punted( CBaseEntity *pObject ); + virtual void Event_PlayerTraveled( CBasePlayer *pBasePlayer, float distanceInInches, bool bInVehicle, bool bSprinting ); + virtual void Event_WeaponFired( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName ); + virtual void Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info ); + virtual void Event_SaveGame( void ); + virtual void Event_LoadGame( void ); + virtual void Event_FlippedVehicle( CBasePlayer *pDriver, CPropVehicleDriveable *pVehicle ); + // Called before .sav file is actually loaded (player should still be in previous level, if any) + virtual void Event_PreSaveGameLoaded( char const *pSaveName, bool bInGame ); + virtual void Event_PlayerEnteredGodMode( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerEnteredNoClip( CBasePlayer *pBasePlayer ); + virtual void Event_DecrementPlayerEnteredNoClip( CBasePlayer *pBasePlayer ); + // Generic statistics lump + virtual void Event_IncrementCountedStatistic( const Vector& vecAbsOrigin, char const *pchStatisticName, float flIncrementAmount ); + +public: //FIXME: temporary used for CC_ListDeaths command + Ep2LevelStats_t *FindOrAddMapStats( const char *szMapName ); + +public: + + Ep2LevelStats_t::EntityDeathsLump_t *FindDeathsLump( char const *npcName ); + Ep2LevelStats_t::WeaponLump_t *FindWeaponsLump( char const *pchWeaponName, bool bPrimary ); + Ep2LevelStats_t::GenericStatsLump_t *FindGenericLump( char const *pchStatName ); + // Utilities. + Ep2LevelStats_t *GetCurrentMap( void ) { return m_pCurrentMap; } + + Ep2LevelStats_t *m_pCurrentMap; + CUtlDict m_dictMapStats; + enum + { + INVEHICLE = 0, + ONFOOT, + ONFOOTSPRINTING, + + NUM_TRAVEL_TYPES + }; + float m_flInchesRemainder[ NUM_TRAVEL_TYPES ]; +}; +#endif + +#endif // EP2_GAMESTATS_H diff --git a/game/server/episodic/grenade_hopwire.h b/game/server/episodic/grenade_hopwire.h new file mode 100644 index 0000000..c8cd71e --- /dev/null +++ b/game/server/episodic/grenade_hopwire.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GRENADE_HOPWIRE_H +#define GRENADE_HOPWIRE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" +#include "Sprite.h" + +extern ConVar hopwire_trap; + +class CGravityVortexController; + +class CGrenadeHopwire : public CBaseGrenade +{ + DECLARE_CLASS( CGrenadeHopwire, CBaseGrenade ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + +public: + void Spawn( void ); + void Precache( void ); + bool CreateVPhysics( void ); + void SetTimer( float timer ); + void SetVelocity( const Vector &velocity, const AngularImpulse &angVelocity ); + void Detonate( void ); + + void EndThink( void ); // Last think before going away + void CombatThink( void ); // Makes the main explosion go off + +protected: + + void KillStriders( void ); + + CHandle m_hVortexController; +}; + +extern CBaseGrenade *HopWire_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, float timer ); + +#endif // GRENADE_HOPWIRE_H diff --git a/game/server/episodic/npc_hunter.h b/game/server/episodic/npc_hunter.h new file mode 100644 index 0000000..b68cedf --- /dev/null +++ b/game/server/episodic/npc_hunter.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Expose an IsAHunter function +// +//=============================================================================// + +#ifndef NPC_HUNTER_H +#define NPC_HUNTER_H + +#if defined( _WIN32 ) +#pragma once +#endif + +class CBaseEntity; + +/// true if given entity pointer is a hunter. +bool Hunter_IsHunter(CBaseEntity *pEnt); + +// call throughs for member functions + +void Hunter_StriderBusterAttached( CBaseEntity *pHunter, CBaseEntity *pAttached ); +void Hunter_StriderBusterDetached( CBaseEntity *pHunter, CBaseEntity *pAttached ); +void Hunter_StriderBusterLaunched( CBaseEntity *pBuster ); + +#endif diff --git a/game/server/episodic/vehicle_jeep_episodic.h b/game/server/episodic/vehicle_jeep_episodic.h new file mode 100644 index 0000000..70cb589 --- /dev/null +++ b/game/server/episodic/vehicle_jeep_episodic.h @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VEHICLE_JEEP_EPISODIC_H +#define VEHICLE_JEEP_EPISODIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vehicle_jeep.h" +#include "ai_basenpc.h" +#include "hl2_vehicle_radar.h" + +class CParticleSystem; +class CVehicleCargoTrigger; +class CSprite; + +#define NUM_WHEEL_EFFECTS 2 +#define NUM_HAZARD_LIGHTS 4 + +//============================================================================= +// Episodic jeep + +class CPropJeepEpisodic : public CPropJeep +{ + DECLARE_CLASS( CPropJeepEpisodic, CPropJeep ); + DECLARE_SERVERCLASS(); + +public: + CPropJeepEpisodic( void ); + + virtual void Spawn( void ); + virtual void Activate( void ); + virtual void Think( void ); + virtual void UpdateOnRemove( void ); + + virtual void NPC_FinishedEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); + virtual void NPC_FinishedExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); + + virtual bool NPC_CanEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); + virtual bool NPC_CanExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void Precache( void ); + virtual void EnterVehicle( CBaseCombatCharacter *pPassenger ); + virtual void ExitVehicle( int nRole ); + virtual bool AllowBlockedExit( CBaseCombatCharacter *pPassenger, int nRole ); + + // Passengers take no damage except what we pass them + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) + { + if ( GetServerVehicle() && GetServerVehicle()->IsPassengerExiting() ) + return false; + + return ( info.GetDamageType() & DMG_VEHICLE ) != 0; + } + + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_NOTIFY_ON_TRANSITION); } + + void SpawnRadarPanel(); + void DestroyRadarPanel(); + int NumRadarContacts() { return m_iNumRadarContacts; } + + void AddPropToCargoHold( CPhysicsProp *pProp ); + + virtual CBaseEntity *OnFailedPhysGunPickup( Vector vPhysgunPos ); + virtual void DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased ); + virtual int DrawDebugTextOverlays( void ); + + DECLARE_DATADESC(); + +protected: + void HazardBlinkThink( void ); + void CreateHazardLights( void ); + void DestroyHazardLights( void ); + + void UpdateCargoEntry( void ); + void ReleasePropFromCargoHold( void ); + void CreateCargoTrigger( void ); + virtual float GetUprightTime( void ) { return 1.0f; } + virtual float GetUprightStrength( void ); + virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) { return ( reason == PHYSGUN_FORCE_PUNTED ); } + virtual void HandleWater( void ); + + virtual AngularImpulse PhysGunLaunchAngularImpulse( void ); + virtual Vector PhysGunLaunchVelocity( const Vector &forward, float flMass ); + bool PassengerInTransition( void ); + + void SetBusterHopperVisibility(bool visible); + +private: + + void UpdateWheelDust( void ); + void UpdateRadar( bool forceUpdate = false ); + + void InputLockEntrance( inputdata_t &data ); + void InputUnlockEntrance( inputdata_t &data ); + void InputLockExit( inputdata_t &data ); + void InputUnlockExit( inputdata_t &data ); + void InputEnableRadar( inputdata_t &data ); + void InputDisableRadar( inputdata_t &data ); + void InputEnableRadarDetectEnemies( inputdata_t &data ); + void InputAddBusterToCargo( inputdata_t &data ); + void InputSetCargoVisibility( inputdata_t &data ); + void InputOutsideTransition( inputdata_t &data ); + void InputDisablePhysGun( inputdata_t &data ); + void InputEnablePhysGun( inputdata_t &data ); + void InputCreateLinkController( inputdata_t &data ); + void InputDestroyLinkController( inputdata_t &data ); + void CreateAvoidanceZone( void ); + + bool m_bEntranceLocked; + bool m_bExitLocked; + bool m_bAddingCargo; + bool m_bBlink; + + float m_flCargoStartTime; // Time when the cargo was first added to the vehicle (used for animating into hold) + float m_flNextAvoidBroadcastTime; // Next time we'll warn entity to move out of us + + COutputEvent m_OnCompanionEnteredVehicle; // Passenger has completed entering the vehicle + COutputEvent m_OnCompanionExitedVehicle; // Passenger has completed exited the vehicle + COutputEvent m_OnHostileEnteredVehicle; // Passenger has completed entering the vehicle + COutputEvent m_OnHostileExitedVehicle; // Passenger has completed exited the vehicle + + CHandle< CParticleSystem > m_hWheelDust[NUM_WHEEL_EFFECTS]; + CHandle< CParticleSystem > m_hWheelWater[NUM_WHEEL_EFFECTS]; + CHandle< CVehicleCargoTrigger > m_hCargoTrigger; + CHandle< CPhysicsProp > m_hCargoProp; + + CHandle< CSprite > m_hHazardLights[NUM_HAZARD_LIGHTS]; + float m_flNextWaterSound; + + bool m_bRadarEnabled; + bool m_bRadarDetectsEnemies; + float m_flNextRadarUpdateTime; + EHANDLE m_hRadarScreen; + + EHANDLE m_hLinkControllerFront; + EHANDLE m_hLinkControllerRear; + + bool m_bBusterHopperVisible; // is the hopper assembly visible on the vehicle? please do not set this directly - use the accessor funct. + + CNetworkVar( int, m_iNumRadarContacts ); + CNetworkArray( Vector, m_vecRadarContactPos, RADAR_MAX_CONTACTS ); + CNetworkArray( int, m_iRadarContactType, RADAR_MAX_CONTACTS ); +}; + +#endif // VEHICLE_JEEP_EPISODIC_H diff --git a/game/server/episodic/weapon_striderbuster.h b/game/server/episodic/weapon_striderbuster.h new file mode 100644 index 0000000..fe67034 --- /dev/null +++ b/game/server/episodic/weapon_striderbuster.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Helper functions for the striderbuster weapon. +// +//============================================================================= + +#ifndef WEAPON_STRIDERBUSTER_H +#define WEAPON_STRIDERBUSTER_H +#ifdef _WIN32 +#pragma once +#endif + +bool StriderBuster_IsAttachedStriderBuster( CBaseEntity *pEntity, CBaseEntity *pAttachedTo = NULL ); +void StriderBuster_OnAddToCargoHold( CBaseEntity *pEntity ); +bool StriderBuster_OnFlechetteAttach( CBaseEntity *pEntity, Vector &vecForceDir ); +int StriderBuster_NumFlechettesAttached( CBaseEntity *pEntity ); +float StriderBuster_GetPickupTime( CBaseEntity *pEntity ); +bool StriderBuster_WasKnockedOffStrider( CBaseEntity *pEntity ); + +#endif // WEAPON_STRIDERBUSTER_H diff --git a/game/server/event_tempentity_tester.h b/game/server/event_tempentity_tester.h new file mode 100644 index 0000000..9ece13a --- /dev/null +++ b/game/server/event_tempentity_tester.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( EVENT_TEMPENTITY_TESTER_H ) +#define EVENT_TEMPENTITY_TESTER_H +#ifdef _WIN32 +#pragma once +#endif + +class CBaseTempEntity; + + +//----------------------------------------------------------------------------- +// Purpose: A server object that is used to test all registered temp entities +//----------------------------------------------------------------------------- +class CTempEntTester : public CPointEntity +{ +public: + DECLARE_CLASS( CTempEntTester, CPointEntity ); + + void Spawn( void ); + void Think( void ); + + static CBaseEntity *Create( const Vector &vecOrigin, const QAngle &vecAngles, const char *lifetime, const char *single_te ); +private: + // Current temp entity to test + CBaseTempEntity *m_pCurrent; + + // Lifetime + float m_fLifeTime; + + char m_szClass[ 64 ]; +}; + +#endif // EVENT_TEMPENTITY_TESTER_H \ No newline at end of file diff --git a/game/server/eventqueue.h b/game/server/eventqueue.h new file mode 100644 index 0000000..1c7f030 --- /dev/null +++ b/game/server/eventqueue.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A global class that holds a prioritized queue of entity I/O events. +// Events can be posted with a nonzero delay, which determines how long +// they are held before being dispatched to their recipients. +// +// The queue is serviced once per server frame. +// +//=============================================================================// + +#ifndef EVENTQUEUE_H +#define EVENTQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mempool.h" + +struct EventQueuePrioritizedEvent_t +{ + float m_flFireTime; + string_t m_iTarget; + string_t m_iTargetInput; + EHANDLE m_pActivator; + EHANDLE m_pCaller; + int m_iOutputID; + EHANDLE m_pEntTarget; // a pointer to the entity to target; overrides m_iTarget + + variant_t m_VariantValue; // variable-type parameter + + EventQueuePrioritizedEvent_t *m_pNext; + EventQueuePrioritizedEvent_t *m_pPrev; + + DECLARE_SIMPLE_DATADESC(); + + DECLARE_FIXEDSIZE_ALLOCATOR( PrioritizedEvent_t ); +}; + +class CEventQueue +{ +public: + // pushes an event into the queue, targeting a string name (m_iName), or directly by a pointer + void AddEvent( const char *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); + void AddEvent( CBaseEntity *target, const char *action, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); + void AddEvent( CBaseEntity *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); + + void CancelEvents( CBaseEntity *pCaller ); + void CancelEventOn( CBaseEntity *pTarget, const char *sInputName ); + bool HasEventPending( CBaseEntity *pTarget, const char *sInputName ); + + // services the queue, firing off any events who's time hath come + void ServiceEvents( void ); + + // debugging + void ValidateQueue( void ); + + // serialization + int Save( ISave &save ); + int Restore( IRestore &restore ); + + CEventQueue(); + ~CEventQueue(); + + void Init( void ); + void Clear( void ); // resets the list + + void Dump( void ); + +private: + + void AddEvent( EventQueuePrioritizedEvent_t *event ); + void RemoveEvent( EventQueuePrioritizedEvent_t *pe ); + + DECLARE_SIMPLE_DATADESC(); + EventQueuePrioritizedEvent_t m_Events; + int m_iListCount; +}; + +extern CEventQueue g_EventQueue; + + +#endif // EVENTQUEUE_H + diff --git a/game/server/explode.h b/game/server/explode.h new file mode 100644 index 0000000..956c1e0 --- /dev/null +++ b/game/server/explode.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef EXPLODE_H +#define EXPLODE_H + +#define SF_ENVEXPLOSION_NODAMAGE 0x00000001 // when set, ENV_EXPLOSION will not actually inflict damage +#define SF_ENVEXPLOSION_REPEATABLE 0x00000002 // can this entity be refired? +#define SF_ENVEXPLOSION_NOFIREBALL 0x00000004 // don't draw the fireball +#define SF_ENVEXPLOSION_NOSMOKE 0x00000008 // don't draw the smoke +#define SF_ENVEXPLOSION_NODECAL 0x00000010 // don't make a scorch mark +#define SF_ENVEXPLOSION_NOSPARKS 0x00000020 // don't make sparks +#define SF_ENVEXPLOSION_NOSOUND 0x00000040 // don't play explosion sound. +#define SF_ENVEXPLOSION_RND_ORIENT 0x00000080 // randomly oriented sprites +#define SF_ENVEXPLOSION_NOFIREBALLSMOKE 0x0100 +#define SF_ENVEXPLOSION_NOPARTICLES 0x00000200 +#define SF_ENVEXPLOSION_NODLIGHTS 0x00000400 +#define SF_ENVEXPLOSION_NOCLAMPMIN 0x00000800 // don't clamp the minimum size of the fireball sprite +#define SF_ENVEXPLOSION_NOCLAMPMAX 0x00001000 // don't clamp the maximum size of the fireball sprite +#define SF_ENVEXPLOSION_SURFACEONLY 0x00002000 // don't damage the player if he's underwater. +#define SF_ENVEXPLOSION_GENERIC_DAMAGE 0x00004000 // don't do BLAST damage + +extern short g_sModelIndexFireball; +extern short g_sModelIndexSmoke; + +void ExplosionCreate( const Vector ¢er, const QAngle &angles, + CBaseEntity *pOwner, int magnitude, int radius, bool doDamage, float flExplosionForce = 0.0f, bool bSurfaceOnly = false, bool bSilent = false, int iCustomDamageType = -1 ); + +void ExplosionCreate( const Vector ¢er, const QAngle &angles, + CBaseEntity *pOwner, int magnitude, int radius, int nSpawnFlags, + float flExplosionForce = 0.0f, CBaseEntity *pInflictor = NULL, int iCustomDamageType = -1, const EHANDLE *ignoredEntity = NULL, Class_T ignoredClass = CLASS_NONE); + +// this version lets you specify classes or entities to be ignored +void ExplosionCreate( const Vector ¢er, const QAngle &angles, + CBaseEntity *pOwner, int magnitude, int radius, bool doDamage, + const EHANDLE *ignoredEntity, Class_T ignoredClass, + float flExplosionForce = 0.0f, bool bSurfaceOnly = false, bool bSilent = false, int iCustomDamageType = -1 ); + +#endif //EXPLODE_H diff --git a/game/server/filters.h b/game/server/filters.h new file mode 100644 index 0000000..483de24 --- /dev/null +++ b/game/server/filters.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Filters are outboard entities that hold a set of rules that other +// entities can use to determine behaviors. +// +// For example, triggers can use an activator filter to determine who +// activates them. NPCs and breakables can use a damage filter to +// determine what can damage them. +// +// Current filter criteria are: +// +// Activator name +// Activator class +// Activator team +// Damage type (for damage filters only) +// +// More than one filter can be combined to create a more complex boolean +// expression by using filter_multi. +// +//=============================================================================// + +#ifndef FILTERS_H +#define FILTERS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "entityoutput.h" + +// ################################################################### +// > BaseFilter +// ################################################################### +class CBaseFilter : public CLogicalEntity +{ + DECLARE_CLASS( CBaseFilter, CLogicalEntity ); + +public: + + DECLARE_DATADESC(); + + bool PassesFilter( CBaseEntity *pCaller, CBaseEntity *pEntity ); + bool PassesDamageFilter( const CTakeDamageInfo &info ); + + bool m_bNegated; + + // Inputs + void InputTestActivator( inputdata_t &inputdata ); + + // Outputs + COutputEvent m_OnPass; // Fired when filter is passed + COutputEvent m_OnFail; // Fired when filter is failed + +protected: + + virtual bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ); + virtual bool PassesDamageFilterImpl(const CTakeDamageInfo &info); +}; + +#endif // FILTERS_H diff --git a/game/server/fire.h b/game/server/fire.h new file mode 100644 index 0000000..c04641b --- /dev/null +++ b/game/server/fire.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FIRE_H +#define FIRE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "entityoutput.h" +#include "fire_smoke.h" +#include "plasma.h" + +//Spawnflags +#define SF_FIRE_INFINITE 0x00000001 +#define SF_FIRE_SMOKELESS 0x00000002 +#define SF_FIRE_START_ON 0x00000004 +#define SF_FIRE_START_FULL 0x00000008 +#define SF_FIRE_DONT_DROP 0x00000010 +#define SF_FIRE_NO_GLOW 0x00000020 +#define SF_FIRE_DIE_PERMANENT 0x00000080 +#define SF_FIRE_VISIBLE_FROM_ABOVE 0x00000100 + +//================================================== +// CFire +//================================================== + +enum fireType_e +{ + FIRE_NATURAL = 0, + FIRE_PLASMA, +}; + +//================================================== + +// NPCs and grates do not prevent fire from travelling +#define MASK_FIRE_SOLID ( MASK_SOLID & (~(CONTENTS_MONSTER|CONTENTS_GRATE)) ) + +//================================================== +// FireSystem +//================================================== +bool FireSystem_StartFire( const Vector &position, float fireHeight, float attack, float fuel, int flags, CBaseEntity *owner, fireType_e type = FIRE_NATURAL); +void FireSystem_ExtinguishInRadius( const Vector &origin, float radius, float rate ); +void FireSystem_AddHeatInRadius( const Vector &origin, float radius, float heat ); + +bool FireSystem_GetFireDamageDimensions( CBaseEntity *pFire, Vector *pFireMins, Vector *pFireMaxs ); + +#endif // FIRE_H diff --git a/game/server/fire_smoke.h b/game/server/fire_smoke.h new file mode 100644 index 0000000..a41aeb4 --- /dev/null +++ b/game/server/fire_smoke.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef FIRE_SMOKE_H +#define FIRE_SMOKE_H +#pragma once + +#include "baseparticleentity.h" + +//================================================== +// CBaseFire +//================================================== + +//NOTENOTE: Reserved for all descendants +#define bitsFIRE_NONE 0x00000000 +#define bitsFIRE_ACTIVE 0x00000001 + +class CBaseFire : public CBaseEntity +{ +public: + DECLARE_DATADESC(); + DECLARE_CLASS( CBaseFire, CBaseEntity ); + + CBaseFire( void ); + virtual ~CBaseFire( void ); + + virtual void Scale( float size, float time ); + virtual void Scale( float start, float size, float time ); + virtual void Enable( int state = true ); + + //Client-side + CNetworkVar( float, m_flStartScale ); + CNetworkVar( float, m_flScale ); + CNetworkVar( float, m_flScaleTime ); + CNetworkVar( int, m_nFlags ); +}; + +//================================================== +// CFireSmoke +//================================================== + +//NOTENOTE: Mirrored in cl_dll/c_fire_smoke.cpp +#define bitsFIRESMOKE_SMOKE 0x00000002 +#define bitsFIRESMOKE_SMOKE_COLLISION 0x00000004 +#define bitsFIRESMOKE_GLOW 0x00000008 +#define bitsFIRESMOKE_VISIBLE_FROM_ABOVE 0x00000010 + +class CFireSmoke : public CBaseFire +{ +public: + DECLARE_CLASS( CFireSmoke, CBaseFire ); + + CFireSmoke( void ); + virtual ~CFireSmoke( void ); + + void Spawn(); + void Precache(); + void EnableSmoke( int state = true ); + void EnableGlow( int state = true ); + void EnableVisibleFromAbove( int state = true ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +public: + + //Client-side + CNetworkVar( int, m_nFlameModelIndex ); + CNetworkVar( int, m_nFlameFromAboveModelIndex ); + + //Server-side +}; + +#endif //FIRE_SMOKE_H diff --git a/game/server/fish.h b/game/server/fish.h new file mode 100644 index 0000000..6eb7e64 --- /dev/null +++ b/game/server/fish.h @@ -0,0 +1,140 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// fish.h +// Simple fish behavior +// Author: Michael S. Booth, April 2005 + +#ifndef _FISH_H_ +#define _FISH_H_ + +#include "baseanimating.h" +#include "GameEventListener.h" + +class CFishPool; + +//---------------------------------------------------------------------------------------------- +/** + * Simple ambient fish + */ +class CFish : public CBaseAnimating +{ +public: + DECLARE_CLASS( CFish, CBaseAnimating ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CFish( void ); + virtual ~CFish(); + + void Initialize( CFishPool *pool, unsigned int id ); + + virtual void Spawn( void ); + + virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual void Touch( CBaseEntity *other ); ///< in contact with "other" + + void Update( float deltaT ); ///< invoked each server tick + + void FlockTo( CFish *other, float amount ); ///< influence my motion to flock with other nearby fish + float Avoid( void ); + void Panic( void ); ///< panic for awhile + + void ResetVisible( void ); ///< zero the visible vector + void AddVisible( CFish *fish ); ///< add this fish to our visible vector + +private: + friend void SendProxy_FishOriginX( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); + friend void SendProxy_FishOriginY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); + + CHandle m_pool; ///< the pool we are in + unsigned int m_id; ///< our unique ID + + CNetworkVar( float, m_x ); ///< have to send position coordinates separately since Z is unused + CNetworkVar( float, m_y ); ///< have to send position coordinates separately since Z is unused + CNetworkVar( float, m_z ); ///< only sent once since fish always swim at the same depth + + CNetworkVar( float, m_angle ); ///< only yaw changes + float m_angleChange; + Vector m_forward; + Vector m_perp; + + CNetworkVar( Vector, m_poolOrigin ); ///< used to efficiently network our relative position + CNetworkVar( float, m_waterLevel ); + + float m_speed; + float m_desiredSpeed; + + float m_calmSpeed; ///< speed the fish moves when calm + float m_panicSpeed; ///< speed the fish moves when panicked + + float m_avoidRange; ///< range to avoid obstacles + + CountdownTimer m_turnTimer; ///< every so often our turn preference changes + bool m_turnClockwise; ///< if true this fish prefers to turn clockwise, else CCW + + CountdownTimer m_goTimer; ///< start the fish moving when timer elapses + CountdownTimer m_moveTimer; ///< dont decay speed while we are moving + CountdownTimer m_panicTimer; ///< if active, fish is panicked + CountdownTimer m_disperseTimer; ///< initial non-flocking time + + CUtlVector< CFish * > m_visible; ///< vector of fish that we can see +}; + + +//---------------------------------------------------------------------------------------------- +/** + * This class defines a volume of water where a number of CFish swim + */ +class CFishPool : public CBaseEntity, public CGameEventListener +{ +public: + DECLARE_CLASS( CFishPool, CBaseEntity ); + DECLARE_DATADESC(); + + CFishPool( void ); + + virtual void Spawn(); + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual void FireGameEvent( IGameEvent *event ); + + void Update( void ); ///< invoked each server tick + + float GetWaterLevel( void ) const; ///< return Z coordinate of water in world coords + float GetMaxRange( void ) const; ///< return how far a fish is allowed to wander + +private: + int m_fishCount; ///< number of fish in the pool + float m_maxRange; ///< how far a fish is allowed to wander + float m_swimDepth; ///< the depth the fish swim below the water surface + + float m_waterLevel; ///< Z of water surface + + bool m_isDormant; + + CUtlVector< CHandle > m_fishes; ///< vector of all fish in this pool + + CountdownTimer m_visTimer; ///< for throttling line of sight checks between all fish +}; + + +inline float CFishPool::GetMaxRange( void ) const +{ + return m_maxRange; +} + + +inline float CFishPool::GetWaterLevel( void ) const +{ + return m_waterLevel; +} + + +#endif // _FISH_H_ + diff --git a/game/server/fogcontroller.h b/game/server/fogcontroller.h new file mode 100644 index 0000000..3a5b716 --- /dev/null +++ b/game/server/fogcontroller.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FOGCONTROLLER_H +#define FOGCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "playernet_vars.h" +#include "igamesystem.h" + +// Spawn Flags +#define SF_FOG_MASTER 0x0001 + +//============================================================================= +// +// Class Fog Controller: +// Compares a set of integer inputs to the one main input +// Outputs true if they are all equivalant, false otherwise +// +class CFogController : public CBaseEntity +{ +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DECLARE_CLASS( CFogController, CBaseEntity ); + + CFogController(); + ~CFogController(); + + // Parse data from a map file + virtual void Activate(); + virtual int UpdateTransmitState(); + + // Input handlers + void InputSetStartDist(inputdata_t &data); + void InputSetEndDist(inputdata_t &data); + void InputTurnOn(inputdata_t &data); + void InputTurnOff(inputdata_t &data); + void InputSetColor(inputdata_t &data); + void InputSetColorSecondary(inputdata_t &data); + void InputSetFarZ( inputdata_t &data ); + void InputSetAngles( inputdata_t &inputdata ); + void InputSetMaxDensity( inputdata_t &inputdata ); + + void InputSetColorLerpTo(inputdata_t &data); + void InputSetColorSecondaryLerpTo(inputdata_t &data); + void InputSetStartDistLerpTo(inputdata_t &data); + void InputSetEndDistLerpTo(inputdata_t &data); + + void InputStartFogTransition(inputdata_t &data); + + int DrawDebugTextOverlays(void); + + void SetLerpValues( void ); + void Spawn( void ); + + bool IsMaster( void ) { return HasSpawnFlags( SF_FOG_MASTER ); } + +public: + + CNetworkVarEmbedded( fogparams_t, m_fog ); + bool m_bUseAngles; + int m_iChangedVariables; +}; + +//============================================================================= +// +// Fog Controller System. +// +class CFogSystem : public CAutoGameSystem +{ +public: + + // Creation/Init. + CFogSystem( char const *name ) : CAutoGameSystem( name ) + { + m_pMasterController = NULL; + } + + ~CFogSystem() + { + m_pMasterController = NULL; + } + + virtual void LevelInitPreEntity(); + virtual void LevelInitPostEntity(); + CFogController *GetMasterFogController( void ) { return m_pMasterController; } + +private: + + CFogController *m_pMasterController; +}; + +CFogSystem *FogSystem( void ); + +#endif // FOGCONTROLLER_H diff --git a/game/server/fourwheelvehiclephysics.h b/game/server/fourwheelvehiclephysics.h new file mode 100644 index 0000000..ab9e850 --- /dev/null +++ b/game/server/fourwheelvehiclephysics.h @@ -0,0 +1,218 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A base class that deals with four-wheel vehicles +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FOUR_WHEEL_VEHICLE_PHYSICS_H +#define FOUR_WHEEL_VEHICLE_PHYSICS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vphysics/vehicles.h" +#include "vcollide_parse.h" +#include "datamap.h" +#include "vehicle_sounds.h" + +// in/sec to miles/hour +#define INS2MPH_SCALE ( 3600 * (1/5280.0f) * (1/12.0f) ) +#define INS2MPH(x) ( (x) * INS2MPH_SCALE ) +#define MPH2INS(x) ( (x) * (1/INS2MPH_SCALE) ) + +class CBaseAnimating; +class CFourWheelServerVehicle; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CFourWheelVehiclePhysics +{ +public: + DECLARE_DATADESC(); + + CFourWheelVehiclePhysics( CBaseAnimating *pOuter ); + ~CFourWheelVehiclePhysics (); + + // Call Precache + Spawn from the containing entity's Precache + Spawn methods + void Spawn(); + void SetOuter( CBaseAnimating *pOuter, CFourWheelServerVehicle *pServerVehicle ); + + // Initializes the vehicle physics so we can drive it + bool Initialize( const char *pScriptName, unsigned int nVehicleType ); + + void Teleport( matrix3x4_t& relativeTransform ); + bool VPhysicsUpdate( IPhysicsObject *pPhysics ); + bool Think(); + void PlaceWheelDust( int wheelIndex, bool ignoreSpeed = false ); + + void DrawDebugGeometryOverlays(); + int DrawDebugTextOverlays( int nOffset ); + + // Updates the controls based on user input + void UpdateDriverControls( CUserCmd *cmd, float flFrameTime ); + + // Various steering parameters + void SetThrottle( float flThrottle ); + void SetMaxThrottle( float flMaxThrottle ); + void SetMaxReverseThrottle( float flMaxThrottle ); + void SetSteering( float flSteering, float flSteeringRate ); + void SetSteeringDegrees( float flDegrees ); + void SetAction( float flAction ); + void TurnOn( ); + void TurnOff(); + void ReleaseHandbrake(); + void SetHandbrake( bool bBrake ); + bool IsOn() const { return m_bIsOn; } + void ResetControls(); + void SetBoost( float flBoost ); + bool UpdateBooster( void ); + void SetHasBrakePedal( bool bHasBrakePedal ); + + // Engine + void SetDisableEngine( bool bDisable ); + bool IsEngineDisabled( void ) { return m_pVehicle->IsEngineDisabled(); } + + // Enable/Disable Motion + void EnableMotion( void ); + void DisableMotion( void ); + + // Shared code to compute the vehicle view position + void GetVehicleViewPosition( const char *pViewAttachment, float flPitchFactor, Vector *pAbsPosition, QAngle *pAbsAngles ); + + IPhysicsObject *GetWheel( int iWheel ) { return m_pWheels[iWheel]; } + + int GetSpeed() const; + int GetMaxSpeed() const; + int GetRPM() const; + float GetThrottle() const; + bool HasBoost() const; + int BoostTimeLeft() const; + bool IsBoosting( void ); + float GetHLSpeed() const; + float GetSteering() const; + float GetSteeringDegrees() const; + IPhysicsVehicleController* GetVehicle(void) { return m_pVehicle; } + float GetWheelBaseHeight(int wheelIndex) { return m_wheelBaseHeight[wheelIndex]; } + float GetWheelTotalHeight(int wheelIndex) { return m_wheelTotalHeight[wheelIndex]; } + + IPhysicsVehicleController *GetVehicleController() { return m_pVehicle; } + const vehicleparams_t &GetVehicleParams( void ) { return m_pVehicle->GetVehicleParams(); } + const vehicle_controlparams_t &GetVehicleControls( void ) { return m_controls; } + const vehicle_operatingparams_t &GetVehicleOperatingParams( void ) { return m_pVehicle->GetOperatingParams(); } + + int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + +private: + // engine sounds + void CalcWheelData( vehicleparams_t &vehicle ); + + void SteeringRest( float carSpeed, const vehicleparams_t &vehicleData ); + void SteeringTurn( float carSpeed, const vehicleparams_t &vehicleData, bool bTurnLeft, bool bBrake, bool bThrottle ); + void SteeringTurnAnalog( float carSpeed, const vehicleparams_t &vehicleData, float sidemove ); + + // A couple wrapper methods to perform common operations + int LookupPoseParameter( const char *szName ); + float GetPoseParameter( int iParameter ); + float SetPoseParameter( int iParameter, float flValue ); + bool GetAttachment ( const char *szName, Vector &origin, QAngle &angles ); + + void InitializePoseParameters(); + bool ParseVehicleScript( const char *pScriptName, solid_t &solid, vehicleparams_t &vehicle ); + +private: + // This is the entity that contains this class + CHandle m_pOuter; + CFourWheelServerVehicle *m_pOuterServerVehicle; + + vehicle_controlparams_t m_controls; + IPhysicsVehicleController *m_pVehicle; + + // Vehicle state info + int m_nSpeed; + int m_nLastSpeed; + int m_nRPM; + float m_fLastBoost; + int m_nBoostTimeLeft; + int m_nHasBoost; + + float m_maxThrottle; + float m_flMaxRevThrottle; + float m_flMaxSpeed; + float m_actionSpeed; + IPhysicsObject *m_pWheels[4]; + + int m_wheelCount; + + Vector m_wheelPosition[4]; + QAngle m_wheelRotation[4]; + float m_wheelBaseHeight[4]; + float m_wheelTotalHeight[4]; + int m_poseParameters[12]; + float m_actionValue; + float m_actionScale; + float m_debugRadius; + float m_throttleRate; + float m_throttleStartTime; + float m_throttleActiveTime; + float m_turboTimer; + + float m_flVehicleVolume; // NPC driven vehicles used louder sounds + bool m_bIsOn; + bool m_bLastThrottle; + bool m_bLastBoost; + bool m_bLastSkid; +}; + + +//----------------------------------------------------------------------------- +// Physics state.. +//----------------------------------------------------------------------------- +inline int CFourWheelVehiclePhysics::GetSpeed() const +{ + return m_nSpeed; +} + +inline int CFourWheelVehiclePhysics::GetMaxSpeed() const +{ + return INS2MPH(m_pVehicle->GetVehicleParams().engine.maxSpeed); +} + +inline int CFourWheelVehiclePhysics::GetRPM() const +{ + return m_nRPM; +} + +inline float CFourWheelVehiclePhysics::GetThrottle() const +{ + return m_controls.throttle; +} + +inline bool CFourWheelVehiclePhysics::HasBoost() const +{ + return m_nHasBoost != 0; +} + +inline int CFourWheelVehiclePhysics::BoostTimeLeft() const +{ + return m_nBoostTimeLeft; +} + +inline void CFourWheelVehiclePhysics::SetOuter( CBaseAnimating *pOuter, CFourWheelServerVehicle *pServerVehicle ) +{ + m_pOuter = pOuter; + m_pOuterServerVehicle = pServerVehicle; +} + +float RemapAngleRange( float startInterval, float endInterval, float value ); + +#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero +#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out + +#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero +#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out + +#endif // FOUR_WHEEL_VEHICLE_PHYSICS_H diff --git a/game/server/func_areaportalbase.h b/game/server/func_areaportalbase.h new file mode 100644 index 0000000..ff6c167 --- /dev/null +++ b/game/server/func_areaportalbase.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_AREAPORTALBASE_H +#define FUNC_AREAPORTALBASE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" +#include "utllinkedlist.h" + + +// Shared stuff between door portals and window portals. +class CFuncAreaPortalBase : public CBaseEntity +{ + DECLARE_CLASS( CFuncAreaPortalBase, CBaseEntity ); +public: + DECLARE_DATADESC(); + + CFuncAreaPortalBase(); + virtual ~CFuncAreaPortalBase(); + + // Areaportals must be placed in each map for preprocess, they can't use transitions + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + // This is called each frame for each client to all portals to close + // when the viewer is far enough away, or on the backside. + // + // The default implementation closes the portal if the viewer (plus some padding) + // is on the backside of the portal. Return false if you close the portal. + // + // Returns whether or not the (server part of) the engine was told to shut the + // portal off for purposes of flowing through portals to determine which areas to + // send to the client. + // + // + // bIsOpenOnClient is usually the same as the return value but NOT always. Here's why (explained + // here in depth because this case was discovered in a lengthy debugging session): + // + // - Each CFuncAreaPortalBase represents two dareaportal_t's (matched by CFuncAreaPortalBase::m_portalNumber + // and dareaportal_t::m_PortalKey). Each dareaportal_t leads into one of the connected areas + // and the dareaportal_t's have opposite-facing planes. + // + // - The engine's SetAreaPortalState function takes a portal key and closes BOTH dareaportal_t's associated with it. + // + // - UpdateVisibility may decide a portal leading out of the _area you're sitting in_ can be closed + // for purposes of flowing through areas because you're on the backside of the dareaportal_t that + // you would flow out of. + // + // - At the same time, you might be able to look through the other dareaportal_t attached to + // that portal key (right back into the area you're standing in). + // + // - An illustration: + // + // -------------------- + // | | + // | |--------|aaaaaa| + // | | |bbbbbb| <---- aaaa and bbbb area both for PortalKey1 + // |**| | | + // | | | area | + // |**| | 2 | + // | | |------| + // | | | | + // | ---------- area | + // | 1 | + // |------------------| + // + // "aaaa" and "bbbb" each represent a different dareaportal_t, (aaa leads into area 2 and + // bbb leads into area 1). They both represent the same portal key though (call it PortalKey1). + // + // When standing in area 1 (where the "area 1" text is), the engine will check aaaa and it'll notice + // that you're on the wrong side of aaaa to be looking through it, so it'll say that PortalKey1 is closed + // for purposes of flowing through areas on the server (it turns out you can get to area 2 through + // the portal right above the "area 1" text). + // + // If you told the client that PortalKey1 was closed, then you'd get a pop when moving from area 1 + // to area 2 because the client would think you couldn't see through PortalKey1 into area 1 UNTIL + // the server transmitted the new updated PortalKey bits, which can be lagged. + // + // That's why we have bIsOpenOnClient which doesn't include this backfacing test. + // + // .. and they all lived happily ever after. + // The End + // + // + // + // Note: when you're standing in the space between the **'s, then the server would stop transmitting + // the contents of area 2 because there would be no portal you were on the correct side of to + // see into area 2. + virtual bool UpdateVisibility( const Vector &vOrigin, float fovDistanceAdjustFactor, bool &bIsOpenOnClient ); + + +public: + + // This matches two dareaportal_t::m_PortalKeys. + int m_portalNumber; + + int m_iPortalVersion; + +private: + + unsigned short m_AreaPortalsElement; // link into g_AreaPortals. +}; + + +extern CUtlLinkedList g_AreaPortals; + + + +#endif // FUNC_AREAPORTALBASE_H diff --git a/game/server/func_areaportalwindow.h b/game/server/func_areaportalwindow.h new file mode 100644 index 0000000..d128c84 --- /dev/null +++ b/game/server/func_areaportalwindow.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_AREAPORTALWINDOW_H +#define FUNC_AREAPORTALWINDOW_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" +#include "utllinkedlist.h" +#include "func_areaportalbase.h" + + +class CFuncAreaPortalWindow : public CFuncAreaPortalBase +{ +public: + DECLARE_CLASS( CFuncAreaPortalWindow, CFuncAreaPortalBase ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CFuncAreaPortalWindow(); + ~CFuncAreaPortalWindow(); + + +// Overrides. +public: + + virtual void Spawn(); + virtual void Activate(); + + +// CFuncAreaPortalBase stuff. +public: + + virtual bool UpdateVisibility( const Vector &vOrigin, float fovDistanceAdjustFactor, bool &bIsOpenOnClient ); + + +public: + // Returns false if the viewer is past the fadeout distance. + bool IsWindowOpen( const Vector &vOrigin, float fovDistanceAdjustFactor ); + +public: + + CNetworkVar( float, m_flFadeStartDist ); // Distance at which it starts fading (when <= this, alpha=m_flTranslucencyLimit). + CNetworkVar( float, m_flFadeDist ); // Distance at which it becomes solid. + + // 0-1 value - minimum translucency it's allowed to get to. + CNetworkVar( float, m_flTranslucencyLimit ); + + string_t m_iBackgroundBModelName; // string name of background bmodel + CNetworkVar( int, m_iBackgroundModelIndex ); + + //Input handlers + void InputSetFadeStartDistance( inputdata_t &inputdata ); + void InputSetFadeEndDistance( inputdata_t &inputdata ); +}; + + + +#endif // FUNC_AREAPORTALWINDOW_H diff --git a/game/server/func_break.h b/game/server/func_break.h new file mode 100644 index 0000000..d423c95 --- /dev/null +++ b/game/server/func_break.h @@ -0,0 +1,174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines a class for objects that break after taking a certain amount +// of damage. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_BREAK_H +#define FUNC_BREAK_H +#pragma once + +#include "entityoutput.h" +#include "props.h" + +typedef enum { expRandom = 0, expDirected, expUsePrecise} Explosions; +typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matWeb, matNone, matLastMaterial } Materials; + + +#define NUM_SHARDS 6 // this many shards spawned when breakable objects break; + +// Spawnflags for func breakable +#define SF_BREAK_TRIGGER_ONLY 0x0001 // may only be broken by trigger +#define SF_BREAK_TOUCH 0x0002 // can be 'crashed through' by running player (plate glass) +#define SF_BREAK_PRESSURE 0x0004 // can be broken by a player standing on it +#define SF_BREAK_PHYSICS_BREAK_IMMEDIATELY 0x0200 // the first physics collision this breakable has will immediately break it +#define SF_BREAK_DONT_TAKE_PHYSICS_DAMAGE 0x0400 // this breakable doesn't take damage from physics collisions +#define SF_BREAK_NO_BULLET_PENETRATION 0x0800 // don't allow bullets to penetrate + +// Spawnflags for func_pushable (it's also func_breakable, so don't collide with those flags) +#define SF_PUSH_BREAKABLE 0x0080 +#define SF_PUSH_NO_USE 0x0100 // player cannot +use pickup this ent + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBreakable : public CBaseEntity, public IBreakableWithPropData, public CDefaultPlayerPickupVPhysics +{ +public: + DECLARE_CLASS( CBreakable, CBaseEntity ); + + // basic functions + virtual void Spawn( void ); + void ParsePropData( void ); + bool CreateVPhysics( void ); + virtual void Precache( void ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + + void BreakTouch( CBaseEntity *pOther ); + void DamageSound( void ); + void Break( CBaseEntity *pBreaker ); + + // Input handlers + void InputAddHealth( inputdata_t &inputdata ); + void InputBreak( inputdata_t &inputdata ); + void InputRemoveHealth( inputdata_t &inputdata ); + void InputSetHealth( inputdata_t &inputdata ); + void InputSetMass( inputdata_t &inputdata ); + + + // breakables use an overridden takedamage + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + // To spark when hit + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + bool IsBreakable( void ); + bool SparkWhenHit( void ); + + char const *DamageDecal( int bitsDamageType, int gameMaterial ); + + virtual void Die( void ); + void ResetOnGroundFlags(void); + + inline bool Explodable( void ) { return GetExplosiveRadius() > 0; } + + Materials GetMaterialType( void ) { return m_Material; } + static void MaterialSoundRandom( int entindex, Materials soundMaterial, float volume ); + static const char *MaterialSound( Materials precacheMaterial ); + + static const char *pSpawnObjects[]; + + int DrawDebugTextOverlays(void); + + DECLARE_DATADESC(); + +public: +// IBreakableWithPropData + void SetDmgModBullet( float flDmgMod ) { m_flDmgModBullet = flDmgMod; } + void SetDmgModClub( float flDmgMod ) { m_flDmgModClub = flDmgMod; } + void SetDmgModExplosive( float flDmgMod ) { m_flDmgModExplosive = flDmgMod; } + float GetDmgModBullet( void ) { return m_flDmgModBullet; } + float GetDmgModClub( void ) { return m_flDmgModClub; } + float GetDmgModExplosive( void ) { return m_flDmgModExplosive; } + void SetExplosiveRadius( float flRadius ) { m_explodeRadius = flRadius; } + void SetExplosiveDamage( float flDamage ) { m_ExplosionMagnitude = flDamage; } + float GetExplosiveRadius( void ) { return m_explodeRadius; } + float GetExplosiveDamage( void ) { return m_ExplosionMagnitude; } + void SetPhysicsDamageTable( string_t iszTableName ) { m_iszPhysicsDamageTableName = iszTableName; } + string_t GetPhysicsDamageTable( void ) { return m_iszPhysicsDamageTableName; } + void SetBreakableModel( string_t iszModel ) { m_iszBreakableModel = iszModel; } + string_t GetBreakableModel( void ) { return m_iszBreakableModel; } + void SetBreakableSkin( int iSkin ) { m_iBreakableSkin = iSkin; } + int GetBreakableSkin( void ) { return m_iBreakableSkin; } + void SetBreakableCount( int iCount ) { m_iBreakableCount = iCount; } + int GetBreakableCount( void ) { return m_iBreakableCount; } + void SetMaxBreakableSize( int iSize ) { m_iMaxBreakableSize = iSize; } + int GetMaxBreakableSize( void ) { return m_iMaxBreakableSize; } + void SetPropDataBlocksLOS( bool bBlocksLOS ) { SetBlocksLOS( bBlocksLOS ); } + void SetPropDataIsAIWalkable( bool bBlocksLOS ) { SetAIWalkable( bBlocksLOS ); } + void SetBasePropData( string_t iszBase ) { m_iszBasePropData = iszBase; } + string_t GetBasePropData( void ) { return m_iszBasePropData; } + void SetInteraction( propdata_interactions_t Interaction ) { m_iInteractions |= (1 << Interaction); } + bool HasInteraction( propdata_interactions_t Interaction ) { return ( m_iInteractions & (1 << Interaction) ) != 0; } + void SetPhysicsMode(int iMode){} + int GetPhysicsMode() { return PHYSICS_MULTIPLAYER_SOLID; } + void SetMultiplayerBreakMode( mp_break_t mode ) {} + mp_break_t GetMultiplayerBreakMode( void ) const { return MULTIPLAYER_BREAK_DEFAULT; } + +protected: + float m_angle; + Materials m_Material; + EHANDLE m_hBreaker; // The entity that broke us. Held as a data member because sometimes breaking is delayed. + +private: + + Explosions m_Explosion; + QAngle m_GibDir; + string_t m_iszGibModel; + string_t m_iszSpawnObject; + int m_ExplosionMagnitude; + float m_flPressureDelay; // Delay before breaking when destoyed by pressure + int m_iMinHealthDmg; // minimum damage attacker must have to cause damage + bool m_bTookPhysicsDamage; + + string_t m_iszPropData; + string_t m_iszModelName; + +protected: + + bool UpdateHealth( int iNewHealth, CBaseEntity *pActivator ); + + float m_impactEnergyScale; + + COutputEvent m_OnBreak; + COutputFloat m_OnHealthChanged; + + // Prop data storage + float m_flDmgModBullet; + float m_flDmgModClub; + float m_flDmgModExplosive; + string_t m_iszPhysicsDamageTableName; + string_t m_iszBreakableModel; + int m_iBreakableSkin; + int m_iBreakableCount; + int m_iMaxBreakableSize; + string_t m_iszBasePropData; + int m_iInteractions; + PerformanceMode_t m_PerformanceMode; + + float m_explodeRadius; + +public: + // IPlayerPickupVPhysics + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + virtual CBasePlayer *HasPhysicsAttacker( float dt ); +private: + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; +}; + +#endif // FUNC_BREAK_H diff --git a/game/server/func_breakablesurf.h b/game/server/func_breakablesurf.h new file mode 100644 index 0000000..58e4f0f --- /dev/null +++ b/game/server/func_breakablesurf.h @@ -0,0 +1,102 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_BREAKABLESURF_H +#define FUNC_BREAKABLESURF_H +#ifdef _WIN32 +#pragma once +#endif + + +#define MAX_NUM_PANELS 16 //Must match client + +#include "func_break.h" + +//############################################################################# +// > CWindowPane +// +// A piece that falls out of the window +//############################################################################# +class CWindowPane : public CBaseAnimating +{ +public: + DECLARE_CLASS( CWindowPane, CBaseAnimating ); + + static CWindowPane* CreateWindowPane( const Vector &vecOrigin, const QAngle &vecAngles ); + + void Spawn( void ); + void Precache( void ); + void PaneTouch( CBaseEntity *pOther ); + void Die( void ); + DECLARE_DATADESC(); +}; + +//############################################################################# +// > CBreakableSurface +// +// A breakable surface +//############################################################################# +class CBreakableSurface : public CBreakable +{ + DECLARE_CLASS( CBreakableSurface, CBreakable ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + +public: + CNetworkVar( int, m_nNumWide ); + CNetworkVar( int, m_nNumHigh ); + CNetworkVar( float, m_flPanelWidth ); + CNetworkVar( float, m_flPanelHeight ); + CNetworkVector( m_vNormal ); + CNetworkVector( m_vCorner ); + CNetworkVar( bool, m_bIsBroken ); + CNetworkVar( ShatterSurface_t, m_nSurfaceType ); + int m_nNumBrokenPanes; + float m_flSupport[MAX_NUM_PANELS][MAX_NUM_PANELS]; //UNDONE: allocate dynamically? + + int m_nFragility; + Vector m_vLLVertex; + Vector m_vULVertex; + Vector m_vLRVertex; + Vector m_vURVertex; + int m_nQuadError; + + void SurfaceTouch( CBaseEntity *pOther ); + void PanePos(const Vector &vPos, float *flWidth, float *flHeight); + + bool IsBroken(int nWidth, int nHeight); + void SetSupport(int w, int h, float support); + + float GetSupport(int nWidth, int nHeight); + float RecalcSupport(int nWidth, int nHeight); + + void BreakPane(int nWidth, int nHeight); + void DropPane(int nWidth, int nHeight); + bool ShatterPane(int nWidth, int nHeight, const Vector &force, const Vector &vForcePos); + void BreakAllPanes(void); + + void CreateShards(const Vector &vBreakPos, const QAngle &vAngles, + const Vector &vForce, const Vector &vForcePos, + float flWidth, float flHeight, + int nShardSize); + + void Spawn(void); + void Precache(void); + void Die( CBaseEntity *pBreaker, const Vector &vAttackDir ); + void BreakThink(void); + void Event_Killed( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + int OnTakeDamage( const CTakeDamageInfo &info ); + void InputShatter( inputdata_t &inputdata ); + void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); +private: + // One bit per pane + CNetworkArray( bool, m_RawPanelBitVec, MAX_NUM_PANELS * MAX_NUM_PANELS ); +}; + +#endif // FUNC_BREAKABLESURF_H + diff --git a/game/server/func_movelinear.h b/game/server/func_movelinear.h new file mode 100644 index 0000000..8f09adc --- /dev/null +++ b/game/server/func_movelinear.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_MOVELINEAR_H +#define FUNC_MOVELINEAR_H + +#pragma once + +#include "basetoggle.h" +#include "entityoutput.h" + + +class IPhysicsFluidController; + + +class CFuncMoveLinear : public CBaseToggle +{ +public: + DECLARE_CLASS( CFuncMoveLinear, CBaseToggle ); + + void Spawn( void ); + void Precache( void ); + bool CreateVPhysics( void ); + bool ShouldSavePhysics( void ); + + void MoveTo(Vector vPosition, float flSpeed); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void MoveDone( void ); + void StopMoveSound( void ); + void Blocked( CBaseEntity *pOther ); + void SetPosition( float flPosition ); + + int DrawDebugTextOverlays(void); + + // Input handlers + void InputOpen( inputdata_t &inputdata ); + void InputClose( inputdata_t &inputdata ); + void InputSetPosition( inputdata_t &inputdata ); + void InputSetSpeed( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + + Vector m_vecMoveDir; // Move direction. + + string_t m_soundStart; // start and looping sound + string_t m_soundStop; // stop sound + string_t m_currentSound; // sound I'm playing + + float m_flBlockDamage; // Damage inflicted when blocked. + float m_flStartPosition; // Position of brush when spawned + float m_flMoveDistance; // Total distance the brush can move + + IPhysicsFluidController *m_pFluidController; + + // Outputs + COutputEvent m_OnFullyOpen; + COutputEvent m_OnFullyClosed; +}; +#endif // FUNC_MOVELINEAR_H diff --git a/game/server/functorutils.h b/game/server/functorutils.h new file mode 100644 index 0000000..4816664 --- /dev/null +++ b/game/server/functorutils.h @@ -0,0 +1,450 @@ +// FunctorUtils.h +// Useful functors +//========= Copyright Valve Corporation, All rights reserved. ============// + +#ifndef _FUNCTOR_UTILS_H_ +#define _FUNCTOR_UTILS_H_ + +#ifdef NEXT_BOT +#include "NextBotInterface.h" +#include "NextBotManager.h" +#endif // NEXT_BOT + +//-------------------------------------------------------------------------------------------------------- +/** + * NOTE: The functors in this file should ideally be game-independent, + * and work for any Source based game + */ +//-------------------------------------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------------------------------------- +/** + * Count the number of living players on a given team (or TEAM_ANY) + */ +class LivePlayerCounter +{ +public: + static const bool EXCLUDE_BOTS = false; + LivePlayerCounter( int team, bool includeBots = true ) + { + m_team = team; + m_includeBots = includeBots; + m_count = 0; + } + + bool operator() ( CBasePlayer *player ) + { + if (player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team)) + { + if (m_includeBots || !player->IsBot()) + { + ++m_count; + } + } + return true; + } + + int GetCount( void ) const + { + return m_count; + } + + int m_team; + bool m_includeBots; + int m_count; +}; + + +//-------------------------------------------------------------------------------------------------------- +/** +* Count the number of dead players on a given team (or TEAM_ANY) +*/ +class DeadPlayerCounter +{ +public: + static const bool EXCLUDE_BOTS = false; + DeadPlayerCounter( int team, bool includeBots = true ) + { + m_team = team; + m_includeBots = includeBots; + m_count = 0; + } + + bool operator() ( CBasePlayer *player ) + { + if (!player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team)) + { + if (m_includeBots || !player->IsBot()) + { + ++m_count; + } + } + return true; + } + + int GetCount( void ) const + { + return m_count; + } + + int m_team; + bool m_includeBots; + int m_count; +}; + + +//-------------------------------------------------------------------------------------------------------- +/** +* Count the number of players on a given team (or TEAM_ANY) +*/ +class PlayerCounter +{ +public: + static const bool EXCLUDE_BOTS = false; + PlayerCounter( int team, int lifeState = -1, bool includeBots = true ) + { + m_team = team; + m_includeBots = includeBots; + m_count = 0; + m_lifeState = lifeState; + } + + bool operator() ( CBasePlayer *player ) + { + if ((player->m_lifeState == m_lifeState || m_lifeState == -1) && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team)) + { + if (m_includeBots || !player->IsBot()) + { + ++m_count; + } + } + return true; + } + + int GetCount( void ) const + { + return m_count; + } + + int m_lifeState; + int m_team; + bool m_includeBots; + int m_count; +}; + + +//-------------------------------------------------------------------------------------------------------- +/** + * Return the closest living player on the given team (or TEAM_ANY) + */ +class ClosestPlayerScan +{ +public: + static const bool EXCLUDE_BOTS = false; + ClosestPlayerScan( const Vector &spot, int team, float maxRange = 0.0f, CBasePlayer *ignore = NULL, bool includeBots = true ) + { + m_spot = spot; + m_team = team; + m_includeBots = includeBots; + m_close = NULL; + + if ( maxRange > 0.0f ) + { + m_closeRangeSq = maxRange * maxRange; + } + else + { + m_closeRangeSq = 999999999.9f; + } + + m_ignore = ignore; + } + + bool operator() ( CBasePlayer *player ) + { + if (player == m_ignore) + return true; + + if (player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team)) + { + if ( !m_includeBots && player->IsBot() ) + return true; + + Vector to = player->WorldSpaceCenter() - m_spot; + float rangeSq = to.LengthSqr(); + if (rangeSq < m_closeRangeSq) + { + m_closeRangeSq = rangeSq; + m_close = player; + } + } + return true; + } + + CBasePlayer *GetPlayer( void ) const + { + return m_close; + } + + bool IsCloserThan( float range ) + { + return (m_closeRangeSq < (range * range)); + } + + bool IsFartherThan( float range ) + { + return (m_closeRangeSq > (range * range)); + } + + Vector m_spot; + int m_team; + bool m_includeBots; + CBasePlayer *m_close; + float m_closeRangeSq; + CBasePlayer *m_ignore; +}; + + +//-------------------------------------------------------------------------------------------------------- +/** +* Return the closest living BaseCombatCharacter on the given team (or TEAM_ANY) +*/ +class ClosestActorScan +{ +public: + ClosestActorScan( const Vector &spot, int team, float maxRange = 0.0f, CBaseCombatCharacter *ignore = NULL ) + { + m_spot = spot; + m_team = team; + m_close = NULL; + + if ( maxRange > 0.0f ) + { + m_closeRangeSq = maxRange * maxRange; + } + else + { + m_closeRangeSq = 999999999.9f; + } + + m_ignore = ignore; + } + + bool operator() ( CBaseCombatCharacter *actor ) + { + if (actor == m_ignore) + return true; + + if (actor->IsAlive() && (m_team == TEAM_ANY || actor->GetTeamNumber() == m_team)) + { + Vector to = actor->WorldSpaceCenter() - m_spot; + float rangeSq = to.LengthSqr(); + if (rangeSq < m_closeRangeSq) + { + m_closeRangeSq = rangeSq; + m_close = actor; + } + } + return true; + } + + CBaseCombatCharacter *GetClosestActor( void ) const + { + return m_close; + } + + bool IsClosestActorCloserThan( float range ) + { + return (m_closeRangeSq < (range * range)); + } + + bool IsClosestActorFartherThan( float range ) + { + return (m_closeRangeSq > (range * range)); + } + + Vector m_spot; + int m_team; + CBaseCombatCharacter *m_close; + float m_closeRangeSq; + CBaseCombatCharacter *m_ignore; +}; + + +//-------------------------------------------------------------------------------------------------------- +class CShowViewportPanel +{ + int m_team; + const char *m_panelName; + bool m_show; + KeyValues *m_data; + +public: + CShowViewportPanel( int team, const char *panelName, bool show, KeyValues *data = NULL ) + { + m_team = team; + m_panelName = panelName; + m_show = show; + m_data = data; + } + + bool operator() ( CBasePlayer *player ) + { + if ( m_team != TEAM_ANY && m_team != player->GetTeamNumber() ) + return true; + + player->ShowViewPortPanel( m_panelName, m_show, m_data ); + return true; + } +}; + +//-------------------------------------------------------------------------------------------------------------- +/** + * Iterate each "actor" in the game, where an actor is a Player or NextBot + */ +template < typename Functor > +inline bool ForEachActor( Functor &func ) +{ + // iterate all non-bot players + for( int i=1; i<=gpGlobals->maxClients; ++i ) + { + CBasePlayer *player = UTIL_PlayerByIndex( i ); + + if ( player == NULL ) + continue; + + if ( FNullEnt( player->edict() ) ) + continue; + + if ( !player->IsPlayer() ) + continue; + + if ( !player->IsConnected() ) + continue; + +#ifdef NEXT_BOT + // skip bots - ForEachCombatCharacter will catch them + INextBot *bot = player->MyNextBotPointer(); + if ( bot ) + { + continue; + } +#endif // NEXT_BOT + + if ( func( player ) == false ) + { + return false; + } + } + +#ifdef NEXT_BOT + // iterate all NextBots + return TheNextBots().ForEachCombatCharacter( func ); +#else + return true; +#endif // NEXT_BOT +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * The interface for functors for use with ForEachActor() that + * want notification before iteration starts and after interation + * is complete (successful or not). + */ +class IActorFunctor +{ +public: + virtual void OnBeginIteration( void ) { } // invoked once before iteration begins + + virtual bool operator() ( CBaseCombatCharacter *them ) = 0; + + virtual void OnEndIteration( bool allElementsIterated ) { } // invoked once after iteration is complete whether successful or not +}; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Iterate each "actor" in the game, where an actor is a Player or NextBot + * Template specialization for IActorFunctors. + */ +template <> +inline bool ForEachActor( IActorFunctor &func ) +{ + func.OnBeginIteration(); + + bool isComplete = true; + + // iterate all non-bot players + for( int i=1; i<=gpGlobals->maxClients; ++i ) + { + CBasePlayer *player = UTIL_PlayerByIndex( i ); + + if ( player == NULL ) + continue; + + if ( FNullEnt( player->edict() ) ) + continue; + + if ( !player->IsPlayer() ) + continue; + + if ( !player->IsConnected() ) + continue; + +#ifdef NEXT_BOT + // skip bots - ForEachCombatCharacter will catch them + INextBot *bot = dynamic_cast< INextBot * >( player ); + if ( bot ) + { + continue; + } +#endif // NEXT_BOT + + if ( func( player ) == false ) + { + isComplete = false; + break; + } + } + +#ifdef NEXT_BOT + if ( !isComplete ) + { + // iterate all NextBots + isComplete = TheNextBots().ForEachCombatCharacter( func ); + } +#endif // NEXT_BOT + + func.OnEndIteration( isComplete ); + + return isComplete; +} + + +//-------------------------------------------------------------------------------------------------------- +class CTraceFilterOnlyClassname : public CTraceFilterSimple +{ +public: + CTraceFilterOnlyClassname( const IHandleEntity *passentity, const char *pchClassname, int collisionGroup ) : + CTraceFilterSimple( passentity, collisionGroup ), m_pchClassname( pchClassname ) + { + } + + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ) + { + CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity ); + if ( !pEntity ) + return false; + + return FClassnameIs( pEntity, m_pchClassname ) && CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask ); + } + +private: + + const char *m_pchClassname; +}; + + +#endif // _FUNCTOR_UTILS_H_ diff --git a/game/server/game.h b/game/server/game.h new file mode 100644 index 0000000..3377baa --- /dev/null +++ b/game/server/game.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef GAME_H +#define GAME_H + + +#include "globals.h" + +extern void GameDLLInit( void ); + +extern ConVar displaysoundlist; +extern ConVar mapcyclefile; +extern ConVar servercfgfile; +extern ConVar lservercfgfile; + +// multiplayer server rules +extern ConVar teamplay; +extern ConVar fraglimit; +extern ConVar falldamage; +extern ConVar weaponstay; +extern ConVar forcerespawn; +extern ConVar footsteps; +extern ConVar flashlight; +extern ConVar aimcrosshair; +extern ConVar decalfrequency; +extern ConVar teamlist; +extern ConVar teamoverride; +extern ConVar defaultteam; +extern ConVar allowNPCs; + +extern ConVar suitvolume; + +// Engine Cvars +extern const ConVar *g_pDeveloper; +#endif // GAME_H diff --git a/game/server/gameinterface.h b/game/server/gameinterface.h new file mode 100644 index 0000000..3092d4f --- /dev/null +++ b/game/server/gameinterface.h @@ -0,0 +1,228 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Expose things from GameInterface.cpp. Mostly the engine interfaces. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GAMEINTERFACE_H +#define GAMEINTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mapentities.h" + +class IReplayFactory; + +extern INetworkStringTable *g_pStringTableInfoPanel; +extern INetworkStringTable *g_pStringTableServerMapCycle; + +#ifdef TF_DLL +extern INetworkStringTable *g_pStringTableServerPopFiles; +#endif + +// Player / Client related functions +// Most of this is implemented in gameinterface.cpp, but some of it is per-mod in files like cs_gameinterface.cpp, etc. +class CServerGameClients : public IServerGameClients +{ +public: + virtual bool ClientConnect( edict_t *pEntity, char const* pszName, char const* pszAddress, char *reject, int maxrejectlen ) OVERRIDE; + virtual void ClientActive( edict_t *pEntity, bool bLoadGame ) OVERRIDE; + virtual void ClientDisconnect( edict_t *pEntity ) OVERRIDE; + virtual void ClientPutInServer( edict_t *pEntity, const char *playername ) OVERRIDE; + virtual void ClientCommand( edict_t *pEntity, const CCommand &args ) OVERRIDE; + virtual void ClientSettingsChanged( edict_t *pEntity ) OVERRIDE; + virtual void ClientSetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char *pvs, int pvssize ) OVERRIDE; + virtual float ProcessUsercmds( edict_t *player, bf_read *buf, int numcmds, int totalcmds, + int dropped_packets, bool ignore, bool paused ) OVERRIDE; + // Player is running a command + virtual void PostClientMessagesSent_DEPRECIATED( void ) OVERRIDE; + virtual void SetCommandClient( int index ) OVERRIDE; + virtual CPlayerState *GetPlayerState( edict_t *player ) OVERRIDE; + virtual void ClientEarPosition( edict_t *pEntity, Vector *pEarOrigin ) OVERRIDE; + + virtual void GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const OVERRIDE; + + // returns number of delay ticks if player is in Replay mode (0 = no delay) + virtual int GetReplayDelay( edict_t *player, int& entity ) OVERRIDE; + // Anything this game .dll wants to add to the bug reporter text (e.g., the entity/model under the picker crosshair) + // can be added here + virtual void GetBugReportInfo( char *buf, int buflen ) OVERRIDE; + virtual void NetworkIDValidated( const char *pszUserName, const char *pszNetworkID ) OVERRIDE; + + // The client has submitted a keyvalues command + virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ) OVERRIDE; + + // Notify that the player is spawned + virtual void ClientSpawned( edict_t *pPlayer ) OVERRIDE; +}; + + +class CServerGameDLL : public IServerGameDLL +{ +public: + virtual bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, + CreateInterfaceFn fileSystemFactory, CGlobalVars *pGlobals) OVERRIDE; + virtual void DLLShutdown( void ) OVERRIDE; + // Get the simulation interval (must be compiled with identical values into both client and game .dll for MOD!!!) + virtual bool ReplayInit( CreateInterfaceFn fnReplayFactory ) OVERRIDE; + virtual float GetTickInterval( void ) const OVERRIDE; + virtual bool GameInit( void ) OVERRIDE; + virtual void GameShutdown( void ) OVERRIDE; + virtual bool LevelInit( const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background ) OVERRIDE; + virtual void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) OVERRIDE; + virtual void LevelShutdown( void ) OVERRIDE; + virtual void GameFrame( bool simulating ) OVERRIDE; // could be called multiple times before sending data to clients + virtual void PreClientUpdate( bool simulating ) OVERRIDE; // called after all GameFrame() calls, before sending data to clients + + virtual ServerClass* GetAllServerClasses( void ) OVERRIDE; + virtual const char *GetGameDescription( void ) OVERRIDE; + virtual void CreateNetworkStringTables( void ) OVERRIDE; + + // Save/restore system hooks + virtual CSaveRestoreData *SaveInit( int size ) OVERRIDE; + virtual void SaveWriteFields( CSaveRestoreData *, char const* , void *, datamap_t *, typedescription_t *, int ) OVERRIDE; + virtual void SaveReadFields( CSaveRestoreData *, char const* , void *, datamap_t *, typedescription_t *, int ) OVERRIDE; + virtual void SaveGlobalState( CSaveRestoreData * ) OVERRIDE; + virtual void RestoreGlobalState( CSaveRestoreData * ) OVERRIDE; + virtual int CreateEntityTransitionList( CSaveRestoreData *, int ) OVERRIDE; + virtual void BuildAdjacentMapList( void ) OVERRIDE; + + virtual void PreSave( CSaveRestoreData * ) OVERRIDE; + virtual void Save( CSaveRestoreData * ) OVERRIDE; + virtual void GetSaveComment( char *comment, int maxlength, float flMinutes, float flSeconds, bool bNoTime = false ) OVERRIDE; +#ifdef _XBOX + virtual void GetTitleName( const char *pMapName, char* pTitleBuff, int titleBuffSize ) OVERRIDE; +#endif + virtual void WriteSaveHeaders( CSaveRestoreData * ) OVERRIDE; + + virtual void ReadRestoreHeaders( CSaveRestoreData * ) OVERRIDE; + virtual void Restore( CSaveRestoreData *, bool ) OVERRIDE; + virtual bool IsRestoring() OVERRIDE; + + // Retrieve info needed for parsing the specified user message + virtual bool GetUserMessageInfo( int msg_type, char *name, int maxnamelength, int& size ) OVERRIDE; + + virtual CStandardSendProxies* GetStandardSendProxies() OVERRIDE; + + virtual void PostInit() OVERRIDE; + virtual void Think( bool finalTick ) OVERRIDE; + + virtual void OnQueryCvarValueFinished( QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue ) OVERRIDE; + + virtual void PreSaveGameLoaded( char const *pSaveName, bool bInGame ) OVERRIDE; + + // Returns true if the game DLL wants the server not to be made public. + // Used by commentary system to hide multiplayer commentary servers from the master. + virtual bool ShouldHideServer( void ) OVERRIDE; + + virtual void InvalidateMdlCache() OVERRIDE; + + virtual void SetServerHibernation( bool bHibernating ) OVERRIDE; + + float m_fAutoSaveDangerousTime; + float m_fAutoSaveDangerousMinHealthToCommit; + bool m_bIsHibernating; + + // Called after the steam API has been activated post-level startup + virtual void GameServerSteamAPIActivated( void ) OVERRIDE; + + // Called after the steam API has been shutdown post-level startup + virtual void GameServerSteamAPIShutdown( void ) OVERRIDE; + + // interface to the new GC based lobby system + virtual IServerGCLobby *GetServerGCLobby() OVERRIDE; + + virtual const char *GetServerBrowserMapOverride() OVERRIDE; + virtual const char *GetServerBrowserGameData() OVERRIDE; + + // Called to add output to the status command + virtual void Status( void (*print) (const char *fmt, ...) ) OVERRIDE; + + virtual void PrepareLevelResources( /* in/out */ char *pszMapName, size_t nMapNameSize, + /* in/out */ char *pszMapFile, size_t nMapFileSize ) OVERRIDE; + + virtual ePrepareLevelResourcesResult AsyncPrepareLevelResources( /* in/out */ char *pszMapName, size_t nMapNameSize, + /* in/out */ char *pszMapFile, size_t nMapFileSize, + float *flProgress = NULL ) OVERRIDE; + + virtual eCanProvideLevelResult CanProvideLevel( /* in/out */ char *pMapName, int nMapNameMax ) OVERRIDE; + + // Called to see if the game server is okay with a manual changelevel or map command + virtual bool IsManualMapChangeOkay( const char **pszReason ) OVERRIDE; + +private: + + // This can just be a wrapper on MapEntity_ParseAllEntities, but CS does some tricks in here + // with the entity list. + void LevelInit_ParseAllEntities( const char *pMapEntities ); + void LoadMessageOfTheDay(); + void LoadSpecificMOTDMsg( const ConVar &convar, const char *pszStringName ); +}; + + +// Normally, when the engine calls ClientPutInServer, it calls a global function in the game DLL +// by the same name. Use this to override the function that it calls. This is used for bots. +typedef CBasePlayer* (*ClientPutInServerOverrideFn)( edict_t *pEdict, const char *playername ); + +void ClientPutInServerOverride( ClientPutInServerOverrideFn fn ); + +// -------------------------------------------------------------------------------------------- // +// Entity list management stuff. +// -------------------------------------------------------------------------------------------- // +// These are created for map entities in order as the map entities are spawned. +class CMapEntityRef +{ +public: + int m_iEdict; // Which edict slot this entity got. -1 if CreateEntityByName failed. + int m_iSerialNumber; // The edict serial number. TODO used anywhere ? +}; + +extern CUtlLinkedList g_MapEntityRefs; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CMapLoadEntityFilter : public IMapEntityFilter +{ +public: + virtual bool ShouldCreateEntity( const char *pClassname ) + { + // During map load, create all the entities. + return true; + } + + virtual CBaseEntity* CreateNextEntity( const char *pClassname ) + { + CBaseEntity *pRet = CreateEntityByName( pClassname ); + + CMapEntityRef ref; + ref.m_iEdict = -1; + ref.m_iSerialNumber = -1; + + if ( pRet ) + { + ref.m_iEdict = pRet->entindex(); + if ( pRet->edict() ) + ref.m_iSerialNumber = pRet->edict()->m_NetworkSerialNumber; + } + + g_MapEntityRefs.AddToTail( ref ); + return pRet; + } +}; + +bool IsEngineThreaded(); + +class CServerGameTags : public IServerGameTags +{ +public: + virtual void GetTaggedConVarList( KeyValues *pCvarTagList ); + +}; +EXPOSE_SINGLE_INTERFACE( CServerGameTags, IServerGameTags, INTERFACEVERSION_SERVERGAMETAGS ); + +#endif // GAMEINTERFACE_H + diff --git a/game/server/gameweaponmanager.h b/game/server/gameweaponmanager.h new file mode 100644 index 0000000..3179914 --- /dev/null +++ b/game/server/gameweaponmanager.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef GAMEWEAPONMANAGER_H +#define GAMEWEAPONMANAGER_H + +#if defined( _WIN32 ) +#pragma once +#endif + +void CreateWeaponManager( const char *pWeaponName, int iMaxPieces ); + +class CBaseCombatWeapon; + +void WeaponManager_AmmoMod( CBaseCombatWeapon *pWeapon ); + +void WeaponManager_AddManaged( CBaseEntity *pWeapon ); +void WeaponManager_RemoveManaged( CBaseEntity *pWeapon ); + +#endif // GAMEWEAPONMANAGER_H diff --git a/game/server/gib.h b/game/server/gib.h new file mode 100644 index 0000000..57d5630 --- /dev/null +++ b/game/server/gib.h @@ -0,0 +1,115 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A gib is a chunk of a body, or a piece of wood/metal/rocks/etc. +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef GIB_H +#define GIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "baseanimating.h" +#include "player_pickup.h" +#include "Sprite.h" + +extern CBaseEntity *CreateRagGib( const char *szModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecForce, float flFadeTime = 0.0, bool bShouldIgnite = false ); + +#define GERMAN_GIB_COUNT 4 +#define HUMAN_GIB_COUNT 6 +#define ALIEN_GIB_COUNT 4 + +enum GibType_e +{ + GIB_HUMAN, + GIB_ALIEN, +}; + +class CGib : public CBaseAnimating, + public CDefaultPlayerPickupVPhysics +{ +public: + DECLARE_CLASS( CGib, CBaseAnimating ); + + void Spawn( const char *szGibModel ); + void Spawn( const char *szGibModel, float flLifetime ); + + void InitGib( CBaseEntity *pVictim, float fMaxVelocity, float fMinVelocity ); + void BounceGibTouch ( CBaseEntity *pOther ); + void StickyGibTouch ( CBaseEntity *pOther ); + void WaitTillLand( void ); + void DieThink( void ); + void LimitVelocity( void ); + virtual bool SUB_AllowedToFade( void ); + + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE | FCAP_IMPULSE_USE; } + static void SpawnHeadGib( CBaseEntity *pVictim ); + static void SpawnRandomGibs( CBaseEntity *pVictim, int cGibs, GibType_e eGibType ); + static void SpawnStickyGibs( CBaseEntity *pVictim, Vector vecOrigin, int cGibs ); + static void SpawnSpecificGibs( CBaseEntity *pVictim, int nNumGibs, float fMaxVelocity, float fMinVelocity, const char* cModelName, float flLifetime = 25); + + void SetPhysicsAttacker( CBasePlayer *pEntity, float flTime ); + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); + virtual CBasePlayer *HasPhysicsAttacker( float dt ); + + void SetSprite( CBaseEntity *pSprite ) + { + m_hSprite = pSprite; + } + + CBaseEntity *GetSprite( void ) + { + return m_hSprite.Get(); + } + + void SetFlame( CBaseEntity *pFlame ) + { + m_hFlame = pFlame; + } + + CBaseEntity *GetFlame( void ) + { + return m_hFlame.Get(); + } + + DECLARE_DATADESC(); + + +public: + void SetBloodColor( int nBloodColor ); + + int m_cBloodDecals; + int m_material; + float m_lifeTime; + bool m_bForceRemove; + + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + +private: + // A little piece of duplicated code + void AdjustVelocityBasedOnHealth( int nHealth, Vector &vecVelocity ); + int m_bloodColor; + + EHANDLE m_hSprite; + EHANDLE m_hFlame; +}; + +class CRagGib : public CBaseAnimating +{ +public: + DECLARE_CLASS( CRagGib, CBaseAnimating ); + + void Spawn( const char *szModel, const Vector &vecOrigin, const Vector &vecForce, float flFadeTime ); +}; + + +#endif //GIB_H diff --git a/game/server/globals.h b/game/server/globals.h new file mode 100644 index 0000000..03076e3 --- /dev/null +++ b/game/server/globals.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GLOBALS_H +#define GLOBALS_H +#ifdef _WIN32 +#pragma once +#endif + + +extern Vector g_vecAttackDir; +extern int g_iSkillLevel; +extern bool g_fGameOver; +extern ConVar g_Language; + + +#endif // GLOBALS_H diff --git a/game/server/globalstate.h b/game/server/globalstate.h new file mode 100644 index 0000000..ff9d4b3 --- /dev/null +++ b/game/server/globalstate.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GLOBALSTATE_H +#define GLOBALSTATE_H +#ifdef _WIN32 +#pragma once +#endif + +typedef enum { GLOBAL_OFF = 0, GLOBAL_ON = 1, GLOBAL_DEAD = 2 } GLOBALESTATE; + +void GlobalEntity_SetState( int globalIndex, GLOBALESTATE state ); +void GlobalEntity_SetMap( int globalIndex, string_t mapname ); +int GlobalEntity_Add( const char *pGlobalname, const char *pMapName, GLOBALESTATE state ); + +int GlobalEntity_GetIndex( const char *pGlobalname ); +GLOBALESTATE GlobalEntity_GetState( int globalIndex ); +const char *GlobalEntity_GetMap( int globalIndex ); +const char *GlobalEntity_GetName( int globalIndex ); + +int GlobalEntity_GetCounter( int globalIndex ); +void GlobalEntity_SetCounter( int globalIndex, int counter ); +int GlobalEntity_AddToCounter( int globalIndex, int delta ); + +int GlobalEntity_GetNumGlobals( void ); +void GlobalEntity_EnableStateUpdates( bool bEnable ); + +inline int GlobalEntity_Add( string_t globalname, string_t mapName, GLOBALESTATE state ) +{ + return GlobalEntity_Add( STRING(globalname), STRING(mapName), state ); +} + +inline int GlobalEntity_GetIndex( string_t globalname ) +{ + return GlobalEntity_GetIndex( STRING(globalname) ); +} + +inline int GlobalEntity_IsInTable( string_t globalname ) +{ + return GlobalEntity_GetIndex( STRING(globalname) ) >= 0 ? true : false; +} + +inline int GlobalEntity_IsInTable( const char *pGlobalname ) +{ + return GlobalEntity_GetIndex( pGlobalname ) >= 0 ? true : false; +} + +inline void GlobalEntity_SetState( string_t globalname, GLOBALESTATE state ) +{ + GlobalEntity_SetState( GlobalEntity_GetIndex( globalname ), state ); +} + +inline void GlobalEntity_SetMap( string_t globalname, string_t mapname ) +{ + GlobalEntity_SetMap( GlobalEntity_GetIndex( globalname ), mapname ); +} + +inline GLOBALESTATE GlobalEntity_GetState( string_t globalname ) +{ + return GlobalEntity_GetState( GlobalEntity_GetIndex( globalname ) ); +} + +inline GLOBALESTATE GlobalEntity_GetState( const char *pGlobalName ) +{ + return GlobalEntity_GetState( GlobalEntity_GetIndex( pGlobalName ) ); +} + +inline int GlobalEntity_GetCounter( string_t globalname ) +{ + return GlobalEntity_GetCounter( GlobalEntity_GetIndex( globalname ) ); +} + +inline int GlobalEntity_GetCounter( const char *pGlobalName ) +{ + return GlobalEntity_GetCounter( GlobalEntity_GetIndex( pGlobalName ) ); +} + +inline void GlobalEntity_SetCounter( string_t globalname, int counter ) +{ + GlobalEntity_SetCounter( GlobalEntity_GetIndex( globalname ), counter ); +} + +inline void GlobalEntity_SetCounter( const char *pGlobalName, int counter ) +{ + GlobalEntity_SetCounter( GlobalEntity_GetIndex( pGlobalName ), counter ); +} + +inline int GlobalEntity_AddToCounter( string_t globalname, int delta ) +{ + return GlobalEntity_AddToCounter( GlobalEntity_GetIndex( globalname ), delta ); +} + +inline int GlobalEntity_AddToCounter( const char *pGlobalName, int delta ) +{ + return GlobalEntity_AddToCounter( GlobalEntity_GetIndex( pGlobalName ), delta ); +} + +inline GLOBALESTATE GlobalEntity_GetStateByIndex( int iIndex ) +{ + return GlobalEntity_GetState( iIndex ); +} + +void ResetGlobalState( void ); + +#endif // GLOBALSTATE_H diff --git a/game/server/globalstate_private.h b/game/server/globalstate_private.h new file mode 100644 index 0000000..fb3f8f9 --- /dev/null +++ b/game/server/globalstate_private.h @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GLOBALSTATE_PRIVATE_H +#define GLOBALSTATE_PRIVATE_H +#ifdef _WIN32 +#pragma once +#endif + + +#endif // GLOBALSTATE_PRIVATE_H diff --git a/game/server/grenadethrown.h b/game/server/grenadethrown.h new file mode 100644 index 0000000..361f13f --- /dev/null +++ b/game/server/grenadethrown.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Header file for player-thrown grenades. +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADE_BASE_H +#define GRENADE_BASE_H +#pragma once + +#include "basegrenade_shared.h" + +class CSprite; + +#define GRENADE_TIMER 5 // Try 5 seconds instead of 3? + +//----------------------------------------------------------------------------- +// Purpose: Base Thrown-Grenade class +//----------------------------------------------------------------------------- +class CThrownGrenade : public CBaseGrenade +{ +public: + DECLARE_CLASS( CThrownGrenade, CBaseGrenade ); + + void Spawn( void ); + void Thrown( Vector vecOrigin, Vector vecVelocity, float flExplodeTime ); +}; + + + +#endif // GRENADE_BASE_H diff --git a/game/server/h_cycler.h b/game/server/h_cycler.h new file mode 100644 index 0000000..2bc7a2a --- /dev/null +++ b/game/server/h_cycler.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef H_CYCLER_H +#define H_CYCLER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCycler : public CAI_BaseNPC +{ +public: + DECLARE_CLASS( CCycler, CAI_BaseNPC ); + + void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax); + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE); } + int OnTakeDamage( const CTakeDamageInfo &info ); + void Spawn( void ); + void Precache( void ); + void Think( void ); + //void Pain( float flDamage ); + void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + // Don't treat as a live target + virtual bool IsAlive( void ) { return false; } + + // Inputs + void InputSetSequence( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + + int m_animate; +}; + +#endif // H_CYCLER_H diff --git a/game/server/hierarchy.h b/game/server/hierarchy.h new file mode 100644 index 0000000..874f5ad --- /dev/null +++ b/game/server/hierarchy.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains the set of functions for manipulating entity hierarchies. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HIERARCHY_H +#define HIERARCHY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +class CBaseEntity; + +void UnlinkFromParent( CBaseEntity *pRemove ); +void TransferChildren( CBaseEntity *pOldParent, CBaseEntity *pNewParent ); +void LinkChild( CBaseEntity *pParent, CBaseEntity *pChild ); +void UnlinkAllChildren( CBaseEntity *pParent ); +int GetAllChildren( CBaseEntity *pParent, CUtlVector &list ); +bool EntityIsParentOf( CBaseEntity *pParent, CBaseEntity *pEntity ); +int GetAllInHierarchy( CBaseEntity *pParent, CUtlVector &list ); + +#endif // HIERARCHY_H diff --git a/game/server/hl1_CBaseHelicopter.h b/game/server/hl1_CBaseHelicopter.h new file mode 100644 index 0000000..0158612 --- /dev/null +++ b/game/server/hl1_CBaseHelicopter.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +//--------------------------------------------------------- +// Helicopter flags +//--------------------------------------------------------- +enum HelicopterFlags_t +{ + BITS_HELICOPTER_GUN_ON = 0x00000001, // Gun is on and aiming + BITS_HELICOPTER_MISSILE_ON = 0x00000002, // Missile turrets are on and aiming +}; + + +//--------------------------------------------------------- +//--------------------------------------------------------- + +#define SF_NOWRECKAGE 0x08 +#define SF_NOROTORWASH 0x20 +#define SF_AWAITINPUT 0x40 + + +//--------------------------------------------------------- +//--------------------------------------------------------- +#define BASECHOPPER_MAX_SPEED 400.0f +#define BASECHOPPER_MAX_FIRING_SPEED 250.0f +#define BASECHOPPER_MIN_ROCKET_DIST 1000.0f +#define BASECHOPPER_MAX_GUN_DIST 2000.0f + + +//========================================================= +//========================================================= +class CBaseHelicopter : public CAI_BaseNPC +{ +public: + DECLARE_CLASS( CBaseHelicopter, CAI_BaseNPC ); + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + void Spawn( void ); + void Precache( void ); + + void Event_Killed( const CTakeDamageInfo &info ); + void StopLoopingSounds(); + + int BloodColor( void ) { return DONT_BLEED; } + void GibMonster( void ); + + Class_T Classify ( void ) { return CLASS_HUMAN_MILITARY; } + + void CallDyingThink( void ) { DyingThink(); } + + bool HasEnemy( void ) { return GetEnemy() != NULL; } + void CheckEnemy( CBaseEntity *pEnemy ); + virtual bool ChooseEnemy( void ); + virtual void HelicopterThink( void ); + virtual void HelicopterPostThink( void ) { }; + virtual void FlyTouch( CBaseEntity *pOther ); + virtual void CrashTouch( CBaseEntity *pOther ); + virtual void DyingThink( void ); + virtual void Startup( void ); + virtual void NullThink( void ); + + virtual void Flight( void ); + + virtual void ShowDamage( void ) {}; + + virtual void FlyPathCorners( void ); + void UpdatePlayerDopplerShift( void ); + + virtual void Hunt( void ); + + virtual bool IsCrashing( void ) { return m_lifeState != LIFE_ALIVE; } + virtual float GetAcceleration( void ) { return 5; } + virtual bool HasReachedTarget( void ); + virtual void OnReachedTarget( CBaseEntity *pTarget ) {}; + + virtual void ApplySidewaysDrag( const Vector &vecRight ); + virtual void ApplyGeneralDrag( void ); + + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + virtual bool FireGun( void ); + + virtual float GetRotorVolume( void ) { return 1.0; } + virtual void InitializeRotorSound( void ); + virtual void UpdateRotorSoundPitch( int iPitch ); + + virtual void AimRocketGun(void) {}; + virtual void FireRocket( Vector vLaunchPos, Vector vLaunchDir ) {}; + + void DrawDebugGeometryOverlays(void); + + CSoundPatch *m_pRotorSound; + + float m_flForce; + int m_fHelicopterFlags; + + Vector m_vecDesiredFaceDir; + Vector m_vecDesiredPosition; + + Vector m_vecGoalOrientation; // orientation of the goal entity. + + float m_flLastSeen; + float m_flPrevSeen; + + int m_iSoundState; // don't save this + + Vector m_vecTarget; + Vector m_vecTargetPosition; + + float m_flMaxSpeed; // Maximum speed of the helicopter. + float m_flMaxSpeedFiring; // Maximum speed of the helicopter whilst firing guns. + + float m_flGoalSpeed; // Goal speed + float m_flInitialSpeed; + float m_angleVelocity; + + void ChangePathCorner( const char *pszName ); + + // Inputs + void InputChangePathCorner( inputdata_t &inputdata ); + void InputActivate( inputdata_t &inputdata ); + + // Outputs + COutputEvent m_AtTarget; // Fired when pathcorner has been reached + COutputEvent m_LeaveTarget; // Fired when pathcorner is left + + float m_flNextCrashExplosion; +}; \ No newline at end of file diff --git a/game/server/hl2/ai_behavior_actbusy.h b/game/server/hl2/ai_behavior_actbusy.h new file mode 100644 index 0000000..750b600 --- /dev/null +++ b/game/server/hl2/ai_behavior_actbusy.h @@ -0,0 +1,318 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_ACTBUSY_H +#define AI_BEHAVIOR_ACTBUSY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior.h" +#include "ai_goalentity.h" + +//----------------------------------------------------------------------------- +enum +{ + ACTBUSY_TYPE_DEFAULT = 0, + ACTBUSY_TYPE_COMBAT, +}; + +enum busyinterrupt_t +{ + BA_INT_NONE, // Nothing breaks us out of this + BA_INT_DANGER, // Only danger signals interrupts this busy anim. The player will be ignored. + BA_INT_PLAYER, // The Player's presence interrupts this busy anim + BA_INT_AMBUSH, // We're waiting to ambush enemies. Don't break on danger sounds in front of us. + BA_INT_COMBAT, // Only break out if we're shot at. + BA_INT_ZOMBIESLUMP, // Zombies who are slumped on the ground. + BA_INT_SIEGE_DEFENSE, +}; + +enum busyanimparts_t +{ + BA_BUSY, + BA_ENTRY, + BA_EXIT, + + BA_MAX_ANIMS, +}; + +struct busyanim_t +{ + string_t iszName; + Activity iActivities[BA_MAX_ANIMS]; + string_t iszSequences[BA_MAX_ANIMS]; + string_t iszSounds[BA_MAX_ANIMS]; + float flMinTime; // Min time spent in this busy animation + float flMaxTime; // Max time spent in this busy animation. 0 means continue until interrupted. + busyinterrupt_t iBusyInterruptType; + bool bUseAutomovement; +}; + +struct busysafezone_t +{ + Vector vecMins; + Vector vecMaxs; +}; + +#define NO_MAX_TIME -1 + +class CAI_ActBusyGoal; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAI_ActBusyBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_ActBusyBehavior, CAI_SimpleBehavior ); +public: + DECLARE_DATADESC(); + CAI_ActBusyBehavior(); + + enum + { + // Schedules + SCHED_ACTBUSY_START_BUSYING = BaseClass::NEXT_SCHEDULE, + SCHED_ACTBUSY_BUSY, + SCHED_ACTBUSY_STOP_BUSYING, + SCHED_ACTBUSY_LEAVE, + SCHED_ACTBUSY_TELEPORT_TO_BUSY, + NEXT_SCHEDULE, + + // Tasks + TASK_ACTBUSY_PLAY_BUSY_ANIM = BaseClass::NEXT_TASK, + TASK_ACTBUSY_PLAY_ENTRY, + TASK_ACTBUSY_PLAY_EXIT, + TASK_ACTBUSY_TELEPORT_TO_BUSY, + TASK_ACTBUSY_WALK_PATH_TO_BUSY, + TASK_ACTBUSY_GET_PATH_TO_ACTBUSY, + TASK_ACTBUSY_VERIFY_EXIT, + NEXT_TASK, + + // Conditions + COND_ACTBUSY_LOST_SEE_ENTITY = BaseClass::NEXT_CONDITION, + COND_ACTBUSY_AWARE_OF_ENEMY_IN_SAFE_ZONE, + COND_ACTBUSY_ENEMY_TOO_CLOSE, + NEXT_CONDITION, + }; + + virtual const char *GetName() { return "ActBusy"; } + + void Enable( CAI_ActBusyGoal *pGoal, float flRange, bool bVisibleOnly ); + void OnRestore(); + void SetBusySearchRange( float flRange ); + void Disable( void ); + void ForceActBusy( CAI_ActBusyGoal *pGoal, CAI_Hint *pHintNode = NULL, float flMaxTime = NO_MAX_TIME, bool bVisibleOnly = false, bool bTeleportToBusy = false, bool bUseNearestBusy = false, CBaseEntity *pSeeEntity = NULL, Activity activity = ACT_INVALID ); + void ForceActBusyLeave( bool bVisibleOnly = false ); + void StopBusying( void ); + bool IsStopBusying(); + CAI_Hint *FindActBusyHintNode( void ); + CAI_Hint *FindCombatActBusyHintNode( void ); + CAI_Hint *FindCombatActBusyTeleportHintNode( void ); + bool CanSelectSchedule( void ); + bool IsCurScheduleOverridable( void ); + bool ShouldIgnoreSound( CSound *pSound ); + void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void GatherConditions( void ); + void BuildScheduleTestBits( void ); + void EndScheduleSelection( void ); + Activity NPC_TranslateActivity( Activity nActivity ); + void HandleAnimEvent( animevent_t *pEvent ); + void CheckAndCleanupOnExit( void ); + bool FValidateHintType( CAI_Hint *pHint ); + bool ActBusyNodeStillActive( void ); + bool IsMovingToBusy( void ) { return m_bMovingToBusy; } + bool IsEnabled( void ) { return m_bEnabled; } + float GetReasonableFacingDist( void ) { return 0; } // Actbusy ignores reasonable facing + bool IsInterruptable( void ); + bool ShouldPlayerAvoid( void ); + void SetUseRenderBounds( bool bUseBounds ) { m_bUseRenderBoundsForCollision = bUseBounds; } + void ComputeAndSetRenderBounds(); + bool CanFlinch( void ); + bool CanRunAScriptedNPCInteraction( bool bForced ); + void OnScheduleChange(); + bool QueryHearSound( CSound *pSound ); + void OnSeeEntity( CBaseEntity *pEntity ); + bool NeedsToPlayExitAnim() { return m_bNeedsToPlayExitAnim; } + + // Returns true if the current NPC is acting busy, or moving to an actbusy + bool IsActive( void ); + // Returns true if the current NPC is actually acting busy (i.e. inside an act busy anim) + bool IsInsideActBusy( void ) { return m_bBusy; } + + // Combat act busy stuff + bool IsCombatActBusy(); + void CollectSafeZoneVolumes( CAI_ActBusyGoal *pActBusyGoal ); + bool IsInSafeZone( CBaseEntity *pEntity ); + int CountEnemiesInSafeZone(); + +private: + virtual int SelectSchedule( void ); + int SelectScheduleForLeaving( void ); + int SelectScheduleWhileNotBusy( int iBase ); + int SelectScheduleWhileBusy( void ); + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + void NotifyBusyEnding( void ); + bool HasAnimForActBusy( int iActBusy, busyanimparts_t AnimPart ); + bool PlayAnimForActBusy( busyanimparts_t AnimPart ); + void PlaySoundForActBusy( busyanimparts_t AnimPart ); + +private: + bool m_bEnabled; + bool m_bForceActBusy; + Activity m_ForcedActivity; + bool m_bTeleportToBusy; + bool m_bUseNearestBusy; + bool m_bLeaving; + bool m_bVisibleOnly; + bool m_bUseRenderBoundsForCollision; + float m_flForcedMaxTime; + bool m_bBusy; + bool m_bMovingToBusy; + bool m_bNeedsToPlayExitAnim; + float m_flNextBusySearchTime; + float m_flEndBusyAt; + float m_flBusySearchRange; + bool m_bInQueue; + int m_iCurrentBusyAnim; + CHandle m_hActBusyGoal; + bool m_bNeedToSetBounds; + EHANDLE m_hSeeEntity; + float m_fTimeLastSawSeeEntity; + bool m_bExitedBusyToDueLostSeeEntity; + bool m_bExitedBusyToDueSeeEnemy; + + int m_iNumConsecutivePathFailures; // Count how many times we failed to find a path to a node, so we can consider teleporting. + bool m_bAutoFireWeapon; + float m_flDeferUntil; + int m_iNumEnemiesInSafeZone; + + CUtlVectorm_SafeZones; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; +}; + + +//----------------------------------------------------------------------------- +// Purpose: A level tool to control the actbusy behavior. +//----------------------------------------------------------------------------- +class CAI_ActBusyGoal : public CAI_GoalEntity +{ + DECLARE_CLASS( CAI_ActBusyGoal, CAI_GoalEntity ); +public: + CAI_ActBusyGoal() + { + // Support legacy maps, where this value used to be set from a constant (with a value of 1). + // Now designers can specify whatever they want in Hammer. Take care of old maps by setting + // this in the constructor. (sjb) + m_flSeeEntityTimeout = 1; + } + + virtual void NPCMovingToBusy( CAI_BaseNPC *pNPC ); + virtual void NPCAbortedMoveTo( CAI_BaseNPC *pNPC ); + virtual void NPCStartedBusy( CAI_BaseNPC *pNPC ); + virtual void NPCStartedLeavingBusy( CAI_BaseNPC *pNPC ); + virtual void NPCFinishedBusy( CAI_BaseNPC *pNPC ); + virtual void NPCLeft( CAI_BaseNPC *pNPC ); + virtual void NPCLostSeeEntity( CAI_BaseNPC *pNPC ); + virtual void NPCSeeEnemy( CAI_BaseNPC *pNPC ); + + int GetType() { return m_iType; } + bool IsCombatActBusyTeleportAllowed() { return m_bAllowCombatActBusyTeleport; } + +protected: + CAI_ActBusyBehavior *GetBusyBehaviorForNPC( const char *pszActorName, CBaseEntity *pActivator, CBaseEntity *pCaller, const char *sInputName ); + CAI_ActBusyBehavior *GetBusyBehaviorForNPC( CBaseEntity *pEntity, const char *sInputName ); + + void EnableGoal( CAI_BaseNPC *pAI ); + + // Inputs + virtual void InputActivate( inputdata_t &inputdata ); + virtual void InputDeactivate( inputdata_t &inputdata ); + void InputSetBusySearchRange( inputdata_t &inputdata ); + void InputForceNPCToActBusy( inputdata_t &inputdata ); + void InputForceThisNPCToActBusy( inputdata_t &inputdata ); + void InputForceThisNPCToLeave( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + +protected: + float m_flBusySearchRange; + bool m_bVisibleOnly; + int m_iType; + bool m_bAllowCombatActBusyTeleport; + +public: + // Let the actbusy behavior query these so we don't have to duplicate the data. + string_t m_iszSeeEntityName; + float m_flSeeEntityTimeout; + string_t m_iszSafeZoneVolume; + int m_iSightMethod; + +protected: + COutputEHANDLE m_OnNPCStartedBusy; + COutputEHANDLE m_OnNPCFinishedBusy; + COutputEHANDLE m_OnNPCLeft; + COutputEHANDLE m_OnNPCLostSeeEntity; + COutputEHANDLE m_OnNPCSeeEnemy; +}; + +// Maximum number of nodes allowed in an actbusy queue +#define MAX_QUEUE_NODES 20 + +//----------------------------------------------------------------------------- +// Purpose: A level tool to control the actbusy behavior to create NPC queues +//----------------------------------------------------------------------------- +class CAI_ActBusyQueueGoal : public CAI_ActBusyGoal +{ + DECLARE_CLASS( CAI_ActBusyQueueGoal, CAI_ActBusyGoal ); +public: + virtual void Spawn( void ); + virtual void DrawDebugGeometryOverlays( void ); + virtual void NPCMovingToBusy( CAI_BaseNPC *pNPC ); + virtual void NPCStartedBusy( CAI_BaseNPC *pNPC ); + virtual void NPCAbortedMoveTo( CAI_BaseNPC *pNPC ); + virtual void NPCFinishedBusy( CAI_BaseNPC *pNPC ); + virtual void NPCStartedLeavingBusy( CAI_BaseNPC *pNPC ); + + virtual void InputActivate( inputdata_t &inputdata ); + void InputPlayerStartedBlocking( inputdata_t &inputdata ); + void InputPlayerStoppedBlocking( inputdata_t &inputdata ); + void InputMoveQueueUp( inputdata_t &inputdata ); + + void PushNPCBackInQueue( CAI_BaseNPC *pNPC, int iStartingNode ); + void RemoveNPCFromQueue( CAI_BaseNPC *pNPC ); + void RecalculateQueueCount( void ); + void QueueThink( void ); + void MoveQueueUp( void ); + void MoveQueueUpThink( void ); + bool NodeIsOccupied( int i ); + CAI_BaseNPC *GetNPCOnNode( int iNode ); + CAI_ActBusyBehavior *GetQueueBehaviorForNPC( CAI_BaseNPC *pNPC ); + + DECLARE_DATADESC(); + +private: + int m_iCurrentQueueCount; + CHandle m_hNodes[ MAX_QUEUE_NODES ]; + bool m_bPlayerBlockedNodes[ MAX_QUEUE_NODES ]; + EHANDLE m_hExitNode; + EHANDLE m_hExitingNPC; + bool m_bForceReachFront; + + // Read from mapdata + string_t m_iszNodes[ MAX_QUEUE_NODES ]; + string_t m_iszExitNode; + + // Outputs + COutputInt m_OnQueueMoved; + COutputEHANDLE m_OnNPCLeftQueue; + COutputEHANDLE m_OnNPCStartedLeavingQueue; +}; + +#endif // AI_BEHAVIOR_ACTBUSY_H diff --git a/game/server/hl2/ai_behavior_functank.h b/game/server/hl2/ai_behavior_functank.h new file mode 100644 index 0000000..a8d6146 --- /dev/null +++ b/game/server/hl2/ai_behavior_functank.h @@ -0,0 +1,120 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_FUNCTANK_H +#define AI_BEHAVIOR_FUNCTANK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "simtimer.h" +#include "ai_behavior.h" +#include "func_tank.h" + +#define AI_FUNCTANK_BEHAVIOR_BUSYTIME 10.0f + +enum +{ + FUNCTANK_SENTENCE_MOVE_TO_MOUNT = SENTENCE_BASE_BEHAVIOR_INDEX, + FUNCTANK_SENTENCE_JUST_MOUNTED, + FUNCTANK_SENTENCE_SCAN_FOR_ENEMIES, + FUNCTANK_SENTENCE_DISMOUNTING, +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAI_FuncTankBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_FuncTankBehavior, CAI_SimpleBehavior ); + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + DECLARE_DATADESC(); + +public: + // Contructor/Deconstructor + CAI_FuncTankBehavior(); + ~CAI_FuncTankBehavior(); + + void UpdateOnRemove(); + + // Identifier + const char *GetName() { return "FuncTank"; } + + // Schedule + bool CanSelectSchedule(); + void BeginScheduleSelection(); + void EndScheduleSelection(); + void PrescheduleThink(); + + Activity NPC_TranslateActivity( Activity activity ); + + // Conditions: + virtual void GatherConditions(); + + enum + { + SCHED_MOVE_TO_FUNCTANK = BaseClass::NEXT_SCHEDULE, + SCHED_FIRE_FUNCTANK, + SCHED_SCAN_WITH_FUNCTANK, + SCHED_FAIL_MOVE_TO_FUNCTANK, + }; + + // Tasks + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + enum + { + TASK_GET_PATH_TO_FUNCTANK = BaseClass::NEXT_TASK, + TASK_FACE_FUNCTANK, + TASK_HOLSTER_WEAPON, + TASK_FIRE_FUNCTANK, + TASK_SCAN_LEFT_FUNCTANK, + TASK_SCAN_RIGHT_FUNCTANK, + TASK_FORGET_ABOUT_FUNCTANK, + TASK_FUNCTANK_ANNOUNCE_SCAN, + }; + + enum + { + COND_FUNCTANK_DISMOUNT = BaseClass::NEXT_CONDITION, + NEXT_CONDITION, + }; + + // Combat. + CBaseEntity *BestEnemy( void ); + void Event_Killed( const CTakeDamageInfo &info ); + + bool HasFuncTank( void ) { return ( m_hFuncTank != NULL ); } + void SetFuncTank( CHandle hFuncTank ); + CFuncTank *GetFuncTank() { return m_hFuncTank; } + void AimGun( void ); + + void Dismount( void ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + // Time. + void SetBusy( float flTime ) { m_flBusyTime = flTime; } + bool IsBusy( void ) { return ( gpGlobals->curtime < m_flBusyTime ); } + + bool IsMounted( void ) { return m_bMounted; } + +private: + + // Schedule + int SelectSchedule(); + +private: + + CHandle m_hFuncTank; + bool m_bMounted; + float m_flBusyTime; + bool m_bSpottedPlayerOutOfCover; +}; + +#endif // AI_BEHAVIOR_FUNCTANK_H \ No newline at end of file diff --git a/game/server/hl2/ai_behavior_holster.h b/game/server/hl2/ai_behavior_holster.h new file mode 100644 index 0000000..5425aa3 --- /dev/null +++ b/game/server/hl2/ai_behavior_holster.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Deal with weapon being out +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef AI_BEHAVIOR_HOLSTER_H +#define AI_BEHAVIOR_HOLSTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior.h" + +class CAI_HolsterBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_HolsterBehavior, CAI_SimpleBehavior ); + +public: + CAI_HolsterBehavior(); + + virtual const char *GetName() { return "Holster"; } + + virtual bool CanSelectSchedule(); + //virtual void BeginScheduleSelection(); + //virtual void EndScheduleSelection(); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + //void BuildScheduleTestBits(); + //int TranslateSchedule( int scheduleType ); + //void OnStartSchedule( int scheduleType ); + + //void InitializeBehavior(); + + enum + { + SCHED_HOLSTER_WEAPON = BaseClass::NEXT_SCHEDULE, // Try to get out of the player's way + SCHED_DRAW_WEAPON, + NEXT_SCHEDULE, + + TASK_HOLSTER_WEAPON = BaseClass::NEXT_TASK, + TASK_DRAW_WEAPON, + NEXT_TASK, + +/* + COND_PUT_CONDITIONS_HERE = BaseClass::NEXT_CONDITION, + NEXT_CONDITION, +*/ + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +public: + +private: + virtual int SelectSchedule(); + + bool m_bWeaponOut; + + //--------------------------------- + + DECLARE_DATADESC(); +}; + +#endif // AI_BEHAVIOR_HOLSTER_H + + diff --git a/game/server/hl2/ai_behavior_operator.h b/game/server/hl2/ai_behavior_operator.h new file mode 100644 index 0000000..afa05fd --- /dev/null +++ b/game/server/hl2/ai_behavior_operator.h @@ -0,0 +1,144 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Operate consoles/machinery in the world. +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef AI_BEHAVIOR_OPERATOR_H +#define AI_BEHAVIOR_OPERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior.h" +#include "ai_goalentity.h" + +enum +{ + OPERATOR_STATE_NOT_READY = 0, + OPERATOR_STATE_READY, + OPERATOR_STATE_FINISHED, +}; + +enum +{ + OPERATOR_MOVETO_RESERVED = 0, + OPERATOR_MOVETO_WALK, + OPERATOR_MOVETO_RUN, +}; + +//========================================================= +//========================================================= +class CAI_OperatorGoal : public CAI_GoalEntity +{ + DECLARE_CLASS( CAI_OperatorGoal, CAI_GoalEntity ); +public: + CAI_OperatorGoal() + { + } + + void EnableGoal( CAI_BaseNPC *pAI ); + + int GetState() { return m_iState; } + int GetMoveTo() { return m_iMoveTo; } + + // Inputs + virtual void InputActivate( inputdata_t &inputdata ); + virtual void InputDeactivate( inputdata_t &inputdata ); + + void InputSetStateReady( inputdata_t &inputdata ); + void InputSetStateFinished( inputdata_t &inputdata ); + + COutputEvent m_OnBeginApproach; + COutputEvent m_OnMakeReady; + COutputEvent m_OnBeginOperating; + COutputEvent m_OnFinished; + + DECLARE_DATADESC(); + +protected: + int m_iState; + int m_iMoveTo; + string_t m_iszContextTarget; +}; + +//========================================================= +//========================================================= +class CAI_OperatorBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_OperatorBehavior, CAI_SimpleBehavior ); + +public: + CAI_OperatorBehavior(); + + virtual const char *GetName() { return "Operator"; } + + virtual void SetParameters( CAI_OperatorGoal *pGoal, CBaseEntity *pPositionEnt, CBaseEntity *pContextTarget ); + + virtual bool CanSelectSchedule(); + //virtual void BeginScheduleSelection(); + //virtual void EndScheduleSelection(); + + bool CanSeePositionEntity(); + bool IsAtPositionEntity(); + + void GatherConditionsNotActive(); + void GatherConditions( void ); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + CAI_OperatorGoal *GetGoalEntity(); + + bool IsGoalReady(); + + //void BuildScheduleTestBits(); + //int TranslateSchedule( int scheduleType ); + //void OnStartSchedule( int scheduleType ); + + //void InitializeBehavior(); + + enum + { + SCHED_OPERATOR_APPROACH_POSITION = BaseClass::NEXT_SCHEDULE, + SCHED_OPERATOR_MAKE_READY, + SCHED_OPERATOR_OPERATE, + SCHED_OPERATOR_WAIT_FOR_HOLSTER, + NEXT_SCHEDULE, + + TASK_OPERATOR_GET_PATH_TO_POSITION = BaseClass::NEXT_TASK, + TASK_OPERATOR_START_PATH, + TASK_OPERATOR_OPERATE, + NEXT_TASK, + + COND_OPERATOR_LOST_SIGHT_OF_POSITION = BaseClass::NEXT_CONDITION, + NEXT_CONDITION, + }; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; + +public: + EHANDLE m_hGoalEntity; + EHANDLE m_hPositionEnt; + EHANDLE m_hContextTarget; + CRandStopwatch m_WatchSeeEntity; + +private: + virtual int SelectSchedule(); + + //--------------------------------- + + DECLARE_DATADESC(); +}; + +#endif // AI_BEHAVIOR_OPERATOR_H + + diff --git a/game/server/hl2/ai_behavior_police.h b/game/server/hl2/ai_behavior_police.h new file mode 100644 index 0000000..84f132b --- /dev/null +++ b/game/server/hl2/ai_behavior_police.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_BEHAVIOR_POLICE_H +#define AI_BEHAVIOR_POLICE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_behavior.h" +#include "ai_goal_police.h" +#include "ai_sentence.h" + +#define PATROL_RADIUS_RATIO 2.0f +#define POLICE_MAX_WARNINGS 4 + +class CAI_PolicingBehavior : public CAI_SimpleBehavior +{ + DECLARE_CLASS( CAI_PolicingBehavior, CAI_SimpleBehavior ); +public: + DECLARE_DATADESC(); + CAI_PolicingBehavior(); + + enum + { + // Schedules + SCHED_POLICE_RETURN_FROM_HARASS = BaseClass::NEXT_SCHEDULE, + SCHED_POLICE_WARN_TARGET, + SCHED_POLICE_HARASS_TARGET, + SCHED_POLICE_SUPPRESS_TARGET, + SCHED_POLICE_FACE_ALONG_GOAL, + SCHED_POLICE_TRACK_TARGET, + NEXT_SCHEDULE, + + // Tasks + TASK_POLICE_GET_PATH_TO_HARASS_GOAL = BaseClass::NEXT_TASK, + TASK_POLICE_GET_PATH_TO_POLICE_GOAL, + TASK_POLICE_FACE_ALONG_GOAL, + TASK_POLICE_ANNOUNCE_HARASS, + NEXT_TASK, + + // Conditions + COND_POLICE_TARGET_TOO_CLOSE_HARASS = BaseClass::NEXT_CONDITION, + COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS, + NEXT_CONDITION, + }; + + virtual const char *GetName() { return "Policing"; } + + void Enable( CAI_PoliceGoal *pGoal ); + void Disable( void ); + bool CanSelectSchedule( void ); + void BuildScheduleTestBits( void ); + + bool IsEnabled( void ) { return m_bEnabled; } + bool TargetIsHostile( void ); + + bool ShouldKnockOutTarget( CBaseEntity *pTarget ); + void KnockOutTarget( CBaseEntity *pTarget ); + + int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + + CBaseEntity *GetGoalTarget( void ); + +private: + + void HostSpeakSentence( const char *pSentence, SentencePriority_t nSoundPriority, SentenceCriteria_t nCriteria ); + + int TranslateSchedule( int scheduleType ); + + int SelectSchedule( void ); + int SelectSuppressSchedule( void ); + int SelectHarassSchedule( void ); + + Activity NPC_TranslateActivity( Activity newActivity ); + void GatherConditions( void ); + bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + void AnnouncePolicing( void ); + void HostSetBatonState( bool state ); + bool HostBatonIsOn( void ); + + void SetTargetHostileDuration( float time ); + bool MaintainGoalPosition( void ); + +protected: + + bool m_bEnabled; + bool m_bStartPolicing; + float m_flNextHarassTime; + float m_flAggressiveTime; + int m_nNumWarnings; + bool m_bTargetIsHostile; + float m_flTargetHostileTime; + + CHandle m_hPoliceGoal; + + DEFINE_CUSTOM_SCHEDULE_PROVIDER; +}; + +#endif // AI_BEHAVIOR_POLICE_H diff --git a/game/server/hl2/ai_goal_police.h b/game/server/hl2/ai_goal_police.h new file mode 100644 index 0000000..c2b7096 --- /dev/null +++ b/game/server/hl2/ai_goal_police.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_GOAL_POLICE_H +#define AI_GOAL_POLICE_H +#ifdef _WIN32 +#pragma once +#endif + +class CAI_PoliceGoal : public CBaseEntity +{ +public: + + DECLARE_CLASS( CAI_PoliceGoal, CBaseEntity ); + + CAI_PoliceGoal( void ); + + float GetRadius( void ); + CBaseEntity *GetTarget( void ); + + bool ShouldKnockOutTarget( const Vector &targetPos, bool bTargetVisible ); // If the target should be knocked out + void KnockOutTarget( CBaseEntity *pTarget ); // Send an output that we've knocked out this target + bool ShouldRemainAtPost( void ); + + void InputEnableKnockOut( inputdata_t &data ); + void InputDisableKnockOut( inputdata_t &data ); + + void FireWarningLevelOutput( int level ); + + float m_flRadius; + EHANDLE m_hTarget; + string_t m_iszTarget; + bool m_bOverrideKnockOut; + + COutputEvent m_OnKnockOut; + COutputEvent m_OnFirstWarning; + COutputEvent m_OnSecondWarning; + COutputEvent m_OnLastWarning; + COutputEvent m_OnSupressingTarget; + + DECLARE_DATADESC(); +}; + +#define SF_POLICE_GOAL_KNOCKOUT_BEHIND (1<<1) // Knockout a target that's behind the plane that cuts perpendicularly through us +#define SF_POLICE_GOAL_DO_NOT_LEAVE_POST (1<<2) // Cop will not come off his policing goal, even when angered + +#endif // AI_GOAL_POLICE_H diff --git a/game/server/hl2/ai_interactions.h b/game/server/hl2/ai_interactions.h new file mode 100644 index 0000000..93f7ef8 --- /dev/null +++ b/game/server/hl2/ai_interactions.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +//================================================== +// Definition for all AI interactions +//================================================== + +#ifndef AI_INTERACTIONS_H +#define AI_INTERACTIONS_H + +#ifdef _WIN32 +#pragma once +#endif + +//Antlion +extern int g_interactionAntlionKilled; + +//Barnacle +extern int g_interactionBarnacleVictimDangle; +extern int g_interactionBarnacleVictimReleased; +extern int g_interactionBarnacleVictimGrab; + +//Bullsquid +//extern int g_interactionBullsquidPlay; +//extern int g_interactionBullsquidThrow; + +//Combine +extern int g_interactionCombineBash; +extern int g_interactionCombineRequestCover; + +//Houndeye +//extern int g_interactionHoundeyeGroupAttack; +//extern int g_interactionHoundeyeGroupRetreat; +//extern int g_interactionHoundeyeGroupRalley; + +//Scanner +extern int g_interactionScannerInspect; +extern int g_interactionScannerInspectBegin; +extern int g_interactionScannerInspectDone; +extern int g_interactionScannerInspectHandsUp; +extern int g_interactionScannerInspectShowArmband; +extern int g_interactionScannerSupportEntity; +extern int g_interactionScannerSupportPosition; + +//Metrocop +extern int g_interactionMetrocopPointed; +extern int g_interactionMetrocopStartedStitch; + +//ScriptedTarget +extern int g_interactionScriptedTarget; + +//Stalker +extern int g_interactionStalkerBurn; + +//Vortigaunt +extern int g_interactionVortigauntStomp; +extern int g_interactionVortigauntStompFail; +extern int g_interactionVortigauntStompHit; +extern int g_interactionVortigauntKick; +extern int g_interactionVortigauntClaw; + +//Floor turret +extern int g_interactionTurretStillStanding; + +// AI Interaction for being hit by a physics object +extern int g_interactionHitByPlayerThrownPhysObj; + +// Alerts vital allies when the player punts a large object (car) +extern int g_interactionPlayerPuntedHeavyObject; + +// Zombie +// Melee attack will land in one second or so. +extern int g_interactionZombieMeleeWarning; + +#endif //AI_INTERACTIONS_H \ No newline at end of file diff --git a/game/server/hl2/ai_spotlight.h b/game/server/hl2/ai_spotlight.h new file mode 100644 index 0000000..c8a2937 --- /dev/null +++ b/game/server/hl2/ai_spotlight.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_SPOTLIGHT_H +#define AI_SPOTLIGHT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_component.h" + +class CBeam; +class CSprite; +class SmokeTrail; +class CSpotlightEnd; + + +//----------------------------------------------------------------------------- +// Parameters for how the scanner relates to citizens. +//----------------------------------------------------------------------------- +enum +{ + AI_SPOTLIGHT_NO_DLIGHTS = 0x1, +}; + + +class CAI_Spotlight : public CAI_Component +{ + DECLARE_SIMPLE_DATADESC(); + DECLARE_CLASS_NOBASE( CAI_Spotlight ); + +public: + CAI_Spotlight(); + ~CAI_Spotlight(); + + void Init( CAI_BaseNPC *pOuter, int nFlags, float flConstraintAngle, float flMaxLength ); + + // Create, destroy the spotlight + void SpotlightCreate( int nAttachment, const Vector &vecInitialDir ); + void SpotlightDestroy(void); + + // Controls the spotlight target position + direction + void SetSpotlightTargetPos( const Vector &vSpotlightTargetPos ); + void SetSpotlightTargetDirection( const Vector &vSpotlightTargetDir ); + + // Updates the spotlight. Call every frame! + void Update(void); + +private: + void Precache(void); + void CreateSpotlightEntities( void ); + void UpdateSpotlightDirection( void ); + void UpdateSpotlightEndpoint( void ); + + // Constrain to cone, returns true if it was constrained + bool ConstrainToCone( Vector *pDirection ); + + // Computes the spotlight endpoint + void ComputeEndpoint( const Vector &vecStartPoint, Vector *pEndPoint ); + +private: + CHandle m_hSpotlight; + CHandle m_hSpotlightTarget; + + Vector m_vSpotlightTargetPos; + Vector m_vSpotlightDir; + float m_flSpotlightCurLength; + float m_flSpotlightMaxLength; + float m_flConstraintAngle; + int m_nHaloSprite; + int m_nSpotlightAttachment; + int m_nFlags; + Quaternion m_vAngularVelocity; +}; + + +#endif // AI_SPOTLIGHT_H + + diff --git a/game/server/hl2/antlion_dust.h b/game/server/hl2/antlion_dust.h new file mode 100644 index 0000000..51b783b --- /dev/null +++ b/game/server/hl2/antlion_dust.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef ANTLION_DUST_H +#define ANTLION_DUST_H + +#include "te_particlesystem.h" + +class CTEAntlionDust : public CTEParticleSystem +{ +public: + + DECLARE_CLASS( CTEAntlionDust, CTEParticleSystem ); + DECLARE_SERVERCLASS(); + + CTEAntlionDust( const char *name ); + virtual ~CTEAntlionDust( void ); + + virtual void Test( const Vector& current_origin, const QAngle& current_angles ) { }; + + CNetworkVector( m_vecOrigin ); + CNetworkVar( QAngle, m_vecAngles ); + CNetworkVar( bool, m_bBlockedSpawner ); +}; + +void UTIL_CreateAntlionDust( const Vector &origin, const QAngle &angles, bool bBlockedSpawner = false ); + +#endif //ANTLION_DUST_H \ No newline at end of file diff --git a/game/server/hl2/antlion_maker.h b/game/server/hl2/antlion_maker.h new file mode 100644 index 0000000..8c8c63d --- /dev/null +++ b/game/server/hl2/antlion_maker.h @@ -0,0 +1,186 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ANTLION_MAKER_H +#define ANTLION_MAKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "npc_antlion.h" +#include "monstermaker.h" +#include "igamesystem.h" +#include "ai_hint.h" + +// +// Antlion maker class +// + +#define SF_ANTLIONMAKER_RANDOM_SPAWN_NODE 0x00000400 +#define SF_ANTLIONMAKER_SPAWN_CLOSE_TO_TARGET 0x00000800 +#define SF_ANTLIONMAKER_RANDOM_FIGHT_TARGET 0x00001000 +#define SF_ANTLIONMAKER_DO_BLOCKEDEFFECTS 0x00002000 + +class CAntlionTemplateMaker : public CTemplateNPCMaker +{ + public: + + DECLARE_CLASS( CAntlionTemplateMaker, CTemplateNPCMaker ); + + CAntlionTemplateMaker( void ); + ~CAntlionTemplateMaker( void ); + + virtual int DrawDebugTextOverlays( void ); + virtual void DrawDebugGeometryOverlays( void ); + + void MakeNPC( void ); + void ChildPreSpawn( CAI_BaseNPC *pChild ); + void ChildPostSpawn( CAI_BaseNPC *pChild ); + + void InputSetFightTarget( inputdata_t &inputdata ); + void InputSetFollowTarget( inputdata_t &inputdata ); + void InputClearFightTarget( inputdata_t &inputdata ); + void InputClearFollowTarget( inputdata_t &inputdata ); + void InputSetSpawnRadius( inputdata_t &inputdata ); + void InputAddToPool( inputdata_t &inputdata ); + void InputSetMaxPool( inputdata_t &inputdata ); + void InputSetPoolRegenAmount( inputdata_t &inputdata ); + void InputSetPoolRegenTime( inputdata_t &inputdata ); + void InputChangeDestinationGroup( inputdata_t &inputdata ); + + void Activate( void ); + + // Do not transition + int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + + bool CanMakeNPC( bool bIgnoreSolidEntities = false ); + bool ShouldAlwaysThink( void ) { return true; } + + void AddChild( CNPC_Antlion *pAnt ); + void RemoveChild( CNPC_Antlion *pAnt ); + + void FixupOrphans( void ); + void UpdateChildren( void ); + + void CreateProxyTarget( const Vector &position ); + void DestroyProxyTarget( void ); + + void SetFightTarget( string_t strTarget, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + void SetFightTarget( CBaseEntity *pEntity ); + void SetFightTarget( const Vector &position ); + + void SetFollowTarget( string_t strTarget, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + void SetFollowTarget( CBaseEntity *pEntity ); + + void SetChildMoveState( AntlionMoveState_e state ); + + void DeathNotice( CBaseEntity *pVictim ); + bool IsDepleted( void ); + + bool ShouldHearBugbait( void ) { return (m_bIgnoreBugbait==false); } + + CBaseEntity *GetFightTarget( void ); + CBaseEntity *GetFollowTarget( void ); + + virtual void Enable( void ); + virtual void Disable( void ); + + + void BlockedCheckFunc( void ); + void FindNodesCloseToPlayer( void ); + void DoBlockedEffects( CBaseEntity *pBlocker, Vector vOrigin ); + + CBaseEntity *AllHintsFromClusterBlocked( CAI_Hint *pNode, bool &bChosenHintBlocked ); + + void ActivateAllSpores( void ); + void ActivateSpore( const char* sporename, Vector vOrigin ); + void DisableSpore( const char* sporename ); + void DisableAllSpores( void ); + +protected: + + void PrecacheTemplateEntity( CBaseEntity *pEntity ); + + bool FindHintSpawnPosition( const Vector &origin, float radius, string_t hintGroupName, CAI_Hint **pHint, bool bRandom = false ); + bool FindNearTargetSpawnPosition( Vector &origin, float radius, CBaseEntity *pTarget ); + + //These are used by FindNearTargetSpawnPosition + bool FindPositionOnFoot( Vector &origin, float radius, CBaseEntity *pTarget ); + bool FindPositionOnVehicle( Vector &origin, float radius, CBaseEntity *pTarget ); + bool ValidateSpawnPosition( Vector &vOrigin, CBaseEntity *pTarget = NULL ); + + // Pool behavior for coast + void PoolAdd( int iNumToAdd ); + void PoolRegenThink( void ); + +protected: + // FIXME: The m_strSpawnGroup is redundant to the m_iszDestinationGroup in the base class NPC template maker + string_t m_strSpawnGroup; // if present, spawn children on the nearest node of this group (to the player) + string_t m_strSpawnTarget; // name of target to spawn near + float m_flSpawnRadius; // radius around target to attempt to spawn in + float m_flWorkerSpawnRate; // Percentage chance of spawning a worker when we spawn an antlion [0..1]. + + string_t m_strFightTarget; // target entity name that all children will be told to fight to + string_t m_strFollowTarget; // entity name that all children will follow + + bool m_bIgnoreBugbait; // Whether or not to ignore bugbait + + AntlionMoveState_e m_nChildMoveState; + + EHANDLE m_hFightTarget; // A normal entity pointer for fight position + EHANDLE m_hProxyTarget; // This is a self-held target that is created and used when a vector is passed in as a fight + // goal, instead of an entity + EHANDLE m_hFollowTarget; // Target to follow + + CUtlVector< CHandle< CNPC_Antlion > > m_Children; + + // Pool behavior for coast + int m_iPool; + int m_iMaxPool; + int m_iPoolRegenAmount; + float m_flPoolRegenTime; + + float m_flVehicleSpawnDistance; + + int m_iSkinCount; + + float m_flBlockedBumpTime; + + bool m_bBlocked; + COutputEvent m_OnAllBlocked; + + bool m_bCreateSpores; + + DECLARE_DATADESC(); +}; + +// ======================================================== +// Antlion maker manager +// ======================================================== + +class CAntlionMakerManager : public CAutoGameSystem +{ +public: + CAntlionMakerManager( char const *name ) : CAutoGameSystem( name ) + { + } + + void LevelInitPostEntity( void ); + + void BroadcastFightGoal( const Vector &vFightGoal ); + void BroadcastFightGoal( CBaseEntity *pFightGoal ); + void BroadcastFollowGoal( CBaseEntity *pFollowGoal ); + +protected: + + void GatherMakers( void ); + + CUtlVector< CHandle< CAntlionTemplateMaker > > m_Makers; +}; + +extern CAntlionMakerManager g_AntlionMakerManager; + +#endif // ANTLION_MAKER_H diff --git a/game/server/hl2/ar2_explosion.h b/game/server/hl2/ar2_explosion.h new file mode 100644 index 0000000..673528d --- /dev/null +++ b/game/server/hl2/ar2_explosion.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef AR2_EXPLOSION_H +#define AR2_EXPLOSION_H + + +#include "baseparticleentity.h" + + +class AR2Explosion : public CBaseParticleEntity +{ + DECLARE_DATADESC(); + +public: + DECLARE_CLASS( AR2Explosion, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + static AR2Explosion* CreateAR2Explosion(const Vector &pos); + + inline void SetMaterialName(const char *szMaterialName); + +private: + + CNetworkString( m_szMaterialName, 255 ); +}; + + +void AR2Explosion::SetMaterialName(const char *szMaterialName) +{ + if (szMaterialName) + { + Q_strncpy(m_szMaterialName.GetForModify(), szMaterialName, sizeof(m_szMaterialName)); + } +} + + +#endif diff --git a/game/server/hl2/assassin_smoke.h b/game/server/hl2/assassin_smoke.h new file mode 100644 index 0000000..5492378 --- /dev/null +++ b/game/server/hl2/assassin_smoke.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ASSASSIN_SMOKE_H +#define ASSASSIN_SMOKE_H + + +#include "baseparticleentity.h" + + +class CAssassinSmoke : public CBaseParticleEntity +{ +public: + DECLARE_CLASS( CAssassinSmoke, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + static CAssassinSmoke* CreateAssassinSmoke (const Vector &pos); +}; + + +#endif//ASSASSIN_SMOKE_H + + diff --git a/game/server/hl2/basehlcombatweapon.h b/game/server/hl2/basehlcombatweapon.h new file mode 100644 index 0000000..7c43164 --- /dev/null +++ b/game/server/hl2/basehlcombatweapon.h @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basehlcombatweapon_shared.h" + +#ifndef BASEHLCOMBATWEAPON_H +#define BASEHLCOMBATWEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +//========================================================= +// Machine gun base class +//========================================================= +abstract_class CHLMachineGun : public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CHLMachineGun, CBaseHLCombatWeapon ); + DECLARE_DATADESC(); + + CHLMachineGun(); + + DECLARE_SERVERCLASS(); + + void PrimaryAttack( void ); + + // Default calls through to m_hOwner, but plasma weapons can override and shoot projectiles here. + virtual void ItemPostFrame( void ); + virtual void FireBullets( const FireBulletsInfo_t &info ); + virtual float GetFireRate( void ) = 0; + virtual int WeaponRangeAttack1Condition( float flDot, float flDist ); + virtual bool Deploy( void ); + + virtual const Vector &GetBulletSpread( void ); + + int WeaponSoundRealtime( WeaponSound_t shoot_type ); + + // utility function + static void DoMachineGunKick( CBasePlayer *pPlayer, float dampEasy, float maxVerticleKickAngle, float fireDurationTime, float slideLimitTime ); + +protected: + + int m_nShotsFired; // Number of consecutive shots fired + + float m_flNextSoundTime; // real-time clock of when to make next sound +}; + +//========================================================= +// Machine guns capable of switching between full auto and +// burst fire modes. +//========================================================= +// Mode settings for select fire weapons +enum +{ + FIREMODE_FULLAUTO = 1, + FIREMODE_SEMI, + FIREMODE_3RNDBURST, +}; + +//========================================================= +// >> CHLSelectFireMachineGun +//========================================================= +class CHLSelectFireMachineGun : public CHLMachineGun +{ + DECLARE_CLASS( CHLSelectFireMachineGun, CHLMachineGun ); +public: + + CHLSelectFireMachineGun( void ); + + DECLARE_SERVERCLASS(); + + virtual float GetBurstCycleRate( void ); + virtual float GetFireRate( void ); + + virtual bool Deploy( void ); + virtual void WeaponSound( WeaponSound_t shoot_type, float soundtime = 0.0f ); + + DECLARE_DATADESC(); + + virtual int GetBurstSize( void ) { return 3; }; + + void BurstThink( void ); + + virtual void PrimaryAttack( void ); + virtual void SecondaryAttack( void ); + + virtual int WeaponRangeAttack1Condition( float flDot, float flDist ); + virtual int WeaponRangeAttack2Condition( float flDot, float flDist ); + +protected: + int m_iBurstSize; + int m_iFireMode; +}; +#endif // BASEHLCOMBATWEAPON_H diff --git a/game/server/hl2/cbasehelicopter.h b/game/server/hl2/cbasehelicopter.h new file mode 100644 index 0000000..4ca3b09 --- /dev/null +++ b/game/server/hl2/cbasehelicopter.h @@ -0,0 +1,294 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base class for helicopters & helicopter-type vehicles +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CBASEHELICOPTER_H +#define CBASEHELICOPTER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_trackpather.h" + + +//--------------------------------------------------------- +// Helicopter flags +//--------------------------------------------------------- +enum HelicopterFlags_t +{ + BITS_HELICOPTER_GUN_ON = 0x00000001, // Gun is on and aiming + BITS_HELICOPTER_MISSILE_ON = 0x00000002, // Missile turrets are on and aiming +}; + + +//--------------------------------------------------------- +//--------------------------------------------------------- +#define SF_NOWRECKAGE 0x08 +#define SF_NOROTORWASH 0x20 +#define SF_AWAITINPUT 0x40 + +//--------------------------------------------------------- +//--------------------------------------------------------- +// Pathing data +#define BASECHOPPER_LEAD_DISTANCE 800.0f +#define BASECHOPPER_MIN_CHASE_DIST_DIFF 128.0f // Distance threshold used to determine when a target has moved enough to update our navigation to it +#define BASECHOPPER_AVOID_DIST 256.0f + +#define BASECHOPPER_MAX_SPEED 400.0f +#define BASECHOPPER_MAX_FIRING_SPEED 250.0f +#define BASECHOPPER_MIN_ROCKET_DIST 1000.0f +#define BASECHOPPER_MAX_GUN_DIST 2000.0f + +//--------------------------------------------------------- +// Physics rotor pushing +#define BASECHOPPER_WASH_RADIUS 256 +#define BASECHOPPER_WASH_PUSH_MIN 30 // Initial force * their mass applied to objects in the wash +#define BASECHOPPER_WASH_PUSH_MAX 40 // Maximum force * their mass applied to objects in the wash +#define BASECHOPPER_WASH_RAMP_TIME 1.0 // Time it takes to ramp from the initial to the max force on an object in the wash (at the center of the wash) +#define BASECHOPPER_WASH_MAX_MASS 300 // Don't attempt to push anything over this mass +#define BASECHOPPER_WASH_MAX_OBJECTS 6 // Maximum number of objects the wash will push at once + +// Wash physics pushing +struct washentity_t +{ + DECLARE_DATADESC(); + + EHANDLE hEntity; + float flWashStartTime; +}; + +#define BASECHOPPER_WASH_ALTITUDE 1024.0f + +//========================================================= +//========================================================= + +class CBaseHelicopter : public CAI_TrackPather +{ +public: + DECLARE_CLASS( CBaseHelicopter, CAI_TrackPather ); + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CBaseHelicopter( void ); + + void Spawn( void ); + void Precache( void ); + virtual void UpdateOnRemove(); + + void Event_Killed( const CTakeDamageInfo &info ); + void StopLoopingSounds(); + + int BloodColor( void ) { return DONT_BLEED; } + void GibMonster( void ); + + Class_T Classify ( void ) { return CLASS_COMBINE; } + + void CallDyingThink( void ) { DyingThink(); } + + bool HasEnemy( void ) { return GetEnemy() != NULL; } + virtual void GatherEnemyConditions( CBaseEntity *pEnemy ); + virtual bool ChooseEnemy( void ); + virtual void HelicopterPostThink( void ) { }; + virtual void FlyTouch( CBaseEntity *pOther ); + virtual void CrashTouch( CBaseEntity *pOther ); + virtual void HelicopterThink( void ); + virtual void DyingThink( void ); + virtual void NullThink( void ); + virtual void Startup ( void ); + + virtual void Flight( void ); + + virtual void ShowDamage( void ) {}; + + void UpdatePlayerDopplerShift( void ); + + virtual void Hunt( void ); + + virtual bool IsCrashing( void ) { return m_lifeState != LIFE_ALIVE; } + virtual float GetAcceleration( void ) { return 5; } + + virtual void ApplySidewaysDrag( const Vector &vecRight ); + virtual void ApplyGeneralDrag( void ); + + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + virtual bool FireGun( void ); + + virtual float GetRotorVolume( void ); + virtual void InitializeRotorSound( void ); + virtual void UpdateRotorSoundPitch( int iPitch ); + + virtual void AimRocketGun(void) {}; + virtual void FireRocket( Vector vLaunchPos, Vector vLaunchDir ) {}; + + virtual bool GetTrackPatherTarget( Vector *pPos ); + virtual CBaseEntity *GetTrackPatherTargetEnt(); + + void DrawDebugGeometryOverlays(void); + + // Rotor washes + virtual void DrawRotorWash( float flAltitude, const Vector &vecRotorOrigin ); + void DoRotorPhysicsPush( const Vector &vecRotorOrigin, float flAltitude ); + bool DoWashPush( washentity_t *pWash, const Vector &vecWashOrigin ); + void StopRotorWash( void ); + + // Purpose: Marks the entity for deletion + void InputKill( inputdata_t &inputdata ); + void DelayedKillThink( ); + + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + // Helicopters never burn + virtual void Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner ) { return; } + + +protected: + void HelicopterMove( ); + + // Updates the enemy + void UpdateEnemy(); + + // Override the desired position if your derived helicopter is doing something special + virtual void UpdateDesiredPosition( void ); + + // Updates the facing direction + virtual void UpdateFacingDirection(); + + // Fire weapons + void FireWeapons(); + + // Computes the actual position to fly to + void ComputeActualTargetPosition( float flSpeed, float flTime, float flPerpDist, Vector *pDest, bool bApplyNoise = true ); + + // Gets the max speed of the helicopter + virtual float GetMaxSpeed(); + virtual float GetMaxSpeedFiring(); + + // Updates the enemy + virtual float EnemySearchDistance( ); + + // Rotor wash think + void RotorWashThink( void ); + + // Purpose: Push an airboat in our wash + void DoWashPushOnAirboat( CBaseEntity *pAirboat, const Vector &vecWashToAirboat, float flWashAmount ); + + // Updates the rotor wash volume + virtual void UpdateRotorWashVolume(); + + // Rotor sound + void InputEnableRotorSound( inputdata_t &inputdata ); + void InputDisableRotorSound( inputdata_t &inputdata ); + +protected: + CSoundPatch *m_pRotorSound; // Rotor loop played when the player can see the helicopter + CSoundPatch *m_pRotorBlast; // Sound played when the helicopter's pushing around physics objects + + float m_flForce; + int m_fHelicopterFlags; + + Vector m_vecDesiredFaceDir; + + float m_flLastSeen; + float m_flPrevSeen; + + int m_iSoundState; // don't save this + + Vector m_vecTargetPosition; + + float m_flMaxSpeed; // Maximum speed of the helicopter. + float m_flMaxSpeedFiring; // Maximum speed of the helicopter whilst firing guns. + + float m_flGoalSpeed; // Goal speed + float m_flInitialSpeed; + + float m_flRandomOffsetTime; + Vector m_vecRandomOffset; + float m_flRotorWashEntitySearchTime; + bool m_bSuppressSound; + + EHANDLE m_hRotorWash; // Attached rotorwash entity + + // Inputs + void InputActivate( inputdata_t &inputdata ); + + // Inputs + void InputGunOn( inputdata_t &inputdata ); + void InputGunOff( inputdata_t &inputdata ); + void InputMissileOn( inputdata_t &inputdata ); + void InputMissileOff( inputdata_t &inputdata ); + void InputEnableRotorWash( inputdata_t &inputdata ); + void InputDisableRotorWash( inputdata_t &inputdata ); + void InputMoveTopSpeed( inputdata_t &inputdata ); // Causes the helicopter to immediately accelerate to its desired velocity + void InputMoveSpecifiedSpeed( inputdata_t &inputdata ); + void InputSetAngles( inputdata_t &inputdata ); // Sets the angles of the helicopter + +protected: + // Custom conservative collision volumes + Vector m_cullBoxMins; + Vector m_cullBoxMaxs; + + // Wash physics pushing + CUtlVector< washentity_t > m_hEntitiesPushedByWash; + + void SetStartupTime( float time ) { m_flStartupTime = time; } +private: + CNetworkVar( float, m_flStartupTime ); +}; + +//----------------------------------------------------------------------------- +// This entity is used to create little force spheres that the helicopter +// should avoid. +//----------------------------------------------------------------------------- +class CAvoidSphere : public CBaseEntity +{ + DECLARE_DATADESC(); + +public: + DECLARE_CLASS( CAvoidSphere, CBaseEntity ); + + void Init( float flRadius ); + virtual void Activate(); + virtual void UpdateOnRemove(); + + static void ComputeAvoidanceForces( CBaseEntity *pEntity, float flEntityRadius, float flAvoidTime, Vector *pVecAvoidForce ); + +private: + typedef CHandle AvoidSphereHandle_t; + + float m_flRadius; + + static CUtlVector< AvoidSphereHandle_t > s_AvoidSpheres; +}; + + +//----------------------------------------------------------------------------- +// This entity is used to create little force boxes that the helicopter +// should avoid. +//----------------------------------------------------------------------------- +class CAvoidBox : public CBaseEntity +{ + DECLARE_DATADESC(); + +public: + DECLARE_CLASS( CAvoidBox, CBaseEntity ); + + virtual void Spawn( ); + virtual void Activate(); + virtual void UpdateOnRemove(); + + static void ComputeAvoidanceForces( CBaseEntity *pEntity, float flEntityRadius, float flAvoidTime, Vector *pVecAvoidForce ); + +private: + typedef CHandle AvoidBoxHandle_t; + static CUtlVector< AvoidBoxHandle_t > s_AvoidBoxes; +}; + + +#endif // CBASEHELICOPTER_H diff --git a/game/server/hl2/cbasespriteprojectile.h b/game/server/hl2/cbasespriteprojectile.h new file mode 100644 index 0000000..bb60051 --- /dev/null +++ b/game/server/hl2/cbasespriteprojectile.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base class for simple projectiles +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CBASESPRITEPROJECTILE_H +#define CBASESPRITEPROJECTILE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "Sprite.h" + +enum MoveType_t; +enum MoveCollide_t; + + +//============================================================================= +//============================================================================= +class CBaseSpriteProjectile : public CSprite +{ + DECLARE_DATADESC(); + DECLARE_CLASS( CBaseSpriteProjectile, CSprite ); + +public: + void Touch( CBaseEntity *pOther ); + virtual void HandleTouch( CBaseEntity *pOther ); + + void Think(); + virtual void HandleThink(); + + void Spawn( char *pszModel, + const Vector &vecOrigin, + const Vector &vecVelocity, + edict_t *pOwner, + MoveType_t iMovetype, + MoveCollide_t nMoveCollide, + int iDamage, + int iDamageType, + CBaseEntity *pIntendedTarget = NULL ); + + virtual void Precache( void ) {}; + + int m_iDmg; + int m_iDmgType; + EHANDLE m_hIntendedTarget; +}; + +#endif // CBASESPRITEPROJECTILE_H diff --git a/game/server/hl2/combine_mine.h b/game/server/hl2/combine_mine.h new file mode 100644 index 0000000..48dbb46 --- /dev/null +++ b/game/server/hl2/combine_mine.h @@ -0,0 +1,128 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "Color.h" + +#ifndef COMBINE_MINE_H +#define COMBINE_MINE_H + +#ifdef _WIN32 +#pragma once +#endif + +class CSoundPatch; + +//--------------------------------------------------------- +//--------------------------------------------------------- +#define BOUNCEBOMB_HOOK_RANGE 64 +#define BOUNCEBOMB_WARN_RADIUS 245.0 // Must be slightly less than physcannon! +#define BOUNCEBOMB_DETONATE_RADIUS 100.0 + +#define BOUNCEBOMB_EXPLODE_RADIUS 125.0 +#define BOUNCEBOMB_EXPLODE_DAMAGE 150.0 +#include "player_pickup.h" + +class CBounceBomb : public CBaseAnimating, public CDefaultPlayerPickupVPhysics +{ + DECLARE_CLASS( CBounceBomb, CBaseAnimating ); + +public: + CBounceBomb() { m_pWarnSound = NULL; m_bPlacedByPlayer = false; } + void Precache(); + void Spawn(); + void OnRestore(); + int DrawDebugTextOverlays(void); + void SetMineState( int iState ); + int GetMineState() { return m_iMineState; } + bool IsValidLocation(); + void Flip( const Vector &vecForce, const AngularImpulse &torque ); + void SearchThink(); + void BounceThink(); + void SettleThink(); + void CaptiveThink(); + void ExplodeThink(); + void ExplodeTouch( CBaseEntity *pOther ); + void CavernBounceThink(); ///< an alternative style of bouncing used for the citizen modded bouncers + bool IsAwake() { return m_bAwake; } + void Wake( bool bWake ); + float FindNearestNPC(); + void SetNearestNPC( CBaseEntity *pNearest ) { m_hNearestNPC.Set( pNearest ); } + int OnTakeDamage( const CTakeDamageInfo &info ); + bool IsFriend( CBaseEntity *pEntity ); + + void UpdateLight( bool bTurnOn, unsigned int r, unsigned int g, unsigned int b, unsigned int a ); + bool IsLightOn() { return m_hSprite.Get() != NULL; } + + void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ); + void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); + bool ForcePhysgunOpen( CBasePlayer *pPlayer ) { return true; } + bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) { return true; } + virtual QAngle PreferredCarryAngles( void ) { return vec3_angle; } + CBasePlayer *HasPhysicsAttacker( float dt ); + + bool IsPlayerPlaced() { return m_bPlacedByPlayer; } + + bool CreateVPhysics() + { + VPhysicsInitNormal( SOLID_VPHYSICS, 0, false ); + return true; + } + + void Pickup(); + + void OpenHooks( bool bSilent = false ); + void CloseHooks(); + + DECLARE_DATADESC(); + + static string_t gm_iszFloorTurretClassname; + static string_t gm_iszGroundTurretClassname; + +private: + float m_flExplosionDelay; + + bool m_bAwake; + bool m_bBounce; + EHANDLE m_hNearestNPC; + EHANDLE m_hSprite; + Color m_LastSpriteColor; + + float m_flHookPositions; + int m_iHookN; + int m_iHookE; + int m_iHookS; + int m_iAllHooks; + + CSoundPatch *m_pWarnSound; + + bool m_bLockSilently; + bool m_bFoeNearest; + + float m_flIgnoreWorldTime; + + bool m_bDisarmed; + + bool m_bPlacedByPlayer; + + bool m_bHeldByPhysgun; + + int m_iFlipAttempts; + int m_iModification; + + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + + float m_flTimeGrabbed; + IPhysicsConstraint *m_pConstraint; + int m_iMineState; + + COutputEvent m_OnPulledUp; + void InputDisarm( inputdata_t &inputdata ); +}; + + + +#endif // COMBINE_MINE_H diff --git a/game/server/hl2/energy_wave.h b/game/server/hl2/energy_wave.h new file mode 100644 index 0000000..484d8df --- /dev/null +++ b/game/server/hl2/energy_wave.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENERGYWAVE_H +#define ENERGYWAVE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basecombatweapon.h" +#include "energy_wave.h" + + +//----------------------------------------------------------------------------- +// Purpose: Shield +//----------------------------------------------------------------------------- +class CEnergyWave : public CBaseEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CEnergyWave, CBaseEntity ); + DECLARE_SERVERCLASS(); + +public: + void Spawn( void ); + void Precache( void ); + +public: + static CEnergyWave* Create( CBaseEntity *pentOwner ); +}; + + +#endif //ENERGYWAVE_H \ No newline at end of file diff --git a/game/server/hl2/env_speaker.h b/game/server/hl2/env_speaker.h new file mode 100644 index 0000000..20fbeb6 --- /dev/null +++ b/game/server/hl2/env_speaker.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENV_SPEAKER_H +#define ENV_SPEAKER_H +#ifdef _WIN32 +#pragma once +#endif + +// =================================================================================== +// +// Speaker class. Used for announcements per level, for door lock/unlock spoken voice. +// + +class CSpeaker : public CPointEntity +{ +public: + DECLARE_CLASS( CSpeaker, CPointEntity ); + + void Spawn( void ); + void Precache( void ); + + DECLARE_DATADESC(); + + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + + virtual IResponseSystem *GetResponseSystem() { return m_pInstancedResponseSystem; } + + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + +protected: + + void SpeakerThink( void ); + + void InputToggle( inputdata_t &inputdata ); + + float m_delayMin; + float m_delayMax; + + string_t m_iszRuleScriptFile; + string_t m_iszConcept; + IResponseSystem *m_pInstancedResponseSystem; + +public: + + void InputTurnOff( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); +}; + +#endif // ENV_SPEAKER_H diff --git a/game/server/hl2/extinguisherjet.h b/game/server/hl2/extinguisherjet.h new file mode 100644 index 0000000..bf328b0 --- /dev/null +++ b/game/server/hl2/extinguisherjet.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EXTINGUISHERJET_H +#define EXTINGUISHERJET_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseparticleentity.h" + +class CExtinguisherJet : public CBaseEntity +{ +public: + DECLARE_CLASS( CExtinguisherJet, CBaseEntity ); + + CExtinguisherJet( void ); + + virtual void Spawn( void ); + virtual void Precache(); + + void TurnOn( void ); + void TurnOff( void ); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + + virtual void Think( void ); + + void ExtinguishThink( void ); + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + +// Stuff from the datatable. +public: + CNetworkVar( bool, m_bEmit ); // Emit particles? + CNetworkVar( int, m_nLength ); // Length of jet + CNetworkVar( int, m_nSize ); // Size of jet (as in width and noise of particle movement) + int m_nRadius; // Radius area to extinguish where jet hits + float m_flStrength; // Strength of the extinguisher + + bool m_bEnabled; + + //Used for viewmodel + CNetworkVar( bool, m_bUseMuzzlePoint ); + bool m_bAutoExtinguish; //Whether extinguisher should put out fires in its think, or let owner do it +}; + +#endif // EXTINGUISHERJET_H diff --git a/game/server/hl2/func_bulletshield.h b/game/server/hl2/func_bulletshield.h new file mode 100644 index 0000000..dcbb1e3 --- /dev/null +++ b/game/server/hl2/func_bulletshield.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_BULLETSHIELD_H +#define FUNC_BULLETSHIELD_H +#ifdef _WIN32 +#pragma once +#endif + +//!! replace this with generic start enabled/disabled +#define SF_WALL_START_OFF 0x0001 +#define SF_IGNORE_PLAYERUSE 0x0002 + +#include "modelentities.h" + +//----------------------------------------------------------------------------- +// Purpose: shield that stops bullets, but not other objects +// enabled state: brush is visible +// disabled staute: brush not visible +//----------------------------------------------------------------------------- +class CFuncBulletShield : public CFuncBrush +{ +public: + DECLARE_CLASS( CFuncBulletShield, CFuncBrush ); + DECLARE_DATADESC(); + + virtual void Spawn( void ); + + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + /* + bool CreateVPhysics( void ); + + virtual int ObjectCaps( void ) { return HasSpawnFlags(SF_IGNORE_PLAYERUSE) ? BaseClass::ObjectCaps() : BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; } + + virtual int DrawDebugTextOverlays( void ); + + void TurnOff( void ); + void TurnOn( void ); + + // Input handlers + void InputTurnOff( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + + enum BrushSolidities_e { + BRUSHSOLID_TOGGLE = 0, + BRUSHSOLID_NEVER = 1, + BRUSHSOLID_ALWAYS = 2, + }; + + BrushSolidities_e m_iSolidity; + int m_iDisabled; + bool m_bSolidBsp; + string_t m_iszExcludedClass; + bool m_bInvertExclusion; + + DECLARE_DATADESC(); + + virtual bool IsOn( void ); + */ +}; + + +#endif // MODELENTITIES_H diff --git a/game/server/hl2/func_tank.h b/game/server/hl2/func_tank.h new file mode 100644 index 0000000..46b444d --- /dev/null +++ b/game/server/hl2/func_tank.h @@ -0,0 +1,353 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FUNC_TANK_H +#define FUNC_TANK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "triggers.h" + +#define SF_TANK_ACTIVE 0x0001 +#define SF_TANK_PLAYER 0x0002 +#define SF_TANK_HUMANS 0x0004 +#define SF_TANK_ALIENS 0x0008 +#define SF_TANK_LINEOFSIGHT 0x0010 +#define SF_TANK_CANCONTROL 0x0020 +#define SF_TANK_DAMAGE_KICK 0x0040 // Kick when take damage +#define SF_TANK_AIM_AT_POS 0x0080 // Aim at a particular position +#define SF_TANK_AIM_ASSISTANCE 0x0100 +#define SF_TANK_NPC 0x0200 +#define SF_TANK_NPC_CONTROLLABLE 0x0400 // 1024 +#define SF_TANK_NPC_SET_CONTROLLER 0x0800 // 2048 +#define SF_TANK_ALLOW_PLAYER_HITS 0x1000 // 4096 Allow friendly NPCs to fire upon enemies near the player +#define SF_TANK_IGNORE_RANGE_IN_VIEWCONE 0x2000 // 8192 Don't use range as a factor in determining if something is in view cone +#define SF_TANK_NOTSOLID 0x8000 // 32768 +#define SF_TANK_SOUNDON 0x10000 // FIXME: This is not really a spawnflag! It holds transient state!!! +#define SF_TANK_HACKPLAYERHIT 0x20000 // 131072 Make this func_tank cheat and hit the player regularly + +#define FUNCTANK_DISTANCE_MAX 1200 // 100 ft. +#define FUNCTANK_DISTANCE_MIN_TO_ENEMY 180 +#define FUNCTANK_FIREVOLUME 1000 +#define FUNCTANK_NPC_ROUTE_TIME 5.0f + +// Effect handling +// If the func_tank has a chosen method of handling effects, use that +// instead of the individual effect settings. (muzzleflash, sound, tracer, etc) +enum FUNCTANK_EFFECT_HANDLING +{ + EH_NONE, // Use the effect settings + EH_AR2, // Use AR2 effects + EH_COMBINE_CANNON // Large Combine cannon +}; + +enum TANKBULLET +{ + TANK_BULLET_NONE = 0, + TANK_BULLET_SMALL = 1, + TANK_BULLET_MEDIUM = 2, + TANK_BULLET_LARGE = 3, +}; + +#define MORTAR_BLAST_RADIUS 350 + + +// Custom damage +// env_laser (duration is 0.5 rate of fire) +// rockets +// explosion? + +class CFuncTank : public CBaseEntity +{ + + DECLARE_CLASS( CFuncTank, CBaseEntity ); + +public: + + CFuncTank(); + ~CFuncTank(); + void Spawn( void ); + void Activate( void ); + void Precache( void ); + bool CreateVPhysics( void ); + bool KeyValue( const char *szKeyName, const char *szValue ); + void UpdateOnRemove(); + + void SetYawRate( float flYawRate ) { m_yawRate = flYawRate; } + void SetPitchRate( float flPitchRate ) { m_pitchRate = flPitchRate; } + + int ObjectCaps( void ) + { + return ( BaseClass::ObjectCaps() | FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS ); + } + + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual void FuncTankPreThink() { return; } + void Think( void ); + virtual void FuncTankPostThink() { return; } + + int GetAmmoCount( void ) { return m_iAmmoCount; } + + // NPC + bool NPC_FindManPoint( Vector &vecPos ); + bool NPC_HasEnemy( void ); + void NPC_Fire( void ); + void NPC_InterruptRoute( void ); + void NPC_JustSawPlayer( CBaseEntity *pTarget ); + void NPC_SetInRoute( bool bInRoute ) { m_bNPCInRoute = bInRoute; } + void NPC_SetIdleAngle( Vector vecIdle ) { m_vecNPCIdleTarget = vecIdle; } + + // LOS + bool IsEntityInViewCone( CBaseEntity *pEntity ); + bool HasLOSTo( CBaseEntity *pEntity ); + + // Controller + CBaseCombatCharacter *GetController( void ); + bool StartControl( CBaseCombatCharacter *pController ); + void StopControl( void ); + Vector GetTargetPosition() { return m_vTargetPosition; } + void SetTargetPosition( const Vector &vecPos ) { m_vTargetPosition = vecPos; } + + const float YawCenter() const { return m_yawCenter; } + const float YawCenterWorld() const { return m_yawCenterWorld; } + const float YawRange() const { return m_yawRange; } + const float PitchCenter() const { return m_pitchCenter; } + const float PitchCenterWorld() const { return m_pitchCenterWorld; } + const float PitchRange() const { return m_pitchRange; } + + virtual void PhysicsSimulate( void ); + + virtual void OnStartControlled() {} + virtual void OnStopControlled() {} + + // SF Tests. + inline bool IsControllable( void ) { return ( m_spawnflags & SF_TANK_CANCONTROL ) ? true : false; } + inline bool IsActive( void ) { return ( m_spawnflags & SF_TANK_ACTIVE ) ? true : false; } + inline bool IsNPCControllable( void ) { return ( m_spawnflags & SF_TANK_NPC_CONTROLLABLE ) ? true : false; } + inline bool IsNPCSetController( void ) { return ( m_spawnflags & SF_TANK_NPC_SET_CONTROLLER ) ? true : false; } + + virtual void DoMuzzleFlash( void ); + virtual const char *GetTracerType( void ); + +protected: + virtual float GetShotSpeed() { return 0; } + + virtual Vector WorldBarrelPosition( void ); + void UpdateMatrix( void ); + + float GetNextAttack() const { return m_flNextAttack; } + virtual void SetNextAttack( float flWait ) { m_flNextAttack = flWait; } + + virtual void Fire( int bulletCount, const Vector &barrelEnd, const Vector &forward, CBaseEntity *pAttacker, bool bIgnoreSpread ); + void TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, trace_t &tr ); + int GetRandomBurst( void ); + float GetRandomFireTime( void ); + + void CalcPlayerCrosshairTarget( Vector *pVecTarget ); + void CalcNPCEnemyTarget( Vector *pVecTarget ); + + inline bool IsPlayerManned( void ) { return m_hController && m_hController->IsPlayer() && ( m_spawnflags & SF_TANK_PLAYER ); } + inline bool IsNPCManned( void ) { return m_hController && m_hController->MyNPCPointer() && ( m_spawnflags & SF_TANK_NPC ); } + +private: + void TrackTarget( void ); + int DrawDebugTextOverlays(void); + void DrawDebugGeometryOverlays(void); + + virtual void FiringSequence( const Vector &barrelEnd, const Vector &forward, CBaseEntity *pAttacker ); + + void StartRotSound( void ); + void StopRotSound( void ); + + // Input handlers. + void InputActivate( inputdata_t &inputdata ); + void InputDeactivate( inputdata_t &inputdata ); + void InputSetFireRate( inputdata_t &inputdata ); + void InputSetDamage( inputdata_t &inputdata ); + void InputSetTargetDir( inputdata_t &inputdata ); + void InputSetTargetPosition( inputdata_t &inputdata ); + void InputSetTargetEntityName( inputdata_t &inputdata ); + +protected: + virtual void InputSetTargetEntity( inputdata_t &inputdata ); + virtual void InputClearTargetEntity( inputdata_t &inputdata ); + +private: + void InputFindNPCToManTank( inputdata_t &inputdata ); + void InputStopFindingNPCs( inputdata_t &inputdata ); + void InputStartFindingNPCs( inputdata_t &inputdata ); + void InputForceNPCOff( inputdata_t &inputdata ); + void InputSetMaxRange( inputdata_t &inputdata ); + + inline bool CanFire( void ); + bool InRange( float range ); + bool InRange2( float flRange2 ); + + void TraceAttack( CBaseEntity *pAttacker, float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType); + + QAngle AimBarrelAt( const Vector &parentTarget ); + + DECLARE_DATADESC(); + + bool OnControls( CBaseEntity *pTest ); + bool HasController( void ); + + CBaseEntity *FindTarget( string_t targetName, CBaseEntity *pActivator ); + + // NPC + void NPC_FindController( void ); + bool NPC_InRoute( void ) { return m_bNPCInRoute; } + bool NPC_InterruptController( void ); + + // Aim the tank at the player crosshair + void AimBarrelAtPlayerCrosshair( QAngle *pAngles ); + + // Aim the tank at the NPC's enemy + void AimBarrelAtNPCEnemy( QAngle *pAngles ); + + // Aim the tank at the func_tank's enemy + void AimFuncTankAtTarget( void ); + + // Returns true if the desired angles are out of range + bool RotateTankToAngles( const QAngle &angles, float *pDistX = NULL, float *pDistY = NULL ); + + // We lost our target! + void LostTarget( void ); + + // Purpose: + void ComputeLeadingPosition( const Vector &vecShootPosition, CBaseEntity *pTarget, Vector *pLeadPosition ); + +protected: + virtual void ControllerPostFrame( void ); + + virtual void TankActivate(void); + virtual void TankDeactivate(void); + + float m_fireLast; // Last time I fired + float m_fireRate; // How many rounds/second + + EHANDLE m_hTarget; + + TANKBULLET m_bulletType; // Bullet type + int m_iBulletDamage; // 0 means use Bullet type's default damage + int m_iBulletDamageVsPlayer; // Damage vs player. 0 means use m_iBulletDamage + +#ifdef HL2_EPISODIC + string_t m_iszAmmoType; // The name of the ammodef that we use when we fire. Bullet damage still comes from keyvalues. + int m_iAmmoType; // The cached index of the ammodef that we use when we fire. +#else + int m_iSmallAmmoType; + int m_iMediumAmmoType; + int m_iLargeAmmoType; +#endif // HL2_EPISODIC + + int m_spread; // firing spread + + EntityMatrix m_parentMatrix; + + Vector m_sightOrigin; // Last sight of target + EHANDLE m_hFuncTankTarget; + + int m_nBulletCount; + +private: + + // This is either the player manning the func_tank, or an NPC. The NPC is either manning the tank, or running + // to the man point. If he's en-route, m_bNPCInRoute will be true. + CHandle m_hController; + + float m_flNextAttack; + Vector m_vecControllerUsePos; + + float m_yawCenter; // "Center" yaw + float m_yawCenterWorld; // "Center" yaw in world space + float m_yawRate; // Max turn rate to track targets + float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) + // Zero is full rotation + float m_yawTolerance; // Tolerance angle + + float m_pitchCenter; // "Center" pitch + float m_pitchCenterWorld; // "Center" pitch in world space + float m_pitchRate; // Max turn rate on pitch + float m_pitchRange; // Range of pitch motion as above + float m_pitchTolerance; // Tolerance angle + + float m_fireTime; // How much time has been used to fire the weapon so far. + float m_lastSightTime;// Last time I saw target + float m_persist; // Persistence of firing (how long do I shoot when I can't see) + float m_persist2; // Secondary persistence of firing (randomly shooting when I can't see) + float m_persist2burst;// How long secondary persistence burst lasts + float m_minRange; // Minimum range to aim/track + float m_maxRange; // Max range to aim/track + float m_flMinRange2; + float m_flMaxRange2; + int m_iAmmoCount; // ammo + + Vector m_barrelPos; // Length of the freakin barrel + float m_spriteScale; // Scale of any sprites we shoot + string_t m_iszSpriteSmoke; + string_t m_iszSpriteFlash; + + string_t m_iszMaster; // Master entity (game_team_master or multisource) + + string_t m_soundStartRotate; + string_t m_soundStopRotate; + string_t m_soundLoopRotate; + + float m_flPlayerGracePeriod; + float m_flIgnoreGraceUpto; + float m_flPlayerLockTimeBeforeFire; + float m_flLastSawNonPlayer; + + string_t m_targetEntityName; + Vector m_vTargetPosition; + Vector m_vecNPCIdleTarget; + + // Used for when the gun is attached to another entity + string_t m_iszBarrelAttachment; + int m_nBarrelAttachment; + string_t m_iszBaseAttachment; + + // Used when the gun is actually a part of the parent entity, and pose params aim it + string_t m_iszYawPoseParam; + string_t m_iszPitchPoseParam; + float m_flYawPoseCenter; + float m_flPitchPoseCenter; + bool m_bUsePoseParameters; + + // Lead the target? + bool m_bPerformLeading; + float m_flStartLeadFactor; + float m_flStartLeadFactorTime; + float m_flNextLeadFactor; + float m_flNextLeadFactorTime; + + COutputEvent m_OnFire; + COutputEvent m_OnLoseTarget; + COutputEvent m_OnAquireTarget; + COutputEvent m_OnAmmoDepleted; + COutputEvent m_OnGotController; + COutputEvent m_OnLostController; + COutputEvent m_OnGotPlayerController; + COutputEvent m_OnLostPlayerController; + COutputEvent m_OnReadyToFire; + + CHandle m_hControlVolume; + string_t m_iszControlVolume; + + float m_flNextControllerSearch; + bool m_bShouldFindNPCs; + bool m_bNPCInRoute; + string_t m_iszNPCManPoint; + + bool m_bReadyToFire; + + int m_iEffectHandling; +}; + +#endif // FUNC_TANK_H \ No newline at end of file diff --git a/game/server/hl2/grenade_ar2.h b/game/server/hl2/grenade_ar2.h new file mode 100644 index 0000000..b49dd20 --- /dev/null +++ b/game/server/hl2/grenade_ar2.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot from the AR2 +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEAR2_H +#define GRENADEAR2_H + +#include "basegrenade_shared.h" + +#define MAX_AR2_NO_COLLIDE_TIME 0.2 + +class SmokeTrail; +class CWeaponAR2; + +class CGrenadeAR2 : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenadeAR2, CBaseGrenade ); + + CHandle< SmokeTrail > m_hSmokeTrail; + float m_fSpawnTime; + float m_fDangerRadius; + + + void Spawn( void ); + void Precache( void ); + void GrenadeAR2Touch( CBaseEntity *pOther ); + void GrenadeAR2Think( void ); + void Event_Killed( const CTakeDamageInfo &info ); + +public: + void EXPORT Detonate(void); + CGrenadeAR2(void); + + DECLARE_DATADESC(); +}; + +#endif //GRENADEAR2_H diff --git a/game/server/hl2/grenade_beam.h b/game/server/hl2/grenade_beam.h new file mode 100644 index 0000000..76203f6 --- /dev/null +++ b/game/server/hl2/grenade_beam.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot by mortar synth +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEBEAM_H +#define GRENADEBEAM_H + +#include "basegrenade_shared.h" + +#define GRENADEBEAM_MAXBEAMS 2 +#define GRENADEBEAM_MAXHITS GRENADEBEAM_MAXBEAMS-1 + +class CGrenadeBeam; +class CBeam; + +// End of the grenade beam +class CGrenadeBeamChaser : public CBaseAnimating +{ +public: + DECLARE_CLASS( CGrenadeBeamChaser, CBaseAnimating ); + DECLARE_DATADESC(); + + static CGrenadeBeamChaser* ChaserCreate( CGrenadeBeam *pTarget ); + + void Spawn( void ); + void ChaserThink(); + + CGrenadeBeam* m_pTarget; +}; + +class CGrenadeBeam : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenadeBeam, CBaseGrenade ); + DECLARE_DATADESC(); + + static CGrenadeBeam* Create( CBaseEntity* pOwner, const Vector &vStart); + +public: + void Spawn( void ); + void Precache( void ); + void Format( color32 clrColor, float flWidth); + void GrenadeBeamTouch( CBaseEntity *pOther ); + void KillBeam(); + void CreateBeams(void); + void UpdateBeams(void); + //void DebugBeams(void); + void GetChaserTargetPos(Vector *vPosition); + void GetNextTargetPos(Vector *vPosition); + int UpdateTransmitState(void); + void Shoot(Vector vDirection, float flSpeed, float flLifetime, float flLag, float flDamage ); + + Vector m_vLaunchPos; + float m_flBeamWidth; + float m_flBeamSpeed; + float m_flBeamLag; + float m_flLaunchTime; + float m_flLastTouchTime; + EHANDLE m_hBeamChaser; + int m_nNumHits; + Vector m_pHitLocation[GRENADEBEAM_MAXHITS]; + CBeam* m_pBeam[GRENADEBEAM_MAXBEAMS]; +}; + +#endif //GRENADEBEAM_H diff --git a/game/server/hl2/grenade_brickbat.h b/game/server/hl2/grenade_brickbat.h new file mode 100644 index 0000000..d0456a6 --- /dev/null +++ b/game/server/hl2/grenade_brickbat.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Things thrown from the hand +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEBRICKBAT_H +#define GRENADEBRICKBAT_H + +#include "basegrenade_shared.h" + +enum BrickbatAmmo_t; + +class CGrenade_Brickbat : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenade_Brickbat, CBaseGrenade ); + + virtual void Spawn( void ); + virtual void SpawnBrickbatWeapon( void ); + virtual void Detonate( void ) { return;}; + virtual bool CreateVPhysics(); + void BrickbatTouch( CBaseEntity *pOther ); + void BrickbatThink( void ); + + BrickbatAmmo_t m_nType; + bool m_bExplodes; + bool m_bBounceToFlat; // Bouncing to flatten + +public: + DECLARE_DATADESC(); +}; + +#endif //GRENADEBRICKBAT_H diff --git a/game/server/hl2/grenade_bugbait.h b/game/server/hl2/grenade_bugbait.h new file mode 100644 index 0000000..7a5df99 --- /dev/null +++ b/game/server/hl2/grenade_bugbait.h @@ -0,0 +1,135 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADE_BUGBAIT_H +#define GRENADE_BUGBAIT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "smoke_trail.h" +#include "basegrenade_shared.h" + +//Radius of the bugbait's effect on other creatures +extern ConVar bugbait_radius; +extern ConVar bugbait_hear_radius; +extern ConVar bugbait_distract_time; +extern ConVar bugbait_grenade_radius; + +#define SF_BUGBAIT_SUPPRESS_CALL 0x00000001 +#define SF_BUGBAIT_NOT_THROWN 0x00000002 // Don't detect player throwing the bugbait near this point +#define SF_BUGBAIT_NOT_SQUEEZE 0x00000004 // Don't detect player squeezing the bugbait + +//============================================================================= +// Bugbait sensor +//============================================================================= + +class CBugBaitSensor : public CPointEntity +{ +public: + + DECLARE_CLASS( CBugBaitSensor, CPointEntity ); + + DECLARE_DATADESC(); + + CBugBaitSensor( void ); + ~CBugBaitSensor( void ); + + bool Baited( CBaseEntity *pOther ) + { + if ( !m_bEnabled ) + return false; + + m_OnBaited.FireOutput( pOther, this ); + return true; + } + + void InputEnable( inputdata_t &data ) + { + m_bEnabled = true; + } + + void InputDisable( inputdata_t &data ) + { + m_bEnabled = false; + } + + void InputToggle( inputdata_t &data ) + { + m_bEnabled = !m_bEnabled; + } + + bool SuppressCall( void ) + { + return ( HasSpawnFlags( SF_BUGBAIT_SUPPRESS_CALL ) ); + } + + bool DetectsSqueeze( void ) + { + return ( !HasSpawnFlags( SF_BUGBAIT_NOT_SQUEEZE ) ); + } + + bool DetectsThrown( void ) + { + return ( !HasSpawnFlags( SF_BUGBAIT_NOT_THROWN ) ); + } + + float GetRadius( void ) const + { + if ( m_flRadius == 0 ) + return bugbait_radius.GetFloat(); + + return m_flRadius; + } + + bool IsDisabled( void ) const + { + return !m_bEnabled; + } + +protected: + + float m_flRadius; + bool m_bEnabled; + COutputEvent m_OnBaited; + +public: + CBugBaitSensor *m_pNext; +}; + +// +// Bug Bait Grenade +// + +class CGrenadeBugBait : public CBaseGrenade +{ + DECLARE_CLASS( CGrenadeBugBait, CBaseGrenade ); +public: + void Spawn( void ); + void Precache( void ); + + void ThinkBecomeSolid( void ); + void SetGracePeriod( float duration ); + + void BugBaitTouch( CBaseEntity *pOther ); + + // Activate nearby bugbait targets + static bool ActivateBugbaitTargets( CBaseEntity *pOwner, Vector vecOrigin, bool bSqueezed ); + + DECLARE_DATADESC(); + +protected: + void CreateTarget( const Vector &position, CBaseEntity *pOther ); + + float m_flGracePeriodEndsAt; + + SporeTrail *m_pSporeTrail; +}; + +extern CGrenadeBugBait *BugBaitGrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const QAngle &angVelocity, CBaseEntity *owner ); + +#endif // GRENADE_BUGBAIT_H diff --git a/game/server/hl2/grenade_energy.h b/game/server/hl2/grenade_energy.h new file mode 100644 index 0000000..f587dbc --- /dev/null +++ b/game/server/hl2/grenade_energy.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot by mortar synth +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEENERGY_H +#define GRENADEENERGY_H + +#include "basegrenade_shared.h" + +class CGrenadeEnergy : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenadeEnergy, CBaseGrenade ); + + static void Shoot( CBaseEntity* pOwner, const Vector &vStart, Vector vVelocity ); + +public: + void Spawn( void ); + void Precache( void ); + void Animate( void ); + void GrenadeEnergyTouch( CBaseEntity *pOther ); + void Event_Killed( const CTakeDamageInfo &info ); + + int m_flMaxFrame; + int m_nEnergySprite; + float m_flLaunchTime; // When was this thing launched + + void EXPORT Detonate(void); + + DECLARE_DATADESC(); +}; + +#endif //GRENADEENERGY_H diff --git a/game/server/hl2/grenade_frag.h b/game/server/hl2/grenade_frag.h new file mode 100644 index 0000000..63fe5ae --- /dev/null +++ b/game/server/hl2/grenade_frag.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADE_FRAG_H +#define GRENADE_FRAG_H +#pragma once + +class CBaseGrenade; +struct edict_t; + +CBaseGrenade *Fraggrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, float timer, bool combineSpawned ); +bool Fraggrenade_WasPunted( const CBaseEntity *pEntity ); +bool Fraggrenade_WasCreatedByCombine( const CBaseEntity *pEntity ); + +#endif // GRENADE_FRAG_H diff --git a/game/server/hl2/grenade_homer.h b/game/server/hl2/grenade_homer.h new file mode 100644 index 0000000..81ebcf9 --- /dev/null +++ b/game/server/hl2/grenade_homer.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot by city scanner +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEHOMER_H +#define GRENADEHOMER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" +#include "weapon_rpg.h" + +enum HomerRocketTrail_t +{ + HOMER_SMOKE_TRAIL_OFF, // No smoke trail + HOMER_SMOKE_TRAIL_ON, // Smoke trail always on + HOMER_SMOKE_TRAIL_ON_HOMING, // Smoke trail on when homing turned on + HOMER_SMOKE_TRAIL_ALIEN, // Alien colors on smoke trail +}; + +class CGrenadeHomer : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenadeHomer, CBaseGrenade ); + + static CGrenadeHomer* CreateGrenadeHomer( string_t nModelName, string_t sFlySound, const Vector &vecOrigin, const QAngle &vecAngles, edict_t *pentOwner ); + + virtual void Precache( void ); + void Spawn( void ); + void Launch( CBaseEntity *pOwner, CBaseEntity *pTarget, const Vector &vInitVelocity, float m_flHomingSpeed, float fFallSpeed, int nRocketTrailType); + void SetSpin(float flSpinMagnitude, float flSpinSpeed); + void SetHoming(float flStrength, float flDelay, float flRampUp, float flDuration, float flRampDown); + + CHandle m_hRocketTrail[3]; + +private: + string_t m_sFlySound; + float m_flNextFlySoundTime; + + // Input Parameters + float m_flHomingStrength; + float m_flHomingDelay; // How long before homing starts + float m_flHomingRampUp; // How long it take to reach full strength + float m_flHomingDuration; // How long does homing last + float m_flHomingRampDown; // How long to reach no homing again + float m_flHomingSpeed; + float m_flSpinMagnitude; + float m_flSpinSpeed; + int m_nRocketTrailType; + int m_spriteTexture; + + // In flight data + float m_flHomingLaunchTime; + float m_flHomingStartTime; + float m_flHomingEndTime; + float m_flSpinOffset; // For randomization + + EHANDLE m_hTarget; + + void AimThink( void ); + void StartRocketTrail(void); + void UpdateRocketTrail(float fScale); + void StopRocketTrail(void); + void PlayFlySound( void ); + void GrenadeHomerTouch( CBaseEntity *pOther ); + void Event_Killed( const CTakeDamageInfo &info ); + int OnTakeDamage( const CTakeDamageInfo &info ); + +public: + void EXPORT Detonate(void); + CGrenadeHomer(void); + + DECLARE_DATADESC(); +}; + +#endif //GRENADEHOMER_H diff --git a/game/server/hl2/grenade_molotov.h b/game/server/hl2/grenade_molotov.h new file mode 100644 index 0000000..3de070c --- /dev/null +++ b/game/server/hl2/grenade_molotov.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Molotov grenades +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEMOLOTOV_H +#define GRENADEMOLOTOV_H + +#include "basegrenade_shared.h" +#include "smoke_trail.h" + +class CGrenade_Molotov : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenade_Molotov, CBaseGrenade ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void Detonate( void ); + void MolotovTouch( CBaseEntity *pOther ); + void MolotovThink( void ); + +protected: + + SmokeTrail *m_pFireTrail; + + DECLARE_DATADESC(); +}; + +#endif //GRENADEMOLOTOV_H diff --git a/game/server/hl2/grenade_pathfollower.h b/game/server/hl2/grenade_pathfollower.h new file mode 100644 index 0000000..5b2247b --- /dev/null +++ b/game/server/hl2/grenade_pathfollower.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot by wasteland scanner +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADEPATHFOLLOWER_H +#define GRENADEPATHFOLLOWER_H + +#include "basegrenade_shared.h" + +class RocketTrail; + +class CGrenadePathfollower : public CBaseGrenade +{ +public: + DECLARE_CLASS( CGrenadePathfollower, CBaseGrenade ); + + static CGrenadePathfollower* CreateGrenadePathfollower( string_t sModelName, string_t sFlySound, const Vector &vecOrigin, const QAngle &vecAngles, edict_t *pentOwner ); + + CHandle m_hRocketTrail; + CBaseEntity* m_pPathTarget; // path corner we are heading towards + float m_flFlySpeed; + string_t m_sFlySound; + float m_flNextFlySoundTime; + + Class_T Classify( void); + void Spawn( void ); + void AimThink( void ); + void GrenadeTouch( CBaseEntity *pOther ); + void Event_Killed( const CTakeDamageInfo &info ); + void Launch( float flLaunchSpeed, string_t sPathCornerName); + void PlayFlySound(void); + + void EXPORT Detonate(void); + + CGrenadePathfollower(void); + ~CGrenadePathfollower(void); + + virtual void Precache(); + + DECLARE_DATADESC(); +}; + +#endif //GRENADEPATHFOLLOWER_H diff --git a/game/server/hl2/grenade_satchel.h b/game/server/hl2/grenade_satchel.h new file mode 100644 index 0000000..d614dbc --- /dev/null +++ b/game/server/hl2/grenade_satchel.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Satchel Charge +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SATCHEL_H +#define SATCHEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "basegrenade_shared.h" +#include "hl2mp/weapon_slam.h" + +class CSoundPatch; + +class CSatchelCharge : public CBaseGrenade +{ +public: + DECLARE_CLASS( CSatchelCharge, CBaseGrenade ); + + void Spawn( void ); + void Precache( void ); + void BounceSound( void ); + void UpdateSlideSound( void ); + void KillSlideSound(void); + void SatchelTouch( CBaseEntity *pOther ); + void SatchelThink( void ); + void SatchelUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + CSoundPatch* m_soundSlide; + float m_flSlideVolume; + float m_flNextBounceSoundTime; + bool m_bInAir; + Vector m_vLastPosition; + +public: + CWeapon_SLAM* m_pMyWeaponSLAM; // Who shot me.. + bool m_bIsAttached; + void Deactivate( void ); + + CSatchelCharge(); + ~CSatchelCharge(); + + DECLARE_DATADESC(); + +private: + void InitSlideSound(void); +}; + +#endif //SATCHEL_H diff --git a/game/server/hl2/grenade_spit.h b/game/server/hl2/grenade_spit.h new file mode 100644 index 0000000..562b852 --- /dev/null +++ b/game/server/hl2/grenade_spit.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot by bullsquid +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADESPIT_H +#define GRENADESPIT_H + +#include "basegrenade_shared.h" + +class CParticleSystem; + +enum SpitSize_e +{ + SPIT_SMALL, + SPIT_MEDIUM, + SPIT_LARGE, +}; + +#define SPIT_GRAVITY 600 + +class CGrenadeSpit : public CBaseGrenade +{ + DECLARE_CLASS( CGrenadeSpit, CBaseGrenade ); + +public: + CGrenadeSpit( void ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void Event_Killed( const CTakeDamageInfo &info ); + + virtual unsigned int PhysicsSolidMaskForEntity( void ) const { return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_WATER ); } + + void GrenadeSpitTouch( CBaseEntity *pOther ); + void SetSpitSize( int nSize ); + void Detonate( void ); + void Think( void ); + +private: + DECLARE_DATADESC(); + + void InitHissSound( void ); + + CHandle< CParticleSystem > m_hSpitEffect; + CSoundPatch *m_pHissSound; + bool m_bPlaySound; +}; + +#endif //GRENADESPIT_H diff --git a/game/server/hl2/grenade_tripmine.h b/game/server/hl2/grenade_tripmine.h new file mode 100644 index 0000000..d905edb --- /dev/null +++ b/game/server/hl2/grenade_tripmine.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADE_TRIPMINE_H +#define GRENADE_TRIPMINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" + +class CBeam; + + +class CTripmineGrenade : public CBaseGrenade +{ +public: + DECLARE_CLASS( CTripmineGrenade, CBaseGrenade ); + + CTripmineGrenade(); + void Spawn( void ); + void Precache( void ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + void WarningThink( void ); + void PowerupThink( void ); + void BeamBreakThink( void ); + void DelayDeathThink( void ); + void Event_Killed( const CTakeDamageInfo &info ); + + void MakeBeam( void ); + void KillBeam( void ); + +public: + EHANDLE m_hOwner; + +private: + float m_flPowerUp; + Vector m_vecDir; + Vector m_vecEnd; + float m_flBeamLength; + + CBeam *m_pBeam; + Vector m_posOwner; + Vector m_angleOwner; + + DECLARE_DATADESC(); +}; + +#endif // GRENADE_TRIPMINE_H diff --git a/game/server/hl2/grenade_tripwire.h b/game/server/hl2/grenade_tripwire.h new file mode 100644 index 0000000..1da7c92 --- /dev/null +++ b/game/server/hl2/grenade_tripwire.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Tripmine +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef TRIPWIRE_H +#define TRIPWIRE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" + +class CRopeKeyframe; + +// #################################################################### +// CTripwireHook +// +// This is what the tripwire shoots out at the end of the rope +// #################################################################### +class CTripwireHook : public CBaseAnimating +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CTripwireHook, CBaseAnimating ); + + EHANDLE m_hGrenade; + bool m_bAttached; + + void Spawn( void ); + void Precache( void ); + bool CreateVPhysics( void ); + void EndTouch( CBaseEntity *pOther ); + void SetVelocity( const Vector &velocity, const AngularImpulse &angVelocity ); +}; + +class CTripwireGrenade : public CBaseGrenade +{ +public: + DECLARE_CLASS( CTripwireGrenade, CBaseGrenade ); + + CTripwireGrenade(); + void Spawn( void ); + void Precache( void ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + void WarningThink( void ); + void PowerupThink( void ); + void RopeBreakThink( void ); + void FireThink( void ); + void Event_Killed( const CTakeDamageInfo &info ); + void Attach( void ); + + void MakeRope( void ); + void BreakRope( void ); + void ShakeRope( void ); + void FireMissile(const Vector &vTargetPos); + +private: + float m_flPowerUp; + Vector m_vecDir; + + int m_nMissileCount; + + Vector m_vTargetPos; + Vector m_vTargetOffset; + + CRopeKeyframe* m_pRope; + CTripwireHook* m_pHook; + + DECLARE_DATADESC(); +}; + +#endif //TRIPWIRE_H diff --git a/game/server/hl2/hl2_gamestats.h b/game/server/hl2/hl2_gamestats.h new file mode 100644 index 0000000..31a91a3 --- /dev/null +++ b/game/server/hl2/hl2_gamestats.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef HL2_GAMESTATS_H +#define HL2_GAMESTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "gamestats.h" + +class CHL2GameStats : public CBaseGameStats +{ + typedef CBaseGameStats BaseClass; + +public: + CHL2GameStats( void ); +}; + +#endif // EP1_GAMESTATS_H diff --git a/game/server/hl2/hl2_player.h b/game/server/hl2/hl2_player.h new file mode 100644 index 0000000..6e72bb9 --- /dev/null +++ b/game/server/hl2/hl2_player.h @@ -0,0 +1,384 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Player for HL2. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL2_PLAYER_H +#define HL2_PLAYER_H +#pragma once + + +#include "player.h" +#include "hl2_playerlocaldata.h" +#include "simtimer.h" +#include "soundenvelope.h" + +class CAI_Squad; +class CPropCombineBall; + +extern int TrainSpeed(int iSpeed, int iMax); +extern void CopyToBodyQue( CBaseAnimating *pCorpse ); + +#define ARMOR_DECAY_TIME 3.5f + +enum HL2PlayerPhysFlag_e +{ + // 1 -- 5 are used by enum PlayerPhysFlag_e in player.h + + PFLAG_ONBARNACLE = ( 1<<6 ) // player is hangning from the barnalce +}; + +class IPhysicsPlayerController; +class CLogicPlayerProxy; + +struct commandgoal_t +{ + Vector m_vecGoalLocation; + CBaseEntity *m_pGoalEntity; +}; + +// Time between checks to determine whether NPCs are illuminated by the flashlight +#define FLASHLIGHT_NPC_CHECK_INTERVAL 0.4 + +//---------------------------------------------------- +// Definitions for weapon slots +//---------------------------------------------------- +#define WEAPON_MELEE_SLOT 0 +#define WEAPON_SECONDARY_SLOT 1 +#define WEAPON_PRIMARY_SLOT 2 +#define WEAPON_EXPLOSIVE_SLOT 3 +#define WEAPON_TOOL_SLOT 4 + +//============================================================================= +//============================================================================= +class CSuitPowerDevice +{ +public: + CSuitPowerDevice( int bitsID, float flDrainRate ) { m_bitsDeviceID = bitsID; m_flDrainRate = flDrainRate; } +private: + int m_bitsDeviceID; // tells what the device is. DEVICE_SPRINT, DEVICE_FLASHLIGHT, etc. BITMASK!!!!! + float m_flDrainRate; // how quickly does this device deplete suit power? ( percent per second ) + +public: + int GetDeviceID( void ) const { return m_bitsDeviceID; } + float GetDeviceDrainRate( void ) const + { + if( g_pGameRules->GetSkillLevel() == SKILL_EASY && hl2_episodic.GetBool() && !(GetDeviceID()&bits_SUIT_DEVICE_SPRINT) ) + return m_flDrainRate * 0.5f; + else + return m_flDrainRate; + } +}; + +//============================================================================= +// >> HL2_PLAYER +//============================================================================= +class CHL2_Player : public CBasePlayer +{ +public: + DECLARE_CLASS( CHL2_Player, CBasePlayer ); + + CHL2_Player(); + ~CHL2_Player( void ); + + static CHL2_Player *CreatePlayer( const char *className, edict_t *ed ) + { + CHL2_Player::s_PlayerEdict = ed; + return (CHL2_Player*)CreateEntityByName( className ); + } + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + virtual void CreateCorpse( void ) { CopyToBodyQue( this ); }; + + virtual void Precache( void ); + virtual void Spawn(void); + virtual void Activate( void ); + virtual void CheatImpulseCommands( int iImpulse ); + virtual void PlayerRunCommand( CUserCmd *ucmd, IMoveHelper *moveHelper); + virtual void PlayerUse ( void ); + virtual void SuspendUse( float flDuration ) { m_flTimeUseSuspended = gpGlobals->curtime + flDuration; } + virtual void UpdateClientData( void ); + virtual void OnRestore(); + virtual void StopLoopingSounds( void ); + virtual void Splash( void ); + virtual void ModifyOrAppendPlayerCriteria( AI_CriteriaSet& set ); + + void DrawDebugGeometryOverlays(void); + + virtual Vector EyeDirection2D( void ); + virtual Vector EyeDirection3D( void ); + + virtual void CommanderMode(); + + virtual bool ClientCommand( const CCommand &args ); + + // from cbasecombatcharacter + void InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity ); + WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); + + Class_T Classify ( void ); + + // from CBasePlayer + virtual void SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize ); + + // Suit Power Interface + void SuitPower_Update( void ); + bool SuitPower_Drain( float flPower ); // consume some of the suit's power. + void SuitPower_Charge( float flPower ); // add suit power. + void SuitPower_SetCharge( float flPower ) { m_HL2Local.m_flSuitPower = flPower; } + void SuitPower_Initialize( void ); + bool SuitPower_IsDeviceActive( const CSuitPowerDevice &device ); + bool SuitPower_AddDevice( const CSuitPowerDevice &device ); + bool SuitPower_RemoveDevice( const CSuitPowerDevice &device ); + bool SuitPower_ShouldRecharge( void ); + float SuitPower_GetCurrentPercentage( void ) { return m_HL2Local.m_flSuitPower; } + + void SetFlashlightEnabled( bool bState ); + + // Apply a battery + bool ApplyBattery( float powerMultiplier = 1.0 ); + + // Commander Mode for controller NPCs + enum CommanderCommand_t + { + CC_NONE, + CC_TOGGLE, + CC_FOLLOW, + CC_SEND, + }; + + void CommanderUpdate(); + void CommanderExecute( CommanderCommand_t command = CC_TOGGLE ); + bool CommanderFindGoal( commandgoal_t *pGoal ); + void NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity ); + CAI_BaseNPC *GetSquadCommandRepresentative(); + int GetNumSquadCommandables(); + int GetNumSquadCommandableMedics(); + + // Locator + void UpdateLocatorPosition( const Vector &vecPosition ); + + // Sprint Device + void StartAutoSprint( void ); + void StartSprinting( void ); + void StopSprinting( void ); + void InitSprinting( void ); + bool IsSprinting( void ) { return m_fIsSprinting; } + bool CanSprint( void ); + void EnableSprint( bool bEnable); + + bool CanZoom( CBaseEntity *pRequester ); + void ToggleZoom(void); + void StartZooming( void ); + void StopZooming( void ); + bool IsZooming( void ); + void CheckSuitZoom( void ); + + // Walking + void StartWalking( void ); + void StopWalking( void ); + bool IsWalking( void ) { return m_fIsWalking; } + + // Aiming heuristics accessors + virtual float GetIdleTime( void ) const { return ( m_flIdleTime - m_flMoveTime ); } + virtual float GetMoveTime( void ) const { return ( m_flMoveTime - m_flIdleTime ); } + virtual float GetLastDamageTime( void ) const { return m_flLastDamageTime; } + virtual bool IsDucking( void ) const { return !!( GetFlags() & FL_DUCKING ); } + + virtual bool PassesDamageFilter( const CTakeDamageInfo &info ); + void InputIgnoreFallDamage( inputdata_t &inputdata ); + void InputIgnoreFallDamageWithoutReset( inputdata_t &inputdata ); + void InputEnableFlashlight( inputdata_t &inputdata ); + void InputDisableFlashlight( inputdata_t &inputdata ); + + const impactdamagetable_t &GetPhysicsImpactDamageTable(); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual void OnDamagedByExplosion( const CTakeDamageInfo &info ); + bool ShouldShootMissTarget( CBaseCombatCharacter *pAttacker ); + + void CombineBallSocketed( CPropCombineBall *pCombineBall ); + + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + + virtual void GetAutoaimVector( autoaim_params_t ¶ms ); + bool ShouldKeepLockedAutoaimTarget( EHANDLE hLockedTarget ); + + void SetLocatorTargetEntity( CBaseEntity *pEntity ) { m_hLocatorTargetEntity.Set( pEntity ); } + + virtual int GiveAmmo( int nCount, int nAmmoIndex, bool bSuppressSound); + virtual bool BumpWeapon( CBaseCombatWeapon *pWeapon ); + + virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); + virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); + virtual bool Weapon_Lower( void ); + virtual bool Weapon_Ready( void ); + virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); + virtual bool Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon ); + + void FirePlayerProxyOutput( const char *pszOutputName, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller ); + + CLogicPlayerProxy *GetPlayerProxy( void ); + + // Flashlight Device + void CheckFlashlight( void ); + int FlashlightIsOn( void ); + void FlashlightTurnOn( void ); + void FlashlightTurnOff( void ); + bool IsIlluminatedByFlashlight( CBaseEntity *pEntity, float *flReturnDot ); + void SetFlashlightPowerDrainScale( float flScale ) { m_flFlashlightPowerDrainScale = flScale; } + + // Underwater breather device + virtual void SetPlayerUnderwater( bool state ); + virtual bool CanBreatheUnderwater() const { return m_HL2Local.m_flSuitPower > 0.0f; } + + // physics interactions + virtual void PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize ); + virtual bool IsHoldingEntity( CBaseEntity *pEnt ); + virtual void ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldindThis ); + virtual float GetHeldObjectMass( IPhysicsObject *pHeldObject ); + + virtual bool IsFollowingPhysics( void ) { return (m_afPhysicsFlags & PFLAG_ONBARNACLE) > 0; } + void InputForceDropPhysObjects( inputdata_t &data ); + + virtual void Event_Killed( const CTakeDamageInfo &info ); + void NotifyScriptsOfDeath( void ); + + // override the test for getting hit + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + + LadderMove_t *GetLadderMove() { return &m_HL2Local.m_LadderMove; } + virtual void ExitLadder(); + virtual surfacedata_t *GetLadderSurface( const Vector &origin ); + + virtual void EquipSuit( bool bPlayEffects = true ); + virtual void RemoveSuit( void ); + void HandleAdmireGlovesAnimation( void ); + void StartAdmireGlovesAnimation( void ); + + void HandleSpeedChanges( void ); + + void SetControlClass( Class_T controlClass ) { m_nControlClass = controlClass; } + + void StartWaterDeathSounds( void ); + void StopWaterDeathSounds( void ); + + bool IsWeaponLowered( void ) { return m_HL2Local.m_bWeaponLowered; } + void HandleArmorReduction( void ); + void StartArmorReduction( void ) { m_flArmorReductionTime = gpGlobals->curtime + ARMOR_DECAY_TIME; + m_iArmorReductionFrom = ArmorValue(); + } + + void MissedAR2AltFire(); + + inline void EnableCappedPhysicsDamage(); + inline void DisableCappedPhysicsDamage(); + + // HUD HINTS + void DisplayLadderHudHint(); + + CSoundPatch *m_sndLeeches; + CSoundPatch *m_sndWaterSplashes; + +protected: + virtual void PreThink( void ); + virtual void PostThink( void ); + virtual bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + virtual void UpdateWeaponPosture( void ); + + virtual void ItemPostFrame(); + virtual void PlayUseDenySound(); + +private: + bool CommanderExecuteOne( CAI_BaseNPC *pNpc, const commandgoal_t &goal, CAI_BaseNPC **Allies, int numAllies ); + + void OnSquadMemberKilled( inputdata_t &data ); + + Class_T m_nControlClass; // Class when player is controlling another entity + // This player's HL2 specific data that should only be replicated to + // the player and not to other players. + CNetworkVarEmbedded( CHL2PlayerLocalData, m_HL2Local ); + + float m_flTimeAllSuitDevicesOff; + + bool m_bSprintEnabled; // Used to disable sprint temporarily + bool m_bIsAutoSprinting; // A proxy for holding down the sprint key. + float m_fAutoSprintMinTime; // Minimum time to maintain autosprint regardless of player speed. + + CNetworkVar( bool, m_fIsSprinting ); + CNetworkVarForDerived( bool, m_fIsWalking ); + +protected: // Jeep: Portal_Player needs access to this variable to overload PlayerUse for picking up objects through portals + bool m_bPlayUseDenySound; // Signaled by PlayerUse, but can be unset by HL2 ladder code... + +private: + + CAI_Squad * m_pPlayerAISquad; + CSimpleSimTimer m_CommanderUpdateTimer; + float m_RealTimeLastSquadCommand; + CommanderCommand_t m_QueuedCommand; + + Vector m_vecMissPositions[16]; + int m_nNumMissPositions; + + float m_flTimeIgnoreFallDamage; + bool m_bIgnoreFallDamageResetAfterImpact; + + // Suit power fields + float m_flSuitPowerLoad; // net suit power drain (total of all device's drainrates) + float m_flAdmireGlovesAnimTime; + + float m_flNextFlashlightCheckTime; + float m_flFlashlightPowerDrainScale; + + // Aiming heuristics code + float m_flIdleTime; //Amount of time we've been motionless + float m_flMoveTime; //Amount of time we've been in motion + float m_flLastDamageTime; //Last time we took damage + float m_flTargetFindTime; + + EHANDLE m_hPlayerProxy; + + bool m_bFlashlightDisabled; + bool m_bUseCappedPhysicsDamageTable; + + float m_flArmorReductionTime; + int m_iArmorReductionFrom; + + float m_flTimeUseSuspended; + + CSimpleSimTimer m_LowerWeaponTimer; + CSimpleSimTimer m_AutoaimTimer; + + EHANDLE m_hLockedAutoAimEntity; + + EHANDLE m_hLocatorTargetEntity; // The entity that's being tracked by the suit locator. + + float m_flTimeNextLadderHint; // Next time we're eligible to display a HUD hint about a ladder. + + friend class CHL2GameMovement; +}; + + +//----------------------------------------------------------------------------- +// FIXME: find a better way to do this +// Switches us to a physics damage table that caps the max damage. +//----------------------------------------------------------------------------- +void CHL2_Player::EnableCappedPhysicsDamage() +{ + m_bUseCappedPhysicsDamageTable = true; +} + + +void CHL2_Player::DisableCappedPhysicsDamage() +{ + m_bUseCappedPhysicsDamageTable = false; +} + + +#endif //HL2_PLAYER_H diff --git a/game/server/hl2/hl2_playerlocaldata.h b/game/server/hl2/hl2_playerlocaldata.h new file mode 100644 index 0000000..e4c8334 --- /dev/null +++ b/game/server/hl2/hl2_playerlocaldata.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL2_PLAYERLOCALDATA_H +#define HL2_PLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkvar.h" + +#include "hl_movedata.h" + +//----------------------------------------------------------------------------- +// Purpose: Player specific data for HL2 ( sent only to local player, too ) +//----------------------------------------------------------------------------- +class CHL2PlayerLocalData +{ +public: + // Save/restore + DECLARE_SIMPLE_DATADESC(); + DECLARE_CLASS_NOBASE( CHL2PlayerLocalData ); + DECLARE_EMBEDDED_NETWORKVAR(); + + CHL2PlayerLocalData(); + + CNetworkVar( float, m_flSuitPower ); + CNetworkVar( bool, m_bZooming ); + CNetworkVar( int, m_bitsActiveDevices ); + CNetworkVar( int, m_iSquadMemberCount ); + CNetworkVar( int, m_iSquadMedicCount ); + CNetworkVar( bool, m_fSquadInFollowMode ); + CNetworkVar( bool, m_bWeaponLowered ); + CNetworkVar( EHANDLE, m_hAutoAimTarget ); + CNetworkVar( Vector, m_vecAutoAimPoint ); + CNetworkVar( bool, m_bDisplayReticle ); + CNetworkVar( bool, m_bStickyAutoAim ); + CNetworkVar( bool, m_bAutoAimTarget ); +#ifdef HL2_EPISODIC + CNetworkVar( float, m_flFlashBattery ); + CNetworkVar( Vector, m_vecLocatorOrigin ); +#endif + + // Ladder related data + CNetworkVar( EHANDLE, m_hLadder ); + LadderMove_t m_LadderMove; +}; + +EXTERN_SEND_TABLE(DT_HL2Local); + + +#endif // HL2_PLAYERLOCALDATA_H diff --git a/game/server/hl2/info_darknessmode_lightsource.h b/game/server/hl2/info_darknessmode_lightsource.h new file mode 100644 index 0000000..51f523a --- /dev/null +++ b/game/server/hl2/info_darknessmode_lightsource.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef INFO_DARKNESSMODE_LIGHTSOURCE_H +#define INFO_DARKNESSMODE_LIGHTSOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +// Default distance from lightsources that entities are considered visible +// NOTE!!! This is bigger by a factor of to deal with fixing a bug from HL2. See dlight_t.h +#define DARKNESS_LIGHTSOURCE_SIZE (256.0f*1.2f) + +void AddEntityToDarknessCheck( CBaseEntity *pEntity, float flLightRadius = DARKNESS_LIGHTSOURCE_SIZE ); +void RemoveEntityFromDarknessCheck( CBaseEntity *pEntity ); +bool LookerCouldSeeTargetInDarkness( CBaseEntity *pLooker, CBaseEntity *pTarget ); +bool DarknessLightSourceWithinRadius( CBaseEntity *pLooker, float flRadius ); + +#endif // INFO_DARKNESSMODE_LIGHTSOURCE_H diff --git a/game/server/hl2/item_dynamic_resupply.h b/game/server/hl2/item_dynamic_resupply.h new file mode 100644 index 0000000..8c2d881 --- /dev/null +++ b/game/server/hl2/item_dynamic_resupply.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ITEM_DYNAMIC_RESUPPLY_H +#define ITEM_DYNAMIC_RESUPPLY_H + +#ifdef _WIN32 +#pragma once +#endif + + +// Spawnflags +#define SF_DYNAMICRESUPPLY_USE_MASTER 1 +#define SF_DYNAMICRESUPPLY_IS_MASTER 2 +#define SF_DYNAMICRESUPPLY_ALWAYS_SPAWN 4 // even if the player has met his target +#define SF_DYNAMICRESUPPLY_FALLBACK_TO_VIAL 8 // If we fail to spawn anything, spawn a health vial +#define SF_DYNAMICRESUPPLY_ALTERNATE_MASTER 16 // Don't assume role as master on activate, but don't think either + +float DynamicResupply_GetDesiredHealthPercentage( void ); +void DynamicResupply_InitFromAlternateMaster( CBaseEntity *pResupply, string_t iszMaster ); + +#endif // ITEM_DYNAMIC_RESUPPLY_H diff --git a/game/server/hl2/npc_BaseZombie.h b/game/server/hl2/npc_BaseZombie.h new file mode 100644 index 0000000..d4800f3 --- /dev/null +++ b/game/server/hl2/npc_BaseZombie.h @@ -0,0 +1,291 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_BASEZOMBIE_H +#define NPC_BASEZOMBIE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_blended_movement.h" +#include "soundenvelope.h" +#include "ai_behavior_actbusy.h" + +#define ZOM_ATTN_FOOTSTEP ATTN_IDLE + +#define ENVELOPE_CONTROLLER (CSoundEnvelopeController::GetController()) + +#define ZOMBIE_MELEE_REACH 55 + +extern int AE_ZOMBIE_ATTACK_RIGHT; +extern int AE_ZOMBIE_ATTACK_LEFT; +extern int AE_ZOMBIE_ATTACK_BOTH; +extern int AE_ZOMBIE_SWATITEM; +extern int AE_ZOMBIE_STARTSWAT; +extern int AE_ZOMBIE_STEP_LEFT; +extern int AE_ZOMBIE_STEP_RIGHT; +extern int AE_ZOMBIE_SCUFF_LEFT; +extern int AE_ZOMBIE_SCUFF_RIGHT; +extern int AE_ZOMBIE_ATTACK_SCREAM; +extern int AE_ZOMBIE_GET_UP; +extern int AE_ZOMBIE_POUND; + +#define ZOMBIE_BODYGROUP_HEADCRAB 1 // The crab on our head + +// Pass these to claw attack so we know where to draw the blood. +#define ZOMBIE_BLOOD_LEFT_HAND 0 +#define ZOMBIE_BLOOD_RIGHT_HAND 1 +#define ZOMBIE_BLOOD_BOTH_HANDS 2 +#define ZOMBIE_BLOOD_BITE 3 + + +enum HeadcrabRelease_t +{ + RELEASE_NO, + RELEASE_IMMEDIATE, // release the headcrab right now! + RELEASE_SCHEDULED, // release the headcrab through the AI schedule. + RELEASE_VAPORIZE, // just destroy the crab. + RELEASE_RAGDOLL, // release a dead crab + RELEASE_RAGDOLL_SLICED_OFF // toss the crab up a bit +}; + + +//========================================================= +// schedules +//========================================================= +enum +{ + SCHED_ZOMBIE_CHASE_ENEMY = LAST_SHARED_SCHEDULE, + SCHED_ZOMBIE_MOVE_SWATITEM, + SCHED_ZOMBIE_SWATITEM, + SCHED_ZOMBIE_ATTACKITEM, + SCHED_ZOMBIE_RELEASECRAB, + SCHED_ZOMBIE_MOVE_TO_AMBUSH, + SCHED_ZOMBIE_WAIT_AMBUSH, + SCHED_ZOMBIE_WANDER_MEDIUM, // medium range wandering behavior. + SCHED_ZOMBIE_WANDER_FAIL, + SCHED_ZOMBIE_WANDER_STANDOFF, + SCHED_ZOMBIE_MELEE_ATTACK1, + SCHED_ZOMBIE_POST_MELEE_WAIT, + + LAST_BASE_ZOMBIE_SCHEDULE, +}; + +//========================================================= +// tasks +//========================================================= +enum +{ + TASK_ZOMBIE_DELAY_SWAT = LAST_SHARED_TASK, + TASK_ZOMBIE_GET_PATH_TO_PHYSOBJ, + TASK_ZOMBIE_SWAT_ITEM, + TASK_ZOMBIE_DIE, + TASK_ZOMBIE_RELEASE_HEADCRAB, + TASK_ZOMBIE_WAIT_POST_MELEE, + + LAST_BASE_ZOMBIE_TASK, +}; + + +//========================================================= +// Zombie conditions +//========================================================= +enum Zombie_Conds +{ + COND_ZOMBIE_CAN_SWAT_ATTACK = LAST_SHARED_CONDITION, + COND_ZOMBIE_RELEASECRAB, + COND_ZOMBIE_LOCAL_MELEE_OBSTRUCTION, + + LAST_BASE_ZOMBIE_CONDITION, +}; + + + +typedef CAI_BlendingHost< CAI_BehaviorHost > CAI_BaseZombieBase; + +//========================================================= +//========================================================= +abstract_class CNPC_BaseZombie : public CAI_BaseZombieBase +{ + DECLARE_CLASS( CNPC_BaseZombie, CAI_BaseZombieBase ); + +public: + CNPC_BaseZombie( void ); + ~CNPC_BaseZombie( void ); + + void Spawn( void ); + void Precache( void ); + void StartTouch( CBaseEntity *pOther ); + bool CreateBehaviors(); + float MaxYawSpeed( void ); + bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + Class_T Classify( void ); + Disposition_t IRelationType( CBaseEntity *pTarget ); + void HandleAnimEvent( animevent_t *pEvent ); + + void OnStateChange( NPC_STATE OldState, NPC_STATE NewState ); + + void KillMe( void ) + { + m_iHealth = 5; + OnTakeDamage( CTakeDamageInfo( this, this, m_iHealth * 2, DMG_GENERIC ) ); + } + + int MeleeAttack1Conditions ( float flDot, float flDist ); + virtual float GetClawAttackRange() const { return ZOMBIE_MELEE_REACH; } + + // No range attacks + int RangeAttack1Conditions ( float flDot, float flDist ) { return( 0 ); } + + virtual float GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual float GetReactionDelay( CBaseEntity *pEnemy ) { return 0.0; } + + virtual int SelectSchedule ( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual void BuildScheduleTestBits( void ); + + virtual int TranslateSchedule( int scheduleType ); + virtual Activity NPC_TranslateActivity( Activity baseAct ); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + void GatherConditions( void ); + void PrescheduleThink( void ); + + virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual bool BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector ); + void StopLoopingSounds(); + virtual void OnScheduleChange( void ); + + virtual void PoundSound(); + + // Custom damage/death + bool ShouldIgnite( const CTakeDamageInfo &info ); + bool ShouldIgniteZombieGib( void ); + virtual bool IsChopped( const CTakeDamageInfo &info ); + virtual bool IsSquashed( const CTakeDamageInfo &info ) { return false; } + virtual void DieChopped( const CTakeDamageInfo &info ); + virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false ); + void CopyRenderColorTo( CBaseEntity *pOther ); + + virtual bool ShouldBecomeTorso( const CTakeDamageInfo &info, float flDamageThreshold ); + virtual HeadcrabRelease_t ShouldReleaseHeadcrab( const CTakeDamageInfo &info, float flDamageThreshold ); + + // Headcrab releasing/breaking apart + void RemoveHead( void ); + virtual void SetZombieModel( void ) { }; + virtual void BecomeTorso( const Vector &vecTorsoForce, const Vector &vecLegsForce ); + virtual bool CanBecomeLiveTorso() { return false; } + virtual bool HeadcrabFits( CBaseAnimating *pCrab ); + void ReleaseHeadcrab( const Vector &vecOrigin, const Vector &vecVelocity, bool fRemoveHead, bool fRagdollBody, bool fRagdollCrab = false ); + void SetHeadcrabSpawnLocation( int iCrabAttachment, CBaseAnimating *pCrab ); + + // Slumping/sleeping + bool IsSlumped( void ); + bool IsGettingUp( void ); + + // Swatting physics objects + int GetSwatActivity( void ); + bool FindNearestPhysicsObject( int iMaxMass ); + float DistToPhysicsEnt( void ); + virtual bool CanSwatPhysicsObjects( void ) { return true; } + + // Returns whether we must be very near our enemy to attack them. + virtual bool MustCloseToAttack(void) { return true; } + + virtual CBaseEntity *ClawAttack( float flDist, int iDamage, QAngle &qaViewPunch, Vector &vecVelocityPunch, int BloodOrigin ); + + // Sounds & sound envelope + virtual bool ShouldPlayFootstepMoan( void ); + virtual void PainSound( const CTakeDamageInfo &info ) = 0; + virtual void AlertSound( void ) = 0; + virtual void IdleSound( void ) = 0; + virtual void AttackSound( void ) = 0; + virtual void AttackHitSound( void ) = 0; + virtual void AttackMissSound( void ) = 0; + virtual void FootstepSound( bool fRightFoot ) = 0; + virtual void FootscuffSound( bool fRightFoot ) = 0; + + // make a sound Alyx can hear when in darkness mode + void MakeAISpookySound( float volume, float duration = 0.5 ); + + virtual bool CanPlayMoanSound(); + virtual void MoanSound( envelopePoint_t *pEnvelope, int iEnvelopeSize ); + bool ShouldPlayIdleSound( void ) { return false; } + + virtual const char *GetMoanSound( int nSound ) = 0; + virtual const char *GetHeadcrabClassname( void ) = 0; + virtual const char *GetLegsModel( void ) = 0; + virtual const char *GetTorsoModel( void ) = 0; + virtual const char *GetHeadcrabModel( void ) = 0; + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy ); + virtual Vector HeadTarget( const Vector &posSrc ); + virtual float GetAutoAimRadius(); + virtual void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition ); + + bool OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + + virtual bool AllowedToIgnite( void ) { return true; } + +public: + CAI_ActBusyBehavior m_ActBusyBehavior; + + + +protected: + + CSoundPatch *m_pMoanSound; + + bool m_fIsTorso; // is this is a half-zombie? + bool m_fIsHeadless; // is this zombie headless + + float m_flNextFlinch; + + bool m_bHeadShot; // Used to determine the survival of our crab beyond our death. + + // + // Zombies catch on fire if they take too much burn damage in a given time period. + // + float m_flBurnDamage; // Keeps track of how much burn damage we've incurred in the last few seconds. + float m_flBurnDamageResetTime; // Time at which we reset the burn damage. + + EHANDLE m_hPhysicsEnt; + + float m_flNextMoanSound; + float m_flNextSwat; + float m_flNextSwatScan; + float m_crabHealth; + float m_flMoanPitch; + + EHANDLE m_hObstructor; + + static int g_numZombies; // counts total number of existing zombies. + + int m_iMoanSound; // each zombie picks one of the 4 and keeps it. + + static int ACT_ZOM_SWATLEFTMID; + static int ACT_ZOM_SWATRIGHTMID; + static int ACT_ZOM_SWATLEFTLOW; + static int ACT_ZOM_SWATRIGHTLOW; + static int ACT_ZOM_RELEASECRAB; + static int ACT_ZOM_FALL; + + DECLARE_DATADESC(); + + DEFINE_CUSTOM_AI; + +private: + bool m_bIsSlumped; + +}; + +#endif // NPC_BASEZOMBIE_H diff --git a/game/server/hl2/npc_alyx.h b/game/server/hl2/npc_alyx.h new file mode 100644 index 0000000..96c1c91 --- /dev/null +++ b/game/server/hl2/npc_alyx.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base combat character with no AI +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include "ai_baseactor.h" +#include "npc_playercompanion.h" +#include "ai_behavior_holster.h" + +class CNPC_Alyx : public CNPC_PlayerCompanion +{ +public: + DECLARE_CLASS( CNPC_Alyx, CNPC_PlayerCompanion ); + + bool CreateBehaviors(); + void Spawn( void ); + void SelectModel(); + void Precache( void ); + void SetupAlyxWithoutParent( void ); + void CreateEmpTool( void ); + void PrescheduleThink( void ); + Class_T Classify ( void ); + void HandleAnimEvent( animevent_t *pEvent ); + Activity NPC_TranslateActivity ( Activity activity ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + bool ShouldLookForBetterWeapon() { return false; } + bool IsReadinessCapable() { return false; } + void DeathSound( const CTakeDamageInfo &info ); + + EHANDLE m_hEmpTool; + + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; +}; diff --git a/game/server/hl2/npc_alyx_episodic.h b/game/server/hl2/npc_alyx_episodic.h new file mode 100644 index 0000000..5657dae --- /dev/null +++ b/game/server/hl2/npc_alyx_episodic.h @@ -0,0 +1,289 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base combat character with no AI +// +//=====================================================================================// + +#include "ai_baseactor.h" +#include "npc_playercompanion.h" +#include "ai_behavior_holster.h" +#include "ai_behavior_functank.h" +#include "soundenvelope.h" + +extern ConVar npc_alyx_readiness; + +class CNPC_Alyx : public CNPC_PlayerCompanion +{ +public: + DECLARE_CLASS( CNPC_Alyx, CNPC_PlayerCompanion ); + + // fast class list + CNPC_Alyx *m_pNext; + + virtual void ModifyOrAppendCriteria( AI_CriteriaSet &set ); + + bool ForceVehicleInteraction( const char *lpszInteractionName, CBaseCombatCharacter *pOther ); + + CNPC_Alyx( ); + ~CNPC_Alyx( ); + + static CNPC_Alyx *GetAlyx( void ); + + bool CreateBehaviors(); + void Spawn( void ); + void Activate( void ); + void StopLoopingSounds( void ); + void SelectModel(); + void Precache( void ); + void SetupAlyxWithoutParent( void ); + void CreateEmpTool( void ); + void PrescheduleThink( void ); + void GatherConditions(); + bool ShouldPlayerAvoid( void ); + void AnalyzeGunfireSound( CSound *pSound ); + bool IsValidEnemy( CBaseEntity *pEnemy ); + void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + void EnemyIgnited( CAI_BaseNPC *pVictim ); + void CombineBallSocketed( int iNumBounces ); + void AimGun( void ); + Vector GetActualShootPosition( const Vector &shootOrigin ); + float MaxYawSpeed( void ); + void OnUpdateShotRegulator(); + bool IsCrouchedActivity( Activity activity ); + bool OnBeginMoveAndShoot(); + void SpeakAttacking( void ); + + virtual float GetJumpGravity() const { return 1.8f; } + + // Crouching + Vector GetCrouchEyeOffset( void ) { return Vector(0,0,50); } + Vector GetCrouchGunOffset( void ) { return Vector(0,0,40); } + bool EnemyIsValidCrouchTarget( CBaseEntity *pEnemy ); + bool Stand( void ); + bool Crouch( void ); + void DesireCrouch( void ); + + // Custom AI + void DoCustomCombatAI( void ); + void DoMobbedCombatAI( void ); + void DoCustomSpeechAI( void ); + + Disposition_t IRelationType( CBaseEntity *pTarget ); + int IRelationPriority( CBaseEntity *pTarget ); + + CAI_FollowBehavior &GetFollowBehavior( void ); + + Class_T Classify ( void ); + bool FValidateHintType( CAI_Hint *pHint ); + int ObjectCaps(); + void HandleAnimEvent( animevent_t *pEvent ); + bool FInViewCone( CBaseEntity *pEntity ); + bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false ); + bool CanSeeEntityInDarkness( CBaseEntity *pEntity ); + bool IsCoverPosition( const Vector &vecThreat, const Vector &vecPosition ); + Activity NPC_TranslateActivity ( Activity activity ); + bool ShouldDeferToFollowBehavior(); + void BuildScheduleTestBits(); + bool ShouldBehaviorSelectSchedule( CAI_BehaviorBase *pBehavior ); + int SelectSchedule( void ); + int SelectScheduleDanger( void ); + int TranslateSchedule( int scheduleType ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void OnStateChange( NPC_STATE OldState, NPC_STATE NewState ); + float LengthOfLastCombat( void ) const; + // bool IsNavigationUrgent(); + + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + bool CanBeHitByMeleeAttack( CBaseEntity *pAttacker ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + bool FCanCheckAttacks(); + float GetAttackDamageScale( CBaseEntity *pVictim ); + + + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 ); + + void HolsterPistol(); + void DrawPistol(); + void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL ); + + void SetEMPHolstered( bool bHolstered ) { m_bIsEMPHolstered = bHolstered; } + bool IsEMPHolstered() { return (!m_hEmpTool || m_hEmpTool->GetParent() != this || m_bIsEMPHolstered); } + + float GetReadinessDecay() { return 60.0f; } + virtual bool IsAllowedToAim(); + + virtual void PainSound( const CTakeDamageInfo &info ); + virtual void DeathSound( const CTakeDamageInfo &info ); + + // Hacking and object interaction + void SearchForInteractTargets(); + bool IsValidInteractTarget( CBaseEntity *pTarget ); + bool CanInteractWithTarget( CBaseEntity *pTarget ); + void SetInteractTarget( CBaseEntity *pTarget ); + bool HasInteractTarget() { return m_hHackTarget != NULL; } + CBaseEntity *GetInteractTarget() { return m_hHackTarget; } + void EmpZapTarget( CBaseEntity *pTarget ); + + virtual void OnSeeEntity( CBaseEntity *pEntity ); + + void InputAllowInteraction( inputdata_t &inputdata ) + { + m_bInteractionAllowed = true; + } + void InputDisallowInteraction( inputdata_t &inputdata ) + { + m_bInteractionAllowed = false; + } + void InputAllowDarknessSpeech( inputdata_t &inputdata ) + { + m_bDarknessSpeechAllowed = inputdata.value.Bool(); + } + void InputGiveEMP( inputdata_t &inputdata ); + void InputVehiclePunted( inputdata_t &inputdata ); + void InputOutsideTransition( inputdata_t &inputdata ); + + virtual void OnGivenWeapon( CBaseCombatWeapon *pNewWeapon ); + virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); + virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); + + // Blinding + virtual void PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot ); + void CheckBlindedByFlare( void ); + bool CanBeBlindedByFlashlight( bool bCheckLightSources ); + bool PlayerFlashlightOnMyEyes( CBasePlayer *pPlayer ); + bool BlindedByFlare( void ); + bool CanReload( void ); + + virtual bool PickTacticalLookTarget( AILookTargetArgs_t *pArgs ); + virtual void OnSelectedLookTarget( AILookTargetArgs_t *pArgs ); + virtual bool IsReadinessCapable( void ); + + virtual void ReadinessLevelChanged( int iPriorLevel ); + + bool IsAllowedToInteract(); + virtual void BarnacleDeathSound( void ); + + virtual const char *GetDeathMessageText( void ) { return "GAMEOVER_ALYXDEAD"; } + + PassengerState_e GetPassengerState( void ); + + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + bool PlayerInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter, bool ignoreHatedPlayers ); + +private: + EHANDLE m_hEmpTool; + EHANDLE m_hHackTarget; + CHandle m_hStealthLookTarget; + bool m_bInteractionAllowed; + float m_fTimeNextSearchForInteractTargets; + bool m_bDarknessSpeechAllowed; + bool m_bIsEMPHolstered; + bool m_bIsFlashlightBlind; + float m_fStayBlindUntil; + float m_flDontBlindUntil; + bool m_bSpokeLostPlayerInDarkness; + bool m_bPlayerFlashlightState; + bool m_bHadCondSeeEnemy; + string_t m_iszCurrentBlindScene; + float m_fTimeUntilNextDarknessFoundPlayer; + float m_fCombatStartTime; + float m_fCombatEndTime; + float m_flNextCrouchTime; + + CSoundPatch *m_sndDarknessBreathing; + + // Speech timers + // Theoretically, these shouldn't be needed. Instead, each response + // should prevent the concept being spoken for the desired time. But + // until the responses exists, Alyx will spam the response rules forever, + // so these timers stop that. + CRandStopwatch m_SpeechWatch_LostPlayer; + CSimpleSimTimer m_SpeechTimer_HeardSound; + CRandStopwatch m_SpeechWatch_SoundDelay; + CRandStopwatch m_SpeechWatch_BreathingRamp; + CRandStopwatch m_SpeechWatch_FoundPlayer; + + CAI_MoveMonitor m_MoveMonitor; + + enum WeaponType_t + { + WT_NONE, + WT_ALYXGUN, + WT_SMG1, + WT_SHOTGUN, + WT_AR2, + WT_OTHER, + }; + + int m_WeaponType; + + bool m_bShouldHaveEMP; + + CAI_FuncTankBehavior m_FuncTankBehavior; + + COutputEvent m_OnFinishInteractWithObject; + COutputEvent m_OnPlayerUse; + + bool RunningPassengerBehavior( void ); + + WeaponType_t ComputeWeaponType( CBaseEntity *pWeapon = NULL ); + WeaponType_t GetWeaponType() { return (WeaponType_t)m_WeaponType; } + bool HasShotgun() { Assert( m_WeaponType == ComputeWeaponType() ); return ( m_WeaponType == WT_SHOTGUN ); } + bool HasAlyxgun() { Assert( m_WeaponType == ComputeWeaponType() ); return ( m_WeaponType == WT_ALYXGUN ); } + bool HasAR2() { Assert( m_WeaponType == ComputeWeaponType() ); return ( m_WeaponType == WT_AR2 ); } + +private: + enum + { + COND_ALYX_HAS_INTERACT_TARGET = BaseClass::NEXT_CONDITION, + COND_ALYX_NO_INTERACT_TARGET, + COND_ALYX_CAN_INTERACT_WITH_TARGET, // Hack target is in a suitable state and location to hack + COND_ALYX_CAN_NOT_INTERACT_WITH_TARGET, + COND_ALYX_PLAYER_TURNED_ON_FLASHLIGHT, + COND_ALYX_PLAYER_TURNED_OFF_FLASHLIGHT, + COND_ALYX_PLAYER_FLASHLIGHT_EXPIRED, + COND_ALYX_IN_DARK, // lights are out and she can't see + }; + + enum + { + SCHED_ALYX_PREPARE_TO_INTERACT_WITH_TARGET = BaseClass::NEXT_SCHEDULE, + SCHED_ALYX_WAIT_TO_INTERACT_WITH_TARGET, + SCHED_ALYX_INTERACT_WITH_TARGET, + SCHED_ALYX_INTERACTION_INTERRUPTED, + SCHED_ALYX_FINISH_INTERACTING_WITH_TARGET, + SCHED_ALYX_HOLSTER_EMP, + SCHED_ALYX_ALERT_FACE_AWAYFROM_BESTSOUND, + SCHED_ALYX_RANGE_ATTACK1, + SCHED_ALYX_ALERT_REACT_TO_COMBAT_SOUND, + SCHED_ALYX_COMBAT_FACE, + SCHED_ALYX_WAKE_ANGRY, + SCHED_ALYX_NEW_WEAPON, + SCHED_ALYX_IDLE_STAND, + SCHED_ALYX_ALERT_FACE_BESTSOUND, + SCHED_ALYX_FALL_TO_GROUND, + }; + + enum + { + + TASK_ALYX_BEGIN_INTERACTION = BaseClass::NEXT_TASK, + TASK_ALYX_COMPLETE_INTERACTION, + TASK_ALYX_ANNOUNCE_HACK, + TASK_ALYX_GET_PATH_TO_INTERACT_TARGET, + TASK_ALYX_WAIT_HACKING, + TASK_ALYX_HOLSTER_PISTOL, + TASK_ALYX_DRAW_PISTOL, + TASK_ALYX_HOLSTER_AND_DESTROY_PISTOL, + TASK_ALYX_BUILD_COMBAT_FACE_PATH, + TASK_ALYX_SET_IDLE_ACTIVITY, + TASK_ALYX_FALL_TO_GROUND, + }; + + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; +}; diff --git a/game/server/hl2/npc_antlion.h b/game/server/hl2/npc_antlion.h new file mode 100644 index 0000000..1de3606 --- /dev/null +++ b/game/server/hl2/npc_antlion.h @@ -0,0 +1,418 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_ANTLION_H +#define NPC_ANTLION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_blended_movement.h" +#include "soundent.h" +#include "ai_behavior_follow.h" +#include "ai_behavior_assault.h" + +class CAntlionTemplateMaker; + +#define ANTLION_FOLLOW_DISTANCE 350 +#define ANTLION_FOLLOW_DISTANCE_SQR (ANTLION_FOLLOW_DISTANCE*ANTLION_FOLLOW_DISTANCE) +#define ANTLION_SKIN_COUNT 4 + +class CNPC_Antlion; + +// Antlion follow behavior +class CAI_AntlionFollowBehavior : public CAI_FollowBehavior +{ + typedef CAI_FollowBehavior BaseClass; + +public: + + CAI_AntlionFollowBehavior() + : BaseClass( AIF_ANTLION ) + { + } + + bool FarFromFollowTarget( void ) + { + return ( GetFollowTarget() && (GetAbsOrigin() - GetFollowTarget()->GetAbsOrigin()).LengthSqr() > ANTLION_FOLLOW_DISTANCE_SQR ); + } + + bool ShouldFollow( void ) + { + if ( GetFollowTarget() == NULL ) + return false; + + if ( GetEnemy() != NULL ) + return false; + + return true; + } +}; + +// +// Antlion class +// + +enum AntlionMoveState_e +{ + ANTLION_MOVE_FREE, + ANTLION_MOVE_FOLLOW, + ANTLION_MOVE_FIGHT_TO_GOAL, +}; + +#define SF_ANTLION_BURROW_ON_ELUDED ( 1 << 16 ) +#define SF_ANTLION_USE_GROUNDCHECKS ( 1 << 17 ) +#define SF_ANTLION_WORKER ( 1 << 18 ) // Use the "worker" model + +typedef CAI_BlendingHost< CAI_BehaviorHost > CAI_BaseAntlionBase; + +class CNPC_Antlion : public CAI_BaseAntlionBase +{ +public: + + DECLARE_CLASS( CNPC_Antlion, CAI_BaseAntlionBase ); + + CNPC_Antlion( void ); + + virtual float InnateRange1MinRange( void ) { return 50*12; } + virtual float InnateRange1MaxRange( void ) { return 250*12; } + + bool IsWorker( void ) const { return HasSpawnFlags( SF_ANTLION_WORKER ); } // NOTE: IsAntlionWorker function must agree! + + float GetIdealAccel( void ) const; + float MaxYawSpeed( void ); + bool FInViewCone( CBaseEntity *pEntity ); + bool FInViewCone( const Vector &vecSpot ); + + void Activate( void ); + void HandleAnimEvent( animevent_t *pEvent ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void IdleSound( void ); + void PainSound( const CTakeDamageInfo &info ); + void Precache( void ); + void Spawn( void ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + void BuildScheduleTestBits( void ); + void GatherConditions( void ); + void PrescheduleThink( void ); + void ZapThink( void ); + void BurrowUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + bool CreateVPhysics(); + + bool IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const; + bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sender = NULL ); + bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false ); + bool ShouldPlayIdleSound( void ); + bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + bool IsValidEnemy(CBaseEntity *pEnemy); + bool QueryHearSound( CSound *pSound ); + bool IsLightDamage( const CTakeDamageInfo &info ); + bool CreateBehaviors( void ); + bool ShouldHearBugbait( void ) { return ( m_bIgnoreBugbait == false ); } + int SelectSchedule( void ); + + void Touch( CBaseEntity *pOther ); + + virtual int RangeAttack1Conditions( float flDot, float flDist ); + virtual int MeleeAttack1Conditions( float flDot, float flDist ); + virtual int MeleeAttack2Conditions( float flDot, float flDist ); + virtual int GetSoundInterests( void ) { return (BaseClass::GetSoundInterests())|(SOUND_DANGER|SOUND_PHYSICS_DANGER|SOUND_THUMPER|SOUND_BUGBAIT); } + virtual bool IsHeavyDamage( const CTakeDamageInfo &info ); + + Class_T Classify( void ) { return CLASS_ANTLION; } + + void Event_Killed( const CTakeDamageInfo &info ); + bool FValidateHintType ( CAI_Hint *pHint ); + void GatherEnemyConditions( CBaseEntity *pEnemy ); + + bool IsAllied( void ); + bool ShouldGib( const CTakeDamageInfo &info ); + bool CorpseGib( const CTakeDamageInfo &info ); + + float GetMaxJumpSpeed() const { return 1024.0f; } + + void SetFightTarget( CBaseEntity *pTarget ); + void InputFightToPosition( inputdata_t &inputdata ); + void InputStopFightToPosition( inputdata_t &inputdata ); + void InputJumpAtTarget( inputdata_t &inputdata ); + + void SetFollowTarget( CBaseEntity *pTarget ); + int TranslateSchedule( int scheduleType ); + + virtual Activity NPC_TranslateActivity( Activity baseAct ); + + bool ShouldResumeFollow( void ); + bool ShouldAbandonFollow( void ); + + void SetMoveState( AntlionMoveState_e state ); + int ChooseMoveSchedule( void ); + + DECLARE_DATADESC(); + + bool m_bStartBurrowed; + float m_flNextJumpPushTime; + + void SetParentSpawnerName( const char *szName ) { m_strParentSpawner = MAKE_STRING( szName ); } + const char *GetParentSpawnerName( void ) { return STRING( m_strParentSpawner ); } + + virtual void StopLoopingSounds( void ); + bool AllowedToBePushed( void ); + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + virtual float GetAutoAimRadius() { return 36.0f; } + + void ClearBurrowPoint( const Vector &origin ); + + void Flip( bool bZapped = false ); + + bool CanBecomeRagdoll(); + + virtual void NotifyDeadFriend( CBaseEntity *pFriend ); + +private: + + inline CBaseEntity *EntityToWatch( void ); + void UpdateHead( void ); + + bool FindChasePosition( const Vector &targetPos, Vector &result ); + bool GetGroundPosition( const Vector &testPos, Vector &result ); + bool GetPathToSoundFleePoint( int soundType ); + inline bool IsFlipped( void ); + + void Burrow( void ); + void Unburrow( void ); + + void InputUnburrow( inputdata_t &inputdata ); + void InputBurrow( inputdata_t &inputdata ); + void InputBurrowAway( inputdata_t &inputdata ); + void InputDisableJump( inputdata_t &inputdata ); + void InputEnableJump( inputdata_t &inputdata ); + void InputIgnoreBugbait( inputdata_t &inputdata ); + void InputHearBugbait( inputdata_t &inputdata ); + + bool FindBurrow( const Vector &origin, float distance, int type, bool excludeNear = true ); + void CreateDust( bool placeDecal = true ); + + bool ValidBurrowPoint( const Vector &point ); + bool CheckLanding( void ); + bool Alone( void ); + bool CheckAlertRadius( void ); + bool ShouldJump( void ); + + void MeleeAttack( float distance, float damage, QAngle& viewPunch, Vector& shove ); + void SetWings( bool state ); + void StartJump( void ); + void LockJumpNode( void ); + + bool IsUnusableNode(int iNodeID, CAI_Hint *pHint); + + bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + + void ManageFleeCapabilities( bool bEnable ); + + int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + bool IsFirmlyOnGround( void ); + void CascadePush( const Vector &vecForce ); + + virtual bool CanRunAScriptedNPCInteraction( bool bForced = false ); + + virtual void Ignite ( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner ); + virtual bool GetSpitVector( const Vector &vecStartPos, const Vector &vecTarget, Vector *vecOut ); + virtual bool InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + virtual bool FCanCheckAttacks( void ); + + bool SeenEnemyWithinTime( float flTime ); + void DelaySquadAttack( float flDuration ); + +#if HL2_EPISODIC + void DoPoisonBurst(); +#endif + + float m_flIdleDelay; + float m_flBurrowTime; + float m_flJumpTime; + float m_flAlertRadius; + + float m_flPounceTime; + int m_iUnBurrowAttempts; + int m_iContext; //for FValidateHintType context + + Vector m_vecSaveSpitVelocity; // Saved when we start to attack and used if we failed to get a clear shot once we release + + CAI_AntlionFollowBehavior m_FollowBehavior; + CAI_AssaultBehavior m_AssaultBehavior; + + AntlionMoveState_e m_MoveState; + + COutputEvent m_OnReachFightGoal; //Reached our scripted destination to fight to + COutputEvent m_OnUnBurrowed; //Unburrowed + + Vector m_vecSavedJump; + Vector m_vecLastJumpAttempt; + + float m_flIgnoreSoundTime; // Sound time to ignore if earlier than + float m_flNextAcknowledgeTime; // Next time an antlion can make an acknowledgement noise + float m_flSuppressFollowTime; // Amount of time to suppress our follow time + float m_flObeyFollowTime; // A range of time the antlions must be obedient + + Vector m_vecHeardSound; + bool m_bHasHeardSound; + bool m_bAgitatedSound; //Playing agitated sound? + bool m_bWingsOpen; //Are the wings open? + bool m_bIgnoreBugbait; //If the antlion should ignore bugbait sounds + string_t m_strParentSpawner; //Name of our spawner + + EHANDLE m_hFollowTarget; + EHANDLE m_hFightGoalTarget; + float m_flEludeDistance; //Distance until the antlion will consider himself "eluded" if so flagged + bool m_bLeapAttack; + bool m_bDisableJump; + float m_flTimeDrown; + float m_flTimeDrownSplash; + bool m_bDontExplode; // Suppresses worker poison burst when drowning, failing to unburrow, etc. + bool m_bLoopingStarted; + bool m_bSuppressUnburrowEffects; // Don't kick up dust when spawning +#if HL2_EPISODIC + bool m_bHasDoneAirAttack; ///< only allowed to apply this damage once per glide +#endif + + bool m_bForcedStuckJump; + int m_nBodyBone; + + // Used to trigger a heavy damage interrupt if sustained damage is taken + int m_nSustainedDamage; + float m_flLastDamageTime; + float m_flZapDuration; + +protected: + int m_poseHead_Yaw, m_poseHead_Pitch; + virtual void PopulatePoseParameters( void ); + +private: + + HSOUNDSCRIPTHANDLE m_hFootstep; + + DEFINE_CUSTOM_AI; + + //================================================== + // AntlionConditions + //================================================== + + enum + { + COND_ANTLION_FLIPPED = LAST_SHARED_CONDITION, + COND_ANTLION_ON_NPC, + COND_ANTLION_CAN_JUMP, + COND_ANTLION_FOLLOW_TARGET_TOO_FAR, + COND_ANTLION_RECEIVED_ORDERS, + COND_ANTLION_IN_WATER, + COND_ANTLION_CAN_JUMP_AT_TARGET, + COND_ANTLION_SQUADMATE_KILLED + }; + + //================================================== + // AntlionSchedules + //================================================== + + enum + { + SCHED_ANTLION_CHASE_ENEMY_BURROW = LAST_SHARED_SCHEDULE, + SCHED_ANTLION_JUMP, + SCHED_ANTLION_RUN_TO_BURROW_IN, + SCHED_ANTLION_BURROW_IN, + SCHED_ANTLION_BURROW_WAIT, + SCHED_ANTLION_BURROW_OUT, + SCHED_ANTLION_WAIT_FOR_UNBORROW_TRIGGER, + SCHED_ANTLION_WAIT_FOR_CLEAR_UNBORROW, + SCHED_ANTLION_WAIT_UNBORROW, + SCHED_ANTLION_FLEE_THUMPER, + SCHED_ANTLION_CHASE_BUGBAIT, + SCHED_ANTLION_FLIP, + SCHED_ANTLION_DISMOUNT_NPC, + SCHED_ANTLION_RUN_TO_FIGHT_GOAL, + SCHED_ANTLION_RUN_TO_FOLLOW_GOAL, + SCHED_ANTLION_BUGBAIT_IDLE_STAND, + SCHED_ANTLION_BURROW_AWAY, + SCHED_ANTLION_FLEE_PHYSICS_DANGER, + SCHED_ANTLION_POUNCE, + SCHED_ANTLION_POUNCE_MOVING, + SCHED_ANTLION_DROWN, + SCHED_ANTLION_WORKER_RANGE_ATTACK1, + SCHED_ANTLION_WORKER_RUN_RANDOM, + SCHED_ANTLION_TAKE_COVER_FROM_ENEMY, + SCHED_ANTLION_ZAP_FLIP, + SCHED_ANTLION_WORKER_FLANK_RANDOM, + SCHED_ANTLION_TAKE_COVER_FROM_SAVEPOSITION + }; + + //================================================== + // AntlionTasks + //================================================== + + enum + { + TASK_ANTLION_SET_CHARGE_GOAL = LAST_SHARED_TASK, + TASK_ANTLION_FIND_BURROW_IN_POINT, + TASK_ANTLION_FIND_BURROW_OUT_POINT, + TASK_ANTLION_BURROW, + TASK_ANTLION_UNBURROW, + TASK_ANTLION_VANISH, + TASK_ANTLION_BURROW_WAIT, + TASK_ANTLION_CHECK_FOR_UNBORROW, + TASK_ANTLION_JUMP, + TASK_ANTLION_WAIT_FOR_TRIGGER, + TASK_ANTLION_GET_THUMPER_ESCAPE_PATH, + TASK_ANTLION_GET_PATH_TO_BUGBAIT, + TASK_ANTLION_FACE_BUGBAIT, + TASK_ANTLION_DISMOUNT_NPC, + TASK_ANTLION_REACH_FIGHT_GOAL, + TASK_ANTLION_GET_PHYSICS_DANGER_ESCAPE_PATH, + TASK_ANTLION_FACE_JUMP, + TASK_ANTLION_DROWN, + TASK_ANTLION_GET_PATH_TO_RANDOM_NODE, + TASK_ANTLION_FIND_COVER_FROM_SAVEPOSITION, + }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Shield +//----------------------------------------------------------------------------- +class CAntlionRepellant : public CPointEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CAntlionRepellant, CPointEntity ); + ~CAntlionRepellant(); + +public: + void Spawn( void ); + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + float GetRadius( void ); + void SetRadius( float flRadius ) { m_flRepelRadius = flRadius; } + + static bool IsPositionRepellantFree( Vector vDesiredPos ); + + void OnRestore( void ); + +private: + + float m_flRepelRadius; + bool m_bEnabled; +}; + +extern bool IsAntlion( CBaseEntity *pEntity ); +extern bool IsAntlionWorker( CBaseEntity *pEntity ); + +#ifdef HL2_EPISODIC +extern float AntlionWorkerBurstRadius( void ); +#endif // HL2_EPISODIC + +#endif // NPC_ANTLION_H diff --git a/game/server/hl2/npc_antliongrub.h b/game/server/hl2/npc_antliongrub.h new file mode 100644 index 0000000..4b0b8ff --- /dev/null +++ b/game/server/hl2/npc_antliongrub.h @@ -0,0 +1,13 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Antlion Grub - cannon fodder +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_ANTLIONGRUB_H +#define NPC_ANTLIONGRUB_H + +#endif //NPC_ANTLIONGRUB_H \ No newline at end of file diff --git a/game/server/hl2/npc_assassin.h b/game/server/hl2/npc_assassin.h new file mode 100644 index 0000000..1849c06 --- /dev/null +++ b/game/server/hl2/npc_assassin.h @@ -0,0 +1,90 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_ASSASSIN_H +#define NPC_ASSASSIN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "Sprite.h" +#include "SpriteTrail.h" +#include "soundent.h" + +//Eye states +enum eyeState_t +{ + ASSASSIN_EYE_SEE_TARGET = 0, //Sees the target, bright and big + ASSASSIN_EYE_SEEKING_TARGET, //Looking for a target, blinking (bright) + ASSASSIN_EYE_ACTIVE, //Actively looking + ASSASSIN_EYE_DORMANT, //Not active + ASSASSIN_EYE_DEAD, //Completely invisible +}; + +//========================================================= +//========================================================= +class CNPC_Assassin : public CAI_BaseNPC +{ +public: + DECLARE_CLASS( CNPC_Assassin, CAI_BaseNPC ); + // DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CNPC_Assassin( void ); + + Class_T Classify( void ) { return CLASS_COMBINE; } + int GetSoundInterests ( void ) { return (SOUND_WORLD|SOUND_COMBAT|SOUND_PLAYER); } + + int SelectSchedule ( void ); + int MeleeAttack1Conditions ( float flDot, float flDist ); + int RangeAttack1Conditions ( float flDot, float flDist ); + int RangeAttack2Conditions ( float flDot, float flDist ); + + void Precache( void ); + void Spawn( void ); + void PrescheduleThink( void ); + void HandleAnimEvent( animevent_t *pEvent ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void OnScheduleChange( void ); + void GatherEnemyConditions( CBaseEntity *pEnemy ); + void BuildScheduleTestBits( void ); + void Event_Killed( const CTakeDamageInfo &info ); + + bool FValidateHintType ( CAI_Hint *pHint ); + bool IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const; + bool MovementCost( int moveType, const Vector &vecStart, const Vector &vecEnd, float *pCost ); + + float MaxYawSpeed( void ); + + const Vector &GetViewOffset( void ); + +private: + + void SetEyeState( eyeState_t state ); + void FirePistol( int hand ); + bool CanFlip( int flipType, Activity &activity, const Vector *avoidPosition ); + + int m_nNumFlips; + int m_nLastFlipType; + float m_flNextFlipTime; //Next earliest time the assassin can flip again + float m_flNextLungeTime; + float m_flNextShotTime; + + bool m_bEvade; + bool m_bAggressive; // Sets certain state, including whether or not her eye is visible + bool m_bBlinkState; + + CSprite *m_pEyeSprite; + CSpriteTrail *m_pEyeTrail; + + DEFINE_CUSTOM_AI; +}; + + +#endif // NPC_ASSASSIN_H diff --git a/game/server/hl2/npc_attackchopper.h b/game/server/hl2/npc_attackchopper.h new file mode 100644 index 0000000..9295bed --- /dev/null +++ b/game/server/hl2/npc_attackchopper.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + + +#ifndef NPC_ATTACKCHOPPER_H +#define NPC_ATTACKCHOPPER_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Creates an avoidance sphere +//----------------------------------------------------------------------------- +CBaseEntity *CreateHelicopterAvoidanceSphere( CBaseEntity *pParent, int nAttachment, float flRadius, bool bAvoidBelow = false ); + +// Chopper gibbage +void Chopper_BecomeChunks( CBaseEntity *pChopper ); +void Chopper_CreateChunk( CBaseEntity *pChopper, const Vector &vecChunkPos, const QAngle &vecChunkAngles, const char *pszChunkName, bool bSmall ); +void Chopper_PrecacheChunks( CBaseEntity *pChopper ); + +#endif // NPC_ATTACKCHOPPER_H + + diff --git a/game/server/hl2/npc_barnacle.h b/game/server/hl2/npc_barnacle.h new file mode 100644 index 0000000..bcb191c --- /dev/null +++ b/game/server/hl2/npc_barnacle.h @@ -0,0 +1,239 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_BARNACLE_H +#define NPC_BARNACLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "studio.h" +#include "physics_prop_ragdoll.h" + +class CNPC_Barnacle; + + +#define BARNACLE_PULL_SPEED 80 +#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them. + +// Tongue +#define BARNACLE_TONGUE_POINTS 8 + +#define BARNACLE_MIN_PULL_TIME 3.0f + +#define NUM_BARNACLE_GIBS 4 + +#define SF_BARNACLE_CHEAP_DEATH (1<<16) // Don't spawn as many gibs +#define SF_BARNACLE_AMBUSH (1<<17) // Start with tongue retracted and wait for input. + +// when true, causes the barnacle's visible tongue to offset +// from the physical one when pulling the player. +#define BARNACLE_USE_TONGUE_OFFSET 1 + + +//----------------------------------------------------------------------------- +// Purpose: This is the entity we place at the top & bottom of the tongue, to create a vphysics spring +//----------------------------------------------------------------------------- +class CBarnacleTongueTip : public CBaseAnimating +{ + DECLARE_CLASS( CBarnacleTongueTip, CBaseAnimating ); + +public: + DECLARE_DATADESC(); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void UpdateOnRemove( ); + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + + virtual int UpdateTransmitState( void ); + bool CreateSpring( CBaseAnimating *pTongueRoot ); + static CBarnacleTongueTip *CreateTongueTip( CNPC_Barnacle *pBarnacle, CBaseAnimating *pTongueRoot, const Vector &vecOrigin, const QAngle &vecAngles ); + static CBarnacleTongueTip *CreateTongueRoot( const Vector &vecOrigin, const QAngle &vecAngles ); + + IPhysicsSpring *m_pSpring; + +private: + CHandle m_hBarnacle; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CNPC_Barnacle : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_Barnacle, CAI_BaseNPC ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CNPC_Barnacle(); + ~CNPC_Barnacle(); + + void Spawn( void ); + virtual void Activate( void ); + void Precache( void ); + Class_T Classify ( void ); + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + virtual void HandleAnimEvent( animevent_t *pEvent ); + void Event_Killed( const CTakeDamageInfo &info ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot ); + + // The tongue's vphysics updated + void OnTongueTipUpdated(); + +private: + void SetAltitude( float flAltitude ); + void SpawnDeathGibs( void ); + + void InitTonguePosition( void ); + CBaseEntity* TongueTouchEnt ( float *pflLength ); + void BarnacleThink ( void ); + void SwallowPrey( void ); + void WaitTillDead ( void ); + void AttachTongueToTarget( CBaseEntity *pTouchEnt, Vector vecGrabPos ); + CRagdollProp *AttachRagdollToTongue( CBaseAnimating *pAnimating ); + void RemoveRagdoll( bool bDestroyRagdoll ); + void LostPrey( bool bRemoveRagdoll ); + void BitePrey( void ); + + // Updates the tongue length + void UpdateTongue( void ); + + // Spit out the prey; add physics force! + void SpitPrey(); + + void SprayBlood(); + + // What type of enemy do we have? + bool IsEnemyAPlayer(); + bool IsEnemyARagdoll(); + bool IsEnemyAPhysicsObject(); + bool IsEnemyAnNPC(); + + bool CanPickup( CBaseCombatCharacter *pBCC ); + + // Allows the ragdoll to settle before biting it + bool WaitForRagdollToSettle( float flBiteZOffset ); + + // Allows the physics prop to settle before biting it + bool WaitForPhysicsObjectToSettle( float flBiteZOffset ); + + // Play a scream right before biting + void PlayLiftingScream( float flBiteZOffset ); + + // Pulls the prey upward toward the mouth + void PullEnemyTorwardsMouth( bool bAdjustEnemyOrigin ); + + // Lift the prey stuck to our tongue up towards our mouth + void LiftPrey( void ); + void LiftPlayer( float flBiteZOffset ); + void LiftRagdoll( float flBiteZOffset ); + void LiftPhysicsObject( float flBiteZOffset ); + void LiftNPC( float flBiteZOffset ); + + void UpdatePlayerConstraint( void ); + + void InputDropTongue( inputdata_t &inputdata ); + void InputSetDropTongueSpeed( inputdata_t &inputdata ); + void DropTongue( void ); + + + +#if HL2_EPISODIC + /// Decides whether something should poison the barnacle upon eating + static bool IsPoisonous( CBaseEntity *pVictim ); + + void InputLetGo( inputdata_t &inputdata ); + COutputEHANDLE m_OnGrab, m_OnRelease; + + const impactdamagetable_t &GetPhysicsImpactDamageTable( void ); +#endif + + CNetworkVar( float, m_flAltitude ); + int m_cGibs; // barnacle loads up on gibs each time it kills something. + bool m_bLiftingPrey; // true when the prey's on the tongue and being lifted to the mouth + bool m_bSwallowingPrey; // if it's a human, true while the barnacle chews it and swallows it whole. + float m_flDigestFinish; // time at which we've finished digesting something we chewed + float m_flVictimHeight; + int m_iGrabbedBoneIndex; + bool m_bPlayedPullSound; + bool m_bPlayerWasStanding; + + static const char *m_szGibNames[NUM_BARNACLE_GIBS]; + + // Tongue spline points + CNetworkVar( Vector, m_vecRoot ); + CNetworkVar( Vector, m_vecTip ); + CNetworkVar( Vector, m_vecTipDrawOffset ); + + // Tongue tip & root + CHandle m_hTongueRoot; + CHandle m_hTongueTip; + CHandle m_hRagdoll; + matrix3x4_t m_pRagdollBones[MAXSTUDIOBONES]; + IPhysicsConstraint *m_pConstraint; + float m_flRestUnitsAboveGround; + int m_nSpitAttachment; + EHANDLE m_hLastSpitEnemy; + int m_nShakeCount; + + float m_flNextBloodTime; +#ifndef _XBOX + int m_nBloodColor; +#endif + Vector m_vecBloodPos; + + float m_flBarnaclePullSpeed; + float m_flLocalTimer; + + Vector m_vLastEnemyPos; + float m_flLastPull; + CSimpleSimTimer m_StuckTimer; + bool m_bSwallowingBomb; +#ifdef HL2_EPISODIC + bool m_bSwallowingPoison; +#endif + +#if BARNACLE_USE_TONGUE_OFFSET + // Static because only one barnacle can be holding the player + // at a time, and because it's not really a big deal if it + // resets to zero after reload. + const static Vector m_svPlayerHeldTipOffset; +#endif + + DEFINE_CUSTOM_AI; +}; + + +//----------------------------------------------------------------------------- +// What type of enemy do we have? +//----------------------------------------------------------------------------- +inline bool CNPC_Barnacle::IsEnemyAPlayer() +{ + return GetEnemy() && GetEnemy()->IsPlayer(); +} + +inline bool CNPC_Barnacle::IsEnemyARagdoll() +{ + return m_hRagdoll != NULL; +} + +inline bool CNPC_Barnacle::IsEnemyAPhysicsObject() +{ + return !m_hRagdoll && GetEnemy() && !GetEnemy()->IsPlayer() && + !GetEnemy()->MyNPCPointer() && (GetEnemy()->GetMoveType() == MOVETYPE_VPHYSICS); +} + +inline bool CNPC_Barnacle::IsEnemyAnNPC() +{ + return !IsEnemyARagdoll() && (GetEnemy()->MyNPCPointer() != NULL); +} + + +#endif // NPC_BARNACLE_H diff --git a/game/server/hl2/npc_basescanner.h b/game/server/hl2/npc_basescanner.h new file mode 100644 index 0000000..ab69c81 --- /dev/null +++ b/game/server/hl2/npc_basescanner.h @@ -0,0 +1,256 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef NPC_BASESCANNER_H +#define NPC_BASESCANNER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" +#include "player_pickup.h" +#include "weapon_physcannon.h" +#include "hl2_player.h" +#include "smoke_trail.h" +#include "ai_basenpc_physicsflyer.h" + +//----------------------------------------------------------------------------- +// States for the scanner's sound. +//----------------------------------------------------------------------------- +enum ScannerFlyMode_t +{ + SCANNER_FLY_PHOTO = 0, // Fly close to photograph entity + SCANNER_FLY_PATROL, // Fly slowly around the enviroment + SCANNER_FLY_FAST, // Fly quickly around the enviroment + SCANNER_FLY_CHASE, // Fly quickly around the enviroment + SCANNER_FLY_SPOT, // Fly above enity in spotlight position + SCANNER_FLY_ATTACK, // Get in my enemies face for spray or flash + SCANNER_FLY_DIVE, // Divebomb - only done when dead + SCANNER_FLY_FOLLOW, // Following a target +}; + +enum ScannerInspectAct_t +{ + SCANNER_INSACT_HANDS_UP, + SCANNER_INSACT_SHOWARMBAND, +}; + +// Sentences +#define SCANNER_SENTENCE_ATTENTION 0 +#define SCANNER_SENTENCE_HANDSUP 1 +#define SCANNER_SENTENCE_PROCEED 2 +#define SCANNER_SENTENCE_CURIOUS 3 + +// Scanner attack distances +#define SCANNER_ATTACK_NEAR_DIST 150 // Fly attack min distance +#define SCANNER_ATTACK_FAR_DIST 300 // Fly attack max distance +#define SCANNER_ATTACK_RANGE 350 // Attack max distance +#define SCANNER_ATTACK_MIN_DELAY 8 // Min time between attacks +#define SCANNER_ATTACK_MAX_DELAY 12 // Max time between attacks +#define SCANNER_EVADE_TIME 1 // How long to evade after take damage + +// Scanner movement vars +#define SCANNER_BANK_RATE 30 +#define SCANNER_MAX_SPEED 250 +#define SCANNER_MAX_DIVE_BOMB_SPEED 2500 +#define SCANNER_SQUAD_FLY_DIST 500 // How far to scanners stay apart +#define SCANNER_SQUAD_HELP_DIST 4000 // How far will I fly to help + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CNPC_BaseScanner : public CAI_BasePhysicsFlyingBot, public CDefaultPlayerPickupVPhysics +{ + DECLARE_CLASS( CNPC_BaseScanner, CAI_BasePhysicsFlyingBot ); + +public: + CNPC_BaseScanner(); + + void Spawn(void); + + virtual void UpdateEfficiency( bool bInPVS ); + + Class_T Classify( void ) { return(CLASS_SCANNER); } + virtual float GetAutoAimRadius(); + + void Event_Killed( const CTakeDamageInfo &info ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + int OnTakeDamage_Dying( const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + void Gib(void); + + void OnStateChange( NPC_STATE eOldState, NPC_STATE eNewState ); + void ClampMotorForces( Vector &linear, AngularImpulse &angular ); + + int DrawDebugTextOverlays(void); + + virtual float GetHeadTurnRate( void ); + + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + + // CDefaultPlayerPickupVPhysics + void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + + bool ShouldPlayIdleSound( void ); + void IdleSound( void ); + void DeathSound( const CTakeDamageInfo &info ); + void AlertSound( void ); + void PainSound( const CTakeDamageInfo &info ); + virtual char *GetScannerSoundPrefix( void ) { return ""; } + void ScannerEmitSound( const char *pszSoundName ); + + int MeleeAttack1Conditions ( float flDot, float flDist ); + + int SelectSchedule(void); + void StartTask( const Task_t *pTask ); + void OnScheduleChange( void ); + void UpdateOnRemove( void ); + virtual float GetMaxSpeed( void ); + + void PostRunStopMoving() {} // scanner can use "movement" activities but not be moving + + virtual bool CanBecomeServerRagdoll( void ) { return false; } + + void SpeakSentence( int sentenceType ); + + bool IsHeldByPhyscannon( void ); + + // Inputs + void InputSetFlightSpeed( inputdata_t &inputdata ); + void InputSetDistanceOverride( inputdata_t &inputdata ); + +protected: + virtual char *GetEngineSound( void ) { return NULL; } + void PlayFlySound(void); + + void SetBanking( float flInterval ); + void UpdateHead( float flInterval ); + inline CBaseEntity *EntityToWatch( void ); + + bool IsEnemyPlayerInSuit( void ); + + // Movement + virtual bool OverridePathMove( CBaseEntity *pMoveTarget, float flInterval ); + virtual bool OverrideMove( float flInterval ); + Vector IdealGoalForMovement( const Vector &goalPos, const Vector &startPos, float idealRange, float idealHeight ); + virtual void AdjustScannerVelocity( void ) { return; } + virtual void MoveToAttack(float flInterval); + virtual void MoveToTarget( float flInterval, const Vector &vecMoveTarget ); + virtual void MoveExecute_Alive(float flInterval); + virtual float MinGroundDist(void) { return 64; } + Vector VelocityToEvade(CBaseCombatCharacter *pEnemy); + virtual float GetGoalDistance( void ); + + // Divebombing + virtual void AttackDivebomb( void ); + void DiveBombSoundThink(); + void AttackDivebombCollide(float flInterval); + void MoveToDivebomb(float flInterval); + void BlendPhyscannonLaunchSpeed(); + +private: + bool GetGoalDirection( Vector *vOut ); + + void StartSmokeTrail( void ); + + // Take damage from being thrown by a physcannon + void TakeDamageFromPhyscannon( CBasePlayer *pPlayer ); + + // Take damage from physics impacts + void TakeDamageFromPhysicsImpact( int index, gamevcollisionevent_t *pEvent ); + + // Do we have a physics attacker? + CBasePlayer *HasPhysicsAttacker( float dt ); + + virtual void StopLoopingSounds(void); + +public: + // ------------------------ + // Death Cleanup + // ------------------------ + CTakeDamageInfo m_KilledInfo; + +protected: + ScannerFlyMode_t m_nFlyMode; + + // Pose parameters + int m_nPoseTail; + int m_nPoseDynamo; + int m_nPoseFlare; + int m_nPoseFaceVert; + int m_nPoseFaceHoriz; + + bool m_bHasSpoken; + + // Movement + float m_flFlyNoiseBase; + float m_flEngineStallTime; + float m_fNextFlySoundTime; + Vector m_vecDiveBombDirection; // The direction we dive bomb. Calculated at the moment of death. + float m_flDiveBombRollForce; // Used for roll while dive bombing. + + float m_flGoalOverrideDistance; + + // Deriver scanner variables + float m_flAttackNearDist; + float m_flAttackFarDist; + float m_flAttackRange; + +private: + CSoundPatch *m_pEngineSound; + + // physics influence + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + + // Attacks + SmokeTrail *m_pSmokeTrail; + +protected: + DEFINE_CUSTOM_AI; + + // Custom interrupt conditions + enum + { + COND_SCANNER_FLY_CLEAR = BaseClass::NEXT_CONDITION, + COND_SCANNER_FLY_BLOCKED, + COND_SCANNER_GRABBED_BY_PHYSCANNON, + COND_SCANNER_RELEASED_FROM_PHYSCANNON, + + NEXT_CONDITION, + }; + + // Custom schedules + enum + { + SCHED_SCANNER_PATROL = BaseClass::NEXT_SCHEDULE, + SCHED_SCANNER_ATTACK, + SCHED_SCANNER_ATTACK_HOVER, + SCHED_SCANNER_ATTACK_DIVEBOMB, + SCHED_SCANNER_CHASE_ENEMY, + SCHED_SCANNER_CHASE_TARGET, + SCHED_SCANNER_FOLLOW_HOVER, + SCHED_SCANNER_HELD_BY_PHYSCANNON, + + NEXT_SCHEDULE, + }; + + // Custom tasks + enum + { + TASK_SCANNER_SET_FLY_PATROL = BaseClass::NEXT_TASK, + TASK_SCANNER_SET_FLY_CHASE, + TASK_SCANNER_SET_FLY_ATTACK, + TASK_SCANNER_SET_FLY_DIVE, + + NEXT_TASK, + }; + + DECLARE_DATADESC(); +}; + +#endif // NPC_BASESCANNER_H diff --git a/game/server/hl2/npc_bullseye.h b/game/server/hl2/npc_bullseye.h new file mode 100644 index 0000000..9138d01 --- /dev/null +++ b/game/server/hl2/npc_bullseye.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_BULLSEYE_H +#define NPC_BULLSEYE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" + +//========================================================= +// >> CBullseye +//========================================================= +class CNPC_Bullseye : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_Bullseye, CAI_BaseNPC ); + +public: + CNPC_Bullseye(void); + ~CNPC_Bullseye(); + + virtual void Precache( void ); + virtual void Spawn( void ); + virtual void Activate( void ); + virtual void OnRestore( void ); + + virtual float GetAutoAimRadius() { return m_fAutoaimRadius; } + + Class_T Classify( void ); + void Event_Killed( const CTakeDamageInfo &info ); + void DecalTrace( trace_t *pTrace, char const *decalName ); + void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + bool IsLightDamage( const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + int OnTakeDamage( const CTakeDamageInfo &info ); + bool UsePerfectAccuracy( void ) { return m_bPerfectAccuracy; } + + bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) { return false; } // force traces to test against hull + + void BullseyeThink( void ); + bool CanBecomeRagdoll( void ); + + void SetPainPartner( CBaseEntity *pOther ); + void InputTargeted( inputdata_t &inputdata ); + void InputReleased( inputdata_t &inputdata ); + bool CanBecomeServerRagdoll( void ) { return false; } + + bool CanBeAnEnemyOf( CBaseEntity *pEnemy ); + + +protected: + + EHANDLE m_hPainPartner; //Entity that the bullseye will pass any damage it take to + COutputEvent m_OnTargeted; + COutputEvent m_OnReleased; + bool m_bPerfectAccuracy; // Entities that shoot at me should be perfectly accurate + float m_fAutoaimRadius; // How much to influence player's autoaim. + float m_flMinDistValidEnemy; + + DECLARE_DATADESC(); +}; + +int FindBullseyesInCone( CBaseEntity **pList, int listMax, const Vector &coneOrigin, const Vector &coneAxis, float coneAngleCos, float coneLength ); + +#define SF_BULLSEYE_NONSOLID (1 << 16) +#define SF_BULLSEYE_NODAMAGE (1 << 17) +#define SF_BULLSEYE_ENEMYDAMAGEONLY (1 << 18) +#define SF_BULLSEYE_BLEED (1 << 19) +#define SF_BULLSEYE_PERFECTACC (1 << 20) +#define SF_BULLSEYE_VPHYSICSSHADOW (1 << 21) + + +#endif // NPC_BULLSEYE_H + diff --git a/game/server/hl2/npc_bullsquid.h b/game/server/hl2/npc_bullsquid.h new file mode 100644 index 0000000..62218b8 --- /dev/null +++ b/game/server/hl2/npc_bullsquid.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base combat character with no AI +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_BULLSQUID_H +#define NPC_BULLSQUID_H + +#include "ai_basenpc.h" + + +class CNPC_Bullsquid : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_Bullsquid, CAI_BaseNPC ); + DECLARE_DATADESC(); + +public: + void Spawn( void ); + void Precache( void ); + Class_T Classify( void ); + + void IdleSound( void ); + void PainSound( const CTakeDamageInfo &info ); + void AlertSound( void ); + void DeathSound( const CTakeDamageInfo &info ); + void AttackSound( void ); + void GrowlSound( void ); + + float MaxYawSpeed ( void ); + + void HandleAnimEvent( animevent_t *pEvent ); + + int RangeAttack1Conditions( float flDot, float flDist ); + int MeleeAttack1Conditions( float flDot, float flDist ); + int MeleeAttack2Conditions( float flDot, float flDist ); + + bool FValidateHintType ( CAI_Hint *pHint ); + void RemoveIgnoredConditions( void ); + Disposition_t IRelationType( CBaseEntity *pTarget ); + int OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ); + + int GetSoundInterests ( void ); + void RunAI ( void ); + virtual void OnListened ( void ); + + int SelectSchedule( void ); + bool FInViewCone ( Vector pOrigin ); + + void StartTask ( const Task_t *pTask ); + void RunTask ( const Task_t *pTask ); + + NPC_STATE SelectIdealState ( void ); + + DEFINE_CUSTOM_AI; + +private: + + bool m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time. + float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while. + float m_flNextSpitTime;// last time the bullsquid used the spit attack. + int m_nSquidSpitSprite; + float m_flHungryTime;// set this is a future time to stop the monster from eating for a while. + + float m_nextSquidSoundTime; +}; +#endif // NPC_BULLSQUID_H \ No newline at end of file diff --git a/game/server/hl2/npc_citizen17.h b/game/server/hl2/npc_citizen17.h new file mode 100644 index 0000000..49efbc7 --- /dev/null +++ b/game/server/hl2/npc_citizen17.h @@ -0,0 +1,426 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The downtrodden citizens of City 17. Timid when unarmed, they will +// rise up against their Combine oppressors when given a weapon. +// +//=============================================================================// + +#ifndef NPC_CITIZEN_H +#define NPC_CITIZEN_H + +#include "npc_playercompanion.h" + +#include "ai_behavior_functank.h" + +struct SquadCandidate_t; + +//----------------------------------------------------------------------------- +// +// CLASS: CNPC_Citizen +// +//----------------------------------------------------------------------------- + +//------------------------------------- +// Spawnflags +//------------------------------------- + +#define SF_CITIZEN_FOLLOW ( 1 << 16 ) //65536 follow the player as soon as I spawn. +#define SF_CITIZEN_MEDIC ( 1 << 17 ) //131072 +#define SF_CITIZEN_RANDOM_HEAD ( 1 << 18 ) //262144 +#define SF_CITIZEN_AMMORESUPPLIER ( 1 << 19 ) //524288 +#define SF_CITIZEN_NOT_COMMANDABLE ( 1 << 20 ) //1048576 +#define SF_CITIZEN_IGNORE_SEMAPHORE ( 1 << 21 ) //2097152 Work outside the speech semaphore system +#define SF_CITIZEN_RANDOM_HEAD_MALE ( 1 << 22 ) //4194304 +#define SF_CITIZEN_RANDOM_HEAD_FEMALE ( 1 << 23 )//8388608 +#define SF_CITIZEN_USE_RENDER_BOUNDS ( 1 << 24 )//16777216 + +//------------------------------------- +// Animation events +//------------------------------------- + +enum CitizenType_t +{ + CT_DEFAULT, + CT_DOWNTRODDEN, + CT_REFUGEE, + CT_REBEL, + CT_UNIQUE +}; + +//----------------------------------------------------------------------------- +// Citizen expression types +//----------------------------------------------------------------------------- +enum CitizenExpressionTypes_t +{ + CIT_EXP_UNASSIGNED, // Defaults to this, selects other in spawn. + + CIT_EXP_SCARED, + CIT_EXP_NORMAL, + CIT_EXP_ANGRY, + + CIT_EXP_LAST_TYPE, +}; + +//------------------------------------- + +class CNPC_Citizen : public CNPC_PlayerCompanion +{ + DECLARE_CLASS( CNPC_Citizen, CNPC_PlayerCompanion ); +public: + CNPC_Citizen() + : m_iHead( -1 ) + { + } + + //--------------------------------- + bool CreateBehaviors(); + void Precache(); + void PrecacheAllOfType( CitizenType_t ); + void Spawn(); + void PostNPCInit(); + virtual void SelectModel(); + void SelectExpressionType(); + void Activate(); + virtual void OnGivenWeapon( CBaseCombatWeapon *pNewWeapon ); + void FixupMattWeapon(); + +#ifdef HL2_EPISODIC + virtual float GetJumpGravity() const { return 1.8f; } +#endif//HL2_EPISODIC + + void OnRestore(); + + //--------------------------------- + string_t GetModelName() const; + + Class_T Classify(); + + bool ShouldAlwaysThink(); + + //--------------------------------- + // Behavior + //--------------------------------- + bool ShouldBehaviorSelectSchedule( CAI_BehaviorBase *pBehavior ); + void GatherConditions(); + void PredictPlayerPush(); + void PrescheduleThink(); + void BuildScheduleTestBits(); + + bool FInViewCone( CBaseEntity *pEntity ); + + int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + int SelectSchedule(); + + int SelectSchedulePriorityAction(); + int SelectScheduleHeal(); + int SelectScheduleRetrieveItem(); + int SelectScheduleNonCombat(); + int SelectScheduleManhackCombat(); + int SelectScheduleCombat(); + bool ShouldDeferToFollowBehavior(); + int TranslateSchedule( int scheduleType ); + + bool ShouldAcceptGoal( CAI_BehaviorBase *pBehavior, CAI_GoalEntity *pGoal ); + void OnClearGoal( CAI_BehaviorBase *pBehavior, CAI_GoalEntity *pGoal ); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + Activity NPC_TranslateActivity( Activity eNewActivity ); + void HandleAnimEvent( animevent_t *pEvent ); + void TaskFail( AI_TaskFailureCode_t code ); + + void PickupItem( CBaseEntity *pItem ); + + void SimpleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + bool IgnorePlayerPushing( void ); + + int DrawDebugTextOverlays( void ); + + virtual const char *SelectRandomExpressionForState( NPC_STATE state ); + + //--------------------------------- + // Combat + //--------------------------------- + bool OnBeginMoveAndShoot(); + void OnEndMoveAndShoot(); + + virtual bool UseAttackSquadSlots() { return false; } + void LocateEnemySound(); + + bool IsManhackMeleeCombatant(); + + Vector GetActualShootPosition( const Vector &shootOrigin ); + void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ); + + bool ShouldLookForBetterWeapon(); + + + //--------------------------------- + // Damage handling + //--------------------------------- + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + //--------------------------------- + // Commander mode + //--------------------------------- + bool IsCommandable(); + bool IsPlayerAlly( CBasePlayer *pPlayer = NULL ); + bool CanJoinPlayerSquad(); + bool WasInPlayerSquad(); + bool HaveCommandGoal() const; + bool IsCommandMoving(); + bool ShouldAutoSummon(); + bool IsValidCommandTarget( CBaseEntity *pTarget ); + bool NearCommandGoal(); + bool VeryFarFromCommandGoal(); + bool TargetOrder( CBaseEntity *pTarget, CAI_BaseNPC **Allies, int numAllies ); + void MoveOrder( const Vector &vecDest, CAI_BaseNPC **Allies, int numAllies ); + void OnMoveOrder(); + void CommanderUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + bool ShouldSpeakRadio( CBaseEntity *pListener ); + void OnMoveToCommandGoalFailed(); + void AddToPlayerSquad(); + void RemoveFromPlayerSquad(); + void TogglePlayerSquadState(); + void UpdatePlayerSquad(); + static int __cdecl PlayerSquadCandidateSortFunc( const SquadCandidate_t *, const SquadCandidate_t * ); + void FixupPlayerSquad(); + void ClearFollowTarget(); + void UpdateFollowCommandPoint(); + bool IsFollowingCommandPoint(); + CAI_BaseNPC * GetSquadCommandRepresentative(); + void SetSquad( CAI_Squad *pSquad ); + void AddInsignia(); + void RemoveInsignia(); + bool SpeakCommandResponse( AIConcept_t concept, const char *modifiers = NULL ); + + //--------------------------------- + // Scanner interaction + //--------------------------------- + float GetNextScannerInspectTime() { return m_fNextInspectTime; } + void SetNextScannerInspectTime( float flTime ) { m_fNextInspectTime = flTime; } + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + //--------------------------------- + // Hints + //--------------------------------- + bool FValidateHintType ( CAI_Hint *pHint ); + + //--------------------------------- + // Special abilities + //--------------------------------- + bool IsMedic() { return HasSpawnFlags(SF_CITIZEN_MEDIC); } + bool IsAmmoResupplier() { return HasSpawnFlags(SF_CITIZEN_AMMORESUPPLIER); } + + bool CanHeal(); + bool ShouldHealTarget( CBaseEntity *pTarget, bool bActiveUse = false ); +#if HL2_EPISODIC + bool ShouldHealTossTarget( CBaseEntity *pTarget, bool bActiveUse = false ); +#endif + void Heal(); + + bool ShouldLookForHealthItem(); + +#if HL2_EPISODIC + void TossHealthKit( CBaseCombatCharacter *pThrowAt, const Vector &offset ); // create a healthkit and throw it at someone + void InputForceHealthKitToss( inputdata_t &inputdata ); +#endif + + //--------------------------------- + // Inputs + //--------------------------------- + void InputRemoveFromPlayerSquad( inputdata_t &inputdata ) { RemoveFromPlayerSquad(); } + void InputStartPatrolling( inputdata_t &inputdata ); + void InputStopPatrolling( inputdata_t &inputdata ); + void InputSetCommandable( inputdata_t &inputdata ); + void InputSetMedicOn( inputdata_t &inputdata ); + void InputSetMedicOff( inputdata_t &inputdata ); + void InputSetAmmoResupplierOn( inputdata_t &inputdata ); + void InputSetAmmoResupplierOff( inputdata_t &inputdata ); + void InputSpeakIdleResponse( inputdata_t &inputdata ); + + //--------------------------------- + // Sounds & speech + //--------------------------------- + void FearSound( void ); + void DeathSound( const CTakeDamageInfo &info ); + bool UseSemaphore( void ); + + virtual void OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ); + +private: + //----------------------------------------------------- + // Conditions, Schedules, Tasks + //----------------------------------------------------- + enum + { + COND_CIT_PLAYERHEALREQUEST = BaseClass::NEXT_CONDITION, + COND_CIT_COMMANDHEAL, + COND_CIT_HURTBYFIRE, + COND_CIT_START_INSPECTION, + + SCHED_CITIZEN_PLAY_INSPECT_ACTIVITY = BaseClass::NEXT_SCHEDULE, + SCHED_CITIZEN_HEAL, + SCHED_CITIZEN_RANGE_ATTACK1_RPG, + SCHED_CITIZEN_PATROL, + SCHED_CITIZEN_MOURN_PLAYER, + SCHED_CITIZEN_SIT_ON_TRAIN, + SCHED_CITIZEN_STRIDER_RANGE_ATTACK1_RPG, +#ifdef HL2_EPISODIC + SCHED_CITIZEN_HEAL_TOSS, +#endif + + TASK_CIT_HEAL = BaseClass::NEXT_TASK, + TASK_CIT_RPG_AUGER, + TASK_CIT_PLAY_INSPECT_SEQUENCE, + TASK_CIT_SIT_ON_TRAIN, + TASK_CIT_LEAVE_TRAIN, + TASK_CIT_SPEAK_MOURNING, +#ifdef HL2_EPISODIC + TASK_CIT_HEAL_TOSS, +#endif + + }; + + //----------------------------------------------------- + + int m_nInspectActivity; + float m_flNextFearSoundTime; + float m_flStopManhackFlinch; + float m_fNextInspectTime; // Next time I'm allowed to get inspected by a scanner + float m_flPlayerHealTime; + float m_flNextHealthSearchTime; // Next time I'm allowed to look for a healthkit + float m_flAllyHealTime; + float m_flPlayerGiveAmmoTime; + string_t m_iszAmmoSupply; + int m_iAmmoAmount; + bool m_bRPGAvoidPlayer; + bool m_bShouldPatrol; + string_t m_iszOriginalSquad; + float m_flTimeJoinedPlayerSquad; + bool m_bWasInPlayerSquad; + float m_flTimeLastCloseToPlayer; + string_t m_iszDenyCommandConcept; + + CSimpleSimTimer m_AutoSummonTimer; + Vector m_vAutoSummonAnchor; + + CitizenType_t m_Type; + CitizenExpressionTypes_t m_ExpressionType; + + int m_iHead; + + static CSimpleSimTimer gm_PlayerSquadEvaluateTimer; + + float m_flTimePlayerStare; // The game time at which the player started staring at me. + float m_flTimeNextHealStare; // Next time I'm allowed to heal a player who is staring at me. + + //----------------------------------------------------- + // Outputs + //----------------------------------------------------- + COutputEvent m_OnJoinedPlayerSquad; + COutputEvent m_OnLeftPlayerSquad; + COutputEvent m_OnFollowOrder; + COutputEvent m_OnStationOrder; + COutputEvent m_OnPlayerUse; + COutputEvent m_OnNavFailBlocked; + + //----------------------------------------------------- + CAI_FuncTankBehavior m_FuncTankBehavior; + + CHandle m_hSavedFollowGoalEnt; + + bool m_bNotifyNavFailBlocked; + bool m_bNeverLeavePlayerSquad; // Don't leave the player squad unless killed, or removed via Entity I/O. + + //----------------------------------------------------- + + DECLARE_DATADESC(); +#ifdef _XBOX +protected: +#endif + DEFINE_CUSTOM_AI; +}; + +//--------------------------------------------------------- +//--------------------------------------------------------- +inline bool CNPC_Citizen::NearCommandGoal() +{ + const float flDistSqr = COMMAND_GOAL_TOLERANCE * COMMAND_GOAL_TOLERANCE; + return ( ( GetAbsOrigin() - GetCommandGoal() ).LengthSqr() <= flDistSqr ); +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +inline bool CNPC_Citizen::VeryFarFromCommandGoal() +{ + const float flDistSqr = (12*50) * (12*50); + return ( ( GetAbsOrigin() - GetCommandGoal() ).LengthSqr() > flDistSqr ); +} + + + +//============================================================================== +// CITIZEN PLAYER-RESPONSE SYSTEM +// +// NOTE: This system is obsolete, and left here for legacy support. +// It has been superseded by the ai_eventresponse system. +// +//============================================================================== +#define CITIZEN_RESPONSE_DISTANCE 768 // Maximum distance for responding citizens +#define CITIZEN_RESPONSE_REFIRE_TIME 15.0 // Time after giving a response before giving any more +#define CITIZEN_RESPONSE_GIVEUP_TIME 4.0 // Time after a response trigger was fired before discarding it without responding + +enum citizenresponses_t +{ + CR_PLAYER_SHOT_GUNSHIP, // Player has shot the gunship with a bullet weapon + CR_PLAYER_KILLED_GUNSHIP, // Player has destroyed the gunship + CR_VITALNPC_DIED, // Mapmaker specified that an NPC that was vital has died + + // Add new responses here + + MAX_CITIZEN_RESPONSES, +}; + +//------------------------------------- + +class CCitizenResponseSystem : public CBaseEntity +{ + DECLARE_CLASS( CCitizenResponseSystem, CBaseEntity ); +public: + DECLARE_DATADESC(); + + void Spawn(); + void OnRestore(); + + void AddResponseTrigger( citizenresponses_t iTrigger ); + + void ResponseThink(); + + //--------------------------------- + // Inputs + //--------------------------------- + void InputResponseVitalNPC( inputdata_t &inputdata ); + +private: + float m_flResponseAddedTime[ MAX_CITIZEN_RESPONSES ]; // Time at which the response was added. 0 if we have no response. + float m_flNextResponseTime; +}; + +//------------------------------------- + +class CSquadInsignia : public CBaseAnimating +{ + DECLARE_CLASS( CSquadInsignia, CBaseAnimating ); + void Spawn(); +}; + +//------------------------------------- + +CCitizenResponseSystem *GetCitizenResponse(); + +//----------------------------------------------------------------------------- + +#endif //NPC_CITIZEN_H diff --git a/game/server/hl2/npc_combine.h b/game/server/hl2/npc_combine.h new file mode 100644 index 0000000..ab16672 --- /dev/null +++ b/game/server/hl2/npc_combine.h @@ -0,0 +1,297 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_COMBINE_H +#define NPC_COMBINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_basehumanoid.h" +#include "ai_behavior.h" +#include "ai_behavior_assault.h" +#include "ai_behavior_standoff.h" +#include "ai_behavior_follow.h" +#include "ai_behavior_functank.h" +#include "ai_behavior_rappel.h" +#include "ai_behavior_actbusy.h" +#include "ai_sentence.h" +#include "ai_baseactor.h" + +// Used when only what combine to react to what the spotlight sees +#define SF_COMBINE_NO_LOOK (1 << 16) +#define SF_COMBINE_NO_GRENADEDROP ( 1 << 17 ) +#define SF_COMBINE_NO_AR2DROP ( 1 << 18 ) + +//========================================================= +// >> CNPC_Combine +//========================================================= +class CNPC_Combine : public CAI_BaseActor +{ + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; + DECLARE_CLASS( CNPC_Combine, CAI_BaseActor ); + +public: + CNPC_Combine(); + + // Create components + virtual bool CreateComponents(); + + bool CanThrowGrenade( const Vector &vecTarget ); + bool CheckCanThrowGrenade( const Vector &vecTarget ); + virtual bool CanGrenadeEnemy( bool bUseFreeKnowledge = true ); + virtual bool CanAltFireEnemy( bool bUseFreeKnowledge ); + int GetGrenadeConditions( float flDot, float flDist ); + int RangeAttack2Conditions( float flDot, float flDist ); // For innate grenade attack + int MeleeAttack1Conditions( float flDot, float flDist ); // For kick/punch + bool FVisible( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); + virtual bool IsCurTaskContinuousMove(); + + virtual float GetJumpGravity() const { return 1.8f; } + + virtual Vector GetCrouchEyeOffset( void ); + + void Event_Killed( const CTakeDamageInfo &info ); + + + void SetActivity( Activity NewActivity ); + NPC_STATE SelectIdealState ( void ); + + // Input handlers. + void InputLookOn( inputdata_t &inputdata ); + void InputLookOff( inputdata_t &inputdata ); + void InputStartPatrolling( inputdata_t &inputdata ); + void InputStopPatrolling( inputdata_t &inputdata ); + void InputAssault( inputdata_t &inputdata ); + void InputHitByBugbait( inputdata_t &inputdata ); + void InputThrowGrenadeAtTarget( inputdata_t &inputdata ); + + bool UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position, CBaseEntity *pInformer = NULL ); + + void Spawn( void ); + void Precache( void ); + void Activate(); + + Class_T Classify( void ); + bool IsElite() { return m_fIsElite; } + void DelayAltFireAttack( float flDelay ); + void DelaySquadAltFireAttack( float flDelay ); + float MaxYawSpeed( void ); + bool ShouldMoveAndShoot(); + bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval );; + void HandleAnimEvent( animevent_t *pEvent ); + Vector Weapon_ShootPosition( ); + + Vector EyeOffset( Activity nActivity ); + Vector EyePosition( void ); + Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + Vector GetAltFireTarget(); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void PostNPCInit(); + void GatherConditions(); + virtual void PrescheduleThink(); + + Activity NPC_TranslateActivity( Activity eNewActivity ); + void BuildScheduleTestBits( void ); + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + int SelectScheduleAttack(); + + bool CreateBehaviors(); + + bool OnBeginMoveAndShoot(); + void OnEndMoveAndShoot(); + + // Combat + WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); + bool HasShotgun(); + bool ActiveWeaponIsFullyLoaded(); + + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter *sourceEnt); + const char* GetSquadSlotDebugName( int iSquadSlot ); + + bool IsUsingTacticalVariant( int variant ); + bool IsUsingPathfindingVariant( int variant ) { return m_iPathfindingVariant == variant; } + + bool IsRunningApproachEnemySchedule(); + + // ------------- + // Sounds + // ------------- + void DeathSound( void ); + void PainSound( void ); + void IdleSound( void ); + void AlertSound( void ); + void LostEnemySound( void ); + void FoundEnemySound( void ); + void AnnounceAssault( void ); + void AnnounceEnemyType( CBaseEntity *pEnemy ); + void AnnounceEnemyKill( CBaseEntity *pEnemy ); + + void NotifyDeadFriend( CBaseEntity* pFriend ); + + virtual float HearingSensitivity( void ) { return 1.0; }; + int GetSoundInterests( void ); + virtual bool QueryHearSound( CSound *pSound ); + + // Speaking + void SpeakSentence( int sentType ); + + virtual int TranslateSchedule( int scheduleType ); + void OnStartSchedule( int scheduleType ); + + virtual bool ShouldPickADeathPose( void ); + +protected: + void SetKickDamage( int nDamage ) { m_nKickDamage = nDamage; } + CAI_Sentence< CNPC_Combine > *GetSentences() { return &m_Sentences; } + +private: + //========================================================= + // Combine S schedules + //========================================================= + enum + { + SCHED_COMBINE_SUPPRESS = BaseClass::NEXT_SCHEDULE, + SCHED_COMBINE_COMBAT_FAIL, + SCHED_COMBINE_VICTORY_DANCE, + SCHED_COMBINE_COMBAT_FACE, + SCHED_COMBINE_HIDE_AND_RELOAD, + SCHED_COMBINE_SIGNAL_SUPPRESS, + SCHED_COMBINE_ENTER_OVERWATCH, + SCHED_COMBINE_OVERWATCH, + SCHED_COMBINE_ASSAULT, + SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE, + SCHED_COMBINE_PRESS_ATTACK, + SCHED_COMBINE_WAIT_IN_COVER, + SCHED_COMBINE_RANGE_ATTACK1, + SCHED_COMBINE_RANGE_ATTACK2, + SCHED_COMBINE_TAKE_COVER1, + SCHED_COMBINE_TAKE_COVER_FROM_BEST_SOUND, + SCHED_COMBINE_RUN_AWAY_FROM_BEST_SOUND, + SCHED_COMBINE_GRENADE_COVER1, + SCHED_COMBINE_TOSS_GRENADE_COVER1, + SCHED_COMBINE_TAKECOVER_FAILED, + SCHED_COMBINE_GRENADE_AND_RELOAD, + SCHED_COMBINE_PATROL, + SCHED_COMBINE_BUGBAIT_DISTRACTION, + SCHED_COMBINE_CHARGE_TURRET, + SCHED_COMBINE_DROP_GRENADE, + SCHED_COMBINE_CHARGE_PLAYER, + SCHED_COMBINE_PATROL_ENEMY, + SCHED_COMBINE_BURNING_STAND, + SCHED_COMBINE_AR2_ALTFIRE, + SCHED_COMBINE_FORCED_GRENADE_THROW, + SCHED_COMBINE_MOVE_TO_FORCED_GREN_LOS, + SCHED_COMBINE_FACE_IDEAL_YAW, + SCHED_COMBINE_MOVE_TO_MELEE, + NEXT_SCHEDULE, + }; + + //========================================================= + // Combine Tasks + //========================================================= + enum + { + TASK_COMBINE_FACE_TOSS_DIR = BaseClass::NEXT_TASK, + TASK_COMBINE_IGNORE_ATTACKS, + TASK_COMBINE_SIGNAL_BEST_SOUND, + TASK_COMBINE_DEFER_SQUAD_GRENADES, + TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY, + TASK_COMBINE_DIE_INSTANTLY, + TASK_COMBINE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET, + TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS, + TASK_COMBINE_SET_STANDING, + NEXT_TASK + }; + + //========================================================= + // Combine Conditions + //========================================================= + enum Combine_Conds + { + COND_COMBINE_NO_FIRE = BaseClass::NEXT_CONDITION, + COND_COMBINE_DEAD_FRIEND, + COND_COMBINE_SHOULD_PATROL, + COND_COMBINE_HIT_BY_BUGBAIT, + COND_COMBINE_DROP_GRENADE, + COND_COMBINE_ON_FIRE, + COND_COMBINE_ATTACK_SLOT_AVAILABLE, + NEXT_CONDITION + }; + +private: + // Select the combat schedule + int SelectCombatSchedule(); + + // Should we charge the player? + bool ShouldChargePlayer(); + + // Chase the enemy, updating the target position as the player moves + void StartTaskChaseEnemyContinuously( const Task_t *pTask ); + void RunTaskChaseEnemyContinuously( const Task_t *pTask ); + + class CCombineStandoffBehavior : public CAI_ComponentWithOuter + { + typedef CAI_ComponentWithOuter BaseClass; + + virtual int SelectScheduleAttack() + { + int result = GetOuter()->SelectScheduleAttack(); + if ( result == SCHED_NONE ) + result = BaseClass::SelectScheduleAttack(); + return result; + } + }; + + // Rappel + virtual bool IsWaitingToRappel( void ) { return m_RappelBehavior.IsWaitingToRappel(); } + void BeginRappel() { m_RappelBehavior.BeginRappel(); } + +private: + int m_nKickDamage; + Vector m_vecTossVelocity; + EHANDLE m_hForcedGrenadeTarget; + bool m_bShouldPatrol; + bool m_bFirstEncounter;// only put on the handsign show in the squad's first encounter. + + // Time Variables + float m_flNextPainSoundTime; + float m_flNextAlertSoundTime; + float m_flNextGrenadeCheck; + float m_flNextLostSoundTime; + float m_flAlertPatrolTime; // When to stop doing alert patrol + float m_flNextAltFireTime; // Elites only. Next time to begin considering alt-fire attack. + + int m_nShots; + float m_flShotDelay; + float m_flStopMoveShootTime; + + CAI_Sentence< CNPC_Combine > m_Sentences; + + int m_iNumGrenades; + CAI_AssaultBehavior m_AssaultBehavior; + CCombineStandoffBehavior m_StandoffBehavior; + CAI_FollowBehavior m_FollowBehavior; + CAI_FuncTankBehavior m_FuncTankBehavior; + CAI_RappelBehavior m_RappelBehavior; + CAI_ActBusyBehavior m_ActBusyBehavior; + +public: + int m_iLastAnimEventHandled; + bool m_fIsElite; + Vector m_vecAltFireTarget; + + int m_iTacticalVariant; + int m_iPathfindingVariant; +}; + + +#endif // NPC_COMBINE_H diff --git a/game/server/hl2/npc_combines.h b/game/server/hl2/npc_combines.h new file mode 100644 index 0000000..e9dc75b --- /dev/null +++ b/game/server/hl2/npc_combines.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_COMBINES_H +#define NPC_COMBINES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "npc_combine.h" + +//========================================================= +// >> CNPC_CombineS +//========================================================= +class CNPC_CombineS : public CNPC_Combine +{ + DECLARE_CLASS( CNPC_CombineS, CNPC_Combine ); +#if HL2_EPISODIC + DECLARE_DATADESC(); +#endif + +public: + void Spawn( void ); + void Precache( void ); + void DeathSound( const CTakeDamageInfo &info ); + void PrescheduleThink( void ); + void BuildScheduleTestBits( void ); + int SelectSchedule ( void ); + float GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDamageInfo &info ); + void HandleAnimEvent( animevent_t *pEvent ); + void OnChangeActivity( Activity eNewActivity ); + void Event_Killed( const CTakeDamageInfo &info ); + void OnListened(); + + void ClearAttackConditions( void ); + + bool m_fIsBlocking; + + bool IsLightDamage( const CTakeDamageInfo &info ); + bool IsHeavyDamage( const CTakeDamageInfo &info ); + + virtual bool AllowedToIgnite( void ) { return true; } + +private: + bool ShouldHitPlayer( const Vector &targetDir, float targetDist ); + +#if HL2_EPISODIC +public: + Activity NPC_TranslateActivity( Activity eNewActivity ); + +protected: + /// whether to use the more casual march anim in ep2_outland_05 + int m_iUseMarch; +#endif + +}; + +#endif // NPC_COMBINES_H diff --git a/game/server/hl2/npc_crow.h b/game/server/hl2/npc_crow.h new file mode 100644 index 0000000..4ecac53 --- /dev/null +++ b/game/server/hl2/npc_crow.h @@ -0,0 +1,256 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_CROW_H +#define NPC_CROW_H +#ifdef _WIN32 +#pragma once +#endif + +#define BIRDTYPE_CROW 1 +#define BIRDTYPE_PIGEON 2 +#define BIRDTYPE_SEAGULL 3 + +// +// Spawnflags. +// +#define SF_CROW_FLYING 16 + +#define CROW_TAKEOFF_SPEED 170 +#define CROW_AIRSPEED 220 // FIXME: should be about 440, but I need to add acceleration + +// +// Custom schedules. +// +enum +{ + SCHED_CROW_IDLE_WALK = LAST_SHARED_SCHEDULE, + SCHED_CROW_IDLE_FLY, + + // + // Various levels of wanting to get away from something, selected + // by current value of m_nMorale. + // + SCHED_CROW_WALK_AWAY, + SCHED_CROW_RUN_AWAY, + SCHED_CROW_HOP_AWAY, + SCHED_CROW_FLY_AWAY, + + SCHED_CROW_FLY, + SCHED_CROW_FLY_FAIL, + + SCHED_CROW_BARNACLED, +}; + + +// +// Custom tasks. +// +enum +{ + TASK_CROW_FIND_FLYTO_NODE = LAST_SHARED_TASK, + //TASK_CROW_PREPARE_TO_FLY, + TASK_CROW_TAKEOFF, + //TASK_CROW_LAND, + TASK_CROW_FLY, + TASK_CROW_FLY_TO_HINT, + TASK_CROW_PICK_RANDOM_GOAL, + TASK_CROW_PICK_EVADE_GOAL, + TASK_CROW_HOP, + + TASK_CROW_FALL_TO_GROUND, + TASK_CROW_PREPARE_TO_FLY_RANDOM, + + TASK_CROW_WAIT_FOR_BARNACLE_KILL, +}; + + +// +// Custom conditions. +// +enum +{ + COND_CROW_ENEMY_TOO_CLOSE = LAST_SHARED_CONDITION, + COND_CROW_ENEMY_WAY_TOO_CLOSE, + COND_CROW_FORCED_FLY, + COND_CROW_BARNACLED, +}; + +enum FlyState_t +{ + FlyState_Walking = 0, + FlyState_Flying, + FlyState_Falling, + FlyState_Landing, +}; + + +//----------------------------------------------------------------------------- +// The crow class. +//----------------------------------------------------------------------------- +class CNPC_Crow : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_Crow, CAI_BaseNPC ); + +public: + + // + // CBaseEntity: + // + virtual void Spawn( void ); + virtual void Precache( void ); + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + + virtual int DrawDebugTextOverlays( void ); + + // + // CBaseCombatCharacter: + // + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual bool CorpseGib( const CTakeDamageInfo &info ); + bool BecomeRagdollOnClient( const Vector &force ); + + // + // CAI_BaseNPC: + // + virtual float MaxYawSpeed( void ) { return 120.0f; } + + virtual Class_T Classify( void ); + virtual void GatherEnemyConditions( CBaseEntity *pEnemy ); + + virtual void HandleAnimEvent( animevent_t *pEvent ); + virtual int GetSoundInterests( void ); + virtual int SelectSchedule( void ); + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + + virtual bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sourceEnt ); + + virtual void OnChangeActivity( Activity eNewActivity ); + + virtual bool OverrideMove( float flInterval ); + + virtual bool FValidateHintType( CAI_Hint *pHint ); + virtual Activity GetHintActivity( short sHintType, Activity HintsActivity ); + + virtual void PainSound( const CTakeDamageInfo &info ); + virtual void DeathSound( const CTakeDamageInfo &info ); + virtual void IdleSound( void ); + virtual void AlertSound( void ); + virtual void StopLoopingSounds( void ); + virtual void UpdateEfficiency( bool bInPVS ); + + virtual bool QueryHearSound( CSound *pSound ); + + void InputFlyAway( inputdata_t &inputdata ); + + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + void StartTargetHandling( CBaseEntity *pTargetEnt ); + + DEFINE_CUSTOM_AI; + DECLARE_DATADESC(); + + int m_iBirdType; + bool m_bOnJeep; + +protected: + void SetFlyingState( FlyState_t eState ); + inline bool IsFlying( void ) const { return GetNavType() == NAV_FLY; } + + void Takeoff( const Vector &vGoal ); + void FlapSound( void ); + + void MoveCrowFly( float flInterval ); + bool Probe( const Vector &vecMoveDir, float flSpeed, Vector &vecDeflect ); + + bool IsDeaf() { return m_bIsDeaf; } + +protected: + float m_flGroundIdleMoveTime; + + float m_flEnemyDist; // Distance to GetEnemy(), cached in GatherEnemyConditions. + int m_nMorale; // Used to determine which avoidance schedule to pick. Degrades as I pick avoidance schedules. + + bool m_bReachedMoveGoal; + + float m_flHopStartZ; // Our Z coordinate when we started a hop. Used to check for accidentally hopping off things. + + bool m_bPlayedLoopingSound; + +private: + + Activity NPC_TranslateActivity( Activity eNewActivity ); + + float m_flSoarTime; + bool m_bSoar; + Vector m_vLastStoredOrigin; + float m_flLastStuckCheck; + + float m_flDangerSoundTime; + + Vector m_vDesiredTarget; + Vector m_vCurrentTarget; + + bool m_bIsDeaf; +}; + +//----------------------------------------------------------------------------- +// Purpose: Seagull. Crow with a different model. +//----------------------------------------------------------------------------- +class CNPC_Seagull : public CNPC_Crow +{ + DECLARE_CLASS( CNPC_Seagull, CNPC_Crow ); + +public: + + void Spawn( void ) + { + SetModelName( AllocPooledString("models/seagull.mdl") ); + BaseClass::Spawn(); + + m_iBirdType = BIRDTYPE_SEAGULL; + } + + void PainSound( const CTakeDamageInfo &info ) + { + EmitSound( "NPC_Seagull.Pain" ); + } + + void DeathSound( const CTakeDamageInfo &info ) + { + EmitSound( "NPC_Seagull.Pain" ); + } + + void IdleSound( void ) + { + EmitSound( "NPC_Seagull.Idle" ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Pigeon. Crow with a different model. +//----------------------------------------------------------------------------- +class CNPC_Pigeon : public CNPC_Crow +{ + DECLARE_CLASS( CNPC_Pigeon, CNPC_Crow ); + +public: + void Spawn( void ) + { + SetModelName( AllocPooledString("models/pigeon.mdl") ); + BaseClass::Spawn(); + + m_iBirdType = BIRDTYPE_PIGEON; + } + + void IdleSound( void ) + { + EmitSound( "NPC_Pigeon.Idle" ); + } +}; + +#endif // NPC_CROW_H diff --git a/game/server/hl2/npc_headcrab.h b/game/server/hl2/npc_headcrab.h new file mode 100644 index 0000000..daf79b4 --- /dev/null +++ b/game/server/hl2/npc_headcrab.h @@ -0,0 +1,296 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the headcrab, a tiny, jumpy alien parasite. +// +//=============================================================================// + +#ifndef NPC_HEADCRAB_H +#define NPC_HEADCRAB_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_squadslot.h" +#include "ai_basenpc.h" +#include "soundent.h" + + + +abstract_class CBaseHeadcrab : public CAI_BaseNPC +{ + DECLARE_CLASS( CBaseHeadcrab, CAI_BaseNPC ); + +public: + void Spawn( void ); + void Precache( void ); + void RunTask( const Task_t *pTask ); + void StartTask( const Task_t *pTask ); + + void OnChangeActivity( Activity NewActivity ); + + bool IsFirmlyOnGround(); + void MoveOrigin( const Vector &vecDelta ); + void ThrowAt( const Vector &vecPos ); + void ThrowThink( void ); + virtual void JumpAttack( bool bRandomJump, const Vector &vecPos = vec3_origin, bool bThrown = false ); + void JumpToBurrowHint( CAI_Hint *pHint ); + + bool HasHeadroom(); + void LeapTouch ( CBaseEntity *pOther ); + virtual void TouchDamage( CBaseEntity *pOther ); + bool CorpseGib( const CTakeDamageInfo &info ); + void Touch( CBaseEntity *pOther ); + Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + float GetAutoAimRadius(); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false ); + + float MaxYawSpeed( void ); + void GatherConditions( void ); + void PrescheduleThink( void ); + Class_T Classify( void ); + void HandleAnimEvent( animevent_t *pEvent ); + int RangeAttack1Conditions ( float flDot, float flDist ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void ClampRagdollForce( const Vector &vecForceIn, Vector *vecForceOut ); + void Event_Killed( const CTakeDamageInfo &info ); + void BuildScheduleTestBits( void ); + bool FValidateHintType( CAI_Hint *pHint ); + + bool IsJumping( void ) { return m_bMidJump; } + + virtual void BiteSound( void ) = 0; + virtual void AttackSound( void ) {}; + virtual void ImpactSound( void ) {}; + virtual void TelegraphSound( void ) {}; + + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual int TranslateSchedule( int scheduleType ); + + virtual float GetReactionDelay( CBaseEntity *pEnemy ) { return 0.0; } + + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + void CrawlFromCanister(); + + virtual bool AllowedToIgnite( void ) { return true; } + + virtual bool CanBeAnEnemyOf( CBaseEntity *pEnemy ); + + bool IsHangingFromCeiling( void ) + { +#ifdef HL2_EPISODIC + return m_bHangingFromCeiling; +#else + return false; +#endif + } + + virtual void PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot ); + + void DropFromCeiling( void ); + + DEFINE_CUSTOM_AI; + DECLARE_DATADESC(); + +protected: + void HeadcrabInit(); + + void Leap( const Vector &vecVel ); + + void GrabHintNode( CAI_Hint *pHint ); + bool FindBurrow( const Vector &origin, float distance, bool excludeNear ); + bool ValidBurrowPoint( const Vector &point ); + void ClearBurrowPoint( const Vector &origin ); + void Burrow( void ); + void Unburrow( void ); + void SetBurrowed( bool bBurrowed ); + void JumpFromCanister(); + + // Begins the climb from the canister + void BeginClimbFromCanister(); + + void InputBurrow( inputdata_t &inputdata ); + void InputBurrowImmediate( inputdata_t &inputdata ); + void InputUnburrow( inputdata_t &inputdata ); + + void InputStartHangingFromCeiling( inputdata_t &inputdata ); + void InputDropFromCeiling( inputdata_t &inputdata ); + + int CalcDamageInfo( CTakeDamageInfo *pInfo ); + void CreateDust( bool placeDecal = true ); + + // Eliminates roll + pitch potentially in the headcrab at canister jump time + void EliminateRollAndPitch(); + + float InnateRange1MinRange( void ); + float InnateRange1MaxRange( void ); + +protected: + int m_nGibCount; + float m_flTimeDrown; + Vector m_vecCommittedJumpPos; // The position of our enemy when we locked in our jump attack. + + float m_flNextNPCThink; + float m_flIgnoreWorldCollisionTime; + + bool m_bCommittedToJump; // Whether we have 'locked in' to jump at our enemy. + bool m_bCrawlFromCanister; + bool m_bStartBurrowed; + bool m_bBurrowed; + bool m_bHidden; + bool m_bMidJump; + bool m_bAttackFailed; // whether we ran into a wall during a jump. + + float m_flBurrowTime; + int m_nContext; // for FValidateHintType context + int m_nJumpFromCanisterDir; + + bool m_bHangingFromCeiling; + float m_flIlluminatedTime; +}; + + +//========================================================= +//========================================================= +// The ever popular chubby classic headcrab +//========================================================= +//========================================================= +class CHeadcrab : public CBaseHeadcrab +{ + DECLARE_CLASS( CHeadcrab, CBaseHeadcrab ); + +public: + void Precache( void ); + void Spawn( void ); + + float MaxYawSpeed( void ); + Activity NPC_TranslateActivity( Activity eNewActivity ); + + void BiteSound( void ); + void PainSound( const CTakeDamageInfo &info ); + void DeathSound( const CTakeDamageInfo &info ); + void IdleSound( void ); + void AlertSound( void ); + void AttackSound( void ); + void TelegraphSound( void ); +}; + +//========================================================= +//========================================================= +// The spindly, fast headcrab +//========================================================= +//========================================================= +class CFastHeadcrab : public CBaseHeadcrab +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CFastHeadcrab, CBaseHeadcrab ); + + void Precache( void ); + void Spawn( void ); + bool QuerySeeEntity(CBaseEntity *pSightEnt, bool bOnlyHateOrFearIfNPC = false); + + float MaxYawSpeed( void ); + + void PrescheduleThink( void ); + void RunTask( const Task_t *pTask ); + void StartTask( const Task_t *pTask ); + + int SelectSchedule( void ); + int TranslateSchedule( int scheduleType ); + + int m_iRunMode; + float m_flRealGroundSpeed; + float m_flSlowRunTime; + float m_flPauseTime; + Vector m_vecJumpVel; + + void BiteSound( void ); + void PainSound( const CTakeDamageInfo &info ); + void DeathSound( const CTakeDamageInfo &info ); + void IdleSound( void ); + void AlertSound( void ); + void AttackSound( void ); + + enum SquadSlot_t + { + SQUAD_SLOT_ENGAGE1 = LAST_SHARED_SQUADSLOT, + SQUAD_SLOT_ENGAGE2, + SQUAD_SLOT_ENGAGE3, + SQUAD_SLOT_ENGAGE4, + }; + + DEFINE_CUSTOM_AI; +}; + + +//========================================================= +//========================================================= +// Treacherous black headcrab +//========================================================= +//========================================================= +class CBlackHeadcrab : public CBaseHeadcrab +{ + DECLARE_CLASS( CBlackHeadcrab, CBaseHeadcrab ); + +public: + void Eject( const QAngle &vecAngles, float flVelocityScale, CBaseEntity *pEnemy ); + void EjectTouch( CBaseEntity *pOther ); + + // + // CBaseHeadcrab implementation. + // + void TouchDamage( CBaseEntity *pOther ); + void BiteSound( void ); + void AttackSound( void ); + + // + // CAI_BaseNPC implementation. + // + virtual void PrescheduleThink( void ); + virtual void BuildScheduleTestBits( void ); + virtual int SelectSchedule( void ); + virtual int TranslateSchedule( int scheduleType ); + + virtual Activity NPC_TranslateActivity( Activity eNewActivity ); + virtual void HandleAnimEvent( animevent_t *pEvent ); + virtual float MaxYawSpeed( void ); + + virtual int GetSoundInterests( void ) { return (BaseClass::GetSoundInterests() | SOUND_DANGER | SOUND_BULLET_IMPACT); } + + bool IsHeavyDamage( const CTakeDamageInfo &info ); + + virtual void PainSound( const CTakeDamageInfo &info ); + virtual void DeathSound( const CTakeDamageInfo &info ); + virtual void IdleSound( void ); + virtual void AlertSound( void ); + virtual void ImpactSound( void ); + virtual void TelegraphSound( void ); +#if HL2_EPISODIC + virtual bool FInViewCone( CBaseEntity *pEntity ); +#endif + + // + // CBaseEntity implementation. + // + virtual void Precache( void ); + virtual void Spawn( void ); + + DEFINE_CUSTOM_AI; + DECLARE_DATADESC(); + +private: + + + void JumpFlinch( const Vector *pvecAwayFromPos ); + void Panic( float flDuration ); + + bool m_bPanicState; + float m_flPanicStopTime; + float m_flNextHopTime; // Keeps us from hopping too often due to damage. +}; + + +#endif // NPC_HEADCRAB_H diff --git a/game/server/hl2/npc_houndeye.h b/game/server/hl2/npc_houndeye.h new file mode 100644 index 0000000..1e7d8ca --- /dev/null +++ b/game/server/hl2/npc_houndeye.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_HOUNDEYE_H +#define NPC_HOUNDEYE_H +#pragma once + + +#include "ai_basenpc.h" + +#include "energy_wave.h" + +class CNPC_Houndeye : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_Houndeye, CAI_BaseNPC ); + +public: + void Spawn( void ); + void Precache( void ); + Class_T Classify ( void ); + void HandleAnimEvent( animevent_t *pEvent ); + float MaxYawSpeed ( void ); + void WarmUpSound ( void ); + void AlertSound( void ); + void DeathSound( const CTakeDamageInfo &info ); + void WarnSound( void ); + void PainSound( const CTakeDamageInfo &info ); + void IdleSound( void ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + int GetSoundInterests( void ); + void SonicAttack( void ); + void PrescheduleThink( void ); + void WriteBeamColor ( void ); + int RangeAttack1Conditions ( float flDot, float flDist ); + bool FCanActiveIdle ( void ); + virtual int TranslateSchedule( int scheduleType ); + Activity NPC_TranslateActivity( Activity eNewActivity ); + virtual int SelectSchedule( void ); + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + void NPCThink(void); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + bool IsAnyoneInSquadAttacking( void ); + void SpeakSentence( int sentenceType ); + + float m_flNextSecondaryAttack; + bool m_bLoopClockwise; + + CEnergyWave* m_pEnergyWave; + float m_flEndEnergyWaveTime; + + bool m_fAsleep;// some houndeyes sleep in idle mode if this is set, the houndeye is lying down + bool m_fDontBlink;// don't try to open/close eye if this bit is set! + + DEFINE_CUSTOM_AI; + + DECLARE_DATADESC(); +}; + + +#endif // NPC_HOUNDEYE_H diff --git a/game/server/hl2/npc_hydra.h b/game/server/hl2/npc_hydra.h new file mode 100644 index 0000000..253dbe0 --- /dev/null +++ b/game/server/hl2/npc_hydra.h @@ -0,0 +1,179 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_HYDRA_H +#define NPC_HYDRA_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "ai_basenpc.h" +#include "soundenvelope.h" + +class CNPC_Hydra; + +//----------------------------------------------------------------------------- +// CNPC_Hydra +// +//----------------------------------------------------------------------------- + +class HydraBone +{ +public: + HydraBone( void ) + { + vecPos = Vector( 0, 0, 0 ); + vecDelta = Vector( 0, 0, 0 ); + //vecBendDelta = Vector( 0, 0, 0 ); + //vecGoalDelta = Vector( 0, 0, 0 ); + //flBendTension = 0.0; + flIdealLength = 1.0; + flGoalInfluence = 0.0; + bStuck = false; + bOnFire = false; + }; + + Vector vecPos; + Vector vecDelta; + //float flBendTension; + float flIdealLength; + bool bStuck; + bool bOnFire; + + float flActualLength; + //Vector vecBendDelta; + //Vector vecGoalDelta; + // float flAccumLength; + + Vector vecGoalPos; + float flGoalInfluence; + + DECLARE_SIMPLE_DATADESC(); +}; + +class CNPC_Hydra : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_Hydra, CAI_BaseNPC ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +public: + CNPC_Hydra() + { + } + + void Spawn( void ); + void Precache( void ); + void Activate( void ); + + Class_T Classify( void ); + + void RunAI( void ); + + float MaxYawSpeed( void ); + int TranslateSchedule( int scheduleType ); + int SelectSchedule( void ); + + void PrescheduleThink( void ); + + void HandleAnimEvent( animevent_t *pEvent ); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + +#define CHAIN_LINKS 32 + + CNetworkArray( Vector, m_vecChain, CHAIN_LINKS ); + int m_activeChain; + + bool m_bHasStuckSegments; + float m_flCurrentLength; + + Vector m_vecHeadGoal; + float m_flHeadGoalInfluence; + CNetworkVector( m_vecHeadDir ); + + CNetworkVar( float, m_flRelaxedLength ); + + Vector m_vecOutward; + + CUtlVector < HydraBone > m_body; + + float m_idealLength; + float m_idealSegmentLength; + + Vector TestPosition( float t ); + + void CalcGoalForces( void ); + void MoveBody( void ); + + void AdjustLength( void ); + void CheckLength( void ); + + bool m_bExtendSoundActive; + CSoundPatch *m_pExtendTentacleSound; + + void Nudge( CBaseEntity *pHitEntity, const Vector &vecContact, const Vector &vecSpeed ); + void Stab( CBaseEntity *pHitEntity, const Vector &vecSpeed, trace_t &ptr ); + void Kick( CBaseEntity *pHitEntity, const Vector &vecContact, const Vector &vecSpeed ); + void Splash( const Vector &vecSplashPos ); + + // float FreeNeckLength( void ); + + virtual Vector EyePosition( void ); + virtual const QAngle &EyeAngles( void ); + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy) ; + + void AimHeadInTravelDirection( float flInfluence ); + + float m_seed; + + // -------------------------------- + Vector m_vecTarget; + Vector m_vecTargetDir; + + float m_flLastAdjustmentTime; + float m_flTaskStartTime; + float m_flTaskEndTime; + + float m_flLengthTime; // time of last successful length adjustment time + + // -------------------------------- + + bool ContractFromHead( void ); + bool ContractBetweenStuckSegments( void ); + bool ContractFromRoot( void ); + + int VirtualRoot( void ); + + bool AddNodeBefore( int iNode ); + bool AddNodeAfter( int iNode ); + + bool GrowFromVirtualRoot( void ); + bool GrowFromMostStretched( void ); + + void CalcRelaxedLength( void ); + + bool IsValidConnection( int iNode0, int iNode1 ); + + void AttachStabbedEntity( CBaseAnimating *pAnimating, Vector vecForce, trace_t &tr ); + void UpdateStabbedEntity( void ); + void DetachStabbedEntity( bool playSound ); + void GetDesiredImpaledPosition( Vector *vecOrigin, QAngle *vecAngles ); + + bool m_bStabbedEntity; + + DEFINE_CUSTOM_AI; + +private: +}; + +//----------------------------------------------------------------------------- + +#endif // NPC_HYDRA_H diff --git a/game/server/hl2/npc_manhack.h b/game/server/hl2/npc_manhack.h new file mode 100644 index 0000000..17a3ced --- /dev/null +++ b/game/server/hl2/npc_manhack.h @@ -0,0 +1,280 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_MANHACK_H +#define NPC_MANHACK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc_physicsflyer.h" +#include "Sprite.h" +#include "SpriteTrail.h" +#include "player_pickup.h" + +// Start with the engine off and folded up. +#define SF_MANHACK_PACKED_UP (1 << 16) +#define SF_MANHACK_NO_DAMAGE_EFFECTS (1 << 17) +#define SF_MANHACK_USE_AIR_NODES (1 << 18) +#define SF_MANHACK_CARRIED (1 << 19) // Being carried by a metrocop +#define SF_MANHACK_NO_DANGER_SOUNDS (1 << 20) + +enum +{ + MANHACK_EYE_STATE_IDLE, + MANHACK_EYE_STATE_CHASE, + MANHACK_EYE_STATE_CHARGE, + MANHACK_EYE_STATE_STUNNED, +}; + +//----------------------------------------------------------------------------- +// Attachment points. +//----------------------------------------------------------------------------- +#define MANHACK_GIB_HEALTH 30 +#define MANHACK_INACTIVE_HEALTH 25 +#define MANHACK_MAX_SPEED 500 +#define MANHACK_BURST_SPEED 650 +#define MANHACK_NPC_BURST_SPEED 800 + +//----------------------------------------------------------------------------- +// Movement parameters. +//----------------------------------------------------------------------------- +#define MANHACK_WAYPOINT_DISTANCE 25 // Distance from waypoint that counts as arrival. + +class CSprite; +class SmokeTrail; +class CSoundPatch; + +//----------------------------------------------------------------------------- +// Manhack +//----------------------------------------------------------------------------- +class CNPC_Manhack : public CNPCBaseInteractive, public CDefaultPlayerPickupVPhysics +{ +DECLARE_CLASS( CNPC_Manhack, CNPCBaseInteractive ); +DECLARE_SERVERCLASS(); + +public: + CNPC_Manhack(); + ~CNPC_Manhack(); + + Class_T Classify(void); + + bool CorpseGib( const CTakeDamageInfo &info ); + void Event_Dying(void); + void Event_Killed( const CTakeDamageInfo &info ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + int OnTakeDamage_Dying( const CTakeDamageInfo &info ); + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition ); + float GetDefaultNavGoalTolerance(); + + void UpdateOnRemove( void ); + void KillSprites( float flDelay ); + + void OnStateChange( NPC_STATE OldState, NPC_STATE NewState ); + + virtual bool CreateVPhysics( void ); + + virtual void DeathSound( const CTakeDamageInfo &info ); + virtual bool ShouldGib( const CTakeDamageInfo &info ); + + Activity NPC_TranslateActivity( Activity baseAct ); + virtual int TranslateSchedule( int scheduleType ); + int MeleeAttack1Conditions ( float flDot, float flDist ); + void HandleAnimEvent( animevent_t *pEvent ); + + bool OverrideMove(float flInterval); + void MoveToTarget(float flInterval, const Vector &MoveTarget); + void MoveExecute_Alive(float flInterval); + void MoveExecute_Dead(float flInterval); + int MoveCollisionMask(void); + + void TurnHeadRandomly( float flInterval ); + + void CrashTouch( CBaseEntity *pOther ); + + void StartEngine( bool fStartSound ); + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ) { return WorldSpaceCenter(); } + + virtual float GetHeadTurnRate( void ) { return 45.0f; } // Degrees per second + + void CheckCollisions(float flInterval); + virtual void GatherEnemyConditions( CBaseEntity *pEnemy ); + void PlayFlySound(void); + virtual void StopLoopingSounds(void); + + void Precache(void); + void RunTask( const Task_t *pTask ); + void Spawn(void); + void Activate(); + void StartTask( const Task_t *pTask ); + + void BladesInit(); + void SoundInit( void ); + void StartEye( void ); + + bool HandleInteraction(int interactionType, void* data, CBaseCombatCharacter* sourceEnt); + + void PostNPCInit( void ); + + void GatherConditions(); + void PrescheduleThink( void ); + + void SpinBlades(float flInterval); + + void Slice( CBaseEntity *pHitEntity, float flInterval, trace_t &tr ); + void Bump( CBaseEntity *pHitEntity, float flInterval, trace_t &tr ); + void Splash( const Vector &vecSplashPos ); + + float ManhackMaxSpeed( void ); + virtual void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent ); + void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + void HitPhysicsObject( CBaseEntity *pOther ); + virtual void ClampMotorForces( Vector &linear, AngularImpulse &angular ); + unsigned int PhysicsSolidMaskForEntity( void ) const; + + // Create smoke trail! + void CreateSmokeTrail(); + void DestroySmokeTrail(); + + void Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner ) { return; } + + void InputDisableSwarm( inputdata_t &inputdata ); + void InputUnpack( inputdata_t &inputdata ); + + // CDefaultPlayerPickupVPhysics + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + + CBasePlayer *HasPhysicsAttacker( float dt ); + + float GetMaxEnginePower(); + + // INPCInteractive Functions + virtual bool CanInteractWith( CAI_BaseNPC *pUser ) { return false; } // Disabled for now (sjb) + virtual bool HasBeenInteractedWith() { return m_bHackedByAlyx; } + virtual void NotifyInteraction( CAI_BaseNPC *pUser ) + { + // Turn the sprites off and on again so their colors will change. + KillSprites(0.0f); + m_bHackedByAlyx = true; + StartEye(); + } + + virtual void InputPowerdown( inputdata_t &inputdata ) + { + m_iHealth = 0; + } + + + DEFINE_CUSTOM_AI; + + DECLARE_DATADESC(); + +private: + + bool IsInEffectiveTargetZone( CBaseEntity *pTarget ); + void MaintainGroundHeight( void ); + + void StartBurst( const Vector &vecDirection ); + void StopBurst( bool bInterruptSchedule = false ); + + void UpdatePanels( void ); + void SetEyeState( int state ); + + void ShowHostile( bool hostile = true ); + + bool IsFlyingActivity( Activity baseAct ); + + // Computes the slice bounce velocity + void ComputeSliceBounceVelocity( CBaseEntity *pHitEntity, trace_t &tr ); + + // Take damage from being thrown by a physcannon + void TakeDamageFromPhyscannon( CBasePlayer *pPlayer ); + + // Take damage from a vehicle: + void TakeDamageFromVehicle( int index, gamevcollisionevent_t *pEvent ); + + // Take damage from physics impacts + void TakeDamageFromPhysicsImpact( int index, gamevcollisionevent_t *pEvent ); + + // Are we being held by the physcannon? + bool IsHeldByPhyscannon( ); + + void StartLoitering( const Vector &vecLoiterPosition ); + void StopLoitering() { m_vecLoiterPosition = vec3_invalid; m_fTimeNextLoiterPulse = gpGlobals->curtime; } + bool IsLoitering() { return m_vecLoiterPosition != vec3_invalid; } + void Loiter(); + + // + // Movement variables. + // + + Vector m_vForceVelocity; // Someone forced me to move + + Vector m_vTargetBanking; + + Vector m_vForceMoveTarget; // Will fly here + float m_fForceMoveTime; // If time is less than this + Vector m_vSwarmMoveTarget; // Will fly here + float m_fSwarmMoveTime; // If time is less than this + float m_fEnginePowerScale; // scale all thrust by this amount (usually 1.0!) + + float m_flNextEngineSoundTime; + float m_flEngineStallTime; + + float m_flNextBurstTime; + float m_flBurstDuration; + Vector m_vecBurstDirection; + + float m_flWaterSuspendTime; + int m_nLastSpinSound; + + // physics influence + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + + // Death + float m_fSparkTime; + float m_fSmokeTime; + + bool m_bDirtyPitch; // indicates whether we want the sound pitch updated.(sjb) + bool m_bShowingHostile; + + bool m_bBladesActive; + bool m_bIgnoreClipbrushes; + + float m_flBladeSpeed; + + CSprite *m_pEyeGlow; + CSprite *m_pLightGlow; + + CHandle m_hSmokeTrail; + + int m_iPanel1; + int m_iPanel2; + int m_iPanel3; + int m_iPanel4; + + int m_nLastWaterLevel; + bool m_bDoSwarmBehavior; + bool m_bGib; + + bool m_bHeld; + bool m_bHackedByAlyx; + Vector m_vecLoiterPosition; + float m_fTimeNextLoiterPulse; + + float m_flBumpSuppressTime; + + CNetworkVar( int, m_nEnginePitch1 ); + CNetworkVar( int, m_nEnginePitch2 ); + CNetworkVar( float, m_flEnginePitch1Time ); + CNetworkVar( float, m_flEnginePitch2Time ); +}; + +#endif //NPC_MANHACK_H diff --git a/game/server/hl2/npc_metropolice.h b/game/server/hl2/npc_metropolice.h new file mode 100644 index 0000000..544fc68 --- /dev/null +++ b/game/server/hl2/npc_metropolice.h @@ -0,0 +1,470 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_METROPOLICE_H +#define NPC_METROPOLICE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "rope.h" +#include "rope_shared.h" +#include "ai_baseactor.h" +#include "ai_basenpc.h" +#include "ai_goal_police.h" +#include "ai_behavior.h" +#include "ai_behavior_standoff.h" +#include "ai_behavior_assault.h" +#include "ai_behavior_functank.h" +#include "ai_behavior_actbusy.h" +#include "ai_behavior_rappel.h" +#include "ai_behavior_police.h" +#include "ai_behavior_follow.h" +#include "ai_sentence.h" +#include "props.h" + +class CNPC_MetroPolice; + +class CNPC_MetroPolice : public CAI_BaseActor +{ + DECLARE_CLASS( CNPC_MetroPolice, CAI_BaseActor ); + DECLARE_DATADESC(); + +public: + CNPC_MetroPolice(); + + virtual bool CreateComponents(); + bool CreateBehaviors(); + void Spawn( void ); + void Precache( void ); + + Class_T Classify( void ); + Disposition_t IRelationType(CBaseEntity *pTarget); + float MaxYawSpeed( void ); + void HandleAnimEvent( animevent_t *pEvent ); + Activity NPC_TranslateActivity( Activity newActivity ); + + Vector EyeDirection3D( void ) { return CAI_BaseHumanoid::EyeDirection3D(); } // cops don't have eyes + + virtual void Event_Killed( const CTakeDamageInfo &info ); + + virtual void OnScheduleChange(); + + float GetIdealAccel( void ) const; + int ObjectCaps( void ) { return UsableNPCObjectCaps(BaseClass::ObjectCaps()); } + void PrecriminalUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + // These are overridden so that the cop can shove and move a non-criminal player safely + CBaseEntity *CheckTraceHullAttack( float flDist, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float forceScale, bool bDamageAnyNPC ); + CBaseEntity *CheckTraceHullAttack( const Vector &vStart, const Vector &vEnd, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float flForceScale, bool bDamageAnyNPC ); + + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual int TranslateSchedule( int scheduleType ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + virtual Vector GetActualShootTrajectory( const Vector &shootOrigin ); + virtual void FireBullets( const FireBulletsInfo_t &info ); + virtual bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); + + //virtual bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + bool ShouldBruteForceFailedNav() { return false; } + + virtual void GatherConditions( void ); + + virtual bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + + // Can't move and shoot when the enemy is an airboat + virtual bool ShouldMoveAndShoot(); + + // TraceAttack + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + // Speaking + virtual void SpeakSentence( int nSentenceType ); + + // Set up the shot regulator based on the equipped weapon + virtual void OnUpdateShotRegulator( ); + + bool ShouldKnockOutTarget( CBaseEntity *pTarget ); + void KnockOutTarget( CBaseEntity *pTarget ); + void StunnedTarget( CBaseEntity *pTarget ); + void AdministerJustice( void ); + + bool QueryHearSound( CSound *pSound ); + + void SetBatonState( bool state ); + bool BatonActive( void ); + + CAI_Sentence< CNPC_MetroPolice > *GetSentences() { return &m_Sentences; } + + virtual bool AllowedToIgnite( void ) { return true; } + + void PlayFlinchGesture( void ); + +protected: + // Determines the best type of flinch anim to play. + virtual Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture ); + + // Only move and shoot when attacking + virtual bool OnBeginMoveAndShoot(); + virtual void OnEndMoveAndShoot(); + +private: + bool PlayerIsCriminal( void ); + void ReleaseManhack( void ); + + // Speech-related methods + void AnnounceTakeCoverFromDanger( CSound *pSound ); + void AnnounceEnemyType( CBaseEntity *pEnemy ); + void AnnounceEnemyKill( CBaseEntity *pEnemy ); + void AnnounceHarrassment( ); + void AnnounceOutOfAmmo( ); + + // Behavior-related sentences + void SpeakFuncTankSentence( int nSentenceType ); + void SpeakAssaultSentence( int nSentenceType ); + void SpeakStandoffSentence( int nSentenceType ); + + virtual void LostEnemySound( void ); + virtual void FoundEnemySound( void ); + virtual void AlertSound( void ); + virtual void PainSound( const CTakeDamageInfo &info ); + virtual void DeathSound( const CTakeDamageInfo &info ); + virtual void IdleSound( void ); + virtual bool ShouldPlayIdleSound( void ); + + // Burst mode! + void SetBurstMode( bool bEnable ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + int GetSoundInterests( void ); + + void BuildScheduleTestBits( void ); + + bool CanDeployManhack( void ); + + bool ShouldHitPlayer( const Vector &targetDir, float targetDist ); + + void PrescheduleThink( void ); + + void SetPlayerCriminalDuration( float time ); + + void IncrementPlayerCriminalStatus( void ); + + virtual bool UseAttackSquadSlots() { return true; } + + WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); + + // Inputs + void InputEnableManhackToss( inputdata_t &inputdata ); + void InputSetPoliceGoal( inputdata_t &inputdata ); + void InputActivateBaton( inputdata_t &inputdata ); + + void NotifyDeadFriend ( CBaseEntity* pFriend ); + + // Stitch aiming! + void AimBurstRandomly( int nMinCount, int nMaxCount, float flMinDelay, float flMaxDelay ); + void AimBurstAtEnemy( float flReactionTime ); + void AimBurstInFrontOfEnemy( float flReactionTime ); + void AimBurstAlongSideOfEnemy( float flFollowTime ); + void AimBurstBehindEnemy( float flFollowTime ); + void AimBurstTightGrouping( float flShotTime ); + + // Anim event handlers + void OnAnimEventDeployManhack( animevent_t *pEvent ); + void OnAnimEventShove( void ); + void OnAnimEventBatonOn( void ); + void OnAnimEventBatonOff( void ); + void OnAnimEventStartDeployManhack( void ); + void OnAnimEventPreDeployManhack( void ); + + bool HasBaton( void ); + + // Normal schedule selection + int SelectCombatSchedule(); + int SelectScheduleNewEnemy(); + int SelectScheduleArrestEnemy(); + int SelectRangeAttackSchedule(); + int SelectScheduleNoDirectEnemy(); + int SelectScheduleInvestigateSound(); + int SelectShoveSchedule( void ); + + bool TryToEnterPistolSlot( int nSquadSlot ); + + // Airboat schedule selection + int SelectAirboatCombatSchedule(); + int SelectAirboatRangeAttackSchedule(); + + // Handle flinching + bool IsHeavyDamage( const CTakeDamageInfo &info ); + + // Is my enemy currently in an airboat? + bool IsEnemyInAnAirboat() const; + + // Returns the airboat + CBaseEntity *GetEnemyAirboat() const; + + // Compute a predicted enemy position n seconds into the future + void PredictShootTargetPosition( float flDeltaTime, float flMinLeadDist, float flAddVelocity, Vector *pVecTarget, Vector *pVecTargetVel ); + + // Compute a predicted velocity n seconds into the future (given a known acceleration rate) + void PredictShootTargetVelocity( float flDeltaTime, Vector *pVecTargetVel ); + + // How many shots will I fire in a particular amount of time? + int CountShotsInTime( float flDeltaTime ) const; + float GetTimeForShots( int nShotCount ) const; + + // Visualize stitch + void VisualizeStitch( const Vector &vecStart, const Vector &vecEnd ); + + // Visualize line of death + void VisualizeLineOfDeath( ); + + // Modify the stitch length + float ComputeDistanceStitchModifier( float flDistanceToTarget ) const; + + // Adjusts the burst toward the target as it's being fired. + void SteerBurstTowardTarget( ); + + // Methods to compute shot trajectory based on burst mode + Vector ComputeBurstLockOnTrajectory( const Vector &shootOrigin ); + Vector ComputeBurstDeliberatelyMissTrajectory( const Vector &shootOrigin ); + Vector ComputeBurstTrajectory( const Vector &shootOrigin ); + Vector ComputeTightBurstTrajectory( const Vector &shootOrigin ); + + // Are we currently firing a burst? + bool IsCurrentlyFiringBurst() const; + + // Which entity are we actually trying to shoot at? + CBaseEntity *GetShootTarget(); + + // Different burst steering modes + void SteerBurstTowardTargetUseSpeedOnly( const Vector &vecShootAt, const Vector &vecShootAtVelocity, float flPredictTime, int nShotsTillPredict ); + void SteerBurstTowardTargetUseVelocity( const Vector &vecShootAt, const Vector &vecShootAtVelocity, int nShotsTillPredict ); + void SteerBurstTowardTargetUsePosition( const Vector &vecShootAt, const Vector &vecShootAtVelocity, int nShotsTillPredict ); + void SteerBurstTowardPredictedPoint( const Vector &vecShootAt, const Vector &vecShootAtVelocity, int nShotsTillPredict ); + void SteerBurstWithinLineOfDeath( ); + + // Set up the shot regulator + int SetupBurstShotRegulator( float flReactionTime ); + + // Choose a random vector somewhere between the two specified vectors + void RandomDirectionBetweenVectors( const Vector &vecStart, const Vector &vecEnd, Vector *pResult ); + + // Stitch selector + float StitchAtWeight( float flDist, float flSpeed, float flDot, float flReactionTime, const Vector &vecTargetToGun ); + float StitchAcrossWeight( float flDist, float flSpeed, float flDot, float flReactionTime ); + float StitchAlongSideWeight( float flDist, float flSpeed, float flDot ); + float StitchBehindWeight( float flDist, float flSpeed, float flDot ); + float StitchTightWeight( float flDist, float flSpeed, const Vector &vecTargetToGun, const Vector &vecVelocity ); + int SelectStitchSchedule(); + + // Can me enemy see me? + bool CanEnemySeeMe( ); + + // Combat schedule selection + int SelectMoveToLedgeSchedule(); + + // position to shoot at + Vector StitchAimTarget( const Vector &posSrc, bool bNoisy ); + + // Should we attempt to stitch? + bool ShouldAttemptToStitch(); + + // Deliberately aims as close as possible w/o hitting + Vector AimCloseToTargetButMiss( CBaseEntity *pTarget, const Vector &shootOrigin ); + + // Compute the actual reaction time based on distance + speed modifiers + float AimBurstAtReactionTime( float flReactonTime, float flDistToTargetSqr, float flCurrentSpeed ); + int AimBurstAtSetupHitCount( float flDistToTargetSqr, float flCurrentSpeed ); + + // How many squad members are trying to arrest the player? + int SquadArrestCount(); + + // He's resisting arrest! + void EnemyResistingArrest(); + void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + + // Rappel + virtual bool IsWaitingToRappel( void ) { return m_RappelBehavior.IsWaitingToRappel(); } + void BeginRappel() { m_RappelBehavior.BeginRappel(); } + +private: + enum + { + BURST_NOT_ACTIVE = 0, + BURST_ACTIVE, + BURST_LOCK_ON_AFTER_HIT, + BURST_LOCKED_ON, + BURST_DELIBERATELY_MISS, + BURST_TIGHT_GROUPING, + }; + + enum + { + BURST_STEER_NONE = 0, + BURST_STEER_TOWARD_PREDICTED_POINT, + BURST_STEER_WITHIN_LINE_OF_DEATH, + BURST_STEER_ADJUST_FOR_SPEED_CHANGES, + BURST_STEER_EXACTLY_TOWARD_TARGET, + }; + + enum + { + COND_METROPOLICE_ON_FIRE = BaseClass::NEXT_CONDITION, + COND_METROPOLICE_ENEMY_RESISTING_ARREST, + COND_METROPOLICE_PLAYER_TOO_CLOSE, + COND_METROPOLICE_CHANGE_BATON_STATE, + COND_METROPOLICE_PHYSOBJECT_ASSAULT, + + }; + + enum + { + SCHED_METROPOLICE_WALK = BaseClass::NEXT_SCHEDULE, + SCHED_METROPOLICE_WAKE_ANGRY, + SCHED_METROPOLICE_HARASS, + SCHED_METROPOLICE_CHASE_ENEMY, + SCHED_METROPOLICE_ESTABLISH_LINE_OF_FIRE, + SCHED_METROPOLICE_DRAW_PISTOL, + SCHED_METROPOLICE_DEPLOY_MANHACK, + SCHED_METROPOLICE_ADVANCE, + SCHED_METROPOLICE_CHARGE, + SCHED_METROPOLICE_BURNING_RUN, + SCHED_METROPOLICE_BURNING_STAND, + SCHED_METROPOLICE_SMG_NORMAL_ATTACK, + SCHED_METROPOLICE_SMG_BURST_ATTACK, + SCHED_METROPOLICE_AIM_STITCH_AT_AIRBOAT, + SCHED_METROPOLICE_AIM_STITCH_IN_FRONT_OF_AIRBOAT, + SCHED_METROPOLICE_AIM_STITCH_TIGHTLY, + SCHED_METROPOLICE_AIM_STITCH_ALONG_SIDE_OF_AIRBOAT, + SCHED_METROPOLICE_AIM_STITCH_BEHIND_AIRBOAT, + SCHED_METROPOLICE_ESTABLISH_STITCH_LINE_OF_FIRE, + SCHED_METROPOLICE_INVESTIGATE_SOUND, + SCHED_METROPOLICE_WARN_AND_ARREST_ENEMY, + SCHED_METROPOLICE_ARREST_ENEMY, + SCHED_METROPOLICE_ENEMY_RESISTING_ARREST, + SCHED_METROPOLICE_WARN_TARGET, + SCHED_METROPOLICE_HARASS_TARGET, + SCHED_METROPOLICE_SUPPRESS_TARGET, + SCHED_METROPOLICE_RETURN_FROM_HARASS, + SCHED_METROPOLICE_SHOVE, + SCHED_METROPOLICE_ACTIVATE_BATON, + SCHED_METROPOLICE_DEACTIVATE_BATON, + SCHED_METROPOLICE_ALERT_FACE_BESTSOUND, + SCHED_METROPOLICE_RETURN_TO_PRECHASE, + SCHED_METROPOLICE_SMASH_PROP, + }; + + enum + { + TASK_METROPOLICE_HARASS = BaseClass::NEXT_TASK, + TASK_METROPOLICE_DIE_INSTANTLY, + TASK_METROPOLICE_BURST_ATTACK, + TASK_METROPOLICE_STOP_FIRE_BURST, + TASK_METROPOLICE_AIM_STITCH_AT_PLAYER, + TASK_METROPOLICE_AIM_STITCH_AT_AIRBOAT, + TASK_METROPOLICE_AIM_STITCH_TIGHTLY, + TASK_METROPOLICE_AIM_STITCH_IN_FRONT_OF_AIRBOAT, + TASK_METROPOLICE_AIM_STITCH_ALONG_SIDE_OF_AIRBOAT, + TASK_METROPOLICE_AIM_STITCH_BEHIND_AIRBOAT, + TASK_METROPOLICE_RELOAD_FOR_BURST, + TASK_METROPOLICE_GET_PATH_TO_STITCH, + TASK_METROPOLICE_RESET_LEDGE_CHECK_TIME, + TASK_METROPOLICE_GET_PATH_TO_BESTSOUND_LOS, + TASK_METROPOLICE_AIM_WEAPON_AT_ENEMY, + TASK_METROPOLICE_ARREST_ENEMY, + TASK_METROPOLICE_LEAD_ARREST_ENEMY, + TASK_METROPOLICE_SIGNAL_FIRING_TIME, + TASK_METROPOLICE_ACTIVATE_BATON, + TASK_METROPOLICE_WAIT_FOR_SENTENCE, + TASK_METROPOLICE_GET_PATH_TO_PRECHASE, + TASK_METROPOLICE_CLEAR_PRECHASE, + }; + +private: + + int m_iPistolClips; // How many clips the cop has in reserve + int m_iManhacks; // How many manhacks the cop has + bool m_fWeaponDrawn; // Is my weapon drawn? (ready to use) + bool m_bSimpleCops; // The easy version of the cops + int m_LastShootSlot; + CRandSimTimer m_TimeYieldShootSlot; + CSimpleSimTimer m_BatonSwingTimer; + CSimpleSimTimer m_NextChargeTimer; + + // All related to burst firing + Vector m_vecBurstTargetPos; + Vector m_vecBurstDelta; + int m_nBurstHits; + int m_nMaxBurstHits; + int m_nBurstReloadCount; + Vector m_vecBurstLineOfDeathDelta; + Vector m_vecBurstLineOfDeathOrigin; + int m_nBurstMode; + int m_nBurstSteerMode; + float m_flBurstSteerDistance; + float m_flBurstPredictTime; + Vector m_vecBurstPredictedVelocityDir; + float m_vecBurstPredictedSpeed; + float m_flValidStitchTime; + float m_flNextLedgeCheckTime; + float m_flTaskCompletionTime; + + bool m_bShouldActivateBaton; + float m_flBatonDebounceTime; // Minimum amount of time before turning the baton off + float m_flLastPhysicsFlinchTime; + float m_flLastDamageFlinchTime; + + // Sentences + float m_flNextPainSoundTime; + float m_flNextLostSoundTime; + int m_nIdleChatterType; + bool m_bPlayerIsNear; + + // Policing state + bool m_bPlayerTooClose; + bool m_bKeepFacingPlayer; + float m_flChasePlayerTime; + Vector m_vecPreChaseOrigin; + float m_flPreChaseYaw; + int m_nNumWarnings; + int m_iNumPlayerHits; + + // Outputs + COutputEvent m_OnStunnedPlayer; + COutputEvent m_OnCupCopped; + + AIHANDLE m_hManhack; + CHandle m_hBlockingProp; + + CAI_ActBusyBehavior m_ActBusyBehavior; + CAI_StandoffBehavior m_StandoffBehavior; + CAI_AssaultBehavior m_AssaultBehavior; + CAI_FuncTankBehavior m_FuncTankBehavior; + CAI_RappelBehavior m_RappelBehavior; + CAI_PolicingBehavior m_PolicingBehavior; + CAI_FollowBehavior m_FollowBehavior; + + CAI_Sentence< CNPC_MetroPolice > m_Sentences; + + int m_nRecentDamage; + float m_flRecentDamageTime; + + // The last hit direction, measured as a yaw relative to our orientation + float m_flLastHitYaw; + + static float gm_flTimeLastSpokePeek; + +public: + DEFINE_CUSTOM_AI; +}; + +#endif // NPC_METROPOLICE_H diff --git a/game/server/hl2/npc_playercompanion.h b/game/server/hl2/npc_playercompanion.h new file mode 100644 index 0000000..f1c3b1f --- /dev/null +++ b/game/server/hl2/npc_playercompanion.h @@ -0,0 +1,439 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base class for humanoid NPCs intended to fight along side player in close +// environments +// +//=============================================================================// + +#ifndef NPC_PLAYERCOMPANION_H +#define NPC_PLAYERCOMPANION_H + +#include "ai_playerally.h" + +#include "ai_behavior_follow.h" +#include "ai_behavior_standoff.h" +#include "ai_behavior_assault.h" +#include "ai_behavior_lead.h" +#include "ai_behavior_actbusy.h" +#include "ai_behavior_fear.h" + +#ifdef HL2_EPISODIC +#include "ai_behavior_operator.h" +#include "ai_behavior_passenger_companion.h" +#endif + +#if defined( _WIN32 ) +#pragma once +#endif + +enum AIReadiness_t +{ + AIRL_PANIC = -2, + AIRL_STEALTH = -1, + AIRL_RELAXED = 0, + AIRL_STIMULATED, + AIRL_AGITATED, +}; + +enum AIReadinessUse_t +{ + AIRU_NEVER, + AIRU_ALWAYS, + AIRU_ONLY_PLAYER_SQUADMATES, +}; + + +class CCompanionActivityRemap : public CActivityRemap +{ +public: + CCompanionActivityRemap( void ) : + m_fUsageBits( 0 ), + m_readiness( AIRL_RELAXED ), + m_bAiming( false ), + m_bWeaponRequired( false ), + m_bInVehicle( false ) {} + + // This bitfield maps which bits of data are being utilized by this data structure, since not all criteria + // in the parsed file are essential. You must add corresponding bits to the definitions below and maintain + // their state in the parsing of the file, as well as check the bitfield before accessing the data. This + // could be encapsulated into this class, but we'll probably move away from this model and closer to something + // more akin to the response rules -- jdw + + int m_fUsageBits; + + AIReadiness_t m_readiness; + bool m_bAiming; + bool m_bWeaponRequired; + bool m_bInVehicle; // For future expansion, this needs to speak more to the exact seat, role, and vehicle +}; + +// Usage bits for remap "extra" parsing - if these bits are set, the associated data has changed +#define bits_REMAP_READINESS (1<<0) +#define bits_REMAP_AIMING (1<<1) +#define bits_REMAP_WEAPON_REQUIRED (1<<2) +#define bits_REMAP_IN_VEHICLE (1<<3) + +// Readiness modes that only change due to mapmaker scripts +#define READINESS_MIN_VALUE -2 +#define READINESS_MODE_PANIC -2 +#define READINESS_MODE_STEALTH -1 + +// Readiness modes that change normally +#define READINESS_VALUE_RELAXED 0.1f +#define READINESS_VALUE_STIMULATED 0.95f +#define READINESS_VALUE_AGITATED 1.0f + +class CPhysicsProp; + +//----------------------------------------------------------------------------- +// +// CLASS: CNPC_PlayerCompanion +// +//----------------------------------------------------------------------------- + +class CNPC_PlayerCompanion : public CAI_PlayerAlly +{ + DECLARE_CLASS( CNPC_PlayerCompanion, CAI_PlayerAlly ); + +public: + //--------------------------------- + bool CreateBehaviors(); + void Precache(); + void Spawn(); + virtual void SelectModel() {}; + + virtual int Restore( IRestore &restore ); + virtual void DoCustomSpeechAI( void ); + + //--------------------------------- + int ObjectCaps(); + bool ShouldAlwaysThink(); + + Disposition_t IRelationType( CBaseEntity *pTarget ); + + bool IsSilentSquadMember() const; + + //--------------------------------- + // Behavior + //--------------------------------- + void GatherConditions(); + virtual void PredictPlayerPush(); + void BuildScheduleTestBits(); + + CSound *GetBestSound( int validTypes = ALL_SOUNDS ); + bool QueryHearSound( CSound *pSound ); + bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false ); + bool ShouldIgnoreSound( CSound * ); + + int SelectSchedule(); + + virtual int SelectScheduleDanger(); + virtual int SelectSchedulePriorityAction(); + virtual int SelectScheduleNonCombat() { return SCHED_NONE; } + virtual int SelectScheduleCombat(); + int SelectSchedulePlayerPush(); + + virtual bool CanReload( void ); + + virtual bool ShouldDeferToFollowBehavior(); + bool ShouldDeferToPassengerBehavior( void ); + + bool IsValidReasonableFacing( const Vector &vecSightDir, float sightDist ); + + int TranslateSchedule( int scheduleType ); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + + Activity TranslateActivityReadiness( Activity activity ); + Activity NPC_TranslateActivity( Activity eNewActivity ); + void HandleAnimEvent( animevent_t *pEvent ); + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + int GetSoundInterests(); + + void Touch( CBaseEntity *pOther ); + + virtual bool IgnorePlayerPushing( void ); + + void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + void Activate( void ); + + void PrepareReadinessRemap( void ); + + virtual bool IsNavigationUrgent( void ); + + //--------------------------------- + // Readiness + //--------------------------------- + +protected: + virtual bool IsReadinessCapable(); + bool IsReadinessLocked() { return gpGlobals->curtime < m_flReadinessLockedUntil; } + void AddReadiness( float flAdd, bool bOverrideLock = false ); + void SubtractReadiness( float flAdd, bool bOverrideLock = false ); + void SetReadinessValue( float flSet ); + void SetReadinessSensitivity( float flSensitivity ) { m_flReadinessSensitivity = flSensitivity; } + virtual void UpdateReadiness(); + virtual float GetReadinessDecay(); + bool IsInScriptedReadinessState( void ) { return (m_flReadiness < 0 ); } + + CUtlVector< CCompanionActivityRemap > m_activityMappings; + +public: + float GetReadinessValue() { return m_flReadiness; } + int GetReadinessLevel(); + void SetReadinessLevel( int iLevel, bool bOverrideLock, bool bSlam ); + void LockReadiness( float duration = -1.0f ); // Defaults to indefinitely locked + void UnlockReadiness( void ); + + virtual void ReadinessLevelChanged( int iPriorLevel ) { } + + void InputGiveWeapon( inputdata_t &inputdata ); + +#ifdef HL2_EPISODIC + //--------------------------------- + // Vehicle passenger + //--------------------------------- + void InputEnterVehicle( inputdata_t &inputdata ); + void InputEnterVehicleImmediately( inputdata_t &inputdata ); + void InputCancelEnterVehicle( inputdata_t &inputdata ); + void InputExitVehicle( inputdata_t &inputdata ); + bool CanEnterVehicle( void ); + bool CanExitVehicle( void ); + void EnterVehicle( CBaseEntity *pEntityVehicle, bool bImmediately ); + virtual bool ExitVehicle( void ); + + virtual void UpdateEfficiency( bool bInPVS ); + virtual bool IsInAVehicle( void ) const; + virtual IServerVehicle *GetVehicle( void ); + virtual CBaseEntity *GetVehicleEntity( void ); + + virtual bool CanRunAScriptedNPCInteraction( bool bForced = false ); + virtual bool IsAllowedToDodge( void ); + +#endif // HL2_EPISODIC + +public: + + virtual void OnPlayerKilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + + //--------------------------------- + //--------------------------------- + bool PickTacticalLookTarget( AILookTargetArgs_t *pArgs ); + + //--------------------------------- + // Aiming + //--------------------------------- + CBaseEntity *GetAimTarget() { return m_hAimTarget; } + void SetAimTarget( CBaseEntity *pTarget ); + void StopAiming( char *pszReason = NULL ); + bool FindNewAimTarget(); + void OnNewLookTarget(); + bool ShouldBeAiming(); + virtual bool IsAllowedToAim(); + bool HasAimLOS( CBaseEntity *pAimTarget ); + void AimGun(); + CBaseEntity *GetAlternateMoveShootTarget(); + + //--------------------------------- + // Combat + //--------------------------------- + virtual void LocateEnemySound() {}; + + bool IsValidEnemy( CBaseEntity *pEnemy ); + + bool IsSafeFromFloorTurret( const Vector &vecLocation, CBaseEntity *pTurret ); + + bool ShouldMoveAndShoot( void ); + void OnUpdateShotRegulator(); + + void DecalTrace( trace_t *pTrace, char const *decalName ); + bool FCanCheckAttacks(); + Vector GetActualShootPosition( const Vector &shootOrigin ); + WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); + bool ShouldLookForBetterWeapon(); + bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); + void Weapon_Equip( CBaseCombatWeapon *pWeapon ); + void PickupWeapon( CBaseCombatWeapon *pWeapon ); + + bool FindCoverPos( CBaseEntity *pEntity, Vector *pResult); + bool FindCoverPosInRadius( CBaseEntity *pEntity, const Vector &goalPos, float coverRadius, Vector *pResult ); + bool FindCoverPos( CSound *pSound, Vector *pResult ); + bool FindMortarCoverPos( CSound *pSound, Vector *pResult ); + bool IsCoverPosition( const Vector &vecThreat, const Vector &vecPosition ); + + bool IsEnemyTurret() { return ( GetEnemy() && IsTurret(GetEnemy()) ); } + + static bool IsMortar( CBaseEntity *pEntity ); + static bool IsSniper( CBaseEntity *pEntity ); + static bool IsTurret( CBaseEntity *pEntity ); + static bool IsGunship( CBaseEntity *pEntity ); + + //--------------------------------- + // Damage handling + //--------------------------------- + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); + + //--------------------------------- + // Hints + //--------------------------------- + bool FValidateHintType ( CAI_Hint *pHint ); + + //--------------------------------- + // Navigation + //--------------------------------- + bool IsValidMoveAwayDest( const Vector &vecDest ); + bool ValidateNavGoal(); + bool OverrideMove( float flInterval ); // Override to take total control of movement (return true if done so) + bool MovementCost( int moveType, const Vector &vecStart, const Vector &vecEnd, float *pCost ); + float GetIdealSpeed() const; + float GetIdealAccel() const; + bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); + + //--------------------------------- + // Inputs + //--------------------------------- + void InputOutsideTransition( inputdata_t &inputdata ); + void InputSetReadinessPanic( inputdata_t &inputdata ); + void InputSetReadinessStealth( inputdata_t &inputdata ); + void InputSetReadinessLow( inputdata_t &inputdata ); + void InputSetReadinessMedium( inputdata_t &inputdata ); + void InputSetReadinessHigh( inputdata_t &inputdata ); + void InputLockReadiness( inputdata_t &inputdata ); +#if HL2_EPISODIC + void InputClearAllOuputs( inputdata_t &inputdata ); ///< annihilate every output on this npc +#endif + + bool AllowReadinessValueChange( void ); + +protected: + //----------------------------------------------------- + // Conditions, Schedules, Tasks + //----------------------------------------------------- + enum + { + COND_PC_HURTBYFIRE = BaseClass::NEXT_CONDITION, + COND_PC_SAFE_FROM_MORTAR, + COND_PC_BECOMING_PASSENGER, + NEXT_CONDITION, + + SCHED_PC_COWER = BaseClass::NEXT_SCHEDULE, + SCHED_PC_MOVE_TOWARDS_COVER_FROM_BEST_SOUND, + SCHED_PC_TAKE_COVER_FROM_BEST_SOUND, + SCHED_PC_FLEE_FROM_BEST_SOUND, + SCHED_PC_FAIL_TAKE_COVER_TURRET, + SCHED_PC_FAKEOUT_MORTAR, + SCHED_PC_GET_OFF_COMPANION, + NEXT_SCHEDULE, + + TASK_PC_WAITOUT_MORTAR = BaseClass::NEXT_TASK, + TASK_PC_GET_PATH_OFF_COMPANION, + NEXT_TASK, + }; + +private: + void SetupCoverSearch( CBaseEntity *pEntity ); + void CleanupCoverSearch(); + + //----------------------------------------------------- + + bool m_bMovingAwayFromPlayer; + bool m_bWeightPathsInCover; + + enum eCoverType + { + CT_NORMAL, + CT_TURRET, + CT_MORTAR + }; + + static eCoverType gm_fCoverSearchType; + static bool gm_bFindingCoverFromAllEnemies; + + CSimpleSimTimer m_FakeOutMortarTimer; + + // Derived classes should not use the expresser directly + virtual CAI_Expresser *GetExpresser() { return BaseClass::GetExpresser(); } + +protected: + //----------------------------------------------------- + + virtual CAI_FollowBehavior &GetFollowBehavior( void ) { return m_FollowBehavior; } + + CAI_AssaultBehavior m_AssaultBehavior; + CAI_FollowBehavior m_FollowBehavior; + CAI_StandoffBehavior m_StandoffBehavior; + CAI_LeadBehavior m_LeadBehavior; + CAI_ActBusyBehavior m_ActBusyBehavior; +#ifdef HL2_EPISODIC + CAI_OperatorBehavior m_OperatorBehavior; + CAI_PassengerBehaviorCompanion m_PassengerBehavior; + CAI_FearBehavior m_FearBehavior; +#endif + //----------------------------------------------------- + + bool ShouldAlwaysTransition( void ); + + // Readiness is a value that's fed by various events in the NPC's AI. It is used + // to make decisions about what type of posture the NPC should be in (relaxed, agitated). + // It is not used to make decisions about what to do in the AI. + float m_flReadiness; + float m_flReadinessSensitivity; + bool m_bReadinessCapable; + float m_flReadinessLockedUntil; + float m_fLastBarrelExploded; + float m_fLastPlayerKill; + int m_iNumConsecutiveBarrelsExploded; // Companions keep track of the # of consecutive barrels exploded by the player and speaks a response as it increases + int m_iNumConsecutivePlayerKills; // Alyx keeps track of the # of consecutive kills by the player and speaks a response as it increases + + //----------------------------------------------------- + + float m_flBoostSpeed; + + //----------------------------------------------------- + + CSimpleSimTimer m_AnnounceAttackTimer; + + //----------------------------------------------------- + + EHANDLE m_hAimTarget; + +#ifdef HL2_EPISODIC + CHandle m_hFlare; +#endif // HL2_EPISODIC + + //----------------------------------------------------- + + static string_t gm_iszMortarClassname; + static string_t gm_iszFloorTurretClassname; + static string_t gm_iszGroundTurretClassname; + static string_t gm_iszShotgunClassname; + static string_t gm_iszRollerMineClassname; + + //----------------------------------------------------- + + void InputEnableAlwaysTransition( inputdata_t &inputdata ); + void InputDisableAlwaysTransition( inputdata_t &inputdata ); + bool m_bAlwaysTransition; + bool m_bDontPickupWeapons; + + void InputEnableWeaponPickup( inputdata_t &inputdata ); + void InputDisableWeaponPickup( inputdata_t &inputdata ); + + COutputEvent m_OnWeaponPickup; + + CStopwatch m_SpeechWatch_PlayerLooking; + + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; +}; + +// Used for quick override move searches against certain types of entities +void OverrideMoveCache_ForceRepopulateList( void ); +CBaseEntity *OverrideMoveCache_FindTargetsInRadius( CBaseEntity *pFirstEntity, const Vector &vecOrigin, float flRadius ); +void OverrideMoveCache_LevelInitPreEntity( void ); +void OverrideMoveCache_LevelShutdownPostEntity( void ); + +#endif // NPC_PLAYERCOMPANION_H diff --git a/game/server/hl2/npc_rollermine.h b/game/server/hl2/npc_rollermine.h new file mode 100644 index 0000000..774e3aa --- /dev/null +++ b/game/server/hl2/npc_rollermine.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_ROLLERMINE_H +#define NPC_ROLLERMINE_H +#ifdef _WIN32 +#pragma once +#endif + +//------------------------------------ +// Spawnflags +//------------------------------------ +#define SF_ROLLERMINE_FRIENDLY (1 << 16) +#define SF_ROLLERMINE_PROP_COLLISION (1 << 17) + +bool NPC_Rollermine_IsRollermine( CBaseEntity *pEntity ); +CBaseEntity *NPC_Rollermine_DropFromPoint( const Vector &originStart, CBaseEntity *pOwner, const char *pszTemplate ); + +#endif // NPC_ROLLERMINE_H diff --git a/game/server/hl2/npc_scanner.h b/game/server/hl2/npc_scanner.h new file mode 100644 index 0000000..f34eba3 --- /dev/null +++ b/game/server/hl2/npc_scanner.h @@ -0,0 +1,215 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef NPC_SCANNER_H +#define NPC_SCANNER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "npc_basescanner.h" + +//------------------------------------ +// Spawnflags +//------------------------------------ +#define SF_CSCANNER_NO_DYNAMIC_LIGHT (1 << 16) +#define SF_CSCANNER_STRIDER_SCOUT (1 << 17) + +class CBeam; +class CSprite; +class SmokeTrail; +class CSpotlightEnd; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CNPC_CScanner : public CNPC_BaseScanner +{ + DECLARE_CLASS( CNPC_CScanner, CNPC_BaseScanner ); + +public: + CNPC_CScanner(); + + int GetSoundInterests( void ) { return (SOUND_WORLD|SOUND_COMBAT|SOUND_PLAYER|SOUND_DANGER); } + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + bool FValidateHintType(CAI_Hint *pHint); + + virtual int TranslateSchedule( int scheduleType ); + Disposition_t IRelationType(CBaseEntity *pTarget); + + void NPCThink( void ); + + void GatherConditions( void ); + void PrescheduleThink( void ); + void Precache(void); + void RunTask( const Task_t *pTask ); + int SelectSchedule(void); + virtual char *GetScannerSoundPrefix( void ); + void Spawn(void); + void Activate(); + void StartTask( const Task_t *pTask ); + void UpdateOnRemove( void ); + void DeployMine(); + float GetMaxSpeed(); + virtual void Gib( void ); + + void HandleAnimEvent( animevent_t *pEvent ); + Activity NPC_TranslateActivity( Activity eNewActivity ); + + void InputDisableSpotlight( inputdata_t &inputdata ); + void InputSetFollowTarget( inputdata_t &inputdata ); + void InputClearFollowTarget( inputdata_t &inputdata ); + void InputInspectTargetPhoto( inputdata_t &inputdata ); + void InputInspectTargetSpotlight( inputdata_t &inputdata ); + void InputDeployMine( inputdata_t &inputdata ); + void InputEquipMine( inputdata_t &inputdata ); + void InputShouldInspect( inputdata_t &inputdata ); + + void InspectTarget( inputdata_t &inputdata, ScannerFlyMode_t eFlyMode ); + + void Event_Killed( const CTakeDamageInfo &info ); + + char *GetEngineSound( void ); + + virtual float MinGroundDist(void); + virtual void AdjustScannerVelocity( void ); + + virtual float GetHeadTurnRate( void ); + +public: + bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); + + // ------------------------------ + // Inspecting + // ------------------------------ + Vector m_vInspectPos; + float m_fInspectEndTime; + float m_fCheckCitizenTime; // Time to look for citizens to harass + float m_fCheckHintTime; // Time to look for hints to inspect + bool m_bShouldInspect; + bool m_bOnlyInspectPlayers; + bool m_bNeverInspectPlayers; + + void SetInspectTargetToEnt(CBaseEntity *pEntity, float fInspectDuration); + void SetInspectTargetToPos(const Vector &vInspectPos, float fInspectDuration); + void SetInspectTargetToHint(CAI_Hint *pHint, float fInspectDuration); + void ClearInspectTarget(void); + bool HaveInspectTarget(void); + Vector InspectTargetPosition(void); + bool IsValidInspectTarget(CBaseEntity *pEntity); + CBaseEntity* BestInspectTarget(void); + void RequestInspectSupport(void); + + bool IsStriderScout() { return HasSpawnFlags( SF_CSCANNER_STRIDER_SCOUT ); } + + // ------------------------ + // Photographing + // ------------------------ + float m_fNextPhotographTime; + CSprite* m_pEyeFlash; + + void TakePhoto( void ); + void BlindFlashTarget( CBaseEntity *pTarget ); + + // ------------------------------ + // Spotlight + // ------------------------------ + Vector m_vSpotlightTargetPos; + Vector m_vSpotlightCurrentPos; + CHandle m_hSpotlight; + CHandle m_hSpotlightTarget; + Vector m_vSpotlightDir; + Vector m_vSpotlightAngVelocity; + float m_flSpotlightCurLength; + float m_flSpotlightMaxLength; + float m_flSpotlightGoalWidth; + float m_fNextSpotlightTime; + int m_nHaloSprite; + + void SpotlightUpdate(void); + Vector SpotlightTargetPos(void); + Vector SpotlightCurrentPos(void); + void SpotlightCreate(void); + void SpotlightDestroy(void); + +protected: + void BecomeClawScanner( void ) { m_bIsClawScanner = true; } + +private: + bool MovingToInspectTarget( void ); + virtual float GetGoalDistance( void ); + + bool m_bIsClawScanner; // Formerly the shield scanner. + bool m_bIsOpen; // Only for claw scanner + + COutputEvent m_OnPhotographPlayer; + COutputEvent m_OnPhotographNPC; + + bool OverrideMove(float flInterval); + void MoveToTarget(float flInterval, const Vector &MoveTarget); + void MoveToSpotlight(float flInterval); + void MoveToPhotograph(float flInterval); + + // Attacks + bool m_bNoLight; + bool m_bPhotoTaken; + + void AttackPreFlash(void); + void AttackFlash(void); + void AttackFlashBlind(void); + + virtual void AttackDivebomb(void); + + DEFINE_CUSTOM_AI; + + // Custom interrupt conditions + enum + { + COND_CSCANNER_HAVE_INSPECT_TARGET = BaseClass::NEXT_CONDITION, + COND_CSCANNER_INSPECT_DONE, + COND_CSCANNER_CAN_PHOTOGRAPH, + COND_CSCANNER_SPOT_ON_TARGET, + + NEXT_CONDITION, + }; + + // Custom schedules + enum + { + SCHED_CSCANNER_SPOTLIGHT_HOVER = BaseClass::NEXT_SCHEDULE, + SCHED_CSCANNER_SPOTLIGHT_INSPECT_POS, + SCHED_CSCANNER_SPOTLIGHT_INSPECT_CIT, + SCHED_CSCANNER_PHOTOGRAPH_HOVER, + SCHED_CSCANNER_PHOTOGRAPH, + SCHED_CSCANNER_ATTACK_FLASH, + SCHED_CSCANNER_MOVE_TO_INSPECT, + SCHED_CSCANNER_PATROL, + + NEXT_SCHEDULE, + }; + + // Custom tasks + enum + { + TASK_CSCANNER_SET_FLY_PHOTO = BaseClass::NEXT_TASK, + TASK_CSCANNER_SET_FLY_SPOT, + TASK_CSCANNER_PHOTOGRAPH, + TASK_CSCANNER_ATTACK_PRE_FLASH, + TASK_CSCANNER_ATTACK_FLASH, + TASK_CSCANNER_SPOT_INSPECT_ON, + TASK_CSCANNER_SPOT_INSPECT_WAIT, + TASK_CSCANNER_SPOT_INSPECT_OFF, + TASK_CSCANNER_CLEAR_INSPECT_TARGET, + TASK_CSCANNER_GET_PATH_TO_INSPECT_TARGET, + + NEXT_TASK, + }; + + DECLARE_DATADESC(); +}; + +#endif // NPC_SCANNER_H diff --git a/game/server/hl2/npc_stalker.h b/game/server/hl2/npc_stalker.h new file mode 100644 index 0000000..dc2c08e --- /dev/null +++ b/game/server/hl2/npc_stalker.h @@ -0,0 +1,115 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPC_STALKER_H +#define NPC_STALKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "entityoutput.h" +#include "ai_behavior.h" +#include "ai_behavior_actbusy.h" + +class CBeam; +class CSprite; +class CScriptedTarget; + +typedef CAI_BehaviorHost CAI_BaseStalker; + +class CNPC_Stalker : public CAI_BaseStalker +{ + DECLARE_CLASS( CNPC_Stalker, CAI_BaseStalker ); + +public: + float m_flNextAttackSoundTime; + float m_flNextBreatheSoundTime; + float m_flNextScrambleSoundTime; + float m_flNextNPCThink; + + // ------------------------------ + // Laser Beam + // ------------------------------ + int m_eBeamPower; + Vector m_vLaserDir; + Vector m_vLaserTargetPos; + float m_fBeamEndTime; + float m_fBeamRechargeTime; + float m_fNextDamageTime; + float m_nextSmokeTime; + float m_bPlayingHitWall; + float m_bPlayingHitFlesh; + CBeam* m_pBeam; + CSprite* m_pLightGlow; + int m_iPlayerAggression; + float m_flNextScreamTime; + + void KillAttackBeam(void); + void DrawAttackBeam(void); + void CalcBeamPosition(void); + Vector LaserStartPosition(Vector vStalkerPos); + + Vector m_vLaserCurPos; // Last position successfully burned + bool InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + + // ------------------------------ + // Dormancy + // ------------------------------ + CAI_Schedule* WakeUp(void); + void GoDormant(void); + +public: + void Spawn( void ); + void Precache( void ); + bool CreateBehaviors(); + float MaxYawSpeed( void ); + Class_T Classify ( void ); + + void PrescheduleThink(); + + bool IsValidEnemy( CBaseEntity *pEnemy ); + + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + virtual int SelectSchedule ( void ); + virtual int TranslateSchedule( int scheduleType ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void OnScheduleChange(); + + void StalkerThink(void); + void NotifyDeadFriend( CBaseEntity *pFriend ); + + int MeleeAttack1Conditions ( float flDot, float flDist ); + int RangeAttack1Conditions ( float flDot, float flDist ); + void HandleAnimEvent( animevent_t *pEvent ); + + bool FValidateHintType(CAI_Hint *pHint); + Activity GetHintActivity( short sHintType, Activity HintsActivity ); + float GetHintDelay( short sHintType ); + + void IdleSound( void ); + void DeathSound( const CTakeDamageInfo &info ); + void PainSound( const CTakeDamageInfo &info ); + + void Event_Killed( const CTakeDamageInfo &info ); + void DoSmokeEffect( const Vector &position ); + + void AddZigZagToPath(void); + void StartAttackBeam(); + void UpdateAttackBeam(); + + CNPC_Stalker(void); + + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; + +private: + CAI_ActBusyBehavior m_ActBusyBehavior; +}; + +#endif // NPC_STALKER_H diff --git a/game/server/hl2/npc_strider.h b/game/server/hl2/npc_strider.h new file mode 100644 index 0000000..dd64578 --- /dev/null +++ b/game/server/hl2/npc_strider.h @@ -0,0 +1,645 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NPC_STRIDER_H +#define NPC_STRIDER_H + +#include "ai_blended_movement.h" +#include "ai_pathfinder.h" +#include "ai_navigator.h" +#include "ai_utils.h" +#include "smoke_trail.h" +#include "physics_bone_follower.h" +#include "physics_prop_ragdoll.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier0/memdbgon.h" + +class CNPC_Strider; +class CNPC_Bullseye; +class CStriderMinigun; + +//----------------------------------------------------------------------------- +// +// Support for moving Strider air nodes to the correct Z for the Strider +// regardless of Hammer placement +// +//----------------------------------------------------------------------------- + +class CAI_Network; +class CAI_Node; +struct StriderMinigunViewcone_t; +struct AI_EnemyInfo_t; + +void AdjustStriderNodePosition( CAI_Network *pNetwork, CAI_Node *pNode ); + +//----------------------------------------------------------------------------- +// +// Strider Minigun +// +//----------------------------------------------------------------------------- + +abstract_class IMinigunHost +{ +public: + virtual void ShootMinigun( const Vector *pTarget, float aimError, const Vector &vecSpread = vec3_origin ) = 0; + virtual void UpdateMinigunControls( float &yaw, float &pitch ) = 0; + virtual void GetViewCone( StriderMinigunViewcone_t &cone ) = 0; + virtual void NewTarget() = 0; + virtual void OnMinigunStartShooting( CBaseEntity *pTarget ) = 0; + virtual void OnMinigunStopShooting( CBaseEntity *pTarget ) = 0; + virtual CAI_BaseNPC *GetEntity() = 0; +}; + +abstract_class IStriderMinigunHost : public IMinigunHost +{ +public: + virtual float GetMinigunRateOfFire() = 0; + virtual float GetMinigunOnTargetTime() = 0; + virtual float GetMinigunShootDuration() = 0; + virtual float GetMinigunShootDowntime() = 0; + virtual float GetMinigunShootVariation() = 0; +}; + +//----------------------------------------------------------------------------- +// +// npc_strider +// +//----------------------------------------------------------------------------- + +const int NUM_STRIDER_IK_TARGETS = 6; + +//--------------------------------------------------------- + +class CNPC_Strider : public CAI_BlendingHost, + public IStriderMinigunHost +{ + DECLARE_CLASS( CNPC_Strider, CAI_BaseNPC ); + DECLARE_SERVERCLASS(); + +public: + CNPC_Strider(); + ~CNPC_Strider(); + + //--------------------------------- + + void Precache(); + void Spawn(); + bool CreateVPhysics(); + void InitBoneFollowers( void ); + void PostNPCInit(); + void Activate(); + void UpdateOnRemove(); + void InitBoneControllers(); + void OnRestore(); + + Class_T Classify(); + bool ShouldAttractAutoAim( CBaseEntity *pAimingEnt ); + + virtual float GetAutoAimRadius() { return 80.0f; } + + int DrawDebugTextOverlays(); + + void UpdateEfficiency( bool bInPVS ) { SetEfficiency( ( GetSleepState() != AISS_AWAKE ) ? AIE_DORMANT : AIE_NORMAL ); SetMoveEfficiency( AIME_NORMAL ); } + virtual bool ShouldProbeCollideAgainstEntity( CBaseEntity *pEntity ); + + //--------------------------------- + + virtual Vector GetNodeViewOffset() { return BaseClass::GetDefaultEyeOffset(); } + + Vector EyePosition(); + const Vector & GetViewOffset(); + Vector EyePositionCrouched() { return GetAbsOrigin() - Vector( 0, 0, 330 ); } + + //--------------------------------- + // CBaseAnimating + void CalculateIKLocks( float currentTime ); + float GetIdealAccel() const { return GetIdealSpeed(); } + + //--------------------------------- + // Behavior + //--------------------------------- + void NPCThink(); + void PrescheduleThink(); + void GatherConditions(); + void CheckFlinches() {} // Strider handles on own + void GatherHeightConditions( const Vector &vTestPos, CBaseEntity *pEntity ); + void OnStateChange( NPC_STATE oldState, NPC_STATE newState ); + void BuildScheduleTestBits(); + int SelectSchedule(); + int TranslateSchedule( int scheduleType ); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ); + void HandleAnimEvent( animevent_t *pEvent ); + + Disposition_t IRelationType( CBaseEntity *pTarget ); + void AddEntityRelationship( CBaseEntity *pEntity, Disposition_t nDisposition, int nPriority ); + + bool ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity ); + bool ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity ); + + //--------------------------------- + // Inputs + //--------------------------------- + void InputSetMinigunTime( inputdata_t &inputdata ); + void InputSetMinigunTarget( inputdata_t &inputdata ); + void InputDisableMinigun( inputdata_t &inputdata ); + void InputEnableMinigun( inputdata_t &inputdata ); + void InputSetCannonTarget( inputdata_t &inputdata ); + void InputFlickRagdoll( inputdata_t &inputdata ); + void InputDisableCollisionWith( inputdata_t &inputdata ); + void InputEnableCollisionWith( inputdata_t &inputdata ); + void InputCrouch( inputdata_t &inputdata ); + void InputCrouchInstantly( inputdata_t &inputdata ); + void InputStand( inputdata_t &inputdata ); + void InputSetHeight( inputdata_t &inputdata ); + void InputSetTargetPath( inputdata_t &inputdata ); + void InputClearTargetPath( inputdata_t &inputdata ); + void InputDisableCrouchWalk( inputdata_t &inputdata ); + void InputEnableCrouchWalk( inputdata_t &inputdata ); + void InputEnableAggressiveBehavior( inputdata_t &inputdata ); + void InputDisableAggressiveBehavior( inputdata_t &inputdata ); + void InputStopShootingMinigunForSeconds( inputdata_t &inputdata ); + void InputDisableCrouch( inputdata_t &inputdata ); + void InputDisableMoveToLOS( inputdata_t &inputdata ); + void InputExplode( inputdata_t &inputdata ); + void InputScaleGroundSpeed( inputdata_t &inputdata ); + + //--------------------------------- + // Combat + //--------------------------------- + bool HasPass() { return m_PlayerFreePass.HasPass(); } + + bool FVisible( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); + Vector BodyTarget( const Vector &posSrc, bool bNoisy ); + + bool IsValidEnemy( CBaseEntity *pTarget ); + bool UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position, CBaseEntity *pInformer = NULL ); + float StriderEnemyDistance( CBaseEntity *pEnemy ); + + bool FCanCheckAttacks(); + int RangeAttack2Conditions( float flDot, float flDist ); + int MeleeAttack1Conditions( float flDot, float flDist ); + int MeleeAttack2Conditions( float flDot, float flDist ); + bool WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions); + bool CurrentWeaponLOSCondition(const Vector &targetPos, bool bSetConditions); + bool IsValidShootPosition ( const Vector &vecCoverLocation, CAI_Node *pNode, CAI_Hint const *pHint ); + bool TestShootPosition(const Vector &vecShootPos, const Vector &targetPos ); + + Vector Weapon_ShootPosition(); + + void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + void DoImpactEffect( trace_t &tr, int nDamageType ); + void DoMuzzleFlash( void ); + + bool CanShootThrough( const trace_t &tr, const Vector &vecTarget ); + + void CreateFocus(); + CNPC_Bullseye * GetFocus(); + + bool GetWeaponLosZ( const Vector &vOrigin, float minZ, float maxZ, float increment, CBaseEntity *pTarget, float *pResult ); + + //--------------------------------- + // Sounds & speech + //--------------------------------- + void AlertSound(); + void PainSound( const CTakeDamageInfo &info ); + void DeathSound( const CTakeDamageInfo &info ); + void HuntSound(); + + //--------------------------------- + // Damage handling + //--------------------------------- + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + int TakeDamageFromCombineBall( const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + void RagdollDeathEffect( CRagdollProp *pRagdoll, float flDuration ); + bool BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector ); + void StartSmoking(); + void StopSmoking( float flDelay = 0.1 ); + bool IsSmoking() { return m_hSmoke != NULL; } + void Explode(); + + //--------------------------------- + // Posture + //--------------------------------- + float GetMaxHeightModel() const { return 500.0; } + float GetMaxHeight() const { return 490.0; } + float GetMinHeight() const { return 200.0; } + float GetHeightRange() const { return GetMaxHeight() - GetMinHeight(); } + void SetHeight( float h ); + float GetHeight() { return GetPoseParameter( gm_BodyHeightPoseParam ); } + void SetIdealHeight( float h ); + void SetAbsIdealHeight( float z ); + float GetIdealHeight() { return m_idealHeight; } + Vector GetAdjustedOrigin() { Vector result = GetAbsOrigin(); result.z -= GetMaxHeightModel() - GetHeight(); return result; } + + bool IsInCrouchedPosture() { return GetIdealHeight() < GetMaxHeight() * .5; } + bool IsInStandingPosture() { return !IsInCrouchedPosture(); } + bool IsStriderCrouching(); + bool IsStriderStanding(); + void SetupGlobalModelData(); + + virtual bool CanBecomeServerRagdoll( void ) { return false; } + + //--------------------------------- + // Navigation & Movement + //--------------------------------- + class CNavigator : public CAI_ComponentWithOuter + { + typedef CAI_ComponentWithOuter BaseClass; + public: + CNavigator( CNPC_Strider *pOuter ) + : BaseClass( pOuter ) + { + } + + void MoveCalcBaseGoal( AILocalMoveGoal_t *pMoveGoal ); + bool MoveUpdateWaypoint( AIMoveResult_t *pResult ); + bool DoFindPathToPos(); + bool ShouldOptimizeInitialPathSegment( AI_Waypoint_t *pFirstWaypoint ); + bool GetStoppingPath( CAI_WaypointList *pClippedWaypoints ); + }; + + class CPathfinder : public CAI_Pathfinder + { + typedef CAI_Pathfinder BaseClass; + public: + CPathfinder( CNPC_Strider *pOuter ) : BaseClass( pOuter ) {} + virtual bool CanUseLocalNavigation() { return false; } + }; + + friend class CNavigator; + friend void AdjustStriderNodePosition( CAI_Network *pNetwork, CAI_Node *pNode ); + + bool OverrideMove( float flInterval ); + void MaintainTurnActivity( void ); + bool IsUnusableNode(int iNodeID, CAI_Hint *pHint); // Override for special NPC behavior + void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition ); + bool HasPendingTargetPath(); + void SetTargetPath(); + float GetDefaultNavGoalTolerance(); + void OnMovementComplete(); + float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ); + + float MaxYawSpeed(); + + CAI_Navigator * CreateNavigator() { return new CNavigator( this ); } + CAI_Pathfinder *CreatePathfinder() { return new CPathfinder( this ); } + + //--------------------------------- + // Minigun + //--------------------------------- + void ShootMinigun( const Vector *pTarget, float aimError, const Vector &vecSpread = vec3_origin ); + void UpdateMinigunControls( float &yaw, float &pitch ); + void GetViewCone( StriderMinigunViewcone_t &cone ); + void NewTarget() { m_flTargetAcquiredTime = gpGlobals->curtime; } + void OnMinigunStartShooting( CBaseEntity *pTarget ) {}; + void OnMinigunStopShooting( CBaseEntity *pTarget ); + float GetMinigunRateOfFire(); + float GetMinigunOnTargetTime(); + float GetMinigunShootDuration(); + float GetMinigunShootDowntime(); + float GetMinigunShootVariation(); + + CAI_BaseNPC * GetEntity() { return this; } + + bool IsUsingAggressiveBehavior() { return m_bUseAggressiveBehavior; } + + //--------------------------------- + // Cannon + //--------------------------------- + Vector CannonPosition(); + CBaseEntity * GetCannonTarget(); + bool HasCannonTarget() const; + bool IsCannonTarget( CBaseEntity *pTarget ) const; + bool AimCannonAt( CBaseEntity *pEntity, float flInterval ); + void FireCannon(); + void CannonHitThink(); + + //--------------------------------- + // Collision handling + //--------------------------------- + + void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent ); + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + + // Conservative collision volumes + static float gm_strideLength; + +#ifdef HL2_EPISODIC + void StriderBusterAttached( CBaseEntity *pAttached ); + void StriderBusterDetached( CBaseEntity *pAttached ); +#endif // HL2_EPISODIC + +public: + + //--------------------------------- + // Misc + //--------------------------------- + bool CarriedByDropship(); + void CarriedThink(); + + //--------------------------------- + // Foot handling + //--------------------------------- + Vector LeftFootHit( float eventtime ); + Vector RightFootHit( float eventtime ); + Vector BackFootHit( float eventtime ); + void StompHit( int followerBoneIndex ); + + void FootFX( const Vector &origin ); + Vector CalculateStompHitPosition( CBaseEntity *pEnemy ); + bool IsLegBoneFollower( CBoneFollower *pFollower ); + CBoneFollower *GetBoneFollowerByIndex( int nIndex ); + int GetBoneFollowerIndex( CBoneFollower *pFollower ); + +protected: + // Because the strider is a leaf class, we can use + // static variables to store this information, and save some memory. + // Should the strider end up having inheritors, their activate may + // stomp these numbers, in which case you should make these ordinary members + // again. + // + // The strider also caches some pose parameters in SetupGlobalModelData(). + static int m_poseMiniGunYaw, m_poseMiniGunPitch; + static bool m_sbStaticPoseParamsLoaded; + virtual void PopulatePoseParameters( void ); + +private: + + bool ShouldExplodeFromDamage( const CTakeDamageInfo &info ); + bool m_bExploding; + + //----------------------------------------------------- + // Conditions, Schedules, Tasks + //----------------------------------------------------- + enum + { + SCHED_STRIDER_RANGE_ATTACK1 = BaseClass::NEXT_SCHEDULE, + SCHED_STRIDER_RANGE_ATTACK2, // Immolator + SCHED_STRIDER_CROUCH, + SCHED_STRIDER_STAND, + SCHED_STRIDER_DODGE, + SCHED_STRIDER_STOMPL, + SCHED_STRIDER_STOMPR, + SCHED_STRIDER_FLICKL, + SCHED_STRIDER_FLICKR, + SCHED_STRIDER_HUNT, + SCHED_STRIDER_DIE, + SCHED_STRIDER_ATTACK_CANNON_TARGET, + SCHED_STRIDER_CHASE_ENEMY, + SCHED_STRIDER_COMBAT_FACE, + SCHED_STRIDER_AGGRESSIVE_COMBAT_STAND, + SCHED_STRIDER_ESTABLISH_LINE_OF_FIRE_CANNON, + SCHED_STRIDER_FALL_TO_GROUND, + + TASK_STRIDER_AIM = BaseClass::NEXT_TASK, + TASK_STRIDER_DODGE, + TASK_STRIDER_STOMP, + TASK_STRIDER_BREAKDOWN, + TASK_STRIDER_START_MOVING, + TASK_STRIDER_REFRESH_HUNT_PATH, + TASK_STRIDER_GET_PATH_TO_CANNON_TARGET, + TASK_STRIDER_FACE_CANNON_TARGET, + TASK_STRIDER_SET_HEIGHT, + TASK_STRIDER_GET_PATH_TO_CANNON_LOS, + TASK_STRIDER_SET_CANNON_HEIGHT, + TASK_STRIDER_FIRE_CANNON, + TASK_STRIDER_FALL_TO_GROUND, + + COND_STRIDER_DO_FLICK = BaseClass::NEXT_CONDITION, + COND_TRACK_PATH_GO, + COND_STRIDER_SHOULD_CROUCH, + COND_STRIDER_SHOULD_STAND, + COND_STRIDER_MINIGUN_SHOOTING, + COND_STRIDER_MINIGUN_NOT_SHOOTING, + COND_STRIDER_HAS_CANNON_TARGET, + COND_STRIDER_ENEMY_UPDATED, + COND_STRIDER_HAS_LOS_Z, + }; + + string_t m_iszStriderBusterName; + string_t m_iszMagnadeClassname; + string_t m_iszHunterClassname; + + CStriderMinigun *m_pMinigun; + int m_miniGunAmmo; + int m_miniGunDirectAmmo; + float m_nextShootTime; + float m_nextStompTime; + float m_ragdollTime; + float m_miniGunShootDuration; + float m_aimYaw; + float m_aimPitch; + Vector m_blastHit; + Vector m_blastNormal; + CNetworkVector( m_vecHitPos ); + CNetworkArray( Vector, m_vecIKTarget, NUM_STRIDER_IK_TARGETS ); + + CRandSimTimer m_PostureAnimationTimer; + + EHANDLE m_hRagdoll; + + EHANDLE m_hCannonTarget; + CSimpleSimTimer m_AttemptCannonLOSTimer; + + float m_flSpeedScale; + float m_flTargetSpeedScale; + + CSimpleSimTimer m_LowZCorrectionTimer; + + // Contained Bone Follower manager + CBoneFollowerManager m_BoneFollowerManager; + + int m_BodyTargetBone; + + bool m_bDisableBoneFollowers; + + int m_iVisibleEnemies; + float m_flTargetAcquiredTime; + bool m_bCrouchLocked; // Designer made the strider crouch. Don't let the AI stand him up. + bool m_bNoCrouchWalk; + bool m_bDontCrouch; + bool m_bNoMoveToLOS; + bool m_bFastCrouch; + bool m_bMinigunEnabled; // If false, minigun disabled by level designer until further notice. + + float m_idealHeight; + float m_HeightVelocity; + + // FIXME: move to a base class to handle turning for blended movement derived characters + float m_prevYaw; + float m_doTurn; + float m_doLeft; + float m_doRight; + float m_flNextTurnAct; + + string_t m_strTrackName; + + EHANDLE m_hFocus; + + float m_flTimeLastAlertSound; + float m_flTimeNextHuntSound; + bool m_bUseAggressiveBehavior; + float m_flTimePlayerMissileDetected; + EHANDLE m_hPlayersMissile; + bool m_bMinigunUseDirectFire; + + CHandle m_hSmoke; + + CSimpleSimTimer m_EnemyUpdatedTimer; + + CAI_FreePass m_PlayerFreePass; + +#ifdef HL2_EPISODIC + CUtlVector< EHANDLE > m_hAttachedBusters; // List of busters attached to us +#endif // HL2_EPISODIC + + static float gm_zCannonDist; + static float gm_zMinigunDist; + static Vector gm_vLocalRelativePositionCannon; + static Vector gm_vLocalRelativePositionMinigun; + + static int gm_YawControl; + static int gm_PitchControl; + static int gm_CannonAttachment; + static int gm_BodyHeightPoseParam; + + DEFINE_CUSTOM_AI; + + DECLARE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +//--------------------------------------------------------- + +enum StriderMinigunPeg_t +{ + MINIGUN_PEGGED_DONT_CARE = 0, + MINIGUN_PEGGED_UP, + MINIGUN_PEGGED_DOWN, + MINIGUN_PEGGED_LEFT, + MINIGUN_PEGGED_RIGHT, +}; + +//--------------------------------------------------------- + +struct StriderMinigunViewcone_t +{ + Vector origin; + Vector axis; + float cosAngle; + float length; +}; + +//--------------------------------------------------------- + +struct StriderMinigunAnimController_t +{ + float current; + float target; + float rate; + + void Update( float dt, bool approach = true ) + { + if( approach ) + { + current = Approach( target, current, rate * dt ); + } + else + { + current = target; + } + } + + void Random( float minTarget, float maxTarget, float minRate, float maxRate ) + { + target = random->RandomFloat( minTarget, maxTarget ); + rate = random->RandomFloat( minRate, maxRate ); + } +}; + +//--------------------------------------------------------- + +class CStriderMinigun +{ +public: + DECLARE_DATADESC(); + + void Init(); + void SetTarget( IStriderMinigunHost *pHost, CBaseEntity *pTarget, bool bOverrideEnemy = false ); + CBaseEntity *GetTarget() { return m_hTarget.Get(); } + void Think( IStriderMinigunHost *pHost, float dt ); + void SetState( int newState ); + bool ShouldFindTarget( IMinigunHost *pHost ); + void AimAtPoint( IStriderMinigunHost *pHost, const Vector &vecPoint, bool bSnap = false ); + void AimAtTarget( IStriderMinigunHost *pHost, CBaseEntity *pTarget, bool bSnap = false ); + void ShootAtTarget( IStriderMinigunHost *pHost, CBaseEntity *pTarget, float shootTime ); + void StartShooting( IStriderMinigunHost *pHost, CBaseEntity *pTarget, float duration ); + void ExtendShooting( float timeExtend ); + void SetShootDuration( float duration ); + void StopShootingForSeconds( IStriderMinigunHost *pHost, CBaseEntity *pTarget, float duration ); + bool IsPegged( int dir = MINIGUN_PEGGED_DONT_CARE ); + bool CanStartShooting( IStriderMinigunHost *pHost, CBaseEntity *pTargetEnt ); + float GetBurstTimeRemaining() { return m_burstTime - gpGlobals->curtime; } + + void RecordShotOnTarget() { m_iOnTargetShots++; } + void ClearOnTarget() { m_iOnTargetShots = 0; } + bool IsOnTarget( int numShots = 0 ) { return ( numShots == 0 ) ? (m_iOnTargetShots > 0) : (m_iOnTargetShots >= numShots); } + + void Enable( IMinigunHost *pHost, bool enable ); + float GetAimError(); + + enum minigunstates_t + { + MINIGUN_OFF = 0, + MINIGUN_SHOOTING = 1, + }; + + int GetState() { return m_minigunState; } + bool IsShooting() { return GetState() == MINIGUN_SHOOTING; } + +private: + bool m_enable; + int m_minigunState; + float m_nextBulletTime; // Minigun is shooting, when can I fire my next bullet? + float m_burstTime; // If firing, how long till done? If not, how long till I can? + float m_nextTwitchTime; + int m_randomState; + EHANDLE m_hTarget; + StriderMinigunAnimController_t m_yaw; + StriderMinigunAnimController_t m_pitch; + bool m_bWarnedAI; + float m_shootDuration; + Vector m_vecAnchor; // A burst starts here and goes to the target's orgin. + bool m_bOverrideEnemy; // The minigun wants something other than the Strider's enemy as a target right now. + Vector m_vecLastTargetPos; // Last place minigun saw the target. + int m_iOnTargetShots; +}; + + +class CSparkTrail : public CPointEntity +{ + DECLARE_CLASS( CSparkTrail, CPointEntity ); + void Spawn( void ); + void SparkThink( void ); + + virtual void Precache(); + + DECLARE_DATADESC(); +}; + +#include "tier0/memdbgoff.h" + +#endif // NPC_STRIDER_H + +//============================================================================= diff --git a/game/server/hl2/npc_turret_floor.h b/game/server/hl2/npc_turret_floor.h new file mode 100644 index 0000000..53c54b0 --- /dev/null +++ b/game/server/hl2/npc_turret_floor.h @@ -0,0 +1,307 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef NPC_TURRET_FLOOR_H +#define NPC_TURRET_FLOOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "player_pickup.h" +#include "particle_system.h" + +//Turret states +enum turretState_e +{ + TURRET_SEARCHING, + TURRET_AUTO_SEARCHING, + TURRET_ACTIVE, + TURRET_SUPPRESSING, + TURRET_DEPLOYING, + TURRET_RETIRING, + TURRET_TIPPED, + TURRET_SELF_DESTRUCTING, + + TURRET_STATE_TOTAL +}; + +//Eye states +enum eyeState_t +{ + TURRET_EYE_SEE_TARGET, //Sees the target, bright and big + TURRET_EYE_SEEKING_TARGET, //Looking for a target, blinking (bright) + TURRET_EYE_DORMANT, //Not active + TURRET_EYE_DEAD, //Completely invisible + TURRET_EYE_DISABLED, //Turned off, must be reactivated before it'll deploy again (completely invisible) + TURRET_EYE_ALARM, // On side, but warning player to pick it back up +}; + +//Spawnflags +// BUG: These all stomp Base NPC spawnflags. Any Base NPC code called by this +// this class may have undesired side effects due to these being set. +#define SF_FLOOR_TURRET_AUTOACTIVATE 0x00000020 +#define SF_FLOOR_TURRET_STARTINACTIVE 0x00000040 +#define SF_FLOOR_TURRET_FASTRETIRE 0x00000080 +#define SF_FLOOR_TURRET_OUT_OF_AMMO 0x00000100 +#define SF_FLOOR_TURRET_CITIZEN 0x00000200 // Citizen modified turret + +class CTurretTipController; +class CBeam; +class CSprite; + +//----------------------------------------------------------------------------- +// Purpose: Floor turret +//----------------------------------------------------------------------------- +class CNPC_FloorTurret : public CNPCBaseInteractive, public CDefaultPlayerPickupVPhysics +{ + DECLARE_CLASS( CNPC_FloorTurret, CNPCBaseInteractive ); +public: + + CNPC_FloorTurret( void ); + + virtual void Precache( void ); + virtual void Spawn( void ); + virtual void Activate( void ); + virtual bool CreateVPhysics( void ); + virtual void UpdateOnRemove( void ); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual void PlayerPenetratingVPhysics( void ); + virtual int VPhysicsTakeDamage( const CTakeDamageInfo &info ); + virtual bool CanBecomeServerRagdoll( void ) { return false; } + +#ifdef HL2_EPISODIC + // We don't want to be NPCSOLID because we'll collide with NPC clips + virtual unsigned int PhysicsSolidMaskForEntity( void ) const { return MASK_SOLID; } +#endif // HL2_EPISODIC + + // Player pickup + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ); + virtual QAngle PreferredCarryAngles( void ); + virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + + const char *GetTracerType( void ) { return "AR2Tracer"; } + + bool ShouldSavePhysics() { return true; } + + bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sourceEnt ); + + // Think functions + virtual void Retire( void ); + virtual void Deploy( void ); + virtual void ActiveThink( void ); + virtual void SearchThink( void ); + virtual void AutoSearchThink( void ); + virtual void TippedThink( void ); + virtual void InactiveThink( void ); + virtual void SuppressThink( void ); + virtual void DisabledThink( void ); + virtual void SelfDestructThink( void ); + virtual void BreakThink( void ); + virtual void HackFindEnemy( void ); + + virtual float GetAttackDamageScale( CBaseEntity *pVictim ); + virtual Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ); + + // Do we have a physics attacker? + CBasePlayer *HasPhysicsAttacker( float dt ); + bool IsHeldByPhyscannon( ) { return VPhysicsGetObject() && (VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD); } + + // Use functions + void ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + int ObjectCaps() + { + return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; + } + + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) + { + CBasePlayer *pPlayer = ToBasePlayer( pActivator ); + if ( pPlayer ) + { + pPlayer->PickupObject( this, false ); + } + } + + // Inputs + void InputToggle( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputDepleteAmmo( inputdata_t &inputdata ); + void InputRestoreAmmo( inputdata_t &inputdata ); + void InputSelfDestruct( inputdata_t &inputdata ); + + virtual bool IsValidEnemy( CBaseEntity *pEnemy ); + bool CanBeAnEnemyOf( CBaseEntity *pEnemy ); + bool IsBeingCarriedByPlayer( void ) { return m_bCarriedByPlayer; } + bool WasJustDroppedByPlayer( void ); + + int BloodColor( void ) { return DONT_BLEED; } + float MaxYawSpeed( void ); + + virtual Class_T Classify( void ); + + Vector EyePosition( void ) + { + UpdateMuzzleMatrix(); + + Vector vecOrigin; + MatrixGetColumn( m_muzzleToWorld, 3, vecOrigin ); + + Vector vecForward; + MatrixGetColumn( m_muzzleToWorld, 0, vecForward ); + + // Note: We back up into the model to avoid an edge case where the eyes clip out of the world and + // cause problems with the PVS calculations -- jdw + + vecOrigin -= vecForward * 8.0f; + + return vecOrigin; + } + + Vector EyeOffset( Activity nActivity ) { return Vector( 0, 0, 58 ); } + + // Restore the turret to working operation after falling over + void ReturnToLife( void ); + + int DrawDebugTextOverlays( void ); + + // INPCInteractive Functions + virtual bool CanInteractWith( CAI_BaseNPC *pUser ) { return false; } // Disabled for now (sjb) + virtual bool HasBeenInteractedWith() { return m_bHackedByAlyx; } + virtual void NotifyInteraction( CAI_BaseNPC *pUser ) + { + // For now, turn green so we can tell who is hacked. + SetRenderColor( 0, 255, 0 ); + m_bHackedByAlyx = true; + } + + static float fMaxTipControllerVelocity; + static float fMaxTipControllerAngularVelocity; + +protected: + + virtual bool PreThink( turretState_e state ); + virtual void Shoot( const Vector &vecSrc, const Vector &vecDirToEnemy, bool bStrict = false ); + virtual void SetEyeState( eyeState_t state ); + void Ping( void ); + void Toggle( void ); + void Enable( void ); + void Disable( void ); + void SpinUp( void ); + void SpinDown( void ); + + virtual bool OnSide( void ); + + bool IsCitizenTurret( void ) { return HasSpawnFlags( SF_FLOOR_TURRET_CITIZEN ); } + bool UpdateFacing( void ); + void DryFire( void ); + void UpdateMuzzleMatrix(); + +protected: + matrix3x4_t m_muzzleToWorld; + int m_muzzleToWorldTick; + int m_iAmmoType; + + bool m_bAutoStart; + bool m_bActive; //Denotes the turret is deployed and looking for targets + bool m_bBlinkState; + bool m_bEnabled; //Denotes whether the turret is able to deploy or not + bool m_bNoAlarmSounds; + bool m_bSelfDestructing; // Going to blow up + + float m_flDestructStartTime; + float m_flShotTime; + float m_flLastSight; + float m_flThrashTime; + float m_flPingTime; + float m_flNextActivateSoundTime; + bool m_bCarriedByPlayer; + bool m_bUseCarryAngles; + float m_flPlayerDropTime; + int m_iKeySkin; + + CHandle m_hLastNPCToKickMe; // Stores the last NPC who tried to knock me over + float m_flKnockOverFailedTime; // Time at which we should tell the NPC that he failed to knock me over + + QAngle m_vecGoalAngles; + + int m_iEyeAttachment; + int m_iMuzzleAttachment; + eyeState_t m_iEyeState; + CHandle m_hEyeGlow; + CHandle m_hLaser; + CHandle m_pMotionController; + + CHandle m_hFizzleEffect; + Vector m_vecEnemyLKP; + + // physics influence + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + + static const char *m_pShotSounds[]; + + COutputEvent m_OnDeploy; + COutputEvent m_OnRetire; + COutputEvent m_OnTipped; + COutputEvent m_OnPhysGunPickup; + COutputEvent m_OnPhysGunDrop; + + bool m_bHackedByAlyx; + HSOUNDSCRIPTHANDLE m_ShotSounds; + + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; +}; + +// +// Tip controller +// + +class CTurretTipController : public CPointEntity, public IMotionEvent +{ + DECLARE_CLASS( CTurretTipController, CPointEntity ); + DECLARE_DATADESC(); + +public: + + ~CTurretTipController( void ); + void Spawn( void ); + void Activate( void ); + void Enable( bool state = true ); + void Suspend( float time ); + float SuspendedTill( void ); + + bool Enabled( void ); + + static CTurretTipController *CreateTipController( CNPC_FloorTurret *pOwner ) + { + if ( pOwner == NULL ) + return NULL; + + CTurretTipController *pController = (CTurretTipController *) Create( "floorturret_tipcontroller", pOwner->GetAbsOrigin(), pOwner->GetAbsAngles() ); + + if ( pController != NULL ) + { + pController->m_pParentTurret = pOwner; + } + + return pController; + } + + // IMotionEvent + virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ); + +private: + bool m_bEnabled; + float m_flSuspendTime; + Vector m_worldGoalAxis; + Vector m_localTestAxis; + IPhysicsMotionController *m_pController; + float m_angularLimit; + CNPC_FloorTurret *m_pParentTurret; +}; + +#endif //#ifndef NPC_TURRET_FLOOR_H diff --git a/game/server/hl2/npc_turret_ground.h b/game/server/hl2/npc_turret_ground.h new file mode 100644 index 0000000..97b1f4a --- /dev/null +++ b/game/server/hl2/npc_turret_ground.h @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef NPC_TURRET_GROUND_H +#define NPC_TURRET_GROUND_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "smoke_trail.h" + +//========================================================= +//========================================================= +class CNPC_GroundTurret : public CAI_BaseNPC +{ +public: + DECLARE_CLASS( CNPC_GroundTurret, CAI_BaseNPC ); + DECLARE_DATADESC(); + + void Precache( void ); + virtual void Spawn( void ); + bool CreateVPhysics( void ); + void PrescheduleThink(); + Class_T Classify( void ); + + void PostNPCInit(); + + // Damage & Death + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + void DeathEffects(); + bool CanBecomeRagdoll( void ) { return false; } + void DeathSound( const CTakeDamageInfo &info ); + + // Combat + void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ) + { + return VECTOR_CONE_5DEGREES; + } + + + // Sensing + void GatherConditions(); + Vector EyePosition(); + bool FVisible( CBaseEntity *pEntity, int traceMask, CBaseEntity **ppBlocker ); + bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false ); + + + bool IsOpeningOrClosing() { return (GetAbsVelocity().z != 0.0f); } + bool IsEnabled(); + bool IsOpen(); + + // Tasks & Schedules + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + virtual int SelectSchedule( void ); + virtual int TranslateSchedule( int scheduleType ); + + // Activities & Animation + Activity NPC_TranslateActivity( Activity eNewActivity ); + virtual void Shoot(); + virtual void Scan(); + void ProjectBeam( const Vector &vecStart, const Vector &vecDir, int width, int brightness, float duration ); + + // Local + void SetActive( bool bActive ) {} + + // Inputs + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + // Outputs + COutputEvent m_OnAreaClear; + + DEFINE_CUSTOM_AI; + +protected: + //----------------------------------------------------- + // Conditions, Schedules, Tasks + //----------------------------------------------------- + enum + { + SCHED_GROUND_TURRET_IDLE = BaseClass::NEXT_SCHEDULE, + SCHED_GROUND_TURRET_ATTACK, + + TASK_GROUNDTURRET_SCAN = BaseClass::NEXT_TASK, + }; + + int m_iAmmoType; + SmokeTrail *m_pSmoke; + + bool m_bEnabled; + + float m_flTimeNextShoot; + float m_flTimeLastSawEnemy; + Vector m_vecSpread; + bool m_bHasExploded; + int m_iDeathSparks; + float m_flSensingDist; + bool m_bSeeEnemy; + float m_flTimeNextPing; + + Vector m_vecClosedPos; + + Vector m_vecLightOffset; + + HSOUNDSCRIPTHANDLE m_ShotSounds; +}; + +#endif //#ifndef NPC_TURRET_GROUND_H diff --git a/game/server/hl2/npc_vortigaunt_episodic.h b/game/server/hl2/npc_vortigaunt_episodic.h new file mode 100644 index 0000000..e0da23d --- /dev/null +++ b/game/server/hl2/npc_vortigaunt_episodic.h @@ -0,0 +1,344 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is the base version of the vortigaunt +// +//=============================================================================// + +#ifndef NPC_VORTIGAUNT_H +#define NPC_VORTIGAUNT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" +#include "ai_behavior.h" +#include "ai_behavior_lead.h" +#include "ai_behavior_standoff.h" +#include "ai_behavior_assault.h" +#include "npc_playercompanion.h" + +#define VORTIGAUNT_MAX_BEAMS 8 + +#define VORTIGAUNT_BEAM_ALL -1 +#define VORTIGAUNT_BEAM_ZAP 0 +#define VORTIGAUNT_BEAM_HEAL 1 +#define VORTIGAUNT_BEAM_DISPEL 2 + +class CBeam; +class CSprite; +class CVortigauntChargeToken; +class CVortigauntEffectDispel; + +extern ConVar sk_vortigaunt_zap_range; + +enum VortigauntHealState_t +{ + HEAL_STATE_NONE, // Not trying to heal + HEAL_STATE_WARMUP, // In the "warm-up" phase of healing + HEAL_STATE_HEALING, // In the process of healing + HEAL_STATE_COOLDOWN, // in the "cooldown" phase of healing +}; + +//========================================================= +// >> CNPC_Vortigaunt +//========================================================= +class CNPC_Vortigaunt : public CNPC_PlayerCompanion +{ + DECLARE_CLASS( CNPC_Vortigaunt, CNPC_PlayerCompanion ); + +public: + CNPC_Vortigaunt( void ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual float MaxYawSpeed( void ); + + virtual Vector FacingPosition( void ); + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + + virtual void PrescheduleThink( void ); + virtual void BuildScheduleTestBits( void ); + virtual void OnScheduleChange( void ); + + virtual int RangeAttack1Conditions( float flDot, float flDist ); // Primary zap + virtual int RangeAttack2Conditions( float flDot, float flDist ); // Concussive zap (larger) + virtual bool InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + virtual int MeleeAttack1Conditions( float flDot, float flDist ); // Dispel + virtual float InnateRange1MinRange( void ) { return 0.0f; } + virtual float InnateRange1MaxRange( void ) { return sk_vortigaunt_zap_range.GetFloat()*12; } + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual bool FInViewCone( CBaseEntity *pEntity ); + virtual bool ShouldMoveAndShoot( void ); + + // vorts have a very long head/neck swing, so debounce heavily + virtual float GetHeadDebounce( void ) { return 0.7; } // how much of previous head turn to use + + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void AlertSound( void ); + virtual Class_T Classify ( void ) { return IsGameEndAlly() ? CLASS_PLAYER_ALLY_VITAL : CLASS_VORTIGAUNT; } + virtual void HandleAnimEvent( animevent_t *pEvent ); + virtual Activity NPC_TranslateActivity( Activity eNewActivity ); + + virtual void UpdateOnRemove( void ); + virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual void GatherConditions( void ); + virtual void RunTask( const Task_t *pTask ); + virtual void StartTask( const Task_t *pTask ); + virtual void ClearSchedule( const char *szReason ); + + virtual void DeclineFollowing( void ); + virtual bool CanBeUsedAsAFriend( void ); + virtual bool IsPlayerAlly( void ) { return true; } + + // Override these to set behavior + virtual int TranslateSchedule( int scheduleType ); + virtual int SelectSchedule( void ); + virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); + virtual bool IsValidEnemy( CBaseEntity *pEnemy ); + bool IsLeading( void ) { return ( GetRunningBehavior() == &m_LeadBehavior && m_LeadBehavior.HasGoal() ); } + + void DeathSound( const CTakeDamageInfo &info ); + void PainSound( const CTakeDamageInfo &info ); + + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + virtual void SpeakSentence( int sentType ); + + virtual int IRelationPriority( CBaseEntity *pTarget ); + virtual Disposition_t IRelationType( CBaseEntity *pTarget ); + virtual bool IsReadinessCapable( void ) { return true; } + virtual float GetReadinessDecay() { return 30.0f; } + virtual bool ShouldRegenerateHealth( void ) { return m_bRegenerateHealth; } + virtual bool CanRunAScriptedNPCInteraction( bool bForced = false ); + virtual void AimGun( void ); + virtual void OnUpdateShotRegulator( void ); + + void InputEnableArmorRecharge( inputdata_t &data ); + void InputDisableArmorRecharge( inputdata_t &data ); + void InputExtractBugbait( inputdata_t &data ); + void InputChargeTarget( inputdata_t &data ); + void InputDispel( inputdata_t &data ); + void InputBeginCarryNPC( inputdata_t &indputdata ); + void InputEndCarryNPC( inputdata_t &indputdata ); + + // Health regeneration + void InputEnableHealthRegeneration( inputdata_t &data ); + void InputDisableHealthRegeneration( inputdata_t &data ); + + // color + void InputTurnBlue( inputdata_t &data ); + void InputTurnBlack( inputdata_t &data ); + + virtual void SetScriptedScheduleIgnoreConditions( Interruptability_t interrupt ); + virtual void OnRestore( void ); + virtual bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ); + virtual void OnStartScene( void ); + virtual bool IsInterruptable( void ); + virtual bool CanFlinch( void ); + + // used so a grub can notify me that I stepped on it. Says a line. + void OnSquishedGrub( const CBaseEntity *pGrub ); + +private: + + int NumAntlionsInRadius( float flRadius ); + void DispelAntlions( const Vector &vecOrigin, float flRadius, bool bDispel = true ); + bool HealGestureHasLOS( void ); + bool PlayerBelowHealthPercentage( CBasePlayer *pPlayer, float flPerc ); + void StartHealing( void ); + void StopHealing( bool bInterrupt = false ); + void MaintainHealSchedule( void ); + bool ShouldHealTarget( CBaseEntity *pTarget ); + int SelectHealSchedule( void ); + + void CreateBeamBlast( const Vector &vecOrigin ); + +private: + //========================================================= + // Vortigaunt schedules + //========================================================= + enum + { + SCHED_VORTIGAUNT_STAND = BaseClass::NEXT_SCHEDULE, + SCHED_VORTIGAUNT_RANGE_ATTACK, + SCHED_VORTIGAUNT_HEAL, + SCHED_VORTIGAUNT_EXTRACT_BUGBAIT, + SCHED_VORTIGAUNT_FACE_PLAYER, + SCHED_VORTIGAUNT_RUN_TO_PLAYER, + SCHED_VORTIGAUNT_DISPEL_ANTLIONS, + SCHED_VORT_FLEE_FROM_BEST_SOUND, + SCHED_VORT_ALERT_FACE_BESTSOUND, + }; + + //========================================================= + // Vortigaunt Tasks + //========================================================= + enum + { + TASK_VORTIGAUNT_HEAL_WARMUP = BaseClass::NEXT_TASK, + TASK_VORTIGAUNT_HEAL, + TASK_VORTIGAUNT_EXTRACT_WARMUP, + TASK_VORTIGAUNT_EXTRACT, + TASK_VORTIGAUNT_EXTRACT_COOLDOWN, + TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT, + TASK_VORTIGAUNT_WAIT_FOR_PLAYER, + TASK_VORTIGAUNT_GET_HEAL_TARGET, + TASK_VORTIGAUNT_DISPEL_ANTLIONS + }; + + //========================================================= + // Vortigaunt Conditions + //========================================================= + enum + { + COND_VORTIGAUNT_CAN_HEAL = BaseClass::NEXT_CONDITION, + COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR, // Outside or heal range + COND_VORTIGAUNT_HEAL_TARGET_BLOCKED, // Blocked by an obstruction + COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US, // Not within our "forward" range + COND_VORTIGAUNT_HEAL_VALID, // All conditions satisfied + COND_VORTIGAUNT_DISPEL_ANTLIONS, // Repulse all antlions around us + }; + + // ------------ + // Beams + // ------------ + inline bool InAttackSequence( void ); + void ClearBeams( void ); + void ArmBeam( int beamType, int nHand ); + void ZapBeam( int nHand ); + int m_nLightningSprite; + + // --------------- + // Glow + // ---------------- + void ClearHandGlow( void ); + float m_fGlowAge; + float m_fGlowChangeTime; + bool m_bGlowTurningOn; + int m_nCurGlowIndex; + + CHandle m_hHandEffect[2]; + + void StartHandGlow( int beamType, int nHand ); + void EndHandGlow( int beamType = VORTIGAUNT_BEAM_ALL ); + void MaintainGlows( void ); + + // ---------------- + // Healing + // ---------------- + bool m_bRegenerateHealth; + float m_flNextHealTime; // Next time allowed to heal player + EHANDLE m_hHealTarget; // The person that I'm going to heal. + bool m_bPlayerRequestedHeal; // This adds some priority to our heal (allows it to happen in combat, etc) + float m_flNextHealTokenTime; + + VortigauntHealState_t m_eHealState; + + CBaseEntity *FindHealTarget( void ); + bool HealBehaviorAvailable( void ); + void SetHealTarget( CBaseEntity *pTarget, bool bPlayerRequested ); + void GatherHealConditions( void ); + + int m_nNumTokensToSpawn; + float m_flHealHinderedTime; + float m_flPainTime; + float m_nextLineFireTime; + + bool m_bArmorRechargeEnabled; + bool m_bForceArmorRecharge; + float m_flDispelTestTime; + + bool m_bExtractingBugbait; + + bool IsCarryingNPC( void ) const { return m_bCarryingNPC; } + bool m_bCarryingNPC; + + COutputEvent m_OnFinishedExtractingBugbait; + COutputEvent m_OnFinishedChargingTarget; + COutputEvent m_OnPlayerUse; + + //Adrian: Let's do it the right way! + int m_iLeftHandAttachment; + int m_iRightHandAttachment; + bool m_bStopLoopingSounds; + float m_flAimDelay; // Amount of time to suppress aiming + + // used for fading from green vort to blue vort + CNetworkVar( bool, m_bIsBlue ); + CNetworkVar( float, m_flBlueEndFadeTime ); + + // used for fading to black + CNetworkVar( bool, m_bIsBlack ); + +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; +}; + +//============================================================================= +// +// Charge Token +// +//============================================================================= + +class CVortigauntChargeToken : public CBaseEntity +{ + DECLARE_CLASS( CVortigauntChargeToken, CBaseEntity ); + +public: + + static CVortigauntChargeToken *CreateChargeToken( const Vector &vecOrigin, CBaseEntity *pOwner, CBaseEntity *pTarget ); + + CVortigauntChargeToken( void ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + + void FadeAndDie( void ); + void SeekThink( void ); + void SeekTouch( CBaseEntity *pOther ); + void SetTargetEntity( CBaseEntity *pTarget ) { m_hTarget = pTarget; } + +private: + + Vector GetSteerVector( const Vector &vecForward ); + + float m_flLifetime; + EHANDLE m_hTarget; + + CNetworkVar( bool, m_bFadeOut ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); +}; + +//============================================================================= +// +// Dispel Effect +// +//============================================================================= + +class CVortigauntEffectDispel : public CBaseEntity +{ + DECLARE_CLASS( CVortigauntEffectDispel, CBaseEntity ); + +public: + + static CVortigauntEffectDispel *CreateEffectDispel( const Vector &vecOrigin, CBaseEntity *pOwner, CBaseEntity *pTarget ); + + CVortigauntEffectDispel( void ); + + virtual void Spawn( void ); + + void FadeAndDie( void ); + +private: + + CNetworkVar( bool, m_bFadeOut ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); +}; + +#endif // NPC_VORTIGAUNT_H diff --git a/game/server/hl2/prop_combine_ball.h b/game/server/hl2/prop_combine_ball.h new file mode 100644 index 0000000..1de4390 --- /dev/null +++ b/game/server/hl2/prop_combine_ball.h @@ -0,0 +1,299 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PROP_COMBINE_BALL_H +#define PROP_COMBINE_BALL_H +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- +#include "player_pickup.h" // for combine ball inheritance + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CFuncCombineBallSpawner; +class CSpriteTrail; + +//----------------------------------------------------------------------------- +// Looks for enemies, bounces a max # of times before it breaks +//----------------------------------------------------------------------------- +class CPropCombineBall : public CBaseAnimating, public CDefaultPlayerPickupVPhysics +{ +public: + DECLARE_CLASS( CPropCombineBall, CBaseAnimating ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual void Precache(); + virtual void Spawn(); + virtual void UpdateOnRemove(); + void StopLoopingSounds(); + + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + + virtual bool OverridePropdata(); + virtual bool CreateVPhysics(); + + CFuncCombineBallSpawner *GetSpawner(); + + virtual void ExplodeThink( void ); + + // Override of IPlayerPickupVPhysics; + virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) { return ( reason == PHYSGUN_FORCE_PUNTED ); } + + void SetRadius( float flRadius ); + void SetSpeed( float flSpeed ) { m_flSpeed = flSpeed; } + float GetSpeed( void ) const { return m_flSpeed; } + + void CaptureBySpawner( ); + bool IsBeingCaptured() const { return m_bCaptureInProgress; } + + void ReplaceInSpawner( float flSpeed ); + + // Input + void InputExplode( inputdata_t &inputdata ); + void InputFadeAndRespawn( inputdata_t &inputdata ); + void InputKill( inputdata_t &inputdata ); + void InputSocketed( inputdata_t &inputdata ); + + enum + { + STATE_NOT_THROWN = 0, + STATE_HOLDING, + STATE_THROWN, + STATE_LAUNCHED, //by a combine_ball launcher + }; + + void SetState( int state ); + bool IsInField() const; + + void StartWhizSoundThink( void ); + + void StartLifetime( float flDuration ); + void ClearLifetime( ); + void SetMass( float mass ); + + void SetWeaponLaunched( bool state = true ) { m_bWeaponLaunched = state; m_bLaunched = state; } + bool WasWeaponLaunched( void ) const { return m_bWeaponLaunched; } + + bool WasFiredByNPC() const { return (GetOwnerEntity() && GetOwnerEntity()->IsNPC()); } + + bool ShouldHitPlayer() const; + + virtual CBasePlayer *HasPhysicsAttacker( float dt ); + + void SetSpawner( CFuncCombineBallSpawner *pSpawner ) { m_hSpawner = pSpawner; } + void NotifySpawnerOfRemoval( void ); + + + float LastCaptureTime() const; + + unsigned char GetState() const { return m_nState; } + + int NumBounces( void ) const { return m_nBounceCount; } + + void SetMaxBounces( int iBounces ) + { + m_nMaxBounces = iBounces; + } + + void SetEmitState( bool bEmit ) + { + m_bEmit = bEmit; + } + + void SetOriginalOwner( CBaseEntity *pEntity ) { m_hOriginalOwner = pEntity; } + CBaseEntity *GetOriginalOwner() { return m_hOriginalOwner; } + +private: + + void SetPlayerLaunched( CBasePlayer *pOwner ); + + float GetBallHoldDissolveTime(); + float GetBallHoldSoundRampTime(); + + // Pow! + void DoExplosion( ); + + void StartAnimating( void ); + void StopAnimating( void ); + + void SetBallAsLaunched( void ); + + void CollisionEventToTrace( int index, gamevcollisionevent_t *pEvent, trace_t &tr ); + bool DissolveEntity( CBaseEntity *pEntity ); + void OnHitEntity( CBaseEntity *pHitEntity, float flSpeed, int index, gamevcollisionevent_t *pEvent ); + void DoImpactEffect( const Vector &preVelocity, int index, gamevcollisionevent_t *pEvent ); + + // Bounce inside the spawner: + void BounceInSpawner( float flSpeed, int index, gamevcollisionevent_t *pEvent ); + + bool IsAttractiveTarget( CBaseEntity *pEntity ); + + // Deflects the ball toward enemies in case of a collision + void DeflectTowardEnemy( float flSpeed, int index, gamevcollisionevent_t *pEvent ); + + // Is this something we can potentially dissolve? + bool IsHittableEntity( CBaseEntity *pHitEntity ); + + // Sucky. + void WhizSoundThink(); + void DieThink(); + void DissolveThink(); + void DissolveRampSoundThink(); + void AnimThink( void ); + + void FadeOut( float flDuration ); + + + bool OutOfBounces( void ) const + { + return ( m_nState == STATE_LAUNCHED && m_nMaxBounces != 0 && m_nBounceCount >= m_nMaxBounces ); + } + +private: + + int m_nBounceCount; + int m_nMaxBounces; + bool m_bBounceDie; + + float m_flLastBounceTime; + + bool m_bFiredGrabbedOutput; + bool m_bStruckEntity; // Has hit an entity already (control accuracy) + bool m_bWeaponLaunched; // Means this was fired from the AR2 + bool m_bForward; // Movement direction in ball spawner + + unsigned char m_nState; + bool m_bCaptureInProgress; + + float m_flSpeed; + + CSpriteTrail *m_pGlowTrail; + CSoundPatch *m_pHoldingSound; + + float m_flNextDamageTime; + float m_flLastCaptureTime; + + CHandle < CFuncCombineBallSpawner > m_hSpawner; + + EHANDLE m_hOriginalOwner; + + CNetworkVar( bool, m_bEmit ); + CNetworkVar( bool, m_bHeld ); + CNetworkVar( bool, m_bLaunched ); + CNetworkVar( float, m_flRadius ); +}; + +class CFuncCombineBallSpawner : public CBaseEntity +{ + DECLARE_CLASS( CFuncCombineBallSpawner, CBaseEntity ); + DECLARE_DATADESC(); + +public: + CFuncCombineBallSpawner(); + + virtual void Spawn(); + virtual void Precache(); + + // Balls call this to figure out where to bounce to + void GetTargetEndpoint( bool bForward, Vector *pVecEndpoint ); + + // Balls call this when they've been removed from the spawner + void RespawnBall( float flRespawnTime ); + void RespawnBallPostExplosion( void ); + + // Fire ball grabbed output + void BallGrabbed( CBaseEntity *pEntity ); + + // Get speed of ball to place into the field + float GetBallSpeed( ) const; + + // Register that a reflection occurred + void RegisterReflection( CPropCombineBall *pBall, bool bForward ); + + // Spawn a ball + virtual void SpawnBall(); + +private: + + // Choose a random point inside the cylinder + void ChoosePointInCylinder( Vector *pVecPoint ); + + // Choose a random point inside the box + void ChoosePointInBox( Vector *pVecPoint ); + + // Used to determine when to respawn balls + void BallThink(); + + // Input + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + // Fire ball grabbed output + void GrabBallTouch( CBaseEntity *pOther ); + +public: + bool m_bShooter; + float m_flBallRadius; + float m_flBallRespawnTime; + float m_flMinSpeed; + float m_flMaxSpeed; + +private: + CUtlVector< float > m_BallRespawnTime; + int m_nBallCount; + int m_nBallsRemainingInField; + float m_flRadius; + float m_flDisableTime; + bool m_bEnabled; + + COutputEvent m_OnBallGrabbed; + COutputEvent m_OnBallReinserted; + COutputEvent m_OnBallHitTopSide; + COutputEvent m_OnBallHitBottomSide; + COutputEvent m_OnLastBallGrabbed; + COutputEvent m_OnFirstBallReinserted; +}; + + +class CPointCombineBallLauncher : public CFuncCombineBallSpawner +{ + DECLARE_CLASS( CPointCombineBallLauncher, CFuncCombineBallSpawner ); + + DECLARE_DATADESC(); + +public: + + virtual void Spawn( void ); + virtual void SpawnBall( void ); + void InputLaunchBall ( inputdata_t &inputdata ); + + CPointCombineBallLauncher(); + +private: + + int m_iBounces; + float m_flConeDegrees; + string_t m_iszBullseyeName; +}; + +// Creates a combine ball +CBaseEntity *CreateCombineBall( const Vector &origin, const Vector &velocity, float radius, float mass, float lifetime, CBaseEntity *pOwner ); + +// Query function to find out if a physics object is a combine ball (used for collision checks) +bool UTIL_IsCombineBall( CBaseEntity *pEntity ); +bool UTIL_IsCombineBallDefinite( CBaseEntity *pEntity ); +bool UTIL_IsAR2CombineBall( CBaseEntity *pEntity ); + +#endif // PROP_COMBINE_BALL_H diff --git a/game/server/hl2/rotorwash.h b/game/server/hl2/rotorwash.h new file mode 100644 index 0000000..a33a687 --- /dev/null +++ b/game/server/hl2/rotorwash.h @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ROTORWASH_H +#define ROTORWASH_H +#ifdef _WIN32 +#pragma once +#endif + +CBaseEntity *CreateRotorWashEmitter( const Vector &localOrigin, const QAngle &localAngles, CBaseEntity *pOwner, float flAltitude ); + +#endif // ROTORWASH_H diff --git a/game/server/hl2/script_intro.h b/game/server/hl2/script_intro.h new file mode 100644 index 0000000..5e59fa3 --- /dev/null +++ b/game/server/hl2/script_intro.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SCRIPT_INTRO_H +#define SCRIPT_INTRO_H +#ifdef _WIN32 +#pragma once +#endif + + +class CPointCamera; + + +//----------------------------------------------------------------------------- +// Purpose: An entity that's used to control the intro sequence +//----------------------------------------------------------------------------- +class CScriptIntro : public CBaseEntity +{ + DECLARE_CLASS(CScriptIntro, CBaseEntity); +public: + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual void Spawn( void ); + virtual void Precache(); + virtual void Activate( void ); + virtual int UpdateTransmitState(void); + + // Inputs + void InputSetPlayerViewEntity( inputdata_t &inputdata ); + void InputSetCameraViewEntity( inputdata_t &inputdata ); + void InputSetBlendMode( inputdata_t &inputdata ); + void InputSetNextBlendMode( inputdata_t &inputdata ); + void InputSetNextFOV( inputdata_t &inputdata ); + void InputSetFOVBlendTime( inputdata_t &inputdata ); + void InputSetFOV( inputdata_t &inputdata ); + void InputSetNextBlendTime( inputdata_t &inputdata ); + void InputActivate( inputdata_t &inputdata ); + void InputDeactivate( inputdata_t &inputdata ); + + void InputFadeTo( inputdata_t &inputdata ); + void InputSetFadeColor( inputdata_t &inputdata ); + + bool GetIncludedPVSOrigin( Vector *pOrigin, CBaseEntity **ppCamera ); + +private: + // Think func used to finish the blend off + void BlendComplete( ); + +private: + CNetworkVar( Vector, m_vecPlayerView ); + CNetworkVar( QAngle, m_vecPlayerViewAngles ); + CNetworkVar( Vector, m_vecCameraView ); + CNetworkVar( QAngle, m_vecCameraViewAngles ); + CNetworkVar( int, m_iBlendMode ); + CNetworkVar( int, m_iNextBlendMode ); + CNetworkVar( float, m_flNextBlendTime ); + CNetworkVar( float, m_flBlendStartTime ); + CNetworkVar( int, m_iStartFOV ); + CNetworkVar( bool, m_bActive ); + + // Fov & fov blends + CNetworkVar( int, m_iNextFOV ); + CNetworkVar( float, m_flNextFOVBlendTime ); + CNetworkVar( float, m_flFOVBlendStartTime ); + CNetworkVar( int, m_iFOV ); + CNetworkVar( bool, m_bAlternateFOV ); + + // Fades + CNetworkArray( float, m_flFadeColor, 3 ); + CNetworkVar( float, m_flFadeAlpha); + CNetworkVar( float, m_flFadeDuration ); + + CNetworkVar( EHANDLE, m_hCameraEntity ); + + int m_iQueuedBlendMode; + int m_iQueuedNextBlendMode; +}; + +extern CHandle g_hIntroScript; + +#endif // SCRIPT_INTRO_H diff --git a/game/server/hl2/vehicle_apc.h b/game/server/hl2/vehicle_apc.h new file mode 100644 index 0000000..5c7aa56 --- /dev/null +++ b/game/server/hl2/vehicle_apc.h @@ -0,0 +1,162 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VEHICLE_APC_H +#define VEHICLE_APC_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vehicle_base.h" +#include "smoke_trail.h" + +//----------------------------------------------------------------------------- +// Purpose: Four wheel physics vehicle server vehicle with weaponry +//----------------------------------------------------------------------------- +class CAPCFourWheelServerVehicle : public CFourWheelServerVehicle +{ + typedef CFourWheelServerVehicle BaseClass; +// IServerVehicle +public: + bool NPC_HasPrimaryWeapon( void ) { return true; } + void NPC_AimPrimaryWeapon( Vector vecTarget ); + bool NPC_HasSecondaryWeapon( void ) { return true; } + void NPC_AimSecondaryWeapon( Vector vecTarget ); + + // Weaponry + void Weapon_PrimaryRanges( float *flMinRange, float *flMaxRange ); + void Weapon_SecondaryRanges( float *flMinRange, float *flMaxRange ); + float Weapon_PrimaryCanFireAt( void ); // Return the time at which this vehicle's primary weapon can fire again + float Weapon_SecondaryCanFireAt( void ); // Return the time at which this vehicle's secondary weapon can fire again +}; + + +//----------------------------------------------------------------------------- +// A driveable vehicle with a gun that shoots wherever the driver looks. +//----------------------------------------------------------------------------- +class CPropAPC : public CPropVehicleDriveable +{ + DECLARE_CLASS( CPropAPC, CPropVehicleDriveable ); +public: + // CBaseEntity + virtual void Precache( void ); + void Think( void ); + virtual void Spawn(void); + virtual void Activate(); + virtual void UpdateOnRemove( void ); + virtual void OnRestore( void ); + + // CPropVehicle + virtual void CreateServerVehicle( void ); + virtual void DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased ); + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ); + virtual Class_T ClassifyPassenger( CBaseCombatCharacter *pPassenger, Class_T defaultClassification ); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual float PassengerDamageModifier( const CTakeDamageInfo &info ); + + // Weaponry + const Vector &GetPrimaryGunOrigin( void ); + void AimPrimaryWeapon( const Vector &vecForward ); + void AimSecondaryWeaponAt( CBaseEntity *pTarget ); + float PrimaryWeaponFireTime( void ) { return m_flMachineGunTime; } + float SecondaryWeaponFireTime( void ) { return m_flRocketTime; } + float MaxAttackRange() const; + bool IsInPrimaryFiringCone() const { return m_bInFiringCone; } + + // Muzzle flashes + const char *GetTracerType( void ) ; + void DoImpactEffect( trace_t &tr, int nDamageType ); + void DoMuzzleFlash( void ); + + virtual Vector EyePosition( ); // position of eyes + Vector BodyTarget( const Vector &posSrc, bool bNoisy ); + + + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +private: + enum + { + MAX_SMOKE_TRAILS = 4, + MAX_EXPLOSIONS = 4, + }; + + // Should we trigger a damage effect? + bool ShouldTriggerDamageEffect( int nPrevHealth, int nEffectCount ) const; + + // Add a smoke trail since we've taken more damage + void AddSmokeTrail( const Vector &vecPos ); + + // Creates the breakable husk of an attack chopper + void CreateChopperHusk(); + + // Pow! + void ExplodeAndThrowChunk( const Vector &vecExplosionPos ); + + void Event_Killed( const CTakeDamageInfo &info ); + + // Purpose: + void GetRocketShootPosition( Vector *pPosition ); + + void FireMachineGun( void ); + void FireRocket( void ); + + // Death volley + void FireDying( ); + + // Create a corpse + void CreateCorpse( ); + + // Blows da shizzle up + void InputDestroy( inputdata_t &inputdata ); + void InputFireMissileAt( inputdata_t &inputdata ); + + void CreateAPCLaserDot( void ); + + virtual bool ShouldAttractAutoAim( CBaseEntity *pAimingEnt ); + + +private: + // Danger sounds made by the APC + float m_flDangerSoundTime; + + // handbrake after the fact to keep vehicles from rolling + float m_flHandbrakeTime; + bool m_bInitialHandbrake; + + // Damage effects + int m_nSmokeTrailCount; + + // Machine gun attacks + int m_nMachineGunMuzzleAttachment; + int m_nMachineGunBaseAttachment; + float m_flMachineGunTime; + int m_iMachineGunBurstLeft; + Vector m_vecBarrelPos; + bool m_bInFiringCone; + + // Rocket attacks + EHANDLE m_hLaserDot; + EHANDLE m_hRocketTarget; + int m_iRocketSalvoLeft; + float m_flRocketTime; + int m_nRocketAttachment; + int m_nRocketSide; + EHANDLE m_hSpecificRocketTarget; + string_t m_strMissileHint; + + COutputEvent m_OnDeath; + COutputEvent m_OnFiredMissile; + COutputEvent m_OnDamaged; + COutputEvent m_OnDamagedByPlayer; + + DECLARE_DATADESC(); +}; + +#endif // VEHICLE_APC_H + diff --git a/game/server/hl2/vehicle_crane.h b/game/server/hl2/vehicle_crane.h new file mode 100644 index 0000000..57d25e8 --- /dev/null +++ b/game/server/hl2/vehicle_crane.h @@ -0,0 +1,250 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// Purpose: +// +//============================================================================= + +#ifndef VEHICLE_CRANE_H +#define VEHICLE_CRANE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "physobj.h" +#include "rope.h" +#include "rope_shared.h" +#include "physics_bone_follower.h" + +#define CRANE_EXTENSION_RATE_MAX 0.01 +#define CRANE_TURN_RATE_MAX 1.2 +#define MAXIMUM_CRANE_PICKUP_MASS 10000 +#define MINIMUM_CRANE_PICKUP_MASS 500 + +#define MAX_CRANE_FLAT_REACH 1400.0 +#define MIN_CRANE_FLAT_REACH 700.0 +#define CRANE_EXTENSION_ACCEL 0.006 +#define CRANE_EXTENSION_DECEL 0.02 +#define CRANE_TURN_ACCEL 0.2 +#define CRANE_DECEL 0.5 + +#define CRANE_SLOWRAISE_TIME 5.0 + +// Turning stats +enum +{ + TURNING_NOT, + TURNING_LEFT, + TURNING_RIGHT, +}; + +class CPropCrane; + +//----------------------------------------------------------------------------- +// Purpose: This is the entity we attach to the tip of the crane and dangle the cable from +//----------------------------------------------------------------------------- +class CCraneTip : public CBaseAnimating +{ + DECLARE_CLASS( CCraneTip, CBaseAnimating ); +public: + DECLARE_DATADESC(); + + ~CCraneTip( void ) + { + if ( m_pSpring ) + { + physenv->DestroySpring( m_pSpring ); + } + } + + void Spawn( void ); + void Precache( void ); + + bool CreateConstraint( CBaseAnimating *pMagnet, IPhysicsConstraintGroup *pGroup ); + static CCraneTip *Create( CBaseAnimating *pCraneMagnet, IPhysicsConstraintGroup *pGroup, const Vector &vecOrigin, const QAngle &vecAngles ); + +public: + IPhysicsSpring *m_pSpring; +}; + +//----------------------------------------------------------------------------- +// Purpose: Crane vehicle server +//----------------------------------------------------------------------------- +class CCraneServerVehicle : public CBaseServerVehicle +{ + typedef CBaseServerVehicle BaseClass; +// IServerVehicle +public: + void GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV = NULL ); + + // NPC Driving + void NPC_SetDriver( CNPC_VehicleDriver *pDriver ); + void NPC_DriveVehicle( void ); + + virtual bool IsPassengerEntering( void ) { return false; } // NOTE: This mimics the scenario HL2 would have seen + virtual bool IsPassengerExiting( void ) { return false; } + +protected: + CPropCrane *GetCrane( void ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPropCrane : public CBaseProp, public IDrivableVehicle +{ + DECLARE_CLASS( CPropCrane, CBaseProp ); +public: + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CPropCrane( void ) + { + m_ServerVehicle.SetVehicle( this ); + } + + ~CPropCrane( void ) + { + physenv->DestroyConstraintGroup( m_pConstraintGroup ); + } + + // CBaseEntity + virtual void Precache( void ); + void Spawn( void ); + void Activate( void ); + void UpdateOnRemove( void ); + bool CreateVPhysics( void ); + void InitCraneSpeeds( void ); + void Think(void); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; }; + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void DrawDebugGeometryOverlays( void ); + + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) + { + if ( info.GetDamageType() & DMG_VEHICLE ) + return true; + + return (info.GetDamageType() & (DMG_RADIATION|DMG_BLAST) ) == 0; + } + + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + void PlayerControlInit( CBasePlayer *pPlayer ); + void PlayerControlShutdown( void ); + void ResetUseKey( CBasePlayer *pPlayer ); + + void DriveCrane( int iDriverButtons, int iButtonsPressed, float flNPCSteering = 0.0 ); + void RunCraneMovement( float flTime ); + + void TurnMagnetOn( void ); + void TurnMagnetOff( void ); + const Vector &GetCraneTipPosition( void ); + float GetExtensionRate( void ) { return m_flExtensionRate; } + float GetTurnRate( void ) { return m_flTurn; } + float GetMaxTurnRate( void ) { return m_flMaxTurnSpeed; } + CPhysMagnet *GetMagnet( void ) { return m_hCraneMagnet; } + float GetTotalMassOnCrane( void ) { return m_hCraneMagnet->GetTotalMassAttachedObjects(); } + bool IsDropping( void ) { return m_bDropping; } + + // Inputs + void InputLock( inputdata_t &inputdata ); + void InputUnlock( inputdata_t &inputdata ); + void InputForcePlayerIn( inputdata_t &inputdata ); + + // Crane handling + void GetCraneTipPosition( Vector *vecOrigin, QAngle *vecAngles ); + void RecalculateCraneTip( void ); + void GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const; + + void SetNPCDriver( CNPC_VehicleDriver *pDriver ); + +// IDrivableVehicle +public: + virtual CBaseEntity *GetDriver( void ); + virtual void ItemPostFrame( CBasePlayer *pPlayer ); + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ) { return; } + virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) { return; } + virtual bool CanEnterVehicle( CBaseEntity *pEntity ); + virtual bool CanExitVehicle( CBaseEntity *pEntity ); + virtual void SetVehicleEntryAnim( bool bOn ) { m_bEnterAnimOn = bOn; } + virtual void SetVehicleExitAnim( bool bOn, Vector vecEyeExitEndpoint ) { m_bExitAnimOn = bOn; if ( bOn ) m_vecEyeExitEndpoint = vecEyeExitEndpoint; } + virtual void EnterVehicle( CBaseCombatCharacter *pPassenger ); + + virtual bool AllowBlockedExit( CBaseCombatCharacter *pPassenger, int nRole ) { return true; } + virtual bool AllowMidairExit( CBaseCombatCharacter *pPassenger, int nRole ) { return false; } + virtual void PreExitVehicle( CBaseCombatCharacter *pPassenger, int nRole ); + virtual void ExitVehicle( int nRole ); + virtual string_t GetVehicleScriptName() { return m_vehicleScript; } + + // If this is a vehicle, returns the vehicle interface + virtual IServerVehicle *GetServerVehicle() { return &m_ServerVehicle; } + +protected: + // Contained IServerVehicle + CCraneServerVehicle m_ServerVehicle; + // Contained Bone Follower manager + CBoneFollowerManager m_BoneFollowerManager; + +private: + + CNetworkHandle( CBasePlayer, m_hPlayer ); + CNetworkVar( bool, m_bMagnetOn ); + + // NPC Driving + CHandle m_hNPCDriver; + int m_nNPCButtons; + + // Entering / Exiting + bool m_bLocked; + CNetworkVar( bool, m_bEnterAnimOn ); + CNetworkVar( bool, m_bExitAnimOn ); + CNetworkVector( m_vecEyeExitEndpoint ); + COutputEvent m_playerOn; + COutputEvent m_playerOff; + + // Turning + int m_iTurning; + bool m_bStartSoundAtCrossover; + float m_flTurn; + + // Crane arm extension / retraction + bool m_bExtending; + float m_flExtension; + float m_flExtensionRate; + + // Magnet movement + bool m_bDropping; + float m_flNextDangerSoundTime; + float m_flNextCreakSound; + float m_flNextDropAllowedTime; + float m_flSlowRaiseTime; + + // Speeds + float m_flMaxExtensionSpeed; + float m_flMaxTurnSpeed; + float m_flExtensionAccel; + float m_flExtensionDecel; + float m_flTurnAccel; + float m_flTurnDecel; + + // Cable Tip & Magnet + string_t m_iszMagnetName; + CHandle m_hCraneMagnet; + CHandle m_hCraneTip; + CHandle m_hRope; + IPhysicsConstraintGroup *m_pConstraintGroup; + + // Vehicle script filename + string_t m_vehicleScript; +}; + +#endif // VEHICLE_CRANE_H diff --git a/game/server/hl2/vehicle_jeep.h b/game/server/hl2/vehicle_jeep.h new file mode 100644 index 0000000..ba08c2c --- /dev/null +++ b/game/server/hl2/vehicle_jeep.h @@ -0,0 +1,167 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VEHICLE_JEEP_H +#define VEHICLE_JEEP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vehicle_base.h" + +#define JEEP_WHEEL_COUNT 4 + +struct JeepWaterData_t +{ + bool m_bWheelInWater[JEEP_WHEEL_COUNT]; + bool m_bWheelWasInWater[JEEP_WHEEL_COUNT]; + Vector m_vecWheelContactPoints[JEEP_WHEEL_COUNT]; + float m_flNextRippleTime[JEEP_WHEEL_COUNT]; + bool m_bBodyInWater; + bool m_bBodyWasInWater; + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPropJeep : public CPropVehicleDriveable +{ +public: + DECLARE_CLASS( CPropJeep, CPropVehicleDriveable ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CPropJeep( void ); + + // CPropVehicle + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ); + virtual void DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased ); + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); + virtual bool AllowBlockedExit( CBasePlayer *pPlayer, int nRole ) { return false; } + virtual bool CanExitVehicle( CBaseEntity *pEntity ); + virtual bool IsVehicleBodyInWater() { return m_WaterData.m_bBodyInWater; } + + // Passengers do not directly receive damage from blasts or radiation damage + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) + { + if ( GetServerVehicle() && GetServerVehicle()->IsPassengerExiting() ) + return false; + + if ( info.GetDamageType() & DMG_VEHICLE ) + return true; + + return (info.GetDamageType() & (DMG_RADIATION|DMG_BLAST) ) == 0; + } + + // CBaseEntity + void Think(void); + void Precache( void ); + void Spawn( void ); + void Activate( void ); + + virtual void CreateServerVehicle( void ); + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual float PassengerDamageModifier( const CTakeDamageInfo &info ); + + virtual void EnterVehicle( CBaseCombatCharacter *pPassenger ); + virtual void ExitVehicle( int nRole ); + + void AimGunAt( Vector *endPos, float flInterval ); + bool TauCannonHasBeenCutOff( void ) { return m_bGunHasBeenCutOff; } + + // NPC Driving + bool NPC_HasPrimaryWeapon( void ) { return true; } + void NPC_AimPrimaryWeapon( Vector vecTarget ); + + const char *GetTracerType( void ) { return "AR2Tracer"; } + void DoImpactEffect( trace_t &tr, int nDamageType ); + + bool HeadlightIsOn( void ) { return m_bHeadlightIsOn; } + void HeadlightTurnOn( void ) { m_bHeadlightIsOn = true; } + void HeadlightTurnOff( void ) { m_bHeadlightIsOn = false; } + +private: + + void FireCannon( void ); + void ChargeCannon( void ); + void FireChargedCannon( void ); + + void DrawBeam( const Vector &startPos, const Vector &endPos, float width ); + void StopChargeSound( void ); + void GetCannonAim( Vector *resultDir ); + + void InitWaterData( void ); + void CheckWaterLevel( void ); + void CreateSplash( const Vector &vecPosition ); + void CreateRipple( const Vector &vecPosition ); + + void CreateDangerSounds( void ); + + void ComputePDControllerCoefficients( float *pCoefficientsOut, float flFrequency, float flDampening, float flDeltaTime ); + void DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ); + void DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ); + + void JeepSeagullThink( void ); + void SpawnPerchedSeagull( void ); + void AddSeagullPoop( const Vector &vecOrigin ); + + void InputShowHudHint( inputdata_t &inputdata ); + void InputStartRemoveTauCannon( inputdata_t &inputdata ); + void InputFinishRemoveTauCannon( inputdata_t &inputdata ); + +protected: + + virtual void HandleWater( void ); + bool CheckWater( void ); + + bool m_bGunHasBeenCutOff; + float m_flDangerSoundTime; + int m_nBulletType; + bool m_bCannonCharging; + float m_flCannonTime; + float m_flCannonChargeStartTime; + Vector m_vecGunOrigin; + CSoundPatch *m_sndCannonCharge; + int m_nSpinPos; + float m_aimYaw; + float m_aimPitch; + float m_throttleDisableTime; + float m_flAmmoCrateCloseTime; + + // handbrake after the fact to keep vehicles from rolling + float m_flHandbrakeTime; + bool m_bInitialHandbrake; + + float m_flOverturnedTime; + + Vector m_vecLastEyePos; + Vector m_vecLastEyeTarget; + Vector m_vecEyeSpeed; + Vector m_vecTargetSpeed; + + JeepWaterData_t m_WaterData; + + int m_iNumberOfEntries; + int m_nAmmoType; + + // Seagull perching + float m_flPlayerExitedTime; // Time at which the player last left this vehicle + float m_flLastSawPlayerAt; // Time at which we last saw the player + EHANDLE m_hLastPlayerInVehicle; + EHANDLE m_hSeagull; + bool m_bHasPoop; + + CNetworkVar( bool, m_bHeadlightIsOn ); +}; + +#endif // VEHICLE_JEEP_H diff --git a/game/server/hl2/weapon_alyxgun.h b/game/server/hl2/weapon_alyxgun.h new file mode 100644 index 0000000..cc3e862 --- /dev/null +++ b/game/server/hl2/weapon_alyxgun.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_ALYXGUN_H +#define WEAPON_ALYXGUN_H + +#include "basehlcombatweapon.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class CWeaponAlyxGun : public CHLSelectFireMachineGun +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CWeaponAlyxGun, CHLSelectFireMachineGun ); + + CWeaponAlyxGun(); + ~CWeaponAlyxGun(); + + DECLARE_SERVERCLASS(); + + void Precache( void ); + + virtual int GetMinBurst( void ) { return 4; } + virtual int GetMaxBurst( void ) { return 7; } + virtual float GetMinRestTime( void ); + virtual float GetMaxRestTime( void ); + + virtual void Equip( CBaseCombatCharacter *pOwner ); + + float GetFireRate( void ) { return 0.1f; } + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + int WeaponRangeAttack1Condition( float flDot, float flDist ); + int WeaponRangeAttack2Condition( float flDot, float flDist ); + + virtual const Vector& GetBulletSpread( void ); + + void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles ); + + void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ); + void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + + virtual void SetPickupTouch( void ) + { + // Alyx gun cannot be picked up + SetTouch(NULL); + } + + float m_flTooCloseTimer; + + DECLARE_ACTTABLE(); + +}; + +#endif // WEAPON_ALYXGUN_H diff --git a/game/server/hl2/weapon_ar2.h b/game/server/hl2/weapon_ar2.h new file mode 100644 index 0000000..d5376a8 --- /dev/null +++ b/game/server/hl2/weapon_ar2.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot from the AR2 +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONAR2_H +#define WEAPONAR2_H + +#include "basegrenade_shared.h" +#include "basehlcombatweapon.h" + +class CWeaponAR2 : public CHLMachineGun +{ +public: + DECLARE_CLASS( CWeaponAR2, CHLMachineGun ); + + CWeaponAR2(); + + DECLARE_SERVERCLASS(); + + void ItemPostFrame( void ); + void Precache( void ); + + void SecondaryAttack( void ); + void DelayedAttack( void ); + + const char *GetTracerType( void ) { return "AR2Tracer"; } + + void AddViewKick( void ); + + void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles ); + void FireNPCSecondaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles ); + void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ); + void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + + int GetMinBurst( void ) { return 2; } + int GetMaxBurst( void ) { return 5; } + float GetFireRate( void ) { return 0.1f; } + + bool CanHolster( void ); + bool Reload( void ); + + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + + Activity GetPrimaryAttackActivity( void ); + + void DoImpactEffect( trace_t &tr, int nDamageType ); + + virtual const Vector& GetBulletSpread( void ) + { + static Vector cone; + + cone = VECTOR_CONE_3DEGREES; + + return cone; + } + + const WeaponProficiencyInfo_t *GetProficiencyValues(); + +protected: + + float m_flDelayedFire; + bool m_bShotDelayed; + int m_nVentPose; + + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); +}; + + +#endif //WEAPONAR2_H diff --git a/game/server/hl2/weapon_brickbat.h b/game/server/hl2/weapon_brickbat.h new file mode 100644 index 0000000..ec4d827 --- /dev/null +++ b/game/server/hl2/weapon_brickbat.h @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Weapon that throws things from the hand +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPON_BRICKBAT_H +#define WEAPON_BRICKBAT_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "basehlcombatweapon.h" + +enum BrickbatAmmo_t +{ + BRICKBAT_ROCK = 0, + BRICKBAT_BOTTLE, + + NUM_BRICKBAT_AMMO_TYPES +}; + +class CGrenade_Brickbat; + +class CWeaponBrickbat : public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CWeaponBrickbat, CBaseHLCombatWeapon ); + + DECLARE_SERVERCLASS(); + +public: + int m_iCurrentAmmoType; + + void Precache( void ); + void Spawn( void ); + bool Deploy( void ); + + virtual const char *GetViewModel( int viewmodelindex =0 ); + virtual const char *GetWorldModel( void ); + + void DrawAmmo( void ); + + virtual int WeaponRangeAttack1Condition( float flDot, float flDist ); + virtual bool WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions); + + void SetPickupTouch( void ); + void BrickbatTouch( CBaseEntity *pOther ); // default weapon touch + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + + bool ObjectInWay( void ); + + void ThrowBrickbat( Vector vecSrc, Vector vecVelocity, float damage); + void ItemPostFrame( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void Throw( void ); + + void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + + DECLARE_DATADESC(); + DECLARE_ACTTABLE(); + + CWeaponBrickbat(void); + +private: + bool m_bNeedDraw; + bool m_bNeedThrow; + int m_iThrowBits; // Save the current throw bits state + float m_fNextThrowCheck; // When to check throw ability next + Vector m_vecTossVelocity; + + int m_nAmmoCount[NUM_BRICKBAT_AMMO_TYPES]; // How much ammo of each type do I own? +}; + +#endif //WEAPON_BRICKBAT_H diff --git a/game/server/hl2/weapon_citizenpackage.h b/game/server/hl2/weapon_citizenpackage.h new file mode 100644 index 0000000..b562d00 --- /dev/null +++ b/game/server/hl2/weapon_citizenpackage.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#ifndef WEAPON_CITIZENPACKAGE_H +#define WEAPON_CITIZENPACKAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basehlcombatweapon.h" + +//============================================================================= +// +// Weapon - Citizen Package Class +// +class CWeaponCitizenPackage : public CBaseHLCombatWeapon +{ + DECLARE_CLASS( CWeaponCitizenPackage, CBaseHLCombatWeapon ); +public: + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DECLARE_ACTTABLE(); + + void ItemPostFrame( void ); + void Drop( const Vector &vecVelocity ); +}; + +#endif // WEAPON_CITIZENPACKAGE_H \ No newline at end of file diff --git a/game/server/hl2/weapon_crowbar.h b/game/server/hl2/weapon_crowbar.h new file mode 100644 index 0000000..1890ef6 --- /dev/null +++ b/game/server/hl2/weapon_crowbar.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_CROWBAR_H +#define WEAPON_CROWBAR_H + +#include "basebludgeonweapon.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifdef HL2MP +#error weapon_crowbar.h must not be included in hl2mp. The windows compiler will use the wrong class elsewhere if it is. +#endif + +#define CROWBAR_RANGE 75.0f +#define CROWBAR_REFIRE 0.4f + +//----------------------------------------------------------------------------- +// CWeaponCrowbar +//----------------------------------------------------------------------------- + +class CWeaponCrowbar : public CBaseHLBludgeonWeapon +{ +public: + DECLARE_CLASS( CWeaponCrowbar, CBaseHLBludgeonWeapon ); + + DECLARE_SERVERCLASS(); + DECLARE_ACTTABLE(); + + CWeaponCrowbar(); + + float GetRange( void ) { return CROWBAR_RANGE; } + float GetFireRate( void ) { return CROWBAR_REFIRE; } + + void AddViewKick( void ); + float GetDamageForActivity( Activity hitActivity ); + + virtual int WeaponMeleeAttack1Condition( float flDot, float flDist ); + void SecondaryAttack( void ) { return; } + + // Animation event + virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + +private: + // Animation event handlers + void HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); +}; + +#endif // WEAPON_CROWBAR_H diff --git a/game/server/hl2/weapon_flaregun.h b/game/server/hl2/weapon_flaregun.h new file mode 100644 index 0000000..5fcfac3 --- /dev/null +++ b/game/server/hl2/weapon_flaregun.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basehlcombatweapon.h" +#include "soundenvelope.h" + +#ifndef WEAPON_FLAREGUN_H +#define WEAPON_FLAREGUN_H +#ifdef _WIN32 +#pragma once +#endif + +#define SF_FLARE_NO_DLIGHT 0x00000001 +#define SF_FLARE_NO_SMOKE 0x00000002 +#define SF_FLARE_INFINITE 0x00000004 +#define SF_FLARE_START_OFF 0x00000008 + +#define FLARE_DURATION 30.0f +#define FLARE_DECAY_TIME 10.0f +#define FLARE_BLIND_TIME 6.0f + +//--------------------- +// Flare +//--------------------- + +class CFlare : public CBaseCombatCharacter +{ +public: + DECLARE_CLASS( CFlare, CBaseCombatCharacter ); + + CFlare(); + ~CFlare(); + + static CFlare * GetActiveFlares( void ); + CFlare * GetNextFlare( void ) const { return m_pNextFlare; } + + static CFlare *Create( Vector vecOrigin, QAngle vecAngles, CBaseEntity *pOwner, float lifetime ); + + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + + void Spawn( void ); + void Precache( void ); + int Restore( IRestore &restore ); + void Activate( void ); + + void StartBurnSound( void ); + + void Start( float lifeTime ); + void Die( float fadeTime ); + void Launch( const Vector &direction, float speed ); + + Class_T Classify( void ); + + void FlareTouch( CBaseEntity *pOther ); + void FlareBurnTouch( CBaseEntity *pOther ); + void FlareThink( void ); + + void InputStart( inputdata_t &inputdata ); + void InputDie( inputdata_t &inputdata ); + void InputLaunch( inputdata_t &inputdata ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + static CFlare *activeFlares; + + CBaseEntity *m_pOwner; + int m_nBounces; // how many times has this flare bounced? + CNetworkVar( float, m_flTimeBurnOut ); // when will the flare burn out? + CNetworkVar( float, m_flScale ); + float m_flDuration; + float m_flNextDamage; + + CSoundPatch *m_pBurnSound; + bool m_bFading; + CNetworkVar( bool, m_bLight ); + CNetworkVar( bool, m_bSmoke ); + CNetworkVar( bool, m_bPropFlare ); + + bool m_bInActiveList; + CFlare * m_pNextFlare; + + void RemoveFromActiveFlares( void ); + void AddToActiveFlares( void ); +}; + +//--------------------- +// Flaregun +//--------------------- +class CFlaregun:public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CFlaregun, CBaseHLCombatWeapon ); + + DECLARE_SERVERCLASS(); + + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); +}; + +#endif // WEAPON_FLAREGUN_H + diff --git a/game/server/hl2/weapon_gauss.h b/game/server/hl2/weapon_gauss.h new file mode 100644 index 0000000..5ed9f03 --- /dev/null +++ b/game/server/hl2/weapon_gauss.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basehlcombatweapon.h" + +#ifndef WEAPON_GAUSS_H +#define WEAPON_GAUSS_H +#ifdef _WIN32 +#pragma once +#endif + + +#define GAUSS_BEAM_SPRITE "sprites/laserbeam.vmt" + +#define GAUSS_CHARGE_TIME 0.2f +#define MAX_GAUSS_CHARGE 16 +#define MAX_GAUSS_CHARGE_TIME 3 +#define DANGER_GAUSS_CHARGE_TIME 10 +#define GAUSS_NUM_BEAMS 4 + + +#endif // WEAPON_GAUSS_H diff --git a/game/server/hl2/weapon_molotov.h b/game/server/hl2/weapon_molotov.h new file mode 100644 index 0000000..a54f02b --- /dev/null +++ b/game/server/hl2/weapon_molotov.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Molotov weapon +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#include "basehlcombatweapon.h" + +#ifndef WEAPON_MOLOTOV_H +#define WEAPON_MOLOTOV_H + +class CGrenade_Molotov; + +class CWeaponMolotov : public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CWeaponMolotov, CBaseHLCombatWeapon ); + + DECLARE_SERVERCLASS(); + +private: + int m_nNumAmmoTypes; + bool m_bNeedDraw; + int m_iThrowBits; // Save the current throw bits state + float m_fNextThrowCheck; // When to check throw ability next + Vector m_vecTossVelocity; + +public: + + void Precache( void ); + void Spawn( void ); + + void DrawAmmo( void ); + + virtual int WeaponRangeAttack1Condition( float flDot, float flDist ); + virtual bool WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions); + + void SetPickupTouch( void ); + void MolotovTouch( CBaseEntity *pOther ); // default weapon touch + + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + + bool ObjectInWay( void ); + + void ThrowMolotov( const Vector &vecSrc, const Vector &vecVelocity); + void ItemPostFrame( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + + void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); + + CWeaponMolotov(void); +}; + +#endif //WEAPON_MOLOTOV_H diff --git a/game/server/hl2/weapon_physcannon.h b/game/server/hl2/weapon_physcannon.h new file mode 100644 index 0000000..d7ce48e --- /dev/null +++ b/game/server/hl2/weapon_physcannon.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_PHYSCANNON_H +#define WEAPON_PHYSCANNON_H +#ifdef _WIN32 +#pragma once +#endif + + + +//----------------------------------------------------------------------------- +// Do we have the super-phys gun? +//----------------------------------------------------------------------------- +bool PlayerHasMegaPhysCannon(); + +// force the physcannon to drop an object (if carried) +void PhysCannonForceDrop( CBaseCombatWeapon *pActiveWeapon, CBaseEntity *pOnlyIfHoldingThis ); +void PhysCannonBeginUpgrade( CBaseAnimating *pAnim ); + +bool PlayerPickupControllerIsHoldingEntity( CBaseEntity *pPickupController, CBaseEntity *pHeldEntity ); +float PlayerPickupGetHeldObjectMass( CBaseEntity *pPickupControllerEntity, IPhysicsObject *pHeldObject ); +float PhysCannonGetHeldObjectMass( CBaseCombatWeapon *pActiveWeapon, IPhysicsObject *pHeldObject ); + +CBaseEntity *PhysCannonGetHeldEntity( CBaseCombatWeapon *pActiveWeapon ); +CBaseEntity *GetPlayerHeldEntity( CBasePlayer *pPlayer ); + +bool PhysCannonAccountableForObject( CBaseCombatWeapon *pPhysCannon, CBaseEntity *pObject ); + +#endif // WEAPON_PHYSCANNON_H diff --git a/game/server/hl2/weapon_rpg.h b/game/server/hl2/weapon_rpg.h new file mode 100644 index 0000000..b8ca99a --- /dev/null +++ b/game/server/hl2/weapon_rpg.h @@ -0,0 +1,256 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPON_RPG_H +#define WEAPON_RPG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basehlcombatweapon.h" +#include "Sprite.h" +#include "npcevent.h" +#include "beam_shared.h" + +class CWeaponRPG; +class CLaserDot; +class RocketTrail; + +//########################################################################### +// >> CMissile (missile launcher class is below this one!) +//########################################################################### +class CMissile : public CBaseCombatCharacter +{ + DECLARE_CLASS( CMissile, CBaseCombatCharacter ); + +public: + static const int EXPLOSION_RADIUS = 200; + + CMissile(); + ~CMissile(); + +#ifdef HL1_DLL + Class_T Classify( void ) { return CLASS_NONE; } +#else + Class_T Classify( void ) { return CLASS_MISSILE; } +#endif + + void Spawn( void ); + void Precache( void ); + void MissileTouch( CBaseEntity *pOther ); + void Explode( void ); + void ShotDown( void ); + void AccelerateThink( void ); + void AugerThink( void ); + void IgniteThink( void ); + void SeekThink( void ); + void DumbFire( void ); + void SetGracePeriod( float flGracePeriod ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + + virtual float GetDamage() { return m_flDamage; } + virtual void SetDamage(float flDamage) { m_flDamage = flDamage; } + + unsigned int PhysicsSolidMaskForEntity( void ) const; + + CHandle m_hOwner; + + static CMissile *Create( const Vector &vecOrigin, const QAngle &vecAngles, edict_t *pentOwner ); + + void CreateDangerSounds( bool bState ){ m_bCreateDangerSounds = bState; } + + static void AddCustomDetonator( CBaseEntity *pEntity, float radius, float height = -1 ); + static void RemoveCustomDetonator( CBaseEntity *pEntity ); + +protected: + virtual void DoExplosion(); + virtual void ComputeActualDotPosition( CLaserDot *pLaserDot, Vector *pActualDotPosition, float *pHomingSpeed ); + virtual int AugerHealth() { return m_iMaxHealth - 20; } + + // Creates the smoke trail + void CreateSmokeTrail( void ); + + // Gets the shooting position + void GetShootPosition( CLaserDot *pLaserDot, Vector *pShootPosition ); + + CHandle m_hRocketTrail; + float m_flAugerTime; // Amount of time to auger before blowing up anyway + float m_flMarkDeadTime; + float m_flDamage; + + struct CustomDetonator_t + { + EHANDLE hEntity; + float radiusSq; + float halfHeight; + }; + + static CUtlVector gm_CustomDetonators; + +private: + float m_flGracePeriodEndsAt; + bool m_bCreateDangerSounds; + + DECLARE_DATADESC(); +}; + + +//----------------------------------------------------------------------------- +// Laser dot control +//----------------------------------------------------------------------------- +CBaseEntity *CreateLaserDot( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot ); +void SetLaserDotTarget( CBaseEntity *pLaserDot, CBaseEntity *pTarget ); +void EnableLaserDot( CBaseEntity *pLaserDot, bool bEnable ); + + +//----------------------------------------------------------------------------- +// Specialized mizzizzile +//----------------------------------------------------------------------------- +class CAPCMissile : public CMissile +{ + DECLARE_CLASS( CMissile, CMissile ); + DECLARE_DATADESC(); + +public: + static CAPCMissile *Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, CBaseEntity *pOwner ); + + CAPCMissile(); + ~CAPCMissile(); + void IgniteDelay( void ); + void AugerDelay( float flDelayTime ); + void ExplodeDelay( float flDelayTime ); + void DisableGuiding(); +#if defined( HL2_DLL ) + virtual Class_T Classify ( void ) { return CLASS_COMBINE; } +#endif + + void AimAtSpecificTarget( CBaseEntity *pTarget ); + void SetGuidanceHint( const char *pHintName ); + + void APCSeekThink( void ); + + CAPCMissile *m_pNext; + +protected: + virtual void DoExplosion(); + virtual void ComputeActualDotPosition( CLaserDot *pLaserDot, Vector *pActualDotPosition, float *pHomingSpeed ); + virtual int AugerHealth(); + +private: + void Init(); + void ComputeLeadingPosition( const Vector &vecShootPosition, CBaseEntity *pTarget, Vector *pLeadPosition ); + void BeginSeekThink(); + void AugerStartThink(); + void ExplodeThink(); + void APCMissileTouch( CBaseEntity *pOther ); + + float m_flReachedTargetTime; + float m_flIgnitionTime; + bool m_bGuidingDisabled; + float m_flLastHomingSpeed; + EHANDLE m_hSpecificTarget; + string_t m_strHint; +}; + + +//----------------------------------------------------------------------------- +// Finds apc missiles in cone +//----------------------------------------------------------------------------- +CAPCMissile *FindAPCMissileInCone( const Vector &vecOrigin, const Vector &vecDirection, float flAngle ); + + +//----------------------------------------------------------------------------- +// RPG +//----------------------------------------------------------------------------- +class CWeaponRPG : public CBaseHLCombatWeapon +{ + DECLARE_CLASS( CWeaponRPG, CBaseHLCombatWeapon ); +public: + + CWeaponRPG(); + ~CWeaponRPG(); + + DECLARE_SERVERCLASS(); + + void Precache( void ); + + void PrimaryAttack( void ); + virtual float GetFireRate( void ) { return 1; }; + void ItemPostFrame( void ); + + void Activate( void ); + void DecrementAmmo( CBaseCombatCharacter *pOwner ); + + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + bool Reload( void ); + bool WeaponShouldBeLowered( void ); + bool Lower( void ); + + virtual void Drop( const Vector &vecVelocity ); + + int GetMinBurst() { return 1; } + int GetMaxBurst() { return 1; } + float GetMinRestTime() { return 4.0; } + float GetMaxRestTime() { return 4.0; } + + bool WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + int WeaponRangeAttack1Condition( float flDot, float flDist ); + + void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + void StartGuiding( void ); + void StopGuiding( void ); + void ToggleGuiding( void ); + bool IsGuiding( void ); + + void NotifyRocketDied( void ); + + bool HasAnyAmmo( void ); + + void SuppressGuiding( bool state = true ); + + void CreateLaserPointer( void ); + void UpdateLaserPosition( Vector vecMuzzlePos = vec3_origin, Vector vecEndPos = vec3_origin ); + Vector GetLaserPosition( void ); + void StartLaserEffects( void ); + void StopLaserEffects( void ); + void UpdateLaserEffects( void ); + + // NPC RPG users cheat and directly set the laser pointer's origin + void UpdateNPCLaserPosition( const Vector &vecTarget ); + void SetNPCLaserPosition( const Vector &vecTarget ); + const Vector &GetNPCLaserPosition( void ); + + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + + virtual const Vector& GetBulletSpread( void ) + { + static Vector cone = VECTOR_CONE_3DEGREES; + return cone; + } + + CBaseEntity *GetMissile( void ) { return m_hMissile; } + + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); + +protected: + + bool m_bInitialStateUpdate; + bool m_bGuiding; + bool m_bHideGuiding; //User to override the player's wish to guide under certain circumstances + Vector m_vecNPCLaserDot; + CHandle m_hLaserDot; + CHandle m_hMissile; + CHandle m_hLaserMuzzleSprite; + CHandle m_hLaserBeam; +}; + +#endif // WEAPON_RPG_H diff --git a/game/server/hl2/weapon_slam.h b/game/server/hl2/weapon_slam.h new file mode 100644 index 0000000..8c0b473 --- /dev/null +++ b/game/server/hl2/weapon_slam.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: SLAM +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONSLAM_H +#define WEAPONSLAM_H +#ifndef HL2MP + +#include "basegrenade_shared.h" +#include "basehlcombatweapon.h" + +enum SlamState_t +{ + SLAM_TRIPMINE_READY, + SLAM_SATCHEL_THROW, + SLAM_SATCHEL_ATTACH, +}; + +class CWeapon_SLAM : public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CWeapon_SLAM, CBaseHLCombatWeapon ); + + DECLARE_SERVERCLASS(); + + SlamState_t m_tSlamState; + bool m_bDetonatorArmed; + bool m_bNeedDetonatorDraw; + bool m_bNeedDetonatorHolster; + bool m_bNeedReload; + bool m_bClearReload; + bool m_bThrowSatchel; + bool m_bAttachSatchel; + bool m_bAttachTripmine; + float m_flWallSwitchTime; + + void Spawn( void ); + void Precache( void ); + + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + void WeaponSwitch( void ); + void SLAMThink( void ); + + void SetPickupTouch( void ); + void SlamTouch( CBaseEntity *pOther ); // default weapon touch + void ItemPostFrame( void ); + bool Reload( void ); + void SetSlamState( SlamState_t newState ); + bool CanAttachSLAM(void); // In position where can attach SLAM? + bool AnyUndetonatedCharges(void); + void StartTripmineAttach( void ); + void TripmineAttach( void ); + + void StartSatchelDetonate( void ); + void SatchelDetonate( void ); + void StartSatchelThrow( void ); + void StartSatchelAttach( void ); + void SatchelThrow( void ); + void SatchelAttach( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + + CWeapon_SLAM(); + + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); +}; + +#endif //HL2MP +#endif //WEAPONSLAM_H diff --git a/game/server/hl2/weapon_stunstick.h b/game/server/hl2/weapon_stunstick.h new file mode 100644 index 0000000..901b472 --- /dev/null +++ b/game/server/hl2/weapon_stunstick.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_STUNSTICK_H +#define WEAPON_STUNSTICK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basebludgeonweapon.h" + +#define STUNSTICK_RANGE 75.0f +#define STUNSTICK_REFIRE 0.6f + +class CWeaponStunStick : public CBaseHLBludgeonWeapon +{ + DECLARE_CLASS( CWeaponStunStick, CBaseHLBludgeonWeapon ); + DECLARE_DATADESC(); + +public: + + CWeaponStunStick(); + + DECLARE_SERVERCLASS(); + DECLARE_ACTTABLE(); + + virtual void Precache(); + + void Spawn(); + + float GetRange( void ) { return STUNSTICK_RANGE; } + float GetFireRate( void ) { return STUNSTICK_REFIRE; } + + int WeaponMeleeAttack1Condition( float flDot, float flDist ); + + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + void Drop( const Vector &vecVelocity ); + void ImpactEffect( trace_t &traceHit ); + void SecondaryAttack( void ) {} + void SetStunState( bool state ); + bool GetStunState( void ); + void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + + float GetDamageForActivity( Activity hitActivity ); + + bool CanBePickedUpByNPCs( void ) { return false; } + +private: + + CNetworkVar( bool, m_bActive ); +}; + +#endif // WEAPON_STUNSTICK_H diff --git a/game/server/hl2/weapon_tripwire.h b/game/server/hl2/weapon_tripwire.h new file mode 100644 index 0000000..9ecde01 --- /dev/null +++ b/game/server/hl2/weapon_tripwire.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TRIPWIRE +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONTRIPWIRE_H +#define WEAPONTRIPWIRE_H + +#include "basegrenade_shared.h" +#include "basehlcombatweapon.h" + +enum TripwireState_t +{ + TRIPWIRE_TRIPMINE_READY, + TRIPWIRE_SATCHEL_THROW, + TRIPWIRE_SATCHEL_ATTACH, +}; + +class CWeapon_Tripwire : public CBaseHLCombatWeapon +{ +public: + DECLARE_CLASS( CWeapon_Tripwire, CBaseHLCombatWeapon ); + + DECLARE_SERVERCLASS(); + + bool m_bNeedReload; + bool m_bClearReload; + bool m_bAttachTripwire; + + void Spawn( void ); + void Precache( void ); + + int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + void WeaponSwitch( void ); + + void SetPickupTouch( void ); + void TripwireTouch( CBaseEntity *pOther ); // default weapon touch + void ItemPostFrame( void ); + bool Reload( void ); + bool CanAttachTripwire(void); // In position where can attach TRIPWIRE? + void StartTripwireAttach( void ); + void TripwireAttach( void ); + + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + + CWeapon_Tripwire(); + + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); +}; + + +#endif //WEAPONTRIPWIRE_H diff --git a/game/server/hl2mp/grenade_satchel.h b/game/server/hl2mp/grenade_satchel.h new file mode 100644 index 0000000..68d5d5a --- /dev/null +++ b/game/server/hl2mp/grenade_satchel.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Satchel Charge +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SATCHEL_H +#define SATCHEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" +#include "hl2mp/weapon_slam.h" + +class CSoundPatch; +class CSprite; + +class CSatchelCharge : public CBaseGrenade +{ +public: + DECLARE_CLASS( CSatchelCharge, CBaseGrenade ); + + void Spawn( void ); + void Precache( void ); + void BounceSound( void ); + void SatchelTouch( CBaseEntity *pOther ); + void SatchelThink( void ); + + // Input handlers + void InputExplode( inputdata_t &inputdata ); + + float m_flNextBounceSoundTime; + bool m_bInAir; + Vector m_vLastPosition; + +public: + CWeapon_SLAM* m_pMyWeaponSLAM; // Who shot me.. + bool m_bIsAttached; + void Deactivate( void ); + + CSatchelCharge(); + ~CSatchelCharge(); + + DECLARE_DATADESC(); + +private: + void CreateEffects( void ); + CHandle m_hGlowSprite; +}; + +#endif //SATCHEL_H diff --git a/game/server/hl2mp/grenade_tripmine.h b/game/server/hl2mp/grenade_tripmine.h new file mode 100644 index 0000000..e188709 --- /dev/null +++ b/game/server/hl2mp/grenade_tripmine.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GRENADE_TRIPMINE_H +#define GRENADE_TRIPMINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" + +class CBeam; + + +class CTripmineGrenade : public CBaseGrenade +{ +public: + DECLARE_CLASS( CTripmineGrenade, CBaseGrenade ); + + CTripmineGrenade(); + void Spawn( void ); + void Precache( void ); + +#if 0 // FIXME: OnTakeDamage_Alive() is no longer called now that base grenade derives from CBaseAnimating + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); +#endif + void WarningThink( void ); + void PowerupThink( void ); + void BeamBreakThink( void ); + void DelayDeathThink( void ); + void Event_Killed( const CTakeDamageInfo &info ); + + void MakeBeam( void ); + void KillBeam( void ); + +public: + EHANDLE m_hOwner; + +private: + float m_flPowerUp; + Vector m_vecDir; + Vector m_vecEnd; + float m_flBeamLength; + + CBeam *m_pBeam; + Vector m_posOwner; + Vector m_angleOwner; + + DECLARE_DATADESC(); +}; + +#endif // GRENADE_TRIPMINE_H diff --git a/game/server/hl2mp/hl2mp_bot_temp.h b/game/server/hl2mp/hl2mp_bot_temp.h new file mode 100644 index 0000000..f78e63e --- /dev/null +++ b/game/server/hl2mp/hl2mp_bot_temp.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef BOT_BASE_H +#define BOT_BASE_H +#ifdef _WIN32 +#pragma once +#endif + + +// If iTeam or iClass is -1, then a team or class is randomly chosen. +CBasePlayer *BotPutInServer( bool bFrozen, int iTeam ); + + +#endif // BOT_BASE_H + diff --git a/game/server/hl2mp/hl2mp_cvars.h b/game/server/hl2mp/hl2mp_cvars.h new file mode 100644 index 0000000..4baf52f --- /dev/null +++ b/game/server/hl2mp/hl2mp_cvars.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL2MP_CVARS_H +#define HL2MP_CVARS_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAX_INTERMISSION_TIME 120 + +extern ConVar mp_restartround; +extern ConVar mp_readyrestart; +extern ConVar mp_ready_signal; + +#endif //HL2MP_CVARS_H \ No newline at end of file diff --git a/game/server/hl2mp/hl2mp_gameinterface.h b/game/server/hl2mp/hl2mp_gameinterface.h new file mode 100644 index 0000000..4955e46 --- /dev/null +++ b/game/server/hl2mp/hl2mp_gameinterface.h @@ -0,0 +1,10 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef HL2MP_GAMEINTERFACE_H +#define HL2MP_GAMEINTERFACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "gameinterface.h" + +#endif \ No newline at end of file diff --git a/game/server/hl2mp/hl2mp_player.h b/game/server/hl2mp/hl2mp_player.h new file mode 100644 index 0000000..f91513c --- /dev/null +++ b/game/server/hl2mp/hl2mp_player.h @@ -0,0 +1,176 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef HL2MP_PLAYER_H +#define HL2MP_PLAYER_H +#pragma once + +class CHL2MP_Player; + +#include "basemultiplayerplayer.h" +#include "hl2_playerlocaldata.h" +#include "hl2_player.h" +#include "simtimer.h" +#include "soundenvelope.h" +#include "hl2mp_player_shared.h" +#include "hl2mp_gamerules.h" +#include "utldict.h" + +//============================================================================= +// >> HL2MP_Player +//============================================================================= +class CHL2MPPlayerStateInfo +{ +public: + HL2MPPlayerState m_iPlayerState; + const char *m_pStateName; + + void (CHL2MP_Player::*pfnEnterState)(); // Init and deinit the state. + void (CHL2MP_Player::*pfnLeaveState)(); + + void (CHL2MP_Player::*pfnPreThink)(); // Do a PreThink() in this state. +}; + +class CHL2MP_Player : public CHL2_Player +{ +public: + DECLARE_CLASS( CHL2MP_Player, CHL2_Player ); + + CHL2MP_Player(); + ~CHL2MP_Player( void ); + + static CHL2MP_Player *CreatePlayer( const char *className, edict_t *ed ) + { + CHL2MP_Player::s_PlayerEdict = ed; + return (CHL2MP_Player*)CreateEntityByName( className ); + } + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + virtual void Precache( void ); + virtual void Spawn( void ); + virtual void PostThink( void ); + virtual void PreThink( void ); + virtual void PlayerDeathThink( void ); + virtual void SetAnimation( PLAYER_ANIM playerAnim ); + virtual bool HandleCommand_JoinTeam( int team ); + virtual bool ClientCommand( const CCommand &args ); + virtual void CreateViewModel( int viewmodelindex = 0 ); + virtual bool BecomeRagdollOnClient( const Vector &force ); + virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual int OnTakeDamage( const CTakeDamageInfo &inputInfo ); + virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec *pEntityTransmitBits ) const; + virtual void FireBullets ( const FireBulletsInfo_t &info ); + virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0); + virtual bool BumpWeapon( CBaseCombatWeapon *pWeapon ); + virtual void ChangeTeam( int iTeam ); + virtual void PickupObject ( CBaseEntity *pObject, bool bLimitMassAndSize ); + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); + virtual void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL ); + virtual void UpdateOnRemove( void ); + virtual void DeathSound( const CTakeDamageInfo &info ); + virtual CBaseEntity* EntSelectSpawnPoint( void ); + + int FlashlightIsOn( void ); + void FlashlightTurnOn( void ); + void FlashlightTurnOff( void ); + void PrecacheFootStepSounds( void ); + bool ValidatePlayerModel( const char *pModel ); + + QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles.Get(); } + + Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL ); + + void CheatImpulseCommands( int iImpulse ); + void CreateRagdollEntity( void ); + void GiveAllItems( void ); + void GiveDefaultItems( void ); + + void NoteWeaponFired( void ); + + void ResetAnimation( void ); + void SetPlayerModel( void ); + void SetPlayerTeamModel( void ); + Activity TranslateTeamActivity( Activity ActToTranslate ); + + float GetNextModelChangeTime( void ) { return m_flNextModelChangeTime; } + float GetNextTeamChangeTime( void ) { return m_flNextTeamChangeTime; } + void PickDefaultSpawnTeam( void ); + void SetupPlayerSoundsByModel( const char *pModelName ); + const char *GetPlayerModelSoundPrefix( void ); + int GetPlayerModelType( void ) { return m_iPlayerSoundType; } + + void DetonateTripmines( void ); + + void Reset(); + + bool IsReady(); + void SetReady( bool bReady ); + + void CheckChatText( char *p, int bufsize ); + + void State_Transition( HL2MPPlayerState newState ); + void State_Enter( HL2MPPlayerState newState ); + void State_Leave(); + void State_PreThink(); + CHL2MPPlayerStateInfo *State_LookupInfo( HL2MPPlayerState state ); + + void State_Enter_ACTIVE(); + void State_PreThink_ACTIVE(); + void State_Enter_OBSERVER_MODE(); + void State_PreThink_OBSERVER_MODE(); + + + virtual bool StartObserverMode( int mode ); + virtual void StopObserverMode( void ); + + + Vector m_vecTotalBulletForce; //Accumulator for bullet force in a single frame + + // Tracks our ragdoll entity. + CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle + + virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer ); + + +private: + + CNetworkQAngle( m_angEyeAngles ); + CPlayerAnimState m_PlayerAnimState; + + int m_iLastWeaponFireUsercmd; + int m_iModelType; + CNetworkVar( int, m_iSpawnInterpCounter ); + CNetworkVar( int, m_iPlayerSoundType ); + + float m_flNextModelChangeTime; + float m_flNextTeamChangeTime; + + float m_flSlamProtectTime; + + HL2MPPlayerState m_iPlayerState; + CHL2MPPlayerStateInfo *m_pCurStateInfo; + + bool ShouldRunRateLimitedCommand( const CCommand &args ); + + // This lets us rate limit the commands the players can execute so they don't overflow things like reliable buffers. + CUtlDict m_RateLimitLastCommandTimes; + + bool m_bEnterObserver; + bool m_bReady; +}; + +inline CHL2MP_Player *ToHL2MPPlayer( CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + + return dynamic_cast( pEntity ); +} + +#endif //HL2MP_PLAYER_H diff --git a/game/server/hl2mp/te_hl2mp_shotgun_shot.h b/game/server/hl2mp/te_hl2mp_shotgun_shot.h new file mode 100644 index 0000000..d6a6833 --- /dev/null +++ b/game/server/hl2mp/te_hl2mp_shotgun_shot.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TE_HL2MP_SHOTGUN_SHOT_H +#define TE_HL2MP_SHOTGUN_SHOT_H +#ifdef _WIN32 +#pragma once +#endif + + +void TE_HL2MPFireBullets( + int iPlayerIndex, + const Vector &vOrigin, + const Vector &vDir, + int iAmmoID, + int iSeed, + int iShots, + float flSpread, + bool bDoTracers, + bool bDoImpacts ); + + +#endif // TE_HL2MP_SHOTGUN_SHOT_H diff --git a/game/server/hltvdirector.h b/game/server/hltvdirector.h new file mode 100644 index 0000000..653bf1d --- /dev/null +++ b/game/server/hltvdirector.h @@ -0,0 +1,124 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HLTVDIRECTOR_H +#define HLTVDIRECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "GameEventListener.h" +#include +#include +#include +#include + +#define HLTV_MIN_DIRECTOR_DELAY 10 // minimum delay if director is enabled +#define HLTV_MAX_DELAY 120 // maximum delay + + +#define MAX_NUM_CAMERAS 64 // support up to 64 fixed cameras per level + +#define MIN_SHOT_LENGTH 4.0f // minimum time of a cut (seconds) +#define MAX_SHOT_LENGTH 8.0f // maximum time of a cut (seconds) +#define DEF_SHOT_LENGTH 6.0f // average time of a cut (seconds) + +class CHLTVGameEvent +{ +public: + int m_Tick; // tick of this command + int m_Priority; // game event priority + IGameEvent *m_Event; // IGameEvent +}; + +class CHLTVDirector : public CGameEventListener, public CBaseGameSystemPerFrame, public IHLTVDirector +{ +public: + DECLARE_CLASS_NOBASE( CHLTVDirector ); + + virtual char const *Name() { return "CHLTVDirector"; } + + CHLTVDirector(); + virtual ~CHLTVDirector(); + + virtual void SetHLTVServer( IHLTVServer *hltv ); // give the director an HLTV interface + IHLTVServer* GetHLTVServer( void ); + int GetDirectorTick( void ); // get current broadcast tick from director + int GetPVSEntity( void ); // get current view entity (PVS) + Vector GetPVSOrigin( void ); // get current PVS origin, if PVS entity is 0 + float GetDelay( void ); // returns current delay in seconds + bool IsActive( void ); + + virtual const char** GetModEvents(); // returns list of event names forwarded to HLTV clients + + void BuildCameraList( void ); + + +public: // IGameEventListener Interface + virtual void FireGameEvent( IGameEvent * event ); + +public: // CBaseGameSystem overrides + + virtual bool Init(); + virtual void Shutdown(); + virtual void FrameUpdatePostEntityThink(); + virtual void LevelInitPostEntity(); + virtual char *GetFixedCameraEntityName( void ) { return "point_viewcontrol"; } + + bool SetCameraMan( int iPlayerIndex ); + int GetCameraMan() { return m_iCameraManIndex; } + + +protected: + + virtual void StartNewShot(); + virtual void StartRandomShot(); + virtual void StartDelayMessage(); + virtual void StartBestFixedCameraShot(bool bForce); + virtual void StartBestPlayerCameraShot(); + virtual void StartFixedCameraShot(int iCamera, int iTarget); + virtual void StartChaseCameraShot(int iTarget1, int iTarget2, int distance, int phi, int theta, bool bInEye); + virtual void UpdateSettings(); + virtual void AnalyzePlayers(); + virtual void AnalyzeCameras(); + virtual bool StartCameraManShot(); + virtual void StartInstantBroadcastShot(); + virtual void FinishCameraManShot(); + virtual void BuildActivePlayerList(); + virtual CHLTVGameEvent *FindBestGameEvent(); + virtual void CreateShotFromEvent( CHLTVGameEvent *ge ); + + int FindFirstEvent( int tick ); // finds first event >= tick + void CheckHistory(); + void RemoveEventsFromHistory(int tick); // removes all commands < tick, or all if tick -1 + + IHLTVServer *m_pHLTVServer; // interface to servers HLTV object + float m_fDelay; // hltv delay in seconds + int m_nBroadcastTick; // world time that is currently "on the air" + int m_iPVSEntity; // entity for PVS center + Vector m_vPVSOrigin; // PVS origin if PVS entity is 0 + int m_iCameraMan; // >0 if current view entity is a cameraman + CBasePlayer *m_pHLTVClient; // the HLTV fake client + int m_nNextShotTick; // time for the next scene cut + int m_iLastPlayer; // last player in random rotation + + int m_nNextAnalyzeTick; + + int m_nNumFixedCameras; //number of cameras in current map + CBaseEntity *m_pFixedCameras[MAX_NUM_CAMERAS]; // fixed cameras (point_viewcontrol) + + int m_nNumActivePlayers; //number of cameras in current map + CBasePlayer *m_pActivePlayers[MAX_PLAYERS]; // fixed cameras (point_viewcontrol) + int m_iCameraManIndex; // entity index of current camera man or 0 + + CUtlRBTree m_EventHistory; +}; + +extern IGameSystem* HLTVDirectorSystem(); +extern CHLTVDirector* HLTVDirector(); + +#endif // HLTVDIRECTOR_H diff --git a/game/server/ilagcompensationmanager.h b/game/server/ilagcompensationmanager.h new file mode 100644 index 0000000..b874904 --- /dev/null +++ b/game/server/ilagcompensationmanager.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ILAGCOMPENSATIONMANAGER_H +#define ILAGCOMPENSATIONMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +class CBasePlayer; +class CUserCmd; + +//----------------------------------------------------------------------------- +// Purpose: This is also an IServerSystem +//----------------------------------------------------------------------------- +abstract_class ILagCompensationManager +{ +public: + // Called during player movement to set up/restore after lag compensation + virtual void StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) = 0; + virtual void FinishLagCompensation( CBasePlayer *player ) = 0; + virtual bool IsCurrentlyDoingLagCompensation() const = 0; +}; + +extern ILagCompensationManager *lagcompensation; + +#endif // ILAGCOMPENSATIONMANAGER_H diff --git a/game/server/info_camera_link.h b/game/server/info_camera_link.h new file mode 100644 index 0000000..592e4f5 --- /dev/null +++ b/game/server/info_camera_link.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef INFO_CAMERA_LINK_H +#define INFO_CAMERA_LINK_H + +#include "baseentity.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CPointCamera; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseEntity *CreateInfoCameraLink( CBaseEntity *pTarget, CPointCamera *pCamera ); + + +//----------------------------------------------------------------------------- +// Sets up visibility +//----------------------------------------------------------------------------- +void PointCameraSetupVisibility( CBaseEntity *pPlayer, int area, unsigned char *pvs, int pvssize ); + + + +#endif // INFO_CAMERA_LINK_H + diff --git a/game/server/init_factory.h b/game/server/init_factory.h new file mode 100644 index 0000000..1cbc95c --- /dev/null +++ b/game/server/init_factory.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef INIT_FACTORY_H +#define INIT_FACTORY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "interface.h" + +struct factorylist_t +{ + CreateInterfaceFn engineFactory; + CreateInterfaceFn physicsFactory; + CreateInterfaceFn fileSystemFactory; +}; + +// Store off the factories +void FactoryList_Store( const factorylist_t &sourceData ); + +// retrieve the stored factories +void FactoryList_Retrieve( factorylist_t &destData ); + +#endif // INIT_FACTORY_H diff --git a/game/server/iscorer.h b/game/server/iscorer.h new file mode 100644 index 0000000..efaf2ef --- /dev/null +++ b/game/server/iscorer.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Interface that entities can use to redirect scoring to other entities. +// i.e. A rocket redirects scoring to the player that fired it. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISCORER_H +#define ISCORER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Interface that entities can use to redirect scoring to other entities. +// i.e. A rocket redirects scoring to the player that fired it. +//----------------------------------------------------------------------------- +abstract_class IScorer +{ +public: + // Return the entity that should receive the score + virtual CBasePlayer *GetScorer( void ) = 0; + // Return the entity that should get assistance credit + virtual CBasePlayer *GetAssistant( void ) = 0; +}; + + +#endif // ISCORER_H diff --git a/game/server/iservervehicle.h b/game/server/iservervehicle.h new file mode 100644 index 0000000..60be008 --- /dev/null +++ b/game/server/iservervehicle.h @@ -0,0 +1,139 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISERVERVEHICLE_H +#define ISERVERVEHICLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "IVehicle.h" +#include "vphysics/vehicles.h" + +class CBaseEntity; +class CBasePlayer; +class CBaseCombatCharacter; +class CNPC_VehicleDriver; +enum VehicleSeatQuery_e; + +// This is used by the player to access vehicles. It's an interface so the +// vehicles are not restricted in what they can derive from. +abstract_class IServerVehicle : public IVehicle +{ +public: + // Get the entity associated with the vehicle. + virtual CBaseEntity* GetVehicleEnt() = 0; + + // Get and set the current driver. Use PassengerRole_t enum in shareddefs.h for adding passengers + virtual void SetPassenger( int nRole, CBaseCombatCharacter *pPassenger ) = 0; + + // Is the player visible while in the vehicle? (this is a constant the vehicle) + virtual bool IsPassengerVisible( int nRole = VEHICLE_ROLE_DRIVER ) = 0; + + // Can a given passenger take damage? + virtual bool IsPassengerDamagable( int nRole = VEHICLE_ROLE_DRIVER ) = 0; + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) = 0; + + // Is the vehicle upright? + virtual bool IsVehicleUpright( void ) = 0; + + // Whether or not we're in a transitional phase + virtual bool IsPassengerEntering( void ) = 0; + virtual bool IsPassengerExiting( void ) = 0; + + // Get a position in *world space* inside the vehicle for the player to start at + virtual void GetPassengerSeatPoint( int nRole, Vector *pPoint, QAngle *pAngles ) = 0; + + virtual void HandlePassengerEntry( CBaseCombatCharacter *pPassenger, bool bAllowEntryOutsideZone = false ) = 0; + virtual bool HandlePassengerExit( CBaseCombatCharacter *pPassenger ) = 0; + + // Get a point in *world space* to leave the vehicle from (may be in solid) + virtual bool GetPassengerExitPoint( int nRole, Vector *pPoint, QAngle *pAngles ) = 0; + virtual int GetEntryAnimForPoint( const Vector &vecPoint ) = 0; + virtual int GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked ) = 0; + virtual void HandleEntryExitFinish( bool bExitAnimOn, bool bResetAnim ) = 0; + + virtual Class_T ClassifyPassenger( CBaseCombatCharacter *pPassenger, Class_T defaultClassification ) = 0; + virtual float PassengerDamageModifier( const CTakeDamageInfo &info ) = 0; + + // Get me the parameters for this vehicle + virtual const vehicleparams_t *GetVehicleParams( void ) = 0; + // If I'm a physics vehicle, get the controller + virtual IPhysicsVehicleController *GetVehicleController() = 0; + + virtual int NPC_GetAvailableSeat( CBaseCombatCharacter *pPassenger, string_t strRoleName, VehicleSeatQuery_e nQueryType ) = 0; + virtual bool NPC_AddPassenger( CBaseCombatCharacter *pPassenger, string_t strRoleName, int nSeat ) = 0; + virtual bool NPC_RemovePassenger( CBaseCombatCharacter *pPassenger ) = 0; + virtual bool NPC_GetPassengerSeatPosition( CBaseCombatCharacter *pPassenger, Vector *vecResultPos, QAngle *vecResultAngle ) = 0; + virtual bool NPC_GetPassengerSeatPositionLocal( CBaseCombatCharacter *pPassenger, Vector *vecResultPos, QAngle *vecResultAngle ) = 0; + virtual int NPC_GetPassengerSeatAttachment( CBaseCombatCharacter *pPassenger ) = 0; + virtual bool NPC_HasAvailableSeat( string_t strRoleName ) = 0; + + virtual const PassengerSeatAnims_t *NPC_GetPassengerSeatAnims( CBaseCombatCharacter *pPassenger, PassengerSeatAnimType_t nType ) = 0; + virtual CBaseCombatCharacter *NPC_GetPassengerInSeat( int nRoleID, int nSeatID ) = 0; + + virtual void RestorePassengerInfo( void ) = 0; + + // NPC Driving + virtual bool NPC_CanDrive( void ) = 0; + virtual void NPC_SetDriver( CNPC_VehicleDriver *pDriver ) = 0; + virtual void NPC_DriveVehicle( void ) = 0; + virtual void NPC_ThrottleCenter( void ) = 0; + virtual void NPC_ThrottleReverse( void ) = 0; + virtual void NPC_ThrottleForward( void ) = 0; + virtual void NPC_Brake( void ) = 0; + virtual void NPC_TurnLeft( float flDegrees ) = 0; + virtual void NPC_TurnRight( float flDegrees ) = 0; + virtual void NPC_TurnCenter( void ) = 0; + virtual void NPC_PrimaryFire( void ) = 0; + virtual void NPC_SecondaryFire( void ) = 0; + virtual bool NPC_HasPrimaryWeapon( void ) = 0; + virtual bool NPC_HasSecondaryWeapon( void ) = 0; + virtual void NPC_AimPrimaryWeapon( Vector vecTarget ) = 0; + virtual void NPC_AimSecondaryWeapon( Vector vecTarget ) = 0; + + // Weapon handling + virtual void Weapon_PrimaryRanges( float *flMinRange, float *flMaxRange ) = 0; + virtual void Weapon_SecondaryRanges( float *flMinRange, float *flMaxRange ) = 0; + virtual float Weapon_PrimaryCanFireAt( void ) = 0; // Return the time at which this vehicle's primary weapon can fire again + virtual float Weapon_SecondaryCanFireAt( void ) = 0; // Return the time at which this vehicle's secondary weapon can fire again + + // debugging, script file flushed + virtual void ReloadScript() = 0; +}; + +// This is an interface to derive from if your class contains an IServerVehicle +// handler (i.e. something derived CBaseServerVehicle. +abstract_class IDrivableVehicle +{ +public: + virtual CBaseEntity *GetDriver( void ) = 0; + + // Process movement + virtual void ItemPostFrame( CBasePlayer *pPlayer ) = 0; + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) = 0; + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ) = 0; + virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) = 0; + + // Entering / Exiting + virtual bool CanEnterVehicle( CBaseEntity *pEntity ) = 0; + virtual bool CanExitVehicle( CBaseEntity *pEntity ) = 0; + virtual void SetVehicleEntryAnim( bool bOn ) = 0; + virtual void SetVehicleExitAnim( bool bOn, Vector vecEyeExitEndpoint ) = 0; + virtual void EnterVehicle( CBaseCombatCharacter *pPassenger ) = 0; + + virtual void PreExitVehicle( CBaseCombatCharacter *pPassenger, int nRole ) = 0; + virtual void ExitVehicle( int nRole ) = 0; + virtual bool AllowBlockedExit( CBaseCombatCharacter *pPassenger, int nRole ) = 0; + virtual bool AllowMidairExit( CBaseCombatCharacter *pPassenger, int nRole ) = 0; + virtual string_t GetVehicleScriptName() = 0; + + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) = 0; +}; + +#endif // IVEHICLE_H diff --git a/game/server/items.h b/game/server/items.h new file mode 100644 index 0000000..bc1bb77 --- /dev/null +++ b/game/server/items.h @@ -0,0 +1,98 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ITEMS_H +#define ITEMS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "entityoutput.h" +#include "player_pickup.h" +#include "vphysics/constraints.h" + + +// Armor given by a battery +#define MAX_NORMAL_BATTERY 100 + +// Ammo counts given by ammo items +#define SIZE_AMMO_PISTOL 20 +#define SIZE_AMMO_PISTOL_LARGE 100 +#define SIZE_AMMO_SMG1 45 +#define SIZE_AMMO_SMG1_LARGE 225 +#define SIZE_AMMO_AR2 20 +#define SIZE_AMMO_AR2_LARGE 100 +#define SIZE_AMMO_RPG_ROUND 1 +#define SIZE_AMMO_SMG1_GRENADE 1 +#define SIZE_AMMO_BUCKSHOT 20 +#define SIZE_AMMO_357 6 +#define SIZE_AMMO_357_LARGE 20 +#define SIZE_AMMO_CROSSBOW 6 +#define SIZE_AMMO_AR2_ALTFIRE 1 + +#define SF_ITEM_START_CONSTRAINED 0x00000001 + + +class CItem : public CBaseAnimating, public CDefaultPlayerPickupVPhysics +{ +public: + DECLARE_CLASS( CItem, CBaseAnimating ); + + CItem(); + + virtual void Spawn( void ); + virtual void Precache(); + + unsigned int PhysicsSolidMaskForEntity( void ) const; + + virtual CBaseEntity* Respawn( void ); + virtual void ItemTouch( CBaseEntity *pOther ); + virtual void Materialize( void ); + virtual bool MyTouch( CBasePlayer *pPlayer ) { return false; }; + + // Become touchable when we are at rest + virtual void OnEntityEvent( EntityEvent_t event, void *pEventData ); + + // Activate when at rest, but don't allow pickup until then + void ActivateWhenAtRest( float flTime = 0.5f ); + + // IPlayerPickupVPhysics + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); + + virtual int ObjectCaps() { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE | FCAP_WCEDIT_POSITION; }; + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + Vector GetOriginalSpawnOrigin( void ) { return m_vOriginalSpawnOrigin; } + QAngle GetOriginalSpawnAngles( void ) { return m_vOriginalSpawnAngles; } + void SetOriginalSpawnOrigin( const Vector& origin ) { m_vOriginalSpawnOrigin = origin; } + void SetOriginalSpawnAngles( const QAngle& angles ) { m_vOriginalSpawnAngles = angles; } + bool CreateItemVPhysicsObject( void ); + virtual bool ItemCanBeTouchedByPlayer( CBasePlayer *pPlayer ); + +#if defined( HL2MP ) || defined( TF_DLL ) + void FallThink( void ); + float m_flNextResetCheckTime; +#endif + + DECLARE_DATADESC(); +protected: + virtual void ComeToRest( void ); + bool m_bActivateWhenAtRest; + +private: + + COutputEvent m_OnPlayerTouch; + COutputEvent m_OnCacheInteraction; + + Vector m_vOriginalSpawnOrigin; + QAngle m_vOriginalSpawnAngles; + + IPhysicsConstraint *m_pConstraint; +}; + +#endif // ITEMS_H diff --git a/game/server/lights.h b/game/server/lights.h new file mode 100644 index 0000000..5b937cd --- /dev/null +++ b/game/server/lights.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef LIGHTS_H +#define LIGHTS_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CLight : public CPointEntity +{ +public: + DECLARE_CLASS( CLight, CPointEntity ); + + bool KeyValue( const char *szKeyName, const char *szValue ); + void Spawn( void ); + void FadeThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + void TurnOn( void ); + void TurnOff( void ); + void Toggle( void ); + + // Input handlers + void InputSetPattern( inputdata_t &inputdata ); + void InputFadeToPattern( inputdata_t &inputdata ); + + void InputToggle( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + +private: + int m_iStyle; + int m_iDefaultStyle; + string_t m_iszPattern; + char m_iCurrentFade; + char m_iTargetFade; +}; + +#endif // LIGHTS_H diff --git a/game/server/locksounds.h b/game/server/locksounds.h new file mode 100644 index 0000000..c70b4c5 --- /dev/null +++ b/game/server/locksounds.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines a structure common to buttons and doors for playing locked +// and unlocked sounds. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef LOCKSOUNDS_H +#define LOCKSOUNDS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamap.h" + + +struct locksound_t // sounds that doors and buttons make when locked/unlocked +{ + DECLARE_DATADESC(); + + string_t sLockedSound; // sound a door makes when it's locked + string_t sLockedSentence; // sentence group played when door is locked + string_t sUnlockedSound; // sound a door makes when it's unlocked + string_t sUnlockedSentence; // sentence group played when door is unlocked + + int iLockedSentence; // which sentence in sentence group to play next + int iUnlockedSentence; // which sentence in sentence group to play next + + float flwaitSound; // time delay between playing consecutive 'locked/unlocked' sounds + float flwaitSentence; // time delay between playing consecutive sentences + byte bEOFLocked; // true if hit end of list of locked sentences + byte bEOFUnlocked; // true if hit end of list of unlocked sentences +}; + + +#endif // LOCKSOUNDS_H diff --git a/game/server/logicrelay.h b/game/server/logicrelay.h new file mode 100644 index 0000000..8d082ac --- /dev/null +++ b/game/server/logicrelay.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef LOGICRELAY_H +#define LOGICRELAY_H + +#include "cbase.h" +#include "entityinput.h" +#include "entityoutput.h" +#include "eventqueue.h" + +class CLogicRelay : public CLogicalEntity +{ +public: + DECLARE_CLASS( CLogicRelay, CLogicalEntity ); + + CLogicRelay(); + + void Activate(); + void Think(); + + // Input handlers + void InputEnable( inputdata_t &inputdata ); + void InputEnableRefire( inputdata_t &inputdata ); // Private input handler, not in FGD + void InputDisable( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + void InputTrigger( inputdata_t &inputdata ); + void InputCancelPending( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + + // Outputs + COutputEvent m_OnTrigger; + COutputEvent m_OnSpawn; + + bool IsDisabled( void ){ return m_bDisabled; } + +private: + + bool m_bDisabled; + bool m_bWaitForRefire; // Set to disallow a refire while we are waiting for our outputs to finish firing. +}; + +#endif //LOGICRELAY_H diff --git a/game/server/mapentities.h b/game/server/mapentities.h new file mode 100644 index 0000000..d8fa428 --- /dev/null +++ b/game/server/mapentities.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MAPENTITIES_H +#define MAPENTITIES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mapentities_shared.h" + +// This class provides hooks into the map-entity loading process that allows CS to do some tricks +// when restarting the round. The main trick it tries to do is recreate all +abstract_class IMapEntityFilter +{ +public: + virtual bool ShouldCreateEntity( const char *pClassname ) = 0; + virtual CBaseEntity* CreateNextEntity( const char *pClassname ) = 0; +}; + +// Use the filter so you can prevent certain entities from being created out of the map. +// CSPort does this when restarting rounds. It wants to reload most entities from the map, but certain +// entities like the world entity need to be left intact. +void MapEntity_ParseAllEntities( const char *pMapData, IMapEntityFilter *pFilter=NULL, bool bActivateEntities=false ); + +const char *MapEntity_ParseEntity( CBaseEntity *&pEntity, const char *pEntData, IMapEntityFilter *pFilter ); +void MapEntity_PrecacheEntity( const char *pEntData, int &nStringSize ); + + +//----------------------------------------------------------------------------- +// Hierarchical spawn +//----------------------------------------------------------------------------- +struct HierarchicalSpawn_t +{ + CBaseEntity *m_pEntity; + int m_nDepth; + CBaseEntity *m_pDeferredParent; // attachment parents can't be set until the parents are spawned + const char *m_pDeferredParentAttachment; // so defer setting them up until the second pass +}; + +void SpawnHierarchicalList( int nEntities, HierarchicalSpawn_t *pSpawnList, bool bActivateEntities ); + +#endif // MAPENTITIES_H diff --git a/game/server/maprules.h b/game/server/maprules.h new file mode 100644 index 0000000..7a4b155 --- /dev/null +++ b/game/server/maprules.h @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef MAPRULES_H +#define MAPRULES_H + + + +#endif // MAPRULES_H + diff --git a/game/server/modelentities.h b/game/server/modelentities.h new file mode 100644 index 0000000..36cf5a7 --- /dev/null +++ b/game/server/modelentities.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MODELENTITIES_H +#define MODELENTITIES_H +#ifdef _WIN32 +#pragma once +#endif + +//!! replace this with generic start enabled/disabled +#define SF_WALL_START_OFF 0x0001 +#define SF_IGNORE_PLAYERUSE 0x0002 + +//----------------------------------------------------------------------------- +// Purpose: basic solid geometry +// enabled state: brush is visible +// disabled state: brush not visible +//----------------------------------------------------------------------------- +class CFuncBrush : public CBaseEntity +{ +public: + DECLARE_CLASS( CFuncBrush, CBaseEntity ); + + virtual void Spawn( void ); + bool CreateVPhysics( void ); + + virtual int ObjectCaps( void ) { return HasSpawnFlags(SF_IGNORE_PLAYERUSE) ? BaseClass::ObjectCaps() : BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; } + + virtual int DrawDebugTextOverlays( void ); + + virtual void TurnOff( void ); + virtual void TurnOn( void ); + + // Input handlers + void InputTurnOff( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + void InputSetExcluded( inputdata_t &inputdata ); + void InputSetInvert( inputdata_t &inputdata ); + + enum BrushSolidities_e { + BRUSHSOLID_TOGGLE = 0, + BRUSHSOLID_NEVER = 1, + BRUSHSOLID_ALWAYS = 2, + }; + + BrushSolidities_e m_iSolidity; + int m_iDisabled; + bool m_bSolidBsp; + string_t m_iszExcludedClass; + bool m_bInvertExclusion; + + DECLARE_DATADESC(); + + virtual bool IsOn( void ) const; +}; + + +#endif // MODELENTITIES_H diff --git a/game/server/monstermaker.h b/game/server/monstermaker.h new file mode 100644 index 0000000..e866662 --- /dev/null +++ b/game/server/monstermaker.h @@ -0,0 +1,184 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MONSTERMAKER_H +#define MONSTERMAKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" + + +//----------------------------------------------------------------------------- +// Spawnflags +//----------------------------------------------------------------------------- +#define SF_NPCMAKER_START_ON 1 // start active ( if has targetname ) +#define SF_NPCMAKER_NPCCLIP 8 // Children are blocked by NPCclip +#define SF_NPCMAKER_FADE 16 // Children's corpses fade +#define SF_NPCMAKER_INF_CHILD 32 // Infinite number of children +#define SF_NPCMAKER_NO_DROP 64 // Do not adjust for the ground's position when checking for spawn +#define SF_NPCMAKER_HIDEFROMPLAYER 128 // Don't spawn if the player's looking at me +#define SF_NPCMAKER_ALWAYSUSERADIUS 256 // Use radius spawn whenever spawning +#define SF_NPCMAKER_NOPRELOADMODELS 512 // Suppress preloading into the cache of all referenced .mdl files + +//========================================================= +//========================================================= +class CNPCSpawnDestination : public CPointEntity +{ + DECLARE_CLASS( CNPCSpawnDestination, CPointEntity ); + +public: + CNPCSpawnDestination(); + bool IsAvailable(); // Is this spawn destination available for selection? + void OnSpawnedNPC( CAI_BaseNPC *pNPC ); // Notify this spawn destination that an NPC has spawned here. + + float m_ReuseDelay; // How long to be unavailable after being selected + string_t m_RenameNPC; // If not NULL, rename the NPC that spawns here to this. + float m_TimeNextAvailable;// The time at which this destination will be available again. + + COutputEvent m_OnSpawnNPC; + + DECLARE_DATADESC(); +}; + +abstract_class CBaseNPCMaker : public CBaseEntity +{ +public: + DECLARE_CLASS( CBaseNPCMaker, CBaseEntity ); + + void Spawn( void ); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + void MakerThink( void ); + bool HumanHullFits( const Vector &vecLocation ); + bool CanMakeNPC( bool bIgnoreSolidEntities = false ); + + virtual void DeathNotice( CBaseEntity *pChild );// NPC maker children use this to tell the NPC maker that they have died. + virtual void MakeNPC( void ) = 0; + + virtual void ChildPreSpawn( CAI_BaseNPC *pChild ) {}; + virtual void ChildPostSpawn( CAI_BaseNPC *pChild ); + + CBaseNPCMaker(void) {} + + // Input handlers + void InputSpawnNPC( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + void InputSetMaxChildren( inputdata_t &inputdata ); + void InputAddMaxChildren( inputdata_t &inputdata ); + void InputSetMaxLiveChildren( inputdata_t &inputdata ); + void InputSetSpawnFrequency( inputdata_t &inputdata ); + + // State changers + void Toggle( void ); + virtual void Enable( void ); + virtual void Disable( void ); + + virtual bool IsDepleted( void ); + + DECLARE_DATADESC(); + + int m_nMaxNumNPCs; // max number of NPCs this ent can create + float m_flSpawnFrequency; // delay (in secs) between spawns + + COutputEHANDLE m_OnSpawnNPC; + COutputEvent m_OnAllSpawned; + COutputEvent m_OnAllSpawnedDead; + COutputEvent m_OnAllLiveChildrenDead; + + int m_nLiveChildren; // how many NPCs made by this NPC maker that are currently alive + int m_nMaxLiveChildren; // max number of NPCs that this maker may have out at one time. + + bool m_bDisabled; + + EHANDLE m_hIgnoreEntity; + string_t m_iszIngoreEnt; +}; + + +class CNPCMaker : public CBaseNPCMaker +{ +public: + DECLARE_CLASS( CNPCMaker, CBaseNPCMaker ); + + CNPCMaker( void ); + + void Precache( void ); + + virtual void MakeNPC( void ); + + DECLARE_DATADESC(); + + string_t m_iszNPCClassname; // classname of the NPC(s) that will be created. + string_t m_SquadName; + string_t m_strHintGroup; + string_t m_spawnEquipment; + string_t m_RelationshipString; // Used to load up relationship keyvalues + string_t m_ChildTargetName; +}; + +class CTemplateNPCMaker : public CBaseNPCMaker +{ +public: + DECLARE_CLASS( CTemplateNPCMaker, CBaseNPCMaker ); + + CTemplateNPCMaker( void ) + { + m_iMinSpawnDistance = 0; + } + + virtual void Precache(); + + virtual CNPCSpawnDestination *FindSpawnDestination(); + virtual void MakeNPC( void ); + void MakeNPCInRadius( void ); + void MakeNPCInLine( void ); + virtual void MakeMultipleNPCS( int nNPCs ); + +protected: + virtual void PrecacheTemplateEntity( CBaseEntity *pEntity ); + + bool PlaceNPCInRadius( CAI_BaseNPC *pNPC ); + bool PlaceNPCInLine( CAI_BaseNPC *pNPC ); + + // Inputs + void InputSpawnInRadius( inputdata_t &inputdata ) { MakeNPCInRadius(); } + void InputSpawnInLine( inputdata_t &inputdata ) { MakeNPCInLine(); } + void InputSpawnMultiple( inputdata_t &inputdata ); + void InputChangeDestinationGroup( inputdata_t &inputdata ); + void InputSetMinimumSpawnDistance( inputdata_t &inputdata ); + + float m_flRadius; + + DECLARE_DATADESC(); + + string_t m_iszTemplateName; // The name of the NPC that will be used as the template. + string_t m_iszTemplateData; // The keyvalue data blob from the template NPC that will be used to spawn new ones. + string_t m_iszDestinationGroup; + + int m_iMinSpawnDistance; + + enum ThreeStateYesNo_t + { + TS_YN_YES = 0, + TS_YN_NO, + TS_YN_DONT_CARE, + }; + + enum ThreeStateDist_t + { + TS_DIST_NEAREST = 0, + TS_DIST_FARTHEST, + TS_DIST_DONT_CARE, + }; + + ThreeStateYesNo_t m_CriterionVisibility; + ThreeStateDist_t m_CriterionDistance; +}; + +#endif // MONSTERMAKER_H diff --git a/game/server/movehelper_server.h b/game/server/movehelper_server.h new file mode 100644 index 0000000..a203f77 --- /dev/null +++ b/game/server/movehelper_server.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MOVEHELPER_SERVER_H +#define MOVEHELPER_SERVER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "imovehelper.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +class CBasePlayer; +class CBaseEntity; + + +//----------------------------------------------------------------------------- +// Implementation of the movehelper on the server +//----------------------------------------------------------------------------- + +abstract_class IMoveHelperServer : public IMoveHelper +{ +public: + virtual void SetHost( CBasePlayer *host ) = 0; +}; + +//----------------------------------------------------------------------------- +// Singleton access +//----------------------------------------------------------------------------- + +IMoveHelperServer* MoveHelperServer(); + + +#endif // MOVEHELPER_SERVER_H diff --git a/game/server/movie_explosion.h b/game/server/movie_explosion.h new file mode 100644 index 0000000..4cd19c0 --- /dev/null +++ b/game/server/movie_explosion.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef MOVIE_EXPLOSION_H +#define MOVIE_EXPLOSION_H + + +#include "baseparticleentity.h" + + +class MovieExplosion : public CBaseParticleEntity +{ +public: + DECLARE_CLASS( MovieExplosion, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + static MovieExplosion* CreateMovieExplosion(const Vector &pos); +}; + + +#endif + + diff --git a/game/server/nav.h b/game/server/nav.h new file mode 100644 index 0000000..a955c3a --- /dev/null +++ b/game/server/nav.h @@ -0,0 +1,498 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// nav.h +// Data structures and constants for the Navigation Mesh system +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +#ifndef _NAV_H_ +#define _NAV_H_ + +#include "modelentities.h" // for CFuncBrush +#include "doors.h" + +/** + * Below are several constants used by the navigation system. + * @todo Move these into TheNavMesh singleton. + */ +const float GenerationStepSize = 25.0f; // (30) was 20, but bots can't fit always fit +const float JumpHeight = 41.8f; // if delta Z is less than this, we can jump up on it + +#if defined(CSTRIKE_DLL) +const float JumpCrouchHeight = 58.0f; // (48) if delta Z is less than or equal to this, we can jumpcrouch up on it +#else +const float JumpCrouchHeight = 64.0f; // (48) if delta Z is less than or equal to this, we can jumpcrouch up on it +#endif + +// There are 3 different definitions of StepHeight throughout the code, waiting to produce bugs if the 18.0 is ever changed. +const float StepHeight = 18.0f; // if delta Z is greater than this, we have to jump to get up + +// TERROR: Increased DeathDrop from 200, since zombies don't take falling damage +#if defined(CSTRIKE_DLL) +const float DeathDrop = 200.0f; // (300) distance at which we will die if we fall - should be about 600, and pay attention to fall damage during pathfind +#else +const float DeathDrop = 400.0f; // (300) distance at which we will die if we fall - should be about 600, and pay attention to fall damage during pathfind +#endif + +#if defined(CSTRIKE_DLL) +const float ClimbUpHeight = JumpCrouchHeight; // CSBots assume all jump up links are reachable +#else +const float ClimbUpHeight = 200.0f; // height to check for climbing up +#endif + +const float CliffHeight = 300.0f; // height which we consider a significant cliff which we would not want to fall off of + +// TERROR: Converted these values to use the same numbers as the player bounding boxes etc +#define HalfHumanWidth 16 +#define HalfHumanHeight 35.5 +#define HumanHeight 71 +#define HumanEyeHeight 62 +#define HumanCrouchHeight 55 +#define HumanCrouchEyeHeight 37 + + +#define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files + +/** + * A place is a named group of navigation areas + */ +typedef unsigned int Place; +#define UNDEFINED_PLACE 0 // ie: "no place" +#define ANY_PLACE 0xFFFF + +enum NavErrorType +{ + NAV_OK, + NAV_CANT_ACCESS_FILE, + NAV_INVALID_FILE, + NAV_BAD_FILE_VERSION, + NAV_FILE_OUT_OF_DATE, + NAV_CORRUPT_DATA, + NAV_OUT_OF_MEMORY, +}; + +enum NavAttributeType +{ + NAV_MESH_INVALID = 0, + NAV_MESH_CROUCH = 0x00000001, // must crouch to use this node/area + NAV_MESH_JUMP = 0x00000002, // must jump to traverse this area (only used during generation) + NAV_MESH_PRECISE = 0x00000004, // do not adjust for obstacles, just move along area + NAV_MESH_NO_JUMP = 0x00000008, // inhibit discontinuity jumping + NAV_MESH_STOP = 0x00000010, // must stop when entering this area + NAV_MESH_RUN = 0x00000020, // must run to traverse this area + NAV_MESH_WALK = 0x00000040, // must walk to traverse this area + NAV_MESH_AVOID = 0x00000080, // avoid this area unless alternatives are too dangerous + NAV_MESH_TRANSIENT = 0x00000100, // area may become blocked, and should be periodically checked + NAV_MESH_DONT_HIDE = 0x00000200, // area should not be considered for hiding spot generation + NAV_MESH_STAND = 0x00000400, // bots hiding in this area should stand + NAV_MESH_NO_HOSTAGES = 0x00000800, // hostages shouldn't use this area + NAV_MESH_STAIRS = 0x00001000, // this area represents stairs, do not attempt to climb or jump them - just walk up + NAV_MESH_NO_MERGE = 0x00002000, // don't merge this area with adjacent areas + NAV_MESH_OBSTACLE_TOP = 0x00004000, // this nav area is the climb point on the tip of an obstacle + NAV_MESH_CLIFF = 0x00008000, // this nav area is adjacent to a drop of at least CliffHeight + + NAV_MESH_FIRST_CUSTOM = 0x00010000, // apps may define custom app-specific bits starting with this value + NAV_MESH_LAST_CUSTOM = 0x04000000, // apps must not define custom app-specific bits higher than with this value + + NAV_MESH_FUNC_COST = 0x20000000, // area has designer specified cost controlled by func_nav_cost entities + NAV_MESH_HAS_ELEVATOR = 0x40000000, // area is in an elevator's path + NAV_MESH_NAV_BLOCKER = 0x80000000 // area is blocked by nav blocker ( Alas, needed to hijack a bit in the attributes to get within a cache line [7/24/2008 tom]) +}; + +extern NavAttributeType NameToNavAttribute( const char *name ); + +enum NavDirType +{ + NORTH = 0, + EAST = 1, + SOUTH = 2, + WEST = 3, + + NUM_DIRECTIONS +}; + +/** + * Defines possible ways to move from one area to another + */ +enum NavTraverseType +{ + // NOTE: First 4 directions MUST match NavDirType + GO_NORTH = 0, + GO_EAST, + GO_SOUTH, + GO_WEST, + + GO_LADDER_UP, + GO_LADDER_DOWN, + GO_JUMP, + GO_ELEVATOR_UP, + GO_ELEVATOR_DOWN, + + NUM_TRAVERSE_TYPES +}; + +enum NavCornerType +{ + NORTH_WEST = 0, + NORTH_EAST = 1, + SOUTH_EAST = 2, + SOUTH_WEST = 3, + + NUM_CORNERS +}; + +enum NavRelativeDirType +{ + FORWARD = 0, + RIGHT, + BACKWARD, + LEFT, + UP, + DOWN, + + NUM_RELATIVE_DIRECTIONS +}; + +struct Extent +{ + Vector lo, hi; + + void Init( void ) + { + lo.Init(); + hi.Init(); + } + + void Init( CBaseEntity *entity ) + { + entity->CollisionProp()->WorldSpaceSurroundingBounds( &lo, &hi ); + } + + float SizeX( void ) const { return hi.x - lo.x; } + float SizeY( void ) const { return hi.y - lo.y; } + float SizeZ( void ) const { return hi.z - lo.z; } + float Area( void ) const { return SizeX() * SizeY(); } + + // Increase bounds to contain the given point + void Encompass( const Vector &pos ) + { + for ( int i=0; i<3; ++i ) + { + if ( pos[i] < lo[i] ) + { + lo[i] = pos[i]; + } + else if ( pos[i] > hi[i] ) + { + hi[i] = pos[i]; + } + } + } + + // Increase bounds to contain the given extent + void Encompass( const Extent &extent ) + { + Encompass( extent.lo ); + Encompass( extent.hi ); + } + + // return true if 'pos' is inside of this extent + bool Contains( const Vector &pos ) const + { + return (pos.x >= lo.x && pos.x <= hi.x && + pos.y >= lo.y && pos.y <= hi.y && + pos.z >= lo.z && pos.z <= hi.z); + } + + // return true if this extent overlaps the given one + bool IsOverlapping( const Extent &other ) const + { + return (lo.x <= other.hi.x && hi.x >= other.lo.x && + lo.y <= other.hi.y && hi.y >= other.lo.y && + lo.z <= other.hi.z && hi.z >= other.lo.z); + } + + // return true if this extent completely contains the given one + bool IsEncompassing( const Extent &other, float tolerance = 0.0f ) const + { + return (lo.x <= other.lo.x + tolerance && hi.x >= other.hi.x - tolerance && + lo.y <= other.lo.y + tolerance && hi.y >= other.hi.y - tolerance && + lo.z <= other.lo.z + tolerance && hi.z >= other.hi.z - tolerance); + } +}; + +struct Ray +{ + Vector from, to; +}; + + +class CNavArea; +class CNavNode; + + +//-------------------------------------------------------------------------------------------------------------- +inline NavDirType OppositeDirection( NavDirType dir ) +{ + switch( dir ) + { + case NORTH: return SOUTH; + case SOUTH: return NORTH; + case EAST: return WEST; + case WEST: return EAST; + default: break; + } + + return NORTH; +} + +//-------------------------------------------------------------------------------------------------------------- +inline NavDirType DirectionLeft( NavDirType dir ) +{ + switch( dir ) + { + case NORTH: return WEST; + case SOUTH: return EAST; + case EAST: return NORTH; + case WEST: return SOUTH; + default: break; + } + + return NORTH; +} + +//-------------------------------------------------------------------------------------------------------------- +inline NavDirType DirectionRight( NavDirType dir ) +{ + switch( dir ) + { + case NORTH: return EAST; + case SOUTH: return WEST; + case EAST: return SOUTH; + case WEST: return NORTH; + default: break; + } + + return NORTH; +} + +//-------------------------------------------------------------------------------------------------------------- +inline void AddDirectionVector( Vector *v, NavDirType dir, float amount ) +{ + switch( dir ) + { + case NORTH: v->y -= amount; return; + case SOUTH: v->y += amount; return; + case EAST: v->x += amount; return; + case WEST: v->x -= amount; return; + default: break; + } +} + +//-------------------------------------------------------------------------------------------------------------- +inline float DirectionToAngle( NavDirType dir ) +{ + switch( dir ) + { + case NORTH: return 270.0f; + case SOUTH: return 90.0f; + case EAST: return 0.0f; + case WEST: return 180.0f; + default: break; + } + + return 0.0f; +} + +//-------------------------------------------------------------------------------------------------------------- +inline NavDirType AngleToDirection( float angle ) +{ + while( angle < 0.0f ) + angle += 360.0f; + + while( angle > 360.0f ) + angle -= 360.0f; + + if (angle < 45 || angle > 315) + return EAST; + + if (angle >= 45 && angle < 135) + return SOUTH; + + if (angle >= 135 && angle < 225) + return WEST; + + return NORTH; +} + +//-------------------------------------------------------------------------------------------------------------- +inline void DirectionToVector2D( NavDirType dir, Vector2D *v ) +{ + switch( dir ) + { + default: Assert(0); + case NORTH: v->x = 0.0f; v->y = -1.0f; break; + case SOUTH: v->x = 0.0f; v->y = 1.0f; break; + case EAST: v->x = 1.0f; v->y = 0.0f; break; + case WEST: v->x = -1.0f; v->y = 0.0f; break; + } +} + + +//-------------------------------------------------------------------------------------------------------------- +inline void CornerToVector2D( NavCornerType dir, Vector2D *v ) +{ + switch( dir ) + { + default: Assert(0); + case NORTH_WEST: v->x = -1.0f; v->y = -1.0f; break; + case NORTH_EAST: v->x = 1.0f; v->y = -1.0f; break; + case SOUTH_EAST: v->x = 1.0f; v->y = 1.0f; break; + case SOUTH_WEST: v->x = -1.0f; v->y = 1.0f; break; + } + + v->NormalizeInPlace(); +} + + +//-------------------------------------------------------------------------------------------------------------- +// Gets the corner types that surround the given direction +inline void GetCornerTypesInDirection( NavDirType dir, NavCornerType *first, NavCornerType *second ) +{ + switch ( dir ) + { + default: + Assert(0); + case NORTH: + *first = NORTH_WEST; + *second = NORTH_EAST; + break; + case SOUTH: + *first = SOUTH_WEST; + *second = SOUTH_EAST; + break; + case EAST: + *first = NORTH_EAST; + *second = SOUTH_EAST; + break; + case WEST: + *first = NORTH_WEST; + *second = SOUTH_WEST; + break; + } +} + + +//-------------------------------------------------------------------------------------------------------------- +inline float RoundToUnits( float val, float unit ) +{ + val = val + ((val < 0.0f) ? -unit*0.5f : unit*0.5f); + return (float)( unit * ( ((int)val) / (int)unit ) ); +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Return true if given entity can be ignored when moving + */ +#define WALK_THRU_PROP_DOORS 0x01 +#define WALK_THRU_FUNC_DOORS 0x02 +#define WALK_THRU_DOORS (WALK_THRU_PROP_DOORS | WALK_THRU_FUNC_DOORS) +#define WALK_THRU_BREAKABLES 0x04 +#define WALK_THRU_TOGGLE_BRUSHES 0x08 +#define WALK_THRU_EVERYTHING (WALK_THRU_DOORS | WALK_THRU_BREAKABLES | WALK_THRU_TOGGLE_BRUSHES) +extern ConVar nav_solid_props; +inline bool IsEntityWalkable( CBaseEntity *entity, unsigned int flags ) +{ + if (FClassnameIs( entity, "worldspawn" )) + return false; + + if (FClassnameIs( entity, "player" )) + return false; + + // if we hit a door, assume its walkable because it will open when we touch it + if (FClassnameIs( entity, "func_door*" )) + { +#ifdef PROBLEMATIC // cp_dustbowl doors dont open by touch - they use surrounding triggers + if ( !entity->HasSpawnFlags( SF_DOOR_PTOUCH ) ) + { + // this door is not opened by touching it, if it is closed, the area is blocked + CBaseDoor *door = (CBaseDoor *)entity; + return door->m_toggle_state == TS_AT_TOP; + } +#endif // _DEBUG + + return (flags & WALK_THRU_FUNC_DOORS) ? true : false; + } + + if (FClassnameIs( entity, "prop_door*" )) + { + return (flags & WALK_THRU_PROP_DOORS) ? true : false; + } + + // if we hit a clip brush, ignore it if it is not BRUSHSOLID_ALWAYS + if (FClassnameIs( entity, "func_brush" )) + { + CFuncBrush *brush = (CFuncBrush *)entity; + switch ( brush->m_iSolidity ) + { + case CFuncBrush::BRUSHSOLID_ALWAYS: + return false; + case CFuncBrush::BRUSHSOLID_NEVER: + return true; + case CFuncBrush::BRUSHSOLID_TOGGLE: + return (flags & WALK_THRU_TOGGLE_BRUSHES) ? true : false; + } + } + + // if we hit a breakable object, assume its walkable because we will shoot it when we touch it + if (FClassnameIs( entity, "func_breakable" ) && entity->GetHealth() && entity->m_takedamage == DAMAGE_YES) + return (flags & WALK_THRU_BREAKABLES) ? true : false; + + if (FClassnameIs( entity, "func_breakable_surf" ) && entity->m_takedamage == DAMAGE_YES) + return (flags & WALK_THRU_BREAKABLES) ? true : false; + + if ( FClassnameIs( entity, "func_playerinfected_clip" ) == true ) + return true; + + if ( nav_solid_props.GetBool() && FClassnameIs( entity, "prop_*" ) ) + return true; + + return false; +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Trace filter that ignores players, NPCs, and objects that can be walked through + */ +class CTraceFilterWalkableEntities : public CTraceFilterNoNPCsOrPlayer +{ +public: + CTraceFilterWalkableEntities( const IHandleEntity *passentity, int collisionGroup, unsigned int flags ) + : CTraceFilterNoNPCsOrPlayer( passentity, collisionGroup ), m_flags( flags ) + { + } + + virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + if ( CTraceFilterNoNPCsOrPlayer::ShouldHitEntity(pServerEntity, contentsMask) ) + { + CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); + return ( !IsEntityWalkable( pEntity, m_flags ) ); + } + return false; + } + +private: + unsigned int m_flags; +}; + + +extern bool IsWalkableTraceLineClear( const Vector &from, const Vector &to, unsigned int flags = 0 ); + +#endif // _NAV_H_ diff --git a/game/server/nav_area.h b/game/server/nav_area.h new file mode 100644 index 0000000..0c97a66 --- /dev/null +++ b/game/server/nav_area.h @@ -0,0 +1,1069 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// nav_area.h +// Navigation areas +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +#ifndef _NAV_AREA_H_ +#define _NAV_AREA_H_ + +#include "nav_ladder.h" +#include "tier1/memstack.h" + +// BOTPORT: Clean up relationship between team index and danger storage in nav areas +enum { MAX_NAV_TEAMS = 2 }; + +#ifdef STAGING_ONLY +inline void DebuggerBreakOnNaN_StagingOnly( float val ) +{ + if ( IS_NAN( val ) ) + DebuggerBreak(); +} +#else +#define DebuggerBreakOnNaN_StagingOnly( _val ) +#endif + +class CFuncElevator; +class CFuncNavPrerequisite; +class CFuncNavCost; + +class CNavVectorNoEditAllocator +{ +public: + CNavVectorNoEditAllocator(); + + static void Reset(); + static void *Alloc( size_t nSize ); + static void *Realloc( void *pMem, size_t nSize ); + static void Free( void *pMem ); + static size_t GetSize( void *pMem ); + +private: + static CMemoryStack m_memory; + static void *m_pCurrent; + static int m_nBytesCurrent; +}; + +#if !defined(_X360) +typedef CUtlVectorUltraConservativeAllocator CNavVectorAllocator; +#else +typedef CNavVectorNoEditAllocator CNavVectorAllocator; +#endif + + +//------------------------------------------------------------------------------------------------------------------- +/** + * Functor interface for iteration + */ +class IForEachNavArea +{ +public: + virtual bool Inspect( const CNavArea *area ) = 0; // Invoked once on each area of the iterated set. Return false to stop iterating. + virtual void PostIteration( bool wasCompleteIteration ) { } // Invoked after the iteration has ended. 'wasCompleteIteration' will be true if the entire set was iterated (ie: Inspect() never returned false) +}; + + +//------------------------------------------------------------------------------------------------------------------- +/** + * The NavConnect union is used to refer to connections to areas + */ +struct NavConnect +{ + NavConnect() + { + id = 0; + length = -1; + } + + union + { + unsigned int id; + CNavArea *area; + }; + + mutable float length; + + bool operator==( const NavConnect &other ) const + { + return (area == other.area) ? true : false; + } +}; + +typedef CUtlVectorUltraConservative NavConnectVector; + + +//------------------------------------------------------------------------------------------------------------------- +/** + * The NavLadderConnect union is used to refer to connections to ladders + */ +union NavLadderConnect +{ + unsigned int id; + CNavLadder *ladder; + + bool operator==( const NavLadderConnect &other ) const + { + return (ladder == other.ladder) ? true : false; + } +}; +typedef CUtlVectorUltraConservative NavLadderConnectVector; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * A HidingSpot is a good place for a bot to crouch and wait for enemies + */ +class HidingSpot +{ +public: + virtual ~HidingSpot() { } + + enum + { + IN_COVER = 0x01, // in a corner with good hard cover nearby + GOOD_SNIPER_SPOT = 0x02, // had at least one decent sniping corridor + IDEAL_SNIPER_SPOT = 0x04, // can see either very far, or a large area, or both + EXPOSED = 0x08 // spot in the open, usually on a ledge or cliff + }; + + bool HasGoodCover( void ) const { return (m_flags & IN_COVER) ? true : false; } // return true if hiding spot in in cover + bool IsGoodSniperSpot( void ) const { return (m_flags & GOOD_SNIPER_SPOT) ? true : false; } + bool IsIdealSniperSpot( void ) const { return (m_flags & IDEAL_SNIPER_SPOT) ? true : false; } + bool IsExposed( void ) const { return (m_flags & EXPOSED) ? true : false; } + + int GetFlags( void ) const { return m_flags; } + + void Save( CUtlBuffer &fileBuffer, unsigned int version ) const; + void Load( CUtlBuffer &fileBuffer, unsigned int version ); + NavErrorType PostLoad( void ); + + const Vector &GetPosition( void ) const { return m_pos; } // get the position of the hiding spot + unsigned int GetID( void ) const { return m_id; } + const CNavArea *GetArea( void ) const { return m_area; } // return nav area this hiding spot is within + + void Mark( void ) { m_marker = m_masterMarker; } + bool IsMarked( void ) const { return (m_marker == m_masterMarker) ? true : false; } + static void ChangeMasterMarker( void ) { ++m_masterMarker; } + + +public: + void SetFlags( int flags ) { m_flags |= flags; } // FOR INTERNAL USE ONLY + void SetPosition( const Vector &pos ) { m_pos = pos; } // FOR INTERNAL USE ONLY + +private: + friend class CNavMesh; + friend void ClassifySniperSpot( HidingSpot *spot ); + + HidingSpot( void ); // must use factory to create + + Vector m_pos; // world coordinates of the spot + unsigned int m_id; // this spot's unique ID + unsigned int m_marker; // this spot's unique marker + CNavArea *m_area; // the nav area containing this hiding spot + + unsigned char m_flags; // bit flags + + static unsigned int m_nextID; // used when allocating spot ID's + static unsigned int m_masterMarker; // used to mark spots +}; +typedef CUtlVectorUltraConservative< HidingSpot * > HidingSpotVector; +extern HidingSpotVector TheHidingSpots; + +extern HidingSpot *GetHidingSpotByID( unsigned int id ); + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Stores a pointer to an interesting "spot", and a parametric distance along a path + */ +struct SpotOrder +{ + float t; // parametric distance along ray where this spot first has LOS to our path + union + { + HidingSpot *spot; // the spot to look at + unsigned int id; // spot ID for save/load + }; +}; +typedef CUtlVector< SpotOrder > SpotOrderVector; + +/** + * This struct stores possible path segments thru a CNavArea, and the dangerous spots + * to look at as we traverse that path segment. + */ +struct SpotEncounter +{ + NavConnect from; + NavDirType fromDir; + NavConnect to; + NavDirType toDir; + Ray path; // the path segment + SpotOrderVector spots; // list of spots to look at, in order of occurrence +}; +typedef CUtlVectorUltraConservative< SpotEncounter * > SpotEncounterVector; + + +//------------------------------------------------------------------------------------------------------------------- +/** + * A CNavArea is a rectangular region defining a walkable area in the environment + */ + +class CNavAreaCriticalData +{ +protected: + // --- Begin critical data, which is heavily hit during pathing operations and carefully arranged for cache performance [7/24/2008 tom] --- + + /* 0 */ Vector m_nwCorner; // north-west corner position (2D mins) + /* 12 */ Vector m_seCorner; // south-east corner position (2D maxs) + /* 24 */ float m_invDxCorners; + /* 28 */ float m_invDyCorners; + /* 32 */ float m_neZ; // height of the implicit corner defined by (m_seCorner.x, m_nwCorner.y, m_neZ) + /* 36 */ float m_swZ; // height of the implicit corner defined by (m_nwCorner.x, m_seCorner.y, m_neZ) + /* 40 */ Vector m_center; // centroid of area + + /* 52 */ unsigned char m_playerCount[ MAX_NAV_TEAMS ]; // the number of players currently in this area + + /* 54 */ bool m_isBlocked[ MAX_NAV_TEAMS ]; // if true, some part of the world is preventing movement through this nav area + + /* 56 */ unsigned int m_marker; // used to flag the area as visited + /* 60 */ float m_totalCost; // the distance so far plus an estimate of the distance left + /* 64 */ float m_costSoFar; // distance travelled so far + + /* 68 */ CNavArea *m_nextOpen, *m_prevOpen; // only valid if m_openMarker == m_masterMarker + /* 76 */ unsigned int m_openMarker; // if this equals the current marker value, we are on the open list + + /* 80 */ int m_attributeFlags; // set of attribute bit flags (see NavAttributeType) + + //- connections to adjacent areas ------------------------------------------------------------------- + /* 84 */ NavConnectVector m_connect[ NUM_DIRECTIONS ]; // a list of adjacent areas for each direction + /* 100*/ NavLadderConnectVector m_ladder[ CNavLadder::NUM_LADDER_DIRECTIONS ]; // list of ladders leading up and down from this area + /* 108*/ NavConnectVector m_elevatorAreas; // a list of areas reachable via elevator from this area + + /* 112*/ unsigned int m_nearNavSearchMarker; // used in GetNearestNavArea() + + /* 116*/ CNavArea *m_parent; // the area just prior to this on in the search path + /* 120*/ NavTraverseType m_parentHow; // how we get from parent to us + + /* 124*/ float m_pathLengthSoFar; // length of path so far, needed for limiting pathfind max path length + + /* *************** 360 cache line *************** */ + + /* 128*/ CFuncElevator *m_elevator; // if non-NULL, this area is in an elevator's path. The elevator can transport us vertically to another area. + + // --- End critical data --- +}; + + +class CNavArea : protected CNavAreaCriticalData +{ +public: + DECLARE_CLASS_NOBASE( CNavArea ) + + CNavArea( void ); + virtual ~CNavArea(); + + virtual void OnServerActivate( void ); // (EXTEND) invoked when map is initially loaded + virtual void OnRoundRestart( void ); // (EXTEND) invoked for each area when the round restarts + virtual void OnRoundRestartPreEntity( void ) { } // invoked for each area when the round restarts, but before entities are deleted and recreated + virtual void OnEnter( CBaseCombatCharacter *who, CNavArea *areaJustLeft ) { } // invoked when player enters this area + virtual void OnExit( CBaseCombatCharacter *who, CNavArea *areaJustEntered ) { } // invoked when player exits this area + + virtual void OnDestroyNotify( CNavArea *dead ); // invoked when given area is going away + virtual void OnDestroyNotify( CNavLadder *dead ); // invoked when given ladder is going away + + virtual void OnEditCreateNotify( CNavArea *newArea ) { } // invoked when given area has just been added to the mesh in edit mode + virtual void OnEditDestroyNotify( CNavArea *deadArea ) { } // invoked when given area has just been deleted from the mesh in edit mode + virtual void OnEditDestroyNotify( CNavLadder *deadLadder ) { } // invoked when given ladder has just been deleted from the mesh in edit mode + + virtual void Save( CUtlBuffer &fileBuffer, unsigned int version ) const; // (EXTEND) + virtual NavErrorType Load( CUtlBuffer &fileBuffer, unsigned int version, unsigned int subVersion ); // (EXTEND) + virtual NavErrorType PostLoad( void ); // (EXTEND) invoked after all areas have been loaded - for pointer binding, etc + + virtual void SaveToSelectedSet( KeyValues *areaKey ) const; // (EXTEND) saves attributes for the area to a KeyValues + virtual void RestoreFromSelectedSet( KeyValues *areaKey ); // (EXTEND) restores attributes from a KeyValues + + // for interactively building or generating nav areas + void Build( CNavNode *nwNode, CNavNode *neNode, CNavNode *seNode, CNavNode *swNode ); + void Build( const Vector &corner, const Vector &otherCorner ); + void Build( const Vector &nwCorner, const Vector &neCorner, const Vector &seCorner, const Vector &swCorner ); + + void ConnectTo( CNavArea *area, NavDirType dir ); // connect this area to given area in given direction + void Disconnect( CNavArea *area ); // disconnect this area from given area + + void ConnectTo( CNavLadder *ladder ); // connect this area to given ladder + void Disconnect( CNavLadder *ladder ); // disconnect this area from given ladder + + unsigned int GetID( void ) const { return m_id; } // return this area's unique ID + static void CompressIDs( void ); // re-orders area ID's so they are continuous + unsigned int GetDebugID( void ) const { return m_debugid; } + + void SetAttributes( int bits ) { m_attributeFlags = bits; } + int GetAttributes( void ) const { return m_attributeFlags; } + bool HasAttributes( int bits ) const { return ( m_attributeFlags & bits ) ? true : false; } + void RemoveAttributes( int bits ) { m_attributeFlags &= ( ~bits ); } + + void SetPlace( Place place ) { m_place = place; } // set place descriptor + Place GetPlace( void ) const { return m_place; } // get place descriptor + + void MarkAsBlocked( int teamID, CBaseEntity *blocker, bool bGenerateEvent = true ); // An entity can force a nav area to be blocked + virtual void UpdateBlocked( bool force = false, int teamID = TEAM_ANY ); // Updates the (un)blocked status of the nav area (throttled) + virtual bool IsBlocked( int teamID, bool ignoreNavBlockers = false ) const; + void UnblockArea( int teamID = TEAM_ANY ); // clear blocked status for the given team(s) + + void CheckFloor( CBaseEntity *ignore ); // Checks if there is a floor under the nav area, in case a breakable floor is gone + + void MarkObstacleToAvoid( float obstructionHeight ); + void UpdateAvoidanceObstacles( void ); + bool HasAvoidanceObstacle( float maxObstructionHeight = StepHeight ) const; // is there a large, immobile object obstructing this area + float GetAvoidanceObstacleHeight( void ) const; // returns the maximum height of the obstruction above the ground + +#ifdef NEXT_BOT + bool HasPrerequisite( CBaseCombatCharacter *actor = NULL ) const; // return true if this area has a prerequisite that applies to the given actor + const CUtlVector< CHandle< CFuncNavPrerequisite > > &GetPrerequisiteVector( void ) const; // return vector of prerequisites that must be met before this area can be traversed + void RemoveAllPrerequisites( void ); + void AddPrerequisite( CFuncNavPrerequisite *prereq ); +#endif + + void ClearAllNavCostEntities( void ); // clear set of func_nav_cost entities that affect this area + void AddFuncNavCostEntity( CFuncNavCost *cost ); // add the given func_nav_cost entity to the cost of this area + float ComputeFuncNavCost( CBaseCombatCharacter *who ) const; // return the cost multiplier of this area's func_nav_cost entities for the given actor + bool HasFuncNavAvoid( void ) const; + bool HasFuncNavPrefer( void ) const; + + void CheckWaterLevel( void ); + bool IsUnderwater( void ) const { return m_isUnderwater; } + + bool IsOverlapping( const Vector &pos, float tolerance = 0.0f ) const; // return true if 'pos' is within 2D extents of area. + bool IsOverlapping( const CNavArea *area ) const; // return true if 'area' overlaps our 2D extents + bool IsOverlapping( const Extent &extent ) const; // return true if 'extent' overlaps our 2D extents + bool IsOverlappingX( const CNavArea *area ) const; // return true if 'area' overlaps our X extent + bool IsOverlappingY( const CNavArea *area ) const; // return true if 'area' overlaps our Y extent + inline float GetZ( const Vector * RESTRICT pPos ) const ; // return Z of area at (x,y) of 'pos' + inline float GetZ( const Vector &pos ) const; // return Z of area at (x,y) of 'pos' + float GetZ( float x, float y ) const RESTRICT; // return Z of area at (x,y) of 'pos' + bool Contains( const Vector &pos ) const; // return true if given point is on or above this area, but no others + bool Contains( const CNavArea *area ) const; + bool IsCoplanar( const CNavArea *area ) const; // return true if this area and given area are approximately co-planar + void GetClosestPointOnArea( const Vector * RESTRICT pPos, Vector *close ) const RESTRICT; // return closest point to 'pos' on this area - returned point in 'close' + void GetClosestPointOnArea( const Vector &pos, Vector *close ) const { return GetClosestPointOnArea( &pos, close ); } + float GetDistanceSquaredToPoint( const Vector &pos ) const; // return shortest distance between point and this area + bool IsDegenerate( void ) const; // return true if this area is badly formed + bool IsRoughlySquare( void ) const; // return true if this area is approximately square + bool IsFlat( void ) const; // return true if this area is approximately flat + bool HasNodes( void ) const; + void GetNodes( NavDirType dir, CUtlVector< CNavNode * > *nodes ) const; // build a vector of nodes along the given direction + CNavNode *FindClosestNode( const Vector &pos, NavDirType dir ) const; // returns the closest node along the given edge to the given point + + bool IsContiguous( const CNavArea *other ) const; // return true if the given area and 'other' share a colinear edge (ie: no drop-down or step/jump/climb) + float ComputeAdjacentConnectionHeightChange( const CNavArea *destinationArea ) const; // return height change between edges of adjacent nav areas (not actual underlying ground) + + bool IsEdge( NavDirType dir ) const; // return true if there are no bi-directional links on the given side + + bool IsDamaging( void ) const; // Return true if continuous damage (ie: fire) is in this area + void MarkAsDamaging( float duration ); // Mark this area is damaging for the next 'duration' seconds + + bool IsVisible( const Vector &eye, Vector *visSpot = NULL ) const; // return true if area is visible from the given eyepoint, return visible spot + + int GetAdjacentCount( NavDirType dir ) const { return m_connect[ dir ].Count(); } // return number of connected areas in given direction + CNavArea *GetAdjacentArea( NavDirType dir, int i ) const; // return the i'th adjacent area in the given direction + CNavArea *GetRandomAdjacentArea( NavDirType dir ) const; + void CollectAdjacentAreas( CUtlVector< CNavArea * > *adjVector ) const; // build a vector of all adjacent areas + + const NavConnectVector *GetAdjacentAreas( NavDirType dir ) const { return &m_connect[dir]; } + bool IsConnected( const CNavArea *area, NavDirType dir ) const; // return true if given area is connected in given direction + bool IsConnected( const CNavLadder *ladder, CNavLadder::LadderDirectionType dir ) const; // return true if given ladder is connected in given direction + float ComputeGroundHeightChange( const CNavArea *area ); // compute change in actual ground height from this area to given area + + const NavConnectVector *GetIncomingConnections( NavDirType dir ) const { return &m_incomingConnect[dir]; } // get areas connected TO this area by a ONE-WAY link (ie: we have no connection back to them) + void AddIncomingConnection( CNavArea *source, NavDirType incomingEdgeDir ); + + const NavLadderConnectVector *GetLadders( CNavLadder::LadderDirectionType dir ) const { return &m_ladder[dir]; } + CFuncElevator *GetElevator( void ) const { Assert( !( m_attributeFlags & NAV_MESH_HAS_ELEVATOR ) == (m_elevator == NULL) ); return ( m_attributeFlags & NAV_MESH_HAS_ELEVATOR ) ? m_elevator : NULL; } + const NavConnectVector &GetElevatorAreas( void ) const { return m_elevatorAreas; } // return collection of areas reachable via elevator from this area + + void ComputePortal( const CNavArea *to, NavDirType dir, Vector *center, float *halfWidth ) const; // compute portal to adjacent area + NavDirType ComputeLargestPortal( const CNavArea *to, Vector *center, float *halfWidth ) const; // compute largest portal to adjacent area, returning direction + void ComputeClosestPointInPortal( const CNavArea *to, NavDirType dir, const Vector &fromPos, Vector *closePos ) const; // compute closest point within the "portal" between to adjacent areas + NavDirType ComputeDirection( Vector *point ) const; // return direction from this area to the given point + + //- for hunting algorithm --------------------------------------------------------------------------- + void SetClearedTimestamp( int teamID ); // set this area's "clear" timestamp to now + float GetClearedTimestamp( int teamID ) const; // get time this area was marked "clear" + + //- hiding spots ------------------------------------------------------------------------------------ + const HidingSpotVector *GetHidingSpots( void ) const { return &m_hidingSpots; } + + SpotEncounter *GetSpotEncounter( const CNavArea *from, const CNavArea *to ); // given the areas we are moving between, return the spots we will encounter + int GetSpotEncounterCount( void ) const { return m_spotEncounters.Count(); } + + //- "danger" ---------------------------------------------------------------------------------------- + void IncreaseDanger( int teamID, float amount ); // increase the danger of this area for the given team + float GetDanger( int teamID ); // return the danger of this area (decays over time) + virtual float GetDangerDecayRate( void ) const; // return danger decay rate per second + + //- extents ----------------------------------------------------------------------------------------- + float GetSizeX( void ) const { return m_seCorner.x - m_nwCorner.x; } + float GetSizeY( void ) const { return m_seCorner.y - m_nwCorner.y; } + void GetExtent( Extent *extent ) const; // return a computed extent (XY is in m_nwCorner and m_seCorner, Z is computed) + const Vector &GetCenter( void ) const { return m_center; } + Vector GetRandomPoint( void ) const; + Vector GetCorner( NavCornerType corner ) const; + void SetCorner( NavCornerType corner, const Vector& newPosition ); + void ComputeNormal( Vector *normal, bool alternate = false ) const; // Computes the area's normal based on m_nwCorner. If 'alternate' is specified, m_seCorner is used instead. + void RemoveOrthogonalConnections( NavDirType dir ); + + //- occupy time ------------------------------------------------------------------------------------ + float GetEarliestOccupyTime( int teamID ) const; // returns the minimum time for someone of the given team to reach this spot from their spawn + bool IsBattlefront( void ) const { return m_isBattlefront; } // true if this area is a "battlefront" - where rushing teams initially meet + + //- player counting -------------------------------------------------------------------------------- + void IncrementPlayerCount( int teamID, int entIndex ); // add one player to this area's count + void DecrementPlayerCount( int teamID, int entIndex ); // subtract one player from this area's count + unsigned char GetPlayerCount( int teamID = 0 ) const; // return number of players of given team currently within this area (team of zero means any/all) + + //- lighting ---------------------------------------------------------------------------------------- + float GetLightIntensity( const Vector &pos ) const; // returns a 0..1 light intensity for the given point + float GetLightIntensity( float x, float y ) const; // returns a 0..1 light intensity for the given point + float GetLightIntensity( void ) const; // returns a 0..1 light intensity averaged over the whole area + + //- A* pathfinding algorithm ------------------------------------------------------------------------ + static void MakeNewMarker( void ) { ++m_masterMarker; if (m_masterMarker == 0) m_masterMarker = 1; } + void Mark( void ) { m_marker = m_masterMarker; } + BOOL IsMarked( void ) const { return (m_marker == m_masterMarker) ? true : false; } + + void SetParent( CNavArea *parent, NavTraverseType how = NUM_TRAVERSE_TYPES ) { m_parent = parent; m_parentHow = how; } + CNavArea *GetParent( void ) const { return m_parent; } + NavTraverseType GetParentHow( void ) const { return m_parentHow; } + + bool IsOpen( void ) const; // true if on "open list" + void AddToOpenList( void ); // add to open list in decreasing value order + void AddToOpenListTail( void ); // add to tail of the open list + void UpdateOnOpenList( void ); // a smaller value has been found, update this area on the open list + void RemoveFromOpenList( void ); + static bool IsOpenListEmpty( void ); + static CNavArea *PopOpenList( void ); // remove and return the first element of the open list + + bool IsClosed( void ) const; // true if on "closed list" + void AddToClosedList( void ); // add to the closed list + void RemoveFromClosedList( void ); + + static void ClearSearchLists( void ); // clears the open and closed lists for a new search + + void SetTotalCost( float value ) { DebuggerBreakOnNaN_StagingOnly( value ); Assert( value >= 0.0 && !IS_NAN(value) ); m_totalCost = value; } + float GetTotalCost( void ) const { DebuggerBreakOnNaN_StagingOnly( m_totalCost ); return m_totalCost; } + + void SetCostSoFar( float value ) { DebuggerBreakOnNaN_StagingOnly( value ); Assert( value >= 0.0 && !IS_NAN(value) ); m_costSoFar = value; } + float GetCostSoFar( void ) const { DebuggerBreakOnNaN_StagingOnly( m_costSoFar ); return m_costSoFar; } + + void SetPathLengthSoFar( float value ) { DebuggerBreakOnNaN_StagingOnly( value ); Assert( value >= 0.0 && !IS_NAN(value) ); m_pathLengthSoFar = value; } + float GetPathLengthSoFar( void ) const { DebuggerBreakOnNaN_StagingOnly( m_pathLengthSoFar ); return m_pathLengthSoFar; } + + //- editing ----------------------------------------------------------------------------------------- + virtual void Draw( void ) const; // draw area for debugging & editing + virtual void DrawFilled( int r, int g, int b, int a, float deltaT = 0.1f, bool noDepthTest = true, float margin = 5.0f ) const; // draw area as a filled rect of the given color + virtual void DrawSelectedSet( const Vector &shift ) const; // draw this area as part of a selected set + void DrawDragSelectionSet( Color &dragSelectionSetColor ) const; + void DrawConnectedAreas( void ) const; + void DrawHidingSpots( void ) const; + bool SplitEdit( bool splitAlongX, float splitEdge, CNavArea **outAlpha = NULL, CNavArea **outBeta = NULL ); // split this area into two areas at the given edge + bool MergeEdit( CNavArea *adj ); // merge this area and given adjacent area + bool SpliceEdit( CNavArea *other ); // create a new area between this area and given area + void RaiseCorner( NavCornerType corner, int amount, bool raiseAdjacentCorners = true ); // raise/lower a corner (or all corners if corner == NUM_CORNERS) + void PlaceOnGround( NavCornerType corner, float inset = 0.0f ); // places a corner (or all corners if corner == NUM_CORNERS) on the ground + NavCornerType GetCornerUnderCursor( void ) const; + bool GetCornerHotspot( NavCornerType corner, Vector hotspot[NUM_CORNERS] ) const; // returns true if the corner is under the cursor + void Shift( const Vector &shift ); // shift the nav area + + //- ladders ----------------------------------------------------------------------------------------- + void AddLadderUp( CNavLadder *ladder ); + void AddLadderDown( CNavLadder *ladder ); + + //- generation and analysis ------------------------------------------------------------------------- + virtual void ComputeHidingSpots( void ); // analyze local area neighborhood to find "hiding spots" in this area - for map learning + virtual void ComputeSniperSpots( void ); // analyze local area neighborhood to find "sniper spots" in this area - for map learning + virtual void ComputeSpotEncounters( void ); // compute spot encounter data - for map learning + virtual void ComputeEarliestOccupyTimes( void ); + virtual void CustomAnalysis( bool isIncremental = false ) { } // for game-specific analysis + virtual bool ComputeLighting( void ); // compute 0..1 light intensity at corners and center (requires client via listenserver) + bool TestStairs( void ); // Test an area for being on stairs + virtual bool IsAbleToMergeWith( CNavArea *other ) const; + + virtual void InheritAttributes( CNavArea *first, CNavArea *second = NULL ); + + + //- visibility ------------------------------------------------------------------------------------- + enum VisibilityType + { + NOT_VISIBLE = 0x00, + POTENTIALLY_VISIBLE = 0x01, + COMPLETELY_VISIBLE = 0x02, + }; + + VisibilityType ComputeVisibility( const CNavArea *area, bool isPVSValid, bool bCheckPVS = true, bool *pOutsidePVS = NULL ) const; // do actual line-of-sight traces to determine if any part of given area is visible from this area + void SetupPVS( void ) const; + bool IsInPVS( void ) const; // return true if this area is within the current PVS + + struct AreaBindInfo // for pointer loading and binding + { + union + { + CNavArea *area; + unsigned int id; + }; + + unsigned char attributes; // VisibilityType + + bool operator==( const AreaBindInfo &other ) const + { + return ( area == other.area ); + } + }; + + virtual bool IsEntirelyVisible( const Vector &eye, const CBaseEntity *ignore = NULL ) const; // return true if entire area is visible from given eyepoint (CPU intensive) + virtual bool IsPartiallyVisible( const Vector &eye, const CBaseEntity *ignore = NULL ) const; // return true if any portion of the area is visible from given eyepoint (CPU intensive) + + virtual bool IsPotentiallyVisible( const CNavArea *area ) const; // return true if given area is potentially visible from somewhere in this area (very fast) + virtual bool IsPotentiallyVisibleToTeam( int team ) const; // return true if any portion of this area is visible to anyone on the given team (very fast) + + virtual bool IsCompletelyVisible( const CNavArea *area ) const; // return true if given area is completely visible from somewhere in this area (very fast) + virtual bool IsCompletelyVisibleToTeam( int team ) const; // return true if given area is completely visible from somewhere in this area by someone on the team (very fast) + + //------------------------------------------------------------------------------------- + /** + * Apply the functor to all navigation areas that are potentially + * visible from this area. + */ + template < typename Functor > + bool ForAllPotentiallyVisibleAreas( Functor &func ) + { + int i; + + ++s_nCurrVisTestCounter; + + for ( i=0; im_nVisTestCounter != s_nCurrVisTestCounter ); + area->m_nVisTestCounter = s_nCurrVisTestCounter; + + if ( m_potentiallyVisibleAreas[i].attributes == NOT_VISIBLE ) + continue; + + if ( func( area ) == false ) + return false; + } + + // for each inherited area + if ( !m_inheritVisibilityFrom.area ) + return true; + + CAreaBindInfoArray &inherited = m_inheritVisibilityFrom.area->m_potentiallyVisibleAreas; + + for ( i=0; im_nVisTestCounter == s_nCurrVisTestCounter ) + continue; + + // Theoretically, this shouldn't matter. But, just in case! + inherited[i].area->m_nVisTestCounter = s_nCurrVisTestCounter; + + if ( inherited[i].attributes == NOT_VISIBLE ) + continue; + + if ( func( inherited[i].area ) == false ) + return false; + } + + return true; + } + + //------------------------------------------------------------------------------------- + /** + * Apply the functor to all navigation areas that are + * completely visible from somewhere in this area. + */ + template < typename Functor > + bool ForAllCompletelyVisibleAreas( Functor &func ) + { + int i; + + ++s_nCurrVisTestCounter; + + for ( i=0; im_nVisTestCounter != s_nCurrVisTestCounter ); + area->m_nVisTestCounter = s_nCurrVisTestCounter; + + if ( ( m_potentiallyVisibleAreas[i].attributes & COMPLETELY_VISIBLE ) == 0 ) + continue; + + if ( func( area ) == false ) + return false; + } + + if ( !m_inheritVisibilityFrom.area ) + return true; + + // for each inherited area + CAreaBindInfoArray &inherited = m_inheritVisibilityFrom.area->m_potentiallyVisibleAreas; + + for ( i=0; im_nVisTestCounter == s_nCurrVisTestCounter ) + continue; + + // Theoretically, this shouldn't matter. But, just in case! + inherited[i].area->m_nVisTestCounter = s_nCurrVisTestCounter; + + if ( ( inherited[i].attributes & COMPLETELY_VISIBLE ) == 0 ) + continue; + + if ( func( inherited[i].area ) == false ) + return false; + } + + return true; + } + + +private: + friend class CNavMesh; + friend class CNavLadder; + friend class CCSNavArea; // allow CS load code to complete replace our default load behavior + + static bool m_isReset; // if true, don't bother cleaning up in destructor since everything is going away + + /* + m_nwCorner + nw ne + +-----------+ + | +-->x | + | | | + | v | + | y | + | | + +-----------+ + sw se + m_seCorner + */ + + static unsigned int m_nextID; // used to allocate unique IDs + unsigned int m_id; // unique area ID + unsigned int m_debugid; + + Place m_place; // place descriptor + + CountdownTimer m_blockedTimer; // Throttle checks on our blocked state while blocked + void UpdateBlockedFromNavBlockers( void ); // checks if nav blockers are still blocking the area + + bool m_isUnderwater; // true if the center of the area is underwater + + bool m_isBattlefront; + + float m_avoidanceObstacleHeight; // if nonzero, a prop is obstructing movement through this nav area + CountdownTimer m_avoidanceObstacleTimer; // Throttle checks on our obstructed state while obstructed + + //- for hunting ------------------------------------------------------------------------------------- + float m_clearedTimestamp[ MAX_NAV_TEAMS ]; // time this area was last "cleared" of enemies + + //- "danger" ---------------------------------------------------------------------------------------- + float m_danger[ MAX_NAV_TEAMS ]; // danger of this area, allowing bots to avoid areas where they died in the past - zero is no danger + float m_dangerTimestamp[ MAX_NAV_TEAMS ]; // time when danger value was set - used for decaying + void DecayDanger( void ); + + //- hiding spots ------------------------------------------------------------------------------------ + HidingSpotVector m_hidingSpots; + bool IsHidingSpotCollision( const Vector &pos ) const; // returns true if an existing hiding spot is too close to given position + + //- encounter spots --------------------------------------------------------------------------------- + SpotEncounterVector m_spotEncounters; // list of possible ways to move thru this area, and the spots to look at as we do + void AddSpotEncounters( const CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir ); // add spot encounter data when moving from area to area + + float m_earliestOccupyTime[ MAX_NAV_TEAMS ]; // min time to reach this spot from spawn + +#ifdef DEBUG_AREA_PLAYERCOUNTS + CUtlVector< int > m_playerEntIndices[ MAX_NAV_TEAMS ]; +#endif + + //- lighting ---------------------------------------------------------------------------------------- + float m_lightIntensity[ NUM_CORNERS ]; // 0..1 light intensity at corners + + //- A* pathfinding algorithm ------------------------------------------------------------------------ + static unsigned int m_masterMarker; + + static CNavArea *m_openList; + static CNavArea *m_openListTail; + + //- connections to adjacent areas ------------------------------------------------------------------- + NavConnectVector m_incomingConnect[ NUM_DIRECTIONS ]; // a list of adjacent areas for each direction that connect TO us, but we have no connection back to them + + //--------------------------------------------------------------------------------------------------- + CNavNode *m_node[ NUM_CORNERS ]; // nav nodes at each corner of the area + + void ResetNodes( void ); // nodes are going away as part of an incremental nav generation + void Strip( void ); // remove "analyzed" data from nav area + + void FinishMerge( CNavArea *adjArea ); // recompute internal data once nodes have been adjusted during merge + void MergeAdjacentConnections( CNavArea *adjArea ); // for merging with "adjArea" - pick up all of "adjArea"s connections + void AssignNodes( CNavArea *area ); // assign internal nodes to the given area + + void FinishSplitEdit( CNavArea *newArea, NavDirType ignoreEdge ); // given the portion of the original area, update its internal data + + void CalcDebugID(); + +#ifdef NEXT_BOT + CUtlVector< CHandle< CFuncNavPrerequisite > > m_prerequisiteVector; // list of prerequisites that must be met before this area can be traversed +#endif + + CNavArea *m_prevHash, *m_nextHash; // for hash table in CNavMesh + + void ConnectElevators( void ); // find elevator connections between areas + + int m_damagingTickCount; // this area is damaging through this tick count + + + //- visibility -------------------------------------------------------------------------------------- + void ComputeVisibilityToMesh( void ); // compute visibility to surrounding mesh + void ResetPotentiallyVisibleAreas(); + static void ComputeVisToArea( CNavArea *&pOtherArea ); + +#ifndef _X360 + typedef CUtlVectorConservative CAreaBindInfoArray; // shaves 8 bytes off structure caused by need to support editing +#else + typedef CUtlVector CAreaBindInfoArray; // Need to use this on 360 to support external allocation pattern +#endif + + AreaBindInfo m_inheritVisibilityFrom; // if non-NULL, m_potentiallyVisibleAreas becomes a list of additions and deletions (NOT_VISIBLE) to the list of this area + CAreaBindInfoArray m_potentiallyVisibleAreas; // list of areas potentially visible from inside this area (after PostLoad(), use area portion of union) + bool m_isInheritedFrom; // latch used during visibility inheritance computation + + const CAreaBindInfoArray &ComputeVisibilityDelta( const CNavArea *other ) const; // return a list of the delta between our visibility list and the given adjacent area + + uint32 m_nVisTestCounter; + static uint32 s_nCurrVisTestCounter; + + CUtlVector< CHandle< CFuncNavCost > > m_funcNavCostVector; // active, overlapping cost entities +}; + +typedef CUtlVector< CNavArea * > NavAreaVector; +extern NavAreaVector TheNavAreas; + + +//-------------------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------------- +// +// Inlines +// + +#ifdef NEXT_BOT + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::HasPrerequisite( CBaseCombatCharacter *actor ) const +{ + return m_prerequisiteVector.Count() > 0; +} + +//-------------------------------------------------------------------------------------------------------------- +inline const CUtlVector< CHandle< CFuncNavPrerequisite > > &CNavArea::GetPrerequisiteVector( void ) const +{ + return m_prerequisiteVector; +} + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavArea::RemoveAllPrerequisites( void ) +{ + m_prerequisiteVector.RemoveAll(); +} + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavArea::AddPrerequisite( CFuncNavPrerequisite *prereq ) +{ + if ( m_prerequisiteVector.Find( prereq ) == m_prerequisiteVector.InvalidIndex() ) + { + m_prerequisiteVector.AddToTail( prereq ); + } +} +#endif + +//-------------------------------------------------------------------------------------------------------------- +inline float CNavArea::GetDangerDecayRate( void ) const +{ + // one kill == 1.0, which we will forget about in two minutes + return 1.0f / 120.0f; +} + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::IsDegenerate( void ) const +{ + return (m_nwCorner.x >= m_seCorner.x || m_nwCorner.y >= m_seCorner.y); +} + +//-------------------------------------------------------------------------------------------------------------- +inline CNavArea *CNavArea::GetAdjacentArea( NavDirType dir, int i ) const +{ + if ( ( i < 0 ) || ( i >= m_connect[dir].Count() ) ) + return NULL; + return m_connect[dir][i].area; +} + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::IsOpen( void ) const +{ + return (m_openMarker == m_masterMarker) ? true : false; +} + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::IsOpenListEmpty( void ) +{ + Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL ); + return (m_openList) ? false : true; +} + +//-------------------------------------------------------------------------------------------------------------- +inline CNavArea *CNavArea::PopOpenList( void ) +{ + Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL ); + + if ( m_openList ) + { + CNavArea *area = m_openList; + + // disconnect from list + area->RemoveFromOpenList(); + area->m_prevOpen = NULL; + area->m_nextOpen = NULL; + + Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL ); + + return area; + } + + Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL ); + + return NULL; +} + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::IsClosed( void ) const +{ + if (IsMarked() && !IsOpen()) + return true; + + return false; +} + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavArea::AddToClosedList( void ) +{ + Mark(); +} + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavArea::RemoveFromClosedList( void ) +{ + // since "closed" is defined as visited (marked) and not on open list, do nothing +} + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavArea::SetClearedTimestamp( int teamID ) +{ + m_clearedTimestamp[ teamID % MAX_NAV_TEAMS ] = gpGlobals->curtime; +} + +//-------------------------------------------------------------------------------------------------------------- +inline float CNavArea::GetClearedTimestamp( int teamID ) const +{ + return m_clearedTimestamp[ teamID % MAX_NAV_TEAMS ]; +} + +//-------------------------------------------------------------------------------------------------------------- +inline float CNavArea::GetEarliestOccupyTime( int teamID ) const +{ + return m_earliestOccupyTime[ teamID % MAX_NAV_TEAMS ]; +} + + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::IsDamaging( void ) const +{ + return ( gpGlobals->tickcount <= m_damagingTickCount ); +} + + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavArea::MarkAsDamaging( float duration ) +{ + m_damagingTickCount = gpGlobals->tickcount + TIME_TO_TICKS( duration ); +} + + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::HasAvoidanceObstacle( float maxObstructionHeight ) const +{ + return m_avoidanceObstacleHeight > maxObstructionHeight; +} + + +//-------------------------------------------------------------------------------------------------------------- +inline float CNavArea::GetAvoidanceObstacleHeight( void ) const +{ + return m_avoidanceObstacleHeight; +} + + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavArea::IsVisible( const Vector &eye, Vector *visSpot ) const +{ + Vector corner; + trace_t result; + CTraceFilterNoNPCsOrPlayer traceFilter( NULL, COLLISION_GROUP_NONE ); + const float offset = 0.75f * HumanHeight; + + // check center first + UTIL_TraceLine( eye, GetCenter() + Vector( 0, 0, offset ), MASK_BLOCKLOS_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE, &traceFilter, &result ); + if (result.fraction == 1.0f) + { + // we can see this area + if (visSpot) + { + *visSpot = GetCenter(); + } + return true; + } + + for( int c=0; cz is not used. +*/ +inline float CNavArea::GetZ( const Vector * RESTRICT pos ) const RESTRICT +{ + return GetZ( pos->x, pos->y ); +} + +inline float CNavArea::GetZ( const Vector & pos ) const RESTRICT +{ + return GetZ( pos.x, pos.y ); +} + +//-------------------------------------------------------------------------------------------------------------- +/** +* Return the coordinates of the area's corner. +*/ +inline Vector CNavArea::GetCorner( NavCornerType corner ) const +{ + // @TODO: Confirm compiler does the "right thing" in release builds, or change this function to to take a pointer [2/4/2009 tom] + Vector pos; + + switch( corner ) + { + default: + Assert( false && "GetCorner: Invalid type" ); + case NORTH_WEST: + return m_nwCorner; + + case NORTH_EAST: + pos.x = m_seCorner.x; + pos.y = m_nwCorner.y; + pos.z = m_neZ; + return pos; + + case SOUTH_WEST: + pos.x = m_nwCorner.x; + pos.y = m_seCorner.y; + pos.z = m_swZ; + return pos; + + case SOUTH_EAST: + return m_seCorner; + } +} + + +#endif // _NAV_AREA_H_ diff --git a/game/server/nav_colors.h b/game/server/nav_colors.h new file mode 100644 index 0000000..1d3a8a4 --- /dev/null +++ b/game/server/nav_colors.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +// Colors used for nav editing + +#ifndef NAV_COLORS_H +#define NAV_COLORS_H + +//-------------------------------------------------------------------------------------------------------------- +enum NavEditColor +{ + // Degenerate area colors + NavDegenerateFirstColor = 0, + NavDegenerateSecondColor, + + // Place painting color + NavSamePlaceColor, + NavDifferentPlaceColor, + NavNoPlaceColor, + + // Normal colors + NavSelectedColor, + NavMarkedColor, + NavNormalColor, + NavCornerColor, + NavBlockedByDoorColor, + NavBlockedByFuncNavBlockerColor, + + // Hiding spot colors + NavIdealSniperColor, + NavGoodSniperColor, + NavGoodCoverColor, + NavExposedColor, + NavApproachPointColor, + + // Connector colors + NavConnectedTwoWaysColor, + NavConnectedOneWayColor, + NavConnectedContiguous, + NavConnectedNonContiguous, + + // Editing colors + NavCursorColor, + NavSplitLineColor, + NavCreationColor, + NavInvalidCreationColor, + NavGridColor, + NavDragSelectionColor, + + // Nav attribute colors + NavAttributeCrouchColor, + NavAttributeJumpColor, + NavAttributePreciseColor, + NavAttributeNoJumpColor, + NavAttributeStopColor, + NavAttributeRunColor, + NavAttributeWalkColor, + NavAttributeAvoidColor, + NavAttributeStairColor, +}; + +//-------------------------------------------------------------------------------------------------------------- + +void NavDrawLine( const Vector& from, const Vector& to, NavEditColor navColor ); +void NavDrawTriangle( const Vector& point1, const Vector& point2, const Vector& point3, NavEditColor navColor ); +void NavDrawFilledTriangle( const Vector& point1, const Vector& point2, const Vector& point3, NavEditColor navColor, bool dark ); +void NavDrawHorizontalArrow( const Vector& from, const Vector& to, float width, NavEditColor navColor ); +void NavDrawDashedLine( const Vector& from, const Vector& to, NavEditColor navColor ); +void NavDrawVolume( const Vector &vMin, const Vector &vMax, int zMidline, NavEditColor navColor ); + +//-------------------------------------------------------------------------------------------------------------- + +#endif // NAV_COLORS_H diff --git a/game/server/nav_entities.h b/game/server/nav_entities.h new file mode 100644 index 0000000..4d7576b --- /dev/null +++ b/game/server/nav_entities.h @@ -0,0 +1,130 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// nav_entities.h +// Navigation entities +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +#ifndef NAV_ENTITIES_H +#define NAV_ENTITIES_H + +//----------------------------------------------------------------------------------------------------- +/** + * An entity that modifies pathfinding cost to all areas it overlaps, to allow map designers + * to tell bots to avoid/prefer certain regions. + */ +class CFuncNavCost : public CBaseEntity +{ +public: + DECLARE_DATADESC(); + DECLARE_CLASS( CFuncNavCost, CBaseEntity ); + + virtual void Spawn( void ); + virtual void UpdateOnRemove( void ); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + bool IsEnabled( void ) const { return !m_isDisabled; } + + void CostThink( void ); + + bool IsApplicableTo( CBaseCombatCharacter *who ) const; // Return true if this cost applies to the given actor + + virtual float GetCostMultiplier( CBaseCombatCharacter *who ) const { return 1.0f; } + +protected: + int m_team; + bool m_isDisabled; + string_t m_iszTags; + + static CUtlVector< CHandle< CFuncNavCost > > gm_masterCostVector; + static CountdownTimer gm_dirtyTimer; + void UpdateAllNavCostDecoration( void ); + + CUtlVector< CFmtStr > m_tags; + bool HasTag( const char *groupname ) const; +}; + + +//----------------------------------------------------------------------------------------------------- +class CFuncNavAvoid : public CFuncNavCost +{ +public: + DECLARE_CLASS( CFuncNavAvoid, CFuncNavCost ); + + virtual float GetCostMultiplier( CBaseCombatCharacter *who ) const; // return pathfind cost multiplier for the given actor +}; + + +//----------------------------------------------------------------------------------------------------- +class CFuncNavPrefer : public CFuncNavCost +{ +public: + DECLARE_CLASS( CFuncNavPrefer, CFuncNavCost ); + + virtual float GetCostMultiplier( CBaseCombatCharacter *who ) const; // return pathfind cost multiplier for the given actor +}; + + +//----------------------------------------------------------------------------------------------------- +/** + * An entity that can block/unblock nav areas. This is meant for semi-transient areas that block + * pathfinding but can be ignored for longer-term queries like computing L4D flow distances and + * escape routes. + */ +class CFuncNavBlocker : public CBaseEntity +{ + DECLARE_DATADESC(); + DECLARE_CLASS( CFuncNavBlocker, CBaseEntity ); + +public: + void Spawn(); + virtual void UpdateOnRemove( void ); + + void InputBlockNav( inputdata_t &inputdata ); + void InputUnblockNav( inputdata_t &inputdata ); + + inline bool IsBlockingNav( int teamNumber ) const + { + if ( teamNumber == TEAM_ANY ) + { + bool isBlocked = false; + for ( int i=0; i gm_NavBlockers; + + void BlockNav( void ); + void UnblockNav( void ); + bool m_isBlockingNav[MAX_NAV_TEAMS]; + int m_blockedTeamNumber; + bool m_bDisabled; + Vector m_CachedMins, m_CachedMaxs; + +}; + +#endif // NAV_ENTITIES_H diff --git a/game/server/nav_ladder.h b/game/server/nav_ladder.h new file mode 100644 index 0000000..f5a02b0 --- /dev/null +++ b/game/server/nav_ladder.h @@ -0,0 +1,154 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +// Navigation ladders +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +#ifndef _NAV_LADDER_H_ +#define _NAV_LADDER_H_ + +#include "nav.h" + +class CNavArea; + +//-------------------------------------------------------------------------------------------------------------- +/** + * The NavLadder represents ladders in the Navigation Mesh, and their connections to adjacent NavAreas + * @todo Deal with ladders that allow jumping off to areas in the middle + */ +class CNavLadder +{ +public: + CNavLadder( void ) + { + m_topForwardArea = NULL; + m_topRightArea = NULL; + m_topLeftArea = NULL; + m_topBehindArea = NULL; + m_bottomArea = NULL; + + // set an ID for interactive editing - loads will overwrite this + m_id = m_nextID++; + } + + ~CNavLadder(); + + void OnRoundRestart( void ); ///< invoked when a game round restarts + + void Save( CUtlBuffer &fileBuffer, unsigned int version ) const; + void Load( CUtlBuffer &fileBuffer, unsigned int version ); + + unsigned int GetID( void ) const { return m_id; } ///< return this ladder's unique ID + static void CompressIDs( void ); /// NavLadderVector; + + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavLadder::IsUsableByTeam( int teamNumber ) const +{ + if ( m_ladderEntity.Get() == NULL ) + return true; + + int ladderTeamNumber = m_ladderEntity->GetTeamNumber(); + return ( teamNumber == ladderTeamNumber || ladderTeamNumber == TEAM_UNASSIGNED ); +} + + +//-------------------------------------------------------------------------------------------------------------- +inline CBaseEntity *CNavLadder::GetLadderEntity( void ) const +{ + return m_ladderEntity.Get(); +} + + +//-------------------------------------------------------------------------------------------------------------- +inline NavDirType CNavLadder::GetDir( void ) const +{ + return m_dir; +} + + +//-------------------------------------------------------------------------------------------------------------- +inline const Vector &CNavLadder::GetNormal( void ) const +{ + return m_normal; +} + + +#endif // _NAV_LADDER_H_ diff --git a/game/server/nav_mesh.h b/game/server/nav_mesh.h new file mode 100644 index 0000000..a69cdc0 --- /dev/null +++ b/game/server/nav_mesh.h @@ -0,0 +1,1348 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// nav_mesh.h +// The Navigation Mesh interface +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +// +// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003 +// +// NOTE: The Navigation code uses Doxygen-style comments. If you run Doxygen over this code, it will +// auto-generate documentation. Visit www.doxygen.org to download the system for free. +// + +#ifndef _NAV_MESH_H_ +#define _NAV_MESH_H_ + +#include "utlbuffer.h" +#include "filesystem.h" +#include "GameEventListener.h" + +#include "nav.h" +#include "nav_area.h" +#include "nav_colors.h" + + +class CNavArea; +class CBaseEntity; +class CBreakable; + +extern ConVar nav_edit; +extern ConVar nav_quicksave; +extern ConVar nav_show_approach_points; +extern ConVar nav_show_danger; + +//-------------------------------------------------------------------------------------------------------- +class NavAreaCollector +{ + bool m_checkForDuplicates; +public: + NavAreaCollector( bool checkForDuplicates = false ) + { + m_checkForDuplicates = checkForDuplicates; + } + + bool operator() ( CNavArea *area ) + { + if ( m_checkForDuplicates && m_area.HasElement( area ) ) + return true; + + m_area.AddToTail( area ); + return true; + } + CUtlVector< CNavArea * > m_area; +}; + + +//-------------------------------------------------------------------------------------------------------- +class EditDestroyNotification +{ + CNavArea *m_deadArea; + +public: + EditDestroyNotification( CNavArea *deadArea ) + { + m_deadArea = deadArea; + } + + bool operator()( CBaseCombatCharacter *actor ) + { + actor->OnNavAreaRemoved( m_deadArea ); + return true; + } +}; + + +//-------------------------------------------------------------------------------------------------------- +class NavAttributeClearer +{ +public: + NavAttributeClearer( NavAttributeType attribute ) + { + m_attribute = attribute; + } + + bool operator() ( CNavArea *area ) + { + area->SetAttributes( area->GetAttributes() & (~m_attribute) ); + + return true; + } + + NavAttributeType m_attribute; +}; + + +//-------------------------------------------------------------------------------------------------------- +class NavAttributeSetter +{ +public: + NavAttributeSetter( NavAttributeType attribute ) + { + m_attribute = attribute; + } + + bool operator() ( CNavArea *area ) + { + area->SetAttributes( area->GetAttributes() | m_attribute ); + + return true; + } + + NavAttributeType m_attribute; +}; + + +//-------------------------------------------------------------------------------------------------------- +class NavAttributeToggler +{ +public: + NavAttributeToggler( NavAttributeType attribute ) + { + m_attribute = attribute; + } + + bool operator() ( CNavArea *area ); + + NavAttributeType m_attribute; +}; + + +//-------------------------------------------------------------------------------------------------------- +struct NavAttributeLookup +{ + const char *name; + NavAttributeType attribute; +}; + +extern NavAttributeLookup TheNavAttributeTable[]; + +//-------------------------------------------------------------------------------------------------------- +class SelectOverlappingAreas +{ +public: + bool operator()( CNavArea *area ); +}; + +//-------------------------------------------------------------------------------------------------------- +abstract_class INavAvoidanceObstacle +{ +public: + virtual bool IsPotentiallyAbleToObstructNavAreas( void ) const = 0; // could we at some future time obstruct nav? + virtual float GetNavObstructionHeight( void ) const = 0; // height at which to obstruct nav areas + virtual bool CanObstructNavAreas( void ) const = 0; // can we obstruct nav right this instant? + virtual CBaseEntity *GetObstructingEntity( void ) = 0; + virtual void OnNavMeshLoaded( void ) = 0; +}; + +//-------------------------------------------------------------------------------------------------------- +enum GetNavAreaFlags_t +{ + GETNAVAREA_CHECK_LOS = 0x1, + GETNAVAREA_ALLOW_BLOCKED_AREAS = 0x2, + GETNAVAREA_CHECK_GROUND = 0x4, +}; + + +//-------------------------------------------------------------------------------------------------------- +// for nav mesh visibilty computation +struct NavVisPair_t +{ + void SetPair( CNavArea *pArea1, CNavArea *pArea2 ) + { + int iArea1 = (int)( pArea1 > pArea2 ); + int iArea2 = ( iArea1 + 1 ) % 2; + pAreas[iArea1] = pArea1; + pAreas[iArea2] = pArea2; + } + + CNavArea *pAreas[2]; +}; + + +// for nav mesh visibilty computation +class CVisPairHashFuncs +{ +public: + CVisPairHashFuncs( int ) {} + + bool operator()( const NavVisPair_t &lhs, const NavVisPair_t &rhs ) const + { + return ( lhs.pAreas[0] == rhs.pAreas[0] && lhs.pAreas[1] == rhs.pAreas[1] ); + } + + unsigned int operator()( const NavVisPair_t &item ) const + { + COMPILE_TIME_ASSERT( sizeof(CNavArea *) == 4 ); + int key[2] = { (int)item.pAreas[0] + item.pAreas[1]->GetID(), (int)item.pAreas[1] + item.pAreas[0]->GetID() }; + return Hash8( key ); + } +}; + + +//-------------------------------------------------------------------------------------------------------------- +// +// The 'place directory' is used to save and load places from +// nav files in a size-efficient manner that also allows for the +// order of the place ID's to change without invalidating the +// nav files. +// +// The place directory is stored in the nav file as a list of +// place name strings. Each nav area then contains an index +// into that directory, or zero if no place has been assigned to +// that area. +// +class PlaceDirectory +{ +public: + typedef unsigned short IndexType; // Loaded/Saved as UnsignedShort. Change this and you'll have to version. + + PlaceDirectory( void ); + void Reset( void ); + bool IsKnown( Place place ) const; /// return true if this place is already in the directory + IndexType GetIndex( Place place ) const; /// return the directory index corresponding to this Place (0 = no entry) + void AddPlace( Place place ); /// add the place to the directory if not already known + Place IndexToPlace( IndexType entry ) const; /// given an index, return the Place + void Save( CUtlBuffer &fileBuffer ); /// store the directory + void Load( CUtlBuffer &fileBuffer, int version ); /// load the directory + const CUtlVector< Place > *GetPlaces( void ) const + { + return &m_directory; + } + + bool HasUnnamedPlaces( void ) const + { + return m_hasUnnamedAreas; + } + + +private: + CUtlVector< Place > m_directory; + bool m_hasUnnamedAreas; +}; + +extern PlaceDirectory placeDirectory; + + + +//-------------------------------------------------------------------------------------------------------- +/** + * The CNavMesh is the global interface to the Navigation Mesh. + * @todo Make this an abstract base class interface, and derive mod-specific implementations. + */ +class CNavMesh : public CGameEventListener +{ +public: + CNavMesh( void ); + virtual ~CNavMesh(); + + virtual void PreLoadAreas( int nAreas ) {} + virtual CNavArea *CreateArea( void ) const; // CNavArea factory + virtual void DestroyArea( CNavArea * ) const; + virtual HidingSpot *CreateHidingSpot( void ) const; // Hiding Spot factory + + virtual void Reset( void ); // destroy Navigation Mesh data and revert to initial state + virtual void Update( void ); // invoked on each game frame + + virtual void FireGameEvent( IGameEvent *event ); // incoming event processing + + virtual NavErrorType Load( void ); // load navigation data from a file + virtual NavErrorType PostLoad( unsigned int version ); // (EXTEND) invoked after all areas have been loaded - for pointer binding, etc + bool IsLoaded( void ) const { return m_isLoaded; } // return true if a Navigation Mesh has been loaded + bool IsAnalyzed( void ) const { return m_isAnalyzed; } // return true if a Navigation Mesh has been analyzed + + /** + * Return true if nav mesh can be trusted for all climbing/jumping decisions because game environment is fairly simple. + * Authoritative meshes mean path followers can skip CPU intensive realtime scanning of unpredictable geometry. + */ + virtual bool IsAuthoritative( void ) const { return false; } + + const CUtlVector< Place > *GetPlacesFromNavFile( bool *hasUnnamedPlaces ); // Reads the used place names from the nav file (can be used to selectively precache before the nav is loaded) + + virtual bool Save( void ) const; // store Navigation Mesh to a file + bool IsOutOfDate( void ) const { return m_isOutOfDate; } // return true if the Navigation Mesh is older than the current map version + + virtual unsigned int GetSubVersionNumber( void ) const; // returns sub-version number of data format used by derived classes + virtual void SaveCustomData( CUtlBuffer &fileBuffer ) const { } // store custom mesh data for derived classes + virtual void LoadCustomData( CUtlBuffer &fileBuffer, unsigned int subVersion ) { } // load custom mesh data for derived classes + virtual void SaveCustomDataPreArea( CUtlBuffer &fileBuffer ) const { } // store custom mesh data for derived classes that needs to be loaded before areas are read in + virtual void LoadCustomDataPreArea( CUtlBuffer &fileBuffer, unsigned int subVersion ) { } // load custom mesh data for derived classes that needs to be loaded before areas are read in + + // events + virtual void OnServerActivate( void ); // (EXTEND) invoked when server loads a new map + virtual void OnRoundRestart( void ); // invoked when a game round restarts + virtual void OnRoundRestartPreEntity( void ); // invoked when a game round restarts, but before entities are deleted and recreated + virtual void OnBreakableCreated( CBaseEntity *breakable ) { } // invoked when a breakable is created + virtual void OnBreakableBroken( CBaseEntity *broken ) { } // invoked when a breakable is broken + virtual void OnAreaBlocked( CNavArea *area ); // invoked when the area becomes blocked + virtual void OnAreaUnblocked( CNavArea *area ); // invoked when the area becomes un-blocked + virtual void OnAvoidanceObstacleEnteredArea( CNavArea *area ); // invoked when the area becomes obstructed + virtual void OnAvoidanceObstacleLeftArea( CNavArea *area ); // invoked when the area becomes un-obstructed + + virtual void OnEditCreateNotify( CNavArea *newArea ); // invoked when given area has just been added to the mesh in edit mode + virtual void OnEditDestroyNotify( CNavArea *deadArea ); // invoked when given area has just been deleted from the mesh in edit mode + virtual void OnEditDestroyNotify( CNavLadder *deadLadder ); // invoked when given ladder has just been deleted from the mesh in edit mode + virtual void OnNodeAdded( CNavNode *node ) {}; + + // Obstructions + void RegisterAvoidanceObstacle( INavAvoidanceObstacle *obstruction ); + void UnregisterAvoidanceObstacle( INavAvoidanceObstacle *obstruction ); + const CUtlVector< INavAvoidanceObstacle * > &GetObstructions( void ) const { return m_avoidanceObstacles; } + + unsigned int GetNavAreaCount( void ) const { return m_areaCount; } // return total number of nav areas + + // See GetNavAreaFlags_t for flags + CNavArea *GetNavArea( const Vector &pos, float beneathLimt = 120.0f ) const; // given a position, return the nav area that IsOverlapping and is *immediately* beneath it + CNavArea *GetNavArea( CBaseEntity *pEntity, int nGetNavAreaFlags, float flBeneathLimit = 120.0f ) const; + CNavArea *GetNavAreaByID( unsigned int id ) const; + CNavArea *GetNearestNavArea( const Vector &pos, bool anyZ = false, float maxDist = 10000.0f, bool checkLOS = false, bool checkGround = true, int team = TEAM_ANY ) const; + CNavArea *GetNearestNavArea( CBaseEntity *pEntity, int nGetNavAreaFlags = GETNAVAREA_CHECK_GROUND, float maxDist = 10000.0f ) const; + + Place GetPlace( const Vector &pos ) const; // return Place at given coordinate + const char *PlaceToName( Place place ) const; // given a place, return its name + Place NameToPlace( const char *name ) const; // given a place name, return a place ID or zero if no place is defined + Place PartialNameToPlace( const char *name ) const; // given the first part of a place name, return a place ID or zero if no place is defined, or the partial match is ambiguous + void PrintAllPlaces( void ) const; // output a list of names to the console + int PlaceNameAutocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); // Given a partial place name, fill in possible place names for ConCommand autocomplete + + bool GetGroundHeight( const Vector &pos, float *height, Vector *normal = NULL ) const; // get the Z coordinate of the topmost ground level below the given point + bool GetSimpleGroundHeight( const Vector &pos, float *height, Vector *normal = NULL ) const;// get the Z coordinate of the ground level directly below the given point + + + /// increase "danger" weights in the given nav area and nearby ones + void IncreaseDangerNearby( int teamID, float amount, CNavArea *area, const Vector &pos, float maxRadius, float dangerLimit = -1.0f ); + void DrawDanger( void ) const; // draw the current danger levels + void DrawPlayerCounts( void ) const; // draw the current player counts for each area + void DrawFuncNavAvoid( void ) const; // draw bot avoidance areas from func_nav_avoid entities + void DrawFuncNavPrefer( void ) const; // draw bot preference areas from func_nav_prefer entities +#ifdef NEXT_BOT + void DrawFuncNavPrerequisite( void ) const; // draw bot prerequisite areas from func_nav_prerequisite entities +#endif + //------------------------------------------------------------------------------------- + // Auto-generation + // + #define INCREMENTAL_GENERATION true + void BeginGeneration( bool incremental = false ); // initiate the generation process + void BeginAnalysis( bool quitWhenFinished = false ); // re-analyze an existing Mesh. Determine Hiding Spots, Encounter Spots, etc. + + bool IsGenerating( void ) const { return m_generationMode != GENERATE_NONE; } // return true while a Navigation Mesh is being generated + const char *GetPlayerSpawnName( void ) const; // return name of player spawn entity + void SetPlayerSpawnName( const char *name ); // define the name of player spawn entities + void AddWalkableSeed( const Vector &pos, const Vector &normal ); // add given walkable position to list of seed positions for map sampling + virtual void AddWalkableSeeds( void ); // adds walkable positions for any/all positions a mod specifies + void ClearWalkableSeeds( void ) { m_walkableSeeds.RemoveAll(); } // erase all walkable seed positions + void MarkStairAreas( void ); + + virtual unsigned int GetGenerationTraceMask( void ) const; // return the mask used by traces when generating the mesh + + + //------------------------------------------------------------------------------------- + // Edit mode + // + unsigned int GetNavPlace( void ) const { return m_navPlace; } + void SetNavPlace( unsigned int place ) { m_navPlace = place; } + + // Edit callbacks from ConCommands + void CommandNavDelete( void ); // delete current area + void CommandNavDeleteMarked( void ); // delete current marked area + + virtual void CommandNavFloodSelect( const CCommand &args ); // select current area and all connected areas, recursively + void CommandNavToggleSelectedSet( void ); // toggles all areas into/out of the selected set + void CommandNavStoreSelectedSet( void ); // stores the current selected set for later + void CommandNavRecallSelectedSet( void ); // restores an older selected set + void CommandNavAddToSelectedSet( void ); // add current area to selected set + void CommandNavAddToSelectedSetByID( const CCommand &args ); // add specified area id to selected set + void CommandNavRemoveFromSelectedSet( void ); // remove current area from selected set + void CommandNavToggleInSelectedSet( void ); // add/remove current area from selected set + void CommandNavClearSelectedSet( void ); // clear the selected set to empty + void CommandNavBeginSelecting( void ); // start continuously selecting areas into the selected set + void CommandNavEndSelecting( void ); // stop continuously selecting areas into the selected set + void CommandNavBeginDragSelecting( void ); // start dragging a selection area + void CommandNavEndDragSelecting( void ); // stop dragging a selection area + void CommandNavBeginDragDeselecting( void ); // start dragging a deselection area + void CommandNavEndDragDeselecting( void ); // stop dragging a deselection area + void CommandNavRaiseDragVolumeMax( void ); // raise the top of the drag volume + void CommandNavLowerDragVolumeMax( void ); // lower the top of the drag volume + void CommandNavRaiseDragVolumeMin( void ); // raise the bottom of the drag volume + void CommandNavLowerDragVolumeMin( void ); // lower the bottom of the drag volume + void CommandNavToggleSelecting( bool playSound = true ); // start/stop continuously selecting areas into the selected set + void CommandNavBeginDeselecting( void ); // start continuously de-selecting areas from the selected set + void CommandNavEndDeselecting( void ); // stop continuously de-selecting areas from the selected set + void CommandNavToggleDeselecting( bool playSound = true ); // start/stop continuously de-selecting areas from the selected set + void CommandNavSelectInvalidAreas( void ); // adds invalid areas to the selected set + void CommandNavSelectBlockedAreas( void ); // adds blocked areas to the selected set + void CommandNavSelectObstructedAreas( void ); // adds obstructed areas to the selected set + void CommandNavSelectDamagingAreas( void ); // adds damaging areas to the selected set + void CommandNavSelectHalfSpace( const CCommand &args ); // selects all areas that intersect the half-space + void CommandNavSelectStairs( void ); // adds stairs areas to the selected set + void CommandNavSelectOrphans( void ); // adds areas not connected to mesh to the selected set + + void CommandNavSplit( void ); // split current area + void CommandNavMerge( void ); // merge adjacent areas + void CommandNavMark( const CCommand &args ); // mark an area for further operations + void CommandNavUnmark( void ); // removes the mark + + void CommandNavBeginArea( void ); // begin creating a new nav area + void CommandNavEndArea( void ); // end creation of the new nav area + + void CommandNavBeginShiftXY( void ); // begin shifting selected set in the XY plane + void CommandNavEndShiftXY( void ); // end shifting selected set in the XY plane + + void CommandNavConnect( void ); // connect marked area to selected area + void CommandNavDisconnect( void ); // disconnect marked area from selected area + void CommandNavDisconnectOutgoingOneWays( void ); // disconnect all outgoing one-way connects from each area in the selected set + void CommandNavSplice( void ); // create new area in between marked and selected areas + void CommandNavCrouch( void ); // toggle crouch attribute on current area + void CommandNavTogglePlaceMode( void ); // switch between normal and place editing + void CommandNavSetPlaceMode( void ); // switch between normal and place editing + void CommandNavPlaceFloodFill( void ); // floodfill areas out from current area + void CommandNavPlaceSet( void ); // sets the Place for the selected set + void CommandNavPlacePick( void ); // "pick up" the place at the current area + void CommandNavTogglePlacePainting( void ); // switch between "painting" places onto areas + void CommandNavMarkUnnamed( void ); // mark an unnamed area for further operations + void CommandNavCornerSelect( void ); // select a corner on the current area + void CommandNavCornerRaise( const CCommand &args ); // raise a corner on the current area + void CommandNavCornerLower( const CCommand &args ); // lower a corner on the current area + void CommandNavCornerPlaceOnGround( const CCommand &args ); // position a corner on the current area at ground height + void CommandNavWarpToMark( void ); // warp a spectating local player to the selected mark + void CommandNavLadderFlip( void ); // Flips the direction a ladder faces + void CommandNavToggleAttribute( NavAttributeType attribute ); // toggle an attribute on current area + void CommandNavMakeSniperSpots( void ); // cuts up the marked area into individual areas suitable for sniper spots + void CommandNavBuildLadder( void ); // builds a nav ladder on the climbable surface under the cursor + void CommandNavRemoveJumpAreas( void ); // removes jump areas, replacing them with connections + void CommandNavSubdivide( const CCommand &args ); // subdivide each nav area in X and Y to create 4 new areas - limit min size + void CommandNavSaveSelected( const CCommand &args ); // Save selected set to disk + void CommandNavMergeMesh( const CCommand &args ); // Merge a saved selected set into the current mesh + void CommandNavMarkWalkable( void ); + + void AddToDragSelectionSet( CNavArea *pArea ); + void RemoveFromDragSelectionSet( CNavArea *pArea ); + void ClearDragSelectionSet( void ); + + CNavArea *GetMarkedArea( void ) const; // return area marked by user in edit mode + CNavLadder *GetMarkedLadder( void ) const { return m_markedLadder; } // return ladder marked by user in edit mode + + CNavArea *GetSelectedArea( void ) const { return m_selectedArea; } // return area user is pointing at in edit mode + CNavLadder *GetSelectedLadder( void ) const { return m_selectedLadder; } // return ladder user is pointing at in edit mode + void SetMarkedLadder( CNavLadder *ladder ); // mark ladder for further edit operations + void SetMarkedArea( CNavArea *area ); // mark area for further edit operations + + bool IsContinuouslySelecting( void ) const + { + return m_isContinuouslySelecting; + } + + bool IsContinuouslyDeselecting( void ) const + { + return m_isContinuouslyDeselecting; + } + + void CreateLadder( const Vector &mins, const Vector &maxs, float maxHeightAboveTopArea ); + void CreateLadder( const Vector &top, const Vector &bottom, float width, const Vector2D &ladderDir, float maxHeightAboveTopArea ); + + float SnapToGrid( float x, bool forceGrid = false ) const; // snap given coordinate to generation grid boundary + Vector SnapToGrid( const Vector& in, bool snapX = true, bool snapY = true, bool forceGrid = false ) const; // snap given vector's X & Y coordinates to generation grid boundary + + const Vector &GetEditCursorPosition( void ) const { return m_editCursorPos; } // return position of edit cursor + void StripNavigationAreas( void ); + const char *GetFilename( void ) const; // return the filename for this map's "nav" file + + /// @todo Remove old select code and make all commands use this selected set + void AddToSelectedSet( CNavArea *area ); // add area to the currently selected set + void RemoveFromSelectedSet( CNavArea *area ); // remove area from the currently selected set + void ClearSelectedSet( void ); // clear the currently selected set to empty + bool IsSelectedSetEmpty( void ) const; // return true if the selected set is empty + bool IsInSelectedSet( const CNavArea *area ) const; // return true if the given area is in the selected set + int GetSelecteSetSize( void ) const; + const NavAreaVector &GetSelectedSet( void ) const; // return the selected set + + /** + * Apply the functor to all navigation areas in the Selected Set, + * or the current selected area. + * If functor returns false, stop processing and return false. + */ + template < typename Functor > + bool ForAllSelectedAreas( Functor &func ) + { + if (IsSelectedSetEmpty()) + { + CNavArea *area = GetSelectedArea(); + + if (area) + { + if (func( area ) == false) + return false; + } + } + else + { + FOR_EACH_VEC( m_selectedSet, it ) + { + CNavArea *area = m_selectedSet[ it ]; + + if (func( area ) == false) + return false; + } + } + + return true; + } + + //------------------------------------------------------------------------------------- + /** + * Apply the functor to all navigation areas. + * If functor returns false, stop processing and return false. + */ + template < typename Functor > + bool ForAllAreas( Functor &func ) + { + FOR_EACH_VEC( TheNavAreas, it ) + { + CNavArea *area = TheNavAreas[ it ]; + + if (func( area ) == false) + return false; + } + + return true; + } + + // const version of the above + template < typename Functor > + bool ForAllAreas( Functor &func ) const + { + FOR_EACH_VEC( TheNavAreas, it ) + { + const CNavArea *area = TheNavAreas[ it ]; + + if (func( area ) == false) + return false; + } + + return true; + } + + //------------------------------------------------------------------------------------- + /** + * Apply the functor to all navigation areas that overlap the given extent. + * If functor returns false, stop processing and return false. + */ + template < typename Functor > + bool ForAllAreasOverlappingExtent( Functor &func, const Extent &extent ) + { + if ( !m_grid.Count() ) + { +#if _DEBUG + Warning("Query before nav mesh is loaded! %d\n", TheNavAreas.Count() ); +#endif + return true; + } + static unsigned int searchMarker = RandomInt(0, 1024*1024 ); + if ( ++searchMarker == 0 ) + { + ++searchMarker; + } + + Extent areaExtent; + + // get list in cell that contains position + int startX = WorldToGridX( extent.lo.x ); + int endX = WorldToGridX( extent.hi.x ); + int startY = WorldToGridY( extent.lo.y ); + int endY = WorldToGridY( extent.hi.y ); + + for( int x = startX; x <= endX; ++x ) + { + for( int y = startY; y <= endY; ++y ) + { + int iGrid = x + y*m_gridSizeX; + if ( iGrid >= m_grid.Count() ) + { + ExecuteNTimes( 10, Warning( "** Walked off of the CNavMesh::m_grid in ForAllAreasOverlappingExtent()\n" ) ); + return true; + } + + NavAreaVector *areaVector = &m_grid[ iGrid ]; + + // find closest area in this cell + FOR_EACH_VEC( (*areaVector), it ) + { + CNavArea *area = (*areaVector)[ it ]; + + // skip if we've already visited this area + if ( area->m_nearNavSearchMarker == searchMarker ) + continue; + + // mark as visited + area->m_nearNavSearchMarker = searchMarker; + area->GetExtent( &areaExtent ); + + if ( extent.IsOverlapping( areaExtent ) ) + { + if ( func( area ) == false ) + return false; + } + } + } + } + return true; + } + + //------------------------------------------------------------------------------------- + /** + * Populate the given vector with all navigation areas that overlap the given extent. + */ + template< typename NavAreaType > + void CollectAreasOverlappingExtent( const Extent &extent, CUtlVector< NavAreaType * > *outVector ) + { + if ( !m_grid.Count() ) + { + return; + } + + static unsigned int searchMarker = RandomInt( 0, 1024*1024 ); + if ( ++searchMarker == 0 ) + { + ++searchMarker; + } + + Extent areaExtent; + + // get list in cell that contains position + int startX = WorldToGridX( extent.lo.x ); + int endX = WorldToGridX( extent.hi.x ); + int startY = WorldToGridY( extent.lo.y ); + int endY = WorldToGridY( extent.hi.y ); + + for( int x = startX; x <= endX; ++x ) + { + for( int y = startY; y <= endY; ++y ) + { + int iGrid = x + y*m_gridSizeX; + if ( iGrid >= m_grid.Count() ) + { + ExecuteNTimes( 10, Warning( "** Walked off of the CNavMesh::m_grid in CollectAreasOverlappingExtent()\n" ) ); + return; + } + + NavAreaVector *areaVector = &m_grid[ iGrid ]; + + // find closest area in this cell + for( int v=0; vCount(); ++v ) + { + CNavArea *area = areaVector->Element( v ); + + // skip if we've already visited this area + if ( area->m_nearNavSearchMarker == searchMarker ) + continue; + + // mark as visited + area->m_nearNavSearchMarker = searchMarker; + area->GetExtent( &areaExtent ); + + if ( extent.IsOverlapping( areaExtent ) ) + { + outVector->AddToTail( (NavAreaType *)area ); + } + } + } + } + } + + + template < typename Functor > + bool ForAllAreasInRadius( Functor &func, const Vector &pos, float radius ) + { + // use a unique marker for this method, so it can be used within a SearchSurroundingArea() call + static unsigned int searchMarker = RandomInt(0, 1024*1024 ); + + ++searchMarker; + + if ( searchMarker == 0 ) + { + ++searchMarker; + } + + + // get list in cell that contains position + int originX = WorldToGridX( pos.x ); + int originY = WorldToGridY( pos.y ); + int shiftLimit = ceil( radius / m_gridCellSize ); + float radiusSq = radius * radius; + if ( radius == 0.0f ) + { + shiftLimit = MAX( m_gridSizeX, m_gridSizeY ); // range 0 means all areas + } + + for( int x = originX - shiftLimit; x <= originX + shiftLimit; ++x ) + { + if ( x < 0 || x >= m_gridSizeX ) + continue; + + for( int y = originY - shiftLimit; y <= originY + shiftLimit; ++y ) + { + if ( y < 0 || y >= m_gridSizeY ) + continue; + + NavAreaVector *areaVector = &m_grid[ x + y*m_gridSizeX ]; + + // find closest area in this cell + FOR_EACH_VEC( (*areaVector), it ) + { + CNavArea *area = (*areaVector)[ it ]; + + // skip if we've already visited this area + if ( area->m_nearNavSearchMarker == searchMarker ) + continue; + + // mark as visited + area->m_nearNavSearchMarker = searchMarker; + + float distSq = ( area->GetCenter() - pos ).LengthSqr(); + + if ( ( distSq <= radiusSq ) || ( radiusSq == 0 ) ) + { + if ( func( area ) == false ) + return false; + } + } + } + } + return true; + } + + //--------------------------------------------------------------------------------------------------------------- + /* + * Step through nav mesh along line between startArea and endArea. + * Return true if enumeration reached endArea, false if doesn't reach it (no mesh between, bad connection, etc) + */ + template < typename Functor > + bool ForAllAreasAlongLine( Functor &func, CNavArea *startArea, CNavArea *endArea ) + { + if ( !startArea || !endArea ) + return false; + + if ( startArea == endArea ) + { + func( startArea ); + return true; + } + + Vector start = startArea->GetCenter(); + Vector end = endArea->GetCenter(); + + Vector to = end - start; + float range = to.NormalizeInPlace(); + + const float epsilon = 0.00001f; + + if ( range < epsilon ) + { + func( startArea ); + return true; + } + + if ( abs( to.x ) < epsilon ) + { + NavDirType dir = ( to.y < 0.0f ) ? NORTH : SOUTH; + + CNavArea *area = startArea; + while( area ) + { + func( area ); + + if ( area == endArea ) + return true; + + const NavConnectVector *adjVector = area->GetAdjacentAreas( dir ); + + area = NULL; + + for( int i=0; iCount(); ++i ) + { + CNavArea *adjArea = adjVector->Element(i).area; + + const Vector &adjOrigin = adjArea->GetCorner( NORTH_WEST ); + + if ( adjOrigin.x <= start.x && adjOrigin.x + adjArea->GetSizeX() >= start.x ) + { + area = adjArea; + break; + } + } + } + + return false; + } + else if ( abs( to.y ) < epsilon ) + { + NavDirType dir = ( to.x < 0.0f ) ? WEST : EAST; + + CNavArea *area = startArea; + while( area ) + { + func( area ); + + if ( area == endArea ) + return true; + + const NavConnectVector *adjVector = area->GetAdjacentAreas( dir ); + + area = NULL; + + for( int i=0; iCount(); ++i ) + { + CNavArea *adjArea = adjVector->Element(i).area; + + const Vector &adjOrigin = adjArea->GetCorner( NORTH_WEST ); + + if ( adjOrigin.y <= start.y && adjOrigin.y + adjArea->GetSizeY() >= start.y ) + { + area = adjArea; + break; + } + } + } + + return false; + } + + + CNavArea *area = startArea; + + while( area ) + { + func( area ); + + if ( area == endArea ) + return true; + + const Vector &origin = area->GetCorner( NORTH_WEST ); + float xMin = origin.x; + float xMax = xMin + area->GetSizeX(); + float yMin = origin.y; + float yMax = yMin + area->GetSizeY(); + + // clip ray to area + Vector exit; + NavDirType edge = NUM_DIRECTIONS; + + if ( to.x < 0.0f ) + { + // find Y at west edge intersection + float t = ( xMin - start.x ) / ( end.x - start.x ); + if ( t > 0.0f && t < 1.0f ) + { + float y = start.y + t * ( end.y - start.y ); + if ( y >= yMin && y <= yMax ) + { + // intersects this edge + exit.x = xMin; + exit.y = y; + edge = WEST; + } + } + } + else + { + // find Y at east edge intersection + float t = ( xMax - start.x ) / ( end.x - start.x ); + if ( t > 0.0f && t < 1.0f ) + { + float y = start.y + t * ( end.y - start.y ); + if ( y >= yMin && y <= yMax ) + { + // intersects this edge + exit.x = xMax; + exit.y = y; + edge = EAST; + } + } + } + + if ( edge == NUM_DIRECTIONS ) + { + if ( to.y < 0.0f ) + { + // find X at north edge intersection + float t = ( yMin - start.y ) / ( end.y - start.y ); + if ( t > 0.0f && t < 1.0f ) + { + float x = start.x + t * ( end.x - start.x ); + if ( x >= xMin && x <= xMax ) + { + // intersects this edge + exit.x = x; + exit.y = yMin; + edge = NORTH; + } + } + } + else + { + // find X at south edge intersection + float t = ( yMax - start.y ) / ( end.y - start.y ); + if ( t > 0.0f && t < 1.0f ) + { + float x = start.x + t * ( end.x - start.x ); + if ( x >= xMin && x <= xMax ) + { + // intersects this edge + exit.x = x; + exit.y = yMax; + edge = SOUTH; + } + } + } + } + + if ( edge == NUM_DIRECTIONS ) + break; + + const NavConnectVector *adjVector = area->GetAdjacentAreas( edge ); + + area = NULL; + + for( int i=0; iCount(); ++i ) + { + CNavArea *adjArea = adjVector->Element(i).area; + + const Vector &adjOrigin = adjArea->GetCorner( NORTH_WEST ); + + if ( edge == NORTH || edge == SOUTH ) + { + if ( adjOrigin.x <= exit.x && adjOrigin.x + adjArea->GetSizeX() >= exit.x ) + { + area = adjArea; + break; + } + } + else + { + if ( adjOrigin.y <= exit.y && adjOrigin.y + adjArea->GetSizeY() >= exit.y ) + { + area = adjArea; + break; + } + } + } + } + + return false; + } + + + //------------------------------------------------------------------------------------- + /** + * Apply the functor to all navigation ladders. + * If functor returns false, stop processing and return false. + */ + template < typename Functor > + bool ForAllLadders( Functor &func ) + { + for ( int i=0; i + bool ForAllLadders( Functor &func ) const + { + for ( int i=0; i void StitchAreaIntoMesh( CNavArea *area, NavDirType dir, Functor &func ); + + //------------------------------------------------------------------------------------- + /** + * Use the functor to test if an area is needing stitching into the existing nav mesh. + * The functor is different from how we normally use functors - it does no processing, + * and it's return value is true if the area is in the new set to be stiched, and false + * if it's a pre-existing area. + */ + template < typename Functor > + bool StitchMesh( Functor &func ) + { + FOR_EACH_VEC( TheNavAreas, it ) + { + CNavArea *area = TheNavAreas[ it ]; + + if ( func( area ) ) + { + StitchAreaIntoMesh( area, NORTH, func ); + StitchAreaIntoMesh( area, SOUTH, func ); + StitchAreaIntoMesh( area, EAST, func ); + StitchAreaIntoMesh( area, WEST, func ); + } + } + + return true; + } + + NavLadderVector& GetLadders( void ) { return m_ladders; } // Returns the list of ladders + CNavLadder *GetLadderByID( unsigned int id ) const; + + CUtlVector< CNavArea * >& GetTransientAreas( void ) { return m_transientAreas; } + + enum EditModeType + { + NORMAL, // normal mesh editing + PLACE_PAINTING, // in place painting mode + CREATING_AREA, // creating a new nav area + CREATING_LADDER, // creating a nav ladder + DRAG_SELECTING, // drag selecting a set of areas + SHIFTING_XY, // shifting selected set in XY plane + SHIFTING_Z, // shifting selected set in Z plane + }; + EditModeType GetEditMode( void ) const; // return the current edit mode + void SetEditMode( EditModeType mode ); // change the edit mode + bool IsEditMode( EditModeType mode ) const; // return true if current mode matches given mode + + bool FindNavAreaOrLadderAlongRay( const Vector &start, const Vector &end, CNavArea **area, CNavLadder **ladder, CNavArea *ignore = NULL ); + + void PostProcessCliffAreas(); + void SimplifySelectedAreas( void ); // Simplifies the selected set by reducing to 1x1 areas and re-merging them up with loosened tolerances + +protected: + virtual void PostCustomAnalysis( void ) { } // invoked when custom analysis step is complete + bool FindActiveNavArea( void ); // Finds the area or ladder the local player is currently pointing at. Returns true if a surface was hit by the traceline. + virtual void RemoveNavArea( CNavArea *area ); // remove an area from the grid + bool FindGroundForNode( Vector *pos, Vector *normal ); + void GenerateNodes( const Extent &bounds ); + void RemoveNodes( void ); + +private: + friend class CNavArea; + friend class CNavNode; + friend class CNavUIBasePanel; + + mutable CUtlVector m_grid; + float m_gridCellSize; // the width/height of a grid cell for spatially partitioning nav areas for fast access + int m_gridSizeX; + int m_gridSizeY; + float m_minX; + float m_minY; + unsigned int m_areaCount; // total number of nav areas + + bool m_isLoaded; // true if a Navigation Mesh has been loaded + bool m_isOutOfDate; // true if the Navigation Mesh is older than the actual BSP + bool m_isAnalyzed; // true if the Navigation Mesh needs analysis + + enum { HASH_TABLE_SIZE = 256 }; + CNavArea *m_hashTable[ HASH_TABLE_SIZE ]; // hash table to optimize lookup by ID + int ComputeHashKey( unsigned int id ) const; // returns a hash key for the given nav area ID + + int WorldToGridX( float wx ) const; // given X component, return grid index + int WorldToGridY( float wy ) const; // given Y component, return grid index + void AllocateGrid( float minX, float maxX, float minY, float maxY ); // clear and reset the grid to the given extents + void GridToWorld( int gridX, int gridY, Vector *pos ) const; + + void AddNavArea( CNavArea *area ); // add an area to the grid + + void DestroyNavigationMesh( bool incremental = false ); // free all resources of the mesh and reset it to empty state + void DestroyHidingSpots( void ); + + void ComputeBattlefrontAreas( void ); // determine areas where rushing teams will first meet + + //---------------------------------------------------------------------------------- + // Place directory + // + char **m_placeName; // master directory of place names (ie: "places") + unsigned int m_placeCount; // number of "places" defined in placeName[] + void LoadPlaceDatabase( void ); // load the place names from a file + + //---------------------------------------------------------------------------------- + // Edit mode + // + EditModeType m_editMode; // the current edit mode + bool m_isEditing; // true if in edit mode + + unsigned int m_navPlace; // current navigation place for editing + void OnEditModeStart( void ); // called when edit mode has just been enabled + void DrawEditMode( void ); // draw navigation areas + void OnEditModeEnd( void ); // called when edit mode has just been disabled + void UpdateDragSelectionSet( void ); // update which areas are overlapping the drag selected bounds + Vector m_editCursorPos; // current position of the cursor + CNavArea *m_markedArea; // currently marked area for edit operations + CNavArea *m_selectedArea; // area that is selected this frame + CNavArea *m_lastSelectedArea; // area that was selected last frame + NavCornerType m_markedCorner; // currently marked corner for edit operations + Vector m_anchor; // first corner of an area being created + bool m_isPlacePainting; // if true, we set an area's place by pointing at it + bool m_splitAlongX; // direction the selected nav area would be split + float m_splitEdge; // location of the possible split + + bool m_climbableSurface; // if true, the cursor is pointing at a climable surface + Vector m_surfaceNormal; // Normal of the surface the cursor is pointing at + Vector m_ladderAnchor; // first corner of a ladder being created + Vector m_ladderNormal; // Normal of the surface of the ladder being created + CNavLadder *m_selectedLadder; // ladder that is selected this frame + CNavLadder *m_lastSelectedLadder; // ladder that was selected last frame + CNavLadder *m_markedLadder; // currently marked ladder for edit operations + + bool FindLadderCorners( Vector *c1, Vector *c2, Vector *c3 ); // computes the other corners of a ladder given m_ladderAnchor, m_editCursorPos, and m_ladderNormal + + void GetEditVectors( Vector *pos, Vector *forward ); // Gets the eye position and view direction of the editing player + + CountdownTimer m_showAreaInfoTimer; // Timer that controls how long area info is displayed + + NavAreaVector m_selectedSet; // all currently selected areas + NavAreaVector m_dragSelectionSet; // all areas in the current drag selection + bool m_isContinuouslySelecting; // if true, we are continuously adding to the selected set + bool m_isContinuouslyDeselecting; // if true, we are continuously removing from the selected set + + bool m_bIsDragDeselecting; + int m_nDragSelectionVolumeZMax; + int m_nDragSelectionVolumeZMin; + + void DoToggleAttribute( CNavArea *area, NavAttributeType attribute ); // toggle an attribute on given area + + + //---------------------------------------------------------------------------------- + // Auto-generation + // + bool UpdateGeneration( float maxTime = 0.25f ); // process the auto-generation for 'maxTime' seconds. return false if generation is complete. + + virtual void BeginCustomAnalysis( bool bIncremental ) {} + virtual void EndCustomAnalysis() {} + + CNavNode *m_currentNode; // the current node we are sampling from + NavDirType m_generationDir; + CNavNode *AddNode( const Vector &destPos, const Vector &destNormal, NavDirType dir, CNavNode *source, bool isOnDisplacement, float obstacleHeight, float flObstacleStartDist, float flObstacleEndDist ); // add a nav node and connect it, update current node + + NavLadderVector m_ladders; // list of ladder navigation representations + void BuildLadders( void ); + void DestroyLadders( void ); + + bool SampleStep( void ); // sample the walkable areas of the map + void CreateNavAreasFromNodes( void ); // cover all of the sampled nodes with nav areas + + bool TestArea( CNavNode *node, int width, int height ); // check if an area of size (width, height) can fit, starting from node as upper left corner + int BuildArea( CNavNode *node, int width, int height ); // create a CNavArea of size (width, height) starting fom node at upper left corner + bool CheckObstacles( CNavNode *node, int width, int height, int x, int y ); + + void MarkPlayerClipAreas( void ); + void MarkJumpAreas( void ); + void StichAndRemoveJumpAreas( void ); + void RemoveJumpAreas( void ); + void SquareUpAreas( void ); + void MergeGeneratedAreas( void ); + void ConnectGeneratedAreas( void ); + void FixUpGeneratedAreas( void ); + void FixCornerOnCornerAreas( void ); + void FixConnections( void ); + void SplitAreasUnderOverhangs( void ); + void ValidateNavAreaConnections( void ); + void StitchGeneratedAreas( void ); // Stitches incrementally-generated areas into the existing mesh + void StitchAreaSet( CUtlVector< CNavArea * > *areas ); // Stitches an arbitrary set of areas into the existing mesh + void HandleObstacleTopAreas( void ); // Handles fixing/generating areas on top of slim obstacles such as fences and railings + void RaiseAreasWithInternalObstacles(); + void CreateObstacleTopAreas(); + bool CreateObstacleTopAreaIfNecessary( CNavArea *area, CNavArea *areaOther, NavDirType dir, bool bMultiNode ); + void RemoveOverlappingObstacleTopAreas(); + + + enum GenerationStateType + { + SAMPLE_WALKABLE_SPACE, + CREATE_AREAS_FROM_SAMPLES, + FIND_HIDING_SPOTS, + FIND_ENCOUNTER_SPOTS, + FIND_SNIPER_SPOTS, + FIND_EARLIEST_OCCUPY_TIMES, + FIND_LIGHT_INTENSITY, + COMPUTE_MESH_VISIBILITY, + CUSTOM, // mod-specific generation step + SAVE_NAV_MESH, + + NUM_GENERATION_STATES + } + m_generationState; // the state of the generation process + enum GenerationModeType + { + GENERATE_NONE, + GENERATE_FULL, + GENERATE_INCREMENTAL, + GENERATE_SIMPLIFY, + GENERATE_ANALYSIS_ONLY, + } + m_generationMode; // true while a Navigation Mesh is being generated + int m_generationIndex; // used for iterating nav areas during generation process + int m_sampleTick; // counter for displaying pseudo-progress while sampling walkable space + bool m_bQuitWhenFinished; + float m_generationStartTime; + Extent m_simplifyGenerationExtent; + + char *m_spawnName; // name of player spawn entity, used to initiate sampling + + struct WalkableSeedSpot + { + Vector pos; + Vector normal; + }; + CUtlVector< WalkableSeedSpot > m_walkableSeeds; // list of walkable seed spots for sampling + + CNavNode *GetNextWalkableSeedNode( void ); // return the next walkable seed as a node + int m_seedIdx; + int m_hostThreadModeRestoreValue; // stores the value of host_threadmode before we changed it + + void BuildTransientAreaList( void ); + CUtlVector< CNavArea * > m_transientAreas; + + void UpdateAvoidanceObstacleAreas( void ); + CUtlVector< CNavArea * > m_avoidanceObstacleAreas; + CUtlVector< INavAvoidanceObstacle * > m_avoidanceObstacles; + + void UpdateBlockedAreas( void ); + CUtlVector< CNavArea * > m_blockedAreas; + + CUtlVector< int > m_storedSelectedSet; // "Stored" selected set, so we can do some editing and then restore the old selected set. Done by ID, so we don't have to worry about split/delete/etc. + + void BeginVisibilityComputations( void ); + void EndVisibilityComputations( void ); + + void TestAllAreasForBlockedStatus( void ); // Used to update blocked areas after a round restart. Need to delay so the map logic has all fired. + CountdownTimer m_updateBlockedAreasTimer; +}; + +// the global singleton interface +extern CNavMesh *TheNavMesh; + +// factory for creating the Navigation Mesh +extern CNavMesh *NavMeshFactory( void ); + +#ifdef STAGING_ONLY +// for debugging the A* algorithm, if nonzero, show debug display and decrement for each pathfind +extern int g_DebugPathfindCounter; +#endif + + +//-------------------------------------------------------------------------------------------------------------- +inline bool CNavMesh::IsEditMode( EditModeType mode ) const +{ + return m_editMode == mode; +} + +//-------------------------------------------------------------------------------------------------------------- +inline CNavMesh::EditModeType CNavMesh::GetEditMode( void ) const +{ + return m_editMode; +} + +//-------------------------------------------------------------------------------------------------------------- +inline unsigned int CNavMesh::GetSubVersionNumber( void ) const +{ + return 0; +} + + +//-------------------------------------------------------------------------------------------------------------- +inline CNavArea *CNavMesh::CreateArea( void ) const +{ + return new CNavArea; +} + +//-------------------------------------------------------------------------------------------------------------- +inline void CNavMesh::DestroyArea( CNavArea *pArea ) const +{ + delete pArea; +} + +//-------------------------------------------------------------------------------------------------------------- +inline int CNavMesh::ComputeHashKey( unsigned int id ) const +{ + return id & 0xFF; +} + +//-------------------------------------------------------------------------------------------------------------- +inline int CNavMesh::WorldToGridX( float wx ) const +{ + int x = (int)( (wx - m_minX) / m_gridCellSize ); + + if (x < 0) + x = 0; + else if (x >= m_gridSizeX) + x = m_gridSizeX-1; + + return x; +} + +//-------------------------------------------------------------------------------------------------------------- +inline int CNavMesh::WorldToGridY( float wy ) const +{ + int y = (int)( (wy - m_minY) / m_gridCellSize ); + + if (y < 0) + y = 0; + else if (y >= m_gridSizeY) + y = m_gridSizeY-1; + + return y; +} + + +//-------------------------------------------------------------------------------------------------------------- +inline unsigned int CNavMesh::GetGenerationTraceMask( void ) const +{ + return MASK_NPCSOLID_BRUSHONLY; +} + + +//-------------------------------------------------------------------------------------------------------------- +// +// Function prototypes +// + +extern void ApproachAreaAnalysisPrep( void ); +extern void CleanupApproachAreaAnalysisPrep( void ); +extern bool IsHeightDifferenceValid( float test, float other1, float other2, float other3 ); + +#endif // _NAV_MESH_H_ diff --git a/game/server/nav_node.h b/game/server/nav_node.h new file mode 100644 index 0000000..9bbafe7 --- /dev/null +++ b/game/server/nav_node.h @@ -0,0 +1,151 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// nav_node.h +// Navigation Nodes are used when generating a Navigation Mesh by point sampling the map +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +#ifndef _NAV_NODE_H_ +#define _NAV_NODE_H_ + +#include "nav.h" + +// If DEBUG_NAV_NODES is true, nav_show_nodes controls drawing node positions, and +// nav_show_node_id allows you to show the IDs of nodes that didn't get used to create areas. +#define DEBUG_NAV_NODES 1 + +//-------------------------------------------------------------------------------------------------------------- +/** + * Navigation Nodes. + * These Nodes encapsulate world locations, and ways to get from one location to an adjacent one. + * Note that these links are not necessarily commutative (falling off of a ledge, for example). + */ +class CNavNode +{ +public: + CNavNode( const Vector &pos, const Vector &normal, CNavNode *parent, bool onDisplacement ); + ~CNavNode(); + + static CNavNode *GetNode( const Vector &pos ); ///< return navigation node at the position, or NULL if none exists + static void CleanupGeneration(); + + CNavNode *GetConnectedNode( NavDirType dir ) const; ///< get navigation node connected in given direction, or NULL if cant go that way + const Vector *GetPosition( void ) const; + const Vector *GetNormal( void ) const { return &m_normal; } + unsigned int GetID( void ) const { return m_id; } + + static CNavNode *GetFirst( void ) { return m_list; } + static unsigned int GetListLength( void ) { return m_listLength; } + CNavNode *GetNext( void ) { return m_next; } + + void Draw( void ); + + void ConnectTo( CNavNode *node, NavDirType dir, float obstacleHeight, float flObstacleStartDist, float flObstacleEndDist ); ///< create a connection FROM this node TO the given node, in the given direction + CNavNode *GetParent( void ) const; + + void MarkAsVisited( NavDirType dir ); ///< mark the given direction as having been visited + BOOL HasVisited( NavDirType dir ); ///< return TRUE if the given direction has already been searched + BOOL IsBiLinked( NavDirType dir ) const; ///< node is bidirectionally linked to another node in the given direction + BOOL IsClosedCell( void ) const; ///< node is the NW corner of a bi-linked quad of nodes + + void Cover( void ) { m_isCovered = true; } ///< @todo Should pass in area that is covering + BOOL IsCovered( void ) const { return m_isCovered; } ///< return true if this node has been covered by an area + + void AssignArea( CNavArea *area ); ///< assign the given area to this node + CNavArea *GetArea( void ) const; ///< return associated area + + void SetAttributes( int bits ) { m_attributeFlags = bits; } + int GetAttributes( void ) const { return m_attributeFlags; } + float GetGroundHeightAboveNode( NavCornerType cornerType ) const; ///< return ground height above node in given corner direction (NUM_CORNERS for highest in any direction) + bool IsBlockedInAnyDirection( void) const; ///< return true if the node is blocked in any direction + + bool IsOnDisplacement( void ) const { return m_isOnDisplacement; } + +private: + CNavNode() {} // constructor used only for hash lookup + friend class CNavMesh; + + bool TestForCrouchArea( NavCornerType cornerNum, const Vector& mins, const Vector& maxs, float *groundHeightAboveNode ); + void CheckCrouch( void ); + + Vector m_pos; ///< position of this node in the world + Vector m_normal; ///< surface normal at this location + CNavNode *m_to[ NUM_DIRECTIONS ]; ///< links to north, south, east, and west. NULL if no link + float m_obstacleHeight[ NUM_DIRECTIONS ]; ///< obstacle height (delta from nav node z position) that must be climbed to reach next node in this direction + float m_obstacleStartDist[ NUM_DIRECTIONS ]; ///< distance along this direction to reach the beginning of the obstacle + float m_obstacleEndDist[ NUM_DIRECTIONS ]; ///< distance along this direction to reach the end of the obstacle + unsigned int m_id; ///< unique ID of this node + int m_attributeFlags; ///< set of attribute bit flags (see NavAttributeType) + + static CNavNode *m_list; ///< the master list of all nodes for this map + static unsigned int m_listLength; + static unsigned int m_nextID; + CNavNode *m_next; ///< next link in master list + CNavNode *m_nextAtXY; ///< next link at a particular position + + // below are only needed when generating + unsigned char m_visited; ///< flags for automatic node generation. If direction bit is clear, that direction hasn't been explored yet. + CNavNode *m_parent; ///< the node prior to this in the search, which we pop back to when this node's search is done (a stack) + bool m_isCovered; ///< true when this node is "covered" by a CNavArea + CNavArea *m_area; ///< the area this node is contained within + + bool m_isBlocked[ NUM_CORNERS ]; + bool m_crouch[ NUM_CORNERS ]; + float m_groundHeightAboveNode[ NUM_CORNERS ]; + bool m_isOnDisplacement; +}; + +//-------------------------------------------------------------------------------------------------------------- +// +// Inlines +// + +inline CNavNode *CNavNode::GetConnectedNode( NavDirType dir ) const +{ + return m_to[ dir ]; +} + +inline const Vector *CNavNode::GetPosition( void ) const +{ + return &m_pos; +} + +inline CNavNode *CNavNode::GetParent( void ) const +{ + return m_parent; +} + +inline void CNavNode::MarkAsVisited( NavDirType dir ) +{ + m_visited |= (1 << dir); +} + +inline BOOL CNavNode::HasVisited( NavDirType dir ) +{ + if (m_visited & (1 << dir)) + return true; + + return false; +} + +inline void CNavNode::AssignArea( CNavArea *area ) +{ + m_area = area; +} + +inline CNavArea *CNavNode::GetArea( void ) const +{ + return m_area; +} + +inline bool CNavNode::IsBlockedInAnyDirection( void ) const +{ + return m_isBlocked[ SOUTH_EAST ] || m_isBlocked[ SOUTH_WEST ] || m_isBlocked[ NORTH_EAST ] || m_isBlocked[ NORTH_WEST ]; +} + + +#endif // _NAV_NODE_H_ diff --git a/game/server/nav_pathfind.h b/game/server/nav_pathfind.h new file mode 100644 index 0000000..e9c2d7e --- /dev/null +++ b/game/server/nav_pathfind.h @@ -0,0 +1,998 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// nav_pathfind.h +// Path-finding mechanisms using the Navigation Mesh +// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 + +#ifndef _NAV_PATHFIND_H_ +#define _NAV_PATHFIND_H_ + +#include "tier0/vprof.h" +#include "mathlib/ssemath.h" +#include "nav_area.h" + +#ifdef STAGING_ONLY +extern int g_DebugPathfindCounter; +#endif + + +//------------------------------------------------------------------------------------------------------------------- +/** + * Used when building a path to determine the kind of path to build + */ +enum RouteType +{ + DEFAULT_ROUTE, + FASTEST_ROUTE, + SAFEST_ROUTE, + RETREAT_ROUTE, +}; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Functor used with NavAreaBuildPath() + */ +class ShortestPathCost +{ +public: + float operator() ( CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder, const CFuncElevator *elevator, float length ) + { + if ( fromArea == NULL ) + { + // first area in path, no cost + return 0.0f; + } + else + { + // compute distance traveled along path so far + float dist; + + if ( ladder ) + { + dist = ladder->m_length; + } + else if ( length > 0.0 ) + { + dist = length; + } + else + { + dist = ( area->GetCenter() - fromArea->GetCenter() ).Length(); + } + + float cost = dist + fromArea->GetCostSoFar(); + + // if this is a "crouch" area, add penalty + if ( area->GetAttributes() & NAV_MESH_CROUCH ) + { + const float crouchPenalty = 20.0f; // 10 + cost += crouchPenalty * dist; + } + + // if this is a "jump" area, add penalty + if ( area->GetAttributes() & NAV_MESH_JUMP ) + { + const float jumpPenalty = 5.0f; + cost += jumpPenalty * dist; + } + + return cost; + } + } +}; + +//-------------------------------------------------------------------------------------------------------------- +/** + * Find path from startArea to goalArea via an A* search, using supplied cost heuristic. + * If cost functor returns -1 for an area, that area is considered a dead end. + * This doesn't actually build a path, but the path is defined by following parent + * pointers back from goalArea to startArea. + * If 'closestArea' is non-NULL, the closest area to the goal is returned (useful if the path fails). + * If 'goalArea' is NULL, will compute a path as close as possible to 'goalPos'. + * If 'goalPos' is NULL, will use the center of 'goalArea' as the goal position. + * If 'maxPathLength' is nonzero, path building will stop when this length is reached. + * Returns true if a path exists. + */ +#define IGNORE_NAV_BLOCKERS true +template< typename CostFunctor > +bool NavAreaBuildPath( CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, CostFunctor &costFunc, CNavArea **closestArea = NULL, float maxPathLength = 0.0f, int teamID = TEAM_ANY, bool ignoreNavBlockers = false ) +{ + VPROF_BUDGET( "NavAreaBuildPath", "NextBotSpiky" ); + + if ( closestArea ) + { + *closestArea = startArea; + } + +#ifdef STAGING_ONLY + bool isDebug = ( g_DebugPathfindCounter-- > 0 ); +#endif + + if (startArea == NULL) + return false; + + startArea->SetParent( NULL ); + + if (goalArea != NULL && goalArea->IsBlocked( teamID, ignoreNavBlockers )) + goalArea = NULL; + + if (goalArea == NULL && goalPos == NULL) + return false; + + // if we are already in the goal area, build trivial path + if (startArea == goalArea) + { + return true; + } + + // determine actual goal position + Vector actualGoalPos = (goalPos) ? *goalPos : goalArea->GetCenter(); + + // start search + CNavArea::ClearSearchLists(); + + // compute estimate of path length + /// @todo Cost might work as "manhattan distance" + startArea->SetTotalCost( (startArea->GetCenter() - actualGoalPos).Length() ); + + float initCost = costFunc( startArea, NULL, NULL, NULL, -1.0f ); + if (initCost < 0.0f) + return false; + startArea->SetCostSoFar( initCost ); + startArea->SetPathLengthSoFar( 0.0 ); + + startArea->AddToOpenList(); + + // keep track of the area we visit that is closest to the goal + float closestAreaDist = startArea->GetTotalCost(); + + // do A* search + while( !CNavArea::IsOpenListEmpty() ) + { + // get next area to check + CNavArea *area = CNavArea::PopOpenList(); + +#ifdef STAGING_ONLY + if ( isDebug ) + { + area->DrawFilled( 0, 255, 0, 128, 30.0f ); + } +#endif + + // don't consider blocked areas + if ( area->IsBlocked( teamID, ignoreNavBlockers ) ) + continue; + + // check if we have found the goal area or position + if (area == goalArea || (goalArea == NULL && goalPos && area->Contains( *goalPos ))) + { + if (closestArea) + { + *closestArea = area; + } + + return true; + } + + // search adjacent areas + enum SearchType + { + SEARCH_FLOOR, SEARCH_LADDERS, SEARCH_ELEVATORS + }; + SearchType searchWhere = SEARCH_FLOOR; + int searchIndex = 0; + + int dir = NORTH; + const NavConnectVector *floorList = area->GetAdjacentAreas( NORTH ); + + bool ladderUp = true; + const NavLadderConnectVector *ladderList = NULL; + enum { AHEAD = 0, LEFT, RIGHT, BEHIND, NUM_TOP_DIRECTIONS }; + int ladderTopDir = AHEAD; + bool bHaveMaxPathLength = ( maxPathLength > 0.0f ); + float length = -1; + + while( true ) + { + CNavArea *newArea = NULL; + NavTraverseType how; + const CNavLadder *ladder = NULL; + const CFuncElevator *elevator = NULL; + + // + // Get next adjacent area - either on floor or via ladder + // + if ( searchWhere == SEARCH_FLOOR ) + { + // if exhausted adjacent connections in current direction, begin checking next direction + if ( searchIndex >= floorList->Count() ) + { + ++dir; + + if ( dir == NUM_DIRECTIONS ) + { + // checked all directions on floor - check ladders next + searchWhere = SEARCH_LADDERS; + + ladderList = area->GetLadders( CNavLadder::LADDER_UP ); + searchIndex = 0; + ladderTopDir = AHEAD; + } + else + { + // start next direction + floorList = area->GetAdjacentAreas( (NavDirType)dir ); + searchIndex = 0; + } + + continue; + } + + const NavConnect &floorConnect = floorList->Element( searchIndex ); + newArea = floorConnect.area; + length = floorConnect.length; + how = (NavTraverseType)dir; + ++searchIndex; + + if ( IsX360() && searchIndex < floorList->Count() ) + { + PREFETCH360( floorList->Element( searchIndex ).area, 0 ); + } + } + else if ( searchWhere == SEARCH_LADDERS ) + { + if ( searchIndex >= ladderList->Count() ) + { + if ( !ladderUp ) + { + // checked both ladder directions - check elevators next + searchWhere = SEARCH_ELEVATORS; + searchIndex = 0; + ladder = NULL; + } + else + { + // check down ladders + ladderUp = false; + ladderList = area->GetLadders( CNavLadder::LADDER_DOWN ); + searchIndex = 0; + } + continue; + } + + if ( ladderUp ) + { + ladder = ladderList->Element( searchIndex ).ladder; + + // do not use BEHIND connection, as its very hard to get to when going up a ladder + if ( ladderTopDir == AHEAD ) + { + newArea = ladder->m_topForwardArea; + } + else if ( ladderTopDir == LEFT ) + { + newArea = ladder->m_topLeftArea; + } + else if ( ladderTopDir == RIGHT ) + { + newArea = ladder->m_topRightArea; + } + else + { + ++searchIndex; + ladderTopDir = AHEAD; + continue; + } + + how = GO_LADDER_UP; + ++ladderTopDir; + } + else + { + newArea = ladderList->Element( searchIndex ).ladder->m_bottomArea; + how = GO_LADDER_DOWN; + ladder = ladderList->Element(searchIndex).ladder; + ++searchIndex; + } + + if ( newArea == NULL ) + continue; + + length = -1.0f; + } + else // if ( searchWhere == SEARCH_ELEVATORS ) + { + const NavConnectVector &elevatorAreas = area->GetElevatorAreas(); + + elevator = area->GetElevator(); + + if ( elevator == NULL || searchIndex >= elevatorAreas.Count() ) + { + // done searching connected areas + elevator = NULL; + break; + } + + newArea = elevatorAreas[ searchIndex++ ].area; + if ( newArea->GetCenter().z > area->GetCenter().z ) + { + how = GO_ELEVATOR_UP; + } + else + { + how = GO_ELEVATOR_DOWN; + } + + length = -1.0f; + } + + + // don't backtrack + Assert( newArea ); + if ( newArea == area->GetParent() ) + continue; + if ( newArea == area ) // self neighbor? + continue; + + // don't consider blocked areas + if ( newArea->IsBlocked( teamID, ignoreNavBlockers ) ) + continue; + + float newCostSoFar = costFunc( newArea, area, ladder, elevator, length ); + + // NaNs really mess this function up causing tough to track down hangs. If + // we get inf back, clamp it down to a really high number. + DebuggerBreakOnNaN_StagingOnly( newCostSoFar ); + if ( IS_NAN( newCostSoFar ) ) + newCostSoFar = 1e30f; + + // check if cost functor says this area is a dead-end + if ( newCostSoFar < 0.0f ) + continue; + + // Safety check against a bogus functor. The cost of the path + // A...B, C should always be at least as big as the path A...B. + Assert( newCostSoFar >= area->GetCostSoFar() ); + + // And now that we've asserted, let's be a bit more defensive. + // Make sure that any jump to a new area incurs some pathfinsing + // cost, to avoid us spinning our wheels over insignificant cost + // benefit, floating point precision bug, or busted cost functor. + float minNewCostSoFar = area->GetCostSoFar() * 1.00001f + 0.00001f; + newCostSoFar = Max( newCostSoFar, minNewCostSoFar ); + + // stop if path length limit reached + if ( bHaveMaxPathLength ) + { + // keep track of path length so far + float deltaLength = ( newArea->GetCenter() - area->GetCenter() ).Length(); + float newLengthSoFar = area->GetPathLengthSoFar() + deltaLength; + if ( newLengthSoFar > maxPathLength ) + continue; + + newArea->SetPathLengthSoFar( newLengthSoFar ); + } + + if ( ( newArea->IsOpen() || newArea->IsClosed() ) && newArea->GetCostSoFar() <= newCostSoFar ) + { + // this is a worse path - skip it + continue; + } + else + { + // compute estimate of distance left to go + float distSq = ( newArea->GetCenter() - actualGoalPos ).LengthSqr(); + float newCostRemaining = ( distSq > 0.0 ) ? FastSqrt( distSq ) : 0.0 ; + + // track closest area to goal in case path fails + if ( closestArea && newCostRemaining < closestAreaDist ) + { + *closestArea = newArea; + closestAreaDist = newCostRemaining; + } + + newArea->SetCostSoFar( newCostSoFar ); + newArea->SetTotalCost( newCostSoFar + newCostRemaining ); + + if ( newArea->IsClosed() ) + { + newArea->RemoveFromClosedList(); + } + + if ( newArea->IsOpen() ) + { + // area already on open list, update the list order to keep costs sorted + newArea->UpdateOnOpenList(); + } + else + { + newArea->AddToOpenList(); + } + + newArea->SetParent( area, how ); + } + } + + // we have searched this area + area->AddToClosedList(); + } + + return false; +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Compute distance between two areas. Return -1 if can't reach 'endArea' from 'startArea'. + */ +template< typename CostFunctor > +float NavAreaTravelDistance( CNavArea *startArea, CNavArea *endArea, CostFunctor &costFunc, float maxPathLength = 0.0f ) +{ + if (startArea == NULL) + return -1.0f; + + if (endArea == NULL) + return -1.0f; + + if (startArea == endArea) + return 0.0f; + + // compute path between areas using given cost heuristic + if (NavAreaBuildPath( startArea, endArea, NULL, costFunc, NULL, maxPathLength ) == false) + return -1.0f; + + // compute distance along path + float distance = 0.0f; + for( CNavArea *area = endArea; area->GetParent(); area = area->GetParent() ) + { + distance += (area->GetCenter() - area->GetParent()->GetCenter()).Length(); + } + + return distance; +} + + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Do a breadth-first search, invoking functor on each area. + * If functor returns 'true', continue searching from this area. + * If functor returns 'false', the area's adjacent areas are not explored (dead end). + * If 'maxRange' is 0 or less, no range check is done (all areas will be examined). + * + * NOTE: Returns all areas that overlap range, even partially + * + * @todo Use ladder connections + */ + +// helper function +inline void AddAreaToOpenList( CNavArea *area, CNavArea *parent, const Vector &startPos, float maxRange ) +{ + if (area == NULL) + return; + + if (!area->IsMarked()) + { + area->Mark(); + area->SetTotalCost( 0.0f ); + area->SetParent( parent ); + + if (maxRange > 0.0f) + { + // make sure this area overlaps range + Vector closePos; + area->GetClosestPointOnArea( startPos, &closePos ); + if ((closePos - startPos).AsVector2D().IsLengthLessThan( maxRange )) + { + // compute approximate distance along path to limit travel range, too + float distAlong = parent->GetCostSoFar(); + distAlong += (area->GetCenter() - parent->GetCenter()).Length(); + area->SetCostSoFar( distAlong ); + + // allow for some fudge due to large size areas + if (distAlong <= 1.5f * maxRange) + area->AddToOpenList(); + } + } + else + { + // infinite range + area->AddToOpenList(); + } + } +} + + +/**************************************************************** + * DEPRECATED: Use filter-based SearchSurroundingAreas below + ****************************************************************/ +#define INCLUDE_INCOMING_CONNECTIONS 0x1 +#define INCLUDE_BLOCKED_AREAS 0x2 +#define EXCLUDE_OUTGOING_CONNECTIONS 0x4 +#define EXCLUDE_ELEVATORS 0x8 +template < typename Functor > +void SearchSurroundingAreas( CNavArea *startArea, const Vector &startPos, Functor &func, float maxRange = -1.0f, unsigned int options = 0, int teamID = TEAM_ANY ) +{ + if (startArea == NULL) + return; + + CNavArea::MakeNewMarker(); + CNavArea::ClearSearchLists(); + + startArea->AddToOpenList(); + startArea->SetTotalCost( 0.0f ); + startArea->SetCostSoFar( 0.0f ); + startArea->SetParent( NULL ); + startArea->Mark(); + + while( !CNavArea::IsOpenListEmpty() ) + { + // get next area to check + CNavArea *area = CNavArea::PopOpenList(); + + // don't use blocked areas + if ( area->IsBlocked( teamID ) && !(options & INCLUDE_BLOCKED_AREAS) ) + continue; + + // invoke functor on area + if (func( area )) + { + // explore adjacent floor areas + for( int dir=0; dirGetAdjacentCount( (NavDirType)dir ); + for( int i=0; iGetAdjacentArea( (NavDirType)dir, i ); + if ( options & EXCLUDE_OUTGOING_CONNECTIONS ) + { + if ( !adjArea->IsConnected( area, NUM_DIRECTIONS ) ) + { + continue; // skip this outgoing connection + } + } + + AddAreaToOpenList( adjArea, area, startPos, maxRange ); + } + } + + // potentially include areas that connect TO this area via a one-way link + if (options & INCLUDE_INCOMING_CONNECTIONS) + { + for( int dir=0; dirGetIncomingConnections( (NavDirType)dir ); + + FOR_EACH_VEC( (*list), it ) + { + NavConnect connect = (*list)[ it ]; + + AddAreaToOpenList( connect.area, area, startPos, maxRange ); + } + } + } + + + // explore adjacent areas connected by ladders + + // check up ladders + const NavLadderConnectVector *ladderList = area->GetLadders( CNavLadder::LADDER_UP ); + if (ladderList) + { + FOR_EACH_VEC( (*ladderList), it ) + { + const CNavLadder *ladder = (*ladderList)[ it ].ladder; + + // do not use BEHIND connection, as its very hard to get to when going up a ladder + AddAreaToOpenList( ladder->m_topForwardArea, area, startPos, maxRange ); + AddAreaToOpenList( ladder->m_topLeftArea, area, startPos, maxRange ); + AddAreaToOpenList( ladder->m_topRightArea, area, startPos, maxRange ); + } + } + + // check down ladders + ladderList = area->GetLadders( CNavLadder::LADDER_DOWN ); + if (ladderList) + { + FOR_EACH_VEC( (*ladderList), it ) + { + const CNavLadder *ladder = (*ladderList)[ it ].ladder; + + AddAreaToOpenList( ladder->m_bottomArea, area, startPos, maxRange ); + } + } + + if ( (options & EXCLUDE_ELEVATORS) == 0 ) + { + const NavConnectVector &elevatorList = area->GetElevatorAreas(); + FOR_EACH_VEC( elevatorList, it ) + { + CNavArea *elevatorArea = elevatorList[ it ].area; + AddAreaToOpenList( elevatorArea, area, startPos, maxRange ); + } + } + } + } +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Derive your own custom search functor from this interface method for use with SearchSurroundingAreas below. + */ +class ISearchSurroundingAreasFunctor +{ +public: + virtual ~ISearchSurroundingAreasFunctor() { } + + /** + * Perform user-defined action on area. + * Return 'false' to end the search (ie: you found what you were looking for) + */ + virtual bool operator() ( CNavArea *area, CNavArea *priorArea, float travelDistanceSoFar ) = 0; + + // return true if 'adjArea' should be included in the ongoing search + virtual bool ShouldSearch( CNavArea *adjArea, CNavArea *currentArea, float travelDistanceSoFar ) + { + return !adjArea->IsBlocked( TEAM_ANY ); + } + + /** + * Collect adjacent areas to continue the search by calling 'IncludeInSearch' on each + */ + virtual void IterateAdjacentAreas( CNavArea *area, CNavArea *priorArea, float travelDistanceSoFar ) + { + // search adjacent outgoing connections + for( int dir=0; dirGetAdjacentCount( (NavDirType)dir ); + for( int i=0; iGetAdjacentArea( (NavDirType)dir, i ); + + if ( ShouldSearch( adjArea, area, travelDistanceSoFar ) ) + { + IncludeInSearch( adjArea, area ); + } + } + } + } + + // Invoked after the search has completed + virtual void PostSearch( void ) { } + + // consider 'area' in upcoming search steps + void IncludeInSearch( CNavArea *area, CNavArea *priorArea ) + { + if ( area == NULL ) + return; + + if ( !area->IsMarked() ) + { + area->Mark(); + area->SetTotalCost( 0.0f ); + area->SetParent( priorArea ); + + // compute approximate travel distance from start area of search + if ( priorArea ) + { + float distAlong = priorArea->GetCostSoFar(); + distAlong += ( area->GetCenter() - priorArea->GetCenter() ).Length(); + area->SetCostSoFar( distAlong ); + } + else + { + area->SetCostSoFar( 0.0f ); + } + + // adding an area to the open list also marks it + area->AddToOpenList(); + } + } +}; + + +/** + * Do a breadth-first search starting from 'startArea' and continuing outward based on + * adjacent areas that pass the given filter + */ +inline void SearchSurroundingAreas( CNavArea *startArea, ISearchSurroundingAreasFunctor &func, float travelDistanceLimit = -1.0f ) +{ + if ( startArea ) + { + CNavArea::MakeNewMarker(); + CNavArea::ClearSearchLists(); + + startArea->AddToOpenList(); + startArea->SetTotalCost( 0.0f ); + startArea->SetCostSoFar( 0.0f ); + startArea->SetParent( NULL ); + startArea->Mark(); + + CUtlVector< CNavArea * > adjVector; + + while( !CNavArea::IsOpenListEmpty() ) + { + // get next area to check + CNavArea *area = CNavArea::PopOpenList(); + + if ( travelDistanceLimit > 0.0f && area->GetCostSoFar() > travelDistanceLimit ) + continue; + + if ( func( area, area->GetParent(), area->GetCostSoFar() ) ) + { + func.IterateAdjacentAreas( area, area->GetParent(), area->GetCostSoFar() ); + } + else + { + // search aborted + break; + } + } + } + + func.PostSearch(); +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Starting from 'startArea', collect adjacent areas via a breadth-first search continuing outward until + * 'travelDistanceLimit' is reached. + * Areas in the collection will be "marked", returning true for IsMarked(). + * Each area in the collection's GetCostSoFar() will be approximate travel distance from 'startArea'. + */ +inline void CollectSurroundingAreas( CUtlVector< CNavArea * > *nearbyAreaVector, CNavArea *startArea, float travelDistanceLimit = 1500.0f, float maxStepUpLimit = StepHeight, float maxDropDownLimit = 100.0f ) +{ + nearbyAreaVector->RemoveAll(); + + if ( startArea ) + { + CNavArea::MakeNewMarker(); + CNavArea::ClearSearchLists(); + + startArea->AddToOpenList(); + startArea->SetTotalCost( 0.0f ); + startArea->SetCostSoFar( 0.0f ); + startArea->SetParent( NULL ); + startArea->Mark(); + + CUtlVector< CNavArea * > adjVector; + + while( !CNavArea::IsOpenListEmpty() ) + { + // get next area to check + CNavArea *area = CNavArea::PopOpenList(); + + if ( travelDistanceLimit > 0.0f && area->GetCostSoFar() > travelDistanceLimit ) + continue; + + if ( area->GetParent() ) + { + float deltaZ = area->GetParent()->ComputeAdjacentConnectionHeightChange( area ); + + if ( deltaZ > maxStepUpLimit ) + continue; + + if ( deltaZ < -maxDropDownLimit ) + continue; + } + + nearbyAreaVector->AddToTail( area ); + + // mark here to ensure all marked areas are also valid areas that are in the collection + area->Mark(); + + // search adjacent outgoing connections + for( int dir=0; dirGetAdjacentCount( (NavDirType)dir ); + for( int i=0; iGetAdjacentArea( (NavDirType)dir, i ); + + if ( adjArea->IsBlocked( TEAM_ANY ) ) + { + continue; + } + + if ( !adjArea->IsMarked() ) + { + adjArea->SetTotalCost( 0.0f ); + adjArea->SetParent( area ); + + // compute approximate travel distance from start area of search + float distAlong = area->GetCostSoFar(); + distAlong += ( adjArea->GetCenter() - area->GetCenter() ).Length(); + adjArea->SetCostSoFar( distAlong ); + adjArea->AddToOpenList(); + } + } + } + } + } +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Functor that returns lowest cost for farthest away areas + * For use with FindMinimumCostArea() + */ +class FarAwayFunctor +{ +public: + float operator() ( CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder ) + { + if (area == fromArea) + return 9999999.9f; + + return 1.0f/(fromArea->GetCenter() - area->GetCenter()).Length(); + } +}; + +/** + * Functor that returns lowest cost for areas farthest from given position + * For use with FindMinimumCostArea() + */ +class FarAwayFromPositionFunctor +{ +public: + FarAwayFromPositionFunctor( const Vector &pos ) : m_pos( pos ) + { + } + + float operator() ( CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder ) + { + return 1.0f/(m_pos - area->GetCenter()).Length(); + } + +private: + const Vector &m_pos; +}; + + +/** + * Pick a low-cost area of "decent" size + */ +template< typename CostFunctor > +CNavArea *FindMinimumCostArea( CNavArea *startArea, CostFunctor &costFunc ) +{ + const float minSize = 150.0f; + + // collect N low-cost areas of a decent size + enum { NUM_CHEAP_AREAS = 32 }; + struct + { + CNavArea *area; + float cost; + } + cheapAreaSet[ NUM_CHEAP_AREAS ] = {}; + int cheapAreaSetCount = 0; + + FOR_EACH_VEC( TheNavAreas, iter ) + { + CNavArea *area = TheNavAreas[iter]; + + // skip the small areas + if ( area->GetSizeX() < minSize || area->GetSizeY() < minSize) + continue; + + // compute cost of this area + + // HPE_FIX[pfreese]: changed this to only pass three parameters, in accord with the two functors above + float cost = costFunc( area, startArea, NULL ); + + if (cheapAreaSetCount < NUM_CHEAP_AREAS) + { + cheapAreaSet[ cheapAreaSetCount ].area = area; + cheapAreaSet[ cheapAreaSetCount++ ].cost = cost; + } + else + { + // replace most expensive cost if this is cheaper + int expensive = 0; + for( int i=1; i cheapAreaSet[expensive].cost) + expensive = i; + + if (cheapAreaSet[expensive].cost > cost) + { + cheapAreaSet[expensive].area = area; + cheapAreaSet[expensive].cost = cost; + } + } + } + + if (cheapAreaSetCount) + { + // pick one of the areas at random + return cheapAreaSet[ RandomInt( 0, cheapAreaSetCount-1 ) ].area; + } + else + { + // degenerate case - no decent sized areas - pick a random area + int numAreas = TheNavAreas.Count(); + int which = RandomInt( 0, numAreas-1 ); + + FOR_EACH_VEC( TheNavAreas, iter ) + { + if (which-- == 0) + return TheNavAreas[iter]; + } + + } + return cheapAreaSet[ RandomInt( 0, cheapAreaSetCount-1 ) ].area; +} + + +//-------------------------------------------------------------------------------------------------------- +// +// Given a vector of CNavAreas (or derived types), 'inVector', populate 'outVector' with a randomly shuffled set +// of 'maxCount' areas that are at least 'minSeparation' travel distance apart from each other. +// +template< typename T > +void SelectSeparatedShuffleSet( int maxCount, float minSeparation, const CUtlVector< T * > &inVector, CUtlVector< T * > *outVector ) +{ + if ( !outVector ) + return; + + outVector->RemoveAll(); + + CUtlVector< T * > shuffledVector; + + int i, j; + + for( i=0; i 1 ) + { + int k = RandomInt( 0, n-1 ); + n--; + + T *tmp = shuffledVector[n]; + shuffledVector[n] = shuffledVector[k]; + shuffledVector[k] = tmp; + } + + // enforce minSeparation between shuffled areas + for( i=0; i nearVector; + CollectSurroundingAreas( &nearVector, area, minSeparation, 2.0f * StepHeight, 2.0f * StepHeight ); + + for( j=0; jAddToTail( area ); + + if ( outVector->Count() >= maxCount ) + return; + } + } +} + + +#endif // _NAV_PATHFIND_H_ diff --git a/game/server/ndebugoverlay.h b/game/server/ndebugoverlay.h new file mode 100644 index 0000000..7b0a64a --- /dev/null +++ b/game/server/ndebugoverlay.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Namespace for functions dealing with Debug Overlays +// +// $NoKeywords: $ +//=============================================================================// +#ifndef NDEBUGOVERLAY_H +#define NDEBUGOVERLAY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "debugoverlay_shared.h" + +// An overlay line +struct OverlayLine_t +{ + Vector origin; + Vector dest; + int r; + int g; + int b; + bool noDepthTest; + bool draw; +}; + +extern void UTIL_AddDebugLine( const Vector &startPos, const Vector &endPos, bool noDepthTest, bool testLOS ); +extern void UTIL_DrawPositioningOverlay( float flCrossDistance ); +extern void UTIL_DrawOverlayLines( void ); + +extern void DebugDrawLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, int r, int g, int b, bool test, float duration ); + +#endif // NDEBUGOVERLAY_H diff --git a/game/server/networkstringtable_gamedll.h b/game/server/networkstringtable_gamedll.h new file mode 100644 index 0000000..20965aa --- /dev/null +++ b/game/server/networkstringtable_gamedll.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NETWORKSTRINGTABLE_GAMEDLL_H +#define NETWORKSTRINGTABLE_GAMEDLL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkstringtabledefs.h" + +class CStringTableSaveRestoreOps; + +// String tables used by the game DLL +#define MAX_VGUI_SCREEN_STRING_BITS 8 +#define MAX_VGUI_SCREEN_STRINGS ( 1 << MAX_VGUI_SCREEN_STRING_BITS ) +#define VGUI_SCREEN_INVALID_STRING ( MAX_VGUI_SCREEN_STRINGS - 1 ) + +#define MAX_MATERIAL_STRING_BITS 10 +#define MAX_MATERIAL_STRINGS ( 1 << MAX_MATERIAL_STRING_BITS ) +#define OVERLAY_MATERIAL_INVALID_STRING ( MAX_MATERIAL_STRINGS - 1 ) + +#define MAX_CHOREO_SCENES_STRING_BITS 13 +#define MAX_CHOREO_SCENES_STRINGS ( 1 << MAX_CHOREO_SCENES_STRING_BITS ) +#define CHOREO_SCENES_INVALID_STRING ( MAX_CHOREO_SCENES_STRINGS - 1 ) + +#define MAX_PARTICLESYSTEMS_STRING_BITS 12 +#define MAX_PARTICLESYSTEMS_STRINGS ( 1 << MAX_PARTICLESYSTEMS_STRING_BITS ) +#define PARTICLESYSTEMS_INVALID_STRING ( MAX_PARTICLESYSTEMS_STRINGS - 1 ) + +extern INetworkStringTableContainer *networkstringtable; +extern INetworkStringTable *g_pStringTableVguiScreen; +extern INetworkStringTable *g_pStringTableEffectDispatch; +extern INetworkStringTable *g_pStringTableClientSideChoreoScenes; + +#define MAX_INFOPANEL_STRINGS 128 + +// save/load +extern CStringTableSaveRestoreOps g_VguiScreenStringOps; + + +#endif // NETWORKSTRINGTABLE_GAMEDLL_H diff --git a/game/server/npc_talker.h b/game/server/npc_talker.h new file mode 100644 index 0000000..c865417 --- /dev/null +++ b/game/server/npc_talker.h @@ -0,0 +1,254 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef TALKNPC_H +#define TALKNPC_H + +#ifdef POSIX +#undef time +#include +#endif + +#ifndef _XBOX +#undef min +#undef max +#pragma warning(push) +#include +#pragma warning(pop) +#endif + +#ifdef _WIN32 +#pragma once +#endif + +// the include monkey's with the MAX() define, unbreak it +#undef MINMAX_H +#include "minmax.h" + +#include "ai_playerally.h" + +#include "soundflags.h" + +#include "ai_task.h" +#include "ai_schedule.h" +#include "ai_default.h" +#include "ai_speech.h" +#include "ai_basenpc.h" +#include "ai_behavior.h" +#include "ai_behavior_follow.h" + +#include "tier0/memdbgon.h" + +//========================================================= +// Talking NPC base class +// Used for scientists and barneys +//========================================================= + +#define TLK_CFRIENDS 4 + +//============================================================================= +// >> CNPCSimpleTalker +//============================================================================= + +#define MONOLOGNAME_LEN 16 // sentence names passed as monolog may be no longer than this. +#define AI_SP_START_MONOLOG '~' +#define AI_SP_MONOLOG_LINE '@' + +class CNPCSimpleTalker; + +class CNPCSimpleTalkerExpresser : public CAI_ComponentWithOuter +{ +public: + CNPCSimpleTalkerExpresser( CNPCSimpleTalker *pOuter ) + : CAI_ComponentWithOuter( pOuter ) + { + EndMonolog(); + } + + virtual int SpeakRawSentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL ); + + // -------------------------------- + // + // Monologue operations + // + + bool HasMonolog( void ) { return m_iMonologIndex != -1; }; + void BeginMonolog( char *pszSentenceName, CBaseEntity *pListener ); + void EndMonolog( void ); + void SpeakMonolog( void ); + + void SuspendMonolog( float flInterval ); + void ResumeMonolog( void ); + + CBaseEntity *GetMonologueTarget() { return m_hMonologTalkTarget.Get(); } + + // -------------------------------- + // + // Monologue data + // + char m_szMonologSentence[MONOLOGNAME_LEN]; // The name of the sentence group for the monolog I'm speaking. + int m_iMonologIndex; // Which sentence from the group I should be speaking. + bool m_fMonologSuspended; + EHANDLE m_hMonologTalkTarget; // Who I'm trying to deliver my monolog to. + + DECLARE_SIMPLE_DATADESC(); +}; + +//------------------------------------- + +class CNPCSimpleTalker : public CAI_PlayerAlly +{ + DECLARE_CLASS( CNPCSimpleTalker, CAI_PlayerAlly ); +public: + void Precache( void ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual CAI_Expresser *CreateExpresser() { return new CNPCSimpleTalkerExpresser(this); } + + virtual void StartFollowing( CBaseEntity *pLeader ) { m_FollowBehavior.SetFollowTarget( pLeader ); DeferSchedulingToBehavior( &m_FollowBehavior ); } + virtual void StopFollowing( ) { m_FollowBehavior.SetFollowTarget( NULL ); DeferSchedulingToBehavior( NULL ); } + CBaseEntity *GetFollowTarget( void ) { return m_FollowBehavior.GetFollowTarget(); } + + virtual void OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ); + bool OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule ); + + int PlayScriptedSentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, bool bConcurrent, CBaseEntity *pListener ); + virtual void FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Event_Killed( const CTakeDamageInfo &info ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + bool CreateBehaviors() + { + AddBehavior( &m_FollowBehavior ); + return BaseClass::CreateBehaviors(); + } + + void BuildScheduleTestBits( void ); + void PrescheduleThink( void ); + virtual int SelectSchedule( void ); + virtual int SelectNonCombatSpeechSchedule(); + void StartTask( const Task_t *pTask ); + void RunTask( const Task_t *pTask ); + void HandleAnimEvent( animevent_t *pEvent ); + Activity NPC_TranslateActivity( Activity newActivity ); + + virtual void OnStartingFollow( CBaseEntity *pTarget ); + virtual void OnStoppingFollow( CBaseEntity *pTarget ); + + virtual void DeferAllIdleSpeech( float flDelay, CAI_BaseNPC *pIgnore = NULL ); + bool ShouldSpeakRandom( int iChance, float flModifier ); + + // For following + virtual void DeclineFollowing( void ) {} + void LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ); + + float GetUseTime() const { return m_useTime; } + + //========================================================= + // TalkNPC schedules + //========================================================= + enum + { + SCHED_TALKER_IDLE_RESPONSE = BaseClass::NEXT_SCHEDULE, + SCHED_TALKER_IDLE_SPEAK, + SCHED_TALKER_IDLE_HELLO, + SCHED_TALKER_IDLE_STOP_SHOOTING, + SCHED_TALKER_IDLE_WATCH_CLIENT, + SCHED_TALKER_IDLE_WATCH_CLIENT_STARE, + SCHED_TALKER_IDLE_EYE_CONTACT, + SCHED_TALKER_BETRAYED, + + // !ALWAYS LAST! + NEXT_SCHEDULE, + }; + + //========================================================= + // TalkNPC tasks + //========================================================= + enum + { + TASK_TALKER_RESPOND = BaseClass::NEXT_TASK, // say my response + TASK_TALKER_SPEAK, // question or remark + TASK_TALKER_HELLO, // Try to say hello to player + TASK_TALKER_BETRAYED, // Player killed an ally + TASK_TALKER_HEADRESET, // reset head position + TASK_TALKER_STOPSHOOTING, // tell player to stop shooting friend + TASK_TALKER_STARE, // let the player know I know he's staring at me. + TASK_TALKER_LOOK_AT_CLIENT,// faces player if not moving and not talking and in idle. + TASK_TALKER_CLIENT_STARE, // same as look at client, but says something if the player stares. + TASK_TALKER_EYECONTACT, // maintain eyecontact with person who I'm talking to + TASK_TALKER_IDEALYAW, // set ideal yaw to face who I'm talking to + TASK_FIND_LOCK_HINTNODE_HEALTH, // Find & lock a nearby healthkit hintnode to heal myself at + TASK_TALKER_WAIT_FOR_SEMAPHORE, + + // !ALWAYS LAST! + NEXT_TASK, + }; + +//private: + virtual bool IsValidSpeechTarget( int flags, CBaseEntity *pEntity ); + + CBaseEntity *FindNearestFriend(bool fPlayer); + + bool IsOkToSpeak( void ); + + void SayHelloToPlayer( CBaseEntity *pPlayer ); + virtual bool CanSayHello( void ); + virtual int FIdleHello( void ); + + // Inputs + void InputIdleRespond( inputdata_t &inputdata ); + + // Conversations / communication + void IdleRespond( void ); + int FIdleSpeak( void ); + void FIdleSpeakWhileMoving( void ); + int FIdleStare( void ); + bool SpeakQuestionFriend( CBaseEntity *pFriend ); + bool SpeakAnswerFriend( CBaseEntity *pFriend ); + void TrySmellTalk( void ); + + virtual void SetAnswerQuestion( CNPCSimpleTalker *pSpeaker ); + + bool ShouldSuspendMonolog( void ); + bool ShouldResumeMonolog( void ); + void OnResumeMonolog() { Speak( TLK_RESUME ); } + + int m_nSpeak; // number of times initiated talking + float m_flNextIdleSpeechTime; + + static char *m_szFriends[TLK_CFRIENDS]; // array of friend names + CBaseEntity *EnumFriends( CBaseEntity *pentPrevious, int listNumber, bool bTrace ); + + virtual int FriendNumber( int arrayNumber ) { return arrayNumber; } + void ShutUpFriends( void ); + void AlertFriends( CBaseEntity *pKiller ); + + string_t m_iszUse; // Custom +USE sentence group (follow) + string_t m_iszUnUse; // Custom +USE sentence group (stop following) + +protected: + CAI_FollowBehavior m_FollowBehavior; + float m_useTime; // Don't allow +USE until this time + + //--------------------------------- + + DECLARE_DATADESC(); +#ifndef _XBOX + DEFINE_CUSTOM_AI; +#else +public: + DEFINE_CUSTOM_AI; +private: +#endif +}; + +#include "tier0/memdbgoff.h" + +#endif //TALKNPC_H diff --git a/game/server/npc_vehicledriver.h b/game/server/npc_vehicledriver.h new file mode 100644 index 0000000..d59b443 --- /dev/null +++ b/game/server/npc_vehicledriver.h @@ -0,0 +1,197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: NPC that drives vehicles +// +//=============================================================================// + +#ifndef NPC_VEHICLEDRIVER_H +#define NPC_VEHICLEDRIVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_basenpc.h" + +class CPropVehicleDriveable; + +//------------------------------------ +// Spawnflags +//------------------------------------ +#define SF_VEHICLEDRIVER_INACTIVE (1 << 16) + +//========================================================= +// Custom schedules +//========================================================= +enum +{ + SCHED_VEHICLEDRIVER_INACTIVE = LAST_SHARED_SCHEDULE, + SCHED_VEHICLEDRIVER_COMBAT_WAIT, + SCHED_VEHICLEDRIVER_DRIVE_PATH, + + LAST_VEHICLEDRIVER_SCHED, +}; + +//========================================================= +// Custom tasks +//========================================================= +enum +{ + TASK_VEHICLEDRIVER_GET_PATH = LAST_SHARED_TASK, + + LAST_VEHICLEDRIVER_TASK, +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CVehicleWaypoint +{ +public: + CVehicleWaypoint( Vector &pPrevPoint, Vector &pCurPoint, Vector &pNextPoint, Vector &pNextNextPoint ) + { + splinePoints[0] = pPrevPoint; + splinePoints[1] = pCurPoint; + splinePoints[2] = pNextPoint; + splinePoints[3] = pNextNextPoint; + + RecalculateSpline(); + } + + void RecalculateSpline( void ) + { + planeWaypoint.normal = (splinePoints[2] - splinePoints[1]); + VectorNormalize( planeWaypoint.normal ); + planeWaypoint.type = PLANE_ANYZ; + planeWaypoint.dist = DotProduct( planeWaypoint.normal, splinePoints[2] ); + planeWaypoint.signbits = SignbitsForPlane(&planeWaypoint); + // TODO: Use the vehicle's absbox + iInitialPlaneSide = BoxOnPlaneSide( -Vector(32,32,32), Vector(32,32,32), &planeWaypoint ); + + // Hackily calculate a length for the spline. Subdivide & measure. + flSplineLength = 0; + Vector vecPrev = splinePoints[1]; + const int iDivs = 10; + for ( int i = 1; i <= iDivs; i++ ) + { + Vector vecCurr; + float flT = (float)i / (float)iDivs; + Catmull_Rom_Spline( splinePoints[0], splinePoints[1], splinePoints[2], splinePoints[3], flT, vecCurr ); + flSplineLength += (vecCurr - vecPrev).Length(); + vecPrev = vecCurr; + } + } + + Vector GetPointAt( float flT ) + { + Vector vecCurr(0,0,0); + Catmull_Rom_Spline( splinePoints[0], splinePoints[1], splinePoints[2], splinePoints[3], flT, vecCurr ); + return vecCurr; + } + + Vector GetTangentAt( float flT ) + { + Vector vecCurr(0,0,0); + Catmull_Rom_Spline_Tangent( splinePoints[0], splinePoints[1], splinePoints[2], splinePoints[3], flT, vecCurr ); + return vecCurr; + } + + float GetLength( void ) + { + return flSplineLength; + } + +public: + int iInitialPlaneSide; + float flSplineLength; + Vector splinePoints[4]; + cplane_t planeWaypoint; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CNPC_VehicleDriver : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_VehicleDriver, CAI_BaseNPC ); +public: + DECLARE_DATADESC(); + DEFINE_CUSTOM_AI; + + CNPC_VehicleDriver( void ); + ~CNPC_VehicleDriver( void ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void Activate( void ); + virtual void OnRestore(); + virtual void UpdateOnRemove( void ); + + // AI + void UpdateEfficiency( bool bInPVS ) { SetEfficiency( ( GetSleepState() != AISS_AWAKE ) ? AIE_DORMANT : AIE_NORMAL ); SetMoveEfficiency( AIME_NORMAL ); } + virtual void PrescheduleThink( void ); + virtual int TranslateSchedule( int scheduleType ); + virtual int SelectSchedule( void ); + virtual void StartTask( const Task_t *pTask ); + virtual void RunTask( const Task_t *pTask ); + virtual void GatherEnemyConditions( CBaseEntity *pEnemy ); + virtual int RangeAttack1Conditions( float flDot, float flDist ); + virtual int RangeAttack2Conditions( float flDot, float flDist ); + + // Driving + virtual void DriveVehicle( void ); + virtual bool OverrideMove( float flInterval ); + bool OverridePathMove( float flInterval ); + void CalculatePostPoints( void ); + bool WaypointReached( void ); + float GetDefaultNavGoalTolerance(); + void RecalculateSpeeds( void ); + void ClearWaypoints( void ); + void CheckForTeleport( void ); + + int BloodColor( void ) { return DONT_BLEED; } + +#ifdef HL2_DLL + Class_T Classify( void ) { return CLASS_METROPOLICE; } +#else + Class_T Classify( void ) { return CLASS_NONE; } +#endif + + Disposition_t IRelationType( CBaseEntity *pTarget ); + + // Inputs + void InputSetDriversMaxSpeed( inputdata_t &inputdata ); + void InputSetDriversMinSpeed( inputdata_t &inputdata ); + void InputStartForward( inputdata_t &inputdata ); + void InputStop( inputdata_t &inputdata ); + void InputStartFiring( inputdata_t &inputdata ); + void InputStopFiring( inputdata_t &inputdata ); + void InputGotoPathCorner( inputdata_t &inputdata ); + +public: + string_t m_iszVehicleName; + IServerVehicle *m_pVehicleInterface; + EHANDLE m_hVehicleEntity; + + // Path driving + CVehicleWaypoint *m_Waypoints[2]; + CVehicleWaypoint *m_pCurrentWaypoint; + CVehicleWaypoint *m_pNextWaypoint; + Vector m_vecDesiredVelocity; + Vector m_vecDesiredPosition; + Vector m_vecPrevPoint; + Vector m_vecPrevPrevPoint; + Vector m_vecPostPoint; + Vector m_vecPostPostPoint; + float m_flDistanceAlongSpline; + float m_flDriversMaxSpeed; + float m_flDriversMinSpeed; + + // Speed + float m_flMaxSpeed; // Maximum speed this driver will go + float m_flGoalSpeed; // Desired speed + float m_flInitialSpeed; + float m_flSteering; +}; + +#endif // NPC_VEHICLEDRIVER_H diff --git a/game/server/particle_fire.h b/game/server/particle_fire.h new file mode 100644 index 0000000..33ecce2 --- /dev/null +++ b/game/server/particle_fire.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef PARTICLE_FIRE_H +#define PARTICLE_FIRE_H + + +#include "baseparticleentity.h" + + +class CParticleFire : public CBaseParticleEntity +{ + DECLARE_DATADESC(); + +public: + CParticleFire(); + + DECLARE_CLASS( CParticleFire, CBaseParticleEntity ); + + DECLARE_SERVERCLASS(); + + // The client shoots a ray out and starts creating fire where it hits. + CNetworkVector( m_vOrigin ); + CNetworkVector( m_vDirection ); +}; + + +#endif + + + diff --git a/game/server/particle_light.h b/game/server/particle_light.h new file mode 100644 index 0000000..cc7d928 --- /dev/null +++ b/game/server/particle_light.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PARTICLE_LIGHT_H +#define PARTICLE_LIGHT_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" + + +//================================================== +// CParticleLight. These are tied to +//================================================== + +#define PARTICLELIGHT_ENTNAME "env_particlelight" + +class CParticleLight : public CServerOnlyPointEntity +{ +public: + DECLARE_CLASS( CParticleLight, CServerOnlyPointEntity ); + DECLARE_DATADESC(); + + CParticleLight(); + + +public: + float m_flIntensity; + Vector m_vColor; // 0-255 + string_t m_PSName; // Name of the particle system entity this light affects. + bool m_bDirectional; +}; + + +#endif // PARTICLE_LIGHT_H diff --git a/game/server/particle_smokegrenade.h b/game/server/particle_smokegrenade.h new file mode 100644 index 0000000..925b11d --- /dev/null +++ b/game/server/particle_smokegrenade.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef PARTICLE_SMOKEGRENADE_H +#define PARTICLE_SMOKEGRENADE_H + + +#include "baseparticleentity.h" + + +#define PARTICLESMOKEGRENADE_ENTITYNAME "env_particlesmokegrenade" + + +class ParticleSmokeGrenade : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( ParticleSmokeGrenade, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + ParticleSmokeGrenade(); + + virtual int UpdateTransmitState( void ); + +public: + + // Tell the client entity to start filling the volume. + void FillVolume(); + + // Set the times it fades out at. + void SetFadeTime(float startTime, float endTime); + + // Set time to fade out relative to current time + void SetRelativeFadeTime(float startTime, float endTime); + + +public: + + // Stage 0 (default): make a smoke trail that follows the entity it's following. + // Stage 1 : fill a volume with smoke. + CNetworkVar( unsigned char, m_CurrentStage ); + + CNetworkVar( float, m_flSpawnTime ); + + // When to fade in and out. + CNetworkVar( float, m_FadeStartTime ); + CNetworkVar( float, m_FadeEndTime ); +}; + + +#endif + + diff --git a/game/server/particle_system.h b/game/server/particle_system.h new file mode 100644 index 0000000..ecf758c --- /dev/null +++ b/game/server/particle_system.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef PARTICLE_SYSTEM_H +#define PARTICLE_SYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" + +//----------------------------------------------------------------------------- +// Purpose: An entity that spawns and controls a particle system +//----------------------------------------------------------------------------- +class CParticleSystem : public CBaseEntity +{ + DECLARE_CLASS( CParticleSystem, CBaseEntity ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CParticleSystem(); + + virtual void Precache( void ); + virtual void Spawn( void ); + virtual void Activate( void ); + virtual int UpdateTransmitState(void); + + void StartParticleSystem( void ); + void StopParticleSystem( void ); + + void InputStart( inputdata_t &inputdata ); + void InputStop( inputdata_t &inputdata ); + void StartParticleSystemThink( void ); + + enum { kMAXCONTROLPOINTS = 63 }; ///< actually one less than the total number of cpoints since 0 is assumed to be me + +protected: + + /// Load up and resolve the entities that are supposed to be the control points + void ReadControlPointEnts( void ); + + bool m_bStartActive; + string_t m_iszEffectName; + + CNetworkVar( bool, m_bActive ); + CNetworkVar( int, m_iEffectIndex ) + CNetworkVar( float, m_flStartTime ); // Time at which this effect was started. This is used after restoring an active effect. + + string_t m_iszControlPointNames[kMAXCONTROLPOINTS]; + CNetworkArray( EHANDLE, m_hControlPointEnts, kMAXCONTROLPOINTS ); + CNetworkArray( unsigned char, m_iControlPointParents, kMAXCONTROLPOINTS ); + CNetworkVar( bool, m_bWeatherEffect ); +}; + +#endif // PARTICLE_SYSTEM_H diff --git a/game/server/pathtrack.h b/game/server/pathtrack.h new file mode 100644 index 0000000..b88e44c --- /dev/null +++ b/game/server/pathtrack.h @@ -0,0 +1,158 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PATHTRACK_H +#define PATHTRACK_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "entityoutput.h" +#include "shareddefs.h" + + +//----------------------------------------------------------------------------- +// Spawnflag for CPathTrack +//----------------------------------------------------------------------------- +#define SF_PATH_DISABLED 0x00000001 +//#define SF_PATH_FIREONCE 0x00000002 +#define SF_PATH_ALTREVERSE 0x00000004 +#define SF_PATH_DISABLE_TRAIN 0x00000008 +#define SF_PATH_TELEPORT 0x00000010 +#define SF_PATH_UPHILL 0x00000020 +#define SF_PATH_DOWNHILL 0x00000040 +#define SF_PATH_ALTERNATE 0x00008000 + + +enum TrackOrientationType_t +{ + TrackOrientation_Fixed = 0, + TrackOrientation_FacePath, + TrackOrientation_FacePathAngles, +}; + + +//----------------------------------------------------------------------------- +// Paths! +//----------------------------------------------------------------------------- +class CPathTrack : public CPointEntity +{ + DECLARE_CLASS( CPathTrack, CPointEntity ); + +public: + CPathTrack(); + + void Spawn( void ); + void Activate( void ); + void DrawDebugGeometryOverlays(); + + void ToggleAlternatePath( void ); + void EnableAlternatePath( void ); + void DisableAlternatePath( void ); + bool HasAlternathPath() const; + + void TogglePath( void ); + void EnablePath( void ); + void DisablePath( void ); + + static CPathTrack *ValidPath( CPathTrack *ppath, int testFlag = true ); // Returns ppath if enabled, NULL otherwise + + CPathTrack *GetNextInDir( bool bForward ); + CPathTrack *GetNext( void ); + CPathTrack *GetPrevious( void ); + + CPathTrack *Nearest( const Vector &origin ); + //CPathTrack *LookAhead( Vector &origin, float dist, int move ); + CPathTrack *LookAhead( Vector &origin, float dist, int move, CPathTrack **pNextNext = NULL ); + + TrackOrientationType_t GetOrientationType(); + QAngle GetOrientation( bool bForwardDir ); + + CHandle m_pnext; + CHandle m_pprevious; + CHandle m_paltpath; + + float GetRadius() const { return m_flRadius; } + + // These four methods help for circular path checking. Call BeginIteration + // before iterating, EndInteration afterwards. Call Visit on each path in the + // list. Then you can use HasBeenVisited to see if you've visited the node + // already, which means you've got a circular or lasso path. You can use the + // macro BEGIN_PATH_TRACK_ITERATION below to simplify the calls to + // BeginInteration + EndIteration. + static void BeginIteration(); + static void EndIteration(); + void Visit(); + bool HasBeenVisited() const; + + bool IsUpHill(){ return ( FBitSet( m_spawnflags, SF_PATH_UPHILL ) ) ? true : false; } + bool IsDownHill(){ return ( FBitSet( m_spawnflags, SF_PATH_DOWNHILL ) ) ? true : false; } + int GetHillType() + { + int iRetVal = HILL_TYPE_NONE; + if ( IsUpHill() ) + { + iRetVal = HILL_TYPE_UPHILL; + } + else if ( IsDownHill() ) + { + iRetVal = HILL_TYPE_DOWNHILL; + } + + return iRetVal; + } + + bool IsDisabled( void ){ return FBitSet( m_spawnflags, SF_PATH_DISABLED ); } + + void InputPass( inputdata_t &inputdata ); + void InputTeleport( inputdata_t &inputdata ); + + void InputToggleAlternatePath( inputdata_t &inputdata ); + void InputEnableAlternatePath( inputdata_t &inputdata ); + void InputDisableAlternatePath( inputdata_t &inputdata ); + + void InputTogglePath( inputdata_t &inputdata ); + void InputEnablePath( inputdata_t &inputdata ); + void InputDisablePath( inputdata_t &inputdata ); + +private: + void Project( CPathTrack *pstart, CPathTrack *pend, Vector &origin, float dist ); + void SetPrevious( CPathTrack *pprevious ); + void Link( void ); + + static CPathTrack *Instance( edict_t *pent ); + + DECLARE_DATADESC(); + + float m_flRadius; + float m_length; + string_t m_altName; + int m_nIterVal; + TrackOrientationType_t m_eOrientationType; + + COutputEvent m_OnPass; + COutputEvent m_OnTeleport; + + static int s_nCurrIterVal; + static bool s_bIsIterating; +}; + +//----------------------------------------------------------------------------- +// Used to make sure circular iteration works all nice +//----------------------------------------------------------------------------- +#define BEGIN_PATH_TRACK_ITERATION() CPathTrackVisitor _visit + +class CPathTrackVisitor +{ +public: + CPathTrackVisitor() { CPathTrack::BeginIteration(); } + ~CPathTrackVisitor() { CPathTrack::EndIteration(); } +}; + + + +#endif // PATHTRACK_H diff --git a/game/server/phys_controller.h b/game/server/phys_controller.h new file mode 100644 index 0000000..1492a50 --- /dev/null +++ b/game/server/phys_controller.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYS_CONTROLLER_H +#define PHYS_CONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + + +CBaseEntity *CreateKeepUpright( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner, float flAngularLimit, bool bActive ); + +AngularImpulse ComputeRotSpeedToAlignAxes( const Vector &testAxis, const Vector &alignAxis, const AngularImpulse ¤tSpeed, + float damping, float scale, float maxSpeed ); + +#endif // PHYS_CONTROLLER_H diff --git a/game/server/physconstraint.h b/game/server/physconstraint.h new file mode 100644 index 0000000..8031ec2 --- /dev/null +++ b/game/server/physconstraint.h @@ -0,0 +1,146 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Physics constraint entities +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PHYSCONSTRAINT_H +#define PHYSCONSTRAINT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vphysics/constraints.h" + +struct hl_constraint_info_t +{ + hl_constraint_info_t() + { + pObjects[0] = pObjects[1] = NULL; + pGroup = NULL; + anchorPosition[0].Init(); + anchorPosition[1].Init(); + swapped = false; + massScale[0] = massScale[1] = 1.0f; + } + Vector anchorPosition[2]; + IPhysicsObject *pObjects[2]; + IPhysicsConstraintGroup *pGroup; + float massScale[2]; + bool swapped; +}; + +abstract_class CPhysConstraint : public CLogicalEntity +{ + DECLARE_CLASS( CPhysConstraint, CLogicalEntity ); +public: + + CPhysConstraint(); + ~CPhysConstraint(); + + DECLARE_DATADESC(); + + void Spawn( void ); + void Precache( void ); + void Activate( void ); + + void ClearStaticFlag( IPhysicsObject *pObj ); + + virtual void Deactivate(); + + void OnBreak( void ); + + void InputBreak( inputdata_t &inputdata ); + + void InputOnBreak( inputdata_t &inputdata ); + + void InputTurnOn( inputdata_t &inputdata ); + + void InputTurnOff( inputdata_t &inputdata ); + + int DrawDebugTextOverlays(); + + void DrawDebugGeometryOverlays(); + + void GetBreakParams( constraint_breakableparams_t ¶ms, const hl_constraint_info_t &info ); + + // the notify system calls this on the constrained entities - used to detect & follow teleports + void NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t ¶ms ); + + // gets called at setup time on first init and restore + virtual void OnConstraintSetup( hl_constraint_info_t &info ); + + // return the internal constraint object (used by sound gadgets) + inline IPhysicsConstraint *GetPhysConstraint() { return m_pConstraint; } + + string_t GetNameAttach1( void ){ return m_nameAttach1; } + string_t GetNameAttach2( void ){ return m_nameAttach2; } + +protected: + void GetConstraintObjects( hl_constraint_info_t &info ); + void SetupTeleportationHandling( hl_constraint_info_t &info ); + bool ActivateConstraint( void ); + virtual IPhysicsConstraint *CreateConstraint( IPhysicsConstraintGroup *pGroup, const hl_constraint_info_t &info ) = 0; + + IPhysicsConstraint *m_pConstraint; + + // These are "template" values used to construct the hinge + string_t m_nameAttach1; + string_t m_nameAttach2; + string_t m_breakSound; + string_t m_nameSystem; + float m_forceLimit; + float m_torqueLimit; + unsigned int m_teleportTick; + float m_minTeleportDistance; + + COutputEvent m_OnBreak; +}; + +//----------------------------------------------------------------------------- +// Purpose: Fixed breakable constraint +//----------------------------------------------------------------------------- +class CPhysFixed : public CPhysConstraint +{ + DECLARE_CLASS( CPhysFixed, CPhysConstraint ); +public: + IPhysicsConstraint *CreateConstraint( IPhysicsConstraintGroup *pGroup, const hl_constraint_info_t &info ); + + // just for debugging - move to the position of the reference entity + void MoveToRefPosition() + { + if ( m_pConstraint ) + { + matrix3x4_t xformRef; + m_pConstraint->GetConstraintTransform( &xformRef, NULL ); + IPhysicsObject *pObj = m_pConstraint->GetReferenceObject(); + if ( pObj && pObj->IsMoveable() ) + { + Vector pos, posWorld; + MatrixPosition( xformRef, pos ); + pObj->LocalToWorld(&posWorld, pos); + SetAbsOrigin(posWorld); + } + } + } + int DrawDebugTextOverlays() + { + if ( m_debugOverlays & OVERLAY_TEXT_BIT ) + { + MoveToRefPosition(); + } + return BaseClass::DrawDebugTextOverlays(); + } + void DrawDebugGeometryOverlays() + { + if ( m_debugOverlays & (OVERLAY_BBOX_BIT|OVERLAY_PIVOT_BIT|OVERLAY_ABSBOX_BIT) ) + { + MoveToRefPosition(); + } + BaseClass::DrawDebugGeometryOverlays(); + } +}; + +#endif // PHYSCONSTRAINT_H + diff --git a/game/server/physconstraint_sounds.h b/game/server/physconstraint_sounds.h new file mode 100644 index 0000000..71b9a57 --- /dev/null +++ b/game/server/physconstraint_sounds.h @@ -0,0 +1,291 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Data types used inside constraints for the purpose of playing sounds +// during movement. +// +//=============================================================================// + +#ifndef PHYSCONSTRAINT_SOUNDS_H +#define PHYSCONSTRAINT_SOUNDS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "soundenvelope.h" + + +/** \brief Class to store a sampled history of velocity for an object -- used for certain sound calculations + +Although this contains only one sample for now, it exists as an interface +so as to make simpler the possibility of moving to a ring buffer +implementation in the future. + +The "sample rate" variable is not nominal: it should be used to specify +the ClientThink() interval. + +Be sure to use the beginSampling() function for the first sample, and +addSample() thereafter: this will be relevant and necessary for a ring +buffer implementation (which will have to perform certain initialization). +*/ +class VelocitySampler +{ +public: + /* + enum + { + HISTORY_DEPTH_LOG = 3, // < log-base-2 of the sampler's array depth + HISTORY_DEPTH = (1 << VELOCITY_SAMPLER_HISTORY_DEPTH_LOG), + }; + */ + + /// Return the internally stored sample rate. + inline float getSampleRate() + { + return m_fIdealSampleRate; + } + + + /// Store off the first recorded sample for the given object. + inline void BeginSampling(const Vector &relativeVelocity); + + /// Record a sample. Do this LAST, after calling hasReversed() et al. + inline void AddSample(const Vector &relativeVelocity); + + /// Using the sample history, determine if the object has reversed direction + /// with at least the given acceleration (in units/sec^2). + int HasReversed(const Vector &relativeVelocity, const float thresholdAcceleration[], const unsigned short numThresholds); + + /// Call this in spawn(). (Not a constructor because those are difficult to use in entities.) + void Initialize(float samplerate); + + + /// A convenience function for extracting the linear velocity of one object relative to another. + inline static Vector GetRelativeVelocity(IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame); + + /// A convenience function for extracting the angular velocity of one object relative to another. + inline static Vector GetRelativeAngularVelocity(IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame); + + +protected: + Vector m_prevSample; + float m_fPrevSampleTime; + + float m_fIdealSampleRate; + +}; + +struct SimpleConstraintSoundProfile +{ + // define the indices of the sound points: + enum + { + kMIN_THRESHOLD, ///< below this no sound is played + kMIN_FULL, ///< at this velocity sound is at its loudest + + kHIGHWATER, ///< high water mark for this enum + } eKeypoints; + + float m_keyPoints[kHIGHWATER]; + + /// Number of entries in the reversal sound array + enum { kREVERSAL_SOUND_ARRAY_SIZE = 3 }; + + /// Acceleration threshold for playing the hard-reverse sound. Divided into sections. + /// Below the 0th threshold no sound will play. + float m_reversalSoundThresholds[kREVERSAL_SOUND_ARRAY_SIZE]; + + /// Get volume for given velocity [0..1] + float GetVolume(float inVel); +}; + +float SimpleConstraintSoundProfile::GetVolume(float inVel) +{ + // clamped lerp on 0-1 + if (inVel <= m_keyPoints[kMIN_THRESHOLD]) + { + return 0; + } + else if (inVel >= m_keyPoints[kMIN_FULL]) + { + return 1; + } + else // lerp... + { + return (inVel - m_keyPoints[kMIN_THRESHOLD])/(m_keyPoints[kMIN_FULL] - m_keyPoints[kMIN_THRESHOLD]); + } +} + +class CPhysConstraint; +/** This class encapsulates the data and behavior necessary for a constraint to play sounds. + + For the moment I have no easy means of populating this from an entity's datadesc. + You should explicitly fill out the fields with eg + + DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_keyPoints[SimpleConstraintSoundProfile::kMIN_THRESHOLD] , FIELD_FLOAT, "minSoundThreshold" ), + DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_keyPoints[SimpleConstraintSoundProfile::kMIN_FULL] , FIELD_FLOAT, "maxSoundThreshold" ), + DEFINE_KEYFIELD( m_soundInfo.m_iszTravelSoundFwd, FIELD_SOUNDNAME, "slidesoundfwd" ), + DEFINE_KEYFIELD( m_soundInfo.m_iszTravelSoundBack, FIELD_SOUNDNAME, "slidesoundback" ), + DEFINE_KEYFIELD( m_soundInfo.m_iszReversalSound, FIELD_SOUNDNAME, "reversalsound" ), + DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_reversalSoundThreshold , FIELD_FLOAT, "reversalsoundthreshold" ), + + */ +class ConstraintSoundInfo +{ +public: + // no ctor. + // dtor + ~ConstraintSoundInfo(); + + /// Call from the constraint's Activate() + void OnActivate( CPhysConstraint *pOuter ); + + /// Constraint should have a think function that calls this. It should pass in relative velocity + /// between child and parent. (This need not be linear velocity; it may be angular.) + void OnThink( CPhysConstraint *pOuter, const Vector &relativeVelocity ); + + /// This is how often the think function should be run: + inline float getThinkRate() const { return 0.09f; } + + /// Call this before the first call to OnThink() + void StartThinking( CPhysConstraint *pOuter, const Vector &relativeVelocity, const Vector &forwardVector ); + + /// Call this if you intend to stop calling OnThink(): + void StopThinking( CPhysConstraint *pOuter ); + + /// Call from owner's Precache(). + void OnPrecache( CPhysConstraint *pOuter ); + + + VelocitySampler m_vSampler; + SimpleConstraintSoundProfile m_soundProfile; + + Vector m_forwardAxis; ///< velocity in this direction is forward. The opposite direction is backward. + + string_t m_iszTravelSoundFwd,m_iszTravelSoundBack; // Path/filename of WAV file to play. + CSoundPatch *m_pTravelSound; + bool m_bPlayTravelSound; + + string_t m_iszReversalSounds[SimpleConstraintSoundProfile::kREVERSAL_SOUND_ARRAY_SIZE]; // Path/filename of WAV files to play -- one per entry in threshold. + // CSoundPatch *m_pReversalSound; + bool m_bPlayReversalSound; + +protected: + /// Maintain consistency of internal datastructures on start + void ValidateInternals( CPhysConstraint *pOuter ); + + /// Stop playing any active sounds. + void DeleteAllSounds(); +}; + + +/////////////// INLINE FUNCTIONS + + +/// compute the relative velocity between an object and its parent. Just a convenience. +Vector VelocitySampler::GetRelativeVelocity( IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame ) +{ + Vector childVelocity, parentVelocity; + pObj->GetImplicitVelocity( &childVelocity, NULL ); + pReferenceFrame->GetImplicitVelocity(&parentVelocity, NULL); + + return (childVelocity - parentVelocity); +} + + +Vector VelocitySampler::GetRelativeAngularVelocity( IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame ) +{ + Assert(pObj); + + if ( pReferenceFrame ) + { + Vector childVelocityLocal, parentVelocityLocal, childVelocityWorld, parentVelocityWorld; + pObj->GetImplicitVelocity( NULL, &childVelocityLocal ); + pObj->LocalToWorldVector( &childVelocityWorld, childVelocityLocal ); + pReferenceFrame->GetImplicitVelocity( NULL, &parentVelocityLocal ); + pObj->LocalToWorldVector( &parentVelocityWorld, parentVelocityLocal ); + + return (childVelocityWorld - parentVelocityWorld); + } + else + { + Vector childVelocityLocal, childVelocityWorld; + pObj->GetImplicitVelocity( NULL, &childVelocityLocal ); + pObj->LocalToWorldVector( &childVelocityWorld, childVelocityLocal ); + + return (childVelocityWorld); + } +} + +/************************************************************************/ +// This function is nominal -- it's here as an interface because in the +// future there will need to be special initialization for the first entry +// in a ring buffer. (I made a test implementation of this, then reverted it +// later; this is not an arbitrary assumption.) +/************************************************************************/ +/// Store off the first recorded sample for the given object. +void VelocitySampler::BeginSampling(const Vector &relativeVelocity) +{ + return AddSample(relativeVelocity); +} + +// Record a sample for the given object +void VelocitySampler::AddSample(const Vector &relativeVelocity) +{ + m_prevSample = relativeVelocity; + m_fPrevSampleTime = gpGlobals->curtime; +} + + + +/* // abandoned -- too complicated, no way to set from keyfields +#pragma warning(push) +#pragma warning( disable:4201 ) // C4201: nonstandard extension used: nameless struct/union +/// Stores information used for playing sounds based on +/// constraint movement +class ConstraintSoundProfile +{ +public: +/// Defines a point in the sound profile: volume and pitch for the sound to play. +/// Implicit crossfading between two sounds. Used to map velocity to a sound profile. +struct SoundInfoTuple +{ +float minVelocity; +union { +struct{ +float volume1,pitch1; //< volume and pitch of sound 1 +float volume2,pitch2; //< volume and pitch of sound 2 +}; +fltx4 m_as4; +}; + +inline SoundInfoTuple(float _minVelocity, float _volume1, float _pitch1, float _volume2, float _pitch2) : +minVelocity(_minVelocity), volume1(_volume1), pitch1(_pitch1), volume2(_volume2), pitch2(_pitch2) +{} +}; + +ConstraintSoundProfile(const SoundInfoTuple *soundTable, unsigned int tableSize) +: m_pSoundInfos(soundTable), m_numSoundInfos(tableSize) +{} + + +protected: + +/// A table of sound info structs +const SoundInfoTuple * const m_pSoundInfos; +/// Size of the table +const unsigned int m_numSoundInfos; +}; + +static ConstraintSoundProfile::SoundInfoTuple CSDebugProfileTable[] = +{ +ConstraintSoundProfile::SoundInfoTuple(12,0,0,0,0), +ConstraintSoundProfile::SoundInfoTuple(24,0,0,0,0), + +}; +#pragma warning(pop) +*/ + + +#endif diff --git a/game/server/physics.h b/game/server/physics.h new file mode 100644 index 0000000..541a165 --- /dev/null +++ b/game/server/physics.h @@ -0,0 +1,189 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is the abstraction layer for the physics simulation system +// Any calls to the external physics library (ipion) should be made through this +// layer. Eventually, the physics system will probably become a DLL and made +// accessible to the client & server side code. +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHYSICS_H +#define PHYSICS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "physics_shared.h" + +class CBaseEntity; +class IPhysicsMaterial; +class IPhysicsConstraint; +class IPhysicsSpring; +class IPhysicsSurfaceProps; +class CTakeDamageInfo; +class ConVar; + +extern IPhysicsMaterial *g_Material; +extern ConVar phys_pushscale; +extern ConVar phys_timescale; + +struct objectparams_t; +extern IPhysicsGameTrace *physgametrace; + +class IPhysicsCollisionSolver; +class IPhysicsCollisionEvent; +class IPhysicsObjectEvent; +extern IPhysicsCollisionSolver * const g_pCollisionSolver; +extern IPhysicsCollisionEvent * const g_pCollisionEventHandler; +extern IPhysicsObjectEvent * const g_pObjectEventHandler; + +// HACKHACK: We treat anything >= 500kg as a special "large mass" that does more impact damage +// and has special recovery on crushing/killing other objects +// also causes screen shakes on impact with static/world objects +const float VPHYSICS_LARGE_OBJECT_MASS = 500.0f; + +struct gamevcollisionevent_t : public vcollisionevent_t +{ + Vector preVelocity[2]; + Vector postVelocity[2]; + AngularImpulse preAngularVelocity[2]; + CBaseEntity *pEntities[2]; + + void Init( vcollisionevent_t *pEvent ) + { + *((vcollisionevent_t *)this) = *pEvent; + pEntities[0] = NULL; + pEntities[1] = NULL; + } +}; + +struct triggerevent_t +{ + CBaseEntity *pTriggerEntity; + IPhysicsObject *pTriggerPhysics; + CBaseEntity *pEntity; + IPhysicsObject *pObject; + bool bStart; + + inline void Init( CBaseEntity *triggerEntity, IPhysicsObject *triggerPhysics, CBaseEntity *entity, IPhysicsObject *object, bool startTouch ) + { + pTriggerEntity = triggerEntity; + pTriggerPhysics= triggerPhysics; + pEntity = entity; + pObject = object; + bStart = startTouch; + } + inline void Clear() + { + memset( this, 0, sizeof(*this) ); + } +}; + +// parse solid parameter overrides out of a string +void PhysSolidOverride( solid_t &solid, string_t overrideScript ); + +extern CEntityList *g_pShadowEntities; +#ifdef PORTAL +extern CEntityList *g_pShadowEntities_Main; +#endif +void PhysAddShadow( CBaseEntity *pEntity ); +void PhysRemoveShadow( CBaseEntity *pEntity ); +bool PhysHasShadow( CBaseEntity *pEntity ); + +void PhysEnableFloating( IPhysicsObject *pObject, bool bEnable ); + +void PhysCollisionSound( CBaseEntity *pEntity, IPhysicsObject *pPhysObject, int channel, int surfaceProps, int surfacePropsHit, float deltaTime, float speed ); +void PhysCollisionScreenShake( gamevcollisionevent_t *pEvent, int index ); +void PhysCollisionDust( gamevcollisionevent_t *pEvent, surfacedata_t *phit ); +#if HL2_EPISODIC +void PhysCollisionWarpEffect( gamevcollisionevent_t *pEvent, surfacedata_t *phit ); +#endif +void PhysBreakSound( CBaseEntity *pEntity, IPhysicsObject *pPhysObject, Vector vecOrigin ); + +// plays the impact sound for a particular material +void PhysicsImpactSound( CBaseEntity *pEntity, IPhysicsObject *pPhysObject, int channel, int surfaceProps, int surfacePropsHit, float volume, float impactSpeed ); + +void PhysCallbackDamage( CBaseEntity *pEntity, const CTakeDamageInfo &info ); +void PhysCallbackDamage( CBaseEntity *pEntity, const CTakeDamageInfo &info, gamevcollisionevent_t &event, int hurtIndex ); + +// Applies force impulses at a later time +void PhysCallbackImpulse( IPhysicsObject *pPhysicsObject, const Vector &vecCenterForce, const AngularImpulse &vecCenterTorque ); + +// Sets the velocity at a later time +void PhysCallbackSetVelocity( IPhysicsObject *pPhysicsObject, const Vector &vecVelocity ); + +// queue up a delete on this object +void PhysCallbackRemove(IServerNetworkable *pRemove); + +bool PhysGetDamageInflictorVelocityStartOfFrame( IPhysicsObject *pInflictor, Vector &velocity, AngularImpulse &angVelocity ); + +// force a physics entity to sleep immediately +void PhysForceEntityToSleep( CBaseEntity *pEntity, IPhysicsObject *pObject ); + +// teleport an entity to it's position relative to an object it's constrained to +void PhysTeleportConstrainedEntity( CBaseEntity *pTeleportSource, IPhysicsObject *pObject0, IPhysicsObject *pObject1, const Vector &prevPosition, const QAngle &prevAngles, bool physicsRotate ); + +void PhysGetListOfPenetratingEntities( CBaseEntity *pSearch, CUtlVector &list ); +bool PhysShouldCollide( IPhysicsObject *pObj0, IPhysicsObject *pObj1 ); + +// returns true when processing a callback - so we can defer things that can't be done inside a callback +bool PhysIsInCallback(); +bool PhysIsFinalTick(); + +bool PhysGetTriggerEvent( triggerevent_t *pEvent, CBaseEntity *pTrigger ); +// note: pErrorEntity is used to report errors (object not found, more than one found). It can be NULL +IPhysicsObject *FindPhysicsObjectByName( const char *pName, CBaseEntity *pErrorEntity ); +bool PhysFindOrAddVehicleScript( const char *pScriptName, struct vehicleparams_t *pParams, struct vehiclesounds_t *pSounds ); +void PhysFlushVehicleScripts(); + +// this is called to flush all queues when the delete list is cleared +void PhysOnCleanupDeleteList(); + +struct masscenteroverride_t +{ + enum align_type + { + ALIGN_POINT = 0, + ALIGN_AXIS = 1, + }; + + void Defaults() + { + entityName = NULL_STRING; + } + + void SnapToPoint( string_t name, const Vector &pointWS ) + { + entityName = name; + center = pointWS; + axis.Init(); + alignType = ALIGN_POINT; + } + + void SnapToAxis( string_t name, const Vector &axisStartWS, const Vector &unitAxisDirWS ) + { + entityName = name; + center = axisStartWS; + axis = unitAxisDirWS; + alignType = ALIGN_AXIS; + } + + Vector center; + Vector axis; + int alignType; + string_t entityName; +}; + +void PhysSetMassCenterOverride( masscenteroverride_t &override ); +// NOTE: this removes the entry from the table as well as retrieving it +void PhysGetMassCenterOverride( CBaseEntity *pEntity, vcollide_t *pCollide, solid_t &solidOut ); +float PhysGetEntityMass( CBaseEntity *pEntity ); +void PhysSetEntityGameFlags( CBaseEntity *pEntity, unsigned short flags ); + +void DebugDrawContactPoints(IPhysicsObject *pPhysics); + +#endif // PHYSICS_H diff --git a/game/server/physics_bone_follower.h b/game/server/physics_bone_follower.h new file mode 100644 index 0000000..10059af --- /dev/null +++ b/game/server/physics_bone_follower.h @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_BONE_FOLLOWER_H +#define PHYSICS_BONE_FOLLOWER_H +#ifdef _WIN32 +#pragma once +#endif + +class CBoneFollower; + +// +// To use bone followers in an entity, contain a CBoneFollowerManager in it. Then: +// - Call InitBoneFollowers() in the entity's CreateVPhysics(). +// - Call UpdateBoneFollowers() after you move your bones. +// - Call DestroyBoneFollowers() when your entity's removed + +struct physfollower_t +{ + DECLARE_SIMPLE_DATADESC(); + int boneIndex; + CHandle hFollower; +}; + +struct vcollide_t; + +// create a manager and a list of followers directly from a ragdoll +void CreateBoneFollowersFromRagdoll( CBaseAnimating *pEntity, class CBoneFollowerManager *pManager, vcollide_t *pCollide ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBoneFollowerManager +{ + DECLARE_SIMPLE_DATADESC(); +public: + CBoneFollowerManager(); + ~CBoneFollowerManager(); + + // Use either of these to create the bone followers in your entity's CreateVPhysics() + void InitBoneFollowers( CBaseAnimating *pParentEntity, int iNumBones, const char **pFollowerBoneNames ); + void AddBoneFollower( CBaseAnimating *pParentEntity, const char *pFollowerBoneName, solid_t *pSolid = NULL ); // Adds a single bone follower + + // Call this after you move your bones + void UpdateBoneFollowers( CBaseAnimating *pParentEntity ); + + // Call this when your entity's removed + void DestroyBoneFollowers( void ); + + physfollower_t *GetBoneFollower( int iFollowerIndex ); + int GetBoneFollowerIndex( CBoneFollower *pFollower ); + int GetNumBoneFollowers( void ) const { return m_iNumBones; } + +private: + bool CreatePhysicsFollower( CBaseAnimating *pParentEntity, physfollower_t &follow, const char *pBoneName, solid_t *pSolid ); + +private: + int m_iNumBones; + CUtlVector m_physBones; +}; + + +class CBoneFollower : public CBaseEntity +{ + DECLARE_CLASS( CBoneFollower, CBaseEntity ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); +public: + // CBaseEntity + void VPhysicsUpdate( IPhysicsObject *pPhysics ); + int UpdateTransmitState(void); + + // NOTE: These are forwarded to the parent object! + void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + void VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ); + void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent ); + + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + int ObjectCaps( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + void Touch( CBaseEntity *pOther ); + + void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + // locals + bool Init( CBaseEntity *pOwner, const char *pModelName, solid_t &solid, const Vector &position, const QAngle &orientation ); + void UpdateFollower( const Vector &position, const QAngle &orientation, float flInterval ); + void SetTraceData( int physicsBone, int hitGroup ); + + // factory + static CBoneFollower *Create( CBaseEntity *pOwner, const char *pModelName, solid_t &solid, const Vector &position, const QAngle &orientation ); + +private: + CNetworkVar( int, m_modelIndex ); + CNetworkVar( int, m_solidIndex ); + int m_physicsBone; + int m_hitGroup; +}; + +#endif // PHYSICS_BONE_FOLLOWER_H diff --git a/game/server/physics_cannister.h b/game/server/physics_cannister.h new file mode 100644 index 0000000..72a1b68 --- /dev/null +++ b/game/server/physics_cannister.h @@ -0,0 +1,145 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_CANNISTER_H +#define PHYSICS_CANNISTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "player_pickup.h" + +class CSteamJet; + +class CThrustController : public IMotionEvent +{ + DECLARE_SIMPLE_DATADESC(); + +public: + IMotionEvent::simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) + { + angular = m_torqueVector; + linear = m_thrustVector; + return SIM_LOCAL_ACCELERATION; + } + + void CalcThrust( const Vector &position, const Vector &direction, IPhysicsObject *pPhys ) + { + Vector force = direction * m_thrust * pPhys->GetMass(); + + // Adjust for the position of the thruster -- apply proper torque) + pPhys->CalculateVelocityOffset( force, position, &m_thrustVector, &m_torqueVector ); + pPhys->WorldToLocalVector( &m_thrustVector, m_thrustVector ); + } + + Vector m_thrustVector; + AngularImpulse m_torqueVector; + float m_thrust; +}; + +class CPhysicsCannister : public CBaseCombatCharacter, public CDefaultPlayerPickupVPhysics +{ + DECLARE_CLASS( CPhysicsCannister, CBaseCombatCharacter ); +public: + ~CPhysicsCannister( void ); + + void Spawn( void ); + void Precache( void ); + virtual void OnRestore(); + bool CreateVPhysics(); + + DECLARE_DATADESC(); + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + + virtual QAngle PreferredCarryAngles( void ) { return QAngle( -90, 0, 0 ); } + virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) { return true; } + + // + // Input handlers. + // + void InputActivate(inputdata_t &data); + void InputDeactivate(inputdata_t &data); + void InputExplode(inputdata_t &data); + void InputWake( inputdata_t &data ); + + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + int ObjectCaps() + { + return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE); + } + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) + { + CBasePlayer *pPlayer = ToBasePlayer( pActivator ); + if ( pPlayer ) + { + pPlayer->PickupObject( this ); + } + } + + void CannisterActivate( CBaseEntity *pActivator, const Vector &thrustOffset ); + void CannisterFire( CBaseEntity *pActivator ); + void Deactivate( void ); + void Explode( CBaseEntity *pAttacker ); + void ExplodeTouch( CBaseEntity *pOther ); + void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + + // Don't treat as a live target + virtual bool IsAlive( void ) { return false; } + + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &dir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + + void ShutdownJet( void ); + void BeginShutdownThink( void ); + +public: + virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ) { return true; } + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); + virtual CBasePlayer *HasPhysicsAttacker( float dt ); + virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) + { + if ( reason == PHYSGUN_FORCE_LAUNCHED ) + return (m_thrustTime!=0); + + return false; + } + virtual AngularImpulse PhysGunLaunchAngularImpulse( void ) { return vec3_origin; } + virtual Vector PhysGunLaunchVelocity( const Vector &forward, float flMass ) { return vec3_origin; } + +protected: + void SetPhysicsAttacker( CBasePlayer *pEntity, float flTime ); + + +public: + Vector m_thrustOrigin; + CThrustController m_thruster; + IPhysicsMotionController *m_pController; + CSteamJet *m_pJet; + bool m_active; + float m_thrustTime; + float m_damage; + float m_damageRadius; + + float m_activateTime; + string_t m_gasSound; + + bool m_bFired; // True if this cannister was fire by a weapon + + COutputEvent m_onActivate; + COutputEvent m_OnAwakened; + + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + EHANDLE m_hLauncher; // Entity that caused this cannister to launch + +private: + Vector CalcLocalThrust( const Vector &offset ); +}; + +#endif // PHYSICS_CANNISTER_H diff --git a/game/server/physics_collisionevent.h b/game/server/physics_collisionevent.h new file mode 100644 index 0000000..67f91d3 --- /dev/null +++ b/game/server/physics_collisionevent.h @@ -0,0 +1,176 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Pulling CCollisionEvent's definition out of physics.cpp so it can be abstracted upon (for the portal mod) +// +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHYSICS_COLLISIONEVENT_H +#define PHYSICS_COLLISIONEVENT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "physics.h" +#include "tier1/callqueue.h" + +extern CCallQueue g_PostSimulationQueue; + +struct damageevent_t +{ + CBaseEntity *pEntity; + IPhysicsObject *pInflictorPhysics; + CTakeDamageInfo info; + bool bRestoreVelocity; +}; + +struct inflictorstate_t +{ + Vector savedVelocity; + AngularImpulse savedAngularVelocity; + IPhysicsObject *pInflictorPhysics; + float otherMassMax; + short nextIndex; + short restored; +}; + +enum +{ + COLLSTATE_ENABLED = 0, + COLLSTATE_TRYDISABLE = 1, + COLLSTATE_TRYNPCSOLVER = 2, + COLLSTATE_TRYENTITYSOLVER = 3, + COLLSTATE_DISABLED = 4 +}; + +struct penetrateevent_t +{ + EHANDLE hEntity0; + EHANDLE hEntity1; + float startTime; + float timeStamp; + int collisionState; +}; + +class CCollisionEvent : public IPhysicsCollisionEvent, public IPhysicsCollisionSolver, public IPhysicsObjectEvent +{ +public: + CCollisionEvent(); + friction_t *FindFriction( CBaseEntity *pObject ); + void ShutdownFriction( friction_t &friction ); + void FrameUpdate(); + void LevelShutdown( void ); + + // IPhysicsCollisionEvent + void PreCollision( vcollisionevent_t *pEvent ); + void PostCollision( vcollisionevent_t *pEvent ); + void Friction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit, IPhysicsCollisionData *pData ); + void StartTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ); + void EndTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ); + void FluidStartTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ); + void FluidEndTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ); + void PostSimulationFrame(); + void ObjectEnterTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ); + void ObjectLeaveTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ); + + bool GetTriggerEvent( triggerevent_t *pEvent, CBaseEntity *pTriggerEntity ); + void BufferTouchEvents( bool enable ) { m_bBufferTouchEvents = enable; } + virtual void AddDamageEvent( CBaseEntity *pEntity, const CTakeDamageInfo &info, IPhysicsObject *pInflictorPhysics, bool bRestoreVelocity, const Vector &savedVel, const AngularImpulse &savedAngVel ); + void AddImpulseEvent( IPhysicsObject *pPhysicsObject, const Vector &vecCenterForce, const AngularImpulse &vecCenterTorque ); + void AddSetVelocityEvent( IPhysicsObject *pPhysicsObject, const Vector &vecVelocity ); + void AddRemoveObject(IServerNetworkable *pRemove); + void FlushQueuedOperations(); + + // IPhysicsCollisionSolver + int ShouldCollide( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1 ); + int ShouldSolvePenetration( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1, float dt ); + bool ShouldFreezeObject( IPhysicsObject *pObject ); + static const char *ModuleName() { return CBaseEntity::IsServer() ? "SERVER" : "CLIENT"; } + int AdditionalCollisionChecksThisTick( int currentChecksDone ) + { + //CallbackContext check(this); + if ( currentChecksDone < 1200 ) + { + DevMsg(1,"%s: VPhysics Collision detection getting expensive, check for too many convex pieces!\n", ModuleName()); + return 1200 - currentChecksDone; + } + DevMsg(1,"%s: VPhysics exceeded collision check limit (%d)!!!\nInterpenetration may result!\n", ModuleName(), currentChecksDone ); + return 0; + } + bool ShouldFreezeContacts( IPhysicsObject **pObjectList, int objectCount ); + + // IPhysicsObjectEvent + // these can be used to optimize out queries on sleeping objects + // Called when an object is woken after sleeping + virtual void ObjectWake( IPhysicsObject *pObject ); + // called when an object goes to sleep (no longer simulating) + virtual void ObjectSleep( IPhysicsObject *pObject ); + + + // locals + bool GetInflictorVelocity( IPhysicsObject *pInflictor, Vector &velocity, AngularImpulse &angVelocity ); + + void GetListOfPenetratingEntities( CBaseEntity *pSearch, CUtlVector &list ); + bool IsInCallback() { return m_inCallback > 0 ? true : false; } + +private: +#if _DEBUG + int ShouldCollide_2( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1 ); +#endif + + void UpdateFrictionSounds(); + void UpdateTouchEvents(); + void UpdateDamageEvents(); + void UpdatePenetrateEvents( void ); + void UpdateFluidEvents(); + void UpdateRemoveObjects(); + void AddTouchEvent( CBaseEntity *pEntity0, CBaseEntity *pEntity1, int touchType, const Vector &point, const Vector &normal ); + penetrateevent_t &FindOrAddPenetrateEvent( CBaseEntity *pEntity0, CBaseEntity *pEntity1 ); + float DeltaTimeSinceLastFluid( CBaseEntity *pEntity ); + + void RestoreDamageInflictorState( IPhysicsObject *pInflictor ); + void RestoreDamageInflictorState( int inflictorStateIndex, float velocityBlend ); + int AddDamageInflictor( IPhysicsObject *pInflictorPhysics, float otherMass, const Vector &savedVel, const AngularImpulse &savedAngVel, bool addList ); + int FindDamageInflictor( IPhysicsObject *pInflictorPhysics ); + + // make the call into the entity system + void DispatchStartTouch( CBaseEntity *pEntity0, CBaseEntity *pEntity1, const Vector &point, const Vector &normal ); + void DispatchEndTouch( CBaseEntity *pEntity0, CBaseEntity *pEntity1 ); + + class CallbackContext + { + public: + CallbackContext(CCollisionEvent *pOuter) + { + m_pOuter = pOuter; + m_pOuter->m_inCallback++; + } + ~CallbackContext() + { + m_pOuter->m_inCallback--; + } + private: + CCollisionEvent *m_pOuter; + }; + friend class CallbackContext; + + friction_t m_current[4]; + gamevcollisionevent_t m_gameEvent; + CUtlVector m_triggerEvents; + triggerevent_t m_currentTriggerEvent; + CUtlVector m_touchEvents; + CUtlVector m_damageEvents; + CUtlVector m_damageInflictors; + CUtlVector m_penetrateEvents; + CUtlVector m_fluidEvents; + CUtlVector m_removeObjects; + int m_inCallback; + int m_lastTickFrictionError; // counter to control printing of the dev warning for large contact systems + bool m_bBufferTouchEvents; +}; + +#endif //#ifndef PHYSICS_COLLISIONEVENT_H diff --git a/game/server/physics_fx.h b/game/server/physics_fx.h new file mode 100644 index 0000000..2d26710 --- /dev/null +++ b/game/server/physics_fx.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_FX_H +#define PHYSICS_FX_H +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseEntity; +class IPhysicsFluidController; + +void PhysicsSplash( IPhysicsFluidController *pFluid, IPhysicsObject *pObject, CBaseEntity *pEntity ); + +#endif // PHYSICS_FX_H diff --git a/game/server/physics_impact_damage.h b/game/server/physics_impact_damage.h new file mode 100644 index 0000000..2bd46a1 --- /dev/null +++ b/game/server/physics_impact_damage.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_IMPACT_DAMAGE_H +#define PHYSICS_IMPACT_DAMAGE_H +#ifdef _WIN32 +#pragma once +#endif + + +struct impactentry_t +{ + float impulse; + float damage; +}; + +// UNDONE: Add a flag to turn off aggregation of mass in object systems (e.g. ragdolls, vehicles)? +struct impactdamagetable_t +{ + impactentry_t *linearTable; + impactentry_t *angularTable; + int linearCount; // array size of linearTable + int angularCount; // array size of angularTable + + float minSpeedSqr; // minimum squared impact speed for damage + float minRotSpeedSqr; + float minMass; // minimum mass to do damage + + // filter out reall small objects, set all to zero to disable + float smallMassMax; + float smallMassCap; + float smallMassMinSpeedSqr; + + // exaggerate the effects of really large objects, set all to 1 to disable + float largeMassMin; + float largeMassScale; + float largeMassFallingScale; // emphasize downward impacts so that this will kill instead of stress (we have more information here than there) + float myMinVelocity; // filter out any energy lost by me unless my velocity is greater than this +}; + + + +extern impactdamagetable_t gDefaultNPCImpactDamageTable; +extern impactdamagetable_t gDefaultPlayerImpactDamageTable; +extern impactdamagetable_t gDefaultPlayerVehicleImpactDamageTable; + +// NOTE Default uses default NPC table +float CalculateDefaultPhysicsDamage( int index, gamevcollisionevent_t *pEvent, float energyScale, bool allowStaticDamage, int &damageTypeOut, string_t iszDamageTableName = NULL_STRING, bool bDamageFromHeldObjects = false ); + +// use passes in the table +float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageTypeOut, bool bDamageFromHeldObjects = false ); + +struct vphysics_objectstress_t +{ + float exertedStress; + float receivedStress; + bool hasNonStaticStress; + bool hasLargeObjectContact; +}; + +float CalculateObjectStress( IPhysicsObject *pObject, CBaseEntity *pOwnerEntity, vphysics_objectstress_t *pOutput ); + +#endif // PHYSICS_IMPACT_DAMAGE_H diff --git a/game/server/physics_npc_solver.h b/game/server/physics_npc_solver.h new file mode 100644 index 0000000..12e2e18 --- /dev/null +++ b/game/server/physics_npc_solver.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_NPC_SOLVER_H +#define PHYSICS_NPC_SOLVER_H +#ifdef _WIN32 +#pragma once +#endif + + +extern CBaseEntity *NPCPhysics_CreateSolver( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationDuration ); +extern CBaseEntity *EntityPhysics_CreateSolver( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, bool disableCollisions, float separationDuration ); +bool NPCPhysics_SolverExists( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject ); + + +#endif // PHYSICS_NPC_SOLVER_H diff --git a/game/server/physics_prop_ragdoll.h b/game/server/physics_prop_ragdoll.h new file mode 100644 index 0000000..7c24b47 --- /dev/null +++ b/game/server/physics_prop_ragdoll.h @@ -0,0 +1,162 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_PROP_RAGDOLL_H +#define PHYSICS_PROP_RAGDOLL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ragdoll_shared.h" +#include "player_pickup.h" + + +//----------------------------------------------------------------------------- +// Purpose: entity class for simple ragdoll physics +//----------------------------------------------------------------------------- + +// UNDONE: Move this to a private header +class CRagdollProp : public CBaseAnimating, public CDefaultPlayerPickupVPhysics +{ + DECLARE_CLASS( CRagdollProp, CBaseAnimating ); + +public: + CRagdollProp( void ); + ~CRagdollProp( void ); + + virtual void UpdateOnRemove( void ); + + void DrawDebugGeometryOverlays(); + + void Spawn( void ); + void Precache( void ); + + // Disable auto fading under dx7 or when level fades are specified + void DisableAutoFade(); + + int ObjectCaps(); + + DECLARE_SERVERCLASS(); + // Don't treat as a live target + virtual bool IsAlive( void ) { return false; } + + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &dir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + virtual bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + virtual void SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ); + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + + virtual int DrawDebugTextOverlays(void); + + // Response system stuff + virtual IResponseSystem *GetResponseSystem(); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + void SetSourceClassName( const char *pClassname ); + + // Physics attacker + virtual CBasePlayer *HasPhysicsAttacker( float dt ); + + // locals + void InitRagdollAnimation( void ); + void InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll = true ); + + void RecheckCollisionFilter( void ); + void SetDebrisThink(); + void ClearFlagsThink( void ); + inline ragdoll_t *GetRagdoll( void ) { return &m_ragdoll; } + + virtual bool IsRagdoll() { return true; } + + // Damage passing + virtual void SetDamageEntity( CBaseEntity *pEntity ); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual void OnSave( IEntitySaveUtils *pUtils ); + virtual void OnRestore(); + + // Purpose: CDefaultPlayerPickupVPhysics + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + virtual AngularImpulse PhysGunLaunchAngularImpulse(); + bool HasPhysgunInteraction( const char *pszKeyName, const char *pszValue ); + void HandleFirstCollisionInteractions( int index, gamevcollisionevent_t *pEvent ); + + void SetUnragdoll( CBaseAnimating *pOther ); + + void SetBlendWeight( float weight ) { m_flBlendWeight = weight; } + void SetOverlaySequence( Activity activity ); + void FadeOut( float flDelay = 0, float fadeTime = -1 ); + bool IsFading(); + CBaseEntity* GetKiller() { return m_hKiller; } + void SetKiller( CBaseEntity *pKiller ) { m_hKiller = pKiller; } + void GetAngleOverrideFromCurrentState( char *pOut, int size ); + + void DisableMotion( void ); + + // Input/Output + void InputStartRadgollBoogie( inputdata_t &inputdata ); + void InputEnableMotion( inputdata_t &inputdata ); + void InputDisableMotion( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + void InputFadeAndRemove( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + +protected: + void CalcRagdollSize( void ); + ragdoll_t m_ragdoll; + +private: + void UpdateNetworkDataFromVPhysics( IPhysicsObject *pPhysics, int index ); + void FadeOutThink(); + + bool m_bStartDisabled; + + CNetworkArray( Vector, m_ragPos, RAGDOLL_MAX_ELEMENTS ); + CNetworkArray( QAngle, m_ragAngles, RAGDOLL_MAX_ELEMENTS ); + + string_t m_anglesOverrideString; + + typedef CHandle CBaseAnimatingHandle; + CNetworkVar( CBaseAnimatingHandle, m_hUnragdoll ); + + + unsigned int m_lastUpdateTickCount; + bool m_allAsleep; + bool m_bFirstCollisionAfterLaunch; + EHANDLE m_hDamageEntity; + EHANDLE m_hKiller; // Who killed me? + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + float m_flFadeOutStartTime; + float m_flFadeTime; + + + string_t m_strSourceClassName; + bool m_bHasBeenPhysgunned; + + // If not 1, then allow underlying sequence to blend in with simulated bone positions + CNetworkVar( float, m_flBlendWeight ); + CNetworkVar( int, m_nOverlaySequence ); + float m_flDefaultFadeScale; + + Vector m_ragdollMins[RAGDOLL_MAX_ELEMENTS]; + Vector m_ragdollMaxs[RAGDOLL_MAX_ELEMENTS]; +}; + +CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, const CTakeDamageInfo &info, int collisionGroup, bool bUseLRURetirement = false ); +CRagdollProp *CreateServerRagdollAttached( CBaseAnimating *pAnimating, const Vector &vecForce, int forceBone, int collisionGroup, IPhysicsObject *pAttached, CBaseAnimating *pParentEntity, int boneAttach, const Vector &originAttached, int parentBoneAttach, const Vector &boneOrigin ); +void DetachAttachedRagdoll( CBaseEntity *pRagdollIn ); +void DetachAttachedRagdollsForEntity( CBaseEntity *pRagdollParent ); +CBaseAnimating *CreateServerRagdollSubmodel( CBaseAnimating *pOwner, const char *pModelName, const Vector &position, const QAngle &angles, int collisionGroup ); + +bool Ragdoll_IsPropRagdoll( CBaseEntity *pEntity ); +void Ragdoll_GetAngleOverrideString( char *pOut, int size, CBaseEntity *pEntity ); +ragdoll_t *Ragdoll_GetRagdoll( CBaseEntity *pEntity ); + +#endif // PHYSICS_PROP_RAGDOLL_H diff --git a/game/server/physobj.h b/game/server/physobj.h new file mode 100644 index 0000000..a6e9e5a --- /dev/null +++ b/game/server/physobj.h @@ -0,0 +1,237 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHYSOBJ_H +#define PHYSOBJ_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef PHYSICS_H +#include "physics.h" +#endif + +#include "entityoutput.h" +#include "func_break.h" +#include "player_pickup.h" + +// --------------------------------------------------------------------- +// +// CPhysBox -- physically simulated brush rectangular solid +// +// --------------------------------------------------------------------- +// Physbox Spawnflags. Start at 0x01000 to avoid collision with CBreakable's +#define SF_PHYSBOX_ASLEEP 0x01000 +#define SF_PHYSBOX_IGNOREUSE 0x02000 +#define SF_PHYSBOX_DEBRIS 0x04000 +#define SF_PHYSBOX_MOTIONDISABLED 0x08000 +#define SF_PHYSBOX_USEPREFERRED 0x10000 +#define SF_PHYSBOX_ENABLE_ON_PHYSCANNON 0x20000 +#define SF_PHYSBOX_NO_ROTORWASH_PUSH 0x40000 // The rotorwash doesn't push these +#define SF_PHYSBOX_ENABLE_PICKUP_OUTPUT 0x80000 +#define SF_PHYSBOX_ALWAYS_PICK_UP 0x100000 // Physcannon can always pick this up, no matter what mass or constraints may apply. +#define SF_PHYSBOX_NEVER_PICK_UP 0x200000 // Physcannon will never be able to pick this up. +#define SF_PHYSBOX_NEVER_PUNT 0x400000 // Physcannon will never be able to punt this object. +#define SF_PHYSBOX_PREVENT_PLAYER_TOUCH_ENABLE 0x800000 // If set, the player will not cause the object to enable its motion when bumped into + +// UNDONE: Hook collisions into the physics system to generate touch functions and take damage on falls +// UNDONE: Base class PhysBrush +class CPhysBox : public CBreakable +{ +DECLARE_CLASS( CPhysBox, CBreakable ); + +public: + DECLARE_SERVERCLASS(); + + void Spawn ( void ); + bool CreateVPhysics(); + void Move( const Vector &force ); + virtual int ObjectCaps(); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual int DrawDebugTextOverlays(void); + + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + int OnTakeDamage( const CTakeDamageInfo &info ); + void EnableMotion( void ); + + bool CanBePickedUpByPhyscannon(); + + // IPlayerPickupVPhysics + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); + + bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ); + virtual QAngle PreferredCarryAngles( void ) { return m_angPreferredCarryAngles; } + + // inputs + void InputWake( inputdata_t &inputdata ); + void InputSleep( inputdata_t &inputdata ); + void InputEnableMotion( inputdata_t &inputdata ); + void InputDisableMotion( inputdata_t &inputdata ); + void InputForceDrop( inputdata_t &inputdata ); + void InputDisableFloating( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + +protected: + int m_damageType; + float m_massScale; + string_t m_iszOverrideScript; + int m_damageToEnableMotion; + float m_flForceToEnableMotion; + QAngle m_angPreferredCarryAngles; + bool m_bNotSolidToWorld; + + // Outputs + COutputEvent m_OnDamaged; + COutputEvent m_OnAwakened; + COutputEvent m_OnMotionEnabled; + COutputEvent m_OnPhysGunPickup; + COutputEvent m_OnPhysGunPunt; + COutputEvent m_OnPhysGunOnlyPickup; + COutputEvent m_OnPhysGunDrop; + COutputEvent m_OnPlayerUse; + + CHandle m_hCarryingPlayer; // Player who's carrying us +}; + +// --------------------------------------------------------------------- +// +// CPhysExplosion -- physically simulated explosion +// +// --------------------------------------------------------------------- +class CPhysExplosion : public CPointEntity +{ +public: + DECLARE_CLASS( CPhysExplosion, CPointEntity ); + + void Spawn ( void ); + void Explode( CBaseEntity *pActivator, CBaseEntity *pCaller ); + + CBaseEntity *FindEntity( CBaseEntity *pEntity, CBaseEntity *pActivator, CBaseEntity *pCaller ); + + int DrawDebugTextOverlays(void); + + // Input handlers + void InputExplode( inputdata_t &inputdata ); + + DECLARE_DATADESC(); +private: + + float GetRadius( void ); + + float m_damage; + float m_radius; + string_t m_targetEntityName; + float m_flInnerRadius; + + COutputEvent m_OnPushedPlayer; +}; + + +//================================================== +// CPhysImpact +//================================================== + +class CPhysImpact : public CPointEntity +{ +public: + DECLARE_CLASS( CPhysImpact, CPointEntity ); + + void Spawn( void ); + //void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Activate( void ); + + void InputImpact( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + +private: + + void PointAtEntity( void ); + + float m_damage; + float m_distance; + string_t m_directionEntityName; +}; + +//----------------------------------------------------------------------------- +// Purpose: A magnet that creates constraints between itself and anything it touches +//----------------------------------------------------------------------------- + +struct magnetted_objects_t +{ + IPhysicsConstraint *pConstraint; + EHANDLE hEntity; + + DECLARE_SIMPLE_DATADESC(); +}; + +class CPhysMagnet : public CBaseAnimating, public IPhysicsConstraintEvent +{ + DECLARE_CLASS( CPhysMagnet, CBaseAnimating ); +public: + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CPhysMagnet(); + ~CPhysMagnet(); + + void Spawn( void ); + void Precache( void ); + void Touch( CBaseEntity *pOther ); + void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + void DoMagnetSuck( CBaseEntity *pOther ); + void SetConstraintGroup( IPhysicsConstraintGroup *pGroup ); + + bool IsOn( void ) { return m_bActive; } + int GetNumAttachedObjects( void ); + float GetTotalMassAttachedObjects( void ); + CBaseEntity *GetAttachedObject( int iIndex ); + + // Checking for hitting something + void ResetHasHitSomething( void ) { m_bHasHitSomething = false; } + bool HasHitSomething( void ) { return m_bHasHitSomething; } + + // Inputs + void InputToggle( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + + void InputConstraintBroken( inputdata_t &inputdata ); + + void DetachAll( void ); + +// IPhysicsConstraintEvent +public: + void ConstraintBroken( IPhysicsConstraint *pConstraint ); + +protected: + // Outputs + COutputEvent m_OnMagnetAttach; + COutputEvent m_OnMagnetDetach; + + // Keys + float m_massScale; + string_t m_iszOverrideScript; + float m_forceLimit; + float m_torqueLimit; + + CUtlVector< magnetted_objects_t > m_MagnettedEntities; + IPhysicsConstraintGroup *m_pConstraintGroup; + + bool m_bActive; + bool m_bHasHitSomething; + float m_flTotalMass; + float m_flRadius; + float m_flNextSuckTime; + int m_iMaxObjectsAttached; +}; + +#endif // PHYSOBJ_H diff --git a/game/server/plasma.h b/game/server/plasma.h new file mode 100644 index 0000000..c723a9a --- /dev/null +++ b/game/server/plasma.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef __PLASMA__ +#define __PLASMA__ +#pragma once + +#include "fire_smoke.h" + +//================================================== +// CPlasma +//================================================== + +//NOTENOTE: Mirrored in cl_dll/c_plasma.cpp +#define bitsPLASMA_FREE 0x00000002 + +class CPlasma : public CBaseFire +{ +public: + DECLARE_CLASS( CPlasma, CBaseFire ); + + CPlasma( void ); + virtual ~CPlasma( void ); + void EnableSmoke( int state ); + + void Precache( void ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +public: + + //Client-side + CNetworkVar( int, m_nPlasmaModelIndex ); + CNetworkVar( int, m_nPlasmaModelIndex2 ); + CNetworkVar( int, m_nGlowModelIndex ); + + //Server-side +}; + +#endif //__PLASMA__ diff --git a/game/server/player.h b/game/server/player.h new file mode 100644 index 0000000..ec930fa --- /dev/null +++ b/game/server/player.h @@ -0,0 +1,1563 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef PLAYER_H +#define PLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basecombatcharacter.h" +#include "usercmd.h" +#include "playerlocaldata.h" +#include "PlayerState.h" +#include "game/server/iplayerinfo.h" +#include "hintsystem.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "util_shared.h" + +#if defined USES_ECON_ITEMS +#include "game_item_schema.h" +#include "econ_item_view.h" +#endif + +// For queuing and processing usercmds +class CCommandContext +{ +public: + CUtlVector< CUserCmd > cmds; + + int numcmds; + int totalcmds; + int dropped_packets; + bool paused; +}; + +// Info about last 20 or so updates to the +class CPlayerCmdInfo +{ +public: + CPlayerCmdInfo() : + m_flTime( 0.0f ), m_nNumCmds( 0 ), m_nDroppedPackets( 0 ) + { + } + + // realtime of sample + float m_flTime; + // # of CUserCmds in this update + int m_nNumCmds; + // # of dropped packets on the link + int m_nDroppedPackets; +}; + +class CPlayerSimInfo +{ +public: + CPlayerSimInfo() : + m_flTime( 0.0f ), m_nNumCmds( 0 ), m_nTicksCorrected( 0 ), m_flFinalSimulationTime( 0.0f ), m_flGameSimulationTime( 0.0f ), m_flServerFrameTime( 0.0f ), m_vecAbsOrigin( 0, 0, 0 ) + { + } + + // realtime of sample + float m_flTime; + // # of CUserCmds in this update + int m_nNumCmds; + // If clock needed correction, # of ticks added/removed + int m_nTicksCorrected; // +ve or -ve + // player's m_flSimulationTime at end of frame + float m_flFinalSimulationTime; + float m_flGameSimulationTime; + // estimate of server perf + float m_flServerFrameTime; + Vector m_vecAbsOrigin; +}; +//----------------------------------------------------------------------------- +// Forward declarations: +//----------------------------------------------------------------------------- +class CBaseCombatWeapon; +class CBaseViewModel; +class CTeam; +class IPhysicsPlayerController; +class IServerVehicle; +class CUserCmd; +class CFuncLadder; +class CNavArea; +class CHintSystem; +class CAI_Expresser; + +#if defined USES_ECON_ITEMS +class CEconWearable; +#endif // USES_ECON_ITEMS + +// for step sounds +struct surfacedata_t; + +// !!!set this bit on guns and stuff that should never respawn. +#define SF_NORESPAWN ( 1 << 30 ) + +// +// Player PHYSICS FLAGS bits +// +enum PlayerPhysFlag_e +{ + PFLAG_DIROVERRIDE = ( 1<<0 ), // override the player's directional control (trains, physics gun, etc.) + PFLAG_DUCKING = ( 1<<1 ), // In the process of ducking, but totally squatted yet + PFLAG_USING = ( 1<<2 ), // Using a continuous entity + PFLAG_OBSERVER = ( 1<<3 ), // player is locked in stationary cam mode. Spectators can move, observers can't. + PFLAG_VPHYSICS_MOTIONCONTROLLER = ( 1<<4 ), // player is physically attached to a motion controller + PFLAG_GAMEPHYSICS_ROTPUSH = (1<<5), // game physics did a rotating push that we may want to override with vphysics + + // If you add another flag here check that you aren't + // overwriting phys flags in the HL2 of TF2 player classes +}; + +// +// generic player +// +//----------------------------------------------------- +//This is Half-Life player entity +//----------------------------------------------------- +#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time +#define SUIT_REPEAT_OK 0 + +#define SUIT_NEXT_IN_30SEC 30 +#define SUIT_NEXT_IN_1MIN 60 +#define SUIT_NEXT_IN_5MIN 300 +#define SUIT_NEXT_IN_10MIN 600 +#define SUIT_NEXT_IN_30MIN 1800 +#define SUIT_NEXT_IN_1HOUR 3600 + +#define CSUITNOREPEAT 32 + +#define TEAM_NAME_LENGTH 16 + +// constant items +#define ITEM_HEALTHKIT 1 +#define ITEM_BATTERY 4 + +#define AUTOAIM_2DEGREES 0.0348994967025 +#define AUTOAIM_5DEGREES 0.08715574274766 +#define AUTOAIM_8DEGREES 0.1391731009601 +#define AUTOAIM_10DEGREES 0.1736481776669 +#define AUTOAIM_20DEGREES 0.3490658503989 + +// useful cosines +#define DOT_1DEGREE 0.9998476951564 +#define DOT_2DEGREE 0.9993908270191 +#define DOT_3DEGREE 0.9986295347546 +#define DOT_4DEGREE 0.9975640502598 +#define DOT_5DEGREE 0.9961946980917 +#define DOT_6DEGREE 0.9945218953683 +#define DOT_7DEGREE 0.9925461516413 +#define DOT_8DEGREE 0.9902680687416 +#define DOT_9DEGREE 0.9876883405951 +#define DOT_10DEGREE 0.9848077530122 +#define DOT_15DEGREE 0.9659258262891 +#define DOT_20DEGREE 0.9396926207859 +#define DOT_25DEGREE 0.9063077870367 +#define DOT_30DEGREE 0.866025403784 +#define DOT_45DEGREE 0.707106781187 +enum +{ + VPHYS_WALK = 0, + VPHYS_CROUCH, + VPHYS_NOCLIP, +}; + + +enum PlayerConnectedState +{ + PlayerConnected, + PlayerDisconnecting, + PlayerDisconnected, +}; + +extern bool gInitHUD; +extern ConVar *sv_cheats; + +class CBasePlayer; +class CPlayerInfo : public IBotController, public IPlayerInfo +{ +public: + CPlayerInfo () { m_pParent = NULL; } + ~CPlayerInfo () {} + void SetParent( CBasePlayer *parent ) { m_pParent = parent; } + + // IPlayerInfo interface + virtual const char *GetName(); + virtual int GetUserID(); + virtual const char *GetNetworkIDString(); + virtual int GetTeamIndex(); + virtual void ChangeTeam( int iTeamNum ); + virtual int GetFragCount(); + virtual int GetDeathCount(); + virtual bool IsConnected(); + virtual int GetArmorValue(); + + virtual bool IsHLTV(); + virtual bool IsReplay(); + virtual bool IsPlayer(); + virtual bool IsFakeClient(); + virtual bool IsDead(); + virtual bool IsInAVehicle(); + virtual bool IsObserver(); + virtual const Vector GetAbsOrigin(); + virtual const QAngle GetAbsAngles(); + virtual const Vector GetPlayerMins(); + virtual const Vector GetPlayerMaxs(); + virtual const char *GetWeaponName(); + virtual const char *GetModelName(); + virtual int GetHealth(); + virtual int GetMaxHealth(); + + // bot specific functions + virtual void SetAbsOrigin( Vector & vec ); + virtual void SetAbsAngles( QAngle & ang ); + virtual void RemoveAllItems( bool removeSuit ); + virtual void SetActiveWeapon( const char *WeaponName ); + virtual void SetLocalOrigin( const Vector& origin ); + virtual const Vector GetLocalOrigin( void ); + virtual void SetLocalAngles( const QAngle& angles ); + virtual const QAngle GetLocalAngles( void ); + virtual bool IsEFlagSet( int nEFlagMask ); + + virtual void RunPlayerMove( CBotCmd *ucmd ); + virtual void SetLastUserCommand( const CBotCmd &cmd ); + + virtual CBotCmd GetLastUserCommand(); + +private: + CBasePlayer *m_pParent; +}; + + +class CBasePlayer : public CBaseCombatCharacter +{ +public: + DECLARE_CLASS( CBasePlayer, CBaseCombatCharacter ); +protected: + // HACK FOR BOTS + friend class CBotManager; + static edict_t *s_PlayerEdict; // must be set before calling constructor +public: + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CBasePlayer(); + ~CBasePlayer(); + + // IPlayerInfo passthrough (because we can't do multiple inheritance) + IPlayerInfo *GetPlayerInfo() { return &m_PlayerInfo; } + IBotController *GetBotController() { return &m_PlayerInfo; } + + virtual void SetModel( const char *szModelName ); + void SetBodyPitch( float flPitch ); + + virtual void UpdateOnRemove( void ); + + static CBasePlayer *CreatePlayer( const char *className, edict_t *ed ); + + virtual void CreateViewModel( int viewmodelindex = 0 ); + CBaseViewModel *GetViewModel( int viewmodelindex = 0, bool bObserverOK = true ); + void HideViewModels( void ); + void DestroyViewModels( void ); + + CPlayerState *PlayerData( void ) { return &pl; } + + int RequiredEdictIndex( void ) { return ENTINDEX(edict()); } + + void LockPlayerInPlace( void ); + void UnlockPlayer( void ); + + virtual void DrawDebugGeometryOverlays(void); + + // Networking is about to update this entity, let it override and specify it's own pvs + virtual void SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize ); + virtual int UpdateTransmitState(); + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + + // Returns true if this player wants pPlayer to be moved back in time when this player runs usercmds. + // Saves a lot of overhead on the server if we can cull out entities that don't need to lag compensate + // (like team members, entities out of our PVS, etc). + virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec *pEntityTransmitBits ) const; + + virtual void Spawn( void ); + virtual void Activate( void ); + virtual void SharedSpawn(); // Shared between client and server. + virtual void ForceRespawn( void ); + + virtual void InitialSpawn( void ); + virtual void InitHUD( void ) {} + virtual void ShowViewPortPanel( const char * name, bool bShow = true, KeyValues *data = NULL ); + + virtual void PlayerDeathThink( void ); + + virtual void Jump( void ); + virtual void Duck( void ); + + const char *GetTracerType( void ); + void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + void DoImpactEffect( trace_t &tr, int nDamageType ); + +#if !defined( NO_ENTITY_PREDICTION ) + void AddToPlayerSimulationList( CBaseEntity *other ); + void RemoveFromPlayerSimulationList( CBaseEntity *other ); + void SimulatePlayerSimulatedEntities( void ); + void ClearPlayerSimulationList( void ); +#endif + + // Physics simulation (player executes it's usercmd's here) + virtual void PhysicsSimulate( void ); + + // Forces processing of usercmds (e.g., even if game is paused, etc.) + void ForceSimulation(); + + virtual unsigned int PhysicsSolidMaskForEntity( void ) const; + + virtual void PreThink( void ); + virtual void PostThink( void ); + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + bool ShouldTakeDamageInCommentaryMode( const CTakeDamageInfo &inputInfo ); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual void DamageEffect(float flDamage, int fDamageType); + + virtual void OnDamagedByExplosion( const CTakeDamageInfo &info ); + + void PauseBonusProgress( bool bPause = true ); + void SetBonusProgress( int iBonusProgress ); + void SetBonusChallenge( int iBonusChallenge ); + + int GetBonusProgress() const { return m_iBonusProgress; } + int GetBonusChallenge() const { return m_iBonusChallenge; } + + virtual Vector EyePosition( ); // position of eyes + const QAngle &EyeAngles( ); + void EyePositionAndVectors( Vector *pPosition, Vector *pForward, Vector *pRight, Vector *pUp ); + virtual const QAngle &LocalEyeAngles(); // Direction of eyes + void EyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL ); + void CacheVehicleView( void ); // Calculate and cache the position of the player in the vehicle + + // Sets the view angles + void SnapEyeAngles( const QAngle &viewAngles ); + + virtual QAngle BodyAngles(); + virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy); + virtual bool ShouldFadeOnDeath( void ) { return FALSE; } + + virtual const impactdamagetable_t &GetPhysicsImpactDamageTable(); + virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + virtual void Event_Killed( const CTakeDamageInfo &info ); + // Notifier that I've killed some other entity. (called from Victim's Event_Killed). + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + + virtual void Event_Dying( const CTakeDamageInfo &info ); + + bool IsHLTV( void ) const { return pl.hltv; } + bool IsReplay( void ) const { return pl.replay; } + virtual bool IsPlayer( void ) const { return true; } // Spectators return TRUE for this, use IsObserver to separate cases + virtual bool IsNetClient( void ) const { return true; } // Bots should return FALSE for this, they can't receive NET messages + // Spectators should return TRUE for this + + virtual bool IsFakeClient( void ) const; + + // Get the client index (entindex-1). + int GetClientIndex() { return ENTINDEX( edict() ) - 1; } + + // returns the player name + const char * GetPlayerName() { return m_szNetname; } + void SetPlayerName( const char *name ); + + int GetUserID() { return engine->GetPlayerUserId( edict() ); } + const char * GetNetworkIDString(); + virtual const Vector GetPlayerMins( void ) const; // uses local player + virtual const Vector GetPlayerMaxs( void ) const; // uses local player + + + void VelocityPunch( const Vector &vecForce ); + void ViewPunch( const QAngle &angleOffset ); + void ViewPunchReset( float tolerance = 0 ); + void ShowViewModel( bool bShow ); + void ShowCrosshair( bool bShow ); + + // View model prediction setup + void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov ); + + // Handle view smoothing when going up stairs + void SmoothViewOnStairs( Vector& eyeOrigin ); + virtual float CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed); + void CalcViewRoll( QAngle& eyeAngles ); + + virtual int Save( ISave &save ); + virtual int Restore( IRestore &restore ); + virtual bool ShouldSavePhysics(); + virtual void OnRestore( void ); + + virtual void PackDeadPlayerItems( void ); + virtual void RemoveAllItems( bool removeSuit ); + bool IsDead() const; +#ifdef CSTRIKE_DLL + virtual bool IsRunning( void ) const { return false; } // bot support under cstrike (AR) +#endif + + bool HasPhysicsFlag( unsigned int flag ) { return (m_afPhysicsFlags & flag) != 0; } + + // Weapon stuff + virtual Vector Weapon_ShootPosition( ); + virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); + virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); + virtual void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget /* = NULL */, const Vector *pVelocity /* = NULL */ ); + virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); // Switch to given weapon if has ammo (false if failed) + virtual void Weapon_SetLast( CBaseCombatWeapon *pWeapon ); + virtual bool Weapon_ShouldSetLast( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) { return true; } + virtual bool Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon ); + void Weapon_DropSlot( int weaponSlot ); + CBaseCombatWeapon *GetLastWeapon( void ) { return m_hLastWeapon.Get(); } + + virtual void OnMyWeaponFired( CBaseCombatWeapon *weapon ); // call this when this player fires a weapon to allow other systems to react + virtual float GetTimeSinceWeaponFired( void ) const; // returns the time, in seconds, since this player fired a weapon + virtual bool IsFiringWeapon( void ) const; // return true if this player is currently firing their weapon + + bool HasAnyAmmoOfType( int nAmmoIndex ); + + // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) + virtual void UpdateClientData( void ); + void RumbleEffect( unsigned char index, unsigned char rumbleData, unsigned char rumbleFlags ); + + // Player is moved across the transition by other means + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual void Precache( void ); + bool IsOnLadder( void ); + virtual void ExitLadder() {} + virtual surfacedata_t *GetLadderSurface( const Vector &origin ); + + virtual void SetFlashlightEnabled( bool bState ) { }; + virtual int FlashlightIsOn( void ) { return false; } + virtual void FlashlightTurnOn( void ) { }; + virtual void FlashlightTurnOff( void ) { }; + virtual bool IsIlluminatedByFlashlight( CBaseEntity *pEntity, float *flReturnDot ) {return false; } + + void UpdatePlayerSound ( void ); + virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity ); + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); + virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ) { return pszBaseStepSoundName; } + virtual void GetStepSoundVelocities( float *velwalk, float *velrun ); + virtual void SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking ); + virtual void DeathSound( const CTakeDamageInfo &info ); + virtual const char* GetSceneSoundToken( void ) { return ""; } + + virtual void OnEmitFootstepSound( const CSoundParameters& params, const Vector& vecOrigin, float fVolume ) {} + + Class_T Classify ( void ); + virtual void SetAnimation( PLAYER_ANIM playerAnim ); + void SetWeaponAnimType( const char *szExtention ); + + // custom player functions + virtual void ImpulseCommands( void ); + virtual void CheatImpulseCommands( int iImpulse ); + virtual bool ClientCommand( const CCommand &args ); + + void NotifySinglePlayerGameEnding() { m_bSinglePlayerGameEnding = true; } + bool IsSinglePlayerGameEnding() { return m_bSinglePlayerGameEnding == true; } + + bool HandleVoteCommands( const CCommand &args ); + + // Observer functions + virtual bool StartObserverMode(int mode); // true, if successful + virtual void StopObserverMode( void ); // stop spectator mode + virtual bool ModeWantsSpectatorGUI( int iMode ) { return true; } + virtual bool SetObserverMode(int mode); // sets new observer mode, returns true if successful + virtual int GetObserverMode( void ); // returns observer mode or OBS_NONE + virtual bool SetObserverTarget(CBaseEntity * target); + virtual void ObserverUse( bool bIsPressed ); // observer pressed use + virtual CBaseEntity *GetObserverTarget( void ); // returns players targer or NULL + virtual CBaseEntity *FindNextObserverTarget( bool bReverse ); // returns next/prev player to follow or NULL + virtual int GetNextObserverSearchStartPoint( bool bReverse ); // Where we should start looping the player list in a FindNextObserverTarget call + virtual bool IsValidObserverTarget(CBaseEntity * target); // true, if player is allowed to see this target + virtual void CheckObserverSettings(); // checks, if target still valid (didn't die etc) + virtual void JumptoPosition(const Vector &origin, const QAngle &angles); + virtual void ForceObserverMode(int mode); // sets a temporary mode, force because of invalid targets + virtual void ResetObserverMode(); // resets all observer related settings + virtual void ValidateCurrentObserverTarget( void ); // Checks the current observer target, and moves on if it's not valid anymore + virtual void AttemptToExitFreezeCam( void ); + + virtual bool StartReplayMode( float fDelay, float fDuration, int iEntity ); + virtual void StopReplayMode(); + virtual int GetDelayTicks(); + virtual int GetReplayEntity(); + + virtual void CreateCorpse( void ) { } + virtual CBaseEntity *EntSelectSpawnPoint( void ); + + // Vehicles + virtual bool IsInAVehicle( void ) const; + bool CanEnterVehicle( IServerVehicle *pVehicle, int nRole ); + virtual bool GetInVehicle( IServerVehicle *pVehicle, int nRole ); + virtual void LeaveVehicle( const Vector &vecExitPoint = vec3_origin, const QAngle &vecExitAngles = vec3_angle ); + int GetVehicleAnalogControlBias() { return m_iVehicleAnalogBias; } + void SetVehicleAnalogControlBias( int bias ) { m_iVehicleAnalogBias = bias; } + + // override these for + virtual void OnVehicleStart() {} + virtual void OnVehicleEnd( Vector &playerDestPosition ) {} + IServerVehicle *GetVehicle(); + CBaseEntity *GetVehicleEntity( void ); + bool UsingStandardWeaponsInVehicle( void ); + + void AddPoints( int score, bool bAllowNegativeScore ); + void AddPointsToTeam( int score, bool bAllowNegativeScore ); + virtual bool BumpWeapon( CBaseCombatWeapon *pWeapon ); + bool RemovePlayerItem( CBaseCombatWeapon *pItem ); + CBaseEntity *HasNamedPlayerItem( const char *pszItemName ); + bool HasWeapons( void );// do I have ANY weapons? + virtual void SelectLastItem(void); + virtual void SelectItem( const char *pstr, int iSubType = 0 ); + void ItemPreFrame( void ); + virtual void ItemPostFrame( void ); + virtual CBaseEntity *GiveNamedItem( const char *szName, int iSubType = 0 ); + void EnableControl(bool fControl); + virtual void CheckTrainUpdate( void ); + void AbortReload( void ); + + void SendAmmoUpdate(void); + + void WaterMove( void ); + float GetWaterJumpTime() const; + void SetWaterJumpTime( float flWaterJumpTime ); + float GetSwimSoundTime( void ) const; + void SetSwimSoundTime( float flSwimSoundTime ); + + virtual void SetPlayerUnderwater( bool state ); + void UpdateUnderwaterState( void ); + bool IsPlayerUnderwater( void ) { return m_bPlayerUnderwater; } + + virtual bool CanBreatheUnderwater() const { return false; } + virtual void PlayerUse( void ); + virtual void PlayUseDenySound() {} + + virtual CBaseEntity *FindUseEntity( void ); + virtual bool IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps ); + bool ClearUseEntity(); + CBaseEntity *DoubleCheckUseNPC( CBaseEntity *pNPC, const Vector &vecSrc, const Vector &vecDir ); + + + // physics interactions + // mass/size limit set to zero for none + static bool CanPickupObject( CBaseEntity *pObject, float massLimit, float sizeLimit ); + virtual void PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize = true ) {} + virtual void ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldindThis = NULL ) {} + virtual float GetHeldObjectMass( IPhysicsObject *pHeldObject ); + + void CheckSuitUpdate(); + void SetSuitUpdate(const char *name, int fgroup, int iNoRepeat); + virtual void UpdateGeigerCounter( void ); + void CheckTimeBasedDamage( void ); + + void ResetAutoaim( void ); + + virtual Vector GetAutoaimVector( float flScale ); + virtual Vector GetAutoaimVector( float flScale, float flMaxDist ); + virtual void GetAutoaimVector( autoaim_params_t ¶ms ); + + float GetAutoaimScore( const Vector &eyePosition, const Vector &viewDir, const Vector &vecTarget, CBaseEntity *pTarget, float fScale, CBaseCombatWeapon *pActiveWeapon ); + QAngle AutoaimDeflection( Vector &vecSrc, autoaim_params_t ¶ms ); + virtual bool ShouldAutoaim( void ); + void SetTargetInfo( Vector &vecSrc, float flDist ); + + void SetViewEntity( CBaseEntity *pEntity ); + CBaseEntity *GetViewEntity( void ) { return m_hViewEntity; } + + virtual void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. + + void DeathMessage( CBaseEntity *pKiller ); + + virtual void ProcessUsercmds( CUserCmd *cmds, int numcmds, int totalcmds, + int dropped_packets, bool paused ); + bool IsUserCmdDataValid( CUserCmd *pCmd ); + + void AvoidPhysicsProps( CUserCmd *pCmd ); + + // Run a user command. The default implementation calls ::PlayerRunCommand. In TF, this controls a vehicle if + // the player is in one. + virtual void PlayerRunCommand(CUserCmd *ucmd, IMoveHelper *moveHelper); + void RunNullCommand(); + CUserCmd * GetCurrentCommand( void ) { return m_pCurrentCommand; } + float GetTimeSinceLastUserCommand( void ) { return ( !IsConnected() || IsFakeClient() || IsBot() ) ? 0.f : gpGlobals->curtime - m_flLastUserCommandTime; } + + // Team Handling + virtual void ChangeTeam( int iTeamNum ) { ChangeTeam(iTeamNum,false, false); } + virtual void ChangeTeam( int iTeamNum, bool bAutoTeam, bool bSilent ); + + // say/sayteam allowed? + virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer ) { return true; } + virtual bool CanSpeak( void ) { return true; } + + audioparams_t &GetAudioParams() { return m_Local.m_audio; } + + virtual void ModifyOrAppendPlayerCriteria( AI_CriteriaSet& set ); + + const QAngle& GetPunchAngle(); + void SetPunchAngle( const QAngle &punchAngle ); + + virtual void DoMuzzleFlash(); + + const char *GetLastKnownPlaceName( void ) const { return m_szLastPlaceName; } // return the last nav place name the player occupied + + virtual void CheckChatText( char *p, int bufsize ) {} + + virtual void CreateRagdollEntity( void ) { return; } + + virtual void HandleAnimEvent( animevent_t *pEvent ); + + virtual bool ShouldAnnounceAchievement( void ); + +#if defined USES_ECON_ITEMS + // Wearables + virtual void EquipWearable( CEconWearable *pItem ); + virtual void RemoveWearable( CEconWearable *pItem ); + void PlayWearableAnimsForPlaybackEvent( wearableanimplayback_t iPlayback ); +#endif + +public: + // Player Physics Shadow + void SetupVPhysicsShadow( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, CPhysCollide *pStandModel, const char *pStandHullName, CPhysCollide *pCrouchModel, const char *pCrouchHullName ); + IPhysicsPlayerController* GetPhysicsController() { return m_pPhysicsController; } + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + void VPhysicsUpdate( IPhysicsObject *pPhysics ); + virtual void VPhysicsShadowUpdate( IPhysicsObject *pPhysics ); + virtual bool IsFollowingPhysics( void ) { return false; } + bool IsRideablePhysics( IPhysicsObject *pPhysics ); + IPhysicsObject *GetGroundVPhysics(); + + virtual void Touch( CBaseEntity *pOther ); + void SetTouchedPhysics( bool bTouch ); + bool TouchedPhysics( void ); + Vector GetSmoothedVelocity( void ); + + virtual void RefreshCollisionBounds( void ); + virtual void InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity ); + virtual void VPhysicsDestroyObject(); + void SetVCollisionState( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, int collisionState ); + void PostThinkVPhysics( void ); + virtual void UpdatePhysicsShadowToCurrentPosition(); + void UpdatePhysicsShadowToPosition( const Vector &vecAbsOrigin ); + void UpdateVPhysicsPosition( const Vector &position, const Vector &velocity, float secondsToArrival ); + + // Hint system + virtual CHintSystem *Hints( void ) { return NULL; } + bool ShouldShowHints( void ) { return Hints() ? Hints()->ShouldShowHints() : false; } + void SetShowHints( bool bShowHints ) { if (Hints()) Hints()->SetShowHints( bShowHints ); } + bool HintMessage( int hint, bool bForce = false ) { return Hints() ? Hints()->HintMessage( hint, bForce ) : false; } + void HintMessage( const char *pMessage ) { if (Hints()) Hints()->HintMessage( pMessage ); } + void StartHintTimer( int iHintID ) { if (Hints()) Hints()->StartHintTimer( iHintID ); } + void StopHintTimer( int iHintID ) { if (Hints()) Hints()->StopHintTimer( iHintID ); } + void RemoveHintTimer( int iHintID ) { if (Hints()) Hints()->RemoveHintTimer( iHintID ); } + + // Accessor methods + int FragCount() const { return m_iFrags; } + int DeathCount() const { return m_iDeaths;} + bool IsConnected() const { return m_iConnected != PlayerDisconnected; } + bool IsDisconnecting() const { return m_iConnected == PlayerDisconnecting; } + bool IsSuitEquipped() const { return m_Local.m_bWearingSuit; } + int ArmorValue() const { return m_ArmorValue; } + bool HUDNeedsRestart() const { return m_fInitHUD; } + float MaxSpeed() const { return m_flMaxspeed; } + Activity GetActivity( ) const { return m_Activity; } + inline void SetActivity( Activity eActivity ) { m_Activity = eActivity; } + bool IsPlayerLockedInPlace() const { return m_iPlayerLocked != 0; } + bool IsObserver() const { return (m_afPhysicsFlags & PFLAG_OBSERVER) != 0; } + bool IsOnTarget() const { return m_fOnTarget; } + float MuzzleFlashTime() const { return m_flFlashTime; } + float PlayerDrownTime() const { return m_AirFinished; } + + int GetObserverMode() const { return m_iObserverMode; } + CBaseEntity *GetObserverTarget() const { return m_hObserverTarget; } + + // Round gamerules + virtual bool IsReadyToPlay( void ) { return true; } + virtual bool IsReadyToSpawn( void ) { return true; } + virtual bool ShouldGainInstantSpawn( void ) { return false; } + virtual void ResetPerRoundStats( void ) { return; } + void AllowInstantSpawn( void ) { m_bAllowInstantSpawn = true; } + + virtual void ResetScores( void ) { ResetFragCount(); ResetDeathCount(); } + void ResetFragCount(); + void IncrementFragCount( int nCount ); + + void ResetDeathCount(); + void IncrementDeathCount( int nCount ); + + void SetArmorValue( int value ); + void IncrementArmorValue( int nCount, int nMaxValue = -1 ); + + void SetConnected( PlayerConnectedState iConnected ) { m_iConnected = iConnected; } + virtual void EquipSuit( bool bPlayEffects = true ); + virtual void RemoveSuit( void ); + void SetMaxSpeed( float flMaxSpeed ) { m_flMaxspeed = flMaxSpeed; } + + void NotifyNearbyRadiationSource( float flRange ); + + void SetAnimationExtension( const char *pExtension ); + + void SetAdditionalPVSOrigin( const Vector &vecOrigin ); + void SetCameraPVSOrigin( const Vector &vecOrigin ); + void SetMuzzleFlashTime( float flTime ); + void SetUseEntity( CBaseEntity *pUseEntity ); + CBaseEntity *GetUseEntity(); + + virtual float GetPlayerMaxSpeed(); + + // Used to set private physics flags PFLAG_* + void SetPhysicsFlag( int nFlag, bool bSet ); + + void AllowImmediateDecalPainting(); + + // Suicide... + virtual void CommitSuicide( bool bExplode = false, bool bForce = false ); + virtual void CommitSuicide( const Vector &vecForce, bool bExplode = false, bool bForce = false ); + + // For debugging... + void ForceOrigin( const Vector &vecOrigin ); + + // Bot accessors... + void SetTimeBase( float flTimeBase ); + float GetTimeBase() const; + void SetLastUserCommand( const CUserCmd &cmd ); + const CUserCmd *GetLastUserCommand( void ); + + virtual bool IsBot() const; // IMPORTANT: This returns true for ANY type of bot. If your game uses different, incompatible types of bots check your specific bot type before casting + virtual bool IsBotOfType( int botType ) const; // return true if this player is a bot of the specific type (zero is invalid) + virtual int GetBotType( void ) const; // return a unique int representing the type of bot instance this is + + bool IsPredictingWeapons( void ) const; + int CurrentCommandNumber() const; + const CUserCmd *GetCurrentUserCommand() const; + int GetLockViewanglesTickNumber() const { return m_iLockViewanglesTickNumber; } + QAngle GetLockViewanglesData() const { return m_qangLockViewangles; } + + int GetFOV( void ); // Get the current FOV value + int GetDefaultFOV( void ) const; // Default FOV if not specified otherwise + int GetFOVForNetworking( void ); // Get the current FOV used for network computations + bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0 ); // Alters the base FOV of the player (must have a valid requester) + void SetDefaultFOV( int FOV ); // Sets the base FOV if nothing else is affecting it by zooming + CBaseEntity *GetFOVOwner( void ) { return m_hZoomOwner; } + float GetFOVDistanceAdjustFactor(); // shared between client and server + float GetFOVDistanceAdjustFactorForNetworking(); + + int GetImpulse( void ) const { return m_nImpulse; } + + // Movement constraints + void ActivateMovementConstraint( CBaseEntity *pEntity, const Vector &vecCenter, float flRadius, float flConstraintWidth, float flSpeedFactor ); + void DeactivateMovementConstraint( ); + + // talk control + void NotePlayerTalked() { m_fLastPlayerTalkTime = gpGlobals->curtime; } + float LastTimePlayerTalked() { return m_fLastPlayerTalkTime; } + + void DisableButtons( int nButtons ); + void EnableButtons( int nButtons ); + void ForceButtons( int nButtons ); + void UnforceButtons( int nButtons ); + + //--------------------------------- + // Inputs + //--------------------------------- + void InputSetHealth( inputdata_t &inputdata ); + void InputSetHUDVisibility( inputdata_t &inputdata ); + void InputHandleMapEvent( inputdata_t &inputdata ); + + surfacedata_t *GetSurfaceData( void ) { return m_pSurfaceData; } + void SetLadderNormal( Vector vecLadderNormal ) { m_vecLadderNormal = vecLadderNormal; } + + // Here so that derived classes can use the expresser + virtual CAI_Expresser *GetExpresser() { return NULL; }; + +#if !defined(NO_STEAM) + //---------------------------- + // Steam handling + bool GetSteamID( CSteamID *pID ); + uint64 GetSteamIDAsUInt64( void ); +#endif + + float GetRemainingMovementTimeForUserCmdProcessing() const { return m_flMovementTimeForUserCmdProcessingRemaining; } + float ConsumeMovementTimeForUserCmdProcessing( float flTimeNeeded ) + { + if ( m_flMovementTimeForUserCmdProcessingRemaining <= 0.0f ) + { + return 0.0f; + } + else if ( flTimeNeeded > m_flMovementTimeForUserCmdProcessingRemaining + FLT_EPSILON ) + { + float flResult = m_flMovementTimeForUserCmdProcessingRemaining; + m_flMovementTimeForUserCmdProcessingRemaining = 0.0f; + return flResult; + } + else + { + m_flMovementTimeForUserCmdProcessingRemaining -= flTimeNeeded; + if ( m_flMovementTimeForUserCmdProcessingRemaining < 0.0f ) + m_flMovementTimeForUserCmdProcessingRemaining = 0.0f; + return flTimeNeeded; + } + } + +private: + // How much of a movement time buffer can we process from this user? + float m_flMovementTimeForUserCmdProcessingRemaining; + + // For queueing up CUserCmds and running them from PhysicsSimulate + int GetCommandContextCount( void ) const; + CCommandContext *GetCommandContext( int index ); + CCommandContext *AllocCommandContext( void ); + void RemoveCommandContext( int index ); + void RemoveAllCommandContexts( void ); + CCommandContext *RemoveAllCommandContextsExceptNewest( void ); + void ReplaceContextCommands( CCommandContext *ctx, CUserCmd *pCommands, int nCommands ); + + int DetermineSimulationTicks( void ); + void AdjustPlayerTimeBase( int simulation_ticks ); + +public: + + // How long since this player last interacted with something the game considers an objective/target/goal + float GetTimeSinceLastObjective( void ) const { return ( m_flLastObjectiveTime == -1.f ) ? 999.f : gpGlobals->curtime - m_flLastObjectiveTime; } + void SetLastObjectiveTime( float flTime ) { m_flLastObjectiveTime = flTime; } + + // Used by gamemovement to check if the entity is stuck. + int m_StuckLast; + + // FIXME: Make these protected or private! + + // This player's data that should only be replicated to + // the player and not to other players. + CNetworkVarEmbedded( CPlayerLocalData, m_Local ); + +#if defined USES_ECON_ITEMS + CNetworkVarEmbedded( CAttributeList, m_AttributeList ); +#endif + + void InitFogController( void ); + void InputSetFogController( inputdata_t &inputdata ); + + // Used by env_soundscape_triggerable to manage when the player is touching multiple + // soundscape triggers simultaneously. + // The one at the HEAD of the list is always the current soundscape for the player. + CUtlVector m_hTriggerSoundscapeList; + + // Player data that's sometimes needed by the engine + CNetworkVarEmbedded( CPlayerState, pl ); + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_fFlags ); + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_vecViewOffset ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_flFriction ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iAmmo ); + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_hGroundEntity ); + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_lifeState ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iHealth ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_vecBaseVelocity ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_nNextThinkTick ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_vecVelocity ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_nWaterLevel ); + + int m_nButtons; + int m_afButtonPressed; + int m_afButtonReleased; + int m_afButtonLast; + int m_afButtonDisabled; // A mask of input flags that are cleared automatically + int m_afButtonForced; // These are forced onto the player's inputs + + CNetworkVar( bool, m_fOnTarget ); //Is the crosshair on a target? + + char m_szAnimExtension[32]; + + int m_nUpdateRate; // user snapshot rate cl_updaterate + float m_fLerpTime; // users cl_interp + bool m_bLagCompensation; // user wants lag compenstation + bool m_bPredictWeapons; // user has client side predicted weapons + + float GetDeathTime( void ) { return m_flDeathTime; } + + void ClearZoomOwner( void ); + + void SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin ); + const Vector &GetPreviouslyPredictedOrigin() const; + float GetFOVTime( void ){ return m_flFOVTime; } + + void AdjustDrownDmg( int nAmount ); + +#if defined USES_ECON_ITEMS + CEconWearable *GetWearable( int i ) { return m_hMyWearables[i]; } + const CEconWearable *GetWearable( int i ) const { return m_hMyWearables[i]; } + int GetNumWearables( void ) const { return m_hMyWearables.Count(); } +#endif + +private: + + Activity m_Activity; + float m_flLastObjectiveTime; // Last curtime player touched/killed something the gamemode considers an objective + +protected: + + void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcVehicleView( IServerVehicle *pVehicle, Vector& eyeOrigin, QAngle& eyeAngles, + float& zNear, float& zFar, float& fov ); + void CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles); + + virtual void Internal_HandleMapEvent( inputdata_t &inputdata ){} + + // FIXME: Make these private! (tf_player uses them) + + // Secondary point to derive PVS from when zoomed in with binoculars/sniper rifle. The PVS is + // a merge of the standing origin and this additional origin + Vector m_vecAdditionalPVSOrigin; + // Extra PVS origin if we are using a camera object + Vector m_vecCameraPVSOrigin; + + CNetworkHandle( CBaseEntity, m_hUseEntity ); // the player is currently controlling this entity because of +USE latched, NULL if no entity + + int m_iTrain; // Train control position + + float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn + unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden + + // Vehicles + CNetworkHandle( CBaseEntity, m_hVehicle ); + + int m_iVehicleAnalogBias; + + void UpdateButtonState( int nUserCmdButtonMask ); + + bool m_bPauseBonusProgress; + CNetworkVar( int, m_iBonusProgress ); + CNetworkVar( int, m_iBonusChallenge ); + + int m_lastDamageAmount; // Last damage taken + + Vector m_DmgOrigin; + float m_DmgTake; + float m_DmgSave; + int m_bitsDamageType; // what types of damage has player taken + int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to the hud via gmsgDamage + + CNetworkVar( float, m_flDeathTime ); // the time at which the player died (used in PlayerDeathThink()) + float m_flDeathAnimTime; // the time at which the player finished their death anim (used in PlayerDeathThink() and ShouldTransmit()) + + CNetworkVar( int, m_iObserverMode ); // if in spectator mode != 0 + CNetworkVar( int, m_iFOV ); // field of view + CNetworkVar( int, m_iDefaultFOV ); // default field of view + CNetworkVar( int, m_iFOVStart ); // What our FOV started at + CNetworkVar( float, m_flFOVTime ); // Time our FOV change started + + int m_iObserverLastMode; // last used observer mode + CNetworkHandle( CBaseEntity, m_hObserverTarget ); // entity handle to m_iObserverTarget + bool m_bForcedObserverMode; // true, player was forced by invalid targets to switch mode + + CNetworkHandle( CBaseEntity, m_hZoomOwner ); //This is a pointer to the entity currently controlling the player's zoom + //Only this entity can change the zoom state once it has ownership + + float m_tbdPrev; // Time-based damage timer + int m_idrowndmg; // track drowning damage taken + int m_idrownrestored; // track drowning damage restored + int m_nPoisonDmg; // track recoverable poison damage taken + int m_nPoisonRestored; // track poison damage restored + // NOTE: bits damage type appears to only be used for time-based damage + BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; + + // Player Physics Shadow + int m_vphysicsCollisionState; + + virtual int SpawnArmorValue( void ) const { return 0; } + + float m_fNextSuicideTime; // the time after which the player can next use the suicide command + int m_iSuicideCustomKillFlags; + + // Replay mode + float m_fDelay; // replay delay in seconds + float m_fReplayEnd; // time to stop replay mode + int m_iReplayEntity; // follow this entity in replay + +private: + void HandleFuncTrain(); + +// DATA +private: + CUtlVector< CCommandContext > m_CommandContext; + // Player Physics Shadow + +protected: //used to be private, but need access for portal mod (Dave Kircher) + IPhysicsPlayerController *m_pPhysicsController; + IPhysicsObject *m_pShadowStand; + IPhysicsObject *m_pShadowCrouch; + Vector m_oldOrigin; + Vector m_vecSmoothedVelocity; + bool m_touchedPhysObject; + bool m_bPhysicsWasFrozen; + +private: + + int m_iPlayerSound;// the index of the sound list slot reserved for this player + int m_iTargetVolume;// ideal sound volume. + + int m_rgItems[MAX_ITEMS]; + + // these are time-sensitive things that we keep track of + float m_flSwimTime; // how long player has been underwater + float m_flDuckTime; // how long we've been ducking + float m_flDuckJumpTime; + + float m_flSuitUpdate; // when to play next suit update + int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update + int m_iSuitPlayNext; // next sentence slot for queue storage; + int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list + float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat + + float m_flgeigerRange; // range to nearest radiation source + float m_flgeigerDelay; // delay per update of range msg to client + int m_igeigerRangePrev; + + bool m_fInitHUD; // True when deferred HUD restart msg needs to be sent + bool m_fGameHUDInitialized; + bool m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info + + int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages + int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new + + // Autoaim data + QAngle m_vecAutoAim; + int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE + + int m_iFrags; + int m_iDeaths; + + float m_flNextDecalTime;// next time this player can spray a decal + + // Team Handling + // char m_szTeamName[TEAM_NAME_LENGTH]; + + // Multiplayer handling + PlayerConnectedState m_iConnected; + + // from edict_t + // CBasePlayer doesn't send this but CCSPlayer does. + CNetworkVarForDerived( int, m_ArmorValue ); + float m_AirFinished; + float m_PainFinished; + + // player locking + int m_iPlayerLocked; + +protected: + // the player's personal view model + typedef CHandle CBaseViewModelHandle; + CNetworkArray( CBaseViewModelHandle, m_hViewModel, MAX_VIEWMODELS ); + + // Last received usercmd (in case we drop a lot of packets ) + CUserCmd m_LastCmd; + CUserCmd *m_pCurrentCommand; + int m_iLockViewanglesTickNumber; + QAngle m_qangLockViewangles; + + float m_flStepSoundTime; // time to check for next footstep sound + + bool m_bAllowInstantSpawn; + +#if defined USES_ECON_ITEMS + // Wearables + CUtlVector > m_hMyWearables; +#endif + +private: + +// Replicated to all clients + CNetworkVar( float, m_flMaxspeed ); + +// Not transmitted + float m_flWaterJumpTime; // used to be called teleport_time + Vector m_vecWaterJumpVel; + int m_nImpulse; + float m_flSwimSoundTime; + Vector m_vecLadderNormal; + + float m_flFlashTime; + int m_nDrownDmgRate; // Drowning damage in points per second without air. + + int m_nNumCrouches; // Number of times we've crouched (for hinting) + bool m_bDuckToggled; // If true, the player is crouching via a toggle + +public: + bool GetToggledDuckState( void ) { return m_bDuckToggled; } + void ToggleDuck( void ); + float GetStickDist( void ); + + float m_flForwardMove; + float m_flSideMove; + int m_nNumCrateHudHints; + +private: + + // Used in test code to teleport the player to random locations in the map. + Vector m_vForcedOrigin; + bool m_bForceOrigin; + + // Clients try to run on their own realtime clock, this is this client's clock + CNetworkVar( int, m_nTickBase ); + + bool m_bGamePaused; + float m_fLastPlayerTalkTime; + + CNetworkVar( CBaseCombatWeaponHandle, m_hLastWeapon ); + +#if !defined( NO_ENTITY_PREDICTION ) + CUtlVector< CHandle< CBaseEntity > > m_SimulatedByThisPlayer; +#endif + + float m_flOldPlayerZ; + float m_flOldPlayerViewOffsetZ; + + bool m_bPlayerUnderwater; + + EHANDLE m_hViewEntity; + + // Movement constraints + CNetworkHandle( CBaseEntity, m_hConstraintEntity ); + CNetworkVector( m_vecConstraintCenter ); + CNetworkVar( float, m_flConstraintRadius ); + CNetworkVar( float, m_flConstraintWidth ); + CNetworkVar( float, m_flConstraintSpeedFactor ); + + friend class CPlayerMove; + friend class CPlayerClass; + + // Player name + char m_szNetname[MAX_PLAYER_NAME_LENGTH]; + +protected: + // HACK FOR TF2 Prediction + friend class CTFGameMovementRecon; + friend class CGameMovement; + friend class CTFGameMovement; + friend class CHL1GameMovement; + friend class CCSGameMovement; + friend class CHL2GameMovement; + friend class CDODGameMovement; + friend class CPortalGameMovement; + + // Accessors for gamemovement + bool IsDucked( void ) const { return m_Local.m_bDucked; } + bool IsDucking( void ) const { return m_Local.m_bDucking; } + float GetStepSize( void ) const { return m_Local.m_flStepSize; } + + CNetworkVar( float, m_flLaggedMovementValue ); + + // These are generated while running usercmds, then given to UpdateVPhysicsPosition after running all queued commands. + Vector m_vNewVPhysicsPosition; + Vector m_vNewVPhysicsVelocity; + + Vector m_vecVehicleViewOrigin; // Used to store the calculated view of the player while riding in a vehicle + QAngle m_vecVehicleViewAngles; // Vehicle angles + float m_flVehicleViewFOV; // FOV of the vehicle driver + int m_nVehicleViewSavedFrame; // Used to mark which frame was the last one the view was calculated for + + Vector m_vecPreviouslyPredictedOrigin; // Used to determine if non-gamemovement game code has teleported, or tweaked the player's origin + int m_nBodyPitchPoseParam; + + CNetworkString( m_szLastPlaceName, MAX_PLACE_NAME_LENGTH ); + + char m_szNetworkIDString[MAX_NETWORKID_LENGTH]; + CPlayerInfo m_PlayerInfo; + + // Texture names and surface data, used by CGameMovement + int m_surfaceProps; + surfacedata_t* m_pSurfaceData; + float m_surfaceFriction; + char m_chTextureType; + char m_chPreviousTextureType; // Separate from m_chTextureType. This is cleared if the player's not on the ground. + + bool m_bSinglePlayerGameEnding; + +public: + + float GetLaggedMovementValue( void ){ return m_flLaggedMovementValue; } + void SetLaggedMovementValue( float flValue ) { m_flLaggedMovementValue = flValue; } + + inline bool IsAutoKickDisabled( void ) const; + inline void DisableAutoKick( bool disabled ); + + void DumpPerfToRecipient( CBasePlayer *pRecipient, int nMaxRecords ); + // NVNT returns true if user has a haptic device + virtual bool HasHaptics(){return m_bhasHaptics;} + // NVNT sets weather a user should receive haptic device messages. + virtual void SetHaptics(bool has) { m_bhasHaptics = has;} +private: + // NVNT member variable holding if this user is using a haptic device. + bool m_bhasHaptics; + + bool m_autoKickDisabled; + + struct StepSoundCache_t + { + StepSoundCache_t() : m_usSoundNameIndex( 0 ) {} + CSoundParameters m_SoundParameters; + unsigned short m_usSoundNameIndex; + }; + // One for left and one for right side of step + StepSoundCache_t m_StepSoundCache[ 2 ]; + + CUtlLinkedList< CPlayerSimInfo > m_vecPlayerSimInfo; + CUtlLinkedList< CPlayerCmdInfo > m_vecPlayerCmdInfo; + + IntervalTimer m_weaponFiredTimer; + + // Store the last time we successfully processed a usercommand + float m_flLastUserCommandTime; + + // used to prevent achievement announcement spam + CUtlVector< float > m_flAchievementTimes; + +public: + virtual unsigned int PlayerSolidMask( bool brushOnly = false ) const; // returns the solid mask for the given player, so bots can have a more-restrictive set + +}; + +typedef CHandle CBasePlayerHandle; + +EXTERN_SEND_TABLE(DT_BasePlayer) + + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline bool CBasePlayer::IsBotOfType( int botType ) const +{ + // bot type of zero is invalid + return ( GetBotType() != 0 ) && ( GetBotType() == botType ); +} + +inline int CBasePlayer::GetBotType( void ) const +{ + return 0; +} + +inline bool CBasePlayer::IsAutoKickDisabled( void ) const +{ + return m_autoKickDisabled; +} + +inline void CBasePlayer::DisableAutoKick( bool disabled ) +{ + m_autoKickDisabled = disabled; +} + +inline void CBasePlayer::SetAdditionalPVSOrigin( const Vector &vecOrigin ) +{ + m_vecAdditionalPVSOrigin = vecOrigin; +} + +inline void CBasePlayer::SetCameraPVSOrigin( const Vector &vecOrigin ) +{ + m_vecCameraPVSOrigin = vecOrigin; +} + +inline void CBasePlayer::SetMuzzleFlashTime( float flTime ) +{ + m_flFlashTime = flTime; +} + +inline void CBasePlayer::SetUseEntity( CBaseEntity *pUseEntity ) +{ + m_hUseEntity = pUseEntity; +} + +inline CBaseEntity *CBasePlayer::GetUseEntity() +{ + return m_hUseEntity; +} + +// Bot accessors... +inline void CBasePlayer::SetTimeBase( float flTimeBase ) +{ + m_nTickBase = TIME_TO_TICKS( flTimeBase ); +} + +inline void CBasePlayer::SetLastUserCommand( const CUserCmd &cmd ) +{ + m_LastCmd = cmd; +} + +inline CUserCmd const *CBasePlayer::GetLastUserCommand( void ) +{ + return &m_LastCmd; +} + +inline bool CBasePlayer::IsPredictingWeapons( void ) const +{ + return m_bPredictWeapons; +} + +inline int CBasePlayer::CurrentCommandNumber() const +{ + Assert( m_pCurrentCommand ); + return m_pCurrentCommand->command_number; +} + +inline const CUserCmd *CBasePlayer::GetCurrentUserCommand() const +{ + Assert( m_pCurrentCommand ); + return m_pCurrentCommand; +} + +inline IServerVehicle *CBasePlayer::GetVehicle() +{ + CBaseEntity *pVehicleEnt = m_hVehicle.Get(); + return pVehicleEnt ? pVehicleEnt->GetServerVehicle() : NULL; +} + +inline CBaseEntity *CBasePlayer::GetVehicleEntity() +{ + return m_hVehicle.Get(); +} + +inline bool CBasePlayer::IsInAVehicle( void ) const +{ + return ( NULL != m_hVehicle.Get() ) ? true : false; +} + +inline void CBasePlayer::SetTouchedPhysics( bool bTouch ) +{ + m_touchedPhysObject = bTouch; +} + +inline bool CBasePlayer::TouchedPhysics( void ) +{ + return m_touchedPhysObject; +} + +inline void CBasePlayer::OnMyWeaponFired( CBaseCombatWeapon *weapon ) +{ + m_weaponFiredTimer.Start(); +} + +inline float CBasePlayer::GetTimeSinceWeaponFired( void ) const +{ + return m_weaponFiredTimer.GetElapsedTime(); +} + +inline bool CBasePlayer::IsFiringWeapon( void ) const +{ + return m_weaponFiredTimer.HasStarted() && m_weaponFiredTimer.IsLessThen( 1.0f ); +} + + + +//----------------------------------------------------------------------------- +// Converts an entity to a player +//----------------------------------------------------------------------------- +inline CBasePlayer *ToBasePlayer( CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; +#if _DEBUG + return dynamic_cast( pEntity ); +#else + return static_cast( pEntity ); +#endif +} + +inline const CBasePlayer *ToBasePlayer( const CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; +#if _DEBUG + return dynamic_cast( pEntity ); +#else + return static_cast( pEntity ); +#endif +} + + +//-------------------------------------------------------------------------------------------------------------- +/** + * DEPRECATED: Use CollectPlayers() instead. + * Iterate over all active players in the game, invoking functor on each. + * If functor returns false, stop iteration and return false. + */ +template < typename Functor > +bool ForEachPlayer( Functor &func ) +{ + for( int i=1; i<=gpGlobals->maxClients; ++i ) + { + CBasePlayer *player = static_cast( UTIL_PlayerByIndex( i ) ); + + if (player == NULL) + continue; + + if (FNullEnt( player->edict() )) + continue; + + if (!player->IsPlayer()) + continue; + + if( !player->IsConnected() ) + continue; + + if (func( player ) == false) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------------------------- +/** + * The interface for an iterative player functor + */ +class IPlayerFunctor +{ +public: + virtual void OnBeginIteration( void ) { } // invoked once before iteration begins + + virtual bool operator() ( CBasePlayer *player ) = 0; + + virtual void OnEndIteration( bool allElementsIterated ) { } // invoked once after iteration is complete whether successful or not +}; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * DEPRECATED: Use CollectPlayers() instead. + * Specialization of ForEachPlayer template for IPlayerFunctors + */ +template <> +inline bool ForEachPlayer( IPlayerFunctor &func ) +{ + func.OnBeginIteration(); + + bool isComplete = true; + + for( int i=1; i<=gpGlobals->maxClients; ++i ) + { + CBasePlayer *player = static_cast( UTIL_PlayerByIndex( i ) ); + + if (player == NULL) + continue; + + if (FNullEnt( player->edict() )) + continue; + + if (!player->IsPlayer()) + continue; + + if( !player->IsConnected() ) + continue; + + if (func( player ) == false) + { + isComplete = false; + break; + } + } + + func.OnEndIteration( isComplete ); + + return isComplete; +} + +//-------------------------------------------------------------------------------------------------------------- +// +// Collect all valid, connected players into given vector. +// Returns number of players collected. +// +#define COLLECT_ONLY_LIVING_PLAYERS true +#define APPEND_PLAYERS true +template < typename T > +int CollectPlayers( CUtlVector< T * > *playerVector, int team = TEAM_ANY, bool isAlive = false, bool shouldAppend = false ) +{ + if ( !shouldAppend ) + { + playerVector->RemoveAll(); + } + + for( int i=1; i<=gpGlobals->maxClients; ++i ) + { + CBasePlayer *player = UTIL_PlayerByIndex( i ); + + if ( player == NULL ) + continue; + + if ( FNullEnt( player->edict() ) ) + continue; + + if ( !player->IsPlayer() ) + continue; + + if ( !player->IsConnected() ) + continue; + + if ( team != TEAM_ANY && player->GetTeamNumber() != team ) + continue; + + if ( isAlive && !player->IsAlive() ) + continue; + + playerVector->AddToTail( assert_cast< T * >( player ) ); + } + + return playerVector->Count(); +} + +template < typename T > +int CollectHumanPlayers( CUtlVector< T * > *playerVector, int team = TEAM_ANY, bool isAlive = false, bool shouldAppend = false ) +{ + if ( !shouldAppend ) + { + playerVector->RemoveAll(); + } + + for( int i=1; i<=gpGlobals->maxClients; ++i ) + { + CBasePlayer *player = UTIL_PlayerByIndex( i ); + + if ( player == NULL ) + continue; + + if ( FNullEnt( player->edict() ) ) + continue; + + if ( !player->IsPlayer() ) + continue; + + if ( player->IsBot() ) + continue; + + if ( !player->IsConnected() ) + continue; + + if ( team != TEAM_ANY && player->GetTeamNumber() != team ) + continue; + + if ( isAlive && !player->IsAlive() ) + continue; + + playerVector->AddToTail( assert_cast< T * >( player ) ); + } + + return playerVector->Count(); +} + +enum +{ + VEHICLE_ANALOG_BIAS_NONE = 0, + VEHICLE_ANALOG_BIAS_FORWARD, + VEHICLE_ANALOG_BIAS_REVERSE, +}; + +#endif // PLAYER_H diff --git a/game/server/player_command.h b/game/server/player_command.h new file mode 100644 index 0000000..574fc8d --- /dev/null +++ b/game/server/player_command.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYER_COMMAND_H +#define PLAYER_COMMAND_H +#pragma once + + +#include "edict.h" +#include "usercmd.h" + + +class IMoveHelper; +class CMoveData; +class CBasePlayer; + +//----------------------------------------------------------------------------- +// Purpose: Server side player movement +//----------------------------------------------------------------------------- +class CPlayerMove +{ +public: + DECLARE_CLASS_NOBASE( CPlayerMove ); + + // Construction/destruction + CPlayerMove( void ); + virtual ~CPlayerMove( void ) {} + + // Public interfaces: + // Run a movement command from the player + void RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *moveHelper ); + +protected: + // Prepare for running movement + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + + // Finish movement + virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ); + + // Called before and after any movement processing + virtual void StartCommand( CBasePlayer *player, CUserCmd *cmd ); + void FinishCommand( CBasePlayer *player ); + + // Helper to determine if the user is standing on ground + void CheckMovingGround( CBasePlayer *player, double frametime ); + + // Helpers to call pre and post think for player, and to call think if a think function is set + void RunPreThink( CBasePlayer *player ); + void RunThink (CBasePlayer *ent, double frametime ); + void RunPostThink( CBasePlayer *player ); +}; + + +//----------------------------------------------------------------------------- +// Singleton accessor +//----------------------------------------------------------------------------- +CPlayerMove *PlayerMove(); + + +#endif // PLAYER_COMMAND_H diff --git a/game/server/player_pickup.h b/game/server/player_pickup.h new file mode 100644 index 0000000..1b6d252 --- /dev/null +++ b/game/server/player_pickup.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: APIs for player pickup of physics objects +// +//=============================================================================// + +#ifndef PLAYER_PICKUP_H +#define PLAYER_PICKUP_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef HL2_DLL +// Needed for launch velocity +extern ConVar physcannon_minforce; +extern ConVar physcannon_maxforce; +#endif + +// Reasons behind a pickup +enum PhysGunPickup_t +{ + PICKED_UP_BY_CANNON, + PUNTED_BY_CANNON, + PICKED_UP_BY_PLAYER, // Picked up by +USE, not physgun. +}; + +// Reasons behind a drop +enum PhysGunDrop_t +{ + DROPPED_BY_PLAYER, + THROWN_BY_PLAYER, + DROPPED_BY_CANNON, + LAUNCHED_BY_CANNON, +}; + +enum PhysGunForce_t +{ + PHYSGUN_FORCE_DROPPED, // Dropped by +USE + PHYSGUN_FORCE_THROWN, // Thrown from +USE + PHYSGUN_FORCE_PUNTED, // Punted by cannon + PHYSGUN_FORCE_LAUNCHED, // Launched by cannon +}; + +void PlayerPickupObject( CBasePlayer *pPlayer, CBaseEntity *pObject ); +void Pickup_ForcePlayerToDropThisObject( CBaseEntity *pTarget ); + +void Pickup_OnPhysGunDrop( CBaseEntity *pDroppedObject, CBasePlayer *pPlayer, PhysGunDrop_t reason ); +void Pickup_OnPhysGunPickup( CBaseEntity *pPickedUpObject, CBasePlayer *pPlayer, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ); +bool Pickup_OnAttemptPhysGunPickup( CBaseEntity *pPickedUpObject, CBasePlayer *pPlayer, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ); +bool Pickup_GetPreferredCarryAngles( CBaseEntity *pObject, CBasePlayer *pPlayer, matrix3x4_t &localToWorld, QAngle &outputAnglesWorldSpace ); +bool Pickup_ForcePhysGunOpen( CBaseEntity *pObject, CBasePlayer *pPlayer ); +bool Pickup_ShouldPuntUseLaunchForces( CBaseEntity *pObject, PhysGunForce_t reason ); +AngularImpulse Pickup_PhysGunLaunchAngularImpulse( CBaseEntity *pObject, PhysGunForce_t reason ); +Vector Pickup_DefaultPhysGunLaunchVelocity( const Vector &vecForward, float flMass ); +Vector Pickup_PhysGunLaunchVelocity( CBaseEntity *pObject, const Vector &vecForward, PhysGunForce_t reason ); + +CBaseEntity *Pickup_OnFailedPhysGunPickup( CBaseEntity *pPickedUpObject, Vector vPhysgunPos ); + +abstract_class IPlayerPickupVPhysics +{ +public: + // Callbacks for the physgun/cannon picking up an entity + virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) = 0; + virtual CBaseEntity *OnFailedPhysGunPickup( Vector vPhysgunPos ) = 0; + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) = 0; + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ) = 0; + virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer = NULL ) = 0; + virtual QAngle PreferredCarryAngles( void ) = 0; + virtual bool ForcePhysgunOpen( CBasePlayer *pPlayer ) = 0; + virtual AngularImpulse PhysGunLaunchAngularImpulse() = 0; + virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) = 0; + virtual Vector PhysGunLaunchVelocity( const Vector &vecForward, float flMass ) = 0; +}; + +class CDefaultPlayerPickupVPhysics : public IPlayerPickupVPhysics +{ +public: + virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) { return true; } + virtual CBaseEntity *OnFailedPhysGunPickup( Vector vPhysgunPos ) { return NULL; } + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) {} + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ) {} + virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) { return false; } + virtual QAngle PreferredCarryAngles( void ) { return vec3_angle; } + virtual bool ForcePhysgunOpen( CBasePlayer *pPlayer ) { return false; } + virtual AngularImpulse PhysGunLaunchAngularImpulse() { return RandomAngularImpulse( -600, 600 ); } + virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) { return false; } + virtual Vector PhysGunLaunchVelocity( const Vector &vecForward, float flMass ) + { + return Pickup_DefaultPhysGunLaunchVelocity( vecForward, flMass ); + } +}; + +#endif // PLAYER_PICKUP_H diff --git a/game/server/player_resource.h b/game/server/player_resource.h new file mode 100644 index 0000000..298eda0 --- /dev/null +++ b/game/server/player_resource.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Entity that propagates general data needed by clients for every player. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYER_RESOURCE_H +#define PLAYER_RESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +class CPlayerResource : public CBaseEntity +{ + DECLARE_CLASS( CPlayerResource, CBaseEntity ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + virtual void Spawn( void ); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_DONT_SAVE; } + virtual void ResourceThink( void ); + virtual void UpdatePlayerData( void ); + virtual int UpdateTransmitState(void); + +protected: + // Data for each player that's propagated to all clients + // Stored in individual arrays so they can be sent down via datatables + CNetworkArray( int, m_iPing, MAX_PLAYERS+1 ); + CNetworkArray( int, m_iScore, MAX_PLAYERS+1 ); + CNetworkArray( int, m_iDeaths, MAX_PLAYERS+1 ); + CNetworkArray( int, m_bConnected, MAX_PLAYERS+1 ); + CNetworkArray( int, m_iTeam, MAX_PLAYERS+1 ); + CNetworkArray( int, m_bAlive, MAX_PLAYERS+1 ); + CNetworkArray( int, m_iHealth, MAX_PLAYERS+1 ); + + int m_nUpdateCounter; +}; + +extern CPlayerResource *g_pPlayerResource; + +#endif // PLAYER_RESOURCE_H diff --git a/game/server/playerinfomanager.h b/game/server/playerinfomanager.h new file mode 100644 index 0000000..33eb1fa --- /dev/null +++ b/game/server/playerinfomanager.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: implementation of player info manager +// +//=============================================================================// +#ifndef PLAYERINFOMANAGER_H +#define PLAYERINFOMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "game/server/iplayerinfo.h" + +//----------------------------------------------------------------------------- +// Purpose: interface for plugins to get player info +//----------------------------------------------------------------------------- +class CPlayerInfoManager: public IPlayerInfoManager +{ +public: + virtual IPlayerInfo *GetPlayerInfo( edict_t *pEdict ); + virtual CGlobalVars *GetGlobalVars(); +}; + +class CPluginBotManager: public IBotManager +{ +public: + virtual IBotController *GetBotController( edict_t *pEdict ); + virtual edict_t *CreateBot( const char *botname ); +}; + +#endif \ No newline at end of file diff --git a/game/server/playerlocaldata.h b/game/server/playerlocaldata.h new file mode 100644 index 0000000..04dc3a8 --- /dev/null +++ b/game/server/playerlocaldata.h @@ -0,0 +1,92 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERLOCALDATA_H +#define PLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "playernet_vars.h" +#include "networkvar.h" +#include "fogcontroller.h" + +//----------------------------------------------------------------------------- +// Purpose: Player specific data ( sent only to local player, too ) +//----------------------------------------------------------------------------- +class CPlayerLocalData +{ +public: + // Save/restore + DECLARE_SIMPLE_DATADESC(); + // Prediction data copying + DECLARE_CLASS_NOBASE( CPlayerLocalData ); + DECLARE_EMBEDDED_NETWORKVAR(); + + CPlayerLocalData(); + + void UpdateAreaBits( CBasePlayer *pl, unsigned char chAreaPortalBits[MAX_AREA_PORTAL_STATE_BYTES] ); + + +public: + + CNetworkArray( unsigned char, m_chAreaBits, MAX_AREA_STATE_BYTES ); // Which areas are potentially visible to the client? + CNetworkArray( unsigned char, m_chAreaPortalBits, MAX_AREA_PORTAL_STATE_BYTES ); // Which area portals are open? + + CNetworkVar( int, m_iHideHUD ); // bitfields containing sections of the HUD to hide + CNetworkVar( float, m_flFOVRate ); // rate at which the FOV changes (defaults to 0) + + Vector m_vecOverViewpoint; // Viewpoint overriding the real player's viewpoint + + // Fully ducked + CNetworkVar( bool, m_bDucked ); + // In process of ducking + CNetworkVar( bool, m_bDucking ); + // In process of duck-jumping + CNetworkVar( bool, m_bInDuckJump ); + // During ducking process, amount of time before full duc + CNetworkVar( float, m_flDucktime ); + CNetworkVar( float, m_flDuckJumpTime ); + // Jump time, time to auto unduck (since we auto crouch jump now). + CNetworkVar( float, m_flJumpTime ); + // Step sound side flip/flip + int m_nStepside;; + // Velocity at time when we hit ground + CNetworkVar( float, m_flFallVelocity ); + // Previous button state + int m_nOldButtons; + class CSkyCamera *m_pOldSkyCamera; + // Base velocity that was passed in to server physics so + // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. + // auto-decaying view angle adjustment + CNetworkQAngle( m_vecPunchAngle ); + CNetworkQAngle( m_vecPunchAngleVel ); + // Draw view model for the player + CNetworkVar( bool, m_bDrawViewmodel ); + + // Is the player wearing the HEV suit + CNetworkVar( bool, m_bWearingSuit ); + CNetworkVar( bool, m_bPoisoned ); + CNetworkVar( float, m_flStepSize ); + CNetworkVar( bool, m_bAllowAutoMovement ); + + // 3d skybox + CNetworkVarEmbedded( sky3dparams_t, m_skybox3d ); + // world fog + CNetworkVarEmbedded( fogplayerparams_t, m_PlayerFog ); + fogparams_t m_fog; + // audio environment + CNetworkVarEmbedded( audioparams_t, m_audio ); + + CNetworkVar( bool, m_bSlowMovement ); +}; + +EXTERN_SEND_TABLE(DT_Local); + + +#endif // PLAYERLOCALDATA_H diff --git a/game/server/point_camera.h b/game/server/point_camera.h new file mode 100644 index 0000000..499b3a3 --- /dev/null +++ b/game/server/point_camera.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CAMERA_H +#define CAMERA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPointCamera : public CBaseEntity +{ +public: + DECLARE_CLASS( CPointCamera, CBaseEntity ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + CPointCamera(); + ~CPointCamera(); + + void Spawn( void ); + + // Tell the client that this camera needs to be rendered + void SetActive( bool bActive ); + int UpdateTransmitState(void); + + void ChangeFOVThink( void ); + + void InputChangeFOV( inputdata_t &inputdata ); + void InputSetOnAndTurnOthersOff( inputdata_t &inputdata ); + void InputSetOn( inputdata_t &inputdata ); + void InputSetOff( inputdata_t &inputdata ); + +private: + float m_TargetFOV; + float m_DegreesPerSecond; + + CNetworkVar( float, m_FOV ); + CNetworkVar( float, m_Resolution ); + CNetworkVar( bool, m_bFogEnable ); + CNetworkColor32( m_FogColor ); + CNetworkVar( float, m_flFogStart ); + CNetworkVar( float, m_flFogEnd ); + CNetworkVar( float, m_flFogMaxDensity ); + CNetworkVar( bool, m_bActive ); + CNetworkVar( bool, m_bUseScreenAspectRatio ); + + // Allows the mapmaker to control whether a camera is active or not + bool m_bIsOn; + +public: + CPointCamera *m_pNext; +}; + +CPointCamera *GetPointCameraList(); +#endif // CAMERA_H diff --git a/game/server/point_template.h b/game/server/point_template.h new file mode 100644 index 0000000..94e3742 --- /dev/null +++ b/game/server/point_template.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Point entity used to create templates out of other entities or groups of entities +// +//=============================================================================// + +#ifndef POINT_TEMPLATE_H +#define POINT_TEMPLATE_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAX_NUM_TEMPLATES 16 + +struct template_t +{ + int iTemplateIndex; + VMatrix matEntityToTemplate; + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPointTemplate : public CLogicalEntity +{ + DECLARE_CLASS( CPointTemplate, CLogicalEntity ); +public: + DECLARE_DATADESC(); + + virtual void Spawn( void ); + virtual void Precache(); + + // Template initialization + void StartBuildingTemplates( void ); + void FinishBuildingTemplates( void ); + + // Template Entity accessors + int GetNumTemplateEntities( void ); + CBaseEntity *GetTemplateEntity( int iTemplateNumber ); + void AddTemplate( CBaseEntity *pEntity, const char *pszMapData, int nLen ); + bool ShouldRemoveTemplateEntities( void ); + bool AllowNameFixup(); + + // Templates accessors + int GetNumTemplates( void ); + int GetTemplateIndexForTemplate( int iTemplate ); + + // Template instancing + bool CreateInstance( const Vector &vecOrigin, const QAngle &vecAngles, CUtlVector *pEntities ); + + // Inputs + void InputForceSpawn( inputdata_t &inputdata ); + + virtual void PerformPrecache(); + +private: + string_t m_iszTemplateEntityNames[MAX_NUM_TEMPLATES]; + + // List of map entities this template targets. Built inside our Spawn(). + // It's only valid between Spawn() & Activate(), because the map entity parsing + // code removes all the entities in it once it finishes turning them into templates. + CUtlVector< CBaseEntity * > m_hTemplateEntities; + + // List of templates, generated from our template entities. + CUtlVector< template_t > m_hTemplates; + + COutputEvent m_pOutputOnSpawned; +}; + +#endif // POINT_TEMPLATE_H diff --git a/game/server/props.h b/game/server/props.h new file mode 100644 index 0000000..7dc9f48 --- /dev/null +++ b/game/server/props.h @@ -0,0 +1,440 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef PROPS_H +#define PROPS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "props_shared.h" +#include "baseanimating.h" +#include "physics_bone_follower.h" +#include "player_pickup.h" +#include "positionwatcher.h" + +//============================================================================================================= +// PROP TYPES +//============================================================================================================= +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBaseProp : public CBaseAnimating +{ + DECLARE_CLASS( CBaseProp, CBaseAnimating ); +public: + + void Spawn( void ); + void Precache( void ); + void Activate( void ); + bool KeyValue( const char *szKeyName, const char *szValue ); + void CalculateBlockLOS( void ); + int ParsePropData( void ); + + void DrawDebugGeometryOverlays( void ); + + // Don't treat as a live target + virtual bool IsAlive( void ) { return false; } + virtual bool OverridePropdata() { return true; } +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBreakableProp : public CBaseProp, public IBreakableWithPropData, public CDefaultPlayerPickupVPhysics +{ +public: + CBreakableProp(); + + DECLARE_CLASS( CBreakableProp, CBaseProp ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + virtual void Spawn(); + virtual void Precache(); + virtual float GetAutoAimRadius() { return 24.0f; } + + void BreakablePropTouch( CBaseEntity *pOther ); + + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + void Break( CBaseEntity *pBreaker, const CTakeDamageInfo &info ); + void BreakThink( void ); + void AnimateThink( void ); + + virtual void PlayPuntSound(); + + void InputBreak( inputdata_t &inputdata ); + void InputAddHealth( inputdata_t &inputdata ); + void InputRemoveHealth( inputdata_t &inputdata ); + void InputSetHealth( inputdata_t &inputdata ); + + int GetNumBreakableChunks( void ) { return m_iNumBreakableChunks; } + + virtual bool OverridePropdata() { return false; } + virtual IPhysicsObject *GetRootPhysicsObjectForBreak(); + + bool PropDataOverrodeBlockLOS( void ) { return m_bBlockLOSSetByPropData; } + bool PropDataOverrodeAIWalkable( void ) { return m_bIsWalkableSetByPropData; } + + virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) + { + if ( HasInteraction( PROPINTER_PHYSGUN_LAUNCH_SPIN_Z ) ) + return true; + + return false; + } + + virtual QAngle PreferredCarryAngles( void ) { return m_preferredCarryAngles; } + + virtual void Ignite( float flFlameLifetime, bool bNPCOnly, float flSize = 0.0f, bool bCalledByLevelDesigner = false ); + + // Specific interactions + void HandleFirstCollisionInteractions( int index, gamevcollisionevent_t *pEvent ); + void HandleInteractionStick( int index, gamevcollisionevent_t *pEvent ); + void StickAtPosition( const Vector &stickPosition, const Vector &savePosition, const QAngle &saveAngles ); + + // Disable auto fading under dx7 or when level fades are specified + void DisableAutoFade(); + +public: + COutputEvent m_OnBreak; + COutputFloat m_OnHealthChanged; + COutputEvent m_OnTakeDamage; + + float m_impactEnergyScale; + + int m_iMinHealthDmg; + + QAngle m_preferredCarryAngles; + +public: +// IBreakableWithPropData + void SetDmgModBullet( float flDmgMod ) { m_flDmgModBullet = flDmgMod; } + void SetDmgModClub( float flDmgMod ) { m_flDmgModClub = flDmgMod; } + void SetDmgModExplosive( float flDmgMod ) { m_flDmgModExplosive = flDmgMod; } + float GetDmgModBullet( void ) { return m_flDmgModBullet; } + float GetDmgModClub( void ) { return m_flDmgModClub; } + float GetDmgModExplosive( void ) { return m_flDmgModExplosive; } + void SetExplosiveRadius( float flRadius ) { m_explodeRadius = flRadius; } + void SetExplosiveDamage( float flDamage ) { m_explodeDamage = flDamage; } + float GetExplosiveRadius( void ) { return m_explodeRadius; } + float GetExplosiveDamage( void ) { return m_explodeDamage; } + void SetPhysicsDamageTable( string_t iszTableName ) { m_iszPhysicsDamageTableName = iszTableName; } + string_t GetPhysicsDamageTable( void ) { return m_iszPhysicsDamageTableName; } + void SetBreakableModel( string_t iszModel ) { m_iszBreakableModel = iszModel; } + string_t GetBreakableModel( void ) { return m_iszBreakableModel; } + void SetBreakableSkin( int iSkin ) { m_iBreakableSkin = iSkin; } + int GetBreakableSkin( void ) { return m_iBreakableSkin; } + void SetBreakableCount( int iCount ) { m_iBreakableCount = iCount; } + int GetBreakableCount( void ) { return m_iBreakableCount; } + void SetMaxBreakableSize( int iSize ) { m_iMaxBreakableSize = iSize; } + int GetMaxBreakableSize( void ) { return m_iMaxBreakableSize; } + void SetPropDataBlocksLOS( bool bBlocksLOS ) { m_bBlockLOSSetByPropData = true; SetBlocksLOS( bBlocksLOS ); } + void SetPropDataIsAIWalkable( bool b ) { m_bIsWalkableSetByPropData = true; SetAIWalkable( b ); } + void SetBasePropData( string_t iszBase ) { m_iszBasePropData = iszBase; } + string_t GetBasePropData( void ) { return m_iszBasePropData; } + void SetInteraction( propdata_interactions_t Interaction ) { m_iInteractions |= (1 << Interaction); } + void RemoveInteraction( propdata_interactions_t Interaction ) { m_iInteractions &= ~(1 << Interaction); } + bool HasInteraction( propdata_interactions_t Interaction ) { return ( m_iInteractions & (1 << Interaction) ) != 0; } + void SetMultiplayerBreakMode( mp_break_t mode ) { m_mpBreakMode = mode; } + mp_break_t GetMultiplayerBreakMode( void ) const { return m_mpBreakMode; } + +// derived by multiplayer phys props: + virtual void SetPhysicsMode(int iMode) {} + virtual int GetPhysicsMode() { return PHYSICS_MULTIPLAYER_SOLID; } + + // Copy fade from another breakable prop + void CopyFadeFrom( CBreakableProp *pSource ); + +protected: + + bool UpdateHealth( int iNewHealth, CBaseEntity *pActivator ); + virtual void OnBreak( const Vector &vecVelocity, const AngularImpulse &angVel, CBaseEntity *pBreaker ) {} + +protected: + + unsigned int m_createTick; + float m_flPressureDelay; + EHANDLE m_hBreaker; + + PerformanceMode_t m_PerformanceMode; + + // Prop data storage + float m_flDmgModBullet; + float m_flDmgModClub; + float m_flDmgModExplosive; + string_t m_iszPhysicsDamageTableName; + string_t m_iszBreakableModel; + int m_iBreakableSkin; + int m_iBreakableCount; + int m_iMaxBreakableSize; + string_t m_iszBasePropData; + int m_iInteractions; + float m_explodeDamage; + float m_explodeRadius; + string_t m_iszBreakModelMessage; + + // Count of how many pieces we'll break into, custom or generic + int m_iNumBreakableChunks; + + void SetEnableMotionPosition( const Vector &position, const QAngle &angles ); + bool GetEnableMotionPosition( Vector *pPosition, QAngle *pAngles ); + void ClearEnableMotionPosition(); +private: + CBaseEntity *FindEnableMotionFixup(); + +public: + virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); + virtual AngularImpulse PhysGunLaunchAngularImpulse(); + virtual CBasePlayer *HasPhysicsAttacker( float dt ); + +#ifdef HL2_EPISODIC + void CreateFlare( float flLifetime ); +#endif //HL2_EPISODIC + +protected: + void SetPhysicsAttacker( CBasePlayer *pEntity, float flTime ); + void CheckRemoveRagdolls(); + +private: + void InputEnablePhyscannonPickup( inputdata_t &inputdata ); + void InputDisablePhyscannonPickup( inputdata_t &inputdata ); + + void InputEnablePuntSound( inputdata_t &inputdata ) { m_bUsePuntSound = true; } + void InputDisablePuntSound( inputdata_t &inputdata ) { m_bUsePuntSound = false; } + + // Prevents fade scale from happening + void ForceFadeScaleToAlwaysVisible(); + void RampToDefaultFadeScale(); + +private: + enum PhysgunState_t + { + PHYSGUN_MUST_BE_DETACHED = 0, + PHYSGUN_IS_DETACHING, + PHYSGUN_CAN_BE_GRABBED, + PHYSGUN_ANIMATE_ON_PULL, + PHYSGUN_ANIMATE_IS_ANIMATING, + PHYSGUN_ANIMATE_FINISHED, + PHYSGUN_ANIMATE_IS_PRE_ANIMATING, + PHYSGUN_ANIMATE_IS_POST_ANIMATING, + }; + + CHandle m_hPhysicsAttacker; + float m_flLastPhysicsInfluenceTime; + bool m_bBlockLOSSetByPropData; + bool m_bIsWalkableSetByPropData; + bool m_bOriginalBlockLOS; // BlockLOS state before physgun pickup + char m_nPhysgunState; // Ripped-off state + COutputEvent m_OnPhysCannonDetach; // We've ripped it off! + COutputEvent m_OnPhysCannonAnimatePreStarted; // Started playing the pre-pull animation + COutputEvent m_OnPhysCannonAnimatePullStarted; // Player started the pull anim + COutputEvent m_OnPhysCannonAnimatePostStarted; // Started playing the post-pull animation + COutputEvent m_OnPhysCannonPullAnimFinished; // We've had our pull anim finished, or the post-pull has finished if there is one + float m_flDefaultFadeScale; // Things may temporarily change the fade scale, but this is its steady-state condition + + mp_break_t m_mpBreakMode; + + EHANDLE m_hLastAttacker; // Last attacker that harmed me. + EHANDLE m_hFlareEnt; + string_t m_iszPuntSound; + bool m_bUsePuntSound; +}; + +// Spawnflags +#define SF_DYNAMICPROP_USEHITBOX_FOR_RENDERBOX 64 +#define SF_DYNAMICPROP_NO_VPHYSICS 128 +#define SF_DYNAMICPROP_DISABLE_COLLISION 256 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CDynamicProp : public CBreakableProp, public IPositionWatcher +{ + DECLARE_CLASS( CDynamicProp, CBreakableProp ); + +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CDynamicProp(); + + void Spawn( void ); + bool CreateVPhysics( void ); + void CreateBoneFollowers(); + void UpdateOnRemove( void ); + void AnimThink( void ); + void PropSetSequence( int nSequence ); + void OnRestore( void ); + bool OverridePropdata( void ); + void HandleAnimEvent( animevent_t *pEvent ); + + // baseentity - watch dynamic hierarchy updates + virtual void SetParent( CBaseEntity* pNewParent, int iAttachment = -1 ); + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + + // breakable prop + virtual IPhysicsObject *GetRootPhysicsObjectForBreak(); + + // IPositionWatcher + virtual void NotifyPositionChanged( CBaseEntity *pEntity ); + + // Input handlers + void InputSetAnimation( inputdata_t &inputdata ); + void InputSetDefaultAnimation( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + void InputDisableCollision( inputdata_t &inputdata ); + void InputEnableCollision( inputdata_t &inputdata ); + void InputSetPlaybackRate( inputdata_t &inputdata ); + + COutputEvent m_pOutputAnimBegun; + COutputEvent m_pOutputAnimOver; + + string_t m_iszDefaultAnim; + + int m_iGoalSequence; + int m_iTransitionDirection; + + // Random animations + bool m_bRandomAnimator; + float m_flNextRandAnim; + float m_flMinRandAnimTime; + float m_flMaxRandAnimTime; + short m_nPendingSequence; + + bool m_bStartDisabled; + bool m_bDisableBoneFollowers; + + CNetworkVar( bool, m_bUseHitboxesForRenderBox ); + +protected: + void FinishSetSequence( int nSequence ); + void PropSetAnim( const char *szAnim ); + void BoneFollowerHierarchyChanged(); + + // Contained Bone Follower manager + CBoneFollowerManager m_BoneFollowerManager; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +DECLARE_AUTO_LIST( IPhysicsPropAutoList ); +class CPhysicsProp : public CBreakableProp, public IPhysicsPropAutoList +{ + DECLARE_CLASS( CPhysicsProp, CBreakableProp ); + DECLARE_SERVERCLASS(); + +public: + ~CPhysicsProp(); + CPhysicsProp( void ) + { + } + + void Spawn( void ); + void Precache(); + bool CreateVPhysics( void ); + bool OverridePropdata( void ); + + virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + + void InputWake( inputdata_t &inputdata ); + void InputSleep( inputdata_t &inputdata ); + void InputEnableMotion( inputdata_t &inputdata ); + void InputDisableMotion( inputdata_t &inputdata ); + void InputDisableFloating( inputdata_t &inputdata ); + + void EnableMotion( void ); + bool CanBePickedUpByPhyscannon( void ); + void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); + + bool GetPropDataAngles( const char *pKeyName, QAngle &vecAngles ); + float GetCarryDistanceOffset( void ); + + int ObjectCaps(); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + void GetMassCenter( Vector *pMassCenter ); + float GetMass() const; + + void ClearFlagsThink( void ); + + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + int DrawDebugTextOverlays(void); + bool IsGib(); + DECLARE_DATADESC(); + + // Specific interactions + void HandleAnyCollisionInteractions( int index, gamevcollisionevent_t *pEvent ); + + string_t GetPhysOverrideScript( void ) { return m_iszOverrideScript; } + float GetMassScale( void ) { return m_massScale; } + +private: + // Compute impulse to apply to the enabled entity. + void ComputeEnablingImpulse( int index, gamevcollisionevent_t *pEvent ); + + COutputEvent m_MotionEnabled; + COutputEvent m_OnAwakened; + COutputEvent m_OnPhysGunPickup; + COutputEvent m_OnPhysGunPunt; + COutputEvent m_OnPhysGunOnlyPickup; + COutputEvent m_OnPhysGunDrop; + COutputEvent m_OnPlayerUse; + COutputEvent m_OnPlayerPickup; + COutputEvent m_OnOutOfWorld; + + float m_massScale; + float m_inertiaScale; + int m_damageType; + string_t m_iszOverrideScript; + int m_damageToEnableMotion; + float m_flForceToEnableMotion; + + bool m_bThrownByPlayer; + bool m_bFirstCollisionAfterLaunch; + +protected: + CNetworkVar( bool, m_bAwake ); +}; + + +// An interface so that objects parented to props can receive collision interaction events. +enum parentCollisionInteraction_t +{ + COLLISIONINTER_PARENT_FIRST_IMPACT = 1, +}; + + +abstract_class IParentPropInteraction +{ +public: + virtual void OnParentCollisionInteraction( parentCollisionInteraction_t eType, int index, gamevcollisionevent_t *pEvent ) = 0; + virtual void OnParentPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ) = 0; +}; + + +// Used by prop_physics_create and the server benchmark. +// pModelName should not include the "models/" prefix. +CPhysicsProp* CreatePhysicsProp( const char *pModelName, const Vector &vTraceStart, const Vector &vTraceEnd, const IHandleEntity *pTraceIgnore, bool bRequireVCollide, const char *pClassName="physics_prop" ); + +bool UTIL_CreateScaledPhysObject( CBaseAnimating *pInstance, float flScale ); + +float GetBreakableDamage( const CTakeDamageInfo &inputInfo, IBreakableWithPropData *pProp = NULL ); +int PropBreakablePrecacheAll( string_t modelName ); + +extern ConVar func_breakdmg_bullet; +extern ConVar func_breakdmg_club; +extern ConVar func_breakdmg_explosive; + +#endif // PROPS_H diff --git a/game/server/pushentity.h b/game/server/pushentity.h new file mode 100644 index 0000000..f1c02d3 --- /dev/null +++ b/game/server/pushentity.h @@ -0,0 +1,160 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#ifndef PUSHENTITY_H +#define PUSHENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "movetype_push.h" + +//----------------------------------------------------------------------------- +// Purpose: Keeps track of original positions of any entities that are being possibly pushed +// and handles restoring positions for those objects if the push is aborted +//----------------------------------------------------------------------------- +class CPhysicsPushedEntities +{ +public: + + DECLARE_CLASS_NOBASE( CPhysicsPushedEntities ); + + CPhysicsPushedEntities( void ); + + // Purpose: Tries to rotate an entity hierarchy, returns the blocker if any + CBaseEntity *PerformRotatePush( CBaseEntity *pRoot, float movetime ); + + // Purpose: Tries to linearly push an entity hierarchy, returns the blocker if any + CBaseEntity *PerformLinearPush( CBaseEntity *pRoot, float movetime ); + + int CountMovedEntities() { return m_rgMoved.Count(); } + void StoreMovedEntities( physicspushlist_t &list ); + void BeginPush( CBaseEntity *pRootEntity ); + +protected: + + // describes the per-frame incremental motion of a rotating MOVETYPE_PUSH + struct RotatingPushMove_t + { + Vector origin; + matrix3x4_t startLocalToWorld; + matrix3x4_t endLocalToWorld; + QAngle amove; // delta orientation + }; + + // Pushers + their original positions also (for touching triggers) + struct PhysicsPusherInfo_t + { + CBaseEntity *m_pEntity; + Vector m_vecStartAbsOrigin; + }; + + // Pushed entities + various state related to them being pushed + struct PhysicsPushedInfo_t + { + CBaseEntity *m_pEntity; + Vector m_vecStartAbsOrigin; + trace_t m_Trace; + bool m_bBlocked; + bool m_bPusherIsGround; + }; + + // Adds the specified entity to the list + void AddEntity( CBaseEntity *ent ); + + // If a move fails, restores all entities to their original positions + void RestoreEntities( ); + + // Compute the direction to move the rotation blocker + void ComputeRotationalPushDirection( CBaseEntity *pBlocker, const RotatingPushMove_t &rotPushMove, Vector *pMove, CBaseEntity *pRoot ); + + // Speculatively checks to see if all entities in this list can be pushed + bool SpeculativelyCheckPush( PhysicsPushedInfo_t &info, const Vector &vecAbsPush, bool bRotationalPush ); + + // Speculatively checks to see if all entities in this list can be pushed + virtual bool SpeculativelyCheckRotPush( const RotatingPushMove_t &rotPushMove, CBaseEntity *pRoot ); + + // Speculatively checks to see if all entities in this list can be pushed + virtual bool SpeculativelyCheckLinearPush( const Vector &vecAbsPush ); + + // Registers a blockage + CBaseEntity *RegisterBlockage(); + + // Some fixup for objects pushed by rotating objects + virtual void FinishRotPushedEntity( CBaseEntity *pPushedEntity, const RotatingPushMove_t &rotPushMove ); + + // Commits the speculative movement + void FinishPush( bool bIsRotPush = false, const RotatingPushMove_t *pRotPushMove = NULL ); + + // Generates a list of all entities potentially blocking all pushers + void GenerateBlockingEntityList(); + void GenerateBlockingEntityListAddBox( const Vector &vecMoved ); + + // Purpose: Gets a list of all entities hierarchically attached to the root + void SetupAllInHierarchy( CBaseEntity *pParent ); + + // Unlink + relink the pusher list so we can actually do the push + void UnlinkPusherList( int *pPusherHandles ); + void RelinkPusherList( int *pPusherHandles ); + + // Causes all entities in the list to touch triggers from their prev position + void FinishPushers(); + + // Purpose: Rotates the root entity, fills in the pushmove structure + void RotateRootEntity( CBaseEntity *pRoot, float movetime, RotatingPushMove_t &rotation ); + + // Purpose: Linearly moves the root entity + void LinearlyMoveRootEntity( CBaseEntity *pRoot, float movetime, Vector *pAbsPushVector ); + + bool IsPushedPositionValid( CBaseEntity *pBlocker ); + +protected: + + CUtlVector m_rgPusher; + CUtlVector m_rgMoved; + int m_nBlocker; + bool m_bIsUnblockableByPlayer; + Vector m_rootPusherStartLocalOrigin; + QAngle m_rootPusherStartLocalAngles; + float m_rootPusherStartLocaltime; + float m_flMoveTime; + + friend class CPushBlockerEnum; +}; + +class CTraceFilterPushMove : public CTraceFilterSimple +{ + DECLARE_CLASS( CTraceFilterPushMove, CTraceFilterSimple ); + +public: + CTraceFilterPushMove( CBaseEntity *pEntity, int nCollisionGroup ) + : CTraceFilterSimple( pEntity, nCollisionGroup ) + { + m_pRootParent = pEntity->GetRootMoveParent(); + } + + bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ) + { + Assert( dynamic_cast(pHandleEntity) ); + CBaseEntity *pTestEntity = static_cast(pHandleEntity); + + if ( UTIL_EntityHasMatchingRootParent( m_pRootParent, pTestEntity ) ) + return false; + + if ( pTestEntity->GetMoveType() == MOVETYPE_VPHYSICS && + pTestEntity->VPhysicsGetObject() && pTestEntity->VPhysicsGetObject()->IsMoveable() ) + return false; + + return BaseClass::ShouldHitEntity( pHandleEntity, contentsMask ); + } + +private: + + CBaseEntity *m_pRootParent; +}; + +extern CPhysicsPushedEntities *g_pPushedEntities; + +#endif // PUSHENTITY_H \ No newline at end of file diff --git a/game/server/recipientfilter.h b/game/server/recipientfilter.h new file mode 100644 index 0000000..30af93a --- /dev/null +++ b/game/server/recipientfilter.h @@ -0,0 +1,241 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RECIPIENTFILTER_H +#define RECIPIENTFILTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "irecipientfilter.h" +#include "const.h" +#include "player.h" +#include "bitvec.h" + +//----------------------------------------------------------------------------- +// Purpose: A generic filter for determining whom to send message/sounds etc. to and +// providing a bit of additional state information +//----------------------------------------------------------------------------- +class CRecipientFilter : public IRecipientFilter +{ +public: + CRecipientFilter(); + virtual ~CRecipientFilter(); + + virtual bool IsReliable( void ) const; + virtual bool IsInitMessage( void ) const; + + virtual int GetRecipientCount( void ) const; + virtual int GetRecipientIndex( int slot ) const; + +public: + + void CopyFrom( const CRecipientFilter& src ); + + void Reset( void ); + + void MakeInitMessage( void ); + + void MakeReliable( void ); + + void AddAllPlayers( void ); + void AddRecipientsByPVS( const Vector& origin ); + void RemoveRecipientsByPVS( const Vector& origin ); + void AddRecipientsByPAS( const Vector& origin ); + void AddRecipient( const CBasePlayer *player ); + void RemoveAllRecipients( void ); + void RemoveRecipient( CBasePlayer *player ); + void RemoveRecipientByPlayerIndex( int playerindex ); + void AddRecipientsByTeam( CTeam *team ); + void RemoveRecipientsByTeam( CTeam *team ); + void RemoveRecipientsNotOnTeam( CTeam *team ); + + void UsePredictionRules( void ); + bool IsUsingPredictionRules( void ) const; + + bool IgnorePredictionCull( void ) const; + void SetIgnorePredictionCull( bool ignore ); + + void AddPlayersFromBitMask( CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ); + void RemovePlayersFromBitMask( CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ); + +private: + + bool m_bReliable; + bool m_bInitMessage; + CUtlVector< int > m_Recipients; + + // If using prediction rules, the filter itself suppresses local player + bool m_bUsingPredictionRules; + // If ignoring prediction cull, then external systems can determine + // whether this is a special case where culling should not occur + bool m_bIgnorePredictionCull; +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for a single player ( unreliable ) +//----------------------------------------------------------------------------- +class CSingleUserRecipientFilter : public CRecipientFilter +{ +public: + CSingleUserRecipientFilter( const CBasePlayer *player ) + { + AddRecipient( player ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for all players on a given team +//----------------------------------------------------------------------------- +class CTeamRecipientFilter : public CRecipientFilter +{ +public: + CTeamRecipientFilter( int team, bool isReliable = false ); +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for all players ( unreliable ) +//----------------------------------------------------------------------------- +class CBroadcastRecipientFilter : public CRecipientFilter +{ +public: + CBroadcastRecipientFilter( void ) + { + AddAllPlayers(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for all players ( reliable ) +//----------------------------------------------------------------------------- +class CReliableBroadcastRecipientFilter : public CBroadcastRecipientFilter +{ +public: + CReliableBroadcastRecipientFilter( void ) + { + MakeReliable(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple class to create a filter for all players except for one ( unreliable ) +//----------------------------------------------------------------------------- +class CBroadcastNonOwnerRecipientFilter : public CRecipientFilter +{ +public: + CBroadcastNonOwnerRecipientFilter( CBasePlayer *player ) + { + AddAllPlayers(); + RemoveRecipient( player ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Add players in PAS to recipient list (unreliable) +//----------------------------------------------------------------------------- +class CPASFilter : public CRecipientFilter +{ +public: + CPASFilter( void ) + { + } + + CPASFilter( const Vector& origin ) + { + AddRecipientsByPAS( origin ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Add players in PAS to list and if not in single player, use attenuation +// to remove those that are too far away from source origin +// Source origin can be stated as an entity or just a passed in origin +// (unreliable) +//----------------------------------------------------------------------------- +class CPASAttenuationFilter : public CPASFilter +{ +public: + CPASAttenuationFilter( void ) + { + } + + CPASAttenuationFilter( CBaseEntity *entity, soundlevel_t soundlevel ) : + CPASFilter( static_cast(entity->GetSoundEmissionOrigin()) ) + { + Filter( entity->GetSoundEmissionOrigin(), SNDLVL_TO_ATTN( soundlevel ) ); + } + + CPASAttenuationFilter( CBaseEntity *entity, float attenuation = ATTN_NORM ) : + CPASFilter( static_cast(entity->GetSoundEmissionOrigin()) ) + { + Filter( entity->GetSoundEmissionOrigin(), attenuation ); + } + + CPASAttenuationFilter( const Vector& origin, soundlevel_t soundlevel ) : + CPASFilter( origin ) + { + Filter( origin, SNDLVL_TO_ATTN( soundlevel ) ); + } + + CPASAttenuationFilter( const Vector& origin, float attenuation = ATTN_NORM ) : + CPASFilter( origin ) + { + Filter( origin, attenuation ); + } + + CPASAttenuationFilter( CBaseEntity *entity, const char *lookupSound ) : + CPASFilter( static_cast(entity->GetSoundEmissionOrigin()) ) + { + soundlevel_t level = CBaseEntity::LookupSoundLevel( lookupSound ); + float attenuation = SNDLVL_TO_ATTN( level ); + Filter( entity->GetSoundEmissionOrigin(), attenuation ); + } + + CPASAttenuationFilter( const Vector& origin, const char *lookupSound ) : + CPASFilter( origin ) + { + soundlevel_t level = CBaseEntity::LookupSoundLevel( lookupSound ); + float attenuation = SNDLVL_TO_ATTN( level ); + Filter( origin, attenuation ); + } + + CPASAttenuationFilter( CBaseEntity *entity, const char *lookupSound, HSOUNDSCRIPTHANDLE& handle ) : + CPASFilter( static_cast(entity->GetSoundEmissionOrigin()) ) + { + soundlevel_t level = CBaseEntity::LookupSoundLevel( lookupSound, handle ); + float attenuation = SNDLVL_TO_ATTN( level ); + Filter( entity->GetSoundEmissionOrigin(), attenuation ); + } + + CPASAttenuationFilter( const Vector& origin, const char *lookupSound, HSOUNDSCRIPTHANDLE& handle ) : + CPASFilter( origin ) + { + soundlevel_t level = CBaseEntity::LookupSoundLevel( lookupSound, handle ); + float attenuation = SNDLVL_TO_ATTN( level ); + Filter( origin, attenuation ); + } + + + + +public: + void Filter( const Vector& origin, float attenuation = ATTN_NORM ); +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple PVS based filter ( unreliable ) +//----------------------------------------------------------------------------- +class CPVSFilter : public CRecipientFilter +{ +public: + CPVSFilter( const Vector& origin ) + { + AddRecipientsByPVS( origin ); + } +}; + +#endif // RECIPIENTFILTER_H diff --git a/game/server/rope.h b/game/server/rope.h new file mode 100644 index 0000000..7ab9604 --- /dev/null +++ b/game/server/rope.h @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ROPE_H +#define ROPE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" + +#include "positionwatcher.h" + +class CRopeKeyframe : public CBaseEntity, public IPositionWatcher +{ + DECLARE_CLASS( CRopeKeyframe, CBaseEntity ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CRopeKeyframe(); + virtual ~CRopeKeyframe(); + + // Create a rope and attach it to two entities. + // Attachment points on the entities are optional. + static CRopeKeyframe* Create( + CBaseEntity *pStartEnt, + CBaseEntity *pEndEnt, + int iStartAttachment=0, + int iEndAttachment=0, + int ropeWidth = 2, + const char *pMaterialName = "cable/cable.vmt", // Note: whoever creates the rope must + // use PrecacheModel for whatever material + // it specifies here. + int numSegments = 5 + ); + + static CRopeKeyframe* CreateWithSecondPointDetached( + CBaseEntity *pStartEnt, + int iStartAttachment = 0, // must be 0 if you don't want to use a specific model attachment. + int ropeLength = 20, + int ropeWidth = 2, + const char *pMaterialName = "cable/cable.vmt", // Note: whoever creates the rope + // use PrecacheModel for whatever material + // it specifies here. + int numSegments = 5, + bool bInitialHang = false + ); + + bool SetupHangDistance( float flHangDist ); + void ActivateStartDirectionConstraints( bool bEnable ); + void ActivateEndDirectionConstraints( bool bEnable ); + + + // Shakes all ropes near vCenter. The higher flMagnitude is, the larger the shake will be. + static void ShakeRopes( const Vector &vCenter, float flRadius, float flMagnitude ); + + +// CBaseEntity overrides. +public: + + // don't cross transitions + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual void Activate(); + virtual void Precache(); + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + void PropagateForce(CBaseEntity *pActivator, CBaseEntity *pCaller, CBaseEntity *pFirstLink, float x, float y, float z); + + // Once-off length recalculation + void RecalculateLength( void ); + + // Kill myself when I next come to rest + void DieAtNextRest( void ); + + virtual int UpdateTransmitState(void); + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + virtual void SetParent( CBaseEntity *pParentEntity, int iAttachment ); + +// Input functions. +public: + + void InputSetScrollSpeed( inputdata_t &inputdata ); + void InputSetForce( inputdata_t &inputdata ); + void InputBreak( inputdata_t &inputdata ); + +public: + + bool Break( void ); + void DetachPoint( int iPoint ); + + void EndpointsChanged(); + + // By default, ropes don't collide with the world. Call this to enable it. + void EnableCollision(); + + // Toggle wind. + void EnableWind( bool bEnable ); + + // Unless this is called during initialization, the caller should have done + // PrecacheModel on whatever material they specify in here. + void SetMaterial( const char *pName ); + + CBaseEntity* GetEndPoint() { return m_hEndPoint.Get(); } + int GetEndAttachment() { return m_iStartAttachment; }; + + void SetStartPoint( CBaseEntity *pStartPoint, int attachment = 0 ); + void SetEndPoint( CBaseEntity *pEndPoint, int attachment = 0 ); + + // See ROPE_PLAYER_WPN_ATTACH for info. + void EnablePlayerWeaponAttach( bool bAttach ); + + + // IPositionWatcher + virtual void NotifyPositionChanged( CBaseEntity *pEntity ); + +private: + + void SetAttachmentPoint( CBaseHandle &hOutEnt, short &iOutAttachment, CBaseEntity *pEnt, int iAttachment ); + + // This is normally called by Activate but if you create the rope at runtime, + // you must call it after you have setup its variables. + void Init(); + + // These work just like the client-side versions. + bool GetEndPointPos2( CBaseEntity *pEnt, int iAttachment, Vector &v ); + bool GetEndPointPos( int iPt, Vector &v ); + + void UpdateBBox( bool bForceRelink ); + + +public: + + CNetworkVar( int, m_RopeFlags ); // Combination of ROPE_ defines in rope_shared.h + + string_t m_iNextLinkName; + CNetworkVar( int, m_Slack ); + CNetworkVar( float, m_Width ); + CNetworkVar( float, m_TextureScale ); + CNetworkVar( int, m_nSegments ); // Number of segments. + CNetworkVar( bool, m_bConstrainBetweenEndpoints ); + + string_t m_strRopeMaterialModel; + CNetworkVar( int, m_iRopeMaterialModelIndex ); // Index of sprite model with the rope's material. + + // Number of subdivisions in between segments. + CNetworkVar( int, m_Subdiv ); + + //EHANDLE m_hNextLink; + + CNetworkVar( int, m_RopeLength ); // Rope length at startup, used to calculate tension. + + CNetworkVar( int, m_fLockedPoints ); + + bool m_bCreatedFromMapFile; // set to false when creating at runtime + + CNetworkVar( float, m_flScrollSpeed ); + +private: + // Used to detect changes. + bool m_bStartPointValid; + bool m_bEndPointValid; + + CNetworkHandle( CBaseEntity, m_hStartPoint ); // StartPoint/EndPoint are entities + CNetworkHandle( CBaseEntity, m_hEndPoint ); + CNetworkVar( short, m_iStartAttachment ); // StartAttachment/EndAttachment are attachment points. + CNetworkVar( short, m_iEndAttachment ); +}; + + +#endif // ROPE_H diff --git a/game/server/sceneentity.h b/game/server/sceneentity.h new file mode 100644 index 0000000..f158079 --- /dev/null +++ b/game/server/sceneentity.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef SCENEENTITY_H +#define SCENEENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +// List of the last 5 lines of speech from NPCs for bug reports +#define SPEECH_LIST_MAX_SOUNDS 5 + +class AI_Response; + +struct recentNPCSpeech_t +{ + float time; + char name[ 512 ]; + char sceneName[ 128 ]; +}; + +int GetRecentNPCSpeech( recentNPCSpeech_t speech[ SPEECH_LIST_MAX_SOUNDS ] ); +float InstancedScriptedScene( CBaseFlex *pActor, const char *pszScene, EHANDLE *phSceneEnt = NULL, float flPostDelay = 0.0f, bool bIsBackground = false, AI_Response *response = NULL, bool bMultiplayer = false, IRecipientFilter *filter = NULL ); +float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname, EHANDLE *phSceneEnt = NULL ); +void StopScriptedScene( CBaseFlex *pActor, EHANDLE hSceneEnt ); +void RemoveActorFromScriptedScenes( CBaseFlex *pActor, bool instancedscenesonly, bool nonidlescenesonly = false, const char *pszThisSceneOnly = NULL ); +void RemoveAllScenesInvolvingActor( CBaseFlex *pActor ); +void PauseActorsScriptedScenes( CBaseFlex *pActor, bool instancedscenesonly ); +void ResumeActorsScriptedScenes( CBaseFlex *pActor, bool instancedscenesonly ); +void QueueActorsScriptedScenesToResume( CBaseFlex *pActor, bool instancedscenesonly ); +bool IsRunningScriptedScene( CBaseFlex *pActor, bool bIgnoreInstancedScenes = true ); +bool IsRunningScriptedSceneAndNotPaused( CBaseFlex *pActor, bool bIgnoreInstancedScenes = true ); +bool IsRunningScriptedSceneWithSpeech( CBaseFlex *pActor, bool bIgnoreInstancedScenes = false ); +bool IsRunningScriptedSceneWithSpeechAndNotPaused( CBaseFlex *pActor, bool bIgnoreInstancedScenes = false ); +float GetSceneDuration( char const *pszScene ); +int GetSceneSpeechCount( char const *pszScene ); +bool IsInInterruptableScenes( CBaseFlex *pActor ); + +void PrecacheInstancedScene( char const *pszScene ); + +char const *GetSceneFilename( CBaseEntity *ent ); +void ReloadSceneFromDisk( CBaseEntity *ent ); + + +#endif // SCENEENTITY_H diff --git a/game/server/scratchpad_gamedll_helpers.h b/game/server/scratchpad_gamedll_helpers.h new file mode 100644 index 0000000..6150319 --- /dev/null +++ b/game/server/scratchpad_gamedll_helpers.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SCRATCHPAD_GAMEDLL_HELPERS_H +#define SCRATCHPAD_GAMEDLL_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +class IScratchPad3D; + + +#define SPDRAWWORLD_DRAW_WORLD 0x001 +#define SPDRAWWORLD_DRAW_PLAYERS 0x002 // Draw player entities? +#define SPDRAWWORLD_DRAW_ENTITIES 0x004 // Draw entities other than players? +#define SPDRAWWORLD_DRAW_ENTITY_CLASSNAMES 0x008 +#define SPDRAWWORLD_DRAW_EDICT_INDICES 0x010 + +#define SPDRAWWORLD_DRAW_ALL 0xFFFFFFFF + + +// Draws the world and various things in it into the scratchpad. +// flags is a combination of the SPDRAWWORLD_ flags. +void ScratchPad_DrawWorldToScratchPad( + IScratchPad3D *pPad, + unsigned long flags ); + +// Draw a specific entity into the scratch pad. +void ScratchPad_DrawEntityToScratchPad( + IScratchPad3D *pPad, + unsigned long flags, + CBaseEntity *pEnt, + const Vector &vColor ); + + +#endif // SCRATCHPAD_GAMEDLL_HELPERS_H diff --git a/game/server/scripted.h b/game/server/scripted.h new file mode 100644 index 0000000..574fcbd --- /dev/null +++ b/game/server/scripted.h @@ -0,0 +1,229 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SCRIPTED_H +#define SCRIPTED_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef SCRIPTEVENT_H +#include "scriptevent.h" +#endif + +#include "ai_basenpc.h" + + +// +// The number of unique outputs that a script can fire from animation events. +// These are fired via SCRIPT_EVENT_FIREEVENT in CAI_BaseNPC::HandleAnimEvent. +// +#define MAX_SCRIPT_EVENTS 8 + + +#define SF_SCRIPT_WAITTILLSEEN 1 +#define SF_SCRIPT_EXITAGITATED 2 +#define SF_SCRIPT_REPEATABLE 4 // Whether the script can be played more than once. +#define SF_SCRIPT_LEAVECORPSE 8 +#define SF_SCRIPT_START_ON_SPAWN 16 +#define SF_SCRIPT_NOINTERRUPT 32 +#define SF_SCRIPT_OVERRIDESTATE 64 +#define SF_SCRIPT_DONT_TELEPORT_AT_END 128 // Don't fixup end position with a teleport when the SS is finished +#define SF_SCRIPT_LOOP_IN_POST_IDLE 256 // Loop in the post idle animation after playing the action animation. +#define SF_SCRIPT_HIGH_PRIORITY 512 // If set, we don't allow other scripts to steal our spot in the queue. +#define SF_SCRIPT_SEARCH_CYCLICALLY 1024 // Start search from last entity found. +#define SF_SCRIPT_NO_COMPLAINTS 2048 // doesn't bitch if it can't find anything +#define SF_SCRIPT_ALLOW_DEATH 4096 // the actor using this scripted sequence may die without interrupting the scene (used for scripted deaths) + + +enum script_moveto_t +{ + CINE_MOVETO_WAIT = 0, + CINE_MOVETO_WALK = 1, + CINE_MOVETO_RUN = 2, + CINE_MOVETO_CUSTOM = 3, + CINE_MOVETO_TELEPORT = 4, + CINE_MOVETO_WAIT_FACING = 5, +}; + +enum SCRIPT_PLAYER_DEATH +{ + SCRIPT_DO_NOTHING = 0, + SCRIPT_CANCEL = 1, +}; + + +// +// Interrupt levels for grabbing NPCs to act out scripted events. These indicate +// how important it is to get a specific NPC, and can affect how they respond. +// +enum SS_INTERRUPT +{ + SS_INTERRUPT_BY_CLASS = 0, // Indicates that we are asking for this NPC by class + SS_INTERRUPT_BY_NAME, // Indicates that we are asking for this NPC by name +}; + + +// when a NPC finishes an AI scripted sequence, we can choose +// a schedule to place them in. These defines are the aliases to +// resolve worldcraft input to real schedules (sjb) +#define SCRIPT_FINISHSCHED_DEFAULT 0 +#define SCRIPT_FINISHSCHED_AMBUSH 1 + +class CAI_ScriptedSequence : public CBaseEntity +{ + DECLARE_CLASS( CAI_ScriptedSequence, CBaseEntity ); +public: + void Spawn( void ); + virtual void Blocked( CBaseEntity *pOther ); + virtual void Touch( CBaseEntity *pOther ); + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + virtual void Activate( void ); + virtual void UpdateOnRemove( void ); + void StartThink(); + void ScriptThink( void ); + void StopThink(); + + DECLARE_DATADESC(); + + void Pain( void ); + void Die( void ); + void DelayStart( bool bDelay ); + bool FindEntity( void ); + void StartScript( void ); + void FireScriptEvent( int nEvent ); + void OnBeginSequence( void ); + + void SetTarget( CBaseEntity *pTarget ) { m_hTargetEnt = pTarget; }; + CBaseEntity *GetTarget( void ) { return m_hTargetEnt; }; + + // Input handlers + void InputBeginSequence( inputdata_t &inputdata ); + void InputCancelSequence( inputdata_t &inputdata ); + void InputMoveToPosition( inputdata_t &inputdata ); + + bool IsTimeToStart( void ); + bool IsWaitingForBegin( void ); + void ReleaseEntity( CAI_BaseNPC *pEntity ); + void CancelScript( void ); + bool StartSequence( CAI_BaseNPC *pTarget, string_t iszSeq, bool completeOnEmpty ); + void SynchronizeSequence( CAI_BaseNPC *pNPC ); + bool FCanOverrideState ( void ); + void SequenceDone( CAI_BaseNPC *pNPC ); + void PostIdleDone( CAI_BaseNPC *pNPC ); + void FixScriptNPCSchedule( CAI_BaseNPC *pNPC, int iSavedCineFlags ); + void FixFlyFlag( CAI_BaseNPC *pNPC, int iSavedCineFlags ); + bool CanInterrupt( void ); + void AllowInterrupt( bool fAllow ); + void RemoveIgnoredConditions( void ); + bool PlayedSequence( void ) { return m_sequenceStarted; } + bool CanEnqueueAfter( void ); + + // Entry & Action loops + bool IsPlayingEntry( void ) { return m_bIsPlayingEntry; } + bool IsPlayingAction( void ) { return ( m_sequenceStarted && !m_bIsPlayingEntry ); } + bool FinishedActionSequence( CAI_BaseNPC *pNPC ); + void SetLoopActionSequence( bool bLoop ) { m_bLoopActionSequence = bLoop; } + bool ShouldLoopActionSequence( void ) { return m_bLoopActionSequence; } + void StopActionLoop( bool bStopSynchronizedScenes ); + void SetSynchPostIdles( bool bSynch ) { m_bSynchPostIdles = bSynch; } + void SynchNewSequence( CAI_BaseNPC::SCRIPTSTATE newState, string_t iszSequence, bool bSynchOtherScenes ); + + // Dynamic scripted sequence spawning + void ForceSetTargetEntity( CAI_BaseNPC *pTarget, bool bDontCancelOtherSequences ); + + // Dynamic interactions + void SetupInteractionPosition( CBaseEntity *pRelativeEntity, VMatrix &matDesiredLocalToWorld ); + void ModifyScriptedAutoMovement( Vector *vecNewPos ); + + bool IsTeleportingDueToMoveTo( void ) { return m_bIsTeleportingDueToMoveTo; } + + // Debug + virtual int DrawDebugTextOverlays( void ); + virtual void DrawDebugGeometryOverlays( void ); + + void InputScriptPlayerDeath( inputdata_t &inputdata ); + +private: + friend class CAI_BaseNPC; // should probably try to eliminate this relationship + + string_t m_iszEntry; // String index for animation that must be played before entering the main action anim + string_t m_iszPreIdle; // String index for idle animation to play before playing the action anim (only played while waiting for the script to begin) + string_t m_iszPlay; // String index for scripted action animation + string_t m_iszPostIdle; // String index for idle animation to play before playing the action anim + string_t m_iszCustomMove; // String index for custom movement animation + string_t m_iszNextScript; // Name of the script to run immediately after this one. + string_t m_iszEntity; // Entity that is wanted for this script + + int m_fMoveTo; + bool m_bIsPlayingEntry; + bool m_bLoopActionSequence; + bool m_bSynchPostIdles; + bool m_bIgnoreGravity; + bool m_bDisableNPCCollisions; // Used when characters must interpenetrate while riding on elevators, trains, etc. + + float m_flRadius; // Range to search for an NPC to possess. + float m_flRepeat; // Repeat rate + + int m_iDelay; // A counter indicating how many scripts are NOT ready to start. + + bool m_bDelayed; // This moderately hacky hack ensures that we don't calls to DelayStart(true) or DelayStart(false) + // twice in succession. This is necessary because we didn't want to remove the call to DelayStart(true) + // from StartScript, even though DelayStart(true) is called from TASK_PRE_SCRIPT. + // All of this is necessary in case the NPCs schedule gets cleared during the script and then they + // reselect the schedule to play the script. Without this you can get NPCs stuck with m_iDelay = -1 + + float m_startTime; // Time when script actually started, used for synchronization + bool m_bWaitForBeginSequence; // Set to true when we are told to MoveToPosition. Holds the actor in the pre-action idle until BeginSequence is called. + + int m_saved_effects; + int m_savedFlags; + int m_savedCollisionGroup; + + bool m_interruptable; + bool m_sequenceStarted; + + EHANDLE m_hTargetEnt; + + EHANDLE m_hNextCine; // The script to hand the NPC off to when we finish with them. + + bool m_bThinking; + bool m_bInitiatedSelfDelete; + + bool m_bIsTeleportingDueToMoveTo; + + CAI_BaseNPC *FindScriptEntity( void ); + EHANDLE m_hLastFoundEntity; + + // Code forced us to use a specific NPC + EHANDLE m_hForcedTarget; + bool m_bDontCancelOtherSequences; + bool m_bForceSynch; + + bool m_bTargetWasAsleep; + + COutputEvent m_OnBeginSequence; + COutputEvent m_OnEndSequence; + COutputEvent m_OnPostIdleEndSequence; + COutputEvent m_OnCancelSequence; + COutputEvent m_OnCancelFailedSequence; // Fired when a scene is cancelled before it's ever run + COutputEvent m_OnScriptEvent[MAX_SCRIPT_EVENTS]; + + static void ScriptEntityCancel( CBaseEntity *pentCine, bool bPretendSuccess = false ); + + static const char *GetSpawnPreIdleSequenceForScript( CBaseEntity *pTargetEntity ); + + // Dynamic interactions + // For now, store just a single one of these. To synchronize positions + // with multiple other NPCs, this needs to be an array of NPCs & desired position matrices. + VMatrix m_matInteractionPosition; + EHANDLE m_hInteractionRelativeEntity; + + int m_iPlayerDeathBehavior; +}; + + +#endif // SCRIPTED_H diff --git a/game/server/scriptedtarget.h b/game/server/scriptedtarget.h new file mode 100644 index 0000000..4f1c1e0 --- /dev/null +++ b/game/server/scriptedtarget.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SCRIPTEDTARGET_H +#define SCRIPTEDTARGET_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef SCRIPTEVENT_H +#include "scriptevent.h" +#endif + +#include "ai_basenpc.h" + +class CScriptedTarget : public CAI_BaseNPC +{ + DECLARE_CLASS( CScriptedTarget, CAI_BaseNPC ); +public: + DECLARE_DATADESC(); + + void Spawn( void ); + virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + + + void ScriptThink( void ); + CBaseEntity* FindEntity( void ); + + void TurnOn(void); + void TurnOff(void); + + // Input handlers + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + CScriptedTarget* NextScriptedTarget(void); + float MoveSpeed(void) { return m_nMoveSpeed; }; + float EffectDuration(void) { return m_flEffectDuration; }; + + int DrawDebugTextOverlays(void); + void DrawDebugGeometryOverlays(void); + float PercentComplete(void); + + Vector m_vLastPosition; // Last position that's been reached + +private: + int m_iDisabled; // Initial state + string_t m_iszEntity; // entity that is wanted for this script + float m_flRadius; // range to search + + int m_nMoveSpeed; // How fast do I burn from target to target + float m_flPauseDuration; // How long to pause at this target + float m_flPauseDoneTime; // When is pause over + float m_flEffectDuration; // How long should any associated effect last? + + COutputEvent m_AtTarget; // Fired when scripted target has been reached + COutputEvent m_LeaveTarget; // Fired when scripted target is left +}; + +#endif // SCRIPTEDTARGET_H diff --git a/game/server/sdk/sdk_bot_temp.h b/game/server/sdk/sdk_bot_temp.h new file mode 100644 index 0000000..2f3130a --- /dev/null +++ b/game/server/sdk/sdk_bot_temp.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDK_BOT_TEMP_H +#define SDK_BOT_TEMP_H +#ifdef _WIN32 +#pragma once +#endif + + +// If iTeam or iClass is -1, then a team or class is randomly chosen. +CBasePlayer *BotPutInServer( bool bFrozen, int iTeam, int iClass ); + +void Bot_RunAll(); + + +#endif // SDK_BOT_TEMP_H diff --git a/game/server/sdk/sdk_player.h b/game/server/sdk/sdk_player.h new file mode 100644 index 0000000..cb93a03 --- /dev/null +++ b/game/server/sdk/sdk_player.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Player for SDK Game +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDK_PLAYER_H +#define SDK_PLAYER_H +#pragma once + + +#include "player.h" +#include "server_class.h" +#include "sdk_playeranimstate.h" +#include "sdk_shareddefs.h" + + +//============================================================================= +// >> SDK Game player +//============================================================================= +class CSDKPlayer : public CBasePlayer, public ISDKPlayerAnimStateHelpers +{ +public: + DECLARE_CLASS( CSDKPlayer, CBasePlayer ); + DECLARE_SERVERCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_DATADESC(); + + CSDKPlayer(); + ~CSDKPlayer(); + + static CSDKPlayer *CreatePlayer( const char *className, edict_t *ed ); + static CSDKPlayer* Instance( int iEnt ); + + // This passes the event to the client's and server's CPlayerAnimState. + void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); + + virtual void FlashlightTurnOn( void ); + virtual void FlashlightTurnOff( void ); + virtual int FlashlightIsOn( void ); + + virtual void PreThink(); + virtual void PostThink(); + virtual void Spawn(); + virtual void InitialSpawn(); + virtual void Precache(); + virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual void LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles ); + + CWeaponSDKBase* GetActiveSDKWeapon() const; + virtual void CreateViewModel( int viewmodelindex = 0 ); + + virtual void CheatImpulseCommands( int iImpulse ); + + CNetworkVar( int, m_iThrowGrenadeCounter ); // used to trigger grenade throw animations. + CNetworkQAngle( m_angEyeAngles ); // Copied from EyeAngles() so we can send it to the client. + CNetworkVar( int, m_iShotsFired ); // number of shots fired recently + + // Tracks our ragdoll entity. + CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle + +// In shared code. +public: + // ISDKPlayerAnimState overrides. + virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon(); + virtual bool SDKAnim_CanMove(); + + + void FireBullet( + Vector vecSrc, + const QAngle &shootAngles, + float vecSpread, + int iDamage, + int iBulletType, + CBaseEntity *pevAttacker, + bool bDoEffects, + float x, + float y ); + +private: + + void CreateRagdollEntity(); + + ISDKPlayerAnimState *m_PlayerAnimState; +}; + + +inline CSDKPlayer *ToSDKPlayer( CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + +#ifdef _DEBUG + Assert( dynamic_cast( pEntity ) != 0 ); +#endif + return static_cast< CSDKPlayer* >( pEntity ); +} + + +#endif // SDK_PLAYER_H diff --git a/game/server/sdk/sdk_team.h b/game/server/sdk/sdk_team.h new file mode 100644 index 0000000..50f4c12 --- /dev/null +++ b/game/server/sdk/sdk_team.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Team management class. Contains all the details for a specific team +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDK_TEAM_H +#define SDK_TEAM_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "utlvector.h" +#include "team.h" + + +//----------------------------------------------------------------------------- +// Purpose: Team Manager +//----------------------------------------------------------------------------- +class CSDKTeam : public CTeam +{ + DECLARE_CLASS( CSDKTeam, CTeam ); + DECLARE_SERVERCLASS(); + +public: + + // Initialization + virtual void Init( const char *pName, int iNumber ); +}; + + +extern CSDKTeam *GetGlobalSDKTeam( int iIndex ); + + +#endif // TF_TEAM_H diff --git a/game/server/sdk/te_firebullets.h b/game/server/sdk/te_firebullets.h new file mode 100644 index 0000000..907dfc1 --- /dev/null +++ b/game/server/sdk/te_firebullets.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TE_FIREBULLETS_H +#define TE_FIREBULLETS_H +#ifdef _WIN32 +#pragma once +#endif + + +void TE_FireBullets( + int iPlayerIndex, + const Vector &vOrigin, + const QAngle &vAngles, + int iWeaponID, + int iMode, + int iSeed, + float flSpread + ); + +#endif // TE_FIREBULLETS_H diff --git a/game/server/sendproxy.h b/game/server/sendproxy.h new file mode 100644 index 0000000..99527b1 --- /dev/null +++ b/game/server/sendproxy.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: implements various common send proxies +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SENDPROXY_H +#define SENDPROXY_H + + +#include "dt_send.h" + + +class DVariant; + +void SendProxy_Color32ToInt( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_EHandleToInt( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_IntAddOne( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_ShortAddOne( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID ); + +SendProp SendPropBool( + const char *pVarName, + int offset, + int sizeofVar ); + +SendProp SendPropEHandle( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, + int flags = 0, + SendVarProxyFn proxyFn=SendProxy_EHandleToInt ); + +SendProp SendPropTime( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE ); + +#if !defined( NO_ENTITY_PREDICTION ) +SendProp SendPropPredictableId( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE ); +#endif + +SendProp SendPropIntWithMinusOneFlag( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, + int bits=-1, + SendVarProxyFn proxyFn=SendProxy_IntAddOne ); + + +// Send a string_t as a string property. +SendProp SendPropStringT( const char *pVarName, int offset, int sizeofVar ); + +//----------------------------------------------------------------------------- +// Purpose: Proxy that only sends data to team members +//----------------------------------------------------------------------------- +void* SendProxy_OnlyToTeam( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID ); + + +#endif // SENDPROXY_H diff --git a/game/server/serverbenchmark_base.h b/game/server/serverbenchmark_base.h new file mode 100644 index 0000000..c4cb005 --- /dev/null +++ b/game/server/serverbenchmark_base.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SERVERBENCHMARK_BASE_H +#define SERVERBENCHMARK_BASE_H +#ifdef _WIN32 +#pragma once +#endif + + +// The base server code calls into this. +class IServerBenchmark +{ +public: + virtual bool StartBenchmark() = 0; + virtual void UpdateBenchmark() = 0; + virtual void EndBenchmark() = 0; + + virtual bool IsBenchmarkRunning() = 0; + virtual bool IsLocalBenchmarkPlayer( CBasePlayer *pPlayer ) = 0; + + // Game-specific benchmark code should use this. + virtual int RandomInt( int nMin, int nMax ) = 0; + virtual float RandomFloat( float flMin, float flMax ) = 0; + virtual int GetTickOffset() = 0; +}; + +extern IServerBenchmark *g_pServerBenchmark; + + +// +// Each game can derive from this to hook into the server benchmark. +// +// Hooks should always use g_pServerBenchmark->RandomInt/Float to get random numbers +// so the benchmark is deterministic. +// +// If they use an absolute tick number for anything, then they should also call g_pServerBenchmark->GetTickOffset() +// to get a tick count since the start of the benchmark instead of looking at gpGlobals->tickcount. +// +class CServerBenchmarkHook +{ +public: + CServerBenchmarkHook(); + + virtual void StartBenchmark() {} + virtual void UpdateBenchmark() {} + virtual void EndBenchmark() {} + + // Give a list of model names that can be spawned in for physics props during the simulation. + virtual void GetPhysicsModelNames( CUtlVector &modelNames ) = 0; + + // The benchmark will call this to create a bot each time it wants to create a player. + // If you want to manage the bots yourself, you can return NULL here. + virtual CBasePlayer* CreateBot() = 0; + +private: + friend class CServerBenchmark; + static CServerBenchmarkHook *s_pBenchmarkHook; // There can be only one!! +}; + + +#endif // SERVERBENCHMARK_BASE_H diff --git a/game/server/smoke_trail.h b/game/server/smoke_trail.h new file mode 100644 index 0000000..34398c1 --- /dev/null +++ b/game/server/smoke_trail.h @@ -0,0 +1,210 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef SMOKE_TRAIL_H +#define SMOKE_TRAIL_H + +#include "baseparticleentity.h" + +//================================================== +// SmokeTrail +//================================================== + +class SmokeTrail : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( SmokeTrail, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + SmokeTrail(); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + void SetEmit(bool bVal); + void FollowEntity( CBaseEntity *pEntity, const char *pAttachmentName = NULL); + static SmokeTrail* CreateSmokeTrail(); + +public: + // Effect parameters. These will assume default values but you can change them. + CNetworkVector( m_StartColor ); // Fade between these colors. + CNetworkVector( m_EndColor ); + CNetworkVar( float, m_Opacity ); + + CNetworkVar( float, m_SpawnRate ); // How many particles per second. + CNetworkVar( float, m_ParticleLifetime ); // How long do the particles live? + CNetworkVar( float, m_StopEmitTime ); // When do I stop emitting particles? + CNetworkVar( float, m_MinSpeed ); // Speed range. + CNetworkVar( float, m_MaxSpeed ); + CNetworkVar( float, m_StartSize ); // Size ramp. + CNetworkVar( float, m_EndSize ); + CNetworkVar( float, m_SpawnRadius ); + CNetworkVar( float, m_MinDirectedSpeed ); // Speed range. + CNetworkVar( float, m_MaxDirectedSpeed ); + CNetworkVar( bool, m_bEmit ); + + CNetworkVar( int, m_nAttachment ); +}; + +//================================================== +// RocketTrail +//================================================== + +class RocketTrail : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( RocketTrail, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + RocketTrail(); + void SetEmit(bool bVal); + void FollowEntity( CBaseEntity *pEntity, const char *pAttachmentName = NULL); + static RocketTrail *CreateRocketTrail(); + +public: + // Effect parameters. These will assume default values but you can change them. + CNetworkVector( m_StartColor ); // Fade between these colors. + CNetworkVector( m_EndColor ); + CNetworkVar( float, m_Opacity ); + + CNetworkVar( float, m_SpawnRate ); // How many particles per second. + CNetworkVar( float, m_ParticleLifetime ); // How long do the particles live? + CNetworkVar( float, m_StopEmitTime ); // When do I stop emitting particles? + CNetworkVar( float, m_MinSpeed ); // Speed range. + CNetworkVar( float, m_MaxSpeed ); + CNetworkVar( float, m_StartSize ); // Size ramp. + CNetworkVar( float, m_EndSize ); + CNetworkVar( float, m_SpawnRadius ); + + CNetworkVar( bool, m_bEmit ); + + CNetworkVar( int, m_nAttachment ); + + CNetworkVar( bool, m_bDamaged ); + + CNetworkVar( float, m_flFlareScale ); // Size of the flare +}; + +//================================================== +// SporeTrail +//================================================== + +class SporeTrail : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( SporeTrail, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + SporeTrail( void ); + + static SporeTrail* CreateSporeTrail(); + +//Data members +public: + + CNetworkVector( m_vecEndColor ); + + CNetworkVar( float, m_flSpawnRate ); + CNetworkVar( float, m_flParticleLifetime ); + CNetworkVar( float, m_flStartSize ); + CNetworkVar( float, m_flEndSize ); + CNetworkVar( float, m_flSpawnRadius ); + + CNetworkVar( bool, m_bEmit ); +}; + +//================================================== +// SporeExplosion +//================================================== + +class SporeExplosion : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( SporeExplosion, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + SporeExplosion( void ); + void Spawn( void ); + + static SporeExplosion* CreateSporeExplosion(); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + +//Data members +public: + + bool m_bDisabled; + + CNetworkVar( float, m_flSpawnRate ); + CNetworkVar( float, m_flParticleLifetime ); + CNetworkVar( float, m_flStartSize ); + CNetworkVar( float, m_flEndSize ); + CNetworkVar( float, m_flSpawnRadius ); + + CNetworkVar( bool, m_bEmit ); + CNetworkVar( bool, m_bDontRemove ); +}; + +//================================================== +// CFireTrail +//================================================== + +class CFireTrail : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CFireTrail, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + static CFireTrail *CreateFireTrail( void ); + void FollowEntity( CBaseEntity *pEntity, const char *pAttachmentName ); + void Precache( void ); + + CNetworkVar( int, m_nAttachment ); + CNetworkVar( float, m_flLifetime ); +}; + +//================================================== +// DustTrail +//================================================== + +class DustTrail : public CBaseParticleEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( DustTrail, CBaseParticleEntity ); + DECLARE_SERVERCLASS(); + + DustTrail(); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + void SetEmit(bool bVal); + static DustTrail* CreateDustTrail(); + +public: + // Effect parameters. These will assume default values but you can change them. + CNetworkVector( m_Color ); + CNetworkVar( float, m_Opacity ); + + CNetworkVar( float, m_SpawnRate ); // How many particles per second. + CNetworkVar( float, m_ParticleLifetime ); // How long do the particles live? + CNetworkVar( float, m_StopEmitTime ); // When do I stop emitting particles? + CNetworkVar( float, m_MinSpeed ); // Speed range. + CNetworkVar( float, m_MaxSpeed ); + CNetworkVar( float, m_StartSize ); // Size ramp. + CNetworkVar( float, m_EndSize ); + CNetworkVar( float, m_SpawnRadius ); + CNetworkVar( float, m_MinDirectedSpeed ); // Speed range. + CNetworkVar( float, m_MaxDirectedSpeed ); + CNetworkVar( bool, m_bEmit ); + + CNetworkVar( int, m_nAttachment ); +}; + + +#endif diff --git a/game/server/smokestack.h b/game/server/smokestack.h new file mode 100644 index 0000000..e8d4986 --- /dev/null +++ b/game/server/smokestack.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the server side of a steam jet particle system entity. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SMOKESTACK_H +#define SMOKESTACK_H +#pragma once + +#include "baseparticleentity.h" + +//================================================== +// CSmokeStack +//================================================== + +class CSmokeStackLightInfo +{ +public: + DECLARE_CLASS_NOBASE( CSmokeStackLightInfo ); + DECLARE_SIMPLE_DATADESC(); + DECLARE_NETWORKVAR_CHAIN(); + + CNetworkVector( m_vPos ); + CNetworkVector( m_vColor ); + CNetworkVar( float, m_flIntensity ); +}; + +class CSmokeStack : public CBaseParticleEntity +{ +public: + DECLARE_CLASS( CSmokeStack, CBaseParticleEntity ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CSmokeStack(); + ~CSmokeStack(); + + virtual void Spawn( void ); + virtual void Activate(); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void Precache(); + + +protected: + + // Input handlers. + void InputTurnOn(inputdata_t &data); + void InputTurnOff(inputdata_t &data); + void InputToggle(inputdata_t &data); + + void RecalcWindVector(); + + +// Stuff from the datatable. +public: + CNetworkVar( float, m_SpreadSpeed ); + CNetworkVar( float, m_Speed ); + CNetworkVar( float, m_StartSize ); + CNetworkVar( float, m_EndSize ); + CNetworkVar( float, m_Rate ); + CNetworkVar( float, m_JetLength ); // Length of the jet. Lifetime is derived from this. + CNetworkVar( float, m_flRollSpeed ); + + CNetworkVar( int, m_bEmit ); // Emit particles? + CNetworkVar( float, m_flBaseSpread ); + + CSmokeStackLightInfo m_AmbientLight; + CSmokeStackLightInfo m_DirLight; + + CNetworkVar( float, m_flTwist ); + + string_t m_strMaterialModel; + CNetworkVar( int, m_iMaterialModel ); + + int m_WindAngle; + int m_WindSpeed; + CNetworkVector( m_vWind ); // m_vWind is just calculated from m_WindAngle and m_WindSpeed. + + bool m_InitialState; +}; + +#endif // SMOKESTACK_H + diff --git a/game/server/soundent.h b/game/server/soundent.h new file mode 100644 index 0000000..4de733f --- /dev/null +++ b/game/server/soundent.h @@ -0,0 +1,264 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// Soundent.h - the entity that spawns when the world +// spawns, and handles the world's active and free sound +// lists. + +#ifndef SOUNDENT_H +#define SOUNDENT_H + +#ifdef _WIN32 +#pragma once +#endif + +enum +{ + MAX_WORLD_SOUNDS_SP = 64, // Maximum number of sounds handled by the world at one time in single player. + // This is also the number of entries saved in a savegame file (for b/w compatibility). + + MAX_WORLD_SOUNDS_MP = 128 // The sound array size is set this large but we'll only use gpGlobals->maxPlayers+32 entries in mp. +}; + +enum +{ + SOUND_NONE = 0, + SOUND_COMBAT = 0x00000001, + SOUND_WORLD = 0x00000002, + SOUND_PLAYER = 0x00000004, + SOUND_DANGER = 0x00000008, + SOUND_BULLET_IMPACT = 0x00000010, + SOUND_CARCASS = 0x00000020, + SOUND_MEAT = 0x00000040, + SOUND_GARBAGE = 0x00000080, + SOUND_THUMPER = 0x00000100, // keeps certain creatures at bay + SOUND_BUGBAIT = 0x00000200, // gets the antlion's attention + SOUND_PHYSICS_DANGER = 0x00000400, + SOUND_DANGER_SNIPERONLY = 0x00000800, // only scares the sniper NPC. + SOUND_MOVE_AWAY = 0x00001000, + SOUND_PLAYER_VEHICLE = 0x00002000, + SOUND_READINESS_LOW = 0x00004000, // Changes listener's readiness (Player Companion only) + SOUND_READINESS_MEDIUM = 0x00008000, + SOUND_READINESS_HIGH = 0x00010000, + + // Contexts begin here. + SOUND_CONTEXT_FROM_SNIPER = 0x00100000, // additional context for SOUND_DANGER + SOUND_CONTEXT_GUNFIRE = 0x00200000, // Added to SOUND_COMBAT + SOUND_CONTEXT_MORTAR = 0x00400000, // Explosion going to happen here. + SOUND_CONTEXT_COMBINE_ONLY = 0x00800000, // Only combine can hear sounds marked this way + SOUND_CONTEXT_REACT_TO_SOURCE = 0x01000000, // React to sound source's origin, not sound's location + SOUND_CONTEXT_EXPLOSION = 0x02000000, // Context added to SOUND_COMBAT, usually. + SOUND_CONTEXT_EXCLUDE_COMBINE = 0x04000000, // Combine do NOT hear this + SOUND_CONTEXT_DANGER_APPROACH = 0x08000000, // Treat as a normal danger sound if you see the source, otherwise turn to face source. + SOUND_CONTEXT_ALLIES_ONLY = 0x10000000, // Only player allies can hear this sound + SOUND_CONTEXT_PLAYER_VEHICLE = 0x20000000, // HACK: need this because we're not treating the SOUND_xxx values as true bit values! See switch in OnListened. + + ALL_CONTEXTS = 0xFFF00000, + + ALL_SCENTS = SOUND_CARCASS | SOUND_MEAT | SOUND_GARBAGE, + + ALL_SOUNDS = 0x000FFFFF & ~ALL_SCENTS, + +}; + +// Make as many of these as you want. +enum +{ + SOUNDENT_CHANNEL_UNSPECIFIED = 0, + SOUNDENT_CHANNEL_REPEATING, + SOUNDENT_CHANNEL_REPEATED_DANGER, // for things that make danger sounds frequently. + SOUNDENT_CHANNEL_REPEATED_PHYSICS_DANGER, + SOUNDENT_CHANNEL_WEAPON, + SOUNDENT_CHANNEL_INJURY, + SOUNDENT_CHANNEL_BULLET_IMPACT, + SOUNDENT_CHANNEL_NPC_FOOTSTEP, + SOUNDENT_CHANNEL_SPOOKY_NOISE, // made by zombies in darkness + SOUNDENT_CHANNEL_ZOMBINE_GRENADE, +}; + +enum +{ + SOUNDLIST_EMPTY = -1 +}; + +#define SOUNDENT_VOLUME_MACHINEGUN 1500.0 +#define SOUNDENT_VOLUME_SHOTGUN 1500.0 +#define SOUNDENT_VOLUME_PISTOL 1500.0 +#define SOUNDENT_VOLUME_EMPTY 500.0 // volume of the "CLICK" when you have no bullets + +enum +{ + SOUND_PRIORITY_VERY_LOW = -2, + SOUND_PRIORITY_LOW, + SOUND_PRIORITY_NORMAL = 0, + SOUND_PRIORITY_HIGH, + SOUND_PRIORITY_VERY_HIGH, + SOUND_PRIORITY_HIGHEST, +}; + +//========================================================= +// CSound - an instance of a sound in the world. +//========================================================= +class CSound +{ + DECLARE_SIMPLE_DATADESC(); + +public: + bool DoesSoundExpire() const; + float SoundExpirationTime() const; + void SetSoundOrigin( const Vector &vecOrigin ) { m_vecOrigin = vecOrigin; } + const Vector& GetSoundOrigin( void ) { return m_vecOrigin; } + const Vector& GetSoundReactOrigin( void ); + bool FIsSound( void ); + bool FIsScent( void ); + bool IsSoundType( int nSoundFlags ) const; + int SoundType( ) const; + int SoundContext() const; + int SoundTypeNoContext( ) const; + int Volume( ) const; + float OccludedVolume() { return m_iVolume * m_flOcclusionScale; } + int NextSound() const; + void Reset ( void ); + int SoundChannel( void ) const; + bool ValidateOwner() const; + + EHANDLE m_hOwner; // sound's owner + EHANDLE m_hTarget; // Sounds's target - an odd concept. For a gunfire sound, the target is the entity being fired at + int m_iVolume; // how loud the sound is + float m_flOcclusionScale; // How loud the sound is when occluded by the world. (volume * occlusionscale) + int m_iType; // what type of sound this is + int m_iNextAudible; // temporary link that NPCs use to build a list of audible sounds + +private: + void Clear ( void ); + + float m_flExpireTime; // when the sound should be purged from the list + short m_iNext; // index of next sound in this list ( Active or Free ) + bool m_bNoExpirationTime; + int m_ownerChannelIndex; + + Vector m_vecOrigin; // sound's location in space + + bool m_bHasOwner; // Lets us know if this sound was created with an owner. In case the owner goes null. + +#ifdef DEBUG + int m_iMyIndex; // debugging +#endif + + friend class CSoundEnt; +}; + +inline bool CSound::DoesSoundExpire() const +{ + return m_bNoExpirationTime == false; +} + +inline float CSound::SoundExpirationTime() const +{ + return m_bNoExpirationTime ? FLT_MAX : m_flExpireTime; +} + +inline bool CSound::IsSoundType( int nSoundFlags ) const +{ + return (m_iType & nSoundFlags) != 0; +} + +inline int CSound::SoundType( ) const +{ + return m_iType; +} + +inline int CSound::SoundContext( ) const +{ + return m_iType & ALL_CONTEXTS; +} + +inline int CSound::SoundTypeNoContext( ) const +{ + return m_iType & ~ALL_CONTEXTS; +} + +inline int CSound::Volume( ) const +{ + return m_iVolume; +} + +inline int CSound::NextSound() const +{ + return m_iNext; +} + +inline int CSound::SoundChannel( void ) const +{ + return m_ownerChannelIndex; +} + +// The owner is considered valid if: +// -The sound never had an assigned owner (quite common) +// -The sound was assigned an owner and that owner still exists +inline bool CSound::ValidateOwner( void ) const +{ + return ( !m_bHasOwner || (m_hOwner.Get() != NULL) ); +} + +//========================================================= +// CSoundEnt - a single instance of this entity spawns when +// the world spawns. The SoundEnt's job is to update the +// world's Free and Active sound lists. +//========================================================= +class CSoundEnt : public CPointEntity +{ + DECLARE_DATADESC(); + +public: + DECLARE_CLASS( CSoundEnt, CPointEntity ); + + // Construction, destruction + static bool InitSoundEnt(); + static void ShutdownSoundEnt(); + + CSoundEnt(); + virtual ~CSoundEnt(); + + virtual void OnRestore(); + void Precache ( void ); + void Spawn( void ); + void Think( void ); + void Initialize ( void ); + int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + static void InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration, CBaseEntity *pOwner = NULL, int soundChannelIndex = SOUNDENT_CHANNEL_UNSPECIFIED, CBaseEntity *pSoundTarget = NULL ); + static void FreeSound ( int iSound, int iPrevious ); + static int ActiveList( void );// return the head of the active list + static int FreeList( void );// return the head of the free list + static CSound* SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list + static CSound* GetLoudestSoundOfType( int iType, const Vector &vecEarPosition ); + static int ClientSoundIndex ( edict_t *pClient ); + + bool IsEmpty( void ); + int ISoundsInList ( int iListType ); + int IAllocSound ( void ); + int FindOrAllocateSound( CBaseEntity *pOwner, int soundChannelIndex ); + +private: + int m_iFreeSound; // index of the first sound in the free sound list + int m_iActiveSound; // indes of the first sound in the active sound list + int m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work) + CSound m_SoundPool[ MAX_WORLD_SOUNDS_MP ]; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline bool CSoundEnt::IsEmpty( void ) +{ + return m_iActiveSound == SOUNDLIST_EMPTY; +} + + +#endif //SOUNDENT_H diff --git a/game/server/soundscape.h b/game/server/soundscape.h new file mode 100644 index 0000000..3e5e826 --- /dev/null +++ b/game/server/soundscape.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SOUNDSCAPE_H +#define SOUNDSCAPE_H +#ifdef _WIN32 +#pragma once +#endif + +class CEnvSoundscape; + +struct ss_update_t +{ + CBasePlayer *pPlayer; + CEnvSoundscape *pCurrentSoundscape; + Vector playerPosition; + float currentDistance; + int traceCount; + bool bInRange; +}; + +class CEnvSoundscape : public CPointEntity +{ +public: + DECLARE_CLASS( CEnvSoundscape, CPointEntity ); + DECLARE_DATADESC(); + + CEnvSoundscape(); + ~CEnvSoundscape(); + + bool KeyValue( const char *szKeyName, const char *szValue ); + void Spawn( void ); + void Precache( void ); + void UpdateForPlayer( ss_update_t &update ); + void WriteAudioParamsTo( audioparams_t &audio ); + virtual int UpdateTransmitState(); + bool InRangeOfPlayer( CBasePlayer *pPlayer ); + void DrawDebugGeometryOverlays( void ); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputToggleEnabled( inputdata_t &inputdata ); + + string_t GetSoundscapeName() const {return m_soundscapeName;} + + +private: + + bool IsEnabled( void ) const; + void Disable( void ); + void Enable( void ); + + +public: + COutputEvent m_OnPlay; + float m_flRadius; + string_t m_soundscapeName; + int m_soundscapeIndex; + int m_soundscapeEntityId; + string_t m_positionNames[NUM_AUDIO_LOCAL_SOUNDS]; + + // If this is set, then this soundscape ignores all its parameters and uses + // those of this soundscape. + CHandle m_hProxySoundscape; + + +private: + + bool m_bDisabled; +}; + + +class CEnvSoundscapeProxy : public CEnvSoundscape +{ +public: + DECLARE_CLASS( CEnvSoundscapeProxy, CEnvSoundscape ); + DECLARE_DATADESC(); + + CEnvSoundscapeProxy(); + virtual void Activate(); + + // Here just to stop it falling back to CEnvSoundscape's, and + // printing bogus errors about missing soundscapes. + virtual void Precache() { return; } + +private: + string_t m_MainSoundscapeName; +}; + + +class CEnvSoundscapeTriggerable : public CEnvSoundscape +{ +friend class CTriggerSoundscape; + +public: + DECLARE_CLASS( CEnvSoundscapeTriggerable, CEnvSoundscape ); + DECLARE_DATADESC(); + + CEnvSoundscapeTriggerable(); + + // Overrides the base class's think and prevents it from running at all. + virtual void Think(); + + +private: + + // Passed through from CTriggerSoundscape. + void DelegateStartTouch( CBaseEntity *pEnt ); + void DelegateEndTouch( CBaseEntity *pEnt ); +}; + + +#endif // SOUNDSCAPE_H diff --git a/game/server/soundscape_system.h b/game/server/soundscape_system.h new file mode 100644 index 0000000..8cdc356 --- /dev/null +++ b/game/server/soundscape_system.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SOUNDSCAPE_SYSTEM_H +#define SOUNDSCAPE_SYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "stringregistry.h" +#include "tier1/utlstring.h" +class CEnvSoundscape; + +struct clusterSoundscapeList_t +{ + unsigned short soundscapeCount; + unsigned short firstSoundscape; +}; + + + +class CSoundscapeSystem : public CAutoGameSystemPerFrame +{ +public: + CSoundscapeSystem( char const *name ) : CAutoGameSystemPerFrame( name ) + { + } + + // game system + virtual bool Init( void ); + virtual void Shutdown( void ); + virtual void FrameUpdatePostEntityThink( void ); + virtual void LevelInitPreEntity( void ); + virtual void LevelInitPostEntity(); + + virtual void AddSoundscapeFile( const char *filename ); + int GetSoundscapeIndex( const char *pName ); + bool IsValidIndex( int index ); + + void FlushSoundscapes( void ); + void AddSoundscapeEntity( CEnvSoundscape *pSoundscape ); + void RemoveSoundscapeEntity( CEnvSoundscape *pSoundscape ); + void PrintDebugInfo( void ); + + void AddSoundscapeSounds( KeyValues *pSoundscape, int soundscapeIndex ); + void PrecacheSounds( int soundscapeIndex ); + +private: + CStringRegistry m_soundscapes; + int m_soundscapeCount; + CUtlVector< CEnvSoundscape * > m_soundscapeEntities; + CUtlVector m_soundscapesInCluster; + CUtlVector m_soundscapeIndexList; + int m_activeIndex; + CUtlVector< CUtlVector< CUtlString > > m_soundscapeSounds; +}; + +extern CSoundscapeSystem g_SoundscapeSystem; + + +#endif // SOUNDSCAPE_SYSTEM_H diff --git a/game/server/spark.h b/game/server/spark.h new file mode 100644 index 0000000..c79fa34 --- /dev/null +++ b/game/server/spark.h @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SPARK_H +#define SPARK_H +#ifdef _WIN32 +#pragma once +#endif + +void DoSpark( CBaseEntity *ent, const Vector &location, int nMagnitude, int nTrailLength, bool bPlaySound, const Vector &vecDir ); +#endif // SPARK_H diff --git a/game/server/spotlightend.h b/game/server/spotlightend.h new file mode 100644 index 0000000..c6b8ae0 --- /dev/null +++ b/game/server/spotlightend.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Dynamic light at the end of a spotlight +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SPOTLIGHTEND_H +#define SPOTLIGHTEND_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" + +class CSpotlightEnd : public CBaseEntity +{ + DECLARE_DATADESC(); +public: + DECLARE_CLASS( CSpotlightEnd, CBaseEntity ); + + void Spawn( void ); + + int ObjectCaps( void ) + { + // Don't save and don't go across transitions + return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; + } + + DECLARE_SERVERCLASS(); + +public: + CNetworkVar( float, m_flLightScale ); + CNetworkVar( float, m_Radius ); +// CNetworkVector( m_vSpotlightDir ); +// CNetworkVector( m_vSpotlightOrg ); + Vector m_vSpotlightDir; + Vector m_vSpotlightOrg; +}; + +#endif //SPOTLIGHTEND_H + + diff --git a/game/server/steamjet.h b/game/server/steamjet.h new file mode 100644 index 0000000..2d784d5 --- /dev/null +++ b/game/server/steamjet.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the server side of a steam jet particle system entity. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef STEAMJET_H +#define STEAMJET_H +#pragma once + +#include "baseparticleentity.h" + +//NOTENOTE: Mirrored in cl_dlls\c_steamjet.cpp +#define STEAM_NORMAL 0 +#define STEAM_HEATWAVE 1 + +//================================================== +// CSteamJet +//================================================== + +class CSteamJet : public CBaseParticleEntity +{ +public: + CSteamJet(); + DECLARE_CLASS( CSteamJet, CBaseParticleEntity ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual void Spawn( void ); + virtual void Precache( void ); + +protected: + + // Input handlers. + void InputTurnOn(inputdata_t &data); + void InputTurnOff(inputdata_t &data); + void InputToggle(inputdata_t &data); + +// Stuff from the datatable. +public: + CNetworkVar( float, m_SpreadSpeed ); + CNetworkVar( float, m_Speed ); + CNetworkVar( float, m_StartSize ); + CNetworkVar( float, m_EndSize ); + CNetworkVar( float, m_Rate ); + CNetworkVar( float, m_JetLength ); // Length of the jet. Lifetime is derived from this. + + CNetworkVar( int, m_bEmit ); // Emit particles? + CNetworkVar( bool, m_bFaceLeft ); // For support of legacy env_steamjet, which faced left instead of forward. + bool m_InitialState; + + CNetworkVar( int, m_nType ); // Type of steam (normal, heatwave) + CNetworkVar( float, m_flRollSpeed ); + + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +#endif // STEAMJET_H + diff --git a/game/server/tactical_mission.h b/game/server/tactical_mission.h new file mode 100644 index 0000000..697d09d --- /dev/null +++ b/game/server/tactical_mission.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// tactical_mission.h +// Interface for managing player "missions" +// Michael Booth, June 2009 + +#ifndef TACTICAL_MISSION_H +#define TACTICAL_MISSION_H + +#include "nav_area.h" +#include "GameEventListener.h" + +class CBasePlayer; + +//--------------------------------------------------------------------------------------------- +/** + * A mission zone defines a region of space where something tactically interesting occurs. + */ +class CTacticalMissionZone +{ +public: + virtual CNavArea *SelectArea( CBasePlayer *who ) const; + + /** + * Iterate each area in this zone. + * If functor returns false, stop iterating and return false. + */ + virtual bool ForEachArea( IForEachNavArea &func ) const; + +protected: + CUtlVector< CNavArea * > m_areaVector; +}; + + +//--------------------------------------------------------------------------------------------- +/** + * A mission encapsulates an important task or set of tasks, such as capturing an enemy point + */ +class CTacticalMission +{ +public: + virtual ~CTacticalMission() { } + + virtual const CTacticalMissionZone *GetDeployZone( CBasePlayer *who ) const; // where give player should be during this mission + virtual const CTacticalMissionZone *GetObjectiveZone( void ) const; // control points, setup gates, sections of cart path, etc. + virtual const CTacticalMissionZone *GetEnemyZone( void ) const; // where we expect enemies to be during this mission + + virtual const char *GetName( void ) const = 0; // return name of this mission +}; + +inline const CTacticalMissionZone *CTacticalMission::GetDeployZone( CBasePlayer *who ) const +{ + return NULL; +} + +inline const CTacticalMissionZone *CTacticalMission::GetObjectiveZone( void ) const +{ + return NULL; +} + +inline const CTacticalMissionZone *CTacticalMission::GetEnemyZone( void ) const +{ + return NULL; +} + + +//--------------------------------------------------------------------------------------------- +/** + * The mission manager provides access to all available missions + */ +class CTacticalMissionManager : public CGameEventListener +{ +public: + CTacticalMissionManager( void ); + virtual ~CTacticalMissionManager() { } + + virtual void FireGameEvent( IGameEvent *event ); // incoming event processing + + virtual void OnServerActivate( void ) { } // invoked when server loads a new map, after everything has been created/spawned + virtual void OnRoundRestart( void ) { } // invoked when a game round restarts + + virtual void Register( CTacticalMission *mission ); + virtual void Unregister( CTacticalMission *mission ); + + virtual const CTacticalMission *GetMission( const char *name ); // given a mission name, return the mission (or NULL) + + /** + * Iterate each mission. + * If functor returns false, stop iterating and return false. + */ + class IForEachMission + { + public: + virtual bool Inspect( const CTacticalMission &mission ) = 0; + }; + virtual bool ForEachMission( IForEachMission &func ); + +protected: + CUtlVector< CTacticalMission * > m_missionVector; +}; + + +// global singleton +extern CTacticalMissionManager &TheTacticalMissions( void ); + +// factory for instantiating the global singleton +extern CTacticalMissionManager *TacticalMissionFactory( void ); + + +#endif // TACTICAL_MISSION_H diff --git a/game/server/te.h b/game/server/te.h new file mode 100644 index 0000000..6e97baa --- /dev/null +++ b/game/server/te.h @@ -0,0 +1,17 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( TE_H ) +#define TE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "itempents.h" + +#endif // TE_H diff --git a/game/server/te_basebeam.h b/game/server/te_basebeam.h new file mode 100644 index 0000000..b0be4c3 --- /dev/null +++ b/game/server/te_basebeam.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +//----------------------------------------------------------------------------- +// Purpose: Dispatches a beam ring between two entities +//----------------------------------------------------------------------------- +#if !defined( TE_BASEBEAM_H ) +#define TE_BASEBEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetempentity.h" + +abstract_class CTEBaseBeam : public CBaseTempEntity +{ +public: + + DECLARE_CLASS( CTEBaseBeam, CBaseTempEntity ); + DECLARE_SERVERCLASS(); + + +public: + CTEBaseBeam( const char *name ); + virtual ~CTEBaseBeam( void ); + + virtual void Test( const Vector& current_origin, const QAngle& current_angles ) = 0; + +public: + CNetworkVar( int, m_nModelIndex ); + CNetworkVar( int, m_nHaloIndex ); + CNetworkVar( int, m_nStartFrame ); + CNetworkVar( int, m_nFrameRate ); + CNetworkVar( float, m_fLife ); + CNetworkVar( float, m_fWidth ); + CNetworkVar( float, m_fEndWidth ); + CNetworkVar( int, m_nFadeLength ); + CNetworkVar( float, m_fAmplitude ); + CNetworkVar( int, r ); + CNetworkVar( int, g ); + CNetworkVar( int, b ); + CNetworkVar( int, a ); + CNetworkVar( int, m_nSpeed ); + CNetworkVar( int, m_nFlags ); +}; + +EXTERN_SEND_TABLE(DT_BaseBeam); + +#endif // TE_BASEBEAM_H \ No newline at end of file diff --git a/game/server/te_effect_dispatch.h b/game/server/te_effect_dispatch.h new file mode 100644 index 0000000..b759ed5 --- /dev/null +++ b/game/server/te_effect_dispatch.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TE_EFFECT_DISPATCH_H +#define TE_EFFECT_DISPATCH_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "effect_dispatch_data.h" +#include "recipientfilter.h" + + +void DispatchEffect( const char *pName, const CEffectData &data ); +void DispatchEffect( const char *pName, const CEffectData &data, CRecipientFilter &filter ); + + +#endif // TE_EFFECT_DISPATCH_H diff --git a/game/server/te_particlesystem.h b/game/server/te_particlesystem.h new file mode 100644 index 0000000..c414920 --- /dev/null +++ b/game/server/te_particlesystem.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TE_PARTICLESYSTEM_H +#define TE_PARTICLESYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "basetempentity.h" + + +class CTEParticleSystem : public CBaseTempEntity +{ +public: + DECLARE_CLASS( CTEParticleSystem, CBaseTempEntity ); + DECLARE_SERVERCLASS(); + + CTEParticleSystem(const char *pName) : BaseClass(pName) + { + m_vecOrigin.GetForModify().Init(); + } + + CNetworkVector( m_vecOrigin ); +}; + + +#endif // TE_PARTICLESYSTEM_H diff --git a/game/server/team.h b/game/server/team.h new file mode 100644 index 0000000..cdbe16d --- /dev/null +++ b/game/server/team.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Team management class. Contains all the details for a specific team +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEAM_H +#define TEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "utlvector.h" + +class CBasePlayer; +class CTeamSpawnPoint; + +class CTeam : public CBaseEntity +{ + DECLARE_CLASS( CTeam, CBaseEntity ); +public: + CTeam( void ); + virtual ~CTeam( void ); + + DECLARE_SERVERCLASS(); + + virtual void Precache( void ) { return; }; + + virtual void Think( void ); + virtual int UpdateTransmitState( void ); + + //----------------------------------------------------------------------------- + // Initialization + //----------------------------------------------------------------------------- + virtual void Init( const char *pName, int iNumber ); + + //----------------------------------------------------------------------------- + // Data Handling + //----------------------------------------------------------------------------- + virtual int GetTeamNumber( void ) const; + virtual const char *GetName( void ); + virtual void UpdateClientData( CBasePlayer *pPlayer ); + virtual bool ShouldTransmitToPlayer( CBasePlayer* pRecipient, CBaseEntity* pEntity ); + + //----------------------------------------------------------------------------- + // Spawnpoints + //----------------------------------------------------------------------------- + virtual void InitializeSpawnpoints( void ); + virtual void AddSpawnpoint( CTeamSpawnPoint *pSpawnpoint ); + virtual void RemoveSpawnpoint( CTeamSpawnPoint *pSpawnpoint ); + virtual CBaseEntity *SpawnPlayer( CBasePlayer *pPlayer ); + + //----------------------------------------------------------------------------- + // Players + //----------------------------------------------------------------------------- + virtual void InitializePlayers( void ); + virtual void AddPlayer( CBasePlayer *pPlayer ); + virtual void RemovePlayer( CBasePlayer *pPlayer ); + virtual int GetNumPlayers( void ); + virtual CBasePlayer *GetPlayer( int iIndex ); + + //----------------------------------------------------------------------------- + // Scoring + //----------------------------------------------------------------------------- + virtual void AddScore( int iScore ); + virtual void SetScore( int iScore ); + virtual int GetScore( void ); + virtual void ResetScores( void ); + + // Round scoring + virtual int GetRoundsWon( void ) { return m_iRoundsWon; } + virtual void SetRoundsWon( int iRounds ) { m_iRoundsWon = iRounds; } + virtual void IncrementRoundsWon( void ) { m_iRoundsWon++; } + + void AwardAchievement( int iAchievement ); + + virtual int GetAliveMembers( void ); + +public: + CUtlVector< CTeamSpawnPoint * > m_aSpawnPoints; + CUtlVector< CBasePlayer * > m_aPlayers; + + // Data + CNetworkString( m_szTeamname, MAX_TEAM_NAME_LENGTH ); + CNetworkVar( int, m_iScore ); + CNetworkVar( int, m_iRoundsWon ); + int m_iDeaths; + + // Spawnpoints + int m_iLastSpawn; // Index of the last spawnpoint used + + CNetworkVar( int, m_iTeamNum ); // Which team is this? +}; + +extern CUtlVector< CTeam * > g_Teams; +extern CTeam *GetGlobalTeam( int iIndex ); +extern int GetNumberOfTeams( void ); + +#endif // TEAM_H diff --git a/game/server/team_control_point.h b/game/server/team_control_point.h new file mode 100644 index 0000000..bfcfe10 --- /dev/null +++ b/game/server/team_control_point.h @@ -0,0 +1,195 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TEAM_CONTROL_POINT_H +#define TEAM_CONTROL_POINT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basemultiplayerplayer.h" + +// Spawnflags +#define SF_CAP_POINT_HIDEFLAG (1<<0) +#define SF_CAP_POINT_HIDE_MODEL (1<<1) +#define SF_CAP_POINT_HIDE_SHADOW (1<<2) +#define SF_CAP_POINT_NO_CAP_SOUNDS (1<<3) +#define SF_CAP_POINT_NO_ANNOUNCER (1<<4) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTeamControlPoint : public CBaseAnimating +{ + DECLARE_CLASS( CTeamControlPoint, CBaseAnimating ); +public: + DECLARE_DATADESC(); + + CTeamControlPoint(); + + // Derived, game-specific control points must override these functions +public: + // Used to find game specific entities + virtual const char *GetControlPointMasterName( void ) { return "team_control_point_master"; } + +public: + virtual void Spawn( void ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void Precache( void ); + virtual int DrawDebugTextOverlays( void ); + + //Inputs + inline void Enable( inputdata_t &input ) { SetActive( false ); } + inline void Disable( inputdata_t &input ) { SetActive( true ); } + void InputReset( inputdata_t &input ); + void InputSetOwner( inputdata_t &input ); + void InputShowModel( inputdata_t &input ); + void InputHideModel( inputdata_t &input ); + void InputRoundActivate( inputdata_t &inputdata ); + void InputSetLocked( inputdata_t &inputdata ); + void InputSetUnlockTime( inputdata_t &inputdata ); + + // Owner handling + void ForceOwner( int iTeam ); // used when selecting a specific round to play + void SetOwner( int iCapTeam, bool bMakeSound = true, int iNumCappers = 0, int *iCappingPlayers = NULL ); + int GetOwner( void ) const; + int GetDefaultOwner( void ) const; + bool RandomOwnerOnRestart( void ){ return m_bRandomOwnerOnRestart; } + + void SetActive( bool active ); + inline bool IsActive( void ) { return m_bActive; } + void AnimThink( void ); + + bool PointIsVisible( void ) { return !( FBitSet( m_spawnflags, SF_CAP_POINT_HIDEFLAG ) ); } + + inline const char *GetName( void ) { return STRING(m_iszPrintName); } + int GetCPGroup( void ); + int GetPointIndex( void ) { return m_iPointIndex; } + void SetPointIndex( int index ) { m_iPointIndex = index; } + + int GetWarnOnCap( void ) { return m_iWarnOnCap; } + string_t GetWarnSound( void ) { return m_iszWarnSound; } + + int GetTeamIcon( int iTeam ); + + int GetCurrentHudIconIndex( void ); + int GetHudIconIndexForTeam( int iGameTeam ); + int GetHudOverlayIndexForTeam( int iGameTeam ); + int GetPreviousPointForTeam( int iGameTeam, int iPrevPoint ); + + void SetCappersRequiredForTeam( int iGameTeam, int iCappers ); + + void CaptureBlocked( CBaseMultiplayerPlayer *pPlayer, CBaseMultiplayerPlayer *pVictim ); + + int PointValue( void ); + + bool HasBeenContested( void ) const; // return true if this point has ever been contested, false if the enemy has never contested this point yet + float LastContestedAt( void ); + void SetLastContestedAt( float flTime ); + + void UpdateCapPercentage( void ); + float GetTeamCapPercentage( int iTeam ); + + // The specified player took part in capping this point. + virtual void PlayerCapped( CBaseMultiplayerPlayer *pPlayer ); + + // The specified player blocked the enemy team from capping this point. + virtual void PlayerBlocked( CBaseMultiplayerPlayer *pPlayer ); + + void CaptureEnd( void ); + void CaptureStart( int iCapTeam, int iNumCappingPlayers, int *pCappingPlayers ); + void CaptureInterrupted( bool bBlocked ); + + virtual void StopLoopingSounds( void ); + + bool IsLocked( void ){ return m_bLocked; } + + void EXPORT UnlockThink( void ); + +private: + void SendCapString( int iCapTeam, int iNumCappingPlayers, int *pCappingPlayers ); + void InternalSetOwner( int iCapTeam, bool bMakeSound = true, int iNumCappers = 0, int *iCappingPlayers = NULL ); + void HandleScoring( int iTeam ); + void InternalSetLocked( bool bLocked ); + + int m_iTeam; + int m_iDefaultOwner; // Team that initially owns the cap point + int m_iIndex; // The index of this point in the controlpointArray + int m_iWarnOnCap; // Warn the team that owns the control point when the opposing team starts to capture it. + string_t m_iszPrintName; + string_t m_iszWarnSound; // Sound played if the team needs to be warned about this point being captured + bool m_bRandomOwnerOnRestart; // Do we want to randomize the owner after a restart? + bool m_bLocked; + float m_flUnlockTime; // Time to unlock + + // We store a copy of this data for each team, +1 for the un-owned state. + struct perteamdata_t + { + perteamdata_t() + { + iszCapSound = NULL_STRING; + iszModel = NULL_STRING; + iModelBodygroup = -1; + iIcon = 0; + iszIcon = NULL_STRING; + iOverlay = 0; + iszOverlay = NULL_STRING; + iPlayersRequired = 0; + iTimedPoints = 0; + for ( int i = 0; i < MAX_PREVIOUS_POINTS; i++ ) + { + iszPreviousPoint[i] = NULL_STRING; + } + iTeamPoseParam = 0; + } + + string_t iszCapSound; + string_t iszModel; + int iModelBodygroup; + int iTeamPoseParam; + int iIcon; + string_t iszIcon; + int iOverlay; + string_t iszOverlay; + int iPlayersRequired; + int iTimedPoints; + string_t iszPreviousPoint[MAX_PREVIOUS_POINTS]; + }; + CUtlVector m_TeamData; + + COutputEvent m_OnCapReset; + + COutputEvent m_OnCapTeam1; + COutputEvent m_OnCapTeam2; + + COutputEvent m_OnOwnerChangedToTeam1; + COutputEvent m_OnOwnerChangedToTeam2; + + COutputEvent m_OnRoundStartOwnedByTeam1; + COutputEvent m_OnRoundStartOwnedByTeam2; + + COutputEvent m_OnUnlocked; + + int m_bPointVisible; //should this capture point be visible on the hud? + int m_iPointIndex; //the mapper set index value of this control point + + int m_iCPGroup; //the group that this control point belongs to + bool m_bActive; // + + string_t m_iszName; //Name used in cap messages + + bool m_bStartDisabled; + + float m_flLastContestedAt; + + CSoundPatch *m_pCaptureInProgressSound; + string_t m_iszCaptureStartSound; + string_t m_iszCaptureEndSound; + string_t m_iszCaptureInProgress; + string_t m_iszCaptureInterrupted; +}; + +#endif // TEAM_CONTROL_POINT_H diff --git a/game/server/team_control_point_master.h b/game/server/team_control_point_master.h new file mode 100644 index 0000000..465a67d --- /dev/null +++ b/game/server/team_control_point_master.h @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TEAM_CONTROL_POINT_MASTER_H +#define TEAM_CONTROL_POINT_MASTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmap.h" +#include "team.h" +#include "teamplay_gamerules.h" +#include "team_control_point.h" +#include "trigger_area_capture.h" +#include "team_objectiveresource.h" +#include "team_control_point_round.h" + +#define CPM_THINK "CTeamControlPointMasterCPMThink" +#define CPM_POSTINITTHINK "CTeamControlPointMasterCPMPostInitThink" + +//----------------------------------------------------------------------------- +// Purpose: One ControlPointMaster is spawned per level. Shortly after spawning it detects all the Control +// points in the map and puts them into the m_ControlPoints. From there it detects the state +// where all points are captured and resets them if necessary It gives points every time interval to +// the owners of the points +//----------------------------------------------------------------------------- +class CTeamControlPointMaster : public CBaseEntity +{ + DECLARE_CLASS( CTeamControlPointMaster, CBaseEntity ); + + // Derived, game-specific control point masters must override these functions +public: + CTeamControlPointMaster(); + + // Used to find game specific entities + virtual const char *GetControlPointName( void ) { return "team_control_point"; } + virtual const char *GetControlPointRoundName( void ) { return "team_control_point_round"; } + +public: + virtual void Spawn( void ); + virtual void UpdateOnRemove( void ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void Precache( void ); + virtual void Activate( void ); + + void RoundRespawn( void ); + void Reset( void ); + + int GetNumPoints( void ){ return m_ControlPoints.Count(); } + int GetNumPointsOwnedByTeam( int iTeam ); + int CalcNumRoundsRemaining( int iTeam ); + + bool IsActive( void ) { return ( m_bDisabled == false ); } + + void FireTeamWinOutput( int iWinningTeam ); + + bool IsInRound( CTeamControlPoint *pPoint ); + void CheckWinConditions( void ); + + bool WouldNewCPOwnerWinGame( CTeamControlPoint *pPoint, int iNewOwner ); + + int GetBaseControlPoint( int iTeam ); + bool IsBaseControlPoint( int iPointIndex ); + + bool PlayingMiniRounds( void ){ return ( m_ControlPointRounds.Count() > 0 ); } + + float PointLastContestedAt( int point ); + CTeamControlPoint *GetControlPoint( int point ) + { + Assert( point >= 0 ); + Assert( point < MAX_CONTROL_POINTS ); + + for ( unsigned int i = 0; i < m_ControlPoints.Count(); i++ ) + { + CTeamControlPoint *pPoint = m_ControlPoints[i]; + if ( pPoint && pPoint->GetPointIndex() == point ) + return pPoint; + } + + return NULL; + } + + CTeamControlPointRound *GetCurrentRound( void ) + { + if ( !PlayingMiniRounds() || m_iCurrentRoundIndex == -1 ) + { + return NULL; + } + + return m_ControlPointRounds[m_iCurrentRoundIndex]; + } + + string_t GetRoundToUseAfterRestart( void ) + { + int nCurrentPriority = -1; + int nHighestPriority = -1; + + string_t nRetVal = NULL_STRING; + + if ( PlayingMiniRounds() && GetCurrentRound() ) + { + nCurrentPriority = GetCurrentRound()->GetPriorityValue(); + nHighestPriority = GetHighestRoundPriorityValue(); + + // if the current round has the highest priority, then use it again + if ( nCurrentPriority == nHighestPriority ) + { + nRetVal = GetCurrentRound()->GetEntityName(); + } + } + + return nRetVal; + } + + void FireRoundStartOutput( void ); + void FireRoundEndOutput( void ); + + bool ShouldScorePerCapture( void ){ return m_bScorePerCapture; } + bool ShouldPlayAllControlPointRounds( void ){ return m_bPlayAllRounds; } + int NumPlayableControlPointRounds( void ); // checks to see if there are any more rounds to play (but doesn't actually "get" one to play) + +#ifdef STAGING_ONLY + void ListRounds( void ); +#endif + + float GetPartialCapturePointRate( void ); + + void SetLastOwnershipChangeTime( float m_flTime ) { m_flLastOwnershipChangeTime = m_flTime; } + float GetLastOwnershipChangeTime( void ) { return m_flLastOwnershipChangeTime; } + + int GetCurrentRoundIndex() { return m_iCurrentRoundIndex; } + bool ShouldSwitchTeamsOnRoundWin( void ) { return m_bSwitchTeamsOnWin; } + +private: + void EXPORT CPMThink( void ); + + void SetBaseControlPoints( void ); + int TeamOwnsAllPoints( CTeamControlPoint *pOverridePoint = NULL, int iOverrideNewTeam = TEAM_UNASSIGNED ); + + bool FindControlPoints( void ); // look in the map to find active control points + bool FindControlPointRounds( void ); // look in the map to find active control point rounds + bool GetControlPointRoundToPlay( void ); // gets the next round we should play + bool SelectSpecificRound( void ); // selects a specific round to play + + int GetHighestRoundPriorityValue( void ) + { + int nRetVal = -1; + + // rounds are sorted with the higher priority rounds first + for ( int i = 0 ; i < m_ControlPointRounds.Count() ; ++i ) + { + CTeamControlPointRound *pRound = m_ControlPointRounds[i]; + + if ( pRound ) + { + if ( pRound->GetPriorityValue() > nRetVal ) + { + nRetVal = pRound->GetPriorityValue(); + } + } + } + + return nRetVal; + } + + void RegisterRoundBeingPlayed( void ); + + CUtlMap m_ControlPoints; + + bool m_bFoundPoints; // true when the control points have been found and the array is initialized + + CUtlVector m_ControlPointRounds; + int m_iCurrentRoundIndex; + + DECLARE_DATADESC(); + + bool m_bDisabled; + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + void InputRoundSpawn( inputdata_t &inputdata ); + void InputRoundActivate( inputdata_t &inputdata ); + void InputSetWinner( inputdata_t &inputdata ); + void InputSetWinnerAndForceCaps( inputdata_t &inputdata ); + void InputSetCapLayout( inputdata_t &inputdata ); + void InputSetCapLayoutCustomPositionX( inputdata_t &inputdata ); + void InputSetCapLayoutCustomPositionY( inputdata_t &inputdata ); + + void InternalSetWinner( int iTeam ); + + void HandleRandomOwnerControlPoints( void ); + + string_t m_iszTeamBaseIcons[MAX_TEAMS]; + int m_iTeamBaseIcons[MAX_TEAMS]; + string_t m_iszCapLayoutInHUD; + + float m_flCustomPositionX; + float m_flCustomPositionY; + + int m_iInvalidCapWinner; + bool m_bSwitchTeamsOnWin; + bool m_bScorePerCapture; + bool m_bPlayAllRounds; + + bool m_bFirstRoundAfterRestart; + + COutputEvent m_OnWonByTeam1; + COutputEvent m_OnWonByTeam2; + + float m_flPartialCapturePointsRate; + float m_flLastOwnershipChangeTime; +}; + +extern CUtlVector< CHandle > g_hControlPointMasters; + +#endif // TEAM_CONTROL_POINT_MASTER_H diff --git a/game/server/team_control_point_round.h b/game/server/team_control_point_round.h new file mode 100644 index 0000000..06cb33a --- /dev/null +++ b/game/server/team_control_point_round.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TEAM_CONTROL_POINT_ROUND_H +#define TEAM_CONTROL_POINT_ROUND_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmap.h" +#include "team.h" +#include "teamplay_gamerules.h" +#include "team_control_point.h" +#include "trigger_area_capture.h" +#include "team_objectiveresource.h" + + +class CTeamControlPointRound : public CBaseEntity +{ + DECLARE_CLASS( CTeamControlPointRound, CBaseEntity ); + +public: + virtual void Spawn( void ); + virtual void Activate( void ); + + bool IsDisabled( void ){ return m_bDisabled; } + + int GetPointOwner( int point ); +// int CountAdvantageFlags( int team ); + bool WouldNewCPOwnerWinGame( CTeamControlPoint *pPoint, int iNewOwner ); + + void FireTeamWinOutput( int iWinningTeam ); + + void SelectedToPlay( void ); + + int CheckWinConditions( void ); // returns the team number of the team that's won, or returns -1 if no winner + + int GetPriorityValue( void ) const { return m_nPriority; } + + bool IsPlayable( void ); + bool MakePlayable( void ); + bool IsControlPointInRound( CTeamControlPoint *pPoint ); + + void FireOnStartOutput( void ); + void FireOnEndOutput( void ); + + inline const char *GetName( void ) { return STRING(m_iszPrintName); } + + CHandle GetPointOwnedBy( int iTeam ); + + bool RoundOwnedByTeam( int iTeam ){ return ( TeamOwnsAllPoints() == iTeam ); } + int GetInvalidCapWinner() { return m_iInvalidCapWinner; } + + CUtlVector< CHandle > m_ControlPoints; + +private: + void FindControlPoints( void ); //look in the map to find the control points for this round + void SetupSpawnPoints( void ); + int TeamOwnsAllPoints( CTeamControlPoint *pOverridePoint = NULL, int iOverrideNewTeam = TEAM_UNASSIGNED ); + + DECLARE_DATADESC(); + + bool m_bDisabled; + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + void InputRoundSpawn( inputdata_t &inputdata ); + + string_t m_iszCPNames; + int m_nPriority; + int m_iInvalidCapWinner; + string_t m_iszPrintName; + + COutputEvent m_OnStart; + COutputEvent m_OnEnd; + COutputEvent m_OnWonByTeam1; + COutputEvent m_OnWonByTeam2; +}; + +#endif // TEAM_CONTROL_POINT_ROUND_H diff --git a/game/server/team_objectiveresource.h b/game/server/team_objectiveresource.h new file mode 100644 index 0000000..8d07294 --- /dev/null +++ b/game/server/team_objectiveresource.h @@ -0,0 +1,240 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TEAM_OBJECTIVERESOURCE_H +#define TEAM_OBJECTIVERESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +#define TEAM_ARRAY( index, team ) (index + (team * MAX_CONTROL_POINTS)) + +//----------------------------------------------------------------------------- +// Purpose: An entity that networks the state of the game's objectives. +// May contain data for objectives that aren't used by your mod, but +// the extra data will never be networked as long as it's zeroed out. +//----------------------------------------------------------------------------- +class CBaseTeamObjectiveResource : public CBaseEntity +{ + DECLARE_CLASS( CBaseTeamObjectiveResource, CBaseEntity ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CBaseTeamObjectiveResource(); + ~CBaseTeamObjectiveResource(); + + virtual void Spawn( void ); + virtual int UpdateTransmitState(void); + + virtual void ObjectiveThink( void ); + + //-------------------------------------------------------------------- + // CONTROL POINT DATA + //-------------------------------------------------------------------- +public: + void ResetControlPoints( void ); + + // Data functions, called to set up the state at the beginning of a round + void SetNumControlPoints( int num ); + int GetNumControlPoints( void ) { return m_iNumControlPoints; } + void SetCPIcons( int index, int iTeam, int iIcon ); + void SetCPOverlays( int index, int iTeam, int iIcon ); + void SetTeamBaseIcons( int iTeam, int iBaseIcon ); + void SetCPPosition( int index, const Vector& vPosition ); + void SetCPVisible( int index, bool bVisible ); + void SetCPRequiredCappers( int index, int iTeam, int iReqPlayers ); + void SetCPCapTime( int index, int iTeam, float flTime ); + void SetCPCapPercentage( int index, float flTime ); + float GetCPCapPercentage( int index ); + void SetTeamCanCap( int index, int iTeam, bool bCanCap ); + void SetBaseCP( int index, int iTeam ); + void SetPreviousPoint( int index, int iTeam, int iPrevIndex, int iPrevPoint ); + int GetPreviousPointForPoint( int index, int team, int iPrevIndex ); + bool TeamCanCapPoint( int index, int team ); + void SetCapLayoutInHUD( const char *pszLayout ) { Q_strncpy(m_pszCapLayoutInHUD.GetForModify(), pszLayout, MAX_CAPLAYOUT_LENGTH ); } + void SetCapLayoutCustomPosition( float flPositionX, float flPositionY ) { m_flCustomPositionX = flPositionX; m_flCustomPositionY = flPositionY; } + void SetWarnOnCap( int index, int iWarnLevel ); + void SetWarnSound( int index, string_t iszSound ); + void SetCPGroup( int index, int iCPGroup ); + void SetCPLocked( int index, bool bLocked ); + void SetTrackAlarm( int index, bool bAlarm ); + void SetCPUnlockTime( int index, float flTime ); + void SetCPTimerTime( int index, float flTime ); + void SetCPCapTimeScalesWithPlayers( int index, bool bScales ); + + // State functions, called many times + void SetNumPlayers( int index, int team, int iNumPlayers ); + void StartCap( int index, int team ); + void SetOwningTeam( int index, int team ); + void SetCappingTeam( int index, int team ); + void SetTeamInZone( int index, int team ); + void SetCapBlocked( int index, bool bBlocked ); + int GetOwningTeam( int index ); + + void AssertValidIndex( int index ) + { + Assert( 0 <= index && index <= MAX_CONTROL_POINTS && index < m_iNumControlPoints ); + } + + int GetBaseControlPointForTeam( int iTeam ) + { + Assert( iTeam < MAX_TEAMS ); + return m_iBaseControlPoints[iTeam]; + } + + int GetCappingTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iCappingTeam[index]; + } + + void SetTimerInHUD( CBaseEntity *pTimer ) + { + m_iTimerToShowInHUD = pTimer ? pTimer->entindex() : 0; + } + + + void SetStopWatchTimer( CBaseEntity *pTimer ) + { + m_iStopWatchTimer = pTimer ? pTimer->entindex() : 0; + } + + int GetTimerInHUD( void ) { return m_iTimerToShowInHUD; } + + // Mini-rounds data + void SetPlayingMiniRounds( bool bPlayingMiniRounds ){ m_bPlayingMiniRounds = bPlayingMiniRounds; } + bool PlayingMiniRounds( void ){ return m_bPlayingMiniRounds; } + void SetInMiniRound( int index, bool bInRound ) { m_bInMiniRound.Set( index, bInRound ); } + bool IsInMiniRound( int index ) { return m_bInMiniRound[index]; } + + void UpdateCapHudElement( void ); + + // Train Path data + void SetTrainPathDistance( int index, float flDistance ); + + bool GetCPLocked( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_bCPLocked[index]; + } + + void ResetHillData( int team ) + { + if ( team < TEAM_TRAIN_MAX_TEAMS ) + { + m_nNumNodeHillData.Set( team, 0 ); + + int nNumEntriesPerTeam = TEAM_TRAIN_MAX_HILLS * TEAM_TRAIN_FLOATS_PER_HILL; + int iStartingIndex = team * nNumEntriesPerTeam; + for ( int i = 0 ; i < nNumEntriesPerTeam ; i++ ) + { + m_flNodeHillData.Set( iStartingIndex + i, 0 ); + } + + iStartingIndex = team * TEAM_TRAIN_MAX_HILLS; + for ( int i = 0; i < TEAM_TRAIN_MAX_HILLS; i++ ) + { + m_bHillIsDownhill.Set( iStartingIndex + i, 0 ); + } + } + } + + void SetHillData( int team, float flStart, float flEnd, bool bDownhill ) + { + if ( team < TEAM_TRAIN_MAX_TEAMS ) + { + int index = ( m_nNumNodeHillData[team] * TEAM_TRAIN_FLOATS_PER_HILL ) + ( team * TEAM_TRAIN_MAX_HILLS * TEAM_TRAIN_FLOATS_PER_HILL ); + if ( index < TEAM_TRAIN_HILLS_ARRAY_SIZE - 1 ) // - 1 because we want to add 2 entries + { + m_flNodeHillData.Set( index, flStart ); + m_flNodeHillData.Set( index + 1, flEnd ); + + if ( m_nNumNodeHillData[team] < TEAM_TRAIN_MAX_HILLS ) + { + m_bHillIsDownhill.Set( m_nNumNodeHillData[team] + ( team * TEAM_TRAIN_MAX_HILLS ), bDownhill ); + } + + m_nNumNodeHillData.Set( team, m_nNumNodeHillData[team] + 1); + } + } + } + +private: + CNetworkVar( int, m_iTimerToShowInHUD ); + CNetworkVar( int, m_iStopWatchTimer ); + + CNetworkVar( int, m_iNumControlPoints ); + CNetworkVar( bool, m_bPlayingMiniRounds ); + CNetworkVar( bool, m_bControlPointsReset ); + CNetworkVar( int, m_iUpdateCapHudParity ); + + // data variables + CNetworkArray( Vector, m_vCPPositions, MAX_CONTROL_POINTS ); + CNetworkArray( int, m_bCPIsVisible, MAX_CONTROL_POINTS ); + CNetworkArray( float, m_flLazyCapPerc, MAX_CONTROL_POINTS ); + CNetworkArray( int, m_iTeamIcons, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ); + CNetworkArray( int, m_iTeamOverlays, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ); + CNetworkArray( int, m_iTeamReqCappers, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ); + CNetworkArray( float, m_flTeamCapTime, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ); + CNetworkArray( int, m_iPreviousPoints, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS * MAX_PREVIOUS_POINTS ); + CNetworkArray( bool, m_bTeamCanCap, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ); + CNetworkArray( int, m_iTeamBaseIcons, MAX_TEAMS ); + CNetworkArray( int, m_iBaseControlPoints, MAX_TEAMS ); + CNetworkArray( bool, m_bInMiniRound, MAX_CONTROL_POINTS ); + CNetworkArray( int, m_iWarnOnCap, MAX_CONTROL_POINTS ); + CNetworkArray( string_t, m_iszWarnSound, MAX_CONTROL_POINTS ); + CNetworkArray( float, m_flPathDistance, MAX_CONTROL_POINTS ); + CNetworkArray( bool, m_bCPLocked, MAX_CONTROL_POINTS ); + CNetworkArray( float, m_flUnlockTimes, MAX_CONTROL_POINTS ); + CNetworkArray( float, m_flCPTimerTimes, MAX_CONTROL_POINTS ); + + // change when players enter/exit an area + CNetworkArray( int, m_iNumTeamMembers, MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ); + + // changes when a cap starts. start and end times are calculated on client + CNetworkArray( int, m_iCappingTeam, MAX_CONTROL_POINTS ); + + CNetworkArray( int, m_iTeamInZone, MAX_CONTROL_POINTS ); + CNetworkArray( bool, m_bBlocked, MAX_CONTROL_POINTS ); + + // changes when a point is successfully captured + CNetworkArray( int, m_iOwner, MAX_CONTROL_POINTS ); + CNetworkArray( bool, m_bCPCapRateScalesWithPlayers, MAX_CONTROL_POINTS ); + + // describes how to lay out the cap points in the hud + CNetworkString( m_pszCapLayoutInHUD, MAX_CAPLAYOUT_LENGTH ); + + // custom screen position for the cap points in the hud + CNetworkVar( float, m_flCustomPositionX ); + CNetworkVar( float, m_flCustomPositionY ); + + // the groups the points belong to + CNetworkArray( int, m_iCPGroup, MAX_CONTROL_POINTS ); + + // Not networked, because the client recalculates it + float m_flCapPercentages[ MAX_CONTROL_POINTS ]; + + // hill data for multi-escort payload maps + CNetworkArray( int, m_nNumNodeHillData, TEAM_TRAIN_MAX_TEAMS ); + CNetworkArray( float, m_flNodeHillData, TEAM_TRAIN_HILLS_ARRAY_SIZE ); + + CNetworkArray( bool, m_bTrackAlarm, TEAM_TRAIN_MAX_TEAMS ); + CNetworkArray( bool, m_bHillIsDownhill, TEAM_TRAIN_MAX_HILLS*TEAM_TRAIN_MAX_TEAMS ); +}; + +extern CBaseTeamObjectiveResource *g_pObjectiveResource; + +inline CBaseTeamObjectiveResource *ObjectiveResource() +{ + return g_pObjectiveResource; +} + +#endif // TEAM_OBJECTIVERESOURCE_H diff --git a/game/server/team_spawnpoint.h b/game/server/team_spawnpoint.h new file mode 100644 index 0000000..76187ff --- /dev/null +++ b/game/server/team_spawnpoint.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Team spawnpoint entity +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TF_TEAMSPAWNPOINT_H +#define TF_TEAMSPAWNPOINT_H +#pragma once + +#include "baseentity.h" +#include "entityoutput.h" + +class CTeam; + +//----------------------------------------------------------------------------- +// Purpose: points at which the player can spawn, restricted by team +//----------------------------------------------------------------------------- +class CTeamSpawnPoint : public CPointEntity +{ +public: + DECLARE_CLASS( CTeamSpawnPoint, CPointEntity ); + + void Activate( void ); + virtual bool IsValid( CBasePlayer *pPlayer ); + + COutputEvent m_OnPlayerSpawn; + +protected: + int m_iDisabled; + + // Input handlers + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + DECLARE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: points at which vehicles can spawn, restricted by team +//----------------------------------------------------------------------------- +class CTeamVehicleSpawnPoint : public CTeamSpawnPoint +{ + DECLARE_CLASS( CTeamVehicleSpawnPoint, CTeamSpawnPoint ); +public: + void Activate( void ); + bool IsValid( void ); + + COutputEvent m_OnVehicleSpawn; + + DECLARE_DATADESC(); +}; + + +#endif // TF_TEAMSPAWNPOINT_H diff --git a/game/server/team_train_watcher.h b/game/server/team_train_watcher.h new file mode 100644 index 0000000..663b614 --- /dev/null +++ b/game/server/team_train_watcher.h @@ -0,0 +1,233 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TEAM_TRAIN_WATCHER_H +#define TEAM_TRAIN_WATCHER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" +#include "trigger_area_capture.h" +#include "shareddefs.h" +#include "envspark.h" +#include "GameEventListener.h" + +class CFuncTrackTrain; +class CPathTrack; +class CTeamControlPoint; + +#define TEAM_TRAIN_ALERT_DISTANCE 750 // alert is the VO warning +#define TEAM_TRAIN_ALARM_DISTANCE 200 // alarm is the looping sound played at the control point + +#define TEAM_TRAIN_ALERT "Announcer.Cart.Warning" +#define TEAM_TRAIN_FINAL_ALERT "Announcer.Cart.FinalWarning" +#define TEAM_TRAIN_ALARM "Cart.Warning" +#define TEAM_TRAIN_ALARM_SINGLE "Cart.WarningSingle" + +#define TW_THINK "CTeamTrainWatcherThink" +#define TW_ALARM_THINK "CTeamTrainWatcherAlarmThink" +#define TW_ALARM_THINK_INTERVAL 8.0 + +// #define TWMASTER_THINK "CTeamTrainWatcherMasterThink" + +DECLARE_AUTO_LIST( ITFTeamTrainWatcher ); + +class CTeamTrainWatcher : public CBaseEntity, public CGameEventListener, public ITFTeamTrainWatcher +{ + DECLARE_CLASS( CTeamTrainWatcher, CBaseEntity ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CTeamTrainWatcher(); + ~CTeamTrainWatcher(); + + virtual void UpdateOnRemove( void ); + virtual int UpdateTransmitState(); + + void InputRoundActivate( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + void InputSetNumTrainCappers( inputdata_t &inputdata ); + void InputOnStartOvertime( inputdata_t &inputdata ); + void InputSetSpeedForwardModifier( inputdata_t &inputdata ); + void InputSetTrainRecedeTime( inputdata_t &inputdata ); + void InputSetTrainCanRecede( inputdata_t &inputdata ); + void InputSetTrainRecedeTimeAndUpdate( inputdata_t &inputdata ); + + // ========================================================== + // given a start node and a list of goal nodes + // calculate the distance between each + // ========================================================== + void WatcherActivate( void ); + + void WatcherThink( void ); + void WatcherAlarmThink( void ); + + CBaseEntity *GetTrainEntity( void ); + bool IsDisabled( void ) { return m_bDisabled; } + + bool TimerMayExpire( void ); + + void StopCaptureAlarm( void ); + + void SetNumTrainCappers( int iNumCappers, CBaseEntity *pTrigger ); // only used for train watchers that control the train movement + + virtual void FireGameEvent( IGameEvent * event ); + + int GetCapturerCount( void ) const; // return the number of players who are "capturing" the payload, or -1 if the payload is blocked + + void ProjectPointOntoPath( const Vector &pos, Vector *posOnPath, float *distanceAlongPath ) const; // project the given position onto the track and return the point and how far along that projected position is + bool IsAheadOfTrain( const Vector &pos ) const; // return true if the given position is farther down the track than the train is + + bool IsTrainAtStart( void ) const; // return true if the train hasn't left its starting position yet + bool IsTrainNearCheckpoint( void ) const; // return true if the train is almost at the next checkpoint + + float GetTrainDistanceAlongTrack( void ) const; + Vector GetNextCheckpointPosition( void ) const; // return world space location of next checkpoint along the path + +#if defined( STAGING_ONLY ) && defined( TF_DLL ) + void DumpStats( void ); +#endif // STAGING_ONLY && TF_DLL + + float GetTrainProgress() { return m_flTotalProgress; } + +private: + + void StartCaptureAlarm( CTeamControlPoint *pPoint ); + void PlayCaptureAlert( CTeamControlPoint *pPoint, bool bFinalPointInMap ); + void InternalSetNumTrainCappers( int iNumCappers, CBaseEntity *pTrigger ); + void InternalSetSpeedForwardModifier( float flModifier ); +#ifdef GLOWS_ENABLE + void FindGlowEntity( void ); +#endif // GLOWS_ENABLE + void HandleTrainMovement( bool bStartReceding = false ); + void HandleSparks( bool bSparks ); + +private: + + bool m_bDisabled; + bool m_bTrainCanRecede; + // === Data === + + // pointer to the train that we're checking + CHandle m_hTrain; + + // start node + CHandle m_hStartNode; + + // goal node + CHandle m_hGoalNode; + + string_t m_iszTrain; + string_t m_iszStartNode; + string_t m_iszGoalNode; + + // list of node associations with control points + typedef struct + { + CHandle hPathTrack; + CHandle hCP; + float flDistanceFromStart; + bool bAlertPlayed; + } node_cp_pair_t; + + node_cp_pair_t m_CPLinks[MAX_CONTROL_POINTS]; + int m_iNumCPLinks; + + string_t m_iszLinkedPathTracks[MAX_CONTROL_POINTS]; + string_t m_iszLinkedCPs[MAX_CONTROL_POINTS]; + + float m_flTotalPathDistance; // calculated only at round start, node graph + // may get chopped as the round progresses + + float m_flTrainDistanceFromStart; // actual distance along path of train, for comparing against m_CPLinks[].flDistanceFromStart + + float m_flSpeedLevels[3]; + + // === Networked Data === + + // current total progress, percentage + CNetworkVar( float, m_flTotalProgress ); + + CNetworkVar( int, m_iTrainSpeedLevel ); + + CNetworkVar( int, m_nNumCappers ); + + bool m_bWaitingToRecede; + CNetworkVar( float, m_flRecedeTime ); + float m_flRecedeTotalTime; + float m_flRecedeStartTime; + COutputEvent m_OnTrainStartRecede; + + bool m_bCapBlocked; + + float m_flNextSpeakForwardConceptTime; // used to have players speak the forward concept every X seconds + CHandle m_hAreaCap; + + CSoundPatch *m_pAlarm; + float m_flAlarmEndTime; + bool m_bAlarmPlayed; + + // added for new mode where the train_watcher handles the train movement + bool m_bHandleTrainMovement; + string_t m_iszSparkName; + CUtlVector< CHandle > m_Sparks; + float m_flSpeedForwardModifier; + int m_iCurrentHillType; + float m_flCurrentSpeed; + bool m_bReceding; + + int m_nTrainRecedeTime; + +#ifdef GLOWS_ENABLE + CNetworkVar( EHANDLE, m_hGlowEnt ); +#endif // GLOWS_ENABLE +}; + + +inline float CTeamTrainWatcher::GetTrainDistanceAlongTrack( void ) const +{ + return m_flTrainDistanceFromStart; +} + +inline int CTeamTrainWatcher::GetCapturerCount( void ) const +{ + return m_nNumCappers; +} + + +/* +class CTeamTrainWatcherMaster : public CBaseEntity, public CGameEventListener +{ + DECLARE_CLASS( CTeamTrainWatcherMaster, CBaseEntity ); + +public: + CTeamTrainWatcherMaster(); + ~CTeamTrainWatcherMaster(); + + void Precache( void ); + +private: + void TWMThink( void ); + void FireGameEvent( IGameEvent *event ); + + bool FindTrainWatchers( void ); + +private: + CTeamTrainWatcher *m_pBlueWatcher; + CTeamTrainWatcher *m_pRedWatcher; + + float m_flBlueProgress; + float m_flRedProgress; +}; + +extern EHANDLE g_hTeamTrainWatcherMaster; +*/ + +#endif //TEAM_TRAIN_WATCHER_H diff --git a/game/server/tesla.h b/game/server/tesla.h new file mode 100644 index 0000000..5728e3b --- /dev/null +++ b/game/server/tesla.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TESLA_H +#define TESLA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "baseentity.h" + + +class CTesla : public CBaseEntity +{ +public: + DECLARE_CLASS( CTesla, CBaseEntity ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CTesla(); + + virtual void Spawn(); + virtual void Activate(); + virtual void Precache(); + + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + void InputDoSpark( inputdata_t &inputdata ); + + void DoSpark(); + void ShootArcThink(); + + void SetupForNextArc(); + CBaseEntity* GetSourceEntity(); + + +public: + + // Tesla parameters. + string_t m_SourceEntityName; // Which entity the arcs come from. + CNetworkVar( string_t, m_SoundName ); // What sound to play when arcing. + + color32 m_Color; + int m_NumBeams[2]; // Number of beams per spark. + + float m_flRadius; // Radius it looks for surfaces to arc to. + + float m_flThickness[2]; // Beam thickness. + float m_flTimeVisible[2]; // How long each beam stays around (min/max). + float m_flArcInterval[2]; // Time between args (min/max). + + bool m_bOn; + + CNetworkVar( string_t, m_iszSpriteName ); +}; + + +#endif // TESLA_H diff --git a/game/server/test_stressentities.h b/game/server/test_stressentities.h new file mode 100644 index 0000000..7583e4e --- /dev/null +++ b/game/server/test_stressentities.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEST_STRESSENTITIES_H +#define TEST_STRESSENTITIES_H +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseEntity; + + +typedef CBaseEntity* (*StressEntityFn)(); // Function to create an entity for the stress test. + + +// Each game DLL can instantiate these to register types of entities it can create +// for the entity stress test. +class CStressEntityReg +{ +public: + + CStressEntityReg( StressEntityFn fn ) + { + m_pFn = fn; + m_pNext = s_pHead; + s_pHead = this; + } + + static CStressEntityReg*GetListHead() { return s_pHead; } + CStressEntityReg* GetNext() { return m_pNext; } + StressEntityFn GetFn() { return m_pFn; } + + +private: + static CStressEntityReg *s_pHead; // List of all CStressEntityReg's. + CStressEntityReg *m_pNext; + StressEntityFn m_pFn; +}; + + +// Use this macro to register a function to create stresstest entities. +#define REGISTER_STRESS_ENTITY( fnName ) static CStressEntityReg s_##fnName##__( fnName ); + + +// Helper function for the functions that create the stress entities. +// Moves the entity to a random place in the level and returns the entity. +CBaseEntity* MoveToRandomSpot( CBaseEntity *pEnt ); +Vector GetRandomSpot(); + + +#endif // TEST_STRESSENTITIES_H diff --git a/game/server/textstatsmgr.h b/game/server/textstatsmgr.h new file mode 100644 index 0000000..473e1a0 --- /dev/null +++ b/game/server/textstatsmgr.h @@ -0,0 +1,133 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEXTSTATSMGR_H +#define TEXTSTATSMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "filesystem.h" +#include "utllinkedlist.h" + + +// Text stats get to print their stuff by implementing this type of function. +typedef void (*TextStatPrintFn)( IFileSystem *pFileSys, FileHandle_t hFile, void *pUserData ); +typedef void (*TextStatFileFn)(); + + +// The CTextStatsMgr is just a collection of CTextStat's that go into the same file. +class CTextStatsMgr +{ +public: + CTextStatsMgr( void ); + + // Write a file with all the registered stats. + bool WriteFile( IFileSystem *pFileSystem, const char *pFilename = NULL ); + + // Get the preset filename to write stats to, if none is specified when writing + char *GetStatsFilename( void ); + + // Set the filename to write stats to, if none is specified when writing + void SetStatsFilename( char *sFilename ); + +private: + char m_szStatFilename[ MAX_PATH ]; +}; + + +// This is the default CTextStatsMgr, but there can be any number of them. +extern CTextStatsMgr g_TextStatsMgr; + + + +// Make these to register text stat functions. +class CTextStat +{ +friend class CTextStatsMgr; + +public: + CTextStat(); + CTextStat( TextStatPrintFn fn, void *pUserData, CTextStatsMgr *pMgr=&g_TextStatsMgr ); + ~CTextStat(); + + // This can be called if you don't want to pass parameters into the constructor. + void Init( TextStatPrintFn printFn, void *pUserData, CTextStatsMgr *pMgr=&g_TextStatsMgr ); + void Term(); + + +private: + + // Special constructor to just tie off the linked list. + CTextStat( bool bGlobalListHead ); + + // The global list of CTextStats. + static CTextStat* GetTextStatsList(); + + static void RemoveFn( void *pUserData ); + + // Link it into the global list. + CTextStat *m_pPrev; + CTextStat *m_pNext; + + CTextStatsMgr *m_pMgr; + + TextStatPrintFn m_PrintFn; + void *m_pUserData; +}; + + +// This class registers like a ConVar and acts like an int. When the game is shutdown, +// its value will be saved in the stats file along with its name.s +class CTextStatInt +{ +public: + CTextStatInt( const char *pName, int initialValue=0, CTextStatsMgr *pMgr=&g_TextStatsMgr ); + + operator int() const { return m_Value; } + int operator=( int val ) { m_Value = val; return m_Value; } + + int operator++() { m_Value++; return m_Value; } + int operator--() { m_Value--; return m_Value; } + int operator+=( int val ) { m_Value += val; return m_Value; } + int operator-=( int val ) { m_Value -= val; return m_Value; } + int operator*=( int val ) { m_Value *= val; return m_Value; } + int operator/=( int val ) { m_Value /= val; return m_Value; } + + +private: + + static void PrintFn( IFileSystem *pFileSys, FileHandle_t hFile, void *pUserData ); + + +private: + + const char *m_pName; + int m_Value; + + CTextStat m_Reg; // Use to register ourselves. +}; + + +// This can be registered to get a callback when the text stats mgr is saving its files. +// You can write data out to your own file in here. +class CTextStatFile +{ +public: + CTextStatFile( TextStatFileFn fn ); + +private: + friend class CTextStatsMgr; + + static CTextStatFile *s_pHead; + CTextStatFile *m_pNext; + TextStatFileFn m_pFn; +}; + + +#endif // TEXTSTATSMGR_H diff --git a/game/server/timedeventmgr.h b/game/server/timedeventmgr.h new file mode 100644 index 0000000..66b1586 --- /dev/null +++ b/game/server/timedeventmgr.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TIMEDEVENTMGR_H +#define TIMEDEVENTMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "utlpriorityqueue.h" + + +// +// +// These classes provide fast timed event callbacks. To use them, make a CTimedEventMgr +// and put CEventRegister objects in your objects that want the timed events. +// +// + + +class CTimedEventMgr; + + +abstract_class IEventRegisterCallback +{ +public: + virtual void FireEvent() = 0; +}; + + +class CEventRegister +{ +friend bool TimedEventMgr_LessFunc( CEventRegister* const &a, CEventRegister* const &b ); +friend class CTimedEventMgr; + +public: + CEventRegister(); + ~CEventRegister(); + + // Call this before ever calling SetUpdateInterval(). + void Init( CTimedEventMgr *pMgr, IEventRegisterCallback *pCallback ); + + // Use these to start and stop getting updates. + void SetUpdateInterval( float interval ); + void StopUpdates(); + + inline bool IsRegistered() const { return m_bRegistered; } + +private: + + void Reregister(); // After having an event processed, this is called to have it register for the next one. + void Term(); + + +private: + + CTimedEventMgr *m_pEventMgr; + float m_flNextEventTime; + float m_flUpdateInterval; + IEventRegisterCallback *m_pCallback; + bool m_bRegistered; +}; + + +class CTimedEventMgr +{ +friend class CEventRegister; + +public: + CTimedEventMgr(); + + // Call this each frame to fire events. + void FireEvents(); + + +private: + + // Things used by CEventRegister. + void RegisterForNextEvent( CEventRegister *pEvent ); + void RemoveEvent( CEventRegister *pEvent ); + +private: + + // Events, sorted by the time at which they will fire. + CUtlPriorityQueue m_Events; +}; + + +#endif // TIMEDEVENTMGR_H diff --git a/game/server/toolframework_server.h b/game/server/toolframework_server.h new file mode 100644 index 0000000..941df13 --- /dev/null +++ b/game/server/toolframework_server.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef TOOLFRAMEWORK_SERVER_H +#define TOOLFRAMEWORK_SERVER_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Are tools enabled? +//----------------------------------------------------------------------------- +#ifndef NO_TOOLFRAMEWORK +bool ToolsEnabled(); +#else +#define ToolsEnabled() 0 +#endif + + +#endif // TOOLFRAMEWORK_SERVER_H diff --git a/game/server/trains.h b/game/server/trains.h new file mode 100644 index 0000000..ef7e8b7 --- /dev/null +++ b/game/server/trains.h @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TRAINS_H +#define TRAINS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "entityoutput.h" +#include "pathtrack.h" + + +// Spawnflags of CPathCorner +#define SF_CORNER_WAITFORTRIG 0x001 +#define SF_CORNER_TELEPORT 0x002 + +// Tracktrain spawn flags +#define SF_TRACKTRAIN_NOPITCH 0x0001 +#define SF_TRACKTRAIN_NOCONTROL 0x0002 +#define SF_TRACKTRAIN_FORWARDONLY 0x0004 +#define SF_TRACKTRAIN_PASSABLE 0x0008 +#define SF_TRACKTRAIN_FIXED_ORIENTATION 0x0010 +#define SF_TRACKTRAIN_HL1TRAIN 0x0080 +#define SF_TRACKTRAIN_USE_MAXSPEED_FOR_PITCH 0x0100 +#define SF_TRACKTRAIN_UNBLOCKABLE_BY_PLAYER 0x0200 + +#define TRAIN_ACTIVE 0x80 +#define TRAIN_NEW 0xc0 +#define TRAIN_OFF 0x00 +#define TRAIN_NEUTRAL 0x01 +#define TRAIN_SLOW 0x02 +#define TRAIN_MEDIUM 0x03 +#define TRAIN_FAST 0x04 +#define TRAIN_BACK 0x05 + + +enum TrainVelocityType_t +{ + TrainVelocity_Instantaneous = 0, + TrainVelocity_LinearBlend, + TrainVelocity_EaseInEaseOut, +}; + + +enum TrainOrientationType_t +{ + TrainOrientation_Fixed = 0, + TrainOrientation_AtPathTracks, + TrainOrientation_LinearBlend, + TrainOrientation_EaseInEaseOut, +}; + +class CFuncTrackTrain : public CBaseEntity +{ + DECLARE_CLASS( CFuncTrackTrain, CBaseEntity ); + DECLARE_SERVERCLASS(); + +public: + CFuncTrackTrain(); + + void Spawn( void ); + bool CreateVPhysics( void ); + void Precache( void ); + void UpdateOnRemove(); + void MoveDone(); + + virtual int OnTakeDamage( const CTakeDamageInfo &info ); + + void Blocked( CBaseEntity *pOther ); + bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual int DrawDebugTextOverlays(); + void DrawDebugGeometryOverlays(); + + void Next( void ); + void Find( void ); + void NearestPath( void ); + void DeadEnd( void ); + + void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest(GetLocalOrigin()); } + void SetControls( CBaseEntity *pControls ); + bool OnControls( CBaseEntity *pControls ); + + void SoundStop( void ); + void SoundUpdate( void ); + + void Start( void ); + void Stop( void ); + + bool IsDirForward(); + void SetDirForward( bool bForward ); + void SetSpeed( float flSpeed, bool bAccel = false ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void SetSpeedDirAccel( float flNewSpeed ); + + // Input handlers + void InputSetSpeed( inputdata_t &inputdata ); + void InputSetSpeedDir( inputdata_t &inputdata ); + void InputSetSpeedReal( inputdata_t &inputdata ); + void InputStop( inputdata_t &inputdata ); + void InputResume( inputdata_t &inputdata ); + void InputReverse( inputdata_t &inputdata ); + void InputStartForward( inputdata_t &inputdata ); + void InputStartBackward( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + void InputSetSpeedDirAccel( inputdata_t &inputdata ); + void InputTeleportToPathTrack( inputdata_t &inputdata ); + void InputSetSpeedForwardModifier( inputdata_t &inputdata ); + + static CFuncTrackTrain *Instance( edict_t *pent ); + +#ifdef TF_DLL + int UpdateTransmitState() + { + return SetTransmitState( FL_EDICT_ALWAYS ); + } +#endif + + DECLARE_DATADESC(); + + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_DIRECTIONAL_USE | FCAP_USE_ONGROUND; } + + virtual void OnRestore( void ); + + float GetMaxSpeed() const { return m_maxSpeed; } + float GetCurrentSpeed() const { return m_flSpeed; } + float GetDesiredSpeed() const { return m_flDesiredSpeed;} + + virtual bool IsBaseTrain( void ) const { return true; } + + void SetSpeedForwardModifier( float flModifier ); + void SetBlockDamage( float flDamage ) { m_flBlockDamage = flDamage; } + void SetDamageChild( bool bDamageChild ) { m_bDamageChild = bDamageChild; } + +private: + + void ArriveAtNode( CPathTrack *pNode ); + void FirePassInputs( CPathTrack *pStart, CPathTrack *pEnd, bool forward ); + +public: + + // UNDONE: Add accessors? + CPathTrack *m_ppath; + float m_length; + +#ifdef HL1_DLL + bool m_bOnTrackChange; // we don't want to find a new node if we restore while + // riding on a func_trackchange +#endif + +private: + + TrainVelocityType_t GetTrainVelocityType(); + void UpdateTrainVelocity( CPathTrack *pnext, CPathTrack *pNextNext, const Vector &nextPos, float flInterval ); + + TrainOrientationType_t GetTrainOrientationType(); + void UpdateTrainOrientation( CPathTrack *pnext, CPathTrack *pNextNext, const Vector &nextPos, float flInterval ); + void UpdateOrientationAtPathTracks( CPathTrack *pnext, CPathTrack *pNextNext, const Vector &nextPos, float flInterval ); + void UpdateOrientationBlend( TrainOrientationType_t eOrientationType, CPathTrack *pPrev, CPathTrack *pNext, const Vector &nextPos, float flInterval ); + void DoUpdateOrientation( const QAngle &curAngles, const QAngle &angles, float flInterval ); + + void TeleportToPathTrack( CPathTrack *pTeleport ); + + + Vector m_controlMins; + Vector m_controlMaxs; + Vector m_lastBlockPos; // These are used to build a heuristic decision about being temporarily blocked by physics objects + int m_lastBlockTick; // ^^^^^^^ + float m_flVolume; + float m_flBank; + float m_oldSpeed; + float m_flBlockDamage; // Damage to inflict when blocked. + float m_height; + float m_maxSpeed; + float m_dir; + + + string_t m_iszSoundMove; // Looping sound to play while moving. Pitch shifted based on speed. + string_t m_iszSoundMovePing; // Ping sound to play while moving. Interval decreased based on speed. + string_t m_iszSoundStart; // Sound to play when starting to move. + string_t m_iszSoundStop; // Sound to play when stopping. + + float m_flMoveSoundMinTime; // The most often to play the move 'ping' sound (used at max speed) + float m_flMoveSoundMaxTime; // The least often to play the move 'ping' sound (used approaching zero speed) + float m_flNextMoveSoundTime; + + int m_nMoveSoundMinPitch; // The sound pitch to approach as we come to a stop + int m_nMoveSoundMaxPitch; // The sound pitch to approach as we approach our max speed (actually, it's hardcoded to 1000 in/sec) + + TrainOrientationType_t m_eOrientationType; + TrainVelocityType_t m_eVelocityType; + bool m_bSoundPlaying; + + COutputEvent m_OnStart,m_OnNext; + + bool m_bManualSpeedChanges; // set when we want to send entity IO to govern speed and obey our TrainVelocityType_t + float m_flDesiredSpeed; // target speed, when m_bManualSpeedChanges is set + float m_flSpeedChangeTime; + float m_flAccelSpeed; + float m_flDecelSpeed; + bool m_bAccelToSpeed; + + float m_flNextMPSoundTime; + + float m_flSpeedForwardModifier; + float m_flUnmodifiedDesiredSpeed; + + bool m_bDamageChild; +}; + + +#endif // TRAINS_H diff --git a/game/server/trigger_area_capture.h b/game/server/trigger_area_capture.h new file mode 100644 index 0000000..90e0ed0 --- /dev/null +++ b/game/server/trigger_area_capture.h @@ -0,0 +1,190 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TRIGGER_AREA_CAPTURE_H +#define TRIGGER_AREA_CAPTURE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basemultiplayerplayer.h" +#include "triggers.h" +#include "team_control_point.h" + +class CTeamTrainWatcher; + +#define AREA_ATTEND_TIME 0.7f + +#define AREA_THINK_TIME 0.1f + +#define CAPTURE_NORMAL 0 +#define CAPTURE_CATCHUP_ALIVEPLAYERS 1 + +#define MAX_CLIENT_AREAS 128 +#define MAX_AREA_CAPPERS 9 + +//----------------------------------------------------------------------------- +// Purpose: An area entity that players must remain in in order to active another entity +// Triggers are fired on start of capture, on end of capture and on broken capture +// Can either be capped by both teams at once, or just by one +// Time to capture and number of people required to capture are both passed by the mapper +//----------------------------------------------------------------------------- +// This class is to get around the fact that DEFINE_FUNCTION doesn't like multiple inheritance +class CTriggerAreaCaptureShim : public CBaseTrigger +{ + virtual void AreaTouch( CBaseEntity *pOther ) = 0; +public: + void Touch( CBaseEntity *pOther ) { return AreaTouch( pOther ) ; } +}; + +DECLARE_AUTO_LIST( ITriggerAreaCaptureAutoList ); + +class CTriggerAreaCapture : public CTriggerAreaCaptureShim, public ITriggerAreaCaptureAutoList +{ + DECLARE_CLASS( CTriggerAreaCapture, CTriggerAreaCaptureShim ); +public: + CTriggerAreaCapture(); + + // Derived, game-specific area triggers must override these functions +public: + // Display a hint about capturing zones to the player + virtual void DisplayCapHintTo( CBaseMultiplayerPlayer *pPlayer ) { return; } + + // A team has finished capturing the zone. + virtual void OnEndCapture( int iTeam ) { return; } + virtual void OnStartCapture( int iTeam ) { return; } + +public: + virtual void Spawn( void ); + virtual void Precache( void ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + bool IsActive( void ); + bool CheckIfDeathCausesBlock( CBaseMultiplayerPlayer *pVictim, CBaseMultiplayerPlayer *pKiller ); + + void UpdateNumPlayers( bool bBlocked = false ); + void UpdateOwningTeam( void ); + void UpdateCappingTeam( int iTeam ); + void UpdateTeamInZone( void ); + void UpdateBlocked( void ); + + void ForceOwner( int team ); // by the control_point_round to force an owner of this point (so we can play a specific round) + + bool TeamCanCap( int iTeam ){ return m_TeamData[iTeam].bCanCap; } + CHandle GetControlPoint( void ){ return m_hPoint; } + + int GetOwningTeam( void ) { return m_nOwningTeam; } + + bool IsBlocked( void ) { return m_bBlocked; } + + void SetTrainWatcher( CTeamTrainWatcher *pTrainWatcher ){ m_hTrainWatcher = pTrainWatcher; } // used for train watchers that control train movement + CTeamTrainWatcher *GetTrainWatcher( void ) const { return m_hTrainWatcher; } + + virtual void StartTouch(CBaseEntity *pOther) OVERRIDE; + virtual void EndTouch(CBaseEntity *pOther) OVERRIDE; + + float GetCapTime() const { return m_flCapTime; } + +protected: + + virtual bool CaptureModeScalesWithPlayers() const; + +private: + virtual void AreaTouch( CBaseEntity *pOther ) OVERRIDE; + void CaptureThink( void ); + + void StartCapture( int team, int capmode ); + void EndCapture( int team ); + void BreakCapture( bool bNotEnoughPlayers ); + void IncrementCapAttemptNumber( void ); + void SwitchCapture( int team ); + void SendNumPlayers( void ); + + void SetOwner( int team ); //sets the owner of this point - useful for resetting all to -1 + + void InputRoundSpawn( inputdata_t &inputdata ); + void InputCaptureCurrentCP( inputdata_t &inputdata ); + void InputSetTeamCanCap( inputdata_t &inputdata ); + void InputSetControlPoint( inputdata_t &inputdata ); + + void SetCapTimeRemaining( float flTime ); + + void HandleRespawnTimeAdjustments( int oldTeam, int newTeam ); + void GetNumCappingPlayers( int team, int &numcappers, int *cappingplayers ); + + void SetNumCappers( int nNumCappers, bool bBlocked = false ); + +private: + int m_iCapMode; //which capture mode we're in + bool m_bCapturing; + int m_nCapturingTeam; //the team that is capturing this point + int m_nOwningTeam; //the team that has captured this point + int m_nTeamInZone; //if there's one team in the zone, this is it. + float m_flCapTime; //the total time it takes to capture the area, in seconds + float m_fTimeRemaining; //the time left in the capture + float m_flLastReductionTime; + bool m_bBlocked; + + struct perteamdata_t + { + perteamdata_t() + { + iNumRequiredToCap = 0; + iNumTouching = 0; + iBlockedTouching = 0; + bCanCap = false; + iSpawnAdjust = 0; + iNumRequiredToStartCap = 0; + } + + int iNumRequiredToCap; + int iNumTouching; + int iBlockedTouching; // Number of capping players on the cap while it's being blocked + bool bCanCap; + int iSpawnAdjust; + int iNumRequiredToStartCap; + }; + CUtlVector m_TeamData; + + struct blockers_t + { + CHandle hPlayer; + int iCapAttemptNumber; + float flNextBlockTime; + }; + CUtlVector m_Blockers; + + bool m_bActive; + + COutputEvent m_OnStartTeam1; + COutputEvent m_OnStartTeam2; + COutputEvent m_OnBreakTeam1; + COutputEvent m_OnBreakTeam2; + COutputEvent m_OnCapTeam1; + COutputEvent m_OnCapTeam2; + + COutputEvent m_StartOutput; + COutputEvent m_BreakOutput; + COutputEvent m_CapOutput; + + COutputInt m_OnNumCappersChanged; + COutputInt m_OnNumCappersChanged2; + + CHandle m_hPoint; //the capture point that we are linked to! + + bool m_bRequiresObject; + + string_t m_iszCapPointName; //name of the cap point that we're linked to + + int m_iCapAttemptNumber; // number used to keep track of discrete cap attempts, for block tracking + bool m_bStartTouch; + + CHandle m_hTrainWatcher; // used for train watchers that control train movement + + DECLARE_DATADESC(); +}; + +#endif // TRIGGER_AREA_CAPTURE_H diff --git a/game/server/triggers.h b/game/server/triggers.h new file mode 100644 index 0000000..6ae7312 --- /dev/null +++ b/game/server/triggers.h @@ -0,0 +1,228 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TRIGGERS_H +#define TRIGGERS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetoggle.h" +#include "entityoutput.h" + +// +// Spawnflags +// + +enum +{ + SF_TRIGGER_ALLOW_CLIENTS = 0x01, // Players can fire this trigger + SF_TRIGGER_ALLOW_NPCS = 0x02, // NPCS can fire this trigger + SF_TRIGGER_ALLOW_PUSHABLES = 0x04, // Pushables can fire this trigger + SF_TRIGGER_ALLOW_PHYSICS = 0x08, // Physics objects can fire this trigger + SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS = 0x10, // *if* NPCs can fire this trigger, this flag means only player allies do so + SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES = 0x20, // *if* Players can fire this trigger, this flag means only players inside vehicles can + SF_TRIGGER_ALLOW_ALL = 0x40, // Everything can fire this trigger EXCEPT DEBRIS! + SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES = 0x200, // *if* Players can fire this trigger, this flag means only players outside vehicles can + SF_TRIG_PUSH_ONCE = 0x80, // trigger_push removes itself after firing once + SF_TRIG_PUSH_AFFECT_PLAYER_ON_LADDER = 0x100, // if pushed object is player on a ladder, then this disengages them from the ladder (HL2only) + SF_TRIG_TOUCH_DEBRIS = 0x400, // Will touch physics debris objects + SF_TRIGGER_ONLY_NPCS_IN_VEHICLES = 0X800, // *if* NPCs can fire this trigger, only NPCs in vehicles do so (respects player ally flag too) + SF_TRIGGER_DISALLOW_BOTS = 0x1000, // Bots are not allowed to fire this trigger +}; + +// DVS TODO: get rid of CBaseToggle +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CBaseTrigger : public CBaseToggle +{ + DECLARE_CLASS( CBaseTrigger, CBaseToggle ); +public: + CBaseTrigger(); + + void Activate( void ); + virtual void PostClientActive( void ); + void InitTrigger( void ); + + void Enable( void ); + void Disable( void ); + void Spawn( void ); + void UpdateOnRemove( void ); + void TouchTest( void ); + + // Input handlers + virtual void InputEnable( inputdata_t &inputdata ); + virtual void InputDisable( inputdata_t &inputdata ); + virtual void InputToggle( inputdata_t &inputdata ); + virtual void InputTouchTest ( inputdata_t &inputdata ); + + virtual void InputStartTouch( inputdata_t &inputdata ); + virtual void InputEndTouch( inputdata_t &inputdata ); + + virtual bool UsesFilter( void ){ return ( m_hFilter.Get() != NULL ); } + virtual bool PassesTriggerFilters(CBaseEntity *pOther); + virtual void StartTouch(CBaseEntity *pOther); + virtual void EndTouch(CBaseEntity *pOther); + virtual void StartTouchAll() {} + virtual void EndTouchAll() {} + bool IsTouching( CBaseEntity *pOther ); + + CBaseEntity *GetTouchedEntityOfType( const char *sClassName ); + + int DrawDebugTextOverlays(void); + + // by default, triggers don't deal with TraceAttack + void TraceAttack(CBaseEntity *pAttacker, float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType) {} + + bool PointIsWithin( const Vector &vecPoint ); + + bool m_bDisabled; + string_t m_iFilterName; + CHandle m_hFilter; + +protected: + + // Outputs + COutputEvent m_OnStartTouch; + COutputEvent m_OnStartTouchAll; + COutputEvent m_OnEndTouch; + COutputEvent m_OnEndTouchAll; + COutputEvent m_OnTouching; + COutputEvent m_OnNotTouching; + + // Entities currently being touched by this trigger + CUtlVector< EHANDLE > m_hTouchingEntities; + + DECLARE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: Variable sized repeatable trigger. Must be targeted at one or more entities. +// If "delay" is set, the trigger waits some time after activating before firing. +// "wait" : Seconds between triggerings. (.2 default/minimum) +//----------------------------------------------------------------------------- +class CTriggerMultiple : public CBaseTrigger +{ + DECLARE_CLASS( CTriggerMultiple, CBaseTrigger ); +public: + void Spawn( void ); + void MultiTouch( CBaseEntity *pOther ); + void MultiWaitOver( void ); + void ActivateMultiTrigger(CBaseEntity *pActivator); + + DECLARE_DATADESC(); + + // Outputs + COutputEvent m_OnTrigger; +}; + +// Global list of triggers that care about weapon fire +extern CUtlVector< CHandle > g_hWeaponFireTriggers; + + +//------------------------------------------------------------------------------ +// Base VPhysics trigger implementation +// NOTE: This uses vphysics to compute touch events. It doesn't do a per-frame Touch call, so the +// Entity I/O is different from a regular trigger +//------------------------------------------------------------------------------ +#define SF_VPHYSICS_MOTION_MOVEABLE 0x1000 + +class CBaseVPhysicsTrigger : public CBaseEntity +{ + DECLARE_CLASS( CBaseVPhysicsTrigger , CBaseEntity ); + +public: + DECLARE_DATADESC(); + + virtual void Spawn(); + virtual void UpdateOnRemove(); + virtual bool CreateVPhysics(); + virtual void Activate( void ); + virtual bool PassesTriggerFilters(CBaseEntity *pOther); + + // UNDONE: Pass trigger event in or change Start/EndTouch. Add ITriggerVPhysics perhaps? + // BUGBUG: If a player touches two of these, his movement will screw up. + // BUGBUG: If a player uses crouch/uncrouch it will generate touch events and clear the motioncontroller flag + virtual void StartTouch( CBaseEntity *pOther ); + virtual void EndTouch( CBaseEntity *pOther ); + + void InputToggle( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + +protected: + bool m_bDisabled; + string_t m_iFilterName; + CHandle m_hFilter; +}; + +//----------------------------------------------------------------------------- +// Purpose: Hurts anything that touches it. If the trigger has a targetname, +// firing it will toggle state. +//----------------------------------------------------------------------------- + +// This class is to get around the fact that DEFINE_FUNCTION doesn't like multiple inheritance +class CTriggerHurtShim : public CBaseTrigger +{ + virtual void RadiationThink( void ) = 0; + virtual void HurtThink( void ) = 0; + +public: + + void RadiationThinkShim( void ){ RadiationThink(); } + void HurtThinkShim( void ){ HurtThink(); } +}; + +DECLARE_AUTO_LIST( ITriggerHurtAutoList ); +class CTriggerHurt : public CTriggerHurtShim, public ITriggerHurtAutoList +{ +public: + CTriggerHurt() + { + // This field came along after levels were built so the field defaults to 20 here in the constructor. + m_flDamageCap = 20.0f; + } + + DECLARE_CLASS( CTriggerHurt, CTriggerHurtShim ); + + void Spawn( void ); + void RadiationThink( void ); + void HurtThink( void ); + void Touch( CBaseEntity *pOther ); + void EndTouch( CBaseEntity *pOther ); + bool HurtEntity( CBaseEntity *pOther, float damage ); + int HurtAllTouchers( float dt ); + + DECLARE_DATADESC(); + + float m_flOriginalDamage; // Damage as specified by the level designer. + float m_flDamage; // Damage per second. + float m_flDamageCap; // Maximum damage per second. + float m_flLastDmgTime; // Time that we last applied damage. + float m_flDmgResetTime; // For forgiveness, the time to reset the counter that accumulates damage. + int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does + int m_damageModel; + bool m_bNoDmgForce; // Should damage from this trigger impart force on what it's hurting + + enum + { + DAMAGEMODEL_NORMAL = 0, + DAMAGEMODEL_DOUBLE_FORGIVENESS, + }; + + // Outputs + COutputEvent m_OnHurt; + COutputEvent m_OnHurtPlayer; + + CUtlVector m_hurtEntities; +}; + +bool IsTakingTriggerHurtDamageAtPoint( const Vector &vecPoint ); + +#endif // TRIGGERS_H diff --git a/game/server/util.h b/game/server/util.h new file mode 100644 index 0000000..c06cbfe --- /dev/null +++ b/game/server/util.h @@ -0,0 +1,636 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Misc utility code. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTIL_H +#define UTIL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_activity.h" +#include "steam/steam_gameserver.h" +#include "enginecallback.h" +#include "basetypes.h" +#include "tempentity.h" +#include "string_t.h" +#include "gamestringpool.h" +#include "engine/IEngineTrace.h" +#include "worldsize.h" +#include "dt_send.h" +#include "server_class.h" +#include "shake.h" + +#include "vstdlib/random.h" +#include + +#include "utlvector.h" +#include "util_shared.h" +#include "shareddefs.h" +#include "networkvar.h" + +struct levellist_t; +class IServerNetworkable; +class IEntityFactory; + +#ifdef _WIN32 + #define SETUP_EXTERNC(mapClassName)\ + extern "C" _declspec( dllexport ) IServerNetworkable* mapClassName( void ); +#else + #define SETUP_EXTERNC(mapClassName) +#endif + +// +// How did I ever live without ASSERT? +// +#ifdef DEBUG +void DBG_AssertFunction(bool fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage); +#define ASSERT(f) DBG_AssertFunction((bool)((f)!=0), #f, __FILE__, __LINE__, NULL) +#define ASSERTSZ(f, sz) DBG_AssertFunction((bool)((f)!=0), #f, __FILE__, __LINE__, sz) +#else // !DEBUG +#define ASSERT(f) +#define ASSERTSZ(f, sz) +#endif // !DEBUG + +#include "tier0/memdbgon.h" + +// entity creation +// creates an entity that has not been linked to a classname +template< class T > +T *_CreateEntityTemplate( T *newEnt, const char *className ) +{ + newEnt = new T; // this is the only place 'new' should be used! + newEnt->PostConstructor( className ); + return newEnt; +} + +#include "tier0/memdbgoff.h" + +CBaseEntity *CreateEntityByName( const char *className, int iForceEdictIndex ); + +// creates an entity by name, and ensure it's correctness +// does not spawn the entity +// use the CREATE_ENTITY() macro which wraps this, instead of using it directly +template< class T > +T *_CreateEntity( T *newClass, const char *className ) +{ + T *newEnt = dynamic_cast( CreateEntityByName(className, -1) ); + if ( !newEnt ) + { + Warning( "classname %s used to create wrong class type\n", className ); + Assert(0); + } + + return newEnt; +} + +#define CREATE_ENTITY( newClass, className ) _CreateEntity( (newClass*)NULL, className ) +#define CREATE_UNSAVED_ENTITY( newClass, className ) _CreateEntityTemplate( (newClass*)NULL, className ) + + +// This is the glue that hooks .MAP entity class names to our CPP classes +abstract_class IEntityFactoryDictionary +{ +public: + virtual void InstallFactory( IEntityFactory *pFactory, const char *pClassName ) = 0; + virtual IServerNetworkable *Create( const char *pClassName ) = 0; + virtual void Destroy( const char *pClassName, IServerNetworkable *pNetworkable ) = 0; + virtual IEntityFactory *FindFactory( const char *pClassName ) = 0; + virtual const char *GetCannonicalName( const char *pClassName ) = 0; +}; + +IEntityFactoryDictionary *EntityFactoryDictionary(); + +inline bool CanCreateEntityClass( const char *pszClassname ) +{ + return ( EntityFactoryDictionary() != NULL && EntityFactoryDictionary()->FindFactory( pszClassname ) != NULL ); +} + +abstract_class IEntityFactory +{ +public: + virtual IServerNetworkable *Create( const char *pClassName ) = 0; + virtual void Destroy( IServerNetworkable *pNetworkable ) = 0; + virtual size_t GetEntitySize() = 0; +}; + +template +class CEntityFactory : public IEntityFactory +{ +public: + CEntityFactory( const char *pClassName ) + { + EntityFactoryDictionary()->InstallFactory( this, pClassName ); + } + + IServerNetworkable *Create( const char *pClassName ) + { + T* pEnt = _CreateEntityTemplate((T*)NULL, pClassName); + return pEnt->NetworkProp(); + } + + void Destroy( IServerNetworkable *pNetworkable ) + { + if ( pNetworkable ) + { + pNetworkable->Release(); + } + } + + virtual size_t GetEntitySize() + { + return sizeof(T); + } +}; + +#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ + static CEntityFactory mapClassName( #mapClassName ); + + +// +// Conversion among the three types of "entity", including identity-conversions. +// +inline int ENTINDEX( edict_t *pEdict) +{ + int nResult = pEdict ? pEdict->m_EdictIndex : 0; + Assert( nResult == engine->IndexOfEdict(pEdict) ); + return nResult; +} + +int ENTINDEX( CBaseEntity *pEnt ); + +inline edict_t* INDEXENT( int iEdictNum ) +{ + return engine->PEntityOfEntIndex(iEdictNum); +} + +// Testing the three types of "entity" for nullity +inline bool FNullEnt(const edict_t* pent) +{ + return pent == NULL || ENTINDEX((edict_t*)pent) == 0; +} + +// Dot products for view cone checking +#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees +#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks +#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks +#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks + +class CBaseEntity; +class CBasePlayer; + +extern CGlobalVars *gpGlobals; + +// Misc useful +inline bool FStrEq(const char *sz1, const char *sz2) +{ + return ( sz1 == sz2 || V_stricmp(sz1, sz2) == 0 ); +} + +#if 0 +// UNDONE: Remove/alter MAKE_STRING so we can do this? +inline bool FStrEq( string_t str1, string_t str2 ) +{ + // now that these are pooled, we can compare them with + // integer equality + return str1 == str2; +} +#endif + +const char *nexttoken(char *token, const char *str, char sep); + +// Misc. Prototypes +void UTIL_SetSize (CBaseEntity *pEnt, const Vector &vecMin, const Vector &vecMax); +void UTIL_ClearTrace ( trace_t &trace ); +void UTIL_SetTrace (trace_t& tr, const Ray_t &ray, edict_t* edict, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept ); + +int UTIL_PrecacheDecal ( const char *name, bool preload = false ); + +//----------------------------------------------------------------------------- + +float UTIL_GetSimulationInterval(); + +//----------------------------------------------------------------------------- +// Purpose: Gets a player pointer by 1-based index +// If player is not yet spawned or connected, returns NULL +// Input : playerIndex - index of the player - first player is index 1 +//----------------------------------------------------------------------------- + +// NOTENOTE: Use UTIL_GetLocalPlayer instead of UTIL_PlayerByIndex IF you're in single player +// and you want the player. +CBasePlayer *UTIL_PlayerByIndex( int playerIndex ); +CBasePlayer *UTIL_PlayerBySteamID( const CSteamID &steamID ); + +// NOTENOTE: Use this instead of UTIL_PlayerByIndex IF you're in single player +// and you want the player. +// not useable in multiplayer - see UTIL_GetListenServerHost() +CBasePlayer* UTIL_GetLocalPlayer( void ); + +// get the local player on a listen server +CBasePlayer *UTIL_GetListenServerHost( void ); + +CBasePlayer* UTIL_PlayerByUserId( int userID ); +CBasePlayer* UTIL_PlayerByName( const char *name ); // not case sensitive + +// Returns true if the command was issued by the listenserver host, or by the dedicated server, via rcon or the server console. +// This is valid during ConCommand execution. +bool UTIL_IsCommandIssuedByServerAdmin( void ); + +CBaseEntity* UTIL_EntityByIndex( int entityIndex ); + +void UTIL_GetPlayerConnectionInfo( int playerIndex, int& ping, int &packetloss ); + +void UTIL_SetClientVisibilityPVS( edict_t *pClient, const unsigned char *pvs, int pvssize ); +bool UTIL_ClientPVSIsExpanded(); + +edict_t *UTIL_FindClientInPVS( edict_t *pEdict ); +edict_t *UTIL_FindClientInVisibilityPVS( edict_t *pEdict ); + +// This is a version which finds any clients whose PVS intersects the box +CBaseEntity *UTIL_FindClientInPVS( const Vector &vecBoxMins, const Vector &vecBoxMaxs ); + +CBaseEntity *UTIL_EntitiesInPVS( CBaseEntity *pPVSEntity, CBaseEntity *pStartingEntity ); + +//----------------------------------------------------------------------------- +// class CFlaggedEntitiesEnum +//----------------------------------------------------------------------------- +// enumerate entities that match a set of edict flags into a static array +class CFlaggedEntitiesEnum : public IPartitionEnumerator +{ +public: + CFlaggedEntitiesEnum( CBaseEntity **pList, int listMax, int flagMask ); + + // This gets called by the enumeration methods with each element + // that passes the test. + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + + int GetCount() { return m_count; } + bool AddToList( CBaseEntity *pEntity ); + +private: + CBaseEntity **m_pList; + int m_listMax; + int m_flagMask; + int m_count; +}; + +// Pass in an array of pointers and an array size, it fills the array and returns the number inserted +int UTIL_EntitiesInBox( const Vector &mins, const Vector &maxs, CFlaggedEntitiesEnum *pEnum ); +int UTIL_EntitiesAlongRay( const Ray_t &ray, CFlaggedEntitiesEnum *pEnum ); +int UTIL_EntitiesInSphere( const Vector ¢er, float radius, CFlaggedEntitiesEnum *pEnum ); + +inline int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ) +{ + CFlaggedEntitiesEnum boxEnum( pList, listMax, flagMask ); + return UTIL_EntitiesInBox( mins, maxs, &boxEnum ); +} + +inline int UTIL_EntitiesAlongRay( CBaseEntity **pList, int listMax, const Ray_t &ray, int flagMask ) +{ + CFlaggedEntitiesEnum rayEnum( pList, listMax, flagMask ); + return UTIL_EntitiesAlongRay( ray, &rayEnum ); +} + +inline int UTIL_EntitiesInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius, int flagMask ) +{ + CFlaggedEntitiesEnum sphereEnum( pList, listMax, flagMask ); + return UTIL_EntitiesInSphere( center, radius, &sphereEnum ); +} + +// marks the entity for deletion so it will get removed next frame +void UTIL_Remove( IServerNetworkable *oldObj ); +void UTIL_Remove( CBaseEntity *oldObj ); + +// deletes an entity, without any delay. Only use this when sure no pointers rely on this entity. +void UTIL_DisableRemoveImmediate(); +void UTIL_EnableRemoveImmediate(); +void UTIL_RemoveImmediate( CBaseEntity *oldObj ); + +// make this a fixed size so it just sits on the stack +#define MAX_SPHERE_QUERY 512 +class CEntitySphereQuery +{ +public: + // currently this builds the list in the constructor + // UNDONE: make an iterative query of ISpatialPartition so we could + // make queries like this optimal + CEntitySphereQuery( const Vector ¢er, float radius, int flagMask=0 ); + CBaseEntity *GetCurrentEntity(); + inline void NextEntity() { m_listIndex++; } + +private: + int m_listIndex; + int m_listCount; + CBaseEntity *m_pList[MAX_SPHERE_QUERY]; +}; + +enum soundlevel_t; + +// Drops an entity onto the floor +int UTIL_DropToFloor( CBaseEntity *pEntity, unsigned int mask, CBaseEntity *pIgnore = NULL ); + +// Returns false if any part of the bottom of the entity is off an edge that is not a staircase. +bool UTIL_CheckBottom( CBaseEntity *pEntity, ITraceFilter *pTraceFilter, float flStepSize ); + +void UTIL_SetOrigin ( CBaseEntity *entity, const Vector &vecOrigin, bool bFireTriggers = false ); +void UTIL_EmitAmbientSound ( int entindex, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float soundtime = 0.0f, float *duration = NULL ); +void UTIL_ParticleEffect ( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ); +void UTIL_ScreenShake ( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake=false ); +void UTIL_ScreenShakeObject ( CBaseEntity *pEnt, const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake=false ); +void UTIL_ViewPunch ( const Vector ¢er, QAngle angPunch, float radius, bool bInAir ); +void UTIL_ShowMessage ( const char *pString, CBasePlayer *pPlayer ); +void UTIL_ShowMessageAll ( const char *pString ); +void UTIL_ScreenFadeAll ( const color32 &color, float fadeTime, float holdTime, int flags ); +void UTIL_ScreenFade ( CBaseEntity *pEntity, const color32 &color, float fadeTime, float fadeHold, int flags ); +void UTIL_MuzzleFlash ( const Vector &origin, const QAngle &angles, int scale, int type ); +Vector UTIL_PointOnLineNearestPoint(const Vector& vStartPos, const Vector& vEndPos, const Vector& vPoint, bool clampEnds = false ); + +int UTIL_EntityInSolid( CBaseEntity *ent ); + +bool UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator); +void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ); +void UTIL_BloodSpray( const Vector &pos, const Vector &dir, int color, int amount, int flags ); +Vector UTIL_RandomBloodVector( void ); +void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName = NULL ); +void UTIL_PlayerDecalTrace( trace_t *pTrace, int playernum ); +void UTIL_Smoke( const Vector &origin, const float scale, const float framerate ); +void UTIL_AxisStringToPointDir( Vector &start, Vector &dir, const char *pString ); +void UTIL_AxisStringToPointPoint( Vector &start, Vector &end, const char *pString ); +void UTIL_AxisStringToUnitDir( Vector &dir, const char *pString ); +void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip ); +void UTIL_PredictedPosition( CBaseEntity *pTarget, float flTimeDelta, Vector *vecPredictedPosition ); +void UTIL_Beam( Vector &Start, Vector &End, int nModelIndex, int nHaloIndex, unsigned char FrameStart, unsigned char FrameRate, + float Life, unsigned char Width, unsigned char EndWidth, unsigned char FadeLength, unsigned char Noise, unsigned char Red, unsigned char Green, + unsigned char Blue, unsigned char Brightness, unsigned char Speed); + +const char *UTIL_VarArgs( PRINTF_FORMAT_STRING const char *format, ... ) FMTFUNCTION( 1, 2 ); +bool UTIL_IsValidEntity( CBaseEntity *pEnt ); +bool UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ); + +// snaps a vector to the nearest axis vector (if within epsilon) +void UTIL_SnapDirectionToAxis( Vector &direction, float epsilon = 0.002f ); + +//Set the entity to point at the target specified +bool UTIL_PointAtEntity( CBaseEntity *pEnt, CBaseEntity *pTarget ); +void UTIL_PointAtNamedEntity( CBaseEntity *pEnt, string_t strTarget ); + +// Copy the pose parameter values from one entity to the other +bool UTIL_TransferPoseParameters( CBaseEntity *pSourceEntity, CBaseEntity *pDestEntity ); + +// Search for water transition along a vertical line +float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); + +// Like UTIL_WaterLevel, but *way* less expensive. +// I didn't replace UTIL_WaterLevel everywhere to avoid breaking anything. +float UTIL_FindWaterSurface( const Vector &position, float minz, float maxz ); + +void UTIL_Bubbles( const Vector& mins, const Vector& maxs, int count ); +void UTIL_BubbleTrail( const Vector& from, const Vector& to, int count ); + +// allows precacheing of other entities +void UTIL_PrecacheOther( const char *szClassname, const char *modelName = NULL ); + +// prints a message to each client +void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); +inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ) +{ + UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); +} + +void UTIL_ValidateSoundName( string_t &name, const char *defaultStr ); + +void UTIL_ClientPrintFilter( IRecipientFilter& filter, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); + +// prints messages through the HUD +void ClientPrint( CBasePlayer *player, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); + +// prints a message to the HUD say (chat) +void UTIL_SayText( const char *pText, CBasePlayer *pEntity ); +void UTIL_SayTextAll( const char *pText, CBasePlayer *pEntity = NULL, bool bChat = false ); +void UTIL_SayTextFilter( IRecipientFilter& filter, const char *pText, CBasePlayer *pEntity, bool bChat ); +void UTIL_SayText2Filter( IRecipientFilter& filter, CBasePlayer *pEntity, bool bChat, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); + +byte *UTIL_LoadFileForMe( const char *filename, int *pLength ); +void UTIL_FreeFile( byte *buffer ); + +class CGameTrace; +typedef CGameTrace trace_t; + +//----------------------------------------------------------------------------- +// These are inlined for backwards compatibility +//----------------------------------------------------------------------------- +inline float UTIL_Approach( float target, float value, float speed ) +{ + return Approach( target, value, speed ); +} + +inline float UTIL_ApproachAngle( float target, float value, float speed ) +{ + return ApproachAngle( target, value, speed ); +} + +inline float UTIL_AngleDistance( float next, float cur ) +{ + return AngleDistance( next, cur ); +} + +inline float UTIL_AngleMod(float a) +{ + return anglemod(a); +} + +inline float UTIL_AngleDiff( float destAngle, float srcAngle ) +{ + return AngleDiff( destAngle, srcAngle ); +} + +typedef struct hudtextparms_s +{ + float x; + float y; + int effect; + byte r1, g1, b1, a1; + byte r2, g2, b2, a2; + float fadeinTime; + float fadeoutTime; + float holdTime; + float fxTime; + int channel; +} hudtextparms_t; + + +//----------------------------------------------------------------------------- +// Sets the model to be associated with an entity +//----------------------------------------------------------------------------- +void UTIL_SetModel( CBaseEntity *pEntity, const char *pModelName ); + + +// prints as transparent 'title' to the HUD +void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ); +void UTIL_HudMessage( CBasePlayer *pToPlayer, const hudtextparms_t &textparms, const char *pMessage ); + +// brings up hud keyboard hints display +void UTIL_HudHintText( CBaseEntity *pEntity, const char *pMessage ); + +// Writes message to console with timestamp and FragLog header. +void UTIL_LogPrintf( PRINTF_FORMAT_STRING const char *fmt, ... ) FMTFUNCTION( 1, 2 ); + +// Sorta like FInViewCone, but for nonNPCs. +float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); + +void UTIL_StripToken( const char *pKey, char *pDest );// for redundant keynames + +// Misc functions +int BuildChangeList( levellist_t *pLevelList, int maxList ); + +// computes gravity scale for an absolute gravity. Pass the result into CBaseEntity::SetGravity() +float UTIL_ScaleForGravity( float desiredGravity ); + + + +// +// Constants that were used only by QC (maybe not used at all now) +// +// Un-comment only as needed +// + +#include "globals.h" + +#define LFO_SQUARE 1 +#define LFO_TRIANGLE 2 +#define LFO_RANDOM 3 + +// func_rotating +#define SF_BRUSH_ROTATE_Y_AXIS 0 +#define SF_BRUSH_ROTATE_START_ON 1 +#define SF_BRUSH_ROTATE_BACKWARDS 2 +#define SF_BRUSH_ROTATE_Z_AXIS 4 +#define SF_BRUSH_ROTATE_X_AXIS 8 +#define SF_BRUSH_ROTATE_CLIENTSIDE 16 + + +#define SF_BRUSH_ROTATE_SMALLRADIUS 128 +#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 +#define SF_BRUSH_ROTATE_LARGERADIUS 512 + +#define PUSH_BLOCK_ONLY_X 1 +#define PUSH_BLOCK_ONLY_Y 2 + +#define SF_LIGHT_START_OFF 1 + +#define SPAWNFLAG_NOMESSAGE 1 +#define SPAWNFLAG_NOTOUCH 1 +#define SPAWNFLAG_DROIDONLY 4 + +#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons) + +#define TELE_PLAYER_ONLY 1 +#define TELE_SILENT 2 + +// Sound Utilities + +enum soundlevel_t; + +void SENTENCEG_Init(); +void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); +int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, soundlevel_t soundlevel, int flags, int pitch); +int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, soundlevel_t soundlevel, int flags, int pitch); +int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, soundlevel_t soundlevel, int flags, int pitch, int ipick, int freset); +void SENTENCEG_PlaySentenceIndex( edict_t *entity, int iSentenceIndex, float volume, soundlevel_t soundlevel, int flags, int pitch ); +int SENTENCEG_PickRndSz(const char *szrootname); +int SENTENCEG_GetIndex(const char *szrootname); +int SENTENCEG_Lookup(const char *sample); + +char TEXTURETYPE_Find( trace_t *ptr ); + +void UTIL_EmitSoundSuit(edict_t *entity, const char *sample); +int UTIL_EmitGroupIDSuit(edict_t *entity, int isentenceg); +int UTIL_EmitGroupnameSuit(edict_t *entity, const char *groupname); +void UTIL_RestartAmbientSounds( void ); + +class EntityMatrix : public VMatrix +{ +public: + void InitFromEntity( CBaseEntity *pEntity, int iAttachment=0 ); + void InitFromEntityLocal( CBaseEntity *entity ); + + inline Vector LocalToWorld( const Vector &vVec ) const + { + return VMul4x3( vVec ); + } + + inline Vector WorldToLocal( const Vector &vVec ) const + { + return VMul4x3Transpose( vVec ); + } + + inline Vector LocalToWorldRotation( const Vector &vVec ) const + { + return VMul3x3( vVec ); + } + + inline Vector WorldToLocalRotation( const Vector &vVec ) const + { + return VMul3x3Transpose( vVec ); + } +}; + +inline float UTIL_DistApprox( const Vector &vec1, const Vector &vec2 ); +inline float UTIL_DistApprox2D( const Vector &vec1, const Vector &vec2 ); + +//--------------------------------------------------------- +//--------------------------------------------------------- +inline float UTIL_DistApprox( const Vector &vec1, const Vector &vec2 ) +{ + float dx; + float dy; + float dz; + + dx = vec1.x - vec2.x; + dy = vec1.y - vec2.y; + dz = vec1.z - vec2.z; + + return fabs(dx) + fabs(dy) + fabs(dz); +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +inline float UTIL_DistApprox2D( const Vector &vec1, const Vector &vec2 ) +{ + float dx; + float dy; + + dx = vec1.x - vec2.x; + dy = vec1.y - vec2.y; + + return fabs(dx) + fabs(dy); +} + +// Find out if an entity is facing another entity or position within a given tolerance range +bool UTIL_IsFacingWithinTolerance( CBaseEntity *pViewer, const Vector &vecPosition, float flDotTolerance, float *pflDot = NULL ); +bool UTIL_IsFacingWithinTolerance( CBaseEntity *pViewer, CBaseEntity *pTarget, float flDotTolerance, float *pflDot = NULL ); + +void UTIL_GetDebugColorForRelationship( int nRelationship, int &r, int &g, int &b ); + +struct datamap_t; +extern const char *UTIL_FunctionToName( datamap_t *pMap, inputfunc_t *function ); + +int UTIL_GetCommandClientIndex( void ); +CBasePlayer *UTIL_GetCommandClient( void ); +bool UTIL_GetModDir( char *lpszTextOut, unsigned int nSize ); + +AngularImpulse WorldToLocalRotation( const VMatrix &localToWorld, const Vector &worldAxis, float rotation ); +void UTIL_WorldToParentSpace( CBaseEntity *pEntity, Vector &vecPosition, QAngle &vecAngles ); +void UTIL_WorldToParentSpace( CBaseEntity *pEntity, Vector &vecPosition, Quaternion &quat ); +void UTIL_ParentToWorldSpace( CBaseEntity *pEntity, Vector &vecPosition, QAngle &vecAngles ); +void UTIL_ParentToWorldSpace( CBaseEntity *pEntity, Vector &vecPosition, Quaternion &quat ); + +bool UTIL_LoadAndSpawnEntitiesFromScript( CUtlVector &entities, const char *pScriptFile, const char *pBlock, bool bActivate = true ); + +// Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h +void UTIL_BoundToWorldSize( Vector *pVecPos ); + +#endif // UTIL_H diff --git a/game/server/variant_t.h b/game/server/variant_t.h new file mode 100644 index 0000000..91b9420 --- /dev/null +++ b/game/server/variant_t.h @@ -0,0 +1,122 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VARIANT_T_H +#define VARIANT_T_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ehandle.h" +#include "mathlib/vmatrix.h" + +class CBaseEntity; + + +// +// A variant class for passing data in entity input/output connections. +// +class variant_t +{ + union + { + bool bVal; + string_t iszVal; + int iVal; + float flVal; + float vecVal[3]; + color32 rgbaVal; + }; + CHandle eVal; // this can't be in the union because it has a constructor. + + fieldtype_t fieldType; + +public: + + // constructor + variant_t() : iVal(0), fieldType(FIELD_VOID) {} + + inline bool Bool( void ) const { return( fieldType == FIELD_BOOLEAN ) ? bVal : false; } + inline const char *String( void ) const { return( fieldType == FIELD_STRING ) ? STRING(iszVal) : ToString(); } + inline string_t StringID( void ) const { return( fieldType == FIELD_STRING ) ? iszVal : NULL_STRING; } + inline int Int( void ) const { return( fieldType == FIELD_INTEGER ) ? iVal : 0; } + inline float Float( void ) const { return( fieldType == FIELD_FLOAT ) ? flVal : 0; } + inline const CHandle &Entity(void) const; + inline color32 Color32(void) const { return rgbaVal; } + inline void Vector3D(Vector &vec) const; + + fieldtype_t FieldType( void ) { return fieldType; } + + void SetBool( bool b ) { bVal = b; fieldType = FIELD_BOOLEAN; } + void SetString( string_t str ) { iszVal = str, fieldType = FIELD_STRING; } + void SetInt( int val ) { iVal = val, fieldType = FIELD_INTEGER; } + void SetFloat( float val ) { flVal = val, fieldType = FIELD_FLOAT; } + void SetEntity( CBaseEntity *val ); + void SetVector3D( const Vector &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_VECTOR; } + void SetPositionVector3D( const Vector &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_POSITION_VECTOR; } + void SetColor32( color32 val ) { rgbaVal = val; fieldType = FIELD_COLOR32; } + void SetColor32( int r, int g, int b, int a ) { rgbaVal.r = r; rgbaVal.g = g; rgbaVal.b = b; rgbaVal.a = a; fieldType = FIELD_COLOR32; } + void Set( fieldtype_t ftype, void *data ); + void SetOther( void *data ); + bool Convert( fieldtype_t newType ); + + static typedescription_t m_SaveBool[]; + static typedescription_t m_SaveInt[]; + static typedescription_t m_SaveFloat[]; + static typedescription_t m_SaveEHandle[]; + static typedescription_t m_SaveString[]; + static typedescription_t m_SaveColor[]; + static typedescription_t m_SaveVector[]; + static typedescription_t m_SavePositionVector[]; + static typedescription_t m_SaveVMatrix[]; + static typedescription_t m_SaveVMatrixWorldspace[]; + static typedescription_t m_SaveMatrix3x4Worldspace[]; + +protected: + + // + // Returns a string representation of the value without modifying the variant. + // + const char *ToString( void ) const; + + friend class CVariantSaveDataOps; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as a vector. +//----------------------------------------------------------------------------- +inline void variant_t::Vector3D(Vector &vec) const +{ + if (( fieldType == FIELD_VECTOR ) || ( fieldType == FIELD_POSITION_VECTOR )) + { + vec[0] = vecVal[0]; + vec[1] = vecVal[1]; + vec[2] = vecVal[2]; + } + else + { + vec = vec3_origin; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as an EHANDLE. +//----------------------------------------------------------------------------- +inline const CHandle &variant_t::Entity(void) const +{ + if ( fieldType == FIELD_EHANDLE ) + return eVal; + + static CHandle hNull; + hNull.Set(NULL); + return(hNull); +} + + +#endif // VARIANT_T_H diff --git a/game/server/vehicle_base.h b/game/server/vehicle_base.h new file mode 100644 index 0000000..ab63005 --- /dev/null +++ b/game/server/vehicle_base.h @@ -0,0 +1,313 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VEHICLE_BASE_H +#define VEHICLE_BASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vphysics/vehicles.h" +#include "iservervehicle.h" +#include "fourwheelvehiclephysics.h" +#include "props.h" +#include "vehicle_sounds.h" +#include "phys_controller.h" +#include "entityblocker.h" +#include "vehicle_baseserver.h" +#include "vehicle_viewblend_shared.h" + +class CNPC_VehicleDriver; +class CFourWheelVehiclePhysics; +class CPropVehicleDriveable; +class CSoundPatch; + +// the tires are considered to be skidding if they have sliding velocity of 10 in/s or more +const float DEFAULT_SKID_THRESHOLD = 10.0f; + +//----------------------------------------------------------------------------- +// Purpose: Four wheel physics vehicle server vehicle +//----------------------------------------------------------------------------- +class CFourWheelServerVehicle : public CBaseServerVehicle +{ + DECLARE_CLASS( CFourWheelServerVehicle, CBaseServerVehicle ); + +// IServerVehicle +public: + virtual ~CFourWheelServerVehicle( void ) + { + } + + CFourWheelServerVehicle( void ); + virtual bool IsVehicleUpright( void ); + virtual bool IsVehicleBodyInWater( void ); + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); + IPhysicsVehicleController *GetVehicleController(); + const vehicleparams_t *GetVehicleParams( void ); + const vehicle_controlparams_t *GetVehicleControlParams( void ); + const vehicle_operatingparams_t *GetVehicleOperatingParams( void ); + + // NPC Driving + void NPC_SetDriver( CNPC_VehicleDriver *pDriver ); + void NPC_DriveVehicle( void ); + + CPropVehicleDriveable *GetFourWheelVehicle( void ); + bool GetWheelContactPoint( int nWheelIndex, Vector &vecPos ); + +public: + virtual void SetVehicle( CBaseEntity *pVehicle ); + void InitViewSmoothing( const Vector &vecStartOrigin, const QAngle &vecStartAngles ); + bool IsPassengerEntering( void ); + bool IsPassengerExiting( void ); + + DECLARE_SIMPLE_DATADESC(); + +private: + CFourWheelVehiclePhysics *GetFourWheelVehiclePhysics( void ); + + ViewSmoothingData_t m_ViewSmoothing; +}; + +//----------------------------------------------------------------------------- +// Purpose: Base class for four wheel physics vehicles +//----------------------------------------------------------------------------- +class CPropVehicle : public CBaseProp, public CDefaultPlayerPickupVPhysics +{ + DECLARE_CLASS( CPropVehicle, CBaseProp ); +public: + CPropVehicle(); + virtual ~CPropVehicle(); + + void SetVehicleType( unsigned int nVehicleType ) { m_nVehicleType = nVehicleType; } + unsigned int GetVehicleType( void ) { return m_nVehicleType; } + + // CBaseEntity + void Spawn( void ); + virtual int Restore( IRestore &restore ); + void VPhysicsUpdate( IPhysicsObject *pPhysics ); + void DrawDebugGeometryOverlays(); + int DrawDebugTextOverlays(); + void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + virtual void Think( void ); + CFourWheelVehiclePhysics *GetPhysics( void ) { return &m_VehiclePhysics; } + CBasePlayer *HasPhysicsAttacker( float dt ); + void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + + Vector GetSmoothedVelocity( void ); //Save and update our smoothed velocity for prediction + + virtual void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ) {} + + // Inputs + void InputThrottle( inputdata_t &inputdata ); + void InputSteering( inputdata_t &inputdata ); + void InputAction( inputdata_t &inputdata ); + void InputHandBrakeOn( inputdata_t &inputdata ); + void InputHandBrakeOff( inputdata_t &inputdata ); + + DECLARE_DATADESC(); + +#ifdef HL2_EPISODIC + void AddPhysicsChild( CBaseEntity *pChild ); + void RemovePhysicsChild( CBaseEntity *pChild ); +#endif //HL2_EPISODIC + +protected: + // engine sounds + void SoundInit(); + void SoundShutdown(); + void SoundUpdate( const vehicle_operatingparams_t ¶ms, const vehicleparams_t &vehicle ); + void CalcWheelData( vehicleparams_t &vehicle ); + void ResetControls(); + + // Upright strength of the controller (angular limit) + virtual float GetUprightStrength( void ) { return 8.0f; } + virtual float GetUprightTime( void ) { return 5.0f; } + +protected: + CFourWheelVehiclePhysics m_VehiclePhysics; + unsigned int m_nVehicleType; + string_t m_vehicleScript; + +#ifdef HL2_EPISODIC + CUtlVector m_hPhysicsChildren; // List of entities who wish to get physics callbacks from the vehicle +#endif //HL2_EPISODIC + +private: + Vector m_vecSmoothedVelocity; + + CHandle m_hPhysicsAttacker; + + float m_flLastPhysicsInfluenceTime; +}; + +//============================================================================= +// NPC Passenger Carrier interface + +class INPCPassengerCarrier +{ +public: + virtual bool NPC_CanEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) = 0; + virtual bool NPC_CanExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) = 0; + virtual bool NPC_AddPassenger( CAI_BaseNPC *pPassenger, string_t strRoleName, int nSeatID ) = 0; + virtual bool NPC_RemovePassenger( CAI_BaseNPC *pPassenger ) = 0; + virtual void NPC_FinishedEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) = 0; + virtual void NPC_FinishedExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Drivable four wheel physics vehicles +//----------------------------------------------------------------------------- +class CPropVehicleDriveable : public CPropVehicle, public IDrivableVehicle, public INPCPassengerCarrier +{ + DECLARE_CLASS( CPropVehicleDriveable, CPropVehicle ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); +public: + CPropVehicleDriveable( void ); + ~CPropVehicleDriveable( void ); + + virtual void Precache( void ); + virtual void Spawn( void ); + virtual int Restore( IRestore &restore ); + virtual void OnRestore(); + virtual void CreateServerVehicle( void ); + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; }; + virtual void GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const; + virtual void VehicleAngleVectors( const QAngle &angles, Vector *pForward, Vector *pRight, Vector *pUp ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void Think( void ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ); + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + + // Vehicle handling + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); + virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + + // Inputs + void InputLock( inputdata_t &inputdata ); + void InputUnlock( inputdata_t &inputdata ); + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + + // Locals + void ResetUseKey( CBasePlayer *pPlayer ); + + // Driving + void DriveVehicle( CBasePlayer *pPlayer, CUserCmd *ucmd ); // Player driving entrypoint + virtual void DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased ); // Driving Button handling + + virtual bool IsOverturned( void ); + virtual bool IsVehicleBodyInWater( void ) { return false; } + + // Engine handling + void StartEngine( void ); + void StopEngine( void ); + bool IsEngineOn( void ); + +// IDrivableVehicle +public: + virtual CBaseEntity *GetDriver( void ); + virtual void ItemPostFrame( CBasePlayer *pPlayer ) { return; } + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ) { return; } + virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) { return; } + virtual bool CanEnterVehicle( CBaseEntity *pEntity ); + virtual bool CanExitVehicle( CBaseEntity *pEntity ); + virtual void SetVehicleEntryAnim( bool bOn ) { m_bEnterAnimOn = bOn; } + virtual void SetVehicleExitAnim( bool bOn, Vector vecEyeExitEndpoint ) { m_bExitAnimOn = bOn; if ( bOn ) m_vecEyeExitEndpoint = vecEyeExitEndpoint; } + virtual void EnterVehicle( CBaseCombatCharacter *pPassenger ); + + virtual bool AllowBlockedExit( CBaseCombatCharacter *pPassenger, int nRole ) { return true; } + virtual bool AllowMidairExit( CBaseCombatCharacter *pPassenger, int nRole ) { return false; } + virtual void PreExitVehicle( CBaseCombatCharacter *pPassenger, int nRole ) {} + virtual void ExitVehicle( int nRole ); + virtual string_t GetVehicleScriptName() { return m_vehicleScript; } + + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) { return true; } + + // If this is a vehicle, returns the vehicle interface + virtual IServerVehicle *GetServerVehicle() { return m_pServerVehicle; } + +protected: + + virtual bool ShouldThink() { return ( GetDriver() != NULL ); } + + inline bool HasGun(); + void DestroyServerVehicle(); + + // Contained IServerVehicle + CFourWheelServerVehicle *m_pServerVehicle; + + COutputEvent m_playerOn; + COutputEvent m_playerOff; + + COutputEvent m_pressedAttack; + COutputEvent m_pressedAttack2; + + COutputFloat m_attackaxis; + COutputFloat m_attack2axis; + + CNetworkHandle( CBasePlayer, m_hPlayer ); +public: + + CNetworkVar( int, m_nSpeed ); + CNetworkVar( int, m_nRPM ); + CNetworkVar( float, m_flThrottle ); + CNetworkVar( int, m_nBoostTimeLeft ); + CNetworkVar( int, m_nHasBoost ); + + CNetworkVector( m_vecEyeExitEndpoint ); + CNetworkVector( m_vecGunCrosshair ); + CNetworkVar( bool, m_bUnableToFire ); + CNetworkVar( bool, m_bHasGun ); + + CNetworkVar( bool, m_nScannerDisabledWeapons ); + CNetworkVar( bool, m_nScannerDisabledVehicle ); + + // NPC Driver + CHandle m_hNPCDriver; + EHANDLE m_hKeepUpright; + + // -------------------------------- + // NPC Passengers +public: + + virtual bool NPC_CanEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); + virtual bool NPC_CanExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); + virtual bool NPC_AddPassenger( CAI_BaseNPC *pPassenger, string_t strRoleName, int nSeatID ); + virtual bool NPC_RemovePassenger( CAI_BaseNPC *pPassenger ); + virtual void NPC_FinishedEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) {} + virtual void NPC_FinishedExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) {} + + // NPC Passengers + // -------------------------------- + + bool IsEnterAnimOn( void ) { return m_bEnterAnimOn; } + bool IsExitAnimOn( void ) { return m_bExitAnimOn; } + const Vector &GetEyeExitEndpoint( void ) { return m_vecEyeExitEndpoint; } + +protected: + // Entering / Exiting + bool m_bEngineLocked; // Mapmaker override on whether the vehicle's allowed to be turned on/off + bool m_bLocked; + float m_flMinimumSpeedToEnterExit; + CNetworkVar( bool, m_bEnterAnimOn ); + CNetworkVar( bool, m_bExitAnimOn ); + + // Used to turn the keepupright off after a short time + float m_flTurnOffKeepUpright; + float m_flNoImpactDamageTime; +}; + + +inline bool CPropVehicleDriveable::HasGun() +{ + return m_bHasGun; +} + + +#endif // VEHICLE_BASE_H diff --git a/game/server/vehicle_baseserver.h b/game/server/vehicle_baseserver.h new file mode 100644 index 0000000..cdf1f75 --- /dev/null +++ b/game/server/vehicle_baseserver.h @@ -0,0 +1,328 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VEHICLE_BASESERVER_H +#define VEHICLE_BASESERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vehicle_sounds.h" +#include "entityblocker.h" + +class CSoundPatch; + +struct vbs_sound_update_t +{ + float flFrameTime; + float flCurrentSpeedFraction; + float flWorldSpaceSpeed; + bool bThrottleDown; + bool bReverse; + bool bTurbo; + bool bVehicleInWater; + bool bExitVehicle; + + void Defaults() + { + flFrameTime = gpGlobals->frametime; + flCurrentSpeedFraction = 0; + flWorldSpaceSpeed = 0; + bThrottleDown = false; + bReverse = false; + bTurbo = false; + bVehicleInWater = false; + bExitVehicle = false; + } +}; + +// ----------------------------------------- +// Information about the passenger in the car +// ----------------------------------------- +class CPassengerInfo +{ +public: + CPassengerInfo( void ) : m_nRole( -1 ), m_nSeat( -1 ), m_strRoleName( NULL_STRING ), m_strSeatName( NULL_STRING ) {} + + DECLARE_SIMPLE_DATADESC(); + + int GetSeat( void ) const { return m_nSeat; } + int GetRole( void ) const { return m_nRole; } + CBaseCombatCharacter *GetPassenger( void ) const { return m_hPassenger; } + +private: + int m_nRole; // Role (by index) + int m_nSeat; // Seat (by index) + string_t m_strRoleName; // Used in restoration for fix-up + string_t m_strSeatName; // Used in restoration for fix-up + CHandle m_hPassenger; // Actual passenger + + friend class CBaseServerVehicle; +}; + +// ----------------------------------------- +// Seat transition information (animation and priority) +// ----------------------------------------- + +class CPassengerSeatTransition +{ +public: + CPassengerSeatTransition( void ) : m_strAnimationName( NULL_STRING ), m_nPriority( -1 ) {}; + + string_t GetAnimationName( void ) const { return m_strAnimationName; } + int GetPriority( void ) const { return m_nPriority; } + +private: + string_t m_strAnimationName; // Name of animation to play + int m_nPriority; // Priority of the transition + + friend class CBaseServerVehicle; +}; + +// ----------------------------------------- +// Seat in a vehicle (attachment and a collection of animations to reach it) +// ----------------------------------------- +class CPassengerSeat +{ +public: + CPassengerSeat( void ) : m_nAttachmentID( -1 ) {}; + int GetAttachmentID( void ) const { return m_nAttachmentID; } + +private: + string_t m_strSeatName; // Used for save/load fixup + int m_nAttachmentID; // Goal attachment + CUtlVector m_EntryTransitions; // Entry information + CUtlVector m_ExitTransitions; // Exit information + + friend class CBaseServerVehicle; +}; + +// ----------------------------------------- +// Passenger role information +// ----------------------------------------- +class CPassengerRole +{ +public: + CPassengerRole( void ) : m_strName( NULL_STRING ) {}; + string_t GetName( void ) const { return m_strName; } + +private: + string_t m_strName; // Name of the set + CUtlVector m_PassengerSeats; // Passenger info + + friend class CBaseServerVehicle; +}; + +//----------------------------------------------------------------------------- +// Purpose: Base class for drivable vehicle handling. Contain it in your +// drivable vehicle. +//----------------------------------------------------------------------------- +class CBaseServerVehicle : public IServerVehicle +{ +public: + DECLARE_SIMPLE_DATADESC(); + DECLARE_CLASS_NOBASE( CBaseServerVehicle ); + + CBaseServerVehicle( void ); + ~CBaseServerVehicle( void ); + + virtual void Precache( void ); + +// IVehicle +public: + virtual CBaseCombatCharacter *GetPassenger( int nRole = VEHICLE_ROLE_DRIVER ); + + virtual int GetPassengerRole( CBaseCombatCharacter *pPassenger ); + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ); + virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ); + virtual void ItemPostFrame( CBasePlayer *pPlayer ); + +// IServerVehicle +public: + virtual CBaseEntity *GetVehicleEnt( void ) { return m_pVehicle; } + virtual void SetPassenger( int nRole, CBaseCombatCharacter *pPassenger ); + virtual bool IsPassengerVisible( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual bool IsPassengerDamagable( int nRole = VEHICLE_ROLE_DRIVER ) { return true; } + virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ); + + virtual bool IsVehicleUpright( void ) { return true; } + virtual bool IsPassengerEntering( void ) { Assert( 0 ); return false; } + virtual bool IsPassengerExiting( void ) { Assert( 0 ); return false; } + + virtual void HandlePassengerEntry( CBaseCombatCharacter *pPassenger, bool bAllowEntryOutsideZone = false ); + virtual bool HandlePassengerExit( CBaseCombatCharacter *pPassenger ); + + virtual void GetPassengerSeatPoint( int nRole, Vector *pPoint, QAngle *pAngles ); + virtual bool GetPassengerExitPoint( int nRole, Vector *pPoint, QAngle *pAngles ); + virtual Class_T ClassifyPassenger( CBaseCombatCharacter *pPassenger, Class_T defaultClassification ) { return defaultClassification; } + virtual float PassengerDamageModifier( const CTakeDamageInfo &info ) { return 1.0; } + virtual const vehicleparams_t *GetVehicleParams( void ) { return NULL; } + virtual bool IsVehicleBodyInWater( void ) { return false; } + virtual IPhysicsVehicleController *GetVehicleController() { return NULL; } + + // NPC Driving + virtual bool NPC_CanDrive( void ) { return true; } + virtual void NPC_SetDriver( CNPC_VehicleDriver *pDriver ) { return; } + virtual void NPC_DriveVehicle( void ) { return; } + virtual void NPC_ThrottleCenter( void ); + virtual void NPC_ThrottleReverse( void ); + virtual void NPC_ThrottleForward( void ); + virtual void NPC_Brake( void ); + virtual void NPC_TurnLeft( float flDegrees ); + virtual void NPC_TurnRight( float flDegrees ); + virtual void NPC_TurnCenter( void ); + virtual void NPC_PrimaryFire( void ); + virtual void NPC_SecondaryFire( void ); + virtual bool NPC_HasPrimaryWeapon( void ) { return false; } + virtual bool NPC_HasSecondaryWeapon( void ) { return false; } + virtual void NPC_AimPrimaryWeapon( Vector vecTarget ) { return; } + virtual void NPC_AimSecondaryWeapon( Vector vecTarget ) { return; } + + // Weapon handling + virtual void Weapon_PrimaryRanges( float *flMinRange, float *flMaxRange ); + virtual void Weapon_SecondaryRanges( float *flMinRange, float *flMaxRange ); + virtual float Weapon_PrimaryCanFireAt( void ); // Return the time at which this vehicle's primary weapon can fire again + virtual float Weapon_SecondaryCanFireAt( void ); // Return the time at which this vehicle's secondary weapon can fire again + + // ---------------------------------------------------------------------------- + // NPC passenger data + +public: + + bool NPC_AddPassenger( CBaseCombatCharacter *pPassenger, string_t strRoleName, int nSeat ); + bool NPC_RemovePassenger( CBaseCombatCharacter *pPassenger ); + virtual bool NPC_GetPassengerSeatPosition( CBaseCombatCharacter *pPassenger, Vector *vecResultPos, QAngle *vecResultAngle ); + virtual bool NPC_GetPassengerSeatPositionLocal( CBaseCombatCharacter *pPassenger, Vector *vecResultPos, QAngle *vecResultAngles ); + virtual int NPC_GetPassengerSeatAttachment( CBaseCombatCharacter *pPassenger ); + virtual int NPC_GetAvailableSeat( CBaseCombatCharacter *pPassenger, string_t strRoleName, VehicleSeatQuery_e nQueryType ); + bool NPC_HasAvailableSeat( string_t strRoleName ); + + + virtual const PassengerSeatAnims_t *NPC_GetPassengerSeatAnims( CBaseCombatCharacter *pPassenger, PassengerSeatAnimType_t nType ); + virtual CBaseCombatCharacter *NPC_GetPassengerInSeat( int nRoleID, int nSeatID ); + + Vector GetSavedViewOffset( void ) { return m_savedViewOffset; } + +private: + + // Vehicle entering/exiting + void ParseNPCRoles( KeyValues *pModelKeyValues ); + void ParseNPCPassengerSeat( KeyValues *pSetKeyValues, CPassengerSeat *pSeat ); + void ParseNPCSeatTransition( KeyValues *pTransitionKeyValues, CPassengerSeatTransition *pTransition ); + +protected: + + int FindRoleIndexByName( string_t strRoleName ); + int FindSeatIndexByName( int nRoleIndex, string_t strSeatName ); + int NPC_GetAvailableSeat_Any( CBaseCombatCharacter *pPassenger, int nRoleID ); + int NPC_GetAvailableSeat_Nearest( CBaseCombatCharacter *pPassenger, int nRoleID ); + + CPassengerRole *FindOrCreatePassengerRole( string_t strName, int *nIndex = NULL ); + + CUtlVector< CPassengerInfo > m_PassengerInfo; + CUtlVector< CPassengerRole > m_PassengerRoles; // Not save/restored + + // ---------------------------------------------------------------------------- + void ReloadScript(); // debug/tuning +public: + + void UseLegacyExitChecks( bool bState ) { m_bUseLegacyExitChecks = bState; } + void RestorePassengerInfo( void ); + + virtual CBaseEntity *GetDriver( void ); // Player Driving + virtual void ParseEntryExitAnims( void ); + void ParseExitAnim( KeyValues *pkvExitList, bool bEscapeExit ); + virtual bool CheckExitPoint( float yaw, int distance, Vector *pEndPoint ); + virtual int GetEntryAnimForPoint( const Vector &vecPoint ); + virtual int GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked ); + virtual void HandleEntryExitFinish( bool bExitAnimOn, bool bResetAnim ); + + virtual void SetVehicle( CBaseEntity *pVehicle ); + IDrivableVehicle *GetDrivableVehicle( void ); + + // Sound handling + bool Initialize( const char *pScriptName ); + virtual void SoundStart(); + virtual void SoundStartDisabled(); + virtual void SoundShutdown( float flFadeTime = 0.0 ); + virtual void SoundUpdate( vbs_sound_update_t ¶ms ); + virtual void PlaySound( vehiclesound iSound ); + virtual void StopSound( vehiclesound iSound ); + virtual void RecalculateSoundGear( vbs_sound_update_t ¶ms ); + void SetVehicleVolume( float flVolume ) { m_flVehicleVolume = clamp( flVolume, 0.0f, 1.0f ); } + + // Rumble + virtual void StartEngineRumble(); + virtual void StopEngineRumble(); + +public: + CBaseEntity *m_pVehicle; + IDrivableVehicle *m_pDrivableVehicle; + + // NPC Driving + int m_nNPCButtons; + int m_nPrevNPCButtons; + float m_flTurnDegrees; + + // Entry / Exit anims + struct entryanim_t + { + int iHitboxGroup; + char szAnimName[128]; + }; + CUtlVector< entryanim_t > m_EntryAnimations; + + struct exitanim_t + { + bool bUpright; + bool bEscapeExit; + char szAnimName[128]; + Vector vecExitPointLocal; // Point the animation leaves the player at when finished + QAngle vecExitAnglesLocal; + }; + + CUtlVector< exitanim_t > m_ExitAnimations; + bool m_bParsedAnimations; + bool m_bUseLegacyExitChecks; // HACK: Choreo vehicles use non-sensical setups to move the player, we need to poll their attachment point positions + int m_iCurrentExitAnim; + Vector m_vecCurrentExitEndPoint; + Vector m_savedViewOffset; + CHandle m_hExitBlocker; // Entity to prevent other entities blocking the player's exit point during the exit animation + + char m_chPreviousTextureType; + +// sound state + vehiclesounds_t m_vehicleSounds; +private: + float m_flVehicleVolume; + int m_iSoundGear; // The sound "gear" that we're currently in + float m_flSpeedPercentage; + + CSoundPatch *m_pStateSound; + CSoundPatch *m_pStateSoundFade; + sound_states m_soundState; + float m_soundStateStartTime; + float m_lastSpeed; + + void SoundState_OnNewState( sound_states lastState ); + void SoundState_Update( vbs_sound_update_t ¶ms ); + sound_states SoundState_ChooseState( vbs_sound_update_t ¶ms ); + void PlaySound( const char *pSound ); + void StopLoopingSound( float fadeTime = 0.25f ); + void PlayLoopingSound( const char *pSoundName ); + bool PlayCrashSound( float speed ); + bool CheckCrash( vbs_sound_update_t ¶ms ); + const char *StateSoundName( sound_states state ); + void InitSoundParams( vbs_sound_update_t ¶ms ); + void CacheEntryExitPoints( void ); + bool GetLocalAttachmentAtTime( int nQuerySequence, int nAttachmentIndex, float flCyclePoint, Vector *vecOriginOut, QAngle *vecAnglesOut ); + bool GetLocalAttachmentAtTime( const char *lpszAnimName, int nAttachmentIndex, float flCyclePoint, Vector *vecOriginOut, QAngle *vecAnglesOut ); +}; + +#endif // VEHICLE_BASESERVER_H diff --git a/game/server/vehicle_sounds.h b/game/server/vehicle_sounds.h new file mode 100644 index 0000000..82557b9 --- /dev/null +++ b/game/server/vehicle_sounds.h @@ -0,0 +1,137 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VEHICLE_SOUNDS_H +#define VEHICLE_SOUNDS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vcollide_parse.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum vehiclesound +{ + VS_SKID_FRICTION_LOW, + VS_SKID_FRICTION_NORMAL, + VS_SKID_FRICTION_HIGH, + VS_ENGINE2_START, + VS_ENGINE2_STOP, + VS_MISC1, + VS_MISC2, + VS_MISC3, + VS_MISC4, + + VS_NUM_SOUNDS, +}; + +extern const char *vehiclesound_parsenames[VS_NUM_SOUNDS]; + +// This is a list of vehiclesounds to automatically stop when the vehicle's driver exits the vehicle +#define NUM_SOUNDS_TO_STOP_ON_EXIT 4 +extern vehiclesound g_iSoundsToStopOnExit[NUM_SOUNDS_TO_STOP_ON_EXIT]; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct vehicle_gear_t +{ + DECLARE_DATADESC(); + + float flMinSpeed; + float flMaxSpeed; + float flSpeedApproachFactor; +}; + +struct vehicle_crashsound_t +{ + DECLARE_DATADESC(); + + float flMinSpeed; + float flMinDeltaSpeed; + int gearLimit; + string_t iszCrashSound; +}; + +enum sound_states +{ + SS_NONE = 0, + SS_SHUTDOWN, + SS_SHUTDOWN_WATER, + SS_START_WATER, + SS_START_IDLE, + SS_IDLE, + SS_GEAR_0, + SS_GEAR_1, + SS_GEAR_2, + SS_GEAR_3, + SS_GEAR_4, + SS_SLOWDOWN, + SS_SLOWDOWN_HIGHSPEED, // not a real state, just a slot for state sounds + SS_GEAR_0_RESUME, + SS_GEAR_1_RESUME, + SS_GEAR_2_RESUME, + SS_GEAR_3_RESUME, + SS_GEAR_4_RESUME, + SS_TURBO, + SS_REVERSE, + + SS_NUM_STATES, +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct vehiclesounds_t +{ + void Init( void ) + { + pGears.Purge(); + crashSounds.Purge(); + + for ( int i = 0; i < VS_NUM_SOUNDS; i++ ) + { + iszSound[i] = NULL_STRING; + } + + for ( int i = 0; i < SS_NUM_STATES; i++ ) + { + iszStateSounds[i] = NULL_STRING; + minStateTime[i] = 0.0f; + } + } + + DECLARE_DATADESC(); + + CUtlVector pGears; + CUtlVector crashSounds; + string_t iszSound[ VS_NUM_SOUNDS ]; + string_t iszStateSounds[SS_NUM_STATES]; + float minStateTime[SS_NUM_STATES]; +}; + +//----------------------------------------------------------------------------- +// Purpose: A KeyValues parse for vehicle sound blocks +//----------------------------------------------------------------------------- +class CVehicleSoundsParser : public IVPhysicsKeyHandler +{ +public: + CVehicleSoundsParser( void ); + + virtual void ParseKeyValue( void *pData, const char *pKey, const char *pValue ); + virtual void SetDefaults( void *pData ); + +private: + // Index of the gear we're currently reading data into + int m_iCurrentGear; + int m_iCurrentState; + int m_iCurrentCrashSound; +}; + +#endif // VEHICLE_SOUNDS_H diff --git a/game/server/vguiscreen.h b/game/server/vguiscreen.h new file mode 100644 index 0000000..cf72091 --- /dev/null +++ b/game/server/vguiscreen.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is an entity that represents a vgui screen +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUISCREEN_H +#define VGUISCREEN_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// This is an entity that represents a vgui screen +//----------------------------------------------------------------------------- +class CVGuiScreen : public CBaseEntity +{ +public: + DECLARE_CLASS( CVGuiScreen, CBaseEntity ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CVGuiScreen(); + + virtual void Precache(); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void Spawn(); + virtual void Activate(); + virtual void OnRestore(); + + const char *GetPanelName() const; + + // Sets the screen size + resolution + void SetActualSize( float flWidth, float flHeight ); + + // Activates/deactivates the screen + bool IsActive() const; + void SetActive( bool bActive ); + + // Is this screen only visible to teammates? + bool IsVisibleOnlyToTeammates() const; + void MakeVisibleOnlyToTeammates( bool bActive ); + bool IsVisibleToTeam( int nTeam ); + + // Sets the overlay material + void SetOverlayMaterial( const char *pMaterial ); + + void SetAttachedToViewModel( bool bAttached ); + bool IsAttachedToViewModel() const; + + void SetTransparency( bool bTransparent ); + + virtual int UpdateTransmitState( void ); + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + + void SetPlayerOwner( CBasePlayer *pPlayer, bool bOwnerOnlyInput = false ); + +private: + void SetAttachmentIndex( int nIndex ); + void SetPanelName( const char *pPanelName ); + void InputSetActive( inputdata_t &inputdata ); + void InputSetInactive( inputdata_t &inputdata ); + + string_t m_strOverlayMaterial; + + CNetworkVar( float, m_flWidth ); + CNetworkVar( float, m_flHeight ); + CNetworkVar( int, m_nPanelName ); // The name of the panel + CNetworkVar( int, m_nAttachmentIndex ); + CNetworkVar( int, m_nOverlayMaterial ); + CNetworkVar( int, m_fScreenFlags ); + CNetworkVar( EHANDLE, m_hPlayerOwner ); + + friend CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex ); +}; + + +void PrecacheVGuiScreen( const char *pScreenType ); +void PrecacheVGuiScreenOverlayMaterial( const char *pMaterialName ); +CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex ); +void DestroyVGuiScreen( CVGuiScreen *pVGuiScreen ); + + +#endif // VGUISCREEN_H diff --git a/game/server/vote_controller.h b/game/server/vote_controller.h new file mode 100644 index 0000000..a3f82ff --- /dev/null +++ b/game/server/vote_controller.h @@ -0,0 +1,140 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Player-driven Voting System for Multiplayer Source games (currently implemented for TF2) +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VOTE_CONTROLLER_H +#define VOTE_CONTROLLER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +#define MAX_COMMAND_LENGTH 64 +#define MAX_CREATE_ERROR_STRING 96 + +class CBaseIssue // Base class concept for vote issues (i.e. Kick Player). Created per level-load and destroyed by CVoteController's dtor. +{ +public: + CBaseIssue( const char *typeString ); + virtual ~CBaseIssue(); + const char *GetTypeString( void ); // Connection between console command and specific type of issue + virtual const char *GetTypeStringLocalized( void ) { return ""; } // When empty, the client uses the classname string and prepends "#Vote_" + virtual const char *GetDetailsString( void ); + virtual void SetIssueDetails( const char *pszDetails ); // We need to know the details part of the con command for later + virtual void OnVoteFailed( int iEntityHoldingVote ); // The moment the vote fails, also has some time for feedback before the window goes away + virtual void OnVoteStarted( void ) {} // Called as soon as the vote starts + virtual bool IsEnabled( void ) { return false; } // Query the issue to see if it's enabled + virtual bool CanTeamCallVote( int iTeam ) const; // Can someone on the given team call this vote? + virtual bool CanCallVote( int nEntIndex, const char *pszDetails, vote_create_failed_t &nFailCode, int &nTime ); // Can this guy hold a vote on this issue? + virtual bool IsTeamRestrictedVote( void ); // Restrict access and visibility of this vote to a specific team? + virtual const char *GetDisplayString( void ) = 0; // The string that will be passed to the client for display + virtual void ExecuteCommand( void ) = 0; // Where the magic happens. Do your thing. + virtual void ListIssueDetails( CBasePlayer *pForWhom ) = 0; // Someone would like to know all your valid details + virtual const char *GetVotePassedString( void ); // Get the string an issue would like to display when it passes. + virtual int CountPotentialVoters( void ); + virtual int GetNumberVoteOptions( void ); // How many choices this vote will have. i.e. Returns 2 on a Yes/No issue (the default). + virtual bool IsYesNoVote( void ); + virtual void SetYesNoVoteCount( int iNumYesVotes, int iNumNoVotes, int iNumPotentialVotes ); + virtual bool GetVoteOptions( CUtlVector &vecNames ); // We use this to generate options for voting + virtual bool BRecordVoteFailureEventForEntity( int iVoteCallingEntityIndex ) const { return iVoteCallingEntityIndex != DEDICATED_SERVER; } + void SetIssueCooldownDuration( float flDuration ) { m_flNextCallTime = gpGlobals->curtime + flDuration; } // The issue can not be raised again for this period of time (in seconds) + virtual float GetQuorumRatio( void ); // Each issue can decide the required ratio of voted-vs-abstained + + CHandle< CBasePlayer > m_hPlayerTarget; // If the target of the issue is a player, we should store them here + +protected: + static void ListStandardNoArgCommand( CBasePlayer *forWhom, const char *issueString ); // List a Yes vote command + + struct FailedVote + { + char szFailedVoteParameter[MAX_VOTE_DETAILS_LENGTH]; + float flLockoutTime; + }; + + CUtlVector< FailedVote* > m_FailedVotes; + char m_szTypeString[MAX_COMMAND_LENGTH]; + char m_szDetailsString[MAX_VOTE_DETAILS_LENGTH]; + int m_iNumYesVotes; + int m_iNumNoVotes; + int m_iNumPotentialVotes; + float m_flNextCallTime; +}; + +class CVoteController : public CBaseEntity +{ + DECLARE_CLASS( CVoteController, CBaseEntity ); + +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + virtual ~CVoteController(); + + enum TryCastVoteResult + { + CAST_OK, + CAST_FAIL_SERVER_DISABLE, + CAST_FAIL_NO_ACTIVE_ISSUE, + CAST_FAIL_TEAM_RESTRICTED, + CAST_FAIL_NO_CHANGES, + CAST_FAIL_DUPLICATE, + CAST_FAIL_VOTE_CLOSED, + CAST_FAIL_SYSTEM_ERROR + }; + + virtual void Spawn( void ); + virtual int UpdateTransmitState( void ); + virtual bool IsVoteSystemEnabled( void ); + + bool SetupVote( int iEntIndex ); // This creates a list of issues for the UI + bool CreateVote( int iEntIndex, const char *pszTypeString, const char *pszDetailString ); // This is what the UI passes in + TryCastVoteResult TryCastVote( int iEntIndex, const char *pszVoteString ); + void RegisterIssue( CBaseIssue *pNewIssue ); + void ListIssues( CBasePlayer *pForWhom ); + bool IsValidVoter( CBasePlayer *pWhom ); + bool CanTeamCastVote( int iTeam ) const; + void SendVoteCreationFailedMessage( vote_create_failed_t nReason, CBasePlayer *pVoteCaller, int nTime = -1 ); + void SendVoteFailedToPassMessage( vote_create_failed_t nReason ); + void VoteChoice_Increment( int nVoteChoice ); + void VoteChoice_Decrement( int nVoteChoice ); + int GetVoteIssueIndexWithHighestCount( void ); + void TrackVoteCaller( CBasePlayer *pPlayer ); + bool CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown, vote_create_failed_t &nErrorCode ); + bool IsVoteActive( void ) { return m_iActiveIssueIndex != INVALID_ISSUE; } + int GetNumVotesCast( void ); + + void AddPlayerToKickWatchList( CSteamID steamID, float flDuration ); // Band-aid until we figure out how player's avoid kick votes + void AddPlayerToNameLockedList( CSteamID steamID, float flDuration, int nUserID ); + bool IsPlayerBeingKicked( CBasePlayer *pPlayer ); + +protected: + void ResetData( void ); + void VoteControllerThink( void ); + void CheckForEarlyVoteClose( void ); // If everyone has voted (and changing votes is not allowed) then end early + + CNetworkVar( int, m_iActiveIssueIndex ); // Type of thing being voted on + CNetworkVar( int, m_iOnlyTeamToVote ); // If an Ally restricted vote, the team number that is allowed to vote + CNetworkArray( int, m_nVoteOptionCount, MAX_VOTE_OPTIONS ); // Vote options counter + CNetworkVar( int, m_nPotentialVotes ); // How many votes could come in, so we can close ballot early + CNetworkVar( bool, m_bIsYesNoVote ); // Is the current issue Yes/No? + CountdownTimer m_acceptingVotesTimer; // How long from vote start until we count the ballots + CountdownTimer m_executeCommandTimer; // How long after end of vote time until we execute a passed vote + CountdownTimer m_resetVoteTimer; // when the current vote will end + int m_nVotesCast[MAX_PLAYERS + 1]; // arrays are zero-based and player indices are one-based + int m_iEntityHoldingVote; + + CUtlVector m_potentialIssues; + CUtlVector m_VoteOptions; + CUtlMap m_VoteCallers; // History of SteamIDs that have tried to call votes. + + friend class CVoteControllerSystem; +}; + +extern CVoteController *g_voteController; + +#endif // VOTE_CONTROLLER_H diff --git a/game/server/waterbullet.h b/game/server/waterbullet.h new file mode 100644 index 0000000..5fc8f9e --- /dev/null +++ b/game/server/waterbullet.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Entity that simulates bullets that are underwater. +// +//=============================================================================// + +#ifndef WEAPON_WATERBULLET_H +#define WEAPON_WATERBULLET_H +#ifdef _WIN32 +#pragma once +#endif + +#define WATER_BULLET_BUBBLES_PER_INCH 0.05f + +//========================================================= +//========================================================= +class CWaterBullet : public CBaseAnimating +{ + DECLARE_CLASS( CWaterBullet, CBaseAnimating ); + +public: + void Precache(); + void Spawn( const Vector &vecOrigin, const Vector &vecDir ); + void Touch( CBaseEntity *pOther ); + void BulletThink(); + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); +}; + +#endif // WEAPON_WATERBULLET_H diff --git a/game/server/wcedit.h b/game/server/wcedit.h new file mode 100644 index 0000000..a169f00 --- /dev/null +++ b/game/server/wcedit.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Namespace for functions having to do with WC Edit mode +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WCEDIT_H +#define WCEDIT_H +#pragma once + +class CBaseEntity; + +//============================================================================= +// >> NWCEdit +//============================================================================= +namespace NWCEdit +{ + Vector AirNodePlacementPosition( void ); + bool IsWCVersionValid(void); + void CreateAINode( CBasePlayer *pPlayer ); + void DestroyAINode( CBasePlayer *pPlayer ); + void CreateAILink( CBasePlayer *pPlayer ); + void DestroyAILink( CBasePlayer *pPlayer ); + void UndoDestroyAINode(void); + void RememberEntityPosition( CBaseEntity *pEntity ); + void UpdateEntityPosition( CBaseEntity *pEntity ); +}; + +#endif // WCEDIT_H \ No newline at end of file diff --git a/game/server/worker_scientist.h b/game/server/worker_scientist.h new file mode 100644 index 0000000..db4f992 --- /dev/null +++ b/game/server/worker_scientist.h @@ -0,0 +1 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// diff --git a/game/server/world.h b/game/server/world.h new file mode 100644 index 0000000..a8547d3 --- /dev/null +++ b/game/server/world.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The worldspawn entity. This spawns first when each level begins. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WORLD_H +#define WORLD_H +#ifdef _WIN32 +#pragma once +#endif + + +class CWorld : public CBaseEntity +{ +public: + DECLARE_CLASS( CWorld, CBaseEntity ); + + CWorld(); + ~CWorld(); + + DECLARE_SERVERCLASS(); + + virtual int RequiredEdictIndex( void ) { return 0; } // the world always needs to be in slot 0 + + static void RegisterSharedActivities( void ); + static void RegisterSharedEvents( void ); + virtual void Spawn( void ); + virtual void Precache( void ); + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + virtual void DecalTrace( trace_t *pTrace, char const *decalName ); + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) {} + virtual void VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ) {} + + inline void GetWorldBounds( Vector &vecMins, Vector &vecMaxs ) + { + VectorCopy( m_WorldMins, vecMins ); + VectorCopy( m_WorldMaxs, vecMaxs ); + } + + inline float GetWaveHeight() const + { + return (float)m_flWaveHeight; + } + + bool GetDisplayTitle() const; + bool GetStartDark() const; + + void SetDisplayTitle( bool display ); + void SetStartDark( bool startdark ); + + bool IsColdWorld( void ); + +private: + DECLARE_DATADESC(); + + string_t m_iszChapterTitle; + + CNetworkVar( float, m_flWaveHeight ); + CNetworkVector( m_WorldMins ); + CNetworkVector( m_WorldMaxs ); + CNetworkVar( float, m_flMaxOccludeeArea ); + CNetworkVar( float, m_flMinOccluderArea ); + CNetworkVar( float, m_flMinPropScreenSpaceWidth ); + CNetworkVar( float, m_flMaxPropScreenSpaceWidth ); + CNetworkVar( string_t, m_iszDetailSpriteMaterial ); + + // start flags + CNetworkVar( bool, m_bStartDark ); + CNetworkVar( bool, m_bColdWorld ); + bool m_bDisplayTitle; +}; + + +CWorld* GetWorldEntity(); +extern const char *GetDefaultLightstyleString( int styleIndex ); + + +#endif // WORLD_H diff --git a/game/shared/GameEventListener.h b/game/shared/GameEventListener.h new file mode 100644 index 0000000..42d2eba --- /dev/null +++ b/game/shared/GameEventListener.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GAME_EVENT_LISTENER_H +#define GAME_EVENT_LISTENER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igameevents.h" +extern IGameEventManager2 *gameeventmanager; + +// A safer method than inheriting straight from IGameEventListener2. +// Avoids requiring the user to remove themselves as listeners in +// their deconstructor, and sets the serverside variable based on +// our dll location. +class CGameEventListener : public IGameEventListener2 +{ +public: + CGameEventListener() : m_bRegisteredForEvents(false) + { + } + + ~CGameEventListener() + { + StopListeningForAllEvents(); + } + + void ListenForGameEvent( const char *name ) + { + m_bRegisteredForEvents = true; + +#ifdef CLIENT_DLL + bool bServerSide = false; +#else + bool bServerSide = true; +#endif + if ( gameeventmanager ) + gameeventmanager->AddListener( this, name, bServerSide ); + } + + void StopListeningForAllEvents() + { + // remove me from list + if ( m_bRegisteredForEvents ) + { + if ( gameeventmanager ) + gameeventmanager->RemoveListener( this ); + m_bRegisteredForEvents = false; + } + } + + // Intentionally abstract + virtual void FireGameEvent( IGameEvent *event ) = 0; + +private: + + // Have we registered for any events? + bool m_bRegisteredForEvents; +}; + +#endif diff --git a/game/shared/IEffects.h b/game/shared/IEffects.h new file mode 100644 index 0000000..e405154 --- /dev/null +++ b/game/shared/IEffects.h @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client-server neutral effects interface +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IEFFECTS_H +#define IEFFECTS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "mathlib/vector.h" +#include "interface.h" +#include "ipredictionsystem.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +enum ShakeCommand_t; +class Vector; +class CGameTrace; +typedef CGameTrace trace_t; + + +//----------------------------------------------------------------------------- +// Client-server neutral effects interface +//----------------------------------------------------------------------------- +#define IEFFECTS_INTERFACE_VERSION "IEffects001" +abstract_class IEffects : public IPredictionSystem +{ +public: + // + // Particle effects + // + virtual void Beam( const Vector &Start, const Vector &End, int nModelIndex, + int nHaloIndex, unsigned char frameStart, unsigned char frameRate, + float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength, + unsigned char noise, unsigned char red, unsigned char green, + unsigned char blue, unsigned char brightness, unsigned char speed) = 0; + + //----------------------------------------------------------------------------- + // Purpose: Emits smoke sprites. + // Input : origin - Where to emit the sprites. + // scale - Sprite scale * 10. + // framerate - Framerate at which to animate the smoke sprites. + //----------------------------------------------------------------------------- + virtual void Smoke( const Vector &origin, int modelIndex, float scale, float framerate ) = 0; + + virtual void Sparks( const Vector &position, int nMagnitude = 1, int nTrailLength = 1, const Vector *pvecDir = NULL ) = 0; + + virtual void Dust( const Vector &pos, const Vector &dir, float size, float speed ) = 0; + + virtual void MuzzleFlash( const Vector &vecOrigin, const QAngle &vecAngles, float flScale, int iType ) = 0; + + // like ricochet, but no sound + virtual void MetalSparks( const Vector &position, const Vector &direction ) = 0; + + virtual void EnergySplash( const Vector &position, const Vector &direction, bool bExplosive = false ) = 0; + + virtual void Ricochet( const Vector &position, const Vector &direction ) = 0; + + // FIXME: Should these methods remain in this interface? Or go in some + // other client-server neutral interface? + virtual float Time() = 0; + virtual bool IsServer() = 0; + + // Used by the playback system to suppress sounds + virtual void SuppressEffectsSounds( bool bSuppress ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Client-server neutral effects interface accessor +//----------------------------------------------------------------------------- +extern IEffects *g_pEffects; + + +#endif // IEFFECTS_H diff --git a/game/shared/IVehicle.h b/game/shared/IVehicle.h new file mode 100644 index 0000000..14ba528 --- /dev/null +++ b/game/shared/IVehicle.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVEHICLE_H +#define IVEHICLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "baseplayer_shared.h" + +class CUserCmd; +class IMoveHelper; +class CMoveData; +class CBaseCombatCharacter; + +// This is used by the player to access vehicles. It's an interface so the +// vehicles are not restricted in what they can derive from. +abstract_class IVehicle +{ +public: + // Get and set the current driver. Use PassengerRole_t enum in shareddefs.h for adding passengers + virtual CBaseCombatCharacter* GetPassenger( int nRole = VEHICLE_ROLE_DRIVER ) = 0; + virtual int GetPassengerRole( CBaseCombatCharacter *pPassenger ) = 0; + + // Where is the passenger seeing from? + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ) = 0; + + // Does the player use his normal weapons while in this mode? + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) = 0; + + // Process movement + virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) = 0; + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ) = 0; + virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) = 0; + + // Process input + virtual void ItemPostFrame( CBasePlayer *pPlayer ) = 0; +}; + + +#endif // IVEHICLE_H diff --git a/game/shared/ModelSoundsCache.h b/game/shared/ModelSoundsCache.h new file mode 100644 index 0000000..d2d5a64 --- /dev/null +++ b/game/shared/ModelSoundsCache.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef MODELSOUNDSCACHE_H +#define MODELSOUNDSCACHE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "UtlCachedFileData.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" + +#define MODELSOUNDSCACHE_VERSION 5 + +class CStudioHdr; + +#pragma pack(1) +class CModelSoundsCache : public IBaseCacheInfo +{ +public: + CUtlVector< unsigned short > sounds; + + CModelSoundsCache(); + CModelSoundsCache( const CModelSoundsCache& src ); + + void PrecacheSoundList(); + + virtual void Save( CUtlBuffer& buf ); + virtual void Restore( CUtlBuffer& buf ); + virtual void Rebuild( char const *filename ); + + static void FindOrAddScriptSound( CUtlVector< unsigned short >& sounds, char const *soundname ); + static void BuildAnimationEventSoundList( CStudioHdr *hdr, CUtlVector< unsigned short >& sounds ); +private: + char const *GetSoundName( int index ); +}; +#pragma pack() + +#endif // MODELSOUNDSCACHE_H diff --git a/game/shared/Multiplayer/multiplayer_animstate.h b/game/shared/Multiplayer/multiplayer_animstate.h new file mode 100644 index 0000000..a3c7937 --- /dev/null +++ b/game/shared/Multiplayer/multiplayer_animstate.h @@ -0,0 +1,351 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#ifndef MULTIPLAYERANIMSTATE_H +#define MULTIPLAYERANIMSTATE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "basecombatweapon_shared.h" +#include "iplayeranimstate.h" + +#if defined( CLIENT_DLL ) +class C_BasePlayer; +#define CPlayer C_BasePlayer +#else +class CBasePlayer; +#endif + +enum PlayerAnimEvent_t +{ + PLAYERANIMEVENT_ATTACK_PRIMARY, + PLAYERANIMEVENT_ATTACK_SECONDARY, + PLAYERANIMEVENT_ATTACK_GRENADE, + PLAYERANIMEVENT_RELOAD, + PLAYERANIMEVENT_RELOAD_LOOP, + PLAYERANIMEVENT_RELOAD_END, + PLAYERANIMEVENT_JUMP, + PLAYERANIMEVENT_SWIM, + PLAYERANIMEVENT_DIE, + PLAYERANIMEVENT_FLINCH_CHEST, + PLAYERANIMEVENT_FLINCH_HEAD, + PLAYERANIMEVENT_FLINCH_LEFTARM, + PLAYERANIMEVENT_FLINCH_RIGHTARM, + PLAYERANIMEVENT_FLINCH_LEFTLEG, + PLAYERANIMEVENT_FLINCH_RIGHTLEG, + PLAYERANIMEVENT_DOUBLEJUMP, + + // Cancel. + PLAYERANIMEVENT_CANCEL, + PLAYERANIMEVENT_SPAWN, + + // Snap to current yaw exactly + PLAYERANIMEVENT_SNAP_YAW, + + PLAYERANIMEVENT_CUSTOM, // Used to play specific activities + PLAYERANIMEVENT_CUSTOM_GESTURE, + PLAYERANIMEVENT_CUSTOM_SEQUENCE, // Used to play specific sequences + PLAYERANIMEVENT_CUSTOM_GESTURE_SEQUENCE, + + // TF Specific. Here until there's a derived game solution to this. + PLAYERANIMEVENT_ATTACK_PRE, + PLAYERANIMEVENT_ATTACK_POST, + PLAYERANIMEVENT_GRENADE1_DRAW, + PLAYERANIMEVENT_GRENADE2_DRAW, + PLAYERANIMEVENT_GRENADE1_THROW, + PLAYERANIMEVENT_GRENADE2_THROW, + PLAYERANIMEVENT_VOICE_COMMAND_GESTURE, + PLAYERANIMEVENT_DOUBLEJUMP_CROUCH, + PLAYERANIMEVENT_STUN_BEGIN, + PLAYERANIMEVENT_STUN_MIDDLE, + PLAYERANIMEVENT_STUN_END, + PLAYERANIMEVENT_PASSTIME_THROW_BEGIN, + PLAYERANIMEVENT_PASSTIME_THROW_MIDDLE, + PLAYERANIMEVENT_PASSTIME_THROW_END, + PLAYERANIMEVENT_PASSTIME_THROW_CANCEL, + + PLAYERANIMEVENT_ATTACK_PRIMARY_SUPER, + + PLAYERANIMEVENT_COUNT +}; + +// Gesture Slots. +enum +{ + GESTURE_SLOT_ATTACK_AND_RELOAD, + GESTURE_SLOT_GRENADE, + GESTURE_SLOT_JUMP, + GESTURE_SLOT_SWIM, + GESTURE_SLOT_FLINCH, + GESTURE_SLOT_VCD, + GESTURE_SLOT_CUSTOM, + + GESTURE_SLOT_COUNT, +}; + +#define GESTURE_SLOT_INVALID -1 + +struct GestureSlot_t +{ + int m_iGestureSlot; + Activity m_iActivity; + bool m_bAutoKill; + bool m_bActive; + CAnimationLayer *m_pAnimLayer; +}; + +inline bool IsCustomPlayerAnimEvent( PlayerAnimEvent_t event ) +{ + return ( event == PLAYERANIMEVENT_CUSTOM ) || ( event == PLAYERANIMEVENT_CUSTOM_GESTURE ) || + ( event == PLAYERANIMEVENT_CUSTOM_SEQUENCE ) || ( event == PLAYERANIMEVENT_CUSTOM_GESTURE_SEQUENCE ); +} + +struct MultiPlayerPoseData_t +{ + int m_iMoveX; + int m_iMoveY; + int m_iAimYaw; + int m_iAimPitch; + int m_iBodyHeight; + int m_iMoveYaw; + int m_iMoveScale; + + float m_flEstimateYaw; + float m_flLastAimTurnTime; + + void Init() + { + m_iMoveX = 0; + m_iMoveY = 0; + m_iAimYaw = 0; + m_iAimPitch = 0; + m_iBodyHeight = 0; + m_iMoveYaw = 0; + m_iMoveScale = 0; + m_flEstimateYaw = 0.0f; + m_flLastAimTurnTime = 0.0f; + } +}; + +struct DebugPlayerAnimData_t +{ + float m_flSpeed; + float m_flAimPitch; + float m_flAimYaw; + float m_flBodyHeight; + Vector2D m_vecMoveYaw; + + void Init() + { + m_flSpeed = 0.0f; + m_flAimPitch = 0.0f; + m_flAimYaw = 0.0f; + m_flBodyHeight = 0.0f; + m_vecMoveYaw.Init(); + } +}; + +struct MultiPlayerMovementData_t +{ + // Set speeds to -1 if they are not used. + float m_flWalkSpeed; + float m_flRunSpeed; + float m_flSprintSpeed; + float m_flBodyYawRate; +}; + + +//============================================================================= +// +// Multi-Player Animation State +// +class CMultiPlayerAnimState +{ +public: + + DECLARE_CLASS_NOBASE( CMultiPlayerAnimState ); + + // Creation/Destruction + CMultiPlayerAnimState() {} + CMultiPlayerAnimState( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData ); + virtual ~CMultiPlayerAnimState(); + + // This is called by both the client and the server in the same way to trigger events for + // players firing, jumping, throwing grenades, etc. + virtual void ClearAnimationState(); + virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); + virtual Activity CalcMainActivity(); + virtual void Update( float eyeYaw, float eyePitch ); + virtual void Release( void ); + + const QAngle &GetRenderAngles(); + + virtual Activity TranslateActivity( Activity actDesired ); + + virtual void SetRunSpeed( float flSpeed ) { m_MovementData.m_flRunSpeed = flSpeed; } + virtual void SetWalkSpeed( float flSpeed ) { m_MovementData.m_flWalkSpeed = flSpeed; } + virtual void SetSprintSpeed( float flSpeed ) { m_MovementData.m_flSprintSpeed = flSpeed; } + + // Debug + virtual void ShowDebugInfo( void ); + virtual void DebugShowAnimState( int iStartLine ); + + Activity GetCurrentMainActivity( void ) { return m_eCurrentMainSequenceActivity; } + + void OnNewModel( void ); + + // Gestures. + void ResetGestureSlots( void ); + void ResetGestureSlot( int iGestureSlot ); + void AddVCDSequenceToGestureSlot( int iGestureSlot, int iGestureSequence, float flCycle = 0.0f, bool bAutoKill = true ); + CAnimationLayer* GetGestureSlotLayer( int iGestureSlot ); + bool IsGestureSlotActive( int iGestureSlot ); + bool VerifyAnimLayerInSlot( int iGestureSlot ); + + // Feet. + // If you are forcing aim yaw, your code is almost definitely broken if you don't include a delay between + // teleporting and forcing yaw. This is due to an unfortunate interaction between the command lookback window, + // and the fact that m_flEyeYaw is never propogated from the server to the client. + // TODO: Fix this after Halloween 2014. + bool m_bForceAimYaw; + +protected: + + virtual void Init( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData ); + CBasePlayer *GetBasePlayer( void ) { return m_pPlayer; } + + // Allow inheriting classes to override SelectWeightedSequence + virtual int SelectWeightedSequence( Activity activity ) { return GetBasePlayer()->SelectWeightedSequence( activity ); } + virtual void RestartMainSequence(); + + virtual void GetOuterAbsVelocity( Vector& vel ); + float GetOuterXYSpeed(); + + virtual bool HandleJumping( Activity &idealActivity ); + virtual bool HandleDucking( Activity &idealActivity ); + virtual bool HandleMoving( Activity &idealActivity ); + virtual bool HandleSwimming( Activity &idealActivity ); + virtual bool HandleDying( Activity &idealActivity ); + + // Gesture Slots + CUtlVector m_aGestureSlots; + bool InitGestureSlots( void ); + void ShutdownGestureSlots( void ); + bool IsGestureSlotPlaying( int iGestureSlot, Activity iGestureActivity ); + void AddToGestureSlot( int iGestureSlot, Activity iGestureActivity, bool bAutoKill ); + virtual void RestartGesture( int iGestureSlot, Activity iGestureActivity, bool bAutoKill = true ); + void ComputeGestureSequence( CStudioHdr *pStudioHdr ); + void UpdateGestureLayer( CStudioHdr *pStudioHdr, GestureSlot_t *pGesture ); + void DebugGestureInfo( void ); + virtual float GetGesturePlaybackRate( void ) { return 1.0f; } + +#ifdef CLIENT_DLL + void RunGestureSlotAnimEventsToCompletion( GestureSlot_t *pGesture ); +#endif + + virtual void PlayFlinchGesture( Activity iActivity ); + + virtual float CalcMovementSpeed( bool *bIsMoving ); + virtual float CalcMovementPlaybackRate( bool *bIsMoving ); + + void DoMovementTest( CStudioHdr *pStudioHdr, float flX, float flY ); + void DoMovementTest( CStudioHdr *pStudioHdr ); + void GetMovementFlags( CStudioHdr *pStudioHdr ); + + // Pose parameters. + bool SetupPoseParameters( CStudioHdr *pStudioHdr ); + virtual void ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr ); + virtual void ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr ); + virtual void ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr ); + void ComputePoseParam_BodyHeight( CStudioHdr *pStudioHdr ); + virtual void EstimateYaw( void ); + void ConvergeYawAngles( float flGoalYaw, float flYawRate, float flDeltaTime, float &flCurrentYaw ); + + virtual float GetCurrentMaxGroundSpeed(); + virtual void ComputeSequences( CStudioHdr *pStudioHdr ); + void ComputeMainSequence(); + void UpdateInterpolators(); + void ResetGroundSpeed( void ); + float GetInterpolatedGroundSpeed( void ); + + void ComputeFireSequence(); + void ComputeDeployedSequence(); + + virtual bool ShouldUpdateAnimState(); + + void DebugShowAnimStateForPlayer( bool bIsServer ); + void DebugShowEyeYaw( void ); + +// Client specific. +#ifdef CLIENT_DLL + + // Debug. + void DebugShowActivity( Activity activity ); + +#endif + +protected: + + CBasePlayer *m_pPlayer; + + QAngle m_angRender; + + // Pose parameters. + bool m_bPoseParameterInit; + MultiPlayerPoseData_t m_PoseParameterData; + DebugPlayerAnimData_t m_DebugAnimData; + + bool m_bCurrentFeetYawInitialized; + float m_flLastAnimationStateClearTime; + + float m_flEyeYaw; + float m_flEyePitch; + float m_flGoalFeetYaw; + float m_flCurrentFeetYaw; + float m_flLastAimTurnTime; + + MultiPlayerMovementData_t m_MovementData; + + // Jumping. + bool m_bJumping; + float m_flJumpStartTime; + bool m_bFirstJumpFrame; + + // Swimming. + bool m_bInSwim; + bool m_bFirstSwimFrame; + + // Dying + bool m_bDying; + bool m_bFirstDyingFrame; + + // Last activity we've used on the lower body. Used to determine if animations should restart. + Activity m_eCurrentMainSequenceActivity; + + // Specific full-body sequence to play + int m_nSpecificMainSequence; + + // Weapon data. + CHandle m_hActiveWeapon; + + // Ground speed interpolators. +#ifdef CLIENT_DLL + float m_flLastGroundSpeedUpdateTime; + CInterpolatedVar m_iv_flMaxGroundSpeed; +#endif + float m_flMaxGroundSpeed; + + // movement playback options + int m_nMovementSequence; + LegAnimType_t m_LegAnimType; +}; + +// If this is set, then the game code needs to make sure to send player animation events +// to the local player if he's the one being watched. +extern ConVar cl_showanimstate; + +#endif // DOD_PLAYERANIMSTATE_H \ No newline at end of file diff --git a/game/shared/SceneCache.h b/game/shared/SceneCache.h new file mode 100644 index 0000000..72dff66 --- /dev/null +++ b/game/shared/SceneCache.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SCENECACHE_H +#define SCENECACHE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "UtlCachedFileData.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" + +class CChoreoEvent; + +#define SCENECACHE_VERSION 7 + +#pragma pack(1) +class CSceneCache : public IBaseCacheInfo +{ +public: + unsigned int msecs; + CUtlVector< unsigned short > sounds; + + CSceneCache(); + CSceneCache( const CSceneCache& src ); + + int GetSoundCount() const; + char const *GetSoundName( int index ); + + virtual void Save( CUtlBuffer& buf ); + virtual void Restore( CUtlBuffer& buf ); + virtual void Rebuild( char const *filename ); + + static unsigned int ComputeSoundScriptFileTimestampChecksum(); + static void PrecacheSceneEvent( CChoreoEvent *event, CUtlVector< unsigned short >& soundlist ); +}; +#pragma pack() + +#endif // SCENECACHE_H diff --git a/game/shared/SharedFunctorUtils.h b/game/shared/SharedFunctorUtils.h new file mode 100644 index 0000000..a4e4c67 --- /dev/null +++ b/game/shared/SharedFunctorUtils.h @@ -0,0 +1,156 @@ +// SharedFunctorUtils.h +// Useful functors for client and server +//========= Copyright Valve Corporation, All rights reserved. ============// + +//-------------------------------------------------------------------------------------------------------- +/** +* NOTE: The functors in this file should ideally be game-independant, +* and work for any Source based game +*/ +//-------------------------------------------------------------------------------------------------------- +#ifndef _SHARED_FUNCTOR_UTILS_H_ +#define _SHARED_FUNCTOR_UTILS_H_ + +#include "debugoverlay_shared.h" +#include "vprof.h" + +//-------------------------------------------------------------------------------------------------------- +/** + * Finds visible player on given team that we are pointing at. + * "team" can be TEAM_ANY + * Use with ForEachPlayer() + */ +template < class PlayerType > +class TargetScan +{ +public: + TargetScan( PlayerType *me, int team, float aimTolerance = 0.01f, float maxRange = 2000.0f, float closestPointTestDistance = 50.0f, bool debug = false ) + { + m_me = me; + AngleVectors( m_me->EyeAngles(), &m_viewForward ); + m_team = team; + m_closeDot = 1.0f - aimTolerance; + m_bestDot = m_closeDot; + m_maxRange = maxRange; + m_target = NULL; + m_closestPointTestDistance = closestPointTestDistance; + m_debug = debug; + } + + + virtual bool operator() ( PlayerType *them ) + { + VPROF( "TargetScan()" ); + if ( them != m_me && + them->IsAlive() && + (m_team == TEAM_ANY || them->GetTeamNumber() == m_team) && + IsPotentialTarget( them ) ) + { + // move the start point out for determining closestPos, to help with close-in checks (healing, etc) + Vector closestPos; + Vector start = m_me->EyePosition(); + Vector end = start + m_viewForward * m_closestPointTestDistance; + Vector testPos; + CalcClosestPointOnLineSegment( them->WorldSpaceCenter(), start, end, testPos ); + + start = them->GetAbsOrigin(); + end = start; + end.z += them->CollisionProp()->OBBMaxs().z; + CalcClosestPointOnLineSegment( testPos, start, end, closestPos ); + if ( m_debug ) + { + NDebugOverlay::Cross3D( closestPos, 1, 255, 255, 255, true, -1.0f ); + NDebugOverlay::Line( end, start, 255, 0, 0, true, -1.0f ); + } + + Vector to = closestPos - m_me->EyePosition(); + to.NormalizeInPlace(); + + Vector meRangePoint, themRangePoint; + m_me->CollisionProp()->CalcNearestPoint( closestPos, &meRangePoint ); + them->CollisionProp()->CalcNearestPoint( meRangePoint, &themRangePoint ); + float range = meRangePoint.DistTo( themRangePoint ); + + if ( range > m_maxRange ) + { + // too far away + return true; + } + + float dot = ViewDot( to ); + if ( dot > m_closeDot ) + { + // target is within angle cone, check visibility + if ( IsTargetVisible( them ) ) + { + if ( dot >= m_bestDot ) + { + m_target = them; + m_bestDot = dot; + } + + m_allTargets.AddToTail( them ); + } + } + } + + return true; + } + + PlayerType *GetTarget( void ) const + { + return m_target; + } + + const CUtlVector< PlayerType * > &GetAllTargets( void ) const + { + return m_allTargets; + } + + float GetTargetDot( void ) const + { + return m_bestDot; + } + +protected: + /** + * Is the point in our FOV? + */ + virtual float ViewDot( const Vector &dir ) const + { + return DotProduct( m_viewForward, dir ); + } + + /** + * Is the given actor a visible target? + */ + virtual bool IsTargetVisible( PlayerType *them ) const + { + // The default check is a straight-up IsAbleToSee + return m_me->IsAbleToSee( them, CBaseCombatCharacter::DISREGARD_FOV ); // already have a dot product checking FOV + } + + /** + * Is the given player a possible target at all? + */ + virtual bool IsPotentialTarget( PlayerType *them ) const + { + return true; + } + + PlayerType *m_me; + Vector m_viewForward; + int m_team; + + float m_closeDot; + float m_bestDot; + float m_maxRange; + float m_closestPointTestDistance; + bool m_debug; + + PlayerType *m_target; + CUtlVector< PlayerType * > m_allTargets; +}; + + +#endif diff --git a/game/shared/Sprite.h b/game/shared/Sprite.h new file mode 100644 index 0000000..79d8c51 --- /dev/null +++ b/game/shared/Sprite.h @@ -0,0 +1,297 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SPRITE_H +#define SPRITE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "predictable_entity.h" +#include "baseentity_shared.h" + +#define SF_SPRITE_STARTON 0x0001 +#define SF_SPRITE_ONCE 0x0002 +#define SF_SPRITE_TEMPORARY 0x8000 + +class CBasePlayer; + +#if defined( CLIENT_DLL ) +#define CSprite C_Sprite +#define CSpriteOriented C_SpriteOriented +#include "c_pixel_visibility.h" +class CEngineSprite; + +class C_SpriteRenderer +{ +public: + //----------------------------------------------------------------------------- + // Purpose: Sprite orientations + // WARNING! Change these in common/MaterialSystem/Sprite.cpp if you change them here! + //----------------------------------------------------------------------------- + typedef enum + { + SPR_VP_PARALLEL_UPRIGHT = 0, + SPR_FACING_UPRIGHT = 1, + SPR_VP_PARALLEL = 2, + SPR_ORIENTED = 3, + SPR_VP_PARALLEL_ORIENTED = 4 + } SPRITETYPE; + + // Determine sprite orientation + static void GetSpriteAxes( SPRITETYPE type, + const Vector& origin, + const QAngle& angles, + Vector& forward, + Vector& right, + Vector& up ); + + // Sprites can alter blending amount + virtual float GlowBlend( CEngineSprite *psprite, const Vector& entorigin, int rendermode, int renderfx, int alpha, float *scale ); + + // Draws tempent as a sprite + int DrawSprite( + IClientEntity *entity, + const model_t *model, + const Vector& origin, + const QAngle& angles, + float frame, + IClientEntity *attachedto, + int attachmentindex, + int rendermode, + int renderfx, + int alpha, + int r, + int g, + int b, + float scale, + float flHDRColorScale = 1.0f + ); + +protected: + pixelvis_handle_t m_queryHandle; + float m_flGlowProxySize; + float m_flHDRColorScale; +}; + +#endif + +class CSprite : public CBaseEntity +#if defined( CLIENT_DLL ) + , public C_SpriteRenderer +#endif +{ + DECLARE_CLASS( CSprite, CBaseEntity ); +public: + DECLARE_PREDICTABLE(); + DECLARE_NETWORKCLASS(); + + CSprite(); + virtual void SetModel( const char *szModelName ); + + void Spawn( void ); + void Precache( void ); + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + void SetGlowProxySize( float flSize ) { m_flGlowProxySize = flSize; } + +#if !defined( CLIENT_DLL ) + + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + virtual int UpdateTransmitState( void ); + + void SetAsTemporary( void ) { AddSpawnFlags( SF_SPRITE_TEMPORARY ); } + bool IsTemporary( void ) { return ( HasSpawnFlags( SF_SPRITE_TEMPORARY ) ); } + + int ObjectCaps( void ) + { + int flags = 0; + + if ( IsTemporary() ) + { + flags = FCAP_DONT_SAVE; + } + + return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + } + + void OnRestore(); +#endif + + void AnimateThink( void ); + void ExpandThink( void ); + void Animate( float frames ); + void Expand( float scaleSpeed, float fadeSpeed ); + void SpriteInit( const char *pSpriteName, const Vector &origin ); + +#if !defined( CLIENT_DLL ) + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + // Input handlers + void InputHideSprite( inputdata_t &inputdata ); + void InputShowSprite( inputdata_t &inputdata ); + void InputToggleSprite( inputdata_t &inputdata ); + void InputColorRedValue( inputdata_t &inputdata ); + void InputColorBlueValue( inputdata_t &inputdata ); + void InputColorGreenValue( inputdata_t &inputdata ); +#endif + + inline void SetAttachment( CBaseEntity *pEntity, int attachment ) + { + if ( pEntity ) + { + m_hAttachedToEntity = pEntity; + m_nAttachment = attachment; + FollowEntity( pEntity ); + } + } + + void TurnOff( void ); + void TurnOn( void ); + bool IsOn() { return !IsEffectActive( EF_NODRAW ); } + + inline float Frames( void ) { return m_flMaxFrame; } + inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx ) + { + SetRenderMode( (RenderMode_t)rendermode ); + SetColor( r, g, b ); + SetBrightness( a ); + m_nRenderFX = fx; + } + inline void SetTexture( int spriteIndex ) { SetModelIndex( spriteIndex ); } + inline void SetColor( int r, int g, int b ) { SetRenderColor( r, g, b, GetRenderColor().a ); } + + void SetBrightness( int brightness, float duration = 0.0f ); + void SetScale( float scale, float duration = 0.0f ); + void SetSpriteScale( float scale ); + void EnableWorldSpaceScale( bool bEnable ); + + float GetScale( void ) { return m_flSpriteScale; } + int GetBrightness( void ) { return m_nBrightness; } + float GetHDRColorScale( void ) { return m_flHDRColorScale; } + + inline void FadeAndDie( float duration ) + { + SetBrightness( 0, duration ); + SetThink(&CSprite::AnimateUntilDead); + m_flDieTime = gpGlobals->curtime + duration; + SetNextThink( gpGlobals->curtime ); + } + + inline void AnimateAndDie( float framerate ) + { + SetThink(&CSprite::AnimateUntilDead); + m_flSpriteFramerate = framerate; + m_flDieTime = gpGlobals->curtime + (m_flMaxFrame / m_flSpriteFramerate); + SetNextThink( gpGlobals->curtime ); + } + + inline void AnimateForTime( float framerate, float time ) + { + SetThink(&CSprite::AnimateUntilDead); + m_flSpriteFramerate = framerate; + m_flDieTime = gpGlobals->curtime + time; + SetNextThink( gpGlobals->curtime ); + } + + // FIXME: This completely blows. + // Surely there's gotta be a better way. + void FadeOutFromSpawn( ) + { + SetThink(&CSprite::BeginFadeOutThink); + SetNextThink( gpGlobals->curtime + 0.01f ); + } + + void BeginFadeOutThink( ) + { + FadeAndDie( 0.25f ); + } + + void AnimateUntilDead( void ); +#if !defined( CLIENT_DLL ) + DECLARE_DATADESC(); + + static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, bool animate ); +#endif + static CSprite *SpriteCreatePredictable( const char *module, int line, const char *pSpriteName, const Vector &origin, bool animate ); + +#if defined( CLIENT_DLL ) + virtual float GetRenderScale( void ); + virtual int GetRenderBrightness( void ); + + virtual int DrawModel( int flags ); + virtual const Vector& GetRenderOrigin(); + virtual void GetRenderBounds( Vector &vecMins, Vector &vecMaxs ); + virtual float GlowBlend( CEngineSprite *psprite, const Vector& entorigin, int rendermode, int renderfx, int alpha, float *scale ); + virtual void GetToolRecordingState( KeyValues *msg ); + +// Only supported in TF2 right now +#if defined( INVASION_CLIENT_DLL ) + virtual bool ShouldPredict( void ) + { + return true; + } +#endif + + virtual void ClientThink( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + +#endif +public: + CNetworkHandle( CBaseEntity, m_hAttachedToEntity ); + CNetworkVar( int, m_nAttachment ); + CNetworkVar( float, m_flSpriteFramerate ); + CNetworkVar( float, m_flFrame ); +#ifdef PORTAL + CNetworkVar( bool, m_bDrawInMainRender ); + CNetworkVar( bool, m_bDrawInPortalRender ); +#endif + + float m_flDieTime; + +private: + + CNetworkVar( int, m_nBrightness ); + CNetworkVar( float, m_flBrightnessTime ); + + CNetworkVar( float, m_flSpriteScale ); + CNetworkVar( float, m_flScaleTime ); + CNetworkVar( bool, m_bWorldSpaceScale ); + CNetworkVar( float, m_flGlowProxySize ); + CNetworkVar( float, m_flHDRColorScale ); + + float m_flLastTime; + float m_flMaxFrame; + + float m_flStartScale; + float m_flDestScale; //Destination scale + float m_flScaleTimeStart; //Real time for start of scale + int m_nStartBrightness; + int m_nDestBrightness; //Destination brightness + float m_flBrightnessTimeStart;//Real time for brightness +}; + + +class CSpriteOriented : public CSprite +{ +public: + DECLARE_CLASS( CSpriteOriented, CSprite ); +#if !defined( CLIENT_DLL ) + DECLARE_SERVERCLASS(); + void Spawn( void ); +#else + DECLARE_CLIENTCLASS(); + virtual bool IsTransparent( void ); +#endif +}; + + + +// Macro to wrap creation +#define SPRITE_CREATE_PREDICTABLE( name, origin, animate ) \ + CSprite::SpriteCreatePredictable( __FILE__, __LINE__, name, origin, animate ) + +#endif // SPRITE_H diff --git a/game/shared/SpriteTrail.h b/game/shared/SpriteTrail.h new file mode 100644 index 0000000..2248dc9 --- /dev/null +++ b/game/shared/SpriteTrail.h @@ -0,0 +1,124 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SPRITETRAIL_H +#define SPRITETRAIL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "Sprite.h" + +#if defined( CLIENT_DLL ) +#define CSpriteTrail C_SpriteTrail +#endif + + +//----------------------------------------------------------------------------- +// Sprite trail +//----------------------------------------------------------------------------- +struct TrailPoint_t +{ + DECLARE_SIMPLE_DATADESC(); + + Vector m_vecScreenPos; + float m_flDieTime; + float m_flTexCoord; + float m_flWidthVariance; +}; + +class CSpriteTrail : public CSprite +{ + DECLARE_CLASS( CSpriteTrail, CSprite ); + DECLARE_DATADESC(); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +public: + CSpriteTrail( void ); + + // Sets parameters of the sprite trail + void SetLifeTime( float time ); + void SetStartWidth( float flStartWidth ); + void SetEndWidth( float flEndWidth ); + void SetStartWidthVariance( float flStartWidthVariance ); + void SetTextureResolution( float flTexelsPerInch ); + void SetMinFadeLength( float flMinFadeLength ); + void SetSkybox( const Vector &vecSkyboxOrigin, float flSkyboxScale ); + + // Is the trail in the skybox? + bool IsInSkybox() const; + void Spawn( void ); + void Precache( void ); + void SetTransmit( bool bTransmit = true ) { m_bDrawForMoveParent = bTransmit; } + +#if defined( CLIENT_DLL ) + // Client only code + virtual int DrawModel( int flags ); + virtual const Vector &GetRenderOrigin( void ); + virtual const QAngle &GetRenderAngles( void ); + + // On data update + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void GetRenderBounds( Vector& mins, Vector& maxs ); + virtual void ClientThink(); + + virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry ); + +#else + // Server only code + + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + static CSpriteTrail *SpriteTrailCreate( const char *pSpriteName, const Vector &origin, bool animate ); + +#endif + +private: +#if defined( CLIENT_DLL ) + enum + { + // NOTE: # of points max must be a power of two! + MAX_SPRITE_TRAIL_POINTS = 256, + MAX_SPRITE_TRAIL_MASK = MAX_SPRITE_TRAIL_POINTS - 1, + }; + + TrailPoint_t *GetTrailPoint( int n ); + void UpdateTrail( void ); + void ComputeScreenPosition( Vector *pScreenPos ); + void ConvertSkybox(); + void UpdateBoundingBox( void ); + + TrailPoint_t m_vecSteps[MAX_SPRITE_TRAIL_POINTS]; + int m_nFirstStep; + int m_nStepCount; + float m_flUpdateTime; + Vector m_vecPrevSkyboxOrigin; + float m_flPrevSkyboxScale; + Vector m_vecRenderMins; + Vector m_vecRenderMaxs; +#endif + + CNetworkVar( float, m_flLifeTime ); // Amount of time before a new trail segment fades away + CNetworkVar( float, m_flStartWidth ); // The starting scale + CNetworkVar( float, m_flEndWidth ); // The ending scale + CNetworkVar( float, m_flStartWidthVariance ); // The starting scale + CNetworkVar( float, m_flTextureRes ); // Texture resolution along the trail + CNetworkVar( float, m_flMinFadeLength ); // The end of the trail must fade out for this many units + CNetworkVector( m_vecSkyboxOrigin ); // What's our skybox origin? + CNetworkVar( float, m_flSkyboxScale ); // What's our skybox scale? + + string_t m_iszSpriteName; + bool m_bAnimate; + bool m_bDrawForMoveParent; + +#if defined( CLIENT_DLL ) +public: + void SetUpdateTime(float setTo){ m_flUpdateTime = setTo; } +#endif +}; + +#endif // SPRITETRAIL_H diff --git a/game/shared/achievement_saverestore.h b/game/shared/achievement_saverestore.h new file mode 100644 index 0000000..c52e064 --- /dev/null +++ b/game/shared/achievement_saverestore.h @@ -0,0 +1,17 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ACHIEVEMENT_SAVERESTORE_H +#define ACHIEVEMENT_SAVERESTORE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +ISaveRestoreBlockHandler *GetAchievementSaveRestoreBlockHandler(); + +#endif // ACHIEVEMENT_SAVERESTORE_H diff --git a/game/shared/achievementmgr.h b/game/shared/achievementmgr.h new file mode 100644 index 0000000..c33261e --- /dev/null +++ b/game/shared/achievementmgr.h @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ACHIEVEMENTMGR_H +#define ACHIEVEMENTMGR_H +#ifdef _WIN32 +#pragma once +#endif +#include "baseachievement.h" +#include "GameEventListener.h" +#include "hl2orange.spa.h" +#include "iachievementmgr.h" +#include "utlmap.h" +#ifndef NO_STEAM +#include "steam/steam_api.h" +#endif + +#define THINK_CLEAR -1 + +class CAchievementMgr : public CAutoGameSystemPerFrame, public CGameEventListener, public IAchievementMgr +{ +public: + //============================================================================= + // HPE_BEGIN + // [dwenger] Steam Cloud Support + //============================================================================= + + enum SteamCloudPersisting + { + SteamCloudPersist_Off = 0, + SteamCloudPersist_On, + }; + + CAchievementMgr( SteamCloudPersisting ePersistToSteamCloud = SteamCloudPersist_Off ); + + //============================================================================= + // HPE_END + //============================================================================= + + virtual bool Init(); + virtual void PostInit(); + virtual void Shutdown(); + virtual void LevelInitPreEntity(); + virtual void LevelShutdownPreEntity(); + virtual void InitializeAchievements(); + virtual void Update( float frametime ); +#ifdef GAME_DLL + virtual void FrameUpdatePostEntityThink(); +#endif + + void OnMapEvent( const char *pchEventName ); + + // Interfaces exported to other dlls for achievement list queries + IAchievement* GetAchievementByIndex( int index ); + int GetAchievementCount(); + + CBaseAchievement *GetAchievementByID( int iAchievementID ); + CUtlMap &GetAchievements() { return m_mapAchievement; } + + CBaseAchievement *GetAchievementByName( const char *pchName ); + bool HasAchieved( const char *pchName ); + + void UploadUserData(); + void DownloadUserData(); + void SaveGlobalState( bool bAsync = false ); + void LoadGlobalState(); + void SaveGlobalStateIfDirty( bool bAsync = false ); + void EnsureGlobalStateLoaded(); + void AwardAchievement( int iAchievementID ); + void UpdateAchievement( int iAchievementID, int nData ); + void PreRestoreSavedGame(); + void PostRestoreSavedGame(); + void ResetAchievements(); + void ResetAchievement( int iAchievementID ); + void PrintAchievementStatus(); + float GetLastClassChangeTime() { return m_flLastClassChangeTime; } + float GetTeamplayStartTime() { return m_flTeamplayStartTime; } + int GetMiniroundsCompleted() { return m_iMiniroundsCompleted; } + const char *GetMapName() { return m_szMap; } + void OnAchievementEvent( int iAchievementID, int iCount = 1 ); + + void CheckMetaAchievements( void ); + + void SetDirty( bool bDirty ) + { + if (bDirty) + { + m_bGlobalStateDirty = true; + m_bSteamDataDirty = true; + } + } + + //============================================================================= + // HPE_END + //============================================================================= + + bool CheckAchievementsEnabled(); + bool LoggedIntoSteam() + { +#if !defined(NO_STEAM) + return ( steamapicontext->SteamUser() && steamapicontext->SteamUserStats() && steamapicontext->SteamUser()->BLoggedOn() ); +#else + return false; +#endif + } + float GetTimeLastUpload() { return m_flTimeLastSaved; } // time we last uploaded to Steam + + bool WereCheatsEverOn( void ) { return m_bCheatsEverOn; } + +#if !defined(NO_STEAM) + STEAM_CALLBACK( CAchievementMgr, Steam_OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived ); + STEAM_CALLBACK( CAchievementMgr, Steam_OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored ); +#endif + + void SetAchievementThink( CBaseAchievement *pAchievement, float flThinkTime ); + +private: + void FireGameEvent( IGameEvent *event ); + void OnKillEvent( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ); + void ResetAchievement_Internal( CBaseAchievement *pAchievement ); + void UpdateStateFromSteam_Internal(); + + CUtlMap m_mapAchievement; // map of all achievements + CUtlVector m_vecAchievement; // vector of all achievements for accessing by index + CUtlVector m_vecKillEventListeners; // vector of achievements that are listening for kill events + CUtlVector m_vecMapEventListeners; // vector of achievements that are listening for map events + CUtlVector m_vecComponentListeners; // vector of achievements that are listening for components that make up an achievement + CUtlMap m_mapMetaAchievement; // map of CAchievement_AchievedCount + + struct achievementthink_t + { + float m_flThinkTime; + CBaseAchievement *pAchievement; + }; + CUtlVector m_vecThinkListeners; // vector of achievements that are actively thinking + + float m_flLevelInitTime; + + float m_flLastClassChangeTime; // Time when player last changed class + float m_flTeamplayStartTime; // Time when player joined a non-spectating team. Not updated if she switches game teams; cleared if she joins spectator + float m_iMiniroundsCompleted; // # of minirounds played since game start (for maps that have minirounds) + char m_szMap[MAX_PATH]; // file base of map name, cached since we access it frequently in this form + bool m_bGlobalStateDirty; // do we have interesting state changes that needs to be saved? + bool m_bSteamDataDirty; // do we have changes to upload to Steamworks? + bool m_bGlobalStateLoaded; // have we loaded global state + bool m_bCheatsEverOn; // have cheats ever been turned on in this level + float m_flTimeLastSaved; // last time we uploaded to Steam + + //============================================================================= + // HPE_BEGIN + // [dwenger] Steam Cloud Support + //============================================================================= + + bool m_bPersistToSteamCloud; // true = persist data to steam cloud + + //============================================================================= + // HPE_END + //============================================================================= + + CUtlVector m_AchievementsAwarded; +}; + +// helper functions +const char *GetModelName( CBaseEntity *pBaseEntity ); + +#ifdef CLIENT_DLL +bool CalcPlayersOnFriendsList( int iMinPlayers ); +bool CalcHasNumClanPlayers( int iClanTeammates ); +int CalcPlayerCount(); +int CalcTeammateCount(); +#endif // CLIENT + +class IMatchmaking; +extern ConVar cc_achievement_debug; +extern IMatchmaking *matchmaking; + +#ifdef CLIENT_DLL +void MsgFunc_AchievementEvent( bf_read &msg ); +#endif // CLIENT_DLL +#endif // ACHIEVEMENTMGR_H diff --git a/game/shared/achievements_and_stats_interface.h b/game/shared/achievements_and_stats_interface.h new file mode 100644 index 0000000..a671902 --- /dev/null +++ b/game/shared/achievements_and_stats_interface.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ACHIEVEMENTSANDSTATSINTERFACE_H +#define ACHIEVEMENTSANDSTATSINTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Panel.h" +#include "vgui_controls/Panel.h" +#include "vgui_controls/PHandle.h" +#include "vgui_controls/MenuItem.h" +#include "vgui_controls/MessageDialog.h" +#include "vgui/ISurface.h" + +class AchievementsAndStatsInterface +{ +public: + AchievementsAndStatsInterface() { } + + virtual void CreatePanel( vgui::Panel* pParent ) {} + virtual void DisplayPanel() {} + virtual void ReleasePanel() {} + virtual int GetAchievementsPanelMinWidth( void ) const { return 0; } + +protected: + //----------------------------------------------------------------------------- + // Purpose: Positions a dialog on screen. + //----------------------------------------------------------------------------- + void PositionDialog(vgui::PHandle dlg) + { + if (!dlg.Get()) + return; + + int x, y, ww, wt, wide, tall; + vgui::surface()->GetWorkspaceBounds( x, y, ww, wt ); + dlg->GetSize(wide, tall); + + // Center it, keeping requested size + dlg->SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2)); + } +}; + + +#endif // ACHIEVEMENTSANDSTATSINTERFACE_H diff --git a/game/shared/activitylist.h b/game/shared/activitylist.h new file mode 100644 index 0000000..712c94e --- /dev/null +++ b/game/shared/activitylist.h @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ACTIVITYLIST_H +#define ACTIVITYLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +typedef struct activityentry_s activityentry_t; + +class CActivityRemap +{ +public: + + CActivityRemap() + { + pExtraBlock = NULL; + } + + void SetExtraKeyValueBlock ( KeyValues *pKVBlock ) + { + pExtraBlock = pKVBlock; + } + + KeyValues *GetExtraKeyValueBlock ( void ) { return pExtraBlock; } + + Activity activity; + Activity mappedActivity; + +private: + + KeyValues *pExtraBlock; +}; + + +class CActivityRemapCache +{ +public: + + CActivityRemapCache() + { + } + + CActivityRemapCache( const CActivityRemapCache& src ) + { + int c = src.m_cachedActivityRemaps.Count(); + for ( int i = 0; i < c; i++ ) + { + m_cachedActivityRemaps.AddToTail( src.m_cachedActivityRemaps[ i ] ); + } + } + + CActivityRemapCache& operator = ( const CActivityRemapCache& src ) + { + if ( this == &src ) + return *this; + + int c = src.m_cachedActivityRemaps.Count(); + for ( int i = 0; i < c; i++ ) + { + m_cachedActivityRemaps.AddToTail( src.m_cachedActivityRemaps[ i ] ); + } + + return *this; + } + + CUtlVector< CActivityRemap > m_cachedActivityRemaps; +}; + +void UTIL_LoadActivityRemapFile( const char *filename, const char *section, CUtlVector &entries ); + +//========================================================= +//========================================================= +extern void ActivityList_Init( void ); +extern void ActivityList_Free( void ); +extern bool ActivityList_RegisterSharedActivity( const char *pszActivityName, int iActivityIndex ); +extern Activity ActivityList_RegisterPrivateActivity( const char *pszActivityName ); +extern int ActivityList_IndexForName( const char *pszActivityName ); +extern const char *ActivityList_NameForIndex( int iActivityIndex ); +extern int ActivityList_HighestIndex(); + +// This macro guarantees that the names of each activity and the constant used to +// reference it in the code are identical. +#define REGISTER_SHARED_ACTIVITY( _n ) ActivityList_RegisterSharedActivity(#_n, _n); +#define REGISTER_PRIVATE_ACTIVITY( _n ) _n = ActivityList_RegisterPrivateActivity( #_n ); + +// Implemented in shared code +extern void ActivityList_RegisterSharedActivities( void ); + +class ISaveRestoreOps; +extern ISaveRestoreOps* ActivityDataOps(); + +#endif // ACTIVITYLIST_H diff --git a/game/shared/ai_activity.h b/game/shared/ai_activity.h new file mode 100644 index 0000000..0f5bba4 --- /dev/null +++ b/game/shared/ai_activity.h @@ -0,0 +1,2197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_ACTIVITY_H +#define AI_ACTIVITY_H +#ifdef _WIN32 +#pragma once +#endif + +#define ACTIVITY_NOT_AVAILABLE -1 + +typedef enum +{ + ACT_INVALID = -1, // So we have something more succint to check for than '-1' + ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity + ACT_IDLE, + ACT_TRANSITION, + ACT_COVER, // FIXME: obsolete? redundant with ACT_COVER_LOW? + ACT_COVER_MED, // FIXME: unsupported? + ACT_COVER_LOW, // FIXME: rename ACT_IDLE_CROUCH? + ACT_WALK, + ACT_WALK_AIM, + ACT_WALK_CROUCH, + ACT_WALK_CROUCH_AIM, + ACT_RUN, + ACT_RUN_AIM, + ACT_RUN_CROUCH, + ACT_RUN_CROUCH_AIM, + ACT_RUN_PROTECTED, + ACT_SCRIPT_CUSTOM_MOVE, + ACT_RANGE_ATTACK1, + ACT_RANGE_ATTACK2, + ACT_RANGE_ATTACK1_LOW, // FIXME: not used yet, crouched versions of the range attack + ACT_RANGE_ATTACK2_LOW, // FIXME: not used yet, crouched versions of the range attack + ACT_DIESIMPLE, + ACT_DIEBACKWARD, + ACT_DIEFORWARD, + ACT_DIEVIOLENT, + ACT_DIERAGDOLL, + ACT_FLY, // Fly (and flap if appropriate) + ACT_HOVER, + ACT_GLIDE, + ACT_SWIM, + ACT_JUMP, + ACT_HOP, // vertical jump + ACT_LEAP, // long forward jump + ACT_LAND, + ACT_CLIMB_UP, + ACT_CLIMB_DOWN, + ACT_CLIMB_DISMOUNT, + ACT_SHIPLADDER_UP, + ACT_SHIPLADDER_DOWN, + ACT_STRAFE_LEFT, + ACT_STRAFE_RIGHT, + ACT_ROLL_LEFT, // tuck and roll, left + ACT_ROLL_RIGHT, // tuck and roll, right + ACT_TURN_LEFT, // turn quickly left (stationary) + ACT_TURN_RIGHT, // turn quickly right (stationary) + ACT_CROUCH, // FIXME: obsolete? only used be soldier (the act of crouching down from a standing position) + ACT_CROUCHIDLE, // FIXME: obsolete? only used be soldier (holding body in crouched position (loops)) + ACT_STAND, // FIXME: obsolete? should be transition (the act of standing from a crouched position) + ACT_USE, + ACT_SIGNAL1, + ACT_SIGNAL2, + ACT_SIGNAL3, + + ACT_SIGNAL_ADVANCE, // Squad handsignals, specific. + ACT_SIGNAL_FORWARD, + ACT_SIGNAL_GROUP, + ACT_SIGNAL_HALT, + ACT_SIGNAL_LEFT, + ACT_SIGNAL_RIGHT, + ACT_SIGNAL_TAKECOVER, + + ACT_LOOKBACK_RIGHT, // look back over shoulder without turning around. + ACT_LOOKBACK_LEFT, + ACT_COWER, // FIXME: unused, should be more extreme version of crouching + ACT_SMALL_FLINCH, // FIXME: needed? shouldn't flinching be down with overlays? + ACT_BIG_FLINCH, + ACT_MELEE_ATTACK1, + ACT_MELEE_ATTACK2, + ACT_RELOAD, + ACT_RELOAD_START, + ACT_RELOAD_FINISH, + ACT_RELOAD_LOW, + ACT_ARM, // pull out gun, for instance + ACT_DISARM, // reholster gun + ACT_DROP_WEAPON, + ACT_DROP_WEAPON_SHOTGUN, + ACT_PICKUP_GROUND, // pick up something in front of you on the ground + ACT_PICKUP_RACK, // pick up something from a rack or shelf in front of you. + ACT_IDLE_ANGRY, // FIXME: being used as an combat ready idle? alternate idle animation in which the monster is clearly agitated. (loop) + + ACT_IDLE_RELAXED, + ACT_IDLE_STIMULATED, + ACT_IDLE_AGITATED, + ACT_IDLE_STEALTH, + ACT_IDLE_HURT, + + ACT_WALK_RELAXED, + ACT_WALK_STIMULATED, + ACT_WALK_AGITATED, + ACT_WALK_STEALTH, + + ACT_RUN_RELAXED, + ACT_RUN_STIMULATED, + ACT_RUN_AGITATED, + ACT_RUN_STEALTH, + + ACT_IDLE_AIM_RELAXED, + ACT_IDLE_AIM_STIMULATED, + ACT_IDLE_AIM_AGITATED, + ACT_IDLE_AIM_STEALTH, + + ACT_WALK_AIM_RELAXED, + ACT_WALK_AIM_STIMULATED, + ACT_WALK_AIM_AGITATED, + ACT_WALK_AIM_STEALTH, + + ACT_RUN_AIM_RELAXED, + ACT_RUN_AIM_STIMULATED, + ACT_RUN_AIM_AGITATED, + ACT_RUN_AIM_STEALTH, + + ACT_CROUCHIDLE_STIMULATED, + ACT_CROUCHIDLE_AIM_STIMULATED, + ACT_CROUCHIDLE_AGITATED, + + ACT_WALK_HURT, // limp (loop) + ACT_RUN_HURT, // limp (loop) + ACT_SPECIAL_ATTACK1, // very monster specific special attacks. + ACT_SPECIAL_ATTACK2, + ACT_COMBAT_IDLE, // FIXME: unused? agitated idle. + ACT_WALK_SCARED, + ACT_RUN_SCARED, + ACT_VICTORY_DANCE, // killed a player, do a victory dance. + ACT_DIE_HEADSHOT, // die, hit in head. + ACT_DIE_CHESTSHOT, // die, hit in chest + ACT_DIE_GUTSHOT, // die, hit in gut + ACT_DIE_BACKSHOT, // die, hit in back + ACT_FLINCH_HEAD, + ACT_FLINCH_CHEST, + ACT_FLINCH_STOMACH, + ACT_FLINCH_LEFTARM, + ACT_FLINCH_RIGHTARM, + ACT_FLINCH_LEFTLEG, + ACT_FLINCH_RIGHTLEG, + ACT_FLINCH_PHYSICS, + + ACT_IDLE_ON_FIRE, // ON FIRE animations + ACT_WALK_ON_FIRE, + ACT_RUN_ON_FIRE, + + ACT_RAPPEL_LOOP, // Rappel down a rope! + + ACT_180_LEFT, // 180 degree left turn + ACT_180_RIGHT, + + ACT_90_LEFT, // 90 degree turns + ACT_90_RIGHT, + + ACT_STEP_LEFT, // Single steps + ACT_STEP_RIGHT, + ACT_STEP_BACK, + ACT_STEP_FORE, + + ACT_GESTURE_RANGE_ATTACK1, + ACT_GESTURE_RANGE_ATTACK2, + ACT_GESTURE_MELEE_ATTACK1, + ACT_GESTURE_MELEE_ATTACK2, + ACT_GESTURE_RANGE_ATTACK1_LOW, // FIXME: not used yet, crouched versions of the range attack + ACT_GESTURE_RANGE_ATTACK2_LOW, // FIXME: not used yet, crouched versions of the range attack + + ACT_MELEE_ATTACK_SWING_GESTURE, + + ACT_GESTURE_SMALL_FLINCH, + ACT_GESTURE_BIG_FLINCH, + ACT_GESTURE_FLINCH_BLAST, // Startled by an explosion + ACT_GESTURE_FLINCH_BLAST_SHOTGUN, + ACT_GESTURE_FLINCH_BLAST_DAMAGED, // Damaged by an explosion + ACT_GESTURE_FLINCH_BLAST_DAMAGED_SHOTGUN, + ACT_GESTURE_FLINCH_HEAD, + ACT_GESTURE_FLINCH_CHEST, + ACT_GESTURE_FLINCH_STOMACH, + ACT_GESTURE_FLINCH_LEFTARM, + ACT_GESTURE_FLINCH_RIGHTARM, + ACT_GESTURE_FLINCH_LEFTLEG, + ACT_GESTURE_FLINCH_RIGHTLEG, + + ACT_GESTURE_TURN_LEFT, + ACT_GESTURE_TURN_RIGHT, + ACT_GESTURE_TURN_LEFT45, + ACT_GESTURE_TURN_RIGHT45, + ACT_GESTURE_TURN_LEFT90, + ACT_GESTURE_TURN_RIGHT90, + ACT_GESTURE_TURN_LEFT45_FLAT, + ACT_GESTURE_TURN_RIGHT45_FLAT, + ACT_GESTURE_TURN_LEFT90_FLAT, + ACT_GESTURE_TURN_RIGHT90_FLAT, + + // HALF-LIFE 1 compatability stuff goes here. Temporary! + ACT_BARNACLE_HIT, // barnacle tongue hits a monster + ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop ) + ACT_BARNACLE_CHOMP, // barnacle latches on to the monster + ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop ) + + // Sometimes, you just want to set an NPC's sequence to a sequence that doesn't actually + // have an activity. The AI will reset the NPC's sequence to whatever its IDEAL activity + // is, though. So if you set ideal activity to DO_NOT_DISTURB, the AI will not interfere + // with the NPC's current sequence. (SJB) + ACT_DO_NOT_DISTURB, + + // viewmodel (weapon) activities + // FIXME: move these to the specific viewmodels, no need to make global + ACT_VM_DRAW, + ACT_VM_HOLSTER, + ACT_VM_IDLE, + ACT_VM_FIDGET, + ACT_VM_PULLBACK, + ACT_VM_PULLBACK_HIGH, + ACT_VM_PULLBACK_LOW, + ACT_VM_THROW, + ACT_VM_PULLPIN, + ACT_VM_PRIMARYATTACK, // fire + ACT_VM_SECONDARYATTACK, // alt. fire + ACT_VM_RELOAD, + ACT_VM_RELOAD_START, + ACT_VM_RELOAD_FINISH, + ACT_VM_DRYFIRE, // fire with no ammo loaded. + ACT_VM_HITLEFT, // bludgeon, swing to left - hit (primary attk) + ACT_VM_HITLEFT2, // bludgeon, swing to left - hit (secondary attk) + ACT_VM_HITRIGHT, // bludgeon, swing to right - hit (primary attk) + ACT_VM_HITRIGHT2, // bludgeon, swing to right - hit (secondary attk) + ACT_VM_HITCENTER, // bludgeon, swing center - hit (primary attk) + ACT_VM_HITCENTER2, // bludgeon, swing center - hit (secondary attk) + ACT_VM_MISSLEFT, // bludgeon, swing to left - miss (primary attk) + ACT_VM_MISSLEFT2, // bludgeon, swing to left - miss (secondary attk) + ACT_VM_MISSRIGHT, // bludgeon, swing to right - miss (primary attk) + ACT_VM_MISSRIGHT2, // bludgeon, swing to right - miss (secondary attk) + ACT_VM_MISSCENTER, // bludgeon, swing center - miss (primary attk) + ACT_VM_MISSCENTER2, // bludgeon, swing center - miss (secondary attk) + ACT_VM_HAULBACK, // bludgeon, haul the weapon back for a hard strike (secondary attk) + ACT_VM_SWINGHARD, // bludgeon, release the hard strike (secondary attk) + ACT_VM_SWINGMISS, + ACT_VM_SWINGHIT, + ACT_VM_IDLE_TO_LOWERED, + ACT_VM_IDLE_LOWERED, + ACT_VM_LOWERED_TO_IDLE, + ACT_VM_RECOIL1, + ACT_VM_RECOIL2, + ACT_VM_RECOIL3, + ACT_VM_PICKUP, + ACT_VM_RELEASE, + + ACT_VM_ATTACH_SILENCER, + ACT_VM_DETACH_SILENCER, + + // TF2 Scout Pack + ACT_VM_DRAW_SPECIAL, + ACT_VM_HOLSTER_SPECIAL, + ACT_VM_IDLE_SPECIAL, + ACT_VM_PULLBACK_SPECIAL, + ACT_VM_PRIMARYATTACK_SPECIAL, + ACT_VM_SECONDARYATTACK_SPECIAL, + ACT_VM_HITCENTER_SPECIAL, + ACT_VM_SWINGHARD_SPECIAL, + ACT_VM_IDLE_TO_LOWERED_SPECIAL, + ACT_VM_IDLE_LOWERED_SPECIAL, + ACT_VM_LOWERED_TO_IDLE_SPECIAL, + + ACT_FISTS_VM_HITLEFT, + ACT_FISTS_VM_HITRIGHT, + ACT_FISTS_VM_SWINGHARD, + ACT_FISTS_VM_IDLE, + ACT_FISTS_VM_DRAW, + +//=========================== +// HL2 Specific Activities +//=========================== + // SLAM Specialty Activities + ACT_SLAM_STICKWALL_IDLE, + ACT_SLAM_STICKWALL_ND_IDLE, + ACT_SLAM_STICKWALL_ATTACH, + ACT_SLAM_STICKWALL_ATTACH2, + ACT_SLAM_STICKWALL_ND_ATTACH, + ACT_SLAM_STICKWALL_ND_ATTACH2, + ACT_SLAM_STICKWALL_DETONATE, + ACT_SLAM_STICKWALL_DETONATOR_HOLSTER, + ACT_SLAM_STICKWALL_DRAW, + ACT_SLAM_STICKWALL_ND_DRAW, + ACT_SLAM_STICKWALL_TO_THROW, + ACT_SLAM_STICKWALL_TO_THROW_ND, + ACT_SLAM_STICKWALL_TO_TRIPMINE_ND, + ACT_SLAM_THROW_IDLE, + ACT_SLAM_THROW_ND_IDLE, + ACT_SLAM_THROW_THROW, + ACT_SLAM_THROW_THROW2, + ACT_SLAM_THROW_THROW_ND, + ACT_SLAM_THROW_THROW_ND2, + ACT_SLAM_THROW_DRAW, + ACT_SLAM_THROW_ND_DRAW, + ACT_SLAM_THROW_TO_STICKWALL, + ACT_SLAM_THROW_TO_STICKWALL_ND, + ACT_SLAM_THROW_DETONATE, + ACT_SLAM_THROW_DETONATOR_HOLSTER, + ACT_SLAM_THROW_TO_TRIPMINE_ND, + ACT_SLAM_TRIPMINE_IDLE, + ACT_SLAM_TRIPMINE_DRAW, + ACT_SLAM_TRIPMINE_ATTACH, + ACT_SLAM_TRIPMINE_ATTACH2, + ACT_SLAM_TRIPMINE_TO_STICKWALL_ND, + ACT_SLAM_TRIPMINE_TO_THROW_ND, + ACT_SLAM_DETONATOR_IDLE, + ACT_SLAM_DETONATOR_DRAW, + ACT_SLAM_DETONATOR_DETONATE, + ACT_SLAM_DETONATOR_HOLSTER, + ACT_SLAM_DETONATOR_STICKWALL_DRAW, + ACT_SLAM_DETONATOR_THROW_DRAW, + + // Shotgun Specialty Activities + ACT_SHOTGUN_RELOAD_START, + ACT_SHOTGUN_RELOAD_FINISH, + ACT_SHOTGUN_PUMP, + + // SMG2 special activities + ACT_SMG2_IDLE2, + ACT_SMG2_FIRE2, + ACT_SMG2_DRAW2, + ACT_SMG2_RELOAD2, + ACT_SMG2_DRYFIRE2, + ACT_SMG2_TOAUTO, + ACT_SMG2_TOBURST, + + // Physcannon special activities + ACT_PHYSCANNON_UPGRADE, + + // weapon override activities + ACT_RANGE_ATTACK_AR1, + ACT_RANGE_ATTACK_AR2, + ACT_RANGE_ATTACK_AR2_LOW, + ACT_RANGE_ATTACK_AR2_GRENADE, + ACT_RANGE_ATTACK_HMG1, + ACT_RANGE_ATTACK_ML, + ACT_RANGE_ATTACK_SMG1, + ACT_RANGE_ATTACK_SMG1_LOW, + ACT_RANGE_ATTACK_SMG2, + ACT_RANGE_ATTACK_SHOTGUN, + ACT_RANGE_ATTACK_SHOTGUN_LOW, + ACT_RANGE_ATTACK_PISTOL, + ACT_RANGE_ATTACK_PISTOL_LOW, + ACT_RANGE_ATTACK_SLAM, + ACT_RANGE_ATTACK_TRIPWIRE, + ACT_RANGE_ATTACK_THROW, + ACT_RANGE_ATTACK_SNIPER_RIFLE, + ACT_RANGE_ATTACK_RPG, + ACT_MELEE_ATTACK_SWING, + + ACT_RANGE_AIM_LOW, + ACT_RANGE_AIM_SMG1_LOW, + ACT_RANGE_AIM_PISTOL_LOW, + ACT_RANGE_AIM_AR2_LOW, + + ACT_COVER_PISTOL_LOW, + ACT_COVER_SMG1_LOW, + + // weapon override activities + ACT_GESTURE_RANGE_ATTACK_AR1, + ACT_GESTURE_RANGE_ATTACK_AR2, + ACT_GESTURE_RANGE_ATTACK_AR2_GRENADE, + ACT_GESTURE_RANGE_ATTACK_HMG1, + ACT_GESTURE_RANGE_ATTACK_ML, + ACT_GESTURE_RANGE_ATTACK_SMG1, + ACT_GESTURE_RANGE_ATTACK_SMG1_LOW, + ACT_GESTURE_RANGE_ATTACK_SMG2, + ACT_GESTURE_RANGE_ATTACK_SHOTGUN, + ACT_GESTURE_RANGE_ATTACK_PISTOL, + ACT_GESTURE_RANGE_ATTACK_PISTOL_LOW, + ACT_GESTURE_RANGE_ATTACK_SLAM, + ACT_GESTURE_RANGE_ATTACK_TRIPWIRE, + ACT_GESTURE_RANGE_ATTACK_THROW, + ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE, + ACT_GESTURE_MELEE_ATTACK_SWING, + + ACT_IDLE_RIFLE, + ACT_IDLE_SMG1, + ACT_IDLE_ANGRY_SMG1, + ACT_IDLE_PISTOL, + ACT_IDLE_ANGRY_PISTOL, + ACT_IDLE_ANGRY_SHOTGUN, + ACT_IDLE_STEALTH_PISTOL, + + ACT_IDLE_PACKAGE, + ACT_WALK_PACKAGE, + ACT_IDLE_SUITCASE, + ACT_WALK_SUITCASE, + + ACT_IDLE_SMG1_RELAXED, + ACT_IDLE_SMG1_STIMULATED, + ACT_WALK_RIFLE_RELAXED, + ACT_RUN_RIFLE_RELAXED, + ACT_WALK_RIFLE_STIMULATED, + ACT_RUN_RIFLE_STIMULATED, + + ACT_IDLE_AIM_RIFLE_STIMULATED, + ACT_WALK_AIM_RIFLE_STIMULATED, + ACT_RUN_AIM_RIFLE_STIMULATED, + + ACT_IDLE_SHOTGUN_RELAXED, + ACT_IDLE_SHOTGUN_STIMULATED, + ACT_IDLE_SHOTGUN_AGITATED, + + // Policing activities + ACT_WALK_ANGRY, + ACT_POLICE_HARASS1, + ACT_POLICE_HARASS2, + + // Manned guns + ACT_IDLE_MANNEDGUN, + + // Melee weapon + ACT_IDLE_MELEE, + ACT_IDLE_ANGRY_MELEE, + + // RPG activities + ACT_IDLE_RPG_RELAXED, + ACT_IDLE_RPG, + ACT_IDLE_ANGRY_RPG, + ACT_COVER_LOW_RPG, + ACT_WALK_RPG, + ACT_RUN_RPG, + ACT_WALK_CROUCH_RPG, + ACT_RUN_CROUCH_RPG, + ACT_WALK_RPG_RELAXED, + ACT_RUN_RPG_RELAXED, + + ACT_WALK_RIFLE, + ACT_WALK_AIM_RIFLE, + ACT_WALK_CROUCH_RIFLE, + ACT_WALK_CROUCH_AIM_RIFLE, + ACT_RUN_RIFLE, + ACT_RUN_AIM_RIFLE, + ACT_RUN_CROUCH_RIFLE, + ACT_RUN_CROUCH_AIM_RIFLE, + ACT_RUN_STEALTH_PISTOL, + + ACT_WALK_AIM_SHOTGUN, + ACT_RUN_AIM_SHOTGUN, + + ACT_WALK_PISTOL, + ACT_RUN_PISTOL, + ACT_WALK_AIM_PISTOL, + ACT_RUN_AIM_PISTOL, + ACT_WALK_STEALTH_PISTOL, + ACT_WALK_AIM_STEALTH_PISTOL, + ACT_RUN_AIM_STEALTH_PISTOL, + + // Reloads + ACT_RELOAD_PISTOL, + ACT_RELOAD_PISTOL_LOW, + ACT_RELOAD_SMG1, + ACT_RELOAD_SMG1_LOW, + ACT_RELOAD_SHOTGUN, + ACT_RELOAD_SHOTGUN_LOW, + + ACT_GESTURE_RELOAD, + ACT_GESTURE_RELOAD_PISTOL, + ACT_GESTURE_RELOAD_SMG1, + ACT_GESTURE_RELOAD_SHOTGUN, + + // Busy animations + ACT_BUSY_LEAN_LEFT, + ACT_BUSY_LEAN_LEFT_ENTRY, + ACT_BUSY_LEAN_LEFT_EXIT, + ACT_BUSY_LEAN_BACK, + ACT_BUSY_LEAN_BACK_ENTRY, + ACT_BUSY_LEAN_BACK_EXIT, + ACT_BUSY_SIT_GROUND, + ACT_BUSY_SIT_GROUND_ENTRY, + ACT_BUSY_SIT_GROUND_EXIT, + ACT_BUSY_SIT_CHAIR, + ACT_BUSY_SIT_CHAIR_ENTRY, + ACT_BUSY_SIT_CHAIR_EXIT, + ACT_BUSY_STAND, + ACT_BUSY_QUEUE, + + // Dodge animations + ACT_DUCK_DODGE, + + // For NPCs being lifted/eaten by barnacles: + // being swallowed by a barnacle + ACT_DIE_BARNACLE_SWALLOW, + // being lifted by a barnacle + ACT_GESTURE_BARNACLE_STRANGLE, + + ACT_PHYSCANNON_DETACH, // An activity to be played if we're picking this up with the physcannon + ACT_PHYSCANNON_ANIMATE, // An activity to be played by an object being picked up with the physcannon, but has different behavior to DETACH + ACT_PHYSCANNON_ANIMATE_PRE, // An activity to be played by an object being picked up with the physcannon, before playing the ACT_PHYSCANNON_ANIMATE + ACT_PHYSCANNON_ANIMATE_POST,// An activity to be played by an object being picked up with the physcannon, after playing the ACT_PHYSCANNON_ANIMATE + + ACT_DIE_FRONTSIDE, + ACT_DIE_RIGHTSIDE, + ACT_DIE_BACKSIDE, + ACT_DIE_LEFTSIDE, + + ACT_OPEN_DOOR, + + // Dynamic interactions + ACT_DI_ALYX_ZOMBIE_MELEE, + ACT_DI_ALYX_ZOMBIE_TORSO_MELEE, + ACT_DI_ALYX_HEADCRAB_MELEE, + ACT_DI_ALYX_ANTLION, + + ACT_DI_ALYX_ZOMBIE_SHOTGUN64, + ACT_DI_ALYX_ZOMBIE_SHOTGUN26, + + ACT_READINESS_RELAXED_TO_STIMULATED, + ACT_READINESS_RELAXED_TO_STIMULATED_WALK, + ACT_READINESS_AGITATED_TO_STIMULATED, + ACT_READINESS_STIMULATED_TO_RELAXED, + + ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED, + ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK, + ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, + ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, + + ACT_IDLE_CARRY, + ACT_WALK_CARRY, + +//=========================== +// TF2 Specific Activities +//=========================== + ACT_STARTDYING, + ACT_DYINGLOOP, + ACT_DYINGTODEAD, + + ACT_RIDE_MANNED_GUN, + + // All viewmodels + ACT_VM_SPRINT_ENTER, + ACT_VM_SPRINT_IDLE, + ACT_VM_SPRINT_LEAVE, + + // Looping weapon firing + ACT_FIRE_START, + ACT_FIRE_LOOP, + ACT_FIRE_END, + + ACT_CROUCHING_GRENADEIDLE, + ACT_CROUCHING_GRENADEREADY, + ACT_CROUCHING_PRIMARYATTACK, + ACT_OVERLAY_GRENADEIDLE, + ACT_OVERLAY_GRENADEREADY, + ACT_OVERLAY_PRIMARYATTACK, + ACT_OVERLAY_SHIELD_UP, + ACT_OVERLAY_SHIELD_DOWN, + ACT_OVERLAY_SHIELD_UP_IDLE, + ACT_OVERLAY_SHIELD_ATTACK, + ACT_OVERLAY_SHIELD_KNOCKBACK, + ACT_SHIELD_UP, + ACT_SHIELD_DOWN, + ACT_SHIELD_UP_IDLE, + ACT_SHIELD_ATTACK, + ACT_SHIELD_KNOCKBACK, + ACT_CROUCHING_SHIELD_UP, + ACT_CROUCHING_SHIELD_DOWN, + ACT_CROUCHING_SHIELD_UP_IDLE, + ACT_CROUCHING_SHIELD_ATTACK, + ACT_CROUCHING_SHIELD_KNOCKBACK, + + // turning in place + ACT_TURNRIGHT45, + ACT_TURNLEFT45, + + ACT_TURN, + + ACT_OBJ_ASSEMBLING, + ACT_OBJ_DISMANTLING, + ACT_OBJ_STARTUP, + ACT_OBJ_RUNNING, + ACT_OBJ_IDLE, + ACT_OBJ_PLACING, + ACT_OBJ_DETERIORATING, + ACT_OBJ_UPGRADING, + + // Deploy + ACT_DEPLOY, + ACT_DEPLOY_IDLE, + ACT_UNDEPLOY, + +//=========================== +// HL1 Specific Activities +//=========================== + // Grenades + ACT_GRENADE_ROLL, + ACT_GRENADE_TOSS, + + // Hand grenade + ACT_HANDGRENADE_THROW1, + ACT_HANDGRENADE_THROW2, + ACT_HANDGRENADE_THROW3, + + // Shotgun + ACT_SHOTGUN_IDLE_DEEP, + ACT_SHOTGUN_IDLE4, + + // Glock + ACT_GLOCK_SHOOTEMPTY, + ACT_GLOCK_SHOOT_RELOAD, + + // RPG + ACT_RPG_DRAW_UNLOADED, + ACT_RPG_HOLSTER_UNLOADED, + ACT_RPG_IDLE_UNLOADED, + ACT_RPG_FIDGET_UNLOADED, + + // Crossbow + ACT_CROSSBOW_DRAW_UNLOADED, + ACT_CROSSBOW_IDLE_UNLOADED, + ACT_CROSSBOW_FIDGET_UNLOADED, + + // Gauss + ACT_GAUSS_SPINUP, + ACT_GAUSS_SPINCYCLE, + + // Tripmine + ACT_TRIPMINE_GROUND, + ACT_TRIPMINE_WORLD, + +//=========================== +// CSPort Specific Activities +//=========================== + + ACT_VM_PRIMARYATTACK_SILENCED, // fire + ACT_VM_RELOAD_SILENCED, + ACT_VM_DRYFIRE_SILENCED, // fire with no ammo loaded. + ACT_VM_IDLE_SILENCED, + ACT_VM_DRAW_SILENCED, + ACT_VM_IDLE_EMPTY_LEFT, + ACT_VM_DRYFIRE_LEFT, + + ACT_PLAYER_IDLE_FIRE, + ACT_PLAYER_CROUCH_FIRE, + ACT_PLAYER_CROUCH_WALK_FIRE, + ACT_PLAYER_WALK_FIRE, + ACT_PLAYER_RUN_FIRE, + + ACT_IDLETORUN, + ACT_RUNTOIDLE, + + +//=========================== +// DoD Specific Activities +//=========================== + ACT_SPRINT, + + ACT_GET_DOWN_STAND, + ACT_GET_UP_STAND, + ACT_GET_DOWN_CROUCH, + ACT_GET_UP_CROUCH, + ACT_PRONE_FORWARD, + ACT_PRONE_IDLE, + + ACT_DEEPIDLE1, + ACT_DEEPIDLE2, + ACT_DEEPIDLE3, + ACT_DEEPIDLE4, + + ACT_VM_RELOAD_DEPLOYED, + ACT_VM_RELOAD_IDLE, + + ACT_VM_DRAW_DEPLOYED, + + //Weapon is empty activities + ACT_VM_DRAW_EMPTY, + ACT_VM_PRIMARYATTACK_EMPTY, + ACT_VM_RELOAD_EMPTY, + ACT_VM_IDLE_EMPTY, + ACT_VM_IDLE_DEPLOYED_EMPTY, + + ACT_VM_IDLE_8, + ACT_VM_IDLE_7, + ACT_VM_IDLE_6, + ACT_VM_IDLE_5, + ACT_VM_IDLE_4, + ACT_VM_IDLE_3, + ACT_VM_IDLE_2, + ACT_VM_IDLE_1, + + ACT_VM_IDLE_DEPLOYED, + ACT_VM_IDLE_DEPLOYED_8, + ACT_VM_IDLE_DEPLOYED_7, + ACT_VM_IDLE_DEPLOYED_6, + ACT_VM_IDLE_DEPLOYED_5, + ACT_VM_IDLE_DEPLOYED_4, + ACT_VM_IDLE_DEPLOYED_3, + ACT_VM_IDLE_DEPLOYED_2, + ACT_VM_IDLE_DEPLOYED_1, + + // Animation from prone idle to standing/crouch idle. Number designates bullets left + ACT_VM_UNDEPLOY, + ACT_VM_UNDEPLOY_8, + ACT_VM_UNDEPLOY_7, + ACT_VM_UNDEPLOY_6, + ACT_VM_UNDEPLOY_5, + ACT_VM_UNDEPLOY_4, + ACT_VM_UNDEPLOY_3, + ACT_VM_UNDEPLOY_2, + ACT_VM_UNDEPLOY_1, + ACT_VM_UNDEPLOY_EMPTY, + + // Animation from standing/crouch idle to prone idle. Number designates bullets left + ACT_VM_DEPLOY, + ACT_VM_DEPLOY_8, + ACT_VM_DEPLOY_7, + ACT_VM_DEPLOY_6, + ACT_VM_DEPLOY_5, + ACT_VM_DEPLOY_4, + ACT_VM_DEPLOY_3, + ACT_VM_DEPLOY_2, + ACT_VM_DEPLOY_1, + ACT_VM_DEPLOY_EMPTY, + + // Shooting animations for standing/crouch position. Number designates bullets left at START of animation + ACT_VM_PRIMARYATTACK_8, + ACT_VM_PRIMARYATTACK_7, + ACT_VM_PRIMARYATTACK_6, + ACT_VM_PRIMARYATTACK_5, + ACT_VM_PRIMARYATTACK_4, + ACT_VM_PRIMARYATTACK_3, + ACT_VM_PRIMARYATTACK_2, + ACT_VM_PRIMARYATTACK_1, + + // Shooting animations for prone position. Number designates bullets left at START of animation + ACT_VM_PRIMARYATTACK_DEPLOYED, + ACT_VM_PRIMARYATTACK_DEPLOYED_8, + ACT_VM_PRIMARYATTACK_DEPLOYED_7, + ACT_VM_PRIMARYATTACK_DEPLOYED_6, + ACT_VM_PRIMARYATTACK_DEPLOYED_5, + ACT_VM_PRIMARYATTACK_DEPLOYED_4, + ACT_VM_PRIMARYATTACK_DEPLOYED_3, + ACT_VM_PRIMARYATTACK_DEPLOYED_2, + ACT_VM_PRIMARYATTACK_DEPLOYED_1, + ACT_VM_PRIMARYATTACK_DEPLOYED_EMPTY, + + // Player anim ACTs + ACT_DOD_DEPLOYED, + ACT_DOD_PRONE_DEPLOYED, + ACT_DOD_IDLE_ZOOMED, + ACT_DOD_WALK_ZOOMED, + ACT_DOD_CROUCH_ZOOMED, + ACT_DOD_CROUCHWALK_ZOOMED, + ACT_DOD_PRONE_ZOOMED, + ACT_DOD_PRONE_FORWARD_ZOOMED, + ACT_DOD_PRIMARYATTACK_DEPLOYED, + ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED, + ACT_DOD_RELOAD_DEPLOYED, + ACT_DOD_RELOAD_PRONE_DEPLOYED, + ACT_DOD_PRIMARYATTACK_PRONE, + ACT_DOD_SECONDARYATTACK_PRONE, + ACT_DOD_RELOAD_CROUCH, + ACT_DOD_RELOAD_PRONE, + ACT_DOD_STAND_IDLE, + ACT_DOD_STAND_AIM, + ACT_DOD_CROUCH_IDLE, + ACT_DOD_CROUCH_AIM, + ACT_DOD_CROUCHWALK_IDLE, + ACT_DOD_CROUCHWALK_AIM, + ACT_DOD_WALK_IDLE, + ACT_DOD_WALK_AIM, + ACT_DOD_RUN_IDLE, + ACT_DOD_RUN_AIM, + + // Positions + ACT_DOD_STAND_AIM_PISTOL, + ACT_DOD_CROUCH_AIM_PISTOL, + ACT_DOD_CROUCHWALK_AIM_PISTOL, + ACT_DOD_WALK_AIM_PISTOL, + ACT_DOD_RUN_AIM_PISTOL, + ACT_DOD_PRONE_AIM_PISTOL, + ACT_DOD_STAND_IDLE_PISTOL, + ACT_DOD_CROUCH_IDLE_PISTOL, + ACT_DOD_CROUCHWALK_IDLE_PISTOL, + ACT_DOD_WALK_IDLE_PISTOL, + ACT_DOD_RUN_IDLE_PISTOL, + ACT_DOD_SPRINT_IDLE_PISTOL, + ACT_DOD_PRONEWALK_IDLE_PISTOL, + + ACT_DOD_STAND_AIM_C96, + ACT_DOD_CROUCH_AIM_C96, + ACT_DOD_CROUCHWALK_AIM_C96, + ACT_DOD_WALK_AIM_C96, + ACT_DOD_RUN_AIM_C96, + ACT_DOD_PRONE_AIM_C96, + ACT_DOD_STAND_IDLE_C96, + ACT_DOD_CROUCH_IDLE_C96, + ACT_DOD_CROUCHWALK_IDLE_C96, + ACT_DOD_WALK_IDLE_C96, + ACT_DOD_RUN_IDLE_C96, + ACT_DOD_SPRINT_IDLE_C96, + ACT_DOD_PRONEWALK_IDLE_C96, + + ACT_DOD_STAND_AIM_RIFLE, + ACT_DOD_CROUCH_AIM_RIFLE, + ACT_DOD_CROUCHWALK_AIM_RIFLE, + ACT_DOD_WALK_AIM_RIFLE, + ACT_DOD_RUN_AIM_RIFLE, + ACT_DOD_PRONE_AIM_RIFLE, + ACT_DOD_STAND_IDLE_RIFLE, + ACT_DOD_CROUCH_IDLE_RIFLE, + ACT_DOD_CROUCHWALK_IDLE_RIFLE, + ACT_DOD_WALK_IDLE_RIFLE, + ACT_DOD_RUN_IDLE_RIFLE, + ACT_DOD_SPRINT_IDLE_RIFLE, + ACT_DOD_PRONEWALK_IDLE_RIFLE, + + ACT_DOD_STAND_AIM_BOLT, + ACT_DOD_CROUCH_AIM_BOLT, + ACT_DOD_CROUCHWALK_AIM_BOLT, + ACT_DOD_WALK_AIM_BOLT, + ACT_DOD_RUN_AIM_BOLT, + ACT_DOD_PRONE_AIM_BOLT, + ACT_DOD_STAND_IDLE_BOLT, + ACT_DOD_CROUCH_IDLE_BOLT, + ACT_DOD_CROUCHWALK_IDLE_BOLT, + ACT_DOD_WALK_IDLE_BOLT, + ACT_DOD_RUN_IDLE_BOLT, + ACT_DOD_SPRINT_IDLE_BOLT, + ACT_DOD_PRONEWALK_IDLE_BOLT, + + ACT_DOD_STAND_AIM_TOMMY, + ACT_DOD_CROUCH_AIM_TOMMY, + ACT_DOD_CROUCHWALK_AIM_TOMMY, + ACT_DOD_WALK_AIM_TOMMY, + ACT_DOD_RUN_AIM_TOMMY, + ACT_DOD_PRONE_AIM_TOMMY, + ACT_DOD_STAND_IDLE_TOMMY, + ACT_DOD_CROUCH_IDLE_TOMMY, + ACT_DOD_CROUCHWALK_IDLE_TOMMY, + ACT_DOD_WALK_IDLE_TOMMY, + ACT_DOD_RUN_IDLE_TOMMY, + ACT_DOD_SPRINT_IDLE_TOMMY, + ACT_DOD_PRONEWALK_IDLE_TOMMY, + + ACT_DOD_STAND_AIM_MP40, + ACT_DOD_CROUCH_AIM_MP40, + ACT_DOD_CROUCHWALK_AIM_MP40, + ACT_DOD_WALK_AIM_MP40, + ACT_DOD_RUN_AIM_MP40, + ACT_DOD_PRONE_AIM_MP40, + ACT_DOD_STAND_IDLE_MP40, + ACT_DOD_CROUCH_IDLE_MP40, + ACT_DOD_CROUCHWALK_IDLE_MP40, + ACT_DOD_WALK_IDLE_MP40, + ACT_DOD_RUN_IDLE_MP40, + ACT_DOD_SPRINT_IDLE_MP40, + ACT_DOD_PRONEWALK_IDLE_MP40, + + ACT_DOD_STAND_AIM_MP44, + ACT_DOD_CROUCH_AIM_MP44, + ACT_DOD_CROUCHWALK_AIM_MP44, + ACT_DOD_WALK_AIM_MP44, + ACT_DOD_RUN_AIM_MP44, + ACT_DOD_PRONE_AIM_MP44, + ACT_DOD_STAND_IDLE_MP44, + ACT_DOD_CROUCH_IDLE_MP44, + ACT_DOD_CROUCHWALK_IDLE_MP44, + ACT_DOD_WALK_IDLE_MP44, + ACT_DOD_RUN_IDLE_MP44, + ACT_DOD_SPRINT_IDLE_MP44, + ACT_DOD_PRONEWALK_IDLE_MP44, + + ACT_DOD_STAND_AIM_GREASE, + ACT_DOD_CROUCH_AIM_GREASE, + ACT_DOD_CROUCHWALK_AIM_GREASE, + ACT_DOD_WALK_AIM_GREASE, + ACT_DOD_RUN_AIM_GREASE, + ACT_DOD_PRONE_AIM_GREASE, + ACT_DOD_STAND_IDLE_GREASE, + ACT_DOD_CROUCH_IDLE_GREASE, + ACT_DOD_CROUCHWALK_IDLE_GREASE, + ACT_DOD_WALK_IDLE_GREASE, + ACT_DOD_RUN_IDLE_GREASE, + ACT_DOD_SPRINT_IDLE_GREASE, + ACT_DOD_PRONEWALK_IDLE_GREASE, + + ACT_DOD_STAND_AIM_MG, + ACT_DOD_CROUCH_AIM_MG, + ACT_DOD_CROUCHWALK_AIM_MG, + ACT_DOD_WALK_AIM_MG, + ACT_DOD_RUN_AIM_MG, + ACT_DOD_PRONE_AIM_MG, + ACT_DOD_STAND_IDLE_MG, + ACT_DOD_CROUCH_IDLE_MG, + ACT_DOD_CROUCHWALK_IDLE_MG, + ACT_DOD_WALK_IDLE_MG, + ACT_DOD_RUN_IDLE_MG, + ACT_DOD_SPRINT_IDLE_MG, + ACT_DOD_PRONEWALK_IDLE_MG, + + ACT_DOD_STAND_AIM_30CAL, + ACT_DOD_CROUCH_AIM_30CAL, + ACT_DOD_CROUCHWALK_AIM_30CAL, + ACT_DOD_WALK_AIM_30CAL, + ACT_DOD_RUN_AIM_30CAL, + ACT_DOD_PRONE_AIM_30CAL, + ACT_DOD_STAND_IDLE_30CAL, + ACT_DOD_CROUCH_IDLE_30CAL, + ACT_DOD_CROUCHWALK_IDLE_30CAL, + ACT_DOD_WALK_IDLE_30CAL, + ACT_DOD_RUN_IDLE_30CAL, + ACT_DOD_SPRINT_IDLE_30CAL, + ACT_DOD_PRONEWALK_IDLE_30CAL, + + ACT_DOD_STAND_AIM_GREN_FRAG, + ACT_DOD_CROUCH_AIM_GREN_FRAG, + ACT_DOD_CROUCHWALK_AIM_GREN_FRAG, + ACT_DOD_WALK_AIM_GREN_FRAG, + ACT_DOD_RUN_AIM_GREN_FRAG, + ACT_DOD_PRONE_AIM_GREN_FRAG, + ACT_DOD_SPRINT_AIM_GREN_FRAG, + ACT_DOD_PRONEWALK_AIM_GREN_FRAG, + ACT_DOD_STAND_AIM_GREN_STICK, + ACT_DOD_CROUCH_AIM_GREN_STICK, + ACT_DOD_CROUCHWALK_AIM_GREN_STICK, + ACT_DOD_WALK_AIM_GREN_STICK, + ACT_DOD_RUN_AIM_GREN_STICK, + ACT_DOD_PRONE_AIM_GREN_STICK, + ACT_DOD_SPRINT_AIM_GREN_STICK, + ACT_DOD_PRONEWALK_AIM_GREN_STICK, + + ACT_DOD_STAND_AIM_KNIFE, + ACT_DOD_CROUCH_AIM_KNIFE, + ACT_DOD_CROUCHWALK_AIM_KNIFE, + ACT_DOD_WALK_AIM_KNIFE, + ACT_DOD_RUN_AIM_KNIFE, + ACT_DOD_PRONE_AIM_KNIFE, + ACT_DOD_SPRINT_AIM_KNIFE, + ACT_DOD_PRONEWALK_AIM_KNIFE, + + ACT_DOD_STAND_AIM_SPADE, + ACT_DOD_CROUCH_AIM_SPADE, + ACT_DOD_CROUCHWALK_AIM_SPADE, + ACT_DOD_WALK_AIM_SPADE, + ACT_DOD_RUN_AIM_SPADE, + ACT_DOD_PRONE_AIM_SPADE, + ACT_DOD_SPRINT_AIM_SPADE, + ACT_DOD_PRONEWALK_AIM_SPADE, + + ACT_DOD_STAND_AIM_BAZOOKA, + ACT_DOD_CROUCH_AIM_BAZOOKA, + ACT_DOD_CROUCHWALK_AIM_BAZOOKA, + ACT_DOD_WALK_AIM_BAZOOKA, + ACT_DOD_RUN_AIM_BAZOOKA, + ACT_DOD_PRONE_AIM_BAZOOKA, + ACT_DOD_STAND_IDLE_BAZOOKA, + ACT_DOD_CROUCH_IDLE_BAZOOKA, + ACT_DOD_CROUCHWALK_IDLE_BAZOOKA, + ACT_DOD_WALK_IDLE_BAZOOKA, + ACT_DOD_RUN_IDLE_BAZOOKA, + ACT_DOD_SPRINT_IDLE_BAZOOKA, + ACT_DOD_PRONEWALK_IDLE_BAZOOKA, + + ACT_DOD_STAND_AIM_PSCHRECK, + ACT_DOD_CROUCH_AIM_PSCHRECK, + ACT_DOD_CROUCHWALK_AIM_PSCHRECK, + ACT_DOD_WALK_AIM_PSCHRECK, + ACT_DOD_RUN_AIM_PSCHRECK, + ACT_DOD_PRONE_AIM_PSCHRECK, + ACT_DOD_STAND_IDLE_PSCHRECK, + ACT_DOD_CROUCH_IDLE_PSCHRECK, + ACT_DOD_CROUCHWALK_IDLE_PSCHRECK, + ACT_DOD_WALK_IDLE_PSCHRECK, + ACT_DOD_RUN_IDLE_PSCHRECK, + ACT_DOD_SPRINT_IDLE_PSCHRECK, + ACT_DOD_PRONEWALK_IDLE_PSCHRECK, + + ACT_DOD_STAND_AIM_BAR, + ACT_DOD_CROUCH_AIM_BAR, + ACT_DOD_CROUCHWALK_AIM_BAR, + ACT_DOD_WALK_AIM_BAR, + ACT_DOD_RUN_AIM_BAR, + ACT_DOD_PRONE_AIM_BAR, + ACT_DOD_STAND_IDLE_BAR, + ACT_DOD_CROUCH_IDLE_BAR, + ACT_DOD_CROUCHWALK_IDLE_BAR, + ACT_DOD_WALK_IDLE_BAR, + ACT_DOD_RUN_IDLE_BAR, + ACT_DOD_SPRINT_IDLE_BAR, + ACT_DOD_PRONEWALK_IDLE_BAR, + + // Zoomed aims + ACT_DOD_STAND_ZOOM_RIFLE, + ACT_DOD_CROUCH_ZOOM_RIFLE, + ACT_DOD_CROUCHWALK_ZOOM_RIFLE, + ACT_DOD_WALK_ZOOM_RIFLE, + ACT_DOD_RUN_ZOOM_RIFLE, + ACT_DOD_PRONE_ZOOM_RIFLE, + + ACT_DOD_STAND_ZOOM_BOLT, + ACT_DOD_CROUCH_ZOOM_BOLT, + ACT_DOD_CROUCHWALK_ZOOM_BOLT, + ACT_DOD_WALK_ZOOM_BOLT, + ACT_DOD_RUN_ZOOM_BOLT, + ACT_DOD_PRONE_ZOOM_BOLT, + + ACT_DOD_STAND_ZOOM_BAZOOKA, + ACT_DOD_CROUCH_ZOOM_BAZOOKA, + ACT_DOD_CROUCHWALK_ZOOM_BAZOOKA, + ACT_DOD_WALK_ZOOM_BAZOOKA, + ACT_DOD_RUN_ZOOM_BAZOOKA, + ACT_DOD_PRONE_ZOOM_BAZOOKA, + + ACT_DOD_STAND_ZOOM_PSCHRECK, + ACT_DOD_CROUCH_ZOOM_PSCHRECK, + ACT_DOD_CROUCHWALK_ZOOM_PSCHRECK, + ACT_DOD_WALK_ZOOM_PSCHRECK, + ACT_DOD_RUN_ZOOM_PSCHRECK, + ACT_DOD_PRONE_ZOOM_PSCHRECK, + + // Deployed Aim + ACT_DOD_DEPLOY_RIFLE, + ACT_DOD_DEPLOY_TOMMY, + ACT_DOD_DEPLOY_MG, + ACT_DOD_DEPLOY_30CAL, + + // Prone Deployed Aim + ACT_DOD_PRONE_DEPLOY_RIFLE , + ACT_DOD_PRONE_DEPLOY_TOMMY, + ACT_DOD_PRONE_DEPLOY_MG, + ACT_DOD_PRONE_DEPLOY_30CAL, + + // Attacks + + // Rifle + ACT_DOD_PRIMARYATTACK_RIFLE, + ACT_DOD_SECONDARYATTACK_RIFLE, + ACT_DOD_PRIMARYATTACK_PRONE_RIFLE, + ACT_DOD_SECONDARYATTACK_PRONE_RIFLE, + ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_RIFLE, + ACT_DOD_PRIMARYATTACK_DEPLOYED_RIFLE, + + // Bolt + ACT_DOD_PRIMARYATTACK_BOLT, + ACT_DOD_SECONDARYATTACK_BOLT, + ACT_DOD_PRIMARYATTACK_PRONE_BOLT , + ACT_DOD_SECONDARYATTACK_PRONE_BOLT , + + // Tommy + ACT_DOD_PRIMARYATTACK_TOMMY, + ACT_DOD_PRIMARYATTACK_PRONE_TOMMY, + ACT_DOD_SECONDARYATTACK_TOMMY, + ACT_DOD_SECONDARYATTACK_PRONE_TOMMY, + + // MP40 + ACT_DOD_PRIMARYATTACK_MP40, + ACT_DOD_PRIMARYATTACK_PRONE_MP40 , + ACT_DOD_SECONDARYATTACK_MP40, + ACT_DOD_SECONDARYATTACK_PRONE_MP40 , + + // MP44 + ACT_DOD_PRIMARYATTACK_MP44, + ACT_DOD_PRIMARYATTACK_PRONE_MP44 , + + // Greasegun + ACT_DOD_PRIMARYATTACK_GREASE, + ACT_DOD_PRIMARYATTACK_PRONE_GREASE , + + // Pistols (Colt, Luger) + ACT_DOD_PRIMARYATTACK_PISTOL, + ACT_DOD_PRIMARYATTACK_PRONE_PISTOL , + ACT_DOD_PRIMARYATTACK_C96, + ACT_DOD_PRIMARYATTACK_PRONE_C96, + + // Mgs (mg42, mg34) + ACT_DOD_PRIMARYATTACK_MG, + ACT_DOD_PRIMARYATTACK_PRONE_MG , + ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_MG , + ACT_DOD_PRIMARYATTACK_DEPLOYED_MG , + + // 30cal + ACT_DOD_PRIMARYATTACK_30CAL, + ACT_DOD_PRIMARYATTACK_PRONE_30CAL, + ACT_DOD_PRIMARYATTACK_DEPLOYED_30CAL, + ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_30CAL , + + // Grenades + ACT_DOD_PRIMARYATTACK_GREN_FRAG, + ACT_DOD_PRIMARYATTACK_PRONE_GREN_FRAG, + ACT_DOD_PRIMARYATTACK_GREN_STICK, + ACT_DOD_PRIMARYATTACK_PRONE_GREN_STICK, + + // Knife + ACT_DOD_PRIMARYATTACK_KNIFE, + ACT_DOD_PRIMARYATTACK_PRONE_KNIFE, + + // Spade + ACT_DOD_PRIMARYATTACK_SPADE, + ACT_DOD_PRIMARYATTACK_PRONE_SPADE, + + // Bazooka + ACT_DOD_PRIMARYATTACK_BAZOOKA, + ACT_DOD_PRIMARYATTACK_PRONE_BAZOOKA, + + // Pschreck + ACT_DOD_PRIMARYATTACK_PSCHRECK, + ACT_DOD_PRIMARYATTACK_PRONE_PSCHRECK , + + // Bar + ACT_DOD_PRIMARYATTACK_BAR, + ACT_DOD_PRIMARYATTACK_PRONE_BAR, + + // Reloads + ACT_DOD_RELOAD_GARAND, + ACT_DOD_RELOAD_K43, + ACT_DOD_RELOAD_BAR, + ACT_DOD_RELOAD_MP40, + ACT_DOD_RELOAD_MP44, + ACT_DOD_RELOAD_BOLT, + ACT_DOD_RELOAD_M1CARBINE, + ACT_DOD_RELOAD_TOMMY, + ACT_DOD_RELOAD_GREASEGUN, + ACT_DOD_RELOAD_PISTOL, + ACT_DOD_RELOAD_FG42, + ACT_DOD_RELOAD_RIFLE, + ACT_DOD_RELOAD_RIFLEGRENADE, + ACT_DOD_RELOAD_C96, + + // Crouch + ACT_DOD_RELOAD_CROUCH_BAR, + ACT_DOD_RELOAD_CROUCH_RIFLE, + ACT_DOD_RELOAD_CROUCH_RIFLEGRENADE, + ACT_DOD_RELOAD_CROUCH_BOLT, + ACT_DOD_RELOAD_CROUCH_MP44, + ACT_DOD_RELOAD_CROUCH_MP40, + ACT_DOD_RELOAD_CROUCH_TOMMY, + ACT_DOD_RELOAD_CROUCH_BAZOOKA, + ACT_DOD_RELOAD_CROUCH_PSCHRECK, + ACT_DOD_RELOAD_CROUCH_PISTOL, + ACT_DOD_RELOAD_CROUCH_M1CARBINE, + ACT_DOD_RELOAD_CROUCH_C96, + + // Bazookas + ACT_DOD_RELOAD_BAZOOKA, + ACT_DOD_ZOOMLOAD_BAZOOKA, + ACT_DOD_RELOAD_PSCHRECK, + ACT_DOD_ZOOMLOAD_PSCHRECK, + + // Deployed + ACT_DOD_RELOAD_DEPLOYED_FG42, + ACT_DOD_RELOAD_DEPLOYED_30CAL, + ACT_DOD_RELOAD_DEPLOYED_MG, + ACT_DOD_RELOAD_DEPLOYED_MG34, + ACT_DOD_RELOAD_DEPLOYED_BAR, + + // Prone + ACT_DOD_RELOAD_PRONE_PISTOL, + ACT_DOD_RELOAD_PRONE_GARAND, + ACT_DOD_RELOAD_PRONE_M1CARBINE, + ACT_DOD_RELOAD_PRONE_BOLT, + ACT_DOD_RELOAD_PRONE_K43, + ACT_DOD_RELOAD_PRONE_MP40, + ACT_DOD_RELOAD_PRONE_MP44, + ACT_DOD_RELOAD_PRONE_BAR, + ACT_DOD_RELOAD_PRONE_GREASEGUN, + ACT_DOD_RELOAD_PRONE_TOMMY, + ACT_DOD_RELOAD_PRONE_FG42, + ACT_DOD_RELOAD_PRONE_RIFLE, + ACT_DOD_RELOAD_PRONE_RIFLEGRENADE, + ACT_DOD_RELOAD_PRONE_C96, + + // Prone bazooka + ACT_DOD_RELOAD_PRONE_BAZOOKA, + ACT_DOD_ZOOMLOAD_PRONE_BAZOOKA, + ACT_DOD_RELOAD_PRONE_PSCHRECK, + ACT_DOD_ZOOMLOAD_PRONE_PSCHRECK, + + // Prone deployed + ACT_DOD_RELOAD_PRONE_DEPLOYED_BAR, + ACT_DOD_RELOAD_PRONE_DEPLOYED_FG42, + ACT_DOD_RELOAD_PRONE_DEPLOYED_30CAL, + ACT_DOD_RELOAD_PRONE_DEPLOYED_MG, + ACT_DOD_RELOAD_PRONE_DEPLOYED_MG34, + + // Prone zoomed aim + ACT_DOD_PRONE_ZOOM_FORWARD_RIFLE, + ACT_DOD_PRONE_ZOOM_FORWARD_BOLT, + ACT_DOD_PRONE_ZOOM_FORWARD_BAZOOKA, + ACT_DOD_PRONE_ZOOM_FORWARD_PSCHRECK, + + // Crouch attack + ACT_DOD_PRIMARYATTACK_CROUCH, + ACT_DOD_PRIMARYATTACK_CROUCH_SPADE, + ACT_DOD_PRIMARYATTACK_CROUCH_KNIFE, + ACT_DOD_PRIMARYATTACK_CROUCH_GREN_FRAG, + ACT_DOD_PRIMARYATTACK_CROUCH_GREN_STICK, + ACT_DOD_SECONDARYATTACK_CROUCH, + ACT_DOD_SECONDARYATTACK_CROUCH_TOMMY, + ACT_DOD_SECONDARYATTACK_CROUCH_MP40, + + // Hand Signals + ACT_DOD_HS_IDLE, + ACT_DOD_HS_CROUCH, + ACT_DOD_HS_IDLE_30CAL, + ACT_DOD_HS_IDLE_BAZOOKA, + ACT_DOD_HS_IDLE_PSCHRECK, + ACT_DOD_HS_IDLE_KNIFE, + ACT_DOD_HS_IDLE_MG42, + ACT_DOD_HS_IDLE_PISTOL, + ACT_DOD_HS_IDLE_STICKGRENADE, + ACT_DOD_HS_IDLE_TOMMY, + ACT_DOD_HS_IDLE_MP44, + ACT_DOD_HS_IDLE_K98, + ACT_DOD_HS_CROUCH_30CAL, + ACT_DOD_HS_CROUCH_BAZOOKA, + ACT_DOD_HS_CROUCH_PSCHRECK, + ACT_DOD_HS_CROUCH_KNIFE, + ACT_DOD_HS_CROUCH_MG42, + ACT_DOD_HS_CROUCH_PISTOL, + ACT_DOD_HS_CROUCH_STICKGRENADE, + ACT_DOD_HS_CROUCH_TOMMY, + ACT_DOD_HS_CROUCH_MP44, + ACT_DOD_HS_CROUCH_K98, + + ACT_DOD_STAND_IDLE_TNT, + ACT_DOD_CROUCH_IDLE_TNT, + ACT_DOD_CROUCHWALK_IDLE_TNT, + ACT_DOD_WALK_IDLE_TNT, + ACT_DOD_RUN_IDLE_TNT, + ACT_DOD_SPRINT_IDLE_TNT, + ACT_DOD_PRONEWALK_IDLE_TNT, + + ACT_DOD_PLANT_TNT, + ACT_DOD_DEFUSE_TNT, + +// HL2MP + ACT_HL2MP_IDLE, + ACT_HL2MP_RUN, + ACT_HL2MP_IDLE_CROUCH, + ACT_HL2MP_WALK_CROUCH, + ACT_HL2MP_GESTURE_RANGE_ATTACK, + ACT_HL2MP_GESTURE_RELOAD, + ACT_HL2MP_JUMP, + + ACT_HL2MP_IDLE_PISTOL, + ACT_HL2MP_RUN_PISTOL, + ACT_HL2MP_IDLE_CROUCH_PISTOL, + ACT_HL2MP_WALK_CROUCH_PISTOL, + ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, + ACT_HL2MP_GESTURE_RELOAD_PISTOL, + ACT_HL2MP_JUMP_PISTOL, + + ACT_HL2MP_IDLE_SMG1, + ACT_HL2MP_RUN_SMG1, + ACT_HL2MP_IDLE_CROUCH_SMG1, + ACT_HL2MP_WALK_CROUCH_SMG1, + ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1, + ACT_HL2MP_GESTURE_RELOAD_SMG1, + ACT_HL2MP_JUMP_SMG1, + + ACT_HL2MP_IDLE_AR2, + ACT_HL2MP_RUN_AR2, + ACT_HL2MP_IDLE_CROUCH_AR2, + ACT_HL2MP_WALK_CROUCH_AR2, + ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, + ACT_HL2MP_GESTURE_RELOAD_AR2, + ACT_HL2MP_JUMP_AR2, + + ACT_HL2MP_IDLE_SHOTGUN, + ACT_HL2MP_RUN_SHOTGUN, + ACT_HL2MP_IDLE_CROUCH_SHOTGUN, + ACT_HL2MP_WALK_CROUCH_SHOTGUN, + ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, + ACT_HL2MP_GESTURE_RELOAD_SHOTGUN, + ACT_HL2MP_JUMP_SHOTGUN, + + ACT_HL2MP_IDLE_RPG, + ACT_HL2MP_RUN_RPG, + ACT_HL2MP_IDLE_CROUCH_RPG, + ACT_HL2MP_WALK_CROUCH_RPG, + ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG, + ACT_HL2MP_GESTURE_RELOAD_RPG, + ACT_HL2MP_JUMP_RPG, + + ACT_HL2MP_IDLE_GRENADE, + ACT_HL2MP_RUN_GRENADE, + ACT_HL2MP_IDLE_CROUCH_GRENADE, + ACT_HL2MP_WALK_CROUCH_GRENADE, + ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, + ACT_HL2MP_GESTURE_RELOAD_GRENADE, + ACT_HL2MP_JUMP_GRENADE, + + ACT_HL2MP_IDLE_PHYSGUN, + ACT_HL2MP_RUN_PHYSGUN, + ACT_HL2MP_IDLE_CROUCH_PHYSGUN, + ACT_HL2MP_WALK_CROUCH_PHYSGUN, + ACT_HL2MP_GESTURE_RANGE_ATTACK_PHYSGUN, + ACT_HL2MP_GESTURE_RELOAD_PHYSGUN, + ACT_HL2MP_JUMP_PHYSGUN, + + ACT_HL2MP_IDLE_CROSSBOW, + ACT_HL2MP_RUN_CROSSBOW, + ACT_HL2MP_IDLE_CROUCH_CROSSBOW, + ACT_HL2MP_WALK_CROUCH_CROSSBOW, + ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, + ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, + ACT_HL2MP_JUMP_CROSSBOW, + + ACT_HL2MP_IDLE_MELEE, + ACT_HL2MP_RUN_MELEE, + ACT_HL2MP_IDLE_CROUCH_MELEE, + ACT_HL2MP_WALK_CROUCH_MELEE, + ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, + ACT_HL2MP_GESTURE_RELOAD_MELEE, + ACT_HL2MP_JUMP_MELEE, + + ACT_HL2MP_IDLE_SLAM, + ACT_HL2MP_RUN_SLAM, + ACT_HL2MP_IDLE_CROUCH_SLAM, + ACT_HL2MP_WALK_CROUCH_SLAM, + ACT_HL2MP_GESTURE_RANGE_ATTACK_SLAM, + ACT_HL2MP_GESTURE_RELOAD_SLAM, + ACT_HL2MP_JUMP_SLAM, + +// Portal! + ACT_VM_FIZZLE, + + // Multiplayer + ACT_MP_STAND_IDLE, + ACT_MP_CROUCH_IDLE, + ACT_MP_CROUCH_DEPLOYED_IDLE, + ACT_MP_CROUCH_DEPLOYED, + ACT_MP_CROUCHWALK_DEPLOYED, + ACT_MP_DEPLOYED_IDLE, + ACT_MP_RUN, + ACT_MP_WALK, + ACT_MP_AIRWALK, + ACT_MP_CROUCHWALK, + ACT_MP_SPRINT, + ACT_MP_JUMP, + ACT_MP_JUMP_START, + ACT_MP_JUMP_FLOAT, + ACT_MP_JUMP_LAND, + ACT_MP_DOUBLEJUMP, + ACT_MP_SWIM, + ACT_MP_DEPLOYED, + ACT_MP_SWIM_DEPLOYED, + ACT_MP_VCD, + + ACT_MP_ATTACK_STAND_PRIMARYFIRE, + ACT_MP_ATTACK_STAND_PRIMARYFIRE_DEPLOYED, + ACT_MP_ATTACK_STAND_SECONDARYFIRE, + ACT_MP_ATTACK_STAND_GRENADE, + ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, + ACT_MP_ATTACK_CROUCH_PRIMARYFIRE_DEPLOYED, + ACT_MP_ATTACK_CROUCH_SECONDARYFIRE, + ACT_MP_ATTACK_CROUCH_GRENADE, + ACT_MP_ATTACK_SWIM_PRIMARYFIRE, + ACT_MP_ATTACK_SWIM_SECONDARYFIRE, + ACT_MP_ATTACK_SWIM_GRENADE, + ACT_MP_ATTACK_AIRWALK_PRIMARYFIRE, + ACT_MP_ATTACK_AIRWALK_SECONDARYFIRE, + ACT_MP_ATTACK_AIRWALK_GRENADE, + ACT_MP_RELOAD_STAND, + ACT_MP_RELOAD_STAND_LOOP, + ACT_MP_RELOAD_STAND_END, + ACT_MP_RELOAD_CROUCH, + ACT_MP_RELOAD_CROUCH_LOOP, + ACT_MP_RELOAD_CROUCH_END, + ACT_MP_RELOAD_SWIM, + ACT_MP_RELOAD_SWIM_LOOP, + ACT_MP_RELOAD_SWIM_END, + ACT_MP_RELOAD_AIRWALK, + ACT_MP_RELOAD_AIRWALK_LOOP, + ACT_MP_RELOAD_AIRWALK_END, + ACT_MP_ATTACK_STAND_PREFIRE, + ACT_MP_ATTACK_STAND_POSTFIRE, + ACT_MP_ATTACK_STAND_STARTFIRE, + ACT_MP_ATTACK_CROUCH_PREFIRE, + ACT_MP_ATTACK_CROUCH_POSTFIRE, + ACT_MP_ATTACK_SWIM_PREFIRE, + ACT_MP_ATTACK_SWIM_POSTFIRE, + + // Multiplayer - Primary + ACT_MP_STAND_PRIMARY, + ACT_MP_CROUCH_PRIMARY, + ACT_MP_RUN_PRIMARY, + ACT_MP_WALK_PRIMARY, + ACT_MP_AIRWALK_PRIMARY, + ACT_MP_CROUCHWALK_PRIMARY, + ACT_MP_JUMP_PRIMARY, + ACT_MP_JUMP_START_PRIMARY, + ACT_MP_JUMP_FLOAT_PRIMARY, + ACT_MP_JUMP_LAND_PRIMARY, + ACT_MP_SWIM_PRIMARY, + ACT_MP_DEPLOYED_PRIMARY, + ACT_MP_SWIM_DEPLOYED_PRIMARY, + ACT_MP_CROUCHWALK_DEPLOYED_PRIMARY, + ACT_MP_CROUCH_DEPLOYED_IDLE_PRIMARY, + + ACT_MP_ATTACK_STAND_PRIMARY, // RUN, WALK + ACT_MP_ATTACK_STAND_PRIMARY_DEPLOYED, + ACT_MP_ATTACK_CROUCH_PRIMARY, // CROUCHWALK + ACT_MP_ATTACK_CROUCH_PRIMARY_DEPLOYED, + ACT_MP_ATTACK_SWIM_PRIMARY, + ACT_MP_ATTACK_AIRWALK_PRIMARY, + + ACT_MP_RELOAD_STAND_PRIMARY, // RUN, WALK + ACT_MP_RELOAD_STAND_PRIMARY_LOOP, + ACT_MP_RELOAD_STAND_PRIMARY_END, + ACT_MP_RELOAD_CROUCH_PRIMARY, // CROUCHWALK + ACT_MP_RELOAD_CROUCH_PRIMARY_LOOP, + ACT_MP_RELOAD_CROUCH_PRIMARY_END, + ACT_MP_RELOAD_SWIM_PRIMARY, + ACT_MP_RELOAD_SWIM_PRIMARY_LOOP, + ACT_MP_RELOAD_SWIM_PRIMARY_END, + ACT_MP_RELOAD_AIRWALK_PRIMARY, + ACT_MP_RELOAD_AIRWALK_PRIMARY_LOOP, + ACT_MP_RELOAD_AIRWALK_PRIMARY_END, + + ACT_MP_RELOAD_STAND_PRIMARY_2, + ACT_MP_RELOAD_STAND_PRIMARY_LOOP_2, + ACT_MP_RELOAD_STAND_PRIMARY_END_2, + ACT_MP_RELOAD_CROUCH_PRIMARY_2, + ACT_MP_RELOAD_CROUCH_PRIMARY_LOOP_2, + ACT_MP_RELOAD_CROUCH_PRIMARY_END_2, + ACT_MP_RELOAD_SWIM_PRIMARY_2, + ACT_MP_RELOAD_SWIM_PRIMARY_LOOP_2, + ACT_MP_RELOAD_SWIM_PRIMARY_END_2, + ACT_MP_RELOAD_AIRWALK_PRIMARY_2, + ACT_MP_RELOAD_AIRWALK_PRIMARY_LOOP_2, + ACT_MP_RELOAD_AIRWALK_PRIMARY_END_2, + + // PRIMARY ALT + ACT_MP_ATTACK_STAND_PRIMARY_ALT, + ACT_MP_ATTACK_CROUCH_PRIMARY_ALT, + ACT_MP_ATTACK_SWIM_PRIMARY_ALT, + ACT_MP_RELOAD_STAND_PRIMARY_ALT, + ACT_MP_RELOAD_CROUCH_PRIMARY_ALT, + ACT_MP_RELOAD_AIRWALK_PRIMARY_ALT, + ACT_MP_RELOAD_STAND_PRIMARY_LOOP_ALT, + ACT_MP_RELOAD_CROUCH_PRIMARY_LOOP_ALT, + ACT_MP_RELOAD_AIRWALK_PRIMARY_LOOP_ALT, + ACT_MP_RELOAD_STAND_PRIMARY_END_ALT, + ACT_MP_RELOAD_CROUCH_PRIMARY_END_ALT, + ACT_MP_RELOAD_AIRWALK_PRIMARY_END_ALT, + ACT_MP_RELOAD_SWIM_PRIMARY_ALT, + ACT_MP_ATTACK_STAND_PRIMARY_SUPER, + ACT_MP_ATTACK_CROUCH_PRIMARY_SUPER, + ACT_MP_ATTACK_SWIM_PRIMARY_SUPER, + + ACT_MP_ATTACK_STAND_GRENADE_PRIMARY, // RUN, WALK + ACT_MP_ATTACK_CROUCH_GRENADE_PRIMARY, // CROUCHWALK + ACT_MP_ATTACK_SWIM_GRENADE_PRIMARY, + ACT_MP_ATTACK_AIRWALK_GRENADE_PRIMARY, + + // Secondary + ACT_MP_STAND_SECONDARY, + ACT_MP_CROUCH_SECONDARY, + ACT_MP_RUN_SECONDARY, + ACT_MP_WALK_SECONDARY, + ACT_MP_AIRWALK_SECONDARY, + ACT_MP_CROUCHWALK_SECONDARY, + ACT_MP_JUMP_SECONDARY, + ACT_MP_JUMP_START_SECONDARY, + ACT_MP_JUMP_FLOAT_SECONDARY, + ACT_MP_JUMP_LAND_SECONDARY, + ACT_MP_SWIM_SECONDARY, + + ACT_MP_ATTACK_STAND_SECONDARY, // RUN, WALK + ACT_MP_ATTACK_CROUCH_SECONDARY, // CROUCHWALK + ACT_MP_ATTACK_SWIM_SECONDARY, + ACT_MP_ATTACK_AIRWALK_SECONDARY, + + ACT_MP_RELOAD_STAND_SECONDARY, // RUN, WALK + ACT_MP_RELOAD_STAND_SECONDARY_LOOP, + ACT_MP_RELOAD_STAND_SECONDARY_END, + ACT_MP_RELOAD_CROUCH_SECONDARY, // CROUCHWALK + ACT_MP_RELOAD_CROUCH_SECONDARY_LOOP, + ACT_MP_RELOAD_CROUCH_SECONDARY_END, + ACT_MP_RELOAD_SWIM_SECONDARY, + ACT_MP_RELOAD_SWIM_SECONDARY_LOOP, + ACT_MP_RELOAD_SWIM_SECONDARY_END, + ACT_MP_RELOAD_AIRWALK_SECONDARY, + ACT_MP_RELOAD_AIRWALK_SECONDARY_LOOP, + ACT_MP_RELOAD_AIRWALK_SECONDARY_END, + + ACT_MP_RELOAD_STAND_SECONDARY_2, + ACT_MP_RELOAD_CROUCH_SECONDARY_2, + ACT_MP_RELOAD_SWIM_SECONDARY_2, + ACT_MP_RELOAD_AIRWALK_SECONDARY_2, + + ACT_MP_ATTACK_STAND_GRENADE_SECONDARY, // RUN, WALK + ACT_MP_ATTACK_CROUCH_GRENADE_SECONDARY, // CROUCHWALK + ACT_MP_ATTACK_SWIM_GRENADE_SECONDARY, + ACT_MP_ATTACK_AIRWALK_GRENADE_SECONDARY, + + // Secondary2 + ACT_MP_STAND_SECONDARY2, + ACT_MP_CROUCH_SECONDARY2, + ACT_MP_RUN_SECONDARY2, + ACT_MP_WALK_SECONDARY2, + ACT_MP_AIRWALK_SECONDARY2, + ACT_MP_CROUCHWALK_SECONDARY2, + ACT_MP_JUMP_SECONDARY2, + ACT_MP_JUMP_START_SECONDARY2, + ACT_MP_JUMP_FLOAT_SECONDARY2, + ACT_MP_JUMP_LAND_SECONDARY2, + ACT_MP_SWIM_SECONDARY2, + + ACT_MP_ATTACK_STAND_SECONDARY2, // RUN, WALK + ACT_MP_ATTACK_CROUCH_SECONDARY2, // CROUCHWALK + ACT_MP_ATTACK_SWIM_SECONDARY2, + ACT_MP_ATTACK_AIRWALK_SECONDARY2, + + ACT_MP_RELOAD_STAND_SECONDARY2, // RUN, WALK + ACT_MP_RELOAD_STAND_SECONDARY2_LOOP, + ACT_MP_RELOAD_STAND_SECONDARY2_END, + ACT_MP_RELOAD_CROUCH_SECONDARY2, // CROUCHWALK + ACT_MP_RELOAD_CROUCH_SECONDARY2_LOOP, + ACT_MP_RELOAD_CROUCH_SECONDARY2_END, + ACT_MP_RELOAD_SWIM_SECONDARY2, + ACT_MP_RELOAD_SWIM_SECONDARY2_LOOP, + ACT_MP_RELOAD_SWIM_SECONDARY2_END, + ACT_MP_RELOAD_AIRWALK_SECONDARY2, + ACT_MP_RELOAD_AIRWALK_SECONDARY2_LOOP, + ACT_MP_RELOAD_AIRWALK_SECONDARY2_END, + + // Melee + ACT_MP_STAND_MELEE, + ACT_MP_CROUCH_MELEE, + ACT_MP_RUN_MELEE, + ACT_MP_WALK_MELEE, + ACT_MP_AIRWALK_MELEE, + ACT_MP_CROUCHWALK_MELEE, + ACT_MP_JUMP_MELEE, + ACT_MP_JUMP_START_MELEE, + ACT_MP_JUMP_FLOAT_MELEE, + ACT_MP_JUMP_LAND_MELEE, + ACT_MP_SWIM_MELEE, + + ACT_MP_ATTACK_STAND_MELEE, // RUN, WALK + ACT_MP_ATTACK_STAND_MELEE_SECONDARY, + ACT_MP_ATTACK_CROUCH_MELEE, // CROUCHWALK + ACT_MP_ATTACK_CROUCH_MELEE_SECONDARY, + ACT_MP_ATTACK_SWIM_MELEE, + ACT_MP_ATTACK_AIRWALK_MELEE, + + ACT_MP_ATTACK_STAND_GRENADE_MELEE, // RUN, WALK + ACT_MP_ATTACK_CROUCH_GRENADE_MELEE, // CROUCHWALK + ACT_MP_ATTACK_SWIM_GRENADE_MELEE, + ACT_MP_ATTACK_AIRWALK_GRENADE_MELEE, + + // Item1 + ACT_MP_STAND_ITEM1, + ACT_MP_CROUCH_ITEM1, + ACT_MP_RUN_ITEM1, + ACT_MP_WALK_ITEM1, + ACT_MP_AIRWALK_ITEM1, + ACT_MP_CROUCHWALK_ITEM1, + ACT_MP_JUMP_ITEM1, + ACT_MP_JUMP_START_ITEM1, + ACT_MP_JUMP_FLOAT_ITEM1, + ACT_MP_JUMP_LAND_ITEM1, + ACT_MP_SWIM_ITEM1, + + ACT_MP_ATTACK_STAND_ITEM1, // RUN, WALK + ACT_MP_ATTACK_STAND_ITEM1_SECONDARY, + ACT_MP_ATTACK_CROUCH_ITEM1, // CROUCHWALK + ACT_MP_ATTACK_CROUCH_ITEM1_SECONDARY, + ACT_MP_ATTACK_SWIM_ITEM1, + ACT_MP_ATTACK_AIRWALK_ITEM1, + + ACT_MP_DEPLOYED_ITEM1, + ACT_MP_DEPLOYED_IDLE_ITEM1, + ACT_MP_CROUCHWALK_DEPLOYED_ITEM1, + ACT_MP_CROUCH_DEPLOYED_IDLE_ITEM1, + ACT_MP_ATTACK_STAND_PRIMARY_DEPLOYED_ITEM1, + ACT_MP_ATTACK_CROUCH_PRIMARY_DEPLOYED_ITEM1, + + // Item2 + ACT_MP_STAND_ITEM2, + ACT_MP_CROUCH_ITEM2, + ACT_MP_RUN_ITEM2, + ACT_MP_WALK_ITEM2, + ACT_MP_AIRWALK_ITEM2, + ACT_MP_CROUCHWALK_ITEM2, + ACT_MP_JUMP_ITEM2, + ACT_MP_JUMP_START_ITEM2, + ACT_MP_JUMP_FLOAT_ITEM2, + ACT_MP_JUMP_LAND_ITEM2, + ACT_MP_SWIM_ITEM2, + + ACT_MP_ATTACK_STAND_ITEM2, // RUN, WALK + ACT_MP_ATTACK_STAND_ITEM2_SECONDARY, + ACT_MP_ATTACK_CROUCH_ITEM2, // CROUCHWALK + ACT_MP_ATTACK_CROUCH_ITEM2_SECONDARY, + ACT_MP_ATTACK_SWIM_ITEM2, + ACT_MP_ATTACK_AIRWALK_ITEM2, + + ACT_MP_ATTACK_STAND_HARD_ITEM2, + ACT_MP_ATTACK_CROUCH_HARD_ITEM2, + ACT_MP_ATTACK_SWIM_HARD_ITEM2, + + ACT_MP_DEPLOYED_ITEM2, + ACT_MP_DEPLOYED_IDLE_ITEM2, + ACT_MP_CROUCHWALK_DEPLOYED_ITEM2, + ACT_MP_CROUCH_DEPLOYED_IDLE_ITEM2, + ACT_MP_ATTACK_STAND_PRIMARY_DEPLOYED_ITEM2, + ACT_MP_ATTACK_CROUCH_PRIMARY_DEPLOYED_ITEM2, + + ACT_MP_RELOAD_STAND_ITEM2, // RUN, WALK + ACT_MP_RELOAD_STAND_ITEM2_LOOP, + ACT_MP_RELOAD_STAND_ITEM2_END, + ACT_MP_RELOAD_CROUCH_ITEM2, // CROUCHWALK + ACT_MP_RELOAD_CROUCH_ITEM2_LOOP, + ACT_MP_RELOAD_CROUCH_ITEM2_END, + ACT_MP_RELOAD_SWIM_ITEM2, + ACT_MP_RELOAD_SWIM_ITEM2_LOOP, + ACT_MP_RELOAD_SWIM_ITEM2_END, + ACT_MP_RELOAD_AIRWALK_ITEM2, + ACT_MP_RELOAD_AIRWALK_ITEM2_LOOP, + ACT_MP_RELOAD_AIRWALK_ITEM2_END, + ACT_MP_RELOAD_NO_AMMO_ITEM2, + + ACT_MP_ATTACK_STAND_GRENADE_ITEM2, // RUN, WALK + ACT_MP_ATTACK_CROUCH_GRENADE_ITEM2, // CROUCHWALK + ACT_MP_ATTACK_SWIM_GRENADE_ITEM2, + ACT_MP_ATTACK_AIRWALK_GRENADE_ITEM2, + + // Passtime + ACT_MP_STAND_PASSTIME, + ACT_MP_RUN_PASSTIME, + ACT_MP_CROUCHWALK_PASSTIME, + + // Flinches + ACT_MP_GESTURE_FLINCH, + ACT_MP_GESTURE_FLINCH_PRIMARY, + ACT_MP_GESTURE_FLINCH_SECONDARY, + ACT_MP_GESTURE_FLINCH_MELEE, + ACT_MP_GESTURE_FLINCH_ITEM1, + ACT_MP_GESTURE_FLINCH_ITEM2, + + ACT_MP_GESTURE_FLINCH_HEAD, + ACT_MP_GESTURE_FLINCH_CHEST, + ACT_MP_GESTURE_FLINCH_STOMACH, + ACT_MP_GESTURE_FLINCH_LEFTARM, + ACT_MP_GESTURE_FLINCH_RIGHTARM, + ACT_MP_GESTURE_FLINCH_LEFTLEG, + ACT_MP_GESTURE_FLINCH_RIGHTLEG, + +// Team Fortress specific - medic heal, medic infect, etc..... + ACT_MP_GRENADE1_DRAW, + ACT_MP_GRENADE1_IDLE, + ACT_MP_GRENADE1_ATTACK, + ACT_MP_GRENADE2_DRAW, + ACT_MP_GRENADE2_IDLE, + ACT_MP_GRENADE2_ATTACK, + + ACT_MP_PRIMARY_GRENADE1_DRAW, + ACT_MP_PRIMARY_GRENADE1_IDLE, + ACT_MP_PRIMARY_GRENADE1_ATTACK, + ACT_MP_PRIMARY_GRENADE2_DRAW, + ACT_MP_PRIMARY_GRENADE2_IDLE, + ACT_MP_PRIMARY_GRENADE2_ATTACK, + + ACT_MP_SECONDARY_GRENADE1_DRAW, + ACT_MP_SECONDARY_GRENADE1_IDLE, + ACT_MP_SECONDARY_GRENADE1_ATTACK, + ACT_MP_SECONDARY_GRENADE2_DRAW, + ACT_MP_SECONDARY_GRENADE2_IDLE, + ACT_MP_SECONDARY_GRENADE2_ATTACK, + + ACT_MP_MELEE_GRENADE1_DRAW, + ACT_MP_MELEE_GRENADE1_IDLE, + ACT_MP_MELEE_GRENADE1_ATTACK, + ACT_MP_MELEE_GRENADE2_DRAW, + ACT_MP_MELEE_GRENADE2_IDLE, + ACT_MP_MELEE_GRENADE2_ATTACK, + + ACT_MP_ITEM1_GRENADE1_DRAW, + ACT_MP_ITEM1_GRENADE1_IDLE, + ACT_MP_ITEM1_GRENADE1_ATTACK, + ACT_MP_ITEM1_GRENADE2_DRAW, + ACT_MP_ITEM1_GRENADE2_IDLE, + ACT_MP_ITEM1_GRENADE2_ATTACK, + + ACT_MP_ITEM2_GRENADE1_DRAW, + ACT_MP_ITEM2_GRENADE1_IDLE, + ACT_MP_ITEM2_GRENADE1_ATTACK, + ACT_MP_ITEM2_GRENADE2_DRAW, + ACT_MP_ITEM2_GRENADE2_IDLE, + ACT_MP_ITEM2_GRENADE2_ATTACK, + + // Building + ACT_MP_STAND_BUILDING, + ACT_MP_CROUCH_BUILDING, + ACT_MP_RUN_BUILDING, + ACT_MP_WALK_BUILDING, + ACT_MP_AIRWALK_BUILDING, + ACT_MP_CROUCHWALK_BUILDING, + ACT_MP_JUMP_BUILDING, + ACT_MP_JUMP_START_BUILDING, + ACT_MP_JUMP_FLOAT_BUILDING, + ACT_MP_JUMP_LAND_BUILDING, + ACT_MP_SWIM_BUILDING, + + ACT_MP_ATTACK_STAND_BUILDING, // RUN, WALK + ACT_MP_ATTACK_CROUCH_BUILDING, // CROUCHWALK + ACT_MP_ATTACK_SWIM_BUILDING, + ACT_MP_ATTACK_AIRWALK_BUILDING, + + ACT_MP_ATTACK_STAND_GRENADE_BUILDING, // RUN, WALK + ACT_MP_ATTACK_CROUCH_GRENADE_BUILDING, // CROUCHWALK + ACT_MP_ATTACK_SWIM_GRENADE_BUILDING, + ACT_MP_ATTACK_AIRWALK_GRENADE_BUILDING, + + // Building + ACT_MP_STAND_BUILDING_DEPLOYED, + ACT_MP_CROUCH_BUILDING_DEPLOYED, + ACT_MP_RUN_BUILDING_DEPLOYED, + ACT_MP_WALK_BUILDING_DEPLOYED, + ACT_MP_AIRWALK_BUILDING_DEPLOYED, + ACT_MP_CROUCHWALK_BUILDING_DEPLOYED, + ACT_MP_JUMP_BUILDING_DEPLOYED, + ACT_MP_JUMP_START_BUILDING_DEPLOYED, + ACT_MP_JUMP_FLOAT_BUILDING_DEPLOYED, + ACT_MP_JUMP_LAND_BUILDING_DEPLOYED, + ACT_MP_SWIM_BUILDING_DEPLOYED, + + ACT_MP_ATTACK_STAND_BUILDING_DEPLOYED, // RUN, WALK + ACT_MP_ATTACK_CROUCH_BUILDING_DEPLOYED, // CROUCHWALK + ACT_MP_ATTACK_SWIM_BUILDING_DEPLOYED, + ACT_MP_ATTACK_AIRWALK_BUILDING_DEPLOYED, + + ACT_MP_ATTACK_STAND_GRENADE_BUILDING_DEPLOYED, // RUN, WALK + ACT_MP_ATTACK_CROUCH_GRENADE_BUILDING_DEPLOYED, // CROUCHWALK + ACT_MP_ATTACK_SWIM_GRENADE_BUILDING_DEPLOYED, + ACT_MP_ATTACK_AIRWALK_GRENADE_BUILDING_DEPLOYED, + + ACT_MP_STAND_PDA, + ACT_MP_CROUCH_PDA, + ACT_MP_RUN_PDA, + ACT_MP_WALK_PDA, + ACT_MP_AIRWALK_PDA, + ACT_MP_CROUCHWALK_PDA, + ACT_MP_JUMP_PDA, + ACT_MP_JUMP_START_PDA, + ACT_MP_JUMP_FLOAT_PDA, + ACT_MP_JUMP_LAND_PDA, + ACT_MP_SWIM_PDA, + + ACT_MP_ATTACK_STAND_PDA, + ACT_MP_ATTACK_SWIM_PDA, + + ACT_MP_STAND_LOSERSTATE, + ACT_MP_CROUCH_LOSERSTATE, + ACT_MP_RUN_LOSERSTATE, + ACT_MP_WALK_LOSERSTATE, + ACT_MP_AIRWALK_LOSERSTATE, + ACT_MP_CROUCHWALK_LOSERSTATE, + ACT_MP_JUMP_LOSERSTATE, + ACT_MP_JUMP_START_LOSERSTATE, + ACT_MP_JUMP_FLOAT_LOSERSTATE, + ACT_MP_JUMP_LAND_LOSERSTATE, + ACT_MP_SWIM_LOSERSTATE, + ACT_MP_DOUBLEJUMP_LOSERSTATE, + + ACT_MP_DOUBLEJUMP_CROUCH, + ACT_MP_DOUBLEJUMP_CROUCH_PRIMARY, + ACT_MP_DOUBLEJUMP_CROUCH_SECONDARY, + ACT_MP_DOUBLEJUMP_CROUCH_MELEE, + ACT_MP_DOUBLEJUMP_CROUCH_ITEM1, + ACT_MP_DOUBLEJUMP_CROUCH_ITEM2, + ACT_MP_DOUBLEJUMP_CROUCH_LOSERSTATE, + ACT_MP_DOUBLEJUMP_CROUCH_PASSTIME, + + ACT_MP_GESTURE_VC_HANDMOUTH, + ACT_MP_GESTURE_VC_FINGERPOINT, + ACT_MP_GESTURE_VC_FISTPUMP, + ACT_MP_GESTURE_VC_THUMBSUP, + ACT_MP_GESTURE_VC_NODYES, + ACT_MP_GESTURE_VC_NODNO, + + ACT_MP_GESTURE_VC_HANDMOUTH_PRIMARY, + ACT_MP_GESTURE_VC_FINGERPOINT_PRIMARY, + ACT_MP_GESTURE_VC_FISTPUMP_PRIMARY, + ACT_MP_GESTURE_VC_THUMBSUP_PRIMARY, + ACT_MP_GESTURE_VC_NODYES_PRIMARY, + ACT_MP_GESTURE_VC_NODNO_PRIMARY, + + ACT_MP_GESTURE_VC_HANDMOUTH_SECONDARY, + ACT_MP_GESTURE_VC_FINGERPOINT_SECONDARY, + ACT_MP_GESTURE_VC_FISTPUMP_SECONDARY, + ACT_MP_GESTURE_VC_THUMBSUP_SECONDARY, + ACT_MP_GESTURE_VC_NODYES_SECONDARY, + ACT_MP_GESTURE_VC_NODNO_SECONDARY, + + ACT_MP_GESTURE_VC_HANDMOUTH_MELEE, + ACT_MP_GESTURE_VC_FINGERPOINT_MELEE, + ACT_MP_GESTURE_VC_FISTPUMP_MELEE, + ACT_MP_GESTURE_VC_THUMBSUP_MELEE, + ACT_MP_GESTURE_VC_NODYES_MELEE, + ACT_MP_GESTURE_VC_NODNO_MELEE, + + ACT_MP_GESTURE_VC_HANDMOUTH_ITEM1, + ACT_MP_GESTURE_VC_FINGERPOINT_ITEM1, + ACT_MP_GESTURE_VC_FISTPUMP_ITEM1, + ACT_MP_GESTURE_VC_THUMBSUP_ITEM1, + ACT_MP_GESTURE_VC_NODYES_ITEM1, + ACT_MP_GESTURE_VC_NODNO_ITEM1, + + ACT_MP_GESTURE_VC_HANDMOUTH_ITEM2, + ACT_MP_GESTURE_VC_FINGERPOINT_ITEM2, + ACT_MP_GESTURE_VC_FISTPUMP_ITEM2, + ACT_MP_GESTURE_VC_THUMBSUP_ITEM2, + ACT_MP_GESTURE_VC_NODYES_ITEM2, + ACT_MP_GESTURE_VC_NODNO_ITEM2, + + ACT_MP_GESTURE_VC_HANDMOUTH_BUILDING, + ACT_MP_GESTURE_VC_FINGERPOINT_BUILDING, + ACT_MP_GESTURE_VC_FISTPUMP_BUILDING, + ACT_MP_GESTURE_VC_THUMBSUP_BUILDING, + ACT_MP_GESTURE_VC_NODYES_BUILDING, + ACT_MP_GESTURE_VC_NODNO_BUILDING, + + ACT_MP_GESTURE_VC_HANDMOUTH_PDA, + ACT_MP_GESTURE_VC_FINGERPOINT_PDA, + ACT_MP_GESTURE_VC_FISTPUMP_PDA, + ACT_MP_GESTURE_VC_THUMBSUP_PDA, + ACT_MP_GESTURE_VC_NODYES_PDA, + ACT_MP_GESTURE_VC_NODNO_PDA, + + ACT_MP_STUN_BEGIN, + ACT_MP_STUN_MIDDLE, + ACT_MP_STUN_END, + + ACT_MP_PASSTIME_THROW_BEGIN, + ACT_MP_PASSTIME_THROW_MIDDLE, + ACT_MP_PASSTIME_THROW_END, + ACT_MP_PASSTIME_THROW_CANCEL, + + ACT_VM_UNUSABLE, + ACT_VM_UNUSABLE_TO_USABLE, + ACT_VM_USABLE_TO_UNUSABLE, + + // Specific viewmodel activities for weapon roles + ACT_PRIMARY_VM_DRAW, + ACT_PRIMARY_VM_HOLSTER, + ACT_PRIMARY_VM_IDLE, + ACT_PRIMARY_VM_PULLBACK, + ACT_PRIMARY_VM_PRIMARYATTACK, + ACT_PRIMARY_VM_SECONDARYATTACK, + ACT_PRIMARY_VM_RELOAD, + ACT_PRIMARY_RELOAD_START, + ACT_PRIMARY_RELOAD_FINISH, + ACT_PRIMARY_VM_DRYFIRE, + ACT_PRIMARY_VM_IDLE_TO_LOWERED, + ACT_PRIMARY_VM_IDLE_LOWERED, + ACT_PRIMARY_VM_LOWERED_TO_IDLE, + ACT_PRIMARY_VM_RELOAD_2, + ACT_PRIMARY_RELOAD_START_2, + ACT_PRIMARY_RELOAD_FINISH_2, + ACT_PRIMARY_VM_RELOAD_3, + ACT_PRIMARY_RELOAD_START_3, + ACT_PRIMARY_RELOAD_FINISH_3, + ACT_PRIMARY_VM_PRIMARYATTACK_3, + + ACT_SECONDARY_VM_DRAW, + ACT_SECONDARY_VM_HOLSTER, + ACT_SECONDARY_VM_IDLE, + ACT_SECONDARY_VM_PULLBACK, + ACT_SECONDARY_VM_PRIMARYATTACK, + ACT_SECONDARY_VM_SECONDARYATTACK, + ACT_SECONDARY_VM_RELOAD, + ACT_SECONDARY_RELOAD_START, + ACT_SECONDARY_RELOAD_FINISH, + ACT_SECONDARY_VM_RELOAD2, + ACT_SECONDARY_VM_DRYFIRE, + ACT_SECONDARY_VM_IDLE_TO_LOWERED, + ACT_SECONDARY_VM_IDLE_LOWERED, + ACT_SECONDARY_VM_LOWERED_TO_IDLE, + + ACT_SECONDARY_VM_DRAW_2, + ACT_SECONDARY_VM_IDLE_2, + ACT_SECONDARY_VM_PRIMARYATTACK_2, + ACT_SECONDARY_VM_RELOAD_2, + + ACT_MELEE_VM_DRAW, + ACT_MELEE_VM_HOLSTER, + ACT_MELEE_VM_IDLE, + ACT_MELEE_VM_PULLBACK, + ACT_MELEE_VM_PRIMARYATTACK, + ACT_MELEE_VM_SECONDARYATTACK, + ACT_MELEE_VM_RELOAD, + ACT_MELEE_VM_DRYFIRE, + ACT_MELEE_VM_IDLE_TO_LOWERED, + ACT_MELEE_VM_IDLE_LOWERED, + ACT_MELEE_VM_LOWERED_TO_IDLE, + ACT_MELEE_VM_STUN, + ACT_MELEE_VM_HITCENTER, + ACT_MELEE_VM_SWINGHARD, + + ACT_PDA_VM_DRAW, + ACT_PDA_VM_HOLSTER, + ACT_PDA_VM_IDLE, + ACT_PDA_VM_PULLBACK, + ACT_PDA_VM_PRIMARYATTACK, + ACT_PDA_VM_SECONDARYATTACK, + ACT_PDA_VM_RELOAD, + ACT_PDA_VM_DRYFIRE, + ACT_PDA_VM_IDLE_TO_LOWERED, + ACT_PDA_VM_IDLE_LOWERED, + ACT_PDA_VM_LOWERED_TO_IDLE, + + ACT_ENGINEER_PDA1_VM_DRAW, + ACT_ENGINEER_PDA2_VM_DRAW, + ACT_ENGINEER_BLD_VM_DRAW, + ACT_ENGINEER_PDA1_VM_IDLE, + ACT_ENGINEER_PDA2_VM_IDLE, + ACT_ENGINEER_BLD_VM_IDLE, + + ACT_ITEM1_VM_DRAW, + ACT_ITEM1_VM_HOLSTER, + ACT_ITEM1_VM_IDLE, + ACT_ITEM1_VM_IDLE_2, + ACT_ITEM1_VM_PULLBACK, + ACT_ITEM1_VM_PRIMARYATTACK, + ACT_ITEM1_VM_SECONDARYATTACK, + ACT_ITEM1_VM_RELOAD, + ACT_ITEM1_VM_DRYFIRE, + ACT_ITEM1_VM_IDLE_TO_LOWERED, + ACT_ITEM1_VM_IDLE_LOWERED, + ACT_ITEM1_VM_LOWERED_TO_IDLE, + ACT_ITEM1_RELOAD_START, + ACT_ITEM1_RELOAD_FINISH, + ACT_ITEM1_VM_HITCENTER, + ACT_ITEM1_VM_SWINGHARD, + ACT_ITEM1_BACKSTAB_VM_UP, + ACT_ITEM1_BACKSTAB_VM_DOWN, + ACT_ITEM1_BACKSTAB_VM_IDLE, + ACT_MELEE_VM_ITEM1_STUN, + + ACT_ITEM2_VM_DRAW, + ACT_ITEM2_VM_HOLSTER, + ACT_ITEM2_VM_IDLE, + ACT_ITEM2_VM_PULLBACK, + ACT_ITEM2_VM_PRIMARYATTACK, + ACT_ITEM2_VM_SECONDARYATTACK, + ACT_ITEM2_VM_RELOAD, + ACT_ITEM2_VM_DRYFIRE, + ACT_ITEM2_VM_IDLE_TO_LOWERED, + ACT_ITEM2_VM_IDLE_LOWERED, + ACT_ITEM2_VM_LOWERED_TO_IDLE, + ACT_ITEM2_VM_CHARGE, + ACT_ITEM2_VM_IDLE_2, + ACT_ITEM2_VM_IDLE_3, + ACT_ITEM2_VM_CHARGE_IDLE_3, + ACT_ITEM2_VM_HITCENTER, + ACT_ITEM2_VM_SWINGHARD, + ACT_ITEM2_BACKSTAB_VM_UP, + ACT_ITEM2_BACKSTAB_VM_DOWN, + ACT_ITEM2_BACKSTAB_VM_IDLE, + ACT_MELEE_VM_ITEM2_STUN, + + ACT_ITEM3_VM_DRAW, + ACT_ITEM3_VM_HOLSTER, + ACT_ITEM3_VM_IDLE, + ACT_ITEM3_VM_PULLBACK, + ACT_ITEM3_VM_PRIMARYATTACK, + ACT_ITEM3_VM_SECONDARYATTACK, + ACT_ITEM3_VM_RELOAD, + ACT_ITEM3_VM_DRYFIRE, + ACT_ITEM3_VM_IDLE_TO_LOWERED, + ACT_ITEM3_VM_IDLE_LOWERED, + ACT_ITEM3_VM_LOWERED_TO_IDLE, + ACT_ITEM3_VM_CHARGE, + ACT_ITEM3_VM_IDLE_2, + ACT_ITEM3_VM_IDLE_3, + ACT_ITEM3_VM_CHARGE_IDLE_3, + ACT_ITEM3_VM_HITCENTER, + ACT_ITEM3_VM_SWINGHARD, + + ACT_SECONDARY2_VM_DRAW, + ACT_SECONDARY2_VM_HOLSTER, + ACT_SECONDARY2_VM_IDLE, + ACT_SECONDARY2_VM_PULLBACK, + ACT_SECONDARY2_VM_PRIMARYATTACK, + ACT_SECONDARY2_VM_SECONDARY2ATTACK, + ACT_SECONDARY2_VM_RELOAD, + ACT_SECONDARY2_RELOAD_START, + ACT_SECONDARY2_RELOAD_FINISH, + ACT_SECONDARY2_VM_RELOAD2, + ACT_SECONDARY2_VM_DRYFIRE, + ACT_SECONDARY2_VM_IDLE_TO_LOWERED, + ACT_SECONDARY2_VM_IDLE_LOWERED, + ACT_SECONDARY2_VM_LOWERED_TO_IDLE, + + ACT_BACKSTAB_VM_UP, + ACT_BACKSTAB_VM_DOWN, + ACT_BACKSTAB_VM_IDLE, + + ACT_PRIMARY_ATTACK_STAND_PREFIRE, + ACT_PRIMARY_ATTACK_STAND_POSTFIRE, + ACT_PRIMARY_ATTACK_STAND_STARTFIRE, + ACT_PRIMARY_ATTACK_CROUCH_PREFIRE, + ACT_PRIMARY_ATTACK_CROUCH_POSTFIRE, + ACT_PRIMARY_ATTACK_SWIM_PREFIRE, + ACT_PRIMARY_ATTACK_SWIM_POSTFIRE, + + ACT_SECONDARY_ATTACK_STAND_PREFIRE, + ACT_SECONDARY_ATTACK_STAND_POSTFIRE, + ACT_SECONDARY_ATTACK_STAND_STARTFIRE, + ACT_SECONDARY_ATTACK_CROUCH_PREFIRE, + ACT_SECONDARY_ATTACK_CROUCH_POSTFIRE, + ACT_SECONDARY_ATTACK_SWIM_PREFIRE, + ACT_SECONDARY_ATTACK_SWIM_POSTFIRE, + + ACT_MELEE_ATTACK_STAND_PREFIRE, + ACT_MELEE_ATTACK_STAND_POSTFIRE, + ACT_MELEE_ATTACK_STAND_STARTFIRE, + ACT_MELEE_ATTACK_CROUCH_PREFIRE, + ACT_MELEE_ATTACK_CROUCH_POSTFIRE, + ACT_MELEE_ATTACK_SWIM_PREFIRE, + ACT_MELEE_ATTACK_SWIM_POSTFIRE, + + ACT_ITEM1_ATTACK_STAND_PREFIRE, + ACT_ITEM1_ATTACK_STAND_POSTFIRE, + ACT_ITEM1_ATTACK_STAND_STARTFIRE, + ACT_ITEM1_ATTACK_CROUCH_PREFIRE, + ACT_ITEM1_ATTACK_CROUCH_POSTFIRE, + ACT_ITEM1_ATTACK_SWIM_PREFIRE, + ACT_ITEM1_ATTACK_SWIM_POSTFIRE, + + ACT_ITEM2_ATTACK_STAND_PREFIRE, + ACT_ITEM2_ATTACK_STAND_POSTFIRE, + ACT_ITEM2_ATTACK_STAND_STARTFIRE, + ACT_ITEM2_ATTACK_CROUCH_PREFIRE, + ACT_ITEM2_ATTACK_CROUCH_POSTFIRE, + ACT_ITEM2_ATTACK_SWIM_PREFIRE, + ACT_ITEM2_ATTACK_SWIM_POSTFIRE, + + ACT_MP_STAND_MELEE_ALLCLASS, + ACT_MP_CROUCH_MELEE_ALLCLASS, + ACT_MP_RUN_MELEE_ALLCLASS, + ACT_MP_WALK_MELEE_ALLCLASS, + ACT_MP_AIRWALK_MELEE_ALLCLASS, + ACT_MP_CROUCHWALK_MELEE_ALLCLASS, + ACT_MP_JUMP_MELEE_ALLCLASS, + ACT_MP_JUMP_START_MELEE_ALLCLASS, + ACT_MP_JUMP_FLOAT_MELEE_ALLCLASS, + ACT_MP_JUMP_LAND_MELEE_ALLCLASS, + ACT_MP_SWIM_MELEE_ALLCLASS, + + ACT_MP_ATTACK_STAND_MELEE_ALLCLASS, // RUN, WALK + ACT_MP_ATTACK_STAND_MELEE_SECONDARY_ALLCLASS, + ACT_MP_ATTACK_CROUCH_MELEE_ALLCLASS, // CROUCHWALK + ACT_MP_ATTACK_CROUCH_MELEE_SECONDARY_ALLCLASS, + ACT_MP_ATTACK_SWIM_MELEE_ALLCLASS, + ACT_MP_ATTACK_AIRWALK_MELEE_ALLCLASS, + + ACT_MELEE_ALLCLASS_VM_DRAW, + ACT_MELEE_ALLCLASS_VM_HOLSTER, + ACT_MELEE_ALLCLASS_VM_IDLE, + ACT_MELEE_ALLCLASS_VM_PULLBACK, + ACT_MELEE_ALLCLASS_VM_PRIMARYATTACK, + ACT_MELEE_ALLCLASS_VM_SECONDARYATTACK, + ACT_MELEE_ALLCLASS_VM_RELOAD, + ACT_MELEE_ALLCLASS_VM_DRYFIRE, + ACT_MELEE_ALLCLASS_VM_IDLE_TO_LOWERED, + ACT_MELEE_ALLCLASS_VM_IDLE_LOWERED, + ACT_MELEE_ALLCLASS_VM_LOWERED_TO_IDLE, + ACT_MELEE_ALLCLASS_VM_STUN, + ACT_MELEE_ALLCLASS_VM_HITCENTER, + ACT_MELEE_ALLCLASS_VM_SWINGHARD, + + // BOMB activities for TD mode. + ACT_MP_STAND_BOMB, + ACT_MP_JUMP_START_BOMB, + ACT_MP_JUMP_FLOAT_BOMB, + ACT_MP_JUMP_LAND_BOMB, + ACT_MP_RUN_BOMB, + ACT_MP_SWIM_BOMB, + + // More Primary VM activities for Soldier Quake RL + ACT_VM_DRAW_QRL, + ACT_VM_IDLE_QRL, + ACT_VM_PULLBACK_QRL, + ACT_VM_PRIMARYATTACK_QRL, + ACT_VM_RELOAD_QRL, + ACT_VM_RELOAD_START_QRL, + ACT_VM_RELOAD_FINISH_QRL, + + // Third person anims for the Soldier Quake RL + ACT_MP_RELOAD_STAND_PRIMARY3, + ACT_MP_RELOAD_CROUCH_PRIMARY3, + ACT_MP_RELOAD_AIRWALK_PRIMARY3, + ACT_MP_RELOAD_STAND_PRIMARY3_LOOP, + ACT_MP_RELOAD_CROUCH_PRIMARY3_LOOP, + ACT_MP_RELOAD_AIRWALK_PRIMARY3_LOOP, + ACT_MP_RELOAD_STAND_PRIMARY3_END, + ACT_MP_RELOAD_CROUCH_PRIMARY3_END, + ACT_MP_RELOAD_AIRWALK_PRIMARY3_END, + ACT_MP_RELOAD_SWIM_PRIMARY3, + + // Throwable Animations + ACT_MP_THROW, + ACT_THROWABLE_VM_DRAW, + ACT_THROWABLE_VM_IDLE, + ACT_THROWABLE_VM_FIRE, + + // Spell Animations + ACT_SPELL_VM_DRAW, + ACT_SPELL_VM_IDLE, + ACT_SPELL_VM_ARM, + ACT_SPELL_VM_FIRE, + + // Bread Monster Sapper + ACT_BREADSAPPER_VM_DRAW, + ACT_BREADSAPPER_VM_IDLE, + + // Bread Gloves + ACT_BREADGLOVES_VM_HITLEFT, + ACT_BREADGLOVES_VM_HITRIGHT, + ACT_BREADGLOVES_VM_SWINGHARD, + ACT_BREADGLOVES_VM_IDLE, + ACT_BREADGLOVES_VM_DRAW, + + ACT_BREADMONSTER_GLOVES_IDLE, + ACT_BREADMONSTER_GLOVES_HITRIGHT, + ACT_BREADMONSTER_GLOVES_HITUP, + + ACT_BREADMONSTER_VM_DRAW, + ACT_BREADMONSTER_VM_IDLE, + ACT_BREADMONSTER_VM_PRIMARYATTACK, + + ACT_PARACHUTE_DEPLOY, + ACT_PARACHUTE_DEPLOY_IDLE, + ACT_PARACHUTE_RETRACT, + ACT_PARACHUTE_RETRACT_IDLE, + + ACT_BOT_SPAWN, + ACT_BOT_PANIC, + ACT_BOT_PRIMARY_MOVEMENT, + ACT_BOT_GESTURE_FLINCH, + ACT_BOT_PANIC_START, + ACT_BOT_PANIC_END, + + ACT_ENGINEER_REVOLVER_DRAW, + ACT_ENGINEER_REVOLVER_IDLE, + ACT_ENGINEER_REVOLVER_PRIMARYATTACK, + ACT_ENGINEER_REVOLVER_RELOAD, + + // Kart! + ACT_KART_IDLE, + ACT_KART_ACTION_SHOOT, + ACT_KART_ACTION_DASH, + ACT_KART_JUMP_START, + ACT_KART_JUMP_FLOAT, + ACT_KART_JUMP_LAND, + ACT_KART_IMPACT, + ACT_KART_IMPACT_BIG, + ACT_KART_GESTURE_POSITIVE, + ACT_KART_GESTURE_NEGATIVE, + + // grappling hook + ACT_GRAPPLE_DRAW, + ACT_GRAPPLE_IDLE, + ACT_GRAPPLE_FIRE_START, + ACT_GRAPPLE_FIRE_IDLE, + ACT_GRAPPLE_PULL_START, + ACT_GRAPPLE_PULL_IDLE, + ACT_GRAPPLE_PULL_END, + + // inspect + ACT_PRIMARY_VM_INSPECT_START, + ACT_PRIMARY_VM_INSPECT_IDLE, + ACT_PRIMARY_VM_INSPECT_END, + + ACT_SECONDARY_VM_INSPECT_START, + ACT_SECONDARY_VM_INSPECT_IDLE, + ACT_SECONDARY_VM_INSPECT_END, + + ACT_MELEE_VM_INSPECT_START, + ACT_MELEE_VM_INSPECT_IDLE, + ACT_MELEE_VM_INSPECT_END, + + // this is the end of the global activities, private per-monster activities start here. + LAST_SHARED_ACTIVITY, +} Activity; + + +#endif // AI_ACTIVITY_H + diff --git a/game/shared/ai_debug_shared.h b/game/shared/ai_debug_shared.h new file mode 100644 index 0000000..bde5844 --- /dev/null +++ b/game/shared/ai_debug_shared.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_DEBUG_SHARED_H +#define AI_DEBUG_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/vprof.h" + + +// This uses VPROF to profile +//#define VPROF_AI 1 + + +#ifdef VPROF_AI +inline void AI_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, + const IHandleEntity *ignore, int collisionGroup, trace_t *ptr ) +{ + VPROF( "AI_TraceLine" ); + UTIL_TraceLine( vecAbsStart, vecAbsEnd, mask, ignore, collisionGroup, ptr ); +} + +inline void AI_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, + ITraceFilter *pFilter, trace_t *ptr ) +{ + VPROF( "AI_TraceLine" ); + UTIL_TraceLine( vecAbsStart, vecAbsEnd, mask, pFilter, ptr ); +} + +inline void AI_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin, + const Vector &hullMax, unsigned int mask, const IHandleEntity *ignore, + int collisionGroup, trace_t *ptr ) +{ + VPROF( "AI_TraceHull" ); + UTIL_TraceHull( vecAbsStart, vecAbsEnd, hullMin, hullMax, mask, ignore, collisionGroup, ptr ); +} + +inline void AI_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin, + const Vector &hullMax, unsigned int mask, ITraceFilter *pFilter, trace_t *ptr ) +{ + VPROF( "AI_TraceHull" ); + UTIL_TraceHull( vecAbsStart, vecAbsEnd, hullMin, hullMax, mask, pFilter, ptr ); +} + +inline void AI_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr ) +{ + VPROF( "AI_TraceEntity" ); + UTIL_TraceEntity( pEntity, vecAbsStart, vecAbsEnd, mask, ptr ); +} + +#else +#define AI_TraceLine UTIL_TraceLine +#define AI_TraceHull UTIL_TraceHull +#define AI_TraceEntity UTIL_TraceEntity +#endif + + +#endif // AI_DEBUG_SHARED_H diff --git a/game/shared/ammodef.h b/game/shared/ammodef.h new file mode 100644 index 0000000..71c1707 --- /dev/null +++ b/game/shared/ammodef.h @@ -0,0 +1,103 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Holds defintion for game ammo types +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_AMMODEF_H +#define AI_AMMODEF_H + +#ifdef _WIN32 +#pragma once +#endif + +class ConVar; + +struct Ammo_t +{ + char *pName; + int nDamageType; + int eTracerType; + float physicsForceImpulse; + int nMinSplashSize; + int nMaxSplashSize; + + int nFlags; + + // Values for player/NPC damage and carrying capability + // If the integers are set, they override the CVars + int pPlrDmg; // CVar for player damage amount + int pNPCDmg; // CVar for NPC damage amount + int pMaxCarry; // CVar for maximum number can carry + const ConVar* pPlrDmgCVar; // CVar for player damage amount + const ConVar* pNPCDmgCVar; // CVar for NPC damage amount + const ConVar* pMaxCarryCVar; // CVar for maximum number can carry +}; + +// Used to tell AmmoDef to use the cvars, not the integers +#define USE_CVAR -1 +// Ammo is infinite +#define INFINITE_AMMO -2 + +enum AmmoTracer_t +{ + TRACER_NONE, + TRACER_LINE, + TRACER_RAIL, + TRACER_BEAM, + TRACER_LINE_AND_WHIZ, +}; + +enum AmmoFlags_t +{ + AMMO_FORCE_DROP_IF_CARRIED = 0x1, + AMMO_INTERPRET_PLRDAMAGE_AS_DAMAGE_TO_PLAYER = 0x2, +}; + + +#include "shareddefs.h" + +//============================================================================= +// >> CAmmoDef +//============================================================================= +class CAmmoDef +{ + +public: + int m_nAmmoIndex; + + Ammo_t m_AmmoType[MAX_AMMO_TYPES]; + + Ammo_t *GetAmmoOfIndex(int nAmmoIndex); + int Index(const char *psz); + int PlrDamage(int nAmmoIndex); + int NPCDamage(int nAmmoIndex); + int MaxCarry(int nAmmoIndex); + int DamageType(int nAmmoIndex); + int TracerType(int nAmmoIndex); + float DamageForce(int nAmmoIndex); + int MinSplashSize(int nAmmoIndex); + int MaxSplashSize(int nAmmoIndex); + int Flags(int nAmmoIndex); + + void AddAmmoType(char const* name, int damageType, int tracerType, int plr_dmg, int npc_dmg, int carry, float physicsForceImpulse, int nFlags, int minSplashSize = 4, int maxSplashSize = 8 ); + void AddAmmoType(char const* name, int damageType, int tracerType, char const* plr_cvar, char const* npc_var, char const* carry_cvar, float physicsForceImpulse, int nFlags, int minSplashSize = 4, int maxSplashSize = 8 ); + + CAmmoDef(void); + virtual ~CAmmoDef( void ); + +private: + bool AddAmmoType(char const* name, int damageType, int tracerType, int nFlags, int minSplashSize, int maxSplashSize ); +}; + + +// Get the global ammodef object. This is usually implemented in each mod's game rules file somewhere, +// so the mod can setup custom ammo types. +CAmmoDef* GetAmmoDef(); + + +#endif // AI_AMMODEF_H + diff --git a/game/shared/animation.h b/game/shared/animation.h new file mode 100644 index 0000000..eb6ae87 --- /dev/null +++ b/game/shared/animation.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef ANIMATION_H +#define ANIMATION_H + +#define ACTIVITY_NOT_AVAILABLE -1 + +struct animevent_t; +struct studiohdr_t; +class CStudioHdr; +struct mstudioseqdesc_t; + +int ExtractBbox( CStudioHdr *pstudiohdr, int sequence, Vector& mins, Vector& maxs ); + +void IndexModelSequences( CStudioHdr *pstudiohdr ); +void ResetActivityIndexes( CStudioHdr *pstudiohdr ); +void VerifySequenceIndex( CStudioHdr *pstudiohdr ); +int SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence = -1 ); +int SelectHeaviestSequence( CStudioHdr *pstudiohdr, int activity ); +void SetEventIndexForSequence( mstudioseqdesc_t &seqdesc ); +void BuildAllAnimationEventIndexes( CStudioHdr *pstudiohdr ); +void ResetEventIndexes( CStudioHdr *pstudiohdr ); + +void GetEyePosition( CStudioHdr *pstudiohdr, Vector &vecEyePosition ); + +int LookupActivity( CStudioHdr *pstudiohdr, const char *label ); +int LookupSequence( CStudioHdr *pstudiohdr, const char *label ); + +#define NOMOTION 99999 +void GetSequenceLinearMotion( CStudioHdr *pstudiohdr, int iSequence, const float poseParameter[], Vector *pVec ); + +const char *GetSequenceName( CStudioHdr *pstudiohdr, int sequence ); +const char *GetSequenceActivityName( CStudioHdr *pstudiohdr, int iSequence ); + +int GetSequenceFlags( CStudioHdr *pstudiohdr, int sequence ); +int GetAnimationEvent( CStudioHdr *pstudiohdr, int sequence, animevent_t *pNPCEvent, float flStart, float flEnd, int index ); +bool HasAnimationEventOfType( CStudioHdr *pstudiohdr, int sequence, int type ); + +int FindTransitionSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, int iGoalSequence, int *piDir ); +bool GotoSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &nNextSequence, float &flNextCycle, int &iNextDir ); + +void SetBodygroup( CStudioHdr *pstudiohdr, int& body, int iGroup, int iValue ); +int GetBodygroup( CStudioHdr *pstudiohdr, int body, int iGroup ); + +const char *GetBodygroupName( CStudioHdr *pstudiohdr, int iGroup ); +int FindBodygroupByName( CStudioHdr *pstudiohdr, const char *name ); +int GetBodygroupCount( CStudioHdr *pstudiohdr, int iGroup ); +int GetNumBodyGroups( CStudioHdr *pstudiohdr ); + +int GetSequenceActivity( CStudioHdr *pstudiohdr, int sequence, int *pweight = NULL ); + +void GetAttachmentLocalSpace( CStudioHdr *pstudiohdr, int attachIndex, matrix3x4_t &pLocalToWorld ); + +float SetBlending( CStudioHdr *pstudiohdr, int sequence, int *pblendings, int iBlender, float flValue ); + +int FindHitboxSetByName( CStudioHdr *pstudiohdr, const char *name ); +const char *GetHitboxSetName( CStudioHdr *pstudiohdr, int setnumber ); +int GetHitboxSetCount( CStudioHdr *pstudiohdr ); + +#endif //ANIMATION_H diff --git a/game/shared/apparent_velocity_helper.h b/game/shared/apparent_velocity_helper.h new file mode 100644 index 0000000..65e28fb --- /dev/null +++ b/game/shared/apparent_velocity_helper.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef APPARENT_VELOCITY_HELPER_H +#define APPARENT_VELOCITY_HELPER_H +#ifdef _WIN32 +#pragma once +#endif + + +inline float CalcDistance( float x, float y ) +{ + return x - y; +} + +inline float CalcDistance( const Vector &a, const Vector &b ) +{ + return a.DistTo( b ); +} + + +template +class CDefaultCalcDistance +{ +public: + static inline float CalcDistance( const T &a, const T &b ) + { + return ::CalcDistance( a, b ); + } +}; + +class CCalcDistance2D +{ +public: + static inline float CalcDistance( const Vector &a, const Vector &b ) + { + return (a-b).Length2D(); + } +}; + + +template< class T, class Functor=CDefaultCalcDistance > +class CApparentVelocity +{ +public: + CApparentVelocity(const T& t0) + { + m_LastTime = -1; + m_LastValue = t0; + } + + float AddSample( float time, T value ) + { + float flRet = 0; + if ( m_LastTime != -1 ) + { + flRet = Functor::CalcDistance(value, m_LastValue) / (time - m_LastTime); + } + + m_LastTime = time; + m_LastValue = value; + + return flRet; + } + +private: + T m_LastValue; + float m_LastTime; +}; + + +#endif // APPARENT_VELOCITY_HELPER_H diff --git a/game/shared/base_playeranimstate.h b/game/shared/base_playeranimstate.h new file mode 100644 index 0000000..5c84755 --- /dev/null +++ b/game/shared/base_playeranimstate.h @@ -0,0 +1,288 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASE_PLAYERANIMSTATE_H +#define BASE_PLAYERANIMSTATE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iplayeranimstate.h" +#include "studio.h" +#include "sequence_Transitioner.h" + +#ifdef CLIENT_DLL + class C_BaseAnimatingOverlay; + #define CBaseAnimatingOverlay C_BaseAnimatingOverlay +#else + class CBaseAnimatingOverlay; +#endif + +// If a guy is moving slower than this, then he's considered to not be moving +// (so he goes to his idle animation at full playback rate rather than his walk +// animation at low playback rate). +#define MOVING_MINIMUM_SPEED 0.5f + + +#define MAIN_IDLE_SEQUENCE_LAYER 0 // For 8-way blended models, this layer blends an idle on top of the run/walk animation to simulate a 9-way blend. + // For 9-way blended models, we don't use this layer. + +#define AIMSEQUENCE_LAYER 1 // Aim sequence uses layers 0 and 1 for the weapon idle animation (needs 2 layers so it can blend). +#define NUM_AIMSEQUENCE_LAYERS 4 // Then it uses layers 2 and 3 to blend in the weapon run/walk/crouchwalk animation. + + +// Everyone who derives from CBasePlayerAnimState gets to fill in this info +// to drive how the animation state is generated. +class CModAnimConfig +{ +public: + // This tells how far the upper body can rotate left and right. If he begins to rotate + // past this, it'll turn his feet to face his upper body. + float m_flMaxBodyYawDegrees; + + // How do the legs animate? + LegAnimType_t m_LegAnimType; + + // Use aim sequences? (CS hostages don't). + bool m_bUseAimSequences; +}; + + +// ------------------------------------------------------------------------------------------------ // +// CBasePlayerAnimState declaration. +// ------------------------------------------------------------------------------------------------ // + +abstract_class CBasePlayerAnimState : virtual public IPlayerAnimState +{ +public: + DECLARE_CLASS_NOBASE( CBasePlayerAnimState ); + + enum + { + TURN_NONE = 0, + TURN_LEFT, + TURN_RIGHT + }; + + CBasePlayerAnimState(); + virtual ~CBasePlayerAnimState(); + + void Init( CBaseAnimatingOverlay *pPlayer, const CModAnimConfig &config ); + virtual void Release(); + + // Update() and DoAnimationEvent() together maintain the entire player's animation state. + // + // Update() maintains the the lower body animation (the player's m_nSequence) + // and the upper body overlay based on the player's velocity and look direction. + // + // It also modulates these based on events triggered by DoAnimationEvent. + virtual void Update( float eyeYaw, float eyePitch ); + + // This is called by the client when a new player enters the PVS to clear any events + // the dormant version of the entity may have been playing. + virtual void ClearAnimationState(); + + // This is called every frame to prepare the animation layers to be filled with data + // since we reconstruct them every frame (in case they get stomped by the networking + // or anything else). + virtual void ClearAnimationLayers(); + + // The client uses this to figure out what angles to render the entity with (since as the guy turns, + // it will change his body_yaw pose parameter before changing his rendered angle). + virtual const QAngle& GetRenderAngles(); + + +// Overrideables. +public: + + virtual bool ShouldUpdateAnimState(); + + // This is called near the start of each frame. + // The base class figures out the main sequence and the aim sequence, and derived + // classes can overlay whatever other animations they want. + virtual void ComputeSequences( CStudioHdr *pStudioHdr ); + + // This is called to figure out what the main activity is. The mod-specific class + // overrides this to handle events like jumping, firing, etc. + virtual Activity CalcMainActivity() = 0; + + // This is called to calculate the aim layer sequence. It usually figures out the + // animation prefixes and suffixes and calls CalcSequenceIndex(). + virtual int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ) = 0; + + // This lets server-controlled idle sequences to play unchanged on the client + virtual bool ShouldChangeSequences( void ) const; + + // If this returns true, then it will blend the current aim layer sequence with an idle aim layer + // sequence based on how fast the character is moving, so it doesn't play the upper-body run at + // full speed if he's moving really slowly. + // + // We return false on this for animations that don't have blends, like reloads. + virtual bool ShouldBlendAimSequenceToIdle(); + + // For the body left/right rotation, some models use a pose parameter and some use a bone controller. + virtual float SetOuterBodyYaw( float flValue ); + + // Return true if the player is allowed to move. + virtual bool CanThePlayerMove(); + + // This is called every frame to see what the maximum speed the player can move is. + // It is used to determine where to put the move_x/move_y pose parameters or to + // determine the animation playback rate, based on the player's movement speed. + // The return value from here is interpolated so the playback rate or pose params don't move sharply. + virtual float GetCurrentMaxGroundSpeed() = 0; + + // Display Con_NPrint output about the animation state. This is called if + // we're on the client and if cl_showanimstate holds the current entity's index. + void DebugShowAnimStateFull( int iStartLine ); + + virtual void DebugShowAnimState( int iStartLine ); + void AnimStatePrintf( int iLine, PRINTF_FORMAT_STRING const char *pMsg, ... ); + void AnimStateLog( PRINTF_FORMAT_STRING const char *pMsg, ... ); + + // Calculate the playback rate for movement layer + virtual float CalcMovementPlaybackRate( bool *bIsMoving ); + + // Allow inheriting classes to translate their desired activity, while keeping all + // internal ACT comparisons using the base activity + virtual Activity TranslateActivity( Activity actDesired ) { return actDesired; } + + // Allow inheriting classes to override SelectWeightedSequence + virtual int SelectWeightedSequence( Activity activity ); + +public: + + void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); + + CBaseAnimatingOverlay *GetOuter() const; + + void RestartMainSequence(); + + +// Helpers for the derived classes to use. +protected: + + // Sets up the string you specify, looks for that sequence and returns the index. + // Complains in the console and returns 0 if it can't find it. + virtual int CalcSequenceIndex( PRINTF_FORMAT_STRING const char *pBaseName, ... ); + + Activity GetCurrentMainSequenceActivity() const; + + void GetOuterAbsVelocity( Vector& vel ) const; + float GetOuterXYSpeed() const; + + // How long has it been since we cleared the animation state? + float TimeSinceLastAnimationStateClear() const; + + float GetEyeYaw() const { return m_flEyeYaw; } + +protected: + + CModAnimConfig m_AnimConfig; + CBaseAnimatingOverlay *m_pOuter; + +protected: + int ConvergeAngles( float goal,float maxrate, float maxgap, float dt, float& current ); + virtual void ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr ); + virtual void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ); + virtual void ComputePoseParam_BodyYaw(); + + virtual void ResetGroundSpeed( void ); + +protected: + // The player's eye yaw and pitch angles. + float m_flEyeYaw; + float m_flEyePitch; + + // The following variables are used for tweaking the yaw of the upper body when standing still and + // making sure that it smoothly blends in and out once the player starts moving + // Direction feet were facing when we stopped moving + float m_flGoalFeetYaw; + + float m_flCurrentFeetYaw; + bool m_bCurrentFeetYawInitialized; + + float m_flCurrentTorsoYaw; + + // To check if they are rotating in place + float m_flLastYaw; + + // Time when we stopped moving + float m_flLastTurnTime; + + // One of the above enums + int m_nTurningInPlace; + + QAngle m_angRender; + +private: + + // Update the prone state machine. + void UpdateProneState(); + + // Get the string that's appended to animation names for the player's current weapon. + const char* GetWeaponSuffix(); + + Activity BodyYawTranslateActivity( Activity activity ); + + void SetOuterPoseParameter( int iParam, float flValue ); + + + void EstimateYaw(); + + virtual bool ShouldResetMainSequence( int iCurrentSequence, int iNewSequence ); + void ComputeMainSequence(); + void ComputeAimSequence(); + + void ComputePlaybackRate(); + + void UpdateInterpolators(); + float GetInterpolatedGroundSpeed(); + +private: + + float m_flMaxGroundSpeed; + + float m_flLastAnimationStateClearTime; + + // If he's using 8-way blending, then we blend to this idle + int m_iCurrent8WayIdleSequence; + int m_iCurrent8WayCrouchIdleSequence; + + // Last activity we've used on the lower body. Used to determine if animations should restart. + Activity m_eCurrentMainSequenceActivity; + + float m_flGaitYaw; + float m_flStoredCycle; + + Vector2D m_vLastMovePose; + + void UpdateAimSequenceLayers( + float flCycle, + int iFirstLayer, + bool bForceIdle, + CSequenceTransitioner *pTransitioner, + float flWeightScale + ); + + void OptimizeLayerWeights( int iFirstLayer, int nLayers ); + + // This gives us smooth transitions between aim anim sequences on the client. + CSequenceTransitioner m_IdleSequenceTransitioner; + CSequenceTransitioner m_SequenceTransitioner; +}; + +extern float g_flLastBodyPitch, g_flLastBodyYaw, m_flLastMoveYaw; + + +inline Activity CBasePlayerAnimState::GetCurrentMainSequenceActivity() const +{ + return m_eCurrentMainSequenceActivity; +} + + +#endif // BASE_PLAYERANIMSTATE_H diff --git a/game/shared/baseachievement.h b/game/shared/baseachievement.h new file mode 100644 index 0000000..2074f81 --- /dev/null +++ b/game/shared/baseachievement.h @@ -0,0 +1,270 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef BASEACHIEVEMENT_H +#define BASEACHIEVEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "GameEventListener.h" +#include "hl2orange.spa.h" +#include "iachievementmgr.h" + +class CAchievementMgr; + +// +// Base class for achievements +// + +class CBaseAchievement : public CGameEventListener, public IAchievement +{ + DECLARE_CLASS_NOBASE( CBaseAchievement ); +public: + CBaseAchievement(); + virtual ~CBaseAchievement(); + virtual void Init() {} + virtual void ListenForEvents() {}; + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ); + + int GetAchievementID() { return m_iAchievementID; } + void SetAchievementID( int iAchievementID ) { m_iAchievementID = iAchievementID; } + void SetName( const char *pszName ) { m_pszName = pszName; } + const char *GetName() { return m_pszName; } + const char *GetStat() { return m_pszStat?m_pszStat:GetName(); } + void SetFlags( int iFlags ); + int GetFlags() { return m_iFlags; } + void SetGoal( int iGoal ) { m_iGoal = iGoal; } + int GetGoal() { return m_iGoal; } + void SetGameDirFilter( const char *pGameDir ); + bool HasComponents() { return ( m_iFlags & ACH_HAS_COMPONENTS ) > 0; } + void SetPointValue( int iPointValue ) { m_iPointValue = iPointValue; } + int GetPointValue() { return m_iPointValue; } + bool ShouldHideUntilAchieved() { return m_bHideUntilAchieved; } + void SetHideUntilAchieved( bool bHide ) { m_bHideUntilAchieved = bHide; } + void SetStoreProgressInSteam( bool bStoreProgressInSteam ) { m_bStoreProgressInSteam = bStoreProgressInSteam; } + bool StoreProgressInSteam() { return m_bStoreProgressInSteam; } + virtual bool ShouldShowProgressNotification() { return true; } + virtual void OnPlayerStatsUpdate() {} + + virtual bool ShouldSaveWithGame(); + bool ShouldSaveGlobal(); + virtual void PreRestoreSavedGame(); + virtual void PostRestoreSavedGame(); + void SetCount( int iCount ) { m_iCount = iCount; } + int GetCount() { return m_iCount; } + void SetProgressShown( int iProgressShown ) { m_iProgressShown = iProgressShown; } + int GetProgressShown() { return m_iProgressShown; } + virtual bool IsAchieved() { return m_bAchieved; } + virtual bool IsActive(); + virtual bool LocalPlayerCanEarn( void ) { return true; } + void SetAchieved( bool bAchieved ) { m_bAchieved = bAchieved; } + virtual bool IsMetaAchievement() { return false; } + virtual bool AlwaysListen() { return false; } + virtual bool AlwaysEnabled() { return false; } + + //============================================================================= + // HPE_BEGIN: + // [pfreese] Notification method for derived classes + //============================================================================= + + virtual void OnAchieved() {} + uint32 GetUnlockTime() const { return m_uUnlockTime; } + void SetUnlockTime( uint32 unlockTime ) { m_uUnlockTime = unlockTime; } + + //============================================================================= + // HPE_END + //============================================================================= + + uint64 GetComponentBits() { return m_iComponentBits; } + void SetComponentBits( uint64 iComponentBits ); + void OnComponentEvent( const char *pchComponentName ); + void EnsureComponentBitSetAndEvaluate( int iBitNumber ); + void EvaluateIsAlreadyAchieved(); + virtual void OnMapEvent( const char *pEventName ); + virtual void PrintAdditionalStatus() {} // for debugging, achievements may report additional status in achievement_status concmd + virtual void OnSteamUserStatsStored() {} + virtual void UpdateAchievement( int nData ) {} + virtual bool ShouldShowOnHUD() { return m_bShowOnHUD; } + virtual void SetShowOnHUD( bool bShow ); + + //============================================================================= + // HPE_BEGIN: + // [pfreese] Serialization methods + //============================================================================= + + virtual void GetSettings( KeyValues* pNodeOut ); // serialize + virtual void ApplySettings( /* const */ KeyValues* pNodeIn ); // unserialize + + //============================================================================= + // HPE_END + //============================================================================= + + virtual void Think( void ) { return; } + + const char *GetMapNameFilter( void ){ return m_pMapNameFilter; } + CAchievementMgr *GetAchievementMgr( void ){ return m_pAchievementMgr; } + +protected: + virtual void FireGameEvent( IGameEvent *event ); + virtual void FireGameEvent_Internal( IGameEvent *event ) {}; + void SetVictimFilter( const char *pClassName ); + void SetAttackerFilter( const char *pClassName ); + void SetInflictorFilter( const char *pClassName ); + void SetInflictorEntityNameFilter( const char *pEntityName ); + void SetMapNameFilter( const char *pMapName ); + void SetComponentPrefix( const char *pPrefix ); + void IncrementCount( int iOptIncrement = 0 ); + void EvaluateNewAchievement(); + void AwardAchievement(); + void ShowProgressNotification(); + void HandleProgressUpdate(); + virtual void CalcProgressMsgIncrement(); + void SetNextThink( float flThinkTime ); + void ClearThink( void ); + void SetStat( const char* pStatName ) { m_pszStat = pStatName; } + + const char *m_pszName; // name of this achievement + const char *m_pszStat; // stat this achievement uses + int m_iAchievementID; // ID of this achievement + int m_iFlags; // ACH_* flags for this achievement + int m_iGoal; // goal # of steps to award this achievement + int m_iProgressMsgIncrement; // after how many steps show we show a progress notification + int m_iProgressMsgMinimum; // the minimum progress needed before showing progress notification + int m_iPointValue; // # of points this achievement is worth (currently only used for XBox Live) + bool m_bHideUntilAchieved; // should this achievement be hidden until achieved? + bool m_bStoreProgressInSteam; // should incremental progress be stored in Steam. A counter with same name as achievement must be set up in Steam. + const char *m_pInflictorClassNameFilter; // if non-NULL, inflictor class name to filter with + const char *m_pInflictorEntityNameFilter; // if non-NULL, inflictor entity name to filter with + const char *m_pVictimClassNameFilter; // if non-NULL, victim class name to filter with + const char *m_pAttackerClassNameFilter; // if non-NULL, attacker class name to filter with + const char *m_pMapNameFilter; // if non-NULL, map name to filter with + const char *m_pGameDirFilter; // if non-NULL, game dir name to filter with + + const char **m_pszComponentNames; + int m_iNumComponents; + const char *m_pszComponentPrefix; + int m_iComponentPrefixLen; + bool m_bAchieved; // is this achievement achieved + uint32 m_uUnlockTime; // time_t that this achievement was unlocked (0 if before Steamworks unlock time support) + int m_iCount; // # of steps satisfied toward this achievement (only valid if not achieved) + int m_iProgressShown; // # of progress msgs we've shown + uint64 m_iComponentBits; // bitfield of components achieved + CAchievementMgr *m_pAchievementMgr; // our achievement manager + bool m_bShowOnHUD; // if set, the player wants this achievement pinned to the HUD + + friend class CAchievementMgr; +public: + DECLARE_DATADESC(); +}; + +class CFailableAchievement : public CBaseAchievement +{ + DECLARE_CLASS( CFailableAchievement, CBaseAchievement ); +public: + CFailableAchievement(); + void SetFailed(); + + virtual bool ShouldSaveWithGame(); + virtual void PreRestoreSavedGame(); + virtual void PostRestoreSavedGame(); + virtual bool IsAchieved() { return !m_bFailed && BaseClass::IsAchieved(); } + virtual bool IsActive() { return m_bActivated && !m_bFailed && BaseClass::IsActive(); } + bool IsFailed() { return m_bFailed; } + + virtual void OnMapEvent( const char *pEventName ); + virtual void OnActivationEvent() { Activate(); } + virtual void OnEvaluationEvent(); + virtual const char *GetActivationEventName() =0; + virtual const char *GetEvaluationEventName() =0; + +protected: + void Activate(); + + bool m_bActivated; // are we activated? (If there is a map event that turns us on, has that happened) + bool m_bFailed; // has this achievement failed + +public: + DECLARE_DATADESC(); +}; + +class CMapAchievement : public CBaseAchievement +{ + virtual void Init() + { + SetFlags( ACH_LISTEN_MAP_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } +}; + + +//---------------------------------------------------------------------------------------------------------------- +class CAchievement_AchievedCount : public CBaseAchievement +{ +public: + void Init(); + virtual void OnSteamUserStatsStored( void ); + virtual bool IsMetaAchievement() { return true; } + + int GetLowRange() { return m_iLowRange; } + int GetHighRange() { return m_iHighRange; } + int GetNumRequired() { return m_iNumRequired; } + +protected: + void SetAchievementsRequired( int iNumRequired, int iLowRange, int iHighRange ); + +private: + int m_iNumRequired; + int m_iLowRange; + int m_iHighRange; +}; + +// +// Helper class for achievement creation +// + +typedef CBaseAchievement* (*achievementCreateFunc) (void); +class CBaseAchievementHelper +{ +public: + CBaseAchievementHelper( achievementCreateFunc createFunc ) + { + m_pfnCreate = createFunc; + m_pNext = s_pFirst; + s_pFirst = this; + } + achievementCreateFunc m_pfnCreate; + CBaseAchievementHelper *m_pNext; + static CBaseAchievementHelper *s_pFirst; +}; + +#define DECLARE_ACHIEVEMENT_( className, achievementID, achievementName, gameDirFilter, iPointValue, bHidden ) \ +static CBaseAchievement *Create_##className( void ) \ +{ \ + CBaseAchievement *pAchievement = new className( ); \ + pAchievement->SetAchievementID( achievementID ); \ + pAchievement->SetName( achievementName ); \ + pAchievement->SetPointValue( iPointValue ); \ + pAchievement->SetHideUntilAchieved( bHidden ); \ + if ( gameDirFilter ) pAchievement->SetGameDirFilter( gameDirFilter ); \ + return pAchievement; \ +}; \ +static CBaseAchievementHelper g_##className##_Helper( Create_##className ); + +#define DECLARE_ACHIEVEMENT( className, achievementID, achievementName, iPointValue ) \ + DECLARE_ACHIEVEMENT_( className, achievementID, achievementName, NULL, iPointValue, false ) + +#define DECLARE_MAP_EVENT_ACHIEVEMENT_( achievementID, achievementName, gameDirFilter, iPointValue, bHidden ) \ +class CAchievement##achievementID : public CMapAchievement {}; \ +DECLARE_ACHIEVEMENT_( CAchievement##achievementID, achievementID, achievementName, gameDirFilter, iPointValue, bHidden ) \ + +#define DECLARE_MAP_EVENT_ACHIEVEMENT( achievementID, achievementName, iPointValue ) \ + DECLARE_MAP_EVENT_ACHIEVEMENT_( achievementID, achievementName, NULL, iPointValue, false ) + +#define DECLARE_MAP_EVENT_ACHIEVEMENT_HIDDEN( achievementID, achievementName, iPointValue ) \ + DECLARE_MAP_EVENT_ACHIEVEMENT_( achievementID, achievementName, NULL, iPointValue, true ) + +#endif // BASEACHIEVEMENT_H diff --git a/game/shared/basecombatweapon_shared.h b/game/shared/basecombatweapon_shared.h new file mode 100644 index 0000000..d4964d8 --- /dev/null +++ b/game/shared/basecombatweapon_shared.h @@ -0,0 +1,665 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef COMBATWEAPON_SHARED_H +#define COMBATWEAPON_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "sharedInterface.h" +#include "vphysics_interface.h" +#include "predictable_entity.h" +#include "soundflags.h" +#include "weapon_parse.h" +#include "baseviewmodel_shared.h" +#include "weapon_proficiency.h" +#include "utlmap.h" + +#if defined( CLIENT_DLL ) +#define CBaseCombatWeapon C_BaseCombatWeapon +#endif + +// Hacky +#if defined ( TF_CLIENT_DLL ) || defined ( TF_DLL ) +#include "econ_entity.h" +#endif // TF_CLIENT_DLL || TF_DLL + +#if !defined( CLIENT_DLL ) +extern void OnBaseCombatWeaponCreated( CBaseCombatWeapon * ); +extern void OnBaseCombatWeaponDestroyed( CBaseCombatWeapon * ); + +void *SendProxy_SendLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID ); +#endif + +class CBasePlayer; +class CBaseCombatCharacter; +class IPhysicsConstraint; +class CUserCmd; + +// How many times to display altfire hud hints (per weapon) +#define WEAPON_ALTFIRE_HUD_HINT_COUNT 1 +#define WEAPON_RELOAD_HUD_HINT_COUNT 1 + +//Start with a constraint in place (don't drop to floor) +#define SF_WEAPON_START_CONSTRAINED (1<<0) +#define SF_WEAPON_NO_PLAYER_PICKUP (1<<1) +#define SF_WEAPON_NO_PHYSCANNON_PUNT (1<<2) + +//Percent +#define CLIP_PERC_THRESHOLD 0.75f + +// Put this in your derived class definition to declare it's activity table +// UNDONE: Cascade these? +#define DECLARE_ACTTABLE() static acttable_t m_acttable[];\ + virtual acttable_t *ActivityList( int &iActivityCount ) OVERRIDE; + +// You also need to include the activity table itself in your class' implementation: +// e.g. +// acttable_t CWeaponStunstick::m_acttable[] = +// { +// { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, TRUE }, +// }; +// +// The stunstick overrides the ACT_MELEE_ATTACK1 activity, replacing it with ACT_MELEE_ATTACK_SWING. +// This animation is required for this weapon's operation. +// + +// Put this after your derived class' definition to implement the accessors for the +// activity table. +// UNDONE: Cascade these? +#define IMPLEMENT_ACTTABLE(className) \ + acttable_t *className::ActivityList( int &iActivityCount ) { iActivityCount = ARRAYSIZE(m_acttable); return m_acttable; } + +typedef struct +{ + int baseAct; + int weaponAct; + bool required; +} acttable_t; + + +struct poseparamtable_t +{ + const char *pszName; + float flValue; +}; + +// Put this in your derived class definition to declare it's poseparam table +#define DECLARE_POSEPARAMTABLE() static poseparamtable_t m_poseparamtable[];\ + virtual poseparamtable_t* PoseParamList( int &iPoseParamCount ) { return NULL; } + +// You also need to include the activity table itself in your class' implementation: +// e.g. +// acttable_t CTFGrapplingHook::m_poseparamtable[] = +// { +// { "r_arm", 2 }, +// }; +// +// The grapplinghook overrides the r_arm pose param, value to 2. + +#define IMPLEMENT_POSEPARAMTABLE(className)\ + poseparamtable_t* className::PoseParamList( int &iPoseParamCount ) { iPoseParamCount = ARRAYSIZE(m_poseparamtable); return m_poseparamtable; } + +class CHudTexture; +class Color; + +namespace vgui2 +{ + typedef unsigned long HFont; +} + +// ----------------------------------------- +// Vector cones +// ----------------------------------------- +// VECTOR_CONE_PRECALCULATED - this resolves to vec3_origin, but adds some +// context indicating that the person writing the code is not allowing +// FireBullets() to modify the direction of the shot because the shot direction +// being passed into the function has already been modified by another piece of +// code and should be fired as specified. See GetActualShotTrajectory(). + +// NOTE: The way these are calculated is that each component == sin (degrees/2) +#define VECTOR_CONE_PRECALCULATED vec3_origin +#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) +#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) +#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) +#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) +#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) +#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) +#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) +#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) +#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) +#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) +#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) +#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) + +//----------------------------------------------------------------------------- +// Purpose: Base weapon class, shared on client and server +//----------------------------------------------------------------------------- + +#if defined USES_ECON_ITEMS +#define BASECOMBATWEAPON_DERIVED_FROM CEconEntity +#else +#define BASECOMBATWEAPON_DERIVED_FROM CBaseAnimating +#endif + +//----------------------------------------------------------------------------- +// Collect trace attacks for weapons that fire multiple projectiles per attack that also penetrate +//----------------------------------------------------------------------------- +class CDmgAccumulator +{ +public: + CDmgAccumulator( void ); + ~CDmgAccumulator(); + +#ifdef GAME_DLL + virtual void Start( void ) { m_bActive = true; } + virtual void AccumulateMultiDamage( const CTakeDamageInfo &info, CBaseEntity *pEntity ); + virtual void Process( void ); + +private: + CTakeDamageInfo m_updatedInfo; + CUtlMap< int, CTakeDamageInfo > m_TargetsDmgInfo; +#endif // GAME_DLL + +private: + bool m_bActive; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Client side rep of CBaseTFCombatWeapon +//----------------------------------------------------------------------------- +// Hacky +class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM +{ +public: + DECLARE_CLASS( CBaseCombatWeapon, BASECOMBATWEAPON_DERIVED_FROM ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CBaseCombatWeapon(); + virtual ~CBaseCombatWeapon(); + + virtual bool IsBaseCombatWeapon( void ) const { return true; } + virtual CBaseCombatWeapon *MyCombatWeaponPointer( void ) { return this; } + + // A derived weapon class should return true here so that weapon sounds, etc, can + // apply the proper filter + virtual bool IsPredicted( void ) const { return false; } + + virtual void Spawn( void ); + virtual void Precache( void ); + + void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + + // Subtypes are used to manage multiple weapons of the same type on the player. + virtual int GetSubType( void ) { return m_iSubType; } + virtual void SetSubType( int iType ) { m_iSubType = iType; } + + virtual void Equip( CBaseCombatCharacter *pOwner ); + virtual void Drop( const Vector &vecVelocity ); + + virtual int UpdateClientData( CBasePlayer *pPlayer ); + + virtual bool IsAllowedToSwitch( void ); + virtual bool CanBeSelected( void ); + virtual bool VisibleInWeaponSelection( void ); + virtual bool HasAmmo( void ); + + // Weapon Pickup For Player + virtual void SetPickupTouch( void ); + virtual void DefaultTouch( CBaseEntity *pOther ); // default weapon touch + virtual void GiveTo( CBaseEntity *pOther ); + + // HUD Hints + virtual bool ShouldDisplayAltFireHUDHint(); + virtual void DisplayAltFireHudHint(); + virtual void RescindAltFireHudHint(); ///< undisplay the hud hint and pretend it never showed. + + virtual bool ShouldDisplayReloadHUDHint(); + virtual void DisplayReloadHudHint(); + virtual void RescindReloadHudHint(); + + // Weapon client handling + virtual void SetViewModelIndex( int index = 0 ); + virtual bool SendWeaponAnim( int iActivity ); + virtual void SendViewModelAnim( int nSequence ); + float GetViewModelSequenceDuration(); // Return how long the current view model sequence is. + bool IsViewModelSequenceFinished( void ) const; // Returns if the viewmodel's current animation is finished + + virtual void SetViewModel(); + + virtual bool HasWeaponIdleTimeElapsed( void ); + virtual void SetWeaponIdleTime( float time ); + virtual float GetWeaponIdleTime( void ); + + // Weapon selection + virtual bool HasAnyAmmo( void ); // Returns true is weapon has ammo + virtual bool HasPrimaryAmmo( void ); // Returns true is weapon has ammo + virtual bool HasSecondaryAmmo( void ); // Returns true is weapon has ammo + bool UsesPrimaryAmmo( void ); // returns true if the weapon actually uses primary ammo + bool UsesSecondaryAmmo( void ); // returns true if the weapon actually uses secondary ammo + void GiveDefaultAmmo( void ); + + virtual bool CanHolster( void ) const { return TRUE; }; // returns true if the weapon can be holstered + virtual bool DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt ); + virtual bool CanDeploy( void ) { return true; } // return true if the weapon's allowed to deploy + virtual bool Deploy( void ); // returns true is deploy was successful + virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + virtual CBaseCombatWeapon *GetLastWeapon( void ) { return this; } + virtual void SetWeaponVisible( bool visible ); + virtual bool IsWeaponVisible( void ); + virtual bool ReloadOrSwitchWeapons( void ); + virtual void OnActiveStateChanged( int iOldState ) { return; } + virtual bool HolsterOnDetach() { return false; } + virtual bool IsHolstered(){ return false; } + virtual void Detach() {} + + // Weapon behaviour + virtual void ItemPreFrame( void ); // called each frame by the player PreThink + virtual void ItemPostFrame( void ); // called each frame by the player PostThink + virtual void ItemBusyFrame( void ); // called each frame by the player PostThink, if the player's not ready to attack yet + virtual void ItemHolsterFrame( void ) {}; // called each frame by the player PreThink, if the weapon is holstered + virtual void WeaponIdle( void ); // called when no buttons pressed + virtual void HandleFireOnEmpty(); // Called when they have the attack button down + // but they are out of ammo. The default implementation + // either reloads, switches weapons, or plays an empty sound. + virtual bool CanPerformSecondaryAttack() const; + + virtual bool ShouldBlockPrimaryFire() { return false; } + +#ifdef CLIENT_DLL + virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd, const QAngle &vecOldViewAngles ) {} + virtual int CalcOverrideModelIndex() OVERRIDE; +#endif + + virtual bool IsWeaponZoomed() { return false; } // Is this weapon in its 'zoomed in' mode? + + // Reloading + virtual void CheckReload( void ); + virtual void FinishReload( void ); + virtual void AbortReload( void ); + virtual bool Reload( void ); + bool DefaultReload( int iClipSize1, int iClipSize2, int iActivity ); + bool ReloadsSingly( void ) const; + + virtual bool AutoFiresFullClip( void ) const { return false; } + virtual void UpdateAutoFire( void ); + + // Weapon firing + virtual void PrimaryAttack( void ); // do "+ATTACK" + virtual void SecondaryAttack( void ) { return; } // do "+ATTACK2" + + // Firing animations + virtual Activity GetPrimaryAttackActivity( void ); + virtual Activity GetSecondaryAttackActivity( void ); + virtual Activity GetDrawActivity( void ); + virtual float GetDefaultAnimSpeed( void ) { return 1.0; } + + // Bullet launch information + virtual int GetBulletType( void ); + virtual const Vector& GetBulletSpread( void ); + virtual Vector GetBulletSpread( WeaponProficiency_t proficiency ) { return GetBulletSpread(); } + virtual float GetSpreadBias( WeaponProficiency_t proficiency ) { return 1.0; } + virtual float GetFireRate( void ); + virtual int GetMinBurst() { return 1; } + virtual int GetMaxBurst() { return 1; } + virtual float GetMinRestTime() { return 0.3; } + virtual float GetMaxRestTime() { return 0.6; } + virtual int GetRandomBurst() { return random->RandomInt( GetMinBurst(), GetMaxBurst() ); } + virtual void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f ); + virtual void StopWeaponSound( WeaponSound_t sound_type ); + virtual const WeaponProficiencyInfo_t *GetProficiencyValues(); + + // Autoaim + virtual float GetMaxAutoAimDeflection() { return 0.99f; } + virtual float WeaponAutoAimScale() { return 1.0f; } // allows a weapon to influence the perceived size of the target's autoaim radius. + + // TF Sprinting functions + virtual bool StartSprinting( void ) { return false; }; + virtual bool StopSprinting( void ) { return false; }; + + // TF Injury functions + virtual float GetDamage( float flDistance, int iLocation ) { return 0.0; }; + + virtual void SetActivity( Activity act, float duration ); + inline void SetActivity( Activity eActivity ) { m_Activity = eActivity; } + inline Activity GetActivity( void ) const { return m_Activity; } + + virtual void AddViewKick( void ); // Add in the view kick for the weapon + + virtual char *GetDeathNoticeName( void ); // Get the string to print death notices with + + CBaseCombatCharacter *GetOwner() const; + void SetOwner( CBaseCombatCharacter *owner ); + virtual void OnPickedUp( CBaseCombatCharacter *pNewOwner ); + + virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ) {}; + virtual float CalcViewmodelBob( void ) { return 0.0f; }; + + // Returns information about the various control panels + virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ); + virtual void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName ); + + virtual bool ShouldShowControlPanels( void ) { return true; } + + void Lock( float lockTime, CBaseEntity *pLocker ); + bool IsLocked( CBaseEntity *pAsker ); + + //All weapons can be picked up by NPCs by default + virtual bool CanBePickedUpByNPCs( void ) { return true; } + + virtual int GetSkinOverride() const { return -1; } + +public: + + // Weapon info accessors for data in the weapon's data file + const FileWeaponInfo_t &GetWpnData( void ) const; + virtual const char *GetViewModel( int viewmodelindex = 0 ) const; + virtual const char *GetWorldModel( void ) const; + virtual const char *GetAnimPrefix( void ) const; + virtual int GetMaxClip1( void ) const; + virtual int GetMaxClip2( void ) const; + virtual int GetDefaultClip1( void ) const; + virtual int GetDefaultClip2( void ) const; + virtual int GetWeight( void ) const; + virtual bool AllowsAutoSwitchTo( void ) const; + virtual bool AllowsAutoSwitchFrom( void ) const; + virtual bool ForceWeaponSwitch( void ) const { return false; } + virtual int GetWeaponFlags( void ) const; + virtual int GetSlot( void ) const; + virtual int GetPosition( void ) const; + virtual char const *GetName( void ) const; + virtual char const *GetPrintName( void ) const; + virtual char const *GetShootSound( int iIndex ) const; + virtual int GetRumbleEffect() const; + virtual bool UsesClipsForAmmo1( void ) const; + virtual bool UsesClipsForAmmo2( void ) const; + bool IsMeleeWeapon() const; + + // derive this function if you mod uses encrypted weapon info files + virtual const unsigned char *GetEncryptionKey( void ); + + virtual int GetPrimaryAmmoType( void ) const { return m_iPrimaryAmmoType; } + virtual int GetSecondaryAmmoType( void ) const { return m_iSecondaryAmmoType; } + virtual int Clip1() { return m_iClip1; } + virtual int Clip2() { return m_iClip2; } + + // Ammo quantity queries for weapons that do not use clips. These are only + // used to determine how much ammo is in a weapon that does not have an owner. + // That is, a weapon that's on the ground for the player to get ammo out of. + int GetPrimaryAmmoCount() { return m_iPrimaryAmmoCount; } + void SetPrimaryAmmoCount( int count ) { m_iPrimaryAmmoCount = count; } + + int GetSecondaryAmmoCount() { return m_iSecondaryAmmoCount; } + void SetSecondaryAmmoCount( int count ) { m_iSecondaryAmmoCount = count; } + + virtual CHudTexture const *GetSpriteActive( void ) const; + virtual CHudTexture const *GetSpriteInactive( void ) const; + virtual CHudTexture const *GetSpriteAmmo( void ) const; + virtual CHudTexture const *GetSpriteAmmo2( void ) const; + virtual CHudTexture const *GetSpriteCrosshair( void ) const; + virtual CHudTexture const *GetSpriteAutoaim( void ) const; + virtual CHudTexture const *GetSpriteZoomedCrosshair( void ) const; + virtual CHudTexture const *GetSpriteZoomedAutoaim( void ) const; + + virtual Activity ActivityOverride( Activity baseAct, bool *pRequired ); + virtual acttable_t* ActivityList( int &iActivityCount ) { return NULL; } + + virtual void PoseParameterOverride( bool bReset ); + virtual poseparamtable_t* PoseParamList( int &iPoseParamCount ) { return NULL; } + + virtual void Activate( void ); + + virtual bool ShouldUseLargeViewModelVROverride() { return false; } +public: +// Server Only Methods +#if !defined( CLIENT_DLL ) + + DECLARE_DATADESC(); + virtual void FallInit( void ); // prepare to fall to the ground + virtual void FallThink( void ); // make the weapon fall to the ground after spawning + + // Weapon spawning + bool IsConstrained() { return m_pConstraint != NULL; } + bool IsInBadPosition ( void ); // Is weapon in bad position to pickup? + bool RepositionWeapon ( void ); // Attempts to reposition the weapon in a location where it can be + virtual void Materialize( void ); // make a weapon visible and tangible + void AttemptToMaterialize( void ); // see if the game rules will let the weapon become visible and tangible + virtual void CheckRespawn( void ); // see if this weapon should respawn after being picked up + CBaseEntity *Respawn ( void ); // copy a weapon + + static int GetAvailableWeaponsInBox( CBaseCombatWeapon **pList, int listMax, const Vector &mins, const Vector &maxs ); + + // Weapon dropping / destruction + virtual void Delete( void ); + void DestroyItem( void ); + virtual void Kill( void ); + + virtual int CapabilitiesGet( void ) { return 0; } + virtual int ObjectCaps( void ); + + bool IsRemoveable() { return m_bRemoveable; } + void SetRemoveable( bool bRemoveable ) { m_bRemoveable = bRemoveable; } + + // Returns bits for weapon conditions + virtual bool WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ); + virtual int WeaponRangeAttack1Condition( float flDot, float flDist ); + virtual int WeaponRangeAttack2Condition( float flDot, float flDist ); + virtual int WeaponMeleeAttack1Condition( float flDot, float flDist ); + virtual int WeaponMeleeAttack2Condition( float flDot, float flDist ); + + virtual void Operator_FrameUpdate( CBaseCombatCharacter *pOperator ); + virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + virtual void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ) { return; } + // NOTE: This should never be called when a character is operating the weapon. Animation events should be + // routed through the character, and then back into CharacterAnimEvent() + void HandleAnimEvent( animevent_t *pEvent ); + + virtual int UpdateTransmitState( void ); + + void InputHideWeapon( inputdata_t &inputdata ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + virtual CDmgAccumulator *GetDmgAccumulator( void ) { return NULL; } + +// Client only methods +#else + + virtual void BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const; + + virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options ) + { +#if defined USES_ECON_ITEMS + return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options ); +#else + return false; +#endif + } + + // Should this object cast shadows? + virtual ShadowType_t ShadowCastType(); + virtual void SetDormant( bool bDormant ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void OnRestore(); + + virtual void RestartParticleEffect( void ) {} + + virtual void Redraw(void); + virtual void ViewModelDrawn( CBaseViewModel *pViewModel ); + // Get the position that bullets are seen coming out. Note: the returned values are different + // for first person and third person. + bool GetShootPosition( Vector &vOrigin, QAngle &vAngles ); + virtual void DrawCrosshair( void ); + virtual bool ShouldDrawCrosshair( void ) { return true; } + + // Weapon state checking + virtual bool IsCarriedByLocalPlayer( void ); + virtual bool ShouldDrawUsingViewModel( void ); + virtual bool IsActiveByLocalPlayer( void ); + + bool IsBeingCarried() const; + + // Is the carrier alive? + bool IsCarrierAlive() const; + + // Returns the aiment render origin + angles + virtual int DrawModel( int flags ); + virtual bool ShouldDraw( void ); + virtual bool ShouldDrawPickup( void ); + virtual void HandleInput( void ) { return; }; + virtual void OverrideMouseInput( float *x, float *y ) { return; }; + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { return 1; } + virtual bool AddLookShift( void ) { return true; }; + + virtual void GetViewmodelBoneControllers(C_BaseViewModel *pViewModel, float controllers[MAXSTUDIOBONECTRLS]) { return; } + + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + WEAPON_FILE_INFO_HANDLE GetWeaponFileInfoHandle() { return m_hWeaponFileInfo; } + + virtual int GetWorldModelIndex( void ); + + virtual void GetToolRecordingState( KeyValues *msg ); + + virtual void GetWeaponCrosshairScale( float &flScale ) { flScale = 1.f; } + +#if !defined USES_ECON_ITEMS + // Viewmodel overriding + virtual bool ViewModel_IsTransparent( void ) { return IsTransparent(); } + virtual bool ViewModel_IsUsingFBTexture( void ) { return UsesPowerOfTwoFrameBufferTexture(); } + virtual bool IsOverridingViewmodel( void ) { return false; }; + virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ) { return 0; }; + bool WantsToOverrideViewmodelAttachments( void ) { return false; } +#endif + +#endif // End client-only methods + + virtual bool CanLower( void ) { return false; } + virtual bool Ready( void ) { return false; } + virtual bool Lower( void ) { return false; } + + virtual void HideThink( void ); + virtual bool CanReload( void ); + +private: + typedef CHandle< CBaseCombatCharacter > CBaseCombatCharacterHandle; + CNetworkVar( CBaseCombatCharacterHandle, m_hOwner ); // Player carrying this weapon + +protected: +#if defined ( TF_CLIENT_DLL ) || defined ( TF_DLL ) + // Regulate crit frequency to reduce client-side seed hacking + void AddToCritBucket( float flAmount ); + void RemoveFromCritBucket( float flAmount ) { m_flCritTokenBucket -= flAmount; } + bool IsAllowedToWithdrawFromCritBucket( float flDamage ); + + float m_flCritTokenBucket; + int m_nCritChecks; + int m_nCritSeedRequests; +#endif // TF + +public: + + // Networked fields + CNetworkVar( int, m_nViewModelIndex ); + + // Weapon firing + CNetworkVar( float, m_flNextPrimaryAttack ); // soonest time ItemPostFrame will call PrimaryAttack + CNetworkVar( float, m_flNextSecondaryAttack ); // soonest time ItemPostFrame will call SecondaryAttack + CNetworkVar( float, m_flTimeWeaponIdle ); // soonest time ItemPostFrame will call WeaponIdle + // Weapon state + bool m_bInReload; // Are we in the middle of a reload; + bool m_bFireOnEmpty; // True when the gun is empty and the player is still holding down the attack key(s) + bool m_bFiringWholeClip; // Are we in the middle of firing the whole clip; + // Weapon art + CNetworkVar( int, m_iViewModelIndex ); + CNetworkVar( int, m_iWorldModelIndex ); + // Sounds + float m_flNextEmptySoundTime; // delay on empty sound playing + + Activity GetIdealActivity( void ) { return m_IdealActivity; } + int GetIdealSequence( void ) { return m_nIdealSequence; } + + bool SetIdealActivity( Activity ideal ); + void MaintainIdealActivity( void ); + +private: + Activity m_Activity; + int m_nIdealSequence; + Activity m_IdealActivity; + + bool m_bRemoveable; + + int m_iPrimaryAmmoCount; + int m_iSecondaryAmmoCount; + +public: + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_nNextThinkTick ); + +#ifdef CLIENT_DLL + static void RecvProxy_WeaponState( const CRecvProxyData *pData, void *pStruct, void *pOut ); +#endif + int WeaponState() const { return m_iState; } + + // Weapon data + CNetworkVar( int, m_iState ); // See WEAPON_* definition + string_t m_iszName; // Classname of this weapon. + CNetworkVar( int, m_iPrimaryAmmoType ); // "primary" ammo index into the ammo info array + CNetworkVar( int, m_iSecondaryAmmoType ); // "secondary" ammo index into the ammo info array + CNetworkVar( int, m_iClip1 ); // number of shots left in the primary weapon clip, -1 it not used + CNetworkVar( int, m_iClip2 ); // number of shots left in the secondary weapon clip, -1 it not used + bool m_bFiresUnderwater; // true if this weapon can fire underwater + bool m_bAltFiresUnderwater; // true if this weapon can fire underwater + float m_fMinRange1; // What's the closest this weapon can be used? + float m_fMinRange2; // What's the closest this weapon can be used? + float m_fMaxRange1; // What's the furthest this weapon can be used? + float m_fMaxRange2; // What's the furthest this weapon can be used? + bool m_bReloadsSingly; // True if this weapon reloads 1 round at a time + float m_fFireDuration; // The amount of time that the weapon has sustained firing + int m_iSubType; + + float m_flUnlockTime; + EHANDLE m_hLocker; // Who locked this weapon. + + CNetworkVar( bool, m_bFlipViewModel ); + + IPhysicsConstraint *GetConstraint() { return m_pConstraint; } + +private: + WEAPON_FILE_INFO_HANDLE m_hWeaponFileInfo; + IPhysicsConstraint *m_pConstraint; + + int m_iAltFireHudHintCount; // How many times has this weapon displayed its alt-fire HUD hint? + int m_iReloadHudHintCount; // How many times has this weapon displayed its reload HUD hint? + bool m_bAltFireHudHintDisplayed; // Have we displayed an alt-fire HUD hint since this weapon was deployed? + bool m_bReloadHudHintDisplayed; // Have we displayed a reload HUD hint since this weapon was deployed? + float m_flHudHintPollTime; // When to poll the weapon again for whether it should display a hud hint. + float m_flHudHintMinDisplayTime; // if the hint is squelched before this, reset my counter so we'll display it again. + + // Server only +#if !defined( CLIENT_DLL ) + + // Outputs +protected: + COutputEvent m_OnPlayerUse; // Fired when the player uses the weapon. + COutputEvent m_OnPlayerPickup; // Fired when the player picks up the weapon. + COutputEvent m_OnNPCPickup; // Fired when an NPC picks up the weapon. + COutputEvent m_OnCacheInteraction; // For awarding lambda cache achievements in HL2 on 360. See .FGD file for details + +#else // Client .dll only + bool m_bJustRestored; + + // Allow weapons resource to access m_hWeaponFileInfo directly + friend class WeaponsResource; + +protected: + int m_iOldState; + +#endif // End Client .dll only +}; + +#endif // COMBATWEAPON_SHARED_H diff --git a/game/shared/baseentity_shared.h b/game/shared/baseentity_shared.h new file mode 100644 index 0000000..52a90ab --- /dev/null +++ b/game/shared/baseentity_shared.h @@ -0,0 +1,314 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEENTITY_SHARED_H +#define BASEENTITY_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +extern ConVar hl2_episodic; + +// Simple shared header file for common base entities + +// entity capabilities +// These are caps bits to indicate what an object's capabilities (currently used for +USE, save/restore and level transitions) +#define FCAP_MUST_SPAWN 0x00000001 // Spawn after restore +#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions +// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! +#define FCAP_FORCE_TRANSITION 0x00000004 // ALWAYS goes across transitions +#define FCAP_NOTIFY_ON_TRANSITION 0x00000008 // Entity will receive Inside/Outside transition inputs when a transition occurs + +#define FCAP_IMPULSE_USE 0x00000010 // can be used by the player +#define FCAP_CONTINUOUS_USE 0x00000020 // can be used by the player +#define FCAP_ONOFF_USE 0x00000040 // can be used by the player +#define FCAP_DIRECTIONAL_USE 0x00000080 // Player sends +/- 1 when using (currently only tracktrains) +// NOTE: Normally +USE only works in direct line of sight. Add these caps for additional searches +#define FCAP_USE_ONGROUND 0x00000100 +#define FCAP_USE_IN_RADIUS 0x00000200 +#define FCAP_SAVE_NON_NETWORKABLE 0x00000400 + +#define FCAP_MASTER 0x10000000 // Can be used to "master" other entities (like multisource) +#define FCAP_WCEDIT_POSITION 0x40000000 // Can change position and update Hammer in edit mode +#define FCAP_DONT_SAVE 0x80000000 // Don't save this + + +// How many bits are used to transmit parent attachment indices? +#define NUM_PARENTATTACHMENT_BITS 6 + +// Maximum number of vphysics objects per entity +#define VPHYSICS_MAX_OBJECT_LIST_COUNT 1024 + +//----------------------------------------------------------------------------- +// For invalidate physics recursive +//----------------------------------------------------------------------------- +enum InvalidatePhysicsBits_t +{ + POSITION_CHANGED = 0x1, + ANGLES_CHANGED = 0x2, + VELOCITY_CHANGED = 0x4, + ANIMATION_CHANGED = 0x8, +}; + + +#if defined( CLIENT_DLL ) +#include "c_baseentity.h" +#include "c_baseanimating.h" +#else +#include "baseentity.h" + +#ifdef HL2_EPISODIC + #include "info_darknessmode_lightsource.h" +#endif // HL2_EPISODIC + +#endif + +#if !defined( NO_ENTITY_PREDICTION ) +// CBaseEntity inlines +inline bool CBaseEntity::IsPlayerSimulated( void ) const +{ + return m_bIsPlayerSimulated; +} + +inline CBasePlayer *CBaseEntity::GetSimulatingPlayer( void ) +{ + return m_hPlayerSimulationOwner; +} +#endif + +inline MoveType_t CBaseEntity::GetMoveType() const +{ + return (MoveType_t)(unsigned char)m_MoveType; +} + +inline MoveCollide_t CBaseEntity::GetMoveCollide() const +{ + return (MoveCollide_t)(unsigned char)m_MoveCollide; +} + +//----------------------------------------------------------------------------- +// Collision group accessors +//----------------------------------------------------------------------------- +inline int CBaseEntity::GetCollisionGroup() const +{ + return m_CollisionGroup; +} + +inline int CBaseEntity::GetFlags( void ) const +{ + return m_fFlags; +} + +inline bool CBaseEntity::IsAlive( void ) +{ + return m_lifeState == LIFE_ALIVE; +} + +inline CBaseEntity *CBaseEntity::GetOwnerEntity() const +{ + return m_hOwnerEntity.Get(); +} + +inline CBaseEntity *CBaseEntity::GetEffectEntity() const +{ + return m_hEffectEntity.Get(); +} + +inline int CBaseEntity::GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime ) +{ +#ifdef GAME_DLL + return bUseUnSyncedServerPlatTime ? m_nPredictionRandomSeedServer : m_nPredictionRandomSeed; +#else + return m_nPredictionRandomSeed; +#endif +} + +inline CBasePlayer *CBaseEntity::GetPredictionPlayer( void ) +{ + return m_pPredictionPlayer; +} + +inline void CBaseEntity::SetPredictionPlayer( CBasePlayer *player ) +{ + m_pPredictionPlayer = player; +} + + +inline bool CBaseEntity::IsSimulatedEveryTick() const +{ + return m_bSimulatedEveryTick; +} + +inline bool CBaseEntity::IsAnimatedEveryTick() const +{ + return m_bAnimatedEveryTick; +} + +inline void CBaseEntity::SetSimulatedEveryTick( bool sim ) +{ + if ( m_bSimulatedEveryTick != sim ) + { + m_bSimulatedEveryTick = sim; +#ifdef CLIENT_DLL + Interp_UpdateInterpolationAmounts( GetVarMapping() ); +#endif + } +} + +inline void CBaseEntity::SetAnimatedEveryTick( bool anim ) +{ + if ( m_bAnimatedEveryTick != anim ) + { + m_bAnimatedEveryTick = anim; +#ifdef CLIENT_DLL + Interp_UpdateInterpolationAmounts( GetVarMapping() ); +#endif + } +} + +inline float CBaseEntity::GetAnimTime() const +{ + return m_flAnimTime; +} + +inline float CBaseEntity::GetSimulationTime() const +{ + return m_flSimulationTime; +} + +inline void CBaseEntity::SetAnimTime( float at ) +{ + m_flAnimTime = at; +} + +inline void CBaseEntity::SetSimulationTime( float st ) +{ + m_flSimulationTime = st; +} + +inline int CBaseEntity::GetEffects( void ) const +{ + return m_fEffects; +} + +inline void CBaseEntity::RemoveEffects( int nEffects ) +{ +#if !defined( CLIENT_DLL ) +#ifdef HL2_EPISODIC + if ( nEffects & (EF_BRIGHTLIGHT|EF_DIMLIGHT) ) + { + // Hack for now, to avoid player emitting radius with his flashlight + if ( !IsPlayer() ) + { + RemoveEntityFromDarknessCheck( this ); + } + } +#endif // HL2_EPISODIC +#endif // !CLIENT_DLL + + m_fEffects &= ~nEffects; + if ( nEffects & EF_NODRAW ) + { +#ifndef CLIENT_DLL + NetworkProp()->MarkPVSInformationDirty(); + DispatchUpdateTransmitState(); +#else + UpdateVisibility(); +#endif + } +} + +inline void CBaseEntity::ClearEffects( void ) +{ +#if !defined( CLIENT_DLL ) +#ifdef HL2_EPISODIC + if ( m_fEffects & (EF_BRIGHTLIGHT|EF_DIMLIGHT) ) + { + // Hack for now, to avoid player emitting radius with his flashlight + if ( !IsPlayer() ) + { + RemoveEntityFromDarknessCheck( this ); + } + } +#endif // HL2_EPISODIC +#endif // !CLIENT_DLL + + m_fEffects = 0; +#ifndef CLIENT_DLL + DispatchUpdateTransmitState(); +#else + UpdateVisibility(); +#endif +} + +inline bool CBaseEntity::IsEffectActive( int nEffects ) const +{ + return (m_fEffects & nEffects) != 0; +} + +// Shared EntityMessage between game and client .dlls +#define BASEENTITY_MSG_REMOVE_DECALS 1 + +extern float k_flMaxEntityPosCoord; +extern float k_flMaxEntityEulerAngle; +extern float k_flMaxEntitySpeed; +extern float k_flMaxEntitySpinRate; + +inline bool IsEntityCoordinateReasonable ( const vec_t c ) +{ + float r = k_flMaxEntityPosCoord; + return c > -r && c < r; +} + +inline bool IsEntityPositionReasonable( const Vector &v ) +{ + float r = k_flMaxEntityPosCoord; + return + v.x > -r && v.x < r && + v.y > -r && v.y < r && + v.z > -r && v.z < r; +} + +// Returns: +// -1 - velocity is really, REALLY bad and probably should be rejected. +// 0 - velocity was suspicious and clamped. +// 1 - velocity was OK and not modified +extern int CheckEntityVelocity( Vector &v ); + +inline bool IsEntityQAngleReasonable( const QAngle &q ) +{ + float r = k_flMaxEntityEulerAngle; + return + q.x > -r && q.x < r && + q.y > -r && q.y < r && + q.z > -r && q.z < r; +} + +// Angular velocity in exponential map form +inline bool IsEntityAngularVelocityReasonable( const Vector &q ) +{ + float r = k_flMaxEntitySpinRate; + return + q.x > -r && q.x < r && + q.y > -r && q.y < r && + q.z > -r && q.z < r; +} + +// Angular velocity of each Euler angle. +inline bool IsEntityQAngleVelReasonable( const QAngle &q ) +{ + float r = k_flMaxEntitySpinRate; + return + q.x > -r && q.x < r && + q.y > -r && q.y < r && + q.z > -r && q.z < r; +} + +extern bool CheckEmitReasonablePhysicsSpew(); + +#endif // BASEENTITY_SHARED_H diff --git a/game/shared/basegrenade_shared.h b/game/shared/basegrenade_shared.h new file mode 100644 index 0000000..38bb684 --- /dev/null +++ b/game/shared/basegrenade_shared.h @@ -0,0 +1,140 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEGRENADE_SHARED_H +#define BASEGRENADE_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseprojectile.h" + +#if defined( CLIENT_DLL ) + +#define CBaseGrenade C_BaseGrenade + +#include "c_basecombatcharacter.h" + +#else + +#include "basecombatcharacter.h" +#include "player_pickup.h" + +#endif + +#define BASEGRENADE_EXPLOSION_VOLUME 1024 + +class CTakeDamageInfo; + +#if !defined( CLIENT_DLL ) +class CBaseGrenade : public CBaseProjectile, public CDefaultPlayerPickupVPhysics +#else +class CBaseGrenade : public CBaseProjectile +#endif +{ + DECLARE_CLASS( CBaseGrenade, CBaseProjectile ); +public: + + CBaseGrenade(void); + ~CBaseGrenade(void); + + DECLARE_PREDICTABLE(); + DECLARE_NETWORKCLASS(); + + +#if !defined( CLIENT_DLL ) + DECLARE_DATADESC(); +#endif + + virtual void Precache( void ); + + virtual void Explode( trace_t *pTrace, int bitsDamageType ); + void Smoke( void ); + + void BounceTouch( CBaseEntity *pOther ); + void SlideTouch( CBaseEntity *pOther ); + void ExplodeTouch( CBaseEntity *pOther ); + void DangerSoundThink( void ); + void PreDetonate( void ); + virtual void Detonate( void ); + void DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void TumbleThink( void ); + + virtual Vector GetBlastForce() { return vec3_origin; } + + virtual void BounceSound( void ); + virtual int BloodColor( void ) { return DONT_BLEED; } + virtual void Event_Killed( const CTakeDamageInfo &info ); + + virtual float GetShakeAmplitude( void ) { return 25.0; } + virtual float GetShakeRadius( void ) { return 750.0; } + + // Damage accessors. + virtual float GetDamage() + { + return m_flDamage; + } + virtual float GetDamageRadius() + { + return m_DmgRadius; + } + + virtual void SetDamage(float flDamage) + { + m_flDamage = flDamage; + } + + virtual void SetDamageRadius(float flDamageRadius) + { + m_DmgRadius = flDamageRadius; + } + + // Bounce sound accessors. + void SetBounceSound( const char *pszBounceSound ) + { + m_iszBounceSound = MAKE_STRING( pszBounceSound ); + } + + CBaseCombatCharacter *GetThrower( void ); + void SetThrower( CBaseCombatCharacter *pThrower ); + CBaseEntity *GetOriginalThrower() { return m_hOriginalThrower; } + +#if !defined( CLIENT_DLL ) + // Allow +USE pickup + int ObjectCaps() + { + return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS); + } + + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +#endif + +public: + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_vecVelocity ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_fFlags ); + + bool m_bHasWarnedAI; // whether or not this grenade has issued its DANGER sound to the world sound list yet. + CNetworkVar( bool, m_bIsLive ); // Is this grenade live, or can it be picked up? + CNetworkVar( float, m_DmgRadius ); // How far do I do damage? + CNetworkVar( float, m_flNextAttack ); + float m_flDetonateTime; // Time at which to detonate. + float m_flWarnAITime; // Time at which to warn the AI + +protected: + + CNetworkVar( float, m_flDamage ); // Damage to inflict. + string_t m_iszBounceSound; // The sound to make on bouncing. If not NULL, overrides the BounceSound() function. + +private: + CNetworkHandle( CBaseEntity, m_hThrower ); // Who threw this grenade + EHANDLE m_hOriginalThrower; // Who was the original thrower of this grenade + + CBaseGrenade( const CBaseGrenade & ); // not defined, not accessible + +}; + +#endif // BASEGRENADE_SHARED_H diff --git a/game/shared/baseparticleentity.h b/game/shared/baseparticleentity.h new file mode 100644 index 0000000..7de9f4a --- /dev/null +++ b/game/shared/baseparticleentity.h @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// Particle system entities can derive from this to handle some of the mundane +// functionality of hooking into the engine's entity system. + +#ifndef PARTICLE_BASEEFFECT_H +#define PARTICLE_BASEEFFECT_H + +#include "predictable_entity.h" +#include "baseentity_shared.h" + +#if defined( CLIENT_DLL ) +#define CBaseParticleEntity C_BaseParticleEntity + +#include "particlemgr.h" + +#endif + +class CBaseParticleEntity : public CBaseEntity +#if defined( CLIENT_DLL ) +, public IParticleEffect +#endif +{ +public: + DECLARE_CLASS( CBaseParticleEntity, CBaseEntity ); + DECLARE_PREDICTABLE(); + DECLARE_NETWORKCLASS(); + + CBaseParticleEntity(); + virtual ~CBaseParticleEntity(); + + // CBaseEntity overrides. +public: +#if !defined( CLIENT_DLL ) + virtual int UpdateTransmitState( void ); +#else +// Default IParticleEffect overrides. +public: + + virtual bool ShouldSimulate() const { return m_bSimulate; } + virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; } + + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual const Vector & GetSortOrigin(); +public: + CParticleEffectBinding m_ParticleEffect; +#endif + + virtual void Activate(); + virtual void Think(); + +#if defined( CLIENT_DLL ) + // NOTE: Ths enclosed particle effect binding will do all the drawing + virtual bool ShouldDraw() { return false; } + + int AllocateToolParticleEffectId(); + int GetToolParticleEffectId() const; + +private: + int m_nToolParticleEffectId; + bool m_bSimulate; +#endif + +public: + void FollowEntity(CBaseEntity *pEntity); + + // UTIL_Remove will be called after the specified amount of time. + // If you pass in -1, the entity will never go away automatically. + void SetLifetime(float lifetime); + +private: + CBaseParticleEntity( const CBaseParticleEntity & ); // not defined, not accessible +}; + + +#if defined( CLIENT_DLL ) + +inline int CBaseParticleEntity::GetToolParticleEffectId() const +{ + return m_nToolParticleEffectId; +} + +inline int CBaseParticleEntity::AllocateToolParticleEffectId() +{ + m_nToolParticleEffectId = ParticleMgr()->AllocateToolParticleEffectId(); + return m_nToolParticleEffectId; +} + +#endif // CLIENT_DLL + +#endif + + diff --git a/game/shared/baseplayer_shared.h b/game/shared/baseplayer_shared.h new file mode 100644 index 0000000..8bdc095 --- /dev/null +++ b/game/shared/baseplayer_shared.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEPLAYER_SHARED_H +#define BASEPLAYER_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +// PlayerUse defines +#define PLAYER_USE_RADIUS 80.f +#define CONE_45_DEGREES 0.707f +#define CONE_15_DEGREES 0.9659258f +#define CONE_90_DEGREES 0 + +#define TRAIN_ACTIVE 0x80 +#define TRAIN_NEW 0xc0 +#define TRAIN_OFF 0x00 +#define TRAIN_NEUTRAL 0x01 +#define TRAIN_SLOW 0x02 +#define TRAIN_MEDIUM 0x03 +#define TRAIN_FAST 0x04 +#define TRAIN_BACK 0x05 + +// entity messages +#define PLAY_PLAYER_JINGLE 1 +#define UPDATE_PLAYER_RADAR 2 + +#define DEATH_ANIMATION_TIME 3.0f + +typedef struct +{ + Vector m_vecAutoAimDir; // The direction autoaim wishes to point. + Vector m_vecAutoAimPoint; // The point (world space) that autoaim is aiming at. + EHANDLE m_hAutoAimEntity; // The entity that autoaim is aiming at. + bool m_bAutoAimAssisting; // If this is true, autoaim is aiming at the target. If false, the player is naturally aiming. + bool m_bOnTargetNatural; + float m_fScale; + float m_fMaxDist; +} autoaim_params_t; + +enum stepsoundtimes_t +{ + STEPSOUNDTIME_NORMAL = 0, + STEPSOUNDTIME_ON_LADDER, + STEPSOUNDTIME_WATER_KNEE, + STEPSOUNDTIME_WATER_FOOT, +}; + +void CopySoundNameWithModifierToken( char *pchDest, const char *pchSource, int nMaxLenInChars, const char *pchToken ); + +// Shared header file for players +#if defined( CLIENT_DLL ) +#define CBasePlayer C_BasePlayer +#include "c_baseplayer.h" +#else +#include "player.h" +#endif + +#endif // BASEPLAYER_SHARED_H diff --git a/game/shared/baseprojectile.h b/game/shared/baseprojectile.h new file mode 100644 index 0000000..9f16f82 --- /dev/null +++ b/game/shared/baseprojectile.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEPROJECTILE_H +#define BASEPROJECTILE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" + +#ifdef GAME_DLL +#include "baseanimating.h" +#else +#include "c_baseanimating.h" +#endif + +#ifdef CLIENT_DLL +#define CBaseProjectile C_BaseProjectile +#endif // CLIENT_DLL + +//============================================================================= +// +// Base Projectile. +// +//============================================================================= +#ifdef CLIENT_DLL +class CBaseProjectile : public CBaseAnimating +#else // CLIENT_DLL +DECLARE_AUTO_LIST( IBaseProjectileAutoList ); +class CBaseProjectile : public CBaseAnimating, public IBaseProjectileAutoList +#endif // !CLIENT_DLL +{ +public: + DECLARE_CLASS( CBaseProjectile, CBaseAnimating ); + DECLARE_NETWORKCLASS(); + + CBaseProjectile(); + + virtual void Spawn(); + +#ifdef GAME_DLL + virtual int GetBaseProjectileType() const { return -1; } // no base + virtual int GetProjectileType() const { return -1; } // no type + virtual int GetDestroyableHitCount( void ) const { return m_iDestroyableHitCount; } + void IncrementDestroyableHitCount( void ) { ++m_iDestroyableHitCount; } + + virtual bool CanCollideWithTeammates() const { return m_bCanCollideWithTeammates; } + virtual float GetCollideWithTeammatesDelay() const { return 0.25f; } +#endif // GAME_DLL + + virtual bool IsDestroyable( void ) { return false; } + virtual void Destroy( bool bBlinkOut = true, bool bBreakRocket = false ) {} + virtual void SetLauncher( CBaseEntity *pLauncher ); + CBaseEntity *GetOriginalLauncher() const { return m_hOriginalLauncher; } + +protected: +#ifdef GAME_DLL + void CollideWithTeammatesThink(); + + int m_iDestroyableHitCount; +#endif // GAME_DLL + +private: + +#ifdef GAME_DLL + void ResetCollideWithTeammates(); + + bool m_bCanCollideWithTeammates; +#endif // GAME_DLL + + CNetworkHandle( CBaseEntity, m_hOriginalLauncher ); +}; + +#endif // BASEPROJECTILE_H diff --git a/game/shared/baseviewmodel_shared.h b/game/shared/baseviewmodel_shared.h new file mode 100644 index 0000000..15d3be5 --- /dev/null +++ b/game/shared/baseviewmodel_shared.h @@ -0,0 +1,210 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEVIEWMODEL_SHARED_H +#define BASEVIEWMODEL_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "predictable_entity.h" +#include "utlvector.h" +#include "baseplayer_shared.h" +#include "shared_classnames.h" +#include "econ/ihasowner.h" + +class CBaseCombatWeapon; +class CBaseCombatCharacter; +class CVGuiScreen; + +#if defined( CLIENT_DLL ) +#define CBaseViewModel C_BaseViewModel +#define CBaseCombatWeapon C_BaseCombatWeapon +#endif + +#define VIEWMODEL_INDEX_BITS 1 + +class CBaseViewModel : public CBaseAnimating, public IHasOwner +{ + DECLARE_CLASS( CBaseViewModel, CBaseAnimating ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +#if !defined( CLIENT_DLL ) + DECLARE_DATADESC(); +#endif + + CBaseViewModel( void ); + ~CBaseViewModel( void ); + + + bool IsViewable(void) { return false; } + + virtual void UpdateOnRemove( void ); + + // Weapon client handling + virtual void SendViewModelMatchingSequence( int sequence ); + virtual void SetWeaponModel( const char *pszModelname, CBaseCombatWeapon *weapon ); + + virtual void CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles ); + virtual void CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, + const QAngle& eyeAngles ); + virtual void AddViewModelBob( CBasePlayer *owner, Vector& eyePosition, QAngle& eyeAngles ) {}; + + // Initializes the viewmodel for use + void SetOwner( CBaseEntity *pEntity ); + void SetIndex( int nIndex ); + // Returns which viewmodel it is + int ViewModelIndex( ) const; + + virtual void Precache( void ); + + virtual void Spawn( void ); + + virtual CBaseEntity *GetOwner( void ) { return m_hOwner; }; + + virtual void AddEffects( int nEffects ); + virtual void RemoveEffects( int nEffects ); + + void SpawnControlPanels(); + void DestroyControlPanels(); + void SetControlPanelsActive( bool bState ); + void ShowControlPanells( bool show ); + + virtual CBaseCombatWeapon *GetOwningWeapon( void ); + + virtual CBaseEntity *GetOwnerViaInterface( void ) { return GetOwner(); } + + virtual bool IsSelfAnimating() + { + return true; + } + + Vector m_vecLastFacing; + + // Only support prediction in TF2 for now +#if defined( INVASION_DLL ) || defined( INVASION_CLIENT_DLL ) + // All predicted weapons need to implement and return true + virtual bool IsPredicted( void ) const + { + return true; + } +#endif + +#if !defined( CLIENT_DLL ) + virtual int UpdateTransmitState( void ); + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); +#else + + virtual RenderGroup_t GetRenderGroup(); + +// Only supported in TF2 right now +#if defined( INVASION_CLIENT_DLL ) + + virtual bool ShouldPredict( void ) + { + if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() ) + return true; + + return BaseClass::ShouldPredict(); + } + +#endif + + + virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + virtual bool Interpolate( float currentTime ); + + bool ShouldFlipViewModel(); + void UpdateAnimationParity( void ); + + virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform ); + + virtual bool ShouldDraw(); + virtual int DrawModel( int flags ); + virtual int InternalDrawModel( int flags ); + int DrawOverriddenViewmodel( int flags ); + virtual int GetFxBlend( void ); + virtual bool IsTransparent( void ); + virtual bool UsesPowerOfTwoFrameBufferTexture( void ); + + // Should this object cast shadows? + virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } + + // Should this object receive shadows? + virtual bool ShouldReceiveProjectedTextures( int flags ) + { + return false; + } + + // Add entity to visible view models list? + virtual void AddEntity( void ); + + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); + + // See C_StudioModel's definition of this. + virtual void UncorrectViewModelAttachment( Vector &vOrigin ); + + // (inherited from C_BaseAnimating) + virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ); + virtual bool IsViewModel() const; + + CBaseCombatWeapon *GetWeapon() const { return m_hWeapon.Get(); } + +#ifdef CLIENT_DLL + virtual bool ShouldResetSequenceOnNewModel( void ) { return false; } + + // Attachments + virtual int LookupAttachment( const char *pAttachmentName ); + virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachment( int number, Vector &origin ); + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); +#endif + +private: + CBaseViewModel( const CBaseViewModel & ); // not defined, not accessible + +#endif + +private: + CNetworkVar( int, m_nViewModelIndex ); // Which viewmodel is it? + CNetworkHandle( CBaseEntity, m_hOwner ); // Player or AI carrying this weapon + + // soonest time Update will call WeaponIdle + float m_flTimeWeaponIdle; + + Activity m_Activity; + + // Used to force restart on client, only needs a few bits + CNetworkVar( int, m_nAnimationParity ); + + // Weapon art + string_t m_sVMName; // View model of this weapon + string_t m_sAnimationPrefix; // Prefix of the animations that should be used by the player carrying this weapon + +#if defined( CLIENT_DLL ) + int m_nOldAnimationParity; +#endif + + + typedef CHandle< CBaseCombatWeapon > CBaseCombatWeaponHandle; + CNetworkVar( CBaseCombatWeaponHandle, m_hWeapon ); + + // Control panel + typedef CHandle ScreenHandle_t; + CUtlVector m_hScreens; +}; + +#endif // BASEVIEWMODEL_SHARED_H diff --git a/game/shared/beam_flags.h b/game/shared/beam_flags.h new file mode 100644 index 0000000..d985aa1 --- /dev/null +++ b/game/shared/beam_flags.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( BEAM_FLAGS_H ) +#define BEAM_FLAGS_H +#ifdef _WIN32 +#pragma once +#endif + +enum +{ + FBEAM_STARTENTITY = 0x00000001, + FBEAM_ENDENTITY = 0x00000002, + FBEAM_FADEIN = 0x00000004, + FBEAM_FADEOUT = 0x00000008, + FBEAM_SINENOISE = 0x00000010, + FBEAM_SOLID = 0x00000020, + FBEAM_SHADEIN = 0x00000040, + FBEAM_SHADEOUT = 0x00000080, + FBEAM_ONLYNOISEONCE = 0x00000100, // Only calculate our noise once + FBEAM_NOTILE = 0x00000200, + FBEAM_USE_HITBOXES = 0x00000400, // Attachment indices represent hitbox indices instead when this is set. + FBEAM_STARTVISIBLE = 0x00000800, // Has this client actually seen this beam's start entity yet? + FBEAM_ENDVISIBLE = 0x00001000, // Has this client actually seen this beam's end entity yet? + FBEAM_ISACTIVE = 0x00002000, + FBEAM_FOREVER = 0x00004000, + FBEAM_HALOBEAM = 0x00008000, // When drawing a beam with a halo, don't ignore the segments and endwidth + FBEAM_REVERSED = 0x00010000, + NUM_BEAM_FLAGS = 17 // KEEP THIS UPDATED! +}; + +#endif // BEAM_FLAGS_H diff --git a/game/shared/beam_shared.h b/game/shared/beam_shared.h new file mode 100644 index 0000000..b9e2b90 --- /dev/null +++ b/game/shared/beam_shared.h @@ -0,0 +1,476 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BEAM_H +#define BEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity_shared.h" +#include "baseplayer_shared.h" +#if !defined( CLIENT_DLL ) +#include "entityoutput.h" +#endif + +#include "beam_flags.h" + +#define MAX_BEAM_WIDTH 102.3f +#define MAX_BEAM_SCROLLSPEED 100.0f +#define MAX_BEAM_NOISEAMPLITUDE 64 + +#define SF_BEAM_STARTON 0x0001 +#define SF_BEAM_TOGGLE 0x0002 +#define SF_BEAM_RANDOM 0x0004 +#define SF_BEAM_RING 0x0008 +#define SF_BEAM_SPARKSTART 0x0010 +#define SF_BEAM_SPARKEND 0x0020 +#define SF_BEAM_DECALS 0x0040 +#define SF_BEAM_SHADEIN 0x0080 +#define SF_BEAM_SHADEOUT 0x0100 +#define SF_BEAM_TAPEROUT 0x0200 // Tapers to zero +#define SF_BEAM_TEMPORARY 0x8000 + +#define ATTACHMENT_INDEX_BITS 5 +#define ATTACHMENT_INDEX_MASK ((1 << ATTACHMENT_INDEX_BITS) - 1) + +#if defined( CLIENT_DLL ) +#define CBeam C_Beam +#include "c_pixel_visibility.h" +#endif + +class CBeam : public CBaseEntity +{ + DECLARE_CLASS( CBeam, CBaseEntity ); +public: + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); +#if !defined( CLIENT_DLL ) + DECLARE_DATADESC(); +#endif + + CBeam(); + + virtual void SetModel( const char *szModelName ); + + void Spawn( void ); + void Precache( void ); +#if !defined( CLIENT_DLL ) + int ObjectCaps( void ); + void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + int UpdateTransmitState( void ); + int ShouldTransmit( const CCheckTransmitInfo *pInfo ); +#endif + + virtual int DrawDebugTextOverlays(void); + + // These functions are here to show the way beams are encoded as entities. + // Encoding beams as entities simplifies their management in the client/server architecture + void SetType( int type ); + void SetBeamFlags( int flags ); + void SetBeamFlag( int flag ); + + // NOTE: Start + End Pos are specified in *relative* coordinates + void SetStartPos( const Vector &pos ); + void SetEndPos( const Vector &pos ); + + // This will change things so the abs position matches the requested spot + void SetAbsStartPos( const Vector &pos ); + void SetAbsEndPos( const Vector &pos ); + + const Vector &GetAbsStartPos( void ) const; + const Vector &GetAbsEndPos( void ) const; + + void SetStartEntity( CBaseEntity *pEntity ); + void SetEndEntity( CBaseEntity *pEntity ); + + void SetStartAttachment( int attachment ); + void SetEndAttachment( int attachment ); + + void SetTexture( int spriteIndex ); + void SetHaloTexture( int spriteIndex ); + void SetHaloScale( float haloScale ); + void SetWidth( float width ); + void SetEndWidth( float endWidth ); + void SetFadeLength( float fadeLength ); + void SetNoise( float amplitude ); + void SetColor( int r, int g, int b ); + void SetBrightness( int brightness ); + void SetFrame( float frame ); + void SetScrollRate( int speed ); + void SetFireTime( float flFireTime ); + void SetFrameRate( float flFrameRate ) { m_flFrameRate = flFrameRate; } + + void SetMinDXLevel( int nMinDXLevel ) { m_nMinDXLevel = nMinDXLevel; } + + void TurnOn( void ); + void TurnOff( void ); + + int GetType( void ) const; + int GetBeamFlags( void ) const; + CBaseEntity* GetStartEntityPtr( void ) const; + int GetStartEntity( void ) const; + CBaseEntity* GetEndEntityPtr( void ) const; + int GetEndEntity( void ) const; + int GetStartAttachment() const; + int GetEndAttachment() const; + + virtual const Vector &WorldSpaceCenter( void ) const; + + int GetTexture( void ); + float GetWidth( void ) const; + float GetEndWidth( void ) const; + float GetFadeLength( void ) const; + float GetNoise( void ) const; + int GetBrightness( void ) const; + float GetFrame( void ) const; + float GetScrollRate( void ) const; + float GetHDRColorScale( void ) const; + void SetHDRColorScale( float flScale ) { m_flHDRColorScale = flScale; } + + + // Call after you change start/end positions + void RelinkBeam( void ); + + void DoSparks( const Vector &start, const Vector &end ); + CBaseEntity *RandomTargetname( const char *szName ); + void BeamDamage( trace_t *ptr ); + // Init after BeamCreate() + void BeamInit( const char *pSpriteName, float width ); + void PointsInit( const Vector &start, const Vector &end ); + void PointEntInit( const Vector &start, CBaseEntity *pEndEntity ); + void EntsInit( CBaseEntity *pStartEntity, CBaseEntity *pEndEntity ); + void LaserInit( CBaseEntity *pStartEntity, CBaseEntity *pEndEntity ); + void HoseInit( const Vector &start, const Vector &direction ); + void SplineInit( int nNumEnts, CBaseEntity** pEntList, int *attachment ); + + // Input handlers + + static CBeam *BeamCreate( const char *pSpriteName, float width ); + static CBeam *BeamCreatePredictable( const char *module, int line, bool persist, const char *pSpriteName, float width, CBasePlayer *pOwner ); + + void LiveForTime( float time ); + void BeamDamageInstant( trace_t *ptr, float damage ); + +// Only supported in TF2 right now +#if defined( INVASION_CLIENT_DLL ) + virtual bool ShouldPredict( void ) + { + return true; + } +#endif + + virtual const char *GetDecalName( void ) { return "BigShot"; } + +#if defined( CLIENT_DLL ) +// IClientEntity overrides. +public: + virtual int DrawModel( int flags ); + virtual bool IsTransparent( void ); + virtual bool ShouldDraw(); + virtual bool IgnoresZBuffer( void ) const { return true; } + virtual void OnDataChanged( DataUpdateType_t updateType ); + + virtual bool OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted ); + + // Add beam to visible entities list? + virtual void AddEntity( void ); + virtual bool ShouldReceiveProjectedTextures( int flags ) + { + return false; + } + +// Beam Data Elements +private: + // Computes the bounding box of a beam local to the origin of the beam + void ComputeBounds( Vector& mins, Vector& maxs ); + + friend void RecvProxy_Beam_ScrollSpeed( const CRecvProxyData *pData, void *pStruct, void *pOut ); + friend class CViewRenderBeams; + +#endif + +protected: + CNetworkVar( float, m_flFrameRate ); + CNetworkVar( float, m_flHDRColorScale ); + float m_flFireTime; + float m_flDamage; // Damage per second to touchers. + CNetworkVar( int, m_nNumBeamEnts ); +#if defined( CLIENT_DLL ) + pixelvis_handle_t m_queryHandleHalo; +#endif + +private: +#if !defined( CLIENT_DLL ) + void InputNoise( inputdata_t &inputdata ); + void InputWidth( inputdata_t &inputdata ); + void InputColorRedValue( inputdata_t &inputdata ); + void InputColorBlueValue( inputdata_t &inputdata ); + void InputColorGreenValue( inputdata_t &inputdata ); +#endif + + // Beam Data Elements + CNetworkVar( int, m_nHaloIndex ); + CNetworkVar( int, m_nBeamType ); + CNetworkVar( int, m_nBeamFlags ); + CNetworkArray( EHANDLE, m_hAttachEntity, MAX_BEAM_ENTS ); + CNetworkArray( int, m_nAttachIndex, MAX_BEAM_ENTS ); + CNetworkVar( float, m_fWidth ); + CNetworkVar( float, m_fEndWidth ); + CNetworkVar( float, m_fFadeLength ); + CNetworkVar( float, m_fHaloScale ); + CNetworkVar( float, m_fAmplitude ); + CNetworkVar( float, m_fStartFrame ); + CNetworkVar( float, m_fSpeed ); + CNetworkVar( int, m_nMinDXLevel ); + CNetworkVar( float, m_flFrame ); + + CNetworkVector( m_vecEndPos ); + + EHANDLE m_hEndEntity; + +#if !defined( CLIENT_DLL ) + int m_nDissolveType; +#endif + +public: +#ifdef PORTAL + CNetworkVar( bool, m_bDrawInMainRender ); + CNetworkVar( bool, m_bDrawInPortalRender ); +#endif //#ifdef PORTAL +}; + +#if !defined( CLIENT_DLL ) +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline int CBeam::ObjectCaps( void ) +{ + int flags = 0; + if ( HasSpawnFlags( SF_BEAM_TEMPORARY ) ) + flags = FCAP_DONT_SAVE; + return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; +} +#endif + +inline void CBeam::SetFireTime( float flFireTime ) +{ + m_flFireTime = flFireTime; +} + +//----------------------------------------------------------------------------- +// NOTE: Start + End Pos are specified in *relative* coordinates +//----------------------------------------------------------------------------- +inline void CBeam::SetStartPos( const Vector &pos ) +{ +#if defined( CLIENT_DLL ) + SetNetworkOrigin( pos ); +#endif + SetLocalOrigin( pos ); +} + +inline void CBeam::SetEndPos( const Vector &pos ) +{ + m_vecEndPos = pos; +} + + // center point of beam +inline const Vector &CBeam::WorldSpaceCenter( void ) const +{ + Vector &vecResult = AllocTempVector(); + VectorAdd( GetAbsStartPos(), GetAbsEndPos(), vecResult ); + vecResult *= 0.5f; + return vecResult; +} + +inline void CBeam::SetStartAttachment( int attachment ) +{ + Assert( (attachment & ~ATTACHMENT_INDEX_MASK) == 0 ); + m_nAttachIndex.Set( 0, attachment ); +} + +inline void CBeam::SetEndAttachment( int attachment ) +{ + Assert( (attachment & ~ATTACHMENT_INDEX_MASK) == 0 ); + m_nAttachIndex.Set( m_nNumBeamEnts-1, attachment ); +} + +inline void CBeam::SetTexture( int spriteIndex ) +{ + SetModelIndex( spriteIndex ); +} + +inline void CBeam::SetHaloTexture( int spriteIndex ) +{ + m_nHaloIndex = spriteIndex; +} + +inline void CBeam::SetHaloScale( float haloScale ) +{ + m_fHaloScale = haloScale; +} + +inline void CBeam::SetWidth( float width ) +{ + Assert( width <= MAX_BEAM_WIDTH ); + m_fWidth = MIN( MAX_BEAM_WIDTH, width ); +} + +inline void CBeam::SetEndWidth( float endWidth ) +{ + Assert( endWidth <= MAX_BEAM_WIDTH ); + m_fEndWidth = MIN( MAX_BEAM_WIDTH, endWidth ); +} + +inline void CBeam::SetFadeLength( float fadeLength ) +{ + m_fFadeLength = fadeLength; +} + +inline void CBeam::SetNoise( float amplitude ) +{ + m_fAmplitude = amplitude; +} + +inline void CBeam::SetColor( int r, int g, int b ) +{ + SetRenderColor( r, g, b, GetRenderColor().a ); +} + +inline void CBeam::SetBrightness( int brightness ) +{ + SetRenderColorA( brightness ); +} + +inline void CBeam::SetFrame( float frame ) +{ + m_fStartFrame = frame; +} + +inline void CBeam::SetScrollRate( int speed ) +{ + m_fSpeed = speed; +} + +inline CBaseEntity* CBeam::GetStartEntityPtr( void ) const +{ + return m_hAttachEntity[0].Get(); +} + +inline int CBeam::GetStartEntity( void ) const +{ + CBaseEntity *pEntity = m_hAttachEntity[0].Get(); + return pEntity ? pEntity->entindex() : 0; +} + +inline CBaseEntity* CBeam::GetEndEntityPtr( void ) const +{ + return m_hAttachEntity[1].Get(); +} + +inline int CBeam::GetEndEntity( void ) const +{ + CBaseEntity *pEntity = m_hAttachEntity[m_nNumBeamEnts-1].Get(); + return pEntity ? pEntity->entindex() : 0; +} + +inline int CBeam::GetStartAttachment() const +{ + return m_nAttachIndex[0] & ATTACHMENT_INDEX_MASK; +} + +inline int CBeam::GetEndAttachment() const +{ + return m_nAttachIndex[m_nNumBeamEnts-1] & ATTACHMENT_INDEX_MASK; +} + +inline int CBeam::GetTexture( void ) +{ + return GetModelIndex(); +} + +inline float CBeam::GetWidth( void ) const +{ + return m_fWidth; +} + +inline float CBeam::GetEndWidth( void ) const +{ + return m_fEndWidth; +} + +inline float CBeam::GetFadeLength( void ) const +{ + return m_fFadeLength; +} + +inline float CBeam::GetNoise( void ) const +{ + return m_fAmplitude; +} + +inline int CBeam::GetBrightness( void ) const +{ + return GetRenderColor().a; +} + +inline float CBeam::GetFrame( void ) const +{ + return m_fStartFrame; +} + +inline float CBeam::GetScrollRate( void ) const +{ + return m_fSpeed; +} + +inline float CBeam::GetHDRColorScale( void ) const +{ + return m_flHDRColorScale; +} + +inline void CBeam::LiveForTime( float time ) +{ + SetThink(&CBeam::SUB_Remove); + SetNextThink( gpGlobals->curtime + time ); +} + +inline void CBeam::BeamDamageInstant( trace_t *ptr, float damage ) +{ + m_flDamage = damage; + m_flFireTime = gpGlobals->curtime - 1; + BeamDamage(ptr); +} + +bool IsStaticPointEntity( CBaseEntity *pEnt ); + +// Macro to wrap creation +#define BEAM_CREATE_PREDICTABLE( name, width, player ) \ + CBeam::BeamCreatePredictable( __FILE__, __LINE__, false, name, width, player ) + +#define BEAM_CREATE_PREDICTABLE_PERSIST( name, width, player ) \ + CBeam::BeamCreatePredictable( __FILE__, __LINE__, true, name, width, player ) + +// Start/End Entity is encoded as 12 bits of entity index, and 4 bits of attachment (4:12) +#define BEAMENT_ENTITY(x) ((x)&0xFFF) +#define BEAMENT_ATTACHMENT(x) (((x)>>12)&0xF) + + +// Beam types, encoded as a byte +enum +{ + BEAM_POINTS = 0, + BEAM_ENTPOINT, + BEAM_ENTS, + BEAM_HOSE, + BEAM_SPLINE, + BEAM_LASER, + NUM_BEAM_TYPES +}; + + +#endif // BEAM_H diff --git a/game/shared/cam_thirdperson.h b/game/shared/cam_thirdperson.h new file mode 100644 index 0000000..54dfeca --- /dev/null +++ b/game/shared/cam_thirdperson.h @@ -0,0 +1,108 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CAM_THIRDPERSON_H +#define CAM_THIRDPERSON_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifdef CLIENT_DLL + #include "c_baseplayer.h" +#else + #include "baseplayer.h" +#endif + +#define DIST_FORWARD 0 +#define DIST_RIGHT 1 +#define DIST_UP 2 + +//-------------------------------------------------- Constants + +#define CAM_MIN_DIST 30.0 +#define CAM_ANGLE_MOVE .5 +#define MAX_ANGLE_DIFF 10.0 +#define PITCH_MAX 90.0 +#define PITCH_MIN 0 +#define YAW_MAX 135.0 +#define YAW_MIN -135.0 +#define DIST 2 +#define CAM_HULL_OFFSET 14.0 // the size of the bounding hull used for collision checking + +#define CAMERA_UP_OFFSET 25.0f +#define CAMERA_OFFSET_LERP_TIME 0.5f +#define CAMERA_UP_OFFSET_LERP_TIME 0.25f + +class CThirdPersonManager +{ +public: + + CThirdPersonManager(); + void SetCameraOffsetAngles( const Vector& vecOffset ) { m_vecCameraOffset = vecOffset; } + const Vector& GetCameraOffsetAngles( void ) const { return m_vecCameraOffset; } + + void SetDesiredCameraOffset( const Vector& vecOffset ) { m_vecDesiredCameraOffset = vecOffset; } + const Vector& GetDesiredCameraOffset( void ) const { return m_vecDesiredCameraOffset; } + + Vector GetFinalCameraOffset( void ); + + void SetCameraOrigin( const Vector& vecOffset ) { m_vecCameraOrigin = vecOffset; } + const Vector& GetCameraOrigin( void ) const { return m_vecCameraOrigin; } + + void Update( void ); + + void PositionCamera( CBasePlayer *pPlayer, const QAngle& angles ); + + void UseCameraOffsets( bool bUse ) { m_bUseCameraOffsets = bUse; } + bool UsingCameraOffsets( void ) { return m_bUseCameraOffsets; } + + const QAngle& GetCameraViewAngles( void ) const { return m_ViewAngles; } + + Vector GetDistanceFraction( void ); + + bool WantToUseGameThirdPerson( void ); + + void SetOverridingThirdPerson( bool bOverride ) { m_bOverrideThirdPerson = bOverride; } + bool IsOverridingThirdPerson( void ) { return m_bOverrideThirdPerson; } + + void Init( void ); + + void SetForcedThirdPerson( bool bForced ) { m_bForced = bForced; } + bool GetForcedThirdPerson() const { return m_bForced; } + +private: + + // What is the current camera offset from the view origin? + Vector m_vecCameraOffset; + // Distances from the center + Vector m_vecDesiredCameraOffset; + + Vector m_vecCameraOrigin; + + bool m_bUseCameraOffsets; + + QAngle m_ViewAngles; + + float m_flFraction; + float m_flUpFraction; + + float m_flTargetFraction; + float m_flTargetUpFraction; + + bool m_bOverrideThirdPerson; + + bool m_bForced; + + float m_flUpOffset; + + float m_flLerpTime; + float m_flUpLerpTime; +}; + +extern CThirdPersonManager g_ThirdPersonManager; + +#endif // CAM_THIRDPERSON_H diff --git a/game/shared/choreoactor.h b/game/shared/choreoactor.h new file mode 100644 index 0000000..8749997 --- /dev/null +++ b/game/shared/choreoactor.h @@ -0,0 +1,89 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef CHOREOACTOR_H +#define CHOREOACTOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" + +class CChoreoChannel; +class CChoreoScene; +class CUtlBuffer; +class IChoreoStringPool; + +//----------------------------------------------------------------------------- +// Purpose: The actor is the atomic element of a scene +// A scene can have one or more actors, who have multiple events on one or +// more channels +//----------------------------------------------------------------------------- +class CChoreoActor +{ +public: + + // Construction + CChoreoActor( void ); + CChoreoActor( const char *name ); + // Assignment + CChoreoActor& operator = ( const CChoreoActor& src ); + + // Serialization + void SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool ); + bool RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool ); + + // Accessors + void SetName( const char *name ); + const char *GetName( void ); + + // Iteration + int GetNumChannels( void ); + CChoreoChannel *GetChannel( int channel ); + + CChoreoChannel *FindChannel( const char *name ); + + // Manipulate children + void AddChannel( CChoreoChannel *channel ); + void RemoveChannel( CChoreoChannel *channel ); + int FindChannelIndex( CChoreoChannel *channel ); + void SwapChannels( int c1, int c2 ); + void RemoveAllChannels(); + + void SetFacePoserModelName( const char *name ); + char const *GetFacePoserModelName( void ) const; + + void SetActive( bool active ); + bool GetActive( void ) const; + + bool IsMarkedForSave() const { return m_bMarkedForSave; } + void SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; } + + void MarkForSaveAll( bool mark ); + +private: + // Clear structure out + void Init( void ); + + enum + { + MAX_ACTOR_NAME = 128, + MAX_FACEPOSER_MODEL_NAME = 128 + }; + + char m_szName[ MAX_ACTOR_NAME ]; + char m_szFacePoserModelName[ MAX_FACEPOSER_MODEL_NAME ]; + + // Children + CUtlVector < CChoreoChannel * > m_Channels; + + bool m_bActive; + + // Purely for save/load + bool m_bMarkedForSave; +}; + +#endif // CHOREOACTOR_H diff --git a/game/shared/choreochannel.h b/game/shared/choreochannel.h new file mode 100644 index 0000000..95a828c --- /dev/null +++ b/game/shared/choreochannel.h @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CHOREOCHANNEL_H +#define CHOREOCHANNEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include "tier1/utlrbtree.h" + +class CChoreoEvent; +class CChoreoActor; +class CChoreoScene; +class CUtlBuffer; +class IChoreoStringPool; + +//----------------------------------------------------------------------------- +// Purpose: A channel is owned by an actor and contains zero or more events +//----------------------------------------------------------------------------- +class CChoreoChannel +{ +public: + // Construction + CChoreoChannel( void ); + CChoreoChannel( const char *name ); + + // Assignment + CChoreoChannel& operator=(const CChoreoChannel& src ); + + // Serialization + void SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool ); + bool RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, CChoreoActor *pActor, IChoreoStringPool *pStringPool ); + + // Accessors + void SetName( const char *name ); + const char *GetName( void ); + + // Iterate children + int GetNumEvents( void ); + CChoreoEvent *GetEvent( int event ); + + // Manipulate children + void AddEvent( CChoreoEvent *event ); + void RemoveEvent( CChoreoEvent *event ); + int FindEventIndex( CChoreoEvent *event ); + void RemoveAllEvents(); + + CChoreoActor *GetActor( void ); + void SetActor( CChoreoActor *actor ); + + void SetActive( bool active ); + bool GetActive( void ) const; + + // Compute true start/end times for gesture events in this channel, factoring in "null" gestures as needed + void ReconcileGestureTimes(); + // Compute master/slave, count, endtime info for close captioning data + void ReconcileCloseCaption(); + + bool IsMarkedForSave() const { return m_bMarkedForSave; } + void SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; } + + void MarkForSaveAll( bool mark ); + + bool GetSortedCombinedEventList( char const *cctoken, CUtlRBTree< CChoreoEvent * >& sorted ); + +private: + // Initialize fields + void Init( void ); + + enum + { + MAX_CHANNEL_NAME = 128, + }; + + CChoreoActor *m_pActor; + + // Channels are just named + char m_szName[ MAX_CHANNEL_NAME ]; + + // All of the events for this channel + CUtlVector < CChoreoEvent * > m_Events; + + bool m_bActive; + + // Purely for save/load + bool m_bMarkedForSave; +}; + +#endif // CHOREOCHANNEL_H diff --git a/game/shared/choreoevent.h b/game/shared/choreoevent.h new file mode 100644 index 0000000..ad4828d --- /dev/null +++ b/game/shared/choreoevent.h @@ -0,0 +1,708 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CHOREOEVENT_H +#define CHOREOEVENT_H +#ifdef _WIN32 +#pragma once +#endif + +class CChoreoActor; +class CChoreoChannel; +class CChoreoEvent; +class CChoreoScene; +class IChoreoEventCallback; +class CAudioMixer; +class CUtlBuffer; +class IChoreoStringPool; + + +#include "tier1/utlstring.h" +#include "tier1/utlvector.h" +#include "expressionsample.h" +#include "networkvar.h" +#include "localflexcontroller.h" + +typedef CUtlString ChoreoStr_t; + +//----------------------------------------------------------------------------- +// Purpose: SPEAK events can have "relative tags" that other objects can reference +// to specify their start times off of +//----------------------------------------------------------------------------- +class CEventRelativeTag +{ +public: + DECLARE_CLASS_NOBASE( CEventRelativeTag ); + + enum + { + MAX_EVENTTAG_LENGTH = 128, + }; + + CEventRelativeTag( CChoreoEvent *owner, const char *name, float percentage ); + CEventRelativeTag( const CEventRelativeTag& src ); + + const char *GetName( void ); + float GetPercentage( void ); + void SetPercentage( float percentage ); + + // Returns the corrected time based on the owner's length and start time + float GetStartTime( void ); + CChoreoEvent *GetOwner( void ); + void SetOwner( CChoreoEvent *event ); + +protected: + + ChoreoStr_t m_Name; + float m_flPercentage; + CChoreoEvent *m_pOwner; +}; + +//----------------------------------------------------------------------------- +// Purpose: GESTURE events can have "absolute tags" (where the value is not a +// percentage, but an actual timestamp from the start of the event) +//----------------------------------------------------------------------------- +class CEventAbsoluteTag +{ +public: + enum + { + MAX_EVENTTAG_LENGTH = 128, + }; + + CEventAbsoluteTag( CChoreoEvent *owner, const char *name, float percentage ); + CEventAbsoluteTag( const CEventAbsoluteTag& src ); + + const char *GetName( void ); + + float GetPercentage( void ); + void SetPercentage( float percentage ); + + float GetEventTime( void ); + void SetEventTime( float t ); + + float GetAbsoluteTime( void ); + void SetAbsoluteTime( float t ); + + CChoreoEvent *GetOwner( void ); + void SetOwner( CChoreoEvent *event ); + + void SetLocked( bool bLocked ); + bool GetLocked( void ); + + void SetLinear( bool bLinear ); + bool GetLinear( void ); + + void SetEntry( bool bEntry ); + bool GetEntry( void ); + + void SetExit( bool bExit ); + bool GetExit( void ); + +protected: + + ChoreoStr_t m_Name; + float m_flPercentage; + bool m_bLocked:1; + bool m_bLinear:1; + bool m_bEntry:1; + bool m_bExit:1; + CChoreoEvent *m_pOwner; +}; + +//----------------------------------------------------------------------------- +// Purpose: FLEXANIMATION events can have "timing tags" that are used to align and +// manipulate flex animation curves +//----------------------------------------------------------------------------- +class CFlexTimingTag : public CEventRelativeTag +{ + DECLARE_CLASS( CFlexTimingTag, CEventRelativeTag ); + +public: + CFlexTimingTag( CChoreoEvent *owner, const char *name, float percentage, bool locked ); + CFlexTimingTag( const CFlexTimingTag& src ); + + bool GetLocked( void ); + void SetLocked( bool locked ); + +protected: + bool m_bLocked; +}; + +//----------------------------------------------------------------------------- +// Purpose: A flex controller position can be animated over a period of time +//----------------------------------------------------------------------------- +class CFlexAnimationTrack +{ +public: + enum + { + MAX_CONTROLLER_NAME = 128, + }; + + CFlexAnimationTrack( CChoreoEvent *event ); + CFlexAnimationTrack( const CFlexAnimationTrack* src ); + virtual ~CFlexAnimationTrack( void ); + + void SetEvent( CChoreoEvent *event ); + CChoreoEvent *GetEvent( void ); + + void SetFlexControllerName( const char *name ); + char const *GetFlexControllerName( void ); + + void SetComboType( bool combo ); + bool IsComboType( void ); + + void SetMin( float value ); + void SetMax( float value ); + float GetMin( int type = 0 ); + float GetMax( int type = 0 ); + + bool IsInverted( void ); + void SetInverted( bool isInverted ); + + int GetNumSamples( int type = 0 ); + CExpressionSample *GetSample( int index, int type = 0 ); + + bool IsTrackActive( void ); + void SetTrackActive( bool active ); + + // returns scaled value for absolute time per left/right side + float GetIntensity( float time, int side = 0 ); + + CExpressionSample *AddSample( float time, float value, int type = 0 ); + void RemoveSample( int index, int type = 0 ); + void Clear( void ); + + void Resort( int type = 0 ); + + // Puts in dummy start/end samples to spline to zero ( or 0.5 for + // left/right data) at the origins + CExpressionSample *GetBoundedSample( int number, bool& bClamped, int type = 0 ); + + int GetFlexControllerIndex( int side = 0 ); + LocalFlexController_t GetRawFlexControllerIndex( int side = 0 ); + void SetFlexControllerIndex( LocalFlexController_t raw, int index, int side = 0 ); + + // returns 0..1 value for 0..1 time fraction per mag/balance + float GetFracIntensity( float time, int type ); + + // retrieves raw intensity values (for mag vs. left/right slider setting) + float GetSampleIntensity( float time ); + float GetBalanceIntensity( float time ); + + void SetEdgeInfo( bool leftEdge, int curveType, float zero ); + void GetEdgeInfo( bool leftEdge, int& curveType, float& zero ) const; + void SetEdgeActive( bool leftEdge, bool state ); + bool IsEdgeActive( bool leftEdge ) const; + int GetEdgeCurveType( bool leftEdge ) const; + float GetEdgeZeroValue( bool leftEdge ) const; + + float GetDefaultEdgeZeroPos() const; + + void SetServerSide( bool state ); + bool IsServerSide() const; +private: + // remove any samples after endtime + void RemoveOutOfRangeSamples( int type ); + + // returns scaled value for absolute time per mag/balance + float GetIntensityInternal( float time, int type ); + +public: + // returns the fractional (0..1) value for "zero" based on Min/Max ranges + float GetZeroValue( int type, bool leftSide ); + + +private: + char *m_pControllerName; + + // base track has range, combo is always 0..1 + float m_flMin; + float m_flMax; + + // 0 == magnitude + // 1 == left/right + CUtlVector< CExpressionSample > m_Samples[ 2 ]; + int m_nFlexControllerIndex[ 2 ]; + LocalFlexController_t m_nFlexControllerIndexRaw[ 2 ]; + + // For left and right edge of type 0 flex data ( magnitude track ) + EdgeInfo_t m_EdgeInfo[ 2 ]; + + CChoreoEvent *m_pEvent; + + // Is track active + bool m_bActive:1; + + // Is this a combo (magnitude + stereo) track + bool m_bCombo:1; + bool m_bServerSide:1; + + bool m_bInverted; // track is displayed 1..0 instead of 0..1 +}; + + +//----------------------------------------------------------------------------- +// Purpose: The generic scene event type +//----------------------------------------------------------------------------- +class CChoreoEvent : public ICurveDataAccessor +{ +public: + // Type of event this object represents + typedef enum + { + // Don't know yet + UNSPECIFIED = 0, + + // Section start/end + SECTION, + + // Play an expression + EXPRESSION, + + // Look at another actor + LOOKAT, + + // Move to a location + MOVETO, + + // Speak/visemes a wave file + SPEAK, + + // Play a gesture + GESTURE, + + // Play a sequence + SEQUENCE, + + // Face another actor + FACE, + + // Fire a trigger + FIRETRIGGER, + + // One or more flex sliders animated over the course of the event time period + FLEXANIMATION, + + // A contained .vcd file + SUBSCENE, + + // Loop back to previous time (forever or up to N times) + LOOP, + + // A time span during which the scene may be temporarily interrupted + INTERRUPT, + + // A dummy event that is used to mark the .vcd end time + STOPPOINT, + + // A time span during which this actor can respond to events happening in the world, etc. + PERMIT_RESPONSES, + + // A string passed to the game code for interpretation + GENERIC, + + // THIS MUST BE LAST!!! + NUM_TYPES, + } EVENTTYPE; + + enum + { + MAX_TAGNAME_STRING = 128, + MAX_CCTOKEN_STRING = 64, + }; + + typedef enum + { + DEFAULT = 0, + SIMULATION, + DISPLAY, + } TIMETYPE; + + typedef enum + { + CC_MASTER = 0, // default, implied + CC_SLAVE, + CC_DISABLED, + + NUM_CC_TYPES, + } CLOSECAPTION; + + static int s_nGlobalID; + + // Construction + CChoreoEvent( CChoreoScene *scene ); + CChoreoEvent( CChoreoScene *scene, EVENTTYPE type, const char *name ); + CChoreoEvent( CChoreoScene *scene, EVENTTYPE type, const char *name, const char *param ); + + // Assignment + CChoreoEvent& operator=(const CChoreoEvent& src ); + + ~CChoreoEvent( void ); + + // ICurveDataAccessor methods + virtual bool CurveHasEndTime(); + virtual int GetDefaultCurveType(); + + // Binary serialization + void SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool ); + bool RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool ); + + // Accessors + EVENTTYPE GetType( void ); + void SetType( EVENTTYPE type ); + + void SetName( const char *name ); + const char *GetName( void ); + + void SetParameters( const char *target ); + const char *GetParameters( void ); + void SetParameters2( const char *target ); + const char *GetParameters2( void ); + void SetParameters3( const char *target ); + const char *GetParameters3( void ); + + void SetStartTime( float starttime ); + float GetStartTime( void ); + + void SetEndTime( float endtime ); + float GetEndTime( void ); + + float GetDuration( void ); + + void SetResumeCondition( bool resumecondition ); + bool IsResumeCondition( void ); + + void SetLockBodyFacing( bool lockbodyfacing ); + bool IsLockBodyFacing( void ); + + void SetDistanceToTarget( float distancetotarget ); + float GetDistanceToTarget( void ); + + void SetForceShortMovement( bool bForceShortMovement ); + bool GetForceShortMovement( void ); + + void SetSyncToFollowingGesture( bool bSyncToFollowingGesture ); + bool GetSyncToFollowingGesture( void ); + + void SetPlayOverScript( bool bPlayOverScript ); + bool GetPlayOverScript( void ); + + int GetRampCount( void ) { return m_Ramp.GetCount(); }; + CExpressionSample *GetRamp( int index ) { return m_Ramp.Get( index ); }; + CExpressionSample *AddRamp( float time, float value, bool selected ) { return m_Ramp.Add( time, value, selected ); }; + void DeleteRamp( int index ) { m_Ramp.Delete( index ); }; + void ClearRamp( void ) { m_Ramp.Clear(); }; + void ResortRamp( void ) { m_Ramp.Resort( this ); }; + CCurveData *GetRamp( void ) { return &m_Ramp; }; + + float GetRampIntensity( float time ) { return m_Ramp.GetIntensity( this, time ); }; + + // Calculates weighting for a given time + float GetIntensity( float scenetime ); + float GetIntensityArea( float scenetime ); + + // Calculates 0..1 completion for a given time + float GetCompletion( float time ); + + // An end time of -1.0f means that the events is just triggered at the leading edge + bool HasEndTime( void ); + + // Is the event something that can be sized ( a wave file, e.g. ) + bool IsFixedLength( void ); + void SetFixedLength( bool isfixedlength ); + + // Move the start/end/both times by the specified dt (fixes up -1.0f endtimes) + void OffsetStartTime( float dt ); + void OffsetEndTime( float dt ); + void OffsetTime( float dt ); + + // Snap to scene framerate + void SnapTimes( void ); + float SnapTime( float t ); + + CChoreoScene *GetScene( void ); + void SetScene( CChoreoScene *scene ); + + // The actor the event is associated with + void SetActor( CChoreoActor *actor ); + CChoreoActor *GetActor( void ); + + // The channel the event is associated with + void SetChannel( CChoreoChannel *channel ); + CChoreoChannel *GetChannel( void ); + + // Get a more involved description of the event + const char *GetDescription( void ); + + void ClearAllRelativeTags( void ); + int GetNumRelativeTags( void ); + CEventRelativeTag *GetRelativeTag( int tagnum ); + CEventRelativeTag *FindRelativeTag( const char *tagname ); + void AddRelativeTag( const char *tagname, float percentage ); + void RemoveRelativeTag( const char *tagname ); + + bool IsUsingRelativeTag( void ); + void SetUsingRelativeTag( bool usetag, const char *tagname = 0, const char *wavname = 0); + const char *GetRelativeTagName( void ); + const char *GetRelativeWavName( void ); + + // Absolute tags + typedef enum + { + PLAYBACK = 0, // new timeline - FIXME: should be stored as an absolute time + ORIGINAL, // original timeline - FIXME: should be stored at a fixed percentage of event + + NUM_ABS_TAG_TYPES, + } AbsTagType; + + void SetGestureSequenceDuration( float duration ); + bool GetGestureSequenceDuration( float& duration ); + + void ClearAllAbsoluteTags( AbsTagType type ); + int GetNumAbsoluteTags( AbsTagType type ); + CEventAbsoluteTag *GetAbsoluteTag( AbsTagType type, int tagnum ); + CEventAbsoluteTag *FindAbsoluteTag( AbsTagType type, const char *tagname ); + void AddAbsoluteTag( AbsTagType type, const char *tagname, float t ); + void RemoveAbsoluteTag( AbsTagType type, const char *tagname ); + bool VerifyTagOrder( void ); + float GetOriginalPercentageFromPlaybackPercentage( float t ); + float GetPlaybackPercentageFromOriginalPercentage( float t ); + + static const char *NameForAbsoluteTagType( AbsTagType t ); + static AbsTagType TypeForAbsoluteTagName( const char *name ); + + void RescaleGestureTimes( float newstart, float newend, bool bMaintainAbsoluteTagPositions ); + bool PreventTagOverlap( void ); + + CEventAbsoluteTag *FindEntryTag( AbsTagType type ); + CEventAbsoluteTag *FindExitTag( AbsTagType type ); + + // Flex animation type + int GetNumFlexAnimationTracks( void ); + CFlexAnimationTrack *GetFlexAnimationTrack( int index ); + CFlexAnimationTrack *AddTrack( const char *controllername ); + CFlexAnimationTrack *FindTrack( const char *controllername ); + void RemoveTrack( int index ); + void RemoveAllTracks( void ); + void OnEndTimeChanged( void ); + + bool GetTrackLookupSet( void ); + void SetTrackLookupSet( bool set ); + + // Flex Timing Tags (used by editor only) + void ClearAllTimingTags( void ); + int GetNumTimingTags( void ); + CFlexTimingTag *GetTimingTag( int tagnum ); + CFlexTimingTag *FindTimingTag( const char *tagname ); + void AddTimingTag( const char *tagname, float percentage, bool locked ); + void RemoveTimingTag( const char *tagname ); + + // Subscene ( embedded .vcd ) support + void SetSubScene( CChoreoScene *scene ); + CChoreoScene *GetSubScene( void ); + + bool IsProcessing( void ) const; + void StartProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t ); + void ContinueProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t ); + void StopProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t ); + bool CheckProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t ); + void ResetProcessing( void ); + + void SetMixer( CAudioMixer *mixer ); + CAudioMixer *GetMixer( void ) const; + + // Hack for LOOKAT in editor + int GetPitch( void ) const; + void SetPitch( int pitch ); + int GetYaw( void ) const; + void SetYaw( int yaw ); + + // For LOOP events + void SetLoopCount( int numloops ); + int GetLoopCount( void ); + int GetNumLoopsRemaining( void ); + void SetNumLoopsRemaining( int loops ); + + bool IsMarkedForSave() const { return m_bMarkedForSave; } + void SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; } + + void GetMovementStyle( char *style, int maxlen ); + void GetDistanceStyle( char *style, int maxlen ); + + int GetGlobalID() const { return m_nGlobalID; } + + // Localization/CC support (close captioning and multiple wave file recombination) + void SetCloseCaptionType( CLOSECAPTION type ); + CLOSECAPTION GetCloseCaptionType() const; + void SetCloseCaptionToken( char const *token ); + char const *GetCloseCaptionToken() const; + void SetUsingCombinedFile( bool isusing ); + bool IsUsingCombinedFile() const; + void SetRequiredCombinedChecksum( unsigned int checksum ); + unsigned int GetRequiredCombinedChecksum(); + void SetNumSlaves( int num ); + int GetNumSlaves() const; + void SetLastSlaveEndTime( float t ); + float GetLastSlaveEndTime() const; + void SetCloseCaptionTokenValid( bool valid ); + bool GetCloseCaptionTokenValid() const; + + bool ComputeCombinedBaseFileName( char *dest, int destlen, bool creategenderwildcard ); + bool IsCombinedUsingGenderToken() const; + void SetCombinedUsingGenderToken( bool using_gender ); + + bool IsSuppressingCaptionAttenuation() const; + void SetSuppressingCaptionAttenuation( bool suppress ); + + int ValidateCombinedFile(); + + // This returns false if the wave is CC_DISABLED or is a CC_SLAVE, + // otherwise it returns the actual m_szCCToken value, or if that's + // blank it'll return the sounds.txt entry name (m_szParameters) + bool GetPlaybackCloseCaptionToken( char *dest, int destlen ); + + void ClearEventDependencies(); + void AddEventDependency( CChoreoEvent *other ); + void GetEventDependencies( CUtlVector< CChoreoEvent * >& list ); + + void SetActive( bool state ); + bool GetActive() const; + + void SetDefaultCurveType( int nCurveType ); + + // Turn enum into string and vice versa + static EVENTTYPE TypeForName( const char *name ); + static const char *NameForType( EVENTTYPE type ); + + // Turn enum into string and vice versa + static CLOSECAPTION CCTypeForName( const char *name ); + static const char *NameForCCType( CLOSECAPTION type ); + +private: + + // Declare copy constructor private to prevent accidental usage... + CChoreoEvent(const CChoreoEvent& src ); + + void SaveFlexAnimationsToBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool ); + bool RestoreFlexAnimationsFromBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool ); + + float GetBoundedAbsoluteTagPercentage( AbsTagType type, int tagnum ); + + float _GetIntensity( float time ); + + // String bounds + enum + { + MAX_CHOREOEVENT_NAME = 128, + MAX_PARAMETERS_STRING = 128, + }; + + // Base initialization + void Init( CChoreoScene *scene ); + + // Type of event + byte m_fType; + + // Close caption type + byte m_ccType; + + // Name of event + ChoreoStr_t m_Name; + + // Event parameters + ChoreoStr_t m_Parameters; + ChoreoStr_t m_Parameters2; + ChoreoStr_t m_Parameters3; + + // Event start time + float m_flStartTime; + + // Event end time ( -1.0f means no ending, just leading edge triggered ) + float m_flEndTime; + + // Duration of underlying gesture sequence + float m_flGestureSequenceDuration; + + // For CChoreoEvent::LOOP + int m_nNumLoops; // -1 == no limit + int m_nLoopsRemaining; + + // Overall intensity curve + CCurveData m_Ramp; + + // Start time is computed based on length of item referenced by tagged name + ChoreoStr_t m_TagName; + ChoreoStr_t m_TagWavName; + + // Associated actor + CChoreoActor *m_pActor; + // Associated channel + CChoreoChannel *m_pChannel; + + CUtlVector < CEventRelativeTag > m_RelativeTags; + CUtlVector < CFlexTimingTag > m_TimingTags; + CUtlVector < CEventAbsoluteTag > m_AbsoluteTags[ NUM_ABS_TAG_TYPES ]; + + CUtlVector < CFlexAnimationTrack * > m_FlexAnimationTracks; + + CChoreoScene *m_pSubScene; + CAudioMixer *m_pMixer; + + // Scene which owns this event + CChoreoScene *m_pScene; + + int m_nPitch; + int m_nYaw; + + float m_flDistanceToTarget; + + int m_nGlobalID; + + ChoreoStr_t m_CCToken; + unsigned int m_uRequiredCombinedChecksum; + // on master only, the combined file must have the same checksum to be useable + int m_nNumSlaves; + // Only set on master, helps UI draw underbar + float m_flLastSlaveEndTime; + // true if the cc token was found in the cc manager's database + + CUtlVector< CChoreoEvent * > m_Dependencies; + + int m_nDefaultCurveType; + +public: + // used only during scrubbing of looping sequences + float m_flPrevCycle; + float m_flPrevTime; + + // Flags + + bool m_bFixedLength:1; + // True if this event must be "finished" before the next section can be started + // after playback is paused from a globalevent + bool m_bResumeCondition:1; + bool m_bUsesTag:1; + bool m_bTrackLookupSet:1; + bool m_bProcessing:1; + bool m_bLockBodyFacing:1; + // Purely for save/load + bool m_bMarkedForSave:1; + bool m_bUsingCombinedSoundFile:1; + bool m_bCCTokenValid:1; + bool m_bCombinedUsingGenderToken:1; + + bool m_bSuppressCaptionAttenuation:1; + + bool m_bForceShortMovement:1; + bool m_bSyncToFollowingGesture:1; + bool m_bActive:1; + bool m_bPlayOverScript:1; +}; + +#endif // CHOREOEVENT_H diff --git a/game/shared/choreoscene.h b/game/shared/choreoscene.h new file mode 100644 index 0000000..d8203c1 --- /dev/null +++ b/game/shared/choreoscene.h @@ -0,0 +1,408 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CHOREOSCENE_H +#define CHOREOSCENE_H +#ifdef _WIN32 +#pragma once +#endif + +class CChoreoEvent; +class CChoreoChannel; +class CChoreoActor; +class IChoreoEventCallback; +class CEventRelativeTag; +class CUtlBuffer; +class CFlexAnimationTrack; +class ISceneTokenProcessor; +class IChoreoStringPool; + +#include "tier1/utlvector.h" +#include "tier1/utldict.h" +#include "bitvec.h" +#include "expressionsample.h" +#include "choreoevent.h" + +#define DEFAULT_SCENE_FPS 60 +#define MIN_SCENE_FPS 10 +#define MAX_SCENE_FPS 240 + +#define SCENE_BINARY_TAG MAKEID( 'b', 'v', 'c', 'd' ) +#define SCENE_BINARY_VERSION 0x04 + +//----------------------------------------------------------------------------- +// Purpose: Container for choreographed scene of events for actors +//----------------------------------------------------------------------------- +class CChoreoScene : public ICurveDataAccessor +{ + typedef enum + { + PROCESSING_TYPE_IGNORE = 0, + PROCESSING_TYPE_START, + PROCESSING_TYPE_START_RESUMECONDITION, + PROCESSING_TYPE_CONTINUE, + PROCESSING_TYPE_STOP, + } PROCESSING_TYPE; + + struct ActiveList + { + PROCESSING_TYPE pt; + CChoreoEvent *e; + }; + +public: + // Construction + CChoreoScene( IChoreoEventCallback *callback ); + ~CChoreoScene( void ); + + // Assignment + CChoreoScene& operator=(const CChoreoScene& src ); + + // ICurveDataAccessor methods + virtual float GetDuration() { return FindStopTime(); }; + virtual bool CurveHasEndTime(); + virtual int GetDefaultCurveType(); + + // Binary serialization + bool SaveBinary( char const *pszBinaryFileName, char const *pPathID, unsigned int nTextVersionCRC, IChoreoStringPool *pStringPool ); + void SaveToBinaryBuffer( CUtlBuffer& buf, unsigned int nTextVersionCRC, IChoreoStringPool *pStringPool ); + bool RestoreFromBinaryBuffer( CUtlBuffer& buf, char const *filename, IChoreoStringPool *pStringPool ); + static bool GetCRCFromBinaryBuffer( CUtlBuffer& buf, unsigned int& crc ); + + // We do some things differently while restoring from a save. + inline void SetRestoring( bool bRestoring ); + inline bool IsRestoring(); + + enum + { + MAX_SCENE_FILENAME = 128, + }; + + // Event callback handler + void SetEventCallbackInterface( IChoreoEventCallback *callback ); + + // Loading + bool ParseFromBuffer( char const *pFilename, ISceneTokenProcessor *tokenizer ); + void SetPrintFunc( void ( *pfn )( PRINTF_FORMAT_STRING const char *fmt, ... ) ); + + // Saving + bool SaveToFile( const char *filename ); + bool ExportMarkedToFile( const char *filename ); + void MarkForSaveAll( bool mark ); + + // Merges two .vcd's together, returns true if any data was merged + bool Merge( CChoreoScene *other ); + + static void FileSaveFlexAnimationTrack( CUtlBuffer& buf, int level, CFlexAnimationTrack *track, int nDefaultCurveType ); + static void FileSaveFlexAnimations( CUtlBuffer& buf, int level, CChoreoEvent *e ); + static void FileSaveRamp( CUtlBuffer& buf, int level, CChoreoEvent *e ); + void FileSaveSceneRamp( CUtlBuffer& buf, int level ); + static void FileSaveScaleSettings( CUtlBuffer& buf, int level, CChoreoScene *scene ); + + static void ParseFlexAnimations( ISceneTokenProcessor *tokenizer, CChoreoEvent *e, bool removeold = true ); + static void ParseRamp( ISceneTokenProcessor *tokenizer, CChoreoEvent *e ); + static void ParseSceneRamp( ISceneTokenProcessor *tokenizer, CChoreoScene *scene ); + static void ParseScaleSettings( ISceneTokenProcessor *tokenizer, CChoreoScene *scene ); + static void ParseEdgeInfo( ISceneTokenProcessor *tokenizer, EdgeInfo_t *edgeinfo ); + + // Debugging + void SceneMsg( PRINTF_FORMAT_STRING const char *pFormat, ... ); + void Print( void ); + + // Sound system needs to have sounds pre-queued by this much time + void SetSoundFileStartupLatency( float time ); + + // Simulation + void Think( float curtime ); + float LoopThink( float curtime ); + void ProcessActiveListEntry( ActiveList *entry ); + // Retrieves time in simulation + float GetTime( void ); + // Retrieves start/stop time for looped/debug scene + void GetSceneTimes( float& start, float& end ); + + void SetTime( float t ); + void LoopToTime( float t ); + + // Has simulation finished + bool SimulationFinished( void ); + // Reset simulation + void ResetSimulation( bool forward = true, float starttime = 0.0f, float endtime = 0.0f ); + // Find time at which last simulation event is triggered + float FindStopTime( void ); + + void ResumeSimulation( void ); + + // Have all the pause events happened + bool CheckEventCompletion( void ); + + // Find named actor in scene data + CChoreoActor *FindActor( const char *name ); + // Remove actor from scene + void RemoveActor( CChoreoActor *actor ); + // Find index for actor + int FindActorIndex( CChoreoActor *actor ); + + // Swap actors in the data + void SwapActors( int a1, int a2 ); + + // General data access + int GetNumEvents( void ); + CChoreoEvent *GetEvent( int event ); + + int GetNumActors( void ); + CChoreoActor *GetActor( int actor ); + + int GetNumChannels( void ); + CChoreoChannel *GetChannel( int channel ); + + // Object allocation/destruction + void DeleteReferencedObjects( CChoreoActor *actor ); + void DeleteReferencedObjects( CChoreoChannel *channel ); + void DeleteReferencedObjects( CChoreoEvent *event ); + + CChoreoActor *AllocActor( void ); + CChoreoChannel *AllocChannel( void ); + CChoreoEvent *AllocEvent( void ); + + void AddEventToScene( CChoreoEvent *event ); + void AddActorToScene( CChoreoActor *actor ); + void AddChannelToScene( CChoreoChannel *channel ); + + // Fixup simulation times for channel gestures + void ReconcileGestureTimes( void ); + + // Go through all elements and update relative tags, removing any orphaned + // tags and updating the timestamp of normal tags + void ReconcileTags( void ); + CEventRelativeTag *FindTagByName( const char *wavname, const char *name ); + CChoreoEvent *FindTargetingEvent( const char *wavname, const char *name ); + + // Used by UI to provide target actor names + char const *GetMapname( void ); + void SetMapname( const char *name ); + + void ExportEvents( const char *filename, CUtlVector< CChoreoEvent * >& events ); + void ImportEvents( ISceneTokenProcessor *tokenizer, CChoreoActor *actor, CChoreoChannel *channel ); + + // Subscene support + void SetSubScene( bool sub ); + bool IsSubScene( void ) const; + + int GetSceneFPS( void ) const; + void SetSceneFPS( int fps ); + bool IsUsingFrameSnap( void ) const; + void SetUsingFrameSnap( bool snap ); + + float SnapTime( float t ); + + int GetSceneRampCount( void ) { return m_SceneRamp.GetCount(); }; + CExpressionSample *GetSceneRamp( int index ) { return m_SceneRamp.Get( index ); }; + CExpressionSample *AddSceneRamp( float time, float value, bool selected ) { return m_SceneRamp.Add( time, value, selected ); }; + void DeleteSceneRamp( int index ) { m_SceneRamp.Delete( index ); }; + void ClearSceneRamp( void ) { m_SceneRamp.Clear(); }; + void ResortSceneRamp( void ) { m_SceneRamp.Resort( this ); }; + + CCurveData *GetSceneRamp( void ) { return &m_SceneRamp; }; + + + // Global intensity for scene + float GetSceneRampIntensity( float time ) { return m_SceneRamp.GetIntensity( this, time ); } + + int GetTimeZoom( char const *tool ); + void SetTimeZoom( char const *tool, int tz ); + int TimeZoomFirst(); + int TimeZoomNext( int i ); + int TimeZoomInvalid() const; + char const *TimeZoomName( int i ); + + void ReconcileCloseCaption(); + + char const *GetFilename() const; + void SetFileName( char const *fn ); + + bool GetPlayingSoundName( char *pchBuff, int iBuffLength ); + bool HasUnplayedSpeech(); + bool HasFlexAnimation(); + void SetBackground( bool bIsBackground ); + bool IsBackground( void ); + + void ClearPauseEventDependencies(); + + bool HasEventsOfType( CChoreoEvent::EVENTTYPE type ) const; + void RemoveEventsExceptTypes( int* typeList, int count ); + + void IgnorePhonemes( bool bIgnore ); + bool ShouldIgnorePhonemes() const; + + // This is set by the engine to signify that we're not modifying the data and + // therefore we can precompute the end time + static bool s_bEditingDisabled; + +private: + + // Simulation stuff + enum + { + IN_RANGE = 0, + BEFORE_RANGE, + AFTER_RANGE + }; + + int IsTimeInRange( float t, float starttime, float endtime ); + + static bool EventLess( const CChoreoScene::ActiveList &al0, const CChoreoScene::ActiveList &al1 ); + + int EventThink( CChoreoEvent *e, + float frame_start_time, + float frame_end_time, + bool playing_forward, PROCESSING_TYPE& disposition ); + + // Prints to debug console, etc + void choreoprintf( int level, PRINTF_FORMAT_STRING const char *fmt, ... ); + + // Initialize scene + void Init( IChoreoEventCallback *callback ); + + float FindAdjustedStartTime( void ); + float FindAdjustedEndTime( void ); + + CChoreoEvent *FindPauseBetweenTimes( float starttime, float endtime ); + + // Parse scenes from token buffer + CChoreoEvent *ParseEvent( CChoreoActor *actor, CChoreoChannel *channel ); + CChoreoChannel *ParseChannel( CChoreoActor *actor ); + CChoreoActor *ParseActor( void ); + + void ParseFPS( void ); + void ParseSnap( void ); + void ParseIgnorePhonemes( void ); + + // Map file for retrieving named objects + void ParseMapname( void ); + // When previewing actor in hlfaceposer, this is the model to associate + void ParseFacePoserModel( CChoreoActor *actor ); + + // Print to printfunc + void PrintEvent( int level, CChoreoEvent *e ); + void PrintChannel( int level, CChoreoChannel *c ); + void PrintActor( int level, CChoreoActor *a ); + + // File I/O +public: + static void FilePrintf( CUtlBuffer& buf, int level, PRINTF_FORMAT_STRING const char *fmt, ... ); +private: + void FileSaveEvent( CUtlBuffer& buf, int level, CChoreoEvent *e ); + void FileSaveChannel( CUtlBuffer& buf, int level, CChoreoChannel *c ); + void FileSaveActor( CUtlBuffer& buf, int level, CChoreoActor *a ); + void FileSaveHeader( CUtlBuffer& buf ); + + // Object destruction + void DestroyActor( CChoreoActor *actor ); + void DestroyChannel( CChoreoChannel *channel ); + void DestroyEvent( CChoreoEvent *event ); + + + void AddPauseEventDependency( CChoreoEvent *pauseEvent, CChoreoEvent *suppressed ); + + void InternalDetermineEventTypes(); + + // Global object storage + CUtlVector < CChoreoEvent * > m_Events; + CUtlVector < CChoreoActor * > m_Actors; + CUtlVector < CChoreoChannel * > m_Channels; + + // These are just pointers, the actual objects are in m_Events + CUtlVector < CChoreoEvent * > m_ResumeConditions; + // These are just pointers, the actual objects are in m_Events + CUtlVector < CChoreoEvent * > m_ActiveResumeConditions; + // These are just pointers, the actual objects are in m_Events + CUtlVector < CChoreoEvent * > m_PauseEvents; + + // Current simulation time + float m_flCurrentTime; + + float m_flStartLoopTime; + + float m_flStartTime; + float m_flEndTime; + + float m_flEarliestTime; + float m_flLatestTime; + int m_nActiveEvents; + + // Wave file playback needs to issue play commands a bit ahead of time + // in order to hit exact marks + float m_flSoundSystemLatency; + + // Scene's linger a bit after finishing to let blends reset themselves + float m_flLastActiveTime; + + // Print callback function + void ( *m_pfnPrint )( PRINTF_FORMAT_STRING const char *fmt, ... ); + + IChoreoEventCallback *m_pIChoreoEventCallback; + + ISceneTokenProcessor *m_pTokenizer; + + enum + { + MAX_MAPNAME = 128 + }; + + char m_szMapname[ MAX_MAPNAME ]; + + int m_nSceneFPS; + + CCurveData m_SceneRamp; + + CUtlDict< int, int > m_TimeZoomLookup; + char m_szFileName[ MAX_SCENE_FILENAME ]; + + CBitVec< CChoreoEvent::NUM_TYPES > m_bitvecHasEventOfType; + + // tag to suppress vcd when others are playing + bool m_bIsBackground : 1; + bool m_bIgnorePhonemes : 1; + bool m_bSubScene : 1; + bool m_bUseFrameSnap : 1; + bool m_bRestoring : 1; + + int m_nLastPauseEvent; + // This only gets updated if it's loaded from a buffer which means we're not in an editor + float m_flPrecomputedStopTime; +}; + + +bool CChoreoScene::IsRestoring() +{ + return m_bRestoring; +} + + +void CChoreoScene::SetRestoring( bool bRestoring ) +{ + m_bRestoring = bRestoring; +} + + +abstract_class IChoreoStringPool +{ +public: + virtual short FindOrAddString( const char *pString ) = 0; + virtual bool GetString( short stringId, char *buff, int buffSize ) = 0; +}; + +CChoreoScene *ChoreoLoadScene( + char const *filename, + IChoreoEventCallback *callback, + ISceneTokenProcessor *tokenizer, + void ( *pfn ) ( PRINTF_FORMAT_STRING const char *fmt, ... ) ); + +bool IsBufferBinaryVCD( char *pBuffer, int bufferSize ); + +#endif // CHOREOSCENE_H diff --git a/game/shared/collisionproperty.h b/game/shared/collisionproperty.h new file mode 100644 index 0000000..346889a --- /dev/null +++ b/game/shared/collisionproperty.h @@ -0,0 +1,503 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COLLISIONPROPERTY_H +#define COLLISIONPROPERTY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkvar.h" +#include "engine/ICollideable.h" +#include "mathlib/vector.h" +#include "ispatialpartition.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CBaseEntity; +class IHandleEntity; +class QAngle; +class Vector; +struct Ray_t; +class IPhysicsObject; + + +//----------------------------------------------------------------------------- +// Force spatial partition updates (to avoid threading problems caused by lazy update) +//----------------------------------------------------------------------------- +void UpdateDirtySpatialPartitionEntities(); + + +//----------------------------------------------------------------------------- +// Specifies how to compute the surrounding box +//----------------------------------------------------------------------------- +enum SurroundingBoundsType_t +{ + USE_OBB_COLLISION_BOUNDS = 0, + USE_BEST_COLLISION_BOUNDS, // Always use the best bounds (most expensive) + USE_HITBOXES, + USE_SPECIFIED_BOUNDS, + USE_GAME_CODE, + USE_ROTATION_EXPANDED_BOUNDS, + USE_COLLISION_BOUNDS_NEVER_VPHYSICS, + + SURROUNDING_TYPE_BIT_COUNT = 3 +}; + + +//----------------------------------------------------------------------------- +// Encapsulates collision representation for an entity +//----------------------------------------------------------------------------- +class CCollisionProperty : public ICollideable +{ + DECLARE_CLASS_NOBASE( CCollisionProperty ); + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_PREDICTABLE(); + +#ifdef GAME_DLL + DECLARE_DATADESC(); +#endif + +public: + CCollisionProperty(); + ~CCollisionProperty(); + + void Init( CBaseEntity *pEntity ); + + // Methods of ICollideable + virtual IHandleEntity *GetEntityHandle(); + virtual const Vector& OBBMinsPreScaled() const { return m_vecMinsPreScaled.Get(); } + virtual const Vector& OBBMaxsPreScaled() const { return m_vecMaxsPreScaled.Get(); } + virtual const Vector& OBBMins() const { return m_vecMins.Get(); } + virtual const Vector& OBBMaxs() const { return m_vecMaxs.Get(); } + virtual void WorldSpaceTriggerBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) const; + virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual int GetCollisionModelIndex(); + virtual const model_t* GetCollisionModel(); + virtual const Vector& GetCollisionOrigin() const; + virtual const QAngle& GetCollisionAngles() const; + virtual const matrix3x4_t& CollisionToWorldTransform() const; + virtual SolidType_t GetSolid() const; + virtual int GetSolidFlags() const; + virtual IClientUnknown* GetIClientUnknown(); + virtual int GetCollisionGroup() const; + virtual void WorldSpaceSurroundingBounds( Vector *pVecMins, Vector *pVecMaxs ); + virtual bool ShouldTouchTrigger( int triggerSolidFlags ) const; + virtual const matrix3x4_t *GetRootParentToWorldTransform() const; + +public: + // Spatial partition management + void CreatePartitionHandle(); + void DestroyPartitionHandle(); + unsigned short GetPartitionHandle() const; + + // Marks the spatial partition dirty + void MarkPartitionHandleDirty(); + + // Sets the collision bounds + the size (OBB) + void SetCollisionBounds( const Vector& mins, const Vector &maxs ); + + // Rebuilds the scaled bounds from the pre-scaled bounds after a model's scale has changed + void RefreshScaledCollisionBounds( void ); + + // Sets special trigger bounds. The bloat amount indicates how much bigger the + // trigger bounds should be beyond the bounds set in SetCollisionBounds + // This method will also set the FSOLID flag FSOLID_USE_TRIGGER_BOUNDS + void UseTriggerBounds( bool bEnable, float flBloat = 0.0f ); + + // Sets the method by which the surrounding collision bounds is set + // You must pass in values for mins + maxs if you select the USE_SPECIFIED_BOUNDS type. + void SetSurroundingBoundsType( SurroundingBoundsType_t type, const Vector *pMins = NULL, const Vector *pMaxs = NULL ); + + // Sets the solid type (which type of collision representation) + void SetSolid( SolidType_t val ); + + // Methods related to size. The OBB here is measured in CollisionSpace + // (specified by GetCollisionToWorld) + const Vector& OBBSize( ) const; + + // Returns a radius (or the square of the radius) of a sphere + // *centered at the world space center* bounding the collision representation + // of the entity. NOTE: The world space center *may* move when the entity rotates. + float BoundingRadius() const; + float BoundingRadius2D() const; + + // Returns the center of the OBB in collision space + const Vector & OBBCenter( ) const; + + // center point of entity measured in world space + // NOTE: This point *may* move when the entity moves depending on + // which solid type is being used. + const Vector & WorldSpaceCenter( ) const; + + // Methods related to solid flags + void ClearSolidFlags( void ); + void RemoveSolidFlags( int flags ); + void AddSolidFlags( int flags ); + bool IsSolidFlagSet( int flagMask ) const; + void SetSolidFlags( int flags ); + bool IsSolid() const; + + // Updates the spatial partition + void UpdatePartition( ); + + // Are the bounds defined in entity space? + bool IsBoundsDefinedInEntitySpace() const; + + // Transforms a point in OBB space to world space + const Vector & CollisionToWorldSpace( const Vector &in, Vector *pResult ) const; + + // Transforms a point in world space to OBB space + const Vector & WorldToCollisionSpace( const Vector &in, Vector *pResult ) const; + + // Transforms a direction in world space to OBB space + const Vector & WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const; + + // Selects a random point in the bounds given the normalized 0-1 bounds + void RandomPointInBounds( const Vector &vecNormalizedMins, const Vector &vecNormalizedMaxs, Vector *pPoint) const; + + // Is a worldspace point within the bounds of the OBB? + bool IsPointInBounds( const Vector &vecWorldPt ) const; + + // Computes a bounding box in world space surrounding the collision bounds + void WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const; + + // Get the collision space mins directly + const Vector & CollisionSpaceMins( void ) const; + + // Get the collision space maxs directly + const Vector & CollisionSpaceMaxs( void ) const; + + // Computes a "normalized" point (range 0,0,0 - 1,1,1) in collision space + // Useful for things like getting a point 75% of the way along z on the OBB, for example + const Vector & NormalizedToCollisionSpace( const Vector &in, Vector *pResult ) const; + + // Computes a "normalized" point (range 0,0,0 - 1,1,1) in world space + const Vector & NormalizedToWorldSpace( const Vector &in, Vector *pResult ) const; + + // Transforms a point in world space to normalized space + const Vector & WorldToNormalizedSpace( const Vector &in, Vector *pResult ) const; + + // Transforms a point in collision space to normalized space + const Vector & CollisionToNormalizedSpace( const Vector &in, Vector *pResult ) const; + + // Computes the nearest point in the OBB to a point specified in world space + void CalcNearestPoint( const Vector &vecWorldPt, Vector *pVecNearestWorldPt ) const; + + // Computes the distance from a point in world space to the OBB + float CalcDistanceFromPoint( const Vector &vecWorldPt ) const; + + // Does a rotation make us need to recompute the surrounding box? + bool DoesRotationInvalidateSurroundingBox( ) const; + + // Does VPhysicsUpdate make us need to recompute the surrounding box? + bool DoesVPhysicsInvalidateSurroundingBox( ) const; + + // Marks the entity has having a dirty surrounding box + void MarkSurroundingBoundsDirty(); + + // Compute the largest dot product of the OBB and the specified direction vector + float ComputeSupportMap( const Vector &vecDirection ) const; + +private: + // Transforms an AABB measured in collision space to a box that surrounds it in world space + void CollisionAABBToWorldAABB( const Vector &entityMins, const Vector &entityMaxs, Vector *pWorldMins, Vector *pWorldMaxs ) const; + + // Expand trigger bounds.. + void ComputeVPhysicsSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Expand trigger bounds.. + bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Computes the surrounding collision bounds based on whatever algorithm we want... + void ComputeCollisionSurroundingBox( bool bUseVPhysics, Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Computes the surrounding collision bounds from the the OBB (not vphysics) + void ComputeRotationExpandedBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Computes the surrounding collision bounds based on whatever algorithm we want... + void ComputeSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Check for untouch + void CheckForUntouch(); + + // Updates the spatial partition + void UpdateServerPartitionMask( ); + + // Outer + CBaseEntity *GetOuter(); + const CBaseEntity *GetOuter() const; + +private: + CBaseEntity *m_pOuter; + + CNetworkVector( m_vecMinsPreScaled ); + CNetworkVector( m_vecMaxsPreScaled ); + CNetworkVector( m_vecMins ); + CNetworkVector( m_vecMaxs ); + float m_flRadius; + + CNetworkVar( unsigned short, m_usSolidFlags ); + + // Spatial partition + SpatialPartitionHandle_t m_Partition; + CNetworkVar( unsigned char, m_nSurroundType ); + + // One of the SOLID_ defines. Use GetSolid/SetSolid. + CNetworkVar( unsigned char, m_nSolidType ); + CNetworkVar( unsigned char , m_triggerBloat ); + + // SUCKY: We didn't use to have to store this previously + // but storing it here means that we can network it + avoid a ton of + // client-side mismatch problems + CNetworkVector( m_vecSpecifiedSurroundingMinsPreScaled ); + CNetworkVector( m_vecSpecifiedSurroundingMaxsPreScaled ); + CNetworkVector( m_vecSpecifiedSurroundingMins ); + CNetworkVector( m_vecSpecifiedSurroundingMaxs ); + + // Cached off world-aligned surrounding bounds +#if 0 + short m_surroundingMins[3]; + short m_surroundingMaxs[3]; +#else + Vector m_vecSurroundingMins; + Vector m_vecSurroundingMaxs; +#endif + + // pointer to the entity's physics object (vphysics.dll) + //IPhysicsObject *m_pPhysicsObject; + + friend class CBaseEntity; +}; + + +//----------------------------------------------------------------------------- +// For networking this bad boy +//----------------------------------------------------------------------------- +#ifdef CLIENT_DLL +EXTERN_RECV_TABLE( DT_CollisionProperty ); +#else +EXTERN_SEND_TABLE( DT_CollisionProperty ); +#endif + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline CBaseEntity *CCollisionProperty::GetOuter() +{ + return m_pOuter; +} + +inline const CBaseEntity *CCollisionProperty::GetOuter() const +{ + return m_pOuter; +} + + +//----------------------------------------------------------------------------- +// Spatial partition +//----------------------------------------------------------------------------- +inline unsigned short CCollisionProperty::GetPartitionHandle() const +{ + return m_Partition; +} + + +//----------------------------------------------------------------------------- +// Methods related to size +//----------------------------------------------------------------------------- +inline const Vector& CCollisionProperty::OBBSize( ) const +{ + // NOTE: Could precache this, but it's not used that often.. + Vector &temp = AllocTempVector(); + VectorSubtract( m_vecMaxs, m_vecMins, temp ); + return temp; +} + + +//----------------------------------------------------------------------------- +// Bounding radius size +//----------------------------------------------------------------------------- +inline float CCollisionProperty::BoundingRadius() const +{ + return m_flRadius; +} + + +//----------------------------------------------------------------------------- +// Methods relating to solid flags +//----------------------------------------------------------------------------- +inline bool CCollisionProperty::IsBoundsDefinedInEntitySpace() const +{ + return (( m_usSolidFlags & FSOLID_FORCE_WORLD_ALIGNED ) == 0 ) && + ( m_nSolidType != SOLID_BBOX ) && ( m_nSolidType != SOLID_NONE ); +} + +inline void CCollisionProperty::ClearSolidFlags( void ) +{ + SetSolidFlags( 0 ); +} + +inline void CCollisionProperty::RemoveSolidFlags( int flags ) +{ + SetSolidFlags( m_usSolidFlags & ~flags ); +} + +inline void CCollisionProperty::AddSolidFlags( int flags ) +{ + SetSolidFlags( m_usSolidFlags | flags ); +} + +inline int CCollisionProperty::GetSolidFlags( void ) const +{ + return m_usSolidFlags; +} + +inline bool CCollisionProperty::IsSolidFlagSet( int flagMask ) const +{ + return (m_usSolidFlags & flagMask) != 0; +} + +inline bool CCollisionProperty::IsSolid() const +{ + return ::IsSolid( (SolidType_t)(unsigned char)m_nSolidType, m_usSolidFlags ); +} + + +//----------------------------------------------------------------------------- +// Returns the center in OBB space +//----------------------------------------------------------------------------- +inline const Vector& CCollisionProperty::OBBCenter( ) const +{ + Vector &vecResult = AllocTempVector(); + VectorLerp( m_vecMins, m_vecMaxs, 0.5f, vecResult ); + return vecResult; +} + + +//----------------------------------------------------------------------------- +// center point of entity +//----------------------------------------------------------------------------- +inline const Vector &CCollisionProperty::WorldSpaceCenter( ) const +{ + Vector &vecResult = AllocTempVector(); + CollisionToWorldSpace( OBBCenter(), &vecResult ); + return vecResult; +} + + +//----------------------------------------------------------------------------- +// Transforms a point in OBB space to world space +//----------------------------------------------------------------------------- +inline const Vector &CCollisionProperty::CollisionToWorldSpace( const Vector &in, Vector *pResult ) const +{ + // Makes sure we don't re-use the same temp twice + if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) ) + { + VectorAdd( in, GetCollisionOrigin(), *pResult ); + } + else + { + VectorTransform( in, CollisionToWorldTransform(), *pResult ); + } + return *pResult; +} + + +//----------------------------------------------------------------------------- +// Transforms a point in world space to OBB space +//----------------------------------------------------------------------------- +inline const Vector &CCollisionProperty::WorldToCollisionSpace( const Vector &in, Vector *pResult ) const +{ + if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) ) + { + VectorSubtract( in, GetCollisionOrigin(), *pResult ); + } + else + { + VectorITransform( in, CollisionToWorldTransform(), *pResult ); + } + return *pResult; +} + + +//----------------------------------------------------------------------------- +// Transforms a direction in world space to OBB space +//----------------------------------------------------------------------------- +inline const Vector & CCollisionProperty::WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const +{ + if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) ) + { + *pResult = in; + } + else + { + VectorIRotate( in, CollisionToWorldTransform(), *pResult ); + } + return *pResult; +} + + +//----------------------------------------------------------------------------- +// Computes a bounding box in world space surrounding the collision bounds +//----------------------------------------------------------------------------- +inline void CCollisionProperty::WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const +{ + CollisionAABBToWorldAABB( m_vecMins, m_vecMaxs, pWorldMins, pWorldMaxs ); +} + + +// Get the collision space mins directly +inline const Vector & CCollisionProperty::CollisionSpaceMins( void ) const +{ + return m_vecMins; +} + +// Get the collision space maxs directly +inline const Vector & CCollisionProperty::CollisionSpaceMaxs( void ) const +{ + return m_vecMaxs; +} + + +//----------------------------------------------------------------------------- +// Does a rotation make us need to recompute the surrounding box? +//----------------------------------------------------------------------------- +inline bool CCollisionProperty::DoesRotationInvalidateSurroundingBox( ) const +{ + if ( IsSolidFlagSet(FSOLID_ROOT_PARENT_ALIGNED) ) + return true; + + switch ( m_nSurroundType ) + { + case USE_COLLISION_BOUNDS_NEVER_VPHYSICS: + case USE_OBB_COLLISION_BOUNDS: + case USE_BEST_COLLISION_BOUNDS: + return IsBoundsDefinedInEntitySpace(); + + // In the case of game code, we don't really know, so we have to assume it does + case USE_HITBOXES: + case USE_GAME_CODE: + return true; + + case USE_ROTATION_EXPANDED_BOUNDS: + case USE_SPECIFIED_BOUNDS: + return false; + + default: + Assert(0); + return true; + } +} + + +#endif // COLLISIONPROPERTY_H diff --git a/game/shared/cs_achievements_and_stats_interface.h b/game/shared/cs_achievements_and_stats_interface.h new file mode 100644 index 0000000..ddeaf03 --- /dev/null +++ b/game/shared/cs_achievements_and_stats_interface.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef CSACHIEVEMENTSANDSTATSINTERFACE_H +#define CSACHIEVEMENTSANDSTATSINTERFACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "achievements_and_stats_interface.h" +#include "vgui_controls/Panel.h" +#include "vgui_controls/PHandle.h" +#include "vgui_controls/MenuItem.h" +#include "vgui_controls/MessageDialog.h" + +#include "cs_gamestats_shared.h" +#include "../client/cstrike/VGUI/achievement_stats_summary.h" +#include "vgui/IInput.h" +#include "vgui/ILocalize.h" +#include "vgui/IPanel.h" +#include "vgui/ISurface.h" +#include "vgui/ISystem.h" +#include "vgui/IVGui.h" + + +#if defined(CSTRIKE_DLL) && defined(CLIENT_DLL) + +class CSAchievementsAndStatsInterface : public AchievementsAndStatsInterface +{ +public: + CSAchievementsAndStatsInterface(); + + virtual void CreatePanel( vgui::Panel* pParent ); + virtual void DisplayPanel(); + virtual void ReleasePanel(); + virtual int GetAchievementsPanelMinWidth( void ) const { return cAchievementsDialogMinWidth; } + +protected: + vgui::DHANDLE m_pAchievementAndStatsSummary; +}; + +#endif + +#endif // CSACHIEVEMENTSANDSTATSINTERFACE_H diff --git a/game/shared/death_pose.h b/game/shared/death_pose.h new file mode 100644 index 0000000..787b601 --- /dev/null +++ b/game/shared/death_pose.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DEATH_POSE_H +#define DEATH_POSE_H +#ifdef _WIN32 +#pragma once +#endif + +enum +{ + DEATH_FRAME_HEAD = 1, + DEATH_FRAME_STOMACH, + DEATH_FRAME_LEFTARM, + DEATH_FRAME_RIGHTARM, + DEATH_FRAME_LEFTLEG, + DEATH_FRAME_RIGHTLEG, + MAX_DEATHPOSE_FRAMES = DEATH_FRAME_RIGHTLEG +}; + +#ifdef CLIENT_DLL + +void GetRagdollCurSequenceWithDeathPose( C_BaseAnimating *entity, matrix3x4_t *curBones, float flTime, int activity, int frame ); + +#else // !CLIENT_DLL + +/// Calculates death pose activity and frame +void SelectDeathPoseActivityAndFrame( CBaseAnimating *entity, const CTakeDamageInfo &info, int hitgroup, Activity& activity, int& frame ); + +#endif // !CLIENT_DLL + +#endif // DEATH_POSE_H diff --git a/game/shared/debugoverlay_shared.h b/game/shared/debugoverlay_shared.h new file mode 100644 index 0000000..a37a1b9 --- /dev/null +++ b/game/shared/debugoverlay_shared.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef DEBUGOVERLAY_SHARED_H +#define DEBUGOVERLAY_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "engine/ivdebugoverlay.h" +#include "mathlib/vector.h" + +//============================================================================= +// NDebugOverlay +//============================================================================= +namespace NDebugOverlay +{ + void Box(const Vector &origin, const Vector &mins, const Vector &maxs, int r, int g, int b, int a, float flDuration); + void BoxDirection(const Vector &origin, const Vector &mins, const Vector &maxs, const Vector &forward, int r, int g, int b, int a, float flDuration); + void BoxAngles(const Vector &origin, const Vector &mins, const Vector &maxs, const QAngle &angles, int r, int g, int b, int a, float flDuration); + void SweptBox(const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, const QAngle & angles, int r, int g, int b, int a, float flDuration); + void EntityBounds( const CBaseEntity *pEntity, int r, int g, int b, int a, float flDuration ); + void Line( const Vector &origin, const Vector &target, int r, int g, int b, bool noDepthTest, float flDuration ); + void Triangle( const Vector &p1, const Vector &p2, const Vector &p3, int r, int g, int b, int a, bool noDepthTest, float duration ); + void EntityText( int entityID, int text_offset, const char *text, float flDuration, int r = 255, int g = 255, int b = 255, int a = 255); + void EntityTextAtPosition( const Vector &origin, int text_offset, const char *text, float flDuration, int r = 255, int g = 255, int b = 255, int a = 255); + void Grid( const Vector &vPosition ); + void Text( const Vector &origin, const char *text, bool bViewCheck, float flDuration ); + void ScreenText( float fXpos, float fYpos, const char *text, int r, int g, int b, int a, float flDuration); + void Cross3D(const Vector &position, const Vector &mins, const Vector &maxs, int r, int g, int b, bool noDepthTest, float flDuration ); + void Cross3D(const Vector &position, float size, int r, int g, int b, bool noDepthTest, float flDuration ); + void Cross3DOriented( const Vector &position, const QAngle &angles, float size, int r, int g, int b, bool noDepthTest, float flDuration ); + void Cross3DOriented( const matrix3x4_t &m, float size, int c, bool noDepthTest, float flDuration ); + void DrawOverlayLines(void); + void DrawTickMarkedLine(const Vector &startPos, const Vector &endPos, float tickDist, int tickTextDist, int r, int g, int b, bool noDepthTest, float flDuration ); + void DrawGroundCrossHairOverlay(); + void HorzArrow( const Vector &startPos, const Vector &endPos, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration); + void YawArrow( const Vector &startPos, float yaw, float length, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration); + void VertArrow( const Vector &startPos, const Vector &endPos, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration); + void Axis( const Vector &position, const QAngle &angles, float size, bool noDepthTest, float flDuration ); + void Sphere( const Vector ¢er, float radius, int r, int g, int b, bool noDepthTest, float flDuration ); + void Circle( const Vector &position, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration ); + void Circle( const Vector &position, const QAngle &angles, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration ); + void Circle( const Vector &position, const Vector &xAxis, const Vector &yAxis, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration ); + void Sphere( const Vector &position, const QAngle &angles, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration ); +}; + +#endif // DEBUGOVERLAY_SHARED_H diff --git a/game/shared/decals.h b/game/shared/decals.h new file mode 100644 index 0000000..83e70c6 --- /dev/null +++ b/game/shared/decals.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef DECALS_H +#define DECALS_H +#ifdef _WIN32 +#pragma once +#endif + +// NOTE: If you add a tex type, be sure to modify the s_pImpactEffect +// array in fx_impact.cpp to get an effect when that surface is shot. +#define CHAR_TEX_ANTLION 'A' +#define CHAR_TEX_BLOODYFLESH 'B' +#define CHAR_TEX_CONCRETE 'C' +#define CHAR_TEX_DIRT 'D' +#define CHAR_TEX_EGGSHELL 'E' ///< the egg sacs in the tunnels in ep2. +#define CHAR_TEX_FLESH 'F' +#define CHAR_TEX_GRATE 'G' +#define CHAR_TEX_ALIENFLESH 'H' +#define CHAR_TEX_CLIP 'I' +//#define CHAR_TEX_UNUSED 'J' +//#define CHAR_TEX_UNUSED 'K' +#define CHAR_TEX_PLASTIC 'L' +#define CHAR_TEX_METAL 'M' +#define CHAR_TEX_SAND 'N' +#define CHAR_TEX_FOLIAGE 'O' +#define CHAR_TEX_COMPUTER 'P' +//#define CHAR_TEX_UNUSED 'Q' +//#define CHAR_TEX_UNUSED 'R' +#define CHAR_TEX_SLOSH 'S' +#define CHAR_TEX_TILE 'T' +//#define CHAR_TEX_UNUSED 'U' +#define CHAR_TEX_VENT 'V' +#define CHAR_TEX_WOOD 'W' +//#define CHAR_TEX_UNUSED 'X' +#define CHAR_TEX_GLASS 'Y' +#define CHAR_TEX_WARPSHIELD 'Z' ///< wierd-looking jello effect for advisor shield. + +abstract_class IDecalEmitterSystem +{ +public: + virtual int GetDecalIndexForName( char const *decalname ) = 0; + virtual const char *GetDecalNameForIndex( int nIndex ) = 0; + virtual char const *TranslateDecalForGameMaterial( char const *decalName, unsigned char gamematerial ) = 0; +}; + +extern IDecalEmitterSystem *decalsystem; + +#endif // DECALS_H diff --git a/game/shared/econ/ihasowner.h b/game/shared/econ/ihasowner.h new file mode 100644 index 0000000..77ac139 --- /dev/null +++ b/game/shared/econ/ihasowner.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IHASOWNER_H +#define IHASOWNER_H +#ifdef _WIN32 +#pragma once +#endif + +class CBaseEntity; + +//----------------------------------------------------------------------------- +// Purpose: Allows an entity to access its owner regardless of entity type +//----------------------------------------------------------------------------- +class IHasOwner +{ +public: + virtual CBaseEntity *GetOwnerViaInterface( void ) = 0; +}; + +#endif // IHASOWNER_H diff --git a/game/shared/effect_color_tables.h b/game/shared/effect_color_tables.h new file mode 100644 index 0000000..348e894 --- /dev/null +++ b/game/shared/effect_color_tables.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef EFFECT_COLOR_TABLES_H +#define EFFECT_COLOR_TABLES_H +#ifdef _WIN32 +#pragma once +#endif + +struct colorentry_t +{ + unsigned char index; + + unsigned char r; + unsigned char g; + unsigned char b; +}; + +#define COLOR_TABLE_SIZE(ct) sizeof(ct)/sizeof(colorentry_t) + +// Commander mode indicators (HL2) +enum +{ + COMMAND_POINT_RED = 0, + COMMAND_POINT_BLUE, + COMMAND_POINT_GREEN, + COMMAND_POINT_YELLOW, +}; + +// Commander mode table +static colorentry_t commandercolors[] = +{ + { COMMAND_POINT_RED, 1, 0, 0 }, + { COMMAND_POINT_BLUE, 0, 0, 1 }, + { COMMAND_POINT_GREEN, 0, 1, 0 }, + { COMMAND_POINT_YELLOW, 1, 1, 0 }, +}; + +static colorentry_t bloodcolors[] = +{ + { BLOOD_COLOR_RED, 72, 0, 0 }, + { BLOOD_COLOR_YELLOW, 195, 195, 0 }, + { BLOOD_COLOR_MECH, 20, 20, 20 }, + { BLOOD_COLOR_GREEN, 195, 195, 0 }, +}; + +#endif // EFFECT_COLOR_TABLES_H diff --git a/game/shared/effect_dispatch_data.h b/game/shared/effect_dispatch_data.h new file mode 100644 index 0000000..5f6e664 --- /dev/null +++ b/game/shared/effect_dispatch_data.h @@ -0,0 +1,139 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef EFFECT_DISPATCH_DATA_H +#define EFFECT_DISPATCH_DATA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particle_parse.h" + +#ifdef CLIENT_DLL + + #include "dt_recv.h" + #include "client_class.h" + + EXTERN_RECV_TABLE( DT_EffectData ); + +#else + + #include "dt_send.h" + #include "server_class.h" + + EXTERN_SEND_TABLE( DT_EffectData ); + +#endif + +// NOTE: These flags are specifically *not* networked; so it's placed above the max effect flag bits +#define EFFECTDATA_NO_RECORD 0x80000000 + +#define MAX_EFFECT_FLAG_BITS 8 + +#define CUSTOM_COLOR_CP1 9 +#define CUSTOM_COLOR_CP2 10 + +// This is the class that holds whatever data we're sending down to the client to make the effect. +class CEffectData +{ +public: + Vector m_vOrigin; + Vector m_vStart; + Vector m_vNormal; + QAngle m_vAngles; + int m_fFlags; +#ifdef CLIENT_DLL + ClientEntityHandle_t m_hEntity; +#else + int m_nEntIndex; +#endif + float m_flScale; + float m_flMagnitude; + float m_flRadius; + int m_nAttachmentIndex; + short m_nSurfaceProp; + + // Some TF2 specific things + int m_nMaterial; + int m_nDamageType; + int m_nHitBox; + + unsigned char m_nColor; + + // Color customizability + bool m_bCustomColors; + te_tf_particle_effects_colors_t m_CustomColors; + + bool m_bControlPoint1; + te_tf_particle_effects_control_point_t m_ControlPoint1; + +// Don't mess with stuff below here. DispatchEffect handles all of this. +public: + CEffectData() + { + m_vOrigin.Init(); + m_vStart.Init(); + m_vNormal.Init(); + m_vAngles.Init(); + + m_fFlags = 0; +#ifdef CLIENT_DLL + m_hEntity = INVALID_EHANDLE_INDEX; +#else + m_nEntIndex = 0; +#endif + m_flScale = 1.f; + m_nAttachmentIndex = 0; + m_nSurfaceProp = 0; + + m_flMagnitude = 0.0f; + m_flRadius = 0.0f; + + m_nMaterial = 0; + m_nDamageType = 0; + m_nHitBox = 0; + + m_nColor = 0; + + m_bCustomColors = false; + m_CustomColors.m_vecColor1.Init(); + m_CustomColors.m_vecColor2.Init(); + + m_bControlPoint1 = false; + m_ControlPoint1.m_eParticleAttachment = PATTACH_ABSORIGIN; + m_ControlPoint1.m_vecOffset.Init(); + } + + int GetEffectNameIndex() { return m_iEffectName; } + +#ifdef CLIENT_DLL + IClientRenderable *GetRenderable() const; + C_BaseEntity *GetEntity() const; + int entindex() const; +#endif + +private: + + #ifdef CLIENT_DLL + DECLARE_CLIENTCLASS_NOBASE() + #else + DECLARE_SERVERCLASS_NOBASE() + #endif + + int m_iEffectName; // Entry in the EffectDispatch network string table. The is automatically handled by DispatchEffect(). +}; + + +#define MAX_EFFECT_DISPATCH_STRING_BITS 10 +#define MAX_EFFECT_DISPATCH_STRINGS ( 1 << MAX_EFFECT_DISPATCH_STRING_BITS ) + +#ifdef CLIENT_DLL +bool SuppressingParticleEffects(); +void SuppressParticleEffects( bool bSuppress ); +#endif + +#endif // EFFECT_DISPATCH_DATA_H diff --git a/game/shared/ehandle.h b/game/shared/ehandle.h new file mode 100644 index 0000000..7e44cf6 --- /dev/null +++ b/game/shared/ehandle.h @@ -0,0 +1,169 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EHANDLE_H +#define EHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( _DEBUG ) && defined( GAME_DLL ) +#include "tier0/dbg.h" +#include "cbase.h" +#endif + + +#include "const.h" +#include "basehandle.h" +#include "entitylist_base.h" + + +class IHandleEntity; + + +// -------------------------------------------------------------------------------------------------- // +// Game-code CBaseHandle implementation. +// -------------------------------------------------------------------------------------------------- // + +inline IHandleEntity* CBaseHandle::Get() const +{ + extern CBaseEntityList *g_pEntityList; + return g_pEntityList->LookupEntity( *this ); +} + + +// -------------------------------------------------------------------------------------------------- // +// CHandle. +// -------------------------------------------------------------------------------------------------- // +template< class T > +class CHandle : public CBaseHandle +{ +public: + + CHandle(); + CHandle( int iEntry, int iSerialNumber ); + CHandle( const CBaseHandle &handle ); + CHandle( T *pVal ); + + // The index should have come from a call to ToInt(). If it hasn't, you're in trouble. + static CHandle FromIndex( int index ); + + T* Get() const; + void Set( const T* pVal ); + + operator T*(); + operator T*() const; + + bool operator !() const; + bool operator==( T *val ) const; + bool operator!=( T *val ) const; + const CBaseHandle& operator=( const T *val ); + + T* operator->() const; +}; + + +// ----------------------------------------------------------------------- // +// Inlines. +// ----------------------------------------------------------------------- // + +template +CHandle::CHandle() +{ +} + + +template +CHandle::CHandle( int iEntry, int iSerialNumber ) +{ + Init( iEntry, iSerialNumber ); +} + + +template +CHandle::CHandle( const CBaseHandle &handle ) + : CBaseHandle( handle ) +{ +} + + +template +CHandle::CHandle( T *pObj ) +{ + Term(); + Set( pObj ); +} + + +template +inline CHandle CHandle::FromIndex( int index ) +{ + CHandle ret; + ret.m_Index = index; + return ret; +} + + +template +inline T* CHandle::Get() const +{ + return (T*)CBaseHandle::Get(); +} + + +template +inline CHandle::operator T *() +{ + return Get( ); +} + +template +inline CHandle::operator T *() const +{ + return Get( ); +} + + +template +inline bool CHandle::operator !() const +{ + return !Get(); +} + +template +inline bool CHandle::operator==( T *val ) const +{ + return Get() == val; +} + +template +inline bool CHandle::operator!=( T *val ) const +{ + return Get() != val; +} + +template +void CHandle::Set( const T* pVal ) +{ + CBaseHandle::Set( reinterpret_cast(pVal) ); +} + +template +inline const CBaseHandle& CHandle::operator=( const T *val ) +{ + Set( val ); + return *this; +} + +template +T* CHandle::operator -> () const +{ + return Get(); +} + + +#endif // EHANDLE_H diff --git a/game/shared/entitydatainstantiator.h b/game/shared/entitydatainstantiator.h new file mode 100644 index 0000000..2882c58 --- /dev/null +++ b/game/shared/entitydatainstantiator.h @@ -0,0 +1,126 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYDATAINSTANTIATOR_H +#define ENTITYDATAINSTANTIATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlhash.h" + +#include "tier0/memdbgon.h" + +// This is the hash key type, but it could just as easily be and int or void * +class CBaseEntity; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +abstract_class IEntityDataInstantiator +{ +public: + virtual ~IEntityDataInstantiator() {}; + + virtual void *GetDataObject( const CBaseEntity *instance ) = 0; + virtual void *CreateDataObject( const CBaseEntity *instance ) = 0; + virtual void DestroyDataObject( const CBaseEntity *instance ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template +class CEntityDataInstantiator : public IEntityDataInstantiator +{ +public: + CEntityDataInstantiator() : + m_HashTable( 64, 0, 0, CompareFunc, KeyFunc ) + { + } + + virtual void *GetDataObject( const CBaseEntity *instance ) + { + UtlHashHandle_t handle; + HashEntry entry; + entry.key = instance; + handle = m_HashTable.Find( entry ); + + if ( handle != m_HashTable.InvalidHandle() ) + { + return (void *)m_HashTable[ handle ].data; + } + + return NULL; + } + + virtual void *CreateDataObject( const CBaseEntity *instance ) + { + UtlHashHandle_t handle; + HashEntry entry; + entry.key = instance; + handle = m_HashTable.Find( entry ); + + // Create it if not already present + if ( handle == m_HashTable.InvalidHandle() ) + { + handle = m_HashTable.Insert( entry ); + Assert( handle != m_HashTable.InvalidHandle() ); + m_HashTable[ handle ].data = new T; + + // FIXME: We'll have to remove this if any objects we instance have vtables!!! + Q_memset( m_HashTable[ handle ].data, 0, sizeof( T ) ); + } + + return (void *)m_HashTable[ handle ].data; + } + + virtual void DestroyDataObject( const CBaseEntity *instance ) + { + UtlHashHandle_t handle; + HashEntry entry; + entry.key = instance; + handle = m_HashTable.Find( entry ); + + if ( handle != m_HashTable.InvalidHandle() ) + { + delete m_HashTable[ handle ].data; + m_HashTable.Remove( handle ); + } + } + +private: + + struct HashEntry + { + HashEntry() + { + key = NULL; + data = NULL; + } + + const CBaseEntity *key; + T *data; + }; + + static bool CompareFunc( const HashEntry &src1, const HashEntry &src2 ) + { + return ( src1.key == src2.key ); + } + + + static unsigned int KeyFunc( const HashEntry &src ) + { + // Shift right to get rid of alignment bits and border the struct on a 16 byte boundary + return (unsigned int)src.key; + } + + CUtlHash< HashEntry > m_HashTable; +}; + +#include "tier0/memdbgoff.h" + +#endif // ENTITYDATAINSTANTIATOR_H diff --git a/game/shared/entitylist_base.h b/game/shared/entitylist_base.h new file mode 100644 index 0000000..8e2db3b --- /dev/null +++ b/game/shared/entitylist_base.h @@ -0,0 +1,209 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYLIST_BASE_H +#define ENTITYLIST_BASE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "const.h" +#include "basehandle.h" +#include "utllinkedlist.h" +#include "ihandleentity.h" + + +class CEntInfo +{ +public: + IHandleEntity *m_pEntity; + int m_SerialNumber; + CEntInfo *m_pPrev; + CEntInfo *m_pNext; + + void ClearLinks(); +}; + + +class CBaseEntityList +{ +public: + CBaseEntityList(); + ~CBaseEntityList(); + + // Add and remove entities. iForcedSerialNum should only be used on the client. The server + // gets to dictate what the networkable serial numbers are on the client so it can send + // ehandles over and they work. + CBaseHandle AddNetworkableEntity( IHandleEntity *pEnt, int index, int iForcedSerialNum = -1 ); + CBaseHandle AddNonNetworkableEntity( IHandleEntity *pEnt ); + void RemoveEntity( CBaseHandle handle ); + + // Get an ehandle from a networkable entity's index (note: if there is no entity in that slot, + // then the ehandle will be invalid and produce NULL). + CBaseHandle GetNetworkableHandle( int iEntity ) const; + + // ehandles use this in their Get() function to produce a pointer to the entity. + IHandleEntity* LookupEntity( const CBaseHandle &handle ) const; + IHandleEntity* LookupEntityByNetworkIndex( int edictIndex ) const; + + // Use these to iterate over all the entities. + CBaseHandle FirstHandle() const; + CBaseHandle NextHandle( CBaseHandle hEnt ) const; + static CBaseHandle InvalidHandle(); + + const CEntInfo *FirstEntInfo() const; + const CEntInfo *NextEntInfo( const CEntInfo *pInfo ) const; + const CEntInfo *GetEntInfoPtr( const CBaseHandle &hEnt ) const; + const CEntInfo *GetEntInfoPtrByIndex( int index ) const; + +// Overridables. +protected: + + // These are notifications to the derived class. It can cache info here if it wants. + virtual void OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle ); + + // It is safe to delete the entity here. We won't be accessing the pointer after + // calling OnRemoveEntity. + virtual void OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle ); + + +private: + + CBaseHandle AddEntityAtSlot( IHandleEntity *pEnt, int iSlot, int iForcedSerialNum ); + void RemoveEntityAtSlot( int iSlot ); + + +private: + + class CEntInfoList + { + public: + CEntInfoList(); + + const CEntInfo *Head() const { return m_pHead; } + const CEntInfo *Tail() const { return m_pTail; } + CEntInfo *Head() { return m_pHead; } + CEntInfo *Tail() { return m_pTail; } + void AddToHead( CEntInfo *pElement ) { LinkAfter( NULL, pElement ); } + void AddToTail( CEntInfo *pElement ) { LinkBefore( NULL, pElement ); } + + void LinkBefore( CEntInfo *pBefore, CEntInfo *pElement ); + void LinkAfter( CEntInfo *pBefore, CEntInfo *pElement ); + void Unlink( CEntInfo *pElement ); + bool IsInList( CEntInfo *pElement ); + + private: + CEntInfo *m_pHead; + CEntInfo *m_pTail; + }; + + int GetEntInfoIndex( const CEntInfo *pEntInfo ) const; + + + // The first MAX_EDICTS entities are networkable. The rest are client-only or server-only. + CEntInfo m_EntPtrArray[NUM_ENT_ENTRIES]; + CEntInfoList m_activeList; + CEntInfoList m_freeNonNetworkableList; +}; + + +// ------------------------------------------------------------------------------------ // +// Inlines. +// ------------------------------------------------------------------------------------ // + +inline int CBaseEntityList::GetEntInfoIndex( const CEntInfo *pEntInfo ) const +{ + Assert( pEntInfo ); + int index = (int)(pEntInfo - m_EntPtrArray); + Assert( index >= 0 && index < NUM_ENT_ENTRIES ); + return index; +} + +inline CBaseHandle CBaseEntityList::GetNetworkableHandle( int iEntity ) const +{ + Assert( iEntity >= 0 && iEntity < MAX_EDICTS ); + if ( m_EntPtrArray[iEntity].m_pEntity ) + return CBaseHandle( iEntity, m_EntPtrArray[iEntity].m_SerialNumber ); + else + return CBaseHandle(); +} + + +inline IHandleEntity* CBaseEntityList::LookupEntity( const CBaseHandle &handle ) const +{ + if ( handle.m_Index == INVALID_EHANDLE_INDEX ) + return NULL; + + const CEntInfo *pInfo = &m_EntPtrArray[ handle.GetEntryIndex() ]; + if ( pInfo->m_SerialNumber == handle.GetSerialNumber() ) + return (IHandleEntity*)pInfo->m_pEntity; + else + return NULL; +} + + +inline IHandleEntity* CBaseEntityList::LookupEntityByNetworkIndex( int edictIndex ) const +{ + // (Legacy support). + if ( edictIndex < 0 ) + return NULL; + + Assert( edictIndex < NUM_ENT_ENTRIES ); + return (IHandleEntity*)m_EntPtrArray[edictIndex].m_pEntity; +} + + +inline CBaseHandle CBaseEntityList::FirstHandle() const +{ + if ( !m_activeList.Head() ) + return INVALID_EHANDLE_INDEX; + + int index = GetEntInfoIndex( m_activeList.Head() ); + return CBaseHandle( index, m_EntPtrArray[index].m_SerialNumber ); +} + +inline CBaseHandle CBaseEntityList::NextHandle( CBaseHandle hEnt ) const +{ + int iSlot = hEnt.GetEntryIndex(); + CEntInfo *pNext = m_EntPtrArray[iSlot].m_pNext; + if ( !pNext ) + return INVALID_EHANDLE_INDEX; + + int index = GetEntInfoIndex( pNext ); + + return CBaseHandle( index, m_EntPtrArray[index].m_SerialNumber ); +} + +inline CBaseHandle CBaseEntityList::InvalidHandle() +{ + return INVALID_EHANDLE_INDEX; +} + +inline const CEntInfo *CBaseEntityList::FirstEntInfo() const +{ + return m_activeList.Head(); +} + +inline const CEntInfo *CBaseEntityList::NextEntInfo( const CEntInfo *pInfo ) const +{ + return pInfo->m_pNext; +} + +inline const CEntInfo *CBaseEntityList::GetEntInfoPtr( const CBaseHandle &hEnt ) const +{ + int iSlot = hEnt.GetEntryIndex(); + return &m_EntPtrArray[iSlot]; +} + +inline const CEntInfo *CBaseEntityList::GetEntInfoPtrByIndex( int index ) const +{ + return &m_EntPtrArray[index]; +} + +extern CBaseEntityList *g_pEntityList; + +#endif // ENTITYLIST_BASE_H diff --git a/game/shared/entityparticletrail_shared.h b/game/shared/entityparticletrail_shared.h new file mode 100644 index 0000000..5928d16 --- /dev/null +++ b/game/shared/entityparticletrail_shared.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENTITYPARTICLETRAIL_SHARED_H +#define ENTITYPARTICLETRAIL_SHARED_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// For networking this bad boy +//----------------------------------------------------------------------------- +#ifdef CLIENT_DLL +EXTERN_RECV_TABLE( DT_EntityParticleTrailInfo ); +#else +EXTERN_SEND_TABLE( DT_EntityParticleTrailInfo ); +#endif + + +//----------------------------------------------------------------------------- +// Particle trail info +//----------------------------------------------------------------------------- +struct EntityParticleTrailInfo_t +{ + EntityParticleTrailInfo_t(); + + DECLARE_CLASS_NOBASE( EntityParticleTrailInfo_t ); + DECLARE_SIMPLE_DATADESC(); + DECLARE_EMBEDDED_NETWORKVAR(); + + string_t m_strMaterialName; + CNetworkVar( float, m_flLifetime ); + CNetworkVar( float, m_flStartSize ); + CNetworkVar( float, m_flEndSize ); +}; + + + +#endif // ENTITYPARTICLETRAIL_SHARED_H diff --git a/game/shared/env_detail_controller.h b/game/shared/env_detail_controller.h new file mode 100644 index 0000000..d1e87bc --- /dev/null +++ b/game/shared/env_detail_controller.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifdef CLIENT_DLL + #define CEnvDetailController C_EnvDetailController +#endif // CLIENT_DLL + +//----------------------------------------------------------------------------- +// Implementation of the class that controls detail prop fade distances +//----------------------------------------------------------------------------- +class CEnvDetailController : public CBaseEntity +{ +public: + DECLARE_CLASS( CEnvDetailController, CBaseEntity ); + DECLARE_NETWORKCLASS(); + + CEnvDetailController(); + virtual ~CEnvDetailController(); + +#ifndef CLIENT_DLL + virtual bool KeyValue( const char *szKeyName, const char *szValue ); +#endif // !CLIENT_DLL + + CNetworkVar( float, m_flFadeStartDist ); + CNetworkVar( float, m_flFadeEndDist ); + + // ALWAYS transmit to all clients. + virtual int UpdateTransmitState( void ); +}; + +CEnvDetailController * GetDetailController(); diff --git a/game/shared/env_meteor_shared.h b/game/shared/env_meteor_shared.h new file mode 100644 index 0000000..36ecd8c --- /dev/null +++ b/game/shared/env_meteor_shared.h @@ -0,0 +1,202 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENV_METEOR_SHARED_H +#define ENV_METEOR_SHARED_H +#pragma once + +#include "vstdlib/random.h" +#include "mathlib/vector.h" +#include "utlvector.h" + +//============================================================================= +// +// Shared Meteor Class +// +#define METEOR_INVALID_TIME -9999.9f +#define METEOR_PASSIVE_TIME 0.0f +#define METEOR_MAX_LIFETIME 60.0f +#define METEOR_MIN_SIZE Vector( -100, -100, -100 ) +#define METEOR_MAX_SIZE Vector( 100, 100, 100 ) + +#define METEOR_LOCATION_INVALID -1 +#define METEOR_LOCATION_WORLD 0 +#define METEOR_LOCATION_SKYBOX 1 + +class CEnvMeteorShared +{ +public: + + //------------------------------------------------------------------------- + // Initialization. + //------------------------------------------------------------------------- + CEnvMeteorShared(); + void Init( int nID, float flStartTime, float flPassiveTime, + const Vector &vecStartPosition, + const Vector &vecDirection, float flSpeed, float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); + + //------------------------------------------------------------------------- + // Returns the position of the object at a given time. + //------------------------------------------------------------------------- + void GetPositionAtTime( float flTime, Vector &vecPosition ); + + //------------------------------------------------------------------------- + // Changes an objects paramters from "skybox space" to "world space." + //------------------------------------------------------------------------- + void ConvertFromSkyboxToWorld( void ); + + //------------------------------------------------------------------------- + // Changes an objects paramters from "world space" to "skybox space." + //------------------------------------------------------------------------- + void ConvertFromWorldToSkybox( void ); + + //------------------------------------------------------------------------- + // Returns whether or not the object is the the skybox given the time. + //------------------------------------------------------------------------- + bool IsInSkybox( float flTime ); + + //------------------------------------------------------------------------- + // Returns whether or not the object is moving in the skybox (or passive). + //------------------------------------------------------------------------- + bool IsPassive( float flTime ); + + //------------------------------------------------------------------------- + // Returns whether or not the object will ever transition from skybox to world. + //------------------------------------------------------------------------- + bool WillTransition( void ); + + //------------------------------------------------------------------------- + // Returns the splash damage radius of the object. + //------------------------------------------------------------------------- + float GetDamageRadius( void ); + +public: + + int m_nID; // unique identifier + + // The objects initial parametric conditions. + Vector m_vecStartPosition; + Vector m_vecDirection; + float m_flSpeed; // (units/sec), unit = 1 inch + float m_flStartTime; + + // NOTE: All times are absolute - ie m_flStartTime has been added in. + + // The time after the starting time in which it object starts to "move." + float m_flPassiveTime; + + // The enter and exit times define the times at which the object enters and + // exits the world. In other words, m_flEnterTime is the time at which the + // object leaves the skybox and enters the world. m_flExitTime is the opposite. + float m_flWorldEnterTime; + float m_flWorldExitTime; + + float m_flPosTime; // Timer used to find the position of the meteor. + Vector m_vecPos; + + // + int m_nLocation; // 0 = Skybox, 1 = World + + float m_flDamageRadius; // + +private: + + // Calculate the enter/exit times. (called from Init) + void CalcEnterAndExitTimes( const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); +}; + +//============================================================================= +// +// Meteor Factory Interface +// +abstract_class IMeteorFactory +{ +public: + + virtual void CreateMeteor( int nID, int iType, + const Vector &vecPosition, const Vector &vecDirection, + float flSpeed, float flStartTime, float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ) = 0; +}; + +//============================================================================= +// +// Shared Meteor Spawner Class +// +class CEnvMeteorSpawnerShared +{ +public: + DECLARE_CLASS_NOBASE( CEnvMeteorSpawnerShared ); + DECLARE_EMBEDDED_NETWORKVAR(); + + //------------------------------------------------------------------------- + // Initialization. + //------------------------------------------------------------------------- + CEnvMeteorSpawnerShared(); + void Init( IMeteorFactory *pFactory, int nRandomSeed, float flTime, + const Vector &vecMinBounds, const Vector &vecMaxBounds, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); + + //------------------------------------------------------------------------- + // Method to generate meteors. + // Time passed in here is global time, not delta time. + // The function returns the time at which it must be called again. + //------------------------------------------------------------------------- + float MeteorThink( float flTime ); + + //------------------------------------------------------------------------- + // Add meteor target data, used to determine meteor travel direction. + //------------------------------------------------------------------------- + void AddToTargetList( const Vector &vecPosition, float flRadius ); + + // Debugging! + int GetRandomInt( int nMin, int nMax ); + float GetRandomFloat( float flMin, float flMax ); + +public: + + // Factory. + IMeteorFactory *m_pFactory; // Meteor creation factory. + + int m_nMeteorCount; // Number of meteors created - used as IDs + + // Initial spawner data. + CNetworkVar( float, m_flStartTime ); // Start time. + CNetworkVar( int, m_nRandomSeed ); // The random number stream seed. + + CNetworkVar( int, m_iMeteorType ); // Type of meteor. + float m_flMeteorDamageRadius; // Meteor damage radius. + CNetworkVar( bool, m_bSkybox ); // Is the spawner in the skybox? + + CNetworkVar( float, m_flMinSpawnTime ); // Spawn time - Min + CNetworkVar( float, m_flMaxSpawnTime ); // Max + CNetworkVar( int, m_nMinSpawnCount ); // Number of meteors to spawn - Min + CNetworkVar( int, m_nMaxSpawnCount ); // Max + CNetworkVector( m_vecMinBounds ); // Spawner volume (space) - Min + CNetworkVector( m_vecMaxBounds ); // Max + CNetworkVar( float, m_flMinSpeed ); // Meteor speed - Min + CNetworkVar( float, m_flMaxSpeed ); // Max + CNetworkVector( m_vecTriggerMins ); // World Bounds (Trigger) in 3D Skybox - Min + CNetworkVector( m_vecTriggerMaxs ); // Max + Vector m_vecTriggerCenter; + + // Generated data. + int m_nRandomCallCount; // Debug! Keep track of number steam calls. + float m_flNextSpawnTime; // Next meteor spawn time (random). + CUniformRandomStream m_NumberStream; // Used to generate random numbers. + + // Use "Targets" to determine meteor direction(s). + struct meteortarget_t + { + Vector m_vecPosition; + float m_flRadius; + }; + CUtlVector m_aTargets; +}; + +#endif // ENV_METEOR_SHARED_H diff --git a/game/shared/env_wind_shared.h b/game/shared/env_wind_shared.h new file mode 100644 index 0000000..e1084e9 --- /dev/null +++ b/game/shared/env_wind_shared.h @@ -0,0 +1,244 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENV_WIND_SHARED_H +#define ENV_WIND_SHARED_H + +#include "utllinkedlist.h" +#include "vstdlib/random.h" +#include "tier0/dbg.h" +#include "mathlib/vector.h" +#include + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CSoundPatch; + +//----------------------------------------------------------------------------- +// Class used to help store events that occurred over time +//----------------------------------------------------------------------------- +template +class CTimedEventQueue +{ +public: + // The time passed in here represents the amount of time the queue stores + CTimedEventQueue( float flMaxTime ); + + // Adds an event to the queue, will pop off stale events from the queue + // NOTE: All events added to the queue must monotonically increase in time! + I PushEvent( float flTime, const T &data ); + + // Grabs the last event that happened before or at the specified time + I GetEventIndex( float flTime ) const; + + // Gets event information + float GetEventTime( I i ) const; + const T &GetEventData( I i ) const; + +private: + struct QueueEntry_t + { + float m_flTime; + T m_Data; + }; + + float m_flQueueHeadTime; + float m_flMaxTime; + CUtlLinkedList< T, I > m_Queue; +}; + + +//----------------------------------------------------------------------------- +// The time passed in here represents the amount of time the queue stores +//----------------------------------------------------------------------------- +template +CTimedEventQueue::CTimedEventQueue( float flMaxTime ) : m_flMaxTime(flMaxTime) +{ + // The length of time of events in the queue must be reasonable + Assert( m_flMaxTime > 0.0f ); + m_flQueueHeadTime = -FLT_MAX; +} + + +//----------------------------------------------------------------------------- +// Adds an event to the queue, will pop off stale events from the queue +//----------------------------------------------------------------------------- +template +I CTimedEventQueue::PushEvent( float flTime, const T &data ) +{ + Assert( m_flQueueHeadTime <= flTime ); + m_flQueueHeadTime = flTime; + + // First push the event... + I idx = m_Queue.AddToHead(); + m_Queue[idx].m_flTime = flTime; + m_Queue[idx].m_Data = data; + + // Then retire stale events... + I i = m_Queue.Tail(); + while (m_Queue[i].m_flTime < m_flQueueHeadTime - m_flMaxTime ) + { + I prev = m_Queue.Prev(i); + Assert( prev != m_Queue.InvalidIndex() ); + m_Queue.Remove(i); + i = prev; + } + + return idx; +} + + +//----------------------------------------------------------------------------- +// Grabs the last event that happened before or at the specified time +//----------------------------------------------------------------------------- +template +I CTimedEventQueue::GetEventIndex( float flTime ) const +{ + // This checks for a request that fell off the queue + Assert( (flTime >= m_flQueueHeadTime - m_flMaxTime) && (flTime <= m_flQueueHeadTime) ); + + // Then retire stale events... + I i = m_Queue.Head(); + while( m_Queue[i].m_flTime > flTime ) + { + i = m_Queue.Next(i); + Assert( i != m_Queue.InvalidIndex() ); + } + + return i; +} + + +//----------------------------------------------------------------------------- +// Gets event information +//----------------------------------------------------------------------------- +template +inline float CTimedEventQueue::GetEventTime( I i ) const +{ + return m_Queue[i].m_flTime; +} + +template +inline const T &CTimedEventQueue::GetEventData( I i ) const +{ + return m_Queue[i].m_Data; +} + + +//----------------------------------------------------------------------------- +// Implementation of the class that computes windspeed +//----------------------------------------------------------------------------- +class CEnvWindShared +{ +public: + DECLARE_CLASS_NOBASE( CEnvWindShared ); + DECLARE_EMBEDDED_NETWORKVAR(); + + CEnvWindShared(); + ~CEnvWindShared(); + + void Init( int iEntIndex, int iRandomSeed, float flTime, int iWindDir, float flInitialWindSpeed ); + + // Method to update the wind speed + // Time passed in here is global time, not delta time + // The function returns the time at which it must be called again + float WindThink( float flTime ); + + // FIXME: These really should be private + CNetworkVar( float, m_flStartTime ); + + CNetworkVar( int, m_iWindSeed ); // random number seed... + + CNetworkVar( int, m_iMinWind ); // the slowest the wind can normally blow + CNetworkVar( int, m_iMaxWind ); // the fastest the wind can normally blow + CNetworkVar( int, m_iMinGust ); // the slowest that a gust can be + CNetworkVar( int, m_iMaxGust ); // the fastest that a gust can be + + CNetworkVar( float, m_flMinGustDelay ); // min time between gusts + CNetworkVar( float, m_flMaxGustDelay ); // max time between gusts + + CNetworkVar( float, m_flGustDuration ); // max time between gusts + + CNetworkVar( int, m_iGustDirChange ); // max number of degrees wind dir changes on gusts. + int m_iszGustSound; // name of the wind sound to play for gusts. + int m_iWindDir; // wind direction (yaw) + float m_flWindSpeed; // the wind speed + + CNetworkVar( int, m_iInitialWindDir ); + CNetworkVar( float, m_flInitialWindSpeed ); + +#ifndef CLIENT_DLL + COutputEvent m_OnGustStart; + COutputEvent m_OnGustEnd; +#endif + +private: + struct WindAveEvent_t + { + float m_flStartWindSpeed; // the wind speed at the time of the event + float m_flAveWindSpeed; // the average wind speed of the event + }; + + struct WindVariationEvent_t + { + float m_flWindAngleVariation; + float m_flWindSpeedVariation; + }; + + void ComputeWindVariation( float flTime ); + + // Updates the wind sound + void UpdateWindSound( float flTotalWindSpeed ); + + float m_flVariationTime; + float m_flSimTime; // What's the time I last simulated up to? + float m_flSwitchTime; // when do I actually switch from gust to not gust + float m_flAveWindSpeed; // the average wind speed + bool m_bGusting; // is the wind gusting right now? + + float m_flWindAngleVariation; + float m_flWindSpeedVariation; + + int m_iEntIndex; + + // Used to generate random numbers + CUniformRandomStream m_Stream; + + // NOTE: In order to make this algorithm independent of calling frequency + // I have to decouple the stream used to generate average wind speed + // and the stream used to generate wind variation since they are + // simulated using different timesteps + CUniformRandomStream m_WindVariationStream; + + // Used to generate the wind sound... + CSoundPatch *m_pWindSound; + + // Event history required for prediction + CTimedEventQueue< WindAveEvent_t, unsigned short > m_WindAveQueue; + CTimedEventQueue< WindVariationEvent_t, unsigned short > m_WindVariationQueue; + +private: + CEnvWindShared( const CEnvWindShared & ); // not defined, not accessible +}; + + +//----------------------------------------------------------------------------- +// Method to sample the windspeed at a particular time +//----------------------------------------------------------------------------- +void GetWindspeedAtTime( float flTime, Vector &vecVelocity ); + + +//----------------------------------------------------------------------------- +// Method to reset windspeed.. +//----------------------------------------------------------------------------- +void ResetWindspeed(); + + +#endif // ENV_WIND_SHARED_H + diff --git a/game/shared/episodic/npc_advisor_shared.h b/game/shared/episodic/npc_advisor_shared.h new file mode 100644 index 0000000..f275fe8 --- /dev/null +++ b/game/shared/episodic/npc_advisor_shared.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared data between client and server side npc_advisor classes. +// +// Catchphrase: "It's advising us!!!" +// +//=============================================================================// + +#ifndef NPC_ADVISOR_SHARED_H +#define NPC_ADVISOR_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +// Set this to 0 to disable the advisor's special AI behavior (all that object chucking), +// which we did in Ep2 to make him a scripted creature. +#define NPC_ADVISOR_HAS_BEHAVIOR 0 + +#if NPC_ADVISOR_HAS_BEHAVIOR +// Message ID constants used for communciation between client and server. +enum +{ + ADVISOR_MSG_START_BEAM = 10, + ADVISOR_MSG_STOP_BEAM, + ADVISOR_MSG_STOP_ALL_BEAMS, + ADVISOR_MSG_START_ELIGHT, + ADVISOR_MSG_STOP_ELIGHT, +}; +#endif + +#endif // NPC_ADVISOR_SHARED_H diff --git a/game/shared/eventlist.h b/game/shared/eventlist.h new file mode 100644 index 0000000..69c6f0c --- /dev/null +++ b/game/shared/eventlist.h @@ -0,0 +1,120 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EVENTLIST_H +#define EVENTLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#define AE_TYPE_SERVER ( 1 << 0 ) +#define AE_TYPE_SCRIPTED ( 1 << 1 ) // see scriptevent.h +#define AE_TYPE_SHARED ( 1 << 2 ) +#define AE_TYPE_WEAPON ( 1 << 3 ) +#define AE_TYPE_CLIENT ( 1 << 4 ) +#define AE_TYPE_FACEPOSER ( 1 << 5 ) + +#define AE_TYPE_NEWEVENTSYSTEM ( 1 << 10 ) //Temporary flag. + +#define AE_NOT_AVAILABLE -1 + +typedef enum +{ + AE_INVALID = -1, // So we have something more succint to check for than '-1' + AE_EMPTY, + AE_NPC_LEFTFOOT, // #define NPC_EVENT_LEFTFOOT 2050 + AE_NPC_RIGHTFOOT, // #define NPC_EVENT_RIGHTFOOT 2051 + AE_NPC_BODYDROP_LIGHT, //#define NPC_EVENT_BODYDROP_LIGHT 2001 + AE_NPC_BODYDROP_HEAVY, //#define NPC_EVENT_BODYDROP_HEAVY 2002 + AE_NPC_SWISHSOUND, //#define NPC_EVENT_SWISHSOUND 2010 + AE_NPC_180TURN, //#define NPC_EVENT_180TURN 2020 + AE_NPC_ITEM_PICKUP, //#define NPC_EVENT_ITEM_PICKUP 2040 + AE_NPC_WEAPON_DROP, //#define NPC_EVENT_WEAPON_DROP 2041 + AE_NPC_WEAPON_SET_SEQUENCE_NAME, //#define NPC_EVENT_WEAPON_SET_SEQUENCE_NAME 2042 + AE_NPC_WEAPON_SET_SEQUENCE_NUMBER, //#define NPC_EVENT_WEAPON_SET_SEQUENCE_NUMBER 2043 + AE_NPC_WEAPON_SET_ACTIVITY, //#define NPC_EVENT_WEAPON_SET_ACTIVITY 2044 + AE_NPC_HOLSTER, + AE_NPC_DRAW, + AE_NPC_WEAPON_FIRE, + + AE_CL_PLAYSOUND, // #define CL_EVENT_SOUND 5004 // Emit a sound + AE_SV_PLAYSOUND, + AE_CL_STOPSOUND, + + AE_START_SCRIPTED_EFFECT, + AE_STOP_SCRIPTED_EFFECT, + + AE_CLIENT_EFFECT_ATTACH, + + AE_MUZZLEFLASH, // Muzzle flash from weapons held by the player + AE_NPC_MUZZLEFLASH, // Muzzle flash from weapons held by NPCs + + AE_THUMPER_THUMP, //Thumper Thump! + AE_AMMOCRATE_PICKUP_AMMO, //Ammo crate pick up ammo! + + AE_NPC_RAGDOLL, + + AE_NPC_ADDGESTURE, + AE_NPC_RESTARTGESTURE, + + AE_NPC_ATTACK_BROADCAST, + + AE_NPC_HURT_INTERACTION_PARTNER, + AE_NPC_SET_INTERACTION_CANTDIE, + + AE_SV_DUSTTRAIL, + + AE_CL_CREATE_PARTICLE_EFFECT, + + AE_RAGDOLL, + + AE_CL_ENABLE_BODYGROUP, + AE_CL_DISABLE_BODYGROUP, + AE_CL_BODYGROUP_SET_VALUE, + AE_CL_BODYGROUP_SET_VALUE_CMODEL_WPN, + + AE_WPN_PRIMARYATTACK, // Used by weapons that want their primary attack to occur during an attack anim (i.e. grenade throwing) + AE_WPN_INCREMENTAMMO, + + AE_WPN_HIDE, // Used to hide player weapons + AE_WPN_UNHIDE, // Used to unhide player weapons + + AE_WPN_PLAYWPNSOUND, // Play a weapon sound from the weapon script file + + AE_RD_ROBOT_POP_PANELS_OFF, + + AE_TAUNT_ENABLE_MOVE, + AE_TAUNT_DISABLE_MOVE, + + LAST_SHARED_ANIMEVENT, +} Animevent; + + +typedef struct evententry_s evententry_t; + +//========================================================= +//========================================================= +extern void EventList_Init( void ); +extern void EventList_Free( void ); +extern bool EventList_RegisterSharedEvent( const char *pszEventName, int iEventIndex, int iType = 0 ); +extern Animevent EventList_RegisterPrivateEvent( const char *pszEventName ); +extern int EventList_IndexForName( const char *pszEventName ); +extern const char *EventList_NameForIndex( int iEventIndex ); +Animevent EventList_RegisterPrivateEvent( const char *pszEventName ); + +// This macro guarantees that the names of each event and the constant used to +// reference it in the code are identical. +#define REGISTER_SHARED_ANIMEVENT( _n, b ) EventList_RegisterSharedEvent(#_n, _n, b ); +#define REGISTER_PRIVATE_ANIMEVENT( _n ) _n = EventList_RegisterPrivateEvent( #_n ); + +// Implemented in shared code +extern void EventList_RegisterSharedEvents( void ); +extern int EventList_GetEventType( int eventIndex ); + + + +#endif // EVENTLIST_H diff --git a/game/shared/expressionsample.h b/game/shared/expressionsample.h new file mode 100644 index 0000000..006db6d --- /dev/null +++ b/game/shared/expressionsample.h @@ -0,0 +1,142 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EXPRESSIONSAMPLE_H +#define EXPRESSIONSAMPLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interpolatortypes.h" + +class CUtlBuffer; +class ISceneTokenProcessor; +class IChoreoStringPool; + +#pragma pack(1) +struct EdgeInfo_t +{ + EdgeInfo_t() : + m_bActive( false ), + m_CurveType( CURVE_DEFAULT ), + m_flZeroPos( 0.0f ) + { + } + + bool m_bActive; + unsigned short m_CurveType; + float m_flZeroPos; +}; + +struct CExpressionSample +{ + CExpressionSample() : + value( 0.0f ), + time( 0.0f ) + { + selected = 0; + m_curvetype = CURVE_DEFAULT; + } + + void SetCurveType( int curveType ) + { + m_curvetype = curveType; + } + + int GetCurveType() const + { + return m_curvetype; + } + + // Height + float value; + // time from start of event + float time; + + unsigned short selected : 1; +private: + unsigned short m_curvetype : 15; +}; +#pragma pack() + +//----------------------------------------------------------------------------- +// Purpose: Provides generic access to scene or event ramp data +//----------------------------------------------------------------------------- +class ICurveDataAccessor +{ +public: + virtual ~ICurveDataAccessor(){} + virtual float GetDuration() = 0; + virtual bool CurveHasEndTime() = 0; // only matters for events + virtual int GetDefaultCurveType() = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: The generic curve data +//----------------------------------------------------------------------------- + +class CCurveData +{ +public: + int GetCount( void ); + CExpressionSample *Get( int index ); + CExpressionSample *Add( float time, float value, bool selected ); + void Delete( int index ); + void Clear( void ); + void Resort( ICurveDataAccessor *data ); + + EdgeInfo_t *GetEdgeInfo( int idx ); + + void SetEdgeInfo( bool leftEdge, int curveType, float zero ); + void GetEdgeInfo( bool leftEdge, int& curveType, float& zero ) const; + void SetEdgeActive( bool leftEdge, bool state ); + bool IsEdgeActive( bool leftEdge ) const; + int GetEdgeCurveType( bool leftEdge ) const; + float GetEdgeZeroValue( bool leftEdge ) const; + void RemoveOutOfRangeSamples( ICurveDataAccessor *data ); + + void SaveToBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool ); + bool RestoreFromBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool ); + + void Parse( ISceneTokenProcessor *tokenizer, ICurveDataAccessor *data ); + void FileSave( CUtlBuffer& buf, int level, const char *name ); + + float GetIntensity( ICurveDataAccessor *data, float time ); + CExpressionSample *GetBoundedSample( ICurveDataAccessor *data, int number, bool& bClamped ); + + CCurveData & operator = (const CCurveData &src) + { + // Copy ramp over + m_Ramp.RemoveAll(); + int i; + for ( i = 0; i < src.m_Ramp.Count(); i++ ) + { + CExpressionSample sample = src.m_Ramp[ i ]; + CExpressionSample *newSample = Add( sample.time, sample.value, sample.selected ); + newSample->SetCurveType( sample.GetCurveType() ); + } + m_RampEdgeInfo[ 0 ] = src.m_RampEdgeInfo[ 0 ]; + m_RampEdgeInfo[ 1 ] = src.m_RampEdgeInfo[ 1 ]; + + return *this; + + }; + +private: + CUtlVector< CExpressionSample > m_Ramp; + EdgeInfo_t m_RampEdgeInfo[ 2 ]; + +public: + float GetIntensityArea( ICurveDataAccessor *data, float time ); + +private: + void UpdateIntensityArea( ICurveDataAccessor *data ); + CUtlVector< float > m_RampAccumulator; +}; + + +#endif // EXPRESSIONSAMPLE_H diff --git a/game/shared/forcefeedback.h b/game/shared/forcefeedback.h new file mode 100644 index 0000000..353cfcf --- /dev/null +++ b/game/shared/forcefeedback.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef FORCEFEEDBACK_H +#define FORCEFEEDBACK_H +#ifdef _WIN32 +#pragma once +#endif + +enum +{ + FFMSG_START = 0, + FFMSG_STOP, + FFMSG_STOPALL, + FFMSG_PAUSE, + FFMSG_RESUME +}; + +typedef enum +{ + FORCE_FEEDBACK_SHOT_SINGLE, + FORCE_FEEDBACK_SHOT_DOUBLE, + + FORCE_FEEDBACK_TAKEDAMAGE, + + FORCE_FEEDBACK_SCREENSHAKE, + + FORCE_FEEDBACK_SKIDDING, + FORCE_FEEDBACK_BREAKING, + + NUM_FORCE_FEEDBACK_PRESETS +} FORCEFEEDBACK_t; + +class CBasePlayer; + +struct FFBaseParams_t +{ + FFBaseParams_t() : + m_flDirection( 0.0f ), + m_flDuration( 0.0f ), + m_flGain( 1.0f ), + m_nPriority( 0 ), + m_bSolo( false ) + { + } + + float m_flDirection; // yaw + float m_flDuration; // seconds (-1 == INFINITE, 0.0 == use duration from .ffe file) + float m_flGain; // 0 -> 1 global scale + int m_nPriority; // Higher is more important + bool m_bSolo; // Temporarily suppress all other FF effects while playing +}; + +abstract_class IForceFeedback +{ +public: + // API + virtual void StopAllEffects( CBasePlayer *player ) = 0; + virtual void StopEffect( CBasePlayer *player, FORCEFEEDBACK_t effect ) = 0; + virtual void StartEffect( CBasePlayer *player, FORCEFEEDBACK_t effect, const FFBaseParams_t& params ) = 0; + + virtual void PauseAll( CBasePlayer *player ) = 0; + virtual void ResumeAll( CBasePlayer *player ) = 0; +}; + +extern IForceFeedback *forcefeedback; + +#endif // FORCEFEEDBACK_H diff --git a/game/shared/func_dust_shared.h b/game/shared/func_dust_shared.h new file mode 100644 index 0000000..5c0c2ba --- /dev/null +++ b/game/shared/func_dust_shared.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FUNC_DUST_SHARED_H +#define FUNC_DUST_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +// Flags for m_DustFlags. +#define DUSTFLAGS_ON (1<<0) // emit particles.. +#define DUSTFLAGS_SCALEMOTES (1<<1) // scale to keep the same size on screen +#define DUSTFLAGS_FROZEN (1<<2) // just emit m_SpawnRate # of particles and freeze +#define DUST_NUMFLAGS 3 + + +#endif // FUNC_DUST_SHARED_H diff --git a/game/shared/func_ladder.h b/game/shared/func_ladder.h new file mode 100644 index 0000000..914389d --- /dev/null +++ b/game/shared/func_ladder.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FUNC_LADDER_H +#define FUNC_LADDER_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) +#define CFuncLadder C_FuncLadder +#define CInfoLadderDismount C_InfoLadderDismount +#endif + +class CInfoLadderDismount : public CBaseEntity +{ +public: + DECLARE_CLASS( CInfoLadderDismount, CBaseEntity ); + DECLARE_NETWORKCLASS(); + + virtual void DrawDebugGeometryOverlays(); +}; + +typedef CHandle< CInfoLadderDismount > CInfoLadderDismountHandle; + +// Spawnflags +#define SF_LADDER_DONTGETON 1 // Set for ladders that are acting as automount points, but not really ladders + +//----------------------------------------------------------------------------- +// Purpose: A player-climbable ladder +//----------------------------------------------------------------------------- +class CFuncLadder : public CBaseEntity +{ +public: + + DECLARE_CLASS( CFuncLadder, CBaseEntity ); + DECLARE_NETWORKCLASS(); + DECLARE_DATADESC(); + + CFuncLadder(); + ~CFuncLadder(); + + virtual void Spawn(); + + virtual void DrawDebugGeometryOverlays(void); + + int GetDismountCount() const; + CInfoLadderDismount *GetDismount( int index ); + + void GetTopPosition( Vector& org ); + void GetBottomPosition( Vector& org ); + void ComputeLadderDir( Vector& bottomToTopVec ); + + void SetEndPoints( const Vector& p1, const Vector& p2 ); + + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + + bool IsEnabled() const; + + void PlayerGotOn( CBasePlayer *pPlayer ); + void PlayerGotOff( CBasePlayer *pPlayer ); + + virtual void Activate(); + + bool DontGetOnLadder( void ) const; + + static int GetLadderCount(); + static CFuncLadder *GetLadder( int index ); + static CUtlVector< CFuncLadder * > s_Ladders; +public: + + void FindNearbyDismountPoints( const Vector& origin, float radius, CUtlVector< CInfoLadderDismountHandle >& list ); + const char *GetSurfacePropName(); + +private: + + + void SearchForDismountPoints(); + + // Movement vector from "bottom" to "top" of ladder + CNetworkVector( m_vecLadderDir ); + + // Dismount points near top/bottom of ladder, precomputed + CUtlVector< CInfoLadderDismountHandle > m_Dismounts; + + // Endpoints for checking for mount/dismount + CNetworkVector( m_vecPlayerMountPositionTop ); + CNetworkVector( m_vecPlayerMountPositionBottom ); + + bool m_bDisabled; + CNetworkVar( bool, m_bFakeLadder ); + +#if defined( GAME_DLL ) + string_t m_surfacePropName; + //----------------------------------------------------- + // Outputs + //----------------------------------------------------- + COutputEvent m_OnPlayerGotOnLadder; + COutputEvent m_OnPlayerGotOffLadder; + + virtual int UpdateTransmitState(); +#endif +}; + +inline bool CFuncLadder::IsEnabled() const +{ + return !m_bDisabled; +} + +const char *FuncLadder_GetSurfaceprops(CBaseEntity *pLadderEntity); + +#endif // FUNC_LADDER_H diff --git a/game/shared/gameeventdefs.h b/game/shared/gameeventdefs.h new file mode 100644 index 0000000..c0de1dd --- /dev/null +++ b/game/shared/gameeventdefs.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GAMEEVENTDEFS_H +#define GAMEEVENTDEFS_H + +#ifdef _WIN32 +#pragma once +#endif + +// Make sure your gameevents.res and this file is in sync +// Event names may be 32 characters long and are case sensitive +// 256 is the maximum number of game events + +#define GAME_EVENT_PLAYER_DEATH "player_death" +#define GAME_EVENT_SAY_TEXT "say_text" + +#endif // GAMEEVENTDEFS_H \ No newline at end of file diff --git a/game/shared/gamemovement.h b/game/shared/gamemovement.h new file mode 100644 index 0000000..79c83fc --- /dev/null +++ b/game/shared/gamemovement.h @@ -0,0 +1,291 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( GAMEMOVEMENT_H ) +#define GAMEMOVEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igamemovement.h" +#include "cmodel.h" +#include "tier0/vprof.h" + +#define CTEXTURESMAX 512 // max number of textures loaded +#define CBTEXTURENAMEMAX 13 // only load first n chars of name + +#define GAMEMOVEMENT_DUCK_TIME 1000.0f // ms +#define GAMEMOVEMENT_JUMP_TIME 510.0f // ms approx - based on the 21 unit height jump +#define GAMEMOVEMENT_JUMP_HEIGHT 21.0f // units +#define GAMEMOVEMENT_TIME_TO_UNDUCK ( TIME_TO_UNDUCK * 1000.0f ) // ms +#define GAMEMOVEMENT_TIME_TO_UNDUCK_INV ( GAMEMOVEMENT_DUCK_TIME - GAMEMOVEMENT_TIME_TO_UNDUCK ) + +enum +{ + SPEED_CROPPED_RESET = 0, + SPEED_CROPPED_DUCK = 1, + SPEED_CROPPED_WEAPON = 2, +}; + +struct surfacedata_t; + +class CBasePlayer; + +class CGameMovement : public IGameMovement +{ +public: + DECLARE_CLASS_NOBASE( CGameMovement ); + + CGameMovement( void ); + virtual ~CGameMovement( void ); + + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ); + + virtual void StartTrackPredictionErrors( CBasePlayer *pPlayer ); + virtual void FinishTrackPredictionErrors( CBasePlayer *pPlayer ); + virtual void DiffPrint( PRINTF_FORMAT_STRING char const *fmt, ... ); + virtual Vector GetPlayerMins( bool ducked ) const; + virtual Vector GetPlayerMaxs( bool ducked ) const; + virtual Vector GetPlayerViewOffset( bool ducked ) const; + +// For sanity checking getting stuck on CMoveData::SetAbsOrigin + virtual void TracePlayerBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ); + + // allows derived classes to exclude entities from trace + virtual void TryTouchGround( const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, unsigned int fMask, int collisionGroup, trace_t& pm ); + + +#define BRUSH_ONLY true + virtual unsigned int PlayerSolidMask( bool brushOnly = false ); ///< returns the solid mask for the given player, so bots can have a more-restrictive set + CBasePlayer *player; + CMoveData *GetMoveData() { return mv; } +protected: + // Input/Output for this movement + CMoveData *mv; + + int m_nOldWaterLevel; + float m_flWaterEntryTime; + int m_nOnLadder; + + Vector m_vecForward; + Vector m_vecRight; + Vector m_vecUp; + + + // Does most of the player movement logic. + // Returns with origin, angles, and velocity modified in place. + // were contacted during the move. + virtual void PlayerMove( void ); + + // Set ground data, etc. + void FinishMove( void ); + + virtual float CalcRoll( const QAngle &angles, const Vector &velocity, float rollangle, float rollspeed ); + + virtual void DecayPunchAngle( void ); + + virtual void CheckWaterJump(void ); + + virtual void WaterMove( void ); + + void WaterJump( void ); + + // Handles both ground friction and water friction + void Friction( void ); + + virtual void AirAccelerate( Vector& wishdir, float wishspeed, float accel ); + + virtual void AirMove( void ); + virtual float GetAirSpeedCap( void ) { return 30.f; } + + virtual bool CanAccelerate(); + virtual void Accelerate( Vector& wishdir, float wishspeed, float accel); + + // Only used by players. Moves along the ground when player is a MOVETYPE_WALK. + virtual void WalkMove( void ); + + // Try to keep a walking player on the ground when running down slopes etc + void StayOnGround( void ); + + // Handle MOVETYPE_WALK. + virtual void FullWalkMove(); + + // allow overridden versions to respond to jumping + virtual void OnJump( float fImpulse ) {} + virtual void OnLand( float fVelocity ) {} + + // Implement this if you want to know when the player collides during OnPlayerMove + virtual void OnTryPlayerMoveCollision( trace_t &tr ) {} + + virtual Vector GetPlayerMins( void ) const; // uses local player + virtual Vector GetPlayerMaxs( void ) const; // uses local player + + typedef enum + { + GROUND = 0, + STUCK, + LADDER + } IntervalType_t; + + virtual int GetCheckInterval( IntervalType_t type ); + + // Useful for things that happen periodically. This lets things happen on the specified interval, but + // spaces the events onto different frames for different players so they don't all hit their spikes + // simultaneously. + bool CheckInterval( IntervalType_t type ); + + + // Decompoosed gravity + void StartGravity( void ); + void FinishGravity( void ); + + // Apply normal ( undecomposed ) gravity + void AddGravity( void ); + + // Handle movement in noclip mode. + void FullNoClipMove( float factor, float maxacceleration ); + + // Returns true if he started a jump (ie: should he play the jump animation)? + virtual bool CheckJumpButton( void ); // Overridden by each game. + + // Dead player flying through air., e.g. + virtual void FullTossMove( void ); + + // Player is a Observer chasing another player + void FullObserverMove( void ); + + // Handle movement when in MOVETYPE_LADDER mode. + virtual void FullLadderMove(); + + // The basic solid body movement clip that slides along multiple planes + virtual int TryPlayerMove( Vector *pFirstDest=NULL, trace_t *pFirstTrace=NULL ); + + virtual bool LadderMove( void ); + virtual bool OnLadder( trace_t &trace ); + virtual float LadderDistance( void ) const { return 2.0f; } ///< Returns the distance a player can be from a ladder and still attach to it + virtual unsigned int LadderMask( void ) const { return MASK_PLAYERSOLID; } + virtual float ClimbSpeed( void ) const { return MAX_CLIMB_SPEED; } + virtual float LadderLateralMultiplier( void ) const { return 1.0f; } + + // See if the player has a bogus velocity value. + void CheckVelocity( void ); + + // Does not change the entities velocity at all + void PushEntity( Vector& push, trace_t *pTrace ); + + // Slide off of the impacting object + // returns the blocked flags: + // 0x01 == floor + // 0x02 == step / wall + int ClipVelocity( Vector& in, Vector& normal, Vector& out, float overbounce ); + + // If pmove.origin is in a solid position, + // try nudging slightly on all axis to + // allow for the cut precision of the net coordinates + virtual int CheckStuck( void ); + + // Check if the point is in water. + // Sets refWaterLevel and refWaterType appropriately. + // If in water, applies current to baseVelocity, and returns true. + virtual bool CheckWater( void ); + + // Determine if player is in water, on ground, etc. + virtual void CategorizePosition( void ); + + virtual void CheckParameters( void ); + + virtual void ReduceTimers( void ); + + virtual void CheckFalling( void ); + + virtual void PlayerRoughLandingEffects( float fvol ); + + void PlayerWaterSounds( void ); + + void ResetGetPointContentsCache(); + int GetPointContentsCached( const Vector &point, int slot ); + + // Ducking + virtual void Duck( void ); + virtual void HandleDuckingSpeedCrop(); + virtual void FinishUnDuck( void ); + virtual void FinishDuck( void ); + virtual bool CanUnduck(); + void UpdateDuckJumpEyeOffset( void ); + bool CanUnDuckJump( trace_t &trace ); + void StartUnDuckJump( void ); + void FinishUnDuckJump( trace_t &trace ); + void SetDuckedEyeOffset( float duckFraction ); + void FixPlayerCrouchStuck( bool moveup ); + + float SplineFraction( float value, float scale ); + + void CategorizeGroundSurface( trace_t &pm ); + + bool InWater( void ); + + // Commander view movement + void IsometricMove( void ); + + // Traces the player bbox as it is swept from start to end + virtual CBaseHandle TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ); + + // Checks to see if we should actually jump + void PlaySwimSound(); + + bool IsDead( void ) const; + + // Figures out how the constraint should slow us down + float ComputeConstraintSpeedFactor( void ); + + virtual void SetGroundEntity( trace_t *pm ); + + virtual void StepMove( Vector &vecDestination, trace_t &trace ); + + // when we step on ground that's too steep, search to see if there's any ground nearby that isn't too steep + void TryTouchGroundInQuadrants( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ); + + +protected: + + // Performs the collision resolution for fliers. + void PerformFlyCollisionResolution( trace_t &pm, Vector &move ); + + virtual bool GameHasLadders() const; + + enum + { + // eyes, waist, feet points (since they are all deterministic + MAX_PC_CACHE_SLOTS = 3, + }; + + // Cache used to remove redundant calls to GetPointContents(). + int m_CachedGetPointContents[ MAX_PLAYERS ][ MAX_PC_CACHE_SLOTS ]; + Vector m_CachedGetPointContentsPoint[ MAX_PLAYERS ][ MAX_PC_CACHE_SLOTS ]; + + Vector m_vecProximityMins; // Used to be globals in sv_user.cpp. + Vector m_vecProximityMaxs; + + float m_fFrameTime; + +//private: + int m_iSpeedCropped; + + float m_flStuckCheckTime[MAX_PLAYERS+1][2]; // Last time we did a full test + + // special function for teleport-with-duck for episodic +#ifdef HL2_EPISODIC +public: + void ForceDuck( void ); + +#endif +}; + + + +#endif // GAMEMOVEMENT_H diff --git a/game/shared/gamerules.h b/game/shared/gamerules.h new file mode 100644 index 0000000..5ba6682 --- /dev/null +++ b/game/shared/gamerules.h @@ -0,0 +1,452 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GAMERULES_H +#define GAMERULES_H +#ifdef _WIN32 +#pragma once +#endif + +// Debug history should be disabled in release builds +//#define DISABLE_DEBUG_HISTORY + +#ifdef CLIENT_DLL + + #include "c_baseentity.h" + + #define CGameRules C_GameRules + #define CGameRulesProxy C_GameRulesProxy + +#else + + #include "baseentity.h" + #include "recipientfilter.h" + +#endif + +#include "igamesystem.h" +#include "gamerules_register.h" + + +//#include "items.h" +class CBaseCombatWeapon; +class CBaseCombatCharacter; +class CBasePlayer; +class CItem; +class CAmmoDef; +class CTacticalMissionManager; + +extern ConVar sk_autoaim_mode; + +// Autoaiming modes +enum +{ + AUTOAIM_NONE = 0, // No autoaim at all. + AUTOAIM_ON, // Autoaim is on. + AUTOAIM_ON_CONSOLE, // Autoaim is on, including enhanced features for Console gaming (more assistance, etc) +}; + +// weapon respawning return codes +enum +{ + GR_NONE = 0, + + GR_WEAPON_RESPAWN_YES, + GR_WEAPON_RESPAWN_NO, + + GR_AMMO_RESPAWN_YES, + GR_AMMO_RESPAWN_NO, + + GR_ITEM_RESPAWN_YES, + GR_ITEM_RESPAWN_NO, + + GR_PLR_DROP_GUN_ALL, + GR_PLR_DROP_GUN_ACTIVE, + GR_PLR_DROP_GUN_NO, + + GR_PLR_DROP_AMMO_ALL, + GR_PLR_DROP_AMMO_ACTIVE, + GR_PLR_DROP_AMMO_NO, +}; + +// Player relationship return codes +enum +{ + GR_NOTTEAMMATE = 0, + GR_TEAMMATE, + GR_ENEMY, + GR_ALLY, + GR_NEUTRAL, +}; + + +// This class has the data tables and gets the CGameRules data to the client. +class CGameRulesProxy : public CBaseEntity +{ +public: + DECLARE_CLASS( CGameRulesProxy, CBaseEntity ); + DECLARE_NETWORKCLASS(); + + CGameRulesProxy(); + ~CGameRulesProxy(); + + // UNDONE: Is this correct, Mike? + // Don't carry these across a transition, they are recreated. + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + // ALWAYS transmit to all clients. + virtual int UpdateTransmitState( void ); + + // CGameRules chains its NetworkStateChanged calls to here, since this + // is the actual entity that will send the data. + static void NotifyNetworkStateChanged(); + +private: + + static CGameRulesProxy *s_pGameRulesProxy; +}; + + +abstract_class CGameRules : public CAutoGameSystemPerFrame +{ +public: + DECLARE_CLASS_GAMEROOT( CGameRules, CAutoGameSystemPerFrame ); + + virtual char const *Name() { return "CGameRules"; } + + // Stuff shared between client and server. + + CGameRules(void); + virtual ~CGameRules( void ); + + // Damage Queries - these need to be implemented by the various subclasses (single-player, multi-player, etc). + // The queries represent queries against damage types and properties. + virtual bool Damage_IsTimeBased( int iDmgType ) = 0; // Damage types that are time-based. + virtual bool Damage_ShouldGibCorpse( int iDmgType ) = 0; // Damage types that gib the corpse. + virtual bool Damage_ShowOnHUD( int iDmgType ) = 0; // Damage types that have client HUD art. + virtual bool Damage_NoPhysicsForce( int iDmgType ) = 0; // Damage types that don't have to supply a physics force & position. + virtual bool Damage_ShouldNotBleed( int iDmgType ) = 0; // Damage types that don't make the player bleed. + //Temp: These will go away once DamageTypes become enums. + virtual int Damage_GetTimeBased( void ) = 0; // Actual bit-fields. + virtual int Damage_GetShouldGibCorpse( void ) = 0; + virtual int Damage_GetShowOnHud( void ) = 0; + virtual int Damage_GetNoPhysicsForce( void )= 0; + virtual int Damage_GetShouldNotBleed( void ) = 0; + +// Ammo Definitions + //CAmmoDef* GetAmmoDef(); + + virtual bool SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); // Switch to the next best weapon + virtual CBaseCombatWeapon *GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); // I can't use this weapon anymore, get me the next best one. + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + + virtual int DefaultFOV( void ) { return 90; } + + // This function is here for our CNetworkVars. + inline void NetworkStateChanged() + { + // Forward the call to the entity that will send the data. + CGameRulesProxy::NotifyNetworkStateChanged(); + } + + inline void NetworkStateChanged( void *pVar ) + { + // Forward the call to the entity that will send the data. + CGameRulesProxy::NotifyNetworkStateChanged(); + } + + // Get the view vectors for this mod. + virtual const CViewVectors* GetViewVectors() const; + +// Damage rules for ammo types + virtual float GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ); + virtual float GetDamageMultiplier( void ) { return 1.0f; } + +// Functions to verify the single/multiplayer status of a game + virtual bool IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) + + virtual const unsigned char *GetEncryptionKey() { return NULL; } + + virtual bool InRoundRestart( void ) { return false; } + + //Allow thirdperson camera. + virtual bool AllowThirdPersonCamera( void ) { return false; } + + virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ) {} + + // IsConnectedUserInfoChangeAllowed allows the clients to change + // cvars with the FCVAR_NOT_CONNECTED rule if it returns true + virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer ) + { + Assert( !IsMultiplayer() ); + return true; + } + +#ifdef CLIENT_DLL + + virtual bool IsBonusChallengeTimeBased( void ); + + virtual bool AllowMapParticleEffect( const char *pszParticleEffect ) { return true; } + + virtual bool AllowWeatherParticles( void ) { return true; } + + virtual bool AllowMapVisionFilterShaders( void ) { return false; } + virtual const char* TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName ) { return pchEffectName; } + + virtual bool IsLocalPlayer( int nEntIndex ); + + virtual void ModifySentChat( char *pBuf, int iBufSize ) { return; } + + virtual bool ShouldWarnOfAbandonOnQuit() { return false; } + +#else + + virtual void Status( void (*print) (const char *fmt, ...) ) {} + + virtual void GetTaggedConVarList( KeyValues *pCvarTagList ) {} + + // NVNT see if the client of the player entered is using a haptic device. + virtual void CheckHaptics(CBasePlayer* pPlayer); + +// CBaseEntity overrides. +public: + +// Setup + + // Called when game rules are destroyed by CWorld + virtual void LevelShutdown( void ) { return; }; + + virtual void Precache( void ) { return; }; + + virtual void RefreshSkillData( bool forceUpdate );// fill skill data struct with proper values + + // Called each frame. This just forwards the call to Think(). + virtual void FrameUpdatePostEntityThink(); + + virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. + virtual bool IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg NPCs don't spawn in deathmatch). + + // Called at the end of GameFrame (i.e. after all game logic has run this frame) + virtual void EndGameFrame( void ); + + virtual bool IsSkillLevel( int iLevel ) { return GetSkillLevel() == iLevel; } + virtual int GetSkillLevel() { return g_iSkillLevel; } + virtual void OnSkillLevelChanged( int iNewLevel ) {}; + virtual void SetSkillLevel( int iLevel ) + { + int oldLevel = g_iSkillLevel; + + if ( iLevel < 1 ) + { + iLevel = 1; + } + else if ( iLevel > 3 ) + { + iLevel = 3; + } + + g_iSkillLevel = iLevel; + + if( g_iSkillLevel != oldLevel ) + { + OnSkillLevelChanged( g_iSkillLevel ); + } + } + + virtual bool FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? + virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ) = 0;// should the player switch to this weapon? + +// Functions to verify the single/multiplayer status of a game + virtual bool IsDeathmatch( void ) = 0;//is this a deathmatch game? + virtual bool IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? + virtual bool IsCoOp( void ) = 0;// is this a coop game? + virtual const char *GetGameDescription( void ) { return "Half-Life 2"; } // this is the game name that gets seen in the server browser + +// Client connection/disconnection + virtual bool ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) = 0;// a client just connected to the server (player hasn't spawned yet) + virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? + virtual bool FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker, const CTakeDamageInfo &info ) {return TRUE;};// can this player take damage from this attacker? + virtual bool ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } + virtual float GetAutoAimScale( CBasePlayer *pPlayer ) { return 1.0f; } + virtual int GetAutoAimMode() { return AUTOAIM_ON; } + + virtual bool ShouldUseRobustRadiusDamage(CBaseEntity *pEntity) { return false; } + virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ); + // Let the game rules specify if fall death should fade screen to black + virtual bool FlPlayerFallDeathDoesScreenFade( CBasePlayer *pl ) { return TRUE; } + + virtual bool AllowDamage( CBaseEntity *pVictim, const CTakeDamageInfo &info ) = 0; + + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game + virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted + virtual bool FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? + virtual CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. + virtual bool IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer ); + + virtual bool AllowAutoTargetCrosshair( void ) { return TRUE; }; + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); // handles the user commands; returns TRUE if command handled properly + virtual void ClientSettingsChanged( CBasePlayer *pPlayer ); // the player has changed cvars + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? + virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ) = 0;// Called each time a player dies + virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )= 0;// Call this from within a GameRules class to report an obituary. + virtual const char *GetDamageCustomString( const CTakeDamageInfo &info ) { return NULL; } + +// Weapon Damage + // Determines how much damage Player's attacks inflict, based on skill level. + virtual float AdjustPlayerDamageInflicted( float damage ) { return damage; } + virtual void AdjustPlayerDamageTaken( CTakeDamageInfo *pInfo ) {}; // Base class does nothing. + +// Weapon retrieval + virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );// The player is touching an CBaseCombatWeapon, do I give it to him? + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon ) = 0;// should this weapon respawn? + virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ) = 0;// when may this weapon respawn? + virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? + virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon ) = 0;// where in the world should this weapon respawn? + +// Item retrieval + virtual bool CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item? + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit) + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn? + virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn? + virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn? + virtual QAngle VecItemRespawnAngles( CItem *pItem ) = 0;// what angles should this item use when respawing? + +// Ammo retrieval + virtual bool CanHaveAmmo( CBaseCombatCharacter *pPlayer, int iAmmoIndex ); // can this player take more of this ammo? + virtual bool CanHaveAmmo( CBaseCombatCharacter *pPlayer, const char *szName ); + virtual void PlayerGotAmmo( CBaseCombatCharacter *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world + virtual float GetAmmoQuantityScale( int iAmmoIndex ) { return 1.0f; } + +// AI Definitions + virtual void InitDefaultAIRelationships( void ) { return; } + virtual const char* AIClassText(int classType) { return NULL; } + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? + virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on? + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? + virtual bool PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker ) = 0; + virtual void CheckChatText( CBasePlayer *pPlayer, char *pText ) { return; } + + virtual int GetTeamIndex( const char *pTeamName ) { return -1; } + virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } + virtual bool IsValidTeam( const char *pTeamName ) { return true; } + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, bool bKill, bool bGib ) {} + virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } + virtual void UpdateClientData( CBasePlayer *pPlayer ) { }; + +// Sounds + virtual bool PlayTextureSounds( void ) { return TRUE; } + virtual bool PlayFootstepSounds( CBasePlayer *pl ) { return TRUE; } + +// NPCs + virtual bool FAllowNPCs( void ) = 0;//are NPCs allowed + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) {} + + // trace line rules + virtual float WeaponTraceEntity( CBaseEntity *pEntity, const Vector &vecStart, const Vector &vecEnd, unsigned int mask, trace_t *ptr ); + + // Setup g_pPlayerResource (some mods use a different entity type here). + virtual void CreateStandardEntities(); + + // Team name, etc shown in chat and dedicated server console + virtual const char *GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ); + + // Location name shown in chat + virtual const char *GetChatLocation( bool bTeamOnly, CBasePlayer *pPlayer ) { return NULL; } + + // VGUI format string for chat, if desired + virtual const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer ) { return NULL; } + + // Whether props that are on fire should get a DLIGHT. + virtual bool ShouldBurningPropsEmitLight() { return false; } + + virtual bool CanEntityBeUsePushed( CBaseEntity *pEnt ) { return true; } + + virtual void CreateCustomNetworkStringTables( void ) { } + + // Game Achievements (server version) + virtual void MarkAchievement ( IRecipientFilter& filter, char const *pchAchievementName ); + + virtual void ResetMapCycleTimeStamp( void ){ return; } + + virtual void OnNavMeshLoad( void ) { return; } + + // game-specific factories + virtual CTacticalMissionManager *TacticalMissionManagerFactory( void ); + + virtual void ProcessVerboseLogOutput( void ){} + +#endif + + virtual const char *GetGameTypeName( void ){ return NULL; } + virtual int GetGameType( void ){ return 0; } + + virtual bool ShouldDrawHeadLabels(){ return true; } + + virtual void ClientSpawned( edict_t * pPlayer ) { return; } + + virtual void OnFileReceived( const char * fileName, unsigned int transferID ) { return; } + + virtual bool IsHolidayActive( /*EHoliday*/ int eHoliday ) const { return false; } + + virtual bool IsManualMapChangeOkay( const char **pszReason ){ return true; } + +#ifndef CLIENT_DLL +private: + float m_flNextVerboseLogOutput; +#endif // CLIENT_DLL +}; + + +#ifndef CLIENT_DLL + void InstallGameRules(); + + // Create user messages for game here, calls into static player class creation functions + void RegisterUserMessages( void ); +#endif + + +extern ConVar g_Language; + + +//----------------------------------------------------------------------------- +// Gets us at the game rules +//----------------------------------------------------------------------------- + +extern CGameRules *g_pGameRules; + +inline CGameRules* GameRules() +{ + return g_pGameRules; +} + +#endif // GAMERULES_H diff --git a/game/shared/gamerules_register.h b/game/shared/gamerules_register.h new file mode 100644 index 0000000..ab63e4d --- /dev/null +++ b/game/shared/gamerules_register.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GAMERULES_REGISTER_H +#define GAMERULES_REGISTER_H +#ifdef _WIN32 +#pragma once +#endif + + +// Each game rules class must register using this in it's .cpp file. +#if !defined(_STATIC_LINKED) +#define REGISTER_GAMERULES_CLASS( className ) \ + void __CreateGameRules_##className() { new className; } \ + static CGameRulesRegister __g_GameRulesRegister_##className( #className, __CreateGameRules_##className ); +#else +#define REGISTER_GAMERULES_CLASS( className ) \ + void MAKE_NAME_UNIQUE(__CreateGameRules_)##className() { new className; } \ + static CGameRulesRegister __g_GameRulesRegister_##className( #className, MAKE_NAME_UNIQUE(__CreateGameRules_)##className ); +#endif + +#ifdef _XBOX +// force symbol expansion +#define REGISTER_GAMERULES_CLASS2( className ) REGISTER_GAMERULES_CLASS( className ) +#endif + +class CGameRulesRegister +{ +public: + typedef void (*CreateGameRulesFn)(); + + CGameRulesRegister( const char *pClassName, CreateGameRulesFn fn ); + + // Allocates the gamerules object associated with this class. + void CreateGameRules(); + + static CGameRulesRegister* FindByName( const char *pName ); + +private: + const char *m_pClassName; + CreateGameRulesFn m_pFn; + CGameRulesRegister *m_pNext; // Links it into the global list. + + static CGameRulesRegister *s_pHead; + +}; + + + +#ifdef CLIENT_DLL + + // The client forwards this call so the game rules manager can create the appropriate + // game rules class. + void InstallStringTableCallback_GameRules(); + +#else + + // Server calls this at startup. + void CreateNetworkStringTables_GameRules(); + + // Server calls this to install a specific game rules object. The class should have been registered + // with REGISTER_GAMERULES_CLASS. + void CreateGameRulesObject( const char *pClassName ); + +#endif + + +#endif // GAMERULES_REGISTER_H diff --git a/game/shared/gamestats.h b/game/shared/gamestats.h new file mode 100644 index 0000000..fae1e41 --- /dev/null +++ b/game/shared/gamestats.h @@ -0,0 +1,456 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef GAMESTATS_H +#define GAMESTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utldict.h" +#include "tier1/utlbuffer.h" +#include "igamesystem.h" +//#include "steamworks_gamestats.h" + +const int GAMESTATS_VERSION = 1; + +enum StatSendType_t +{ + STATSEND_LEVELSHUTDOWN, + STATSEND_APPSHUTDOWN, + STATSEND_NOTENOUGHPLAYERS, +}; + +struct StatsBufferRecord_t +{ + float m_flFrameRate; // fps + float m_flServerPing; // client ping to server + +}; + +#define STATS_WINDOW_SIZE ( 60 * 10 ) // # of records to hold +#define STATS_RECORD_INTERVAL 1 // # of seconds between data grabs. 2 * 300 = every 10 minutes + +class CGameStats; + +void UpdatePerfStats( void ); +void SetGameStatsHandler( CGameStats *pGameStats ); + +class CBasePlayer; +class CPropVehicleDriveable; +class CTakeDamageInfo; + +#ifdef GAME_DLL + +#define GAMESTATS_STANDARD_NOT_SAVED 0xFEEDBEEF + +enum GameStatsVersions_t +{ + GAMESTATS_FILE_VERSION_OLD = 001, + GAMESTATS_FILE_VERSION_OLD2, + GAMESTATS_FILE_VERSION_OLD3, + GAMESTATS_FILE_VERSION_OLD4, + GAMESTATS_FILE_VERSION_OLD5, + GAMESTATS_FILE_VERSION +}; + +struct BasicGameStatsRecord_t +{ +public: + BasicGameStatsRecord_t() : + m_nCount( 0 ), + m_nSeconds( 0 ), + m_nCommentary( 0 ), + m_nHDR( 0 ), + m_nCaptions( 0 ), + m_bSteam( true ), + m_bCyberCafe( false ), + m_nDeaths( 0 ) + { + Q_memset( m_nSkill, 0, sizeof( m_nSkill ) ); + } + + void Clear(); + + void SaveToBuffer( CUtlBuffer& buf ); + bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion ); + + // Data +public: + int m_nCount; + int m_nSeconds; + + int m_nCommentary; + int m_nHDR; + int m_nCaptions; + int m_nSkill[ 3 ]; + bool m_bSteam; + bool m_bCyberCafe; + int m_nDeaths; +}; + +struct BasicGameStats_t +{ +public: + BasicGameStats_t() : + m_nSecondsToCompleteGame( 0 ), + m_nHL2ChaptureUnlocked( 0 ), + m_bSteam( true ), + m_bCyberCafe( false ), + m_nDXLevel( 0 ) + { + } + + void Clear(); + + void SaveToBuffer( CUtlBuffer& buf ); + bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion ); + + BasicGameStatsRecord_t *FindOrAddRecordForMap( char const *mapname ); + + // Data +public: + int m_nSecondsToCompleteGame; // 0 means they haven't finished playing yet + + BasicGameStatsRecord_t m_Summary; // Summary record + CUtlDict< BasicGameStatsRecord_t, unsigned short > m_MapTotals; + bool m_bSteam; + bool m_bCyberCafe; + int m_nHL2ChaptureUnlocked; + int m_nDXLevel; +}; +#endif // GAME_DLL + +class CBaseGameStats +{ +public: + CBaseGameStats(); + + // override this to declare what format you want to send. New products should use new format. + virtual bool UseOldFormat() + { +#ifdef GAME_DLL + return true; // servers by default send old format for backward compat +#else + return false; // clients never used old format so no backward compat issues, they use new format by default +#endif + } + + // Implement this if you support new format gamestats. + // Return true if you added data to KeyValues, false if you have no data to report + virtual bool AddDataForSend( KeyValues *pKV, StatSendType_t sendType ) { return false; } + + // These methods used for new format gamestats only and control when data gets sent. + virtual bool ShouldSendDataOnLevelShutdown() + { + // by default, servers send data at every level change and clients don't +#ifdef GAME_DLL + return true; +#else + return false; +#endif + } + virtual bool ShouldSendDataOnAppShutdown() + { + // by default, clients send data at app shutdown and servers don't +#ifdef GAME_DLL + return false; +#else + return true; +#endif + } + + virtual void Event_Init( void ); + virtual void Event_Shutdown( void ); + virtual void Event_MapChange( const char *szOldMapName, const char *szNewMapName ); + virtual void Event_LevelInit( void ); + virtual void Event_LevelShutdown( float flElapsed ); + virtual void Event_SaveGame( void ); + virtual void Event_LoadGame( void ); + + void CollectData( StatSendType_t sendType ); + void SendData(); + + void StatsLog( PRINTF_FORMAT_STRING char const *fmt, ... ); + + // This is the first call made, so that we can "subclass" the CBaseGameStats based on gamedir as needed (e.g., ep2 vs. episodic) + virtual CBaseGameStats *OnInit( CBaseGameStats *pCurrentGameStats, char const *gamedir ) { return pCurrentGameStats; } + + // Frees up data from gamestats and resets it to a clean state. + virtual void Clear( void ); + + virtual bool StatTrackingEnabledForMod( void ) { return false; } //Override this to turn on the system. Stat tracking is disabled by default and will always be disabled at the user's request + static bool StatTrackingAllowed( void ); //query whether stat tracking is possible and warranted by the user + virtual bool HaveValidData( void ) { return true; } // whether we currently have an interesting enough data set to upload. Called at upload time; if false, data is not uploaded. + + virtual bool ShouldTrackStandardStats( void ) { return true; } //exactly what was tracked for EP1 release + + //Get mod specific strings used for tracking, defaults should work fine for most cases + virtual const char *GetStatSaveFileName( void ); + virtual const char *GetStatUploadRegistryKeyName( void ); + const char *GetUserPseudoUniqueID( void ); + + virtual bool UserPlayedAllTheMaps( void ) { return false; } //be sure to override this to determine user completion time + +#ifdef CLIENT_DLL + virtual void Event_AchievementProgress( int achievementID, const char* achievementName ) {} +#endif + +#ifdef GAME_DLL + virtual void Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info ); + virtual void Event_PlayerConnected( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerDisconnected( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info ); + virtual void Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info ); + virtual void Event_PlayerSuicide( CBasePlayer* pPlayer ) {} + virtual void Event_Credits(); + virtual void Event_Commentary(); + virtual void Event_CrateSmashed(); + virtual void Event_Punted( CBaseEntity *pObject ); + virtual void Event_PlayerTraveled( CBasePlayer *pBasePlayer, float distanceInInches, bool bInVehicle, bool bSprinting ); + virtual void Event_WeaponFired( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName ); + virtual void Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info ); + virtual void Event_FlippedVehicle( CBasePlayer *pDriver, CPropVehicleDriveable *pVehicle ); + virtual void Event_PreSaveGameLoaded( char const *pSaveName, bool bInGame ); + virtual void Event_PlayerEnteredGodMode( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerEnteredNoClip( CBasePlayer *pBasePlayer ); + virtual void Event_DecrementPlayerEnteredNoClip( CBasePlayer *pBasePlayer ); + virtual void Event_IncrementCountedStatistic( const Vector& vecAbsOrigin, char const *pchStatisticName, float flIncrementAmount ); + + //============================================================================= + // HPE_BEGIN + // [dwenger] Functions necessary for cs-specific stats + //============================================================================= + virtual void Event_WindowShattered( CBasePlayer *pPlayer ); + //============================================================================= + // HPE_END + //============================================================================= + + //custom data to tack onto existing stats if you're not doing a complete overhaul + virtual void AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer ) { } //custom data you want thrown into the default save and upload path + virtual void LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer ) { }; //when loading the saved stats file, this will point to where you started saving data to the save buffer + + virtual void LoadingEvent_PlayerIDDifferentThanLoadedStats( void ); //Only called if you use the base SaveToFileNOW() and LoadFromFile() functions. Used in case you want to keep/invalidate data that was just loaded. + + virtual bool LoadFromFile( void ); //called just before Event_Init() + virtual bool SaveToFileNOW( bool bForceSyncWrite = false ); //saves buffers to their respective files now, returns success or failure + virtual bool UploadStatsFileNOW( void ); //uploads data to the CSER now, returns success or failure + + static bool AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData ); + static bool GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive = false ); + static void LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData ); + + //default save behavior is to save on level shutdown, and game shutdown + virtual bool AutoSave_OnInit( void ) { return false; } + virtual bool AutoSave_OnShutdown( void ) { return true; } + virtual bool AutoSave_OnMapChange( void ) { return false; } + virtual bool AutoSave_OnLevelInit( void ) { return false; } + virtual bool AutoSave_OnLevelShutdown( void ) { return true; } + + //default upload behavior is to upload on game shutdown + virtual bool AutoUpload_OnInit( void ) { return false; } + virtual bool AutoUpload_OnShutdown( void ) { return true; } + virtual bool AutoUpload_OnMapChange( void ) { return false; } + virtual bool AutoUpload_OnLevelInit( void ) { return false; } + virtual bool AutoUpload_OnLevelShutdown( void ) { return false; } + + // Helper for builtin stuff + void SetSteamStatistic( bool bUsingSteam ); + void SetCyberCafeStatistic( bool bIsCyberCafeUser ); + void SetHDRStatistic( bool bHDREnabled ); + void SetCaptionsStatistic( bool bClosedCaptionsEnabled ); + void SetSkillStatistic( int iSkillSetting ); + void SetDXLevelStatistic( int iDXLevel ); + void SetHL2UnlockedChapterStatistic( void ); +#endif // GAMEDLL +public: +#ifdef GAME_DLL + BasicGameStats_t m_BasicStats; //exposed in case you do a complete overhaul and still want to save it +#endif + bool m_bLogging : 1; + bool m_bLoggingToFile : 1; +}; + +#ifdef GAME_DLL + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &SaveBuffer - +// iLump - +// iLumpCount - +//----------------------------------------------------------------------------- +inline bool CBaseGameStats::AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData ) +{ + // Verify the lump index. + Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ); + + if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) ) + return false; + + // Check to see if we have any elements to save. + if ( iLumpCount <= 0 ) + return false; + + // Write the lump id and element count. + SaveBuffer.PutUnsignedShort( iLump ); + SaveBuffer.PutUnsignedShort( iLumpCount ); + + size_t nTotalSize = iLumpCount * nSize; + SaveBuffer.Put( pData, nTotalSize ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &LoadBuffer - +// &iLump - +// &iLumpCount - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +inline bool CBaseGameStats::GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive /*= false*/ ) +{ + // Get the lump id and element count. + iLump = LoadBuffer.GetUnsignedShort(); + if ( !LoadBuffer.IsValid() ) + { + // check for EOF + return false; + } + iLumpCount = LoadBuffer.GetUnsignedShort(); + + if ( bPermissive ) + return true; + + // Verify the lump index. + Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ); + if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) ) + { + return false; + } + + // Check to see if we have any elements to save. + if ( iLumpCount <= 0 ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads 1 or more lumps of raw data +// Input : &LoadBuffer - buffer to be read from +// iLumpCount - # of lumps to read +// nSize - size of each lump +// pData - where to store the data +//----------------------------------------------------------------------------- +inline void CBaseGameStats::LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData ) +{ + LoadBuffer.Get( pData, iLumpCount * nSize ); +} + +#endif // GAME_DLL + +// Moving the extern out of the GAME_DLL block so that the client can access it +extern CBaseGameStats *gamestats; //starts out pointing at a singleton of the class above, overriding this in any constructor should work for replacing it + +//used to drive most of the game stat event handlers as well as track basic stats under the hood of CBaseGameStats +class CBaseGameStats_Driver : public CAutoGameSystemPerFrame +{ +public: + CBaseGameStats_Driver( void ); + + typedef CAutoGameSystemPerFrame BaseClass; + + // IGameSystem overloads + virtual bool Init(); + virtual void Shutdown(); + + // Level init, shutdown + virtual void LevelInitPreEntity(); + virtual void LevelShutdownPreEntity(); + virtual void LevelShutdownPreClearSteamAPIContext(); + virtual void LevelShutdown(); + // Called during game save + virtual void OnSave(); + // Called during game restore, after the local player has connected and entities have been fully restored + virtual void OnRestore(); + + virtual void FrameUpdatePostEntityThink(); + + void PossibleMapChange( void ); + + void CollectData( StatSendType_t sendType ); + void SendData(); + void ResetData(); + bool AddBaseDataForSend( KeyValues *pKV, StatSendType_t sendType ); + + StatsBufferRecord_t m_StatsBuffer[STATS_WINDOW_SIZE]; + bool m_bBufferFull; + int m_nWriteIndex; + float m_flLastRealTime; + float m_flLastSampleTime; + float m_flTotalTimeInLevels; + int m_iNumLevels; + bool m_bDidVoiceChat; // Did the player use voice chat at ALL this map? + + template T AverageStat( T StatsBufferRecord_t::*field ) const + { + T sum = 0; + for( int i = 0; i < STATS_WINDOW_SIZE; i++ ) + sum += m_StatsBuffer[i].*field; + return sum / STATS_WINDOW_SIZE; + } + + template T MaxStat( T StatsBufferRecord_t::*field ) const + { + T maxsofar = -16000000; + for( int i = 0; i < STATS_WINDOW_SIZE; i++ ) + maxsofar = MAX( maxsofar, m_StatsBuffer[i].*field ); + return maxsofar; + } + + template T MinStat( T StatsBufferRecord_t::*field ) const + { + T minsofar = 16000000; + for( int i = 0; i < STATS_WINDOW_SIZE; i++ ) + minsofar = MIN( minsofar, m_StatsBuffer[i].*field ); + return minsofar; + } + + inline void AdvanceIndex( void ) + { + m_nWriteIndex++; + if ( m_nWriteIndex == STATS_WINDOW_SIZE ) + { + m_nWriteIndex = 0; + m_bBufferFull = true; + } + } + + void UpdatePerfStats( void ); + + CUtlString m_PrevMapName; //used to track "OnMapChange" events + int m_iLoadedVersion; + char m_szLoadedUserID[ 17 ]; // GUID + + bool m_bEnabled; //false if incapable of uploading or the user doesn't want to enable stat tracking + bool m_bShuttingDown; + bool m_bInLevel; + bool m_bFirstLevel; + time_t m_tLastUpload; + + float m_flLevelStartTime; + + bool m_bStationary; + float m_flLastMovementTime; + CUserCmd m_LastUserCmd; + bool m_bGamePaused; + float m_flPauseStartTime; + + CGamestatsData *m_pGamestatsData; +}; + +#endif // GAMESTATS_H diff --git a/game/shared/gamestringpool.h b/game/shared/gamestringpool.h new file mode 100644 index 0000000..2dc941f --- /dev/null +++ b/game/shared/gamestringpool.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Pool of all per-level strings. Allocates memory for strings, +// consolodating duplicates. The memory is freed on behalf of clients +// at level transition. Strings are of type string_t. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GAMESTRINGPOOL_H +#define GAMESTRINGPOOL_H + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// String allocation +//----------------------------------------------------------------------------- +string_t AllocPooledString( const char *pszValue ); +string_t AllocPooledString_StaticConstantStringPointer( const char *pszGlobalConstValue ); +string_t FindPooledString( const char *pszValue ); + +#define AssertIsValidString( s ) AssertMsg( s == NULL_STRING || s == FindPooledString( STRING(s) ), "Invalid string " #s ); + +#ifndef GC +//----------------------------------------------------------------------------- +// String system accessor +//----------------------------------------------------------------------------- +class IGameSystem; + +IGameSystem *GameStringSystem(); +#endif // #ifndef GC + +#endif // GAMESTRINGPOOL_H diff --git a/game/shared/gamevars_shared.h b/game/shared/gamevars_shared.h new file mode 100644 index 0000000..913a694 --- /dev/null +++ b/game/shared/gamevars_shared.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CS_GAMEVARS_SHARED_H +#define CS_GAMEVARS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" + +extern ConVar mp_forcecamera; +extern ConVar mp_allowspectators; +extern ConVar friendlyfire; +extern ConVar mp_fadetoblack; + +#endif // CS_GAMEVARS_SHARED_H diff --git a/game/shared/groundlink.h b/game/shared/groundlink.h new file mode 100644 index 0000000..9c04861 --- /dev/null +++ b/game/shared/groundlink.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GROUNDLINK_H +#define GROUNDLINK_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Used for tracking many to one ground entity chains ( many ents can share a single ground entity ) +//----------------------------------------------------------------------------- +struct groundlink_t +{ + EHANDLE entity; + groundlink_t *nextLink; + groundlink_t *prevLink; +}; + +#endif // GROUNDLINK_H diff --git a/game/shared/hintmessage.h b/game/shared/hintmessage.h new file mode 100644 index 0000000..916d2ce --- /dev/null +++ b/game/shared/hintmessage.h @@ -0,0 +1,113 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef HINTMESSAGE_H +#define HINTMESSAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "simtimer.h" + +#ifdef GAME_DLL + #include "player.h" +#else + #include "c_baseplayer.h" +#endif + +class CHintSystem; + +//-------------------------------------------------------------------------------------------------------------- +class CHintMessage +{ +public: + CHintMessage( const char * hintString, CUtlVector< const char * > * args, float duration ); + ~CHintMessage(); + + float GetDuration() const { return m_duration; } + void Send( CBasePlayer *client ); + + bool IsEquivalent( const char *hintString, CUtlVector< const char * > * args ) const; + +private: + const char * m_hintString; ///< hintString is a pointer to a string that should never be deleted. + CUtlVector< char * > m_args; ///< list of arguments. The memory for these strings is internal to the CHintMessage. + float m_duration; ///< time until the next message can be displayed +}; + + +//-------------------------------------------------------------------------------------------------------------- +class CHintMessageQueue +{ +public: + CHintMessageQueue( CBasePlayer *pPlayer ); + void Reset(); + void Update(); + bool AddMessage( const char* message, float duration = 6.0f, CUtlVector< const char * > * args = NULL ); + inline bool IsEmpty() { return m_messages.Count() == 0; } + +private: + float m_tmMessageEnd; + CUtlVector< CHintMessage * > m_messages; + CBasePlayer *m_pPlayer; +}; + +//-------------------------------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------------------------------- +// Timers that manage hint messages that should be displayed after some time. +class CHintMessageTimers +{ +public: + CHintMessageTimers( void ); + CHintMessageTimers( CHintSystem *pSystem, CHintMessageQueue *pQueue ); + + void Reset(); + void Update(); + + // Add / Register timers that will be started/stopped during play + void AddTimer( int iHintID, float timer_duration, float message_duration = 6.0f, CUtlVector< const char * > * args = NULL ); + void RemoveTimer( int iHintID ); + + // Start / Stop timers that were previously registered via AddTimer() + void StartTimer( int iHintID ); + void StopTimer( int iHintID ); + +private: + int GetTimerIndex( int iHintID ); + +private: + struct hintmessagetime_t + { + hintmessagetime_t( float flTimerDuration ) : + timer(flTimerDuration) + { + iHintID = 0; + flMessageDuration = 6.0; + } + + ~hintmessagetime_t() + { + for ( int i=0; i args; + }; + + CUtlVector< hintmessagetime_t* > m_Timers; + CHintMessageQueue *m_pQueue; + CHintSystem *m_pHintSystem; +}; + +#endif // HINTMESSAGE_H diff --git a/game/shared/hintsystem.h b/game/shared/hintsystem.h new file mode 100644 index 0000000..813fc8b --- /dev/null +++ b/game/shared/hintsystem.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A class embedded in players to provide hints to that player +// +//============================================================================= + +#ifndef HINTSYSTEM_H +#define HINTSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef CLIENT_DLL + #include "c_baseplayer.h" +#else + #include "player.h" +#endif + +#include "bitvec.h" + +class CHintMessageQueue; +class CHintMessageTimers; + +typedef bool (*HintTimerCallback)( CBasePlayer *pOnPlayer ); + +//----------------------------------------------------------------------------- +// Purpose: A class embedded in players to provide hints to that player +//----------------------------------------------------------------------------- +class CHintSystem +{ + DECLARE_CLASS_NOBASE( CHintSystem ); + +public: + CHintSystem(); + ~CHintSystem(); + + //----------------------------------------------------- + // Call this from your player constructor + void Init( CBasePlayer *pPlayer, int iMaxHintTypes, const char **pszHintStrings ); + + //----------------------------------------------------- + // CBasePlayer calls these for you, if you fall back to its + // versions of Spawn(), Event_Killed(), and PreThink(). + // Call this when your player respawns + void ResetHints( void ); + + // Call this when your player dies + void ResetHintTimers( void ); + + // Call this when in your player PreThink() + void Update( void ); + + //----------------------------------------------------- + // Hint addition + // Call these to add a hint directly onscreen + bool HintMessage( int hint, bool bForce = false, bool bOnlyIfClear = false ); + void HintMessage( const char *pMessage ); + + // Call this to add a hint timer. It'll be reset for you automatically + // everytime ResetHintTimers() is called. + void RegisterHintTimer( int iHintID, float flTimerDuration, bool bOnlyIfClear = false, HintTimerCallback pfnCallback = NULL ); + + // Call these to start & stop registered hint timers + void StartHintTimer( int iHintID ); + void StopHintTimer( int iHintID ); + void RemoveHintTimer( int iHintID ); + bool TimerShouldFire( int iHintID ); + + // Set whether a player should see any hints at all + void SetShowHints( bool bShowHints ) { m_bShowHints = bShowHints; } + void SetHintPlayed( int iHintID ); + bool ShouldShowHints( void ); + + // Returns true if the hint has been played already + bool HasPlayedHint( int iHintID ); + void PlayedAHint( void ); + void ClearHintHistory( void ) { m_HintHistory.ClearAll(); } + + // Not really an optimal solution, but saves us querying the hud element, + // which wouldn't be easy with derived versions in different mods. + bool HintIsCurrentlyVisible( void ) { return (gpGlobals->curtime - m_flLastHintPlayedAt < 11 ); } + +private: + void ReAddHintTimerIfNotDisplayed( int iHintID, float flTimerDuration ); + +private: + CBasePlayer *m_pPlayer; + + float m_flLastHintPlayedAt; + bool m_bShowHints; + CVarBitVec m_HintHistory; + const char **m_pszHintMessages; + CHintMessageQueue *m_pHintMessageQueue; + CHintMessageTimers *m_pHintMessageTimers; + + struct onresethints_t + { + int iHintID; + float flTimer; + bool bOnlyIfClear; + HintTimerCallback pfnCallback; + }; + CUtlVector m_RegisteredResetHints; +}; + +#ifdef CLIENT_DLL +// Derive from this if you have an entity that wants to display a hint +// when the player waves his target ID over it on the client. +abstract_class ITargetIDProvidesHint +{ +public: + virtual void DisplayHintTo( C_BasePlayer *pPlayer ) = 0; +}; +#endif + +#endif // HINTSYSTEM_H diff --git a/game/shared/hl2/basehlcombatweapon_shared.h b/game/shared/hl2/basehlcombatweapon_shared.h new file mode 100644 index 0000000..eb11fa8 --- /dev/null +++ b/game/shared/hl2/basehlcombatweapon_shared.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basecombatweapon_shared.h" + +#ifndef BASEHLCOMBATWEAPON_SHARED_H +#define BASEHLCOMBATWEAPON_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) +#define CBaseHLCombatWeapon C_BaseHLCombatWeapon +#endif + +class CBaseHLCombatWeapon : public CBaseCombatWeapon +{ +#if !defined( CLIENT_DLL ) +#ifndef _XBOX + DECLARE_DATADESC(); +#else +protected: + DECLARE_DATADESC(); +private: +#endif +#endif + + DECLARE_CLASS( CBaseHLCombatWeapon, CBaseCombatWeapon ); +public: + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + virtual bool WeaponShouldBeLowered( void ); + + bool CanLower(); + virtual bool Ready( void ); + virtual bool Lower( void ); + virtual bool Deploy( void ); + virtual bool Holster( CBaseCombatWeapon *pSwitchingTo ); + virtual void WeaponIdle( void ); + + virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ); + virtual float CalcViewmodelBob( void ); + + virtual Vector GetBulletSpread( WeaponProficiency_t proficiency ); + virtual float GetSpreadBias( WeaponProficiency_t proficiency ); + + virtual const WeaponProficiencyInfo_t *GetProficiencyValues(); + static const WeaponProficiencyInfo_t *GetDefaultProficiencyValues(); + + virtual void ItemHolsterFrame( void ); + + int m_iPrimaryAttacks; // # of primary attacks performed with this weapon + int m_iSecondaryAttacks; // # of secondary attacks performed with this weapon + +protected: + + bool m_bLowered; // Whether the viewmodel is raised or lowered + float m_flRaiseTime; // If lowered, the time we should raise the viewmodel + float m_flHolsterTime; // When the weapon was holstered +}; + +#endif // BASEHLCOMBATWEAPON_SHARED_H diff --git a/game/shared/hl2/citadel_effects_shared.h b/game/shared/hl2/citadel_effects_shared.h new file mode 100644 index 0000000..18304d3 --- /dev/null +++ b/game/shared/hl2/citadel_effects_shared.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CITADEL_EFFECTS_SHARED_H +#define CITADEL_EFFECTS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#define SF_ENERGYCORE_NO_PARTICLES (1<<0) +#define SF_ENERGYCORE_START_ON (1<<1) + +enum +{ + ENERGYCORE_STATE_OFF, + ENERGYCORE_STATE_CHARGING, + ENERGYCORE_STATE_DISCHARGING, +}; + +#ifndef CLIENT_DLL + +// ============================================================================ +// +// Energy core - charges up and then releases energy from its position +// +// ============================================================================ + +class CCitadelEnergyCore : public CBaseEntity +{ + DECLARE_CLASS( CCitadelEnergyCore, CBaseEntity ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +public: + void InputStartCharge( inputdata_t &inputdata ); + void InputStartDischarge( inputdata_t &inputdata ); + void InputStop( inputdata_t &inputdata ); + void SetScale( float flScale ) { m_flScale = flScale; } + + void StartCharge( float flWarmUpTime ); + void StartDischarge(); + void StopDischarge( float flCoolDownTime ); + + virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + virtual int UpdateTransmitState( void ); + + virtual void Precache(); + void Spawn( void ); + +private: + CNetworkVar( float, m_flScale ); + CNetworkVar( int, m_nState ); + CNetworkVar( float, m_flDuration ); + CNetworkVar( float, m_flStartTime ); +}; + +#endif + +#endif // CITADEL_EFFECTS_SHARED_H diff --git a/game/shared/hl2/env_alyxemp_shared.h b/game/shared/hl2/env_alyxemp_shared.h new file mode 100644 index 0000000..b6de643 --- /dev/null +++ b/game/shared/hl2/env_alyxemp_shared.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENV_ALYXEMP_SHARED_H +#define ENV_ALYXEMP_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "beam_shared.h" + +enum +{ + ALYXEMP_STATE_OFF, + ALYXEMP_STATE_CHARGING, + ALYXEMP_STATE_DISCHARGING, +}; + +class CAlyxEmpEffect : public CBaseEntity +{ + DECLARE_CLASS( CAlyxEmpEffect, CBaseEntity ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +public: + + void InputStartCharge( inputdata_t &inputdata ); + void InputStartDischarge( inputdata_t &inputdata ); + void InputStop( inputdata_t &inputdata ); + void InputSetTargetEnt( inputdata_t &inputdata ); + + void StartCharge( float flDuration ); + void StartDischarge(); + void Stop( float flDuration ); + void SetTargetEntity( CBaseEntity *pTarget ); + + void ActivateAutomatic( CBaseEntity *pAlyx, CBaseEntity *pTarget ); + void AutomaticThink(); + + void Spawn( void ); + void Precache( void ); + void Activate( void ); + +private: + + void SetTargetEntity( const char *szEntityName ); + CHandle m_hBeam; + CHandle m_hTargetEnt; + string_t m_strTargetName; + int m_nType; // What type of effect this is (small, large) + int m_iState; + bool m_bAutomated; + + CNetworkVar( int, m_nState ); + CNetworkVar( float, m_flDuration ); + CNetworkVar( float, m_flStartTime ); +}; + + +#endif // ENV_ALYXEMP_SHARED_H diff --git a/game/shared/hl2/env_headcrabcanister_shared.h b/game/shared/hl2/env_headcrabcanister_shared.h new file mode 100644 index 0000000..d5f2f7c --- /dev/null +++ b/game/shared/hl2/env_headcrabcanister_shared.h @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENV_HEADCRABCANISTER_SHARED_H +#define ENV_HEADCRABCANISTER_SHARED_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vstdlib/random.h" +#include "mathlib/vector.h" +#include "utlvector.h" +#include "networkvar.h" + +//============================================================================= +// +// Shared HeadcrabCanister Class +// +class CEnvHeadcrabCanisterShared +{ + DECLARE_CLASS_NOBASE( CEnvHeadcrabCanisterShared ); + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_SIMPLE_DATADESC(); + +public: + CEnvHeadcrabCanisterShared(); + + // Initialization. + void InitInWorld( float flLaunchTime, const Vector &vecStartPosition, const QAngle &vecStartAngles, const Vector &vecDirection, const Vector &vecImpactPosition, bool bLaunchedFromWithinWorld = false ); + void InitInSkybox( float flLaunchTime, const Vector &vecStartPosition, const QAngle &vecStartAngles, const Vector &vecDirection, const Vector &vecImpactPosition, const Vector &vecSkyboxOrigin, float flSkyboxScale ); + + // Returns the position of the object at a given time. + void GetPositionAtTime( float flTime, Vector &vecPosition, QAngle &vecAngles ); + + // Returns whether or not the object is the the skybox + bool IsInSkybox( ); + + // Returns the time at which it enters the world + float GetEnterWorldTime() const; + + // Convert from skybox to world + void ConvertFromSkyboxToWorld(); + + // Did we impact? + bool DidImpact( float flTime ) const; + +public: + // The objects initial parametric conditions. + CNetworkVector( m_vecStartPosition ); + CNetworkVector( m_vecEnterWorldPosition ); + CNetworkVector( m_vecDirection ); + CNetworkQAngle( m_vecStartAngles ); + + CNetworkVar( float, m_flFlightTime ); + CNetworkVar( float, m_flFlightSpeed ); + CNetworkVar( float, m_flLaunchTime ); + + CNetworkVar( float, m_flInitialZSpeed ); + CNetworkVar( float, m_flZAcceleration ); + CNetworkVar( float, m_flHorizSpeed ); + + CNetworkVar( bool, m_bLaunchedFromWithinWorld ); + + CNetworkVector( m_vecParabolaDirection ); + + // The time at which the canister enters the skybox + CNetworkVar( float, m_flWorldEnterTime ); + + // Skybox data + CNetworkVector( m_vecSkyboxOrigin ); + CNetworkVar( float, m_flSkyboxScale ); + CNetworkVar( bool, m_bInSkybox ); + +private: + float m_flLaunchHeight; + + // Calculate the enter time. (called from Init) + void CalcEnterTime( const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); + + friend class CEnvHeadcrabCanister; + friend class C_EnvHeadcrabCanister; +}; + +/* +//============================================================================= +// +// HeadcrabCanister Factory Interface +// +abstract_class IHeadcrabCanisterFactory +{ +public: + + virtual void CreateHeadcrabCanister( int nID, int iType, + const Vector &vecPosition, const Vector &vecDirection, + float flSpeed, float flStartTime, float flDamageRadius, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ) = 0; +}; + +//============================================================================= +// +// Shared HeadcrabCanister Spawner Class +// +class CEnvHeadcrabCanisterSpawnerShared +{ +public: + DECLARE_CLASS_NOBASE( CEnvHeadcrabCanisterSpawnerShared ); + DECLARE_EMBEDDED_NETWORKVAR(); + + //------------------------------------------------------------------------- + // Initialization. + //------------------------------------------------------------------------- + CEnvHeadcrabCanisterSpawnerShared(); + void Init( IHeadcrabCanisterFactory *pFactory, int nRandomSeed, float flTime, + const Vector &vecMinBounds, const Vector &vecMaxBounds, + const Vector &vecTriggerMins, const Vector &vecTriggerMaxs ); + + //------------------------------------------------------------------------- + // Method to generate HeadcrabCanisters. + // Time passed in here is global time, not delta time. + // The function returns the time at which it must be called again. + //------------------------------------------------------------------------- + float HeadcrabCanisterThink( float flTime ); + + //------------------------------------------------------------------------- + // Add HeadcrabCanister target data, used to determine HeadcrabCanister travel direction. + //------------------------------------------------------------------------- + void AddToTargetList( const Vector &vecPosition, float flRadius ); + + // Debugging! + int GetRandomInt( int nMin, int nMax ); + float GetRandomFloat( float flMin, float flMax ); + +public: + + // Factory. + IHeadcrabCanisterFactory *m_pFactory; // HeadcrabCanister creation factory. + + int m_nHeadcrabCanisterCount; // Number of HeadcrabCanisters created - used as IDs + + // Initial spawner data. + CNetworkVar( float, m_flStartTime ); // Start time. + CNetworkVar( int, m_nRandomSeed ); // The random number stream seed. + + CNetworkVar( int, m_iHeadcrabCanisterType ); // Type of HeadcrabCanister. + float m_flHeadcrabCanisterDamageRadius; // HeadcrabCanister damage radius. + CNetworkVar( bool, m_bSkybox ); // Is the spawner in the skybox? + + CNetworkVar( float, m_flMinSpawnTime ); // Spawn time - Min + CNetworkVar( float, m_flMaxSpawnTime ); // Max + CNetworkVar( int, m_nMinSpawnCount ); // Number of HeadcrabCanisters to spawn - Min + CNetworkVar( int, m_nMaxSpawnCount ); // Max + CNetworkVector( m_vecMinBounds ); // Spawner volume (space) - Min + CNetworkVector( m_vecMaxBounds ); // Max + CNetworkVar( float, m_flMinSpeed ); // HeadcrabCanister speed - Min + CNetworkVar( float, m_flMaxSpeed ); // Max + CNetworkVector( m_vecTriggerMins ); // World Bounds (Trigger) in 3D Skybox - Min + CNetworkVector( m_vecTriggerMaxs ); // Max + Vector m_vecTriggerCenter; + + // Generated data. + int m_nRandomCallCount; // Debug! Keep track of number steam calls. + float m_flNextSpawnTime; // Next HeadcrabCanister spawn time (random). + CUniformRandomStream m_NumberStream; // Used to generate random numbers. + + // Use "Targets" to determine HeadcrabCanister direction(s). + struct HeadcrabCanistertarget_t + { + Vector m_vecPosition; + float m_flRadius; + }; + CUtlVector m_aTargets; +}; +*/ + +#endif // ENV_HEADCRAB_CANISTER_SHARED_H diff --git a/game/shared/hl2/hl2_gamerules.h b/game/shared/hl2/hl2_gamerules.h new file mode 100644 index 0000000..4f64793 --- /dev/null +++ b/game/shared/hl2/hl2_gamerules.h @@ -0,0 +1,118 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game rules for Half-Life 2. +// +//=============================================================================// + +#ifndef HL2_GAMERULES_H +#define HL2_GAMERULES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "gamerules.h" +#include "singleplay_gamerules.h" +#include "hl2_shareddefs.h" + +#ifdef CLIENT_DLL + #define CHalfLife2 C_HalfLife2 + #define CHalfLife2Proxy C_HalfLife2Proxy +#endif + + +class CHalfLife2Proxy : public CGameRulesProxy +{ +public: + DECLARE_CLASS( CHalfLife2Proxy, CGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + + +class CHalfLife2 : public CSingleplayRules +{ +public: + DECLARE_CLASS( CHalfLife2, CSingleplayRules ); + + // Damage Query Overrides. + virtual bool Damage_IsTimeBased( int iDmgType ); + // TEMP: + virtual int Damage_GetTimeBased( void ); + + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + virtual bool ShouldUseRobustRadiusDamage(CBaseEntity *pEntity); +#ifndef CLIENT_DLL + virtual bool ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); + virtual float GetAutoAimScale( CBasePlayer *pPlayer ); + virtual float GetAmmoQuantityScale( int iAmmoIndex ); + virtual void LevelInitPreEntity(); +#endif + +private: + // Rules change for the mega physgun + CNetworkVar( bool, m_bMegaPhysgun ); + +#ifdef CLIENT_DLL + + DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars. + +#else + + DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars. + + CHalfLife2(); + virtual ~CHalfLife2() {} + + virtual void Think( void ); + + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + + virtual void InitDefaultAIRelationships( void ); + virtual const char* AIClassText(int classType); + virtual const char *GetGameDescription( void ) { return "Half-Life 2"; } + + // Ammo + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual float GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ); + + virtual bool ShouldBurningPropsEmitLight(); +public: + + bool AllowDamage( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + + bool NPC_ShouldDropGrenade( CBasePlayer *pRecipient ); + bool NPC_ShouldDropHealth( CBasePlayer *pRecipient ); + void NPC_DroppedHealth( void ); + void NPC_DroppedGrenade( void ); + bool MegaPhyscannonActive( void ) { return m_bMegaPhysgun; } + + virtual bool IsAlyxInDarknessMode(); + +private: + + float m_flLastHealthDropTime; + float m_flLastGrenadeDropTime; + + void AdjustPlayerDamageTaken( CTakeDamageInfo *pInfo ); + float AdjustPlayerDamageInflicted( float damage ); + + int DefaultFOV( void ) { return 75; } +#endif +}; + + +//----------------------------------------------------------------------------- +// Gets us at the Half-Life 2 game rules +//----------------------------------------------------------------------------- +inline CHalfLife2* HL2GameRules() +{ +#if ( !defined( HL2_DLL ) && !defined( HL2_CLIENT_DLL ) ) || defined( HL2MP ) + Assert( 0 ); // g_pGameRules is NOT an instance of CHalfLife2 and bad things happen +#endif + + return static_cast(g_pGameRules); +} + + + +#endif // HL2_GAMERULES_H diff --git a/game/shared/hl2/hl2_player_shared.h b/game/shared/hl2/hl2_player_shared.h new file mode 100644 index 0000000..bae88da --- /dev/null +++ b/game/shared/hl2/hl2_player_shared.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HL2_PLAYER_SHARED_H +#define HL2_PLAYER_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +// Shared header file for players +#if defined( CLIENT_DLL ) +#define CHL2_Player C_BaseHLPlayer //FIXME: Lovely naming job between server and client here... +#include "c_basehlplayer.h" +#else +#include "hl2_player.h" +#endif + +#endif // HL2_PLAYER_SHARED_H diff --git a/game/shared/hl2/hl2_shareddefs.h b/game/shared/hl2/hl2_shareddefs.h new file mode 100644 index 0000000..e84d90c --- /dev/null +++ b/game/shared/hl2/hl2_shareddefs.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL2_SHAREDDEFS_H +#define HL2_SHAREDDEFS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "const.h" + + +//-------------------------------------------------------------------------- +// Collision groups +//-------------------------------------------------------------------------- + +enum +{ + HL2COLLISION_GROUP_PLASMANODE = LAST_SHARED_COLLISION_GROUP, + HL2COLLISION_GROUP_SPIT, + HL2COLLISION_GROUP_HOMING_MISSILE, + HL2COLLISION_GROUP_COMBINE_BALL, + + HL2COLLISION_GROUP_FIRST_NPC, + HL2COLLISION_GROUP_HOUNDEYE, + HL2COLLISION_GROUP_CROW, + HL2COLLISION_GROUP_HEADCRAB, + HL2COLLISION_GROUP_STRIDER, + HL2COLLISION_GROUP_GUNSHIP, + HL2COLLISION_GROUP_ANTLION, + HL2COLLISION_GROUP_LAST_NPC, + HL2COLLISION_GROUP_COMBINE_BALL_NPC, +}; + + +//-------------- +// HL2 SPECIFIC +//-------------- +#define DMG_SNIPER (DMG_LASTGENERICFLAG<<1) // This is sniper damage +#define DMG_MISSILEDEFENSE (DMG_LASTGENERICFLAG<<2) // The only kind of damage missiles take. (special missile defense) + + + +#endif // HL2_SHAREDDEFS_H diff --git a/game/shared/hl2/hl2_vehicle_radar.h b/game/shared/hl2/hl2_vehicle_radar.h new file mode 100644 index 0000000..102cc83 --- /dev/null +++ b/game/shared/hl2/hl2_vehicle_radar.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef HL2_VEHICLE_RADAR_H +#define HL2_VEHICLE_RADAR_H + +#define RADAR_MAX_CONTACTS 24 +#define RADAR_CONTACT_TYPE_BITS 3 // Max 8 types of contacts (for networking) +#define RADAR_UPDATE_FREQUENCY 1.5f +#define RADAR_UPDATE_FREQUENCY_FAST 0.5f + +enum // If we have more than 16 types of contacts, RADAR_CONTACT_TYPE_BITS +{ + RADAR_CONTACT_NONE = -1, + RADAR_CONTACT_GENERIC = 0, + RADAR_CONTACT_MAGNUSSEN_RDU, + RADAR_CONTACT_DOG, + RADAR_CONTACT_ALLY_INSTALLATION, + RADAR_CONTACT_ENEMY, // 'regular' sized enemy (Hunter) + RADAR_CONTACT_LARGE_ENEMY, // Large enemy (Strider) +}; + +#endif \ No newline at end of file diff --git a/game/shared/hl2/hl_gamemovement.h b/game/shared/hl2/hl_gamemovement.h new file mode 100644 index 0000000..1e9abef --- /dev/null +++ b/game/shared/hl2/hl_gamemovement.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Special handling for hl2 usable ladders +// +//=============================================================================// + +#include "gamemovement.h" +#include "func_ladder.h" + +#if defined( CLIENT_DLL ) + +#include "c_basehlplayer.h" +#define CHL2_Player C_BaseHLPlayer +#else + +#include "hl2_player.h" + +#endif + +struct LadderMove_t; +class CInfoLadderDismount; + +struct NearbyDismount_t +{ + CInfoLadderDismount *dismount; + float distSqr; +}; + +//----------------------------------------------------------------------------- +// Purpose: HL2 specific movement code +//----------------------------------------------------------------------------- +class CHL2GameMovement : public CGameMovement +{ + typedef CGameMovement BaseClass; +public: + + CHL2GameMovement(); + +// Overrides + virtual void FullLadderMove(); + virtual bool LadderMove( void ); + virtual bool OnLadder( trace_t &trace ); + virtual int GetCheckInterval( IntervalType_t type ); + virtual void SetGroundEntity( trace_t *pm ); + virtual bool CanAccelerate( void ); + +private: + + // See if we are pressing use near a ladder "mount" point and if so, latch us onto the ladder + bool CheckLadderAutoMount( CFuncLadder *ladder, const Vector& bestOrigin ); + + bool CheckLadderAutoMountCone( CFuncLadder *ladder, const Vector& bestOrigin, float maxAngleDelta, float maxDistToLadder ); + bool CheckLadderAutoMountEndPoint(CFuncLadder *ladder, const Vector& bestOrigin ); + + + bool LookingAtLadder( CFuncLadder *ladder ); + + // Are we forcing the user's position to a new spot + bool IsForceMoveActive(); + // Start forcing player position + void StartForcedMove( bool mounting, float transit_speed, const Vector& goalpos, CFuncLadder *ladder ); + // Returns false when finished + bool ContinueForcedMove(); + + // Given a list of nearby ladders, find the best ladder and the "mount" origin + void Findladder( float maxdist, CFuncLadder **ppLadder, Vector& ladderOrigin, const CFuncLadder *skipLadder ); + + // Debounce the +USE key + void SwallowUseKey(); + + // Returns true if the player will auto-exit the ladder via a dismount node + bool ExitLadderViaDismountNode( CFuncLadder *ladder, bool strict, bool useAlternate = false ); + void GetSortedDismountNodeList( const Vector &org, float radius, CFuncLadder *ladder, CUtlRBTree< NearbyDismount_t, int >& list ); + + LadderMove_t *GetLadderMove(); + CHL2_Player *GetHL2Player(); + + void SetLadder( CFuncLadder *ladder ); + CFuncLadder *GetLadder(); +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline CHL2_Player *CHL2GameMovement::GetHL2Player() +{ + return static_cast< CHL2_Player * >( player ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : inline LadderMove* +//----------------------------------------------------------------------------- +inline LadderMove_t *CHL2GameMovement::GetLadderMove() +{ + CHL2_Player *p = GetHL2Player(); + if ( !p ) + { + return NULL; + } + return p->GetLadderMove(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *ladder - +//----------------------------------------------------------------------------- +inline void CHL2GameMovement::SetLadder( CFuncLadder *ladder ) +{ + CFuncLadder* oldLadder = GetLadder(); + + if ( !ladder && oldLadder ) + { + oldLadder->PlayerGotOff( GetHL2Player() ); + } + + + GetHL2Player()->m_HL2Local.m_hLadder.Set( ladder ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CFuncLadder +//----------------------------------------------------------------------------- +inline CFuncLadder *CHL2GameMovement::GetLadder() +{ + return static_cast( static_cast( GetHL2Player()->m_HL2Local.m_hLadder.Get() ) ); +} diff --git a/game/shared/hl2/hl_movedata.h b/game/shared/hl2/hl_movedata.h new file mode 100644 index 0000000..5b7d4f8 --- /dev/null +++ b/game/shared/hl2/hl_movedata.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL_MOVEDATA_H +#define HL_MOVEDATA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "igamemovement.h" + + +// This class contains HL2-specific prediction data. +class CHLMoveData : public CMoveData +{ +public: + bool m_bIsSprinting; +}; + +class CFuncLadder; +class CReservePlayerSpot; + +//----------------------------------------------------------------------------- +// Purpose: Data related to automatic mounting/dismounting from ladders +//----------------------------------------------------------------------------- +struct LadderMove_t +{ + DECLARE_SIMPLE_DATADESC(); + + // Are we forcing player movement during mount/dismount + bool m_bForceLadderMove; + // Is the forced move getting on or off the ladder + bool m_bForceMount; + + // Simulation info for forcing the player move + float m_flStartTime; + float m_flArrivalTime; + Vector m_vecGoalPosition; + Vector m_vecStartPosition; + + // The ladder entity owning the forced move (for marking us "on" the ladder after automounting it) + CHandle< CFuncLadder > m_hForceLadder; + CHandle< CReservePlayerSpot > m_hReservedSpot; +}; + +#endif // HL_MOVEDATA_H diff --git a/game/shared/hl2mp/hl2mp_gamerules.h b/game/shared/hl2mp/hl2mp_gamerules.h new file mode 100644 index 0000000..8d91554 --- /dev/null +++ b/game/shared/hl2mp/hl2mp_gamerules.h @@ -0,0 +1,172 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL2MP_GAMERULES_H +#define HL2MP_GAMERULES_H +#pragma once + +#include "gamerules.h" +#include "teamplay_gamerules.h" +#include "gamevars_shared.h" + +#ifndef CLIENT_DLL +#include "hl2mp_player.h" +#endif + +#define VEC_CROUCH_TRACE_MIN HL2MPRules()->GetHL2MPViewVectors()->m_vCrouchTraceMin +#define VEC_CROUCH_TRACE_MAX HL2MPRules()->GetHL2MPViewVectors()->m_vCrouchTraceMax + +enum +{ + TEAM_COMBINE = 2, + TEAM_REBELS, +}; + + +#ifdef CLIENT_DLL + #define CHL2MPRules C_HL2MPRules + #define CHL2MPGameRulesProxy C_HL2MPGameRulesProxy +#endif + +class CHL2MPGameRulesProxy : public CGameRulesProxy +{ +public: + DECLARE_CLASS( CHL2MPGameRulesProxy, CGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class HL2MPViewVectors : public CViewVectors +{ +public: + HL2MPViewVectors( + Vector vView, + Vector vHullMin, + Vector vHullMax, + Vector vDuckHullMin, + Vector vDuckHullMax, + Vector vDuckView, + Vector vObsHullMin, + Vector vObsHullMax, + Vector vDeadViewHeight, + Vector vCrouchTraceMin, + Vector vCrouchTraceMax ) : + CViewVectors( + vView, + vHullMin, + vHullMax, + vDuckHullMin, + vDuckHullMax, + vDuckView, + vObsHullMin, + vObsHullMax, + vDeadViewHeight ) + { + m_vCrouchTraceMin = vCrouchTraceMin; + m_vCrouchTraceMax = vCrouchTraceMax; + } + + Vector m_vCrouchTraceMin; + Vector m_vCrouchTraceMax; +}; + +class CHL2MPRules : public CTeamplayRules +{ +public: + DECLARE_CLASS( CHL2MPRules, CTeamplayRules ); + +#ifdef CLIENT_DLL + + DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars. + +#else + + DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars. +#endif + + CHL2MPRules(); + virtual ~CHL2MPRules(); + + virtual void Precache( void ); + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + + virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ); + virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon ); + virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon ); + virtual void Think( void ); + virtual void CreateStandardEntities( void ); + virtual void ClientSettingsChanged( CBasePlayer *pPlayer ); + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual void GoToIntermission( void ); + virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + virtual const char *GetGameDescription( void ); + // derive this function if you mod uses encrypted weapon info files + virtual const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"x9Ke0BY7"; } + virtual const CViewVectors* GetViewVectors() const; + const HL2MPViewVectors* GetHL2MPViewVectors() const; + + float GetMapRemainingTime(); + void CleanUpMap(); + void CheckRestartGame(); + void RestartGame(); + +#ifndef CLIENT_DLL + virtual Vector VecItemRespawnSpot( CItem *pItem ); + virtual QAngle VecItemRespawnAngles( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pItem ); + virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ); + + void AddLevelDesignerPlacedObject( CBaseEntity *pEntity ); + void RemoveLevelDesignerPlacedObject( CBaseEntity *pEntity ); + void ManageObjectRelocation( void ); + void CheckChatForReadySignal( CHL2MP_Player *pPlayer, const char *chatmsg ); + const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer ); + +#endif + virtual void ClientDisconnected( edict_t *pClient ); + + bool CheckGameOver( void ); + bool IsIntermission( void ); + + void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + + + bool IsTeamplay( void ) { return m_bTeamPlayEnabled; } + void CheckAllPlayersReady( void ); + + virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer ); + +private: + + CNetworkVar( bool, m_bTeamPlayEnabled ); + CNetworkVar( float, m_flGameStartTime ); + CUtlVector m_hRespawnableItemsAndWeapons; + float m_tmNextPeriodicThink; + float m_flRestartGameTime; + bool m_bCompleteReset; + bool m_bAwaitingReadyRestart; + bool m_bHeardAllPlayersReady; + +#ifndef CLIENT_DLL + bool m_bChangelevelDone; +#endif +}; + +inline CHL2MPRules* HL2MPRules() +{ + return static_cast(g_pGameRules); +} + +#endif //HL2MP_GAMERULES_H diff --git a/game/shared/hl2mp/hl2mp_player_shared.h b/game/shared/hl2mp/hl2mp_player_shared.h new file mode 100644 index 0000000..3aee923 --- /dev/null +++ b/game/shared/hl2mp/hl2mp_player_shared.h @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef HL2MP_PLAYER_SHARED_H +#define HL2MP_PLAYER_SHARED_H +#pragma once + +#define HL2MP_PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f) +#include "studio.h" + + +enum +{ + PLAYER_SOUNDS_CITIZEN = 0, + PLAYER_SOUNDS_COMBINESOLDIER, + PLAYER_SOUNDS_METROPOLICE, + PLAYER_SOUNDS_MAX, +}; + +enum HL2MPPlayerState +{ + // Happily running around in the game. + STATE_ACTIVE=0, + STATE_OBSERVER_MODE, // Noclipping around, watching players, etc. + NUM_PLAYER_STATES +}; + + +#if defined( CLIENT_DLL ) +#define CHL2MP_Player C_HL2MP_Player +#endif + +class CPlayerAnimState +{ +public: + enum + { + TURN_NONE = 0, + TURN_LEFT, + TURN_RIGHT + }; + + CPlayerAnimState( CHL2MP_Player *outer ); + + Activity BodyYawTranslateActivity( Activity activity ); + + void Update(); + + const QAngle& GetRenderAngles(); + + void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); + + CHL2MP_Player *GetOuter(); + +private: + void GetOuterAbsVelocity( Vector& vel ); + + int ConvergeAngles( float goal,float maxrate, float dt, float& current ); + + void EstimateYaw( void ); + void ComputePoseParam_BodyYaw( void ); + void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ); + void ComputePoseParam_BodyLookYaw( void ); + + void ComputePlaybackRate(); + + CHL2MP_Player *m_pOuter; + + float m_flGaitYaw; + float m_flStoredCycle; + + // The following variables are used for tweaking the yaw of the upper body when standing still and + // making sure that it smoothly blends in and out once the player starts moving + // Direction feet were facing when we stopped moving + float m_flGoalFeetYaw; + float m_flCurrentFeetYaw; + + float m_flCurrentTorsoYaw; + + // To check if they are rotating in place + float m_flLastYaw; + // Time when we stopped moving + float m_flLastTurnTime; + + // One of the above enums + int m_nTurningInPlace; + + QAngle m_angRender; + + float m_flTurnCorrectionTime; +}; + +#endif //HL2MP_PLAYER_SHARED_h diff --git a/game/shared/hl2mp/hl2mp_weapon_parse.h b/game/shared/hl2mp/hl2mp_weapon_parse.h new file mode 100644 index 0000000..2ec16dd --- /dev/null +++ b/game/shared/hl2mp/hl2mp_weapon_parse.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HL2MP_WEAPON_PARSE_H +#define HL2MP_WEAPON_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "weapon_parse.h" +#include "networkvar.h" + + +//-------------------------------------------------------------------------------------------------------- +class CHL2MPSWeaponInfo : public FileWeaponInfo_t +{ +public: + DECLARE_CLASS_GAMEROOT( CHL2MPSWeaponInfo, FileWeaponInfo_t ); + + CHL2MPSWeaponInfo(); + + virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName ); + + +public: + + int m_iPlayerDamage; +}; + + +#endif // HL2MP_WEAPON_PARSE_H diff --git a/game/shared/hl2mp/weapon_ar2.h b/game/shared/hl2mp/weapon_ar2.h new file mode 100644 index 0000000..8aa8dde --- /dev/null +++ b/game/shared/hl2mp/weapon_ar2.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot from the AR2 +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONAR2_H +#define WEAPONAR2_H + +#include "basegrenade_shared.h" +#include "weapon_hl2mpbase_machinegun.h" + +#ifdef CLIENT_DLL +#define CWeaponAR2 C_WeaponAR2 +#endif + +class CWeaponAR2 : public CHL2MPMachineGun +{ +public: + DECLARE_CLASS( CWeaponAR2, CHL2MPMachineGun ); + + CWeaponAR2(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + void ItemPostFrame( void ); + void Precache( void ); + + void SecondaryAttack( void ); + void DelayedAttack( void ); + + const char *GetTracerType( void ) { return "AR2Tracer"; } + + void AddViewKick( void ); + + int GetMinBurst( void ) { return 2; } + int GetMaxBurst( void ) { return 5; } + float GetFireRate( void ) { return 0.1f; } + + bool CanHolster( void ); + bool Reload( void ); + + Activity GetPrimaryAttackActivity( void ); + + void DoImpactEffect( trace_t &tr, int nDamageType ); + + virtual bool Deploy( void ); + + + virtual const Vector& GetBulletSpread( void ) + { + static Vector cone; + + cone = VECTOR_CONE_3DEGREES; + + return cone; + } + + const WeaponProficiencyInfo_t *GetProficiencyValues(); + +private: + CWeaponAR2( const CWeaponAR2 & ); + +protected: + + float m_flDelayedFire; + bool m_bShotDelayed; + int m_nVentPose; + +#ifndef CLIENT_DLL + DECLARE_ACTTABLE(); +#endif +}; + + +#endif //WEAPONAR2_H diff --git a/game/shared/hl2mp/weapon_crowbar.h b/game/shared/hl2mp/weapon_crowbar.h new file mode 100644 index 0000000..2cd10fb --- /dev/null +++ b/game/shared/hl2mp/weapon_crowbar.h @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL2MP_WEAPON_CROWBAR_H +#define HL2MP_WEAPON_CROWBAR_H +#pragma once + + +#include "weapon_hl2mpbasehlmpcombatweapon.h" +#include "weapon_hl2mpbasebasebludgeon.h" + + +#ifdef CLIENT_DLL +#define CWeaponCrowbar C_WeaponCrowbar +#endif + +//----------------------------------------------------------------------------- +// CWeaponCrowbar +//----------------------------------------------------------------------------- + +class CWeaponCrowbar : public CBaseHL2MPBludgeonWeapon +{ +public: + DECLARE_CLASS( CWeaponCrowbar, CBaseHL2MPBludgeonWeapon ); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +#ifndef CLIENT_DLL + DECLARE_ACTTABLE(); +#endif + + CWeaponCrowbar(); + + float GetRange( void ); + float GetFireRate( void ); + + void AddViewKick( void ); + float GetDamageForActivity( Activity hitActivity ); + void SecondaryAttack( void ) { return; } + + void Drop( const Vector &vecVelocity ); + + + // Animation event +#ifndef CLIENT_DLL + virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + void HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); + int WeaponMeleeAttack1Condition( float flDot, float flDist ); +#endif + + CWeaponCrowbar( const CWeaponCrowbar & ); + +private: + +}; + + +#endif // HL2MP_WEAPON_CROWBAR_H + diff --git a/game/shared/hl2mp/weapon_hl2mpbase.h b/game/shared/hl2mp/weapon_hl2mpbase.h new file mode 100644 index 0000000..0f21044 --- /dev/null +++ b/game/shared/hl2mp/weapon_hl2mpbase.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_HL2MPBASE_H +#define WEAPON_HL2MPBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hl2mp_player_shared.h" +#include "basecombatweapon_shared.h" +#include "hl2mp_weapon_parse.h" + +#if defined( CLIENT_DLL ) + #define CWeaponHL2MPBase C_WeaponHL2MPBase + void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip ); +#endif + +class CHL2MP_Player; + +// These are the names of the ammo types that go in the CAmmoDefs and that the +// weapon script files reference. + +// Given an ammo type (like from a weapon's GetPrimaryAmmoType()), this compares it +// against the ammo name you specify. +// MIKETODO: this should use indexing instead of searching and strcmp()'ing all the time. +bool IsAmmoType( int iAmmoType, const char *pAmmoName ); + +class CWeaponHL2MPBase : public CBaseCombatWeapon +{ +public: + DECLARE_CLASS( CWeaponHL2MPBase, CBaseCombatWeapon ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponHL2MPBase(); + + #ifdef GAME_DLL + DECLARE_DATADESC(); + + void SendReloadSoundEvent( void ); + + void Materialize( void ); + virtual int ObjectCaps( void ); + #endif + + // All predicted weapons need to implement and return true + virtual bool IsPredicted() const; + + CBasePlayer* GetPlayerOwner() const; + CHL2MP_Player* GetHL2MPPlayerOwner() const; + + void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f ); + + CHL2MPSWeaponInfo const &GetHL2MPWpnData() const; + + + virtual void FireBullets( const FireBulletsInfo_t &info ); + virtual void FallInit( void ); + +public: + #if defined( CLIENT_DLL ) + + virtual bool ShouldPredict(); + virtual void OnDataChanged( DataUpdateType_t type ); + + virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options ); + + #else + + virtual void Spawn(); + + #endif + + float m_flPrevAnimTime; + float m_flNextResetCheckTime; + + Vector GetOriginalSpawnOrigin( void ) { return m_vOriginalSpawnOrigin; } + QAngle GetOriginalSpawnAngles( void ) { return m_vOriginalSpawnAngles; } + +private: + + CWeaponHL2MPBase( const CWeaponHL2MPBase & ); + + Vector m_vOriginalSpawnOrigin; + QAngle m_vOriginalSpawnAngles; +}; + + +#endif // WEAPON_HL2MPBASE_H diff --git a/game/shared/hl2mp/weapon_hl2mpbase_machinegun.h b/game/shared/hl2mp/weapon_hl2mpbase_machinegun.h new file mode 100644 index 0000000..c7f9a56 --- /dev/null +++ b/game/shared/hl2mp/weapon_hl2mpbase_machinegun.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "weapon_hl2mpbase.h" + +#ifndef BASEHLCOMBATWEAPON_H +#define BASEHLCOMBATWEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) + #define CHL2MPMachineGun C_HL2MPMachineGun +#endif + +//========================================================= +// Machine gun base class +//========================================================= +class CHL2MPMachineGun : public CWeaponHL2MPBase +{ +public: + DECLARE_CLASS( CHL2MPMachineGun, CWeaponHL2MPBase ); + DECLARE_DATADESC(); + + CHL2MPMachineGun(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + void PrimaryAttack( void ); + + // Default calls through to m_hOwner, but plasma weapons can override and shoot projectiles here. + virtual void ItemPostFrame( void ); + virtual void FireBullets( const FireBulletsInfo_t &info ); + virtual bool Deploy( void ); + + virtual const Vector &GetBulletSpread( void ); + + int WeaponSoundRealtime( WeaponSound_t shoot_type ); + + // utility function + static void DoMachineGunKick( CBasePlayer *pPlayer, float dampEasy, float maxVerticleKickAngle, float fireDurationTime, float slideLimitTime ); + +private: + + CHL2MPMachineGun( const CHL2MPMachineGun & ); + +protected: + + int m_nShotsFired; // Number of consecutive shots fired + + float m_flNextSoundTime; // real-time clock of when to make next sound +}; + +#endif // BASEHLCOMBATWEAPON_H diff --git a/game/shared/hl2mp/weapon_hl2mpbasebasebludgeon.h b/game/shared/hl2mp/weapon_hl2mpbasebasebludgeon.h new file mode 100644 index 0000000..d268b32 --- /dev/null +++ b/game/shared/hl2mp/weapon_hl2mpbasebasebludgeon.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The class from which all bludgeon melee +// weapons are derived. +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include "weapon_hl2mpbasehlmpcombatweapon.h" + +#ifndef BASEBLUDGEONWEAPON_H +#define BASEBLUDGEONWEAPON_H + +#ifdef _WIN32 +#pragma once +#endif + + +#if defined( CLIENT_DLL ) +#define CBaseHL2MPBludgeonWeapon C_BaseHL2MPBludgeonWeapon +#endif + +//========================================================= +// CBaseHLBludgeonWeapon +//========================================================= +class CBaseHL2MPBludgeonWeapon : public CBaseHL2MPCombatWeapon +{ + DECLARE_CLASS( CBaseHL2MPBludgeonWeapon, CBaseHL2MPCombatWeapon ); +public: + CBaseHL2MPBludgeonWeapon(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + virtual void Spawn( void ); + virtual void Precache( void ); + + //Attack functions + virtual void PrimaryAttack( void ); + virtual void SecondaryAttack( void ); + + virtual void ItemPostFrame( void ); + + //Functions to select animation sequences + virtual Activity GetPrimaryAttackActivity( void ) { return ACT_VM_HITCENTER; } + virtual Activity GetSecondaryAttackActivity( void ) { return ACT_VM_HITCENTER2; } + + virtual float GetFireRate( void ) { return 0.2f; } + virtual float GetRange( void ) { return 32.0f; } + virtual float GetDamageForActivity( Activity hitActivity ) { return 1.0f; } + + CBaseHL2MPBludgeonWeapon( const CBaseHL2MPBludgeonWeapon & ); + +protected: + virtual void ImpactEffect( trace_t &trace ); + +private: + bool ImpactWater( const Vector &start, const Vector &end ); + void Swing( int bIsSecondary ); + void Hit( trace_t &traceHit, Activity nHitActivity ); + Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner ); +}; + +#endif \ No newline at end of file diff --git a/game/shared/hl2mp/weapon_hl2mpbasehlmpcombatweapon.h b/game/shared/hl2mp/weapon_hl2mpbasehlmpcombatweapon.h new file mode 100644 index 0000000..e846932 --- /dev/null +++ b/game/shared/hl2mp/weapon_hl2mpbasehlmpcombatweapon.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef WEAPON_BASEHL2MPCOMBATWEAPON_SHARED_H +#define WEAPON_BASEHL2MPCOMBATWEAPON_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef CLIENT_DLL + #include "c_hl2mp_player.h" +#else + #include "hl2mp_player.h" +#endif + +#include "weapon_hl2mpbase.h" + +#if defined( CLIENT_DLL ) +#define CBaseHL2MPCombatWeapon C_BaseHL2MPCombatWeapon +#endif + +class CBaseHL2MPCombatWeapon : public CWeaponHL2MPBase +{ +#if !defined( CLIENT_DLL ) + DECLARE_DATADESC(); +#endif + + DECLARE_CLASS( CBaseHL2MPCombatWeapon, CWeaponHL2MPBase ); +public: + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CBaseHL2MPCombatWeapon(); + + virtual bool WeaponShouldBeLowered( void ); + + virtual bool Ready( void ); + virtual bool Lower( void ); + virtual bool Deploy( void ); + virtual bool Holster( CBaseCombatWeapon *pSwitchingTo ); + virtual void WeaponIdle( void ); + + virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ); + virtual float CalcViewmodelBob( void ); + + virtual Vector GetBulletSpread( WeaponProficiency_t proficiency ); + virtual float GetSpreadBias( WeaponProficiency_t proficiency ); + + virtual const WeaponProficiencyInfo_t *GetProficiencyValues(); + static const WeaponProficiencyInfo_t *GetDefaultProficiencyValues(); + + virtual void ItemHolsterFrame( void ); + +protected: + + bool m_bLowered; // Whether the viewmodel is raised or lowered + float m_flRaiseTime; // If lowered, the time we should raise the viewmodel + float m_flHolsterTime; // When the weapon was holstered + +private: + + CBaseHL2MPCombatWeapon( const CBaseHL2MPCombatWeapon & ); +}; + +#endif // WEAPON_BASEHL2MPCOMBATWEAPON_SHARED_H diff --git a/game/shared/hl2mp/weapon_physcannon.h b/game/shared/hl2mp/weapon_physcannon.h new file mode 100644 index 0000000..03f60f8 --- /dev/null +++ b/game/shared/hl2mp/weapon_physcannon.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_PHYSCANNON_H +#define WEAPON_PHYSCANNON_H +#ifdef _WIN32 +#pragma once +#endif + + + +//----------------------------------------------------------------------------- +// Do we have the super-phys gun? +//----------------------------------------------------------------------------- +bool PlayerHasMegaPhysCannon(); + +// force the physcannon to drop an object (if carried) +void PhysCannonForceDrop( CBaseCombatWeapon *pActiveWeapon, CBaseEntity *pOnlyIfHoldingThis ); +void PhysCannonBeginUpgrade( CBaseAnimating *pAnim ); + +bool PlayerPickupControllerIsHoldingEntity( CBaseEntity *pPickupController, CBaseEntity *pHeldEntity ); +float PlayerPickupGetHeldObjectMass( CBaseEntity *pPickupControllerEntity, IPhysicsObject *pHeldObject ); +float PhysCannonGetHeldObjectMass( CBaseCombatWeapon *pActiveWeapon, IPhysicsObject *pHeldObject ); + +CBaseEntity *PhysCannonGetHeldEntity( CBaseCombatWeapon *pActiveWeapon ); + +#endif // WEAPON_PHYSCANNON_H diff --git a/game/shared/hl2mp/weapon_rpg.h b/game/shared/hl2mp/weapon_rpg.h new file mode 100644 index 0000000..bbd6f2d --- /dev/null +++ b/game/shared/hl2mp/weapon_rpg.h @@ -0,0 +1,267 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPON_RPG_H +#define WEAPON_RPG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "weapon_hl2mpbasehlmpcombatweapon.h" + +#ifdef CLIENT_DLL + + #include "iviewrender_beams.h" + +#endif + +#ifndef CLIENT_DLL +#include "Sprite.h" +#include "npcevent.h" +#include "beam_shared.h" + +class CWeaponRPG; +class CLaserDot; +class RocketTrail; + +//########################################################################### +// >> CMissile (missile launcher class is below this one!) +//########################################################################### +class CMissile : public CBaseCombatCharacter +{ + DECLARE_CLASS( CMissile, CBaseCombatCharacter ); + +public: + CMissile(); + ~CMissile(); + +#ifdef HL1_DLL + Class_T Classify( void ) { return CLASS_NONE; } +#else + Class_T Classify( void ) { return CLASS_MISSILE; } +#endif + + void Spawn( void ); + void Precache( void ); + void MissileTouch( CBaseEntity *pOther ); + void Explode( void ); + void ShotDown( void ); + void AccelerateThink( void ); + void AugerThink( void ); + void IgniteThink( void ); + void SeekThink( void ); + void DumbFire( void ); + void SetGracePeriod( float flGracePeriod ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void Event_Killed( const CTakeDamageInfo &info ); + + virtual float GetDamage() { return m_flDamage; } + virtual void SetDamage(float flDamage) { m_flDamage = flDamage; } + + unsigned int PhysicsSolidMaskForEntity( void ) const; + + CHandle m_hOwner; + + static CMissile *Create( const Vector &vecOrigin, const QAngle &vecAngles, edict_t *pentOwner ); + +protected: + virtual void DoExplosion(); + virtual void ComputeActualDotPosition( CLaserDot *pLaserDot, Vector *pActualDotPosition, float *pHomingSpeed ); + virtual int AugerHealth() { return m_iMaxHealth - 20; } + + // Creates the smoke trail + void CreateSmokeTrail( void ); + + // Gets the shooting position + void GetShootPosition( CLaserDot *pLaserDot, Vector *pShootPosition ); + + CHandle m_hRocketTrail; + float m_flAugerTime; // Amount of time to auger before blowing up anyway + float m_flMarkDeadTime; + float m_flDamage; + +private: + float m_flGracePeriodEndsAt; + + DECLARE_DATADESC(); +}; + + +//----------------------------------------------------------------------------- +// Laser dot control +//----------------------------------------------------------------------------- +CBaseEntity *CreateLaserDot( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot ); +void SetLaserDotTarget( CBaseEntity *pLaserDot, CBaseEntity *pTarget ); +void EnableLaserDot( CBaseEntity *pLaserDot, bool bEnable ); + + +//----------------------------------------------------------------------------- +// Specialized mizzizzile +//----------------------------------------------------------------------------- +class CAPCMissile : public CMissile +{ + DECLARE_CLASS( CMissile, CMissile ); + DECLARE_DATADESC(); + +public: + static CAPCMissile *Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, CBaseEntity *pOwner ); + + CAPCMissile(); + ~CAPCMissile(); + void IgniteDelay( void ); + void AugerDelay( float flDelayTime ); + void ExplodeDelay( float flDelayTime ); + void DisableGuiding(); +#if defined( HL2_DLL ) + virtual Class_T Classify ( void ) { return CLASS_COMBINE; } +#endif + + void AimAtSpecificTarget( CBaseEntity *pTarget ); + void SetGuidanceHint( const char *pHintName ); + + CAPCMissile *m_pNext; + +protected: + virtual void DoExplosion(); + virtual void ComputeActualDotPosition( CLaserDot *pLaserDot, Vector *pActualDotPosition, float *pHomingSpeed ); + virtual int AugerHealth(); + +private: + void Init(); + void ComputeLeadingPosition( const Vector &vecShootPosition, CBaseEntity *pTarget, Vector *pLeadPosition ); + void BeginSeekThink(); + void AugerStartThink(); + void ExplodeThink(); + void APCMissileTouch( CBaseEntity *pOther ); + + float m_flReachedTargetTime; + float m_flIgnitionTime; + bool m_bGuidingDisabled; + float m_flLastHomingSpeed; + EHANDLE m_hSpecificTarget; + string_t m_strHint; +}; + + +//----------------------------------------------------------------------------- +// Finds apc missiles in cone +//----------------------------------------------------------------------------- +CAPCMissile *FindAPCMissileInCone( const Vector &vecOrigin, const Vector &vecDirection, float flAngle ); + +#endif + +//----------------------------------------------------------------------------- +// RPG +//----------------------------------------------------------------------------- + +#ifdef CLIENT_DLL +#define CWeaponRPG C_WeaponRPG +#endif + +class CWeaponRPG : public CBaseHL2MPCombatWeapon +{ + DECLARE_CLASS( CWeaponRPG, CBaseHL2MPCombatWeapon ); +public: + + CWeaponRPG(); + ~CWeaponRPG(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + void Precache( void ); + + void PrimaryAttack( void ); + virtual float GetFireRate( void ) { return 1; }; + void ItemPostFrame( void ); + + void Activate( void ); + void DecrementAmmo( CBaseCombatCharacter *pOwner ); + + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + bool Reload( void ); + bool WeaponShouldBeLowered( void ); + bool Lower( void ); + + bool CanHolster( void ); + + virtual void Drop( const Vector &vecVelocity ); + + int GetMinBurst() { return 1; } + int GetMaxBurst() { return 1; } + float GetMinRestTime() { return 4.0; } + float GetMaxRestTime() { return 4.0; } + + void StartGuiding( void ); + void StopGuiding( void ); + void ToggleGuiding( void ); + bool IsGuiding( void ); + + void NotifyRocketDied( void ); + + bool HasAnyAmmo( void ); + + void SuppressGuiding( bool state = true ); + + void CreateLaserPointer( void ); + void UpdateLaserPosition( Vector vecMuzzlePos = vec3_origin, Vector vecEndPos = vec3_origin ); + Vector GetLaserPosition( void ); + + // NPC RPG users cheat and directly set the laser pointer's origin + void UpdateNPCLaserPosition( const Vector &vecTarget ); + void SetNPCLaserPosition( const Vector &vecTarget ); + const Vector &GetNPCLaserPosition( void ); + +#ifdef CLIENT_DLL + + // We need to render opaque and translucent pieces + virtual RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TWOPASS; } + + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual int DrawModel( int flags ); + virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel ); + virtual bool IsTranslucent( void ); + + void InitBeam( void ); + void GetWeaponAttachment( int attachmentId, Vector &outVector, Vector *dir = NULL ); + void DrawEffects( void ); +// void DrawLaserDot( void ); + + CMaterialReference m_hSpriteMaterial; // Used for the laser glint + CMaterialReference m_hBeamMaterial; // Used for the laser beam + Beam_t *m_pBeam; // Laser beam temp entity + +#endif //CLIENT_DLL + + CBaseEntity *GetMissile( void ) { return m_hMissile; } + +#ifndef CLIENT_DLL + DECLARE_ACTTABLE(); +#endif + +protected: + + CNetworkVar( bool, m_bInitialStateUpdate ); + CNetworkVar( bool, m_bGuiding ); + CNetworkVar( bool, m_bHideGuiding ); + + CNetworkHandle( CBaseEntity, m_hMissile ); + CNetworkVar( Vector, m_vecLaserDot ); + +#ifndef CLIENT_DLL + CHandle m_hLaserDot; +#endif + +private: + + CWeaponRPG( const CWeaponRPG & ); +}; + +#endif // WEAPON_RPG_H diff --git a/game/shared/hl2mp/weapon_slam.h b/game/shared/hl2mp/weapon_slam.h new file mode 100644 index 0000000..0b59bed --- /dev/null +++ b/game/shared/hl2mp/weapon_slam.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: SLAM +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONSLAM_H +#define WEAPONSLAM_H + +#include "basegrenade_shared.h" +#include "weapon_hl2mpbasehlmpcombatweapon.h" + +enum +{ + SLAM_TRIPMINE_READY, + SLAM_SATCHEL_THROW, + SLAM_SATCHEL_ATTACH, +}; + +#ifdef CLIENT_DLL +#define CWeapon_SLAM C_Weapon_SLAM +#endif + +class CWeapon_SLAM : public CBaseHL2MPCombatWeapon +{ +public: + DECLARE_CLASS( CWeapon_SLAM, CBaseHL2MPCombatWeapon ); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CNetworkVar( int, m_tSlamState ); + CNetworkVar( bool, m_bDetonatorArmed ); + CNetworkVar( bool, m_bNeedDetonatorDraw); + CNetworkVar( bool, m_bNeedDetonatorHolster); + CNetworkVar( bool, m_bNeedReload); + CNetworkVar( bool, m_bClearReload); + CNetworkVar( bool, m_bThrowSatchel); + CNetworkVar( bool, m_bAttachSatchel); + CNetworkVar( bool, m_bAttachTripmine); + float m_flWallSwitchTime; + + void Spawn( void ); + void Precache( void ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + void Weapon_Switch( void ); + void SLAMThink( void ); + + void SetPickupTouch( void ); + void SlamTouch( CBaseEntity *pOther ); // default weapon touch + void ItemPostFrame( void ); + bool Reload( void ); + void SetSlamState( int newState ); + bool CanAttachSLAM(void); // In position where can attach SLAM? + bool AnyUndetonatedCharges(void); + void StartTripmineAttach( void ); + void TripmineAttach( void ); + + void StartSatchelDetonate( void ); + void SatchelDetonate( void ); + void StartSatchelThrow( void ); + void StartSatchelAttach( void ); + void SatchelThrow( void ); + void SatchelAttach( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + + CWeapon_SLAM(); + +#ifndef CLIENT_DLL + DECLARE_ACTTABLE(); + DECLARE_DATADESC(); +#endif + +private: + CWeapon_SLAM( const CWeapon_SLAM & ); +}; + + +#endif //WEAPONSLAM_H diff --git a/game/shared/ichoreoeventcallback.h b/game/shared/ichoreoeventcallback.h new file mode 100644 index 0000000..69b98c6 --- /dev/null +++ b/game/shared/ichoreoeventcallback.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef ICHOREOEVENTCALLBACK_H +#define ICHOREOEVENTCALLBACK_H +#ifdef _WIN32 +#pragma once +#endif + +class CChoreoEvent; +class CChoreoChannel; +class CChoreoActor; +class CChoreoScene; + +//----------------------------------------------------------------------------- +// Purpose: During choreo playback, events are triggered by calling back from +// the scene through this interface. +//----------------------------------------------------------------------------- +abstract_class IChoreoEventCallback +{ +public: + virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) = 0; + // Only called for events with HasEndTime() == true + virtual void EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) = 0; + // Called for events which have been started but aren't done yet + virtual void ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) = 0; + // Called for events that are part of a pause condition + virtual bool CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) = 0; +}; + +#endif // ICHOREOEVENTCALLBACK_H diff --git a/game/shared/igamemovement.h b/game/shared/igamemovement.h new file mode 100644 index 0000000..ae24839 --- /dev/null +++ b/game/shared/igamemovement.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( IGAMEMOVEMENT_H ) +#define IGAMEMOVEMENT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "interface.h" +#include "imovehelper.h" +#include "const.h" + +//----------------------------------------------------------------------------- +// Name of the class implementing the game movement. +//----------------------------------------------------------------------------- + +#define INTERFACENAME_GAMEMOVEMENT "GameMovement001" + +//----------------------------------------------------------------------------- +// Forward declarations. +//----------------------------------------------------------------------------- + +class IMoveHelper; + +//----------------------------------------------------------------------------- +// Purpose: Encapsulated input parameters to player movement. +//----------------------------------------------------------------------------- + +class CMoveData +{ +public: + bool m_bFirstRunOfFunctions : 1; + bool m_bGameCodeMovedPlayer : 1; + + EntityHandle_t m_nPlayerHandle; // edict index on server, client entity handle on client + + int m_nImpulseCommand; // Impulse command issued. + QAngle m_vecViewAngles; // Command view angles (local space) + QAngle m_vecAbsViewAngles; // Command view angles (world space) + int m_nButtons; // Attack buttons. + int m_nOldButtons; // From host_client->oldbuttons; + float m_flForwardMove; + float m_flSideMove; + float m_flUpMove; + + float m_flMaxSpeed; + float m_flClientMaxSpeed; + + // Variables from the player edict (sv_player) or entvars on the client. + // These are copied in here before calling and copied out after calling. + Vector m_vecVelocity; // edict::velocity // Current movement direction. + QAngle m_vecAngles; // edict::angles + QAngle m_vecOldAngles; + +// Output only + float m_outStepHeight; // how much you climbed this move + Vector m_outWishVel; // This is where you tried + Vector m_outJumpVel; // This is your jump velocity + + // Movement constraints (radius 0 means no constraint) + Vector m_vecConstraintCenter; + float m_flConstraintRadius; + float m_flConstraintWidth; + float m_flConstraintSpeedFactor; + + void SetAbsOrigin( const Vector &vec ); + const Vector &GetAbsOrigin() const; + +private: + Vector m_vecAbsOrigin; // edict::origin +}; + +inline const Vector &CMoveData::GetAbsOrigin() const +{ + return m_vecAbsOrigin; +} + +#if !defined( CLIENT_DLL ) && defined( _DEBUG ) +// We only ever want this code path on the server side in a debug build +// and you have to uncomment the code below and rebuild to have the test operate. +//#define PLAYER_GETTING_STUCK_TESTING + +#endif + +#if !defined( PLAYER_GETTING_STUCK_TESTING ) + +// This is implemented with a more exhaustive test in gamemovement.cpp. We check if the origin being requested is +// inside solid, which it never should be +inline void CMoveData::SetAbsOrigin( const Vector &vec ) +{ + m_vecAbsOrigin = vec; +} + +#endif + + +//----------------------------------------------------------------------------- +// Purpose: The basic player movement interface +//----------------------------------------------------------------------------- + +abstract_class IGameMovement +{ +public: + virtual ~IGameMovement( void ) {} + + // Process the current movement command + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ) = 0; + virtual void StartTrackPredictionErrors( CBasePlayer *pPlayer ) = 0; + virtual void FinishTrackPredictionErrors( CBasePlayer *pPlayer ) = 0; + virtual void DiffPrint( PRINTF_FORMAT_STRING char const *fmt, ... ) = 0; + + // Allows other parts of the engine to find out the normal and ducked player bbox sizes + virtual Vector GetPlayerMins( bool ducked ) const = 0; + virtual Vector GetPlayerMaxs( bool ducked ) const = 0; + virtual Vector GetPlayerViewOffset( bool ducked ) const = 0; + +}; + + +#endif // IGAMEMOVEMENT_H diff --git a/game/shared/igamesystem.h b/game/shared/igamesystem.h new file mode 100644 index 0000000..6dc9835 --- /dev/null +++ b/game/shared/igamesystem.h @@ -0,0 +1,259 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IGAMESYSTEM_H +#define IGAMESYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Game systems are singleton objects in the client + server codebase responsible for +// various tasks +// The order in which the server systems appear in this list are the +// order in which they are initialized and updated. They are shut down in +// reverse order from which they are initialized. +//----------------------------------------------------------------------------- + + +// UNDONE: Do these need GameInit/GameShutdown as well? +// UNDONE: Remove the Pre/Post entity semantics and rely on system ordering? +// FIXME: Remove all ifdef CLIENT_DLL if we can... +abstract_class IGameSystem +{ +public: + // GameSystems are expected to implement these methods. + virtual char const *Name() = 0; + + // Init, shutdown + // return true on success. false to abort DLL init! + virtual bool Init() = 0; + virtual void PostInit() = 0; + virtual void Shutdown() = 0; + + // Level init, shutdown + virtual void LevelInitPreEntity() = 0; + // entities are created / spawned / precached here + virtual void LevelInitPostEntity() = 0; + + virtual void LevelShutdownPreClearSteamAPIContext() {}; + virtual void LevelShutdownPreEntity() = 0; + // Entities are deleted / released here... + virtual void LevelShutdownPostEntity() = 0; + // end of level shutdown + + // Called during game save + virtual void OnSave() = 0; + + // Called during game restore, after the local player has connected and entities have been fully restored + virtual void OnRestore() = 0; + + // Called every frame. It's safe to remove an igamesystem from within this callback. + virtual void SafeRemoveIfDesired() = 0; + + virtual bool IsPerFrame() = 0; + + // destructor, cleans up automagically.... + virtual ~IGameSystem(); + + // Client systems can use this to get at the map name + static char const* MapName(); + + // These methods are used to add and remove server systems from the + // main server loop. The systems are invoked in the order in which + // they are added. + static void Add ( IGameSystem* pSys ); + static void Remove ( IGameSystem* pSys ); + static void RemoveAll ( ); + + // These methods are used to initialize, shutdown, etc all systems + static bool InitAllSystems(); + static void PostInitAllSystems(); + static void ShutdownAllSystems(); + static void LevelInitPreEntityAllSystems( char const* pMapName ); + static void LevelInitPostEntityAllSystems(); + static void LevelShutdownPreClearSteamAPIContextAllSystems(); // Called prior to steamgameserverapicontext->Clear() + static void LevelShutdownPreEntityAllSystems(); + static void LevelShutdownPostEntityAllSystems(); + + static void OnSaveAllSystems(); + static void OnRestoreAllSystems(); + + static void SafeRemoveIfDesiredAllSystems(); + +#ifdef CLIENT_DLL + static void PreRenderAllSystems(); + static void UpdateAllSystems( float frametime ); + static void PostRenderAllSystems(); +#else + static void FrameUpdatePreEntityThinkAllSystems(); + static void FrameUpdatePostEntityThinkAllSystems(); + static void PreClientUpdateAllSystems(); + + // Accessors for the above function + static CBasePlayer *RunCommandPlayer(); + static CUserCmd *RunCommandUserCmd(); +#endif +}; + +class IGameSystemPerFrame : public IGameSystem +{ +public: + // destructor, cleans up automagically.... + virtual ~IGameSystemPerFrame(); + +#ifdef CLIENT_DLL + // Called before rendering + virtual void PreRender() = 0; + + // Gets called each frame + virtual void Update( float frametime ) = 0; + + // Called after rendering + virtual void PostRender() = 0; +#else + // Called each frame before entities think + virtual void FrameUpdatePreEntityThink() = 0; + // called after entities think + virtual void FrameUpdatePostEntityThink() = 0; + virtual void PreClientUpdate() = 0; +#endif +}; + +// Quick and dirty server system for users who don't care about precise ordering +// and usually only want to implement a few of the callbacks +class CBaseGameSystem : public IGameSystem +{ +public: + + virtual char const *Name() { return "unnamed"; } + + // Init, shutdown + // return true on success. false to abort DLL init! + virtual bool Init() { return true; } + virtual void PostInit() {} + virtual void Shutdown() {} + + // Level init, shutdown + virtual void LevelInitPreEntity() {} + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreClearSteamAPIContext() {} + virtual void LevelShutdownPreEntity() {} + virtual void LevelShutdownPostEntity() {} + + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + + virtual bool IsPerFrame() { return false; } +private: + + // Prevent anyone derived from CBaseGameSystem from implementing these, they need + // to derive from CBaseGameSystemPerFrame below!!! +#ifdef CLIENT_DLL + // Called before rendering + virtual void PreRender() {} + + // Gets called each frame + virtual void Update( float frametime ) {} + + // Called after rendering + virtual void PostRender() {} +#else + // Called each frame before entities think + virtual void FrameUpdatePreEntityThink() {} + // called after entities think + virtual void FrameUpdatePostEntityThink() {} + virtual void PreClientUpdate() {} +#endif +}; + +// Quick and dirty server system for users who don't care about precise ordering +// and usually only want to implement a few of the callbacks +class CBaseGameSystemPerFrame : public IGameSystemPerFrame +{ +public: + virtual char const *Name() { return "unnamed"; } + + // Init, shutdown + // return true on success. false to abort DLL init! + virtual bool Init() { return true; } + virtual void PostInit() {} + virtual void Shutdown() {} + + // Level init, shutdown + virtual void LevelInitPreEntity() {} + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreClearSteamAPIContext() {} + virtual void LevelShutdownPreEntity() {} + virtual void LevelShutdownPostEntity() {} + + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + + virtual bool IsPerFrame() { return true; } + +#ifdef CLIENT_DLL + // Called before rendering + virtual void PreRender () { } + + // Gets called each frame + virtual void Update( float frametime ) { } + + // Called after rendering + virtual void PostRender () { } +#else + // Called each frame before entities think + virtual void FrameUpdatePreEntityThink() { } + // called after entities think + virtual void FrameUpdatePostEntityThink() { } + virtual void PreClientUpdate() { } +#endif +}; + +// Quick and dirty server system for users who don't care about precise ordering +// and usually only want to implement a few of the callbacks +class CAutoGameSystem : public CBaseGameSystem +{ +public: + CAutoGameSystem( char const *name = NULL ); // hooks in at startup, no need to explicitly add + CAutoGameSystem *m_pNext; + + virtual char const *Name() { return m_pszName ? m_pszName : "unnamed"; } + +private: + char const *m_pszName; +}; + +//----------------------------------------------------------------------------- +// Purpose: This is a CAutoGameSystem which also cares about the "per frame" hooks +//----------------------------------------------------------------------------- +class CAutoGameSystemPerFrame : public CBaseGameSystemPerFrame +{ +public: + CAutoGameSystemPerFrame( char const *name = NULL ); + CAutoGameSystemPerFrame *m_pNext; + + virtual char const *Name() { return m_pszName ? m_pszName : "unnamed"; } + +private: + char const *m_pszName; +}; + + +//----------------------------------------------------------------------------- +// Purpose: This interface is here to add more hooks than IGameSystemPerFrame exposes, +// so we don't pollute it with hooks that only the tool cares about +//----------------------------------------------------------------------------- +class IToolFrameworkServer +{ +public: + virtual void PreSetupVisibility() = 0; +}; + +#endif // IGAMESYSTEM_H diff --git a/game/shared/imovehelper.h b/game/shared/imovehelper.h new file mode 100644 index 0000000..a02312d --- /dev/null +++ b/game/shared/imovehelper.h @@ -0,0 +1,115 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMOVEHELPER_H +#define IMOVEHELPER_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +enum PLAYER_ANIM; +class IPhysicsSurfaceProps; +class Vector; +struct model_t; +struct cmodel_t; +struct vcollide_t; +class CGameTrace; +enum soundlevel_t; + +//----------------------------------------------------------------------------- +// Purpose: Identifies how submerged in water a player is. +//----------------------------------------------------------------------------- + +enum +{ + WL_NotInWater=0, + WL_Feet, + WL_Waist, + WL_Eyes +}; + + +//----------------------------------------------------------------------------- +// An entity identifier that works in both game + client dlls +//----------------------------------------------------------------------------- + +typedef CBaseHandle EntityHandle_t; + + +#define INVALID_ENTITY_HANDLE INVALID_EHANDLE_INDEX + +//----------------------------------------------------------------------------- +// Functions the engine provides to IGameMovement to assist in its movement. +//----------------------------------------------------------------------------- + +abstract_class IMoveHelper +{ +public: + // Call this to set the singleton + static IMoveHelper* GetSingleton( ) { return sm_pSingleton; } + + // Methods associated with a particular entity + virtual char const* GetName( EntityHandle_t handle ) const = 0; + + // Adds the trace result to touch list, if contact is not already in list. + virtual void ResetTouchList( void ) = 0; + virtual bool AddToTouched( const CGameTrace& tr, const Vector& impactvelocity ) = 0; + virtual void ProcessImpacts( void ) = 0; + + // Numbered line printf + virtual void Con_NPrintf( int idx, PRINTF_FORMAT_STRING char const* fmt, ... ) = 0; + + // These have separate server vs client impementations + virtual void StartSound( const Vector& origin, int channel, char const* sample, float volume, soundlevel_t soundlevel, int fFlags, int pitch ) = 0; + virtual void StartSound( const Vector& origin, const char *soundname ) = 0; + virtual void PlaybackEventFull( int flags, int clientindex, unsigned short eventindex, float delay, Vector& origin, Vector& angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) = 0; + + // Apply falling damage to m_pHostPlayer based on m_pHostPlayer->m_flFallVelocity. + virtual bool PlayerFallingDamage( void ) = 0; + + // Apply falling damage to m_pHostPlayer based on m_pHostPlayer->m_flFallVelocity. + virtual void PlayerSetAnimation( PLAYER_ANIM playerAnim ) = 0; + + virtual IPhysicsSurfaceProps *GetSurfaceProps( void ) = 0; + + virtual bool IsWorldEntity( const CBaseHandle &handle ) = 0; + +protected: + // Inherited classes can call this to set the singleton + static void SetSingleton( IMoveHelper* pMoveHelper ) { sm_pSingleton = pMoveHelper; } + + // Clients shouldn't call delete directly + virtual ~IMoveHelper() {} + + // The global instance + static IMoveHelper* sm_pSingleton; +}; + +//----------------------------------------------------------------------------- +// Add this to the CPP file that implements the IMoveHelper +//----------------------------------------------------------------------------- + +#define IMPLEMENT_MOVEHELPER() \ + IMoveHelper* IMoveHelper::sm_pSingleton = 0 + +//----------------------------------------------------------------------------- +// Call this to set the singleton +//----------------------------------------------------------------------------- + +inline IMoveHelper* MoveHelper( ) +{ + return IMoveHelper::GetSingleton(); +} + + +#endif // IMOVEHELPER_H diff --git a/game/shared/in_buttons.h b/game/shared/in_buttons.h new file mode 100644 index 0000000..3248685 --- /dev/null +++ b/game/shared/in_buttons.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef IN_BUTTONS_H +#define IN_BUTTONS_H +#ifdef _WIN32 +#pragma once +#endif + +#define IN_ATTACK (1 << 0) +#define IN_JUMP (1 << 1) +#define IN_DUCK (1 << 2) +#define IN_FORWARD (1 << 3) +#define IN_BACK (1 << 4) +#define IN_USE (1 << 5) +#define IN_CANCEL (1 << 6) +#define IN_LEFT (1 << 7) +#define IN_RIGHT (1 << 8) +#define IN_MOVELEFT (1 << 9) +#define IN_MOVERIGHT (1 << 10) +#define IN_ATTACK2 (1 << 11) +#define IN_RUN (1 << 12) +#define IN_RELOAD (1 << 13) +#define IN_ALT1 (1 << 14) +#define IN_ALT2 (1 << 15) +#define IN_SCORE (1 << 16) // Used by client.dll for when scoreboard is held down +#define IN_SPEED (1 << 17) // Player is holding the speed key +#define IN_WALK (1 << 18) // Player holding walk key +#define IN_ZOOM (1 << 19) // Zoom key for HUD zoom +#define IN_WEAPON1 (1 << 20) // weapon defines these bits +#define IN_WEAPON2 (1 << 21) // weapon defines these bits +#define IN_BULLRUSH (1 << 22) +#define IN_GRENADE1 (1 << 23) // grenade 1 +#define IN_GRENADE2 (1 << 24) // grenade 2 +#define IN_ATTACK3 (1 << 25) + +#endif // IN_BUTTONS_H diff --git a/game/shared/interval.h b/game/shared/interval.h new file mode 100644 index 0000000..08f7261 --- /dev/null +++ b/game/shared/interval.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef INTERVAL_H +#define INTERVAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" + + +interval_t ReadInterval( const char *pString ); +float RandomInterval( const interval_t &interval ); + +#endif // INTERVAL_H diff --git a/game/shared/iplayeranimstate.h b/game/shared/iplayeranimstate.h new file mode 100644 index 0000000..5e7b188 --- /dev/null +++ b/game/shared/iplayeranimstate.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IPLAYERANIMSTATE_H +#define IPLAYERANIMSTATE_H +#ifdef _WIN32 +#pragma once +#endif + + + +typedef enum +{ + LEGANIM_9WAY, // Legs use a 9-way blend, with "move_x" and "move_y" pose parameters. + LEGANIM_8WAY, // Legs use an 8-way blend with "move_yaw" pose param. + LEGANIM_GOLDSRC // Legs always point in the direction he's running and the torso rotates. +} LegAnimType_t; + + + +abstract_class IPlayerAnimState +{ +public: + virtual void Release() = 0; + + // Update() and DoAnimationEvent() together maintain the entire player's animation state. + // + // Update() maintains the the lower body animation (the player's m_nSequence) + // and the upper body overlay based on the player's velocity and look direction. + // + // It also modulates these based on events triggered by DoAnimationEvent. + virtual void Update( float eyeYaw, float eyePitch ) = 0; + + // This is called by the client when a new player enters the PVS to clear any events + // the dormant version of the entity may have been playing. + virtual void ClearAnimationState() = 0; + + // The client uses this to figure out what angles to render the entity with (since as the guy turns, + // it will change his body_yaw pose parameter before changing his rendered angle). + virtual const QAngle& GetRenderAngles() = 0; +}; + + +#endif // IPLAYERANIMSTATE_H diff --git a/game/shared/ipredictionsystem.h b/game/shared/ipredictionsystem.h new file mode 100644 index 0000000..e9738bc --- /dev/null +++ b/game/shared/ipredictionsystem.h @@ -0,0 +1,164 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IPREDICTIONSYSTEM_H +#define IPREDICTIONSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "predictable_entity.h" + +class CBaseEntity; + +//----------------------------------------------------------------------------- +// Purpose: Interfaces derived from this are able to filter out the local player +// when doing prediction on the client, this includes not sending network data to +// the local player from the server if needed. +//----------------------------------------------------------------------------- +class IPredictionSystem +{ +public: + IPredictionSystem() + { + m_pNextSystem = g_pPredictionSystems; + g_pPredictionSystems = this; + + m_bSuppressEvent = false; + m_pSuppressHost = NULL; + + m_nStatusPushed = 0; + }; + + virtual ~IPredictionSystem() {}; + + IPredictionSystem *GetNext() + { + return m_pNextSystem; + } + + void SetSuppressEvent( bool state ) + { + m_bSuppressEvent = state; + } + + void SetSuppressHost( CBaseEntity *host ) + { + m_pSuppressHost = host; + } + + CBaseEntity const *GetSuppressHost( void ) + { + if ( DisableFiltering() ) + { + return NULL; + } + + return m_pSuppressHost; + } + + bool CanPredict( void ) const + { + if ( DisableFiltering() ) + { + return false; + } + + return !m_bSuppressEvent; + } + + static IPredictionSystem *g_pPredictionSystems; + + static void SuppressEvents( bool state ) + { + IPredictionSystem *sys = g_pPredictionSystems; + while ( sys ) + { + sys->SetSuppressEvent( state ); + sys = sys->GetNext(); + } + } + + static void SuppressHostEvents( CBaseEntity *host ) + { + IPredictionSystem *sys = g_pPredictionSystems; + while ( sys ) + { + sys->SetSuppressHost( host ); + sys = sys->GetNext(); + } + } + +private: + + static void Push( void ) + { + IPredictionSystem *sys = g_pPredictionSystems; + while ( sys ) + { + sys->_Push(); + sys = sys->GetNext(); + } + } + + static void Pop( void ) + { + IPredictionSystem *sys = g_pPredictionSystems; + while ( sys ) + { + sys->_Pop(); + sys = sys->GetNext(); + } + } + + void _Push( void ) + { + ++m_nStatusPushed; + } + void _Pop( void ) + { + --m_nStatusPushed; + } + + bool DisableFiltering( void ) const + { + return ( m_nStatusPushed > 0 ) ? true : false; + } + + IPredictionSystem *m_pNextSystem; + bool m_bSuppressEvent; + CBaseEntity *m_pSuppressHost; + + int m_nStatusPushed; + + friend class CDisablePredictionFiltering; +}; + +class CDisablePredictionFiltering +{ +public: + CDisablePredictionFiltering( bool disable = true ) + { + m_bDisabled = disable; + if ( m_bDisabled ) + { + IPredictionSystem::Push(); + } + } + + ~CDisablePredictionFiltering( void ) + { + if ( m_bDisabled ) + { + IPredictionSystem::Pop(); + } + } +private: + bool m_bDisabled; +}; + +#endif // IPREDICTIONSYSTEM_H diff --git a/game/shared/iscenetokenprocessor.h b/game/shared/iscenetokenprocessor.h new file mode 100644 index 0000000..4973324 --- /dev/null +++ b/game/shared/iscenetokenprocessor.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISCENETOKENPROCESSOR_H +#define ISCENETOKENPROCESSOR_H +#ifdef _WIN32 +#pragma once +#endif + +abstract_class ISceneTokenProcessor +{ +public: + virtual const char *CurrentToken( void ) = 0; + virtual bool GetToken( bool crossline ) = 0; + virtual bool TokenAvailable( void ) = 0; + virtual void Error( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; +}; + +#endif // ISCENETOKENPROCESSOR_H diff --git a/game/shared/itempents.h b/game/shared/itempents.h new file mode 100644 index 0000000..b5a5ca6 --- /dev/null +++ b/game/shared/itempents.h @@ -0,0 +1,131 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// + +#if !defined( ITEMPENTS_H ) +#define ITEMPENTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ipredictionsystem.h" +#include "shattersurfacetypes.h" +#include "irecipientfilter.h" + +class CEffectData; +class KeyValues; + + +//----------------------------------------------------------------------------- +// Purpose: Shared interface to temp entities +//----------------------------------------------------------------------------- +abstract_class ITempEntsSystem : public IPredictionSystem +{ +public: + virtual void ArmorRicochet( IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir ) = 0; + virtual void BeamEntPoint( IRecipientFilter& filer, float delay, + int nStartEntity, const Vector *start, int nEndEntity, const Vector* end, + int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, + int r, int g, int b, int a, int speed ) = 0; + virtual void BeamEnts( IRecipientFilter& filer, float delay, + int start, int end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, + int r, int g, int b, int a, int speed ) = 0; + virtual void BeamFollow( IRecipientFilter& filter, float delay, + int iEntIndex, int modelIndex, int haloIndex, float life, float width, float endWidth, + float fadeLength, float r, float g, float b, float a ) = 0; + virtual void BeamPoints( IRecipientFilter& filer, float delay, + const Vector* start, const Vector* end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, + int r, int g, int b, int a, int speed ) = 0; + virtual void BeamLaser( IRecipientFilter& filer, float delay, + int start, int end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, int r, int g, int b, int a, int speed ) = 0; + virtual void BeamRing( IRecipientFilter& filer, float delay, + int start, int end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, int spread, float amplitude, int r, int g, int b, int a, int speed, int flags = 0 ) = 0; + virtual void BeamRingPoint( IRecipientFilter& filer, float delay, + const Vector& center, float start_radius, float end_radius, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, int spread, float amplitude, int r, int g, int b, int a, int speed, int flags = 0 ) = 0; + virtual void BeamSpline( IRecipientFilter& filer, float delay, + int points, Vector* rgPoints ) = 0; + virtual void BloodStream( IRecipientFilter& filer, float delay, + const Vector* org, const Vector* dir, int r, int g, int b, int a, int amount ) = 0; + virtual void BloodSprite( IRecipientFilter& filer, float delay, + const Vector* org, const Vector *dir, int r, int g, int b, int a, int size ) = 0; + virtual void BreakModel( IRecipientFilter& filer, float delay, + const Vector& pos, const QAngle &angle, const Vector& size, const Vector& vel, + int modelindex, int randomization, int count, float time, int flags ) = 0; + virtual void BSPDecal( IRecipientFilter& filer, float delay, + const Vector* pos, int entity, int index ) = 0; + virtual void ProjectDecal( IRecipientFilter& filter, float delay, + const Vector* pos, const QAngle *angles, float distance, int index ) = 0; + virtual void Bubbles( IRecipientFilter& filer, float delay, + const Vector* mins, const Vector* maxs, float height, int modelindex, int count, float speed ) = 0; + virtual void BubbleTrail( IRecipientFilter& filer, float delay, + const Vector* mins, const Vector* maxs, float height, int modelindex, int count, float speed ) = 0; + virtual void Decal( IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* start, int entity, int hitbox, int index ) = 0; + virtual void DynamicLight( IRecipientFilter& filer, float delay, + const Vector* org, int r, int g, int b, int exponent, float radius, float time, float decay ) = 0; + virtual void Explosion( IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float scale, int framerate, int flags, int radius, int magnitude, const Vector* normal = NULL, unsigned char materialType = 'C' ) = 0; + virtual void ShatterSurface( IRecipientFilter& filer, float delay, + const Vector* pos, const QAngle* angle, const Vector* vForce, const Vector* vForcePos, + float width, float height, float shardsize, ShatterSurface_t surfacetype, + int front_r, int front_g, int front_b, int back_r, int back_g, int back_b) = 0; + virtual void GlowSprite( IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float life, float size, int brightness ) = 0; + virtual void FootprintDecal( IRecipientFilter& filer, float delay, const Vector *origin, const Vector* right, + int entity, int index, unsigned char materialType ) = 0; + virtual void Fizz( IRecipientFilter& filer, float delay, + const CBaseEntity *ed, int modelindex, int density, int current ) = 0; + virtual void KillPlayerAttachments( IRecipientFilter& filer, float delay, + int player ) = 0; + virtual void LargeFunnel( IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, int reversed ) = 0; + virtual void MetalSparks( IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir ) = 0; + virtual void EnergySplash( IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir, bool bExplosive ) = 0; + virtual void PlayerDecal( IRecipientFilter& filer, float delay, + const Vector* pos, int player, int entity ) = 0; + virtual void ShowLine( IRecipientFilter& filer, float delay, + const Vector* start, const Vector* end ) = 0; + virtual void Smoke( IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float scale, int framerate ) = 0; + virtual void Sparks( IRecipientFilter& filer, float delay, + const Vector* pos, int nMagnitude, int nTrailLength, const Vector *pDir ) = 0; + virtual void Sprite( IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float size, int brightness ) = 0; + virtual void SpriteSpray( IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir, int modelindex, int speed, float noise, int count ) = 0; + virtual void WorldDecal( IRecipientFilter& filer, float delay, + const Vector* pos, int index ) = 0; + virtual void MuzzleFlash( IRecipientFilter& filer, float delay, + const Vector &start, const QAngle &angles, float scale, int type ) = 0; + virtual void Dust( IRecipientFilter& filer, float delay, + const Vector &pos, const Vector &dir, float size, float speed ) = 0; + virtual void GaussExplosion( IRecipientFilter& filer, float delay, + const Vector &pos, const Vector &dir, int type ) = 0; + virtual void DispatchEffect( IRecipientFilter& filter, float delay, + const Vector &pos, const char *pName, const CEffectData &data ) = 0; + virtual void PhysicsProp( IRecipientFilter& filter, float delay, int modelindex, int skin, + const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects ) = 0; + + // For playback from external tools + virtual void TriggerTempEntity( KeyValues *pKeyValues ) = 0; + + virtual void ClientProjectile( IRecipientFilter& filter, float delay, + const Vector* vecOrigin, const Vector* vecVelocity, int modelindex, int lifetime, CBaseEntity *pOwner ) = 0; +}; + +extern ITempEntsSystem *te; + +#endif // ITEMPENTS_H diff --git a/game/shared/mapdata_shared.h b/game/shared/mapdata_shared.h new file mode 100644 index 0000000..93eb290 --- /dev/null +++ b/game/shared/mapdata_shared.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MAPDATA_SHARED_H +#define MAPDATA_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib/vector.h" + +#define INTERFACEVERSION_MAPDATA "MapData001" + +abstract_class IMapData +{ +public: + + // World data queries. + virtual void GetMapBounds( Vector &vecMins, Vector &vecMaxs ) = 0; + virtual void GetMapOrigin( Vector &vecOrigin ) = 0; + virtual void GetMapSize( Vector &vecSize ) = 0; + + // 3D Skybox data queries. + virtual void Get3DSkyboxOrigin( Vector &vecOrigin ) = 0; + virtual float Get3DSkyboxScale( void ) = 0; +}; + +#endif // MAPDATA_SHARED_H \ No newline at end of file diff --git a/game/shared/mapentities_shared.h b/game/shared/mapentities_shared.h new file mode 100644 index 0000000..fee9f0d --- /dev/null +++ b/game/shared/mapentities_shared.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MAPENTITIES_SHARED_H +#define MAPENTITIES_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAPKEY_MAXLENGTH 2048 + + +//----------------------------------------------------------------------------- +// Purpose: encapsulates the data string in the map file +// that is used to initialise entities. The data +// string contains a set of key/value pairs. +//----------------------------------------------------------------------------- +class CEntityMapData +{ +private: + char *m_pEntData; + int m_nEntDataSize; + char *m_pCurrentKey; + +public: + explicit CEntityMapData( char *entBlock, int nEntBlockSize = -1 ) : + m_pEntData(entBlock), m_nEntDataSize(nEntBlockSize), m_pCurrentKey(entBlock) {} + + // find the keyName in the entdata and puts it's value into Value. returns false if key is not found + bool ExtractValue( const char *keyName, char *Value ); + + // find the nth keyName in the endata and change its value to specified one + // where n == nKeyInstance + bool SetValue( const char *keyName, char *NewValue, int nKeyInstance = 0 ); + + bool GetFirstKey( char *keyName, char *Value ); + bool GetNextKey( char *keyName, char *Value ); + + const char *CurrentBufferPosition( void ); +}; + +const char *MapEntity_ParseToken( const char *data, char *newToken ); +const char *MapEntity_SkipToNextEntity( const char *pMapData, char *pWorkBuffer ); +bool MapEntity_ExtractValue( const char *pEntData, const char *keyName, char Value[MAPKEY_MAXLENGTH] ); + + +#endif // MAPENTITIES_SHARED_H diff --git a/game/shared/movetype_push.h b/game/shared/movetype_push.h new file mode 100644 index 0000000..538b23b --- /dev/null +++ b/game/shared/movetype_push.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MOVETYPE_PUSH_H +#define MOVETYPE_PUSH_H +#ifdef _WIN32 +#pragma once +#endif + +const int MAX_PUSHED_ENTITIES = 32; +struct physicspushlist_t +{ + float localMoveTime; + Vector localOrigin; + QAngle localAngles; + int pushedCount; + EHANDLE pushedEnts[MAX_PUSHED_ENTITIES]; + Vector pushVec[MAX_PUSHED_ENTITIES]; +}; + +#endif // MOVETYPE_PUSH_H diff --git a/game/shared/movevars_shared.h b/game/shared/movevars_shared.h new file mode 100644 index 0000000..58412eb --- /dev/null +++ b/game/shared/movevars_shared.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MOVEVARS_SHARED_H +#define MOVEVARS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" + +float GetCurrentGravity( void ); + +extern ConVar sv_gravity; +extern ConVar sv_stopspeed; +extern ConVar sv_noclipaccelerate; +extern ConVar sv_noclipspeed; +extern ConVar sv_maxspeed; +extern ConVar sv_accelerate; +extern ConVar sv_airaccelerate; +extern ConVar sv_wateraccelerate; +extern ConVar sv_waterfriction; +extern ConVar sv_footsteps; +extern ConVar sv_rollspeed; +extern ConVar sv_rollangle; +extern ConVar sv_friction; +extern ConVar sv_bounce; +extern ConVar sv_maxvelocity; +extern ConVar sv_stepsize; +extern ConVar sv_skyname; +extern ConVar sv_backspeed; +extern ConVar sv_waterdist; +extern ConVar sv_specaccelerate; +extern ConVar sv_specspeed; +extern ConVar sv_specnoclip; + +// Vehicle convars +extern ConVar r_VehicleViewDampen; + +// Jeep convars +extern ConVar r_JeepViewDampenFreq; +extern ConVar r_JeepViewDampenDamp; +extern ConVar r_JeepViewZHeight; + +// Airboat convars +extern ConVar r_AirboatViewDampenFreq; +extern ConVar r_AirboatViewDampenDamp; +extern ConVar r_AirboatViewZHeight; + +#endif // MOVEVARS_SHARED_H diff --git a/game/shared/mp_shareddefs.h b/game/shared/mp_shareddefs.h new file mode 100644 index 0000000..c65cbac --- /dev/null +++ b/game/shared/mp_shareddefs.h @@ -0,0 +1,213 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#ifndef MP_SHAREDDEFS_H +#define MP_SHAREDDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +//----------------------------------------------------------------------------- +// TF Concepts +//----------------------------------------------------------------------------- +#define MP_CONCEPT_NONE -1 + +enum +{ + MP_CONCEPT_FIREWEAPON = 0, // "TLK_FIREWEAPON" + MP_CONCEPT_HURT, // "TLK_HURT" + MP_CONCEPT_PLAYER_EXPRESSION, // "TLK_PLAYER_EXPRESSION" + MP_CONCEPT_WINDMINIGUN, // "TLK_WINDMINIGUN" + MP_CONCEPT_FIREMINIGUN, // "TLK_FIREMINIGUN" + MP_CONCEPT_PLAYER_MEDIC, // "TLK_PLAYER_MEDIC" + MP_CONCEPT_DETONATED_OBJECT, // "TLK_DETONATED_OBJECT" + MP_CONCEPT_KILLED_PLAYER, // "TLK_KILLED_PLAYER" + MP_CONCEPT_KILLED_OBJECT, // "TLK_KILLED_OBJECT" + MP_CONCEPT_PLAYER_PAIN, // "TLK_PLAYER_PAIN" + MP_CONCEPT_PLAYER_ATTACKER_PAIN, // "TLK_PLAYER_ATTACKER_PAIN" + MP_CONCEPT_PLAYER_TAUNT, // "TLK_PLAYER_TAUNT" + MP_CONCEPT_PLAYER_HELP, // "TLK_PLAYER_HELP" + MP_CONCEPT_PLAYER_GO, // "TLK_PLAYER_GO" + MP_CONCEPT_PLAYER_MOVEUP, // "TLK_PLAYER_MOVEUP" + MP_CONCEPT_PLAYER_LEFT, // "TLK_PLAYER_LEFT" + MP_CONCEPT_PLAYER_RIGHT, // "TLK_PLAYER_RIGHT" + MP_CONCEPT_PLAYER_YES, // "TLK_PLAYER_YES" + MP_CONCEPT_PLAYER_NO, // "TLK_PLAYER_NO" + MP_CONCEPT_PLAYER_INCOMING, // "TLK_PLAYER_INCOMING" + MP_CONCEPT_PLAYER_CLOAKEDSPY, // "TLK_PLAYER_CLOAKEDSPY" + MP_CONCEPT_PLAYER_SENTRYAHEAD, // "TLK_PLAYER_SENTRYAHEAD" + MP_CONCEPT_PLAYER_TELEPORTERHERE, // "TLK_PLAYER_TELEPORTERHERE" + MP_CONCEPT_PLAYER_DISPENSERHERE, // "TLK_PLAYER_DISPENSERHERE" + MP_CONCEPT_PLAYER_SENTRYHERE, // "TLK_PLAYER_SENTRYHERE" + MP_CONCEPT_PLAYER_ACTIVATECHARGE, // "TLK_PLAYER_ACTIVATECHARGE" + MP_CONCEPT_PLAYER_CHARGEREADY, // "TLK_PLAYER_CHARGEREADY" + MP_CONCEPT_PLAYER_TAUNTS, // "TLK_PLAYER_TAUNTS" + MP_CONCEPT_PLAYER_BATTLECRY, // "TLK_PLAYER_BATTLECRY" + MP_CONCEPT_PLAYER_CHEERS, // "TLK_PLAYER_CHEERS" + MP_CONCEPT_PLAYER_JEERS, // "TLK_PLAYER_JEERS" + MP_CONCEPT_PLAYER_POSITIVE, // "TLK_PLAYER_POSITIVE" + MP_CONCEPT_PLAYER_NEGATIVE, // "TLK_PLAYER_NEGATIVE" + MP_CONCEPT_PLAYER_NICESHOT, // "TLK_PLAYER_NICESHOT" + MP_CONCEPT_PLAYER_GOODJOB, // "TLK_PLAYER_GOODJOB" + MP_CONCEPT_MEDIC_STARTEDHEALING, // "TLK_MEDIC_STARTEDHEALING" + MP_CONCEPT_MEDIC_CHARGEREADY, // "TLK_MEDIC_CHARGEREADY" + MP_CONCEPT_MEDIC_STOPPEDHEALING, // "TLK_MEDIC_STOPPEDHEALING" + MP_CONCEPT_MEDIC_CHARGEDEPLOYED, // "TLK_MEDIC_CHARGEDEPLOYED" + MP_CONCEPT_FLAGPICKUP, // "TLK_FLAGPICKUP" + MP_CONCEPT_FLAGCAPTURED, // "TLK_FLAGCAPTURED" + MP_CONCEPT_ROUND_START, // "TLK_ROUND_START" + MP_CONCEPT_SUDDENDEATH_START, // "TLK_SUDDENDEATH_START" + MP_CONCEPT_ONFIRE, // "TLK_ONFIRE" + MP_CONCEPT_STALEMATE, // "TLK_STALEMATE" + MP_CONCEPT_BUILDING_OBJECT, // "TLK_BUILDING_OBJECT" + MP_CONCEPT_LOST_OBJECT, // "TLK_LOST_OBJECT" + MP_CONCEPT_SPY_SAPPER, // "TLK_SPY_SAPPER" + MP_CONCEPT_TELEPORTED, // "TLK_TELEPORTED" + MP_CONCEPT_LOST_CONTROL_POINT, // "TLK_LOST_CONTROL_POINT" + MP_CONCEPT_CAPTURED_POINT, // "TLK_CAPTURED_POINT" + MP_CONCEPT_CAPTURE_BLOCKED, // "TLK_CAPTURE_BLOCKED" + MP_CONCEPT_HEALTARGET_STARTEDHEALING, // "TLK_HEALTARGET_STARTEDHEALING" + MP_CONCEPT_HEALTARGET_CHARGEREADY, // "TLK_HEALTARGET_CHARGEREADY" + MP_CONCEPT_HEALTARGET_STOPPEDHEALING, // "TLK_HEALTARGET_STOPPEDHEALING" + MP_CONCEPT_HEALTARGET_CHARGEDEPLOYED, // "TLK_HEALTARGET_CHARGEDEPLOYED" + MP_CONCEPT_MINIGUN_FIREWEAPON, // "TLK_MINIGUN_FIREWEAPON" + MP_CONCEPT_DIED, // "TLK_DIED" + MP_CONCEPT_PLAYER_THANKS, // "TLK_PLAYER_THANKS" + MP_CONCEPT_CART_MOVING_FORWARD, // "TLK_CART_MOVING_FORWARD" + MP_CONCEPT_CART_MOVING_BACKWARD, // "TLK_CART_MOVING_BACKWARD" + MP_CONCEPT_CART_STOP, // "TLK_CART_STOP" + MP_CONCEPT_ATE_FOOD, // "TLK_ATE_FOOD" + MP_CONCEPT_DOUBLE_JUMP, // "TLK_DOUBLE_JUMP" + MP_CONCEPT_DODGING, // "TLK_DODGING" + MP_CONCEPT_DODGE_SHOT, // "TLK_DODGE_SHOT" + MP_CONCEPT_GRAB_BALL, // "TLK_GRAB_BALL" + MP_CONCEPT_REGEN_BALL, // "TLK_REGEN_BALL" + MP_CONCEPT_DEFLECTED, // "TLK_DEFLECTED" + MP_CONCEPT_BALL_MISSED, // "TLK_BALL_MISSED" + MP_CONCEPT_STUNNED, // "TLK_STUNNED" + MP_CONCEPT_STUNNED_TARGET, // "TLK_STUNNED_TARGET" + MP_CONCEPT_TIRED, // "TLK_TIRED" + MP_CONCEPT_BAT_BALL, // "TLK_BAT_BALL" + MP_CONCEPT_ACHIEVEMENT_AWARD, // "TLK_ACHIEVEMENT_AWARD" + MP_CONCEPT_JARATE_HIT, // "TLK_JARATE_HIT" + MP_CONCEPT_JARATE_LAUNCH, // "TLK_JARATE_LAUNCH" + MP_CONCEPT_HIGHFIVE_SUCCESS, // "TLK_HIGHFIVE_SUCCESS" + MP_CONCEPT_HIGHFIVE_SUCCESS_FULL, // "TLK_HIGHFIVE_SUCCESS_FULL" + MP_CONCEPT_HIGHFIVE_FAILURE, // "TLK_HIGHFIVE_FAILURE" + MP_CONCEPT_HIGHFIVE_FAILURE_FULL, // "TLK_HIGHFIVE_FAILURE_FULL" + MP_CONCEPT_PLAYER_TAUNT2, // "TLK_PLAYER_TAUNT2" + MP_CONCEPT_PICKUP_BUILDING, // "TLK_PICKUP_BUILDING" + MP_CONCEPT_REDEPLOY_BUILDING, // "TLK_REDEPLOY_BUILDING" + MP_CONCEPT_CARRYING_BUILDING, // "TLK_CARRYING_BUILDING" + MP_CONCEPT_DUEL_REQUEST, // "TLK_REQUEST_DUEL" + MP_CONCEPT_DUEL_TARGET_REJECT, // "TLK_REJECT_DUEL" + MP_CONCEPT_DUEL_REJECTED, // "TLK_DUEL_WAS_REJECTED" + MP_CONCEPT_DUEL_TARGET_ACCEPT, // "TLK_ACCEPT_DUEL" + MP_CONCEPT_DUEL_ACCEPTED, // "TLK_DUEL_WAS_ACCEPTED" + MP_CONCEPT_PLAYER_SHOW_ITEM_TAUNT, // "TLK_PLAYER_SHOW_ITEM_TAUNT" + MP_CONCEPT_TAUNT_REPLAY, // "TLK_TAUNT_REPLAY" + MP_CONCEPT_TAUNT_LAUGH, // "TLK_TAUNT_LAUGH" + MP_CONCEPT_TAUNT_HEROIC_POSE, // "TLK_TAUNT_HEROIC_POSE" + MP_CONCEPT_PARTNER_TAUNT_READY, // "TLK_PARTNER_TAUNT_READY" + MP_CONCEPT_HOLDTAUNT, // "TLK_PLAYER_HOLDTAUNT" + MP_CONCEPT_TAUNT_PYRO_ARMAGEDDON, // "TLK_TAUNT_PYRO_ARMAGEDDON" + MP_CONCEPT_ROCKET_DESTOYED, // "TLK_ROCKET_DESTOYED" + MP_CONCEPT_MVM_BOMB_DROPPED, // "TLK_MVM_BOMB_DROPPED" + MP_CONCEPT_MVM_BOMB_CARRIER_UPGRADE1, // "TLK_MVM_BOMB_CARRIER_UPGRADE1" + MP_CONCEPT_MVM_BOMB_CARRIER_UPGRADE2, // "TLK_MVM_BOMB_CARRIER_UPGRADE2" + MP_CONCEPT_MVM_BOMB_CARRIER_UPGRADE3, // "TLK_MVM_BOMB_CARRIER_UPGRADE3" + MP_CONCEPT_MVM_DEFENDER_DIED, // "TLK_MVM_DEFENDER_DIED" + MP_CONCEPT_MVM_FIRST_BOMB_PICKUP, // "TLK_MVM_FIRST_BOMB_PICKUP" + MP_CONCEPT_MVM_BOMB_PICKUP, // "TLK_MVM_BOMB_PICKUP" + MP_CONCEPT_MVM_SENTRY_BUSTER, // "TLK_MVM_SENTRY_BUSTER" + MP_CONCEPT_MVM_SENTRY_BUSTER_DOWN, // "TLK_MVM_SENTRY_BUSTER_DOWN" + MP_CONCEPT_MVM_SNIPER_CALLOUT, // "TLK_MVM_SNIPER_CALLOUT" + MP_CONCEPT_MVM_LAST_MAN_STANDING, // "TLK_MVM_LAST_MAN_STANDING" + MP_CONCEPT_MVM_ENCOURAGE_MONEY, // "TLK_MVM_ENCOURAGE_MONEY" + MP_CONCEPT_MVM_MONEY_PICKUP, // "TLK_MVM_MONEY_PICKUP" + MP_CONCEPT_MVM_ENCOURAGE_UPGRADE, // "TLK_MVM_ENCOURAGE_UPGRADE" + MP_CONCEPT_MVM_UPGRADE_COMPLETE, // "TLK_MVM_UPGRADE_COMPLETE" + MP_CONCEPT_MVM_GIANT_CALLOUT, // "TLK_MVM_GIANT_CALLOUT" + MP_CONCEPT_MVM_GIANT_HAS_BOMB, // "TLK_MVM_GIANT_HAS_BOMB" + MP_CONCEPT_MVM_GIANT_KILLED, // "TLK_MVM_GIANT_KILLED" + MP_CONCEPT_MVM_GIANT_KILLED_TEAMMATE, // "TLK_MVM_GIANT_KILLED_TEAMMATE" + MP_CONCEPT_MVM_SAPPED_ROBOT, // "TLK_MVM_SAPPED_ROBOT" + MP_CONCEPT_MVM_CLOSE_CALL, // "TLK_MVM_CLOSE_CALL" + MP_CONCEPT_MVM_TANK_CALLOUT, // "TLK_MVM_TANK_CALLOUT" + MP_CONCEPT_MVM_TANK_DEAD, // "TLK_MVM_TANK_DEAD" + MP_CONCEPT_MVM_TANK_DEPLOYING, // "TLK_MVM_TANK_DEPLOYING" + MP_CONCEPT_MVM_ATTACK_THE_TANK, // "TLK_MVM_ATTACK_THE_TANK" + MP_CONCEPT_MVM_TAUNT, // "TLK_MVM_TAUNT" + MP_CONCEPT_MVM_WAVE_START, // "TLK_MVM_WAVE_START" + MP_CONCEPT_MVM_WAVE_WIN, // "TLK_MVM_WAVE_WIN" + MP_CONCEPT_MVM_WAVE_LOSE, // "TLK_MVM_WAVE_LOSE" + MP_CONCEPT_MVM_DEPLOY_RAGE, // "TLK_MVM_DEPLOY_RAGE" + MP_CONCEPT_MAGIC_BIGHEAD, // "TLK_MAGIC_BIGHEAD" + MP_CONCEPT_MAGIC_SMALLHEAD, // "TLK_MAGIC_SMALLHEAD" + MP_CONCEPT_MAGIC_GRAVITY, // "TLK_MAGIC_GRAVITY" + MP_CONCEPT_MAGIC_GOOD, // "TLK_MAGIC_GOOD" + MP_CONCEPT_MAGIC_DANCE, // "TLK_MAGIC_DANCE" + MP_CONCEPT_HALLOWEEN_LONGFALL, + MP_CONCEPT_TAUNT_GUITAR_RIFF, // "TLK_TAUNT_GUITAR_RIFF" + + // TF Halloween 2013 shenanigans. + MP_CONCEPT_PLAYER_CAST_FIREBALL, // "TLK_PLAYER_CAST_FIREBALL" + MP_CONCEPT_PLAYER_CAST_MERASMUS_ZAP, // "TLK_PLAYER_CAST_MERASMUS_ZAP" + MP_CONCEPT_PLAYER_CAST_SELF_HEAL, // "TLK_PLAYER_CAST_SELF_HEAL" + MP_CONCEPT_PLAYER_CAST_MIRV, // "TLK_PLAYER_CAST_MIRV" + MP_CONCEPT_PLAYER_CAST_BLAST_JUMP, // "TLK_PLAYER_CAST_BLAST_JUMP" + MP_CONCEPT_PLAYER_CAST_STEALTH, // "TLK_PLAYER_CAST_STEALTH" + MP_CONCEPT_PLAYER_CAST_TELEPORT, // "TLK_PLAYER_CAST_TELEPORT" + MP_CONCEPT_PLAYER_CAST_LIGHTNING_BALL, // "TLK_PLAYER_CAST_LIGHTNING_BALL" + MP_CONCEPT_PLAYER_CAST_MOVEMENT_BUFF, // "TLK_PLAYER_CAST_MOVEMENT_BUFF" + MP_CONCEPT_PLAYER_CAST_MONOCULOUS, // "TLK_PLAYER_CAST_MONOCULOUS" + MP_CONCEPT_PLAYER_CAST_METEOR_SWARM, // "TLK_PLAYER_CAST_METEOR_SWARM" + MP_CONCEPT_PLAYER_CAST_SKELETON_HORDE, // "TLK_PLAYER_CAST_SKELETON_HORDE" + MP_CONCEPT_PLAYER_CAST_BOMB_HEAD_CURSE, // "TLK_PLAYER_CAST_BOMB_HEAD_CURSE" + + MP_CONCEPT_PLAYER_SPELL_FIREBALL, // "TLK_PLAYER_SPELL_FIREBALL" + MP_CONCEPT_PLAYER_SPELL_MERASMUS_ZAP, // "TLK_PLAYER_SPELL_MERASMUS_ZAP" + MP_CONCEPT_PLAYER_SPELL_SELF_HEAL, // "TLK_PLAYER_SPELL_SELF_HEAL" + MP_CONCEPT_PLAYER_SPELL_MIRV, // "TLK_PLAYER_SPELL_MIRV" + MP_CONCEPT_PLAYER_SPELL_BLAST_JUMP, // "TLK_PLAYER_SPELL_BLAST_JUMP" + MP_CONCEPT_PLAYER_SPELL_STEALTH, // "TLK_PLAYER_SPELL_STEALTH" + MP_CONCEPT_PLAYER_SPELL_TELEPORT, // "TLK_PLAYER_SPELL_TELEPORT" + MP_CONCEPT_PLAYER_SPELL_LIGHTNING_BALL, // "TLK_PLAYER_SPELL_LIGHTNING_BALL" + MP_CONCEPT_PLAYER_SPELL_MOVEMENT_BUFF, // "TLK_PLAYER_SPELL_MOVEMENT_BUFF" + MP_CONCEPT_PLAYER_SPELL_MONOCULOUS, // "TLK_PLAYER_SPELL_MONOCULOUS" + MP_CONCEPT_PLAYER_SPELL_METEOR_SWARM, // "TLK_PLAYER_SPELL_METEOR_SWARM" + MP_CONCEPT_PLAYER_SPELL_SKELETON_HORDE, // "TLK_PLAYER_SPELL_SKELETON_HORDE" + MP_CONCEPT_PLAYER_SPELL_BOMB_HEAD_CURSE, // "TLK_PLAYER_SPELL_BOMB_HEAD_CURSE" + + // Events. + MP_CONCEPT_PLAYER_SPELL_PICKUP_COMMON, // "TLK_PLAYER_SPELL_PICKUP_COMMON" + MP_CONCEPT_PLAYER_SPELL_PICKUP_RARE, // "TLK_PLAYER_SPELL_PICKUP_RARE" + MP_CONCEPT_PLAYER_HELLTOWER_MIDNIGHT, // "TLK_PLAYER_HELLTOWER_MIDNIGHT" + MP_CONCEPT_PLAYER_SKELETON_KING_APPEAR, // "TLK_PLAYER_SKELETON_KING_APPEAR" + + MP_CONCEPT_MANNHATTAN_GATE_ATK, // "TLK_MANNHATTAN_GATE_ATK" + MP_CONCEPT_MANNHATTAN_GATE_TAKE, // "TLK_MANNHATTAN_GATE_TAKE" + MP_CONCEPT_RESURRECTED, // "TLK_RESURRECTED" + MP_CONCEPT_MVM_LOOT_COMMON, // "TLK_MVM_LOOT_COMMON" + MP_CONCEPT_MVM_LOOT_RARE, // "TLK_MVM_LOOT_RARE" + MP_CONCEPT_MVM_LOOT_ULTRARARE, // "TLK_MVM_LOOT_ULTRARARE" + MP_CONCEPT_MEDIC_HEAL_SHIELD, // "TLK_MEDIC_HEAL_SHIELD" + + MP_CONCEPT_TAUNT_EUREKA_EFFECT_TELEPORT,// "TLK_TAUNT_EUREKA_EFFECT" + + MP_CONCEPT_COMBO_KILLED, // "TLK_COMBO_KILLED" + MP_CONCEPT_PLAYER_ASK_FOR_BALL, // "TLK_PLAYER_ASK_FOR_BALL" + + MP_TF_CONCEPT_COUNT + + // Other MP_CONCEPT_* start he using MP_TF_CONCEPT_COUNT + 1 as start. +}; + +extern const char *g_pszMPConcepts[]; +int GetMPConceptIndexFromString( const char *pszConcept ); + +#endif // MP_SHAREDDEFS_H diff --git a/game/shared/multiplay_gamerules.h b/game/shared/multiplay_gamerules.h new file mode 100644 index 0000000..b74dd34 --- /dev/null +++ b/game/shared/multiplay_gamerules.h @@ -0,0 +1,288 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MULTIPLAY_GAMERULES_H +#define MULTIPLAY_GAMERULES_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "gamerules.h" + +#ifdef CLIENT_DLL + + #define CMultiplayRules C_MultiplayRules + +#else + +extern ConVar mp_restartgame; +extern ConVar mp_restartgame_immediate; +extern ConVar mp_waitingforplayers_time; +extern ConVar mp_waitingforplayers_restart; +extern ConVar mp_waitingforplayers_cancel; +extern ConVar mp_clan_readyrestart; +extern ConVar mp_clan_ready_signal; +extern ConVar nextlevel; +extern INetworkStringTable *g_pStringTableServerMapCycle; + +#if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL ) +extern INetworkStringTable *g_pStringTableServerPopFiles; +extern INetworkStringTable *g_pStringTableServerMapCycleMvM; +#endif + +#define VOICE_COMMAND_MAX_SUBTITLE_DIST 1900 + +class CBaseMultiplayerPlayer; + +#endif + +extern ConVar mp_show_voice_icons; + +#define MAX_SPEAK_CONCEPT_LEN 64 +#define MAX_VOICE_COMMAND_SUBTITLE 256 + +typedef struct +{ +#ifndef CLIENT_DLL + // concept to speak + int m_iConcept; + + // play subtitle? + bool m_bShowSubtitle; + bool m_bDistanceBasedSubtitle; + + char m_szGestureActivity[64]; + +#else + // localizable subtitle + char m_szSubtitle[MAX_VOICE_COMMAND_SUBTITLE]; + + // localizable string for menu + char m_szMenuLabel[MAX_VOICE_COMMAND_SUBTITLE]; +#endif + +} VoiceCommandMenuItem_t; + +extern ConVar mp_timelimit; + +//========================================================= +// CMultiplayRules - rules for the basic half life multiplayer +// competition +//========================================================= +class CMultiplayRules : public CGameRules +{ +public: + DECLARE_CLASS( CMultiplayRules, CGameRules ); + +// Functions to verify the single/multiplayer status of a game + virtual bool IsMultiplayer( void ); + + virtual bool Init(); + + // Damage query implementations. + virtual bool Damage_IsTimeBased( int iDmgType ); // Damage types that are time-based. + virtual bool Damage_ShouldGibCorpse( int iDmgType ); // Damage types that gib the corpse. + virtual bool Damage_ShowOnHUD( int iDmgType ); // Damage types that have client HUD art. + virtual bool Damage_NoPhysicsForce( int iDmgType ); // Damage types that don't have to supply a physics force & position. + virtual bool Damage_ShouldNotBleed( int iDmgType ); // Damage types that don't make the player bleed. + // TEMP: These will go away once DamageTypes become enums. + virtual int Damage_GetTimeBased( void ); + virtual int Damage_GetShouldGibCorpse( void ); + virtual int Damage_GetShowOnHud( void ); + virtual int Damage_GetNoPhysicsForce( void ); + virtual int Damage_GetShouldNotBleed( void ); + + CMultiplayRules(); + virtual ~CMultiplayRules() {} + + void LoadVoiceCommandScript( void ); + + virtual bool ShouldDrawHeadLabels() + { + if ( mp_show_voice_icons.GetBool() == false ) + return false; + + return BaseClass::ShouldDrawHeadLabels(); + } + +#ifndef CLIENT_DLL + virtual void FrameUpdatePostEntityThink(); + +// GR_Think + virtual void Think( void ); + virtual void RefreshSkillData( bool forceUpdate ); + virtual bool IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual bool FAllowFlashlight( void ); + + virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ); + virtual CBaseCombatWeapon *GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); + virtual bool SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual bool IsDeathmatch( void ); + virtual bool IsCoOp( void ); + +// Client connection/disconnection + // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in + // svRejectReason + // Only the client's name and remote address are provided to the dll for verification. + virtual bool ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + virtual bool FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker, const CTakeDamageInfo &info ); + virtual bool AllowDamage( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual bool FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + virtual CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); + + virtual bool AllowAutoTargetCrosshair( void ); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + CBasePlayer *GetDeathScorer( CBaseEntity *pKiller, CBaseEntity *pInflictor ); // old version of method - kept for backward compat + virtual CBasePlayer *GetDeathScorer( CBaseEntity *pKiller, CBaseEntity *pInflictor, CBaseEntity *pVictim ); // new version of method + +// Weapon retrieval + virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );// The player is touching an CBaseCombatWeapon, do I give it to him? + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon ); + virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ); + virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon ); + +// Item retrieval + virtual bool CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + virtual QAngle VecItemRespawnAngles( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBaseCombatCharacter *pPlayer, char *szName, int iCount ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + virtual float FlHEVChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual bool PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker ); + + virtual bool PlayTextureSounds( void ) { return FALSE; } + virtual bool PlayFootstepSounds( CBasePlayer *pl ); + +// NPCs + virtual bool FAllowNPCs( void ); + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) { GoToIntermission(); } + +// Voice commands + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + virtual VoiceCommandMenuItem_t *VoiceCommand( CBaseMultiplayerPlayer *pPlayer, int iMenu, int iItem ); + +// Bugbait report + bool IsLoadingBugBaitReport( void ); + + virtual void ResetMapCycleTimeStamp( void ){ m_nMapCycleTimeStamp = 0; } + + virtual void HandleTimeLimitChange( void ){ return; } + + void IncrementMapCycleIndex(); + + void HaveAllPlayersSpeakConceptIfAllowed( int iConcept, int iTeam = TEAM_UNASSIGNED, const char *modifiers = NULL ); + void RandomPlayersSpeakConceptIfAllowed( int iConcept, int iNumRandomPlayer = 1, int iTeam = TEAM_UNASSIGNED, const char *modifiers = NULL ); + + virtual void GetTaggedConVarList( KeyValues *pCvarTagList ); + + void SkipNextMapInCycle(); + + virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ); + +public: + + struct ResponseRules_t + { + CUtlVector m_ResponseSystems; + }; + CUtlVector m_ResponseRules; + + virtual void InitCustomResponseRulesDicts() {} + virtual void ShutdownCustomResponseRulesDicts() {} + + // NVNT virtual to check for haptic device + virtual void ClientSettingsChanged( CBasePlayer *pPlayer ); + virtual void GetNextLevelName( char *szNextMap, int bufsize, bool bRandom = false ); + + static void DetermineMapCycleFilename( char *pszResult, int nSizeResult, bool bForceSpew ); + virtual void LoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector &mapList ); + static void FreeMapCycleFileVector ( CUtlVector &mapList ); + + // LoadMapCycleFileIntoVector without the fixups inherited versions of gamerules may provide + static void RawLoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector &mapList ); + + bool IsMapInMapCycle( const char *pszName ); + + virtual bool IsManualMapChangeOkay( const char **pszReason ) OVERRIDE; + +protected: + virtual bool UseSuicidePenalty() { return true; } // apply point penalty for suicide? + virtual float GetLastMajorEventTime( void ){ return -1.0f; } + +public: + virtual void ChangeLevel( void ); + +protected: + virtual void GoToIntermission( void ); + virtual void LoadMapCycleFile( void ); + void ChangeLevelToMap( const char *pszMap ); + + float m_flIntermissionEndTime; + static int m_nMapCycleTimeStamp; + static int m_nMapCycleindex; + static CUtlVector m_MapList; + + float m_flTimeLastMapChangeOrPlayerWasConnected; + +#else + + public: + const char *GetVoiceCommandSubtitle( int iMenu, int iItem ); + bool GetVoiceMenuLabels( int iMenu, KeyValues *pKV ); + +#endif + + private: + CUtlVector< CUtlVector< VoiceCommandMenuItem_t > > m_VoiceCommandMenus; +}; + +inline CMultiplayRules* MultiplayRules() +{ + return static_cast(g_pGameRules); +} + +#endif // MULTIPLAY_GAMERULES_H diff --git a/game/shared/npcevent.h b/game/shared/npcevent.h new file mode 100644 index 0000000..8f681ab --- /dev/null +++ b/game/shared/npcevent.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NPCEVENT_H +#define NPCEVENT_H +#ifdef _WIN32 +#pragma once +#endif + +class CBaseAnimating; + +struct animevent_t +{ + int event; + const char *options; + float cycle; + float eventtime; + int type; + CBaseAnimating *pSource; +}; +#define EVENT_SPECIFIC 0 +#define EVENT_SCRIPTED 1000 // see scriptevent.h +#define EVENT_SHARED 2000 +#define EVENT_WEAPON 3000 +#define EVENT_CLIENT 5000 + +#define NPC_EVENT_BODYDROP_LIGHT 2001 +#define NPC_EVENT_BODYDROP_HEAVY 2002 + +#define NPC_EVENT_SWISHSOUND 2010 + +#define NPC_EVENT_180TURN 2020 + +#define NPC_EVENT_ITEM_PICKUP 2040 +#define NPC_EVENT_WEAPON_DROP 2041 +#define NPC_EVENT_WEAPON_SET_SEQUENCE_NAME 2042 +#define NPC_EVENT_WEAPON_SET_SEQUENCE_NUMBER 2043 +#define NPC_EVENT_WEAPON_SET_ACTIVITY 2044 + +#define NPC_EVENT_LEFTFOOT 2050 +#define NPC_EVENT_RIGHTFOOT 2051 + +#define NPC_EVENT_OPEN_DOOR 2060 + +// !! DON'T CHANGE TO ORDER OF THESE. THEY ARE HARD CODED IN THE WEAPON QC FILES (YUCK!) !! +#define EVENT_WEAPON_MELEE_HIT 3001 +#define EVENT_WEAPON_SMG1 3002 +#define EVENT_WEAPON_MELEE_SWISH 3003 +#define EVENT_WEAPON_SHOTGUN_FIRE 3004 +#define EVENT_WEAPON_THROW 3005 +#define EVENT_WEAPON_AR1 3006 +#define EVENT_WEAPON_AR2 3007 +#define EVENT_WEAPON_HMG1 3008 +#define EVENT_WEAPON_SMG2 3009 +#define EVENT_WEAPON_MISSILE_FIRE 3010 +#define EVENT_WEAPON_SNIPER_RIFLE_FIRE 3011 +#define EVENT_WEAPON_AR2_GRENADE 3012 +#define EVENT_WEAPON_THROW2 3013 +#define EVENT_WEAPON_PISTOL_FIRE 3014 +#define EVENT_WEAPON_RELOAD 3015 +#define EVENT_WEAPON_THROW3 3016 +#define EVENT_WEAPON_RELOAD_SOUND 3017 // Use this + EVENT_WEAPON_RELOAD_FILL_CLIP to prevent shooting during the reload animation +#define EVENT_WEAPON_RELOAD_FILL_CLIP 3018 +#define EVENT_WEAPON_SMG1_BURST1 3101 // first round in a 3-round burst +#define EVENT_WEAPON_SMG1_BURSTN 3102 // 2, 3 rounds +#define EVENT_WEAPON_AR2_ALTFIRE 3103 + +#define EVENT_WEAPON_SEQUENCE_FINISHED 3900 + +// NOTE: MUST BE THE LAST WEAPON EVENT -- ONLY WEAPON EVENTS BETWEEN EVENT_WEAPON AND THIS +#define EVENT_WEAPON_LAST 3999 + +#endif // NPCEVENT_H diff --git a/game/shared/obstacle_pushaway.h b/game/shared/obstacle_pushaway.h new file mode 100644 index 0000000..4a63fc5 --- /dev/null +++ b/game/shared/obstacle_pushaway.h @@ -0,0 +1,187 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef OBSTACLE_PUSHAWAY_H +#define OBSTACLE_PUSHAWAY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "props_shared.h" +#ifndef CLIENT_DLL +#include "func_breakablesurf.h" +#include "BasePropDoor.h" +#include "doors.h" +#endif // CLIENT_DLL + +//-------------------------------------------------------------------------------------------------------------- +bool IsPushAwayEntity( CBaseEntity *pEnt ); +bool IsPushableEntity( CBaseEntity *pEnt ); + +//-------------------------------------------------------------------------------------------------------------- +#ifndef CLIENT_DLL +bool IsBreakableEntity( CBaseEntity *pEnt ); +#endif // !CLIENT_DLL + +//-------------------------------------------------------------------------------------------------------------- +class CPushAwayEnumerator : public IPartitionEnumerator +{ +public: + // Forced constructor + CPushAwayEnumerator(CBaseEntity **ents, int nMaxEnts) + { + m_nAlreadyHit = 0; + m_AlreadyHit = ents; + m_nMaxHits = nMaxEnts; + } + + // Actual work code + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) + { +#ifdef CLIENT_DLL + CBaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); +#else + CBaseEntity *pEnt = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() ); +#endif // CLIENT_DLL + + if ( IsPushAwayEntity( pEnt ) && m_nAlreadyHit < m_nMaxHits ) + { + m_AlreadyHit[m_nAlreadyHit] = pEnt; + m_nAlreadyHit++; + } + + return ITERATION_CONTINUE; + } + +public: + + CBaseEntity **m_AlreadyHit; + int m_nAlreadyHit; + int m_nMaxHits; +}; + + +#ifndef CLIENT_DLL +//-------------------------------------------------------------------------------------------------------------- +/** + * This class will collect breakable objects in a volume. Physics props that can be damaged, func_breakable*, etc + * are all collected by this class. + */ +class CBotBreakableEnumerator : public CPushAwayEnumerator +{ +public: + CBotBreakableEnumerator(CBaseEntity **ents, int nMaxEnts) : CPushAwayEnumerator(ents, nMaxEnts) + { + } + + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) + { + CBaseEntity *pEnt = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() ); + + if ( !IsBreakableEntity( pEnt ) ) + return ITERATION_CONTINUE; + + // ignore breakables parented to doors + if ( pEnt->GetParent() && + ( FClassnameIs( pEnt->GetParent(), "func_door*" ) || + FClassnameIs( pEnt, "prop_door*" ) ) ) + return ITERATION_CONTINUE; + + if ( m_nAlreadyHit < m_nMaxHits ) + { + m_AlreadyHit[m_nAlreadyHit] = pEnt; + m_nAlreadyHit++; + } + + return ITERATION_CONTINUE; + } +}; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * This class will collect door objects in a volume. + */ +class CBotDoorEnumerator : public CPushAwayEnumerator +{ +public: + CBotDoorEnumerator(CBaseEntity **ents, int nMaxEnts) : CPushAwayEnumerator(ents, nMaxEnts) + { + } + + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) + { + CBaseEntity *pEnt = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() ); + + if ( pEnt == NULL ) + return ITERATION_CONTINUE; + + if ( ( pEnt->ObjectCaps() & FCAP_IMPULSE_USE ) == 0 ) + { + return ITERATION_CONTINUE; + } + + if ( FClassnameIs( pEnt, "func_door*" ) ) + { + CBaseDoor *door = dynamic_cast(pEnt); + if ( !door ) + { + return ITERATION_CONTINUE; + } + + if ( door->m_toggle_state == TS_GOING_UP || door->m_toggle_state == TS_GOING_DOWN ) + { + return ITERATION_CONTINUE; + } + } + else if ( FClassnameIs( pEnt, "prop_door*" ) ) + { + CBasePropDoor *door = dynamic_cast(pEnt); + if ( !door ) + { + return ITERATION_CONTINUE; + } + + if ( door->IsDoorOpening() || door->IsDoorClosing() ) + { + return ITERATION_CONTINUE; + } + } + else + { + return ITERATION_CONTINUE; + } + + if ( m_nAlreadyHit < m_nMaxHits ) + { + m_AlreadyHit[m_nAlreadyHit] = pEnt; + m_nAlreadyHit++; + } + + return ITERATION_CONTINUE; + } +}; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Returns an entity that matches the filter that is along the line segment + */ +CBaseEntity * CheckForEntitiesAlongSegment( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, CPushAwayEnumerator *enumerator ); +#endif // CLIENT_DLL + + +//-------------------------------------------------------------------------------------------------------------- +// Retrieves physics objects near pPushingEntity +void AvoidPushawayProps( CBaseCombatCharacter *pPlayer, CUserCmd *pCmd ); +int GetPushawayEnts( CBaseCombatCharacter *pPushingEntity, CBaseEntity **ents, int nMaxEnts, float flPlayerExpand, int PartitionMask, CPushAwayEnumerator *enumerator = NULL ); + +//-------------------------------------------------------------------------------------------------------------- +// Pushes physics objects away from the entity +void PerformObstaclePushaway( CBaseCombatCharacter *pPushingEntity ); + + +#endif // OBSTACLE_PUSHAWAY_H diff --git a/game/shared/particle_parse.h b/game/shared/particle_parse.h new file mode 100644 index 0000000..66f0a6d --- /dev/null +++ b/game/shared/particle_parse.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef PARTICLE_PARSE_H +#define PARTICLE_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utlstring.h" +#include "ifilelist.h" + +//----------------------------------------------------------------------------- +// Particle attachment methods +//----------------------------------------------------------------------------- +enum ParticleAttachment_t +{ + PATTACH_ABSORIGIN = 0, // Create at absorigin, but don't follow + PATTACH_ABSORIGIN_FOLLOW, // Create at absorigin, and update to follow the entity + PATTACH_CUSTOMORIGIN, // Create at a custom origin, but don't follow + PATTACH_POINT, // Create on attachment point, but don't follow + PATTACH_POINT_FOLLOW, // Create on attachment point, and update to follow the entity + + PATTACH_WORLDORIGIN, // Used for control points that don't attach to an entity + + PATTACH_ROOTBONE_FOLLOW, // Create at the root bone of the entity, and update to follow + + MAX_PATTACH_TYPES, +}; + +extern int GetAttachTypeFromString( const char *pszString ); + +#define PARTICLE_DISPATCH_FROM_ENTITY (1<<0) +#define PARTICLE_DISPATCH_RESET_PARTICLES (1<<1) + +struct te_tf_particle_effects_colors_t +{ + Vector m_vecColor1; + Vector m_vecColor2; +}; + +struct te_tf_particle_effects_control_point_t +{ + ParticleAttachment_t m_eParticleAttachment; + Vector m_vecOffset; +}; + +//----------------------------------------------------------------------------- +// Particle parsing methods +//----------------------------------------------------------------------------- +// Parse the particle manifest file & register the effects within it +// Only needs to be called once per game, unless tools change particle definitions +void ParseParticleEffects( bool bLoadSheets, bool bPrecache ); +void ParseParticleEffectsMap( const char *pMapName, bool bLoadSheets, IFileList *pFilesToReload = NULL ); + +// Get a list of the files inside the particle manifest file +void GetParticleManifest( CUtlVector& list ); + +// Precaches standard particle systems (only necessary on server) +// Should be called once per level +void PrecacheStandardParticleSystems( ); + +class IFileList; +void ReloadParticleEffectsInList( IFileList *pFilesToReload ); + +//----------------------------------------------------------------------------- +// Particle spawning methods +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, bool bResetAllParticlesOnEntity = false ); +void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity = NULL, int iAttachmentPoint = -1, bool bResetAllParticlesOnEntity = false ); +void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, CBaseEntity *pEntity = NULL ); +void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity = NULL ); +void DispatchParticleEffect( int iEffectIndex, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity = NULL ); + +void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, Vector vecColor1, Vector vecColor2, bool bUseColors=true, bool bResetAllParticlesOnEntity = false ); +void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, Vector vecColor1, Vector vecColor2, bool bUseColors=true, CBaseEntity *pEntity = NULL, int iAttachType = PATTACH_CUSTOMORIGIN ); + + +void StopParticleEffects( CBaseEntity *pEntity ); + + +#endif // PARTICLE_PARSE_H diff --git a/game/shared/particle_property.h b/game/shared/particle_property.h new file mode 100644 index 0000000..7978d8e --- /dev/null +++ b/game/shared/particle_property.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef PARTICLEPROPERTY_H +#define PARTICLEPROPERTY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "smartptr.h" +#include "globalvars_base.h" +#include "particles_new.h" +#include "particle_parse.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CBaseEntity; +class CNewParticleEffect; + +// Argh: Server considers -1 to be an invalid attachment, whereas the client uses 0 +#ifdef CLIENT_DLL +#define INVALID_PARTICLE_ATTACHMENT 0 +#else +#define INVALID_PARTICLE_ATTACHMENT -1 +#endif + +struct ParticleControlPoint_t +{ + ParticleControlPoint_t() + { + iControlPoint = 0; + iAttachType = PATTACH_ABSORIGIN_FOLLOW; + iAttachmentPoint = 0; + vecOriginOffset = vec3_origin; + } + + int iControlPoint; + ParticleAttachment_t iAttachType; + int iAttachmentPoint; + Vector vecOriginOffset; + EHANDLE hEntity; +}; + +struct ParticleEffectList_t +{ + ParticleEffectList_t() + { + pParticleEffect = NULL; + } + + CUtlVector pControlPoints; + CSmartPtr pParticleEffect; +}; + +extern int GetAttachTypeFromString( const char *pszString ); + +//----------------------------------------------------------------------------- +// Encapsulates particle handling for an entity +//----------------------------------------------------------------------------- +class CParticleProperty +{ + DECLARE_CLASS_NOBASE( CParticleProperty ); + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_PREDICTABLE(); + DECLARE_DATADESC(); + +public: + CParticleProperty(); + ~CParticleProperty(); + + void Init( CBaseEntity *pEntity ); + CBaseEntity *GetOuter( void ) { return m_pOuter; } + + // Effect Creation + CNewParticleEffect *Create( const char *pszParticleName, ParticleAttachment_t iAttachType, const char *pszAttachmentName ); + CNewParticleEffect *Create( const char *pszParticleName, ParticleAttachment_t iAttachType, int iAttachmentPoint = INVALID_PARTICLE_ATTACHMENT, Vector vecOriginOffset = vec3_origin ); + void AddControlPoint( CNewParticleEffect *pEffect, int iPoint, C_BaseEntity *pEntity, ParticleAttachment_t iAttachType, const char *pszAttachmentName = NULL, Vector vecOriginOffset = vec3_origin ); + void AddControlPoint( int iEffectIndex, int iPoint, C_BaseEntity *pEntity, ParticleAttachment_t iAttachType, int iAttachmentPoint = INVALID_PARTICLE_ATTACHMENT, Vector vecOriginOffset = vec3_origin ); + + inline void SetControlPointParent( CNewParticleEffect *pEffect, int whichControlPoint, int parentIdx ); + void SetControlPointParent( int iEffectIndex, int whichControlPoint, int parentIdx ); + + // Commands + void StopEmission( CNewParticleEffect *pEffect = NULL, bool bWakeOnStop = false, bool bDestroyAsleepSystems = false ); + void StopEmissionAndDestroyImmediately( CNewParticleEffect *pEffect = NULL ); + + // kill all particle systems involving a given entity for their control points + void StopParticlesInvolving( CBaseEntity *pEntity ); + void StopParticlesNamed( const char *pszEffectName, bool bForceRemoveInstantly = false, bool bInverse = false ); ///< kills all particles using the given definition name + void StopParticlesWithNameAndAttachment( const char *pszEffectName, int iAttachmentPoint, bool bForceRemoveInstantly = false ); ///< kills all particles using the given definition name + + // Particle System hooks + void OnParticleSystemUpdated( CNewParticleEffect *pEffect, float flTimeDelta ); + void OnParticleSystemDeleted( CNewParticleEffect *pEffect ); + +#ifdef CLIENT_DLL + void OwnerSetDormantTo( bool bDormant ); +#endif + + // Used to replace a particle effect with a different one; attaches the control point updating to the new one + void ReplaceParticleEffect( CNewParticleEffect *pOldEffect, CNewParticleEffect *pNewEffect ); + + // Debugging + void DebugPrintEffects( void ); + + int FindEffect( const char *pEffectName, int nStart = 0 ); + inline CNewParticleEffect *GetParticleEffectFromIdx( int idx ); + +private: + int GetParticleAttachment( C_BaseEntity *pEntity, const char *pszAttachmentName, const char *pszParticleName ); + int FindEffect( CNewParticleEffect *pEffect ); + void UpdateParticleEffect( ParticleEffectList_t *pEffect, bool bInitializing = false, int iOnlyThisControlPoint = -1 ); + void UpdateControlPoint( ParticleEffectList_t *pEffect, int iPoint, bool bInitializing ); + +private: + CBaseEntity *m_pOuter; + CUtlVector m_ParticleEffects; + int m_iDormancyChangedAtFrame; + + friend class CBaseEntity; +}; + +#include "particle_property_inlines.h" + +#endif // PARTICLEPROPERTY_H diff --git a/game/shared/particle_property_inlines.h b/game/shared/particle_property_inlines.h new file mode 100644 index 0000000..a6232e3 --- /dev/null +++ b/game/shared/particle_property_inlines.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Define inline functions for the CParticleProperty class. The +// definitions exist in this include file to avoid cluttering up +// particle_property.h, but this file should not be included from any- +// where else. +// +//============================================================================= + +#ifndef PARTICLEPROPERTY_H +#pragma message("Do not include particle_property_inlines.h from anywhere other than particle_property.h!") +#pragma error +#endif + +#ifndef PARTICLEPROPERTY_INLINES_H +#define PARTICLEPROPERTY_INLINES_H +#ifdef _WIN32 +#pragma once +#endif + + +/// Set the parent of a given control point on a given effect to the index of another control point. This is +/// in fact entirely redundant given the function is actually on the CNewParticleEffect, but is included here +/// for uniformity of interface. +void CParticleProperty::SetControlPointParent( CNewParticleEffect *pEffect, int whichControlPoint, int parentIdx ) +{ + pEffect->SetControlPointParent(whichControlPoint, parentIdx); +} + +/// Given an index, return a pointer to the relevant particle effect structure. For convenience. +CNewParticleEffect *CParticleProperty::GetParticleEffectFromIdx( int idx ) +{ + return m_ParticleEffects[idx].pParticleEffect.GetObject(); +} + + + +#endif // #ifndef PARTICLEPROPERTY_INLINES_H diff --git a/game/shared/physics_saverestore.h b/game/shared/physics_saverestore.h new file mode 100644 index 0000000..1c7c0a7 --- /dev/null +++ b/game/shared/physics_saverestore.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHYSICS_SAVERESTORE_H +#define PHYSICS_SAVERESTORE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "vphysics_interface.h" + +class ISaveRestoreBlockHandler; +class IPhysicsObject; +class CPhysCollide; + +//----------------------------------------------------------------------------- + +ISaveRestoreBlockHandler *GetPhysSaveRestoreBlockHandler(); +ISaveRestoreOps *GetPhysObjSaveRestoreOps( PhysInterfaceId_t ); + +//------------------------------------- + +#define DEFINE_PHYSPTR(name) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, GetPhysObjSaveRestoreOps( GetPhysIID( &(((classNameTypedef *)0)->name) ) ), NULL } + +#define DEFINE_PHYSPTR_ARRAY(name) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, ARRAYSIZE(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, GetPhysObjSaveRestoreOps( GetPhysIID( &(((classNameTypedef *)0)->name[0]) ) ), NULL } + +//----------------------------------------------------------------------------- + +abstract_class IPhysSaveRestoreManager +{ +public: + virtual void NoteBBox( const Vector &mins, const Vector &maxs, CPhysCollide * ) = 0; + + virtual void AssociateModel( IPhysicsObject *, int modelIndex ) = 0; + virtual void AssociateModel( IPhysicsObject *, const CPhysCollide *pModel ) = 0; + virtual void ForgetModel( IPhysicsObject * ) = 0; + + virtual void ForgetAllModels() = 0; +}; + +extern IPhysSaveRestoreManager *g_pPhysSaveRestoreManager; + +//============================================================================= + +#endif // PHYSICS_SAVERESTORE_H diff --git a/game/shared/physics_shared.h b/game/shared/physics_shared.h new file mode 100644 index 0000000..0f1178a --- /dev/null +++ b/game/shared/physics_shared.h @@ -0,0 +1,175 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PHYSICS_SHARED_H +#define PHYSICS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +class IPhysics; +class IPhysicsEnvironment; +class IPhysicsSurfaceProps; +class IPhysicsCollision; +class IPhysicsObject; +class IPhysicsObjectPairHash; +class CSoundPatch; + + +extern IPhysicsObject *g_PhysWorldObject; +extern IPhysics *physics; +extern IPhysicsCollision *physcollision; +extern IPhysicsEnvironment *physenv; +#ifdef PORTAL +extern IPhysicsEnvironment *physenv_main; +#endif +extern IPhysicsSurfaceProps *physprops; +extern IPhysicsObjectPairHash *g_EntityCollisionHash; + +extern const objectparams_t g_PhysDefaultObjectParams; + +// Compute enough energy of a reference mass travelling at speed +// makes numbers more intuitive +#define MASS_SPEED2ENERGY(mass, speed) ((speed)*(speed)*(mass)) + +// energy of a 10kg mass moving at speed +#define MASS10_SPEED2ENERGY(speed) MASS_SPEED2ENERGY(10,speed) + +#define MASS_ENERGY2SPEED(mass,energy) (FastSqrt((energy)/mass)) + +#define ENERGY_VOLUME_SCALE (1.0f / 15500.0f) + +#define FLUID_TIME_MAX 2.0f // keep track of last time hitting fluid for up to 2 seconds + +// VPHYSICS object game-specific flags +#define FVPHYSICS_DMG_SLICE 0x0001 // does slice damage, not just blunt damage +#define FVPHYSICS_CONSTRAINT_STATIC 0x0002 // object is constrained to the world, so it should behave like a static +#define FVPHYSICS_PLAYER_HELD 0x0004 // object is held by the player, so have a very inelastic collision response +#define FVPHYSICS_PART_OF_RAGDOLL 0x0008 // object is part of a client or server ragdoll +#define FVPHYSICS_MULTIOBJECT_ENTITY 0x0010 // object is part of a multi-object entity +#define FVPHYSICS_HEAVY_OBJECT 0x0020 // HULK SMASH! (Do large damage even if the mass is small) +#define FVPHYSICS_PENETRATING 0x0040 // This object is currently stuck inside another object +#define FVPHYSICS_NO_PLAYER_PICKUP 0x0080 // Player can't pick this up for some game rule reason +#define FVPHYSICS_WAS_THROWN 0x0100 // Player threw this object +#define FVPHYSICS_DMG_DISSOLVE 0x0200 // does dissolve damage, not just blunt damage +#define FVPHYSICS_NO_IMPACT_DMG 0x0400 // don't do impact damage to anything +#define FVPHYSICS_NO_NPC_IMPACT_DMG 0x0800 // Don't do impact damage to NPC's. This is temporary for NPC's shooting combine balls (sjb) +#define FVPHYSICS_NO_SELF_COLLISIONS 0x8000 // don't collide with other objects that are part of the same entity + +//----------------------------------------------------------------------------- +// Purpose: A little cache of current objects making noises +//----------------------------------------------------------------------------- +struct friction_t +{ + CSoundPatch *patch; + CBaseEntity *pObject; + float flLastUpdateTime; + float flLastEffectTime; +}; + +enum +{ + TOUCH_START=0, + TOUCH_END, +}; + +struct touchevent_t +{ + CBaseEntity *pEntity0; + CBaseEntity *pEntity1; + int touchType; + Vector endPoint; //sv + Vector normal; //sv +}; + +struct fluidevent_t +{ + EHANDLE hEntity; + float impactTime; +}; + +void PhysFrictionSound( CBaseEntity *pEntity, IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ); +void PhysFrictionSound( CBaseEntity *pEntity, IPhysicsObject *pObject, const char *pSoundName, HSOUNDSCRIPTHANDLE& handle, float flVolume ); +void PhysCleanupFrictionSounds( CBaseEntity *pEntity ); +void PhysFrictionEffect( Vector &vecPos, Vector vecVel, float energy, int surfaceProps, int surfacePropsHit ); + +// Convenience routine +// ORs gameFlags with the physics object's current game flags +inline unsigned short PhysSetGameFlags( IPhysicsObject *pPhys, unsigned short gameFlags ) +{ + unsigned short flags = pPhys->GetGameFlags(); + flags |= gameFlags; + pPhys->SetGameFlags( flags ); + + return flags; +} +// mask off gameFlags +inline unsigned short PhysClearGameFlags( IPhysicsObject *pPhys, unsigned short gameFlags ) +{ + unsigned short flags = pPhys->GetGameFlags(); + flags &= ~gameFlags; + pPhys->SetGameFlags( flags ); + + return flags; +} + + +// Create a vphysics object based on a model +IPhysicsObject *PhysModelCreate( CBaseEntity *pEntity, int modelIndex, const Vector &origin, const QAngle &angles, solid_t *pSolid = NULL ); + +IPhysicsObject *PhysModelCreateBox( CBaseEntity *pEntity, const Vector &mins, const Vector &maxs, const Vector &origin, bool isStatic ); +IPhysicsObject *PhysModelCreateOBB( CBaseEntity *pEntity, const Vector &mins, const Vector &maxs, const Vector &origin, const QAngle &angle, bool isStatic ); + +// Create a vphysics object based on a BSP model (unmoveable) +IPhysicsObject *PhysModelCreateUnmoveable( CBaseEntity *pEntity, int modelIndex, const Vector &origin, const QAngle &angles ); + +// Create a vphysics object based on an existing collision model +IPhysicsObject *PhysModelCreateCustom( CBaseEntity *pEntity, const CPhysCollide *pModel, const Vector &origin, const QAngle &angles, const char *pName, bool isStatic, solid_t *pSolid = NULL ); + +// Create a bbox collision model (these may be shared among entities, they are auto-deleted at end of level. do not manage) +CPhysCollide *PhysCreateBbox( const Vector &mins, const Vector &maxs ); + +// Create a vphysics sphere object +IPhysicsObject *PhysSphereCreate( CBaseEntity *pEntity, float radius, const Vector &origin, solid_t &solid ); + +// Destroy a physics object created using PhysModelCreate...() +void PhysDestroyObject( IPhysicsObject *pObject, CBaseEntity *pEntity = NULL ); + +void PhysDisableObjectCollisions( IPhysicsObject *pObject0, IPhysicsObject *pObject1 ); +void PhysDisableEntityCollisions( IPhysicsObject *pObject0, IPhysicsObject *pObject1 ); +void PhysDisableEntityCollisions( CBaseEntity *pEntity0, CBaseEntity *pEntity1 ); +void PhysEnableObjectCollisions( IPhysicsObject *pObject0, IPhysicsObject *pObject1 ); +void PhysEnableEntityCollisions( IPhysicsObject *pObject0, IPhysicsObject *pObject1 ); +void PhysEnableEntityCollisions( CBaseEntity *pEntity0, CBaseEntity *pEntity1 ); +bool PhysEntityCollisionsAreDisabled( CBaseEntity *pEntity0, CBaseEntity *pEntity1 ); + +// create the world physics objects +IPhysicsObject *PhysCreateWorld_Shared( CBaseEntity *pWorld, vcollide_t *pWorldCollide, const objectparams_t &defaultParams ); + +// parse the parameters for a single solid from the model's collision data +bool PhysModelParseSolid( solid_t &solid, CBaseEntity *pEntity, int modelIndex ); +// parse the parameters for a solid matching a particular index +bool PhysModelParseSolidByIndex( solid_t &solid, CBaseEntity *pEntity, int modelIndex, int solidIndex ); + +void PhysParseSurfaceData( class IPhysicsSurfaceProps *pProps, class IFileSystem *pFileSystem ); + +// fill out this solid_t with the AABB defaults (high inertia/no rotation) +void PhysGetDefaultAABBSolid( solid_t &solid ); + +// Compute an output velocity based on sliding along the current contact points +// in the closest direction toward inputVelocity. +void PhysComputeSlideDirection( IPhysicsObject *pPhysics, const Vector &inputVelocity, const AngularImpulse &inputAngularVelocity, + Vector *pOutputVelocity, Vector *pOutputAngularVelocity, float minMass ); + +void PhysForceClearVelocity( IPhysicsObject *pPhys ); +bool PhysHasContactWithOtherInDirection( IPhysicsObject *pPhysics, const Vector &dir ); + +//----------------------------------------------------------------------------- +// Singleton access +//----------------------------------------------------------------------------- +IGameSystem* PhysicsGameSystem(); + +#endif // PHYSICS_SHARED_H diff --git a/game/shared/playerclass_info_parse.h b/game/shared/playerclass_info_parse.h new file mode 100644 index 0000000..1f00833 --- /dev/null +++ b/game/shared/playerclass_info_parse.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Player class data file parsing, shared by game & client dlls. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERCLASS_INFO_PARSE_H +#define PLAYERCLASS_INFO_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +class IFileSystem; +class KeyValues; + +typedef unsigned short PLAYERCLASS_FILE_INFO_HANDLE; + +#define MAX_PLAYERCLASS_NAME_LENGTH 128 + +//----------------------------------------------------------------------------- +// Purpose: Contains the data read from the player class script files. +// It's cached so we only read each script file once. +// Each game provides a CreatePlayerClassInfo function so it can have game-specific +// data in the player class scripts. +//----------------------------------------------------------------------------- +class FilePlayerClassInfo_t +{ +public: + + FilePlayerClassInfo_t(); + + // Each game can override this to get whatever values it wants from the script. + virtual void Parse( KeyValues *pKeyValuesData, const char *szClassName ); + + +public: + bool m_bParsedScript; + +public: + // Class properties + + // todo : better lengths for these arrays ? + + char m_szPlayerClassName[MAX_PLAYERCLASS_NAME_LENGTH]; + char m_szPrintName[MAX_PLAYERCLASS_NAME_LENGTH]; // localization key for print name + char m_szPlayerModel[MAX_PLAYERCLASS_NAME_LENGTH]; + char m_szSelectCmd[32]; //command the player can issue to switch to this class +}; + +// The weapon parse function +bool ReadPlayerClassDataFromFileForSlot( IFileSystem* filesystem, const char *szClassName, + PLAYERCLASS_FILE_INFO_HANDLE *phandle, const unsigned char *pICEKey = NULL ); + +// If player class info has been loaded for the specified class name, this returns it. +PLAYERCLASS_FILE_INFO_HANDLE LookupPlayerClassInfoSlot( const char *name ); + +// Given a handle to the player class info, return the class data +FilePlayerClassInfo_t *GetFilePlayerClassInfoFromHandle( PLAYERCLASS_FILE_INFO_HANDLE handle ); + +// Get the null Player Class object +PLAYERCLASS_FILE_INFO_HANDLE GetInvalidPlayerClassInfoHandle( void ); + +// Initialize all player class info +void ResetFilePlayerClassInfoDatabase( void ); + + +// +// Read a possibly-encrypted KeyValues file in. +// If pICEKey is NULL, then it appends .txt to the filename and loads it as an unencrypted file. +// If pICEKey is non-NULL, then it appends .ctx to the filename and loads it as an encrypted file. +// +// (This should be moved into a more appropriate place). +// +extern KeyValues* ReadEncryptedKVPlayerClassFile( IFileSystem *filesystem, const char *szFilenameWithoutExtension, const unsigned char *pICEKey ); + + +// Each game implements this. It can return a derived class and override Parse() if it wants. +extern FilePlayerClassInfo_t* CreatePlayerClassInfo(); + + +#endif // PLAYERCLASS_INFO_PARSE_H diff --git a/game/shared/playernet_vars.h b/game/shared/playernet_vars.h new file mode 100644 index 0000000..ac9f776 --- /dev/null +++ b/game/shared/playernet_vars.h @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERNET_VARS_H +#define PLAYERNET_VARS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shared_classnames.h" + +#define NUM_AUDIO_LOCAL_SOUNDS 8 + +// These structs are contained in each player's local data and shared by the client & server + +struct fogparams_t +{ + DECLARE_CLASS_NOBASE( fogparams_t ); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + bool operator !=( const fogparams_t& other ) const; + + CNetworkVector( dirPrimary ); + CNetworkColor32( colorPrimary ); + CNetworkColor32( colorSecondary ); + CNetworkColor32( colorPrimaryLerpTo ); + CNetworkColor32( colorSecondaryLerpTo ); + CNetworkVar( float, start ); + CNetworkVar( float, end ); + CNetworkVar( float, farz ); + CNetworkVar( float, maxdensity ); + + CNetworkVar( float, startLerpTo ); + CNetworkVar( float, endLerpTo ); + CNetworkVar( float, lerptime ); + CNetworkVar( float, duration ); + CNetworkVar( bool, enable ); + CNetworkVar( bool, blend ); +}; + +// Crappy. Needs to be here because it wants to use +#ifdef CLIENT_DLL +#define CFogController C_FogController +#endif + +class CFogController; + +struct fogplayerparams_t +{ + DECLARE_CLASS_NOBASE( fogplayerparams_t ); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + CNetworkHandle( CFogController, m_hCtrl ); + float m_flTransitionTime; + + color32 m_OldColor; + float m_flOldStart; + float m_flOldEnd; + + color32 m_NewColor; + float m_flNewStart; + float m_flNewEnd; + + fogplayerparams_t() + { + m_hCtrl.Set( NULL ); + m_flTransitionTime = -1.0f; + m_OldColor.r = m_OldColor.g = m_OldColor.b = m_OldColor.a = 0; + m_flOldStart = 0.0f; + m_flOldEnd = 0.0f; + m_NewColor.r = m_NewColor.g = m_NewColor.b = m_NewColor.a = 0; + m_flNewStart = 0.0f; + m_flNewEnd = 0.0f; + } +}; + +struct sky3dparams_t +{ + DECLARE_CLASS_NOBASE( sky3dparams_t ); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + // 3d skybox camera data + CNetworkVar( int, scale ); + CNetworkVector( origin ); + CNetworkVar( int, area ); + + // 3d skybox fog data + CNetworkVarEmbedded( fogparams_t, fog ); +}; + +struct audioparams_t +{ + DECLARE_CLASS_NOBASE( audioparams_t ); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + CNetworkArray( Vector, localSound, NUM_AUDIO_LOCAL_SOUNDS ) + CNetworkVar( int, soundscapeIndex ); // index of the current soundscape from soundscape.txt + CNetworkVar( int, localBits ); // if bits 0,1,2,3 are set then position 0,1,2,3 are valid/used + CNetworkHandle( CBaseEntity, ent ); // the entity setting the soundscape +}; + + +#endif // PLAYERNET_VARS_H diff --git a/game/shared/point_bonusmaps_accessor.h b/game/shared/point_bonusmaps_accessor.h new file mode 100644 index 0000000..a78b2f5 --- /dev/null +++ b/game/shared/point_bonusmaps_accessor.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef POINT_BONUSMAPS_ACCESSOR_H +#define POINT_BONUSMAPS_ACCESSOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +void BonusMapChallengeUpdate( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest ); +void BonusMapChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName ); +void BonusMapChallengeObjectives( int &iBronze, int &iSilver, int &iGold ); + + +#endif // POINT_BONUSMAPS_ACCESSOR_H diff --git a/game/shared/point_posecontroller.h b/game/shared/point_posecontroller.h new file mode 100644 index 0000000..2e11bc5 --- /dev/null +++ b/game/shared/point_posecontroller.h @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Controls the pose parameters of a model +// +//===========================================================================// + + +#define MAX_POSE_CONTROLLED_PROPS 4 // Number of entities by the same name that can be controlled + + +// Type of frequency modulations +enum PoseController_FModType_t +{ + POSECONTROLLER_FMODTYPE_NONE = 0, + POSECONTROLLER_FMODTYPE_SINE, + POSECONTROLLER_FMODTYPE_SQUARE, + POSECONTROLLER_FMODTYPE_TRIANGLE, + POSECONTROLLER_FMODTYPE_SAWTOOTH, + POSECONTROLLER_FMODTYPE_NOISE, + + POSECONTROLLER_FMODTYPE_TOTAL, +}; + + +#ifndef CLIENT_DLL +//----------------------------------------------------------------------------- +// SERVER CLASS +//----------------------------------------------------------------------------- + +#include "baseentity.h" + + +class CPoseController : public CBaseEntity +{ +public: + DECLARE_CLASS( CPoseController, CBaseEntity ); + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + virtual void Spawn( void ); + + void Think( void ); + + void BuildPropList( void ); + void BuildPoseIndexList( void ); + void SetPoseIndex( int i, int iValue ); + void SetCurrentPose( float fCurrentPoseValue ); + + float GetPoseValue( void ); + + void SetProp( CBaseAnimating *pProp ); + void SetPropName( const char *pName ); + void SetPoseParameterName( const char *pName ); + void SetPoseValue( float fValue ); + void SetInterpolationTime( float fValue ); + void SetInterpolationWrap( bool bWrap ); + void SetCycleFrequency( float fValue ); + void SetFModType( int nType ); + void SetFModTimeOffset( float fValue ); + void SetFModRate( float fValue ); + void SetFModAmplitude( float fValue ); + void RandomizeFMod( float fExtremeness ); + + // Input handlers + void InputSetPoseParameterName( inputdata_t &inputdata ); + void InputSetPoseValue( inputdata_t &inputdata ); + void InputSetInterpolationTime( inputdata_t &inputdata ); + void InputSetCycleFrequency( inputdata_t &inputdata ); + void InputSetFModType( inputdata_t &inputdata ); + void InputSetFModTimeOffset( inputdata_t &inputdata ); + void InputSetFModRate( inputdata_t &inputdata ); + void InputSetFModAmplitude( inputdata_t &inputdata ); + void InputRandomizeFMod( inputdata_t &inputdata ); + void InputGetFMod( inputdata_t &inputdata ); + +private: + + CNetworkArray( EHANDLE, m_hProps, MAX_POSE_CONTROLLED_PROPS ); // Handles to controlled models + CNetworkArray( unsigned char, m_chPoseIndex, MAX_POSE_CONTROLLED_PROPS ); // Pose parameter indices for each model + + bool m_bDisablePropLookup; + + CNetworkVar( bool, m_bPoseValueParity ); + + string_t m_iszPropName; // Targetname of the models to control + string_t m_iszPoseParameterName; // Pose parameter name to control + + CNetworkVar( float, m_fPoseValue ); // Normalized pose parameter value (maps to each pose parameter's min and max range) + CNetworkVar( float, m_fInterpolationTime ); // Interpolation speed for client matching absolute pose values + CNetworkVar( bool, m_bInterpolationWrap ); // Interpolation for the client wraps 0 to 1. + + CNetworkVar( float, m_fCycleFrequency ); // Cycles per second + + // Frequency modulation variables + CNetworkVar( PoseController_FModType_t, m_nFModType ); + CNetworkVar( float, m_fFModTimeOffset ); + CNetworkVar( float, m_fFModRate ); + CNetworkVar( float, m_fFModAmplitude ); +}; + + +#else //#ifndef CLIENT_DLL +//----------------------------------------------------------------------------- +// CLIENT CLASS +//----------------------------------------------------------------------------- + +#include "c_baseentity.h" +#include "fx_interpvalue.h" + + +class C_PoseController : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_PoseController, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + virtual void Spawn( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + virtual void ClientThink( void ); + +private: + + void UpdateModulation( void ); + void UpdatePoseCycle( float fCycleAmount ); + void SetCurrentPose( float fCurrentPoseValue ); + + + // Networked variables + EHANDLE m_hProps[MAX_POSE_CONTROLLED_PROPS]; + unsigned char m_chPoseIndex[MAX_POSE_CONTROLLED_PROPS]; + bool m_bPoseValueParity; + float m_fPoseValue; + float m_fInterpolationTime; + bool m_bInterpolationWrap; + float m_fCycleFrequency; + PoseController_FModType_t m_nFModType; + float m_fFModTimeOffset; + float m_fFModRate; + float m_fFModAmplitude; + bool m_bOldPoseValueParity; + + float m_fCurrentPoseValue; // Actual pose value cycled by the frequency and modulation + float m_fCurrentFMod; // The current fequency modulation amount (stored for noise walk) + + CInterpolatedValue m_PoseTransitionValue; +}; + + +#endif //#ifndef CLIENT_DLL \ No newline at end of file diff --git a/game/shared/positionwatcher.h b/game/shared/positionwatcher.h new file mode 100644 index 0000000..7e01c0f --- /dev/null +++ b/game/shared/positionwatcher.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef POSITIONWATCHER_H +#define POSITIONWATCHER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ehandle.h" + +// inherit from this interface to be able to call WatchPositionChanges +abstract_class IWatcherCallback +{ +public: + virtual ~IWatcherCallback() {} +}; + +abstract_class IPositionWatcher : public IWatcherCallback +{ +public: + virtual void NotifyPositionChanged( CBaseEntity *pEntity ) = 0; +}; + +// NOTE: The table of watchers is NOT saved/loaded! Recreate these links on restore +void ReportPositionChanged( CBaseEntity *pMovedEntity ); +void WatchPositionChanges( CBaseEntity *pWatcher, CBaseEntity *pMovingEntity ); +void RemovePositionWatcher( CBaseEntity *pWatcher, CBaseEntity *pMovingEntity ); + + +// inherit from this interface to be able to call WatchPositionChanges +abstract_class IVPhysicsWatcher : public IWatcherCallback +{ +public: + virtual void NotifyVPhysicsStateChanged( IPhysicsObject *pPhysics, CBaseEntity *pEntity, bool bAwake ) = 0; +}; + +// NOTE: The table of watchers is NOT saved/loaded! Recreate these links on restore +void ReportVPhysicsStateChanged( IPhysicsObject *pPhysics, CBaseEntity *pEntity, bool bAwake ); +void WatchVPhysicsStateChanges( CBaseEntity *pWatcher, CBaseEntity *pPhysicsEntity ); +void RemoveVPhysicsStateWatcher( CBaseEntity *pWatcher, CBaseEntity *pPhysicsEntity ); + + +#endif // POSITIONWATCHER_H diff --git a/game/shared/precache_register.h b/game/shared/precache_register.h new file mode 100644 index 0000000..379949f --- /dev/null +++ b/game/shared/precache_register.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PRECACHE_REGISTER_H +#define PRECACHE_REGISTER_H +#pragma once + + +// Use these macros to register something to be precached. +#define PRECACHE_REGISTER_FN(functionName) static CPrecacheRegister precache_function_##functionName(functionName, 0); +#define PRECACHE_WEAPON_REGISTER(className) static CPrecacheRegister precache_weapon_##className(&CPrecacheRegister::PrecacheFn_Other, #className) +#define PRECACHE_REGISTER(className) static CPrecacheRegister precache_other_##className( &CPrecacheRegister::PrecacheFn_Other, #className) + +class CPrecacheRegister +{ +public: + + typedef void (*PrecacheFn)(void *pUser); // Prototype for a custom precache function. + + CPrecacheRegister(PrecacheFn fn, const void *pUser); + + PrecacheFn m_Fn; + void *m_pUser; + CPrecacheRegister *m_pNext; + + static void Precache(); // Calls everything that has registered to precache. + +// Don't call these. +public: + static void PrecacheFn_Other(void *pUser); +}; + + +#endif // PRECACHE_REGISTER_H diff --git a/game/shared/precipitation_shared.h b/game/shared/precipitation_shared.h new file mode 100644 index 0000000..791ec29 --- /dev/null +++ b/game/shared/precipitation_shared.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PRECIPITATION_SHARED_H +#define PRECIPITATION_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +// Types of precipitation +enum PrecipitationType_t +{ + PRECIPITATION_TYPE_RAIN = 0, + PRECIPITATION_TYPE_SNOW, + PRECIPITATION_TYPE_ASH, + PRECIPITATION_TYPE_SNOWFALL, + NUM_PRECIPITATION_TYPES +}; + + +#endif // PRECIPITATION_SHARED_H diff --git a/game/shared/predictable_entity.h b/game/shared/predictable_entity.h new file mode 100644 index 0000000..fa0bf3d --- /dev/null +++ b/game/shared/predictable_entity.h @@ -0,0 +1,203 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PREDICTABLE_ENTITY_H +#define PREDICTABLE_ENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +// For introspection +#include "tier0/platform.h" +#include "predictioncopy.h" +#include "shared_classnames.h" + +#ifndef NO_ENTITY_PREDICTION +#define UsePrediction() 1 +#else +#define UsePrediction() 0 +#endif + +// CLIENT DLL includes +#if defined( CLIENT_DLL ) + +#include "iclassmap.h" +#include "recvproxy.h" + +class SendTable; + +// Game DLL includes +#else + +#include "sendproxy.h" + +#endif // !CLIENT_DLL + +#if defined( CLIENT_DLL ) + +#define DECLARE_NETWORKCLASS() \ + DECLARE_CLIENTCLASS() + +#define DECLARE_NETWORKCLASS_NOBASE() \ + DECLARE_CLIENTCLASS_NOBASE() + +#else + +#define DECLARE_NETWORKCLASS() \ + DECLARE_SERVERCLASS() + +#define DECLARE_NETWORKCLASS_NOBASE() \ + DECLARE_SERVERCLASS_NOBASE() + +#endif + +#if defined( CLIENT_DLL ) + +#ifndef NO_ENTITY_PREDICTION +#define DECLARE_PREDICTABLE() \ + public: \ + static typedescription_t m_PredDesc[]; \ + static datamap_t m_PredMap; \ + virtual datamap_t *GetPredDescMap( void ); \ + template friend datamap_t *PredMapInit(T *) +#else +#define DECLARE_PREDICTABLE() template friend datamap_t *PredMapInit(T *) +#endif + +#ifndef NO_ENTITY_PREDICTION +#define BEGIN_PREDICTION_DATA( className ) \ + datamap_t className::m_PredMap = { 0, 0, #className, &BaseClass::m_PredMap }; \ + datamap_t *className::GetPredDescMap( void ) { return &m_PredMap; } \ + BEGIN_PREDICTION_DATA_GUTS( className ) + +#define BEGIN_PREDICTION_DATA_NO_BASE( className ) \ + datamap_t className::m_PredMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetPredDescMap( void ) { return &m_PredMap; } \ + BEGIN_PREDICTION_DATA_GUTS( className ) + +#define BEGIN_PREDICTION_DATA_GUTS( className ) \ + template datamap_t *PredMapInit(T *); \ + template <> datamap_t *PredMapInit( className * ); \ + namespace className##_PredDataDescInit \ + { \ + datamap_t *g_PredMapHolder = PredMapInit( (className *)NULL ); /* This can/will be used for some clean up duties later */ \ + } \ + \ + template <> datamap_t *PredMapInit( className * ) \ + { \ + typedef className classNameTypedef; \ + static typedescription_t predDesc[] = \ + { \ + { FIELD_VOID,0, {0,0},0,0,0,0,0,0}, /* so you can define "empty" tables */ + +#define END_PREDICTION_DATA() \ + }; \ + \ + if ( sizeof( predDesc ) > sizeof( predDesc[0] ) ) \ + { \ + classNameTypedef::m_PredMap.dataNumFields = ARRAYSIZE( predDesc ) - 1; \ + classNameTypedef::m_PredMap.dataDesc = &predDesc[1]; \ + } \ + else \ + { \ + classNameTypedef::m_PredMap.dataNumFields = 1; \ + classNameTypedef::m_PredMap.dataDesc = predDesc; \ + } \ + return &classNameTypedef::m_PredMap; \ + } +#else +#define BEGIN_PREDICTION_DATA( className ) \ + template <> inline datamap_t *PredMapInit( className * ) \ + { \ + if ( 0 ) \ + { \ + typedef className classNameTypedef; \ + typedescription_t predDesc[] = \ + { \ + { FIELD_VOID,0, {0,0},0,0,0,0,0,0}, + +#define BEGIN_PREDICTION_DATA_NO_BASE( className ) BEGIN_PREDICTION_DATA( className ) + +#define END_PREDICTION_DATA() \ + }; \ + predDesc[0].flags = 0; /* avoid compiler warning of unused data */ \ + } \ + } +#endif + +#else + + // nothing, only client has a prediction system + #define DECLARE_PREDICTABLE() + #define BEGIN_PREDICTION_DATA( className ) + #define END_PREDICTION_DATA() + +#endif + +#if defined( CLIENT_DLL ) + +// On the client .dll this creates a mapping between a classname and +// a client side class. Probably could be templatized at some point. + +#define LINK_ENTITY_TO_CLASS( localName, className ) \ + static C_BaseEntity *C##className##Factory( void ) \ + { \ + return static_cast< C_BaseEntity * >( new className ); \ + }; \ + class C##localName##Foo \ + { \ + public: \ + C##localName##Foo( void ) \ + { \ + GetClassMap().Add( #localName, #className, sizeof( className ), \ + &C##className##Factory ); \ + } \ + }; \ + static C##localName##Foo g_C##localName##Foo; + +#define BEGIN_NETWORK_TABLE( className, tableName ) BEGIN_RECV_TABLE( className, tableName ) +#define BEGIN_NETWORK_TABLE_NOBASE( className, tableName ) BEGIN_RECV_TABLE_NOBASE( className, tableName ) + +#define END_NETWORK_TABLE END_RECV_TABLE + +#define IMPLEMENT_NETWORKCLASS_ALIASED(className, dataTable) \ + IMPLEMENT_CLIENTCLASS( C_##className, dataTable, C##className ) +#define IMPLEMENT_NETWORKCLASS(className, dataTable) \ + IMPLEMENT_CLIENTCLASS(className, dataTable, className) +#define IMPLEMENT_NETWORKCLASS_DT(className, dataTable) \ + IMPLEMENT_CLIENTCLASS_DT(className, dataTable, className) + +#else + +#define BEGIN_NETWORK_TABLE( className, tableName ) BEGIN_SEND_TABLE( className, tableName ) +#define BEGIN_NETWORK_TABLE_NOBASE( className, tableName ) BEGIN_SEND_TABLE_NOBASE( className, tableName ) + +#define END_NETWORK_TABLE END_SEND_TABLE + +#define IMPLEMENT_NETWORKCLASS_ALIASED(className, dataTable) \ + IMPLEMENT_SERVERCLASS( C##className, dataTable ) +#define IMPLEMENT_NETWORKCLASS(className, dataTable) \ + IMPLEMENT_SERVERCLASS(className, dataTable) +#define IMPLEMENT_NETWORKCLASS_DT(className, dataTable) \ + IMPLEMENT_SERVERCLASS_ST(className, dataTable) + +#endif + +// Interface used by client and server to track predictable entities +abstract_class IPredictableList +{ +public: + // Get predictables by index + virtual CBaseEntity *GetPredictable( int slot ) = 0; + // Get count of predictables + virtual int GetPredictableCount( void ) = 0; +}; + +// Expose interface to rest of .dll +extern IPredictableList *predictables; + +#endif // PREDICTABLE_ENTITY_H diff --git a/game/shared/predictableid.h b/game/shared/predictableid.h new file mode 100644 index 0000000..703de9a --- /dev/null +++ b/game/shared/predictableid.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PREDICTABLEID_H +#define PREDICTABLEID_H +#ifdef _WIN32 +#pragma once +#endif + +#if !defined( NO_ENTITY_PREDICTION ) +//----------------------------------------------------------------------------- +// Purpose: Wraps 32bit predictID to allow access and creation +//----------------------------------------------------------------------------- +class CPredictableId +{ +public: + // Construction + CPredictableId( void ); + + static void ResetInstanceCounters( void ); + + // Is the Id being used + bool IsActive( void ) const; + + // Call this to set from data + void Init( int player, int command, const char *classname, const char *module, int line ); + + // Get player index + int GetPlayer( void ) const; + // Get hash value + int GetHash( void ) const; + // Get index number + int GetInstanceNumber( void ) const; + // Get command number + int GetCommandNumber( void ) const; + + // Check command number +// bool IsCommandNumberEqual( int testNumber ) const; + + // Client only + void SetAcknowledged( bool ack ); + bool GetAcknowledged( void ) const; + + // For conversion to/from integer + int GetRaw( void ) const; + void SetRaw( int raw ); + + char const *Describe( void ) const; + + // Equality test + bool operator ==( const CPredictableId& other ) const; + bool operator !=( const CPredictableId& other ) const; +private: + void SetCommandNumber( int commandNumber ); + void SetPlayer( int playerIndex ); + void SetInstanceNumber( int counter ); + + // Encoding bits, should total 32 + struct bitfields + { + unsigned int ack : 1; // 1 + unsigned int player : 5; // 6 + unsigned int command : 10; // 16 + unsigned int hash : 12; // 28 + unsigned int instance : 4; // 32 + } m_PredictableID; +}; + +// This can be empty, the class has a proper constructor +FORCEINLINE void NetworkVarConstruct( CPredictableId &x ) {} + +#endif + +#endif // PREDICTABLEID_H diff --git a/game/shared/predicted_viewmodel.h b/game/shared/predicted_viewmodel.h new file mode 100644 index 0000000..8e5af39 --- /dev/null +++ b/game/shared/predicted_viewmodel.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PREDICTED_VIEWMODEL_H +#define PREDICTED_VIEWMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "predictable_entity.h" +#include "utlvector.h" +#include "baseplayer_shared.h" +#include "shared_classnames.h" + +#if defined( CLIENT_DLL ) +#define CPredictedViewModel C_PredictedViewModel +#endif + +class CPredictedViewModel : public CBaseViewModel +{ + DECLARE_CLASS( CPredictedViewModel, CBaseViewModel ); +public: + + DECLARE_NETWORKCLASS(); + + CPredictedViewModel( void ); + virtual ~CPredictedViewModel( void ); + + virtual void CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles ); + +#if defined( CLIENT_DLL ) + virtual bool ShouldPredict( void ) + { + if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() ) + return true; + + return BaseClass::ShouldPredict(); + } +#endif + +private: + +#if defined( CLIENT_DLL ) + + // This is used to lag the angles. + CInterpolatedVar m_LagAnglesHistory; + QAngle m_vLagAngles; + + CPredictedViewModel( const CPredictedViewModel & ); // not defined, not accessible + +#endif +}; + +#endif // PREDICTED_VIEWMODEL_H diff --git a/game/shared/predictioncopy.h b/game/shared/predictioncopy.h new file mode 100644 index 0000000..1fdea3b --- /dev/null +++ b/game/shared/predictioncopy.h @@ -0,0 +1,293 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PREDICTIONCOPY_H +#define PREDICTIONCOPY_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "datamap.h" +#include "ehandle.h" +#include "tier1/utlstring.h" + +#if defined( CLIENT_DLL ) +class C_BaseEntity; +typedef CHandle EHANDLE; + +#if defined( _DEBUG ) +// #define COPY_CHECK_STRESSTEST +class IGameSystem; +IGameSystem* GetPredictionCopyTester( void ); +#endif + +#else +class CBaseEntity; +typedef CHandle EHANDLE; +#endif + +enum +{ + PC_EVERYTHING = 0, + PC_NON_NETWORKED_ONLY, + PC_NETWORKED_ONLY, +}; + +#define PC_DATA_PACKED true +#define PC_DATA_NORMAL false + +typedef void ( *FN_FIELD_COMPARE )( const char *classname, const char *fieldname, const char *fieldtype, + bool networked, bool noterrorchecked, bool differs, bool withintolerance, const char *value ); + +class CPredictionCopy +{ +public: + typedef enum + { + DIFFERS = 0, + IDENTICAL, + WITHINTOLERANCE, + } difftype_t; + + CPredictionCopy( int type, void *dest, bool dest_packed, void const *src, bool src_packed, + bool counterrors = false, bool reporterrors = false, bool performcopy = true, + bool describefields = false, FN_FIELD_COMPARE func = NULL ); + + void CopyShort( difftype_t dt, short *outvalue, const short *invalue, int count ); + void CopyInt( difftype_t dt, int *outvalue, const int *invalue, int count ); // Copy an int + void CopyBool( difftype_t dt, bool *outvalue, const bool *invalue, int count ); // Copy a bool + void CopyFloat( difftype_t dt, float *outvalue, const float *invalue, int count ); // Copy a float + void CopyString( difftype_t dt, char *outstring, const char *instring ); // Copy a null-terminated string + void CopyVector( difftype_t dt, Vector& outValue, const Vector &inValue ); // Copy a vector + void CopyVector( difftype_t dt, Vector* outValue, const Vector *inValue, int count ); // Copy a vector array + void CopyQuaternion( difftype_t dt, Quaternion& outValue, const Quaternion &inValue ); // Copy a quaternion + void CopyQuaternion( difftype_t dt, Quaternion* outValue, const Quaternion *inValue, int count ); // Copy a quaternion array + void CopyEHandle( difftype_t dt, EHANDLE *outvalue, EHANDLE const *invalue, int count ); + + void FORCEINLINE CopyData( difftype_t dt, int size, char *outdata, const char *indata ) // Copy a binary data block + { + if ( !m_bPerformCopy ) + return; + + if ( dt == IDENTICAL ) + return; + + memcpy( outdata, indata, size ); + } + + int TransferData( const char *operation, int entindex, datamap_t *dmap ); + +private: + void TransferData_R( int chaincount, datamap_t *dmap ); + + void DetermineWatchField( const char *operation, int entindex, datamap_t *dmap ); + void DumpWatchField( typedescription_t *field ); + void WatchMsg( PRINTF_FORMAT_STRING const char *fmt, ... ); + + difftype_t CompareShort( short *outvalue, const short *invalue, int count ); + difftype_t CompareInt( int *outvalue, const int *invalue, int count ); // Compare an int + difftype_t CompareBool( bool *outvalue, const bool *invalue, int count ); // Compare a bool + difftype_t CompareFloat( float *outvalue, const float *invalue, int count ); // Compare a float + difftype_t CompareData( int size, char *outdata, const char *indata ); // Compare a binary data block + difftype_t CompareString( char *outstring, const char *instring ); // Compare a null-terminated string + difftype_t CompareVector( Vector& outValue, const Vector &inValue ); // Compare a vector + difftype_t CompareVector( Vector* outValue, const Vector *inValue, int count ); // Compare a vector array + difftype_t CompareQuaternion( Quaternion& outValue, const Quaternion &inValue ); // Compare a Quaternion + difftype_t CompareQuaternion( Quaternion* outValue, const Quaternion *inValue, int count ); // Compare a Quaternion array + difftype_t CompareEHandle( EHANDLE *outvalue, EHANDLE const *invalue, int count ); + + void DescribeShort( difftype_t dt, short *outvalue, const short *invalue, int count ); + void DescribeInt( difftype_t dt, int *outvalue, const int *invalue, int count ); // Compare an int + void DescribeBool( difftype_t dt, bool *outvalue, const bool *invalue, int count ); // Compare a bool + void DescribeFloat( difftype_t dt, float *outvalue, const float *invalue, int count ); // Compare a float + void DescribeData( difftype_t dt, int size, char *outdata, const char *indata ); // Compare a binary data block + void DescribeString( difftype_t dt, char *outstring, const char *instring ); // Compare a null-terminated string + void DescribeVector( difftype_t dt, Vector& outValue, const Vector &inValue ); // Compare a vector + void DescribeVector( difftype_t dt, Vector* outValue, const Vector *inValue, int count ); // Compare a vector array + void DescribeQuaternion( difftype_t dt, Quaternion& outValue, const Quaternion &inValue ); // Compare a Quaternion + void DescribeQuaternion( difftype_t dt, Quaternion* outValue, const Quaternion *inValue, int count ); // Compare a Quaternion array + void DescribeEHandle( difftype_t dt, EHANDLE *outvalue, EHANDLE const *invalue, int count ); + + void WatchShort( difftype_t dt, short *outvalue, const short *invalue, int count ); + void WatchInt( difftype_t dt, int *outvalue, const int *invalue, int count ); // Compare an int + void WatchBool( difftype_t dt, bool *outvalue, const bool *invalue, int count ); // Compare a bool + void WatchFloat( difftype_t dt, float *outvalue, const float *invalue, int count ); // Compare a float + void WatchData( difftype_t dt, int size, char *outdata, const char *indata ); // Compare a binary data block + void WatchString( difftype_t dt, char *outstring, const char *instring ); // Compare a null-terminated string + void WatchVector( difftype_t dt, Vector& outValue, const Vector &inValue ); // Compare a vector + void WatchVector( difftype_t dt, Vector* outValue, const Vector *inValue, int count ); // Compare a vector array + void WatchQuaternion( difftype_t dt, Quaternion& outValue, const Quaternion &inValue ); // Compare a Quaternion + void WatchQuaternion( difftype_t dt, Quaternion* outValue, const Quaternion *inValue, int count ); // Compare a Quaternion array + void WatchEHandle( difftype_t dt, EHANDLE *outvalue, EHANDLE const *invalue, int count ); + + // Report function + void ReportFieldsDiffer( PRINTF_FORMAT_STRING const char *fmt, ... ); + void DescribeFields( difftype_t dt, PRINTF_FORMAT_STRING const char *fmt, ... ); + + bool CanCheck( void ); + + void CopyFields( int chaincount, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); + +private: + + int m_nType; + void *m_pDest; + void const *m_pSrc; + int m_nDestOffsetIndex; + int m_nSrcOffsetIndex; + + + bool m_bErrorCheck; + bool m_bReportErrors; + bool m_bDescribeFields; + typedescription_t *m_pCurrentField; + char const *m_pCurrentClassName; + datamap_t *m_pCurrentMap; + bool m_bShouldReport; + bool m_bShouldDescribe; + int m_nErrorCount; + bool m_bPerformCopy; + + FN_FIELD_COMPARE m_FieldCompareFunc; + + typedescription_t *m_pWatchField; + char const *m_pOperation; +}; + +typedef void (*FN_FIELD_DESCRIPTION)( const char *classname, const char *fieldname, const char *fieldtype, + bool networked, const char *value ); + +//----------------------------------------------------------------------------- +// Purpose: Simply dumps all data fields in object +//----------------------------------------------------------------------------- +class CPredictionDescribeData +{ +public: + CPredictionDescribeData( void const *src, bool src_packed, FN_FIELD_DESCRIPTION func = 0 ); + + void DescribeShort( const short *invalue, int count ); + void DescribeInt( const int *invalue, int count ); + void DescribeBool( const bool *invalue, int count ); + void DescribeFloat( const float *invalue, int count ); + void DescribeData( int size, const char *indata ); + void DescribeString( const char *instring ); + void DescribeVector( const Vector &inValue ); + void DescribeVector( const Vector *inValue, int count ); + void DescribeQuaternion( const Quaternion &inValue ); + void DescribeQuaternion( const Quaternion *inValue, int count ); + void DescribeEHandle( EHANDLE const *invalue, int count ); + + void DumpDescription( datamap_t *pMap ); + +private: + void DescribeFields_R( int chain_count, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); + + void const *m_pSrc; + int m_nSrcOffsetIndex; + + void Describe( PRINTF_FORMAT_STRING const char *fmt, ... ); + + typedescription_t *m_pCurrentField; + char const *m_pCurrentClassName; + datamap_t *m_pCurrentMap; + + bool m_bShouldReport; + + FN_FIELD_DESCRIPTION m_FieldDescFunc; +}; + +#if defined( CLIENT_DLL ) +class CValueChangeTracker +{ +public: + CValueChangeTracker(); + + void Reset(); + + void StartTrack( char const *pchContext ); + void EndTrack(); + + bool IsActive() const; + + void SetupTracking( C_BaseEntity *ent, char const *pchFieldName ); + void ClearTracking(); + + void Spew(); + + C_BaseEntity *GetEntity(); + +private: + + enum + { + eChangeTrackerBufSize = 128, + }; + + // Returns field size + void GetValue( char *buf, size_t bufsize ); + + bool m_bActive : 1; + bool m_bTracking : 1; + EHANDLE m_hEntityToTrack; + CUtlVector< typedescription_t * > m_FieldStack; + CUtlString m_strFieldName; + CUtlString m_strContext; + // First 128 bytes of data is all we will consider + char m_OrigValueBuf[ eChangeTrackerBufSize ]; + CUtlVector< CUtlString > m_History; +}; + +extern CValueChangeTracker *g_pChangeTracker; + +class CValueChangeTrackerScope +{ +public: + CValueChangeTrackerScope( char const *pchContext ) + { + m_bCallEndTrack = true; + g_pChangeTracker->StartTrack( pchContext ); + } + + // Only calls Start/End if passed in entity matches entity to track + CValueChangeTrackerScope( C_BaseEntity *pEntity, char const *pchContext ) + { + m_bCallEndTrack = g_pChangeTracker->GetEntity() == pEntity; + if ( m_bCallEndTrack ) + { + g_pChangeTracker->StartTrack( pchContext ); + } + } + + ~CValueChangeTrackerScope() + { + if ( m_bCallEndTrack ) + { + g_pChangeTracker->EndTrack(); + } + } +private: + + bool m_bCallEndTrack; +}; + +#if defined( _DEBUG ) +#define PREDICTION_TRACKVALUECHANGESCOPE( context ) CValueChangeTrackerScope scope( context ); +#define PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( entity, context ) CValueChangeTrackerScope scope( entity, context ); +#define PREDICTION_STARTTRACKVALUE( context ) g_pChangeTracker->StartTrack( context ); +#define PREDICTION_ENDTRACKVALUE() g_pChangeTracker->EndTrack(); +#define PREDICTION_SPEWVALUECHANGES() g_pChangeTracker->Spew(); +#else +#define PREDICTION_TRACKVALUECHANGESCOPE( context ) +#define PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( entity, context ) +#define PREDICTION_STARTTRACKVALUE( context ) +#define PREDICTION_ENDTRACKVALUE() +#define PREDICTION_SPEWVALUECHANGES() +#endif + +#endif // !CLIENT_DLL +#endif // PREDICTIONCOPY_H diff --git a/game/shared/props_shared.h b/game/shared/props_shared.h new file mode 100644 index 0000000..07878d8 --- /dev/null +++ b/game/shared/props_shared.h @@ -0,0 +1,257 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PROPS_SHARED_H +#define PROPS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include + +// Phys prop spawnflags +#define SF_PHYSPROP_START_ASLEEP 0x000001 +#define SF_PHYSPROP_DONT_TAKE_PHYSICS_DAMAGE 0x000002 // this prop can't be damaged by physics collisions +#define SF_PHYSPROP_DEBRIS 0x000004 +#define SF_PHYSPROP_MOTIONDISABLED 0x000008 // motion disabled at startup (flag only valid in spawn - motion can be enabled via input) +#define SF_PHYSPROP_TOUCH 0x000010 // can be 'crashed through' by running player (plate glass) +#define SF_PHYSPROP_PRESSURE 0x000020 // can be broken by a player standing on it +#define SF_PHYSPROP_ENABLE_ON_PHYSCANNON 0x000040 // enable motion only if the player grabs it with the physcannon +#define SF_PHYSPROP_NO_ROTORWASH_PUSH 0x000080 // The rotorwash doesn't push these +#define SF_PHYSPROP_ENABLE_PICKUP_OUTPUT 0x000100 // If set, allow the player to +USE this for the purposes of generating an output +#define SF_PHYSPROP_PREVENT_PICKUP 0x000200 // If set, prevent +USE/Physcannon pickup of this prop +#define SF_PHYSPROP_PREVENT_PLAYER_TOUCH_ENABLE 0x000400 // If set, the player will not cause the object to enable its motion when bumped into +#define SF_PHYSPROP_HAS_ATTACHED_RAGDOLLS 0x000800 // Need to remove attached ragdolls on enable motion/etc +#define SF_PHYSPROP_FORCE_TOUCH_TRIGGERS 0x001000 // Override normal debris behavior and respond to triggers anyway +#define SF_PHYSPROP_FORCE_SERVER_SIDE 0x002000 // Force multiplayer physics object to be serverside +#define SF_PHYSPROP_RADIUS_PICKUP 0x004000 // For Xbox, makes small objects easier to pick up by allowing them to be found +#define SF_PHYSPROP_ALWAYS_PICK_UP 0x100000 // Physcannon can always pick this up, no matter what mass or constraints may apply. +#define SF_PHYSPROP_NO_COLLISIONS 0x200000 // Don't enable collisions on spawn +#define SF_PHYSPROP_IS_GIB 0x400000 // Limit # of active gibs + +// Any barrel farther away than this is ignited rather than exploded. +#define PROP_EXPLOSION_IGNITE_RADIUS 32.0f + +// ParsePropData returns +enum +{ + PARSE_SUCCEEDED, // Parsed propdata. Prop must be a prop_physics. + PARSE_SUCCEEDED_ALLOWED_STATIC, // Parsed propdata. Prop allowed to be prop_physics or prop_dynamic/prop_static. + PARSE_FAILED_NO_DATA, // Parse failed, no propdata in model. Prop must be prop_dynamic/prop_static. + PARSE_FAILED_BAD_DATA, // Parse failed, found propdata but it had bad data. +}; + +// Propdata defined interactions +enum propdata_interactions_t +{ + PROPINTER_PHYSGUN_WORLD_STICK, // "onworldimpact" "stick" + PROPINTER_PHYSGUN_FIRST_BREAK, // "onfirstimpact" "break" + PROPINTER_PHYSGUN_FIRST_PAINT, // "onfirstimpact" "paintsplat" + PROPINTER_PHYSGUN_FIRST_IMPALE, // "onfirstimpact" "impale" + PROPINTER_PHYSGUN_LAUNCH_SPIN_NONE, // "onlaunch" "spin_none" + PROPINTER_PHYSGUN_LAUNCH_SPIN_Z, // "onlaunch" "spin_zaxis" + PROPINTER_PHYSGUN_BREAK_EXPLODE, // "onbreak" "explode_fire" + PROPINTER_PHYSGUN_DAMAGE_NONE, // "damage" "none" + + PROPINTER_FIRE_FLAMMABLE, // "flammable" "yes" + PROPINTER_FIRE_EXPLOSIVE_RESIST, // "explosive_resist" "yes" + PROPINTER_FIRE_IGNITE_HALFHEALTH, // "ignite" "halfhealth" + + PROPINTER_PHYSGUN_CREATE_FLARE, // "onpickup" "create_flare" + + PROPINTER_PHYSGUN_ALLOW_OVERHEAD, // "allow_overhead" "yes" + + PROPINTER_WORLD_BLOODSPLAT, // "onworldimpact", "bloodsplat" + + PROPINTER_PHYSGUN_NOTIFY_CHILDREN, // "onfirstimpact" cause attached flechettes to explode + + // If we get more than 32 of these, we'll need a different system + + PROPINTER_NUM_INTERACTIONS, +}; + +// Entities using COLLISION_GROUP_SPECIAL_PHYSICS should support this interface. +abstract_class IMultiplayerPhysics +{ +public: + virtual int GetMultiplayerPhysicsMode() = 0; + virtual float GetMass() = 0; + virtual bool IsAsleep() = 0; +}; + +#define PHYSICS_MULTIPLAYER_AUTODETECT 0 // use multiplayer physics mode as defined in model prop data +#define PHYSICS_MULTIPLAYER_SOLID 1 // soild, pushes player away +#define PHYSICS_MULTIPLAYER_NON_SOLID 2 // nonsolid, but pushed by player +#define PHYSICS_MULTIPLAYER_CLIENTSIDE 3 // Clientside only, nonsolid + +enum mp_break_t +{ + MULTIPLAYER_BREAK_DEFAULT, + MULTIPLAYER_BREAK_SERVERSIDE, + MULTIPLAYER_BREAK_CLIENTSIDE, + MULTIPLAYER_BREAK_BOTH +}; + + +enum PerformanceMode_t +{ + PM_NORMAL, + PM_NO_GIBS, + PM_FULL_GIBS, + PM_REDUCED_GIBS, +}; + + +//============================================================================================================= +// PROP DATA +//============================================================================================================= +//----------------------------------------------------------------------------- +// Purpose: Derive your entity from this if you want your entity to parse propdata +//----------------------------------------------------------------------------- +abstract_class IBreakableWithPropData +{ +public: + // Damage modifiers + virtual void SetDmgModBullet( float flDmgMod ) = 0; + virtual void SetDmgModClub( float flDmgMod ) = 0; + virtual void SetDmgModExplosive( float flDmgMod ) = 0; + virtual float GetDmgModBullet( void ) = 0; + virtual float GetDmgModClub( void ) = 0; + virtual float GetDmgModExplosive( void ) = 0; + + // Explosive + virtual void SetExplosiveRadius( float flRadius ) = 0; + virtual void SetExplosiveDamage( float flDamage ) = 0; + virtual float GetExplosiveRadius( void ) = 0; + virtual float GetExplosiveDamage( void ) = 0; + + // Physics damage tables + virtual void SetPhysicsDamageTable( string_t iszTableName ) = 0; + virtual string_t GetPhysicsDamageTable( void ) = 0; + + // Breakable chunks + virtual void SetBreakableModel( string_t iszModel ) = 0; + virtual string_t GetBreakableModel( void ) = 0; + virtual void SetBreakableSkin( int iSkin ) = 0; + virtual int GetBreakableSkin( void ) = 0; + virtual void SetBreakableCount( int iCount ) = 0; + virtual int GetBreakableCount( void ) = 0; + virtual void SetMaxBreakableSize( int iSize ) = 0; + virtual int GetMaxBreakableSize( void ) = 0; + + // LOS blocking + virtual void SetPropDataBlocksLOS( bool bBlocksLOS ) = 0; + virtual void SetPropDataIsAIWalkable( bool bBlocksLOS ) = 0; + + // Interactions + virtual void SetInteraction( propdata_interactions_t Interaction ) = 0; + virtual bool HasInteraction( propdata_interactions_t Interaction ) = 0; + + // Multiplayer physics mode + virtual void SetPhysicsMode(int iMode) = 0; + virtual int GetPhysicsMode() = 0; + + // Multiplayer breakable spawn behavior + virtual void SetMultiplayerBreakMode( mp_break_t mode ) = 0; + virtual mp_break_t GetMultiplayerBreakMode( void ) const = 0; + + // Used for debugging + virtual void SetBasePropData( string_t iszBase ) = 0; + virtual string_t GetBasePropData( void ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Gamesystem that parses the prop data file +//----------------------------------------------------------------------------- +class CPropData : public CAutoGameSystem +{ +public: + CPropData( void ); + + // Inherited from IAutoServerSystem + virtual void LevelInitPreEntity( void ); + virtual void LevelShutdownPostEntity( void ); + + // Read in the data from the prop data file + void ParsePropDataFile( void ); + + // Parse a keyvalues section into the prop + int ParsePropFromKV( CBaseEntity *pProp, KeyValues *pSection, KeyValues *pInteractionSection ); + + // Fill out a prop's with base data parsed from the propdata file + int ParsePropFromBase( CBaseEntity *pProp, const char *pszPropData ); + + // Get a random chunk in the specified breakable section + const char *GetRandomChunkModel( const char *pszBreakableSection, int iMaxSize = -1 ); + +protected: + KeyValues *m_pKVPropData; + bool m_bPropDataLoaded; + + struct propdata_breakablechunk_t + { + string_t iszChunkType; + CUtlVector iszChunkModels; + }; + CUtlVector m_BreakableChunks; +}; + +extern CPropData g_PropDataSystem; + +struct breakmodel_t +{ + Vector offset; + char modelName[512]; + char placementName[512]; + float fadeTime; + float fadeMinDist; + float fadeMaxDist; + float health; + float burstScale; + int collisionGroup; + bool isRagdoll; + bool placementIsBone; + bool isMotionDisabled; + mp_break_t mpBreakMode; + Vector velocity; +}; + +struct breakablepropparams_t +{ + breakablepropparams_t( const Vector &_origin, const QAngle &_angles, const Vector &_velocity, const AngularImpulse &_angularVelocity ) + : origin(_origin), angles(_angles), velocity(_velocity), angularVelocity(_angularVelocity) + { + impactEnergyScale = 0; + defBurstScale = 0; + defCollisionGroup = COLLISION_GROUP_NONE; + nDefaultSkin = 0; + } + + const Vector &origin; + const QAngle &angles; + const Vector &velocity; + const AngularImpulse &angularVelocity; + float impactEnergyScale; + float defBurstScale; + int defCollisionGroup; + int nDefaultSkin; +}; + +const char *GetMassEquivalent(float flMass); +int GetAutoMultiplayerPhysicsMode( Vector size, float mass ); +void BuildPropList( const char *pszBlockName, CUtlVector &list, int modelindex, float defBurstScale, int defCollisionGroup ); +void BreakModelList( CUtlVector &list, int modelindex, float defBurstScale, int defCollisionGroup ); +void PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const breakablepropparams_t ¶ms, CBaseEntity *pEntity, int iPrecomputedBreakableCount, bool bIgnoreGibLImit, bool defaultLocation = true ); +void PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const Vector &origin, const QAngle &angles, const Vector &velocity, const AngularImpulse &angularVelocity, float impactEnergyScale, float burstScale, int collisionGroup, CBaseEntity *pEntity = NULL, bool defaultLocation = true ); + +// Player gibs. +void PrecachePropsForModel( int iModel, const char *pszBlockName ); +void PrecacheGibsForModel( int iModel ); +void BuildGibList( CUtlVector &list, int modelindex, float defBurstScale, int defCollisionGroup ); +CBaseEntity *CreateGibsFromList( CUtlVector &list, int modelindex, IPhysicsObject *pPhysics, const breakablepropparams_t ¶ms, CBaseEntity *pEntity, int iPrecomputedBreakableCount, bool bIgnoreGibLImit, bool defaultLocation = true, CUtlVector *pGibList = NULL, bool bBurning = false ); + +#endif // PROPS_SHARED_H diff --git a/game/shared/querycache.h b/game/shared/querycache.h new file mode 100644 index 0000000..774be51 --- /dev/null +++ b/game/shared/querycache.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef QUERYCACHE_H +#define QUERYCACHE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "mathlib/vector.h" + +// this system provides several piece of functionality to ai or other systems which wish to do +// traces and other trace-like queries. + +// a. By maintaining a set of incrementally updated trace results, it makes it simple to have ai +// code use hyteresis on traces as an optimization method. + +// b. By updating the cache entries outside of the entity think functions, the update is done in a +// fully multi-threaded fashion + + +enum EQueryType_t +{ + EQUERY_INVALID = 0, // an invalid or unused entry + EQUERY_TRACELINE, + EQUERY_ENTITY_LOS_CHECK, + +}; + +enum EEntityOffsetMode_t +{ + EOFFSET_MODE_WORLDSPACE_CENTER, + EOFFSET_MODE_EYEPOSITION, + EOFFSET_MODE_NONE, // nop +}; + + +#define QCACHE_MAXPNTS 3 // maximum number of points/entities + // involved in a query + +struct QueryCacheKey_t +{ + EQueryType_t m_Type; + int m_nNumValidPoints; + Vector m_Points[QCACHE_MAXPNTS]; + EHANDLE m_pEntities[QCACHE_MAXPNTS]; + EEntityOffsetMode_t m_nOffsetMode[QCACHE_MAXPNTS]; + unsigned int m_nTraceMask; + unsigned int m_nHashIdx; + int m_nCollisionGroup; + ShouldHitFunc_t m_pTraceFilterFunction; + + float m_flMinimumUpdateInterval; + + void ComputeHashIndex( void ); + + bool Matches( QueryCacheKey_t const *pNode ) const ; +}; + +struct QueryCacheEntry_t +{ + QueryCacheEntry_t *m_pNext; + QueryCacheEntry_t *m_pPrev; + QueryCacheKey_t m_QueryParams; + float m_flLastUpdateTime; + bool m_bUsedSinceUpdated; // was this cell referenced? + bool m_bSpeculativelyDone; + bool m_bResult; // for queries with a boolean result + + void IssueQuery( void ); + +}; + + + +bool IsLineOfSightBetweenTwoEntitiesClear( CBaseEntity *pSrcEntity, + EEntityOffsetMode_t nSrcOffsetMode, + CBaseEntity *pDestEntity, + EEntityOffsetMode_t nDestOffsetMode, + CBaseEntity *pSkipEntity, + int nCollisionGroup, + unsigned int nTraceMask, + ShouldHitFunc_t pTraceFilterCallback, + float flMinimumUpdateInterval = 0.2 + ); + + + +// call during main loop for threaded update of the query cache +void UpdateQueryCache( void ); + +// call on level transition or other significant step-functions +void InvalidateQueryCache( void ); + +#endif // querycache_h diff --git a/game/shared/ragdoll_shared.h b/game/shared/ragdoll_shared.h new file mode 100644 index 0000000..f230e99 --- /dev/null +++ b/game/shared/ragdoll_shared.h @@ -0,0 +1,157 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef RAGDOLL_SHARED_H +#define RAGDOLL_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +class IPhysicsObject; +class IPhysicsConstraint; +class IPhysicsConstraintGroup; +class IPhysicsCollision; +class IPhysicsEnvironment; +class IPhysicsSurfaceProps; +struct matrix3x4_t; + +struct vcollide_t; +struct studiohdr_t; +class CStudioHdr; +class CBoneAccessor; + +#include "mathlib/vector.h" +#include "bone_accessor.h" + +// UNDONE: Remove and make dynamic? +#define RAGDOLL_MAX_ELEMENTS 24 +#define RAGDOLL_INDEX_BITS 5 // NOTE 1<= RAGDOLL_MAX_ELEMENTS + +#define CORE_DISSOLVE_FADE_START 0.2f +#define CORE_DISSOLVE_MODEL_FADE_START 0.1f +#define CORE_DISSOLVE_MODEL_FADE_LENGTH 0.05f +#define CORE_DISSOLVE_FADEIN_LENGTH 0.1f + +struct ragdollelement_t +{ + Vector originParentSpace; + IPhysicsObject *pObject; // all valid elements have an object + IPhysicsConstraint *pConstraint; // all valid elements have a constraint (except the root) + int parentIndex; +}; + +struct ragdollanimatedfriction_t +{ + float flFrictionTimeIn; + float flFrictionTimeOut; + float flFrictionTimeHold; + int iMinAnimatedFriction; + int iMaxAnimatedFriction; +}; + +struct ragdoll_t +{ + int listCount; + bool allowStretch; + bool unused; + IPhysicsConstraintGroup *pGroup; + // store these in separate arrays for save/load + ragdollelement_t list[RAGDOLL_MAX_ELEMENTS]; + int boneIndex[RAGDOLL_MAX_ELEMENTS]; + ragdollanimatedfriction_t animfriction; +}; + +struct ragdollparams_t +{ + void *pGameData; + vcollide_t *pCollide; + CStudioHdr *pStudioHdr; + int modelIndex; + Vector forcePosition; + Vector forceVector; + int forceBoneIndex; + const matrix3x4_t *pCurrentBones; + float jointFrictionScale; + bool allowStretch; + bool fixedConstraints; +}; + +//----------------------------------------------------------------------------- +// This hooks the main game systems callbacks to allow the AI system to manage memory +//----------------------------------------------------------------------------- +class CRagdollLRURetirement : public CAutoGameSystemPerFrame +{ +public: + CRagdollLRURetirement( char const *name ) : CAutoGameSystemPerFrame( name ) + { + } + + // Methods of IGameSystem + virtual void Update( float frametime ); + virtual void FrameUpdatePostEntityThink( void ); + + // Move it to the top of the LRU + void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false ); + void SetMaxRagdollCount( int iMaxCount ){ m_iMaxRagdolls = iMaxCount; } + + virtual void LevelInitPreEntity( void ); + int CountRagdolls( bool bOnlySimulatingRagdolls ) { return bOnlySimulatingRagdolls ? m_iSimulatedRagdollCount : m_iRagdollCount; } + +private: + typedef CHandle CRagdollHandle; + CUtlLinkedList< CRagdollHandle > m_LRU; + CUtlLinkedList< CRagdollHandle > m_LRUImportantRagdolls; + + int m_iMaxRagdolls; + int m_iSimulatedRagdollCount; + int m_iRagdollCount; +}; + +extern CRagdollLRURetirement s_RagdollLRU; + +// Manages ragdolls fading for the low violence versions +class CRagdollLowViolenceManager +{ +public: + CRagdollLowViolenceManager(){ m_bLowViolence = false; } + // Turn the low violence ragdoll stuff off if we're in the HL2 Citadel maps because + // the player has the super gravity gun and fading ragdolls will break things. + void SetLowViolence( const char *pMapName ); + bool IsLowViolence( void ){ return m_bLowViolence; } + +private: + bool m_bLowViolence; +}; + +extern CRagdollLowViolenceManager g_RagdollLVManager; + + +bool RagdollCreate( ragdoll_t &ragdoll, const ragdollparams_t ¶ms, IPhysicsEnvironment *pPhysEnv ); + +void RagdollActivate( ragdoll_t &ragdoll, vcollide_t *pCollide, int modelIndex, bool bForceWake = true ); +void RagdollSetupCollisions( ragdoll_t &ragdoll, vcollide_t *pCollide, int modelIndex ); +void RagdollDestroy( ragdoll_t &ragdoll ); + +// Gets the bone matrix for a ragdoll object +// NOTE: This is different than the object's position because it is +// forced to be rigidly attached in parent space +bool RagdollGetBoneMatrix( const ragdoll_t &ragdoll, CBoneAccessor &pBoneToWorld, int objectIndex ); + +// Parse the ragdoll and obtain the mapping from each physics element index to a bone index +// returns num phys elements +int RagdollExtractBoneIndices( int *boneIndexOut, CStudioHdr *pStudioHdr, vcollide_t *pCollide ); + +// computes an exact bbox of the ragdoll's physics objects +void RagdollComputeExactBbox( const ragdoll_t &ragdoll, const Vector &origin, Vector &outMins, Vector &outMaxs ); +bool RagdollIsAsleep( const ragdoll_t &ragdoll ); +void RagdollSetupAnimatedFriction( IPhysicsEnvironment *pPhysEnv, ragdoll_t *ragdoll, int iModelIndex ); + +void RagdollApplyAnimationAsVelocity( ragdoll_t &ragdoll, const matrix3x4_t *pBoneToWorld ); +void RagdollApplyAnimationAsVelocity( ragdoll_t &ragdoll, const matrix3x4_t *pPrevBones, const matrix3x4_t *pCurrentBones, float dt ); + +void RagdollSolveSeparation( ragdoll_t &ragdoll, CBaseEntity *pEntity ); + +#endif // RAGDOLL_SHARED_H diff --git a/game/shared/rope_helpers.h b/game/shared/rope_helpers.h new file mode 100644 index 0000000..7a5ad78 --- /dev/null +++ b/game/shared/rope_helpers.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ROPE_HELPERS_H +#define ROPE_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" + + +// +// This function can help you choose starting conditions for your rope. It is fairly +// expensive (slightly less than 0.5ms for a 10-node rope), but it's within reason for the +// frequency we create ropes at. +// +// Input: +// - rope endpoints +// - the number of nodes the client will be simulating (CRopeKeyframe::m_nSegments) +// - how low you want the rope to hang (below the lowest of the two endpoints) +// +// Output: +// - pOutputLength = length of the rope +// - pOutputSlack = slack you should set to produce the desired hang +// +void CalcRopeStartingConditions( + const Vector &vStartPos, + const Vector &vEndPos, + int const nNodes, + float const desiredHang, + float *pOutputLength, + float *pOutputSlack + ); + + +#endif // ROPE_HELPERS_H diff --git a/game/shared/rumble_shared.h b/game/shared/rumble_shared.h new file mode 100644 index 0000000..07707de --- /dev/null +++ b/game/shared/rumble_shared.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared code for XBox Rumble Effects +// +// $NoKeywords: $ +// +//=============================================================================// +#pragma once +#ifndef RUMBLE_SHARED_H +#define RUMBLE_SHARED_H + +#define RUMBLE_FLAGS_NONE 0x0000 +#define RUMBLE_FLAG_STOP 0x0001 // Stop any instance of this type of effect that's already playing. +#define RUMBLE_FLAG_LOOP 0x0002 // Make this effect loop. +#define RUMBLE_FLAG_RESTART 0x0004 // If this effect is already playing, restart it. +#define RUMBLE_FLAG_UPDATE_SCALE 0x0008 // Apply DATA to this effect if already playing, but don't restart. +#define RUMBLE_FLAG_ONLYONE 0x0010 // Don't play this effect if it is already playing. +#define RUMBLE_FLAG_RANDOM_AMPLITUDE 0x0020 // Amplitude scale will be randomly chosen. Between 10% and 100% +#define RUMBLE_FLAG_INITIAL_SCALE 0x0040 // Data is the initial scale to start this effect ( * 100 ) + +enum +{ +// DO NOT CHANGE THE ORDER OF ANY OF THESE ENUMS +// DO NOT INSERT ANY ITEMS + RUMBLE_INVALID = -1, + + RUMBLE_STOP_ALL = 0, // Cease all current rumbling effects. + + // Weapons + RUMBLE_PISTOL, + RUMBLE_357, + RUMBLE_SMG1, + RUMBLE_AR2, + RUMBLE_SHOTGUN_SINGLE, + RUMBLE_SHOTGUN_DOUBLE, + RUMBLE_AR2_ALT_FIRE, + +// YOU MAY INSERT/REARRANGE ITEMS FROM HERE DOWN, AS YOU SEE FIT + RUMBLE_RPG_MISSILE, + + RUMBLE_CROWBAR_SWING, + + // Vehicles + RUMBLE_AIRBOAT_GUN, + RUMBLE_JEEP_ENGINE_LOOP, + + RUMBLE_FLAT_LEFT, + RUMBLE_FLAT_RIGHT, + RUMBLE_FLAT_BOTH, + + // Damage + RUMBLE_DMG_LOW, + RUMBLE_DMG_MED, + RUMBLE_DMG_HIGH, + + // Fall damage + RUMBLE_FALL_LONG, + RUMBLE_FALL_SHORT, + + RUMBLE_PHYSCANNON_OPEN, + RUMBLE_PHYSCANNON_PUNT, + RUMBLE_PHYSCANNON_LOW, + RUMBLE_PHYSCANNON_MEDIUM, + RUMBLE_PHYSCANNON_HIGH, + + RUMBLE_PORTALGUN_LEFT, + RUMBLE_PORTALGUN_RIGHT, + RUMBLE_PORTAL_PLACEMENT_FAILURE, + + NUM_RUMBLE_EFFECTS, // THIS MUST BE LAST!!! +}; + +#endif//RUMBLE_SHARED_H \ No newline at end of file diff --git a/game/shared/saverestore.h b/game/shared/saverestore.h new file mode 100644 index 0000000..ebadd0d --- /dev/null +++ b/game/shared/saverestore.h @@ -0,0 +1,355 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Helper classes and functions for the save/restore system. These +// classes are internally structured to distinguish simple from +// complex types. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SAVERESTORE_H +#define SAVERESTORE_H + +#include "isaverestore.h" +#include "utlvector.h" +#include "filesystem.h" + +#ifdef _WIN32 +#pragma once +#endif + +//------------------------------------- + +class CSaveRestoreData; +class CSaveRestoreSegment; +class CGameSaveRestoreInfo; +struct typedescription_t; +struct edict_t; +struct datamap_t; +class CBaseEntity; +struct interval_t; + +//----------------------------------------------------------------------------- +// +// CSave +// +//----------------------------------------------------------------------------- + +class CSave : public ISave +{ +public: + CSave( CSaveRestoreData *pdata ); + + //--------------------------------- + // Logging + void StartLogging( const char *pszLogName ); + void EndLogging( void ); + + //--------------------------------- + bool IsAsync(); + + //--------------------------------- + + int GetWritePos() const; + void SetWritePos(int pos); + + //--------------------------------- + // Datamap based writing + // + + int WriteAll( const void *pLeafObject, datamap_t *pLeafMap ) { return DoWriteAll( pLeafObject, pLeafMap, pLeafMap ); } + + int WriteFields( const char *pname, const void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); + + //--------------------------------- + // Block support + // + + virtual void StartBlock( const char *pszBlockName ); + virtual void StartBlock(); + virtual void EndBlock(); + + //--------------------------------- + // Primitive types + // + + void WriteShort( const short *value, int count = 1 ); + void WriteInt( const int *value, int count = 1 ); // Save an int + void WriteBool( const bool *value, int count = 1 ); // Save a bool + void WriteFloat( const float *value, int count = 1 ); // Save a float + void WriteData( const char *pdata, int size ); // Save a binary data block + void WriteString( const char *pstring ); // Save a null-terminated string + void WriteString( const string_t *stringId, int count = 1 ); // Save a null-terminated string (engine string) + void WriteVector( const Vector &value ); // Save a vector + void WriteVector( const Vector *value, int count = 1 ); // Save a vector array + void WriteQuaternion( const Quaternion &value ); // Save a Quaternion + void WriteQuaternion( const Quaternion *value, int count = 1 ); // Save a Quaternion array + void WriteVMatrix( const VMatrix *value, int count = 1 ); // Save a vmatrix array + + // Note: All of the following will write out both a header and the data. On restore, + // this needs to be cracked + void WriteShort( const char *pname, const short *value, int count = 1 ); + void WriteInt( const char *pname, const int *value, int count = 1 ); // Save an int + void WriteBool( const char *pname, const bool *value, int count = 1 ); // Save a bool + void WriteFloat( const char *pname, const float *value, int count = 1 ); // Save a float + void WriteData( const char *pname, int size, const char *pdata ); // Save a binary data block + void WriteString( const char *pname, const char *pstring ); // Save a null-terminated string + void WriteString( const char *pname, const string_t *stringId, int count = 1 ); // Save a null-terminated string (engine string) + void WriteVector( const char *pname, const Vector &value ); // Save a vector + void WriteVector( const char *pname, const Vector *value, int count = 1 ); // Save a vector array + void WriteQuaternion( const char *pname, const Quaternion &value ); // Save a Quaternion + void WriteQuaternion( const char *pname, const Quaternion *value, int count = 1 ); // Save a Quaternion array + void WriteVMatrix( const char *pname, const VMatrix *value, int count = 1 ); + //--------------------------------- + // Game types + // + + void WriteTime( const char *pname, const float *value, int count = 1 ); // Save a float (timevalue) + void WriteTick( const char *pname, const int *value, int count = 1 ); // Save a int (timevalue) + void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary + void WritePositionVector( const char *pname, const Vector *value, int count = 1 ); // array of pos vectors + void WriteFunction( datamap_t *pMap, const char *pname, inputfunc_t **value, int count = 1 ); // Save a function pointer + + void WriteEntityPtr( const char *pname, CBaseEntity **ppEntity, int count = 1 ); + void WriteEdictPtr( const char *pname, edict_t **ppEdict, int count = 1 ); + void WriteEHandle( const char *pname, const EHANDLE *pEHandle, int count = 1 ); + + virtual void WriteTime( const float *value, int count = 1 ); // Save a float (timevalue) + virtual void WriteTick( const int *value, int count = 1 ); // Save a int (timevalue) + virtual void WritePositionVector( const Vector &value ); // Offset for landmark if necessary + virtual void WritePositionVector( const Vector *value, int count = 1 ); // array of pos vectors + + virtual void WriteEntityPtr( CBaseEntity **ppEntity, int count = 1 ); + virtual void WriteEdictPtr( edict_t **ppEdict, int count = 1 ); + virtual void WriteEHandle( const EHANDLE *pEHandle, int count = 1 ); + void WriteVMatrixWorldspace( const char *pname, const VMatrix *value, int count = 1 ); // Save a vmatrix array + void WriteVMatrixWorldspace( const VMatrix *value, int count = 1 ); // Save a vmatrix array + void WriteMatrix3x4Worldspace( const matrix3x4_t *value, int count ); + void WriteMatrix3x4Worldspace( const char *pname, const matrix3x4_t *value, int count ); + + void WriteInterval( const interval_t *value, int count = 1 ); // Save an interval + void WriteInterval( const char *pname, const interval_t *value, int count = 1 ); + + //--------------------------------- + + int EntityIndex( const CBaseEntity *pEntity ); + int EntityFlagsSet( int entityIndex, int flags ); + + CGameSaveRestoreInfo *GetGameSaveRestoreInfo() { return m_pGameInfo; } + +private: + + //--------------------------------- + bool IsLogging( void ); + void Log( const char *pName, fieldtype_t fieldType, void *value, int count ); + + //--------------------------------- + + void BufferField( const char *pname, int size, const char *pdata ); + void BufferData( const char *pdata, int size ); + void WriteHeader( const char *pname, int size ); + + int DoWriteAll( const void *pLeafObject, datamap_t *pLeafMap, datamap_t *pCurMap ); + bool WriteField( const char *pname, void *pData, datamap_t *pRootMap, typedescription_t *pField ); + + bool WriteBasicField( const char *pname, void *pData, datamap_t *pRootMap, typedescription_t *pField ); + + int DataEmpty( const char *pdata, int size ); + void BufferString( char *pdata, int len ); + + int CountFieldsToSave( const void *pBaseData, typedescription_t *pFields, int fieldCount ); + bool ShouldSaveField( const void *pData, typedescription_t *pField ); + + //--------------------------------- + // Game info methods + // + + bool WriteGameField( const char *pname, void *pData, datamap_t *pRootMap, typedescription_t *pField ); + int EntityIndex( const edict_t *pentLookup ); + + //--------------------------------- + + CUtlVector m_BlockStartStack; + + // Stream data + CSaveRestoreSegment *m_pData; + + // Game data + CGameSaveRestoreInfo *m_pGameInfo; + + FileHandle_t m_hLogFile; + bool m_bAsync; +}; + +//----------------------------------------------------------------------------- +// +// CRestore +// +//----------------------------------------------------------------------------- + +class CRestore : public IRestore +{ +public: + CRestore( CSaveRestoreData *pdata ); + + int GetReadPos() const; + void SetReadPos( int pos ); + + //--------------------------------- + // Datamap based reading + // + + int ReadAll( void *pLeafObject, datamap_t *pLeafMap ) { return DoReadAll( pLeafObject, pLeafMap, pLeafMap ); } + + int ReadFields( const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); + void EmptyFields( void *pBaseData, typedescription_t *pFields, int fieldCount ); + + //--------------------------------- + // Block support + // + + virtual void StartBlock( SaveRestoreRecordHeader_t *pHeader ); + virtual void StartBlock( char szBlockName[SIZE_BLOCK_NAME_BUF] ); + virtual void StartBlock(); + virtual void EndBlock(); + + //--------------------------------- + // Field header cracking + // + + void ReadHeader( SaveRestoreRecordHeader_t *pheader ); + int SkipHeader() { SaveRestoreRecordHeader_t header; ReadHeader( &header ); return header.size; } + const char * StringFromHeaderSymbol( int symbol ); + + //--------------------------------- + // Primitive types + // + + short ReadShort( void ); + int ReadShort( short *pValue, int count = 1, int nBytesAvailable = 0); + int ReadInt( int *pValue, int count = 1, int nBytesAvailable = 0); + int ReadInt( void ); + int ReadBool( bool *pValue, int count = 1, int nBytesAvailable = 0); + int ReadFloat( float *pValue, int count = 1, int nBytesAvailable = 0); + int ReadData( char *pData, int size, int nBytesAvailable ); + void ReadString( char *pDest, int nSizeDest, int nBytesAvailable ); // A null-terminated string + int ReadString( string_t *pString, int count = 1, int nBytesAvailable = 0); + int ReadVector( Vector *pValue ); + int ReadVector( Vector *pValue, int count = 1, int nBytesAvailable = 0); + int ReadQuaternion( Quaternion *pValue ); + int ReadQuaternion( Quaternion *pValue, int count = 1, int nBytesAvailable = 0); + int ReadVMatrix( VMatrix *pValue, int count = 1, int nBytesAvailable = 0); + + //--------------------------------- + // Game types + // + + int ReadTime( float *pValue, int count = 1, int nBytesAvailable = 0); + int ReadTick( int *pValue, int count = 1, int nBytesAvailable = 0); + int ReadPositionVector( Vector *pValue ); + int ReadPositionVector( Vector *pValue, int count = 1, int nBytesAvailable = 0); + int ReadFunction( datamap_t *pMap, inputfunc_t **pValue, int count = 1, int nBytesAvailable = 0); + + int ReadEntityPtr( CBaseEntity **ppEntity, int count = 1, int nBytesAvailable = 0 ); + int ReadEdictPtr( edict_t **ppEdict, int count = 1, int nBytesAvailable = 0 ); + int ReadEHandle( EHANDLE *pEHandle, int count = 1, int nBytesAvailable = 0 ); + int ReadVMatrixWorldspace( VMatrix *pValue, int count = 1, int nBytesAvailable = 0); + int ReadMatrix3x4Worldspace( matrix3x4_t *pValue, int nElems = 1, int nBytesAvailable = 0 ); + int ReadInterval( interval_t *interval, int count = 1, int nBytesAvailable = 0 ); + + //--------------------------------- + + void SetGlobalMode( int global ) { m_global = global; } + void PrecacheMode( bool mode ) { m_precache = mode; } + bool GetPrecacheMode( void ) { return m_precache; } + + CGameSaveRestoreInfo *GetGameSaveRestoreInfo() { return m_pGameInfo; } + +private: + //--------------------------------- + // Read primitives + // + + char * BufferPointer( void ); + void BufferSkipBytes( int bytes ); + + int DoReadAll( void *pLeafObject, datamap_t *pLeafMap, datamap_t *pCurMap ); + + typedescription_t *FindField( const char *pszFieldName, typedescription_t *pFields, int fieldCount, int *pIterator ); + void ReadField( const SaveRestoreRecordHeader_t &header, void *pDest, datamap_t *pRootMap, typedescription_t *pField ); + + void ReadBasicField( const SaveRestoreRecordHeader_t &header, void *pDest, datamap_t *pRootMap, typedescription_t *pField ); + + void BufferReadBytes( char *pOutput, int size ); + + template + int ReadSimple( T *pValue, int nElems, int nBytesAvailable ) // must be inline in class to keep MSVS happy + { + int desired = nElems * sizeof(T); + int actual; + + if ( nBytesAvailable == 0 ) + actual = desired; + else + { + Assert( nBytesAvailable % sizeof(T) == 0 ); + actual = MIN( desired, nBytesAvailable ); + } + + BufferReadBytes( (char *)pValue, actual ); + + if ( actual < nBytesAvailable ) + BufferSkipBytes( nBytesAvailable - actual ); + + return ( actual / sizeof(T) ); + } + + bool ShouldReadField( typedescription_t *pField ); + bool ShouldEmptyField( typedescription_t *pField ); + + //--------------------------------- + // Game info methods + // + CBaseEntity * EntityFromIndex( int entityIndex ); + void ReadGameField( const SaveRestoreRecordHeader_t &header, void *pDest, datamap_t *pRootMap, typedescription_t *pField ); + + //--------------------------------- + + CUtlVector m_BlockEndStack; + + // Stream data + CSaveRestoreSegment *m_pData; + + // Game data + CGameSaveRestoreInfo * m_pGameInfo; + int m_global; // Restoring a global entity? + bool m_precache; +}; + + +//----------------------------------------------------------------------------- +// An interface passed into the OnSave method of all entities +//----------------------------------------------------------------------------- +abstract_class IEntitySaveUtils +{ +public: + // Adds a level transition save dependency + virtual void AddLevelTransitionSaveDependency( CBaseEntity *pEntity1, CBaseEntity *pEntity2 ) = 0; + + // Gets the # of dependencies for a particular entity + virtual int GetEntityDependencyCount( CBaseEntity *pEntity ) = 0; + + // Gets all dependencies for a particular entity + virtual int GetEntityDependencies( CBaseEntity *pEntity, int nCount, CBaseEntity **ppEntList ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +IEntitySaveUtils *GetEntitySaveUtils(); + + +//============================================================================= + +#endif // SAVERESTORE_H diff --git a/game/shared/saverestore_bitstring.h b/game/shared/saverestore_bitstring.h new file mode 100644 index 0000000..e7a6c80 --- /dev/null +++ b/game/shared/saverestore_bitstring.h @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SAVERESTORE_BITSTRING_H +#define SAVERESTORE_BITSTRING_H + +#include "isaverestore.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//------------------------------------- + +template +class CVarBitVecSaveRestoreOps : public CDefSaveRestoreOps +{ +public: + CVarBitVecSaveRestoreOps() + { + } + + // save data type interface + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + BITSTRING *pBitString = (BITSTRING *)fieldInfo.pField; + int numBits = pBitString->GetNumBits(); + pSave->WriteInt( &numBits ); + pSave->WriteInt( pBitString->Base(), pBitString->GetNumDWords() ); + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + BITSTRING *pBitString = (BITSTRING *)fieldInfo.pField; + int numBits = pRestore->ReadInt(); + if ( !pBitString->IsFixedSize() ) + pBitString->Resize( numBits ); + else + { + Assert( pBitString->GetNumBits() >= numBits ); + pBitString->ClearAll(); + } + int numIntsInStream = CalcNumIntsForBits( numBits ); + int readSize = MIN( pBitString->GetNumDWords(), numIntsInStream ); + pRestore->ReadInt( pBitString->Base(), numIntsInStream ); + + numIntsInStream -= readSize; + while ( numIntsInStream-- > 0 ) + { + int ignored; + pRestore->ReadInt( &ignored, 1 ); + } + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + BITSTRING *pBitString = (BITSTRING *)fieldInfo.pField; + pBitString->ClearAll(); + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + BITSTRING *pBitString = (BITSTRING *)fieldInfo.pField; + return pBitString->IsAllClear(); + } +}; + +//------------------------------------- + +template +ISaveRestoreOps *GetBitstringDataOps(BITSTRING *) +{ + static CVarBitVecSaveRestoreOps ops; + return &ops; +} + +//------------------------------------- + +#define SaveBitString( pSave, pBitString, fieldtype) \ + CDataopsInstantiator::GetDataOps( pBitString )->Save( pBitString, pSave ); + +#define RestoreBitString( pRestore, pBitString, fieldtype) \ + CDataopsInstantiator::GetDataOps( pBitString )->Restore( pBitString, pRestore ); + +//------------------------------------- + +#define DEFINE_BITSTRING(name) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, GetBitstringDataOps(&(((classNameTypedef *)0)->name)), NULL } + +#endif // SAVERESTORE_BITSTRING_H + diff --git a/game/shared/saverestore_stringtable.h b/game/shared/saverestore_stringtable.h new file mode 100644 index 0000000..3e2ba82 --- /dev/null +++ b/game/shared/saverestore_stringtable.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SAVERESTORE_STRINGTABLE_H +#define SAVERESTORE_STRINGTABLE_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +#include "isaverestore.h" +#include "networkstringtabledefs.h" + + +//------------------------------------- + +class CStringTableSaveRestoreOps : public CDefSaveRestoreOps +{ +public: + void Init( INetworkStringTable* pNetworkStringTable ) + { + m_pStringTable = pNetworkStringTable; + } + + // save data type interface + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + int *pStringIndex = (int *)fieldInfo.pField; + const char *pString = m_pStringTable->GetString( *pStringIndex ); + int nLen = Q_strlen( pString ) + 1; + pSave->WriteInt( &nLen ); + pSave->WriteString( pString ); + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + int *pStringIndex = (int *)fieldInfo.pField; + int nLen = pRestore->ReadInt(); + char *pTemp = (char *)stackalloc( nLen ); + pRestore->ReadString( pTemp, nLen, nLen ); + *pStringIndex = m_pStringTable->AddString( CBaseEntity::IsServer(), pTemp ); + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + int *pStringIndex = (int *)fieldInfo.pField; + *pStringIndex = INVALID_STRING_INDEX; + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + int *pStringIndex = (int *)fieldInfo.pField; + return *pStringIndex == INVALID_STRING_INDEX; + } + +private: + INetworkStringTable *m_pStringTable; +}; + +#endif // SAVERESTORE_STRINGTABLE_H diff --git a/game/shared/saverestore_utlclass.h b/game/shared/saverestore_utlclass.h new file mode 100644 index 0000000..ed38b68 --- /dev/null +++ b/game/shared/saverestore_utlclass.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SAVERESTORE_UTLCLASS_H +#define SAVERESTORE_UTLCLASS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +//------------------------------------- + +template +class CTypedescDeducer +{ +public: + template + static datamap_t *Deduce( UTLCLASS *p ) + { + return NULL; + } + +}; + +template<> +class CTypedescDeducer +{ +public: + template + static datamap_t *Deduce( UTLCLASS *p ) + { + return &UTLCLASS::ElemType_t::m_DataMap; + } + +}; + +#define UTLCLASS_SAVERESTORE_VALIDATE_TYPE( type ) \ + COMPILE_TIME_ASSERT( \ + type == FIELD_FLOAT ||\ + type == FIELD_STRING ||\ + type == FIELD_CLASSPTR ||\ + type == FIELD_EHANDLE ||\ + type == FIELD_EDICT ||\ + type == FIELD_VECTOR ||\ + type == FIELD_QUATERNION ||\ + type == FIELD_POSITION_VECTOR ||\ + type == FIELD_INTEGER ||\ + type == FIELD_BOOLEAN ||\ + type == FIELD_SHORT ||\ + type == FIELD_CHARACTER ||\ + type == FIELD_TIME ||\ + type == FIELD_TICK ||\ + type == FIELD_MODELNAME ||\ + type == FIELD_SOUNDNAME ||\ + type == FIELD_COLOR32 ||\ + type == FIELD_EMBEDDED ||\ + type == FIELD_MODELINDEX ||\ + type == FIELD_MATERIALINDEX\ + ) + +//------------------------------------- + +#endif // SAVERESTORE_UTLCLASS_H diff --git a/game/shared/saverestore_utlmap.h b/game/shared/saverestore_utlmap.h new file mode 100644 index 0000000..06b624a --- /dev/null +++ b/game/shared/saverestore_utlmap.h @@ -0,0 +1,198 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SAVERESTORE_UTLMAP_H +#define SAVERESTORE_UTLMAP_H + +#include "utlmap.h" +#include "saverestore_utlrbtree.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +template +class CUtlMapDataOps : public CDefSaveRestoreOps +{ +public: + CUtlMapDataOps() + { + UTLCLASS_SAVERESTORE_VALIDATE_TYPE( KEY_TYPE ); + UTLCLASS_SAVERESTORE_VALIDATE_TYPE( FIELD_TYPE ); + } + + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + datamap_t *pKeyDatamap = CTypedescDeducer::Deduce( (UTLMAP *)NULL ); + datamap_t *pFieldDatamap = CTypedescDeducer::Deduce( (UTLMAP *)NULL ); + typedescription_t dataDesc[] = + { + { + (fieldtype_t)KEY_TYPE, + "K", + { 0, 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pKeyDatamap, + sizeof(KEY_TYPE), + }, + + { + (fieldtype_t)FIELD_TYPE, + "T", + { offsetof(typename UTLMAP::Node_t, elem), 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pFieldDatamap, + sizeof(FIELD_TYPE), + } + }; + + datamap_t dataMap = + { + dataDesc, + 2, + "um", + NULL, + false, + false, + 0, +#ifdef _DEBUG + true +#endif + }; + + typename UTLMAP::CTree *pUtlRBTree = ((UTLMAP *)fieldInfo.pField)->AccessTree(); + + pSave->StartBlock(); + + int nElems = pUtlRBTree->Count(); + pSave->WriteInt( &nElems, 1 ); + + typename UTLMAP::CTree::IndexType_t i = pUtlRBTree->FirstInorder(); + while ( i != pUtlRBTree->InvalidIndex() ) + { + typename UTLMAP::CTree::ElemType_t &elem = pUtlRBTree->Element( i ); + + pSave->WriteAll( &elem, &dataMap ); + + i = pUtlRBTree->NextInorder( i ); + } + pSave->EndBlock(); + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + datamap_t *pKeyDatamap = CTypedescDeducer::Deduce( (UTLMAP *)NULL ); + datamap_t *pFieldDatamap = CTypedescDeducer::Deduce( (UTLMAP *)NULL ); + typedescription_t dataDesc[] = + { + { + (fieldtype_t)KEY_TYPE, + "K", + { 0, 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pKeyDatamap, + sizeof(KEY_TYPE), + }, + + { + (fieldtype_t)FIELD_TYPE, + "T", + { offsetof(typename UTLMAP::Node_t, elem), 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pFieldDatamap, + sizeof(FIELD_TYPE), + } + }; + + datamap_t dataMap = + { + dataDesc, + 2, + "um", + NULL, + false, + false, + 0, +#ifdef _DEBUG + true +#endif + }; + + UTLMAP *pUtlMap = ((UTLMAP *)fieldInfo.pField); + + pRestore->StartBlock(); + + int nElems = pRestore->ReadInt(); + typename UTLMAP::CTree::ElemType_t temp; + + while ( nElems-- ) + { + pRestore->ReadAll( &temp, &dataMap ); + pUtlMap->Insert( temp.key, temp.elem ); + } + + pRestore->EndBlock(); + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + UTLMAP *pUtlMap = (UTLMAP *)fieldInfo.pField; + pUtlMap->RemoveAll(); + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + UTLMAP *pUtlMap = (UTLMAP *)fieldInfo.pField; + return ( pUtlMap->Count() == 0 ); + } + +}; + +//------------------------------------- + +template +class CUtlMapDataopsInstantiator +{ +public: + template + static ISaveRestoreOps *GetDataOps(UTLMAP *) + { + static CUtlMapDataOps ops; + return &ops; + } +}; + +//------------------------------------- + +#define SaveUtlMap( pSave, pUtlMap, fieldtype) \ + CUtlMapDataopsInstantiator::GetDataOps( pUtlMap )->Save( pUtlMap, pSave ); + +#define RestoreUtlMap( pRestore, pUtlMap, fieldtype) \ + CUtlMapDataopsInstantiator::GetDataOps( pUtlMap )->Restore( pUtlMap, pRestore ); + +//------------------------------------- + +#define DEFINE_UTLMAP(name,keyType,fieldtype) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, CUtlMapDataopsInstantiator::GetDataOps(&(((classNameTypedef *)0)->name)), NULL } + + +#endif // SAVERESTORE_UTLMAP_H diff --git a/game/shared/saverestore_utlrbtree.h b/game/shared/saverestore_utlrbtree.h new file mode 100644 index 0000000..33bd3ee --- /dev/null +++ b/game/shared/saverestore_utlrbtree.h @@ -0,0 +1,167 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SAVERESTORE_UTLRBTREE_H +#define SAVERESTORE_UTLRBTREE_H + +#include "utlrbtree.h" +#include "isaverestore.h" +#include "saverestore_utlclass.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//------------------------------------- + +template +class CUtlRBTreeDataOps : public CDefSaveRestoreOps +{ +public: + CUtlRBTreeDataOps() + { + UTLCLASS_SAVERESTORE_VALIDATE_TYPE( FIELD_TYPE ); + } + + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + datamap_t *pTreeTypeDatamap = CTypedescDeducer::Deduce( (UTLRBTREE *)NULL ); + typedescription_t dataDesc = + { + (fieldtype_t)FIELD_TYPE, + "elem", + { 0, 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pTreeTypeDatamap, + -1, + }; + + datamap_t dataMap = + { + &dataDesc, + 1, + "urb", + NULL, + false, + false, + 0, +#ifdef _DEBUG + true +#endif + }; + + UTLRBTREE *pUtlRBTree = (UTLRBTREE *)fieldInfo.pField; + + pSave->StartBlock(); + + int nElems = pUtlRBTree->Count(); + pSave->WriteInt( &nElems, 1 ); + + typename UTLRBTREE::IndexType_t i = pUtlRBTree->FirstInorder(); + while ( i != pUtlRBTree->InvalidIndex() ) + { + typename UTLRBTREE::ElemType_t &elem = pUtlRBTree->Element( i ); + + pSave->WriteAll( &elem, &dataMap ); + + i = pUtlRBTree->NextInorder( i ); + } + pSave->EndBlock(); + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + datamap_t *pTreeTypeDatamap = CTypedescDeducer::Deduce( (UTLRBTREE *)NULL ); + typedescription_t dataDesc = + { + (fieldtype_t)FIELD_TYPE, + "elems", + { 0, 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pTreeTypeDatamap, + -1, + }; + + datamap_t dataMap = + { + &dataDesc, + 1, + "uv", + NULL, + false, + false, + 0, +#ifdef _DEBUG + true +#endif + }; + + UTLRBTREE *pUtlRBTree = (UTLRBTREE *)fieldInfo.pField; + + pRestore->StartBlock(); + + int nElems = pRestore->ReadInt(); + typename UTLRBTREE::ElemType_t temp; + + while ( nElems-- ) + { + pRestore->ReadAll( &temp, &dataMap ); + pUtlRBTree->Insert( temp ); + } + + pRestore->EndBlock(); + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + UTLRBTREE *pUtlRBTree = (UTLRBTREE *)fieldInfo.pField; + pUtlRBTree->RemoveAll(); + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + UTLRBTREE *pUtlRBTree = (UTLRBTREE *)fieldInfo.pField; + return ( pUtlRBTree->Count() == 0 ); + } + +}; + +//------------------------------------- + +template +class CUtlRBTreeDataopsInstantiator +{ +public: + template + static ISaveRestoreOps *GetDataOps(UTLRBTREE *) + { + static CUtlRBTreeDataOps ops; + return &ops; + } +}; + +//------------------------------------- + +#define SaveUtlRBTree( pSave, pUtlRBTree, fieldtype) \ + CUtlRBTreeDataopsInstantiator::GetDataOps( pUtlRBTree )->Save( pUtlRBTree, pSave ); + +#define RestoreUtlRBTree( pRestore, pUtlRBTree, fieldtype) \ + CUtlRBTreeDataopsInstantiator::GetDataOps( pUtlRBTree )->Restore( pUtlRBTree, pRestore ); + +//------------------------------------- + +#define DEFINE_UTLRBTREE(name,fieldtype) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, CUtlRBTreeDataopsInstantiator::GetDataOps(&(((classNameTypedef *)0)->name)), NULL } + +#endif // SAVERESTORE_UTLRBTREE_H diff --git a/game/shared/saverestore_utlsymbol.h b/game/shared/saverestore_utlsymbol.h new file mode 100644 index 0000000..176f36e --- /dev/null +++ b/game/shared/saverestore_utlsymbol.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SAVERESTORE_UTLSYMBOL_H +#define SAVERESTORE_UTLSYMBOL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlsymbol.h" + +class CUtlSymbolDataOps : public CDefSaveRestoreOps +{ +public: + CUtlSymbolDataOps( CUtlSymbolTable &masterTable ) : m_symbolTable(masterTable) {} + + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + CUtlSymbol *sym = ((CUtlSymbol *)fieldInfo.pField); + + pSave->WriteString( m_symbolTable.String( *sym ) ); + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + CUtlSymbol *sym = ((CUtlSymbol *)fieldInfo.pField); + + char tmp[1024]; + pRestore->ReadString( tmp, sizeof(tmp), 0 ); + *sym = m_symbolTable.AddString( tmp ); + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + CUtlSymbol *sym = ((CUtlSymbol *)fieldInfo.pField); + *sym = UTL_INVAL_SYMBOL; + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + CUtlSymbol *sym = ((CUtlSymbol *)fieldInfo.pField); + return (*sym).IsValid() ? false : true; + } + +private: + CUtlSymbolTable &m_symbolTable; + +}; + +#endif // SAVERESTORE_UTLSYMBOL_H diff --git a/game/shared/saverestore_utlvector.h b/game/shared/saverestore_utlvector.h new file mode 100644 index 0000000..a6b31ac --- /dev/null +++ b/game/shared/saverestore_utlvector.h @@ -0,0 +1,182 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SAVERESTORE_UTLVECTOR_H +#define SAVERESTORE_UTLVECTOR_H + +#include "utlvector.h" +#include "isaverestore.h" +#include "saverestore_utlclass.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//------------------------------------- + +template +class CUtlVectorDataOps : public CDefSaveRestoreOps +{ +public: + CUtlVectorDataOps() + { + UTLCLASS_SAVERESTORE_VALIDATE_TYPE( FIELD_TYPE ); + } + + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + datamap_t *pArrayTypeDatamap = CTypedescDeducer::Deduce( (UTLVECTOR *)NULL ); + typedescription_t dataDesc = + { + (fieldtype_t)FIELD_TYPE, + "elems", + { 0, 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pArrayTypeDatamap, + -1, + }; + + datamap_t dataMap = + { + &dataDesc, + 1, + "uv", + NULL, + false, + false, + 0, +#ifdef _DEBUG + true +#endif + }; + + UTLVECTOR *pUtlVector = (UTLVECTOR *)fieldInfo.pField; + int nElems = pUtlVector->Count(); + + pSave->WriteInt( &nElems, 1 ); + if ( pArrayTypeDatamap == NULL ) + { + if ( nElems ) + { + dataDesc.fieldSize = nElems; + dataDesc.fieldSizeInBytes = nElems * CDatamapFieldSizeDeducer::FieldSize(); + pSave->WriteFields("elems", &((*pUtlVector)[0]), &dataMap, &dataDesc, 1 ); + } + } + else + { + // @Note (toml 11-21-02): Save load does not support arrays of user defined types (embedded) + dataDesc.fieldSizeInBytes = CDatamapFieldSizeDeducer::FieldSize(); + for ( int i = 0; i < nElems; i++ ) + pSave->WriteAll( &((*pUtlVector)[i]), &dataMap ); + } + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + datamap_t *pArrayTypeDatamap = CTypedescDeducer::Deduce( (UTLVECTOR *)NULL ); + typedescription_t dataDesc = + { + (fieldtype_t)FIELD_TYPE, + "elems", + { 0, 0 }, + 1, + FTYPEDESC_SAVE, + NULL, + NULL, + NULL, + pArrayTypeDatamap, + -1, + }; + + datamap_t dataMap = + { + &dataDesc, + 1, + "uv", + NULL, + false, + false, + 0, +#ifdef _DEBUG + true +#endif + }; + + UTLVECTOR *pUtlVector = (UTLVECTOR *)fieldInfo.pField; + + int nElems = pRestore->ReadInt(); + + pUtlVector->SetCount( nElems ); + if ( pArrayTypeDatamap == NULL ) + { + if ( nElems ) + { + dataDesc.fieldSize = nElems; + dataDesc.fieldSizeInBytes = nElems * CDatamapFieldSizeDeducer::FieldSize(); + pRestore->ReadFields("elems", &((*pUtlVector)[0]), &dataMap, &dataDesc, 1 ); + } + } + else + { + // @Note (toml 11-21-02): Save load does not support arrays of user defined types (embedded) + dataDesc.fieldSizeInBytes = CDatamapFieldSizeDeducer::FieldSize(); + for ( int i = 0; i < nElems; i++ ) + pRestore->ReadAll( &((*pUtlVector)[i]), &dataMap ); + } + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + UTLVECTOR *pUtlVector = (UTLVECTOR *)fieldInfo.pField; + pUtlVector->SetCount( 0 ); + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + UTLVECTOR *pUtlVector = (UTLVECTOR *)fieldInfo.pField; + return ( pUtlVector->Count() == 0 ); + } + +}; + +//------------------------------------- + +template +class CUtlVectorDataopsInstantiator +{ +public: + template + static ISaveRestoreOps *GetDataOps(UTLVECTOR *) + { + static CUtlVectorDataOps ops; + return &ops; + } +}; + +//------------------------------------- + +#define SaveUtlVector( pSave, pUtlVector, fieldtype) \ + CUtlVectorDataopsInstantiator::GetDataOps( pUtlVector )->Save( pUtlVector, pSave ); + +#define RestoreUtlVector( pRestore, pUtlVector, fieldtype) \ + CUtlVectorDataopsInstantiator::GetDataOps( pUtlVector )->Restore( pUtlVector, pRestore ); + +//------------------------------------- + +#define DEFINE_UTLVECTOR(name,fieldtype) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, CUtlVectorDataopsInstantiator::GetDataOps(&(((classNameTypedef *)0)->name)), NULL } + +#define DEFINE_GLOBAL_UTLVECTOR(name,fieldtype) \ +{ FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE|FTYPEDESC_GLOBAL, NULL, CUtlVectorDataopsInstantiator::GetDataOps(&(((classNameTypedef *)0)->name)), NULL } + + +#endif // SAVERESTORE_UTLVECTOR_H diff --git a/game/shared/sceneentity_shared.h b/game/shared/sceneentity_shared.h new file mode 100644 index 0000000..6293e23 --- /dev/null +++ b/game/shared/sceneentity_shared.h @@ -0,0 +1,120 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SCENEENTITY_SHARED_H +#define SCENEENTITY_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) +#define CBaseFlex C_BaseFlex +#define CSceneEntity C_SceneEntity +#endif + +#include "iscenetokenprocessor.h" + +class CBaseFlex; + +class CChoreoEvent; +class CChoreoScene; +class CChoreoActor; +class CSceneEntity; + +//----------------------------------------------------------------------------- +// Purpose: One of a number of currently playing scene events for this actor +//----------------------------------------------------------------------------- +// FIXME: move this, it's only used in in baseflex and baseactor +class CSceneEventInfo +{ +public: + CSceneEventInfo() + : + m_pEvent( 0 ), + m_pScene( 0 ), + m_pActor( 0 ), + m_bStarted( false ), + m_iLayer( -1 ), + m_iPriority( 0 ), + m_nSequence( 0 ), + m_bIsGesture( false ), + m_flWeight( 0.0f ), + m_hTarget(), + m_bIsMoving( false ), + m_bHasArrived( false ), + m_flInitialYaw( 0.0f ), + m_flTargetYaw( 0.0f ), + m_flFacingYaw( 0.0f ), + m_nType( 0 ), + m_flNext( 0.0f ), + m_bClientSide( false ) + { + } + + // The event handle of the current scene event + CChoreoEvent *m_pEvent; + + // Current Scene + CChoreoScene *m_pScene; + + // Current actor + CChoreoActor *m_pActor; + + // Set after the first time the event has been configured ( allows + // bumping markov index only at start of event playback, not every frame ) + bool m_bStarted; + +public: + // EVENT local data... + // FIXME: Evil, make accessors or figure out better place + // FIXME: This won't work, scenes don't save and restore... + int m_iLayer; + int m_iPriority; + int m_nSequence; + bool m_bIsGesture; + float m_flWeight; // used for suppressions of posture while moving + + // movement, faceto targets? + EHANDLE m_hTarget; + bool m_bIsMoving; + bool m_bHasArrived; + float m_flInitialYaw; + float m_flTargetYaw; + float m_flFacingYaw; + + // generic AI events + int m_nType; + float m_flNext; + + // is this event only client side? + bool m_bClientSide; + + void InitWeight( CBaseFlex *pActor ); + float UpdateWeight( CBaseFlex *pActor ); +}; + +//----------------------------------------------------------------------------- +// Purpose: Helper for parsing scene data file +//----------------------------------------------------------------------------- +class CSceneTokenProcessor : public ISceneTokenProcessor +{ +public: + const char *CurrentToken( void ); + bool GetToken( bool crossline ); + bool TokenAvailable( void ); + void Error( PRINTF_FORMAT_STRING const char *fmt, ... ); + void SetBuffer( char *buffer ); +private: + const char *m_pBuffer; + char m_szToken[ 1024 ]; +}; + +extern CSceneTokenProcessor g_TokenProcessor; + +void Scene_Printf( PRINTF_FORMAT_STRING const char *pFormat, ... ); +extern ConVar scene_clientflex; + +#endif // SCENEENTITY_SHARED_H diff --git a/game/shared/sceneimage.h b/game/shared/sceneimage.h new file mode 100644 index 0000000..1d1c608 --- /dev/null +++ b/game/shared/sceneimage.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SCENEIMAGE_H +#define SCENEIMAGE_H +#ifdef _WIN32 +#pragma once +#endif + +class ISceneTokenProcessor; + +class ISceneCompileStatus +{ +public: + virtual void UpdateStatus( char const *pchSceneName, bool bQuiet, int nIndex, int nCount ) = 0; +}; + +class CUtlBuffer; + +class ISceneImage +{ +public: + virtual bool CreateSceneImageFile( CUtlBuffer &targetBuffer, char const *pchModPath, bool bLittleEndian, bool bQuiet, ISceneCompileStatus *Status ) = 0; +}; + +extern ISceneImage *g_pSceneImage; +extern ISceneTokenProcessor *tokenprocessor; + +#endif // SCENEIMAGE_H diff --git a/game/shared/scriptevent.h b/game/shared/scriptevent.h new file mode 100644 index 0000000..c879613 --- /dev/null +++ b/game/shared/scriptevent.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef SCRIPTEVENT_H +#define SCRIPTEVENT_H + +#define SCRIPT_EVENT_DEAD 1000 // character is now dead +#define SCRIPT_EVENT_NOINTERRUPT 1001 // does not allow interrupt +#define SCRIPT_EVENT_CANINTERRUPT 1002 // will allow interrupt +#define SCRIPT_EVENT_FIREEVENT 1003 // Fires OnScriptEventXX output in the script entity, where XX is the event number from the options data. +#define SCRIPT_EVENT_SOUND 1004 // Play named wave file (on CHAN_BODY) +#define SCRIPT_EVENT_SENTENCE 1005 // Play named sentence +#define SCRIPT_EVENT_INAIR 1006 // Leave the character in air at the end of the sequence (don't find the floor) +#define SCRIPT_EVENT_ENDANIMATION 1007 // Set the animation by name after the sequence completes +#define SCRIPT_EVENT_SOUND_VOICE 1008 // Play named wave file (on CHAN_VOICE) +#define SCRIPT_EVENT_SENTENCE_RND1 1009 // Play sentence group 25% of the time +#define SCRIPT_EVENT_NOT_DEAD 1010 // Bring back to life (for life/death sequences) +#define SCRIPT_EVENT_EMPHASIS 1011 // Emphasis point for gestures + +#define SCRIPT_EVENT_BODYGROUPON 1020 // Turn a bodygroup on +#define SCRIPT_EVENT_BODYGROUPOFF 1021 // Turn a bodygroup off +#define SCRIPT_EVENT_BODYGROUPTEMP 1022 // Turn a bodygroup on until this sequence ends + +#define SCRIPT_EVENT_FIRE_INPUT 1100 // Fires named input on the event handler + +#endif //SCRIPTEVENT_H diff --git a/game/shared/sdk/sdk_basegrenade_projectile.h b/game/shared/sdk/sdk_basegrenade_projectile.h new file mode 100644 index 0000000..6838f2b --- /dev/null +++ b/game/shared/sdk/sdk_basegrenade_projectile.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASECSGRENADE_PROJECTILE_H +#define BASECSGRENADE_PROJECTILE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "basegrenade_shared.h" + + +#ifdef CLIENT_DLL + #define CBaseGrenadeProjectile C_BaseGrenadeProjectile +#endif + + +class CBaseGrenadeProjectile : public CBaseGrenade +{ +public: + DECLARE_CLASS( CBaseGrenadeProjectile, CBaseGrenade ); + DECLARE_NETWORKCLASS(); + + virtual void Spawn(); + + +public: + + // This gets sent to the client and placed in the client's interpolation history + // so the projectile starts out moving right off the bat. + CNetworkVector( m_vInitialVelocity ); + + +#ifdef CLIENT_DLL + CBaseGrenadeProjectile() {} + CBaseGrenadeProjectile( const CBaseGrenadeProjectile& ) {} + virtual int DrawModel( int flags ); + virtual void PostDataUpdate( DataUpdateType_t type ); + + float m_flSpawnTime; +#else + DECLARE_DATADESC(); + + //Constants for all CS Grenades + static inline float GetGrenadeGravity() { return 0.4f; } + static inline const float GetGrenadeFriction() { return 0.2f; } + static inline const float GetGrenadeElasticity() { return 0.45f; } + + //Think function to emit danger sounds for the AI + void DangerSoundThink( void ); + + virtual float GetShakeAmplitude( void ) { return 0.0f; } + + // Specify what velocity we want the grenade to have on the client immediately. + // Without this, the entity wouldn't have an interpolation history initially, so it would + // sit still until it had gotten a few updates from the server. + void SetupInitialTransmittedGrenadeVelocity( const Vector &velocity ); + +protected: + + //Set the time to detonate ( now + timer ) + void SetDetonateTimerLength( float timer ); + +private: + + //Custom collision to allow for constant elasticity on hit surfaces + virtual void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ); + + float m_flDetonateTime; +#endif +}; + + +#endif // BASECSGRENADE_PROJECTILE_H diff --git a/game/shared/sdk/sdk_fx_shared.h b/game/shared/sdk/sdk_fx_shared.h new file mode 100644 index 0000000..2437909 --- /dev/null +++ b/game/shared/sdk/sdk_fx_shared.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_CS_SHARED_H +#define FX_CS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +// This runs on both the client and the server. +// On the server, it only does the damage calculations. +// On the client, it does all the effects. +void FX_FireBullets( + int iPlayer, + const Vector &vOrigin, + const QAngle &vAngles, + int iWeaponID, + int iMode, + int iSeed, + float flSpread + ); + + +#endif // FX_CS_SHARED_H diff --git a/game/shared/sdk/sdk_gamerules.h b/game/shared/sdk/sdk_gamerules.h new file mode 100644 index 0000000..df1b79b --- /dev/null +++ b/game/shared/sdk/sdk_gamerules.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The TF Game rules object +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDK_GAMERULES_H +#define SDK_GAMERULES_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "teamplay_gamerules.h" +#include "convar.h" +#include "gamevars_shared.h" + +#ifdef CLIENT_DLL + #include "c_baseplayer.h" +#else + #include "player.h" +#endif + + +#ifdef CLIENT_DLL + #define CSDKGameRules C_SDKGameRules + #define CSDKGameRulesProxy C_SDKGameRulesProxy +#endif + + +class CSDKGameRulesProxy : public CGameRulesProxy +{ +public: + DECLARE_CLASS( CSDKGameRulesProxy, CGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + + +class CSDKGameRules : public CTeamplayRules +{ +public: + DECLARE_CLASS( CSDKGameRules, CTeamplayRules ); + + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual bool IsTeamplay( void ) { return false; } + +#ifdef CLIENT_DLL + + DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars. + +#else + + DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars. + + CSDKGameRules(); + virtual ~CSDKGameRules(); + + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ); + virtual void Think(); + + virtual const char *GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ); + +private: + + void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld ); + + +#endif +}; + +//----------------------------------------------------------------------------- +// Gets us at the team fortress game rules +//----------------------------------------------------------------------------- + +inline CSDKGameRules* SDKGameRules() +{ + return static_cast(g_pGameRules); +} + + +#endif // SDK_GAMERULES_H diff --git a/game/shared/sdk/sdk_player_shared.h b/game/shared/sdk/sdk_player_shared.h new file mode 100644 index 0000000..f745fc8 --- /dev/null +++ b/game/shared/sdk/sdk_player_shared.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared Player Variables / Functions and variables that may or may not be networked +// +//===========================================================================================// + +#ifndef SDK_PLAYER_SHARED_H +#define SDK_PLAYER_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkvar.h" +#include "weapon_sdkbase.h" + +#ifdef CLIENT_DLL +class C_SDKPlayer; +#else +class CSDKPlayer; +#endif + +class CSDKPlayerShared +{ +public: + +#ifdef CLIENT_DLL + friend class C_SDKPlayer; + typedef C_SDKPlayer OuterClass; + DECLARE_PREDICTABLE(); +#else + friend class CSDKPlayer; + typedef CSDKPlayer OuterClass; +#endif + + DECLARE_EMBEDDED_NETWORKVAR() + DECLARE_CLASS_NOBASE( CSDKPlayerShared ); + + CSDKPlayerShared(); + ~CSDKPlayerShared(); + +#if defined ( SDK_USE_STAMINA ) || defined ( SDK_USE_SPRINTING ) + void SetStamina( float stamina ); + float GetStamina( void ) { return m_flStamina; } +#endif // SDK_USE_STAMINA || SDK_USE_SPRINTING + + void Init( OuterClass *pOuter ); + + bool IsSniperZoomed( void ) const; + bool IsDucking( void ) const; + +#if defined ( SDK_USE_PLAYERCLASSES ) + void SetDesiredPlayerClass( int playerclass ); + int DesiredPlayerClass( void ); + + void SetPlayerClass( int playerclass ); + int PlayerClass( void ); +#endif + + CWeaponSDKBase* GetActiveSDKWeapon() const; + +#if defined ( SDK_USE_PRONE ) + void StartGoingProne( void ); + void StandUpFromProne( void ); + bool IsProne() const; + bool IsGettingUpFromProne() const; + bool IsGoingProne() const; + void SetProne( bool bProne, bool bNoAnimation = false ); + bool CanChangePosition( void ); +#endif + + bool IsJumping( void ) { return m_bJumping; } + void SetJumping( bool bJumping ); + + void ForceUnzoom( void ); + +#ifdef SDK_USE_SPRINTING + bool IsSprinting( void ) { return m_bIsSprinting; } + + void SetSprinting( bool bSprinting ); + void StartSprinting( void ); + void StopSprinting( void ); + + void ResetSprintPenalty( void ); +#endif + + void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + +private: + +#if defined ( SDK_USE_PRONE ) + CNetworkVar( bool, m_bProne ); +#endif + +#if defined ( SDK_USE_PLAYERCLASSES ) + CNetworkVar( int, m_iPlayerClass ); + CNetworkVar( int, m_iDesiredPlayerClass ); +#endif + + +#if defined ( SDK_USE_SPRINTING ) + CNetworkVar( bool, m_bIsSprinting ); + bool m_bGaveSprintPenalty; +#endif + +#if defined ( SDK_USE_STAMINA ) || defined ( SDK_USE_SPRINTING ) + CNetworkVar( float, m_flStamina ); +#endif // SDK_USE_STAMINA || SDK_USE_SPRINTING + +public: + +#ifdef SDK_USE_PRONE + float m_flNextProneCheck; // Prevent it switching their prone state constantly. + + CNetworkVar( float, m_flUnProneTime ); + CNetworkVar( float, m_flGoProneTime ); + CNetworkVar( bool, m_bForceProneChange ); +#endif + + bool m_bJumping; + + float m_flLastViewAnimationTime; + + //Tony; player speeds; at spawn server and client update both of these based on class (if any) + float m_flRunSpeed; + float m_flSprintSpeed; + float m_flProneSpeed; + +private: + + OuterClass *m_pOuter; +}; + + + + +#endif //SDK_PLAYER_SHARED_H \ No newline at end of file diff --git a/game/shared/sdk/sdk_playeranimstate.h b/game/shared/sdk/sdk_playeranimstate.h new file mode 100644 index 0000000..46ca04c --- /dev/null +++ b/game/shared/sdk/sdk_playeranimstate.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_PLAYERANIMSTATE_H +#define SDK_PLAYERANIMSTATE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "convar.h" +#include "iplayeranimstate.h" +#include "base_playeranimstate.h" + + +#ifdef CLIENT_DLL + class C_BaseAnimatingOverlay; + class C_WeaponSDKBase; + #define CBaseAnimatingOverlay C_BaseAnimatingOverlay + #define CWeaponSDKBase C_WeaponSDKBase + #define CSDKPlayer C_SDKPlayer +#else + class CBaseAnimatingOverlay; + class CWeaponSDKBase; + class CSDKPlayer; +#endif + + +// When moving this fast, he plays run anim. +#define ARBITRARY_RUN_SPEED 175.0f + + +enum PlayerAnimEvent_t +{ + PLAYERANIMEVENT_FIRE_GUN_PRIMARY=0, + PLAYERANIMEVENT_FIRE_GUN_SECONDARY, + PLAYERANIMEVENT_THROW_GRENADE, + PLAYERANIMEVENT_JUMP, + PLAYERANIMEVENT_RELOAD, + + PLAYERANIMEVENT_COUNT +}; + + +class ISDKPlayerAnimState : virtual public IPlayerAnimState +{ +public: + // This is called by both the client and the server in the same way to trigger events for + // players firing, jumping, throwing grenades, etc. + virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ) = 0; + + // Returns true if we're playing the grenade prime or throw animation. + virtual bool IsThrowingGrenade() = 0; +}; + + +// This abstracts the differences between SDK players and hostages. +class ISDKPlayerAnimStateHelpers +{ +public: + virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon() = 0; + virtual bool SDKAnim_CanMove() = 0; +}; + + +ISDKPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ISDKPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences ); + +// If this is set, then the game code needs to make sure to send player animation events +// to the local player if he's the one being watched. +extern ConVar cl_showanimstate; + + +#endif // SDK_PLAYERANIMSTATE_H diff --git a/game/shared/sdk/sdk_playerclass_info_parse.h b/game/shared/sdk/sdk_playerclass_info_parse.h new file mode 100644 index 0000000..2e15f34 --- /dev/null +++ b/game/shared/sdk/sdk_playerclass_info_parse.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_PLAYERCLASS_INFO_PARSE_H +#define SDK_PLAYERCLASS_INFO_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "playerclass_info_parse.h" +#include "networkvar.h" + +#if defined ( SDK_USE_PLAYERCLASSES ) +//-------------------------------------------------------------------------------------------------------- +class CSDKPlayerClassInfo : public FilePlayerClassInfo_t +{ +public: + DECLARE_CLASS_GAMEROOT( CSDKPlayerClassInfo, FilePlayerClassInfo_t ); + + CSDKPlayerClassInfo(); + + virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName ); + + int m_iTeam; //which team. 2 == team 1, 3 == team 2 + + int m_iPrimaryWeapon; + int m_iSecondaryWeapon; + int m_iMeleeWeapon; + + int m_iNumGrensType1; + int m_iGrenType1; + + int m_iNumGrensType2; + int m_iGrenType2; + + char m_szLimitCvar[64]; //which cvar controls the class limit for this class + + char m_szClassImage[SDK_PLAYERCLASS_IMAGE_LENGTH]; + char m_szClassImageBG[SDK_PLAYERCLASS_IMAGE_LENGTH]; + + float m_flRunSpeed; + float m_flSprintSpeed; + float m_flProneSpeed; + + int m_iArmor; +}; +#endif // SDK_USE_PLAYERCLASSES + +#endif // DOD_PLAYERCLASS_INFO_PARSE_H diff --git a/game/shared/sdk/sdk_shareddefs.h b/game/shared/sdk/sdk_shareddefs.h new file mode 100644 index 0000000..ef3acfe --- /dev/null +++ b/game/shared/sdk/sdk_shareddefs.h @@ -0,0 +1,208 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_SHAREDDEFS_H +#define SDK_SHAREDDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +//========================= +// GAMEPLAY RELATED OPTIONS +//========================= +// NOTES: The Wizard automatically replaces these strings! If you extract the source as is, you will have to add the defines manually! +// +// Will your mod be team based? +// define SDK_USE_TEAMS +#define SDK_USE_TEAMS + +// +// Do you use player classes? +// define SDK_USE_PLAYERCLASSES +#define SDK_USE_PLAYERCLASSES + +//================================ +// PLAYER MOVEMENT RELATED OPTIONS +//================================ + +// +// Do your players have stamina? - this is a pre-requisite for sprinting, if you define sprinting, and don't uncomment this, it will be included anyway. +// define SDK_USE_STAMINA +#define SDK_USE_STAMINA + +// +// Are your players able to sprint? +// define SDK_USE_SPRINTING +#define SDK_USE_SPRINTING + +//Tony; stamina is a pre-requisite to sprinting, if you don't declare stamina but you do declare sprinting +//stamina needs to be included. +#if defined ( SDK_USE_SPRINTING ) && !defined( SDK_USE_STAMINA ) +#define SDK_USE_STAMINA +#endif +// +// Can your players go prone? +// define SDK_USE_PRONE +#define SDK_USE_PRONE + +//===================== +// EXTRA WEAPON OPTIONS +//===================== + +// +// If you're allowing sprinting, do you want to be able to shoot while sprinting? +// define SDK_SHOOT_WHILE_SPRINTING +#define SDK_SHOOT_WHILE_SPRINTING + +// +// Do you want your players to be able to shoot while climing ladders? +// define SDK_SHOOT_ON_LADDERS +#define SDK_SHOOT_ON_LADDERS + +// +// Do you want your players to be able to shoot while jumping? +// define SDK_SHOOT_WHILE_JUMPING +#define SDK_SHOOT_WHILE_JUMPING + + + +#define SDK_GAME_DESCRIPTION "SDK Template mod v1" + +//================================================================================ +// Most elements below here are specific to the options above. +//================================================================================ + +#if defined ( SDK_USE_TEAMS ) + +enum sdkteams_e + { + SDK_TEAM_BLUE = LAST_SHARED_TEAM+1, + SDK_TEAM_RED, + }; + +#endif // SDK_USE_TEAMS + +#if defined ( SDK_USE_PRONE ) + + #define TIME_TO_PRONE 1.2f + #define VEC_PRONE_HULL_MIN SDKGameRules()->GetSDKViewVectors()->m_vProneHullMin + #define VEC_PRONE_HULL_MAX SDKGameRules()->GetSDKViewVectors()->m_vProneHullMax + #define VEC_PRONE_VIEW SDKGameRules()->GetSDKViewVectors()->m_vProneView + +#endif // SDK_USE_PRONE + +#if defined ( SDK_USE_SPRINTING ) + + #define INITIAL_SPRINT_STAMINA_PENALTY 15 + #define LOW_STAMINA_THRESHOLD 35 + +#endif // SDK_USE_SPRINTING + +#if defined ( SDK_USE_PLAYERCLASSES ) + #define SDK_NUM_PLAYERCLASSES 3 //Tony; our template sample has 3 player classes. + #define SDK_PLAYERCLASS_IMAGE_LENGTH 64 + + #define PLAYERCLASS_RANDOM -2 + #define PLAYERCLASS_UNDEFINED -1 + + #if defined ( SDK_USE_TEAMS ) + //Tony; using teams with classes, so make sure the team class panel names are defined. + #define PANEL_CLASS_BLUE "class_blue" + #define PANEL_CLASS_RED "class_red" + + extern const char *pszTeamBlueClasses[]; + extern const char *pszTeamRedClasses[]; + #else + #define PANEL_CLASS_NOTEAMS "class_noteams" + extern const char *pszPlayerClasses[]; + #endif // SDK_USE_TEAMS + +#endif // SDK_USE_PLAYERCLASSES + +#define SDK_PLAYER_MODEL "models/player/american_rifleman.mdl" + +//Tony; We need to precache all possible player models that we're going to use +extern const char *pszPossiblePlayerModels[]; + +extern const char *pszTeamNames[]; + +//Tony; these defines handle the default speeds for all of these - all are listed regardless of which option is enabled. +#define SDK_DEFAULT_PLAYER_RUNSPEED 220 +#define SDK_DEFAULT_PLAYER_SPRINTSPEED 330 +#define SDK_DEFAULT_PLAYER_PRONESPEED 50 + +//-------------------------------------------------------------------------------------------------------- +// +// Weapon IDs for all SDK Game weapons +// +typedef enum +{ + WEAPON_NONE = 0, + + SDK_WEAPON_NONE = WEAPON_NONE, + SDK_WEAPON_MP5, + SDK_WEAPON_SHOTGUN, + SDK_WEAPON_GRENADE, + SDK_WEAPON_PISTOL, + SDK_WEAPON_CROWBAR, + + + WEAPON_MAX, // number of weapons weapon index +} SDKWeaponID; + +typedef enum +{ + FM_AUTOMATIC = 0, + FM_SEMIAUTOMATIC, + FM_BURST, + +} SDK_Weapon_Firemodes; + +const char *WeaponIDToAlias( int id ); +int AliasToWeaponID( const char *alias ); + + +// The various states the player can be in during the join game process. +enum SDKPlayerState +{ + // Happily running around in the game. + // You can't move though if CSGameRules()->IsFreezePeriod() returns true. + // This state can jump to a bunch of other states like STATE_PICKINGCLASS or STATE_DEATH_ANIM. + STATE_ACTIVE=0, + + // This is the state you're in when you first enter the server. + // It's switching between intro cameras every few seconds, and there's a level info + // screen up. + STATE_WELCOME, // Show the level intro screen. + + // During these states, you can either be a new player waiting to join, or + // you can be a live player in the game who wants to change teams. + // Either way, you can't move while choosing team or class (or while any menu is up). +#if defined ( SDK_USE_TEAMS ) + STATE_PICKINGTEAM, // Choosing team. +#endif +#if defined ( SDK_USE_PLAYERCLASSES ) + STATE_PICKINGCLASS, // Choosing class. +#endif + + STATE_DEATH_ANIM, // Playing death anim, waiting for that to finish. + STATE_OBSERVER_MODE, // Noclipping around, watching players, etc. + + NUM_PLAYER_STATES +}; +#define SDK_PLAYER_DEATH_TIME 5.0f //Minimum Time before respawning + +// Special Damage types +enum +{ + SDK_DMG_CUSTOM_NONE = 0, + SDK_DMG_CUSTOM_SUICIDE, +}; + +// Player avoidance +#define PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f) + +#endif // SDK_SHAREDDEFS_H diff --git a/game/shared/sdk/sdk_weapon_melee.h b/game/shared/sdk/sdk_weapon_melee.h new file mode 100644 index 0000000..be9d75d --- /dev/null +++ b/game/shared/sdk/sdk_weapon_melee.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base code for any melee based weapon +// +//=====================================================================================// + +#ifndef SDK_WEAPON_MELEE_H +#define SDK_WEAPON_MELEE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#if defined( CLIENT_DLL ) +#define CWeaponSDKMelee C_WeaponSDKMelee +#endif + +//========================================================= +// CBaseHLBludgeonWeapon +//========================================================= +class CWeaponSDKMelee : public CWeaponSDKBase +{ + DECLARE_CLASS( CWeaponSDKMelee, CWeaponSDKBase ); +public: + CWeaponSDKMelee(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + virtual void Spawn( void ); + virtual void Precache( void ); + + //Attack functions + virtual void PrimaryAttack( void ); + virtual void SecondaryAttack( void ); + + virtual void ItemPostFrame( void ); + + //Functions to select animation sequences + virtual Activity GetPrimaryAttackActivity( void ) { return ACT_VM_HITCENTER; } + virtual Activity GetSecondaryAttackActivity( void ) { return ACT_VM_HITCENTER2; } + + virtual float GetRange( void ) { return 32.0f; } + virtual float GetDamageForActivity( Activity hitActivity ) { return GetSDKWpnData().m_iDamage; } + + CWeaponSDKMelee( const CWeaponSDKMelee & ); + +protected: + virtual void ImpactEffect( trace_t &trace ); + +private: + bool ImpactWater( const Vector &start, const Vector &end ); + void Swing( int bIsSecondary ); + void Hit( trace_t &traceHit, Activity nHitActivity ); + Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CSDKPlayer *pOwner ); +}; + + +#endif // SDK_WEAPON_MELEE_H \ No newline at end of file diff --git a/game/shared/sdk/sdk_weapon_parse.h b/game/shared/sdk/sdk_weapon_parse.h new file mode 100644 index 0000000..dfa0992 --- /dev/null +++ b/game/shared/sdk/sdk_weapon_parse.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_WEAPON_PARSE_H +#define SDK_WEAPON_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "weapon_parse.h" +#include "networkvar.h" + + +//-------------------------------------------------------------------------------------------------------- +class CSDKWeaponInfo : public FileWeaponInfo_t +{ +public: + DECLARE_CLASS_GAMEROOT( CSDKWeaponInfo, FileWeaponInfo_t ); + + CSDKWeaponInfo(); + + virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName ); + + char m_szAnimExtension[16]; // string used to generate player animations with this weapon + + // Parameters for FX_FireBullets: + int m_iDamage; + int m_iBullets; + float m_flCycleTime; +}; + + +#endif // SDK_WEAPON_PARSE_H diff --git a/game/shared/sdk/weapon_basesdkgrenade.h b/game/shared/sdk/weapon_basesdkgrenade.h new file mode 100644 index 0000000..3eaa26c --- /dev/null +++ b/game/shared/sdk/weapon_basesdkgrenade.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_BASESDKGRENADE_H +#define WEAPON_BASESDKGRENADE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "weapon_sdkbase.h" + + +#ifdef CLIENT_DLL + + #define CBaseSDKGrenade C_BaseSDKGrenade + +#endif + + +class CBaseSDKGrenade : public CWeaponSDKBase +{ +public: + DECLARE_CLASS( CBaseSDKGrenade, CWeaponSDKBase ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CBaseSDKGrenade(); + + virtual void Precache(); + + bool Deploy(); + bool Holster( CBaseCombatWeapon *pSwitchingTo ); + + void PrimaryAttack(); + void SecondaryAttack(); + + bool Reload(); + + virtual void ItemPostFrame(); + + void DecrementAmmo( CBaseCombatCharacter *pOwner ); + virtual void StartGrenadeThrow(); + virtual void ThrowGrenade(); + virtual void DropGrenade(); + + bool IsPinPulled() const; + +#ifndef CLIENT_DLL + DECLARE_DATADESC(); + + virtual bool AllowsAutoSwitchFrom( void ) const; + + int CapabilitiesGet(); + + // Each derived grenade class implements this. + virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer ); +#endif + +protected: + CNetworkVar( bool, m_bRedraw ); // Draw the weapon again after throwing a grenade + CNetworkVar( bool, m_bPinPulled ); // Set to true when the pin has been pulled but the grenade hasn't been thrown yet. + CNetworkVar( float, m_fThrowTime ); // the time at which the grenade will be thrown. If this value is 0 then the time hasn't been set yet. + +private: + CBaseSDKGrenade( const CBaseSDKGrenade & ) {} +}; + + +inline bool CBaseSDKGrenade::IsPinPulled() const +{ + return m_bPinPulled; +} + + +#endif // WEAPON_BASESDKGRENADE_H diff --git a/game/shared/sdk/weapon_grenade.h b/game/shared/sdk/weapon_grenade.h new file mode 100644 index 0000000..9d8434b --- /dev/null +++ b/game/shared/sdk/weapon_grenade.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_GRENADE_H +#define WEAPON_GRENADE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "weapon_basesdkgrenade.h" + + +#ifdef CLIENT_DLL + + #define CSDKGrenade C_SDKGrenade + +#endif + +//----------------------------------------------------------------------------- +// Fragmentation grenades +//----------------------------------------------------------------------------- +class CSDKGrenade : public CBaseSDKGrenade +{ +public: + DECLARE_CLASS( CSDKGrenade, CBaseSDKGrenade ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CSDKGrenade() {} + + virtual SDKWeaponID GetWeaponID( void ) const { return WEAPON_GRENADE; } + +#ifdef CLIENT_DLL + +#else + DECLARE_DATADESC(); + + virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer ); + +#endif + + CSDKGrenade( const CSDKGrenade & ) {} +}; + + +#endif // WEAPON_GRENADE_H diff --git a/game/shared/sdk/weapon_sdkbase.h b/game/shared/sdk/weapon_sdkbase.h new file mode 100644 index 0000000..b91ff88 --- /dev/null +++ b/game/shared/sdk/weapon_sdkbase.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_SDKBASE_H +#define WEAPON_SDKBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "sdk_playeranimstate.h" +#include "sdk_weapon_parse.h" + +#if defined( CLIENT_DLL ) + #define CWeaponSDKBase C_WeaponSDKBase +#endif + +class CSDKPlayer; + +// These are the names of the ammo types that the weapon script files reference. +#define AMMO_BULLETS "AMMO_BULLETS" +#define AMMO_ROCKETS "AMMO_ROCKETS" +#define AMMO_GRENADE "AMMO_GRENADE" + +//-------------------------------------------------------------------------------------------------------- +// +// Weapon IDs for all SDK Game weapons +// +typedef enum +{ + WEAPON_NONE = 0, + + WEAPON_MP5, + WEAPON_SHOTGUN, + WEAPON_GRENADE, + + WEAPON_MAX, // number of weapons weapon index +} SDKWeaponID; + +typedef enum +{ + Primary_Mode = 0, + Secondary_Mode, +} SDKWeaponMode; + +const char *WeaponIDToAlias( int id ); + +class CWeaponSDKBase : public CBaseCombatWeapon +{ +public: + DECLARE_CLASS( CWeaponSDKBase, CBaseCombatWeapon ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponSDKBase(); + + #ifdef GAME_DLL + DECLARE_DATADESC(); + #endif + + // All predicted weapons need to implement and return true + virtual bool IsPredicted() const { return true; } + virtual SDKWeaponID GetWeaponID( void ) const { return WEAPON_NONE; } + + // Get SDK weapon specific weapon data. + CSDKWeaponInfo const &GetSDKWpnData() const; + + // Get a pointer to the player that owns this weapon + CSDKPlayer* GetPlayerOwner() const; + + // override to play custom empty sounds + virtual bool PlayEmptySound(); + +#ifdef GAME_DLL + virtual void SendReloadEvents(); +#endif + +private: + CWeaponSDKBase( const CWeaponSDKBase & ); +}; + + +#endif // WEAPON_SDKBASE_H diff --git a/game/shared/sequence_Transitioner.h b/game/shared/sequence_Transitioner.h new file mode 100644 index 0000000..8ad23ad --- /dev/null +++ b/game/shared/sequence_Transitioner.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SEQUENCE_TRANSITIONER_H +#define SEQUENCE_TRANSITIONER_H +#ifdef _WIN32 +#pragma once +#endif + + +// ------------------------------------------------------------------------------------------------ // +// CSequenceTransitioner declaration. +// ------------------------------------------------------------------------------------------------ // +class CSequenceTransitioner +{ +public: + void CheckForSequenceChange( + // Describe the current animation state with these parameters. + CStudioHdr *hdr, + int nCurSequence, + + // Even if the sequence hasn't changed, you can force it to interpolate from the previous + // spot in the same sequence to the current spot in the same sequence by setting this to true. + bool bForceNewSequence, + + // Follows EF_NOINTERP. + bool bInterpolate + ); + + void UpdateCurrent( + // Describe the current animation state with these parameters. + CStudioHdr *hdr, + int nCurSequence, + float flCurCycle, + float flCurPlaybackRate, + float flCurTime + ); + + void RemoveAll( void ) { m_animationQueue.RemoveAll(); }; + +public: + CUtlVector< CAnimationLayer > m_animationQueue; +}; + +#endif // SEQUENCE_TRANSITIONER_H diff --git a/game/shared/sharedInterface.h b/game/shared/sharedInterface.h new file mode 100644 index 0000000..4f66837 --- /dev/null +++ b/game/shared/sharedInterface.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Exposes client-server neutral interfaces implemented in both places +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SHAREDINTERFACE_H +#define SHAREDINTERFACE_H + +#ifdef POSIX +#define random random_valve// stdlib.h defined random() and our class defn conflicts so under POSIX rename it using the preprocessor +#endif + +class IFileSystem; +class IUniformRandomStream; +class CGaussianRandomStream; +class IEngineSound; +class IMapData; + +extern IFileSystem *filesystem; +#if defined(_STATIC_LINKED) && defined(_SUBSYSTEM) && (defined(CLIENT_DLL) || defined(GAME_DLL)) +namespace _SUBSYSTEM +{ +extern IUniformRandomStream *random; +} +#else +extern IUniformRandomStream *random; +#endif +extern CGaussianRandomStream *randomgaussian; +extern IEngineSound *enginesound; +extern IMapData *g_pMapData; // TODO: current implementations of the + // interface are in TF2, should probably move + // to TF2/HL2 neutral territory + +#endif // SHAREDINTERFACE_H + diff --git a/game/shared/shared_classnames.h b/game/shared/shared_classnames.h new file mode 100644 index 0000000..48749cf --- /dev/null +++ b/game/shared/shared_classnames.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SHARED_CLASSNAMES_H +#define SHARED_CLASSNAMES_H +#ifdef _WIN32 +#pragma once +#endif + +// Hacky macros to allow shared code to work without even worse macro-izing +#if defined( CLIENT_DLL ) + +#define CBaseEntity C_BaseEntity +#define CBaseCombatCharacter C_BaseCombatCharacter +#define CBaseAnimating C_BaseAnimating +#define CBasePlayer C_BasePlayer + +#endif + + +#endif // SHARED_CLASSNAMES_H diff --git a/game/shared/shareddefs.h b/game/shared/shareddefs.h new file mode 100644 index 0000000..5236693 --- /dev/null +++ b/game/shared/shareddefs.h @@ -0,0 +1,954 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Definitions that are shared by the game DLL and the client DLL. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SHAREDDEFS_H +#define SHAREDDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +#define TICK_INTERVAL (gpGlobals->interval_per_tick) + + +#define TIME_TO_TICKS( dt ) ( (int)( 0.5f + (float)(dt) / TICK_INTERVAL ) ) +#define TICKS_TO_TIME( t ) ( TICK_INTERVAL *( t ) ) +#define ROUND_TO_TICKS( t ) ( TICK_INTERVAL * TIME_TO_TICKS( t ) ) +#define TICK_NEVER_THINK (-1) + +#if defined( TF_DLL ) +#define ANIMATION_CYCLE_BITS 10 +#else +#define ANIMATION_CYCLE_BITS 15 +#endif +#define ANIMATION_CYCLE_MINFRAC (1.0f / (1<GetViewVectors()->m_vView +#define VEC_HULL_MIN g_pGameRules->GetViewVectors()->m_vHullMin +#define VEC_HULL_MAX g_pGameRules->GetViewVectors()->m_vHullMax + +#define VEC_DUCK_HULL_MIN g_pGameRules->GetViewVectors()->m_vDuckHullMin +#define VEC_DUCK_HULL_MAX g_pGameRules->GetViewVectors()->m_vDuckHullMax +#define VEC_DUCK_VIEW g_pGameRules->GetViewVectors()->m_vDuckView + +#define VEC_OBS_HULL_MIN g_pGameRules->GetViewVectors()->m_vObsHullMin +#define VEC_OBS_HULL_MAX g_pGameRules->GetViewVectors()->m_vObsHullMax + +#define VEC_DEAD_VIEWHEIGHT g_pGameRules->GetViewVectors()->m_vDeadViewHeight + +// If the player (enemy bots) are scaled, adjust the hull +#define VEC_VIEW_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vView * player->GetModelScale() ) +#define VEC_HULL_MIN_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vHullMin * player->GetModelScale() ) +#define VEC_HULL_MAX_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vHullMax * player->GetModelScale() ) + +#define VEC_DUCK_HULL_MIN_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vDuckHullMin * player->GetModelScale() ) +#define VEC_DUCK_HULL_MAX_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vDuckHullMax * player->GetModelScale() ) +#define VEC_DUCK_VIEW_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vDuckView * player->GetModelScale() ) + +#define VEC_OBS_HULL_MIN_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vObsHullMin * player->GetModelScale() ) +#define VEC_OBS_HULL_MAX_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vObsHullMax * player->GetModelScale() ) + +#define VEC_DEAD_VIEWHEIGHT_SCALED( player ) ( g_pGameRules->GetViewVectors()->m_vDeadViewHeight * player->GetModelScale() ) + +#define WATERJUMP_HEIGHT 8 + +#define MAX_CLIMB_SPEED 200 + +#if defined(TF_DLL) || defined(TF_CLIENT_DLL) + #define TIME_TO_DUCK 0.2 + #define TIME_TO_DUCK_MS 200.0f +#else + #define TIME_TO_DUCK 0.4 + #define TIME_TO_DUCK_MS 400.0f +#endif +#define TIME_TO_UNDUCK 0.2 +#define TIME_TO_UNDUCK_MS 200.0f + +#define MAX_WEAPON_SLOTS 6 // hud item selection slots +#define MAX_WEAPON_POSITIONS 20 // max number of items within a slot +#define MAX_ITEM_TYPES 6 // hud item selection slots +#define MAX_WEAPONS 48 // Max number of weapons available + +#define MAX_ITEMS 5 // hard coded item types + +#define WEAPON_NOCLIP -1 // clip sizes set to this tell the weapon it doesn't use a clip + +#define MAX_AMMO_TYPES 32 // ??? +#define MAX_AMMO_SLOTS 32 // not really slots + +#define HUD_PRINTNOTIFY 1 +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 + +// Vote creation or processing failure codes +typedef enum +{ + VOTE_FAILED_GENERIC = 0, + VOTE_FAILED_TRANSITIONING_PLAYERS, + VOTE_FAILED_RATE_EXCEEDED, + VOTE_FAILED_YES_MUST_EXCEED_NO, + VOTE_FAILED_QUORUM_FAILURE, + VOTE_FAILED_ISSUE_DISABLED, + VOTE_FAILED_MAP_NOT_FOUND, + VOTE_FAILED_MAP_NAME_REQUIRED, + VOTE_FAILED_ON_COOLDOWN, + VOTE_FAILED_TEAM_CANT_CALL, + VOTE_FAILED_WAITINGFORPLAYERS, + VOTE_FAILED_PLAYERNOTFOUND, + VOTE_FAILED_CANNOT_KICK_ADMIN, + VOTE_FAILED_SCRAMBLE_IN_PROGRESS, + VOTE_FAILED_SPECTATOR, + VOTE_FAILED_NEXTLEVEL_SET, + VOTE_FAILED_MAP_NOT_VALID, + VOTE_FAILED_CANNOT_KICK_FOR_TIME, + VOTE_FAILED_CANNOT_KICK_DURING_ROUND, + VOTE_FAILED_VOTE_IN_PROGRESS, + VOTE_FAILED_KICK_LIMIT_REACHED, + + // TF-specific? + VOTE_FAILED_MODIFICATION_ALREADY_ACTIVE, +} vote_create_failed_t; + +enum +{ +#ifdef STAGING_ONLY + SERVER_MODIFICATION_ITEM_DURATION_IN_MINUTES = 2 +#else + SERVER_MODIFICATION_ITEM_DURATION_IN_MINUTES = 120 +#endif +}; + +#define MAX_VOTE_DETAILS_LENGTH 64 +#define INVALID_ISSUE -1 +#define MAX_VOTE_OPTIONS 5 +#define DEDICATED_SERVER 99 + +enum CastVote +{ + VOTE_OPTION1, // Use this for Yes + VOTE_OPTION2, // Use this for No + VOTE_OPTION3, + VOTE_OPTION4, + VOTE_OPTION5, + VOTE_UNCAST +}; + +//=================================================================================================================== +// Close caption flags +#define CLOSE_CAPTION_WARNIFMISSING ( 1<<0 ) +#define CLOSE_CAPTION_FROMPLAYER ( 1<<1 ) +#define CLOSE_CAPTION_GENDER_MALE ( 1<<2 ) +#define CLOSE_CAPTION_GENDER_FEMALE ( 1<<3 ) + +//=================================================================================================================== +// Hud Element hiding flags +#define HIDEHUD_WEAPONSELECTION ( 1<<0 ) // Hide ammo count & weapon selection +#define HIDEHUD_FLASHLIGHT ( 1<<1 ) +#define HIDEHUD_ALL ( 1<<2 ) +#define HIDEHUD_HEALTH ( 1<<3 ) // Hide health & armor / suit battery +#define HIDEHUD_PLAYERDEAD ( 1<<4 ) // Hide when local player's dead +#define HIDEHUD_NEEDSUIT ( 1<<5 ) // Hide when the local player doesn't have the HEV suit +#define HIDEHUD_MISCSTATUS ( 1<<6 ) // Hide miscellaneous status elements (trains, pickup history, death notices, etc) +#define HIDEHUD_CHAT ( 1<<7 ) // Hide all communication elements (saytext, voice icon, etc) +#define HIDEHUD_CROSSHAIR ( 1<<8 ) // Hide crosshairs +#define HIDEHUD_VEHICLE_CROSSHAIR ( 1<<9 ) // Hide vehicle crosshair +#define HIDEHUD_INVEHICLE ( 1<<10 ) +#define HIDEHUD_BONUS_PROGRESS ( 1<<11 ) // Hide bonus progress display (for bonus map challenges) + +#define HIDEHUD_BITCOUNT 12 + +//=================================================================================================================== +// suit usage bits +#define bits_SUIT_DEVICE_SPRINT 0x00000001 +#define bits_SUIT_DEVICE_FLASHLIGHT 0x00000002 +#define bits_SUIT_DEVICE_BREATHER 0x00000004 + +#define MAX_SUIT_DEVICES 3 + + +//=================================================================================================================== +// Player Defines + +// Max number of players in a game ( see const.h for ABSOLUTE_PLAYER_LIMIT (256 ) ) +// The Source engine is really designed for 32 or less players. If you raise this number above 32, you better know what you are doing +// and have a good answer for a bunch of perf question related to player simulation, thinking logic, tracelines, networking overhead, etc. +// But if you are brave or are doing something interesting, go for it... ywb 9/22/03 + +//You might be wondering why these aren't multiple of 2. Well the reason is that if servers decide to have HLTV or Replay enabled we need the extra slot. +//This is ok since MAX_PLAYERS is used for code specific things like arrays and loops, but it doesn't really means that this is the max number of players allowed +//Since this is decided by the gamerules (and it can be whatever number as long as its less than MAX_PLAYERS). +#if defined( CSTRIKE_DLL ) + #define MAX_PLAYERS 65 // Absolute max players supported +#else + #define MAX_PLAYERS 33 // Absolute max players supported +#endif + +#define MAX_PLACE_NAME_LENGTH 18 + +#define MAX_FOV 90 + +//=================================================================================================================== +// Team Defines +#define TEAM_ANY -2 +#define TEAM_INVALID -1 +#define TEAM_UNASSIGNED 0 // not assigned to a team +#define TEAM_SPECTATOR 1 // spectator team +// Start your team numbers after this +#define LAST_SHARED_TEAM TEAM_SPECTATOR + +// The first team that's game specific (i.e. not unassigned / spectator) +#define FIRST_GAME_TEAM (LAST_SHARED_TEAM+1) + +#define MAX_TEAMS 32 // Max number of teams in a game +#define MAX_TEAM_NAME_LENGTH 32 // Max length of a team's name + +// Weapon m_iState +#define WEAPON_IS_ONTARGET 0x40 + +#define WEAPON_NOT_CARRIED 0 // Weapon is on the ground +#define WEAPON_IS_CARRIED_BY_PLAYER 1 // This client is carrying this weapon. +#define WEAPON_IS_ACTIVE 2 // This client is carrying this weapon and it's the currently held weapon + +// ----------------------------------------- +// Skill Level +// ----------------------------------------- +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 + + +// Weapon flags +// ----------------------------------------- +// Flags - NOTE: KEEP g_ItemFlags IN WEAPON_PARSE.CPP UPDATED WITH THESE +// ----------------------------------------- +#define ITEM_FLAG_SELECTONEMPTY (1<<0) +#define ITEM_FLAG_NOAUTORELOAD (1<<1) +#define ITEM_FLAG_NOAUTOSWITCHEMPTY (1<<2) +#define ITEM_FLAG_LIMITINWORLD (1<<3) +#define ITEM_FLAG_EXHAUSTIBLE (1<<4) // A player can totally exhaust their ammo supply and lose this weapon +#define ITEM_FLAG_DOHITLOCATIONDMG (1<<5) // This weapon take hit location into account when applying damage +#define ITEM_FLAG_NOAMMOPICKUPS (1<<6) // Don't draw ammo pickup sprites/sounds when ammo is received +#define ITEM_FLAG_NOITEMPICKUP (1<<7) // Don't draw weapon pickup when this weapon is picked up by the player +// NOTE: KEEP g_ItemFlags IN WEAPON_PARSE.CPP UPDATED WITH THESE + + +// Humans only have left and right hands, though we might have aliens with more +// than two, sigh +#define MAX_VIEWMODELS 2 + +#define MAX_BEAM_ENTS 10 + +#define TRACER_TYPE_DEFAULT 0x00000001 +#define TRACER_TYPE_GUNSHIP 0x00000002 +#define TRACER_TYPE_STRIDER 0x00000004 // Here ya go, Jay! +#define TRACER_TYPE_GAUSS 0x00000008 +#define TRACER_TYPE_WATERBULLET 0x00000010 + +#define MUZZLEFLASH_TYPE_DEFAULT 0x00000001 +#define MUZZLEFLASH_TYPE_GUNSHIP 0x00000002 +#define MUZZLEFLASH_TYPE_STRIDER 0x00000004 + +// Muzzle flash definitions (for the flags field of the "MuzzleFlash" DispatchEffect) +enum +{ + MUZZLEFLASH_AR2 = 0, + MUZZLEFLASH_SHOTGUN, + MUZZLEFLASH_SMG1, + MUZZLEFLASH_SMG2, + MUZZLEFLASH_PISTOL, + MUZZLEFLASH_COMBINE, + MUZZLEFLASH_357, + MUZZLEFLASH_RPG, + MUZZLEFLASH_COMBINE_TURRET, + + MUZZLEFLASH_FIRSTPERSON = 0x100, +}; + +// Tracer Flags +#define TRACER_FLAG_WHIZ 0x0001 +#define TRACER_FLAG_USEATTACHMENT 0x0002 + +#define TRACER_DONT_USE_ATTACHMENT -1 + +// Entity Dissolve types +enum +{ + ENTITY_DISSOLVE_NORMAL = 0, + ENTITY_DISSOLVE_ELECTRICAL, + ENTITY_DISSOLVE_ELECTRICAL_LIGHT, + ENTITY_DISSOLVE_CORE, + + // NOTE: Be sure to up the bits if you make more dissolve types + ENTITY_DISSOLVE_BITS = 3 +}; + +// --------------------------- +// Hit Group standards +// --------------------------- +#define HITGROUP_GENERIC 0 +#define HITGROUP_HEAD 1 +#define HITGROUP_CHEST 2 +#define HITGROUP_STOMACH 3 +#define HITGROUP_LEFTARM 4 +#define HITGROUP_RIGHTARM 5 +#define HITGROUP_LEFTLEG 6 +#define HITGROUP_RIGHTLEG 7 +#define HITGROUP_GEAR 10 // alerts NPC, but doesn't do damage or bleed (1/100th damage) + +// +// Enumerations for setting player animation. +// +enum PLAYER_ANIM +{ + PLAYER_IDLE, + PLAYER_WALK, + PLAYER_JUMP, + PLAYER_SUPERJUMP, + PLAYER_DIE, + PLAYER_ATTACK1, + PLAYER_IN_VEHICLE, + + // TF Player animations + PLAYER_RELOAD, + PLAYER_START_AIMING, + PLAYER_LEAVE_AIMING, +}; + +#ifdef HL2_DLL +// HL2 has 600 gravity by default +// NOTE: The discrete ticks can have quantization error, so these numbers are biased a little to +// make the heights more exact +#define PLAYER_FATAL_FALL_SPEED 922.5f // approx 60 feet sqrt( 2 * gravity * 60 * 12 ) +#define PLAYER_MAX_SAFE_FALL_SPEED 526.5f // approx 20 feet sqrt( 2 * gravity * 20 * 12 ) +#define PLAYER_LAND_ON_FLOATING_OBJECT 173 // Can fall another 173 in/sec without getting hurt +#define PLAYER_MIN_BOUNCE_SPEED 173 +#define PLAYER_FALL_PUNCH_THRESHOLD 303.0f // won't punch player's screen/make scrape noise unless player falling at least this fast - at least a 76" fall (sqrt( 2 * g * 76)) +#else +#define PLAYER_FATAL_FALL_SPEED 1024 // approx 60 feet +#define PLAYER_MAX_SAFE_FALL_SPEED 580 // approx 20 feet +#define PLAYER_LAND_ON_FLOATING_OBJECT 200 // Can go another 200 units without getting hurt +#define PLAYER_MIN_BOUNCE_SPEED 200 +#define PLAYER_FALL_PUNCH_THRESHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. +#endif +#define DAMAGE_FOR_FALL_SPEED 100.0f / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED ) // damage per unit per second. + + +#define AUTOAIM_2DEGREES 0.0348994967025 +#define AUTOAIM_5DEGREES 0.08715574274766 +#define AUTOAIM_8DEGREES 0.1391731009601 +#define AUTOAIM_10DEGREES 0.1736481776669 +#define AUTOAIM_20DEGREES 0.3490658503989 + +#define AUTOAIM_SCALE_DEFAULT 1.0f +#define AUTOAIM_SCALE_DIRECT_ONLY 0.0f + +// instant damage + +// For a means of resolving these consts into debug string text, see function +// CTakeDamageInfo::DebugGetDamageTypeString(unsigned int DamageType, char *outbuf, unsigned int outbuflength ) +#define DMG_GENERIC 0 // generic damage -- do not use if you want players to flinch and bleed! +#define DMG_CRUSH (1 << 0) // crushed by falling or moving object. + // NOTE: It's assumed crush damage is occurring as a result of physics collision, so no extra physics force is generated by crush damage. + // DON'T use DMG_CRUSH when damaging entities unless it's the result of a physics collision. You probably want DMG_CLUB instead. +#define DMG_BULLET (1 << 1) // shot +#define DMG_SLASH (1 << 2) // cut, clawed, stabbed +#define DMG_BURN (1 << 3) // heat burned +#define DMG_VEHICLE (1 << 4) // hit by a vehicle +#define DMG_FALL (1 << 5) // fell too far +#define DMG_BLAST (1 << 6) // explosive blast damage +#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt +#define DMG_SHOCK (1 << 8) // electric shock +#define DMG_SONIC (1 << 9) // sound pulse shockwave +#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam +#define DMG_PREVENT_PHYSICS_FORCE (1 << 11) // Prevent a physics force +#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death +#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. +#define DMG_DROWN (1 << 14) // Drowning + + +#define DMG_PARALYZE (1 << 15) // slows affected creature down +#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +#define DMG_POISON (1 << 17) // blood poisoning - heals over time like drowning damage +#define DMG_RADIATION (1 << 18) // radiation exposure +#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1 << 21) // in an oven + +#define DMG_REMOVENORAGDOLL (1<<22) // with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed. + // use this to kill an entity that you've already got a server-side ragdoll for + +#define DMG_PHYSGUN (1<<23) // Hit by manipulator. Usually doesn't do any damage. +#define DMG_PLASMA (1<<24) // Shot by Cremator +#define DMG_AIRBOAT (1<<25) // Hit by the airboat's gun + +#define DMG_DISSOLVE (1<<26) // Dissolving! +#define DMG_BLAST_SURFACE (1<<27) // A blast on the surface of water that cannot harm things underwater +#define DMG_DIRECT (1<<28) +#define DMG_BUCKSHOT (1<<29) // not quite a bullet. Little, rounder, different. + +// NOTE: DO NOT ADD ANY MORE CUSTOM DMG_ TYPES. MODS USE THE DMG_LASTGENERICFLAG BELOW, AND +// IF YOU ADD NEW DMG_ TYPES, THEIR TYPES WILL BE HOSED. WE NEED A BETTER SOLUTION. + +// TODO: keep this up to date so all the mod-specific flags don't overlap anything. +#define DMG_LASTGENERICFLAG DMG_BUCKSHOT + + + +// settings for m_takedamage +#define DAMAGE_NO 0 +#define DAMAGE_EVENTS_ONLY 1 // Call damage functions, but don't modify health +#define DAMAGE_YES 2 +#define DAMAGE_AIM 3 + +// Spectator Movement modes +enum { + OBS_MODE_NONE = 0, // not in spectator mode + OBS_MODE_DEATHCAM, // special mode for death cam animation + OBS_MODE_FREEZECAM, // zooms to a target, and freeze-frames on them + OBS_MODE_FIXED, // view from a fixed camera position + OBS_MODE_IN_EYE, // follow a player in first person view + OBS_MODE_CHASE, // follow a player in third person view + OBS_MODE_POI, // PASSTIME point of interest - game objective, big fight, anything interesting; added in the middle of the enum due to tons of hard-coded " m_UtlVecSoundOrigin; ///< Actual sound origin(s) (can be multiple if sound routed through speaker entity(ies) ) + mutable HSOUNDSCRIPTHANDLE m_hSoundScriptHandle; +}; + +#define MAX_ACTORS_IN_SCENE 16 + +//----------------------------------------------------------------------------- +// Multiplayer specific defines +//----------------------------------------------------------------------------- +#define MAX_CONTROL_POINTS 8 +#define MAX_CONTROL_POINT_GROUPS 8 + +// Maximum number of points that a control point may need owned to be cappable +#define MAX_PREVIOUS_POINTS 3 + +// The maximum number of teams the control point system knows how to deal with +#define MAX_CONTROL_POINT_TEAMS 8 + +// Maximum length of the cap layout string +#define MAX_CAPLAYOUT_LENGTH 32 + +// Maximum length of the current round printname +#define MAX_ROUND_NAME 32 + +// Maximum length of the current round name +#define MAX_ROUND_IMAGE_NAME 64 + +// Score added to the team score for a round win +#define TEAMPLAY_ROUND_WIN_SCORE 1 + +enum +{ + CP_WARN_NORMAL = 0, + CP_WARN_FINALCAP, + CP_WARN_NO_ANNOUNCEMENTS +}; + +// YWB: 3/12/2007 +// Changing the following #define for Prediction Error checking (See gamemovement.cpp for overview) will to 1 or 2 enables the system, 0 turns it off +// Level 1 enables it, but doesn't force "full precision" networking, so you can still get lots of errors in position/velocity/etc. +// Level 2 enables it but also forces origins/angles to be sent full precision, so other fields can be error / tolerance checked +// NOTE: This stuff only works on a listen server since it punches a hole from the client .dll to server .dll!!! +#define PREDICTION_ERROR_CHECK_LEVEL 0 + +//----------------------------------------------------------------------------- +// Round timer states +//----------------------------------------------------------------------------- +enum +{ + RT_STATE_SETUP, // Timer is in setup mode + RT_STATE_NORMAL, // Timer is in normal mode +}; + +enum +{ + SIMULATION_TIME_WINDOW_BITS = 8, +}; + +//----------------------------------------------------------------------------- +// Commentary Mode +//----------------------------------------------------------------------------- +#if defined(TF_DLL) || defined(TF_CLIENT_DLL) +#define GAME_HAS_NO_USE_KEY + +#if defined( SPROP_COORD ) +#undef SPROP_COORD +#endif + +#define SPROP_COORD SPROP_COORD_MP + +#endif + +// The player's method of starting / stopping commentary +#ifdef GAME_HAS_NO_USE_KEY +#define COMMENTARY_BUTTONS (IN_ATTACK | IN_ATTACK2 | IN_USE) +#else +#define COMMENTARY_BUTTONS (IN_USE) +#endif + +#define TEAM_TRAIN_MAX_TEAMS 4 +#define TEAM_TRAIN_MAX_HILLS 5 +#define TEAM_TRAIN_FLOATS_PER_HILL 2 +#define TEAM_TRAIN_HILLS_ARRAY_SIZE TEAM_TRAIN_MAX_TEAMS * TEAM_TRAIN_MAX_HILLS * TEAM_TRAIN_FLOATS_PER_HILL + +enum +{ + HILL_TYPE_NONE = 0, + HILL_TYPE_UPHILL, + HILL_TYPE_DOWNHILL, +}; + +#define NOINTERP_PARITY_MAX 4 +#define NOINTERP_PARITY_MAX_BITS 2 + +//----------------------------------------------------------------------------- +// Generic activity lookup support +//----------------------------------------------------------------------------- +enum +{ + kActivityLookup_Unknown = -2, // hasn't been searched for + kActivityLookup_Missing = -1, // has been searched for but wasn't found +}; + +#if defined(TF_DLL) || defined(TF_CLIENT_DLL) +//----------------------------------------------------------------------------- +// Vision Filters. +//----------------------------------------------------------------------------- +// Also used in the item schema to define vision filter or vision mode opt in +#define TF_VISION_FILTER_NONE 0 +#define TF_VISION_FILTER_PYRO (1<<0) // 1 +#define TF_VISION_FILTER_HALLOWEEN (1<<1) // 2 +#define TF_VISION_FILTER_ROME (1<<2) // 4 + +// THIS ENUM SHOULD MATCH THE ORDER OF THE FLAGS ABOVE +enum +{ + VISION_MODE_NONE = 0, + VISION_MODE_PYRO, + VISION_MODE_HALLOWEEN, + VISION_MODE_ROME, + + MAX_VISION_MODES +}; +#endif // TF_DLL || TF_CLIENT_DLL + +#endif // SHAREDDEFS_H diff --git a/game/shared/sheetsimulator.h b/game/shared/sheetsimulator.h new file mode 100644 index 0000000..aac523e --- /dev/null +++ b/game/shared/sheetsimulator.h @@ -0,0 +1,213 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SHEETSIMULATOR_H +#define SHEETSIMULATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "utlvector.h" + + +// Uncomment this for client-side simulation +//#define CLIENT_SIDE_SIMULATION 1 + +//----------------------------------------------------------------------------- +// Simulates a sheet +//----------------------------------------------------------------------------- + +class CGameTrace; +typedef CGameTrace trace_t; +//struct trace_t; +typedef void (*TraceLineFunc_t)(const Vector &vecStart, const Vector &vecEnd, + unsigned int mask, int collisionGroup, trace_t *ptr); +typedef void (*TraceHullFunc_t)(const Vector &vecStart, const Vector &vecEnd, + const Vector &hullMin, const Vector &hullMax, + unsigned int mask, int collisionGroup, trace_t *ptr); + + +class CSheetSimulator +{ +public: + CSheetSimulator( TraceLineFunc_t traceline, TraceHullFunc_t traceHull ); + ~CSheetSimulator(); + + void Init( int w, int h, int fixedPointCount ); + + // orientation + void SetPosition( const Vector& origin, const QAngle& angles ); + + // Makes a spring + void AddSpring( int p1, int p2, float restLength ); + void AddFixedPointSpring( int fixedPoint, int p, float restLength ); + + // spring constants.... + void SetPointSpringConstant( float constant ); + void SetFixedSpringConstant( float constant ); + + // Used for both kinds of springs + void SetSpringDampConstant( float damp ); + void SetViscousDrag( float drag ); + + // Sets the collision group + void SetCollisionGroup( int group ); + + // Sets the bounding box used for collision vs world + void SetBoundingBox( Vector& mins, Vector& maxs ); + + // Computes the bounding box + void ComputeBounds( Vector& mins, Vector& maxs ); + + // simulation + void Simulate( float dt ); + void Simulate( float dt, int steps ); + + // get at the points + int NumHorizontal() const; + int NumVertical() const; + int PointCount() const; + + // Fixed points + Vector& GetFixedPoint( int i ); + + // Point masses + const Vector& GetPoint( int x, int y ) const; + const Vector& GetPoint( int i ) const; + + // For iterative collision detection + void DetectCollision( int i, float flOffset ); + void InitPosition( int i ); + + // For offseting the control points + void SetControlPointOffset( const Vector& offset ); + + // Gravity + void SetGravityConstant( float g ); + void AddGravityForce( int particle ); + +protected: + struct Particle_t + { + float m_Mass; + Vector m_Position; + Vector m_Velocity; + Vector m_Force; + int m_Collided; + int m_CollisionPlane; + float m_CollisionDist; + }; + + struct Spring_t + { + int m_Particle1; + int m_Particle2; + float m_RestLength; + }; + + inline int NumParticles() const + { + return m_HorizontalCount * m_VerticalCount; + } + + // simulator + void EulerStep( float dt ); + void ComputeControlPoints(); + void ClearForces(); + void ComputeForces(); + void TestVertAgainstPlane( int vert, int plane, bool bFarTest = true ); + void SatisfyCollisionConstraints(); + void DetermineBestCollisionPlane( bool bFarTest = true ); + void ClampPointsToCollisionPlanes(); + + // How many particles horiz + vert? + int m_HorizontalCount; + int m_VerticalCount; + + // The particles + Particle_t* m_Particle; + + // Output position after simulation + Vector* m_OutputPosition; + + // fixed points + int m_FixedPointCount; + Vector* m_pFixedPoint; + Vector* m_ControlPoints; + + CUtlVector m_Springs; + CUtlVector m_Gravity; + + // raycasting methods + TraceLineFunc_t m_TraceLine; + TraceHullFunc_t m_TraceHull; + + // Spring constants + float m_FixedSpringConstant; + float m_PointSpringConstant; + float m_DampConstant; + float m_ViscousDrag; + + // Collision group + int m_CollisionGroup; + + // position + orientation + Vector m_Origin; + QAngle m_Angles; + + // collision box + Vector m_FrustumBoxMin; + Vector m_FrustumBoxMax; + + // Collision planes + cplane_t* m_pCollisionPlanes; + bool* m_pValidCollisionPlane; + + // Control point offset + Vector m_ControlPointOffset; + + // Gravity + float m_GravityConstant; +}; + + +//----------------------------------------------------------------------------- +// Class to help dealing with the iterative computation +//----------------------------------------------------------------------------- + +class CIterativeSheetSimulator : public CSheetSimulator +{ +public: + CIterativeSheetSimulator( TraceLineFunc_t traceline, TraceHullFunc_t traceHull ); + + void BeginSimulation( float dt, int steps, int substeps, int collisionCount ); + + // Returns true if it just did a simulation step + bool Think( ); + bool IsDone() const { return m_SimulationSteps == 0; } + + int StepsRemaining( ) const { return m_SimulationSteps; } + +private: + CIterativeSheetSimulator( const CIterativeSheetSimulator & ); // not defined, not accessible + + // Iterative collision detection + void DetectCollisions( void ); + + float m_TimeStep; + float m_SubSteps; + char m_TotalSteps; + char m_SimulationSteps; + char m_CollisionCount; + char m_CurrentCollisionPt; + bool m_InitialPass; +}; + + +#endif // TF_SHIELD_SHARED_H diff --git a/game/shared/shot_manipulator.h b/game/shared/shot_manipulator.h new file mode 100644 index 0000000..4056cb3 --- /dev/null +++ b/game/shared/shot_manipulator.h @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SHOT_MANIPULATOR_H +#define SHOT_MANIPULATOR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" + + +extern ConVar ai_shot_bias_min; +extern ConVar ai_shot_bias_max; + + +//--------------------------------------------------------- +// Caches off a shot direction and allows you to perform +// various operations on it without having to recalculate +// vecRight and vecUp each time. +//--------------------------------------------------------- +class CShotManipulator +{ +public: + CShotManipulator( const Vector &vecForward ) + { + SetShootDir( vecForward ); + }; + + void SetShootDir( const Vector &vecForward ) + { + m_vecShotDirection = vecForward; + VectorVectors( m_vecShotDirection, m_vecRight, m_vecUp ); + } + + const Vector &ApplySpread( const Vector &vecSpread, float bias = 1.0 ); + + const Vector &GetShotDirection() { return m_vecShotDirection; } + const Vector &GetResult() { return m_vecResult; } + const Vector &GetRightVector() { return m_vecRight; } + const Vector &GetUpVector() { return m_vecUp;} + +private: + Vector m_vecShotDirection; + Vector m_vecRight; + Vector m_vecUp; + Vector m_vecResult; +}; + +//--------------------------------------------------------- +// Take a vector (direction) and another vector (spread) +// and modify the direction to point somewhere within the +// spread. This used to live inside FireBullets. +//--------------------------------------------------------- +inline const Vector &CShotManipulator::ApplySpread( const Vector &vecSpread, float bias ) +{ + // get circular gaussian spread + float x, y, z; + + if ( bias > 1.0 ) + bias = 1.0; + else if ( bias < 0.0 ) + bias = 0.0; + + float shotBiasMin = ai_shot_bias_min.GetFloat(); + float shotBiasMax = ai_shot_bias_max.GetFloat(); + + // 1.0 gaussian, 0.0 is flat, -1.0 is inverse gaussian + float shotBias = ( ( shotBiasMax - shotBiasMin ) * bias ) + shotBiasMin; + + float flatness = ( fabsf(shotBias) * 0.5 ); + + do + { + x = random->RandomFloat(-1,1) * flatness + random->RandomFloat(-1,1) * (1 - flatness); + y = random->RandomFloat(-1,1) * flatness + random->RandomFloat(-1,1) * (1 - flatness); + if ( shotBias < 0 ) + { + x = ( x >= 0 ) ? 1.0 - x : -1.0 - x; + y = ( y >= 0 ) ? 1.0 - y : -1.0 - y; + } + z = x*x+y*y; + } while (z > 1); + + m_vecResult = m_vecShotDirection + x * vecSpread.x * m_vecRight + y * vecSpread.y * m_vecUp; + + return m_vecResult; +} + + +#endif // SHOT_MANIPULATOR_H diff --git a/game/shared/simtimer.h b/game/shared/simtimer.h new file mode 100644 index 0000000..7f26c41 --- /dev/null +++ b/game/shared/simtimer.h @@ -0,0 +1,346 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SIMTIMER_H +#define SIMTIMER_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#define ST_EPS 0.001 + +#define DEFINE_SIMTIMER( type, name ) DEFINE_EMBEDDED( type, name ) + +//----------------------------------------------------------------------------- + +class CSimpleSimTimer +{ +public: + CSimpleSimTimer() + : m_next( -1 ) + { + } + + void Force() + { + m_next = -1; + } + + bool Expired() const + { + return ( gpGlobals->curtime - m_next > -ST_EPS ); + } + + float Delay( float delayTime ) + { + return (m_next += delayTime); + } + + float GetNext() const + { + return m_next; + } + + void Set( float interval ) + { + m_next = gpGlobals->curtime + interval; + } + + void Set( float minInterval, float maxInterval ) + { + if ( maxInterval > 0.0 ) + m_next = gpGlobals->curtime + random->RandomFloat( minInterval, maxInterval ); + else + m_next = gpGlobals->curtime + minInterval; + } + + float GetRemaining() const + { + float result = m_next - gpGlobals->curtime; + if (result < 0 ) + return 0; + return result; + } + + DECLARE_SIMPLE_DATADESC(); + +protected: + float m_next; +}; + +//----------------------------------------------------------------------------- + +class CSimTimer : public CSimpleSimTimer +{ +public: + CSimTimer( float interval = 0.0, bool startExpired = true ) + { + Set( interval, startExpired ); + } + + void Set( float interval, bool startExpired = true ) + { + m_interval = interval; + m_next = (startExpired) ? -1.0 : gpGlobals->curtime + m_interval; + } + + void Reset( float interval = -1.0 ) + { + if ( interval == -1.0 ) + { + m_next = gpGlobals->curtime + m_interval; + } + else + { + m_next = gpGlobals->curtime + interval; + } + } + + float GetInterval() const + { + return m_interval; + } + + DECLARE_SIMPLE_DATADESC(); + +private: + float m_interval; +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +class CRandSimTimer : public CSimpleSimTimer +{ +public: + CRandSimTimer( float minInterval = 0.0, float maxInterval = 0.0, bool startExpired = true ) + { + Set( minInterval, maxInterval, startExpired ); + } + + void Set( float minInterval, float maxInterval = 0.0, bool startExpired = true ) + { + m_minInterval = minInterval; + m_maxInterval = maxInterval; + + if (startExpired) + { + m_next = -1; + } + else + { + if ( m_maxInterval == 0 ) + m_next = gpGlobals->curtime + m_minInterval; + else + m_next = gpGlobals->curtime + random->RandomFloat( m_minInterval, m_maxInterval ); + } + } + + void Reset() + { + if ( m_maxInterval == 0 ) + m_next = gpGlobals->curtime + m_minInterval; + else + m_next = gpGlobals->curtime + random->RandomFloat( m_minInterval, m_maxInterval ); + } + + float GetMinInterval() const + { + return m_minInterval; + } + + float GetMaxInterval() const + { + return m_maxInterval; + } + + DECLARE_SIMPLE_DATADESC(); + +private: + float m_minInterval; + float m_maxInterval; +}; + +//----------------------------------------------------------------------------- + +class CStopwatchBase : public CSimpleSimTimer +{ +public: + CStopwatchBase() + { + m_fIsRunning = false; + } + + bool IsRunning() const + { + return m_fIsRunning; + } + + void Stop() + { + m_fIsRunning = false; + } + + bool Expired() const + { + return ( m_fIsRunning && CSimpleSimTimer::Expired() ); + } + + DECLARE_SIMPLE_DATADESC(); + +protected: + bool m_fIsRunning; + +}; + +//------------------------------------- +class CSimpleStopwatch : public CStopwatchBase +{ +public: + void Start( float minCountdown, float maxCountdown = 0.0 ) + { + m_fIsRunning = true; + CSimpleSimTimer::Set( minCountdown, maxCountdown ); + } + + void Stop() + { + m_fIsRunning = false; + } + + bool Expired() const + { + return ( m_fIsRunning && CSimpleSimTimer::Expired() ); + } +}; +//------------------------------------- + +class CStopwatch : public CStopwatchBase +{ +public: + CStopwatch ( float interval = 0.0 ) + { + Set( interval ); + } + + void Set( float interval ) + { + m_interval = interval; + } + + void Start( float intervalOverride ) + { + m_fIsRunning = true; + m_next = gpGlobals->curtime + intervalOverride; + } + + void Start() + { + Start( m_interval ); + } + + float GetInterval() const + { + return m_interval; + } + + DECLARE_SIMPLE_DATADESC(); + +private: + float m_interval; +}; + +//------------------------------------- + +class CRandStopwatch : public CStopwatchBase +{ +public: + CRandStopwatch( float minInterval = 0.0, float maxInterval = 0.0 ) + { + Set( minInterval, maxInterval ); + } + + void Set( float minInterval, float maxInterval = 0.0 ) + { + m_minInterval = minInterval; + m_maxInterval = maxInterval; + } + + void Start( float minOverride, float maxOverride = 0.0 ) + { + m_fIsRunning = true; + if ( maxOverride == 0 ) + m_next = gpGlobals->curtime + minOverride; + else + m_next = gpGlobals->curtime + random->RandomFloat( minOverride, maxOverride ); + } + + void Start() + { + Start( m_minInterval, m_maxInterval ); + } + + float GetInterval() const + { + return m_minInterval; + } + + float GetMinInterval() const + { + return m_minInterval; + } + + float GetMaxInterval() const + { + return m_maxInterval; + } + + DECLARE_SIMPLE_DATADESC(); + +private: + float m_minInterval; + float m_maxInterval; +}; + +//----------------------------------------------------------------------------- + +class CThinkOnceSemaphore +{ +public: + CThinkOnceSemaphore() + : m_lastTime( -1 ) + { + } + + bool EnterThink() + { + if ( m_lastTime == gpGlobals->curtime ) + return false; + m_lastTime = gpGlobals->curtime; + return true; + } + + bool DidThink() const + { + return ( gpGlobals->curtime == m_lastTime ); + + } + + void SetDidThink() + { + m_lastTime = gpGlobals->curtime; + } + +private: + float m_lastTime; +}; + +//----------------------------------------------------------------------------- + +#endif // SIMTIMER_H diff --git a/game/shared/singleplay_gamerules.h b/game/shared/singleplay_gamerules.h new file mode 100644 index 0000000..3b48b43 --- /dev/null +++ b/game/shared/singleplay_gamerules.h @@ -0,0 +1,132 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SINGLEPLAY_GAMERULES_H +#define SINGLEPLAY_GAMERULES_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "gamerules.h" + + +#ifdef CLIENT_DLL + + #define CSingleplayRules C_SingleplayRules + +#endif + + +//========================================================= +// CSingleplayRules - rules for the single player Half-Life +// game. +//========================================================= +class CSingleplayRules : public CGameRules +{ +public: + + DECLARE_CLASS( CSingleplayRules, CGameRules ); + + +// Functions to verify the single/multiplayer status of a game + virtual bool IsMultiplayer( void ); + + // Damage query implementations. + virtual bool Damage_IsTimeBased( int iDmgType ); // Damage types that are time-based. + virtual bool Damage_ShouldGibCorpse( int iDmgType ); // Damage types that gib the corpse. + virtual bool Damage_ShowOnHUD( int iDmgType ); // Damage types that have client HUD art. + virtual bool Damage_NoPhysicsForce( int iDmgType ); // Damage types that don't have to supply a physics force & position. + virtual bool Damage_ShouldNotBleed( int iDmgType ); // Damage types that don't make the player bleed. + // TEMP: These will go away once DamageTypes become enums. + virtual int Damage_GetTimeBased( void ); + virtual int Damage_GetShouldGibCorpse( void ); + virtual int Damage_GetShowOnHud( void ); + virtual int Damage_GetNoPhysicsForce( void ); + virtual int Damage_GetShouldNotBleed( void ); + +#ifdef CLIENT_DLL + +#else + + CSingleplayRules(); + virtual ~CSingleplayRules() {} + +// GR_Think + virtual void Think( void ); + virtual bool IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual bool FAllowFlashlight( void ) { return TRUE; }; + + virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ); + virtual CBaseCombatWeapon *GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); + bool SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual bool IsDeathmatch( void ); + virtual bool IsCoOp( void ); + +// Client connection/disconnection + virtual bool ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + virtual bool AllowDamage( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual bool FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + + virtual bool AllowAutoTargetCrosshair( void ); + virtual int GetAutoAimMode(); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon ); + virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ); + virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon ); + +// Item retrieval + virtual bool CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + virtual QAngle VecItemRespawnAngles( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBaseCombatCharacter *pPlayer, char *szName, int iCount ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// NPCs + virtual bool FAllowNPCs( void ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual bool PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker ); +#endif +}; + + +#endif // SINGLEPLAY_GAMERULES_H diff --git a/game/shared/sixense/sixense_convars_extern.h b/game/shared/sixense/sixense_convars_extern.h new file mode 100644 index 0000000..0fe4d88 --- /dev/null +++ b/game/shared/sixense/sixense_convars_extern.h @@ -0,0 +1,124 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// + +class ConVar; + +#include "cbase.h" +#include "convar.h" + +#ifdef SIXENSE + +// +// general sixense convars +// + +extern ConVar sixense_enabled; +extern ConVar sixense_filter_level; +extern ConVar sixense_features_enabled; +extern ConVar sixense_mode; +extern ConVar sixense_ratchet_lesson_angle_threshold; +extern ConVar sixense_ratchet_lesson_angle_end_threshold; +extern ConVar sixense_ratchet_lesson_angle_hold_time; +extern ConVar sixense_disable_ratchet_lesson; +extern ConVar sixense_enable_tutorial_ratchet_lesson; +extern ConVar sixense_disable_scale_reset_lesson; + +// +// grab convars +// + +extern ConVar sixense_throw_multiplier; +extern ConVar sixense_hold_multiplier; +extern ConVar sixense_hold_z_scale; +extern ConVar sixense_hold_z_min; +extern ConVar sixense_hold_z_max; +extern ConVar sixense_hold_z_min_no_portalgun; +extern ConVar sixense_hold_z_max_no_portalgun; +extern ConVar sixense_throw_max_vel; +extern ConVar sixense_hold_blend; +extern ConVar sixense_hold_offset_x; +extern ConVar sixense_hold_offset_y; +extern ConVar sixense_hold_offset_z; +extern ConVar sixense_velocity_blend_val; +extern ConVar sixense_hold_error_max_noise; +extern ConVar sixense_hold_error_min; +extern ConVar sixense_hold_error_max; +extern ConVar sixense_hold_sound_pitch; +extern ConVar sixense_hold_sound_scaling_pitch; +extern ConVar sixense_hold_sound_error_pitch; +extern ConVar sixense_hold_move_sound_pitch; +extern ConVar sixense_hold_beam_portal_delay_time; +extern ConVar sixense_hold_length_error; +extern ConVar sixense_hold_length_error_fraction; +extern ConVar sixense_drop_cube_button_funnel_velocity_scale; +extern ConVar sixense_hold_color_error_min; +extern ConVar sixense_hold_color_error_max; +extern ConVar sixense_hold_turret_pickup_time; +extern ConVar sixense_hold_turret_distance; + +// +// portal tweaking convars +// + +extern ConVar sixense_portal_tweaking_enabled; +extern ConVar sixense_portal_tweaking_roll_scale; +extern ConVar sixense_portal_tweaking_grab_radius; +extern ConVar sixense_portal_tweaking_fire_hold_time; +extern ConVar sixense_portal_tweaking_break_cos_angle; +extern ConVar sixense_portal_tweaking_break_distance; +extern ConVar sixense_portal_tweaking_failed_break_distance; +extern ConVar sixense_portal_tweaking_was_delay; +extern ConVar sixense_portal_tweaking_align_blend_time; +extern ConVar sixense_portal_tweaking_strength_noise; +extern ConVar sixense_portal_tweaking_whoosh_pitch; +extern ConVar sixense_portal_tweaking_pitch_1; +extern ConVar sixense_portal_tweaking_pitch_2; +extern ConVar sixense_portal_tweaking_strength_pitch; +extern ConVar sixense_portal_tweaking_velocity_pitch; +extern ConVar sixense_portal_tweaking_roll_velocity_pitch; +extern ConVar sixense_portal_tweaking_velocity_min; +extern ConVar sixense_portal_tweaking_velocity_max; +extern ConVar sixense_portal_tweaking_roll_velocity_min; +extern ConVar sixense_portal_tweaking_roll_velocity_max; +extern ConVar sixense_portal_tweaking_velocity_time; +extern ConVar sixense_portal_tweaking_volume; +extern ConVar sixense_portal_tweaking_move_volume; +extern ConVar sixense_portal_tweaking_disabled_with_scaled_cube; +extern ConVar sixense_portal_tweaking_moved_time; + +// +// scaling convars +// + +extern ConVar sixense_scaling_hold_radius_mode; +extern ConVar sixense_scaling_hold_radius; +extern ConVar sixense_scaling_hold_radius_base; +extern ConVar sixense_scaling_hold_radius_blend_time; +extern ConVar sixense_scaling_error_blend_time; +extern ConVar sixense_scaling_error_noise; +extern ConVar sixense_scaling_increment_controller_distance; +extern ConVar sixense_scaling_reset_time; +extern ConVar sixense_scaling_increment; +extern ConVar sixense_scaling_min; +extern ConVar sixense_scaling_max; +extern ConVar sixense_scaling_volume; +extern ConVar sixense_scaling_volume_clamped; +extern ConVar sixense_scaling_volume_initial; +extern ConVar sixense_scaling_pitch_clamped_min; +extern ConVar sixense_scaling_pitch_clamped_max; +extern ConVar sixense_scaling_pitch_initial; +extern ConVar sixense_scaling_turret_controller_distance; +extern ConVar sixense_scaling_turret_min; +extern ConVar sixense_scaling_turret_max; +extern ConVar sixense_scaling_turret_increment; +extern ConVar sixense_scaling_turret_beam_min; +extern ConVar sixense_scaling_turret_beam_max; +extern ConVar sixense_scaling_turret_time; +extern ConVar sixense_scaling_turret_model_time; +extern ConVar sixense_scaling_turret_volume; +extern ConVar sixense_scaling_turret_pitch_larger; +extern ConVar sixense_scaling_turret_pitch_smaller; +extern ConVar sixense_scaling_blend; +extern ConVar sixense_scaling_blend_time; +extern ConVar sixense_scaling_controller_pos_offset_z; + +#endif // SIXENSE diff --git a/game/shared/smoke_fog_overlay_shared.h b/game/shared/smoke_fog_overlay_shared.h new file mode 100644 index 0000000..2674e5e --- /dev/null +++ b/game/shared/smoke_fog_overlay_shared.h @@ -0,0 +1,14 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// + +#ifndef SMOKE_FOG_OVERLAY_SHARED_H +#define SMOKE_FOG_OVERLAY_SHARED_H + + +#define SMOKEGRENADE_PARTICLERADIUS 80 +#define SMOKEPARTICLE_OVERLAP 20 +#define SMOKEPARTICLE_SIZE 80 + + +#endif + + diff --git a/game/shared/solidsetdefaults.h b/game/shared/solidsetdefaults.h new file mode 100644 index 0000000..1017796 --- /dev/null +++ b/game/shared/solidsetdefaults.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SOLIDSETDEFAULTS_H +#define SOLIDSETDEFAULTS_H +#ifdef _WIN32 +#pragma once +#endif + +// solid_t parsing +class CSolidSetDefaults : public IVPhysicsKeyHandler +{ +public: + virtual void ParseKeyValue( void *pData, const char *pKey, const char *pValue ); + virtual void SetDefaults( void *pData ); + + unsigned int GetContentsMask() { return m_contentsMask; } + +private: + unsigned int m_contentsMask; +}; + +extern CSolidSetDefaults g_SolidSetup; + +#endif // SOLIDSETDEFAULTS_H diff --git a/game/shared/soundenvelope.h b/game/shared/soundenvelope.h new file mode 100644 index 0000000..5a84b59 --- /dev/null +++ b/game/shared/soundenvelope.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SOUNDENVELOPE_H +#define SOUNDENVELOPE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "engine/IEngineSound.h" + +class CSoundPatch; + +enum soundcommands_t +{ + SOUNDCTRL_CHANGE_VOLUME, + SOUNDCTRL_CHANGE_PITCH, + SOUNDCTRL_STOP, + SOUNDCTRL_DESTROY, +}; + +//Envelope point +struct envelopePoint_t +{ + float amplitudeMin, amplitudeMax; + float durationMin, durationMax; +}; + +//Envelope description +struct envelopeDescription_t +{ + envelopePoint_t *pPoints; + int nNumPoints; +}; + +class IRecipientFilter; + +abstract_class CSoundEnvelopeController +{ +public: + virtual void SystemReset( void ) = 0; + virtual void SystemUpdate( void ) = 0; + virtual void Play( CSoundPatch *pSound, float volume, float pitch, float flStartTime = 0 ) = 0; + virtual void CommandAdd( CSoundPatch *pSound, float executeDeltaTime, soundcommands_t command, float commandTime, float value ) = 0; + virtual void CommandClear( CSoundPatch *pSound ) = 0; + virtual void Shutdown( CSoundPatch *pSound ) = 0; + + virtual CSoundPatch *SoundCreate( IRecipientFilter& filter, int nEntIndex, const char *pSoundName ) = 0; + virtual CSoundPatch *SoundCreate( IRecipientFilter& filter, int nEntIndex, int channel, const char *pSoundName, + float attenuation ) = 0; + virtual CSoundPatch *SoundCreate( IRecipientFilter& filter, int nEntIndex, int channel, const char *pSoundName, + soundlevel_t soundlevel ) = 0; + virtual CSoundPatch *SoundCreate( IRecipientFilter& filter, int nEntIndex, const EmitSound_t &es ) = 0; + virtual void SoundDestroy( CSoundPatch * ) = 0; + virtual void SoundChangePitch( CSoundPatch *pSound, float pitchTarget, float deltaTime ) = 0; + virtual void SoundChangeVolume( CSoundPatch *pSound, float volumeTarget, float deltaTime ) = 0; + virtual void SoundFadeOut( CSoundPatch *pSound, float deltaTime, bool destroyOnFadeout = false ) = 0; + virtual float SoundGetPitch( CSoundPatch *pSound ) = 0; + virtual float SoundGetVolume( CSoundPatch *pSound ) = 0; + + virtual float SoundPlayEnvelope( CSoundPatch *pSound, soundcommands_t soundCommand, envelopePoint_t *points, int numPoints ) = 0; + virtual float SoundPlayEnvelope( CSoundPatch *pSound, soundcommands_t soundCommand, envelopeDescription_t *envelope ) = 0; + + virtual void CheckLoopingSoundsForPlayer( CBasePlayer *pPlayer ) = 0; + + virtual string_t SoundGetName( CSoundPatch *pSound ) = 0; + static CSoundEnvelopeController &GetController( void ); + + virtual void SoundSetCloseCaptionDuration( CSoundPatch *pSound, float flDuration ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Save/restore +//----------------------------------------------------------------------------- +class ISaveRestoreOps; + +ISaveRestoreOps *GetSoundSaveRestoreOps( ); + +#define DEFINE_SOUNDPATCH(name) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, GetSoundSaveRestoreOps( ), NULL } + + +#endif // SOUNDENVELOPE_H diff --git a/game/shared/sun_shared.h b/game/shared/sun_shared.h new file mode 100644 index 0000000..7696908 --- /dev/null +++ b/game/shared/sun_shared.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SUN_SHARED_H +#define SUN_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +//FIXME: It strikes me that the usefulness of this header file is now diminished + +#define MAX_SUN_LAYERS 4 + +#define SF_LIGHTGLOW_DIRECTIONAL (1<<0) +#define SF_MODULATE_BY_DIRECTION (1<<1) + +#endif // SUN_SHARED_H diff --git a/game/shared/takedamageinfo.h b/game/shared/takedamageinfo.h new file mode 100644 index 0000000..43dfdf4 --- /dev/null +++ b/game/shared/takedamageinfo.h @@ -0,0 +1,394 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TAKEDAMAGEINFO_H +#define TAKEDAMAGEINFO_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "networkvar.h" // todo: change this when DECLARE_CLASS is moved into a better location. + +// Used to initialize m_flBaseDamage to something that we know pretty much for sure +// hasn't been modified by a user. +#define BASEDAMAGE_NOT_SPECIFIED FLT_MAX + +class CBaseEntity; + + +class CTakeDamageInfo +{ +public: + DECLARE_CLASS_NOBASE( CTakeDamageInfo ); + + CTakeDamageInfo(); + CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, int iKillType = 0 ); + CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, float flDamage, int bitsDamageType, int iKillType = 0 ); + CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType = 0, Vector *reportedPosition = NULL ); + CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType = 0, Vector *reportedPosition = NULL ); + + + // Inflictor is the weapon or rocket (or player) that is dealing the damage. + CBaseEntity* GetInflictor() const; + void SetInflictor( CBaseEntity *pInflictor ); + + // Weapon is the weapon that did the attack. + // For hitscan weapons, it'll be the same as the inflictor. For projectile weapons, the projectile + // is the inflictor, and this contains the weapon that created the projectile. + CBaseEntity* GetWeapon() const; + void SetWeapon( CBaseEntity *pWeapon ); + + // Attacker is the character who originated the attack (like a player or an AI). + CBaseEntity* GetAttacker() const; + void SetAttacker( CBaseEntity *pAttacker ); + + float GetDamage() const; + void SetDamage( float flDamage ); + float GetMaxDamage() const; + void SetMaxDamage( float flMaxDamage ); + void ScaleDamage( float flScaleAmount ); + void AddDamage( float flAddAmount ); + void SubtractDamage( float flSubtractAmount ); + float GetDamageBonus() const; + CBaseEntity *GetDamageBonusProvider() const; + void SetDamageBonus( float flBonus, CBaseEntity *pProvider = NULL ); + + float GetBaseDamage() const; + bool BaseDamageIsValid() const; + + Vector GetDamageForce() const; + void SetDamageForce( const Vector &damageForce ); + void ScaleDamageForce( float flScaleAmount ); + float GetDamageForForceCalc() const; + void SetDamageForForceCalc( const float flScaleAmount ); + + Vector GetDamagePosition() const; + void SetDamagePosition( const Vector &damagePosition ); + + Vector GetReportedPosition() const; + void SetReportedPosition( const Vector &reportedPosition ); + + int GetDamageType() const; + void SetDamageType( int bitsDamageType ); + void AddDamageType( int bitsDamageType ); + int GetDamageCustom( void ) const; + void SetDamageCustom( int iDamageCustom ); + int GetDamageStats( void ) const; + void SetDamageStats( int iDamageStats ); + void SetForceFriendlyFire( bool bValue ) { m_bForceFriendlyFire = bValue; } + bool IsForceFriendlyFire( void ) const { return m_bForceFriendlyFire; } + + int GetAmmoType() const; + void SetAmmoType( int iAmmoType ); + const char * GetAmmoName() const; + + int GetPlayerPenetrationCount() const { return m_iPlayerPenetrationCount; } + void SetPlayerPenetrationCount( int iPlayerPenetrationCount ) { m_iPlayerPenetrationCount = iPlayerPenetrationCount; } + + int GetDamagedOtherPlayers() const { return m_iDamagedOtherPlayers; } + void SetDamagedOtherPlayers( int iVal ) { m_iDamagedOtherPlayers = iVal; } + + void Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, int iKillType = 0 ); + void Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, float flDamage, int bitsDamageType, int iKillType = 0 ); + void Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType = 0, Vector *reportedPosition = NULL ); + void Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType = 0, Vector *reportedPosition = NULL ); + + void AdjustPlayerDamageInflictedForSkillLevel(); + void AdjustPlayerDamageTakenForSkillLevel(); + + // Given a damage type (composed of the #defines above), fill out a string with the appropriate text. + // For designer debug output. + static void DebugGetDamageTypeString(unsigned int DamageType, char *outbuf, int outbuflength ); + + +//private: + void CopyDamageToBaseDamage(); + +protected: + void Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iKillType ); + + Vector m_vecDamageForce; + Vector m_vecDamagePosition; + Vector m_vecReportedPosition; // Position players are told damage is coming from + EHANDLE m_hInflictor; + EHANDLE m_hAttacker; + EHANDLE m_hWeapon; + float m_flDamage; + float m_flMaxDamage; + float m_flBaseDamage; // The damage amount before skill leve adjustments are made. Used to get uniform damage forces. + int m_bitsDamageType; + int m_iDamageCustom; + int m_iDamageStats; + int m_iAmmoType; // AmmoType of the weapon used to cause this damage, if any + int m_iDamagedOtherPlayers; + int m_iPlayerPenetrationCount; + float m_flDamageBonus; // Anything that increases damage (crit) - store the delta + EHANDLE m_hDamageBonusProvider; // Who gave us the ability to do extra damage? + bool m_bForceFriendlyFire; // Ideally this would be a dmg type, but we can't add more + + float m_flDamageForForce; + + DECLARE_SIMPLE_DATADESC(); +}; + +//----------------------------------------------------------------------------- +// Purpose: Multi damage. Used to collect multiple damages in the same frame (i.e. shotgun pellets) +//----------------------------------------------------------------------------- +class CMultiDamage : public CTakeDamageInfo +{ + DECLARE_CLASS( CMultiDamage, CTakeDamageInfo ); +public: + CMultiDamage(); + + bool IsClear( void ) { return (m_hTarget == NULL); } + CBaseEntity *GetTarget() const; + void SetTarget( CBaseEntity *pTarget ); + + void Init( CBaseEntity *pTarget, CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iKillType ); + +protected: + EHANDLE m_hTarget; + + DECLARE_SIMPLE_DATADESC(); +}; + +extern CMultiDamage g_MultiDamage; + +// Multidamage accessors +void ClearMultiDamage( void ); +void ApplyMultiDamage( void ); +void AddMultiDamage( const CTakeDamageInfo &info, CBaseEntity *pEntity ); + +//----------------------------------------------------------------------------- +// Purpose: Utility functions for physics damage force calculation +//----------------------------------------------------------------------------- +float ImpulseScale( float flTargetMass, float flDesiredSpeed ); +void CalculateExplosiveDamageForce( CTakeDamageInfo *info, const Vector &vecDir, const Vector &vecForceOrigin, float flScale = 1.0 ); +void CalculateBulletDamageForce( CTakeDamageInfo *info, int iBulletType, const Vector &vecBulletDir, const Vector &vecForceOrigin, float flScale = 1.0 ); +void CalculateMeleeDamageForce( CTakeDamageInfo *info, const Vector &vecMeleeDir, const Vector &vecForceOrigin, float flScale = 1.0 ); +void GuessDamageForce( CTakeDamageInfo *info, const Vector &vecForceDir, const Vector &vecForceOrigin, float flScale = 1.0 ); + + +// -------------------------------------------------------------------------------------------------- // +// Inlines. +// -------------------------------------------------------------------------------------------------- // + +inline CBaseEntity* CTakeDamageInfo::GetInflictor() const +{ + return m_hInflictor; +} + + +inline void CTakeDamageInfo::SetInflictor( CBaseEntity *pInflictor ) +{ + m_hInflictor = pInflictor; +} + + +inline CBaseEntity* CTakeDamageInfo::GetAttacker() const +{ + return m_hAttacker; +} + + +inline void CTakeDamageInfo::SetAttacker( CBaseEntity *pAttacker ) +{ + m_hAttacker = pAttacker; +} + +inline CBaseEntity* CTakeDamageInfo::GetWeapon() const +{ + return m_hWeapon; +} + + +inline void CTakeDamageInfo::SetWeapon( CBaseEntity *pWeapon ) +{ + m_hWeapon = pWeapon; +} + + +inline float CTakeDamageInfo::GetDamage() const +{ + return m_flDamage; +} + +inline void CTakeDamageInfo::SetDamage( float flDamage ) +{ + m_flDamage = flDamage; +} + +inline float CTakeDamageInfo::GetMaxDamage() const +{ + return m_flMaxDamage; +} + +inline void CTakeDamageInfo::SetMaxDamage( float flMaxDamage ) +{ + m_flMaxDamage = flMaxDamage; +} + +inline void CTakeDamageInfo::ScaleDamage( float flScaleAmount ) +{ + m_flDamage *= flScaleAmount; +} + +inline void CTakeDamageInfo::AddDamage( float flAddAmount ) +{ + m_flDamage += flAddAmount; +} + +inline void CTakeDamageInfo::SubtractDamage( float flSubtractAmount ) +{ + m_flDamage -= flSubtractAmount; +} + +inline float CTakeDamageInfo::GetDamageBonus() const +{ + return m_flDamageBonus; +} + +inline CBaseEntity *CTakeDamageInfo::GetDamageBonusProvider() const +{ + return m_hDamageBonusProvider; +} + +inline void CTakeDamageInfo::SetDamageBonus( float flBonus, CBaseEntity *pProvider /*= NULL*/ ) +{ + m_flDamageBonus = flBonus; + m_hDamageBonusProvider = pProvider; +} + +inline float CTakeDamageInfo::GetBaseDamage() const +{ + if( BaseDamageIsValid() ) + return m_flBaseDamage; + + // No one ever specified a base damage, so just return damage. + return m_flDamage; +} + +inline bool CTakeDamageInfo::BaseDamageIsValid() const +{ + return (m_flBaseDamage != BASEDAMAGE_NOT_SPECIFIED); +} + +inline Vector CTakeDamageInfo::GetDamageForce() const +{ + return m_vecDamageForce; +} + +inline void CTakeDamageInfo::SetDamageForce( const Vector &damageForce ) +{ + m_vecDamageForce = damageForce; +} + +inline void CTakeDamageInfo::ScaleDamageForce( float flScaleAmount ) +{ + m_vecDamageForce *= flScaleAmount; +} + +inline float CTakeDamageInfo::GetDamageForForceCalc() const +{ + return m_flDamageForForce; +} + +inline void CTakeDamageInfo::SetDamageForForceCalc( float flDamage ) +{ + m_flDamageForForce = flDamage; +} + +inline Vector CTakeDamageInfo::GetDamagePosition() const +{ + return m_vecDamagePosition; +} + + +inline void CTakeDamageInfo::SetDamagePosition( const Vector &damagePosition ) +{ + m_vecDamagePosition = damagePosition; +} + +inline Vector CTakeDamageInfo::GetReportedPosition() const +{ + return m_vecReportedPosition; +} + + +inline void CTakeDamageInfo::SetReportedPosition( const Vector &reportedPosition ) +{ + m_vecReportedPosition = reportedPosition; +} + + +inline void CTakeDamageInfo::SetDamageType( int bitsDamageType ) +{ + m_bitsDamageType = bitsDamageType; +} + +inline int CTakeDamageInfo::GetDamageType() const +{ + return m_bitsDamageType; +} + +inline void CTakeDamageInfo::AddDamageType( int bitsDamageType ) +{ + m_bitsDamageType |= bitsDamageType; +} + +inline int CTakeDamageInfo::GetDamageCustom() const +{ + return m_iDamageCustom; +} + +inline void CTakeDamageInfo::SetDamageCustom( int iDamageCustom ) +{ + m_iDamageCustom = iDamageCustom; +} + +inline int CTakeDamageInfo::GetDamageStats() const +{ + return m_iDamageCustom; +} + +inline void CTakeDamageInfo::SetDamageStats( int iDamageCustom ) +{ + m_iDamageCustom = iDamageCustom; +} + +inline int CTakeDamageInfo::GetAmmoType() const +{ + return m_iAmmoType; +} + +inline void CTakeDamageInfo::SetAmmoType( int iAmmoType ) +{ + m_iAmmoType = iAmmoType; +} + +inline void CTakeDamageInfo::CopyDamageToBaseDamage() +{ + m_flBaseDamage = m_flDamage; +} + + +// -------------------------------------------------------------------------------------------------- // +// Inlines. +// -------------------------------------------------------------------------------------------------- // +inline CBaseEntity *CMultiDamage::GetTarget() const +{ + return m_hTarget; +} + +inline void CMultiDamage::SetTarget( CBaseEntity *pTarget ) +{ + m_hTarget = pTarget; +} + + +#endif // TAKEDAMAGEINFO_H diff --git a/game/shared/teamplay_gamerules.h b/game/shared/teamplay_gamerules.h new file mode 100644 index 0000000..6be6082 --- /dev/null +++ b/game/shared/teamplay_gamerules.h @@ -0,0 +1,126 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEAMPLAY_GAMERULES_H +#define TEAMPLAY_GAMERULES_H +#pragma once + +#include "gamerules.h" +#include "multiplay_gamerules.h" + +#ifdef CLIENT_DLL + + #define CTeamplayRules C_TeamplayRules + +#else + + #include "takedamageinfo.h" + +#endif + + +// +// teamplay_gamerules.h +// + + +#define MAX_TEAMNAME_LENGTH 16 +#define MAX_TEAMS 32 + +#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH + + +class CTeamplayRules : public CMultiplayRules +{ +public: + DECLARE_CLASS( CTeamplayRules, CMultiplayRules ); + + // Return the value of this player towards capturing a point + virtual int GetCaptureValueForPlayer( CBasePlayer *pPlayer ) { return 1; } + virtual bool TeamMayCapturePoint( int iTeam, int iPointIndex ) { return true; } + virtual bool PlayerMayCapturePoint( CBasePlayer *pPlayer, int iPointIndex, char *pszReason = NULL, int iMaxReasonLength = 0 ) { return true; } + virtual bool PlayerMayBlockPoint( CBasePlayer *pPlayer, int iPointIndex, char *pszReason = NULL, int iMaxReasonLength = 0 ) { return false; } + + // Return false if players aren't allowed to cap points at this time (i.e. in WaitingForPlayers) + virtual bool PointsMayBeCaptured( void ) { return true; } + virtual void SetLastCapPointChanged( int iIndex ) { return; } + +#ifdef CLIENT_DLL + +#else + + CTeamplayRules(); + virtual ~CTeamplayRules() {}; + + virtual void Precache( void ); + + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + virtual void ClientSettingsChanged( CBasePlayer *pPlayer ); + virtual bool IsTeamplay( void ); + virtual bool FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker, const CTakeDamageInfo &info ); + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual bool PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker ); + virtual const char *GetTeamID( CBaseEntity *pEntity ); + virtual bool ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void InitHUD( CBasePlayer *pl ); + virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + virtual const char *GetGameDescription( void ) { return "Teamplay"; } // this is the game name that gets seen in the server browser + virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ); + virtual void Think ( void ); + virtual int GetTeamIndex( const char *pTeamName ); + virtual const char *GetIndexedTeamName( int teamIndex ); + virtual bool IsValidTeam( const char *pTeamName ); + virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, bool bKill, bool bGib ); + virtual void ClientDisconnected( edict_t *pClient ); + virtual bool TimerMayExpire( void ) { return true; } + + // A game has been won by the specified team + virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) { return; } + virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false ) { return; } + + // Used to determine if all players should switch teams + virtual void SetSwitchTeams( bool bSwitch ){ m_bSwitchTeams = bSwitch; } + virtual bool ShouldSwitchTeams( void ){ return m_bSwitchTeams; } + virtual void HandleSwitchTeams( void ){ return; } + + // Used to determine if we should scramble the teams + virtual void SetScrambleTeams( bool bScramble ){ m_bScrambleTeams = bScramble; } + virtual bool ShouldScrambleTeams( void ){ return m_bScrambleTeams; } + virtual void HandleScrambleTeams( void ){ return; } + + virtual bool PointsMayAlwaysBeBlocked(){ return false; } + +protected: + bool m_DisableDeathMessages; + +private: + void RecountTeams( void ); + const char *TeamWithFewestPlayers( void ); + + bool m_DisableDeathPenalty; + bool m_teamLimit; // This means the server set only some teams as valid + char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; + bool m_bSwitchTeams; + bool m_bScrambleTeams; + +#endif +}; + +inline CTeamplayRules* TeamplayGameRules() +{ + return static_cast(g_pGameRules); +} + +#endif // TEAMPLAY_GAMERULES_H diff --git a/game/shared/teamplay_round_timer.h b/game/shared/teamplay_round_timer.h new file mode 100644 index 0000000..df94a27 --- /dev/null +++ b/game/shared/teamplay_round_timer.h @@ -0,0 +1,175 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Round timer for team gamerules +// +//=============================================================================// + +#ifndef TEAM_ROUND_TIMER_H +#define TEAM_ROUND_TIMER_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef CLIENT_DLL +#define CTeamRoundTimer C_TeamRoundTimer +#endif + +class CTeamRoundTimer : public CBaseEntity +{ +public: + DECLARE_CLASS( CTeamRoundTimer, CBaseEntity ); + DECLARE_NETWORKCLASS(); + + CTeamRoundTimer(); + virtual ~CTeamRoundTimer(); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void Activate( void ); + + // Returns seconds to display. + // When paused shows amount of time left once the timer is resumed + virtual float GetTimeRemaining( void ); + virtual int GetTimerMaxLength( void ); + virtual bool ShowInHud( void ); + virtual bool StartPaused( void ){ return m_bStartPaused; } + bool ShowTimeRemaining( void ) { return m_bShowTimeRemaining; } + + bool IsDisabled( void ) { return m_bIsDisabled; } + int GetTimerState( void ){ return m_nState; } + + bool IsTimerPaused( void ) { return m_bTimerPaused; } + +#ifdef CLIENT_DLL + + void InternalSetPaused( bool bPaused ) { m_bTimerPaused = bPaused; } + +#else + + void SetStopWatchTimeStamp( void ); + virtual void SetTimeRemaining( int iTimerSeconds ); // Set the initial length of the timer + virtual void AddTimerSeconds( int iSecondsToAdd, int iTeamResponsible = TEAM_UNASSIGNED ); // Add time to an already running ( or paused ) timer + virtual void PauseTimer( void ); + virtual void ResumeTimer( void ); + virtual void SetAutoCountdown( bool bAuto ){ m_bAutoCountdown = bAuto; } + + void SetShowInHud( bool bShowInHUD ) { m_bShowInHUD = bShowInHUD; } + + int UpdateTransmitState(); + + void InputEnable( inputdata_t &input ); + void InputDisable( inputdata_t &input ); + void InputPause( inputdata_t &input ); + void InputResume( inputdata_t &input ); + void InputSetTime( inputdata_t &input ); + void InputAddTime( inputdata_t &input ); + void InputRestart( inputdata_t &input ); + void InputShowInHUD( inputdata_t &input ); + void InputRoundSpawn( inputdata_t &inputdata ); + void InputSetMaxTime( inputdata_t &input ); + void InputAutoCountdown( inputdata_t &input ); + void InputAddTeamTime( inputdata_t &input ); + void InputSetSetupTime( inputdata_t &input ); + +#endif + + void SetCaptureWatchState( bool bCaptureWatch ); + bool IsWatchingTimeStamps( void ) { return m_bInCaptureWatchState; } + void SetStopWatch( bool bState ) { m_bStopWatchTimer = bState; } + bool IsStopWatchTimer( void ) { return m_bStopWatchTimer; } + float GetStopWatchTotalTime( void ) { return m_flTotalTime; } + bool IsRoundMaxTimerSet( void ) { return m_nTimerMaxLength > 0; } + int GetTimerInitialLength( void ) { return m_nTimerInitialLength; } + +private: + void CalculateOutputMessages( void ); + +#ifdef CLIENT_DLL + virtual void ClientThink(); + void OnPreDataChanged( DataUpdateType_t updateType ); + void OnDataChanged( DataUpdateType_t updateType ); + void SendTimeWarning( int nWarning ); + const char *GetTimeWarningSound( int nWarning ); + +#else + void SetState( int nState, bool bFireOutput = true ); + void SetTimerThink( int nType ); + void EXPORT RoundTimerThink( void ); + void EXPORT RoundTimerSetupThink( void ); + + static void SetActiveTimer( CTeamRoundTimer *pNewlyActive ); +#endif + +private: + CNetworkVar( bool, m_bTimerPaused ); + CNetworkVar( float, m_flTimeRemaining ); + CNetworkVar( float, m_flTimerEndTime ); + CNetworkVar( bool, m_bIsDisabled ); + CNetworkVar( bool, m_bShowInHUD ); + CNetworkVar( int, m_nTimerLength ); // current timer's length (used in the timer panel if no max length is set) + CNetworkVar( int, m_nTimerInitialLength ); // initial length of the timer + CNetworkVar( int, m_nTimerMaxLength ); // max time the timer can have (0 is no max) + CNetworkVar( bool, m_bAutoCountdown ); // automatically count down the end of a round + CNetworkVar( int, m_nSetupTimeLength ); // current timer's setup time length (setup time is the time before the round begins) + CNetworkVar( int, m_nState ); // RT_STATE_SETUP or RT_STATE_NORMAL + CNetworkVar( bool, m_bStartPaused ); // start the timer paused when it spawns + CNetworkVar( bool, m_bShowTimeRemaining ); //show how much time is left (default) instead of how much time has passed. + CNetworkVar( bool, m_bInCaptureWatchState ); + CNetworkVar( float, m_flTotalTime ); + CNetworkVar( bool, m_bStopWatchTimer ); + + bool m_bFireFinished; + bool m_bFire5MinRemain; + bool m_bFire4MinRemain; + bool m_bFire3MinRemain; + bool m_bFire2MinRemain; + bool m_bFire1MinRemain; + bool m_bFire30SecRemain; + bool m_bFire10SecRemain; + bool m_bFire5SecRemain; + bool m_bFire4SecRemain; + bool m_bFire3SecRemain; + bool m_bFire2SecRemain; + bool m_bFire1SecRemain; + +#ifdef CLIENT_DLL + + int m_nOldTimerLength; + int m_nOldTimerState; + +#else + COutputEvent m_OnRoundStart; + COutputEvent m_OnFinished; + COutputEvent m_On5MinRemain; + COutputEvent m_On4MinRemain; + COutputEvent m_On3MinRemain; + COutputEvent m_On2MinRemain; + COutputEvent m_On1MinRemain; + COutputEvent m_On30SecRemain; + COutputEvent m_On10SecRemain; + COutputEvent m_On5SecRemain; + COutputEvent m_On4SecRemain; + COutputEvent m_On3SecRemain; + COutputEvent m_On2SecRemain; + COutputEvent m_On1SecRemain; + + COutputEvent m_OnSetupStart; + COutputEvent m_OnSetupFinished; + + float m_flNextOvertimeNag; + float m_flLastTime; + + DECLARE_DATADESC(); + + bool m_bPauseDueToWin; + bool m_bResetTimeOnRoundStart; + int m_nTimeToUseAfterSetupFinished; +#endif +}; + +#ifdef CLIENT_DLL +extern CTeamRoundTimer *g_TeamRoundTimer; +#endif + +#endif //TEAM_ROUND_TIMER_H \ No newline at end of file diff --git a/game/shared/teamplayroundbased_gamerules.h b/game/shared/teamplayroundbased_gamerules.h new file mode 100644 index 0000000..95060d3 --- /dev/null +++ b/game/shared/teamplayroundbased_gamerules.h @@ -0,0 +1,615 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Teamplay game rules that manage a round based structure for you +// +//============================================================================= + +#ifndef TEAMPLAYROUNDBASED_GAMERULES_H +#define TEAMPLAYROUNDBASED_GAMERULES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "teamplay_gamerules.h" +#include "teamplay_round_timer.h" +#include "GameEventListener.h" + +#ifdef GAME_DLL +#include "team_control_point.h" + extern ConVar mp_respawnwavetime; + extern ConVar mp_showroundtransitions; + extern ConVar mp_enableroundwaittime; + extern ConVar mp_showcleanedupents; + extern ConVar mp_bonusroundtime; + extern ConVar mp_restartround; + extern ConVar mp_winlimit; + extern ConVar mp_maxrounds; + extern ConVar mp_stalemate_timelimit; + extern ConVar mp_stalemate_enable; +#else + #define CTeamplayRoundBasedRules C_TeamplayRoundBasedRules + #define CTeamplayRoundBasedRulesProxy C_TeamplayRoundBasedRulesProxy +#endif + +extern ConVar tf_arena_use_queue; +extern ConVar mp_stalemate_meleeonly; +extern ConVar mp_forceautoteam; + +class CTeamplayRoundBasedRules; + +//----------------------------------------------------------------------------- +// Round states +//----------------------------------------------------------------------------- +enum gamerules_roundstate_t +{ + // initialize the game, create teams + GR_STATE_INIT = 0, + + //Before players have joined the game. Periodically checks to see if enough players are ready + //to start a game. Also reverts to this when there are no active players + GR_STATE_PREGAME, + + //The game is about to start, wait a bit and spawn everyone + GR_STATE_STARTGAME, + + //All players are respawned, frozen in place + GR_STATE_PREROUND, + + //Round is on, playing normally + GR_STATE_RND_RUNNING, + + //Someone has won the round + GR_STATE_TEAM_WIN, + + //Noone has won, manually restart the game, reset scores + GR_STATE_RESTART, + + //Noone has won, restart the game + GR_STATE_STALEMATE, + + //Game is over, showing the scoreboard etc + GR_STATE_GAME_OVER, + + //Game is in a bonus state, transitioned to after a round ends + GR_STATE_BONUS, + + //Game is awaiting the next wave/round of a multi round experience + GR_STATE_BETWEEN_RNDS, + + GR_NUM_ROUND_STATES +}; + +enum { + WINREASON_NONE =0, + WINREASON_ALL_POINTS_CAPTURED, + WINREASON_OPPONENTS_DEAD, + WINREASON_FLAG_CAPTURE_LIMIT, + WINREASON_DEFEND_UNTIL_TIME_LIMIT, + WINREASON_STALEMATE, + WINREASON_TIMELIMIT, + WINREASON_WINLIMIT, + WINREASON_WINDIFFLIMIT, +#if defined(TF_CLIENT_DLL) || defined(TF_DLL) + WINREASON_RD_REACTOR_CAPTURED, + WINREASON_RD_CORES_COLLECTED, + WINREASON_RD_REACTOR_RETURNED, +#endif +}; + +enum stalemate_reasons_t +{ + STALEMATE_JOIN_MID, + STALEMATE_TIMER, + STALEMATE_SERVER_TIMELIMIT, + + NUM_STALEMATE_REASONS, +}; + + +#if defined(TF_CLIENT_DLL) || defined(TF_DLL) + +/// Info about a player in a PVE game or any other mode that we +/// might eventually decide to use the lobby system for. +struct LobbyPlayerInfo_t +{ + int m_nEntNum; //< Index of player (1...MAX_PLAYERS), or 0 if the guy is in the lobby but not yet known to us + CUtlString m_sPlayerName; //< Player display name + CSteamID m_steamID; //< Steam ID of the player + int m_iTeam; //< Team selection. + bool m_bInLobby; //< Is this guy in the lobby? + bool m_bConnected; //< Is this a bot? + bool m_bBot; //< Is this a bot? + bool m_bSquadSurplus; //< Did he present a voucher to get surplus for his squad +}; + +#endif + +//----------------------------------------------------------------------------- +// Purpose: Per-state data +//----------------------------------------------------------------------------- +class CGameRulesRoundStateInfo +{ +public: + gamerules_roundstate_t m_iRoundState; + const char *m_pStateName; + + void (CTeamplayRoundBasedRules::*pfnEnterState)(); // Init and deinit the state. + void (CTeamplayRoundBasedRules::*pfnLeaveState)(); + void (CTeamplayRoundBasedRules::*pfnThink)(); // Do a PreThink() in this state. +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTeamplayRoundBasedRulesProxy : public CGameRulesProxy +{ +public: + DECLARE_CLASS( CTeamplayRoundBasedRulesProxy, CGameRulesProxy ); + DECLARE_NETWORKCLASS(); + +#ifdef GAME_DLL + DECLARE_DATADESC(); + void InputSetStalemateOnTimelimit( inputdata_t &inputdata ); +#endif + + //---------------------------------------------------------------------------------- + // Client specific +#ifdef CLIENT_DLL + void OnPreDataChanged( DataUpdateType_t updateType ); + void OnDataChanged( DataUpdateType_t updateType ); +#endif // CLIENT_DLL +}; + +//----------------------------------------------------------------------------- +// Purpose: Teamplay game rules that manage a round based structure for you +//----------------------------------------------------------------------------- +class CTeamplayRoundBasedRules : public CTeamplayRules, public CGameEventListener +{ + DECLARE_CLASS( CTeamplayRoundBasedRules, CTeamplayRules ); +public: + CTeamplayRoundBasedRules(); + +#ifdef CLIENT_DLL + DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars. + + void SetRoundState( int iRoundState ); +#else + DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars. +#endif + + float GetLastRoundStateChangeTime( void ) const { return m_flLastRoundStateChangeTime; } + float m_flLastRoundStateChangeTime; + + // Data accessors + inline gamerules_roundstate_t State_Get( void ) { return m_iRoundState; } + bool IsInWaitingForPlayers( void ) { return m_bInWaitingForPlayers; } + virtual bool InRoundRestart( void ) { return State_Get() == GR_STATE_PREROUND; } + bool InStalemate( void ) { return State_Get() == GR_STATE_STALEMATE; } + bool RoundHasBeenWon( void ) { return State_Get() == GR_STATE_TEAM_WIN; } + + virtual float GetNextRespawnWave( int iTeam, CBasePlayer *pPlayer ); + virtual bool HasPassedMinRespawnTime( CBasePlayer *pPlayer ); + virtual void LevelInitPostEntity( void ); + virtual float GetRespawnTimeScalar( int iTeam ); + virtual float GetRespawnWaveMaxLength( int iTeam, bool bScaleWithNumPlayers = true ); + virtual bool ShouldRespawnQuickly( CBasePlayer *pPlayer ) { return false; } + float GetMinTimeWhenPlayerMaySpawn( CBasePlayer *pPlayer ); + + // Return false if players aren't allowed to cap points at this time (i.e. in WaitingForPlayers) + virtual bool PointsMayBeCaptured( void ) { return ((State_Get() == GR_STATE_RND_RUNNING || State_Get() == GR_STATE_STALEMATE) && !IsInWaitingForPlayers()); } + virtual void SetLastCapPointChanged( int iIndex ) { m_iLastCapPointChanged = iIndex; } + int GetLastCapPointChanged( void ) { return m_iLastCapPointChanged; } + + virtual int GetWinningTeam( void ){ return m_iWinningTeam; } + int GetWinReason() { return m_iWinReason; } + + bool InOvertime( void ){ return m_bInOvertime; } + void SetOvertime( bool bOvertime ); + + bool InSetup( void ){ return m_bInSetup; } + + void BalanceTeams( bool bRequireSwitcheesToBeDead ); + + bool SwitchedTeamsThisRound( void ) { return m_bSwitchedTeamsThisRound; } + + virtual bool ShouldBalanceTeams( void ); + bool IsInTournamentMode( void ); + bool IsInHighlanderMode( void ); + bool IsInPreMatch( void ) { return (IsInTournamentMode() && IsInWaitingForPlayers()); } + bool IsWaitingForTeams( void ) { return m_bAwaitingReadyRestart; } + bool IsInStopWatch( void ) { return m_bStopWatch; } + void SetInStopWatch( bool bState ) { m_bStopWatch = bState; } + virtual void StopWatchModeThink( void ) { }; + + bool IsTeamReady( int iTeamNumber ) + { + return m_bTeamReady[iTeamNumber]; + } + + bool IsPlayerReady( int iIndex ) + { + return m_bPlayerReady[iIndex]; + } + + virtual void HandleTeamScoreModify( int iTeam, int iScore) { }; + + + float GetRoundRestartTime( void ) { return m_flRestartRoundTime; } + + //Arena Mode + virtual bool IsInArenaMode( void ) { return false; } + + //Koth Mode + virtual bool IsInKothMode( void ) { return false; } + + //Training Mode + virtual bool IsInTraining( void ) { return false; } + virtual bool IsInItemTestingMode( void ) { return false; } + + void SetMultipleTrains( bool bMultipleTrains ){ m_bMultipleTrains = bMultipleTrains; } + bool HasMultipleTrains( void ){ return m_bMultipleTrains; } + + virtual int GetBonusRoundTime( bool bFinal = false ); + +#if defined(TF_CLIENT_DLL) || defined(TF_DLL) + + // Get list of all the players, including those in the lobby but who have + // not yet joined. + void GetAllPlayersLobbyInfo( CUtlVector &vecPlayers, bool bIncludeBots = false ); + + // Get list of players who are on the defending team now, or are likely + // to end up on the defending team (not yet connected or assigned a team) + void GetPotentialPlayersLobbyPlayerInfo( CUtlVector &vecLobbyPlayers, bool bIncludeBots = false ); + +#endif + + void SetAllowBetweenRounds( bool bValue ) { m_bAllowBetweenRounds = bValue; } + +public: // IGameEventListener Interface + virtual void FireGameEvent( IGameEvent * event ); + + //---------------------------------------------------------------------------------- + // Server specific +#ifdef GAME_DLL + // Derived game rules class should override these +public: + // Override this to prevent removal of game specific entities that need to persist + virtual bool RoundCleanupShouldIgnore( CBaseEntity *pEnt ); + virtual bool ShouldCreateEntity( const char *pszClassName ); + + // Called when a new round is being initialized + virtual void SetupOnRoundStart( void ) { return; } + + // Called when a new round is off and running + virtual void SetupOnRoundRunning( void ) { return; } + + // Called before a new round is started (so the previous round can end) + virtual void PreviousRoundEnd( void ) { return; } + + // Send the team scores down to the client + virtual void SendTeamScoresEvent( void ) { return; } + + // Send the end of round info displayed in the win panel + virtual void SendWinPanelInfo( void ) { return; } + + // Setup spawn points for the current round before it starts + virtual void SetupSpawnPointsForRound( void ) { return; } + + // Called when a round has entered stalemate mode (timer has run out) + virtual void SetupOnStalemateStart( void ) { return; } + virtual void SetupOnStalemateEnd( void ) { return; } + virtual void SetSetup( bool bSetup ); + + virtual bool ShouldGoToBonusRound( void ) { return false; } + virtual void SetupOnBonusStart( void ) { return; } + virtual void SetupOnBonusEnd( void ) { return; } + virtual void BonusStateThink( void ) { return; } + + virtual void BetweenRounds_Start( void ) { return; } + virtual void BetweenRounds_End( void ) { return; } + virtual void BetweenRounds_Think( void ) { return; } + + virtual void PreRound_End( void ) { return; } + + bool PrevRoundWasWaitingForPlayers() { return m_bPrevRoundWasWaitingForPlayers; } + + virtual bool ShouldScorePerRound( void ){ return true; } + + bool CheckNextLevelCvar( bool bAllowEnd = true ); + + virtual bool TimerMayExpire( void ); + + virtual bool IsValveMap( void ){ return false; } + + virtual void RestartTournament( void ); + + virtual bool TournamentModeCanEndWithTimelimit( void ){ return true; } + +public: + void State_Transition( gamerules_roundstate_t newState ); + + void RespawnPlayers( bool bForceRespawn, bool bTeam = false, int iTeam = TEAM_UNASSIGNED ); + + void SetForceMapReset( bool reset ); + + void SetRoundToPlayNext( string_t strName ){ m_iszRoundToPlayNext = strName; } + string_t GetRoundToPlayNext( void ){ return m_iszRoundToPlayNext; } + void AddPlayedRound( string_t strName ); + bool IsPreviouslyPlayedRound ( string_t strName ); + string_t GetLastPlayedRound( void ); + + virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) OVERRIDE; + virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false ); + + virtual void SetRoundOverlayDetails( void ){ return; } + + virtual float GetWaitingForPlayersTime( void ) { return mp_waitingforplayers_time.GetFloat(); } + void ShouldResetScores( bool bResetTeam, bool bResetPlayer ){ m_bResetTeamScores = bResetTeam; m_bResetPlayerScores = bResetPlayer; } + void ShouldResetRoundsPlayed( bool bResetRoundsPlayed ){ m_bResetRoundsPlayed = bResetRoundsPlayed; } + + void SetFirstRoundPlayed( string_t strName ){ m_iszFirstRoundPlayed = strName ; } + string_t GetFirstRoundPlayed(){ return m_iszFirstRoundPlayed; } + + void SetTeamRespawnWaveTime( int iTeam, float flValue ); + void AddTeamRespawnWaveTime( int iTeam, float flValue ); + virtual void FillOutTeamplayRoundWinEvent( IGameEvent *event ) {} // derived classes may implement to add fields to this event + + void SetStalemateOnTimelimit( bool bStalemate ) { m_bAllowStalemateAtTimelimit = bStalemate; } + + bool IsGameUnderTimeLimit( void ); + + CTeamRoundTimer *GetActiveRoundTimer( void ); + + void HandleTimeLimitChange( void ); + + void SetTeamReadyState( bool bState, int iTeam ) + { + m_bTeamReady.Set( iTeam, bState ); + } + + void SetPlayerReadyState( int iIndex, bool bState ) + { + m_bPlayerReady.Set( iIndex, bState ); + } + void ResetPlayerAndTeamReadyState( void ); + + virtual void PlayTrainCaptureAlert( CTeamControlPoint *pPoint, bool bFinalPointInMap ){ return; } + + virtual void PlaySpecialCapSounds( int iCappingTeam, CTeamControlPoint *pPoint ){ return; } + + bool PlayThrottledAlert( int iTeam, const char *sound, float fDelayBeforeNext ); + + void BroadcastSound( int iTeam, const char *sound, int iAdditionalSoundFlags = 0 ); + int GetRoundsPlayed( void ) { return m_nRoundsPlayed; } + + virtual void RecalculateControlPointState( void ){ return; } + + virtual bool ShouldSkipAutoScramble( void ){ return false; } + + virtual bool ShouldWaitToStartRecording( void ){ return IsInWaitingForPlayers(); } + +protected: + virtual void Think( void ); + + virtual void CheckChatText( CBasePlayer *pPlayer, char *pText ); + void CheckChatForReadySignal( CBasePlayer *pPlayer, const char *chatmsg ); + + // Game beginning / end handling + virtual void GoToIntermission( void ); + void SetInWaitingForPlayers( bool bWaitingForPlayers ); + void CheckWaitingForPlayers( void ); + virtual bool AllowWaitingForPlayers( void ) { return true; } + void CheckRestartRound( void ); + bool CheckTimeLimit( bool bAllowEnd = true ); + int GetTimeLeft( void ); + virtual bool CheckWinLimit( bool bAllowEnd = true ); + bool CheckMaxRounds( bool bAllowEnd = true ); + + void CheckReadyRestart( void ); +#if defined(TF_CLIENT_DLL) || defined(TF_DLL) + bool AreLobbyPlayersOnTeamReady( int iTeam ); + bool AreLobbyPlayersConnected( void ); +#endif + + virtual bool CanChangelevelBecauseOfTimeLimit( void ) { return true; } + virtual bool CanGoToStalemate( void ) { return true; } + + // State machine handling + void State_Enter( gamerules_roundstate_t newState ); // Initialize the new state. + void State_Leave(); // Cleanup the previous state. + void State_Think(); // Update the current state. + static CGameRulesRoundStateInfo* State_LookupInfo( gamerules_roundstate_t state ); // Find the state info for the specified state. + + // State Functions + void State_Enter_INIT( void ); + void State_Think_INIT( void ); + + void State_Enter_PREGAME( void ); + void State_Think_PREGAME( void ); + + void State_Enter_STARTGAME( void ); + void State_Think_STARTGAME( void ); + + void State_Enter_PREROUND( void ); + void State_Leave_PREROUND( void ); + void State_Think_PREROUND( void ); + + void State_Enter_RND_RUNNING( void ); + void State_Think_RND_RUNNING( void ); + + void State_Enter_TEAM_WIN( void ); + void State_Think_TEAM_WIN( void ); + + void State_Enter_RESTART( void ); + void State_Think_RESTART( void ); + + void State_Enter_STALEMATE( void ); + void State_Think_STALEMATE( void ); + void State_Leave_STALEMATE( void ); + + void State_Enter_BONUS( void ); + void State_Think_BONUS( void ); + void State_Leave_BONUS( void ); + + void State_Enter_BETWEEN_RNDS( void ); + void State_Leave_BETWEEN_RNDS( void ); + void State_Think_BETWEEN_RNDS( void ); + + // mp_scrambleteams_auto + void ResetTeamsRoundWinTracking( void ); + +protected: + virtual void InitTeams( void ); + virtual int CountActivePlayers( void ); + + virtual void RoundRespawn( void ); + virtual void CleanUpMap( void ); + virtual void CheckRespawnWaves( void ); + void ResetScores( void ); + void ResetMapTime( void ); + + void PlayStartRoundVoice( void ); + void PlayWinSong( int team ); + void PlayStalemateSong( void ); + void PlaySuddenDeathSong( void ); + + virtual const char* GetStalemateSong( int nTeam ) { return "Game.Stalemate"; } + virtual const char* WinSongName( int nTeam ) { return "Game.YourTeamWon"; } + virtual const char* LoseSongName( int nTeam ) { return "Game.YourTeamLost"; } + + virtual void RespawnTeam( int iTeam ) { RespawnPlayers( false, true, iTeam ); } + + void HideActiveTimer( void ); + virtual void RestoreActiveTimer( void ); + + virtual void InternalHandleTeamWin( int iWinningTeam ){ return; } + + bool MapHasActiveTimer( void ); + void CreateTimeLimitTimer( void ); + + virtual float GetLastMajorEventTime( void ) OVERRIDE { return m_flLastTeamWin; } + +protected: + CGameRulesRoundStateInfo *m_pCurStateInfo; // Per-state data + float m_flStateTransitionTime; // Timer for round states + + float m_flWaitingForPlayersTimeEnds; + CHandle m_hWaitingForPlayersTimer; + + float m_flNextPeriodicThink; + bool m_bChangeLevelOnRoundEnd; + + bool m_bResetTeamScores; + bool m_bResetPlayerScores; + bool m_bResetRoundsPlayed; + + // Stalemate + EHANDLE m_hPreviousActiveTimer; + CHandle m_hStalemateTimer; + float m_flStalemateStartTime; + + CHandle m_hTimeLimitTimer; + + bool m_bForceMapReset; // should the map be reset when a team wins and the round is restarted? + bool m_bPrevRoundWasWaitingForPlayers; // was the previous map reset after a waiting for players period + bool m_bInitialSpawn; + + string_t m_iszRoundToPlayNext; + CUtlVector m_iszPreviousRounds; // we'll store the two previous rounds so we won't play them again right away if there are other rounds that can be played first + string_t m_iszFirstRoundPlayed; // store the first round played after a full restart so we can pick a different one next time if we have other options + + float m_flOriginalTeamRespawnWaveTime[ MAX_TEAMS ]; + + bool m_bAllowStalemateAtTimelimit; + bool m_bChangelevelAfterStalemate; + + float m_flRoundStartTime; // time the current round started + float m_flNewThrottledAlertTime; // time that we can play another throttled alert + + int m_nRoundsPlayed; + bool m_bUseAddScoreAnim; + + gamerules_roundstate_t m_prevState; + + bool m_bPlayerReadyBefore[MAX_PLAYERS+1]; // Test to see if a player has hit ready before + + float m_flLastTeamWin; + +private: + + CUtlMap < int, int > m_GameTeams; // Team index, Score +#endif + // End server specific + //---------------------------------------------------------------------------------- + + //---------------------------------------------------------------------------------- + // Client specific +#ifdef CLIENT_DLL +public: + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void HandleOvertimeBegin(){} + virtual void GetTeamGlowColor( int nTeam, float &r, float &g, float &b ){ r = 0.76f; g = 0.76f; b = 0.76f; } + +private: + bool m_bOldInWaitingForPlayers; + bool m_bOldInOvertime; + bool m_bOldInSetup; +#endif // CLIENT_DLL + +public: + bool WouldChangeUnbalanceTeams( int iNewTeam, int iCurrentTeam ); + bool AreTeamsUnbalanced( int &iHeaviestTeam, int &iLightestTeam ); + virtual bool HaveCheatsBeenEnabledDuringLevel( void ) { return m_bCheatsEnabledDuringLevel; } + +protected: + CNetworkVar( gamerules_roundstate_t, m_iRoundState ); + CNetworkVar( bool, m_bInOvertime ); // Are we currently in overtime? + CNetworkVar( bool, m_bInSetup ); // Are we currently in setup? + CNetworkVar( bool, m_bSwitchedTeamsThisRound ); + +protected: + CNetworkVar( int, m_iWinningTeam ); // Set before entering GR_STATE_TEAM_WIN + CNetworkVar( int, m_iWinReason ); + CNetworkVar( bool, m_bInWaitingForPlayers ); + CNetworkVar( bool, m_bAwaitingReadyRestart ); + CNetworkVar( float, m_flRestartRoundTime ); + CNetworkVar( float, m_flMapResetTime ); // Time that the map was reset + CNetworkArray( float, m_flNextRespawnWave, MAX_TEAMS ); // Minor waste, but cleaner code + CNetworkArray( bool, m_bTeamReady, MAX_TEAMS ); + CNetworkVar( bool, m_bStopWatch ); + CNetworkVar( bool, m_bMultipleTrains ); // two trains in this map? + CNetworkArray( bool, m_bPlayerReady, MAX_PLAYERS ); + CNetworkVar( bool, m_bCheatsEnabledDuringLevel ); + +public: + CNetworkArray( float, m_TeamRespawnWaveTimes, MAX_TEAMS ); // Time between each team's respawn wave + +private: + float m_flStartBalancingTeamsAt; + float m_flNextBalanceTeamsTime; + bool m_bPrintedUnbalanceWarning; + float m_flFoundUnbalancedTeamsTime; + + float m_flAutoBalanceQueueTimeEnd; + int m_nAutoBalanceQueuePlayerIndex; + int m_nAutoBalanceQueuePlayerScore; + +protected: + bool m_bAllowBetweenRounds; + +public: + + float m_flStopWatchTotalTime; + int m_iLastCapPointChanged; +}; + +// Utility function +bool FindInList( const char **pStrings, const char *pToFind ); + +inline CTeamplayRoundBasedRules* TeamplayRoundBasedRules() +{ + return static_cast(g_pGameRules); +} + +#endif // TEAMPLAYROUNDBASED_GAMERULES_H diff --git a/game/shared/tempentity.h b/game/shared/tempentity.h new file mode 100644 index 0000000..cc7e96a --- /dev/null +++ b/game/shared/tempentity.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TEMPENTITY_H +#define TEMPENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#define TE_EXPLFLAG_NONE 0x0 // all flags clear makes default Half-Life explosion +#define TE_EXPLFLAG_NOADDITIVE 0x1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) +#define TE_EXPLFLAG_NODLIGHTS 0x2 // do not render dynamic lights +#define TE_EXPLFLAG_NOSOUND 0x4 // do not play client explosion sound +#define TE_EXPLFLAG_NOPARTICLES 0x8 // do not draw particles +#define TE_EXPLFLAG_DRAWALPHA 0x10 // sprite will be drawn alpha +#define TE_EXPLFLAG_ROTATE 0x20 // rotate the sprite randomly +#define TE_EXPLFLAG_NOFIREBALL 0x40 // do not draw a fireball +#define TE_EXPLFLAG_NOFIREBALLSMOKE 0x80 // do not draw smoke with the fireball + +#define TE_BEAMPOINTS 0 // beam effect between two points +#define TE_SPRITE 1 // additive sprite, plays 1 cycle +#define TE_BEAMDISK 2 // disk that expands to max radius over lifetime +#define TE_BEAMCYLINDER 3 // cylinder that expands to max radius over lifetime +#define TE_BEAMFOLLOW 4 // create a line of decaying beam segments until entity stops moving +#define TE_BEAMRING 5 // connect a beam ring to two entities +#define TE_BEAMSPLINE 6 +#define TE_BEAMRINGPOINT 7 +#define TE_BEAMLASER 8 // Fades according to viewpoint +#define TE_BEAMTESLA 9 + + +#endif // TEMPENTITY_H diff --git a/game/shared/touchlink.h b/game/shared/touchlink.h new file mode 100644 index 0000000..5bb115d --- /dev/null +++ b/game/shared/touchlink.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared data definition file for touch links +// +//=============================================================================// + +#ifndef TOUCHLINK_H +#define TOUCHLINK_H +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Purpose: for resolving touch/untouch pairs +//----------------------------------------------------------------------------- +enum touchlink_flags_t +{ + FTOUCHLINK_START_TOUCH = 0x00000001, +}; + +struct touchlink_t +{ +#if defined( CLIENT_DLL ) + C_BaseEntity *entityTouched; +#else + EHANDLE entityTouched; +#endif + int touchStamp; + touchlink_t *nextLink; + touchlink_t *prevLink; + int flags; +}; + +// means this touchlink is managed external to the main physics system +#define TOUCHSTAMP_EVENT_DRIVEN -1 + + +#endif // TOUCHLINK_H diff --git a/game/shared/triggers_shared.h b/game/shared/triggers_shared.h new file mode 100644 index 0000000..1467ae9 --- /dev/null +++ b/game/shared/triggers_shared.h @@ -0,0 +1,33 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef TRIGGERS_SHARED_H +#define TRIGGERS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +// +// Spawnflags +// +enum +{ + SF_TRIGGER_ALLOW_CLIENTS = 0x01, // Players can fire this trigger + SF_TRIGGER_ALLOW_NPCS = 0x02, // NPCS can fire this trigger + SF_TRIGGER_ALLOW_PUSHABLES = 0x04, // Pushables can fire this trigger + SF_TRIGGER_ALLOW_PHYSICS = 0x08, // Physics objects can fire this trigger + SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS = 0x10, // *if* NPCs can fire this trigger, this flag means only player allies do so + SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES = 0x20, // *if* Players can fire this trigger, this flag means only players inside vehicles can + SF_TRIGGER_ALLOW_ALL = 0x40, // Everything can fire this trigger EXCEPT DEBRIS! + SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES = 0x200, // *if* Players can fire this trigger, this flag means only players outside vehicles can + SF_TRIG_PUSH_ONCE = 0x80, // trigger_push removes itself after firing once + SF_TRIG_PUSH_AFFECT_PLAYER_ON_LADDER = 0x100, // if pushed object is player on a ladder, then this disengages them from the ladder (HL2only) + SF_TRIG_TOUCH_DEBRIS = 0x400, // Will touch physics debris objects + SF_TRIGGER_ONLY_NPCS_IN_VEHICLES = 0X800, // *if* NPCs can fire this trigger, only NPCs in vehicles do so (respects player ally flag too) + SF_TRIGGER_DISALLOW_BOTS = 0x1000, // Bots are not allowed to fire this trigger +}; + +#endif // TRIGGERS_SHARED_H diff --git a/game/shared/usercmd.h b/game/shared/usercmd.h new file mode 100644 index 0000000..0005bde --- /dev/null +++ b/game/shared/usercmd.h @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( USERCMD_H ) +#define USERCMD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "utlvector.h" +#include "imovehelper.h" +#include "checksum_crc.h" + + +class bf_read; +class bf_write; + +class CEntityGroundContact +{ +public: + int entindex; + float minheight; + float maxheight; +}; + +class CUserCmd +{ +public: + CUserCmd() + { + Reset(); + } + + virtual ~CUserCmd() { }; + + void Reset() + { + command_number = 0; + tick_count = 0; + viewangles.Init(); + forwardmove = 0.0f; + sidemove = 0.0f; + upmove = 0.0f; + buttons = 0; + impulse = 0; + weaponselect = 0; + weaponsubtype = 0; + random_seed = 0; +#ifdef GAME_DLL + server_random_seed = 0; +#endif + mousedx = 0; + mousedy = 0; + + hasbeenpredicted = false; +#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) + entitygroundcontact.RemoveAll(); +#endif + } + + CUserCmd& operator =( const CUserCmd& src ) + { + if ( this == &src ) + return *this; + + command_number = src.command_number; + tick_count = src.tick_count; + viewangles = src.viewangles; + forwardmove = src.forwardmove; + sidemove = src.sidemove; + upmove = src.upmove; + buttons = src.buttons; + impulse = src.impulse; + weaponselect = src.weaponselect; + weaponsubtype = src.weaponsubtype; + random_seed = src.random_seed; +#ifdef GAME_DLL + server_random_seed = src.server_random_seed; +#endif + mousedx = src.mousedx; + mousedy = src.mousedy; + + hasbeenpredicted = src.hasbeenpredicted; + +#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) + entitygroundcontact = src.entitygroundcontact; +#endif + + return *this; + } + + CUserCmd( const CUserCmd& src ) + { + *this = src; + } + + CRC32_t GetChecksum( void ) const + { + CRC32_t crc; + + CRC32_Init( &crc ); + CRC32_ProcessBuffer( &crc, &command_number, sizeof( command_number ) ); + CRC32_ProcessBuffer( &crc, &tick_count, sizeof( tick_count ) ); + CRC32_ProcessBuffer( &crc, &viewangles, sizeof( viewangles ) ); + CRC32_ProcessBuffer( &crc, &forwardmove, sizeof( forwardmove ) ); + CRC32_ProcessBuffer( &crc, &sidemove, sizeof( sidemove ) ); + CRC32_ProcessBuffer( &crc, &upmove, sizeof( upmove ) ); + CRC32_ProcessBuffer( &crc, &buttons, sizeof( buttons ) ); + CRC32_ProcessBuffer( &crc, &impulse, sizeof( impulse ) ); + CRC32_ProcessBuffer( &crc, &weaponselect, sizeof( weaponselect ) ); + CRC32_ProcessBuffer( &crc, &weaponsubtype, sizeof( weaponsubtype ) ); + CRC32_ProcessBuffer( &crc, &random_seed, sizeof( random_seed ) ); + CRC32_ProcessBuffer( &crc, &mousedx, sizeof( mousedx ) ); + CRC32_ProcessBuffer( &crc, &mousedy, sizeof( mousedy ) ); + CRC32_Final( &crc ); + + return crc; + } + + // Allow command, but negate gameplay-affecting values + void MakeInert( void ) + { + viewangles = vec3_angle; + forwardmove = 0.f; + sidemove = 0.f; + upmove = 0.f; + buttons = 0; + impulse = 0; + } + + // For matching server and client commands for debugging + int command_number; + + // the tick the client created this command + int tick_count; + + // Player instantaneous view angles. + QAngle viewangles; + // Intended velocities + // forward velocity. + float forwardmove; + // sideways velocity. + float sidemove; + // upward velocity. + float upmove; + // Attack button states + int buttons; + // Impulse command issued. + byte impulse; + // Current weapon id + int weaponselect; + int weaponsubtype; + + int random_seed; // For shared random functions +#ifdef GAME_DLL + int server_random_seed; // Only the server populates this seed +#endif + + short mousedx; // mouse accum in x from create move + short mousedy; // mouse accum in y from create move + + // Client only, tracks whether we've predicted this command at least once + bool hasbeenpredicted; + + // Back channel to communicate IK state +#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) + CUtlVector< CEntityGroundContact > entitygroundcontact; +#endif + +}; + +void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ); +void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ); + +#endif // USERCMD_H diff --git a/game/shared/usermessages.h b/game/shared/usermessages.h new file mode 100644 index 0000000..16a3279 --- /dev/null +++ b/game/shared/usermessages.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef USERMESSAGES_H +#define USERMESSAGES_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + + +// Client dispatch function for usermessages +typedef void (*pfnUserMsgHook)(bf_read &msg); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CUserMessage +{ + public: + // byte size of message, or -1 for variable sized + int size; + const char *name; + // Client only dispatch function for message + CUtlVector clienthooks; +}; + +//----------------------------------------------------------------------------- +// Purpose: Interface for registering and dispatching usermessages +// Shred code creates same ordered list on client/server +//----------------------------------------------------------------------------- +class CUserMessages +{ +public: + + CUserMessages(); + ~CUserMessages(); + + // Returns -1 if not found, otherwise, returns appropriate index + int LookupUserMessage( const char *name ); + int GetUserMessageSize( int index ); + const char *GetUserMessageName( int index ); + bool IsValidIndex( int index ); + + // Server only + void Register( const char *name, int size ); + + // Client only + void HookMessage( const char *name, pfnUserMsgHook hook ); + bool DispatchUserMessage( int msg_type, bf_read &msg_data ); + +private: + + CUtlDict< CUserMessage*, int > m_UserMessages; +}; + +extern CUserMessages *usermessages; + +#endif // USERMESSAGES_H diff --git a/game/shared/util_shared.h b/game/shared/util_shared.h new file mode 100644 index 0000000..8379341 --- /dev/null +++ b/game/shared/util_shared.h @@ -0,0 +1,626 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared util code between client and server. +// +//=============================================================================// + +#ifndef UTIL_SHARED_H +#define UTIL_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "cmodel.h" +#include "utlvector.h" +#include "networkvar.h" +#include "engine/IEngineTrace.h" +#include "engine/IStaticPropMgr.h" +#include "shared_classnames.h" + +#ifdef CLIENT_DLL +#include "cdll_client_int.h" +#endif + +#ifdef PORTAL +#include "portal_util_shared.h" +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CGameTrace; +class CBasePlayer; +typedef CGameTrace trace_t; + +extern ConVar developer; // developer mode + + +//----------------------------------------------------------------------------- +// Language IDs. +//----------------------------------------------------------------------------- +#define LANGUAGE_ENGLISH 0 +#define LANGUAGE_GERMAN 1 +#define LANGUAGE_FRENCH 2 +#define LANGUAGE_BRITISH 3 + + +//----------------------------------------------------------------------------- +// Pitch + yaw +//----------------------------------------------------------------------------- +float UTIL_VecToYaw (const Vector &vec); +float UTIL_VecToPitch (const Vector &vec); +float UTIL_VecToYaw (const matrix3x4_t& matrix, const Vector &vec); +float UTIL_VecToPitch (const matrix3x4_t& matrix, const Vector &vec); +Vector UTIL_YawToVector ( float yaw ); + +//----------------------------------------------------------------------------- +// Shared random number generators for shared/predicted code: +// whenever generating random numbers in shared/predicted code, these functions +// have to be used. Each call should specify a unique "sharedname" string that +// seeds the random number generator. In loops make sure the "additionalSeed" +// is increased with the loop counter, otherwise it will always return the +// same random number +//----------------------------------------------------------------------------- +float SharedRandomFloat( const char *sharedname, float flMinVal, float flMaxVal, int additionalSeed = 0 ); +int SharedRandomInt( const char *sharedname, int iMinVal, int iMaxVal, int additionalSeed = 0 ); +Vector SharedRandomVector( const char *sharedname, float minVal, float maxVal, int additionalSeed = 0 ); +QAngle SharedRandomAngle( const char *sharedname, float minVal, float maxVal, int additionalSeed = 0 ); + +//----------------------------------------------------------------------------- +// Standard collision filters... +//----------------------------------------------------------------------------- +bool PassServerEntityFilter( const IHandleEntity *pTouch, const IHandleEntity *pPass ); +bool StandardFilterRules( IHandleEntity *pHandleEntity, int fContentsMask ); + + +//----------------------------------------------------------------------------- +// Converts an IHandleEntity to an CBaseEntity +//----------------------------------------------------------------------------- +inline const CBaseEntity *EntityFromEntityHandle( const IHandleEntity *pConstHandleEntity ) +{ + IHandleEntity *pHandleEntity = const_cast(pConstHandleEntity); + +#ifdef CLIENT_DLL + IClientUnknown *pUnk = (IClientUnknown*)pHandleEntity; + return pUnk->GetBaseEntity(); +#else + if ( staticpropmgr->IsStaticProp( pHandleEntity ) ) + return NULL; + + IServerUnknown *pUnk = (IServerUnknown*)pHandleEntity; + return pUnk->GetBaseEntity(); +#endif +} + +inline CBaseEntity *EntityFromEntityHandle( IHandleEntity *pHandleEntity ) +{ +#ifdef CLIENT_DLL + IClientUnknown *pUnk = (IClientUnknown*)pHandleEntity; + return pUnk->GetBaseEntity(); +#else + if ( staticpropmgr->IsStaticProp( pHandleEntity ) ) + return NULL; + + IServerUnknown *pUnk = (IServerUnknown*)pHandleEntity; + return pUnk->GetBaseEntity(); +#endif +} + +typedef bool (*ShouldHitFunc_t)( IHandleEntity *pHandleEntity, int contentsMask ); + +//----------------------------------------------------------------------------- +// traceline methods +//----------------------------------------------------------------------------- +class CTraceFilterSimple : public CTraceFilter +{ +public: + // It does have a base, but we'll never network anything below here.. + DECLARE_CLASS_NOBASE( CTraceFilterSimple ); + + CTraceFilterSimple( const IHandleEntity *passentity, int collisionGroup, ShouldHitFunc_t pExtraShouldHitCheckFn = NULL ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + virtual void SetPassEntity( const IHandleEntity *pPassEntity ) { m_pPassEnt = pPassEntity; } + virtual void SetCollisionGroup( int iCollisionGroup ) { m_collisionGroup = iCollisionGroup; } + + const IHandleEntity *GetPassEntity( void ){ return m_pPassEnt;} + +private: + const IHandleEntity *m_pPassEnt; + int m_collisionGroup; + ShouldHitFunc_t m_pExtraShouldHitCheckFunction; + +}; + +class CTraceFilterSkipTwoEntities : public CTraceFilterSimple +{ +public: + // It does have a base, but we'll never network anything below here.. + DECLARE_CLASS( CTraceFilterSkipTwoEntities, CTraceFilterSimple ); + + CTraceFilterSkipTwoEntities( const IHandleEntity *passentity, const IHandleEntity *passentity2, int collisionGroup ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + virtual void SetPassEntity2( const IHandleEntity *pPassEntity2 ) { m_pPassEnt2 = pPassEntity2; } + +private: + const IHandleEntity *m_pPassEnt2; +}; + +class CTraceFilterSimpleList : public CTraceFilterSimple +{ +public: + CTraceFilterSimpleList( int collisionGroup ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + + void AddEntityToIgnore( IHandleEntity *pEntity ); +protected: + CUtlVector m_PassEntities; +}; + +class CTraceFilterOnlyNPCsAndPlayer : public CTraceFilterSimple +{ +public: + CTraceFilterOnlyNPCsAndPlayer( const IHandleEntity *passentity, int collisionGroup ) + : CTraceFilterSimple( passentity, collisionGroup ) + { + } + + virtual TraceType_t GetTraceType() const + { + return TRACE_ENTITIES_ONLY; + } + + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); +}; + +class CTraceFilterNoNPCsOrPlayer : public CTraceFilterSimple +{ +public: + CTraceFilterNoNPCsOrPlayer( const IHandleEntity *passentity, int collisionGroup ) + : CTraceFilterSimple( passentity, collisionGroup ) + { + } + + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); +}; + +//----------------------------------------------------------------------------- +// Purpose: Custom trace filter used for NPC LOS traces +//----------------------------------------------------------------------------- +class CTraceFilterLOS : public CTraceFilterSkipTwoEntities +{ +public: + CTraceFilterLOS( IHandleEntity *pHandleEntity, int collisionGroup, IHandleEntity *pHandleEntity2 = NULL ); + bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); +}; + +class CTraceFilterSkipClassname : public CTraceFilterSimple +{ +public: + CTraceFilterSkipClassname( const IHandleEntity *passentity, const char *pchClassname, int collisionGroup ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + +private: + + const char *m_pchClassname; +}; + +class CTraceFilterSkipTwoClassnames : public CTraceFilterSkipClassname +{ +public: + // It does have a base, but we'll never network anything below here.. + DECLARE_CLASS( CTraceFilterSkipTwoClassnames, CTraceFilterSkipClassname ); + + CTraceFilterSkipTwoClassnames( const IHandleEntity *passentity, const char *pchClassname, const char *pchClassname2, int collisionGroup ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + +private: + const char *m_pchClassname2; +}; + +class CTraceFilterSimpleClassnameList : public CTraceFilterSimple +{ +public: + CTraceFilterSimpleClassnameList( const IHandleEntity *passentity, int collisionGroup ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + + void AddClassnameToIgnore( const char *pchClassname ); +private: + CUtlVector m_PassClassnames; +}; + +class CTraceFilterChain : public CTraceFilter +{ +public: + CTraceFilterChain( ITraceFilter *pTraceFilter1, ITraceFilter *pTraceFilter2 ); + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ); + +private: + ITraceFilter *m_pTraceFilter1; + ITraceFilter *m_pTraceFilter2; +}; + +// helper +void DebugDrawLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, int r, int g, int b, bool test, float duration ); + +extern ConVar r_visualizetraces; + +inline void UTIL_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, + const IHandleEntity *ignore, int collisionGroup, trace_t *ptr ) +{ + Ray_t ray; + ray.Init( vecAbsStart, vecAbsEnd ); + CTraceFilterSimple traceFilter( ignore, collisionGroup ); + + enginetrace->TraceRay( ray, mask, &traceFilter, ptr ); + + if( r_visualizetraces.GetBool() ) + { + DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f ); + } +} + +inline void UTIL_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, + ITraceFilter *pFilter, trace_t *ptr ) +{ + Ray_t ray; + ray.Init( vecAbsStart, vecAbsEnd ); + + enginetrace->TraceRay( ray, mask, pFilter, ptr ); + + if( r_visualizetraces.GetBool() ) + { + DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f ); + } +} + +inline void UTIL_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin, + const Vector &hullMax, unsigned int mask, const IHandleEntity *ignore, + int collisionGroup, trace_t *ptr ) +{ + Ray_t ray; + ray.Init( vecAbsStart, vecAbsEnd, hullMin, hullMax ); + CTraceFilterSimple traceFilter( ignore, collisionGroup ); + + enginetrace->TraceRay( ray, mask, &traceFilter, ptr ); + + if( r_visualizetraces.GetBool() ) + { + DebugDrawLine( ptr->startpos, ptr->endpos, 255, 255, 0, true, -1.0f ); + } +} + +inline void UTIL_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin, + const Vector &hullMax, unsigned int mask, ITraceFilter *pFilter, trace_t *ptr ) +{ + Ray_t ray; + ray.Init( vecAbsStart, vecAbsEnd, hullMin, hullMax ); + + enginetrace->TraceRay( ray, mask, pFilter, ptr ); + + if( r_visualizetraces.GetBool() ) + { + DebugDrawLine( ptr->startpos, ptr->endpos, 255, 255, 0, true, -1.0f ); + } +} + +inline void UTIL_TraceRay( const Ray_t &ray, unsigned int mask, + const IHandleEntity *ignore, int collisionGroup, trace_t *ptr, ShouldHitFunc_t pExtraShouldHitCheckFn = NULL ) +{ + CTraceFilterSimple traceFilter( ignore, collisionGroup, pExtraShouldHitCheckFn ); + + enginetrace->TraceRay( ray, mask, &traceFilter, ptr ); + + if( r_visualizetraces.GetBool() ) + { + DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f ); + } +} + + +// Sweeps a particular entity through the world +void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr ); +void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, + unsigned int mask, ITraceFilter *pFilter, trace_t *ptr ); +void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, + unsigned int mask, const IHandleEntity *ignore, int collisionGroup, trace_t *ptr ); + +bool UTIL_EntityHasMatchingRootParent( CBaseEntity *pRootParent, CBaseEntity *pEntity ); + +inline int UTIL_PointContents( const Vector &vec ) +{ + return enginetrace->GetPointContents( vec ); +} + +// Sweeps against a particular model, using collision rules +void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, + const Vector &hullMax, CBaseEntity *pentModel, int collisionGroup, trace_t *ptr ); + +void UTIL_ClipTraceToPlayers( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, ITraceFilter *filter, trace_t *tr ); + +// Particle effect tracer +void UTIL_ParticleTracer( const char *pszTracerEffectName, const Vector &vecStart, const Vector &vecEnd, int iEntIndex = 0, int iAttachment = 0, bool bWhiz = false ); + +// Old style, non-particle system, tracers +void UTIL_Tracer( const Vector &vecStart, const Vector &vecEnd, int iEntIndex = 0, int iAttachment = TRACER_DONT_USE_ATTACHMENT, float flVelocity = 0, bool bWhiz = false, const char *pCustomTracerName = NULL, int iParticleID = 0 ); + +bool UTIL_IsLowViolence( void ); +bool UTIL_ShouldShowBlood( int bloodColor ); +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ); + +void UTIL_BloodImpact( const Vector &pos, const Vector &dir, int color, int amount ); +void UTIL_BloodDecalTrace( trace_t *pTrace, int bloodColor ); +void UTIL_DecalTrace( trace_t *pTrace, char const *decalName ); +bool UTIL_IsSpaceEmpty( CBaseEntity *pMainEnt, const Vector &vMin, const Vector &vMax ); + +void UTIL_StringToVector( float *pVector, const char *pString ); +void UTIL_StringToIntArray( int *pVector, int count, const char *pString ); +void UTIL_StringToFloatArray( float *pVector, int count, const char *pString ); +void UTIL_StringToColor32( color32 *color, const char *pString ); + +CBasePlayer *UTIL_PlayerByIndex( int entindex ); + +//============================================================================= +// HPE_BEGIN: +// [menglish] Added UTIL function for events in client win_panel which transmit the player as a user ID +//============================================================================= +CBasePlayer *UTIL_PlayerByUserId( int userID ); +//============================================================================= +// HPE_END +//============================================================================= + +// decodes a buffer using a 64bit ICE key (inplace) +void UTIL_DecodeICE( unsigned char * buffer, int size, const unsigned char *key); + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Given a position and a ray, return the shortest distance between the two. + * If 'pos' is beyond either end of the ray, the returned distance is negated. + */ +inline float DistanceToRay( const Vector &pos, const Vector &rayStart, const Vector &rayEnd, float *along = NULL, Vector *pointOnRay = NULL ) +{ + Vector to = pos - rayStart; + Vector dir = rayEnd - rayStart; + float length = dir.NormalizeInPlace(); + + float rangeAlong = DotProduct( dir, to ); + if (along) + { + *along = rangeAlong; + } + + float range; + + if (rangeAlong < 0.0f) + { + // off start point + range = -(pos - rayStart).Length(); + + if (pointOnRay) + { + *pointOnRay = rayStart; + } + } + else if (rangeAlong > length) + { + // off end point + range = -(pos - rayEnd).Length(); + + if (pointOnRay) + { + *pointOnRay = rayEnd; + } + } + else // within ray bounds + { + Vector onRay = rayStart + rangeAlong * dir; + range = (pos - onRay).Length(); + + if (pointOnRay) + { + *pointOnRay = onRay; + } + } + + return range; +} + + +//-------------------------------------------------------------------------------------------------------------- +/** +* Macro for creating an interface that when inherited from automatically maintains a list of instances +* that inherit from that interface. +*/ + +// interface for entities that want to a auto maintained global list +#define DECLARE_AUTO_LIST( interfaceName ) \ + class interfaceName; \ + abstract_class interfaceName \ + { \ + public: \ + interfaceName( bool bAutoAdd = true ); \ + virtual ~interfaceName(); \ + static void AddToAutoList( interfaceName *pElement ) { m_##interfaceName##AutoList.AddToTail( pElement ); } \ + static void RemoveFromAutoList( interfaceName *pElement ) { m_##interfaceName##AutoList.FindAndFastRemove( pElement ); } \ + static const CUtlVector< interfaceName* >& AutoList( void ) { return m_##interfaceName##AutoList; } \ + private: \ + static CUtlVector< interfaceName* > m_##interfaceName##AutoList; \ + }; + +// Creates the auto add/remove constructor/destructor... +// Pass false to the constructor to not auto add +#define IMPLEMENT_AUTO_LIST( interfaceName ) \ + CUtlVector< class interfaceName* > interfaceName::m_##interfaceName##AutoList; \ + interfaceName::interfaceName( bool bAutoAdd ) \ + { \ + if ( bAutoAdd ) \ + { \ + AddToAutoList( this ); \ + } \ + } \ + interfaceName::~interfaceName() \ + { \ + RemoveFromAutoList( this ); \ + } + +//-------------------------------------------------------------------------------------------------------------- +// This would do the same thing without requiring casts all over the place. Yes, it's a template, but +// DECLARE_AUTO_LIST requires a CUtlVector anyway. TODO ask about replacing the macros with this. +//template +//class AutoList { +//public: +// typedef CUtlVector AutoListType; +// static AutoListType& All() { return m_autolist; } +//protected: +// AutoList() { m_autolist.AddToTail(static_cast(this)); } +// virtual ~AutoList() { m_autolist.FindAndFastRemove(static_cast(this)); } +//private: +// static AutoListType m_autolist; +//}; + +//-------------------------------------------------------------------------------------------------------------- +/** + * Simple class for tracking intervals of game time. + * Upon creation, the timer is invalidated. To measure time intervals, start the timer via Start(). + */ +class IntervalTimer +{ +public: + IntervalTimer( void ) + { + m_timestamp = -1.0f; + } + + void Reset( void ) + { + m_timestamp = Now(); + } + + void Start( void ) + { + m_timestamp = Now(); + } + + void Invalidate( void ) + { + m_timestamp = -1.0f; + } + + bool HasStarted( void ) const + { + return (m_timestamp > 0.0f); + } + + /// if not started, elapsed time is very large + float GetElapsedTime( void ) const + { + return (HasStarted()) ? (Now() - m_timestamp) : 99999.9f; + } + + bool IsLessThen( float duration ) const + { + return (Now() - m_timestamp < duration) ? true : false; + } + + bool IsGreaterThen( float duration ) const + { + return (Now() - m_timestamp > duration) ? true : false; + } + +private: + float m_timestamp; + float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime +}; + + +//-------------------------------------------------------------------------------------------------------------- +/** + * Simple class for counting down a short interval of time. + * Upon creation, the timer is invalidated. Invalidated countdown timers are considered to have elapsed. + */ +class CountdownTimer +{ +public: + CountdownTimer( void ) + { + m_timestamp = -1.0f; + m_duration = 0.0f; + } + + void Reset( void ) + { + m_timestamp = Now() + m_duration; + } + + void Start( float duration ) + { + m_timestamp = Now() + duration; + m_duration = duration; + } + + void Invalidate( void ) + { + m_timestamp = -1.0f; + } + + bool HasStarted( void ) const + { + return (m_timestamp > 0.0f); + } + + bool IsElapsed( void ) const + { + return (Now() > m_timestamp); + } + + float GetElapsedTime( void ) const + { + return Now() - m_timestamp + m_duration; + } + + float GetRemainingTime( void ) const + { + return (m_timestamp - Now()); + } + + /// return original countdown time + float GetCountdownDuration( void ) const + { + return (m_timestamp > 0.0f) ? m_duration : 0.0f; + } + +private: + float m_duration; + float m_timestamp; + virtual float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime +}; + +class RealTimeCountdownTimer : public CountdownTimer +{ + virtual float Now( void ) const OVERRIDE + { + return Plat_FloatTime(); + } +}; + +char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename = NULL ); + +int UTIL_StringFieldToInt( const char *szValue, const char **pValueStrings, int iNumStrings ); + +//----------------------------------------------------------------------------- +// Holidays +//----------------------------------------------------------------------------- + +// Used at level change and round start to re-calculate which holiday is active +void UTIL_CalculateHolidays(); + +bool UTIL_IsHolidayActive( /*EHoliday*/ int eHoliday ); +/*EHoliday*/ int UTIL_GetHolidayForString( const char* pszHolidayName ); + +// This will return the first active holiday string it can find. In the case of multiple +// holidays overlapping, the list order will act as priority. +const char *UTIL_GetActiveHolidayString(); + + +#endif // UTIL_SHARED_H diff --git a/game/shared/vehicle_choreo_generic_shared.h b/game/shared/vehicle_choreo_generic_shared.h new file mode 100644 index 0000000..8d6c1e1 --- /dev/null +++ b/game/shared/vehicle_choreo_generic_shared.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VEHICLE_CHOREO_GENERIC_SHARED_H +#define VEHICLE_CHOREO_GENERIC_SHARED_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct vehicleview_t +{ + DECLARE_CLASS_NOBASE( vehicleview_t ); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_DATADESC(); +#endif + + CNetworkVar( bool, bClampEyeAngles ); // Perform eye Z clamping + + CNetworkVar( float, flPitchCurveZero ); // Pitch values below this are clamped to zero. + CNetworkVar( float, flPitchCurveLinear ); // Pitch values above this are mapped directly. + // Spline in between. + CNetworkVar( float, flRollCurveZero ); // Pitch values below this are clamped to zero. + CNetworkVar( float, flRollCurveLinear ); // Roll values above this are mapped directly. + // Spline in between. + CNetworkVar( float, flFOV ); // FOV when in the vehicle. + + CNetworkVar( float, flYawMin ); + CNetworkVar( float, flYawMax ); + + CNetworkVar( float, flPitchMin ); + CNetworkVar( float, flPitchMax ); +}; + + +#endif // VEHICLE_CHOREO_GENERIC_SHARED_H diff --git a/game/shared/vehicle_viewblend_shared.h b/game/shared/vehicle_viewblend_shared.h new file mode 100644 index 0000000..a741490 --- /dev/null +++ b/game/shared/vehicle_viewblend_shared.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VEHICLE_VIEWBLEND_SHARED_H +#define VEHICLE_VIEWBLEND_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +// Definition for how to calculate a point on the remap curve +enum RemapAngleRange_CurvePart_t +{ + RemapAngleRange_CurvePart_Zero = 0, + RemapAngleRange_CurvePart_Spline, + RemapAngleRange_CurvePart_Linear, +}; + +// If we enter the linear part of the remap for curve for any degree of freedom, we can lock +// that DOF (stop remapping). This is useful for making flips feel less spastic as we oscillate +// randomly between different parts of the remapping curve. +struct ViewLockData_t +{ + float flLockInterval; // The duration to lock the view when we lock it for this degree of freedom. + // 0 = never lock this degree of freedom. + + bool bLocked; // True if this DOF was locked because of the above condition. + + float flUnlockTime; // If this DOF is locked, the time when we will unlock it. + + float flUnlockBlendInterval; // If this DOF is locked, how long to spend blending out of the locked view when we unlock. +}; + +// This is separate from the base vehicle implementation so that any class +// that derives from IClientVehicle can use it. To use it, contain one of the +// following structs, fill out the first section, and then call VehicleViewSmoothing() +// inside your GetVehicleViewPosition() function. +struct ViewSmoothingData_t +{ + DECLARE_SIMPLE_DATADESC(); + + // Fill these out in your vehicle + CBaseAnimating *pVehicle; + bool bClampEyeAngles; // Perform eye Z clamping + float flPitchCurveZero; // Pitch values below this are clamped to zero. + float flPitchCurveLinear; // Pitch values above this are mapped directly. + // Spline in between. + float flRollCurveZero; // Pitch values below this are clamped to zero. + float flRollCurveLinear; // Roll values above this are mapped directly. + // Spline in between. + float flFOV; // FOV when in the vehicle. + + ViewLockData_t pitchLockData; + ViewLockData_t rollLockData; + + bool bDampenEyePosition; // Only set to true for C_PropVehicleDriveable derived vehicles + + // Don't change these, they're used by VehicleViewSmoothing() + bool bRunningEnterExit; + bool bWasRunningAnim; + float flEnterExitStartTime; // Time we began our animation at + float flEnterExitDuration; // Duration of the animation + QAngle vecAnglesSaved; + Vector vecOriginSaved; + QAngle vecAngleDiffSaved; // The original angular error between the entry/exit anim and player's view when we started playing the anim. + QAngle vecAngleDiffMin; // Tracks the minimum angular error achieved so we can converge on the anim's angles. +}; + +// TEMP: Shared vehicle view smoothing +void SharedVehicleViewSmoothing(CBasePlayer *pPlayer, + Vector *pAbsOrigin, QAngle *pAbsAngles, + bool bEnterAnimOn, bool bExitAnimOn, + const Vector &vecEyeExitEndpoint, + ViewSmoothingData_t *pData, + float *pFOV ); + +#endif // VEHICLE_VIEWBLEND_SHARED_H diff --git a/game/shared/vgui_defaultinputsignal.h b/game/shared/vgui_defaultinputsignal.h new file mode 100644 index 0000000..858a528 --- /dev/null +++ b/game/shared/vgui_defaultinputsignal.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_DEFAULTINPUTSIGNAL_H +#define VGUI_DEFAULTINPUTSIGNAL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_inputsignal.h" + + +namespace vgui +{ + // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. + class CDefaultInputSignal : public vgui::InputSignal + { + public: + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) {} + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseReleased(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} + }; +} + + +#endif // VGUI_DEFAULTINPUTSIGNAL_H diff --git a/game/shared/viewport_panel_names.h b/game/shared/viewport_panel_names.h new file mode 100644 index 0000000..b579493 --- /dev/null +++ b/game/shared/viewport_panel_names.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VIEWPORT_PANEL_NAMES_H +#define VIEWPORT_PANEL_NAMES_H +#ifdef _WIN32 +#pragma once +#endif + + +// default panel name definitions +#define PANEL_ALL "all" // all current panels +#define PANEL_ACTIVE "active" // current active panel + +#define PANEL_SCOREBOARD "scores" +#define PANEL_OVERVIEW "overview" +#define PANEL_CLASS "class" +#define PANEL_TEAM "team" +#define PANEL_SPECGUI "specgui" // passive spectator elements (top/bottom bars) +#define PANEL_SPECMENU "specmenu" // active spectator elements (options menus etc) +#define PANEL_INFO "info" +#define PANEL_BUY "buy" +#define PANEL_BUY_CT "buy_ct" +#define PANEL_BUY_TER "buy_ter" +#define PANEL_BUY_EQUIP_CT "buyequip_ct" +#define PANEL_BUY_EQUIP_TER "buyequip_ter" +#define PANEL_NAV_PROGRESS "nav_progress" +#define PANEL_BUYPRESET_MAIN "buypreset_main" +#define PANEL_BUYPRESET_EDIT "buypreset_edit" +#define PANEL_INTRO "intro" + + +#define PANEL_COMMENTARY_MODELVIEWER "commentary_modelviewer" + +#endif // VIEWPORT_PANEL_NAMES_H diff --git a/game/shared/voice_banmgr.h b/game/shared/voice_banmgr.h new file mode 100644 index 0000000..6adfdc5 --- /dev/null +++ b/game/shared/voice_banmgr.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VOICE_BANMGR_H +#define VOICE_BANMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class manages the (persistent) list of squelched players. +class CVoiceBanMgr +{ +public: + + CVoiceBanMgr(); + ~CVoiceBanMgr(); + + // Init loads the list of squelched players from disk. + bool Init(const char *pGameDir); + void Term(); + + // Saves the state into voice_squelch.dt. + void SaveState(const char *pGameDir); + + bool GetPlayerBan(char const playerID[SIGNED_GUID_LEN]); + void SetPlayerBan(char const playerID[SIGNED_GUID_LEN], bool bSquelch); + + +protected: + + class BannedPlayer + { + public: + char m_PlayerID[SIGNED_GUID_LEN]; + BannedPlayer *m_pPrev, *m_pNext; + }; + + void Clear(); + BannedPlayer* InternalFindPlayerSquelch(char const playerID[SIGNED_GUID_LEN]); + BannedPlayer* AddBannedPlayer(char const playerID[SIGNED_GUID_LEN]); + + +protected: + + BannedPlayer m_PlayerHash[256]; +}; + + +#endif // VOICE_BANMGR_H diff --git a/game/shared/voice_common.h b/game/shared/voice_common.h new file mode 100644 index 0000000..86511e9 --- /dev/null +++ b/game/shared/voice_common.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VOICE_COMMON_H +#define VOICE_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "bitvec.h" +#include "const.h" + + +#define VOICE_MAX_PLAYERS MAX_PLAYERS +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec CPlayerBitVec; + +#define VOICE_DEFAULT_PROXIMITY_RANGE 1200 //100 feet + + +#endif // VOICE_COMMON_H diff --git a/game/shared/voice_gamemgr.h b/game/shared/voice_gamemgr.h new file mode 100644 index 0000000..a572469 --- /dev/null +++ b/game/shared/voice_gamemgr.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VOICE_GAMEMGR_H +#define VOICE_GAMEMGR_H +#pragma once + + +#include "voice_common.h" + + +class CGameRules; +class CBasePlayer; + +abstract_class IVoiceGameMgrHelper +{ +public: + virtual ~IVoiceGameMgrHelper() {} + + // Called each frame to determine which players are allowed to hear each other. This overrides + // whatever squelch settings players have. + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker, bool &bProximity ) = 0; +}; + + +// CVoiceGameMgr manages which clients can hear which other clients. +class CVoiceGameMgr +{ +public: + CVoiceGameMgr(); + virtual ~CVoiceGameMgr(); + + bool Init( + IVoiceGameMgrHelper *m_pHelper, + int maxClients + ); + + void SetHelper(IVoiceGameMgrHelper *pHelper); + + // Updates which players can hear which other players. + // If gameplay mode is DM, then only players within the PVS can hear each other. + // If gameplay mode is teamplay, then only players on the same team can hear each other. + // Player masks are always applied. + void Update(double frametime); + + // Called when a new client connects (unsquelches its entity for everyone). + void ClientConnected(struct edict_t *pEdict); + + // Called on ClientCommand. Checks for the squelch and unsquelch commands. + // Returns true if it handled the command. + bool ClientCommand(CBasePlayer *pPlayer, const CCommand &args ); + + bool CheckProximity( int iDistance ); + void SetProximityDistance( int iDistance ); + + bool IsPlayerIgnoringPlayer( int iTalker, int iListener ); + +private: + + // Force it to update the client masks. + void UpdateMasks(); + + +private: + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. + int m_iProximityDistance; +}; + + +// Use this to access CVoiceGameMgr. +CVoiceGameMgr* GetVoiceGameMgr(); + + + +#endif // VOICE_GAMEMGR_H diff --git a/game/shared/voice_status.h b/game/shared/voice_status.h new file mode 100644 index 0000000..f9bc426 --- /dev/null +++ b/game/shared/voice_status.h @@ -0,0 +1,197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VOICE_STATUS_H +#define VOICE_STATUS_H +#pragma once + + +#include +//#include "vgui_bitmap.h" +#include +#include +#include "voice_common.h" +#include "voice_banmgr.h" +#include "hudelement.h" + +#ifdef VOICE_VOX_ENABLE +extern ConVar voice_vox; +#endif // VOICE_VOX_ENABLE + +class CVoiceStatus; +class IMaterial; +class BitmapImage; + +// Voice Panel +class CVoicePanel : public vgui::Panel +{ +public: + CVoicePanel( ); + ~CVoicePanel(); + + virtual void Paint( void ); + virtual void setImage( BitmapImage *pImage ); + +private: + BitmapImage *m_pImage; +}; + +class CVoiceLabel +{ +public: + vgui::Label *m_pLabel; + vgui::Label *m_pBackground; + CVoicePanel *m_pIcon; // Voice icon next to player name. + int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. +}; + +// This is provided by each mod to access data that may not be the same across mods. +abstract_class IVoiceStatusHelper +{ +public: + virtual ~IVoiceStatusHelper() {} + + // Get RGB color for voice status text about this player. + virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; + + // Force it to update the cursor state. + virtual void UpdateCursorState() = 0; + + // Return true if the voice manager is allowed to show speaker labels + // (mods usually return false when the scoreboard is up). + virtual bool CanShowSpeakerLabels() = 0; +}; + +class CVoiceStatus /*: public vgui::CDefaultInputSignal*/ +{ +public: + CVoiceStatus(); + virtual ~CVoiceStatus(); + +// CHudBase overrides. +public: + + // Initialize the cl_dll's voice manager. + virtual int Init( + IVoiceStatusHelper *m_pHelper, + vgui::VPANEL pParentPanel); + + // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. + virtual void VidInit(); + +public: + + // Call from HUD_Frame each frame. + void Frame(double frametime); + + // Called when a player starts or stops talking. + // entindex is -1 to represent the local client talking (before the data comes back from the server). + // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). + // entindex is -2 to represent the local client's voice being acked by the server. + void UpdateSpeakerStatus(int entindex, bool bTalking); + + // Call from the HUD_CreateEntities function so it can add sprites above player heads. + void DrawHeadLabels(); + void SetHeadLabelOffset( float offset ); + float GetHeadLabelOffset( void ) const; + void SetHeadLabelsDisabled( bool bDisabled ) { m_bHeadLabelsDisabled = bDisabled; } + + // Called when the server registers a change to who this client can hear. + void HandleVoiceMaskMsg(bf_read &msg); + + // The server sends this message initially to tell the client to send their state. + void HandleReqStateMsg(bf_read &msg); + + +// Squelch mode functions. +public: + + // When you enter squelch mode, pass in + void StartSquelchMode(); + void StopSquelchMode(); + bool IsInSquelchMode(); + + // returns true if the target client has been banned + // playerIndex is of range 1..maxplayers + bool IsPlayerBlocked(int iPlayerIndex); + + // returns false if the player can't hear the other client due to game rules (eg. the other team) + bool IsPlayerAudible(int iPlayerIndex); + + // returns true if the player is currently speaking + bool IsPlayerSpeaking(int iPlayerIndex); + + // returns true if the local player is attempting to speak + bool IsLocalPlayerSpeaking( void ); + + // blocks the target client from being heard + void SetPlayerBlockedState(int iPlayerIndex, bool blocked); + + void SetHeadLabelMaterial( const char *pszMaterial ); + + IMaterial *GetHeadLabelMaterial( void ) { return m_pHeadLabelMaterial; } + +private: + + void UpdateServerState(bool bForce); + + // Update the button artwork to reflect the client's current state. + void UpdateBanButton(int iClient); + + +private: + float m_LastUpdateServerState; // Last time we called this function. + int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. + + vgui::VPANEL m_pParentPanel; + CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. + + // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on + // and is totally separate from the ban list. Indexed by client index. + CPlayerBitVec m_AudiblePlayers; + + // Players who have spoken at least once in the game so far + CPlayerBitVec m_VoiceEnabledPlayers; + + // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). + // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. + CPlayerBitVec m_ServerBannedPlayers; + + IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. + + // Squelch mode stuff. + bool m_bInSquelchMode; + + bool m_bTalking; // Set to true when the client thinks it's talking. + bool m_bServerAcked; // Set to true when the server knows the client is talking. + +public: + + CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. + +private: + + IMaterial *m_pHeadLabelMaterial; // For labels above players' heads. + + bool m_bBanMgrInitialized; + + int m_nControlSize; + + bool m_bHeadLabelsDisabled; + +#ifdef VOICE_VOX_ENABLE + CountdownTimer m_bAboveThresholdTimer; +#endif // VOICE_VOX_ENABLE +}; + + +// Get the (global) voice manager. +CVoiceStatus* GetClientVoiceMgr(); +void ClientVoiceMgr_Init(); +void ClientVoiceMgr_Shutdown(); + +#endif // VOICE_STATUS_H diff --git a/game/shared/vphysics_sound.h b/game/shared/vphysics_sound.h new file mode 100644 index 0000000..591a0db --- /dev/null +++ b/game/shared/vphysics_sound.h @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPHYSICS_SOUND_H +#define VPHYSICS_SOUND_H +#ifdef _WIN32 +#pragma once +#endif + +#include "SoundEmitterSystem/isoundemittersystembase.h" + +namespace physicssound +{ + struct impactsound_t + { + void *pGameData; + int entityIndex; + int soundChannel; + float volume; + float impactSpeed; + unsigned short surfaceProps; + unsigned short surfacePropsHit; + Vector origin; + }; + + // UNDONE: Use a sorted container and sort by volume/distance? + struct soundlist_t + { + CUtlVector elements; + impactsound_t &GetElement(int index) { return elements[index]; } + impactsound_t &AddElement() { return elements[elements.AddToTail()]; } + int Count() { return elements.Count(); } + void RemoveAll() { elements.RemoveAll(); } + }; + + void PlayImpactSounds( soundlist_t &list ) + { + for ( int i = list.Count()-1; i >= 0; --i ) + { + impactsound_t &sound = list.GetElement(i); + const surfacedata_t *psurf = physprops->GetSurfaceData( sound.surfaceProps ); + if ( psurf->sounds.impactHard ) + { + const surfacedata_t *pHit = physprops->GetSurfaceData( sound.surfacePropsHit ); + unsigned short soundName = psurf->sounds.impactHard; + if ( pHit && psurf->sounds.impactSoft ) + { + if ( pHit->audio.hardnessFactor < psurf->audio.hardThreshold || + (psurf->audio.hardVelocityThreshold > 0 && psurf->audio.hardVelocityThreshold > sound.impactSpeed) ) + { + soundName = psurf->sounds.impactSoft; + } + } + const char *pSound = physprops->GetString( soundName ); + + CSoundParameters params; + if ( !CBaseEntity::GetParametersForSound( pSound, params, NULL ) ) + break; + + if ( sound.volume > 1 ) + sound.volume = 1; + CPASAttenuationFilter filter( sound.origin, params.soundlevel ); + // JAY: If this entity gets deleted, the sound comes out at the world origin + // this sounds bad! Play on ent 0 for now. + EmitSound_t ep; + ep.m_nChannel = sound.soundChannel; + ep.m_pSoundName = params.soundname; + ep.m_flVolume = params.volume * sound.volume; + ep.m_SoundLevel = params.soundlevel; + ep.m_nPitch = params.pitch; + ep.m_pOrigin = &sound.origin; + + CBaseEntity::EmitSound( filter, 0 /*sound.entityIndex*/, ep ); + } + } + list.RemoveAll(); + } + void AddImpactSound( soundlist_t &list, void *pGameData, int entityIndex, int soundChannel, IPhysicsObject *pObject, int surfaceProps, int surfacePropsHit, float volume, float impactSpeed ) + { + impactSpeed += 1e-4; + for ( int i = list.Count()-1; i >= 0; --i ) + { + impactsound_t &sound = list.GetElement(i); + // UNDONE: Compare entity or channel somehow? + // UNDONE: Doing one slot per entity is too noisy. So now we use one slot per material + + // heuristic - after 4 impacts sounds in one frame, start merging everything + if ( surfaceProps == sound.surfaceProps || list.Count() > 4 ) + { + // UNDONE: Store instance volume separate from aggregate volume and compare that? + if ( volume > sound.volume ) + { + pObject->GetPosition( &sound.origin, NULL ); + sound.pGameData = pGameData; + sound.entityIndex = entityIndex; + sound.soundChannel = soundChannel; + sound.surfacePropsHit = surfacePropsHit; + } + sound.volume += volume; + sound.impactSpeed = MAX(impactSpeed,sound.impactSpeed); + return; + } + } + + impactsound_t &sound = list.AddElement(); + sound.pGameData = pGameData; + sound.entityIndex = entityIndex; + sound.soundChannel = soundChannel; + pObject->GetPosition( &sound.origin, NULL ); + sound.surfaceProps = surfaceProps; + sound.surfacePropsHit = surfacePropsHit; + sound.volume = volume; + sound.impactSpeed = impactSpeed; + } + + struct breaksound_t + { + Vector origin; + int surfacePropsBreak; + }; + + void AddBreakSound( CUtlVector &list, const Vector &origin, unsigned short surfaceProps ) + { + const surfacedata_t *psurf = physprops->GetSurfaceData( surfaceProps ); + if ( !psurf->sounds.breakSound ) + return; + + for ( int i = list.Count()-1; i >= 0; --i ) + { + breaksound_t &sound = list.Element(i); + // Allow 3 break sounds before you start merging anything. + if ( list.Count() > 2 && surfaceProps == sound.surfacePropsBreak ) + { + sound.origin = (sound.origin + origin) * 0.5f; + return; + } + } + breaksound_t sound; + sound.origin = origin; + sound.surfacePropsBreak = surfaceProps; + list.AddToTail(sound); + + } + + void PlayBreakSounds( CUtlVector &list ) + { + for ( int i = list.Count()-1; i >= 0; --i ) + { + breaksound_t &sound = list.Element(i); + + const surfacedata_t *psurf = physprops->GetSurfaceData( sound.surfacePropsBreak ); + const char *pSound = physprops->GetString( psurf->sounds.breakSound ); + CSoundParameters params; + if ( !CBaseEntity::GetParametersForSound( pSound, params, NULL ) ) + return; + + // Play from the world, because the entity is breaking, so it'll be destroyed soon + CPASAttenuationFilter filter( sound.origin, params.soundlevel ); + EmitSound_t ep; + ep.m_nChannel = CHAN_STATIC; + ep.m_pSoundName = params.soundname; + ep.m_flVolume = params.volume; + ep.m_SoundLevel = params.soundlevel; + ep.m_nPitch = params.pitch; + ep.m_pOrigin = &sound.origin; + CBaseEntity::EmitSound( filter, 0 /*sound.entityIndex*/, ep ); + } + list.RemoveAll(); + } +}; + + +#endif // VPHYSICS_SOUND_H diff --git a/game/shared/vphysicsupdateai.h b/game/shared/vphysicsupdateai.h new file mode 100644 index 0000000..02ce7e1 --- /dev/null +++ b/game/shared/vphysicsupdateai.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VPHYSICSUPDATEAI_H +#define VPHYSICSUPDATEAI_H +#ifdef _WIN32 +#pragma once +#endif + + +// this is used to temporarily allow the vphysics shadow object to update the entity's position +// for entities that typically ignore those updates. +struct vphysicsupdateai_t +{ + float startUpdateTime; + float stopUpdateTime; + float savedShadowControllerMaxSpeed; +}; + + +#endif // VPHYSICSUPDATEAI_H diff --git a/game/shared/weapon_ifmbase.h b/game/shared/weapon_ifmbase.h new file mode 100644 index 0000000..cf0b93c --- /dev/null +++ b/game/shared/weapon_ifmbase.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef WEAPON_IFMBASE_H +#define WEAPON_IFMBASE_H +#ifdef _WIN32 +#pragma once +#endif + + +#if defined( CLIENT_DLL ) + #define CWeaponIFMBase C_WeaponIFMBase +#endif + +#if defined ( DOD_DLL ) + #include "weapon_dodbase.h" + #define CWeaponModBaseClass CWeaponDODBase +#elif defined ( TF_CLIENT_DLL ) || defined ( TF_DLL ) + #include "tf_weaponbase.h" + #define CWeaponModBaseClass CTFWeaponBase +#endif + +class CWeaponIFMBase : public CWeaponModBaseClass +{ +public: + DECLARE_CLASS( CWeaponIFMBase, CWeaponModBaseClass ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponIFMBase(); + +#ifdef GAME_DLL + DECLARE_DATADESC(); +#endif + + // All predicted weapons need to implement and return true + virtual bool IsPredicted() const; + +// virtual void FallInit( void ); + +public: +#if defined( CLIENT_DLL ) + virtual bool ShouldPredict(); + virtual void OnDataChanged( DataUpdateType_t type ); +#else + virtual void Spawn(); + + // FIXME: How should this work? This is a hack to get things working + virtual const unsigned char *GetEncryptionKey( void ) { return NULL; } +#endif + +private: + CWeaponIFMBase( const CWeaponIFMBase & ); +}; + + +#endif // WEAPON_IFMBASE_H diff --git a/game/shared/weapon_ifmbasecamera.h b/game/shared/weapon_ifmbasecamera.h new file mode 100644 index 0000000..bd12c2f --- /dev/null +++ b/game/shared/weapon_ifmbasecamera.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef WEAPON_IFMBASECAMERA_H +#define WEAPON_IFMBASECAMERA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "weapon_ifmbase.h" + +#ifdef CLIENT_DLL +#include "materialsystem/MaterialSystemUtil.h" +#endif + +#if defined( CLIENT_DLL ) + #define CWeaponIFMBaseCamera C_WeaponIFMBaseCamera +#endif + +class CWeaponIFMBaseCamera : public CWeaponIFMBase +{ +public: + DECLARE_CLASS( CWeaponIFMBaseCamera, CWeaponIFMBase ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +#ifdef GAME_DLL + DECLARE_DATADESC(); +#endif + + // Shared code +public: + CWeaponIFMBaseCamera(); + +#ifdef CLIENT_DLL + // Client code +public: + virtual void ViewModelDrawn( CBaseViewModel *pBaseViewModel ); + virtual void DrawCrosshair( ); + virtual int DrawModel( int flags ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + +protected: + // Gets the abs orientation of the camera + virtual void ComputeAbsCameraTransform( Vector &vecAbsOrigin, QAngle &angAbsRotation ); + + // Gets the bounds of the overlay to draw + void GetOverlayBounds( int &x, int &y, int &w, int &h ); + + // Gets the size of the overlay to draw + void GetViewportSize( int &w, int &h ); + + void TransmitRenderInfo(); + + float m_flFOV; + float m_flArmLength; + Vector m_vecRelativePosition; + QAngle m_angRelativeAngles; + int m_nScreenWidth; + int m_nScreenHeight; + bool m_bFullScreen; + CMaterialReference m_FrustumMaterial; + CMaterialReference m_FrustumWireframeMaterial; +#endif + +#ifdef GAME_DLL + // Server code +public: + void SetRenderInfo( float flAspectRatio, float flFOV, float flArmLength, const Vector &vecPosition, const QAngle &angles ); +#endif + +private: + CNetworkVar( float, m_flRenderAspectRatio ); + CNetworkVar( float, m_flRenderFOV ); + CNetworkVar( float, m_flRenderArmLength ); + CNetworkVector( m_vecRenderPosition ); + CNetworkQAngle( m_angRenderAngles ); + + CWeaponIFMBaseCamera( const CWeaponIFMBaseCamera & ); +}; + + +#endif // WEAPON_IFMBASECAMERA_H diff --git a/game/shared/weapon_ifmsteadycam.h b/game/shared/weapon_ifmsteadycam.h new file mode 100644 index 0000000..98f32ba --- /dev/null +++ b/game/shared/weapon_ifmsteadycam.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef WEAPON_IFMSTEADYCAM_H +#define WEAPON_IFMSTEADYCAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "weapon_ifmbasecamera.h" + +#if defined( CLIENT_DLL ) + #define CWeaponIFMSteadyCam C_WeaponIFMSteadyCam +#endif + +class CWeaponIFMSteadyCam : public CWeaponIFMBaseCamera +{ +public: + DECLARE_CLASS( CWeaponIFMSteadyCam, CWeaponIFMBaseCamera ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +#ifdef GAME_DLL + DECLARE_DATADESC(); +#endif + +public: + // Shared code + CWeaponIFMSteadyCam(); + virtual ~CWeaponIFMSteadyCam(); + + virtual void ItemPostFrame(); + +private: + +#ifdef CLIENT_DLL + +public: + // Client code + virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd, const QAngle &vecOldViewAngles ); + virtual void DrawCrosshair( void ); + virtual void GetToolRecordingState( KeyValues *msg ); + +private: + // Purpose: Draw the weapon's crosshair + void DrawArmLength( int x, int y, int w, int h, Color clr ); + void DrawFOV( int x, int y, int w, int h, Color clrEdges, Color clrTriangle ); + + // Transmits the lock target + void TransmitLockTarget(); + + // Updates the relative orientation of the camera + void UpdateRelativeOrientation(); + void UpdateLockedRelativeOrientation(); + void UpdateDirectRelativeOrientation(); + + // Computes a matrix given a forward direction + void MatrixFromForwardDirection( const Vector &vecForward, matrix3x4_t &mat ); + + // Targets the camera to always look at a point + void LockCamera(); + + // Toggles to springy camera + void ToggleSpringCamera(); + void ToggleDirectMode(); + + // Compute the location of the camera for rendering + virtual void ComputeAbsCameraTransform( Vector &origin, QAngle &angles ); + + // Updates the relative orientation of the camera, spring mode + void ComputeMouseRay( const VMatrix &steadyCamToPlayer, Vector &vecForward ); + + // Updates the 2d spring + void ComputeViewOffset(); + + bool m_bIsLocked; + bool m_bInDirectMode; + bool m_bInSpringMode; + Vector m_vecOffset; + + Vector m_vec2DVelocity; + Vector m_vecActualViewOffset; + Vector m_vecViewOffset; + float m_flFOVOffsetY; + + vgui::HFont m_hFont; + int m_nTextureId; +#endif // CLIENT_DLL + +#ifdef GAME_DLL +public: + // Server code +#endif // GAME_DLL + +private: + EHANDLE m_hLockTarget; + +private: + CWeaponIFMSteadyCam( const CWeaponIFMSteadyCam & ); +}; + + +#endif // WEAPON_IFMSTEADYCAM_H diff --git a/game/shared/weapon_parse.h b/game/shared/weapon_parse.h new file mode 100644 index 0000000..f1d4c92 --- /dev/null +++ b/game/shared/weapon_parse.h @@ -0,0 +1,161 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Weapon data file parsing, shared by game & client dlls. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPON_PARSE_H +#define WEAPON_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" + +class IFileSystem; + +typedef unsigned short WEAPON_FILE_INFO_HANDLE; + +// ----------------------------------------------------------- +// Weapon sound types +// Used to play sounds defined in the weapon's classname.txt file +// This needs to match pWeaponSoundCategories in weapon_parse.cpp +// ------------------------------------------------------------ +typedef enum { + EMPTY, + SINGLE, + SINGLE_NPC, + WPN_DOUBLE, // Can't be "DOUBLE" because windows.h uses it. + DOUBLE_NPC, + BURST, + RELOAD, + RELOAD_NPC, + MELEE_MISS, + MELEE_HIT, + MELEE_HIT_WORLD, + SPECIAL1, + SPECIAL2, + SPECIAL3, + TAUNT, + DEPLOY, + + // Add new shoot sound types here + + NUM_SHOOT_SOUND_TYPES, +} WeaponSound_t; + +int GetWeaponSoundFromString( const char *pszString ); + +#define MAX_SHOOT_SOUNDS 16 // Maximum number of shoot sounds per shoot type + +#define MAX_WEAPON_STRING 80 +#define MAX_WEAPON_PREFIX 16 +#define MAX_WEAPON_AMMO_NAME 32 + +#define WEAPON_PRINTNAME_MISSING "!!! Missing printname on weapon" + +class CHudTexture; +class KeyValues; + +//----------------------------------------------------------------------------- +// Purpose: Contains the data read from the weapon's script file. +// It's cached so we only read each weapon's script file once. +// Each game provides a CreateWeaponInfo function so it can have game-specific +// data (like CS move speeds) in the weapon script. +//----------------------------------------------------------------------------- +class FileWeaponInfo_t +{ +public: + + FileWeaponInfo_t(); + + // Each game can override this to get whatever values it wants from the script. + virtual void Parse( KeyValues *pKeyValuesData, const char *szWeaponName ); + + +public: + bool bParsedScript; + bool bLoadedHudElements; + +// SHARED + char szClassName[MAX_WEAPON_STRING]; + char szPrintName[MAX_WEAPON_STRING]; // Name for showing in HUD, etc. + + char szViewModel[MAX_WEAPON_STRING]; // View model of this weapon + char szWorldModel[MAX_WEAPON_STRING]; // Model of this weapon seen carried by the player + char szAnimationPrefix[MAX_WEAPON_PREFIX]; // Prefix of the animations that should be used by the player carrying this weapon + int iSlot; // inventory slot. + int iPosition; // position in the inventory slot. + int iMaxClip1; // max primary clip size (-1 if no clip) + int iMaxClip2; // max secondary clip size (-1 if no clip) + int iDefaultClip1; // amount of primary ammo in the gun when it's created + int iDefaultClip2; // amount of secondary ammo in the gun when it's created + int iWeight; // this value used to determine this weapon's importance in autoselection. + int iRumbleEffect; // Which rumble effect to use when fired? (xbox) + bool bAutoSwitchTo; // whether this weapon should be considered for autoswitching to + bool bAutoSwitchFrom; // whether this weapon can be autoswitched away from when picking up another weapon or ammo + int iFlags; // miscellaneous weapon flags + char szAmmo1[MAX_WEAPON_AMMO_NAME]; // "primary" ammo type + char szAmmo2[MAX_WEAPON_AMMO_NAME]; // "secondary" ammo type + + // Sound blocks + char aShootSounds[NUM_SHOOT_SOUND_TYPES][MAX_WEAPON_STRING]; + + int iAmmoType; + int iAmmo2Type; + bool m_bMeleeWeapon; // Melee weapons can always "fire" regardless of ammo. + + // This tells if the weapon was built right-handed (defaults to true). + // This helps cl_righthand make the decision about whether to flip the model or not. + bool m_bBuiltRightHanded; + bool m_bAllowFlipping; // False to disallow flipping the model, regardless of whether + // it is built left or right handed. + +// CLIENT DLL + // Sprite data, read from the data file + int iSpriteCount; + CHudTexture *iconActive; + CHudTexture *iconInactive; + CHudTexture *iconAmmo; + CHudTexture *iconAmmo2; + CHudTexture *iconCrosshair; + CHudTexture *iconAutoaim; + CHudTexture *iconZoomedCrosshair; + CHudTexture *iconZoomedAutoaim; + CHudTexture *iconSmall; + +// TF2 specific + bool bShowUsageHint; // if true, then when you receive the weapon, show a hint about it + +// SERVER DLL + +}; + +// The weapon parse function +bool ReadWeaponDataFromFileForSlot( IFileSystem* filesystem, const char *szWeaponName, + WEAPON_FILE_INFO_HANDLE *phandle, const unsigned char *pICEKey = NULL ); + +// If weapon info has been loaded for the specified class name, this returns it. +WEAPON_FILE_INFO_HANDLE LookupWeaponInfoSlot( const char *name ); + +FileWeaponInfo_t *GetFileWeaponInfoFromHandle( WEAPON_FILE_INFO_HANDLE handle ); +WEAPON_FILE_INFO_HANDLE GetInvalidWeaponInfoHandle( void ); +void PrecacheFileWeaponInfoDatabase( IFileSystem *filesystem, const unsigned char *pICEKey ); + + +// +// Read a possibly-encrypted KeyValues file in. +// If pICEKey is NULL, then it appends .txt to the filename and loads it as an unencrypted file. +// If pICEKey is non-NULL, then it appends .ctx to the filename and loads it as an encrypted file. +// +// (This should be moved into a more appropriate place). +// +KeyValues* ReadEncryptedKVFile( IFileSystem *filesystem, const char *szFilenameWithoutExtension, const unsigned char *pICEKey, bool bForceReadEncryptedFile = false ); + + +// Each game implements this. It can return a derived class and override Parse() if it wants. +extern FileWeaponInfo_t* CreateWeaponInfo(); + + +#endif // WEAPON_PARSE_H diff --git a/game/shared/weapon_proficiency.h b/game/shared/weapon_proficiency.h new file mode 100644 index 0000000..6532b79 --- /dev/null +++ b/game/shared/weapon_proficiency.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_PROFICIENCY_H +#define WEAPON_PROFICIENCY_H + +#if defined( _WIN32 ) +#pragma once +#endif + +struct WeaponProficiencyInfo_t +{ + float spreadscale; + float bias; +}; + +enum WeaponProficiency_t +{ + WEAPON_PROFICIENCY_POOR = 0, + WEAPON_PROFICIENCY_AVERAGE, + WEAPON_PROFICIENCY_GOOD, + WEAPON_PROFICIENCY_VERY_GOOD, + WEAPON_PROFICIENCY_PERFECT, +}; + +const char *GetWeaponProficiencyName( WeaponProficiency_t proficiency ); + + +#endif // WEAPON_PROFICIENCY_H diff --git a/lib/public/def/lua_shared.def b/lib/public/def/lua_shared.def new file mode 100644 index 0000000..61525f0 --- /dev/null +++ b/lib/public/def/lua_shared.def @@ -0,0 +1,152 @@ +EXPORTS + ?AdvancedLuaErrorReporter@@YAHPEAUlua_State@@@Z + ?g_pFullFileSystem@@3PEAVIFileSystem@@EA + CreateInterface + cvar + GMOD_LoadBinaryModule + lua_atpanic + lua_call + lua_checkstack + lua_close + lua_concat + lua_copy + lua_cpcall + lua_createtable + lua_dump + lua_equal + lua_error + lua_gc + lua_getallocf + lua_getfenv + lua_getfield + lua_gethook + lua_gethookcount + lua_gethookmask + lua_getinfo + lua_getlocal + lua_getmetatable + lua_getstack + lua_gettable + lua_gettop + lua_getupvalue + lua_insert + lua_iscfunction + lua_isnumber + lua_isstring + lua_isuserdata + lua_isyieldable + lua_lessthan + lua_load + lua_loadx + lua_newstate + lua_newthread + lua_newuserdata + lua_next + lua_objlen + lua_pcall + lua_pushboolean + lua_pushcclosure + lua_pushfstring + lua_pushinteger + lua_pushlightuserdata + lua_pushlstring + lua_pushnil + lua_pushnumber + lua_pushstring + lua_pushthread + lua_pushvalue + lua_pushvfstring + lua_rawequal + lua_rawget + lua_rawgeti + lua_rawset + lua_rawseti + lua_remove + lua_replace + lua_resume_real + lua_setallocf + lua_setfenv + lua_setfield + lua_sethook + lua_setlocal + lua_setmetatable + lua_settable + lua_settop + lua_setupvalue + lua_status + lua_toboolean + lua_tocfunction + lua_tointeger + lua_tointegerx + lua_tolstring + lua_tonumber + lua_tonumberx + lua_topointer + lua_tothread + lua_touserdata + lua_type + lua_typename + lua_upvalueid + lua_upvaluejoin + lua_version + lua_xmove + lua_yield + luaJIT_profile_dumpstack + luaJIT_profile_start + luaJIT_profile_stop + luaJIT_setmode + luaJIT_version_2_1_0_beta3 + luaL_addlstring + luaL_addstring + luaL_addvalue + luaL_argerror + luaL_buffinit + luaL_callmeta + luaL_checkany + luaL_checkinteger + luaL_checklstring + luaL_checknumber + luaL_checkoption + luaL_checkstack + luaL_checktype + luaL_checkudata + luaL_error + luaL_execresult + luaL_fileresult + luaL_findtable + luaL_getmetafield + luaL_gsub + luaL_loadbuffer + luaL_loadbufferx + luaL_loadfile + luaL_loadfilex + luaL_loadstring + luaL_newmetatable + luaL_newmetatable_type + luaL_newstate + luaL_openlib + luaL_openlibs + luaL_optinteger + luaL_optlstring + luaL_optnumber + luaL_prepbuffer + luaL_pushmodule + luaL_pushresult + luaL_ref + luaL_register + luaL_setfuncs + luaL_setmetatable + luaL_testudata + luaL_traceback + luaL_typerror + luaL_unref + luaL_where + luaopen_base + luaopen_bit + luaopen_debug + luaopen_jit + luaopen_math + luaopen_os + luaopen_package + luaopen_string + luaopen_table diff --git a/lib/public/def/lua_shared.exp b/lib/public/def/lua_shared.exp new file mode 100644 index 0000000..3101a18 Binary files /dev/null and b/lib/public/def/lua_shared.exp differ diff --git a/lib/public/def/steam_api64.def b/lib/public/def/steam_api64.def new file mode 100644 index 0000000..64b76cf --- /dev/null +++ b/lib/public/def/steam_api64.def @@ -0,0 +1,942 @@ +EXPORTS + CAddAppDependencyResult_t_RemoveCallResult + CAddAppDependencyResult_t_SetCallResult + CAddUGCDependencyResult_t_RemoveCallResult + CAddUGCDependencyResult_t_SetCallResult + CAssociateWithClanResult_t_RemoveCallResult + CAssociateWithClanResult_t_SetCallResult + CChangeNumOpenSlotsCallback_t_RemoveCallResult + CChangeNumOpenSlotsCallback_t_SetCallResult + CCheckFileSignature_t_RemoveCallResult + CCheckFileSignature_t_SetCallResult + CClanOfficerListResponse_t_RemoveCallResult + CClanOfficerListResponse_t_SetCallResult + CComputeNewPlayerCompatibilityResult_t_RemoveCallResult + CComputeNewPlayerCompatibilityResult_t_SetCallResult + CCreateBeaconCallback_t_RemoveCallResult + CCreateBeaconCallback_t_SetCallResult + CCreateItemResult_t_RemoveCallResult + CCreateItemResult_t_SetCallResult + CDeleteItemResult_t_RemoveCallResult + CDeleteItemResult_t_SetCallResult + CEncryptedAppTicketResponse_t_RemoveCallResult + CEncryptedAppTicketResponse_t_SetCallResult + CFileDetailsResult_t_RemoveCallResult + CFileDetailsResult_t_SetCallResult + CFriendsEnumerateFollowingList_t_RemoveCallResult + CFriendsEnumerateFollowingList_t_SetCallResult + CFriendsGetFollowerCount_t_RemoveCallResult + CFriendsGetFollowerCount_t_SetCallResult + CFriendsIsFollowing_t_RemoveCallResult + CFriendsIsFollowing_t_SetCallResult + CGetAppDependenciesResult_t_RemoveCallResult + CGetAppDependenciesResult_t_SetCallResult + CGetOPFSettingsResult_t_RemoveCallback + CGetOPFSettingsResult_t_SetCallback + CGetUserItemVoteResult_t_RemoveCallResult + CGetUserItemVoteResult_t_SetCallResult + CGlobalAchievementPercentagesReady_t_RemoveCallResult + CGlobalAchievementPercentagesReady_t_SetCallResult + CGlobalStatsReceived_t_RemoveCallResult + CGlobalStatsReceived_t_SetCallResult + CGSReputation_t_RemoveCallResult + CGSReputation_t_SetCallResult + CGSStatsReceived_t_RemoveCallResult + CGSStatsReceived_t_SetCallResult + CGSStatsStored_t_RemoveCallResult + CGSStatsStored_t_SetCallResult + CHTML_BrowserReady_t_RemoveCallResult + CHTML_BrowserReady_t_SetCallResult + CJoinClanChatRoomCompletionResult_t_RemoveCallResult + CJoinClanChatRoomCompletionResult_t_SetCallResult + CJoinPartyCallback_t_RemoveCallResult + CJoinPartyCallback_t_SetCallResult + CLeaderboardFindResult_t_RemoveCallResult + CLeaderboardFindResult_t_SetCallResult + CLeaderboardScoresDownloaded_t_RemoveCallResult + CLeaderboardScoresDownloaded_t_SetCallResult + CLeaderboardScoreUploaded_t_RemoveCallResult + CLeaderboardScoreUploaded_t_SetCallResult + CLeaderboardUGCSet_t_RemoveCallResult + CLeaderboardUGCSet_t_SetCallResult + CLobbyCreated_t_RemoveCallResult + CLobbyCreated_t_SetCallResult + CLobbyEnter_t_RemoveCallResult + CLobbyEnter_t_SetCallResult + CLobbyMatchList_t_RemoveCallResult + CLobbyMatchList_t_SetCallResult + CMarketEligibilityResponse_t_RemoveCallResult + CMarketEligibilityResponse_t_SetCallResult + CNumberOfCurrentPlayers_t_RemoveCallResult + CNumberOfCurrentPlayers_t_SetCallResult + CRemoteStorageDeletePublishedFileResult_t_RemoveCallResult + CRemoteStorageDeletePublishedFileResult_t_SetCallResult + CRemoteStorageDownloadUGCResult_t_RemoveCallResult + CRemoteStorageDownloadUGCResult_t_SetCallResult + CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_RemoveCallResult + CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_SetCallResult + CRemoteStorageEnumerateUserPublishedFilesResult_t_RemoveCallResult + CRemoteStorageEnumerateUserPublishedFilesResult_t_SetCallResult + CRemoteStorageEnumerateUserSubscribedFilesResult_t_RemoveCallResult + CRemoteStorageEnumerateUserSubscribedFilesResult_t_SetCallResult + CRemoteStorageEnumerateWorkshopFilesResult_t_RemoveCallResult + CRemoteStorageEnumerateWorkshopFilesResult_t_SetCallResult + CRemoteStorageFileReadAsyncComplete_t_RemoveCallResult + CRemoteStorageFileReadAsyncComplete_t_SetCallResult + CRemoteStorageFileShareResult_t_RemoveCallResult + CRemoteStorageFileShareResult_t_SetCallResult + CRemoteStorageFileWriteAsyncComplete_t_RemoveCallResult + CRemoteStorageFileWriteAsyncComplete_t_SetCallResult + CRemoteStorageGetPublishedFileDetailsResult_t_RemoveCallResult + CRemoteStorageGetPublishedFileDetailsResult_t_SetCallResult + CRemoteStorageGetPublishedItemVoteDetailsResult_t_RemoveCallResult + CRemoteStorageGetPublishedItemVoteDetailsResult_t_SetCallResult + CRemoteStoragePublishFileProgress_t_RemoveCallResult + CRemoteStoragePublishFileProgress_t_SetCallResult + CRemoteStorageSetUserPublishedFileActionResult_t_RemoveCallResult + CRemoteStorageSetUserPublishedFileActionResult_t_SetCallResult + CRemoteStorageSubscribePublishedFileResult_t_RemoveCallResult + CRemoteStorageSubscribePublishedFileResult_t_SetCallResult + CRemoteStorageUnsubscribePublishedFileResult_t_RemoveCallResult + CRemoteStorageUnsubscribePublishedFileResult_t_SetCallResult + CRemoteStorageUpdatePublishedFileResult_t_RemoveCallResult + CRemoteStorageUpdatePublishedFileResult_t_SetCallResult + CRemoteStorageUpdateUserPublishedItemVoteResult_t_RemoveCallResult + CRemoteStorageUpdateUserPublishedItemVoteResult_t_SetCallResult + CRemoveAppDependencyResult_t_RemoveCallResult + CRemoveAppDependencyResult_t_SetCallResult + CRemoveUGCDependencyResult_t_RemoveCallResult + CRemoveUGCDependencyResult_t_SetCallResult + CSetPersonaNameResponse_t_RemoveCallResult + CSetPersonaNameResponse_t_SetCallResult + CSetUserItemVoteResult_t_RemoveCallResult + CSetUserItemVoteResult_t_SetCallResult + CStartPlaytimeTrackingResult_t_RemoveCallResult + CStartPlaytimeTrackingResult_t_SetCallResult + CSteamInventoryEligiblePromoItemDefIDs_t_RemoveCallResult + CSteamInventoryEligiblePromoItemDefIDs_t_SetCallResult + CSteamInventoryRequestPricesResult_t_RemoveCallResult + CSteamInventoryRequestPricesResult_t_SetCallResult + CSteamInventoryStartPurchaseResult_t_RemoveCallResult + CSteamInventoryStartPurchaseResult_t_SetCallResult + CSteamUGCQueryCompleted_t_RemoveCallResult + CSteamUGCQueryCompleted_t_SetCallResult + CStopPlaytimeTrackingResult_t_RemoveCallResult + CStopPlaytimeTrackingResult_t_SetCallResult + CStoreAuthURLResponse_t_RemoveCallResult + CStoreAuthURLResponse_t_SetCallResult + CSubmitItemUpdateResult_t_RemoveCallResult + CSubmitItemUpdateResult_t_SetCallResult + CUserFavoriteItemsListChanged_t_RemoveCallResult + CUserFavoriteItemsListChanged_t_SetCallResult + CUserStatsReceived_t_RemoveCallback + CUserStatsReceived_t_RemoveCallResult + CUserStatsReceived_t_SetCallback + CUserStatsReceived_t_SetCallResult + g_pSteamClientGameServer + GetHSteamPipe + GetHSteamUser + Steam_GetHSteamUserCurrent + Steam_RegisterInterfaceFuncs + Steam_RunCallbacks + SteamAPI_GetHSteamPipe + SteamAPI_GetHSteamUser + SteamAPI_GetSteamInstallPath + SteamAPI_Init + SteamAPI_InitAnonymousUser + SteamAPI_InitSafe + SteamAPI_IsSteamRunning + SteamAPI_ISteamAppList_GetAppBuildId + SteamAPI_ISteamAppList_GetAppInstallDir + SteamAPI_ISteamAppList_GetAppName + SteamAPI_ISteamAppList_GetInstalledApps + SteamAPI_ISteamAppList_GetNumInstalledApps + SteamAPI_ISteamApps_BGetDLCDataByIndex + SteamAPI_ISteamApps_BIsAppInstalled + SteamAPI_ISteamApps_BIsCybercafe + SteamAPI_ISteamApps_BIsDlcInstalled + SteamAPI_ISteamApps_BIsLowViolence + SteamAPI_ISteamApps_BIsSubscribed + SteamAPI_ISteamApps_BIsSubscribedApp + SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing + SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend + SteamAPI_ISteamApps_BIsVACBanned + SteamAPI_ISteamApps_GetAppBuildId + SteamAPI_ISteamApps_GetAppInstallDir + SteamAPI_ISteamApps_GetAppOwner + SteamAPI_ISteamApps_GetAvailableGameLanguages + SteamAPI_ISteamApps_GetCurrentBetaName + SteamAPI_ISteamApps_GetCurrentGameLanguage + SteamAPI_ISteamApps_GetDLCCount + SteamAPI_ISteamApps_GetDlcDownloadProgress + SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime + SteamAPI_ISteamApps_GetFileDetails + SteamAPI_ISteamApps_GetInstalledDepots + SteamAPI_ISteamApps_GetLaunchCommandLine + SteamAPI_ISteamApps_GetLaunchQueryParam + SteamAPI_ISteamApps_InstallDLC + SteamAPI_ISteamApps_MarkContentCorrupt + SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys + SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey + SteamAPI_ISteamApps_UninstallDLC + SteamAPI_ISteamClient_BReleaseSteamPipe + SteamAPI_ISteamClient_BShutdownIfAllPipesClosed + SteamAPI_ISteamClient_ConnectToGlobalUser + SteamAPI_ISteamClient_CreateLocalUser + SteamAPI_ISteamClient_CreateSteamPipe + SteamAPI_ISteamClient_GetIPCCallCount + SteamAPI_ISteamClient_GetISteamAppList + SteamAPI_ISteamClient_GetISteamApps + SteamAPI_ISteamClient_GetISteamController + SteamAPI_ISteamClient_GetISteamFriends + SteamAPI_ISteamClient_GetISteamGameSearch + SteamAPI_ISteamClient_GetISteamGameServer + SteamAPI_ISteamClient_GetISteamGameServerStats + SteamAPI_ISteamClient_GetISteamGenericInterface + SteamAPI_ISteamClient_GetISteamHTMLSurface + SteamAPI_ISteamClient_GetISteamHTTP + SteamAPI_ISteamClient_GetISteamInput + SteamAPI_ISteamClient_GetISteamInventory + SteamAPI_ISteamClient_GetISteamMatchmaking + SteamAPI_ISteamClient_GetISteamMatchmakingServers + SteamAPI_ISteamClient_GetISteamMusic + SteamAPI_ISteamClient_GetISteamMusicRemote + SteamAPI_ISteamClient_GetISteamNetworking + SteamAPI_ISteamClient_GetISteamParentalSettings + SteamAPI_ISteamClient_GetISteamParties + SteamAPI_ISteamClient_GetISteamRemoteStorage + SteamAPI_ISteamClient_GetISteamScreenshots + SteamAPI_ISteamClient_GetISteamUGC + SteamAPI_ISteamClient_GetISteamUser + SteamAPI_ISteamClient_GetISteamUserStats + SteamAPI_ISteamClient_GetISteamUtils + SteamAPI_ISteamClient_GetISteamVideo + SteamAPI_ISteamClient_ReleaseUser + SteamAPI_ISteamClient_SetLocalIPBinding + SteamAPI_ISteamClient_SetWarningMessageHook + SteamAPI_ISteamController_ActivateActionSet + SteamAPI_ISteamController_ActivateActionSetLayer + SteamAPI_ISteamController_DeactivateActionSetLayer + SteamAPI_ISteamController_DeactivateAllActionSetLayers + SteamAPI_ISteamController_GetActionOriginFromXboxOrigin + SteamAPI_ISteamController_GetActionSetHandle + SteamAPI_ISteamController_GetActiveActionSetLayers + SteamAPI_ISteamController_GetAnalogActionData + SteamAPI_ISteamController_GetAnalogActionHandle + SteamAPI_ISteamController_GetAnalogActionOrigins + SteamAPI_ISteamController_GetConnectedControllers + SteamAPI_ISteamController_GetControllerForGamepadIndex + SteamAPI_ISteamController_GetCurrentActionSet + SteamAPI_ISteamController_GetDigitalActionData + SteamAPI_ISteamController_GetDigitalActionHandle + SteamAPI_ISteamController_GetDigitalActionOrigins + SteamAPI_ISteamController_GetGamepadIndexForController + SteamAPI_ISteamController_GetGlyphForActionOrigin + SteamAPI_ISteamController_GetGlyphForXboxOrigin + SteamAPI_ISteamController_GetInputTypeForHandle + SteamAPI_ISteamController_GetMotionData + SteamAPI_ISteamController_GetStringForActionOrigin + SteamAPI_ISteamController_GetStringForXboxOrigin + SteamAPI_ISteamController_Init + SteamAPI_ISteamController_RunFrame + SteamAPI_ISteamController_SetLEDColor + SteamAPI_ISteamController_ShowBindingPanel + SteamAPI_ISteamController_Shutdown + SteamAPI_ISteamController_StopAnalogActionMomentum + SteamAPI_ISteamController_TranslateActionOrigin + SteamAPI_ISteamController_TriggerHapticPulse + SteamAPI_ISteamController_TriggerRepeatedHapticPulse + SteamAPI_ISteamController_TriggerVibration + SteamAPI_ISteamFriends_ActivateGameOverlay + SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog + SteamAPI_ISteamFriends_ActivateGameOverlayToStore + SteamAPI_ISteamFriends_ActivateGameOverlayToUser + SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage + SteamAPI_ISteamFriends_ClearRichPresence + SteamAPI_ISteamFriends_CloseClanChatWindowInSteam + SteamAPI_ISteamFriends_DownloadClanActivityCounts + SteamAPI_ISteamFriends_EnumerateFollowingList + SteamAPI_ISteamFriends_GetChatMemberByIndex + SteamAPI_ISteamFriends_GetClanActivityCounts + SteamAPI_ISteamFriends_GetClanByIndex + SteamAPI_ISteamFriends_GetClanChatMemberCount + SteamAPI_ISteamFriends_GetClanChatMessage + SteamAPI_ISteamFriends_GetClanCount + SteamAPI_ISteamFriends_GetClanName + SteamAPI_ISteamFriends_GetClanOfficerByIndex + SteamAPI_ISteamFriends_GetClanOfficerCount + SteamAPI_ISteamFriends_GetClanOwner + SteamAPI_ISteamFriends_GetClanTag + SteamAPI_ISteamFriends_GetCoplayFriend + SteamAPI_ISteamFriends_GetCoplayFriendCount + SteamAPI_ISteamFriends_GetFollowerCount + SteamAPI_ISteamFriends_GetFriendByIndex + SteamAPI_ISteamFriends_GetFriendCoplayGame + SteamAPI_ISteamFriends_GetFriendCoplayTime + SteamAPI_ISteamFriends_GetFriendCount + SteamAPI_ISteamFriends_GetFriendCountFromSource + SteamAPI_ISteamFriends_GetFriendFromSourceByIndex + SteamAPI_ISteamFriends_GetFriendGamePlayed + SteamAPI_ISteamFriends_GetFriendMessage + SteamAPI_ISteamFriends_GetFriendPersonaName + SteamAPI_ISteamFriends_GetFriendPersonaNameHistory + SteamAPI_ISteamFriends_GetFriendPersonaState + SteamAPI_ISteamFriends_GetFriendRelationship + SteamAPI_ISteamFriends_GetFriendRichPresence + SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex + SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount + SteamAPI_ISteamFriends_GetFriendsGroupCount + SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex + SteamAPI_ISteamFriends_GetFriendsGroupMembersCount + SteamAPI_ISteamFriends_GetFriendsGroupMembersList + SteamAPI_ISteamFriends_GetFriendsGroupName + SteamAPI_ISteamFriends_GetFriendSteamLevel + SteamAPI_ISteamFriends_GetLargeFriendAvatar + SteamAPI_ISteamFriends_GetMediumFriendAvatar + SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages + SteamAPI_ISteamFriends_GetPersonaName + SteamAPI_ISteamFriends_GetPersonaState + SteamAPI_ISteamFriends_GetPlayerNickname + SteamAPI_ISteamFriends_GetSmallFriendAvatar + SteamAPI_ISteamFriends_GetUserRestrictions + SteamAPI_ISteamFriends_HasFriend + SteamAPI_ISteamFriends_InviteUserToGame + SteamAPI_ISteamFriends_IsClanChatAdmin + SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam + SteamAPI_ISteamFriends_IsClanOfficialGameGroup + SteamAPI_ISteamFriends_IsClanPublic + SteamAPI_ISteamFriends_IsFollowing + SteamAPI_ISteamFriends_IsUserInSource + SteamAPI_ISteamFriends_JoinClanChatRoom + SteamAPI_ISteamFriends_LeaveClanChatRoom + SteamAPI_ISteamFriends_OpenClanChatWindowInSteam + SteamAPI_ISteamFriends_ReplyToFriendMessage + SteamAPI_ISteamFriends_RequestClanOfficerList + SteamAPI_ISteamFriends_RequestFriendRichPresence + SteamAPI_ISteamFriends_RequestUserInformation + SteamAPI_ISteamFriends_SendClanChatMessage + SteamAPI_ISteamFriends_SetInGameVoiceSpeaking + SteamAPI_ISteamFriends_SetListenForFriendsMessages + SteamAPI_ISteamFriends_SetPersonaName + SteamAPI_ISteamFriends_SetPlayedWith + SteamAPI_ISteamFriends_SetRichPresence + SteamAPI_ISteamGameSearch_AcceptGame + SteamAPI_ISteamGameSearch_AddGameSearchParams + SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame + SteamAPI_ISteamGameSearch_DeclineGame + SteamAPI_ISteamGameSearch_EndGame + SteamAPI_ISteamGameSearch_EndGameSearch + SteamAPI_ISteamGameSearch_HostConfirmGameStart + SteamAPI_ISteamGameSearch_RequestPlayersForGame + SteamAPI_ISteamGameSearch_RetrieveConnectionDetails + SteamAPI_ISteamGameSearch_SearchForGameSolo + SteamAPI_ISteamGameSearch_SearchForGameWithLobby + SteamAPI_ISteamGameSearch_SetConnectionDetails + SteamAPI_ISteamGameSearch_SetGameHostParams + SteamAPI_ISteamGameSearch_SubmitPlayerResult + SteamAPI_ISteamGameServer_AssociateWithClan + SteamAPI_ISteamGameServer_BeginAuthSession + SteamAPI_ISteamGameServer_BLoggedOn + SteamAPI_ISteamGameServer_BSecure + SteamAPI_ISteamGameServer_BUpdateUserData + SteamAPI_ISteamGameServer_CancelAuthTicket + SteamAPI_ISteamGameServer_ClearAllKeyValues + SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility + SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection + SteamAPI_ISteamGameServer_EnableHeartbeats + SteamAPI_ISteamGameServer_EndAuthSession + SteamAPI_ISteamGameServer_ForceHeartbeat + SteamAPI_ISteamGameServer_GetAuthSessionTicket + SteamAPI_ISteamGameServer_GetGameplayStats + SteamAPI_ISteamGameServer_GetNextOutgoingPacket + SteamAPI_ISteamGameServer_GetPublicIP + SteamAPI_ISteamGameServer_GetServerReputation + SteamAPI_ISteamGameServer_GetSteamID + SteamAPI_ISteamGameServer_HandleIncomingPacket + SteamAPI_ISteamGameServer_InitGameServer + SteamAPI_ISteamGameServer_LogOff + SteamAPI_ISteamGameServer_LogOn + SteamAPI_ISteamGameServer_LogOnAnonymous + SteamAPI_ISteamGameServer_RequestUserGroupStatus + SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate + SteamAPI_ISteamGameServer_SendUserDisconnect + SteamAPI_ISteamGameServer_SetBotPlayerCount + SteamAPI_ISteamGameServer_SetDedicatedServer + SteamAPI_ISteamGameServer_SetGameData + SteamAPI_ISteamGameServer_SetGameDescription + SteamAPI_ISteamGameServer_SetGameTags + SteamAPI_ISteamGameServer_SetHeartbeatInterval + SteamAPI_ISteamGameServer_SetKeyValue + SteamAPI_ISteamGameServer_SetMapName + SteamAPI_ISteamGameServer_SetMaxPlayerCount + SteamAPI_ISteamGameServer_SetModDir + SteamAPI_ISteamGameServer_SetPasswordProtected + SteamAPI_ISteamGameServer_SetProduct + SteamAPI_ISteamGameServer_SetRegion + SteamAPI_ISteamGameServer_SetServerName + SteamAPI_ISteamGameServer_SetSpectatorPort + SteamAPI_ISteamGameServer_SetSpectatorServerName + SteamAPI_ISteamGameServer_UserHasLicenseForApp + SteamAPI_ISteamGameServer_WasRestartRequested + SteamAPI_ISteamGameServerStats_ClearUserAchievement + SteamAPI_ISteamGameServerStats_GetUserAchievement + SteamAPI_ISteamGameServerStats_GetUserStat + SteamAPI_ISteamGameServerStats_GetUserStat0 + SteamAPI_ISteamGameServerStats_RequestUserStats + SteamAPI_ISteamGameServerStats_SetUserAchievement + SteamAPI_ISteamGameServerStats_SetUserStat + SteamAPI_ISteamGameServerStats_SetUserStat0 + SteamAPI_ISteamGameServerStats_StoreUserStats + SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat + SteamAPI_ISteamHTMLSurface_AddHeader + SteamAPI_ISteamHTMLSurface_AllowStartRequest + SteamAPI_ISteamHTMLSurface_CopyToClipboard + SteamAPI_ISteamHTMLSurface_CreateBrowser + SteamAPI_ISteamHTMLSurface_DestructISteamHTMLSurface + SteamAPI_ISteamHTMLSurface_ExecuteJavascript + SteamAPI_ISteamHTMLSurface_Find + SteamAPI_ISteamHTMLSurface_GetLinkAtPosition + SteamAPI_ISteamHTMLSurface_GoBack + SteamAPI_ISteamHTMLSurface_GoForward + SteamAPI_ISteamHTMLSurface_Init + SteamAPI_ISteamHTMLSurface_JSDialogResponse + SteamAPI_ISteamHTMLSurface_KeyChar + SteamAPI_ISteamHTMLSurface_KeyDown + SteamAPI_ISteamHTMLSurface_KeyUp + SteamAPI_ISteamHTMLSurface_LoadURL + SteamAPI_ISteamHTMLSurface_MouseDoubleClick + SteamAPI_ISteamHTMLSurface_MouseDown + SteamAPI_ISteamHTMLSurface_MouseMove + SteamAPI_ISteamHTMLSurface_MouseUp + SteamAPI_ISteamHTMLSurface_MouseWheel + SteamAPI_ISteamHTMLSurface_OpenDeveloperTools + SteamAPI_ISteamHTMLSurface_PasteFromClipboard + SteamAPI_ISteamHTMLSurface_Reload + SteamAPI_ISteamHTMLSurface_RemoveBrowser + SteamAPI_ISteamHTMLSurface_SetBackgroundMode + SteamAPI_ISteamHTMLSurface_SetCookie + SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor + SteamAPI_ISteamHTMLSurface_SetHorizontalScroll + SteamAPI_ISteamHTMLSurface_SetKeyFocus + SteamAPI_ISteamHTMLSurface_SetPageScaleFactor + SteamAPI_ISteamHTMLSurface_SetSize + SteamAPI_ISteamHTMLSurface_SetVerticalScroll + SteamAPI_ISteamHTMLSurface_Shutdown + SteamAPI_ISteamHTMLSurface_StopFind + SteamAPI_ISteamHTMLSurface_StopLoad + SteamAPI_ISteamHTMLSurface_ViewSource + SteamAPI_ISteamHTTP_CreateCookieContainer + SteamAPI_ISteamHTTP_CreateHTTPRequest + SteamAPI_ISteamHTTP_DeferHTTPRequest + SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct + SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut + SteamAPI_ISteamHTTP_GetHTTPResponseBodyData + SteamAPI_ISteamHTTP_GetHTTPResponseBodySize + SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize + SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue + SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData + SteamAPI_ISteamHTTP_PrioritizeHTTPRequest + SteamAPI_ISteamHTTP_ReleaseCookieContainer + SteamAPI_ISteamHTTP_ReleaseHTTPRequest + SteamAPI_ISteamHTTP_SendHTTPRequest + SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse + SteamAPI_ISteamHTTP_SetCookie + SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS + SteamAPI_ISteamHTTP_SetHTTPRequestContextValue + SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer + SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter + SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue + SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout + SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody + SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate + SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo + SteamAPI_ISteamInput_ActivateActionSet + SteamAPI_ISteamInput_ActivateActionSetLayer + SteamAPI_ISteamInput_DeactivateActionSetLayer + SteamAPI_ISteamInput_DeactivateAllActionSetLayers + SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin + SteamAPI_ISteamInput_GetActionSetHandle + SteamAPI_ISteamInput_GetActiveActionSetLayers + SteamAPI_ISteamInput_GetAnalogActionData + SteamAPI_ISteamInput_GetAnalogActionHandle + SteamAPI_ISteamInput_GetAnalogActionOrigins + SteamAPI_ISteamInput_GetConnectedControllers + SteamAPI_ISteamInput_GetControllerForGamepadIndex + SteamAPI_ISteamInput_GetCurrentActionSet + SteamAPI_ISteamInput_GetDigitalActionData + SteamAPI_ISteamInput_GetDigitalActionHandle + SteamAPI_ISteamInput_GetDigitalActionOrigins + SteamAPI_ISteamInput_GetGamepadIndexForController + SteamAPI_ISteamInput_GetGlyphForActionOrigin + SteamAPI_ISteamInput_GetGlyphForXboxOrigin + SteamAPI_ISteamInput_GetInputTypeForHandle + SteamAPI_ISteamInput_GetMotionData + SteamAPI_ISteamInput_GetStringForActionOrigin + SteamAPI_ISteamInput_GetStringForXboxOrigin + SteamAPI_ISteamInput_Init + SteamAPI_ISteamInput_RunFrame + SteamAPI_ISteamInput_SetLEDColor + SteamAPI_ISteamInput_ShowBindingPanel + SteamAPI_ISteamInput_Shutdown + SteamAPI_ISteamInput_StopAnalogActionMomentum + SteamAPI_ISteamInput_TranslateActionOrigin + SteamAPI_ISteamInput_TriggerHapticPulse + SteamAPI_ISteamInput_TriggerRepeatedHapticPulse + SteamAPI_ISteamInput_TriggerVibration + SteamAPI_ISteamInventory_AddPromoItem + SteamAPI_ISteamInventory_AddPromoItems + SteamAPI_ISteamInventory_CheckResultSteamID + SteamAPI_ISteamInventory_ConsumeItem + SteamAPI_ISteamInventory_DeserializeResult + SteamAPI_ISteamInventory_DestroyResult + SteamAPI_ISteamInventory_ExchangeItems + SteamAPI_ISteamInventory_GenerateItems + SteamAPI_ISteamInventory_GetAllItems + SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs + SteamAPI_ISteamInventory_GetItemDefinitionIDs + SteamAPI_ISteamInventory_GetItemDefinitionProperty + SteamAPI_ISteamInventory_GetItemPrice + SteamAPI_ISteamInventory_GetItemsByID + SteamAPI_ISteamInventory_GetItemsWithPrices + SteamAPI_ISteamInventory_GetNumItemsWithPrices + SteamAPI_ISteamInventory_GetResultItemProperty + SteamAPI_ISteamInventory_GetResultItems + SteamAPI_ISteamInventory_GetResultStatus + SteamAPI_ISteamInventory_GetResultTimestamp + SteamAPI_ISteamInventory_GrantPromoItems + SteamAPI_ISteamInventory_LoadItemDefinitions + SteamAPI_ISteamInventory_RemoveProperty + SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs + SteamAPI_ISteamInventory_RequestPrices + SteamAPI_ISteamInventory_SendItemDropHeartbeat + SteamAPI_ISteamInventory_SerializeResult + SteamAPI_ISteamInventory_SetProperty + SteamAPI_ISteamInventory_SetProperty0 + SteamAPI_ISteamInventory_SetProperty1 + SteamAPI_ISteamInventory_SetProperty2 + SteamAPI_ISteamInventory_StartPurchase + SteamAPI_ISteamInventory_StartUpdateProperties + SteamAPI_ISteamInventory_SubmitUpdateProperties + SteamAPI_ISteamInventory_TradeItems + SteamAPI_ISteamInventory_TransferItemQuantity + SteamAPI_ISteamInventory_TriggerItemDrop + SteamAPI_ISteamMatchmaking_AddFavoriteGame + SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter + SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter + SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable + SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter + SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter + SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter + SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter + SteamAPI_ISteamMatchmaking_CreateLobby + SteamAPI_ISteamMatchmaking_DeleteLobbyData + SteamAPI_ISteamMatchmaking_GetFavoriteGame + SteamAPI_ISteamMatchmaking_GetFavoriteGameCount + SteamAPI_ISteamMatchmaking_GetLobbyByIndex + SteamAPI_ISteamMatchmaking_GetLobbyChatEntry + SteamAPI_ISteamMatchmaking_GetLobbyData + SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex + SteamAPI_ISteamMatchmaking_GetLobbyDataCount + SteamAPI_ISteamMatchmaking_GetLobbyGameServer + SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex + SteamAPI_ISteamMatchmaking_GetLobbyMemberData + SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit + SteamAPI_ISteamMatchmaking_GetLobbyOwner + SteamAPI_ISteamMatchmaking_GetNumLobbyMembers + SteamAPI_ISteamMatchmaking_InviteUserToLobby + SteamAPI_ISteamMatchmaking_JoinLobby + SteamAPI_ISteamMatchmaking_LeaveLobby + SteamAPI_ISteamMatchmaking_RemoveFavoriteGame + SteamAPI_ISteamMatchmaking_RequestLobbyData + SteamAPI_ISteamMatchmaking_RequestLobbyList + SteamAPI_ISteamMatchmaking_SendLobbyChatMsg + SteamAPI_ISteamMatchmaking_SetLinkedLobby + SteamAPI_ISteamMatchmaking_SetLobbyData + SteamAPI_ISteamMatchmaking_SetLobbyGameServer + SteamAPI_ISteamMatchmaking_SetLobbyJoinable + SteamAPI_ISteamMatchmaking_SetLobbyMemberData + SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit + SteamAPI_ISteamMatchmaking_SetLobbyOwner + SteamAPI_ISteamMatchmaking_SetLobbyType + SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond + SteamAPI_ISteamMatchmakingPingResponse_ServerResponded + SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList + SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond + SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete + SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond + SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete + SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded + SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete + SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond + SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded + SteamAPI_ISteamMatchmakingServers_CancelQuery + SteamAPI_ISteamMatchmakingServers_CancelServerQuery + SteamAPI_ISteamMatchmakingServers_GetServerCount + SteamAPI_ISteamMatchmakingServers_GetServerDetails + SteamAPI_ISteamMatchmakingServers_IsRefreshing + SteamAPI_ISteamMatchmakingServers_PingServer + SteamAPI_ISteamMatchmakingServers_PlayerDetails + SteamAPI_ISteamMatchmakingServers_RefreshQuery + SteamAPI_ISteamMatchmakingServers_RefreshServer + SteamAPI_ISteamMatchmakingServers_ReleaseRequest + SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList + SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList + SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList + SteamAPI_ISteamMatchmakingServers_RequestInternetServerList + SteamAPI_ISteamMatchmakingServers_RequestLANServerList + SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList + SteamAPI_ISteamMatchmakingServers_ServerRules + SteamAPI_ISteamMusic_BIsEnabled + SteamAPI_ISteamMusic_BIsPlaying + SteamAPI_ISteamMusic_GetPlaybackStatus + SteamAPI_ISteamMusic_GetVolume + SteamAPI_ISteamMusic_Pause + SteamAPI_ISteamMusic_Play + SteamAPI_ISteamMusic_PlayNext + SteamAPI_ISteamMusic_PlayPrevious + SteamAPI_ISteamMusic_SetVolume + SteamAPI_ISteamMusicRemote_BActivationSuccess + SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote + SteamAPI_ISteamMusicRemote_CurrentEntryDidChange + SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable + SteamAPI_ISteamMusicRemote_CurrentEntryWillChange + SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote + SteamAPI_ISteamMusicRemote_EnableLooped + SteamAPI_ISteamMusicRemote_EnablePlaylists + SteamAPI_ISteamMusicRemote_EnablePlayNext + SteamAPI_ISteamMusicRemote_EnablePlayPrevious + SteamAPI_ISteamMusicRemote_EnableQueue + SteamAPI_ISteamMusicRemote_EnableShuffled + SteamAPI_ISteamMusicRemote_PlaylistDidChange + SteamAPI_ISteamMusicRemote_PlaylistWillChange + SteamAPI_ISteamMusicRemote_QueueDidChange + SteamAPI_ISteamMusicRemote_QueueWillChange + SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote + SteamAPI_ISteamMusicRemote_ResetPlaylistEntries + SteamAPI_ISteamMusicRemote_ResetQueueEntries + SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry + SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry + SteamAPI_ISteamMusicRemote_SetDisplayName + SteamAPI_ISteamMusicRemote_SetPlaylistEntry + SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64 + SteamAPI_ISteamMusicRemote_SetQueueEntry + SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt + SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds + SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText + SteamAPI_ISteamMusicRemote_UpdateLooped + SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus + SteamAPI_ISteamMusicRemote_UpdateShuffled + SteamAPI_ISteamMusicRemote_UpdateVolume + SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser + SteamAPI_ISteamNetworking_AllowP2PPacketRelay + SteamAPI_ISteamNetworking_CloseP2PChannelWithUser + SteamAPI_ISteamNetworking_CloseP2PSessionWithUser + SteamAPI_ISteamNetworking_CreateConnectionSocket + SteamAPI_ISteamNetworking_CreateListenSocket + SteamAPI_ISteamNetworking_CreateP2PConnectionSocket + SteamAPI_ISteamNetworking_DestroyListenSocket + SteamAPI_ISteamNetworking_DestroySocket + SteamAPI_ISteamNetworking_GetListenSocketInfo + SteamAPI_ISteamNetworking_GetMaxPacketSize + SteamAPI_ISteamNetworking_GetP2PSessionState + SteamAPI_ISteamNetworking_GetSocketConnectionType + SteamAPI_ISteamNetworking_GetSocketInfo + SteamAPI_ISteamNetworking_IsDataAvailable + SteamAPI_ISteamNetworking_IsDataAvailableOnSocket + SteamAPI_ISteamNetworking_IsP2PPacketAvailable + SteamAPI_ISteamNetworking_ReadP2PPacket + SteamAPI_ISteamNetworking_RetrieveData + SteamAPI_ISteamNetworking_RetrieveDataFromSocket + SteamAPI_ISteamNetworking_SendDataOnSocket + SteamAPI_ISteamNetworking_SendP2PPacket + SteamAPI_ISteamParentalSettings_BIsAppBlocked + SteamAPI_ISteamParentalSettings_BIsAppInBlockList + SteamAPI_ISteamParentalSettings_BIsFeatureBlocked + SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList + SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled + SteamAPI_ISteamParentalSettings_BIsParentalLockLocked + SteamAPI_ISteamParties_CancelReservation + SteamAPI_ISteamParties_ChangeNumOpenSlots + SteamAPI_ISteamParties_CreateBeacon + SteamAPI_ISteamParties_DestroyBeacon + SteamAPI_ISteamParties_GetAvailableBeaconLocations + SteamAPI_ISteamParties_GetBeaconByIndex + SteamAPI_ISteamParties_GetBeaconDetails + SteamAPI_ISteamParties_GetBeaconLocationData + SteamAPI_ISteamParties_GetNumActiveBeacons + SteamAPI_ISteamParties_GetNumAvailableBeaconLocations + SteamAPI_ISteamParties_JoinParty + SteamAPI_ISteamParties_OnReservationCompleted + SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate + SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest + SteamAPI_ISteamRemoteStorage_DeletePublishedFile + SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction + SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles + SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles + SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles + SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles + SteamAPI_ISteamRemoteStorage_FileDelete + SteamAPI_ISteamRemoteStorage_FileExists + SteamAPI_ISteamRemoteStorage_FileForget + SteamAPI_ISteamRemoteStorage_FilePersisted + SteamAPI_ISteamRemoteStorage_FileRead + SteamAPI_ISteamRemoteStorage_FileReadAsync + SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete + SteamAPI_ISteamRemoteStorage_FileShare + SteamAPI_ISteamRemoteStorage_FileWrite + SteamAPI_ISteamRemoteStorage_FileWriteAsync + SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel + SteamAPI_ISteamRemoteStorage_FileWriteStreamClose + SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen + SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk + SteamAPI_ISteamRemoteStorage_GetCachedUGCCount + SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle + SteamAPI_ISteamRemoteStorage_GetFileCount + SteamAPI_ISteamRemoteStorage_GetFileNameAndSize + SteamAPI_ISteamRemoteStorage_GetFileSize + SteamAPI_ISteamRemoteStorage_GetFileTimestamp + SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails + SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails + SteamAPI_ISteamRemoteStorage_GetQuota + SteamAPI_ISteamRemoteStorage_GetSyncPlatforms + SteamAPI_ISteamRemoteStorage_GetUGCDetails + SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress + SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails + SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount + SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp + SteamAPI_ISteamRemoteStorage_PublishVideo + SteamAPI_ISteamRemoteStorage_PublishWorkshopFile + SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp + SteamAPI_ISteamRemoteStorage_SetSyncPlatforms + SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction + SteamAPI_ISteamRemoteStorage_SubscribePublishedFile + SteamAPI_ISteamRemoteStorage_UGCDownload + SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation + SteamAPI_ISteamRemoteStorage_UGCRead + SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile + SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription + SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile + SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile + SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription + SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags + SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle + SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility + SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote + SteamAPI_ISteamScreenshots_AddScreenshotToLibrary + SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary + SteamAPI_ISteamScreenshots_HookScreenshots + SteamAPI_ISteamScreenshots_IsScreenshotsHooked + SteamAPI_ISteamScreenshots_SetLocation + SteamAPI_ISteamScreenshots_TagPublishedFile + SteamAPI_ISteamScreenshots_TagUser + SteamAPI_ISteamScreenshots_TriggerScreenshot + SteamAPI_ISteamScreenshots_WriteScreenshot + SteamAPI_ISteamUGC_AddAppDependency + SteamAPI_ISteamUGC_AddDependency + SteamAPI_ISteamUGC_AddExcludedTag + SteamAPI_ISteamUGC_AddItemKeyValueTag + SteamAPI_ISteamUGC_AddItemPreviewFile + SteamAPI_ISteamUGC_AddItemPreviewVideo + SteamAPI_ISteamUGC_AddItemToFavorites + SteamAPI_ISteamUGC_AddRequiredKeyValueTag + SteamAPI_ISteamUGC_AddRequiredTag + SteamAPI_ISteamUGC_BInitWorkshopForGameServer + SteamAPI_ISteamUGC_CreateItem + SteamAPI_ISteamUGC_CreateQueryAllUGCRequest + SteamAPI_ISteamUGC_CreateQueryAllUGCRequest0 + SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest + SteamAPI_ISteamUGC_CreateQueryUserUGCRequest + SteamAPI_ISteamUGC_DeleteItem + SteamAPI_ISteamUGC_DownloadItem + SteamAPI_ISteamUGC_GetAppDependencies + SteamAPI_ISteamUGC_GetItemDownloadInfo + SteamAPI_ISteamUGC_GetItemInstallInfo + SteamAPI_ISteamUGC_GetItemState + SteamAPI_ISteamUGC_GetItemUpdateProgress + SteamAPI_ISteamUGC_GetNumSubscribedItems + SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview + SteamAPI_ISteamUGC_GetQueryUGCChildren + SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag + SteamAPI_ISteamUGC_GetQueryUGCMetadata + SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews + SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags + SteamAPI_ISteamUGC_GetQueryUGCPreviewURL + SteamAPI_ISteamUGC_GetQueryUGCResult + SteamAPI_ISteamUGC_GetQueryUGCStatistic + SteamAPI_ISteamUGC_GetSubscribedItems + SteamAPI_ISteamUGC_GetUserItemVote + SteamAPI_ISteamUGC_ReleaseQueryUGCRequest + SteamAPI_ISteamUGC_RemoveAppDependency + SteamAPI_ISteamUGC_RemoveDependency + SteamAPI_ISteamUGC_RemoveItemFromFavorites + SteamAPI_ISteamUGC_RemoveItemKeyValueTags + SteamAPI_ISteamUGC_RemoveItemPreview + SteamAPI_ISteamUGC_RequestUGCDetails + SteamAPI_ISteamUGC_SendQueryUGCRequest + SteamAPI_ISteamUGC_SetAllowCachedResponse + SteamAPI_ISteamUGC_SetAllowLegacyUpload + SteamAPI_ISteamUGC_SetCloudFileNameFilter + SteamAPI_ISteamUGC_SetItemContent + SteamAPI_ISteamUGC_SetItemDescription + SteamAPI_ISteamUGC_SetItemMetadata + SteamAPI_ISteamUGC_SetItemPreview + SteamAPI_ISteamUGC_SetItemTags + SteamAPI_ISteamUGC_SetItemTitle + SteamAPI_ISteamUGC_SetItemUpdateLanguage + SteamAPI_ISteamUGC_SetItemVisibility + SteamAPI_ISteamUGC_SetLanguage + SteamAPI_ISteamUGC_SetMatchAnyTag + SteamAPI_ISteamUGC_SetRankedByTrendDays + SteamAPI_ISteamUGC_SetReturnAdditionalPreviews + SteamAPI_ISteamUGC_SetReturnChildren + SteamAPI_ISteamUGC_SetReturnKeyValueTags + SteamAPI_ISteamUGC_SetReturnLongDescription + SteamAPI_ISteamUGC_SetReturnMetadata + SteamAPI_ISteamUGC_SetReturnOnlyIDs + SteamAPI_ISteamUGC_SetReturnPlaytimeStats + SteamAPI_ISteamUGC_SetReturnTotalOnly + SteamAPI_ISteamUGC_SetSearchText + SteamAPI_ISteamUGC_SetUserItemVote + SteamAPI_ISteamUGC_StartItemUpdate + SteamAPI_ISteamUGC_StartPlaytimeTracking + SteamAPI_ISteamUGC_StopPlaytimeTracking + SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems + SteamAPI_ISteamUGC_SubmitItemUpdate + SteamAPI_ISteamUGC_SubscribeItem + SteamAPI_ISteamUGC_SuspendDownloads + SteamAPI_ISteamUGC_UnsubscribeItem + SteamAPI_ISteamUGC_UpdateItemPreviewFile + SteamAPI_ISteamUGC_UpdateItemPreviewVideo + SteamAPI_ISteamUser_AdvertiseGame + SteamAPI_ISteamUser_BeginAuthSession + SteamAPI_ISteamUser_BIsBehindNAT + SteamAPI_ISteamUser_BIsPhoneIdentifying + SteamAPI_ISteamUser_BIsPhoneRequiringVerification + SteamAPI_ISteamUser_BIsPhoneVerified + SteamAPI_ISteamUser_BIsTwoFactorEnabled + SteamAPI_ISteamUser_BLoggedOn + SteamAPI_ISteamUser_CancelAuthTicket + SteamAPI_ISteamUser_DecompressVoice + SteamAPI_ISteamUser_EndAuthSession + SteamAPI_ISteamUser_GetAuthSessionTicket + SteamAPI_ISteamUser_GetAvailableVoice + SteamAPI_ISteamUser_GetEncryptedAppTicket + SteamAPI_ISteamUser_GetGameBadgeLevel + SteamAPI_ISteamUser_GetHSteamUser + SteamAPI_ISteamUser_GetMarketEligibility + SteamAPI_ISteamUser_GetPlayerSteamLevel + SteamAPI_ISteamUser_GetSteamID + SteamAPI_ISteamUser_GetUserDataFolder + SteamAPI_ISteamUser_GetVoice + SteamAPI_ISteamUser_GetVoiceOptimalSampleRate + SteamAPI_ISteamUser_InitiateGameConnection + SteamAPI_ISteamUser_RequestEncryptedAppTicket + SteamAPI_ISteamUser_RequestStoreAuthURL + SteamAPI_ISteamUser_StartVoiceRecording + SteamAPI_ISteamUser_StopVoiceRecording + SteamAPI_ISteamUser_TerminateGameConnection + SteamAPI_ISteamUser_TrackAppUsageEvent + SteamAPI_ISteamUser_UserHasLicenseForApp + SteamAPI_ISteamUserStats_AttachLeaderboardUGC + SteamAPI_ISteamUserStats_ClearAchievement + SteamAPI_ISteamUserStats_DownloadLeaderboardEntries + SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers + SteamAPI_ISteamUserStats_FindLeaderboard + SteamAPI_ISteamUserStats_FindOrCreateLeaderboard + SteamAPI_ISteamUserStats_GetAchievement + SteamAPI_ISteamUserStats_GetAchievementAchievedPercent + SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime + SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute + SteamAPI_ISteamUserStats_GetAchievementIcon + SteamAPI_ISteamUserStats_GetAchievementName + SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry + SteamAPI_ISteamUserStats_GetGlobalStat + SteamAPI_ISteamUserStats_GetGlobalStat0 + SteamAPI_ISteamUserStats_GetGlobalStatHistory + SteamAPI_ISteamUserStats_GetGlobalStatHistory0 + SteamAPI_ISteamUserStats_GetLeaderboardDisplayType + SteamAPI_ISteamUserStats_GetLeaderboardEntryCount + SteamAPI_ISteamUserStats_GetLeaderboardName + SteamAPI_ISteamUserStats_GetLeaderboardSortMethod + SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo + SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo + SteamAPI_ISteamUserStats_GetNumAchievements + SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers + SteamAPI_ISteamUserStats_GetStat + SteamAPI_ISteamUserStats_GetStat0 + SteamAPI_ISteamUserStats_GetUserAchievement + SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime + SteamAPI_ISteamUserStats_GetUserStat + SteamAPI_ISteamUserStats_GetUserStat0 + SteamAPI_ISteamUserStats_IndicateAchievementProgress + SteamAPI_ISteamUserStats_RequestCurrentStats + SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages + SteamAPI_ISteamUserStats_RequestGlobalStats + SteamAPI_ISteamUserStats_RequestUserStats + SteamAPI_ISteamUserStats_ResetAllStats + SteamAPI_ISteamUserStats_SetAchievement + SteamAPI_ISteamUserStats_SetStat + SteamAPI_ISteamUserStats_SetStat0 + SteamAPI_ISteamUserStats_StoreStats + SteamAPI_ISteamUserStats_UpdateAvgRateStat + SteamAPI_ISteamUserStats_UploadLeaderboardScore + SteamAPI_ISteamUtils_BOverlayNeedsPresent + SteamAPI_ISteamUtils_CheckFileSignature + SteamAPI_ISteamUtils_GetAPICallFailureReason + SteamAPI_ISteamUtils_GetAPICallResult + SteamAPI_ISteamUtils_GetAppID + SteamAPI_ISteamUtils_GetConnectedUniverse + SteamAPI_ISteamUtils_GetCSERIPPort + SteamAPI_ISteamUtils_GetCurrentBatteryPower + SteamAPI_ISteamUtils_GetEnteredGamepadTextInput + SteamAPI_ISteamUtils_GetEnteredGamepadTextLength + SteamAPI_ISteamUtils_GetImageRGBA + SteamAPI_ISteamUtils_GetImageSize + SteamAPI_ISteamUtils_GetIPCCallCount + SteamAPI_ISteamUtils_GetIPCountry + SteamAPI_ISteamUtils_GetSecondsSinceAppActive + SteamAPI_ISteamUtils_GetSecondsSinceComputerActive + SteamAPI_ISteamUtils_GetServerRealTime + SteamAPI_ISteamUtils_GetSteamUILanguage + SteamAPI_ISteamUtils_IsAPICallCompleted + SteamAPI_ISteamUtils_IsOverlayEnabled + SteamAPI_ISteamUtils_IsSteamInBigPictureMode + SteamAPI_ISteamUtils_IsSteamRunningInVR + SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled + SteamAPI_ISteamUtils_SetOverlayNotificationInset + SteamAPI_ISteamUtils_SetOverlayNotificationPosition + SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled + SteamAPI_ISteamUtils_SetWarningMessageHook + SteamAPI_ISteamUtils_ShowGamepadTextInput + SteamAPI_ISteamUtils_StartVRDashboard + SteamAPI_ISteamVideo_GetOPFSettings + SteamAPI_ISteamVideo_GetOPFStringForApp + SteamAPI_ISteamVideo_GetVideoURL + SteamAPI_ISteamVideo_IsBroadcasting + SteamAPI_RegisterCallback + SteamAPI_RegisterCallResult + SteamAPI_ReleaseCurrentThreadMemory + SteamAPI_RestartAppIfNecessary + SteamAPI_RunCallbacks + SteamAPI_SetBreakpadAppID + SteamAPI_SetMiniDumpComment + SteamAPI_SetTryCatchCallbacks + SteamAPI_Shutdown + SteamAPI_UnregisterCallback + SteamAPI_UnregisterCallResult + SteamAPI_UseBreakpadCrashHandler + SteamAPI_WriteMiniDump + SteamClient + SteamGameServer_BSecure + SteamGameServer_GetHSteamPipe + SteamGameServer_GetHSteamUser + SteamGameServer_GetIPCCallCount + SteamGameServer_GetSteamID + SteamGameServer_InitSafe + SteamGameServer_RunCallbacks + SteamGameServer_Shutdown + SteamInternal_ContextInit + SteamInternal_CreateInterface + SteamInternal_FindOrCreateGameServerInterface + SteamInternal_FindOrCreateUserInterface + SteamInternal_GameServer_Init diff --git a/lib/public/def/steam_api64.exp b/lib/public/def/steam_api64.exp new file mode 100644 index 0000000..4d6a5bb Binary files /dev/null and b/lib/public/def/steam_api64.exp differ diff --git a/lib/public/def/tier0.def b/lib/public/def/tier0.def new file mode 100644 index 0000000..6c849ef --- /dev/null +++ b/lib/public/def/tier0.def @@ -0,0 +1,496 @@ +EXPORTS + ??0BasicStatStructFieldDesc@@QEAA@$$QEAV0@@Z + ??0BasicStatStructFieldDesc@@QEAA@AEBV0@@Z + ??0BasicStatStructFieldDesc@@QEAA@W4BasicStatStructFieldTypes_t@@W4BasicStatStructFieldCombineMethods_t@@@Z + ??0CallStackStatStructDescFuncs@@QEAA@$$QEAV0@@Z + ??0CallStackStatStructDescFuncs@@QEAA@AEBV0@@Z + ??0CallStackStatStructDescFuncs@@QEAA@XZ + ??0CCallStackStorage@@QEAA@AEBV0@@Z + ??0CCallStackStorage@@QEAA@P6AHPEAPEAXHH@ZI@Z + ??0CPerfStatsData@@QEAA@XZ + ??0CStackTop_CopyParentStack@@QEAA@PEBQEAXH@Z + ??0CStackTop_ReferenceParentStack@@QEAA@PEBQEAXH@Z + ??0CThread@@QEAA@XZ + ??0CThreadEvent@@QEAA@_N@Z + ??0CThreadEvent@@QEAA@PEBD_N1@Z + ??0CThreadFullMutex@@QEAA@_NPEBD@Z + ??0CThreadLocalBase@GenericThreadLocals@@QEAA@XZ + ??0CThreadMutex@@QEAA@XZ + ??0CThreadRWLock@@QEAA@XZ + ??0CThreadSemaphore@@QEAA@HH@Z + ??0CThreadSpinRWLock@@QEAA@XZ + ??0CThreadSyncObject@@IEAA@XZ + ??0CValidatableThread@@QEAA@XZ + ??0CVProfile@@QEAA@XZ + ??0CVProfNode@@QEAA@PEBDHPEAV0@0H@Z + ??0CWorkerThread@@QEAA@XZ + ??1CStackTop_CopyParentStack@@QEAA@XZ + ??1CStackTop_ReferenceParentStack@@QEAA@XZ + ??1CThread@@UEAA@XZ + ??1CThreadEvent@@QEAA@XZ + ??1CThreadFullMutex@@QEAA@XZ + ??1CThreadLocalBase@GenericThreadLocals@@QEAA@XZ + ??1CThreadMutex@@QEAA@XZ + ??1CThreadRWLock@@QEAA@XZ + ??1CThreadSemaphore@@QEAA@XZ + ??1CThreadSyncObject@@QEAA@XZ + ??1CValidatableThread@@UEAA@XZ + ??1CVProfile@@QEAA@XZ + ??1CVProfNode@@QEAA@XZ + ??1CWorkerThread@@UEAA@XZ + ??4BasicStatStructFieldDesc@@QEAAAEAV0@$$QEAV0@@Z + ??4BasicStatStructFieldDesc@@QEAAAEAV0@AEBV0@@Z + ??4CallStackStatStructDescFuncs@@QEAAAEAV0@$$QEAV0@@Z + ??4CallStackStatStructDescFuncs@@QEAAAEAV0@AEBV0@@Z + ??4CCallStackStorage@@QEAAAEAV0@AEBV0@@Z + ??4CPerfStatsData@@QEAAAEAV0@$$QEAV0@@Z + ??4CPerfStatsData@@QEAAAEAV0@AEBV0@@Z + ??4CStackTop_Base@@QEAAAEAV0@$$QEAV0@@Z + ??4CStackTop_Base@@QEAAAEAV0@AEBV0@@Z + ??4CStackTop_CopyParentStack@@QEAAAEAV0@AEBV0@@Z + ??4CStackTop_ReferenceParentStack@@QEAAAEAV0@AEBV0@@Z + ??4CThreadLocalBase@GenericThreadLocals@@QEAAAEAV01@AEBV01@@Z + ??4CThreadSpinRWLock@@QEAAAEAV0@$$QEAV0@@Z + ??4CThreadSpinRWLock@@QEAAAEAV0@AEBV0@@Z + ??4CVProfile@@QEAAAEAV0@AEBV0@@Z + ??4CVProfNode@@QEAAAEAV0@AEBV0@@Z + ??7CThreadSyncObject@@QEBA_NXZ + ??_7BasicStatStructFieldDesc@@6B@ + ??_7CallStackStatStructDescFuncs@@6B@ + ??_7CThread@@6B@ + ??_7CValidatableThread@@6B@ + ??_7CWorkerThread@@6B@ + ??_FCCallStackStorage@@QEAAXXZ + ??_FCStackTop_ReferenceParentStack@@QEAAXXZ + ??_FCThreadEvent@@QEAAXXZ + ??_FCThreadFullMutex@@QEAAXXZ + ??BCThreadSyncObject@@QEAAPEAXXZ + ?AddBudgetGroupName@CVProfile@@IEAAHPEBDH@Z + ?AssertOwnedByCurrentThread@CThreadFullMutex@@QEAA_NXZ + ?AssertOwnedByCurrentThread@CThreadMutex@@QEAA_NXZ + ?AssertUseable@CThreadSyncObject@@IEAAXXZ + ?AtRoot@CVProfile@@QEBA_NXZ + ?BoostPriority@CWorkerThread@@QEAAHXZ + ?BudgetGroupNameToBudgetGroupID@CVProfile@@QEAAHPEBD@Z + ?BudgetGroupNameToBudgetGroupID@CVProfile@@QEAAHPEBDH@Z + ?BudgetGroupNameToBudgetGroupIDNoCreate@CVProfile@@QEAAHPEBD@Z + ?CalcStackDepth@CThread@@QEAA_KPEAX@Z + ?Call@CWorkerThread@@IEAAHII_NP6AIIPEAPEAVCThreadEvent@@HI@Z@Z + ?CallMaster@CWorkerThread@@QEAAHII@Z + ?CallWorker@CWorkerThread@@QEAAHII_N@Z + ?Check@CThreadEvent@@QEAA_NXZ + ?CheckNamedEvent@CThreadEvent@@SA?AW4NamedEventResult_t@@PEBDI@Z + ?ClearPrevTime@CVProfNode@@QEAAXXZ + ?ConColorMsg@@YAXAEBVColor@@PEBDZZ + ?ConMsg@@YAXPEBDZZ + ?DescribeField@BasicStatStructFieldDesc@@UEAA_KPEAE_K@Z + ?DevMsg@@YAXPEBDZZ + ?DevWarning@@YAXPEBDZZ + ?DisableVTuneGroup@CVProfile@@QEAAXXZ + ?DumpNodes@CVProfile@@IEAAXPEAVCVProfNode@@H_N@Z + ?EnableVTuneGroup@CVProfile@@QEAAXPEBD@Z + ?EnterScope@CVProfile@@QEAAXPEBDH0_N@Z + ?EnterScope@CVProfile@@QEAAXPEBDH0_NH@Z + ?EnterScope@CVProfNode@@QEAAXXZ + ?ExitScope@CVProfile@@QEAAXXZ + ?ExitScope@CVProfNode@@QEAA_NXZ + ?FindBudgetGroupName@CVProfile@@IEAAHPEBD@Z + ?FindNode@CVProfile@@QEAAPEAVCVProfNode@@PEAV2@PEBD@Z + ?FindOrCreateCounter@CVProfile@@QEAAPEAHPEBDW4CounterGroup_t@@@Z + ?FreeNodes_R@CVProfile@@IEAAXPEAVCVProfNode@@@Z + ?g_bInException@@3_NA + ?g_nThreadID@@3V?$CThreadLocalInt@H@GenericThreadLocals@@A + ?Get@CThreadLocalBase@GenericThreadLocals@@QEBAPEAXXZ + ?GetBudgetGroupColor@CVProfile@@QEAAXHAEAH000@Z + ?GetBudgetGroupFlags@CVProfile@@QEBAHH@Z + ?GetBudgetGroupID@CVProfNode@@QEAAHXZ + ?GetBudgetGroupName@CVProfile@@QEAAPEBDH@Z + ?GetCallHandle@CWorkerThread@@QEAAAEAVCThreadEvent@@XZ + ?GetCallParam@CWorkerThread@@QEBAIXZ + ?GetChild@CVProfNode@@QEAAPEAV1@XZ + ?GetClientData@CVProfNode@@QEBAHXZ + ?GetCounterGroup@CVProfile@@QEBA?AW4CounterGroup_t@@H@Z + ?GetCounterName@CVProfile@@QEBAPEBDH@Z + ?GetCounterNameAndValue@CVProfile@@QEBAPEBDHAEAH@Z + ?GetCounterValue@CVProfile@@QEBAHH@Z + ?GetCurCalls@CVProfNode@@QEAAHXZ + ?GetCurrentCThread@CThread@@SAPEAV1@XZ + ?GetCurrentNode@CVProfile@@QEAAPEAVCVProfNode@@XZ + ?GetCurTime@CVProfNode@@QEAANXZ + ?GetCurTimeLessChildren@CVProfNode@@QEAANXZ + ?GetDetailLevel@CVProfile@@QEBAHXZ + ?GetHandle@CThreadSyncObject@@QEBAQEAXXZ + ?GetL2CacheMisses@CVProfNode@@QEAAHXZ + ?GetName@CThread@@QEAAPEBDXZ + ?GetName@CVProfNode@@QEAAPEBDXZ + ?GetNumBudgetGroups@CVProfile@@QEAAHXZ + ?GetNumCounters@CVProfile@@QEBAHXZ + ?GetParent@CVProfNode@@QEAAPEAV1@XZ + ?GetPeakFrameTime@CVProfile@@QEAANXZ + ?GetPeakTime@CVProfNode@@QEAANXZ + ?GetPrevCalls@CVProfNode@@QEAAHXZ + ?GetPrevL2CacheMissLessChildren@CVProfNode@@QEAAHXZ + ?GetPrevLoadHitStoreLessChildren@CVProfNode@@QEAAHXZ + ?GetPrevSibling@CVProfNode@@QEAAPEAV1@XZ + ?GetPrevTime@CVProfNode@@QEAANXZ + ?GetPrevTimeLessChildren@CVProfNode@@QEAANXZ + ?GetPriority@CThread@@QEBAHXZ + ?GetResult@CThread@@QEAAHXZ + ?GetRoot@CVProfile@@QEAAPEAVCVProfNode@@XZ + ?GetSibling@CVProfNode@@QEAAPEAV1@XZ + ?GetSubNode@CVProfNode@@QEAAPEAV1@PEBDH0@Z + ?GetSubNode@CVProfNode@@QEAAPEAV1@PEBDH0H@Z + ?GetTargetThreadId@CVProfile@@QEAAIXZ + ?GetThreadHandle@CThread@@IEBAQEAUThreadHandle_t__@@XZ + ?GetThreadHandle@CThread@@QEAAPEAUThreadHandle_t__@@XZ + ?GetThreadID@CThread@@IEBA?B_KXZ + ?GetThreadProc@CThread@@MEAAP6AKPEAX@ZXZ + ?GetTimeLastFrame@CVProfile@@QEAANXZ + ?GetTotalCalls@CVProfNode@@QEAAHXZ + ?GetTotalTime@CVProfNode@@QEAANXZ + ?GetTotalTimeLessChildren@CVProfNode@@QEAANXZ + ?GetTotalTimeSampled@CVProfile@@QEAANXZ + ?GetUniqueNodeID@CVProfNode@@AEBAHXZ + ?HideBudgetGroup@CVProfile@@QEAAXH_N@Z + ?HideBudgetGroup@CVProfile@@QEAAXPEBD_N@Z + ?Init@CThread@@MEAA_NXZ + ?InTargetThread@CVProfile@@QEAA_NXZ + ?IsAlive@CThread@@QEAA_NXZ + ?IsEnabled@CVProfile@@QEBA_NXZ + ?IsLockedForRead@CThreadSpinRWLock@@QEAA_NXZ + ?IsLockedForWrite@CThreadSpinRWLock@@QEAA_NXZ + ?IsOwnedByCurrentThread_DebugOnly@CThreadMutex@@QEAA_NXZ + ?IsSuspended@CThread@@QEAA_NXZ + ?IsThreadRunning@CThread@@MEAA_NXZ + ?Join@CThread@@QEAA_NI@Z + ?Lock@CThreadFastMutex@@AECAXII@Z + ?Lock@CThreadFullMutex@@QEAAXI@Z + ?Lock@CThreadFullMutex@@QEAAXXZ + ?Lock@CThreadMutex@@QEAAXXZ + ?Lock@CThreadMutex@@QEBAXXZ + ?LockForRead@CThreadRWLock@@QEAAXXZ + ?LockForRead@CThreadRWLock@@QEBAXXZ + ?LockForRead@CThreadSpinRWLock@@QEAAXXZ + ?LockForRead@CThreadSpinRWLock@@QEBAXXZ + ?LockForWrite@CThreadRWLock@@QEAAXXZ + ?LockForWrite@CThreadRWLock@@QEBAXXZ + ?LockForWrite@CThreadSpinRWLock@@QEAAXXZ + ?LockForWrite@CThreadSpinRWLock@@QEBAXXZ + ?LockSilent@CThreadMutex@@QEAAXXZ + ?LoggingSystem_Log@@YA?AW4LoggingResponse_t@@HW4LoggingSeverity_t@@VColor@@PEBDZZ + ?MarkFrame@CVProfile@@QEAAXPEBD@Z + ?MarkFrame@CVProfile@@QEAAXXZ + ?MarkFrame@CVProfNode@@QEAAXXZ + ?NumFramesSampled@CVProfile@@QEAAHXZ + ?OnExit@CThread@@MEAAXXZ + ?OutputReport@CVProfile@@QEAAXHPEBDH@Z + ?Pause@CVProfile@@QEAAXXZ + ?Pause@CVProfNode@@QEAAXXZ + ?PeekCall@CWorkerThread@@QEAA_NPEAI@Z + ?PMEEnable@CVProfile@@QEAAX_N@Z + ?PMEInitialized@CVProfile@@QEAAX_N@Z + ?PopGroup@CVProfile@@QEAAXXZ + ?PushGroup@CVProfile@@QEAAXH@Z + ?RegisterNumBudgetGroupsChangedCallBack@CVProfile@@QEAAXP6AXXZ@Z + ?Release@CThreadFullMutex@@QEAA_NXZ + ?Release@CThreadSemaphore@@QEAA_NHPEAH@Z + ?ReleaseParentStackReferences@CStackTop_ReferenceParentStack@@QEAAXXZ + ?Reply@CWorkerThread@@QEAAXI@Z + ?Reset@CPerfStatsData@@QEAAXXZ + ?Reset@CThreadEvent@@QEAA_NXZ + ?Reset@CVProfile@@QEAAXXZ + ?Reset@CVProfNode@@QEAAXXZ + ?ResetCounters@CVProfile@@QEAAXW4CounterGroup_t@@@Z + ?ResetPeak@CVProfNode@@QEAAXXZ + ?ResetPeaks@CVProfile@@QEAAXXZ + ?Resume@CThread@@QEAAIXZ + ?Resume@CVProfile@@QEAAXXZ + ?Resume@CVProfNode@@QEAAXXZ + ?s_iCurrentUniqueNodeID@CVProfNode@@0HA + ?Set@CThreadEvent@@QEAA_NXZ + ?Set@CThreadLocalBase@GenericThreadLocals@@QEAAXPEAX@Z + ?SetBudgetGroupID@CVProfNode@@QEAAXH@Z + ?SetClientData@CVProfNode@@QEAAXH@Z + ?SetCurFrameTime@CVProfNode@@QEAAXK@Z + ?SetName@CThread@@QEAAXPEBD@Z + ?SetPriority@CThread@@QEAA_NH@Z + ?SetTargetThreadId@CVProfile@@QEAAXI@Z + ?SetTrace@CThreadFullMutex@@QEAAX_N@Z + ?SetTrace@CThreadMutex@@QEAAX_N@Z + ?SetUniqueNodeID@CVProfNode@@AEAAXH@Z + ?Sleep@CThread@@SAXI@Z + ?SpinLockForRead@CThreadSpinRWLock@@QEAAXXZ + ?SpinLockForWrite@CThreadSpinRWLock@@QEAAXXZ + ?Start@CThread@@UEAA_NIW4ThreadPriorityEnum_t@@@Z + ?Start@CVProfile@@QEAAXXZ + ?Stop@CThread@@QEAAXH@Z + ?Stop@CVProfile@@QEAAXXZ + ?SumTimes@CVProfile@@IEAAXPEAVCVProfNode@@H@Z + ?SumTimes@CVProfile@@IEAAXPEBDH@Z + ?Suspend@CThread@@QEAAIXZ + ?Term@CVProfile@@QEAAXXZ + ?Terminate@CThread@@QEAA_NH@Z + ?ThreadProc@CThread@@KAKPEAX@Z + ?ThreadProcRunWithMinidumpHandler@CThread@@KAXPEAX@Z + ?Tick@CPerfStatsData@@QEAAXXZ + ?TryLock@CThreadMutex@@QEAA_NXZ + ?TryLock@CThreadMutex@@QEBA_NXZ + ?TryLockForRead@CThreadSpinRWLock@@QEAA_NXZ + ?TryLockForRead@CThreadSpinRWLock@@QEBA_NXZ + ?TryLockForRead_UnforcedInline@CThreadSpinRWLock@@QEAA_NXZ + ?TryLockForWrite@CThreadSpinRWLock@@QEAA_NXZ + ?TryLockForWrite@CThreadSpinRWLock@@QEBA_NXZ + ?TryLockForWrite_UnforcedInline@CThreadSpinRWLock@@QEAA_NXZ + ?Unlock@CThreadFullMutex@@QEAAXXZ + ?Unlock@CThreadMutex@@QEAAXXZ + ?Unlock@CThreadMutex@@QEBAXXZ + ?UnlockRead@CThreadRWLock@@QEAAXXZ + ?UnlockRead@CThreadRWLock@@QEBAXXZ + ?UnlockRead@CThreadSpinRWLock@@QEAAXXZ + ?UnlockRead@CThreadSpinRWLock@@QEBAXXZ + ?UnlockSilent@CThreadMutex@@QEAAXXZ + ?UnlockWrite@CThreadRWLock@@QEAAXXZ + ?UnlockWrite@CThreadRWLock@@QEBAXXZ + ?UnlockWrite@CThreadSpinRWLock@@QEAAXXZ + ?UnlockWrite@CThreadSpinRWLock@@QEBAXXZ + ?UsePME@CVProfile@@QEAA_NXZ + ?VTuneGroupEnabled@CVProfile@@IEAA_NXZ + ?VTuneGroupID@CVProfile@@IEAAHXZ + ?Wait@CThreadEvent@@QEAA_NI@Z + ?Wait@CThreadSyncObject@@QEAA_NI@Z + ?WaitForCall@CWorkerThread@@QEAA_NIPEAI@Z + ?WaitForCall@CWorkerThread@@QEAA_NPEAI@Z + ?WaitForCreateComplete@CThread@@MEAA_NPEAVCThreadEvent@@@Z + ?WaitForMultiple@CThreadEvent@@SAIHPEAPEAV1@_NI@Z + ?WaitForMultiple@CThreadEvent@@SAIHPEAV1@_NI@Z + ?WaitForMultiple@CThreadSyncObject@@SAIHPEAPEAV1@_NI@Z + ?WaitForMultiple@CThreadSyncObject@@SAIHPEAV1@_NI@Z + ?WaitForRead@CThreadRWLock@@AEAAXXZ + ?WaitForReply@CWorkerThread@@IEAAHIP6AIIPEAPEAVCThreadEvent@@HI@Z@Z + ?WaitForReply@CWorkerThread@@QEAAHI@Z + ?Yield@CThread@@SAXXZ + AddMemoryInfoCallback + AllocateThreadID + AppendMiniProfilerToList + AreAllAssertsDisabled + _AssertValidReadPtr + _AssertValidReadWritePtr + _AssertValidStringPtr + _AssertValidWritePtr + AssertValidWStringPtr + CallAssertFailedNotifyFunc + CatchAndWriteMiniDump + CatchAndWriteMiniDumpEx + CatchAndWriteMiniDumpExForVoidPtrFn + CatchAndWriteMiniDumpExReturnsInt + CatchAndWriteMiniDumpForVoidPtrFn + _CCallStackStatsGatherer_Internal_DumpStatsToFile + _CCallStackStatsGatherer_Write_FieldDescriptions + ClearHardwareBreakpoint + COM_TimestampedLog + CommandLine + ConDMsg + CrackSmokingCompiler + CreateSimpleThread + DeclareCurrentThreadIsMainThread + DecodeBinaryFromString + DevMsg + DevWarning + DoNewAssertDialog + Dump_AddCallback + Dump_CallFunction + Dump_CallMainFunction + Dump_CallWinMainFunction + Dump_CreateDump + Dump_EnableCrashingOnCrashes + Dump_EnableFullDumps + Dump_RemoveCallback + DumpMemoryInfoStats + EnableCrashingOnCrashes + EncodeBinaryToString + Error + _Error_AlwaysSpewCallStack_Enable + _Error_AlwaysSpewCallStack_Length + Error_SpewCallStack + _ExitOnFatalAssert + FreeThreadID + g_ClockSpeed + g_ClockSpeedMicrosecondsMultiplier + g_ClockSpeedMillisecondsMultiplier + g_ClockSpeedSecondsMultiplier + g_dwClockSpeed + g_nMiniProfilerFrame + g_pAssertMiniProfilers + g_PerfStats + g_pGlobalMiniProfilers + g_pLastMiniProfiler + g_pMemAlloc + g_pRootMiniProfiler + g_VProfCurrentProfile + g_VProfSignalSpike + GetCallStack + GetCallStack_Fast + GetCPUFrequencyResults + GetCPUInformation + GetCurrentDate + GetCurrentDayOfTheWeek + GetCurrentDayOfTheYear + GetFileAndLineFromAddress + GetHardwareClockReliably + GetModuleNameFromAddress + GetSymbolNameFromAddress + GetThreadedLoadLibraryFunc + GetVAtom + InitPME + InitWin32ConsoleColorContext + InstallProgressReportHandler + IsAssertDialogDisabled + LOG_GENERAL + LoggingSystem_AddTagToCurrentChannel + LoggingSystem_FindChannel + LoggingSystem_GetChannel + LoggingSystem_GetChannelColor + LoggingSystem_GetChannelCount + LoggingSystem_GetChannelFlags + LoggingSystem_GetFirstChannelID + LoggingSystem_GetNextChannelID + LoggingSystem_HasTag + LoggingSystem_IsChannelEnabled + LoggingSystem_Log + LoggingSystem_LogAssert + LoggingSystem_LogDirect + LoggingSystem_PopLoggingState + LoggingSystem_PushLoggingState + LoggingSystem_RegisterLoggingChannel + LoggingSystem_RegisterLoggingListener + LoggingSystem_ResetCurrentLoggingState + LoggingSystem_SetChannelColor + LoggingSystem_SetChannelFlags + LoggingSystem_SetChannelSpewLevel + LoggingSystem_SetChannelSpewLevelByName + LoggingSystem_SetChannelSpewLevelByTag + LoggingSystem_SetGlobalSpewLevel + LoggingSystem_SetLoggingResponsePolicy + LoggingSystem_UnregisterLoggingListener + MemAllocScratch + MemFreeScratch + MemOutOfMemory + MicroProfilerAddTS + MinidumpSetUnhandledExceptionFunction + Msg + Plat_Alloc + Plat_chmod + Plat_ConvertToLocalTime + Plat_CreateWindow + Plat_ctime + Plat_DebugString + Plat_ExitProcess + Plat_ExitProcessWithError + Plat_FastVerifyHardwareKey + Plat_FileExists + Plat_FileIsReadOnly + Plat_FileSize + Plat_FloatTime + Plat_Free + Plat_GetClockStart + Plat_GetCommandLine + Plat_GetCommandLineA + Plat_GetDesktopResolution + Plat_GetEnv + Plat_GetExecutablePath + Plat_GetLocalTime + Plat_GetMemPageSize + Plat_GetModuleFilename + Plat_GetOSVersion + Plat_GetPagedPoolInfo + Plat_GetShellWindow + Plat_GetTime + Plat_GetTimeString + Plat_getwd + Plat_GetWindowClientSize + Plat_IsDirectory + Plat_IsInBenchmarkMode + Plat_IsInDebugSession + Plat_IsWindowMinimized + Plat_localtime + Plat_MessageBox + Plat_MSTime + Plat_Realloc + Plat_ScreenToWindowCoords + Plat_SetAllocErrorFn + Plat_SetBenchmarkMode + Plat_SetExitProcessWithErrorCB + Plat_SetWindowPos + Plat_SetWindowTitle + Plat_SimpleLog + Plat_timegm + Plat_USTime + Plat_VerifyHardwareKey + Plat_VerifyHardwareKeyDriver + Plat_VerifyHardwareKeyPrompt + Plat_WindowToScreenCoords + Platform_gmtime + PopMiniProfilerTS + PreloadStackInformation + PublishAll + PublishAllMiniProfilers + PushMiniProfilerTS + ReleaseThreadHandle + RemoveMemoryInfoCallback + RemoveMiniProfilerFromList + ReportProgress + RestoreWin32ConsoleColor + RunTSListTests + RunTSQueueTests + SetAllAssertsDisabled + SetAssertDialogDisabled + SetAssertFailedNotifyFunc + SetCPUMonitoringInterval + SetHardwareBreakpoint + SetMinidumpComment + SetMinidumpFilenamePrefix + SetMiniDumpFunction + SetStackTranslationSymbolSearchPath + SetThreadedLoadLibraryFunc + SetupWin32ConsoleIO + SetWin32ConsoleColor + ShouldUseNewAssertDialog + ShutdownPME + StackToolsNotify_LoadedLibrary + ThreadGetCurrentHandle + ThreadGetCurrentId + ThreadGetPriority + ThreadInMainThread + ThreadInterlockedAssignIf + ThreadInterlockedAssignIf128 + ThreadInterlockedAssignIf64 + ThreadInterlockedAssignPointerIf + ThreadInterlockedCompareExchange + ThreadInterlockedCompareExchange64 + ThreadInterlockedCompareExchangePointer + ThreadInterlockedDecrement + ThreadInterlockedExchange + ThreadInterlockedExchange64 + ThreadInterlockedExchangeAdd + ThreadInterlockedExchangePointer + ThreadInterlockedIncrement + ThreadJoin + ThreadNanoSleep + ThreadSetAffinity + ThreadSetDebugName + ThreadSetPriority + ThreadSleep + TranslateStackInfo + V_tier0_snprintf + V_tier0_stricmp + V_tier0_strncat + V_tier0_strncpy + V_tier0_vsnprintf + VoidFnPtrLookup_Tier0 + vtune + Warning + _Warning_AlwaysSpewCallStack_Enable + _Warning_AlwaysSpewCallStack_Length + Warning_SpewCallStack + WriteMiniDump + WriteMiniDumpUsingExceptionInfo diff --git a/lib/public/def/tier0.exp b/lib/public/def/tier0.exp new file mode 100644 index 0000000..5d36420 Binary files /dev/null and b/lib/public/def/tier0.exp differ diff --git a/lib/public/def/vstdlib.def b/lib/public/def/vstdlib.def new file mode 100644 index 0000000..ee4cf22 --- /dev/null +++ b/lib/public/def/vstdlib.def @@ -0,0 +1,54 @@ +EXPORTS + ??0CGaussianRandomStream@@QEAA@$$QEAV0@@Z + ??0CGaussianRandomStream@@QEAA@AEBV0@@Z + ??0CGaussianRandomStream@@QEAA@PEAVIUniformRandomStream@@@Z + ??0CUniformRandomStream@@QEAA@$$QEAV0@@Z + ??0CUniformRandomStream@@QEAA@AEBV0@@Z + ??0CUniformRandomStream@@QEAA@XZ + ??4CGaussianRandomStream@@QEAAAEAV0@$$QEAV0@@Z + ??4CGaussianRandomStream@@QEAAAEAV0@AEBV0@@Z + ??4CUniformRandomStream@@QEAAAEAV0@$$QEAV0@@Z + ??4CUniformRandomStream@@QEAAAEAV0@AEBV0@@Z + ??_7CUniformRandomStream@@6B@ + ??_FCGaussianRandomStream@@QEAAXXZ + ?AttachToStream@CGaussianRandomStream@@QEAAXPEAVIUniformRandomStream@@@Z + ?GenerateRandomNumber@CUniformRandomStream@@AEAAHXZ + ?RandomFloat@CGaussianRandomStream@@QEAAMMM@Z + ?RandomFloat@CUniformRandomStream@@UEAAMMM@Z + ?RandomFloatExp@CUniformRandomStream@@UEAAMMMM@Z + ?RandomInt@CUniformRandomStream@@UEAAHHH@Z + ?SetSeed@CUniformRandomStream@@UEAAXH@Z + Coroutine_Cancel + Coroutine_Continue + Coroutine_Create + Coroutine_DebugAssert + Coroutine_DebugBreak + Coroutine_GetCurrentlyActive + Coroutine_GetStackDepth + Coroutine_IsActive + Coroutine_ReleaseThreadMemory + Coroutine_ValidateGlobals + Coroutine_YieldToMain + CreateInterface + CreateNewThreadPool + cvar + DestroyThreadPool + g_pScheduledFunctions + g_pThreadPool + g_VCoverage + InstallUniformRandomStream + KeyValuesSystem + RandomFloat + RandomFloatExp + RandomGaussianFloat + RandomInt + RandomSeed + RunThreadPoolTests + V_UCS2ToUnicode + V_UCS2ToUTF8 + V_UnicodeToUCS2 + V_UnicodeToUTF8 + V_UTF8_strncpy + V_UTF8ToUCS2 + V_UTF8ToUnicode + VStdLib_GetICVarFactory diff --git a/lib/public/def/vstdlib.exp b/lib/public/def/vstdlib.exp new file mode 100644 index 0000000..ea55db0 Binary files /dev/null and b/lib/public/def/vstdlib.exp differ diff --git a/lib/public/lua_shared.lib b/lib/public/lua_shared.lib new file mode 100644 index 0000000..c0740ea Binary files /dev/null and b/lib/public/lua_shared.lib differ diff --git a/lib/public/mathlib.lib b/lib/public/mathlib.lib new file mode 100644 index 0000000..605b39a Binary files /dev/null and b/lib/public/mathlib.lib differ diff --git a/lib/public/raytrace.lib b/lib/public/raytrace.lib new file mode 100644 index 0000000..8fc7418 Binary files /dev/null and b/lib/public/raytrace.lib differ diff --git a/lib/public/steam_api64.lib b/lib/public/steam_api64.lib new file mode 100644 index 0000000..841470c Binary files /dev/null and b/lib/public/steam_api64.lib differ diff --git a/lib/public/tier0.lib b/lib/public/tier0.lib new file mode 100644 index 0000000..21b8760 Binary files /dev/null and b/lib/public/tier0.lib differ diff --git a/lib/public/tier1.lib b/lib/public/tier1.lib new file mode 100644 index 0000000..248d6b5 Binary files /dev/null and b/lib/public/tier1.lib differ diff --git a/lib/public/vstdlib.lib b/lib/public/vstdlib.lib new file mode 100644 index 0000000..3d4c848 Binary files /dev/null and b/lib/public/vstdlib.lib differ diff --git a/mathlib/3dnow.cpp b/mathlib/3dnow.cpp new file mode 100644 index 0000000..db17c8c --- /dev/null +++ b/mathlib/3dnow.cpp @@ -0,0 +1,197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: 3DNow Math primitives. +// +//=====================================================================================// + +#include +#include // Needed for FLT_EPSILON +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/amd3dx.h" +#include "mathlib/vector.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if !defined(COMPILER_MSVC64) && !defined(LINUX) +// Implement for 64-bit Windows if needed. +// Clang hits "fatal error: error in backend:" and other errors when trying +// to compile the inline assembly below. 3DNow support is highly unlikely to +// be useful/used, so it's not worth spending time on fixing. + +#pragma warning(disable:4244) // "conversion from 'const int' to 'float', possible loss of data" +#pragma warning(disable:4730) // "mixing _m64 and floating point expressions may result in incorrect code" + +//----------------------------------------------------------------------------- +// 3D Now Implementations of optimized routines: +//----------------------------------------------------------------------------- +float _3DNow_Sqrt(float x) +{ + Assert( s_bMathlibInitialized ); + float root = 0.f; +#ifdef _WIN32 + _asm + { + femms + movd mm0, x + PFRSQRT (mm1,mm0) + punpckldq mm0, mm0 + PFMUL (mm0, mm1) + movd root, mm0 + femms + } +#elif LINUX + __asm __volatile__( "femms" ); + __asm __volatile__ + ( + "pfrsqrt %y0, %y1 \n\t" + "punpckldq %y1, %y1 \n\t" + "pfmul %y1, %y0 \n\t" + : "=y" (root), "=y" (x) + :"0" (x) + ); + __asm __volatile__( "femms" ); +#else +#error +#endif + + return root; +} + +// NJS FIXME: Need to test Recripricol squareroot performance and accuraccy +// on AMD's before using the specialized instruction. +float _3DNow_RSqrt(float x) +{ + Assert( s_bMathlibInitialized ); + + return 1.f / _3DNow_Sqrt(x); +} + + +float FASTCALL _3DNow_VectorNormalize (Vector& vec) +{ + Assert( s_bMathlibInitialized ); + float *v = &vec[0]; + float radius = 0.f; + + if ( v[0] || v[1] || v[2] ) + { +#ifdef _WIN32 + _asm + { + mov eax, v + femms + movq mm0, QWORD PTR [eax] + movd mm1, DWORD PTR [eax+8] + movq mm2, mm0 + movq mm3, mm1 + PFMUL (mm0, mm0) + PFMUL (mm1, mm1) + PFACC (mm0, mm0) + PFADD (mm1, mm0) + PFRSQRT (mm0, mm1) + punpckldq mm1, mm1 + PFMUL (mm1, mm0) + PFMUL (mm2, mm0) + PFMUL (mm3, mm0) + movq QWORD PTR [eax], mm2 + movd DWORD PTR [eax+8], mm3 + movd radius, mm1 + femms + } +#elif LINUX + long long a,c; + int b,d; + memcpy(&a,&vec[0],sizeof(a)); + memcpy(&b,&vec[2],sizeof(b)); + memcpy(&c,&vec[0],sizeof(c)); + memcpy(&d,&vec[2],sizeof(d)); + + __asm __volatile__( "femms" ); + __asm __volatile__ + ( + "pfmul %y3, %y3\n\t" + "pfmul %y0, %y0 \n\t" + "pfacc %y3, %y3 \n\t" + "pfadd %y3, %y0 \n\t" + "pfrsqrt %y0, %y3 \n\t" + "punpckldq %y0, %y0 \n\t" + "pfmul %y3, %y0 \n\t" + "pfmul %y3, %y2 \n\t" + "pfmul %y3, %y1 \n\t" + : "=y" (radius), "=y" (c), "=y" (d) + : "y" (a), "0" (b), "1" (c), "2" (d) + ); + memcpy(&vec[0],&c,sizeof(c)); + memcpy(&vec[2],&d,sizeof(d)); + __asm __volatile__( "femms" ); + +#else +#error +#endif + } + return radius; +} + + +void FASTCALL _3DNow_VectorNormalizeFast (Vector& vec) +{ + _3DNow_VectorNormalize( vec ); +} + + +// JAY: This complains with the latest processor pack +#pragma warning(disable: 4730) + +float _3DNow_InvRSquared(const float* v) +{ + Assert( s_bMathlibInitialized ); + float r2 = 1.f; +#ifdef _WIN32 + _asm { // AMD 3DNow only routine + mov eax, v + femms + movq mm0, QWORD PTR [eax] + movd mm1, DWORD PTR [eax+8] + movd mm2, [r2] + PFMUL (mm0, mm0) + PFMUL (mm1, mm1) + PFACC (mm0, mm0) + PFADD (mm1, mm0) + PFMAX (mm1, mm2) + PFRCP (mm0, mm1) + movd [r2], mm0 + femms + } +#elif LINUX + long long a,c; + int b; + memcpy(&a,&v[0],sizeof(a)); + memcpy(&b,&v[2],sizeof(b)); + memcpy(&c,&v[0],sizeof(c)); + + __asm __volatile__( "femms" ); + __asm __volatile__ + ( + "PFMUL %y2, %y2 \n\t" + "PFMUL %y3, %y3 \n\t" + "PFACC %y2, %y2 \n\t" + "PFADD %y2, %y3 \n\t" + "PFMAX %y3, %y4 \n\t" + "PFRCP %y3, %y2 \n\t" + "movq %y2, %y0 \n\t" + : "=y" (r2) + : "0" (r2), "y" (a), "y" (b), "y" (c) + ); + __asm __volatile__( "femms" ); +#else +#error +#endif + + return r2; +} + +#endif // COMPILER_MSVC64 diff --git a/mathlib/3dnow.h b/mathlib/3dnow.h new file mode 100644 index 0000000..c39b2ec --- /dev/null +++ b/mathlib/3dnow.h @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef _3DNOW_H +#define _3DNOW_H + +float _3DNow_Sqrt(float x); +float _3DNow_RSqrt(float x); +float FASTCALL _3DNow_VectorNormalize (Vector& vec); +void FASTCALL _3DNow_VectorNormalizeFast (Vector& vec); +float _3DNow_InvRSquared(const float* v); + +#endif // _3DNOW_H diff --git a/mathlib/IceKey.cpp b/mathlib/IceKey.cpp new file mode 100644 index 0000000..c03c72f --- /dev/null +++ b/mathlib/IceKey.cpp @@ -0,0 +1,393 @@ +// Purpose: C++ implementation of the ICE encryption algorithm. +// Taken from public domain code, as written by Matthew Kwan - July 1996 +// http://www.darkside.com.au/ice/ + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#include "mathlib/IceKey.H" +#include "tier0/memdbgon.h" +#pragma warning(disable: 4244) + + + /* Structure of a single round subkey */ +class IceSubkey { + public: + unsigned long val[3]; +}; + + + /* The S-boxes */ +static unsigned long ice_sbox[4][1024]; +static int ice_sboxes_initialised = 0; + + + /* Modulo values for the S-boxes */ +static const int ice_smod[4][4] = { + {333, 313, 505, 369}, + {379, 375, 319, 391}, + {361, 445, 451, 397}, + {397, 425, 395, 505}}; + + /* XOR values for the S-boxes */ +static const int ice_sxor[4][4] = { + {0x83, 0x85, 0x9b, 0xcd}, + {0xcc, 0xa7, 0xad, 0x41}, + {0x4b, 0x2e, 0xd4, 0x33}, + {0xea, 0xcb, 0x2e, 0x04}}; + + /* Permutation values for the P-box */ +static const unsigned long ice_pbox[32] = { + 0x00000001, 0x00000080, 0x00000400, 0x00002000, + 0x00080000, 0x00200000, 0x01000000, 0x40000000, + 0x00000008, 0x00000020, 0x00000100, 0x00004000, + 0x00010000, 0x00800000, 0x04000000, 0x20000000, + 0x00000004, 0x00000010, 0x00000200, 0x00008000, + 0x00020000, 0x00400000, 0x08000000, 0x10000000, + 0x00000002, 0x00000040, 0x00000800, 0x00001000, + 0x00040000, 0x00100000, 0x02000000, 0x80000000}; + + /* The key rotation schedule */ +static const int ice_keyrot[16] = { + 0, 1, 2, 3, 2, 1, 3, 0, + 1, 3, 2, 0, 3, 1, 0, 2}; + + +/* + * 8-bit Galois Field multiplication of a by b, modulo m. + * Just like arithmetic multiplication, except that additions and + * subtractions are replaced by XOR. + */ + +static unsigned int +gf_mult ( + unsigned int a, + unsigned int b, + unsigned int m +) { + unsigned int res = 0; + + while (b) { + if (b & 1) + res ^= a; + + a <<= 1; + b >>= 1; + + if (a >= 256) + a ^= m; + } + + return (res); +} + + +/* + * Galois Field exponentiation. + * Raise the base to the power of 7, modulo m. + */ + +static unsigned long +gf_exp7 ( + unsigned int b, + unsigned int m +) { + unsigned int x; + + if (b == 0) + return (0); + + x = gf_mult (b, b, m); + x = gf_mult (b, x, m); + x = gf_mult (x, x, m); + return (gf_mult (b, x, m)); +} + + +/* + * Carry out the ICE 32-bit P-box permutation. + */ + +static unsigned long +ice_perm32 ( + unsigned long x +) { + unsigned long res = 0; + const unsigned long *pbox = ice_pbox; + + while (x) { + if (x & 1) + res |= *pbox; + pbox++; + x >>= 1; + } + + return (res); +} + + +/* + * Initialise the ICE S-boxes. + * This only has to be done once. + */ + +static void +ice_sboxes_init (void) +{ + int i; + + for (i=0; i<1024; i++) { + int col = (i >> 1) & 0xff; + int row = (i & 0x1) | ((i & 0x200) >> 8); + unsigned long x; + + x = gf_exp7 (col ^ ice_sxor[0][row], ice_smod[0][row]) << 24; + ice_sbox[0][i] = ice_perm32 (x); + + x = gf_exp7 (col ^ ice_sxor[1][row], ice_smod[1][row]) << 16; + ice_sbox[1][i] = ice_perm32 (x); + + x = gf_exp7 (col ^ ice_sxor[2][row], ice_smod[2][row]) << 8; + ice_sbox[2][i] = ice_perm32 (x); + + x = gf_exp7 (col ^ ice_sxor[3][row], ice_smod[3][row]); + ice_sbox[3][i] = ice_perm32 (x); + } +} + + +/* + * Create a new ICE key. + */ + +IceKey::IceKey (int n) +{ + if (!ice_sboxes_initialised) { + ice_sboxes_init (); + ice_sboxes_initialised = 1; + } + + if (n < 1) { + _size = 1; + _rounds = 8; + } else { + _size = n; + _rounds = n * 16; + } + + _keysched = new IceSubkey[_rounds]; +} + + +/* + * Destroy an ICE key. + */ + +IceKey::~IceKey () +{ + int i, j; + + for (i=0; i<_rounds; i++) + for (j=0; j<3; j++) + _keysched[i].val[j] = 0; + + _rounds = _size = 0; + + delete[] _keysched; +} + + +/* + * The single round ICE f function. + */ + +static unsigned long +ice_f ( + unsigned long p, + const IceSubkey *sk +) { + unsigned long tl, tr; /* Expanded 40-bit values */ + unsigned long al, ar; /* Salted expanded 40-bit values */ + + /* Left half expansion */ + tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00); + + /* Right half expansion */ + tr = (p & 0x3ff) | ((p << 2) & 0xffc00); + + /* Perform the salt permutation */ + // al = (tr & sk->val[2]) | (tl & ~sk->val[2]); + // ar = (tl & sk->val[2]) | (tr & ~sk->val[2]); + al = sk->val[2] & (tl ^ tr); + ar = al ^ tr; + al ^= tl; + + al ^= sk->val[0]; /* XOR with the subkey */ + ar ^= sk->val[1]; + + /* S-box lookup and permutation */ + return (ice_sbox[0][al >> 10] | ice_sbox[1][al & 0x3ff] + | ice_sbox[2][ar >> 10] | ice_sbox[3][ar & 0x3ff]); +} + + +/* + * Encrypt a block of 8 bytes of data with the given ICE key. + */ + +void +IceKey::encrypt ( + const unsigned char *ptext, + unsigned char *ctext +) const +{ + int i; + unsigned long l, r; + + l = (((unsigned long) ptext[0]) << 24) + | (((unsigned long) ptext[1]) << 16) + | (((unsigned long) ptext[2]) << 8) | ptext[3]; + r = (((unsigned long) ptext[4]) << 24) + | (((unsigned long) ptext[5]) << 16) + | (((unsigned long) ptext[6]) << 8) | ptext[7]; + + for (i = 0; i < _rounds; i += 2) { + l ^= ice_f (r, &_keysched[i]); + r ^= ice_f (l, &_keysched[i + 1]); + } + + for (i = 0; i < 4; i++) { + ctext[3 - i] = r & 0xff; + ctext[7 - i] = l & 0xff; + + r >>= 8; + l >>= 8; + } +} + + +/* + * Decrypt a block of 8 bytes of data with the given ICE key. + */ + +void +IceKey::decrypt ( + const unsigned char *ctext, + unsigned char *ptext +) const +{ + int i; + unsigned long l, r; + + l = (((unsigned long) ctext[0]) << 24) + | (((unsigned long) ctext[1]) << 16) + | (((unsigned long) ctext[2]) << 8) | ctext[3]; + r = (((unsigned long) ctext[4]) << 24) + | (((unsigned long) ctext[5]) << 16) + | (((unsigned long) ctext[6]) << 8) | ctext[7]; + + for (i = _rounds - 1; i > 0; i -= 2) { + l ^= ice_f (r, &_keysched[i]); + r ^= ice_f (l, &_keysched[i - 1]); + } + + for (i = 0; i < 4; i++) { + ptext[3 - i] = r & 0xff; + ptext[7 - i] = l & 0xff; + + r >>= 8; + l >>= 8; + } +} + + +/* + * Set 8 rounds [n, n+7] of the key schedule of an ICE key. + */ + +void +IceKey::scheduleBuild ( + unsigned short *kb, + int n, + const int *keyrot +) { + int i; + + for (i=0; i<8; i++) { + int j; + int kr = keyrot[i]; + IceSubkey *isk = &_keysched[n + i]; + + for (j=0; j<3; j++) + isk->val[j] = 0; + + for (j=0; j<15; j++) { + int k; + unsigned long *curr_sk = &isk->val[j % 3]; + + for (k=0; k<4; k++) { + unsigned short *curr_kb = &kb[(kr + k) & 3]; + int bit = *curr_kb & 1; + + *curr_sk = (*curr_sk << 1) | bit; + *curr_kb = (*curr_kb >> 1) | ((bit ^ 1) << 15); + } + } + } +} + + +/* + * Set the key schedule of an ICE key. + */ + +void +IceKey::set ( + const unsigned char *key +) { + int i; + + if (_rounds == 8) { + unsigned short kb[4]; + + for (i=0; i<4; i++) + kb[3 - i] = (key[i*2] << 8) | key[i*2 + 1]; + + scheduleBuild (kb, 0, ice_keyrot); + return; + } + + for (i=0; i<_size; i++) { + int j; + unsigned short kb[4]; + + for (j=0; j<4; j++) + kb[3 - j] = (key[i*8 + j*2] << 8) | key[i*8 + j*2 + 1]; + + scheduleBuild (kb, i*8, ice_keyrot); + scheduleBuild (kb, _rounds - 8 - i*8, &ice_keyrot[8]); + } +} + + +/* + * Return the key size, in bytes. + */ + +int +IceKey::keySize () const +{ + return (_size * 8); +} + + +/* + * Return the block size, in bytes. + */ + +int +IceKey::blockSize () const +{ + return (8); +} + +#endif // !_STATIC_LINKED || _SHARED_LIB diff --git a/mathlib/almostequal.cpp b/mathlib/almostequal.cpp new file mode 100644 index 0000000..53b8a9e --- /dev/null +++ b/mathlib/almostequal.cpp @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Fast ways to compare equality of two floats. Assumes +// sizeof(float) == sizeof(int) and we are using IEEE format. +// +// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm +//=====================================================================================// + +#include +#include + +#include "mathlib/mathlib.h" + +static inline bool AE_IsInfinite(float a) +{ + const int kInfAsInt = 0x7F800000; + + // An infinity has an exponent of 255 (shift left 23 positions) and + // a zero mantissa. There are two infinities - positive and negative. + if ((*(int*)&a & 0x7FFFFFFF) == kInfAsInt) + return true; + return false; +} + +static inline bool AE_IsNan(float a) +{ + // a NAN has an exponent of 255 (shifted left 23 positions) and + // a non-zero mantissa. + int exp = *(int*)&a & 0x7F800000; + int mantissa = *(int*)&a & 0x007FFFFF; + if (exp == 0x7F800000 && mantissa != 0) + return true; + return false; +} + +static inline int AE_Sign(float a) +{ + // The sign bit of a number is the high bit. + return (*(int*)&a) & 0x80000000; +} + +// This is the 'final' version of the AlmostEqualUlps function. +// The optional checks are included for completeness, but in many +// cases they are not necessary, or even not desirable. +bool AlmostEqual(float a, float b, int maxUlps) +{ + // There are several optional checks that you can do, depending + // on what behavior you want from your floating point comparisons. + // These checks should not be necessary and they are included + // mainly for completeness. + + // If a or b are infinity (positive or negative) then + // only return true if they are exactly equal to each other - + // that is, if they are both infinities of the same sign. + // This check is only needed if you will be generating + // infinities and you don't want them 'close' to numbers + // near FLT_MAX. + if (AE_IsInfinite(a) || AE_IsInfinite(b)) + return a == b; + + // If a or b are a NAN, return false. NANs are equal to nothing, + // not even themselves. + // This check is only needed if you will be generating NANs + // and you use a maxUlps greater than 4 million or you want to + // ensure that a NAN does not equal itself. + if (AE_IsNan(a) || AE_IsNan(b)) + return false; + + // After adjusting floats so their representations are lexicographically + // ordered as twos-complement integers a very small positive number + // will compare as 'close' to a very small negative number. If this is + // not desireable, and if you are on a platform that supports + // subnormals (which is the only place the problem can show up) then + // you need this check. + // The check for a == b is because zero and negative zero have different + // signs but are equal to each other. + if (AE_Sign(a) != AE_Sign(b)) + return a == b; + + int aInt = *(int*)&a; + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) + aInt = 0x80000000 - aInt; + // Make bInt lexicographically ordered as a twos-complement int + int bInt = *(int*)&b; + if (bInt < 0) + bInt = 0x80000000 - bInt; + + // Now we can compare aInt and bInt to find out how far apart a and b + // are. + int intDiff = abs(aInt - bInt); + if (intDiff <= maxUlps) + return true; + return false; +} + + diff --git a/mathlib/anorms.cpp b/mathlib/anorms.cpp new file mode 100644 index 0000000..600dd65 --- /dev/null +++ b/mathlib/anorms.cpp @@ -0,0 +1,181 @@ +//========= Copyright Valve Corporationf, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + + +#include "mathlib/vector.h" +#include "mathlib/anorms.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +Vector g_anorms[NUMVERTEXNORMALS] = +{ + Vector(-0.525731f, 0.000000f, 0.850651), + Vector(-0.442863f, 0.238856f, 0.864188), + Vector(-0.295242f, 0.000000f, 0.955423), + Vector(-0.309017f, 0.500000f, 0.809017), + Vector(-0.162460f, 0.262866f, 0.951056), + Vector(0.000000f, 0.000000f, 1.000000), + Vector(0.000000f, 0.850651f, 0.525731), + Vector(-0.147621f, 0.716567f, 0.681718), + Vector(0.147621f, 0.716567f, 0.681718), + Vector(0.000000f, 0.525731f, 0.850651), + Vector(0.309017f, 0.500000f, 0.809017), + Vector(0.525731f, 0.000000f, 0.850651), + Vector(0.295242f, 0.000000f, 0.955423), + Vector(0.442863f, 0.238856f, 0.864188), + Vector(0.162460f, 0.262866f, 0.951056), + Vector(-0.681718f, 0.147621f, 0.716567), + Vector(-0.809017f, 0.309017f, 0.500000), + Vector(-0.587785f, 0.425325f, 0.688191), + Vector(-0.850651f, 0.525731f, 0.000000), + Vector(-0.864188f, 0.442863f, 0.238856), + Vector(-0.716567f, 0.681718f, 0.147621), + Vector(-0.688191f, 0.587785f, 0.425325), + Vector(-0.500000f, 0.809017f, 0.309017), + Vector(-0.238856f, 0.864188f, 0.442863), + Vector(-0.425325f, 0.688191f, 0.587785), + Vector(-0.716567f, 0.681718f, -0.147621), + Vector(-0.500000f, 0.809017f, -0.309017), + Vector(-0.525731f, 0.850651f, 0.000000), + Vector(0.000000f, 0.850651f, -0.525731), + Vector(-0.238856f, 0.864188f, -0.442863), + Vector(0.000000f, 0.955423f, -0.295242), + Vector(-0.262866f, 0.951056f, -0.162460), + Vector(0.000000f, 1.000000f, 0.000000), + Vector(0.000000f, 0.955423f, 0.295242), + Vector(-0.262866f, 0.951056f, 0.162460), + Vector(0.238856f, 0.864188f, 0.442863), + Vector(0.262866f, 0.951056f, 0.162460), + Vector(0.500000f, 0.809017f, 0.309017), + Vector(0.238856f, 0.864188f, -0.442863), + Vector(0.262866f, 0.951056f, -0.162460), + Vector(0.500000f, 0.809017f, -0.309017), + Vector(0.850651f, 0.525731f, 0.000000), + Vector(0.716567f, 0.681718f, 0.147621), + Vector(0.716567f, 0.681718f, -0.147621), + Vector(0.525731f, 0.850651f, 0.000000), + Vector(0.425325f, 0.688191f, 0.587785), + Vector(0.864188f, 0.442863f, 0.238856), + Vector(0.688191f, 0.587785f, 0.425325), + Vector(0.809017f, 0.309017f, 0.500000), + Vector(0.681718f, 0.147621f, 0.716567), + Vector(0.587785f, 0.425325f, 0.688191), + Vector(0.955423f, 0.295242f, 0.000000), + Vector(1.000000f, 0.000000f, 0.000000), + Vector(0.951056f, 0.162460f, 0.262866), + Vector(0.850651f, -0.525731f, 0.000000), + Vector(0.955423f, -0.295242f, 0.000000), + Vector(0.864188f, -0.442863f, 0.238856), + Vector(0.951056f, -0.162460f, 0.262866), + Vector(0.809017f, -0.309017f, 0.500000), + Vector(0.681718f, -0.147621f, 0.716567), + Vector(0.850651f, 0.000000f, 0.525731), + Vector(0.864188f, 0.442863f, -0.238856), + Vector(0.809017f, 0.309017f, -0.500000), + Vector(0.951056f, 0.162460f, -0.262866), + Vector(0.525731f, 0.000000f, -0.850651), + Vector(0.681718f, 0.147621f, -0.716567), + Vector(0.681718f, -0.147621f, -0.716567), + Vector(0.850651f, 0.000000f, -0.525731), + Vector(0.809017f, -0.309017f, -0.500000), + Vector(0.864188f, -0.442863f, -0.238856), + Vector(0.951056f, -0.162460f, -0.262866), + Vector(0.147621f, 0.716567f, -0.681718), + Vector(0.309017f, 0.500000f, -0.809017), + Vector(0.425325f, 0.688191f, -0.587785), + Vector(0.442863f, 0.238856f, -0.864188), + Vector(0.587785f, 0.425325f, -0.688191), + Vector(0.688191f, 0.587785f, -0.425325), + Vector(-0.147621f, 0.716567f, -0.681718), + Vector(-0.309017f, 0.500000f, -0.809017), + Vector(0.000000f, 0.525731f, -0.850651), + Vector(-0.525731f, 0.000000f, -0.850651), + Vector(-0.442863f, 0.238856f, -0.864188), + Vector(-0.295242f, 0.000000f, -0.955423), + Vector(-0.162460f, 0.262866f, -0.951056), + Vector(0.000000f, 0.000000f, -1.000000), + Vector(0.295242f, 0.000000f, -0.955423), + Vector(0.162460f, 0.262866f, -0.951056), + Vector(-0.442863f, -0.238856f, -0.864188), + Vector(-0.309017f, -0.500000f, -0.809017), + Vector(-0.162460f, -0.262866f, -0.951056), + Vector(0.000000f, -0.850651f, -0.525731), + Vector(-0.147621f, -0.716567f, -0.681718), + Vector(0.147621f, -0.716567f, -0.681718), + Vector(0.000000f, -0.525731f, -0.850651), + Vector(0.309017f, -0.500000f, -0.809017), + Vector(0.442863f, -0.238856f, -0.864188), + Vector(0.162460f, -0.262866f, -0.951056), + Vector(0.238856f, -0.864188f, -0.442863), + Vector(0.500000f, -0.809017f, -0.309017), + Vector(0.425325f, -0.688191f, -0.587785), + Vector(0.716567f, -0.681718f, -0.147621), + Vector(0.688191f, -0.587785f, -0.425325), + Vector(0.587785f, -0.425325f, -0.688191), + Vector(0.000000f, -0.955423f, -0.295242), + Vector(0.000000f, -1.000000f, 0.000000), + Vector(0.262866f, -0.951056f, -0.162460), + Vector(0.000000f, -0.850651f, 0.525731), + Vector(0.000000f, -0.955423f, 0.295242), + Vector(0.238856f, -0.864188f, 0.442863), + Vector(0.262866f, -0.951056f, 0.162460), + Vector(0.500000f, -0.809017f, 0.309017), + Vector(0.716567f, -0.681718f, 0.147621), + Vector(0.525731f, -0.850651f, 0.000000), + Vector(-0.238856f, -0.864188f, -0.442863), + Vector(-0.500000f, -0.809017f, -0.309017), + Vector(-0.262866f, -0.951056f, -0.162460), + Vector(-0.850651f, -0.525731f, 0.000000), + Vector(-0.716567f, -0.681718f, -0.147621), + Vector(-0.716567f, -0.681718f, 0.147621), + Vector(-0.525731f, -0.850651f, 0.000000), + Vector(-0.500000f, -0.809017f, 0.309017), + Vector(-0.238856f, -0.864188f, 0.442863), + Vector(-0.262866f, -0.951056f, 0.162460), + Vector(-0.864188f, -0.442863f, 0.238856), + Vector(-0.809017f, -0.309017f, 0.500000), + Vector(-0.688191f, -0.587785f, 0.425325), + Vector(-0.681718f, -0.147621f, 0.716567), + Vector(-0.442863f, -0.238856f, 0.864188), + Vector(-0.587785f, -0.425325f, 0.688191), + Vector(-0.309017f, -0.500000f, 0.809017), + Vector(-0.147621f, -0.716567f, 0.681718), + Vector(-0.425325f, -0.688191f, 0.587785), + Vector(-0.162460f, -0.262866f, 0.951056), + Vector(0.442863f, -0.238856f, 0.864188), + Vector(0.162460f, -0.262866f, 0.951056), + Vector(0.309017f, -0.500000f, 0.809017), + Vector(0.147621f, -0.716567f, 0.681718), + Vector(0.000000f, -0.525731f, 0.850651), + Vector(0.425325f, -0.688191f, 0.587785), + Vector(0.587785f, -0.425325f, 0.688191), + Vector(0.688191f, -0.587785f, 0.425325), + Vector(-0.955423f, 0.295242f, 0.000000), + Vector(-0.951056f, 0.162460f, 0.262866), + Vector(-1.000000f, 0.000000f, 0.000000), + Vector(-0.850651f, 0.000000f, 0.525731), + Vector(-0.955423f, -0.295242f, 0.000000), + Vector(-0.951056f, -0.162460f, 0.262866), + Vector(-0.864188f, 0.442863f, -0.238856), + Vector(-0.951056f, 0.162460f, -0.262866), + Vector(-0.809017f, 0.309017f, -0.500000), + Vector(-0.864188f, -0.442863f, -0.238856), + Vector(-0.951056f, -0.162460f, -0.262866), + Vector(-0.809017f, -0.309017f, -0.500000), + Vector(-0.681718f, 0.147621f, -0.716567), + Vector(-0.681718f, -0.147621f, -0.716567), + Vector(-0.850651f, 0.000000f, -0.525731), + Vector(-0.688191f, 0.587785f, -0.425325), + Vector(-0.587785f, 0.425325f, -0.688191), + Vector(-0.425325f, 0.688191f, -0.587785), + Vector(-0.425325f, -0.688191f, -0.587785), + Vector(-0.587785f, -0.425325f, -0.688191), + Vector(-0.688191f, -0.587785f, -0.425325) +}; + +#endif // !_STATIC_LINKED || _SHARED_LIB \ No newline at end of file diff --git a/mathlib/bumpvects.cpp b/mathlib/bumpvects.cpp new file mode 100644 index 0000000..5edbe4d --- /dev/null +++ b/mathlib/bumpvects.cpp @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + + +#ifdef QUIVER +#include "r_local.h" +#endif +#include "mathlib/bumpvects.h" +#include "mathlib/vector.h" +#include + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// z is coming out of the face. + +void GetBumpNormals( const Vector& sVect, const Vector& tVect, const Vector& flatNormal, + const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] ) +{ + Vector tmpNormal; + bool leftHanded; + int i; + + assert( NUM_BUMP_VECTS == 3 ); + + // Are we left or right handed? + CrossProduct( sVect, tVect, tmpNormal ); + if( DotProduct( flatNormal, tmpNormal ) < 0.0f ) + { + leftHanded = true; + } + else + { + leftHanded = false; + } + + // Build a basis for the face around the phong normal + matrix3x4_t smoothBasis; + CrossProduct( phongNormal.Base(), sVect.Base(), smoothBasis[1] ); + VectorNormalize( smoothBasis[1] ); + CrossProduct( smoothBasis[1], phongNormal.Base(), smoothBasis[0] ); + VectorNormalize( smoothBasis[0] ); + VectorCopy( phongNormal.Base(), smoothBasis[2] ); + + if( leftHanded ) + { + VectorNegate( smoothBasis[1] ); + } + + // move the g_localBumpBasis into world space to create bumpNormals + for( i = 0; i < 3; i++ ) + { + VectorIRotate( g_localBumpBasis[i], smoothBasis, bumpNormals[i] ); + } +} + +#endif // !_STATIC_LINKED || _SHARED_LIB \ No newline at end of file diff --git a/mathlib/color_conversion.cpp b/mathlib/color_conversion.cpp new file mode 100644 index 0000000..e069713 --- /dev/null +++ b/mathlib/color_conversion.cpp @@ -0,0 +1,637 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Color conversion routines. +// +//=====================================================================================// + +#include +#include // Needed for FLT_EPSILON +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Gamma conversion support +//----------------------------------------------------------------------------- +static byte texgammatable[256]; // palette is sent through this to convert to screen gamma + +static float texturetolinear[256]; // texture (0..255) to linear (0..1) +static int lineartotexture[1024]; // linear (0..1) to texture (0..255) +static int lineartoscreen[1024]; // linear (0..1) to gamma corrected vertex light (0..255) + +// build a lightmap texture to combine with surface texture, adjust for src*dst+dst*src, ramp reprogramming, etc +float lineartovertex[4096]; // linear (0..4) to screen corrected vertex space (0..1?) +unsigned char lineartolightmap[4096]; // linear (0..4) to screen corrected texture value (0..255) + +static float g_Mathlib_GammaToLinear[256]; // gamma (0..1) to linear (0..1) +static float g_Mathlib_LinearToGamma[256]; // linear (0..1) to gamma (0..1) + +// This is aligned to 16-byte boundaries so that we can load it +// onto SIMD registers easily if needed (used by SSE version of lightmaps) +// TODO: move this into the one DLL that actually uses it, instead of statically +// linking it everywhere via mathlib. +ALIGN128 float power2_n[256] = // 2**(index - 128) / 255 +{ + 1.152445441982634800E-041f, 2.304890883965269600E-041f, 4.609781767930539200E-041f, 9.219563535861078400E-041f, + 1.843912707172215700E-040f, 3.687825414344431300E-040f, 7.375650828688862700E-040f, 1.475130165737772500E-039f, + 2.950260331475545100E-039f, 5.900520662951090200E-039f, 1.180104132590218000E-038f, 2.360208265180436100E-038f, + 4.720416530360872100E-038f, 9.440833060721744200E-038f, 1.888166612144348800E-037f, 3.776333224288697700E-037f, + 7.552666448577395400E-037f, 1.510533289715479100E-036f, 3.021066579430958200E-036f, 6.042133158861916300E-036f, + 1.208426631772383300E-035f, 2.416853263544766500E-035f, 4.833706527089533100E-035f, 9.667413054179066100E-035f, + 1.933482610835813200E-034f, 3.866965221671626400E-034f, 7.733930443343252900E-034f, 1.546786088668650600E-033f, + 3.093572177337301200E-033f, 6.187144354674602300E-033f, 1.237428870934920500E-032f, 2.474857741869840900E-032f, + 4.949715483739681800E-032f, 9.899430967479363700E-032f, 1.979886193495872700E-031f, 3.959772386991745500E-031f, + 7.919544773983491000E-031f, 1.583908954796698200E-030f, 3.167817909593396400E-030f, 6.335635819186792800E-030f, + 1.267127163837358600E-029f, 2.534254327674717100E-029f, 5.068508655349434200E-029f, 1.013701731069886800E-028f, + 2.027403462139773700E-028f, 4.054806924279547400E-028f, 8.109613848559094700E-028f, 1.621922769711818900E-027f, + 3.243845539423637900E-027f, 6.487691078847275800E-027f, 1.297538215769455200E-026f, 2.595076431538910300E-026f, + 5.190152863077820600E-026f, 1.038030572615564100E-025f, 2.076061145231128300E-025f, 4.152122290462256500E-025f, + 8.304244580924513000E-025f, 1.660848916184902600E-024f, 3.321697832369805200E-024f, 6.643395664739610400E-024f, + 1.328679132947922100E-023f, 2.657358265895844200E-023f, 5.314716531791688300E-023f, 1.062943306358337700E-022f, + 2.125886612716675300E-022f, 4.251773225433350700E-022f, 8.503546450866701300E-022f, 1.700709290173340300E-021f, + 3.401418580346680500E-021f, 6.802837160693361100E-021f, 1.360567432138672200E-020f, 2.721134864277344400E-020f, + 5.442269728554688800E-020f, 1.088453945710937800E-019f, 2.176907891421875500E-019f, 4.353815782843751100E-019f, + 8.707631565687502200E-019f, 1.741526313137500400E-018f, 3.483052626275000900E-018f, 6.966105252550001700E-018f, + 1.393221050510000300E-017f, 2.786442101020000700E-017f, 5.572884202040001400E-017f, 1.114576840408000300E-016f, + 2.229153680816000600E-016f, 4.458307361632001100E-016f, 8.916614723264002200E-016f, 1.783322944652800400E-015f, + 3.566645889305600900E-015f, 7.133291778611201800E-015f, 1.426658355722240400E-014f, 2.853316711444480700E-014f, + 5.706633422888961400E-014f, 1.141326684577792300E-013f, 2.282653369155584600E-013f, 4.565306738311169100E-013f, + 9.130613476622338300E-013f, 1.826122695324467700E-012f, 3.652245390648935300E-012f, 7.304490781297870600E-012f, + 1.460898156259574100E-011f, 2.921796312519148200E-011f, 5.843592625038296500E-011f, 1.168718525007659300E-010f, + 2.337437050015318600E-010f, 4.674874100030637200E-010f, 9.349748200061274400E-010f, 1.869949640012254900E-009f, + 3.739899280024509800E-009f, 7.479798560049019500E-009f, 1.495959712009803900E-008f, 2.991919424019607800E-008f, + 5.983838848039215600E-008f, 1.196767769607843100E-007f, 2.393535539215686200E-007f, 4.787071078431372500E-007f, + 9.574142156862745000E-007f, 1.914828431372549000E-006f, 3.829656862745098000E-006f, 7.659313725490196000E-006f, + 1.531862745098039200E-005f, 3.063725490196078400E-005f, 6.127450980392156800E-005f, 1.225490196078431400E-004f, + 2.450980392156862700E-004f, 4.901960784313725400E-004f, 9.803921568627450800E-004f, 1.960784313725490200E-003f, + 3.921568627450980300E-003f, 7.843137254901960700E-003f, 1.568627450980392100E-002f, 3.137254901960784300E-002f, + 6.274509803921568500E-002f, 1.254901960784313700E-001f, 2.509803921568627400E-001f, 5.019607843137254800E-001f, + 1.003921568627451000E+000f, 2.007843137254901900E+000f, 4.015686274509803900E+000f, 8.031372549019607700E+000f, + 1.606274509803921500E+001f, 3.212549019607843100E+001f, 6.425098039215686200E+001f, 1.285019607843137200E+002f, + 2.570039215686274500E+002f, 5.140078431372548900E+002f, 1.028015686274509800E+003f, 2.056031372549019600E+003f, + 4.112062745098039200E+003f, 8.224125490196078300E+003f, 1.644825098039215700E+004f, 3.289650196078431300E+004f, + 6.579300392156862700E+004f, 1.315860078431372500E+005f, 2.631720156862745100E+005f, 5.263440313725490100E+005f, + 1.052688062745098000E+006f, 2.105376125490196000E+006f, 4.210752250980392100E+006f, 8.421504501960784200E+006f, + 1.684300900392156800E+007f, 3.368601800784313700E+007f, 6.737203601568627400E+007f, 1.347440720313725500E+008f, + 2.694881440627450900E+008f, 5.389762881254901900E+008f, 1.077952576250980400E+009f, 2.155905152501960800E+009f, + 4.311810305003921500E+009f, 8.623620610007843000E+009f, 1.724724122001568600E+010f, 3.449448244003137200E+010f, + 6.898896488006274400E+010f, 1.379779297601254900E+011f, 2.759558595202509800E+011f, 5.519117190405019500E+011f, + 1.103823438081003900E+012f, 2.207646876162007800E+012f, 4.415293752324015600E+012f, 8.830587504648031200E+012f, + 1.766117500929606200E+013f, 3.532235001859212500E+013f, 7.064470003718425000E+013f, 1.412894000743685000E+014f, + 2.825788001487370000E+014f, 5.651576002974740000E+014f, 1.130315200594948000E+015f, 2.260630401189896000E+015f, + 4.521260802379792000E+015f, 9.042521604759584000E+015f, 1.808504320951916800E+016f, 3.617008641903833600E+016f, + 7.234017283807667200E+016f, 1.446803456761533400E+017f, 2.893606913523066900E+017f, 5.787213827046133800E+017f, + 1.157442765409226800E+018f, 2.314885530818453500E+018f, 4.629771061636907000E+018f, 9.259542123273814000E+018f, + 1.851908424654762800E+019f, 3.703816849309525600E+019f, 7.407633698619051200E+019f, 1.481526739723810200E+020f, + 2.963053479447620500E+020f, 5.926106958895241000E+020f, 1.185221391779048200E+021f, 2.370442783558096400E+021f, + 4.740885567116192800E+021f, 9.481771134232385600E+021f, 1.896354226846477100E+022f, 3.792708453692954200E+022f, + 7.585416907385908400E+022f, 1.517083381477181700E+023f, 3.034166762954363400E+023f, 6.068333525908726800E+023f, + 1.213666705181745400E+024f, 2.427333410363490700E+024f, 4.854666820726981400E+024f, 9.709333641453962800E+024f, + 1.941866728290792600E+025f, 3.883733456581585100E+025f, 7.767466913163170200E+025f, 1.553493382632634000E+026f, + 3.106986765265268100E+026f, 6.213973530530536200E+026f, 1.242794706106107200E+027f, 2.485589412212214500E+027f, + 4.971178824424429000E+027f, 9.942357648848857900E+027f, 1.988471529769771600E+028f, 3.976943059539543200E+028f, + 7.953886119079086300E+028f, 1.590777223815817300E+029f, 3.181554447631634500E+029f, 6.363108895263269100E+029f, + 1.272621779052653800E+030f, 2.545243558105307600E+030f, 5.090487116210615300E+030f, 1.018097423242123100E+031f, + 2.036194846484246100E+031f, 4.072389692968492200E+031f, 8.144779385936984400E+031f, 1.628955877187396900E+032f, + 3.257911754374793800E+032f, 6.515823508749587500E+032f, 1.303164701749917500E+033f, 2.606329403499835000E+033f, + 5.212658806999670000E+033f, 1.042531761399934000E+034f, 2.085063522799868000E+034f, 4.170127045599736000E+034f, + 8.340254091199472000E+034f, 1.668050818239894400E+035f, 3.336101636479788800E+035f, 6.672203272959577600E+035f +}; + +// You can use this to double check the exponent table and assert that +// the precomputation is correct. +#ifdef DBGFLAG_ASSERT +#pragma warning(push) +#pragma warning( disable : 4189 ) // disable unused local variable warning +static void CheckExponentTable() +{ + for( int i = 0; i < 256; i++ ) + { + float testAgainst = pow( 2.0f, i - 128 ) / 255.0f; + float diff = testAgainst - power2_n[i] ; + float relativeDiff = diff / testAgainst; + Assert( testAgainst == 0 ? + power2_n[i] < 1.16E-041 : + power2_n[i] == testAgainst ); + } +} +#pragma warning(pop) +#endif + +void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright ) +{ + int i, inf; + float g1, g3; + + // Con_Printf("BuildGammaTable %.1f %.1f %.1f\n", g, v_lightgamma.GetFloat(), v_texgamma.GetFloat() ); + + float g = gamma; + if (g > 3.0) + { + g = 3.0; + } + + g = 1.0 / g; + g1 = texGamma * g; + + if (brightness <= 0.0) + { + g3 = 0.125; + } + else if (brightness > 1.0) + { + g3 = 0.05; + } + else + { + g3 = 0.125 - (brightness * brightness) * 0.075; + } + + for (i=0 ; i<256 ; i++) + { + inf = 255 * pow ( i/255.f, g1 ); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + texgammatable[i] = inf; + } + + for (i=0 ; i<1024 ; i++) + { + float f; + + f = i / 1023.0; + + // scale up + if (brightness > 1.0) + f = f * brightness; + + // shift up + if (f <= g3) + f = (f / g3) * 0.125; + else + f = 0.125 + ((f - g3) / (1.0 - g3)) * 0.875; + + // convert linear space to desired gamma space + inf = 255 * pow ( f, g ); + + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + lineartoscreen[i] = inf; + } + + /* + for (i=0 ; i<1024 ; i++) + { + // convert from screen gamma space to linear space + lineargammatable[i] = 1023 * pow ( i/1023.0, v_gamma.GetFloat() ); + // convert from linear gamma space to screen space + screengammatable[i] = 1023 * pow ( i/1023.0, 1.0 / v_gamma.GetFloat() ); + } + */ + + for (i=0 ; i<256 ; i++) + { + // convert from nonlinear texture space (0..255) to linear space (0..1) + texturetolinear[i] = pow( i / 255.f, texGamma ); + + // convert from linear space (0..1) to nonlinear (sRGB) space (0..1) + g_Mathlib_LinearToGamma[i] = LinearToGammaFullRange( i / 255.f ); + + // convert from sRGB gamma space (0..1) to linear space (0..1) + g_Mathlib_GammaToLinear[i] = GammaToLinearFullRange( i / 255.f ); + } + + for (i=0 ; i<1024 ; i++) + { + // convert from linear space (0..1) to nonlinear texture space (0..255) + lineartotexture[i] = pow( i / 1023.0, 1.0 / texGamma ) * 255; + } + +#if 0 + for (i=0 ; i<256 ; i++) + { + float f; + + // convert from nonlinear lightmap space (0..255) to linear space (0..4) + // f = (i / 255.0) * sqrt( 4 ); + f = i * (2.0 / 255.0); + f = f * f; + + texlighttolinear[i] = f; + } +#endif + + { + float f; + float overbrightFactor = 1.0f; + + // Can't do overbright without texcombine + // UNDONE: Add GAMMA ramp to rectify this + if ( overbright == 2 ) + { + overbrightFactor = 0.5; + } + else if ( overbright == 4 ) + { + overbrightFactor = 0.25; + } + + for (i=0 ; i<4096 ; i++) + { + // convert from linear 0..4 (x1024) to screen corrected vertex space (0..1?) + f = pow ( i/1024.0, 1.0 / gamma ); + + lineartovertex[i] = f * overbrightFactor; + if (lineartovertex[i] > 1) + lineartovertex[i] = 1; + + int nLightmap = RoundFloatToInt( f * 255 * overbrightFactor ); + nLightmap = clamp( nLightmap, 0, 255 ); + lineartolightmap[i] = (unsigned char)nLightmap; + } + } +} + +float GammaToLinearFullRange( float gamma ) +{ + return pow( gamma, 2.2f ); +} + +float LinearToGammaFullRange( float linear ) +{ + return pow( linear, 1.0f / 2.2f ); +} + +float GammaToLinear( float gamma ) +{ + Assert( s_bMathlibInitialized ); + if ( gamma < 0.0f ) + { + return 0.0f; + } + + if ( gamma >= 0.95f ) + { + // Use GammaToLinearFullRange maybe if you trip this. +// X360TEMP +// Assert( gamma <= 1.0f ); + return 1.0f; + } + + int index = RoundFloatToInt( gamma * 255.0f ); + Assert( index >= 0 && index < 256 ); + return g_Mathlib_GammaToLinear[index]; +} + +float LinearToGamma( float linear ) +{ + Assert( s_bMathlibInitialized ); + if ( linear < 0.0f ) + { + return 0.0f; + } + if ( linear > 1.0f ) + { + // Use LinearToGammaFullRange maybe if you trip this. + Assert( 0 ); + return 1.0f; + } + + int index = RoundFloatToInt( linear * 255.0f ); + Assert( index >= 0 && index < 256 ); + return g_Mathlib_LinearToGamma[index]; +} + +//----------------------------------------------------------------------------- +// Helper functions to convert between sRGB and 360 gamma space +//----------------------------------------------------------------------------- +float SrgbGammaToLinear( float flSrgbGammaValue ) +{ + float x = clamp( flSrgbGammaValue, 0.0f, 1.0f ); + return ( x <= 0.04045f ) ? ( x / 12.92f ) : ( pow( ( x + 0.055f ) / 1.055f, 2.4f ) ); +} + +float SrgbLinearToGamma( float flLinearValue ) +{ + float x = clamp( flLinearValue, 0.0f, 1.0f ); + return ( x <= 0.0031308f ) ? ( x * 12.92f ) : ( 1.055f * pow( x, ( 1.0f / 2.4f ) ) ) - 0.055f; +} + +float X360GammaToLinear( float fl360GammaValue ) +{ + float flLinearValue; + + fl360GammaValue = clamp( fl360GammaValue, 0.0f, 1.0f ); + if ( fl360GammaValue < ( 96.0f / 255.0f ) ) + { + if ( fl360GammaValue < ( 64.0f / 255.0f ) ) + { + flLinearValue = fl360GammaValue * 255.0f; + } + else + { + flLinearValue = fl360GammaValue * ( 255.0f * 2.0f ) - 64.0f; + flLinearValue += floor( flLinearValue * ( 1.0f / 512.0f ) ); + } + } + else + { + if( fl360GammaValue < ( 192.0f / 255.0f ) ) + { + flLinearValue = fl360GammaValue * ( 255.0f * 4.0f ) - 256.0f; + flLinearValue += floor( flLinearValue * ( 1.0f / 256.0f ) ); + } + else + { + flLinearValue = fl360GammaValue * ( 255.0f * 8.0f ) - 1024.0f; + flLinearValue += floor( flLinearValue * ( 1.0f / 128.0f ) ); + } + } + + flLinearValue *= 1.0f / 1023.0f; + + flLinearValue = clamp( flLinearValue, 0.0f, 1.0f ); + return flLinearValue; +} + +float X360LinearToGamma( float flLinearValue ) +{ + float fl360GammaValue; + + flLinearValue = clamp( flLinearValue, 0.0f, 1.0f ); + if ( flLinearValue < ( 128.0f / 1023.0f ) ) + { + if ( flLinearValue < ( 64.0f / 1023.0f ) ) + { + fl360GammaValue = flLinearValue * ( 1023.0f * ( 1.0f / 255.0f ) ); + } + else + { + fl360GammaValue = flLinearValue * ( ( 1023.0f / 2.0f ) * ( 1.0f / 255.0f ) ) + ( 32.0f / 255.0f ); + } + } + else + { + if ( flLinearValue < ( 512.0f / 1023.0f ) ) + { + fl360GammaValue = flLinearValue * ( ( 1023.0f / 4.0f ) * ( 1.0f / 255.0f ) ) + ( 64.0f / 255.0f ); + } + else + { + fl360GammaValue = flLinearValue * ( ( 1023.0f /8.0f ) * ( 1.0f / 255.0f ) ) + ( 128.0f /255.0f ); // 1.0 -> 1.0034313725490196078431372549016 + if ( fl360GammaValue > 1.0f ) + { + fl360GammaValue = 1.0f; + } + } + } + + fl360GammaValue = clamp( fl360GammaValue, 0.0f, 1.0f ); + return fl360GammaValue; +} + +float SrgbGammaTo360Gamma( float flSrgbGammaValue ) +{ + float flLinearValue = SrgbGammaToLinear( flSrgbGammaValue ); + float fl360GammaValue = X360LinearToGamma( flLinearValue ); + return fl360GammaValue; +} + +// convert texture to linear 0..1 value +float TextureToLinear( int c ) +{ + Assert( s_bMathlibInitialized ); + if (c < 0) + return 0; + if (c > 255) + return 1.0; + + return texturetolinear[c]; +} + +// convert texture to linear 0..1 value +int LinearToTexture( float f ) +{ + Assert( s_bMathlibInitialized ); + int i; + i = f * 1023; // assume 0..1 range + if (i < 0) + i = 0; + if (i > 1023) + i = 1023; + + return lineartotexture[i]; +} + + +// converts 0..1 linear value to screen gamma (0..255) +int LinearToScreenGamma( float f ) +{ + Assert( s_bMathlibInitialized ); + int i; + i = f * 1023; // assume 0..1 range + if (i < 0) + i = 0; + if (i > 1023) + i = 1023; + + return lineartoscreen[i]; +} + +void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out ) +{ + Assert( s_bMathlibInitialized ); + // FIXME: Why is there a factor of 255 built into this? + out.x = 255.0f * TexLightToLinear( in.r, in.exponent ); + out.y = 255.0f * TexLightToLinear( in.g, in.exponent ); + out.z = 255.0f * TexLightToLinear( in.b, in.exponent ); +} + +#if 0 +// assumes that the desired mantissa range is 128..255 +static int VectorToColorRGBExp32_CalcExponent( float in ) +{ + int power = 0; + + if( in != 0.0f ) + { + while( in > 255.0f ) + { + power += 1; + in *= 0.5f; + } + + while( in < 128.0f ) + { + power -= 1; + in *= 2.0f; + } + } + + return power; +} + +void VectorToColorRGBExp32( const Vector& vin, ColorRGBExp32 &c ) +{ + Vector v = vin; + Assert( s_bMathlibInitialized ); + Assert( v.x >= 0.0f && v.y >= 0.0f && v.z >= 0.0f ); + int i; + float max = v[0]; + for( i = 1; i < 3; i++ ) + { + // Get the maximum value. + if( v[i] > max ) + { + max = v[i]; + } + } + + // figure out the exponent for this luxel. + int exponent = VectorToColorRGBExp32_CalcExponent( max ); + + // make the exponent fits into a signed byte. + if( exponent < -128 ) + { + exponent = -128; + } + else if( exponent > 127 ) + { + exponent = 127; + } + + // undone: optimize with a table + float scalar = pow( 2.0f, -exponent ); + // convert to mantissa x 2^exponent format + for( i = 0; i < 3; i++ ) + { + v[i] *= scalar; + // clamp + if( v[i] > 255.0f ) + { + v[i] = 255.0f; + } + } + c.r = ( unsigned char )v[0]; + c.g = ( unsigned char )v[1]; + c.b = ( unsigned char )v[2]; + c.exponent = ( signed char )exponent; +} + +#else + +// given a floating point number f, return an exponent e such that +// for f' = f * 2^e, f is on [128..255]. +// Uses IEEE 754 representation to directly extract this information +// from the float. +inline static int VectorToColorRGBExp32_CalcExponent( const float *pin ) +{ + // The thing we will take advantage of here is that the exponent component + // is stored in the float itself, and because we want to map to 128..255, we + // want an "ideal" exponent of 2^7. So, we compute the difference between the + // input exponent and 7 to work out the normalizing exponent. Thus if you pass in + // 32 (represented in IEEE 754 as 2^5), this function will return 2 + // (because 32 * 2^2 = 128) + if (*pin == 0.0f) + return 0; + + unsigned int fbits = *reinterpret_cast(pin); + + // the exponent component is bits 23..30, and biased by +127 + const unsigned int biasedSeven = 7 + 127; + + signed int expComponent = ( fbits & 0x7F800000 ) >> 23; + expComponent -= biasedSeven; // now the difference from seven (positive if was less than, etc) + return expComponent; +} + + + +/// Slightly faster version of the function to turn a float-vector color into +/// a compressed-exponent notation 32bit color. However, still not SIMD optimized. +/// PS3 developer: note there is a movement of a float onto an int here, which is +/// bad on the base registers -- consider doing this as Altivec code, or better yet +/// moving it onto the cell. +/// \warning: Assumes an IEEE 754 single-precision float representation! Those of you +/// porting to an 8080 are out of luck. +void VectorToColorRGBExp32( const Vector& vin, ColorRGBExp32 &c ) +{ + Assert( s_bMathlibInitialized ); + Assert( vin.x >= 0.0f && vin.y >= 0.0f && vin.z >= 0.0f ); + + // work out which of the channels is the largest ( we will use that to map the exponent ) + // this is a sluggish branch-based decision tree -- most architectures will offer a [max] + // assembly opcode to do this faster. + const float *pMax; + if (vin.x > vin.y) + { + if (vin.x > vin.z) + { + pMax = &vin.x; + } + else + { + pMax = &vin.z; + } + } + else + { + if (vin.y > vin.z) + { + pMax = &vin.y; + } + else + { + pMax = &vin.z; + } + } + + // now work out the exponent for this luxel. + signed int exponent = VectorToColorRGBExp32_CalcExponent( pMax ); + + // make sure the exponent fits into a signed byte. + // (in single precision format this is assured because it was a signed byte to begin with) + Assert(exponent > -128 && exponent <= 127); + + // promote the exponent back onto a scalar that we'll use to normalize all the numbers + float scalar; + { + unsigned int fbits = (127 - exponent) << 23; + scalar = *reinterpret_cast(&fbits); + } + + // We can totally wind up above 255 and that's okay--but above 256 would be right out. + Assert(vin.x * scalar < 256.0f && + vin.y * scalar < 256.0f && + vin.z * scalar < 256.0f); + + // This awful construction is necessary to prevent VC2005 from using the + // fldcw/fnstcw control words around every float-to-unsigned-char operation. + { + int red = (vin.x * scalar); + int green = (vin.y * scalar); + int blue = (vin.z * scalar); + + c.r = red; + c.g = green; + c.b = blue; + } + /* + c.r = ( unsigned char )(vin.x * scalar); + c.g = ( unsigned char )(vin.y * scalar); + c.b = ( unsigned char )(vin.z * scalar); + */ + + c.exponent = ( signed char )exponent; +} + +#endif \ No newline at end of file diff --git a/mathlib/halton.cpp b/mathlib/halton.cpp new file mode 100644 index 0000000..f9daae7 --- /dev/null +++ b/mathlib/halton.cpp @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include + +HaltonSequenceGenerator_t::HaltonSequenceGenerator_t(int b) +{ + base=b; + fbase=(float) b; + seed=1; + +} + +float HaltonSequenceGenerator_t::GetElement(int elem) +{ + int tmpseed=seed; + float ret=0.0; + float base_inv=1.0/fbase; + while(tmpseed) + { + int dig=tmpseed % base; + ret+=((float) dig)*base_inv; + base_inv/=fbase; + tmpseed/=base; + } + return ret; +} diff --git a/mathlib/imagequant.cpp b/mathlib/imagequant.cpp new file mode 100644 index 0000000..3f26e3a --- /dev/null +++ b/mathlib/imagequant.cpp @@ -0,0 +1,96 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include +#include + +#define N_EXTRAVALUES 1 +#define N_DIMENSIONS (3+N_EXTRAVALUES) + +#define PIXEL(x,y,c) Image[4*((x)+((Width*(y))))+c] + +static uint8 Weights[]={5,7,4,8}; +static int ExtraValueXForms[3*N_EXTRAVALUES]={ + 76,151,28, +}; + + + +#define MAX_QUANTIZE_IMAGE_WIDTH 4096 + +void ColorQuantize(uint8 const *Image, + int Width, + int Height, + int flags, int ncolors, + uint8 *out_pixels, + uint8 *out_palette, + int firstcolor) +{ + int Error[MAX_QUANTIZE_IMAGE_WIDTH+1][3][2]; + struct Sample *s=AllocSamples(Width*Height,N_DIMENSIONS); + int x,y,c; + for(y=0;yValue[c]=PIXEL(x,y,c); + // now, let's generate extra values to quantize on + for(int i=0;i>=8; + NthSample(s,y*Width+x,N_DIMENSIONS)->Value[c]=(uint8) + (vmin(255,vmax(0,val1))); + } + } + struct QuantizedValue *q=Quantize(s,Width*Height,N_DIMENSIONS, + ncolors,Weights,firstcolor); + delete[] s; + memset(out_palette,0x55,768); + for(int p=0;p<256;p++) + { + struct QuantizedValue *v=FindQNode(q,p); + if (v) + for(int c=0;c<3;c++) + out_palette[p*3+c]=v->Mean[c]; + } + memset(Error,0,sizeof(Error)); + for(y=0;yvalue); + if (! (flags & QUANTFLAGS_NODITHER)) + for(int i=0;i<3;i++) + { + int newerr=samp[i]-f->Mean[i]; + int orthog_error=(newerr*3)/8; + Error[x+1][i][ErrorUse]+=orthog_error; + Error[x][i][ErrorUpdate]=orthog_error; + Error[x+1][i][ErrorUpdate]=newerr-2*orthog_error; + } + } + } + if (q) FreeQuantization(q); +} + diff --git a/mathlib/lightdesc.cpp b/mathlib/lightdesc.cpp new file mode 100644 index 0000000..7d69282 --- /dev/null +++ b/mathlib/lightdesc.cpp @@ -0,0 +1,312 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include +#include +#include "mathlib.h" + +void LightDesc_t::RecalculateDerivedValues(void) +{ + m_Flags = LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED; + if (m_Attenuation0) + m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0; + if (m_Attenuation1) + m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1; + if (m_Attenuation2) + m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2; + + if (m_Type==MATERIAL_LIGHT_SPOT) + { + m_ThetaDot=cos(m_Theta); + m_PhiDot=cos(m_Phi); + float spread=m_ThetaDot-m_PhiDot; + if (spread>1.0e-10) + { + // note - this quantity is very sensitive to round off error. the sse + // reciprocal approximation won't cut it here. + OneOver_ThetaDot_Minus_PhiDot=1.0/spread; + } + else + { + // hard falloff instead of divide by zero + OneOver_ThetaDot_Minus_PhiDot=1.0; + } + } + if (m_Type==MATERIAL_LIGHT_DIRECTIONAL) + { + // set position to be real far away in the right direction + m_Position=m_Direction; + m_Position *= 2.0e6; + } + + m_RangeSquared=m_Range*m_Range; + +} + +void LightDesc_t::ComputeLightAtPointsForDirectional( + const FourVectors &pos, const FourVectors &normal, + FourVectors &color, bool DoHalfLambert ) const +{ + FourVectors delta; + delta.DuplicateVector(m_Direction); +// delta.VectorNormalizeFast(); + fltx4 strength=delta*normal; + if (DoHalfLambert) + { + strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives); + } + else + strength=MaxSIMD(Four_Zeros,delta*normal); + + color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x))); + color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y))); + color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z))); +} + + +void LightDesc_t::ComputeLightAtPoints( const FourVectors &pos, const FourVectors &normal, + FourVectors &color, bool DoHalfLambert ) const +{ + FourVectors delta; + Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL)); + switch (m_Type) + { + case MATERIAL_LIGHT_POINT: + case MATERIAL_LIGHT_SPOT: + delta.DuplicateVector(m_Position); + delta-=pos; + break; + + case MATERIAL_LIGHT_DIRECTIONAL: + ComputeLightAtPointsForDirectional( pos, normal, color, DoHalfLambert ); + return; + } + + fltx4 dist2 = delta*delta; + + dist2=MaxSIMD( Four_Ones, dist2 ); + + fltx4 falloff; + + if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 ) + { + falloff = ReplicateX4(m_Attenuation0); + } + else + falloff= Four_Epsilons; + + if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 ) + { + falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2))); + } + + if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 ) + { + falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2)); + } + + falloff=ReciprocalEstSIMD(falloff); + // Cull out light beyond this radius + // now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format + if (m_Range != 0.f) + { + fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!! + falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared)); + } + + delta.VectorNormalizeFast(); + fltx4 strength=delta*normal; + if (DoHalfLambert) + { + strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives); + } + else + strength=MaxSIMD(Four_Zeros,delta*normal); + + switch(m_Type) + { + case MATERIAL_LIGHT_POINT: + // half-lambert + break; + + case MATERIAL_LIGHT_SPOT: + { + fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff + + + fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(OneOver_ThetaDot_Minus_PhiDot), + SubSIMD(dot2,ReplicateX4(m_PhiDot))); + cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones); + + if ((m_Falloff!=0.0) && (m_Falloff!=1.0)) + { + // !!speed!! could compute integer exponent needed by powsimd and store in light + cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff); + } + strength=MulSIMD(cone_falloff_scale,strength); + + // now, zero out lighting where dot2 range^2. !!speed!! lights should store dist^2 in sse format + if (m_Range != 0.f) + { + fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!! + falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared)); + } + + delta.VectorNormalizeFast(); + fltx4 strength = Four_Ones; + //fltx4 strength=delta; + //fltx4 strength = MaxSIMD(Four_Zeros,delta); + + switch(m_Type) + { + case MATERIAL_LIGHT_POINT: + // half-lambert + break; + + case MATERIAL_LIGHT_SPOT: + { + fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff + + + fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(OneOver_ThetaDot_Minus_PhiDot), + SubSIMD(dot2,ReplicateX4(m_PhiDot))); + cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones); + + if ((m_Falloff!=0.0) && (m_Falloff!=1.0)) + { + // !!speed!! could compute integer exponent needed by powsimd and store in light + cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff); + } + strength=MulSIMD(cone_falloff_scale,strength); + + // now, zero out lighting where dot2 0 ) + m_Color *= fScaleFactor; +} + +void LightDesc_t::SetupNewStyleAttenuation( float fFiftyPercentDistance, + float fZeroPercentDistance ) +{ + // new style storing 50% and 0% distances + float d50=fFiftyPercentDistance; + float d0=fZeroPercentDistance; + if (d0 + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {8B8B7962-9D35-4CDC-890E-ACCE3B4ADC6E} + mathlib + 10.0 + + + + Application + true + v142 + MultiByte + + + Application + true + v142 + MultiByte + + + StaticLibrary + false + v142 + true + MultiByte + + + StaticLibrary + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\lib\public + + + $(SolutionDir)\lib\public + + + + Level3 + Disabled + true + + + true + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + ..\common;..\public;..\public\tier0;..\public\tier1;..\public\mathlib + Speed + RAD_TELEMETRY_DISABLED;WIN64;_WIN64;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_ALLOW_RUNTIME_LIBRARY_MISMATCH;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_MSC_VER_MISMATCH;%(PreprocessorDefinitions);COMPILER_MSVC64;COMPILER_MSVC;_DLL_EXT=.dll;LIBNAME=mathlib;BINK_VIDEO;AVI_VIDEO;WMV_VIDEO;DEV_BUILD;FRAME_POINTER_OMISSION_DISABLED;MATHLIB_LIB;_EXTERNAL_DLL_EXT=.dll;VPCGAMECAPS=GMOD;PROJECTDIR=.\;SOURCE1=1;VPCGAME=gmod + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + RAD_TELEMETRY_DISABLED;WIN64;_WIN64;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_ALLOW_RUNTIME_LIBRARY_MISMATCH;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_MSC_VER_MISMATCH;%(PreprocessorDefinitions);COMPILER_MSVC64;COMPILER_MSVC;_DLL_EXT=.dll;LIBNAME=mathlib;BINK_VIDEO;AVI_VIDEO;WMV_VIDEO;DEV_BUILD;FRAME_POINTER_OMISSION_DISABLED;MATHLIB_LIB;_EXTERNAL_DLL_EXT=.dll;VPCGAMECAPS=GMOD;PROJECTDIR=.\;SOURCE1=1;VPCGAME=gmod + ..\common;..\public;..\public\tier0;..\public\tier1;..\public\mathlib + Speed + Fast + + + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mathlib/mathlib.vcxproj.filters b/mathlib/mathlib.vcxproj.filters new file mode 100644 index 0000000..27b0ac9 --- /dev/null +++ b/mathlib/mathlib.vcxproj.filters @@ -0,0 +1,96 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/mathlib/mathlib_base.cpp b/mathlib/mathlib_base.cpp new file mode 100644 index 0000000..aa3c952 --- /dev/null +++ b/mathlib/mathlib_base.cpp @@ -0,0 +1,4303 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Math primitives. +// +//===========================================================================// + +/// FIXME: As soon as all references to mathlib.c are gone, include it in here + +#include +#include // Needed for FLT_EPSILON + +#include "tier0/basetypes.h" +#include +#include "tier0/dbg.h" + +#include "tier0/vprof.h" +//#define _VPROF_MATHLIB + +#pragma warning(disable:4244) // "conversion from 'const int' to 'float', possible loss of data" +#pragma warning(disable:4730) // "mixing _m64 and floating point expressions may result in incorrect code" + +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#if !defined( _X360 ) +#include "mathlib/amd3dx.h" +#ifndef OSX +#include "3dnow.h" +#endif +#include "sse.h" +#endif + +#include "mathlib/ssemath.h" +#include "mathlib/ssequaternion.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +bool s_bMathlibInitialized = false; + +#ifdef PARANOID +// User must provide an implementation of Sys_Error() +void Sys_Error (char *error, ...); +#endif + +const Vector vec3_origin(0,0,0); +const QAngle vec3_angle(0,0,0); +const Vector vec3_invalid( FLT_MAX, FLT_MAX, FLT_MAX ); +const int nanmask = 255<<23; + +//----------------------------------------------------------------------------- +// Standard C implementations of optimized routines: +//----------------------------------------------------------------------------- +float _sqrtf(float _X) +{ + Assert( s_bMathlibInitialized ); + return sqrtf(_X); +} + +float _rsqrtf(float x) +{ + Assert( s_bMathlibInitialized ); + + return 1.f / _sqrtf( x ); +} + +float FASTCALL _VectorNormalize (Vector& vec) +{ +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "_VectorNormalize", "Mathlib" ); +#endif + Assert( s_bMathlibInitialized ); + float radius = sqrtf(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z); + + // FLT_EPSILON is added to the radius to eliminate the possibility of divide by zero. + float iradius = 1.f / ( radius + FLT_EPSILON ); + + vec.x *= iradius; + vec.y *= iradius; + vec.z *= iradius; + + return radius; +} + +// TODO: Add fast C VectorNormalizeFast. +// Perhaps use approximate rsqrt trick, if the accuracy isn't too bad. +void FASTCALL _VectorNormalizeFast (Vector& vec) +{ + Assert( s_bMathlibInitialized ); + + // FLT_EPSILON is added to the radius to eliminate the possibility of divide by zero. + float iradius = 1.f / ( sqrtf(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z) + FLT_EPSILON ); + + vec.x *= iradius; + vec.y *= iradius; + vec.z *= iradius; + +} + +float _InvRSquared(const float* v) +{ + Assert( s_bMathlibInitialized ); + float r2 = DotProduct(v, v); + return r2 < 1.f ? 1.f : 1/r2; +} + +//----------------------------------------------------------------------------- +// Function pointers selecting the appropriate implementation +//----------------------------------------------------------------------------- +float (*pfSqrt)(float x) = _sqrtf; +float (*pfRSqrt)(float x) = _rsqrtf; +float (*pfRSqrtFast)(float x) = _rsqrtf; +float (FASTCALL *pfVectorNormalize)(Vector& v) = _VectorNormalize; +void (FASTCALL *pfVectorNormalizeFast)(Vector& v) = _VectorNormalizeFast; +float (*pfInvRSquared)(const float* v) = _InvRSquared; +void (*pfFastSinCos)(float x, float* s, float* c) = SinCos; +float (*pfFastCos)(float x) = cosf; + +float SinCosTable[SIN_TABLE_SIZE]; +void InitSinCosTable() +{ + for( int i = 0; i < SIN_TABLE_SIZE; i++ ) + { + SinCosTable[i] = sin(i * 2.0 * M_PI / SIN_TABLE_SIZE); + } +} + +qboolean VectorsEqual( const float *v1, const float *v2 ) +{ + Assert( s_bMathlibInitialized ); + return ( ( v1[0] == v2[0] ) && + ( v1[1] == v2[1] ) && + ( v1[2] == v2[2] ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Generates Euler angles given a left-handed orientation matrix. The +// columns of the matrix contain the forward, left, and up vectors. +// Input : matrix - Left-handed orientation matrix. +// angles[PITCH, YAW, ROLL]. Receives right-handed counterclockwise +// rotations in degrees around Y, Z, and X respectively. +//----------------------------------------------------------------------------- + +void MatrixAngles( const matrix3x4_t& matrix, RadianEuler &angles, Vector &position ) +{ + MatrixGetColumn( matrix, 3, position ); + MatrixAngles( matrix, angles ); +} + +void MatrixAngles( const matrix3x4_t &matrix, Quaternion &q, Vector &pos ) +{ +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "MatrixQuaternion", "Mathlib" ); +#endif + float trace; + trace = matrix[0][0] + matrix[1][1] + matrix[2][2] + 1.0f; + if( trace > 1.0f + FLT_EPSILON ) + { + // VPROF_INCREMENT_COUNTER("MatrixQuaternion A",1); + q.x = ( matrix[2][1] - matrix[1][2] ); + q.y = ( matrix[0][2] - matrix[2][0] ); + q.z = ( matrix[1][0] - matrix[0][1] ); + q.w = trace; + } + else if ( matrix[0][0] > matrix[1][1] && matrix[0][0] > matrix[2][2] ) + { + // VPROF_INCREMENT_COUNTER("MatrixQuaternion B",1); + trace = 1.0f + matrix[0][0] - matrix[1][1] - matrix[2][2]; + q.x = trace; + q.y = (matrix[1][0] + matrix[0][1] ); + q.z = (matrix[0][2] + matrix[2][0] ); + q.w = (matrix[2][1] - matrix[1][2] ); + } + else if (matrix[1][1] > matrix[2][2]) + { + // VPROF_INCREMENT_COUNTER("MatrixQuaternion C",1); + trace = 1.0f + matrix[1][1] - matrix[0][0] - matrix[2][2]; + q.x = (matrix[0][1] + matrix[1][0] ); + q.y = trace; + q.z = (matrix[2][1] + matrix[1][2] ); + q.w = (matrix[0][2] - matrix[2][0] ); + } + else + { + // VPROF_INCREMENT_COUNTER("MatrixQuaternion D",1); + trace = 1.0f + matrix[2][2] - matrix[0][0] - matrix[1][1]; + q.x = (matrix[0][2] + matrix[2][0] ); + q.y = (matrix[2][1] + matrix[1][2] ); + q.z = trace; + q.w = (matrix[1][0] - matrix[0][1] ); + } + + QuaternionNormalize( q ); + +#if 0 + // check against the angle version + RadianEuler ang; + MatrixAngles( matrix, ang ); + Quaternion test; + AngleQuaternion( ang, test ); + float d = QuaternionDotProduct( q, test ); + Assert( fabs(d) > 0.99 && fabs(d) < 1.01 ); +#endif + + MatrixGetColumn( matrix, 3, pos ); +} + +void MatrixAngles( const matrix3x4_t& matrix, float *angles ) +{ +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "MatrixAngles", "Mathlib" ); +#endif + Assert( s_bMathlibInitialized ); + float forward[3]; + float left[3]; + float up[3]; + + // + // Extract the basis vectors from the matrix. Since we only need the Z + // component of the up vector, we don't get X and Y. + // + forward[0] = matrix[0][0]; + forward[1] = matrix[1][0]; + forward[2] = matrix[2][0]; + left[0] = matrix[0][1]; + left[1] = matrix[1][1]; + left[2] = matrix[2][1]; + up[2] = matrix[2][2]; + + float xyDist = sqrtf( forward[0] * forward[0] + forward[1] * forward[1] ); + + // enough here to get angles? + if ( xyDist > 0.001f ) + { + // (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis + angles[1] = RAD2DEG( atan2f( forward[1], forward[0] ) ); + + // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) ); + angles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) ); + + // (roll) z = ATAN( left.z, up.z ); + angles[2] = RAD2DEG( atan2f( left[2], up[2] ) ); + } + else // forward is mostly Z, gimbal lock- + { + // (yaw) y = ATAN( -left.x, left.y ); -- forward is mostly z, so use right for yaw + angles[1] = RAD2DEG( atan2f( -left[0], left[1] ) ); + + // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) ); + angles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) ); + + // Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll) + angles[2] = 0; + } +} + + +// transform in1 by the matrix in2 +void VectorTransform (const float *in1, const matrix3x4_t& in2, float *out) +{ + Assert( s_bMathlibInitialized ); + Assert( in1 != out ); + out[0] = DotProduct(in1, in2[0]) + in2[0][3]; + out[1] = DotProduct(in1, in2[1]) + in2[1][3]; + out[2] = DotProduct(in1, in2[2]) + in2[2][3]; +} + + +// assuming the matrix is orthonormal, transform in1 by the transpose (also the inverse in this case) of in2. +void VectorITransform (const float *in1, const matrix3x4_t& in2, float *out) +{ + Assert( s_bMathlibInitialized ); + float in1t[3]; + + in1t[0] = in1[0] - in2[0][3]; + in1t[1] = in1[1] - in2[1][3]; + in1t[2] = in1[2] - in2[2][3]; + + out[0] = in1t[0] * in2[0][0] + in1t[1] * in2[1][0] + in1t[2] * in2[2][0]; + out[1] = in1t[0] * in2[0][1] + in1t[1] * in2[1][1] + in1t[2] * in2[2][1]; + out[2] = in1t[0] * in2[0][2] + in1t[1] * in2[1][2] + in1t[2] * in2[2][2]; +} + + +// assume in2 is a rotation and rotate the input vector +void VectorRotate( const float *in1, const matrix3x4_t& in2, float *out ) +{ + Assert( s_bMathlibInitialized ); + Assert( in1 != out ); + out[0] = DotProduct( in1, in2[0] ); + out[1] = DotProduct( in1, in2[1] ); + out[2] = DotProduct( in1, in2[2] ); +} + +// assume in2 is a rotation and rotate the input vector +void VectorRotate( const Vector &in1, const QAngle &in2, Vector &out ) +{ + matrix3x4_t matRotate; + AngleMatrix( in2, matRotate ); + VectorRotate( in1, matRotate, out ); +} + +// assume in2 is a rotation and rotate the input vector +void VectorRotate( const Vector &in1, const Quaternion &in2, Vector &out ) +{ + matrix3x4_t matRotate; + QuaternionMatrix( in2, matRotate ); + VectorRotate( in1, matRotate, out ); +} + + +// rotate by the inverse of the matrix +void VectorIRotate( const float *in1, const matrix3x4_t& in2, float *out ) +{ + Assert( s_bMathlibInitialized ); + Assert( in1 != out ); + out[0] = in1[0]*in2[0][0] + in1[1]*in2[1][0] + in1[2]*in2[2][0]; + out[1] = in1[0]*in2[0][1] + in1[1]*in2[1][1] + in1[2]*in2[2][1]; + out[2] = in1[0]*in2[0][2] + in1[1]*in2[1][2] + in1[2]*in2[2][2]; +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS +// transform a set of angles in the output space of parentMatrix to the input space +QAngle TransformAnglesToLocalSpace( const QAngle &angles, const matrix3x4_t &parentMatrix ) +{ + matrix3x4_t angToWorld, worldToParent, localMatrix; + MatrixInvert( parentMatrix, worldToParent ); + AngleMatrix( angles, angToWorld ); + ConcatTransforms( worldToParent, angToWorld, localMatrix ); + + QAngle out; + MatrixAngles( localMatrix, out ); + return out; +} + +// transform a set of angles in the input space of parentMatrix to the output space +QAngle TransformAnglesToWorldSpace( const QAngle &angles, const matrix3x4_t &parentMatrix ) +{ + matrix3x4_t angToParent, angToWorld; + AngleMatrix( angles, angToParent ); + ConcatTransforms( parentMatrix, angToParent, angToWorld ); + QAngle out; + MatrixAngles( angToWorld, out ); + return out; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + +void MatrixInitialize( matrix3x4_t &mat, const Vector &vecOrigin, const Vector &vecXAxis, const Vector &vecYAxis, const Vector &vecZAxis ) +{ + MatrixSetColumn( vecXAxis, 0, mat ); + MatrixSetColumn( vecYAxis, 1, mat ); + MatrixSetColumn( vecZAxis, 2, mat ); + MatrixSetColumn( vecOrigin, 3, mat ); +} + +void MatrixCopy( const matrix3x4_t& in, matrix3x4_t& out ) +{ + Assert( s_bMathlibInitialized ); + memcpy( out.Base(), in.Base(), sizeof( float ) * 3 * 4 ); +} + +//----------------------------------------------------------------------------- +// Matrix equality test +//----------------------------------------------------------------------------- +bool MatricesAreEqual( const matrix3x4_t &src1, const matrix3x4_t &src2, float flTolerance ) +{ + for ( int i = 0; i < 3; ++i ) + { + for ( int j = 0; j < 4; ++j ) + { + if ( fabs( src1[i][j] - src2[i][j] ) > flTolerance ) + return false; + } + } + return true; +} + +// NOTE: This is just the transpose not a general inverse +void MatrixInvert( const matrix3x4_t& in, matrix3x4_t& out ) +{ + Assert( s_bMathlibInitialized ); + if ( &in == &out ) + { + V_swap(out[0][1],out[1][0]); + V_swap(out[0][2],out[2][0]); + V_swap(out[1][2],out[2][1]); + } + else + { + // transpose the matrix + out[0][0] = in[0][0]; + out[0][1] = in[1][0]; + out[0][2] = in[2][0]; + + out[1][0] = in[0][1]; + out[1][1] = in[1][1]; + out[1][2] = in[2][1]; + + out[2][0] = in[0][2]; + out[2][1] = in[1][2]; + out[2][2] = in[2][2]; + } + + // now fix up the translation to be in the other space + float tmp[3]; + tmp[0] = in[0][3]; + tmp[1] = in[1][3]; + tmp[2] = in[2][3]; + + out[0][3] = -DotProduct( tmp, out[0] ); + out[1][3] = -DotProduct( tmp, out[1] ); + out[2][3] = -DotProduct( tmp, out[2] ); +} + +void MatrixGetColumn( const matrix3x4_t& in, int column, Vector &out ) +{ + out.x = in[0][column]; + out.y = in[1][column]; + out.z = in[2][column]; +} + +void MatrixSetColumn( const Vector &in, int column, matrix3x4_t& out ) +{ + out[0][column] = in.x; + out[1][column] = in.y; + out[2][column] = in.z; +} + +void MatrixScaleBy ( const float flScale, matrix3x4_t &out ) +{ + out[0][0] *= flScale; + out[1][0] *= flScale; + out[2][0] *= flScale; + out[0][1] *= flScale; + out[1][1] *= flScale; + out[2][1] *= flScale; + out[0][2] *= flScale; + out[1][2] *= flScale; + out[2][2] *= flScale; +} + +void MatrixScaleByZero ( matrix3x4_t &out ) +{ + out[0][0] = 0.0f; + out[1][0] = 0.0f; + out[2][0] = 0.0f; + out[0][1] = 0.0f; + out[1][1] = 0.0f; + out[2][1] = 0.0f; + out[0][2] = 0.0f; + out[1][2] = 0.0f; + out[2][2] = 0.0f; +} + + + +int VectorCompare (const float *v1, const float *v2) +{ + Assert( s_bMathlibInitialized ); + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +void CrossProduct (const float* v1, const float* v2, float* cross) +{ + Assert( s_bMathlibInitialized ); + Assert( v1 != cross ); + Assert( v2 != cross ); + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +int Q_log2(int val) +{ + int answer=0; + while (val>>=1) + answer++; + return answer; +} + +// Matrix is right-handed x=forward, y=left, z=up. We a left-handed convention for vectors in the game code (forward, right, up) +void MatrixVectors( const matrix3x4_t &matrix, Vector* pForward, Vector *pRight, Vector *pUp ) +{ + MatrixGetColumn( matrix, 0, *pForward ); + MatrixGetColumn( matrix, 1, *pRight ); + MatrixGetColumn( matrix, 2, *pUp ); + *pRight *= -1.0f; +} + + +void VectorVectors( const Vector &forward, Vector &right, Vector &up ) +{ + Assert( s_bMathlibInitialized ); + Vector tmp; + + if (forward[0] == 0 && forward[1] == 0) + { + // pitch 90 degrees up/down from identity + right[0] = 0; + right[1] = -1; + right[2] = 0; + up[0] = -forward[2]; + up[1] = 0; + up[2] = 0; + } + else + { + tmp[0] = 0; tmp[1] = 0; tmp[2] = 1.0; + CrossProduct( forward, tmp, right ); + VectorNormalize( right ); + CrossProduct( right, forward, up ); + VectorNormalize( up ); + } +} + +void VectorMatrix( const Vector &forward, matrix3x4_t& matrix) +{ + Assert( s_bMathlibInitialized ); + Vector right, up; + VectorVectors(forward, right, up); + + MatrixSetColumn( forward, 0, matrix ); + MatrixSetColumn( -right, 1, matrix ); + MatrixSetColumn( up, 2, matrix ); +} + + +void VectorAngles( const float *forward, float *angles ) +{ + Assert( s_bMathlibInitialized ); + float tmp, yaw, pitch; + + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 270; + else + pitch = 90; + } + else + { + yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); + pitch = (atan2(-forward[2], tmp) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} + + +/* +================ +R_ConcatRotations +================ +*/ +void ConcatRotations (const float in1[3][3], const float in2[3][3], float out[3][3]) +{ + Assert( s_bMathlibInitialized ); + Assert( in1 != out ); + Assert( in2 != out ); + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + +void ConcatTransforms_Aligned( const matrix3x4_t &m0, const matrix3x4_t &m1, matrix3x4_t &out ) +{ + Assert( (((size_t)&m0) % 16) == 0 ); + Assert( (((size_t)&m1) % 16) == 0 ); + Assert( (((size_t)&out) % 16) == 0 ); + + fltx4 lastMask = *(fltx4 *)(&g_SIMD_ComponentMask[3]); + fltx4 rowA0 = LoadAlignedSIMD( m0.m_flMatVal[0] ); + fltx4 rowA1 = LoadAlignedSIMD( m0.m_flMatVal[1] ); + fltx4 rowA2 = LoadAlignedSIMD( m0.m_flMatVal[2] ); + + fltx4 rowB0 = LoadAlignedSIMD( m1.m_flMatVal[0] ); + fltx4 rowB1 = LoadAlignedSIMD( m1.m_flMatVal[1] ); + fltx4 rowB2 = LoadAlignedSIMD( m1.m_flMatVal[2] ); + + // now we have the rows of m0 and the columns of m1 + // first output row + fltx4 A0 = SplatXSIMD(rowA0); + fltx4 A1 = SplatYSIMD(rowA0); + fltx4 A2 = SplatZSIMD(rowA0); + fltx4 mul00 = MulSIMD( A0, rowB0 ); + fltx4 mul01 = MulSIMD( A1, rowB1 ); + fltx4 mul02 = MulSIMD( A2, rowB2 ); + fltx4 out0 = AddSIMD( mul00, AddSIMD(mul01,mul02) ); + + // second output row + A0 = SplatXSIMD(rowA1); + A1 = SplatYSIMD(rowA1); + A2 = SplatZSIMD(rowA1); + fltx4 mul10 = MulSIMD( A0, rowB0 ); + fltx4 mul11 = MulSIMD( A1, rowB1 ); + fltx4 mul12 = MulSIMD( A2, rowB2 ); + fltx4 out1 = AddSIMD( mul10, AddSIMD(mul11,mul12) ); + + // third output row + A0 = SplatXSIMD(rowA2); + A1 = SplatYSIMD(rowA2); + A2 = SplatZSIMD(rowA2); + fltx4 mul20 = MulSIMD( A0, rowB0 ); + fltx4 mul21 = MulSIMD( A1, rowB1 ); + fltx4 mul22 = MulSIMD( A2, rowB2 ); + fltx4 out2 = AddSIMD( mul20, AddSIMD(mul21,mul22) ); + + // add in translation vector + A0 = AndSIMD(rowA0,lastMask); + A1 = AndSIMD(rowA1,lastMask); + A2 = AndSIMD(rowA2,lastMask); + out0 = AddSIMD(out0, A0); + out1 = AddSIMD(out1, A1); + out2 = AddSIMD(out2, A2); + + StoreAlignedSIMD( out.m_flMatVal[0], out0 ); + StoreAlignedSIMD( out.m_flMatVal[1], out1 ); + StoreAlignedSIMD( out.m_flMatVal[2], out2 ); +} + +/* +================ +R_ConcatTransforms +================ +*/ + +void ConcatTransforms (const matrix3x4_t& in1, const matrix3x4_t& in2, matrix3x4_t& out) +{ +#if 0 + // test for ones that'll be 2x faster + if ( (((size_t)&in1) % 16) == 0 && (((size_t)&in2) % 16) == 0 && (((size_t)&out) % 16) == 0 ) + { + ConcatTransforms_Aligned( in1, in2, out ); + return; + } +#endif + + fltx4 lastMask = *(fltx4 *)(&g_SIMD_ComponentMask[3]); + fltx4 rowA0 = LoadUnalignedSIMD( in1.m_flMatVal[0] ); + fltx4 rowA1 = LoadUnalignedSIMD( in1.m_flMatVal[1] ); + fltx4 rowA2 = LoadUnalignedSIMD( in1.m_flMatVal[2] ); + + fltx4 rowB0 = LoadUnalignedSIMD( in2.m_flMatVal[0] ); + fltx4 rowB1 = LoadUnalignedSIMD( in2.m_flMatVal[1] ); + fltx4 rowB2 = LoadUnalignedSIMD( in2.m_flMatVal[2] ); + + // now we have the rows of m0 and the columns of m1 + // first output row + fltx4 A0 = SplatXSIMD(rowA0); + fltx4 A1 = SplatYSIMD(rowA0); + fltx4 A2 = SplatZSIMD(rowA0); + fltx4 mul00 = MulSIMD( A0, rowB0 ); + fltx4 mul01 = MulSIMD( A1, rowB1 ); + fltx4 mul02 = MulSIMD( A2, rowB2 ); + fltx4 out0 = AddSIMD( mul00, AddSIMD(mul01,mul02) ); + + // second output row + A0 = SplatXSIMD(rowA1); + A1 = SplatYSIMD(rowA1); + A2 = SplatZSIMD(rowA1); + fltx4 mul10 = MulSIMD( A0, rowB0 ); + fltx4 mul11 = MulSIMD( A1, rowB1 ); + fltx4 mul12 = MulSIMD( A2, rowB2 ); + fltx4 out1 = AddSIMD( mul10, AddSIMD(mul11,mul12) ); + + // third output row + A0 = SplatXSIMD(rowA2); + A1 = SplatYSIMD(rowA2); + A2 = SplatZSIMD(rowA2); + fltx4 mul20 = MulSIMD( A0, rowB0 ); + fltx4 mul21 = MulSIMD( A1, rowB1 ); + fltx4 mul22 = MulSIMD( A2, rowB2 ); + fltx4 out2 = AddSIMD( mul20, AddSIMD(mul21,mul22) ); + + // add in translation vector + A0 = AndSIMD(rowA0,lastMask); + A1 = AndSIMD(rowA1,lastMask); + A2 = AndSIMD(rowA2,lastMask); + out0 = AddSIMD(out0, A0); + out1 = AddSIMD(out1, A1); + out2 = AddSIMD(out2, A2); + + // write to output + StoreUnalignedSIMD( out.m_flMatVal[0], out0 ); + StoreUnalignedSIMD( out.m_flMatVal[1], out1 ); + StoreUnalignedSIMD( out.m_flMatVal[2], out2 ); +} + + +/* +=================== +FloorDivMod + +Returns mathematically correct (floor-based) quotient and remainder for +numer and denom, both of which should contain no fractional part. The +quotient must fit in 32 bits. +==================== +*/ + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem) +{ + Assert( s_bMathlibInitialized ); + int q, r; + double x; + +#ifdef PARANOID + if (denom <= 0.0) + Sys_Error ("FloorDivMod: bad denominator %d\n", denom); + +// if ((floor(numer) != numer) || (floor(denom) != denom)) +// Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n", +// numer, denom); +#endif + + if (numer >= 0.0) + { + + x = floor(numer / denom); + q = (int)x; + r = Floor2Int(numer - (x * denom)); + } + else + { + // + // perform operations with positive values, and fix mod to make floor-based + // + x = floor(-numer / denom); + q = -(int)x; + r = Floor2Int(-numer - (x * denom)); + if (r != 0) + { + q--; + r = (int)denom - r; + } + } + + *quotient = q; + *rem = r; +} + + +/* +=================== +GreatestCommonDivisor +==================== +*/ +int GreatestCommonDivisor (int i1, int i2) +{ + Assert( s_bMathlibInitialized ); + if (i1 > i2) + { + if (i2 == 0) + return (i1); + return GreatestCommonDivisor (i2, i1 % i2); + } + else + { + if (i1 == 0) + return (i2); + return GreatestCommonDivisor (i1, i2 % i1); + } +} + + +bool IsDenormal( const float &val ) +{ + const int x = *reinterpret_cast (&val); // needs 32-bit int + const int abs_mantissa = x & 0x007FFFFF; + const int biased_exponent = x & 0x7F800000; + + return ( biased_exponent == 0 && abs_mantissa != 0 ); +} + +int SignbitsForPlane (cplane_t *out) +{ + Assert( s_bMathlibInitialized ); + int bits, j; + + // for fast box on planeside test + + bits = 0; + for (j=0 ; j<3 ; j++) + { + if (out->normal[j] < 0) + bits |= 1<type < 3) + { + if (p->dist <= emins[p->type]) + return 1; + if (p->dist >= emaxs[p->type]) + return 2; + return 3; + } + + // general case + switch (p->signbits) + { + case 0: + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 1: + dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 2: + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 3: + dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 4: + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 5: + dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 6: + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + case 7: + dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + default: + dist1 = dist2 = 0; // shut up compiler + Assert( 0 ); + break; + } + + sides = 0; + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + + Assert( sides != 0 ); + + return sides; +} + +//----------------------------------------------------------------------------- +// Euler QAngle -> Basis Vectors +//----------------------------------------------------------------------------- + +void AngleVectors (const QAngle &angles, Vector *forward) +{ + Assert( s_bMathlibInitialized ); + Assert( forward ); + + float sp, sy, cp, cy; + + SinCos( DEG2RAD( angles[YAW] ), &sy, &cy ); + SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp ); + + forward->x = cp*cy; + forward->y = cp*sy; + forward->z = -sp; +} + +//----------------------------------------------------------------------------- +// Euler QAngle -> Basis Vectors. Each vector is optional +//----------------------------------------------------------------------------- +void AngleVectors( const QAngle &angles, Vector *forward, Vector *right, Vector *up ) +{ + Assert( s_bMathlibInitialized ); + + float sr, sp, sy, cr, cp, cy; + +#ifdef _X360 + fltx4 radians, scale, sine, cosine; + radians = LoadUnaligned3SIMD( angles.Base() ); + scale = ReplicateX4( M_PI_F / 180.f ); + radians = MulSIMD( radians, scale ); + SinCos3SIMD( sine, cosine, radians ); + sp = SubFloat( sine, 0 ); sy = SubFloat( sine, 1 ); sr = SubFloat( sine, 2 ); + cp = SubFloat( cosine, 0 ); cy = SubFloat( cosine, 1 ); cr = SubFloat( cosine, 2 ); +#else + SinCos( DEG2RAD( angles[YAW] ), &sy, &cy ); + SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp ); + SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr ); +#endif + + if (forward) + { + forward->x = cp*cy; + forward->y = cp*sy; + forward->z = -sp; + } + + if (right) + { + right->x = (-1*sr*sp*cy+-1*cr*-sy); + right->y = (-1*sr*sp*sy+-1*cr*cy); + right->z = -1*sr*cp; + } + + if (up) + { + up->x = (cr*sp*cy+-sr*-sy); + up->y = (cr*sp*sy+-sr*cy); + up->z = cr*cp; + } +} + +//----------------------------------------------------------------------------- +// Euler QAngle -> Basis Vectors transposed +//----------------------------------------------------------------------------- + +void AngleVectorsTranspose (const QAngle &angles, Vector *forward, Vector *right, Vector *up) +{ + Assert( s_bMathlibInitialized ); + float sr, sp, sy, cr, cp, cy; + + SinCos( DEG2RAD( angles[YAW] ), &sy, &cy ); + SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp ); + SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr ); + + if (forward) + { + forward->x = cp*cy; + forward->y = (sr*sp*cy+cr*-sy); + forward->z = (cr*sp*cy+-sr*-sy); + } + + if (right) + { + right->x = cp*sy; + right->y = (sr*sp*sy+cr*cy); + right->z = (cr*sp*sy+-sr*cy); + } + + if (up) + { + up->x = -sp; + up->y = sr*cp; + up->z = cr*cp; + } +} + +//----------------------------------------------------------------------------- +// Forward direction vector -> Euler angles +//----------------------------------------------------------------------------- + +void VectorAngles( const Vector& forward, QAngle &angles ) +{ + Assert( s_bMathlibInitialized ); + float tmp, yaw, pitch; + + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 270; + else + pitch = 90; + } + else + { + yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = FastSqrt (forward[0]*forward[0] + forward[1]*forward[1]); + pitch = (atan2(-forward[2], tmp) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} + +//----------------------------------------------------------------------------- +// Forward direction vector with a reference up vector -> Euler angles +//----------------------------------------------------------------------------- + +void VectorAngles( const Vector &forward, const Vector &pseudoup, QAngle &angles ) +{ + Assert( s_bMathlibInitialized ); + + Vector left; + + CrossProduct( pseudoup, forward, left ); + VectorNormalizeFast( left ); + + float xyDist = sqrtf( forward[0] * forward[0] + forward[1] * forward[1] ); + + // enough here to get angles? + if ( xyDist > 0.001f ) + { + // (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis + angles[1] = RAD2DEG( atan2f( forward[1], forward[0] ) ); + + // The engine does pitch inverted from this, but we always end up negating it in the DLL + // UNDONE: Fix the engine to make it consistent + // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) ); + angles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) ); + + float up_z = (left[1] * forward[0]) - (left[0] * forward[1]); + + // (roll) z = ATAN( left.z, up.z ); + angles[2] = RAD2DEG( atan2f( left[2], up_z ) ); + } + else // forward is mostly Z, gimbal lock- + { + // (yaw) y = ATAN( -left.x, left.y ); -- forward is mostly z, so use right for yaw + angles[1] = RAD2DEG( atan2f( -left[0], left[1] ) ); //This was originally copied from the "void MatrixAngles( const matrix3x4_t& matrix, float *angles )" code, and it's 180 degrees off, negated the values and it all works now (Dave Kircher) + + // The engine does pitch inverted from this, but we always end up negating it in the DLL + // UNDONE: Fix the engine to make it consistent + // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) ); + angles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) ); + + // Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll) + angles[2] = 0; + } +} + +void SetIdentityMatrix( matrix3x4_t& matrix ) +{ + memset( matrix.Base(), 0, sizeof(float)*3*4 ); + matrix[0][0] = 1.0; + matrix[1][1] = 1.0; + matrix[2][2] = 1.0; +} + + +//----------------------------------------------------------------------------- +// Builds a scale matrix +//----------------------------------------------------------------------------- +void SetScaleMatrix( float x, float y, float z, matrix3x4_t &dst ) +{ + dst[0][0] = x; dst[0][1] = 0.0f; dst[0][2] = 0.0f; dst[0][3] = 0.0f; + dst[1][0] = 0.0f; dst[1][1] = y; dst[1][2] = 0.0f; dst[1][3] = 0.0f; + dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = z; dst[2][3] = 0.0f; +} + + +//----------------------------------------------------------------------------- +// Purpose: Builds the matrix for a counterclockwise rotation about an arbitrary axis. +// +// | ax2 + (1 - ax2)cosQ axay(1 - cosQ) - azsinQ azax(1 - cosQ) + aysinQ | +// Ra(Q) = | axay(1 - cosQ) + azsinQ ay2 + (1 - ay2)cosQ ayaz(1 - cosQ) - axsinQ | +// | azax(1 - cosQ) - aysinQ ayaz(1 - cosQ) + axsinQ az2 + (1 - az2)cosQ | +// +// Input : mat - +// vAxisOrRot - +// angle - +//----------------------------------------------------------------------------- +void MatrixBuildRotationAboutAxis( const Vector &vAxisOfRot, float angleDegrees, matrix3x4_t &dst ) +{ + float radians; + float axisXSquared; + float axisYSquared; + float axisZSquared; + float fSin; + float fCos; + + radians = angleDegrees * ( M_PI / 180.0 ); + fSin = sin( radians ); + fCos = cos( radians ); + + axisXSquared = vAxisOfRot[0] * vAxisOfRot[0]; + axisYSquared = vAxisOfRot[1] * vAxisOfRot[1]; + axisZSquared = vAxisOfRot[2] * vAxisOfRot[2]; + + // Column 0: + dst[0][0] = axisXSquared + (1 - axisXSquared) * fCos; + dst[1][0] = vAxisOfRot[0] * vAxisOfRot[1] * (1 - fCos) + vAxisOfRot[2] * fSin; + dst[2][0] = vAxisOfRot[2] * vAxisOfRot[0] * (1 - fCos) - vAxisOfRot[1] * fSin; + + // Column 1: + dst[0][1] = vAxisOfRot[0] * vAxisOfRot[1] * (1 - fCos) - vAxisOfRot[2] * fSin; + dst[1][1] = axisYSquared + (1 - axisYSquared) * fCos; + dst[2][1] = vAxisOfRot[1] * vAxisOfRot[2] * (1 - fCos) + vAxisOfRot[0] * fSin; + + // Column 2: + dst[0][2] = vAxisOfRot[2] * vAxisOfRot[0] * (1 - fCos) + vAxisOfRot[1] * fSin; + dst[1][2] = vAxisOfRot[1] * vAxisOfRot[2] * (1 - fCos) - vAxisOfRot[0] * fSin; + dst[2][2] = axisZSquared + (1 - axisZSquared) * fCos; + + // Column 3: + dst[0][3] = 0; + dst[1][3] = 0; + dst[2][3] = 0; +} + + +//----------------------------------------------------------------------------- +// Computes the transpose +//----------------------------------------------------------------------------- +void MatrixTranspose( matrix3x4_t& mat ) +{ + vec_t tmp; + tmp = mat[0][1]; mat[0][1] = mat[1][0]; mat[1][0] = tmp; + tmp = mat[0][2]; mat[0][2] = mat[2][0]; mat[2][0] = tmp; + tmp = mat[1][2]; mat[1][2] = mat[2][1]; mat[2][1] = tmp; +} + +void MatrixTranspose( const matrix3x4_t& src, matrix3x4_t& dst ) +{ + dst[0][0] = src[0][0]; dst[0][1] = src[1][0]; dst[0][2] = src[2][0]; dst[0][3] = 0.0f; + dst[1][0] = src[0][1]; dst[1][1] = src[1][1]; dst[1][2] = src[2][1]; dst[1][3] = 0.0f; + dst[2][0] = src[0][2]; dst[2][1] = src[1][2]; dst[2][2] = src[2][2]; dst[2][3] = 0.0f; +} + + +//----------------------------------------------------------------------------- +// Purpose: converts engine euler angles into a matrix +// Input : vec3_t angles - PITCH, YAW, ROLL +// Output : *matrix - left-handed column matrix +// the basis vectors for the rotations will be in the columns as follows: +// matrix[][0] is forward +// matrix[][1] is left +// matrix[][2] is up +//----------------------------------------------------------------------------- +void AngleMatrix( RadianEuler const &angles, const Vector &position, matrix3x4_t& matrix ) +{ + AngleMatrix( angles, matrix ); + MatrixSetColumn( position, 3, matrix ); +} + +void AngleMatrix( const RadianEuler& angles, matrix3x4_t& matrix ) +{ + QAngle quakeEuler( RAD2DEG( angles.y ), RAD2DEG( angles.z ), RAD2DEG( angles.x ) ); + + AngleMatrix( quakeEuler, matrix ); +} + + +void AngleMatrix( const QAngle &angles, const Vector &position, matrix3x4_t& matrix ) +{ + AngleMatrix( angles, matrix ); + MatrixSetColumn( position, 3, matrix ); +} + +void AngleMatrix( const QAngle &angles, matrix3x4_t& matrix ) +{ +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "AngleMatrix", "Mathlib" ); +#endif + Assert( s_bMathlibInitialized ); + + float sr, sp, sy, cr, cp, cy; + +#ifdef _X360 + fltx4 radians, scale, sine, cosine; + radians = LoadUnaligned3SIMD( angles.Base() ); + scale = ReplicateX4( M_PI_F / 180.f ); + radians = MulSIMD( radians, scale ); + SinCos3SIMD( sine, cosine, radians ); + + sp = SubFloat( sine, 0 ); sy = SubFloat( sine, 1 ); sr = SubFloat( sine, 2 ); + cp = SubFloat( cosine, 0 ); cy = SubFloat( cosine, 1 ); cr = SubFloat( cosine, 2 ); +#else + SinCos( DEG2RAD( angles[YAW] ), &sy, &cy ); + SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp ); + SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr ); +#endif + + // matrix = (YAW * PITCH) * ROLL + matrix[0][0] = cp*cy; + matrix[1][0] = cp*sy; + matrix[2][0] = -sp; + + float crcy = cr*cy; + float crsy = cr*sy; + float srcy = sr*cy; + float srsy = sr*sy; + matrix[0][1] = sp*srcy-crsy; + matrix[1][1] = sp*srsy+crcy; + matrix[2][1] = sr*cp; + + matrix[0][2] = (sp*crcy+srsy); + matrix[1][2] = (sp*crsy-srcy); + matrix[2][2] = cr*cp; + + matrix[0][3] = 0.0f; + matrix[1][3] = 0.0f; + matrix[2][3] = 0.0f; +} + +void AngleIMatrix( const RadianEuler& angles, matrix3x4_t& matrix ) +{ + QAngle quakeEuler( RAD2DEG( angles.y ), RAD2DEG( angles.z ), RAD2DEG( angles.x ) ); + + AngleIMatrix( quakeEuler, matrix ); +} + +void AngleIMatrix (const QAngle& angles, matrix3x4_t& matrix ) +{ + Assert( s_bMathlibInitialized ); + float sr, sp, sy, cr, cp, cy; + + SinCos( DEG2RAD( angles[YAW] ), &sy, &cy ); + SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp ); + SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr ); + + // matrix = (YAW * PITCH) * ROLL + matrix[0][0] = cp*cy; + matrix[0][1] = cp*sy; + matrix[0][2] = -sp; + matrix[1][0] = sr*sp*cy+cr*-sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[1][2] = sr*cp; + matrix[2][0] = (cr*sp*cy+-sr*-sy); + matrix[2][1] = (cr*sp*sy+-sr*cy); + matrix[2][2] = cr*cp; + matrix[0][3] = 0.f; + matrix[1][3] = 0.f; + matrix[2][3] = 0.f; +} + +void AngleIMatrix (const QAngle &angles, const Vector &position, matrix3x4_t &mat ) +{ + AngleIMatrix( angles, mat ); + + Vector vecTranslation; + VectorRotate( position, mat, vecTranslation ); + vecTranslation *= -1.0f; + MatrixSetColumn( vecTranslation, 3, mat ); +} + + +//----------------------------------------------------------------------------- +// Bounding box construction methods +//----------------------------------------------------------------------------- + +void ClearBounds (Vector& mins, Vector& maxs) +{ + Assert( s_bMathlibInitialized ); + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (const Vector& v, Vector& mins, Vector& maxs) +{ + Assert( s_bMathlibInitialized ); + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} + +// solve a x^2 + b x + c = 0 +bool SolveQuadratic( float a, float b, float c, float &root1, float &root2 ) +{ + Assert( s_bMathlibInitialized ); + if (a == 0) + { + if (b != 0) + { + // no x^2 component, it's a linear system + root1 = root2 = -c / b; + return true; + } + if (c == 0) + { + // all zero's + root1 = root2 = 0; + return true; + } + return false; + } + + float tmp = b * b - 4.0f * a * c; + + if (tmp < 0) + { + // imaginary number, bah, no solution. + return false; + } + + tmp = sqrt( tmp ); + root1 = (-b + tmp) / (2.0f * a); + root2 = (-b - tmp) / (2.0f * a); + return true; +} + +// solves for "a, b, c" where "a x^2 + b x + c = y", return true if solution exists +bool SolveInverseQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c ) +{ + float det = (x1 - x2)*(x1 - x3)*(x2 - x3); + + // FIXME: check with some sort of epsilon + if (det == 0.0) + return false; + + a = (x3*(-y1 + y2) + x2*(y1 - y3) + x1*(-y2 + y3)) / det; + + b = (x3*x3*(y1 - y2) + x1*x1*(y2 - y3) + x2*x2*(-y1 + y3)) / det; + + c = (x1*x3*(-x1 + x3)*y2 + x2*x2*(x3*y1 - x1*y3) + x2*(-(x3*x3*y1) + x1*x1*y3)) / det; + + return true; +} + +bool SolveInverseQuadraticMonotonic( float x1, float y1, float x2, float y2, float x3, float y3, + float &a, float &b, float &c ) +{ + // use SolveInverseQuadratic, but if the sigm of the derivative at the start point is the wrong + // sign, displace the mid point + + // first, sort parameters + if (x1>x2) + { + V_swap(x1,x2); + V_swap(y1,y2); + } + if (x2>x3) + { + V_swap(x2,x3); + V_swap(y2,y3); + } + if (x1>x2) + { + V_swap(x1,x2); + V_swap(y1,y2); + } + // this code is not fast. what it does is when the curve would be non-monotonic, slowly shifts + // the center point closer to the linear line between the endpoints. Should anyone need htis + // function to be actually fast, it would be fairly easy to change it to be so. + for(float blend_to_linear_factor=0.0;blend_to_linear_factor<=1.0;blend_to_linear_factor+=0.05) + { + float tempy2=(1-blend_to_linear_factor)*y2+blend_to_linear_factor*FLerp(y1,y3,x1,x3,x2); + if (!SolveInverseQuadratic(x1,y1,x2,tempy2,x3,y3,a,b,c)) + return false; + float derivative=2.0*a+b; + if ( (y1=0.0) + return true; + } + else + { + if ( (y1>y2) && (y2>y3)) // monotonically decreasing + { + if (derivative<=0.0) + return true; + } + else + return true; + } + } + return true; +} + + +// solves for "a, b, c" where "1/(a x^2 + b x + c ) = y", return true if solution exists +bool SolveInverseReciprocalQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c ) +{ + float det = (x1 - x2)*(x1 - x3)*(x2 - x3)*y1*y2*y3; + + // FIXME: check with some sort of epsilon + if (det == 0.0) + return false; + + a = (x1*y1*(y2 - y3) + x3*(y1 - y2)*y3 + x2*y2*(-y1 + y3)) / det; + + b = (x2*x2*y2*(y1 - y3) + x3*x3*(-y1 + y2)*y3 + x1*x1*y1*(-y2 + y3)) / det; + + c = (x2*(x2 - x3)*x3*y2*y3 + x1*x1*y1*(x2*y2 - x3*y3) + x1*(-(x2*x2*y1*y2) + x3*x3*y1*y3)) / det; + + return true; +} + + +// Rotate a vector around the Z axis (YAW) +void VectorYawRotate( const Vector &in, float flYaw, Vector &out) +{ + Assert( s_bMathlibInitialized ); + if (&in == &out ) + { + Vector tmp; + tmp = in; + VectorYawRotate( tmp, flYaw, out ); + return; + } + + float sy, cy; + + SinCos( DEG2RAD(flYaw), &sy, &cy ); + + out.x = in.x * cy - in.y * sy; + out.y = in.x * sy + in.y * cy; + out.z = in.z; +} + + + +float Bias( float x, float biasAmt ) +{ + // WARNING: not thread safe + static float lastAmt = -1; + static float lastExponent = 0; + if( lastAmt != biasAmt ) + { + lastExponent = log( biasAmt ) * -1.4427f; // (-1.4427 = 1 / log(0.5)) + } + float fRet = pow( x, lastExponent ); + Assert ( !IS_NAN( fRet ) ); + return fRet; +} + + +float Gain( float x, float biasAmt ) +{ + // WARNING: not thread safe + if( x < 0.5 ) + return 0.5f * Bias( 2*x, 1-biasAmt ); + else + return 1 - 0.5f * Bias( 2 - 2*x, 1-biasAmt ); +} + + +float SmoothCurve( float x ) +{ + // Actual smooth curve. Visualization: + // http://www.wolframalpha.com/input/?i=plot%5B+0.5+*+%281+-+cos%5B2+*+pi+*+x%5D%29+for+x+%3D+%280%2C+1%29+%5D + return 0.5f * (1 - cos( 2.0f * M_PI * x ) ); +} + + +inline float MovePeak( float x, float flPeakPos ) +{ + // Todo: make this higher-order? + if( x < flPeakPos ) + return x * 0.5f / flPeakPos; + else + return 0.5 + 0.5 * (x - flPeakPos) / (1 - flPeakPos); +} + + +float SmoothCurve_Tweak( float x, float flPeakPos, float flPeakSharpness ) +{ + float flMovedPeak = MovePeak( x, flPeakPos ); + float flSharpened = Gain( flMovedPeak, flPeakSharpness ); + return SmoothCurve( flSharpened ); +} + +//----------------------------------------------------------------------------- +// make sure quaternions are within 180 degrees of one another, if not, reverse q +//----------------------------------------------------------------------------- + +void QuaternionAlign( const Quaternion &p, const Quaternion &q, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); + + // FIXME: can this be done with a quat dot product? + + int i; + // decide if one of the quaternions is backwards + float a = 0; + float b = 0; + for (i = 0; i < 4; i++) + { + a += (p[i]-q[i])*(p[i]-q[i]); + b += (p[i]+q[i])*(p[i]+q[i]); + } + if (a > b) + { + for (i = 0; i < 4; i++) + { + qt[i] = -q[i]; + } + } + else if (&qt != &q) + { + for (i = 0; i < 4; i++) + { + qt[i] = q[i]; + } + } +} + + +//----------------------------------------------------------------------------- +// Do a piecewise addition of the quaternion elements. This actually makes little +// mathematical sense, but it's a cheap way to simulate a slerp. +//----------------------------------------------------------------------------- +void QuaternionBlend( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); +#if ALLOW_SIMD_QUATERNION_MATH + fltx4 psimd, qsimd, qtsimd; + psimd = LoadUnalignedSIMD( p.Base() ); + qsimd = LoadUnalignedSIMD( q.Base() ); + qtsimd = QuaternionBlendSIMD( psimd, qsimd, t ); + StoreUnalignedSIMD( qt.Base(), qtsimd ); +#else + // decide if one of the quaternions is backwards + Quaternion q2; + QuaternionAlign( p, q, q2 ); + QuaternionBlendNoAlign( p, q2, t, qt ); +#endif +} + + +void QuaternionBlendNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); + float sclp, sclq; + int i; + + // 0.0 returns p, 1.0 return q. + sclp = 1.0f - t; + sclq = t; + for (i = 0; i < 4; i++) { + qt[i] = sclp * p[i] + sclq * q[i]; + } + QuaternionNormalize( qt ); +} + + + +void QuaternionIdentityBlend( const Quaternion &p, float t, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); + float sclp; + + sclp = 1.0f - t; + + qt.x = p.x * sclp; + qt.y = p.y * sclp; + qt.z = p.z * sclp; + if (qt.w < 0.0) + { + qt.w = p.w * sclp - t; + } + else + { + qt.w = p.w * sclp + t; + } + QuaternionNormalize( qt ); +} + +//----------------------------------------------------------------------------- +// Quaternion sphereical linear interpolation +//----------------------------------------------------------------------------- + +void QuaternionSlerp( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ) +{ + Quaternion q2; + // 0.0 returns p, 1.0 return q. + + // decide if one of the quaternions is backwards + QuaternionAlign( p, q, q2 ); + + QuaternionSlerpNoAlign( p, q2, t, qt ); +} + + +void QuaternionSlerpNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); + float omega, cosom, sinom, sclp, sclq; + int i; + + // 0.0 returns p, 1.0 return q. + + cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + + if ((1.0f + cosom) > 0.000001f) { + if ((1.0f - cosom) > 0.000001f) { + omega = acos( cosom ); + sinom = sin( omega ); + sclp = sin( (1.0f - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else { + // TODO: add short circuit for cosom == 1.0f? + sclp = 1.0f - t; + sclq = t; + } + for (i = 0; i < 4; i++) { + qt[i] = sclp * p[i] + sclq * q[i]; + } + } + else { + Assert( &qt != &q ); + + qt[0] = -q[1]; + qt[1] = q[0]; + qt[2] = -q[3]; + qt[3] = q[2]; + sclp = sin( (1.0f - t) * (0.5f * M_PI)); + sclq = sin( t * (0.5f * M_PI)); + for (i = 0; i < 3; i++) { + qt[i] = sclp * p[i] + sclq * qt[i]; + } + } + + Assert( qt.IsValid() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the angular delta between the two normalized quaternions in degrees. +//----------------------------------------------------------------------------- +float QuaternionAngleDiff( const Quaternion &p, const Quaternion &q ) +{ +#if 1 + // this code path is here for 2 reasons: + // 1 - acos maps 1-epsilon to values much larger than epsilon (vs asin, which maps epsilon to itself) + // this means that in floats, anything below ~0.05 degrees truncates to 0 + // 2 - normalized quaternions are frequently slightly non-normalized due to float precision issues, + // and the epsilon off of normalized can be several percents of a degree + Quaternion qInv, diff; + QuaternionConjugate( q, qInv ); + QuaternionMult( p, qInv, diff ); + + // Note if the quaternion is slightly non-normalized the square root below may be more than 1, + // the value is clamped to one otherwise it may result in asin() returning an undefined result. + float sinang = MIN( 1.0f, sqrt( diff.x * diff.x + diff.y * diff.y + diff.z * diff.z ) ); + float angle = RAD2DEG( 2 * asin( sinang ) ); + return angle; +#else + Quaternion q2; + QuaternionAlign( p, q, q2 ); + + Assert( s_bMathlibInitialized ); + float cosom = p.x * q2.x + p.y * q2.y + p.z * q2.z + p.w * q2.w; + + if ( cosom > -1.0f ) + { + if ( cosom < 1.0f ) + { + float omega = 2 * fabs( acos( cosom ) ); + return RAD2DEG( omega ); + } + return 0.0f; + } + + return 180.0f; +#endif +} + +void QuaternionConjugate( const Quaternion &p, Quaternion &q ) +{ + Assert( s_bMathlibInitialized ); + Assert( q.IsValid() ); + + q.x = -p.x; + q.y = -p.y; + q.z = -p.z; + q.w = p.w; +} + +void QuaternionInvert( const Quaternion &p, Quaternion &q ) +{ + Assert( s_bMathlibInitialized ); + Assert( q.IsValid() ); + + QuaternionConjugate( p, q ); + + float magnitudeSqr = QuaternionDotProduct( p, p ); + Assert( magnitudeSqr ); + if ( magnitudeSqr ) + { + float inv = 1.0f / magnitudeSqr; + q.x *= inv; + q.y *= inv; + q.z *= inv; + q.w *= inv; + } +} + +//----------------------------------------------------------------------------- +// Make sure the quaternion is of unit length +//----------------------------------------------------------------------------- +float QuaternionNormalize( Quaternion &q ) +{ + Assert( s_bMathlibInitialized ); + float radius, iradius; + + Assert( q.IsValid() ); + + radius = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]; + + if ( radius ) // > FLT_EPSILON && ((radius < 1.0f - 4*FLT_EPSILON) || (radius > 1.0f + 4*FLT_EPSILON)) + { + radius = sqrt(radius); + iradius = 1.0f/radius; + q[3] *= iradius; + q[2] *= iradius; + q[1] *= iradius; + q[0] *= iradius; + } + return radius; +} + + +void QuaternionScale( const Quaternion &p, float t, Quaternion &q ) +{ + Assert( s_bMathlibInitialized ); + +#if 0 + Quaternion p0; + Quaternion q; + p0.Init( 0.0, 0.0, 0.0, 1.0 ); + + // slerp in "reverse order" so that p doesn't get realigned + QuaternionSlerp( p, p0, 1.0 - fabs( t ), q ); + if (t < 0.0) + { + q.w = -q.w; + } +#else + float r; + + // FIXME: nick, this isn't overly sensitive to accuracy, and it may be faster to + // use the cos part (w) of the quaternion (sin(omega)*N,cos(omega)) to figure the new scale. + float sinom = sqrt( DotProduct( &p.x, &p.x ) ); + sinom = vmin( sinom, 1.f ); + + float sinsom = sin( asin( sinom ) * t ); + + t = sinsom / (sinom + FLT_EPSILON); + VectorScale( &p.x, t, &q.x ); + + // rescale rotation + r = 1.0f - sinsom * sinsom; + + // Assert( r >= 0 ); + if (r < 0.0f) + r = 0.0f; + r = sqrt( r ); + + // keep sign of rotation + if (p.w < 0) + q.w = -r; + else + q.w = r; +#endif + + Assert( q.IsValid() ); + + return; +} + + +void QuaternionAdd( const Quaternion &p, const Quaternion &q, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); + Assert( p.IsValid() ); + Assert( q.IsValid() ); + + // decide if one of the quaternions is backwards + Quaternion q2; + QuaternionAlign( p, q, q2 ); + + // is this right??? + qt[0] = p[0] + q2[0]; + qt[1] = p[1] + q2[1]; + qt[2] = p[2] + q2[2]; + qt[3] = p[3] + q2[3]; + + return; +} + + +float QuaternionDotProduct( const Quaternion &p, const Quaternion &q ) +{ + Assert( s_bMathlibInitialized ); + Assert( p.IsValid() ); + Assert( q.IsValid() ); + + return p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w; +} + + +// qt = p * q +void QuaternionMult( const Quaternion &p, const Quaternion &q, Quaternion &qt ) +{ + Assert( s_bMathlibInitialized ); + Assert( p.IsValid() ); + Assert( q.IsValid() ); + + if (&p == &qt) + { + Quaternion p2 = p; + QuaternionMult( p2, q, qt ); + return; + } + + // decide if one of the quaternions is backwards + Quaternion q2; + QuaternionAlign( p, q, q2 ); + + qt.x = p.x * q2.w + p.y * q2.z - p.z * q2.y + p.w * q2.x; + qt.y = -p.x * q2.z + p.y * q2.w + p.z * q2.x + p.w * q2.y; + qt.z = p.x * q2.y - p.y * q2.x + p.z * q2.w + p.w * q2.z; + qt.w = -p.x * q2.x - p.y * q2.y - p.z * q2.z + p.w * q2.w; +} + + +void QuaternionMatrix( const Quaternion &q, const Vector &pos, matrix3x4_t& matrix ) +{ + if ( !HushAsserts() ) + { + Assert( pos.IsValid() ); + } + + QuaternionMatrix( q, matrix ); + + matrix[0][3] = pos.x; + matrix[1][3] = pos.y; + matrix[2][3] = pos.z; +} + +void QuaternionMatrix( const Quaternion &q, matrix3x4_t& matrix ) +{ + Assert( s_bMathlibInitialized ); + if ( !HushAsserts() ) + { + Assert( q.IsValid() ); + } + +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "QuaternionMatrix", "Mathlib" ); +#endif + +// Original code +// This should produce the same code as below with optimization, but looking at the assmebly, +// it doesn't. There are 7 extra multiplies in the release build of this, go figure. +#if 1 + matrix[0][0] = 1.0 - 2.0 * q.y * q.y - 2.0 * q.z * q.z; + matrix[1][0] = 2.0 * q.x * q.y + 2.0 * q.w * q.z; + matrix[2][0] = 2.0 * q.x * q.z - 2.0 * q.w * q.y; + + matrix[0][1] = 2.0f * q.x * q.y - 2.0f * q.w * q.z; + matrix[1][1] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z; + matrix[2][1] = 2.0f * q.y * q.z + 2.0f * q.w * q.x; + + matrix[0][2] = 2.0f * q.x * q.z + 2.0f * q.w * q.y; + matrix[1][2] = 2.0f * q.y * q.z - 2.0f * q.w * q.x; + matrix[2][2] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y; + + matrix[0][3] = 0.0f; + matrix[1][3] = 0.0f; + matrix[2][3] = 0.0f; +#else + float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + + // precalculate common multiplitcations + x2 = q.x + q.x; + y2 = q.y + q.y; + z2 = q.z + q.z; + xx = q.x * x2; + xy = q.x * y2; + xz = q.x * z2; + yy = q.y * y2; + yz = q.y * z2; + zz = q.z * z2; + wx = q.w * x2; + wy = q.w * y2; + wz = q.w * z2; + + matrix[0][0] = 1.0 - (yy + zz); + matrix[0][1] = xy - wz; + matrix[0][2] = xz + wy; + matrix[0][3] = 0.0f; + + matrix[1][0] = xy + wz; + matrix[1][1] = 1.0 - (xx + zz); + matrix[1][2] = yz - wx; + matrix[1][3] = 0.0f; + + matrix[2][0] = xz - wy; + matrix[2][1] = yz + wx; + matrix[2][2] = 1.0 - (xx + yy); + matrix[2][3] = 0.0f; +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts a quaternion into engine angles +// Input : *quaternion - q3 + q0.i + q1.j + q2.k +// *outAngles - PITCH, YAW, ROLL +//----------------------------------------------------------------------------- +void QuaternionAngles( const Quaternion &q, QAngle &angles ) +{ + Assert( s_bMathlibInitialized ); + Assert( q.IsValid() ); + +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "QuaternionAngles", "Mathlib" ); +#endif + +#if 1 + // FIXME: doing it this way calculates too much data, needs to do an optimized version... + matrix3x4_t matrix; + QuaternionMatrix( q, matrix ); + MatrixAngles( matrix, angles ); +#else + float m11, m12, m13, m23, m33; + + m11 = ( 2.0f * q.w * q.w ) + ( 2.0f * q.x * q.x ) - 1.0f; + m12 = ( 2.0f * q.x * q.y ) + ( 2.0f * q.w * q.z ); + m13 = ( 2.0f * q.x * q.z ) - ( 2.0f * q.w * q.y ); + m23 = ( 2.0f * q.y * q.z ) + ( 2.0f * q.w * q.x ); + m33 = ( 2.0f * q.w * q.w ) + ( 2.0f * q.z * q.z ) - 1.0f; + + // FIXME: this code has a singularity near PITCH +-90 + angles[YAW] = RAD2DEG( atan2(m12, m11) ); + angles[PITCH] = RAD2DEG( asin(-m13) ); + angles[ROLL] = RAD2DEG( atan2(m23, m33) ); +#endif + + Assert( angles.IsValid() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Converts a quaternion to an axis / angle in degrees +// (exponential map) +//----------------------------------------------------------------------------- +void QuaternionAxisAngle( const Quaternion &q, Vector &axis, float &angle ) +{ + angle = RAD2DEG(2 * acos(q.w)); + if ( angle > 180 ) + { + angle -= 360; + } + axis.x = q.x; + axis.y = q.y; + axis.z = q.z; + VectorNormalize( axis ); +} + +//----------------------------------------------------------------------------- +// Purpose: Converts an exponential map (ang/axis) to a quaternion +//----------------------------------------------------------------------------- +void AxisAngleQuaternion( const Vector &axis, float angle, Quaternion &q ) +{ + float sa, ca; + + SinCos( DEG2RAD(angle) * 0.5f, &sa, &ca ); + + q.x = axis.x * sa; + q.y = axis.y * sa; + q.z = axis.z * sa; + q.w = ca; +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts radian-euler axis aligned angles to a quaternion +// Input : *pfAngles - Right-handed Euler angles in radians +// *outQuat - quaternion of form (i,j,k,real) +//----------------------------------------------------------------------------- +void AngleQuaternion( const RadianEuler &angles, Quaternion &outQuat ) +{ + Assert( s_bMathlibInitialized ); +// Assert( angles.IsValid() ); + +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "AngleQuaternion", "Mathlib" ); +#endif + + float sr, sp, sy, cr, cp, cy; + +#ifdef _X360 + fltx4 radians, scale, sine, cosine; + radians = LoadUnaligned3SIMD( &angles.x ); + scale = ReplicateX4( 0.5f ); + radians = MulSIMD( radians, scale ); + SinCos3SIMD( sine, cosine, radians ); + + // NOTE: The ordering here is *different* from the AngleQuaternion below + // because p, y, r are not in the same locations in QAngle + RadianEuler. Yay! + sr = SubFloat( sine, 0 ); sp = SubFloat( sine, 1 ); sy = SubFloat( sine, 2 ); + cr = SubFloat( cosine, 0 ); cp = SubFloat( cosine, 1 ); cy = SubFloat( cosine, 2 ); +#else + SinCos( angles.z * 0.5f, &sy, &cy ); + SinCos( angles.y * 0.5f, &sp, &cp ); + SinCos( angles.x * 0.5f, &sr, &cr ); +#endif + + // NJS: for some reason VC6 wasn't recognizing the common subexpressions: + float srXcp = sr * cp, crXsp = cr * sp; + outQuat.x = srXcp*cy-crXsp*sy; // X + outQuat.y = crXsp*cy+srXcp*sy; // Y + + float crXcp = cr * cp, srXsp = sr * sp; + outQuat.z = crXcp*sy-srXsp*cy; // Z + outQuat.w = crXcp*cy+srXsp*sy; // W (real component) +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts engine-format euler angles to a quaternion +// Input : angles - Right-handed Euler angles in degrees as follows: +// [0]: PITCH: Clockwise rotation around the Y axis. +// [1]: YAW: Counterclockwise rotation around the Z axis. +// [2]: ROLL: Counterclockwise rotation around the X axis. +// *outQuat - quaternion of form (i,j,k,real) +//----------------------------------------------------------------------------- +void AngleQuaternion( const QAngle &angles, Quaternion &outQuat ) +{ +#ifdef _VPROF_MATHLIB + VPROF_BUDGET( "AngleQuaternion", "Mathlib" ); +#endif + + float sr, sp, sy, cr, cp, cy; + +#ifdef _X360 + fltx4 radians, scale, sine, cosine; + radians = LoadUnaligned3SIMD( angles.Base() ); + scale = ReplicateX4( 0.5f * M_PI_F / 180.f ); + radians = MulSIMD( radians, scale ); + SinCos3SIMD( sine, cosine, radians ); + + // NOTE: The ordering here is *different* from the AngleQuaternion above + // because p, y, r are not in the same locations in QAngle + RadianEuler. Yay! + sp = SubFloat( sine, 0 ); sy = SubFloat( sine, 1 ); sr = SubFloat( sine, 2 ); + cp = SubFloat( cosine, 0 ); cy = SubFloat( cosine, 1 ); cr = SubFloat( cosine, 2 ); +#else + SinCos( DEG2RAD( angles.y ) * 0.5f, &sy, &cy ); + SinCos( DEG2RAD( angles.x ) * 0.5f, &sp, &cp ); + SinCos( DEG2RAD( angles.z ) * 0.5f, &sr, &cr ); +#endif + + // NJS: for some reason VC6 wasn't recognizing the common subexpressions: + float srXcp = sr * cp, crXsp = cr * sp; + outQuat.x = srXcp*cy-crXsp*sy; // X + outQuat.y = crXsp*cy+srXcp*sy; // Y + + float crXcp = cr * cp, srXsp = sr * sp; + outQuat.z = crXcp*sy-srXsp*cy; // Z + outQuat.w = crXcp*cy+srXsp*sy; // W (real component) +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts a basis to a quaternion +//----------------------------------------------------------------------------- +void BasisToQuaternion( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Quaternion &q ) +{ + Assert( fabs( vecForward.LengthSqr() - 1.0f ) < 1e-3 ); + Assert( fabs( vecRight.LengthSqr() - 1.0f ) < 1e-3 ); + Assert( fabs( vecUp.LengthSqr() - 1.0f ) < 1e-3 ); + + Vector vecLeft; + VectorMultiply( vecRight, -1.0f, vecLeft ); + + // FIXME: Don't know why, but this doesn't match at all with other result + // so we can't use this super-fast way. + /* + // Find the trace of the matrix: + float flTrace = vecForward.x + vecLeft.y + vecUp.z + 1.0f; + if ( flTrace > 1e-6 ) + { + float flSqrtTrace = FastSqrt( flTrace ); + float s = 0.5f / flSqrtTrace; + q.x = ( vecUp.y - vecLeft.z ) * s; + q.y = ( vecForward.z - vecUp.x ) * s; + q.z = ( vecLeft.x - vecForward.y ) * s; + q.w = 0.5f * flSqrtTrace; + } + else + { + if (( vecForward.x > vecLeft.y ) && ( vecForward.x > vecUp.z ) ) + { + float flSqrtTrace = FastSqrt( 1.0f + vecForward.x - vecLeft.y - vecUp.z ); + float s = 0.5f / flSqrtTrace; + q.x = 0.5f * flSqrtTrace; + q.y = ( vecForward.y + vecLeft.x ) * s; + q.z = ( vecUp.x + vecForward.z ) * s; + q.w = ( vecUp.y - vecLeft.z ) * s; + } + else if ( vecLeft.y > vecUp.z ) + { + float flSqrtTrace = FastSqrt( 1.0f + vecLeft.y - vecForward.x - vecUp.z ); + float s = 0.5f / flSqrtTrace; + q.x = ( vecForward.y + vecLeft.x ) * s; + q.y = 0.5f * flSqrtTrace; + q.z = ( vecUp.y + vecLeft.z ) * s; + q.w = ( vecForward.z - vecUp.x ) * s; + } + else + { + float flSqrtTrace = FastSqrt( 1.0 + vecUp.z - vecForward.x - vecLeft.y ); + float s = 0.5f / flSqrtTrace; + q.x = ( vecUp.x + vecForward.z ) * s; + q.y = ( vecUp.y + vecLeft.z ) * s; + q.z = 0.5f * flSqrtTrace; + q.w = ( vecLeft.x - vecForward.y ) * s; + } + } + QuaternionNormalize( q ); + */ + + // Version 2: Go through angles + + matrix3x4_t mat; + MatrixSetColumn( vecForward, 0, mat ); + MatrixSetColumn( vecLeft, 1, mat ); + MatrixSetColumn( vecUp, 2, mat ); + + QAngle angles; + MatrixAngles( mat, angles ); + +// Quaternion q2; + AngleQuaternion( angles, q ); + +// Assert( fabs(q.x - q2.x) < 1e-3 ); +// Assert( fabs(q.y - q2.y) < 1e-3 ); +// Assert( fabs(q.z - q2.z) < 1e-3 ); +// Assert( fabs(q.w - q2.w) < 1e-3 ); +} + +// FIXME: Optimize! +void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q ) +{ + QAngle angles; + MatrixAngles( mat, angles ); + AngleQuaternion( angles, q ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts a quaternion into engine angles +// Input : *quaternion - q3 + q0.i + q1.j + q2.k +// *outAngles - PITCH, YAW, ROLL +//----------------------------------------------------------------------------- +void QuaternionAngles( const Quaternion &q, RadianEuler &angles ) +{ + Assert( s_bMathlibInitialized ); + Assert( q.IsValid() ); + + // FIXME: doing it this way calculates too much data, needs to do an optimized version... + matrix3x4_t matrix; + QuaternionMatrix( q, matrix ); + MatrixAngles( matrix, angles ); + + Assert( angles.IsValid() ); +} + +//----------------------------------------------------------------------------- +// Purpose: A helper function to normalize p2.x->p1.x and p3.x->p4.x to +// be the same length as p2.x->p3.x +// Input : &p2 - +// &p4 - +// p4n - +//----------------------------------------------------------------------------- +void Spline_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + Vector& p1n, + Vector& p4n ) +{ + float dt = p3.x - p2.x; + + p1n = p1; + p4n = p4; + + if ( dt != 0.0 ) + { + if (p1.x != p2.x) + { + // Equivalent to p1n = p2 - (p2 - p1) * (dt / (p2.x - p1.x)); + VectorLerp( p2, p1, dt / (p2.x - p1.x), p1n ); + } + if (p4.x != p3.x) + { + // Equivalent to p4n = p3 + (p4 - p3) * (dt / (p4.x - p3.x)); + VectorLerp( p3, p4, dt / (p4.x - p3.x), p4n ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +//----------------------------------------------------------------------------- + +void Catmull_Rom_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + float tSqr = t*t*0.5f; + float tSqrSqr = t*tSqr; + t *= 0.5f; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &p3 ); + Assert( &output != &p4 ); + + output.Init(); + + Vector a, b, c, d; + + // matrix row 1 + VectorScale( p1, -tSqrSqr, a ); // 0.5 t^3 * [ (-1*p1) + ( 3*p2) + (-3*p3) + p4 ] + VectorScale( p2, tSqrSqr*3, b ); + VectorScale( p3, tSqrSqr*-3, c ); + VectorScale( p4, tSqrSqr, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 2 + VectorScale( p1, tSqr*2, a ); // 0.5 t^2 * [ ( 2*p1) + (-5*p2) + ( 4*p3) - p4 ] + VectorScale( p2, tSqr*-5, b ); + VectorScale( p3, tSqr*4, c ); + VectorScale( p4, -tSqr, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 3 + VectorScale( p1, -t, a ); // 0.5 t * [ (-1*p1) + p3 ] + VectorScale( p3, t, b ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + + // matrix row 4 + VectorAdd( p2, output, output ); // p2 +} + +void Catmull_Rom_Spline_Tangent( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + float tOne = 3*t*t*0.5f; + float tTwo = 2*t*0.5f; + float tThree = 0.5; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &p3 ); + Assert( &output != &p4 ); + + output.Init(); + + Vector a, b, c, d; + + // matrix row 1 + VectorScale( p1, -tOne, a ); // 0.5 t^3 * [ (-1*p1) + ( 3*p2) + (-3*p3) + p4 ] + VectorScale( p2, tOne*3, b ); + VectorScale( p3, tOne*-3, c ); + VectorScale( p4, tOne, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 2 + VectorScale( p1, tTwo*2, a ); // 0.5 t^2 * [ ( 2*p1) + (-5*p2) + ( 4*p3) - p4 ] + VectorScale( p2, tTwo*-5, b ); + VectorScale( p3, tTwo*4, c ); + VectorScale( p4, -tTwo, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 3 + VectorScale( p1, -tThree, a ); // 0.5 t * [ (-1*p1) + p3 ] + VectorScale( p3, tThree, b ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); +} + +// area under the curve [0..t] +void Catmull_Rom_Spline_Integral( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + output = p2*t + -0.25f*(p1 - p3)*t*t + + (1.0f/6.0f)*(2.0f*p1 - 5.0f*p2 + 4.0f*p3 - p4)*t*t*t + - 0.125f*(p1 - 3.0f*p2 + 3.0f*p3 - p4)*t*t*t*t; +} + + +// area under the curve [0..1] +void Catmull_Rom_Spline_Integral( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + Vector& output ) +{ + output = (-0.25f * p1 + 3.25f * p2 + 3.25f * p3 - 0.25f * p4) * (1.0f / 6.0f); +} + + +void Catmull_Rom_Spline_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + // Normalize p2->p1 and p3->p4 to be the same length as p2->p3 + float dt = p3.DistTo(p2); + + Vector p1n, p4n; + VectorSubtract( p1, p2, p1n ); + VectorSubtract( p4, p3, p4n ); + + VectorNormalize( p1n ); + VectorNormalize( p4n ); + + VectorMA( p2, dt, p1n, p1n ); + VectorMA( p3, dt, p4n, p4n ); + + Catmull_Rom_Spline( p1n, p2, p3, p4n, t, output ); +} + + +void Catmull_Rom_Spline_Integral_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + // Normalize p2->p1 and p3->p4 to be the same length as p2->p3 + float dt = p3.DistTo(p2); + + Vector p1n, p4n; + VectorSubtract( p1, p2, p1n ); + VectorSubtract( p4, p3, p4n ); + + VectorNormalize( p1n ); + VectorNormalize( p4n ); + + VectorMA( p2, dt, p1n, p1n ); + VectorMA( p3, dt, p4n, p4n ); + + Catmull_Rom_Spline_Integral( p1n, p2, p3, p4n, t, output ); +} + + +void Catmull_Rom_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Vector p1n, p4n; + Spline_Normalize( p1, p2, p3, p4, p1n, p4n ); + Catmull_Rom_Spline( p1n, p2, p3, p4n, t, output ); +} + + +//----------------------------------------------------------------------------- +// Purpose: basic hermite spline. t = 0 returns p1, t = 1 returns p2, +// d1 and d2 are used to entry and exit slope of curve +// Input : +//----------------------------------------------------------------------------- + +void Hermite_Spline( + const Vector &p1, + const Vector &p2, + const Vector &d1, + const Vector &d2, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + float tSqr = t*t; + float tCube = t*tSqr; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &d1 ); + Assert( &output != &d2 ); + + float b1 = 2.0f*tCube-3.0f*tSqr+1.0f; + float b2 = 1.0f - b1; // -2*tCube+3*tSqr; + float b3 = tCube-2*tSqr+t; + float b4 = tCube-tSqr; + + VectorScale( p1, b1, output ); + VectorMA( output, b2, p2, output ); + VectorMA( output, b3, d1, output ); + VectorMA( output, b4, d2, output ); +} + +float Hermite_Spline( + float p1, + float p2, + float d1, + float d2, + float t ) +{ + Assert( s_bMathlibInitialized ); + float output; + float tSqr = t*t; + float tCube = t*tSqr; + + float b1 = 2.0f*tCube-3.0f*tSqr+1.0f; + float b2 = 1.0f - b1; // -2*tCube+3*tSqr; + float b3 = tCube-2*tSqr+t; + float b4 = tCube-tSqr; + + output = p1 * b1; + output += p2 * b2; + output += d1 * b3; + output += d2 * b4; + + return output; +} + + +void Hermite_SplineBasis( float t, float basis[4] ) +{ + float tSqr = t*t; + float tCube = t*tSqr; + + basis[0] = 2.0f*tCube-3.0f*tSqr+1.0f; + basis[1] = 1.0f - basis[0]; // -2*tCube+3*tSqr; + basis[2] = tCube-2*tSqr+t; + basis[3] = tCube-tSqr; +} + +//----------------------------------------------------------------------------- +// Purpose: simple three data point hermite spline. +// t = 0 returns p1, t = 1 returns p2, +// slopes are generated from the p0->p1 and p1->p2 segments +// this is reasonable C1 method when there's no "p3" data yet. +// Input : +//----------------------------------------------------------------------------- + +// BUG: the VectorSubtract()'s calls go away if the global optimizer is enabled +#pragma optimize( "g", off ) + +void Hermite_Spline( const Vector &p0, const Vector &p1, const Vector &p2, float t, Vector& output ) +{ + Vector e10, e21; + VectorSubtract( p1, p0, e10 ); + VectorSubtract( p2, p1, e21 ); + Hermite_Spline( p1, p2, e10, e21, t, output ); +} + +#pragma optimize( "", on ) + +float Hermite_Spline( float p0, float p1, float p2, float t ) +{ + return Hermite_Spline( p1, p2, p1 - p0, p2 - p1, t ); +} + + +void Hermite_Spline( const Quaternion &q0, const Quaternion &q1, const Quaternion &q2, float t, Quaternion &output ) +{ + // cheap, hacked version of quaternions + Quaternion q0a; + Quaternion q1a; + + QuaternionAlign( q2, q0, q0a ); + QuaternionAlign( q2, q1, q1a ); + + output.x = Hermite_Spline( q0a.x, q1a.x, q2.x, t ); + output.y = Hermite_Spline( q0a.y, q1a.y, q2.y, t ); + output.z = Hermite_Spline( q0a.z, q1a.z, q2.z, t ); + output.w = Hermite_Spline( q0a.w, q1a.w, q2.w, t ); + + QuaternionNormalize( output ); +} + +// See http://en.wikipedia.org/wiki/Kochanek-Bartels_curves +// +// Tension: -1 = Round -> 1 = Tight +// Bias: -1 = Pre-shoot (bias left) -> 1 = Post-shoot (bias right) +// Continuity: -1 = Box corners -> 1 = Inverted corners +// +// If T=B=C=0 it's the same matrix as Catmull-Rom. +// If T=1 & B=C=0 it's the same as Cubic. +// If T=B=0 & C=-1 it's just linear interpolation +// +// See http://news.povray.org/povray.binaries.tutorials/attachment/%3CXns91B880592482seed7@povray.org%3E/Splines.bas.txt +// for example code and descriptions of various spline types... +// +void Kochanek_Bartels_Spline( + float tension, + float bias, + float continuity, + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + + float ffa, ffb, ffc, ffd; + + ffa = ( 1.0f - tension ) * ( 1.0f + continuity ) * ( 1.0f + bias ); + ffb = ( 1.0f - tension ) * ( 1.0f - continuity ) * ( 1.0f - bias ); + ffc = ( 1.0f - tension ) * ( 1.0f - continuity ) * ( 1.0f + bias ); + ffd = ( 1.0f - tension ) * ( 1.0f + continuity ) * ( 1.0f - bias ); + + float tSqr = t*t*0.5f; + float tSqrSqr = t*tSqr; + t *= 0.5f; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &p3 ); + Assert( &output != &p4 ); + + output.Init(); + + Vector a, b, c, d; + + // matrix row 1 + VectorScale( p1, tSqrSqr * -ffa, a ); + VectorScale( p2, tSqrSqr * ( 4.0f + ffa - ffb - ffc ), b ); + VectorScale( p3, tSqrSqr * ( -4.0f + ffb + ffc - ffd ), c ); + VectorScale( p4, tSqrSqr * ffd, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 2 + VectorScale( p1, tSqr* 2 * ffa, a ); + VectorScale( p2, tSqr * ( -6 - 2 * ffa + 2 * ffb + ffc ), b ); + VectorScale( p3, tSqr * ( 6 - 2 * ffb - ffc + ffd ), c ); + VectorScale( p4, tSqr * -ffd, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 3 + VectorScale( p1, t * -ffa, a ); + VectorScale( p2, t * ( ffa - ffb ), b ); + VectorScale( p3, t * ffb, c ); + // p4 unchanged + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + + // matrix row 4 + // p1, p3, p4 unchanged + // p2 is multiplied by 1 and added, so just added it directly + + VectorAdd( p2, output, output ); +} + +void Kochanek_Bartels_Spline_NormalizeX( + float tension, + float bias, + float continuity, + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Vector p1n, p4n; + Spline_Normalize( p1, p2, p3, p4, p1n, p4n ); + Kochanek_Bartels_Spline( tension, bias, continuity, p1n, p2, p3, p4n, t, output ); +} + +void Cubic_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + + float tSqr = t*t; + float tSqrSqr = t*tSqr; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &p3 ); + Assert( &output != &p4 ); + + output.Init(); + + Vector a, b, c, d; + + // matrix row 1 + VectorScale( p2, tSqrSqr * 2, b ); + VectorScale( p3, tSqrSqr * -2, c ); + + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + + // matrix row 2 + VectorScale( p2, tSqr * -3, b ); + VectorScale( p3, tSqr * 3, c ); + + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + + // matrix row 3 + // no influence + // p4 unchanged + + // matrix row 4 + // p1, p3, p4 unchanged + VectorAdd( p2, output, output ); +} + +void Cubic_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Vector p1n, p4n; + Spline_Normalize( p1, p2, p3, p4, p1n, p4n ); + Cubic_Spline( p1n, p2, p3, p4n, t, output ); +} + +void BSpline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + + float oneOver6 = 1.0f / 6.0f; + + float tSqr = t * t * oneOver6; + float tSqrSqr = t*tSqr; + t *= oneOver6; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &p3 ); + Assert( &output != &p4 ); + + output.Init(); + + Vector a, b, c, d; + + // matrix row 1 + VectorScale( p1, -tSqrSqr, a ); + VectorScale( p2, tSqrSqr * 3.0f, b ); + VectorScale( p3, tSqrSqr * -3.0f, c ); + VectorScale( p4, tSqrSqr, d ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + VectorAdd( d, output, output ); + + // matrix row 2 + VectorScale( p1, tSqr * 3.0f, a ); + VectorScale( p2, tSqr * -6.0f, b ); + VectorScale( p3, tSqr * 3.0f, c ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + + // matrix row 3 + VectorScale( p1, t * -3.0f, a ); + VectorScale( p3, t * 3.0f, c ); + // p4 unchanged + + VectorAdd( a, output, output ); + VectorAdd( c, output, output ); + + // matrix row 4 + // p1 and p3 scaled by 1.0f, so done below + VectorScale( p1, oneOver6, a ); + VectorScale( p2, 4.0f * oneOver6, b ); + VectorScale( p3, oneOver6, c ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); +} + +void BSpline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Vector p1n, p4n; + Spline_Normalize( p1, p2, p3, p4, p1n, p4n ); + BSpline( p1n, p2, p3, p4n, t, output ); +} + +void Parabolic_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Assert( s_bMathlibInitialized ); + + float tSqr = t*t*0.5f; + t *= 0.5f; + + Assert( &output != &p1 ); + Assert( &output != &p2 ); + Assert( &output != &p3 ); + Assert( &output != &p4 ); + + output.Init(); + + Vector a, b, c, d; + + // matrix row 1 + // no influence from t cubed + + // matrix row 2 + VectorScale( p1, tSqr, a ); + VectorScale( p2, tSqr * -2.0f, b ); + VectorScale( p3, tSqr, c ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + VectorAdd( c, output, output ); + + // matrix row 3 + VectorScale( p1, t * -2.0f, a ); + VectorScale( p2, t * 2.0f, b ); + // p4 unchanged + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); + + // matrix row 4 + VectorScale( p1, 0.5f, a ); + VectorScale( p2, 0.5f, b ); + + VectorAdd( a, output, output ); + VectorAdd( b, output, output ); +} + +void Parabolic_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ) +{ + Vector p1n, p4n; + Spline_Normalize( p1, p2, p3, p4, p1n, p4n ); + Parabolic_Spline( p1n, p2, p3, p4n, t, output ); +} + +//----------------------------------------------------------------------------- +// Purpose: Compress the input values for a ranged result such that from 75% to 200% smoothly of the range maps +//----------------------------------------------------------------------------- + +float RangeCompressor( float flValue, float flMin, float flMax, float flBase ) +{ + // clamp base + if (flBase < flMin) + flBase = flMin; + if (flBase > flMax) + flBase = flMax; + + flValue += flBase; + + // convert to 0 to 1 value + float flMid = (flValue - flMin) / (flMax - flMin); + // convert to -1 to 1 value + float flTarget = flMid * 2 - 1; + + if (fabs(flTarget) > 0.75) + { + float t = (fabs(flTarget) - 0.75) / (1.25); + if (t < 1.0) + { + if (flTarget > 0) + { + flTarget = Hermite_Spline( 0.75, 1, 0.75, 0, t ); + } + else + { + flTarget = -Hermite_Spline( 0.75, 1, 0.75, 0, t ); + } + } + else + { + flTarget = (flTarget > 0) ? 1.0f : -1.0f; + } + } + + flMid = (flTarget + 1 ) / 2.0; + flValue = flMin * (1 - flMid) + flMax * flMid; + + flValue -= flBase; + + return flValue; +} + + +//#pragma optimize( "", on ) + +//----------------------------------------------------------------------------- +// Transforms a AABB into another space; which will inherently grow the box. +//----------------------------------------------------------------------------- +void TransformAABB( const matrix3x4_t& transform, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) +{ + Vector localCenter; + VectorAdd( vecMinsIn, vecMaxsIn, localCenter ); + localCenter *= 0.5f; + + Vector localExtents; + VectorSubtract( vecMaxsIn, localCenter, localExtents ); + + Vector worldCenter; + VectorTransform( localCenter, transform, worldCenter ); + + Vector worldExtents; + worldExtents.x = DotProductAbs( localExtents, transform[0] ); + worldExtents.y = DotProductAbs( localExtents, transform[1] ); + worldExtents.z = DotProductAbs( localExtents, transform[2] ); + + VectorSubtract( worldCenter, worldExtents, vecMinsOut ); + VectorAdd( worldCenter, worldExtents, vecMaxsOut ); +} + + +//----------------------------------------------------------------------------- +// Uses the inverse transform of in1 +//----------------------------------------------------------------------------- +void ITransformAABB( const matrix3x4_t& transform, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) +{ + Vector worldCenter; + VectorAdd( vecMinsIn, vecMaxsIn, worldCenter ); + worldCenter *= 0.5f; + + Vector worldExtents; + VectorSubtract( vecMaxsIn, worldCenter, worldExtents ); + + Vector localCenter; + VectorITransform( worldCenter, transform, localCenter ); + + Vector localExtents; + localExtents.x = FloatMakePositive( worldExtents.x * transform[0][0] ) + + FloatMakePositive( worldExtents.y * transform[1][0] ) + + FloatMakePositive( worldExtents.z * transform[2][0] ); + localExtents.y = FloatMakePositive( worldExtents.x * transform[0][1] ) + + FloatMakePositive( worldExtents.y * transform[1][1] ) + + FloatMakePositive( worldExtents.z * transform[2][1] ); + localExtents.z = FloatMakePositive( worldExtents.x * transform[0][2] ) + + FloatMakePositive( worldExtents.y * transform[1][2] ) + + FloatMakePositive( worldExtents.z * transform[2][2] ); + + VectorSubtract( localCenter, localExtents, vecMinsOut ); + VectorAdd( localCenter, localExtents, vecMaxsOut ); +} + + +//----------------------------------------------------------------------------- +// Rotates a AABB into another space; which will inherently grow the box. +// (same as TransformAABB, but doesn't take the translation into account) +//----------------------------------------------------------------------------- +void RotateAABB( const matrix3x4_t &transform, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) +{ + Vector localCenter; + VectorAdd( vecMinsIn, vecMaxsIn, localCenter ); + localCenter *= 0.5f; + + Vector localExtents; + VectorSubtract( vecMaxsIn, localCenter, localExtents ); + + Vector newCenter; + VectorRotate( localCenter, transform, newCenter ); + + Vector newExtents; + newExtents.x = DotProductAbs( localExtents, transform[0] ); + newExtents.y = DotProductAbs( localExtents, transform[1] ); + newExtents.z = DotProductAbs( localExtents, transform[2] ); + + VectorSubtract( newCenter, newExtents, vecMinsOut ); + VectorAdd( newCenter, newExtents, vecMaxsOut ); +} + + +//----------------------------------------------------------------------------- +// Uses the inverse transform of in1 +//----------------------------------------------------------------------------- +void IRotateAABB( const matrix3x4_t &transform, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) +{ + Vector oldCenter; + VectorAdd( vecMinsIn, vecMaxsIn, oldCenter ); + oldCenter *= 0.5f; + + Vector oldExtents; + VectorSubtract( vecMaxsIn, oldCenter, oldExtents ); + + Vector newCenter; + VectorIRotate( oldCenter, transform, newCenter ); + + Vector newExtents; + newExtents.x = FloatMakePositive( oldExtents.x * transform[0][0] ) + + FloatMakePositive( oldExtents.y * transform[1][0] ) + + FloatMakePositive( oldExtents.z * transform[2][0] ); + newExtents.y = FloatMakePositive( oldExtents.x * transform[0][1] ) + + FloatMakePositive( oldExtents.y * transform[1][1] ) + + FloatMakePositive( oldExtents.z * transform[2][1] ); + newExtents.z = FloatMakePositive( oldExtents.x * transform[0][2] ) + + FloatMakePositive( oldExtents.y * transform[1][2] ) + + FloatMakePositive( oldExtents.z * transform[2][2] ); + + VectorSubtract( newCenter, newExtents, vecMinsOut ); + VectorAdd( newCenter, newExtents, vecMaxsOut ); +} + + +float CalcSqrDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point ) +{ + float flDelta; + float flDistSqr = 0.0f; + + if ( point.x < mins.x ) + { + flDelta = (mins.x - point.x); + flDistSqr += flDelta * flDelta; + } + else if ( point.x > maxs.x ) + { + flDelta = (point.x - maxs.x); + flDistSqr += flDelta * flDelta; + } + + if ( point.y < mins.y ) + { + flDelta = (mins.y - point.y); + flDistSqr += flDelta * flDelta; + } + else if ( point.y > maxs.y ) + { + flDelta = (point.y - maxs.y); + flDistSqr += flDelta * flDelta; + } + + if ( point.z < mins.z ) + { + flDelta = (mins.z - point.z); + flDistSqr += flDelta * flDelta; + } + else if ( point.z > maxs.z ) + { + flDelta = (point.z - maxs.z); + flDistSqr += flDelta * flDelta; + } + + return flDistSqr; +} + + +void CalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut ) +{ + closestOut.x = clamp( point.x, mins.x, maxs.x ); + closestOut.y = clamp( point.y, mins.y, maxs.y ); + closestOut.z = clamp( point.z, mins.z, maxs.z ); +} + +void CalcSqrDistAndClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut, float &distSqrOut ) +{ + distSqrOut = 0.0f; + for ( int i = 0; i < 3; i++ ) + { + if ( point[i] < mins[i] ) + { + closestOut[i] = mins[i]; + float flDelta = closestOut[i] - mins[i]; + distSqrOut += flDelta * flDelta; + } + else if ( point[i] > maxs[i] ) + { + closestOut[i] = maxs[i]; + float flDelta = closestOut[i] - maxs[i]; + distSqrOut += flDelta * flDelta; + } + else + { + closestOut[i] = point[i]; + } + } + +} + +float CalcClosestPointToLineT( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vDir ) +{ + Assert( s_bMathlibInitialized ); + VectorSubtract( vLineB, vLineA, vDir ); + + // D dot [P - (A + D*t)] = 0 + // t = ( DP - DA) / DD + float div = vDir.Dot( vDir ); + if( div < 0.00001f ) + { + return 0; + } + else + { + return (vDir.Dot( P ) - vDir.Dot( vLineA )) / div; + } +} + +void CalcClosestPointOnLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector vDir; + float t = CalcClosestPointToLineT( P, vLineA, vLineB, vDir ); + if ( outT ) *outT = t; + vClosest.MulAdd( vLineA, vDir, t ); +} + + +float CalcDistanceToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector vClosest; + CalcClosestPointOnLine( P, vLineA, vLineB, vClosest, outT ); + return P.DistTo(vClosest); +} + +float CalcDistanceSqrToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector vClosest; + CalcClosestPointOnLine( P, vLineA, vLineB, vClosest, outT ); + return P.DistToSqr(vClosest); +} + +void CalcClosestPointOnLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *outT ) +{ + Vector vDir; + float t = CalcClosestPointToLineT( P, vLineA, vLineB, vDir ); + t = clamp( t, 0.f, 1.f ); + if ( outT ) + { + *outT = t; + } + vClosest.MulAdd( vLineA, vDir, t ); +} + + +float CalcDistanceToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector vClosest; + CalcClosestPointOnLineSegment( P, vLineA, vLineB, vClosest, outT ); + return P.DistTo( vClosest ); +} + +float CalcDistanceSqrToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector vClosest; + CalcClosestPointOnLineSegment( P, vLineA, vLineB, vClosest, outT ); + return P.DistToSqr(vClosest); +} + +float CalcClosestPointToLineT2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, Vector2D &vDir ) +{ + Assert( s_bMathlibInitialized ); + Vector2DSubtract( vLineB, vLineA, vDir ); + + // D dot [P - (A + D*t)] = 0 + // t = (DP - DA) / DD + float div = vDir.Dot( vDir ); + if( div < 0.00001f ) + { + return 0; + } + else + { + return (vDir.Dot( P ) - vDir.Dot( vLineA )) / div; + } +} + +void CalcClosestPointOnLine2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, Vector2D &vClosest, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector2D vDir; + float t = CalcClosestPointToLineT2D( P, vLineA, vLineB, vDir ); + if ( outT ) *outT = t; + vClosest.MulAdd( vLineA, vDir, t ); +} + +float CalcDistanceToLine2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector2D vClosest; + CalcClosestPointOnLine2D( P, vLineA, vLineB, vClosest, outT ); + return P.DistTo( vClosest ); +} + +float CalcDistanceSqrToLine2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector2D vClosest; + CalcClosestPointOnLine2D( P, vLineA, vLineB, vClosest, outT ); + return P.DistToSqr(vClosest); +} + +void CalcClosestPointOnLineSegment2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, Vector2D &vClosest, float *outT ) +{ + Vector2D vDir; + float t = CalcClosestPointToLineT2D( P, vLineA, vLineB, vDir ); + t = clamp( t, 0.f, 1.f ); + if ( outT ) + { + *outT = t; + } + vClosest.MulAdd( vLineA, vDir, t ); +} + +float CalcDistanceToLineSegment2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector2D vClosest; + CalcClosestPointOnLineSegment2D( P, vLineA, vLineB, vClosest, outT ); + return P.DistTo( vClosest ); +} + +float CalcDistanceSqrToLineSegment2D( const Vector2D &P, const Vector2D &vLineA, const Vector2D &vLineB, float *outT ) +{ + Assert( s_bMathlibInitialized ); + Vector2D vClosest; + CalcClosestPointOnLineSegment2D( P, vLineA, vLineB, vClosest, outT ); + return P.DistToSqr( vClosest ); +} + +// Do we have another epsilon we could use +#define LINE_EPS ( 0.000001f ) + +//----------------------------------------------------------------------------- +// Purpose: Given lines p1->p2 and p3->p4, computes a line segment (pa->pb) and returns the parameters 0->1 multipliers +// along each segment for the returned points +// Input : p1 - +// p2 - +// p3 - +// p4 - +// *s1 - +// *s2 - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CalcLineToLineIntersectionSegment( + const Vector& p1,const Vector& p2,const Vector& p3,const Vector& p4,Vector *s1,Vector *s2, + float *t1, float *t2) +{ + Vector p13,p43,p21; + float d1343,d4321,d1321,d4343,d2121; + float numer,denom; + + p13.x = p1.x - p3.x; + p13.y = p1.y - p3.y; + p13.z = p1.z - p3.z; + p43.x = p4.x - p3.x; + p43.y = p4.y - p3.y; + p43.z = p4.z - p3.z; + + if (fabs(p43.x) < LINE_EPS && fabs(p43.y) < LINE_EPS && fabs(p43.z) < LINE_EPS) + return false; + p21.x = p2.x - p1.x; + p21.y = p2.y - p1.y; + p21.z = p2.z - p1.z; + if (fabs(p21.x) < LINE_EPS && fabs(p21.y) < LINE_EPS && fabs(p21.z) < LINE_EPS) + return false; + + d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z; + d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z; + d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z; + d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z; + d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z; + + denom = d2121 * d4343 - d4321 * d4321; + if (fabs(denom) < LINE_EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + *t1 = numer / denom; + *t2 = (d1343 + d4321 * (*t1)) / d4343; + + s1->x = p1.x + *t1 * p21.x; + s1->y = p1.y + *t1 * p21.y; + s1->z = p1.z + *t1 * p21.z; + s2->x = p3.x + *t2 * p43.x; + s2->y = p3.y + *t2 * p43.y; + s2->z = p3.z + *t2 * p43.z; + + return true; +} + +#pragma optimize( "", off ) + +#ifndef EXCEPTION_EXECUTE_HANDLER +#define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +#pragma optimize( "", on ) + +static bool s_b3DNowEnabled = false; +static bool s_bMMXEnabled = false; +static bool s_bSSEEnabled = false; +static bool s_bSSE2Enabled = false; + +void MathLib_Init( float gamma, float texGamma, float brightness, int overbright, bool bAllow3DNow, bool bAllowSSE, bool bAllowSSE2, bool bAllowMMX ) +{ + if ( s_bMathlibInitialized ) + return; + + // FIXME: Hook SSE into VectorAligned + Vector4DAligned + +#if !defined( _X360 ) + // Grab the processor information: + const CPUInformation& pi = *GetCPUInformation(); + + // Select the default generic routines. + pfSqrt = _sqrtf; + pfRSqrt = _rsqrtf; + pfRSqrtFast = _rsqrtf; + pfVectorNormalize = _VectorNormalize; + pfVectorNormalizeFast = _VectorNormalizeFast; + pfInvRSquared = _InvRSquared; + pfFastSinCos = SinCos; + pfFastCos = cosf; + + if ( bAllowMMX && pi.m_bMMX ) + { + // Select the MMX specific routines if available + // (MMX routines were used by SW span fillers - not currently used for HW) + s_bMMXEnabled = true; + } + else + { + s_bMMXEnabled = false; + } + + // SSE Generally performs better than 3DNow when present, so this is placed + // first to allow SSE to override these settings. +#if !defined( OSX ) && !defined( PLATFORM_WINDOWS_PC64 ) && !defined(LINUX) + if ( bAllow3DNow && pi.m_b3DNow ) + { + s_b3DNowEnabled = true; + + // Select the 3DNow specific routines if available; + pfVectorNormalize = _3DNow_VectorNormalize; + pfVectorNormalizeFast = _3DNow_VectorNormalizeFast; + pfInvRSquared = _3DNow_InvRSquared; + pfSqrt = _3DNow_Sqrt; + pfRSqrt = _3DNow_RSqrt; + pfRSqrtFast = _3DNow_RSqrt; + } + else +#endif + { + s_b3DNowEnabled = false; + } + + if ( bAllowSSE && pi.m_bSSE ) + { + s_bSSEEnabled = true; + +#ifndef PLATFORM_WINDOWS_PC64 + // These are not yet available. + // Select the SSE specific routines if available + pfVectorNormalize = _VectorNormalize; + pfVectorNormalizeFast = _SSE_VectorNormalizeFast; + pfInvRSquared = _SSE_InvRSquared; + pfSqrt = _SSE_Sqrt; + pfRSqrt = _SSE_RSqrtAccurate; + pfRSqrtFast = _SSE_RSqrtFast; +#endif +#ifdef PLATFORM_WINDOWS_PC32 + pfFastSinCos = _SSE_SinCos; + pfFastCos = _SSE_cos; +#endif + } + else + { + s_bSSEEnabled = false; + } + + if ( bAllowSSE2 && pi.m_bSSE2 ) + { + s_bSSE2Enabled = true; +#ifdef PLATFORM_WINDOWS_PC32 + pfFastSinCos = _SSE2_SinCos; + pfFastCos = _SSE2_cos; +#endif + } + else + { + s_bSSE2Enabled = false; + } +#endif // !_X360 + + s_bMathlibInitialized = true; + + InitSinCosTable(); + BuildGammaTable( gamma, texGamma, brightness, overbright ); +} + +bool MathLib_3DNowEnabled( void ) +{ + Assert( s_bMathlibInitialized ); + return s_b3DNowEnabled; +} + +bool MathLib_MMXEnabled( void ) +{ + Assert( s_bMathlibInitialized ); + return s_bMMXEnabled; +} + +bool MathLib_SSEEnabled( void ) +{ + Assert( s_bMathlibInitialized ); + return s_bSSEEnabled; +} + +bool MathLib_SSE2Enabled( void ) +{ + Assert( s_bMathlibInitialized ); + return s_bSSE2Enabled; +} + +float Approach( float target, float value, float speed ) +{ + float delta = target - value; + + if ( delta > speed ) + value += speed; + else if ( delta < -speed ) + value -= speed; + else + value = target; + + return value; +} + +// BUGBUG: Why doesn't this call angle diff?!?!? +float ApproachAngle( float target, float value, float speed ) +{ + target = anglemod( target ); + value = anglemod( value ); + + float delta = target - value; + + // Speed is assumed to be positive + if ( speed < 0 ) + speed = -speed; + + if ( delta < -180 ) + delta += 360; + else if ( delta > 180 ) + delta -= 360; + + if ( delta > speed ) + value += speed; + else if ( delta < -speed ) + value -= speed; + else + value = target; + + return value; +} + + +// BUGBUG: Why do we need both of these? +float AngleDiff( float destAngle, float srcAngle ) +{ + float delta; + + delta = fmodf(destAngle - srcAngle, 360.0f); + if ( destAngle > srcAngle ) + { + if ( delta >= 180 ) + delta -= 360; + } + else + { + if ( delta <= -180 ) + delta += 360; + } + return delta; +} + + +float AngleDistance( float next, float cur ) +{ + float delta = next - cur; + + if ( delta < -180 ) + delta += 360; + else if ( delta > 180 ) + delta -= 360; + + return delta; +} + + +float AngleNormalize( float angle ) +{ + angle = fmodf(angle, 360.0f); + if (angle > 180) + { + angle -= 360; + } + if (angle < -180) + { + angle += 360; + } + return angle; +} + +//-------------------------------------------------------------------------------------------------------------- +// ensure that 0 <= angle <= 360 +float AngleNormalizePositive( float angle ) +{ + angle = fmodf( angle, 360.0f ); + + if (angle < 0.0f) + { + angle += 360.0f; + } + + return angle; +} + +//-------------------------------------------------------------------------------------------------------------- +bool AnglesAreEqual( float a, float b, float tolerance ) +{ + return (fabs( AngleDiff( a, b ) ) < tolerance); +} + +void RotationDeltaAxisAngle( const QAngle &srcAngles, const QAngle &destAngles, Vector &deltaAxis, float &deltaAngle ) +{ + Quaternion srcQuat, destQuat, srcQuatInv, out; + AngleQuaternion( srcAngles, srcQuat ); + AngleQuaternion( destAngles, destQuat ); + QuaternionScale( srcQuat, -1, srcQuatInv ); + QuaternionMult( destQuat, srcQuatInv, out ); + + QuaternionNormalize( out ); + QuaternionAxisAngle( out, deltaAxis, deltaAngle ); +} + +void RotationDelta( const QAngle &srcAngles, const QAngle &destAngles, QAngle *out ) +{ + matrix3x4_t src, srcInv; + matrix3x4_t dest; + AngleMatrix( srcAngles, src ); + AngleMatrix( destAngles, dest ); + // xform = src(-1) * dest + MatrixInvert( src, srcInv ); + matrix3x4_t xform; + ConcatTransforms( dest, srcInv, xform ); + QAngle xformAngles; + MatrixAngles( xform, xformAngles ); + if ( out ) + { + *out = xformAngles; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Computes a triangle normal +//----------------------------------------------------------------------------- +void ComputeTrianglePlane( const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept ) +{ + Vector e1, e2; + VectorSubtract( v2, v1, e1 ); + VectorSubtract( v3, v1, e2 ); + CrossProduct( e1, e2, normal ); + VectorNormalize( normal ); + intercept = DotProduct( normal, v1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: This is a clone of BaseWindingForPlane() +// Input : *outVerts - an array of preallocated verts to build the polygon in +// normal - the plane normal +// dist - the plane constant +// Output : int - vert count (always 4) +//----------------------------------------------------------------------------- +int PolyFromPlane( Vector *outVerts, const Vector& normal, float dist, float fHalfScale ) +{ + int i, x; + vec_t max, v; + Vector org, vright, vup; + + // find the major axis + + max = -16384; //MAX_COORD_INTEGER + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + + if (x==-1) + return 0; + + // Build a unit vector along something other than the major axis + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + // Remove the component of this vector along the normal + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + // Make it a unit (perpendicular) + VectorNormalize (vup); + + // Center of the poly is at normal * dist + VectorScale (normal, dist, org); + // Calculate the third orthonormal basis vector for our plane space (this one and vup are in the plane) + CrossProduct (vup, normal, vright); + + // Make the plane's basis vectors big (these are the half-sides of the polygon we're making) + VectorScale (vup, fHalfScale, vup); + VectorScale (vright, fHalfScale, vright); + + // Move diagonally away from org to create the corner verts + VectorSubtract (org, vright, outVerts[0]); // left + VectorAdd (outVerts[0], vup, outVerts[0]); // up + + VectorAdd (org, vright, outVerts[1]); // right + VectorAdd (outVerts[1], vup, outVerts[1]); // up + + VectorAdd (org, vright, outVerts[2]); // right + VectorSubtract (outVerts[2], vup, outVerts[2]); // down + + VectorSubtract (org, vright, outVerts[3]); // left + VectorSubtract (outVerts[3], vup, outVerts[3]); // down + + // The four corners form a planar quadrilateral normal to "normal" + return 4; +} + +//----------------------------------------------------------------------------- +// Purpose: clip a poly to the plane and return the poly on the front side of the plane +// Input : *inVerts - input polygon +// vertCount - # verts in input poly +// *outVerts - destination poly +// normal - plane normal +// dist - plane constant +// Output : int - # verts in output poly +//----------------------------------------------------------------------------- + +int ClipPolyToPlane( Vector *inVerts, int vertCount, Vector *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon ) +{ + vec_t *dists = (vec_t *)stackalloc( sizeof(vec_t) * vertCount * 4 ); //4x vertcount should cover all cases + int *sides = (int *)stackalloc( sizeof(vec_t) * vertCount * 4 ); + int counts[3]; + vec_t dot; + int i, j; + Vector mid = vec3_origin; + int outCount; + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for ( i = 0; i < vertCount; i++ ) + { + dot = DotProduct( inVerts[i], normal) - dist; + dists[i] = dot; + if ( dot > fOnPlaneEpsilon ) + { + sides[i] = SIDE_FRONT; + } + else if ( dot < -fOnPlaneEpsilon ) + { + sides[i] = SIDE_BACK; + } + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + return 0; + + if (!counts[1]) + { + // Copy to output verts + for ( i = 0; i < vertCount; i++ ) + { + VectorCopy( inVerts[i], outVerts[i] ); + } + return vertCount; + } + + outCount = 0; + for ( i = 0; i < vertCount; i++ ) + { + Vector& p1 = inVerts[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy( p1, outVerts[outCount]); + outCount++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy( p1, outVerts[outCount]); + outCount++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + Vector& p2 = inVerts[(i+1)%vertCount]; + + 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, outVerts[outCount]); + outCount++; + } + + return outCount; +} + + +int ClipPolyToPlane_Precise( double *inVerts, int vertCount, double *outVerts, const double *normal, double dist, double fOnPlaneEpsilon ) +{ + double *dists = (double *)stackalloc( sizeof(double) * vertCount * 4 ); //4x vertcount should cover all cases + int *sides = (int *)stackalloc( sizeof(double) * vertCount * 4 ); + int counts[3]; + double dot; + int i, j; + //Vector mid = vec3_origin; + double mid[3]; + mid[0] = 0.0; + mid[1] = 0.0; + mid[2] = 0.0; + int outCount; + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for ( i = 0; i < vertCount; i++ ) + { + //dot = DotProduct( inVerts[i], normal) - dist; + dot = ((inVerts[i*3 + 0] * normal[0]) + (inVerts[i*3 + 1] * normal[1]) + (inVerts[i*3 + 2] * normal[2])) - dist; + dists[i] = dot; + if ( dot > fOnPlaneEpsilon ) + { + sides[i] = SIDE_FRONT; + } + else if ( dot < -fOnPlaneEpsilon ) + { + sides[i] = SIDE_BACK; + } + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + return 0; + + if (!counts[1]) + { + // Copy to output verts + //for ( i = 0; i < vertCount; i++ ) + for ( i = 0; i < vertCount * 3; i++ ) + { + //VectorCopy( inVerts[i], outVerts[i] ); + outVerts[i] = inVerts[i]; + } + return vertCount; + } + + outCount = 0; + for ( i = 0; i < vertCount; i++ ) + { + //Vector& p1 = inVerts[i]; + double *p1 = &inVerts[i*3]; + //p1[0] = inVerts[i*3 + 0]; + //p1[1] = inVerts[i*3 + 1]; + //p1[2] = inVerts[i*3 + 2]; + + if (sides[i] == SIDE_ON) + { + //VectorCopy( p1, outVerts[outCount]); + outVerts[outCount*3 + 0] = p1[0]; + outVerts[outCount*3 + 1] = p1[1]; + outVerts[outCount*3 + 2] = p1[2]; + outCount++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + //VectorCopy( p1, outVerts[outCount]); + outVerts[outCount*3 + 0] = p1[0]; + outVerts[outCount*3 + 1] = p1[1]; + outVerts[outCount*3 + 2] = p1[2]; + outCount++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + //Vector& p2 = inVerts[(i+1)%vertCount]; + int wrappedindex = (i+1)%vertCount; + double *p2 = &inVerts[wrappedindex*3]; + //p2[0] = inVerts[wrappedindex*3 + 0]; + //p2[1] = inVerts[wrappedindex*3 + 1]; + //p2[2] = inVerts[wrappedindex*3 + 2]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { + mid[j] = (double)p1[j] + dot*((double)p2[j]-(double)p1[j]); + } + + //VectorCopy (mid, outVerts[outCount]); + outVerts[outCount*3 + 0] = mid[0]; + outVerts[outCount*3 + 1] = mid[1]; + outVerts[outCount*3 + 2] = mid[2]; + outCount++; + } + + return outCount; +} + +int CeilPow2( int in ) +{ + int retval; + + retval = 1; + while( retval < in ) + retval <<= 1; + return retval; +} + +int FloorPow2( int in ) +{ + int retval; + + retval = 1; + while( retval < in ) + retval <<= 1; + return retval >> 1; +} + + +//----------------------------------------------------------------------------- +// Computes Y fov from an X fov and a screen aspect ratio +//----------------------------------------------------------------------------- +float CalcFovY( float flFovX, float flAspect ) +{ + if ( flFovX < 1 || flFovX > 179) + { + flFovX = 90; // error, set to 90 + } + + // The long, but illustrative version (more closely matches CShaderAPIDX8::PerspectiveX, which + // is what it's based on). + // + //float width = 2 * zNear * tan( DEG2RAD( fov_x / 2.0 ) ); + //float height = width / screenaspect; + //float yRadians = atan( (height/2.0) / zNear ); + //return RAD2DEG( yRadians ) * 2; + + // The short and sweet version. + float val = atan( tan( DEG2RAD( flFovX ) * 0.5f ) / flAspect ); + val = RAD2DEG( val ) * 2.0f; + return val; +} + +float CalcFovX( float flFovY, float flAspect ) +{ + return RAD2DEG( atan( tan( DEG2RAD( flFovY ) * 0.5f ) * flAspect ) ) * 2.0f; +} + + +//----------------------------------------------------------------------------- +// Generate a frustum based on perspective view parameters +//----------------------------------------------------------------------------- +void GeneratePerspectiveFrustum( const Vector& origin, const Vector &forward, + const Vector &right, const Vector &up, float flZNear, float flZFar, + float flFovX, float flFovY, Frustum_t &frustum ) +{ + float flIntercept = DotProduct( origin, forward ); + + // Setup the near and far planes. + frustum.SetPlane( FRUSTUM_FARZ, PLANE_ANYZ, -forward, -flZFar - flIntercept ); + frustum.SetPlane( FRUSTUM_NEARZ, PLANE_ANYZ, forward, flZNear + flIntercept ); + + flFovX *= 0.5f; + flFovY *= 0.5f; + + float flTanX = tan( DEG2RAD( flFovX ) ); + float flTanY = tan( DEG2RAD( flFovY ) ); + + // OPTIMIZE: Normalizing these planes is not necessary for culling + Vector normalPos, normalNeg; + + VectorMA( right, flTanX, forward, normalPos ); + VectorMA( normalPos, -2.0f, right, normalNeg ); + + VectorNormalize( normalPos ); + VectorNormalize( normalNeg ); + + frustum.SetPlane( FRUSTUM_LEFT, PLANE_ANYZ, normalPos, normalPos.Dot( origin ) ); + frustum.SetPlane( FRUSTUM_RIGHT, PLANE_ANYZ, normalNeg, normalNeg.Dot( origin ) ); + + VectorMA( up, flTanY, forward, normalPos ); + VectorMA( normalPos, -2.0f, up, normalNeg ); + + VectorNormalize( normalPos ); + VectorNormalize( normalNeg ); + + frustum.SetPlane( FRUSTUM_BOTTOM, PLANE_ANYZ, normalPos, normalPos.Dot( origin ) ); + frustum.SetPlane( FRUSTUM_TOP, PLANE_ANYZ, normalNeg, normalNeg.Dot( origin ) ); +} + + +//----------------------------------------------------------------------------- +// Version that accepts angles instead of vectors +//----------------------------------------------------------------------------- +void GeneratePerspectiveFrustum( const Vector& origin, const QAngle &angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t &frustum ) +{ + Vector vecForward, vecRight, vecUp; + AngleVectors( angles, &vecForward, &vecRight, &vecUp ); + float flFovY = CalcFovY( flFovX, flAspectRatio ); + GeneratePerspectiveFrustum( origin, vecForward, vecRight, vecUp, flZNear, flZFar, flFovX, flFovY, frustum ); +} + +bool R_CullBox( const Vector& mins, const Vector& maxs, const Frustum_t &frustum ) +{ + return (( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_RIGHT) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_LEFT) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_TOP) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_BOTTOM) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_NEARZ) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_FARZ) ) == 2 ) ); +} + +bool R_CullBoxSkipNear( const Vector& mins, const Vector& maxs, const Frustum_t &frustum ) +{ + return (( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_RIGHT) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_LEFT) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_TOP) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_BOTTOM) ) == 2 ) || + ( BoxOnPlaneSide( mins, maxs, frustum.GetPlane(FRUSTUM_FARZ) ) == 2 ) ); +} + + +// NOTE: This routine was taken (and modified) from NVidia's BlinnReflection demo +// Creates basis vectors, based on a vertex and index list. +// See the NVidia white paper 'GDC2K PerPixel Lighting' for a description +// of how this computation works +#define SMALL_FLOAT 1e-12 + +void CalcTriangleTangentSpace( const Vector &p0, const Vector &p1, const Vector &p2, + const Vector2D &t0, const Vector2D &t1, const Vector2D& t2, + Vector &sVect, Vector &tVect ) +{ + /* Compute the partial derivatives of X, Y, and Z with respect to S and T. */ + sVect.Init( 0.0f, 0.0f, 0.0f ); + tVect.Init( 0.0f, 0.0f, 0.0f ); + + // x, s, t + Vector edge01( p1.x - p0.x, t1.x - t0.x, t1.y - t0.y ); + Vector edge02( p2.x - p0.x, t2.x - t0.x, t2.y - t0.y ); + + Vector cross; + CrossProduct( edge01, edge02, cross ); + if ( fabs( cross.x ) > SMALL_FLOAT ) + { + sVect.x += -cross.y / cross.x; + tVect.x += -cross.z / cross.x; + } + + // y, s, t + edge01.Init( p1.y - p0.y, t1.x - t0.x, t1.y - t0.y ); + edge02.Init( p2.y - p0.y, t2.x - t0.x, t2.y - t0.y ); + + CrossProduct( edge01, edge02, cross ); + if ( fabs( cross.x ) > SMALL_FLOAT ) + { + sVect.y += -cross.y / cross.x; + tVect.y += -cross.z / cross.x; + } + + // z, s, t + edge01.Init( p1.z - p0.z, t1.x - t0.x, t1.y - t0.y ); + edge02.Init( p2.z - p0.z, t2.x - t0.x, t2.y - t0.y ); + + CrossProduct( edge01, edge02, cross ); + if( fabs( cross.x ) > SMALL_FLOAT ) + { + sVect.z += -cross.y / cross.x; + tVect.z += -cross.z / cross.x; + } + + // Normalize sVect and tVect + VectorNormalize( sVect ); + VectorNormalize( tVect ); +} + + +//----------------------------------------------------------------------------- +// Convert RGB to HSV +//----------------------------------------------------------------------------- +void RGBtoHSV( const Vector &rgb, Vector &hsv ) +{ + float flMax = vmax( rgb.x, rgb.y ); + flMax = vmax( flMax, rgb.z ); + float flMin = vmin( rgb.x, rgb.y ); + flMin = vmin( flMin, rgb.z ); + + // hsv.z is the value + hsv.z = flMax; + + // hsv.y is the saturation + if (flMax != 0.0F) + { + hsv.y = (flMax - flMin) / flMax; + } + else + { + hsv.y = 0.0F; + } + + // hsv.x is the hue + if (hsv.y == 0.0F) + { + hsv.x = -1.0f; + } + else + { + float32 d = flMax - flMin; + if (rgb.x == flMax) + { + hsv.x = (rgb.y - rgb.z) / d; + } + else if (rgb.y == flMax) + { + hsv.x = 2.0F + (rgb.z - rgb.x) / d; + } + else + { + hsv.x = 4.0F + (rgb.x - rgb.y) / d; + } + hsv.x *= 60.0F; + if ( hsv.x < 0.0F ) + { + hsv.x += 360.0F; + } + } +} + + +//----------------------------------------------------------------------------- +// Convert HSV to RGB +//----------------------------------------------------------------------------- +void HSVtoRGB( const Vector &hsv, Vector &rgb ) +{ + if ( hsv.y == 0.0F ) + { + rgb.Init( hsv.z, hsv.z, hsv.z ); + return; + } + + float32 hue = hsv.x; + if (hue == 360.0F) + { + hue = 0.0F; + } + hue /= 60.0F; + int i = hue; // integer part + float32 f = hue - i; // fractional part + float32 p = hsv.z * (1.0F - hsv.y); + float32 q = hsv.z * (1.0F - hsv.y * f); + float32 t = hsv.z * (1.0F - hsv.y * (1.0F - f)); + switch(i) + { + case 0: rgb.Init( hsv.z, t, p ); break; + case 1: rgb.Init( q, hsv.z, p ); break; + case 2: rgb.Init( p, hsv.z, t ); break; + case 3: rgb.Init( p, q, hsv.z ); break; + case 4: rgb.Init( t, p, hsv.z ); break; + case 5: rgb.Init( hsv.z, p, q ); break; + } +} + + +void GetInterpolationData( float const *pKnotPositions, + float const *pKnotValues, + int nNumValuesinList, + int nInterpolationRange, + float flPositionToInterpolateAt, + bool bWrap, + float *pValueA, + float *pValueB, + float *pInterpolationValue) +{ + // first, find the bracketting knots by looking for the first knot >= our index + + int idx; + for(idx = 0; idx < nNumValuesinList; idx++ ) + { + if ( pKnotPositions[idx] >= flPositionToInterpolateAt ) + break; + } + int nKnot1, nKnot2; + float flOffsetFromStartOfGap, flSizeOfGap; + if ( idx == 0) + { + if ( bWrap ) + { + nKnot1 = nNumValuesinList-1; + nKnot2 = 0; + flSizeOfGap = + ( pKnotPositions[nKnot2] + ( nInterpolationRange-pKnotPositions[nKnot1] ) ); + flOffsetFromStartOfGap = + flPositionToInterpolateAt + ( nInterpolationRange-pKnotPositions[nKnot1] ); + } + else + { + *pValueA = *pValueB = pKnotValues[0]; + *pInterpolationValue = 1.0; + return; + } + } + else if ( idx == nNumValuesinList ) // ran out of values + { + if ( bWrap ) + { + nKnot1 = nNumValuesinList -1; + nKnot2 = 0; + flSizeOfGap = ( pKnotPositions[nKnot2] + + ( nInterpolationRange-pKnotPositions[nKnot1] ) ); + flOffsetFromStartOfGap = flPositionToInterpolateAt - pKnotPositions[nKnot1]; + } + else + { + *pValueA = *pValueB = pKnotValues[nNumValuesinList-1]; + *pInterpolationValue = 1.0; + return; + } + + } + else + { + nKnot1 = idx-1; + nKnot2 = idx; + flSizeOfGap = pKnotPositions[nKnot2]-pKnotPositions[nKnot1]; + flOffsetFromStartOfGap = flPositionToInterpolateAt-pKnotPositions[nKnot1]; + } + + *pValueA = pKnotValues[nKnot1]; + *pValueB = pKnotValues[nKnot2]; + *pInterpolationValue = FLerp( 0, 1, 0, flSizeOfGap, flOffsetFromStartOfGap ); + return; +} + +float RandomVectorInUnitSphere( Vector *pVector ) +{ + // Guarantee uniform random distribution within a sphere + // Graphics gems III contains this algorithm ("Nonuniform random point sets via warping") + float u = ((float)rand() / VALVE_RAND_MAX); + float v = ((float)rand() / VALVE_RAND_MAX); + float w = ((float)rand() / VALVE_RAND_MAX); + + float flPhi = acos( 1 - 2 * u ); + float flTheta = 2 * M_PI * v; + float flRadius = powf( w, 1.0f / 3.0f ); + + float flSinPhi, flCosPhi; + float flSinTheta, flCosTheta; + SinCos( flPhi, &flSinPhi, &flCosPhi ); + SinCos( flTheta, &flSinTheta, &flCosTheta ); + + pVector->x = flRadius * flSinPhi * flCosTheta; + pVector->y = flRadius * flSinPhi * flSinTheta; + pVector->z = flRadius * flCosPhi; + return flRadius; +} + +float RandomVectorInUnitCircle( Vector2D *pVector ) +{ + // Guarantee uniform random distribution within a sphere + // Graphics gems III contains this algorithm ("Nonuniform random point sets via warping") + float u = ((float)rand() / VALVE_RAND_MAX); + float v = ((float)rand() / VALVE_RAND_MAX); + + float flTheta = 2 * M_PI * v; + float flRadius = powf( u, 1.0f / 2.0f ); + + float flSinTheta, flCosTheta; + SinCos( flTheta, &flSinTheta, &flCosTheta ); + + pVector->x = flRadius * flCosTheta; + pVector->y = flRadius * flSinTheta; + return flRadius; +} +#ifdef FP_EXCEPTIONS_ENABLED +#include // For _clearfp and _controlfp_s +#endif + +// FPExceptionDisable and FPExceptionEnabler taken from my blog post +// at http://www.altdevblogaday.com/2012/04/20/exceptional-floating-point/ + +#ifdef FP_EXCEPTIONS_ENABLED +// These functions are all inlined NOPs if FP_EXCEPTIONS_ENABLED is not defined. +FPExceptionDisabler::FPExceptionDisabler() +{ + // Retrieve the current state of the exception flags. This + // must be done before changing them. _MCW_EM is a bit + // mask representing all available exception masks. + _controlfp_s(&mOldValues, 0, 0); + // Set all of the exception flags, which suppresses FP + // exceptions on the x87 and SSE units. + _controlfp_s(0, _MCW_EM, _MCW_EM); +} + +FPExceptionDisabler::~FPExceptionDisabler() +{ + // Clear any pending FP exceptions. This must be done + // prior to enabling FP exceptions since otherwise there + // may be a 'deferred crash' as soon the exceptions are + // enabled. + _clearfp(); + + // Reset (possibly enabling) the exception status. + _controlfp_s(0, mOldValues, _MCW_EM); +} + +// Overflow, divide-by-zero, and invalid-operation are the FP +// exceptions most frequently associated with bugs. +FPExceptionEnabler::FPExceptionEnabler(unsigned int enableBits /*= _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID*/) +{ + // Retrieve the current state of the exception flags. This + // must be done before changing them. _MCW_EM is a bit + // mask representing all available exception masks. + _controlfp_s(&mOldValues, 0, 0); + + // Make sure no non-exception flags have been specified, + // to avoid accidental changing of rounding modes, etc. + enableBits &= _MCW_EM; + + // Clear any pending FP exceptions. This must be done + // prior to enabling FP exceptions since otherwise there + // may be a 'deferred crash' as soon the exceptions are + // enabled. + _clearfp(); + + // Zero out the specified bits, leaving other bits alone. + _controlfp_s(0, ~enableBits, enableBits); +} + +FPExceptionEnabler::~FPExceptionEnabler() +{ + // Reset the exception state. + _controlfp_s(0, mOldValues, _MCW_EM); +} +#endif diff --git a/mathlib/noisedata.h b/mathlib/noisedata.h new file mode 100644 index 0000000..87da902 --- /dev/null +++ b/mathlib/noisedata.h @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: static data for noise() primitives. +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +// +// **** DO NOT EDIT THIS FILE. GENERATED BY DATAGEN.PL **** +// + +static int perm_a[]={ + 66,147,106,213,89,115,239,25,171,175,9,114,141,226,118,128,41,208,4,56, + 180,248,43,82,246,219,94,245,133,131,222,103,160,130,168,145,238,38,23,6, + 236,67,99,2,70,232,80,209,1,3,68,65,102,210,13,73,55,252,187,170,22,36, + 52,181,117,163,46,79,166,224,148,75,113,95,156,185,220,164,51,142,161,35, + 206,251,45,136,197,190,132,32,218,127,63,27,137,93,242,20,189,108,183, + 122,139,191,249,253,87,98,69,0,144,64,24,214,97,116,158,42,107,15,53,212, + 83,111,152,240,74,237,62,77,205,149,26,151,178,204,91,176,234,49,154,203, + 33,221,125,134,165,124,86,39,37,60,150,157,179,109,110,44,159,153,5,100, + 10,207,40,186,96,215,143,162,230,184,101,54,174,247,76,59,241,223,192,84, + 104,78,169,146,138,30,48,85,233,19,29,92,126,17,199,250,31,81,188,225,28, + 112,88,11,182,173,211,129,194,172,14,120,200,167,135,12,177,227,229,155, + 201,61,105,195,193,244,235,58,8,196,123,254,16,18,50,121,71,243,90,57, + 202,119,255,47,7,198,228,21,217,216,231,140,72,34 +}; + +static int perm_b[]={ + 123,108,201,64,40,75,24,221,137,110,191,142,9,69,230,83,7,247,51,54,115, + 133,180,248,109,116,62,99,251,55,89,253,65,106,228,167,131,132,58,143, + 97,102,163,202,149,234,12,117,174,94,121,74,32,113,20,60,159,182,204,29, + 244,118,3,178,255,38,6,114,36,93,30,134,213,90,245,209,88,232,162,125, + 84,166,70,136,208,231,27,71,157,80,76,0,170,225,203,176,33,161,196,128, + 252,236,246,2,138,1,250,197,77,243,218,242,19,164,68,212,14,237,144,63, + 46,103,177,188,85,223,8,160,222,4,216,219,35,15,44,23,126,127,100,226, + 235,37,168,101,49,22,11,73,61,135,111,183,72,96,185,239,82,18,50,155, + 186,153,17,233,146,156,107,5,254,10,192,198,148,207,104,13,124,48,95, + 129,120,206,199,81,249,91,150,210,119,240,122,194,92,34,28,205,175,227, + 179,220,140,152,79,26,195,47,66,173,169,241,53,184,187,145,112,238,214, + 147,98,171,229,200,151,25,67,78,189,217,130,224,57,172,59,41,43,16,105, + 158,165,21,45,56,141,139,215,190,86,42,52,39,87,181,31,154,193,211 +}; + +static int perm_c[]={ + 97,65,96,25,122,26,219,85,148,251,102,0,140,130,136,213,138,60,236,52, + 178,131,115,183,144,78,147,168,39,45,169,70,57,146,67,142,252,216,28,54, + 86,222,194,200,48,5,205,125,214,56,181,255,196,155,37,218,153,208,66, + 242,73,248,206,61,62,246,177,2,197,107,162,152,89,41,6,160,94,8,201,38, + 235,228,165,93,111,239,74,231,121,47,166,221,157,64,77,244,29,105,150, + 123,190,191,225,118,133,42,10,84,185,159,124,132,240,180,44,1,9,19,99, + 254,12,207,186,71,234,184,11,20,16,193,139,175,98,59,113,27,170,230,91, + 187,46,156,249,108,195,171,114,14,188,82,192,233,24,32,241,87,164,90,43, + 163,245,92,40,215,55,226,15,3,112,158,250,172,22,227,137,35,128,145,247, + 161,119,80,217,189,81,7,63,202,120,223,83,179,4,106,199,229,95,53,50,33, + 182,72,143,23,243,75,18,173,141,167,198,204,58,174,237,17,129,238,127, + 31,101,176,36,30,110,209,34,203,135,232,68,149,49,134,126,212,79,76,117, + 104,210,211,224,253,100,220,109,116,88,13,151,154,69,21,51,103 +}; + +static int perm_d[]={ + 94,234,145,235,151,166,187,238,4,5,128,115,87,107,229,175,190,108,218, + 32,17,220,97,90,122,121,71,109,64,227,225,75,81,19,27,162,3,89,139,69, + 92,26,48,215,116,191,114,2,104,157,66,39,1,127,96,124,30,0,82,233,219, + 42,131,173,35,201,182,144,14,98,148,244,160,159,179,91,31,68,119,154, + 205,113,149,167,44,60,18,228,251,245,43,10,80,15,129,67,181,174,6,45, + 194,237,213,52,99,232,211,212,164,217,57,153,156,102,134,20,249,132,55, + 204,65,33,231,85,61,37,163,193,189,170,226,63,168,236,165,224,242,195, + 41,200,40,70,112,100,36,172,130,74,137,252,243,135,230,161,207,16,146, + 198,118,150,24,29,250,188,25,209,103,23,105,47,7,46,133,83,184,50,79, + 110,120,53,253,206,214,9,240,101,147,152,183,254,59,126,216,197,171,51, + 208,248,202,58,176,28,72,177,185,141,12,11,56,222,86,178,155,223,88,111, + 73,142,210,138,239,221,199,192,84,93,241,125,76,77,255,95,8,78,247,186, + 123,196,13,140,180,143,54,106,136,34,62,169,38,117,22,21,49,203,158,246 +}; + +static float impulse_xcoords[]={ + 0.788235f,0.541176f,0.972549f,0.082353f,0.352941f,0.811765f,0.286275f,0.752941f, + 0.203922f,0.705882f,0.537255f,0.886275f,0.580392f,0.137255f,0.800000f,0.533333f, + 0.117647f,0.447059f,0.129412f,0.925490f,0.086275f,0.478431f,0.666667f,0.568627f, + 0.678431f,0.313725f,0.321569f,0.349020f,0.988235f,0.419608f,0.898039f,0.219608f, + 0.243137f,0.623529f,0.501961f,0.772549f,0.952941f,0.517647f,0.949020f,0.701961f, + 0.454902f,0.505882f,0.564706f,0.960784f,0.207843f,0.007843f,0.831373f,0.184314f, + 0.576471f,0.462745f,0.572549f,0.247059f,0.262745f,0.694118f,0.615686f,0.121569f, + 0.384314f,0.749020f,0.145098f,0.717647f,0.415686f,0.607843f,0.105882f,0.101961f, + 0.200000f,0.807843f,0.521569f,0.780392f,0.466667f,0.552941f,0.996078f,0.627451f, + 0.992157f,0.529412f,0.407843f,0.011765f,0.709804f,0.458824f,0.058824f,0.819608f, + 0.176471f,0.317647f,0.392157f,0.223529f,0.156863f,0.490196f,0.325490f,0.074510f, + 0.239216f,0.164706f,0.890196f,0.603922f,0.921569f,0.839216f,0.854902f,0.098039f, + 0.686275f,0.843137f,0.152941f,0.372549f,0.062745f,0.474510f,0.486275f,0.227451f, + 0.400000f,0.298039f,0.309804f,0.274510f,0.054902f,0.815686f,0.647059f,0.635294f, + 0.662745f,0.976471f,0.094118f,0.509804f,0.650980f,0.211765f,0.180392f,0.003922f, + 0.827451f,0.278431f,0.023529f,0.525490f,0.450980f,0.725490f,0.690196f,0.941176f, + 0.639216f,0.560784f,0.196078f,0.364706f,0.043137f,0.494118f,0.796078f,0.113725f, + 0.760784f,0.729412f,0.258824f,0.290196f,0.584314f,0.674510f,0.823529f,0.905882f, + 0.917647f,0.070588f,0.862745f,0.345098f,0.913725f,0.937255f,0.031373f,0.215686f, + 0.768627f,0.333333f,0.411765f,0.423529f,0.945098f,0.721569f,0.039216f,0.792157f, + 0.956863f,0.266667f,0.254902f,0.047059f,0.294118f,0.658824f,0.250980f,1.000000f, + 0.984314f,0.756863f,0.027451f,0.305882f,0.835294f,0.513725f,0.360784f,0.776471f, + 0.611765f,0.192157f,0.866667f,0.858824f,0.592157f,0.803922f,0.141176f,0.435294f, + 0.588235f,0.619608f,0.341176f,0.109804f,0.356863f,0.270588f,0.737255f,0.847059f, + 0.050980f,0.764706f,0.019608f,0.870588f,0.933333f,0.784314f,0.549020f,0.337255f, + 0.631373f,0.929412f,0.231373f,0.427451f,0.078431f,0.498039f,0.968627f,0.654902f, + 0.125490f,0.698039f,0.015686f,0.878431f,0.713725f,0.368627f,0.431373f,0.874510f, + 0.403922f,0.556863f,0.443137f,0.964706f,0.909804f,0.301961f,0.035294f,0.850980f, + 0.882353f,0.741176f,0.380392f,0.133333f,0.470588f,0.643137f,0.282353f,0.396078f, + 0.980392f,0.168627f,0.149020f,0.235294f,0.670588f,0.596078f,0.733333f,0.160784f, + 0.376471f,0.682353f,0.545098f,0.482353f,0.745098f,0.894118f,0.188235f,0.329412f, + 0.439216f,0.901961f,0.000000f,0.600000f,0.388235f,0.172549f,0.090196f,0.066667f +}; + +static float impulse_ycoords[]={ + 0.827451f,0.337255f,0.941176f,0.886275f,0.878431f,0.239216f,0.400000f,0.164706f, + 0.490196f,0.411765f,0.964706f,0.349020f,0.803922f,0.317647f,0.647059f,0.431373f, + 0.933333f,0.156863f,0.094118f,0.219608f,0.039216f,0.521569f,0.498039f,0.705882f, + 0.717647f,0.047059f,0.631373f,0.517647f,0.984314f,0.847059f,0.482353f,0.439216f, + 0.250980f,0.862745f,0.690196f,0.913725f,0.270588f,0.070588f,0.027451f,0.694118f, + 0.811765f,0.000000f,0.494118f,0.823529f,0.800000f,0.600000f,0.003922f,0.443137f, + 0.639216f,0.376471f,0.031373f,0.035294f,0.552941f,0.215686f,0.305882f,0.133333f, + 0.564706f,0.176471f,0.211765f,0.874510f,0.360784f,0.654902f,0.223529f,0.807843f, + 0.372549f,0.137255f,0.321569f,0.015686f,0.007843f,0.262745f,0.125490f,0.078431f, + 0.396078f,0.976471f,0.929412f,1.000000f,0.937255f,0.509804f,0.188235f,0.850980f, + 0.831373f,0.392157f,0.741176f,0.541176f,0.592157f,0.286275f,0.345098f,0.572549f, + 0.537255f,0.725490f,0.839216f,0.184314f,0.772549f,0.149020f,0.505882f,0.423529f, + 0.780392f,0.011765f,0.890196f,0.086275f,0.427451f,0.023529f,0.788235f,0.050980f, + 0.760784f,0.603922f,0.066667f,0.643137f,0.623529f,0.960784f,0.172549f,0.333333f, + 0.082353f,0.290196f,0.992157f,0.709804f,0.894118f,0.596078f,0.243137f,0.752941f, + 0.486275f,0.670588f,0.949020f,0.784314f,0.145098f,0.560784f,0.513725f,0.180392f, + 0.580392f,0.996078f,0.380392f,0.556863f,0.407843f,0.945098f,0.117647f,0.058824f, + 0.678431f,0.129412f,0.192157f,0.105882f,0.968627f,0.545098f,0.462745f,0.227451f, + 0.019608f,0.866667f,0.674510f,0.207843f,0.627451f,0.819608f,0.921569f,0.356863f, + 0.447059f,0.533333f,0.435294f,0.341176f,0.054902f,0.529412f,0.235294f,0.764706f, + 0.615686f,0.043137f,0.745098f,0.266667f,0.501961f,0.619608f,0.776471f,0.450980f, + 0.309804f,0.325490f,0.200000f,0.635294f,0.247059f,0.698039f,0.721569f,0.168627f, + 0.854902f,0.141176f,0.611765f,0.525490f,0.415686f,0.298039f,0.254902f,0.858824f, + 0.568627f,0.329412f,0.062745f,0.843137f,0.588235f,0.733333f,0.607843f,0.478431f, + 0.576471f,0.662745f,0.470588f,0.666667f,0.980392f,0.113725f,0.898039f,0.203922f, + 0.294118f,0.152941f,0.098039f,0.909804f,0.796078f,0.768627f,0.713725f,0.196078f, + 0.368627f,0.419608f,0.352941f,0.090196f,0.749020f,0.121569f,0.882353f,0.278431f, + 0.388235f,0.917647f,0.701961f,0.729412f,0.835294f,0.258824f,0.301961f,0.101961f, + 0.792157f,0.474510f,0.686275f,0.658824f,0.364706f,0.682353f,0.458824f,0.815686f, + 0.282353f,0.160784f,0.870588f,0.988235f,0.756863f,0.549020f,0.274510f,0.384314f, + 0.650980f,0.737255f,0.901961f,0.956863f,0.972549f,0.584314f,0.925490f,0.403922f, + 0.074510f,0.454902f,0.952941f,0.109804f,0.313725f,0.905882f,0.231373f,0.466667f +}; + +static float impulse_zcoords[]={ + 0.082353f,0.643137f,0.415686f,0.929412f,0.568627f,0.509804f,0.537255f,0.815686f, + 0.698039f,0.941176f,0.776471f,0.752941f,0.737255f,0.525490f,0.498039f,0.423529f, + 0.792157f,0.125490f,0.619608f,0.164706f,0.368627f,0.870588f,0.137255f,0.372549f, + 0.466667f,0.486275f,0.501961f,0.513725f,0.709804f,0.576471f,0.203922f,0.258824f, + 0.152941f,0.556863f,0.223529f,0.047059f,0.235294f,0.474510f,0.764706f,0.552941f, + 0.847059f,0.145098f,0.176471f,0.937255f,0.654902f,0.894118f,0.729412f,0.054902f, + 0.666667f,0.749020f,0.262745f,0.560784f,0.431373f,0.286275f,0.352941f,0.239216f, + 0.156863f,0.839216f,0.427451f,0.949020f,0.384314f,0.227451f,0.180392f,0.074510f, + 0.172549f,0.356863f,0.066667f,0.517647f,0.447059f,0.184314f,0.062745f,0.670588f, + 0.603922f,0.219608f,0.270588f,0.976471f,0.505882f,0.627451f,0.819608f,0.854902f, + 0.843137f,0.019608f,0.713725f,0.035294f,0.925490f,0.349020f,0.866667f,0.701961f, + 0.909804f,0.811765f,0.717647f,0.141176f,0.917647f,0.023529f,0.098039f,0.803922f, + 0.733333f,0.658824f,0.827451f,0.133333f,0.858824f,0.800000f,0.635294f,1.000000f, + 0.078431f,0.450980f,0.835294f,0.321569f,0.360784f,0.529412f,0.725490f,0.572549f, + 0.639216f,0.341176f,0.533333f,0.094118f,0.149020f,0.545098f,0.101961f,0.901961f, + 0.278431f,0.694118f,0.521569f,0.490196f,0.454902f,0.329412f,0.274510f,0.027451f, + 0.745098f,0.933333f,0.443137f,0.168627f,0.192157f,0.988235f,0.070588f,0.972549f, + 0.768627f,0.400000f,0.470588f,0.207843f,0.215686f,0.388235f,0.439216f,0.780392f, + 0.482353f,0.121569f,0.964706f,0.086275f,0.890196f,0.337255f,0.109804f,0.305882f, + 0.113725f,0.435294f,0.721569f,0.772549f,0.807843f,0.741176f,0.254902f,0.596078f, + 0.494118f,0.317647f,0.419608f,0.000000f,0.188235f,0.031373f,0.376471f,0.380392f, + 0.611765f,0.945098f,0.411765f,0.313725f,0.874510f,0.588235f,0.678431f,0.160784f, + 0.007843f,0.090196f,0.850980f,0.788235f,0.705882f,0.266667f,0.309804f,0.541176f, + 0.231373f,0.129412f,0.294118f,0.243137f,0.913725f,0.996078f,0.117647f,0.478431f, + 0.290196f,0.549020f,0.682353f,0.784314f,0.396078f,0.831373f,0.984314f,0.584314f, + 0.039216f,0.250980f,0.600000f,0.392157f,0.298039f,0.050980f,0.364706f,0.105882f, + 0.623529f,0.886275f,0.980392f,0.325490f,0.247059f,0.690196f,0.674510f,0.960784f, + 0.647059f,0.211765f,0.882353f,0.686275f,0.823529f,0.058824f,0.956863f,0.043137f, + 0.345098f,0.301961f,0.592157f,0.862745f,0.607843f,0.458824f,0.282353f,0.003922f, + 0.580392f,0.760784f,0.564706f,0.011765f,0.968627f,0.905882f,0.756863f,0.952941f, + 0.662745f,0.015686f,0.898039f,0.196078f,0.333333f,0.992157f,0.650980f,0.407843f, + 0.796078f,0.615686f,0.878431f,0.921569f,0.631373f,0.200000f,0.403922f,0.462745f +}; + diff --git a/mathlib/polyhedron.cpp b/mathlib/polyhedron.cpp new file mode 100644 index 0000000..5a858f1 --- /dev/null +++ b/mathlib/polyhedron.cpp @@ -0,0 +1,2293 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "mathlib/polyhedron.h" +#include "mathlib/vmatrix.h" +#include +#include +#include "tier1/utlvector.h" + + + +struct GeneratePolyhedronFromPlanes_Point; +struct GeneratePolyhedronFromPlanes_PointLL; +struct GeneratePolyhedronFromPlanes_Line; +struct GeneratePolyhedronFromPlanes_LineLL; +struct GeneratePolyhedronFromPlanes_Polygon; +struct GeneratePolyhedronFromPlanes_PolygonLL; + +struct GeneratePolyhedronFromPlanes_UnorderedPointLL; +struct GeneratePolyhedronFromPlanes_UnorderedLineLL; +struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL; + +Vector FindPointInPlanes( const float *pPlanes, int planeCount ); +bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ); +CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ); +CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory ); + +//#define ENABLE_DEBUG_POLYHEDRON_DUMPS //Dumps debug information to disk for use with glview. Requires that tier2 also be in all projects using debug mathlib +//#define DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS //dumps successfully generated polyhedrons + +#ifdef _DEBUG +void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform ); +void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform ); +void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile ); +void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile ); + +#if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( WIN32 ) +#include "winlite.h" +#endif + +static VMatrix s_matIdentity( 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); +#endif + +#if defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS ) +static int g_iPolyhedronDumpCounter = 0; +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) +void CreateDumpDirectory( const char *szDirectoryName ) +{ +#if defined( WIN32 ) + CreateDirectory( szDirectoryName, NULL ); +#else + Assert( false ); //TODO: create directories in linux +#endif +} +#endif + + + +void CPolyhedron_AllocByNew::Release( void ) +{ + delete this; +} + +CPolyhedron_AllocByNew *CPolyhedron_AllocByNew::Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //creates the polyhedron along with enough memory to hold all it's data in a single allocation +{ + void *pMemory = new unsigned char [ sizeof( CPolyhedron_AllocByNew ) + + (iVertices * sizeof(Vector)) + + (iLines * sizeof(Polyhedron_IndexedLine_t)) + + (iIndices * sizeof( Polyhedron_IndexedLineReference_t )) + + (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))]; + +#include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging + CPolyhedron_AllocByNew *pAllocated = new ( pMemory ) CPolyhedron_AllocByNew; +#include "tier0/memdbgon.h" + + pAllocated->iVertexCount = iVertices; + pAllocated->iLineCount = iLines; + pAllocated->iIndexCount = iIndices; + pAllocated->iPolygonCount = iPolygons; + pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class + pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices); + pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines); + pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices); + + return pAllocated; +} + + +class CPolyhedron_TempMemory : public CPolyhedron +{ +public: +#ifdef DBGFLAG_ASSERT + int iReferenceCount; +#endif + + virtual void Release( void ) + { +#ifdef DBGFLAG_ASSERT + --iReferenceCount; +#endif + } + + CPolyhedron_TempMemory( void ) +#ifdef DBGFLAG_ASSERT + : iReferenceCount( 0 ) +#endif + { }; +}; + + +static CUtlVector s_TempMemoryPolyhedron_Buffer; +static CPolyhedron_TempMemory s_TempMemoryPolyhedron; + +CPolyhedron *GetTempPolyhedron( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //grab the temporary polyhedron. Avoids new/delete for quick work. Can only be in use by one chunk of code at a time +{ + AssertMsg( s_TempMemoryPolyhedron.iReferenceCount == 0, "Temporary polyhedron memory being rewritten before released" ); +#ifdef DBGFLAG_ASSERT + ++s_TempMemoryPolyhedron.iReferenceCount; +#endif + s_TempMemoryPolyhedron_Buffer.SetCount( (sizeof( Vector ) * iVertices) + + (sizeof( Polyhedron_IndexedLine_t ) * iLines) + + (sizeof( Polyhedron_IndexedLineReference_t ) * iIndices) + + (sizeof( Polyhedron_IndexedPolygon_t ) * iPolygons) ); + + s_TempMemoryPolyhedron.iVertexCount = iVertices; + s_TempMemoryPolyhedron.iLineCount = iLines; + s_TempMemoryPolyhedron.iIndexCount = iIndices; + s_TempMemoryPolyhedron.iPolygonCount = iPolygons; + + s_TempMemoryPolyhedron.pVertices = (Vector *)s_TempMemoryPolyhedron_Buffer.Base(); + s_TempMemoryPolyhedron.pLines = (Polyhedron_IndexedLine_t *)(&s_TempMemoryPolyhedron.pVertices[s_TempMemoryPolyhedron.iVertexCount]); + s_TempMemoryPolyhedron.pIndices = (Polyhedron_IndexedLineReference_t *)(&s_TempMemoryPolyhedron.pLines[s_TempMemoryPolyhedron.iLineCount]); + s_TempMemoryPolyhedron.pPolygons = (Polyhedron_IndexedPolygon_t *)(&s_TempMemoryPolyhedron.pIndices[s_TempMemoryPolyhedron.iIndexCount]); + + return &s_TempMemoryPolyhedron; +} + + +Vector CPolyhedron::Center( void ) +{ + if( iVertexCount == 0 ) + return vec3_origin; + + Vector vAABBMin, vAABBMax; + vAABBMin = vAABBMax = pVertices[0]; + for( int i = 1; i != iVertexCount; ++i ) + { + Vector &vPoint = pVertices[i]; + if( vPoint.x < vAABBMin.x ) + vAABBMin.x = vPoint.x; + if( vPoint.y < vAABBMin.y ) + vAABBMin.y = vPoint.y; + if( vPoint.z < vAABBMin.z ) + vAABBMin.z = vPoint.z; + + if( vPoint.x > vAABBMax.x ) + vAABBMax.x = vPoint.x; + if( vPoint.y > vAABBMax.y ) + vAABBMax.y = vPoint.y; + if( vPoint.z > vAABBMax.z ) + vAABBMax.z = vPoint.z; + } + return ((vAABBMin + vAABBMax) * 0.5f); +} + +enum PolyhedronPointPlanarity +{ + POINT_DEAD, + POINT_ONPLANE, + POINT_ALIVE +}; + +struct GeneratePolyhedronFromPlanes_Point +{ + Vector ptPosition; + GeneratePolyhedronFromPlanes_LineLL *pConnectedLines; //keep these in a clockwise order, circular linking + float fPlaneDist; //used in plane cutting + PolyhedronPointPlanarity planarity; + int iSaveIndices; +}; + +struct GeneratePolyhedronFromPlanes_Line +{ + GeneratePolyhedronFromPlanes_Point *pPoints[2]; //the 2 connecting points in no particular order + GeneratePolyhedronFromPlanes_Polygon *pPolygons[2]; //viewing from the outside with the point connections going up, 0 is the left polygon, 1 is the right + int iSaveIndices; + bool bAlive; //connected to at least one living point + bool bCut; //connected to at least one dead point + + GeneratePolyhedronFromPlanes_LineLL *pPointLineLinks[2]; //rather than going into a point and searching for its link to this line, lets just cache it to eliminate searching + GeneratePolyhedronFromPlanes_LineLL *pPolygonLineLinks[2]; //rather than going into a polygon and searching for its link to this line, lets just cache it to eliminate searching +#ifdef POLYHEDRON_EXTENSIVE_DEBUGGING + int iDebugFlags; +#endif +}; + +struct GeneratePolyhedronFromPlanes_LineLL +{ + GeneratePolyhedronFromPlanes_Line *pLine; + int iReferenceIndex; //whatever is referencing the line should know which side of the line it's on (points and polygons), for polygons, it's which point to follow to continue going clockwise, which makes polygon 0 the one on the left side of an upward facing line vector, for points, it's the OTHER point's index + GeneratePolyhedronFromPlanes_LineLL *pPrev; + GeneratePolyhedronFromPlanes_LineLL *pNext; +}; + +struct GeneratePolyhedronFromPlanes_Polygon +{ + Vector vSurfaceNormal; + GeneratePolyhedronFromPlanes_LineLL *pLines; //keep these in a clockwise order, circular linking + + bool bMissingASide; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL //an unordered collection of polygons +{ + GeneratePolyhedronFromPlanes_Polygon *pPolygon; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPrev; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedLineLL //an unordered collection of lines +{ + GeneratePolyhedronFromPlanes_Line *pLine; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pPrev; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedPointLL //an unordered collection of points +{ + GeneratePolyhedronFromPlanes_Point *pPoint; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pPrev; +}; + + + + +CPolyhedron *ClipPolyhedron( const CPolyhedron *pExistingPolyhedron, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + if( pExistingPolyhedron == NULL ) + return NULL; + + AssertMsg( (pExistingPolyhedron->iVertexCount >= 3) && (pExistingPolyhedron->iPolygonCount >= 2), "Polyhedron doesn't meet absolute minimum spec" ); + + float *pUsefulPlanes = (float *)stackalloc( sizeof( float ) * 4 * iPlaneCount ); + int iUsefulPlaneCount = 0; + Vector *pExistingVertices = pExistingPolyhedron->pVertices; + + //A large part of clipping will either eliminate the polyhedron entirely, or clip nothing at all, so lets just check for those first and throw away useless planes + { + int iLiveCount = 0; + int iDeadCount = 0; + const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon; + + for( int i = 0; i != iPlaneCount; ++i ) + { + Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(i * 4) + 0]); + float fPlaneDist = pOutwardFacingPlanes[(i * 4) + 3]; + + for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j ) + { + float fPointDist = vNormal.Dot( pExistingVertices[j] ) - fPlaneDist; + + if( fPointDist <= fNegativeOnPlaneEpsilon ) + ++iLiveCount; + else if( fPointDist > fOnPlaneEpsilon ) + ++iDeadCount; + } + + if( iLiveCount == 0 ) + { + //all points are dead or on the plane, so the polyhedron is dead + return NULL; + } + + if( iDeadCount != 0 ) + { + //at least one point died, this plane yields useful results + pUsefulPlanes[(iUsefulPlaneCount * 4) + 0] = vNormal.x; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 1] = vNormal.y; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 2] = vNormal.z; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 3] = fPlaneDist; + ++iUsefulPlaneCount; + } + } + } + + if( iUsefulPlaneCount == 0 ) + { + //testing shows that the polyhedron won't even be cut, clone the existing polyhedron and return that + + CPolyhedron *pReturn; + if( bUseTemporaryMemory ) + { + pReturn = GetTempPolyhedron( pExistingPolyhedron->iVertexCount, + pExistingPolyhedron->iLineCount, + pExistingPolyhedron->iIndexCount, + pExistingPolyhedron->iPolygonCount ); + } + else + { + pReturn = CPolyhedron_AllocByNew::Allocate( pExistingPolyhedron->iVertexCount, + pExistingPolyhedron->iLineCount, + pExistingPolyhedron->iIndexCount, + pExistingPolyhedron->iPolygonCount ); + } + + memcpy( pReturn->pVertices, pExistingPolyhedron->pVertices, sizeof( Vector ) * pReturn->iVertexCount ); + memcpy( pReturn->pLines, pExistingPolyhedron->pLines, sizeof( Polyhedron_IndexedLine_t ) * pReturn->iLineCount ); + memcpy( pReturn->pIndices, pExistingPolyhedron->pIndices, sizeof( Polyhedron_IndexedLineReference_t ) * pReturn->iIndexCount ); + memcpy( pReturn->pPolygons, pExistingPolyhedron->pPolygons, sizeof( Polyhedron_IndexedPolygon_t ) * pReturn->iPolygonCount ); + + return pReturn; + } + + + + //convert the polyhedron to linked geometry + GeneratePolyhedronFromPlanes_Point *pStartPoints = (GeneratePolyhedronFromPlanes_Point *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_Point ) ); + GeneratePolyhedronFromPlanes_Line *pStartLines = (GeneratePolyhedronFromPlanes_Line *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_Line ) ); + GeneratePolyhedronFromPlanes_Polygon *pStartPolygons = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_Polygon ) ); + + GeneratePolyhedronFromPlanes_LineLL *pStartLineLinks = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( pExistingPolyhedron->iLineCount * 4 * sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + int iCurrentLineLinkIndex = 0; + + //setup points + for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i ) + { + pStartPoints[i].ptPosition = pExistingPolyhedron->pVertices[i]; + pStartPoints[i].pConnectedLines = NULL; //we won't be circular linking until later + } + + //setup lines and interlink to points (line links are not yet circularly linked, and are unordered) + for( int i = 0; i != pExistingPolyhedron->iLineCount; ++i ) + { + for( int j = 0; j != 2; ++j ) + { + pStartLines[i].pPoints[j] = &pStartPoints[pExistingPolyhedron->pLines[i].iPointIndices[j]]; + + GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++]; + pStartLines[i].pPointLineLinks[j] = pLineLink; + pLineLink->pLine = &pStartLines[i]; + pLineLink->iReferenceIndex = 1 - j; + //pLineLink->pPrev = NULL; + pLineLink->pNext = pStartLines[i].pPoints[j]->pConnectedLines; + pStartLines[i].pPoints[j]->pConnectedLines = pLineLink; + } + } + + + + //setup polygons + for( int i = 0; i != pExistingPolyhedron->iPolygonCount; ++i ) + { + pStartPolygons[i].vSurfaceNormal = pExistingPolyhedron->pPolygons[i].polyNormal; + Polyhedron_IndexedLineReference_t *pOffsetPolyhedronLines = &pExistingPolyhedron->pIndices[pExistingPolyhedron->pPolygons[i].iFirstIndex]; + + + GeneratePolyhedronFromPlanes_LineLL *pFirstLink = &pStartLineLinks[iCurrentLineLinkIndex]; + pStartPolygons[i].pLines = pFirstLink; //technically going to link to itself on first pass, then get linked properly immediately afterward + for( int j = 0; j != pExistingPolyhedron->pPolygons[i].iIndexCount; ++j ) + { + GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++]; + pLineLink->pLine = &pStartLines[pOffsetPolyhedronLines[j].iLineIndex]; + pLineLink->iReferenceIndex = pOffsetPolyhedronLines[j].iEndPointIndex; + + pLineLink->pLine->pPolygons[pLineLink->iReferenceIndex] = &pStartPolygons[i]; + pLineLink->pLine->pPolygonLineLinks[pLineLink->iReferenceIndex] = pLineLink; + + pLineLink->pPrev = pStartPolygons[i].pLines; + pStartPolygons[i].pLines->pNext = pLineLink; + pStartPolygons[i].pLines = pLineLink; + } + + pFirstLink->pPrev = pStartPolygons[i].pLines; + pStartPolygons[i].pLines->pNext = pFirstLink; + } + + Assert( iCurrentLineLinkIndex == (pExistingPolyhedron->iLineCount * 4) ); + + //go back to point line links so we can circularly link them as well as order them now that every point has all its line links + for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i ) + { + //interlink the points + { + GeneratePolyhedronFromPlanes_LineLL *pLastVisitedLink = pStartPoints[i].pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pCurrentLink = pLastVisitedLink; + + do + { + pCurrentLink->pPrev = pLastVisitedLink; + pLastVisitedLink = pCurrentLink; + pCurrentLink = pCurrentLink->pNext; + } while( pCurrentLink ); + + //circular link + pLastVisitedLink->pNext = pStartPoints[i].pConnectedLines; + pStartPoints[i].pConnectedLines->pPrev = pLastVisitedLink; + } + + + //fix ordering + GeneratePolyhedronFromPlanes_LineLL *pFirstLink = pStartPoints[i].pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pFirstLink; + GeneratePolyhedronFromPlanes_LineLL *pSearchLink; + GeneratePolyhedronFromPlanes_Polygon *pLookingForPolygon; + Assert( pFirstLink->pNext != pFirstLink ); + do + { + pLookingForPolygon = pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex]; //grab pointer to left polygon + pSearchLink = pWorkLink->pPrev; + + while( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] != pLookingForPolygon ) + pSearchLink = pSearchLink->pPrev; + + Assert( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] == pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex] ); + + //pluck the search link from wherever it is + pSearchLink->pPrev->pNext = pSearchLink->pNext; + pSearchLink->pNext->pPrev = pSearchLink->pPrev; + + //insert the search link just before the work link + pSearchLink->pPrev = pWorkLink->pPrev; + pSearchLink->pNext = pWorkLink; + + pSearchLink->pPrev->pNext = pSearchLink; + pWorkLink->pPrev = pSearchLink; + + pWorkLink = pSearchLink; + } while( pWorkLink != pFirstLink ); + } + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) ); + GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) ); + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) ); + + //setup point collection + { + pPoints[0].pPrev = NULL; + pPoints[0].pPoint = &pStartPoints[0]; + pPoints[0].pNext = &pPoints[1]; + int iLastPoint = pExistingPolyhedron->iVertexCount - 1; + for( int i = 1; i != iLastPoint; ++i ) + { + pPoints[i].pPrev = &pPoints[i - 1]; + pPoints[i].pPoint = &pStartPoints[i]; + pPoints[i].pNext = &pPoints[i + 1]; + } + pPoints[iLastPoint].pPrev = &pPoints[iLastPoint - 1]; + pPoints[iLastPoint].pPoint = &pStartPoints[iLastPoint]; + pPoints[iLastPoint].pNext = NULL; + } + + //setup line collection + { + pLines[0].pPrev = NULL; + pLines[0].pLine = &pStartLines[0]; + pLines[0].pNext = &pLines[1]; + int iLastLine = pExistingPolyhedron->iLineCount - 1; + for( int i = 1; i != iLastLine; ++i ) + { + pLines[i].pPrev = &pLines[i - 1]; + pLines[i].pLine = &pStartLines[i]; + pLines[i].pNext = &pLines[i + 1]; + } + pLines[iLastLine].pPrev = &pLines[iLastLine - 1]; + pLines[iLastLine].pLine = &pStartLines[iLastLine]; + pLines[iLastLine].pNext = NULL; + } + + //setup polygon collection + { + pPolygons[0].pPrev = NULL; + pPolygons[0].pPolygon = &pStartPolygons[0]; + pPolygons[0].pNext = &pPolygons[1]; + int iLastPolygon = pExistingPolyhedron->iPolygonCount - 1; + for( int i = 1; i != iLastPolygon; ++i ) + { + pPolygons[i].pPrev = &pPolygons[i - 1]; + pPolygons[i].pPolygon = &pStartPolygons[i]; + pPolygons[i].pNext = &pPolygons[i + 1]; + } + pPolygons[iLastPolygon].pPrev = &pPolygons[iLastPolygon - 1]; + pPolygons[iLastPolygon].pPolygon = &pStartPolygons[iLastPolygon]; + pPolygons[iLastPolygon].pNext = NULL; + } + + return ClipLinkedGeometry( pPolygons, pLines, pPoints, pUsefulPlanes, iUsefulPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory ); +} + + + +Vector FindPointInPlanes( const float *pPlanes, int planeCount ) +{ + Vector point = vec3_origin; + + for ( int i = 0; i < planeCount; i++ ) + { + float fD = DotProduct( *(Vector *)&pPlanes[i*4], point ) - pPlanes[i*4 + 3]; + if ( fD < 0 ) + { + point -= fD * (*(Vector *)&pPlanes[i*4]); + } + } + return point; +} + + + +bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ) //bounding box of the convex shape (subject to floating point error) +{ + //returns false if the AABB hasn't been set + if( pAABBMins == NULL && pAABBMaxs == NULL ) //no use in actually finding out what it is + return false; + + struct FindConvexShapeAABB_Polygon_t + { + float *verts; + int iVertCount; + }; + + float *pMovedPlanes = (float *)stackalloc( iPlaneCount * 4 * sizeof( float ) ); + //Vector vPointInPlanes = FindPointInPlanes( pInwardFacingPlanes, iPlaneCount ); + + for( int i = 0; i != iPlaneCount; ++i ) + { + pMovedPlanes[(i * 4) + 0] = pInwardFacingPlanes[(i * 4) + 0]; + pMovedPlanes[(i * 4) + 1] = pInwardFacingPlanes[(i * 4) + 1]; + pMovedPlanes[(i * 4) + 2] = pInwardFacingPlanes[(i * 4) + 2]; + pMovedPlanes[(i * 4) + 3] = pInwardFacingPlanes[(i * 4) + 3] - 100.0f; //move planes out a lot to kill some imprecision problems + } + + + + //vAABBMins = vAABBMaxs = FindPointInPlanes( pPlanes, iPlaneCount ); + float *vertsIn = NULL; //we'll be allocating a new buffer for this with each new polygon, and moving it off to the polygon array + float *vertsOut = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) ); //each plane will initially have 4 points in its polygon representation, and each plane clip has the possibility to add 1 point to the polygon + float *vertsSwap; + + FindConvexShapeAABB_Polygon_t *pPolygons = (FindConvexShapeAABB_Polygon_t *)stackalloc( iPlaneCount * sizeof( FindConvexShapeAABB_Polygon_t ) ); + int iPolyCount = 0; + + for ( int i = 0; i < iPlaneCount; i++ ) + { + Vector *pPlaneNormal = (Vector *)&pInwardFacingPlanes[i*4]; + float fPlaneDist = pInwardFacingPlanes[(i*4) + 3]; + + if( vertsIn == NULL ) + vertsIn = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) ); + + // Build a big-ass poly in this plane + int vertCount = PolyFromPlane( (Vector *)vertsIn, *pPlaneNormal, fPlaneDist, 100000.0f ); + + //chop it by every other plane + for( int j = 0; j < iPlaneCount; j++ ) + { + // don't clip planes with themselves + if ( i == j ) + continue; + + // Chop the polygon against this plane + vertCount = ClipPolyToPlane( (Vector *)vertsIn, vertCount, (Vector *)vertsOut, *(Vector *)&pMovedPlanes[j*4], pMovedPlanes[(j*4) + 3], 0.0f ); + + //swap the input and output arrays + vertsSwap = vertsIn; vertsIn = vertsOut; vertsOut = vertsSwap; + + // Less than a poly left, something's wrong, don't bother with this polygon + if ( vertCount < 3 ) + break; + } + + if ( vertCount < 3 ) + continue; //not enough to work with + + pPolygons[iPolyCount].iVertCount = vertCount; + pPolygons[iPolyCount].verts = vertsIn; + vertsIn = NULL; + ++iPolyCount; + } + + if( iPolyCount == 0 ) + return false; + + //initialize the AABB to the first point available + Vector vAABBMins, vAABBMaxs; + vAABBMins = vAABBMaxs = ((Vector *)pPolygons[0].verts)[0]; + + if( pAABBMins && pAABBMaxs ) //they want the full box + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x < vAABBMins.x ) + vAABBMins.x = PolyVerts[j].x; + if( PolyVerts[j].y < vAABBMins.y ) + vAABBMins.y = PolyVerts[j].y; + if( PolyVerts[j].z < vAABBMins.z ) + vAABBMins.z = PolyVerts[j].z; + + if( PolyVerts[j].x > vAABBMaxs.x ) + vAABBMaxs.x = PolyVerts[j].x; + if( PolyVerts[j].y > vAABBMaxs.y ) + vAABBMaxs.y = PolyVerts[j].y; + if( PolyVerts[j].z > vAABBMaxs.z ) + vAABBMaxs.z = PolyVerts[j].z; + } + } + *pAABBMins = vAABBMins; + *pAABBMaxs = vAABBMaxs; + } + else if( pAABBMins ) //they only want the min + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x < vAABBMins.x ) + vAABBMins.x = PolyVerts[j].x; + if( PolyVerts[j].y < vAABBMins.y ) + vAABBMins.y = PolyVerts[j].y; + if( PolyVerts[j].z < vAABBMins.z ) + vAABBMins.z = PolyVerts[j].z; + } + } + *pAABBMins = vAABBMins; + } + else //they only want the max + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x > vAABBMaxs.x ) + vAABBMaxs.x = PolyVerts[j].x; + if( PolyVerts[j].y > vAABBMaxs.y ) + vAABBMaxs.y = PolyVerts[j].y; + if( PolyVerts[j].z > vAABBMaxs.z ) + vAABBMaxs.z = PolyVerts[j].z; + } + } + *pAABBMaxs = vAABBMaxs; + } + + return true; +} + + + + + + + +CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory ) +{ + Assert( (pPolygons != NULL) && (pLines != NULL) && (pPoints != NULL) ); + unsigned int iPolyCount = 0, iLineCount = 0, iPointCount = 0, iIndexCount = 0; + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pPolygons; + do + { + ++iPolyCount; + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + Assert( pLineWalk != NULL ); + + do + { + ++iIndexCount; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } while( pActivePolygonWalk ); + + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pLines; + do + { + ++iLineCount; + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pPoints; + do + { + ++iPointCount; + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + + CPolyhedron *pReturn; + if( bUseTemporaryMemory ) + { + pReturn = GetTempPolyhedron( iPointCount, iLineCount, iIndexCount, iPolyCount ); + } + else + { + pReturn = CPolyhedron_AllocByNew::Allocate( iPointCount, iLineCount, iIndexCount, iPolyCount ); + } + + Vector *pVertexArray = pReturn->pVertices; + Polyhedron_IndexedLine_t *pLineArray = pReturn->pLines; + Polyhedron_IndexedLineReference_t *pIndexArray = pReturn->pIndices; + Polyhedron_IndexedPolygon_t *pPolyArray = pReturn->pPolygons; + + //copy points + pActivePointWalk = pPoints; + for( unsigned int i = 0; i != iPointCount; ++i ) + { + pVertexArray[i] = pActivePointWalk->pPoint->ptPosition; + pActivePointWalk->pPoint->iSaveIndices = i; //storing array indices + pActivePointWalk = pActivePointWalk->pNext; + } + + //copy lines + pActiveLineWalk = pLines; + for( unsigned int i = 0; i != iLineCount; ++i ) + { + pLineArray[i].iPointIndices[0] = (unsigned short)pActiveLineWalk->pLine->pPoints[0]->iSaveIndices; + pLineArray[i].iPointIndices[1] = (unsigned short)pActiveLineWalk->pLine->pPoints[1]->iSaveIndices; + + pActiveLineWalk->pLine->iSaveIndices = i; //storing array indices + + pActiveLineWalk = pActiveLineWalk->pNext; + } + + //copy polygons and indices at the same time + pActivePolygonWalk = pPolygons; + iIndexCount = 0; + for( unsigned int i = 0; i != iPolyCount; ++i ) + { + pPolyArray[i].polyNormal = pActivePolygonWalk->pPolygon->vSurfaceNormal; + pPolyArray[i].iFirstIndex = iIndexCount; + + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + //pIndexArray[iIndexCount] = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->iWorkData; //startpoint of each line, iWorkData is the index of the vertex + pIndexArray[iIndexCount].iLineIndex = pLineWalk->pLine->iSaveIndices; + pIndexArray[iIndexCount].iEndPointIndex = pLineWalk->iReferenceIndex; + + ++iIndexCount; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + pPolyArray[i].iIndexCount = iIndexCount - pPolyArray[i].iFirstIndex; + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + +#if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS ) + char szCollisionFile[128]; + CreateDumpDirectory( "PolyhedronDumps" ); + Q_snprintf( szCollisionFile, 128, "PolyhedronDumps/NewStyle_PolyhedronDump%i.txt", g_iPolyhedronDumpCounter ); + ++g_iPolyhedronDumpCounter; + + remove( szCollisionFile ); + DumpPolyhedronToGLView( pReturn, szCollisionFile, &s_matIdentity ); + DumpPolyhedronToGLView( pReturn, "PolyhedronDumps/NewStyle_PolyhedronDump_All-Appended.txt", &s_matIdentity ); +#endif + + return pReturn; +} + + + +#ifdef _DEBUG + +void DumpPointListToGLView( GeneratePolyhedronFromPlanes_UnorderedPointLL *pHead, PolyhedronPointPlanarity planarity, const Vector &vColor, const char *szDumpFile, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + FILE *pFile = fopen( szDumpFile, "ab" ); + + while( pHead ) + { + if( pHead->pPoint->planarity == planarity ) + { + const Vector vPointExtents( 0.5f, 0.5f, 0.01f ); + DumpAABBToGLView( (*pTransform) * pHead->pPoint->ptPosition, vPointExtents, vColor, pFile ); + } + pHead = pHead->pNext; + } + + fclose( pFile ); +#endif +} + +const char * DumpPolyhedronCutHistory( const CUtlVector &DumpedHistory, const CUtlVector &CutHistory, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + static char szDumpFile[100] = "FailedPolyhedronCut_Error.txt"; //most recent filename returned for further dumping + + for( int i = 0; i != DumpedHistory.Count(); ++i ) + { + if( DumpedHistory[i] != NULL ) + { + Q_snprintf( szDumpFile, 100, "FailedPolyhedronCut_%d.txt", i ); + DumpPolyhedronToGLView( DumpedHistory[i], szDumpFile, pTransform ); + DumpPlaneToGlView( CutHistory[i], 1.0f, szDumpFile, pTransform ); + } + } + + return szDumpFile; +#else + return NULL; +#endif +} + +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS +#define AssertMsg_DumpPolyhedron(condition, message)\ + if( (condition) == false )\ + {\ + VMatrix matTransform;\ + matTransform.Identity();\ + matTransform[0][0] = matTransform[1][1] = matTransform[2][2] = 25.0f;\ + matTransform.SetTranslation( -DebugCutHistory.Tail()->Center() * 25.0f );\ + const char *szLastDumpFile = DumpPolyhedronCutHistory( DebugCutHistory, PlaneCutHistory, &matTransform );\ + DumpPointListToGLView( pAllPoints, POINT_ALIVE, Vector( 0.9f, 0.9f, 0.9f ), szLastDumpFile, &matTransform );\ + DumpPointListToGLView( pAllPoints, POINT_ONPLANE, Vector( 0.5f, 0.5f, 0.5f ), szLastDumpFile, &matTransform );\ + DumpPointListToGLView( pDeadPointCollection, POINT_DEAD, Vector( 0.1f, 0.1f, 0.1f ), szLastDumpFile, &matTransform );\ + if( pStartPoint )\ + {\ + FILE *pFileDumpRepairProgress = fopen( szLastDumpFile, "ab" );\ + DumpAABBToGLView( matTransform * pStartPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 0.0f, 1.0f, 0.0f ), pFileDumpRepairProgress );\ + DumpAABBToGLView( matTransform * pWorkPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 1.0f, 0.0f, 0.0f ), pFileDumpRepairProgress );\ + fclose( pFileDumpRepairProgress );\ + }\ + AssertMsg( condition, message );\ + } +#else +#define AssertMsg_DumpPolyhedron(condition, message) AssertMsg( condition, message ) +#endif +#define Assert_DumpPolyhedron(condition) AssertMsg_DumpPolyhedron( condition, #condition ) + +#else + +#define AssertMsg_DumpPolyhedron(condition, message) NULL; +#define Assert_DumpPolyhedron(condition) NULL; + +#endif + +CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon; + +#ifdef _DEBUG + CUtlVector DebugCutHistory; + CUtlVector PlaneCutHistory; + GeneratePolyhedronFromPlanes_Point *pStartPoint = NULL; + GeneratePolyhedronFromPlanes_Point *pWorkPoint = NULL; + + static int iPolyhedronClipCount = 0; + ++iPolyhedronClipCount; + + DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) ); +#endif + + //clear out polygon work variables + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + do + { + pActivePolygonWalk->pPolygon->bMissingASide = false; + pActivePolygonWalk = pActivePolygonWalk->pNext; + } while( pActivePolygonWalk ); + } + + + //Collections of dead pointers for reallocation, shouldn't be touched until the current loop iteration is done. + GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPointCollection = NULL; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLineCollection = NULL; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygonCollection = NULL; + GeneratePolyhedronFromPlanes_LineLL *pDeadLineLinkCollection = NULL; + + + for( int iCurrentPlane = 0; iCurrentPlane != iPlaneCount; ++iCurrentPlane ) + { + //clear out line work variables + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + pActiveLineWalk->pLine->bAlive = false; + pActiveLineWalk->pLine->bCut = false; + + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + } + + //TODO: Move these pointers into a reallocation pool + pDeadPointCollection = NULL; + pDeadLineCollection = NULL; + pDeadLineLinkCollection = NULL; + pDeadPolygonCollection = NULL; + + Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(iCurrentPlane * 4) + 0]); + /*double vNormalAsDouble[3]; + vNormalAsDouble[0] = vNormal.x; + vNormalAsDouble[1] = vNormal.y; + vNormalAsDouble[2] = vNormal.z;*/ + float fPlaneDist = pOutwardFacingPlanes[(iCurrentPlane * 4) + 3]; + + //=================================================================================================== + // Step 1: Categorize each point as being either cut, split, or alive + //=================================================================================================== + { + bool bAllPointsDead = true; + bool bAllPointsAlive = true; + + //find point distances from the plane + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + GeneratePolyhedronFromPlanes_Point *pPoint = pActivePointWalk->pPoint; + float fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; + if( fPointDist > fOnPlaneEpsilon ) + { + pPoint->planarity = POINT_DEAD; //point is dead, bang bang + + //mark connected lines as cut + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + pLineWalk->pLine->bCut = true; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + bAllPointsAlive = false; + } + else if( fPointDist <= fNegativeOnPlaneEpsilon ) + { + pPoint->planarity = POINT_ALIVE; //point is in behind plane, not voted off the island....yet + bAllPointsDead = false; + + //mark connected lines as alive + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + pLineWalk->pLine->bAlive = true; //mark the line as alive + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + } + else + { + pPoint->planarity = POINT_ONPLANE; //point is on the plane, he's everyone's buddy + + //Project on-plane points leaning towards death closer to the plane. This battles floating point precision decay. + // Consider the case of a large on-plane epsilon leaving protrusions over time + /*if( fPointDist < 0.0f ) + { + double distAsDouble = fPointDist; + double vPositionAsDouble[3]; + vPositionAsDouble[0] = pPoint->ptPosition.x; + vPositionAsDouble[1] = pPoint->ptPosition.y; + vPositionAsDouble[2] = pPoint->ptPosition.z; + + pPoint->ptPosition.x = vPositionAsDouble[0] - (distAsDouble * vNormalAsDouble[0]); + pPoint->ptPosition.y = vPositionAsDouble[1] - (distAsDouble * vNormalAsDouble[1]); + pPoint->ptPosition.z = vPositionAsDouble[2] - (distAsDouble * vNormalAsDouble[2]); + +#if ( 0 && defined( _DEBUG ) ) + float fDebugDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows + AssertMsg( fabs( fDebugDist ) < fabs(fPointDist), "Projected point is further from plane than unprojected." ); +#endif + fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //recompute dist (not guaranteed to be 0.0 like we want) + }*/ + } + + pPoint->fPlaneDist = fPointDist; + + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + + if( bAllPointsDead ) //all the points either died or are on the plane, no polyhedron left at all + { +#ifdef _DEBUG + for( int i = DebugCutHistory.Count(); --i >= 0; ) + { + if( DebugCutHistory[i] ) + DebugCutHistory[i]->Release(); + } + DebugCutHistory.RemoveAll(); +#endif + + return NULL; + } + + if( bAllPointsAlive ) + continue; //no cuts made + + + //Scan for onplane points connected to only other onplane/dead points, these points get downgraded to dead status. + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint->planarity == POINT_ONPLANE ) + { + GeneratePolyhedronFromPlanes_LineLL *pOnPlaneLineWalk = pActivePointWalk->pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pStartLineWalk = pOnPlaneLineWalk; + bool bDead = true; //assume it's dead and disprove + do + { + if ( pOnPlaneLineWalk->pLine->bAlive ) + { + bDead = false; + } + else if ( pOnPlaneLineWalk->pLine->bCut ) + { + //connected to a dead point. + if( pOnPlaneLineWalk->pNext->pLine->bCut || pOnPlaneLineWalk->pPrev->pLine->bCut ) + { + //This on-plane point is surrounded by dead points on one polygon of the polyhedron. + // We have to downgrade this point to dead to avoid situations where float imprecision + // turns the polyhedron into a *slightly* concave shape. Concave shapes might break this algorithm, even falsely concave shapes. + bDead = true; + break; + } + } + + pOnPlaneLineWalk = pOnPlaneLineWalk->pNext; + } while( pOnPlaneLineWalk != pStartLineWalk ); + + if( bDead ) + { + pActivePointWalk->pPoint->planarity = POINT_DEAD; + + pOnPlaneLineWalk = pStartLineWalk; + + //mark connected lines as cut + do + { + pOnPlaneLineWalk->pLine->bCut = true; + pOnPlaneLineWalk = pOnPlaneLineWalk->pNext; + } while( pOnPlaneLineWalk != pStartLineWalk ); + } + } + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + } +#ifdef _DEBUG + PlaneCutHistory.AddToTail( &pOutwardFacingPlanes[iCurrentPlane * 4] ); +#endif + } + + + + +#ifdef _DEBUG + //Run around the edges of all the polygons and ensure they don't have more than one point of lowered "alive" status (alive > onplane > dead) surrounded by higher status + // It indicates a concave shape. It's impossible to have it occur in theoretical space. But floating point numbers introduce error. + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons; + do + { + int iSurroundedCount = 0; + GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugPolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstDebugLine = pDebugLineWalk; + + do + { + PolyhedronPointPlanarity currentPlanarity = pDebugLineWalk->pLine->pPoints[pDebugLineWalk->iReferenceIndex]->planarity; + + GeneratePolyhedronFromPlanes_LineLL *pNext = pDebugLineWalk->pNext; + PolyhedronPointPlanarity nextPlanarity = pNext->pLine->pPoints[pNext->iReferenceIndex]->planarity; + + if( currentPlanarity < nextPlanarity ) + { + GeneratePolyhedronFromPlanes_LineLL *pPrev = pDebugLineWalk->pPrev; + PolyhedronPointPlanarity prevPlanarity = pPrev->pLine->pPoints[pPrev->iReferenceIndex]->planarity; + + if( currentPlanarity < prevPlanarity ) + { + ++iSurroundedCount; + } + } + + pDebugLineWalk = pDebugLineWalk->pNext; + } while( pDebugLineWalk != pFirstDebugLine ); + + AssertMsg_DumpPolyhedron( iSurroundedCount <= 1, "Concave polygon, cutting process might break. Consider adjusting the on-plane epsilon to better compensate for floating point precision." ); + pDebugPolygonWalk = pDebugPolygonWalk->pNext; + } while( pDebugPolygonWalk ); + } +#endif + + //=================================================================================================== + // Step 2: Remove dead lines. A dead line is one with a dead point that isn't connected to a living point + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + GeneratePolyhedronFromPlanes_Line *pLine = pActiveLineWalk->pLine; + if( (pLine->bAlive == false) && (pLine->bCut == true) ) //not connected to a live point, but connected to a dead one. Dead line + { + //remove line from connected polygons + for( int i = 0; i != 2; ++i ) + { + GeneratePolyhedronFromPlanes_Polygon *pPolygon = pLine->pPolygons[i]; + GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPolygonLineLinks[i]; + + pPolygon->bMissingASide = true; + + if( pLineLink->pNext == pLineLink ) + { + //this was the last line of the polygon, it's dead + pPolygon->pLines = NULL; + } + else + { + //link around this line + pPolygon->pLines = pLineLink->pPrev; //Always have the polygon's head line be just before the gap in the polygon + pLineLink->pNext->pPrev = pLineLink->pPrev; + pLineLink->pPrev->pNext = pLineLink->pNext; + } + + //move the line link to the dead list + pLineLink->pNext = pDeadLineLinkCollection; + pDeadLineLinkCollection = pLineLink; + } + + //remove the line from connected points + for( int i = 0; i != 2; ++i ) + { + GeneratePolyhedronFromPlanes_Point *pPoint = pLine->pPoints[i]; + GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPointLineLinks[i]; + + if( pLineLink->pNext == pLineLink ) + { + //this is the last line + pPoint->pConnectedLines = NULL; + Assert( pPoint->planarity != POINT_ALIVE ); + pPoint->planarity = POINT_DEAD; //in case it was merely POINT_ONPLANE before + } + else + { + //link around this line + pPoint->pConnectedLines = pLineLink->pNext; //in case pLineLink was the head line + pLineLink->pNext->pPrev = pLineLink->pPrev; + pLineLink->pPrev->pNext = pLineLink->pNext; + } + + //move the line link to the dead list + pLineLink->pNext = pDeadLineLinkCollection; + pDeadLineLinkCollection = pLineLink; + } + + //move the line to the dead list + { + //link past this node + if( pActiveLineWalk->pPrev ) + pActiveLineWalk->pPrev->pNext = pActiveLineWalk->pNext; + else + pAllLines = pActiveLineWalk->pNext; + + if( pActiveLineWalk->pNext ) + pActiveLineWalk->pNext->pPrev = pActiveLineWalk->pPrev; + + GeneratePolyhedronFromPlanes_UnorderedLineLL *pNextLineWalk = pActiveLineWalk->pNext; + + //add to the dead list + pActiveLineWalk->pNext = pDeadLineCollection; + pDeadLineCollection = pActiveLineWalk; + + //next + pActiveLineWalk = pNextLineWalk; + } + } + else + { + pActiveLineWalk = pActiveLineWalk->pNext; + } + } while( pActiveLineWalk ); + } + + + //=================================================================================================== + // Step 3: Remove dead polygons. A dead polygon has less than 2 lines. + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + do + { + GeneratePolyhedronFromPlanes_Polygon *pPolygon = pActivePolygonWalk->pPolygon; + GeneratePolyhedronFromPlanes_LineLL *pHeadLine = pPolygon->pLines; + + bool bDead = (pHeadLine == NULL) || (pHeadLine->pNext == pHeadLine); + if( !bDead ) + { + //there's a rare case where a polygon can be almost entirely coplanar with the cut, it comes purely out of the land of imprecision + bDead = true; //assume it's dead, and disprove + + GeneratePolyhedronFromPlanes_LineLL *pTestLineWalk = pHeadLine; + do + { + if( pTestLineWalk->pLine->bAlive ) + { + bDead = false; + break; + } + + pTestLineWalk = pTestLineWalk->pNext; + } while( pTestLineWalk != pHeadLine ); + } + + if( bDead ) + { + //dead polygon, move it to the dead list + + //link around this node + if( pActivePolygonWalk->pPrev ) + pActivePolygonWalk->pPrev->pNext = pActivePolygonWalk->pNext; + else + pAllPolygons = pAllPolygons->pNext; //pActivePolygonWalk was the head node + + if( pActivePolygonWalk->pNext ) + pActivePolygonWalk->pNext->pPrev = pActivePolygonWalk->pPrev; + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNextPolygonWalk = pActivePolygonWalk->pNext; + + //add to the dead list + pActivePolygonWalk->pNext = pDeadPolygonCollection; + pDeadPolygonCollection = pActivePolygonWalk; + + //next + pActivePolygonWalk = pNextPolygonWalk; + } + else + { + AssertMsg_DumpPolyhedron( (pActivePolygonWalk->pPolygon->pLines != NULL) && + (pActivePolygonWalk->pPolygon->pLines != pActivePolygonWalk->pPolygon->pLines->pNext), "Living polygon with less than 2 lines" ); + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + } while( pActivePolygonWalk ); + } + + //=================================================================================================== + // Step 4: Remove dead points. + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint->planarity == POINT_DEAD ) + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext = pActivePointWalk->pNext; + + if( pActivePointWalk->pPrev ) + pActivePointWalk->pPrev->pNext = pActivePointWalk->pNext; + else + pAllPoints = pAllPoints->pNext; + + if( pActivePointWalk->pNext ) + pActivePointWalk->pNext->pPrev = pActivePointWalk->pPrev; + + pActivePointWalk->pNext = pDeadPointCollection; + pDeadPointCollection = pActivePointWalk; + + pActivePointWalk = pNext; + } + else + { + pActivePointWalk = pActivePointWalk->pNext; + } + } while( pActivePointWalk ); + } + + + //=================================================================================================== + // Step 5: Handle cut lines + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + GeneratePolyhedronFromPlanes_Line *pWorkLine = pActiveLineWalk->pLine; + Assert_DumpPolyhedron( (pWorkLine->bAlive == true) || (pWorkLine->bCut == false) ); //all dead lines should have already been removed + + if( pWorkLine->bCut ) + { + GeneratePolyhedronFromPlanes_Point **pLinePoints = pWorkLine->pPoints; + + Assert_DumpPolyhedron( (pLinePoints[0]->planarity == POINT_DEAD) || (pLinePoints[1]->planarity == POINT_DEAD) ); //one of the two has to be a dead point + + int iDeadIndex = (pLinePoints[0]->planarity == POINT_DEAD)?(0):(1); + int iLivingIndex = 1 - iDeadIndex; + GeneratePolyhedronFromPlanes_Point *pDeadPoint = pLinePoints[iDeadIndex]; + GeneratePolyhedronFromPlanes_Point *pLivingPoint = pLinePoints[iLivingIndex]; + + Assert_DumpPolyhedron( pLivingPoint->planarity == POINT_ALIVE ); //if this point were on-plane or dead, the line should be dead + + //We'll be de-linking from the old point and generating a new one. We do this so other lines can still access the dead point's untouched data. + + //Generate a new point + GeneratePolyhedronFromPlanes_Point *pNewPoint = (GeneratePolyhedronFromPlanes_Point *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Point ) ); + { + //add this point to the active list + pAllPoints->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) ); + pAllPoints->pPrev->pNext = pAllPoints; + pAllPoints = pAllPoints->pPrev; + pAllPoints->pPrev = NULL; + pAllPoints->pPoint = pNewPoint; + + + float fInvTotalDist = 1.0f/(pDeadPoint->fPlaneDist - pLivingPoint->fPlaneDist); //subtraction because the living index is known to be negative + pNewPoint->ptPosition = (pLivingPoint->ptPosition * (pDeadPoint->fPlaneDist * fInvTotalDist)) - (pDeadPoint->ptPosition * (pLivingPoint->fPlaneDist * fInvTotalDist)); + +#if ( 0 && defined( _DEBUG ) ) + float fDebugDist = vNormal.Dot( pNewPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows + AssertMsg_DumpPolyhedron( fabs( fDebugDist ) < fOnPlaneEpsilon, "Generated split point is far from plane" ); + + //verify that the new point isn't sitting on top of another + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint != pNewPoint ) + { + Vector vDiff = pActivePointWalk->pPoint->ptPosition - pNewPoint->ptPosition; + + AssertMsg_DumpPolyhedron( vDiff.Length() > fOnPlaneEpsilon, "Generated a point on top of another" ); + } + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + } +#endif + + pNewPoint->planarity = POINT_ONPLANE; + pNewPoint->fPlaneDist = 0.0f; + } + + GeneratePolyhedronFromPlanes_LineLL *pNewLineLink = pNewPoint->pConnectedLines = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pNewLineLink->pLine = pWorkLine; + pNewLineLink->pNext = pNewLineLink; + pNewLineLink->pPrev = pNewLineLink; + pNewLineLink->iReferenceIndex = iLivingIndex; + + pWorkLine->pPoints[iDeadIndex] = pNewPoint; + pWorkLine->pPointLineLinks[iDeadIndex] = pNewLineLink; + pNewPoint->pConnectedLines = pNewLineLink; + + //A new line is needed on each polygon touching the dead point to connect the two new endpoints for split lines. + // So mark connected polygons as missing a side. + for( int i = 0; i != 2; ++i ) + pWorkLine->pPolygons[i]->bMissingASide = true; + + + //Always have a cut polygon's head line be just before the gap in the polygon. + // In this case, we know that one of the two polygons goes clockwise into the dead point, so have that polygon point at this line. + // We don't know enough about the other polygon to do anything here, but another cut line will handle that polygon. So it all works out in the end. + pWorkLine->pPolygons[iDeadIndex]->pLines = pWorkLine->pPolygonLineLinks[iDeadIndex]; + } + + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + } + + + //=================================================================================================== + // Step 6: Repair polygons that are missing a side. And generate the new coplanar polygon. + //=================================================================================================== + { + //Find the first polygon missing a side. + // We'll then walk from polygon to polygon using line connections so that we can generate the new polygon in a clockwise manner. + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + + while( (pActivePolygonWalk != NULL) && (pActivePolygonWalk->pPolygon->bMissingASide == false) ) + { + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + + //acquire iteration data +#ifndef _DEBUG + GeneratePolyhedronFromPlanes_Point *pStartPoint; + GeneratePolyhedronFromPlanes_Point *pWorkPoint; +#endif + + GeneratePolyhedronFromPlanes_LineLL *pLastLineLink; + GeneratePolyhedronFromPlanes_Polygon *pWorkPolygon; + GeneratePolyhedronFromPlanes_LineLL *pTestLine; + +#ifdef _DEBUG + GeneratePolyhedronFromPlanes_Polygon *pLastWorkPolygon = NULL; + GeneratePolyhedronFromPlanes_Point *pLastWorkPoint = NULL; +#endif + + if( pActivePolygonWalk ) + { + //grab the polygon we'll be starting with + GeneratePolyhedronFromPlanes_Polygon *pBrokenPolygon = pActivePolygonWalk->pPolygon; + + { + GeneratePolyhedronFromPlanes_LineLL *pTemp = pBrokenPolygon->pLines->pNext; + pStartPoint = pTemp->pLine->pPoints[1 - pTemp->iReferenceIndex]; + Assert_DumpPolyhedron( pStartPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + pLastLineLink = pTemp->pLine->pPointLineLinks[1 - pTemp->iReferenceIndex]->pNext; + pWorkPolygon = pBrokenPolygon; + } + + pWorkPoint = pStartPoint; + pTestLine = pLastLineLink->pPrev; //rotate counterclockwise around the point + } + else + { + //apparently the plane was entirely through existing polygonal borders, extremely rare but it can happen with inefficient cutting planes + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + while( (pActivePointWalk != NULL) && (pActivePointWalk->pPoint->planarity != POINT_ONPLANE) ) + { + pActivePointWalk = pActivePointWalk->pNext; + } + + Assert( pActivePointWalk != NULL ); + + pStartPoint = pWorkPoint = pActivePointWalk->pPoint; + GeneratePolyhedronFromPlanes_LineLL *pLines = pWorkPoint->pConnectedLines; + + while( !pLines->pLine->bAlive ) //seek clockwise until we find a line not on the plane + pLines = pLines->pNext; + + while( pLines->pLine->bAlive ) //now seek counterclockwise until we find a line on the plane (in case we started on an alive line last seek) + pLines = pLines->pPrev; + + //now pLines points at one side of the polygon, with pActivePointWalk + pLastLineLink = pLines; + pTestLine = pLines->pPrev; + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + } + + //create the new polygon + GeneratePolyhedronFromPlanes_Polygon *pNewPolygon = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Polygon ) ); + { + //before we forget, add this polygon to the active list + pAllPolygons->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) ); + pAllPolygons->pPrev->pNext = pAllPolygons; + pAllPolygons = pAllPolygons->pPrev; + pAllPolygons->pPrev = NULL; + pAllPolygons->pPolygon = pNewPolygon; + + pNewPolygon->bMissingASide = false; //technically missing all it's sides, but we're fixing it now + pNewPolygon->vSurfaceNormal = vNormal; + pNewPolygon->pLines = NULL; + } + + + + //=================================================================================================================== + // The general idea of the upcoming algorithm to put together a new polygon and patch broken polygons... + // You have a point and a line the algorithm just jumped across. + // 1. Rotate through the point's line links one time counterclockwise (pPrev) + // 2. If the line is cut, then we make a new bridging line in the polygon between that line and the one counterclockwise to it. (pPrev) + // If the line is on-plane. Skip the bridge line making, but set links to the new polygon as if we'd just created the bridge + // 3. Once we follow a line back to the point where we started, we should be all done. + + do + { + if( pWorkPolygon->bMissingASide ) + { + //during the cutting process we made sure that the head line link was going clockwise into the missing area + GeneratePolyhedronFromPlanes_LineLL *pGapLines[2]; + pGapLines[1] = pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex]; //get the same line, but in the polygons linked list. + Assert_DumpPolyhedron( pGapLines[1]->pLine == pTestLine->pLine ); + pGapLines[0] = pGapLines[1]->pPrev; + + Assert_DumpPolyhedron( pWorkPolygon->bMissingASide ); + +#ifdef _DEBUG + { + //ensure that the space between the gap lines is the only space where fixing is required + GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pGapLines[1]->pNext; + + while( pDebugLineWalk != pGapLines[0] ) + { + Assert_DumpPolyhedron( pDebugLineWalk->pLine->bCut == false ); + pDebugLineWalk = pDebugLineWalk->pNext; + } + } +#endif + + GeneratePolyhedronFromPlanes_Line *pJoinLine = (GeneratePolyhedronFromPlanes_Line *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Line ) ); + { + //before we forget, add this line to the active list + pAllLines->pPrev = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) ); + pAllLines->pPrev->pNext = pAllLines; + pAllLines = pAllLines->pPrev; + pAllLines->pPrev = NULL; + pAllLines->pLine = pJoinLine; + + pJoinLine->bAlive = false; + pJoinLine->bCut = false; + } + + + pJoinLine->pPoints[0] = pGapLines[0]->pLine->pPoints[pGapLines[0]->iReferenceIndex]; + pJoinLine->pPoints[1] = pGapLines[1]->pLine->pPoints[1 - pGapLines[1]->iReferenceIndex]; + + pJoinLine->pPolygons[0] = pNewPolygon; + pJoinLine->pPolygons[1] = pWorkPolygon; + + //now create all 4 links into the line + GeneratePolyhedronFromPlanes_LineLL *pPointLinks[2]; + pPointLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pPointLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + GeneratePolyhedronFromPlanes_LineLL *pPolygonLinks[2]; + pPolygonLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pPolygonLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + pPointLinks[0]->pLine = pPointLinks[1]->pLine = pPolygonLinks[0]->pLine = pPolygonLinks[1]->pLine = pJoinLine; + + pJoinLine->pPointLineLinks[0] = pPointLinks[0]; + pJoinLine->pPointLineLinks[1] = pPointLinks[1]; + pJoinLine->pPolygonLineLinks[0] = pPolygonLinks[0]; + pJoinLine->pPolygonLineLinks[1] = pPolygonLinks[1]; + + + + pPointLinks[0]->iReferenceIndex = 1; + pPointLinks[1]->iReferenceIndex = 0; + + //Insert before the link from point 0 to gap line 0 (counterclockwise rotation) + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[0]->pLine->pPointLineLinks[pGapLines[0]->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[0]->pLine ); + + pPointLinks[0]->pPrev = pWorkLink->pPrev; + pPointLinks[0]->pNext = pWorkLink; + + pWorkLink->pPrev->pNext = pPointLinks[0]; + pWorkLink->pPrev = pPointLinks[0]; + } + + //Insert after the link from point 1 to gap line 1 (clockwise rotation) + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[1]->pLine->pPointLineLinks[1 - pGapLines[1]->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[1]->pLine ); + + pPointLinks[1]->pNext = pWorkLink->pNext; + pPointLinks[1]->pPrev = pWorkLink; + + pWorkLink->pNext->pPrev = pPointLinks[1]; + pWorkLink->pNext = pPointLinks[1]; + } + + + + + pPolygonLinks[0]->iReferenceIndex = 0; + pPolygonLinks[1]->iReferenceIndex = 1; + + //Insert before the head line in the new polygon (at the end of the clockwise order) + { + if( pNewPolygon->pLines == NULL ) + { + //this is the first line being added to the polygon + pNewPolygon->pLines = pPolygonLinks[0]; + pPolygonLinks[0]->pNext = pPolygonLinks[0]; + pPolygonLinks[0]->pPrev = pPolygonLinks[0]; + } + else + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines; + + pPolygonLinks[0]->pNext = pWorkLink; + pPolygonLinks[0]->pPrev = pWorkLink->pPrev; + + pWorkLink->pPrev->pNext = pPolygonLinks[0]; + pWorkLink->pPrev = pPolygonLinks[0]; + } + } + + //Insert after the head line in the work polygon + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pWorkPolygon->pLines; + + pPolygonLinks[1]->pNext = pWorkLink->pNext; + pPolygonLinks[1]->pPrev = pWorkLink; + + pWorkLink->pNext->pPrev = pPolygonLinks[1]; + pWorkLink->pNext = pPolygonLinks[1]; + } + + pWorkPolygon->bMissingASide = false; //repairs are finished + +#ifdef _DEBUG + pLastWorkPolygon = pWorkPolygon; + pLastWorkPoint = pWorkPoint; +#endif + //move to the next point + pWorkPoint = pJoinLine->pPoints[0]; + pLastLineLink = pJoinLine->pPointLineLinks[0]; + Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + + pTestLine = pLastLineLink->pPrev; + if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE ) + pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex]; + else + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon ); + Assert_DumpPolyhedron( (pWorkPoint == pStartPoint) || + (pGapLines[0]->pLine->bCut == false) || + (pWorkPolygon->bMissingASide == true) ); //if we're not done fixing, and if the shared line was cut, the next polygon must be missing a side + } + else + { + //line is on the plane, meaning the polygon isn't broken and doesn't need patching + Assert_DumpPolyhedron( pTestLine->pLine->bCut == false ); + Assert_DumpPolyhedron( (pTestLine->pLine->pPoints[0]->planarity == POINT_ONPLANE) && (pTestLine->pLine->pPoints[1]->planarity == POINT_ONPLANE) ); + + + //link to this line from the new polygon + GeneratePolyhedronFromPlanes_LineLL *pNewLineLink; + pNewLineLink = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + pNewLineLink->pLine = pTestLine->pLine; + pNewLineLink->iReferenceIndex = pTestLine->iReferenceIndex; + + //Insert before the head line in the new polygon (at the end of the clockwise order) + { + if( pNewPolygon->pLines == NULL ) + { + //this is the first line being added to the polygon + pNewPolygon->pLines = pNewLineLink; + pNewLineLink->pNext = pNewLineLink; + pNewLineLink->pPrev = pNewLineLink; + } + else + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines; + + pNewLineLink->pNext = pWorkLink; + pNewLineLink->pPrev = pWorkLink->pPrev; + + pWorkLink->pPrev->pNext = pNewLineLink; + pWorkLink->pPrev = pNewLineLink; + } + } + + //Since the entire line is on the plane, that means it used to point to something that used to reside where the new polygon is going + // Update the link to the new the polygon pointer and be on our way + pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex] = pNewPolygon; + pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex] = pNewLineLink; + +#ifdef _DEBUG + pLastWorkPolygon = pWorkPolygon; + pLastWorkPoint = pWorkPoint; +#endif + + pWorkPoint = pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]; + pLastLineLink = pTestLine->pLine->pPointLineLinks[pTestLine->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + + pTestLine = pLastLineLink->pPrev; + if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE ) + pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex]; + else + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon ); + } + } while( pWorkPoint != pStartPoint ); + } + +#ifdef _DEBUG + //verify that repairs are complete + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons; + do + { + AssertMsg_DumpPolyhedron( pDebugPolygonWalk->pPolygon->bMissingASide == false, "Some polygons not repaired after cut" ); + pDebugPolygonWalk = pDebugPolygonWalk->pNext; + } while( pDebugPolygonWalk ); + + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pDebugPointWalk = pAllPoints; + do + { + AssertMsg_DumpPolyhedron( pDebugPointWalk->pPoint->pConnectedLines, "Point connected to no lines after cut" ); + pDebugPointWalk = pDebugPointWalk->pNext; + } while( pDebugPointWalk ); + + pStartPoint = NULL; + } + + //maintain the cut history + DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) ); +#endif + } + +#ifdef _DEBUG + for( int i = DebugCutHistory.Count(); --i >= 0; ) + { + if( DebugCutHistory[i] ) + DebugCutHistory[i]->Release(); + } + DebugCutHistory.RemoveAll(); +#endif + + return ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, bUseTemporaryMemory ); +} + + + +#define STARTPOINTTOLINELINKS(iPointNum, lineindex1, iOtherPointIndex1, lineindex2, iOtherPointIndex2, lineindex3, iOtherPointIndex3 )\ + StartingBoxPoints[iPointNum].pConnectedLines = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pLine = &StartingBoxLines[lineindex1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].iReferenceIndex = iOtherPointIndex1;\ + StartingBoxLines[lineindex1].pPointLineLinks[1 - iOtherPointIndex1] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pLine = &StartingBoxLines[lineindex2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].iReferenceIndex = iOtherPointIndex2;\ + StartingBoxLines[lineindex2].pPointLineLinks[1 - iOtherPointIndex2] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pLine = &StartingBoxLines[lineindex3];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].iReferenceIndex = iOtherPointIndex3;\ + StartingBoxLines[lineindex3].pPointLineLinks[1 - iOtherPointIndex3] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0]; + +#define STARTBOXCONNECTION( linenum, point1, point2, poly1, poly2 )\ + StartingBoxLines[linenum].pPoints[0] = &StartingBoxPoints[point1];\ + StartingBoxLines[linenum].pPoints[1] = &StartingBoxPoints[point2];\ + StartingBoxLines[linenum].pPolygons[0] = &StartingBoxPolygons[poly1];\ + StartingBoxLines[linenum].pPolygons[1] = &StartingBoxPolygons[poly2]; + +#define STARTPOLYGONTOLINELINKS( polynum, lineindex1, iThisPolyIndex1, lineindex2, iThisPolyIndex2, lineindex3, iThisPolyIndex3, lineindex4, iThisPolyIndex4 )\ + StartingBoxPolygons[polynum].pLines = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pLine = &StartingBoxLines[lineindex1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].iReferenceIndex = iThisPolyIndex1;\ + StartingBoxLines[lineindex1].pPolygonLineLinks[iThisPolyIndex1] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pLine = &StartingBoxLines[lineindex2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].iReferenceIndex = iThisPolyIndex2;\ + StartingBoxLines[lineindex2].pPolygonLineLinks[iThisPolyIndex2] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pLine = &StartingBoxLines[lineindex3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].iReferenceIndex = iThisPolyIndex3;\ + StartingBoxLines[lineindex3].pPolygonLineLinks[iThisPolyIndex3] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pLine = &StartingBoxLines[lineindex4];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].iReferenceIndex = iThisPolyIndex4;\ + StartingBoxLines[lineindex4].pPolygonLineLinks[iThisPolyIndex4] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0]; + + +CPolyhedron *GeneratePolyhedronFromPlanes( const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + //this is version 2 of the polyhedron generator, version 1 made individual polygons and joined points together, some guesswork is involved and it therefore isn't a solid method + //this version will start with a cube and hack away at it (retaining point connection information) to produce a polyhedron with no guesswork involved, this method should be rock solid + + //the polygon clipping functions we're going to use want inward facing planes + float *pFlippedPlanes = (float *)stackalloc( (iPlaneCount * 4) * sizeof( float ) ); + for( int i = 0; i != iPlaneCount * 4; ++i ) + { + pFlippedPlanes[i] = -pOutwardFacingPlanes[i]; + } + + //our first goal is to find the size of a cube big enough to encapsulate all points that will be in the final polyhedron + Vector vAABBMins, vAABBMaxs; + if( FindConvexShapeLooseAABB( pFlippedPlanes, iPlaneCount, &vAABBMins, &vAABBMaxs ) == false ) + return NULL; //no shape to work with apparently + + + //grow the bounding box to a larger size since it's probably inaccurate a bit + { + Vector vGrow = (vAABBMaxs - vAABBMins) * 0.5f; + vGrow.x += 100.0f; + vGrow.y += 100.0f; + vGrow.z += 100.0f; + + vAABBMaxs += vGrow; + vAABBMins -= vGrow; + } + + //generate our starting cube using the 2x AABB so we can start hacking away at it + + + + //create our starting box on the stack + GeneratePolyhedronFromPlanes_Point StartingBoxPoints[8]; + GeneratePolyhedronFromPlanes_Line StartingBoxLines[12]; + GeneratePolyhedronFromPlanes_Polygon StartingBoxPolygons[6]; + GeneratePolyhedronFromPlanes_LineLL StartingPoints_To_Lines_Links[24]; //8 points, 3 lines per point + GeneratePolyhedronFromPlanes_LineLL StartingPolygon_To_Lines_Links[24]; //6 polygons, 4 lines per poly + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL StartingPolygonList[6]; //6 polygons + GeneratePolyhedronFromPlanes_UnorderedLineLL StartingLineList[12]; //12 lines + GeneratePolyhedronFromPlanes_UnorderedPointLL StartingPointList[8]; //8 points + + + //I had to work all this out on a whiteboard if it seems completely unintuitive. + { + StartingBoxPoints[0].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 0, 0, 1, 4, 1, 3, 0 ); + + StartingBoxPoints[1].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 1, 0, 0, 1, 1, 5, 1 ); + + StartingBoxPoints[2].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 2, 4, 0, 8, 1, 11, 0 ); + + StartingBoxPoints[3].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 3, 5, 0, 9, 1, 8, 0 ); + + StartingBoxPoints[4].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 4, 2, 0, 3, 1, 7, 1 ); + + StartingBoxPoints[5].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 5, 1, 0, 2, 1, 6, 1 ); + + StartingBoxPoints[6].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 6, 7, 0, 11, 1, 10, 0 ); + + StartingBoxPoints[7].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 7, 6, 0, 10, 1, 9, 0 ); + + STARTBOXCONNECTION( 0, 0, 1, 0, 5 ); + STARTBOXCONNECTION( 1, 1, 5, 1, 5 ); + STARTBOXCONNECTION( 2, 5, 4, 2, 5 ); + STARTBOXCONNECTION( 3, 4, 0, 3, 5 ); + STARTBOXCONNECTION( 4, 0, 2, 3, 0 ); + STARTBOXCONNECTION( 5, 1, 3, 0, 1 ); + STARTBOXCONNECTION( 6, 5, 7, 1, 2 ); + STARTBOXCONNECTION( 7, 4, 6, 2, 3 ); + STARTBOXCONNECTION( 8, 2, 3, 4, 0 ); + STARTBOXCONNECTION( 9, 3, 7, 4, 1 ); + STARTBOXCONNECTION( 10, 7, 6, 4, 2 ); + STARTBOXCONNECTION( 11, 6, 2, 4, 3 ); + + + STARTBOXCONNECTION( 0, 0, 1, 5, 0 ); + STARTBOXCONNECTION( 1, 1, 5, 5, 1 ); + STARTBOXCONNECTION( 2, 5, 4, 5, 2 ); + STARTBOXCONNECTION( 3, 4, 0, 5, 3 ); + STARTBOXCONNECTION( 4, 0, 2, 0, 3 ); + STARTBOXCONNECTION( 5, 1, 3, 1, 0 ); + STARTBOXCONNECTION( 6, 5, 7, 2, 1 ); + STARTBOXCONNECTION( 7, 4, 6, 3, 2 ); + STARTBOXCONNECTION( 8, 2, 3, 0, 4 ); + STARTBOXCONNECTION( 9, 3, 7, 1, 4 ); + STARTBOXCONNECTION( 10, 7, 6, 2, 4 ); + STARTBOXCONNECTION( 11, 6, 2, 3, 4 ); + + StartingBoxPolygons[0].vSurfaceNormal.Init( -1.0f, 0.0f, 0.0f ); + StartingBoxPolygons[1].vSurfaceNormal.Init( 0.0f, 1.0f, 0.0f ); + StartingBoxPolygons[2].vSurfaceNormal.Init( 1.0f, 0.0f, 0.0f ); + StartingBoxPolygons[3].vSurfaceNormal.Init( 0.0f, -1.0f, 0.0f ); + StartingBoxPolygons[4].vSurfaceNormal.Init( 0.0f, 0.0f, 1.0f ); + StartingBoxPolygons[5].vSurfaceNormal.Init( 0.0f, 0.0f, -1.0f ); + + + STARTPOLYGONTOLINELINKS( 0, 0, 1, 5, 1, 8, 0, 4, 0 ); + STARTPOLYGONTOLINELINKS( 1, 1, 1, 6, 1, 9, 0, 5, 0 ); + STARTPOLYGONTOLINELINKS( 2, 2, 1, 7, 1, 10, 0, 6, 0 ); + STARTPOLYGONTOLINELINKS( 3, 3, 1, 4, 1, 11, 0, 7, 0 ); + STARTPOLYGONTOLINELINKS( 4, 8, 1, 9, 1, 10, 1, 11, 1 ); + STARTPOLYGONTOLINELINKS( 5, 0, 0, 3, 0, 2, 0, 1, 0 ); + + + { + StartingPolygonList[0].pPolygon = &StartingBoxPolygons[0]; + StartingPolygonList[0].pNext = &StartingPolygonList[1]; + StartingPolygonList[0].pPrev = NULL; + + StartingPolygonList[1].pPolygon = &StartingBoxPolygons[1]; + StartingPolygonList[1].pNext = &StartingPolygonList[2]; + StartingPolygonList[1].pPrev = &StartingPolygonList[0]; + + StartingPolygonList[2].pPolygon = &StartingBoxPolygons[2]; + StartingPolygonList[2].pNext = &StartingPolygonList[3]; + StartingPolygonList[2].pPrev = &StartingPolygonList[1]; + + StartingPolygonList[3].pPolygon = &StartingBoxPolygons[3]; + StartingPolygonList[3].pNext = &StartingPolygonList[4]; + StartingPolygonList[3].pPrev = &StartingPolygonList[2]; + + StartingPolygonList[4].pPolygon = &StartingBoxPolygons[4]; + StartingPolygonList[4].pNext = &StartingPolygonList[5]; + StartingPolygonList[4].pPrev = &StartingPolygonList[3]; + + StartingPolygonList[5].pPolygon = &StartingBoxPolygons[5]; + StartingPolygonList[5].pNext = NULL; + StartingPolygonList[5].pPrev = &StartingPolygonList[4]; + } + + + + { + StartingLineList[0].pLine = &StartingBoxLines[0]; + StartingLineList[0].pNext = &StartingLineList[1]; + StartingLineList[0].pPrev = NULL; + + StartingLineList[1].pLine = &StartingBoxLines[1]; + StartingLineList[1].pNext = &StartingLineList[2]; + StartingLineList[1].pPrev = &StartingLineList[0]; + + StartingLineList[2].pLine = &StartingBoxLines[2]; + StartingLineList[2].pNext = &StartingLineList[3]; + StartingLineList[2].pPrev = &StartingLineList[1]; + + StartingLineList[3].pLine = &StartingBoxLines[3]; + StartingLineList[3].pNext = &StartingLineList[4]; + StartingLineList[3].pPrev = &StartingLineList[2]; + + StartingLineList[4].pLine = &StartingBoxLines[4]; + StartingLineList[4].pNext = &StartingLineList[5]; + StartingLineList[4].pPrev = &StartingLineList[3]; + + StartingLineList[5].pLine = &StartingBoxLines[5]; + StartingLineList[5].pNext = &StartingLineList[6]; + StartingLineList[5].pPrev = &StartingLineList[4]; + + StartingLineList[6].pLine = &StartingBoxLines[6]; + StartingLineList[6].pNext = &StartingLineList[7]; + StartingLineList[6].pPrev = &StartingLineList[5]; + + StartingLineList[7].pLine = &StartingBoxLines[7]; + StartingLineList[7].pNext = &StartingLineList[8]; + StartingLineList[7].pPrev = &StartingLineList[6]; + + StartingLineList[8].pLine = &StartingBoxLines[8]; + StartingLineList[8].pNext = &StartingLineList[9]; + StartingLineList[8].pPrev = &StartingLineList[7]; + + StartingLineList[9].pLine = &StartingBoxLines[9]; + StartingLineList[9].pNext = &StartingLineList[10]; + StartingLineList[9].pPrev = &StartingLineList[8]; + + StartingLineList[10].pLine = &StartingBoxLines[10]; + StartingLineList[10].pNext = &StartingLineList[11]; + StartingLineList[10].pPrev = &StartingLineList[9]; + + StartingLineList[11].pLine = &StartingBoxLines[11]; + StartingLineList[11].pNext = NULL; + StartingLineList[11].pPrev = &StartingLineList[10]; + } + + { + StartingPointList[0].pPoint = &StartingBoxPoints[0]; + StartingPointList[0].pNext = &StartingPointList[1]; + StartingPointList[0].pPrev = NULL; + + StartingPointList[1].pPoint = &StartingBoxPoints[1]; + StartingPointList[1].pNext = &StartingPointList[2]; + StartingPointList[1].pPrev = &StartingPointList[0]; + + StartingPointList[2].pPoint = &StartingBoxPoints[2]; + StartingPointList[2].pNext = &StartingPointList[3]; + StartingPointList[2].pPrev = &StartingPointList[1]; + + StartingPointList[3].pPoint = &StartingBoxPoints[3]; + StartingPointList[3].pNext = &StartingPointList[4]; + StartingPointList[3].pPrev = &StartingPointList[2]; + + StartingPointList[4].pPoint = &StartingBoxPoints[4]; + StartingPointList[4].pNext = &StartingPointList[5]; + StartingPointList[4].pPrev = &StartingPointList[3]; + + StartingPointList[5].pPoint = &StartingBoxPoints[5]; + StartingPointList[5].pNext = &StartingPointList[6]; + StartingPointList[5].pPrev = &StartingPointList[4]; + + StartingPointList[6].pPoint = &StartingBoxPoints[6]; + StartingPointList[6].pNext = &StartingPointList[7]; + StartingPointList[6].pPrev = &StartingPointList[5]; + + StartingPointList[7].pPoint = &StartingBoxPoints[7]; + StartingPointList[7].pNext = NULL; + StartingPointList[7].pPrev = &StartingPointList[6]; + } + } + + return ClipLinkedGeometry( StartingPolygonList, StartingLineList, StartingPointList, pOutwardFacingPlanes, iPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory ); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef _DEBUG +void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + Vector vMins = vCenter - vExtents; + Vector vMaxs = vCenter + vExtents; + + //x min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + //x max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + //y min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + + //y max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + + //z min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + //z max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); +#endif +} + +void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + Vector vDirection = vPoint2 - vPoint1; + vDirection.NormalizeInPlace(); + + Vector vPseudoPerpandicular = vec3_origin; + + if( vDirection.x != 0.0f ) + vPseudoPerpandicular.z = 1.0f; + else + vPseudoPerpandicular.x = 1.0f; + + Vector vWidth = vDirection.Cross( vPseudoPerpandicular ); + vWidth.NormalizeInPlace(); + + Vector vHeight = vDirection.Cross( vWidth ); + vHeight.NormalizeInPlace(); + + fThickness *= 0.5f; //we use half thickness in both directions + vDirection *= fThickness; + vWidth *= fThickness; + vHeight *= fThickness; + + Vector vLinePoints[8]; + vLinePoints[0] = vPoint1 - vDirection - vWidth - vHeight; + vLinePoints[1] = vPoint1 - vDirection - vWidth + vHeight; + vLinePoints[2] = vPoint1 - vDirection + vWidth - vHeight; + vLinePoints[3] = vPoint1 - vDirection + vWidth + vHeight; + + vLinePoints[4] = vPoint2 + vDirection - vWidth - vHeight; + vLinePoints[5] = vPoint2 + vDirection - vWidth + vHeight; + vLinePoints[6] = vPoint2 + vDirection + vWidth - vHeight; + vLinePoints[7] = vPoint2 + vDirection + vWidth + vHeight; + + const Vector *pLineColors[8] = { &vColor1, &vColor1, &vColor1, &vColor1, &vColor2, &vColor2, &vColor2, &vColor2 }; + + +#define DPTGLV_LINE_WRITEPOINT(index) fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vLinePoints[index].x, vLinePoints[index].y, vLinePoints[index].z, pLineColors[index]->x, pLineColors[index]->y, pLineColors[index]->z ); +#define DPTGLV_LINE_DOUBLESIDEDQUAD(index1,index2,index3,index4)\ + fprintf( pFile, "4\n" );\ + DPTGLV_LINE_WRITEPOINT(index1);\ + DPTGLV_LINE_WRITEPOINT(index2);\ + DPTGLV_LINE_WRITEPOINT(index3);\ + DPTGLV_LINE_WRITEPOINT(index4);\ + fprintf( pFile, "4\n" );\ + DPTGLV_LINE_WRITEPOINT(index4);\ + DPTGLV_LINE_WRITEPOINT(index3);\ + DPTGLV_LINE_WRITEPOINT(index2);\ + DPTGLV_LINE_WRITEPOINT(index1); + + + DPTGLV_LINE_DOUBLESIDEDQUAD(0,4,6,2); + DPTGLV_LINE_DOUBLESIDEDQUAD(3,7,5,1); + DPTGLV_LINE_DOUBLESIDEDQUAD(1,5,4,0); + DPTGLV_LINE_DOUBLESIDEDQUAD(2,6,7,3); + DPTGLV_LINE_DOUBLESIDEDQUAD(0,2,3,1); + DPTGLV_LINE_DOUBLESIDEDQUAD(5,7,6,4); +#endif +} + +void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if ( (pPolyhedron == NULL) || (pPolyhedron->iVertexCount == 0) ) + return; + + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + printf("Writing %s...\n", pFilename ); + + FILE *pFile = fopen( pFilename, "ab" ); + + //randomizing an array of colors to help spot shared/unshared vertices + Vector *pColors = (Vector *)stackalloc( sizeof( Vector ) * pPolyhedron->iVertexCount ); + int counter; + for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + pColors[counter].Init( rand()/32768.0f, rand()/32768.0f, rand()/32768.0f ); + } + + Vector *pTransformedPoints = (Vector *)stackalloc( pPolyhedron->iVertexCount * sizeof( Vector ) ); + for ( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + pTransformedPoints[counter] = (*pTransform) * pPolyhedron->pVertices[counter]; + } + + for ( counter = 0; counter != pPolyhedron->iPolygonCount; ++counter ) + { + fprintf( pFile, "%i\n", pPolyhedron->pPolygons[counter].iIndexCount ); + int counter2; + for( counter2 = 0; counter2 != pPolyhedron->pPolygons[counter].iIndexCount; ++counter2 ) + { + Polyhedron_IndexedLineReference_t *pLineReference = &pPolyhedron->pIndices[pPolyhedron->pPolygons[counter].iFirstIndex + counter2]; + + Vector *pVertex = &pTransformedPoints[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]]; + Vector *pColor = &pColors[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]]; + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n",pVertex->x, pVertex->y, pVertex->z, pColor->x, pColor->y, pColor->z ); + } + } + + for( counter = 0; counter != pPolyhedron->iLineCount; ++counter ) + { + const Vector vOne( 1.0f, 1.0f, 1.0f ); + DumpLineToGLView( pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[0]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[0]], + pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[1]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[1]], + 0.1f, pFile ); + } + + for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + const Vector vPointHalfSize(0.15f, 0.15f, 0.15f ); + DumpAABBToGLView( pTransformedPoints[counter], vPointHalfSize, pColors[counter], pFile ); + } + + fclose( pFile ); +#endif +} + + +void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + FILE *pFile = fopen( pszFileName, "ab" ); + + //transform the plane + Vector vNormal = pTransform->ApplyRotation( *(Vector *)pPlane ); + float fDist = pPlane[3] * vNormal.NormalizeInPlace(); //possible scaling going on + fDist += vNormal.Dot( pTransform->GetTranslation() ); + + Vector vPlaneVerts[4]; + + PolyFromPlane( vPlaneVerts, vNormal, fDist, 100000.0f ); + + fprintf( pFile, "4\n" ); + + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[0].x, vPlaneVerts[0].y, vPlaneVerts[0].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[1].x, vPlaneVerts[1].y, vPlaneVerts[1].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[2].x, vPlaneVerts[2].y, vPlaneVerts[2].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[3].x, vPlaneVerts[3].y, vPlaneVerts[3].z, fGrayScale, fGrayScale, fGrayScale ); + + fclose( pFile ); +#endif +} +#endif + + diff --git a/mathlib/powsse.cpp b/mathlib/powsse.cpp new file mode 100644 index 0000000..b026c64 --- /dev/null +++ b/mathlib/powsse.cpp @@ -0,0 +1,96 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "mathlib/ssemath.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +fltx4 Pow_FixedPoint_Exponent_SIMD( const fltx4 & x, int exponent) +{ + fltx4 rslt=Four_Ones; // x^0=1.0 + int xp=abs(exponent); + if (xp & 3) // fraction present? + { + fltx4 sq_rt=SqrtEstSIMD(x); + if (xp & 1) // .25? + rslt=SqrtEstSIMD(sq_rt); // x^.25 + if (xp & 2) + rslt=MulSIMD(rslt,sq_rt); + } + xp>>=2; // strip fraction + fltx4 curpower=x; // curpower iterates through x,x^2,x^4,x^8,x^16... + + while(1) + { + if (xp & 1) + rslt=MulSIMD(rslt,curpower); + xp>>=1; + if (xp) + curpower=MulSIMD(curpower,curpower); + else + break; + } + if (exponent<0) + return ReciprocalEstSaturateSIMD(rslt); // pow(x,-b)=1/pow(x,b) + else + return rslt; +} + + + + +/* + * (c) Ian Stephenson + * + * ian@dctsystems.co.uk + * + * Fast pow() reference implementation + */ + + +static float shift23=(1<<23); +static float OOshift23=1.0/(1<<23); + +float FastLog2(float i) +{ + float LogBodge=0.346607f; + float x; + float y; + x=*(int *)&i; + x*= OOshift23; //1/pow(2,23); + x=x-127; + + y=x-floorf(x); + y=(y-y*y)*LogBodge; + return x+y; +} +float FastPow2(float i) +{ + float PowBodge=0.33971f; + float x; + float y=i-floorf(i); + y=(y-y*y)*PowBodge; + + x=i+127-y; + x*= shift23; //pow(2,23); + *(int*)&x=(int)x; + return x; +} +float FastPow(float a, float b) +{ + if (a <= OOshift23) + { + return 0.0f; + } + return FastPow2(b*FastLog2(a)); +} +float FastPow10( float i ) +{ + return FastPow2( i * 3.321928f ); +} + diff --git a/mathlib/quantize.cpp b/mathlib/quantize.cpp new file mode 100644 index 0000000..868e606 --- /dev/null +++ b/mathlib/quantize.cpp @@ -0,0 +1,679 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef STDIO_H +#include +#endif + +#ifndef STRING_H +#include +#endif + +#ifndef QUANTIZE_H +#include +#endif + +#include +#include + +#include + +static int current_ndims; +static struct QuantizedValue *current_root; +static int current_ssize; + +static uint8 *current_weights; + +double SquaredError; + +#define SPLIT_THEN_SORT 1 + +#define SQ(x) ((x)*(x)) + +static struct QuantizedValue *AllocQValue(void) +{ + struct QuantizedValue *ret=new QuantizedValue; + ret->Samples=0; + ret->Children[0]=ret->Children[1]=0; + ret->NSamples=0; + + ret->ErrorMeasure=new double[current_ndims]; + ret->Mean=new uint8[current_ndims]; + ret->Mins=new uint8[current_ndims]; + ret->Maxs=new uint8[current_ndims]; + ret->Sums=new int [current_ndims]; + memset(ret->Sums,0,sizeof(int)*current_ndims); + ret->NQuant=0; + ret->sortdim=-1; + return ret; +} + +void FreeQuantization(struct QuantizedValue *t) +{ + if (t) + { + delete[] t->ErrorMeasure; + delete[] t->Mean; + delete[] t->Mins; + delete[] t->Maxs; + FreeQuantization(t->Children[0]); + FreeQuantization(t->Children[1]); + delete[] t->Sums; + delete[] t; + } +} + +static int QNumSort(void const *a, void const *b) +{ + int32 as=((struct Sample *) a)->QNum; + int32 bs=((struct Sample *) b)->QNum; + if (as==bs) return 0; + return (as>bs)?1:-1; +} + +#if SPLIT_THEN_SORT +#else +static int current_sort_dim; + +static int samplesort(void const *a, void const *b) +{ + uint8 as=((struct Sample *) a)->Value[current_sort_dim]; + uint8 bs=((struct Sample *) b)->Value[current_sort_dim]; + if (as==bs) return 0; + return (as>bs)?1:-1; +} +#endif + +static int sortlong(void const *a, void const *b) +{ + // treat the entire vector of values as a long integer for duplicate removal. + return memcmp(((struct Sample *) a)->Value, + ((struct Sample *) b)->Value,current_ndims); +} + + + +#define NEXTSAMPLE(s) ( (struct Sample *) (((uint8 *) s)+current_ssize)) +#define SAMPLE(s,i) NthSample(s,i,current_ndims) + +static void SetNDims(int n) +{ + current_ssize=sizeof(struct Sample)+(n-1); + current_ndims=n; +} + +int CompressSamples(struct Sample *s, int nsamples, int ndims) +{ + SetNDims(ndims); + qsort(s,nsamples,current_ssize,sortlong); + // now, they are all sorted by treating all dimensions as a large number. + // we may now remove duplicates. + struct Sample *src=s; + struct Sample *dst=s; + struct Sample *lastdst=dst; + dst=NEXTSAMPLE(dst); // copy first sample to get the ball rolling + src=NEXTSAMPLE(src); + int noutput=1; + while(--nsamples) // while some remain + { + if (memcmp(src->Value,lastdst->Value,current_ndims)) + { + // yikes, a difference has been found! + memcpy(dst,src,current_ssize); + lastdst=dst; + dst=NEXTSAMPLE(dst); + noutput++; + } + else + lastdst->Count++; + src=NEXTSAMPLE(src); + } + return noutput; +} + +void PrintSamples(struct Sample const *s, int nsamples, int ndims) +{ + SetNDims(ndims); + int cnt=0; + while(nsamples--) + { + printf("sample #%d, count=%d, values=\n { ",cnt++,s->Count); + for(int d=0;dValue[d]); + printf("}\n"); + s=NEXTSAMPLE(s); + } +} + +void PrintQTree(struct QuantizedValue const *p,int idlevel) +{ + int i; + + if (p) + { + for(i=0;iNSamples,p->value); + for(i=0;iMean[i]); + printf("}\n"); + for(i=0;iErrorMeasure[i]); + printf("}\n"); + for(i=0;iMins[i]); + printf("} Maxs={"); + for(i=0;iMaxs[i]); + printf("}\n"); + PrintQTree(p->Children[0],idlevel+2); + PrintQTree(p->Children[1],idlevel+2); + } +} + +static void UpdateStats(struct QuantizedValue *v) +{ + // first, find mean + int32 Means[MAXDIMS]; + double Errors[MAXDIMS]; + double WorstError[MAXDIMS]; + int i,j; + + memset(Means,0,sizeof(Means)); + int N=0; + for(i=0;iNSamples;i++) + { + struct Sample *s=SAMPLE(v->Samples,i); + N+=s->Count; + for(j=0;jValue[j]; + Means[j]+=v*s->Count; + } + } + for(j=0;jMean[j]=(uint8) (Means[j]/N); + Errors[j]=WorstError[j]=0.; + } + for(i=0;iNSamples;i++) + { + struct Sample *s=SAMPLE(v->Samples,i); + double c=s->Count; + for(j=0;jValue[j]-v->Mean[j]); + Errors[j]+=c*diff; // charles uses abs not sq() + if (diff>WorstError[j]) + WorstError[j]=diff; + } + } + v->TotalError=0.; + double ErrorScale=1.; // /sqrt((double) (N)); + for(j=0;jErrorMeasure[j]=(ErrorScale*Errors[j]*current_weights[j]); + v->TotalError+=v->ErrorMeasure[j]; +#if SPLIT_THEN_SORT + v->ErrorMeasure[j]*=WorstError[j]; +#endif + } + v->TotSamples=N; +} + +static int ErrorDim; +static double ErrorVal; +static struct QuantizedValue *ErrorNode; + +static void UpdateWorst(struct QuantizedValue *q) +{ + if (q->Children[0]) + { + // not a leaf node + UpdateWorst(q->Children[0]); + UpdateWorst(q->Children[1]); + } + else + { + if (q->TotalError>ErrorVal) + { + ErrorVal=q->TotalError; + ErrorNode=q; + ErrorDim=0; + for(int d=0;dErrorMeasure[d]>q->ErrorMeasure[ErrorDim]) + ErrorDim=d; + } + } +} + +static int FindWorst(void) +{ + ErrorVal=-1.; + UpdateWorst(current_root); + return (ErrorVal>0); +} + + + +static void SubdivideNode(struct QuantizedValue *n, int whichdim) +{ + int NAdded=0; + int i; + +#if SPLIT_THEN_SORT + // we will try the "split then sort" method. This works by finding the + // means for all samples above and below the mean along the given axis. + // samples are then split into two groups, with the selection based upon + // which of the n-dimensional means the sample is closest to. + double LocalMean[MAXDIMS][2]; + int totsamps[2]; + for(i=0;iNSamples;i++) + { + uint8 v; + int whichside=1; + struct Sample *sl; + sl=SAMPLE(n->Samples,i); + v=sl->Value[whichdim]; + if (vmaxv) { maxv=v; maxS=sl; } + if (vMean[whichdim]) + whichside=0; + totsamps[whichside]+=sl->Count; + for(int d=0;dCount*sl->Value[d]; + } + + if (totsamps[0] && totsamps[1]) + for(i=0;iValue[i]; + LocalMean[i][1]=maxS->Value[i]; + } + } + + // now, we have 2 n-dimensional means. We will label each sample + // for which one it is nearer to by using the QNum field. + for(i=0;iNSamples;i++) + { + double dist[2]; + dist[0]=dist[1]=0.; + struct Sample *s=SAMPLE(n->Samples,i); + for(int d=0;dValue[d]); + s->QNum=(dist[0]sortdim=-1; + qsort(n->Samples,n->NSamples,current_ssize,QNumSort); + for(i=0;iNSamples;i++,NAdded++) + if (SAMPLE(n->Samples,i)->QNum) + break; + +#else + if (whichdim != n->sortdim) + { + current_sort_dim=whichdim; + qsort(n->Samples,n->NSamples,current_ssize,samplesort); + n->sortdim=whichdim; + } + // now, the samples are sorted along the proper dimension. we need + // to find the place to cut in order to split the node. this is + // complicated by the fact that each sample entry can represent many + // samples. What we will do is start at the beginning of the array, + // adding samples to the first node, until either the number added + // is >=TotSamples/2, or there is only one left. + int TotAdded=0; + for(;;) + { + if (NAdded==n->NSamples-1) + break; + if (TotAdded>=n->TotSamples/2) + break; + TotAdded+=SAMPLE(n->Samples,NAdded)->Count; + NAdded++; + } +#endif + struct QuantizedValue *a=AllocQValue(); + a->sortdim=n->sortdim; + a->Samples=n->Samples; + a->NSamples=NAdded; + n->Children[0]=a; + UpdateStats(a); + a=AllocQValue(); + a->Samples=SAMPLE(n->Samples,NAdded); + a->NSamples=n->NSamples-NAdded; + a->sortdim=n->sortdim; + n->Children[1]=a; + UpdateStats(a); +} + +static int colorid=0; + +static void Label(struct QuantizedValue *q, int updatecolor) +{ + // fill in max/min values for tree, etc. + if (q) + { + Label(q->Children[0],updatecolor); + Label(q->Children[1],updatecolor); + if (! q->Children[0]) // leaf node? + { + if (updatecolor) + { + q->value=colorid++; + for(int j=0;jNSamples;j++) + { + SAMPLE(q->Samples,j)->QNum=q->value; + SAMPLE(q->Samples,j)->qptr=q; + } + } + for(int i=0;iMins[i]=q->Mean[i]; + q->Maxs[i]=q->Mean[i]; + } + } + else + for(int i=0;iMins[i]=vmin(q->Children[0]->Mins[i],q->Children[1]->Mins[i]); + q->Maxs[i]=vmax(q->Children[0]->Maxs[i],q->Children[1]->Maxs[i]); + } + } +} + +struct QuantizedValue *FindQNode(struct QuantizedValue const *q, int32 code) +{ + if (! (q->Children[0])) + if (code==q->value) return (struct QuantizedValue *) q; + else return 0; + else + { + struct QuantizedValue *found=FindQNode(q->Children[0],code); + if (! found) found=FindQNode(q->Children[1],code); + return found; + } +} + + +void CheckInRange(struct QuantizedValue *q, uint8 *max, uint8 *min) +{ + if (q) + { + if (q->Children[0]) + { + // non-leaf node + CheckInRange(q->Children[0],q->Maxs, q->Mins); + CheckInRange(q->Children[1],q->Maxs, q->Mins); + CheckInRange(q->Children[0],max, min); + CheckInRange(q->Children[1],max, min); + } + for (int i=0;iMaxs[i]>max[i]) printf("error1\n"); + if (q->Mins[i]Samples=s; + current_root->NSamples=nsamples; + UpdateStats(current_root); + while(--nvalues) + { + if (! FindWorst()) + break; // if Mins[i]<=val2) && (q->Maxs[i]>=val2)) val1=val2; + else + { + val1=(val2<=q->Mins[i])?q->Mins[i]:q->Maxs[i]; + } + err+=weights[i]*SQ(val1-val2); + } + return err; +} + +double MaximumError(struct QuantizedValue const *q, uint8 const *sample, + int ndims, uint8 const *weights) +{ + double err=0; + for(int i=0;iMins[i])>abs(val2-q->Maxs[i]))? + q->Mins[i]: + q->Maxs[i]; + err+=weights[i]*SQ(val2-val1); + } + return err; +} + + + +// heap (priority queue) routines used for nearest-neghbor searches +struct FHeap { + int heap_n; + double *heap[MAXQUANT]; +}; + +void InitHeap(struct FHeap *h) +{ + h->heap_n=0; +} + + +void UpHeap(int k, struct FHeap *h) +{ + double *tmpk=h->heap[k]; + double tmpkn=*tmpk; + while((k>1) && (tmpkn <= *(h->heap[k/2]))) + { + h->heap[k]=h->heap[k/2]; + k/=2; + } + h->heap[k]=tmpk; +} + +void HeapInsert(struct FHeap *h,double *elem) +{ + h->heap_n++; + h->heap[h->heap_n]=elem; + UpHeap(h->heap_n,h); +} + +void DownHeap(int k, struct FHeap *h) +{ + double *v=h->heap[k]; + while(k<=h->heap_n/2) + { + int j=2*k; + if (jheap_n) + if (*(h->heap[j]) >= *(h->heap[j+1])) + j++; + if (*v < *(h->heap[j])) + { + h->heap[k]=v; + return; + } + h->heap[k]=h->heap[j]; k=j; + } + h->heap[k]=v; +} + +void *RemoveHeapItem(struct FHeap *h) +{ + void *ret=0; + if (h->heap_n!=0) + { + ret=h->heap[1]; + h->heap[1]=h->heap[h->heap_n]; + h->heap_n--; + DownHeap(1,h); + } + return ret; +} + +// now, nearest neighbor finder. Use a heap to traverse the tree, stopping +// when there are no nodes with a minimum error < the current error. + +struct FHeap TheQueue; + +#define PUSHNODE(a) { \ + (a)->MinError=MinimumError(a,sample,ndims,weights); \ + if ((a)->MinError < besterror) HeapInsert(&TheQueue,&(a)->MinError); \ + } + +struct QuantizedValue *FindMatch(uint8 const *sample, int ndims, + uint8 *weights, struct QuantizedValue *q) +{ + InitHeap(&TheQueue); + struct QuantizedValue *bestmatch=0; + double besterror=1.0e63; + PUSHNODE(q); + for(;;) + { + struct QuantizedValue *test=(struct QuantizedValue *) + RemoveHeapItem(&TheQueue); + if (! test) break; // heap empty +// printf("got pop node =%p minerror=%f\n",test,test->MinError); + + if (test->MinError>besterror) break; + if (test->Children[0]) + { + // it's a parent node. put the children on the queue + struct QuantizedValue *c1=test->Children[0]; + struct QuantizedValue *c2=test->Children[1]; + c1->MinError=MinimumError(c1,sample,ndims,weights); + if (c1->MinError < besterror) + HeapInsert(&TheQueue,&(c1->MinError)); + c2->MinError=MinimumError(c2,sample,ndims,weights); + if (c2->MinError < besterror) + HeapInsert(&TheQueue,&(c2->MinError)); + } + else + { + // it's a leaf node. This must be a new minimum or the MinError + // test would have failed. + if (test->MinError < besterror) + { + bestmatch=test; + besterror=test->MinError; + } + } + } + if (bestmatch) + { + SquaredError+=besterror; + bestmatch->NQuant++; + for(int i=0;iSums[i]+=sample[i]; + } + return bestmatch; +} + +static void RecalcMeans(struct QuantizedValue *q) +{ + if (q) + { + if (q->Children[0]) + { + // not a leaf, invoke recursively. + RecalcMeans(q->Children[0]); + RecalcMeans(q->Children[0]); + } + else + { + // it's a leaf. Set the means + if (q->NQuant) + { + for(int i=0;iMean[i]=(uint8) (q->Sums[i]/q->NQuant); + q->Sums[i]=0; + } + q->NQuant=0; + } + } + } +} + +void OptimizeQuantizer(struct QuantizedValue *q, int ndims) +{ + SetNDims(ndims); + RecalcMeans(q); // reset q values + Label(q,0); // update max/mins +} + + +static void RecalcStats(struct QuantizedValue *q) +{ + if (q) + { + UpdateStats(q); + RecalcStats(q->Children[0]); + RecalcStats(q->Children[1]); + } +} + +void RecalculateValues(struct QuantizedValue *q, int ndims) +{ + SetNDims(ndims); + RecalcStats(q); + Label(q,0); +} diff --git a/mathlib/randsse.cpp b/mathlib/randsse.cpp new file mode 100644 index 0000000..b718d39 --- /dev/null +++ b/mathlib/randsse.cpp @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: generates 4 randum numbers in the range 0..1 quickly, using SIMD +// +//=====================================================================================// + +#include +#include // Needed for FLT_EPSILON +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "mathlib/ssemath.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// see knuth volume 3 for insight. + +class SIMDRandStreamContext +{ + fltx4 m_RandY[55]; + + fltx4 *m_pRand_J, *m_pRand_K; + + +public: + void Seed( uint32 seed ) + { + m_pRand_J=m_RandY+23; m_pRand_K=m_RandY+54; + for(int i=0;i<55;i++) + { + for(int j=0;j<4;j++) + { + SubFloat( m_RandY[i], j) = (seed>>16)/65536.0; + seed=(seed+1)*3141592621u; + } + } + } + + inline fltx4 RandSIMD( void ) + { + // ret= rand[k]+rand[j] + fltx4 retval=AddSIMD( *m_pRand_K, *m_pRand_J ); + + // if ( ret>=1.0) ret-=1.0 + fltx4 overflow_mask=CmpGeSIMD( retval, Four_Ones ); + retval=SubSIMD( retval, AndSIMD( Four_Ones, overflow_mask ) ); + + *m_pRand_K = retval; + + // update pointers w/ wrap-around + if ( --m_pRand_J < m_RandY ) + m_pRand_J=m_RandY+54; + if ( --m_pRand_K < m_RandY ) + m_pRand_K=m_RandY+54; + + return retval; + } +}; + +#define MAX_SIMULTANEOUS_RANDOM_STREAMS 32 + +static SIMDRandStreamContext s_SIMDRandContexts[MAX_SIMULTANEOUS_RANDOM_STREAMS]; + +static volatile int s_nRandContextsInUse[MAX_SIMULTANEOUS_RANDOM_STREAMS]; + +void SeedRandSIMD(uint32 seed) +{ + for( int i = 0; i> 2); + int ntrailing_pixels_per_source_line=(srcwidth & 3); + for(int y=0;y( p_write_ptr ); + // copy full input blocks + for(int x=0;xx=Pow_FixedPoint_Exponent_SIMD( src->x, fixed_point_exp ); + src->y=Pow_FixedPoint_Exponent_SIMD( src->y, fixed_point_exp ); + src->z=Pow_FixedPoint_Exponent_SIMD( src->z, fixed_point_exp ); + src++; + } while (--nv); + } +} + +CSIMDVectorMatrix & CSIMDVectorMatrix::operator+=( CSIMDVectorMatrix const &src ) +{ + Assert( m_nWidth == src.m_nWidth ); + Assert( m_nHeight == src.m_nHeight ); + int nv=NVectors(); + if ( nv ) + { + FourVectors *srcv=src.m_pData; + FourVectors *destv=m_pData; + do // !! speed !! inline more iters + { + *( destv++ ) += *( srcv++ ); + } while ( --nv ); + } + return *this; +} + +CSIMDVectorMatrix & CSIMDVectorMatrix::operator*=( Vector const &src ) +{ + int nv=NVectors(); + if ( nv ) + { + FourVectors scalevalue; + scalevalue.DuplicateVector( src ); + FourVectors *destv=m_pData; + do // !! speed !! inline more iters + { + destv->VProduct( scalevalue ); + destv++; + } while ( --nv ); + } + return *this; +} + diff --git a/mathlib/sparse_convolution_noise.cpp b/mathlib/sparse_convolution_noise.cpp new file mode 100644 index 0000000..be1426d --- /dev/null +++ b/mathlib/sparse_convolution_noise.cpp @@ -0,0 +1,218 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: noise() primitives. +// +//=====================================================================================// + +#include +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "mathlib/noise.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// generate high quality noise based upon "sparse convolution". HIgher quality than perlin noise, +// and no direcitonal artifacts. + +#include "noisedata.h" + +#define N_IMPULSES_PER_CELL 5 +#define NORMALIZING_FACTOR 1.0 + +//(0.5/N_IMPULSES_PER_CELL) + +static inline int LatticeCoord(float x) +{ + return ((int) floor(x)) & 0xff; +} + +static inline int Hash4D(int ix, int iy, int iz, int idx) +{ + int ret=perm_a[ix]; + ret=perm_b[(ret+iy) & 0xff]; + ret=perm_c[(ret+iz) & 0xff]; + ret=perm_d[(ret+idx) & 0xff]; + return ret; +} + +#define SQ(x) ((x)*(x)) + +static float CellNoise( int ix, int iy, int iz, float xfrac, float yfrac, float zfrac, + float (*pNoiseShapeFunction)(float) ) +{ + float ret=0; + for(int idx=0;idx +#include // Needed for FLT_EPSILON +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "mathlib/spherical_geometry.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +float s_flFactorials[]={ + 1.f, + 1.f, + 2.f, + 6.f, + 24.f, + 120.f, + 720.f, + 5040.f, + 40320.f, + 362880.f, + 3628800.f, + 39916800.f, + 479001600.f, + 6227020800.f, + 87178291200.f, + 1307674368000.f, + 20922789888000.f, + 355687428096000.f, + 6402373705728000.f, + 121645100408832000.f, + 2432902008176640000.f, + 51090942171709440000.f, + 1124000727777607680000.f, + 25852016738884976640000.f, + 620448401733239439360000.f, + 15511210043330985984000000.f, + 403291461126605635584000000.f, + 10888869450418352160768000000.f, + 304888344611713860501504000000.f, + 8841761993739701954543616000000.f, + 265252859812191058636308480000000.f, + 8222838654177922817725562880000000.f, + 263130836933693530167218012160000000.f, + 8683317618811886495518194401280000000.f +}; + +float AssociatedLegendrePolynomial( int nL, int nM, float flX ) +{ + // evaluate associated legendre polynomial at flX, using recurrence relation + float flPmm = 1.; + if ( nM > 0 ) + { + float flSomX2 = sqrt( ( 1 - flX ) * ( 1 + flX ) ); + float flFact = 1.; + for( int i = 0 ; i < nM; i++ ) + { + flPmm *= -flFact * flSomX2; + flFact += 2.0; + } + } + if ( nL == nM ) + return flPmm; + float flPmmp1 = flX * ( 2.0 * nM + 1.0 ) * flPmm; + if ( nL == nM + 1 ) + return flPmmp1; + float flPll = 0.; + for( int nLL = nM + 2 ; nLL <= nL; nLL++ ) + { + flPll = ( ( 2.0 * nLL - 1.0 ) * flX * flPmmp1 - ( nLL + nM - 1.0 ) * flPmm ) * ( 1.0 / ( nLL - nM ) ); + flPmm = flPmmp1; + flPmmp1 = flPll; + } + return flPll; +} + +static float SHNormalizationFactor( int nL, int nM ) +{ + double flTemp = ( ( 2. * nL + 1.0 ) * s_flFactorials[ nL - nM ] )/ ( 4. * M_PI * s_flFactorials[ nL + nM ] ); + return sqrt( flTemp ); +} + +#define SQRT_2 1.414213562373095 + +FORCEINLINE float SphericalHarmonic( int nL, int nM, float flTheta, float flPhi, float flCosTheta ) +{ + if ( nM == 0 ) + return SHNormalizationFactor( nL, 0 ) * AssociatedLegendrePolynomial( nL, nM, flCosTheta ); + + if ( nM > 0 ) + return SQRT_2 * SHNormalizationFactor( nL, nM ) * cos ( nM * flPhi ) * + AssociatedLegendrePolynomial( nL, nM, flCosTheta ); + + return + SQRT_2 * SHNormalizationFactor( nL, -nM ) * sin( -nM * flPhi ) * AssociatedLegendrePolynomial( nL, -nM, flCosTheta ); + +} + +float SphericalHarmonic( int nL, int nM, float flTheta, float flPhi ) +{ + return SphericalHarmonic( nL, nM, flTheta, flPhi, cos( flTheta ) ); +} + +float SphericalHarmonic( int nL, int nM, Vector const &vecDirection ) +{ + Assert( fabs( VectorLength( vecDirection ) - 1.0 ) < 0.0001 ); + float flPhi = acos( vecDirection.z ); + float flTheta = 0; + float S = Square( vecDirection.x ) + Square( vecDirection.y ); + if ( S > 0 ) + { + flTheta = atan2( vecDirection.y, vecDirection.x ); + } + return SphericalHarmonic( nL, nM, flTheta, flPhi, cos( flTheta ) ); +} + diff --git a/mathlib/sse.cpp b/mathlib/sse.cpp new file mode 100644 index 0000000..dd03648 --- /dev/null +++ b/mathlib/sse.cpp @@ -0,0 +1,1107 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: SSE Math primitives. +// +//=====================================================================================// + +#include +#include // Needed for FLT_EPSILON +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "sse.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifndef COMPILER_MSVC64 +// Implement for 64-bit Windows if needed. + +static const uint32 _sincos_masks[] = { (uint32)0x0, (uint32)~0x0 }; +static const uint32 _sincos_inv_masks[] = { (uint32)~0x0, (uint32)0x0 }; + +//----------------------------------------------------------------------------- +// Macros and constants required by some of the SSE assembly: +//----------------------------------------------------------------------------- + +#ifdef _WIN32 + #define _PS_EXTERN_CONST(Name, Val) \ + const __declspec(align(16)) float _ps_##Name[4] = { Val, Val, Val, Val } + + #define _PS_EXTERN_CONST_TYPE(Name, Type, Val) \ + const __declspec(align(16)) Type _ps_##Name[4] = { Val, Val, Val, Val }; \ + + #define _EPI32_CONST(Name, Val) \ + static const __declspec(align(16)) __int32 _epi32_##Name[4] = { Val, Val, Val, Val } + + #define _PS_CONST(Name, Val) \ + static const __declspec(align(16)) float _ps_##Name[4] = { Val, Val, Val, Val } +#elif POSIX + #define _PS_EXTERN_CONST(Name, Val) \ + const float _ps_##Name[4] __attribute__((aligned(16))) = { Val, Val, Val, Val } + + #define _PS_EXTERN_CONST_TYPE(Name, Type, Val) \ + const Type _ps_##Name[4] __attribute__((aligned(16))) = { Val, Val, Val, Val }; \ + + #define _EPI32_CONST(Name, Val) \ + static const int32 _epi32_##Name[4] __attribute__((aligned(16))) = { Val, Val, Val, Val } + + #define _PS_CONST(Name, Val) \ + static const float _ps_##Name[4] __attribute__((aligned(16))) = { Val, Val, Val, Val } +#endif + +_PS_EXTERN_CONST(am_0, 0.0f); +_PS_EXTERN_CONST(am_1, 1.0f); +_PS_EXTERN_CONST(am_m1, -1.0f); +_PS_EXTERN_CONST(am_0p5, 0.5f); +_PS_EXTERN_CONST(am_1p5, 1.5f); +_PS_EXTERN_CONST(am_pi, (float)M_PI); +_PS_EXTERN_CONST(am_pi_o_2, (float)(M_PI / 2.0)); +_PS_EXTERN_CONST(am_2_o_pi, (float)(2.0 / M_PI)); +_PS_EXTERN_CONST(am_pi_o_4, (float)(M_PI / 4.0)); +_PS_EXTERN_CONST(am_4_o_pi, (float)(4.0 / M_PI)); +_PS_EXTERN_CONST_TYPE(am_sign_mask, int32, (int32)0x80000000); +_PS_EXTERN_CONST_TYPE(am_inv_sign_mask, int32, ~0x80000000); +_PS_EXTERN_CONST_TYPE(am_min_norm_pos,int32, 0x00800000); +_PS_EXTERN_CONST_TYPE(am_mant_mask, int32, 0x7f800000); +_PS_EXTERN_CONST_TYPE(am_inv_mant_mask, int32, (int32)~0x7f800000); + +_EPI32_CONST(1, 1); +_EPI32_CONST(2, 2); + +_PS_CONST(sincos_p0, 0.15707963267948963959e1f); +_PS_CONST(sincos_p1, -0.64596409750621907082e0f); +_PS_CONST(sincos_p2, 0.7969262624561800806e-1f); +_PS_CONST(sincos_p3, -0.468175413106023168e-2f); + +#ifdef PFN_VECTORMA +void __cdecl _SSE_VectorMA( const float *start, float scale, const float *direction, float *dest ); +#endif + +//----------------------------------------------------------------------------- +// SSE implementations of optimized routines: +//----------------------------------------------------------------------------- +float _SSE_Sqrt(float x) +{ + Assert( s_bMathlibInitialized ); + float root = 0.f; +#ifdef _WIN32 + _asm + { + sqrtss xmm0, x + movss root, xmm0 + } +#elif POSIX + _mm_store_ss( &root, _mm_sqrt_ss( _mm_load_ss( &x ) ) ); +#endif + return root; +} + +// Single iteration NewtonRaphson reciprocal square root: +// 0.5 * rsqrtps * (3 - x * rsqrtps(x) * rsqrtps(x)) +// Very low error, and fine to use in place of 1.f / sqrtf(x). +#if 0 +float _SSE_RSqrtAccurate(float x) +{ + Assert( s_bMathlibInitialized ); + + float rroot; + _asm + { + rsqrtss xmm0, x + movss rroot, xmm0 + } + + return (0.5f * rroot) * (3.f - (x * rroot) * rroot); +} +#else + +#ifdef POSIX +const __m128 f3 = _mm_set_ss(3.0f); // 3 as SSE value +const __m128 f05 = _mm_set_ss(0.5f); // 0.5 as SSE value +#endif + +// Intel / Kipps SSE RSqrt. Significantly faster than above. +float _SSE_RSqrtAccurate(float a) +{ + +#ifdef _WIN32 + float x; + float half = 0.5f; + float three = 3.f; + + __asm + { + movss xmm3, a; + movss xmm1, half; + movss xmm2, three; + rsqrtss xmm0, xmm3; + + mulss xmm3, xmm0; + mulss xmm1, xmm0; + mulss xmm3, xmm0; + subss xmm2, xmm3; + mulss xmm1, xmm2; + + movss x, xmm1; + } + + return x; +#elif POSIX + __m128 xx = _mm_load_ss( &a ); + __m128 xr = _mm_rsqrt_ss( xx ); + __m128 xt; + + xt = _mm_mul_ss( xr, xr ); + xt = _mm_mul_ss( xt, xx ); + xt = _mm_sub_ss( f3, xt ); + xt = _mm_mul_ss( xt, f05 ); + xr = _mm_mul_ss( xr, xt ); + + _mm_store_ss( &a, xr ); + return a; +#else + #error "Not Implemented" +#endif + +} +#endif + +// Simple SSE rsqrt. Usually accurate to around 6 (relative) decimal places +// or so, so ok for closed transforms. (ie, computing lighting normals) +float _SSE_RSqrtFast(float x) +{ + Assert( s_bMathlibInitialized ); + + float rroot; +#ifdef _WIN32 + _asm + { + rsqrtss xmm0, x + movss rroot, xmm0 + } +#elif POSIX + __asm__ __volatile__( "rsqrtss %0, %1" : "=x" (rroot) : "x" (x) ); +#else +#error +#endif + + return rroot; +} + +float FASTCALL _SSE_VectorNormalize (Vector& vec) +{ + Assert( s_bMathlibInitialized ); + + // NOTE: This is necessary to prevent an memory overwrite... + // sice vec only has 3 floats, we can't "movaps" directly into it. +#ifdef _WIN32 + __declspec(align(16)) float result[4]; +#elif POSIX + float result[4] __attribute__((aligned(16))); +#endif + + float *v = &vec[0]; +#ifdef _WIN32 + float *r = &result[0]; +#endif + + float radius = 0.f; + // Blah, get rid of these comparisons ... in reality, if you have all 3 as zero, it shouldn't + // be much of a performance win, considering you will very likely miss 3 branch predicts in a row. + if ( v[0] || v[1] || v[2] ) + { +#ifdef _WIN32 + _asm + { + mov eax, v + mov edx, r +#ifdef ALIGNED_VECTOR + movaps xmm4, [eax] // r4 = vx, vy, vz, X + movaps xmm1, xmm4 // r1 = r4 +#else + movups xmm4, [eax] // r4 = vx, vy, vz, X + movaps xmm1, xmm4 // r1 = r4 +#endif + mulps xmm1, xmm4 // r1 = vx * vx, vy * vy, vz * vz, X + movhlps xmm3, xmm1 // r3 = vz * vz, X, X, X + movaps xmm2, xmm1 // r2 = r1 + shufps xmm2, xmm2, 1 // r2 = vy * vy, X, X, X + addss xmm1, xmm2 // r1 = (vx * vx) + (vy * vy), X, X, X + addss xmm1, xmm3 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X + sqrtss xmm1, xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X + movss radius, xmm1 // radius = sqrt((vx * vx) + (vy * vy) + (vz * vz)) + rcpss xmm1, xmm1 // r1 = 1/radius, X, X, X + shufps xmm1, xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X + mulps xmm4, xmm1 // r4 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X + movaps [edx], xmm4 // v = vx * 1/radius, vy * 1/radius, vz * 1/radius, X + } +#elif POSIX + __asm__ __volatile__( +#ifdef ALIGNED_VECTOR + "movaps %2, %%xmm4 \n\t" + "movaps %%xmm4, %%xmm1 \n\t" +#else + "movups %2, %%xmm4 \n\t" + "movaps %%xmm4, %%xmm1 \n\t" +#endif + "mulps %%xmm4, %%xmm1 \n\t" + "movhlps %%xmm1, %%xmm3 \n\t" + "movaps %%xmm1, %%xmm2 \n\t" + "shufps $1, %%xmm2, %%xmm2 \n\t" + "addss %%xmm2, %%xmm1 \n\t" + "addss %%xmm3, %%xmm1 \n\t" + "sqrtss %%xmm1, %%xmm1 \n\t" + "movss %%xmm1, %0 \n\t" + "rcpss %%xmm1, %%xmm1 \n\t" + "shufps $0, %%xmm1, %%xmm1 \n\t" + "mulps %%xmm1, %%xmm4 \n\t" + "movaps %%xmm4, %1 \n\t" + : "=m" (radius), "=m" (result) + : "m" (*v) + : "xmm1", "xmm2", "xmm3", "xmm4" + ); +#else + #error "Not Implemented" +#endif + vec.x = result[0]; + vec.y = result[1]; + vec.z = result[2]; + + } + + return radius; +} + +void FASTCALL _SSE_VectorNormalizeFast (Vector& vec) +{ + float ool = _SSE_RSqrtAccurate( FLT_EPSILON + vec.x * vec.x + vec.y * vec.y + vec.z * vec.z ); + + vec.x *= ool; + vec.y *= ool; + vec.z *= ool; +} + +float _SSE_InvRSquared(const float* v) +{ + float inv_r2 = 1.f; +#ifdef _WIN32 + _asm { // Intel SSE only routine + mov eax, v + movss xmm5, inv_r2 // x5 = 1.0, 0, 0, 0 +#ifdef ALIGNED_VECTOR + movaps xmm4, [eax] // x4 = vx, vy, vz, X +#else + movups xmm4, [eax] // x4 = vx, vy, vz, X +#endif + movaps xmm1, xmm4 // x1 = x4 + mulps xmm1, xmm4 // x1 = vx * vx, vy * vy, vz * vz, X + movhlps xmm3, xmm1 // x3 = vz * vz, X, X, X + movaps xmm2, xmm1 // x2 = x1 + shufps xmm2, xmm2, 1 // x2 = vy * vy, X, X, X + addss xmm1, xmm2 // x1 = (vx * vx) + (vy * vy), X, X, X + addss xmm1, xmm3 // x1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X + maxss xmm1, xmm5 // x1 = max( 1.0, x1 ) + rcpss xmm0, xmm1 // x0 = 1 / max( 1.0, x1 ) + movss inv_r2, xmm0 // inv_r2 = x0 + } +#elif POSIX + __asm__ __volatile__( + "movss %0, %%xmm5 \n\t" +#ifdef ALIGNED_VECTOR + "movaps %1, %%xmm4 \n\t" +#else + "movups %1, %%xmm4 \n\t" +#endif + "movaps %%xmm4, %%xmm1 \n\t" + "mulps %%xmm4, %%xmm1 \n\t" + "movhlps %%xmm1, %%xmm3 \n\t" + "movaps %%xmm1, %%xmm2 \n\t" + "shufps $1, %%xmm2, %%xmm2 \n\t" + "addss %%xmm2, %%xmm1 \n\t" + "addss %%xmm3, %%xmm1 \n\t" + "maxss %%xmm5, %%xmm1 \n\t" + "rcpss %%xmm1, %%xmm0 \n\t" + "movss %%xmm0, %0 \n\t" + : "+m" (inv_r2) + : "m" (*v) + : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +#else + #error "Not Implemented" +#endif + + return inv_r2; +} + + +#ifdef POSIX +// #define _PS_CONST(Name, Val) static const ALIGN16 float _ps_##Name[4] ALIGN16_POST = { Val, Val, Val, Val } +#define _PS_CONST_TYPE(Name, Type, Val) static const ALIGN16 Type _ps_##Name[4] ALIGN16_POST = { Val, Val, Val, Val } + +_PS_CONST_TYPE(sign_mask, int, (int)0x80000000); +_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000); + + +#define _PI32_CONST(Name, Val) static const ALIGN16 int _pi32_##Name[4] ALIGN16_POST = { Val, Val, Val, Val } + +_PI32_CONST(1, 1); +_PI32_CONST(inv1, ~1); +_PI32_CONST(2, 2); +_PI32_CONST(4, 4); +_PI32_CONST(0x7f, 0x7f); +_PS_CONST(1 , 1.0f); +_PS_CONST(0p5, 0.5f); + +_PS_CONST(minus_cephes_DP1, -0.78515625); +_PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4); +_PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8); +_PS_CONST(sincof_p0, -1.9515295891E-4); +_PS_CONST(sincof_p1, 8.3321608736E-3); +_PS_CONST(sincof_p2, -1.6666654611E-1); +_PS_CONST(coscof_p0, 2.443315711809948E-005); +_PS_CONST(coscof_p1, -1.388731625493765E-003); +_PS_CONST(coscof_p2, 4.166664568298827E-002); +_PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI + +typedef union xmm_mm_union { + __m128 xmm; + __m64 mm[2]; +} xmm_mm_union; + +#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; } + +typedef __m128 v4sf; // vector of 4 float (sse1) +typedef __m64 v2si; // vector of 2 int (mmx) + +#endif + +void _SSE_SinCos(float x, float* s, float* c) +{ +#ifdef _WIN32 + float t4, t8, t12; + + __asm + { + movss xmm0, x + movss t12, xmm0 + movss xmm1, _ps_am_inv_sign_mask + mov eax, t12 + mulss xmm0, _ps_am_2_o_pi + andps xmm0, xmm1 + and eax, 0x80000000 + + cvttss2si edx, xmm0 + mov ecx, edx + mov t12, esi + mov esi, edx + add edx, 0x1 + shl ecx, (31 - 1) + shl edx, (31 - 1) + + movss xmm4, _ps_am_1 + cvtsi2ss xmm3, esi + mov t8, eax + and esi, 0x1 + + subss xmm0, xmm3 + movss xmm3, _sincos_inv_masks[esi * 4] + minss xmm0, xmm4 + + subss xmm4, xmm0 + + movss xmm6, xmm4 + andps xmm4, xmm3 + and ecx, 0x80000000 + movss xmm2, xmm3 + andnps xmm3, xmm0 + and edx, 0x80000000 + movss xmm7, t8 + andps xmm0, xmm2 + mov t8, ecx + mov t4, edx + orps xmm4, xmm3 + + mov eax, s //mov eax, [esp + 4 + 16] + mov edx, c //mov edx, [esp + 4 + 16 + 4] + + andnps xmm2, xmm6 + orps xmm0, xmm2 + + movss xmm2, t8 + movss xmm1, xmm0 + movss xmm5, xmm4 + xorps xmm7, xmm2 + movss xmm3, _ps_sincos_p3 + mulss xmm0, xmm0 + mulss xmm4, xmm4 + movss xmm2, xmm0 + movss xmm6, xmm4 + orps xmm1, xmm7 + movss xmm7, _ps_sincos_p2 + mulss xmm0, xmm3 + mulss xmm4, xmm3 + movss xmm3, _ps_sincos_p1 + addss xmm0, xmm7 + addss xmm4, xmm7 + movss xmm7, _ps_sincos_p0 + mulss xmm0, xmm2 + mulss xmm4, xmm6 + addss xmm0, xmm3 + addss xmm4, xmm3 + movss xmm3, t4 + mulss xmm0, xmm2 + mulss xmm4, xmm6 + orps xmm5, xmm3 + mov esi, t12 + addss xmm0, xmm7 + addss xmm4, xmm7 + mulss xmm0, xmm1 + mulss xmm4, xmm5 + + // use full stores since caller might reload with full loads + movss [eax], xmm0 + movss [edx], xmm4 + } +#elif POSIX + + Assert( "Needs testing, verify impl!\n" ); + + v4sf xx = _mm_load_ss( &x ); + + v4sf xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y; + v2si mm0, mm1, mm2, mm3, mm4, mm5; + sign_bit_sin = xx; + /* take the absolute value */ + xx = _mm_and_ps(xx, *(v4sf*)_ps_inv_sign_mask); + /* extract the sign bit (upper one) */ + sign_bit_sin = _mm_and_ps(sign_bit_sin, *(v4sf*)_ps_sign_mask); + + /* scale by 4/Pi */ + y = _mm_mul_ps(xx, *(v4sf*)_ps_cephes_FOPI); + + /* store the integer part of y in mm2:mm3 */ + xmm3 = _mm_movehl_ps(xmm3, y); + mm2 = _mm_cvttps_pi32(y); + mm3 = _mm_cvttps_pi32(xmm3); + + /* j=(j+1) & (~1) (see the cephes sources) */ + mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1); + mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1); + mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1); + mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1); + + y = _mm_cvtpi32x2_ps(mm2, mm3); + + mm4 = mm2; + mm5 = mm3; + + /* get the swap sign flag for the sine */ + mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4); + mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4); + mm0 = _mm_slli_pi32(mm0, 29); + mm1 = _mm_slli_pi32(mm1, 29); + v4sf swap_sign_bit_sin; + COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit_sin); + + /* get the polynom selection mask for the sine */ + + mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2); + mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2); + mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64()); + mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64()); + v4sf poly_mask; + COPY_MM_TO_XMM(mm2, mm3, poly_mask); + + /* The magic pass: "Extended precision modular arithmetic" + x = ((x - y * DP1) - y * DP2) - y * DP3; */ + xmm1 = *(v4sf*)_ps_minus_cephes_DP1; + xmm2 = *(v4sf*)_ps_minus_cephes_DP2; + xmm3 = *(v4sf*)_ps_minus_cephes_DP3; + xmm1 = _mm_mul_ps(y, xmm1); + xmm2 = _mm_mul_ps(y, xmm2); + xmm3 = _mm_mul_ps(y, xmm3); + xx = _mm_add_ps(xx, xmm1); + xx = _mm_add_ps(xx, xmm2); + xx = _mm_add_ps(xx, xmm3); + + /* get the sign flag for the cosine */ + mm4 = _mm_sub_pi32(mm4, *(v2si*)_pi32_2); + mm5 = _mm_sub_pi32(mm5, *(v2si*)_pi32_2); + mm4 = _mm_andnot_si64(mm4, *(v2si*)_pi32_4); + mm5 = _mm_andnot_si64(mm5, *(v2si*)_pi32_4); + mm4 = _mm_slli_pi32(mm4, 29); + mm5 = _mm_slli_pi32(mm5, 29); + v4sf sign_bit_cos; + COPY_MM_TO_XMM(mm4, mm5, sign_bit_cos); + _mm_empty(); /* good-bye mmx */ + + sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin); + + + /* Evaluate the first polynom (0 <= x <= Pi/4) */ + v4sf z = _mm_mul_ps(xx,xx); + y = *(v4sf*)_ps_coscof_p0; + + y = _mm_mul_ps(y, z); + y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1); + y = _mm_mul_ps(y, z); + y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2); + y = _mm_mul_ps(y, z); + y = _mm_mul_ps(y, z); + v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5); + y = _mm_sub_ps(y, tmp); + y = _mm_add_ps(y, *(v4sf*)_ps_1); + + /* Evaluate the second polynom (Pi/4 <= x <= 0) */ + + v4sf y2 = *(v4sf*)_ps_sincof_p0; + y2 = _mm_mul_ps(y2, z); + y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1); + y2 = _mm_mul_ps(y2, z); + y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2); + y2 = _mm_mul_ps(y2, z); + y2 = _mm_mul_ps(y2, xx); + y2 = _mm_add_ps(y2, xx); + + /* select the correct result from the two polynoms */ + xmm3 = poly_mask; + v4sf ysin2 = _mm_and_ps(xmm3, y2); + v4sf ysin1 = _mm_andnot_ps(xmm3, y); + y2 = _mm_sub_ps(y2,ysin2); + y = _mm_sub_ps(y, ysin1); + + xmm1 = _mm_add_ps(ysin1,ysin2); + xmm2 = _mm_add_ps(y,y2); + + /* update the sign */ + _mm_store_ss( s, _mm_xor_ps(xmm1, sign_bit_sin) ); + _mm_store_ss( c, _mm_xor_ps(xmm2, sign_bit_cos) ); + +#else + #error "Not Implemented" +#endif +} + +float _SSE_cos( float x ) +{ +#ifdef _WIN32 + float temp; + __asm + { + movss xmm0, x + movss xmm1, _ps_am_inv_sign_mask + andps xmm0, xmm1 + addss xmm0, _ps_am_pi_o_2 + mulss xmm0, _ps_am_2_o_pi + + cvttss2si ecx, xmm0 + movss xmm5, _ps_am_1 + mov edx, ecx + shl edx, (31 - 1) + cvtsi2ss xmm1, ecx + and edx, 0x80000000 + and ecx, 0x1 + + subss xmm0, xmm1 + movss xmm6, _sincos_masks[ecx * 4] + minss xmm0, xmm5 + + movss xmm1, _ps_sincos_p3 + subss xmm5, xmm0 + + andps xmm5, xmm6 + movss xmm7, _ps_sincos_p2 + andnps xmm6, xmm0 + mov temp, edx + orps xmm5, xmm6 + movss xmm0, xmm5 + + mulss xmm5, xmm5 + movss xmm4, _ps_sincos_p1 + movss xmm2, xmm5 + mulss xmm5, xmm1 + movss xmm1, _ps_sincos_p0 + addss xmm5, xmm7 + mulss xmm5, xmm2 + movss xmm3, temp + addss xmm5, xmm4 + mulss xmm5, xmm2 + orps xmm0, xmm3 + addss xmm5, xmm1 + mulss xmm0, xmm5 + + movss x, xmm0 + + } +#elif POSIX + + Assert( "Needs testing, verify impl!\n" ); + + v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, y; + v2si mm0, mm1, mm2, mm3; + /* take the absolute value */ + v4sf xx = _mm_load_ss( &x ); + + xx = _mm_and_ps(xx, *(v4sf*)_ps_inv_sign_mask); + + /* scale by 4/Pi */ + y = _mm_mul_ps(xx, *(v4sf*)_ps_cephes_FOPI); + + /* store the integer part of y in mm0:mm1 */ + xmm2 = _mm_movehl_ps(xmm2, y); + mm2 = _mm_cvttps_pi32(y); + mm3 = _mm_cvttps_pi32(xmm2); + + /* j=(j+1) & (~1) (see the cephes sources) */ + mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1); + mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1); + mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1); + mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1); + + y = _mm_cvtpi32x2_ps(mm2, mm3); + + + mm2 = _mm_sub_pi32(mm2, *(v2si*)_pi32_2); + mm3 = _mm_sub_pi32(mm3, *(v2si*)_pi32_2); + + /* get the swap sign flag in mm0:mm1 and the + polynom selection mask in mm2:mm3 */ + + mm0 = _mm_andnot_si64(mm2, *(v2si*)_pi32_4); + mm1 = _mm_andnot_si64(mm3, *(v2si*)_pi32_4); + mm0 = _mm_slli_pi32(mm0, 29); + mm1 = _mm_slli_pi32(mm1, 29); + + mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2); + mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2); + + mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64()); + mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64()); + + v4sf sign_bit, poly_mask; + COPY_MM_TO_XMM(mm0, mm1, sign_bit); + COPY_MM_TO_XMM(mm2, mm3, poly_mask); + _mm_empty(); /* good-bye mmx */ + + /* The magic pass: "Extended precision modular arithmetic" + x = ((x - y * DP1) - y * DP2) - y * DP3; */ + xmm1 = *(v4sf*)_ps_minus_cephes_DP1; + xmm2 = *(v4sf*)_ps_minus_cephes_DP2; + xmm3 = *(v4sf*)_ps_minus_cephes_DP3; + xmm1 = _mm_mul_ps(y, xmm1); + xmm2 = _mm_mul_ps(y, xmm2); + xmm3 = _mm_mul_ps(y, xmm3); + xx = _mm_add_ps(xx, xmm1); + xx = _mm_add_ps(xx, xmm2); + xx = _mm_add_ps(xx, xmm3); + + /* Evaluate the first polynom (0 <= x <= Pi/4) */ + y = *(v4sf*)_ps_coscof_p0; + v4sf z = _mm_mul_ps(xx,xx); + + y = _mm_mul_ps(y, z); + y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1); + y = _mm_mul_ps(y, z); + y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2); + y = _mm_mul_ps(y, z); + y = _mm_mul_ps(y, z); + v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5); + y = _mm_sub_ps(y, tmp); + y = _mm_add_ps(y, *(v4sf*)_ps_1); + + /* Evaluate the second polynom (Pi/4 <= x <= 0) */ + + v4sf y2 = *(v4sf*)_ps_sincof_p0; + y2 = _mm_mul_ps(y2, z); + y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1); + y2 = _mm_mul_ps(y2, z); + y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2); + y2 = _mm_mul_ps(y2, z); + y2 = _mm_mul_ps(y2, xx); + y2 = _mm_add_ps(y2, xx); + + /* select the correct result from the two polynoms */ + xmm3 = poly_mask; + y2 = _mm_and_ps(xmm3, y2); //, xmm3); + y = _mm_andnot_ps(xmm3, y); + y = _mm_add_ps(y,y2); + /* update the sign */ + + _mm_store_ss( &x, _mm_xor_ps(y, sign_bit) ); + +#else + #error "Not Implemented" +#endif + + return x; +} + +//----------------------------------------------------------------------------- +// SSE2 implementations of optimized routines: +//----------------------------------------------------------------------------- +#ifdef PLATFORM_WINDOWS_PC32 +void _SSE2_SinCos(float x, float* s, float* c) // any x +{ +#ifdef _WIN32 + __asm + { + movss xmm0, x + movaps xmm7, xmm0 + movss xmm1, _ps_am_inv_sign_mask + movss xmm2, _ps_am_sign_mask + movss xmm3, _ps_am_2_o_pi + andps xmm0, xmm1 + andps xmm7, xmm2 + mulss xmm0, xmm3 + + pxor xmm3, xmm3 + movd xmm5, _epi32_1 + movss xmm4, _ps_am_1 + + cvttps2dq xmm2, xmm0 + pand xmm5, xmm2 + movd xmm1, _epi32_2 + pcmpeqd xmm5, xmm3 + movd xmm3, _epi32_1 + cvtdq2ps xmm6, xmm2 + paddd xmm3, xmm2 + pand xmm2, xmm1 + pand xmm3, xmm1 + subss xmm0, xmm6 + pslld xmm2, (31 - 1) + minss xmm0, xmm4 + + mov eax, s // mov eax, [esp + 4 + 16] + mov edx, c // mov edx, [esp + 4 + 16 + 4] + + subss xmm4, xmm0 + pslld xmm3, (31 - 1) + + movaps xmm6, xmm4 + xorps xmm2, xmm7 + movaps xmm7, xmm5 + andps xmm6, xmm7 + andnps xmm7, xmm0 + andps xmm0, xmm5 + andnps xmm5, xmm4 + movss xmm4, _ps_sincos_p3 + orps xmm6, xmm7 + orps xmm0, xmm5 + movss xmm5, _ps_sincos_p2 + + movaps xmm1, xmm0 + movaps xmm7, xmm6 + mulss xmm0, xmm0 + mulss xmm6, xmm6 + orps xmm1, xmm2 + orps xmm7, xmm3 + movaps xmm2, xmm0 + movaps xmm3, xmm6 + mulss xmm0, xmm4 + mulss xmm6, xmm4 + movss xmm4, _ps_sincos_p1 + addss xmm0, xmm5 + addss xmm6, xmm5 + movss xmm5, _ps_sincos_p0 + mulss xmm0, xmm2 + mulss xmm6, xmm3 + addss xmm0, xmm4 + addss xmm6, xmm4 + mulss xmm0, xmm2 + mulss xmm6, xmm3 + addss xmm0, xmm5 + addss xmm6, xmm5 + mulss xmm0, xmm1 + mulss xmm6, xmm7 + + // use full stores since caller might reload with full loads + movss [eax], xmm0 + movss [edx], xmm6 + } +#elif POSIX + #warning "_SSE2_SinCos NOT implemented!" + Assert( 0 ); +#else + #error "Not Implemented" +#endif +} +#endif // PLATFORM_WINDOWS_PC32 + +#ifdef PLATFORM_WINDOWS_PC32 +float _SSE2_cos(float x) +{ +#ifdef _WIN32 + __asm + { + movss xmm0, x + movss xmm1, _ps_am_inv_sign_mask + movss xmm2, _ps_am_pi_o_2 + movss xmm3, _ps_am_2_o_pi + andps xmm0, xmm1 + addss xmm0, xmm2 + mulss xmm0, xmm3 + + pxor xmm3, xmm3 + movd xmm5, _epi32_1 + movss xmm4, _ps_am_1 + cvttps2dq xmm2, xmm0 + pand xmm5, xmm2 + movd xmm1, _epi32_2 + pcmpeqd xmm5, xmm3 + cvtdq2ps xmm6, xmm2 + pand xmm2, xmm1 + pslld xmm2, (31 - 1) + + subss xmm0, xmm6 + movss xmm3, _ps_sincos_p3 + minss xmm0, xmm4 + subss xmm4, xmm0 + andps xmm0, xmm5 + andnps xmm5, xmm4 + orps xmm0, xmm5 + + movaps xmm1, xmm0 + movss xmm4, _ps_sincos_p2 + mulss xmm0, xmm0 + movss xmm5, _ps_sincos_p1 + orps xmm1, xmm2 + movaps xmm7, xmm0 + mulss xmm0, xmm3 + movss xmm6, _ps_sincos_p0 + addss xmm0, xmm4 + mulss xmm0, xmm7 + addss xmm0, xmm5 + mulss xmm0, xmm7 + addss xmm0, xmm6 + mulss xmm0, xmm1 + movss x, xmm0 + } +#elif POSIX + #warning "_SSE2_cos NOT implemented!" + Assert( 0 ); +#else + #error "Not Implemented" +#endif + + return x; +} +#endif // PLATFORM_WINDOWS_PC32 + +#if 0 +// SSE Version of VectorTransform +void VectorTransformSSE(const float *in1, const matrix3x4_t& in2, float *out1) +{ + Assert( s_bMathlibInitialized ); + Assert( in1 != out1 ); + +#ifdef _WIN32 + __asm + { + mov eax, in1; + mov ecx, in2; + mov edx, out1; + + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + addss xmm0, [ecx+12] + movss [edx], xmm0; + add ecx, 16; + + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + addss xmm0, [ecx+12] + movss [edx+4], xmm0; + add ecx, 16; + + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + addss xmm0, [ecx+12] + movss [edx+8], xmm0; + } +#elif POSIX + #warning "VectorTransformSSE C implementation only" + out1[0] = DotProduct(in1, in2[0]) + in2[0][3]; + out1[1] = DotProduct(in1, in2[1]) + in2[1][3]; + out1[2] = DotProduct(in1, in2[2]) + in2[2][3]; +#else + #error "Not Implemented" +#endif +} +#endif + +#if 0 +void VectorRotateSSE( const float *in1, const matrix3x4_t& in2, float *out1 ) +{ + Assert( s_bMathlibInitialized ); + Assert( in1 != out1 ); + +#ifdef _WIN32 + __asm + { + mov eax, in1; + mov ecx, in2; + mov edx, out1; + + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + movss [edx], xmm0; + add ecx, 16; + + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + movss [edx+4], xmm0; + add ecx, 16; + + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + movss [edx+8], xmm0; + } +#elif POSIX + #warning "VectorRotateSSE C implementation only" + out1[0] = DotProduct( in1, in2[0] ); + out1[1] = DotProduct( in1, in2[1] ); + out1[2] = DotProduct( in1, in2[2] ); +#else + #error "Not Implemented" +#endif +} +#endif + +#ifdef _WIN32 +void _declspec(naked) _SSE_VectorMA( const float *start, float scale, const float *direction, float *dest ) +{ + // FIXME: This don't work!! It will overwrite memory in the write to dest + Assert(0); + + Assert( s_bMathlibInitialized ); + _asm { // Intel SSE only routine + mov eax, DWORD PTR [esp+0x04] ; *start, s0..s2 + mov ecx, DWORD PTR [esp+0x0c] ; *direction, d0..d2 + mov edx, DWORD PTR [esp+0x10] ; *dest + movss xmm2, [esp+0x08] ; x2 = scale, 0, 0, 0 +#ifdef ALIGNED_VECTOR + movaps xmm3, [ecx] ; x3 = dir0,dir1,dir2,X + pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale + movaps xmm1, [eax] ; x1 = start1, start2, start3, X + mulps xmm3, xmm2 ; x3 *= x2 + addps xmm3, xmm1 ; x3 += x1 + movaps [edx], xmm3 ; *dest = x3 +#else + movups xmm3, [ecx] ; x3 = dir0,dir1,dir2,X + pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale + movups xmm1, [eax] ; x1 = start1, start2, start3, X + mulps xmm3, xmm2 ; x3 *= x2 + addps xmm3, xmm1 ; x3 += x1 + movups [edx], xmm3 ; *dest = x3 +#endif + } +} +#endif + +#ifdef _WIN32 +#ifdef PFN_VECTORMA +void _declspec(naked) __cdecl _SSE_VectorMA( const Vector &start, float scale, const Vector &direction, Vector &dest ) +{ + // FIXME: This don't work!! It will overwrite memory in the write to dest + Assert(0); + + Assert( s_bMathlibInitialized ); + _asm + { + // Intel SSE only routine + mov eax, DWORD PTR [esp+0x04] ; *start, s0..s2 + mov ecx, DWORD PTR [esp+0x0c] ; *direction, d0..d2 + mov edx, DWORD PTR [esp+0x10] ; *dest + movss xmm2, [esp+0x08] ; x2 = scale, 0, 0, 0 +#ifdef ALIGNED_VECTOR + movaps xmm3, [ecx] ; x3 = dir0,dir1,dir2,X + pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale + movaps xmm1, [eax] ; x1 = start1, start2, start3, X + mulps xmm3, xmm2 ; x3 *= x2 + addps xmm3, xmm1 ; x3 += x1 + movaps [edx], xmm3 ; *dest = x3 +#else + movups xmm3, [ecx] ; x3 = dir0,dir1,dir2,X + pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale + movups xmm1, [eax] ; x1 = start1, start2, start3, X + mulps xmm3, xmm2 ; x3 *= x2 + addps xmm3, xmm1 ; x3 += x1 + movups [edx], xmm3 ; *dest = x3 +#endif + } +} +float (__cdecl *pfVectorMA)(Vector& v) = _VectorMA; +#endif +#endif + + +// SSE DotProduct -- it's a smidgen faster than the asm DotProduct... +// Should be validated too! :) +// NJS: (Nov 1 2002) -NOT- faster. may time a couple cycles faster in a single function like +// this, but when inlined, and instruction scheduled, the C version is faster. +// Verified this via VTune +/* +vec_t DotProduct (const vec_t *a, const vec_t *c) +{ + vec_t temp; + + __asm + { + mov eax, a; + mov ecx, c; + mov edx, DWORD PTR [temp] + movss xmm0, [eax]; + mulss xmm0, [ecx]; + movss xmm1, [eax+4]; + mulss xmm1, [ecx+4]; + movss xmm2, [eax+8]; + mulss xmm2, [ecx+8]; + addss xmm0, xmm1; + addss xmm0, xmm2; + movss [edx], xmm0; + fld DWORD PTR [edx]; + ret + } +} +*/ + +#endif // COMPILER_MSVC64 diff --git a/mathlib/sse.h b/mathlib/sse.h new file mode 100644 index 0000000..1b49c50 --- /dev/null +++ b/mathlib/sse.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef _SSE_H +#define _SSE_H + +float _SSE_Sqrt(float x); +float _SSE_RSqrtAccurate(float a); +float _SSE_RSqrtFast(float x); +float FASTCALL _SSE_VectorNormalize(Vector& vec); +void FASTCALL _SSE_VectorNormalizeFast(Vector& vec); +float _SSE_InvRSquared(const float* v); +void _SSE_SinCos(float x, float* s, float* c); +float _SSE_cos( float x); +#ifdef PLATFORM_WINDOWS_PC32 +void _SSE2_SinCos(float x, float* s, float* c); +float _SSE2_cos(float x); +#endif +#if 0 +void VectorTransformSSE(const float *in1, const matrix3x4_t& in2, float *out1); +void VectorRotateSSE( const float *in1, const matrix3x4_t& in2, float *out1 ); +#endif + +#endif // _SSE_H diff --git a/mathlib/sseconst.cpp b/mathlib/sseconst.cpp new file mode 100644 index 0000000..2e3724b --- /dev/null +++ b/mathlib/sseconst.cpp @@ -0,0 +1,1164 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "mathlib/ssemath.h" +#include "mathlib/ssequaternion.h" + +const fltx4 Four_PointFives={0.5,0.5,0.5,0.5}; +#ifndef _X360 +const fltx4 Four_Zeros={0.0,0.0,0.0,0.0}; +const fltx4 Four_Ones={1.0,1.0,1.0,1.0}; +#endif +const fltx4 Four_Twos={2.0,2.0,2.0,2.0}; +const fltx4 Four_Threes={3.0,3.0,3.0,3.0}; +const fltx4 Four_Fours={4.0,4.0,4.0,4.0}; +const fltx4 Four_Origin={0,0,0,1}; +const fltx4 Four_NegativeOnes={-1,-1,-1,-1}; + +const fltx4 Four_2ToThe21s={ (float) (1<<21), (float) (1<<21), (float) (1<<21), (float)(1<<21) }; +const fltx4 Four_2ToThe22s={ (float) (1<<22), (float) (1<<22), (float) (1<<22), (float)(1<<22) }; +const fltx4 Four_2ToThe23s={ (float) (1<<23), (float) (1<<23), (float) (1<<23), (float)(1<<23) }; +const fltx4 Four_2ToThe24s={ (float) (1<<24), (float) (1<<24), (float) (1<<24), (float)(1<<24) }; + +const fltx4 Four_Point225s={ .225f, .225f, .225f, .225f }; +const fltx4 Four_Epsilons={FLT_EPSILON,FLT_EPSILON,FLT_EPSILON,FLT_EPSILON}; + +const fltx4 Four_FLT_MAX={FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; +const fltx4 Four_Negative_FLT_MAX={-FLT_MAX,-FLT_MAX,-FLT_MAX,-FLT_MAX}; +const fltx4 g_SIMD_0123 = { 0., 1., 2., 3. }; + +const fltx4 g_QuatMultRowSign[4] = +{ + { 1.0f, 1.0f, -1.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 1.0f }, + { -1.0f, -1.0f, -1.0f, 1.0f } +}; + +const int32 ALIGN16 g_SIMD_clear_signmask[4] ALIGN16_POST = {0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff}; +const int32 ALIGN16 g_SIMD_signmask[4] ALIGN16_POST = { (int32)0x80000000, (int32)0x80000000, (int32)0x80000000, (int32)0x80000000 }; +const int32 ALIGN16 g_SIMD_lsbmask[4] ALIGN16_POST = { (int32)0xfffffffe, (int32)0xfffffffe, (int32)0xfffffffe, (int32)0xfffffffe }; +const int32 ALIGN16 g_SIMD_clear_wmask[4] ALIGN16_POST = { (int32)0xffffffff, (int32)0xffffffff, (int32)0xffffffff, 0 }; +const int32 ALIGN16 g_SIMD_AllOnesMask[4] ALIGN16_POST = { (int32)0xffffffff, (int32)0xffffffff, (int32)0xffffffff, (int32)0xffffffff }; // ~0,~0,~0,~0 +const int32 ALIGN16 g_SIMD_Low16BitsMask[4] ALIGN16_POST = { 0xffff, 0xffff, 0xffff, 0xffff }; // 0xffff x 4 + +const int32 ALIGN16 g_SIMD_ComponentMask[4][4] ALIGN16_POST = +{ + { (int32)0xFFFFFFFF, 0, 0, 0 }, { 0, (int32)0xFFFFFFFF, 0, 0 }, { 0, 0, (int32)0xFFFFFFFF, 0 }, { 0, 0, 0, (int32)0xFFFFFFFF } +}; + +const int32 ALIGN16 g_SIMD_SkipTailMask[4][4] ALIGN16_POST = +{ + { (int32)0xffffffff, (int32)0xffffffff, (int32)0xffffffff, (int32)0xffffffff }, + { (int32)0xffffffff, 0x00000000, 0x00000000, 0x00000000 }, + { (int32)0xffffffff, (int32)0xffffffff, 0x00000000, 0x00000000 }, + { (int32)0xffffffff, (int32)0xffffffff, (int32)0xffffffff, 0x00000000 }, +}; + + + // FUNCTIONS + // NOTE: WHY YOU **DO NOT** WANT TO PUT FUNCTIONS HERE +// Generally speaking, you want to make sure SIMD math functions +// are inlined, because that gives the compiler much more latitude +// in instruction scheduling. It's not that the overhead of calling +// the function is particularly great; rather, many of the SIMD +// opcodes have long latencies, and if you have a sequence of +// several dependent ones inside a function call, the latencies +// stack up to create a big penalty. If the function is inlined, +// the compiler can interleave its operations with ones from the +// caller to better hide those latencies. Finally, on the 360, +// putting parameters or return values on the stack, and then +// reading them back within the next forty cycles, is a very +// severe penalty. So, as much as possible, you want to leave your +// data on the registers. + +// That said, there are certain occasions where it is appropriate +// to call into functions -- particularly for very large blocks +// of code that will spill most of the registers anyway. Unless your +// function is more than one screen long, yours is probably not one +// of those occasions. + + + +/// You can use this to rotate a long array of FourVectors all by the same +/// matrix. The first parameter is the head of the array. The second is the +/// number of vectors to rotate. The third is the matrix. +void FourVectors::RotateManyBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix ) +{ + Assert(numVectors > 0); + if ( numVectors == 0 ) + return; + + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the tranpose row of + // the matrix, but we don't really care about that. + fltx4 matCol0 = LoadUnalignedSIMD(rotationMatrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(rotationMatrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(rotationMatrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + } + +#ifdef _X360 + // Same algorithm as above, but the loop is unrolled to eliminate data hazard latencies + // and simplify prefetching. Named variables are deliberately used instead of arrays to + // ensure that the variables live on the registers instead of the stack (stack load/store + // is a serious penalty on 360). Nb: for prefetching to be most efficient here, the + // loop should be unrolled to 8 FourVectors per iteration; because each FourVectors is + // 48 bytes long, 48 * 8 = 384, its least common multiple with the 128-byte cache line. + // That way you can fetch the next 3 cache lines while you work on these three. + // If you do go this route, be sure to dissassemble and make sure it doesn't spill + // registers to stack as you do this; the cost of that will be excessive. Unroll the loop + // a little and just live with the fact that you'll be doing a couple of redundant dbcts + // (they don't cost you anything). Be aware that all three cores share L2 and it can only + // have eight cache lines fetching at a time. + fltx4 outX0, outY0, outZ0; // bank one of outputs + fltx4 outX1, outY1, outZ1; // bank two of outputs + + + // Because of instruction latencies and scheduling, it's actually faster to use adds and muls + // rather than madds. (Empirically determined by timing.) + const FourVectors * stop = pVectors + numVectors; + FourVectors * RESTRICT pVectNext; + // prime the pump. + if (numVectors & 0x01) + { + // odd number of vectors to process + // prime the 1 group of registers + pVectNext = pVectors++; + outX1 = AddSIMD( AddSIMD( MulSIMD( pVectNext->x, matSplat00 ), MulSIMD( pVectNext->y, matSplat01 ) ), MulSIMD( pVectNext->z, matSplat02 ) ); + outY1 = AddSIMD( AddSIMD( MulSIMD( pVectNext->x, matSplat10 ), MulSIMD( pVectNext->y, matSplat11 ) ), MulSIMD( pVectNext->z, matSplat12 ) ); + outZ1 = AddSIMD( AddSIMD( MulSIMD( pVectNext->x, matSplat20 ), MulSIMD( pVectNext->y, matSplat21 ) ), MulSIMD( pVectNext->z, matSplat22 ) ); + } + else + { + // even number of total vectors to process; + // prime the zero group and jump into the middle of the loop + outX0 = AddSIMD( AddSIMD( MulSIMD( pVectors->x, matSplat00 ), MulSIMD( pVectors->y, matSplat01 ) ), MulSIMD( pVectors->z, matSplat02 ) ); + outY0 = AddSIMD( AddSIMD( MulSIMD( pVectors->x, matSplat10 ), MulSIMD( pVectors->y, matSplat11 ) ), MulSIMD( pVectors->z, matSplat12 ) ); + outZ0 = AddSIMD( AddSIMD( MulSIMD( pVectors->x, matSplat20 ), MulSIMD( pVectors->y, matSplat21 ) ), MulSIMD( pVectors->z, matSplat22 ) ); + goto EVEN_CASE; + } + + // perform an even number of iterations through this loop. + while (pVectors < stop) + { + outX0 = MaddSIMD( pVectors->z, matSplat02, AddSIMD( MulSIMD( pVectors->x, matSplat00 ), MulSIMD( pVectors->y, matSplat01 ) ) ); + outY0 = MaddSIMD( pVectors->z, matSplat12, AddSIMD( MulSIMD( pVectors->x, matSplat10 ), MulSIMD( pVectors->y, matSplat11 ) ) ); + outZ0 = MaddSIMD( pVectors->z, matSplat22, AddSIMD( MulSIMD( pVectors->x, matSplat20 ), MulSIMD( pVectors->y, matSplat21 ) ) ); + + pVectNext->x = outX1; + pVectNext->y = outY1; + pVectNext->z = outZ1; + +EVEN_CASE: + pVectNext = pVectors+1; + + outX1 = MaddSIMD( pVectNext->z, matSplat02, AddSIMD( MulSIMD( pVectNext->x, matSplat00 ), MulSIMD( pVectNext->y, matSplat01 ) ) ); + outY1 = MaddSIMD( pVectNext->z, matSplat12, AddSIMD( MulSIMD( pVectNext->x, matSplat10 ), MulSIMD( pVectNext->y, matSplat11 ) ) ); + outZ1 = MaddSIMD( pVectNext->z, matSplat22, AddSIMD( MulSIMD( pVectNext->x, matSplat20 ), MulSIMD( pVectNext->y, matSplat21 ) ) ); + + pVectors->x = outX0; + pVectors->y = outY0; + pVectors->z = outZ0; + + pVectors += 2; + } + + // flush the last round of output + pVectNext->x = outX1; + pVectNext->y = outY1; + pVectNext->z = outZ1; +#else + // PC does not benefit from the unroll/scheduling above + fltx4 outX0, outY0, outZ0; // bank one of outputs + + + // Because of instruction latencies and scheduling, it's actually faster to use adds and muls + // rather than madds. (Empirically determined by timing.) + const FourVectors * stop = pVectors + numVectors; + + // perform an even number of iterations through this loop. + while (pVectors < stop) + { + outX0 = MaddSIMD( pVectors->z, matSplat02, AddSIMD( MulSIMD( pVectors->x, matSplat00 ), MulSIMD( pVectors->y, matSplat01 ) ) ); + outY0 = MaddSIMD( pVectors->z, matSplat12, AddSIMD( MulSIMD( pVectors->x, matSplat10 ), MulSIMD( pVectors->y, matSplat11 ) ) ); + outZ0 = MaddSIMD( pVectors->z, matSplat22, AddSIMD( MulSIMD( pVectors->x, matSplat20 ), MulSIMD( pVectors->y, matSplat21 ) ) ); + + pVectors->x = outX0; + pVectors->y = outY0; + pVectors->z = outZ0; + pVectors++; + } +#endif +} + +#ifdef _X360 +// Loop-scheduled code to process FourVectors in groups of eight quite efficiently. +void FourVectors_TransformManyGroupsOfEightBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors * RESTRICT pOut ) +{ + Assert(numVectors > 0); + if ( numVectors == 0 ) + return; + + AssertMsg( (pOut < pVectors && pOut+numVectors <= pVectors) || + (pOut > pVectors && pVectors+numVectors <= pOut), "FourVectors::TransformManyBy called with overlapping buffer pointers." ); + + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, matSplat03, // TWELVE REGISTERS + matSplat10, matSplat11, matSplat12, matSplat13, + matSplat20, matSplat21, matSplat22, matSplat23; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the tranpose row of + // the matrix. + fltx4 matCol0 = LoadUnalignedSIMD(rotationMatrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(rotationMatrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(rotationMatrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + matSplat03 = SplatWSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + matSplat13 = SplatWSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + matSplat23 = SplatWSIMD(matCol2); + } + + // this macro defines how to compute a specific row from an input and certain splat columns +#define COMPUTE(res, invec, xterm, yterm, zterm, transterm) res = AddSIMD( AddSIMD( MulSIMD((invec)->z, zterm), AddSIMD( MulSIMD( (invec)->x, xterm ), MulSIMD( (invec)->y, yterm ) ) ), transterm ) +#define WRITE(term, reg, toptr) toptr->term = reg + + // define result groups (we're going to have an eight-way unroll) + + fltx4 res0X, res0Y, res0Z, res0XTemp, res0YTemp, res0ZTemp; // 48 REGISTERS + fltx4 res1X, res1Y, res1Z, res1XTemp, res1YTemp, res1ZTemp; + fltx4 res2X, res2Y, res2Z, res2XTemp, res2YTemp, res2ZTemp; + fltx4 res3X, res3Y, res3Z, res3XTemp, res3YTemp, res3ZTemp; + fltx4 res4X, res4Y, res4Z, res4XTemp, res4YTemp, res4ZTemp; + fltx4 res5X, res5Y, res5Z, res5XTemp, res5YTemp, res5ZTemp; + fltx4 res6X, res6Y, res6Z, res6XTemp, res6YTemp, res6ZTemp; + fltx4 res7X, res7Y, res7Z, res7XTemp, res7YTemp, res7ZTemp; + + +// #define FROZ(out,in,offset) COMPUTE((out+offset)->x, (in + offset), matSplat00, matSplat01, matSplat02, matSplat03); COMPUTE((out + offset )->y, (in + offset), matSplat10, matSplat11, matSplat12, matSplat13); COMPUTE((out + offset)->z, (in + offset), matSplat20, matSplat21, matSplat22, matSplat23) +#define COMPUTE_GROUP(resgroup,dataptr) COMPUTE(resgroup ## X, (dataptr), matSplat00, matSplat01, matSplat02, matSplat03); COMPUTE(resgroup ## Y, (dataptr), matSplat10, matSplat11, matSplat12, matSplat13); COMPUTE(resgroup ## Z, (dataptr), matSplat20, matSplat21, matSplat22, matSplat23) +#define WRITE_GROUP(ptr, resgroup) (ptr)->x = resgroup ## X; (ptr)->y = resgroup ## Y; (ptr)->z = resgroup ## Z + + /* + // stage 1 -- 6 ops for xyz, each w 12 cycle latency + res0X = MulSIMD( (invec)->y, matSplat01 ); + res0Temp = MaddSIMD((invec)->z, matSplat02, matSplat03); + // stage 2 -- 3 clocks for xyz + res0X = MaddSIMD( (invec)->x, matSplat00, res0X ); + // stage 3 -- 3 clocks for xyz + res0X = AddSIMD(res0X, res0Temp); + */ +#define COMPUTE_STAGE1_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = MulSIMD( (invec)->y, ysplat ); tempvar = MaddSIMD((invec)->z, zsplat, transplat) +#define COMPUTE_STAGE2_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = MaddSIMD( (invec)->x, xsplat, res ) +#define COMPUTE_STAGE3_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = AddSIMD(res, tempvar) // frees up the tempvar + +#define COMPUTE_STAGE1_GROUP(resgroup, invec) COMPUTE_STAGE1_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE1_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE1_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + +#define COMPUTE_STAGE2_GROUP(resgroup, invec) COMPUTE_STAGE2_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE2_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE2_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + +#define COMPUTE_STAGE3_GROUP(resgroup, invec) COMPUTE_STAGE3_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE3_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE3_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + + FourVectors * RESTRICT inData = pVectors; + FourVectors * RESTRICT outData = pOut; + const FourVectors * const RESTRICT STOP = pVectors + numVectors; + + // Use techniques of loop scheduling to eliminate data hazards; process + // eight groups simultaneously so that we never have any operations stalling + // waiting for data. + // Note: this loop, while pretty fast, could be faster still -- you'll notice + // that it does all of its loads, then all computation, then writes everything + // out. If made truly cyclic, such that every line interleaved a stage 1, stage 2, + // stage 3, and write, then throughput could be higher (probably by about 50%). + while (inData < STOP) + { + // start prefetching the three cache lines + // we'll hit two iterations from now + __dcbt( sizeof(FourVectors) * 16, inData ); + __dcbt( sizeof(FourVectors) * 16 + 128, inData ); + __dcbt( sizeof(FourVectors) * 16 + 256, inData ); + + // synchro + COMPUTE_STAGE1_GROUP(res0, inData + 0); + COMPUTE_STAGE1_GROUP(res1, inData + 1); + COMPUTE_STAGE1_GROUP(res2, inData + 2); + COMPUTE_STAGE1_GROUP(res3, inData + 3); + + COMPUTE_STAGE2_GROUP(res0, inData + 0); + COMPUTE_STAGE1_GROUP(res4, inData + 4); + COMPUTE_STAGE2_GROUP(res1, inData + 1); + COMPUTE_STAGE1_GROUP(res5, inData + 5); + COMPUTE_STAGE2_GROUP(res2, inData + 2); + COMPUTE_STAGE1_GROUP(res6, inData + 6); + COMPUTE_STAGE2_GROUP(res3, inData + 3); + COMPUTE_STAGE1_GROUP(res7, inData + 7); + + COMPUTE_STAGE3_GROUP(res0, inData + 0); + COMPUTE_STAGE2_GROUP(res4, inData + 4); + COMPUTE_STAGE3_GROUP(res1, inData + 1); + COMPUTE_STAGE2_GROUP(res5, inData + 5); + COMPUTE_STAGE3_GROUP(res2, inData + 2); + COMPUTE_STAGE2_GROUP(res6, inData + 6); + COMPUTE_STAGE3_GROUP(res3, inData + 3); + COMPUTE_STAGE2_GROUP(res7, inData + 7); + + COMPUTE_STAGE3_GROUP(res4, inData + 4); + WRITE_GROUP( outData + 0, res0 ); + COMPUTE_STAGE3_GROUP(res5, inData + 5); + WRITE_GROUP( outData + 1, res1 ); + COMPUTE_STAGE3_GROUP(res6, inData + 6); + WRITE_GROUP( outData + 2, res2 ); + COMPUTE_STAGE3_GROUP(res7, inData + 7); + WRITE_GROUP( outData + 3, res3 ); + + + WRITE_GROUP( outData + 4, res4 ); + WRITE_GROUP( outData + 5, res5 ); + WRITE_GROUP( outData + 6, res6 ); + WRITE_GROUP( outData + 7, res7 ); + + inData += 8; + outData += 8; + } + + +#undef COMPUTE +#undef WRITE +#undef COMPUTE_STAGE1_ROW +#undef COMPUTE_STAGE2_ROW +#undef COMPUTE_STAGE3_ROW +#undef COMPUTE_STAGE1_GROUP +#undef COMPUTE_STAGE2_GROUP +#undef COMPUTE_STAGE3_GROUP +#undef COMPUTE_GROUP +#undef WRITE_GROUP +} + +#ifdef _X360 +// Loop-scheduled code to process FourVectors in groups of eight quite efficiently. This is the version +// to call when starting on a 128-byte-aligned address. +void FourVectors_TransformManyGroupsOfEightBy_128byteAligned(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors * RESTRICT pOut ) +{ + /* If this has changed, you will need to change all the prefetches, * + * and groups of eight are no longer the ideal unit for iterating * + * on many vectors. */ + COMPILE_TIME_ASSERT( sizeof(FourVectors) == 48 ) ; + + Assert(numVectors > 0); + if ( numVectors == 0 ) + return; + + AssertMsg((numVectors & 0x07) == 0, "FourVectors_TransformManyGroupsOfEight called with numVectors % 8 != 0!"); + + // Assert alignment + AssertMsg( ( ( reinterpret_cast( pVectors ) & 127 ) == 0) && + ( ( reinterpret_cast(pOut) & 127 ) == 0), + "FourVectors_Transform..aligned called with non-128-byte-aligned buffers." ); + + // Assert non overlap + AssertMsg( (pOut < pVectors && pOut+numVectors <= pVectors) || + (pOut > pVectors && pVectors+numVectors <= pOut), "FourVectors::TransformManyBy called with overlapping buffer pointers." ); + + // Here's the plan. 8 four-vecs = 3 cache lines exactly. It takes about 400 cycles to process a group + // of eight, and cache latency is 600 cycles, so we try to prefetch two iterations ahead (eg fetch + // iteration 3 while working on iteration 1). In the case of the output, we can simply zero-flush + // the cache lines since we are sure to write into them. Because we're reading and fetching two ahead, + // we want to stop two away from the last iteration. + + // No matter what, we will need to prefetch the first two groups of eight of input (that's the + // first six cache lines) + __dcbt( 0, pVectors ); + __dcbt( 128, pVectors ); + __dcbt( 256, pVectors ); + __dcbt( 384, pVectors ); + __dcbt( 512, pVectors ); + __dcbt( 640, pVectors ); + + + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, matSplat03, // TWELVE REGISTERS + matSplat10, matSplat11, matSplat12, matSplat13, + matSplat20, matSplat21, matSplat22, matSplat23; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the tranpose row of + // the matrix. + fltx4 matCol0 = LoadUnalignedSIMD(rotationMatrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(rotationMatrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(rotationMatrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + matSplat03 = SplatWSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + matSplat13 = SplatWSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + matSplat23 = SplatWSIMD(matCol2); + } + + // this macro defines how to compute a specific row from an input and certain splat columns +#define COMPUTE(res, invec, xterm, yterm, zterm, transterm) res = AddSIMD( AddSIMD( MulSIMD((invec)->z, zterm), AddSIMD( MulSIMD( (invec)->x, xterm ), MulSIMD( (invec)->y, yterm ) ) ), transterm ) +#define WRITE(term, reg, toptr) toptr->term = reg + + // define result groups (we're going to have an eight-way unroll) + + fltx4 res0X, res0Y, res0Z, res0XTemp, res0YTemp, res0ZTemp; // 48 REGISTERS + fltx4 res1X, res1Y, res1Z, res1XTemp, res1YTemp, res1ZTemp; + fltx4 res2X, res2Y, res2Z, res2XTemp, res2YTemp, res2ZTemp; + fltx4 res3X, res3Y, res3Z, res3XTemp, res3YTemp, res3ZTemp; + fltx4 res4X, res4Y, res4Z, res4XTemp, res4YTemp, res4ZTemp; + fltx4 res5X, res5Y, res5Z, res5XTemp, res5YTemp, res5ZTemp; + fltx4 res6X, res6Y, res6Z, res6XTemp, res6YTemp, res6ZTemp; + fltx4 res7X, res7Y, res7Z, res7XTemp, res7YTemp, res7ZTemp; + + + // #define FROZ(out,in,offset) COMPUTE((out+offset)->x, (in + offset), matSplat00, matSplat01, matSplat02, matSplat03); COMPUTE((out + offset )->y, (in + offset), matSplat10, matSplat11, matSplat12, matSplat13); COMPUTE((out + offset)->z, (in + offset), matSplat20, matSplat21, matSplat22, matSplat23) +#define COMPUTE_GROUP(resgroup,dataptr) COMPUTE(resgroup ## X, (dataptr), matSplat00, matSplat01, matSplat02, matSplat03); COMPUTE(resgroup ## Y, (dataptr), matSplat10, matSplat11, matSplat12, matSplat13); COMPUTE(resgroup ## Z, (dataptr), matSplat20, matSplat21, matSplat22, matSplat23) +#define WRITE_GROUP(ptr, resgroup) (ptr)->x = resgroup ## X; (ptr)->y = resgroup ## Y; (ptr)->z = resgroup ## Z + + /* + // stage 1 -- 6 ops for xyz, each w 12 cycle latency + res0X = MulSIMD( (invec)->y, matSplat01 ); + res0Temp = MaddSIMD((invec)->z, matSplat02, matSplat03); + // stage 2 -- 3 clocks for xyz + res0X = MaddSIMD( (invec)->x, matSplat00, res0X ); + // stage 3 -- 3 clocks for xyz + res0X = AddSIMD(res0X, res0Temp); + */ +#define COMPUTE_STAGE1_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = MulSIMD( (invec)->y, ysplat ); tempvar = MaddSIMD((invec)->z, zsplat, transplat) +#define COMPUTE_STAGE2_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = MaddSIMD( (invec)->x, xsplat, res ) +#define COMPUTE_STAGE3_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = AddSIMD(res, tempvar) // frees up the tempvar + +#define COMPUTE_STAGE1_GROUP(resgroup, invec) COMPUTE_STAGE1_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE1_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE1_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + +#define COMPUTE_STAGE2_GROUP(resgroup, invec) COMPUTE_STAGE2_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE2_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE2_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + +#define COMPUTE_STAGE3_GROUP(resgroup, invec) COMPUTE_STAGE3_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE3_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE3_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + + + // Okay. First do all but the last two turns of the crank; we don't want to overshoot with the flush-to-zero. + FourVectors * RESTRICT inData = pVectors; + FourVectors * RESTRICT outData = pOut; + const FourVectors * RESTRICT STOP; + if (numVectors > 16) + { + STOP = pVectors + numVectors - 16; + // flush the first two blocks we'll write into + __dcbz128( 0, outData ); + __dcbz128( 128, outData ); + __dcbz128( 256, outData ); + + while (inData < STOP) + { + // start prefetching the three cache lines + // we'll hit two iterations from now + __dcbt( sizeof(FourVectors) * 16, inData ); + __dcbt( sizeof(FourVectors) * 16 + 128, inData ); + __dcbt( sizeof(FourVectors) * 16 + 256, inData ); + + // synchro + COMPUTE_STAGE1_GROUP(res0, inData + 0); + COMPUTE_STAGE1_GROUP(res1, inData + 1); + COMPUTE_STAGE1_GROUP(res2, inData + 2); + COMPUTE_STAGE1_GROUP(res3, inData + 3); + + // pre-zero the three cache lines we'll overwrite + // in the next iteration + __dcbz128( 384, outData ); + __dcbz128( 512, outData ); + __dcbz128( 640, outData ); + + + COMPUTE_STAGE2_GROUP(res0, inData + 0); + COMPUTE_STAGE1_GROUP(res4, inData + 4); + COMPUTE_STAGE2_GROUP(res1, inData + 1); + COMPUTE_STAGE1_GROUP(res5, inData + 5); + COMPUTE_STAGE2_GROUP(res2, inData + 2); + COMPUTE_STAGE1_GROUP(res6, inData + 6); + COMPUTE_STAGE2_GROUP(res3, inData + 3); + COMPUTE_STAGE1_GROUP(res7, inData + 7); + + COMPUTE_STAGE3_GROUP(res0, inData + 0); + COMPUTE_STAGE2_GROUP(res4, inData + 4); + COMPUTE_STAGE3_GROUP(res1, inData + 1); + COMPUTE_STAGE2_GROUP(res5, inData + 5); + COMPUTE_STAGE3_GROUP(res2, inData + 2); + COMPUTE_STAGE2_GROUP(res6, inData + 6); + COMPUTE_STAGE3_GROUP(res3, inData + 3); + COMPUTE_STAGE2_GROUP(res7, inData + 7); + + COMPUTE_STAGE3_GROUP(res4, inData + 4); + WRITE_GROUP( outData + 0, res0 ); + COMPUTE_STAGE3_GROUP(res5, inData + 5); + WRITE_GROUP( outData + 1, res1 ); + COMPUTE_STAGE3_GROUP(res6, inData + 6); + WRITE_GROUP( outData + 2, res2 ); + COMPUTE_STAGE3_GROUP(res7, inData + 7); + WRITE_GROUP( outData + 3, res3 ); + + + WRITE_GROUP( outData + 4, res4 ); + WRITE_GROUP( outData + 5, res5 ); + WRITE_GROUP( outData + 6, res6 ); + WRITE_GROUP( outData + 7, res7 ); + + inData += 8; + outData += 8; + } + } + else if (numVectors == 16) + { + // zero out the exactly six cache lines we will write into + __dcbz128( 0, outData ); + __dcbz128( 128, outData ); + __dcbz128( 256, outData ); + __dcbz128( 384, outData ); + __dcbz128( 512, outData ); + __dcbz128( 640, outData ); + } + else if (numVectors == 8) + { + // zero out the exactly three cache lines we will write into + __dcbz128( 0, outData ); + __dcbz128( 128, outData ); + __dcbz128( 256, outData ); + } + else + { + AssertMsg(false, "Can't happen!"); + } + + // deal with the ultimate two groups (or, if we were fed + // less than 16 groups, the whole shebang) + STOP = pVectors + numVectors - 16; + + + // Use techniques of loop scheduling to eliminate data hazards; process + // eight groups simultaneously so that we never have any operations stalling + // waiting for data. + // Note: this loop, while pretty fast, could be faster still -- you'll notice + // that it does all of its loads, then all computation, then writes everything + // out. If made truly cyclic, such that every line interleaved a stage 1, stage 2, + // stage 3, and write, then throughput could be higher (probably by about 50%). + while (inData < STOP) + { + // synchro + COMPUTE_STAGE1_GROUP(res0, inData + 0); + COMPUTE_STAGE1_GROUP(res1, inData + 1); + COMPUTE_STAGE1_GROUP(res2, inData + 2); + COMPUTE_STAGE1_GROUP(res3, inData + 3); + + COMPUTE_STAGE2_GROUP(res0, inData + 0); + COMPUTE_STAGE1_GROUP(res4, inData + 4); + COMPUTE_STAGE2_GROUP(res1, inData + 1); + COMPUTE_STAGE1_GROUP(res5, inData + 5); + COMPUTE_STAGE2_GROUP(res2, inData + 2); + COMPUTE_STAGE1_GROUP(res6, inData + 6); + COMPUTE_STAGE2_GROUP(res3, inData + 3); + COMPUTE_STAGE1_GROUP(res7, inData + 7); + + COMPUTE_STAGE3_GROUP(res0, inData + 0); + COMPUTE_STAGE2_GROUP(res4, inData + 4); + COMPUTE_STAGE3_GROUP(res1, inData + 1); + COMPUTE_STAGE2_GROUP(res5, inData + 5); + COMPUTE_STAGE3_GROUP(res2, inData + 2); + COMPUTE_STAGE2_GROUP(res6, inData + 6); + COMPUTE_STAGE3_GROUP(res3, inData + 3); + COMPUTE_STAGE2_GROUP(res7, inData + 7); + + COMPUTE_STAGE3_GROUP(res4, inData + 4); + WRITE_GROUP( outData + 0, res0 ); + COMPUTE_STAGE3_GROUP(res5, inData + 5); + WRITE_GROUP( outData + 1, res1 ); + COMPUTE_STAGE3_GROUP(res6, inData + 6); + WRITE_GROUP( outData + 2, res2 ); + COMPUTE_STAGE3_GROUP(res7, inData + 7); + WRITE_GROUP( outData + 3, res3 ); + + + WRITE_GROUP( outData + 4, res4 ); + WRITE_GROUP( outData + 5, res5 ); + WRITE_GROUP( outData + 6, res6 ); + WRITE_GROUP( outData + 7, res7 ); + + inData += 8; + outData += 8; + } + + +#undef COMPUTE +#undef WRITE +#undef COMPUTE_STAGE1_ROW +#undef COMPUTE_STAGE2_ROW +#undef COMPUTE_STAGE3_ROW +#undef COMPUTE_STAGE1_GROUP +#undef COMPUTE_STAGE2_GROUP +#undef COMPUTE_STAGE3_GROUP +#undef COMPUTE_GROUP +#undef WRITE_GROUP +} +#endif + +// Transform a long array of FourVectors by a given matrix. +void FourVectors::TransformManyBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors * RESTRICT pOut ) +{ + Assert(numVectors > 0); + + AssertMsg( (pOut < pVectors && pOut+numVectors <= pVectors) || + (pOut > pVectors && pVectors+numVectors <= pOut), "FourVectors::TransformManyBy called with overlapping buffer pointers." ); + +#ifdef _X360 + // The really fast version of this function likes to operate on blocks of eight. So, chug through + // groups of eight, then deal with any leftovers. + int numVectorsRoundedToNearestEight = numVectors & (~0x07); + if (numVectors >= 8) + { + // aligned? + if ((reinterpret_cast(pVectors) & 127) == 0 && (reinterpret_cast(pOut) & 127) == 0) + { + FourVectors_TransformManyGroupsOfEightBy_128byteAligned(pVectors, numVectorsRoundedToNearestEight, rotationMatrix, pOut); + } + else + { + FourVectors_TransformManyGroupsOfEightBy(pVectors, numVectorsRoundedToNearestEight, rotationMatrix, pOut); + } + numVectors -= numVectorsRoundedToNearestEight; + pVectors += numVectorsRoundedToNearestEight; + pOut += numVectorsRoundedToNearestEight; + } +#endif + + // any left over? + if (numVectors > 0) + { + + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, matSplat03, // TWELVE REGISTERS + matSplat10, matSplat11, matSplat12, matSplat13, + matSplat20, matSplat21, matSplat22, matSplat23; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the transpose row of + // the matrix. + fltx4 matCol0 = LoadUnalignedSIMD(rotationMatrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(rotationMatrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(rotationMatrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + matSplat03 = SplatWSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + matSplat13 = SplatWSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + matSplat23 = SplatWSIMD(matCol2); + } + + do + { + // Trust in the compiler to schedule these operations correctly: + pOut->x = MaddSIMD(pVectors->z, matSplat02, MaddSIMD(pVectors->y, matSplat01, MaddSIMD(pVectors->x, matSplat00, matSplat03))); + pOut->y = MaddSIMD(pVectors->z, matSplat12, MaddSIMD(pVectors->y, matSplat11, MaddSIMD(pVectors->x, matSplat00, matSplat13))); + pOut->z = MaddSIMD(pVectors->z, matSplat22, MaddSIMD(pVectors->y, matSplat21, MaddSIMD(pVectors->x, matSplat00, matSplat23))); + + ++pOut; + ++pVectors; + --numVectors; + } while(numVectors > 0); + } +} + +#ifdef _X360 +// Loop-scheduled code to process FourVectors in groups of eight quite efficiently. +static void FourVectors_TransformManyGroupsOfEightBy_InPlace(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix ) +{ + Assert(numVectors > 0); + if ( numVectors == 0 ) + return; + + // Prefetch line 1 and 2 + __dcbt(0,pVectors); + __dcbt(128,pVectors); + + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, matSplat03, // TWELVE REGISTERS + matSplat10, matSplat11, matSplat12, matSplat13, + matSplat20, matSplat21, matSplat22, matSplat23; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the tranpose row of + // the matrix. + fltx4 matCol0 = LoadUnalignedSIMD(rotationMatrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(rotationMatrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(rotationMatrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + matSplat03 = SplatWSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + matSplat13 = SplatWSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + matSplat23 = SplatWSIMD(matCol2); + } + + // this macro defines how to compute a specific row from an input and certain splat columns +#define COMPUTE(res, invec, xterm, yterm, zterm, transterm) res = AddSIMD( AddSIMD( MulSIMD((invec)->z, zterm), AddSIMD( MulSIMD( (invec)->x, xterm ), MulSIMD( (invec)->y, yterm ) ) ), transterm ) +#define WRITE(term, reg, toptr) toptr->term = reg + + // define result groups (we're going to have an eight-way unroll) + + fltx4 res0X, res0Y, res0Z, res0XTemp, res0YTemp, res0ZTemp; // 48 REGISTERS + fltx4 res1X, res1Y, res1Z, res1XTemp, res1YTemp, res1ZTemp; + fltx4 res2X, res2Y, res2Z, res2XTemp, res2YTemp, res2ZTemp; + fltx4 res3X, res3Y, res3Z, res3XTemp, res3YTemp, res3ZTemp; + fltx4 res4X, res4Y, res4Z, res4XTemp, res4YTemp, res4ZTemp; + fltx4 res5X, res5Y, res5Z, res5XTemp, res5YTemp, res5ZTemp; + fltx4 res6X, res6Y, res6Z, res6XTemp, res6YTemp, res6ZTemp; + fltx4 res7X, res7Y, res7Z, res7XTemp, res7YTemp, res7ZTemp; + + + // #define FROZ(out,in,offset) COMPUTE((out+offset)->x, (in + offset), matSplat00, matSplat01, matSplat02, matSplat03); COMPUTE((out + offset )->y, (in + offset), matSplat10, matSplat11, matSplat12, matSplat13); COMPUTE((out + offset)->z, (in + offset), matSplat20, matSplat21, matSplat22, matSplat23) +#define COMPUTE_GROUP(resgroup,dataptr) COMPUTE(resgroup ## X, (dataptr), matSplat00, matSplat01, matSplat02, matSplat03); COMPUTE(resgroup ## Y, (dataptr), matSplat10, matSplat11, matSplat12, matSplat13); COMPUTE(resgroup ## Z, (dataptr), matSplat20, matSplat21, matSplat22, matSplat23) +#define WRITE_GROUP(ptr, resgroup) (ptr)->x = resgroup ## X; (ptr)->y = resgroup ## Y; (ptr)->z = resgroup ## Z + + /* + // stage 1 -- 6 ops for xyz, each w 12 cycle latency + res0X = MulSIMD( (invec)->y, matSplat01 ); + res0Temp = MaddSIMD((invec)->z, matSplat02, matSplat03); + // stage 2 -- 3 clocks for xyz + res0X = MaddSIMD( (invec)->x, matSplat00, res0X ); + // stage 3 -- 3 clocks for xyz + res0X = AddSIMD(res0X, res0Temp); + */ +#define COMPUTE_STAGE1_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = MulSIMD( (invec)->y, ysplat ); tempvar = MaddSIMD((invec)->z, zsplat, transplat) +#define COMPUTE_STAGE2_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = MaddSIMD( (invec)->x, xsplat, res ) +#define COMPUTE_STAGE3_ROW(res, tempvar, invec, xsplat, ysplat, zsplat, transplat) res = AddSIMD(res, tempvar) // frees up the tempvar + +#define COMPUTE_STAGE1_GROUP(resgroup, invec) COMPUTE_STAGE1_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE1_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE1_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + +#define COMPUTE_STAGE2_GROUP(resgroup, invec) COMPUTE_STAGE2_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE2_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE2_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + +#define COMPUTE_STAGE3_GROUP(resgroup, invec) COMPUTE_STAGE3_ROW(resgroup ## X, resgroup ## X ## Temp, invec, matSplat00, matSplat01, matSplat02, matSplat03);\ + COMPUTE_STAGE3_ROW(resgroup ## Y, resgroup ## Y ## Temp, invec, matSplat10, matSplat11, matSplat12, matSplat13);\ + COMPUTE_STAGE3_ROW(resgroup ## Z, resgroup ## Z ## Temp, invec, matSplat20, matSplat21, matSplat22, matSplat23) + + const FourVectors * const RESTRICT STOP = pVectors + numVectors; + + // Use techniques of loop scheduling to eliminate data hazards; process + // eight groups simultaneously so that we never have any operations stalling + // waiting for data. + // Note: this loop, while pretty fast, could be faster still -- you'll notice + // that it does all of its loads, then all computation, then writes everything + // out. If made truly cyclic, such that every line interleaved a stage 1, stage 2, + // stage 3, and write, then throughput could be higher (probably by about 50%). + while (pVectors < STOP) + { + // start prefetching the three cache lines + // we'll hit two iterations from now + __dcbt( sizeof(FourVectors) * 16, pVectors ); + __dcbt( sizeof(FourVectors) * 16 + 128, pVectors ); + __dcbt( sizeof(FourVectors) * 16 + 256, pVectors ); + + // synchro + COMPUTE_STAGE1_GROUP(res0, pVectors + 0); + COMPUTE_STAGE1_GROUP(res1, pVectors + 1); + COMPUTE_STAGE1_GROUP(res2, pVectors + 2); + COMPUTE_STAGE1_GROUP(res3, pVectors + 3); + + COMPUTE_STAGE2_GROUP(res0, pVectors + 0); + COMPUTE_STAGE1_GROUP(res4, pVectors + 4); + COMPUTE_STAGE2_GROUP(res1, pVectors + 1); + COMPUTE_STAGE1_GROUP(res5, pVectors + 5); + COMPUTE_STAGE2_GROUP(res2, pVectors + 2); + COMPUTE_STAGE1_GROUP(res6, pVectors + 6); + COMPUTE_STAGE2_GROUP(res3, pVectors + 3); + COMPUTE_STAGE1_GROUP(res7, pVectors + 7); + + COMPUTE_STAGE3_GROUP(res0, pVectors + 0); + COMPUTE_STAGE2_GROUP(res4, pVectors + 4); + COMPUTE_STAGE3_GROUP(res1, pVectors + 1); + COMPUTE_STAGE2_GROUP(res5, pVectors + 5); + COMPUTE_STAGE3_GROUP(res2, pVectors + 2); + COMPUTE_STAGE2_GROUP(res6, pVectors + 6); + COMPUTE_STAGE3_GROUP(res3, pVectors + 3); + COMPUTE_STAGE2_GROUP(res7, pVectors + 7); + + COMPUTE_STAGE3_GROUP(res4, pVectors + 4); + WRITE_GROUP( pVectors + 0, res0 ); + COMPUTE_STAGE3_GROUP(res5, pVectors + 5); + WRITE_GROUP( pVectors + 1, res1 ); + COMPUTE_STAGE3_GROUP(res6, pVectors + 6); + WRITE_GROUP( pVectors + 2, res2 ); + COMPUTE_STAGE3_GROUP(res7, pVectors + 7); + WRITE_GROUP( pVectors + 3, res3 ); + + WRITE_GROUP( pVectors + 4, res4 ); + WRITE_GROUP( pVectors + 5, res5 ); + WRITE_GROUP( pVectors + 6, res6 ); + WRITE_GROUP( pVectors + 7, res7 ); + + pVectors += 8; + } + + +#undef COMPUTE +#undef WRITE +#undef COMPUTE_STAGE1_ROW +#undef COMPUTE_STAGE2_ROW +#undef COMPUTE_STAGE3_ROW +#undef COMPUTE_STAGE1_GROUP +#undef COMPUTE_STAGE2_GROUP +#undef COMPUTE_STAGE3_GROUP +#undef COMPUTE_GROUP +#undef WRITE_GROUP +} +#endif + +// In-place version of above. It's necessary to have this, rather than just allowing pOut and pVectors +// to equal each other, because of the semantics of RESTRICT: pVectors and pOut must not be allowed +// to alias. (Simply un-restricting the pointers results in very poor scheduling.) +void FourVectors::TransformManyBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix ) +{ + Assert(numVectors > 0); + +#ifdef _X360 + // The really fast version of this function likes to operate on blocks of eight. So, chug through + // groups of eight, then deal with any leftovers. + int numVectorsRoundedToNearestEight = numVectors & (~0x07); + if (numVectors >= 8) + { + FourVectors_TransformManyGroupsOfEightBy_InPlace(pVectors, numVectorsRoundedToNearestEight, rotationMatrix); + numVectors -= numVectorsRoundedToNearestEight; + pVectors += numVectorsRoundedToNearestEight; + } +#endif + + // any left over? + if (numVectors > 0) + { + + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, matSplat03, // TWELVE REGISTERS + matSplat10, matSplat11, matSplat12, matSplat13, + matSplat20, matSplat21, matSplat22, matSplat23; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the transpose row of + // the matrix. + fltx4 matCol0 = LoadUnalignedSIMD(rotationMatrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(rotationMatrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(rotationMatrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + matSplat03 = SplatWSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + matSplat13 = SplatWSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + matSplat23 = SplatWSIMD(matCol2); + } + + do + { + fltx4 resultX, resultY, resultZ; + // Trust in the compiler to schedule these operations correctly: + resultX = MaddSIMD(pVectors->z, matSplat02, MaddSIMD(pVectors->y, matSplat01, MaddSIMD(pVectors->x, matSplat00, matSplat03))); + resultY = MaddSIMD(pVectors->z, matSplat12, MaddSIMD(pVectors->y, matSplat11, MaddSIMD(pVectors->x, matSplat00, matSplat13))); + resultZ = MaddSIMD(pVectors->z, matSplat22, MaddSIMD(pVectors->y, matSplat21, MaddSIMD(pVectors->x, matSplat00, matSplat23))); + + pVectors->x = resultX; + pVectors->y = resultY; + pVectors->z = resultZ; + + ++pVectors; + --numVectors; + } while(numVectors > 0); + } +} + + +#endif + +// Transform many (horizontal) points in-place by a 3x4 matrix, +// here already loaded onto three fltx4 registers but not transposed. +// The points must be stored as 16-byte aligned. They are points +// and not vectors because we assume the w-component to be 1. +#ifdef _X360 +void TransformManyPointsBy(VectorAligned * RESTRICT pVectors, unsigned int numVectors, FLTX4 mRow0, FLTX4 mRow1, FLTX4 mRow2) +{ + /************************************************** + * Here is an elaborate and carefully scheduled * + * algorithm nicked from xboxmath.inl and hacked * + * up for 3x4 matrices. * + **************************************************/ + + COMPILE_TIME_ASSERT(sizeof(VectorAligned) == sizeof(XMFLOAT4)); // VectorAligned's need to be 16 bytes + + XMVECTOR R0[8], R1[8], R2[8]; + XMVECTOR vIn[8]; + + // C_ASSERT(UnrollCount == 8); + // C_ASSERT(sizeof(XMFLOAT4) == 16); + Assert(pVectors); + Assert(((UINT_PTR)pVectors & 3) == 0); // assert alignment + + UINT GroupIndex; + + VectorAligned * RESTRICT vCurrent = pVectors; + // sentinel pointers + VectorAligned * vStreamEnd, *vStreamGroupBase, *vStreamGroupEnd; + + { + // cook up the pointers from integer math. Necessary because otherwise we LHS all over + // the place. (Odd that this doesn't happen to the xbox math.) + + UINT_PTR InputVector = (UINT_PTR)pVectors; + UINT_PTR InputStreamEnd = InputVector + numVectors * sizeof(XMFLOAT4); + // compute start and end points on 128-byte alignment + UINT_PTR InputStreamCGroupBase = XMMin(InputVector + (XM_CACHE_LINE_SIZE - 1), InputStreamEnd) & ~(XM_CACHE_LINE_SIZE - 1); + UINT_PTR InputStreamCGroupEnd = InputStreamCGroupBase + ((InputStreamEnd - InputStreamCGroupBase) & ~(4 * XM_CACHE_LINE_SIZE - 1)); + + vStreamEnd = (VectorAligned *)InputStreamEnd; + vStreamGroupBase = (VectorAligned *)InputStreamCGroupBase; + vStreamGroupEnd = (VectorAligned *)InputStreamCGroupEnd; + } + + + __dcbt(0, vStreamGroupBase); + __dcbt(XM_CACHE_LINE_SIZE, vStreamGroupBase); + __dcbt(XM_CACHE_LINE_SIZE * 2, vStreamGroupBase); + __dcbt(XM_CACHE_LINE_SIZE * 3, vStreamGroupBase); + + while (vCurrent < vStreamGroupBase) + { + fltx4 vec = __lvx(vCurrent->Base(), 0); + + R0[0] = __vmsum4fp(vec, mRow0); + R1[0] = __vmsum4fp(vec, mRow1); + R2[0] = __vmsum4fp(vec, mRow2); + + __stvewx(R0[0], vCurrent->Base(), 0); + __stvewx(R1[0], vCurrent->Base(), 4); + __stvewx(R2[0], vCurrent->Base(), 8); + + vCurrent++; + } + + while (vCurrent < vStreamGroupEnd) + { + __dcbt(XM_CACHE_LINE_SIZE * 4, vCurrent); + __dcbt(XM_CACHE_LINE_SIZE * 5, vCurrent); + __dcbt(XM_CACHE_LINE_SIZE * 6, vCurrent); + __dcbt(XM_CACHE_LINE_SIZE * 7, vCurrent); + + for (GroupIndex = 0; GroupIndex < 4; GroupIndex++) + { + // all kinds of LHS on this pointer. Why? + VectorAligned* OutputVector = vCurrent; + + vIn[0] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[1] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[2] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[3] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[4] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[5] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[6] = __lvx(vCurrent->Base(), 0); + vCurrent++; + vIn[7] = __lvx(vCurrent->Base(), 0); + vCurrent++; + + R0[0] = __vmsum4fp(vIn[0], mRow0); + R1[0] = __vmsum4fp(vIn[0], mRow1); + R2[0] = __vmsum4fp(vIn[0], mRow2); + + R0[1] = __vmsum4fp(vIn[1], mRow0); + R1[1] = __vmsum4fp(vIn[1], mRow1); + R2[1] = __vmsum4fp(vIn[1], mRow2); + + R0[2] = __vmsum4fp(vIn[2], mRow0); + R1[2] = __vmsum4fp(vIn[2], mRow1); + R2[2] = __vmsum4fp(vIn[2], mRow2); + + R0[3] = __vmsum4fp(vIn[3], mRow0); + R1[3] = __vmsum4fp(vIn[3], mRow1); + R2[3] = __vmsum4fp(vIn[3], mRow2); + + R0[4] = __vmsum4fp(vIn[4], mRow0); + R1[4] = __vmsum4fp(vIn[4], mRow1); + R2[4] = __vmsum4fp(vIn[4], mRow2); + + R0[5] = __vmsum4fp(vIn[5], mRow0); + R1[5] = __vmsum4fp(vIn[5], mRow1); + R2[5] = __vmsum4fp(vIn[5], mRow2); + + R0[6] = __vmsum4fp(vIn[6], mRow0); + R1[6] = __vmsum4fp(vIn[6], mRow1); + R2[6] = __vmsum4fp(vIn[6], mRow2); + + R0[7] = __vmsum4fp(vIn[7], mRow0); + R1[7] = __vmsum4fp(vIn[7], mRow1); + R2[7] = __vmsum4fp(vIn[7], mRow2); + + __stvewx(R0[0], OutputVector, 0); + __stvewx(R1[0], OutputVector, 4); + __stvewx(R2[0], OutputVector, 8); + OutputVector++; + + __stvewx(R0[1], OutputVector, 0); + __stvewx(R1[1], OutputVector, 4); + __stvewx(R2[1], OutputVector, 8); + OutputVector++; + + __stvewx(R0[2], OutputVector, 0); + __stvewx(R1[2], OutputVector, 4); + __stvewx(R2[2], OutputVector, 8); + OutputVector++; + + __stvewx(R0[3], OutputVector, 0); + __stvewx(R1[3], OutputVector, 4); + __stvewx(R2[3], OutputVector, 8); + OutputVector++; + + __stvewx(R0[4], OutputVector, 0); + __stvewx(R1[4], OutputVector, 4); + __stvewx(R2[4], OutputVector, 8); + OutputVector++; + + __stvewx(R0[5], OutputVector, 0); + __stvewx(R1[5], OutputVector, 4); + __stvewx(R2[5], OutputVector, 8); + OutputVector++; + + __stvewx(R0[6], OutputVector, 0); + __stvewx(R1[6], OutputVector, 4); + __stvewx(R2[6], OutputVector, 8); + OutputVector++; + + __stvewx(R0[7], OutputVector, 0); + __stvewx(R1[7], OutputVector, 4); + __stvewx(R2[7], OutputVector, 8); + OutputVector++; + } + } + + while (vCurrent < vStreamEnd) + { + vIn[0] = __lvx(vCurrent->Base(), 0); + + R0[0] = __vmsum4fp(vIn[0], mRow0); + R1[0] = __vmsum4fp(vIn[0], mRow1); + R2[0] = __vmsum4fp(vIn[0], mRow2); + + __stvewx(R0[0], vCurrent->Base(), 0); + __stvewx(R1[0], vCurrent->Base(), 4); + __stvewx(R2[0], vCurrent->Base(), 8); + + vCurrent++; + } + + +} +#endif diff --git a/mathlib/ssenoise.cpp b/mathlib/ssenoise.cpp new file mode 100644 index 0000000..6ead1c8 --- /dev/null +++ b/mathlib/ssenoise.cpp @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Fast low quality noise suitable for real time use +// +//=====================================================================================// + +#include +#include // Needed for FLT_EPSILON +#include "basetypes.h" +#include +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "mathlib/ssemath.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" +#include "noisedata.h" + + +#define MAGIC_NUMBER (1<<15) // gives 8 bits of fraction + +static fltx4 Four_MagicNumbers = { MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER }; + + +static ALIGN16 int32 idx_mask[4]= {0xffff, 0xffff, 0xffff, 0xffff}; + +#define MASK255 (*((fltx4 *)(& idx_mask ))) + +// returns 0..1 +static inline float GetLatticePointValue( int idx_x, int idx_y, int idx_z ) +{ + NOTE_UNUSED(perm_d); + NOTE_UNUSED(impulse_ycoords); + NOTE_UNUSED(impulse_zcoords); + + int ret_idx = perm_a[idx_x & 0xff]; + ret_idx = perm_b[( idx_y + ret_idx ) & 0xff]; + ret_idx = perm_c[( idx_z + ret_idx ) & 0xff]; + return impulse_xcoords[ret_idx]; + +} + +fltx4 NoiseSIMD( const fltx4 & x, const fltx4 & y, const fltx4 & z ) +{ + // use magic to convert to integer index + fltx4 x_idx = AndSIMD( MASK255, AddSIMD( x, Four_MagicNumbers ) ); + fltx4 y_idx = AndSIMD( MASK255, AddSIMD( y, Four_MagicNumbers ) ); + fltx4 z_idx = AndSIMD( MASK255, AddSIMD( z, Four_MagicNumbers ) ); + + fltx4 lattice000 = Four_Zeros, lattice001 = Four_Zeros, lattice010 = Four_Zeros, lattice011 = Four_Zeros; + fltx4 lattice100 = Four_Zeros, lattice101 = Four_Zeros, lattice110 = Four_Zeros, lattice111 = Four_Zeros; + + // FIXME: Converting the input vectors to int indices will cause load-hit-stores (48 bytes) + // Converting the indexed noise values back to vectors will cause more (128 bytes) + // The noise table could store vectors if we chunked it into 2x2x2 blocks. + fltx4 xfrac = Four_Zeros, yfrac = Four_Zeros, zfrac = Four_Zeros; +#define DOPASS(i) \ + { unsigned int xi = SubInt( x_idx, i ); \ + unsigned int yi = SubInt( y_idx, i ); \ + unsigned int zi = SubInt( z_idx, i ); \ + SubFloat( xfrac, i ) = (xi & 0xff)*(1.0/256.0); \ + SubFloat( yfrac, i ) = (yi & 0xff)*(1.0/256.0); \ + SubFloat( zfrac, i ) = (zi & 0xff)*(1.0/256.0); \ + xi>>=8; \ + yi>>=8; \ + zi>>=8; \ + \ + SubFloat( lattice000, i ) = GetLatticePointValue( xi,yi,zi ); \ + SubFloat( lattice001, i ) = GetLatticePointValue( xi,yi,zi+1 ); \ + SubFloat( lattice010, i ) = GetLatticePointValue( xi,yi+1,zi ); \ + SubFloat( lattice011, i ) = GetLatticePointValue( xi,yi+1,zi+1 ); \ + SubFloat( lattice100, i ) = GetLatticePointValue( xi+1,yi,zi ); \ + SubFloat( lattice101, i ) = GetLatticePointValue( xi+1,yi,zi+1 ); \ + SubFloat( lattice110, i ) = GetLatticePointValue( xi+1,yi+1,zi ); \ + SubFloat( lattice111, i ) = GetLatticePointValue( xi+1,yi+1,zi+1 ); \ + } + + DOPASS( 0 ); + DOPASS( 1 ); + DOPASS( 2 ); + DOPASS( 3 ); + + // now, we have 8 lattice values for each of four points as m128s, and interpolant values for + // each axis in m128 form in [xyz]frac. Perfom the trilinear interpolation as SIMD ops + + // first, do x interpolation + fltx4 l2d00 = AddSIMD( lattice000, MulSIMD( xfrac, SubSIMD( lattice100, lattice000 ) ) ); + fltx4 l2d01 = AddSIMD( lattice001, MulSIMD( xfrac, SubSIMD( lattice101, lattice001 ) ) ); + fltx4 l2d10 = AddSIMD( lattice010, MulSIMD( xfrac, SubSIMD( lattice110, lattice010 ) ) ); + fltx4 l2d11 = AddSIMD( lattice011, MulSIMD( xfrac, SubSIMD( lattice111, lattice011 ) ) ); + + // now, do y interpolation + fltx4 l1d0 = AddSIMD( l2d00, MulSIMD( yfrac, SubSIMD( l2d10, l2d00 ) ) ); + fltx4 l1d1 = AddSIMD( l2d01, MulSIMD( yfrac, SubSIMD( l2d11, l2d01 ) ) ); + + // final z interpolation + fltx4 rslt = AddSIMD( l1d0, MulSIMD( zfrac, SubSIMD( l1d1, l1d0 ) ) ); + + // map to 0..1 + return MulSIMD( Four_Twos, SubSIMD( rslt, Four_PointFives ) ); + + +} + +fltx4 NoiseSIMD( FourVectors const &pos ) +{ + return NoiseSIMD( pos.x, pos.y, pos.z ); +} diff --git a/mathlib/vector.cpp b/mathlib/vector.cpp new file mode 100644 index 0000000..5cb72d4 --- /dev/null +++ b/mathlib/vector.cpp @@ -0,0 +1,12 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "mathlib/vector.h" + +Vector vec3_origin(0,0,0); + diff --git a/mathlib/vmatrix.cpp b/mathlib/vmatrix.cpp new file mode 100644 index 0000000..01a987b --- /dev/null +++ b/mathlib/vmatrix.cpp @@ -0,0 +1,1293 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#include "basetypes.h" +#include "mathlib/vmatrix.h" +#include "mathlib/mathlib.h" +#include +#include "mathlib/vector4d.h" +#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#pragma warning (disable : 4700) // local variable 'x' used without having been initialized + +// ------------------------------------------------------------------------------------------- // +// Helper functions. +// ------------------------------------------------------------------------------------------- // + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +VMatrix SetupMatrixIdentity() +{ + return VMatrix( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} + +VMatrix SetupMatrixTranslation(const Vector &vTranslation) +{ + return VMatrix( + 1.0f, 0.0f, 0.0f, vTranslation.x, + 0.0f, 1.0f, 0.0f, vTranslation.y, + 0.0f, 0.0f, 1.0f, vTranslation.z, + 0.0f, 0.0f, 0.0f, 1.0f + ); +} + +VMatrix SetupMatrixScale(const Vector &vScale) +{ + return VMatrix( + vScale.x, 0.0f, 0.0f, 0.0f, + 0.0f, vScale.y, 0.0f, 0.0f, + 0.0f, 0.0f, vScale.z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); +} + +VMatrix SetupMatrixReflection(const VPlane &thePlane) +{ + VMatrix mReflect, mBack, mForward; + Vector vOrigin, N; + + N = thePlane.m_Normal; + + mReflect.Init( + -2.0f*N.x*N.x + 1.0f, -2.0f*N.x*N.y, -2.0f*N.x*N.z, 0.0f, + -2.0f*N.y*N.x, -2.0f*N.y*N.y + 1.0f, -2.0f*N.y*N.z, 0.0f, + -2.0f*N.z*N.x, -2.0f*N.z*N.y, -2.0f*N.z*N.z + 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + vOrigin = thePlane.GetPointOnPlane(); + + mBack.Identity(); + mBack.SetTranslation(-vOrigin); + + mForward.Identity(); + mForward.SetTranslation(vOrigin); + + // (multiplied in reverse order, so it translates to the origin point, + // reflects, and translates back). + return mForward * mReflect * mBack; +} + +VMatrix SetupMatrixProjection(const Vector &vOrigin, const VPlane &thePlane) +{ + vec_t dot; + VMatrix mRet; + + + #define PN thePlane.m_Normal + #define PD thePlane.m_Dist; + + dot = PN[0]*vOrigin.x + PN[1]*vOrigin.y + PN[2]*vOrigin.z - PD; + + mRet.m[0][0] = dot - vOrigin.x * PN[0]; + mRet.m[0][1] = -vOrigin.x * PN[1]; + mRet.m[0][2] = -vOrigin.x * PN[2]; + mRet.m[0][3] = -vOrigin.x * -PD; + + mRet.m[1][0] = -vOrigin.y * PN[0]; + mRet.m[1][1] = dot - vOrigin.y * PN[1]; + mRet.m[1][2] = -vOrigin.y * PN[2]; + mRet.m[1][3] = -vOrigin.y * -PD; + + mRet.m[2][0] = -vOrigin.z * PN[0]; + mRet.m[2][1] = -vOrigin.z * PN[1]; + mRet.m[2][2] = dot - vOrigin.z * PN[2]; + mRet.m[2][3] = -vOrigin.z * -PD; + + mRet.m[3][0] = -PN[0]; + mRet.m[3][1] = -PN[1]; + mRet.m[3][2] = -PN[2]; + mRet.m[3][3] = dot + PD; + + #undef PN + #undef PD + + return mRet; +} + +VMatrix SetupMatrixAxisRot(const Vector &vAxis, vec_t fDegrees) +{ + vec_t s, c, t; + vec_t tx, ty, tz; + vec_t sx, sy, sz; + vec_t fRadians; + + + fRadians = fDegrees * (M_PI / 180.0f); + + s = (vec_t)sin(fRadians); + c = (vec_t)cos(fRadians); + t = 1.0f - c; + + tx = t * vAxis.x; ty = t * vAxis.y; tz = t * vAxis.z; + sx = s * vAxis.x; sy = s * vAxis.y; sz = s * vAxis.z; + + return VMatrix( + tx*vAxis.x + c, tx*vAxis.y - sz, tx*vAxis.z + sy, 0.0f, + tx*vAxis.y + sz, ty*vAxis.y + c, ty*vAxis.z - sx, 0.0f, + tx*vAxis.z - sy, ty*vAxis.z + sx, tz*vAxis.z + c, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} + +VMatrix SetupMatrixAngles(const QAngle &vAngles) +{ + VMatrix mRet; + MatrixFromAngles( vAngles, mRet ); + return mRet; +} + +VMatrix SetupMatrixOrgAngles(const Vector &origin, const QAngle &vAngles) +{ + VMatrix mRet; + mRet.SetupMatrixOrgAngles( origin, vAngles ); + return mRet; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +bool PlaneIntersection( const VPlane &vp1, const VPlane &vp2, const VPlane &vp3, Vector &vOut ) +{ + VMatrix mMat, mInverse; + + mMat.Init( + vp1.m_Normal.x, vp1.m_Normal.y, vp1.m_Normal.z, -vp1.m_Dist, + vp2.m_Normal.x, vp2.m_Normal.y, vp2.m_Normal.z, -vp2.m_Dist, + vp3.m_Normal.x, vp3.m_Normal.y, vp3.m_Normal.z, -vp3.m_Dist, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + if(mMat.InverseGeneral(mInverse)) + { + //vOut = mInverse * Vector(0.0f, 0.0f, 0.0f); + mInverse.GetTranslation( vOut ); + return true; + } + else + { + return false; + } +} + + + +// ------------------------------------------------------------------------------------------- // +// VMatrix functions. +// ------------------------------------------------------------------------------------------- // + +VMatrix& VMatrix::operator=(const VMatrix &mOther) +{ + m[0][0] = mOther.m[0][0]; + m[0][1] = mOther.m[0][1]; + m[0][2] = mOther.m[0][2]; + m[0][3] = mOther.m[0][3]; + + m[1][0] = mOther.m[1][0]; + m[1][1] = mOther.m[1][1]; + m[1][2] = mOther.m[1][2]; + m[1][3] = mOther.m[1][3]; + + m[2][0] = mOther.m[2][0]; + m[2][1] = mOther.m[2][1]; + m[2][2] = mOther.m[2][2]; + m[2][3] = mOther.m[2][3]; + + m[3][0] = mOther.m[3][0]; + m[3][1] = mOther.m[3][1]; + m[3][2] = mOther.m[3][2]; + m[3][3] = mOther.m[3][3]; + + return *this; +} + +bool VMatrix::operator==( const VMatrix& src ) const +{ + return !memcmp( src.m, m, sizeof(m) ); +} + +void VMatrix::MatrixMul( const VMatrix &vm, VMatrix &out ) const +{ + out.Init( + m[0][0]*vm.m[0][0] + m[0][1]*vm.m[1][0] + m[0][2]*vm.m[2][0] + m[0][3]*vm.m[3][0], + m[0][0]*vm.m[0][1] + m[0][1]*vm.m[1][1] + m[0][2]*vm.m[2][1] + m[0][3]*vm.m[3][1], + m[0][0]*vm.m[0][2] + m[0][1]*vm.m[1][2] + m[0][2]*vm.m[2][2] + m[0][3]*vm.m[3][2], + m[0][0]*vm.m[0][3] + m[0][1]*vm.m[1][3] + m[0][2]*vm.m[2][3] + m[0][3]*vm.m[3][3], + + m[1][0]*vm.m[0][0] + m[1][1]*vm.m[1][0] + m[1][2]*vm.m[2][0] + m[1][3]*vm.m[3][0], + m[1][0]*vm.m[0][1] + m[1][1]*vm.m[1][1] + m[1][2]*vm.m[2][1] + m[1][3]*vm.m[3][1], + m[1][0]*vm.m[0][2] + m[1][1]*vm.m[1][2] + m[1][2]*vm.m[2][2] + m[1][3]*vm.m[3][2], + m[1][0]*vm.m[0][3] + m[1][1]*vm.m[1][3] + m[1][2]*vm.m[2][3] + m[1][3]*vm.m[3][3], + + m[2][0]*vm.m[0][0] + m[2][1]*vm.m[1][0] + m[2][2]*vm.m[2][0] + m[2][3]*vm.m[3][0], + m[2][0]*vm.m[0][1] + m[2][1]*vm.m[1][1] + m[2][2]*vm.m[2][1] + m[2][3]*vm.m[3][1], + m[2][0]*vm.m[0][2] + m[2][1]*vm.m[1][2] + m[2][2]*vm.m[2][2] + m[2][3]*vm.m[3][2], + m[2][0]*vm.m[0][3] + m[2][1]*vm.m[1][3] + m[2][2]*vm.m[2][3] + m[2][3]*vm.m[3][3], + + m[3][0]*vm.m[0][0] + m[3][1]*vm.m[1][0] + m[3][2]*vm.m[2][0] + m[3][3]*vm.m[3][0], + m[3][0]*vm.m[0][1] + m[3][1]*vm.m[1][1] + m[3][2]*vm.m[2][1] + m[3][3]*vm.m[3][1], + m[3][0]*vm.m[0][2] + m[3][1]*vm.m[1][2] + m[3][2]*vm.m[2][2] + m[3][3]*vm.m[3][2], + m[3][0]*vm.m[0][3] + m[3][1]*vm.m[1][3] + m[3][2]*vm.m[2][3] + m[3][3]*vm.m[3][3] + ); +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +VMatrix VMatrix::operator*(const VMatrix &vm) const +{ + VMatrix ret; + MatrixMul( vm, ret ); + return ret; +} + +#endif + +bool VMatrix::InverseGeneral(VMatrix &vInverse) const +{ + return MatrixInverseGeneral( *this, vInverse ); +} + + +bool MatrixInverseGeneral(const VMatrix& src, VMatrix& dst) +{ + int iRow, i, j, iTemp, iTest; + vec_t mul, fTest, fLargest; + vec_t mat[4][8]; + int rowMap[4], iLargest; + vec_t *pOut, *pRow, *pScaleRow; + + + // How it's done. + // AX = I + // A = this + // X = the matrix we're looking for + // I = identity + + // Setup AI + for(i=0; i < 4; i++) + { + const vec_t *pIn = src[i]; + pOut = mat[i]; + + for(j=0; j < 4; j++) + { + pOut[j] = pIn[j]; + } + + pOut[4] = 0.0f; + pOut[5] = 0.0f; + pOut[6] = 0.0f; + pOut[7] = 0.0f; + pOut[i+4] = 1.0f; + + rowMap[i] = i; + } + + // Use row operations to get to reduced row-echelon form using these rules: + // 1. Multiply or divide a row by a nonzero number. + // 2. Add a multiple of one row to another. + // 3. Interchange two rows. + + for(iRow=0; iRow < 4; iRow++) + { + // Find the row with the largest element in this column. + fLargest = 0.00001f; + iLargest = -1; + for(iTest=iRow; iTest < 4; iTest++) + { + fTest = (vec_t)FloatMakePositive(mat[rowMap[iTest]][iRow]); + if(fTest > fLargest) + { + iLargest = iTest; + fLargest = fTest; + } + } + + // They're all too small.. sorry. + if(iLargest == -1) + { + return false; + } + + // Swap the rows. + iTemp = rowMap[iLargest]; + rowMap[iLargest] = rowMap[iRow]; + rowMap[iRow] = iTemp; + + pRow = mat[rowMap[iRow]]; + + // Divide this row by the element. + mul = 1.0f / pRow[iRow]; + for(j=0; j < 8; j++) + pRow[j] *= mul; + + pRow[iRow] = 1.0f; // Preserve accuracy... + + // Eliminate this element from the other rows using operation 2. + for(i=0; i < 4; i++) + { + if(i == iRow) + continue; + + pScaleRow = mat[rowMap[i]]; + + // Multiply this row by -(iRow*the element). + mul = -pScaleRow[iRow]; + for(j=0; j < 8; j++) + { + pScaleRow[j] += pRow[j] * mul; + } + + pScaleRow[iRow] = 0.0f; // Preserve accuracy... + } + } + + // The inverse is on the right side of AX now (the identity is on the left). + for(i=0; i < 4; i++) + { + const vec_t *pIn = mat[rowMap[i]] + 4; + pOut = dst.m[i]; + + for(j=0; j < 4; j++) + { + pOut[j] = pIn[j]; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Does a fast inverse, assuming the matrix only contains translation and rotation. +//----------------------------------------------------------------------------- +void MatrixInverseTR( const VMatrix& src, VMatrix &dst ) +{ + Vector vTrans, vNewTrans; + + // Transpose the upper 3x3. + dst.m[0][0] = src.m[0][0]; dst.m[0][1] = src.m[1][0]; dst.m[0][2] = src.m[2][0]; + dst.m[1][0] = src.m[0][1]; dst.m[1][1] = src.m[1][1]; dst.m[1][2] = src.m[2][1]; + dst.m[2][0] = src.m[0][2]; dst.m[2][1] = src.m[1][2]; dst.m[2][2] = src.m[2][2]; + + // Transform the translation. + vTrans.Init( -src.m[0][3], -src.m[1][3], -src.m[2][3] ); + Vector3DMultiply( dst, vTrans, vNewTrans ); + MatrixSetColumn( dst, 3, vNewTrans ); + + // Fill in the bottom row. + dst.m[3][0] = dst.m[3][1] = dst.m[3][2] = 0.0f; + dst.m[3][3] = 1.0f; +} + + +void VMatrix::InverseTR( VMatrix &ret ) const +{ + MatrixInverseTR( *this, ret ); +} + +void MatrixInverseTranspose( const VMatrix& src, VMatrix& dst ) +{ + src.InverseGeneral( dst ); + MatrixTranspose( dst, dst ); +} + +//----------------------------------------------------------------------------- +// Computes the inverse transpose +//----------------------------------------------------------------------------- +void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst ) +{ + VMatrix tmp, out; + tmp.CopyFrom3x4( src ); + ::MatrixInverseTranspose( tmp, out ); + out.Set3x4( dst ); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +VMatrix VMatrix::InverseTR() const +{ + VMatrix ret; + MatrixInverseTR( *this, ret ); + return ret; +} + +Vector VMatrix::GetScale() const +{ + Vector vecs[3]; + + GetBasisVectors(vecs[0], vecs[1], vecs[2]); + + return Vector( + vecs[0].Length(), + vecs[1].Length(), + vecs[2].Length() + ); +} + +VMatrix VMatrix::Scale(const Vector &vScale) +{ + return VMatrix( + m[0][0]*vScale.x, m[0][1]*vScale.y, m[0][2]*vScale.z, m[0][3], + m[1][0]*vScale.x, m[1][1]*vScale.y, m[1][2]*vScale.z, m[1][3], + m[2][0]*vScale.x, m[2][1]*vScale.y, m[2][2]*vScale.z, m[2][3], + m[3][0]*vScale.x, m[3][1]*vScale.y, m[3][2]*vScale.z, 1.0f + ); +} + +VMatrix VMatrix::NormalizeBasisVectors() const +{ + Vector vecs[3]; + VMatrix mRet; + + + GetBasisVectors(vecs[0], vecs[1], vecs[2]); + + VectorNormalize( vecs[0] ); + VectorNormalize( vecs[1] ); + VectorNormalize( vecs[2] ); + + mRet.SetBasisVectors(vecs[0], vecs[1], vecs[2]); + + // Set everything but basis vectors to identity. + mRet.m[3][0] = mRet.m[3][1] = mRet.m[3][2] = 0.0f; + mRet.m[3][3] = 1.0f; + + return mRet; +} + +VMatrix VMatrix::Transpose() const +{ + return VMatrix( + m[0][0], m[1][0], m[2][0], m[3][0], + m[0][1], m[1][1], m[2][1], m[3][1], + m[0][2], m[1][2], m[2][2], m[3][2], + m[0][3], m[1][3], m[2][3], m[3][3]); +} + +// Transpose upper-left 3x3. +VMatrix VMatrix::Transpose3x3() const +{ + return VMatrix( + m[0][0], m[1][0], m[2][0], m[0][3], + m[0][1], m[1][1], m[2][1], m[1][3], + m[0][2], m[1][2], m[2][2], m[2][3], + m[3][0], m[3][1], m[3][2], m[3][3]); +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +bool VMatrix::IsRotationMatrix() const +{ + Vector &v1 = (Vector&)m[0][0]; + Vector &v2 = (Vector&)m[1][0]; + Vector &v3 = (Vector&)m[2][0]; + + return + FloatMakePositive( 1 - v1.Length() ) < 0.01f && + FloatMakePositive( 1 - v2.Length() ) < 0.01f && + FloatMakePositive( 1 - v3.Length() ) < 0.01f && + FloatMakePositive( v1.Dot(v2) ) < 0.01f && + FloatMakePositive( v1.Dot(v3) ) < 0.01f && + FloatMakePositive( v2.Dot(v3) ) < 0.01f; +} + +static void SetupMatrixAnglesInternal( vec_t m[4][4], const QAngle & vAngles ) +{ + float sr, sp, sy, cr, cp, cy; + + SinCos( DEG2RAD( vAngles[YAW] ), &sy, &cy ); + SinCos( DEG2RAD( vAngles[PITCH] ), &sp, &cp ); + SinCos( DEG2RAD( vAngles[ROLL] ), &sr, &cr ); + + // matrix = (YAW * PITCH) * ROLL + m[0][0] = cp*cy; + m[1][0] = cp*sy; + m[2][0] = -sp; + m[0][1] = sr*sp*cy+cr*-sy; + m[1][1] = sr*sp*sy+cr*cy; + m[2][1] = sr*cp; + m[0][2] = (cr*sp*cy+-sr*-sy); + m[1][2] = (cr*sp*sy+-sr*cy); + m[2][2] = cr*cp; + m[0][3] = 0.f; + m[1][3] = 0.f; + m[2][3] = 0.f; +} + +void VMatrix::SetupMatrixOrgAngles( const Vector &origin, const QAngle &vAngles ) +{ + SetupMatrixAnglesInternal( m, vAngles ); + + // Add translation + m[0][3] = origin.x; + m[1][3] = origin.y; + m[2][3] = origin.z; + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + + +void VMatrix::SetupMatrixAngles( const QAngle &vAngles ) +{ + SetupMatrixAnglesInternal( m, vAngles ); + + // Zero everything else + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + + +//----------------------------------------------------------------------------- +// Sets matrix to identity +//----------------------------------------------------------------------------- +void MatrixSetIdentity( VMatrix &dst ) +{ + dst[0][0] = 1.0f; dst[0][1] = 0.0f; dst[0][2] = 0.0f; dst[0][3] = 0.0f; + dst[1][0] = 0.0f; dst[1][1] = 1.0f; dst[1][2] = 0.0f; dst[1][3] = 0.0f; + dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = 1.0f; dst[2][3] = 0.0f; + dst[3][0] = 0.0f; dst[3][1] = 0.0f; dst[3][2] = 0.0f; dst[3][3] = 1.0f; +} + + +//----------------------------------------------------------------------------- +// Setup a matrix from euler angles. +//----------------------------------------------------------------------------- +void MatrixFromAngles( const QAngle& vAngles, VMatrix& dst ) +{ + dst.SetupMatrixOrgAngles( vec3_origin, vAngles ); +} + + +//----------------------------------------------------------------------------- +// Creates euler angles from a matrix +//----------------------------------------------------------------------------- +void MatrixToAngles( const VMatrix& src, QAngle& vAngles ) +{ + float forward[3]; + float left[3]; + float up[3]; + + // Extract the basis vectors from the matrix. Since we only need the Z + // component of the up vector, we don't get X and Y. + forward[0] = src[0][0]; + forward[1] = src[1][0]; + forward[2] = src[2][0]; + left[0] = src[0][1]; + left[1] = src[1][1]; + left[2] = src[2][1]; + up[2] = src[2][2]; + + float xyDist = sqrtf( forward[0] * forward[0] + forward[1] * forward[1] ); + + // enough here to get angles? + if ( xyDist > 0.001f ) + { + // (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis + vAngles[1] = RAD2DEG( atan2f( forward[1], forward[0] ) ); + + // The engine does pitch inverted from this, but we always end up negating it in the DLL + // UNDONE: Fix the engine to make it consistent + // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) ); + vAngles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) ); + + // (roll) z = ATAN( left.z, up.z ); + vAngles[2] = RAD2DEG( atan2f( left[2], up[2] ) ); + } + else // forward is mostly Z, gimbal lock- + { + // (yaw) y = ATAN( -left.x, left.y ); -- forward is mostly z, so use right for yaw + vAngles[1] = RAD2DEG( atan2f( -left[0], left[1] ) ); + + // The engine does pitch inverted from this, but we always end up negating it in the DLL + // UNDONE: Fix the engine to make it consistent + // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) ); + vAngles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) ); + + // Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll) + vAngles[2] = 0; + } +} + + +//----------------------------------------------------------------------------- +// Transpose +//----------------------------------------------------------------------------- +inline void Swap( float& a, float& b ) +{ + float tmp = a; + a = b; + b = tmp; +} + +void MatrixTranspose( const VMatrix& src, VMatrix& dst ) +{ + if (&src == &dst) + { + Swap( dst[0][1], dst[1][0] ); + Swap( dst[0][2], dst[2][0] ); + Swap( dst[0][3], dst[3][0] ); + Swap( dst[1][2], dst[2][1] ); + Swap( dst[1][3], dst[3][1] ); + Swap( dst[2][3], dst[3][2] ); + } + else + { + dst[0][0] = src[0][0]; dst[0][1] = src[1][0]; dst[0][2] = src[2][0]; dst[0][3] = src[3][0]; + dst[1][0] = src[0][1]; dst[1][1] = src[1][1]; dst[1][2] = src[2][1]; dst[1][3] = src[3][1]; + dst[2][0] = src[0][2]; dst[2][1] = src[1][2]; dst[2][2] = src[2][2]; dst[2][3] = src[3][2]; + dst[3][0] = src[0][3]; dst[3][1] = src[1][3]; dst[3][2] = src[2][3]; dst[3][3] = src[3][3]; + } +} + + +//----------------------------------------------------------------------------- +// Matrix copy +//----------------------------------------------------------------------------- + +void MatrixCopy( const VMatrix& src, VMatrix& dst ) +{ + if (&src != &dst) + { + memcpy( dst.m, src.m, 16 * sizeof(float) ); + } +} + +//----------------------------------------------------------------------------- +// Matrix multiply +//----------------------------------------------------------------------------- +typedef float VMatrixRaw_t[4]; + +void MatrixMultiply( const VMatrix& src1, const VMatrix& src2, VMatrix& dst ) +{ + // Make sure it works if src1 == dst or src2 == dst + VMatrix tmp1, tmp2; + const VMatrixRaw_t* s1 = (&src1 == &dst) ? tmp1.m : src1.m; + const VMatrixRaw_t* s2 = (&src2 == &dst) ? tmp2.m : src2.m; + + if (&src1 == &dst) + { + MatrixCopy( src1, tmp1 ); + } + if (&src2 == &dst) + { + MatrixCopy( src2, tmp2 ); + } + + dst[0][0] = s1[0][0] * s2[0][0] + s1[0][1] * s2[1][0] + s1[0][2] * s2[2][0] + s1[0][3] * s2[3][0]; + dst[0][1] = s1[0][0] * s2[0][1] + s1[0][1] * s2[1][1] + s1[0][2] * s2[2][1] + s1[0][3] * s2[3][1]; + dst[0][2] = s1[0][0] * s2[0][2] + s1[0][1] * s2[1][2] + s1[0][2] * s2[2][2] + s1[0][3] * s2[3][2]; + dst[0][3] = s1[0][0] * s2[0][3] + s1[0][1] * s2[1][3] + s1[0][2] * s2[2][3] + s1[0][3] * s2[3][3]; + + dst[1][0] = s1[1][0] * s2[0][0] + s1[1][1] * s2[1][0] + s1[1][2] * s2[2][0] + s1[1][3] * s2[3][0]; + dst[1][1] = s1[1][0] * s2[0][1] + s1[1][1] * s2[1][1] + s1[1][2] * s2[2][1] + s1[1][3] * s2[3][1]; + dst[1][2] = s1[1][0] * s2[0][2] + s1[1][1] * s2[1][2] + s1[1][2] * s2[2][2] + s1[1][3] * s2[3][2]; + dst[1][3] = s1[1][0] * s2[0][3] + s1[1][1] * s2[1][3] + s1[1][2] * s2[2][3] + s1[1][3] * s2[3][3]; + + dst[2][0] = s1[2][0] * s2[0][0] + s1[2][1] * s2[1][0] + s1[2][2] * s2[2][0] + s1[2][3] * s2[3][0]; + dst[2][1] = s1[2][0] * s2[0][1] + s1[2][1] * s2[1][1] + s1[2][2] * s2[2][1] + s1[2][3] * s2[3][1]; + dst[2][2] = s1[2][0] * s2[0][2] + s1[2][1] * s2[1][2] + s1[2][2] * s2[2][2] + s1[2][3] * s2[3][2]; + dst[2][3] = s1[2][0] * s2[0][3] + s1[2][1] * s2[1][3] + s1[2][2] * s2[2][3] + s1[2][3] * s2[3][3]; + + dst[3][0] = s1[3][0] * s2[0][0] + s1[3][1] * s2[1][0] + s1[3][2] * s2[2][0] + s1[3][3] * s2[3][0]; + dst[3][1] = s1[3][0] * s2[0][1] + s1[3][1] * s2[1][1] + s1[3][2] * s2[2][1] + s1[3][3] * s2[3][1]; + dst[3][2] = s1[3][0] * s2[0][2] + s1[3][1] * s2[1][2] + s1[3][2] * s2[2][2] + s1[3][3] * s2[3][2]; + dst[3][3] = s1[3][0] * s2[0][3] + s1[3][1] * s2[1][3] + s1[3][2] * s2[2][3] + s1[3][3] * s2[3][3]; +} + +//----------------------------------------------------------------------------- +// Matrix/vector multiply +//----------------------------------------------------------------------------- + +void Vector4DMultiply( const VMatrix& src1, Vector4D const& src2, Vector4D& dst ) +{ + // Make sure it works if src2 == dst + Vector4D tmp; + Vector4D const&v = (&src2 == &dst) ? tmp : src2; + + if (&src2 == &dst) + { + Vector4DCopy( src2, tmp ); + } + + dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2] + src1[0][3] * v[3]; + dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2] + src1[1][3] * v[3]; + dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2] + src1[2][3] * v[3]; + dst[3] = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2] + src1[3][3] * v[3]; +} + +//----------------------------------------------------------------------------- +// Matrix/vector multiply +//----------------------------------------------------------------------------- + +void Vector4DMultiplyPosition( const VMatrix& src1, Vector const& src2, Vector4D& dst ) +{ + // Make sure it works if src2 == dst + Vector tmp; + Vector const&v = ( &src2 == &dst.AsVector3D() ) ? static_cast(tmp) : src2; + + if (&src2 == &dst.AsVector3D()) + { + VectorCopy( src2, tmp ); + } + + dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2] + src1[0][3]; + dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2] + src1[1][3]; + dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2] + src1[2][3]; + dst[3] = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2] + src1[3][3]; +} + + + +//----------------------------------------------------------------------------- +// Matrix/vector multiply +//----------------------------------------------------------------------------- + +void Vector3DMultiply( const VMatrix &src1, const Vector &src2, Vector &dst ) +{ + // Make sure it works if src2 == dst + Vector tmp; + const Vector &v = (&src2 == &dst) ? static_cast(tmp) : src2; + + if( &src2 == &dst ) + { + VectorCopy( src2, tmp ); + } + + dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2]; + dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2]; + dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2]; +} + + +//----------------------------------------------------------------------------- +// Vector3DMultiplyPositionProjective treats src2 as if it's a point +// and does the perspective divide at the end +//----------------------------------------------------------------------------- +void Vector3DMultiplyPositionProjective( const VMatrix& src1, const Vector &src2, Vector& dst ) +{ + // Make sure it works if src2 == dst + Vector tmp; + const Vector &v = (&src2 == &dst) ? static_cast(tmp): src2; + if( &src2 == &dst ) + { + VectorCopy( src2, tmp ); + } + + float w = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2] + src1[3][3]; + if ( w != 0.0f ) + { + w = 1.0f / w; + } + + dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2] + src1[0][3]; + dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2] + src1[1][3]; + dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2] + src1[2][3]; + dst *= w; +} + + +//----------------------------------------------------------------------------- +// Vector3DMultiplyProjective treats src2 as if it's a direction +// and does the perspective divide at the end +//----------------------------------------------------------------------------- +void Vector3DMultiplyProjective( const VMatrix& src1, const Vector &src2, Vector& dst ) +{ + // Make sure it works if src2 == dst + Vector tmp; + const Vector &v = (&src2 == &dst) ? static_cast(tmp) : src2; + if( &src2 == &dst ) + { + VectorCopy( src2, tmp ); + } + + float w; + dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2]; + dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2]; + dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2]; + w = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2]; + if (w != 0.0f) + { + dst /= w; + } + else + { + dst = vec3_origin; + } +} + + +//----------------------------------------------------------------------------- +// Multiplies the vector by the transpose of the matrix +//----------------------------------------------------------------------------- +void Vector4DMultiplyTranspose( const VMatrix& src1, Vector4D const& src2, Vector4D& dst ) +{ + // Make sure it works if src2 == dst + bool srcEqualsDst = (&src2 == &dst); + + Vector4D tmp; + Vector4D const&v = srcEqualsDst ? tmp : src2; + + if (srcEqualsDst) + { + Vector4DCopy( src2, tmp ); + } + + dst[0] = src1[0][0] * v[0] + src1[1][0] * v[1] + src1[2][0] * v[2] + src1[3][0] * v[3]; + dst[1] = src1[0][1] * v[0] + src1[1][1] * v[1] + src1[2][1] * v[2] + src1[3][1] * v[3]; + dst[2] = src1[0][2] * v[0] + src1[1][2] * v[1] + src1[2][2] * v[2] + src1[3][2] * v[3]; + dst[3] = src1[0][3] * v[0] + src1[1][3] * v[1] + src1[2][3] * v[2] + src1[3][3] * v[3]; +} + +//----------------------------------------------------------------------------- +// Multiplies the vector by the transpose of the matrix +//----------------------------------------------------------------------------- +void Vector3DMultiplyTranspose( const VMatrix& src1, const Vector& src2, Vector& dst ) +{ + // Make sure it works if src2 == dst + bool srcEqualsDst = (&src2 == &dst); + + Vector tmp; + const Vector&v = srcEqualsDst ? static_cast(tmp) : src2; + + if (srcEqualsDst) + { + VectorCopy( src2, tmp ); + } + + dst[0] = src1[0][0] * v[0] + src1[1][0] * v[1] + src1[2][0] * v[2]; + dst[1] = src1[0][1] * v[0] + src1[1][1] * v[1] + src1[2][1] * v[2]; + dst[2] = src1[0][2] * v[0] + src1[1][2] * v[1] + src1[2][2] * v[2]; +} + + +//----------------------------------------------------------------------------- +// Transform a plane +//----------------------------------------------------------------------------- +void MatrixTransformPlane( const VMatrix &src, const cplane_t &inPlane, cplane_t &outPlane ) +{ + // What we want to do is the following: + // 1) transform the normal into the new space. + // 2) Determine a point on the old plane given by plane dist * plane normal + // 3) Transform that point into the new space + // 4) Plane dist = DotProduct( new normal, new point ) + + // An optimized version, which works if the plane is orthogonal. + // 1) Transform the normal into the new space + // 2) Realize that transforming the old plane point into the new space + // is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ] + // where d = old plane dist, n' = transformed normal, Tn = translational component of transform + // 3) Compute the new plane dist using the dot product of the normal result of #2 + + // For a correct result, this should be an inverse-transpose matrix + // but that only matters if there are nonuniform scale or skew factors in this matrix. + Vector vTrans; + Vector3DMultiply( src, inPlane.normal, outPlane.normal ); + outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal ); + outPlane.dist += DotProduct( outPlane.normal, src.GetTranslation(vTrans) ); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +VPlane VMatrix::operator*(const VPlane &thePlane) const +{ + VPlane ret; + TransformPlane( thePlane, ret ); + return ret; +} + +#endif + + +//----------------------------------------------------------------------------- +// Builds a rotation matrix that rotates one direction vector into another +//----------------------------------------------------------------------------- +void MatrixBuildTranslation( VMatrix& dst, float x, float y, float z ) +{ + MatrixSetIdentity( dst ); + dst[0][3] = x; + dst[1][3] = y; + dst[2][3] = z; +} + +void MatrixBuildTranslation( VMatrix& dst, const Vector &translation ) +{ + MatrixSetIdentity( dst ); + dst[0][3] = translation[0]; + dst[1][3] = translation[1]; + dst[2][3] = translation[2]; +} + + +//----------------------------------------------------------------------------- +// Purpose: Builds the matrix for a counterclockwise rotation about an arbitrary axis. +// +// | ax2 + (1 - ax2)cosQ axay(1 - cosQ) - azsinQ azax(1 - cosQ) + aysinQ | +// Ra(Q) = | axay(1 - cosQ) + azsinQ ay2 + (1 - ay2)cosQ ayaz(1 - cosQ) - axsinQ | +// | azax(1 - cosQ) - aysinQ ayaz(1 - cosQ) + axsinQ az2 + (1 - az2)cosQ | +// +// Input : mat - +// vAxisOrRot - +// angle - +//----------------------------------------------------------------------------- +void MatrixBuildRotationAboutAxis( VMatrix &dst, const Vector &vAxisOfRot, float angleDegrees ) +{ + MatrixBuildRotationAboutAxis( vAxisOfRot, angleDegrees, const_cast< matrix3x4_t &> ( dst.As3x4() ) ); + dst[3][0] = 0; + dst[3][1] = 0; + dst[3][2] = 0; + dst[3][3] = 1; +} + + +//----------------------------------------------------------------------------- +// Builds a rotation matrix that rotates one direction vector into another +//----------------------------------------------------------------------------- +void MatrixBuildRotation( VMatrix &dst, const Vector& initialDirection, const Vector& finalDirection ) +{ + float angle = DotProduct( initialDirection, finalDirection ); + Assert( IsFinite(angle) ); + + Vector axis; + + // No rotation required + if (angle - 1.0 > -1e-3) + { + // parallel case + MatrixSetIdentity(dst); + return; + } + else if (angle + 1.0 < 1e-3) + { + // antiparallel case, pick any axis in the plane + // perpendicular to the final direction. Choose the direction (x,y,z) + // which has the minimum component of the final direction, use that + // as an initial guess, then subtract out the component which is + // parallel to the final direction + int idx = 0; + if (FloatMakePositive(finalDirection[1]) < FloatMakePositive(finalDirection[idx])) + idx = 1; + if (FloatMakePositive(finalDirection[2]) < FloatMakePositive(finalDirection[idx])) + idx = 2; + + axis.Init( 0, 0, 0 ); + axis[idx] = 1.0f; + VectorMA( axis, -DotProduct( axis, finalDirection ), finalDirection, axis ); + VectorNormalize(axis); + angle = 180.0f; + } + else + { + CrossProduct( initialDirection, finalDirection, axis ); + VectorNormalize( axis ); + angle = acos(angle) * 180 / M_PI; + } + + MatrixBuildRotationAboutAxis( dst, axis, angle ); + +#ifdef _DEBUG + Vector test; + Vector3DMultiply( dst, initialDirection, test ); + test -= finalDirection; + Assert( test.LengthSqr() < 1e-3 ); +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void MatrixBuildRotateZ( VMatrix &dst, float angleDegrees ) +{ + float radians = angleDegrees * ( M_PI / 180.0f ); + + float fSin = ( float )sin( radians ); + float fCos = ( float )cos( radians ); + + dst[0][0] = fCos; dst[0][1] = -fSin; dst[0][2] = 0.0f; dst[0][3] = 0.0f; + dst[1][0] = fSin; dst[1][1] = fCos; dst[1][2] = 0.0f; dst[1][3] = 0.0f; + dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = 1.0f; dst[2][3] = 0.0f; + dst[3][0] = 0.0f; dst[3][1] = 0.0f; dst[3][2] = 0.0f; dst[3][3] = 1.0f; +} + +// Builds a scale matrix +void MatrixBuildScale( VMatrix &dst, float x, float y, float z ) +{ + dst[0][0] = x; dst[0][1] = 0.0f; dst[0][2] = 0.0f; dst[0][3] = 0.0f; + dst[1][0] = 0.0f; dst[1][1] = y; dst[1][2] = 0.0f; dst[1][3] = 0.0f; + dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = z; dst[2][3] = 0.0f; + dst[3][0] = 0.0f; dst[3][1] = 0.0f; dst[3][2] = 0.0f; dst[3][3] = 1.0f; +} + +void MatrixBuildScale( VMatrix &dst, const Vector& scale ) +{ + MatrixBuildScale( dst, scale.x, scale.y, scale.z ); +} + +void MatrixBuildPerspective( VMatrix &dst, float fovX, float fovY, float zNear, float zFar ) +{ + // FIXME: collapse all of this into one matrix after we figure out what all should be in here. + float width = 2 * zNear * tan( fovX * ( M_PI/180.0f ) * 0.5f ); + float height = 2 * zNear * tan( fovY * ( M_PI/180.0f ) * 0.5f ); + + memset( dst.Base(), 0, sizeof( dst ) ); + dst[0][0] = 2.0F * zNear / width; + dst[1][1] = 2.0F * zNear / height; + dst[2][2] = -zFar / ( zNear - zFar ); + dst[3][2] = 1.0f; + dst[2][3] = zNear * zFar / ( zNear - zFar ); + + // negate X and Y so that X points right, and Y points up. + VMatrix negateXY; + negateXY.Identity(); + negateXY[0][0] = -1.0f; + negateXY[1][1] = -1.0f; + MatrixMultiply( negateXY, dst, dst ); + + VMatrix addW; + addW.Identity(); + addW[0][3] = 1.0f; + addW[1][3] = 1.0f; + addW[2][3] = 0.0f; + MatrixMultiply( addW, dst, dst ); + + VMatrix scaleHalf; + scaleHalf.Identity(); + scaleHalf[0][0] = 0.5f; + scaleHalf[1][1] = 0.5f; + MatrixMultiply( scaleHalf, dst, dst ); +} + +static inline void CalculateAABBForNormalizedFrustum_Helper( float x, float y, float z, const VMatrix &volumeToWorld, Vector &mins, Vector &maxs ) +{ + Vector volumeSpacePos( x, y, z ); + + // Make sure it's been clipped + Assert( volumeSpacePos[0] >= -1e-3f ); + Assert( volumeSpacePos[0] - 1.0f <= 1e-3f ); + Assert( volumeSpacePos[1] >= -1e-3f ); + Assert( volumeSpacePos[1] - 1.0f <= 1e-3f ); + Assert( volumeSpacePos[2] >= -1e-3f ); + Assert( volumeSpacePos[2] - 1.0f <= 1e-3f ); + + Vector worldPos; + Vector3DMultiplyPositionProjective( volumeToWorld, volumeSpacePos, worldPos ); + AddPointToBounds( worldPos, mins, maxs ); +} + +//----------------------------------------------------------------------------- +// Given an inverse projection matrix, take the extremes of the space in transformed into world space and +// get a bounding box. +//----------------------------------------------------------------------------- +void CalculateAABBFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pMins, Vector *pMaxs ) +{ + // FIXME: Could maybe do better than the compile with all of these multiplies by 0 and 1. + ClearBounds( *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 0, 0, 0, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 0, 0, 1, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 0, 1, 0, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 0, 1, 1, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 1, 0, 0, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 1, 0, 1, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 1, 1, 0, volumeToWorld, *pMins, *pMaxs ); + CalculateAABBForNormalizedFrustum_Helper( 1, 1, 1, volumeToWorld, *pMins, *pMaxs ); +} + +void CalculateAABBFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pMins, Vector *pMaxs ) +{ + VMatrix volumeToWorld; + MatrixInverseGeneral( worldToVolume, volumeToWorld ); + CalculateAABBFromProjectionMatrixInverse( volumeToWorld, pMins, pMaxs ); +} + +//----------------------------------------------------------------------------- +// Given an inverse projection matrix, take the extremes of the space in transformed into world space and +// get a bounding sphere. +//----------------------------------------------------------------------------- +void CalculateSphereFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pCenter, float *pflRadius ) +{ + // FIXME: Could maybe do better than the compile with all of these multiplies by 0 and 1. + + // Need 3 points: the endpoint of the line through the center of the near + far planes, + // and one point on the far plane. From that, we can derive a point somewhere on the center line + // which would produce the smallest bounding sphere. + Vector vecCenterNear, vecCenterFar, vecNearEdge, vecFarEdge; + Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.5f, 0.5f, 0.0f ), vecCenterNear ); + Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.5f, 0.5f, 1.0f ), vecCenterFar ); + Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.0f, 0.0f, 0.0f ), vecNearEdge ); + Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.0f, 0.0f, 1.0f ), vecFarEdge ); + + // Let the distance between the near + far center points = l + // Let the distance between the near center point + near edge point = h1 + // Let the distance between the far center point + far edge point = h2 + // Let the distance along the center line from the near point to the sphere center point = x + // Then let the distance between the sphere center point + near edge point == + // the distance between the sphere center point + far edge point == r == radius of sphere + // Then h1^2 + x^2 == r^2 == (l-x)^2 + h2^2 + // h1^x + x^2 = l^2 - 2 * l * x + x^2 + h2^2 + // 2 * l * x = l^2 + h2^2 - h1^2 + // x = (l^2 + h2^2 - h1^2) / (2 * l) + // r = sqrt( hl^1 + x^2 ) + Vector vecDelta; + VectorSubtract( vecCenterFar, vecCenterNear, vecDelta ); + float l = vecDelta.Length(); + float h1Sqr = vecCenterNear.DistToSqr( vecNearEdge ); + float h2Sqr = vecCenterFar.DistToSqr( vecFarEdge ); + float x = (l*l + h2Sqr - h1Sqr) / (2.0f * l); + VectorMA( vecCenterNear, (x / l), vecDelta, *pCenter ); + *pflRadius = sqrt( h1Sqr + x*x ); +} + +//----------------------------------------------------------------------------- +// Given a projection matrix, take the extremes of the space in transformed into world space and +// get a bounding sphere. +//----------------------------------------------------------------------------- +void CalculateSphereFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pCenter, float *pflRadius ) +{ + VMatrix volumeToWorld; + MatrixInverseGeneral( worldToVolume, volumeToWorld ); + CalculateSphereFromProjectionMatrixInverse( volumeToWorld, pCenter, pflRadius ); +} + + +static inline void FrustumPlanesFromMatrixHelper( const VMatrix &shadowToWorld, const Vector &p1, const Vector &p2, const Vector &p3, + Vector &normal, float &dist ) +{ + Vector world1, world2, world3; + Vector3DMultiplyPositionProjective( shadowToWorld, p1, world1 ); + Vector3DMultiplyPositionProjective( shadowToWorld, p2, world2 ); + Vector3DMultiplyPositionProjective( shadowToWorld, p3, world3 ); + + Vector v1, v2; + VectorSubtract( world2, world1, v1 ); + VectorSubtract( world3, world1, v2 ); + + CrossProduct( v1, v2, normal ); + VectorNormalize( normal ); + dist = DotProduct( normal, world1 ); +} + +void FrustumPlanesFromMatrix( const VMatrix &clipToWorld, Frustum_t &frustum ) +{ + Vector normal; + float dist; + + FrustumPlanesFromMatrixHelper( clipToWorld, + Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), Vector( 0.0f, 1.0f, 0.0f ), normal, dist ); + frustum.SetPlane( FRUSTUM_NEARZ, PLANE_ANYZ, normal, dist ); + + FrustumPlanesFromMatrixHelper( clipToWorld, + Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), normal, dist ); + frustum.SetPlane( FRUSTUM_FARZ, PLANE_ANYZ, normal, dist ); + + FrustumPlanesFromMatrixHelper( clipToWorld, + Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), normal, dist ); + frustum.SetPlane( FRUSTUM_RIGHT, PLANE_ANYZ, normal, dist ); + + FrustumPlanesFromMatrixHelper( clipToWorld, + Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 0.0f, 1.0f ), normal, dist ); + frustum.SetPlane( FRUSTUM_LEFT, PLANE_ANYZ, normal, dist ); + + FrustumPlanesFromMatrixHelper( clipToWorld, + Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), normal, dist ); + frustum.SetPlane( FRUSTUM_TOP, PLANE_ANYZ, normal, dist ); + + FrustumPlanesFromMatrixHelper( clipToWorld, + Vector( 1.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), normal, dist ); + frustum.SetPlane( FRUSTUM_BOTTOM, PLANE_ANYZ, normal, dist ); +} + +void MatrixBuildOrtho( VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar ) +{ + // FIXME: This is being used incorrectly! Should read: + // D3DXMatrixOrthoOffCenterRH( &matrix, left, right, bottom, top, zNear, zFar ); + // Which is certainly why we need these extra -1 scales in y. Bleah + + // NOTE: The camera can be imagined as the following diagram: + // /z + // / + // /____ x Z is going into the screen + // | + // | + // |y + // + // (0,0,z) represents the upper-left corner of the screen. + // Our projection transform needs to transform from this space to a LH coordinate + // system that looks thusly: + // + // y| /z + // | / + // |/____ x Z is going into the screen + // + // Where x,y lies between -1 and 1, and z lies from 0 to 1 + // This is because the viewport transformation from projection space to pixels + // introduces a -1 scale in the y coordinates + // D3DXMatrixOrthoOffCenterRH( &matrix, left, right, top, bottom, zNear, zFar ); + + dst.Init( 2.0f / ( right - left ), 0.0f, 0.0f, ( left + right ) / ( left - right ), + 0.0f, 2.0f / ( bottom - top ), 0.0f, ( bottom + top ) / ( top - bottom ), + 0.0f, 0.0f, 1.0f / ( zNear - zFar ), zNear / ( zNear - zFar ), + 0.0f, 0.0f, 0.0f, 1.0f ); +} + +void MatrixBuildPerspectiveZRange( VMatrix& dst, double flZNear, double flZFar ) +{ + dst.m[2][0] = 0.0f; + dst.m[2][1] = 0.0f; + dst.m[2][2] = flZFar / ( flZNear - flZFar ); + dst.m[2][3] = flZNear * flZFar / ( flZNear - flZFar ); +} + +void MatrixBuildPerspectiveX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar ) +{ + float flWidthScale = 1.0f / tanf( flFovX * M_PI / 360.0f ); + float flHeightScale = flAspect * flWidthScale; + dst.Init( flWidthScale, 0.0f, 0.0f, 0.0f, + 0.0f, flHeightScale, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f ); + + MatrixBuildPerspectiveZRange ( dst, flZNear, flZFar ); +} + +void MatrixBuildPerspectiveOffCenterX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right ) +{ + float flWidth = tanf( flFovX * M_PI / 360.0f ); + float flHeight = flWidth / flAspect; + + // bottom, top, left, right are 0..1 so convert to -/2../2 + float flLeft = -(flWidth/2.0f) * (1.0f - left) + left * (flWidth/2.0f); + float flRight = -(flWidth/2.0f) * (1.0f - right) + right * (flWidth/2.0f); + float flBottom = -(flHeight/2.0f) * (1.0f - bottom) + bottom * (flHeight/2.0f); + float flTop = -(flHeight/2.0f) * (1.0f - top) + top * (flHeight/2.0f); + + dst.Init( 1.0f / (flRight-flLeft), 0.0f, (flLeft+flRight)/(flRight-flLeft), 0.0f, + 0.0f, 1.0f /(flTop-flBottom), (flTop+flBottom)/(flTop-flBottom), 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f ); + + MatrixBuildPerspectiveZRange ( dst, flZNear, flZFar ); +} +#endif // !_STATIC_LINKED || _SHARED_LIB + diff --git a/public/BitmapFontFile.h b/public/BitmapFontFile.h new file mode 100644 index 0000000..9628c3d --- /dev/null +++ b/public/BitmapFontFile.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Baked Bitmap fonts +// +//=========================================================================== + +#ifndef _BITMAPFONTFILE_H_ +#define _BITMAPFONTFILE_H_ + +#include "datamap.h" + +#define BITMAPFONT_ID (('T'<<24)|('N'<<16)|('F'<<8)|('V')) +#define BITMAPFONT_VERSION 3 + +// style flags +#define BF_BOLD 0x0001 +#define BF_ITALIC 0x0002 +#define BF_OUTLINED 0x0004 +#define BF_DROPSHADOW 0x0008 +#define BF_BLURRED 0x0010 +#define BF_SCANLINES 0x0020 +#define BF_ANTIALIASED 0x0040 +#define BF_CUSTOM 0x0080 + +#pragma pack(1) //X360TBD +typedef struct BitmapGlyph_s +{ + DECLARE_BYTESWAP_DATADESC(); + short x; + short y; + short w; + short h; + short a; + short b; + short c; +} BitmapGlyph_t; + +typedef struct BitmapFont_s +{ + DECLARE_BYTESWAP_DATADESC(); + int m_id; + int m_Version; + short m_PageWidth; + short m_PageHeight; + short m_MaxCharWidth; + short m_MaxCharHeight; + short m_Flags; + short m_Ascent; + short m_NumGlyphs; + unsigned char m_TranslateTable[256]; +} BitmapFont_t; +#pragma pack() + +#endif \ No newline at end of file diff --git a/public/Color.h b/public/Color.h new file mode 100644 index 0000000..e800a37 --- /dev/null +++ b/public/Color.h @@ -0,0 +1,103 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COLOR_H +#define COLOR_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Basic handler for an rgb set of colors +// This class is fully inline +//----------------------------------------------------------------------------- +class Color +{ +public: + // constructors + Color() + { + *((int *)this) = 0; + } + Color(int _r,int _g,int _b) + { + SetColor(_r, _g, _b, 0); + } + Color(int _r,int _g,int _b,int _a) + { + SetColor(_r, _g, _b, _a); + } + + // set the color + // r - red component (0-255) + // g - green component (0-255) + // b - blue component (0-255) + // a - alpha component, controls transparency (0 - transparent, 255 - opaque); + void SetColor(int _r, int _g, int _b, int _a = 0) + { + _color[0] = (unsigned char)_r; + _color[1] = (unsigned char)_g; + _color[2] = (unsigned char)_b; + _color[3] = (unsigned char)_a; + } + + void GetColor(int &_r, int &_g, int &_b, int &_a) const + { + _r = _color[0]; + _g = _color[1]; + _b = _color[2]; + _a = _color[3]; + } + + void SetRawColor( int color32 ) + { + *((int *)this) = color32; + } + + int GetRawColor() const + { + return *((int *)this); + } + + inline int r() const { return _color[0]; } + inline int g() const { return _color[1]; } + inline int b() const { return _color[2]; } + inline int a() const { return _color[3]; } + + unsigned char &operator[](int index) + { + return _color[index]; + } + + const unsigned char &operator[](int index) const + { + return _color[index]; + } + + bool operator == (const Color &rhs) const + { + return ( *((int *)this) == *((int *)&rhs) ); + } + + bool operator != (const Color &rhs) const + { + return !(operator==(rhs)); + } + + Color &operator=( const Color &rhs ) + { + SetRawColor( rhs.GetRawColor() ); + return *this; + } + +private: + unsigned char _color[4]; +}; + + +#endif // COLOR_H diff --git a/public/Friends/AddOns/AddOnMessages.h b/public/Friends/AddOns/AddOnMessages.h new file mode 100644 index 0000000..ca778f9 --- /dev/null +++ b/public/Friends/AddOns/AddOnMessages.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ADDONMESSAGES_H +#define ADDONMESSAGES_H +#pragma once + +enum GameMessageIDs +{ + GAME_MSG_TEXT = 1, // text chat message + GAME_MSG_DATA, // binary game data + + GAME_MSG_INVITE_REQUEST, + GAME_MSG_INVITE_RESPONSE, + GAME_MSG_REJOIN_REQUEST, + GAME_MSG_REJOIN_RESPONSE, + + GAME_MSG_INVITE_PERMISSION, // ask permission to invite someone + GAME_MSG_INVITE_NOTIFY, // tell everybody that we're inviting + GAME_MSG_INVITE_DENIED, + + GAME_MSG_PLAYER_STATUS_UPDATE, + GAME_MSG_SETUP_INFO, // when user joins a game, host send the setup information of who's in the game + GAME_MSG_INVITE_CANCEL, // host has cancelled an invite + GAME_MSG_GAME_START, // if a game has a setup phase, this tells everybody the game has started + + GAME_MSG_PLAYER_KICK, // player kicked from game + GAME_MSG_UPDATING, + GAME_MSG_UP_TO_DATE, // player is up to date and ready to get data + + GAME_MSG_STARTING_CARD_HAND = 300, + GAME_MSG_STARTING_PLAYER, + GAME_MSG_CARD_PLAY, + + GAME_MSG_CHEAT_POSSIBLE = 400, // when host detects a possible cheat + + GAME_MSG_MOVE = 500, + GAME_MSG_COLOR_CHOICE, + GAME_MSG_RECONNECT_DATA, + GAME_MSG_QUIT, + GAME_MSG_PASS, + + GAME_MSG_ABORT, // phase these out + GAME_MSG_WAITING_ABORT, + +// GAME_MSG_CLOSE_WINDOW, + + // special individual game messages should take IDs 1000 and over +}; + + +#endif // ADDONMESSAGES_H + diff --git a/public/Friends/AddOns/AddOnTypes.h b/public/Friends/AddOns/AddOnTypes.h new file mode 100644 index 0000000..b6cf75f --- /dev/null +++ b/public/Friends/AddOns/AddOnTypes.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ADDONTYPES_H +#define ADDONTYPES_H +#pragma once + +#ifndef WIN32 + typedef unsigned long long SessionInt64; +#else + typedef unsigned __int64 SessionInt64; +#endif + +#endif // ADDONTYPES_H + diff --git a/public/Friends/AddOns/ISteamAddOn.h b/public/Friends/AddOns/ISteamAddOn.h new file mode 100644 index 0000000..ff395c3 --- /dev/null +++ b/public/Friends/AddOns/ISteamAddOn.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Interface to a Steam Add On +// +//=============================================================================// + +#ifndef ISTEAMADDON_H +#define ISTEAMADDON_H +#pragma once + +#include "interface.h" +#include "AddOnTypes.h" +#include + +class CUtlMsgBuffer; + +class ISteamAddOn : public IBaseInterface +{ +public: + // allows SteamAddOn to link to the core vgui factories + virtual bool Initialize(CreateInterfaceFn *vguiFactories, int factoryCount) = 0; + + // allows SteamAddOns to link to all other modules + virtual bool PostInitialize(CreateInterfaceFn *modules, int factoryCount) = 0; + + // when Friends closes down - all SteamAddOns are notified + virtual void Deactivate() = 0; + + // notifies the addon who its VGUI parent panel is + virtual void SetParent( vgui::Panel *parent ) = 0; + + // notifies the SteamAddOn of the user's ID and username. + // Note: username can be set mulitple times due to changing of name + virtual void SetUserID(unsigned int userID) = 0; + virtual void SetUserName(const char *userName) = 0; + + // Query if there are any 'open' sessions - open meaning allowing new users to join the sessions + virtual int QueryOpenSessionCount() = 0; + + // will be valid right after a call to QueryOpenInviteCount will set the addOnSessionID and hostname for + // any open sessions for this addOn. Return true if it's a valid index + virtual bool QueryOpenSessionInfo(int nOpenGameIndex, SessionInt64 &addOnSessionID, char *pszHostName) = 0; + + // returns true if this userID is involved in an addOnSession with this ID + virtual bool QueryUserInvolved(SessionInt64 addOnSessionID, unsigned int userID) = 0; + + // if session doesn't exist, then the SteamAddOn body should deal with it + virtual bool OnReceiveMsg(SessionInt64 addOnSessionID, CUtlMsgBuffer *msgBuffer) = 0; + + // Let's the SteamAddOn know when when any friend's status has changed + virtual void OnFriendStatusChanged() = 0; + + // A request to start/join this AddOn with this user ID/name. addOnSessionID will be zero if it's a new session request + virtual void OnInviteUser(unsigned int targetUserID, const char *username, SessionInt64 addOnSessionID) = 0; + + // user accepted this host's invite request + virtual void OnAcceptInviteRequest(unsigned int hostID, const char *hostUserName, SessionInt64 addOnSessionID, const char *pAppData, int dataLen) = 0; + + // user accepted this host's rejoin request + virtual void OnAcceptRejoinRequest(unsigned int hostID, const char *hostUserName, SessionInt64 addOnSessionID, const char *pAppData, int dataLen) = 0; + + // user starts this addOn from a menu + virtual void StartAddOn() = 0; +}; + +#define STEAMADDON_INTERFACE_VERSION "SteamAddOn007" + +#endif // ISTEAMADDON_H + diff --git a/public/Friends/IFriendsNET.h b/public/Friends/IFriendsNET.h new file mode 100644 index 0000000..b0b6c89 --- /dev/null +++ b/public/Friends/IFriendsNET.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FRIENDSNET_INTERFACE_H +#define FRIENDSNET_INTERFACE_H +#pragma once + +class CUtlMsgBuffer; +class CServerSession; + +#include "interface.h" +#include "Friends/AddOns/AddOnTypes.h" + +class IFriendsNET : public IBaseInterface +{ +public: + // check if we have network information for this user + virtual bool CheckUserRegistered(unsigned int userID) = 0; + + // update a user's network information + virtual void UpdateUserNetInfo(unsigned int userID, unsigned int netSessionID, int serverID, int IP, int port) = 0; + + // set whether or not we send directly to user or through the server + virtual void SetUserSendViaServer(unsigned int userID, bool bSendViaServer) = 0; + + // Gets a blob of data that represents this user's information + virtual bool GetUserNetInfoBlob(unsigned int userID, unsigned int dataBlob[8]) = 0; + // Sets a user's information using the same blob of data type + virtual bool SetUserNetInfoBlob(unsigned int userID, const unsigned int dataBlob[8]) = 0; + + // send binary data to user, marked with game/sessionID + virtual void SendAddOnPacket(const char *pszGameID, SessionInt64 addOnSessionID, unsigned int userID, const CUtlMsgBuffer& buffer) = 0; +}; + +#define FRIENDSNET_INTERFACE_VERSION "FriendsNET003" + +#endif // FRIENDSNET_INTERFACE_H + diff --git a/public/Friends/IFriendsUser.h b/public/Friends/IFriendsUser.h new file mode 100644 index 0000000..4c9375a --- /dev/null +++ b/public/Friends/IFriendsUser.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IFRIENDSUSER_H +#define IFRIENDSUSER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing information about Friends Users +//----------------------------------------------------------------------------- +class IFriendsUser : public IBaseInterface +{ +public: + // returns true if the interface is ready for use + virtual bool IsValid() = 0; + + // returns the Friends ID of the current user + virtual unsigned int GetFriendsID() = 0; + + // returns information about a user + // information may not be known about some users, "" will be returned + virtual const char *GetUserName(unsigned int friendsID) = 0; + virtual const char *GetFirstName(unsigned int friendsID) = 0; + virtual const char *GetLastName(unsigned int friendsID) = 0; + virtual const char *GetEmail(unsigned int friendsID) = 0; + + // returns true if buddyID is a buddy of the current user + // ie. the current is authorized to see when the buddy is online + virtual bool IsBuddy(unsigned int buddyID) = 0; + + // requests authorization from a user + virtual void RequestAuthorizationFromUser(unsigned int potentialBuddyID) = 0; + + // returns the status of the buddy, > 0 is online, 4 is ingame + virtual int GetBuddyStatus(unsigned int friendsID) = 0; + + // gets the IP address of the server the buddy is on, returns false if couldn't get + virtual bool GetBuddyGameAddress(unsigned int friendsID, int *ip, int *port) = 0; + + // returns the number of buddies + virtual int GetNumberOfBuddies() = 0; + + // returns the FriendsID of a buddy - buddyIndex is valid in the range [0, GetNumberOfBuddies) + virtual unsigned int GetBuddyFriendsID(int buddyIndex) = 0; + + // sets whether or not the user can receive messages at this time + // messages will be queued until this is set to true + virtual void SetCanReceiveMessages(bool state) = 0; +}; + +#define FRIENDSUSER_INTERFACE_VERSION "FriendsUser001" + + +#endif // IFRIENDSUSER_H diff --git a/public/GarrysMod/Addon.h b/public/GarrysMod/Addon.h new file mode 100644 index 0000000..e19d38c --- /dev/null +++ b/public/GarrysMod/Addon.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include +#include + +class CSteamAPIContext; +class IAddonDownloadNotification; +struct SteamUGCDetails_t; + +namespace IAddonSystem +{ + struct Information + { + std::string title; + std::string file; + std::string tags; + uint64_t time_updated; + uint64_t wsid; + uint64_t creator; + uint64_t hcontent_file; + uint64_t placeholder4; + uint64_t hcontent_preview; + uint64_t placeholder6; + uint64_t placeholder7; + uint16_t placeholder8; + bool placeholder9; + }; + + struct UGCInfo + { + std::string title; + std::string file; + std::string placeholder1; + uint64_t wsid; + uint64_t creator; + uint32_t pubdate; + }; +} + +namespace Addon +{ + namespace Job + { + class Base; + } + + class FileSystem + { + public: + virtual void Clear( ) = 0; + virtual void Refresh( ) = 0; + virtual int MountFile( const std::string &, std::vector * ) = 0; + virtual bool ShouldMount( const std::string & ) = 0; + virtual bool ShouldMount( uint64_t ) = 0; + virtual void SetShouldMount( const std::string &, bool ) = 0; + virtual void Save( ) = 0; + virtual const std::list &GetList( ) const = 0; + virtual const std::list &GetUGCList( ) const = 0; + virtual void ScanForSubscriptions( CSteamAPIContext *, const char * ) = 0; + virtual void Think( ) = 0; + virtual void SetDownloadNotify( IAddonDownloadNotification * ) = 0; + virtual bool IsSubscribed( uint64_t ) = 0; + virtual const IAddonSystem::Information *FindFileOwner( const std::string & ) = 0; + virtual void AddFile( const IAddonSystem::Information & ) = 0; + virtual void ClearAllGMAs( ) = 0; + virtual void MountFloatingAddons( ) = 0; + virtual void Shutdown( ) = 0; + virtual void AddFile( const SteamUGCDetails_t & ) = 0; + virtual void AddSubscription( const SteamUGCDetails_t & ) = 0; + virtual void AddJob( Job::Base * ) = 0; + virtual void Notify( ) = 0; + virtual bool HasChanges( ) = 0; + virtual void MarkChanged( ) = 0; + virtual void AddonDownloaded( IAddonSystem::Information & ) = 0; + virtual const std::list &GetSubList( ) const = 0; + virtual void Load( ) = 0; + }; + +} \ No newline at end of file diff --git a/public/GarrysMod/GameDepot.h b/public/GarrysMod/GameDepot.h new file mode 100644 index 0000000..c047834 --- /dev/null +++ b/public/GarrysMod/GameDepot.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +namespace IGameDepotSystem +{ + +struct Information +{ + uint32_t placeholder1; + uint32_t depot; + std::string title; + std::string folder; + bool mounted; + bool placeholder6; + bool owned; + bool installed; +}; + +} + +namespace GameDepot +{ + +class System +{ +public: + virtual void Refresh( ) = 0; + virtual void Clear( ) = 0; + virtual void Save( ) = 0; + virtual void SetMount( uint32_t, bool ) = 0; + virtual const std::list &GetList( ) const = 0; + virtual void MountAsMapFix( uint32_t ) = 0; + virtual void MountCurrentGame( const std::string & ) = 0; +}; + +} diff --git a/public/GarrysMod/Gamemode.h b/public/GarrysMod/Gamemode.h new file mode 100644 index 0000000..5e5a14b --- /dev/null +++ b/public/GarrysMod/Gamemode.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +namespace IGamemodeSystem +{ + +struct Information +{ + bool placeholder1; + bool menusystem; + std::string title; + std::string name; + std::string maps; + std::string basename; + std::string workshopid; +}; + +} + +namespace Gamemode +{ + +class System +{ +public: + virtual void OnJoinServer( const std::string & ) = 0; + virtual void OnLeaveServer( ) = 0; + virtual void Refresh( ) = 0; + virtual void Clear( ) = 0; + virtual const IGamemodeSystem::Information &Active( ) = 0; + virtual void FindByName( const std::string & ) = 0; + virtual void SetActive( const std::string & ) = 0; + virtual const std::list &GetList( ) const = 0; +}; + +} diff --git a/public/GarrysMod/Language.h b/public/GarrysMod/Language.h new file mode 100644 index 0000000..87d31ca --- /dev/null +++ b/public/GarrysMod/Language.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +class CLanguage +{ +public: + virtual void ChangeLanguage( const char * ) = 0; + virtual void ChangeLanguage_Steam( const char * ) = 0; + virtual void GetString( const char *, wchar_t *, int32_t ) = 0; +}; diff --git a/public/GarrysMod/LegacyAddons.h b/public/GarrysMod/LegacyAddons.h new file mode 100644 index 0000000..1d359bf --- /dev/null +++ b/public/GarrysMod/LegacyAddons.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +namespace ILegacyAddons +{ + +struct Information +{ + std::string name; + std::string path; + std::string luapath; + std::string placeholder4; +}; + +} + +namespace LegacyAddons +{ + +class System +{ +public: + virtual void Refresh( ) = 0; + virtual const std::list &GetList( ) const = 0; +}; + +} diff --git a/public/IGameUIFuncs.h b/public/IGameUIFuncs.h new file mode 100644 index 0000000..21f01e6 --- /dev/null +++ b/public/IGameUIFuncs.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef IGAMEUIFUNCS_H +#define IGAMEUIFUNCS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui/KeyCode.h" + +abstract_class IGameUIFuncs +{ +public: + virtual bool IsKeyDown( const char *keyname, bool& isdown ) = 0; + virtual const char *GetBindingForButtonCode( ButtonCode_t code ) = 0; + virtual ButtonCode_t GetButtonCodeForBind( const char *pBind ) = 0; + virtual void GetVideoModes( struct vmode_s **liststart, int *count ) = 0; + virtual void SetFriendsID( uint friendsID, const char *friendsName ) = 0; + virtual void GetDesktopResolution( int &width, int &height ) = 0; + virtual bool IsConnectedToVACSecureServer() = 0; +}; + +#define VENGINE_GAMEUIFUNCS_VERSION "VENGINE_GAMEUIFUNCS_VERSION005" + +#endif // IGAMEUIFUNCS_H diff --git a/public/IHammer.h b/public/IHammer.h new file mode 100644 index 0000000..7e85f2d --- /dev/null +++ b/public/IHammer.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The application object. +// +//=============================================================================// + +#ifndef IHAMMER_H +#define IHAMMER_H + +#include "appframework/IAppSystem.h" + +typedef struct tagMSG MSG; + + +class IStudioDataCache; + + +//----------------------------------------------------------------------------- +// Return values for RequestNewConfig +//----------------------------------------------------------------------------- +enum RequestRetval_t +{ + REQUEST_OK = 0, + REQUEST_QUIT +}; + + +//----------------------------------------------------------------------------- +// Interface used to drive hammer +//----------------------------------------------------------------------------- +#define INTERFACEVERSION_HAMMER "Hammer001" +class IHammer : public IAppSystem +{ +public: + virtual bool HammerPreTranslateMessage( MSG * pMsg ) = 0; + virtual bool HammerIsIdleMessage( MSG * pMsg ) = 0; + virtual bool HammerOnIdle( long count ) = 0; + + virtual void RunFrame() = 0; + + // Returns the mod and the game to initially start up + virtual const char *GetDefaultMod() = 0; + virtual const char *GetDefaultGame() = 0; + + virtual bool InitSessionGameConfig( const char *szGameDir ) = 0; + + // Request a new config from hammer's config system + virtual RequestRetval_t RequestNewConfig() = 0; + + // Returns the full path to the mod and the game to initially start up + virtual const char *GetDefaultModFullPath() = 0; + + virtual int MainLoop() = 0; +}; + +#endif // IHAMMER_H diff --git a/public/OfflineMode.h b/public/OfflineMode.h new file mode 100644 index 0000000..d4c1f2c --- /dev/null +++ b/public/OfflineMode.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include +#include + +#define STEAM_OFFLINE_MODE "HKEY_CURRENT_USER\\Software\\Valve\\Steam\\Offline" +#define STEAM_AFS_MODE "HKEY_CURRENT_USER\\Software\\Valve\\Steam\\OfflineAFS" +#define OFFLINE_FILE "Steam\\cached\\offline_" // first part of filename + +inline bool IsSteamInOfflineMode() +{ + int offline = 0; + vgui::system()->GetRegistryInteger( STEAM_OFFLINE_MODE, offline ); + return ( offline == 1 ); +}inline bool IsSteamInAuthenticationFailSafeMode() +{ + int offline = 0; + vgui::system()->GetRegistryInteger( STEAM_AFS_MODE, offline ); + return ( offline == 1 ); +} + +inline bool IsSteamGameServerBrowsingEnabled() +{ + return (IsSteamInAuthenticationFailSafeMode() || !IsSteamInOfflineMode()); +} diff --git a/public/PlayerState.h b/public/PlayerState.h new file mode 100644 index 0000000..9097ca7 --- /dev/null +++ b/public/PlayerState.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLAYERSTATE_H +#define PLAYERSTATE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "edict.h" +#include "networkvar.h" +// Only care about this stuff in game/client .dlls +#if defined( CLIENT_DLL ) +#include "predictable_entity.h" +#endif + +class CPlayerState +{ +public: + DECLARE_CLASS_NOBASE( CPlayerState ); + DECLARE_EMBEDDED_NETWORKVAR(); + + // This virtual method is necessary to generate a vtable in all cases + // (DECLARE_PREDICTABLE will generate a vtable also)! + virtual ~CPlayerState() {} + + // true if the player is dead + CNetworkVar( bool, deadflag ); + // Viewing angle (player only) + QAngle v_angle; + +// The client .dll only cares about deadflag +// the game and engine .dlls need to worry about the rest of this data +#if !defined( CLIENT_DLL ) + // Player's network name + string_t netname; + // 0:nothing, 1:force view angles, 2:add avelocity + int fixangle; + // delta angle for fixangle == FIXANGLE_RELATIVE + QAngle anglechange; + // flag to single the HLTV/Replay fake client, not transmitted + bool hltv; + bool replay; + int frags; + int deaths; +#endif + +// NOTE: Only care about this stuff in game/client dlls +// Put at end in case it has any effect on size of structure +#if defined( GAME_DLL ) + DECLARE_SIMPLE_DATADESC(); +#endif + +#if defined( CLIENT_DLL ) + DECLARE_PREDICTABLE(); +#endif +}; + +#endif // PLAYERSTATE_H diff --git a/public/ScratchPadUtils.cpp b/public/ScratchPadUtils.cpp new file mode 100644 index 0000000..dfb93b0 --- /dev/null +++ b/public/ScratchPadUtils.cpp @@ -0,0 +1,467 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#include "iscratchpad3d.h" +#include "mathlib/mathlib.h" +#include "ScratchPadUtils.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// --------------------------------------------------------------------------------------------------------------------- // +// CScratchPadGraph implementation. +// --------------------------------------------------------------------------------------------------------------------- // + +CScratchPadGraph::CScratchPadGraph() +{ + m_pPad = NULL; +} + + +void CScratchPadGraph::Init( + IScratchPad3D *pPad, + + Vector vTimeAxis, + float flInchesPerSecond, + Vector vTimeLineColor, + float flTimeOrigin, + + float flTimeLabelEveryNSeconds, + + Vector vValueAxis, + float flInchesPerValue, + Vector vValueLineColor, + float flValueOrigin + + ) +{ + m_pPad = pPad; + m_vTimeAxis = vTimeAxis; + m_flInchesPerSecond = flInchesPerSecond; + m_vValueAxis = vValueAxis; + m_flInchesPerValue = flInchesPerValue; + m_flTimeLabelEveryNSeconds = flTimeLabelEveryNSeconds; + + m_vTimeLineColor = vTimeLineColor; + m_vValueLineColor = vValueLineColor; + + m_flTimeOrigin = flTimeOrigin; + m_flValueOrigin = flValueOrigin; + + m_nTimeLabelsDrawn = 0; + m_flHighestTime = flTimeOrigin; + m_flHighestValue = flValueOrigin; +} + + +bool CScratchPadGraph::IsInitted() const +{ + return m_pPad != NULL; +} + + +CScratchPadGraph::LineID CScratchPadGraph::AddLine( Vector vColor ) +{ + CScratchPadGraph::CLineInfo info; + info.m_bFirst = true; + info.m_vColor = vColor; + return m_LineInfos.AddToTail( info ); +} + + +void CScratchPadGraph::AddSample( LineID iLine, float flTime, float flValue ) +{ + CScratchPadGraph::CLineInfo *pInfo = &m_LineInfos[iLine]; + + UpdateTicksAndStuff( flTime, flValue ); + + if ( !pInfo->m_bFirst ) + { + // Draw a line from the last value to the current one. + Vector vStart = GetSamplePosition( pInfo->m_flLastTime, pInfo->m_flLastValue ); + Vector vEnd = GetSamplePosition( flTime, flValue ); + + m_pPad->DrawLine( + CSPVert( vStart, pInfo->m_vColor ), + CSPVert( vEnd, pInfo->m_vColor ) + ); + } + + pInfo->m_flLastTime = flTime; + pInfo->m_flLastValue = flValue; + pInfo->m_bFirst = false; +} + + +void CScratchPadGraph::AddVerticalLine( float flTime, float flMinValue, float flMaxValue, const CSPColor &vColor ) +{ + Vector v1 = GetSamplePosition( flTime, flMinValue ); + Vector v2 = GetSamplePosition( flTime, flMaxValue ); + m_pPad->DrawLine( + CSPVert( v1, vColor ), + CSPVert( v2, vColor ) ); +} + + +void CScratchPadGraph::UpdateTicksAndStuff( float flTime, float flValue ) +{ + if ( flTime > m_flHighestTime ) + { + // Update the left part of the time axis. + Vector vStart = GetSamplePosition( m_flHighestTime, m_flValueOrigin ); + Vector vEnd = GetSamplePosition( flTime, m_flValueOrigin ); + + m_pPad->DrawLine( + CSPVert( vStart, m_vTimeLineColor ), + CSPVert( vEnd, m_vTimeLineColor ) + ); + + m_flHighestTime = flTime; + } + + if ( flValue > m_flHighestValue ) + { + // Update the left part of the time axis. + Vector vStart = GetSamplePosition( m_flTimeOrigin, m_flHighestValue ); + Vector vEnd = GetSamplePosition( m_flTimeOrigin, flValue ); + + m_pPad->DrawLine( + CSPVert( vStart, m_vValueLineColor ), + CSPVert( vEnd, m_vValueLineColor ) + ); + + // Extend the lines attached to the time labels. + for ( int i=0; i < m_nTimeLabelsDrawn; i++ ) + { + float flTime = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds; + + m_pPad->DrawLine( + CSPVert((const Vector&) GetSamplePosition( flTime, m_flHighestValue )), + CSPVert((const Vector&) GetSamplePosition( flTime, flValue ) ) + ); + } + + m_flHighestValue = flValue; + } + + // More text labels? + int iHighestTextLabel = (int)ceil( (flTime - m_flTimeOrigin) / m_flTimeLabelEveryNSeconds + 0.5f ); + while ( m_nTimeLabelsDrawn < iHighestTextLabel ) + { + CTextParams params; + + float flTime = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds; + + params.m_bSolidBackground = true; + params.m_vPos = GetSamplePosition( flTime, m_flValueOrigin-5 ); + params.m_bTwoSided = true; + + char str[512]; + Q_snprintf( str, sizeof( str ), "time: %.2f", flTime ); + m_pPad->DrawText( str, params ); + + + // Now draw the vertical line for the value.. + m_pPad->DrawLine( + CSPVert( (const Vector&)GetSamplePosition( flTime, m_flValueOrigin ) ), + CSPVert( (const Vector&)GetSamplePosition( flTime, m_flHighestValue ) ) + ); + + + m_nTimeLabelsDrawn++; + } +} + + +Vector CScratchPadGraph::GetSamplePosition( float flTime, float flValue ) +{ + Vector vRet = + m_vTimeAxis * ((flTime - m_flTimeOrigin) * m_flInchesPerSecond) + + m_vValueAxis * ((flValue - m_flValueOrigin) * m_flInchesPerValue); + + return vRet; +} + + + +// --------------------------------------------------------------------------------------------------------------------- // +// Global functions. +// --------------------------------------------------------------------------------------------------------------------- // + +void ScratchPad_DrawLitCone( + IScratchPad3D *pPad, + const Vector &vBaseCenter, + const Vector &vTip, + const Vector &vBrightColor, + const Vector &vDarkColor, + const Vector &vLightDir, + float baseWidth, + int nSegments ) +{ + // Make orthogonal vectors. + Vector vDir = vTip - vBaseCenter; + VectorNormalize( vDir ); + + Vector vRight, vUp; + VectorVectors( vDir, vRight, vUp ); + vRight *= baseWidth; + vUp *= baseWidth; + + // Setup the top and bottom caps. + CSPVertList bottomCap, tri; + bottomCap.m_Verts.SetSize( nSegments ); + tri.m_Verts.SetSize( 3 ); + + float flDot = -vLightDir.Dot( vDir ); + Vector topColor, bottomColor; + VectorLerp( vDarkColor, vBrightColor, RemapVal( -flDot, -1, 1, 0, 1 ), bottomColor ); + + + // Draw each quad. + Vector vPrevBottom = vBaseCenter + vRight; + + for ( int i=0; i < nSegments; i++ ) + { + float flAngle = (float)(i+1) * M_PI * 2.0 / nSegments; + Vector vOffset = vRight * cos( flAngle ) + vUp * sin( flAngle ); + Vector vCurBottom = vBaseCenter + vOffset; + + const Vector &v1 = vTip; + const Vector &v2 = vPrevBottom; + const Vector &v3 = vCurBottom; + Vector vFaceNormal = (v2 - v1).Cross( v3 - v1 ); + VectorNormalize( vFaceNormal ); + + // Now light it. + flDot = -vLightDir.Dot( vFaceNormal ); + Vector vColor; + VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), vColor ); + + // Draw the quad. + tri.m_Verts[0] = CSPVert( v1, vColor ); + tri.m_Verts[1] = CSPVert( v2, vColor ); + tri.m_Verts[2] = CSPVert( v3, vColor ); + pPad->DrawPolygon( tri ); + + bottomCap.m_Verts[i] = CSPVert( vCurBottom, bottomColor ); + } + + pPad->DrawPolygon( bottomCap ); +} + + +void ScratchPad_DrawLitCylinder( + IScratchPad3D *pPad, + const Vector &v1, + const Vector &v2, + const Vector &vBrightColor, + const Vector &vDarkColor, + const Vector &vLightDir, + float width, + int nSegments ) +{ + // Make orthogonal vectors. + Vector vDir = v2 - v1; + VectorNormalize( vDir ); + + Vector vRight, vUp; + VectorVectors( vDir, vRight, vUp ); + vRight *= width; + vUp *= width; + + // Setup the top and bottom caps. + CSPVertList topCap, bottomCap, quad; + + topCap.m_Verts.SetSize( nSegments ); + bottomCap.m_Verts.SetSize( nSegments ); + quad.m_Verts.SetSize( 4 ); + + float flDot = -vLightDir.Dot( vDir ); + Vector topColor, bottomColor; + + VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), topColor ); + VectorLerp( vDarkColor, vBrightColor, RemapVal( -flDot, -1, 1, 0, 1 ), bottomColor ); + + + // Draw each quad. + Vector vPrevTop = v1 + vRight; + Vector vPrevBottom = v2 + vRight; + + for ( int i=0; i < nSegments; i++ ) + { + float flAngle = (float)(i+1) * M_PI * 2.0 / nSegments; + Vector vOffset = vRight * cos( flAngle ) + vUp * sin( flAngle ); + Vector vCurTop = v1 + vOffset; + Vector vCurBottom = v2 + vOffset; + + // Now light it. + VectorNormalize( vOffset ); + flDot = -vLightDir.Dot( vOffset ); + Vector vColor; + VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), vColor ); + + // Draw the quad. + quad.m_Verts[0] = CSPVert( vPrevTop, vColor ); + quad.m_Verts[1] = CSPVert( vPrevBottom, vColor ); + quad.m_Verts[2] = CSPVert( vCurBottom, vColor ); + quad.m_Verts[3] = CSPVert( vCurTop, vColor ); + pPad->DrawPolygon( quad ); + + topCap.m_Verts[i] = CSPVert( vCurTop, topColor ); + bottomCap.m_Verts[i] = CSPVert( vCurBottom, bottomColor ); + } + + pPad->DrawPolygon( topCap ); + pPad->DrawPolygon( bottomCap ); +} + + +void ScratchPad_DrawArrow( + IScratchPad3D *pPad, + const Vector &vPos, + const Vector &vDirection, + const Vector &vColor, + float flLength, + float flLineWidth, + float flHeadWidth, + int nCylinderSegments, + int nHeadSegments, + float flArrowHeadPercentage + ) +{ + Vector vNormDir = vDirection; + VectorNormalize( vNormDir ); + + Vector vConeBase = vPos + vNormDir * (flLength * ( 1 - flArrowHeadPercentage ) ); + Vector vConeEnd = vPos + vNormDir * flLength; + + Vector vLightDir( -1, -1, -1 ); + VectorNormalize( vLightDir ); // could precalculate this + + pPad->SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Solid ); + pPad->SetRenderState( IScratchPad3D::RS_ZRead, true ); + + ScratchPad_DrawLitCylinder( pPad, vPos, vConeBase, vColor, vColor*0.25f, vLightDir, flLineWidth, nCylinderSegments ); + ScratchPad_DrawLitCone( pPad, vConeBase, vConeEnd, vColor, vColor*0.25f, vLightDir, flHeadWidth, nHeadSegments ); +} + + +void ScratchPad_DrawArrowSimple( + IScratchPad3D *pPad, + const Vector &vPos, + const Vector &vDirection, + const Vector &vColor, + float flLength ) +{ + ScratchPad_DrawArrow( + pPad, + vPos, + vDirection, + vColor, + flLength, + flLength * 1.0/15, + flLength * 3.0/15, + 4, + 4 ); +} + + +void ScratchPad_DrawSphere( + IScratchPad3D *pPad, + const Vector &vCenter, + float flRadius, + const Vector &vColor, + int nSubDivs ) +{ + CUtlVector prevPoints; + prevPoints.SetSize( nSubDivs ); + + // For each vertical slice.. (the top and bottom ones are just a single point). + for ( int iSlice=0; iSlice < nSubDivs; iSlice++ ) + { + float flHalfSliceAngle = M_PI * (float)iSlice / (nSubDivs - 1); + + if ( iSlice == 0 ) + { + prevPoints[0] = vCenter + Vector( 0, 0, flRadius ); + for ( int z=1; z < prevPoints.Count(); z++ ) + prevPoints[z] = prevPoints[0]; + } + else + { + for ( int iSubPt=0; iSubPt < nSubDivs; iSubPt++ ) + { + float flHalfAngle = M_PI * (float)iSubPt / (nSubDivs - 1); + float flAngle = flHalfAngle * 2; + + Vector pt; + if ( iSlice == (nSubDivs - 1) ) + { + pt = vCenter - Vector( 0, 0, flRadius ); + } + else + { + pt.x = cos( flAngle ) * sin( flHalfSliceAngle ); + pt.y = sin( flAngle ) * sin( flHalfSliceAngle ); + pt.z = cos( flHalfSliceAngle ); + + pt *= flRadius; + pt += vCenter; + } + + pPad->DrawLine( CSPVert( pt, vColor ), CSPVert( prevPoints[iSubPt], vColor ) ); + prevPoints[iSubPt] = pt; + } + + if ( iSlice != (nSubDivs - 1) ) + { + for ( int i=0; i < nSubDivs; i++ ) + pPad->DrawLine( CSPVert( prevPoints[i], vColor ), CSPVert( prevPoints[(i+1)%nSubDivs], vColor ) ); + } + } + } +} + + +void ScratchPad_DrawAABB( + IScratchPad3D *pPad, + const Vector &vMins, + const Vector &vMaxs, + const Vector &vColor ) +{ + int vertOrder[4][2] = {{0,0},{1,0},{1,1},{0,1}}; + const Vector *vecs[2] = {&vMins, &vMaxs}; + + Vector vTop, vBottom, vPrevTop, vPrevBottom; + vTop.z = vPrevTop.z = vMaxs.z; + vBottom.z = vPrevBottom.z = vMins.z; + + vPrevTop.x = vPrevBottom.x = vecs[vertOrder[3][0]]->x; + vPrevTop.y = vPrevBottom.y = vecs[vertOrder[3][1]]->y; + + for ( int i=0; i < 4; i++ ) + { + vTop.x = vBottom.x = vecs[vertOrder[i][0]]->x; + vTop.y = vBottom.y = vecs[vertOrder[i][1]]->y; + + // Draw the top line. + pPad->DrawLine( CSPVert( vPrevTop, vColor ), CSPVert( vTop, vColor ) ); + pPad->DrawLine( CSPVert( vPrevBottom, vColor ), CSPVert( vBottom, vColor ) ); + pPad->DrawLine( CSPVert( vTop, vColor ), CSPVert( vBottom, vColor ) ); + + vPrevTop = vTop; + vPrevBottom = vBottom; + } +} + + +#endif // !_STATIC_LINKED || _SHARED_LIB + diff --git a/public/ScratchPadUtils.h b/public/ScratchPadUtils.h new file mode 100644 index 0000000..9ff47fe --- /dev/null +++ b/public/ScratchPadUtils.h @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This module contains helper functions for use with scratch pads. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SCRATCHPADUTILS_H +#define SCRATCHPADUTILS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iscratchpad3d.h" + + +// Use this to make a graph. +class CScratchPadGraph +{ +public: + + typedef int LineID; + + CScratchPadGraph(); + + // Initialze the orientation and scales of the two axes. + // Axis indices are 0, 1, or 2 for x, y, and z. + void Init( + IScratchPad3D *pPad, + + Vector vTimeAxis = Vector(0,-1,0), + float flInchesPerSecond=1, + Vector vTimeLineColor=Vector(0,0,1), + float flTimeOrigin=0, // Where the origin of the graph is. + + float flTimeLabelEveryNSeconds=1, + + Vector vValueAxis = Vector(0,0,1), + float flInchesPerValue=1, + Vector vValueLineColor=Vector(1,0,0), + float flValueOrigin=0 // Where the origin of the graph is. + + ); + + bool IsInitted() const; + + // Add another line into the graph. + LineID AddLine( Vector vColor ); + void AddSample( LineID iLine, float flTime, float flValue ); + void AddVerticalLine( float flTime, float flMinValue, float flMaxValue, const CSPColor &vColor ); + + // Get the 3D position of a sample on the graph (so you can draw other things there). + Vector GetSamplePosition( float flTime, float flValue ); + + +private: + + void UpdateTicksAndStuff( float flTime, float flValue ); + + + +private: + class CLineInfo + { + public: + bool m_bFirst; + float m_flLastTime; + float m_flLastValue; + Vector m_vColor; + }; + + IScratchPad3D *m_pPad; + + CUtlVector m_LineInfos; + + Vector m_vTimeAxis; + float m_flInchesPerSecond; + + Vector m_vValueAxis; + float m_flInchesPerValue; + + // How often to make a time label. + float m_flTimeLabelEveryNSeconds; + int m_nTimeLabelsDrawn; + + Vector m_vTimeLineColor; + Vector m_vValueLineColor; + + float m_flTimeOrigin; + float m_flValueOrigin; + + // Used to extend the value border. + float m_flHighestValue; + float m_flHighestTime; +}; + + + +// Draw a cone. +void ScratchPad_DrawLitCone( + IScratchPad3D *pPad, + const Vector &vBaseCenter, + const Vector &vTip, + const Vector &vBrightColor, + const Vector &vDarkColor, + const Vector &vLightDir, + float baseWidth, + int nSegments ); + + +// Draw a cylinder. +void ScratchPad_DrawLitCylinder( + IScratchPad3D *pPad, + const Vector &v1, + const Vector &v2, + const Vector &vBrightColor, + const Vector &vDarkColor, + const Vector &vLightDir, + float width, + int nSegments ); + + +// Draw an arrow. +void ScratchPad_DrawArrow( + IScratchPad3D *pPad, + const Vector &vPos, + const Vector &vDirection, + const Vector &vColor, + float flLength=20, + float flLineWidth=3, + float flHeadWidth=8, + int nCylinderSegments=5, + int nHeadSegments=8, + float flArrowHeadPercentage = 0.3f // How much of the line is the arrow head. + ); + + +// Draw an arrow with less parameters.. it generates parameters based on length +// automatically to make the arrow look good. +void ScratchPad_DrawArrowSimple( + IScratchPad3D *pPad, + const Vector &vPos, + const Vector &vDirection, + const Vector &vColor, + float flLength ); + +void ScratchPad_DrawSphere( + IScratchPad3D *pPad, + const Vector &vCenter, + float flRadius, + const Vector &vColor, + int nSubDivs=7 ); + + +void ScratchPad_DrawAABB( + IScratchPad3D *pPad, + const Vector &vMins, + const Vector &vMaxs, + const Vector &vColor = Vector( 1,1,1 ) ); + + +#endif // SCRATCHPADUTILS_H diff --git a/public/SoundEmitterSystem/isoundemittersystembase.h b/public/SoundEmitterSystem/isoundemittersystembase.h new file mode 100644 index 0000000..77fbf0d --- /dev/null +++ b/public/SoundEmitterSystem/isoundemittersystembase.h @@ -0,0 +1,272 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ISOUNDEMITTERSYSTEMBASE_H +#define ISOUNDEMITTERSYSTEMBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utldict.h" +#include "vstdlib/random.h" +#include "soundflags.h" +#include "mathlib/compressed_vector.h" +#include "appframework/IAppSystem.h" + + +#define SOUNDEMITTERSYSTEM_INTERFACE_VERSION "VSoundEmitter002" + +#define SOUNDGENDER_MACRO "$gender" +#define SOUNDGENDER_MACRO_LENGTH 7 // Length of above including $ + +typedef short HSOUNDSCRIPTHANDLE; +#define SOUNDEMITTER_INVALID_HANDLE (HSOUNDSCRIPTHANDLE)-1 + +class IFileList; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct CSoundParameters +{ + CSoundParameters() + { + channel = CHAN_AUTO; // 0 + volume = VOL_NORM; // 1.0f + pitch = PITCH_NORM; // 100 + + pitchlow = PITCH_NORM; + pitchhigh = PITCH_NORM; + + soundlevel = SNDLVL_NORM; // 75dB + soundname[ 0 ] = 0; + play_to_owner_only = false; + count = 0; + + delay_msec = 0; + } + + int channel; + float volume; + int pitch; + int pitchlow, pitchhigh; + soundlevel_t soundlevel; + // For weapon sounds... + bool play_to_owner_only; + int count; + char soundname[ 128 ]; + int delay_msec; +}; + +// A bit of a hack, but these are just utility function which are implemented in the SouneParametersInternal.cpp file which all users of this lib also compile +const char *SoundLevelToString( soundlevel_t level ); +const char *ChannelToString( int channel ); +const char *VolumeToString( float volume ); +const char *PitchToString( float pitch ); +soundlevel_t TextToSoundLevel( const char *key ); +int TextToChannel( const char *name ); + + +enum gender_t +{ + GENDER_NONE = 0, + GENDER_MALE, + GENDER_FEMALE, +}; + + +#pragma pack(1) +struct SoundFile +{ + SoundFile() + { + symbol = UTL_INVAL_SYMBOL; + gender = GENDER_NONE; + available = true; + COMPILE_TIME_ASSERT( sizeof(SoundFile) == 4 ); + } + + CUtlSymbol symbol; + byte gender; + byte available; +}; + +#pragma pack() + +#pragma pack(1) +template +struct sound_interval_t +{ + T start; + T range; + + interval_t &ToInterval( interval_t &dest ) const { dest.start = start; dest.range = range; return dest; } + void FromInterval( const interval_t &from ) { start = from.start; range = from.range; } + float Random() const { return RandomFloat( start, start + range ); } +}; + + +#pragma pack() + +typedef sound_interval_t volume_interval_t; +typedef sound_interval_t soundlevel_interval_t; +typedef sound_interval_t pitch_interval_t; + +#pragma pack(1) +struct CSoundParametersInternal +{ + CSoundParametersInternal(); + ~CSoundParametersInternal(); + + void CopyFrom( const CSoundParametersInternal& src ); + + bool operator == ( const CSoundParametersInternal& other ) const; + + const char *VolumeToString( void ) const; + const char *ChannelToString( void ) const; + const char *SoundLevelToString( void ) const; + const char *PitchToString( void ) const; + + void VolumeFromString( const char *sz ); + void ChannelFromString( const char *sz ); + void PitchFromString( const char *sz ); + void SoundLevelFromString( const char *sz ); + + int GetChannel() const { return channel; } + const volume_interval_t &GetVolume() const { return volume; } + const pitch_interval_t &GetPitch() const { return pitch; } + const soundlevel_interval_t &GetSoundLevel() const { return soundlevel; } + int GetDelayMsec() const { return delay_msec; } + bool OnlyPlayToOwner() const { return play_to_owner_only; } + bool HadMissingWaveFiles() const { return had_missing_wave_files; } + bool UsesGenderToken() const { return uses_gender_token; } + bool ShouldPreload() const { return m_bShouldPreload; } + + void SetChannel( int newChannel ) { channel = newChannel; } + void SetVolume( float start, float range = 0.0 ) { volume.start = start; volume.range = range; } + void SetPitch( float start, float range = 0.0 ) { pitch.start = start; pitch.range = range; } + void SetSoundLevel( float start, float range = 0.0 ) { soundlevel.start = start; soundlevel.range = range; } + void SetDelayMsec( int delay ) { delay_msec = delay; } + void SetShouldPreload( bool bShouldPreload ) { m_bShouldPreload = bShouldPreload; } + void SetOnlyPlayToOwner( bool b ) { play_to_owner_only = b; } + void SetHadMissingWaveFiles( bool b ) { had_missing_wave_files = b; } + void SetUsesGenderToken( bool b ) { uses_gender_token = b; } + + void AddSoundName( const SoundFile &soundFile ) { AddToTail( &m_pSoundNames, &m_nSoundNames, soundFile ); } + int NumSoundNames() const { return m_nSoundNames; } + SoundFile * GetSoundNames() { return ( m_nSoundNames == 1 ) ? (SoundFile *)&m_pSoundNames : m_pSoundNames; } + const SoundFile *GetSoundNames() const { return ( m_nSoundNames == 1 ) ? (SoundFile *)&m_pSoundNames : m_pSoundNames; } + + void AddConvertedName( const SoundFile &soundFile ) { AddToTail( &m_pConvertedNames, &m_nConvertedNames, soundFile ); } + int NumConvertedNames() const { return m_nConvertedNames; } + SoundFile * GetConvertedNames() { return ( m_nConvertedNames == 1 ) ? (SoundFile *)&m_pConvertedNames : m_pConvertedNames; } + const SoundFile *GetConvertedNames() const { return ( m_nConvertedNames == 1 ) ? (SoundFile *)&m_pConvertedNames : m_pConvertedNames; } + +private: + void operator=( const CSoundParametersInternal& src ); // disallow implicit copies + CSoundParametersInternal( const CSoundParametersInternal& src ); + + void AddToTail( SoundFile **pDest, uint16 *pDestCount, const SoundFile &source ); + + SoundFile * m_pSoundNames; // 4 + SoundFile * m_pConvertedNames; // 8 + uint16 m_nSoundNames; // 10 + uint16 m_nConvertedNames; // 12 + + volume_interval_t volume; // 16 + soundlevel_interval_t soundlevel; // 20 + pitch_interval_t pitch; // 22 + uint16 channel; // 24 + uint16 delay_msec; // 26 + + bool play_to_owner_only:1; // For weapon sounds... // 27 + // Internal use, for warning about missing .wav files + bool had_missing_wave_files:1; + bool uses_gender_token:1; + bool m_bShouldPreload:1; + + byte reserved; // 28 + + +}; +#pragma pack() + + +//----------------------------------------------------------------------------- +// Purpose: Base class for sound emitter system handling (can be used by tools) +//----------------------------------------------------------------------------- +abstract_class ISoundEmitterSystemBase : public IAppSystem +{ +public: + // Init, shutdown called after we know what mod is running + virtual bool ModInit() = 0; + virtual void ModShutdown() = 0; + + virtual int GetSoundIndex( const char *pName ) const = 0; + virtual bool IsValidIndex( int index ) = 0; + virtual int GetSoundCount( void ) = 0; + + virtual const char *GetSoundName( int index ) = 0; + virtual bool GetParametersForSound( const char *soundname, CSoundParameters& params, gender_t gender, bool isbeingemitted = false ) = 0; + + virtual const char *GetWaveName( CUtlSymbol& sym ) = 0; + virtual CUtlSymbol AddWaveName( const char *name ) = 0; + + virtual soundlevel_t LookupSoundLevel( const char *soundname ) = 0; + virtual const char *GetWavFileForSound( const char *soundname, char const *actormodel ) = 0; + virtual const char *GetWavFileForSound( const char *soundname, gender_t gender ) = 0; + virtual int CheckForMissingWavFiles( bool verbose ) = 0; + virtual const char *GetSourceFileForSound( int index ) const = 0; + + // Iteration methods + virtual int First() const = 0; + virtual int Next( int i ) const = 0; + virtual int InvalidIndex() const = 0; + + virtual CSoundParametersInternal *InternalGetParametersForSound( int index ) = 0; + + // The host application is responsible for dealing with dirty sound scripts, etc. + virtual bool AddSound( const char *soundname, const char *scriptfile, const CSoundParametersInternal& params ) = 0; + virtual void RemoveSound( const char *soundname ) = 0; + virtual void MoveSound( const char *soundname, const char *newscript ) = 0; + virtual void RenameSound( const char *soundname, const char *newname ) = 0; + + virtual void UpdateSoundParameters( const char *soundname, const CSoundParametersInternal& params ) = 0; + + virtual int GetNumSoundScripts() const = 0; + virtual char const *GetSoundScriptName( int index ) const = 0; + virtual bool IsSoundScriptDirty( int index ) const = 0; + virtual int FindSoundScript( const char *name ) const = 0; + virtual void SaveChangesToSoundScript( int scriptindex ) = 0; + + virtual void ExpandSoundNameMacros( CSoundParametersInternal& params, char const *wavename ) = 0; + virtual gender_t GetActorGender( char const *actormodel ) = 0; + virtual void GenderExpandString( char const *actormodel, char const *in, char *out, int maxlen ) = 0; + virtual void GenderExpandString( gender_t gender, char const *in, char *out, int maxlen ) = 0; + virtual bool IsUsingGenderToken( char const *soundname ) = 0; + + // For blowing away caches based on filetimstamps of the manifest, or of any of the + // .txt files that are read into the sound emitter system + virtual unsigned int GetManifestFileTimeChecksum() = 0; + + // Called from both client and server (single player) or just one (server only in dedicated server and client only if connected to a remote server) + // Called by LevelInitPreEntity to override sound scripts for the mod with level specific overrides based on custom mapnames, etc. + virtual void AddSoundOverrides( char const *scriptfile, bool bPreload = false ) = 0; + + // Called by either client or server in LevelShutdown to clear out custom overrides + virtual void ClearSoundOverrides() = 0; + + virtual bool GetParametersForSoundEx( const char *soundname, HSOUNDSCRIPTHANDLE& handle, CSoundParameters& params, gender_t gender, bool isbeingemitted = false ) = 0; + virtual soundlevel_t LookupSoundLevelByHandle( char const *soundname, HSOUNDSCRIPTHANDLE& handle ) = 0; + + virtual void ReloadSoundEntriesInList( IFileList *pFilesToReload ) = 0; + + // Called by either client or server to force ModShutdown and ModInit + virtual void Flush() = 0; +}; + +#endif // ISOUNDEMITTERSYSTEMBASE_H diff --git a/public/SoundParametersInternal.cpp b/public/SoundParametersInternal.cpp new file mode 100644 index 0000000..b408c93 --- /dev/null +++ b/public/SoundParametersInternal.cpp @@ -0,0 +1,583 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "cbase.h" + +#if !defined(_STATIC_LINKED) || defined(SOUNDEMITTERSYSTEM_DLL) + +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "interval.h" +#include "soundchars.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +struct SoundChannels +{ + int channel; + const char *name; +}; + +// NOTE: This will need to be updated if channel names are added/removed +static SoundChannels g_pChannelNames[] = +{ + { CHAN_AUTO, "CHAN_AUTO" }, + { CHAN_WEAPON, "CHAN_WEAPON" }, + { CHAN_VOICE, "CHAN_VOICE" }, + { CHAN_ITEM, "CHAN_ITEM" }, + { CHAN_BODY, "CHAN_BODY" }, + { CHAN_STREAM, "CHAN_STREAM" }, + { CHAN_STATIC, "CHAN_STATIC" }, + { CHAN_VOICE2, "CHAN_VOICE2" }, +}; + +struct VolumeLevel +{ + float volume; + const char *name; +}; + +static VolumeLevel g_pVolumeLevels[] = +{ + { VOL_NORM, "VOL_NORM" }, +}; + +struct PitchLookup +{ + float pitch; + const char *name; +}; + +static PitchLookup g_pPitchLookup[] = +{ + { PITCH_NORM, "PITCH_NORM" }, + { PITCH_LOW, "PITCH_LOW" }, + { PITCH_HIGH, "PITCH_HIGH" }, +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct SoundLevelLookup +{ + soundlevel_t level; + char const *name; +}; + +// NOTE: Needs to reflect the soundlevel_t enum defined in soundflags.h +static SoundLevelLookup g_pSoundLevels[] = +{ + { SNDLVL_NONE, "SNDLVL_NONE" }, + { SNDLVL_20dB, "SNDLVL_20dB" }, + { SNDLVL_25dB, "SNDLVL_25dB" }, + { SNDLVL_30dB, "SNDLVL_30dB" }, + { SNDLVL_35dB, "SNDLVL_35dB" }, + { SNDLVL_40dB, "SNDLVL_40dB" }, + { SNDLVL_45dB, "SNDLVL_45dB" }, + { SNDLVL_50dB, "SNDLVL_50dB" }, + { SNDLVL_55dB, "SNDLVL_55dB" }, + { SNDLVL_IDLE, "SNDLVL_IDLE" }, + { SNDLVL_TALKING, "SNDLVL_TALKING" }, + { SNDLVL_60dB, "SNDLVL_60dB" }, + { SNDLVL_65dB, "SNDLVL_65dB" }, + { SNDLVL_STATIC, "SNDLVL_STATIC" }, + { SNDLVL_70dB, "SNDLVL_70dB" }, + { SNDLVL_NORM, "SNDLVL_NORM" }, + { SNDLVL_75dB, "SNDLVL_75dB" }, + { SNDLVL_80dB, "SNDLVL_80dB" }, + { SNDLVL_85dB, "SNDLVL_85dB" }, + { SNDLVL_90dB, "SNDLVL_90dB" }, + { SNDLVL_95dB, "SNDLVL_95dB" }, + { SNDLVL_100dB, "SNDLVL_100dB" }, + { SNDLVL_105dB, "SNDLVL_105dB" }, + { SNDLVL_110dB, "SNDLVL_110dB" }, + { SNDLVL_120dB, "SNDLVL_120dB" }, + { SNDLVL_130dB, "SNDLVL_130dB" }, + { SNDLVL_GUNFIRE, "SNDLVL_GUNFIRE" }, + { SNDLVL_140dB, "SNDLVL_140dB" }, + { SNDLVL_150dB, "SNDLVL_150dB" }, + { SNDLVL_180dB, "SNDLVL_180dB" }, +}; + +static const char *_SoundLevelToString( soundlevel_t level ) +{ + int c = ARRAYSIZE( g_pSoundLevels ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + SoundLevelLookup *entry = &g_pSoundLevels[ i ]; + if ( entry->level == level ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%i", (int)level ); + return sz; +} + +static const char *_ChannelToString( int channel ) +{ + int c = ARRAYSIZE( g_pChannelNames ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + SoundChannels *entry = &g_pChannelNames[ i ]; + if ( entry->channel == channel ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%i", (int)channel ); + return sz; +} + +static const char *_VolumeToString( float volume ) +{ + int c = ARRAYSIZE( g_pVolumeLevels ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + VolumeLevel *entry = &g_pVolumeLevels[ i ]; + if ( entry->volume == volume ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%.3f", volume ); + return sz; +} + +static const char *_PitchToString( float pitch ) +{ + int c = ARRAYSIZE( g_pPitchLookup ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + PitchLookup *entry = &g_pPitchLookup[ i ]; + if ( entry->pitch == pitch ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%.3f", pitch ); + return sz; +} + +#define SNDLVL_PREFIX "SNDLVL_" + +soundlevel_t TextToSoundLevel( const char *key ) +{ + if ( !key ) + { + Assert( 0 ); + return SNDLVL_NORM; + } + + int c = ARRAYSIZE( g_pSoundLevels ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + SoundLevelLookup *entry = &g_pSoundLevels[ i ]; + if ( !Q_strcasecmp( key, entry->name ) ) + return entry->level; + } + + if ( !Q_strnicmp( key, SNDLVL_PREFIX, Q_strlen( SNDLVL_PREFIX ) ) ) + { + char const *val = key + Q_strlen( SNDLVL_PREFIX ); + int sndlvl = atoi( val ); + if ( sndlvl > 0 && sndlvl <= 180 ) + { + return ( soundlevel_t )sndlvl; + } + } + + DevMsg( "CSoundEmitterSystem: Unknown sound level %s\n", key ); + + return SNDLVL_NORM; +} + +//----------------------------------------------------------------------------- +// Purpose: Convert "chan_xxx" into integer value for channel +// Input : *name - +// Output : static int +//----------------------------------------------------------------------------- +int TextToChannel( const char *name ) +{ + if ( !name ) + { + Assert( 0 ); + // CHAN_AUTO + return CHAN_AUTO; + } + + if ( Q_strncasecmp( name, "chan_", strlen( "chan_" ) ) ) + { + return atoi( name ); + } + + int c = ARRAYSIZE( g_pChannelNames ); + int i; + + for ( i = 0; i < c; i++ ) + { + if ( !Q_strcasecmp( name, g_pChannelNames[ i ].name ) ) + { + return g_pChannelNames[ i ].channel; + } + } + + // At this point, it starts with chan_ but is not recognized + // atoi would return 0, so just do chan auto + DevMsg( "CSoundEmitterSystem: Warning, unknown channel type in sounds.txt (%s)\n", name ); + + return CHAN_AUTO; +} + +const char *SoundLevelToString( soundlevel_t level ) +{ + int c = ARRAYSIZE( g_pSoundLevels ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + SoundLevelLookup *entry = &g_pSoundLevels[ i ]; + if ( entry->level == level ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%i", (int)level ); + return sz; +} + +const char *ChannelToString( int channel ) +{ + int c = ARRAYSIZE( g_pChannelNames ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + SoundChannels *entry = &g_pChannelNames[ i ]; + if ( entry->channel == channel ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%i", (int)channel ); + return sz; +} + +const char *VolumeToString( float volume ) +{ + int c = ARRAYSIZE( g_pVolumeLevels ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + VolumeLevel *entry = &g_pVolumeLevels[ i ]; + if ( entry->volume == volume ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%.3f", volume ); + return sz; +} + +const char *PitchToString( float pitch ) +{ + int c = ARRAYSIZE( g_pPitchLookup ); + + int i; + + for ( i = 0 ; i < c; i++ ) + { + PitchLookup *entry = &g_pPitchLookup[ i ]; + if ( entry->pitch == pitch ) + return entry->name; + } + + static char sz[ 32 ]; + Q_snprintf( sz, sizeof( sz ), "%.3f", pitch ); + return sz; +} + +CSoundParametersInternal::CSoundParametersInternal() +{ + m_pConvertedNames = m_pSoundNames = NULL; + m_nConvertedNames = m_nSoundNames = 0; + channel = CHAN_AUTO; // 0 + + volume.start = VOL_NORM; // 1.0f + volume.range = 0.0f; + + pitch.start = PITCH_NORM; // 100 + pitch.range = 0; + + soundlevel.start = SNDLVL_NORM; // 75dB + soundlevel.range = 0; + delay_msec = 0; + play_to_owner_only = false; + had_missing_wave_files = false; + uses_gender_token = false; + +} + +CSoundParametersInternal::CSoundParametersInternal( const CSoundParametersInternal& src ) +{ + m_pSoundNames = NULL; + m_pConvertedNames = NULL; + m_nSoundNames = 0; + m_nConvertedNames = 0; + CopyFrom( src ); +} + +CSoundParametersInternal::~CSoundParametersInternal() +{ + if ( m_nSoundNames > 1 ) + free(m_pSoundNames ); + if ( m_nConvertedNames > 1 ) + free( m_pConvertedNames); + + m_pConvertedNames = NULL; + m_pSoundNames = NULL; + m_nSoundNames = 0; + m_nConvertedNames = 0; +} + +void CSoundParametersInternal::CopyFrom( const CSoundParametersInternal& src ) +{ + if ( m_nSoundNames > 1 ) + free(m_pSoundNames); + if ( m_nConvertedNames > 1 ) + free(m_pConvertedNames); + + channel = src.channel; + volume = src.volume; + pitch = src.pitch; + soundlevel = src.soundlevel; + delay_msec = src.delay_msec; + play_to_owner_only = src.play_to_owner_only; + + m_nSoundNames = src.m_nSoundNames; + if ( m_nSoundNames ) + { + if ( m_nSoundNames > 1 ) + { + m_pSoundNames = (SoundFile*)malloc( sizeof(SoundFile)*m_nSoundNames); + memcpy( m_pSoundNames, src.m_pSoundNames, m_nSoundNames * sizeof(SoundFile) ); + } + else + { + m_pSoundNames = src.m_pSoundNames; + } + } + else + { + m_pSoundNames = NULL; + } + + m_nConvertedNames = src.m_nConvertedNames; + if ( m_nConvertedNames ) + { + if ( m_nConvertedNames > 1 ) + { + m_pConvertedNames = (SoundFile*)malloc( sizeof(SoundFile)*m_nConvertedNames); + memcpy( m_pConvertedNames, src.m_pConvertedNames, m_nConvertedNames * sizeof(SoundFile) ); + } + else + { + m_pConvertedNames = src.m_pConvertedNames; + } + } + else + { + m_pConvertedNames = NULL; + } + + had_missing_wave_files = src.had_missing_wave_files; + uses_gender_token = src.uses_gender_token; +} + +#define CompareInterval( i1, i2 ) ( memcmp( &(i1), &(i2), sizeof(i1) ) == 0 ) + +bool CSoundParametersInternal::operator == ( const CSoundParametersInternal& other ) const +{ + if ( this == &other ) + return true; + + if ( channel != other.channel ) + return false; + if ( !CompareInterval( volume, other.volume ) ) + return false; + if ( !CompareInterval( pitch, other.pitch ) ) + return false; + if ( !CompareInterval( soundlevel, other.soundlevel ) ) + return false; + if ( delay_msec != other.delay_msec ) + return false; + if ( play_to_owner_only != other.play_to_owner_only ) + return false; + + if ( m_nSoundNames != other.m_nSoundNames ) + return false; + + // Compare items + int c = m_nSoundNames; + for ( int i = 0; i < c; i++ ) + { + if ( GetSoundNames()[ i ].symbol != other.GetSoundNames()[ i ].symbol ) + return false; + } + + return true; +} + +float16 ZERO_FLOAT16; + +const char *CSoundParametersInternal::VolumeToString( void ) const +{ + if ( volume.range == ZERO_FLOAT16 ) + { + return _VolumeToString( volume.start ); + } + + static char sz[ 64 ]; + Q_snprintf( sz, sizeof( sz ), "%.3f, %.3f", (float)volume.start, (float)volume.start + (float)volume.range ); + return sz; +} + +const char *CSoundParametersInternal::ChannelToString( void ) const +{ + return _ChannelToString( channel ); +} + +const char *CSoundParametersInternal::SoundLevelToString( void ) const +{ + if ( soundlevel.range == 0 ) + { + return _SoundLevelToString( (soundlevel_t)(int)soundlevel.start ); + } + + static char sz[ 64 ]; + Q_snprintf( sz, sizeof( sz ), "%i, %i", (soundlevel_t)(int)soundlevel.start, (soundlevel_t)(int)(soundlevel.start + soundlevel.range ) ); + return sz; +} + +const char *CSoundParametersInternal::PitchToString( void ) const +{ + if ( pitch.range == 0 ) + { + return _PitchToString( (int)pitch.start ); + } + + static char sz[ 64 ]; + Q_snprintf( sz, sizeof( sz ), "%i, %i", (int)pitch.start, (int)(pitch.start + pitch.range ) ); + return sz; +} + +void CSoundParametersInternal::VolumeFromString( const char *sz ) +{ + if ( !Q_strcasecmp( sz, "VOL_NORM" ) ) + { + volume.start = VOL_NORM; + volume.range = 0.0f; + } + else + { + volume.FromInterval( ReadInterval( sz ) ); + } +} + +void CSoundParametersInternal::ChannelFromString( const char *sz ) +{ + channel = TextToChannel( sz ); +} + +void CSoundParametersInternal::PitchFromString( const char *sz ) +{ + if ( !Q_strcasecmp( sz, "PITCH_NORM" ) ) + { + pitch.start = PITCH_NORM; + pitch.range = 0; + } + else if ( !Q_strcasecmp( sz, "PITCH_LOW" ) ) + { + pitch.start = PITCH_LOW; + pitch.range = 0; + } + else if ( !Q_strcasecmp( sz, "PITCH_HIGH" ) ) + { + pitch.start = PITCH_HIGH; + pitch.range = 0; + } + else + { + pitch.FromInterval( ReadInterval( sz ) ); + } +} + +void CSoundParametersInternal::SoundLevelFromString( const char *sz ) +{ + if ( !Q_strncasecmp( sz, "SNDLVL_", strlen( "SNDLVL_" ) ) ) + { + soundlevel.start = TextToSoundLevel( sz ); + soundlevel.range = 0; + } + else + { + soundlevel.FromInterval( ReadInterval( sz ) ); + } +} + +void CSoundParametersInternal::AddToTail( SoundFile **pDest, uint16 *pDestCount, const SoundFile &source ) +{ + (*pDestCount)++; + if ( *pDestCount == 1 ) + { + // NOTE: when there's only one soundfile in the list, we store it + // packed into the pointer itself, the four bytes for the pointer is just used to store the sound file! + COMPILE_TIME_ASSERT( sizeof(SoundFile) <= sizeof(SoundFile *) ); + *((SoundFile *)(pDest)) = source; + } + else + { + SoundFile temp; + if ( *pDestCount == 2 ) + { + // Copying from a list of one soundfile. Save off the struct + // packed into the pointer field. + temp = *((SoundFile *)(pDest)); + *pDest = NULL; + } + + *pDest = (SoundFile *)realloc( *pDest, (*pDestCount) * sizeof(SoundFile) ); + (*pDest)[ *pDestCount - 1 ] = source; + + if ( *pDestCount == 2 ) + { + (*pDest)[0] = temp; + } + } +} + +#endif // !_STATIC_LINKED || SOUNDEMITTERSYSTEM_DLL diff --git a/public/UnicodeFileHelpers.cpp b/public/UnicodeFileHelpers.cpp new file mode 100644 index 0000000..6451827 --- /dev/null +++ b/public/UnicodeFileHelpers.cpp @@ -0,0 +1,240 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include +#include +#include "utlbuffer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Advances until non-whitespace hit +//----------------------------------------------------------------------------- +ucs2 *AdvanceOverWhitespace(ucs2 *Start) +{ + while (*Start != 0 && iswspace(*Start)) + { + Start++; + } + + return Start; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ucs2 *ReadUnicodeToken(ucs2 *start, ucs2 *token, int tokenBufferSize, bool "ed) +{ + // skip over any whitespace + start = AdvanceOverWhitespace(start); + quoted = false; + *token = 0; + + if (!*start) + { + return start; + } + + // check to see if it's a quoted string + if (*start == '\"') + { + quoted = true; + // copy out the string until we hit an end quote + start++; + int count = 0; + while (*start && *start != '\"' && count < tokenBufferSize-1) + { + // check for special characters + if (*start == '\\' && *(start+1) == 'n') + { + start++; + *token = '\n'; + } + else if (*start == '\\' && *(start+1) == '\"') + { + start++; + *token = '\"'; + } + else + { + *token = *start; + } + + start++; + token++; + count++; + } + + if (*start == '\"') + { + start++; + } + } + else + { + // copy out the string until we hit a whitespace + int count = 0; + while (*start && !iswspace(*start) && count < tokenBufferSize-1) + { + // no checking for special characters if it's not a quoted string + *token = *start; + + start++; + token++; + count++; + } + } + + *token = 0; + return start; +} + +//----------------------------------------------------------------------------- +// Purpose: Same as above but no translation of \n +//----------------------------------------------------------------------------- +ucs2 *ReadUnicodeTokenNoSpecial(ucs2 *start, ucs2 *token, int tokenBufferSize, bool "ed) +{ + // skip over any whitespace + start = AdvanceOverWhitespace(start); + quoted = false; + *token = 0; + + if (!*start) + { + return start; + } + + // check to see if it's a quoted string + if (*start == '\"') + { + quoted = true; + // copy out the string until we hit an end quote + start++; + int count = 0; + while (*start && *start != '\"' && count < tokenBufferSize-1) + { + // check for special characters + /* + if (*start == '\\' && *(start+1) == 'n') + { + start++; + *token = '\n'; + } + else + */ + if (*start == '\\' && *(start+1) == '\"') + { + start++; + *token = '\"'; + } + else + { + *token = *start; + } + + start++; + token++; + count++; + } + + if (*start == '\"') + { + start++; + } + } + else + { + // copy out the string until we hit a whitespace + int count = 0; + while (*start && !iswspace(*start) && count < tokenBufferSize-1) + { + // no checking for special characters if it's not a quoted string + *token = *start; + + start++; + token++; + count++; + } + } + + *token = 0; + return start; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the first character after the next EOL characters +//----------------------------------------------------------------------------- +ucs2 *ReadToEndOfLine(ucs2 *start) +{ + if (!*start) + return start; + + while (*start) + { + if (*start == 0x0D || *start== 0x0A) + break; + start++; + } + + while (*start == 0x0D || *start== 0x0A) + start++; + + return start; +} + +//----------------------------------------------------------------------------- +// Purpose: file writing +//----------------------------------------------------------------------------- +void WriteUnicodeString(CUtlBuffer &buf, const wchar_t *string, bool addQuotes) +{ + if (addQuotes) + { + buf.PutUnsignedShort('\"'); + } + + for (const wchar_t *ws = string; *ws != 0; ws++) + { + // handle special characters + if (addQuotes && *ws == '\"') + { + buf.PutUnsignedShort('\\'); + } + // write the character + buf.PutUnsignedShort(*ws); + } + + if (addQuotes) + { + buf.PutUnsignedShort('\"'); + } +} + +//----------------------------------------------------------------------------- +// Purpose: file writing +//----------------------------------------------------------------------------- +void WriteAsciiStringAsUnicode(CUtlBuffer &buf, const char *string, bool addQuotes) +{ + if (addQuotes) + { + buf.PutUnsignedShort('\"'); + } + + for (const char *sz = string; *sz != 0; sz++) + { + // handle special characters + if (addQuotes && *sz == '\"') + { + buf.PutUnsignedShort('\\'); + } + buf.PutUnsignedShort(*sz); + } + + if (addQuotes) + { + buf.PutUnsignedShort('\"'); + } +} diff --git a/public/UnicodeFileHelpers.h b/public/UnicodeFileHelpers.h new file mode 100644 index 0000000..df35f71 --- /dev/null +++ b/public/UnicodeFileHelpers.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef UNICODEFILEHELPERS_H +#define UNICODEFILEHELPERS_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +// helper functions for parsing unicode file buffers +ucs2 *AdvanceOverWhitespace(ucs2 *start); +ucs2 *ReadUnicodeToken(ucs2 *start, ucs2 *token, int tokenBufferSize, bool "ed); +ucs2 *ReadUnicodeTokenNoSpecial(ucs2 *start, ucs2 *token, int tokenBufferSize, bool "ed); +ucs2 *ReadToEndOfLine(ucs2 *start); + +// writing to unicode files via CUtlBuffer +class CUtlBuffer; +void WriteUnicodeString(CUtlBuffer &buffer, const wchar_t *string, bool addQuotes = false); +void WriteAsciiStringAsUnicode(CUtlBuffer &buffer, const char *string, bool addQuotes = false); + + + +#endif // UNICODEFILEHELPERS_H diff --git a/public/UtlCachedFileData.h b/public/UtlCachedFileData.h new file mode 100644 index 0000000..4420c21 --- /dev/null +++ b/public/UtlCachedFileData.h @@ -0,0 +1,999 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef UTLCACHEDFILEDATA_H +#define UTLCACHEDFILEDATA_H +#if defined( WIN32 ) +#pragma once +#endif + +#include "filesystem.h" // FileNameHandle_t +#include "utlrbtree.h" +#include "utlbuffer.h" +#include "UtlSortVector.h" +#include "tier1/strtools.h" + +#include "tier0/memdbgon.h" + +// If you change to serialization protocols, this must be bumped... +#define UTL_CACHE_SYSTEM_VERSION 2 + +#define UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO (long)-2 + +// Cacheable types must derive from this and implement the appropriate methods... +abstract_class IBaseCacheInfo +{ +public: + virtual void Save( CUtlBuffer& buf ) = 0; + virtual void Restore( CUtlBuffer& buf ) = 0; + + virtual void Rebuild( char const *filename ) = 0; +}; + +typedef unsigned int (*PFNCOMPUTECACHEMETACHECKSUM)( void ); + +typedef enum +{ + UTL_CACHED_FILE_USE_TIMESTAMP = 0, + UTL_CACHED_FILE_USE_FILESIZE, +} UtlCachedFileDataType_t; + +template +class CUtlCachedFileData +{ +public: + CUtlCachedFileData + ( + char const *repositoryFileName, + int version, + PFNCOMPUTECACHEMETACHECKSUM checksumfunc = NULL, + UtlCachedFileDataType_t fileCheckType = UTL_CACHED_FILE_USE_TIMESTAMP, + bool nevercheckdisk = false, + bool readonly = false, + bool savemanifest = false + ) + : m_Elements( 0, 0, FileNameHandleLessFunc ), + m_sRepositoryFileName( repositoryFileName ), + m_nVersion( version ), + m_pfnMetaChecksum( checksumfunc ), + m_bDirty( false ), + m_bInitialized( false ), + m_uCurrentMetaChecksum( 0u ), + m_fileCheckType( fileCheckType ), + m_bNeverCheckDisk( nevercheckdisk ), + m_bReadOnly( readonly ), + m_bSaveManifest( savemanifest ) + { + Assert( !m_sRepositoryFileName.IsEmpty() ); + } + + virtual ~CUtlCachedFileData() + { + m_Elements.RemoveAll(); + int c = m_Data.Count(); + for ( int i = 0; i < c ; ++i ) + { + delete m_Data[ i ]; + } + m_Data.RemoveAll(); + } + + T* Get( char const *filename ); + const T* Get( char const *filename ) const; + + T* operator[]( int i ); + const T* operator[]( int i ) const; + + int Count() const; + + void GetElementName( int i, char *buf, int buflen ) + { + buf[ 0 ] = 0; + if ( !m_Elements.IsValidIndex( i ) ) + return; + + g_pFullFileSystem->String( m_Elements[ i ].handle, buf, buflen ); + } + + bool EntryExists( char const *filename ) const + { + ElementType_t element; + element.handle = g_pFullFileSystem->FindOrAddFileName( filename ); + int idx = m_Elements.Find( element ); + return idx != m_Elements.InvalidIndex() ? true : false; + } + + void SetElement( char const *name, long fileinfo, T* src ) + { + SetDirty( true ); + + int idx = GetIndex( name ); + + Assert( idx != m_Elements.InvalidIndex() ); + + ElementType_t& e = m_Elements[ idx ]; + + CUtlBuffer buf( 0, 0, 0 ); + + Assert( e.dataIndex != m_Data.InvalidIndex() ); + + T *dest = m_Data[ e.dataIndex ]; + + Assert( dest ); + + // I suppose we could do an assignment operator, but this should save/restore the data element just fine for + // tool purposes + ((IBaseCacheInfo *)src)->Save( buf ); + ((IBaseCacheInfo *)dest)->Restore( buf ); + + e.fileinfo = fileinfo; + if ( ( e.fileinfo == -1 ) && + ( m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) ) + { + e.fileinfo = 0; + } + // Force recheck + e.diskfileinfo = UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO; + } + + // If you create a cache and don't call init/shutdown, you can call this to do a quick check to see if the checksum/version + // will cause a rebuild... + bool IsUpToDate(); + + void Shutdown(); + bool Init(); + + void Save(); + + void Reload(); + + void ForceRecheckDiskInfo(); + // Iterates all entries and gets filesystem info and optionally causes rebuild on any existing items which are out of date + void CheckDiskInfo( bool force_rebuild, long cacheFileTime = 0L ); + + void SaveManifest(); + bool ManifestExists(); + + const char *GetRepositoryFileName() const { return m_sRepositoryFileName; } + + long GetFileInfo( char const *filename ) + { + ElementType_t element; + element.handle = g_pFullFileSystem->FindOrAddFileName( filename ); + int idx = m_Elements.Find( element ); + if ( idx == m_Elements.InvalidIndex() ) + { + return 0L; + } + + return m_Elements[ idx ].fileinfo; + } + + int GetNumElements() + { + return m_Elements.Count(); + } + + bool IsDirty() const + { + return m_bDirty; + } + + T *RebuildItem( const char *filename ); + +private: + + void InitSmallBuffer( FileHandle_t& fh, int fileSize, bool& deleteFile ); + void InitLargeBuffer( FileHandle_t& fh, bool& deleteFile ); + + int GetIndex( const char *filename ) + { + ElementType_t element; + element.handle = g_pFullFileSystem->FindOrAddFileName( filename ); + int idx = m_Elements.Find( element ); + if ( idx == m_Elements.InvalidIndex() ) + { + T *data = new T(); + + int dataIndex = m_Data.AddToTail( data ); + idx = m_Elements.Insert( element ); + m_Elements[ idx ].dataIndex = dataIndex; + } + + return idx; + } + + void CheckInit(); + + void SetDirty( bool dirty ) + { + m_bDirty = dirty; + } + + void RebuildCache( char const *filename, T *data ); + + struct ElementType_t + { + ElementType_t() : + handle( 0 ), + fileinfo( 0 ), + diskfileinfo( UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO ), + dataIndex( -1 ) + { + } + + FileNameHandle_t handle; + long fileinfo; + long diskfileinfo; + int dataIndex; + }; + + static bool FileNameHandleLessFunc( ElementType_t const &lhs, ElementType_t const &rhs ) + { + return lhs.handle < rhs.handle; + } + + CUtlRBTree< ElementType_t > m_Elements; + CUtlVector< T * > m_Data; + CUtlString m_sRepositoryFileName; + int m_nVersion; + PFNCOMPUTECACHEMETACHECKSUM m_pfnMetaChecksum; + unsigned int m_uCurrentMetaChecksum; + UtlCachedFileDataType_t m_fileCheckType; + bool m_bNeverCheckDisk : 1; + bool m_bReadOnly : 1; + bool m_bSaveManifest : 1; + bool m_bDirty : 1; + bool m_bInitialized : 1; + +}; + + +template +T* CUtlCachedFileData::Get( char const *filename ) +{ + int idx = GetIndex( filename ); + + ElementType_t& e = m_Elements[ idx ]; + + if ( e.fileinfo == -1 && + m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) + { + e.fileinfo = 0; + } + long cachefileinfo = e.fileinfo; + // Set the disk fileinfo the first time we encounter the filename + if ( e.diskfileinfo == UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO ) + { + if ( m_bNeverCheckDisk ) + { + e.diskfileinfo = cachefileinfo; + } + else + { + if ( m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) + { + e.diskfileinfo = g_pFullFileSystem->Size( filename, "GAME" ); + // Missing files get a disk file size of 0 + if ( e.diskfileinfo == -1 ) + { + e.diskfileinfo = 0; + } + } + else + { + e.diskfileinfo = g_pFullFileSystem->GetFileTime( filename, "GAME" ); + } + } + } + + Assert( e.dataIndex != m_Data.InvalidIndex() ); + + T *data = m_Data[ e.dataIndex ]; + + Assert( data ); + + // Compare fileinfo to disk fileinfo and rebuild cache if out of date or not correct... + if ( cachefileinfo != e.diskfileinfo ) + { + if ( !m_bReadOnly ) + { + RebuildCache( filename, data ); + } + e.fileinfo = e.diskfileinfo; + } + + return data; +} + +template +const T* CUtlCachedFileData::Get( char const *filename ) const +{ + return const_cast< CUtlCachedFileData * >(this)->Get( filename ); +} + +template +T* CUtlCachedFileData::operator[]( int i ) +{ + return m_Data[ m_Elements[ i ].dataIndex ]; +} + +template +const T* CUtlCachedFileData::operator[]( int i ) const +{ + return m_Data[ m_Elements[ i ].dataIndex ]; +} + +template +int CUtlCachedFileData::Count() const +{ + return m_Elements.Count(); +} + +template +void CUtlCachedFileData::Reload() +{ + Shutdown(); + Init(); +} + +template +bool CUtlCachedFileData::IsUpToDate() +{ + // Don't call Init/Shutdown if using this method!!! + Assert( !m_bInitialized ); + + if ( m_sRepositoryFileName.IsEmpty() ) + { + Error( "CUtlCachedFileData: Can't IsUpToDate, no repository file specified." ); + return false; + } + + // Always compute meta checksum + m_uCurrentMetaChecksum = m_pfnMetaChecksum ? (*m_pfnMetaChecksum)() : 0; + + FileHandle_t fh; + + fh = g_pFullFileSystem->Open( m_sRepositoryFileName, "rb", "MOD" ); + if ( fh == FILESYSTEM_INVALID_HANDLE ) + { + return false; + } + + // Version data is in first 12 bytes of file + byte header[ 12 ]; + g_pFullFileSystem->Read( header, sizeof( header ), fh ); + g_pFullFileSystem->Close( fh ); + + int cacheversion = *( int *)&header[ 0 ]; + + if ( UTL_CACHE_SYSTEM_VERSION != cacheversion ) + { + DevMsg( "Discarding repository '%s' due to cache system version change\n", m_sRepositoryFileName.String() ); + Assert( !m_bReadOnly ); + if ( !m_bReadOnly ) + { + g_pFullFileSystem->RemoveFile( m_sRepositoryFileName, "MOD" ); + } + return false; + } + + // Now parse data from the buffer + int version = *( int *)&header[ 4 ]; + if ( version != m_nVersion ) + { + DevMsg( "Discarding repository '%s' due to version change\n", m_sRepositoryFileName.String() ); + Assert( !m_bReadOnly ); + if ( !m_bReadOnly ) + { + g_pFullFileSystem->RemoveFile( m_sRepositoryFileName, "MOD" ); + } + return false; + } + + // This is a checksum based on any meta data files which the cache depends on (supplied by a passed in + // meta data function + unsigned int cache_meta_checksum = (unsigned int)*( int *)&header[ 8 ]; + + if ( cache_meta_checksum != m_uCurrentMetaChecksum ) + { + DevMsg( "Discarding repository '%s' due to meta checksum change\n", m_sRepositoryFileName.String() ); + Assert( !m_bReadOnly ); + if ( !m_bReadOnly ) + { + g_pFullFileSystem->RemoveFile( m_sRepositoryFileName, "MOD" ); + } + return false; + } + + // Looks valid + return true; +} + +template +void CUtlCachedFileData::InitSmallBuffer( FileHandle_t& fh, int fileSize, bool& deleteFile ) +{ + deleteFile = false; + + CUtlBuffer loadBuf; + g_pFullFileSystem->ReadToBuffer( fh, loadBuf ); + g_pFullFileSystem->Close( fh ); + + int cacheversion = 0; + loadBuf.Get( &cacheversion, sizeof( cacheversion ) ); + + if ( UTL_CACHE_SYSTEM_VERSION == cacheversion ) + { + // Now parse data from the buffer + int version = loadBuf.GetInt(); + + if ( version == m_nVersion ) + { + // This is a checksum based on any meta data files which the cache depends on (supplied by a passed in + // meta data function + unsigned int cache_meta_checksum = loadBuf.GetInt(); + + if ( cache_meta_checksum == m_uCurrentMetaChecksum ) + { + int count = loadBuf.GetInt(); + + Assert( count < 2000000 ); + + CUtlBuffer buf( 0, 0, 0 ); + + for ( int i = 0 ; i < count; ++i ) + { + int bufsize = loadBuf.GetInt(); + Assert( bufsize < 1000000 ); + + buf.Clear(); + buf.EnsureCapacity( bufsize ); + + loadBuf.Get( buf.Base(), bufsize ); + + buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, bufsize ); + + // Read the element name + char elementFileName[ 512 ]; + buf.GetString( elementFileName ); + + // Now read the element + int slot = GetIndex( elementFileName ); + + Assert( slot != m_Elements.InvalidIndex() ); + + ElementType_t& element = m_Elements[ slot ]; + + element.fileinfo = buf.GetInt(); + if ( ( element.fileinfo == -1 ) && + ( m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) ) + { + element.fileinfo = 0; + } + + Assert( element.dataIndex != m_Data.InvalidIndex() ); + + T *data = m_Data[ element.dataIndex ]; + + Assert( data ); + + ((IBaseCacheInfo *)data)->Restore( buf ); + } + } + else + { + Msg( "Discarding repository '%s' due to meta checksum change\n", m_sRepositoryFileName.String() ); + deleteFile = true; + } + } + else + { + Msg( "Discarding repository '%s' due to version change\n", m_sRepositoryFileName.String() ); + deleteFile = true; + } + } + else + { + DevMsg( "Discarding repository '%s' due to cache system version change\n", m_sRepositoryFileName.String() ); + deleteFile = true; + } +} + +template +void CUtlCachedFileData::InitLargeBuffer( FileHandle_t& fh, bool& deleteFile ) +{ + deleteFile = false; + + int cacheversion = 0; + g_pFullFileSystem->Read( &cacheversion, sizeof( cacheversion ), fh ); + + if ( UTL_CACHE_SYSTEM_VERSION == cacheversion ) + { + // Now parse data from the buffer + int version = 0; + g_pFullFileSystem->Read( &version, sizeof( version ), fh ); + + if ( version == m_nVersion ) + { + // This is a checksum based on any meta data files which the cache depends on (supplied by a passed in + // meta data function + unsigned int cache_meta_checksum = 0; + + g_pFullFileSystem->Read( &cache_meta_checksum, sizeof( cache_meta_checksum ), fh ); + + if ( cache_meta_checksum == m_uCurrentMetaChecksum ) + { + int count = 0; + + g_pFullFileSystem->Read( &count, sizeof( count ), fh ); + + Assert( count < 2000000 ); + + CUtlBuffer buf( 0, 0, 0 ); + + for ( int i = 0 ; i < count; ++i ) + { + int bufsize = 0; + g_pFullFileSystem->Read( &bufsize, sizeof( bufsize ), fh ); + + Assert( bufsize < 1000000 ); + if ( bufsize > 1000000 ) + { + Msg( "Discarding repository '%s' due to corruption\n", m_sRepositoryFileName.String() ); + deleteFile = true; + break; + } + + + buf.Clear(); + buf.EnsureCapacity( bufsize ); + + int nBytesRead = g_pFullFileSystem->Read( buf.Base(), bufsize, fh ); + + buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead ); + + // Read the element name + char elementFileName[ 512 ]; + buf.GetString( elementFileName ); + + // Now read the element + int slot = GetIndex( elementFileName ); + + Assert( slot != m_Elements.InvalidIndex() ); + + ElementType_t& element = m_Elements[ slot ]; + + element.fileinfo = buf.GetInt(); + if ( ( element.fileinfo == -1 ) && + ( m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) ) + { + element.fileinfo = 0; + } + + Assert( element.dataIndex != m_Data.InvalidIndex() ); + + T *data = m_Data[ element.dataIndex ]; + + Assert( data ); + + ((IBaseCacheInfo *)data)->Restore( buf ); + } + } + else + { + Msg( "Discarding repository '%s' due to meta checksum change\n", m_sRepositoryFileName.String() ); + deleteFile = true; + } + } + else + { + Msg( "Discarding repository '%s' due to version change\n", m_sRepositoryFileName.String() ); + deleteFile = true; + } + } + else + { + DevMsg( "Discarding repository '%s' due to cache system version change\n", m_sRepositoryFileName.String() ); + deleteFile = true; + } + + g_pFullFileSystem->Close( fh ); +} + +template +bool CUtlCachedFileData::Init() +{ + if ( m_bInitialized ) + { + return true; + } + + m_bInitialized = true; + + if ( m_sRepositoryFileName.IsEmpty() ) + { + Error( "CUtlCachedFileData: Can't Init, no repository file specified." ); + return false; + } + + // Always compute meta checksum + m_uCurrentMetaChecksum = m_pfnMetaChecksum ? (*m_pfnMetaChecksum)() : 0; + + FileHandle_t fh; + + fh = g_pFullFileSystem->Open( m_sRepositoryFileName, "rb", "MOD" ); + if ( fh == FILESYSTEM_INVALID_HANDLE ) + { + // Nothing on disk, we'll recreate everything from scratch... + SetDirty( true ); + return true; + } + long fileTime = g_pFullFileSystem->GetFileTime( m_sRepositoryFileName, "MOD" ); + int size = g_pFullFileSystem->Size( fh ); + + bool deletefile = false; + + if ( size > 1024 * 1024 ) + { + InitLargeBuffer( fh, deletefile ); + } + else + { + InitSmallBuffer( fh, size, deletefile ); + } + + if ( deletefile ) + { + Assert( !m_bReadOnly ); + if ( !m_bReadOnly ) + { + g_pFullFileSystem->RemoveFile( m_sRepositoryFileName, "MOD" ); + } + SetDirty( true ); + } + CheckDiskInfo( false, fileTime ); + return true; +} + +template +void CUtlCachedFileData::Save() +{ + char path[ 512 ]; + Q_strncpy( path, m_sRepositoryFileName, sizeof( path ) ); + Q_StripFilename( path ); + + g_pFullFileSystem->CreateDirHierarchy( path, "MOD" ); + + if ( g_pFullFileSystem->FileExists( m_sRepositoryFileName, "MOD" ) && + !g_pFullFileSystem->IsFileWritable( m_sRepositoryFileName, "MOD" ) ) + { + g_pFullFileSystem->SetFileWritable( m_sRepositoryFileName, true, "MOD" ); + } + + // Now write to file + FileHandle_t fh; + fh = g_pFullFileSystem->Open( m_sRepositoryFileName, "wb" ); + if ( FILESYSTEM_INVALID_HANDLE == fh ) + { + ExecuteNTimes( 25, Warning( "Unable to persist cache '%s', check file permissions\n", m_sRepositoryFileName.String() ) ); + } + else + { + SetDirty( false ); + + int v = UTL_CACHE_SYSTEM_VERSION; + g_pFullFileSystem->Write( &v, sizeof( v ), fh ); + v = m_nVersion; + g_pFullFileSystem->Write( &v, sizeof( v ), fh ); + v = (int)m_uCurrentMetaChecksum; + g_pFullFileSystem->Write( &v, sizeof( v ), fh ); + + // Element count + int c = Count(); + + g_pFullFileSystem->Write( &c, sizeof( c ), fh ); + + // Save repository back out to disk... + CUtlBuffer buf( 0, 0, 0 ); + + for ( int i = m_Elements.FirstInorder(); i != m_Elements.InvalidIndex(); i = m_Elements.NextInorder( i ) ) + { + buf.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); + + ElementType_t& element = m_Elements[ i ]; + + char fn[ 512 ]; + g_pFullFileSystem->String( element.handle, fn, sizeof( fn ) ); + + buf.PutString( fn ); + buf.PutInt( element.fileinfo ); + + Assert( element.dataIndex != m_Data.InvalidIndex() ); + + T *data = m_Data[ element.dataIndex ]; + + Assert( data ); + + ((IBaseCacheInfo *)data)->Save( buf ); + + int bufsize = buf.TellPut(); + g_pFullFileSystem->Write( &bufsize, sizeof( bufsize ), fh ); + g_pFullFileSystem->Write( buf.Base(), bufsize, fh ); + } + + g_pFullFileSystem->Close( fh ); + } + + if ( m_bSaveManifest ) + { + SaveManifest(); + } +} + +template +void CUtlCachedFileData::Shutdown() +{ + if ( !m_bInitialized ) + return; + + m_bInitialized = false; + + if ( IsDirty() ) + { + Save(); + } + // No matter what, create the manifest if it doesn't exist on the HD yet + else if ( m_bSaveManifest && !ManifestExists() ) + { + SaveManifest(); + } + + m_Elements.RemoveAll(); +} + +template +bool CUtlCachedFileData::ManifestExists() +{ + char manifest_name[ 512 ]; + Q_strncpy( manifest_name, m_sRepositoryFileName, sizeof( manifest_name ) ); + + Q_SetExtension( manifest_name, ".manifest", sizeof( manifest_name ) ); + + return g_pFullFileSystem->FileExists( manifest_name, "MOD" ); +} + +template +void CUtlCachedFileData::SaveManifest() +{ + // Save manifest out to disk... + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + + for ( int i = m_Elements.FirstInorder(); i != m_Elements.InvalidIndex(); i = m_Elements.NextInorder( i ) ) + { + ElementType_t& element = m_Elements[ i ]; + + char fn[ 512 ]; + g_pFullFileSystem->String( element.handle, fn, sizeof( fn ) ); + + buf.Printf( "\"%s\"\r\n", fn ); + } + + char path[ 512 ]; + Q_strncpy( path, m_sRepositoryFileName, sizeof( path ) ); + Q_StripFilename( path ); + + g_pFullFileSystem->CreateDirHierarchy( path, "MOD" ); + + char manifest_name[ 512 ]; + Q_strncpy( manifest_name, m_sRepositoryFileName, sizeof( manifest_name ) ); + + Q_SetExtension( manifest_name, ".manifest", sizeof( manifest_name ) ); + + if ( g_pFullFileSystem->FileExists( manifest_name, "MOD" ) && + !g_pFullFileSystem->IsFileWritable( manifest_name, "MOD" ) ) + { + g_pFullFileSystem->SetFileWritable( manifest_name, true, "MOD" ); + } + + // Now write to file + FileHandle_t fh; + fh = g_pFullFileSystem->Open( manifest_name, "wb" ); + if ( FILESYSTEM_INVALID_HANDLE != fh ) + { + g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh ); + g_pFullFileSystem->Close( fh ); + + // DevMsg( "Persisting cache manifest '%s' (%d entries)\n", manifest_name, c ); + } + else + { + Warning( "Unable to persist cache manifest '%s', check file permissions\n", manifest_name ); + } +} + +template +T *CUtlCachedFileData::RebuildItem( const char *filename ) +{ + int idx = GetIndex( filename ); + ElementType_t& e = m_Elements[ idx ]; + + ForceRecheckDiskInfo(); + + long cachefileinfo = e.fileinfo; + // Set the disk fileinfo the first time we encounter the filename + if ( e.diskfileinfo == UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO ) + { + if ( m_bNeverCheckDisk ) + { + e.diskfileinfo = cachefileinfo; + } + else + { + if ( m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) + { + e.diskfileinfo = g_pFullFileSystem->Size( filename, "GAME" ); + // Missing files get a disk file size of 0 + if ( e.diskfileinfo == -1 ) + { + e.diskfileinfo = 0; + } + } + else + { + e.diskfileinfo = g_pFullFileSystem->GetFileTime( filename, "GAME" ); + } + } + } + + Assert( e.dataIndex != m_Data.InvalidIndex() ); + + T *data = m_Data[ e.dataIndex ]; + + Assert( data ); + + // Compare fileinfo to disk fileinfo and rebuild cache if out of date or not correct... + if ( !m_bReadOnly ) + { + RebuildCache( filename, data ); + } + e.fileinfo = e.diskfileinfo; + + return data; +} + +template +void CUtlCachedFileData::RebuildCache( char const *filename, T *data ) +{ + Assert( !m_bReadOnly ); + + // Recache item, mark self as dirty + SetDirty( true ); + + ((IBaseCacheInfo *)data)->Rebuild( filename ); +} + +template +void CUtlCachedFileData::ForceRecheckDiskInfo() +{ + for ( int i = m_Elements.FirstInorder(); i != m_Elements.InvalidIndex(); i = m_Elements.NextInorder( i ) ) + { + ElementType_t& element = m_Elements[ i ]; + element.diskfileinfo = UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO; + } +} + +class CSortedCacheFile +{ +public: + FileNameHandle_t handle; + int index; + + bool Less( const CSortedCacheFile &file0, const CSortedCacheFile &file1, void * ) + { + char name0[ 512 ]; + char name1[ 512 ]; + g_pFullFileSystem->String( file0.handle, name0, sizeof( name0 ) ); + g_pFullFileSystem->String( file1.handle, name1, sizeof( name1 ) ); + return Q_stricmp( name0, name1 ) < 0 ? true : false; + } +}; + +// Iterates all entries and causes rebuild on any existing items which are out of date +template +void CUtlCachedFileData::CheckDiskInfo( bool forcerebuild, long cacheFileTime ) +{ + char fn[ 512 ]; + int i; + if ( forcerebuild ) + { + for ( i = m_Elements.FirstInorder(); i != m_Elements.InvalidIndex(); i = m_Elements.NextInorder( i ) ) + { + ElementType_t& element = m_Elements[ i ]; + g_pFullFileSystem->String( element.handle, fn, sizeof( fn ) ); + Get(fn); + } + return; + } + + CUtlSortVector list; + for ( i = m_Elements.FirstInorder(); i != m_Elements.InvalidIndex(); i = m_Elements.NextInorder( i ) ) + { + ElementType_t& element = m_Elements[ i ]; + CSortedCacheFile insert; + insert.handle = element.handle; + insert.index = i; + list.InsertNoSort( insert ); + } + list.RedoSort(); + + if ( !list.Count() ) + return; + + for ( int listStart = 0, listEnd = 0; listStart < list.Count(); listStart = listEnd+1 ) + { + int pathIndex = g_pFullFileSystem->GetPathIndex( m_Elements[list[listStart].index].handle ); + for ( listEnd = listStart; listEnd < list.Count(); listEnd++ ) + { + ElementType_t& element = m_Elements[ list[listEnd].index ]; + + int pathTest = g_pFullFileSystem->GetPathIndex( element.handle ); + if ( pathTest != pathIndex ) + break; + } + g_pFullFileSystem->String( m_Elements[list[listStart].index].handle, fn, sizeof( fn ) ); + Q_StripFilename( fn ); + bool bCheck = true; + + if ( m_bNeverCheckDisk ) + { + bCheck = false; + } + else + { + long pathTime = g_pFullFileSystem->GetPathTime( fn, "GAME" ); + bCheck = (pathTime > cacheFileTime) ? true : false; + } + + for ( i = listStart; i < listEnd; i++ ) + { + ElementType_t& element = m_Elements[ list[i].index ]; + + if ( element.diskfileinfo == UTL_CACHED_FILE_DATA_UNDEFINED_DISKINFO ) + { + if ( !bCheck ) + { + element.diskfileinfo = element.fileinfo; + } + else + { + g_pFullFileSystem->String( element.handle, fn, sizeof( fn ) ); + if ( m_fileCheckType == UTL_CACHED_FILE_USE_FILESIZE ) + { + element.diskfileinfo = g_pFullFileSystem->Size( fn, "GAME" ); + + // Missing files get a disk file size of 0 + if ( element.diskfileinfo == -1 ) + { + element.diskfileinfo = 0; + } + } + else + { + element.diskfileinfo = g_pFullFileSystem->GetFileTime( fn, "GAME" ); + } + } + } + } + } +} + +#include "tier0/memdbgoff.h" + +#endif // UTLCACHEDFILEDATA_H diff --git a/public/VGuiMatSurface/IMatSystemSurface.h b/public/VGuiMatSurface/IMatSystemSurface.h new file mode 100644 index 0000000..8d76b80 --- /dev/null +++ b/public/VGuiMatSurface/IMatSystemSurface.h @@ -0,0 +1,122 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: An extra interface implemented by the material system +// implementation of vgui::ISurface +// +// $Revision: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef IMATSYSTEMSURFACE_H +#define IMATSYSTEMSURFACE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "vgui/ISurface.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class VMatrix; +class IMaterial; +struct InputEvent_t; + + +//----------------------------------------------------------------------------- +// Callbacks for mouse getting + setting +//----------------------------------------------------------------------------- +typedef void (*GetMouseCallback_t)(int &x, int &y); +typedef void (*SetMouseCallback_t)(int x, int y); + +//----------------------------------------------------------------------------- +// Callbacks for sound playing +//----------------------------------------------------------------------------- +typedef void (*PlaySoundFunc_t)(const char *pFileName); + + +//----------------------------------------------------------------------------- +// +// An extra interface implemented by the material system implementation of vgui::ISurface +// +//----------------------------------------------------------------------------- +#define MAT_SYSTEM_SURFACE_INTERFACE_VERSION "MatSystemSurface008" +class IMatSystemSurface : public vgui::ISurface +{ +public: + // Hook needed to get input to work. + // If the app drives the input (like the engine needs to do for VCR mode), + // it can set bLetAppDriveInput to true and call HandleInputEvent for the input events. + virtual void AttachToWindow( void *hwnd, bool bLetAppDriveInput=false ) = 0; + + // Tells the surface to ignore windows messages + virtual void EnableWindowsMessages( bool bEnable ) = 0; + + // Starts, ends 3D painting + // NOTE: These methods should only be called from within the paint() + // method of a panel. + virtual void Begin3DPaint( int iLeft, int iTop, int iRight, int iBottom, bool bRenderToTexture = true ) = 0; + virtual void End3DPaint() = 0; + + // NOTE: This also should only be called from within the paint() + // method of a panel. Use it to disable clipping for the rendering + // of this panel. + virtual void DisableClipping( bool bDisable ) = 0; + virtual void GetClippingRect( int &left, int &top, int &right, int &bottom, bool &bClippingDisabled ) = 0; // <<<<< NOTE: output flag is *disabled* state, not enabled, to match the rest of the interface + virtual void SetClippingRect( int left, int top, int right, int bottom ) = 0; + + // Prevents vgui from changing the cursor + virtual bool IsCursorLocked() const = 0; + + // Sets the mouse get + set callbacks + virtual void SetMouseCallbacks( GetMouseCallback_t getFunc, SetMouseCallback_t setFunc ) = 0; + + // Installs a function to play sounds + virtual void InstallPlaySoundFunc( PlaySoundFunc_t soundFunc ) = 0; + + // Some drawing methods that cannot be accomplished under Win32 + virtual void DrawColoredCircle( int centerx, int centery, float radius, int r, int g, int b, int a ) = 0; + virtual int DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // Draws text with current font at position and wordwrapped to the rect using color values specified + virtual void DrawColoredTextRect( vgui::HFont font, int x, int y, int w, int h, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + virtual void DrawTextHeight( vgui::HFont font, int w, int& h, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // Returns the length of the text string in pixels + virtual int DrawTextLen( vgui::HFont font, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // Draws a panel in 3D space. Assumes view + projection are already set up + // Also assumes the (x,y) coordinates of the panels are defined in 640xN coords + // (N isn't necessary 480 because the panel may not be 4x3) + // The width + height specified are the size of the panel in world coordinates + virtual void DrawPanelIn3DSpace( vgui::VPANEL pRootPanel, const VMatrix &panelCenterToWorld, int nPixelWidth, int nPixelHeight, float flWorldWidth, float flWorldHeight ) = 0; + + // Binds a material to a surface texture ID + virtual void DrawSetTextureMaterial( int id, IMaterial *pMaterial ) = 0; + + // Handles an input event, returns true if the event should be filtered from the rest of the game + virtual bool HandleInputEvent( const InputEvent_t &event ) = 0; + + virtual void Set3DPaintTempRenderTarget( const char *pRenderTargetName ) = 0; + virtual void Reset3DPaintTempRenderTarget( void ) = 0; + +// Gets a material bound to a surface texture ID + virtual IMaterial *DrawGetTextureMaterial( int id ) = 0; + + virtual void GetFullscreenViewportAndRenderTarget( int & x, int & y, int & w, int & h, ITexture **ppRenderTarget ) = 0; + virtual void SetFullscreenViewportAndRenderTarget( int x, int y, int w, int h, ITexture *pRenderTarget ) = 0; + + // get texture id for a texture + virtual int DrawGetTextureId( ITexture *pTexture ) = 0; + + // begin and end skin composition painting + virtual void BeginSkinCompositionPainting() = 0; + virtual void EndSkinCompositionPainting() = 0; +}; + + +#endif // IMATSYSTEMSURFACE_H + diff --git a/public/VGuiMatSurface/IMatSystemSurfaceV5.h b/public/VGuiMatSurface/IMatSystemSurfaceV5.h new file mode 100644 index 0000000..3c4aa68 --- /dev/null +++ b/public/VGuiMatSurface/IMatSystemSurfaceV5.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IMATSYSTEMSURFACEV5_H +#define IMATSYSTEMSURFACEV5_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "vgui/isurfacev30.h" + + +namespace MatSystemSurfaceV5 +{ + #define MAT_SYSTEM_SURFACE_INTERFACE_VERSION_5 "MatSystemSurface005" + + + class IMatSystemSurface : public SurfaceV30::ISurface + { + public: + // Hook needed to get input to work. + // If the app drives the input (like the engine needs to do for VCR mode), + // it can set bLetAppDriveInput to true and call HandleWindowMessage for the Windows messages. + virtual void AttachToWindow( void *hwnd, bool bLetAppDriveInput=false ) = 0; + + // If you specified true for bLetAppDriveInput, then call this for each window message that comes in. + virtual void HandleWindowMessage( void *hwnd, unsigned int uMsg, unsigned int wParam, long lParam ) = 0; + + // Tells the surface to ignore windows messages + virtual void EnableWindowsMessages( bool bEnable ) = 0; + + // Starts, ends 3D painting + // NOTE: These methods should only be called from within the paint() + // method of a panel. + virtual void Begin3DPaint( int iLeft, int iTop, int iRight, int iBottom ) = 0; + virtual void End3DPaint() = 0; + + // NOTE: This also should only be called from within the paint() + // method of a panel. Use it to disable clipping for the rendering + // of this panel. + virtual void DisableClipping( bool bDisable ) = 0; + + // Prevents vgui from changing the cursor + virtual bool IsCursorLocked() const = 0; + + // Sets the mouse get + set callbacks + virtual void SetMouseCallbacks( GetMouseCallback_t getFunc, SetMouseCallback_t setFunc ) = 0; + + // Installs a function to play sounds + virtual void InstallPlaySoundFunc( PlaySoundFunc_t soundFunc ) = 0; + + // Some drawing methods that cannot be accomplished under Win32 + virtual void DrawColoredCircle( int centerx, int centery, float radius, int r, int g, int b, int a ) = 0; + virtual int DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, PRINTF_FORMAT_STRING char *fmt, ... ) = 0; + + // Draws text with current font at position and wordwrapped to the rect using color values specified + virtual void DrawColoredTextRect( vgui::HFont font, int x, int y, int w, int h, int r, int g, int b, int a, PRINTF_FORMAT_STRING char *fmt, ... ) = 0; + virtual void DrawTextHeight( vgui::HFont font, int w, int& h, PRINTF_FORMAT_STRING char *fmt, ... ) = 0; + + // Returns the length of the text string in pixels + virtual int DrawTextLen( vgui::HFont font, PRINTF_FORMAT_STRING char *fmt, ... ) = 0; + + // Draws a panel in 3D space. Assumes view + projection are already set up + // Also assumes the (x,y) coordinates of the panels are defined in 640xN coords + // (N isn't necessary 480 because the panel may not be 4x3) + // The width + height specified are the size of the panel in world coordinates + virtual void DrawPanelIn3DSpace( vgui::VPANEL pRootPanel, const VMatrix &panelCenterToWorld, int nPixelWidth, int nPixelHeight, float flWorldWidth, float flWorldHeight ) = 0; + + // Binds a material to a surface texture ID + virtual void DrawSetTextureMaterial( int id, IMaterial *pMaterial ) = 0; + }; + +} + +//----------------------------------------------------------------------------- +// FIXME: This works around using scoped interfaces w/ EXPOSE_SINGLE_INTERFACE +//----------------------------------------------------------------------------- +class IMatSystemSurfaceV5 : public MatSystemSurfaceV5::IMatSystemSurface +{ +public: +}; + +#endif // IMATSYSTEMSURFACEV5_H diff --git a/public/XUnzip.cpp b/public/XUnzip.cpp new file mode 100644 index 0000000..e58f55b --- /dev/null +++ b/public/XUnzip.cpp @@ -0,0 +1,4488 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// XUnzip.cpp Version 1.1 +// +// Authors: Mark Adler et al. (see below) +// +// Modified by: Lucian Wischik +// lu@wischik.com +// +// Version 1.0 - Turned C files into just a single CPP file +// - Made them compile cleanly as C++ files +// - Gave them simpler APIs +// - Added the ability to zip/unzip directly in memory without +// any intermediate files +// +// Modified by: Hans Dietrich +// hdietrich2@hotmail.com +// +// Version 1.1: - Added Unicode support to CreateZip() and ZipAdd() +// - Changed file names to avoid conflicts with Lucian's files +// +/////////////////////////////////////////////////////////////////////////////// +// +// Lucian Wischik's comments: +// -------------------------- +// THIS FILE is almost entirely based upon code by Info-ZIP. +// It has been modified by Lucian Wischik. +// The original code may be found at http://www.info-zip.org +// The original copyright text follows. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Original authors' comments: +// --------------------------- +// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The +// definitive version of this document should be available at +// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. +// +// Copyright (c) 1990-2002 Info-ZIP. All rights reserved. +// +// For the purposes of this copyright and license, "Info-ZIP" is defined as +// the following set of individuals: +// +// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, +// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, +// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, +// David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, +// Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, +// Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler, +// Antoine Verheijen, Paul von Behren, Rich Wales, Mike White +// +// This software is provided "as is", without warranty of any kind, express +// or implied. In no event shall Info-ZIP or its contributors be held liable +// for any direct, indirect, incidental, special or consequential damages +// arising out of the use of or inability to use this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. Redistributions of source code must retain the above copyright notice, +// definition, disclaimer, and this list of conditions. +// +// 2. Redistributions in binary form (compiled executables) must reproduce +// the above copyright notice, definition, disclaimer, and this list of +// conditions in documentation and/or other materials provided with the +// distribution. The sole exception to this condition is redistribution +// of a standard UnZipSFX binary as part of a self-extracting archive; +// that is permitted without inclusion of this license, as long as the +// normal UnZipSFX banner has not been removed from the binary or disabled. +// +// 3. Altered versions--including, but not limited to, ports to new +// operating systems, existing ports with new graphical interfaces, and +// dynamic, shared, or static library versions--must be plainly marked +// as such and must not be misrepresented as being the original source. +// Such altered versions also must not be misrepresented as being +// Info-ZIP releases--including, but not limited to, labeling of the +// altered versions with the names "Info-ZIP" (or any variation thereof, +// including, but not limited to, different capitalizations), +// "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of +// Info-ZIP. Such altered versions are further prohibited from +// misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or +// of the Info-ZIP URL(s). +// +// 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip", +// "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its +// own source and binary releases. +// +/////////////////////////////////////////////////////////////////////////////// + +#if defined( WIN32 ) && !defined( _X360 ) +#define STRICT +#define WIN32_LEAN_AND_MEAN +#include +#include +#elif defined(POSIX) +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include "zip/XUnzip.h" + +#if defined(POSIX) +#define _tcslen strlen +#define _tcscpy strcpy +#define _tcscat strcat +#define _tcsstr strstr +#if !defined( _T ) +#define _T( arg ) arg +#endif +#define INVALID_HANDLE_VALUE (void*)-1 +#define CloseHandle( arg ) close( (int) arg ) +#define ZeroMemory( ptr, size ) memset( ptr, 0, size ) +#define FILE_CURRENT SEEK_CUR +#define FILE_BEGIN SEEK_SET +#define FILE_END SEEK_END +#define CreateDirectory( dir, ign ) mkdir( dir, S_IRWXU | S_IRWXG | S_IRWXO ) +#define SetFilePointer( handle, pos, ign, dir ) lseek( (int) handle, pos, dir ) +bool ReadFile( void *handle, void *outbuf, unsigned int toread, unsigned int *nread, void *ignored ) +{ + *nread = read( (int) handle, outbuf, toread ); + return *nread == toread; +} +bool WriteFile( void *handle, void *buf, unsigned int towrite, unsigned int *written, void *ignored ) +{ + *written = write( (int) handle, buf, towrite ); + return *written == towrite; +} + +#define FILE_ATTRIBUTE_NORMAL S_IFREG +#define FILE_ATTRIBUTE_DIRECTORY S_IFDIR +#define FILE_ATTRIBUTE_ARCHIVE 0 +#define FILE_ATTRIBUTE_HIDDEN 0 +#define FILE_ATTRIBUTE_READONLY 0 +#define FILE_ATTRIBUTE_SYSTEM 0 +typedef unsigned char BYTE; +#endif // POSIX + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + + +// THIS FILE is almost entirely based upon code by Jean-loup Gailly +// and Mark Adler. It has been modified by Lucian Wischik. +// The original code may be found at http://www.gzip.org/zlib/ +// The original copyright text follows. +// +// +// +// zlib.h -- interface of the 'zlib' general purpose compression library +// version 1.1.3, July 9th, 1998 +// +// Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Jean-loup Gailly Mark Adler +// jloup@gzip.org madler@alumni.caltech.edu +// +// +// The data format used by the zlib library is described by RFCs (Request for +// Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt +// (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +// +// +// The 'zlib' compression library provides in-memory compression and +// decompression functions, including integrity checks of the uncompressed +// data. This version of the library supports only one compression method +// (deflation) but other algorithms will be added later and will have the same +// stream interface. +// +// Compression can be done in a single step if the buffers are large +// enough (for example if an input file is mmap'ed), or can be done by +// repeated calls of the compression function. In the latter case, the +// application must provide more input and/or consume the output +// (providing more output space) before each call. +// +// The library also supports reading and writing files in gzip (.gz) format +// with an interface similar to that of stdio. +// +// The library does not install any signal handler. The decoder checks +// the consistency of the compressed data, so the library should never +// crash even in case of corrupted input. +// +// for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip +// PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip + +#define zmalloc(len) malloc(len) + +#define zfree(p) free(p) + +/* +void *zmalloc(unsigned int len) +{ char *buf = new char[len+32]; + for (int i=0; i<16; i++) + { buf[i]=i; + buf[len+31-i]=i; + } + *((unsigned int*)buf) = len; + char c[1000]; wsprintf(c,"malloc 0x%lx - %lu",buf+16,len); + OutputDebugString(c); + return buf+16; +} + +void zfree(void *buf) +{ char c[1000]; wsprintf(c,"free 0x%lx",buf); + OutputDebugString(c); + char *p = ((char*)buf)-16; + unsigned int len = *((unsigned int*)p); + bool blown=false; + for (int i=0; i<16; i++) + { char lo = p[i]; + char hi = p[len+31-i]; + if (hi!=i || (lo!=i && i>4)) blown=true; + } + if (blown) + { OutputDebugString("BLOWN!!!"); + } + delete[] p; +} +*/ + +#pragma warning(disable : 4702) // unreachable code + +typedef struct tm_unz_s +{ unsigned int tm_sec; // seconds after the minute - [0,59] + unsigned int tm_min; // minutes after the hour - [0,59] + unsigned int tm_hour; // hours since midnight - [0,23] + unsigned int tm_mday; // day of the month - [1,31] + unsigned int tm_mon; // months since January - [0,11] + unsigned int tm_year; // years - [1980..2044] +} tm_unz; + + +// unz_global_info structure contain global data about the ZIPfile +typedef struct unz_global_info_s +{ unsigned long number_entry; // total number of entries in the central dir on this disk + unsigned long size_comment; // size of the global comment of the zipfile +} unz_global_info; + +// unz_file_info contain information about a file in the zipfile +typedef struct unz_file_info_s +{ unsigned long version; // version made by 2 bytes + unsigned long version_needed; // version needed to extract 2 bytes + unsigned long flag; // general purpose bit flag 2 bytes + unsigned long compression_method; // compression method 2 bytes + unsigned long dosDate; // last mod file date in Dos fmt 4 bytes + unsigned long crc; // crc-32 4 bytes + unsigned long compressed_size; // compressed size 4 bytes + unsigned long uncompressed_size; // uncompressed size 4 bytes + unsigned long size_filename; // filename length 2 bytes + unsigned long size_file_extra; // extra field length 2 bytes + unsigned long size_file_comment; // file comment length 2 bytes + unsigned long disk_num_start; // disk number start 2 bytes + unsigned long internal_fa; // internal file attributes 2 bytes + unsigned long external_fa; // external file attributes 4 bytes + tm_unz tmu_date; +} unz_file_info; + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + + + + + + + +#define ZLIB_VERSION "1.1.3" + + +// Allowed flush values; see deflate() for details +#define Z_NO_FLUSH 0 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 + + +// compression levels +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) + +// compression strategy; see deflateInit2() for details +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 + +// Possible values of the data_type field +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 + +// The deflate compression method (the only one supported in this version) +#define Z_DEFLATED 8 + +// for initializing zalloc, zfree, opaque +#define Z_NULL 0 + +// case sensitivity when searching for filenames +#define CASE_SENSITIVE 1 +#define CASE_INSENSITIVE 2 + + +// Return codes for the compression/decompression functions. Negative +// values are errors, positive values are used for special but normal events. +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) + + + +// Basic data types +typedef unsigned char Byte; // 8 bits +typedef unsigned int uInt; // 16 bits or more +typedef unsigned long uLong; // 32 bits or more +typedef void *voidpf; +typedef void *voidp; +typedef long z_off_t; + + + + + + + + + + + + +typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size); +typedef void (*free_func) (voidpf opaque, voidpf address); + +struct internal_state; + +typedef struct z_stream_s { + Byte *next_in; // next input byte + uInt avail_in; // number of bytes available at next_in + uLong total_in; // total nb of input bytes read so far + + Byte *next_out; // next output byte should be put there + uInt avail_out; // remaining free space at next_out + uLong total_out; // total nb of bytes output so far + + char *msg; // last error message, NULL if no error + struct internal_state *state; // not visible by applications + + alloc_func zalloc; // used to allocate the internal state + free_func zfree; // used to free the internal state + voidpf opaque; // private data object passed to zalloc and zfree + + int data_type; // best guess about the data type: ascii or binary + uLong adler; // adler32 value of the uncompressed data + uLong reserved; // reserved for future use +} z_stream; + +typedef z_stream *z_streamp; + + +// The application must update next_in and avail_in when avail_in has +// dropped to zero. It must update next_out and avail_out when avail_out +// has dropped to zero. The application must initialize zalloc, zfree and +// opaque before calling the init function. All other fields are set by the +// compression library and must not be updated by the application. +// +// The opaque value provided by the application will be passed as the first +// parameter for calls of zalloc and zfree. This can be useful for custom +// memory management. The compression library attaches no meaning to the +// opaque value. +// +// zalloc must return Z_NULL if there is not enough memory for the object. +// If zlib is used in a multi-threaded application, zalloc and zfree must be +// thread safe. +// +// The fields total_in and total_out can be used for statistics or +// progress reports. After compression, total_in holds the total size of +// the uncompressed data and may be saved for use in the decompressor +// (particularly if the decompressor wants to decompress everything in +// a single step). +// + + +// basic functions + +const char *zlibVersion (); +// The application can compare zlibVersion and ZLIB_VERSION for consistency. +// If the first character differs, the library code actually used is +// not compatible with the zlib.h header file used by the application. +// This check is automatically made by inflateInit. + + + + + + +int inflate (z_streamp strm, int flush); +// +// inflate decompresses as much data as possible, and stops when the input +// buffer becomes empty or the output buffer becomes full. It may some +// introduce some output latency (reading input without producing any output) +// except when forced to flush. +// +// The detailed semantics are as follows. inflate performs one or both of the +// following actions: +// +// - Decompress more input starting at next_in and update next_in and avail_in +// accordingly. If not all input can be processed (because there is not +// enough room in the output buffer), next_in is updated and processing +// will resume at this point for the next call of inflate(). +// +// - Provide more output starting at next_out and update next_out and avail_out +// accordingly. inflate() provides as much output as possible, until there +// is no more input data or no more space in the output buffer (see below +// about the flush parameter). +// +// Before the call of inflate(), the application should ensure that at least +// one of the actions is possible, by providing more input and/or consuming +// more output, and updating the next_* and avail_* values accordingly. +// The application can consume the uncompressed output when it wants, for +// example when the output buffer is full (avail_out == 0), or after each +// call of inflate(). If inflate returns Z_OK and with zero avail_out, it +// must be called again after making room in the output buffer because there +// might be more output pending. +// +// If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much +// output as possible to the output buffer. The flushing behavior of inflate is +// not specified for values of the flush parameter other than Z_SYNC_FLUSH +// and Z_FINISH, but the current implementation actually flushes as much output +// as possible anyway. +// +// inflate() should normally be called until it returns Z_STREAM_END or an +// error. However if all decompression is to be performed in a single step +// (a single call of inflate), the parameter flush should be set to +// Z_FINISH. In this case all pending input is processed and all pending +// output is flushed; avail_out must be large enough to hold all the +// uncompressed data. (The size of the uncompressed data may have been saved +// by the compressor for this purpose.) The next operation on this stream must +// be inflateEnd to deallocate the decompression state. The use of Z_FINISH +// is never required, but can be used to inform inflate that a faster routine +// may be used for the single inflate() call. +// +// If a preset dictionary is needed at this point (see inflateSetDictionary +// below), inflate sets strm-adler to the adler32 checksum of the +// dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise +// it sets strm->adler to the adler32 checksum of all output produced +// so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or +// an error code as described below. At the end of the stream, inflate() +// checks that its computed adler32 checksum is equal to that saved by the +// compressor and returns Z_STREAM_END only if the checksum is correct. +// +// inflate() returns Z_OK if some progress has been made (more input processed +// or more output produced), Z_STREAM_END if the end of the compressed data has +// been reached and all uncompressed output has been produced, Z_NEED_DICT if a +// preset dictionary is needed at this point, Z_DATA_ERROR if the input data was +// corrupted (input stream not conforming to the zlib format or incorrect +// adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent +// (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not +// enough memory, Z_BUF_ERROR if no progress is possible or if there was not +// enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR +// case, the application may then call inflateSync to look for a good +// compression block. +// + + +int inflateEnd (z_streamp strm); +// +// All dynamically allocated data structures for this stream are freed. +// This function discards any unprocessed input and does not flush any +// pending output. +// +// inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state +// was inconsistent. In the error case, msg may be set but then points to a +// static string (which must not be deallocated). + + // Advanced functions + +// The following functions are needed only in some special applications. + + + + + +int inflateSetDictionary (z_streamp strm, + const Byte *dictionary, + uInt dictLength); +// +// Initializes the decompression dictionary from the given uncompressed byte +// sequence. This function must be called immediately after a call of inflate +// if this call returned Z_NEED_DICT. The dictionary chosen by the compressor +// can be determined from the Adler32 value returned by this call of +// inflate. The compressor and decompressor must use exactly the same +// dictionary. +// +// inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a +// parameter is invalid (such as NULL dictionary) or the stream state is +// inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the +// expected one (incorrect Adler32 value). inflateSetDictionary does not +// perform any decompression: this will be done by subsequent calls of +// inflate(). + + +int inflateSync (z_streamp strm); +// +// Skips invalid compressed data until a full flush point can be found, or until all +// available input is skipped. No output is provided. +// +// inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR +// if no more input was provided, Z_DATA_ERROR if no flush point has been found, +// or Z_STREAM_ERROR if the stream structure was inconsistent. In the success +// case, the application may save the current current value of total_in which +// indicates where valid compressed data was found. In the error case, the +// application may repeatedly call inflateSync, providing more input each time, +// until success or end of the input data. + + +int inflateReset (z_streamp strm); +// This function is equivalent to inflateEnd followed by inflateInit, +// but does not free and reallocate all the internal decompression state. +// The stream will keep attributes that may have been set by inflateInit2. +// +// inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source +// stream state was inconsistent (such as zalloc or state being NULL). +// + + + +// checksum functions +// These functions are not related to compression but are exported +// anyway because they might be useful in applications using the +// compression library. + +uLong adler32 (uLong adler, const Byte *buf, uInt len); +// Update a running Adler-32 checksum with the bytes buf[0..len-1] and +// return the updated checksum. If buf is NULL, this function returns +// the required initial value for the checksum. +// An Adler-32 checksum is almost as reliable as a CRC32 but can be computed +// much faster. Usage example: +// +// uLong adler = adler32(0L, Z_NULL, 0); +// +// while (read_buffer(buffer, length) != EOF) { +// adler = adler32(adler, buffer, length); +// } +// if (adler != original_adler) error(); + +uLong ucrc32 (uLong crc, const Byte *buf, uInt len); +// Update a running crc with the bytes buf[0..len-1] and return the updated +// crc. If buf is NULL, this function returns the required initial value +// for the crc. Pre- and post-conditioning (one's complement) is performed +// within this function so it shouldn't be done by the application. +// Usage example: +// +// uLong crc = crc32(0L, Z_NULL, 0); +// +// while (read_buffer(buffer, length) != EOF) { +// crc = crc32(crc, buffer, length); +// } +// if (crc != original_crc) error(); + + + + +const char *zError (int err); +int inflateSyncPoint (z_streamp z); +const uLong *get_crc_table (void); + + + +typedef unsigned char uch; +typedef uch uchf; +typedef unsigned short ush; +typedef ush ushf; +typedef unsigned long ulg; + + + +const char * const z_errmsg[10] = { // indexed by 2-zlib_error +"need dictionary", // Z_NEED_DICT 2 +"stream end", // Z_STREAM_END 1 +"", // Z_OK 0 +"file error", // Z_ERRNO (-1) +"stream error", // Z_STREAM_ERROR (-2) +"data error", // Z_DATA_ERROR (-3) +"insufficient memory", // Z_MEM_ERROR (-4) +"buffer error", // Z_BUF_ERROR (-5) +"incompatible version",// Z_VERSION_ERROR (-6) +""}; + + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +// To be used only when the state is known to be valid + + // common constants + + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +// The three kinds of block type + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +// The minimum and maximum match lengths + +#define PRESET_DICT 0x20 // preset dictionary flag in zlib header + + // target dependencies + +#define OS_CODE 0x0b // Window 95 & Windows NT + + + + // functions + +#define zmemzero(dest, len) memset(dest, 0, len) + +// Diagnostic functions +#undef Assert +#undef Trace +#undef Tracev +#undef Tracevv +#undef Tracec +#undef Tracecv + +#ifdef DEBUG + int z_verbose = 0; + void z_error (char *m) {fprintf(stderr, "%s\n", m); exit(1);} +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) (uLong check, const Byte *buf, uInt len); +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size); +void zcfree (voidpf opaque, voidpf ptr); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) + +//void ZFREE(z_streamp strm,voidpf addr) +//{ *((strm)->zfree))((strm)->opaque, addr); +//} + +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + + + +// Huffman code lookup table entry--this entry is four bytes for machines +// that have 16-bit pointers (e.g. PC's in the small or medium model). + + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; // number of extra bits or operation + Byte Bits; // number of bits in this code or subcode + } what; + uInt pad; // pad structure to a power of 2 (4 bytes for + } word; // 16-bit, 8 bytes for 32-bit int's) + uInt base; // literal, length base, distance base, or table offset +}; + +// Maximum size of dynamic tree. The maximum found in a long but non- +// exhaustive search was 1004 huft structures (850 for length/literals +// and 154 for distances, the latter actually the result of an +// exhaustive search). The actual maximum is not known, but the +// value below is more than safe. +#define MANY 1440 + +int inflate_trees_bits ( + uInt *, // 19 code lengths + uInt *, // bits tree desired/actual depth + inflate_huft * *, // bits tree result + inflate_huft *, // space for trees + z_streamp); // for messages + +int inflate_trees_dynamic ( + uInt, // number of literal/length codes + uInt, // number of distance codes + uInt *, // that many (total) code lengths + uInt *, // literal desired/actual bit depth + uInt *, // distance desired/actual bit depth + inflate_huft * *, // literal/length tree result + inflate_huft * *, // distance tree result + inflate_huft *, // space for trees + z_streamp); // for messages + +int inflate_trees_fixed ( + uInt *, // literal desired/actual bit depth + uInt *, // distance desired/actual bit depth + const inflate_huft * *, // literal/length tree result + const inflate_huft * *, // distance tree result + z_streamp); // for memory allocation + + + + + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +inflate_blocks_statef * inflate_blocks_new ( + z_streamp z, + check_func c, // check function + uInt w); // window size + +int inflate_blocks ( + inflate_blocks_statef *, + z_streamp , + int); // initial return code + +void inflate_blocks_reset ( + inflate_blocks_statef *, + z_streamp , + uLong *); // check value on output + +int inflate_blocks_free ( + inflate_blocks_statef *, + z_streamp); + +void inflate_set_dictionary ( + inflate_blocks_statef *s, + const Byte *d, // dictionary + uInt n); // dictionary length + +int inflate_blocks_sync_point ( + inflate_blocks_statef *s); + + + + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +inflate_codes_statef *inflate_codes_new ( + uInt, uInt, + const inflate_huft *, const inflate_huft *, + z_streamp ); + +int inflate_codes ( + inflate_blocks_statef *, + z_streamp , + int); + +void inflate_codes_free ( + inflate_codes_statef *, + z_streamp ); + + + + +typedef enum { + IBM_TYPE, // get type bits (3, including end bit) + IBM_LENS, // get lengths for stored + IBM_STORED, // processing stored block + IBM_TABLE, // get table lengths + IBM_BTREE, // get bit lengths tree for a dynamic block + IBM_DTREE, // get length, distance trees for a dynamic block + IBM_CODES, // processing fixed or dynamic block + IBM_DRY, // output remaining window bytes + IBM_DONE, // finished last block, done + IBM_BAD} // got a data error--stuck here +inflate_block_mode; + +// inflate blocks semi-private state +struct inflate_blocks_state { + + // mode + inflate_block_mode mode; // current inflate_block mode + + // mode dependent information + union { + uInt left; // if STORED, bytes left to copy + struct { + uInt table; // table lengths (14 bits) + uInt index; // index into blens (or border) + uInt *blens; // bit lengths of codes + uInt bb; // bit length tree depth + inflate_huft *tb; // bit length decoding tree + } trees; // if DTREE, decoding info for trees + struct { + inflate_codes_statef + *codes; + } decode; // if CODES, current state + } sub; // submode + uInt last; // true if this block is the last block + + // mode independent information + uInt bitk; // bits in bit buffer + uLong bitb; // bit buffer + inflate_huft *hufts; // single malloc for tree space + Byte *window; // sliding window + Byte *end; // one byte after sliding window + Byte *read; // window read pointer + Byte *write; // window write pointer + check_func checkfn; // check function + uLong check; // check on output + +}; + + +// defines for inflate input/output +// update pointers and return +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +// get bytes and bits +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +// output bytes +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;m;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +// load local pointers +#define LOAD {LOADIN LOADOUT} + +// masks for lower bits (size given to avoid silly warnings with Visual C++) +// And'ing with mask[n] masks the lower n bits +const uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +// copy as much as possible from the sliding window to the output area +int inflate_flush (inflate_blocks_statef *, z_streamp, int); + +int inflate_fast (uInt, uInt, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp ); + + + +const uInt fixed_bl = 9; +const uInt fixed_bd = 5; +const inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +const inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + + + + + + + +// copy as much as possible from the sliding window to the output area +int inflate_flush(inflate_blocks_statef *s,z_streamp z,int r) +{ + uInt n; + Byte *p; + Byte *q; + + // local copies of source and destination pointers + p = z->next_out; + q = s->read; + + // compute number of bytes to copy as far as end of window + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z->avail_out -= n; + z->total_out += n; + + // update check information + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + // copy as far as end of window + if (n!=0) // check for n!=0 to avoid waking up CodeGuard + { memcpy(p, q, n); + p += n; + q += n; + } + + // see if more to copy at beginning of window + if (q == s->end) + { + // wrap pointers + q = s->window; + if (s->write == s->end) + s->write = s->window; + + // compute bytes to copy + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z->avail_out -= n; + z->total_out += n; + + // update check information + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + // copy + memcpy(p, q, n); + p += n; + q += n; + } + + // update pointers + z->next_out = p; + s->read = q; + + // done + return r; +} + + + + + + +// simplify the use of the inflate_huft type with some defines +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing + START, // x: set up for LEN + LEN, // i: get length/literal/eob next + LENEXT, // i: getting length extra (have base) + DIST, // i: get distance next + DISTEXT, // i: getting distance extra + COPY, // o: copying bytes in window, waiting for space + LIT, // o: got literal, waiting for output space + WASH, // o: got eob, possibly still output waiting + END, // x: got eob and all data flushed + BADCODE} // x: got error +inflate_codes_mode; + +// inflate codes private state +struct inflate_codes_state { + + // mode + inflate_codes_mode mode; // current inflate_codes mode + + // mode dependent information + uInt len; + union { + struct { + const inflate_huft *tree; // pointer into tree + uInt need; // bits needed + } code; // if LEN or DIST, where in tree + uInt lit; // if LIT, literal + struct { + uInt get; // bits to get for extra + uInt dist; // distance back to copy from + } copy; // if EXT or COPY, where and how much + } sub; // submode + + // mode independent information + Byte lbits; // ltree bits decoded per branch + Byte dbits; // dtree bits decoder per branch + const inflate_huft *ltree; // literal/length/eob tree + const inflate_huft *dtree; // distance tree + +}; + + +inflate_codes_statef *inflate_codes_new( +uInt bl, uInt bd, +const inflate_huft *tl, +const inflate_huft *td, // need separate declaration for Borland C++ +z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; // temporary storage + const inflate_huft *t; // temporary pointer + uInt e; // extra bits or operation + uLong b; // bit buffer + uInt k; // bits in bit buffer + Byte *p; // input data pointer + uInt n; // bytes available there + Byte *q; // output window write pointer + uInt m; // bytes to end of window or read pointer + Byte *f; // pointer to copy strings from + inflate_codes_statef *c = s->sub.decode.codes; // codes state + + // copy input/output information to locals (UPDATE macro restores) + LOAD + + // process input and output based on current state + for(;;) switch (c->mode) + { // waiting for "i:"=input, "o:"=output, "x:"=nothing + case START: // x: set up for LEN +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif // !SLOW + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: // i: get length/literal/eob next + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) // literal + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) // length + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) // next table + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) // end of block + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; // invalid code + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: // i: getting length extra (have base) + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: // i: get distance next + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) // distance + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) // next table + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; // invalid code + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: // i: getting distance extra + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: // o: copying bytes in window, waiting for space + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: // o: got literal, waiting for output space + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: // o: got eob, possibly more output + if (k > 7) // return unused byte, if any + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; // can always return one + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: // x: got error + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +void inflate_codes_free(inflate_codes_statef *c,z_streamp z) +{ ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} + + + +// infblock.c -- interpret and process block types to last block +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +//struct inflate_codes_state {int dummy;}; // for buggy compilers + + + +// Table for deflate from PKZIP's appnote.txt. +const uInt border[] = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +// +// Notes beyond the 1.93a appnote.txt: +// +// 1. Distance pointers never point before the beginning of the output stream. +// 2. Distance pointers can point back across blocks, up to 32k away. +// 3. There is an implied maximum of 7 bits for the bit length table and +// 15 bits for the actual data. +// 4. If only one code exists, then it is encoded using one bit. (Zero +// would be more efficient, but perhaps a little confusing.) If two +// codes exist, they are coded using one bit each (0 and 1). +// 5. There is no way of sending zero distance codes--a dummy must be +// sent if there are none. (History: a pre 2.0 version of PKZIP would +// store blocks with no distance codes, but this was discovered to be +// too harsh a criterion.) Valid only for 1.93a. 2.04c does allow +// zero distance codes, which is sent as one code of zero bits in +// length. +// 6. There are up to 286 literal/length codes. Code 256 represents the +// end-of-block. Note however that the static length tree defines +// 288 codes just to fill out the Huffman codes. Codes 286 and 287 +// cannot be used though, since there is no length base or extra bits +// defined for them. Similarily, there are up to 30 distance codes. +// However, static trees define 32 codes (all 5 bits) to fill out the +// Huffman codes, but the last two had better not show up in the data. +// 7. Unzip can check dynamic Huffman blocks for complete code sets. +// The exception is that a single code would not be complete (see #4). +// 8. The five bits following the block type is really the number of +// literal codes sent minus 257. +// 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits +// (1+6+6). Therefore, to output three times the length, you output +// three codes (1+1+1), whereas to output four times the same length, +// you only need two codes (1+3). Hmm. +//10. In the tree reconstruction algorithm, Code = Code + Increment +// only if BitLength(i) is not zero. (Pretty obvious.) +//11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) +//12. Note: length code 284 can represent 227-258, but length code 285 +// really is 258. The last length deserves its own, short code +// since it gets used a lot in very redundant files. The length +// 258 is special since 258 - 3 (the min match length) is 255. +//13. The literal/length and distance code bit lengths are read as a +// single stream of lengths. It is possible (and advantageous) for +// a repeat code (16, 17, or 18) to go across the boundary between +// the two sets of lengths. + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == IBM_BTREE || s->mode == IBM_DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == IBM_CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = IBM_TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = IBM_TYPE; + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; // temporary storage + uLong b; // bit buffer + uInt k; // bits in bit buffer + Byte *p; // input data pointer + uInt n; // bytes available there + Byte *q; // output window write pointer + uInt m; // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + LOAD + + // process input based on current state + for(;;) switch (s->mode) + { + case IBM_TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: // stored + Tracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; // go to byte boundary + DUMPBITS(t) + s->mode = IBM_LENS; // get length of stored block + break; + case 1: // fixed + Tracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + const inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = IBM_CODES; + break; + case 2: // dynamic + Tracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = IBM_TABLE; + break; + case 3: // illegal + DUMPBITS(3) + s->mode = IBM_BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case IBM_LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = IBM_BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; // dump bits + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE); + break; + case IBM_STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + memcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? IBM_DRY : IBM_TYPE; + break; + case IBM_TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; + // remove this section to workaround bug in pkzip + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = IBM_BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } + // end remove + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = IBM_BTREE; + case IBM_BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = IBM_BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = IBM_DTREE; + case IBM_DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else // c == 16..18 + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = IBM_BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; // must be <= 9 for lookahead assumptions + bd = 6; // must be <= 9 for lookahead assumptions + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = IBM_BAD; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = IBM_CODES; + case IBM_CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = IBM_TYPE; + break; + } + s->mode = IBM_DRY; + case IBM_DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = IBM_DONE; + case IBM_DONE: + r = Z_STREAM_END; + LEAVE + case IBM_BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + + +// inftrees.c -- generate Huffman trees for efficient decoding +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h +// + + + +extern const char inflate_copyright_XUnzip[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +// If you use the zlib library in a product, an acknowledgment is welcome +// in the documentation of your product. If for some reason you cannot +// include such an acknowledgment, I would appreciate that you keep this +// copyright string in the executable of your product. + + + +int huft_build ( + uInt *, // code lengths in bits + uInt, // number of codes + uInt, // number of "simple" codes + const uInt *, // list of base values for non-simple codes + const uInt *, // list of extra bits for non-simple codes + inflate_huft **,// result: starting table + uInt *, // maximum lookup bits (returns actual) + inflate_huft *, // space for trees + uInt *, // hufts used in space + uInt * ); // space for values + +// Tables for deflate from PKZIP's appnote.txt. +const uInt cplens[31] = { // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + // see note #13 above about 258 +const uInt cplext[31] = { // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid +const uInt cpdist[30] = { // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +const uInt cpdext[30] = { // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +// +// Huffman code decoding is performed using a multi-level table lookup. +// The fastest way to decode is to simply build a lookup table whose +// size is determined by the longest code. However, the time it takes +// to build this table can also be a factor if the data being decoded +// is not very long. The most common codes are necessarily the +// shortest codes, so those codes dominate the decoding time, and hence +// the speed. The idea is you can have a shorter table that decodes the +// shorter, more probable codes, and then point to subsidiary tables for +// the longer codes. The time it costs to decode the longer codes is +// then traded against the time it takes to make longer tables. +// +// This results of this trade are in the variables lbits and dbits +// below. lbits is the number of bits the first level table for literal/ +// length codes can decode in one step, and dbits is the same thing for +// the distance codes. Subsequent tables are also less than or equal to +// those sizes. These values may be adjusted either when all of the +// codes are shorter than that, in which case the longest code length in +// bits is used, or when the shortest code is *longer* than the requested +// table size, in which case the length of the shortest code in bits is +// used. +// +// There are two different values for the two tables, since they code a +// different number of possibilities each. The literal/length table +// codes 286 possible values, or in a flat code, a little over eight +// bits. The distance table codes 30 possible values, or a little less +// than five bits, flat. The optimum values for speed end up being +// about one bit more than those, so lbits is 8+1 and dbits is 5+1. +// The optimum values may differ though from machine to machine, and +// possibly even between compilers. Your mileage may vary. +// + + +// If BMAX needs to be larger than 16, then h and x[] should be uLong. +#define BMAX 15 // maximum bit length of any code + +int huft_build( +uInt *b, // code lengths in bits (all assumed <= BMAX) +uInt n, // number of codes (assumed <= 288) +uInt s, // number of simple-valued codes (0..s-1) +const uInt *d, // list of base values for non-simple codes +const uInt *e, // list of extra bits for non-simple codes +inflate_huft * *t, // result: starting table +uInt *m, // maximum lookup bits, returns actual +inflate_huft *hp, // space for trees +uInt *hn, // hufts used in space +uInt *v) // working area: values in order of bit length +// Given a list of code lengths and a maximum table size, make a set of +// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR +// if the given code set is incomplete (the tables are still built in this +// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of +// lengths), or Z_MEM_ERROR if not enough memory. +{ + + uInt a; // counter for codes of length k + uInt c[BMAX+1]; // bit length count table + uInt f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + uInt i; // counter, current code + uInt j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + uInt mask; // (1 << w) - 1, to avoid cc -O bug on HP + uInt *p; // pointer into c[], b[], or v[] + inflate_huft *q; // points to current table + struct inflate_huft_s r; // table entry for structure assignment + inflate_huft *u[BMAX]; // table stack + int w; // bits before this table == (l * h) + uInt x[BMAX+1]; // bit offsets, then code stack + uInt *xp; // pointer into x + int y; // number of dummy codes added + uInt z; // number of entries in current table + + + // Generate counts for each bit length + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4; p; // clear c[]--assume BMAX+1 is 16 + p = b; i = n; + do { + c[*p++]++; // assume all entries <= BMAX + } while (--i); + if (c[0] == n) // null input--all zero length codes + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + // Find minimum and maximum length, bound *m by those + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; // minimum code length + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; // maximum code length + if ((uInt)l > i) + l = i; + *m = l; + + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { // note that i == g from above + *xp++ = (j += *p++); + } + + + // Make a table of values in order of bit lengths + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; // set n to length of v + + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = v; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy + q = (inflate_huft *)Z_NULL; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l) + { + h++; + w += l; // previous table always l bits + + // compute minimum size table less than or equal to l bits + z = g - w; + z = z > (uInt)l ? l : z; // table size upper limit + if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table + { // too few codes for k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = c + k; + if (j < z) + while (++j < z) // try smaller tables up to z bits + { + if ((f <<= 1) <= *++xp) + break; // enough codes to use up j bits + f -= *xp; // else deduct codes from patterns + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (*hn + z > MANY) // (note: doesn't matter for fixed) + return Z_MEM_ERROR; // not enough memory + u[h] = q = hp + *hn; + *hn += z; + + // connect to last table, if there is one + if (h) + { + x[h] = i; // save pattern for backing up + r.bits = (Byte)l; // bits to dump before this table + r.exop = (Byte)j; // bits in this table + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); // offset to this table + u[h-1][j] = r; // connect to last table + } + else + *t = q; // first table is returned result + } + + // set up table entry in r + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; // out of values--invalid code + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block + r.base = *p++; // simple code is just the value + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);// non-simple--look up in lists + r.base = d[*p++ - s]; + } + + // fill code-like entries with r + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + // backwards increment the k-bit code i + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]) + { + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + + + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits( +uInt *c, // 19 code lengths +uInt *bb, // bits tree desired/actual depth +inflate_huft * *tb, // bits tree result +inflate_huft *hp, // space for trees +z_streamp z) // for messages +{ + int r; + uInt hn = 0; // hufts used in space + uInt *v; // work area for huft_build + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic( +uInt nl, // number of literal/length codes +uInt nd, // number of distance codes +uInt *c, // that many (total) code lengths +uInt *bl, // literal desired/actual bit depth +uInt *bd, // distance desired/actual bit depth +inflate_huft * *tl, // literal/length tree result +inflate_huft * *td, // distance tree result +inflate_huft *hp, // space for trees +z_streamp z) // for messages +{ + int r; + uInt hn = 0; // hufts used in space + uInt *v; // work area for huft_build + + // allocate work area + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + // build literal/length tree + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + // build distance tree + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + // done + ZFREE(z, v); + return Z_OK; +} + + + + + +int inflate_trees_fixed( +uInt *bl, // literal desired/actual bit depth +uInt *bd, // distance desired/actual bit depth +const inflate_huft * * tl, // literal/length tree result +const inflate_huft * *td, // distance tree result +z_streamp ) // for memory allocation +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +// inffast.c -- process literals and length/distance pairs fast +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h +// + + +//struct inflate_codes_state {int dummy;}; // for buggy compilers + + +// macros for bit input with no checking and for returning unused bytes +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +// Called with number of bytes left to write in window at least 258 +// (the maximum string length) and number of input bytes available +// at least ten. The ten bytes are six bytes for the longest length/ +// distance pair plus four bytes for overloading the bit buffer. + +int inflate_fast( +uInt bl, uInt bd, +const inflate_huft *tl, +const inflate_huft *td, // need separate declaration for Borland C++ +inflate_blocks_statef *s, +z_streamp z) +{ + const inflate_huft *t; // temporary pointer + uInt e; // extra bits or operation + uLong b; // bit buffer + uInt k; // bits in bit buffer + Byte *p; // input data pointer + uInt n; // bytes available there + Byte *q; // output window write pointer + uInt m; // bytes to end of window or read pointer + uInt ml; // mask for literal/length tree + uInt md; // mask for distance tree + uInt c; // bytes to copy + uInt d; // distance back to copy from + Byte *r; // copy source pointer + + // load input, output, bit values + LOAD + + // initialize masks + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + // do until not enough input or output space for fast loop + do { // assume called with m >= 258 && n >= 10 + // get literal/length code + GRABBITS(20) // max bits for literal/length code + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + for (;;) { + DUMPBITS(t->bits) + if (e & 16) + { + // get extra bits for length + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + // decode distance base of block to copy + GRABBITS(15); // max bits for distance code + e = (t = td + ((uInt)b & md))->exop; + for (;;) { + DUMPBITS(t->bits) + if (e & 16) + { + // get extra bits to add to distance base + e &= 15; + GRABBITS(e) // get extra bits (up to 13) + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + // do the copy + m -= c; + if ((uInt)(q - s->window) >= d) // offset before dest + { // just copy + r = q - d; + *q++ = *r++; c--; // minimum count is three, + *q++ = *r++; c--; // so unroll loop a little + } + else // else offset after destination + { + e = d - (uInt)(q - s->window); // bytes from offset to end + r = s->end - e; // pointer to offset + if (c > e) // if source crosses, + { + c -= e; // copy to end of window + do { + *q++ = *r++; + } while (--e); + r = s->window; // copy rest from start of window + } + } + do { // copy all or what's left + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + }; + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + }; + } while (m >= 258 && n >= 10); + + // not enough input or output--restore pointers and return + UNGRAB + UPDATE + return Z_OK; +} + + + + + + +// crc32.c -- compute the CRC-32 of a data stream +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +// @(#) $Id$ + + + + + + +// Table of CRC-32's of all single-byte values (made by make_crc_table) +const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +const uLong * get_crc_table() +{ return (const uLong *)crc_table; +} + +#define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define CRC_DO2(buf) CRC_DO1(buf); CRC_DO1(buf); +#define CRC_DO4(buf) CRC_DO2(buf); CRC_DO2(buf); +#define CRC_DO8(buf) CRC_DO4(buf); CRC_DO4(buf); + +uLong ucrc32(uLong crc, const Byte *buf, uInt len) +{ if (buf == Z_NULL) return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) {CRC_DO8(buf); len -= 8;} + if (len) do {CRC_DO1(buf);} while (--len); + return crc ^ 0xffffffffL; +} + + +// adler32.c -- compute the Adler-32 checksum of a data stream +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +// @(#) $Id$ + + +#define BASE 65521L // largest prime smaller than 65536 +#define NMAX 5552 +// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + +#define AD_DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define AD_DO2(buf,i) AD_DO1(buf,i); AD_DO1(buf,i+1); +#define AD_DO4(buf,i) AD_DO2(buf,i); AD_DO2(buf,i+2); +#define AD_DO8(buf,i) AD_DO4(buf,i); AD_DO4(buf,i+4); +#define AD_DO16(buf) AD_DO8(buf,0); AD_DO8(buf,8); + +// ========================================================================= +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + AD_DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + + + +// zutil.c -- target dependent utility functions for the compression library +// Copyright (C) 1995-1998 Jean-loup Gailly. +// For conditions of distribution and use, see copyright notice in zlib.h +// @(#) $Id$ + + + + + + +const char * zlibVersion() +{ + return ZLIB_VERSION; +} + +// exported to allow conversion of error code to string for compress() and +// uncompress() +const char * zError(int err) +{ return ERR_MSG(err); +} + + + + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; // make compiler happy + return (voidpf)calloc(items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + zfree(ptr); + if (opaque) return; // make compiler happy +} + + + +// inflate.c -- zlib interface to inflate modules +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +//struct inflate_blocks_state {int dummy;}; // for buggy compilers + +typedef enum { + IM_METHOD, // waiting for method byte + IM_FLAG, // waiting for flag byte + IM_DICT4, // four dictionary check bytes to go + IM_DICT3, // three dictionary check bytes to go + IM_DICT2, // two dictionary check bytes to go + IM_DICT1, // one dictionary check byte to go + IM_DICT0, // waiting for inflateSetDictionary + IM_BLOCKS, // decompressing blocks + IM_CHECK4, // four check bytes to go + IM_CHECK3, // three check bytes to go + IM_CHECK2, // two check bytes to go + IM_CHECK1, // one check byte to go + IM_DONE, // finished check, done + IM_BAD} // got an error--stay here +inflate_mode; + +// inflate private state +struct internal_state { + + // mode + inflate_mode mode; // current inflate mode + + // mode dependent information + union { + uInt method; // if IM_FLAGS, method byte + struct { + uLong was; // computed check value + uLong need; // stream check value + } check; // if CHECK, check values to compare + uInt marker; // if IM_BAD, inflateSync's marker bytes count + } sub; // submode + + // mode independent information + int nowrap; // flag for no wrapper + uInt wbits; // log2(window size) (8..15, defaults to 15) + inflate_blocks_statef + *blocks; // current inflate_blocks state + +}; + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2(z_streamp z) +{ const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream); + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; + + int w = -15; // MAX_WBITS: 32K LZ77 window. + // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files created by gzip. + // The memory requirements for deflate are (in bytes): + // (1 << (windowBits+2)) + (1 << (memLevel+9)) + // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + // plus a few kilobytes for small objects. For example, if you want to reduce + // the default memory requirements from 256K to 128K, compile with + // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + // Of course this will generally degrade compression (there's no free lunch). + // + // The memory requirements for inflate are (in bytes) 1 << windowBits + // that is, 32K for windowBits=15 (default value) plus a few kilobytes + // for small objects. + + // initialize state + if (z == Z_NULL) return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + // handle undocumented nowrap option (no zlib header or check) + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + // set window size + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + // create inflate_blocks state + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev((stderr, "inflate: allocated\n")); + + // reset state + inflateReset(z); + return Z_OK; +} + + + +#define IM_NEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + for (;;) switch (z->state->mode) + { + case IM_METHOD: + IM_NEEDBYTE + if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = IM_BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = IM_BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + z->state->mode = IM_FLAG; + case IM_FLAG: + IM_NEEDBYTE + b = IM_NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = IM_BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = IM_BLOCKS; + break; + } + z->state->mode = IM_DICT4; + case IM_DICT4: + IM_NEEDBYTE + z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; + z->state->mode = IM_DICT3; + case IM_DICT3: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; + z->state->mode = IM_DICT2; + case IM_DICT2: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; + z->state->mode = IM_DICT1; + case IM_DICT1: + IM_NEEDBYTE; r; + z->state->sub.check.need += (uLong)IM_NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = IM_DICT0; + return Z_NEED_DICT; + case IM_DICT0: + z->state->mode = IM_BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case IM_BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = IM_BAD; + z->state->sub.marker = 0; // can try inflateSync + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = IM_DONE; + break; + } + z->state->mode = IM_CHECK4; + case IM_CHECK4: + IM_NEEDBYTE + z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; + z->state->mode = IM_CHECK3; + case IM_CHECK3: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; + z->state->mode = IM_CHECK2; + case IM_CHECK2: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; + z->state->mode = IM_CHECK1; + case IM_CHECK1: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = IM_BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + Tracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = IM_DONE; + case IM_DONE: + return Z_STREAM_END; + case IM_BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +} + + + +#ifdef _UNICODE + +static int GetAnsiFileName(LPCWSTR name, char * buf, int nBufSize) +{ + memset(buf, 0, nBufSize); + + int n = WideCharToMultiByte(CP_ACP, // code page + 0, // performance and mapping flags + name, // wide-character string + -1, // number of chars in string + buf, // buffer for new string + nBufSize, // size of buffer + NULL, // default for unmappable chars + NULL); // set when default char used + return n; +} + +static int GetUnicodeFileName(const char * name, LPWSTR buf, int nBufSize) +{ + memset(buf, 0, nBufSize*sizeof(TCHAR)); + + int n = MultiByteToWideChar(CP_ACP, // code page + 0, // character-type options + name, // string to map + -1, // number of bytes in string + buf, // wide-character buffer + nBufSize); // size of buffer + + return n; +} + +#endif + + +// unzip.c -- IO on .zip files using zlib +// Version 0.15 beta, Mar 19th, 1998, +// Read unzip.h for more info + + + + +#define UNZ_BUFSIZE (16384) +#define UNZ_MAXFILENAMEINZIP (256) +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = " unzip 0.15 Copyright 1998 Gilles Vollant "; + +// unz_file_info_interntal contain internal info about a file in zipfile +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;// relative offset of local header 4 bytes +} unz_file_info_internal; + + +typedef struct +{ bool is_handle; // either a handle or memory + bool canseek; + // for handles: + HANDLE h; bool herr; unsigned long initial_offset; + // for memory: + void *buf; unsigned int len,pos; // if it's a memory block +} LUFILE; + + +LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) +{ + if (flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) + { + *err=ZR_ARGS; + return NULL; + } + // + HANDLE h=0; bool canseek=false; *err=ZR_OK; + if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) + { + if (flags==ZIP_HANDLE) + { + HANDLE hf = z; + bool res; +#ifdef _WIN32 + res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS) == TRUE; +#else + h = (void*) dup( (int)hf ); + res = (int) dup >= 0; +#endif + if (!res) + { + *err=ZR_NODUPH; + return NULL; + } + } + else + { +#ifdef _WIN32 + h = CreateFile((const TCHAR *)z, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +#else + h = (void*) open( (const TCHAR *)z, O_RDONLY ); +#endif + if (h == INVALID_HANDLE_VALUE) + { + *err = ZR_NOFILE; + return NULL; + } + } +#ifdef _WIN32 + DWORD type = GetFileType(h); + canseek = (type==FILE_TYPE_DISK); +#else + struct stat buf; + fstat( (int)h, &buf ); + canseek = buf.st_mode & S_IFREG; +#endif + } + LUFILE *lf = new LUFILE; + if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) + { + lf->is_handle=true; + lf->canseek=canseek; + lf->h=h; lf->herr=false; + lf->initial_offset=0; + if (canseek) + { + lf->initial_offset = SetFilePointer(h,0,NULL,FILE_CURRENT); + } + } + else + { + lf->is_handle=false; + lf->canseek=true; + lf->buf=z; + lf->len=len; + lf->pos=0; + lf->initial_offset=0; + } + *err=ZR_OK; + return lf; +} + + +int lufclose(LUFILE *stream) +{ if (stream==NULL) return EOF; + if (stream->is_handle) CloseHandle(stream->h); + delete stream; + return 0; +} + +int luferror(LUFILE *stream) +{ if (stream->is_handle && stream->herr) return 1; + else return 0; +} + +long int luftell(LUFILE *stream) +{ if (stream->is_handle && stream->canseek) return SetFilePointer(stream->h,0,NULL,FILE_CURRENT)-stream->initial_offset; + else if (stream->is_handle) return 0; + else return stream->pos; +} + +int lufseek(LUFILE *stream, long offset, int whence) +{ if (stream->is_handle && stream->canseek) + { if (whence==SEEK_SET) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN); + else if (whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT); + else if (whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END); + else return 19; // EINVAL + return 0; + } + else if (stream->is_handle) return 29; // ESPIPE + else + { if (whence==SEEK_SET) stream->pos=offset; + else if (whence==SEEK_CUR) stream->pos+=offset; + else if (whence==SEEK_END) stream->pos=stream->len+offset; + return 0; + } +} + + +size_t lufread(void *ptr,size_t size,size_t n,LUFILE *stream) +{ unsigned int toread = (unsigned int)(size*n); + if (stream->is_handle) + { DWORD red; BOOL res = ReadFile(stream->h,ptr,toread,&red,NULL); + if (!res) stream->herr=true; + return red/size; + } + if (stream->pos+toread > stream->len) toread = stream->len-stream->pos; + memcpy(ptr, (char*)stream->buf + stream->pos, toread); DWORD red = toread; + stream->pos += red; + return red/size; +} + + + + +// file_in_zip_read_info_s contain internal information about a file in zipfile, +// when reading and decompress it +typedef struct +{ + char *read_buffer; // internal buffer for compressed data + z_stream stream; // zLib stream structure for inflate + + uLong pos_in_zipfile; // position in byte on the zipfile, for fseek + uLong stream_initialised; // flag set if stream structure is initialised + + uLong offset_local_extrafield;// offset of the local extra field + uInt size_local_extrafield;// size of the local extra field + uLong pos_local_extrafield; // position in the local extra field in read + + uLong crc32; // crc32 of all data uncompressed + uLong crc32_wait; // crc32 we must obtain after decompress all + uLong rest_read_compressed; // number of byte to be decompressed + uLong rest_read_uncompressed;//number of byte to be obtained after decomp + LUFILE* file; // io structore of the zipfile + uLong compression_method; // compression method (0==store) + uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) +} file_in_zip_read_info_s; + + +// unz_s contain internal information about the zipfile +typedef struct +{ + LUFILE* file; // io structore of the zipfile + unz_global_info gi; // public global information + uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) + uLong num_file; // number of the current file in the zipfile + uLong pos_in_central_dir; // pos of the current file in the central dir + uLong current_file_ok; // flag about the usability of the current file + uLong central_pos; // position of the beginning of the central dir + + uLong size_central_dir; // size of the central directory + uLong offset_central_dir; // offset of start of central directory with respect to the starting disk number + + unz_file_info cur_file_info; // public info about the current file in zip + unz_file_info_internal cur_file_info_internal; // private info about it + file_in_zip_read_info_s* pfile_in_zip_read; // structure about the current file if we are decompressing it +} unz_s, *unzFile; + + +int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity); +// Compare two filename (fileName1,fileName2). + +z_off_t unztell (unzFile file); +// Give the current position in uncompressed data + +int unzeof (unzFile file); +// return 1 if the end of file was reached, 0 elsewhere + +int unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len); +// Read extra field from the current file (opened by unzOpenCurrentFile) +// This is the local-header version of the extra field (sometimes, there is +// more info in the local-header version than in the central-header) +// +// if buf==NULL, it return the size of the local extra field +// +// if buf!=NULL, len is the size of the buffer, the extra header is copied in +// buf. +// the return value is the number of bytes copied in buf, or (if <0) +// the error code + + + +// =========================================================================== +// Read a byte from a gz_stream; update next_in and avail_in. Return EOF +// for end of file. +// IN assertion: the stream s has been sucessfully opened for reading. + +int unzlocal_getByte(LUFILE *fin,int *pi) +{ unsigned char c; + int err = (int)lufread(&c, 1, 1, fin); + if (err==1) + { *pi = (int)c; + return UNZ_OK; + } + else + { if (luferror(fin)) return UNZ_ERRNO; + else return UNZ_EOF; + } +} + + +// =========================================================================== +// Reads a long in LSB order from the given gz_stream. Sets +int unzlocal_getShort (LUFILE *fin,uLong *pX) +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +int unzlocal_getLong (LUFILE *fin,uLong *pX) +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +// My own strcmpi / strcasecmp +int strcmpcasenosensitive_internal (const char* fileName1,const char *fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= (char)0x20; + if ((c2>='a') && (c2<='z')) + c2 -= (char)0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + + + +// +// Compare two filename (fileName1,fileName2). +// If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) +// If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) +// +int unzStringFileNameCompare (const char*fileName1,const char*fileName2,int iCaseSensitivity) +{ if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); + else return strcmpcasenosensitive_internal(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + + +// Locate the Central directory of a zipfile (at the end, just before +// the global comment) +uLong unzlocal_SearchCentralDir(LUFILE *fin) +{ if (lufseek(fin,0,SEEK_END) != 0) return 0; + uLong uSizeFile = luftell(fin); + + uLong uMaxBack=0xffff; // maximum size of global comment + if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; + + unsigned char *buf = (unsigned char*)zmalloc(BUFREADCOMMENT+4); + if (buf==NULL) return 0; + uLong uPosFound=0; + + uLong uBackRead = 4; + while (uBackReaduMaxBack) uBackRead = uMaxBack; + else uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (lufseek(fin,uReadPos,SEEK_SET)!=0) break; + if (lufread(buf,(uInt)uReadSize,1,fin)!=1) break; + for (i=(int)uReadSize-3; (i--)>0;) + { if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { uPosFound = uReadPos+i; break; + } + } + if (uPosFound!=0) break; + } + if (buf) zfree(buf); + return uPosFound; +} + + +int unzGoToFirstFile (unzFile file); +int unzCloseCurrentFile (unzFile file); + +// Open a Zip file. +// If the zipfile cannot be opened (file don't exist or in not valid), return NULL. +// Otherwise, the return value is a unzFile Handle, usable with other unzip functions +unzFile unzOpenInternal(LUFILE *fin) +{ if (fin==NULL) return NULL; + if (unz_copyright[0]!=' ') {lufclose(fin); return NULL;} + + int err=UNZ_OK; + unz_s us; + uLong central_pos,uL; + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) err=UNZ_ERRNO; + if (lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO; + // the signature, already checked + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; + // number of this disk + uLong number_disk; // number of the current dist, used for spanning ZIP, unsupported, always 0 + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; + // number of the disk with the start of the central directory + uLong number_disk_with_CD; // number the the disk with central dir, used for spaning ZIP, unsupported, always 0 + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; + // total number of entries in the central dir on this disk + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; + // total number of entries in the central dir + uLong number_entry_CD; // total number of entries in the central dir (same than number_entry on nospan) + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; + if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; + // size of the central directory + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; + // offset of start of central directory with respect to the starting disk number + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; + // zipfile comment length + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; + if ((central_pos+fin->initial_offsetinitial_offset - (us.offset_central_dir+us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + fin->initial_offset = 0; // since the zipfile itself is expected to handle this + + unz_s *s = (unz_s*)zmalloc(sizeof(unz_s)); + *s=us; + unzGoToFirstFile((unzFile)s); + return (unzFile)s; +} + + + +// Close a ZipFile opened with unzipOpen. +// If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), +// these files MUST be closed with unzipCloseCurrentFile before call unzipClose. +// return UNZ_OK if there is no problem. +int unzClose (unzFile file) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + if (s->pfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + lufclose(s->file); + if (s) zfree(s); // unused s=0; + return UNZ_OK; +} + + +// Write info about the ZipFile in the *pglobal_info structure. +// No preparation of the structure is needed +// return UNZ_OK if there is no problem. +int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +// Translate date/time from Dos format to tm_unz (readable more easilty) +void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +// Get Info about the current file in the zipfile, with internal only info +int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize); + +int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, + unz_file_info_internal *pfile_info_internal, char *szFileName, + uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + // we check the magic + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (lufread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (lufread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + {} // unused lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (lufread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + //unused lSeek+=file_info.size_file_comment - uSizeRead; + } + else {} //unused lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +// Write info about the ZipFile in the *pglobal_info structure. +// No preparation of the structure is needed +// return UNZ_OK if there is no problem. +int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, szComment,commentBufferSize); +} + + +// Set the current file of the zipfile to the first file. +// return UNZ_OK if there is no problem +int unzGoToFirstFile (unzFile file) +{ + int err; + unz_s* s; + if (file==NULL) return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +// Set the current file of the zipfile to the next file. +// return UNZ_OK if there is no problem +// return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +// Try locate the file szFileName in the zipfile. +// For the iCaseSensitivity signification, see unzStringFileNameCompare +// return value : +// UNZ_OK if the file is found. It becomes the current file. +// UNZ_END_OF_LIST_OF_FILE if the file is not found +int unzLocateFile (unzFile file, const TCHAR *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + if (file==NULL) + return UNZ_PARAMERROR; + + if (_tcslen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + char szFileNameA[MAX_PATH]; + +#ifdef _UNICODE + GetAnsiFileName(szFileName, szFileNameA, MAX_PATH-1); +#else + strcpy(szFileNameA, szFileName); +#endif + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName,szFileNameA,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +// Read the local header of the current zipfile +// Check the coherency of the local header and info in the end of central +// directory about this file +// store in *piSizeVar the size of extra info in local header +// (filename and size of extra field data) +int unzlocal_CheckCurrentFileCoherencyHeader (unz_s *s,uInt *piSizeVar, + uLong *poffset_local_extrafield, uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +// else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) +// err=UNZ_BADZIPFILE; + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size compr + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + + + + + +// Open for reading data the current file in the zipfile. +// If there is no error and the file is opened, the return value is UNZ_OK. +int unzOpenCurrentFile (unzFile file) +{ + int err; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; // offset of the local extra field + uInt size_local_extrafield; // size of the local extra field + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*)zmalloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)zmalloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); //unused pfile_in_zip_read_info=0; + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) + { // unused err=UNZ_BADZIPFILE; + } + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + // windowBits is passed < 0 to tell that there is no zlib header. + // Note that in this case inflate *requires* an extra "dummy" byte + // after the compressed stream in order to complete decompression and + // return Z_STREAM_END. + // In unzip, i don't wait absolutely Z_STREAM_END because I known the + // size of both compressed and uncompressed data + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +// Read bytes from the current file. +// buf contain buffer where data must be copied +// len the size of buf. +// return the number of byte copied if somes bytes are copied +// return 0 if the end of file was reached +// return <0 with error code if there is an error +// (UNZ_ERRNO for IO error, or zLib error for uncompress error) +int unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ int err=UNZ_OK; + uInt iRead = 0; + + unz_s *s = (unz_s*)file; + if (s==NULL) return UNZ_PARAMERROR; + + file_in_zip_read_info_s* pfile_in_zip_read_info = s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; + if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; + if (len==0) return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + { pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + } + + while (pfile_in_zip_read_info->stream.avail_out>0) + { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) + { uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) return UNZ_EOF; + if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; + if (lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + pfile_in_zip_read_info->stream.next_in = (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) + { uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + } + else + { uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + } + for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); + } + pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,pfile_in_zip_read_info->stream.next_out,uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + err=inflate(&pfile_in_zip_read_info->stream,flush); + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,bufBefore,(uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) break; + } + } + + if (err==Z_OK) return iRead; + return err; +} + + +// Give the current position in uncompressed data +z_off_t unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +// return 1 if the end of file was reached, 0 elsewhere +int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +// Read extra field from the current file (opened by unzOpenCurrentFile) +// This is the local-header version of the extra field (sometimes, there is +// more info in the local-header version than in the central-header) +// if buf==NULL, it return the size of the local extra field that can be read +// if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. +// the return value is the number of bytes copied in buf, or (if <0) the error code +int unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (lufread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +// Close the file in zip opened with unzipOpenCurrentFile +// Return UNZ_CRCERROR if all the file was read but the CRC is not good +int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + if (pfile_in_zip_read_info->read_buffer!=0) + { void *buf = pfile_in_zip_read_info->read_buffer; + zfree(buf); + pfile_in_zip_read_info->read_buffer=0; + } + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; + + s->pfile_in_zip_read=NULL; + + return err; +} + + +// Get the global comment string of the ZipFile, in the szComment buffer. +// uSizeBuf is the size of the szComment buffer. +// return the number of byte copied or an error code <0 +int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ //int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) return UNZ_PARAMERROR; + s=(unz_s*)file; + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; + if (lufseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO; + if (uReadThis>0) + { *szComment='\0'; + if (lufread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO; + } + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + + + + + +int unzOpenCurrentFile (unzFile file); +int unzReadCurrentFile (unzFile file, void *buf, unsigned len); +int unzCloseCurrentFile (unzFile file); + + +#ifdef _WIN32 +FILETIME timet2filetime(const time_t timer) +{ struct tm *tm = gmtime(&timer); + SYSTEMTIME st; + st.wYear = (WORD)(tm->tm_year+1900); + st.wMonth = (WORD)(tm->tm_mon+1); + st.wDay = (WORD)(tm->tm_mday); + st.wHour = (WORD)(tm->tm_hour); + st.wMinute = (WORD)(tm->tm_min); + st.wSecond = (WORD)(tm->tm_sec); + st.wMilliseconds=0; + FILETIME ft; + SystemTimeToFileTime(&st,&ft); + return ft; +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +class TUnzip +{ public: + TUnzip() : uf(0), currentfile(-1), czei(-1) {} + + unzFile uf; int currentfile; ZIPENTRY cze; int czei; + TCHAR rootdir[MAX_PATH]; + + ZRESULT Open(void *z,unsigned int len,DWORD flags); + ZRESULT Get(int index,ZIPENTRY *ze); + ZRESULT Find(const TCHAR *name,bool ic,int *index,ZIPENTRY *ze); + ZRESULT Unzip(int index,void *dst,unsigned int len,DWORD flags); + ZRESULT Close(); +}; + + +ZRESULT TUnzip::Open(void *z,unsigned int len,DWORD flags) +{ + if (uf!=0 || currentfile!=-1) + return ZR_NOTINITED; +#ifdef _WIN32 + GetCurrentDirectory(MAX_PATH,rootdir); + _tcscat(rootdir,_T("\\")); + if (flags==ZIP_HANDLE) + { + DWORD type = GetFileType(z); + if (type!=FILE_TYPE_DISK) + return ZR_SEEK; + } +#endif + ZRESULT e; + LUFILE *f = lufopen(z,len,flags,&e); + if (f==NULL) + return e; + uf = unzOpenInternal(f); + return uf ? ZR_OK : ZR_CORRUPT; +} + +ZRESULT TUnzip::Get(int index,ZIPENTRY *ze) +{ if (index<-1 || index>=(int)uf->gi.number_entry) + return ZR_ARGS; + if (currentfile!=-1) + unzCloseCurrentFile(uf); + currentfile=-1; + if (index==czei && index!=-1) {memcpy(ze,&cze,sizeof(ZIPENTRY)); return ZR_OK;} + if (index==-1) + { ze->index = uf->gi.number_entry; + ze->name[0]=0; + ze->attr=0; +#ifdef _WIN32 + ze->atime.dwLowDateTime=0; ze->atime.dwHighDateTime=0; + ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0; + ze->mtime.dwLowDateTime=0; ze->mtime.dwHighDateTime=0; +#else + ze->atime = 0; + ze->ctime = 0; + ze->mtime = 0; +#endif + ze->comp_size=0; + ze->unc_size=0; + return ZR_OK; + } + if (index<(int)uf->num_file) unzGoToFirstFile(uf); + while ((int)uf->num_filefile,offset,SEEK_SET)!=0) return ZR_READ; + char *extra = new char[extralen]; + if (lufread(extra,1,(uInt)extralen,uf->file)!=extralen) {delete[] extra; return ZR_READ;} + // + ze->index=uf->num_file; + strcpy(ze->name,fn); + // zip has an 'attribute' 32bit value. Its lower half is windows stuff + // its upper half is standard unix attr. + unsigned long a = ufi.external_fa; + bool uisdir = (a&0x40000000)!=0; + //bool uwriteable= (a&0x08000000)!=0; + bool uwriteable= (a&0x00800000)!=0; // ***hd*** + //bool ureadable= (a&0x01000000)!=0; + //bool uexecutable=(a&0x00400000)!=0; + bool wreadonly= (a&0x00000001)!=0; + bool whidden= (a&0x00000002)!=0; + bool wsystem= (a&0x00000004)!=0; + bool wisdir= (a&0x00000010)!=0; + bool warchive= (a&0x00000020)!=0; + ze->attr=FILE_ATTRIBUTE_NORMAL; + if (uisdir || wisdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY; + if (warchive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE; + if (whidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN; + if (!uwriteable||wreadonly) ze->attr|=FILE_ATTRIBUTE_READONLY; + if (wsystem) ze->attr|=FILE_ATTRIBUTE_SYSTEM; + ze->comp_size = ufi.compressed_size; + ze->unc_size = ufi.uncompressed_size; + // +#ifdef _WIN32 + WORD dostime = (WORD)(ufi.dosDate&0xFFFF); + WORD dosdate = (WORD)((ufi.dosDate>>16)&0xFFFF); + FILETIME ft; + DosDateTimeToFileTime(dosdate,dostime,&ft); + ze->atime=ft; ze->ctime=ft; ze->mtime=ft; +#else + ze->atime=ufi.dosDate; ze->ctime=ufi.dosDate; ze->mtime=ufi.dosDate; +#endif + // the zip will always have at least that dostime. But if it also has + // an extra header, then we'll instead get the info from that. + unsigned int epos=0; + while (epos+4mtime = timet2filetime(mtime); +#else + ze->mtime = mtime; +#endif + } + if (hasatime) + { time_t atime = *(time_t*)(extra+epos); epos+=4; +#ifdef _WIN32 + ze->atime = timet2filetime(atime); +#else + ze->atime = atime; +#endif + } + if (hasctime) + { time_t ctime = *(time_t*)(extra+epos); +#ifdef _WIN32 + ze->ctime = timet2filetime(ctime); +#else + ze->ctime = ctime; +#endif + } + break; + } + // + if (extra!=0) delete[] extra; + memcpy(&cze,ze,sizeof(ZIPENTRY)); czei=index; + return ZR_OK; +} + +ZRESULT TUnzip::Find(const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) +{ + int res = unzLocateFile(uf,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE); + if (res!=UNZ_OK) + { + if (index!=0) + *index=-1; + if (ze!=NULL) + { + ZeroMemory(ze,sizeof(ZIPENTRY)); ze->index=-1; + } + return ZR_NOTFOUND; + } + if (currentfile!=-1) + unzCloseCurrentFile(uf); + currentfile=-1; + int i = (int)uf->num_file; + if (index!=NULL) + *index=i; + if (ze!=NULL) + { + ZRESULT zres = Get(i,ze); + if (zres!=ZR_OK) + return zres; + } + return ZR_OK; +} + +void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) +{ + if (dir==NULL || dir[0] == _T('\0')) + return; + + TCHAR cd[MAX_PATH]; + _tcscpy(cd,rootdir); + _tcscat(cd,dir); + for ( unsigned int iCD = 0; iCD < _tcslen( cd ); iCD++ ) + { + if ( cd[ iCD ] == _T( '/' ) || cd[ iCD ] == _T( '\\' ) ) + { + cd[ iCD ] = 0; + CreateDirectory(cd,NULL); + cd[ iCD ] = _T( '\\' ); + } + } + CreateDirectory(cd,NULL); +} + +ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) +{ + if (flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE) + return ZR_ARGS; + if (flags==ZIP_MEMORY) + { + if (index!=currentfile) + { + if (currentfile!=-1) + unzCloseCurrentFile(uf); + currentfile=-1; + if (index>=(int)uf->gi.number_entry) + return ZR_ARGS; + if (index<(int)uf->num_file) + unzGoToFirstFile(uf); + while ((int)uf->num_file0) + return ZR_MORE; + unzCloseCurrentFile(uf); + currentfile=-1; + if (res==0) + return ZR_OK; + else + return ZR_FLATE; + } + + // otherwise we're writing to a handle or a file + if (currentfile!=-1) + unzCloseCurrentFile(uf); + currentfile=-1; + if (index >= (int)uf->gi.number_entry) + return ZR_ARGS; + if (index < (int)uf->num_file) + unzGoToFirstFile(uf); + while ((int)uf->num_filelen) n=len-1; + memcpy(buf,msg,n); buf[n]=0; + return mlen; +} + + +typedef struct +{ DWORD flag; + TUnzip *unz; +} TUnzipHandleData; + +HZIP OpenZipU(void *z,unsigned int len,DWORD flags) +{ + TUnzip *unz = new TUnzip(); + lasterrorU = unz->Open(z,len,flags); + if (lasterrorU!=ZR_OK) + { + delete unz; + return 0; + } + TUnzipHandleData *han = new TUnzipHandleData; + han->flag=1; + han->unz=unz; + return (HZIP)han; +} + +ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze) +{ + if (hz==0) + { + lasterrorU=ZR_ARGS; + return ZR_ARGS; + } + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) + { + lasterrorU=ZR_ZMODE; + return ZR_ZMODE; + } + TUnzip *unz = han->unz; + lasterrorU = unz->Get(index,ze); + return lasterrorU; +} + +ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *zew) +{ + if (hz==0) + { + lasterrorU=ZR_ARGS; + return ZR_ARGS; + } + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) + { + lasterrorU=ZR_ZMODE; + return ZR_ZMODE; + } + TUnzip *unz = han->unz; + ZIPENTRY ze; + lasterrorU = unz->Get(index,&ze); + if (lasterrorU == ZR_OK) + { + zew->index = ze.index; + zew->attr = ze.attr; + zew->atime = ze.atime; + zew->ctime = ze.ctime; + zew->mtime = ze.mtime; + zew->comp_size = ze.comp_size; + zew->unc_size = ze.unc_size; +#ifdef _UNICODE + GetUnicodeFileName(ze.name, zew->name, MAX_PATH-1); +#else + strcpy(zew->name, ze.name); +#endif + } + return lasterrorU; +} + +ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) +{ + if (hz==0) + { + lasterrorU=ZR_ARGS; + return ZR_ARGS; + } + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) + { + lasterrorU=ZR_ZMODE; + return ZR_ZMODE; + } + TUnzip *unz = han->unz; + lasterrorU = unz->Find(name,ic,index,ze); + return lasterrorU; +} + +ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *zew) +{ + if (hz==0) + { + lasterrorU=ZR_ARGS; + return ZR_ARGS; + } + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) + { + lasterrorU=ZR_ZMODE; + return ZR_ZMODE; + } + TUnzip *unz = han->unz; + ZIPENTRY ze; + lasterrorU = unz->Find(name,ic,index,&ze); + if (lasterrorU == ZR_OK) + { + zew->index = ze.index; + zew->attr = ze.attr; + zew->atime = ze.atime; + zew->ctime = ze.ctime; + zew->mtime = ze.mtime; + zew->comp_size = ze.comp_size; + zew->unc_size = ze.unc_size; +#ifdef _UNICODE + GetUnicodeFileName(ze.name, zew->name, MAX_PATH-1); +#else + strcpy(zew->name, ze.name); +#endif + } + + return lasterrorU; +} + +ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags) +{ + if (hz==0) + { + lasterrorU=ZR_ARGS; + return ZR_ARGS; + } + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) + { + lasterrorU=ZR_ZMODE; + return ZR_ZMODE; + } + TUnzip *unz = han->unz; + lasterrorU = unz->Unzip(index,dst,len,flags); + return lasterrorU; +} + +ZRESULT CloseZipU(HZIP hz) +{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} + TUnzip *unz = han->unz; + lasterrorU = unz->Close(); + delete unz; + delete han; + return lasterrorU; +} + +bool IsZipHandleU(HZIP hz) +{ if (hz==0) return true; + TUnzipHandleData *han = (TUnzipHandleData*)hz; + return (han->flag==1); +} + +bool SafeUnzipMemory( const void *pvZipped, int cubZipped, void *pvDest, int cubDest /* should be the exact expected unzipped size */ ) +{ + // unzip + HZIP hZip = OpenZip( (void *)pvZipped, cubZipped, ZIP_MEMORY ); + + // UnzipItem is returning ZR_MORE no matter what size buffer is passed in, we know the real size so just accept + int iRes = ZR_CORRUPT; + if ( hZip ) + { + iRes = UnzipItem( hZip, 0, pvDest, cubDest, ZIP_MEMORY ); + CloseZip( hZip ); + } + + // check for failure + if ( ZR_OK != iRes && ZR_MORE != iRes ) + return false; + + return true; +} + diff --git a/public/XZip.cpp b/public/XZip.cpp new file mode 100644 index 0000000..2aab213 --- /dev/null +++ b/public/XZip.cpp @@ -0,0 +1,3034 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// XZip.cpp Version 1.1 +// +// Authors: Mark Adler et al. (see below) +// +// Modified by: Lucian Wischik +// lu@wischik.com +// +// Version 1.0 - Turned C files into just a single CPP file +// - Made them compile cleanly as C++ files +// - Gave them simpler APIs +// - Added the ability to zip/unzip directly in memory without +// any intermediate files +// +// Modified by: Hans Dietrich +// hdietrich2@hotmail.com +// +// Version 1.1: - Added Unicode support to CreateZip() and ZipAdd() +// - Changed file names to avoid conflicts with Lucian's files +// +/////////////////////////////////////////////////////////////////////////////// +// +// Lucian Wischik's comments: +// -------------------------- +// THIS FILE is almost entirely based upon code by Info-ZIP. +// It has been modified by Lucian Wischik. +// The original code may be found at http://www.info-zip.org +// The original copyright text follows. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Original authors' comments: +// --------------------------- +// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The +// definitive version of this document should be available at +// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. +// +// Copyright (c) 1990-2002 Info-ZIP. All rights reserved. +// +// For the purposes of this copyright and license, "Info-ZIP" is defined as +// the following set of individuals: +// +// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, +// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, +// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, +// David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, +// Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, +// Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler, +// Antoine Verheijen, Paul von Behren, Rich Wales, Mike White +// +// This software is provided "as is", without warranty of any kind, express +// or implied. In no event shall Info-ZIP or its contributors be held liable +// for any direct, indirect, incidental, special or consequential damages +// arising out of the use of or inability to use this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. Redistributions of source code must retain the above copyright notice, +// definition, disclaimer, and this list of conditions. +// +// 2. Redistributions in binary form (compiled executables) must reproduce +// the above copyright notice, definition, disclaimer, and this list of +// conditions in documentation and/or other materials provided with the +// distribution. The sole exception to this condition is redistribution +// of a standard UnZipSFX binary as part of a self-extracting archive; +// that is permitted without inclusion of this license, as long as the +// normal UnZipSFX banner has not been removed from the binary or disabled. +// +// 3. Altered versions--including, but not limited to, ports to new +// operating systems, existing ports with new graphical interfaces, and +// dynamic, shared, or static library versions--must be plainly marked +// as such and must not be misrepresented as being the original source. +// Such altered versions also must not be misrepresented as being +// Info-ZIP releases--including, but not limited to, labeling of the +// altered versions with the names "Info-ZIP" (or any variation thereof, +// including, but not limited to, different capitalizations), +// "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of +// Info-ZIP. Such altered versions are further prohibited from +// misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or +// of the Info-ZIP URL(s). +// +// 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip", +// "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its +// own source and binary releases. +// +/////////////////////////////////////////////////////////////////////////////// + +#if defined( WIN32) && !defined( _X360 ) +#define STRICT +#define WIN32_LEAN_AND_MEAN +#include +#elif !defined(_X360) +#define far +#define near +#define INVALID_HANDLE_VALUE (void*)-1 +#define _tzset tzset +#endif + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +#include +#include "zip/XZip.h" + +#ifdef __clang__ + // These clang 3.1 warnings don't seem very useful, and cannot easily be + // avoided in this file. + #pragma GCC diagnostic ignored "-Wdangling-else" // warning: add explicit braces to avoid dangling else [-Wdangling-else] +#endif + +#ifdef OSX +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifdef XZIP_NOT_THREAD_SAFE +static ZRESULT lasterrorZ=ZR_OK; +#else +#include "tier0/threadtools.h" +static CThreadLocalInt lasterrorZ; +#endif + +typedef unsigned char uch; // unsigned 8-bit value +typedef unsigned short ush; // unsigned 16-bit value +typedef unsigned long ulg; // unsigned 32-bit value +typedef size_t extent; // file size +typedef unsigned Pos; // must be at least 32 bits +typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing + +#ifndef EOF +#define EOF (-1) +#endif + + +// Error return values. The values 0..4 and 12..18 follow the conventions +// of PKZIP. The values 4..10 are all assigned to "insufficient memory" +// by PKZIP, so the codes 5..10 are used here for other purposes. +#define ZE_MISS -1 // used by procname(), zipbare() +#define ZE_OK 0 // success +#define ZE_EOF 2 // unexpected end of zip file +#define ZE_FORM 3 // zip file structure error +#define ZE_MEM 4 // out of memory +#define ZE_LOGIC 5 // internal logic error +#define ZE_BIG 6 // entry too large to split +#define ZE_NOTE 7 // invalid comment format +#define ZE_TEST 8 // zip test (-T) failed or out of memory +#define ZE_ABORT 9 // user interrupt or termination +#define ZE_TEMP 10 // error using a temp file +#define ZE_READ 11 // read or seek error +#define ZE_NONE 12 // nothing to do +#define ZE_NAME 13 // missing or empty zip file +#define ZE_WRITE 14 // error writing to a file +#define ZE_CREAT 15 // couldn't open to write +#define ZE_PARMS 16 // bad command line +#define ZE_OPEN 18 // could not open a specified file to read +#define ZE_MAXERR 18 // the highest error number + + +// internal file attribute +#define UNKNOWN (-1) +#define BINARY 0 +#define ASCII 1 + +#define BEST -1 // Use best method (deflation or store) +#define STORE 0 // Store method +#define DEFLATE 8 // Deflation method + +#define CRCVAL_INITIAL 0L + +// MSDOS file or directory attributes +#define MSDOS_HIDDEN_ATTR 0x02 +#define MSDOS_DIR_ATTR 0x10 + +// Lengths of headers after signatures in bytes +#define LOCHEAD 26 +#define CENHEAD 42 +#define ENDHEAD 18 + +// Definitions for extra field handling: +#define EB_HEADSIZE 4 /* length of a extra field block header */ +#define EB_LEN 2 /* offset of data length field in header */ +#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */ +#define EB_UT_FLAGS 0 /* byte offset of Flags field */ +#define EB_UT_TIME1 1 /* byte offset of 1st time value */ +#define EB_UT_FL_MTIME (1 << 0) /* mtime present */ +#define EB_UT_FL_ATIME (1 << 1) /* atime present */ +#define EB_UT_FL_CTIME (1 << 2) /* ctime present */ +#define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n)) +#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3)) +#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1)) + + +// Macros for writing machine integers to little-endian format +#define PUTSH(a,f) {char _putsh_c=(char)((a)&0xff); wfunc(param,&_putsh_c,1); _putsh_c=(char)((a)>>8); wfunc(param,&_putsh_c,1);} +#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))} + + +// -- Structure of a ZIP file -- +// Signatures for zip file information headers +#define LOCSIG 0x04034b50L +#define CENSIG 0x02014b50L +#define ENDSIG 0x06054b50L +#define EXTLOCSIG 0x08074b50L + + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +// The minimum and maximum match lengths + + +#define WSIZE (0x8000) +// Maximum window size = 32K. If you are really short of memory, compile +// with a smaller WSIZE but this reduces the compression ratio for files +// of size > WSIZE. WSIZE must be a power of two in the current implementation. +// + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +// Minimum amount of lookahead, except at the end of the input file. +// See deflate.c for comments about the MIN_MATCH+1. +// + +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) +// In order to simplify the code, particularly on 16 bit machines, match +// distances are limited to MAX_DIST instead of WSIZE. +// + + + + + +// =========================================================================== +// Constants +// + +#define MAX_BITS 15 +// All codes must not exceed MAX_BITS bits + +#define MAX_BL_BITS 7 +// Bit length codes must not exceed MAX_BL_BITS bits + +#define LENGTH_CODES 29 +// number of length codes, not counting the special END_BLOCK code + +#define LITERALS 256 +// number of literal bytes 0..255 + +#define END_BLOCK 256 +// end of block literal code + +#define L_CODES (LITERALS+1+LENGTH_CODES) +// number of Literal or Length codes, including the END_BLOCK code + +#define D_CODES 30 +// number of distance codes + +#define BL_CODES 19 +// number of codes used to transfer the bit lengths + + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +// The three kinds of block type + +#define LIT_BUFSIZE 0x8000 +#define DIST_BUFSIZE LIT_BUFSIZE +// Sizes of match buffers for literals/lengths and distances. There are +// 4 reasons for limiting LIT_BUFSIZE to 64K: +// - frequencies can be kept in 16 bit counters +// - if compression is not successful for the first block, all input data is +// still in the window so we can still emit a stored block even when input +// comes from standard input. (This can also be done for all blocks if +// LIT_BUFSIZE is not greater than 32K.) +// - if compression is not successful for a file smaller than 64K, we can +// even emit a stored file instead of a stored block (saving 5 bytes). +// - creating new Huffman trees less frequently may not provide fast +// adaptation to changes in the input data statistics. (Take for +// example a binary file with poorly compressible code followed by +// a highly compressible string table.) Smaller buffer sizes give +// fast adaptation but have of course the overhead of transmitting trees +// more frequently. +// - I can't count above 4 +// The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save +// memory at the expense of compression). Some optimizations would be possible +// if we rely on DIST_BUFSIZE == LIT_BUFSIZE. +// + +#define REP_3_6 16 +// repeat previous bit length 3-6 times (2 bits of repeat count) + +#define REPZ_3_10 17 +// repeat a zero length 3-10 times (3 bits of repeat count) + +#define REPZ_11_138 18 +// repeat a zero length 11-138 times (7 bits of repeat count) + +#define HEAP_SIZE (2*L_CODES+1) +// maximum heap size + + +// =========================================================================== +// Local data used by the "bit string" routines. +// + +#define Buf_size (8 * 2*sizeof(char)) +// Number of bits used within bi_buf. (bi_buf may be implemented on +// more than 16 bits on some systems.) + +// Output a 16 bit value to the bit stream, lower (oldest) byte first +#define PUTSHORT(state,w) \ +{ if (state.bs.out_offset >= state.bs.out_size-1) \ + state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ + /* flush may fail, so only write into the buffer if there's actually room (same below) */ \ + if (state.bs.out_offset < state.bs.out_size-1) { \ + state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \ + state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \ + } \ +} + +#define PUTBYTE(state,b) \ +{ if (state.bs.out_offset >= state.bs.out_size) \ + state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ + if (state.bs.out_offset < state.bs.out_size) \ + state.bs.out_buf[state.bs.out_offset++] = (char) (b); \ +} + +// DEFLATE.CPP HEADER + +#define HASH_BITS 15 +// For portability to 16 bit machines, do not use values above 15. + +#define HASH_SIZE (unsigned)(1<= HASH_BITS + +#define max_insert_length max_lazy_match +// Insert new strings in the hash table only if the match length +// is not greater than this length. This saves time but degrades compression. +// max_insert_length is used only for compression levels <= 3. + + + +const int extra_lbits[LENGTH_CODES] // extra bits for each length code + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +const int extra_dbits[D_CODES] // extra bits for each distance code + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +const int extra_blbits[BL_CODES]// extra bits for each bit length code + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +// The lengths of the bit length codes are sent in order of decreasing +// probability, to avoid transmitting the lengths for unused bit length codes. + + +typedef struct config { + ush good_length; // reduce lazy search above this match length + ush max_lazy; // do not perform lazy search above this match length + ush nice_length; // quit search above this match length + ush max_chain; +} config; + +// Values for max_lazy_match, good_match, nice_match and max_chain_length, +// depending on the desired pack level (0..9). The values given below have +// been tuned to exclude worst case performance for pathological files. +// Better values may be found for specific files. +// + +const config configuration_table[10] = { +// good lazy nice chain + {0, 0, 0, 0}, // 0 store only + {4, 4, 8, 4}, // 1 maximum speed, no lazy matches + {4, 5, 16, 8}, // 2 + {4, 6, 32, 32}, // 3 + {4, 4, 16, 16}, // 4 lazy matches */ + {8, 16, 32, 32}, // 5 + {8, 16, 128, 128}, // 6 + {8, 32, 128, 256}, // 7 + {32, 128, 258, 1024}, // 8 + {32, 258, 258, 4096}};// 9 maximum compression */ + +// Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 +// For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning. + + + + + +// Data structure describing a single value and its code string. +typedef struct ct_data { + union { + ush freq; // frequency count + ush code; // bit string + } fc; + union { + ush dad; // father node in Huffman tree + ush len; // length of bit string + } dl; +} ct_data; + +typedef struct tree_desc { + ct_data *dyn_tree; // the dynamic tree + ct_data *static_tree; // corresponding static tree or NULL + const int *extra_bits; // extra bits for each code or NULL + int extra_base; // base index for extra_bits + int elems; // max number of elements in the tree + int max_length; // max bit length for the codes + int max_code; // largest code with non zero frequency +} tree_desc; + + + + +class TTreeState +{ public: + TTreeState(); + + ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree + ct_data dyn_dtree[2*D_CODES+1]; // distance tree + ct_data static_ltree[L_CODES+2]; // the static literal tree... + // ... Since the bit lengths are imposed, there is no need for the L_CODES + // extra codes used during heap construction. However the codes 286 and 287 + // are needed to build a canonical tree (see ct_init below). + ct_data static_dtree[D_CODES]; // the static distance tree... + // ... (Actually a trivial tree since all codes use 5 bits.) + ct_data bl_tree[2*BL_CODES+1]; // Huffman tree for the bit lengths + + tree_desc l_desc; + tree_desc d_desc; + tree_desc bl_desc; + + ush bl_count[MAX_BITS+1]; // number of codes at each bit length for an optimal tree + + int heap[2*L_CODES+1]; // heap used to build the Huffman trees + int heap_len; // number of elements in the heap + int heap_max; // element of largest frequency + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + uch depth[2*L_CODES+1]; + // Depth of each subtree used as tie breaker for trees of equal frequency + + uch length_code[MAX_MATCH-MIN_MATCH+1]; + // length code for each normalized match length (0 == MIN_MATCH) + + uch dist_code[512]; + // distance codes. The first 256 values correspond to the distances + // 3 .. 258, the last 256 values correspond to the top 8 bits of + // the 15 bit distances. + + int base_length[LENGTH_CODES]; + // First normalized length for each code (0 = MIN_MATCH) + + int base_dist[D_CODES]; + // First normalized distance for each code (0 = distance of 1) + + uch far l_buf[LIT_BUFSIZE]; // buffer for literals/lengths + ush far d_buf[DIST_BUFSIZE]; // buffer for distances + + uch flag_buf[(LIT_BUFSIZE/8)]; + // flag_buf is a bit array distinguishing literals from lengths in + // l_buf, and thus indicating the presence or absence of a distance. + + unsigned last_lit; // running index in l_buf + unsigned last_dist; // running index in d_buf + unsigned last_flags; // running index in flag_buf + uch flags; // current flags not yet saved in flag_buf + uch flag_bit; // current bit used in flags + // bits are filled in flags starting at bit 0 (least significant). + // Note: these flags are overkill in the current code since we don't + // take advantage of DIST_BUFSIZE == LIT_BUFSIZE. + + ulg opt_len; // bit length of current block with optimal trees + ulg static_len; // bit length of current block with static trees + + ulg cmpr_bytelen; // total byte length of compressed file + ulg cmpr_len_bits; // number of bits past 'cmpr_bytelen' + + ulg input_len; // total byte length of input file + // input_len is for debugging only since we can get it by other means. + + ush *file_type; // pointer to UNKNOWN, BINARY or ASCII +// int *file_method; // pointer to DEFLATE or STORE +}; + +TTreeState::TTreeState() +{ tree_desc a = {dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0}; l_desc = a; + tree_desc b = {dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0}; d_desc = b; + tree_desc c = {bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0}; bl_desc = c; + last_lit=0; + last_dist=0; + last_flags=0; +} + + + +class TBitState +{ public: + + int flush_flg; + // + unsigned bi_buf; + // Output buffer. bits are inserted starting at the bottom (least significant + // bits). The width of bi_buf must be at least 16 bits. + int bi_valid; + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + char *out_buf; + // Current output buffer. + unsigned out_offset; + // Current offset in output buffer. + // On 16 bit machines, the buffer is limited to 64K. + unsigned out_size; + // Size of current output buffer + ulg bits_sent; // bit length of the compressed data only needed for debugging??? +}; + + + + + + + +class TDeflateState +{ public: + TDeflateState() {window_size=0;} + + uch window[2L*WSIZE]; + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least WSIZE + // bytes. With this organization, matches are limited to a distance of + // WSIZE-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. Also, it limits + // the window size to 64K, which is quite useful on MSDOS. + // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would + // be less efficient since the data would have to be copied WSIZE/CBSZ times) + Pos prev[WSIZE]; + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + Pos head[HASH_SIZE]; + // Heads of the hash chains or NIL. If your compiler thinks that + // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC. + + ulg window_size; + // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the + // input file length plus MIN_LOOKAHEAD. + + long block_start; + // window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + int sliding; + // Set to false when the input file is already in memory + + unsigned ins_h; // hash index of string to be inserted + + unsigned int prev_length; + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + + unsigned strstart; // start of string to insert + unsigned match_start; // start of matching string + int eofile; // flag set at end of input file + unsigned lookahead; // number of valid bytes ahead in window + + unsigned max_chain_length; + // To speed up deflation, hash chains are never searched beyond this length. + // A higher limit improves compression ratio but degrades the speed. + + unsigned int max_lazy_match; + // Attempt to find a better match only when the current match is strictly + // smaller than this value. This mechanism is used only for compression + // levels >= 4. + + unsigned good_match; + // Use a faster search when the previous match is longer than this + + int nice_match; // Stop searching when current match exceeds this +}; + + +typedef struct iztimes { + time_t atime,mtime,ctime; +} iztimes; // access, modify, create times + +typedef struct zlist { + ush vem, ver, flg, how; // See central header in zipfile.c for what vem..off are + ulg tim, crc, siz, len; + extent nam, ext, cext, com; // offset of ext must be >= LOCHEAD + ush dsk, att, lflg; // offset of lflg must be >= LOCHEAD + ulg atx, off; + char name[MAX_PATH]; // File name in zip file + char *extra; // Extra field (set only if ext != 0) + char *cextra; // Extra in central (set only if cext != 0) + char *comment; // Comment (set only if com != 0) + char iname[MAX_PATH]; // Internal file name after cleanup + char zname[MAX_PATH]; // External version of internal name + int mark; // Marker for files to operate on + int trash; // Marker for files to delete + int dosflag; // Set to force MSDOS file attributes + struct zlist far *nxt; // Pointer to next header in list +} TZipFileInfo; + + +class TState; +typedef unsigned (*READFUNC)(TState &state, char *buf,unsigned size); +typedef unsigned (*FLUSHFUNC)(void *param, const char *buf, unsigned *size); +typedef unsigned (*WRITEFUNC)(void *param, const char *buf, unsigned size); +class TState +{ public: TState() {err=0;} + // + void *param; + int level; bool seekable; + READFUNC readfunc; FLUSHFUNC flush_outbuf; + TTreeState ts; TBitState bs; TDeflateState ds; + const char *err; +}; + + + + + + + + +#undef Assert +void Assert(TState &state,bool cond, const char *msg) +{ if (cond) return; + state.err=msg; +} +void __cdecl Trace(const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} +void __cdecl Tracec(bool ,const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} + + + +// =========================================================================== +// Local (static) routines in this file. +// + +void init_block (TState &); +void pqdownheap (TState &,ct_data *tree, int k); +void gen_bitlen (TState &,tree_desc *desc); +void gen_codes (TState &state,ct_data *tree, int max_code); +void build_tree (TState &,tree_desc *desc); +void scan_tree (TState &,ct_data *tree, int max_code); +void send_tree (TState &state,ct_data *tree, int max_code); +int build_bl_tree (TState &); +void send_all_trees (TState &state,int lcodes, int dcodes, int blcodes); +void compress_block (TState &state,ct_data *ltree, ct_data *dtree); +void set_file_type (TState &); +void send_bits (TState &state, int value, int length); +unsigned bi_reverse (unsigned code, int len); +void bi_windup (TState &state); +void copy_block (TState &state,char *buf, unsigned len, int header); + + +#define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len) +// Send a code of the given tree. c and tree must not have side effects + +// alternatively... +//#define send_code(state, c, tree) +// { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c)); +// send_bits(state, tree[c].fc.code, tree[c].dl.len); } + +#define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)]) +// Mapping from a distance to a distance code. dist is the distance - 1 and +// must not have side effects. dist_code[256] and dist_code[257] are never used. + +#define Max(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Allocate the match buffer, initialize the various tables and save the + * location of the internal file attribute (ascii/binary) and method + * (DEFLATE/STORE). + */ +void ct_init(TState &state, ush *attr) +{ + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + + state.ts.file_type = attr; + //state.ts.file_method = method; + state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L; + state.ts.input_len = 0L; + + if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + state.ts.base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + state.ts.base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + state.ts.base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + state.ts.dist_code[256 + dist++] = (uch)code; + } + } + Assert(state,dist == 256, "ct_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; + n = 0; + while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; + while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++; + while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++; + while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; + /* fc.codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(state,(ct_data *)state.ts.static_ltree, L_CODES+1); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + state.ts.static_dtree[n].dl.len = 5; + state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5); + } + + /* Initialize the first block of the first file: */ + init_block(state); +} + +/* =========================================================================== + * Initialize a new block. + */ +void init_block(TState &state) +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) state.ts.dyn_ltree[n].fc.freq = 0; + for (n = 0; n < D_CODES; n++) state.ts.dyn_dtree[n].fc.freq = 0; + for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0; + + state.ts.dyn_ltree[END_BLOCK].fc.freq = 1; + state.ts.opt_len = state.ts.static_len = 0L; + state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0; + state.ts.flags = 0; state.ts.flag_bit = 1; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(tree, top) \ +{\ + top = state.ts.heap[SMALLEST]; \ + state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \ + pqdownheap(state,tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m) \ + (tree[n].fc.freq < tree[m].fc.freq || \ + (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +void pqdownheap(TState &state,ct_data *tree, int k) +{ + int v = state.ts.heap[k]; + int j = k << 1; /* left son of k */ + int htemp; /* required because of bug in SASC compiler */ + + while (j <= state.ts.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j+1], state.ts.heap[j])) j++; + + /* Exit if v is smaller than both sons */ + htemp = state.ts.heap[j]; + if (smaller(tree, v, htemp)) break; + + /* Exchange v with the smallest son */ + state.ts.heap[k] = htemp; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + state.ts.heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +void gen_bitlen(TState &state,tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + const int *extra = desc->extra_bits; + int base = desc->extra_base; + int max_code = desc->max_code; + int max_length = desc->max_length; + ct_data *stree = desc->static_tree; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */ + + for (h = state.ts.heap_max+1; h < HEAP_SIZE; h++) { + n = state.ts.heap[h]; + bits = tree[tree[n].dl.dad].dl.len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].dl.len = (ush)bits; + /* We overwrite tree[n].dl.dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + state.ts.bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].fc.freq; + state.ts.opt_len += (ulg)f * (bits + xbits); + if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits); + } + if (overflow == 0) return; + + Trace("\nbit length overflow\n"); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (state.ts.bl_count[bits] == 0) bits--; + state.ts.bl_count[bits]--; /* move one leaf down the tree */ + state.ts.bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */ + state.ts.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = state.ts.bl_count[bits]; + while (n != 0) { + m = state.ts.heap[--h]; + if (m > max_code) continue; + if (tree[m].dl.len != (ush)bits) { + Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits); + state.ts.opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq; + tree[m].dl.len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +void gen_codes (TState &state, ct_data *tree, int max_code) +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (ush)((code + state.ts.bl_count[bits-1]) << 1); + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert(state,code + state.ts.bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1, + "inconsistent bit counts"); + Trace("\ngen_codes: max_code %d ", max_code); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].dl.len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len); + + //Tracec(tree != state.ts.static_ltree, "\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].fc.code, next_code[len]-1); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +void build_tree(TState &state,tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + ct_data *stree = desc->static_tree; + int elems = desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node = elems; /* next internal node of the tree */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].fc.freq != 0) { + state.ts.heap[++state.ts.heap_len] = max_code = n; + state.ts.depth[n] = 0; + } else { + tree[n].dl.len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (state.ts.heap_len < 2) { + int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[newcp].fc.freq = 1; + state.ts.depth[newcp] = 0; + state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len; + /* new is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = state.ts.heap_len/2; n >= 1; n--) pqdownheap(state,tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + do { + pqremove(tree, n); /* n = node of least frequency */ + m = state.ts.heap[SMALLEST]; /* m = node of next least frequency */ + + state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */ + state.ts.heap[--state.ts.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq); + state.ts.depth[node] = (uch) (Max(state.ts.depth[n], state.ts.depth[m]) + 1); + tree[n].dl.dad = tree[m].dl.dad = (ush)node; + /* and insert the new node in the heap */ + state.ts.heap[SMALLEST] = node++; + pqdownheap(state,tree, SMALLEST); + + } while (state.ts.heap_len >= 2); + + state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(state,(tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes (state,(ct_data *)tree, max_code); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. Updates opt_len to take into account the repeat + * counts. (The contribution of the bit length codes will be added later + * during the construction of bl_tree.) + */ +void scan_tree (TState &state,ct_data *tree, int max_code) +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].dl.len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].dl.len = (ush)-1; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].dl.len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count); + } else if (curlen != 0) { + if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++; + state.ts.bl_tree[REP_3_6].fc.freq++; + } else if (count <= 10) { + state.ts.bl_tree[REPZ_3_10].fc.freq++; + } else { + state.ts.bl_tree[REPZ_11_138].fc.freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +void send_tree (TState &state, ct_data *tree, int max_code) +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].dl.len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].dl.len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].dl.len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(state, curlen, state.ts.bl_tree); count--; + } + Assert(state,count >= 3 && count <= 6, " 3_6?"); + send_code(state,REP_3_6, state.ts.bl_tree); send_bits(state,count-3, 2); + + } else if (count <= 10) { + send_code(state,REPZ_3_10, state.ts.bl_tree); send_bits(state,count-3, 3); + + } else { + send_code(state,REPZ_11_138, state.ts.bl_tree); send_bits(state,count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +int build_bl_tree(TState &state) +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(state,(ct_data *)state.ts.dyn_ltree, state.ts.l_desc.max_code); + scan_tree(state,(ct_data *)state.ts.dyn_dtree, state.ts.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(state,(tree_desc *)(&state.ts.bl_desc)); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + state.ts.opt_len += 3*(max_blindex+1) + 5+5+4; + Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +void send_all_trees(TState &state,int lcodes, int dcodes, int blcodes) +{ + int rank; /* index in bl_order */ + + Assert(state,lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert(state,lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Trace("\nbl counts: "); + send_bits(state,lcodes-257, 5); + /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */ + send_bits(state,dcodes-1, 5); + send_bits(state,blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Trace("\nbl code %2d ", bl_order[rank]); + send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3); + } + Trace("\nbl tree: sent %ld", state.bs.bits_sent); + + send_tree(state,(ct_data *)state.ts.dyn_ltree, lcodes-1); /* send the literal tree */ + Trace("\nlit tree: sent %ld", state.bs.bits_sent); + + send_tree(state,(ct_data *)state.ts.dyn_dtree, dcodes-1); /* send the distance tree */ + Trace("\ndist tree: sent %ld", state.bs.bits_sent); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length (in bytes) for the file so far. + */ +ulg flush_block(TState &state,char *buf, ulg stored_len, int eof) +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex; /* index of last bit length code of non zero freq */ + + state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */ + + /* Check if the file is ascii or binary */ + if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state); + + /* Construct the literal and distance trees */ + build_tree(state,(tree_desc *)(&state.ts.l_desc)); + Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); + + build_tree(state,(tree_desc *)(&state.ts.d_desc)); + Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(state); + + /* Determine the best encoding. Compute first the block length in bytes */ + opt_lenb = (state.ts.opt_len+3+7)>>3; + static_lenb = (state.ts.static_len+3+7)>>3; + state.ts.input_len += stored_len; /* for debugging only */ + + Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", + opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len, + state.ts.last_lit, state.ts.last_dist); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + // Originally, zip allowed the file to be transformed from a compressed + // into a stored file in the case where compression failed, there + // was only one block, and it was allowed to change. I've removed this + // possibility since the code's cleaner if no changes are allowed. + //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L + // && state.ts.cmpr_len_bits == 0L && state.seekable) + //{ // && state.ts.file_method != NULL + // // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: + // Assert(state,buf!=NULL,"block vanished"); + // copy_block(state,buf, (unsigned)stored_len, 0); // without header + // state.ts.cmpr_bytelen = stored_len; + // Assert(state,false,"unimplemented *state.ts.file_method = STORE;"); + // //*state.ts.file_method = STORE; + //} + //else + if (stored_len+4 <= opt_lenb && buf != (char*)NULL) { + /* 4: two words for the lengths */ + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + send_bits(state,(STORED_BLOCK<<1)+eof, 3); /* send block type */ + state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4; + state.ts.cmpr_len_bits = 0L; + + copy_block(state,buf, (unsigned)stored_len, 1); /* with header */ + } + else if (static_lenb == opt_lenb) { + send_bits(state,(STATIC_TREES<<1)+eof, 3); + compress_block(state,(ct_data *)state.ts.static_ltree, (ct_data *)state.ts.static_dtree); + state.ts.cmpr_len_bits += 3 + state.ts.static_len; + state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; + state.ts.cmpr_len_bits &= 7L; + } + else { + send_bits(state,(DYN_TREES<<1)+eof, 3); + send_all_trees(state,state.ts.l_desc.max_code+1, state.ts.d_desc.max_code+1, max_blindex+1); + compress_block(state,(ct_data *)state.ts.dyn_ltree, (ct_data *)state.ts.dyn_dtree); + state.ts.cmpr_len_bits += 3 + state.ts.opt_len; + state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; + state.ts.cmpr_len_bits &= 7L; + } + Assert(state,((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size"); + init_block(state); + + if (eof) { + // Assert(state,input_len == isize, "bad input size"); + bi_windup(state); + state.ts.cmpr_len_bits += 7; /* align on byte boundary */ + } + Trace("\n"); + + return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ct_tally (TState &state,int dist, int lc) +{ + state.ts.l_buf[state.ts.last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + state.ts.dyn_ltree[lc].fc.freq++; + } else { + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert(state,(ush)dist < (ush)MAX_DIST && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match"); + + state.ts.dyn_ltree[state.ts.length_code[lc]+LITERALS+1].fc.freq++; + state.ts.dyn_dtree[d_code(dist)].fc.freq++; + + state.ts.d_buf[state.ts.last_dist++] = (ush)dist; + state.ts.flags |= state.ts.flag_bit; + } + state.ts.flag_bit <<= 1; + + /* Output the flags if they fill a byte: */ + if ((state.ts.last_lit & 7) == 0) { + state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags; + state.ts.flags = 0, state.ts.flag_bit = 1; + } + /* Try to guess if it is profitable to stop the current block here */ + if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)state.ts.last_lit*8L; + ulg in_length = (ulg)state.ds.strstart-state.ds.block_start; + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq*(5L+extra_dbits[dcode]); + } + out_length >>= 3; + Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", + state.ts.last_lit, state.ts.last_dist, in_length, out_length, + 100L - out_length*100L/in_length); + if (state.ts.last_dist < state.ts.last_lit/2 && out_length < in_length/2) return 1; + } + return (state.ts.last_lit == LIT_BUFSIZE-1 || state.ts.last_dist == DIST_BUFSIZE); + /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +void compress_block(TState &state,ct_data *ltree, ct_data *dtree) +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned dx = 0; /* running index in d_buf */ + unsigned fx = 0; /* running index in flag_buf */ + uch flag = 0; /* current flags */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (state.ts.last_lit != 0) do { + if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++]; + lc = state.ts.l_buf[lx++]; + if ((flag & 1) == 0) { + send_code(state,lc, ltree); /* send a literal byte */ + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = state.ts.length_code[lc]; + send_code(state,code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= state.ts.base_length[code]; + send_bits(state,lc, extra); /* send the extra length bits */ + } + dist = state.ts.d_buf[dx++]; + /* Here, dist is the match distance - 1 */ + code = d_code(dist); + Assert(state,code < D_CODES, "bad d_code"); + + send_code(state,code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= state.ts.base_dist[code]; + send_bits(state,dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + flag >>= 1; + } while (lx < state.ts.last_lit); + + send_code(state,END_BLOCK, ltree); +} + +/* =========================================================================== + * Set the file type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +void set_file_type(TState &state) +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += state.ts.dyn_ltree[n++].fc.freq; + while (n < 128) ascii_freq += state.ts.dyn_ltree[n++].fc.freq; + while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq; + *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); +} + + +/* =========================================================================== + * Initialize the bit string routines. + */ +void bi_init (TState &state,char *tgt_buf, unsigned tgt_size, int flsh_allowed) +{ + state.bs.out_buf = tgt_buf; + state.bs.out_size = tgt_size; + state.bs.out_offset = 0; + state.bs.flush_flg = flsh_allowed; + + state.bs.bi_buf = 0; + state.bs.bi_valid = 0; + state.bs.bits_sent = 0L; +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +void send_bits(TState &state,int value, int length) +{ + Assert(state,length > 0 && length <= 15, "invalid length"); + state.bs.bits_sent += (ulg)length; + /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and + * (Buf_size - bi_valid) bits from value to flush the filled bi_buf, + * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid)) + * unused bits in bi_buf. + */ + state.bs.bi_buf |= (value << state.bs.bi_valid); + state.bs.bi_valid += length; + if (state.bs.bi_valid > (int)Buf_size) { + PUTSHORT(state,state.bs.bi_buf); + state.bs.bi_valid -= Buf_size; + state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid); + } +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +unsigned bi_reverse(unsigned code, int len) +{ + unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Write out any remaining bits in an incomplete byte. + */ +void bi_windup(TState &state) +{ + if (state.bs.bi_valid > 8) { + PUTSHORT(state,state.bs.bi_buf); + } else if (state.bs.bi_valid > 0) { + PUTBYTE(state,state.bs.bi_buf); + } + if (state.bs.flush_flg) { + state.flush_outbuf(state.param, state.bs.out_buf, &state.bs.out_offset); + } + state.bs.bi_buf = 0; + state.bs.bi_valid = 0; + state.bs.bits_sent = (state.bs.bits_sent+7) & ~7; +} + +/* =========================================================================== + * Copy a stored block to the zip file, storing first the length and its + * one's complement if requested. + */ +void copy_block(TState &state, char *block, unsigned len, int header) +{ + bi_windup(state); /* align on byte boundary */ + + if (header) { + PUTSHORT(state,(ush)len); + PUTSHORT(state,(ush)~len); + state.bs.bits_sent += 2*16; + } + if (state.bs.flush_flg) { + state.flush_outbuf(state.param, state.bs.out_buf, &state.bs.out_offset); + state.bs.out_offset = len; + state.flush_outbuf(state.param, block, &state.bs.out_offset); + } else if (state.bs.out_offset + len > state.bs.out_size) { + Assert(state,false,"output buffer too small for in-memory compression"); + } else { + memcpy(state.bs.out_buf + state.bs.out_offset, block, len); + state.bs.out_offset += len; + } + state.bs.bits_sent += (ulg)len<<3; +} + + + + + + + + +/* =========================================================================== + * Prototypes for functions. + */ + +void fill_window (TState &state); +ulg deflate_fast (TState &state); + +int longest_match (TState &state,IPos cur_match); + + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(h,c) (h = (((h)< 0 if the input file is already read or + * mmap'ed in the window[] array, 0 otherwise. In the first case, + * window_size is sufficient to contain the whole input file plus + * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end + * of window[] when looking for matches towards the end). + */ +void lm_init (TState &state, int pack_level, ush *flags) +{ + unsigned j; + + Assert(state,pack_level>=1 && pack_level<=8,"bad pack level"); + + /* Do not slide the window if the whole input is already in memory + * (window_size > 0) + */ + state.ds.sliding = 0; + if (state.ds.window_size == 0L) { + state.ds.sliding = 1; + state.ds.window_size = (ulg)2L*WSIZE; + } + + /* Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ + state.ds.head[HASH_SIZE-1] = NIL; + memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*state.ds.head)); + + /* Set the default configuration parameters: + */ + state.ds.max_lazy_match = configuration_table[pack_level].max_lazy; + state.ds.good_match = configuration_table[pack_level].good_length; + state.ds.nice_match = configuration_table[pack_level].nice_length; + state.ds.max_chain_length = configuration_table[pack_level].max_chain; + if (pack_level <= 2) { + *flags |= FAST; + } else if (pack_level >= 8) { + *flags |= SLOW; + } + /* ??? reduce max_chain_length for binary files */ + + state.ds.strstart = 0; + state.ds.block_start = 0L; + + j = WSIZE; + j <<= 1; // Can read 64K in one step + state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j); + + if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) { + state.ds.eofile = 1, state.ds.lookahead = 0; + return; + } + state.ds.eofile = 0; + /* Make sure that we always have enough lookahead. This is important + * if input comes from a device such as a tty. + */ + if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); + + state.ds.ins_h = 0; + for (j=0; j= 1 + */ +// For 80x86 and 680x0 and ARM, an optimized version is in match.asm or +// match.S. The code is functionally equivalent, so you can use the C version +// if desired. Which I do so desire! +int longest_match(TState &state,IPos cur_match) +{ + unsigned chain_length = state.ds.max_chain_length; /* max hash chain length */ + uch far *scan = state.ds.window + state.ds.strstart; /* current string */ + uch far *match; /* matched string */ + int len; /* length of current match */ + int best_len = state.ds.prev_length; /* best match length so far */ + IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + Assert(state,HASH_BITS>=8 && MAX_MATCH==258,"Code too clever"); + + + + uch far *strend = state.ds.window + state.ds.strstart + MAX_MATCH; + uch scan_end1 = scan[best_len-1]; + uch scan_end = scan[best_len]; + + /* Do not waste too much time if we already have a good match: */ + if (state.ds.prev_length >= state.ds.good_match) { + chain_length >>= 2; + } + + Assert(state,state.ds.strstart <= state.ds.window_size-MIN_LOOKAHEAD, "insufficient lookahead"); + + do { + Assert(state,cur_match < state.ds.strstart, "no future"); + match = state.ds.window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(state,scan <= state.ds.window+(unsigned)(state.ds.window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + + + if (len > best_len) { + state.ds.match_start = cur_match; + best_len = len; + if (len >= state.ds.nice_match) break; + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; + } + } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit + && --chain_length != 0); + + return best_len; +} + + + +#define check_match(state,start, match, length) +// or alternatively... +//void check_match(TState &state,IPos start, IPos match, int length) +//{ // check that the match is indeed a match +// if (memcmp((char*)state.ds.window + match, +// (char*)state.ds.window + start, length) != EQUAL) { +// fprintf(stderr, +// " start %d, match %d, length %d\n", +// start, match, length); +// error("invalid match"); +// } +// if (state.verbose > 1) { +// fprintf(stderr,"\\[%d,%d]", start-match, length); +// do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0); +// } +//} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead, and sets eofile if end of input file. + * + * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or eofile is set; file reads are + * performed for at least two bytes (required for the translate_eol option). + */ +void fill_window(TState &state) +{ + unsigned n, m; + unsigned more; /* Amount of free space at the end of the window. */ + + do { + more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart); + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (more == (unsigned)EOF) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* For MMAP or BIG_MEM, the whole input file is already in memory so + * we must not perform sliding. We must however call (*read_buf)() in + * order to compute the crc, update lookahead and possibly set eofile. + */ + } else if (state.ds.strstart >= WSIZE+MAX_DIST && state.ds.sliding) { + + /* By the IN assertion, the window is not empty so we can't confuse + * more == 0 with more == 64K on a 16 bit machine. + */ + memcpy((char*)state.ds.window, (char*)state.ds.window+WSIZE, (unsigned)WSIZE); + state.ds.match_start -= WSIZE; + state.ds.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ + + state.ds.block_start -= (long) WSIZE; + + for (n = 0; n < HASH_SIZE; n++) { + m = state.ds.head[n]; + state.ds.head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); + } + for (n = 0; n < WSIZE; n++) { + m = state.ds.prev[n]; + state.ds.prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } + more += WSIZE; + } + if (state.ds.eofile) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the MMAP or BIG_MEM case (not yet supported in gzip), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(state,more >= 2, "more < 2"); + + n = state.readfunc(state, (char*)state.ds.window+state.ds.strstart+state.ds.lookahead, more); + + if (n == 0 || n == (unsigned)EOF) { + state.ds.eofile = 1; + } else { + state.ds.lookahead += n; + } + } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK(state,eof) \ + flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \ + (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof)) + +/* =========================================================================== + * Processes a new input file and return its compressed length. This + * function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +ulg deflate_fast(TState &state) +{ + IPos hash_head = NIL; /* head of the hash chain */ + int flush; /* set if current block must be flushed */ + unsigned match_length = 0; /* length of best match */ + + state.ds.prev_length = MIN_MATCH-1; + while (state.ds.lookahead != 0) { + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (state.ds.lookahead >= MIN_MATCH) + INSERT_STRING(state.ds.strstart, hash_head); + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + /* Do not look for matches beyond the end of the input. + * This is necessary to make deflate deterministic. + */ + if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; + match_length = longest_match (state,hash_head); + /* longest_match() sets match_start */ + if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; + } + if (match_length >= MIN_MATCH) { + check_match(state,state.ds.strstart, state.ds.match_start, match_length); + + flush = ct_tally(state,state.ds.strstart-state.ds.match_start, match_length - MIN_MATCH); + + state.ds.lookahead -= match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (match_length <= state.ds.max_insert_length + && state.ds.lookahead >= MIN_MATCH) { + match_length--; /* string at strstart already in hash table */ + do { + state.ds.strstart++; + INSERT_STRING(state.ds.strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--match_length != 0); + state.ds.strstart++; + } else { + state.ds.strstart += match_length; + match_length = 0; + state.ds.ins_h = state.ds.window[state.ds.strstart]; + UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart+1]); + Assert(state,MIN_MATCH==3,"Call UPDATE_HASH() MIN_MATCH-3 more times"); + } + } else { + /* No match, output a literal byte */ + flush = ct_tally (state,0, state.ds.window[state.ds.strstart]); + state.ds.lookahead--; + state.ds.strstart++; + } + if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); + } + return FLUSH_BLOCK(state,1); /* eof */ +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +ulg deflate(TState &state) +{ + IPos hash_head = NIL; /* head of hash chain */ + IPos prev_match; /* previous match */ + int flush; /* set if current block must be flushed */ + int match_available = 0; /* set if previous match exists */ + unsigned match_length = MIN_MATCH-1; /* length of best match */ + + if (state.level <= 3) return deflate_fast(state); /* optimized for speed */ + + /* Process the input block. */ + while (state.ds.lookahead != 0) { + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (state.ds.lookahead >= MIN_MATCH) + INSERT_STRING(state.ds.strstart, hash_head); + + /* Find the longest match, discarding those <= prev_length. + */ + state.ds.prev_length = match_length, prev_match = state.ds.match_start; + match_length = MIN_MATCH-1; + + if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match && + state.ds.strstart - hash_head <= MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + /* Do not look for matches beyond the end of the input. + * This is necessary to make deflate deterministic. + */ + if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; + match_length = longest_match (state,hash_head); + /* longest_match() sets match_start */ + if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; + + /* Ignore a length 3 match if it is too distant: */ + if (match_length == MIN_MATCH && state.ds.strstart-state.ds.match_start > TOO_FAR){ + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) { + unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH; + check_match(state,state.ds.strstart-1, prev_match, state.ds.prev_length); + flush = ct_tally(state,state.ds.strstart-1-prev_match, state.ds.prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. + */ + state.ds.lookahead -= state.ds.prev_length-1; + state.ds.prev_length -= 2; + do { + if (++state.ds.strstart <= max_insert) { + INSERT_STRING(state.ds.strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } + } while (--state.ds.prev_length != 0); + state.ds.strstart++; + match_available = 0; + match_length = MIN_MATCH-1; + + if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; + + } else if (match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + if (ct_tally (state,0, state.ds.window[state.ds.strstart-1])) { + FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; + } + state.ds.strstart++; + state.ds.lookahead--; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + match_available = 1; + state.ds.strstart++; + state.ds.lookahead--; + } +// Assert(state,strstart <= isize && lookahead <= isize, "a bit too far"); + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); + } + if (match_available) ct_tally (state,0, state.ds.window[state.ds.strstart-1]); + + return FLUSH_BLOCK(state,1); /* eof */ +} + + + + + + + + + + + + +int putlocal(struct zlist far *z, WRITEFUNC wfunc,void *param) +{ // Write a local header described by *z to file *f. Return a ZE_ error code. + PUTLG(LOCSIG, f); + PUTSH(z->ver, f); + PUTSH(z->lflg, f); + PUTSH(z->how, f); + PUTLG(z->tim, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + PUTSH(z->nam, f); + PUTSH(z->ext, f); + size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam); + if (res!=z->nam) return ZE_TEMP; + if (z->ext) + { res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext); + if (res!=z->ext) return ZE_TEMP; + } + return ZE_OK; +} + +int putextended(struct zlist far *z, WRITEFUNC wfunc, void *param) +{ // Write an extended local header described by *z to file *f. Returns a ZE_ code + PUTLG(EXTLOCSIG, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + return ZE_OK; +} + +int putcentral(struct zlist far *z, WRITEFUNC wfunc, void *param) +{ // Write a central header entry of *z to file *f. Returns a ZE_ code. + PUTLG(CENSIG, f); + PUTSH(z->vem, f); + PUTSH(z->ver, f); + PUTSH(z->flg, f); + PUTSH(z->how, f); + PUTLG(z->tim, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + PUTSH(z->nam, f); + PUTSH(z->cext, f); + PUTSH(z->com, f); + PUTSH(z->dsk, f); + PUTSH(z->att, f); + PUTLG(z->atx, f); + PUTLG(z->off, f); + if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam || + (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) || + (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com)) + return ZE_TEMP; + return ZE_OK; +} + + +int putend(int n, ulg s, ulg c, extent m, char *z, WRITEFUNC wfunc, void *param) +{ // write the end of the central-directory-data to file *f. + PUTLG(ENDSIG, f); + PUTSH(0, f); + PUTSH(0, f); + PUTSH(n, f); + PUTSH(n, f); + PUTLG(s, f); + PUTLG(c, f); + PUTSH(m, f); + // Write the comment, if any + if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP; + return ZE_OK; +} + + + + + + +const ulg crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) +#define DO1(buf) crc = CRC32(crc, *buf++) +#define DO2(buf) DO1(buf); DO1(buf) +#define DO4(buf) DO2(buf); DO2(buf) +#define DO8(buf) DO4(buf); DO4(buf) + +ulg crc32(ulg crc, const uch *buf, extent len) +{ if (buf==NULL) return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) {DO8(buf); len -= 8;} + if (len) do {DO1(buf);} while (--len); + return crc ^ 0xffffffffL; // (instead of ~c for 64-bit machines) +} + + + + + + + + +bool HasZipSuffix(const char *fn) +{ const char *ext = fn+strlen(fn); + while (ext>fn && *ext!='.') ext--; + if (ext==fn && *ext!='.') return false; + if (_stricmp(ext,".Z")==0) return true; + if (_stricmp(ext,".zip")==0) return true; + if (_stricmp(ext,".zoo")==0) return true; + if (_stricmp(ext,".arc")==0) return true; + if (_stricmp(ext,".lzh")==0) return true; + if (_stricmp(ext,".arj")==0) return true; + if (_stricmp(ext,".gz")==0) return true; + if (_stricmp(ext,".tgz")==0) return true; + return false; +} + +#ifdef _WIN32 +time_t filetime2timet(const FILETIME ft) +{ SYSTEMTIME st; FileTimeToSystemTime(&ft,&st); + if (st.wYear<1970) {st.wYear=1970; st.wMonth=1; st.wDay=1;} + if (st.wYear>=2038) {st.wYear=2037; st.wMonth=12; st.wDay=31;} + struct tm tm; + tm.tm_sec = st.wSecond; + tm.tm_min = st.wMinute; + tm.tm_hour = st.wHour; + tm.tm_mday = st.wDay; + tm.tm_mon = st.wMonth-1; + tm.tm_year = st.wYear-1900; + tm.tm_isdst = 0; + time_t t = mktime(&tm); + return t; +} + +ZRESULT GetFileInfo(HANDLE hf, ulg *attr, long *size, iztimes *times, ulg *timestamp) +{ + DWORD type=GetFileType(hf); + if (type!=FILE_TYPE_DISK) + return ZR_NOTINITED; + // The handle must be a handle to a file + // The date and time is returned in a long with the date most significant to allow + // unsigned integer comparison of absolute times. The attributes have two + // high bytes unix attr, and two low bytes a mapping of that to DOS attr. + //struct stat s; int res=stat(fn,&s); if (res!=0) return false; + // translate windows file attributes into zip ones. + BY_HANDLE_FILE_INFORMATION bhi; + BOOL res=GetFileInformationByHandle(hf,&bhi); + if (!res) + return ZR_NOFILE; + FileTimeToLocalFileTime( &bhi.ftLastAccessTime, &bhi.ftLastAccessTime ); + FileTimeToLocalFileTime( &bhi.ftLastWriteTime, &bhi.ftLastWriteTime ); + FileTimeToLocalFileTime( &bhi.ftCreationTime, &bhi.ftCreationTime ); + DWORD fa=bhi.dwFileAttributes; + ulg a=0; + // Zip uses the lower word for its interpretation of windows stuff + if (fa&FILE_ATTRIBUTE_READONLY) a|=0x01; + if (fa&FILE_ATTRIBUTE_HIDDEN) a|=0x02; + if (fa&FILE_ATTRIBUTE_SYSTEM) a|=0x04; + if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x10; + if (fa&FILE_ATTRIBUTE_ARCHIVE) a|=0x20; + // It uses the upper word for standard unix attr, which we must manually construct + if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x40000000; // directory + else a|=0x80000000; // normal file + a|=0x01000000; // readable + if (fa&FILE_ATTRIBUTE_READONLY) {} + else a|=0x00800000; // writeable + // now just a small heuristic to check if it's an executable: + DWORD red, hsize=GetFileSize(hf,NULL); if (hsize>40) + { SetFilePointer(hf,0,NULL,FILE_BEGIN); unsigned short magic; ReadFile(hf,&magic,sizeof(magic),&red,NULL); + SetFilePointer(hf,36,NULL,FILE_BEGIN); unsigned long hpos; ReadFile(hf,&hpos,sizeof(hpos),&red,NULL); + if (magic==0x54AD && hsize>hpos+4+20+28) + { SetFilePointer(hf,hpos,NULL,FILE_BEGIN); unsigned long signature; ReadFile(hf,&signature,sizeof(signature),&red,NULL); + if (signature==IMAGE_DOS_SIGNATURE || signature==IMAGE_OS2_SIGNATURE + || signature==IMAGE_OS2_SIGNATURE_LE || signature==IMAGE_NT_SIGNATURE) + { a |= 0x00400000; // executable + } + } + } + // + if (attr!=NULL) *attr = a; + if (size!=NULL) *size = hsize; + if (times!=NULL) + { // time_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970. + // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601 + times->atime = filetime2timet(bhi.ftLastAccessTime); + times->mtime = filetime2timet(bhi.ftLastWriteTime); + times->ctime = filetime2timet(bhi.ftCreationTime); + } + if (timestamp!=NULL) + { WORD dosdate,dostime; + FileTimeToDosDateTime(&bhi.ftLastWriteTime,&dosdate,&dostime); + *timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + } + return ZR_OK; +} +#endif + +#ifndef _WIN32 +int timet_to_timestamp( time_t time ) +{ + struct tm *tm; + tm = localtime( &time ); + if ( !tm ) + return 0; + + int date = 0; + + date |= ( ( ( tm->tm_year & 0x7f ) + ( 1900 - 1980 ) ) << 9 ); + date |= ( ( ( tm->tm_mon & 0x0f ) + 1 ) << 5 ); + date |= ( ( ( tm->tm_mday & 0x1f ) ) ); + + int timepart = 0; + + timepart |= ( ( ( tm->tm_hour & 0x1f ) ) << 11 ); + timepart |= ( ( ( tm->tm_min & 0x3f ) ) << 5 ); + timepart |= ( ( ( tm->tm_sec & 0x3e ) ) >> 1 ); + + return time | (date << 16 ); +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +class TZip +{ public: + TZip() : hfout(0),hmapout(0),zfis(0),obuf(0),hfin(0),writ(0),oerr(false),hasputcen(false),ooffset(0) {} + ~TZip() {} + + // These variables say about the file we're writing into + // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile + HANDLE hfout; // if valid, we'll write here (for files or pipes) + HANDLE hmapout; // otherwise, we'll write here (for memmap) + unsigned ooffset; // for hfout, this is where the pointer was initially + ZRESULT oerr; // did a write operation give rise to an error? + unsigned writ; // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks + bool ocanseek; // can we seek? + char *obuf; // this is where we've locked mmap to view. + unsigned int opos; // current pos in the mmap + unsigned int mapsize; // the size of the map we created + bool hasputcen; // have we yet placed the central directory? + // + TZipFileInfo *zfis; // each file gets added onto this list, for writing the table at the end + + ZRESULT Create(void *z,unsigned int len,DWORD flags); + static unsigned sflush(void *param,const char *buf, unsigned *size); + static unsigned swrite(void *param,const char *buf, unsigned size); + unsigned int write(const char *buf,unsigned int size); + bool oseek(unsigned int pos); + ZRESULT GetMemory(void **pbuf, unsigned long *plen); + ZRESULT Close(); + + // some variables to do with the file currently being read: + // I haven't done it object-orientedly here, just put them all + // together, since OO didn't seem to make the design any clearer. + ulg attr; iztimes times; ulg timestamp; // all open_* methods set these + bool iseekable; long isize,ired; // size is not set until close() on pips + ulg crc; // crc is not set until close(). iwrit is cumulative + HANDLE hfin; bool selfclosehf; // for input files and pipes + const char *bufin; unsigned int lenin,posin; // for memory + // and a variable for what we've done with the input: (i.e. compressed it!) + ulg csize; // compressed size, set by the compression routines + // and this is used by some of the compression routines + char buf[16384]; + + + ZRESULT open_file(const TCHAR *fn); + ZRESULT open_handle(HANDLE hf,unsigned int len); + ZRESULT open_mem(void *src,unsigned int len); + ZRESULT open_dir(); + static unsigned sread(TState &s,char *buf,unsigned size); + unsigned read(char *buf, unsigned size); + ZRESULT iclose(); + + ZRESULT ideflate(TZipFileInfo *zfi); + ZRESULT istore(); + + ZRESULT Add(const char *odstzn, void *src,unsigned int len, DWORD flags); + ZRESULT AddCentral(); + +}; + +ZRESULT TZip::Create(void *z,unsigned int len,DWORD flags) +{ + if (hfout!=0 || hmapout!=0 || obuf!=0 || writ!=0 || oerr!=ZR_OK || hasputcen) + return ZR_NOTINITED; + // + if (flags==ZIP_MEMORY) + { + if (len==0) + return ZR_MEMSIZE; + if (z!=0) + obuf=(char*)z; + else + { +#ifdef _WIN32 + hmapout = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,len,NULL); + if (hmapout==NULL) + return ZR_NOALLOC; + obuf = (char*)MapViewOfFile(hmapout,FILE_MAP_ALL_ACCESS,0,0,len); + if (obuf==0) + { + CloseHandle(hmapout); + hmapout=0; + return ZR_NOALLOC; + } +#endif +#ifdef POSIX + obuf = (char*) calloc( len, 1 ); + hmapout = (void*)-1; // sentinel to let close know it's a file in posix. + if ( !obuf ) + return ZR_NOALLOC; +#endif + } + ocanseek=true; + opos=0; + mapsize=len; + return ZR_OK; + } +#ifdef _WIN32 + else if (flags==ZIP_HANDLE) + { + HANDLE hf = (HANDLE)z; + BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&hfout,0,FALSE,DUPLICATE_SAME_ACCESS); + if (!res) + return ZR_NODUPH; + // now we have our own hfout, which we must close. And the caller will close hf + DWORD type = GetFileType(hfout); + ocanseek = (type==FILE_TYPE_DISK); + if (type==FILE_TYPE_DISK) + ooffset=SetFilePointer(hfout,0,NULL,FILE_CURRENT); + else + ooffset=0; + return ZR_OK; + } + else if (flags==ZIP_FILENAME) + { +#ifdef _UNICODE + const TCHAR *fn = (const TCHAR*)z; + hfout = CreateFileW(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); +#else + const char *fn = (const char*)z; + hfout = CreateFileA(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); +#endif + + if (hfout==INVALID_HANDLE_VALUE) + { + hfout=0; + return ZR_NOFILE; + } + ocanseek=true; + ooffset=0; + return ZR_OK; + } +#endif + else + return ZR_ARGS; +} + + +unsigned TZip::sflush(void *param,const char *buf, unsigned *size) +{ // static + if (*size==0) return 0; + TZip *zip = (TZip*)param; + unsigned int writ = zip->write(buf,*size); + if (writ!=0) *size=0; + return writ; +} +unsigned TZip::swrite(void *param,const char *buf, unsigned size) +{ // static + if (size==0) return 0; + TZip *zip=(TZip*)param; return zip->write(buf,size); +} +unsigned int TZip::write(const char *buf,unsigned int size) +{ if (obuf!=0) + { if (opos+size>=mapsize) {oerr=ZR_MEMSIZE; return 0;} + memcpy(obuf+opos, buf, size); + opos+=size; + return size; + } +#ifdef _WIN32 + else if (hfout!=0) + { DWORD writ; WriteFile(hfout,buf,size,&writ,NULL); + return writ; + } +#endif + oerr=ZR_NOTINITED; return 0; +} + +bool TZip::oseek(unsigned int pos) +{ if (!ocanseek) {oerr=ZR_SEEK; return false;} + if (obuf!=0) + { if (pos>=mapsize) {oerr=ZR_MEMSIZE; return false;} + opos=pos; + return true; + } +#ifdef _WIN32 + else if (hfout!=0) + { SetFilePointer(hfout,pos+ooffset,NULL,FILE_BEGIN); + return true; + } +#endif + oerr=ZR_NOTINITED; return 0; +} + +ZRESULT TZip::GetMemory(void **pbuf, unsigned long *plen) +{ // When the user calls GetMemory, they're presumably at the end + // of all their adding. In any case, we have to add the central + // directory now, otherwise the memory we tell them won't be complete. + if (!hasputcen) AddCentral(); hasputcen=true; + if (pbuf!=NULL) *pbuf=(void*)obuf; + if (plen!=NULL) *plen=writ; + if (obuf==NULL) return ZR_NOTMMAP; + return ZR_OK; +} + +ZRESULT TZip::Close() +{ // if the directory hadn't already been added through a call to GetMemory, + // then we do it now + ZRESULT res=ZR_OK; if (!hasputcen) res=AddCentral(); hasputcen=true; + if (obuf!=0 && hmapout!=0) +#ifdef _WIN32 + UnmapViewOfFile(obuf); +#elif defined( POSIX ) + free(obuf); +#endif + obuf=0; +#ifdef _WIN32 + if (hmapout!=0) CloseHandle(hmapout); hmapout=0; + if (hfout!=0) CloseHandle(hfout); hfout=0; +#endif + return res; +} + + + + +ZRESULT TZip::open_file(const TCHAR *fn) +{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; + if (fn==0) return ZR_ARGS; + HANDLE hf = INVALID_HANDLE_VALUE; +#ifdef _WIN32 + hf = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); +#endif + if (hf==INVALID_HANDLE_VALUE) return ZR_NOFILE; + ZRESULT res = open_handle(hf,0); + if (res!=ZR_OK) { +#ifdef _WIN32 + CloseHandle(hf); +#endif + return res; + } + selfclosehf=true; + return ZR_OK; +} +ZRESULT TZip::open_handle(HANDLE hf,unsigned int len) +{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; + if (hf==0 || hf==INVALID_HANDLE_VALUE) return ZR_ARGS; +#ifdef _WIN32 + DWORD type = GetFileType(hf); + if (type==FILE_TYPE_DISK) + { ZRESULT res = GetFileInfo(hf,&attr,&isize,×,×tamp); + if (res!=ZR_OK) return res; + SetFilePointer(hf,0,NULL,FILE_BEGIN); // because GetFileInfo will have screwed it up + iseekable=true; hfin=hf; + return ZR_OK; + } + else + { attr= 0x80000000; // just a normal file + isize = -1; // can't know size until at the end + if (len!=0) isize=len; // unless we were told explicitly! + iseekable=false; + SYSTEMTIME st; GetLocalTime(&st); + FILETIME ft; SystemTimeToFileTime(&st,&ft); + WORD dosdate,dostime; FileTimeToDosDateTime(&ft,&dosdate,&dostime); + times.atime = filetime2timet(ft); + times.mtime = times.atime; + times.ctime = times.atime; + timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + hfin=hf; + return ZR_OK; + } +#else + return ZR_FAILED; +#endif +} + +ZRESULT TZip::open_mem(void *src,unsigned int len) +{ hfin=0; bufin=(const char*)src; selfclosehf=false; crc=CRCVAL_INITIAL; ired=0; csize=0; ired=0; + lenin=len; posin=0; + if (src==0 || len==0) return ZR_ARGS; +#ifdef _WIN32 + attr= 0x80000000; // just a normal file + isize = len; + iseekable=true; + SYSTEMTIME st; GetLocalTime(&st); + FILETIME ft; SystemTimeToFileTime(&st,&ft); + WORD dosdate,dostime; FileTimeToDosDateTime(&ft,&dosdate,&dostime); + times.atime = filetime2timet(ft); + times.mtime = times.atime; + times.ctime = times.atime; + timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + return ZR_OK; +#else + times.atime = time(NULL); + times.mtime = times.atime; + times.ctime = times.atime; + timestamp = timet_to_timestamp( times.atime ); + return ZR_OK; +#endif +} + +ZRESULT TZip::open_dir() +{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; +#ifdef _WIN32 + attr= 0x41C00010; // a readable writable directory, and again directory + isize = 0; + iseekable=false; + SYSTEMTIME st; GetLocalTime(&st); + FILETIME ft; SystemTimeToFileTime(&st,&ft); + WORD dosdate,dostime; FileTimeToDosDateTime(&ft,&dosdate,&dostime); + times.atime = filetime2timet(ft); + times.mtime = times.atime; + times.ctime = times.atime; + timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + return ZR_OK; +#else + times.atime = time(NULL); + times.mtime = times.atime; + times.ctime = times.atime; + timestamp = timet_to_timestamp( times.atime ); + return ZR_OK; +#endif +} + +unsigned TZip::sread(TState &s,char *buf,unsigned size) +{ // static + TZip *zip = (TZip*)s.param; + return zip->read(buf,size); +} + +unsigned TZip::read(char *buf, unsigned size) +{ if (bufin!=0) + { if (posin>=lenin) return 0; // end of input + ulg red = lenin-posin; + if (red>size) red=size; + memcpy(buf, bufin+posin, red); + posin += red; + ired += red; + crc = crc32(crc, (uch*)buf, red); + return red; + } +#ifdef _WIN32 + else if (hfin!=0) + { DWORD red; + BOOL ok = ReadFile(hfin,buf,size,&red,NULL); + if (!ok) return 0; + ired += red; + crc = crc32(crc, (uch*)buf, red); + return red; + } +#endif + else {oerr=ZR_NOTINITED; return 0;} +} + +ZRESULT TZip::iclose() +{ +#ifdef _WIN32 + if (selfclosehf && hfin!=0) CloseHandle(hfin); +#endif + hfin=0; + bool mismatch = (isize!=-1 && isize!=ired); + isize=ired; // and crc has been being updated anyway + if (mismatch) return ZR_MISSIZE; + else return ZR_OK; +} + + + +ZRESULT TZip::ideflate(TZipFileInfo *zfi) +{ TState state; + state.readfunc=sread; state.flush_outbuf=sflush; + state.param=this; state.level=8; state.seekable=iseekable; state.err=NULL; + // the following line will make ct_init realise it has to perform the init + state.ts.static_dtree[0].dl.len = 0; + // It would be nicer if I could figure out precisely which data had to + // be initted each time, and which didn't, but that's kind of difficult. + // Maybe for the next version... + // + bi_init(state,buf, sizeof(buf), TRUE); // it used to be just 1024-size, not 16384 as here + ct_init(state,&zfi->att); + lm_init(state,state.level, &zfi->flg); + ulg sz = deflate(state); + csize=sz; + if (state.err!=NULL) return ZR_FLATE; + else return ZR_OK; +} + +ZRESULT TZip::istore() +{ ulg size=0; + for (;;) + { unsigned int cin=read(buf,16384); if (cin<=0 || cin==(unsigned int)EOF) break; + unsigned int cout = write(buf,cin); if (cout!=cin) return ZR_MISSIZE; + size += cin; + } + csize=size; + return ZR_OK; +} + + + + +ZRESULT TZip::Add(const char *odstzn, void *src,unsigned int len, DWORD flags) +{ + if (oerr) + return ZR_FAILED; + if (hasputcen) + return ZR_ENDED; + + // zip has its own notion of what its names should look like: i.e. dir/file.stuff + char dstzn[MAX_PATH]; + strcpy(dstzn, odstzn); + if (*dstzn == 0) + return ZR_ARGS; + char *d=dstzn; + while (*d != 0) + { + if (*d == '\\') + *d = '/'; + d++; + } + bool isdir = (flags==ZIP_FOLDER); + bool needs_trailing_slash = (isdir && dstzn[strlen(dstzn)-1]!='/'); + int method=DEFLATE; + if (isdir || HasZipSuffix(dstzn)) + method=STORE; + + // now open whatever was our input source: + ZRESULT openres; + if (flags==ZIP_FILENAME) + openres=open_file((const TCHAR*)src); + else if (flags==ZIP_HANDLE) + openres=open_handle((HANDLE)src,len); + else if (flags==ZIP_MEMORY) + openres=open_mem(src,len); + else if (flags==ZIP_FOLDER) + openres=open_dir(); + else return ZR_ARGS; + if (openres!=ZR_OK) + return openres; + + // A zip "entry" consists of a local header (which includes the file name), + // then the compressed data, and possibly an extended local header. + + // Initialize the local header + TZipFileInfo zfi; zfi.nxt=NULL; + strcpy(zfi.name,""); + strcpy(zfi.iname,dstzn); + zfi.nam=strlen(zfi.iname); + if (needs_trailing_slash) + { + strcat(zfi.iname,"/"); + zfi.nam++; + } + strcpy(zfi.zname,""); + zfi.extra=NULL; zfi.ext=0; // extra header to go after this compressed data, and its length + zfi.cextra=NULL; zfi.cext=0; // extra header to go in the central end-of-zip directory, and its length + zfi.comment=NULL; zfi.com=0; // comment, and its length + zfi.mark = 1; + zfi.dosflag = 0; + zfi.att = (ush)BINARY; + zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3 + zfi.ver = (ush)20; // Needs PKUNZIP 2.0 to unzip it + zfi.tim = timestamp; + // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. + zfi.crc = 0; // to be updated later + zfi.flg = 8; // 8 means 'there is an extra header'. Assume for the moment that we need it. + zfi.lflg = zfi.flg; // to be updated later + zfi.how = (ush)method; // to be updated later + zfi.siz = (ulg)(method==STORE && isize>=0 ? isize : 0); // to be updated later + zfi.len = (ulg)(isize); // to be updated later + zfi.dsk = 0; + zfi.atx = attr; + zfi.off = writ+ooffset; // offset within file of the start of this local record + // stuff the 'times' structure into zfi.extra + char xloc[EB_L_UT_SIZE]; + zfi.extra=xloc; + zfi.ext=EB_L_UT_SIZE; + char xcen[EB_C_UT_SIZE]; + zfi.cextra=xcen; + zfi.cext=EB_C_UT_SIZE; + xloc[0] = 'U'; + xloc[1] = 'T'; + xloc[2] = EB_UT_LEN(3); // length of data part of e.f. + xloc[3] = 0; + xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME; + xloc[5] = (char)(times.mtime); + xloc[6] = (char)(times.mtime >> 8); + xloc[7] = (char)(times.mtime >> 16); + xloc[8] = (char)(times.mtime >> 24); + xloc[9] = (char)(times.atime); + xloc[10] = (char)(times.atime >> 8); + xloc[11] = (char)(times.atime >> 16); + xloc[12] = (char)(times.atime >> 24); + xloc[13] = (char)(times.ctime); + xloc[14] = (char)(times.ctime >> 8); + xloc[15] = (char)(times.ctime >> 16); + xloc[16] = (char)(times.ctime >> 24); + memcpy(zfi.cextra,zfi.extra,EB_C_UT_SIZE); + zfi.cextra[EB_LEN] = EB_UT_LEN(1); + + + // (1) Start by writing the local header: + int r = putlocal(&zfi,swrite,this); + if (r!=ZE_OK) + { + iclose(); + return ZR_WRITE; + } + writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext; + if (oerr!=ZR_OK) + { + iclose(); + return oerr; + } + + //(2) Write deflated/stored file to zip file + ZRESULT writeres=ZR_OK; + if (!isdir && method==DEFLATE) + writeres=ideflate(&zfi); + else if (!isdir && method==STORE) + writeres=istore(); + else if (isdir) + csize=0; + iclose(); + writ += csize; + if (oerr!=ZR_OK) + return oerr; + if (writeres!=ZR_OK) + return ZR_WRITE; + + // (3) Either rewrite the local header with correct information... + bool first_header_has_size_right = (zfi.siz==csize); + zfi.crc = crc; + zfi.siz = csize; + zfi.len = isize; + if (ocanseek) + { + zfi.how = (ush)method; + if ((zfi.flg & 1) == 0) + zfi.flg &= ~8; // clear the extended local header flag + zfi.lflg = zfi.flg; + // rewrite the local header: + if (!oseek(zfi.off-ooffset)) + return ZR_SEEK; + if ((r = putlocal(&zfi, swrite,this)) != ZE_OK) + return ZR_WRITE; + if (!oseek(writ)) + return ZR_SEEK; + } + else + { + // (4) ... or put an updated header at the end + if (zfi.how != (ush) method) + return ZR_NOCHANGE; + if (method==STORE && !first_header_has_size_right) + return ZR_NOCHANGE; + if ((r = putextended(&zfi, swrite,this)) != ZE_OK) + return ZR_WRITE; + writ += 16L; + zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index + } + if (oerr!=ZR_OK) + return oerr; + + // Keep a copy of the zipfileinfo, for our end-of-zip directory + char *cextra = new char[zfi.cext]; + memcpy(cextra,zfi.cextra,zfi.cext); zfi.cextra=cextra; + TZipFileInfo *pzfi = new TZipFileInfo; + memcpy(pzfi,&zfi,sizeof(zfi)); + if (zfis==NULL) + zfis=pzfi; + else + { + TZipFileInfo *z=zfis; + while (z->nxt!=NULL) + z=z->nxt; + z->nxt=pzfi; + } + return ZR_OK; +} + +ZRESULT TZip::AddCentral() +{ // write central directory + int numentries = 0; + ulg pos_at_start_of_central = writ; + //ulg tot_unc_size=0, tot_compressed_size=0; + bool okay=true; + for (TZipFileInfo *zfi=zfis; zfi!=NULL; ) + { if (okay) + { int res = putcentral(zfi, swrite,this); + if (res!=ZE_OK) okay=false; + } + writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com; + //tot_unc_size += zfi->len; + //tot_compressed_size += zfi->siz; + numentries++; + // + TZipFileInfo *zfinext = zfi->nxt; + if (zfi->cextra!=0) delete[] zfi->cextra; + delete zfi; + zfi = zfinext; + } + ulg center_size = writ - pos_at_start_of_central; + if (okay) + { int res = putend(numentries, center_size, pos_at_start_of_central+ooffset, 0, NULL, swrite,this); + if (res!=ZE_OK) okay=false; + writ += 4 + ENDHEAD + 0; + } + if (!okay) return ZR_WRITE; + return ZR_OK; +} + + +unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len) +{ if (code==ZR_RECENT) code=lasterrorZ; + const char *msg="unknown zip result code"; + switch (code) + { case ZR_OK: msg="Success"; break; + case ZR_NODUPH: msg="Culdn't duplicate handle"; break; + case ZR_NOFILE: msg="Couldn't create/open file"; break; + case ZR_NOALLOC: msg="Failed to allocate memory"; break; + case ZR_WRITE: msg="Error writing to file"; break; + case ZR_NOTFOUND: msg="File not found in the zipfile"; break; + case ZR_MORE: msg="Still more data to unzip"; break; + case ZR_CORRUPT: msg="Zipfile is corrupt or not a zipfile"; break; + case ZR_READ: msg="Error reading file"; break; + case ZR_ARGS: msg="Caller: faulty arguments"; break; + case ZR_PARTIALUNZ: msg="Caller: the file had already been partially unzipped"; break; + case ZR_NOTMMAP: msg="Caller: can only get memory of a memory zipfile"; break; + case ZR_MEMSIZE: msg="Caller: not enough space allocated for memory zipfile"; break; + case ZR_FAILED: msg="Caller: there was a previous error"; break; + case ZR_ENDED: msg="Caller: additions to the zip have already been ended"; break; + case ZR_ZMODE: msg="Caller: mixing creation and opening of zip"; break; + case ZR_NOTINITED: msg="Zip-bug: internal initialisation not completed"; break; + case ZR_SEEK: msg="Zip-bug: trying to seek the unseekable"; break; + case ZR_MISSIZE: msg="Zip-bug: the anticipated size turned out wrong"; break; + case ZR_NOCHANGE: msg="Zip-bug: tried to change mind, but not allowed"; break; + case ZR_FLATE: msg="Zip-bug: an internal error during flation"; break; + } + unsigned int mlen=(unsigned int)strlen(msg); + if (buf==0 || len==0) return mlen; + unsigned int n=mlen; if (n+1>len) n=len-1; + memcpy(buf,msg,n); buf[n]=0; + return mlen; +} + + + +typedef struct +{ DWORD flag; + TZip *zip; +} TZipHandleData; + + +HZIP CreateZipZ(void *z,unsigned int len,DWORD flags) +{ + _tzset(); + TZip *zip = new TZip(); + lasterrorZ = zip->Create(z,len,flags); + if (lasterrorZ != ZR_OK) + { + delete zip; + return 0; + } + TZipHandleData *han = new TZipHandleData; + han->flag = 2; + han->zip = zip; + return (HZIP)han; +} + +ZRESULT ZipAdd(HZIP hz, const TCHAR *dstzn, void *src, unsigned int len, DWORD flags) +{ + if (hz == 0) + { + lasterrorZ = ZR_ARGS; + return ZR_ARGS; + } + TZipHandleData *han = (TZipHandleData*)hz; + if (han->flag != 2) + { + lasterrorZ = ZR_ZMODE; + return ZR_ZMODE; + } + TZip *zip = han->zip; + + + if (flags == ZIP_FILENAME) + { + char szDest[MAX_PATH*2]; + memset(szDest, 0, sizeof(szDest)); + +#ifdef _UNICODE + // need to convert Unicode dest to ANSI + int nActualChars = WideCharToMultiByte(CP_ACP, // code page + 0, // performance and mapping flags + (LPCWSTR) dstzn, // wide-character string + -1, // number of chars in string + szDest, // buffer for new string + MAX_PATH*2-2, // size of buffer + NULL, // default for unmappable chars + NULL); // set when default char used + if (nActualChars == 0) + return ZR_ARGS; +#else + strcpy(szDest, dstzn); +#endif + + lasterrorZ = zip->Add(szDest, src, len, flags); + } + else + { + lasterrorZ = zip->Add((char *)dstzn, src, len, flags); + } + + return lasterrorZ; +} + +ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len) +{ if (hz==0) {if (buf!=0) *buf=0; if (len!=0) *len=0; lasterrorZ=ZR_ARGS;return ZR_ARGS;} + TZipHandleData *han = (TZipHandleData*)hz; + if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} + TZip *zip = han->zip; + lasterrorZ = zip->GetMemory(buf,len); + return lasterrorZ; +} + +ZRESULT CloseZipZ(HZIP hz) +{ if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} + TZipHandleData *han = (TZipHandleData*)hz; + if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} + TZip *zip = han->zip; + lasterrorZ = zip->Close(); + delete zip; + delete han; + return lasterrorZ; +} + +bool IsZipHandleZ(HZIP hz) +{ if (hz==0) return true; + TZipHandleData *han = (TZipHandleData*)hz; + return (han->flag==2); +} + + diff --git a/public/appframework/AppFramework.h b/public/appframework/AppFramework.h new file mode 100644 index 0000000..185d2f3 --- /dev/null +++ b/public/appframework/AppFramework.h @@ -0,0 +1,158 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: An application framework +// +// $Revision: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef APPFRAMEWORK_H +#define APPFRAMEWORK_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystemGroup.h" + + +//----------------------------------------------------------------------------- +// Gets the application instance.. +//----------------------------------------------------------------------------- +void *GetAppInstance(); + + +//----------------------------------------------------------------------------- +// Sets the application instance, should only be used if you're not calling AppMain. +//----------------------------------------------------------------------------- +void SetAppInstance( void* hInstance ); + + +//----------------------------------------------------------------------------- +// Main entry point for the application +//----------------------------------------------------------------------------- +int AppMain( void* hInstance, void* hPrevInstance, const char* lpCmdLine, int nCmdShow, CAppSystemGroup *pAppSystemGroup ); +int AppMain( int argc, char **argv, CAppSystemGroup *pAppSystemGroup ); + + +//----------------------------------------------------------------------------- +// Used to startup/shutdown the application +//----------------------------------------------------------------------------- +int AppStartup( void* hInstance, void* hPrevInstance, const char* lpCmdLine, int nCmdShow, CAppSystemGroup *pAppSystemGroup ); +int AppStartup( int argc, char **argv, CAppSystemGroup *pAppSystemGroup ); +void AppShutdown( CAppSystemGroup *pAppSystemGroup ); + + +//----------------------------------------------------------------------------- +// Macros to create singleton application objects for windowed + console apps +//----------------------------------------------------------------------------- +#if !defined( _X360 ) + +#ifdef WIN32 +#define DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ + int __stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) \ + { \ + return AppMain( hInstance, hPrevInstance, lpCmdLine, nCmdShow, &_globalVarName ); \ + } +#elif defined( OSX ) +#define DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ + int main( int argc, char **argv ) \ + { \ + extern int ValveCocoaMain( int argc, char **argv, CAppSystemGroup *pAppSystemGroup ); \ + return ValveCocoaMain( argc, argv, &_globalVarName ); \ + } +#elif defined( LINUX ) +#define DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ + int main( int argc, char **argv ) \ + { \ + extern int ValveLinuxWindowedMain( int argc, char **argv, CAppSystemGroup *pAppSystemGroup ); \ + return ValveLinuxWindowedMain( argc, argv, &_globalVarName ); \ + } +#else +#error +#endif + +#else +#define DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ + void __cdecl main() \ + { \ + AppMain( (HINSTANCE)1, (HINSTANCE)0, NULL, 0, &_globalVarName ); \ + } +#endif + +#if !defined( _X360 ) +#define DEFINE_CONSOLE_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ + int main( int argc, char **argv ) \ + { \ + return AppMain( argc, argv, &_globalVarName ); \ + } +#else +#define DEFINE_CONSOLE_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ + void __cdecl main() \ + { \ + AppMain( 0, (char**)NULL, &_globalVarName ); \ + } +#endif + +#define DEFINE_WINDOWED_APPLICATION_OBJECT( _className ) \ + static _className __s_ApplicationObject; \ + DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( __s_ApplicationObject ) + +#define DEFINE_CONSOLE_APPLICATION_OBJECT( _className ) \ + static _className __s_ApplicationObject; \ + DEFINE_CONSOLE_APPLICATION_OBJECT_GLOBALVAR( __s_ApplicationObject ) + + +//----------------------------------------------------------------------------- +// This class is a helper class used for steam-based applications. +// It loads up the file system in preparation for using it to load other +// required modules from steam. +//----------------------------------------------------------------------------- +class CSteamApplication : public CAppSystemGroup +{ + typedef CAppSystemGroup BaseClass; + +public: + CSteamApplication( CSteamAppSystemGroup *pAppSystemGroup ); + + // Implementation of IAppSystemGroup + virtual bool Create( ); + virtual bool PreInit( ); + virtual int Main( ); + virtual void PostShutdown(); + virtual void Destroy(); + + // Use this version in cases where you can't control the main loop and + // expect to be ticked + virtual int Startup(); + virtual void Shutdown(); + +protected: + IFileSystem *m_pFileSystem; + CSteamAppSystemGroup *m_pChildAppSystemGroup; + bool m_bSteam; +}; + + +//----------------------------------------------------------------------------- +// Macros to help create singleton application objects for windowed + console steam apps +//----------------------------------------------------------------------------- +#define DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT_GLOBALVAR( _className, _varName ) \ + static CSteamApplication __s_SteamApplicationObject( &_varName ); \ + DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( __s_SteamApplicationObject ) + +#define DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( _className ) \ + static _className __s_ApplicationObject; \ + static CSteamApplication __s_SteamApplicationObject( &__s_ApplicationObject ); \ + DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( __s_SteamApplicationObject ) + +#define DEFINE_CONSOLE_STEAM_APPLICATION_OBJECT_GLOBALVAR( _className, _varName ) \ + static CSteamApplication __s_SteamApplicationObject( &_varName ); \ + DEFINE_CONSOLE_APPLICATION_OBJECT_GLOBALVAR( __s_SteamApplicationObject ) + +#define DEFINE_CONSOLE_STEAM_APPLICATION_OBJECT( _className ) \ + static _className __s_ApplicationObject; \ + static CSteamApplication __s_SteamApplicationObject( &__s_ApplicationObject ); \ + DEFINE_CONSOLE_APPLICATION_OBJECT_GLOBALVAR( __s_SteamApplicationObject ) + +#endif // APPFRAMEWORK_H diff --git a/public/appframework/IAppSystem.h b/public/appframework/IAppSystem.h new file mode 100644 index 0000000..c69988f --- /dev/null +++ b/public/appframework/IAppSystem.h @@ -0,0 +1,128 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: An application framework +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef IAPPSYSTEM_H +#define IAPPSYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" + + +//----------------------------------------------------------------------------- +// Client systems are singleton objects in the client codebase responsible for +// various tasks +// The order in which the client systems appear in this list are the +// order in which they are initialized and updated. They are shut down in +// reverse order from which they are initialized. +//----------------------------------------------------------------------------- + +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + + INIT_LAST_VAL, +}; + + +abstract_class IAppSystem +{ +public: + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + + // Here's where systems can access other interfaces implemented by this object + // Returns NULL if it doesn't implement the requested interface + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + + // Init, shutdown + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + // INTERFACE_UPDATE:23.02.2020 + virtual void IAppSystem_stub_001(){} + virtual void IAppSystem_stub_002(){} + virtual void IAppSystem_stub_003(){} + virtual void IAppSystem_stub_004(){} +}; + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem +//----------------------------------------------------------------------------- +template< class IInterface > +class CBaseAppSystem : public IInterface +{ +public: + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) { return true; } + virtual void Disconnect() {} + + // Here's where systems can access other interfaces implemented by this object + // Returns NULL if it doesn't implement the requested interface + virtual void *QueryInterface( const char *pInterfaceName ) { return NULL; } + + // Init, shutdown + virtual InitReturnVal_t Init() { return INIT_OK; } + virtual void Shutdown() {} +}; + + +//----------------------------------------------------------------------------- +// Helper implementation of an IAppSystem for tier0 +//----------------------------------------------------------------------------- +template< class IInterface > +class CTier0AppSystem : public CBaseAppSystem< IInterface > +{ +public: + CTier0AppSystem( bool bIsPrimaryAppSystem = true ) + { + m_bIsPrimaryAppSystem = bIsPrimaryAppSystem; + } + +protected: + // NOTE: a single DLL may have multiple AppSystems it's trying to + // expose. If this is true, you must return true from only + // one of those AppSystems; not doing so will cause all static + // libraries connected to it to connect/disconnect multiple times + + // NOTE: We don't do this as a virtual function to avoid + // having to up the version on all interfaces + bool IsPrimaryAppSystem() { return m_bIsPrimaryAppSystem; } + +private: + bool m_bIsPrimaryAppSystem; +}; + + +//----------------------------------------------------------------------------- +// This is the version of IAppSystem shipped 10/15/04 +// NOTE: Never change this!!! +//----------------------------------------------------------------------------- +abstract_class IAppSystemV0 +{ +public: + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + + // Here's where systems can access other interfaces implemented by this object + // Returns NULL if it doesn't implement the requested interface + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + + // Init, shutdown + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; +}; + +#endif // IAPPSYSTEM_H + diff --git a/public/appframework/IAppSystemGroup.h b/public/appframework/IAppSystemGroup.h new file mode 100644 index 0000000..5cc32aa --- /dev/null +++ b/public/appframework/IAppSystemGroup.h @@ -0,0 +1,265 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Defines a group of app systems that all have the same lifetime +// that need to be connected/initialized, etc. in a well-defined order +// +// $Revision: $ +// $NoKeywords: $ +//============================================================================= + +#ifndef IAPPSYSTEMGROUP_H +#define IAPPSYSTEMGROUP_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/interface.h" +#include "tier1/utlvector.h" +#include "tier1/utldict.h" +#include "IAppSystem.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IAppSystem; +class CSysModule; +class IBaseInterface; +class IFileSystem; + +//----------------------------------------------------------------------------- +// Handle to a DLL +//----------------------------------------------------------------------------- +typedef int AppModule_t; + +enum +{ + APP_MODULE_INVALID = (AppModule_t)~0 +}; + + +//----------------------------------------------------------------------------- +// NOTE: The following methods must be implemented in your application +// although they can be empty implementations if you like... +//----------------------------------------------------------------------------- +abstract_class IAppSystemGroup +{ +public: + // An installed application creation function, you should tell the group + // the DLLs and the singleton interfaces you want to instantiate. + // Return false if there's any problems and the app will abort + virtual bool Create( ) = 0; + + // Allow the application to do some work after AppSystems are connected but + // they are all Initialized. + // Return false if there's any problems and the app will abort + virtual bool PreInit() = 0; + + // Main loop implemented by the application + virtual int Main( ) = 0; + + // Allow the application to do some work after all AppSystems are shut down + virtual void PostShutdown() = 0; + + // Call an installed application destroy function, occurring after all modules + // are unloaded + virtual void Destroy() = 0; +}; + + +//----------------------------------------------------------------------------- +// Specifies a module + interface name for initialization +//----------------------------------------------------------------------------- +struct AppSystemInfo_t +{ + const char *m_pModuleName; + const char *m_pInterfaceName; +}; + + +//----------------------------------------------------------------------------- +// This class represents a group of app systems that all have the same lifetime +// that need to be connected/initialized, etc. in a well-defined order +//----------------------------------------------------------------------------- +class CAppSystemGroup : public IAppSystemGroup +{ +public: + // Used to determine where we exited out from the system + enum AppSystemGroupStage_t + { + CREATION = 0, + CONNECTION, + PREINITIALIZATION, + INITIALIZATION, + SHUTDOWN, + POSTSHUTDOWN, + DISCONNECTION, + DESTRUCTION, + + NONE, // This means no error + }; + +public: + // constructor + CAppSystemGroup( CAppSystemGroup *pParentAppSystem = NULL ); + + // Runs the app system group. + // First, modules are loaded, next they are connected, followed by initialization + // Then Main() is run + // Then modules are shut down, disconnected, and unloaded + int Run( ); + + // Use this version in cases where you can't control the main loop and + // expect to be ticked + virtual int Startup(); + virtual void Shutdown(); + + // Returns the stage at which the app system group ran into an error + AppSystemGroupStage_t GetErrorStage() const; + +protected: + // These methods are meant to be called by derived classes of CAppSystemGroup + + // Methods to load + unload DLLs + AppModule_t LoadModule( const char *pDLLName ); + AppModule_t LoadModule( CreateInterfaceFn factory ); + + // Method to add various global singleton systems + IAppSystem *AddSystem( AppModule_t module, const char *pInterfaceName ); + void AddSystem( IAppSystem *pAppSystem, const char *pInterfaceName ); + + // Simpler method of doing the LoadModule/AddSystem thing. + // Make sure the last AppSystemInfo has a NULL module name + bool AddSystems( AppSystemInfo_t *pSystems ); + + // Method to look up a particular named system... + void *FindSystem( const char *pInterfaceName ); + + // Gets at a class factory for the topmost appsystem group in an appsystem stack + static CreateInterfaceFn GetFactory(); + +private: + int OnStartup(); + void OnShutdown(); + + void UnloadAllModules( ); + void RemoveAllSystems(); + + // Method to connect/disconnect all systems + bool ConnectSystems( ); + void DisconnectSystems(); + + // Method to initialize/shutdown all systems + InitReturnVal_t InitSystems(); + void ShutdownSystems(); + + // Gets at the parent appsystem group + CAppSystemGroup *GetParent(); + + // Loads a module the standard way + virtual CSysModule *LoadModuleDLL( const char *pDLLName ); + + void ReportStartupFailure( int nErrorStage, int nSysIndex ); + + struct Module_t + { + CSysModule *m_pModule; + CreateInterfaceFn m_Factory; + char *m_pModuleName; + }; + + CUtlVector m_Modules; + CUtlVector m_Systems; + CUtlDict m_SystemDict; + CAppSystemGroup *m_pParentAppSystem; + AppSystemGroupStage_t m_nErrorStage; + + friend void *AppSystemCreateInterfaceFn(const char *pName, int *pReturnCode); + friend class CSteamAppSystemGroup; +}; + + +//----------------------------------------------------------------------------- +// This class represents a group of app systems that are loaded through steam +//----------------------------------------------------------------------------- +class CSteamAppSystemGroup : public CAppSystemGroup +{ +public: + CSteamAppSystemGroup( IFileSystem *pFileSystem = NULL, CAppSystemGroup *pParentAppSystem = NULL ); + + // Used by CSteamApplication to set up necessary pointers if we can't do it in the constructor + void Setup( IFileSystem *pFileSystem, CAppSystemGroup *pParentAppSystem ); + +protected: + // Sets up the search paths + bool SetupSearchPaths( const char *pStartingDir, bool bOnlyUseStartingDir, bool bIsTool ); + + // Returns the game info path. Only works if you've called SetupSearchPaths first + const char *GetGameInfoPath() const; + +private: + virtual CSysModule *LoadModuleDLL( const char *pDLLName ); + + IFileSystem *m_pFileSystem; + char m_pGameInfoPath[ MAX_PATH ]; +}; + + +//----------------------------------------------------------------------------- +// Helper empty decorator implementation of an IAppSystemGroup +//----------------------------------------------------------------------------- +template< class CBaseClass > +class CDefaultAppSystemGroup : public CBaseClass +{ +public: + virtual bool Create( ) { return true; } + virtual bool PreInit() { return true; } + virtual void PostShutdown() {} + virtual void Destroy() {} +}; + + +//----------------------------------------------------------------------------- +// Special helper for game info directory suggestion +//----------------------------------------------------------------------------- + +class CFSSteamSetupInfo; // Forward declaration + +// +// SuggestGameInfoDirFn_t +// Game info suggestion function. +// Provided by the application to possibly detect the suggested game info +// directory and initialize all the game-info-related systems appropriately. +// Parameters: +// pFsSteamSetupInfo steam file system setup information if available. +// pchPathBuffer buffer to hold game info directory path on return. +// nBufferLength length of the provided buffer to hold game info directory path. +// pbBubbleDirectories should contain "true" on return to bubble the directories up searching for game info file. +// Return values: +// Returns "true" if the game info directory path suggestion is available and +// was successfully copied into the provided buffer. +// Returns "false" otherwise, interpreted that no suggestion will be used. +// +typedef bool ( * SuggestGameInfoDirFn_t ) ( CFSSteamSetupInfo const *pFsSteamSetupInfo, char *pchPathBuffer, int nBufferLength, bool *pbBubbleDirectories ); + +// +// SetSuggestGameInfoDirFn +// Installs the supplied game info directory suggestion function. +// Parameters: +// pfnNewFn the new game info directory suggestion function. +// Returns: +// The previously installed suggestion function or NULL if none was installed before. +// This function never fails. +// +SuggestGameInfoDirFn_t SetSuggestGameInfoDirFn( SuggestGameInfoDirFn_t pfnNewFn ); + + +#endif // APPSYSTEMGROUP_H + + diff --git a/public/appframework/VguiMatSysApp.h b/public/appframework/VguiMatSysApp.h new file mode 100644 index 0000000..e40793e --- /dev/null +++ b/public/appframework/VguiMatSysApp.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Material editor +//============================================================================= + +#ifndef VGUIMATSYSAPP_H +#define VGUIMATSYSAPP_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "appframework/tier3app.h" + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CVguiMatSysApp : public CVguiSteamApp +{ + typedef CVguiSteamApp BaseClass; + +public: + CVguiMatSysApp(); + + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit(); + virtual void PostShutdown(); + virtual void Destroy(); + + // Returns the window handle (HWND in Win32) + void* GetAppWindow(); + + // Gets the window size + int GetWindowWidth() const; + int GetWindowHeight() const; + +protected: + void AppPumpMessages(); + + // Sets the video mode + bool SetVideoMode( ); + + // Sets up the game path + bool SetupSearchPaths( const char *pStartingDir, bool bOnlyUseStartingDir, bool bIsTool ); + +private: + // Returns the app name + virtual const char *GetAppName() = 0; + virtual bool AppUsesReadPixels() { return false; } + + // Creates the app window + virtual void *CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ); + + void *m_HWnd; + int m_nWidth; + int m_nHeight; +}; + + +#endif // VGUIMATSYSAPP_H diff --git a/public/appframework/ilaunchermgr.h b/public/appframework/ilaunchermgr.h new file mode 100644 index 0000000..4b433ad --- /dev/null +++ b/public/appframework/ilaunchermgr.h @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// ilaunchermgr.h +// +//================================================================================================== +#ifndef ILAUNCHERMGR_H +#define ILAUNCHERMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#if defined( USE_SDL ) + +#include "tier0/threadtools.h" +#include "appframework/IAppSystem.h" + +#if defined( DX_TO_GL_ABSTRACTION ) +#include "togl/linuxwin/glmgrbasics.h" +#include "togl/linuxwin/glmdisplay.h" + +class GLMDisplayDB; +class CShowPixelsParams; +#endif + +// if you rev this version also update materialsystem/cmaterialsystem.cpp CMaterialSystem::Connect as it defines the string directly +#define SDLMGR_INTERFACE_VERSION "SDLMgrInterface001" + +class CCocoaEvent; +class CStackCrawlParams; + +typedef struct SDL_Cursor SDL_Cursor; + +class ILauncherMgr : public IAppSystem +{ +public: + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + + // Init, shutdown + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + // Create the window. + virtual bool CreateGameWindow( const char *pTitle, bool bWindowed, int width, int height ) = 0; + + virtual void IncWindowRefCount() = 0; + virtual void DecWindowRefCount() = 0; + + // Get the next N events. The function returns the number of events that were filled into your array. + virtual int GetEvents( CCocoaEvent *pEvents, int nMaxEventsToReturn, bool debugEvents = false ) = 0; +#ifdef LINUX + virtual int PeekAndRemoveKeyboardEvents( bool *pbEsc, bool *pbReturn, bool *pbSpace, bool debugEvents = false ) = 0; +#endif + + // Set the mouse cursor position. + virtual void SetCursorPosition( int x, int y ) = 0; + + virtual void SetWindowFullScreen( bool bFullScreen, int nWidth, int nHeight ) = 0; + virtual bool IsWindowFullScreen() = 0; + virtual void MoveWindow( int x, int y ) = 0; + virtual void SizeWindow( int width, int tall ) = 0; + virtual void PumpWindowsMessageLoop() = 0; + + virtual void DestroyGameWindow() = 0; + virtual void SetApplicationIcon( const char *pchAppIconFile ) = 0; + + virtual void GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta = false ) = 0; + + virtual void GetNativeDisplayInfo( int nDisplay, uint &nWidth, uint &nHeight, uint &nRefreshHz ) = 0; // Retrieve the size of the monitor (desktop) + virtual void RenderedSize( uint &width, uint &height, bool set ) = 0; // either set or retrieve rendered size value (from dxabstract) + virtual void DisplayedSize( uint &width, uint &height ) = 0; // query backbuffer size (window size whether FS or windowed) + +#if defined( DX_TO_GL_ABSTRACTION ) + virtual PseudoGLContextPtr GetMainContext() = 0; + // Get the NSGLContext for a window's main view - note this is the carbon windowref as an argument + virtual PseudoGLContextPtr GetGLContextForWindow( void* windowref ) = 0; + virtual PseudoGLContextPtr CreateExtraContext() = 0; + virtual void DeleteContext( PseudoGLContextPtr hContext ) = 0; + virtual bool MakeContextCurrent( PseudoGLContextPtr hContext ) = 0; + virtual GLMDisplayDB *GetDisplayDB( void ) = 0; + virtual void GetDesiredPixelFormatAttribsAndRendererInfo( uint **ptrOut, uint *countOut, GLMRendererInfoFields *rendInfoOut ) = 0; + virtual void ShowPixels( CShowPixelsParams *params ) = 0; +#endif + + virtual void GetStackCrawl( CStackCrawlParams *params ) = 0; + + virtual void WaitUntilUserInput( int msSleepTime ) = 0; + + virtual void *GetWindowRef() = 0; + + virtual void SetMouseVisible( bool bState ) = 0; + virtual void SetMouseCursor( SDL_Cursor *hCursor ) = 0; + virtual void SetForbidMouseGrab( bool bForbidMouseGrab ) = 0; + virtual void OnFrameRendered() = 0; + + virtual void SetGammaRamp( const uint16 *pRed, const uint16 *pGreen, const uint16 *pBlue ) = 0; + + virtual double GetPrevGLSwapWindowTime() = 0; +}; + +extern ILauncherMgr *g_pLauncherMgr; + +enum CocoaEventType_t +{ + CocoaEvent_KeyDown, + CocoaEvent_KeyUp, + CocoaEvent_MouseButtonDown, + CocoaEvent_MouseMove, + CocoaEvent_MouseButtonUp, + CocoaEvent_AppActivate, + CocoaEvent_MouseScroll, + CocoaEvent_AppQuit, + CocoaEvent_Deleted, // Event was one of the above, but has been handled and should be ignored now. +}; + +// enum values need to match bit-shifting logic in CInputSystem::UpdateMouseButtonState and +// the codes from NSEvent pressedMouseButtons, turns out the two are in agreement right now +enum CocoaMouseButton_t +{ + COCOABUTTON_LEFT = 1 << 0, + COCOABUTTON_RIGHT = 1 << 1, + COCOABUTTON_MIDDLE = 1 << 2, + COCOABUTTON_4 = 1 << 3, + COCOABUTTON_5 = 1 << 4, +}; + +enum ECocoaKeyModifier +{ + eCapsLockKey, + eShiftKey, + eControlKey, + eAltKey, // aka option + eCommandKey +}; + +class CCocoaEvent +{ +public: + CocoaEventType_t m_EventType; + int m_VirtualKeyCode; + wchar_t m_UnicodeKey; + wchar_t m_UnicodeKeyUnmodified; + uint m_ModifierKeyMask; // + int m_MousePos[2]; + int m_MouseButtonFlags; // Current state of the mouse buttons. See COCOABUTTON_xxxx. + uint m_nMouseClickCount; + int m_MouseButton; // which of the CocoaMouseButton_t buttons this is for from above +}; + +#endif // defined( USE_SDL ) + +#endif // ILAUNCHERMGR_H diff --git a/public/appframework/tier2app.h b/public/appframework/tier2app.h new file mode 100644 index 0000000..266fc10 --- /dev/null +++ b/public/appframework/tier2app.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The application object for apps that use tier2 +//============================================================================= + +#ifndef TIER2APP_H +#define TIER2APP_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "appframework/AppFramework.h" +#include "tier2/tier2dm.h" +#include "tier1/convar.h" + + +//----------------------------------------------------------------------------- +// The application object for apps that use tier2 +//----------------------------------------------------------------------------- +class CTier2SteamApp : public CSteamAppSystemGroup +{ + typedef CSteamAppSystemGroup BaseClass; + +public: + // Methods of IApplication + virtual bool PreInit() + { + CreateInterfaceFn factory = GetFactory(); + ConnectTier1Libraries( &factory, 1 ); + ConVar_Register( 0 ); + ConnectTier2Libraries( &factory, 1 ); + return true; + } + + virtual void PostShutdown() + { + DisconnectTier2Libraries(); + ConVar_Unregister(); + DisconnectTier1Libraries(); + } +}; + + +//----------------------------------------------------------------------------- +// The application object for apps that use tier2 and datamodel +//----------------------------------------------------------------------------- +class CTier2DmSteamApp : public CTier2SteamApp +{ + typedef CTier2SteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool PreInit() + { + if ( !BaseClass::PreInit() ) + return false; + + CreateInterfaceFn factory = GetFactory(); + if ( !ConnectDataModel( factory ) ) + return false; + + InitReturnVal_t nRetVal = InitDataModel(); + return ( nRetVal == INIT_OK ); + } + + virtual void PostShutdown() + { + ShutdownDataModel(); + DisconnectDataModel(); + BaseClass::PostShutdown(); + } +}; + + +#endif // TIER2APP_H diff --git a/public/appframework/tier3app.h b/public/appframework/tier3app.h new file mode 100644 index 0000000..d180647 --- /dev/null +++ b/public/appframework/tier3app.h @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The application objects for apps that use tier3 +//============================================================================= + +#ifndef TIER3APP_H +#define TIER3APP_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "appframework/tier2app.h" +#include "tier3/tier3.h" +#include "vgui_controls/Controls.h" + + +//----------------------------------------------------------------------------- +// The application object for apps that use tier3 +//----------------------------------------------------------------------------- +class CTier3SteamApp : public CTier2SteamApp +{ + typedef CTier2SteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool PreInit() + { + if ( !BaseClass::PreInit() ) + return false; + + CreateInterfaceFn factory = GetFactory(); + ConnectTier3Libraries( &factory, 1 ); + return true; + } + + virtual void PostShutdown() + { + DisconnectTier3Libraries(); + BaseClass::PostShutdown(); + } +}; + + +//----------------------------------------------------------------------------- +// The application object for apps that use tier3 +//----------------------------------------------------------------------------- +class CTier3DmSteamApp : public CTier2DmSteamApp +{ + typedef CTier2DmSteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool PreInit() + { + if ( !BaseClass::PreInit() ) + return false; + + CreateInterfaceFn factory = GetFactory(); + ConnectTier3Libraries( &factory, 1 ); + return true; + } + + virtual void PostShutdown() + { + DisconnectTier3Libraries(); + BaseClass::PostShutdown(); + } +}; + + +//----------------------------------------------------------------------------- +// The application object for apps that use vgui +//----------------------------------------------------------------------------- +class CVguiSteamApp : public CTier3SteamApp +{ + typedef CTier3SteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool PreInit() + { + if ( !BaseClass::PreInit() ) + return false; + + CreateInterfaceFn factory = GetFactory(); + return vgui::VGui_InitInterfacesList( "CVguiSteamApp", &factory, 1 ); + } +}; + + +//----------------------------------------------------------------------------- +// The application object for apps that use vgui +//----------------------------------------------------------------------------- +class CVguiDmSteamApp : public CTier3DmSteamApp +{ + typedef CTier3DmSteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool PreInit() + { + if ( !BaseClass::PreInit() ) + return false; + + CreateInterfaceFn factory = GetFactory(); + return vgui::VGui_InitInterfacesList( "CVguiSteamApp", &factory, 1 ); + } +}; + + +#endif // TIER3APP_H diff --git a/public/arraystack.h b/public/arraystack.h new file mode 100644 index 0000000..907fb61 --- /dev/null +++ b/public/arraystack.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ARRAYSTACK_H +#define ARRAYSTACK_H +#pragma once + +#include +#include "List.h" + +template class ArrayStack +{ +protected: + T *data; + int m_stackDepth; + int m_maxNumElements; + +public: + ArrayStack( int maxNumElements ) + { + data = new T[maxNumElements]; + m_maxNumElements = maxNumElements; + m_stackDepth = 0; + assert( data ); + } + + void Push( T elem ) + { + data[m_stackDepth++] = elem; + if( m_stackDepth > m_maxNumElements ) + { + printf( "ArrayStack overflow\n" ); + assert( 0 ); + } + } + + T Pop( void ) + { + if( m_stackDepth == 0 ) + { + printf( "ArrayStack underflow\n" ); + assert( 0 ); + } + return data[--m_stackDepth]; + } + + bool IsEmpty() + { + return ( m_stackDepth == 0 ); + } + + int GetDepth() + { + return m_stackDepth; + } +}; + + +#endif // ARRAYSTACK_H diff --git a/public/avi/iavi.h b/public/avi/iavi.h new file mode 100644 index 0000000..1143310 --- /dev/null +++ b/public/avi/iavi.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +//============================================================================= + +#ifndef IAVI_H +#define IAVI_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct BGR888_t; +class IMaterial; + + +//----------------------------------------------------------------------------- +// Parameters for creating a new AVI +//----------------------------------------------------------------------------- +struct AVIParams_t +{ + AVIParams_t() : + m_nFrameRate( 0 ), m_nFrameScale( 1 ), m_nWidth( 0 ), m_nHeight( 0 ), + m_nSampleRate( 0 ), m_nSampleBits( 0 ), m_nNumChannels( 0 ), m_bGetCodecFromUser( true ) + { + m_pFileName[ 0 ] = 0; + } + + char m_pFileName[ 256 ]; + char m_pPathID[ 256 ]; + + // fps = m_nFrameRate / m_nFrameScale + // for integer framerates, set framerate to the fps, and framescale to 1 + // for ntsc-style framerates like 29.97 (or 23.976 or 59.94), + // set framerate to 30,000 (or 24,000 or 60,000) and framescale to 1001 + // yes, framescale is an odd naming choice, but it matching MS's AVI api + int m_nFrameRate; + int m_nFrameScale; + + int m_nWidth; + int m_nHeight; + + // Sound/.wav info + int m_nSampleRate; + int m_nSampleBits; + int m_nNumChannels; + + // The user will be asked to select a compressor if true, otherwise the + // previous or default will be used. + bool m_bGetCodecFromUser; +}; + + +//----------------------------------------------------------------------------- +// Handle to an AVI +//----------------------------------------------------------------------------- +typedef unsigned short AVIHandle_t; +enum +{ + AVIHANDLE_INVALID = (AVIHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Handle to an AVI material +//----------------------------------------------------------------------------- +typedef unsigned short AVIMaterial_t; +enum +{ + AVIMATERIAL_INVALID = (AVIMaterial_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Main AVI interface +//----------------------------------------------------------------------------- +#define AVI_INTERFACE_VERSION "VAvi001" + +class IAvi : public IAppSystem +{ +public: + // Necessary to call this before any other AVI interface methods + virtual void SetMainWindow( void* hWnd ) = 0; + + // Start/stop recording an AVI + virtual AVIHandle_t StartAVI( const AVIParams_t& params ) = 0; + virtual void FinishAVI( AVIHandle_t handle ) = 0; + + // Add frames to an AVI + virtual void AppendMovieSound( AVIHandle_t h, short *buf, size_t bufsize ) = 0; + virtual void AppendMovieFrame( AVIHandle_t h, const BGR888_t *pRGBData ) = 0; + + // Create/destroy an AVI material (a materialsystem IMaterial) + virtual AVIMaterial_t CreateAVIMaterial( const char *pMaterialName, const char *pFileName, const char *pPathID ) = 0; + virtual void DestroyAVIMaterial( AVIMaterial_t hMaterial ) = 0; + + // Sets the time for an AVI material + virtual void SetTime( AVIMaterial_t hMaterial, float flTime ) = 0; + + // Gets the IMaterial associated with an AVI material + virtual IMaterial* GetMaterial( AVIMaterial_t hMaterial ) = 0; + + // Returns the max texture coordinate of the AVI + virtual void GetTexCoordRange( AVIMaterial_t hMaterial, float *pMaxU, float *pMaxV ) = 0; + + // Returns the frame size of the AVI (stored in a subrect of the material itself) + virtual void GetFrameSize( AVIMaterial_t hMaterial, int *pWidth, int *pHeight ) = 0; + + // Returns the frame rate of the AVI + virtual int GetFrameRate( AVIMaterial_t hMaterial ) = 0; + + // Returns the total frame count of the AVI + virtual int GetFrameCount( AVIMaterial_t hMaterial ) = 0; + + // Sets the frame for an AVI material (use instead of SetTime) + virtual void SetFrame( AVIMaterial_t hMaterial, float flFrame ) = 0; + + // Plays a given AVI/WMV file until it completes or the user presses ESC, SPACE, or ENTER + virtual void PlayWindowsMediaVideo( const char *filename, void *mainWindow, int width, int height, float forcedMinTime ) = 0; + +}; + + + +#endif // IAVI_H diff --git a/public/avi/iquicktime.h b/public/avi/iquicktime.h new file mode 100644 index 0000000..83867e7 --- /dev/null +++ b/public/avi/iquicktime.h @@ -0,0 +1,174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +//============================================================================= + +#ifndef IQUICKTIME_H +#define IQUICKTIME_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "appframework/IAppSystem.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct BGR888_t; +class IMaterial; + + +//----------------------------------------------------------------------------- +// Handle to a QUICKTIME +//----------------------------------------------------------------------------- +typedef unsigned short QUICKTIMEHandle_t; +enum +{ + QUICKTIMEHANDLE_INVALID = (QUICKTIMEHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Handle to an QUICKTIME material +//----------------------------------------------------------------------------- +typedef unsigned short QUICKTIMEMaterial_t; +enum +{ + QUICKTIMEMATERIAL_INVALID = (QUICKTIMEMaterial_t)~0 +}; + +typedef unsigned int MovieHandle_t; +const MovieHandle_t cInvalidMovieHandle = (MovieHandle_t) ~0; + +enum eVideoSystemStatus +{ + cVideoSystem_OK = 0, + cVideoSystem_NotInstalled, + cVideoSystem_NotCurrentVersion, + cVideoSystem_InitializationError, + + cVideoSystem_ForceInt32 = 0x7FFFFFFF // Make sure eNum is (at least) an int32 +}; + + +enum eVideoSystemFeatures +{ + cVideoSystem_NoFeatures = 0x00000000, + cVideoSystem_PlayMoviesFromFile = 0x00000001, + cVideoSystem_RenderVideoFrameToMaterial = 0x00000002, + cVideoSystem_EncodeVideoToFile = 0x00000010, + cVideoSystem_EncodeAudioToFile = 0x00000020, + + cVideoSystem_ForceInt32a = 0x7FFFFFFF +}; + +DEFINE_ENUM_BITWISE_OPERATORS( eVideoSystemFeatures ); + +enum eVideoEncodeQuality +{ + cVEQuality_Min = 0, + cVEQuality_Low = 25, + cVEQuality_Normal = 50, + cVEQuality_High = 75, + cVEQuality_Max = 100 +}; + +// ----------------------------------------------------------------------- +// eVideoFrameFormat_t - bit format for quicktime video frames +// ----------------------------------------------------------------------- +enum eVideoFrameFormat_t +{ + cVFF_Undefined = 0, + cVFF_R8G8B8A8_32Bit, + cVFF_R8G8B8_24Bit, + + cVFF_Count, // Auto list counter + cVFF_ForceInt32 = 0x7FFFFFFF // Make sure eNum is (at least) an int32 +}; + +// ----------------------------------------------------------------------- +// eAudioSourceFormat_t - Audio encoding source options +// ----------------------------------------------------------------------- +enum eAudioSourceFormat_t +{ + cASF_Undefined = 0, + cASF_None, + cASF_16BitPCMStereo, + + cASF_Count, // Auto list counter + cASF_ForceInt32 = 0x7FFFFFFF // Make sure eNum is (at least) an int32 +}; + + + +//----------------------------------------------------------------------------- +// IQuickTimeMovieMaker interface +//----------------------------------------------------------------------------- +class IQuickTimeMovieMaker : public IBaseInterface +{ +public: + virtual bool CreateNewMovieFile( MovieHandle_t &theMovie, const char *pFilename, int nWidth, int nHeight, int nFps, eVideoEncodeQuality quality, eAudioSourceFormat_t srcAudioFormat = cASF_None, int audioSampleRate = 0 ) = 0; + virtual bool AppendVideoFrame( MovieHandle_t theMovie, unsigned char *pFrame ) = 0; + virtual bool AppendAudioSamples( MovieHandle_t theMovie, void *sampleBuffer, size_t sampleSize ) = 0; + virtual bool FinishMovie( MovieHandle_t theMovie, bool success = true ) = 0; +}; + +//----------------------------------------------------------------------------- +// Main QUICKTIME interface +//----------------------------------------------------------------------------- +#define QUICKTIME_INTERFACE_VERSION "IQuickTime002" + +class IQuickTime : public IAppSystem +{ +public: + virtual bool IsVideoSystemAvailable() = 0; + virtual eVideoSystemStatus GetVideoSystemStatus() = 0; + virtual eVideoSystemFeatures GetVideoSystemFeatures() = 0; + + // Create/destroy a QUICKTIME material (a materialsystem IMaterial) + virtual QUICKTIMEMaterial_t CreateMaterial( const char *pMaterialName, const char *pFileName, const char *pPathID ) = 0; + virtual void DestroyMaterial( QUICKTIMEMaterial_t hMaterial ) = 0; + + // Create/destroy a quicktime movie maker, which will encode audio/video + virtual IQuickTimeMovieMaker *CreateMovieMaker() = 0; + virtual void DestroyMovieMaker( IQuickTimeMovieMaker *&pMovieMaker ) = 0; + + // Update the frame (if necessary) + virtual bool Update( QUICKTIMEMaterial_t hMaterial ) = 0; + + // Gets the IMaterial associated with an BINK material + virtual IMaterial* GetMaterial( QUICKTIMEMaterial_t hMaterial ) = 0; + + // Returns the max texture coordinate of the BINK + virtual void GetTexCoordRange( QUICKTIMEMaterial_t hMaterial, float *pMaxU, float *pMaxV ) = 0; + + // Returns the frame size of the QUICKTIME Image Frame (stored in a subrect of the material itself) + virtual void GetFrameSize( QUICKTIMEMaterial_t hMaterial, int *pWidth, int *pHeight ) = 0; + + // Returns the frame rate of the QUICKTIME + virtual int GetFrameRate( QUICKTIMEMaterial_t hMaterial ) = 0; + + // Sets the frame for an BINK material (use instead of SetTime) + virtual void SetFrame( QUICKTIMEMaterial_t hMaterial, float flFrame ) = 0; + + // Returns the total frame count of the BINK + virtual int GetFrameCount( QUICKTIMEMaterial_t hMaterial ) = 0; + + virtual bool SetSoundDevice( void *pDevice ) = 0; + + // Plays a given MOV file until it completes or the user presses ESC, SPACE, or ENTER + virtual void PlayQuicktimeVideo( const char *filename, void *mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime ) = 0; + + // Estimates the size of a recorded movie + virtual bool EstimateMovieSize( unsigned long &EstSize, int nWidth, int nHeight, int nFps, float duration, eVideoEncodeQuality quality, eAudioSourceFormat_t srcAudioFormat = cASF_None, int audioSampleRate = 0 ) = 0; + +}; + + +#endif // IQUICKTIME_H diff --git a/public/basehandle.h b/public/basehandle.h new file mode 100644 index 0000000..91eb02d --- /dev/null +++ b/public/basehandle.h @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASEHANDLE_H +#define BASEHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "const.h" +#include "tier0/dbg.h" + + +class IHandleEntity; + + +// -------------------------------------------------------------------------------------------------- // +// CBaseHandle. +// -------------------------------------------------------------------------------------------------- // + +class CBaseHandle +{ +friend class CBaseEntityList; + +public: + + CBaseHandle(); + CBaseHandle( const CBaseHandle &other ); + CBaseHandle( unsigned long value ); + CBaseHandle( int iEntry, int iSerialNumber ); + + void Init( int iEntry, int iSerialNumber ); + void Term(); + + // Even if this returns true, Get() still can return return a non-null value. + // This just tells if the handle has been initted with any values. + bool IsValid() const; + + int GetEntryIndex() const; + int GetSerialNumber() const; + + int ToInt() const; + bool operator !=( const CBaseHandle &other ) const; + bool operator ==( const CBaseHandle &other ) const; + bool operator ==( const IHandleEntity* pEnt ) const; + bool operator !=( const IHandleEntity* pEnt ) const; + bool operator <( const CBaseHandle &other ) const; + bool operator <( const IHandleEntity* pEnt ) const; + + // Assign a value to the handle. + const CBaseHandle& operator=( const IHandleEntity *pEntity ); + const CBaseHandle& Set( const IHandleEntity *pEntity ); + + // Use this to dereference the handle. + // Note: this is implemented in game code (ehandle.h) + IHandleEntity* Get() const; + + +protected: + // The low NUM_SERIAL_BITS hold the index. If this value is less than MAX_EDICTS, then the entity is networkable. + // The high NUM_SERIAL_NUM_BITS bits are the serial number. + unsigned long m_Index; +}; + + +#include "ihandleentity.h" + + +inline CBaseHandle::CBaseHandle() +{ + m_Index = INVALID_EHANDLE_INDEX; +} + +inline CBaseHandle::CBaseHandle( const CBaseHandle &other ) +{ + m_Index = other.m_Index; +} + +inline CBaseHandle::CBaseHandle( unsigned long value ) +{ + m_Index = value; +} + +inline CBaseHandle::CBaseHandle( int iEntry, int iSerialNumber ) +{ + Init( iEntry, iSerialNumber ); +} + +inline void CBaseHandle::Init( int iEntry, int iSerialNumber ) +{ + Assert( iEntry >= 0 && iEntry < NUM_ENT_ENTRIES ); + Assert( iSerialNumber >= 0 && iSerialNumber < (1 << NUM_SERIAL_NUM_BITS) ); + + m_Index = iEntry | (iSerialNumber << NUM_ENT_ENTRY_BITS); +} + +inline void CBaseHandle::Term() +{ + m_Index = INVALID_EHANDLE_INDEX; +} + +inline bool CBaseHandle::IsValid() const +{ + return m_Index != INVALID_EHANDLE_INDEX; +} + +inline int CBaseHandle::GetEntryIndex() const +{ + return m_Index & ENT_ENTRY_MASK; +} + +inline int CBaseHandle::GetSerialNumber() const +{ + return m_Index >> NUM_ENT_ENTRY_BITS; +} + +inline int CBaseHandle::ToInt() const +{ + return (int)m_Index; +} + +inline bool CBaseHandle::operator !=( const CBaseHandle &other ) const +{ + return m_Index != other.m_Index; +} + +inline bool CBaseHandle::operator ==( const CBaseHandle &other ) const +{ + return m_Index == other.m_Index; +} + +inline bool CBaseHandle::operator ==( const IHandleEntity* pEnt ) const +{ + return Get() == pEnt; +} + +inline bool CBaseHandle::operator !=( const IHandleEntity* pEnt ) const +{ + return Get() != pEnt; +} + +inline bool CBaseHandle::operator <( const CBaseHandle &other ) const +{ + return m_Index < other.m_Index; +} + +inline bool CBaseHandle::operator <( const IHandleEntity *pEntity ) const +{ + unsigned long otherIndex = (pEntity) ? pEntity->GetRefEHandle().m_Index : INVALID_EHANDLE_INDEX; + return m_Index < otherIndex; +} + +inline const CBaseHandle& CBaseHandle::operator=( const IHandleEntity *pEntity ) +{ + return Set( pEntity ); +} + +inline const CBaseHandle& CBaseHandle::Set( const IHandleEntity *pEntity ) +{ + if ( pEntity ) + { + *this = pEntity->GetRefEHandle(); + } + else + { + m_Index = INVALID_EHANDLE_INDEX; + } + + return *this; +} + + +#endif // BASEHANDLE_H diff --git a/public/bitmap/bitmap.h b/public/bitmap/bitmap.h new file mode 100644 index 0000000..bc56ed2 --- /dev/null +++ b/public/bitmap/bitmap.h @@ -0,0 +1,142 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef BITMAP_H +#define BITMAP_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "bitmap/imageformat.h" +#include "Color.h" +#include "dbg.h" + +class CUtlBuffer; + +//----------------------------------------------------------------------------- +// A Bitmap +//----------------------------------------------------------------------------- +struct Bitmap_t +{ + Bitmap_t() { Reset(); } + ~Bitmap_t() { Clear(); } + + // + // Accessors + // + inline int Width() const { return m_nWidth; } + inline int Height() const { return m_nHeight; } + inline ImageFormat Format() const { return m_ImageFormat; } + inline unsigned char *GetBits() const { return m_pBits; } + inline int Stride() const { return m_nStride; } + inline bool GetOwnsBuffer() const { return m_bOwnsBuffer; } + + /// Allocate the buffer. Discards existing data, freeing it if we own it + void Init( int nWidth, int nHeight, ImageFormat imageFormat, int nStride = 0 ); + + /// Set the bitmap to the specified buffer. Any existing data is discarded/freed + /// as appropriate. + void SetBuffer( int nWidth, int nHeight, ImageFormat imageFormat, unsigned char *pBits, bool bAssumeOwnership, int nStride = 0 ); + + /// Sets / releases ownershp of the buffer. This does not otherwise alter the + /// state of the bitmap. + void SetOwnsBuffer( bool bOwnsBuffer ) + { + Assert( m_pBits ); + m_bOwnsBuffer = bOwnsBuffer; + } + + /// Free up all memory and reset to default state + void Clear(); + + /// Return true if we have a valid size and buffer + bool IsValid() const; + + /// Get pointer to raw pixel data. + unsigned char *GetPixel( int x, int y ); + const unsigned char *GetPixel( int x, int y ) const; + + /// Get pixel value at specified coordinates + Color GetColor( int x, int y ) const; + + /// Set pixel value at specified coordinates + void SetColor( int x, int y, Color c ); + + /// Set this bitmap to be a logical copy of the specified + /// bitmap. No memory is allocated or copied, just copying + /// some pointers. We can also optionally transfer ownership + /// of the buffer. + void MakeLogicalCopyOf( Bitmap_t &src, bool bTransferBufferOwnership = false ); + + /// Set this bitmap to be a cropped rectangle from the given bitmap. + /// The source pointer can be NULL or point to this, which means to do + /// the crop in place. + void Crop( int x0, int y0, int nWidth, int nHeight, const Bitmap_t *pImgSource = NULL ); + + /// Blit a rectangle of pixel data into this image. + void SetPixelData( const Bitmap_t &src, int nSrcX1, int nSrcY1, int nCopySizeX, int nCopySizeY, int nDestX1, int nDestY1 ); + + /// Blit the entire source image into this image, at the specified offset. + /// the rectangle is clipped if necessary + void SetPixelData( const Bitmap_t &src, int nDestX1 = 0, int nDestY1 = 0 ); + +private: + void Reset(); + + /// Dimensions + int m_nWidth; + int m_nHeight; + + /// Size, in bytes, of one pixel + int m_nPixelSize; + + /// Image row stride, in bytes + int m_nStride; + + // Do we own this buffer? + bool m_bOwnsBuffer; + + /// Pixel format + ImageFormat m_ImageFormat; + + /// Bitmap data. Must be allocated with malloc/free. Don't use + /// new/delete + unsigned char *m_pBits; +}; + +inline void Bitmap_t::Reset() +{ + m_nWidth = 0; + m_nHeight = 0; + m_ImageFormat = IMAGE_FORMAT_UNKNOWN; + m_pBits = NULL; + m_nPixelSize = 0; + m_bOwnsBuffer = false; + m_nStride = 0; +} + +inline unsigned char *Bitmap_t::GetPixel( int x, int y ) +{ + if ( !m_pBits ) + return NULL; + + return m_pBits + (y*m_nStride) + x* m_nPixelSize; +} + +inline const unsigned char *Bitmap_t::GetPixel( int x, int y ) const +{ + if ( !m_pBits ) + return NULL; + + return m_pBits + (y*m_nStride) + x* m_nPixelSize; +} + + +#endif // BITMAP_H diff --git a/public/bitmap/cubemap.h b/public/bitmap/cubemap.h new file mode 100644 index 0000000..1bda06f --- /dev/null +++ b/public/bitmap/cubemap.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: a class for performing cube-mapped spherical sample lookups. +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef CUBEMAP_H +#define CUBEMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/utlmemory.h" +#include "mathlib/mathlib.h" + +template struct CCubeMap +{ + T m_Samples[6][RES][RES]; + +public: + FORCEINLINE void GetCoords( Vector const &vecNormalizedDirection, int &nX, int &nY, int &nFace ) + { + // find largest magnitude component + int nLargest = 0; + int nAxis0 = 1; + int nAxis1 = 2; + if ( fabs( vecNormalizedDirection[1] ) > fabs( vecNormalizedDirection[0] ) ) + { + nLargest = 1; + nAxis0 = 0; + nAxis1 = 2; + } + if ( fabs( vecNormalizedDirection[2] ) > fabs( vecNormalizedDirection[nLargest] ) ) + { + nLargest = 2; + nAxis0 = 0; + nAxis1 = 1; + } + float flZ = vecNormalizedDirection[nLargest]; + if ( flZ < 0 ) + { + flZ = - flZ; + nLargest += 3; + } + nFace = nLargest; + flZ = 1.0 / flZ; + nX = RemapValClamped( vecNormalizedDirection[nAxis0] * flZ, -1, 1, 0, RES - 1 ); + nY = RemapValClamped( vecNormalizedDirection[nAxis1] * flZ, -1, 1, 0, RES - 1 ); + } + + FORCEINLINE T & GetSample( Vector const &vecNormalizedDirection ) + { + int nX, nY, nFace; + GetCoords( vecNormalizedDirection, nX, nY, nFace ); + return m_Samples[nFace][nX][nY]; + } +}; + + + + + +#endif // CUBEMAP_H diff --git a/public/bitmap/float_bm.h b/public/bitmap/float_bm.h new file mode 100644 index 0000000..94920eb --- /dev/null +++ b/public/bitmap/float_bm.h @@ -0,0 +1,363 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef FLOAT_BM_H +#define FLOAT_BM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier0/dbg.h" +#include + +struct PixRGBAF +{ + float Red; + float Green; + float Blue; + float Alpha; +}; + +struct PixRGBA8 +{ + unsigned char Red; + unsigned char Green; + unsigned char Blue; + unsigned char Alpha; +}; + +inline PixRGBAF PixRGBA8_to_F( PixRGBA8 const &x ) +{ + PixRGBAF f; + f.Red = x.Red / float( 255.0f ); + f.Green = x.Green / float( 255.0f ); + f.Blue = x.Blue / float( 255.0f ); + f.Alpha = x.Alpha / float( 255.0f ); + return f; +} + +inline PixRGBA8 PixRGBAF_to_8( PixRGBAF const &f ) +{ + PixRGBA8 x; + x.Red = vmax( 0, vmin( 255.0,255.0*f.Red ) ); + x.Green = vmax( 0, vmin( 255.0,255.0*f.Green ) ); + x.Blue = vmax( 0, vmin( 255.0,255.0*f.Blue ) ); + x.Alpha = vmax( 0, vmin( 255.0,255.0*f.Alpha ) ); + return x; +} + +#define SPFLAGS_MAXGRADIENT 1 + +// bit flag options for ComputeSelfShadowedBumpmapFromHeightInAlphaChannel: +#define SSBUMP_OPTION_NONDIRECTIONAL 1 // generate ambient occlusion only +#define SSBUMP_MOD2X_DETAIL_TEXTURE 2 // scale so that a flat unshadowed + // value is 0.5, and bake rgb luminance + // in. + + + +class FloatBitMap_t +{ +public: + int Width, Height; // bitmap dimensions + float *RGBAData; // actual data + + FloatBitMap_t(void) // empty one + { + Width=Height=0; + RGBAData=0; + } + + + + FloatBitMap_t(int width, int height); // make one and allocate space + FloatBitMap_t(char const *filename); // read one from a file (tga or pfm) + FloatBitMap_t(FloatBitMap_t const *orig); + // quantize one to 8 bits + bool WriteTGAFile(char const *filename) const; + + bool LoadFromPFM(char const *filename); // load from floating point pixmap (.pfm) file + bool WritePFM(char const *filename); // save to floating point pixmap (.pfm) file + + + void InitializeWithRandomPixelsFromAnotherFloatBM(FloatBitMap_t const &other); + + inline float & Pixel(int x, int y, int comp) const + { + Assert((x>=0) && (x=0) && (y= Width) + x -= Width; + + if ( y < 0 ) + y+=Height; + else + if ( y >= Height ) + y -= Height; + + return RGBAData[4*(x+Width*y)+comp]; + } + + inline float & PixelClamped(int x, int y, int comp) const + { + // like Pixel except wraps around to other side + x=clamp(x,0,Width-1); + y=clamp(y,0,Height-1); + return RGBAData[4*(x+Width*y)+comp]; + } + + + inline float & Alpha(int x, int y) const + { + Assert((x>=0) && (x=0) && (y=0) && (x=0) && (y=0) && (x=0) && (y=0) && (x=0) && (y + +enum NormalDecodeMode_t +{ + NORMAL_DECODE_NONE = 0, + NORMAL_DECODE_ATI2N = 1, + NORMAL_DECODE_ATI2N_ALPHA = 2 +}; + +// Forward declaration +#ifdef _WIN32 +typedef enum _D3DFORMAT D3DFORMAT; +#endif + +//----------------------------------------------------------------------------- +// The various image format types +//----------------------------------------------------------------------------- + +// don't bitch that inline functions aren't used!!!! +#pragma warning(disable : 4514) + +enum ImageFormat +{ + IMAGE_FORMAT_UNKNOWN = -1, + IMAGE_FORMAT_RGBA8888 = 0, + IMAGE_FORMAT_ABGR8888, + IMAGE_FORMAT_RGB888, + IMAGE_FORMAT_BGR888, + IMAGE_FORMAT_RGB565, + IMAGE_FORMAT_I8, + IMAGE_FORMAT_IA88, + IMAGE_FORMAT_P8, + IMAGE_FORMAT_A8, + IMAGE_FORMAT_RGB888_BLUESCREEN, + IMAGE_FORMAT_BGR888_BLUESCREEN, + IMAGE_FORMAT_ARGB8888, + IMAGE_FORMAT_BGRA8888, + IMAGE_FORMAT_DXT1, + IMAGE_FORMAT_DXT3, + IMAGE_FORMAT_DXT5, + IMAGE_FORMAT_BGRX8888, + IMAGE_FORMAT_BGR565, + IMAGE_FORMAT_BGRX5551, + IMAGE_FORMAT_BGRA4444, + IMAGE_FORMAT_DXT1_ONEBITALPHA, + IMAGE_FORMAT_BGRA5551, + IMAGE_FORMAT_UV88, + IMAGE_FORMAT_UVWQ8888, + IMAGE_FORMAT_RGBA16161616F, + IMAGE_FORMAT_RGBA16161616, + IMAGE_FORMAT_UVLX8888, + IMAGE_FORMAT_R32F, // Single-channel 32-bit floating point + IMAGE_FORMAT_RGB323232F, + IMAGE_FORMAT_RGBA32323232F, + + // Depth-stencil texture formats for shadow depth mapping + IMAGE_FORMAT_NV_DST16, // + IMAGE_FORMAT_NV_DST24, // + IMAGE_FORMAT_NV_INTZ, // Vendor-specific depth-stencil texture + IMAGE_FORMAT_NV_RAWZ, // formats for shadow depth mapping + IMAGE_FORMAT_ATI_DST16, // + IMAGE_FORMAT_ATI_DST24, // + IMAGE_FORMAT_NV_NULL, // Dummy format which takes no video memory + + // Compressed normal map formats + IMAGE_FORMAT_ATI2N, // One-surface ATI2N / DXN format + IMAGE_FORMAT_ATI1N, // Two-surface ATI1N format + +#if defined( _X360 ) + // Depth-stencil texture formats + IMAGE_FORMAT_X360_DST16, + IMAGE_FORMAT_X360_DST24, + IMAGE_FORMAT_X360_DST24F, + // supporting these specific formats as non-tiled for procedural cpu access + IMAGE_FORMAT_LINEAR_BGRX8888, + IMAGE_FORMAT_LINEAR_RGBA8888, + IMAGE_FORMAT_LINEAR_ABGR8888, + IMAGE_FORMAT_LINEAR_ARGB8888, + IMAGE_FORMAT_LINEAR_BGRA8888, + IMAGE_FORMAT_LINEAR_RGB888, + IMAGE_FORMAT_LINEAR_BGR888, + IMAGE_FORMAT_LINEAR_BGRX5551, + IMAGE_FORMAT_LINEAR_I8, + IMAGE_FORMAT_LINEAR_RGBA16161616, + + IMAGE_FORMAT_LE_BGRX8888, + IMAGE_FORMAT_LE_BGRA8888, +#endif + + IMAGE_FORMAT_DXT1_RUNTIME, + IMAGE_FORMAT_DXT5_RUNTIME, + + NUM_IMAGE_FORMATS +}; + +#if defined( POSIX ) || defined( DX_TO_GL_ABSTRACTION ) +typedef enum _D3DFORMAT + { + D3DFMT_INDEX16, + D3DFMT_D16, + D3DFMT_D24S8, + D3DFMT_A8R8G8B8, + D3DFMT_A4R4G4B4, + D3DFMT_X8R8G8B8, + D3DFMT_R5G6R5, + D3DFMT_X1R5G5B5, + D3DFMT_A1R5G5B5, + D3DFMT_L8, + D3DFMT_A8L8, + D3DFMT_A, + D3DFMT_DXT1, + D3DFMT_DXT3, + D3DFMT_DXT5, + D3DFMT_V8U8, + D3DFMT_Q8W8V8U8, + D3DFMT_X8L8V8U8, + D3DFMT_A16B16G16R16F, + D3DFMT_A16B16G16R16, + D3DFMT_R32F, + D3DFMT_A32B32G32R32F, + D3DFMT_R8G8B8, + D3DFMT_D24X4S4, + D3DFMT_A8, + D3DFMT_R5G6B5, + D3DFMT_D15S1, + D3DFMT_D24X8, + D3DFMT_VERTEXDATA, + D3DFMT_INDEX32, + + // adding fake D3D format names for the vendor specific ones (eases debugging/logging) + + // NV shadow depth tex + D3DFMT_NV_INTZ = 0x5a544e49, // MAKEFOURCC('I','N','T','Z') + D3DFMT_NV_RAWZ = 0x5a574152, // MAKEFOURCC('R','A','W','Z') + + // NV null tex + D3DFMT_NV_NULL = 0x4c4c554e, // MAKEFOURCC('N','U','L','L') + + // ATI shadow depth tex + D3DFMT_ATI_D16 = 0x36314644, // MAKEFOURCC('D','F','1','6') + D3DFMT_ATI_D24S8 = 0x34324644, // MAKEFOURCC('D','F','2','4') + + // ATI 1N and 2N compressed tex + D3DFMT_ATI_2N = 0x32495441, // MAKEFOURCC('A', 'T', 'I', '2') + D3DFMT_ATI_1N = 0x31495441, // MAKEFOURCC('A', 'T', 'I', '1') + + D3DFMT_UNKNOWN + } D3DFORMAT; +#endif + +//----------------------------------------------------------------------------- +// Color structures +//----------------------------------------------------------------------------- + +struct BGRA8888_t +{ + unsigned char b; // change the order of names to change the + unsigned char g; // order of the output ARGB or BGRA, etc... + unsigned char r; // Last one is MSB, 1st is LSB. + unsigned char a; + inline BGRA8888_t& operator=( const BGRA8888_t& in ) + { + *( unsigned int * )this = *( unsigned int * )∈ + return *this; + } +}; + +struct RGBA8888_t +{ + unsigned char r; // change the order of names to change the + unsigned char g; // order of the output ARGB or BGRA, etc... + unsigned char b; // Last one is MSB, 1st is LSB. + unsigned char a; + inline RGBA8888_t& operator=( const BGRA8888_t& in ) + { + r = in.r; + g = in.g; + b = in.b; + a = in.a; + return *this; + } +}; + +struct RGB888_t +{ + unsigned char r; + unsigned char g; + unsigned char b; + inline RGB888_t& operator=( const BGRA8888_t& in ) + { + r = in.r; + g = in.g; + b = in.b; + return *this; + } + inline bool operator==( const RGB888_t& in ) const + { + return ( r == in.r ) && ( g == in.g ) && ( b == in.b ); + } + inline bool operator!=( const RGB888_t& in ) const + { + return ( r != in.r ) || ( g != in.g ) || ( b != in.b ); + } +}; + +struct BGR888_t +{ + unsigned char b; + unsigned char g; + unsigned char r; + inline BGR888_t& operator=( const BGRA8888_t& in ) + { + r = in.r; + g = in.g; + b = in.b; + return *this; + } +}; + +// 360 uses this structure for x86 dxt decoding +#if defined( _X360 ) +#pragma bitfield_order( push, lsb_to_msb ) +#endif +struct BGR565_t +{ + unsigned short b : 5; // order of names changes + unsigned short g : 6; // byte order of output to 32 bit + unsigned short r : 5; + inline BGR565_t& operator=( const BGRA8888_t& in ) + { + r = in.r >> 3; + g = in.g >> 2; + b = in.b >> 3; + return *this; + } + inline BGR565_t &Set( int red, int green, int blue ) + { + r = red >> 3; + g = green >> 2; + b = blue >> 3; + return *this; + } +}; +#if defined( _X360 ) +#pragma bitfield_order( pop ) +#endif + +struct BGRA5551_t +{ + unsigned short b : 5; // order of names changes + unsigned short g : 5; // byte order of output to 32 bit + unsigned short r : 5; + unsigned short a : 1; + inline BGRA5551_t& operator=( const BGRA8888_t& in ) + { + r = in.r >> 3; + g = in.g >> 3; + b = in.b >> 3; + a = in.a >> 7; + return *this; + } +}; + +struct BGRA4444_t +{ + unsigned short b : 4; // order of names changes + unsigned short g : 4; // byte order of output to 32 bit + unsigned short r : 4; + unsigned short a : 4; + inline BGRA4444_t& operator=( const BGRA8888_t& in ) + { + r = in.r >> 4; + g = in.g >> 4; + b = in.b >> 4; + a = in.a >> 4; + return *this; + } +}; + +struct RGBX5551_t +{ + unsigned short r : 5; + unsigned short g : 5; + unsigned short b : 5; + unsigned short x : 1; + inline RGBX5551_t& operator=( const BGRA8888_t& in ) + { + r = in.r >> 3; + g = in.g >> 3; + b = in.b >> 3; + return *this; + } +}; + +//----------------------------------------------------------------------------- +// some important constants +//----------------------------------------------------------------------------- +#define ARTWORK_GAMMA ( 2.2f ) +#define IMAGE_MAX_DIM ( 2048 ) + + +//----------------------------------------------------------------------------- +// information about each image format +//----------------------------------------------------------------------------- +struct ImageFormatInfo_t +{ + const char* m_pName; + int m_NumBytes; + int m_NumRedBits; + int m_NumGreeBits; + int m_NumBlueBits; + int m_NumAlphaBits; + bool m_IsCompressed; +}; + + +//----------------------------------------------------------------------------- +// Various methods related to pixelmaps and color formats +//----------------------------------------------------------------------------- +namespace ImageLoader +{ + + bool GetInfo( const char *fileName, int *width, int *height, enum ImageFormat *imageFormat, float *sourceGamma ); + int GetMemRequired( int width, int height, int depth, ImageFormat imageFormat, bool mipmap ); + int GetMipMapLevelByteOffset( int width, int height, enum ImageFormat imageFormat, int skipMipLevels ); + void GetMipMapLevelDimensions( int *width, int *height, int skipMipLevels ); + int GetNumMipMapLevels( int width, int height, int depth = 1 ); + bool Load( unsigned char *imageData, const char *fileName, int width, int height, enum ImageFormat imageFormat, float targetGamma, bool mipmap ); + bool Load( unsigned char *imageData, FILE *fp, int width, int height, + enum ImageFormat imageFormat, float targetGamma, bool mipmap ); + + // convert from any image format to any other image format. + // return false if the conversion cannot be performed. + // Strides denote the number of bytes per each line, + // by default assumes width * # of bytes per pixel + bool ConvertImageFormat( const unsigned char *src, enum ImageFormat srcImageFormat, + unsigned char *dst, enum ImageFormat dstImageFormat, + int width, int height, int srcStride = 0, int dstStride = 0 ); + + // must be used in conjunction with ConvertImageFormat() to pre-swap and post-swap + void PreConvertSwapImageData( unsigned char *pImageData, int nImageSize, ImageFormat imageFormat, int width = 0, int stride = 0 ); + void PostConvertSwapImageData( unsigned char *pImageData, int nImageSize, ImageFormat imageFormat, int width = 0, int stride = 0 ); + void ByteSwapImageData( unsigned char *pImageData, int nImageSize, ImageFormat imageFormat, int width = 0, int stride = 0 ); + bool IsFormatValidForConversion( ImageFormat fmt ); + + //----------------------------------------------------------------------------- + // convert back and forth from D3D format to ImageFormat, regardless of + // whether it's supported or not + //----------------------------------------------------------------------------- + ImageFormat D3DFormatToImageFormat( D3DFORMAT format ); + D3DFORMAT ImageFormatToD3DFormat( ImageFormat format ); + + // Flags for ResampleRGBA8888 + enum + { + RESAMPLE_NORMALMAP = 0x1, + RESAMPLE_ALPHATEST = 0x2, + RESAMPLE_NICE_FILTER = 0x4, + RESAMPLE_CLAMPS = 0x8, + RESAMPLE_CLAMPT = 0x10, + RESAMPLE_CLAMPU = 0x20, + }; + + struct ResampleInfo_t + { + + ResampleInfo_t() : m_nFlags(0), m_flAlphaThreshhold(0.4f), m_flAlphaHiFreqThreshhold(0.4f), m_nSrcDepth(1), m_nDestDepth(1) + { + m_flColorScale[0] = 1.0f, m_flColorScale[1] = 1.0f, m_flColorScale[2] = 1.0f, m_flColorScale[3] = 1.0f; + m_flColorGoal[0] = 0.0f, m_flColorGoal[1] = 0.0f, m_flColorGoal[2] = 0.0f, m_flColorGoal[3] = 0.0f; + } + + unsigned char *m_pSrc; + unsigned char *m_pDest; + + int m_nSrcWidth; + int m_nSrcHeight; + int m_nSrcDepth; + + int m_nDestWidth; + int m_nDestHeight; + int m_nDestDepth; + + float m_flSrcGamma; + float m_flDestGamma; + + float m_flColorScale[4]; // Color scale factors RGBA + float m_flColorGoal[4]; // Color goal values RGBA DestColor = ColorGoal + scale * (SrcColor - ColorGoal) + + float m_flAlphaThreshhold; + float m_flAlphaHiFreqThreshhold; + + int m_nFlags; + }; + + bool ResampleRGBA8888( const ResampleInfo_t &info ); + bool ResampleRGBA16161616( const ResampleInfo_t &info ); + bool ResampleRGB323232F( const ResampleInfo_t &info ); + + void ConvertNormalMapRGBA8888ToDUDVMapUVLX8888( const unsigned char *src, int width, int height, + unsigned char *dst_ ); + void ConvertNormalMapRGBA8888ToDUDVMapUVWQ8888( const unsigned char *src, int width, int height, + unsigned char *dst_ ); + void ConvertNormalMapRGBA8888ToDUDVMapUV88( const unsigned char *src, int width, int height, + unsigned char *dst_ ); + + void ConvertIA88ImageToNormalMapRGBA8888( const unsigned char *src, int width, + int height, unsigned char *dst, + float bumpScale ); + + void NormalizeNormalMapRGBA8888( unsigned char *src, int numTexels ); + + + //----------------------------------------------------------------------------- + // Gamma correction + //----------------------------------------------------------------------------- + void GammaCorrectRGBA8888( unsigned char *src, unsigned char* dst, + int width, int height, int depth, float srcGamma, float dstGamma ); + + + //----------------------------------------------------------------------------- + // Makes a gamma table + //----------------------------------------------------------------------------- + void ConstructGammaTable( unsigned char* pTable, float srcGamma, float dstGamma ); + + + //----------------------------------------------------------------------------- + // Gamma corrects using a previously constructed gamma table + //----------------------------------------------------------------------------- + void GammaCorrectRGBA8888( unsigned char* pSrc, unsigned char* pDst, + int width, int height, int depth, unsigned char* pGammaTable ); + + + //----------------------------------------------------------------------------- + // Generates a number of mipmap levels + //----------------------------------------------------------------------------- + void GenerateMipmapLevels( unsigned char* pSrc, unsigned char* pDst, int width, + int height, int depth, ImageFormat imageFormat, float srcGamma, float dstGamma, + int numLevels = 0 ); + + // Low quality mipmap generation, but way faster. + void GenerateMipmapLevelsLQ( unsigned char* pSrc, unsigned char* pDst, int width, int height, + ImageFormat imageFormat, int numLevels ); + + //----------------------------------------------------------------------------- + // operations on square images (src and dst can be the same) + //----------------------------------------------------------------------------- + bool RotateImageLeft( const unsigned char *src, unsigned char *dst, + int widthHeight, ImageFormat imageFormat ); + bool RotateImage180( const unsigned char *src, unsigned char *dst, + int widthHeight, ImageFormat imageFormat ); + bool FlipImageVertically( void *pSrc, void *pDst, int nWidth, int nHeight, ImageFormat imageFormat, int nDstStride = 0 ); + bool FlipImageHorizontally( void *pSrc, void *pDst, int nWidth, int nHeight, ImageFormat imageFormat, int nDstStride = 0 ); + bool SwapAxes( unsigned char *src, + int widthHeight, ImageFormat imageFormat ); + + + //----------------------------------------------------------------------------- + // Returns info about each image format + //----------------------------------------------------------------------------- + ImageFormatInfo_t const& ImageFormatInfo( ImageFormat fmt ); + + + //----------------------------------------------------------------------------- + // Gets the name of the image format + //----------------------------------------------------------------------------- + inline char const* GetName( ImageFormat fmt ) + { + return ImageFormatInfo(fmt).m_pName; + } + + + //----------------------------------------------------------------------------- + // Gets the size of the image format in bytes + //----------------------------------------------------------------------------- + inline int SizeInBytes( ImageFormat fmt ) + { + return ImageFormatInfo(fmt).m_NumBytes; + } + + //----------------------------------------------------------------------------- + // Does the image format support transparency? + //----------------------------------------------------------------------------- + inline bool IsTransparent( ImageFormat fmt ) + { + return ImageFormatInfo(fmt).m_NumAlphaBits > 0; + } + + + //----------------------------------------------------------------------------- + // Is the image format compressed? + //----------------------------------------------------------------------------- + inline bool IsCompressed( ImageFormat fmt ) + { + return ImageFormatInfo(fmt).m_IsCompressed; + } + + //----------------------------------------------------------------------------- + // Is any channel > 8 bits? + //----------------------------------------------------------------------------- + inline bool HasChannelLargerThan8Bits( ImageFormat fmt ) + { + ImageFormatInfo_t info = ImageFormatInfo(fmt); + return ( info.m_NumRedBits > 8 || info.m_NumGreeBits > 8 || info.m_NumBlueBits > 8 || info.m_NumAlphaBits > 8 ); + } + + inline bool IsRuntimeCompressed( ImageFormat fmt ) + { + return ( fmt == IMAGE_FORMAT_DXT1_RUNTIME ) || ( fmt == IMAGE_FORMAT_DXT5_RUNTIME ); + } + +} // end namespace ImageLoader + + +#endif // IMAGEFORMAT_H diff --git a/public/bitmap/psd.h b/public/bitmap/psd.h new file mode 100644 index 0000000..aae3cbf --- /dev/null +++ b/public/bitmap/psd.h @@ -0,0 +1,105 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Methods relating to saving + loading PSD files (photoshop) +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PSD_H +#define PSD_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" //ImageFormat enum definition + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; +struct Bitmap_t; + +class PSDImageResources +{ +public: + enum Resource { + eResFileInfo = 0x0404 + }; + + struct ResElement { + Resource m_eType; + // unsigned char m_pReserved[4]; + unsigned short m_numBytes; + unsigned char const *m_pvData; + }; + +public: + explicit PSDImageResources( unsigned int numBytes, unsigned char const *pvBuffer ) : m_numBytes( numBytes ), m_pvBuffer( pvBuffer ) {} + +public: + ResElement FindElement( Resource eType ) const; + +protected: + unsigned int m_numBytes; + unsigned char const * m_pvBuffer; +}; + +class PSDResFileInfo +{ +public: + enum ResFileInfo { + eTitle = 0x05, + eAuthor = 0x50, + eAuthorTitle = 0x55, + eDescription = 0x78, + eDescriptionWriter = 0x7A, + eKeywords = 0x19, + eCopyrightNotice = 0x74 + }; + + struct ResFileInfoElement { + ResFileInfo m_eType; + unsigned short m_numBytes; + unsigned char const *m_pvData; + }; + +public: + explicit PSDResFileInfo( PSDImageResources::ResElement res ) : m_res( res ) {} + +public: + ResFileInfoElement FindElement( ResFileInfo eType ) const; + +protected: + PSDImageResources::ResElement m_res; +}; + + +//----------------------------------------------------------------------------- +// Is a file a PSD file? +//----------------------------------------------------------------------------- +bool IsPSDFile( const char *pFileName, const char *pPathID ); +bool IsPSDFile( CUtlBuffer &buf ); + + +//----------------------------------------------------------------------------- +// Returns information about the PSD file +//----------------------------------------------------------------------------- +bool PSDGetInfo( const char *pFileName, const char *pPathID, int *pWidth, int *pHeight, ImageFormat *pImageFormat, float *pSourceGamma ); +bool PSDGetInfo( CUtlBuffer &buf, int *pWidth, int *pHeight, ImageFormat *pImageFormat, float *pSourceGamma ); + + +//----------------------------------------------------------------------------- +// Get PSD file image resources, pointers refer into the utlbuffer +//----------------------------------------------------------------------------- +PSDImageResources PSDGetImageResources( CUtlBuffer &buf ); + + +//----------------------------------------------------------------------------- +// Reads the PSD file into the specified buffer +//----------------------------------------------------------------------------- +bool PSDReadFileRGBA8888( CUtlBuffer &buf, Bitmap_t &bitmap ); +bool PSDReadFileRGBA8888( const char *pFileName, const char *pPathID, Bitmap_t &bitmap ); + + +#endif // PSD_H diff --git a/public/bitmap/tgaloader.h b/public/bitmap/tgaloader.h new file mode 100644 index 0000000..413eb17 --- /dev/null +++ b/public/bitmap/tgaloader.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef TGALOADER_H +#define TGALOADER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" +#include "tier1/utlmemory.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; + + +namespace TGALoader +{ + +int TGAHeaderSize(); + +bool GetInfo( const char *fileName, int *width, int *height, ImageFormat *imageFormat, float *sourceGamma ); +bool GetInfo( CUtlBuffer &buf, int *width, int *height, ImageFormat *imageFormat, float *sourceGamma ); + +bool Load( unsigned char *imageData, const char *fileName, int width, int height, + ImageFormat imageFormat, float targetGamma, bool mipmap ); +bool Load( unsigned char *imageData, CUtlBuffer &buf, int width, int height, + ImageFormat imageFormat, float targetGamma, bool mipmap ); + +bool LoadRGBA8888( const char *pFileName, CUtlMemory &outputData, int &outWidth, int &outHeight ); +bool LoadRGBA8888( CUtlBuffer &buf, CUtlMemory &outputData, int &outWidth, int &outHeight ); + +} // end namespace TGALoader + +#endif // TGALOADER_H diff --git a/public/bitmap/tgawriter.h b/public/bitmap/tgawriter.h new file mode 100644 index 0000000..51854ba --- /dev/null +++ b/public/bitmap/tgawriter.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef TGAWRITER_H +#define TGAWRITER_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/interface.h" +#include "bitmap/imageformat.h" //ImageFormat enum definition + +class CUtlBuffer; + + +namespace TGAWriter +{ + + bool WriteToBuffer( unsigned char *pImageData, CUtlBuffer &buffer, int width, int height, + ImageFormat srcFormat, ImageFormat dstFormat ); + + + // write out a simple tga file from a memory buffer. + bool WriteTGAFile( const char *fileName, int width, int height, enum ImageFormat srcFormat, uint8 const *srcData, int nStride ); + +// A pair of routines for writing to files without allocating any memory in the TGA writer +// Useful for very large files such as posters, which are rendered as sub-rects anyway + bool WriteDummyFileNoAlloc( const char *fileName, int width, int height, ImageFormat dstFormat ); + bool WriteRectNoAlloc( unsigned char *pImageData, const char *fileName, int nXOrigin, int nYOrigin, int width, int height, int nStride, ImageFormat srcFormat ); + + +} // end namespace TGAWriter + +#endif // TGAWRITER_H diff --git a/public/bitvec.h b/public/bitvec.h new file mode 100644 index 0000000..68f260c --- /dev/null +++ b/public/bitvec.h @@ -0,0 +1,1442 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier0/dbg.h" +#include "tier0/basetypes.h" + + +class CBitVecAccessor +{ +public: + CBitVecAccessor(uint32 *pDWords, int iBit); + + void operator=(int val); + operator uint32(); + +private: + uint32 *m_pDWords; + int m_iBit; +}; + + +//----------------------------------------------------------------------------- +// Support functions +//----------------------------------------------------------------------------- + +#define LOG2_BITS_PER_INT 5 +#define BITS_PER_INT 32 + +#if _WIN32 && !defined(_X360) +#include +#pragma intrinsic(_BitScanForward) +#endif + +inline int FirstBitInWord( unsigned int elem, int offset ) +{ +#if _WIN32 + if ( !elem ) + return -1; +#if defined( _X360 ) + // this implements CountTrailingZeros() / BitScanForward() + unsigned int mask = elem-1; + unsigned int comp = ~elem; + elem = mask & comp; + return (32 - _CountLeadingZeros(elem)) + offset; +#else + unsigned long out; + _BitScanForward(&out, elem); + return out + offset; +#endif + +#else + static unsigned firstBitLUT[256] = + { + 0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + }; + unsigned elemByte; + + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + return -1; +#endif +} + +//------------------------------------- + +inline unsigned GetEndMask( int numBits ) +{ + static unsigned bitStringEndMasks[] = + { + 0xffffffff, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + }; + + return bitStringEndMasks[numBits % BITS_PER_INT]; +} + + +inline int GetBitForBitnum( int bitNum ) +{ + static int bitsForBitnum[] = + { + ( 1 << 0 ), + ( 1 << 1 ), + ( 1 << 2 ), + ( 1 << 3 ), + ( 1 << 4 ), + ( 1 << 5 ), + ( 1 << 6 ), + ( 1 << 7 ), + ( 1 << 8 ), + ( 1 << 9 ), + ( 1 << 10 ), + ( 1 << 11 ), + ( 1 << 12 ), + ( 1 << 13 ), + ( 1 << 14 ), + ( 1 << 15 ), + ( 1 << 16 ), + ( 1 << 17 ), + ( 1 << 18 ), + ( 1 << 19 ), + ( 1 << 20 ), + ( 1 << 21 ), + ( 1 << 22 ), + ( 1 << 23 ), + ( 1 << 24 ), + ( 1 << 25 ), + ( 1 << 26 ), + ( 1 << 27 ), + ( 1 << 28 ), + ( 1 << 29 ), + ( 1 << 30 ), + ( 1 << 31 ), + }; + + return bitsForBitnum[ (bitNum) & (BITS_PER_INT-1) ]; +} + +inline int GetBitForBitnumByte( int bitNum ) +{ + static int bitsForBitnum[] = + { + ( 1 << 0 ), + ( 1 << 1 ), + ( 1 << 2 ), + ( 1 << 3 ), + ( 1 << 4 ), + ( 1 << 5 ), + ( 1 << 6 ), + ( 1 << 7 ), + }; + + return bitsForBitnum[ bitNum & 7 ]; +} + +inline int CalcNumIntsForBits( int numBits ) { return (numBits + (BITS_PER_INT-1)) / BITS_PER_INT; } + +#ifdef _X360 +#define BitVec_Bit( bitNum ) GetBitForBitnum( bitNum ) +#define BitVec_BitInByte( bitNum ) GetBitForBitnumByte( bitNum ) +#else +#define BitVec_Bit( bitNum ) ( 1 << ( (bitNum) & (BITS_PER_INT-1) ) ) +#define BitVec_BitInByte( bitNum ) ( 1 << ( (bitNum) & 7 ) ) +#endif +#define BitVec_Int( bitNum ) ( (bitNum) >> LOG2_BITS_PER_INT ) + + +//----------------------------------------------------------------------------- +// template CBitVecT +// +// Defines the operations relevant to any bit array. Simply requires a base +// class that implements GetNumBits(), Base(), GetNumDWords() & ValidateOperand() +// +// CVarBitVec and CBitVec are the actual classes generally used +// by clients +// + +template +class CBitVecT : public BASE_OPS +{ +public: + CBitVecT(); + CBitVecT(int numBits); // Must be initialized with the number of bits + + void Init(int val = 0); + + // Access the bits like an array. + CBitVecAccessor operator[](int i); + + // Do NOT override bitwise operators (see note in header) + void And(const CBitVecT &andStr, CBitVecT *out) const; + void Or(const CBitVecT &orStr, CBitVecT *out) const; + void Xor(const CBitVecT &orStr, CBitVecT *out) const; + + void Not(CBitVecT *out) const; + + void CopyTo(CBitVecT *out) const; + void Copy( const CBitVecT &other, int nBits=-1 ); + bool Compare( const CBitVecT &other, int nBits=-1 ) const; + + bool IsAllClear(void) const; // Are all bits zero? + bool IsAllSet(void) const; // Are all bits one? + + uint32 Get( uint32 bitNum ) const; + bool IsBitSet( int bitNum ) const; + void Set( int bitNum ); + void Set( int bitNum, bool bNewVal ); + void Clear(int bitNum); + + bool TestAndSet(int bitNum); + + void Set( uint32 offset, uint32 mask ); + void Clear( uint32 offset, uint32 mask ); + uint32 Get( uint32 offset, uint32 mask ); + + void SetAll(void); // Sets all bits + void ClearAll(void); // Clears all bits + + uint32 GetDWord(int i) const; + void SetDWord(int i, uint32 val); + + CBitVecT& operator=(const CBitVecT &other) { other.CopyTo( this ); return *this; } + bool operator==(const CBitVecT &other) { return Compare( other ); } + bool operator!=(const CBitVecT &other) { return !operator==( other ); } + + static void GetOffsetMaskForBit( uint32 bitNum, uint32 *pOffset, uint32 *pMask ) { *pOffset = BitVec_Int( bitNum ); *pMask = BitVec_Bit( bitNum ); } +}; + +//----------------------------------------------------------------------------- +// class CVarBitVecBase +// +// Defines the operations necessary for a variable sized bit array +template +class CVarBitVecBase +{ +public: + bool IsFixedSize() const { return false; } + int GetNumBits(void) const { return m_numBits; } + void Resize( int numBits, bool bClearAll = false ); // resizes bit array + + int GetNumDWords() const { return m_numInts; } + uint32 *Base() { return m_pInt; } + const uint32 *Base() const { return m_pInt; } + + void Attach( uint32 *pBits, int numBits ); + bool Detach( uint32 **ppBits, int *pNumBits ); + + int FindNextSetBit(int iStartBit) const; // returns -1 if no set bit was found + +protected: + CVarBitVecBase(); + CVarBitVecBase(int numBits); + CVarBitVecBase( const CVarBitVecBase &from ); + CVarBitVecBase &operator=( const CVarBitVecBase &from ); + ~CVarBitVecBase(void); + + void ValidateOperand( const CVarBitVecBase &operand ) const { Assert(GetNumBits() == operand.GetNumBits()); } + + unsigned GetEndMask() const { return ::GetEndMask( GetNumBits() ); } + +private: + + BITCOUNTTYPE m_numBits; // Number of bits in the bitstring + BITCOUNTTYPE m_numInts; // Number of ints to needed to store bitstring + uint32 m_iBitStringStorage; // If the bit string fits in one int, it goes here + uint32 * m_pInt; // Array of ints containing the bitstring + + void AllocInts( int numInts ); // Free the allocated bits + void ReallocInts( int numInts ); + void FreeInts( void ); // Free the allocated bits +}; + +//----------------------------------------------------------------------------- +// class CFixedBitVecBase +// +// Defines the operations necessary for a fixed sized bit array. +// + +template struct BitCountToEndMask_t { }; +template <> struct BitCountToEndMask_t< 0> { enum { MASK = 0xffffffff }; }; +template <> struct BitCountToEndMask_t< 1> { enum { MASK = 0x00000001 }; }; +template <> struct BitCountToEndMask_t< 2> { enum { MASK = 0x00000003 }; }; +template <> struct BitCountToEndMask_t< 3> { enum { MASK = 0x00000007 }; }; +template <> struct BitCountToEndMask_t< 4> { enum { MASK = 0x0000000f }; }; +template <> struct BitCountToEndMask_t< 5> { enum { MASK = 0x0000001f }; }; +template <> struct BitCountToEndMask_t< 6> { enum { MASK = 0x0000003f }; }; +template <> struct BitCountToEndMask_t< 7> { enum { MASK = 0x0000007f }; }; +template <> struct BitCountToEndMask_t< 8> { enum { MASK = 0x000000ff }; }; +template <> struct BitCountToEndMask_t< 9> { enum { MASK = 0x000001ff }; }; +template <> struct BitCountToEndMask_t<10> { enum { MASK = 0x000003ff }; }; +template <> struct BitCountToEndMask_t<11> { enum { MASK = 0x000007ff }; }; +template <> struct BitCountToEndMask_t<12> { enum { MASK = 0x00000fff }; }; +template <> struct BitCountToEndMask_t<13> { enum { MASK = 0x00001fff }; }; +template <> struct BitCountToEndMask_t<14> { enum { MASK = 0x00003fff }; }; +template <> struct BitCountToEndMask_t<15> { enum { MASK = 0x00007fff }; }; +template <> struct BitCountToEndMask_t<16> { enum { MASK = 0x0000ffff }; }; +template <> struct BitCountToEndMask_t<17> { enum { MASK = 0x0001ffff }; }; +template <> struct BitCountToEndMask_t<18> { enum { MASK = 0x0003ffff }; }; +template <> struct BitCountToEndMask_t<19> { enum { MASK = 0x0007ffff }; }; +template <> struct BitCountToEndMask_t<20> { enum { MASK = 0x000fffff }; }; +template <> struct BitCountToEndMask_t<21> { enum { MASK = 0x001fffff }; }; +template <> struct BitCountToEndMask_t<22> { enum { MASK = 0x003fffff }; }; +template <> struct BitCountToEndMask_t<23> { enum { MASK = 0x007fffff }; }; +template <> struct BitCountToEndMask_t<24> { enum { MASK = 0x00ffffff }; }; +template <> struct BitCountToEndMask_t<25> { enum { MASK = 0x01ffffff }; }; +template <> struct BitCountToEndMask_t<26> { enum { MASK = 0x03ffffff }; }; +template <> struct BitCountToEndMask_t<27> { enum { MASK = 0x07ffffff }; }; +template <> struct BitCountToEndMask_t<28> { enum { MASK = 0x0fffffff }; }; +template <> struct BitCountToEndMask_t<29> { enum { MASK = 0x1fffffff }; }; +template <> struct BitCountToEndMask_t<30> { enum { MASK = 0x3fffffff }; }; +template <> struct BitCountToEndMask_t<31> { enum { MASK = 0x7fffffff }; }; + +//------------------------------------- + +template +class CFixedBitVecBase +{ +public: + bool IsFixedSize() const { return true; } + int GetNumBits(void) const { return NUM_BITS; } + void Resize( int numBits, bool bClearAll = false ) { Assert(numBits == NUM_BITS); if ( bClearAll ) Plat_FastMemset( m_Ints, 0, NUM_INTS * sizeof(uint32) ); }// for syntatic consistency (for when using templates) + + int GetNumDWords() const { return NUM_INTS; } + uint32 * Base() { return m_Ints; } + const uint32 * Base() const { return m_Ints; } + + int FindNextSetBit(int iStartBit) const; // returns -1 if no set bit was found + +protected: + CFixedBitVecBase() {} + CFixedBitVecBase(int numBits) { Assert( numBits == NUM_BITS ); } // doesn't make sense, really. Supported to simplify templates & allow easy replacement of variable + + void ValidateOperand( const CFixedBitVecBase &operand ) const { } // no need, compiler does so statically + +public: // for test code + unsigned GetEndMask() const { return static_cast( BitCountToEndMask_t::MASK ); } + +private: + enum + { + NUM_INTS = (NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT + }; + + uint32 m_Ints[(NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT]; +}; + +//----------------------------------------------------------------------------- +// +// The actual classes used +// + +// inheritance instead of typedef to allow forward declarations +class CVarBitVec : public CBitVecT< CVarBitVecBase > +{ +public: + CVarBitVec() + { + } + + CVarBitVec(int numBits) + : CBitVecT< CVarBitVecBase >(numBits) + { + } +}; + +class CLargeVarBitVec : public CBitVecT< CVarBitVecBase > +{ +public: + CLargeVarBitVec() + { + } + + CLargeVarBitVec(int numBits) + : CBitVecT< CVarBitVecBase >(numBits) + { + } +}; + +//----------------------------------------------------------------------------- + +template < int NUM_BITS > +class CBitVec : public CBitVecT< CFixedBitVecBase > +{ +public: + CBitVec() + { + } + + CBitVec(int numBits) + : CBitVecT< CFixedBitVecBase >(numBits) + { + } +}; + + +//----------------------------------------------------------------------------- + +typedef CBitVec<32> CDWordBitVec; + +//----------------------------------------------------------------------------- + +template +inline CVarBitVecBase::CVarBitVecBase() +{ + Plat_FastMemset( this, 0, sizeof( *this ) ); +} + +//----------------------------------------------------------------------------- + +template +inline CVarBitVecBase::CVarBitVecBase(int numBits) +{ + Assert( numBits ); + m_numBits = (BITCOUNTTYPE)numBits; + + // Figure out how many ints are needed + m_numInts = (BITCOUNTTYPE)CalcNumIntsForBits( numBits ); + m_pInt = NULL; + AllocInts( m_numInts ); +} + +//----------------------------------------------------------------------------- + +template +inline CVarBitVecBase::CVarBitVecBase( const CVarBitVecBase &from ) +{ + if ( from.m_numInts ) + { + m_numBits = from.m_numBits; + m_numInts = from.m_numInts; + m_pInt = NULL; + AllocInts( m_numInts ); + memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); + } + else + memset( this, 0, sizeof( *this ) ); +} + +//----------------------------------------------------------------------------- + +template +inline CVarBitVecBase &CVarBitVecBase::operator=( const CVarBitVecBase &from ) +{ + Resize( from.GetNumBits() ); + if ( m_pInt ) + memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); + return (*this); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +// Input : +// Output : +//----------------------------------------------------------------------------- + +template +inline CVarBitVecBase::~CVarBitVecBase(void) +{ + FreeInts(); +} + +//----------------------------------------------------------------------------- + +template +inline void CVarBitVecBase::Attach( uint32 *pBits, int numBits ) +{ + FreeInts(); + m_numBits = numBits; + m_numInts = CalcNumIntsForBits( numBits ); + if ( m_numInts > 1 ) + { + m_pInt = pBits; + } + else + { + m_iBitStringStorage = *pBits; + m_pInt = &m_iBitStringStorage; + free( pBits ); + } +} + +//----------------------------------------------------------------------------- + +template +inline bool CVarBitVecBase::Detach( uint32 **ppBits, int *pNumBits ) +{ + if ( !m_numBits ) + { + return false; + } + + *pNumBits = m_numBits; + if ( m_numInts > 1 ) + { + *ppBits = m_pInt; + } + else + { + *ppBits = (uint32 *)malloc( sizeof(uint32) ); + **ppBits = m_iBitStringStorage; + free( m_pInt ); + } + + memset( this, 0, sizeof( *this ) ); + return true; +} + +//----------------------------------------------------------------------------- + +template +inline CBitVecT::CBitVecT() +{ + // undef this is ints are not 4 bytes + // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) + + COMPILE_TIME_ASSERT( sizeof(int)==4 ); + + // Initialize bitstring by clearing all bits + ClearAll(); +} + +//----------------------------------------------------------------------------- +template +inline CBitVecT::CBitVecT(int numBits) + : BASE_OPS( numBits ) +{ + // undef this is ints are not 4 bytes + // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) + + COMPILE_TIME_ASSERT( sizeof(int)==4 ); + + // Initialize bitstring by clearing all bits + ClearAll(); +} + +//----------------------------------------------------------------------------- + +template +inline CBitVecAccessor CBitVecT::operator[](int i) +{ + Assert(i >= 0 && i < this->GetNumBits()); + return CBitVecAccessor(this->Base(), i); +} + + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Init( int val ) +{ + if ( this->Base() ) + Plat_FastMemset( this->Base(), ( val ) ? 0xff : 0, this->GetNumDWords() * sizeof(int) ); +} + +//----------------------------------------------------------------------------- + +template +inline uint32 CBitVecT::Get( uint32 bitNum ) const +{ + Assert( bitNum < (uint32)this->GetNumBits() ); + const uint32 *pInt = this->Base() + BitVec_Int( bitNum ); + return ( *pInt & BitVec_Bit( bitNum ) ); +} + +//----------------------------------------------------------------------------- + +template +inline bool CBitVecT::IsBitSet( int bitNum ) const +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + const uint32 *pInt = this->Base() + BitVec_Int( bitNum ); + return ( ( *pInt & BitVec_Bit( bitNum ) ) != 0 ); +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Set( int bitNum ) +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + uint32 *pInt = this->Base() + BitVec_Int( bitNum ); + *pInt |= BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template +inline bool CBitVecT::TestAndSet(int bitNum) +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + uint32 bitVecBit = BitVec_Bit( bitNum ); + uint32 *pInt = this->Base() + BitVec_Int( bitNum ); + bool bResult = ( ( *pInt & bitVecBit) != 0 ); + *pInt |= bitVecBit; + return bResult; +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Clear(int bitNum) +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + uint32 *pInt = this->Base() + BitVec_Int( bitNum ); + *pInt &= ~BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Set( int bitNum, bool bNewVal ) +{ + uint32 *pInt = this->Base() + BitVec_Int( bitNum ); + uint32 bitMask = BitVec_Bit( bitNum ); + if ( bNewVal ) + { + *pInt |= bitMask; + } + else + { + *pInt &= ~bitMask; + } +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Set( uint32 offset, uint32 mask ) +{ + uint32 *pInt = this->Base() + offset; + *pInt |= mask; +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Clear( uint32 offset, uint32 mask ) +{ + uint32 *pInt = this->Base() + offset; + *pInt &= ~mask; +} + +//----------------------------------------------------------------------------- + +template +inline uint32 CBitVecT::Get( uint32 offset, uint32 mask ) +{ + uint32 *pInt = this->Base() + offset; + return ( *pInt & mask ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::And(const CBitVecT &addStr, CBitVecT *out) const +{ + this->ValidateOperand( addStr ); + this->ValidateOperand( *out ); + + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = this->Base(); + const uint32 *pOperand2 = addStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0 ; --i) + { + pDest[i] = pOperand1[i] & pOperand2[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Or(const CBitVecT &orStr, CBitVecT *out) const +{ + this->ValidateOperand( orStr ); + this->ValidateOperand( *out ); + + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = this->Base(); + const uint32 *pOperand2 = orStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] | pOperand2[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Xor(const CBitVecT &xorStr, CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = this->Base(); + const uint32 *pOperand2 = xorStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] ^ pOperand2[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Not(CBitVecT *out) const +{ + this->ValidateOperand( *out ); + + uint32 * pDest = out->Base(); + const uint32 *pOperand = this->Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = ~(pOperand[i]); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Copy a bit string +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::CopyTo(CBitVecT *out) const +{ + out->Resize( this->GetNumBits() ); + + this->ValidateOperand( *out ); + Assert( out != this ); + + memcpy( out->Base(), this->Base(), this->GetNumDWords() * sizeof( int ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Are all bits zero? +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline bool CBitVecT::IsAllClear(void) const +{ + // Number of available bits may be more than the number + // actually used, so make sure to mask out unused bits + // before testing for zero + (const_cast(this))->Base()[this->GetNumDWords()-1] &= CBitVecT::GetEndMask(); // external semantics of const retained + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + if ( this->Base()[i] !=0 ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Are all bits set? +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline bool CBitVecT::IsAllSet(void) const +{ + // Number of available bits may be more than the number + // actually used, so make sure to mask out unused bits + // before testing for set bits + (const_cast(this))->Base()[this->GetNumDWords()-1] |= ~CBitVecT::GetEndMask(); // external semantics of const retained + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + if ( this->Base()[i] != ~0 ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets all bits +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::SetAll(void) +{ + if ( this->Base() ) + Plat_FastMemset( this->Base(), 0xff, this->GetNumDWords() * sizeof(int) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Clears all bits +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::ClearAll(void) +{ + if ( this->Base() ) + Plat_FastMemset( this->Base(), 0, this->GetNumDWords() * sizeof(int) ); +} + +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Copy( const CBitVecT &other, int nBits ) +{ + if ( nBits == - 1 ) + { + nBits = other.GetNumBits(); + } + + this->Resize( nBits ); + + this->ValidateOperand( other ); + Assert( &other != this ); + + memcpy( this->Base(), other.Base(), this->GetNumDWords() * sizeof( uint32 ) ); +} + +//----------------------------------------------------------------------------- +template +inline bool CBitVecT::Compare( const CBitVecT &other, int nBits ) const +{ + if ( nBits == - 1 ) + { + if ( other.GetNumBits() != this->GetNumBits() ) + { + return false; + } + + nBits = other.GetNumBits(); + } + + if ( nBits > other.GetNumBits() || nBits > this->GetNumBits() ) + { + return false; + } + + (const_cast(this))->Base()[this->GetNumDWords()-1] &= CBitVecT::GetEndMask(); // external semantics of const retained + (const_cast(&other))->Base()[this->GetNumDWords()-1] &= other.CBitVecT::GetEndMask(); // external semantics of const retained + + int nBytes = PAD_NUMBER( nBits, 8 ) >> 3; + + return ( memcmp( this->Base(), other.Base(), nBytes ) == 0 ); +} + +//----------------------------------------------------------------------------- +template +inline uint32 CBitVecT::GetDWord(int i) const +{ + Assert(i >= 0 && i < this->GetNumDWords()); + return this->Base()[i]; +} + +//----------------------------------------------------------------------------- +template +inline void CBitVecT::SetDWord(int i, uint32 val) +{ + Assert(i >= 0 && i < this->GetNumDWords()); + this->Base()[i] = val; +} + +//----------------------------------------------------------------------------- + +inline unsigned GetStartBitMask( int startBit ) +{ + static unsigned int g_StartMask[32] = + { + 0xffffffff, + 0xfffffffe, + 0xfffffffc, + 0xfffffff8, + 0xfffffff0, + 0xffffffe0, + 0xffffffc0, + 0xffffff80, + 0xffffff00, + 0xfffffe00, + 0xfffffc00, + 0xfffff800, + 0xfffff000, + 0xffffe000, + 0xffffc000, + 0xffff8000, + 0xffff0000, + 0xfffe0000, + 0xfffc0000, + 0xfff80000, + 0xfff00000, + 0xffe00000, + 0xffc00000, + 0xff800000, + 0xff000000, + 0xfe000000, + 0xfc000000, + 0xf8000000, + 0xf0000000, + 0xe0000000, + 0xc0000000, + 0x80000000, + }; + + return g_StartMask[ startBit & 31 ]; +} + +template +inline int CVarBitVecBase::FindNextSetBit( int startBit ) const +{ + if ( startBit < GetNumBits() ) + { + int wordIndex = BitVec_Int(startBit); + unsigned int startMask = GetStartBitMask( startBit ); + int lastWord = GetNumDWords()-1; + + // handle non dword lengths + if ( (GetNumBits() % BITS_PER_INT) != 0 ) + { + unsigned int elem = Base()[wordIndex]; + elem &= startMask; + if ( wordIndex == lastWord) + { + elem &= (GetEndMask()); + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + } + else + { + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + + // iterate the words + for ( int i = wordIndex+1; i < lastWord; i++ ) + { + elem = Base()[i]; + if ( elem ) + return FirstBitInWord(elem, i << 5); + } + elem = Base()[lastWord] & GetEndMask(); + if ( elem ) + return FirstBitInWord(elem, lastWord << 5); + } + } + else + { + const uint32 * RESTRICT pCurElem = Base() + wordIndex; + unsigned int elem = *pCurElem; + elem &= startMask; + do + { + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + ++pCurElem; + elem = *pCurElem; + ++wordIndex; + } while( wordIndex <= lastWord ); + } + + } + + return -1; +} + +template +inline int CFixedBitVecBase::FindNextSetBit( int startBit ) const +{ + if ( startBit < NUM_BITS ) + { + int wordIndex = BitVec_Int(startBit); + unsigned int startMask = GetStartBitMask( startBit ); + + // handle non dword lengths + if ( (NUM_BITS % BITS_PER_INT) != 0 ) + { + unsigned int elem = Base()[wordIndex]; + elem &= startMask; + if ( wordIndex == NUM_INTS-1) + { + elem &= (GetEndMask()); + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + } + else + { + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + + // iterate the words + for ( int i = wordIndex+1; i < NUM_INTS-1; i++ ) + { + elem = Base()[i]; + if ( elem ) + return FirstBitInWord(elem, i << 5); + } + elem = Base()[NUM_INTS-1] & GetEndMask(); + if ( elem ) + return FirstBitInWord(elem, (NUM_INTS-1) << 5); + } + } + else + { + const uint32 * RESTRICT pCurElem = Base() + wordIndex; + unsigned int elem = *pCurElem; + elem &= startMask; + do + { + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + ++pCurElem; + elem = *pCurElem; + ++wordIndex; + } while( wordIndex <= NUM_INTS-1); + } + + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Unrolled loops for some common sizes + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<256> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = Base(); + const uint32 *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; + pDest[3] = pOperand1[3] & pOperand2[3]; + pDest[4] = pOperand1[4] & pOperand2[4]; + pDest[5] = pOperand1[5] & pOperand2[5]; + pDest[6] = pOperand1[6] & pOperand2[6]; + pDest[7] = pOperand1[7] & pOperand2[7]; +} + +template<> +FORCEINLINE_TEMPLATE bool CBitVecT< CFixedBitVecBase<256> >::IsAllClear(void) const +{ + const uint32 *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 && pInts[4] == 0 && pInts[5] == 0 && pInts[6] == 0 && pInts[7] == 0 ); +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<256> >::CopyTo(CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; + pDest[3] = pInts[3]; + pDest[4] = pInts[4]; + pDest[5] = pInts[5]; + pDest[6] = pInts[6]; + pDest[7] = pInts[7]; +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<128> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = Base(); + const uint32 *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; + pDest[3] = pOperand1[3] & pOperand2[3]; +} + +template<> +FORCEINLINE_TEMPLATE bool CBitVecT< CFixedBitVecBase<128> >::IsAllClear(void) const +{ + const uint32 *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 ); +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<128> >::CopyTo(CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; + pDest[3] = pInts[3]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<96> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = Base(); + const uint32 *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<96> >::IsAllClear(void) const +{ + const uint32 *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 ); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<96> >::CopyTo(CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<64> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = Base(); + const uint32 *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<64> >::IsAllClear(void) const +{ + const uint32 *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 ); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<64> >::CopyTo(CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<32> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pOperand1 = Base(); + const uint32 *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<32> >::IsAllClear(void) const +{ + const uint32 *pInts = Base(); + + return ( pInts[0] == 0 ); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<32> >::CopyTo(CBitVecT *out) const +{ + uint32 * pDest = out->Base(); + const uint32 *pInts = Base(); + + pDest[0] = pInts[0]; +} + +//----------------------------------------------------------------------------- + +template <> +inline uint32 CBitVecT< CFixedBitVecBase<32> >::Get( uint32 bitNum ) const +{ + return ( *Base() & BitVec_Bit( bitNum ) ); +} + +//----------------------------------------------------------------------------- + +template <> +inline bool CBitVecT< CFixedBitVecBase<32> >::IsBitSet( int bitNum ) const +{ + return ( ( *Base() & BitVec_Bit( bitNum ) ) != 0 ); +} + +//----------------------------------------------------------------------------- + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Set( int bitNum ) +{ + *Base() |= BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Clear(int bitNum) +{ + *Base() &= ~BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Set( int bitNum, bool bNewVal ) +{ + uint32 bitMask = BitVec_Bit( bitNum ); + if ( bNewVal ) + { + *Base() |= bitMask; + } + else + { + *Base() &= ~bitMask; + } +} + + +//----------------------------------------------------------------------------- + +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Resizes the bit string to a new number of bits +// Input : resizeNumBits - +//----------------------------------------------------------------------------- +template +inline void CVarBitVecBase::Resize( int resizeNumBits, bool bClearAll ) +{ + Assert( resizeNumBits >= 0 && ((BITCOUNTTYPE)resizeNumBits == resizeNumBits) ); + + int newIntCount = CalcNumIntsForBits( resizeNumBits ); + if ( newIntCount != GetNumDWords() ) + { + if ( Base() ) + { + ReallocInts( newIntCount ); + if ( !bClearAll && resizeNumBits >= GetNumBits() ) + { + Base()[GetNumDWords() - 1] &= GetEndMask(); + Plat_FastMemset( Base() + GetNumDWords(), 0, (newIntCount - GetNumDWords()) * sizeof(int) ); + } + } + else + { + // Figure out how many ints are needed + AllocInts( newIntCount ); + // Initialize bitstring by clearing all bits + bClearAll = true; + } + + m_numInts = newIntCount; + } + else if ( !bClearAll && resizeNumBits >= GetNumBits() && Base() ) + { + Base()[GetNumDWords() - 1] &= GetEndMask(); + } + + if ( bClearAll && Base() ) + { + Plat_FastMemset( Base(), 0, newIntCount * sizeof(int) ); + } + + // store the new size and end mask + m_numBits = resizeNumBits; +} + +//----------------------------------------------------------------------------- +// Purpose: Allocate the storage for the ints +// Input : numInts - +//----------------------------------------------------------------------------- +template +inline void CVarBitVecBase::AllocInts( int numInts ) +{ + Assert( !m_pInt ); + + if ( numInts == 0 ) + return; + + if ( numInts == 1 ) + { + m_pInt = &m_iBitStringStorage; + return; + } + + m_pInt = (uint32 *)malloc( numInts * sizeof(int) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reallocate the storage for the ints +// Input : numInts - +//----------------------------------------------------------------------------- +template +inline void CVarBitVecBase::ReallocInts( int numInts ) +{ + Assert( Base() ); + if ( numInts == 0) + { + FreeInts(); + return; + } + + if ( m_pInt == &m_iBitStringStorage ) + { + if ( numInts != 1 ) + { + m_pInt = ((uint32 *)malloc( numInts * sizeof(int) )); + *m_pInt = m_iBitStringStorage; + } + + return; + } + + if ( numInts == 1 ) + { + m_iBitStringStorage = *m_pInt; + free( m_pInt ); + m_pInt = &m_iBitStringStorage; + return; + } + + m_pInt = (uint32 *)realloc( m_pInt, numInts * sizeof(int) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Free storage allocated with AllocInts +//----------------------------------------------------------------------------- +template +inline void CVarBitVecBase::FreeInts( void ) +{ + if ( m_numInts > 1 ) + { + free( m_pInt ); + } + m_pInt = NULL; +} + +#include "tier0/memdbgoff.h" + +// ------------------------------------------------------------------------ // +// CBitVecAccessor inlines. +// ------------------------------------------------------------------------ // + +inline CBitVecAccessor::CBitVecAccessor(uint32 *pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + + +inline void CBitVecAccessor::operator=(int val) +{ + if(val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator uint32() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + +//============================================================================= + +#endif // BITVEC_H diff --git a/public/blockingudpsocket.cpp b/public/blockingudpsocket.cpp new file mode 100644 index 0000000..aefd54f --- /dev/null +++ b/public/blockingudpsocket.cpp @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#if defined(_WIN32) && !defined(_X360) +#include +#elif POSIX +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#include +#include +#include +#include +#define closesocket close +#endif + +#include "blockingudpsocket.h" +#include "tier0/vcrmode.h" + +class CBlockingUDPSocket::CImpl +{ +public: + struct sockaddr_in m_SocketIP; + fd_set m_FDSet; +}; + +CBlockingUDPSocket::CBlockingUDPSocket() : + m_cserIP(), + m_Socket( 0 ), + m_pImpl( new CImpl ) +{ + CreateSocket(); +} + +CBlockingUDPSocket::~CBlockingUDPSocket() +{ + delete m_pImpl; + closesocket( static_cast( m_Socket )); +} + +bool CBlockingUDPSocket::CreateSocket (void) +{ + struct sockaddr_in address; + + m_Socket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if ( m_Socket == INVALID_SOCKET ) + { + return false; + } + + address = m_pImpl->m_SocketIP; + + if ( SOCKET_ERROR == bind( m_Socket, ( struct sockaddr * )&address, sizeof( address ) ) ) + { + return false; + } + +#ifdef _WIN32 + if ( m_pImpl->m_SocketIP.sin_addr.S_un.S_addr == INADDR_ANY ) + { + m_pImpl->m_SocketIP.sin_addr.S_un.S_addr = 0L; + } +#elif POSIX + if ( m_pImpl->m_SocketIP.sin_addr.s_addr == INADDR_ANY ) + { + m_pImpl->m_SocketIP.sin_addr.s_addr = 0L; + } +#endif + + return true; +} + +bool CBlockingUDPSocket::WaitForMessage( float timeOutInSeconds ) +{ + struct timeval tv; + + FD_ZERO( &m_pImpl->m_FDSet ); + FD_SET( m_Socket, &m_pImpl->m_FDSet );//lint !e717 + + tv.tv_sec = (int)timeOutInSeconds; + float remainder = timeOutInSeconds - (int)timeOutInSeconds; + tv.tv_usec = (int)( remainder * 1000000 + 0.5f ); /* micro seconds */ + + if ( SOCKET_ERROR == select( ( int )m_Socket + 1, &m_pImpl->m_FDSet, NULL, NULL, &tv ) ) + { + return false; + } + + if ( FD_ISSET( m_Socket, &m_pImpl->m_FDSet) ) + { + return true; + } + + // Timed out + return false; +} + +unsigned int CBlockingUDPSocket::ReceiveSocketMessage( struct sockaddr_in *packet_from, unsigned char *buf, size_t bufsize ) +{ + memset( packet_from, 0, sizeof( *packet_from ) ); + + struct sockaddr fromaddress; + int fromlen = sizeof( fromaddress ); + + int packet_length = VCRHook_recvfrom + ( + m_Socket, + (char *)buf, + (int)bufsize, + 0, + &fromaddress, + &fromlen + ); + + if ( SOCKET_ERROR == packet_length ) + { + return 0; + } + + // In case it's parsed as a string + buf[ packet_length ] = 0; + + // Copy over the receive address + *packet_from = *( struct sockaddr_in * )&fromaddress; + + return ( unsigned int )packet_length; +} + +bool CBlockingUDPSocket::SendSocketMessage( const struct sockaddr_in & rRecipient, const unsigned char *buf, size_t bufsize ) +{ + // Send data + int bytesSent = sendto + ( + m_Socket, + (const char *)buf, + (int)bufsize, + 0, + reinterpret_cast< const sockaddr * >( &rRecipient ), + sizeof( rRecipient ) + ); + + if ( SOCKET_ERROR == bytesSent ) + { + return false; + } + + return true; +} diff --git a/public/blockingudpsocket.h b/public/blockingudpsocket.h new file mode 100644 index 0000000..2f60555 --- /dev/null +++ b/public/blockingudpsocket.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BLOCKINGUDPSOCKET_H +#define BLOCKINGUDPSOCKET_H +#ifdef _WIN32 +#pragma once +#endif + +#include "netadr.h" + +class CBlockingUDPSocket +{ +public: + explicit CBlockingUDPSocket(); + virtual ~CBlockingUDPSocket(); + + bool WaitForMessage( float timeOutInSeconds ); + unsigned int ReceiveSocketMessage( struct sockaddr_in *packet_from, unsigned char *buf, size_t bufsize ); + bool SendSocketMessage( const struct sockaddr_in& rRecipient, const unsigned char *buf, size_t bufsize ); + + bool IsValid() const { return m_Socket != 0; } + +protected: + bool CreateSocket (void); + + class CImpl; + CImpl *m_pImpl; + + netadr_t m_cserIP; + unsigned int m_Socket; + + +}; + +#endif // BLOCKINGUDPSOCKET_H diff --git a/public/bone_accessor.cpp b/public/bone_accessor.cpp new file mode 100644 index 0000000..f8edd10 --- /dev/null +++ b/public/bone_accessor.cpp @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "bone_accessor.h" + + +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + + void CBoneAccessor::SanityCheckBone( int iBone, bool bReadable ) const + { + if ( m_pAnimating ) + { + CStudioHdr *pHdr = m_pAnimating->GetModelPtr(); + if ( pHdr ) + { + mstudiobone_t *pBone = pHdr->pBone( iBone ); + if ( bReadable ) + { + AssertOnce( pBone->flags & m_ReadableBones ); + } + else + { + AssertOnce( pBone->flags & m_WritableBones ); + } + } + } + } + +#endif + diff --git a/public/bone_accessor.h b/public/bone_accessor.h new file mode 100644 index 0000000..99e07f9 --- /dev/null +++ b/public/bone_accessor.h @@ -0,0 +1,131 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BONE_ACCESSOR_H +#define BONE_ACCESSOR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "studio.h" + + +class C_BaseAnimating; + + +class CBoneAccessor +{ +public: + + CBoneAccessor(); + CBoneAccessor( matrix3x4_t *pBones ); // This can be used to allow access to all bones. + + // Initialize. +#if defined( CLIENT_DLL ) + void Init( const C_BaseAnimating *pAnimating, matrix3x4_t *pBones ); +#endif + + int GetReadableBones(); + void SetReadableBones( int flags ); + + int GetWritableBones(); + void SetWritableBones( int flags ); + + // Get bones for read or write access. + const matrix3x4_t& GetBone( int iBone ) const; + const matrix3x4_t& operator[]( int iBone ) const; + matrix3x4_t& GetBoneForWrite( int iBone ); + + matrix3x4_t *GetBoneArrayForWrite( ) const; + +private: + +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + void SanityCheckBone( int iBone, bool bReadable ) const; +#endif + + // Only used in the client DLL for debug verification. + const C_BaseAnimating *m_pAnimating; + + matrix3x4_t *m_pBones; + + int m_ReadableBones; // Which bones can be read. + int m_WritableBones; // Which bones can be written. +}; + + +inline CBoneAccessor::CBoneAccessor() +{ + m_pAnimating = NULL; + m_pBones = NULL; + m_ReadableBones = m_WritableBones = 0; +} + +inline CBoneAccessor::CBoneAccessor( matrix3x4_t *pBones ) +{ + m_pAnimating = NULL; + m_pBones = pBones; +} + +#if defined( CLIENT_DLL ) + inline void CBoneAccessor::Init( const C_BaseAnimating *pAnimating, matrix3x4_t *pBones ) + { + m_pAnimating = pAnimating; + m_pBones = pBones; + } +#endif + +inline int CBoneAccessor::GetReadableBones() +{ + return m_ReadableBones; +} + +inline void CBoneAccessor::SetReadableBones( int flags ) +{ + m_ReadableBones = flags; +} + +inline int CBoneAccessor::GetWritableBones() +{ + return m_WritableBones; +} + +inline void CBoneAccessor::SetWritableBones( int flags ) +{ + m_WritableBones = flags; +} + +inline const matrix3x4_t& CBoneAccessor::GetBone( int iBone ) const +{ +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + SanityCheckBone( iBone, true ); +#endif + return m_pBones[iBone]; +} + +inline const matrix3x4_t& CBoneAccessor::operator[]( int iBone ) const +{ +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + SanityCheckBone( iBone, true ); +#endif + return m_pBones[iBone]; +} + +inline matrix3x4_t& CBoneAccessor::GetBoneForWrite( int iBone ) +{ +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + SanityCheckBone( iBone, false ); +#endif + return m_pBones[iBone]; +} + +inline matrix3x4_t *CBoneAccessor::GetBoneArrayForWrite( void ) const +{ + return m_pBones; +} + +#endif // BONE_ACCESSOR_H diff --git a/public/bone_setup.cpp b/public/bone_setup.cpp new file mode 100644 index 0000000..aadd209 --- /dev/null +++ b/public/bone_setup.cpp @@ -0,0 +1,6052 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" +#include "bone_setup.h" +#include + +#include "collisionutils.h" +#include "vstdlib/random.h" +#include "tier0/vprof.h" +#include "bone_accessor.h" +#include "mathlib/ssequaternion.h" +#include "bitvec.h" +#include "datamanager.h" +#include "convar.h" +#include "tier0/tslist.h" +#include "vphysics_interface.h" +#ifdef CLIENT_DLL + #include "posedebugger.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CBoneSetup +{ +public: + CBoneSetup( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], IPoseDebugger *pPoseDebugger = NULL ); + void InitPose( Vector pos[], Quaternion q[] ); + void AccumulatePose( Vector pos[], Quaternion q[], int sequence, float cycle, float flWeight, float flTime, CIKContext *pIKContext ); + void CalcAutoplaySequences( Vector pos[], Quaternion q[], float flRealTime, CIKContext *pIKContext ); +private: + void AddSequenceLayers( Vector pos[], Quaternion q[], mstudioseqdesc_t &seqdesc, int sequence, float cycle, float flWeight, float flTime, CIKContext *pIKContext ); + void AddLocalLayers( Vector pos[], Quaternion q[], mstudioseqdesc_t &seqdesc, int sequence, float cycle, float flWeight, float flTime, CIKContext *pIKContext ); +public: + const CStudioHdr *m_pStudioHdr; + int m_boneMask; + const float *m_flPoseParameter; + IPoseDebugger *m_pPoseDebugger; +}; + +// ----------------------------------------------------------------- +template +class CBoneSetupMemoryPool +{ +public: + T *Alloc() + { + T *p = (T *)m_FreeBlocks.Pop(); + if ( !p ) + { + p = new T[MAXSTUDIOBONES]; + if ( ((size_t)p) % TSLIST_NODE_ALIGNMENT != 0 ) + { + DebuggerBreak(); + } + } + + return p; + } + + void Free( T *p ) + { + m_FreeBlocks.Push( (TSLNodeBase_t *)p ); + } + +private: + CTSListBase m_FreeBlocks; +}; + +CBoneSetupMemoryPool g_QaternionPool; +CBoneSetupMemoryPool g_VectorPool; +CBoneSetupMemoryPool g_MatrixPool; + +// ----------------------------------------------------------------- +CBoneCache *CBoneCache::CreateResource( const bonecacheparams_t ¶ms ) +{ + short studioToCachedIndex[MAXSTUDIOBONES]; + short cachedToStudioIndex[MAXSTUDIOBONES]; + int cachedBoneCount = 0; + for ( int i = 0; i < params.pStudioHdr->numbones(); i++ ) + { + // skip bones that aren't part of the boneMask (and aren't the root bone) + if (i != 0 && !(params.pStudioHdr->boneFlags(i) & params.boneMask)) + { + studioToCachedIndex[i] = -1; + continue; + } + studioToCachedIndex[i] = cachedBoneCount; + cachedToStudioIndex[cachedBoneCount] = i; + cachedBoneCount++; + } + int tableSizeStudio = sizeof(short) * params.pStudioHdr->numbones(); + int tableSizeCached = sizeof(short) * cachedBoneCount; + int matrixSize = sizeof(matrix3x4_t) * cachedBoneCount; + int size = ( sizeof(CBoneCache) + tableSizeStudio + tableSizeCached + matrixSize + 3 ) & ~3; + + CBoneCache *pMem = (CBoneCache *)malloc( size ); + Construct( pMem ); + pMem->Init( params, size, studioToCachedIndex, cachedToStudioIndex, cachedBoneCount ); + return pMem; +} + +unsigned int CBoneCache::EstimatedSize( const bonecacheparams_t ¶ms ) +{ + // conservative estimate - max size + return ( params.pStudioHdr->numbones() * (sizeof(short) + sizeof(short) + sizeof(matrix3x4_t)) + 3 ) & ~3; +} + +void CBoneCache::DestroyResource() +{ + free( this ); +} + + +CBoneCache::CBoneCache() +{ + m_size = 0; + m_cachedBoneCount = 0; +} + +void CBoneCache::Init( const bonecacheparams_t ¶ms, unsigned int size, short *pStudioToCached, short *pCachedToStudio, int cachedBoneCount ) +{ + m_cachedBoneCount = cachedBoneCount; + m_size = size; + m_timeValid = params.curtime; + m_boneMask = params.boneMask; + + int studioTableSize = params.pStudioHdr->numbones() * sizeof(short); + m_cachedToStudioOffset = studioTableSize; + memcpy( StudioToCached(), pStudioToCached, studioTableSize ); + + int cachedTableSize = cachedBoneCount * sizeof(short); + memcpy( CachedToStudio(), pCachedToStudio, cachedTableSize ); + + m_matrixOffset = ( m_cachedToStudioOffset + cachedTableSize + 3 ) & ~3; + + UpdateBones( params.pBoneToWorld, params.pStudioHdr->numbones(), params.curtime ); +} + +void CBoneCache::UpdateBones( const matrix3x4_t *pBoneToWorld, int numbones, float curtime ) +{ + matrix3x4_t *pBones = BoneArray(); + const short *pCachedToStudio = CachedToStudio(); + + for ( int i = 0; i < m_cachedBoneCount; i++ ) + { + int index = pCachedToStudio[i]; + MatrixCopy( pBoneToWorld[index], pBones[i] ); + } + m_timeValid = curtime; +} + +matrix3x4_t *CBoneCache::GetCachedBone( int studioIndex ) +{ + int cachedIndex = StudioToCached()[studioIndex]; + if ( cachedIndex >= 0 ) + { + return BoneArray() + cachedIndex; + } + return NULL; +} + +void CBoneCache::ReadCachedBones( matrix3x4_t *pBoneToWorld ) +{ + matrix3x4_t *pBones = BoneArray(); + const short *pCachedToStudio = CachedToStudio(); + for ( int i = 0; i < m_cachedBoneCount; i++ ) + { + MatrixCopy( pBones[i], pBoneToWorld[pCachedToStudio[i]] ); + } +} + +void CBoneCache::ReadCachedBonePointers( matrix3x4_t **bones, int numbones ) +{ + memset( bones, 0, sizeof(matrix3x4_t *) * numbones ); + matrix3x4_t *pBones = BoneArray(); + const short *pCachedToStudio = CachedToStudio(); + for ( int i = 0; i < m_cachedBoneCount; i++ ) + { + bones[pCachedToStudio[i]] = pBones + i; + } +} + +bool CBoneCache::IsValid( float curtime, float dt ) +{ + if ( curtime - m_timeValid <= dt ) + return true; + return false; +} + + +// private functions +matrix3x4_t *CBoneCache::BoneArray() +{ + return (matrix3x4_t *)( (char *)(this+1) + m_matrixOffset ); +} + +short *CBoneCache::StudioToCached() +{ + return (short *)( (char *)(this+1) ); +} + +short *CBoneCache::CachedToStudio() +{ + return (short *)( (char *)(this+1) + m_cachedToStudioOffset ); +} + +// Construct a singleton +static CDataManager g_StudioBoneCache( 128 * 1024L ); + +CBoneCache *Studio_GetBoneCache( memhandle_t cacheHandle ) +{ + AUTO_LOCK( g_StudioBoneCache.AccessMutex() ); + return g_StudioBoneCache.GetResource_NoLock( cacheHandle ); +} + +memhandle_t Studio_CreateBoneCache( bonecacheparams_t ¶ms ) +{ + AUTO_LOCK( g_StudioBoneCache.AccessMutex() ); + return g_StudioBoneCache.CreateResource( params ); +} + +void Studio_DestroyBoneCache( memhandle_t cacheHandle ) +{ + AUTO_LOCK( g_StudioBoneCache.AccessMutex() ); + g_StudioBoneCache.DestroyResource( cacheHandle ); +} + +void Studio_InvalidateBoneCache( memhandle_t cacheHandle ) +{ + AUTO_LOCK( g_StudioBoneCache.AccessMutex() ); + CBoneCache *pCache = g_StudioBoneCache.GetResource_NoLock( cacheHandle ); + if ( pCache ) + { + pCache->m_timeValid = -1.0f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void BuildBoneChain( + const CStudioHdr *pStudioHdr, + const matrix3x4_t &rootxform, + const Vector pos[], + const Quaternion q[], + int iBone, + matrix3x4_t *pBoneToWorld ) +{ + CBoneBitList boneComputed; + BuildBoneChain( pStudioHdr, rootxform, pos, q, iBone, pBoneToWorld, boneComputed ); + return; +} + + +//----------------------------------------------------------------------------- +// Purpose: return a sub frame rotation for a single bone +//----------------------------------------------------------------------------- +void ExtractAnimValue( int frame, mstudioanimvalue_t *panimvalue, float scale, float &v1, float &v2 ) +{ + if ( !panimvalue ) + { + v1 = v2 = 0; + return; + } + + // Avoids a crash reading off the end of the data + // There is probably a better long-term solution; Ken is going to look into it. + if ( ( panimvalue->num.total == 1 ) && ( panimvalue->num.valid == 1 ) ) + { + v1 = v2 = panimvalue[1].value * scale; + return; + } + + int k = frame; + + // find the data list that has the frame + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + if ( panimvalue->num.total == 0 ) + { + Assert( 0 ); // running off the end of the animation stream is bad + v1 = v2 = 0; + return; + } + } + if (panimvalue->num.valid > k) + { + // has valid animation data + v1 = panimvalue[k+1].value * scale; + + if (panimvalue->num.valid > k + 1) + { + // has valid animation blend data + v2 = panimvalue[k+2].value * scale; + } + else + { + if (panimvalue->num.total > k + 1) + { + // data repeats, no blend + v2 = v1; + } + else + { + // pull blend from first data block in next list + v2 = panimvalue[panimvalue->num.valid+2].value * scale; + } + } + } + else + { + // get last valid data block + v1 = panimvalue[panimvalue->num.valid].value * scale; + if (panimvalue->num.total > k + 1) + { + // data repeats, no blend + v2 = v1; + } + else + { + // pull blend from first data block in next list + v2 = panimvalue[panimvalue->num.valid + 2].value * scale; + } + } +} + + +void ExtractAnimValue( int frame, mstudioanimvalue_t *panimvalue, float scale, float &v1 ) +{ + if ( !panimvalue ) + { + v1 = 0; + return; + } + + int k = frame; + + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + if ( panimvalue->num.total == 0 ) + { + Assert( 0 ); // running off the end of the animation stream is bad + v1 = 0; + return; + } + } + if (panimvalue->num.valid > k) + { + v1 = panimvalue[k+1].value * scale; + } + else + { + // get last valid data block + v1 = panimvalue[panimvalue->num.valid].value * scale; + } +} + +//----------------------------------------------------------------------------- +// Purpose: return a sub frame rotation for a single bone +//----------------------------------------------------------------------------- +void CalcBoneQuaternion( int frame, float s, + const Quaternion &baseQuat, const RadianEuler &baseRot, const Vector &baseRotScale, + int iBaseFlags, const Quaternion &baseAlignment, + const mstudioanim_t *panim, Quaternion &q ) +{ + if ( panim->flags & STUDIO_ANIM_RAWROT ) + { + q = *(panim->pQuat48()); + Assert( q.IsValid() ); + return; + } + + if ( panim->flags & STUDIO_ANIM_RAWROT2 ) + { + q = *(panim->pQuat64()); + Assert( q.IsValid() ); + return; + } + + if ( !(panim->flags & STUDIO_ANIM_ANIMROT) ) + { + if (panim->flags & STUDIO_ANIM_DELTA) + { + q.Init( 0.0f, 0.0f, 0.0f, 1.0f ); + } + else + { + q = baseQuat; + } + return; + } + + mstudioanim_valueptr_t *pValuesPtr = panim->pRotV(); + + if (s > 0.001f) + { + QuaternionAligned q1, q2; + RadianEuler angle1, angle2; + + ExtractAnimValue( frame, pValuesPtr->pAnimvalue( 0 ), baseRotScale.x, angle1.x, angle2.x ); + ExtractAnimValue( frame, pValuesPtr->pAnimvalue( 1 ), baseRotScale.y, angle1.y, angle2.y ); + ExtractAnimValue( frame, pValuesPtr->pAnimvalue( 2 ), baseRotScale.z, angle1.z, angle2.z ); + + if (!(panim->flags & STUDIO_ANIM_DELTA)) + { + angle1.x = angle1.x + baseRot.x; + angle1.y = angle1.y + baseRot.y; + angle1.z = angle1.z + baseRot.z; + angle2.x = angle2.x + baseRot.x; + angle2.y = angle2.y + baseRot.y; + angle2.z = angle2.z + baseRot.z; + } + + Assert( angle1.IsValid() && angle2.IsValid() ); + if (angle1.x != angle2.x || angle1.y != angle2.y || angle1.z != angle2.z) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + + #ifdef _X360 + fltx4 q1simd, q2simd, qsimd; + q1simd = LoadAlignedSIMD( q1 ); + q2simd = LoadAlignedSIMD( q2 ); + qsimd = QuaternionBlendSIMD( q1simd, q2simd, s ); + StoreUnalignedSIMD( q.Base(), qsimd ); + #else + QuaternionBlend( q1, q2, s, q ); + #endif + } + else + { + AngleQuaternion( angle1, q ); + } + } + else + { + RadianEuler angle; + + ExtractAnimValue( frame, pValuesPtr->pAnimvalue( 0 ), baseRotScale.x, angle.x ); + ExtractAnimValue( frame, pValuesPtr->pAnimvalue( 1 ), baseRotScale.y, angle.y ); + ExtractAnimValue( frame, pValuesPtr->pAnimvalue( 2 ), baseRotScale.z, angle.z ); + + if (!(panim->flags & STUDIO_ANIM_DELTA)) + { + angle.x = angle.x + baseRot.x; + angle.y = angle.y + baseRot.y; + angle.z = angle.z + baseRot.z; + } + + Assert( angle.IsValid() ); + AngleQuaternion( angle, q ); + } + + Assert( q.IsValid() ); + + // align to unified bone + if (!(panim->flags & STUDIO_ANIM_DELTA) && (iBaseFlags & BONE_FIXED_ALIGNMENT)) + { + QuaternionAlign( baseAlignment, q, q ); + } +} + +inline void CalcBoneQuaternion( int frame, float s, + const mstudiobone_t *pBone, + const mstudiolinearbone_t *pLinearBones, + const mstudioanim_t *panim, Quaternion &q ) +{ + if (pLinearBones) + { + CalcBoneQuaternion( frame, s, pLinearBones->quat(panim->bone), pLinearBones->rot(panim->bone), pLinearBones->rotscale(panim->bone), pLinearBones->flags(panim->bone), pLinearBones->qalignment(panim->bone), panim, q ); + } + else + { + CalcBoneQuaternion( frame, s, pBone->quat, pBone->rot, pBone->rotscale, pBone->flags, pBone->qAlignment, panim, q ); + } +} + + + + + +//----------------------------------------------------------------------------- +// Purpose: return a sub frame position for a single bone +//----------------------------------------------------------------------------- +void CalcBonePosition( int frame, float s, + const Vector &basePos, const Vector &baseBoneScale, + const mstudioanim_t *panim, Vector &pos ) +{ + if (panim->flags & STUDIO_ANIM_RAWPOS) + { + pos = *(panim->pPos()); + Assert( pos.IsValid() ); + + return; + } + else if (!(panim->flags & STUDIO_ANIM_ANIMPOS)) + { + if (panim->flags & STUDIO_ANIM_DELTA) + { + pos.Init( 0.0f, 0.0f, 0.0f ); + } + else + { + pos = basePos; + } + return; + } + + mstudioanim_valueptr_t *pPosV = panim->pPosV(); + int j; + + if (s > 0.001f) + { + float v1, v2; + for (j = 0; j < 3; j++) + { + ExtractAnimValue( frame, pPosV->pAnimvalue( j ), baseBoneScale[j], v1, v2 ); + pos[j] = v1 * (1.0 - s) + v2 * s; + } + } + else + { + for (j = 0; j < 3; j++) + { + ExtractAnimValue( frame, pPosV->pAnimvalue( j ), baseBoneScale[j], pos[j] ); + } + } + + if (!(panim->flags & STUDIO_ANIM_DELTA)) + { + pos.x = pos.x + basePos.x; + pos.y = pos.y + basePos.y; + pos.z = pos.z + basePos.z; + } + + Assert( pos.IsValid() ); +} + + +inline void CalcBonePosition( int frame, float s, + const mstudiobone_t *pBone, + const mstudiolinearbone_t *pLinearBones, + const mstudioanim_t *panim, Vector &pos ) +{ + if (pLinearBones) + { + CalcBonePosition( frame, s, pLinearBones->pos(panim->bone), pLinearBones->posscale(panim->bone), panim, pos ); + } + else + { + CalcBonePosition( frame, s, pBone->pos, pBone->posscale, panim, pos ); + } +} + + + +void SetupSingleBoneMatrix( + CStudioHdr *pOwnerHdr, + int nSequence, + int iFrame, + int iBone, + matrix3x4_t &mBoneLocal ) +{ + mstudioseqdesc_t &seqdesc = pOwnerHdr->pSeqdesc( nSequence ); + mstudioanimdesc_t &animdesc = pOwnerHdr->pAnimdesc( seqdesc.anim( 0, 0 ) ); + int iLocalFrame = iFrame; + mstudioanim_t *panim = animdesc.pAnim( &iLocalFrame ); + float s = 0; + mstudiobone_t *pbone = pOwnerHdr->pBone( iBone ); + + Quaternion boneQuat; + Vector bonePos; + + // search for bone + while (panim && panim->bone != iBone) + { + panim = panim->pNext(); + } + + // look up animation if found, if not, initialize + if (panim && seqdesc.weight(iBone) > 0) + { + CalcBoneQuaternion( iLocalFrame, s, pbone, NULL, panim, boneQuat ); + CalcBonePosition ( iLocalFrame, s, pbone, NULL, panim, bonePos ); + } + else if (animdesc.flags & STUDIO_DELTA) + { + boneQuat.Init( 0.0f, 0.0f, 0.0f, 1.0f ); + bonePos.Init( 0.0f, 0.0f, 0.0f ); + } + else + { + boneQuat = pbone->quat; + bonePos = pbone->pos; + } + + QuaternionMatrix( boneQuat, bonePos, mBoneLocal ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +static void CalcDecompressedAnimation( const mstudiocompressedikerror_t *pCompressed, int iFrame, float fraq, Vector &pos, Quaternion &q ) +{ + if (fraq > 0.0001f) + { + Vector p1, p2; + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 0 ), pCompressed->scale[0], p1.x, p2.x ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 1 ), pCompressed->scale[1], p1.y, p2.y ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 2 ), pCompressed->scale[2], p1.z, p2.z ); + pos = p1 * (1 - fraq) + p2 * fraq; + + Quaternion q1, q2; + RadianEuler angle1, angle2; + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 3 ), pCompressed->scale[3], angle1.x, angle2.x ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 4 ), pCompressed->scale[4], angle1.y, angle2.y ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 5 ), pCompressed->scale[5], angle1.z, angle2.z ); + + if (angle1.x != angle2.x || angle1.y != angle2.y || angle1.z != angle2.z) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionBlend( q1, q2, fraq, q ); + } + else + { + AngleQuaternion( angle1, q ); + } + } + else + { + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 0 ), pCompressed->scale[0], pos.x ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 1 ), pCompressed->scale[1], pos.y ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 2 ), pCompressed->scale[2], pos.z ); + + RadianEuler angle; + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 3 ), pCompressed->scale[3], angle.x ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 4 ), pCompressed->scale[4], angle.y ); + ExtractAnimValue( iFrame, pCompressed->pAnimvalue( 5 ), pCompressed->scale[5], angle.z ); + + AngleQuaternion( angle, q ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: translate animations done in a non-standard parent space +//----------------------------------------------------------------------------- +static void CalcLocalHierarchyAnimation( + const CStudioHdr *pStudioHdr, + matrix3x4_t *boneToWorld, + CBoneBitList &boneComputed, + Vector *pos, + Quaternion *q, + //const mstudioanimdesc_t &animdesc, + const mstudiobone_t *pbone, + mstudiolocalhierarchy_t *pHierarchy, + int iBone, + int iNewParent, + float cycle, + int iFrame, + float flFraq, + int boneMask + ) +{ +#ifdef STAGING_ONLY + Assert( iNewParent == -1 || (iNewParent >= 0 && iNewParent < MAXSTUDIOBONES) ); + Assert( iBone > 0 ); + Assert( iBone < MAXSTUDIOBONES ); +#endif // STAGING_ONLY + + Vector localPos; + Quaternion localQ; + + // make fake root transform + static ALIGN16 matrix3x4_t rootXform ALIGN16_POST ( 1.0f, 0, 0, 0, 0, 1.0f, 0, 0, 0, 0, 1.0f, 0 ); + + // FIXME: missing check to see if seq has a weight for this bone + float weight = 1.0f; + + // check to see if there's a ramp on the influence + if ( pHierarchy->tail - pHierarchy->peak < 1.0f ) + { + float index = cycle; + + if (pHierarchy->end > 1.0f && index < pHierarchy->start) + index += 1.0f; + + if (index < pHierarchy->start) + return; + if (index >= pHierarchy->end) + return; + + if (index < pHierarchy->peak && pHierarchy->start != pHierarchy->peak) + { + weight = (index - pHierarchy->start) / (pHierarchy->peak - pHierarchy->start); + } + else if (index > pHierarchy->tail && pHierarchy->end != pHierarchy->tail) + { + weight = (pHierarchy->end - index) / (pHierarchy->end - pHierarchy->tail); + } + + weight = SimpleSpline( weight ); + } + + CalcDecompressedAnimation( pHierarchy->pLocalAnim(), iFrame - pHierarchy->iStart, flFraq, localPos, localQ ); + + BuildBoneChain( pStudioHdr, rootXform, pos, q, iBone, boneToWorld, boneComputed ); + + matrix3x4_t localXform; + AngleMatrix( localQ, localPos, localXform ); + + if ( iNewParent != -1 ) + { + BuildBoneChain( pStudioHdr, rootXform, pos, q, iNewParent, boneToWorld, boneComputed ); + ConcatTransforms( boneToWorld[iNewParent], localXform, boneToWorld[iBone] ); + } + else + { + boneToWorld[iBone] = localXform; + } + + // back solve + Vector p1; + Quaternion q1; + int n = pbone[iBone].parent; + if (n == -1) + { + if (weight == 1.0f) + { + MatrixAngles( boneToWorld[iBone], q[iBone], pos[iBone] ); + } + else + { + MatrixAngles( boneToWorld[iBone], q1, p1 ); + QuaternionSlerp( q[iBone], q1, weight, q[iBone] ); + pos[iBone] = Lerp( weight, p1, pos[iBone] ); + } + } + else + { + matrix3x4_t worldToBone; + MatrixInvert( boneToWorld[n], worldToBone ); + + matrix3x4_t local; + ConcatTransforms( worldToBone, boneToWorld[iBone], local ); + if (weight == 1.0f) + { + MatrixAngles( local, q[iBone], pos[iBone] ); + } + else + { + MatrixAngles( local, q1, p1 ); + QuaternionSlerp( q[iBone], q1, weight, q[iBone] ); + pos[iBone] = Lerp( weight, p1, pos[iBone] ); + } + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Calc Zeroframe Data +//----------------------------------------------------------------------------- + +static void CalcZeroframeData( const CStudioHdr *pStudioHdr, const studiohdr_t *pAnimStudioHdr, const virtualgroup_t *pAnimGroup, const mstudiobone_t *pAnimbone, mstudioanimdesc_t &animdesc, float fFrame, Vector *pos, Quaternion *q, int boneMask, float flWeight ) +{ + byte *pData = animdesc.pZeroFrameData(); + + if (!pData) + return; + + int i, j; + + // Msg("zeroframe %s\n", animdesc.pszName() ); + if (animdesc.zeroframecount == 1) + { + for (j = 0; j < pAnimStudioHdr->numbones; j++) + { + if (pAnimGroup) + i = pAnimGroup->masterBone[j]; + else + i = j; + + if (pAnimbone[j].flags & BONE_HAS_SAVEFRAME_POS) + { + if ((i >= 0) && (pStudioHdr->boneFlags(i) & boneMask)) + { + Vector p = *(Vector48 *)pData; + pos[i] = pos[i] * (1.0f - flWeight) + p * flWeight; + Assert( pos[i].IsValid() ); + } + pData += sizeof( Vector48 ); + } + if (pAnimbone[j].flags & BONE_HAS_SAVEFRAME_ROT) + { + if ((i >= 0) && (pStudioHdr->boneFlags(i) & boneMask)) + { + Quaternion q0 = *(Quaternion64 *)pData; + QuaternionBlend( q[i], q0, flWeight, q[i] ); + Assert( q[i].IsValid() ); + } + pData += sizeof( Quaternion64 ); + } + } + } + else + { + float s1; + int index = fFrame / animdesc.zeroframespan; + if (index >= animdesc.zeroframecount - 1) + { + index = animdesc.zeroframecount - 2; + s1 = 1.0f; + } + else + { + s1 = clamp( (fFrame - index * animdesc.zeroframespan) / animdesc.zeroframespan, 0.0f, 1.0f ); + } + int i0 = vmax( index - 1, 0 ); + int i1 = index; + int i2 = vmin( index + 1, animdesc.zeroframecount - 1 ); + for (j = 0; j < pAnimStudioHdr->numbones; j++) + { + if (pAnimGroup) + i = pAnimGroup->masterBone[j]; + else + i = j; + + if (pAnimbone[j].flags & BONE_HAS_SAVEFRAME_POS) + { + if ((i >= 0) && (pStudioHdr->boneFlags(i) & boneMask)) + { + Vector p0 = *(((Vector48 *)pData) + i0); + Vector p1 = *(((Vector48 *)pData) + i1); + Vector p2 = *(((Vector48 *)pData) + i2); + Vector p3; + Hermite_Spline( p0, p1, p2, s1, p3 ); + pos[i] = pos[i] * (1.0f - flWeight) + p3 * flWeight; + Assert( pos[i].IsValid() ); + } + pData += sizeof( Vector48 ) * animdesc.zeroframecount; + } + if (pAnimbone[j].flags & BONE_HAS_SAVEFRAME_ROT) + { + if ((i >= 0) && (pStudioHdr->boneFlags(i) & boneMask)) + { + Quaternion q0 = *(((Quaternion64 *)pData) + i0); + Quaternion q1 = *(((Quaternion64 *)pData) + i1); + Quaternion q2 = *(((Quaternion64 *)pData) + i2); + if (flWeight == 1.0f) + { + Hermite_Spline( q0, q1, q2, s1, q[i] ); + } + else + { + Quaternion q3; + Hermite_Spline( q0, q1, q2, s1, q3 ); + QuaternionBlend( q[i], q3, flWeight, q[i] ); + } + Assert( q[i].IsValid() ); + } + pData += sizeof( Quaternion64 ) * animdesc.zeroframecount; + } + } + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Find and decode a sub-frame of animation, remapping the skeleton bone indexes +//----------------------------------------------------------------------------- +static void CalcVirtualAnimation( virtualmodel_t *pVModel, const CStudioHdr *pStudioHdr, Vector *pos, Quaternion *q, + mstudioseqdesc_t &seqdesc, int sequence, int animation, + float cycle, int boneMask ) +{ + int i, j, k; + + const mstudiobone_t *pbone; + const virtualgroup_t *pSeqGroup; + const studiohdr_t *pSeqStudioHdr; + const mstudiolinearbone_t *pSeqLinearBones; + const mstudiobone_t *pSeqbone; + const mstudioanim_t *panim; + const studiohdr_t *pAnimStudioHdr; + const mstudiolinearbone_t *pAnimLinearBones; + const mstudiobone_t *pAnimbone; + const virtualgroup_t *pAnimGroup; + + pSeqGroup = pVModel->pSeqGroup( sequence ); + int baseanimation = pStudioHdr->iRelativeAnim( sequence, animation ); + mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( baseanimation ); + pSeqStudioHdr = ((CStudioHdr *)pStudioHdr)->pSeqStudioHdr( sequence ); + pSeqLinearBones = pSeqStudioHdr->pLinearBones(); + pSeqbone = pSeqStudioHdr->pBone( 0 ); + pAnimGroup = pVModel->pAnimGroup( baseanimation ); + pAnimStudioHdr = ((CStudioHdr *)pStudioHdr)->pAnimStudioHdr( baseanimation ); + pAnimLinearBones = pAnimStudioHdr->pLinearBones(); + pAnimbone = pAnimStudioHdr->pBone( 0 ); + + int iFrame; + float s; + + float fFrame = cycle * (animdesc.numframes - 1); + + iFrame = (int)fFrame; + s = (fFrame - iFrame); + + int iLocalFrame = iFrame; + float flStall; + panim = animdesc.pAnim( &iLocalFrame, flStall ); + + float *pweight = seqdesc.pBoneweight( 0 ); + pbone = pStudioHdr->pBone( 0 ); + + for (i = 0; i < pStudioHdr->numbones(); i++) + { + if (pStudioHdr->boneFlags(i) & boneMask) + { + int j = pSeqGroup->boneMap[i]; + if (j >= 0 && pweight[j] > 0.0f) + { + if (animdesc.flags & STUDIO_DELTA) + { + q[i].Init( 0.0f, 0.0f, 0.0f, 1.0f ); + pos[i].Init( 0.0f, 0.0f, 0.0f ); + } + else if (pSeqLinearBones) + { + q[i] = pSeqLinearBones->quat(j); + pos[i] = pSeqLinearBones->pos(j); + } + else + { + q[i] = pSeqbone[j].quat; + pos[i] = pSeqbone[j].pos; + } +#ifdef STUDIO_ENABLE_PERF_COUNTERS + pStudioHdr->m_nPerfUsedBones++; +#endif + } + } + } + + // if the animation isn't available, look for the zero frame cache + if (!panim) + { + CalcZeroframeData( ((CStudioHdr *)pStudioHdr), pAnimStudioHdr, pAnimGroup, pAnimbone, animdesc, fFrame, pos, q, boneMask, 1.0 ); + return; + } + + // FIXME: change encoding so that bone -1 is never the case + while (panim && panim->bone < 255) + { + j = pAnimGroup->masterBone[panim->bone]; + if ( j >= 0 && ( pStudioHdr->boneFlags(j) & boneMask ) ) + { + k = pSeqGroup->boneMap[j]; + + if (k >= 0 && pweight[k] > 0.0f) + { + CalcBoneQuaternion( iLocalFrame, s, &pAnimbone[panim->bone], pAnimLinearBones, panim, q[j] ); + CalcBonePosition ( iLocalFrame, s, &pAnimbone[panim->bone], pAnimLinearBones, panim, pos[j] ); +#ifdef STUDIO_ENABLE_PERF_COUNTERS + pStudioHdr->m_nPerfAnimatedBones++; +#endif + } + } + panim = panim->pNext(); + } + + // cross fade in previous zeroframe data + if (flStall > 0.0f) + { + CalcZeroframeData( pStudioHdr, pAnimStudioHdr, pAnimGroup, pAnimbone, animdesc, fFrame, pos, q, boneMask, flStall ); + } + + // calculate a local hierarchy override + if (animdesc.numlocalhierarchy) + { + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + + int i; + for (i = 0; i < animdesc.numlocalhierarchy; i++) + { + mstudiolocalhierarchy_t *pHierarchy = animdesc.pHierarchy( i ); + + if ( !pHierarchy ) + break; + + int iBone = pAnimGroup->masterBone[pHierarchy->iBone]; + if (iBone >= 0 && (pStudioHdr->boneFlags(iBone) & boneMask)) + { + if ( pHierarchy->iNewParent != -1 ) + { + int iNewParent = pAnimGroup->masterBone[pHierarchy->iNewParent]; + if (iNewParent >= 0 && (pStudioHdr->boneFlags(iNewParent) & boneMask)) + { + CalcLocalHierarchyAnimation( pStudioHdr, boneToWorld, boneComputed, pos, q, pbone, pHierarchy, iBone, iNewParent, cycle, iFrame, s, boneMask ); + } + } + else + { + CalcLocalHierarchyAnimation( pStudioHdr, boneToWorld, boneComputed, pos, q, pbone, pHierarchy, iBone, -1, cycle, iFrame, s, boneMask ); + } + } + } + + g_MatrixPool.Free( boneToWorld ); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Find and decode a sub-frame of animation +//----------------------------------------------------------------------------- + +static void CalcAnimation( const CStudioHdr *pStudioHdr, Vector *pos, Quaternion *q, + mstudioseqdesc_t &seqdesc, + int sequence, int animation, + float cycle, int boneMask ) +{ +#ifdef STUDIO_ENABLE_PERF_COUNTERS + pStudioHdr->m_nPerfAnimationLayers++; +#endif + + virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel(); + + if (pVModel) + { + CalcVirtualAnimation( pVModel, pStudioHdr, pos, q, seqdesc, sequence, animation, cycle, boneMask ); + return; + } + + mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( animation ); + mstudiobone_t *pbone = pStudioHdr->pBone( 0 ); + const mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones(); + + int i; + int iFrame; + float s; + + float fFrame = cycle * (animdesc.numframes - 1); + + iFrame = (int)fFrame; + s = (fFrame - iFrame); + + int iLocalFrame = iFrame; + float flStall; + mstudioanim_t *panim = animdesc.pAnim( &iLocalFrame, flStall ); + + float *pweight = seqdesc.pBoneweight( 0 ); + + // if the animation isn't available, look for the zero frame cache + if (!panim) + { + // Msg("zeroframe %s\n", animdesc.pszName() ); + // pre initialize + for (i = 0; i < pStudioHdr->numbones(); i++, pbone++, pweight++) + { + if (*pweight > 0 && (pStudioHdr->boneFlags(i) & boneMask)) + { + if (animdesc.flags & STUDIO_DELTA) + { + q[i].Init( 0.0f, 0.0f, 0.0f, 1.0f ); + pos[i].Init( 0.0f, 0.0f, 0.0f ); + } + else + { + q[i] = pbone->quat; + pos[i] = pbone->pos; + } + } + } + + CalcZeroframeData( pStudioHdr, pStudioHdr->GetRenderHdr(), NULL, pStudioHdr->pBone( 0 ), animdesc, fFrame, pos, q, boneMask, 1.0 ); + + return; + } + + // BUGBUG: the sequence, the anim, and the model can have all different bone mappings. + for (i = 0; i < pStudioHdr->numbones(); i++, pbone++, pweight++) + { + if (panim && panim->bone == i) + { + if (*pweight > 0 && (pStudioHdr->boneFlags(i) & boneMask)) + { + CalcBoneQuaternion( iLocalFrame, s, pbone, pLinearBones, panim, q[i] ); + CalcBonePosition ( iLocalFrame, s, pbone, pLinearBones, panim, pos[i] ); +#ifdef STUDIO_ENABLE_PERF_COUNTERS + pStudioHdr->m_nPerfAnimatedBones++; + pStudioHdr->m_nPerfUsedBones++; +#endif + } + panim = panim->pNext(); + } + else if (*pweight > 0 && (pStudioHdr->boneFlags(i) & boneMask)) + { + if (animdesc.flags & STUDIO_DELTA) + { + q[i].Init( 0.0f, 0.0f, 0.0f, 1.0f ); + pos[i].Init( 0.0f, 0.0f, 0.0f ); + } + else + { + q[i] = pbone->quat; + pos[i] = pbone->pos; + } +#ifdef STUDIO_ENABLE_PERF_COUNTERS + pStudioHdr->m_nPerfUsedBones++; +#endif + } + } + + // cross fade in previous zeroframe data + if (flStall > 0.0f) + { + CalcZeroframeData( pStudioHdr, pStudioHdr->GetRenderHdr(), NULL, pStudioHdr->pBone( 0 ), animdesc, fFrame, pos, q, boneMask, flStall ); + } + + if (animdesc.numlocalhierarchy) + { + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + + int i; + for (i = 0; i < animdesc.numlocalhierarchy; i++) + { + mstudiolocalhierarchy_t *pHierarchy = animdesc.pHierarchy( i ); + + if ( !pHierarchy ) + break; + + if (pStudioHdr->boneFlags(pHierarchy->iBone) & boneMask) + { + if (pStudioHdr->boneFlags(pHierarchy->iNewParent) & boneMask) + { + CalcLocalHierarchyAnimation( pStudioHdr, boneToWorld, boneComputed, pos, q, pbone, pHierarchy, pHierarchy->iBone, pHierarchy->iNewParent, cycle, iFrame, s, boneMask ); + } + } + } + + g_MatrixPool.Free( boneToWorld ); + } + +} + + +//----------------------------------------------------------------------------- +// Purpose: qt = ( s * p ) * q +//----------------------------------------------------------------------------- +void QuaternionSM( float s, const Quaternion &p, const Quaternion &q, Quaternion &qt ) +{ + Quaternion p1, q1; + + QuaternionScale( p, s, p1 ); + QuaternionMult( p1, q, q1 ); + QuaternionNormalize( q1 ); + qt[0] = q1[0]; + qt[1] = q1[1]; + qt[2] = q1[2]; + qt[3] = q1[3]; +} + +#if ALLOW_SIMD_QUATERNION_MATH +FORCEINLINE fltx4 QuaternionSMSIMD( float s, const fltx4 &p, const fltx4 &q ) +{ + fltx4 p1, q1, result; + p1 = QuaternionScaleSIMD( p, s ); + q1 = QuaternionMultSIMD( p1, q ); + result = QuaternionNormalizeSIMD( q1 ); + return result; +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: qt = p * ( s * q ) +//----------------------------------------------------------------------------- +void QuaternionMA( const Quaternion &p, float s, const Quaternion &q, Quaternion &qt ) +{ + Quaternion p1, q1; + + QuaternionScale( q, s, q1 ); + QuaternionMult( p, q1, p1 ); + QuaternionNormalize( p1 ); + qt[0] = p1[0]; + qt[1] = p1[1]; + qt[2] = p1[2]; + qt[3] = p1[3]; +} + +#if ALLOW_SIMD_QUATERNION_MATH +FORCEINLINE fltx4 QuaternionMASIMD( const fltx4 &p, float s, const fltx4 &q ) +{ + fltx4 p1, q1, result; + q1 = QuaternionScaleSIMD( q, s ); + p1 = QuaternionMultSIMD( p, q1 ); + result = QuaternionNormalizeSIMD( p1 ); + return result; +} +#endif + + +//----------------------------------------------------------------------------- +// Purpose: qt = p + s * q +//----------------------------------------------------------------------------- +void QuaternionAccumulate( const Quaternion &p, float s, const Quaternion &q, Quaternion &qt ) +{ + Quaternion q2; + QuaternionAlign( p, q, q2 ); + + qt[0] = p[0] + s * q2[0]; + qt[1] = p[1] + s * q2[1]; + qt[2] = p[2] + s * q2[2]; + qt[3] = p[3] + s * q2[3]; +} + +#if ALLOW_SIMD_QUATERNION_MATH +FORCEINLINE fltx4 QuaternionAccumulateSIMD( const fltx4 &p, float s, const fltx4 &q ) +{ + fltx4 q2, s4, result; + q2 = QuaternionAlignSIMD( p, q ); + s4 = ReplicateX4( s ); + result = MaddSIMD( s4, q2, p ); + return result; +} +#endif + + + +//----------------------------------------------------------------------------- +// Purpose: blend together in world space q1,pos1 with q2,pos2. Return result in q1,pos1. +// 0 returns q1, pos1. 1 returns q2, pos2 +//----------------------------------------------------------------------------- + +void WorldSpaceSlerp( + const CStudioHdr *pStudioHdr, + Quaternion q1[MAXSTUDIOBONES], + Vector pos1[MAXSTUDIOBONES], + mstudioseqdesc_t &seqdesc, + int sequence, + const Quaternion q2[MAXSTUDIOBONES], + const Vector pos2[MAXSTUDIOBONES], + float s, + int boneMask ) +{ + int i, j; + float s1; // weight of parent for q2, pos2 + float s2; // weight for q2, pos2 + + // make fake root transform + matrix3x4_t rootXform; + SetIdentityMatrix( rootXform ); + + // matrices for q2, pos2 + matrix3x4_t *srcBoneToWorld = g_MatrixPool.Alloc(); + CBoneBitList srcBoneComputed; + + matrix3x4_t *destBoneToWorld = g_MatrixPool.Alloc(); + CBoneBitList destBoneComputed; + + matrix3x4_t *targetBoneToWorld = g_MatrixPool.Alloc(); + CBoneBitList targetBoneComputed; + + virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel(); + const virtualgroup_t *pSeqGroup = NULL; + if (pVModel) + { + pSeqGroup = pVModel->pSeqGroup( sequence ); + } + + mstudiobone_t *pbone = pStudioHdr->pBone( 0 ); + + for (i = 0; i < pStudioHdr->numbones(); i++) + { + // skip unused bones + if (!(pStudioHdr->boneFlags(i) & boneMask)) + { + continue; + } + + int n = pbone[i].parent; + s1 = 0.0; + if (pSeqGroup) + { + j = pSeqGroup->boneMap[i]; + if (j >= 0) + { + s2 = s * seqdesc.weight( j ); // blend in based on this bones weight + if (n != -1) + { + s1 = s * seqdesc.weight( pSeqGroup->boneMap[n] ); + } + } + else + { + s2 = 0.0; + } + } + else + { + s2 = s * seqdesc.weight( i ); // blend in based on this bones weight + if (n != -1) + { + s1 = s * seqdesc.weight( n ); + } + } + + if (s1 == 1.0 && s2 == 1.0) + { + pos1[i] = pos2[i]; + q1[i] = q2[i]; + } + else if (s2 > 0.0) + { + Quaternion srcQ, destQ; + Vector srcPos, destPos; + Quaternion targetQ; + Vector targetPos; + Vector tmp; + + BuildBoneChain( pStudioHdr, rootXform, pos1, q1, i, destBoneToWorld, destBoneComputed ); + BuildBoneChain( pStudioHdr, rootXform, pos2, q2, i, srcBoneToWorld, srcBoneComputed ); + + MatrixAngles( destBoneToWorld[i], destQ, destPos ); + MatrixAngles( srcBoneToWorld[i], srcQ, srcPos ); + + QuaternionSlerp( destQ, srcQ, s2, targetQ ); + AngleMatrix( targetQ, destPos, targetBoneToWorld[i] ); + + // back solve + if (n == -1) + { + MatrixAngles( targetBoneToWorld[i], q1[i], tmp ); + } + else + { + matrix3x4_t worldToBone; + MatrixInvert( targetBoneToWorld[n], worldToBone ); + + matrix3x4_t local; + ConcatTransforms( worldToBone, targetBoneToWorld[i], local ); + MatrixAngles( local, q1[i], tmp ); + + // blend bone lengths (local space) + pos1[i] = Lerp( s2, pos1[i], pos2[i] ); + } + } + } + g_MatrixPool.Free( srcBoneToWorld ); + g_MatrixPool.Free( destBoneToWorld ); + g_MatrixPool.Free( targetBoneToWorld ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: blend together q1,pos1 with q2,pos2. Return result in q1,pos1. +// 0 returns q1, pos1. 1 returns q2, pos2 +//----------------------------------------------------------------------------- +void SlerpBones( + const CStudioHdr *pStudioHdr, + Quaternion q1[MAXSTUDIOBONES], + Vector pos1[MAXSTUDIOBONES], + mstudioseqdesc_t &seqdesc, // source of q2 and pos2 + int sequence, + const QuaternionAligned q2[MAXSTUDIOBONES], + const Vector pos2[MAXSTUDIOBONES], + float s, + int boneMask ) +{ + if (s <= 0.0f) + return; + if (s > 1.0f) + { + s = 1.0f; + } + + if (seqdesc.flags & STUDIO_WORLD) + { + WorldSpaceSlerp( pStudioHdr, q1, pos1, seqdesc, sequence, q2, pos2, s, boneMask ); + return; + } + + int i, j; + virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel(); + const virtualgroup_t *pSeqGroup = NULL; + if (pVModel) + { + pSeqGroup = pVModel->pSeqGroup( sequence ); + } + + // Build weightlist for all bones + int nBoneCount = pStudioHdr->numbones(); + float *pS2 = (float*)stackalloc( nBoneCount * sizeof(float) ); + for (i = 0; i < nBoneCount; i++) + { + // skip unused bones + if (!(pStudioHdr->boneFlags(i) & boneMask)) + { + pS2[i] = 0.0f; + continue; + } + + if ( !pSeqGroup ) + { + pS2[i] = s * seqdesc.weight( i ); // blend in based on this bones weight + continue; + } + + j = pSeqGroup->boneMap[i]; + if ( j >= 0 ) + { + pS2[i] = s * seqdesc.weight( j ); // blend in based on this bones weight + } + else + { + pS2[i] = 0.0; + } + } + + float s1, s2; + if ( seqdesc.flags & STUDIO_DELTA ) + { + for ( i = 0; i < nBoneCount; i++ ) + { + s2 = pS2[i]; + if ( s2 <= 0.0f ) + continue; + + if ( seqdesc.flags & STUDIO_POST ) + { +#ifndef _X360 + QuaternionMA( q1[i], s2, q2[i], q1[i] ); +#else + fltx4 q1simd = LoadUnalignedSIMD( q1[i].Base() ); + fltx4 q2simd = LoadAlignedSIMD( q2[i] ); + fltx4 result = QuaternionMASIMD( q1simd, s2, q2simd ); + StoreUnalignedSIMD( q1[i].Base(), result ); +#endif + // FIXME: are these correct? + pos1[i][0] = pos1[i][0] + pos2[i][0] * s2; + pos1[i][1] = pos1[i][1] + pos2[i][1] * s2; + pos1[i][2] = pos1[i][2] + pos2[i][2] * s2; + } + else + { +#ifndef _X360 + QuaternionSM( s2, q2[i], q1[i], q1[i] ); +#else + fltx4 q1simd = LoadUnalignedSIMD( q1[i].Base() ); + fltx4 q2simd = LoadAlignedSIMD( q2[i] ); + fltx4 result = QuaternionSMSIMD( s2, q2simd, q1simd ); + StoreUnalignedSIMD( q1[i].Base(), result ); +#endif + + // FIXME: are these correct? + pos1[i][0] = pos1[i][0] + pos2[i][0] * s2; + pos1[i][1] = pos1[i][1] + pos2[i][1] * s2; + pos1[i][2] = pos1[i][2] + pos2[i][2] * s2; + } + } + return; + } + + QuaternionAligned q3; + for (i = 0; i < nBoneCount; i++) + { + s2 = pS2[i]; + if ( s2 <= 0.0f ) + continue; + + s1 = 1.0 - s2; + +#ifdef _X360 + fltx4 q1simd, q2simd, result; + q1simd = LoadUnalignedSIMD( q1[i].Base() ); + q2simd = LoadAlignedSIMD( q2[i] ); +#endif + if ( pStudioHdr->boneFlags(i) & BONE_FIXED_ALIGNMENT ) + { +#ifndef _X360 + QuaternionSlerpNoAlign( q2[i], q1[i], s1, q3 ); +#else + result = QuaternionSlerpNoAlignSIMD( q2simd, q1simd, s1 ); +#endif + } + else + { +#ifndef _X360 + QuaternionSlerp( q2[i], q1[i], s1, q3 ); +#else + result = QuaternionSlerpSIMD( q2simd, q1simd, s1 ); +#endif + } + +#ifndef _X360 + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; +#else + StoreUnalignedSIMD( q1[i].Base(), result ); +#endif + + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s2; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s2; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s2; + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Inter-animation blend. Assumes both types are identical. +// blend together q1,pos1 with q2,pos2. Return result in q1,pos1. +// 0 returns q1, pos1. 1 returns q2, pos2 +//----------------------------------------------------------------------------- +void BlendBones( + const CStudioHdr *pStudioHdr, + Quaternion q1[MAXSTUDIOBONES], + Vector pos1[MAXSTUDIOBONES], + mstudioseqdesc_t &seqdesc, + int sequence, + const Quaternion q2[MAXSTUDIOBONES], + const Vector pos2[MAXSTUDIOBONES], + float s, + int boneMask ) +{ + int i, j; + Quaternion q3; + + virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel(); + const virtualgroup_t *pSeqGroup = NULL; + if (pVModel) + { + pSeqGroup = pVModel->pSeqGroup( sequence ); + } + + if (s <= 0) + { + Assert(0); // shouldn't have been called + return; + } + else if (s >= 1.0) + { + Assert(0); // shouldn't have been called + for (i = 0; i < pStudioHdr->numbones(); i++) + { + // skip unused bones + if (!(pStudioHdr->boneFlags(i) & boneMask)) + { + continue; + } + + if (pSeqGroup) + { + j = pSeqGroup->boneMap[i]; + } + else + { + j = i; + } + + if (j >= 0 && seqdesc.weight( j ) > 0.0) + { + q1[i] = q2[i]; + pos1[i] = pos2[i]; + } + } + return; + } + + float s2 = s; + float s1 = 1.0 - s2; + + for (i = 0; i < pStudioHdr->numbones(); i++) + { + // skip unused bones + if (!(pStudioHdr->boneFlags(i) & boneMask)) + { + continue; + } + + if (pSeqGroup) + { + j = pSeqGroup->boneMap[i]; + } + else + { + j = i; + } + + if (j >= 0 && seqdesc.weight( j ) > 0.0) + { + if (pStudioHdr->boneFlags(i) & BONE_FIXED_ALIGNMENT) + { + QuaternionBlendNoAlign( q2[i], q1[i], s1, q3 ); + } + else + { + QuaternionBlend( q2[i], q1[i], s1, q3 ); + } + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s2; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s2; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s2; + } + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Scale a set of bones. Must be of type delta +//----------------------------------------------------------------------------- +void ScaleBones( + const CStudioHdr *pStudioHdr, + Quaternion q1[MAXSTUDIOBONES], + Vector pos1[MAXSTUDIOBONES], + int sequence, + float s, + int boneMask ) +{ + int i, j; + Quaternion q3; + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( sequence ); + + virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel(); + const virtualgroup_t *pSeqGroup = NULL; + if (pVModel) + { + pSeqGroup = pVModel->pSeqGroup( sequence ); + } + + float s2 = s; + float s1 = 1.0 - s2; + + for (i = 0; i < pStudioHdr->numbones(); i++) + { + // skip unused bones + if (!(pStudioHdr->boneFlags(i) & boneMask)) + { + continue; + } + + if (pSeqGroup) + { + j = pSeqGroup->boneMap[i]; + } + else + { + j = i; + } + + if (j >= 0 && seqdesc.weight( j ) > 0.0) + { + QuaternionIdentityBlend( q1[i], s1, q1[i] ); + VectorScale( pos1[i], s2, pos1[i] ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: resolve a global pose parameter to the specific setting for this sequence +//----------------------------------------------------------------------------- +void Studio_LocalPoseParameter( const CStudioHdr *pStudioHdr, const float poseParameter[], mstudioseqdesc_t &seqdesc, int iSequence, int iLocalIndex, float &flSetting, int &index ) +{ + int iPose = pStudioHdr->GetSharedPoseParameter( iSequence, seqdesc.paramindex[iLocalIndex] ); + + if (iPose == -1) + { + flSetting = 0; + index = 0; + return; + } + + const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)pStudioHdr)->pPoseParameter( iPose ); + + float flValue = poseParameter[iPose]; + + if (Pose.loop) + { + float wrap = (Pose.start + Pose.end) / 2.0 + Pose.loop / 2.0; + float shift = Pose.loop - wrap; + + flValue = flValue - Pose.loop * floor((flValue + shift) / Pose.loop); + } + + if (seqdesc.posekeyindex == 0) + { + float flLocalStart = ((float)seqdesc.paramstart[iLocalIndex] - Pose.start) / (Pose.end - Pose.start); + float flLocalEnd = ((float)seqdesc.paramend[iLocalIndex] - Pose.start) / (Pose.end - Pose.start); + + // convert into local range + flSetting = (flValue - flLocalStart) / (flLocalEnd - flLocalStart); + + // clamp. This shouldn't ever need to happen if it's looping. + if (flSetting < 0) + flSetting = 0; + if (flSetting > 1) + flSetting = 1; + + index = 0; + if (seqdesc.groupsize[iLocalIndex] > 2 ) + { + // estimate index + index = (int)(flSetting * (seqdesc.groupsize[iLocalIndex] - 1)); + if (index == seqdesc.groupsize[iLocalIndex] - 1) index = seqdesc.groupsize[iLocalIndex] - 2; + flSetting = flSetting * (seqdesc.groupsize[iLocalIndex] - 1) - index; + } + } + else + { + flValue = flValue * (Pose.end - Pose.start) + Pose.start; + index = 0; + + // FIXME: this needs to be 2D + // FIXME: this shouldn't be a linear search + + while (1) + { + flSetting = (flValue - seqdesc.poseKey( iLocalIndex, index )) / (seqdesc.poseKey( iLocalIndex, index + 1 ) - seqdesc.poseKey( iLocalIndex, index )); + /* + if (index > 0 && flSetting < 0.0) + { + index--; + continue; + } + else + */ + if (index < seqdesc.groupsize[iLocalIndex] - 2 && flSetting > 1.0) + { + index++; + continue; + } + break; + } + + // clamp. + if (flSetting < 0.0f) + flSetting = 0.0f; + if (flSetting > 1.0f) + flSetting = 1.0f; + } +} + +void Studio_CalcBoneToBoneTransform( const CStudioHdr *pStudioHdr, int inputBoneIndex, int outputBoneIndex, matrix3x4_t& matrixOut ) +{ + mstudiobone_t *pbone = pStudioHdr->pBone( inputBoneIndex ); + + matrix3x4_t inputToPose; + MatrixInvert( pbone->poseToBone, inputToPose ); + ConcatTransforms( pStudioHdr->pBone( outputBoneIndex )->poseToBone, inputToPose, matrixOut ); +} + +//----------------------------------------------------------------------------- +// Purpose: calculate a pose for a single sequence +//----------------------------------------------------------------------------- +void InitPose( + const CStudioHdr *pStudioHdr, + Vector pos[], + Quaternion q[], + int boneMask + ) +{ + if (!pStudioHdr->pLinearBones()) + { + for (int i = 0; i < pStudioHdr->numbones(); i++) + { + if (pStudioHdr->boneFlags( i ) & boneMask ) + { + mstudiobone_t *pbone = pStudioHdr->pBone( i ); + pos[i] = pbone->pos; + q[i] = pbone->quat; + } + } + } + else + { + mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones(); + for (int i = 0; i < pStudioHdr->numbones(); i++) + { + if (pStudioHdr->boneFlags( i ) & boneMask ) + { + pos[i] = pLinearBones->pos(i); + q[i] = pLinearBones->quat(i); + } + } + } +} + + +inline bool PoseIsAllZeros( + const CStudioHdr *pStudioHdr, + int sequence, + mstudioseqdesc_t &seqdesc, + int i0, + int i1 + ) +{ + int baseanim; + + // remove "zero" positional blends + baseanim = pStudioHdr->iRelativeAnim( sequence, seqdesc.anim(i0 ,i1 ) ); + mstudioanimdesc_t &anim = ((CStudioHdr *)pStudioHdr)->pAnimdesc( baseanim ); + return (anim.flags & STUDIO_ALLZEROS) != 0; +} + +//----------------------------------------------------------------------------- +// Purpose: turn a 2x2 blend into a 3 way triangle blend +// Returns: returns the animination indices and barycentric coordinates of a triangle +// the triangle is a right triangle, and the diagonal is between elements [0] and [2] +//----------------------------------------------------------------------------- + +static ConVar anim_3wayblend( "anim_3wayblend", "1", FCVAR_REPLICATED, "Toggle the 3-way animation blending code." ); + +void Calc3WayBlendIndices( int i0, int i1, float s0, float s1, const mstudioseqdesc_t &seqdesc, int *pAnimIndices, float *pWeight ) +{ + // Figure out which bi-section direction we are using to make triangles. + bool bEven = ( ( ( i0 + i1 ) & 0x1 ) == 0 ); + + int x1, y1; + int x2, y2; + int x3, y3; + + // diagonal is between elements 1 & 3 + // TL to BR + if ( bEven ) + { + if ( s0 > s1 ) + { + // B + x1 = 0; y1 = 0; + x2 = 1; y2 = 0; + x3 = 1; y3 = 1; + pWeight[0] = (1.0f - s0); + pWeight[1] = s0 - s1; + } + else + { + // C + x1 = 1; y1 = 1; + x2 = 0; y2 = 1; + x3 = 0; y3 = 0; + pWeight[0] = s0; + pWeight[1] = s1 - s0; + } + } + // BL to TR + else + { + float flTotal = s0 + s1; + + if( flTotal > 1.0f ) + { + // D + x1 = 1; y1 = 0; + x2 = 1; y2 = 1; + x3 = 0; y3 = 1; + pWeight[0] = (1.0f - s1); + pWeight[1] = s0 - 1.0f + s1; + } + else + { + // A + x1 = 0; y1 = 1; + x2 = 0; y2 = 0; + x3 = 1; y3 = 0; + pWeight[0] = s1; + pWeight[1] = 1.0f - s0 - s1; + } + } + + pAnimIndices[0] = seqdesc.anim( i0 + x1, i1 + y1 ); + pAnimIndices[1] = seqdesc.anim( i0 + x2, i1 + y2 ); + pAnimIndices[2] = seqdesc.anim( i0 + x3, i1 + y3 ); + + /* + float w0 = ((x2-x3)*(y3-s1) - (x3-s0)*(y2-y3)) / ((x1-x3)*(y2-y3) - (x2-x3)*(y1-y3)); + float w1 = ((x1-x3)*(y3-s1) - (x3-s0)*(y1-y3)) / ((x2-x3)*(y1-y3) - (x1-x3)*(y2-y3)); + Assert( pWeight[0] == w0 && pWeight[1] == w1 ); + */ + + // clamp the diagonal + if (pWeight[1] < 0.001f) + pWeight[1] = 0.0f; + pWeight[2] = 1.0f - pWeight[0] - pWeight[1]; + + Assert( pWeight[0] >= 0.0f && pWeight[0] <= 1.0f ); + Assert( pWeight[1] >= 0.0f && pWeight[1] <= 1.0f ); + Assert( pWeight[2] >= 0.0f && pWeight[2] <= 1.0f ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: calculate a pose for a single sequence +//----------------------------------------------------------------------------- +bool CalcPoseSingle( + const CStudioHdr *pStudioHdr, + Vector pos[], + Quaternion q[], + mstudioseqdesc_t &seqdesc, + int sequence, + float cycle, + const float poseParameter[], + int boneMask, + float flTime + ) +{ + bool bResult = true; + + Vector *pos2 = g_VectorPool.Alloc(); + Quaternion *q2 = g_QaternionPool.Alloc(); + Vector *pos3= g_VectorPool.Alloc(); + Quaternion *q3 = g_QaternionPool.Alloc(); + + if (sequence >= pStudioHdr->GetNumSeq()) + { + sequence = 0; + seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( sequence ); + } + + + int i0 = 0, i1 = 0; + float s0 = 0, s1 = 0; + + Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, sequence, 0, s0, i0 ); + Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, sequence, 1, s1, i1 ); + + + if (seqdesc.flags & STUDIO_REALTIME) + { + float cps = Studio_CPS( pStudioHdr, seqdesc, sequence, poseParameter ); + cycle = flTime * cps; + cycle = cycle - (int)cycle; + } + else if (seqdesc.flags & STUDIO_CYCLEPOSE) + { + int iPose = pStudioHdr->GetSharedPoseParameter( sequence, seqdesc.cycleposeindex ); + if (iPose != -1) + { + /* + const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)pStudioHdr)->pPoseParameter( iPose ); + cycle = poseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start; + */ + cycle = poseParameter[ iPose ]; + } + else + { + cycle = 0.0f; + } + } + else if (cycle < 0 || cycle >= 1) + { + if (seqdesc.flags & STUDIO_LOOPING) + { + cycle = cycle - (int)cycle; + if (cycle < 0) cycle += 1; + } + else + { + cycle = clamp( cycle, 0.0f, 1.0f ); + } + } + + if (s0 < 0.001) + { + if (s1 < 0.001) + { + if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0, i1 )) + { + bResult = false; + } + else + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 , i1 ), cycle, boneMask ); + } + } + else if (s1 > 0.999) + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 , i1+1 ), cycle, boneMask ); + } + else + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 , i1 ), cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0 , i1+1 ), cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s1, boneMask ); + } + } + else if (s0 > 0.999) + { + if (s1 < 0.001) + { + if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0+1, i1 )) + { + bResult = false; + } + else + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1, i1 ), cycle, boneMask ); + } + } + else if (s1 > 0.999) + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1, i1+1 ), cycle, boneMask ); + } + else + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1, i1 ), cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1, i1+1 ), cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s1, boneMask ); + } + } + else + { + if (s1 < 0.001) + { + if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0+1, i1 )) + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1 ), cycle, boneMask ); + ScaleBones( pStudioHdr, q, pos, sequence, 1.0 - s0, boneMask ); + } + else if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0, i1 )) + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1 ,i1 ), cycle, boneMask ); + ScaleBones( pStudioHdr, q, pos, sequence, s0, boneMask ); + } + else + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1 ), cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1,i1 ), cycle, boneMask ); + + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s0, boneMask ); + } + } + else if (s1 > 0.999) + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1+1 ), cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1,i1+1 ), cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s0, boneMask ); + } + else if ( !anim_3wayblend.GetBool() ) + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1 ), cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1,i1 ), cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s0, boneMask ); + + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0 , i1+1), cycle, boneMask ); + CalcAnimation( pStudioHdr, pos3, q3, seqdesc, sequence, seqdesc.anim( i0+1, i1+1), cycle, boneMask ); + BlendBones( pStudioHdr, q2, pos2, seqdesc, sequence, q3, pos3, s0, boneMask ); + + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s1, boneMask ); + } + else + { + int iAnimIndices[3]; + float weight[3]; + + Calc3WayBlendIndices( i0, i1, s0, s1, seqdesc, iAnimIndices, weight ); + + /* + char buf[256]; + sprintf( buf, "%d %6.2f %d %6.2f : %6.2f %6.2f %6.2f\n", i0, s0, i1, s1, weight[0], weight[1], weight[2] ); + OutputDebugString( buf ); + */ + + if (weight[1] < 0.001) + { + // on diagonal + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, iAnimIndices[0], cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, iAnimIndices[2], cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, weight[2] / (weight[0] + weight[2]), boneMask ); + } + else + { + CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, iAnimIndices[0], cycle, boneMask ); + CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, iAnimIndices[1], cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, weight[1] / (weight[0] + weight[1]), boneMask ); + + CalcAnimation( pStudioHdr, pos3, q3, seqdesc, sequence, iAnimIndices[2], cycle, boneMask ); + BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q3, pos3, weight[2], boneMask ); + } + } + } + + g_VectorPool.Free( pos2 ); + g_QaternionPool.Free( q2 ); + g_VectorPool.Free( pos3 ); + g_QaternionPool.Free( q3 ); + + return bResult; +} + + + + +//----------------------------------------------------------------------------- +// Purpose: calculate a pose for a single sequence +// adds autolayers, runs local ik rukes +//----------------------------------------------------------------------------- +void CBoneSetup::AddSequenceLayers( + Vector pos[], + Quaternion q[], + mstudioseqdesc_t &seqdesc, + int sequence, + float cycle, + float flWeight, + float flTime, + CIKContext *pIKContext + ) +{ + for (int i = 0; i < seqdesc.numautolayers; i++) + { + mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i ); + + if (pLayer->flags & STUDIO_AL_LOCAL) + continue; + + float layerCycle = cycle; + float layerWeight = flWeight; + + if (pLayer->start != pLayer->end) + { + float s = 1.0; + float index; + + if (!(pLayer->flags & STUDIO_AL_POSE)) + { + index = cycle; + } + else + { + int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence ); + int iPose = m_pStudioHdr->GetSharedPoseParameter( iSequence, pLayer->iPose ); + if (iPose != -1) + { + const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)m_pStudioHdr)->pPoseParameter( iPose ); + index = m_flPoseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start; + } + else + { + index = 0; + } + } + + if (index < pLayer->start) + continue; + if (index >= pLayer->end) + continue; + + if (index < pLayer->peak && pLayer->start != pLayer->peak) + { + s = (index - pLayer->start) / (pLayer->peak - pLayer->start); + } + else if (index > pLayer->tail && pLayer->end != pLayer->tail) + { + s = (pLayer->end - index) / (pLayer->end - pLayer->tail); + } + + if (pLayer->flags & STUDIO_AL_SPLINE) + { + s = SimpleSpline( s ); + } + + if ((pLayer->flags & STUDIO_AL_XFADE) && (index > pLayer->tail)) + { + layerWeight = ( s * flWeight ) / ( 1 - flWeight + s * flWeight ); + } + else if (pLayer->flags & STUDIO_AL_NOBLEND) + { + layerWeight = s; + } + else + { + layerWeight = flWeight * s; + } + + if (!(pLayer->flags & STUDIO_AL_POSE)) + { + layerCycle = (cycle - pLayer->start) / (pLayer->end - pLayer->start); + } + } + + int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence ); + AccumulatePose( pos, q, iSequence, layerCycle, layerWeight, flTime, pIKContext ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate a pose for a single sequence +// adds autolayers, runs local ik rukes +//----------------------------------------------------------------------------- +void CBoneSetup::AddLocalLayers( + Vector pos[], + Quaternion q[], + mstudioseqdesc_t &seqdesc, + int sequence, + float cycle, + float flWeight, + float flTime, + CIKContext *pIKContext + ) +{ + if (!(seqdesc.flags & STUDIO_LOCAL)) + { + return; + } + + for (int i = 0; i < seqdesc.numautolayers; i++) + { + mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i ); + + if (!(pLayer->flags & STUDIO_AL_LOCAL)) + continue; + + float layerCycle = cycle; + float layerWeight = flWeight; + + if (pLayer->start != pLayer->end) + { + float s = 1.0; + + if (cycle < pLayer->start) + continue; + if (cycle >= pLayer->end) + continue; + + if (cycle < pLayer->peak && pLayer->start != pLayer->peak) + { + s = (cycle - pLayer->start) / (pLayer->peak - pLayer->start); + } + else if (cycle > pLayer->tail && pLayer->end != pLayer->tail) + { + s = (pLayer->end - cycle) / (pLayer->end - pLayer->tail); + } + + if (pLayer->flags & STUDIO_AL_SPLINE) + { + s = SimpleSpline( s ); + } + + if ((pLayer->flags & STUDIO_AL_XFADE) && (cycle > pLayer->tail)) + { + layerWeight = ( s * flWeight ) / ( 1 - flWeight + s * flWeight ); + } + else if (pLayer->flags & STUDIO_AL_NOBLEND) + { + layerWeight = s; + } + else + { + layerWeight = flWeight * s; + } + + layerCycle = (cycle - pLayer->start) / (pLayer->end - pLayer->start); + } + + int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence ); + AccumulatePose( pos, q, iSequence, layerCycle, layerWeight, flTime, pIKContext ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: my sleezy attempt at an interface only class +//----------------------------------------------------------------------------- + +IBoneSetup::IBoneSetup( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], IPoseDebugger *pPoseDebugger ) +{ + m_pBoneSetup = new CBoneSetup( pStudioHdr, boneMask, poseParameter, pPoseDebugger ); +} + +IBoneSetup::~IBoneSetup( void ) +{ + if ( m_pBoneSetup ) + { + delete m_pBoneSetup; + } +} + +void IBoneSetup::InitPose( Vector pos[], Quaternion q[] ) +{ + ::InitPose( m_pBoneSetup->m_pStudioHdr, pos, q, m_pBoneSetup->m_boneMask ); +} + +void IBoneSetup::AccumulatePose( Vector pos[], Quaternion q[], int sequence, float cycle, float flWeight, float flTime, CIKContext *pIKContext ) +{ + m_pBoneSetup->AccumulatePose( pos, q, sequence, cycle, flWeight, flTime, pIKContext ); +} + +void IBoneSetup::CalcAutoplaySequences( Vector pos[], Quaternion q[], float flRealTime, CIKContext *pIKContext ) +{ + m_pBoneSetup->CalcAutoplaySequences( pos, q, flRealTime, pIKContext ); +} + +void CalcBoneAdj( const CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], const float controllers[], int boneMask ); + +// takes a "controllers[]" array normalized to 0..1 and adds in the adjustments to pos[], and q[]. +void IBoneSetup::CalcBoneAdj( Vector pos[], Quaternion q[], const float controllers[] ) +{ + ::CalcBoneAdj( m_pBoneSetup->m_pStudioHdr, pos, q, controllers, m_pBoneSetup->m_boneMask ); +} + +CStudioHdr *IBoneSetup::GetStudioHdr() +{ + return (CStudioHdr *)m_pBoneSetup->m_pStudioHdr; +} + +CBoneSetup::CBoneSetup( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], IPoseDebugger *pPoseDebugger ) +{ + m_pStudioHdr = pStudioHdr; + m_boneMask = boneMask; + m_flPoseParameter = poseParameter; + m_pPoseDebugger = pPoseDebugger; +} + +#if 0 +//----------------------------------------------------------------------------- +// Purpose: calculate a pose for a single sequence +// adds autolayers, runs local ik rukes +//----------------------------------------------------------------------------- +void CalcPose( + const CStudioHdr *pStudioHdr, + CIKContext *pIKContext, + Vector pos[], + Quaternion q[], + int sequence, + float cycle, + const float poseParameter[], + int boneMask, + float flWeight, + float flTime + ) +{ + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( sequence ); + + Assert( flWeight >= 0.0f && flWeight <= 1.0f ); + // This shouldn't be necessary, but the Assert should help us catch whoever is screwing this up + flWeight = clamp( flWeight, 0.0f, 1.0f ); + + // add any IK locks to prevent numautolayers from moving extremities + CIKContext seq_ik; + if (seqdesc.numiklocks) + { + seq_ik.Init( pStudioHdr, vec3_angle, vec3_origin, 0.0, 0, boneMask ); // local space relative so absolute position doesn't mater + seq_ik.AddSequenceLocks( seqdesc, pos, q ); + } + + CalcPoseSingle( pStudioHdr, pos, q, seqdesc, sequence, cycle, poseParameter, boneMask, flTime ); + + if ( pIKContext ) + { + pIKContext->AddDependencies( seqdesc, sequence, cycle, poseParameter, flWeight ); + } + + AddSequenceLayers( pStudioHdr, pIKContext, pos, q, seqdesc, sequence, cycle, poseParameter, boneMask, flWeight, flTime ); + + if (seqdesc.numiklocks) + { + seq_ik.SolveSequenceLocks( seqdesc, pos, q ); + } +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: accumulate a pose for a single sequence on top of existing animation +// adds autolayers, runs local ik rukes +//----------------------------------------------------------------------------- +void CBoneSetup::AccumulatePose( + Vector pos[], + Quaternion q[], + int sequence, + float cycle, + float flWeight, + float flTime, + CIKContext *pIKContext + ) +{ + Vector pos2[MAXSTUDIOBONES]; + QuaternionAligned q2[MAXSTUDIOBONES]; + + Assert( flWeight >= 0.0f && flWeight <= 1.0f ); + // This shouldn't be necessary, but the Assert should help us catch whoever is screwing this up + flWeight = clamp( flWeight, 0.0f, 1.0f ); + + if ( sequence < 0 ) + return; + +#ifdef CLIENT_DLL + // Trigger pose debugger + if (m_pPoseDebugger) + { + m_pPoseDebugger->AccumulatePose( m_pStudioHdr, pIKContext, pos, q, sequence, cycle, m_flPoseParameter, m_boneMask, flWeight, flTime ); + } +#endif + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)m_pStudioHdr)->pSeqdesc( sequence ); + + // add any IK locks to prevent extremities from moving + CIKContext seq_ik; + if (seqdesc.numiklocks) + { + seq_ik.Init( m_pStudioHdr, vec3_angle, vec3_origin, 0.0, 0, m_boneMask ); // local space relative so absolute position doesn't mater + seq_ik.AddSequenceLocks( seqdesc, pos, q ); + } + + if (seqdesc.flags & STUDIO_LOCAL) + { + ::InitPose( m_pStudioHdr, pos2, q2, m_boneMask ); + } + + if (CalcPoseSingle( m_pStudioHdr, pos2, q2, seqdesc, sequence, cycle, m_flPoseParameter, m_boneMask, flTime )) + { + // this weight is wrong, the IK rules won't composite at the correct intensity + AddLocalLayers( pos2, q2, seqdesc, sequence, cycle, 1.0, flTime, pIKContext ); + SlerpBones( m_pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, flWeight, m_boneMask ); + } + + + if ( pIKContext ) + { + pIKContext->AddDependencies( seqdesc, sequence, cycle, m_flPoseParameter, flWeight ); + } + + AddSequenceLayers( pos, q, seqdesc, sequence, cycle, flWeight, flTime, pIKContext ); + + if (seqdesc.numiklocks) + { + seq_ik.SolveSequenceLocks( seqdesc, pos, q ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: blend together q1,pos1 with q2,pos2. Return result in q1,pos1. +// 0 returns q1, pos1. 1 returns q2, pos2 +//----------------------------------------------------------------------------- +void CalcBoneAdj( + const CStudioHdr *pStudioHdr, + Vector pos[], + Quaternion q[], + const float controllers[], + int boneMask + ) +{ + int i, j, k; + float value; + mstudiobonecontroller_t *pbonecontroller; + Vector p0; + RadianEuler a0; + Quaternion q0; + + for (j = 0; j < pStudioHdr->numbonecontrollers(); j++) + { + pbonecontroller = pStudioHdr->pBonecontroller( j ); + k = pbonecontroller->bone; + + if (pStudioHdr->boneFlags( k ) & boneMask) + { + i = pbonecontroller->inputfield; + value = controllers[i]; + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller->start + value * pbonecontroller->end; + + switch(pbonecontroller->type & STUDIO_TYPES) + { + case STUDIO_XR: + a0.Init( value * (M_PI / 180.0), 0, 0 ); + AngleQuaternion( a0, q0 ); + QuaternionSM( 1.0, q0, q[k], q[k] ); + break; + case STUDIO_YR: + a0.Init( 0, value * (M_PI / 180.0), 0 ); + AngleQuaternion( a0, q0 ); + QuaternionSM( 1.0, q0, q[k], q[k] ); + break; + case STUDIO_ZR: + a0.Init( 0, 0, value * (M_PI / 180.0) ); + AngleQuaternion( a0, q0 ); + QuaternionSM( 1.0, q0, q[k], q[k] ); + break; + case STUDIO_X: + pos[k].x += value; + break; + case STUDIO_Y: + pos[k].y += value; + break; + case STUDIO_Z: + pos[k].z += value; + break; + } + } + } +} + + +void CalcBoneDerivatives( Vector &velocity, AngularImpulse &angVel, const matrix3x4_t &prev, const matrix3x4_t ¤t, float dt ) +{ + float scale = 1.0; + if ( dt > 0 ) + { + scale = 1.0 / dt; + } + + Vector endPosition, startPosition, deltaAxis; + QAngle endAngles, startAngles; + float deltaAngle; + + MatrixAngles( prev, startAngles, startPosition ); + MatrixAngles( current, endAngles, endPosition ); + + velocity.x = (endPosition.x - startPosition.x) * scale; + velocity.y = (endPosition.y - startPosition.y) * scale; + velocity.z = (endPosition.z - startPosition.z) * scale; + RotationDeltaAxisAngle( startAngles, endAngles, deltaAxis, deltaAngle ); + VectorScale( deltaAxis, (deltaAngle * scale), angVel ); +} + +void CalcBoneVelocityFromDerivative( const QAngle &vecAngles, Vector &velocity, AngularImpulse &angVel, const matrix3x4_t ¤t ) +{ + Vector vecLocalVelocity; + AngularImpulse LocalAngVel; + Quaternion q; + float angle; + MatrixAngles( current, q, vecLocalVelocity ); + QuaternionAxisAngle( q, LocalAngVel, angle ); + LocalAngVel *= angle; + + matrix3x4_t matAngles; + AngleMatrix( vecAngles, matAngles ); + VectorTransform( vecLocalVelocity, matAngles, velocity ); + VectorTransform( LocalAngVel, matAngles, angVel ); +} + + + + +class CIKSolver +{ +public: +//-------- SOLVE TWO LINK INVERSE KINEMATICS ------------- +// Author: Ken Perlin +// +// Given a two link joint from [0,0,0] to end effector position P, +// let link lengths be a and b, and let norm |P| = c. Clearly a+b <= c. +// +// Problem: find a "knee" position Q such that |Q| = a and |P-Q| = b. +// +// In the case of a point on the x axis R = [c,0,0], there is a +// closed form solution S = [d,e,0], where |S| = a and |R-S| = b: +// +// d2+e2 = a2 -- because |S| = a +// (c-d)2+e2 = b2 -- because |R-S| = b +// +// c2-2cd+d2+e2 = b2 -- combine the two equations +// c2-2cd = b2 - a2 +// c-2d = (b2-a2)/c +// d - c/2 = (a2-b2)/c / 2 +// +// d = (c + (a2-b2/c) / 2 -- to solve for d and e. +// e = sqrt(a2-d2) + + static float findD(float a, float b, float c) { + return (c + (a*a-b*b)/c) / 2; + } + static float findE(float a, float d) { return sqrt(a*a-d*d); } + +// This leads to a solution to the more general problem: +// +// (1) R = Mfwd(P) -- rotate P onto the x axis +// (2) Solve for S +// (3) Q = Minv(S) -- rotate back again + + float Mfwd[3][3]; + float Minv[3][3]; + + bool solve(float A, float B, float const P[], float const D[], float Q[]) { + float R[3]; + defineM(P,D); + rot(Minv,P,R); + float r = length(R); + float d = findD(A,B,r); + float e = findE(A,d); + float S[3] = {d,e,0}; + rot(Mfwd,S,Q); + return d > (r - B) && d < A; + } + +// If "knee" position Q needs to be as close as possible to some point D, +// then choose M such that M(D) is in the y>0 half of the z=0 plane. +// +// Given that constraint, define the forward and inverse of M as follows: + + void defineM(float const P[], float const D[]) { + float *X = Minv[0], *Y = Minv[1], *Z = Minv[2]; + +// Minv defines a coordinate system whose x axis contains P, so X = unit(P). + int i; + for (i = 0 ; i < 3 ; i++) + X[i] = P[i]; + normalize(X); + +// Its y axis is perpendicular to P, so Y = unit( E - X(EX) ). + + float dDOTx = dot(D,X); + for (i = 0 ; i < 3 ; i++) + Y[i] = D[i] - dDOTx * X[i]; + normalize(Y); + +// Its z axis is perpendicular to both X and Y, so Z = XY. + + cross(X,Y,Z); + +// Mfwd = (Minv)T, since transposing inverts a rotation matrix. + + for (i = 0 ; i < 3 ; i++) { + Mfwd[i][0] = Minv[0][i]; + Mfwd[i][1] = Minv[1][i]; + Mfwd[i][2] = Minv[2][i]; + } + } + +//------------ GENERAL VECTOR MATH SUPPORT ----------- + + static float dot(float const a[], float const b[]) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } + + static float length(float const v[]) { return sqrt( dot(v,v) ); } + + static void normalize(float v[]) { + float norm = length(v); + for (int i = 0 ; i < 3 ; i++) + v[i] /= norm; + } + + static void cross(float const a[], float const b[], float c[]) { + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; + } + + static void rot(float const M[3][3], float const src[], float dst[]) { + for (int i = 0 ; i < 3 ; i++) + dst[i] = dot(M[i],src); + } +}; + + + +//----------------------------------------------------------------------------- +// Purpose: visual debugging code +//----------------------------------------------------------------------------- +#if 1 +inline void debugLine(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration) { }; +#else +extern void drawLine( const Vector &p1, const Vector &p2, int r = 0, int g = 0, int b = 1, bool noDepthTest = true, float duration = 0.1 ); +void debugLine(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration) +{ + drawLine( origin, dest, r, g, b, noDepthTest, duration ); +} +#endif + + +//----------------------------------------------------------------------------- +// Purpose: for a 2 bone chain, find the IK solution and reset the matrices +//----------------------------------------------------------------------------- +bool Studio_SolveIK( mstudioikchain_t *pikchain, Vector &targetFoot, matrix3x4_t *pBoneToWorld ) +{ + if (pikchain->pLink(0)->kneeDir.LengthSqr() > 0.0) + { + Vector targetKneeDir, targetKneePos; + // FIXME: knee length should be as long as the legs + Vector tmp = pikchain->pLink( 0 )->kneeDir; + VectorRotate( tmp, pBoneToWorld[ pikchain->pLink( 0 )->bone ], targetKneeDir ); + MatrixPosition( pBoneToWorld[ pikchain->pLink( 1 )->bone ], targetKneePos ); + return Studio_SolveIK( pikchain->pLink( 0 )->bone, pikchain->pLink( 1 )->bone, pikchain->pLink( 2 )->bone, targetFoot, targetKneePos, targetKneeDir, pBoneToWorld ); + } + else + { + return Studio_SolveIK( pikchain->pLink( 0 )->bone, pikchain->pLink( 1 )->bone, pikchain->pLink( 2 )->bone, targetFoot, pBoneToWorld ); + } +} + + +#define KNEEMAX_EPSILON 0.9998 // (0.9998 is about 1 degree) + +//----------------------------------------------------------------------------- +// Purpose: Solve Knee position for a known hip and foot location, but no specific knee direction preference +//----------------------------------------------------------------------------- + +bool Studio_SolveIK( int iThigh, int iKnee, int iFoot, Vector &targetFoot, matrix3x4_t *pBoneToWorld ) +{ + Vector worldFoot, worldKnee, worldThigh; + + MatrixPosition( pBoneToWorld[ iThigh ], worldThigh ); + MatrixPosition( pBoneToWorld[ iKnee ], worldKnee ); + MatrixPosition( pBoneToWorld[ iFoot ], worldFoot ); + + //debugLine( worldThigh, worldKnee, 0, 0, 255, true, 0 ); + //debugLine( worldKnee, worldFoot, 0, 0, 255, true, 0 ); + + Vector ikFoot, ikKnee; + + ikFoot = targetFoot - worldThigh; + ikKnee = worldKnee - worldThigh; + + float l1 = (worldKnee-worldThigh).Length(); + float l2 = (worldFoot-worldKnee).Length(); + float l3 = (worldFoot-worldThigh).Length(); + + // leg too straight to figure out knee? + if (l3 > (l1 + l2) * KNEEMAX_EPSILON) + { + return false; + } + + Vector ikHalf = (worldFoot-worldThigh) * (l1 / l3); + + // FIXME: what to do when the knee completely straight? + Vector ikKneeDir = ikKnee - ikHalf; + VectorNormalize( ikKneeDir ); + + return Studio_SolveIK( iThigh, iKnee, iFoot, targetFoot, worldKnee, ikKneeDir, pBoneToWorld ); +} + +//----------------------------------------------------------------------------- +// Purpose: Realign the matrix so that its X axis points along the desired axis. +//----------------------------------------------------------------------------- +void Studio_AlignIKMatrix( matrix3x4_t &mMat, const Vector &vAlignTo ) +{ + Vector tmp1, tmp2, tmp3; + + // Column 0 (X) becomes the vector. + tmp1 = vAlignTo; + VectorNormalize( tmp1 ); + MatrixSetColumn( tmp1, 0, mMat ); + + // Column 1 (Y) is the cross of the vector and column 2 (Z). + MatrixGetColumn( mMat, 2, tmp3 ); + tmp2 = tmp3.Cross( tmp1 ); + VectorNormalize( tmp2 ); + // FIXME: check for X being too near to Z + MatrixSetColumn( tmp2, 1, mMat ); + + // Column 2 (Z) is the cross of columns 0 (X) and 1 (Y). + tmp3 = tmp1.Cross( tmp2 ); + MatrixSetColumn( tmp3, 2, mMat ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Solve Knee position for a known hip and foot location, and a known knee direction +//----------------------------------------------------------------------------- + +bool Studio_SolveIK( int iThigh, int iKnee, int iFoot, Vector &targetFoot, Vector &targetKneePos, Vector &targetKneeDir, matrix3x4_t *pBoneToWorld ) +{ + Vector worldFoot, worldKnee, worldThigh; + + MatrixPosition( pBoneToWorld[ iThigh ], worldThigh ); + MatrixPosition( pBoneToWorld[ iKnee ], worldKnee ); + MatrixPosition( pBoneToWorld[ iFoot ], worldFoot ); + + //debugLine( worldThigh, worldKnee, 0, 0, 255, true, 0 ); + //debugLine( worldThigh, worldThigh + targetKneeDir, 0, 0, 255, true, 0 ); + // debugLine( worldKnee, targetKnee, 0, 0, 255, true, 0 ); + + Vector ikFoot, ikTargetKnee, ikKnee; + + ikFoot = targetFoot - worldThigh; + ikKnee = targetKneePos - worldThigh; + + float l1 = (worldKnee-worldThigh).Length(); + float l2 = (worldFoot-worldKnee).Length(); + + // exaggerate knee targets for legs that are nearly straight + // FIXME: should be configurable, and the ikKnee should be from the original animation, not modifed + float d = (targetFoot-worldThigh).Length() - vmin( l1, l2 ); + d = vmax( l1 + l2, d ); + // FIXME: too short knee directions cause trouble + d = d * 100; + + ikTargetKnee = ikKnee + targetKneeDir * d; + + // debugLine( worldKnee, worldThigh + ikTargetKnee, 0, 0, 255, true, 0 ); + + int color[3] = { 0, 255, 0 }; + + // too far away? (0.9998 is about 1 degree) + if (ikFoot.Length() > (l1 + l2) * KNEEMAX_EPSILON) + { + VectorNormalize( ikFoot ); + VectorScale( ikFoot, (l1 + l2) * KNEEMAX_EPSILON, ikFoot ); + color[0] = 255; color[1] = 0; color[2] = 0; + } + + // too close? + // limit distance to about an 80 degree knee bend + float minDist = vmax( fabs(l1 - l2) * 1.15, vmin( l1, l2 ) * 0.15 ); + if (ikFoot.Length() < minDist) + { + // too close to get an accurate vector, just use original vector + ikFoot = (worldFoot - worldThigh); + VectorNormalize( ikFoot ); + VectorScale( ikFoot, minDist, ikFoot ); + } + + CIKSolver ik; + if (ik.solve( l1, l2, ikFoot.Base(), ikTargetKnee.Base(), ikKnee.Base() )) + { + matrix3x4_t& mWorldThigh = pBoneToWorld[ iThigh ]; + matrix3x4_t& mWorldKnee = pBoneToWorld[ iKnee ]; + matrix3x4_t& mWorldFoot = pBoneToWorld[ iFoot ]; + + //debugLine( worldThigh, ikKnee + worldThigh, 255, 0, 0, true, 0 ); + //debugLine( ikKnee + worldThigh, ikFoot + worldThigh, 255, 0, 0, true,0 ); + + // debugLine( worldThigh, ikKnee + worldThigh, color[0], color[1], color[2], true, 0 ); + // debugLine( ikKnee + worldThigh, ikFoot + worldThigh, color[0], color[1], color[2], true,0 ); + + + // build transformation matrix for thigh + Studio_AlignIKMatrix( mWorldThigh, ikKnee ); + Studio_AlignIKMatrix( mWorldKnee, ikFoot - ikKnee ); + + + mWorldKnee[0][3] = ikKnee.x + worldThigh.x; + mWorldKnee[1][3] = ikKnee.y + worldThigh.y; + mWorldKnee[2][3] = ikKnee.z + worldThigh.z; + + mWorldFoot[0][3] = ikFoot.x + worldThigh.x; + mWorldFoot[1][3] = ikFoot.y + worldThigh.y; + mWorldFoot[2][3] = ikFoot.z + worldThigh.z; + + return true; + } + else + { + /* + debugLine( worldThigh, worldThigh + ikKnee, 255, 0, 0, true, 0 ); + debugLine( worldThigh + ikKnee, worldThigh + ikFoot, 255, 0, 0, true, 0 ); + debugLine( worldThigh + ikFoot, worldThigh, 255, 0, 0, true, 0 ); + debugLine( worldThigh + ikKnee, worldThigh + ikTargetKnee, 255, 0, 0, true, 0 ); + */ + return false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +float Studio_IKRuleWeight( mstudioikrule_t &ikRule, const mstudioanimdesc_t *panim, float flCycle, int &iFrame, float &fraq ) +{ + if (ikRule.end > 1.0f && flCycle < ikRule.start) + { + flCycle = flCycle + 1.0f; + } + + float value = 0.0f; + fraq = (panim->numframes - 1) * (flCycle - ikRule.start) + ikRule.iStart; + iFrame = (int)fraq; + fraq = fraq - iFrame; + + if (flCycle < ikRule.start) + { + iFrame = ikRule.iStart; + fraq = 0.0f; + return 0.0f; + } + else if (flCycle < ikRule.peak ) + { + value = (flCycle - ikRule.start) / (ikRule.peak - ikRule.start); + } + else if (flCycle < ikRule.tail ) + { + return 1.0f; + } + else if (flCycle < ikRule.end ) + { + value = 1.0f - ((flCycle - ikRule.tail) / (ikRule.end - ikRule.tail)); + } + else + { + fraq = (panim->numframes - 1) * (ikRule.end - ikRule.start) + ikRule.iStart; + iFrame = (int)fraq; + fraq = fraq - iFrame; + } + return SimpleSpline( value ); +} + + +float Studio_IKRuleWeight( ikcontextikrule_t &ikRule, float flCycle ) +{ + if (ikRule.end > 1.0f && flCycle < ikRule.start) + { + flCycle = flCycle + 1.0f; + } + + float value = 0.0f; + if (flCycle < ikRule.start) + { + return 0.0f; + } + else if (flCycle < ikRule.peak ) + { + value = (flCycle - ikRule.start) / (ikRule.peak - ikRule.start); + } + else if (flCycle < ikRule.tail ) + { + return 1.0f; + } + else if (flCycle < ikRule.end ) + { + value = 1.0f - ((flCycle - ikRule.tail) / (ikRule.end - ikRule.tail)); + } + return 3.0f * value * value - 2.0f * value * value * value; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +bool Studio_IKShouldLatch( ikcontextikrule_t &ikRule, float flCycle ) +{ + if (ikRule.end > 1.0f && flCycle < ikRule.start) + { + flCycle = flCycle + 1.0f; + } + + if (flCycle < ikRule.peak ) + { + return false; + } + else if (flCycle < ikRule.end ) + { + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +float Studio_IKTail( ikcontextikrule_t &ikRule, float flCycle ) +{ + if (ikRule.end > 1.0f && flCycle < ikRule.start) + { + flCycle = flCycle + 1.0f; + } + + if (flCycle <= ikRule.tail ) + { + return 0.0f; + } + else if (flCycle < ikRule.end ) + { + return ((flCycle - ikRule.tail) / (ikRule.end - ikRule.tail)); + } + return 0.0; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +bool Studio_IKAnimationError( const CStudioHdr *pStudioHdr, mstudioikrule_t *pRule, const mstudioanimdesc_t *panim, float flCycle, Vector &pos, Quaternion &q, float &flWeight ) +{ + float fraq; + int iFrame; + + flWeight = Studio_IKRuleWeight( *pRule, panim, flCycle, iFrame, fraq ); + Assert( fraq >= 0.0 && fraq < 1.0 ); + Assert( flWeight >= 0.0f && flWeight <= 1.0f ); + + // This shouldn't be necessary, but the Assert should help us catch whoever is screwing this up + flWeight = clamp( flWeight, 0.0f, 1.0f ); + + if (pRule->type != IK_GROUND && flWeight < 0.0001) + return false; + + mstudioikerror_t *pError = pRule->pError( iFrame ); + if (pError != NULL) + { + if (fraq < 0.001) + { + q = pError[0].q; + pos = pError[0].pos; + } + else + { + QuaternionBlend( pError[0].q, pError[1].q, fraq, q ); + pos = pError[0].pos * (1.0f - fraq) + pError[1].pos * fraq; + } + return true; + } + + mstudiocompressedikerror_t *pCompressed = pRule->pCompressedError(); + if (pCompressed != NULL) + { + CalcDecompressedAnimation( pCompressed, iFrame - pRule->iStart, fraq, pos, q ); + return true; + } + // no data, disable IK rule + Assert( 0 ); + flWeight = 0.0f; + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: For a specific sequence:rule, find where it starts, stops, and what +// the estimated offset from the connection point is. +// return true if the rule is within bounds. +//----------------------------------------------------------------------------- + +bool Studio_IKSequenceError( const CStudioHdr *pStudioHdr, mstudioseqdesc_t &seqdesc, int iSequence, float flCycle, int iRule, const float poseParameter[], mstudioanimdesc_t *panim[4], float weight[4], ikcontextikrule_t &ikRule ) +{ + int i; + + memset( &ikRule, 0, sizeof(ikRule) ); + ikRule.start = ikRule.peak = ikRule.tail = ikRule.end = 0; + + + mstudioikrule_t *prevRule = NULL; + + // find overall influence + for (i = 0; i < 4; i++) + { + if (weight[i]) + { + if (iRule >= panim[i]->numikrules || panim[i]->numikrules != panim[0]->numikrules) + { + Assert( 0 ); + return false; + } + + mstudioikrule_t *pRule = panim[i]->pIKRule( iRule ); + if (pRule == NULL) + return false; + + float dt = 0.0; + if (prevRule != NULL) + { + if (pRule->start - prevRule->start > 0.5) + { + dt = -1.0; + } + else if (pRule->start - prevRule->start < -0.5) + { + dt = 1.0; + } + } + else + { + prevRule = pRule; + } + + ikRule.start += (pRule->start + dt) * weight[i]; + ikRule.peak += (pRule->peak + dt) * weight[i]; + ikRule.tail += (pRule->tail + dt) * weight[i]; + ikRule.end += (pRule->end + dt) * weight[i]; + } + } + if (ikRule.start > 1.0) + { + ikRule.start -= 1.0; + ikRule.peak -= 1.0; + ikRule.tail -= 1.0; + ikRule.end -= 1.0; + } + else if (ikRule.start < 0.0) + { + ikRule.start += 1.0; + ikRule.peak += 1.0; + ikRule.tail += 1.0; + ikRule.end += 1.0; + } + + ikRule.flWeight = Studio_IKRuleWeight( ikRule, flCycle ); + if (ikRule.flWeight <= 0.001f) + { + // go ahead and allow IK_GROUND rules a virtual looping section + if ( panim[0]->pIKRule( iRule ) == NULL ) + return false; + if ((panim[0]->flags & STUDIO_LOOPING) && panim[0]->pIKRule( iRule )->type == IK_GROUND && ikRule.end - ikRule.start > 0.75 ) + { + ikRule.flWeight = 0.001; + flCycle = ikRule.end - 0.001; + } + else + { + return false; + } + } + + Assert( ikRule.flWeight > 0.0f ); + + ikRule.pos.Init(); + ikRule.q.Init(); + + // find target error + float total = 0.0f; + for (i = 0; i < 4; i++) + { + if (weight[i]) + { + Vector pos1; + Quaternion q1; + float w; + + mstudioikrule_t *pRule = panim[i]->pIKRule( iRule ); + if (pRule == NULL) + return false; + + ikRule.chain = pRule->chain; // FIXME: this is anim local + ikRule.bone = pRule->bone; // FIXME: this is anim local + ikRule.type = pRule->type; + ikRule.slot = pRule->slot; + + ikRule.height += pRule->height * weight[i]; + ikRule.floor += pRule->floor * weight[i]; + ikRule.radius += pRule->radius * weight[i]; + ikRule.drop += pRule->drop * weight[i]; + ikRule.top += pRule->top * weight[i]; + + // keep track of tail condition + ikRule.release += Studio_IKTail( ikRule, flCycle ) * weight[i]; + + // only check rules with error values + switch( ikRule.type ) + { + case IK_SELF: + case IK_WORLD: + case IK_GROUND: + case IK_ATTACHMENT: + { + int bResult = Studio_IKAnimationError( pStudioHdr, pRule, panim[i], flCycle, pos1, q1, w ); + + if (bResult) + { + ikRule.pos = ikRule.pos + pos1 * weight[i]; + QuaternionAccumulate( ikRule.q, weight[i], q1, ikRule.q ); + total += weight[i]; + } + } + break; + default: + total += weight[i]; + break; + } + + ikRule.latched = Studio_IKShouldLatch( ikRule, flCycle ) * ikRule.flWeight; + + if (ikRule.type == IK_ATTACHMENT) + { + ikRule.szLabel = pRule->pszAttachment(); + } + } + } + + if (total <= 0.0001f) + { + return false; + } + + if (total < 0.999f) + { + VectorScale( ikRule.pos, 1.0f / total, ikRule.pos ); + QuaternionScale( ikRule.q, 1.0f / total, ikRule.q ); + } + + if (ikRule.type == IK_SELF && ikRule.bone != -1) + { + // FIXME: this is anim local, not seq local! + ikRule.bone = pStudioHdr->RemapSeqBone( iSequence, ikRule.bone ); + if (ikRule.bone == -1) + return false; + } + + QuaternionNormalize( ikRule.q ); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +CIKContext::CIKContext() +{ + m_target.EnsureCapacity( 12 ); // FIXME: this sucks, shouldn't it be grown? + m_iFramecounter = -1; + m_pStudioHdr = NULL; + m_flTime = -1.0f; + m_target.SetSize( 0 ); +} + + +void CIKContext::Init( const CStudioHdr *pStudioHdr, const QAngle &angles, const Vector &pos, float flTime, int iFramecounter, int boneMask ) +{ + m_pStudioHdr = pStudioHdr; + m_ikChainRule.RemoveAll(); // m_numikrules = 0; + if (pStudioHdr->numikchains()) + { + m_ikChainRule.SetSize( pStudioHdr->numikchains() ); + + // FIXME: Brutal hackery to prevent a crash + if (m_target.Count() == 0) + { + m_target.SetSize(12); + memset( m_target.Base(), 0, sizeof(m_target[0])*m_target.Count() ); + ClearTargets(); + } + + } + else + { + m_target.SetSize( 0 ); + } + AngleMatrix( angles, pos, m_rootxform ); + m_iFramecounter = iFramecounter; + m_flTime = flTime; + m_boneMask = boneMask; +} + +void CIKContext::AddDependencies( mstudioseqdesc_t &seqdesc, int iSequence, float flCycle, const float poseParameters[], float flWeight ) +{ + int i; + + if ( m_pStudioHdr->numikchains() == 0) + return; + + if (seqdesc.numikrules == 0) + return; + + ikcontextikrule_t ikrule; + + Assert( flWeight >= 0.0f && flWeight <= 1.0f ); + // This shouldn't be necessary, but the Assert should help us catch whoever is screwing this up + flWeight = clamp( flWeight, 0.0f, 1.0f ); + + // unify this + if (seqdesc.flags & STUDIO_REALTIME) + { + float cps = Studio_CPS( m_pStudioHdr, seqdesc, iSequence, poseParameters ); + flCycle = m_flTime * cps; + flCycle = flCycle - (int)flCycle; + } + else if (flCycle < 0 || flCycle >= 1) + { + if (seqdesc.flags & STUDIO_LOOPING) + { + flCycle = flCycle - (int)flCycle; + if (flCycle < 0) flCycle += 1; + } + else + { + flCycle = vmax( 0.0, vmin( flCycle, 0.9999 ) ); + } + } + + mstudioanimdesc_t *panim[4]; + float weight[4]; + + Studio_SeqAnims( m_pStudioHdr, seqdesc, iSequence, poseParameters, panim, weight ); + + // FIXME: add proper number of rules!!! + for (i = 0; i < seqdesc.numikrules; i++) + { + if ( !Studio_IKSequenceError( m_pStudioHdr, seqdesc, iSequence, flCycle, i, poseParameters, panim, weight, ikrule ) ) + continue; + + // don't add rule if the bone isn't going to be calculated + int bone = m_pStudioHdr->pIKChain( ikrule.chain )->pLink( 2 )->bone; + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + continue; + + // or if its relative bone isn't going to be calculated + if ( ikrule.bone >= 0 && !(m_pStudioHdr->boneFlags( ikrule.bone ) & m_boneMask)) + continue; + + // FIXME: Brutal hackery to prevent a crash + if (m_target.Count() == 0) + { + m_target.SetSize(12); + memset( m_target.Base(), 0, sizeof(m_target[0])*m_target.Count() ); + ClearTargets(); + } + + ikrule.flRuleWeight = flWeight; + + if (ikrule.flRuleWeight * ikrule.flWeight > 0.999) + { + if ( ikrule.type != IK_UNLATCH) + { + // clear out chain if rule is 100% + m_ikChainRule.Element( ikrule.chain ).RemoveAll( ); + if ( ikrule.type == IK_RELEASE) + { + continue; + } + } + } + + int nIndex = m_ikChainRule.Element( ikrule.chain ).AddToTail( ); + m_ikChainRule.Element( ikrule.chain ).Element( nIndex ) = ikrule; + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKContext::AddAutoplayLocks( Vector pos[], Quaternion q[] ) +{ + // skip all array access if no autoplay locks. + if (m_pStudioHdr->GetNumIKAutoplayLocks() == 0) + { + return; + } + + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + + int ikOffset = m_ikLock.AddMultipleToTail( m_pStudioHdr->GetNumIKAutoplayLocks() ); + memset( &m_ikLock[ikOffset], 0, sizeof(ikcontextikrule_t)*m_pStudioHdr->GetNumIKAutoplayLocks() ); + + for (int i = 0; i < m_pStudioHdr->GetNumIKAutoplayLocks(); i++) + { + const mstudioiklock_t &lock = ((CStudioHdr *)m_pStudioHdr)->pIKAutoplayLock( i ); + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( lock.chain ); + int bone = pchain->pLink( 2 )->bone; + + // don't bother with iklock if the bone isn't going to be calculated + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + continue; + + // eval current ik'd bone + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + + ikcontextikrule_t &ikrule = m_ikLock[ i + ikOffset ]; + + ikrule.chain = lock.chain; + ikrule.slot = i; + ikrule.type = IK_WORLD; + + MatrixAngles( boneToWorld[bone], ikrule.q, ikrule.pos ); + + // save off current knee direction + if (pchain->pLink(0)->kneeDir.LengthSqr() > 0.0) + { + Vector tmp = pchain->pLink( 0 )->kneeDir; + VectorRotate( pchain->pLink( 0 )->kneeDir, boneToWorld[ pchain->pLink( 0 )->bone ], ikrule.kneeDir ); + MatrixPosition( boneToWorld[ pchain->pLink( 1 )->bone ], ikrule.kneePos ); + } + else + { + ikrule.kneeDir.Init( ); + } + } + g_MatrixPool.Free( boneToWorld ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKContext::AddSequenceLocks( mstudioseqdesc_t &seqdesc, Vector pos[], Quaternion q[] ) +{ + if ( m_pStudioHdr->numikchains() == 0) + { + return; + } + + if ( seqdesc.numiklocks == 0 ) + { + return; + } + + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + + int ikOffset = m_ikLock.AddMultipleToTail( seqdesc.numiklocks ); + memset( &m_ikLock[ikOffset], 0, sizeof(ikcontextikrule_t) * seqdesc.numiklocks ); + + for (int i = 0; i < seqdesc.numiklocks; i++) + { + mstudioiklock_t *plock = seqdesc.pIKLock( i ); + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( plock->chain ); + int bone = pchain->pLink( 2 )->bone; + + // don't bother with iklock if the bone isn't going to be calculated + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + continue; + + // eval current ik'd bone + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + + ikcontextikrule_t &ikrule = m_ikLock[i+ikOffset]; + ikrule.chain = i; + ikrule.slot = i; + ikrule.type = IK_WORLD; + + MatrixAngles( boneToWorld[bone], ikrule.q, ikrule.pos ); + + // save off current knee direction + if (pchain->pLink(0)->kneeDir.LengthSqr() > 0.0) + { + VectorRotate( pchain->pLink( 0 )->kneeDir, boneToWorld[ pchain->pLink( 0 )->bone ], ikrule.kneeDir ); + } + else + { + ikrule.kneeDir.Init( ); + } + } + g_MatrixPool.Free( boneToWorld ); +} + +//----------------------------------------------------------------------------- +// Purpose: build boneToWorld transforms for a specific bone +//----------------------------------------------------------------------------- +void CIKContext::BuildBoneChain( + const Vector pos[], + const Quaternion q[], + int iBone, + matrix3x4_t *pBoneToWorld, + CBoneBitList &boneComputed ) +{ + Assert( m_pStudioHdr->boneFlags( iBone ) & m_boneMask ); + ::BuildBoneChain( m_pStudioHdr, m_rootxform, pos, q, iBone, pBoneToWorld, boneComputed ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: build boneToWorld transforms for a specific bone +//----------------------------------------------------------------------------- +void BuildBoneChain( + const CStudioHdr *pStudioHdr, + const matrix3x4_t &rootxform, + const Vector pos[], + const Quaternion q[], + int iBone, + matrix3x4_t *pBoneToWorld, + CBoneBitList &boneComputed ) +{ + if ( boneComputed.IsBoneMarked(iBone) ) + return; + + matrix3x4_t bonematrix; + QuaternionMatrix( q[iBone], pos[iBone], bonematrix ); + + int parent = pStudioHdr->boneParent( iBone ); + if (parent == -1) + { + ConcatTransforms( rootxform, bonematrix, pBoneToWorld[iBone] ); + } + else + { + // evil recursive!!! + BuildBoneChain( pStudioHdr, rootxform, pos, q, parent, pBoneToWorld, boneComputed ); + ConcatTransforms( pBoneToWorld[parent], bonematrix, pBoneToWorld[iBone]); + } + boneComputed.MarkBone(iBone); +} + + +//----------------------------------------------------------------------------- +// Purpose: turn a specific bones boneToWorld transform into a pos and q in parents bonespace +//----------------------------------------------------------------------------- +void SolveBone( + const CStudioHdr *pStudioHdr, + int iBone, + matrix3x4_t *pBoneToWorld, + Vector pos[], + Quaternion q[] + ) +{ + int iParent = pStudioHdr->boneParent( iBone ); + + matrix3x4_t worldToBone; + MatrixInvert( pBoneToWorld[iParent], worldToBone ); + + matrix3x4_t local; + ConcatTransforms( worldToBone, pBoneToWorld[iBone], local ); + + MatrixAngles( local, q[iBone], pos[iBone] ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKTarget::SetOwner( int entindex, const Vector &pos, const QAngle &angles ) +{ + latched.owner = entindex; + latched.absOrigin = pos; + latched.absAngles = angles; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKTarget::ClearOwner( void ) +{ + latched.owner = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CIKTarget::GetOwner( void ) +{ + return latched.owner; +} + +//----------------------------------------------------------------------------- +// Purpose: update the latched IK values that are in a moving frame of reference +//----------------------------------------------------------------------------- + +void CIKTarget::UpdateOwner( int entindex, const Vector &pos, const QAngle &angles ) +{ + if (pos == latched.absOrigin && angles == latched.absAngles) + return; + + matrix3x4_t in, out; + AngleMatrix( angles, pos, in ); + AngleIMatrix( latched.absAngles, latched.absOrigin, out ); + + matrix3x4_t tmp1, tmp2; + QuaternionMatrix( latched.q, latched.pos, tmp1 ); + ConcatTransforms( out, tmp1, tmp2 ); + ConcatTransforms( in, tmp2, tmp1 ); + MatrixAngles( tmp1, latched.q, latched.pos ); +} + + +//----------------------------------------------------------------------------- +// Purpose: sets the ground position of an ik target +//----------------------------------------------------------------------------- + +void CIKTarget::SetPos( const Vector &pos ) +{ + est.pos = pos; +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ground "identity" orientation of an ik target +//----------------------------------------------------------------------------- + +void CIKTarget::SetAngles( const QAngle &angles ) +{ + AngleQuaternion( angles, est.q ); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ground "identity" orientation of an ik target +//----------------------------------------------------------------------------- + +void CIKTarget::SetQuaternion( const Quaternion &q ) +{ + est.q = q; +} + +//----------------------------------------------------------------------------- +// Purpose: calculates a ground "identity" orientation based on the surface +// normal of the ground and the desired ground identity orientation +//----------------------------------------------------------------------------- + +void CIKTarget::SetNormal( const Vector &normal ) +{ + // recalculate foot angle based on slope of surface + matrix3x4_t m1; + Vector forward, right; + QuaternionMatrix( est.q, m1 ); + + MatrixGetColumn( m1, 1, right ); + forward = CrossProduct( right, normal ); + right = CrossProduct( normal, forward ); + MatrixSetColumn( forward, 0, m1 ); + MatrixSetColumn( right, 1, m1 ); + MatrixSetColumn( normal, 2, m1 ); + QAngle a1; + Vector p1; + MatrixAngles( m1, est.q, p1 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: estimates the ground impact at the center location assuming a the edge of +// an Z axis aligned disc collided with it the surface. +//----------------------------------------------------------------------------- + +void CIKTarget::SetPosWithNormalOffset( const Vector &pos, const Vector &normal ) +{ + // assume it's a disc edge intersecting with the floor, so try to estimate the z location of the center + est.pos = pos; + if (normal.z > 0.9999) + { + return; + } + // clamp at 45 degrees + else if (normal.z > 0.707) + { + // tan == sin / cos + float tan = sqrt( 1 - normal.z * normal.z ) / normal.z; + est.pos.z = est.pos.z - est.radius * tan; + } + else + { + est.pos.z = est.pos.z - est.radius; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKTarget::SetOnWorld( bool bOnWorld ) +{ + est.onWorld = bOnWorld; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +bool CIKTarget::IsActive() +{ + return (est.flWeight > 0.0f); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKTarget::IKFailed( void ) +{ + latched.deltaPos.Init(); + latched.deltaQ.Init(); + latched.pos = ideal.pos; + latched.q = ideal.q; + est.latched = 0.0; + est.flWeight = 0.0; + est.onWorld = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKTarget::MoveReferenceFrame( Vector &deltaPos, QAngle &deltaAngles ) +{ + est.pos -= deltaPos; + latched.pos -= deltaPos; + offset.pos -= deltaPos; + ideal.pos -= deltaPos; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Invalidate any IK locks. +//----------------------------------------------------------------------------- + +void CIKContext::ClearTargets( void ) +{ + int i; + for (i = 0; i < m_target.Count(); i++) + { + m_target[i].latched.iFramecounter = -9999; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Run through the rules that survived and turn a specific bones boneToWorld +// transform into a pos and q in parents bonespace +//----------------------------------------------------------------------------- + +void CIKContext::UpdateTargets( Vector pos[], Quaternion q[], matrix3x4_t boneToWorld[], CBoneBitList &boneComputed ) +{ + int i, j; + + for (i = 0; i < m_target.Count(); i++) + { + m_target[i].est.flWeight = 0.0f; + m_target[i].est.latched = 1.0f; + m_target[i].est.release = 1.0f; + m_target[i].est.height = 0.0f; + m_target[i].est.floor = 0.0f; + m_target[i].est.radius = 0.0f; + m_target[i].offset.pos.Init(); + m_target[i].offset.q.Init(); + } + + AutoIKRelease( ); + + for (j = 0; j < m_ikChainRule.Count(); j++) + { + for (i = 0; i < m_ikChainRule.Element( j ).Count(); i++) + { + ikcontextikrule_t *pRule = &m_ikChainRule.Element( j ).Element( i ); + + // ikchainresult_t *pChainRule = &chainRule[ m_ikRule[i].chain ]; + + switch( pRule->type ) + { + case IK_ATTACHMENT: + case IK_GROUND: + // case IK_SELF: + { + matrix3x4_t footTarget; + CIKTarget *pTarget = &m_target[pRule->slot]; + pTarget->chain = pRule->chain; + pTarget->type = pRule->type; + + if (pRule->type == IK_ATTACHMENT) + { + pTarget->offset.pAttachmentName = pRule->szLabel; + } + else + { + pTarget->offset.pAttachmentName = NULL; + } + + if (pRule->flRuleWeight == 1.0f || pTarget->est.flWeight == 0.0f) + { + pTarget->offset.q = pRule->q; + pTarget->offset.pos = pRule->pos; + pTarget->est.height = pRule->height; + pTarget->est.floor = pRule->floor; + pTarget->est.radius = pRule->radius; + pTarget->est.latched = pRule->latched * pRule->flRuleWeight; + pTarget->est.release = pRule->release; + pTarget->est.flWeight = pRule->flWeight * pRule->flRuleWeight; + } + else + { + QuaternionSlerp( pTarget->offset.q, pRule->q, pRule->flRuleWeight, pTarget->offset.q ); + pTarget->offset.pos = Lerp( pRule->flRuleWeight, pTarget->offset.pos, pRule->pos ); + pTarget->est.height = Lerp( pRule->flRuleWeight, pTarget->est.height, pRule->height ); + pTarget->est.floor = Lerp( pRule->flRuleWeight, pTarget->est.floor, pRule->floor ); + pTarget->est.radius = Lerp( pRule->flRuleWeight, pTarget->est.radius, pRule->radius ); + //pTarget->est.latched = Lerp( pRule->flRuleWeight, pTarget->est.latched, pRule->latched ); + pTarget->est.latched = vmin( pTarget->est.latched, pRule->latched ); + pTarget->est.release = Lerp( pRule->flRuleWeight, pTarget->est.release, pRule->release ); + pTarget->est.flWeight = Lerp( pRule->flRuleWeight, pTarget->est.flWeight, pRule->flWeight ); + } + + if ( pRule->type == IK_GROUND ) + { + pTarget->latched.deltaPos.z = 0; + pTarget->est.pos.z = pTarget->est.floor + m_rootxform[2][3]; + } + } + break; + case IK_UNLATCH: + { + CIKTarget *pTarget = &m_target[pRule->slot]; + if (pRule->latched > 0.0) + pTarget->est.latched = 0.0; + else + pTarget->est.latched = vmin( pTarget->est.latched, 1.0f - pRule->flWeight ); + } + break; + case IK_RELEASE: + { + CIKTarget *pTarget = &m_target[pRule->slot]; + if (pRule->latched > 0.0) + pTarget->est.latched = 0.0; + else + pTarget->est.latched = vmin( pTarget->est.latched, 1.0f - pRule->flWeight ); + + pTarget->est.flWeight = (pTarget->est.flWeight) * (1 - pRule->flWeight * pRule->flRuleWeight); + } + break; + } + } + } + + for (i = 0; i < m_target.Count(); i++) + { + CIKTarget *pTarget = &m_target[i]; + if (pTarget->est.flWeight > 0.0) + { + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( pTarget->chain ); + // ikchainresult_t *pChainRule = &chainRule[ i ]; + int bone = pchain->pLink( 2 )->bone; + + // eval current ik'd bone + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + + // xform IK target error into world space + matrix3x4_t local; + matrix3x4_t worldFootpad; + QuaternionMatrix( pTarget->offset.q, pTarget->offset.pos, local ); + MatrixInvert( local, local ); + ConcatTransforms( boneToWorld[bone], local, worldFootpad ); + + if (pTarget->est.latched == 1.0) + { + pTarget->latched.bNeedsLatch = true; + } + else + { + pTarget->latched.bNeedsLatch = false; + } + + // disable latched position if it looks invalid + if (m_iFramecounter < 0 || pTarget->latched.iFramecounter < m_iFramecounter - 1 || pTarget->latched.iFramecounter > m_iFramecounter) + { + pTarget->latched.bHasLatch = false; + pTarget->latched.influence = 0.0; + } + pTarget->latched.iFramecounter = m_iFramecounter; + + // find ideal contact position + MatrixAngles( worldFootpad, pTarget->ideal.q, pTarget->ideal.pos ); + pTarget->est.q = pTarget->ideal.q; + pTarget->est.pos = pTarget->ideal.pos; + + float latched = pTarget->est.latched; + + if (pTarget->latched.bHasLatch) + { + if (pTarget->est.latched == 1.0) + { + // keep track of latch position error from ideal contact position + pTarget->latched.deltaPos = pTarget->latched.pos - pTarget->est.pos; + QuaternionSM( -1, pTarget->est.q, pTarget->latched.q, pTarget->latched.deltaQ ); + pTarget->est.q = pTarget->latched.q; + pTarget->est.pos = pTarget->latched.pos; + } + else if (pTarget->est.latched > 0.0) + { + // ramp out latch differences during decay phase of rule + if (latched > 0 && latched < pTarget->latched.influence) + { + // latching has decreased + float dt = pTarget->latched.influence - latched; + if (pTarget->latched.influence > 0.0) + dt = dt / pTarget->latched.influence; + + VectorScale( pTarget->latched.deltaPos, (1-dt), pTarget->latched.deltaPos ); + QuaternionScale( pTarget->latched.deltaQ, (1-dt), pTarget->latched.deltaQ ); + } + + // move ideal contact position by latched error factor + pTarget->est.pos = pTarget->est.pos + pTarget->latched.deltaPos; + QuaternionMA( pTarget->est.q, 1, pTarget->latched.deltaQ, pTarget->est.q ); + pTarget->latched.q = pTarget->est.q; + pTarget->latched.pos = pTarget->est.pos; + } + else + { + pTarget->latched.bHasLatch = false; + pTarget->latched.q = pTarget->est.q; + pTarget->latched.pos = pTarget->est.pos; + pTarget->latched.deltaPos.Init(); + pTarget->latched.deltaQ.Init(); + } + pTarget->latched.influence = latched; + } + + // check for illegal requests + Vector p1, p2, p3; + MatrixPosition( boneToWorld[pchain->pLink( 0 )->bone], p1 ); // hip + MatrixPosition( boneToWorld[pchain->pLink( 1 )->bone], p2 ); // knee + MatrixPosition( boneToWorld[pchain->pLink( 2 )->bone], p3 ); // foot + + float d1 = (p2 - p1).Length(); + float d2 = (p3 - p2).Length(); + + if (pTarget->latched.bHasLatch) + { + //float d3 = (p3 - p1).Length(); + float d4 = (p3 + pTarget->latched.deltaPos - p1).Length(); + + // unstick feet when distance is too great + if ((d4 < fabs( d1 - d2 ) || d4 * 0.95 > d1 + d2) && pTarget->est.latched > 0.2) + { + pTarget->error.flTime = m_flTime; + } + + // unstick feet when angle is too great + if (pTarget->est.latched > 0.2) + { + float d = fabs( pTarget->latched.deltaQ.w ) * 2.0f - 1.0f; // QuaternionDotProduct( pTarget->latched.q, pTarget->est.q ); + + // FIXME: cos(45), make property of chain + if (d < 0.707) + { + pTarget->error.flTime = m_flTime; + } + } + } + + Vector dt = pTarget->est.pos - p1; + pTarget->trace.hipToFoot = VectorNormalize( dt ); + pTarget->trace.hipToKnee = d1; + pTarget->trace.kneeToFoot = d2; + pTarget->trace.hip = p1; + pTarget->trace.knee = p2; + pTarget->trace.closest = p1 + dt * (fabs( d1 - d2 ) * 1.01); + pTarget->trace.farthest = p1 + dt * (d1 + d2) * 0.99; + pTarget->trace.lowest = p1 + Vector( 0, 0, -1 ) * (d1 + d2) * 0.99; + // pTarget->trace.endpos = pTarget->est.pos; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: insert release rules if the ik rules were in error +//----------------------------------------------------------------------------- + +void CIKContext::AutoIKRelease( void ) +{ + int i; + + for (i = 0; i < m_target.Count(); i++) + { + CIKTarget *pTarget = &m_target[i]; + + float dt = m_flTime - pTarget->error.flTime; + if (pTarget->error.bInError || dt < 0.5) + { + if (!pTarget->error.bInError) + { + pTarget->error.ramp = 0.0; + pTarget->error.flErrorTime = pTarget->error.flTime; + pTarget->error.bInError = true; + } + + float ft = m_flTime - pTarget->error.flErrorTime; + if (dt < 0.25) + { + pTarget->error.ramp = vmin( pTarget->error.ramp + ft * 4.0, 1.0 ); + } + else + { + pTarget->error.ramp = vmax( pTarget->error.ramp - ft * 4.0, 0.0 ); + } + if (pTarget->error.ramp > 0.0) + { + ikcontextikrule_t ikrule; + + ikrule.chain = pTarget->chain; + ikrule.bone = 0; + ikrule.type = IK_RELEASE; + ikrule.slot = i; + ikrule.flWeight = SimpleSpline( pTarget->error.ramp ); + ikrule.flRuleWeight = 1.0; + ikrule.latched = dt < 0.25 ? 0.0 : ikrule.flWeight; + + // don't bother with AutoIKRelease if the bone isn't going to be calculated + // this code is crashing for some unknown reason. + if ( pTarget->chain >= 0 && pTarget->chain < m_pStudioHdr->numikchains()) + { + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( pTarget->chain ); + if (pchain != NULL) + { + int bone = pchain->pLink( 2 )->bone; + if (bone >= 0 && bone < m_pStudioHdr->numbones()) + { + mstudiobone_t *pBone = m_pStudioHdr->pBone( bone ); + if (pBone != NULL) + { + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + { + pTarget->error.bInError = false; + continue; + } + /* + char buf[256]; + sprintf( buf, "dt %.4f ft %.4f weight %.4f latched %.4f\n", dt, ft, ikrule.flWeight, ikrule.latched ); + OutputDebugString( buf ); + */ + + int nIndex = m_ikChainRule.Element( ikrule.chain ).AddToTail( ); + m_ikChainRule.Element( ikrule.chain ).Element( nIndex ) = ikrule; + } + else + { + DevWarning( 1, "AutoIKRelease (%s) got a NULL pBone %d\n", m_pStudioHdr->pszName(), bone ); + } + } + else + { + DevWarning( 1, "AutoIKRelease (%s) got an out of range bone %d (%d)\n", m_pStudioHdr->pszName(), bone, m_pStudioHdr->numbones() ); + } + } + else + { + DevWarning( 1, "AutoIKRelease (%s) got a NULL pchain %d\n", m_pStudioHdr->pszName(), pTarget->chain ); + } + } + else + { + DevWarning( 1, "AutoIKRelease (%s) got an out of range chain %d (%d)\n", m_pStudioHdr->pszName(), pTarget->chain, m_pStudioHdr->numikchains()); + } + } + else + { + pTarget->error.bInError = false; + } + pTarget->error.flErrorTime = m_flTime; + } + } +} + + + +void CIKContext::SolveDependencies( Vector pos[], Quaternion q[], matrix3x4_t boneToWorld[], CBoneBitList &boneComputed ) +{ +// ASSERT_NO_REENTRY(); + + matrix3x4_t worldTarget; + int i, j; + + ikchainresult_t chainResult[32]; // allocate!!! + + // init chain rules + for (i = 0; i < m_pStudioHdr->numikchains(); i++) + { + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( i ); + ikchainresult_t *pChainResult = &chainResult[ i ]; + int bone = pchain->pLink( 2 )->bone; + + pChainResult->target = -1; + pChainResult->flWeight = 0.0; + + // don't bother with chain if the bone isn't going to be calculated + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + continue; + + // eval current ik'd bone + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + + MatrixAngles( boneToWorld[bone], pChainResult->q, pChainResult->pos ); + } + + for (j = 0; j < m_ikChainRule.Count(); j++) + { + for (i = 0; i < m_ikChainRule.Element( j ).Count(); i++) + { + ikcontextikrule_t *pRule = &m_ikChainRule.Element( j ).Element( i ); + ikchainresult_t *pChainResult = &chainResult[ pRule->chain ]; + pChainResult->target = -1; + + + switch( pRule->type ) + { + case IK_SELF: + { + // xform IK target error into world space + matrix3x4_t local; + QuaternionMatrix( pRule->q, pRule->pos, local ); + // eval target bone space + if (pRule->bone != -1) + { + BuildBoneChain( pos, q, pRule->bone, boneToWorld, boneComputed ); + ConcatTransforms( boneToWorld[pRule->bone], local, worldTarget ); + } + else + { + ConcatTransforms( m_rootxform, local, worldTarget ); + } + + float flWeight = pRule->flWeight * pRule->flRuleWeight; + pChainResult->flWeight = pChainResult->flWeight * (1 - flWeight) + flWeight; + + Vector p2; + Quaternion q2; + + // target p and q + MatrixAngles( worldTarget, q2, p2 ); + + // debugLine( pChainResult->pos, p2, 0, 0, 255, true, 0.1 ); + + // blend in position and angles + pChainResult->pos = pChainResult->pos * (1.0 - flWeight) + p2 * flWeight; + QuaternionSlerp( pChainResult->q, q2, flWeight, pChainResult->q ); + } + break; + case IK_WORLD: + Assert( 0 ); + break; + + case IK_ATTACHMENT: + break; + + case IK_GROUND: + break; + + case IK_RELEASE: + { + // move target back towards original location + float flWeight = pRule->flWeight * pRule->flRuleWeight; + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( pRule->chain ); + int bone = pchain->pLink( 2 )->bone; + + Vector p2; + Quaternion q2; + + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + MatrixAngles( boneToWorld[bone], q2, p2 ); + + // blend in position and angles + pChainResult->pos = pChainResult->pos * (1.0 - flWeight) + p2 * flWeight; + QuaternionSlerp( pChainResult->q, q2, flWeight, pChainResult->q ); + } + break; + case IK_UNLATCH: + { + /* + pChainResult->flWeight = pChainResult->flWeight * (1 - pRule->flWeight) + pRule->flWeight; + + pChainResult->pos = pChainResult->pos * (1.0 - pRule->flWeight ) + pChainResult->local.pos * pRule->flWeight; + QuaternionSlerp( pChainResult->q, pChainResult->local.q, pRule->flWeight, pChainResult->q ); + */ + } + break; + } + } + } + + for (i = 0; i < m_target.Count(); i++) + { + CIKTarget *pTarget = &m_target[i]; + + if (m_target[i].est.flWeight > 0.0) + { + matrix3x4_t worldFootpad; + matrix3x4_t local; + //mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( m_target[i].chain ); + ikchainresult_t *pChainResult = &chainResult[ pTarget->chain ]; + + AngleMatrix(pTarget->offset.q, pTarget->offset.pos, local ); + + AngleMatrix( pTarget->est.q, pTarget->est.pos, worldFootpad ); + + ConcatTransforms( worldFootpad, local, worldTarget ); + + Vector p2; + Quaternion q2; + // target p and q + MatrixAngles( worldTarget, q2, p2 ); + // MatrixAngles( worldTarget, pChainResult->q, pChainResult->pos ); + + // blend in position and angles + pChainResult->flWeight = pTarget->est.flWeight; + pChainResult->pos = pChainResult->pos * (1.0 - pChainResult->flWeight ) + p2 * pChainResult->flWeight; + QuaternionSlerp( pChainResult->q, q2, pChainResult->flWeight, pChainResult->q ); + } + + if (pTarget->latched.bNeedsLatch) + { + // keep track of latch position + pTarget->latched.bHasLatch = true; + pTarget->latched.q = pTarget->est.q; + pTarget->latched.pos = pTarget->est.pos; + } + } + + for (i = 0; i < m_pStudioHdr->numikchains(); i++) + { + ikchainresult_t *pChainResult = &chainResult[ i ]; + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( i ); + + if (pChainResult->flWeight > 0.0) + { + Vector tmp; + MatrixPosition( boneToWorld[pchain->pLink( 2 )->bone], tmp ); + // debugLine( pChainResult->pos, tmp, 255, 255, 255, true, 0.1 ); + + // do exact IK solution + // FIXME: once per link! + if (Studio_SolveIK(pchain, pChainResult->pos, boneToWorld )) + { + Vector p3; + MatrixGetColumn( boneToWorld[pchain->pLink( 2 )->bone], 3, p3 ); + QuaternionMatrix( pChainResult->q, p3, boneToWorld[pchain->pLink( 2 )->bone] ); + + // rebuild chain + // FIXME: is this needed if everyone past this uses the boneToWorld array? + SolveBone( m_pStudioHdr, pchain->pLink( 2 )->bone, boneToWorld, pos, q ); + SolveBone( m_pStudioHdr, pchain->pLink( 1 )->bone, boneToWorld, pos, q ); + SolveBone( m_pStudioHdr, pchain->pLink( 0 )->bone, boneToWorld, pos, q ); + } + else + { + // FIXME: need to invalidate the targets that forced this... + if (pChainResult->target != -1) + { + CIKTarget *pTarget = &m_target[pChainResult->target]; + VectorScale( pTarget->latched.deltaPos, 0.8, pTarget->latched.deltaPos ); + QuaternionScale( pTarget->latched.deltaQ, 0.8, pTarget->latched.deltaQ ); + } + } + } + } + +#if 0 + Vector p1, p2, p3; + Quaternion q1, q2, q3; + + // current p and q + MatrixAngles( boneToWorld[bone], q1, p1 ); + + + // target p and q + MatrixAngles( worldTarget, q2, p2 ); + + // blend in position and angles + p3 = p1 * (1.0 - m_ikRule[i].flWeight ) + p2 * m_ikRule[i].flWeight; + + // do exact IK solution + // FIXME: once per link! + Studio_SolveIK(pchain, p3, boneToWorld ); + + // force angle (bad?) + QuaternionSlerp( q1, q2, m_ikRule[i].flWeight, q3 ); + MatrixGetColumn( boneToWorld[bone], 3, p3 ); + QuaternionMatrix( q3, p3, boneToWorld[bone] ); + + // rebuild chain + SolveBone( m_pStudioHdr, pchain->pLink( 2 )->bone, boneToWorld, pos, q ); + SolveBone( m_pStudioHdr, pchain->pLink( 1 )->bone, boneToWorld, pos, q ); + SolveBone( m_pStudioHdr, pchain->pLink( 0 )->bone, boneToWorld, pos, q ); +#endif +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKContext::SolveAutoplayLocks( + Vector pos[], + Quaternion q[] + ) +{ + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + int i; + + for (i = 0; i < m_ikLock.Count(); i++) + { + const mstudioiklock_t &lock = ((CStudioHdr *)m_pStudioHdr)->pIKAutoplayLock( i ); + SolveLock( &lock, i, pos, q, boneToWorld, boneComputed ); + } + g_MatrixPool.Free( boneToWorld ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKContext::SolveSequenceLocks( + mstudioseqdesc_t &seqdesc, + Vector pos[], + Quaternion q[] + ) +{ + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + int i; + + for (i = 0; i < m_ikLock.Count(); i++) + { + mstudioiklock_t *plock = seqdesc.pIKLock( i ); + SolveLock( plock, i, pos, q, boneToWorld, boneComputed ); + } + g_MatrixPool.Free( boneToWorld ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CIKContext::AddAllLocks( Vector pos[], Quaternion q[] ) +{ + // skip all array access if no autoplay locks. + if (m_pStudioHdr->GetNumIKChains() == 0) + { + return; + } + + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + + int ikOffset = m_ikLock.AddMultipleToTail( m_pStudioHdr->GetNumIKChains() ); + memset( &m_ikLock[ikOffset], 0, sizeof(ikcontextikrule_t)*m_pStudioHdr->GetNumIKChains() ); + + for (int i = 0; i < m_pStudioHdr->GetNumIKChains(); i++) + { + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( i ); + int bone = pchain->pLink( 2 )->bone; + + // don't bother with iklock if the bone isn't going to be calculated + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + continue; + + // eval current ik'd bone + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + + ikcontextikrule_t &ikrule = m_ikLock[ i + ikOffset ]; + + ikrule.chain = i; + ikrule.slot = i; + ikrule.type = IK_WORLD; + + MatrixAngles( boneToWorld[bone], ikrule.q, ikrule.pos ); + + // save off current knee direction + if (pchain->pLink(0)->kneeDir.LengthSqr() > 0.0) + { + Vector tmp = pchain->pLink( 0 )->kneeDir; + VectorRotate( pchain->pLink( 0 )->kneeDir, boneToWorld[ pchain->pLink( 0 )->bone ], ikrule.kneeDir ); + MatrixPosition( boneToWorld[ pchain->pLink( 1 )->bone ], ikrule.kneePos ); + } + else + { + ikrule.kneeDir.Init( ); + } + } + g_MatrixPool.Free( boneToWorld ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +void CIKContext::SolveAllLocks( + Vector pos[], + Quaternion q[] + ) +{ + matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); + CBoneBitList boneComputed; + int i; + + mstudioiklock_t lock; + + for (i = 0; i < m_ikLock.Count(); i++) + { + lock.chain = i; + lock.flPosWeight = 1.0; + lock.flLocalQWeight = 0.0; + lock.flags = 0; + + SolveLock( &lock, i, pos, q, boneToWorld, boneComputed ); + } + g_MatrixPool.Free( boneToWorld ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +void CIKContext::SolveLock( + const mstudioiklock_t *plock, + int i, + Vector pos[], + Quaternion q[], + matrix3x4_t boneToWorld[], + CBoneBitList &boneComputed + ) +{ + mstudioikchain_t *pchain = m_pStudioHdr->pIKChain( plock->chain ); + int bone = pchain->pLink( 2 )->bone; + + // don't bother with iklock if the bone isn't going to be calculated + if ( !(m_pStudioHdr->boneFlags( bone ) & m_boneMask)) + return; + + // eval current ik'd bone + BuildBoneChain( pos, q, bone, boneToWorld, boneComputed ); + + Vector p1, p2, p3; + Quaternion q2, q3; + + // current p and q + MatrixPosition( boneToWorld[bone], p1 ); + + // blend in position + p3 = p1 * (1.0 - plock->flPosWeight ) + m_ikLock[i].pos * plock->flPosWeight; + + // do exact IK solution + if (m_ikLock[i].kneeDir.LengthSqr() > 0) + { + Studio_SolveIK(pchain->pLink( 0 )->bone, pchain->pLink( 1 )->bone, pchain->pLink( 2 )->bone, p3, m_ikLock[i].kneePos, m_ikLock[i].kneeDir, boneToWorld ); + } + else + { + Studio_SolveIK(pchain, p3, boneToWorld ); + } + + // slam orientation + MatrixPosition( boneToWorld[bone], p3 ); + QuaternionMatrix( m_ikLock[i].q, p3, boneToWorld[bone] ); + + // rebuild chain + q2 = q[ bone ]; + SolveBone( m_pStudioHdr, pchain->pLink( 2 )->bone, boneToWorld, pos, q ); + QuaternionSlerp( q[bone], q2, plock->flLocalQWeight, q[bone] ); + + SolveBone( m_pStudioHdr, pchain->pLink( 1 )->bone, boneToWorld, pos, q ); + SolveBone( m_pStudioHdr, pchain->pLink( 0 )->bone, boneToWorld, pos, q ); +} + + +//----------------------------------------------------------------------------- +// Purpose: run all animations that automatically play and are driven off of poseParameters +//----------------------------------------------------------------------------- +void CBoneSetup::CalcAutoplaySequences( + Vector pos[], + Quaternion q[], + float flRealTime, + CIKContext *pIKContext + ) +{ + // ASSERT_NO_REENTRY(); + + int i; + if ( pIKContext ) + { + pIKContext->AddAutoplayLocks( pos, q ); + } + + unsigned short *pList = NULL; + int count = m_pStudioHdr->GetAutoplayList( &pList ); + for (i = 0; i < count; i++) + { + int sequenceIndex = pList[i]; + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)m_pStudioHdr)->pSeqdesc( sequenceIndex ); + if (seqdesc.flags & STUDIO_AUTOPLAY) + { + float cycle = 0; + float cps = Studio_CPS( m_pStudioHdr, seqdesc, sequenceIndex, m_flPoseParameter ); + cycle = flRealTime * cps; + cycle = cycle - (int)cycle; + + AccumulatePose( pos, q, sequenceIndex, cycle, 1.0, flRealTime, pIKContext ); + } + } + + if ( pIKContext ) + { + pIKContext->SolveAutoplayLocks( pos, q ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void Studio_BuildMatrices( + const CStudioHdr *pStudioHdr, + const QAngle& angles, + const Vector& origin, + const Vector pos[], + const Quaternion q[], + int iBone, + float flScale, + matrix3x4_t bonetoworld[MAXSTUDIOBONES], + int boneMask + ) +{ + int i, j; + + int chain[MAXSTUDIOBONES] = {}; + int chainlength = 0; + + if (iBone < -1 || iBone >= pStudioHdr->numbones()) + iBone = 0; + + // build list of what bones to use + if (iBone == -1) + { + // all bones + chainlength = pStudioHdr->numbones(); + for (i = 0; i < pStudioHdr->numbones(); i++) + { + chain[chainlength - i - 1] = i; + } + } + else + { + // only the parent bones + i = iBone; + while (i != -1) + { + chain[chainlength++] = i; + i = pStudioHdr->boneParent( i ); + } + } + + matrix3x4_t bonematrix; + matrix3x4_t rotationmatrix; // model to world transformation + AngleMatrix( angles, origin, rotationmatrix ); + + // Account for a change in scale + if ( flScale < 1.0f-FLT_EPSILON || flScale > 1.0f+FLT_EPSILON ) + { + Vector vecOffset; + MatrixGetColumn( rotationmatrix, 3, vecOffset ); + vecOffset -= origin; + vecOffset *= flScale; + vecOffset += origin; + MatrixSetColumn( vecOffset, 3, rotationmatrix ); + + // Scale it uniformly + VectorScale( rotationmatrix[0], flScale, rotationmatrix[0] ); + VectorScale( rotationmatrix[1], flScale, rotationmatrix[1] ); + VectorScale( rotationmatrix[2], flScale, rotationmatrix[2] ); + } + + for (j = chainlength - 1; j >= 0; j--) + { + i = chain[j]; + if (pStudioHdr->boneFlags(i) & boneMask) + { + QuaternionMatrix( q[i], pos[i], bonematrix ); + + if (pStudioHdr->boneParent(i) == -1) + { + ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]); + } + else + { + ConcatTransforms (bonetoworld[pStudioHdr->boneParent(i)], bonematrix, bonetoworld[i]); + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: look at single column vector of another bones local transformation +// and generate a procedural transformation based on how that column +// points down the 6 cardinal axis (all negative weights are clamped to 0). +//----------------------------------------------------------------------------- + +void DoAxisInterpBone( + mstudiobone_t *pbones, + int ibone, + CBoneAccessor &bonetoworld + ) +{ + matrix3x4_t bonematrix; + Vector control; + + mstudioaxisinterpbone_t *pProc = (mstudioaxisinterpbone_t *)pbones[ibone].pProcedure( ); + const matrix3x4_t &controlBone = bonetoworld.GetBone( pProc->control ); + if (pProc && pbones[pProc->control].parent != -1) + { + Vector tmp; + // pull out the control column + tmp.x = controlBone[0][pProc->axis]; + tmp.y = controlBone[1][pProc->axis]; + tmp.z = controlBone[2][pProc->axis]; + + // invert it back into parent's space. + VectorIRotate( tmp, bonetoworld.GetBone( pbones[pProc->control].parent ), control ); +#if 0 + matrix3x4_t tmpmatrix; + matrix3x4_t controlmatrix; + MatrixInvert( bonetoworld.GetBone( pbones[pProc->control].parent ), tmpmatrix ); + ConcatTransforms( tmpmatrix, bonetoworld.GetBone( pProc->control ), controlmatrix ); + + // pull out the control column + control.x = controlmatrix[0][pProc->axis]; + control.y = controlmatrix[1][pProc->axis]; + control.z = controlmatrix[2][pProc->axis]; +#endif + } + else + { + // pull out the control column + control.x = controlBone[0][pProc->axis]; + control.y = controlBone[1][pProc->axis]; + control.z = controlBone[2][pProc->axis]; + } + + Quaternion *q1, *q2, *q3; + Vector *p1, *p2, *p3; + + // find axial control inputs + float a1 = control.x; + float a2 = control.y; + float a3 = control.z; + if (a1 >= 0) + { + q1 = &pProc->quat[0]; + p1 = &pProc->pos[0]; + } + else + { + a1 = -a1; + q1 = &pProc->quat[1]; + p1 = &pProc->pos[1]; + } + + if (a2 >= 0) + { + q2 = &pProc->quat[2]; + p2 = &pProc->pos[2]; + } + else + { + a2 = -a2; + q2 = &pProc->quat[3]; + p2 = &pProc->pos[3]; + } + + if (a3 >= 0) + { + q3 = &pProc->quat[4]; + p3 = &pProc->pos[4]; + } + else + { + a3 = -a3; + q3 = &pProc->quat[5]; + p3 = &pProc->pos[5]; + } + + // do a three-way blend + Vector p; + Quaternion v, tmp; + if (a1 + a2 > 0) + { + float t = 1.0 / (a1 + a2 + a3); + // FIXME: do a proper 3-way Quat blend! + QuaternionSlerp( *q2, *q1, a1 / (a1 + a2), tmp ); + QuaternionSlerp( tmp, *q3, a3 * t, v ); + VectorScale( *p1, a1 * t, p ); + VectorMA( p, a2 * t, *p2, p ); + VectorMA( p, a3 * t, *p3, p ); + } + else + { + QuaternionSlerp( *q3, *q3, 0, v ); // ??? no quat copy? + p = *p3; + } + + QuaternionMatrix( v, p, bonematrix ); + + ConcatTransforms (bonetoworld.GetBone( pbones[ibone].parent ), bonematrix, bonetoworld.GetBoneForWrite( ibone )); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Generate a procedural transformation based on how that another bones +// local transformation matches a set of target orientations. +//----------------------------------------------------------------------------- +void DoQuatInterpBone( + mstudiobone_t *pbones, + int ibone, + CBoneAccessor &bonetoworld + ) +{ + matrix3x4_t bonematrix; + Vector control; + + mstudioquatinterpbone_t *pProc = (mstudioquatinterpbone_t *)pbones[ibone].pProcedure( ); + if (pProc && pbones[pProc->control].parent != -1) + { + Quaternion src; + float weight[32]; + float scale = 0.0; + Quaternion quat; + Vector pos; + + matrix3x4_t tmpmatrix; + matrix3x4_t controlmatrix; + MatrixInvert( bonetoworld.GetBone( pbones[pProc->control].parent), tmpmatrix ); + ConcatTransforms( tmpmatrix, bonetoworld.GetBone( pProc->control ), controlmatrix ); + + MatrixAngles( controlmatrix, src, pos ); // FIXME: make a version without pos + + int i; + for (i = 0; i < pProc->numtriggers; i++) + { + float dot = fabs( QuaternionDotProduct( pProc->pTrigger( i )->trigger, src ) ); + // FIXME: a fast acos should be acceptable + dot = clamp( dot, -1.f, 1.f ); + weight[i] = 1 - (2 * acos( dot ) * pProc->pTrigger( i )->inv_tolerance ); + weight[i] = vmax( 0, weight[i] ); + scale += weight[i]; + } + + if (scale <= 0.001) // EPSILON? + { + AngleMatrix( pProc->pTrigger( 0 )->quat, pProc->pTrigger( 0 )->pos, bonematrix ); + ConcatTransforms ( bonetoworld.GetBone( pbones[ibone].parent ), bonematrix, bonetoworld.GetBoneForWrite( ibone ) ); + return; + } + + scale = 1.0 / scale; + + quat.Init( 0, 0, 0, 0); + pos.Init( ); + + for (i = 0; i < pProc->numtriggers; i++) + { + if (weight[i]) + { + float s = weight[i] * scale; + mstudioquatinterpinfo_t *pTrigger = pProc->pTrigger( i ); + + QuaternionAlign( pTrigger->quat, quat, quat ); + + quat.x = quat.x + s * pTrigger->quat.x; + quat.y = quat.y + s * pTrigger->quat.y; + quat.z = quat.z + s * pTrigger->quat.z; + quat.w = quat.w + s * pTrigger->quat.w; + pos.x = pos.x + s * pTrigger->pos.x; + pos.y = pos.y + s * pTrigger->pos.y; + pos.z = pos.z + s * pTrigger->pos.z; + } + } + Assert( QuaternionNormalize( quat ) != 0); + QuaternionMatrix( quat, pos, bonematrix ); + } + + ConcatTransforms (bonetoworld.GetBone( pbones[ibone].parent ), bonematrix, bonetoworld.GetBoneForWrite( ibone )); +} + +/* + * This is for DoAimAtBone below, was just for testing, not needed in general + * but to turn it back on, uncomment this and the section in DoAimAtBone() below + * + +static ConVar aim_constraint( "aim_constraint", "1", FCVAR_REPLICATED, "Toggle Helper Bones" ); + +*/ + +//----------------------------------------------------------------------------- +// Purpose: Generate a procedural transformation so that one bone points at +// another point on the model +//----------------------------------------------------------------------------- +void DoAimAtBone( + mstudiobone_t *pBones, + int iBone, + CBoneAccessor &bonetoworld, + const CStudioHdr *pStudioHdr + ) +{ + mstudioaimatbone_t *pProc = (mstudioaimatbone_t *)pBones[iBone].pProcedure(); + + if ( !pProc ) + { + return; + } + + /* + * Uncomment this if the ConVar above is uncommented + * + + if ( !aim_constraint.GetBool() ) + { + // If the aim constraint is turned off then just copy the parent transform + // plus the offset value + + matrix3x4_t boneToWorldSpace; + MatrixCopy ( bonetoworld.GetBone( pProc->parent ), boneToWorldSpace ); + Vector boneWorldPosition; + VectorTransform( pProc->basepos, boneToWorldSpace, boneWorldPosition ); + MatrixSetColumn( boneWorldPosition, 3, boneToWorldSpace ); + MatrixCopy( boneToWorldSpace, bonetoworld.GetBoneForWrite( iBone ) ); + + return; + } + + */ + + // The world matrix of the bone to change + matrix3x4_t boneMatrix; + + // Guaranteed to be unit length + const Vector &userAimVector( pProc->aimvector ); + + // Guaranteed to be unit length + const Vector &userUpVector( pProc->upvector ); + + // Get to get position of bone but also for up reference + matrix3x4_t parentSpace; + MatrixCopy ( bonetoworld.GetBone( pProc->parent ), parentSpace ); + + // World space position of the bone to aim + Vector aimWorldPosition; + VectorTransform( pProc->basepos, parentSpace, aimWorldPosition ); + + // The worldspace matrix of the bone to aim at + matrix3x4_t aimAtSpace; + if ( pStudioHdr ) + { + // This means it's AIMATATTACH + const mstudioattachment_t &attachment( ((CStudioHdr *)pStudioHdr)->pAttachment( pProc->aim ) ); + ConcatTransforms( + bonetoworld.GetBone( attachment.localbone ), + attachment.local, + aimAtSpace ); + } + else + { + MatrixCopy( bonetoworld.GetBone( pProc->aim ), aimAtSpace ); + } + + Vector aimAtWorldPosition; + MatrixGetColumn( aimAtSpace, 3, aimAtWorldPosition ); + + // make sure the redundant parent info is correct + Assert( pProc->parent == pBones[iBone].parent ); + // make sure the redundant position info is correct + Assert( pProc->basepos.DistToSqr( pBones[iBone].pos ) < 0.1 ); + + // The aim and up data is relative to this bone, not the parent bone + matrix3x4_t bonematrix, boneLocalToWorld; + AngleMatrix( pBones[iBone].quat, pProc->basepos, bonematrix ); + ConcatTransforms( bonetoworld.GetBone( pProc->parent ), bonematrix, boneLocalToWorld ); + + Vector aimVector; + VectorSubtract( aimAtWorldPosition, aimWorldPosition, aimVector ); + VectorNormalizeFast( aimVector ); + + Vector axis; + CrossProduct( userAimVector, aimVector, axis ); + VectorNormalizeFast( axis ); + Assert( 1.0f - fabs( DotProduct( userAimVector, aimVector ) ) > FLT_EPSILON ); + float angle( acosf( DotProduct( userAimVector, aimVector ) ) ); + Quaternion aimRotation; + AxisAngleQuaternion( axis, RAD2DEG( angle ), aimRotation ); + + if ( ( 1.0f - fabs( DotProduct( userUpVector, userAimVector ) ) ) > FLT_EPSILON ) + { + matrix3x4_t aimRotationMatrix; + QuaternionMatrix( aimRotation, aimRotationMatrix ); + + Vector tmpV; + + Vector tmp_pUp; + VectorRotate( userUpVector, aimRotationMatrix, tmp_pUp ); + VectorScale( aimVector, DotProduct( aimVector, tmp_pUp ), tmpV ); + Vector pUp; + VectorSubtract( tmp_pUp, tmpV, pUp ); + VectorNormalizeFast( pUp ); + + Vector tmp_pParentUp; + VectorRotate( userUpVector, boneLocalToWorld, tmp_pParentUp ); + VectorScale( aimVector, DotProduct( aimVector, tmp_pParentUp ), tmpV ); + Vector pParentUp; + VectorSubtract( tmp_pParentUp, tmpV, pParentUp ); + VectorNormalizeFast( pParentUp ); + + Quaternion upRotation; + //Assert( 1.0f - fabs( DotProduct( pUp, pParentUp ) ) > FLT_EPSILON ); + if( 1.0f - fabs( DotProduct( pUp, pParentUp ) ) > FLT_EPSILON ) + { + angle = acos( DotProduct( pUp, pParentUp ) ); + CrossProduct( pUp, pParentUp, axis ); + } + else + { + angle = 0; + axis = pUp; + } + + VectorNormalizeFast( axis ); + AxisAngleQuaternion( axis, RAD2DEG( angle ), upRotation ); + + Quaternion boneRotation; + QuaternionMult( upRotation, aimRotation, boneRotation ); + QuaternionMatrix( boneRotation, aimWorldPosition, boneMatrix ); + } + else + { + QuaternionMatrix( aimRotation, aimWorldPosition, boneMatrix ); + } + + MatrixCopy( boneMatrix, bonetoworld.GetBoneForWrite( iBone ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +bool CalcProceduralBone( + const CStudioHdr *pStudioHdr, + int iBone, + CBoneAccessor &bonetoworld + ) +{ + mstudiobone_t *pbones = pStudioHdr->pBone( 0 ); + + if ( pStudioHdr->boneFlags(iBone) & BONE_ALWAYS_PROCEDURAL ) + { + switch( pbones[iBone].proctype ) + { + case STUDIO_PROC_AXISINTERP: + DoAxisInterpBone( pbones, iBone, bonetoworld ); + return true; + + case STUDIO_PROC_QUATINTERP: + DoQuatInterpBone( pbones, iBone, bonetoworld ); + return true; + + case STUDIO_PROC_AIMATBONE: + DoAimAtBone( pbones, iBone, bonetoworld, NULL ); + return true; + + case STUDIO_PROC_AIMATATTACH: + DoAimAtBone( pbones, iBone, bonetoworld, pStudioHdr ); + return true; + + default: + return false; + } + } + return false; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Lookup a bone controller +//----------------------------------------------------------------------------- + + + +static mstudiobonecontroller_t* FindController( const CStudioHdr *pStudioHdr, int iController) +{ + // find first controller that matches the index + for (int i = 0; i < pStudioHdr->numbonecontrollers(); i++) + { + if (pStudioHdr->pBonecontroller( i )->inputfield == iController) + return pStudioHdr->pBonecontroller( i ); + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: converts a ranged bone controller value into a 0..1 encoded value +// Output: ctlValue contains 0..1 encoding. +// returns clamped ranged value +//----------------------------------------------------------------------------- + +float Studio_SetController( const CStudioHdr *pStudioHdr, int iController, float flValue, float &ctlValue ) +{ + if (! pStudioHdr) + return flValue; + + mstudiobonecontroller_t *pbonecontroller = FindController(pStudioHdr, iController); + if(!pbonecontroller) + { + ctlValue = 0; + return flValue; + } + + // wrap 0..360 if it's a rotational controller + if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) + { + // ugly hack, invert value if end < start + if (pbonecontroller->end < pbonecontroller->start) + flValue = -flValue; + + // does the controller not wrap? + if (pbonecontroller->start + 359.0 >= pbonecontroller->end) + { + if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180) + flValue = flValue - 360; + if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180) + flValue = flValue + 360; + } + else + { + if (flValue > 360) + flValue = flValue - (int)(flValue / 360.0) * 360.0; + else if (flValue < 0) + flValue = flValue + (int)((flValue / -360.0) + 1) * 360.0; + } + } + + ctlValue = (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start); + if (ctlValue < 0) ctlValue = 0; + if (ctlValue > 1) ctlValue = 1; + + float flReturnVal = ((1.0 - ctlValue)*pbonecontroller->start + ctlValue *pbonecontroller->end); + + // ugly hack, invert value if a rotational controller and end < start + if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR) && + pbonecontroller->end < pbonecontroller->start ) + { + flReturnVal *= -1; + } + + return flReturnVal; +} + + +//----------------------------------------------------------------------------- +// Purpose: converts a 0..1 encoded bone controller value into a ranged value +// Output: returns ranged value +//----------------------------------------------------------------------------- + +float Studio_GetController( const CStudioHdr *pStudioHdr, int iController, float ctlValue ) +{ + if (!pStudioHdr) + return 0.0; + + mstudiobonecontroller_t *pbonecontroller = FindController(pStudioHdr, iController); + if(!pbonecontroller) + return 0; + + return ctlValue * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start; +} + + +//----------------------------------------------------------------------------- +// Purpose: Calculates default values for the pose parameters +// Output: fills in an array +//----------------------------------------------------------------------------- + +void Studio_CalcDefaultPoseParameters( const CStudioHdr *pStudioHdr, float flPoseParameter[], int nCount ) +{ + int nPoseCount = pStudioHdr->GetNumPoseParameters(); + int nNumParams = MIN( nCount, MAXSTUDIOPOSEPARAM ); + + for ( int i = 0; i < nNumParams; ++i ) + { + // Default to middle of the pose parameter range + flPoseParameter[ i ] = 0.5f; + if ( i < nPoseCount ) + { + const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)pStudioHdr)->pPoseParameter( i ); + + // Want to try for a zero state. If one doesn't exist set it to .5 by default. + if ( Pose.start < 0.0f && Pose.end > 0.0f ) + { + float flPoseDelta = Pose.end - Pose.start; + flPoseParameter[i] = -Pose.start / flPoseDelta; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: converts a ranged pose parameter value into a 0..1 encoded value +// Output: ctlValue contains 0..1 encoding. +// returns clamped ranged value +//----------------------------------------------------------------------------- + +float Studio_SetPoseParameter( const CStudioHdr *pStudioHdr, int iParameter, float flValue, float &ctlValue ) +{ + if (iParameter < 0 || iParameter >= pStudioHdr->GetNumPoseParameters()) + { + return 0; + } + + const mstudioposeparamdesc_t &PoseParam = ((CStudioHdr *)pStudioHdr)->pPoseParameter( iParameter ); + + Assert( IsFinite( flValue ) ); + + if (PoseParam.loop) + { + float wrap = (PoseParam.start + PoseParam.end) / 2.0 + PoseParam.loop / 2.0; + float shift = PoseParam.loop - wrap; + + flValue = flValue - PoseParam.loop * floor((flValue + shift) / PoseParam.loop); + } + + ctlValue = (flValue - PoseParam.start) / (PoseParam.end - PoseParam.start); + + if (ctlValue < 0) ctlValue = 0; + if (ctlValue > 1) ctlValue = 1; + + Assert( IsFinite( ctlValue ) ); + + return ctlValue * (PoseParam.end - PoseParam.start) + PoseParam.start; +} + + +//----------------------------------------------------------------------------- +// Purpose: converts a 0..1 encoded pose parameter value into a ranged value +// Output: returns ranged value +//----------------------------------------------------------------------------- + +float Studio_GetPoseParameter( const CStudioHdr *pStudioHdr, int iParameter, float ctlValue ) +{ + if (iParameter < 0 || iParameter >= pStudioHdr->GetNumPoseParameters()) + { + return 0; + } + + const mstudioposeparamdesc_t &PoseParam = ((CStudioHdr *)pStudioHdr)->pPoseParameter( iParameter ); + + return ctlValue * (PoseParam.end - PoseParam.start) + PoseParam.start; +} + + +#pragma warning (disable : 4701) + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +static int ClipRayToHitbox( const Ray_t &ray, mstudiobbox_t *pbox, matrix3x4_t& matrix, trace_t &tr ) +{ + const float flProjEpsilon = 0.01f; + // scale by current t so hits shorten the ray and increase the likelihood of early outs + Vector delta2; + VectorScale( ray.m_Delta, (0.5f * tr.fraction), delta2 ); + + // OPTIMIZE: Store this in the box instead of computing it here + // compute center in local space + Vector boxextents; + boxextents.x = (pbox->bbmin.x + pbox->bbmax.x) * 0.5; + boxextents.y = (pbox->bbmin.y + pbox->bbmax.y) * 0.5; + boxextents.z = (pbox->bbmin.z + pbox->bbmax.z) * 0.5; + Vector boxCenter; + // transform to world space + VectorTransform( boxextents, matrix, boxCenter ); + // calc extents from local center + boxextents.x = pbox->bbmax.x - boxextents.x; + boxextents.y = pbox->bbmax.y - boxextents.y; + boxextents.z = pbox->bbmax.z - boxextents.z; + // OPTIMIZE: This is optimized for world space. If the transform is fast enough, it may make more + // sense to just xform and call UTIL_ClipToBox() instead. MEASURE THIS. + + // save the extents of the ray along + Vector extent, uextent; + Vector segmentCenter; + segmentCenter.x = ray.m_Start.x + delta2.x - boxCenter.x; + segmentCenter.y = ray.m_Start.y + delta2.y - boxCenter.y; + segmentCenter.z = ray.m_Start.z + delta2.z - boxCenter.z; + + extent.Init(); + + // check box axes for separation + for ( int j = 0; j < 3; j++ ) + { + extent[j] = delta2.x * matrix[0][j] + delta2.y * matrix[1][j] + delta2.z * matrix[2][j]; + uextent[j] = fabsf(extent[j]); + float coord = segmentCenter.x * matrix[0][j] + segmentCenter.y * matrix[1][j] + segmentCenter.z * matrix[2][j]; + coord = fabsf(coord); + + if ( coord > (boxextents[j] + uextent[j]) ) + return -1; + } + + // now check cross axes for separation + float tmp, tmpfix, cextent; + Vector cross; + CrossProduct( delta2, segmentCenter, cross ); + cextent = cross.x * matrix[0][0] + cross.y * matrix[1][0] + cross.z * matrix[2][0]; + cextent = fabsf(cextent); + tmp = boxextents[1]*uextent[2] + boxextents[2]*uextent[1]; + tmpfix = MAX(tmp, flProjEpsilon); + if ( cextent > tmpfix ) + return -1; + +// if ( cextent > tmp && cextent <= tmpfix ) +// DevWarning( "ClipRayToHitbox trace precision error case\n" ); + + cextent = cross.x * matrix[0][1] + cross.y * matrix[1][1] + cross.z * matrix[2][1]; + cextent = fabsf(cextent); + tmp = boxextents[0]*uextent[2] + boxextents[2]*uextent[0]; + tmpfix = MAX(tmp, flProjEpsilon); + if ( cextent > tmpfix ) + return -1; + +// if ( cextent > tmp && cextent <= tmpfix ) +// DevWarning( "ClipRayToHitbox trace precision error case\n" ); + + cextent = cross.x * matrix[0][2] + cross.y * matrix[1][2] + cross.z * matrix[2][2]; + cextent = fabsf(cextent); + tmp = boxextents[0]*uextent[1] + boxextents[1]*uextent[0]; + tmpfix = MAX(tmp, flProjEpsilon); + if ( cextent > tmpfix ) + return -1; + +// if ( cextent > tmp && cextent <= tmpfix ) +// DevWarning( "ClipRayToHitbox trace precision error case\n" ); + + // !!! We hit this box !!! compute intersection point and return + Vector start; + + // Compute ray start in bone space + VectorITransform( ray.m_Start, matrix, start ); + // extent is delta2 in bone space, recompute delta in bone space + VectorScale( extent, 2, extent ); + + // delta was prescaled by the current t, so no need to see if this intersection + // is closer + trace_t boxTrace; + if ( !IntersectRayWithBox( start, extent, pbox->bbmin, pbox->bbmax, 0.0f, &boxTrace ) ) + return -1; + + Assert( IsFinite(boxTrace.fraction) ); + tr.fraction *= boxTrace.fraction; + tr.startsolid = boxTrace.startsolid; + int hitside = boxTrace.plane.type; + if ( boxTrace.plane.normal[hitside] >= 0 ) + { + hitside += 3; + } + return hitside; +} + +#pragma warning (default : 4701) + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool SweepBoxToStudio( IPhysicsSurfaceProps *pProps, const Ray_t& ray, CStudioHdr *pStudioHdr, mstudiohitboxset_t *set, + matrix3x4_t **hitboxbones, int fContentsMask, trace_t &tr ) +{ + tr.fraction = 1.0; + tr.startsolid = false; + + // OPTIMIZE: Partition these? + Ray_t clippedRay = ray; + int hitbox = -1; + for ( int i = 0; i < set->numhitboxes; i++ ) + { + mstudiobbox_t *pbox = set->pHitbox(i); + + // Filter based on contents mask + int fBoneContents = pStudioHdr->pBone( pbox->bone )->contents; + if ( ( fBoneContents & fContentsMask ) == 0 ) + continue; + + //FIXME: Won't work with scaling! + trace_t obbTrace; + if ( IntersectRayWithOBB( clippedRay, *hitboxbones[pbox->bone], pbox->bbmin, pbox->bbmax, 0.0f, &obbTrace ) ) + { + tr.startpos = obbTrace.startpos; + tr.endpos = obbTrace.endpos; + tr.plane = obbTrace.plane; + tr.startsolid = obbTrace.startsolid; + tr.allsolid = obbTrace.allsolid; + + // This logic here is to shorten the ray each time to get more early outs + tr.fraction *= obbTrace.fraction; + clippedRay.m_Delta *= obbTrace.fraction; + hitbox = i; + if (tr.startsolid) + break; + } + } + + if ( hitbox >= 0 ) + { + tr.hitgroup = set->pHitbox(hitbox)->group; + tr.hitbox = hitbox; + const mstudiobone_t *pBone = pStudioHdr->pBone( set->pHitbox(hitbox)->bone ); + tr.contents = pBone->contents | CONTENTS_HITBOX; + tr.physicsbone = pBone->physicsbone; + tr.surface.name = "**studio**"; + tr.surface.flags = SURF_HITBOX; + tr.surface.surfaceProps = pProps->GetSurfaceIndex( pBone->pszSurfaceProp() ); + + Assert( tr.physicsbone >= 0 ); + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool TraceToStudio( IPhysicsSurfaceProps *pProps, const Ray_t& ray, CStudioHdr *pStudioHdr, mstudiohitboxset_t *set, + matrix3x4_t **hitboxbones, int fContentsMask, const Vector &vecOrigin, float flScale, trace_t &tr ) +{ + if ( !ray.m_IsRay ) + { + return SweepBoxToStudio( pProps, ray, pStudioHdr, set, hitboxbones, fContentsMask, tr ); + } + + tr.fraction = 1.0; + tr.startsolid = false; + + // no hit yet + int hitbox = -1; + int hitside = -1; + + // OPTIMIZE: Partition these? + for ( int i = 0; i < set->numhitboxes; i++ ) + { + mstudiobbox_t *pbox = set->pHitbox(i); + + // Filter based on contents mask + int fBoneContents = pStudioHdr->pBone( pbox->bone )->contents; + if ( ( fBoneContents & fContentsMask ) == 0 ) + continue; + + // columns are axes of the bones in world space, translation is in world space + matrix3x4_t& matrix = *hitboxbones[pbox->bone]; + + // Because we're sending in a matrix with scale data, and because the matrix inversion in the hitbox + // code does not handle that case, we pre-scale the bones and ray down here and do our collision checks + // in unscaled space. We can then rescale the results afterwards. + + int side = -1; + if ( flScale < 1.0f-FLT_EPSILON || flScale > 1.0f+FLT_EPSILON ) + { + matrix3x4_t matScaled; + MatrixCopy( matrix, matScaled ); + + float invScale = 1.0f / flScale; + + Vector vecBoneOrigin; + MatrixGetColumn( matScaled, 3, vecBoneOrigin ); + + // Pre-scale the origin down + Vector vecNewOrigin = vecBoneOrigin - vecOrigin; + vecNewOrigin *= invScale; + vecNewOrigin += vecOrigin; + MatrixSetColumn( vecNewOrigin, 3, matScaled ); + + // Scale it uniformly + VectorScale( matScaled[0], invScale, matScaled[0] ); + VectorScale( matScaled[1], invScale, matScaled[1] ); + VectorScale( matScaled[2], invScale, matScaled[2] ); + + // Pre-scale our ray as well + Vector vecRayStart = ray.m_Start - vecOrigin; + vecRayStart *= invScale; + vecRayStart += vecOrigin; + + Vector vecRayDelta = ray.m_Delta * invScale; + + Ray_t newRay; + newRay.Init( vecRayStart, vecRayStart + vecRayDelta ); + + side = ClipRayToHitbox( newRay, pbox, matScaled, tr ); + } + else + { + side = ClipRayToHitbox( ray, pbox, matrix, tr ); + } + + if ( side >= 0 ) + { + hitbox = i; + hitside = side; + } + } + + if ( hitbox >= 0 ) + { + mstudiobbox_t *pbox = set->pHitbox(hitbox); + VectorMA( ray.m_Start, tr.fraction, ray.m_Delta, tr.endpos ); + tr.hitgroup = set->pHitbox(hitbox)->group; + tr.hitbox = hitbox; + const mstudiobone_t *pBone = pStudioHdr->pBone( pbox->bone ); + tr.contents = pBone->contents | CONTENTS_HITBOX; + tr.physicsbone = pBone->physicsbone; + tr.surface.name = "**studio**"; + tr.surface.flags = SURF_HITBOX; + tr.surface.surfaceProps = pProps->GetSurfaceIndex( pBone->pszSurfaceProp() ); + + Assert( tr.physicsbone >= 0 ); + matrix3x4_t& matrix = *hitboxbones[pbox->bone]; + if ( hitside >= 3 ) + { + hitside -= 3; + tr.plane.normal[0] = matrix[0][hitside]; + tr.plane.normal[1] = matrix[1][hitside]; + tr.plane.normal[2] = matrix[2][hitside]; + //tr.plane.dist = DotProduct( tr.plane.normal, Vector(matrix[0][3], matrix[1][3], matrix[2][3] ) ) + pbox->bbmax[hitside]; + } + else + { + tr.plane.normal[0] = -matrix[0][hitside]; + tr.plane.normal[1] = -matrix[1][hitside]; + tr.plane.normal[2] = -matrix[2][hitside]; + //tr.plane.dist = DotProduct( tr.plane.normal, Vector(matrix[0][3], matrix[1][3], matrix[2][3] ) ) - pbox->bbmin[hitside]; + } + // simpler plane constant equation + tr.plane.dist = DotProduct( tr.endpos, tr.plane.normal ); + tr.plane.type = 3; + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns array of animations and weightings for a sequence based on current pose parameters +//----------------------------------------------------------------------------- + +void Studio_SeqAnims( const CStudioHdr *pStudioHdr, mstudioseqdesc_t &seqdesc, int iSequence, const float poseParameter[], mstudioanimdesc_t *panim[4], float *weight ) +{ +#if _DEBUG + VPROF_INCREMENT_COUNTER("SEQ_ANIMS",1); +#endif + if (!pStudioHdr || iSequence >= pStudioHdr->GetNumSeq()) + { + weight[0] = weight[1] = weight[2] = weight[3] = 0.0; + return; + } + + int i0 = 0, i1 = 0; + float s0 = 0, s1 = 0; + + Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, iSequence, 0, s0, i0 ); + Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, iSequence, 1, s1, i1 ); + + panim[0] = &((CStudioHdr *)pStudioHdr)->pAnimdesc( pStudioHdr->iRelativeAnim( iSequence, seqdesc.anim( i0 , i1 ) ) ); + weight[0] = (1 - s0) * (1 - s1); + + panim[1] = &((CStudioHdr *)pStudioHdr)->pAnimdesc( pStudioHdr->iRelativeAnim( iSequence, seqdesc.anim( i0+1, i1 ) ) ); + weight[1] = (s0) * (1 - s1); + + panim[2] = &((CStudioHdr *)pStudioHdr)->pAnimdesc( pStudioHdr->iRelativeAnim( iSequence, seqdesc.anim( i0 , i1+1 ) ) ); + weight[2] = (1 - s0) * (s1); + + panim[3] = &((CStudioHdr *)pStudioHdr)->pAnimdesc( pStudioHdr->iRelativeAnim( iSequence, seqdesc.anim( i0+1, i1+1 ) ) ); + weight[3] = (s0) * (s1); + + Assert( weight[0] >= 0.0f && weight[1] >= 0.0f && weight[2] >= 0.0f && weight[3] >= 0.0f ); +} + +//----------------------------------------------------------------------------- +// Purpose: returns max frame number for a sequence +//----------------------------------------------------------------------------- + +int Studio_MaxFrame( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[] ) +{ + mstudioanimdesc_t *panim[4]; + float weight[4]; + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, poseParameter, panim, weight ); + + float maxFrame = 0; + for (int i = 0; i < 4; i++) + { + if (weight[i] > 0) + { + maxFrame += panim[i]->numframes * weight[i]; + } + } + + if ( maxFrame > 1 ) + maxFrame -= 1; + + + // FIXME: why does the weights sometimes not exactly add it 1.0 and this sometimes rounds down? + return (maxFrame + 0.01); +} + + +//----------------------------------------------------------------------------- +// Purpose: returns frames per second of a sequence +//----------------------------------------------------------------------------- + +float Studio_FPS( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[] ) +{ + mstudioanimdesc_t *panim[4]; + float weight[4]; + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, poseParameter, panim, weight ); + + float t = 0; + + for (int i = 0; i < 4; i++) + { + if (weight[i] > 0) + { + t += panim[i]->fps * weight[i]; + } + } + return t; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns cycles per second of a sequence (cycles/second) +//----------------------------------------------------------------------------- + +float Studio_CPS( const CStudioHdr *pStudioHdr, mstudioseqdesc_t &seqdesc, int iSequence, const float poseParameter[] ) +{ + mstudioanimdesc_t *panim[4]; + float weight[4]; + + Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, poseParameter, panim, weight ); + + float t = 0; + + for (int i = 0; i < 4; i++) + { + if (weight[i] > 0 && panim[i]->numframes > 1) + { + t += (panim[i]->fps / (panim[i]->numframes - 1)) * weight[i]; + } + } + return t; +} + +//----------------------------------------------------------------------------- +// Purpose: returns length (in seconds) of a sequence (seconds/cycle) +//----------------------------------------------------------------------------- + +float Studio_Duration( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[] ) +{ + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + float cps = Studio_CPS( pStudioHdr, seqdesc, iSequence, poseParameter ); + + if( cps == 0 ) + return 0.0f; + + return 1.0f/cps; +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate changes in position and angle relative to the start of an animations cycle +// Output: updated position and angle, relative to the origin +// returns false if animation is not a movement animation +//----------------------------------------------------------------------------- + +bool Studio_AnimPosition( mstudioanimdesc_t *panim, float flCycle, Vector &vecPos, QAngle &vecAngle ) +{ + float prevframe = 0; + vecPos.Init( ); + vecAngle.Init( ); + + if (panim->nummovements == 0) + return false; + + int iLoops = 0; + if (flCycle > 1.0) + { + iLoops = (int)flCycle; + } + else if (flCycle < 0.0) + { + iLoops = (int)flCycle - 1; + } + flCycle = flCycle - iLoops; + + float flFrame = flCycle * (panim->numframes - 1); + + for (int i = 0; i < panim->nummovements; i++) + { + mstudiomovement_t *pmove = panim->pMovement( i ); + + if (pmove->endframe >= flFrame) + { + float f = (flFrame - prevframe) / (pmove->endframe - prevframe); + + float d = pmove->v0 * f + 0.5 * (pmove->v1 - pmove->v0) * f * f; + + vecPos = vecPos + d * pmove->vector; + vecAngle.y = vecAngle.y * (1 - f) + pmove->angle * f; + if (iLoops != 0) + { + mstudiomovement_t *pmove = panim->pMovement( panim->nummovements - 1 ); + vecPos = vecPos + iLoops * pmove->position; + vecAngle.y = vecAngle.y + iLoops * pmove->angle; + } + return true; + } + else + { + prevframe = pmove->endframe; + vecPos = pmove->position; + vecAngle.y = pmove->angle; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate instantaneous velocity in ips at a given point +// in the animations cycle +// Output: velocity vector, relative to identity orientation +// returns false if animation is not a movement animation +//----------------------------------------------------------------------------- + +bool Studio_AnimVelocity( mstudioanimdesc_t *panim, float flCycle, Vector &vecVelocity ) +{ + float prevframe = 0; + + float flFrame = flCycle * (panim->numframes - 1); + flFrame = flFrame - (int)(flFrame / (panim->numframes - 1)); + + for (int i = 0; i < panim->nummovements; i++) + { + mstudiomovement_t *pmove = panim->pMovement( i ); + + if (pmove->endframe >= flFrame) + { + float f = (flFrame - prevframe) / (pmove->endframe - prevframe); + + float vel = pmove->v0 * (1 - f) + pmove->v1 * f; + // scale from per block to per sec velocity + vel = vel * panim->fps / (pmove->endframe - prevframe); + + vecVelocity = pmove->vector * vel; + return true; + } + else + { + prevframe = pmove->endframe; + } + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate changes in position and angle between two points in an animation cycle +// Output: updated position and angle, relative to CycleFrom being at the origin +// returns false if animation is not a movement animation +//----------------------------------------------------------------------------- + +bool Studio_AnimMovement( mstudioanimdesc_t *panim, float flCycleFrom, float flCycleTo, Vector &deltaPos, QAngle &deltaAngle ) +{ + if (panim->nummovements == 0) + return false; + + Vector startPos; + QAngle startA; + Studio_AnimPosition( panim, flCycleFrom, startPos, startA ); + + Vector endPos; + QAngle endA; + Studio_AnimPosition( panim, flCycleTo, endPos, endA ); + + Vector tmp = endPos - startPos; + deltaAngle.y = endA.y - startA.y; + VectorYawRotate( tmp, -startA.y, deltaPos ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: finds how much of an animation to play to move given linear distance +//----------------------------------------------------------------------------- + +float Studio_FindAnimDistance( mstudioanimdesc_t *panim, float flDist ) +{ + float prevframe = 0; + + if (flDist <= 0) + return 0.0; + + for (int i = 0; i < panim->nummovements; i++) + { + mstudiomovement_t *pmove = panim->pMovement( i ); + + float flMove = (pmove->v0 + pmove->v1) * 0.5; + + if (flMove >= flDist) + { + float root1, root2; + + // d = V0 * t + 1/2 (V1-V0) * t^2 + if (SolveQuadratic( 0.5 * (pmove->v1 - pmove->v0), pmove->v0, -flDist, root1, root2 )) + { + float cpf = 1.0 / (panim->numframes - 1); // cycles per frame + + return (prevframe + root1 * (pmove->endframe - prevframe)) * cpf; + } + return 0.0; + } + else + { + flDist -= flMove; + prevframe = pmove->endframe; + } + } + return 1.0; +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate changes in position and angle between two points in a sequences cycle +// Output: updated position and angle, relative to CycleFrom being at the origin +// returns false if sequence is not a movement sequence +//----------------------------------------------------------------------------- + +bool Studio_SeqMovement( const CStudioHdr *pStudioHdr, int iSequence, float flCycleFrom, float flCycleTo, const float poseParameter[], Vector &deltaPos, QAngle &deltaAngles ) +{ + mstudioanimdesc_t *panim[4]; + float weight[4]; + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + + Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, poseParameter, panim, weight ); + + deltaPos.Init( ); + deltaAngles.Init( ); + + bool found = false; + + for (int i = 0; i < 4; i++) + { + if (weight[i]) + { + Vector localPos; + QAngle localAngles; + + localPos.Init(); + localAngles.Init(); + + if (Studio_AnimMovement( panim[i], flCycleFrom, flCycleTo, localPos, localAngles )) + { + found = true; + deltaPos = deltaPos + localPos * weight[i]; + // FIXME: this makes no sense + deltaAngles = deltaAngles + localAngles * weight[i]; + } + else if (!(panim[i]->flags & STUDIO_DELTA) && panim[i]->nummovements == 0 && seqdesc.weight(0) > 0.0) + { + found = true; + } + } + } + return found; +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate instantaneous velocity in ips at a given point in the sequence's cycle +// Output: velocity vector, relative to identity orientation +// returns false if sequence is not a movement sequence +//----------------------------------------------------------------------------- + +bool Studio_SeqVelocity( const CStudioHdr *pStudioHdr, int iSequence, float flCycle, const float poseParameter[], Vector &vecVelocity ) +{ + mstudioanimdesc_t *panim[4]; + float weight[4]; + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, poseParameter, panim, weight ); + + vecVelocity.Init( ); + + bool found = false; + + for (int i = 0; i < 4; i++) + { + if (weight[i]) + { + Vector vecLocalVelocity; + + if (Studio_AnimVelocity( panim[i], flCycle, vecLocalVelocity )) + { + vecVelocity = vecVelocity + vecLocalVelocity * weight[i]; + found = true; + } + } + } + return found; +} + +//----------------------------------------------------------------------------- +// Purpose: finds how much of an sequence to play to move given linear distance +//----------------------------------------------------------------------------- + +float Studio_FindSeqDistance( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[], float flDist ) +{ + mstudioanimdesc_t *panim[4]; + float weight[4]; + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, poseParameter, panim, weight ); + + float flCycle = 0; + + for (int i = 0; i < 4; i++) + { + if (weight[i]) + { + float flLocalCycle = Studio_FindAnimDistance( panim[i], flDist ); + flCycle = flCycle + flLocalCycle * weight[i]; + } + } + return flCycle; +} + +//----------------------------------------------------------------------------- +// Purpose: lookup attachment by name +//----------------------------------------------------------------------------- + +int Studio_FindAttachment( const CStudioHdr *pStudioHdr, const char *pAttachmentName ) +{ + if ( pStudioHdr && pStudioHdr->SequencesAvailable() ) + { + // Extract the bone index from the name + for (int i = 0; i < pStudioHdr->GetNumAttachments(); i++) + { + if (!V_stricmp(pAttachmentName,((CStudioHdr *)pStudioHdr)->pAttachment(i).pszName( ))) + { + return i; + } + } + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: lookup attachments by substring. Randomly return one of the matching attachments. +//----------------------------------------------------------------------------- + +int Studio_FindRandomAttachment( const CStudioHdr *pStudioHdr, const char *pAttachmentName ) +{ + if ( pStudioHdr ) + { + // First move them all matching attachments into a list + CUtlVector matchingAttachments; + + // Extract the bone index from the name + for (int i = 0; i < pStudioHdr->GetNumAttachments(); i++) + { + if ( strstr( ((CStudioHdr *)pStudioHdr)->pAttachment(i).pszName(), pAttachmentName ) ) + { + matchingAttachments.AddToTail(i); + } + } + + // Then randomly return one of the attachments + if ( matchingAttachments.Size() > 0 ) + return matchingAttachments[ RandomInt( 0, matchingAttachments.Size()-1 ) ]; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: lookup bone by name +//----------------------------------------------------------------------------- + +int Studio_BoneIndexByName( const CStudioHdr *pStudioHdr, const char *pName ) +{ + if ( pStudioHdr ) + { + // binary search for the bone matching pName + int start = 0, end = pStudioHdr->numbones()-1; + const byte *pBoneTable = pStudioHdr->GetBoneTableSortedByName(); + mstudiobone_t *pbones = pStudioHdr->pBone( 0 ); + while (start <= end) + { + int mid = (start + end) >> 1; + int cmp = Q_stricmp( pbones[pBoneTable[mid]].pszName(), pName ); + + if ( cmp < 0 ) + { + start = mid + 1; + } + else if ( cmp > 0 ) + { + end = mid - 1; + } + else + { + return pBoneTable[mid]; + } + } + } + + return -1; +} + +const char *Studio_GetDefaultSurfaceProps( CStudioHdr *pstudiohdr ) +{ + return pstudiohdr->pszSurfaceProp(); +} + +float Studio_GetMass( CStudioHdr *pstudiohdr ) +{ + return pstudiohdr->mass(); +} + +//----------------------------------------------------------------------------- +// Purpose: return pointer to sequence key value buffer +//----------------------------------------------------------------------------- + +const char *Studio_GetKeyValueText( const CStudioHdr *pStudioHdr, int iSequence ) +{ + if (pStudioHdr && pStudioHdr->SequencesAvailable()) + { + if (iSequence >= 0 && iSequence < pStudioHdr->GetNumSeq()) + { + return ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ).KeyValueText(); + } + } + return NULL; +} + +bool Studio_PrefetchSequence( const CStudioHdr *pStudioHdr, int iSequence ) +{ + bool pendingload = false; + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( iSequence ); + int size0 = seqdesc.groupsize[ 0 ]; + int size1 = seqdesc.groupsize[ 1 ]; + for ( int i = 0; i < size0; ++i ) + { + for ( int j = 0; j < size1; ++j ) + { + mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( seqdesc.anim( i, j ) ); + int iFrame = 0; + mstudioanim_t *panim = animdesc.pAnim( &iFrame ); + if ( !panim ) + { + pendingload = true; + } + } + } + + // Everything for this sequence is resident? + return !pendingload; +} + + +//----------------------------------------------------------------------------- +// Purpose: Drive a flex controller from a component of a bone +//----------------------------------------------------------------------------- +void Studio_RunBoneFlexDrivers( float *pflFlexControllerWeights, const CStudioHdr *pStudioHdr, const Vector *pvPositions, const matrix3x4_t *pBoneToWorld, const matrix3x4_t &mRootToWorld ) +{ + bool bRootToWorldInvComputed = false; + matrix3x4_t mRootToWorldInv; + matrix3x4_t mParentInv; + matrix3x4_t mBoneLocal; + + const int nBoneFlexDriverCount = pStudioHdr->BoneFlexDriverCount(); + + for ( int i = 0; i < nBoneFlexDriverCount; ++i ) + { + const mstudioboneflexdriver_t *pBoneFlexDriver = pStudioHdr->BoneFlexDriver( i ); + const mstudiobone_t *pStudioBone = pStudioHdr->pBone( pBoneFlexDriver->m_nBoneIndex ); + + const int nControllerCount = pBoneFlexDriver->m_nControlCount; + + if ( pStudioBone->flags & BONE_USED_BY_BONE_MERGE ) + { + // The local space version of the bone is not available if this is a bonemerged bone + // so do the slow computation of the local version of the bone from boneToWorld + + if ( pStudioBone->parent < 0 ) + { + if ( !bRootToWorldInvComputed ) + { + MatrixInvert( mRootToWorld, mRootToWorldInv ); + bRootToWorldInvComputed = true; + } + + MatrixMultiply( mRootToWorldInv, pBoneToWorld[ pBoneFlexDriver->m_nBoneIndex ], mBoneLocal ); + } + else + { + MatrixInvert( pBoneToWorld[ pStudioBone->parent ], mParentInv ); + MatrixMultiply( mParentInv, pBoneToWorld[ pBoneFlexDriver->m_nBoneIndex ], mBoneLocal ); + } + + for ( int j = 0; j < nControllerCount; ++j ) + { + const mstudioboneflexdrivercontrol_t *pController = pBoneFlexDriver->pBoneFlexDriverControl( j ); + const mstudioflexcontroller_t *pFlexController = pStudioHdr->pFlexcontroller( static_cast< LocalFlexController_t >( pController->m_nFlexControllerIndex ) ); + + if ( pFlexController->localToGlobal < 0 ) + continue; + + Assert( pController->m_nFlexControllerIndex >= 0 && pController->m_nFlexControllerIndex < pStudioHdr->numflexcontrollers() ); + Assert( pController->m_nBoneComponent >= 0 && pController->m_nBoneComponent <= 2 ); + pflFlexControllerWeights[pFlexController->localToGlobal] = + RemapValClamped( mBoneLocal[pController->m_nBoneComponent][3], pController->m_flMin, pController->m_flMax, 0.0f, 1.0f ); + } + } + else + { + // Use the local space version of the bone directly for non-bonemerged bones + + const Vector &position = pvPositions[ pBoneFlexDriver->m_nBoneIndex ]; + + for ( int j = 0; j < nControllerCount; ++j ) + { + const mstudioboneflexdrivercontrol_t *pController = pBoneFlexDriver->pBoneFlexDriverControl( j ); + const mstudioflexcontroller_t *pFlexController = pStudioHdr->pFlexcontroller( static_cast< LocalFlexController_t >( pController->m_nFlexControllerIndex ) ); + + if ( pFlexController->localToGlobal < 0 ) + continue; + + Assert( pController->m_nFlexControllerIndex >= 0 && pController->m_nFlexControllerIndex < pStudioHdr->numflexcontrollers() ); + Assert( pController->m_nBoneComponent >= 0 && pController->m_nBoneComponent <= 2 ); + pflFlexControllerWeights[pFlexController->localToGlobal] = + RemapValClamped( position[pController->m_nBoneComponent], pController->m_flMin, pController->m_flMax, 0.0f, 1.0f ); + } + } + } +} diff --git a/public/bone_setup.h b/public/bone_setup.h new file mode 100644 index 0000000..76f00a6 --- /dev/null +++ b/public/bone_setup.h @@ -0,0 +1,449 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BONE_SETUP_H +#define BONE_SETUP_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "studio.h" +#include "cmodel.h" +#include "bitvec.h" + + +class CBoneToWorld; +class CIKContext; +class CBoneAccessor; +class IPoseDebugger; + + +// This provides access to networked arrays, so if this code actually changes a value, +// the entity is marked as changed. +abstract_class IParameterAccess +{ +public: + virtual float GetParameter( int iParam ) = 0; + virtual void SetParameter( int iParam, float flValue ) = 0; +}; + + + +class CBoneBitList : public CBitVec +{ +public: + inline void MarkBone(int iBone) + { + Set(iBone); + } + inline bool IsBoneMarked(int iBone) + { + return Get(iBone) != 0 ? true : false; + } +}; + +class CBoneSetup; +class IBoneSetup +{ +public: + IBoneSetup( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], IPoseDebugger *pPoseDebugger = NULL ); + ~IBoneSetup( void ); + void InitPose( Vector pos[], Quaternion[] ); + void AccumulatePose( Vector pos[], Quaternion q[], int sequence, float cycle, float flWeight, float flTime, CIKContext *pIKContext ); + void CalcAutoplaySequences( Vector pos[], Quaternion q[], float flRealTime, CIKContext *pIKContext ); + void CalcBoneAdj( Vector pos[], Quaternion q[], const float controllers[] ); + CStudioHdr *GetStudioHdr(); +private: + CBoneSetup *m_pBoneSetup; +}; + +//----------------------------------------------------------------------------- +// Purpose: blends together all the bones from two p:q lists +// +// p1 = p1 * (1 - s) + p2 * s +// q1 = q1 * (1 - s) + q2 * s +//----------------------------------------------------------------------------- +void SlerpBones( + const CStudioHdr *pStudioHdr, + Quaternion q1[MAXSTUDIOBONES], + Vector pos1[MAXSTUDIOBONES], + mstudioseqdesc_t &seqdesc, // source of q2 and pos2 + int sequence, + const Quaternion q2[MAXSTUDIOBONES], + const Vector pos2[MAXSTUDIOBONES], + float s, + int boneMask + ); + +// Given two samples of a bone separated in time by dt, +// compute the velocity and angular velocity of that bone +void CalcBoneDerivatives( Vector &velocity, AngularImpulse &angVel, const matrix3x4_t &prev, const matrix3x4_t ¤t, float dt ); +// Give a derivative of a bone, compute the velocity & angular velocity of that bone +void CalcBoneVelocityFromDerivative( const QAngle &vecAngles, Vector &velocity, AngularImpulse &angVel, const matrix3x4_t ¤t ); + +// This function sets up the local transform for a single frame of animation. It doesn't handle +// pose parameters or interpolation between frames. +void SetupSingleBoneMatrix( + CStudioHdr *pOwnerHdr, + int nSequence, + int iFrame, + int iBone, + matrix3x4_t &mBoneLocal ); + + +// Purpose: build boneToWorld transforms for a specific bone +void BuildBoneChain( + const CStudioHdr *pStudioHdr, + const matrix3x4_t &rootxform, + const Vector pos[], + const Quaternion q[], + int iBone, + matrix3x4_t *pBoneToWorld ); + +void BuildBoneChain( + const CStudioHdr *pStudioHdr, + const matrix3x4_t &rootxform, + const Vector pos[], + const Quaternion q[], + int iBone, + matrix3x4_t *pBoneToWorld, + CBoneBitList &boneComputed ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +// ik info +class CIKTarget +{ +public: + void SetOwner( int entindex, const Vector &pos, const QAngle &angles ); + void ClearOwner( void ); + int GetOwner( void ); + void UpdateOwner( int entindex, const Vector &pos, const QAngle &angles ); + void SetPos( const Vector &pos ); + void SetAngles( const QAngle &angles ); + void SetQuaternion( const Quaternion &q ); + void SetNormal( const Vector &normal ); + void SetPosWithNormalOffset( const Vector &pos, const Vector &normal ); + void SetOnWorld( bool bOnWorld = true ); + + bool IsActive( void ); + void IKFailed( void ); + int chain; + int type; + void MoveReferenceFrame( Vector &deltaPos, QAngle &deltaAngles ); + // accumulated offset from ideal footplant location +public: + struct x2 { + char *pAttachmentName; + Vector pos; + Quaternion q; + } offset; +private: + struct x3 { + Vector pos; + Quaternion q; + } ideal; +public: + struct x4 { + float latched; + float release; + float height; + float floor; + float radius; + float flTime; + float flWeight; + Vector pos; + Quaternion q; + bool onWorld; + } est; // estimate contact position + struct x5 { + float hipToFoot; // distance from hip + float hipToKnee; // distance from hip to knee + float kneeToFoot; // distance from knee to foot + Vector hip; // location of hip + Vector closest; // closest valid location from hip to foot that the foot can move to + Vector knee; // pre-ik location of knee + Vector farthest; // farthest valid location from hip to foot that the foot can move to + Vector lowest; // lowest position directly below hip that the foot can drop to + } trace; +private: + // internally latched footset, position + struct x1 { + // matrix3x4_t worldTarget; + bool bNeedsLatch; + bool bHasLatch; + float influence; + int iFramecounter; + int owner; + Vector absOrigin; + QAngle absAngles; + Vector pos; + Quaternion q; + Vector deltaPos; // acculated error + Quaternion deltaQ; + Vector debouncePos; + Quaternion debounceQ; + } latched; + struct x6 { + float flTime; // time last error was detected + float flErrorTime; + float ramp; + bool bInError; + } error; + + friend class CIKContext; +}; + + +struct ikchainresult_t +{ + // accumulated offset from ideal footplant location + int target; + Vector pos; + Quaternion q; + float flWeight; +}; + + + +struct ikcontextikrule_t +{ + int index; + + int type; + int chain; + + int bone; + + int slot; // iktarget slot. Usually same as chain. + float height; + float radius; + float floor; + Vector pos; + Quaternion q; + + float start; // beginning of influence + float peak; // start of full influence + float tail; // end of full influence + float end; // end of all influence + + float top; + float drop; + + float commit; // frame footstep target should be committed + float release; // frame ankle should end rotation from latched orientation + + float flWeight; // processed version of start-end cycle + float flRuleWeight; // blending weight + float latched; // does the IK rule use a latched value? + char *szLabel; + + Vector kneeDir; + Vector kneePos; + + ikcontextikrule_t() {} + +private: + // No copy constructors allowed + ikcontextikrule_t(const ikcontextikrule_t& vOther); +}; + + +void Studio_AlignIKMatrix( matrix3x4_t &mMat, const Vector &vAlignTo ); + +bool Studio_SolveIK( int iThigh, int iKnee, int iFoot, Vector &targetFoot, matrix3x4_t* pBoneToWorld ); + +bool Studio_SolveIK( int iThigh, int iKnee, int iFoot, Vector &targetFoot, Vector &targetKneePos, Vector &targetKneeDir, matrix3x4_t* pBoneToWorld ); + + + +class CIKContext +{ +public: + CIKContext( ); + void Init( const CStudioHdr *pStudioHdr, const QAngle &angles, const Vector &pos, float flTime, int iFramecounter, int boneMask ); + void AddDependencies( mstudioseqdesc_t &seqdesc, int iSequence, float flCycle, const float poseParameters[], float flWeight = 1.0f ); + + void ClearTargets( void ); + void UpdateTargets( Vector pos[], Quaternion q[], matrix3x4_t boneToWorld[], CBoneBitList &boneComputed ); + void AutoIKRelease( void ); + void SolveDependencies( Vector pos[], Quaternion q[], matrix3x4_t boneToWorld[], CBoneBitList &boneComputed ); + + void AddAutoplayLocks( Vector pos[], Quaternion q[] ); + void SolveAutoplayLocks( Vector pos[], Quaternion q[] ); + + void AddSequenceLocks( mstudioseqdesc_t &SeqDesc, Vector pos[], Quaternion q[] ); + void SolveSequenceLocks( mstudioseqdesc_t &SeqDesc, Vector pos[], Quaternion q[] ); + + void AddAllLocks( Vector pos[], Quaternion q[] ); + void SolveAllLocks( Vector pos[], Quaternion q[] ); + + void SolveLock( const mstudioiklock_t *plock, int i, Vector pos[], Quaternion q[], matrix3x4_t boneToWorld[], CBoneBitList &boneComputed ); + + CUtlVectorFixed< CIKTarget, 12 > m_target; + +private: + + CStudioHdr const *m_pStudioHdr; + + bool Estimate( int iSequence, float flCycle, int iTarget, const float poseParameter[], float flWeight = 1.0f ); + void BuildBoneChain( const Vector pos[], const Quaternion q[], int iBone, matrix3x4_t *pBoneToWorld, CBoneBitList &boneComputed ); + + // virtual IK rules, filtered and combined from each sequence + CUtlVector< CUtlVector< ikcontextikrule_t > > m_ikChainRule; + CUtlVector< ikcontextikrule_t > m_ikLock; + matrix3x4_t m_rootxform; + + int m_iFramecounter; + float m_flTime; + int m_boneMask; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +// replaces the bonetoworld transforms for all bones that are procedural +bool CalcProceduralBone( + const CStudioHdr *pStudioHdr, + int iBone, + CBoneAccessor &bonetoworld + ); + +void Studio_BuildMatrices( + const CStudioHdr *pStudioHdr, + const QAngle& angles, + const Vector& origin, + const Vector pos[], + const Quaternion q[], + int iBone, + float flScale, + matrix3x4_t bonetoworld[MAXSTUDIOBONES], + int boneMask + ); + + +// Get a bone->bone relative transform +void Studio_CalcBoneToBoneTransform( const CStudioHdr *pStudioHdr, int inputBoneIndex, int outputBoneIndex, matrix3x4_t &matrixOut ); + +// Given a bone rotation value, figures out the value you need to give to the controller +// to have the bone at that value. +// [in] flValue = the desired bone rotation value +// [out] ctlValue = the (0-1) value to set the controller t. +// return value = flValue, unwrapped to lie between the controller's start and end. +float Studio_SetController( const CStudioHdr *pStudioHdr, int iController, float flValue, float &ctlValue ); + + +// Given a 0-1 controller value, maps it into the controller's start and end and returns the bone rotation angle. +// [in] ctlValue = value in controller space (0-1). +// return value = value in bone space +float Studio_GetController( const CStudioHdr *pStudioHdr, int iController, float ctlValue ); + +void Studio_CalcDefaultPoseParameters( const CStudioHdr *pStudioHdr, float flPoseParameter[MAXSTUDIOPOSEPARAM], int nCount ); +float Studio_GetPoseParameter( const CStudioHdr *pStudioHdr, int iParameter, float ctlValue ); +float Studio_SetPoseParameter( const CStudioHdr *pStudioHdr, int iParameter, float flValue, float &ctlValue ); + +// converts a global 0..1 pose parameter into the local sequences blending value +void Studio_LocalPoseParameter( const CStudioHdr *pStudioHdr, const float poseParameter[], mstudioseqdesc_t &seqdesc, int iSequence, int iLocalIndex, float &flSetting, int &index ); + +void Studio_SeqAnims( const CStudioHdr *pStudioHdr, mstudioseqdesc_t &seqdesc, int iSequence, const float poseParameter[], mstudioanimdesc_t *panim[4], float *weight ); +int Studio_MaxFrame( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[] ); +float Studio_FPS( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[] ); +float Studio_CPS( const CStudioHdr *pStudioHdr, mstudioseqdesc_t &seqdesc, int iSequence, const float poseParameter[] ); +float Studio_Duration( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[] ); +void Studio_MovementRate( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[], Vector *pVec ); + +// void Studio_Movement( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[], Vector *pVec ); + +//void Studio_AnimPosition( mstudioanimdesc_t *panim, float flCycle, Vector &vecPos, Vector &vecAngle ); +//void Studio_AnimVelocity( mstudioanimdesc_t *panim, float flCycle, Vector &vecVelocity ); +//float Studio_FindAnimDistance( mstudioanimdesc_t *panim, float flDist ); +bool Studio_AnimMovement( mstudioanimdesc_t *panim, float flCycleFrom, float flCycleTo, Vector &deltaPos, QAngle &deltaAngle ); +bool Studio_SeqMovement( const CStudioHdr *pStudioHdr, int iSequence, float flCycleFrom, float flCycleTo, const float poseParameter[], Vector &deltaMovement, QAngle &deltaAngle ); +bool Studio_SeqVelocity( const CStudioHdr *pStudioHdr, int iSequence, float flCycle, const float poseParameter[], Vector &vecVelocity ); +float Studio_FindSeqDistance( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[], float flDist ); +float Studio_FindSeqVelocity( const CStudioHdr *pStudioHdr, int iSequence, const float poseParameter[], float flVelocity ); +int Studio_FindAttachment( const CStudioHdr *pStudioHdr, const char *pAttachmentName ); +int Studio_FindRandomAttachment( const CStudioHdr *pStudioHdr, const char *pAttachmentName ); +int Studio_BoneIndexByName( const CStudioHdr *pStudioHdr, const char *pName ); +const char *Studio_GetDefaultSurfaceProps( CStudioHdr *pstudiohdr ); +float Studio_GetMass( CStudioHdr *pstudiohdr ); +const char *Studio_GetKeyValueText( const CStudioHdr *pStudioHdr, int iSequence ); + +FORWARD_DECLARE_HANDLE( memhandle_t ); +struct bonecacheparams_t +{ + CStudioHdr *pStudioHdr; + matrix3x4_t *pBoneToWorld; + float curtime; + int boneMask; +}; + +class CBoneCache +{ +public: + + // you must implement these static functions for the ResourceManager + // ----------------------------------------------------------- + static CBoneCache *CreateResource( const bonecacheparams_t ¶ms ); + static unsigned int EstimatedSize( const bonecacheparams_t ¶ms ); + // ----------------------------------------------------------- + // member functions that must be present for the ResourceManager + void DestroyResource(); + CBoneCache *GetData() { return this; } + unsigned int Size() { return m_size; } + // ----------------------------------------------------------- + + CBoneCache(); + + // was constructor, but placement new is messy wrt memdebug - so cast & init instead + void Init( const bonecacheparams_t ¶ms, unsigned int size, short *pStudioToCached, short *pCachedToStudio, int cachedBoneCount ); + + void UpdateBones( const matrix3x4_t *pBoneToWorld, int numbones, float curtime ); + matrix3x4_t *GetCachedBone( int studioIndex ); + void ReadCachedBones( matrix3x4_t *pBoneToWorld ); + void ReadCachedBonePointers( matrix3x4_t **bones, int numbones ); + + bool IsValid( float curtime, float dt = 0.1f ); + +public: + float m_timeValid; + int m_boneMask; + +private: + matrix3x4_t *BoneArray(); + short *StudioToCached(); + short *CachedToStudio(); + + unsigned int m_size; + unsigned short m_cachedBoneCount; + unsigned short m_matrixOffset; + unsigned short m_cachedToStudioOffset; + unsigned short m_boneOutOffset; +}; + +CBoneCache *Studio_GetBoneCache( memhandle_t cacheHandle ); +memhandle_t Studio_CreateBoneCache( bonecacheparams_t ¶ms ); +void Studio_DestroyBoneCache( memhandle_t cacheHandle ); +void Studio_InvalidateBoneCache( memhandle_t cacheHandle ); + +// Given a ray, trace for an intersection with this studiomodel. Get the array of bones from StudioSetupHitboxBones +bool TraceToStudio( class IPhysicsSurfaceProps *pProps, const Ray_t& ray, CStudioHdr *pStudioHdr, mstudiohitboxset_t *set, matrix3x4_t **hitboxbones, int fContentsMask, const Vector &vecOrigin, float flScale, trace_t &trace ); + +void QuaternionSM( float s, const Quaternion &p, const Quaternion &q, Quaternion &qt ); +void QuaternionMA( const Quaternion &p, float s, const Quaternion &q, Quaternion &qt ); + +bool Studio_PrefetchSequence( const CStudioHdr *pStudioHdr, int iSequence ); + +void Studio_RunBoneFlexDrivers( float *pFlexController, const CStudioHdr *pStudioHdr, const Vector *pPositions, const matrix3x4_t *pBoneToWorld, const matrix3x4_t &mRootToWorld ); + +#endif // BONE_SETUP_H diff --git a/public/bspfile.h b/public/bspfile.h new file mode 100644 index 0000000..d4c3a05 --- /dev/null +++ b/public/bspfile.h @@ -0,0 +1,1156 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines and structures for the BSP file format. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BSPFILE_H +#define BSPFILE_H +#pragma once + +#ifndef MATHLIB_H +#include "mathlib/mathlib.h" +#endif + +#include "datamap.h" +#include "mathlib/bumpvects.h" +#include "mathlib/compressed_light_cube.h" + +// little-endian "VBSP" +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'V') + +// MINBSPVERSION is the minimum acceptable version. The engine will load MINBSPVERSION through BSPVERSION +#define MINBSPVERSION 19 +#define BSPVERSION 20 + + +// This needs to match the value in gl_lightmap.h +// Need to dynamically allocate the weights and light values in radial_t to make this variable. +#define MAX_BRUSH_LIGHTMAP_DIM_WITHOUT_BORDER 32 +// This is one more than what vbsp cuts for to allow for rounding errors +#define MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER 35 + +// We can have larger lightmaps on displacements +#define MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER 125 +#define MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER 128 + + +// This is the actual max.. (change if you change the brush lightmap dim or disp lightmap dim +#define MAX_LIGHTMAP_DIM_WITHOUT_BORDER MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER +#define MAX_LIGHTMAP_DIM_INCLUDING_BORDER MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER + +#define MAX_LIGHTSTYLES 64 + + +// upper design bounds +#define MIN_MAP_DISP_POWER 2 // Minimum and maximum power a displacement can be. +#define MAX_MAP_DISP_POWER 4 + +// Max # of neighboring displacement touching a displacement's corner. +#define MAX_DISP_CORNER_NEIGHBORS 4 + +#define NUM_DISP_POWER_VERTS(power) ( ((1 << (power)) + 1) * ((1 << (power)) + 1) ) +#define NUM_DISP_POWER_TRIS(power) ( (1 << (power)) * (1 << (power)) * 2 ) + +#if !defined( BSP_USE_LESS_MEMORY ) +// Common limits +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 8192 +#define MAX_MAP_TEXINFO 12288 +#define MAX_MAP_TEXDATA 2048 +#define MAX_MAP_DISPINFO 2048 +#define MAX_MAP_DISP_VERTS ( MAX_MAP_DISPINFO * ((1< x --------------> 2 +// +// ^ ^ +// | | +// | | +// M2C | | M2C +// | | +// | | +// +// x x x +// +// ^ ^ +// | | +// | | +// C2M | | C2M +// | | +// | | +// +// 0 --------------> x --------------> 3 +// +// C2M M2C +// +// +// The CHILDNODE_ defines can be used to refer to a node's child nodes (this is for when you're +// recursing into the node tree inside a displacement): +// +// --------- +// | | | +// | 1 | 0 | +// | | | +// |---x---| +// | | | +// | 2 | 3 | +// | | | +// --------- +// +// ------------------------------------------------------------------------------------------------ // + +// These can be used to index g_ChildNodeIndexMul. +enum +{ + CHILDNODE_UPPER_RIGHT=0, + CHILDNODE_UPPER_LEFT=1, + CHILDNODE_LOWER_LEFT=2, + CHILDNODE_LOWER_RIGHT=3 +}; + + +// Corner indices. Used to index m_CornerNeighbors. +enum +{ + CORNER_LOWER_LEFT=0, + CORNER_UPPER_LEFT=1, + CORNER_UPPER_RIGHT=2, + CORNER_LOWER_RIGHT=3 +}; + + +// These edge indices must match the edge indices of the CCoreDispSurface. +enum +{ + NEIGHBOREDGE_LEFT=0, + NEIGHBOREDGE_TOP=1, + NEIGHBOREDGE_RIGHT=2, + NEIGHBOREDGE_BOTTOM=3 +}; + + +// These denote where one dispinfo fits on another. +// Note: tables are generated based on these indices so make sure to update +// them if these indices are changed. +typedef enum +{ + CORNER_TO_CORNER=0, + CORNER_TO_MIDPOINT=1, + MIDPOINT_TO_CORNER=2 +} NeighborSpan; + + +// These define relative orientations of displacement neighbors. +typedef enum +{ + ORIENTATION_CCW_0=0, + ORIENTATION_CCW_90=1, + ORIENTATION_CCW_180=2, + ORIENTATION_CCW_270=3 +} NeighborOrientation; + + +//============================================================================= + +enum +{ + 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, // CDispVerts + LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS = 34, // For each displacement + // For each lightmap sample + // byte for index + // if 255, then index = next byte + 255 + // 3 bytes for barycentric coordinates + // The game lump is a method of adding game-specific lumps + // FIXME: Eventually, all lumps could use the game lump system + LUMP_GAME_LUMP = 35, + LUMP_LEAFWATERDATA = 36, + LUMP_PRIMITIVES = 37, + LUMP_PRIMVERTS = 38, + LUMP_PRIMINDICES = 39, + // A pak file can be embedded in a .bsp now, and the file system will search the pak + // file first for any referenced names, before deferring to the game directory + // file system/pak files and finally the base directory file system/pak files. + LUMP_PAKFILE = 40, + LUMP_CLIPPORTALVERTS = 41, + // A map can have a number of cubemap entities in it which cause cubemap renders + // to be taken after running vrad. + 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, // deprecated. We no longer use win32-specific havok compression on terrain + LUMP_WATEROVERLAYS = 50, + LUMP_LEAF_AMBIENT_INDEX_HDR = 51, // index of LUMP_LEAF_AMBIENT_LIGHTING_HDR + LUMP_LEAF_AMBIENT_INDEX = 52, // index of LUMP_LEAF_AMBIENT_LIGHTING + + // optional lumps for HDR + LUMP_LIGHTING_HDR = 53, + LUMP_WORLDLIGHTS_HDR = 54, + LUMP_LEAF_AMBIENT_LIGHTING_HDR = 55, // NOTE: this data overrides part of the data stored in LUMP_LEAFS. + LUMP_LEAF_AMBIENT_LIGHTING = 56, // NOTE: this data overrides part of the data stored in LUMP_LEAFS. + + LUMP_XZIPPAKFILE = 57, // deprecated. xbox 1: xzip version of pak file + LUMP_FACES_HDR = 58, // HDR maps may have different face data. + LUMP_MAP_FLAGS = 59, // extended level-wide flags. not present in all levels + LUMP_OVERLAY_FADES = 60, // Fade distances for overlays +}; + + +// Lumps that have versions are listed here +enum +{ + LUMP_LIGHTING_VERSION = 1, + LUMP_FACES_VERSION = 1, + LUMP_OCCLUSION_VERSION = 2, + LUMP_LEAFS_VERSION = 1, + LUMP_LEAF_AMBIENT_LIGHTING_VERSION = 1, +}; + + +#define HEADER_LUMPS 64 + +#include "zip_uncompressed.h" + +struct lump_t +{ + DECLARE_BYTESWAP_DATADESC(); + int fileofs, filelen; + int version; // default to zero + // this field was char fourCC[4] previously, but was unused, favoring the LUMP IDs above instead. It has been + // repurposed for compression. 0 implies the lump is not compressed. + int uncompressedSize; // default to zero +}; + + +struct dheader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; + int mapRevision; // the map's revision (iteration, version) number (added BSPVERSION 6) +}; + +// level feature flags +#define LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_NONHDR 0x00000001 // was processed by vrad with -staticproplighting, no hdr data +#define LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_HDR 0x00000002 // was processed by vrad with -staticproplighting, in hdr + +struct dflagslump_t +{ + DECLARE_BYTESWAP_DATADESC(); + uint32 m_LevelFlags; // LVLFLAGS_xxx +}; + +struct lumpfileheader_t +{ + int lumpOffset; + int lumpID; + int lumpVersion; + int lumpLength; + int mapRevision; // the map's revision (iteration, version) number (added BSPVERSION 6) +}; + +struct dgamelumpheader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int lumpCount; + + // dgamelump_t follow this +}; + +// This is expected to be a four-CC code ('lump') +typedef int GameLumpId_t; + +// game lump is compressed, filelen reflects original size +// use next entry fileofs to determine actual disk lump compressed size +// compression stage ensures a terminal null dictionary entry +#define GAMELUMPFLAG_COMPRESSED 0x0001 + +struct dgamelump_t +{ + DECLARE_BYTESWAP_DATADESC(); + GameLumpId_t id; + unsigned short flags; + unsigned short version; + int fileofs; + int filelen; +}; + +extern int g_MapRevision; + +struct dmodel_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector mins, maxs; + Vector origin; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces without walking the bsp tree +}; + +struct dphysmodel_t +{ + DECLARE_BYTESWAP_DATADESC() + int modelIndex; + int dataSize; + int keydataSize; + int solidCount; +}; + +// contains the binary blob for each displacement surface's virtual hull +struct dphysdisp_t +{ + DECLARE_BYTESWAP_DATADESC() + unsigned short numDisplacements; + //unsigned short dataSize[numDisplacements]; +}; + +struct dvertex_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector point; +}; + +// planes (x&~1) and (x&~1)+1 are always opposites +struct dplane_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector normal; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +}; + +#ifndef BSPFLAGS_H +#include "bspflags.h" +#endif + +struct dnode_t +{ + DECLARE_BYTESWAP_DATADESC(); + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides + short area; // If all leaves below this node are in the same area, then + // this is the area index. If not, this is -1. +}; + +typedef struct texinfo_s +{ + DECLARE_BYTESWAP_DATADESC(); + float textureVecsTexelsPerWorldUnits[2][4]; // [s/t][xyz offset] + float lightmapVecsLuxelsPerWorldUnits[2][4]; // [s/t][xyz offset] - length is in units of texels/area + int flags; // miptex flags + overrides + int texdata; // Pointer to texture name, size, etc. +} texinfo_t; + +#define TEXTURE_NAME_LENGTH 128 // changed from 64 BSPVERSION 8 + +struct dtexdata_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector reflectivity; + int nameStringTableID; // index into g_StringTable for the texture name + int width, height; // source image + int view_width, view_height; // +}; + + +//----------------------------------------------------------------------------- +// Occluders are simply polygons +//----------------------------------------------------------------------------- +// Flags field of doccluderdata_t +enum +{ + OCCLUDER_FLAGS_INACTIVE = 0x1, +}; + +struct doccluderdata_t +{ + DECLARE_BYTESWAP_DATADESC(); + int flags; + int firstpoly; // index into doccluderpolys + int polycount; + Vector mins; + Vector maxs; + int area; +}; + +struct doccluderdataV1_t +{ + int flags; + int firstpoly; // index into doccluderpolys + int polycount; + Vector mins; + Vector maxs; +}; + +struct doccluderpolydata_t +{ + DECLARE_BYTESWAP_DATADESC(); + int firstvertexindex; // index into doccludervertindices + int vertexcount; + int planenum; +}; + + +// NOTE: see the section above titled "displacement neighbor rules". +struct CDispSubNeighbor +{ +public: + DECLARE_BYTESWAP_DATADESC(); + unsigned short GetNeighborIndex() const { return m_iNeighbor; } + NeighborSpan GetSpan() const { return (NeighborSpan)m_Span; } + NeighborSpan GetNeighborSpan() const { return (NeighborSpan)m_NeighborSpan; } + NeighborOrientation GetNeighborOrientation() const { return (NeighborOrientation)m_NeighborOrientation; } + + bool IsValid() const { return m_iNeighbor != 0xFFFF; } + void SetInvalid() { m_iNeighbor = 0xFFFF; } + + +public: + unsigned short m_iNeighbor; // This indexes into ddispinfos. + // 0xFFFF if there is no neighbor here. + + unsigned char m_NeighborOrientation; // (CCW) rotation of the neighbor wrt this displacement. + + // These use the NeighborSpan type. + unsigned char m_Span; // Where the neighbor fits onto this side of our displacement. + unsigned char m_NeighborSpan; // Where we fit onto our neighbor. +}; + + +// NOTE: see the section above titled "displacement neighbor rules". +class CDispNeighbor +{ +public: + DECLARE_BYTESWAP_DATADESC(); + void SetInvalid() { m_SubNeighbors[0].SetInvalid(); m_SubNeighbors[1].SetInvalid(); } + + // Returns false if there isn't anything touching this edge. + bool IsValid() { return m_SubNeighbors[0].IsValid() || m_SubNeighbors[1].IsValid(); } + + +public: + // Note: if there is a neighbor that fills the whole side (CORNER_TO_CORNER), + // then it will always be in CDispNeighbor::m_Neighbors[0] + CDispSubNeighbor m_SubNeighbors[2]; +}; + + +class CDispCornerNeighbors +{ +public: + DECLARE_BYTESWAP_DATADESC(); + void SetInvalid() { m_nNeighbors = 0; } + + +public: + unsigned short m_Neighbors[MAX_DISP_CORNER_NEIGHBORS]; // indices of neighbors. + unsigned char m_nNeighbors; +}; + + +class CDispVert +{ +public: + DECLARE_BYTESWAP_DATADESC(); + Vector m_vVector; // Vector field defining displacement volume. + float m_flDist; // Displacement distances. + float m_flAlpha; // "per vertex" alpha values. +}; + +#define DISPTRI_TAG_SURFACE (1<<0) +#define DISPTRI_TAG_WALKABLE (1<<1) +#define DISPTRI_TAG_BUILDABLE (1<<2) +#define DISPTRI_FLAG_SURFPROP1 (1<<3) +#define DISPTRI_FLAG_SURFPROP2 (1<<4) +#define DISPTRI_TAG_REMOVE (1<<5) + +class CDispTri +{ +public: + DECLARE_BYTESWAP_DATADESC(); + unsigned short m_uiTags; // Displacement triangle tags. +}; + +class ddispinfo_t +{ +public: + DECLARE_BYTESWAP_DATADESC(); + int NumVerts() const { return NUM_DISP_POWER_VERTS(power); } + int NumTris() const { return NUM_DISP_POWER_TRIS(power); } + +public: + Vector startPosition; // start position used for orientation -- (added BSPVERSION 6) + int m_iDispVertStart; // Index into LUMP_DISP_VERTS. + int m_iDispTriStart; // Index into LUMP_DISP_TRIS. + + int power; // power - indicates size of map (2^power + 1) + int minTess; // minimum tesselation allowed + float smoothingAngle; // lighting smoothing angle + int contents; // surface contents + + unsigned short m_iMapFace; // Which map face this displacement comes from. + + int m_iLightmapAlphaStart; // Index into ddisplightmapalpha. + // The count is m_pParent->lightmapTextureSizeInLuxels[0]*m_pParent->lightmapTextureSizeInLuxels[1]. + + int m_iLightmapSamplePositionStart; // Index into LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS. + + CDispNeighbor m_EdgeNeighbors[4]; // Indexed by NEIGHBOREDGE_ defines. + CDispCornerNeighbors m_CornerNeighbors[4]; // Indexed by CORNER_ defines. + + enum unnamed { ALLOWEDVERTS_SIZE = PAD_NUMBER( MAX_DISPVERTS, 32 ) / 32 }; + unsigned long m_AllowedVerts[ALLOWEDVERTS_SIZE]; // This is built based on the layout and sizes of our neighbors + // and tells us which vertices are allowed to be active. +}; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +struct dedge_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short v[2]; // vertex numbers +}; + +#define MAXLIGHTMAPS 4 + +enum dprimitive_type +{ + PRIM_TRILIST=0, + PRIM_TRISTRIP=1, +}; + +struct dprimitive_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned char type; + unsigned short firstIndex; + unsigned short indexCount; + unsigned short firstVert; + unsigned short vertCount; +}; + +struct dprimvert_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector pos; +}; + +struct dface_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short planenum; + byte side; // faces opposite to the node's plane direction + byte onNode; // 1 of on node, 0 if in leaf + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + // This is a union under the assumption that a fog volume boundary (ie. water surface) + // isn't a displacement map. + // FIXME: These should be made a union with a flags or type field for which one it is + // if we can add more to this. +// union +// { + short dispinfo; + // This is only for surfaces that are the boundaries of fog volumes + // (ie. water surfaces) + // All of the rest of the surfaces can look at their leaf to find out + // what fog volume they are in. + short surfaceFogVolumeID; +// }; + + // lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples + float area; + + // TODO: make these unsigned chars? + int m_LightmapTextureMinsInLuxels[2]; + int m_LightmapTextureSizeInLuxels[2]; + + int origFace; // reference the original face this face was derived from + + +public: + + unsigned short GetNumPrims() const; + void SetNumPrims( unsigned short nPrims ); + bool AreDynamicShadowsEnabled(); + void SetDynamicShadowsEnabled( bool bEnabled ); + + // non-polygon primitives (strips and lists) +private: + unsigned short m_NumPrims; // Top bit, if set, disables shadows on this surface (this is why there are accessors). + +public: + unsigned short firstPrimID; + + unsigned int smoothingGroups; +}; + + +inline unsigned short dface_t::GetNumPrims() const +{ + return m_NumPrims & 0x7FFF; +} + +inline void dface_t::SetNumPrims( unsigned short nPrims ) +{ + Assert( (nPrims & 0x8000) == 0 ); + m_NumPrims &= ~0x7FFF; + m_NumPrims |= (nPrims & 0x7FFF); +} + +inline bool dface_t::AreDynamicShadowsEnabled() +{ + return (m_NumPrims & 0x8000) == 0; +} + +inline void dface_t::SetDynamicShadowsEnabled( bool bEnabled ) +{ + if ( bEnabled ) + m_NumPrims &= ~0x8000; + else + m_NumPrims |= 0x8000; +} + +struct dfaceid_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short hammerfaceid; +}; + + +// NOTE: Only 7-bits stored!!! +#define LEAF_FLAGS_SKY 0x01 // This leaf has 3D sky in its PVS +#define LEAF_FLAGS_RADIAL 0x02 // This leaf culled away some portals due to radial vis +#define LEAF_FLAGS_SKY2D 0x04 // This leaf has 2D sky in its PVS + +#if defined( _X360 ) +#pragma bitfield_order( push, lsb_to_msb ) +#endif +#pragma warning( disable:4201 ) // C4201: nonstandard extension used: nameless struct/union +struct dleaf_version_0_t +{ + DECLARE_BYTESWAP_DATADESC(); + int contents; // OR of all brushes (not needed?) + + short cluster; + + BEGIN_BITFIELD( bf ); + short area:9; + short flags:7; // Per leaf flags. + END_BITFIELD(); + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; + short leafWaterDataID; // -1 for not in water + + // Precaculated light info for entities. + CompressedLightCube m_AmbientLighting; +}; + +// version 1 +struct dleaf_t +{ + DECLARE_BYTESWAP_DATADESC(); + int contents; // OR of all brushes (not needed?) + + short cluster; + + BEGIN_BITFIELD( bf ); + short area:9; + short flags:7; // Per leaf flags. + END_BITFIELD(); + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; + short leafWaterDataID; // -1 for not in water + + // NOTE: removed this for version 1 and moved into separate lump "LUMP_LEAF_AMBIENT_LIGHTING" or "LUMP_LEAF_AMBIENT_LIGHTING_HDR" + // Precaculated light info for entities. +// CompressedLightCube m_AmbientLighting; +}; +#pragma warning( default:4201 ) // C4201: nonstandard extension used: nameless struct/union +#if defined( _X360 ) +#pragma bitfield_order( pop ) +#endif + +// each leaf contains N samples of the ambient lighting +// each sample contains a cube of ambient light projected on to each axis +// and a sampling position encoded as a 0.8 fraction (mins=0,maxs=255) of the leaf's bounding box +struct dleafambientlighting_t +{ + DECLARE_BYTESWAP_DATADESC(); + CompressedLightCube cube; + byte x; // fixed point fraction of leaf bounds + byte y; // fixed point fraction of leaf bounds + byte z; // fixed point fraction of leaf bounds + byte pad; // unused +}; + +struct dleafambientindex_t +{ + DECLARE_BYTESWAP_DATADESC(); + + unsigned short ambientSampleCount; + unsigned short firstAmbientSample; +}; + +struct dbrushside_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short planenum; // facing out of the leaf + short texinfo; + short dispinfo; // displacement info (BSPVERSION 7) + short bevel; // is the side a bevel plane? (BSPVERSION 7) +}; + +struct dbrush_t +{ + DECLARE_BYTESWAP_DATADESC(); + int firstside; + int numsides; + int contents; +}; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PAS 1 +struct dvis_t +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +}; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +struct dareaportal_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short m_PortalKey; // Entities have a key called portalnumber (and in vbsp a variable + // called areaportalnum) which is used + // to bind them to the area portals by comparing with this value. + + unsigned short otherarea; // The area this portal looks into. + + unsigned short m_FirstClipPortalVert; // Portal geometry. + unsigned short m_nClipPortalVerts; + + int planenum; +}; + + +struct darea_t +{ + DECLARE_BYTESWAP_DATADESC(); + int numareaportals; + int firstareaportal; +}; + +struct dleafwaterdata_t +{ + DECLARE_BYTESWAP_DATADESC(); + float surfaceZ; + float minZ; + short surfaceTexInfoID; +}; + +class CFaceMacroTextureInfo +{ +public: + DECLARE_BYTESWAP_DATADESC(); + // This looks up into g_TexDataStringTable, which looks up into g_TexDataStringData. + // 0xFFFF if the face has no macro texture. + unsigned short m_MacroTextureNameID; +}; + +// lights that were used to illuminate the world +enum emittype_t +{ + emit_surface, // 90 degree spotlight + emit_point, // simple point light source + emit_spotlight, // spotlight with penumbra + emit_skylight, // directional light with no falloff (surface must trace to SKY texture) + emit_quakelight, // linear falloff, non-lambertian + emit_skyambient, // spherical light source with no falloff (surface must trace to SKY texture) +}; + + +// Flags for dworldlight_t::flags +#define DWL_FLAGS_INAMBIENTCUBE 0x0001 // This says that the light was put into the per-leaf ambient cubes. + + +struct dworldlight_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector origin; + Vector intensity; + Vector normal; // for surfaces and spotlights + int cluster; + emittype_t type; + int style; + float stopdot; // start of penumbra for emit_spotlight + float stopdot2; // end of penumbra for emit_spotlight + float exponent; // + float radius; // cutoff distance + // falloff for emit_spotlight + emit_point: + // 1 / (constant_attn + linear_attn * dist + quadratic_attn * dist^2) + float constant_attn; + float linear_attn; + float quadratic_attn; + int flags; // Uses a combination of the DWL_FLAGS_ defines. + int texinfo; // + int owner; // entity that this light it relative to +}; + +struct dcubemapsample_t +{ + DECLARE_BYTESWAP_DATADESC(); + int origin[3]; // position of light snapped to the nearest integer + // the filename for the vtf file is derived from the position + unsigned char size; // 0 - default + // otherwise, 1<<(size-1) +}; + +#define OVERLAY_BSP_FACE_COUNT 64 + +#define OVERLAY_NUM_RENDER_ORDERS (1<> (16 - OVERLAY_RENDER_ORDER_NUM_BITS)); +} + + +struct doverlayfade_t +{ + DECLARE_BYTESWAP_DATADESC(); + + float flFadeDistMinSq; + float flFadeDistMaxSq; +}; + + +#define WATEROVERLAY_BSP_FACE_COUNT 256 +#define WATEROVERLAY_RENDER_ORDER_NUM_BITS 2 +#define WATEROVERLAY_NUM_RENDER_ORDERS (1<> ( 16 - WATEROVERLAY_RENDER_ORDER_NUM_BITS ) ); +} + +#ifndef _DEF_BYTE_ +#define _DEF_BYTE_ +typedef unsigned char byte; +typedef unsigned short word; +#endif + + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +//=============== + + +struct epair_t +{ + epair_t *next; + char *key; + char *value; +}; + +// finalized page of surface's lightmaps +#define MAX_LIGHTMAPPAGE_WIDTH 256 +#define MAX_LIGHTMAPPAGE_HEIGHT 128 +typedef struct nameForDatadesc_dlightmappage_t // unnamed structs collide in the datadesc macros +{ + DECLARE_BYTESWAP_DATADESC(); + byte data[MAX_LIGHTMAPPAGE_WIDTH*MAX_LIGHTMAPPAGE_HEIGHT]; + byte palette[256*4]; +} dlightmappage_t; + +typedef struct nameForDatadesc_dlightmappageinfo_t // unnamed structs collide in the datadesc macros +{ + DECLARE_BYTESWAP_DATADESC(); + byte page; // lightmap page [0..?] + byte offset[2]; // offset into page (s,t) + byte pad; // unused + ColorRGBExp32 avgColor; // average used for runtime lighting calcs +} dlightmappageinfo_t; + +#endif // BSPFILE_H diff --git a/public/bspflags.h b/public/bspflags.h new file mode 100644 index 0000000..01070ab --- /dev/null +++ b/public/bspflags.h @@ -0,0 +1,149 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef BSPFLAGS_H +#define BSPFLAGS_H + +#ifdef _WIN32 +#pragma once +#endif + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// these definitions also need to be in q_shared.h! + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_EMPTY 0 // No contents + +#define CONTENTS_SOLID 0x1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 0x2 // translucent, but not watery (glass) +#define CONTENTS_AUX 0x4 +#define CONTENTS_GRATE 0x8 // alpha-tested "grate" textures. Bullets/sight pass through, but solids don't +#define CONTENTS_SLIME 0x10 +#define CONTENTS_WATER 0x20 +#define CONTENTS_BLOCKLOS 0x40 // block AI line of sight +#define CONTENTS_OPAQUE 0x80 // things that cannot be seen through (may be non-solid though) +#define LAST_VISIBLE_CONTENTS 0x80 + +#define ALL_VISIBLE_CONTENTS (LAST_VISIBLE_CONTENTS | (LAST_VISIBLE_CONTENTS-1)) + +#define CONTENTS_TESTFOGVOLUME 0x100 +#define CONTENTS_UNUSED 0x200 + +// unused +// NOTE: If it's visible, grab from the top + update LAST_VISIBLE_CONTENTS +// if not visible, then grab from the bottom. +#define CONTENTS_UNUSED6 0x400 + +#define CONTENTS_TEAM1 0x800 // per team contents used to differentiate collisions +#define CONTENTS_TEAM2 0x1000 // between players and objects on different teams + +// ignore CONTENTS_OPAQUE on surfaces that have SURF_NODRAW +#define CONTENTS_IGNORE_NODRAW_OPAQUE 0x2000 + +// hits entities which are MOVETYPE_PUSH (doors, plats, etc.) +#define CONTENTS_MOVEABLE 0x4000 + +// remaining contents are non-visible, and don't eat brushes +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define CONTENTS_DEBRIS 0x4000000 +#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTS_LADDER 0x20000000 +#define CONTENTS_HITBOX 0x40000000 // use accurate hitboxes on trace + + +// NOTE: These are stored in a short in the engine now. Don't use more than 16 bits +#define SURF_LIGHT 0x0001 // value will hold the light strength +#define SURF_SKY2D 0x0002 // don't draw, indicates we should skylight + draw 2d sky but not draw the 3D skybox +#define SURF_SKY 0x0004 // don't draw, but add to skybox +#define SURF_WARP 0x0008 // turbulent water warp +#define SURF_TRANS 0x0010 +#define SURF_NOPORTAL 0x0020 // the surface can not have a portal placed on it +#define SURF_TRIGGER 0x0040 // FIXME: This is an xbox hack to work around elimination of trigger surfaces, which breaks occluders +#define SURF_NODRAW 0x0080 // don't bother referencing the texture + +#define SURF_HINT 0x0100 // make a primary bsp splitter + +#define SURF_SKIP 0x0200 // completely ignore, allowing non-closed brushes +#define SURF_NOLIGHT 0x0400 // Don't calculate light +#define SURF_BUMPLIGHT 0x0800 // calculate three lightmaps for the surface for bumpmapping +#define SURF_NOSHADOWS 0x1000 // Don't receive shadows +#define SURF_NODECALS 0x2000 // Don't receive decals +#define SURF_NOCHOP 0x4000 // Don't subdivide patches on this surface +#define SURF_HITBOX 0x8000 // surface is part of a hitbox + + + +// ----------------------------------------------------- +// spatial content masks - used for spatial queries (traceline,etc.) +// ----------------------------------------------------- +#define MASK_ALL (0xFFFFFFFF) +// everything that is normally solid +#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +// everything that blocks player movement +#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +// blocks npc movement +#define MASK_NPCSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +// water physics in these contents +#define MASK_WATER (CONTENTS_WATER|CONTENTS_MOVEABLE|CONTENTS_SLIME) +// everything that blocks lighting +#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_OPAQUE) +// everything that blocks lighting, but with monsters added. +#define MASK_OPAQUE_AND_NPCS (MASK_OPAQUE|CONTENTS_MONSTER) +// everything that blocks line of sight for AI +#define MASK_BLOCKLOS (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_BLOCKLOS) +// everything that blocks line of sight for AI plus NPCs +#define MASK_BLOCKLOS_AND_NPCS (MASK_BLOCKLOS|CONTENTS_MONSTER) +// everything that blocks line of sight for players +#define MASK_VISIBLE (MASK_OPAQUE|CONTENTS_IGNORE_NODRAW_OPAQUE) +// everything that blocks line of sight for players, but with monsters added. +#define MASK_VISIBLE_AND_NPCS (MASK_OPAQUE_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE) +// bullets see these as solid +#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_HITBOX) +// non-raycasted weapons see this as solid (includes grates) +#define MASK_SHOT_HULL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_GRATE) +// hits solids (not grates) and passes through everything else +#define MASK_SHOT_PORTAL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER) +// everything normally solid, except monsters (world+brush only) +#define MASK_SOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_GRATE) +// everything normally solid for player movement, except monsters (world+brush only) +#define MASK_PLAYERSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_PLAYERCLIP|CONTENTS_GRATE) +// everything normally solid for npc movement, except monsters (world+brush only) +#define MASK_NPCSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) +// just the world, used for route rebuilding +#define MASK_NPCWORLDSTATIC (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) +// These are things that can split areaportals +#define MASK_SPLITAREAPORTAL (CONTENTS_WATER|CONTENTS_SLIME) + +// UNDONE: This is untested, any moving water +#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN) + +// everything that blocks corpse movement +// UNDONE: Not used yet / may be deleted +#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_GRATE) + +#endif // BSPFLAGS_H diff --git a/public/bsptreedata.cpp b/public/bsptreedata.cpp new file mode 100644 index 0000000..e03dd2c --- /dev/null +++ b/public/bsptreedata.cpp @@ -0,0 +1,352 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +// +// The BSP tree leaf data system +// +//=============================================================================// + +#include "basetypes.h" +#include "bsptreedata.h" +#include "utllinkedlist.h" +#include "utlvector.h" +#include "tier0/dbg.h" +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// The BSP tree leaf data system +//----------------------------------------------------------------------------- +class CBSPTreeData : public IBSPTreeData, public ISpatialLeafEnumerator +{ +public: + // constructor, destructor + CBSPTreeData(); + virtual ~CBSPTreeData(); + + // Methods of IBSPTreeData + void Init( ISpatialQuery* pBSPTree ); + void Shutdown(); + + BSPTreeDataHandle_t Insert( int userId, Vector const& mins, Vector const& maxs ); + void Remove( BSPTreeDataHandle_t handle ); + void ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ); + + // Enumerate elements in a particular leaf + bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context ); + + // For convenience, 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 ); + + // methods of IBSPLeafEnumerator + bool EnumerateLeaf( int leaf, int context ); + + // Is the element in any leaves at all? + bool IsElementInTree( BSPTreeDataHandle_t handle ) const; + +private: + // Creates a new handle + BSPTreeDataHandle_t NewHandle( int userId ); + + // Adds a handle to the list of handles + void AddHandleToLeaf( int leaf, BSPTreeDataHandle_t handle ); + + // insert, remove handles from leaves + void InsertIntoTree( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ); + void RemoveFromTree( BSPTreeDataHandle_t handle ); + + // Returns the number of elements in a leaf + int CountElementsInLeaf( int leaf ); + +private: + // All the information associated with a particular handle + struct HandleInfo_t + { + int m_UserId; // Client-defined id + unsigned short m_LeafList; // What leafs is it in? + }; + + // The leaf contains an index into a list of elements + struct Leaf_t + { + unsigned short m_FirstElement; + }; + + // The handle knows about the leaves it lies in + struct HandleInLeaf_t + { + int m_Leaf; // what leaf is the handle in? + unsigned short m_LeafElementIndex; // what's the m_LeafElements index of the entry? + }; + + // Stores data associated with each leaf. + CUtlVector< Leaf_t > m_Leaf; + + // Stores all unique handles + CUtlLinkedList< HandleInfo_t, unsigned short > m_Handles; + + // Maintains the list of all handles in a particular leaf + CUtlLinkedList< BSPTreeDataHandle_t, unsigned short, true > m_LeafElements; + + // Maintains the list of all leaves a particular handle spans + CUtlLinkedList< HandleInLeaf_t, unsigned short, true > m_HandleLeafList; + + // Interface to BSP tree + ISpatialQuery* m_pBSPTree; +}; + + +//----------------------------------------------------------------------------- +// Class factory +//----------------------------------------------------------------------------- + +IBSPTreeData* CreateBSPTreeData() +{ + return new CBSPTreeData; +} + +void DestroyBSPTreeData( IBSPTreeData* pTreeData ) +{ + if (pTreeData) + delete pTreeData; +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +CBSPTreeData::CBSPTreeData() +{ +} + +CBSPTreeData::~CBSPTreeData() +{ +} + + +//----------------------------------------------------------------------------- +// Level init, shutdown +//----------------------------------------------------------------------------- + +void CBSPTreeData::Init( ISpatialQuery* pBSPTree ) +{ + Assert( pBSPTree ); + m_pBSPTree = pBSPTree; + + m_Handles.EnsureCapacity( 1024 ); + m_LeafElements.EnsureCapacity( 1024 ); + m_HandleLeafList.EnsureCapacity( 1024 ); + + // Add all the leaves we'll need + int leafCount = m_pBSPTree->LeafCount(); + m_Leaf.EnsureCapacity( leafCount ); + + Leaf_t newLeaf; + newLeaf.m_FirstElement = m_LeafElements.InvalidIndex(); + while ( --leafCount >= 0 ) + { + m_Leaf.AddToTail( newLeaf ); + } +} + +void CBSPTreeData::Shutdown() +{ + m_Handles.Purge(); + m_LeafElements.Purge(); + m_HandleLeafList.Purge(); + m_Leaf.Purge(); +} + + +//----------------------------------------------------------------------------- +// Creates a new handle +//----------------------------------------------------------------------------- + +BSPTreeDataHandle_t CBSPTreeData::NewHandle( int userId ) +{ + BSPTreeDataHandle_t handle = m_Handles.AddToTail(); + m_Handles[handle].m_UserId = userId; + m_Handles[handle].m_LeafList = m_HandleLeafList.InvalidIndex(); + + return handle; +} + +//----------------------------------------------------------------------------- +// Add/remove handle +//----------------------------------------------------------------------------- + +BSPTreeDataHandle_t CBSPTreeData::Insert( int userId, Vector const& mins, Vector const& maxs ) +{ + BSPTreeDataHandle_t handle = NewHandle( userId ); + InsertIntoTree( handle, mins, maxs ); + return handle; +} + +void CBSPTreeData::Remove( BSPTreeDataHandle_t handle ) +{ + if (!m_Handles.IsValidIndex(handle)) + return; + + RemoveFromTree( handle ); + m_Handles.Free( handle ); +} + + +//----------------------------------------------------------------------------- +// Adds a handle to a leaf +//----------------------------------------------------------------------------- +void CBSPTreeData::AddHandleToLeaf( int leaf, BSPTreeDataHandle_t handle ) +{ + // Got to a leaf baby! Add the handle to the leaf's list of elements + unsigned short leafElement = m_LeafElements.Alloc( true ); + if (m_Leaf[leaf].m_FirstElement != m_LeafElements.InvalidIndex() ) + m_LeafElements.LinkBefore( m_Leaf[leaf].m_FirstElement, leafElement ); + m_Leaf[leaf].m_FirstElement = leafElement; + m_LeafElements[leafElement] = handle; + + // Insert the leaf into the handles's list of leaves + unsigned short handleElement = m_HandleLeafList.Alloc( true ); + if (m_Handles[handle].m_LeafList != m_HandleLeafList.InvalidIndex() ) + m_HandleLeafList.LinkBefore( m_Handles[handle].m_LeafList, handleElement ); + m_Handles[handle].m_LeafList = handleElement; + m_HandleLeafList[handleElement].m_Leaf = leaf; + m_HandleLeafList[handleElement].m_LeafElementIndex = leafElement; +} + + +//----------------------------------------------------------------------------- +// Inserts an element into the tree +//----------------------------------------------------------------------------- +bool CBSPTreeData::EnumerateLeaf( int leaf, int context ) +{ + BSPTreeDataHandle_t handle = (BSPTreeDataHandle_t)context; + AddHandleToLeaf( leaf, handle ); + return true; +} + +void CBSPTreeData::InsertIntoTree( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ) +{ + m_pBSPTree->EnumerateLeavesInBox( mins, maxs, this, handle ); +} + +//----------------------------------------------------------------------------- +// Removes an element from the tree +//----------------------------------------------------------------------------- + +void CBSPTreeData::RemoveFromTree( BSPTreeDataHandle_t handle ) +{ + // Iterate over the list of all leaves the handle is in + unsigned short i = m_Handles[handle].m_LeafList; + while (i != m_HandleLeafList.InvalidIndex()) + { + int leaf = m_HandleLeafList[i].m_Leaf; + unsigned short leafElement = m_HandleLeafList[i].m_LeafElementIndex; + + // Unhook the handle from the leaf handle list + if (leafElement == m_Leaf[leaf].m_FirstElement) + m_Leaf[leaf].m_FirstElement = m_LeafElements.Next(leafElement); + m_LeafElements.Free(leafElement); + + unsigned short prevNode = i; + i = m_HandleLeafList.Next(i); + m_HandleLeafList.Free(prevNode); + } + + m_Handles[handle].m_LeafList = m_HandleLeafList.InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Call this when the element moves +//----------------------------------------------------------------------------- +void CBSPTreeData::ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ) +{ + if (handle != TREEDATA_INVALID_HANDLE) + { + RemoveFromTree( handle ); + InsertIntoTree( handle, mins, maxs ); + } +} + + +//----------------------------------------------------------------------------- +// Is the element in any leaves at all? +//----------------------------------------------------------------------------- +bool CBSPTreeData::IsElementInTree( BSPTreeDataHandle_t handle ) const +{ + return m_Handles[handle].m_LeafList != m_HandleLeafList.InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Enumerate elements in a particular leaf +//----------------------------------------------------------------------------- +int CBSPTreeData::CountElementsInLeaf( int leaf ) +{ + int i; + int nCount = 0; + for( i = m_Leaf[leaf].m_FirstElement; i != m_LeafElements.InvalidIndex(); i = m_LeafElements.Next(i) ) + { + ++nCount; + } + + return nCount; +} + +//----------------------------------------------------------------------------- +// Enumerate elements in a particular leaf +//----------------------------------------------------------------------------- +bool CBSPTreeData::EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context ) +{ +#ifdef DBGFLAG_ASSERT + // The enumeration method better damn well not change this list... + int nCount = CountElementsInLeaf(leaf); +#endif + + unsigned short idx = m_Leaf[leaf].m_FirstElement; + while (idx != m_LeafElements.InvalidIndex()) + { + BSPTreeDataHandle_t handle = m_LeafElements[idx]; + if (!pEnum->EnumerateElement( m_Handles[handle].m_UserId, context )) + { + Assert( CountElementsInLeaf(leaf) == nCount ); + return false; + } + idx = m_LeafElements.Next(idx); + } + + Assert( CountElementsInLeaf(leaf) == nCount ); + + return true; +} + + +//----------------------------------------------------------------------------- +// For convenience, enumerates the leaves along a ray, box, etc. +//----------------------------------------------------------------------------- +bool CBSPTreeData::EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ) +{ + return m_pBSPTree->EnumerateLeavesAtPoint( pt, pEnum, context ); +} + +bool CBSPTreeData::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) +{ + return m_pBSPTree->EnumerateLeavesInBox( mins, maxs, pEnum, context ); +} + +bool CBSPTreeData::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) +{ + return m_pBSPTree->EnumerateLeavesInSphere( center, radius, pEnum, context ); +} + +bool CBSPTreeData::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) +{ + return m_pBSPTree->EnumerateLeavesAlongRay( ray, pEnum, context ); +} + diff --git a/public/bsptreedata.h b/public/bsptreedata.h new file mode 100644 index 0000000..2132dfb --- /dev/null +++ b/public/bsptreedata.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +// +// The BSP tree leaf data system +// +//=============================================================================// + +#include "tier0/platform.h" + +#if !defined( BSPTREEDATA ) +#define BSPTREEDATA +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +class Vector; +struct Ray_t; + + +//----------------------------------------------------------------------------- +// Handle to an renderable in the client leaf system +//----------------------------------------------------------------------------- + +typedef unsigned short BSPTreeDataHandle_t; + +enum +{ + TREEDATA_INVALID_HANDLE = (BSPTreeDataHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Interface needed by tree data to do its job +// +// Note that anything that has convex spatial regions with leaves identified +// by indices can implement the ISpatialQuery. All you have to do is to implement +// a class that can answer the 5 questions in the Query interface about the +// spatial subdivision. For example, a K-D tree or a BSP tree could implement +// this interface +// +//----------------------------------------------------------------------------- + +abstract_class ISpatialLeafEnumerator +{ +public: + // call back with a leaf and a context + // The context is completely user defined; it's passed into the enumeration + // function of ISpatialQuery. + // This gets called by the enumeration methods with each leaf + // that passes the test; return true to continue enumerating, + // false to stop + + virtual bool EnumerateLeaf( int leaf, int context ) = 0; +}; + +abstract_class ISpatialQuery +{ +public: + // Returns the number of leaves + virtual int LeafCount() const = 0; + + // Enumerates the leaves along a ray, box, etc. + virtual bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Data associated with leaves. +// +// This is a parasitic class that attaches data to the leaves specified by the +// ISpatialQuery sent in to the initialization function. It can't exist without +// a spatial partition of some sort to hold onto. +//----------------------------------------------------------------------------- + +abstract_class IBSPTreeDataEnumerator +{ +public: + // call back with a userId and a context + virtual bool FASTCALL EnumerateElement( int userId, int context ) = 0; +}; + +abstract_class IBSPTreeData +{ +public: + // Add a virtual destructor so that the derived class destructors will + // be called. + virtual ~IBSPTreeData() {} + + // Initializes, shuts down + virtual void Init( ISpatialQuery* pBSPTree ) = 0; + virtual void Shutdown() = 0; + + // Adds and removes data from the leaf lists + virtual BSPTreeDataHandle_t Insert( int userId, Vector const& mins, Vector const& maxs ) = 0; + virtual void Remove( BSPTreeDataHandle_t handle ) = 0; + + // Call this when a element moves + virtual void ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ) = 0; + + // Enumerate elements in a particular leaf + virtual bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context ) = 0; + + // Is the element in any leaves at all? + virtual bool IsElementInTree( BSPTreeDataHandle_t handle ) const = 0; + + // NOTE: These methods call through to the functions in the attached + // ISpatialQuery + // For convenience, enumerates the leaves along a ray, box, etc. + virtual bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) = 0; +}; + +//----------------------------------------------------------------------------- +// Class factory +//----------------------------------------------------------------------------- + +IBSPTreeData* CreateBSPTreeData(); +void DestroyBSPTreeData( IBSPTreeData* pTreeData ); + + +#endif // BSPTREEDATA + + diff --git a/public/builddisp.cpp b/public/builddisp.cpp new file mode 100644 index 0000000..9f82182 --- /dev/null +++ b/public/builddisp.cpp @@ -0,0 +1,3116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +//#include +#include +#include +#include "builddisp.h" +#include "collisionutils.h" +#include "tier1/strtools.h" +#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// +// Node Functions (friend functions) +// + +//----------------------------------------------------------------------------- +// should make this more programatic and extensible! +//----------------------------------------------------------------------------- +int GetNodeLevel( int index ) +{ + // root + if( index == 0 ) + return 1; + + // [1...4] + if( index < 5 ) + return 2; + + // [5....20] + if( index < 21 ) + return 3; + + // [21....84] + if( index < 85 ) + return 4; + + // error!!! + return -1; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int GetNodeCount( int power ) +{ + return ( ( 1 << ( power << 1 ) ) / 3 ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int GetNodeParent( int index ) +{ + // ( index - 1 ) / 4 + return ( ( index - 1 ) >> 2 ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int GetNodeChild( int power, int index, int direction ) +{ + // ( index * 4 ) + direction + return ( ( index << 2 ) + ( direction - 3 ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int GetNodeMinNodeAtLevel( int level ) +{ + switch( level ) + { + case 1: return 0; + case 2: return 1; + case 3: return 5; + case 4: return 21; + default: return -99999; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void GetComponentsFromNodeIndex( int index, int *x, int *y ) +{ + *x = 0; + *y = 0; + + for( int shift = 0; index != 0; shift++ ) + { + *x |= ( index & 1 ) << shift; + index >>= 1; + + *y |= ( index & 1 ) << shift; + index >>= 1; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int GetNodeIndexFromComponents( int x, int y ) +{ + int index = 0; + + // Interleave bits from the x and y values to create the index: + + int shift; + for( shift = 0; x != 0; shift += 2, x >>= 1 ) + { + index |= ( x & 1 ) << shift; + } + + for( shift = 1; y != 0; shift += 2, y >>= 1 ) + { + index |= ( y & 1 ) << shift; + } + + return index; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CalcBarycentricCooefs( Vector const &v0, Vector const &v1, Vector const &v2, + Vector const &pt, float &c0, float &c1, float &c2 ) +{ + Vector vSeg0, vSeg1, vCross; + vSeg0 = v1 - v0; + vSeg1 = v2 - v0; + + // get the area of the triangle + vCross = vSeg0.Cross( vSeg1 ); + float totalArea = vCross.Length() * 0.5f; + float ooTotalArea = totalArea ? 1.0f / totalArea : 0.0f; + + // get the area for cooeficient 0 (pt, v1, v2) + vSeg0 = v1 - pt; + vSeg1 = v2 - pt; + vCross = vSeg0.Cross( vSeg1 ); + float subArea = vCross.Length() * 0.5f; + c0 = subArea * ooTotalArea; + + // get the area for cooeficient 1 (v0, pt, v2) + vSeg0 = v2 - pt; + vSeg1 = v0 - pt; + vCross = vSeg0.Cross( vSeg1 ); + subArea = vCross.Length() * 0.5f; + c1 = subArea * ooTotalArea; + + // get the area for cooeficient 2 (v0, v1, pt) + vSeg0 = v0 - pt; + vSeg1 = v1 - pt; + vCross = vSeg0.Cross( vSeg1 ); + subArea = vCross.Length() * 0.5f; + c2 = subArea * ooTotalArea; + + float cTotal = c0 + c1 + c2; + if ( FloatMakePositive( 1.0f - cTotal ) < 1e-3 ) + return true; + + return false; +} + +// For some reason, the global optimizer screws up the recursion here. disable the global optimizations to fix this. +// IN VC++ 6.0 +#pragma optimize( "g", off ) + +CCoreDispSurface::CCoreDispSurface() +{ + Init(); +} + + +//============================================================================= +// +// CDispSurface Functions +// + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispSurface::Init( void ) +{ + m_Index = -1; + + m_PointCount = 0; + int i; + for( i = 0; i < QUAD_POINT_COUNT; i++ ) + { + VectorClear( m_Points[i] ); + VectorClear( m_Normals[i] ); + Vector2DClear( m_TexCoords[i] ); + + for( int j = 0; j < NUM_BUMP_VECTS+1; j++ ) + { + Vector2DClear( m_LuxelCoords[i][j] ); + } + + m_Alphas[i] = 1.0f; + } + + m_PointStartIndex = -1; + VectorClear( m_PointStart ); + VectorClear( sAxis ); + VectorClear( tAxis ); + + for( i = 0; i < 4; i++ ) + { + m_EdgeNeighbors[i].SetInvalid(); + m_CornerNeighbors[i].SetInvalid(); + } + + m_Flags = 0; + m_Contents = 0; +} + + +void CCoreDispSurface::SetNeighborData( const CDispNeighbor edgeNeighbors[4], const CDispCornerNeighbors cornerNeighbors[4] ) +{ + for ( int i=0; i < 4; i++ ) + { + m_EdgeNeighbors[i] = edgeNeighbors[i]; + m_CornerNeighbors[i] = cornerNeighbors[i]; + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispSurface::GeneratePointStartIndexFromMappingAxes( Vector const &sAxis, Vector const &tAxis ) +{ + if( m_PointStartIndex != -1 ) + return; + + int numIndices = 0; + int indices[4]; + int offsetIndex; + + // + // project all points on to the v-axis first and find the minimum + // + float minValue = DotProduct( tAxis, m_Points[0] ); + indices[numIndices] = 0; + numIndices++; + + int i; + for( i = 1; i < m_PointCount; i++ ) + { + float value = DotProduct( tAxis, m_Points[i] ); + float delta = ( value - minValue ); + delta = FloatMakePositive( delta ); + if( delta < 0.1 ) + { + indices[numIndices] = i; + numIndices++; + } + else if( value < minValue ) + { + minValue = value; + indices[0] = i; + numIndices = 1; + } + } + + // + // break ties with the u-axis projection + // + minValue = DotProduct( sAxis, m_Points[indices[0]] ); + offsetIndex = indices[0]; + + for( i = 1; i < numIndices; i++ ) + { + float value = DotProduct( sAxis, m_Points[indices[i]] ); + if( ( value < minValue ) ) + { + minValue = value; + offsetIndex = indices[i]; + } + } + + m_PointStartIndex = offsetIndex; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CCoreDispSurface::GenerateSurfPointStartIndex( void ) +{ + // + // get the minimum surface component values + // + Vector bMin; + VectorFill( bMin, 99999.0f ); + + int i; + for( i = 0; i < QUAD_POINT_COUNT; i++ ) + { + for( int j = 0; j < 3; j++ ) + { + if( m_Points[i][j] < bMin[j] ) + { + bMin[j] = m_Points[i][j]; + } + } + } + + // + // find the point closest to the minimum, that is the start point + // + int minIndex = -1; + float minDistance = 999999999.0f; + for( i = 0; i < QUAD_POINT_COUNT; i++ ) + { + Vector segment; + segment = m_Points[i] - bMin; + float distanceSq = segment.LengthSqr(); + if( distanceSq < minDistance ) + { + minDistance = distanceSq; + minIndex = i; + } + } + + m_PointStartIndex = minIndex; + + return minIndex; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CCoreDispSurface::FindSurfPointStartIndex( void ) +{ + if( m_PointStartIndex != -1 ) + return m_PointStartIndex; + + int minIndex = -1; + float minDistance = 999999999.0f; + + for( int i = 0; i < QUAD_POINT_COUNT; i++ ) + { + Vector segment; + VectorSubtract( m_PointStart, m_Points[i], segment ); + float distanceSq = segment.LengthSqr(); + if( distanceSq < minDistance ) + { + minDistance = distanceSq; + minIndex = i; + } + } + + m_PointStartIndex = minIndex; + + return minIndex; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispSurface::AdjustSurfPointData( void ) +{ + Vector tmpPoints[4]; + Vector tmpNormals[4]; + Vector2D tmpTexCoords[4]; + float tmpAlphas[4]; + + int i; + for( i = 0; i < QUAD_POINT_COUNT; i++ ) + { + VectorCopy( m_Points[i], tmpPoints[i] ); + VectorCopy( m_Normals[i], tmpNormals[i] ); + Vector2DCopy( m_TexCoords[i], tmpTexCoords[i] ); + + tmpAlphas[i] = m_Alphas[i]; + } + + for( i = 0; i < QUAD_POINT_COUNT; i++ ) + { + VectorCopy( tmpPoints[(i+m_PointStartIndex)%4], m_Points[i] ); + VectorCopy( tmpNormals[(i+m_PointStartIndex)%4], m_Normals[i] ); + Vector2DCopy( tmpTexCoords[(i+m_PointStartIndex)%4], m_TexCoords[i] ); + + m_Alphas[i] = tmpAlphas[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CCoreDispSurface::LongestInU( const Vector &vecU, const Vector &vecV ) +{ + Vector vecNormU = vecU; + Vector vecNormV = vecV; + VectorNormalize( vecNormU ); + VectorNormalize( vecNormV ); + + float flDistU[4]; + float flDistV[4]; + for ( int iPoint = 0; iPoint < 4; ++iPoint ) + { + flDistU[iPoint] = vecNormU.Dot( m_Points[iPoint] ); + flDistV[iPoint] = vecNormV.Dot( m_Points[iPoint] ); + } + + float flULength = 0.0f; + float flVLength = 0.0f; + for ( int iPoint = 0; iPoint < 4; ++iPoint ) + { + float flTestDist = fabs( flDistU[(iPoint+1)%4] - flDistU[iPoint] ); + if ( flTestDist > flULength ) + { + flULength = flTestDist; + } + + flTestDist = fabs( flDistV[(iPoint+1)%4] - flDistV[iPoint] ); + if ( flTestDist > flVLength ) + { + flVLength = flTestDist; + } + } + + if ( flULength < flVLength ) + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +//----------------------------------------------------------------------------- +bool CCoreDispSurface::CalcLuxelCoords( int nLuxels, bool bAdjust, const Vector &vecU, const Vector &vecV ) +{ + // Valid value? + if ( nLuxels <= 0.0f ) + return false; + + // Get the start point offset. + int iOffset = 0; + if ( bAdjust ) + { + iOffset = GetPointStartIndex(); + } + + // Does projecting along U or V create the longest edge? + bool bLongU = LongestInU( vecU, vecV ); + + float flLengthTemp = 0.0f; + float flULength = ( m_Points[(3+iOffset)%4] - m_Points[(0+iOffset)%4] ).Length(); + flLengthTemp = ( m_Points[(2+iOffset)%4] - m_Points[(1+iOffset)%4] ).Length(); + if ( flLengthTemp > flULength ) + { + flULength = flLengthTemp; + } + + // Find the largest edge in V. + float flVLength = ( m_Points[(1+iOffset)%4] - m_Points[(0+iOffset)%4] ).Length(); + flLengthTemp = ( m_Points[(2+iOffset)%4] - m_Points[(3+iOffset)%4] ).Length(); + if ( flLengthTemp > flVLength ) + { + flVLength = flLengthTemp; + } + + float flOOLuxelScale = 1.0f / static_cast( nLuxels ); + float flUValue = static_cast( static_cast( flULength * flOOLuxelScale ) + 1 ); + if ( flUValue > MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER ) + { + flUValue = MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER; + } + + float flVValue = static_cast( static_cast( flVLength * flOOLuxelScale ) + 1 ); + if ( flVValue > MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER ) + { + flVValue = MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER; + } + + // Swap if necessary. + bool bSwapped = false; + if ( bLongU ) + { + if ( flVValue > flUValue ) + { + bSwapped = true; + } + } + else + { + if ( flUValue > flVValue ) + { + bSwapped = true; + } + } + + m_nLuxelU = static_cast( flUValue ); + m_nLuxelV = static_cast( flVValue ); + + // Generate luxel coordinates. + for( int iBump = 0; iBump < NUM_BUMP_VECTS+1; ++iBump ) + { + m_LuxelCoords[iBump][(0+iOffset)%4].Init( 0.5f, 0.5f ); + m_LuxelCoords[iBump][(1+iOffset)%4].Init( 0.5f, flVValue + 0.5 ); + m_LuxelCoords[iBump][(2+iOffset)%4].Init( flUValue + 0.5, flVValue + 0.5 ); + m_LuxelCoords[iBump][(3+iOffset)%4].Init( flUValue + 0.5, 0.5f ); + } + + return bSwapped; +} + +//============================================================================= +// +// CDispNode Functions +// + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispNode::Init( void ) +{ + VectorClear( m_BBox[0] ); + VectorClear( m_BBox[1] ); + + m_ErrorTerm = 0.0f; + + m_VertIndex = -1; + + int j; + for( j = 0; j < MAX_NEIGHBOR_NODE_COUNT; j++ ) + { + m_NeighborVertIndices[j] = -1; + } + + for( j = 0; j < MAX_SURF_AT_NODE_COUNT; j++ ) + { + VectorClear( m_SurfBBoxes[j][0] ); + VectorClear( m_SurfBBoxes[j][1] ); + VectorClear( m_SurfPlanes[j].normal ); + m_SurfPlanes[j].dist = 0.0f; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void GetDispNodeTriVerts( CCoreDispInfo *pDisp, int nodeIndex, int triIndex, Vector& v1, Vector& v2, Vector& v3 ) +{ + // get the node + CCoreDispNode *pNode = pDisp->GetNode( nodeIndex ); + + switch( triIndex ) + { + case 0: + { + pDisp->GetVert( pNode->GetNeighborVertIndex( 4 ), v1 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 0 ), v2 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 3 ), v3 ); + return; + } + case 1: + { + pDisp->GetVert( pNode->GetNeighborVertIndex( 3 ), v1 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 0 ), v2 ); + pDisp->GetVert( pNode->GetCenterVertIndex(), v3 ); + return; + } + case 2: + { + pDisp->GetVert( pNode->GetNeighborVertIndex( 3 ), v1 ); + pDisp->GetVert( pNode->GetCenterVertIndex(), v2 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 5 ), v3 ); + return; + } + case 3: + { + pDisp->GetVert( pNode->GetNeighborVertIndex( 5 ), v1 ); + pDisp->GetVert( pNode->GetCenterVertIndex(), v2 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 2 ), v3 ); + return; + } + case 4: + { + pDisp->GetVert( pNode->GetNeighborVertIndex( 0 ), v1 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 6 ), v2 ); + pDisp->GetVert( pNode->GetCenterVertIndex(), v3 ); + return; + } + case 5: + { + pDisp->GetVert( pNode->GetCenterVertIndex(), v1 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 6 ), v2 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 1 ), v3 ); + return; + } + case 6: + { + pDisp->GetVert( pNode->GetCenterVertIndex(), v1 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 1 ), v2 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 2 ), v3 ); + return; + } + case 7: + { + pDisp->GetVert( pNode->GetNeighborVertIndex( 2 ), v1 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 1 ), v2 ); + pDisp->GetVert( pNode->GetNeighborVertIndex( 7 ), v3 ); + return; + } + default: { return; } + } +} + + +//============================================================================= +// +// CCoreDispInfo Functions +// + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CCoreDispInfo::CCoreDispInfo() +{ + m_pVerts = NULL; + m_RenderIndices = NULL; + m_Nodes = NULL; + m_pTris = NULL; + + // initialize the base surface data + m_Surf.Init(); + + // + // initialize the disp info + // + m_Power = 0; + m_Elevation = 0.0f; + m_RenderIndexCount = 0; + m_RenderCounter = 0; + m_bTouched = false; + + m_pNext = NULL; + + m_ppListBase = NULL; + m_ListSize = 0; + m_nListIndex = -1; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CCoreDispInfo::~CCoreDispInfo() +{ + if (m_pVerts) + delete [] m_pVerts; + if (m_RenderIndices) + delete [] m_RenderIndices; + if (m_Nodes) + delete [] m_Nodes; + if (m_pTris) + delete [] m_pTris; +} + + +#if 0 +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::InitSurf( int parentIndex, Vector points[4], Vector normals[4], + Vector2D texCoords[4], Vector2D lightCoords[4][4], int contents, int flags, + bool bGenerateSurfPointStart, Vector& startPoint, + bool bHasMappingAxes, Vector& uAxis, Vector& vAxis ) +{ + // save the "parent" index + m_Surf.m_Index = parentIndex; + + // + // save the surface points and point normals, texture coordinates, and + // lightmap coordinates + // + m_Surf.m_PointCount = CSurface::QUAD_POINT_COUNT; + for( int i = 0; i < CSurface::QUAD_POINT_COUNT; i++ ) + { + VectorCopy( points[i], m_Surf.m_Points[i] ); + + if( normals ) + { + VectorCopy( normals[i], m_Surf.m_pVerts[i].m_Normal ); + } + + if( texCoords ) + { + Vector2DCopy( texCoords[i], m_Surf.m_TexCoords[i] ); + } + + if( lightCoords ) + { + Assert( NUM_BUMP_VECTS == 3 ); + Vector2DCopy( lightCoords[0][i], m_Surf.m_LightCoords[i][0] ); + Vector2DCopy( lightCoords[1][i], m_Surf.m_LightCoords[i][1] ); + Vector2DCopy( lightCoords[2][i], m_Surf.m_LightCoords[i][2] ); + Vector2DCopy( lightCoords[3][i], m_Surf.m_LightCoords[i][3] ); + } + } + + // save the starting point + if( startPoint ) + { + VectorCopy( startPoint, m_Surf.m_PointStart ); + } + + // + // save the surface contents and flags + // + m_Contents = contents; + m_Flags = flags; + + // + // adjust surface points, texture coordinates, etc.... + // + if( bHasMappingAxes && ( m_Surf.m_PointStartIndex == -1 ) ) + { + GeneratePointStartIndexFromMappingAxes( uAxis, vAxis ); + } + else + { + // + // adjust the surf data + // + if( bGenerateSurfPointStart ) + { + GenerateSurfPointStartIndex(); + } + else + { + FindSurfPointStartIndex(); + } + } + + AdjustSurfPointData(); +} +#endif + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::InitDispInfo( int power, int minTess, float smoothingAngle, + float *alphas, Vector *dispVectorField, float *dispDistances ) +{ + Assert( power >= MIN_MAP_DISP_POWER && power <= MAX_MAP_DISP_POWER ); + + // + // general displacement data + // + m_Power = power; + + if ( ( minTess & 0x80000000 ) != 0 ) + { + // If the high bit is set, this represents FLAGS (SURF_NOPHYSICS_COLL, etc.) flags. + int nFlags = minTess; + nFlags &= ~0x80000000; + GetSurface()->SetFlags( nFlags ); + } + + // Allocate + initialize verts + int size = GetSize(); + m_pVerts = new CoreDispVert_t[size]; + + int nIndexCount = size * 2 * 3; + m_RenderIndices = new unsigned short[nIndexCount]; + + int nNodeCount = GetNodeCount(power); + m_Nodes = new CCoreDispNode[nNodeCount]; + + int i; + for( i = 0; i < size; i++ ) + { + m_pVerts[i].m_FieldVector.Init(); + m_pVerts[i].m_SubdivPos.Init(); + m_pVerts[i].m_SubdivNormal.Init(); + + m_pVerts[i].m_FieldDistance = 0.0f; + + m_pVerts[i].m_Vert.Init(); + m_pVerts[i].m_FlatVert.Init(); + m_pVerts[i].m_Normal.Init(); + m_pVerts[i].m_TangentS.Init(); + m_pVerts[i].m_TangentT.Init(); + m_pVerts[i].m_TexCoord.Init(); + + for( int j = 0; j < ( NUM_BUMP_VECTS + 1 ); j++ ) + { + m_pVerts[i].m_LuxelCoords[j].Init(); + } + + m_pVerts[i].m_Alpha = 0.0f; + } + + for( i = 0; i < nIndexCount; i++ ) + { + m_RenderIndices[i] = 0; + } + + for( i = 0; i < nNodeCount; i++ ) + { + m_Nodes[i].Init(); + } + + // + // save the displacement vector field and distances within the field + // offset have been combined with fieldvectors at this point!!! + // + if (alphas && dispVectorField && dispDistances) + { + for( i = 0; i < size; i++ ) + { + VectorCopy( dispVectorField[i], m_pVerts[i].m_FieldVector ); + m_pVerts[i].m_FieldDistance = dispDistances[i]; + m_pVerts[i].m_Alpha = alphas[i]; + } + } + + // Init triangle information. + int nTriCount = GetTriCount(); + if ( nTriCount != 0 ) + { + m_pTris = new CoreDispTri_t[nTriCount]; + if ( m_pTris ) + { + InitTris(); + } + } +} + + +void CCoreDispInfo::InitDispInfo( int power, int minTess, float smoothingAngle, const CDispVert *pVerts, + const CDispTri *pTris ) +{ + Vector vectors[MAX_DISPVERTS]; + float dists[MAX_DISPVERTS]; + float alphas[MAX_DISPVERTS]; + + int nVerts = NUM_DISP_POWER_VERTS( power ); + for ( int i=0; i < nVerts; i++ ) + { + vectors[i] = pVerts[i].m_vVector; + dists[i] = pVerts[i].m_flDist; + alphas[i] = pVerts[i].m_flAlpha; + } + + InitDispInfo( power, minTess, smoothingAngle, alphas, vectors, dists ); + + int nTris = NUM_DISP_POWER_TRIS( power ); + for ( int iTri = 0; iTri < nTris; ++iTri ) + { + m_pTris[iTri].m_uiTags = pTris[iTri].m_uiTags; + } +} + + +void CCoreDispInfo::SetDispUtilsHelperInfo( CCoreDispInfo **ppListBase, int listSize ) +{ + m_ppListBase = ppListBase; + m_ListSize = listSize; +} + +const CPowerInfo* CCoreDispInfo::GetPowerInfo() const +{ + return ::GetPowerInfo( GetPower() ); +} + +CDispNeighbor* CCoreDispInfo::GetEdgeNeighbor( int index ) +{ + return GetSurface()->GetEdgeNeighbor( index ); +} + +CDispCornerNeighbors* CCoreDispInfo::GetCornerNeighbors( int index ) +{ + return GetSurface()->GetCornerNeighbors( index ); +} + +CDispUtilsHelper* CCoreDispInfo::GetDispUtilsByIndex( int index ) +{ + Assert( m_ppListBase ); + return index == 0xFFFF ? 0 : m_ppListBase[index]; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::BuildTriTLtoBR( int ndx ) +{ + // get width and height of displacement maps + int nWidth = ( ( 1 << m_Power ) + 1 ); + + m_RenderIndices[m_RenderIndexCount] = ndx; + m_RenderIndices[m_RenderIndexCount+1] = ndx + nWidth; + m_RenderIndices[m_RenderIndexCount+2] = ndx + 1; + m_RenderIndexCount += 3; + + m_RenderIndices[m_RenderIndexCount] = ndx + 1; + m_RenderIndices[m_RenderIndexCount+1] = ndx + nWidth; + m_RenderIndices[m_RenderIndexCount+2] = ndx + nWidth + 1; + m_RenderIndexCount += 3; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::BuildTriBLtoTR( int ndx ) +{ + // get width and height of displacement maps + int nWidth = ( ( 1 << m_Power ) + 1 ); + + m_RenderIndices[m_RenderIndexCount] = ndx; + m_RenderIndices[m_RenderIndexCount+1] = ndx + nWidth; + m_RenderIndices[m_RenderIndexCount+2] = ndx + nWidth + 1; + m_RenderIndexCount += 3; + + m_RenderIndices[m_RenderIndexCount] = ndx; + m_RenderIndices[m_RenderIndexCount+1] = ndx + nWidth + 1; + m_RenderIndices[m_RenderIndexCount+2] = ndx + 1; + m_RenderIndexCount += 3; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GenerateCollisionSurface( void ) +{ + // get width and height of displacement maps + int nWidth = ( ( 1 << m_Power ) + 1 ); + int nHeight = ( ( 1 << m_Power ) + 1 ); + + // + // generate a fan tesselated (at quadtree node) rendering index list + // + m_RenderIndexCount = 0; + for ( int iV = 0; iV < ( nHeight - 1 ); iV++ ) + { + for ( int iU = 0; iU < ( nWidth - 1 ); iU++ ) + { + int ndx = ( iV * nWidth ) + iU; + + // test whether or not the index is odd + bool bOdd = ( ( ndx %2 ) == 1 ); + + // Top Left to Bottom Right + if( bOdd ) + { + BuildTriTLtoBR( ndx ); + } + // Bottom Left to Top Right + else + { + BuildTriBLtoTR( ndx ); + } + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GenerateCollisionData( void ) +{ + GenerateCollisionSurface(); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcTriSurfPlanes( int nodeIndex, int indices[8][3] ) +{ + // + // calculate plane info for each face + // + for( int i = 0; i < 8; i++ ) + { + Vector v[3]; + VectorCopy( m_pVerts[indices[i][0]].m_Vert, v[0] ); + VectorCopy( m_pVerts[indices[i][1]].m_Vert, v[1] ); + VectorCopy( m_pVerts[indices[i][2]].m_Vert, v[2] ); + + Vector seg[2]; + VectorSubtract( v[1], v[0], seg[0] ); + VectorSubtract( v[2], v[0], seg[1] ); + + Vector normal; + CrossProduct( seg[1], seg[0], normal ); + VectorNormalize( normal ); + float dist = DotProduct( v[0], normal ); + + m_Nodes[nodeIndex].SetTriPlane( i, normal, dist ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcRayBoundingBoxes( int nodeIndex, int indices[8][3] ) +{ + Vector triMin, triMax; + + for( int i = 0; i < 4; i++ ) + { + triMin[0] = triMax[0] = m_pVerts[indices[(i*2)][0]].m_Vert[0]; + triMin[1] = triMax[1] = m_pVerts[indices[(i*2)][0]].m_Vert[1]; + triMin[2] = triMax[2] = m_pVerts[indices[(i*2)][0]].m_Vert[2]; + + for( int j = 0; j < 3; j++ ) + { + // + // minimum + // + if( triMin[0] > m_pVerts[indices[(i*2)][j]].m_Vert[0] ) + triMin[0] = m_pVerts[indices[(i*2)][j]].m_Vert[0]; + if( triMin[0] > m_pVerts[indices[(i*2+1)][j]].m_Vert[0] ) + triMin[0] = m_pVerts[indices[(i*2+1)][j]].m_Vert[0]; + + if( triMin[1] > m_pVerts[indices[(i*2)][j]].m_Vert[1] ) + triMin[1] = m_pVerts[indices[(i*2)][j]].m_Vert[1]; + if( triMin[1] > m_pVerts[indices[(i*2+1)][j]].m_Vert[1] ) + triMin[1] = m_pVerts[indices[(i*2+1)][j]].m_Vert[1]; + + if( triMin[2] > m_pVerts[indices[(i*2)][j]].m_Vert[2] ) + triMin[2] = m_pVerts[indices[(i*2)][j]].m_Vert[2]; + if( triMin[2] > m_pVerts[indices[(i*2+1)][j]].m_Vert[2] ) + triMin[2] = m_pVerts[indices[(i*2+1)][j]].m_Vert[2]; + + // + // maximum + // + if( triMax[0] < m_pVerts[indices[(i*2)][j]].m_Vert[0] ) + triMax[0] = m_pVerts[indices[(i*2)][j]].m_Vert[0]; + if( triMax[0] < m_pVerts[indices[(i*2+1)][j]].m_Vert[0] ) + triMax[0] = m_pVerts[indices[(i*2+1)][j]].m_Vert[0]; + + if( triMax[1] < m_pVerts[indices[(i*2)][j]].m_Vert[1] ) + triMax[1] = m_pVerts[indices[(i*2)][j]].m_Vert[1]; + if( triMax[1] < m_pVerts[indices[(i*2+1)][j]].m_Vert[1] ) + triMax[1] = m_pVerts[indices[(i*2+1)][j]].m_Vert[1]; + + if( triMax[2] < m_pVerts[indices[(i*2)][j]].m_Vert[2] ) + triMax[2] = m_pVerts[indices[(i*2)][j]].m_Vert[2]; + if( triMax[2] < m_pVerts[indices[(i*2+1)][j]].m_Vert[2] ) + triMax[2] = m_pVerts[indices[(i*2+1)][j]].m_Vert[2]; + } + + m_Nodes[nodeIndex].SetRayBoundingBox( i, triMin, triMax ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcTriSurfBoundingBoxes( int nodeIndex, int indices[8][3] ) +{ + Vector triMin, triMax; + + for( int i = 0; i < 8; i++ ) + { + m_Nodes[nodeIndex].GetTriBoundingBox( i, triMin, triMax ); + + for( int j = 0; j < 3; j++ ) + { + // + // minimum + // + if( triMin[0] > m_pVerts[indices[i][j]].m_Vert[0] ) + triMin[0] = m_pVerts[indices[i][j]].m_Vert[0]; + + if( triMin[1] > m_pVerts[indices[i][j]].m_Vert[1] ) + triMin[1] = m_pVerts[indices[i][j]].m_Vert[1]; + + if( triMin[2] > m_pVerts[indices[i][j]].m_Vert[2] ) + triMin[2] = m_pVerts[indices[i][j]].m_Vert[2]; + + // + // maximum + // + if( triMax[0] < m_pVerts[indices[i][j]].m_Vert[0] ) + triMax[0] = m_pVerts[indices[i][j]].m_Vert[0]; + + if( triMax[1] < m_pVerts[indices[i][j]].m_Vert[1] ) + triMax[1] = m_pVerts[indices[i][j]].m_Vert[1]; + + if( triMax[2] < m_pVerts[indices[i][j]].m_Vert[2] ) + triMax[2] = m_pVerts[indices[i][j]].m_Vert[2]; + } + + m_Nodes[nodeIndex].SetTriBoundingBox( i, triMin, triMax ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcTriSurfIndices( int nodeIndex, int indices[8][3] ) +{ + indices[0][0] = m_Nodes[nodeIndex].GetNeighborVertIndex( 4 ); + indices[0][1] = m_Nodes[nodeIndex].GetNeighborVertIndex( 0 ); + indices[0][2] = m_Nodes[nodeIndex].GetNeighborVertIndex( 3 ); + + indices[1][0] = m_Nodes[nodeIndex].GetNeighborVertIndex( 3 ); + indices[1][1] = m_Nodes[nodeIndex].GetNeighborVertIndex( 0 ); + indices[1][2] = m_Nodes[nodeIndex].GetCenterVertIndex(); + + indices[2][0] = m_Nodes[nodeIndex].GetNeighborVertIndex( 3 ); + indices[2][1] = m_Nodes[nodeIndex].GetCenterVertIndex(); + indices[2][2] = m_Nodes[nodeIndex].GetNeighborVertIndex( 5 ); + + indices[3][0] = m_Nodes[nodeIndex].GetNeighborVertIndex( 5 ); + indices[3][1] = m_Nodes[nodeIndex].GetCenterVertIndex(); + indices[3][2] = m_Nodes[nodeIndex].GetNeighborVertIndex( 2 ); + + indices[4][0] = m_Nodes[nodeIndex].GetNeighborVertIndex( 0 ); + indices[4][1] = m_Nodes[nodeIndex].GetNeighborVertIndex( 6 ); + indices[4][2] = m_Nodes[nodeIndex].GetCenterVertIndex(); + + indices[5][0] = m_Nodes[nodeIndex].GetCenterVertIndex(); + indices[5][1] = m_Nodes[nodeIndex].GetNeighborVertIndex( 6 ); + indices[5][2] = m_Nodes[nodeIndex].GetNeighborVertIndex( 1 ); + + indices[6][0] = m_Nodes[nodeIndex].GetCenterVertIndex(); + indices[6][1] = m_Nodes[nodeIndex].GetNeighborVertIndex( 1 ); + indices[6][2] = m_Nodes[nodeIndex].GetNeighborVertIndex( 2 ); + + indices[7][0] = m_Nodes[nodeIndex].GetNeighborVertIndex( 2 ); + indices[7][1] = m_Nodes[nodeIndex].GetNeighborVertIndex( 1 ); + indices[7][2] = m_Nodes[nodeIndex].GetNeighborVertIndex( 7 ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcTriSurfInfoAtNode( int nodeIndex ) +{ + int indices[8][3]; + + CalcTriSurfIndices( nodeIndex, indices ); + CalcTriSurfBoundingBoxes( nodeIndex, indices ); + CalcRayBoundingBoxes( nodeIndex, indices ); + CalcTriSurfPlanes( nodeIndex, indices ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcMinMaxBoundingBoxAtNode( int nodeIndex, Vector& bMin, Vector& bMax ) +{ + // get the child node index + int childNodeIndex = GetNodeChild( m_Power, nodeIndex, 4 ); + + // get initial bounding box values + m_Nodes[childNodeIndex].GetBoundingBox( bMin, bMax ); + + Vector nodeMin, nodeMax; + for( int i = 1, j = 5; i < 4; i++, j++ ) + { + // + // get the child node bounding box + // + childNodeIndex = GetNodeChild( m_Power, nodeIndex, j ); + m_Nodes[childNodeIndex].GetBoundingBox( nodeMin, nodeMax ); + + // minimum + if( bMin[0] > nodeMin[0] ) + bMin[0] = nodeMin[0]; + + if( bMin[1] > nodeMin[1] ) + bMin[1] = nodeMin[1]; + + if( bMin[2] > nodeMin[2] ) + bMin[2] = nodeMin[2]; + + // maximum + if( bMax[0] < nodeMax[0] ) + bMax[0] = nodeMax[0]; + + if( bMax[1] < nodeMax[1] ) + bMax[1] = nodeMax[1]; + + if( bMax[2] < nodeMax[2] ) + bMax[2] = nodeMax[2]; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcBoundingBoxAtNode( int nodeIndex ) +{ + Vector bMin, bMax; + + // + // initialize the minimum and maximum values for the bounding box + // + int level = GetNodeLevel( nodeIndex ); + + int vertIndex = m_Nodes[nodeIndex].GetCenterVertIndex(); + if( level == m_Power ) + { + VectorCopy( m_pVerts[vertIndex].m_Vert, bMin ); + VectorCopy( m_pVerts[vertIndex].m_Vert, bMax ); + } + else + { + CalcMinMaxBoundingBoxAtNode( nodeIndex, bMin, bMax ); + + if( bMin[0] > m_pVerts[vertIndex].m_Vert[0] ) + bMin[0] = m_pVerts[vertIndex].m_Vert[0]; + + if( bMin[1] > m_pVerts[vertIndex].m_Vert[1] ) + bMin[1] = m_pVerts[vertIndex].m_Vert[1]; + + if( bMin[2] > m_pVerts[vertIndex].m_Vert[2] ) + bMin[2] = m_pVerts[vertIndex].m_Vert[2]; + + + if( bMax[0] < m_pVerts[vertIndex].m_Vert[0] ) + bMax[0] = m_pVerts[vertIndex].m_Vert[0]; + + if( bMax[1] < m_pVerts[vertIndex].m_Vert[1] ) + bMax[1] = m_pVerts[vertIndex].m_Vert[1]; + + if( bMax[2] < m_pVerts[vertIndex].m_Vert[2] ) + bMax[2] = m_pVerts[vertIndex].m_Vert[2]; + } + + for( int i = 0; i < 8; i++ ) + { + int neighborVertIndex = m_Nodes[nodeIndex].GetNeighborVertIndex( i ); + + // + // minimum + // + if( bMin[0] > m_pVerts[neighborVertIndex].m_Vert[0] ) + bMin[0] = m_pVerts[neighborVertIndex].m_Vert[0]; + + if( bMin[1] > m_pVerts[neighborVertIndex].m_Vert[1] ) + bMin[1] = m_pVerts[neighborVertIndex].m_Vert[1]; + + if( bMin[2] > m_pVerts[neighborVertIndex].m_Vert[2] ) + bMin[2] = m_pVerts[neighborVertIndex].m_Vert[2]; + + // + // maximum + // + if( bMax[0] < m_pVerts[neighborVertIndex].m_Vert[0] ) + bMax[0] = m_pVerts[neighborVertIndex].m_Vert[0]; + + if( bMax[1] < m_pVerts[neighborVertIndex].m_Vert[1] ) + bMax[1] = m_pVerts[neighborVertIndex].m_Vert[1]; + + if( bMax[2] < m_pVerts[neighborVertIndex].m_Vert[2] ) + bMax[2] = m_pVerts[neighborVertIndex].m_Vert[2]; + } + + m_Nodes[nodeIndex].SetBoundingBox( bMin, bMax ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +float CCoreDispInfo::GetMaxErrorFromChildren( int nodeIndex, int level ) +{ + // + // check for children nodes + // + if( level == m_Power ) + return 0.0f; + + // + // get the child's error term and save the greatest error -- SW, SE, NW, NE + // + float errorTerm = 0.0f; + for( int i = 4; i < 8; i++ ) + { + int childIndex = GetNodeChild( m_Power, nodeIndex, i ); + + float nodeErrorTerm = m_Nodes[childIndex].GetErrorTerm(); + if( errorTerm < nodeErrorTerm ) + { + errorTerm = nodeErrorTerm; + } + } + + return errorTerm; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcErrorTermAtNode( int nodeIndex, int level ) +{ + if( level == m_Power ) + return; + + // + // get the vertex indices + // + int neighborVertIndices[9]; + for( int i = 0; i < 8; i++ ) + { + neighborVertIndices[i] = m_Nodes[nodeIndex].GetNeighborVertIndex( i ); + } + neighborVertIndices[8] = m_Nodes[nodeIndex].GetCenterVertIndex(); + + + // + // calculate the error terms + // + Vector segment; + Vector v; + + VectorAdd( m_pVerts[neighborVertIndices[5]].m_Vert, m_pVerts[neighborVertIndices[4]].m_Vert, v ); + VectorScale( v, 0.5f, v ); + VectorSubtract( m_pVerts[neighborVertIndices[0]].m_Vert, v, segment ); + float errorTerm = ( float )VectorLength( segment ); + + VectorAdd( m_pVerts[neighborVertIndices[5]].m_Vert, m_pVerts[neighborVertIndices[6]].m_Vert, v ); + VectorScale( v, 0.5f, v ); + VectorSubtract( m_pVerts[neighborVertIndices[1]].m_Vert, v, segment ); + if( errorTerm < ( float )VectorLength( segment ) ) + errorTerm = ( float )VectorLength( segment ); + + VectorAdd( m_pVerts[neighborVertIndices[6]].m_Vert, m_pVerts[neighborVertIndices[7]].m_Vert, v ); + VectorScale( v, 0.5f, v ); + VectorSubtract( m_pVerts[neighborVertIndices[2]].m_Vert, v, segment ); + if( errorTerm < ( float )VectorLength( segment ) ) + errorTerm = ( float )VectorLength( segment ); + + VectorAdd( m_pVerts[neighborVertIndices[7]].m_Vert, m_pVerts[neighborVertIndices[4]].m_Vert, v ); + VectorScale( v, 0.5f, v ); + VectorSubtract( m_pVerts[neighborVertIndices[3]].m_Vert, v, segment ); + if( errorTerm < ( float )VectorLength( segment ) ) + errorTerm = ( float )VectorLength( segment ); + + VectorAdd( m_pVerts[neighborVertIndices[4]].m_Vert, m_pVerts[neighborVertIndices[6]].m_Vert, v ); + VectorScale( v, 0.5f, v ); + VectorSubtract( m_pVerts[neighborVertIndices[8]].m_Vert, v, segment ); + if( errorTerm < ( float )VectorLength( segment ) ) + errorTerm = ( float )VectorLength( segment ); + + VectorAdd( m_pVerts[neighborVertIndices[5]].m_Vert, m_pVerts[neighborVertIndices[7]].m_Vert, v ); + VectorScale( v, 0.5f, v ); + VectorSubtract( m_pVerts[neighborVertIndices[8]].m_Vert, v, segment ); + if( errorTerm < ( float )VectorLength( segment ) ) + errorTerm = ( float )VectorLength( segment ); + + // + // add the max child's error term + // + errorTerm += GetMaxErrorFromChildren( nodeIndex, level ); + + // set the error term + m_Nodes[nodeIndex].SetErrorTerm( errorTerm ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcNeighborVertIndicesAtNode( int nodeIndex, int level ) +{ + // calculate the shift in direction in the matrix + int shift = ( 1 << ( m_Power - level ) ); + + // calculate the width, height of the displacement surface (are uniform) + int extent = ( ( 1 << m_Power ) + 1 ); + + // + // get the neighbor vertex indices (defining the surface at the node level) + // + for( int direction = 0; direction < 8; direction++ ) + { + // + // get the parent vertex index in component form + // + int posX = m_Nodes[nodeIndex].GetCenterVertIndex() % extent; + int posY = m_Nodes[nodeIndex].GetCenterVertIndex() / extent; + + // + // calculate the neighboring vertex indices for surface rendering + // + bool bError = false; + switch( direction ) + { + case WEST: { posX -= shift; break; } + case NORTH: { posY += shift; break; } + case EAST: { posX += shift; break; } + case SOUTH: { posY -= shift; break; } + case SOUTHWEST: { posX -= shift; posY -= shift; break; } + case SOUTHEAST: { posX += shift; posY -= shift; break; } + case NORTHWEST: { posX -= shift; posY += shift; break; } + case NORTHEAST: { posX += shift; posY += shift; break; } + default: { bError = true; break; } + } + + if( bError ) + { + m_Nodes[nodeIndex].SetNeighborVertIndex( direction, -99999 ); + } + else + { + m_Nodes[nodeIndex].SetNeighborVertIndex( direction, ( ( posY * extent ) + posX ) ); + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcNodeInfo( int nodeIndex, int terminationLevel ) +{ + // get the level of the current node + int level = GetNodeLevel( nodeIndex ); + + // + // get the node data at the termination level + // + if( level == terminationLevel ) + { + // get the neighbor vertex indices (used to create surface at node level) + CalcNeighborVertIndicesAtNode( nodeIndex, level ); + + // get the neighbor node indices + //CalcNeighborNodeIndicesAtNode( nodeIndex, level ); + + // calculate the error term at the node + CalcErrorTermAtNode( nodeIndex, level ); + + // calcluate the axial-aligned bounding box at the node + CalcBoundingBoxAtNode( nodeIndex ); + + // calculate the triangular surface info at the node + CalcTriSurfInfoAtNode( nodeIndex ); + + return; + } + + // + // continue recursion (down to nodes "children") + // + for( int i = 4; i < 8; i++ ) + { + int childIndex = GetNodeChild( m_Power, nodeIndex, i ); + CalcNodeInfo( childIndex, terminationLevel ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CCoreDispInfo::GetNodeVertIndexFromParentIndex( int level, int parentVertIndex, int direction ) +{ + // calculate the "shift" + int shift = ( 1 << ( m_Power - ( level + 1 ) ) ); + + // calculate the width and height of displacement (is uniform) + int extent = ( ( 1 << m_Power ) + 1 ); + + // get the parent vertex index in component form + int posX = parentVertIndex % extent; + int posY = parentVertIndex / extent; + + // + // calculate the child index based on the parent index and child + // direction + // + switch( direction ) + { + case SOUTHWEST: { posX -= shift; posY -= shift; break; } + case SOUTHEAST: { posX += shift; posY -= shift; break; } + case NORTHWEST: { posX -= shift; posY += shift; break; } + case NORTHEAST: { posX += shift; posY += shift; break; } + default: return -99999; + } + + // return the child vertex index + return ( ( posY * extent ) + posX ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcVertIndicesAtNodes( int nodeIndex ) +{ + // + // check for recursion termination ( node level = power ) + // + int level = GetNodeLevel( nodeIndex ); + if( level == m_Power ) + return; + + // + // get the children indices - SW, SE, NW, NE + // + int childIndices[4]; + int i, j; + for( i = 0, j = 4; i < 4; i++, j++ ) + { + childIndices[i] = GetNodeChild( m_Power, nodeIndex, j ); + int centerIndex = GetNodeVertIndexFromParentIndex( level, m_Nodes[nodeIndex].GetCenterVertIndex(), j ); + m_Nodes[childIndices[i]].SetCenterVertIndex( centerIndex ); + } + + // + // calculate the children's node vertex indices + // + for( i = 0; i < 4; i++ ) + { + CalcVertIndicesAtNodes( childIndices[i] ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GenerateLODTree( void ) +{ + // + // calculate the displacement surface's vertex index at each quad-tree node + // centroid + // + int size = GetSize(); + int initialIndex = ( ( size - 1 ) >> 1 ); + m_Nodes[0].SetCenterVertIndex( initialIndex ); + CalcVertIndicesAtNodes( 0 ); + + // + // calculate the error terms, bounding boxes, and neighboring vertex indices + // at each node + // + for( int i = m_Power; i > 0; i-- ) + { + CalcNodeInfo( 0, i ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcDispSurfCoords( bool bLightMap, int lightmapID ) +{ + // + // get base surface texture coords + // + Vector2D texCoords[4]; + Vector2D luxelCoords[4]; + CCoreDispSurface *pSurf = GetSurface(); + + int i; + for( i = 0; i < 4; i++ ) + { + pSurf->GetTexCoord( i, texCoords[i] ); + pSurf->GetLuxelCoord( lightmapID, i, luxelCoords[i] ); + } + + // + // get images width and intervals along the edge + // + int postSpacing = GetPostSpacing(); + float ooInt = ( 1.0f / ( float )( postSpacing - 1 ) ); + + // + // calculate the parallel edge intervals + // + Vector2D edgeInt[2]; + if( !bLightMap ) + { + Vector2DSubtract( texCoords[1], texCoords[0], edgeInt[0] ); + Vector2DSubtract( texCoords[2], texCoords[3], edgeInt[1] ); + } + else + { + Vector2DSubtract( luxelCoords[1], luxelCoords[0], edgeInt[0] ); + Vector2DSubtract( luxelCoords[2], luxelCoords[3], edgeInt[1] ); + } + Vector2DMultiply( edgeInt[0], ooInt, edgeInt[0] ); + Vector2DMultiply( edgeInt[1], ooInt, edgeInt[1] ); + + // + // calculate the displacement points + // + for( i = 0; i < postSpacing; i++ ) + { + // + // position along parallel edges (start and end for a perpendicular segment) + // + Vector2D endPts[2]; + Vector2DMultiply( edgeInt[0], ( float )i, endPts[0] ); + Vector2DMultiply( edgeInt[1], ( float )i, endPts[1] ); + if( !bLightMap ) + { + Vector2DAdd( endPts[0], texCoords[0], endPts[0] ); + Vector2DAdd( endPts[1], texCoords[3], endPts[1] ); + } + else + { + Vector2DAdd( endPts[0], luxelCoords[0], endPts[0] ); + Vector2DAdd( endPts[1], luxelCoords[3], endPts[1] ); + } + + // + // interval length for perpendicular edge + // + Vector2D seg, segInt; + Vector2DSubtract( endPts[1], endPts[0], seg ); + Vector2DMultiply( seg, ooInt, segInt ); + + // + // calculate the material (texture or light) coordinate at each point + // + for( int j = 0; j < postSpacing; j++ ) + { + Vector2DMultiply( segInt, ( float )j, seg ); + + if( !bLightMap ) + { + Vector2DAdd( endPts[0], seg, m_pVerts[i*postSpacing+j].m_TexCoord ); + } + else + { + Vector2DAdd( endPts[0], seg, m_pVerts[i*postSpacing+j].m_LuxelCoords[lightmapID] ); + } + } + } +} + +#if 0 +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcDispSurfAlphas( void ) +{ + // + // get images width and intervals along the edge + // + int postSpacing = GetPostSpacing(); + float ooInt = ( 1.0f / ( float )( postSpacing - 1 ) ); + + // + // calculate the parallel edge intervals + // + float edgeInt[2]; + edgeInt[0] = m_Surf.m_Alpha[1] - m_Surf.m_Alpha[0]; + edgeInt[1] = m_Surf.m_Alpha[2] - m_Surf.m_Alpha[3]; + edgeInt[0] *= ooInt; + edgeInt[1] *= ooInt; + + // + // calculate the displacement points + // + for( int i = 0; i < postSpacing; i++ ) + { + // + // position along parallel edges (start and end for a perpendicular segment) + // + float endValues[2]; + + endValues[0] = edgeInt[0] * ( float )i; + endValues[1] = edgeInt[1] * ( float )i; + endValues[0] += m_Surf.m_Alpha[0]; + endValues[1] += m_Surf.m_Alpha[3]; + + // + // interval length for perpendicular edge + // + float seg, segInt; + seg = endValues[1] - endValues[0]; + segInt = seg * ooInt; + + // + // calculate the alpha value at each point + // + for( int j = 0; j < postSpacing; j++ ) + { + seg = segInt * ( float )j; + m_Alphas[i*postSpacing+j] = endValues[0] + seg; + } + } +} +#endif + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GenerateDispSurfTangentSpaces( void ) +{ + // + // get texture axes from base surface + // + CCoreDispSurface *pSurf = GetSurface(); + Vector sAxis, tAxis; + pSurf->GetSAxis( sAxis ); + pSurf->GetTAxis( tAxis ); + + // + // calculate the tangent spaces + // + int size = GetSize(); + for( int i = 0; i < size; i++ ) + { + // + // create the axes - normals, tangents, and binormals + // + VectorCopy( tAxis, m_pVerts[i].m_TangentT ); + VectorNormalize( m_pVerts[i].m_TangentT ); + CrossProduct( m_pVerts[i].m_Normal, m_pVerts[i].m_TangentT, m_pVerts[i].m_TangentS ); + VectorNormalize( m_pVerts[i].m_TangentS ); + CrossProduct( m_pVerts[i].m_TangentS, m_pVerts[i].m_Normal, m_pVerts[i].m_TangentT ); + VectorNormalize( m_pVerts[i].m_TangentT ); + + Vector tmpVect; + Vector planeNormal; + pSurf->GetNormal( planeNormal ); + CrossProduct( sAxis, tAxis, tmpVect ); + if( DotProduct( planeNormal, tmpVect ) > 0.0f ) + { + VectorScale( m_pVerts[i].m_TangentS, -1.0f, m_pVerts[i].m_TangentS ); + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::CalcNormalFromEdges( int indexRow, int indexCol, bool bIsEdge[4], + Vector& normal ) +{ + // get the post spacing (size/interval of displacement surface) + int postSpacing = ( ( 1 << m_Power ) + 1 ); + + // initialize the normal accumulator - counter + Vector accumNormal; + int normalCount = 0; + + VectorClear( accumNormal ); + + Vector tmpVect[2]; + Vector tmpNormal; + + // + // check quadrant I (posX, posY) + // + if( bIsEdge[1] && bIsEdge[2] ) + { + // tri i + VectorSubtract( m_pVerts[(indexCol+1)*postSpacing+indexRow].m_Vert, m_pVerts[indexCol*postSpacing+indexRow].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[indexCol*postSpacing+(indexRow+1)].m_Vert, m_pVerts[indexCol*postSpacing+indexRow].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + + // tri 2 + VectorSubtract( m_pVerts[(indexCol+1)*postSpacing+indexRow].m_Vert, m_pVerts[indexCol*postSpacing+(indexRow+1)].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[(indexCol+1)*postSpacing+(indexRow+1)].m_Vert, m_pVerts[indexCol*postSpacing+(indexRow+1)].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + } + + // + // check quadrant II (negX, posY) + // + if( bIsEdge[0] && bIsEdge[1] ) + { + // tri i + VectorSubtract( m_pVerts[(indexCol+1)*postSpacing+(indexRow-1)].m_Vert, m_pVerts[indexCol*postSpacing+(indexRow-1)].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[indexCol*postSpacing+indexRow].m_Vert, m_pVerts[indexCol*postSpacing+(indexRow-1)].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + + // tri 2 + VectorSubtract( m_pVerts[(indexCol+1)*postSpacing+(indexRow-1)].m_Vert, m_pVerts[indexCol*postSpacing+indexRow].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[(indexCol+1)*postSpacing+indexRow].m_Vert, m_pVerts[indexCol*postSpacing+indexRow].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + } + + // + // check quadrant III (negX, negY) + // + if( bIsEdge[0] && bIsEdge[3] ) + { + // tri i + VectorSubtract( m_pVerts[indexCol*postSpacing+(indexRow-1)].m_Vert, m_pVerts[(indexCol-1)*postSpacing+(indexRow-1)].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[(indexCol-1)*postSpacing+indexRow].m_Vert, m_pVerts[(indexCol-1)*postSpacing+(indexRow-1)].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + + // tri 2 + VectorSubtract( m_pVerts[indexCol*postSpacing+(indexRow-1)].m_Vert, m_pVerts[(indexCol-1)*postSpacing+indexRow].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[indexCol*postSpacing+indexRow].m_Vert, m_pVerts[(indexCol-1)*postSpacing+indexRow].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + } + + // + // check quadrant IV (posX, negY) + // + if( bIsEdge[2] && bIsEdge[3] ) + { + // tri i + VectorSubtract( m_pVerts[indexCol*postSpacing+indexRow].m_Vert, m_pVerts[(indexCol-1)*postSpacing+indexRow].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[(indexCol-1)*postSpacing+(indexRow+1)].m_Vert, m_pVerts[(indexCol-1)*postSpacing+indexRow].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + + // tri 2 + VectorSubtract( m_pVerts[indexCol*postSpacing+indexRow].m_Vert, m_pVerts[(indexCol-1)*postSpacing+(indexRow+1)].m_Vert, tmpVect[0] ); + VectorSubtract( m_pVerts[indexCol*postSpacing+(indexRow+1)].m_Vert, m_pVerts[(indexCol-1)*postSpacing+(indexRow+1)].m_Vert, tmpVect[1] ); + CrossProduct( tmpVect[1], tmpVect[0], tmpNormal ); + VectorNormalize( tmpNormal ); + VectorAdd( accumNormal, tmpNormal, accumNormal ); + normalCount++; + } + + VectorScale( accumNormal, ( 1.0f / ( float )normalCount ), normal ); +} + + +//----------------------------------------------------------------------------- +// Purpose: This function determines if edges exist in each of the directions +// off of the given point (given in component form). We know ahead of +// time that there are only 4 possibilities. +// +// 1 "directions" +// 0 + 2 +// 3 +// +// Input: indexRow - row position +// indexCol - col position +// direction - the direction (edge) currently being evaluated +// postSpacing - the number of intervals in the row and col directions +// Output: the edge existed? (true/false) +//----------------------------------------------------------------------------- +bool CCoreDispInfo::DoesEdgeExist( int indexRow, int indexCol, int direction, int postSpacing ) +{ + switch( direction ) + { + case 0: + // left edge + if( ( indexRow - 1 ) < 0 ) + return false; + return true; + case 1: + // top edge + if( ( indexCol + 1 ) > ( postSpacing - 1 ) ) + return false; + return true; + case 2: + // right edge + if( ( indexRow + 1 ) > ( postSpacing - 1 ) ) + return false; + return true; + case 3: + // bottom edge + if( ( indexCol - 1 ) < 0 ) + return false; + return true; + default: + return false; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GenerateDispSurfNormals( void ) +{ + // get the post spacing (size/interval of displacement surface) + int postSpacing = GetPostSpacing(); + + // + // generate the normals at each displacement surface vertex + // + for( int i = 0; i < postSpacing; i++ ) + { + for( int j = 0; j < postSpacing; j++ ) + { + bool bIsEdge[4]; + + // edges + for( int k = 0; k < 4; k++ ) + { + bIsEdge[k] = DoesEdgeExist( j, i, k, postSpacing ); + } + + Vector normal; + CalcNormalFromEdges( j, i, bIsEdge, normal ); + + // save generated normal + VectorCopy( normal, m_pVerts[i*postSpacing+j].m_Normal ); + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GenerateDispSurf( void ) +{ + int i; + CCoreDispSurface *pSurf = GetSurface(); + Vector points[4]; + for( i = 0; i < 4; i++ ) + { + pSurf->GetPoint( i, points[i] ); + } + + // + // get the spacing (interval = width/height, are equal because it is uniform) along the edge + // + int postSpacing = GetPostSpacing(); + float ooInt = 1.0f / ( float )( postSpacing - 1 ); + + // + // calculate the opposite edge intervals + // + Vector edgeInt[2]; + VectorSubtract( points[1], points[0], edgeInt[0] ); + VectorScale( edgeInt[0], ooInt, edgeInt[0] ); + VectorSubtract( points[2], points[3], edgeInt[1] ); + VectorScale( edgeInt[1], ooInt, edgeInt[1] ); + + Vector elevNormal; + elevNormal.Init(); + if( m_Elevation != 0.0f ) + { + pSurf->GetNormal( elevNormal ); + VectorScale( elevNormal, m_Elevation, elevNormal ); + } + + // + // calculate the displaced vertices + // + for( i = 0; i < postSpacing; i++ ) + { + // + // calculate segment interval between opposite edges + // + Vector endPts[2]; + VectorScale( edgeInt[0], ( float )i, endPts[0] ); + VectorAdd( endPts[0], points[0], endPts[0] ); + VectorScale( edgeInt[1], ( float )i, endPts[1] ); + VectorAdd( endPts[1], points[3], endPts[1] ); + + Vector seg, segInt; + VectorSubtract( endPts[1], endPts[0], seg ); + VectorScale( seg, ooInt, segInt ); + + // + // calculate the surface vertices + // + for( int j = 0; j < postSpacing; j++ ) + { + int ndx = i * postSpacing + j; + + CoreDispVert_t *pVert = &m_pVerts[ndx]; + + // calculate the flat surface position -- saved separately + pVert->m_FlatVert = endPts[0] + ( segInt * ( float )j ); + + // start with the base surface position + pVert->m_Vert = pVert->m_FlatVert; + + // add the elevation vector -- if it exists + if( m_Elevation != 0.0f ) + { + pVert->m_Vert += elevNormal; + } + + // add the subdivision surface position + pVert->m_Vert += pVert->m_SubdivPos; + + // add the displacement field direction(normalized) and distance + pVert->m_Vert += pVert->m_FieldVector * pVert->m_FieldDistance; + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//bool CCoreDispInfo::Create( int creationFlags ) +bool CCoreDispInfo::Create( void ) +{ + // sanity check + CCoreDispSurface *pSurf = GetSurface(); + if( pSurf->GetPointCount() != 4 ) + return false; + + // generate the displacement surface + GenerateDispSurf(); + + GenerateDispSurfNormals(); + + GenerateDispSurfTangentSpaces(); + + CalcDispSurfCoords( false, 0 ); + + for( int bumpID = 0; bumpID < ( NUM_BUMP_VECTS + 1 ); bumpID++ ) + { + CalcDispSurfCoords( true, bumpID ); + } + + GenerateLODTree(); + + GenerateCollisionData(); + + CreateTris(); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Create a displacement surface without generating the LOD for it. +//----------------------------------------------------------------------------- +bool CCoreDispInfo::CreateWithoutLOD( void ) +{ + // sanity check + CCoreDispSurface *pSurf = GetSurface(); + if( pSurf->GetPointCount() != 4 ) + return false; + + GenerateDispSurf(); + + GenerateDispSurfNormals(); + + GenerateDispSurfTangentSpaces(); + + CalcDispSurfCoords( false, 0 ); + + for( int bumpID = 0; bumpID < ( NUM_BUMP_VECTS + 1 ); bumpID++ ) + { + CalcDispSurfCoords( true, bumpID ); + } + GenerateCollisionData(); + + CreateTris(); + + return true; +} + + + +//----------------------------------------------------------------------------- +// Purpose: This function calculates the neighbor node index given the base +// node and direction of the neighbor node in the tree. +// Input: power - the size in one dimension of the displacement map (2^power + 1 ) +// index - the "base" node index +// direction - the direction of the neighbor { W = 1, N = 2, E = 3, S = 4 } +// Output: returns the index of the neighbor node +//----------------------------------------------------------------------------- +int GetNodeNeighborNode( int power, int index, int direction, int level ) +{ + // adjust the index to range [0...?] + int minNodeIndex = GetNodeMinNodeAtLevel( level ); + + // get node extent (uniform: height = width) + int nodeExtent = ( 1 << ( level - 1 ) ); + + // + // get node's component positions in quad-tree + // + int posX, posY; + GetComponentsFromNodeIndex( ( index - minNodeIndex ), &posX, &posY ); + + // + // find the neighbor in the "direction" + // + switch( direction ) + { + case CCoreDispInfo::WEST: + { + if( ( posX - 1 ) < 0 ) + { + return -( CCoreDispInfo::WEST + 1 ); + } + else + { + return ( GetNodeIndexFromComponents( ( posX - 1 ), posY ) + minNodeIndex ); + } + } + case CCoreDispInfo::NORTH: + { + if( ( posY + 1 ) == nodeExtent ) + { + return -( CCoreDispInfo::NORTH + 1 ); + } + else + { + return ( GetNodeIndexFromComponents( posX, ( posY + 1 ) ) + minNodeIndex ); + } + } + case CCoreDispInfo::EAST: + { + if( ( posX + 1 ) == nodeExtent ) + { + return -( CCoreDispInfo::EAST + 1 ); + } + else + { + return ( GetNodeIndexFromComponents( ( posX + 1 ), posY ) + minNodeIndex ); + } + } + case CCoreDispInfo::SOUTH: + { + if( ( posY - 1 ) < 0 ) + { + return -( CCoreDispInfo::SOUTH + 1 ); + } + else + { + return ( GetNodeIndexFromComponents( posX, ( posY - 1 ) ) + minNodeIndex ); + } + } + default: + { + return -99999; + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int GetNodeNeighborNodeFromNeighborSurf( int power, int index, int direction, int level, int neighborOrient ) +{ + // adjust the index to range [0...?] + int minNodeIndex = GetNodeMinNodeAtLevel( level ); + + // get node extent (uniform: height = width) + int nodeExtent = ( 1 << ( level - 1 ) ); + + // + // get node's component positions in quad-tree + // + int posX, posY; + GetComponentsFromNodeIndex( ( index - minNodeIndex ), &posX, &posY ); + + switch( direction ) + { + case CCoreDispInfo::WEST: + { + switch( neighborOrient ) + { + case CCoreDispInfo::WEST: return -( ( GetNodeIndexFromComponents( posX, ( ( nodeExtent - 1 ) - posY ) ) ) + minNodeIndex ); + case CCoreDispInfo::NORTH: return -( ( GetNodeIndexFromComponents( ( nodeExtent - 1 ) - posY, ( nodeExtent - 1 ) ) ) + minNodeIndex ); + case CCoreDispInfo::EAST: return -( ( GetNodeIndexFromComponents( ( nodeExtent - 1 ), posY ) ) + minNodeIndex ); + case CCoreDispInfo::SOUTH: return -( ( GetNodeIndexFromComponents( posY, posX ) ) + minNodeIndex ); + default: return -99999; + } + } + case CCoreDispInfo::NORTH: + { + switch( neighborOrient ) + { + case CCoreDispInfo::WEST: return -( ( GetNodeIndexFromComponents( ( ( nodeExtent - 1 ) - posY ), ( ( nodeExtent - 1 ) - posX ) ) ) + minNodeIndex ); + case CCoreDispInfo::NORTH: return -( ( GetNodeIndexFromComponents( ( ( nodeExtent - 1 ) - posX ), posY ) ) + minNodeIndex ); + case CCoreDispInfo::EAST: return -( ( GetNodeIndexFromComponents( posY, posX ) ) + minNodeIndex ); + case CCoreDispInfo::SOUTH: return -( ( GetNodeIndexFromComponents( posX, ( ( nodeExtent - 1 ) - posY ) ) ) + minNodeIndex ); + default: return -99999; + } + } + case CCoreDispInfo::EAST: + { + switch( neighborOrient ) + { + case CCoreDispInfo::WEST: return -( ( GetNodeIndexFromComponents( ( ( nodeExtent - 1 ) - posX ), posY ) ) + minNodeIndex ); + case CCoreDispInfo::NORTH: return -( ( GetNodeIndexFromComponents( posY, posX ) ) + minNodeIndex ); + case CCoreDispInfo::EAST: return -( ( GetNodeIndexFromComponents( posX, ( ( nodeExtent - 1 ) - posY ) ) ) + minNodeIndex ); + case CCoreDispInfo::SOUTH: return -( ( GetNodeIndexFromComponents( ( ( nodeExtent - 1 ) - posY ), ( ( nodeExtent - 1 ) - posX ) ) ) + minNodeIndex ); + default: return -99999; + } + } + case CCoreDispInfo::SOUTH: + { + switch( neighborOrient ) + { + case CCoreDispInfo::WEST: return -( ( GetNodeIndexFromComponents( posY, posX ) ) + minNodeIndex ); + case CCoreDispInfo::NORTH: return -( ( GetNodeIndexFromComponents( posX, ( nodeExtent - 1 ) ) ) + minNodeIndex ); + case CCoreDispInfo::EAST: return -( ( GetNodeIndexFromComponents( ( nodeExtent - 1 ), ( ( nodeExtent - 1 ) - posX ) ) ) + minNodeIndex ); + case CCoreDispInfo::SOUTH: return -( ( GetNodeIndexFromComponents( ( ( nodeExtent - 1 ) - posX ), posY ) ) + minNodeIndex ); + default: return -99999; + } + } + default: + { + return -99999; + } + } +} + + + +// Turn the optimizer back on +#pragma optimize( "", on ) + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GetPositionOnSurface( float u, float v, Vector &vPos, + Vector *pNormal, float *pAlpha ) +{ + Vector2D dispUV( u, v ); + DispUVToSurf( dispUV, vPos, pNormal, pAlpha ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::BaseFacePlaneToDispUV( Vector const &planePt, Vector2D &dispUV ) +{ + // Get the base surface points. + CCoreDispSurface *pSurf = GetSurface(); + Vector vecPoints[4]; + for( int iPoint = 0; iPoint < 4; ++iPoint ) + { + pSurf->GetPoint( iPoint, vecPoints[iPoint] ); + } + + PointInQuadToBarycentric( vecPoints[0], vecPoints[3], vecPoints[2], vecPoints[1], planePt, dispUV ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf_TriTLToBR_1( const Vector &vecIntersectPoint, + int nSnapU, int nNextU, int nSnapV, int nNextV, + Vector &vecPoint, Vector *pNormal, float *pAlpha, + bool bBackup ) +{ + int nWidth = GetWidth(); + + int nIndices[3]; + nIndices[0] = nNextV * nWidth + nSnapU; + nIndices[1] = nNextV * nWidth + nNextU; + nIndices[2] = nSnapV * nWidth + nNextU; + + Vector vecFlatVerts[3], vecVerts[3]; + float flAlphas[3]; + for ( int iVert = 0; iVert < 3; ++iVert ) + { + vecFlatVerts[iVert] = m_pVerts[nIndices[iVert]].m_FlatVert; + vecVerts[iVert] = m_pVerts[nIndices[iVert]].m_Vert; + flAlphas[iVert] = m_pVerts[nIndices[iVert]].m_Alpha; + } + + if ( nSnapU == nNextU ) + { + if ( nSnapV == nNextV ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[2] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[0] - vecVerts[1]; + Vector edgeV = vecVerts[2] - vecVerts[1]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else if ( nSnapV == nNextV ) + { + if ( nSnapU == nNextU ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[2] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[0] - vecVerts[1]; + Vector edgeV = vecVerts[2] - vecVerts[1]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else + { + float flCfs[3]; + if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) ) + { + vecPoint = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] ); + + if( pAlpha ) + { + *pAlpha = ( flAlphas[0] * flCfs[0] ) + ( flAlphas[1] * flCfs[1] ) + ( flAlphas[2] * flCfs[2] ); + } + + if( pNormal ) + { + Vector edgeU = vecVerts[0] - vecVerts[1]; + Vector edgeV = vecVerts[2] - vecVerts[1]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else + { + if ( !bBackup ) + { + DispUVToSurf_TriTLToBR_2( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, true ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf_TriTLToBR_2( const Vector &vecIntersectPoint, + int nSnapU, int nNextU, int nSnapV, int nNextV, + Vector &vecPoint, Vector *pNormal, float *pAlpha, + bool bBackup ) +{ + int nWidth = GetWidth(); + + int nIndices[3]; + nIndices[0] = nSnapV * nWidth + nSnapU; + nIndices[1] = nNextV * nWidth + nSnapU; + nIndices[2] = nSnapV * nWidth + nNextU; + + Vector vecFlatVerts[3], vecVerts[3]; + float flAlphas[3]; + for ( int iVert = 0; iVert < 3; ++iVert ) + { + vecFlatVerts[iVert] = m_pVerts[nIndices[iVert]].m_FlatVert; + vecVerts[iVert] = m_pVerts[nIndices[iVert]].m_Vert; + flAlphas[iVert] = m_pVerts[nIndices[iVert]].m_Alpha; + } + + if ( nSnapU == nNextU ) + { + if ( nSnapV == nNextV ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[1] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[1] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[1] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[2] - vecVerts[0]; + Vector edgeV = vecVerts[1] - vecVerts[0]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else if ( nSnapV == nNextV ) + { + if ( nSnapU == nNextU ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[2] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[2] - vecVerts[0]; + Vector edgeV = vecVerts[1] - vecVerts[0]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else + { + float flCfs[3]; + if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) ) + { + vecPoint = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] ); + + if( pAlpha ) + { + *pAlpha = ( flAlphas[0] * flCfs[0] ) + ( flAlphas[1] * flCfs[1] ) + ( flAlphas[2] * flCfs[2] ); + } + + if( pNormal ) + { + Vector edgeU = vecVerts[2] - vecVerts[0]; + Vector edgeV = vecVerts[1] - vecVerts[0]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else + { + if ( !bBackup ) + { + DispUVToSurf_TriTLToBR_1( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, true ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf_TriTLToBR( Vector &vecPoint, Vector *pNormal, float *pAlpha, + float flU, float flV, const Vector &vecIntersectPoint ) +{ + const float TRIEDGE_EPSILON = 0.00001f; + + int nWidth = GetWidth(); + int nHeight = GetHeight(); + + int nSnapU = static_cast( flU ); + int nSnapV = static_cast( flV ); + int nNextU = nSnapU + 1; + int nNextV = nSnapV + 1; + if ( nNextU == nWidth) { --nNextU; } + if ( nNextV == nHeight ) { --nNextV; } + + float flFracU = flU - static_cast( nSnapU ); + float flFracV = flV - static_cast( nSnapV ); + + if ( ( flFracU + flFracV ) >= ( 1.0f + TRIEDGE_EPSILON ) ) + { + DispUVToSurf_TriTLToBR_1( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, false ); + } + else + { + DispUVToSurf_TriTLToBR_2( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf_TriBLToTR_1( const Vector &vecIntersectPoint, + int nSnapU, int nNextU, int nSnapV, int nNextV, + Vector &vecPoint, Vector *pNormal, float *pAlpha, + bool bBackup ) +{ + int nWidth = GetWidth(); + + int nIndices[3]; + nIndices[0] = nSnapV * nWidth + nSnapU; + nIndices[1] = nNextV * nWidth + nSnapU; + nIndices[2] = nNextV * nWidth + nNextU; + + Vector vecFlatVerts[3], vecVerts[3]; + float flAlphas[3]; + for ( int iVert = 0; iVert < 3; ++iVert ) + { + vecFlatVerts[iVert] = m_pVerts[nIndices[iVert]].m_FlatVert; + vecVerts[iVert] = m_pVerts[nIndices[iVert]].m_Vert; + flAlphas[iVert] = m_pVerts[nIndices[iVert]].m_Alpha; + } + + if ( nSnapU == nNextU ) + { + if ( nSnapV == nNextV ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[2] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[2] - vecVerts[1]; + Vector edgeV = vecVerts[0] - vecVerts[1]; + *pNormal = CrossProduct( edgeU, edgeV ); + VectorNormalize( *pNormal ); + } + } + else if ( nSnapV == nNextV ) + { + if ( nSnapU == nNextU ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[2] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[2] - vecVerts[1]; + Vector edgeV = vecVerts[0] - vecVerts[1]; + *pNormal = CrossProduct( edgeV, edgeU ); + VectorNormalize( *pNormal ); + } + } + else + { + float flCfs[3]; + if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) ) + { + vecPoint = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] ); + + if( pAlpha ) + { + *pAlpha = ( flAlphas[0] * flCfs[0] ) + ( flAlphas[1] * flCfs[1] ) + ( flAlphas[2] * flCfs[2] ); + } + + if( pNormal ) + { + Vector edgeU = vecVerts[2] - vecVerts[1]; + Vector edgeV = vecVerts[0] - vecVerts[1]; + *pNormal = CrossProduct( edgeV, edgeU ); + VectorNormalize( *pNormal ); + } + } + else + { + if ( !bBackup ) + { + DispUVToSurf_TriBLToTR_2( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, true ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf_TriBLToTR_2( const Vector &vecIntersectPoint, + int nSnapU, int nNextU, int nSnapV, int nNextV, + Vector &vecPoint, Vector *pNormal, float *pAlpha, + bool bBackup ) +{ + int nWidth = GetWidth(); + + int nIndices[3]; + nIndices[0] = nSnapV * nWidth + nSnapU; + nIndices[1] = nNextV * nWidth + nNextU; + nIndices[2] = nSnapV * nWidth + nNextU; + + Vector vecFlatVerts[3], vecVerts[3]; + float flAlphas[3]; + for ( int iVert = 0; iVert < 3; ++iVert ) + { + vecFlatVerts[iVert] = m_pVerts[nIndices[iVert]].m_FlatVert; + vecVerts[iVert] = m_pVerts[nIndices[iVert]].m_Vert; + flAlphas[iVert] = m_pVerts[nIndices[iVert]].m_Alpha; + } + + if ( nSnapU == nNextU ) + { + if ( nSnapV == nNextV ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[1] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[1] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[1] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[0] - vecVerts[2]; + Vector edgeV = vecVerts[1] - vecVerts[2]; + *pNormal = CrossProduct( edgeV, edgeU ); + VectorNormalize( *pNormal ); + } + } + else if ( nSnapV == nNextV ) + { + if ( nSnapU == nNextU ) + { + vecPoint = vecVerts[0]; + *pAlpha = flAlphas[0]; + } + else + { + float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length(); + vecPoint = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) ); + + if ( pAlpha ) + { + *pAlpha = flAlphas[0] + ( flFrac * ( flAlphas[2] - flAlphas[0] ) ); + } + } + + if( pNormal ) + { + Vector edgeU = vecVerts[0] - vecVerts[2]; + Vector edgeV = vecVerts[1] - vecVerts[2]; + *pNormal = CrossProduct( edgeV, edgeU ); + VectorNormalize( *pNormal ); + } + } + else + { + float flCfs[3]; + if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) ) + { + vecPoint = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] ); + + if( pAlpha ) + { + *pAlpha = ( flAlphas[0] * flCfs[0] ) + ( flAlphas[1] * flCfs[1] ) + ( flAlphas[2] * flCfs[2] ); + } + + if( pNormal ) + { + Vector edgeU = vecVerts[0] - vecVerts[2]; + Vector edgeV = vecVerts[1] - vecVerts[2]; + *pNormal = CrossProduct( edgeV, edgeU ); + VectorNormalize( *pNormal ); + } + } + else + { + if ( !bBackup ) + { + DispUVToSurf_TriBLToTR_1( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, true ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf_TriBLToTR( Vector &vecPoint, Vector *pNormal, float *pAlpha, + float flU, float flV, const Vector &vecIntersectPoint ) +{ + int nWidth = GetWidth(); + int nHeight = GetHeight(); + + int nSnapU = static_cast( flU ); + int nSnapV = static_cast( flV ); + int nNextU = nSnapU + 1; + int nNextV = nSnapV + 1; + if ( nNextU == nWidth) { --nNextU; } + if ( nNextV == nHeight ) { --nNextV; } + + float flFracU = flU - static_cast( nSnapU ); + float flFracV = flV - static_cast( nSnapV ); + + if( flFracU < flFracV ) + { + DispUVToSurf_TriBLToTR_1( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, false ); + } + else + { + DispUVToSurf_TriBLToTR_2( vecIntersectPoint, nSnapU, nNextU, nSnapV, nNextV, vecPoint, pNormal, pAlpha, false ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::DispUVToSurf( Vector2D const &dispUV, Vector &vecPoint, + Vector *pNormal, float *pAlpha ) +{ + // Check to see that the point is on the surface. + if ( dispUV.x < 0.0f || dispUV.x > 1.0f || dispUV.y < 0.0f || dispUV.y > 1.0f ) + return; + + // Get the base surface points. + Vector vecIntersectPoint; + CCoreDispSurface *pSurf = GetSurface(); + PointInQuadFromBarycentric( pSurf->GetPoint( 0 ), pSurf->GetPoint( 3 ), pSurf->GetPoint( 2 ), pSurf->GetPoint( 1 ), dispUV, vecIntersectPoint ); + + // Get the displacement power. + int nWidth = GetWidth(); + int nHeight = GetHeight(); + + // Scale the U, V coordinates to the displacement grid size. + float flU = dispUV.x * ( static_cast( nWidth ) - 1.000001f ); + float flV = dispUV.y * ( static_cast( nHeight ) - 1.000001f ); + + // Find the base U, V. + int nSnapU = static_cast( flU ); + int nSnapV = static_cast( flV ); + + // Use this to get the triangle orientation. + bool bOdd = ( ( ( nSnapV * nWidth ) + nSnapU ) % 2 == 1 ); + + // Top Left to Bottom Right + if( bOdd ) + { + DispUVToSurf_TriTLToBR( vecPoint, pNormal, pAlpha, flU, flV, vecIntersectPoint ); + } + // Bottom Left to Top Right + else + { + DispUVToSurf_TriBLToTR( vecPoint, pNormal, pAlpha, flU, flV, vecIntersectPoint ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Create bounding boxes around pairs of triangles (in a grid-like) +// fashion; used for culling +//----------------------------------------------------------------------------- +void CCoreDispInfo::CreateBoundingBoxes( CoreDispBBox_t *pBBox, int count ) +{ + // + // Initialize the bounding boxes. + // + int iBox; + for( iBox = 0; iBox < count; ++iBox ) + { + pBBox[iBox].vMin.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + pBBox[iBox].vMax.Init( FLT_MIN, FLT_MIN, FLT_MIN ); + } + + // Get the width and height of the displacement surface. + int nHeight = GetHeight(); + int nWidth = GetWidth(); + + // Find bounding box of every two consecutive triangles + iBox = 0; + int nIndex = 0; + for( int iHgt = 0; iHgt < ( nHeight - 1 ); ++iHgt ) + { + for( int iWid = 0; iWid < ( nWidth - 1 ); ++iWid ) + { + for( int iPoint = 0; iPoint < 4; ++iPoint ) + { + switch( iPoint ) + { + case 0: { nIndex = ( nHeight * iHgt ) + iWid; break; } + case 1: { nIndex = ( nHeight * ( iHgt + 1 ) ) + iWid; break; } + case 2: { nIndex = ( nHeight * ( iHgt + 1 ) ) + ( iWid + 1 ); break; } + case 3: { nIndex = ( nHeight * iHgt ) + ( iWid + 1 ); break; } + default: { break; } + } + + Vector vecPoint; + GetVert( nIndex, vecPoint ); + if( vecPoint[0] < pBBox[iBox].vMin[0] ) { pBBox[iBox].vMin[0] = vecPoint[0]; } + if( vecPoint[1] < pBBox[iBox].vMin[1] ) { pBBox[iBox].vMin[1] = vecPoint[1]; } + if( vecPoint[2] < pBBox[iBox].vMin[2] ) { pBBox[iBox].vMin[2] = vecPoint[2]; } + + if( vecPoint[0] > pBBox[iBox].vMax[0] ) { pBBox[iBox].vMax[0] = vecPoint[0]; } + if( vecPoint[1] > pBBox[iBox].vMax[1] ) { pBBox[iBox].vMax[1] = vecPoint[1]; } + if( vecPoint[2] > pBBox[iBox].vMax[2] ) { pBBox[iBox].vMax[2] = vecPoint[2]; } + } + + iBox++; + } + } + + // Verify. + Assert( iBox == count ); + + // Bloat. + for ( iBox = 0; iBox < count; ++iBox ) + { + for( int iAxis = 0; iAxis < 3; ++iAxis ) + { + pBBox[iBox].vMin[iAxis] -= 1.0f; + pBBox[iBox].vMax[iAxis] += 1.0f; + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline bool PointInDispBBox( CoreDispBBox_t *pBox, const Vector &vecPoint ) +{ + // Check to see if point lies in box + if( ( vecPoint.x < pBox->vMin.x ) || ( vecPoint.x > pBox->vMax.x ) ) + return false; + + if( ( vecPoint.y < pBox->vMin.y ) || ( vecPoint.y > pBox->vMax.y ) ) + return false; + + if( ( vecPoint.z < pBox->vMin.z ) || ( vecPoint.z > pBox->vMax.z ) ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CCoreDispInfo::GetTriangleIndicesForDispBBox( int nIndex, int nTris[2][3] ) +{ + // Test to see whether or not the index is odd. + bool bOdd = ( ( nIndex % 2 ) == 1 ); + + int nWidth = GetWidth(); + + // Tris for TLtoBR + if ( bOdd ) + { + nTris[0][0] = nIndex; + nTris[0][1] = nIndex + nWidth; + nTris[0][2] = nIndex + 1; + + nTris[1][0] = nIndex + 1; + nTris[1][1] = nIndex + nWidth; + nTris[1][2] = nIndex + nWidth + 1; + } + // Tris for BLtoTR + else + { + nTris[0][0] = nIndex; + nTris[0][1] = nIndex + nWidth; + nTris[0][2] = nIndex + nWidth + 1; + + nTris[1][0] = nIndex; + nTris[1][1] = nIndex + nWidth + 1; + nTris[1][2] = nIndex + 1; + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CCoreDispInfo::SurfToBaseFacePlane( Vector const &surfPt, Vector &planePt ) +{ + // Create bounding boxes + int nBoxCount = ( GetHeight() - 1 ) * ( GetWidth() - 1 ); + CoreDispBBox_t *pBBox = new CoreDispBBox_t[nBoxCount]; + CreateBoundingBoxes( pBBox, nBoxCount ); + + // Use the boxes as a first-pass culling mechanism. + for( int iBox = 0; iBox < nBoxCount; ++iBox ) + { + // Get the current displacement triangle-pair bounding-box. + CoreDispBBox_t *pBox = &pBBox[iBox]; + if( !pBox ) + continue; + + // Check the point against the current displacement bounding-box. + if ( !PointInDispBBox( pBox, surfPt ) ) + continue; + + // Point lies within the bounding box. + int nIndex = iBox + ( iBox / ( GetWidth() - 1 ) ); + + // Get the triangle coordinates for this box. + int aTris[2][3]; + GetTriangleIndicesForDispBBox( nIndex, aTris ); + + // Barycentrically test the triangles on the displacement surface. + Vector vecPoints[3]; + for ( int iTri = 0; iTri < 2; ++iTri ) + { + for ( int iVert = 0; iVert < 3; ++iVert ) + { + GetVert( aTris[iTri][iVert], vecPoints[iVert] ); + } + + float c[3]; + if ( CalcBarycentricCooefs( vecPoints[0], vecPoints[1], vecPoints[2], surfPt, c[0], c[1], c[2] ) ) + { + Vector vecFlatPoints[3]; + for ( int iVert = 0; iVert < 3; ++iVert ) + { + GetFlatVert( aTris[iTri][iVert], vecFlatPoints[iVert] ); + } + + planePt = ( vecFlatPoints[0] * c[0] ) + ( vecFlatPoints[1] * c[1] ) + ( vecFlatPoints[2] * c[2] ); + + // Delete temporary memory. + delete [] pBBox; + return true; + } + } + } + + // Delete temporary memory + delete [] pBBox; + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CCoreDispInfo::GetTriCount( void ) +{ + return ( ( GetHeight() - 1 ) * ( GetWidth() -1 ) * 2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::GetTriIndices( int iTri, unsigned short &v1, unsigned short &v2, unsigned short &v3 ) +{ + // Verify we have the correct data (only build when collision data is built). + if ( !m_pTris || ( iTri < 0 ) || ( iTri >= GetTriCount() ) ) + { + Assert( iTri >= 0 ); + Assert( iTri < GetTriCount() ); + Assert( m_pTris ); + return; + } + + CoreDispTri_t *pTri = &m_pTris[iTri]; + v1 = pTri->m_iIndex[0]; + v2 = pTri->m_iIndex[1]; + v3 = pTri->m_iIndex[2]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::SetTriIndices( int iTri, unsigned short v1, unsigned short v2, unsigned short v3 ) +{ + // Verify we have the correct data (only build when collision data is built). + if ( !m_pTris || ( iTri < 0 ) || ( iTri >= GetTriCount() ) ) + { + Assert( iTri >= 0 ); + Assert( iTri < GetTriCount() ); + Assert( m_pTris ); + return; + } + + CoreDispTri_t *pTri = &m_pTris[iTri]; + pTri->m_iIndex[0] = v1; + pTri->m_iIndex[1] = v2; + pTri->m_iIndex[2] = v3; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::GetTriPos( int iTri, Vector &v1, Vector &v2, Vector &v3 ) +{ + // Verify we have the correct data (only build when collision data is built). + if ( !m_pTris || ( iTri < 0 ) || ( iTri >= GetTriCount() ) ) + { + Assert( iTri >= 0 ); + Assert( iTri < GetTriCount() ); + Assert( m_pTris ); + return; + } + + CoreDispTri_t *pTri = &m_pTris[iTri]; + v1 = m_pVerts[pTri->m_iIndex[0]].m_Vert; + v2 = m_pVerts[pTri->m_iIndex[1]].m_Vert; + v3 = m_pVerts[pTri->m_iIndex[2]].m_Vert; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::InitTris( void ) +{ + // Verify we have the correct data (only build when collision data is built). + if ( !m_pTris ) + { + Assert( m_pTris ); + return; + } + + int nTriCount = GetTriCount(); + for ( int iTri = 0; iTri < nTriCount; ++iTri ) + { + m_pTris[iTri].m_uiTags = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::CreateTris( void ) +{ + // Verify we have the correct data (only build when collision data is built). + if ( !m_pTris ) + { + Assert( m_pTris ); + return; + } + + // Extra sanity check if wanted! + Assert( GetTriCount() == ( m_RenderIndexCount / 3 ) ); + + int nTriCount = GetTriCount(); + for ( int iTri = 0, iRender = 0; iTri < nTriCount; ++iTri, iRender += 3 ) + { + m_pTris[iTri].m_iIndex[0] = m_RenderIndices[iRender]; + m_pTris[iTri].m_iIndex[1] = m_RenderIndices[iRender+1]; + m_pTris[iTri].m_iIndex[2] = m_RenderIndices[iRender+2]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CCoreDispInfo::IsTriWalkable( int iTri ) +{ + if ( IsTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT ) ) + { + return IsTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL ); + } + + return IsTriTag( iTri, COREDISPTRI_TAG_WALKABLE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CCoreDispInfo::IsTriBuildable( int iTri ) +{ + if ( IsTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT ) ) + { + return IsTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL ); + } + + return IsTriTag( iTri, COREDISPTRI_TAG_BUILDABLE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CCoreDispInfo::IsTriRemove( int iTri ) +{ + return IsTriTag( iTri, COREDISPTRI_TAG_FORCE_REMOVE_BIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCoreDispInfo::Position_Update( int iVert, Vector vecPos ) +{ + Vector vSPos, vFlat; + GetFlatVert( iVert, vFlat ); + GetSubdivPosition( iVert, vSPos ); + + Vector vSeg; + vSeg = vecPos - vFlat; + vSeg -= vSPos; + + // Subtract out the elevation. + float elev = GetElevation(); + if( elev != 0.0 ) + { + Vector vNormal; + GetSurface()->GetNormal( vNormal ); + vNormal *= elev; + + vSeg -= vNormal; + } + + float flDistance = VectorNormalize( vSeg ); + + SetFieldVector( iVert, vSeg ); + SetFieldDistance( iVert, flDistance ); +} diff --git a/public/builddisp.h b/public/builddisp.h new file mode 100644 index 0000000..c6ef149 --- /dev/null +++ b/public/builddisp.h @@ -0,0 +1,1460 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef BUILDDISP_H +#define BUILDDISP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "commonmacros.h" +#include "tier0/dbg.h" +#include "bspfile.h" +#include "mathlib/mathlib.h" +#include "mathlib/bumpvects.h" +#include "disp_common.h" +#include "bitvec.h" + +#define DISP_ALPHA_PROP_DELTA 382.5f + +class CCoreDispInfo; + +struct CoreDispBBox_t +{ + Vector vMin, vMax; +}; + +//========================================================================= +// +// Surface Class - interfacing class (fill in with MapFace, dface_t, and +// msurface_t) +// +class CCoreDispSurface +{ +public: + + enum { QUAD_POINT_COUNT = 4 }; + enum { MAX_CORNER_NEIGHBOR_COUNT = 16 }; + + CCoreDispSurface(); + + //========================================================================= + // + // initialization + // + void Init( void ); + + //========================================================================= + // + // parent surface id - index to CMapFace, dface_t, or msurface_t + // + inline void SetHandle( int handle ); + inline int GetHandle( void ); + + //========================================================================= + // + // vertex data - pos, normal, texture, lightmap, alpha, etc... + // + inline void SetPointCount( int count ); + inline int GetPointCount( void ) const; + + inline void SetPoint( int index, Vector const &pt ); + inline void GetPoint( int index, Vector& pt ) const; + inline Vector const& GetPoint( int index ) const; + + inline void SetPointNormal( int index, Vector const &normal ); + inline void GetPointNormal( int index, Vector &normal ); + inline void SetTexCoord( int index, Vector2D const& texCoord ); + inline void GetTexCoord( int index, Vector2D& texCoord ) const; + + inline void SetLuxelCoord( int bumpIndex, int index, Vector2D const& luxelCoord ); + inline void GetLuxelCoord( int bumpIndex, int index, Vector2D& luxelCoord ) const; + inline void SetLuxelCoords( int bumpIndex, Vector2D const coords[4] ); + inline void GetLuxelCoords( int bumpIndex, Vector2D coords[4] ) const; + + inline void SetLuxelU( int nU ) { m_nLuxelU = nU; } + inline int GetLuxelU( void ) { return m_nLuxelU; } + inline void SetLuxelV( int nV ) { m_nLuxelV = nV; } + inline int GetLuxelV( void ) { return m_nLuxelV; } + bool CalcLuxelCoords( int nLuxels, bool bAdjust, const Vector &vecU, const Vector &vecV ); + + inline void SetAlpha( int index, float alpha ); + inline float GetAlpha( int const index ) const; + + //========================================================================= + // + // utils + // + inline void GetNormal( Vector& normal ); + inline void SetFlags( int flag ); + inline int GetFlags( void ); + inline void SetContents( int contents ); + inline int GetContents( void ); + + //========================================================================= + // + // create utils (texture axis not use anymore but here to support older maps) + // + inline void SetSAxis( Vector const &axis ); + inline void GetSAxis( Vector &axis ); + inline void SetTAxis( Vector const &axis ); + inline void GetTAxis( Vector &axis ); + + inline void SetPointStartIndex( int index ); + inline int GetPointStartIndex( void ); + inline void SetPointStart( Vector const &pt ); + inline void GetPointStart( Vector &pt ); + + // Used by the tools to set the neighbor data from the BSP file. + void SetNeighborData( const CDispNeighbor edgeNeighbors[4], const CDispCornerNeighbors cornerNeighbors[4] ); + + void GeneratePointStartIndexFromMappingAxes( Vector const &sAxis, Vector const &tAxis ); + int GenerateSurfPointStartIndex( void ); + int FindSurfPointStartIndex( void ); + void AdjustSurfPointData( void ); + + // Indexed by CORNER_ defines. + CDispCornerNeighbors* GetCornerNeighbors( int iCorner ) { Assert( iCorner >= 0 && iCorner < ARRAYSIZE( m_CornerNeighbors ) ); return &m_CornerNeighbors[iCorner]; } + const CDispCornerNeighbors* GetCornerNeighbors( int iCorner ) const { Assert( iCorner >= 0 && iCorner < ARRAYSIZE( m_CornerNeighbors ) ); return &m_CornerNeighbors[iCorner]; } + + // Indexed by CORNER_ defines. + int GetCornerNeighborCount( int iCorner ) const { return GetCornerNeighbors( iCorner )->m_nNeighbors; } + int GetCornerNeighbor( int iCorner, int iNeighbor ) const { Assert( iNeighbor >= 0 && iNeighbor < GetCornerNeighbors(iCorner)->m_nNeighbors ); return GetCornerNeighbors( iCorner )->m_Neighbors[iNeighbor]; } + + CDispNeighbor* GetEdgeNeighbor( int iEdge ) { Assert( iEdge >= 0 && iEdge < ARRAYSIZE( m_EdgeNeighbors ) ); return &m_EdgeNeighbors[iEdge]; } + const CDispNeighbor* GetEdgeNeighbor( int iEdge ) const { Assert( iEdge >= 0 && iEdge < ARRAYSIZE( m_EdgeNeighbors ) ); return &m_EdgeNeighbors[iEdge]; } + + +protected: + + // Utility + bool LongestInU( const Vector &vecU, const Vector &vecV ); + + + int m_Index; // parent face (CMapFace, dface_t, msurface_t) index "handle" + + int m_PointCount; // number of points in the face (should be 4!) + Vector m_Points[QUAD_POINT_COUNT]; // points + Vector m_Normals[QUAD_POINT_COUNT]; // normals at points + Vector2D m_TexCoords[QUAD_POINT_COUNT]; // texture coordinates at points + Vector2D m_LuxelCoords[NUM_BUMP_VECTS+1][QUAD_POINT_COUNT]; // lightmap coordinates at points + float m_Alphas[QUAD_POINT_COUNT]; // alpha at points + + // Luxels sizes + int m_nLuxelU; + int m_nLuxelV; + + // Straight from the BSP file. + CDispNeighbor m_EdgeNeighbors[4]; + CDispCornerNeighbors m_CornerNeighbors[4]; + + int m_Flags; // surface flags - inherited from the "parent" face + int m_Contents; // contents flags - inherited from the "parent" face + + Vector sAxis; // used to generate start disp orientation (old method) + Vector tAxis; // used to generate start disp orientation (old method) + int m_PointStartIndex; // index to the starting point -- for saving starting point + Vector m_PointStart; // starting point used to determine the orientation of the displacement map on the surface +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetHandle( int handle ) +{ + m_Index = handle; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispSurface::GetHandle( void ) +{ + return m_Index; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetPointCount( int count ) +{ + // quad only -- currently! + if( count != 4 ) + return; + m_PointCount = count; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispSurface::GetPointCount( void ) const +{ + return m_PointCount; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetPoint( int index, Vector const &pt ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + VectorCopy( pt, m_Points[index] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetPoint( int index, Vector &pt ) const +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + VectorCopy( m_Points[index], pt ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline Vector const& CCoreDispSurface::GetPoint( int index ) const +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + return m_Points[index]; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetPointNormal( int index, Vector const &normal ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + VectorCopy( normal, m_Normals[index] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetPointNormal( int index, Vector& normal ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + VectorCopy( m_Normals[index], normal ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetTexCoord( int index, Vector2D const& texCoord ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + Vector2DCopy( texCoord, m_TexCoords[index] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetTexCoord( int index, Vector2D& texCoord ) const +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + Vector2DCopy( m_TexCoords[index], texCoord ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetLuxelCoord( int bumpIndex, int index, Vector2D const& luxelCoord ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + Assert( bumpIndex >= 0 ); + Assert( bumpIndex < NUM_BUMP_VECTS + 1 ); + Vector2DCopy( luxelCoord, m_LuxelCoords[bumpIndex][index] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetLuxelCoord( int bumpIndex, int index, Vector2D& luxelCoord ) const +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + Assert( bumpIndex >= 0 ); + Assert( bumpIndex < NUM_BUMP_VECTS + 1 ); + Vector2DCopy( m_LuxelCoords[bumpIndex][index], luxelCoord ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetLuxelCoords( int bumpIndex, Vector2D const luxelCoords[4] ) +{ + Assert( bumpIndex >= 0 ); + Assert( bumpIndex < NUM_BUMP_VECTS + 1 ); + for( int i=0; i < 4; i++ ) + Vector2DCopy( luxelCoords[i], m_LuxelCoords[bumpIndex][i] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetLuxelCoords( int bumpIndex, Vector2D luxelCoords[4] ) const +{ + Assert( bumpIndex >= 0 ); + Assert( bumpIndex < NUM_BUMP_VECTS + 1 ); + for( int i=0; i < 4; i++ ) + Vector2DCopy( m_LuxelCoords[bumpIndex][i], luxelCoords[i] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetAlpha( int index, float alpha ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + m_Alphas[index] = alpha; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline float CCoreDispSurface::GetAlpha( int const index ) const +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + return m_Alphas[index]; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetFlags( int flag ) +{ + m_Flags = flag; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispSurface::GetFlags( void ) +{ + return m_Flags; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetContents( int contents ) +{ + m_Contents = contents; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispSurface::GetContents( void ) +{ + return m_Contents; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetSAxis( Vector const &axis ) +{ + VectorCopy( axis, sAxis ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetSAxis( Vector& axis ) +{ + VectorCopy( sAxis, axis ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetTAxis( Vector const &axis ) +{ + VectorCopy( axis, tAxis ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetTAxis( Vector& axis ) +{ + VectorCopy( tAxis, axis ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetPointStartIndex( int index ) +{ + Assert( index >= 0 ); + Assert( index < QUAD_POINT_COUNT ); + m_PointStartIndex = index; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispSurface::GetPointStartIndex( void ) +{ + return m_PointStartIndex; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::SetPointStart( Vector const& pt ) +{ + VectorCopy( pt, m_PointStart ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetPointStart( Vector& pt ) +{ + VectorCopy( m_PointStart, pt ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispSurface::GetNormal( Vector& normal ) +{ + // + // calculate the displacement surface normal + // + Vector tmp[2]; + VectorSubtract( m_Points[1], m_Points[0], tmp[0] ); + VectorSubtract( m_Points[3], m_Points[0], tmp[1] ); + CrossProduct( tmp[1], tmp[0], normal ); + VectorNormalize( normal ); +} + + +//========================================================================= +// +// Node Class (for displacement quad-tree) +// +class CCoreDispNode +{ +public: + + enum { MAX_NEIGHBOR_NODE_COUNT = 4 }; + enum { MAX_NEIGHBOR_VERT_COUNT = 8 }; + enum { MAX_SURF_AT_NODE_COUNT = 8 }; + + //========================================================================= + // + // Initialization + // + void Init( void ); + + //========================================================================= + // + // + // + inline void SetBoundingBox( Vector const& bMin, Vector const& bMax ); + inline void GetBoundingBox( Vector& bMin, Vector& bMax ); + + inline void SetErrorTerm( float errorTerm ); + inline float GetErrorTerm( void ); + + inline void SetNeighborNodeIndex( int dir, int index ); + inline int GetNeighborNodeIndex( int dir ); + + inline void SetCenterVertIndex( int index ); + inline int GetCenterVertIndex( void ); + inline void SetNeighborVertIndex( int dir, int index ); + inline int GetNeighborVertIndex( int dir ); + + inline void SetTriBoundingBox( int index, Vector const& bMin, Vector const& bMax ); + inline void GetTriBoundingBox( int index, Vector& bMin, Vector& bMax ); + inline void SetTriPlane( int index, Vector const& normal, float dist ); + inline void GetTriPlane( int index, cplane_t *plane ); + + inline void SetRayBoundingBox( int index, Vector const& bMin, Vector const& bMax ); + inline void GetRayBoundingBox( int index, Vector& bMin, Vector& bMax ); + + //========================================================================= + // + // Node Functions (friend functions) + // + friend int GetNodeLevel( int index ); + friend int GetNodeCount( int power ); + friend int GetNodeParent( int index ); + friend int GetNodeChild( int power, int index, int direction ); + friend int GetNodeNeighborNode( int power, int index, int direction, int level ); + friend int GetNodeNeighborNodeFromNeighborSurf( int power, int index, int direction, int level, int neighborOrient ); + friend int GetNodeMinNodeAtLevel( int level ); + + friend void GetDispNodeTriVerts( CCoreDispInfo *pDisp, int nodeIndex, int triIndex, float *v1, float *v2, float *v3 ); + + friend void GetComponentsFromNodeIndex( int index, int *x, int *y ); + friend int GetNodeIndexFromComponents( int x, int y ); + +protected: + + Vector m_BBox[2]; // displacement node bounding box (take into account size of children) + float m_ErrorTerm; // LOD error term (the "precision" of the representation of the surface at this node's level) + int m_VertIndex; // the node's vertex index (center vertex of node) + int m_NeighborVertIndices[MAX_NEIGHBOR_VERT_COUNT]; // all other vertex indices in node (maximally creates 8 trianglar surfaces) + Vector m_SurfBBoxes[MAX_SURF_AT_NODE_COUNT][2]; // surface bounding boxes - old method + cplane_t m_SurfPlanes[MAX_SURF_AT_NODE_COUNT]; // surface plane info - old method + + Vector m_RayBBoxes[4][2]; // bounding boxes for ray traces +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetBoundingBox( Vector const& bMin, Vector const& bMax ) +{ + VectorCopy( bMin, m_BBox[0] ); + VectorCopy( bMax, m_BBox[1] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::GetBoundingBox( Vector& bMin, Vector& bMax ) +{ + VectorCopy( m_BBox[0], bMin ); + VectorCopy( m_BBox[1], bMax ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetErrorTerm( float errorTerm ) +{ + m_ErrorTerm = errorTerm; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline float CCoreDispNode::GetErrorTerm( void ) +{ + return m_ErrorTerm; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetCenterVertIndex( int index ) +{ + m_VertIndex = index; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispNode::GetCenterVertIndex( void ) +{ + return m_VertIndex; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetNeighborVertIndex( int dir, int index ) +{ + Assert( dir >= 0 ); + Assert( dir < MAX_NEIGHBOR_VERT_COUNT ); + m_NeighborVertIndices[dir] = index; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispNode::GetNeighborVertIndex( int dir ) +{ + Assert( dir >= 0 ); + Assert( dir < MAX_NEIGHBOR_VERT_COUNT ); + return m_NeighborVertIndices[dir]; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetTriBoundingBox( int index, Vector const& bMin, Vector const& bMax ) +{ + Assert( index >= 0 ); + Assert( index < MAX_SURF_AT_NODE_COUNT ); + VectorCopy( bMin, m_SurfBBoxes[index][0] ); + VectorCopy( bMax, m_SurfBBoxes[index][1] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::GetTriBoundingBox( int index, Vector& bMin, Vector& bMax ) +{ + Assert( index >= 0 ); + Assert( index < MAX_SURF_AT_NODE_COUNT ); + VectorCopy( m_SurfBBoxes[index][0], bMin ); + VectorCopy( m_SurfBBoxes[index][1], bMax ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetTriPlane( int index, Vector const &normal, float dist ) +{ + Assert( index >= 0 ); + Assert( index < MAX_SURF_AT_NODE_COUNT ); + VectorCopy( normal, m_SurfPlanes[index].normal ); + m_SurfPlanes[index].dist = dist; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::GetTriPlane( int index, cplane_t *plane ) +{ + Assert( index >= 0 ); + Assert( index < MAX_SURF_AT_NODE_COUNT ); + VectorCopy( m_SurfPlanes[index].normal, plane->normal ); + plane->dist = m_SurfPlanes[index].dist; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::SetRayBoundingBox( int index, Vector const &bMin, Vector const &bMax ) +{ + Assert( index >= 0 ); + Assert( index < 4 ); + VectorCopy( bMin, m_RayBBoxes[index][0] ); + VectorCopy( bMax, m_RayBBoxes[index][1] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispNode::GetRayBoundingBox( int index, Vector& bMin, Vector& bMax ) +{ + Assert( index >= 0 ); + Assert( index < 4 ); + VectorCopy( m_RayBBoxes[index][0], bMin ); + VectorCopy( m_RayBBoxes[index][1], bMax ); +} + + +//============================================================================= +// +// CCoreInfoBuilder - the primary data necessay to derive a displacement surface +// used by WorldCraft (CMapFace, CMapDisp), VRAD (dface_t, ddispinto_t), +// and the engine (msurface_t, CDispInfo) +// + +struct CoreDispVert_t +{ + Vector m_FieldVector; // displacement vector field + float m_FieldDistance; // the distances along the displacement vector normal + + Vector m_SubdivNormal; + Vector m_SubdivPos; // used the create curvature of displacements + + // generated displacement surface data + Vector m_Vert; // displacement surface vertices + Vector m_FlatVert; + Vector m_Normal; // displacement surface normals + Vector m_TangentS; // use in calculating the tangent space axes + Vector m_TangentT; // use in calculating the tangent space axes + Vector2D m_TexCoord; // displacement surface texture coordinates + Vector2D m_LuxelCoords[NUM_BUMP_VECTS+1]; // displacement surface lightmap coordinates + + // additional per-vertex data + float m_Alpha; // displacement alpha values (per displacement vertex) +}; + +// New, need to use this at the node level +#define COREDISPTRI_TAG_WALKABLE (1<<0) +#define COREDISPTRI_TAG_FORCE_WALKABLE_BIT (1<<1) +#define COREDISPTRI_TAG_FORCE_WALKABLE_VAL (1<<2) +#define COREDISPTRI_TAG_BUILDABLE (1<<3) +#define COREDISPTRI_TAG_FORCE_BUILDABLE_BIT (1<<4) +#define COREDISPTRI_TAG_FORCE_BUILDABLE_VAL (1<<5) +#define COREDISPTRI_TAG_FORCE_REMOVE_BIT (1<<6) + +struct CoreDispTri_t +{ + unsigned short m_iIndex[3]; // the three indices that make up a triangle + unsigned short m_uiTags; // walkable, buildable, etc. +}; + +class CCoreDispInfo : public CDispUtilsHelper +{ +public: + + // + // tree and displacement surface directions + // + enum { WEST = 0, + NORTH = 1, + EAST = 2, + SOUTH = 3, + SOUTHWEST = 4, + SOUTHEAST = 5, + NORTHWEST = 6, + NORTHEAST = 7 }; + +#if 0 + // + // building parameters + // + enum { BUILD_NORMALS = 0x1, + BUILD_TEXCOORDS = 0x2, + BUILD_LIGHTCOORDS = 0x4, + BUILD_LODTREE = 0x8, + BUILD_COLLISION = 0x10, + BUILD_TANGENTSPACE = 0x20 }; +#endif + + // + // surface info flags + // + enum { SURF_BUMPED = 0x1, + SURF_NOPHYSICS_COLL = 0x2, + SURF_NOHULL_COLL = 0x4, + SURF_NORAY_COLL = 0x8 }; + + enum { MAX_DISP_POWER = MAX_MAP_DISP_POWER }; + enum { MAX_VERT_COUNT = MAX_DISPVERTS }; + enum { MAX_NODE_COUNT = 85 }; + + +// Convert from a CDispUtilsHelper. +public: + + static CCoreDispInfo* FromDispUtils( CDispUtilsHelper *p ) { return (CCoreDispInfo*)p; } + + +// CDispUtilsHelper implementation. +public: + + virtual CDispNeighbor* GetEdgeNeighbor( int index ); + virtual CDispCornerNeighbors* GetCornerNeighbors( int index ); + virtual const CPowerInfo* GetPowerInfo() const; + virtual CDispUtilsHelper* GetDispUtilsByIndex( int index ); + + +public: + + //========================================================================= + // + // Creation/Destruction + // + CCoreDispInfo(); + ~CCoreDispInfo(); + + void InitSurf( int parentIndex, Vector points[4], Vector normals[4], + Vector2D texCoords[4], Vector2D lightCoords[4][4], int contents, int flags, + bool bGenerateSurfPointStart, Vector& startPoint, + bool bHasMappingAxes, Vector& uAxis, Vector& vAxis ); + + void InitDispInfo( int power, int minTess, float smoothingAngle, + float *alphas, Vector *dispVectorField, float *dispDistances ); + + // This just unpacks the contents of the verts into arrays and calls InitDispInfo. + void InitDispInfo( int power, int minTess, float smoothingAngle, const CDispVert *pVerts, const CDispTri *pTris ); + +// bool Create( int creationFlags ); + bool Create( void ); + bool CreateWithoutLOD( void ); + + //========================================================================= + // + // Parameter "Wrappers" + // + CCoreDispSurface* GetSurface() { return &m_Surf; } + const CCoreDispSurface* GetSurface() const { return &m_Surf; } + + inline CCoreDispNode *GetNode( int index ); + + inline void SetPower( int power ); + inline int GetPower( void ) const; + inline int GetPostSpacing( void ); + inline int GetWidth( void ); + inline int GetHeight( void ); + inline int GetSize( void ) const; + + // Use this disp as a CDispUtils. + void SetDispUtilsHelperInfo( CCoreDispInfo **ppListBase, int listSize ); + + void SetNeighborData( const CDispNeighbor edgeNeighbors[4], const CDispCornerNeighbors cornerNeighbors[4] ) { GetSurface()->SetNeighborData( edgeNeighbors, cornerNeighbors ); } + + // Get a corner point. Indexed by the CORNER_ defines. + const CVertIndex& GetCornerPointIndex( int index ) const { return GetPowerInfo()->GetCornerPointIndex( index ); } + const Vector& GetCornerPoint( int index ) const { return GetVert( VertIndexToInt( GetCornerPointIndex( index ) ) ); } + + inline void SetVert( int index, Vector const& vert ); + inline void GetVert( int index, Vector& vert ) const; + + inline const Vector& GetVert( int index ) const; + inline const Vector& GetVert( const CVertIndex &index ) const; + + inline void GetFlatVert( int index, Vector& vert ) const; + inline void SetFlatVert( int index, const Vector &vert ); + + inline void GetNormal( int index, Vector& normal ) const; + inline const Vector& GetNormal( int index ) const; + inline const Vector& GetNormal( const CVertIndex &index ) const; + inline void SetNormal( int index, Vector const& normal ); + inline void SetNormal( const CVertIndex &index, Vector const& normal ); + + inline void GetTangentS( int index, Vector& tangentS ) const; + inline const Vector &GetTangentS( int index ) const; + inline const Vector &GetTangentS( const CVertIndex &index ) const { return GetTangentS(VertIndexToInt(index)); } + inline void GetTangentT( int index, Vector& tangentT ) const; + inline void SetTangentS( int index, Vector const& vTangentS ) { m_pVerts[index].m_TangentS = vTangentS; } + inline void SetTangentT( int index, Vector const& vTangentT ) { m_pVerts[index].m_TangentT = vTangentT; } + + inline void SetTexCoord( int index, Vector2D const& texCoord ); + inline void GetTexCoord( int index, Vector2D& texCoord ) const; + + inline void SetLuxelCoord( int bumpIndex, int index, Vector2D const& luxelCoord ); + inline void GetLuxelCoord( int bumpIndex, int index, Vector2D& luxelCoord ) const; + + inline void SetAlpha( int index, float alpha ); + inline float GetAlpha( int index ); + + int GetTriCount( void ); + void GetTriIndices( int iTri, unsigned short &v1, unsigned short &v2, unsigned short &v3 ); + void SetTriIndices( int iTri, unsigned short v1, unsigned short v2, unsigned short v3 ); + void GetTriPos( int iTri, Vector &v1, Vector &v2, Vector &v3 ); + inline void SetTriTag( int iTri, unsigned short nTag ) { m_pTris[iTri].m_uiTags |= nTag; } + inline void ResetTriTag( int iTri, unsigned short nTag ) { m_pTris[iTri].m_uiTags &= ~nTag; } + inline void ToggleTriTag( int iTri, unsigned short nTag ) { m_pTris[iTri].m_uiTags ^= nTag; } + inline bool IsTriTag( int iTri, unsigned short nTag ) { return ( ( m_pTris[iTri].m_uiTags & nTag ) != 0 ); } + inline unsigned short GetTriTagValue( int iTri ) { return m_pTris[iTri].m_uiTags; } + inline void SetTriTagValue( int iTri, unsigned short nVal ) { m_pTris[iTri].m_uiTags = nVal; } + + bool IsTriWalkable( int iTri ); + bool IsTriBuildable( int iTri ); + bool IsTriRemove( int iTri ); + + inline void SetElevation( float elevation ); + inline float GetElevation( void ); + + inline void ResetFieldVectors( void ); + inline void SetFieldVector( int index, Vector const &v ); + inline void GetFieldVector( int index, Vector& v ); + inline void ResetFieldDistances( void ); + inline void SetFieldDistance( int index, float dist ); + inline float GetFieldDistance( int index ); + + inline void ResetSubdivPositions( void ); + inline void SetSubdivPosition( int ndx, Vector const &v ); + inline void GetSubdivPosition( int ndx, Vector& v ); + + inline void ResetSubdivNormals( void ); + inline void SetSubdivNormal( int ndx, Vector const &v ); + inline void GetSubdivNormal( int ndx, Vector &v ); + + inline void SetRenderIndexCount( int count ); + inline int GetRenderIndexCount( void ); + inline void SetRenderIndex( int index, int triIndex ); + inline int GetRenderIndex( int index ); + + inline CoreDispVert_t *GetDispVert( int iVert ) { return &m_pVerts[iVert]; } + inline CoreDispVert_t *GetDispVertList(); + inline unsigned short *GetRenderIndexList( void ); + + inline void SetTouched( bool touched ); + inline bool IsTouched( void ); + + void CalcDispSurfCoords( bool bLightMap, int lightmapID ); + void GetPositionOnSurface( float u, float v, Vector &vPos, Vector *pNormal, float *pAlpha ); + + void DispUVToSurf( Vector2D const &dispUV, Vector &vecPoint, Vector *pNormal, float *pAlpha ); + void BaseFacePlaneToDispUV( Vector const &planePt, Vector2D &dispUV ); + bool SurfToBaseFacePlane( Vector const &surfPt, Vector &planePt ); + + const CDispCornerNeighbors* GetCornerNeighbors( int iCorner ) const { return GetSurface()->GetCornerNeighbors( iCorner ); } + const CDispNeighbor* GetEdgeNeighbor( int iEdge ) const { return GetSurface()->GetEdgeNeighbor( iEdge ); } + + void SetListIndex( int nIndex ) { m_nListIndex = nIndex; } + int GetListIndex( void ) { return m_nListIndex; } + + CBitVec& GetAllowedVerts() { return m_AllowedVerts; } + const CBitVec& GetAllowedVerts() const { return m_AllowedVerts; } + void AllowedVerts_Clear( void ) { m_AllowedVerts.SetAll(); } + int AllowedVerts_GetNumDWords() const { return m_AllowedVerts.GetNumDWords(); } + unsigned long AllowedVerts_GetDWord(int i) const { return m_AllowedVerts.GetDWord( i ); } + void AllowedVerts_SetDWord(int i, unsigned long val) { m_AllowedVerts.SetDWord( i, val ); } + + + void Position_Update( int iVert, Vector vecPos ); + + //========================================================================= + // + // friend functions + // + friend void SmoothNeighboringDispSurfNormals( CCoreDispInfo **ppCoreDispInfoList, int listSize ); + +private: + // be changed to match the paint normal next pass) + // LOD/collision node data + CCoreDispNode *m_Nodes; // LOD quad-tree nodes + + float m_Elevation; // distance along the subdivision normal (should + + // defines the size of the displacement surface + int m_Power; // "size" of the displacement map + + // base surface data + CCoreDispSurface m_Surf; // surface containing displacement data + // be changed to match the paint normal next pass) + // Vertex data.. + CoreDispVert_t *m_pVerts; + + // Triangle data.. + CoreDispTri_t *m_pTris; + + // render specific data + int m_RenderIndexCount; // number of indices used in rendering + unsigned short *m_RenderIndices; // rendering index list (list of triangles) + int m_RenderCounter; // counter to verify surfaces are renderered/collided with only once per frame + + // utility data + bool m_bTouched; // touched flag + CCoreDispInfo *m_pNext; // used for chaining + + // The list that this disp is in (used for CDispUtils::IHelper implementation). + CCoreDispInfo **m_ppListBase; + int m_ListSize; + + CBitVec m_AllowedVerts; // Built in VBSP. Defines which verts are allowed to exist based on what the neighbors are. + + int m_nListIndex; + + //========================================================================= + // + // Creation Functions + // + + void GenerateDispSurf( void ); + void GenerateDispSurfNormals( void ); + void GenerateDispSurfTangentSpaces( void ); + bool DoesEdgeExist( int indexRow, int indexCol, int direction, int postSpacing ); + void CalcNormalFromEdges( int indexRow, int indexCol, bool bIsEdge[4], Vector& normal ); + void CalcDispSurfAlphas( void ); + void GenerateLODTree( void ); + void CalcVertIndicesAtNodes( int nodeIndex ); + int GetNodeVertIndexFromParentIndex( int level, int parentVertIndex, int direction ); + void CalcNodeInfo( int nodeIndex, int terminationLevel ); + void CalcNeighborVertIndicesAtNode( int nodeIndex, int level ); + void CalcNeighborNodeIndicesAtNode( int nodeIndex, int level ); + void CalcErrorTermAtNode( int nodeIndex, int level ); + float GetMaxErrorFromChildren( int nodeIndex, int level ); + void CalcBoundingBoxAtNode( int nodeIndex ); + void CalcMinMaxBoundingBoxAtNode( int nodeIndex, Vector& bMin, Vector& bMax ); + void CalcTriSurfInfoAtNode( int nodeIndex ); + void CalcTriSurfIndices( int nodeIndex, int indices[8][3] ); + void CalcTriSurfBoundingBoxes( int nodeIndex, int indices[8][3] ); + void CalcRayBoundingBoxes( int nodeIndex, int indices[8][3] ); + void CalcTriSurfPlanes( int nodeIndex, int indices[8][3] ); + void GenerateCollisionData( void ); + void GenerateCollisionSurface( void ); + + void CreateBoundingBoxes( CoreDispBBox_t *pBBox, int count ); + + void DispUVToSurf_TriTLToBR( Vector &vecPoint, Vector *pNormal, float *pAlpha, float flU, float flV, const Vector &vecIntersectPoint ); + void DispUVToSurf_TriBLToTR( Vector &vecPoint, Vector *pNormal, float *pAlpha, float flU, float flV, const Vector &vecIntersectPoint ); + void DispUVToSurf_TriTLToBR_1( const Vector &vecIntersectPoint, int nSnapU, int nNextU, int nSnapV, int nNextV, Vector &vecPoint, Vector *pNormal, float *pAlpha, bool bBackup ); + void DispUVToSurf_TriTLToBR_2( const Vector &vecIntersectPoint, int nSnapU, int nNextU, int nSnapV, int nNextV, Vector &vecPoint, Vector *pNormal, float *pAlpha, bool bBackup ); + void DispUVToSurf_TriBLToTR_1( const Vector &vecIntersectPoint, int nSnapU, int nNextU, int nSnapV, int nNextV, Vector &vecPoint, Vector *pNormal, float *pAlpha, bool bBackup ); + void DispUVToSurf_TriBLToTR_2( const Vector &vecIntersectPoint, int nSnapU, int nNextU, int nSnapV, int nNextV, Vector &vecPoint, Vector *pNormal, float *pAlpha, bool bBackup ); + + void GetTriangleIndicesForDispBBox( int nIndex, int nTris[2][3] ); + + void BuildTriTLtoBR( int ndx ); + void BuildTriBLtoTR( int ndx ); + + void InitTris( void ); + void CreateTris( void ); +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetPower( int power ) +{ + m_Power = power; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetPower( void ) const +{ + return m_Power; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetPostSpacing( void ) +{ + return ( ( 1 << m_Power ) + 1 ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetWidth( void ) +{ + return ( ( 1 << m_Power ) + 1 ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetHeight( void ) +{ + return ( ( 1 << m_Power ) + 1 ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetSize( void ) const +{ + return ( ( ( 1 << m_Power ) + 1 ) * ( ( 1 << m_Power ) + 1 ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetVert( int index, Vector const &vert ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( vert, m_pVerts[index].m_Vert ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetVert( int index, Vector& vert ) const +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( m_pVerts[index].m_Vert, vert ); +} + + +inline const Vector& CCoreDispInfo::GetVert( int index ) const +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + return m_pVerts[index].m_Vert; +} + +inline const Vector& CCoreDispInfo::GetVert( const CVertIndex &index ) const +{ + return GetVert( VertIndexToInt( index ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetFlatVert( int index, Vector& vert ) const +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( m_pVerts[index].m_FlatVert, vert ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetFlatVert( int index, const Vector &vert ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( vert, m_pVerts[index].m_FlatVert ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetNormal( int index, Vector const &normal ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( normal, m_pVerts[index].m_Normal ); +} + + +inline void CCoreDispInfo::SetNormal( const CVertIndex &index, Vector const &normal ) +{ + SetNormal( VertIndexToInt( index ), normal ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetNormal( int index, Vector& normal ) const +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( m_pVerts[index].m_Normal, normal ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline const Vector& CCoreDispInfo::GetNormal( int index ) const +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + return m_pVerts[index].m_Normal; +} + + +inline const Vector& CCoreDispInfo::GetNormal( const CVertIndex &index ) const +{ + return GetNormal( VertIndexToInt( index ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetTangentS( int index, Vector& tangentS ) const +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + VectorCopy( m_pVerts[index].m_TangentS, tangentS ); +} + +inline const Vector &CCoreDispInfo::GetTangentS( int index ) const +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + return m_pVerts[index].m_TangentS; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetTangentT( int index, Vector& tangentT ) const +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + VectorCopy( m_pVerts[index].m_TangentT, tangentT ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetTexCoord( int index, Vector2D const& texCoord ) +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + Vector2DCopy( texCoord, m_pVerts[index].m_TexCoord ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetTexCoord( int index, Vector2D& texCoord ) const +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + Vector2DCopy( m_pVerts[index].m_TexCoord, texCoord ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetLuxelCoord( int bumpIndex, int index, Vector2D const& luxelCoord ) +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + Assert( bumpIndex >= 0 ); + Assert( bumpIndex < NUM_BUMP_VECTS + 1 ); + Vector2DCopy( luxelCoord, m_pVerts[index].m_LuxelCoords[bumpIndex] ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetLuxelCoord( int bumpIndex, int index, Vector2D& luxelCoord ) const +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + Assert( bumpIndex >= 0 ); + Assert( bumpIndex < NUM_BUMP_VECTS + 1 ); + Vector2DCopy( m_pVerts[index].m_LuxelCoords[bumpIndex], luxelCoord ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetAlpha( int index, float alpha ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + m_pVerts[index].m_Alpha = alpha; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline float CCoreDispInfo::GetAlpha( int index ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + return m_pVerts[index].m_Alpha; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetElevation( float elevation ) +{ + m_Elevation = elevation; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline float CCoreDispInfo::GetElevation( void ) +{ + return m_Elevation; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::ResetFieldVectors( void ) +{ +// Vector normal; +// m_Surf.GetNormal( normal ); + + int size = GetSize(); + for( int i = 0; i < size; i++ ) + { + m_pVerts[i].m_FieldVector.Init(); +// m_FieldVectors[i] = normal; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetFieldVector( int index, Vector const &v ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( v, m_pVerts[index].m_FieldVector ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetFieldVector( int index, Vector& v ) +{ + Assert( index >= 0 ); + Assert( index < MAX_VERT_COUNT ); + VectorCopy( m_pVerts[index].m_FieldVector, v ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::ResetSubdivPositions( void ) +{ + int size = GetSize(); + for( int i = 0; i < size; i++ ) + { + m_pVerts[i].m_SubdivPos.Init(); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetSubdivPosition( int ndx, Vector const &v ) +{ + Assert( ndx >= 0 ); + Assert( ndx < MAX_VERT_COUNT ); + m_pVerts[ndx].m_SubdivPos = v; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetSubdivPosition( int ndx, Vector& v ) +{ + Assert( ndx >= 0 ); + Assert( ndx < MAX_VERT_COUNT ); + v = m_pVerts[ndx].m_SubdivPos; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::ResetSubdivNormals( void ) +{ + Vector normal; + m_Surf.GetNormal( normal ); + + int size = GetSize(); + for( int i = 0; i < size; i++ ) + { + m_pVerts[i].m_SubdivNormal = normal; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetSubdivNormal( int ndx, Vector const &v ) +{ + Assert( ndx >= 0 ); + Assert( ndx < MAX_VERT_COUNT ); + m_pVerts[ndx].m_SubdivNormal = v; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::GetSubdivNormal( int ndx, Vector &v ) +{ + Assert( ndx >= 0 ); + Assert( ndx < MAX_VERT_COUNT ); + v = m_pVerts[ndx].m_SubdivNormal; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::ResetFieldDistances( void ) +{ + int size = GetSize(); + for( int i = 0; i < size; i++ ) + { + m_pVerts[i].m_FieldDistance = 0.0f; + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetFieldDistance( int index, float dist ) +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + m_pVerts[index].m_FieldDistance = dist; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline float CCoreDispInfo::GetFieldDistance( int index ) +{ + Assert( index >= 0 ); + Assert( index < GetSize() ); + return m_pVerts[index].m_FieldDistance; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetRenderIndexCount( int count ) +{ + m_RenderIndexCount = count; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetRenderIndexCount( void ) +{ + return m_RenderIndexCount; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetRenderIndex( int index, int triIndex ) +{ + Assert( index >= 0 ); + Assert( index < ( MAX_VERT_COUNT*2*3) ); + m_RenderIndices[index] = triIndex; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CCoreDispInfo::GetRenderIndex( int index ) +{ + Assert( index >= 0 ); + Assert( index < ( MAX_VERT_COUNT*2*3) ); + return m_RenderIndices[index]; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline CoreDispVert_t *CCoreDispInfo::GetDispVertList() +{ + return m_pVerts; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline unsigned short *CCoreDispInfo::GetRenderIndexList( void ) +{ + return &m_RenderIndices[0]; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CCoreDispInfo::SetTouched( bool touched ) +{ + m_bTouched = touched; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline bool CCoreDispInfo::IsTouched( void ) +{ + return m_bTouched; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline CCoreDispNode *CCoreDispInfo::GetNode( int index ) +{ + Assert( index >= 0 ); + Assert( index < MAX_NODE_COUNT ); + return &m_Nodes[index]; +} + +bool CalcBarycentricCooefs( Vector const &v0, Vector const &v1, Vector const &v2, + Vector const &pt, float &c0, float &c1, float &c2 ); + +#endif // BUILDDISP_H diff --git a/public/captioncompiler.h b/public/captioncompiler.h new file mode 100644 index 0000000..1b723dc --- /dev/null +++ b/public/captioncompiler.h @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef CAPTIONCOMPILER_H +#define CAPTIONCOMPILER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamap.h" +#include "checksum_crc.h" + +#define MAX_BLOCK_BITS 13 + +#define MAX_BLOCK_SIZE (1<deleteThis() + virtual void ServerCmdKeyValues( KeyValues *pKeyValues ) = 0; + + virtual bool IsSkippingPlayback( void ) = 0; + virtual bool IsLoadingDemo( void ) = 0; + + // Returns true if the engine is playing back a "locally recorded" demo, which includes + // both SourceTV and replay demos, since they're recorded locally (on servers), as opposed + // to a client recording a demo while connected to a remote server. + virtual bool IsPlayingDemoALocallyRecordedDemo() = 0; + + // Given the string pBinding which may be bound to a key, + // returns the string name of the key to which this string is bound. Returns NULL if no such binding exists + // Unlike Key_LookupBinding, leading '+' characters are not stripped from bindings. + virtual const char *Key_LookupBindingExact( const char *pBinding ) = 0; + + virtual void GMOD_SetTimeManipulator( float fScaleFramerate ); + virtual void GMOD_SendToServer( void *data, unsigned int dataSize, bool reliable ); + virtual void GMOD_PlaceDecalMaterial( IMaterial *, bool, int, IClientEntity *, const Vector &, const Vector &, const color32_s &, float, float ); + virtual void GMOD_GetSpew( char *buffer, unsigned int bufferSize ); + virtual void GMOD_SetViewEntity( uint ); + virtual void GMOD_BrushMaterialOverride( IMaterial *matOverride ); + virtual void GMOD_R_RedownloadAllLightmaps( bool ); + virtual void GMOD_RawClientCmd_Unrestricted( const char *command ); + virtual IGMODDataTable *GMOD_CreateDataTable( void( * )( void *, int, const CGMODVariant & ) ); + virtual void GMOD_DestroyDataTable( IGMODDataTable *dataTable ); + virtual void GMOD_LoadModel( const char *path ); + +}; + +abstract_class IVEngineClient : public IVEngineClient013 +{ +public: + virtual uint GetProtocolVersion() = 0; + virtual bool IsWindowedMode() = 0; + + // Flash the window (os specific) + virtual void FlashWindow() = 0; + + // Client version from the steam.inf, this will be compared to the GC version + virtual int GetClientVersion() const = 0; // engines build + + // Is App Active + virtual bool IsActiveApp() = 0; + + virtual void DisconnectInternal() = 0; + + virtual bool IsInCommentaryMode( ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Interface exposed from the client .dll back to the engine +//----------------------------------------------------------------------------- +abstract_class IBaseClientDLL +{ +public: + // Called once when the client DLL is loaded + virtual int Init( CreateInterfaceFn appSystemFactory, + CreateInterfaceFn physicsFactory, + CGlobalVarsBase *pGlobals ) = 0; + + virtual void PostInit() = 0; + + // Called once when the client DLL is being unloaded + virtual void Shutdown( void ) = 0; + + // Called once the client is initialized to setup client-side replay interface pointers + virtual bool ReplayInit( CreateInterfaceFn replayFactory ) = 0; + virtual bool ReplayPostInit() = 0; + + // Called at the start of each level change + virtual void LevelInitPreEntity( char const* pMapName ) = 0; + // Called at the start of a new level, after the entities have been received and created + virtual void LevelInitPostEntity( ) = 0; + // Called at the end of a level + virtual void LevelShutdown( void ) = 0; + + // Request a pointer to the list of client datatable classes + virtual ClientClass *GetAllClasses( void ) = 0; + + // Called once per level to re-initialize any hud element drawing stuff + virtual int HudVidInit( void ) = 0; + // Called by the engine when gathering user input + virtual void HudProcessInput( bool bActive ) = 0; + // Called oncer per frame to allow the hud elements to think + virtual void HudUpdate( bool bActive ) = 0; + // Reset the hud elements to their initial states + virtual void HudReset( void ) = 0; + // Display a hud text message + virtual void HudText( const char * message ) = 0; + + // Mouse Input Interfaces + // Activate the mouse (hides the cursor and locks it to the center of the screen) + virtual void IN_ActivateMouse( void ) = 0; + // Deactivates the mouse (shows the cursor and unlocks it) + virtual void IN_DeactivateMouse( void ) = 0; + // This is only called during extra sound updates and just accumulates mouse x, y offets and recenters the mouse. + // This call is used to try to prevent the mouse from appearing out of the side of a windowed version of the engine if + // rendering or other processing is taking too long + virtual void IN_Accumulate (void) = 0; + // Reset all key and mouse states to their initial, unpressed state + virtual void IN_ClearStates (void) = 0; + // If key is found by name, returns whether it's being held down in isdown, otherwise function returns false + virtual bool IN_IsKeyDown( const char *name, bool& isdown ) = 0; + // Notify the client that the mouse was wheeled while in game - called prior to executing any bound commands. + virtual void IN_OnMouseWheeled( int nDelta ) = 0; + // Raw keyboard signal, if the client .dll returns 1, the engine processes the key as usual, otherwise, + // if the client .dll returns 0, the key is swallowed. + virtual int IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding ) = 0; + + // This function is called once per tick to create the player CUserCmd (used for prediction/physics simulation of the player) + // Because the mouse can be sampled at greater than the tick interval, there is a separate input_sample_frametime, which + // specifies how much additional mouse / keyboard simulation to perform. + virtual void CreateMove ( + int sequence_number, // sequence_number of this cmd + float input_sample_frametime, // Frametime for mouse input sampling + bool active ) = 0; // True if the player is active (not paused) + + // If the game is running faster than the tick_interval framerate, then we do extra mouse sampling to avoid jittery input + // This code path is much like the normal move creation code, except no move is created + virtual void ExtraMouseSample( float frametime, bool active ) = 0; + + // Encode the delta (changes) between the CUserCmd in slot from vs the one in slot to. The game code will have + // matching logic to read the delta. + virtual bool WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand ) = 0; + // Demos need to be able to encode/decode CUserCmds to memory buffers, so these functions wrap that + virtual void EncodeUserCmdToBuffer( bf_write& buf, int slot ) = 0; + virtual void DecodeUserCmdFromBuffer( bf_read& buf, int slot ) = 0; + + // Set up and render one or more views (e.g., rear view window, etc.). This called into RenderView below + virtual void View_Render( vrect_t *rect ) = 0; + + // Allow engine to expressly render a view (e.g., during timerefresh) + // See IVRenderView.h, PushViewFlags_t for nFlags values + virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) = 0; + + // Apply screen fade directly from engine + virtual void View_Fade( ScreenFade_t *pSF ) = 0; + + // The engine has parsed a crosshair angle message, this function is called to dispatch the new crosshair angle + virtual void SetCrosshairAngle( const QAngle& angle ) = 0; + + // Sprite (.spr) model handling code + // Load a .spr file by name + virtual void InitSprite( CEngineSprite *pSprite, const char *loadname ) = 0; + // Shutdown a .spr file + virtual void ShutdownSprite( CEngineSprite *pSprite ) = 0; + // Returns sizeof( CEngineSprite ) so the engine can allocate appropriate memory + virtual int GetSpriteSize( void ) const = 0; + + // Called when a player starts or stops talking. + // entindex is -1 to represent the local client talking (before the data comes back from the server). + // entindex is -2 to represent the local client's voice being acked by the server. + // entindex is GetPlayer() when the server acknowledges that the local client is talking. + virtual void VoiceStatus( int entindex, qboolean bTalking ) = 0; + + // Networked string table definitions have arrived, allow client .dll to + // hook string changes with a callback function ( see INetworkStringTableClient.h ) + virtual void InstallStringTableCallback( char const *tableName ) = 0; + + // Notification that we're moving into another stage during the frame. + virtual void FrameStageNotify( ClientFrameStage_t curStage ) = 0; + + // The engine has received the specified user message, this code is used to dispatch the message handler + virtual bool DispatchUserMessage( int msg_type, bf_read &msg_data ) = 0; + + // Save/restore system hooks + virtual CSaveRestoreData *SaveInit( int size ) = 0; + virtual void SaveWriteFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveReadFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void PreSave( CSaveRestoreData * ) = 0; + virtual void Save( CSaveRestoreData * ) = 0; + virtual void WriteSaveHeaders( CSaveRestoreData * ) = 0; + virtual void ReadRestoreHeaders( CSaveRestoreData * ) = 0; + virtual void Restore( CSaveRestoreData *, bool ) = 0; + virtual void DispatchOnRestore() = 0; + + // Hand over the StandardRecvProxies in the client DLL's module. + virtual CStandardRecvProxies* GetStandardRecvProxies() = 0; + + // save game screenshot writing + virtual void WriteSaveGameScreenshot( const char *pFilename ) = 0; + + // Given a list of "S(wavname) S(wavname2)" tokens, look up the localized text and emit + // the appropriate close caption if running with closecaption = 1 + virtual void EmitSentenceCloseCaption( char const *tokenstream ) = 0; + // Emits a regular close caption by token name + virtual void EmitCloseCaption( char const *captionname, float duration ) = 0; + + // Returns true if the client can start recording a demo now. If the client returns false, + // an error message of up to length bytes should be returned in errorMsg. + virtual bool CanRecordDemo( char *errorMsg, int length ) const = 0; + + // Give the Client a chance to do setup/cleanup. + virtual void OnDemoRecordStart( char const* pDemoBaseName ) = 0; + virtual void OnDemoRecordStop() = 0; + virtual void OnDemoPlaybackStart( char const* pDemoBaseName ) = 0; + virtual void OnDemoPlaybackStop() = 0; + + // Draw the console overlay? + virtual bool ShouldDrawDropdownConsole() = 0; + + // Get client screen dimensions + virtual int GetScreenWidth() = 0; + virtual int GetScreenHeight() = 0; + + // Added interface + + // save game screenshot writing + virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded = false, bool bWriteVTF = false ) = 0; + + // Gets the current view + virtual bool GetPlayerView( CViewSetup &playerView ) = 0; + + // Matchmaking + virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) = 0; + virtual uint GetPresenceID( const char *pIDName ) = 0; + virtual const char *GetPropertyIdString( const uint id ) = 0; + virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) = 0; + +#ifdef WIN32 + virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ) = 0; +#endif + + virtual void InvalidateMdlCache() = 0; + + virtual void IN_SetSampleTime( float frametime ) = 0; + + + // For sv_pure mode. The filesystem figures out which files the client needs to reload to be "pure" ala the server's preferences. + virtual void ReloadFilesInList( IFileList *pFilesToReload ) = 0; +#ifdef POSIX + // AR: Same as above win32 defn but down here at the end of the vtable for back compat + virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ) = 0; +#endif + + // Let the client handle UI toggle - if this function returns false, the UI will toggle, otherwise it will not. + virtual bool HandleUiToggle() = 0; + + // Allow the console to be shown? + virtual bool ShouldAllowConsole() = 0; + + // Get renamed recv tables + virtual CRenamedRecvTableInfo *GetRenamedRecvTableInfos() = 0; + + // Get the mouthinfo for the sound being played inside UI panels + virtual CMouthInfo *GetClientUIMouthInfo() = 0; + + // Notify the client that a file has been received from the game server + virtual void FileReceived( const char * fileName, unsigned int transferID ) = 0; + + virtual const char* TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName ) = 0; + + // Give the client a chance to modify sound settings however they want before the sound plays. This is used for + // things like adjusting pitch of voice lines in Pyroland in TF2. + virtual void ClientAdjustStartSoundParams( struct StartSoundParams_t& params ) = 0; + + // Returns true if the disconnect command has been handled by the client + virtual bool DisconnectAttempt( void ) = 0; + + virtual bool IsConnectedUserInfoChangeAllowed( IConVar *pCvar ) = 0; +}; + +#define CLIENT_DLL_INTERFACE_VERSION "VClient017" + +//----------------------------------------------------------------------------- +// Purpose: Interface exposed from the client .dll back to the engine for specifying shared .dll IAppSystems (e.g., ISoundEmitterSystem) +//----------------------------------------------------------------------------- +abstract_class IClientDLLSharedAppSystems +{ +public: + virtual int Count() = 0; + virtual char const *GetDllName( int idx ) = 0; + virtual char const *GetInterfaceName( int idx ) = 0; +}; + +#define CLIENT_DLL_SHARED_APPSYSTEMS "VClientDllSharedAppSystems001" + +#endif // CDLL_INT_H diff --git a/public/chunkfile.cpp b/public/chunkfile.cpp new file mode 100644 index 0000000..81a77dd --- /dev/null +++ b/public/chunkfile.cpp @@ -0,0 +1,985 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements an interface for reading and writing heirarchical +// text files of key value pairs. The format of the file is as follows: +// +// chunkname0 +// { +// "key0" "value0" +// "key1" "value1" +// ... +// "keyN" "valueN" +// chunkname1 +// { +// "key0" "value0" +// "key1" "value1" +// ... +// "keyN" "valueN" +// } +// } +// ... +// chunknameN +// { +// "key0" "value0" +// "key1" "value1" +// ... +// "keyN" "valueN" +// } +// +// The chunk names are not necessarily unique, nor are the key names, unless the +// parsing application requires them to be. +// +// $NoKeywords: $ +//=============================================================================// + +#include +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include "chunkfile.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "tier1/strtools.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. +//----------------------------------------------------------------------------- +CChunkHandlerMap::CChunkHandlerMap(void) +{ + m_pHandlers = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor. Frees handler list. +//----------------------------------------------------------------------------- +CChunkHandlerMap::~CChunkHandlerMap(void) +{ + ChunkHandlerInfoNode_t *pNode = m_pHandlers; + while (pNode != NULL) + { + ChunkHandlerInfoNode_t *pPrev = pNode; + pNode = pNode->pNext; + + delete pPrev; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Adds a chunk handler to the handler list. +// Input : pszChunkName - Name of chunk to be handled. +// pfnHandler - Address of handler callback function. +// pData - Data to pass to the handler callback. +//----------------------------------------------------------------------------- +void CChunkHandlerMap::AddHandler(const char *pszChunkName, ChunkHandler_t pfnHandler, void *pData) +{ + ChunkHandlerInfoNode_t *pNew = new ChunkHandlerInfoNode_t; + + Q_strncpy(pNew->Handler.szChunkName, pszChunkName, sizeof( pNew->Handler.szChunkName )); + pNew->Handler.pfnHandler = pfnHandler; + pNew->Handler.pData = pData; + pNew->pNext = NULL; + + if (m_pHandlers == NULL) + { + m_pHandlers = pNew; + } + else + { + ChunkHandlerInfoNode_t *pNode = m_pHandlers; + while (pNode->pNext != NULL) + { + pNode = pNode->pNext; + } + pNode->pNext = pNew; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the callback for error handling within this chunk's scope. +// Input : pfnHandler - +// pData - +//----------------------------------------------------------------------------- +void CChunkHandlerMap::SetErrorHandler(ChunkErrorHandler_t pfnHandler, void *pData) +{ + m_pfnErrorHandler = pfnHandler; + m_pErrorData = pData; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ppData - +// Output : ChunkErrorHandler_t +//----------------------------------------------------------------------------- +ChunkErrorHandler_t CChunkHandlerMap::GetErrorHandler(void **ppData) +{ + *ppData = m_pErrorData; + return(m_pfnErrorHandler); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the handler for a given chunk name, if one has been set. +// Input : pszChunkName - Name of chunk. +// ppfnHandler - Receives the address of the callback function. +// ppData - Receives the context data for the given chunk. +// Output : Returns true if a handler was found, false if not. +//----------------------------------------------------------------------------- +ChunkHandler_t CChunkHandlerMap::GetHandler(const char *pszChunkName, void **ppData) +{ + ChunkHandlerInfoNode_t *pNode = m_pHandlers; + while (pNode != NULL) + { + if (!stricmp(pNode->Handler.szChunkName, pszChunkName)) + { + *ppData = pNode->Handler.pData; + return(pNode->Handler.pfnHandler); + } + + pNode = pNode->pNext; + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. Initializes data members. +//----------------------------------------------------------------------------- +CChunkFile::CChunkFile(void) +{ + m_hFile = NULL; + m_nCurrentDepth = 0; + m_szIndent[0] = '\0'; + m_nHandlerStackDepth = 0; + m_DefaultChunkHandler = 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor. Closes the file if it is currently open. +//----------------------------------------------------------------------------- +CChunkFile::~CChunkFile(void) +{ + if (m_hFile != NULL) + { + fclose(m_hFile); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszChunkName - +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::BeginChunk(const char *pszChunkName) +{ + // + // Write the chunk name and open curly. + // + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "%s\r\n%s{", pszChunkName, m_szIndent); + ChunkFileResult_t eResult = WriteLine(szBuf); + + // + // Update the indentation depth. + // + if (eResult == ChunkFile_Ok) + { + m_nCurrentDepth++; + BuildIndentString(m_szIndent, m_nCurrentDepth); + } + + return(eResult); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CChunkFile::BuildIndentString(char *pszDest, int nDepth) +{ + if (nDepth >= 0) + { + for (int i = 0; i < nDepth; i++) + { + pszDest[i] = '\t'; + } + + pszDest[nDepth] = '\0'; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::Close(void) +{ + if (m_hFile != NULL) + { + fclose(m_hFile); + m_hFile = NULL; + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::EndChunk(void) +{ + if (m_nCurrentDepth > 0) + { + m_nCurrentDepth--; + BuildIndentString(m_szIndent, m_nCurrentDepth); + } + + WriteLine("}"); + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a string explaining the last error that occurred. +//----------------------------------------------------------------------------- +const char *CChunkFile::GetErrorText(ChunkFileResult_t eResult) +{ + static char szError[MAX_KEYVALUE_LEN]; + + switch (eResult) + { + case ChunkFile_UnexpectedEOF: + { + Q_strncpy(szError, "unexpected end of file", sizeof( szError ) ); + break; + } + + case ChunkFile_UnexpectedSymbol: + { + Q_snprintf(szError, sizeof( szError ), "unexpected symbol '%s'", m_szErrorToken); + break; + } + + case ChunkFile_OpenFail: + { + Q_snprintf(szError, sizeof( szError ), "%s", strerror(errno)) ; + break; + } + + case ChunkFile_StringTooLong: + { + Q_strncpy(szError, "unterminated string or string too long", sizeof( szError ) ); + break; + } + + default: + { + Q_snprintf(szError, sizeof( szError ), "error %d", eResult); + } + } + + return(m_TokenReader.Error(szError)); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : eError - +//----------------------------------------------------------------------------- +void CChunkFile::HandleError(const char *szChunkName, ChunkFileResult_t eError) +{ + // UNDONE: dispatch errors to the error handler. + // - keep track of current chunkname for reporting errors + // - use the last non-NULL handler that was pushed onto the stack? + // - need a return code to determine whether to abort parsing? +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : ChunkFileResult_t +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::HandleChunk(const char *szChunkName) +{ + // See if the default handler wants it? + if( m_DefaultChunkHandler ) + { + ChunkFileResult_t testResult = m_DefaultChunkHandler( this, m_pDefaultChunkHandlerData, szChunkName ); + if( testResult == ChunkFile_Ok ) + { + return ChunkFile_Ok; + } + } + + // + // If there is an active handler map... + // + if (m_nHandlerStackDepth > 0) + { + CChunkHandlerMap *pHandler = m_HandlerStack[m_nHandlerStackDepth - 1]; + + // + // If a chunk handler was found in the handler map... + // + void *pData; + ChunkHandler_t pfnHandler = pHandler->GetHandler(szChunkName, &pData); + if (pfnHandler != NULL) + { + // Dispatch this chunk to the handler. + ChunkFileResult_t eResult = pfnHandler(this, pData); + if (eResult != ChunkFile_Ok) + { + return(eResult); + } + } + else + { + // + // No handler for this chunk. Skip to the matching close curly brace. + // + int nDepth = 1; + ChunkFileResult_t eResult; + + do + { + ChunkType_t eChunkType; + char szKey[MAX_KEYVALUE_LEN]; + char szValue[MAX_KEYVALUE_LEN]; + + while ((eResult = ReadNext(szKey, szValue, sizeof(szValue), eChunkType)) == ChunkFile_Ok) + { + if (eChunkType == ChunkType_Chunk) + { + nDepth++; + } + } + + if (eResult == ChunkFile_EndOfChunk) + { + eResult = ChunkFile_Ok; + nDepth--; + } + else if (eResult == ChunkFile_EOF) + { + return(ChunkFile_UnexpectedEOF); + } + + } while ((nDepth) && (eResult == ChunkFile_Ok)); + } + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: Opens the chunk file for reading or writing. +// Input : pszFileName - Path of file to open. +// eMode - ChunkFile_Read or ChunkFile_Write. +// Output : Returns ChunkFile_Ok on success, ChunkFile_Fail on failure. +// UNDONE: boolean return value? +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::Open(const char *pszFileName, ChunkFileOpenMode_t eMode) +{ + if (eMode == ChunkFile_Read) + { + // UNDONE: TokenReader encapsulates file - unify reading and writing to use the same file I/O. + // UNDONE: Support in-memory parsing. + if (m_TokenReader.Open(pszFileName)) + { + m_nCurrentDepth = 0; + } + else + { + return(ChunkFile_OpenFail); + } + } + else if (eMode == ChunkFile_Write) + { + m_hFile = fopen(pszFileName, "wb"); + + if (m_hFile == NULL) + { + return(ChunkFile_OpenFail); + } + + m_nCurrentDepth = 0; + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: Removes the topmost set of chunk handlers. +//----------------------------------------------------------------------------- +void CChunkFile::PopHandlers(void) +{ + if (m_nHandlerStackDepth > 0) + { + m_nHandlerStackDepth--; + } +} + + +void CChunkFile::SetDefaultChunkHandler( DefaultChunkHandler_t pHandler, void *pData ) +{ + m_DefaultChunkHandler = pHandler; + m_pDefaultChunkHandlerData = pData;} + + +//----------------------------------------------------------------------------- +// Purpose: Adds a set of chunk handlers to the top of the handler stack. +// Input : pHandlerMap - Object containing the list of chunk handlers. +//----------------------------------------------------------------------------- +void CChunkFile::PushHandlers(CChunkHandlerMap *pHandlerMap) +{ + if (m_nHandlerStackDepth < MAX_INDENT_DEPTH) + { + m_HandlerStack[m_nHandlerStackDepth] = pHandlerMap; + m_nHandlerStackDepth++; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads the next term from the chunk file. The type of term read is +// returned in the eChunkType parameter. +// Input : szName - Name of key or chunk. +// szValue - If eChunkType is ChunkType_Key, contains the value of the key. +// nValueSize - Size of the buffer pointed to by szValue. +// eChunkType - ChunkType_Key or ChunkType_Chunk. +// Output : Returns ChunkFile_Ok on success, an error code if a parsing error occurs. +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::ReadNext(char *szName, char *szValue, int nValueSize, ChunkType_t &eChunkType) +{ + // HACK: pass in buffer sizes? + trtoken_t eTokenType = m_TokenReader.NextToken(szName, MAX_KEYVALUE_LEN); + + if (eTokenType != TOKENEOF) + { + switch (eTokenType) + { + case IDENT: + case STRING: + { + char szNext[MAX_KEYVALUE_LEN]; + trtoken_t eNextTokenType; + + // + // Read the next token to determine what we have. + // + eNextTokenType = m_TokenReader.NextToken(szNext, sizeof(szNext)); + + switch (eNextTokenType) + { + case OPERATOR: + { + if (!stricmp(szNext, "{")) + { + // Beginning of new chunk. + m_nCurrentDepth++; + eChunkType = ChunkType_Chunk; + szValue[0] = '\0'; + return(ChunkFile_Ok); + } + else + { + // Unexpected symbol. + Q_strncpy(m_szErrorToken, szNext, sizeof( m_szErrorToken ) ); + return(ChunkFile_UnexpectedSymbol); + } + } + + case STRING: + case IDENT: + { + // Key value pair. + Q_strncpy(szValue, szNext, nValueSize ); + eChunkType = ChunkType_Key; + return(ChunkFile_Ok); + } + + case TOKENEOF: + { + // Unexpected end of file. + return(ChunkFile_UnexpectedEOF); + } + + case TOKENSTRINGTOOLONG: + { + // String too long or unterminated string. + return ChunkFile_StringTooLong; + } + } + } + + case OPERATOR: + { + if (!stricmp(szName, "}")) + { + // End of current chunk. + m_nCurrentDepth--; + return(ChunkFile_EndOfChunk); + } + else + { + // Unexpected symbol. + Q_strncpy(m_szErrorToken, szName, sizeof( m_szErrorToken ) ); + return(ChunkFile_UnexpectedSymbol); + } + } + + case TOKENSTRINGTOOLONG: + { + return ChunkFile_StringTooLong; + } + } + } + + if (m_nCurrentDepth != 0) + { + // End of file while within the scope of a chunk. + return(ChunkFile_UnexpectedEOF); + } + + return(ChunkFile_EOF); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads the current chunk and dispatches keys and sub-chunks to the +// appropriate handler callbacks. +// Input : pfnKeyHandler - Callback for any key values in this chunk. +// pData - Data to pass to the key value callback function. +// Output : Normally returns ChunkFile_Ok or ChunkFile_EOF. Otherwise, returns +// a ChunkFile_xxx error code. +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::ReadChunk(KeyHandler_t pfnKeyHandler, void *pData) +{ + // + // Read the keys and sub-chunks. + // + ChunkFileResult_t eResult; + do + { + char szName[MAX_KEYVALUE_LEN]; + char szValue[MAX_KEYVALUE_LEN]; + ChunkType_t eChunkType; + + eResult = ReadNext(szName, szValue, sizeof(szValue), eChunkType); + + if (eResult == ChunkFile_Ok) + { + if (eChunkType == ChunkType_Chunk) + { + // + // Dispatch sub-chunks to the appropriate handler. + // + eResult = HandleChunk(szName); + } + else if ((eChunkType == ChunkType_Key) && (pfnKeyHandler != NULL)) + { + // + // Dispatch keys to the key value handler. + // + eResult = pfnKeyHandler(szName, szValue, pData); + } + } + } while (eResult == ChunkFile_Ok); + + // + // Cover up ChunkFile_EndOfChunk results because the caller doesn't want to see them. + // + if (eResult == ChunkFile_EndOfChunk) + { + eResult = ChunkFile_Ok; + } + + // + // Dispatch errors to the handler. + // + if ((eResult != ChunkFile_Ok) && (eResult != ChunkFile_EOF)) + { + //HandleError("chunkname", eResult); + } + + return(eResult); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pbBool - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueBool(const char *pszValue, bool &bBool) +{ + int nValue = atoi(pszValue); + + if (nValue > 0) + { + bBool = true; + } + else + { + bBool = false; + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfFloat - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueFloat(const char *pszValue, float &flFloat) +{ + flFloat = (float)atof(pszValue); + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pnInt - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueInt(const char *pszValue, int &nInt) +{ + nInt = atoi(pszValue); + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// r - +// g - +// b - +// Output : +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueColor(const char *pszValue, unsigned char &chRed, unsigned char &chGreen, unsigned char &chBlue) +{ + if (pszValue != NULL) + { + int r = 0; + int g = 0; + int b = 0; + + if (sscanf(pszValue, "%d %d %d", &r, &g, &b) == 3) + { + chRed = r; + chGreen = g; + chBlue = b; + + return(true); + } + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfPoint - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValuePoint(const char *pszValue, Vector &Point) +{ + if (pszValue != NULL) + { + return(sscanf(pszValue, "(%f %f %f)", &Point.x, &Point.y, &Point.z) == 3); + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfVector - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueVector2(const char *pszValue, Vector2D &vec) +{ + if (pszValue != NULL) + { + return ( sscanf( pszValue, "[%f %f]", &vec.x, &vec.y) == 2 ); + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfVector - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueVector3(const char *pszValue, Vector &vec) +{ + if (pszValue != NULL) + { + return(sscanf(pszValue, "[%f %f %f]", &vec.x, &vec.y, &vec.z) == 3); + } + + return(false); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszValue - +// pfVector - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CChunkFile::ReadKeyValueVector4(const char *pszValue, Vector4D &vec) +{ + if( pszValue != NULL ) + { + return(sscanf(pszValue, "[%f %f %f %f]", &vec[0], &vec[1], &vec[2], &vec[3]) == 4); + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszLine - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValue(const char *pszKey, const char *pszValue) +{ + if ((pszKey != NULL) && (pszValue != NULL)) + { + char szTemp[MAX_KEYVALUE_LEN]; + Q_snprintf(szTemp, sizeof( szTemp ), "\"%s\" \"%s\"", pszKey, pszValue); + return(WriteLine(szTemp)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// bValue - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueBool(const char *pszKey, bool bValue) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, (int)bValue); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// nValue - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueInt(const char *pszKey, int nValue) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d\"", pszKey, nValue); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// fValue - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueFloat(const char *pszKey, float fValue) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%g\"", pszKey, (double)fValue); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// r - +// g - +// b - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueColor(const char *pszKey, unsigned char r, unsigned char g, unsigned char b) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"%d %d %d\"", pszKey, (int)r, (int)g, (int)b); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// fVector - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValuePoint(const char *pszKey, const Vector &Point) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"(%g %g %g)\"", pszKey, (double)Point[0], (double)Point[1], (double)Point[2]); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueVector2(const char *pszKey, const Vector2D &vec) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf( szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g]\"", pszKey, (double)vec.x, (double)vec.y ); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueVector3(const char *pszKey, const Vector &vec) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z); + return(WriteLine(szBuf)); + } + + return(ChunkFile_Ok); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszKey - +// fVector - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteKeyValueVector4(const char *pszKey, const Vector4D &vec) +{ + if (pszKey != NULL) + { + char szBuf[MAX_KEYVALUE_LEN]; + Q_snprintf(szBuf, sizeof( szBuf ), "\"%s\" \"[%g %g %g %g]\"", pszKey, (double)vec.x, (double)vec.y, (double)vec.z, (double)vec.w); + return( WriteLine( szBuf ) ); + } + + return( ChunkFile_Ok ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszLine - +// Output : +//----------------------------------------------------------------------------- +ChunkFileResult_t CChunkFile::WriteLine(const char *pszLine) +{ + if (pszLine != NULL) + { + // + // Write the indentation string. + // + if (m_nCurrentDepth > 0) + { + int nWritten = fwrite(m_szIndent, 1, m_nCurrentDepth, m_hFile); + if (nWritten != m_nCurrentDepth) + { + return(ChunkFile_Fail); + } + } + + // + // Write the string. + // + int nLen = strlen(pszLine); + int nWritten = fwrite(pszLine, 1, nLen, m_hFile); + if (nWritten != nLen) + { + return(ChunkFile_Fail); + } + + // + // Write the linefeed. + // + if (fwrite("\r\n", 1, 2, m_hFile) != 2) + { + return(ChunkFile_Fail); + } + } + + return(ChunkFile_Ok); +} + diff --git a/public/chunkfile.h b/public/chunkfile.h new file mode 100644 index 0000000..6359ace --- /dev/null +++ b/public/chunkfile.h @@ -0,0 +1,197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef CHUNKFILE_H +#define CHUNKFILE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tokenreader.h" + + +#define MAX_INDENT_DEPTH 80 +#define MAX_KEYVALUE_LEN 1024 + + +class CChunkFile; +class Vector2D; +class Vector; +class Vector4D; + + +// +// Modes for Open. +// +enum ChunkFileOpenMode_t +{ + ChunkFile_Read = 0, + ChunkFile_Write, +}; + + +// +// Return codes. +// +enum ChunkFileResult_t +{ + ChunkFile_Ok = 0, + ChunkFile_Fail, + ChunkFile_OpenFail, + ChunkFile_EndOfChunk, + ChunkFile_EOF, + ChunkFile_UnexpectedEOF, + ChunkFile_UnexpectedSymbol, + ChunkFile_OutOfMemory, + ChunkFile_StringTooLong, + ChunkFile_NotHandled +}; + + +enum ChunkType_t +{ + ChunkType_Key = 0, + ChunkType_Chunk, +}; + + +typedef ChunkFileResult_t (*DefaultChunkHandler_t)(CChunkFile *pFile, void *pData, char const *pChunkName); + +typedef ChunkFileResult_t (*ChunkHandler_t)(CChunkFile *pFile, void *pData); +typedef ChunkFileResult_t (*KeyHandler_t)(const char *szKey, const char *szValue, void *pData); +typedef bool (*ChunkErrorHandler_t)(CChunkFile *pFile, const char *szChunkName, void *pData); + + +struct ChunkHandlerInfo_t +{ + char szChunkName[80]; + ChunkHandler_t pfnHandler; + void *pData; +}; + + +struct ChunkHandlerInfoNode_t +{ + ChunkHandlerInfo_t Handler; + struct ChunkHandlerInfoNode_t *pNext; +}; + + +// +// Consider handling chunks with handler objects instead of callbacks. +// +//class CChunkHandler +//{ +// virtual ChunkFileResult_t HandleChunk(const char *szName); +// virtual ChunkFileResult_t HandleKey(const char *szKey, const char *szValue); +// virtual bool HandleError(const char *szChunkName, ChunkFileResult_t eError); +//}; + + +class CChunkHandlerMap +{ + public: + + CChunkHandlerMap(void); + ~CChunkHandlerMap(void); + + void AddHandler(const char *pszChunkName, ChunkHandler_t pfnHandler, void *pData); + ChunkHandler_t GetHandler(const char *pszChunkName, void **pData); + + void SetErrorHandler(ChunkErrorHandler_t pfnHandler, void *pData); + ChunkErrorHandler_t GetErrorHandler(void **pData); + + protected: + + ChunkHandlerInfoNode_t *m_pHandlers; + ChunkErrorHandler_t m_pfnErrorHandler; + void *m_pErrorData; +}; + + +class CChunkFile +{ + public: + + CChunkFile(void); + ~CChunkFile(void); + + ChunkFileResult_t Open(const char *pszFileName, ChunkFileOpenMode_t eMode); + ChunkFileResult_t Close(void); + const char *GetErrorText(ChunkFileResult_t eResult); + + // + // Functions for writing chunk files. + // + ChunkFileResult_t BeginChunk(const char *pszChunkName); + ChunkFileResult_t EndChunk(void); + + ChunkFileResult_t WriteKeyValue(const char *pszKey, const char *pszValue); + ChunkFileResult_t WriteKeyValueBool(const char *pszKey, bool bValue); + ChunkFileResult_t WriteKeyValueColor(const char *pszKey, unsigned char r, unsigned char g, unsigned char b); + ChunkFileResult_t WriteKeyValueFloat(const char *pszKey, float fValue); + ChunkFileResult_t WriteKeyValueInt(const char *pszKey, int nValue); + ChunkFileResult_t WriteKeyValuePoint(const char *pszKey, const Vector &Point); + ChunkFileResult_t WriteKeyValueVector2(const char *pszKey, const Vector2D &vec); + ChunkFileResult_t WriteKeyValueVector3(const char *pszKey, const Vector &vec); + ChunkFileResult_t WriteKeyValueVector4( const char *pszKey, const Vector4D &vec); + + ChunkFileResult_t WriteLine(const char *pszLine); + + // + // Functions for reading chunk files. + // + ChunkFileResult_t ReadChunk(KeyHandler_t pfnKeyHandler = NULL, void *pData = NULL); + ChunkFileResult_t ReadNext(char *szKey, char *szValue, int nValueSize, ChunkType_t &eChunkType); + ChunkFileResult_t HandleChunk(const char *szChunkName); + void HandleError(const char *szChunkName, ChunkFileResult_t eError); + + // These functions should more really be named Parsexxx and possibly moved elsewhere. + static bool ReadKeyValueBool(const char *pszValue, bool &bBool); + static bool ReadKeyValueColor(const char *pszValue, unsigned char &chRed, unsigned char &chGreen, unsigned char &chBlue); + static bool ReadKeyValueInt(const char *pszValue, int &nInt); + static bool ReadKeyValueFloat(const char *pszValue, float &flFloat); + static bool ReadKeyValuePoint(const char *pszValue, Vector &Point); + static bool ReadKeyValueVector2(const char *pszValue, Vector2D &vec); + static bool ReadKeyValueVector3(const char *pszValue, Vector &vec); + static bool ReadKeyValueVector4( const char *pszValue, Vector4D &vec); + + // The default chunk handler gets called before any other chunk handlers. + // + // If the handler returns ChunkFile_Ok, then it goes into the chunk. + // If the handler returns ChunkFile_NotHandled, then the chunk is + // passed to the regular handlers. + // + // If you pass NULL in here, then it disables the default chunk handler. + void SetDefaultChunkHandler( DefaultChunkHandler_t pHandler, void *pData ); + + void PushHandlers(CChunkHandlerMap *pHandlerMap); + void PopHandlers(void); + + protected: + + void BuildIndentString(char *pszDest, int nDepth); + + TokenReader m_TokenReader; + + FILE *m_hFile; + char m_szErrorToken[80]; + char m_szIndent[MAX_INDENT_DEPTH]; + int m_nCurrentDepth; + + // See SetDefaultChunkHandler.. + DefaultChunkHandler_t m_DefaultChunkHandler; + void *m_pDefaultChunkHandlerData; + + CChunkHandlerMap *m_HandlerStack[MAX_INDENT_DEPTH]; + int m_nHandlerStackDepth; +}; + + +#endif // CHUNKFILE_H diff --git a/public/client_class.cpp b/public/client_class.cpp new file mode 100644 index 0000000..bbb5bc0 --- /dev/null +++ b/public/client_class.cpp @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "client_class.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ClientClass *g_pClientClassHead=0; + + diff --git a/public/client_class.h b/public/client_class.h new file mode 100644 index 0000000..77827d8 --- /dev/null +++ b/public/client_class.h @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENT_CLASS_H ) +#define CLIENT_CLASS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "dt_recv.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class Vector; +class CMouthInfo; + + +//----------------------------------------------------------------------------- +// represents a handle used only by the client DLL +//----------------------------------------------------------------------------- + +#include "iclientrenderable.h" +#include "iclientnetworkable.h" + + +class ClientClass; +// Linked list of all known client classes +extern ClientClass *g_pClientClassHead; + +// The serial number that gets passed in is used for ehandles. +typedef IClientNetworkable* (*CreateClientClassFn)( int entnum, int serialNum ); +typedef IClientNetworkable* (*CreateEventFn)(); + +//----------------------------------------------------------------------------- +// Purpose: Client side class definition +//----------------------------------------------------------------------------- +class ClientClass +{ +public: + ClientClass( const char *pNetworkName, CreateClientClassFn createFn, CreateEventFn createEventFn, RecvTable *pRecvTable ) + { + m_pNetworkName = pNetworkName; + m_pCreateFn = createFn; + m_pCreateEventFn= createEventFn; + m_pRecvTable = pRecvTable; + + // Link it in + m_pNext = g_pClientClassHead; + g_pClientClassHead = this; + } + + const char* GetName() + { + return m_pNetworkName; + } + +public: + CreateClientClassFn m_pCreateFn; + CreateEventFn m_pCreateEventFn; // Only called for event objects. + const char *m_pNetworkName; + RecvTable *m_pRecvTable; + ClientClass *m_pNext; + int m_ClassID; // Managed by the engine. +}; + +#define DECLARE_CLIENTCLASS() \ + virtual int YouForgotToImplementOrDeclareClientClass();\ + virtual ClientClass* GetClientClass();\ + static RecvTable *m_pClassRecvTable; \ + DECLARE_CLIENTCLASS_NOBASE() + + +// This can be used to give all datatables access to protected and private members of the class. +#define ALLOW_DATATABLES_PRIVATE_ACCESS() \ + template friend int ClientClassInit(T *); + + +#define DECLARE_CLIENTCLASS_NOBASE ALLOW_DATATABLES_PRIVATE_ACCESS + +// This macro adds a ClientClass to the linked list in g_pClientClassHead (so +// the list can be given to the engine). +// Use this macro to expose your client class to the engine. +// networkName must match the network name of a class registered on the server. +#define IMPLEMENT_CLIENTCLASS(clientClassName, dataTable, serverClassName) \ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName) \ + static IClientNetworkable* _##clientClassName##_CreateObject( int entnum, int serialNum ) \ + { \ + clientClassName *pRet = new clientClassName; \ + if ( !pRet ) \ + return 0; \ + pRet->Init( entnum, serialNum ); \ + return pRet; \ + } \ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + _##clientClassName##_CreateObject, \ + NULL,\ + &dataTable::g_RecvTable); + +// Implement a client class and provide a factory so you can allocate and delete it yourself +// (or make it a singleton). +#define IMPLEMENT_CLIENTCLASS_FACTORY(clientClassName, dataTable, serverClassName, factory) \ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName) \ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + factory, \ + NULL,\ + &dataTable::g_RecvTable); + +// The IMPLEMENT_CLIENTCLASS_DT macros do IMPLEMENT_CLIENT_CLASS and also do BEGIN_RECV_TABLE. +#define IMPLEMENT_CLIENTCLASS_DT(clientClassName, dataTable, serverClassName)\ + IMPLEMENT_CLIENTCLASS(clientClassName, dataTable, serverClassName)\ + BEGIN_RECV_TABLE(clientClassName, dataTable) + +#define IMPLEMENT_CLIENTCLASS_DT_NOBASE(clientClassName, dataTable, serverClassName)\ + IMPLEMENT_CLIENTCLASS(clientClassName, dataTable, serverClassName)\ + BEGIN_RECV_TABLE_NOBASE(clientClassName, dataTable) + + +// Using IMPLEMENT_CLIENTCLASS_EVENT means the engine thinks the entity is an event so the entity +// is responsible for freeing itself. +#define IMPLEMENT_CLIENTCLASS_EVENT(clientClassName, dataTable, serverClassName)\ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName)\ + static clientClassName __g_##clientClassName; \ + static IClientNetworkable* _##clientClassName##_CreateObject() {return &__g_##clientClassName;}\ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + NULL,\ + _##clientClassName##_CreateObject, \ + &dataTable::g_RecvTable); + +#define IMPLEMENT_CLIENTCLASS_EVENT_DT(clientClassName, dataTable, serverClassName)\ + namespace dataTable {extern RecvTable g_RecvTable;}\ + IMPLEMENT_CLIENTCLASS_EVENT(clientClassName, dataTable, serverClassName)\ + BEGIN_RECV_TABLE(clientClassName, dataTable) + + +// Register a client event singleton but specify a pointer to give to the engine rather than +// have a global instance. This is useful if you're using Initializers and your object's constructor +// uses some other global object (so you must use Initializers so you're constructed afterwards). +#define IMPLEMENT_CLIENTCLASS_EVENT_POINTER(clientClassName, dataTable, serverClassName, ptr)\ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName)\ + static IClientNetworkable* _##clientClassName##_CreateObject() {return ptr;}\ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + NULL,\ + _##clientClassName##_CreateObject, \ + &dataTable::g_RecvTable); + +#define IMPLEMENT_CLIENTCLASS_EVENT_NONSINGLETON(clientClassName, dataTable, serverClassName)\ + static IClientNetworkable* _##clientClassName##_CreateObject() \ + { \ + clientClassName *p = new clientClassName; \ + if ( p ) \ + p->Init( -1, 0 ); \ + return p; \ + } \ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + NULL,\ + _##clientClassName##_CreateObject, \ + &dataTable::g_RecvTable); + + +// Used internally.. +#define INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName) \ + namespace dataTable {extern RecvTable g_RecvTable;}\ + extern ClientClass __g_##clientClassName##ClientClass;\ + RecvTable* clientClassName::m_pClassRecvTable = &dataTable::g_RecvTable;\ + int clientClassName::YouForgotToImplementOrDeclareClientClass() {return 0;}\ + ClientClass* clientClassName::GetClientClass() {return &__g_##clientClassName##ClientClass;} + +#endif // CLIENT_CLASS_H diff --git a/public/client_render_handle.h b/public/client_render_handle.h new file mode 100644 index 0000000..8162540 --- /dev/null +++ b/public/client_render_handle.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CLIENT_RENDER_HANDLE_H +#define CLIENT_RENDER_HANDLE_H +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Foward declarations +//----------------------------------------------------------------------------- +class IClientRenderable; + + +//----------------------------------------------------------------------------- +// Handle to an renderable in the client leaf system +//----------------------------------------------------------------------------- +typedef unsigned short ClientRenderHandle_t; + +enum +{ + INVALID_CLIENT_RENDER_HANDLE = (ClientRenderHandle_t)0xffff, +}; + + +#endif // CLIENT_RENDER_HANDLE_H diff --git a/public/client_textmessage.h b/public/client_textmessage.h new file mode 100644 index 0000000..a48490b --- /dev/null +++ b/public/client_textmessage.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CLIENT_TEXTMESSAGE_H +#define CLIENT_TEXTMESSAGE_H +#ifdef _WIN32 +#pragma once +#endif + +struct client_textmessage_t +{ + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + const char *pVGuiSchemeFontName; // If null, use default font for messages + const char *pName; + const char *pMessage; + bool bRoundedRectBackdropBox; + float flBoxSize; // as a function of font height + byte boxcolor[4]; + char const *pClearMessage; // message to clear +}; + +#endif // CLIENT_TEXTMESSAGE_H diff --git a/public/clientstats.h b/public/clientstats.h new file mode 100644 index 0000000..c334069 --- /dev/null +++ b/public/clientstats.h @@ -0,0 +1,198 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined( CLIENTSTATS_H ) +#define CLIENTSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include +#include "tier0/dbg.h" + +#define INTERFACEVERSION_CLIENTSTATS "ClientStats004" + +//----------------------------------------------------------------------------- +// An interface used to help the client stats implementation tell time +//----------------------------------------------------------------------------- + +struct IClientStatsTime +{ + virtual float GetTime() = 0; +}; + +//----------------------------------------------------------------------------- +// Allows clients to draw their own stats text, will be passed by the +// engine into DisplayStats of the IClientStats interface. +//----------------------------------------------------------------------------- + +struct IClientStatsTextDisplay +{ + // Draws the stats + virtual void DrawStatsText( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + virtual void SetDrawColor( unsigned char r, unsigned char g, unsigned char b ) = 0; + + // Sets a color based on a value and its max acceptable limit + virtual void SetDrawColorFromStatValues( float limit, float value ) = 0; +}; + + +//----------------------------------------------------------------------------- +// This will exist as a singleton within the client DLL and will be hooked into +// the engine to allow clients to render their own stats. +//----------------------------------------------------------------------------- + +abstract_class IClientStats +{ +public: + // This is called at startup to tell the stats about time + virtual void Init( IClientStatsTime* pTime ) = 0; + + // These methods are called at the beginning and the end of each run + virtual void BeginRun() = 0; + virtual void EndRun() = 0; + + // These methods are called at the beginning and the end of each frame + virtual void BeginFrame() = 0; + virtual void EndFrame() = 0; + + // --------------------------------------------------------------- + // All this stuff is used to prop stats for gathering r_speeds data during timedemo. + // --------------------------------------------------------------- + virtual int GetNumTimesStats( void ) const = 0; + + // returns timed stats + virtual double TimedStatInFrame( int statID ) const = 0; + virtual double TotalTimedStat( int statID ) const = 0; +}; + + +//----------------------------------------------------------------------------- +// This is a templatized implementation which can be instantiated anywhere +// Note that you still have to install it and display it though. +//----------------------------------------------------------------------------- + +template +abstract_class CBaseClientStats : public IClientStats +{ +public: + void Init( IClientStatsTime* pTime ); + void BeginRun(); + void EndRun(); + void BeginFrame(); + void EndFrame(); + + // Timed stat gathering + void BeginTimedStat( int stat ); + void EndTimedStat( int stat ); + + // --------------------------------------------------------------- + // All this stuff is used to prop stats for gathering r_speeds data during timedemo. + // --------------------------------------------------------------- + // returns timed stats + double TimedStatInFrame( int statID ) const + { + Assert( statID >= 0 && statID < timedStatCount ); + Assert( m_StatFrameTime[statID] >= 0.0 ); + return m_StatFrameTime[statID]; + } + + double TotalTimedStat( int statID ) const + { + Assert( statID >= 0 && statID < timedStatCount ); + return m_TotalStatTime[statID]; + } + virtual const char *GetCountedStatName( int statID ) const = 0; + virtual const char *GetTimedStatName( int statID ) const = 0; + +protected: + + // Timed statistics + double m_StatFrameTime[timedStatCount]; + double m_StatStartTime[timedStatCount]; + double m_TotalStatTime[timedStatCount]; + +private: + IClientStatsTime* m_pTime; +}; + + +//----------------------------------------------------------------------------- +// Initializes client stats +//----------------------------------------------------------------------------- + +template +void CBaseClientStats::Init( IClientStatsTime* pTime ) +{ + Assert( pTime ); + m_pTime = pTime; +} + +//----------------------------------------------------------------------------- +// These methods are called at the beginning and the end of each run +//----------------------------------------------------------------------------- + +template +void CBaseClientStats::BeginRun() +{ + int i; + + for (i = 0; i < timedStatCount; ++i) + m_TotalStatTime[i] = 0.0; + +} + +template +void CBaseClientStats::EndRun() +{ +} + + +//----------------------------------------------------------------------------- +// These methods are called at the beginning and the end of each frame +//----------------------------------------------------------------------------- + +template +void CBaseClientStats::BeginFrame() +{ + int i; + for (i = 0; i < timedStatCount; ++i) + m_StatFrameTime[i] = 0.0; +} + +template +void CBaseClientStats::EndFrame() +{ + int i; + for (i = 0; i < timedStatCount; ++i) + m_TotalStatTime[i] += m_StatFrameTime[i]; +} + + +//----------------------------------------------------------------------------- +// Inlined stat gathering methods +//----------------------------------------------------------------------------- + +template +void CBaseClientStats::BeginTimedStat( int stat ) +{ + if (m_pTime) + m_StatStartTime[stat] = m_pTime->GetTime(); +} + +template +void CBaseClientStats::EndTimedStat( int stat ) +{ + if (m_pTime) + m_StatFrameTime[stat] += m_pTime->GetTime() - m_StatStartTime[stat]; +} + + +#endif // CLIENTSTATS_H diff --git a/public/cmodel.h b/public/cmodel.h new file mode 100644 index 0000000..3e13cb5 --- /dev/null +++ b/public/cmodel.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef CMODEL_H +#define CMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "trace.h" +#include "tier0/dbg.h" +#include "basehandle.h" + +struct edict_t; +struct model_t; + +/* +============================================================== + +COLLISION DETECTION + +============================================================== +*/ + +#include "bspflags.h" +//#include "mathlib/vector.h" + +// gi.BoxEdicts() can return a list of either solid or trigger entities +// FIXME: eliminate AREA_ distinction? +#define AREA_SOLID 1 +#define AREA_TRIGGERS 2 + +#include "vcollide.h" + +struct cmodel_t +{ + Vector mins, maxs; + Vector origin; // for sounds or lights + int headnode; + + vcollide_t vcollisionData; +}; + +struct csurface_t +{ + const char *name; + short surfaceProps; + unsigned short flags; // BUGBUG: These are declared per surface, not per material, but this database is per-material now +}; + +//----------------------------------------------------------------------------- +// A ray... +//----------------------------------------------------------------------------- + +struct Ray_t +{ + VectorAligned m_Start; // starting point, centered within the extents + VectorAligned m_Delta; // direction + length of the ray + VectorAligned m_StartOffset; // Add this to m_Start to get the actual ray start + VectorAligned m_Extents; // Describes an axis aligned box extruded along a ray + bool m_IsRay; // are the extents zero? + bool m_IsSwept; // is delta != 0? + + void Init( Vector const& start, Vector const& end ) + { + Assert( &end ); + VectorSubtract( end, start, m_Delta ); + + m_IsSwept = (m_Delta.LengthSqr() != 0); + + VectorClear( m_Extents ); + m_IsRay = true; + + // Offset m_Start to be in the center of the box... + VectorClear( m_StartOffset ); + VectorCopy( start, m_Start ); + } + + void Init( Vector const& start, Vector const& end, Vector const& mins, Vector const& maxs ) + { + Assert( &end ); + VectorSubtract( end, start, m_Delta ); + + m_IsSwept = (m_Delta.LengthSqr() != 0); + + VectorSubtract( maxs, mins, m_Extents ); + m_Extents *= 0.5f; + m_IsRay = (m_Extents.LengthSqr() < 1e-6); + + // Offset m_Start to be in the center of the box... + VectorAdd( mins, maxs, m_StartOffset ); + m_StartOffset *= 0.5f; + VectorAdd( start, m_StartOffset, m_Start ); + m_StartOffset *= -1.0f; + } + + // compute inverse delta + Vector InvDelta() const + { + Vector vecInvDelta; + for ( int iAxis = 0; iAxis < 3; ++iAxis ) + { + if ( m_Delta[iAxis] != 0.0f ) + { + vecInvDelta[iAxis] = 1.0f / m_Delta[iAxis]; + } + else + { + vecInvDelta[iAxis] = FLT_MAX; + } + } + return vecInvDelta; + } + +private: +}; + + +#endif // CMODEL_H + + +#include "gametrace.h" + diff --git a/public/collisionutils.cpp b/public/collisionutils.cpp new file mode 100644 index 0000000..2549a56 --- /dev/null +++ b/public/collisionutils.cpp @@ -0,0 +1,3262 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Common collision utility methods +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#include "collisionutils.h" +#include "cmodel.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "tier0/dbg.h" +#include +#include "mathlib/vector4d.h" +#include "trace.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define UNINIT -99999.0 + +//----------------------------------------------------------------------------- +// Clears the trace +//----------------------------------------------------------------------------- +static void Collision_ClearTrace( const Vector &vecRayStart, const Vector &vecRayDelta, CBaseTrace *pTrace ) +{ + pTrace->startpos = vecRayStart; + pTrace->endpos = vecRayStart; + pTrace->endpos += vecRayDelta; + pTrace->startsolid = false; + pTrace->allsolid = false; + pTrace->fraction = 1.0f; + pTrace->contents = 0; +} + + +//----------------------------------------------------------------------------- +// Compute the offset in t along the ray that we'll use for the collision +//----------------------------------------------------------------------------- +static float ComputeBoxOffset( const Ray_t& ray ) +{ + if (ray.m_IsRay) + return 1e-3f; + + // Find the projection of the box diagonal along the ray... + float offset = FloatMakePositive(ray.m_Extents[0] * ray.m_Delta[0]) + + FloatMakePositive(ray.m_Extents[1] * ray.m_Delta[1]) + + FloatMakePositive(ray.m_Extents[2] * ray.m_Delta[2]); + + // We need to divide twice: Once to normalize the computation above + // so we get something in units of extents, and the second to normalize + // that with respect to the entire raycast. + offset *= InvRSquared( ray.m_Delta ); + + // 1e-3 is an epsilon + return offset + 1e-3; +} + + +//----------------------------------------------------------------------------- +// Intersects a swept box against a triangle +//----------------------------------------------------------------------------- +float IntersectRayWithTriangle( const Ray_t& ray, + const Vector& v1, const Vector& v2, const Vector& v3, bool oneSided ) +{ + // This is cute: Use barycentric coordinates to represent the triangle + // Vo(1-u-v) + V1u + V2v and intersect that with a line Po + Dt + // This gives us 3 equations + 3 unknowns, which we can solve with + // Cramer's rule... + // E1x u + E2x v - Dx t = Pox - Vox + // There's a couple of other optimizations, Cramer's rule involves + // computing the determinant of a matrix which has been constructed + // by three vectors. It turns out that + // det | A B C | = -( A x C ) dot B or -(C x B) dot A + // which we'll use below.. + + Vector edge1, edge2, org; + VectorSubtract( v2, v1, edge1 ); + VectorSubtract( v3, v1, edge2 ); + + // Cull out one-sided stuff + if (oneSided) + { + Vector normal; + CrossProduct( edge1, edge2, normal ); + if (DotProduct( normal, ray.m_Delta ) >= 0.0f) + return -1.0f; + } + + // FIXME: This is inaccurate, but fast for boxes + // We want to do a fast separating axis implementation here + // with a swept triangle along the reverse direction of the ray. + + // Compute some intermediary terms + Vector dirCrossEdge2, orgCrossEdge1; + CrossProduct( ray.m_Delta, edge2, dirCrossEdge2 ); + + // Compute the denominator of Cramer's rule: + // | -Dx E1x E2x | + // det | -Dy E1y E2y | = (D x E2) dot E1 + // | -Dz E1z E2z | + float denom = DotProduct( dirCrossEdge2, edge1 ); + if( FloatMakePositive( denom ) < 1e-6 ) + return -1.0f; + denom = 1.0f / denom; + + // Compute u. It's gotta lie in the range of 0 to 1. + // | -Dx orgx E2x | + // u = denom * det | -Dy orgy E2y | = (D x E2) dot org + // | -Dz orgz E2z | + VectorSubtract( ray.m_Start, v1, org ); + float u = DotProduct( dirCrossEdge2, org ) * denom; + if ((u < 0.0f) || (u > 1.0f)) + return -1.0f; + + // Compute t and v the same way... + // In barycentric coords, u + v < 1 + CrossProduct( org, edge1, orgCrossEdge1 ); + float v = DotProduct( orgCrossEdge1, ray.m_Delta ) * denom; + if ((v < 0.0f) || (v + u > 1.0f)) + return -1.0f; + + // Compute the distance along the ray direction that we need to fudge + // when using swept boxes + float boxt = ComputeBoxOffset( ray ); + float t = DotProduct( orgCrossEdge1, edge2 ) * denom; + if ((t < -boxt) || (t > 1.0f + boxt)) + return -1.0f; + + return clamp( t, 0.f, 1.f ); +} + +//----------------------------------------------------------------------------- +// computes the barycentric coordinates of an intersection +//----------------------------------------------------------------------------- + +bool ComputeIntersectionBarycentricCoordinates( const Ray_t& ray, + const Vector& v1, const Vector& v2, const Vector& v3, float& u, float& v, + float *t ) +{ + Vector edge1, edge2, org; + VectorSubtract( v2, v1, edge1 ); + VectorSubtract( v3, v1, edge2 ); + + // Compute some intermediary terms + Vector dirCrossEdge2, orgCrossEdge1; + CrossProduct( ray.m_Delta, edge2, dirCrossEdge2 ); + + // Compute the denominator of Cramer's rule: + // | -Dx E1x E2x | + // det | -Dy E1y E2y | = (D x E2) dot E1 + // | -Dz E1z E2z | + float denom = DotProduct( dirCrossEdge2, edge1 ); + if( FloatMakePositive( denom ) < 1e-6 ) + return false; + denom = 1.0f / denom; + + // Compute u. It's gotta lie in the range of 0 to 1. + // | -Dx orgx E2x | + // u = denom * det | -Dy orgy E2y | = (D x E2) dot org + // | -Dz orgz E2z | + VectorSubtract( ray.m_Start, v1, org ); + u = DotProduct( dirCrossEdge2, org ) * denom; + + // Compute t and v the same way... + // In barycentric coords, u + v < 1 + CrossProduct( org, edge1, orgCrossEdge1 ); + v = DotProduct( orgCrossEdge1, ray.m_Delta ) * denom; + + // Compute the distance along the ray direction that we need to fudge + // when using swept boxes + if( t ) + { + float boxt = ComputeBoxOffset( ray ); + *t = DotProduct( orgCrossEdge1, edge2 ) * denom; + if( ( *t < -boxt ) || ( *t > 1.0f + boxt ) ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Intersects a plane with a triangle (requires barycentric definition) +//----------------------------------------------------------------------------- + +int IntersectTriangleWithPlaneBarycentric( const Vector& org, const Vector& edgeU, + const Vector& edgeV, const Vector4D& plane, Vector2D* pIntersection ) +{ + // This uses a barycentric method, since we need that to determine + // interpolated points, alphas, and normals + // Given the plane equation P dot N + d = 0 + // and the barycentric coodinate equation P = Org + EdgeU * u + EdgeV * v + // Plug em in. Intersection occurs at u = 0 or v = 0 or u + v = 1 + + float orgDotNormal = DotProduct( org, plane.AsVector3D() ); + float edgeUDotNormal = DotProduct( edgeU, plane.AsVector3D() ); + float edgeVDotNormal = DotProduct( edgeV, plane.AsVector3D() ); + + int ptIdx = 0; + + // u = 0 + if ( edgeVDotNormal != 0.0f ) + { + pIntersection[ptIdx].x = 0.0f; + pIntersection[ptIdx].y = - ( orgDotNormal - plane.w ) / edgeVDotNormal; + if ((pIntersection[ptIdx].y >= 0.0f) && (pIntersection[ptIdx].y <= 1.0f)) + ++ptIdx; + } + + // v = 0 + if ( edgeUDotNormal != 0.0f ) + { + pIntersection[ptIdx].x = - ( orgDotNormal - plane.w ) / edgeUDotNormal; + pIntersection[ptIdx].y = 0.0f; + if ((pIntersection[ptIdx].x >= 0.0f) && (pIntersection[ptIdx].x <= 1.0f)) + ++ptIdx; + } + + // u + v = 1 + if (ptIdx == 2) + return ptIdx; + + if ( edgeVDotNormal != edgeUDotNormal ) + { + pIntersection[ptIdx].x = - ( orgDotNormal - plane.w + edgeVDotNormal) / + ( edgeUDotNormal - edgeVDotNormal); + pIntersection[ptIdx].y = 1.0f - pIntersection[ptIdx].x; + if ((pIntersection[ptIdx].x >= 0.0f) && (pIntersection[ptIdx].x <= 1.0f) && + (pIntersection[ptIdx].y >= 0.0f) && (pIntersection[ptIdx].y <= 1.0f)) + ++ptIdx; + } + + Assert( ptIdx < 3 ); + return ptIdx; +} + + +//----------------------------------------------------------------------------- +// Returns true if a box intersects with a sphere +//----------------------------------------------------------------------------- +bool IsSphereIntersectingSphere( const Vector& center1, float radius1, + const Vector& center2, float radius2 ) +{ + Vector delta; + VectorSubtract( center2, center1, delta ); + float distSq = delta.LengthSqr(); + float radiusSum = radius1 + radius2; + return (distSq <= (radiusSum * radiusSum)); +} + + +//----------------------------------------------------------------------------- +// Returns true if a box intersects with a sphere +//----------------------------------------------------------------------------- +bool IsBoxIntersectingSphere( const Vector& boxMin, const Vector& boxMax, + const Vector& center, float radius ) +{ + // See Graphics Gems, box-sphere intersection + float dmin = 0.0f; + float flDelta; + + // Unrolled the loop.. this is a big cycle stealer... + if (center[0] < boxMin[0]) + { + flDelta = center[0] - boxMin[0]; + dmin += flDelta * flDelta; + } + else if (center[0] > boxMax[0]) + { + flDelta = boxMax[0] - center[0]; + dmin += flDelta * flDelta; + } + + if (center[1] < boxMin[1]) + { + flDelta = center[1] - boxMin[1]; + dmin += flDelta * flDelta; + } + else if (center[1] > boxMax[1]) + { + flDelta = boxMax[1] - center[1]; + dmin += flDelta * flDelta; + } + + if (center[2] < boxMin[2]) + { + flDelta = center[2] - boxMin[2]; + dmin += flDelta * flDelta; + } + else if (center[2] > boxMax[2]) + { + flDelta = boxMax[2] - center[2]; + dmin += flDelta * flDelta; + } + + return dmin < radius * radius; +} + +bool IsBoxIntersectingSphereExtents( const Vector& boxCenter, const Vector& boxHalfDiag, + const Vector& center, float radius ) +{ + // See Graphics Gems, box-sphere intersection + float dmin = 0.0f; + float flDelta, flDiff; + + // Unrolled the loop.. this is a big cycle stealer... + flDiff = FloatMakePositive( center.x - boxCenter.x ); + if (flDiff > boxHalfDiag.x) + { + flDelta = flDiff - boxHalfDiag.x; + dmin += flDelta * flDelta; + } + + flDiff = FloatMakePositive( center.y - boxCenter.y ); + if (flDiff > boxHalfDiag.y) + { + flDelta = flDiff - boxHalfDiag.y; + dmin += flDelta * flDelta; + } + + flDiff = FloatMakePositive( center.z - boxCenter.z ); + if (flDiff > boxHalfDiag.z) + { + flDelta = flDiff - boxHalfDiag.z; + dmin += flDelta * flDelta; + } + + return dmin < radius * radius; +} + + +//----------------------------------------------------------------------------- +// Returns true if a rectangle intersects with a circle +//----------------------------------------------------------------------------- +bool IsCircleIntersectingRectangle( const Vector2D& boxMin, const Vector2D& boxMax, + const Vector2D& center, float radius ) +{ + // See Graphics Gems, box-sphere intersection + float dmin = 0.0f; + float flDelta; + + if (center[0] < boxMin[0]) + { + flDelta = center[0] - boxMin[0]; + dmin += flDelta * flDelta; + } + else if (center[0] > boxMax[0]) + { + flDelta = boxMax[0] - center[0]; + dmin += flDelta * flDelta; + } + + if (center[1] < boxMin[1]) + { + flDelta = center[1] - boxMin[1]; + dmin += flDelta * flDelta; + } + else if (center[1] > boxMax[1]) + { + flDelta = boxMax[1] - center[1]; + dmin += flDelta * flDelta; + } + + return dmin < radius * radius; +} + + +//----------------------------------------------------------------------------- +// returns true if there's an intersection between ray and sphere +//----------------------------------------------------------------------------- +bool IsRayIntersectingSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector& vecCenter, float flRadius, float flTolerance ) +{ + // For this algorithm, find a point on the ray which is closest to the sphere origin + // Do this by making a plane passing through the sphere origin + // whose normal is parallel to the ray. Intersect that plane with the ray. + // Plane: N dot P = I, N = D (ray direction), I = C dot N = C dot D + // Ray: P = O + D * t + // D dot ( O + D * t ) = C dot D + // D dot O + D dot D * t = C dot D + // t = (C - O) dot D / D dot D + // Clamp t to (0,1) + // Find distance of the point on the ray to the sphere center. + Assert( flTolerance >= 0.0f ); + flRadius += flTolerance; + + Vector vecRayToSphere; + VectorSubtract( vecCenter, vecRayOrigin, vecRayToSphere ); + float flNumerator = DotProduct( vecRayToSphere, vecRayDelta ); + + float t; + if (flNumerator <= 0.0f) + { + t = 0.0f; + } + else + { + float flDenominator = DotProduct( vecRayDelta, vecRayDelta ); + if ( flNumerator > flDenominator ) + t = 1.0f; + else + t = flNumerator / flDenominator; + } + + Vector vecClosestPoint; + VectorMA( vecRayOrigin, t, vecRayDelta, vecClosestPoint ); + return ( vecClosestPoint.DistToSqr( vecCenter ) <= flRadius * flRadius ); + + // NOTE: This in an alternate algorithm which I didn't use because I'd have to use a sqrt + // So it's probably faster to do this other algorithm. I'll leave the comments here + // for how to go back if we want to + + // Solve using the ray equation + the sphere equation + // P = o + dt + // (x - xc)^2 + (y - yc)^2 + (z - zc)^2 = r^2 + // (ox + dx * t - xc)^2 + (oy + dy * t - yc)^2 + (oz + dz * t - zc)^2 = r^2 + // (ox - xc)^2 + 2 * (ox-xc) * dx * t + dx^2 * t^2 + + // (oy - yc)^2 + 2 * (oy-yc) * dy * t + dy^2 * t^2 + + // (oz - zc)^2 + 2 * (oz-zc) * dz * t + dz^2 * t^2 = r^2 + // (dx^2 + dy^2 + dz^2) * t^2 + 2 * ((ox-xc)dx + (oy-yc)dy + (oz-zc)dz) t + + // (ox-xc)^2 + (oy-yc)^2 + (oz-zc)^2 - r^2 = 0 + // or, t = (-b +/- sqrt( b^2 - 4ac)) / 2a + // a = DotProduct( vecRayDelta, vecRayDelta ); + // b = 2 * DotProduct( vecRayOrigin - vecCenter, vecRayDelta ) + // c = DotProduct(vecRayOrigin - vecCenter, vecRayOrigin - vecCenter) - flRadius * flRadius; + // Valid solutions are possible only if b^2 - 4ac >= 0 + // Therefore, compute that value + see if we got it +} + + +//----------------------------------------------------------------------------- +// +// IntersectInfiniteRayWithSphere +// +// Returns whether or not there was an intersection. +// Returns the two intersection points +// +//----------------------------------------------------------------------------- +bool IntersectInfiniteRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 ) +{ + // Solve using the ray equation + the sphere equation + // P = o + dt + // (x - xc)^2 + (y - yc)^2 + (z - zc)^2 = r^2 + // (ox + dx * t - xc)^2 + (oy + dy * t - yc)^2 + (oz + dz * t - zc)^2 = r^2 + // (ox - xc)^2 + 2 * (ox-xc) * dx * t + dx^2 * t^2 + + // (oy - yc)^2 + 2 * (oy-yc) * dy * t + dy^2 * t^2 + + // (oz - zc)^2 + 2 * (oz-zc) * dz * t + dz^2 * t^2 = r^2 + // (dx^2 + dy^2 + dz^2) * t^2 + 2 * ((ox-xc)dx + (oy-yc)dy + (oz-zc)dz) t + + // (ox-xc)^2 + (oy-yc)^2 + (oz-zc)^2 - r^2 = 0 + // or, t = (-b +/- sqrt( b^2 - 4ac)) / 2a + // a = DotProduct( vecRayDelta, vecRayDelta ); + // b = 2 * DotProduct( vecRayOrigin - vecCenter, vecRayDelta ) + // c = DotProduct(vecRayOrigin - vecCenter, vecRayOrigin - vecCenter) - flRadius * flRadius; + + Vector vecSphereToRay; + VectorSubtract( vecRayOrigin, vecSphereCenter, vecSphereToRay ); + + float a = DotProduct( vecRayDelta, vecRayDelta ); + + // This would occur in the case of a zero-length ray + if ( a == 0.0f ) + { + *pT1 = *pT2 = 0.0f; + return vecSphereToRay.LengthSqr() <= flRadius * flRadius; + } + + float b = 2 * DotProduct( vecSphereToRay, vecRayDelta ); + float c = DotProduct( vecSphereToRay, vecSphereToRay ) - flRadius * flRadius; + float flDiscrim = b * b - 4 * a * c; + if ( flDiscrim < 0.0f ) + return false; + + flDiscrim = sqrt( flDiscrim ); + float oo2a = 0.5f / a; + *pT1 = ( - b - flDiscrim ) * oo2a; + *pT2 = ( - b + flDiscrim ) * oo2a; + return true; +} + + + +//----------------------------------------------------------------------------- +// +// IntersectRayWithSphere +// +// Returns whether or not there was an intersection. +// Returns the two intersection points, clamped to (0,1) +// +//----------------------------------------------------------------------------- +bool IntersectRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 ) +{ + if ( !IntersectInfiniteRayWithSphere( vecRayOrigin, vecRayDelta, vecSphereCenter, flRadius, pT1, pT2 ) ) + return false; + + if (( *pT1 > 1.0f ) || ( *pT2 < 0.0f )) + return false; + + // Clamp it! + if ( *pT1 < 0.0f ) + *pT1 = 0.0f; + if ( *pT2 > 1.0f ) + *pT2 = 1.0f; + + return true; +} + + +// returns true if the sphere and cone intersect +// NOTE: cone sine/cosine are the half angle of the cone +bool IsSphereIntersectingCone( const Vector &sphereCenter, float sphereRadius, const Vector &coneOrigin, const Vector &coneNormal, float coneSine, float coneCosine ) +{ + Vector backCenter = coneOrigin - (sphereRadius / coneSine) * coneNormal; + Vector delta = sphereCenter - backCenter; + float deltaLen = delta.Length(); + if ( DotProduct(coneNormal, delta) >= deltaLen*coneCosine ) + { + delta = sphereCenter - coneOrigin; + deltaLen = delta.Length(); + if ( -DotProduct(coneNormal, delta) >= deltaLen * coneSine ) + { + return ( deltaLen <= sphereRadius ) ? true : false; + } + return true; + } + return false; +} + + + +//----------------------------------------------------------------------------- +// returns true if the point is in the box +//----------------------------------------------------------------------------- +bool IsPointInBox( const Vector& pt, const Vector& boxMin, const Vector& boxMax ) +{ + Assert( boxMin[0] <= boxMax[0] ); + Assert( boxMin[1] <= boxMax[1] ); + Assert( boxMin[2] <= boxMax[2] ); + + // on x360, force use of SIMD version. + if (IsX360()) + { + return IsPointInBox( LoadUnaligned3SIMD(pt.Base()), LoadUnaligned3SIMD(boxMin.Base()), LoadUnaligned3SIMD(boxMax.Base()) ) ; + } + + if ( (pt[0] > boxMax[0]) || (pt[0] < boxMin[0]) ) + return false; + if ( (pt[1] > boxMax[1]) || (pt[1] < boxMin[1]) ) + return false; + if ( (pt[2] > boxMax[2]) || (pt[2] < boxMin[2]) ) + return false; + return true; +} + + +bool IsPointInCone( const Vector &pt, const Vector &origin, const Vector &axis, float cosAngle, float length ) +{ + Vector delta = pt - origin; + float dist = VectorNormalize( delta ); + float dot = DotProduct( delta, axis ); + if ( dot < cosAngle ) + return false; + if ( dist * dot > length ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// returns true if there's an intersection between two boxes +//----------------------------------------------------------------------------- +bool IsBoxIntersectingBox( const Vector& boxMin1, const Vector& boxMax1, + const Vector& boxMin2, const Vector& boxMax2 ) +{ + Assert( boxMin1[0] <= boxMax1[0] ); + Assert( boxMin1[1] <= boxMax1[1] ); + Assert( boxMin1[2] <= boxMax1[2] ); + Assert( boxMin2[0] <= boxMax2[0] ); + Assert( boxMin2[1] <= boxMax2[1] ); + Assert( boxMin2[2] <= boxMax2[2] ); + + if ( (boxMin1[0] > boxMax2[0]) || (boxMax1[0] < boxMin2[0]) ) + return false; + if ( (boxMin1[1] > boxMax2[1]) || (boxMax1[1] < boxMin2[1]) ) + return false; + if ( (boxMin1[2] > boxMax2[2]) || (boxMax1[2] < boxMin2[2]) ) + return false; + return true; +} + +bool IsBoxIntersectingBoxExtents( const Vector& boxCenter1, const Vector& boxHalfDiagonal1, + const Vector& boxCenter2, const Vector& boxHalfDiagonal2 ) +{ + Vector vecDelta, vecSize; + VectorSubtract( boxCenter1, boxCenter2, vecDelta ); + VectorAdd( boxHalfDiagonal1, boxHalfDiagonal2, vecSize ); + return ( FloatMakePositive( vecDelta.x ) <= vecSize.x ) && + ( FloatMakePositive( vecDelta.y ) <= vecSize.y ) && + ( FloatMakePositive( vecDelta.z ) <= vecSize.z ); +} + + +//----------------------------------------------------------------------------- +// +// IsOBBIntersectingOBB +// +// returns true if there's an intersection between two OBBs +// +//----------------------------------------------------------------------------- +bool IsOBBIntersectingOBB( const Vector &vecOrigin1, const QAngle &vecAngles1, const Vector& boxMin1, const Vector& boxMax1, + const Vector &vecOrigin2, const QAngle &vecAngles2, const Vector& boxMin2, const Vector& boxMax2, float flTolerance ) +{ + // FIXME: Simple case AABB check doesn't work because the min and max extents are not oriented based on the angle + // this fast check would only be good for cubes. + /*if ( vecAngles1 == vecAngles2 ) + { + const Vector &vecDelta = vecOrigin2 - vecOrigin1; + Vector vecOtherMins, vecOtherMaxs; + VectorAdd( boxMin2, vecDelta, vecOtherMins ); + VectorAdd( boxMax2, vecDelta, vecOtherMaxs ); + return IsBoxIntersectingBox( boxMin1, boxMax1, vecOtherMins, vecOtherMaxs ); + }*/ + + // OBB test... + cplane_t plane; + bool bFoundPlane = ComputeSeparatingPlane( vecOrigin1, vecAngles1, boxMin1, boxMax1, + vecOrigin2, vecAngles2, boxMin2, boxMax2, flTolerance, &plane ); + return (bFoundPlane == false); +} + +// NOTE: This is only very slightly faster on high end PCs and x360 +#define USE_SIMD_RAY_CHECKS 1 +//----------------------------------------------------------------------------- +// returns true if there's an intersection between box and ray +//----------------------------------------------------------------------------- +bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, + const Vector& origin, const Vector& vecDelta, float flTolerance ) +{ + +#if USE_SIMD_RAY_CHECKS + // Load the unaligned ray/box parameters into SIMD registers + fltx4 start = LoadUnaligned3SIMD(origin.Base()); + fltx4 delta = LoadUnaligned3SIMD(vecDelta.Base()); + fltx4 boxMins = LoadUnaligned3SIMD( boxMin.Base() ); + fltx4 boxMaxs = LoadUnaligned3SIMD( boxMax.Base() ); + fltx4 epsilon = ReplicateX4(flTolerance); + // compute the mins/maxs of the box expanded by the ray extents + // relocate the problem so that the ray start is at the origin. + fltx4 offsetMins = SubSIMD(boxMins, start); + fltx4 offsetMaxs = SubSIMD(boxMaxs, start); + fltx4 offsetMinsExpanded = SubSIMD(offsetMins, epsilon); + fltx4 offsetMaxsExpanded = AddSIMD(offsetMaxs, epsilon); + + // Check to see if both the origin (start point) and the end point (delta) are on the front side + // of any of the box sides - if so there can be no intersection + fltx4 startOutMins = CmpLtSIMD(Four_Zeros, offsetMinsExpanded); + fltx4 endOutMins = CmpLtSIMD(delta,offsetMinsExpanded); + fltx4 minsMask = AndSIMD( startOutMins, endOutMins ); + fltx4 startOutMaxs = CmpGtSIMD(Four_Zeros, offsetMaxsExpanded); + fltx4 endOutMaxs = CmpGtSIMD(delta,offsetMaxsExpanded); + fltx4 maxsMask = AndSIMD( startOutMaxs, endOutMaxs ); + if ( IsAnyNegative(SetWToZeroSIMD(OrSIMD(minsMask,maxsMask)))) + return false; + + // now build the per-axis interval of t for intersections + fltx4 invDelta = ReciprocalSaturateSIMD(delta); + fltx4 tmins = MulSIMD( offsetMinsExpanded, invDelta ); + fltx4 tmaxs = MulSIMD( offsetMaxsExpanded, invDelta ); + fltx4 crossPlane = OrSIMD(XorSIMD(startOutMins,endOutMins), XorSIMD(startOutMaxs,endOutMaxs)); + + // only consider axes where we crossed a plane + tmins = MaskedAssign( crossPlane, tmins, Four_Negative_FLT_MAX ); + tmaxs = MaskedAssign( crossPlane, tmaxs, Four_FLT_MAX ); + + // now sort the interval per axis + fltx4 mint = MinSIMD( tmins, tmaxs ); + fltx4 maxt = MaxSIMD( tmins, tmaxs ); + + // now find the intersection of the intervals on all axes + fltx4 firstOut = FindLowestSIMD3(maxt); + fltx4 lastIn = FindHighestSIMD3(mint); + // NOTE: This is really a scalar quantity now [t0,t1] == [lastIn,firstOut] + firstOut = MinSIMD(firstOut, Four_Ones); + lastIn = MaxSIMD(lastIn, Four_Zeros); + + // If the final interval is valid lastIn boxMax[i] + flTolerance) ) + return false; + + continue; + } + + // non-parallel case + // Find the t's corresponding to the entry and exit of + // the ray along x, y, and z. The find the furthest entry + // point, and the closest exit point. Once that is done, + // we know we don't collide if the closest exit point + // is behind the starting location. We also don't collide if + // the closest exit point is in front of the furthest entry point + + float invDelta = 1.0f / vecDelta[i]; + float t1 = (boxMin[i] - flTolerance - origin[i]) * invDelta; + float t2 = (boxMax[i] + flTolerance - origin[i]) * invDelta; + if (t1 > t2) + { + float temp = t1; + t1 = t2; + t2 = temp; + } + if (t1 > tmin) + tmin = t1; + if (t2 < tmax) + tmax = t2; + if (tmin > tmax) + return false; + if (tmax < 0) + return false; + if (tmin > 1) + return false; + } + + return true; +#endif +} + +//----------------------------------------------------------------------------- +// returns true if there's an intersection between box and ray +//----------------------------------------------------------------------------- +bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, + const Vector& origin, const Vector& vecDelta, + const Vector& vecInvDelta, float flTolerance ) +{ +#if USE_SIMD_RAY_CHECKS + // Load the unaligned ray/box parameters into SIMD registers + fltx4 start = LoadUnaligned3SIMD(origin.Base()); + fltx4 delta = LoadUnaligned3SIMD(vecDelta.Base()); + fltx4 boxMins = LoadUnaligned3SIMD( boxMin.Base() ); + fltx4 boxMaxs = LoadUnaligned3SIMD( boxMax.Base() ); + // compute the mins/maxs of the box expanded by the ray extents + // relocate the problem so that the ray start is at the origin. + boxMins = SubSIMD(boxMins, start); + boxMaxs = SubSIMD(boxMaxs, start); + + // Check to see if both the origin (start point) and the end point (delta) are on the front side + // of any of the box sides - if so there can be no intersection + fltx4 startOutMins = CmpLtSIMD(Four_Zeros, boxMins); + fltx4 endOutMins = CmpLtSIMD(delta,boxMins); + fltx4 minsMask = AndSIMD( startOutMins, endOutMins ); + fltx4 startOutMaxs = CmpGtSIMD(Four_Zeros, boxMaxs); + fltx4 endOutMaxs = CmpGtSIMD(delta,boxMaxs); + fltx4 maxsMask = AndSIMD( startOutMaxs, endOutMaxs ); + if ( IsAnyNegative(SetWToZeroSIMD(OrSIMD(minsMask,maxsMask)))) + return false; + + // now build the per-axis interval of t for intersections + fltx4 epsilon = ReplicateX4(flTolerance); + fltx4 invDelta = LoadUnaligned3SIMD(vecInvDelta.Base()); + boxMins = SubSIMD(boxMins, epsilon); + boxMaxs = AddSIMD(boxMaxs, epsilon); + + boxMins = MulSIMD( boxMins, invDelta ); + boxMaxs = MulSIMD( boxMaxs, invDelta ); + + fltx4 crossPlane = OrSIMD(XorSIMD(startOutMins,endOutMins), XorSIMD(startOutMaxs,endOutMaxs)); + // only consider axes where we crossed a plane + boxMins = MaskedAssign( crossPlane, boxMins, Four_Negative_FLT_MAX ); + boxMaxs = MaskedAssign( crossPlane, boxMaxs, Four_FLT_MAX ); + + // now sort the interval per axis + fltx4 mint = MinSIMD( boxMins, boxMaxs ); + fltx4 maxt = MaxSIMD( boxMins, boxMaxs ); + + // now find the intersection of the intervals on all axes + fltx4 firstOut = FindLowestSIMD3(maxt); + fltx4 lastIn = FindHighestSIMD3(mint); + // NOTE: This is really a scalar quantity now [t0,t1] == [lastIn,firstOut] + firstOut = MinSIMD(firstOut, Four_Ones); + lastIn = MaxSIMD(lastIn, Four_Zeros); + + // If the final interval is valid lastIn boxMax[i] + flTolerance ) ) + return false; + + continue; + } + + // Non-parallel case + // Find the t's corresponding to the entry and exit of + // the ray along x, y, and z. The find the furthest entry + // point, and the closest exit point. Once that is done, + // we know we don't collide if the closest exit point + // is behind the starting location. We also don't collide if + // the closest exit point is in front of the furthest entry point + float t1 = ( boxMin[i] - flTolerance - origin[i] ) * vecInvDelta[i]; + float t2 = ( boxMax[i] + flTolerance - origin[i] ) * vecInvDelta[i]; + if ( t1 > t2 ) + { + float temp = t1; + t1 = t2; + t2 = temp; + } + + if (t1 > tmin) + tmin = t1; + + if (t2 < tmax) + tmax = t2; + + if (tmin > tmax) + return false; + + if (tmax < 0) + return false; + + if (tmin > 1) + return false; + } + + return true; +#endif +} + +//----------------------------------------------------------------------------- +// Intersects a ray with a aabb, return true if they intersect +//----------------------------------------------------------------------------- +bool FASTCALL IsBoxIntersectingRay( const Vector& vecBoxMin, const Vector& vecBoxMax, const Ray_t& ray, float flTolerance ) +{ + // On the x360, we force use of the SIMD functions. +#if defined(_X360) + if (IsX360()) + { + return IsBoxIntersectingRay( + LoadUnaligned3SIMD(vecBoxMin.Base()), LoadUnaligned3SIMD(vecBoxMax.Base()), + ray, flTolerance); + } +#endif + + if ( !ray.m_IsSwept ) + { + Vector rayMins, rayMaxs; + VectorSubtract( ray.m_Start, ray.m_Extents, rayMins ); + VectorAdd( ray.m_Start, ray.m_Extents, rayMaxs ); + if ( flTolerance != 0.0f ) + { + rayMins.x -= flTolerance; rayMins.y -= flTolerance; rayMins.z -= flTolerance; + rayMaxs.x += flTolerance; rayMaxs.y += flTolerance; rayMaxs.z += flTolerance; + } + return IsBoxIntersectingBox( vecBoxMin, vecBoxMax, rayMins, rayMaxs ); + } + + Vector vecExpandedBoxMin, vecExpandedBoxMax; + VectorSubtract( vecBoxMin, ray.m_Extents, vecExpandedBoxMin ); + VectorAdd( vecBoxMax, ray.m_Extents, vecExpandedBoxMax ); + return IsBoxIntersectingRay( vecExpandedBoxMin, vecExpandedBoxMax, ray.m_Start, ray.m_Delta, flTolerance ); +} + + +//----------------------------------------------------------------------------- +// returns true if there's an intersection between box and ray (SIMD version) +//----------------------------------------------------------------------------- + + +#ifdef _X360 +bool FASTCALL IsBoxIntersectingRay( fltx4 boxMin, fltx4 boxMax, + fltx4 origin, fltx4 delta, fltx4 invDelta, // ray parameters + fltx4 vTolerance ///< eg from ReplicateX4(flTolerance) + ) +#else +bool FASTCALL IsBoxIntersectingRay( const fltx4 &inBoxMin, const fltx4 & inBoxMax, + const fltx4 & origin, const fltx4 & delta, const fltx4 & invDelta, // ray parameters + const fltx4 & vTolerance ///< eg from ReplicateX4(flTolerance) + ) +#endif +{ + // Load the unaligned ray/box parameters into SIMD registers + // compute the mins/maxs of the box expanded by the ray extents + // relocate the problem so that the ray start is at the origin. + +#ifdef _X360 + boxMin = SubSIMD(boxMin, origin); + boxMax = SubSIMD(boxMax, origin); +#else + fltx4 boxMin = SubSIMD(inBoxMin, origin); + fltx4 boxMax = SubSIMD(inBoxMax, origin); +#endif + + // Check to see if the origin (start point) and the end point (delta) are on the same side + // of any of the box sides - if so there can be no intersection + fltx4 startOutMins = AndSIMD( CmpLtSIMD(Four_Zeros, boxMin), CmpLtSIMD(delta,boxMin) ); + fltx4 startOutMaxs = AndSIMD( CmpGtSIMD(Four_Zeros, boxMax), CmpGtSIMD(delta,boxMax) ); + if ( IsAnyNegative(SetWToZeroSIMD(OrSIMD(startOutMaxs,startOutMins)))) + return false; + + // now build the per-axis interval of t for intersections + boxMin = SubSIMD(boxMin, vTolerance); + boxMax = AddSIMD(boxMax, vTolerance); + + boxMin = MulSIMD( boxMin, invDelta ); + boxMax = MulSIMD( boxMax, invDelta ); + + // now sort the interval per axis + fltx4 mint = MinSIMD( boxMin, boxMax ); + fltx4 maxt = MaxSIMD( boxMin, boxMax ); + + // now find the intersection of the intervals on all axes + fltx4 firstOut = FindLowestSIMD3(maxt); + fltx4 lastIn = FindHighestSIMD3(mint); + // NOTE: This is really a scalar quantity now [t0,t1] == [lastIn,firstOut] + firstOut = MinSIMD(firstOut, Four_Ones); + lastIn = MaxSIMD(lastIn, Four_Zeros); + + // If the final interval is valid lastInt1 = -1.0f; + pTrace->t2 = 1.0f; + pTrace->hitside = -1; + + // UNDONE: This makes this code a little messy + pTrace->startsolid = true; + + for ( i = 0; i < 6; ++i ) + { + if ( i >= 3 ) + { + d1 = vecRayStart[i-3] - boxMaxs[i-3]; + d2 = d1 + vecRayDelta[i-3]; + } + else + { + d1 = -vecRayStart[i] + boxMins[i]; + d2 = d1 - vecRayDelta[i]; + } + + // if completely in front of face, no intersection + if (d1 > 0 && d2 > 0) + { + // UNDONE: Have to revert this in case it's still set + // UNDONE: Refactor to have only 2 return points (true/false) from this function + pTrace->startsolid = false; + return false; + } + + // completely inside, check next face + if (d1 <= 0 && d2 <= 0) + continue; + + if (d1 > 0) + { + pTrace->startsolid = false; + } + + // crosses face + if (d1 > d2) + { + f = d1 - flTolerance; + if ( f < 0 ) + { + f = 0; + } + f = f / (d1-d2); + if (f > pTrace->t1) + { + pTrace->t1 = f; + pTrace->hitside = i; + } + } + else + { + // leave + f = (d1 + flTolerance) / (d1-d2); + if (f < pTrace->t2) + { + pTrace->t2 = f; + } + } + } + + return pTrace->startsolid || (pTrace->t1 < pTrace->t2 && pTrace->t1 >= 0.0f); +} + + +//----------------------------------------------------------------------------- +// Intersects a ray against a box +//----------------------------------------------------------------------------- +bool IntersectRayWithBox( const Vector &vecRayStart, const Vector &vecRayDelta, + const Vector &boxMins, const Vector &boxMaxs, float flTolerance, CBaseTrace *pTrace, float *pFractionLeftSolid ) +{ + Collision_ClearTrace( vecRayStart, vecRayDelta, pTrace ); + + BoxTraceInfo_t trace; + + if ( IntersectRayWithBox( vecRayStart, vecRayDelta, boxMins, boxMaxs, flTolerance, &trace ) ) + { + pTrace->startsolid = trace.startsolid; + if (trace.t1 < trace.t2 && trace.t1 >= 0.0f) + { + pTrace->fraction = trace.t1; + VectorMA( pTrace->startpos, trace.t1, vecRayDelta, pTrace->endpos ); + pTrace->contents = CONTENTS_SOLID; + pTrace->plane.normal = vec3_origin; + if ( trace.hitside >= 3 ) + { + trace.hitside -= 3; + pTrace->plane.dist = boxMaxs[trace.hitside]; + pTrace->plane.normal[trace.hitside] = 1.0f; + pTrace->plane.type = trace.hitside; + } + else + { + pTrace->plane.dist = -boxMins[trace.hitside]; + pTrace->plane.normal[trace.hitside] = -1.0f; + pTrace->plane.type = trace.hitside; + } + return true; + } + + if ( pTrace->startsolid ) + { + pTrace->allsolid = (trace.t2 <= 0.0f) || (trace.t2 >= 1.0f); + pTrace->fraction = 0; + if ( pFractionLeftSolid ) + { + *pFractionLeftSolid = trace.t2; + } + pTrace->endpos = pTrace->startpos; + pTrace->contents = CONTENTS_SOLID; + pTrace->plane.dist = pTrace->startpos[0]; + pTrace->plane.normal.Init( 1.0f, 0.0f, 0.0f ); + pTrace->plane.type = 0; + pTrace->startpos = vecRayStart + (trace.t2 * vecRayDelta); + return true; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Intersects a ray against a box +//----------------------------------------------------------------------------- +bool IntersectRayWithBox( const Ray_t &ray, const Vector &boxMins, const Vector &boxMaxs, + float flTolerance, CBaseTrace *pTrace, float *pFractionLeftSolid ) +{ + if ( !ray.m_IsRay ) + { + Vector vecExpandedMins = boxMins - ray.m_Extents; + Vector vecExpandedMaxs = boxMaxs + ray.m_Extents; + bool bIntersects = IntersectRayWithBox( ray.m_Start, ray.m_Delta, vecExpandedMins, vecExpandedMaxs, flTolerance, pTrace, pFractionLeftSolid ); + pTrace->startpos += ray.m_StartOffset; + pTrace->endpos += ray.m_StartOffset; + return bIntersects; + } + return IntersectRayWithBox( ray.m_Start, ray.m_Delta, boxMins, boxMaxs, flTolerance, pTrace, pFractionLeftSolid ); +} + + +//----------------------------------------------------------------------------- +// Intersects a ray against an OBB, returns t1 and t2 +//----------------------------------------------------------------------------- +bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta, + const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs, + float flTolerance, BoxTraceInfo_t *pTrace ) +{ + // FIXME: Two transforms is pretty expensive. Should we optimize this? + Vector start, delta; + VectorITransform( vecRayStart, matOBBToWorld, start ); + VectorIRotate( vecRayDelta, matOBBToWorld, delta ); + + return IntersectRayWithBox( start, delta, vecOBBMins, vecOBBMaxs, flTolerance, pTrace ); +} + + + +//----------------------------------------------------------------------------- +// Intersects a ray against an OBB +//----------------------------------------------------------------------------- +bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta, + const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs, + float flTolerance, CBaseTrace *pTrace ) +{ + Collision_ClearTrace( vecRayStart, vecRayDelta, pTrace ); + + // FIXME: Make it work with tolerance + Assert( flTolerance == 0.0f ); + + // OPTIMIZE: Store this in the box instead of computing it here + // compute center in local space + Vector vecBoxExtents = (vecOBBMins + vecOBBMaxs) * 0.5; + Vector vecBoxCenter; + + // transform to world space + VectorTransform( vecBoxExtents, matOBBToWorld, vecBoxCenter ); + + // calc extents from local center + vecBoxExtents = vecOBBMaxs - vecBoxExtents; + + // OPTIMIZE: This is optimized for world space. If the transform is fast enough, it may make more + // sense to just xform and call UTIL_ClipToBox() instead. MEASURE THIS. + + // save the extents of the ray along + Vector extent, uextent; + Vector segmentCenter = vecRayStart + vecRayDelta - vecBoxCenter; + + extent.Init(); + + // check box axes for separation + for ( int j = 0; j < 3; j++ ) + { + extent[j] = vecRayDelta.x * matOBBToWorld[0][j] + vecRayDelta.y * matOBBToWorld[1][j] + vecRayDelta.z * matOBBToWorld[2][j]; + uextent[j] = fabsf(extent[j]); + float coord = segmentCenter.x * matOBBToWorld[0][j] + segmentCenter.y * matOBBToWorld[1][j] + segmentCenter.z * matOBBToWorld[2][j]; + coord = fabsf(coord); + + if ( coord > (vecBoxExtents[j] + uextent[j]) ) + return false; + } + + // now check cross axes for separation + float tmp, cextent; + Vector cross = vecRayDelta.Cross( segmentCenter ); + cextent = cross.x * matOBBToWorld[0][0] + cross.y * matOBBToWorld[1][0] + cross.z * matOBBToWorld[2][0]; + cextent = fabsf(cextent); + tmp = vecBoxExtents[1]*uextent[2] + vecBoxExtents[2]*uextent[1]; + if ( cextent > tmp ) + return false; + + cextent = cross.x * matOBBToWorld[0][1] + cross.y * matOBBToWorld[1][1] + cross.z * matOBBToWorld[2][1]; + cextent = fabsf(cextent); + tmp = vecBoxExtents[0]*uextent[2] + vecBoxExtents[2]*uextent[0]; + if ( cextent > tmp ) + return false; + + cextent = cross.x * matOBBToWorld[0][2] + cross.y * matOBBToWorld[1][2] + cross.z * matOBBToWorld[2][2]; + cextent = fabsf(cextent); + tmp = vecBoxExtents[0]*uextent[1] + vecBoxExtents[1]*uextent[0]; + if ( cextent > tmp ) + return false; + + // !!! We hit this box !!! compute intersection point and return + // Compute ray start in bone space + Vector start; + VectorITransform( vecRayStart, matOBBToWorld, start ); + + // extent is ray.m_Delta in bone space, recompute delta in bone space + extent *= 2.0f; + + // delta was prescaled by the current t, so no need to see if this intersection + // is closer + trace_t boxTrace; + if ( !IntersectRayWithBox( start, extent, vecOBBMins, vecOBBMaxs, flTolerance, pTrace ) ) + return false; + + // Fix up the start/end pos and fraction + Vector vecTemp; + VectorTransform( pTrace->endpos, matOBBToWorld, vecTemp ); + pTrace->endpos = vecTemp; + + pTrace->startpos = vecRayStart; + pTrace->fraction *= 2.0f; + + // Fix up the plane information + float flSign = pTrace->plane.normal[ pTrace->plane.type ]; + pTrace->plane.normal[0] = flSign * matOBBToWorld[0][pTrace->plane.type]; + pTrace->plane.normal[1] = flSign * matOBBToWorld[1][pTrace->plane.type]; + pTrace->plane.normal[2] = flSign * matOBBToWorld[2][pTrace->plane.type]; + pTrace->plane.dist = DotProduct( pTrace->endpos, pTrace->plane.normal ); + pTrace->plane.type = 3; + + return true; +} + + +//----------------------------------------------------------------------------- +// Intersects a ray against an OBB +//----------------------------------------------------------------------------- +bool IntersectRayWithOBB( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector &vecBoxOrigin, const QAngle &angBoxRotation, + const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace ) +{ + if (angBoxRotation == vec3_angle) + { + Vector vecAbsMins, vecAbsMaxs; + VectorAdd( vecBoxOrigin, vecOBBMins, vecAbsMins ); + VectorAdd( vecBoxOrigin, vecOBBMaxs, vecAbsMaxs ); + return IntersectRayWithBox( vecRayOrigin, vecRayDelta, vecAbsMins, vecAbsMaxs, flTolerance, pTrace ); + } + + matrix3x4_t obbToWorld; + AngleMatrix( angBoxRotation, vecBoxOrigin, obbToWorld ); + return IntersectRayWithOBB( vecRayOrigin, vecRayDelta, obbToWorld, vecOBBMins, vecOBBMaxs, flTolerance, pTrace ); +} + + +//----------------------------------------------------------------------------- +// Box support map +//----------------------------------------------------------------------------- +inline void ComputeSupportMap( const Vector &vecDirection, const Vector &vecBoxMins, + const Vector &vecBoxMaxs, float pDist[2] ) +{ + int nIndex = (vecDirection.x > 0.0f); + pDist[nIndex] = vecBoxMaxs.x * vecDirection.x; + pDist[1 - nIndex] = vecBoxMins.x * vecDirection.x; + + nIndex = (vecDirection.y > 0.0f); + pDist[nIndex] += vecBoxMaxs.y * vecDirection.y; + pDist[1 - nIndex] += vecBoxMins.y * vecDirection.y; + + nIndex = (vecDirection.z > 0.0f); + pDist[nIndex] += vecBoxMaxs.z * vecDirection.z; + pDist[1 - nIndex] += vecBoxMins.z * vecDirection.z; +} + +inline void ComputeSupportMap( const Vector &vecDirection, int i1, int i2, + const Vector &vecBoxMins, const Vector &vecBoxMaxs, float pDist[2] ) +{ + int nIndex = (vecDirection[i1] > 0.0f); + pDist[nIndex] = vecBoxMaxs[i1] * vecDirection[i1]; + pDist[1 - nIndex] = vecBoxMins[i1] * vecDirection[i1]; + + nIndex = (vecDirection[i2] > 0.0f); + pDist[nIndex] += vecBoxMaxs[i2] * vecDirection[i2]; + pDist[1 - nIndex] += vecBoxMins[i2] * vecDirection[i2]; +} + +//----------------------------------------------------------------------------- +// Intersects a ray against an OBB +//----------------------------------------------------------------------------- +static int s_ExtIndices[3][2] = +{ + { 2, 1 }, + { 0, 2 }, + { 0, 1 }, +}; + +static int s_MatIndices[3][2] = +{ + { 1, 2 }, + { 2, 0 }, + { 1, 0 }, +}; + +bool IntersectRayWithOBB( const Ray_t &ray, const matrix3x4_t &matOBBToWorld, + const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace ) +{ + if ( ray.m_IsRay ) + { + return IntersectRayWithOBB( ray.m_Start, ray.m_Delta, matOBBToWorld, + vecOBBMins, vecOBBMaxs, flTolerance, pTrace ); + } + + Collision_ClearTrace( ray.m_Start + ray.m_StartOffset, ray.m_Delta, pTrace ); + + // Compute a bounding sphere around the bloated OBB + Vector vecOBBCenter; + VectorAdd( vecOBBMins, vecOBBMaxs, vecOBBCenter ); + vecOBBCenter *= 0.5f; + vecOBBCenter.x += matOBBToWorld[0][3]; + vecOBBCenter.y += matOBBToWorld[1][3]; + vecOBBCenter.z += matOBBToWorld[2][3]; + + Vector vecOBBHalfDiagonal; + VectorSubtract( vecOBBMaxs, vecOBBMins, vecOBBHalfDiagonal ); + vecOBBHalfDiagonal *= 0.5f; + + float flRadius = vecOBBHalfDiagonal.Length() + ray.m_Extents.Length(); + if ( !IsRayIntersectingSphere( ray.m_Start, ray.m_Delta, vecOBBCenter, flRadius, flTolerance ) ) + return false; + + // Ok, we passed the trivial reject, so lets do the dirty deed. + // Basically we're going to do the GJK thing explicitly. We'll shrink the ray down + // to a point, and bloat the OBB by the ray's extents. This will generate facet + // planes which are perpendicular to all of the separating axes typically seen in + // a standard seperating axis implementation. + + // We're going to create a number of planes through various vertices in the OBB + // which represent all of the separating planes. Then we're going to bloat the planes + // by the ray extents. + + // We're going to do all work in OBB-space because it's easier to do the + // support-map in this case + + // First, transform the ray into the space of the OBB + Vector vecLocalRayOrigin, vecLocalRayDirection; + VectorITransform( ray.m_Start, matOBBToWorld, vecLocalRayOrigin ); + VectorIRotate( ray.m_Delta, matOBBToWorld, vecLocalRayDirection ); + + // Next compute all separating planes + Vector pPlaneNormal[15]; + float ppPlaneDist[15][2]; + + int i; + for ( i = 0; i < 3; ++i ) + { + // Each plane needs to be bloated an amount = to the abs dot product of + // the ray extents with the plane normal + // For the OBB planes, do it in world space; + // and use the direction of the OBB (the ith column of matOBBToWorld) in world space vs extents + pPlaneNormal[i].Init( ); + pPlaneNormal[i][i] = 1.0f; + + float flExtentDotNormal = + FloatMakePositive( matOBBToWorld[0][i] * ray.m_Extents.x ) + + FloatMakePositive( matOBBToWorld[1][i] * ray.m_Extents.y ) + + FloatMakePositive( matOBBToWorld[2][i] * ray.m_Extents.z ); + + ppPlaneDist[i][0] = vecOBBMins[i] - flExtentDotNormal; + ppPlaneDist[i][1] = vecOBBMaxs[i] + flExtentDotNormal; + + // For the ray-extents planes, they are bloated by the extents + // Use the support map to determine which + VectorCopy( matOBBToWorld[i], pPlaneNormal[i+3].Base() ); + ComputeSupportMap( pPlaneNormal[i+3], vecOBBMins, vecOBBMaxs, ppPlaneDist[i+3] ); + ppPlaneDist[i+3][0] -= ray.m_Extents[i]; + ppPlaneDist[i+3][1] += ray.m_Extents[i]; + + // Now the edge cases... (take the cross product of x,y,z axis w/ ray extent axes + // given by the rows of the obb to world matrix. + // Compute the ray extent bloat in world space because it's easier... + + // These are necessary to compute the world-space versions of + // the edges so we can compute the extent dot products + float flRayExtent0 = ray.m_Extents[s_ExtIndices[i][0]]; + float flRayExtent1 = ray.m_Extents[s_ExtIndices[i][1]]; + const float *pMatRow0 = matOBBToWorld[s_MatIndices[i][0]]; + const float *pMatRow1 = matOBBToWorld[s_MatIndices[i][1]]; + + // x axis of the OBB + world ith axis + pPlaneNormal[i+6].Init( 0.0f, -matOBBToWorld[i][2], matOBBToWorld[i][1] ); + ComputeSupportMap( pPlaneNormal[i+6], 1, 2, vecOBBMins, vecOBBMaxs, ppPlaneDist[i+6] ); + flExtentDotNormal = + FloatMakePositive( pMatRow0[0] ) * flRayExtent0 + + FloatMakePositive( pMatRow1[0] ) * flRayExtent1; + ppPlaneDist[i+6][0] -= flExtentDotNormal; + ppPlaneDist[i+6][1] += flExtentDotNormal; + + // y axis of the OBB + world ith axis + pPlaneNormal[i+9].Init( matOBBToWorld[i][2], 0.0f, -matOBBToWorld[i][0] ); + ComputeSupportMap( pPlaneNormal[i+9], 0, 2, vecOBBMins, vecOBBMaxs, ppPlaneDist[i+9] ); + flExtentDotNormal = + FloatMakePositive( pMatRow0[1] ) * flRayExtent0 + + FloatMakePositive( pMatRow1[1] ) * flRayExtent1; + ppPlaneDist[i+9][0] -= flExtentDotNormal; + ppPlaneDist[i+9][1] += flExtentDotNormal; + + // z axis of the OBB + world ith axis + pPlaneNormal[i+12].Init( -matOBBToWorld[i][1], matOBBToWorld[i][0], 0.0f ); + ComputeSupportMap( pPlaneNormal[i+12], 0, 1, vecOBBMins, vecOBBMaxs, ppPlaneDist[i+12] ); + flExtentDotNormal = + FloatMakePositive( pMatRow0[2] ) * flRayExtent0 + + FloatMakePositive( pMatRow1[2] ) * flRayExtent1; + ppPlaneDist[i+12][0] -= flExtentDotNormal; + ppPlaneDist[i+12][1] += flExtentDotNormal; + } + + float enterfrac, leavefrac; + float d1[2], d2[2]; + float f; + + int hitplane = -1; + int hitside = -1; + enterfrac = -1.0f; + leavefrac = 1.0f; + + pTrace->startsolid = true; + + Vector vecLocalRayEnd; + VectorAdd( vecLocalRayOrigin, vecLocalRayDirection, vecLocalRayEnd ); + + for ( i = 0; i < 15; ++i ) + { + // FIXME: Not particularly optimal since there's a lot of 0's in the plane normals + float flStartDot = DotProduct( pPlaneNormal[i], vecLocalRayOrigin ); + float flEndDot = DotProduct( pPlaneNormal[i], vecLocalRayEnd ); + + // NOTE: Negative here is because the plane normal + dist + // are defined in negative terms for the far plane (plane dist index 0) + d1[0] = -(flStartDot - ppPlaneDist[i][0]); + d2[0] = -(flEndDot - ppPlaneDist[i][0]); + + d1[1] = flStartDot - ppPlaneDist[i][1]; + d2[1] = flEndDot - ppPlaneDist[i][1]; + + int j; + for ( j = 0; j < 2; ++j ) + { + // if completely in front near plane or behind far plane no intersection + if (d1[j] > 0 && d2[j] > 0) + return false; + + // completely inside, check next plane set + if (d1[j] <= 0 && d2[j] <= 0) + continue; + + if (d1[j] > 0) + { + pTrace->startsolid = false; + } + + // crosses face + float flDenom = 1.0f / (d1[j] - d2[j]); + if (d1[j] > d2[j]) + { + f = d1[j] - flTolerance; + if ( f < 0 ) + { + f = 0; + } + f *= flDenom; + if (f > enterfrac) + { + enterfrac = f; + hitplane = i; + hitside = j; + } + } + else + { + // leave + f = (d1[j] + flTolerance) * flDenom; + if (f < leavefrac) + { + leavefrac = f; + } + } + } + } + + if (enterfrac < leavefrac && enterfrac >= 0.0f) + { + pTrace->fraction = enterfrac; + VectorMA( pTrace->startpos, enterfrac, ray.m_Delta, pTrace->endpos ); + pTrace->contents = CONTENTS_SOLID; + + // Need to transform the plane into world space... + cplane_t temp; + temp.normal = pPlaneNormal[hitplane]; + temp.dist = ppPlaneDist[hitplane][hitside]; + if (hitside == 0) + { + temp.normal *= -1.0f; + temp.dist *= -1.0f; + } + temp.type = 3; + + MatrixITransformPlane( matOBBToWorld, temp, pTrace->plane ); + return true; + } + + if ( pTrace->startsolid ) + { + pTrace->allsolid = (leavefrac <= 0.0f) || (leavefrac >= 1.0f); + pTrace->fraction = 0; + pTrace->endpos = pTrace->startpos; + pTrace->contents = CONTENTS_SOLID; + pTrace->plane.dist = pTrace->startpos[0]; + pTrace->plane.normal.Init( 1.0f, 0.0f, 0.0f ); + pTrace->plane.type = 0; + return true; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Intersects a ray against an OBB +//----------------------------------------------------------------------------- +bool IntersectRayWithOBB( const Ray_t &ray, const Vector &vecBoxOrigin, const QAngle &angBoxRotation, + const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace ) +{ + if ( angBoxRotation == vec3_angle ) + { + Vector vecWorldMins, vecWorldMaxs; + VectorAdd( vecBoxOrigin, vecOBBMins, vecWorldMins ); + VectorAdd( vecBoxOrigin, vecOBBMaxs, vecWorldMaxs ); + return IntersectRayWithBox( ray, vecWorldMins, vecWorldMaxs, flTolerance, pTrace ); + } + + if ( ray.m_IsRay ) + { + return IntersectRayWithOBB( ray.m_Start, ray.m_Delta, vecBoxOrigin, angBoxRotation, vecOBBMins, vecOBBMaxs, flTolerance, pTrace ); + } + + matrix3x4_t matOBBToWorld; + AngleMatrix( angBoxRotation, vecBoxOrigin, matOBBToWorld ); + return IntersectRayWithOBB( ray, matOBBToWorld, vecOBBMins, vecOBBMaxs, flTolerance, pTrace ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void GetNonMajorAxes( const Vector &vNormal, Vector2D &axes ) +{ + axes[0] = 0; + axes[1] = 1; + + if( FloatMakePositive( vNormal.x ) > FloatMakePositive( vNormal.y ) ) + { + if( FloatMakePositive( vNormal.x ) > FloatMakePositive( vNormal.z ) ) + { + axes[0] = 1; + axes[1] = 2; + } + } + else + { + if( FloatMakePositive( vNormal.y ) > FloatMakePositive( vNormal.z ) ) + { + axes[0] = 0; + axes[1] = 2; + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +QuadBarycentricRetval_t QuadWithParallelEdges( const Vector &vecOrigin, + const Vector &vecU, float lengthU, const Vector &vecV, float lengthV, + const Vector &pt, Vector2D &vecUV ) +{ + Ray_t rayAxis; + Ray_t rayPt; + + // + // handle the u axis + // + rayAxis.m_Start = vecOrigin; + rayAxis.m_Delta = vecU; + rayAxis.m_IsRay = true; + + rayPt.m_Start = pt; + rayPt.m_Delta = vecV * -( lengthV * 10.0f ); + rayPt.m_IsRay = true; + + float s, t; + IntersectRayWithRay( rayAxis, rayPt, t, s ); + vecUV[0] = t / lengthU; + + // + // handle the v axis + // + rayAxis.m_Delta = vecV; + + rayPt.m_Delta = vecU * -( lengthU * 10.0f ); + + IntersectRayWithRay( rayAxis, rayPt, t, s ); + vecUV[1] = t / lengthV; + + // inside of the quad?? + if( ( vecUV[0] < 0.0f ) || ( vecUV[0] > 1.0f ) || + ( vecUV[1] < 0.0f ) || ( vecUV[1] > 1.0f ) ) + return BARY_QUADRATIC_FALSE; + + return BARY_QUADRATIC_TRUE; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void ResolveQuadratic( double tPlus, double tMinus, + const Vector axisU0, const Vector axisU1, + const Vector axisV0, const Vector axisV1, + const Vector axisOrigin, const Vector pt, + int projU, double &s, double &t ) +{ + // calculate the sPlus, sMinus pair(s) + double sDenomPlus = ( axisU0[projU] * ( 1 - tPlus ) ) + ( axisU1[projU] * tPlus ); + double sDenomMinus = ( axisU0[projU] * ( 1 - tMinus ) ) + ( axisU1[projU] * tMinus ); + + double sPlus = UNINIT, sMinus = UNINIT; + if( FloatMakePositive( sDenomPlus ) >= 1e-5 ) + { + sPlus = ( pt[projU] - axisOrigin[projU] - ( axisV0[projU] * tPlus ) ) / sDenomPlus; + } + + if( FloatMakePositive( sDenomMinus ) >= 1e-5 ) + { + sMinus = ( pt[projU] - axisOrigin[projU] - ( axisV0[projU] * tMinus ) ) / sDenomMinus; + } + + if( ( tPlus >= 0.0 ) && ( tPlus <= 1.0 ) && ( sPlus >= 0.0 ) && ( sPlus <= 1.0 ) ) + { + s = sPlus; + t = tPlus; + return; + } + + if( ( tMinus >= 0.0 ) && ( tMinus <= 1.0 ) && ( sMinus >= 0.0 ) && ( sMinus <= 1.0 ) ) + { + s = sMinus; + t = tMinus; + return; + } + + double s0, t0, s1, t1; + + s0 = sPlus; + t0 = tPlus; + if( s0 >= 1.0 ) { s0 -= 1.0; } + if( t0 >= 1.0 ) { t0 -= 1.0; } + + s1 = sMinus; + t1 = tMinus; + if( s1 >= 1.0 ) { s1 -= 1.0; } + if( t1 >= 1.0 ) { t1 -= 1.0; } + + s0 = FloatMakePositive( s0 ); + t0 = FloatMakePositive( t0 ); + s1 = FloatMakePositive( s1 ); + t1 = FloatMakePositive( t1 ); + + double max0, max1; + max0 = s0; + if( t0 > max0 ) { max0 = t0; } + max1 = s1; + if( t1 > max1 ) { max1 = t1; } + + if( max0 > max1 ) + { + s = sMinus; + t = tMinus; + } + else + { + s = sPlus; + t = tPlus; + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +QuadBarycentricRetval_t PointInQuadToBarycentric( const Vector &v1, const Vector &v2, + const Vector &v3, const Vector &v4, const Vector &point, Vector2D &uv ) +{ +#define PIQ_TEXTURE_EPSILON 0.001 +#define PIQ_PLANE_EPSILON 0.1 +#define PIQ_DOT_EPSILON 0.99f + + // + // Think of a quad with points v1, v2, v3, v4 and u, v line segments + // u0 = v2 - v1 + // u1 = v3 - v4 + // v0 = v4 - v1 + // v1 = v3 - v2 + // + Vector axisU[2], axisV[2]; + Vector axisUNorm[2], axisVNorm[2]; + axisU[0] = axisUNorm[0] = v2 - v1; + axisU[1] = axisUNorm[1] = v3 - v4; + axisV[0] = axisVNorm[0] = v4 - v1; + axisV[1] = axisVNorm[1] = v3 - v2; + + float lengthU[2], lengthV[2]; + lengthU[0] = VectorNormalize( axisUNorm[0] ); + lengthU[1] = VectorNormalize( axisUNorm[1] ); + lengthV[0] = VectorNormalize( axisVNorm[0] ); + lengthV[1] = VectorNormalize( axisVNorm[1] ); + + // + // check for an early out - parallel opposite edges! + // NOTE: quad property if 1 set of opposite edges is parallel and equal + // in length, then the other set of edges is as well + // + if( axisUNorm[0].Dot( axisUNorm[1] ) > PIQ_DOT_EPSILON ) + { + if( FloatMakePositive( lengthU[0] - lengthU[1] ) < PIQ_PLANE_EPSILON ) + { + return QuadWithParallelEdges( v1, axisUNorm[0], lengthU[0], axisVNorm[0], lengthV[0], point, uv ); + } + } + + // + // since we are solving for s in our equations below we need to ensure that + // the v axes are non-parallel + // + bool bFlipped = false; + if( axisVNorm[0].Dot( axisVNorm[1] ) > PIQ_DOT_EPSILON ) + { + Vector tmp[2]; + tmp[0] = axisV[0]; + tmp[1] = axisV[1]; + axisV[0] = axisU[0]; + axisV[1] = axisU[1]; + axisU[0] = tmp[0]; + axisU[1] = tmp[1]; + bFlipped = true; + } + + // + // get the "projection" axes + // + Vector2D projAxes; + Vector vNormal = axisU[0].Cross( axisV[0] ); + GetNonMajorAxes( vNormal, projAxes ); + + // + // NOTE: axisU[0][projAxes[0]] < axisU[0][projAxes[1]], + // this is done to decrease error when dividing later + // + if( FloatMakePositive( axisU[0][projAxes[0]] ) < FloatMakePositive( axisU[0][projAxes[1]] ) ) + { + int tmp = projAxes[0]; + projAxes[0] = projAxes[1]; + projAxes[1] = tmp; + } + + // Here's how we got these equations: + // + // Given the points and u,v line segments above... + // + // Then: + // + // (1.0) PT = P0 + U0 * s + V * t + // + // where + // + // (1.1) V = V0 + s * (V1 - V0) + // (1.2) U = U0 + t * (U1 - U0) + // + // Therefore (from 1.1 + 1.0): + // PT - P0 = U0 * s + (V0 + s * (V1-V0)) * t + // Group s's: + // PT - P0 - t * V0 = s * (U0 + t * (V1-V0)) + // Two equations and two unknowns in x and y get you the following quadratic: + // + // solve the quadratic + // + double s = 0.0, t = 0.0; + double A, negB, C; + + A = ( axisU[0][projAxes[1]] * axisV[0][projAxes[0]] ) - + ( axisU[0][projAxes[0]] * axisV[0][projAxes[1]] ) - + ( axisU[1][projAxes[1]] * axisV[0][projAxes[0]] ) + + ( axisU[1][projAxes[0]] * axisV[0][projAxes[1]] ); + C = ( v1[projAxes[1]] * axisU[0][projAxes[0]] ) - + ( point[projAxes[1]] * axisU[0][projAxes[0]] ) - + ( v1[projAxes[0]] * axisU[0][projAxes[1]] ) + + ( point[projAxes[0]] * axisU[0][projAxes[1]] ); + negB = C - + ( v1[projAxes[1]] * axisU[1][projAxes[0]] ) + + ( point[projAxes[1]] * axisU[1][projAxes[0]] ) + + ( v1[projAxes[0]] * axisU[1][projAxes[1]] ) - + ( point[projAxes[0]] * axisU[1][projAxes[1]] ) + + ( axisU[0][projAxes[1]] * axisV[0][projAxes[0]] ) - + ( axisU[0][projAxes[0]] * axisV[0][projAxes[1]] ); + + if( ( A > -PIQ_PLANE_EPSILON ) && ( A < PIQ_PLANE_EPSILON ) ) + { + // shouldn't be here -- this should have been take care of in the "early out" +// Assert( 0 ); + + Vector vecUAvg, vecVAvg; + vecUAvg = ( axisUNorm[0] + axisUNorm[1] ) * 0.5f; + vecVAvg = ( axisVNorm[0] + axisVNorm[1] ) * 0.5f; + + float fLengthUAvg = ( lengthU[0] + lengthU[1] ) * 0.5f; + float fLengthVAvg = ( lengthV[0] + lengthV[1] ) * 0.5f; + + return QuadWithParallelEdges( v1, vecUAvg, fLengthUAvg, vecVAvg, fLengthVAvg, point, uv ); + +#if 0 + // legacy code -- kept here for completeness! + + // not a quadratic -- solve linearly + t = C / negB; + + // See (1.2) above + float ui = axisU[0][projAxes[0]] + t * ( axisU[1][projAxes[0]] - axisU[0][projAxes[0]] ); + if( FloatMakePositive( ui ) >= 1e-5 ) + { + // See (1.0) above + s = ( point[projAxes[0]] - v1[projAxes[0]] - axisV[0][projAxes[0]] * t ) / ui; + } +#endif + } + else + { + // (-b +/- sqrt( b^2 - 4ac )) / 2a + double discriminant = (negB*negB) - (4.0f * A * C); + if( discriminant < 0.0f ) + { + uv[0] = -99999.0f; + uv[1] = -99999.0f; + return BARY_QUADRATIC_NEGATIVE_DISCRIMINANT; + } + + double quad = sqrt( discriminant ); + double QPlus = ( negB + quad ) / ( 2.0f * A ); + double QMinus = ( negB - quad ) / ( 2.0f * A ); + + ResolveQuadratic( QPlus, QMinus, axisU[0], axisU[1], axisV[0], axisV[1], v1, point, projAxes[0], s, t ); + } + + if( !bFlipped ) + { + uv[0] = ( float )s; + uv[1] = ( float )t; + } + else + { + uv[0] = ( float )t; + uv[1] = ( float )s; + } + + // inside of the quad?? + if( ( uv[0] < 0.0f ) || ( uv[0] > 1.0f ) || ( uv[1] < 0.0f ) || ( uv[1] > 1.0f ) ) + return BARY_QUADRATIC_FALSE; + + return BARY_QUADRATIC_TRUE; + +#undef PIQ_TEXTURE_EPSILON +#undef PIQ_PLANE_EPSILON +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void PointInQuadFromBarycentric( const Vector &v1, const Vector &v2, const Vector &v3, const Vector &v4, + const Vector2D &uv, Vector &point ) +{ + // + // Think of a quad with points v1, v2, v3, v4 and u, v line segments + // find the ray from v0 edge to v1 edge at v + // + Vector vPts[2]; + VectorLerp( v1, v4, uv[1], vPts[0] ); + VectorLerp( v2, v3, uv[1], vPts[1] ); + VectorLerp( vPts[0], vPts[1], uv[0], point ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void TexCoordInQuadFromBarycentric( const Vector2D &v1, const Vector2D &v2, const Vector2D &v3, const Vector2D &v4, + const Vector2D &uv, Vector2D &texCoord ) +{ + // + // Think of a quad with points v1, v2, v3, v4 and u, v line segments + // find the ray from v0 edge to v1 edge at v + // + Vector2D vCoords[2]; + Vector2DLerp( v1, v4, uv[1], vCoords[0] ); + Vector2DLerp( v2, v3, uv[1], vCoords[1] ); + Vector2DLerp( vCoords[0], vCoords[1], uv[0], texCoord ); +} + + +//----------------------------------------------------------------------------- +// Compute point from barycentric specification +// Edge u goes from v0 to v1, edge v goes from v0 to v2 +//----------------------------------------------------------------------------- +void ComputePointFromBarycentric( const Vector& v0, const Vector& v1, const Vector& v2, + float u, float v, Vector& pt ) +{ + Vector edgeU, edgeV; + VectorSubtract( v1, v0, edgeU ); + VectorSubtract( v2, v0, edgeV ); + VectorMA( v0, u, edgeU, pt ); + VectorMA( pt, v, edgeV, pt ); +} + +void ComputePointFromBarycentric( const Vector2D& v0, const Vector2D& v1, const Vector2D& v2, + float u, float v, Vector2D& pt ) +{ + Vector2D edgeU, edgeV; + Vector2DSubtract( v1, v0, edgeU ); + Vector2DSubtract( v2, v0, edgeV ); + Vector2DMA( v0, u, edgeU, pt ); + Vector2DMA( pt, v, edgeV, pt ); +} + + +//----------------------------------------------------------------------------- +// Compute a matrix that has the correct orientation but which has an origin at +// the center of the bounds +//----------------------------------------------------------------------------- +static void ComputeCenterMatrix( const Vector& origin, const QAngle& angles, + const Vector& mins, const Vector& maxs, matrix3x4_t& matrix ) +{ + Vector centroid; + VectorAdd( mins, maxs, centroid ); + centroid *= 0.5f; + AngleMatrix( angles, matrix ); + + Vector worldCentroid; + VectorRotate( centroid, matrix, worldCentroid ); + worldCentroid += origin; + MatrixSetColumn( worldCentroid, 3, matrix ); +} + +static void ComputeCenterIMatrix( const Vector& origin, const QAngle& angles, + const Vector& mins, const Vector& maxs, matrix3x4_t& matrix ) +{ + Vector centroid; + VectorAdd( mins, maxs, centroid ); + centroid *= -0.5f; + AngleIMatrix( angles, matrix ); + + // For the translational component here, note that the origin in world space + // is T = R * C + O, (R = rotation matrix, C = centroid in local space, O = origin in world space) + // The IMatrix translation = - transpose(R) * T = -C - transpose(R) * 0 + Vector localOrigin; + VectorRotate( origin, matrix, localOrigin ); + centroid -= localOrigin; + MatrixSetColumn( centroid, 3, matrix ); +} + + +//----------------------------------------------------------------------------- +// Compute a matrix which is the absolute value of another +//----------------------------------------------------------------------------- +static inline void ComputeAbsMatrix( const matrix3x4_t& in, matrix3x4_t& out ) +{ + FloatBits(out[0][0]) = FloatAbsBits(in[0][0]); + FloatBits(out[0][1]) = FloatAbsBits(in[0][1]); + FloatBits(out[0][2]) = FloatAbsBits(in[0][2]); + FloatBits(out[1][0]) = FloatAbsBits(in[1][0]); + FloatBits(out[1][1]) = FloatAbsBits(in[1][1]); + FloatBits(out[1][2]) = FloatAbsBits(in[1][2]); + FloatBits(out[2][0]) = FloatAbsBits(in[2][0]); + FloatBits(out[2][1]) = FloatAbsBits(in[2][1]); + FloatBits(out[2][2]) = FloatAbsBits(in[2][2]); +} + + +//----------------------------------------------------------------------------- +// Compute a separating plane between two boxes (expensive!) +// Returns false if no separating plane exists +//----------------------------------------------------------------------------- +static bool ComputeSeparatingPlane( const matrix3x4_t &worldToBox1, const matrix3x4_t &box2ToWorld, + const Vector& box1Size, const Vector& box2Size, float tolerance, cplane_t* pPlane ) +{ + // The various separating planes can be either + // 1) A plane parallel to one of the box face planes + // 2) A plane parallel to the cross-product of an edge from each box + + // First, compute the basis of second box in the space of the first box + // NOTE: These basis place the origin at the centroid of each box! + matrix3x4_t box2ToBox1; + ConcatTransforms( worldToBox1, box2ToWorld, box2ToBox1 ); + + // We're going to be using the origin of box2 in the space of box1 alot, + // lets extract it from the matrix.... + Vector box2Origin; + MatrixGetColumn( box2ToBox1, 3, box2Origin ); + + // Next get the absolute values of these entries and store in absbox2ToBox1. + matrix3x4_t absBox2ToBox1; + ComputeAbsMatrix( box2ToBox1, absBox2ToBox1 ); + + // There are 15 tests to make. The first 3 involve trying planes parallel + // to the faces of the first box. + + // NOTE: The algorithm here involves finding the projections of the two boxes + // onto a particular line. If the projections on the line do not overlap, + // that means that there's a plane perpendicular to the line which separates + // the two boxes; and we've therefore found a separating plane. + + // The way we check for overlay is we find the projections of the two boxes + // onto the line, and add them up. We compare the sum with the projection + // of the relative center of box2 onto the same line. + + Vector tmp; + float boxProjectionSum; + float originProjection; + + // NOTE: For these guys, we're taking advantage of the fact that the ith + // row of the box2ToBox1 is the direction of the box1 (x,y,z)-axis + // transformed into the space of box2. + + // First side of box 1 + boxProjectionSum = box1Size.x + MatrixRowDotProduct( absBox2ToBox1, 0, box2Size ); + originProjection = FloatMakePositive( box2Origin.x ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + VectorCopy( worldToBox1[0], pPlane->normal.Base() ); + return true; + } + + // Second side of box 1 + boxProjectionSum = box1Size.y + MatrixRowDotProduct( absBox2ToBox1, 1, box2Size ); + originProjection = FloatMakePositive( box2Origin.y ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + VectorCopy( worldToBox1[1], pPlane->normal.Base() ); + return true; + } + + // Third side of box 1 + boxProjectionSum = box1Size.z + MatrixRowDotProduct( absBox2ToBox1, 2, box2Size ); + originProjection = FloatMakePositive( box2Origin.z ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + VectorCopy( worldToBox1[2], pPlane->normal.Base() ); + return true; + } + + // The next three involve checking splitting planes parallel to the + // faces of the second box. + + // NOTE: For these guys, we're taking advantage of the fact that the 0th + // column of the box2ToBox1 is the direction of the box2 x-axis + // transformed into the space of box1. + // Here, we're determining the distance of box2's center from box1's center + // by projecting it onto a line parallel to box2's axis + + // First side of box 2 + boxProjectionSum = box2Size.x + MatrixColumnDotProduct( absBox2ToBox1, 0, box1Size ); + originProjection = FloatMakePositive( MatrixColumnDotProduct( box2ToBox1, 0, box2Origin ) ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 0, pPlane->normal ); + return true; + } + + // Second side of box 2 + boxProjectionSum = box2Size.y + MatrixColumnDotProduct( absBox2ToBox1, 1, box1Size ); + originProjection = FloatMakePositive( MatrixColumnDotProduct( box2ToBox1, 1, box2Origin ) ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 1, pPlane->normal ); + return true; + } + + // Third side of box 2 + boxProjectionSum = box2Size.z + MatrixColumnDotProduct( absBox2ToBox1, 2, box1Size ); + originProjection = FloatMakePositive( MatrixColumnDotProduct( box2ToBox1, 2, box2Origin ) ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 2, pPlane->normal ); + return true; + } + + // Next check the splitting planes which are orthogonal to the pairs + // of edges, one from box1 and one from box2. As only direction matters, + // there are 9 pairs since each box has 3 distinct edge directions. + + // Here, we take advantage of the fact that the edges from box 1 are all + // axis aligned; therefore the crossproducts are simplified. Let's walk through + // the example of b1e1 x b2e1: + + // In this example, the line to check is perpendicular to b1e1 + b2e2 + // we can compute this line by taking the cross-product: + // + // [ i j k ] + // [ 1 0 0 ] = - ez j + ey k = l1 + // [ ex ey ez ] + + // Where ex, ey, ez is the components of box2's x axis in the space of box 1, + // which is == to the 0th column of of box2toBox1 + + // The projection of box1 onto this line = the absolute dot product of the box size + // against the line, which = + // AbsDot( box1Size, l1 ) = abs( -ez * box1.y ) + abs( ey * box1.z ) + + // To compute the projection of box2 onto this line, we'll do it in the space of box 2 + // + // [ i j k ] + // [ fx fy fz ] = fz j - fy k = l2 + // [ 1 0 0 ] + + // Where fx, fy, fz is the components of box1's x axis in the space of box 2, + // which is == to the 0th row of of box2toBox1 + + // The projection of box2 onto this line = the absolute dot product of the box size + // against the line, which = + // AbsDot( box2Size, l2 ) = abs( fz * box2.y ) + abs ( fy * box2.z ) + + // The projection of the relative origin position on this line is done in the + // space of box 1: + // + // originProjection = DotProduct( <-ez j + ey k>, box2Origin ) = + // -ez * box2Origin.y + ey * box2Origin.z + + // NOTE: These checks can be bogus if both edges are parallel. The if + // checks at the beginning of each block are designed to catch that case + + // b1e1 x b2e1 + if ( absBox2ToBox1[0][0] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.y * absBox2ToBox1[2][0] + box1Size.z * absBox2ToBox1[1][0] + + box2Size.y * absBox2ToBox1[0][2] + box2Size.z * absBox2ToBox1[0][1]; + originProjection = FloatMakePositive( -box2Origin.y * box2ToBox1[2][0] + box2Origin.z * box2ToBox1[1][0] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 0, tmp ); + CrossProduct( worldToBox1[0], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e1 x b2e2 + if ( absBox2ToBox1[0][1] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.y * absBox2ToBox1[2][1] + box1Size.z * absBox2ToBox1[1][1] + + box2Size.x * absBox2ToBox1[0][2] + box2Size.z * absBox2ToBox1[0][0]; + originProjection = FloatMakePositive( -box2Origin.y * box2ToBox1[2][1] + box2Origin.z * box2ToBox1[1][1] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 1, tmp ); + CrossProduct( worldToBox1[0], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e1 x b2e3 + if ( absBox2ToBox1[0][2] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.y * absBox2ToBox1[2][2] + box1Size.z * absBox2ToBox1[1][2] + + box2Size.x * absBox2ToBox1[0][1] + box2Size.y * absBox2ToBox1[0][0]; + originProjection = FloatMakePositive( -box2Origin.y * box2ToBox1[2][2] + box2Origin.z * box2ToBox1[1][2] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 2, tmp ); + CrossProduct( worldToBox1[0], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e2 x b2e1 + if ( absBox2ToBox1[1][0] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.x * absBox2ToBox1[2][0] + box1Size.z * absBox2ToBox1[0][0] + + box2Size.y * absBox2ToBox1[1][2] + box2Size.z * absBox2ToBox1[1][1]; + originProjection = FloatMakePositive( box2Origin.x * box2ToBox1[2][0] - box2Origin.z * box2ToBox1[0][0] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 0, tmp ); + CrossProduct( worldToBox1[1], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e2 x b2e2 + if ( absBox2ToBox1[1][1] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.x * absBox2ToBox1[2][1] + box1Size.z * absBox2ToBox1[0][1] + + box2Size.x * absBox2ToBox1[1][2] + box2Size.z * absBox2ToBox1[1][0]; + originProjection = FloatMakePositive( box2Origin.x * box2ToBox1[2][1] - box2Origin.z * box2ToBox1[0][1] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 1, tmp ); + CrossProduct( worldToBox1[1], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e2 x b2e3 + if ( absBox2ToBox1[1][2] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.x * absBox2ToBox1[2][2] + box1Size.z * absBox2ToBox1[0][2] + + box2Size.x * absBox2ToBox1[1][1] + box2Size.y * absBox2ToBox1[1][0]; + originProjection = FloatMakePositive( box2Origin.x * box2ToBox1[2][2] - box2Origin.z * box2ToBox1[0][2] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 2, tmp ); + CrossProduct( worldToBox1[1], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e3 x b2e1 + if ( absBox2ToBox1[2][0] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.x * absBox2ToBox1[1][0] + box1Size.y * absBox2ToBox1[0][0] + + box2Size.y * absBox2ToBox1[2][2] + box2Size.z * absBox2ToBox1[2][1]; + originProjection = FloatMakePositive( -box2Origin.x * box2ToBox1[1][0] + box2Origin.y * box2ToBox1[0][0] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 0, tmp ); + CrossProduct( worldToBox1[2], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e3 x b2e2 + if ( absBox2ToBox1[2][1] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.x * absBox2ToBox1[1][1] + box1Size.y * absBox2ToBox1[0][1] + + box2Size.x * absBox2ToBox1[2][2] + box2Size.z * absBox2ToBox1[2][0]; + originProjection = FloatMakePositive( -box2Origin.x * box2ToBox1[1][1] + box2Origin.y * box2ToBox1[0][1] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 1, tmp ); + CrossProduct( worldToBox1[2], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + + // b1e3 x b2e3 + if ( absBox2ToBox1[2][2] < 1.0f - 1e-3f ) + { + boxProjectionSum = + box1Size.x * absBox2ToBox1[1][2] + box1Size.y * absBox2ToBox1[0][2] + + box2Size.x * absBox2ToBox1[2][1] + box2Size.y * absBox2ToBox1[2][0]; + originProjection = FloatMakePositive( -box2Origin.x * box2ToBox1[1][2] + box2Origin.y * box2ToBox1[0][2] ) + tolerance; + if ( FloatBits(originProjection) > FloatBits(boxProjectionSum) ) + { + MatrixGetColumn( box2ToWorld, 2, tmp ); + CrossProduct( worldToBox1[2], tmp.Base(), pPlane->normal.Base() ); + return true; + } + } + return false; +} + + +//----------------------------------------------------------------------------- +// Compute a separating plane between two boxes (expensive!) +// Returns false if no separating plane exists +//----------------------------------------------------------------------------- +bool ComputeSeparatingPlane( const Vector& org1, const QAngle& angles1, const Vector& min1, const Vector& max1, + const Vector& org2, const QAngle& angles2, const Vector& min2, const Vector& max2, + float tolerance, cplane_t* pPlane ) +{ + matrix3x4_t worldToBox1, box2ToWorld; + ComputeCenterIMatrix( org1, angles1, min1, max1, worldToBox1 ); + ComputeCenterMatrix( org2, angles2, min2, max2, box2ToWorld ); + + // Then compute the size of the two boxes + Vector box1Size, box2Size; + VectorSubtract( max1, min1, box1Size ); + VectorSubtract( max2, min2, box2Size ); + box1Size *= 0.5f; + box2Size *= 0.5f; + + return ComputeSeparatingPlane( worldToBox1, box2ToWorld, box1Size, box2Size, tolerance, pPlane ); +} + + +//----------------------------------------------------------------------------- +// Swept OBB test +//----------------------------------------------------------------------------- +bool IsRayIntersectingOBB( const Ray_t &ray, const Vector& org, const QAngle& angles, + const Vector& mins, const Vector& maxs ) +{ + if ( angles == vec3_angle ) + { + Vector vecWorldMins, vecWorldMaxs; + VectorAdd( org, mins, vecWorldMins ); + VectorAdd( org, maxs, vecWorldMaxs ); + return IsBoxIntersectingRay( vecWorldMins, vecWorldMaxs, ray ); + } + + if ( ray.m_IsRay ) + { + matrix3x4_t worldToBox; + AngleIMatrix( angles, org, worldToBox ); + + Ray_t rotatedRay; + VectorTransform( ray.m_Start, worldToBox, rotatedRay.m_Start ); + VectorRotate( ray.m_Delta, worldToBox, rotatedRay.m_Delta ); + rotatedRay.m_StartOffset = vec3_origin; + rotatedRay.m_Extents = vec3_origin; + rotatedRay.m_IsRay = ray.m_IsRay; + rotatedRay.m_IsSwept = ray.m_IsSwept; + + return IsBoxIntersectingRay( mins, maxs, rotatedRay ); + } + + if ( !ray.m_IsSwept ) + { + cplane_t plane; + return ComputeSeparatingPlane( ray.m_Start, vec3_angle, -ray.m_Extents, ray.m_Extents, + org, angles, mins, maxs, 0.0f, &plane ) == false; + } + + // NOTE: See the comments in ComputeSeparatingPlane to understand this math + + // First, compute the basis of box in the space of the ray + // NOTE: These basis place the origin at the centroid of each box! + matrix3x4_t worldToBox1, box2ToWorld; + ComputeCenterMatrix( org, angles, mins, maxs, box2ToWorld ); + + // Find the center + extents of an AABB surrounding the ray + Vector vecRayCenter; + VectorMA( ray.m_Start, 0.5, ray.m_Delta, vecRayCenter ); + vecRayCenter *= -1.0f; + SetIdentityMatrix( worldToBox1 ); + MatrixSetColumn( vecRayCenter, 3, worldToBox1 ); + + Vector box1Size; + box1Size.x = ray.m_Extents.x + FloatMakePositive( ray.m_Delta.x ) * 0.5f; + box1Size.y = ray.m_Extents.y + FloatMakePositive( ray.m_Delta.y ) * 0.5f; + box1Size.z = ray.m_Extents.z + FloatMakePositive( ray.m_Delta.z ) * 0.5f; + + // Then compute the size of the box + Vector box2Size; + VectorSubtract( maxs, mins, box2Size ); + box2Size *= 0.5f; + + // Do an OBB test of the box with the AABB surrounding the ray + cplane_t plane; + if ( ComputeSeparatingPlane( worldToBox1, box2ToWorld, box1Size, box2Size, 0.0f, &plane ) ) + return false; + + // Now deal with the planes which are the cross products of the ray sweep direction vs box edges + Vector vecRayDirection = ray.m_Delta; + VectorNormalize( vecRayDirection ); + + // Need a vector between ray center vs box center measured in the space of the ray (world) + Vector vecCenterDelta; + vecCenterDelta.x = box2ToWorld[0][3] - ray.m_Start.x; + vecCenterDelta.y = box2ToWorld[1][3] - ray.m_Start.y; + vecCenterDelta.z = box2ToWorld[2][3] - ray.m_Start.z; + + // Rotate the ray direction into the space of the OBB + Vector vecAbsRayDirBox2; + VectorIRotate( vecRayDirection, box2ToWorld, vecAbsRayDirBox2 ); + + // Make abs versions of the ray in world space + ray in box2 space + VectorAbs( vecAbsRayDirBox2, vecAbsRayDirBox2 ); + + // Now do the work for the planes which are perpendicular to the edges of the AABB + // and the sweep direction edges... + + // In this example, the line to check is perpendicular to box edge x + ray delta + // we can compute this line by taking the cross-product: + // + // [ i j k ] + // [ 1 0 0 ] = - dz j + dy k = l1 + // [ dx dy dz ] + + // Where dx, dy, dz is the ray delta (normalized) + + // The projection of the box onto this line = the absolute dot product of the box size + // against the line, which = + // AbsDot( vecBoxHalfDiagonal, l1 ) = abs( -dz * vecBoxHalfDiagonal.y ) + abs( dy * vecBoxHalfDiagonal.z ) + + // Because the plane contains the sweep direction, the sweep will produce + // no extra projection onto the line normal to the plane. + // Therefore all we need to do is project the ray extents onto this line also: + // AbsDot( ray.m_Extents, l1 ) = abs( -dz * ray.m_Extents.y ) + abs( dy * ray.m_Extents.z ) + + Vector vecPlaneNormal; + + // box x x ray delta + CrossProduct( vecRayDirection, Vector( box2ToWorld[0][0], box2ToWorld[1][0], box2ToWorld[2][0] ), vecPlaneNormal ); + float flCenterDeltaProjection = FloatMakePositive( DotProduct( vecPlaneNormal, vecCenterDelta ) ); + float flBoxProjectionSum = + vecAbsRayDirBox2.z * box2Size.y + vecAbsRayDirBox2.y * box2Size.z + + DotProductAbs( vecPlaneNormal, ray.m_Extents ); + if ( FloatBits(flCenterDeltaProjection) > FloatBits(flBoxProjectionSum) ) + return false; + + // box y x ray delta + CrossProduct( vecRayDirection, Vector( box2ToWorld[0][1], box2ToWorld[1][1], box2ToWorld[2][1] ), vecPlaneNormal ); + flCenterDeltaProjection = FloatMakePositive( DotProduct( vecPlaneNormal, vecCenterDelta ) ); + flBoxProjectionSum = + vecAbsRayDirBox2.z * box2Size.x + vecAbsRayDirBox2.x * box2Size.z + + DotProductAbs( vecPlaneNormal, ray.m_Extents ); + if ( FloatBits(flCenterDeltaProjection) > FloatBits(flBoxProjectionSum) ) + return false; + + // box z x ray delta + CrossProduct( vecRayDirection, Vector( box2ToWorld[0][2], box2ToWorld[1][2], box2ToWorld[2][2] ), vecPlaneNormal ); + flCenterDeltaProjection = FloatMakePositive( DotProduct( vecPlaneNormal, vecCenterDelta ) ); + flBoxProjectionSum = + vecAbsRayDirBox2.y * box2Size.x + vecAbsRayDirBox2.x * box2Size.y + + DotProductAbs( vecPlaneNormal, ray.m_Extents ); + if ( FloatBits(flCenterDeltaProjection) > FloatBits(flBoxProjectionSum) ) + return false; + + return true; +} + +//-------------------------------------------------------------------------- +// Purpose: +// +// NOTE: +// triangle points are given in clockwise order (aabb-triangle test) +// +// 1 edge0 = 1 - 0 +// | \ edge1 = 2 - 1 +// | \ edge2 = 0 - 2 +// | \ . +// | \ . +// 0-----2 . +// +//-------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Purpose: find the minima and maxima of the 3 given values +//----------------------------------------------------------------------------- +inline void FindMinMax( float v1, float v2, float v3, float &min, float &max ) +{ + min = max = v1; + if ( v2 < min ) { min = v2; } + if ( v2 > max ) { max = v2; } + if ( v3 < min ) { min = v3; } + if ( v3 > max ) { max = v3; } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool AxisTestEdgeCrossX2( float flEdgeZ, float flEdgeY, float flAbsEdgeZ, float flAbsEdgeY, + const Vector &p1, const Vector &p3, const Vector &vecExtents, + float flTolerance ) +{ + // Cross Product( axialX(1,0,0) x edge ): x = 0.0f, y = edge.z, z = -edge.y + // Triangle Point Distances: dist(x) = normal.y * pt(x).y + normal.z * pt(x).z + float flDist1 = flEdgeZ * p1.y - flEdgeY * p1.z; + float flDist3 = flEdgeZ * p3.y - flEdgeY * p3.z; + + // Extents are symmetric: dist = abs( normal.y ) * extents.y + abs( normal.z ) * extents.z + float flDistBox = flAbsEdgeZ * vecExtents.y + flAbsEdgeY * vecExtents.z; + + // Either dist1, dist3 is the closest point to the box, determine which and test of overlap with box(AABB). + if ( flDist1 < flDist3 ) + { + if ( ( flDist1 > ( flDistBox + flTolerance ) ) || ( flDist3 < -( flDistBox + flTolerance ) ) ) + return false; + } + else + { + if ( ( flDist3 > ( flDistBox + flTolerance ) ) || ( flDist1 < -( flDistBox + flTolerance ) ) ) + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +// Purpose: +//-------------------------------------------------------------------------- +inline bool AxisTestEdgeCrossX3( float flEdgeZ, float flEdgeY, float flAbsEdgeZ, float flAbsEdgeY, + const Vector &p1, const Vector &p2, const Vector &vecExtents, + float flTolerance ) +{ + // Cross Product( axialX(1,0,0) x edge ): x = 0.0f, y = edge.z, z = -edge.y + // Triangle Point Distances: dist(x) = normal.y * pt(x).y + normal.z * pt(x).z + float flDist1 = flEdgeZ * p1.y - flEdgeY * p1.z; + float flDist2 = flEdgeZ * p2.y - flEdgeY * p2.z; + + // Extents are symmetric: dist = abs( normal.y ) * extents.y + abs( normal.z ) * extents.z + float flDistBox = flAbsEdgeZ * vecExtents.y + flAbsEdgeY * vecExtents.z; + + // Either dist1, dist2 is the closest point to the box, determine which and test of overlap with box(AABB). + if ( flDist1 < flDist2 ) + { + if ( ( flDist1 > ( flDistBox + flTolerance ) ) || ( flDist2 < -( flDistBox + flTolerance ) ) ) + return false; + } + else + { + if ( ( flDist2 > ( flDistBox + flTolerance ) ) || ( flDist1 < -( flDistBox + flTolerance ) ) ) + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +inline bool AxisTestEdgeCrossY2( float flEdgeZ, float flEdgeX, float flAbsEdgeZ, float flAbsEdgeX, + const Vector &p1, const Vector &p3, const Vector &vecExtents, + float flTolerance ) +{ + // Cross Product( axialY(0,1,0) x edge ): x = -edge.z, y = 0.0f, z = edge.x + // Triangle Point Distances: dist(x) = normal.x * pt(x).x + normal.z * pt(x).z + float flDist1 = -flEdgeZ * p1.x + flEdgeX * p1.z; + float flDist3 = -flEdgeZ * p3.x + flEdgeX * p3.z; + + // Extents are symmetric: dist = abs( normal.x ) * extents.x + abs( normal.z ) * extents.z + float flDistBox = flAbsEdgeZ * vecExtents.x + flAbsEdgeX * vecExtents.z; + + // Either dist1, dist3 is the closest point to the box, determine which and test of overlap with box(AABB). + if ( flDist1 < flDist3 ) + { + if ( ( flDist1 > ( flDistBox + flTolerance ) ) || ( flDist3 < -( flDistBox + flTolerance ) ) ) + return false; + } + else + { + if ( ( flDist3 > ( flDistBox + flTolerance ) ) || ( flDist1 < -( flDistBox + flTolerance ) ) ) + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +inline bool AxisTestEdgeCrossY3( float flEdgeZ, float flEdgeX, float flAbsEdgeZ, float flAbsEdgeX, + const Vector &p1, const Vector &p2, const Vector &vecExtents, + float flTolerance ) +{ + // Cross Product( axialY(0,1,0) x edge ): x = -edge.z, y = 0.0f, z = edge.x + // Triangle Point Distances: dist(x) = normal.x * pt(x).x + normal.z * pt(x).z + float flDist1 = -flEdgeZ * p1.x + flEdgeX * p1.z; + float flDist2 = -flEdgeZ * p2.x + flEdgeX * p2.z; + + // Extents are symmetric: dist = abs( normal.x ) * extents.x + abs( normal.z ) * extents.z + float flDistBox = flAbsEdgeZ * vecExtents.x + flAbsEdgeX * vecExtents.z; + + // Either dist1, dist2 is the closest point to the box, determine which and test of overlap with box(AABB). + if ( flDist1 < flDist2 ) + { + if ( ( flDist1 > ( flDistBox + flTolerance ) ) || ( flDist2 < -( flDistBox + flTolerance ) ) ) + return false; + } + else + { + if ( ( flDist2 > ( flDistBox + flTolerance ) ) || ( flDist1 < -( flDistBox + flTolerance ) ) ) + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +inline bool AxisTestEdgeCrossZ1( float flEdgeY, float flEdgeX, float flAbsEdgeY, float flAbsEdgeX, + const Vector &p2, const Vector &p3, const Vector &vecExtents, + float flTolerance ) +{ + // Cross Product( axialZ(0,0,1) x edge ): x = edge.y, y = -edge.x, z = 0.0f + // Triangle Point Distances: dist(x) = normal.x * pt(x).x + normal.y * pt(x).y + float flDist2 = flEdgeY * p2.x - flEdgeX * p2.y; + float flDist3 = flEdgeY * p3.x - flEdgeX * p3.y; + + // Extents are symmetric: dist = abs( normal.x ) * extents.x + abs( normal.y ) * extents.y + float flDistBox = flAbsEdgeY * vecExtents.x + flAbsEdgeX * vecExtents.y; + + // Either dist2, dist3 is the closest point to the box, determine which and test of overlap with box(AABB). + if ( flDist3 < flDist2 ) + { + if ( ( flDist3 > ( flDistBox + flTolerance ) ) || ( flDist2 < -( flDistBox + flTolerance ) ) ) + return false; + } + else + { + if ( ( flDist2 > ( flDistBox + flTolerance ) ) || ( flDist3 < -( flDistBox + flTolerance ) ) ) + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +inline bool AxisTestEdgeCrossZ2( float flEdgeY, float flEdgeX, float flAbsEdgeY, float flAbsEdgeX, + const Vector &p1, const Vector &p3, const Vector &vecExtents, + float flTolerance ) +{ + // Cross Product( axialZ(0,0,1) x edge ): x = edge.y, y = -edge.x, z = 0.0f + // Triangle Point Distances: dist(x) = normal.x * pt(x).x + normal.y * pt(x).y + float flDist1 = flEdgeY * p1.x - flEdgeX * p1.y; + float flDist3 = flEdgeY * p3.x - flEdgeX * p3.y; + + // Extents are symmetric: dist = abs( normal.x ) * extents.x + abs( normal.y ) * extents.y + float flDistBox = flAbsEdgeY * vecExtents.x + flAbsEdgeX * vecExtents.y; + + // Either dist1, dist3 is the closest point to the box, determine which and test of overlap with box(AABB). + if ( flDist1 < flDist3 ) + { + if ( ( flDist1 > ( flDistBox + flTolerance ) ) || ( flDist3 < -( flDistBox + flTolerance ) ) ) + return false; + } + else + { + if ( ( flDist3 > ( flDistBox + flTolerance ) ) || ( flDist1 < -( flDistBox + flTolerance ) ) ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Test for an intersection (overlap) between an axial-aligned bounding +// box (AABB) and a triangle. +// +// Using the "Separating-Axis Theorem" to test for intersections between +// a triangle and an axial-aligned bounding box (AABB). +// 1. 3 Axis Planes - x, y, z +// 2. 9 Edge Planes Tests - the 3 edges of the triangle crossed with all 3 axial +// planes (x, y, z) +// 3. 1 Face Plane - the triangle plane (cplane_t plane below) +// Output: false = separating axis (no intersection) +// true = intersection +//----------------------------------------------------------------------------- +bool IsBoxIntersectingTriangle( const Vector &vecBoxCenter, const Vector &vecBoxExtents, + const Vector &v1, const Vector &v2, const Vector &v3, + const cplane_t &plane, float flTolerance ) +{ + // Test the axial planes (x,y,z) against the min, max of the triangle. + float flMin, flMax; + Vector p1, p2, p3; + + // x plane + p1.x = v1.x - vecBoxCenter.x; + p2.x = v2.x - vecBoxCenter.x; + p3.x = v3.x - vecBoxCenter.x; + FindMinMax( p1.x, p2.x, p3.x, flMin, flMax ); + if ( ( flMin > ( vecBoxExtents.x + flTolerance ) ) || ( flMax < -( vecBoxExtents.x + flTolerance ) ) ) + return false; + + // y plane + p1.y = v1.y - vecBoxCenter.y; + p2.y = v2.y - vecBoxCenter.y; + p3.y = v3.y - vecBoxCenter.y; + FindMinMax( p1.y, p2.y, p3.y, flMin, flMax ); + if ( ( flMin > ( vecBoxExtents.y + flTolerance ) ) || ( flMax < -( vecBoxExtents.y + flTolerance ) ) ) + return false; + + // z plane + p1.z = v1.z - vecBoxCenter.z; + p2.z = v2.z - vecBoxCenter.z; + p3.z = v3.z - vecBoxCenter.z; + FindMinMax( p1.z, p2.z, p3.z, flMin, flMax ); + if ( ( flMin > ( vecBoxExtents.z + flTolerance ) ) || ( flMax < -( vecBoxExtents.z + flTolerance ) ) ) + return false; + + // Test the 9 edge cases. + Vector vecEdge, vecAbsEdge; + + // edge 0 (cross x,y,z) + vecEdge = p2 - p1; + vecAbsEdge.y = FloatMakePositive( vecEdge.y ); + vecAbsEdge.z = FloatMakePositive( vecEdge.z ); + if ( !AxisTestEdgeCrossX2( vecEdge.z, vecEdge.y, vecAbsEdge.z, vecAbsEdge.y, p1, p3, vecBoxExtents, flTolerance ) ) + return false; + + vecAbsEdge.x = FloatMakePositive( vecEdge.x ); + if ( !AxisTestEdgeCrossY2( vecEdge.z, vecEdge.x, vecAbsEdge.z, vecAbsEdge.x, p1, p3, vecBoxExtents, flTolerance ) ) + return false; + + if ( !AxisTestEdgeCrossZ1( vecEdge.y, vecEdge.x, vecAbsEdge.y, vecAbsEdge.x, p2, p3, vecBoxExtents, flTolerance ) ) + return false; + + // edge 1 (cross x,y,z) + vecEdge = p3 - p2; + vecAbsEdge.y = FloatMakePositive( vecEdge.y ); + vecAbsEdge.z = FloatMakePositive( vecEdge.z ); + if ( !AxisTestEdgeCrossX2( vecEdge.z, vecEdge.y, vecAbsEdge.z, vecAbsEdge.y, p1, p2, vecBoxExtents, flTolerance ) ) + return false; + + vecAbsEdge.x = FloatMakePositive( vecEdge.x ); + if ( !AxisTestEdgeCrossY2( vecEdge.z, vecEdge.x, vecAbsEdge.z, vecAbsEdge.x, p1, p2, vecBoxExtents, flTolerance ) ) + return false; + + if ( !AxisTestEdgeCrossZ2( vecEdge.y, vecEdge.x, vecAbsEdge.y, vecAbsEdge.x, p1, p3, vecBoxExtents, flTolerance ) ) + return false; + + // edge 2 (cross x,y,z) + vecEdge = p1 - p3; + vecAbsEdge.y = FloatMakePositive( vecEdge.y ); + vecAbsEdge.z = FloatMakePositive( vecEdge.z ); + if ( !AxisTestEdgeCrossX3( vecEdge.z, vecEdge.y, vecAbsEdge.z, vecAbsEdge.y, p1, p2, vecBoxExtents, flTolerance ) ) + return false; + + vecAbsEdge.x = FloatMakePositive( vecEdge.x ); + if ( !AxisTestEdgeCrossY3( vecEdge.z, vecEdge.x, vecAbsEdge.z, vecAbsEdge.x, p1, p2, vecBoxExtents, flTolerance ) ) + return false; + + if ( !AxisTestEdgeCrossZ1( vecEdge.y, vecEdge.x, vecAbsEdge.y, vecAbsEdge.x, p2, p3, vecBoxExtents, flTolerance ) ) + return false; + + // Test against the triangle face plane. + Vector vecMin, vecMax; + VectorSubtract( vecBoxCenter, vecBoxExtents, vecMin ); + VectorAdd( vecBoxCenter, vecBoxExtents, vecMax ); + if ( BoxOnPlaneSide( vecMin, vecMax, &plane ) != 3 ) + return false; + + return true; +} + +// NOTE: JAY: This is untested code based on Real-time Collision Detection by Ericson +#if 0 +Vector CalcClosestPointOnTriangle( const Vector &P, const Vector &v0, const Vector &v1, const Vector &v2 ) +{ + Vector e0 = v1 - v0; + Vector e1 = v2 - v0; + Vector p0 = P - v0; + + // voronoi region of v0 + float d1 = DotProduct( e0, p0 ); + float d2 = DotProduct( e1, p0 ); + if (d1 <= 0.0f && d2 <= 0.0f) + return v0; + + // voronoi region of v1 + Vector p1 = P - v1; + float d3 = DotProduct( e0, p1 ); + float d4 = DotProduct( e1, p1 ); + if (d3 >=0.0f && d4 <= d3) + return v1; + + // voronoi region of e0 (v0-v1) + float ve2 = d1*d4 - d3*d2; + if ( ve2 <= 0.0f && d1 >= 0.0f && d3 <= 0.0f ) + { + float v = d1 / (d1-d3); + return v0 + v * e0; + } + // voronoi region of v2 + Vector p2 = P - v2; + float d5 = DotProduct( e0, p2 ); + float d6 = DotProduct( e1, p2 ); + if (d6 >= 0.0f && d5 <= d6) + return v2; + // voronoi region of e1 + float ve1 = d5*d2 - d1*d6; + if (ve1 <= 0.0f && d2 >= 0.0f && d6 >= 0.0f) + { + float w = d2 / (d2-d6); + return v0 + w * e1; + } + // voronoi region on e2 + float ve0 = d3*d6 - d5*d4; + if ( ve0 <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f ) + { + float w = (d4-d3)/((d4-d3) + (d5-d6)); + return v1 + w * (v2-v1); + } + // voronoi region of v0v1v2 triangle + float denom = 1.0f / (ve0+ve1+ve2); + float v = ve1*denom; + float w = ve2 * denom; + return v0 + e0 * v + e1 * w; +} +#endif + + +bool OBBHasFullyContainedIntersectionWithQuad( const Vector &vOBBExtent1_Scaled, const Vector &vOBBExtent2_Scaled, const Vector &vOBBExtent3_Scaled, const Vector &ptOBBCenter, + const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter, + const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length, + const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length ) +{ + Vector ptOBB[8]; //this specific ordering helps us web out from a point to its 3 connecting points with some bit math (most importantly, no if's) + ptOBB[0] = ptOBBCenter - vOBBExtent1_Scaled - vOBBExtent2_Scaled - vOBBExtent3_Scaled; + ptOBB[1] = ptOBBCenter - vOBBExtent1_Scaled - vOBBExtent2_Scaled + vOBBExtent3_Scaled; + ptOBB[2] = ptOBBCenter - vOBBExtent1_Scaled + vOBBExtent2_Scaled + vOBBExtent3_Scaled; + ptOBB[3] = ptOBBCenter - vOBBExtent1_Scaled + vOBBExtent2_Scaled - vOBBExtent3_Scaled; + ptOBB[4] = ptOBBCenter + vOBBExtent1_Scaled - vOBBExtent2_Scaled - vOBBExtent3_Scaled; + ptOBB[5] = ptOBBCenter + vOBBExtent1_Scaled - vOBBExtent2_Scaled + vOBBExtent3_Scaled; + ptOBB[6] = ptOBBCenter + vOBBExtent1_Scaled + vOBBExtent2_Scaled + vOBBExtent3_Scaled; + ptOBB[7] = ptOBBCenter + vOBBExtent1_Scaled + vOBBExtent2_Scaled - vOBBExtent3_Scaled; + + float fDists[8]; + for( int i = 0; i != 8; ++i ) + fDists[i] = vQuadNormal.Dot( ptOBB[i] ) - fQuadPlaneDist; + + int iSides[8]; + int iSideMask = 0; + for( int i = 0; i != 8; ++i ) + { + if( fDists[i] > 0.0f ) + { + iSides[i] = 1; + iSideMask |= 1; + } + else + { + iSides[i] = 2; + iSideMask |= 2; + } + } + + if( iSideMask != 3 ) //points reside entirely on one side of the quad's plane + return false; + + Vector ptPlaneIntersections[12]; //only have 12 lines, can only possibly generate 12 split points + int iPlaneIntersectionsCount = 0; + + for( int i = 0; i != 8; ++i ) + { + if( iSides[i] == 2 ) //point behind the plane + { + int iAxisCrossings[3]; + iAxisCrossings[0] = i ^ 4; //upper 4 vs lower 4 crosses vOBBExtent1 axis + iAxisCrossings[1] = ((i + 1) & 3) + (i & 4); //cycle to the next element while staying within the upper 4 or lower 4, this will cross either vOBBExtent2 or vOBBExtent3 axis, we don't care which + iAxisCrossings[2] = ((i - 1) & 3) + (i & 4); //cylce to the previous element while staying within the upper 4 or lower 4, this will cross the axis iAxisCrossings[1] didn't cross + + for( int j = 0; j != 3; ++j ) + { + if( iSides[iAxisCrossings[j]] == 1 ) //point in front of the plane + { + //line between ptOBB[i] and ptOBB[iAxisCrossings[j]] intersects the plane, generate a point at the intersection for further testing + float fTotalDist = fDists[iAxisCrossings[j]] - fDists[i]; //remember that fDists[i] is a negative value + ptPlaneIntersections[iPlaneIntersectionsCount] = (ptOBB[iAxisCrossings[j]] * (-fDists[i]/fTotalDist)) + (ptOBB[i] * (fDists[iAxisCrossings[j]]/fTotalDist)); + + Assert( fabs( ptPlaneIntersections[iPlaneIntersectionsCount].Dot( vQuadNormal ) - fQuadPlaneDist ) < 0.1f ); //intersection point is on plane + + ++iPlaneIntersectionsCount; + } + } + } + } + + Assert( iPlaneIntersectionsCount != 0 ); + + for( int i = 0; i != iPlaneIntersectionsCount; ++i ) + { + //these points are guaranteed to be on the plane, now just check to see if they're within the quad's extents + Vector vToPointFromQuadCenter = ptPlaneIntersections[i] - ptQuadCenter; + + float fExt1Dist = vQuadExtent1_Normalized.Dot( vToPointFromQuadCenter ); + if( fabs( fExt1Dist ) > fQuadExtent1Length ) + return false; //point is outside boundaries + + //vToPointFromQuadCenter -= vQuadExtent1_Normalized * fExt1Dist; //to handle diamond shaped quads + + float fExt2Dist = vQuadExtent2_Normalized.Dot( vToPointFromQuadCenter ); + if( fabs( fExt2Dist ) > fQuadExtent2Length ) + return false; //point is outside boundaries + } + + return true; //there were lines crossing the quad plane, and every line crossing that plane had its intersection with the plane within the quad's boundaries +} + +//----------------------------------------------------------------------------- +// Compute if the Ray intersects the quad plane, and whether the entire +// Ray/Quad intersection is contained within the quad itself +// +// False if no intersection exists, or if part of the intersection is +// outside the quad's extents +//----------------------------------------------------------------------------- +bool RayHasFullyContainedIntersectionWithQuad( const Ray_t &ray, + const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter, + const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length, + const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length ) +{ + Vector ptPlaneIntersections[(12 + 12 + 8)]; //absolute max possible: 12 lines to connect the start box, 12 more to connect the end box, 8 to connect the boxes to eachother + + //8 points to make an AABB, 8 lines to connect each point from it's start to end point along the ray, 8 possible intersections + int iPlaneIntersectionsCount = 0; + + if( ray.m_IsRay ) + { + //just 1 line + if( ray.m_IsSwept ) + { + Vector ptEndPoints[2]; + ptEndPoints[0] = ray.m_Start; + ptEndPoints[1] = ptEndPoints[0] + ray.m_Delta; + + int i; + float fDists[2]; + for( i = 0; i != 2; ++i ) + fDists[i] = vQuadNormal.Dot( ptEndPoints[i] ) - fQuadPlaneDist; + + for( i = 0; i != 2; ++i ) + { + if( fDists[i] <= 0.0f ) + { + int j = 1-i; + if( fDists[j] >= 0.0f ) + { + float fInvTotalDist = 1.0f / (fDists[j] - fDists[i]); //fDists[i] <= 0, ray is swept so no chance that the denom was 0 + ptPlaneIntersections[0] = (ptEndPoints[i] * (fDists[j] * fInvTotalDist)) - (ptEndPoints[j] * (fDists[i] * fInvTotalDist)); //fDists[i] <= 0 + Assert( fabs( ptPlaneIntersections[iPlaneIntersectionsCount].Dot( vQuadNormal ) - fQuadPlaneDist ) < 0.1f ); //intersection point is on plane + iPlaneIntersectionsCount = 1; + } + else + { + return false; + } + break; + } + } + + if( i == 2 ) + return false; + } + else //not swept, so this is actually a point on quad question + { + if( fabs( vQuadNormal.Dot( ray.m_Start ) - fQuadPlaneDist ) < 1e-6 ) + { + ptPlaneIntersections[0] = ray.m_Start; + iPlaneIntersectionsCount = 1; + } + else + { + return false; + } + } + } + else + { + Vector ptEndPoints[2][8]; + //this specific ordering helps us web out from a point to its 3 connecting points with some bit math (most importantly, no if's) + ptEndPoints[0][0] = ray.m_Start; ptEndPoints[0][0].x -= ray.m_Extents.x; ptEndPoints[0][0].y -= ray.m_Extents.y; ptEndPoints[0][0].z -= ray.m_Extents.z; + ptEndPoints[0][1] = ray.m_Start; ptEndPoints[0][1].x -= ray.m_Extents.x; ptEndPoints[0][1].y -= ray.m_Extents.y; ptEndPoints[0][1].z += ray.m_Extents.z; + ptEndPoints[0][2] = ray.m_Start; ptEndPoints[0][2].x -= ray.m_Extents.x; ptEndPoints[0][2].y += ray.m_Extents.y; ptEndPoints[0][2].z += ray.m_Extents.z; + ptEndPoints[0][3] = ray.m_Start; ptEndPoints[0][3].x -= ray.m_Extents.x; ptEndPoints[0][3].y += ray.m_Extents.y; ptEndPoints[0][3].z -= ray.m_Extents.z; + ptEndPoints[0][4] = ray.m_Start; ptEndPoints[0][4].x += ray.m_Extents.x; ptEndPoints[0][4].y -= ray.m_Extents.y; ptEndPoints[0][4].z -= ray.m_Extents.z; + ptEndPoints[0][5] = ray.m_Start; ptEndPoints[0][5].x += ray.m_Extents.x; ptEndPoints[0][5].y -= ray.m_Extents.y; ptEndPoints[0][5].z += ray.m_Extents.z; + ptEndPoints[0][6] = ray.m_Start; ptEndPoints[0][6].x += ray.m_Extents.x; ptEndPoints[0][6].y += ray.m_Extents.y; ptEndPoints[0][6].z += ray.m_Extents.z; + ptEndPoints[0][7] = ray.m_Start; ptEndPoints[0][7].x += ray.m_Extents.x; ptEndPoints[0][7].y += ray.m_Extents.y; ptEndPoints[0][7].z -= ray.m_Extents.z; + + float fDists[2][8]; + int iSides[2][8]; + int iSideMask[2] = { 0, 0 }; + for( int i = 0; i != 8; ++i ) + { + fDists[0][i] = vQuadNormal.Dot( ptEndPoints[0][i] ) - fQuadPlaneDist; + if( fDists[0][i] > 0.0f ) + { + iSides[0][i] = 1; + iSideMask[0] |= 1; + } + else + { + iSides[0][i] = 2; + iSideMask[0] |= 2; + } + } + + if( ray.m_IsSwept ) + { + for( int i = 0; i != 8; ++i ) + ptEndPoints[1][i] = ptEndPoints[0][i] + ray.m_Delta; + + for( int i = 0; i != 8; ++i ) + { + fDists[1][i] = vQuadNormal.Dot( ptEndPoints[1][i] ) - fQuadPlaneDist; + if( fDists[1][i] > 0.0f ) + { + iSides[1][i] = 1; + iSideMask[1] |= 1; + } + else + { + iSides[1][i] = 2; + iSideMask[1] |= 2; + } + } + } + + if( (iSideMask[0] | iSideMask[1]) != 3 ) + { + //Assert( (iSideMask[0] | iSideMask[1]) != 2 ); + return false; //all points resides entirely on one side of the quad + } + + + //generate intersections for boxes split by the plane at either end of the ray + for( int k = 0; k != 2; ++k ) + { + if( iSideMask[k] == 3 ) //box is split by the plane + { + for( int i = 0; i != 8; ++i ) + { + if( iSides[k][i] == 2 ) //point behind the plane + { + int iAxisCrossings[3]; + iAxisCrossings[0] = i ^ 4; //upper 4 vs lower 4 crosses X axis + iAxisCrossings[1] = ((i + 1) & 3) + (i & 4); //cycle to the next element while staying within the upper 4 or lower 4, this will cross either Y or Z axis, we don't care which + iAxisCrossings[2] = ((i - 1) & 3) + (i & 4); //cylce to the previous element while staying within the upper 4 or lower 4, this will cross the axis iAxisCrossings[1] didn't cross + + for( int j = 0; j != 3; ++j ) + { + if( iSides[k][iAxisCrossings[j]] == 1 ) //point in front of the plane + { + //line between ptEndPoints[i] and ptEndPoints[iAxisCrossings[j]] intersects the plane, generate a point at the intersection for further testing + float fInvTotalDist = 1.0f / (fDists[k][iAxisCrossings[j]] - fDists[k][i]); //remember that fDists[k][i] is a negative value + ptPlaneIntersections[iPlaneIntersectionsCount] = (ptEndPoints[k][iAxisCrossings[j]] * (-fDists[k][i] * fInvTotalDist)) + (ptEndPoints[k][i] * (fDists[k][iAxisCrossings[j]] * fInvTotalDist)); + + Assert( fabs( ptPlaneIntersections[iPlaneIntersectionsCount].Dot( vQuadNormal ) - fQuadPlaneDist ) < 0.1f ); //intersection point is on plane + + ++iPlaneIntersectionsCount; + } + } + } + } + } + } + + if( ray.m_IsSwept ) + { + for( int i = 0; i != 8; ++i ) + { + if( iSides[0][i] != iSides[1][i] ) + { + int iPosSide, iNegSide; + if( iSides[0][i] == 1 ) + { + iPosSide = 0; + iNegSide = 1; + } + else + { + iPosSide = 1; + iNegSide = 0; + } + + Assert( (fDists[iPosSide][i] >= 0.0f) && (fDists[iNegSide][i] <= 0.0f) ); + + float fInvTotalDist = 1.0f / (fDists[iPosSide][i] - fDists[iNegSide][i]); //remember that fDists[iNegSide][i] is a negative value + ptPlaneIntersections[iPlaneIntersectionsCount] = (ptEndPoints[iPosSide][i] * (-fDists[iNegSide][i] * fInvTotalDist)) + (ptEndPoints[iNegSide][i] * (fDists[iPosSide][i] * fInvTotalDist)); + + Assert( fabs( ptPlaneIntersections[iPlaneIntersectionsCount].Dot( vQuadNormal ) - fQuadPlaneDist ) < 0.1f ); //intersection point is on plane + + ++iPlaneIntersectionsCount; + } + } + } + } + + //down here, we should simply have a collection of plane intersections, now we see if they reside within the quad + Assert( iPlaneIntersectionsCount != 0 ); + + for( int i = 0; i != iPlaneIntersectionsCount; ++i ) + { + //these points are guaranteed to be on the plane, now just check to see if they're within the quad's extents + Vector vToPointFromQuadCenter = ptPlaneIntersections[i] - ptQuadCenter; + + float fExt1Dist = vQuadExtent1_Normalized.Dot( vToPointFromQuadCenter ); + if( fabs( fExt1Dist ) > fQuadExtent1Length ) + return false; //point is outside boundaries + + //vToPointFromQuadCenter -= vQuadExtent1_Normalized * fExt1Dist; //to handle diamond shaped quads + + float fExt2Dist = vQuadExtent2_Normalized.Dot( vToPointFromQuadCenter ); + if( fabs( fExt2Dist ) > fQuadExtent2Length ) + return false; //point is outside boundaries + } + + return true; //there were lines crossing the quad plane, and every line crossing that plane had its intersection with the plane within the quad's boundaries +} + +#endif // !_STATIC_LINKED || _SHARED_LIB diff --git a/public/collisionutils.h b/public/collisionutils.h new file mode 100644 index 0000000..50f8704 --- /dev/null +++ b/public/collisionutils.h @@ -0,0 +1,450 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Common collision utility methods +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef COLLISIONUTILS_H +#define COLLISIONUTILS_H + +#include "tier0/platform.h" + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/ssemath.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +struct Ray_t; +class Vector; +class Vector2D; +class Vector4D; +struct cplane_t; +class QAngle; +class CBaseTrace; +struct matrix3x4_t; + + +//----------------------------------------------------------------------------- +// +// IntersectRayWithTriangle +// +// Intersects a ray with a triangle, returns distance t along ray. +// t will be less than zero if no intersection occurred +// oneSided will cull collisions which approach the triangle from the back +// side, assuming the vertices are specified in counter-clockwise order +// The vertices need not be specified in that order if oneSided is not used +// +//----------------------------------------------------------------------------- +float IntersectRayWithTriangle( const Ray_t& ray, + const Vector& v1, const Vector& v2, const Vector& v3, + bool oneSided ); + +//----------------------------------------------------------------------------- +// +// ComputeIntersectionBarycentricCoordinates +// +// Figures out the barycentric coordinates (u,v) where a ray hits a +// triangle. Note that this will ignore the ray extents, and it also ignores +// the ray length. Note that the edge from v1->v2 represents u (v2: u = 1), +// and the edge from v1->v3 represents v (v3: v = 1). It returns false +// if the ray is parallel to the triangle (or when t is specified if t is less +// than zero). +// +//----------------------------------------------------------------------------- +bool ComputeIntersectionBarycentricCoordinates( const Ray_t& ray, + const Vector& v1, const Vector& v2, const Vector& v3, float& u, float& v, + float *t = 0 ); + +//----------------------------------------------------------------------------- +// +// IntersectRayWithRay +// +// Returns whether or not there was an intersection. The "t" paramter is the +// distance along ray0 and the "s" parameter is the distance along ray1. If +// the two lines to not intersect the "t" and "s" represent the closest approach. +// "t" and "s" will not change if the rays are parallel. +// +//----------------------------------------------------------------------------- +bool IntersectRayWithRay( const Ray_t &ray0, const Ray_t &ray1, float &t, float &s ); + + +//----------------------------------------------------------------------------- +// +// IntersectRayWithSphere +// +// Returns whether or not there was an intersection. Returns the two intersection points. +// NOTE: The point of closest approach can be found at the average t value. +// +//----------------------------------------------------------------------------- +bool IntersectRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 ); + + +//----------------------------------------------------------------------------- +// +// IntersectInfiniteRayWithSphere +// +// Returns whether or not there was an intersection of a sphere against an infinitely +// extending ray. +// Returns the two intersection points +// +//----------------------------------------------------------------------------- +bool IntersectInfiniteRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 ); + + +// returns true if the sphere and cone intersect +// NOTE: cone sine/cosine are the half angle of the cone +bool IsSphereIntersectingCone( const Vector &sphereCenter, float sphereRadius, const Vector &coneOrigin, const Vector &coneNormal, float coneSine, float coneCosine ); + +//----------------------------------------------------------------------------- +// +// IntersectRayWithPlane +// +// Intersects a ray with a plane, returns distance t along ray. +// t will be less than zero the intersection occurs in the opposite direction of the ray. +// +//----------------------------------------------------------------------------- +float IntersectRayWithPlane( const Ray_t& ray, const cplane_t& plane ); +float IntersectRayWithPlane( const Vector& org, const Vector& dir, const cplane_t& plane ); +float IntersectRayWithPlane( const Vector& org, const Vector& dir, const Vector& normal, float dist ); + +// This version intersects a ray with an axis-aligned plane +float IntersectRayWithAAPlane( const Vector& vecStart, const Vector& vecEnd, int nAxis, float flSign, float flDist ); + + +//----------------------------------------------------------------------------- +// IntersectRayWithBox +// +// Purpose: Computes the intersection of a ray with a box (AABB) +// Output : Returns true if there is an intersection + trace information +//----------------------------------------------------------------------------- +bool IntersectRayWithBox( const Vector &rayStart, const Vector &rayDelta, const Vector &boxMins, const Vector &boxMaxs, float epsilon, CBaseTrace *pTrace, float *pFractionLeftSolid = NULL ); +bool IntersectRayWithBox( const Ray_t &ray, const Vector &boxMins, const Vector &boxMaxs, float epsilon, CBaseTrace *pTrace, float *pFractionLeftSolid = NULL ); + +//----------------------------------------------------------------------------- +// Intersects a ray against a box +//----------------------------------------------------------------------------- +struct BoxTraceInfo_t +{ + float t1; + float t2; + int hitside; + bool startsolid; +}; + +bool IntersectRayWithBox( const Vector &vecRayStart, const Vector &vecRayDelta, + const Vector &boxMins, const Vector &boxMaxs, float flTolerance, BoxTraceInfo_t *pTrace ); + + +//----------------------------------------------------------------------------- +// IntersectRayWithOBB +// +// Purpose: Computes the intersection of a ray with a oriented box (OBB) +// Output : Returns true if there is an intersection + trace information +//----------------------------------------------------------------------------- +bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta, + const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs, + float flTolerance, CBaseTrace *pTrace ); + +bool IntersectRayWithOBB( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector &vecBoxOrigin, const QAngle &angBoxRotation, + const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace ); + +bool IntersectRayWithOBB( const Ray_t &ray, const Vector &vecBoxOrigin, const QAngle &angBoxRotation, + const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace ); + +bool IntersectRayWithOBB( const Ray_t &ray, const matrix3x4_t &matOBBToWorld, + const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace ); + +bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta, + const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs, + float flTolerance, BoxTraceInfo_t *pTrace ); + +//----------------------------------------------------------------------------- +// +// IsSphereIntersectingSphere +// +// returns true if there's an intersection between sphere and sphere +// +//----------------------------------------------------------------------------- +bool IsSphereIntersectingSphere( const Vector& center1, float radius1, + const Vector& center2, float radius2 ); + + +//----------------------------------------------------------------------------- +// +// IsBoxIntersectingSphere +// +// returns true if there's an intersection between box and sphere +// +//----------------------------------------------------------------------------- +bool IsBoxIntersectingSphere( const Vector& boxMin, const Vector& boxMax, + const Vector& center, float radius ); + +bool IsBoxIntersectingSphereExtents( const Vector& boxCenter, const Vector& boxHalfDiag, + const Vector& center, float radius ); + +//----------------------------------------------------------------------------- +// returns true if there's an intersection between ray and sphere +//----------------------------------------------------------------------------- +bool IsRayIntersectingSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, + const Vector &vecSphereCenter, float flRadius, float flTolerance = 0.0f ); + + +//----------------------------------------------------------------------------- +// +// IsCircleIntersectingRectangle +// +// returns true if there's an intersection between rectangle and circle +// +//----------------------------------------------------------------------------- +bool IsCircleIntersectingRectangle( const Vector2D& boxMin, const Vector2D& boxMax, + const Vector2D& center, float radius ); + + +//----------------------------------------------------------------------------- +// +// IsBoxIntersectingBox +// +// returns true if there's an intersection between two boxes +// +//----------------------------------------------------------------------------- +bool IsBoxIntersectingBox( const Vector& boxMin1, const Vector& boxMax1, + const Vector& boxMin2, const Vector& boxMax2 ); + +bool IsBoxIntersectingBoxExtents( const Vector& boxCenter1, const Vector& boxHalfDiagonal1, + const Vector& boxCenter2, const Vector& boxHalfDiagonal2 ); + + +#ifdef _X360 +// inline version: +#include "mathlib/ssemath.h" +inline bool IsBoxIntersectingBoxExtents( const fltx4 boxCenter1, const fltx4 boxHalfDiagonal1, + const fltx4 boxCenter2, const fltx4 boxHalfDiagonal2 ); +#endif + +//----------------------------------------------------------------------------- +// +// IsOBBIntersectingOBB +// +// returns true if there's an intersection between two OBBs +// +//----------------------------------------------------------------------------- +bool IsOBBIntersectingOBB( const Vector &vecOrigin1, const QAngle &vecAngles1, const Vector& boxMin1, const Vector& boxMax1, + const Vector &vecOrigin2, const QAngle &vecAngles2, const Vector& boxMin2, const Vector& boxMax2, float flTolerance = 0.0f ); + + +//----------------------------------------------------------------------------- +// +// IsBoxIntersectingRay +// +// returns true if there's an intersection between box and ray +// +//----------------------------------------------------------------------------- + +bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, + const Vector& origin, const Vector& delta, float flTolerance = 0.0f ); + +bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, + const Ray_t& ray, float flTolerance = 0.0f ); + +bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, + const Vector& origin, const Vector& delta, + const Vector& invDelta, float flTolerance = 0.0f ); + + +// On the PC, we can't pass fltx4's in registers like this. On the x360, it is +// much better if we do. +#ifdef _X360 +bool FASTCALL IsBoxIntersectingRay( fltx4 boxMin, fltx4 boxMax, + fltx4 origin, fltx4 delta, fltx4 invDelta, // ray parameters + fltx4 vTolerance = LoadZeroSIMD() ///< eg from ReplicateX4(flTolerance) + ); +#else +bool FASTCALL IsBoxIntersectingRay( const fltx4 &boxMin, const fltx4 &boxMax, + const fltx4 & origin, const fltx4 & delta, const fltx4 & invDelta, // ray parameters + const fltx4 & vTolerance = Four_Zeros ///< eg from ReplicateX4(flTolerance) + ); +#endif + +bool inline FASTCALL IsBoxIntersectingRay( const fltx4& boxMin, const fltx4& boxMax, + const fltx4& origin, const fltx4& delta, float flTolerance = 0.0f ) +{ + return IsBoxIntersectingRay( boxMin, boxMax, origin, delta, ReciprocalSIMD(delta), ReplicateX4(flTolerance) ); +} + + +bool FASTCALL IsBoxIntersectingRay( const fltx4& boxMin, const fltx4& boxMax, + const Ray_t& ray, float flTolerance = 0.0f ); + + + +//----------------------------------------------------------------------------- +// +// IsPointInBox +// +// returns true if the point is in the box +// +//----------------------------------------------------------------------------- +bool IsPointInBox( const Vector& pt, const Vector& boxMin, const Vector& boxMax ); + + +// SIMD version +FORCEINLINE bool IsPointInBox( const fltx4& pt, const fltx4& boxMin, const fltx4& boxMax ) +{ + fltx4 greater = CmpGtSIMD( pt,boxMax ); + fltx4 less = CmpLtSIMD( pt, boxMin ); + return (IsAllZeros(SetWToZeroSIMD(OrSIMD(greater,less)))); +} + + + +//----------------------------------------------------------------------------- +// Purpose: returns true if pt intersects the truncated cone +// origin - cone tip, axis unit cone axis, cosAngle - cosine of cone axis to surface angle +//----------------------------------------------------------------------------- +bool IsPointInCone( const Vector &pt, const Vector &origin, const Vector &axis, float cosAngle, float length ); + +//----------------------------------------------------------------------------- +// Intersects a plane with a triangle (using barycentric definition) +// The return value, in pIntersection, is an array of barycentric coordinates +// describing at most 2 intersection points. +// The return value is the number of intersection points +//----------------------------------------------------------------------------- +int IntersectTriangleWithPlaneBarycentric( const Vector& org, const Vector& edgeU, const Vector& edgeV, + const Vector4D& plane, Vector2D* pIntersection ); + +//----------------------------------------------------------------------------- +// +// PointInQuadBarycentric +// +// Given a point and a quad in a plane return the u and v (barycentric) positions +// of the point relative to the quad. The points (v1,v2,v3,v4) should be given +// in a counter-clockwise order with v1 acting as the primary corner (u=0, v=0). +// Thus, u0 = v2 - v1, and v0 = v4 - v1. +// +//----------------------------------------------------------------------------- + +enum QuadBarycentricRetval_t +{ + BARY_QUADRATIC_FALSE = 0, + BARY_QUADRATIC_TRUE = 1, + BARY_QUADRATIC_NEGATIVE_DISCRIMINANT = 2 +}; + +QuadBarycentricRetval_t PointInQuadToBarycentric( const Vector &v1, const Vector &v2, + const Vector &v3, const Vector &v4, const Vector &point, Vector2D &uv ); + + +void PointInQuadFromBarycentric( const Vector &v1, const Vector &v2, const Vector &v3, const Vector &v4, + const Vector2D &uv, Vector &point ); +void TexCoordInQuadFromBarycentric( const Vector2D &v1, const Vector2D &v2, const Vector2D &v3, const Vector2D &v4, + const Vector2D &uv, Vector2D &texCoord ); + + +//----------------------------------------------------------------------------- +// Compute point from barycentric specification +// Edge u goes from v0 to v1, edge v goes from v0 to v2 +//----------------------------------------------------------------------------- +void ComputePointFromBarycentric( const Vector& v0, const Vector& v1, const Vector& v2, + float u, float v, Vector& pt ); +void ComputePointFromBarycentric( const Vector2D& v0, const Vector2D& v1, const Vector2D& v2, + float u, float v, Vector2D& pt ); + + +//----------------------------------------------------------------------------- +// Swept OBB test +//----------------------------------------------------------------------------- +bool IsRayIntersectingOBB( const Ray_t &ray, const Vector& org, const QAngle& angles, + const Vector& mins, const Vector& maxs ); + + +//----------------------------------------------------------------------------- +// Compute a separating plane between two boxes (expensive!) +// Returns false if no separating plane exists +//----------------------------------------------------------------------------- +bool ComputeSeparatingPlane( const Vector& org1, const QAngle& angles1, const Vector& min1, const Vector& max1, + const Vector& org2, const QAngle& angles2, const Vector& min2, const Vector& max2, + float tolerance, cplane_t* pPlane ); + +//----------------------------------------------------------------------------- +// IsBoxIntersectingTriangle +// +// Test for an intersection (overlap) between an axial-aligned bounding +// box (AABB) and a triangle. +// +// Triangle points are in counter-clockwise order with the normal facing "out." +// +// Using the "Separating-Axis Theorem" to test for intersections between +// a triangle and an axial-aligned bounding box (AABB). +// 1. 3 Axis Plane Tests - x, y, z +// 2. 9 Edge Planes Tests - the 3 edges of the triangle crossed with all 3 axial +// planes (x, y, z) +// 3. 1 Face Plane Test - the plane the triangle resides in (cplane_t plane) +//----------------------------------------------------------------------------- +bool IsBoxIntersectingTriangle( const Vector &vecBoxCenter, const Vector &vecBoxExtents, + const Vector &v1, const Vector &v2, const Vector &v3, + const cplane_t &plane, float flTolerance ); + + +Vector CalcClosestPointOnTriangle( const Vector &P, const Vector &v0, const Vector &v1, const Vector &v2 ); + + +//----------------------------------------------------------------------------- +// Compute if the OBB intersects the quad plane, and whether the entire +// OBB/Quad intersection is contained within the quad itself +// +// False if no intersection exists, or if part of the intersection is +// outside the quad's extents +//----------------------------------------------------------------------------- +bool OBBHasFullyContainedIntersectionWithQuad( const Vector &vOBBExtent1_Scaled, const Vector &vOBBExtent2_Scaled, const Vector &vOBBExtent3_Scaled, const Vector &ptOBBCenter, + const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter, + const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length, + const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length ); + + +//----------------------------------------------------------------------------- +// Compute if the Ray intersects the quad plane, and whether the entire +// Ray/Quad intersection is contained within the quad itself +// +// False if no intersection exists, or if part of the intersection is +// outside the quad's extents +//----------------------------------------------------------------------------- +bool RayHasFullyContainedIntersectionWithQuad( const Ray_t &ray, + const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter, + const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length, + const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length ); + + + +//----------------------------------------------------------------------------- +// INLINES +//----------------------------------------------------------------------------- + + +#ifdef _X360 +inline bool IsBoxIntersectingBoxExtents( const fltx4 boxCenter1, const fltx4 boxHalfDiagonal1, + const fltx4 boxCenter2, const fltx4 boxHalfDiagonal2 ) +{ + fltx4 vecDelta, vecSize; + + vecDelta = SubSIMD(boxCenter1, boxCenter2); + vecSize = AddSIMD(boxHalfDiagonal1, boxHalfDiagonal2); + + uint condition; + XMVectorInBoundsR(&condition, vecDelta, vecSize); + // we want the top three words to be all 1's ; that means in bounds + + + return XMComparisonAllInBounds( condition ); +} +#endif + + +#endif // COLLISIONUTILS_H diff --git a/public/con_nprint.h b/public/con_nprint.h new file mode 100644 index 0000000..8e86652 --- /dev/null +++ b/public/con_nprint.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Debug overlay / notfication printing +// +//=============================================================================// + +#ifndef CON_NPRINT_H +#define CON_NPRINT_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Debug overlay / notfication printing +// NOTE: Structure cannot be changed by mods +//----------------------------------------------------------------------------- +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it disappears. -1 means to display for 1 frame then go away. + float color[ 3 ]; // RGB colors ( 0.0 -> 1.0 scale ) + bool fixed_width_font; +} con_nprint_t; + +// Print string on line idx +void Con_NPrintf( int idx, PRINTF_FORMAT_STRING const char *fmt, ... ); +// Customized printout +void Con_NXPrintf( const con_nprint_t *info, PRINTF_FORMAT_STRING const char *fmt, ... ); + +#endif // CON_NPRINT_H diff --git a/public/const.h b/public/const.h new file mode 100644 index 0000000..0ed97e9 --- /dev/null +++ b/public/const.h @@ -0,0 +1,447 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef CONST_H +#define CONST_H + +#ifdef _WIN32 +#pragma once +#endif + +// the command line param that tells the engine to use steam +#define STEAM_PARM "-steam" +// the command line param to tell dedicated server to restart +// if they are out of date +#define AUTO_RESTART "-autoupdate" + +// the message a server sends when a clients steam login is expired +#define INVALID_STEAM_TICKET "Invalid STEAM UserID Ticket\n" +#define INVALID_STEAM_VACBANSTATE "VAC banned from secure server\n" +#define INVALID_STEAM_LOGGED_IN_ELSEWHERE "This Steam account is being used in another location\n" +#define INVALID_STEAM_LOGON_NOT_CONNECTED "Client not connected to Steam\n" +#define INVALID_STEAM_LOGON_TICKET_CANCELED "Client left game (Steam auth ticket has been canceled)\n" + +#define CLIENTNAME_TIMED_OUT "%s timed out" + +// This is the default, see shareddefs.h for mod-specific value, which can override this +#define DEFAULT_TICK_INTERVAL (0.015) // 15 msec is the default +#define MINIMUM_TICK_INTERVAL (0.001) +#define MAXIMUM_TICK_INTERVAL (0.1) + +// This is the max # of players the engine can handle +#define ABSOLUTE_PLAYER_LIMIT 255 // not 256, so we can send the limit as a byte +#define ABSOLUTE_PLAYER_LIMIT_DW ( (ABSOLUTE_PLAYER_LIMIT/32) + 1 ) + +// a player name may have 31 chars + 0 on the PC. +// the 360 only allows 15 char + 0, but stick with the larger PC size for cross-platform communication +#define MAX_PLAYER_NAME_LENGTH 32 + +#ifdef _X360 +#define MAX_PLAYERS_PER_CLIENT XUSER_MAX_COUNT // Xbox 360 supports 4 players per console +#else +#define MAX_PLAYERS_PER_CLIENT 1 // One player per PC +#endif + +// Max decorated map name, with things like workshop/cp_foo.ugc123456 +#define MAX_MAP_NAME 96 + +// Max name used in save files. Needs to be left at 32 for SourceSDK compatibility. +#define MAX_MAP_NAME_SAVE 32 + +// Max non-decorated map name for e.g. server browser (just cp_foo) +#define MAX_DISPLAY_MAP_NAME 32 + +#define MAX_NETWORKID_LENGTH 64 // num chars for a network (i.e steam) ID + +// BUGBUG: Reconcile with or derive this from the engine's internal definition! +// FIXME: I added an extra bit because I needed to make it signed +#define SP_MODEL_INDEX_BITS 13 + +// How many bits to use to encode an edict. +#define MAX_EDICT_BITS 11 // # of bits needed to represent max edicts +// Max # of edicts in a level +#define MAX_EDICTS (1<movetype values +enum MoveType_t +{ + MOVETYPE_NONE = 0, // never moves + MOVETYPE_ISOMETRIC, // For players -- in TF2 commander view, etc. + MOVETYPE_WALK, // Player only - moving on the ground + MOVETYPE_STEP, // gravity, special edge handling -- monsters use this + MOVETYPE_FLY, // No gravity, but still collides with stuff + MOVETYPE_FLYGRAVITY, // flies through the air + is affected by gravity + MOVETYPE_VPHYSICS, // uses VPHYSICS for simulation + MOVETYPE_PUSH, // no clip to world, push and crush + MOVETYPE_NOCLIP, // No gravity, no collisions, still do velocity/avelocity + MOVETYPE_LADDER, // Used by players only when going onto a ladder + MOVETYPE_OBSERVER, // Observer movement, depends on player's observer mode + MOVETYPE_CUSTOM, // Allows the entity to describe its own physics + + // should always be defined as the last item in the list + MOVETYPE_LAST = MOVETYPE_CUSTOM, + + MOVETYPE_MAX_BITS = 4 +}; + +// edict->movecollide values +enum MoveCollide_t +{ + MOVECOLLIDE_DEFAULT = 0, + + // These ones only work for MOVETYPE_FLY + MOVETYPE_FLYGRAVITY + MOVECOLLIDE_FLY_BOUNCE, // bounces, reflects, based on elasticity of surface and object - applies friction (adjust velocity) + MOVECOLLIDE_FLY_CUSTOM, // Touch() will modify the velocity however it likes + MOVECOLLIDE_FLY_SLIDE, // slides along surfaces (no bounce) - applies friciton (adjusts velocity) + + MOVECOLLIDE_COUNT, // Number of different movecollides + + // When adding new movecollide types, make sure this is correct + MOVECOLLIDE_MAX_BITS = 3 +}; + +// edict->solid values +// NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves +// SOLID only effects OTHER entities colliding with this one when they move - UGH! + +// Solid type basically describes how the bounding volume of the object is represented +// NOTE: SOLID_BBOX MUST BE 2, and SOLID_VPHYSICS MUST BE 6 +// NOTE: These numerical values are used in the FGD by the prop code (see prop_dynamic) +enum SolidType_t +{ + SOLID_NONE = 0, // no solid model + SOLID_BSP = 1, // a BSP tree + SOLID_BBOX = 2, // an AABB + SOLID_OBB = 3, // an OBB (not implemented yet) + SOLID_OBB_YAW = 4, // an OBB, constrained so that it can only yaw + SOLID_CUSTOM = 5, // Always call into the entity for tests + SOLID_VPHYSICS = 6, // solid vphysics object, get vcollide from the model and collide with that + SOLID_LAST, +}; + +enum SolidFlags_t +{ + FSOLID_CUSTOMRAYTEST = 0x0001, // Ignore solid type + always call into the entity for ray tests + FSOLID_CUSTOMBOXTEST = 0x0002, // Ignore solid type + always call into the entity for swept box tests + FSOLID_NOT_SOLID = 0x0004, // Are we currently not solid? + FSOLID_TRIGGER = 0x0008, // This is something may be collideable but fires touch functions + // even when it's not collideable (when the FSOLID_NOT_SOLID flag is set) + FSOLID_NOT_STANDABLE = 0x0010, // You can't stand on this + FSOLID_VOLUME_CONTENTS = 0x0020, // Contains volumetric contents (like water) + FSOLID_FORCE_WORLD_ALIGNED = 0x0040, // Forces the collision rep to be world-aligned even if it's SOLID_BSP or SOLID_VPHYSICS + FSOLID_USE_TRIGGER_BOUNDS = 0x0080, // Uses a special trigger bounds separate from the normal OBB + FSOLID_ROOT_PARENT_ALIGNED = 0x0100, // Collisions are defined in root parent's local coordinate space + FSOLID_TRIGGER_TOUCH_DEBRIS = 0x0200, // This trigger will touch debris objects + + FSOLID_MAX_BITS = 10 +}; + +//----------------------------------------------------------------------------- +// A couple of inline helper methods +//----------------------------------------------------------------------------- +inline bool IsSolid( SolidType_t solidType, int nSolidFlags ) +{ + return (solidType != SOLID_NONE) && ((nSolidFlags & FSOLID_NOT_SOLID) == 0); +} + + +// m_lifeState values +#define LIFE_ALIVE 0 // alive +#define LIFE_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground +#define LIFE_DEAD 2 // dead. lying still. +#define LIFE_RESPAWNABLE 3 +#define LIFE_DISCARDBODY 4 + +// entity effects +enum +{ + EF_BONEMERGE = 0x001, // Performs bone merge on client side + EF_BRIGHTLIGHT = 0x002, // DLIGHT centered at entity origin + EF_DIMLIGHT = 0x004, // player flashlight + EF_NOINTERP = 0x008, // don't interpolate the next frame + EF_NOSHADOW = 0x010, // Don't cast no shadow + EF_NODRAW = 0x020, // don't draw entity + EF_NORECEIVESHADOW = 0x040, // Don't receive no shadow + EF_BONEMERGE_FASTCULL = 0x080, // For use with EF_BONEMERGE. If this is set, then it places this ent's origin at its + // parent and uses the parent's bbox + the max extents of the aiment. + // Otherwise, it sets up the parent's bones every frame to figure out where to place + // the aiment, which is inefficient because it'll setup the parent's bones even if + // the parent is not in the PVS. + EF_ITEM_BLINK = 0x100, // blink an item so that the user notices it. + EF_PARENT_ANIMATES = 0x200, // always assume that the parent entity is animating + EF_MAX_BITS = 10 +}; + +#define EF_PARITY_BITS 3 +#define EF_PARITY_MASK ((1< +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void CheckHeap( void ) +{ +#ifdef USECRTMEMDEBUG + _CrtCheckMemory(); +#endif +} + +// undone: this needs to be somehow made to construct before everything else. +// see http://msdn.microsoft.com/library/periodic/period97/dembugs.htm for info +void InitCRTMemDebug( void ) +{ +#ifdef USECRTMEMDEBUG + _CrtSetDbgFlag( +// _CRTDBG_ALLOC_MEM_DF | + _CRTDBG_CHECK_ALWAYS_DF | + _CRTDBG_CHECK_CRT_DF | + _CRTDBG_DELAY_FREE_MEM_DF ); +#endif +} + +#endif // !_STATIC_LINKED || _SHARED_LIB diff --git a/public/crtmemdebug.h b/public/crtmemdebug.h new file mode 100644 index 0000000..15ed5ff --- /dev/null +++ b/public/crtmemdebug.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CRTMEMDEBUG_H +#define CRTMEMDEBUG_H +#pragma once + +#ifdef USECRTMEMDEBUG + +#include +#define MEMCHECK CheckHeap() +void CheckHeap( void ); + +#else + +#define MEMCHECK + +#endif + +void InitCRTMemDebug( void ); + + +#endif // CRTMEMDEBUG_H diff --git a/public/datacache/idatacache.h b/public/datacache/idatacache.h new file mode 100644 index 0000000..c21937f --- /dev/null +++ b/public/datacache/idatacache.h @@ -0,0 +1,545 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef IDATACACHE_H +#define IDATACACHE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/dbg.h" +#include "appframework/IAppSystem.h" + +class IDataCache; + +//----------------------------------------------------------------------------- +// +// Shared Data Cache API +// +//----------------------------------------------------------------------------- + +#define DATACACHE_INTERFACE_VERSION "VDataCache003" + +//----------------------------------------------------------------------------- +// Support types and enums +//----------------------------------------------------------------------------- + +//--------------------------------------------------------- +// Unique (per section) identifier for a cache item defined by client +//--------------------------------------------------------- +typedef uint32 DataCacheClientID_t; + + +//--------------------------------------------------------- +// Cache-defined handle for a cache item +//--------------------------------------------------------- +FORWARD_DECLARE_HANDLE( memhandle_t ); +typedef memhandle_t DataCacheHandle_t; +#define DC_INVALID_HANDLE ((DataCacheHandle_t)0) + +//--------------------------------------------------------- +// Cache Limits +//--------------------------------------------------------- +struct DataCacheLimits_t +{ + DataCacheLimits_t( unsigned _nMaxBytes = (unsigned)-1, unsigned _nMaxItems = (unsigned)-1, unsigned _nMinBytes = 0, unsigned _nMinItems = 0 ) + : nMaxBytes(_nMaxBytes), + nMaxItems(_nMaxItems), + nMinBytes(_nMinBytes), + nMinItems(_nMinItems) + { + } + + // Maximum levels permitted + unsigned nMaxBytes; + unsigned nMaxItems; + + // Minimum levels permitted + unsigned nMinBytes; + unsigned nMinItems; +}; + +//--------------------------------------------------------- +// Cache status +//--------------------------------------------------------- +struct DataCacheStatus_t +{ + // Current state of the cache + unsigned nBytes; + unsigned nItems; + + unsigned nBytesLocked; + unsigned nItemsLocked; + + // Diagnostics + unsigned nFindRequests; + unsigned nFindHits; +}; + +//--------------------------------------------------------- +// Cache options +//--------------------------------------------------------- +enum DataCacheOptions_t +{ + DC_TRACE_ACTIVITY = (1 << 0), + DC_FORCE_RELOCATE = (1 << 1), + DC_ALWAYS_MISS = (1 << 2), + DC_VALIDATE = (1 << 3), +}; + + +//--------------------------------------------------------- +// Cache report types +//--------------------------------------------------------- +enum DataCacheReportType_t +{ + DC_SUMMARY_REPORT, + DC_DETAIL_REPORT, + DC_DETAIL_REPORT_LRU, +}; + + +//--------------------------------------------------------- +// Notifications to section clients on cache events +//--------------------------------------------------------- +enum DataCacheNotificationType_t +{ + // Used internally to prohibit notifications + DC_NONE, + + // Item is falling off the LRU and should be deleted, return false to block + DC_AGE_DISCARD, + + // Item is being explicitly flushed and should be deleted, return false to block + DC_FLUSH_DISCARD, + + // Item is being explicitly removed and should be deleted. Failure is not an option + DC_REMOVED, + + // Cache is requesting item be relocated for debugging purposes + DC_RELOCATE, + + // Item info should be output to console, return false to accept default handling + DC_PRINT_INF0, +}; + +//------------------------------------- + +struct DataCacheNotification_t +{ + DataCacheNotificationType_t type; + const char * pszSectionName; + DataCacheClientID_t clientId; + const void * pItemData; + unsigned nItemSize; +}; + +//--------------------------------------------------------- + +const int DC_MAX_CLIENT_NAME = 15; +const int DC_MAX_ITEM_NAME = 511; + +//--------------------------------------------------------- +// Result codes +//--------------------------------------------------------- +enum DataCacheRemoveResult_t +{ + DC_OK, + DC_NOT_FOUND, + DC_LOCKED, +}; + +//--------------------------------------------------------- +// Add flags +//--------------------------------------------------------- +enum DataCacheAddFlags_t +{ + DCAF_LOCK = ( 1 << 0 ), + DCAF_DEFAULT = 0, +}; + + + +//----------------------------------------------------------------------------- +// IDataCacheSection +// +// Purpose: Implements a sub-section of the global cache. Subsections are +// areas of the cache with thier own memory constraints and common +// management. +//----------------------------------------------------------------------------- +abstract_class IDataCacheSection +{ +public: + //-------------------------------------------------------- + + virtual IDataCache *GetSharedCache() = 0; + virtual const char *GetName() = 0; + + //-------------------------------------------------------- + // Purpose: Controls cache size & options + //-------------------------------------------------------- + virtual void SetLimits( const DataCacheLimits_t &limits ) = 0; + virtual void SetOptions( unsigned options ) = 0; + + + //-------------------------------------------------------- + // Purpose: Get the current state of the section + //-------------------------------------------------------- + virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ) = 0; + + + //-------------------------------------------------------- + // Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache. + //-------------------------------------------------------- + virtual void EnsureCapacity( unsigned nBytes, unsigned nItems = 1 ) = 0; + + + //-------------------------------------------------------- + // Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache. + //-------------------------------------------------------- + virtual bool Add( DataCacheClientID_t clientId, const void *pItemData, unsigned size, DataCacheHandle_t *pHandle ) = 0; + + //-------------------------------------------------------- + // Purpose: Finds an item in the cache, returns NULL if item is not in cache. Not a cheap operation if section not configured for fast find. + //-------------------------------------------------------- + virtual DataCacheHandle_t Find( DataCacheClientID_t clientId ) = 0; + + + //-------------------------------------------------------- + // Purpose: Get an item out of the cache and remove it. No callbacks are executed unless explicity specified. + //-------------------------------------------------------- + virtual DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, const void **ppItemData, unsigned *pItemSize = NULL, bool bNotify = false ) = 0; + DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, bool bNotify = false ) { return Remove( handle, NULL, NULL, bNotify ); } + + + //-------------------------------------------------------- + // Purpose: Returns if the data is currently in memory, but does *not* change its location in the LRU + //-------------------------------------------------------- + virtual bool IsPresent( DataCacheHandle_t handle ) = 0; + + + //-------------------------------------------------------- + // Purpose: Lock an item in the cache, returns NULL if item is not in the cache. + //-------------------------------------------------------- + virtual void *Lock( DataCacheHandle_t handle ) = 0; + + + //-------------------------------------------------------- + // Purpose: Unlock a previous lock. + //-------------------------------------------------------- + virtual int Unlock( DataCacheHandle_t handle ) = 0; + + + //-------------------------------------------------------- + // Purpose: Get an item without locking it, returns NULL if item is not in the cache. Use with care! + //-------------------------------------------------------- + virtual void *Get( DataCacheHandle_t handle, bool bFrameLock = false ) = 0; + virtual void *GetNoTouch( DataCacheHandle_t handle, bool bFrameLock = false ) = 0; + + //-------------------------------------------------------- + // Purpose: "Frame locking" (not game frame). A crude way to manage locks over relatively + // short periods. Does not affect normal locks/unlocks + //-------------------------------------------------------- + virtual int BeginFrameLocking() = 0; + virtual bool IsFrameLocking() = 0; + virtual void *FrameLock( DataCacheHandle_t handle ) = 0; + virtual int EndFrameLocking() = 0; + virtual int *GetFrameUnlockCounterPtr() = 0; + + + //-------------------------------------------------------- + // Purpose: Lock management, not for the feint of heart + //-------------------------------------------------------- + virtual int GetLockCount( DataCacheHandle_t handle ) = 0; + virtual int BreakLock( DataCacheHandle_t handle ) = 0; + + + //-------------------------------------------------------- + // Purpose: Explicitly mark an item as "recently used" + //-------------------------------------------------------- + virtual bool Touch( DataCacheHandle_t handle ) = 0; + + + //-------------------------------------------------------- + // Purpose: Explicitly mark an item as "least recently used". + //-------------------------------------------------------- + virtual bool Age( DataCacheHandle_t handle ) = 0; + + + //-------------------------------------------------------- + // Purpose: Empty the cache. Returns bytes released, will remove locked items if force specified + //-------------------------------------------------------- + virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ) = 0; + + + //-------------------------------------------------------- + // Purpose: Dump the oldest items to free the specified amount of memory. Returns amount actually freed + //-------------------------------------------------------- + virtual unsigned Purge( unsigned nBytes ) = 0; + + + //-------------------------------------------------------- + // Purpose: Output the state of the section + //-------------------------------------------------------- + virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT ) = 0; + + //-------------------------------------------------------- + // Purpose: Updates the size used by a specific item (locks the item, kicks + // other items out to make room as necessary, unlocks the item). + //-------------------------------------------------------- + virtual void UpdateSize( DataCacheHandle_t handle, unsigned int nNewSize ) = 0; + + + //-------------------------------------------------------- + // Purpose: Access to the mutex. More explicit control during get-then-lock sequences + // to ensure object stays valid during "then" + //-------------------------------------------------------- + virtual void LockMutex() = 0; + virtual void UnlockMutex() = 0; + + //-------------------------------------------------------- + // Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache. + //-------------------------------------------------------- + virtual bool AddEx( DataCacheClientID_t clientId, const void *pItemData, unsigned size, unsigned flags, DataCacheHandle_t *pHandle ) = 0; +}; + + +//----------------------------------------------------------------------------- +// IDataCacheClient +// +// Purpose: Connection between the cache and the owner of a cache section +// +//----------------------------------------------------------------------------- +abstract_class IDataCacheClient +{ +public: + //-------------------------------------------------------- + // + //-------------------------------------------------------- + virtual bool HandleCacheNotification( const DataCacheNotification_t ¬ification ) = 0; + + + //-------------------------------------------------------- + // + //-------------------------------------------------------- + virtual bool GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen ) = 0; +}; + +//------------------------------------- + +class CDefaultDataCacheClient : public IDataCacheClient +{ +public: + virtual bool HandleCacheNotification( const DataCacheNotification_t ¬ification ) + { + switch ( notification.type ) + { + case DC_AGE_DISCARD: + case DC_FLUSH_DISCARD: + case DC_REMOVED: + default: + Assert ( 0 ); + return false; + } + return false; + } + + virtual bool GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen ) + { + return false; + } +}; + + +//----------------------------------------------------------------------------- +// IDataCache +// +// Purpose: The global shared cache. Manages sections and overall budgets. +// +//----------------------------------------------------------------------------- +abstract_class IDataCache : public IAppSystem +{ +public: + //-------------------------------------------------------- + // Purpose: Controls cache size. + //-------------------------------------------------------- + virtual void SetSize( int nMaxBytes ) = 0; + virtual void SetOptions( unsigned options ) = 0; + virtual void SetSectionLimits( const char *pszSectionName, const DataCacheLimits_t &limits ) = 0; + + + //-------------------------------------------------------- + // Purpose: Get the current state of the cache + //-------------------------------------------------------- + virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ) = 0; + + + //-------------------------------------------------------- + // Purpose: Add a section to the cache + //-------------------------------------------------------- + virtual IDataCacheSection *AddSection( IDataCacheClient *pClient, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false ) = 0; + + + //-------------------------------------------------------- + // Purpose: Remove a section from the cache + //-------------------------------------------------------- + virtual void RemoveSection( const char *pszClientName, bool bCallFlush = true ) = 0; + void RemoveSection( IDataCacheSection *pSection, bool bCallFlush = true ) { if ( pSection) RemoveSection( pSection->GetName() ); } + + + //-------------------------------------------------------- + // Purpose: Find a section of the cache + //-------------------------------------------------------- + virtual IDataCacheSection *FindSection( const char *pszClientName ) = 0; + + + //-------------------------------------------------------- + // Purpose: Dump the oldest items to free the specified amount of memory. Returns amount actually freed + //-------------------------------------------------------- + virtual unsigned Purge( unsigned nBytes ) = 0; + + + //-------------------------------------------------------- + // Purpose: Empty the cache. Returns bytes released, will remove locked items if force specified + //-------------------------------------------------------- + virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ) = 0; + + + //-------------------------------------------------------- + // Purpose: Output the state of the cache + //-------------------------------------------------------- + virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char *pszSection = NULL ) = 0; +}; + +//----------------------------------------------------------------------------- +// Helper class to support usage pattern similar to CDataManager +//----------------------------------------------------------------------------- + +template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE * > +class CManagedDataCacheClient : public CDefaultDataCacheClient +{ +public: + typedef CManagedDataCacheClient CCacheClientBaseClass; + + CManagedDataCacheClient() + : m_pCache( NULL ) + { + } + + void Init( IDataCache *pSharedCache, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false ) + { + if ( !m_pCache ) + { + m_pCache = pSharedCache->AddSection( this, pszSectionName, limits, bSupportFastFind ); + } + } + + void Shutdown() + { + if ( m_pCache ) + { + m_pCache->GetSharedCache()->RemoveSection( m_pCache ); + m_pCache = NULL; + } + } + + LOCK_TYPE CacheGet( DataCacheHandle_t handle, bool bFrameLock = true ) + { + return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->Get( handle, bFrameLock ))->GetData()); + } + + LOCK_TYPE CacheGetNoTouch( DataCacheHandle_t handle ) + { + return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->GetNoTouch( handle ))->GetData()); + } + + LOCK_TYPE CacheLock( DataCacheHandle_t handle ) + { + return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->Lock( handle ))->GetData()); + } + + int CacheUnlock( DataCacheHandle_t handle ) + { + return m_pCache->Unlock( handle ); + } + + void CacheTouch( DataCacheHandle_t handle ) + { + m_pCache->Touch( handle ); + } + + void CacheRemove( DataCacheHandle_t handle, bool bNotify = true ) + { + m_pCache->Remove( handle, bNotify ); + } + + void CacheFlush() + { + m_pCache->Flush(); + } + + DataCacheHandle_t CacheCreate( const CREATE_PARAMS &createParams, unsigned flags = DCAF_DEFAULT ) + { + m_pCache->EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); + STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); + DataCacheHandle_t handle; + m_pCache->AddEx( (DataCacheClientID_t)pStore, pStore, pStore->Size(), flags, &handle); + return handle; + } + + void CacheLockMutex() + { + m_pCache->LockMutex(); + } + + void CacheUnlockMutex() + { + m_pCache->UnlockMutex(); + } + + bool HandleCacheNotification( const DataCacheNotification_t ¬ification ) + { + switch ( notification.type ) + { + case DC_AGE_DISCARD: + case DC_FLUSH_DISCARD: + case DC_REMOVED: + { + STORAGE_TYPE *p = (STORAGE_TYPE *)notification.clientId; + p->DestroyResource(); + } + return true; + default: + return CDefaultDataCacheClient::HandleCacheNotification( notification ); + } + } + + +protected: + + ~CManagedDataCacheClient() + { + Shutdown(); + } + + IDataCacheSection *GetCacheSection() + { + return m_pCache; + } + +private: + IDataCacheSection *m_pCache; + +}; + +//----------------------------------------------------------------------------- + +#endif // IDataCache diff --git a/public/datacache/imdlcache.h b/public/datacache/imdlcache.h new file mode 100644 index 0000000..0f7093a --- /dev/null +++ b/public/datacache/imdlcache.h @@ -0,0 +1,297 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// model loading and caching +// +//============================================================================= + +#ifndef IMDLCACHE_H +#define IMDLCACHE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct studiohdr_t; +struct studiohwdata_t; +struct vcollide_t; +struct virtualmodel_t; +struct vertexFileHeader_t; + +namespace OptimizedModel +{ + struct FileHeader_t; +} + + +//----------------------------------------------------------------------------- +// Reference to a loaded studiomdl +//----------------------------------------------------------------------------- +typedef unsigned short MDLHandle_t; + +enum +{ + MDLHANDLE_INVALID = (MDLHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Cache data types +//----------------------------------------------------------------------------- +enum MDLCacheDataType_t +{ + // Callbacks to get called when data is loaded or unloaded for these: + MDLCACHE_STUDIOHDR = 0, + MDLCACHE_STUDIOHWDATA, + MDLCACHE_VCOLLIDE, + + // Callbacks NOT called when data is loaded or unloaded for these: + MDLCACHE_ANIMBLOCK, + MDLCACHE_VIRTUALMODEL, + MDLCACHE_VERTEXES, + MDLCACHE_DECODEDANIMBLOCK, +}; + +abstract_class IMDLCacheNotify +{ +public: + // Called right after the data is loaded + virtual void OnDataLoaded( MDLCacheDataType_t type, MDLHandle_t handle ) = 0; + + // Called right before the data is unloaded + virtual void OnDataUnloaded( MDLCacheDataType_t type, MDLHandle_t handle ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Flags for flushing +//----------------------------------------------------------------------------- +enum MDLCacheFlush_t +{ + MDLCACHE_FLUSH_STUDIOHDR = 0x01, + MDLCACHE_FLUSH_STUDIOHWDATA = 0x02, + MDLCACHE_FLUSH_VCOLLIDE = 0x04, + MDLCACHE_FLUSH_ANIMBLOCK = 0x08, + MDLCACHE_FLUSH_VIRTUALMODEL = 0x10, + MDLCACHE_FLUSH_AUTOPLAY = 0x20, + MDLCACHE_FLUSH_VERTEXES = 0x40, + + MDLCACHE_FLUSH_IGNORELOCK = 0x80000000, + MDLCACHE_FLUSH_ALL = 0xFFFFFFFF +}; + +/* +#define MDLCACHE_INTERFACE_VERSION_4 "MDLCache004" + +namespace MDLCacheV4 +{ + +abstract_class IMDLCache : public IAppSystem +{ +public: + // Used to install callbacks for when data is loaded + unloaded + virtual void SetCacheNotify( IMDLCacheNotify *pNotify ) = 0; + // NOTE: This assumes the "GAME" path if you don't use + // the UNC method of specifying files. This will also increment + // the reference count of the MDL + virtual MDLHandle_t FindMDL( const char *pMDLRelativePath ) = 0; + + // Reference counting + virtual int AddRef( MDLHandle_t handle ) = 0; + virtual int Release( MDLHandle_t handle ) = 0; + + // Gets at the various data associated with a MDL + virtual studiohdr_t *GetStudioHdr( MDLHandle_t handle ) = 0; + virtual studiohwdata_t *GetHardwareData( MDLHandle_t handle ) = 0; + virtual vcollide_t *GetVCollide( MDLHandle_t handle ) = 0; + virtual unsigned char *GetAnimBlock( MDLHandle_t handle, int nBlock ) = 0; + virtual virtualmodel_t *GetVirtualModel( MDLHandle_t handle ) = 0; + virtual int GetAutoplayList( MDLHandle_t handle, unsigned short **pOut ) = 0; + virtual vertexFileHeader_t *GetVertexData( MDLHandle_t handle ) = 0; + + // Brings all data associated with an MDL into memory + virtual void TouchAllData( MDLHandle_t handle ) = 0; + + // Gets/sets user data associated with the MDL + virtual void SetUserData( MDLHandle_t handle, void* pData ) = 0; + virtual void *GetUserData( MDLHandle_t handle ) = 0; + + // Is this MDL using the error model? + virtual bool IsErrorModel( MDLHandle_t handle ) = 0; + + // Flushes the cache, force a full discard + virtual void Flush( int nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0; + + // Flushes a particular model out of memory + virtual void Flush( MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0; + + // Returns the name of the model (its relative path) + virtual const char *GetModelName( MDLHandle_t handle ) = 0; + + // faster access when you already have the studiohdr + virtual virtualmodel_t *GetVirtualModelFast( const studiohdr_t *pStudioHdr, MDLHandle_t handle ) = 0; + + // all cache entries that subsequently allocated or successfully checked + // are considered "locked" and will not be freed when additional memory is needed + virtual void BeginLock() = 0; + + // reset all protected blocks to normal + virtual void EndLock() = 0; + + // returns a pointer to a counter that is incremented every time the cache has been out of the locked state (EVIL) + virtual int *GetFrameUnlockCounterPtr() = 0; + + // Finish all pending async operations + virtual void FinishPendingLoads() = 0; +}; + + +} +*/ + +//----------------------------------------------------------------------------- +// The main MDL cacher +//----------------------------------------------------------------------------- +#define MDLCACHE_INTERFACE_VERSION "MDLCache004" + +abstract_class IMDLCache : public IAppSystem +{ +public: + // Used to install callbacks for when data is loaded + unloaded + // Returns the prior notify + virtual void SetCacheNotify( IMDLCacheNotify *pNotify ) = 0; + + // NOTE: This assumes the "GAME" path if you don't use + // the UNC method of specifying files. This will also increment + // the reference count of the MDL + virtual MDLHandle_t FindMDL( const char *pMDLRelativePath ) = 0; + + // Reference counting + virtual int AddRef( MDLHandle_t handle ) = 0; + virtual int Release( MDLHandle_t handle ) = 0; + virtual int GetRef( MDLHandle_t handle ) = 0; + + // Gets at the various data associated with a MDL + virtual studiohdr_t *GetStudioHdr( MDLHandle_t handle ) = 0; + virtual studiohwdata_t *GetHardwareData( MDLHandle_t handle ) = 0; + virtual vcollide_t *GetVCollide( MDLHandle_t handle ) = 0; + virtual unsigned char *GetAnimBlock( MDLHandle_t handle, int nBlock ) = 0; + virtual virtualmodel_t *GetVirtualModel( MDLHandle_t handle ) = 0; + virtual int GetAutoplayList( MDLHandle_t handle, unsigned short **pOut ) = 0; + virtual vertexFileHeader_t *GetVertexData( MDLHandle_t handle ) = 0; + + // Brings all data associated with an MDL into memory + virtual void TouchAllData( MDLHandle_t handle ) = 0; + + // Gets/sets user data associated with the MDL + virtual void SetUserData( MDLHandle_t handle, void* pData ) = 0; + virtual void *GetUserData( MDLHandle_t handle ) = 0; + + // Is this MDL using the error model? + virtual bool IsErrorModel( MDLHandle_t handle ) = 0; + + // Flushes the cache, force a full discard + virtual void Flush( MDLCacheFlush_t nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0; + + // Flushes a particular model out of memory + virtual void Flush( MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0; + + // Returns the name of the model (its relative path) + virtual const char *GetModelName( MDLHandle_t handle ) = 0; + + // faster access when you already have the studiohdr + virtual virtualmodel_t *GetVirtualModelFast( const studiohdr_t *pStudioHdr, MDLHandle_t handle ) = 0; + + // all cache entries that subsequently allocated or successfully checked + // are considered "locked" and will not be freed when additional memory is needed + virtual void BeginLock() = 0; + + // reset all protected blocks to normal + virtual void EndLock() = 0; + + // returns a pointer to a counter that is incremented every time the cache has been out of the locked state (EVIL) + virtual int *GetFrameUnlockCounterPtrOLD() = 0; + + // Finish all pending async operations + virtual void FinishPendingLoads() = 0; + + virtual vcollide_t *GetVCollideEx( MDLHandle_t handle, bool synchronousLoad = true ) = 0; + virtual bool GetVCollideSize( MDLHandle_t handle, int *pVCollideSize ) = 0; + + virtual bool GetAsyncLoad( MDLCacheDataType_t type ) = 0; + virtual bool SetAsyncLoad( MDLCacheDataType_t type, bool bAsync ) = 0; + + virtual void BeginMapLoad() = 0; + virtual void EndMapLoad() = 0; + virtual void MarkAsLoaded( MDLHandle_t handle ) = 0; + + virtual void InitPreloadData( bool rebuild ) = 0; + virtual void ShutdownPreloadData() = 0; + + virtual bool IsDataLoaded( MDLHandle_t handle, MDLCacheDataType_t type ) = 0; + + virtual int *GetFrameUnlockCounterPtr( MDLCacheDataType_t type ) = 0; + + virtual studiohdr_t *LockStudioHdr( MDLHandle_t handle ) = 0; + virtual void UnlockStudioHdr( MDLHandle_t handle ) = 0; + + virtual bool PreloadModel( MDLHandle_t handle ) = 0; + + // Hammer uses this. If a model has an error loading in GetStudioHdr, then it is flagged + // as an error model and any further attempts to load it will just get the error model. + // That is, until you call this function. Then it will load the correct model. + virtual void ResetErrorModelStatus( MDLHandle_t handle ) = 0; + + virtual void MarkFrame() = 0; +}; + + +//----------------------------------------------------------------------------- +// Critical section helper code +//----------------------------------------------------------------------------- +class CMDLCacheCriticalSection +{ +public: + CMDLCacheCriticalSection( IMDLCache *pCache ) : m_pCache( pCache ) + { + m_pCache->BeginLock(); + } + + ~CMDLCacheCriticalSection() + { + m_pCache->EndLock(); + } + +private: + IMDLCache *m_pCache; +}; + +#define MDCACHE_FINE_GRAINED 1 + +#if defined(MDCACHE_FINE_GRAINED) +#define MDLCACHE_CRITICAL_SECTION_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache) +#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0)) +#elif defined(MDLCACHE_LEVEL_LOCKED) +#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0)) +#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0)) +#else +#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0)) +#define MDLCACHE_COARSE_LOCK_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache) +#endif +#define MDLCACHE_CRITICAL_SECTION() MDLCACHE_CRITICAL_SECTION_(mdlcache) +#define MDLCACHE_COARSE_LOCK() MDLCACHE_COARSE_LOCK_(mdlcache) + +#endif // IMDLCACHE_H + diff --git a/public/datamap.h b/public/datamap.h new file mode 100644 index 0000000..34a1caf --- /dev/null +++ b/public/datamap.h @@ -0,0 +1,455 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DATAMAP_H +#define DATAMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef VECTOR_H +#include "mathlib/vector.h" +#endif + +#include "tier1/utlvector.h" + +#include "tier0/memdbgon.h" + +// SINGLE_INHERITANCE restricts the size of CBaseEntity pointers-to-member-functions to 4 bytes +class SINGLE_INHERITANCE CBaseEntity; +struct inputdata_t; + +#define INVALID_TIME (FLT_MAX * -1.0) // Special value not rebased on save/load + +typedef enum _fieldtypes +{ + FIELD_VOID = 0, // No type or value + FIELD_FLOAT, // Any floating point value + FIELD_STRING, // A string ID (return from ALLOC_STRING) + FIELD_VECTOR, // Any vector, QAngle, or AngularImpulse + FIELD_QUATERNION, // A quaternion + FIELD_INTEGER, // Any integer or enum + FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression + FIELD_SHORT, // 2 byte integer + FIELD_CHARACTER, // a byte + FIELD_COLOR32, // 8-bit per channel r,g,b,a (32bit color) + FIELD_EMBEDDED, // an embedded object with a datadesc, recursively traverse and embedded class/structure based on an additional typedescription + FIELD_CUSTOM, // special type that contains function pointers to it's read/write/parse functions + + FIELD_CLASSPTR, // CBaseEntity * + FIELD_EHANDLE, // Entity handle + FIELD_EDICT, // edict_t * + + FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically) + FIELD_TIME, // a floating point time (these are fixed up automatically too!) + FIELD_TICK, // an integer tick count( fixed up similarly to time) + FIELD_MODELNAME, // Engine string that is a model name (needs precache) + FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) + + FIELD_INPUT, // a list of inputed data fields (all derived from CMultiInputVar) + FIELD_FUNCTION, // A class function pointer (Think, Use, etc) + + FIELD_VMATRIX, // a vmatrix (output coords are NOT worldspace) + + // NOTE: Use float arrays for local transformations that don't need to be fixed up. + FIELD_VMATRIX_WORLDSPACE,// A VMatrix that maps some local space to world space (translation is fixed up on level transitions) + FIELD_MATRIX3X4_WORLDSPACE, // matrix3x4_t that maps some local space to world space (translation is fixed up on level transitions) + + FIELD_INTERVAL, // a start and range floating point interval ( e.g., 3.2->3.6 == 3.2 and 0.4 ) + FIELD_MODELINDEX, // a model index + FIELD_MATERIALINDEX, // a material index (using the material precache string table) + + FIELD_VECTOR2D, // 2 floats + + FIELD_TYPECOUNT, // MUST BE LAST +} fieldtype_t; + + +//----------------------------------------------------------------------------- +// Field sizes... +//----------------------------------------------------------------------------- +template +class CDatamapFieldSizeDeducer +{ +public: + enum + { + SIZE = 0 + }; + + static int FieldSize( ) + { + return 0; + } +}; + +#define DECLARE_FIELD_SIZE( _fieldType, _fieldSize ) \ + template< > class CDatamapFieldSizeDeducer<_fieldType> { public: enum { SIZE = _fieldSize }; static int FieldSize() { return _fieldSize; } }; +#define FIELD_SIZE( _fieldType ) CDatamapFieldSizeDeducer<_fieldType>::SIZE +#define FIELD_BITS( _fieldType ) (FIELD_SIZE( _fieldType ) * 8) + +DECLARE_FIELD_SIZE( FIELD_FLOAT, sizeof(float) ) +DECLARE_FIELD_SIZE( FIELD_STRING, sizeof(int) ) +DECLARE_FIELD_SIZE( FIELD_VECTOR, 3 * sizeof(float) ) +DECLARE_FIELD_SIZE( FIELD_VECTOR2D, 2 * sizeof(float) ) +DECLARE_FIELD_SIZE( FIELD_QUATERNION, 4 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_INTEGER, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_BOOLEAN, sizeof(char)) +DECLARE_FIELD_SIZE( FIELD_SHORT, sizeof(short)) +DECLARE_FIELD_SIZE( FIELD_CHARACTER, sizeof(char)) +DECLARE_FIELD_SIZE( FIELD_COLOR32, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_POSITION_VECTOR, 3 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_TIME, sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_TICK, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_INPUT, sizeof(int)) +#ifdef POSIX +// pointer to members under gnuc are 8bytes if you have a virtual func +DECLARE_FIELD_SIZE( FIELD_FUNCTION, sizeof(uint64)) +#else +DECLARE_FIELD_SIZE( FIELD_FUNCTION, sizeof(int *)) +#endif +DECLARE_FIELD_SIZE( FIELD_VMATRIX, 16 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_VMATRIX_WORLDSPACE, 16 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_MATRIX3X4_WORLDSPACE, 12 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_INTERVAL, 2 * sizeof( float) ) // NOTE: Must match interval.h definition +DECLARE_FIELD_SIZE( FIELD_MODELINDEX, sizeof(int) ) +DECLARE_FIELD_SIZE( FIELD_MATERIALINDEX, sizeof(int) ) + + +#define ARRAYSIZE2D(p) (sizeof(p)/sizeof(p[0][0])) +#define SIZE_OF_ARRAY(p) _ARRAYSIZE(p) + +#define _FIELD(name,fieldtype,count,flags,mapname,tolerance) { fieldtype, #name, { offsetof(classNameTypedef, name), 0 }, count, flags, mapname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, tolerance } +#define DEFINE_FIELD_NULL { FIELD_VOID,0, {0,0},0,0,0,0,0,0} +#define DEFINE_FIELD(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_KEYFIELD(name,fieldtype, mapname) _FIELD(name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_KEYFIELD_NOT_SAVED(name,fieldtype, mapname)_FIELD(name, fieldtype, 1, FTYPEDESC_KEY, mapname, 0 ) +#define DEFINE_AUTO_ARRAY(name,fieldtype) _FIELD(name, fieldtype, SIZE_OF_ARRAY(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_AUTO_ARRAY_KEYFIELD(name,fieldtype,mapname) _FIELD(name, fieldtype, SIZE_OF_ARRAY(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_ARRAY(name,fieldtype, count) _FIELD(name, fieldtype, count, FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(edict_t, name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE, #name, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(edict_t, name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE | FTYPEDESC_GLOBAL, #name, 0 ) +#define DEFINE_GLOBAL_FIELD(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_GLOBAL | FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_GLOBAL_KEYFIELD(name,fieldtype, mapname) _FIELD(name, fieldtype, 1, FTYPEDESC_GLOBAL | FTYPEDESC_KEY | FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_CUSTOM_FIELD(name,datafuncs) { FIELD_CUSTOM, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, datafuncs, NULL } +#define DEFINE_CUSTOM_KEYFIELD(name,datafuncs,mapname) { FIELD_CUSTOM, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE | FTYPEDESC_KEY, mapname, datafuncs, NULL } +#define DEFINE_AUTO_ARRAY2D(name,fieldtype) _FIELD(name, fieldtype, ARRAYSIZE2D(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, 0 ) +// Used by byteswap datadescs +#define DEFINE_BITFIELD(name,fieldtype,bitcount) DEFINE_ARRAY(name,fieldtype,((bitcount+FIELD_BITS(fieldtype)-1)&~(FIELD_BITS(fieldtype)-1)) / FIELD_BITS(fieldtype) ) +#define DEFINE_INDEX(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_INDEX, NULL, 0 ) + +#define DEFINE_EMBEDDED( name ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name.m_DataMap), sizeof( ((classNameTypedef *)0)->name ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_OVERRIDE( name, overridetype ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &((overridetype *)0)->m_DataMap, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDEDBYREF( name ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE | FTYPEDESC_PTR, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( *(((classNameTypedef *)0)->name) ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_ARRAY( name, count ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, count, FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( ((classNameTypedef *)0)->name[0] ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_AUTO_ARRAY( name ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, SIZE_OF_ARRAY( ((classNameTypedef *)0)->name ), FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( ((classNameTypedef *)0)->name[0] ), NULL, 0, 0.0f } + +#ifndef NO_ENTITY_PREDICTION + +#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &fieldtype::m_PredMap } + +#define DEFINE_PRED_TYPEDESCRIPTION_PTR( name, fieldtype ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE | FTYPEDESC_PTR, NULL, NULL, NULL, &fieldtype::m_PredMap } + +#else + +#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) DEFINE_FIELD_NULL +#define DEFINE_PRED_TYPEDESCRIPTION_PTR( name, fieldtype ) DEFINE_FIELD_NULL + +#endif + +// Extensions to datamap.h macros for predicted entities only +#define DEFINE_PRED_FIELD(name,fieldtype, flags) _FIELD(name, fieldtype, 1, flags, NULL, 0.0f ) +#define DEFINE_PRED_ARRAY(name,fieldtype, count,flags) _FIELD(name, fieldtype, count, flags, NULL, 0.0f ) +#define DEFINE_FIELD_NAME(localname,netname,fieldtype) _FIELD(localname, fieldtype, 1, 0, #netname, 0.0f ) +// Predictable macros, which include a tolerance for floating point values... +#define DEFINE_PRED_FIELD_TOL(name,fieldtype, flags,tolerance) _FIELD(name, fieldtype, 1, flags, NULL, tolerance ) +#define DEFINE_PRED_ARRAY_TOL(name,fieldtype, count,flags,tolerance) _FIELD(name, fieldtype, count, flags, NULL, tolerance) +#define DEFINE_FIELD_NAME_TOL(localname,netname,fieldtolerance) _FIELD(localname, fieldtype, 1, 0, #netname, tolerance ) + +//#define DEFINE_DATA( name, fieldextname, flags ) _FIELD(name, fieldtype, 1, flags, extname ) + +// INPUTS +#define DEFINE_INPUT( name, fieldtype, inputname ) { fieldtype, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_INPUT | FTYPEDESC_SAVE | FTYPEDESC_KEY, inputname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ) } +#define DEFINE_INPUTFUNC( fieldtype, inputname, inputfunc ) { fieldtype, #inputfunc, { NULL, NULL }, 1, FTYPEDESC_INPUT, inputname, NULL, static_cast (&classNameTypedef::inputfunc) } + +// OUTPUTS +// the variable 'name' MUST BE derived from CBaseOutput +// we know the output type from the variable itself, so it doesn't need to be specified here +class ISaveRestoreOps; +extern ISaveRestoreOps *eventFuncs; +#define DEFINE_OUTPUT( name, outputname ) { FIELD_CUSTOM, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_OUTPUT | FTYPEDESC_SAVE | FTYPEDESC_KEY, outputname, eventFuncs } + +// replaces EXPORT table for portability and non-DLL based systems (xbox) +#define DEFINE_FUNCTION_RAW( function, func_type ) { FIELD_VOID, nameHolder.GenerateName(#function), { NULL, NULL }, 1, FTYPEDESC_FUNCTIONTABLE, NULL, NULL, (inputfunc_t)((func_type)(&classNameTypedef::function)) } +#define DEFINE_FUNCTION( function ) DEFINE_FUNCTION_RAW( function, inputfunc_t ) + + +#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore +#define FTYPEDESC_SAVE 0x0002 // This field is saved to disk +#define FTYPEDESC_KEY 0x0004 // This field can be requested and written to by string name at load time +#define FTYPEDESC_INPUT 0x0008 // This field can be written to by string name at run time, and a function called +#define FTYPEDESC_OUTPUT 0x0010 // This field propogates it's value to all targets whenever it changes +#define FTYPEDESC_FUNCTIONTABLE 0x0020 // This is a table entry for a member function pointer +#define FTYPEDESC_PTR 0x0040 // This field is a pointer, not an embedded object +#define FTYPEDESC_OVERRIDE 0x0080 // The field is an override for one in a base class (only used by prediction system for now) + +// Flags used by other systems (e.g., prediction system) +#define FTYPEDESC_INSENDTABLE 0x0100 // This field is present in a network SendTable +#define FTYPEDESC_PRIVATE 0x0200 // The field is local to the client or server only (not referenced by prediction code and not replicated by networking) +#define FTYPEDESC_NOERRORCHECK 0x0400 // The field is part of the prediction typedescription, but doesn't get compared when checking for errors + +#define FTYPEDESC_MODELINDEX 0x0800 // The field is a model index (used for debugging output) + +#define FTYPEDESC_INDEX 0x1000 // The field is an index into file data, used for byteswapping. + +// These flags apply to C_BasePlayer derived objects only +#define FTYPEDESC_VIEW_OTHER_PLAYER 0x2000 // By default you can only view fields on the local player (yourself), + // but if this is set, then we allow you to see fields on other players +#define FTYPEDESC_VIEW_OWN_TEAM 0x4000 // Only show this data if the player is on the same team as the local player +#define FTYPEDESC_VIEW_NEVER 0x8000 // Never show this field to anyone, even the local player (unusual) + +#define TD_MSECTOLERANCE 0.001f // This is a FIELD_FLOAT and should only be checked to be within 0.001 of the networked info + +struct typedescription_t; + + +class ISaveRestoreOps; + +// +// Function prototype for all input handlers. +// +typedef void (CBaseEntity::*inputfunc_t)(inputdata_t &data); + +struct datamap_t; +struct typedescription_t; + +enum +{ + TD_OFFSET_NORMAL = 0, + TD_OFFSET_PACKED = 1, + + // Must be last + TD_OFFSET_COUNT, +}; + +struct typedescription_t +{ + fieldtype_t fieldType; + const char *fieldName; + int fieldOffset[ TD_OFFSET_COUNT ]; // 0 == normal, 1 == packed offset + unsigned short fieldSize; + short flags; + // the name of the variable in the map/fgd data, or the name of the action + const char *externalName; + // pointer to the function set for save/restoring of custom data types + ISaveRestoreOps *pSaveRestoreOps; + // for associating function with string names + inputfunc_t inputFunc; + // For embedding additional datatables inside this one + datamap_t *td; + + // Stores the actual member variable size in bytes + int fieldSizeInBytes; + + // FTYPEDESC_OVERRIDE point to first baseclass instance if chains_validated has occurred + struct typedescription_t *override_field; + + // Used to track exclusion of baseclass fields + int override_count; + + // Tolerance for field errors for float fields + float fieldTolerance; +}; + + +//----------------------------------------------------------------------------- +// Purpose: stores the list of objects in the hierarchy +// used to iterate through an object's data descriptions +//----------------------------------------------------------------------------- +struct datamap_t +{ + typedescription_t *dataDesc; + int dataNumFields; + char const *dataClassName; + datamap_t *baseMap; + + bool chains_validated; + // Have the "packed" offsets been computed + bool packed_offsets_computed; + int packed_size; + +#if defined( _DEBUG ) + bool bValidityChecked; +#endif // _DEBUG +}; + + +//----------------------------------------------------------------------------- +// +// Macros used to implement datadescs +// +#define DECLARE_SIMPLE_DATADESC() \ + static datamap_t m_DataMap; \ + static datamap_t *GetBaseMap(); \ + template friend void DataMapAccess(T *, datamap_t **p); \ + template friend datamap_t *DataMapInit(T *); + +#define DECLARE_DATADESC() \ + DECLARE_SIMPLE_DATADESC() \ + virtual datamap_t *GetDataDescMap( void ); + +#define BEGIN_DATADESC( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \ + datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_DATADESC_NO_BASE( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \ + datamap_t *className::GetBaseMap() { return NULL; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_SIMPLE_DATADESC( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetBaseMap() { return NULL; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_SIMPLE_DATADESC_( className, BaseClass ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_DATADESC_GUTS( className ) \ + template datamap_t *DataMapInit(T *); \ + template <> datamap_t *DataMapInit( className * ); \ + namespace className##_DataDescInit \ + { \ + datamap_t *g_DataMapHolder = DataMapInit( (className *)NULL ); /* This can/will be used for some clean up duties later */ \ + } \ + \ + template <> datamap_t *DataMapInit( className * ) \ + { \ + typedef className classNameTypedef; \ + static CDatadescGeneratedNameHolder nameHolder(#className); \ + className::m_DataMap.baseMap = className::GetBaseMap(); \ + static typedescription_t dataDesc[] = \ + { \ + { FIELD_VOID,0, {0,0},0,0,0,0,0,0}, /* so you can define "empty" tables */ + +#define END_DATADESC() \ + }; \ + \ + if ( sizeof( dataDesc ) > sizeof( dataDesc[0] ) ) \ + { \ + classNameTypedef::m_DataMap.dataNumFields = SIZE_OF_ARRAY( dataDesc ) - 1; \ + classNameTypedef::m_DataMap.dataDesc = &dataDesc[1]; \ + } \ + else \ + { \ + classNameTypedef::m_DataMap.dataNumFields = 1; \ + classNameTypedef::m_DataMap.dataDesc = dataDesc; \ + } \ + return &classNameTypedef::m_DataMap; \ + } + +// used for when there is no data description +#define IMPLEMENT_NULL_SIMPLE_DATADESC( derivedClass ) \ + BEGIN_SIMPLE_DATADESC( derivedClass ) \ + END_DATADESC() + +#define IMPLEMENT_NULL_SIMPLE_DATADESC_( derivedClass, baseClass ) \ + BEGIN_SIMPLE_DATADESC_( derivedClass, baseClass ) \ + END_DATADESC() + +#define IMPLEMENT_NULL_DATADESC( derivedClass ) \ + BEGIN_DATADESC( derivedClass ) \ + END_DATADESC() + +// helps get the offset of a bitfield +#define BEGIN_BITFIELD( name ) \ + union \ + { \ + char name; \ + struct \ + { + +#define END_BITFIELD() \ + }; \ + }; + +//----------------------------------------------------------------------------- +// Forward compatability with potential seperate byteswap datadescs + +#define DECLARE_BYTESWAP_DATADESC() DECLARE_SIMPLE_DATADESC() +#define BEGIN_BYTESWAP_DATADESC(name) BEGIN_SIMPLE_DATADESC(name) +#define BEGIN_BYTESWAP_DATADESC_(name,base) BEGIN_SIMPLE_DATADESC_(name,base) +#define END_BYTESWAP_DATADESC() END_DATADESC() + +//----------------------------------------------------------------------------- + +template +inline void DataMapAccess(T *ignored, datamap_t **p) +{ + *p = &T::m_DataMap; +} + +//----------------------------------------------------------------------------- + +class CDatadescGeneratedNameHolder +{ +public: + CDatadescGeneratedNameHolder( const char *pszBase ) + : m_pszBase(pszBase) + { + m_nLenBase = strlen( m_pszBase ); + } + + ~CDatadescGeneratedNameHolder() + { + for ( int i = 0; i < m_Names.Count(); i++ ) + { + delete m_Names[i]; + } + } + + const char *GenerateName( const char *pszIdentifier ) + { + char *pBuf = new char[m_nLenBase + strlen(pszIdentifier) + 1]; + strcpy( pBuf, m_pszBase ); + strcat( pBuf, pszIdentifier ); + m_Names.AddToTail( pBuf ); + return pBuf; + } + +private: + const char *m_pszBase; + size_t m_nLenBase; + CUtlVector m_Names; +}; + +//----------------------------------------------------------------------------- + +#include "tier0/memdbgoff.h" + +#endif // DATAMAP_H diff --git a/public/datamodel/attributeflags.h b/public/datamodel/attributeflags.h new file mode 100644 index 0000000..8cacdb4 --- /dev/null +++ b/public/datamodel/attributeflags.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ATTRIBUTEFLAGS_H +#define ATTRIBUTEFLAGS_H + +#ifdef _WIN32 +#pragma once +#endif + +enum +{ + // NOTE: The first 5 flags bits are reserved for attribute type + FATTRIB_TYPEMASK = 0x1F, + + FATTRIB_READONLY = (1<<5), // Don't allow editing value in editors + FATTRIB_DONTSAVE = (1<<6), // Don't persist to .dmx file + FATTRIB_DIRTY = (1<<7), // Indicates the attribute has been changed since the resolve phase + FATTRIB_HAS_CALLBACK = (1<<8), // Indicates that this will notify its owner and/or other elements when it changes + FATTRIB_EXTERNAL = (1<<9), // Indicates this attribute's data is externally owned (in a CDmElement somewhere) + FATTRIB_TOPOLOGICAL = (1<<10), // Indicates this attribute effects the scene's topology (ie it's an attribute name or element) + FATTRIB_MUSTCOPY = (1<<11), // parent element must make a new copy during CopyInto, even for shallow copy + FATTRIB_NEVERCOPY = (1<<12), // parent element shouldn't make a new copy during CopyInto, even for deep copy + FATTRIB_STANDARD = (1<<13), // This flag is set if it's a "standard" attribute, namely "name" + FATTRIB_USERDEFINED = (1<<14), // This flag is used to sort attributes in the element properties view. User defined flags come last. + FATTRIB_NODUPLICATES = (1<<15),// For element array types, disallows duplicate values from being inserted into the array. + FATTRIB_HAS_ARRAY_CALLBACK = (1<<16), // Indicates that this will notify its owner and/or other elements array elements changes. Note that when elements shift (say, inserting at head, or fast remove), callbacks are not executed for these elements. + FATTRIB_HAS_PRE_CALLBACK = (1<<17), // Indicates that this will notify its owner and/or other elements right before it changes + FATTRIB_OPERATOR_DIRTY = (1<<18),// Used and cleared only by operator phase of datamodel +}; + +#endif // ATTRIBUTEFLAGS_H diff --git a/public/datamodel/dmattribute.h b/public/datamodel/dmattribute.h new file mode 100644 index 0000000..e383eab --- /dev/null +++ b/public/datamodel/dmattribute.h @@ -0,0 +1,768 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMATTRIBUTE_H +#define DMATTRIBUTE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/attributeflags.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmattributetypes.h" +#include "datamodel/dmelement.h" +#include "datamodel/dmvar.h" +#include "tier1/utlhash.h" + +//----------------------------------------------------------------------------- +// Fast dynamic cast +//----------------------------------------------------------------------------- +template< class E > +inline E *CastElement( CDmElement *pElement ) +{ + if ( pElement && pElement->IsA( E::GetStaticTypeSymbol() ) ) + return static_cast< E* >( pElement ); + return NULL; +} + + +//----------------------------------------------------------------------------- +// type-safe element creation and accessor helpers - infers type name string from actual type +//----------------------------------------------------------------------------- +template< class E > +inline E *GetElement( DmElementHandle_t hElement ) +{ + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + return CastElement< E >( pElement ); +} + +//----------------------------------------------------------------------------- +// Typesafe element creation + destruction +//----------------------------------------------------------------------------- +template< class E > +inline E *CreateElement( const char *pObjectName, DmFileId_t fileid = DMFILEID_INVALID, const DmObjectId_t *pObjectID = NULL ) +{ + return GetElement< E >( g_pDataModel->CreateElement( E::GetStaticTypeSymbol(), pObjectName, fileid, pObjectID ) ); +} + +template< class E > +inline E *CreateElement( const char *pElementType, const char *pObjectName, DmFileId_t fileid = DMFILEID_INVALID, const DmObjectId_t *pObjectID = NULL ) +{ + return GetElement< E >( g_pDataModel->CreateElement( pElementType, pObjectName, fileid, pObjectID ) ); +} + + +//----------------------------------------------------------------------------- +// Used for attribute change callbacks +//----------------------------------------------------------------------------- +typedef unsigned short DmMailingList_t; +enum +{ + DMMAILINGLIST_INVALID = (DmMailingList_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Purpose: A general purpose pAttribute. Eventually will be extensible to arbitrary user types +//----------------------------------------------------------------------------- +class CDmAttribute +{ +public: + // Returns the type + DmAttributeType_t GetType() const; + const char *GetTypeString() const; + template< class T > bool IsA() const; + + // Returns the name. NOTE: The utlsymbol + // can be turned into a string by using g_pDataModel->String(); + const char *GetName() const; + UtlSymId_t GetNameSymbol() const; + void SetName( const char *newName ); + + // Gets the attribute value + // NOTE: GetValueUntyped is used with GetType() for use w/ SetValue( type, void* ) + template< class T > const T& GetValue() const; + template< class T > const T& GetValue( const T& defaultValue ) const; + const char *GetValueString() const; + template< class E > E *GetValueElement() const; + const void *GetValueUntyped() const; + + // Sets the attribute value + template< class T > void SetValue( const T &value ); + template< class E > void SetValue( E* pValue ); + void SetValue( const void *pValue, size_t nSize ); + + // Copies w/ type conversion (if possible) from another attribute + void SetValue( const CDmAttribute *pAttribute ); + void SetValue( CDmAttribute *pAttribute ); + void SetValue( DmAttributeType_t valueType, const void *pValue ); + + // Sets the attribute to its default value based on its type + void SetToDefaultValue(); + + // Convert to and from string + void SetValueFromString( const char *pValue ); + const char *GetValueAsString( char *pBuffer, size_t nBufLen ) const; + + // Used for element and element array attributes; it specifies which type of + // elements are valid to be referred to by this attribute + void SetElementTypeSymbol( UtlSymId_t typeSymbol ); + UtlSymId_t GetElementTypeSymbol() const; + + // Returns the next attribute + CDmAttribute *NextAttribute(); + const CDmAttribute *NextAttribute() const; + + // Returns the owner + CDmElement *GetOwner(); + + // Methods related to flags + void AddFlag( int flags ); + void RemoveFlag( int flags ); + void ClearFlags(); + int GetFlags() const; + bool IsFlagSet( int flags ) const; + + // Serialization + bool Serialize( CUtlBuffer &buf ) const; + bool Unserialize( CUtlBuffer &buf ); + + // Serialization of a single element. + // First version of UnserializeElement adds to tail if it worked + // Second version overwrites, but does not add, the element at the specified index + bool SerializeElement( int nElement, CUtlBuffer &buf ) const; + bool UnserializeElement( CUtlBuffer &buf ); + bool UnserializeElement( int nElement, CUtlBuffer &buf ); + + // Does this attribute serialize on multiple lines? + bool SerializesOnMultipleLines() const; + + // Get the attribute/create an attribute handle + DmAttributeHandle_t GetHandle( bool bCreate = true ); + + // Notify external elements upon change ( Calls OnAttributeChanged ) + // Pass false here to stop notification + void NotifyWhenChanged( DmElementHandle_t h, bool bNotify ); + + // estimate memory overhead + int EstimateMemoryUsage( TraversalDepth_t depth ) const; + +private: + // Class factory + static CDmAttribute *CreateAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName ); + static CDmAttribute *CreateExternalAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pExternalMemory ); + static void DestroyAttribute( CDmAttribute *pAttribute ); + + // Constructor, destructor + CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName ); + CDmAttribute( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName, void *pMemory ); + ~CDmAttribute(); + + // Used when constructing CDmAttributes + void Init( CDmElement *pOwner, DmAttributeType_t type, const char *pAttributeName ); + + // Used when shutting down, indicates DmAttributeHandle_t referring to this are invalid + void InvalidateHandle(); + + // Used when shutting down, indicates no more change notifications will be sent to listening elements + void CleanupMailingList(); + + // Called when the attribute changes + void PreChanged(); + void OnChanged( bool bArrayCountChanged = false, bool bIsTopological = false ); + + // Is modification allowed in this phase? + bool ModificationAllowed() const; + + // Mark the attribute as being dirty + bool MarkDirty(); + + // Is the data inline in a containing element class? + bool IsDataInline() const; + + // Allocates, frees internal data storage + void CreateAttributeData(); + void DeleteAttributeData(); + + // Gets at the internal data storage + void* GetAttributeData(); + const void* GetAttributeData() const; + template < class T > typename CDmAttributeInfo< T >::StorageType_t* GetData(); + template < class T > const typename CDmAttributeInfo< T >::StorageType_t* GetData() const; + template < class T > typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* GetArrayData(); + template < class T > const typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* GetArrayData() const; + + // Used by CDmElement to manage the list of attributes it owns + CDmAttribute **GetNextAttributeRef(); + + // Implementational function used for memory consumption estimation computation + int EstimateMemoryUsageInternal( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories ) const; + + // Called by elements after unserialization of their attributes is complete + void OnUnserializationFinished(); + + template< class T > bool IsTypeConvertable() const; + template< class T > bool ShouldModify( const T& src ); + template< class T > void CopyData( const T& src ); + template< class T > void CopyDataOut( T& dest ) const; + +private: + CDmAttribute *m_pNext; + void *m_pData; + CDmElement *m_pOwner; + int m_nFlags; + DmAttributeHandle_t m_Handle; + CUtlSymbol m_Name; + DmMailingList_t m_hMailingList; + + friend class CDmElement; + friend class CDmAttributeAccessor; + template< class T > friend class CDmrElementArray; + template< class E > friend class CDmrElementArrayConst; + template< class T > friend class CDmaArrayAccessor; + template< class T, class B > friend class CDmrDecorator; + template< class T, class B > friend class CDmrDecoratorConst; + template< class T > friend class CDmArrayAttributeOp; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline DmAttributeType_t CDmAttribute::GetType() const +{ + return (DmAttributeType_t)( m_nFlags & FATTRIB_TYPEMASK ); +} + +template< class T > inline bool CDmAttribute::IsA() const +{ + return GetType() == CDmAttributeInfo< T >::AttributeType(); +} + +inline const char *CDmAttribute::GetName() const +{ + return g_pDataModel->GetString( m_Name ); +} + +inline UtlSymId_t CDmAttribute::GetNameSymbol() const +{ + return m_Name; +} + + +//----------------------------------------------------------------------------- +// Iteration +//----------------------------------------------------------------------------- +inline CDmAttribute *CDmAttribute::NextAttribute() +{ + return m_pNext; +} + +inline const CDmAttribute *CDmAttribute::NextAttribute() const +{ + return m_pNext; +} + + +//----------------------------------------------------------------------------- +// Returns the owner +//----------------------------------------------------------------------------- +inline CDmElement *CDmAttribute::GetOwner() +{ + return m_pOwner; +} + + +//----------------------------------------------------------------------------- +// Value getting methods +//----------------------------------------------------------------------------- +template< class T > +inline const T& CDmAttribute::GetValue( const T& defaultValue ) const +{ + if ( GetType() == ( DmAttributeType_t )( CDmAttributeInfo< T >::ATTRIBUTE_TYPE ) ) + return *reinterpret_cast< const T* >( m_pData ); + + if ( IsTypeConvertable< T >() ) + { + static T tempVal; + CopyDataOut( tempVal ); + return tempVal; + } + + Assert( 0 ); + return defaultValue; +} + +template< class T > +inline const T& CDmAttribute::GetValue() const +{ + static CDmaVar< T > defaultVal; + return GetValue( defaultVal.Get() ); +} + +inline const char *CDmAttribute::GetValueString() const +{ + Assert( GetType() == AT_STRING ); + if ( GetType() != AT_STRING ) + return NULL; + + return GetValue< CUtlString >(); +} + +// used with GetType() for use w/ SetValue( type, void* ) +inline const void* CDmAttribute::GetValueUntyped() const +{ + return m_pData; +} + +template< class E > +inline E* CDmAttribute::GetValueElement() const +{ + Assert( GetType() == AT_ELEMENT ); + if ( GetType() == AT_ELEMENT ) + return GetElement( this->GetValue< DmElementHandle_t >() ); + return NULL; +} + + +//----------------------------------------------------------------------------- +// Value setting methods +//----------------------------------------------------------------------------- +template< class E > +inline void CDmAttribute::SetValue( E* pValue ) +{ + Assert( GetType() == AT_ELEMENT ); + if ( GetType() == AT_ELEMENT ) + { + SetValue( pValue ? pValue->GetHandle() : DMELEMENT_HANDLE_INVALID ); + } +} + +template<> +inline void CDmAttribute::SetValue( const char *pValue ) +{ + int nLen = pValue ? Q_strlen( pValue ) + 1 : 0; + CUtlString str( pValue, nLen ); + return SetValue( str ); +} + +template<> +inline void CDmAttribute::SetValue( char *pValue ) +{ + return SetValue( (const char *)pValue ); +} + +inline void CDmAttribute::SetValue( const void *pValue, size_t nSize ) +{ + CUtlBinaryBlock buf( pValue, (int)nSize ); + return SetValue( buf ); +} + + +//----------------------------------------------------------------------------- +// Methods related to flags +//----------------------------------------------------------------------------- +inline void CDmAttribute::AddFlag( int nFlags ) +{ + m_nFlags |= nFlags; +} + +inline void CDmAttribute::RemoveFlag( int nFlags ) +{ + m_nFlags &= ~nFlags; +} + +inline void CDmAttribute::ClearFlags() +{ + m_nFlags = 0; +} + +inline int CDmAttribute::GetFlags() const +{ + return m_nFlags; +} + +inline bool CDmAttribute::IsFlagSet( int nFlags ) const +{ + return ( nFlags & m_nFlags ) ? true : false; +} + +inline bool CDmAttribute::IsDataInline() const +{ + return !IsFlagSet(FATTRIB_EXTERNAL); +} + + +//----------------------------------------------------------------------------- +// Gets at the internal data storage +//----------------------------------------------------------------------------- +inline void* CDmAttribute::GetAttributeData() +{ + return m_pData; +} + +inline const void* CDmAttribute::GetAttributeData() const +{ + return m_pData; +} + +template < class T > +inline typename CDmAttributeInfo< T >::StorageType_t* CDmAttribute::GetData() +{ + return ( typename CDmAttributeInfo< T >::StorageType_t* )m_pData; +} + +template < class T > +inline typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* CDmAttribute::GetArrayData() +{ + return ( typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* )m_pData; +} + +template < class T > +inline const typename CDmAttributeInfo< T >::StorageType_t* CDmAttribute::GetData() const +{ + return ( const typename CDmAttributeInfo< T >::StorageType_t* )m_pData; +} + +template < class T > +inline const typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* CDmAttribute::GetArrayData() const +{ + return ( const typename CDmAttributeInfo< CUtlVector< T > >::StorageType_t* )m_pData; +} + + +//----------------------------------------------------------------------------- +// Used by CDmElement to manage the list of attributes it owns +//----------------------------------------------------------------------------- +inline CDmAttribute **CDmAttribute::GetNextAttributeRef() +{ + return &m_pNext; +} + + +//----------------------------------------------------------------------------- +// helper function for determining which attributes/elements to traverse during copy/find/save/etc. +//----------------------------------------------------------------------------- +inline bool ShouldTraverse( const CDmAttribute *pAttr, TraversalDepth_t depth ) +{ + switch ( depth ) + { + case TD_NONE: + return false; + + case TD_SHALLOW: + if ( !pAttr->IsFlagSet( FATTRIB_MUSTCOPY ) ) + return false; + // fall-through intentional + case TD_DEEP: + if ( pAttr->IsFlagSet( FATTRIB_NEVERCOPY ) ) + return false; + // fall-through intentional + case TD_ALL: + return true; + } + + Assert( 0 ); + return false; +} + + +//----------------------------------------------------------------------------- +// Gets attributes +//----------------------------------------------------------------------------- +inline CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type ) +{ + CDmAttribute *pAttribute = FindAttribute( pAttributeName ); + if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) ) + return NULL; + return pAttribute; +} + +inline const CDmAttribute *CDmElement::GetAttribute( const char *pAttributeName, DmAttributeType_t type ) const +{ + CDmAttribute *pAttribute = FindAttribute( pAttributeName ); + if ( ( type != AT_UNKNOWN ) && pAttribute && ( pAttribute->GetType() != type ) ) + return NULL; + return pAttribute; +} + + +//----------------------------------------------------------------------------- +// AddAttribute calls +//----------------------------------------------------------------------------- +inline CDmAttribute *CDmElement::AddAttribute( const char *pAttributeName, DmAttributeType_t type ) +{ + CDmAttribute *pAttribute = FindAttribute( pAttributeName ); + if ( pAttribute ) + return ( pAttribute->GetType() == type ) ? pAttribute : NULL; + pAttribute = CreateAttribute( pAttributeName, type ); + return pAttribute; +} + +template< class E > inline CDmAttribute *CDmElement::AddAttributeElement( const char *pAttributeName ) +{ + CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT ); + if ( !pAttribute ) + return NULL; + + // FIXME: If the attribute exists but has a different element type symbol, should we complain? + pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() ); + return pAttribute; +} + +template< class E > inline CDmAttribute *CDmElement::AddAttributeElementArray( const char *pAttributeName ) +{ + CDmAttribute *pAttribute = AddAttribute( pAttributeName, AT_ELEMENT_ARRAY ); + if ( !pAttribute ) + return NULL; + + // FIXME: If the attribute exists but has a different element type symbol, should we complain? + pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() ); + return pAttribute; +} + +//----------------------------------------------------------------------------- +// GetValue methods +//----------------------------------------------------------------------------- + +template< class T > +inline const T& CDmElement::GetValue( const char *pAttributeName ) const +{ + static CDmaVar defaultVal; + return GetValue( pAttributeName, defaultVal.Get() ); +} + +inline const char *CDmElement::GetValueString( const char *pAttributeName ) const +{ + return GetValue( pAttributeName ).Get(); +} + +template< class E > +inline E* CDmElement::GetValueElement( const char *pAttributeName ) const +{ + DmElementHandle_t h = GetValue< DmElementHandle_t >( pAttributeName ); + return GetElement( h ); +} + + +template< class T > +inline const T& CDmElement::GetValue( const char *pAttributeName, const T& defaultVal ) const +{ + const CDmAttribute *pAttribute = FindAttribute( pAttributeName ); + if ( pAttribute != NULL ) + return pAttribute->GetValue(); + return defaultVal; +} + +//----------------------------------------------------------------------------- +// SetValue methods +//----------------------------------------------------------------------------- +template< class T > +inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const T& value ) +{ + CDmAttribute *pAttribute = FindAttribute( pAttributeName ); + if ( !pAttribute ) + { + pAttribute = CreateAttribute( pAttributeName, CDmAttributeInfo::AttributeType() ); + } + if ( pAttribute ) + { + pAttribute->SetValue( value ); + return pAttribute; + } + return NULL; +} + +template< class E > +inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, E* pElement ) +{ + DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID; + return SetValue( pAttributeName, hElement ); +} + +template<> +inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const char *pValue ) +{ + int nLen = pValue ? Q_strlen( pValue ) + 1 : 0; + CUtlString str( pValue, nLen ); + return SetValue( pAttributeName, str ); +} + +template<> +inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, char *pValue ) +{ + return SetValue( pAttributeName, (const char *)pValue ); +} + +inline CDmAttribute* CDmElement::SetValue( const char *pAttributeName, const void *pValue, size_t nSize ) +{ + CUtlBinaryBlock buf( pValue, (int)nSize ); + return SetValue( pAttributeName, buf ); +} + + +//----------------------------------------------------------------------------- +// AddValue methods( set value if not found ) +//----------------------------------------------------------------------------- +template< class T > +inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const T& value ) +{ + CDmAttribute *pAttribute = GetAttribute( pAttributeName ); + if ( !pAttribute ) + return SetValue( pAttributeName, value ); + return pAttribute; +} + +template< class E > +inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, E* pElement ) +{ + DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID; + return InitValue( pAttributeName, hElement ); +} + +inline CDmAttribute* CDmElement::InitValue( const char *pAttributeName, const void *pValue, size_t size ) +{ + CDmAttribute *pAttribute = GetAttribute( pAttributeName ); + if ( !pAttribute ) + return SetValue( pAttributeName, pValue, size ); + return pAttribute; +} + +template< class T > +T *FindReferringElement( CDmElement *pElement, UtlSymId_t symAttrName, bool bMustBeInSameFile = true ) +{ + DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pElement->GetHandle() ); + while ( i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID ) + { + CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i ); + CDmElement *pDmeParent = pAttribute->GetOwner(); + if ( pDmeParent && pAttribute->GetNameSymbol() == symAttrName ) + { + T *pParent = CastElement< T >( pDmeParent ); + if ( pParent ) + { + if ( !bMustBeInSameFile || ( pParent->GetFileId() == pElement->GetFileId() ) ) + return pParent; + } + } + i = g_pDataModel->NextAttributeReferencingElement( i ); + } + + return NULL; +} + +template< class T > +T *FindAncestorReferencingElement( CDmElement *target ) +{ + if ( !target ) + return NULL; + + for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( target->GetHandle() ); + it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; + it = g_pDataModel->NextAttributeReferencingElement( it ) ) + { + CDmAttribute *attr = g_pDataModel->GetAttribute( it ); + Assert( attr ); + CDmElement *element = attr->GetOwner(); + Assert( element ); + if ( !element ) + continue; + T *t = CastElement< T >( element ); + if ( !t ) + continue; + + return t; + } + return NULL; +} + +template< class T > +T *FindAncestorReferencingElement_R_Impl( CUtlRBTree< CDmElement * >& visited, CDmElement *check ) +{ + if ( visited.Find( check ) != visited.InvalidIndex() ) + return NULL; + + visited.Insert( check ); + + // Pass one, see if it's in this ancestor list + DmAttributeReferenceIterator_t it; + for ( it = g_pDataModel->FirstAttributeReferencingElement( check->GetHandle() ); + it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; + it = g_pDataModel->NextAttributeReferencingElement( it ) ) + { + CDmAttribute *attr = g_pDataModel->GetAttribute( it ); + Assert( attr ); + CDmElement *element = attr->GetOwner(); + Assert( element ); + if ( !element ) + continue; + T *t = CastElement< T >( element ); + if ( !t ) + continue; + + return t; + } + + for ( it = g_pDataModel->FirstAttributeReferencingElement( check->GetHandle() ); + it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; + it = g_pDataModel->NextAttributeReferencingElement( it ) ) + { + CDmAttribute *attr = g_pDataModel->GetAttribute( it ); + Assert( attr ); + CDmElement *element = attr->GetOwner(); + Assert( element ); + if ( !element ) + continue; + + T *found = FindAncestorReferencingElement_R_Impl< T >( visited, element ); + if ( found ) + return found; + } + return NULL; +} + + +template< class T > +void FindAncestorsReferencingElement( CDmElement *target, CUtlVector< T* >& list ) +{ + if ( !target ) + return; + + list.RemoveAll(); + for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( target->GetHandle() ); + it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; + it = g_pDataModel->NextAttributeReferencingElement( it ) ) + { + CDmAttribute *attr = g_pDataModel->GetAttribute( it ); + Assert( attr ); + CDmElement *element = attr->GetOwner(); + Assert( element ); + if ( !element ) + continue; + T* t = CastElement< T >( element ); + if ( !t ) + continue; + + if ( list.Find( t ) != list.InvalidIndex() ) + continue; + + list.AddToTail( t ); + } +} + + +template< class T > +T *FindAncestorReferencingElement_R( CDmElement *target ) +{ + if ( !target ) + return NULL; + + CUtlRBTree< CDmElement * > visited( 0, 0, DefLessFunc( CDmElement * ) ); + return FindAncestorReferencingElement_R_Impl< T >( visited, target ); +} + + +#endif // DMATTRIBUTE_H diff --git a/public/datamodel/dmattributetypes.h b/public/datamodel/dmattributetypes.h new file mode 100644 index 0000000..3a29caa --- /dev/null +++ b/public/datamodel/dmattributetypes.h @@ -0,0 +1,317 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMATTRIBUTETYPES_H +#define DMATTRIBUTETYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include "tier1/utlbinaryblock.h" +#include "tier1/utlstring.h" +#include "tier1/uniqueid.h" +#include "Color.h" +#include "mathlib/vector2d.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "mathlib/vmatrix.h" +#include "datamodel/dmelementhandle.h" +#include "tier1/utlsymbol.h" + + +//----------------------------------------------------------------------------- +// Object Id +//----------------------------------------------------------------------------- +typedef UniqueId_t DmObjectId_t; + + +//----------------------------------------------------------------------------- +// Necessary for template specialization for AT_UNKNOWN +//----------------------------------------------------------------------------- +struct DmUnknownAttribute_t +{ + bool operator==( const DmUnknownAttribute_t& src ) const { return true; } +}; + + +//----------------------------------------------------------------------------- +// Element array +//----------------------------------------------------------------------------- +struct DmElementAttribute_t +{ + DmElementAttribute_t() : m_ElementType( UTL_INVAL_SYMBOL ) {} + + operator DmElementHandle_t&() { return m_Handle; } + operator const DmElementHandle_t&() const { return m_Handle; } + + DmElementHandle_t m_Handle; + UtlSymId_t m_ElementType; +}; + +struct DmElementArray_t : public CUtlVector< DmElementHandle_t > +{ + DmElementArray_t() : m_ElementType( UTL_INVAL_SYMBOL ) {} + + UtlSymId_t m_ElementType; +}; + + +//----------------------------------------------------------------------------- +// Attribute chunk type enum +//----------------------------------------------------------------------------- +enum DmAttributeType_t +{ + AT_UNKNOWN = 0, + + AT_FIRST_VALUE_TYPE, + + AT_ELEMENT = AT_FIRST_VALUE_TYPE, + AT_INT, + AT_FLOAT, + AT_BOOL, + AT_STRING, + AT_VOID, + AT_OBJECTID, + AT_COLOR, //rgba + AT_VECTOR2, + AT_VECTOR3, + AT_VECTOR4, + AT_QANGLE, + AT_QUATERNION, + AT_VMATRIX, + + AT_FIRST_ARRAY_TYPE, + + AT_ELEMENT_ARRAY = AT_FIRST_ARRAY_TYPE, + AT_INT_ARRAY, + AT_FLOAT_ARRAY, + AT_BOOL_ARRAY, + AT_STRING_ARRAY, + AT_VOID_ARRAY, + AT_OBJECTID_ARRAY, + AT_COLOR_ARRAY, + AT_VECTOR2_ARRAY, + AT_VECTOR3_ARRAY, + AT_VECTOR4_ARRAY, + AT_QANGLE_ARRAY, + AT_QUATERNION_ARRAY, + AT_VMATRIX_ARRAY, + AT_TYPE_COUNT, +}; + +const char *GetTypeString( DmAttributeType_t type ); + +inline bool IsValueType( DmAttributeType_t type ) +{ + return type >= AT_FIRST_VALUE_TYPE && type < AT_FIRST_ARRAY_TYPE; +} + +inline bool IsArrayType( DmAttributeType_t type ) +{ + return type >= AT_FIRST_ARRAY_TYPE && type < AT_TYPE_COUNT; +} + +inline bool IsTopological( DmAttributeType_t type ) +{ + return type == AT_ELEMENT || type == AT_ELEMENT_ARRAY; +} + +inline DmAttributeType_t ValueTypeToArrayType( DmAttributeType_t type ) +{ + Assert( IsValueType( type ) ); + return ( DmAttributeType_t )( ( type - AT_FIRST_VALUE_TYPE ) + AT_FIRST_ARRAY_TYPE ); +} + +inline DmAttributeType_t ArrayTypeToValueType( DmAttributeType_t type ) +{ + Assert( IsArrayType( type ) ); + return ( DmAttributeType_t )( ( type - AT_FIRST_ARRAY_TYPE ) + AT_FIRST_VALUE_TYPE ); +} + +inline int NumComponents( DmAttributeType_t type ) +{ + switch ( type ) + { + case AT_BOOL: + case AT_INT: + case AT_FLOAT: + return 1; + + case AT_VECTOR2: + return 2; + + case AT_VECTOR3: + case AT_QANGLE: + return 3; + + case AT_COLOR: //rgba + case AT_VECTOR4: + case AT_QUATERNION: + return 4; + + case AT_VMATRIX: + return 16; + + case AT_ELEMENT: + case AT_STRING: + case AT_VOID: + case AT_OBJECTID: + default: + return 0; + } +} + +template< typename T > +inline float GetComponent( const T &value, int i ) +{ + Assert( 0 ); + return 0.0f; +} + +template <> inline float GetComponent( const bool &value, int i ) +{ + Assert( i == 0 ); + return value ? 1.0f : 0.0f; +} + +template <> inline float GetComponent( const int &value, int i ) +{ + Assert( i == 0 ); + return float( value ); +} + +template <> inline float GetComponent( const float &value, int i ) +{ + Assert( i == 0 ); + return value; +} + +template <> inline float GetComponent( const Vector2D &value, int i ) +{ + return value[ i ]; +} + +template <> inline float GetComponent( const Vector &value, int i ) +{ + return value[ i ]; +} + +template <> inline float GetComponent( const QAngle &value, int i ) +{ + return value[ i ]; +} + +template <> inline float GetComponent( const Color &value, int i ) +{ + return value[ i ]; +} + +template <> inline float GetComponent( const Vector4D &value, int i ) +{ + return value[ i ]; +} + +template <> inline float GetComponent( const Quaternion &value, int i ) +{ + return value[ i ]; +} + +template <> inline float GetComponent( const VMatrix &value, int i ) +{ + return value.Base()[ i ]; +} + + +//----------------------------------------------------------------------------- +// Attribute info... +//----------------------------------------------------------------------------- +template +class CDmAttributeInfo +{ +public: + enum { ATTRIBUTE_TYPE = AT_UNKNOWN }; + + typedef T StorageType_t; + + static DmAttributeType_t AttributeType() + { + return AT_UNKNOWN; + } + + static const char *AttributeTypeName() + { + return "unknown"; + } + + static void SetDefaultValue( T& value ) + { + Assert(0); + } +}; + + +#define DECLARE_ATTRIBUTE_TYPE_INTERNAL( _className, _storageType, _attributeType, _attributeName, _defaultSetStatement ) \ + template< > class CDmAttributeInfo< _className > \ + { \ + public: \ + enum { ATTRIBUTE_TYPE = _attributeType }; \ + typedef _storageType StorageType_t; \ + static DmAttributeType_t AttributeType() { return _attributeType; } \ + static const char *AttributeTypeName() { return _attributeName; } \ + static void SetDefaultValue( _className& value ) { _defaultSetStatement } \ + }; \ + +#define DECLARE_ATTRIBUTE_ARRAY_TYPE_INTERNAL( _className, _storageType, _attributeType, _attributeName ) \ + template< > class CDmAttributeInfo< CUtlVector<_className> > \ + { \ + public: \ + enum { ATTRIBUTE_TYPE = _attributeType }; \ + typedef _storageType StorageType_t; \ + static DmAttributeType_t AttributeType() { return _attributeType; } \ + static const char *AttributeTypeName() { return _attributeName; } \ + static void SetDefaultValue( CUtlVector< _className >& value ) { value.RemoveAll(); } \ + }; \ + +#define DECLARE_ATTRIBUTE_TYPE( _className, _attributeType, _attributeName, _defaultSetStatement ) \ + DECLARE_ATTRIBUTE_TYPE_INTERNAL( _className, _className, _attributeType, _attributeName, _defaultSetStatement ) + +#define DECLARE_ATTRIBUTE_ARRAY_TYPE( _className, _attributeType, _attributeName )\ + DECLARE_ATTRIBUTE_ARRAY_TYPE_INTERNAL( _className, CUtlVector< _className >, _attributeType, _attributeName ) + +// NOTE: If you add an attribute type here, also add it to the list of DEFINE_ATTRIBUTE_TYPES in dmattribute.cpp +DECLARE_ATTRIBUTE_TYPE( int, AT_INT, "int", value = 0; ) +DECLARE_ATTRIBUTE_TYPE( float, AT_FLOAT, "float", value = 0.0f; ) +DECLARE_ATTRIBUTE_TYPE( bool, AT_BOOL, "bool", value = false; ) +DECLARE_ATTRIBUTE_TYPE( Color, AT_COLOR, "color", value.SetColor( 0, 0, 0, 255 ); ) +DECLARE_ATTRIBUTE_TYPE( Vector2D, AT_VECTOR2, "vector2", value.Init( 0.0f, 0.0f ); ) +DECLARE_ATTRIBUTE_TYPE( Vector, AT_VECTOR3, "vector3", value.Init( 0.0f, 0.0f, 0.0f ); ) +DECLARE_ATTRIBUTE_TYPE( Vector4D, AT_VECTOR4, "vector4", value.Init( 0.0f, 0.0f, 0.0f, 0.0f ); ) +DECLARE_ATTRIBUTE_TYPE( QAngle, AT_QANGLE, "qangle", value.Init( 0.0f, 0.0f, 0.0f ); ) +DECLARE_ATTRIBUTE_TYPE( Quaternion, AT_QUATERNION, "quaternion", value.Init( 0.0f, 0.0f, 0.0f, 1.0f ); ) +DECLARE_ATTRIBUTE_TYPE( VMatrix, AT_VMATRIX, "matrix", MatrixSetIdentity( value ); ) +DECLARE_ATTRIBUTE_TYPE( CUtlString, AT_STRING, "string", value.Set( NULL ); ) +DECLARE_ATTRIBUTE_TYPE( CUtlBinaryBlock, AT_VOID, "binary", value.Set( NULL, 0 ); ) +DECLARE_ATTRIBUTE_TYPE( DmObjectId_t, AT_OBJECTID, "elementid", InvalidateUniqueId( &value ); ) +DECLARE_ATTRIBUTE_TYPE_INTERNAL( DmElementHandle_t, DmElementAttribute_t, AT_ELEMENT, "element", value = DMELEMENT_HANDLE_INVALID; ) + +DECLARE_ATTRIBUTE_ARRAY_TYPE( int, AT_INT_ARRAY, "int_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( float, AT_FLOAT_ARRAY, "float_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( bool, AT_BOOL_ARRAY, "bool_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( Color, AT_COLOR_ARRAY, "color_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( Vector2D, AT_VECTOR2_ARRAY, "vector2_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( Vector, AT_VECTOR3_ARRAY, "vector3_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( Vector4D, AT_VECTOR4_ARRAY, "vector4_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( QAngle, AT_QANGLE_ARRAY, "qangle_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( Quaternion, AT_QUATERNION_ARRAY, "quaternion_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( VMatrix, AT_VMATRIX_ARRAY, "matrix_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( CUtlString, AT_STRING_ARRAY, "string_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( CUtlBinaryBlock, AT_VOID_ARRAY, "binary_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( DmObjectId_t, AT_OBJECTID_ARRAY, "elementid_array" ) +DECLARE_ATTRIBUTE_ARRAY_TYPE_INTERNAL( DmElementHandle_t, DmElementArray_t, AT_ELEMENT_ARRAY, "element_array" ) + + +#endif // DMATTRIBUTETYPES_H diff --git a/public/datamodel/dmattributevar.h b/public/datamodel/dmattributevar.h new file mode 100644 index 0000000..4bf2a23 --- /dev/null +++ b/public/datamodel/dmattributevar.h @@ -0,0 +1,1481 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMATTRIBUTEVAR_H +#define DMATTRIBUTEVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include "Color.h" +#include "mathlib/vector2d.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "mathlib/vmatrix.h" +#include "datamodel/dmelement.h" +#include "datamodel/dmattribute.h" + +template< class C, bool D > class CDmeHandle; + +//----------------------------------------------------------------------------- +// Specialization for color +//----------------------------------------------------------------------------- +class CDmaColor : public CDmaVar< Color > +{ +public: + // Set methods + void SetColor( int r, int g, int b, int a = 0 ); + void SetRed( int r ); + void SetGreen( int g ); + void SetBlue( int b ); + void SetAlpha( int a ); + + // Sets the color as a 32-bit integer + void SetRawColor( int color ); + + // Get methods + unsigned char r() const; + unsigned char g() const; + unsigned char b() const; + unsigned char a() const; + const unsigned char &operator[]( int index ) const; +}; + + +//----------------------------------------------------------------------------- +// Specialization for object ids +//----------------------------------------------------------------------------- +class CDmaObjectId : public CDmaVar< DmObjectId_t > +{ +public: + void CreateObjectId( ); + void Invalidate( ); + bool IsValid( ) const; + bool IsEqual( const DmObjectId_t &id ) const; + const DmObjectId_t &operator=( const DmObjectId_t& src ); + const CDmaObjectId& operator=( const CDmaObjectId& src ); + const DmObjectId_t& Set( const DmObjectId_t &src ); +}; + + +//----------------------------------------------------------------------------- +// Specialization for binary block +//----------------------------------------------------------------------------- +class CDmaBinaryBlock : public CDmaVar< CUtlBinaryBlock > +{ +public: + void Get( void *pValue, int nMaxLen ) const; + void Set( const void *pValue, int nLen ); + const void *Get() const; + const unsigned char& operator[]( int i ) const; + + // Returns buffer length + int Length() const; +}; + + +//----------------------------------------------------------------------------- +// Specialization for elements +//----------------------------------------------------------------------------- +template +class CDmaElement : public CDmaVar< DmElementHandle_t > +{ + typedef CDmaVar< DmElementHandle_t > BaseClass; + +public: + // Used to initialize the attribute in an element's OnConstruction method + void InitAndCreate( CDmElement *pOwner, const char *pAttributeName, const char *pElementName = NULL, int flags = 0 ); + void Init( CDmElement *pOwner, const char *pAttributeName, int flags = 0 ); + + // Returns the type of elements allowed into this attribute. UTL_INVAL_SYMBOL allows everything. + UtlSymId_t GetElementType() const; + + // Get/set + void Set( T* pElement ); + T* GetElement() const; + + // Cast + T* operator->() const; + operator T*() const; + + // NULL check + bool operator!() const; + + // Assignment.. wish I knew how to un-inline these methods + template CDmaElement &operator=( S* pElement ) + { + Set( static_cast( pElement ) ); + return *this; + } + + template CDmaElement &operator=( const CDmaElement& src ) + { + Set( static_cast( src.Get() ) ); + return *this; + } + + template bool operator==( const CDmaElement& src ) const + { + return Value() == src.Value(); + } + + template bool operator!=( const CDmaElement& src ) const + { + return Value() != src.Value(); + } +}; + + +//----------------------------------------------------------------------------- +// Can access any array attribute, regardless of type +// See below for type-specific array accessors which have more features +//----------------------------------------------------------------------------- +class CDmrGenericArrayConst +{ +public: + CDmrGenericArrayConst( const CDmAttribute* pAttribute ); + CDmrGenericArrayConst( const CDmElement *pElement, const char *pAttributeName ); + + // Array count + int Count() const; + + // Gets + const void* GetUntyped( int i ) const; + + // String conversion + const char* GetAsString( int i, char *pBuffer, size_t nBufLen ) const; + + const CDmAttribute *GetAttribute() const; + bool IsValid() const; + +protected: + CDmrGenericArrayConst(); + void Init( const CDmAttribute *pAttribute ); + void Init( const CDmElement *pElement, const char *pAttributeName ); + + CDmAttribute *m_pAttribute; +}; + +class CDmrGenericArray : public CDmrGenericArrayConst +{ +public: + CDmrGenericArray( CDmAttribute* pAttribute ); + CDmrGenericArray( CDmElement *pElement, const char *pAttributeName ); + + void EnsureCount( int num ); + + // Sets multiple elements at the same time + int AddToTail(); + void Remove( int elem ); // preserves order, shifts elements + void RemoveAll(); // doesn't deallocate memory + void SetMultiple( int i, int nCount, DmAttributeType_t valueType, const void *pValue ); + void Set( int i, DmAttributeType_t valueType, const void *pValue ); + + // String conversion + void SetFromString( int i, const char *pValue ); + + CDmAttribute *GetAttribute(); + const CDmAttribute *GetAttribute() const; +}; + + +//----------------------------------------------------------------------------- +// Helper template for external array attribute vars +// NOTE: To use this class, don't use CDmaArrayBase directly. Instead, use +// CDmaArray var; <- Instantiate an array attribute var as a member of a element class +// CDmrArray var; <- Used to reference an existing array attribute + read/modify it +// CDmrArrayConst var; <- Used to reference an existing array attribute + read it (no modify) +// +// Also, there is a CDmaStringArray/CDmrStringArray/CDmrStringArrayConst for strings +// and a CDmaElementArray/CDmrElementArray/CDmrElementArrayConst for elements +//----------------------------------------------------------------------------- +template< class T, class B > +class CDmaArrayConstBase : public B +{ +public: + // Accessors + const CUtlVector &Get() const; + const T *Base() const; + + // Iteration + int Count() const; + const T& operator[]( int i ) const; + const T& Element( int i ) const; + const T& Get( int i ) const; + const void* GetUntyped( int i ) const; + bool IsValidIndex( int i ) const; + int InvalidIndex( void ) const; + + // Search + int Find( const T &value ) const; + + // Attribute-related methods + const CDmAttribute *GetAttribute() const; + CDmElement *GetOwner(); + bool IsDirty() const; + +protected: + CDmaArrayConstBase( ); + + CDmAttribute *m_pAttribute; +}; + +template< class T, class B > +class CDmaArrayBase : public CDmaArrayConstBase< T, B > +{ +public: + // Insertion + int AddToTail(); + int InsertBefore( int elem ); + int AddToTail( const T& src ); + int InsertBefore( int elem, const T& src ); + int AddMultipleToTail( int num ); + int InsertMultipleBefore( int elem, int num ); + void EnsureCount( int num ); + + // Element Modification + void Set( int i, const T& value ); + void SetMultiple( int i, int nCount, const T* pValue ); + void Swap( int i, int j ); + + // Copy related methods + void CopyArray( const T *pArray, int size ); + + // this is basically just a faster version of CopyArray which uses pointer swap + // NOTE: This doesn't work for element arrays + void SwapArray( CUtlVector< T > &array ); + + // Removal + void FastRemove( int elem ); + void Remove( int elem ); + void RemoveMultiple( int elem, int num ); + void RemoveAll(); + + // Memory management + void EnsureCapacity( int num ); + void Purge(); + + // Attribute-related methods + CDmAttribute *GetAttribute(); + const CDmAttribute *GetAttribute() const; +}; + + +//----------------------------------------------------------------------------- +// Specialization for string arrays +// NOTE: To use this class, don't use CDmaStringArrayBase directly. Instead, use +// CDmaStringArray var; <- Instantiate an array attribute var as a member of a element class +// CDmrStringArray var; <- Used to reference an existing array attribute + read/modify it +// CDmrStringArrayConst var; <- Used to reference an existing array attribute + read it (no modify) +//----------------------------------------------------------------------------- +template< class BaseClass > +class CDmaStringArrayConstBase : public BaseClass +{ +public: + const char *operator[]( int i ) const; + const char *Element( int i ) const; + const char *Get( int i ) const; + const CUtlVector< CUtlString > &Get() const; + + // Returns strlen of element i + int Length( int i ) const; +}; + +template< class B > +class CDmaStringArrayBase : public CDmaStringArrayConstBase< CDmaArrayBase< CUtlString, B > > +{ + typedef CDmaStringArrayConstBase< CDmaArrayBase< CUtlString, B > > BaseClass; + +public: + // Sets an element in the array + void Set( int i, const char * pValue ); + + // Adds an element, uses copy constructor + int AddToTail( const char *pValue ); + int InsertBefore( int elem, const char *pValue ); +}; + + +//----------------------------------------------------------------------------- +// Specialization for elements +// NOTE: To use this class, don't use CDmaElementArrayBase directly. Instead, use +// CDmaElementArray< element_type > var; <- Instantiate an array attribute var as a member of a element class +// CDmrElementArray< element_type > var; <- Used to reference an existing array attribute + read/modify it +// CDmrElementArrayConst< element_type > var; <- Used to reference an existing array attribute + read it (no modify) +//----------------------------------------------------------------------------- +template< class E, class BaseClass > +class CDmaElementArrayConstBase : public BaseClass +{ +public: + // Returns the element type + UtlSymId_t GetElementType() const; + + // Array access + E *operator[]( int i ) const; + E *Element( int i ) const; + E *Get( int i ) const; + const DmElementHandle_t& GetHandle( int i ) const; + const CUtlVector< DmElementHandle_t > &Get() const; + + // Search + int Find( const E *pValue ) const; + int Find( DmElementHandle_t h ) const; +}; + +template < class E, class B > +class CDmaElementArrayBase : public CDmaElementArrayConstBase< E, CDmaArrayBase< DmElementHandle_t, B > > +{ + typedef CDmaElementArrayConstBase< E, CDmaArrayBase< DmElementHandle_t, B > > BaseClass; + +public: + void SetHandle( int i, DmElementHandle_t h ); + void Set( int i, E *pElement ); + + // Insertion + int AddToTail( ); + int AddToTail( DmElementHandle_t src ); + int AddToTail( E *pValue ); + int InsertBefore( int elem ); + int InsertBefore( int elem, DmElementHandle_t src ); + int InsertBefore( int elem, E *pValue ); + + template< class C, bool D > int AddToTail( const CDmeHandle& value ) + { + return BaseClass::AddToTail( value.GetHandle() ); + } + + template< class C, bool D > int InsertBefore( int elem, const CDmeHandle& value ) + { + return BaseClass::InsertBefore( elem, value.GetHandle() ); + } +}; + + +// NOTE: The next couple classes are implementation details used to create CDmrAray/CDmaArray + +//----------------------------------------------------------------------------- +// Base classes that contain data or refer to it; used for array accessor classes +//----------------------------------------------------------------------------- +template< typename T > +class CDmaDataInternal +{ +protected: + typedef typename CDmAttributeInfo< T >::StorageType_t D; + + const T& Value() const { return m_Storage; } + T& Value( ) { return m_Storage; } + const D& Data() const { return m_Storage; } + D& Data( ) { return m_Storage; } + +private: + D m_Storage; +}; + +template< typename T > +class CDmaDataExternal +{ +protected: + typedef typename CDmAttributeInfo< T >::StorageType_t D; + + CDmaDataExternal() : m_pStorage(0) {} + void Attach( void *pData ) { m_pStorage = (D*)pData; } + const T& Value() const { return *m_pStorage; } + T& Value( ) { return *m_pStorage; } + const D& Data() const { return *m_pStorage; } + D& Data( ) { return *m_pStorage; } + +private: + D* m_pStorage; +}; + + +//----------------------------------------------------------------------------- +// Versions for access, or for attribute vars +//----------------------------------------------------------------------------- +template< class T, class B > +class CDmaDecorator : public B +{ +public: + void Init( CDmElement *pOwner, const char *pAttributeName, int flags = 0 ); +}; + + +template< class T, class BaseClass > +class CDmrDecoratorConst : public BaseClass +{ +public: + void Init( const CDmAttribute* pAttribute ); + void Init( const CDmElement *pElement, const char *pAttributeName ); + + bool IsValid() const; +}; + +template< class T, class BaseClass > +class CDmrDecorator : public BaseClass +{ +public: + void Init( CDmAttribute* pAttribute ); + void Init( CDmElement *pElement, const char *pAttributeName, bool bAddAttribute = false ); + + bool IsValid() const; +}; + + +#define DECLARE_ATTRIBUTE_ARRAY_VARIABLE( _className, _elementType ) \ + public: \ + _className() {} + +#define DECLARE_ATTRIBUTE_ARRAY_REFERENCE( _className, _elementType ) \ + public: \ + _className() {} \ + _className( CDmAttribute* pAttribute ) { BaseClass::Init( pAttribute ); } \ + _className( CDmElement *pElement, const char *pAttributeName, bool bAddAttribute = false ) { BaseClass::Init( pElement, pAttributeName, bAddAttribute ); } \ + _className( CDmaArray<_className>& var ) { BaseClass::Init( var.GetAttribute() ); } \ + _className( CDmrArray<_className>& var ) { BaseClass::Init( var.GetAttribute() ); } + +#define DECLARE_ATTRIBUTE_ARRAY_CONST_REFERENCE( _className, _elementType ) \ + public: \ + _className() {} \ + _className( const CDmAttribute* pAttribute ) { BaseClass::Init( pAttribute ); } \ + _className( const CDmElement *pElement, const char *pAttributeName ) { BaseClass::Init( pElement, pAttributeName ); } \ + _className( const CDmaArray<_className>& var ) { BaseClass::Init( var.GetAttribute() ); } \ + _className( const CDmrArrayConst<_className>& var ) { BaseClass::Init( var.GetAttribute() ); } \ + _className( const CDmrArray<_className>& var ) { BaseClass::Init( var.GetAttribute() ); } + +template class CDmrArray; +template class CDmrArrayConst; +template class CDmaArray; + +//----------------------------------------------------------------------------- +// Versions for access, or for attribute vars +//----------------------------------------------------------------------------- +template +class CDmaArray : public CDmaDecorator< T, CDmaArrayBase< T, CDmaDataInternal< CUtlVector< T > > > > +{ + DECLARE_ATTRIBUTE_ARRAY_VARIABLE( CDmaArray, T ); + +public: + const CDmaArray& operator=( const CDmaArray &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + + template< class C > const CDmaArray& operator=( const C &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + +private: + CDmaArray( const CDmaArray& array ) {} +}; + + +template +class CDmrArrayConst : public CDmrDecoratorConst< T, CDmaArrayConstBase< T, CDmaDataExternal< CUtlVector< T > > > > +{ + typedef CDmrDecoratorConst< T, CDmaArrayConstBase< T, CDmaDataExternal< CUtlVector< T > > > > BaseClass; + DECLARE_ATTRIBUTE_ARRAY_CONST_REFERENCE( CDmrArrayConst, T ); +}; + + +template +class CDmrArray : public CDmrDecorator< T, CDmaArrayBase< T, CDmaDataExternal< CUtlVector< T > > > > +{ + typedef CDmrDecorator< T, CDmaArrayBase< T, CDmaDataExternal< CUtlVector< T > > > > BaseClass; + DECLARE_ATTRIBUTE_ARRAY_REFERENCE( CDmrArray, T ); + +public: + const CDmrArray& operator=( const CDmrArray &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + + template< class C > const CDmrArray& operator=( const C &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } +}; + +class CDmrStringArray; + +class CDmaStringArray : public CDmaDecorator< CUtlString, CDmaStringArrayBase< CDmaDataInternal< CUtlVector< CUtlString > > > > +{ + DECLARE_ATTRIBUTE_ARRAY_VARIABLE( CDmaStringArray, CUtlString ); + +public: + const CDmaStringArray& operator=( const CDmaStringArray &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + + template< class C > const CDmaStringArray& operator=( const C &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + +private: + CDmaStringArray( const CDmaStringArray& array ) {} +}; + +class CDmrStringArray : public CDmrDecorator< CUtlString, CDmaStringArrayBase< CDmaDataExternal< CUtlVector< CUtlString > > > > +{ + typedef CDmrDecorator< CUtlString, CDmaStringArrayBase< CDmaDataExternal< CUtlVector< CUtlString > > > > BaseClass; + DECLARE_ATTRIBUTE_ARRAY_REFERENCE( CDmrStringArray, CUtlString ); + +public: + CDmrStringArray( CDmaStringArray& var ) { Init( var.GetAttribute() ); } + CDmrStringArray( CDmrStringArray& var ) { Init( var.GetAttribute() ); } + + const CDmrStringArray& operator=( const CDmrStringArray &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + + template< class C > const CDmrStringArray& operator=( const C &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } +}; + +class CDmrStringArrayConst : public CDmrDecoratorConst< CUtlString, CDmaStringArrayConstBase< CDmaArrayConstBase< CUtlString, CDmaDataExternal< CUtlVector< CUtlString > > > > > +{ + typedef CDmrDecoratorConst< CUtlString, CDmaStringArrayConstBase< CDmaArrayConstBase< CUtlString, CDmaDataExternal< CUtlVector< CUtlString > > > > > BaseClass; + DECLARE_ATTRIBUTE_ARRAY_CONST_REFERENCE( CDmrStringArrayConst, CUtlString ); + +public: + CDmrStringArrayConst( const CDmaStringArray& var ) { Init( var.GetAttribute() ); } + CDmrStringArrayConst( const CDmrStringArray& var ) { Init( var.GetAttribute() ); } + CDmrStringArrayConst( const CDmrStringArrayConst& var ) { Init( var.GetAttribute() ); } +}; + + +//----------------------------------------------------------------------------- +// Prevent CDmaArray for DmElementHandle_t +//----------------------------------------------------------------------------- +template<> class CDmaArray { private: CDmaArray(); }; + + +template< class E > class CDmrElementArray; + +template< class E = CDmElement > +class CDmaElementArray : public CDmaElementArrayBase< E, CDmaDataInternal< CUtlVector< DmElementHandle_t > > > +{ + DECLARE_ATTRIBUTE_ARRAY_VARIABLE( CDmaElementArray, DmElementHandle_t ); + +public: + void Init( CDmElement *pOwner, const char *pAttributeName, int flags = 0 ) + { + Assert( pOwner ); + this->m_pAttribute = pOwner->AddExternalAttribute( pAttributeName, AT_ELEMENT_ARRAY, &CDmaElementArrayBase< E, CDmaDataInternal< CUtlVector< DmElementHandle_t > > >::Value() ); + this->m_pAttribute->SetElementTypeSymbol( E::GetStaticTypeSymbol() ); + if ( flags ) + { + this->m_pAttribute->AddFlag( flags ); + } + } + + template< typename C > CDmaElementArray& operator=( const C &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + + // NOTE: The copy operator= must be defined in addition to the generic one + const CDmaElementArray& operator=( const CDmaElementArray &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + +private: + template< class C > CDmaElementArray( const CDmaElementArray& var ); +}; + +template< class E = CDmElement > +class CDmrElementArrayConst : public CDmaElementArrayConstBase< E, CDmaArrayConstBase< DmElementHandle_t, CDmaDataExternal< CUtlVector< DmElementHandle_t > > > > +{ +public: + CDmrElementArrayConst() + { + this->m_pAttribute = NULL; + } + + CDmrElementArrayConst( const CDmAttribute* pAttribute ) + { + Init( pAttribute ); + } + + CDmrElementArrayConst( const CDmElement *pElement, const char *pAttributeName ) + { + Init( pElement, pAttributeName ); + } + + template< typename C > CDmrElementArrayConst( const CDmaElementArray& var ) + { + Init( var.GetAttribute() ); + } + + template< typename C > CDmrElementArrayConst( const CDmrElementArray& var ) + { + Init( var.GetAttribute() ); + } + + template< typename C > CDmrElementArrayConst( const CDmrElementArrayConst& var ) + { + Init( var.GetAttribute() ); + } + + void Init( const CDmAttribute* pAttribute ) + { + if ( pAttribute && pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + this->m_pAttribute = const_cast( pAttribute ); + this->Attach( this->m_pAttribute->GetAttributeData() ); + } + else + { + this->m_pAttribute = NULL; + this->Attach( NULL ); + } + } + + void Init( const CDmElement *pElement, const char *pAttributeName ) + { + const CDmAttribute *pAttribute = NULL; + if ( pElement && pAttributeName && pAttributeName[0] ) + { + pAttribute = (CDmAttribute*)pElement->GetAttribute( pAttributeName ); + } + Init( pAttribute ); + } + + bool IsValid() const + { + return this->m_pAttribute != NULL; + } +}; + +template< class T = CDmElement > +class CDmrElementArray : public CDmaElementArrayBase< T, CDmaDataExternal< CUtlVector< DmElementHandle_t > > > +{ +public: + CDmrElementArray() + { + this->m_pAttribute = NULL; + } + + CDmrElementArray( CDmAttribute* pAttribute ) + { + Init( pAttribute ); + } + + CDmrElementArray( CDmElement *pElement, const char *pAttributeName, bool bAddAttribute = false ) + { + Init( pElement, pAttributeName, bAddAttribute ); + } + + template< typename C > CDmrElementArray( CDmaElementArray& var ) + { + Init( var.GetAttribute() ); + } + + template< typename C > CDmrElementArray( CDmrElementArray& var ) + { + Init( var.GetAttribute() ); + } + + void Init( CDmAttribute* pAttribute ) + { + if ( pAttribute && pAttribute->GetType() == AT_ELEMENT_ARRAY ) + { + this->m_pAttribute = pAttribute; + this->Attach( this->m_pAttribute->GetAttributeData() ); + } + else + { + this->m_pAttribute = NULL; + this->Attach( NULL ); + } + } + + void Init( CDmElement *pElement, const char *pAttributeName, bool bAddAttribute = false ) + { + CDmAttribute *pAttribute = NULL; + if ( pElement && pAttributeName && pAttributeName[0] ) + { + pAttribute = pElement->GetAttribute( pAttributeName ); + if ( bAddAttribute && !pAttribute ) + { + pAttribute = pElement->CreateAttribute( pAttributeName, AT_ELEMENT_ARRAY ); + + // FIXME: Should we do this? + pAttribute->SetElementTypeSymbol( T::GetStaticTypeSymbol() ); + } + } + Init( pAttribute ); + } + + bool IsValid() const + { + return this->m_pAttribute != NULL; + } + + template< typename C > CDmrElementArray& operator=( const C &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } + + // NOTE: The copy operator= must be defined in addition to the generic one + const CDmrElementArray& operator=( const CDmrElementArray &val ) + { + CopyArray( val.Base(), val.Count() ); + return *this; + } +}; + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaVar +// +//----------------------------------------------------------------------------- +template< class T > inline CDmaVar::CDmaVar( ) +{ + m_pAttribute = NULL; + CDmAttributeInfo::SetDefaultValue( m_Storage ); +} + +template< class T > inline void CDmaVar::Init( CDmElement *pOwner, const char *pAttributeName, int flags ) +{ + Assert( pOwner ); + m_pAttribute = pOwner->AddExternalAttribute( pAttributeName, CDmAttributeInfo::AttributeType(), &m_Storage ); + Assert( m_pAttribute ); + if ( flags ) + { + m_pAttribute->AddFlag( flags ); + } +} + +template< class T > inline void CDmaVar::InitAndSet( CDmElement *pOwner, const char *pAttributeName, const T &value, int flags ) +{ + Init( pOwner, pAttributeName ); + Set( value ); + + // this has to happen AFTER set so the set happens before FATTRIB_READONLY + if ( flags ) + { + m_pAttribute->AddFlag( flags ); + } +} + +template< class T > inline const T& CDmaVar::Set( const T &val ) +{ + Assert( m_pAttribute ); + m_pAttribute->SetValue( val ); + return m_Storage; +} + +template< class T > inline const T& CDmaVar::operator=( const T &val ) +{ + return Set( val ); +} + +template< class T > inline const CDmaVar& CDmaVar::operator=( const CDmaVar& src ) +{ + Set( src.Get() ); + return *this; +} + +template< class T > inline const T& CDmaVar::operator+=( const T &val ) +{ + return Set( Value() + val ); +} + +template< class T > inline const T& CDmaVar::operator-=( const T &val ) +{ + return Set( Value() - val ); +} + +template< class T > inline const T& CDmaVar::operator/=( const T &val ) +{ + return Set( Value() / val ); +} + +template< class T > inline const T& CDmaVar::operator*=( const T &val ) +{ + return Set( Value() * val ); +} + +template< class T > inline const T& CDmaVar::operator^=( const T &val ) +{ + return Set( Value() ^ val ); +} + +template< class T > inline const T& CDmaVar::operator|=( const T &val ) +{ + return Set( Value() | val ); +} + +template< class T > inline const T& CDmaVar::operator&=( const T &val ) +{ + return Set( Value() & val ); +} + +template< class T > inline T CDmaVar::operator++() +{ + return Set( Value() + 1 ); +} + +template< class T > inline T CDmaVar::operator--() +{ + return Set( Value() - 1 ); +} + +template< class T > inline T CDmaVar::operator++( int ) // postfix version.. +{ + T oldValue = Value(); + Set( Value() + 1 ); + return oldValue; +} + +template< class T > inline T CDmaVar::operator--( int ) // postfix version.. +{ + T oldValue = Value(); + Set( Value() - 1 ); + return oldValue; +} + +template< class T > inline CDmaVar::operator const T&() const +{ + return Value(); +} + +template< class T > inline const T& CDmaVar::Get() const +{ + return Value(); +} + +template< class T > inline const T* CDmaVar::operator->() const +{ + return &Value(); +} + +template< class T > inline CDmAttribute *CDmaVar::GetAttribute() +{ + Assert( m_pAttribute ); + return m_pAttribute; +} + +template< class T > inline const CDmAttribute *CDmaVar::GetAttribute() const +{ + Assert( m_pAttribute ); + return m_pAttribute; +} + +template< class T > inline bool CDmaVar::IsDirty() const +{ + Assert( m_pAttribute ); + return m_pAttribute->IsFlagSet( FATTRIB_DIRTY ); +} + +template< class T > inline const T& CDmaVar::Value() const +{ + return m_Storage; +} + +template< class T > inline T& CDmaVar::Value() +{ + return m_Storage; +} + +template<> inline const DmElementHandle_t& CDmaVar< DmElementHandle_t >::Value() const +{ + return m_Storage.m_Handle; +} + +template<> inline DmElementHandle_t& CDmaVar< DmElementHandle_t >::Value() +{ + return m_Storage.m_Handle; +} + +template< class T > inline const typename CDmaVar::D& CDmaVar::Storage() const +{ + return m_Storage; +} + +template< class T > inline typename CDmaVar::D& CDmaVar::Storage() +{ + return m_Storage; +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaColor +// +//----------------------------------------------------------------------------- +inline void CDmaColor::SetColor( int r, int g, int b, int a ) +{ + Color clr( r, g, b, a ); + m_pAttribute->SetValue( clr ); +} + +inline void CDmaColor::SetRed( int r ) +{ + Color org = Value(); + org[ 0 ] = r; + m_pAttribute->SetValue( org ); +} + +inline void CDmaColor::SetGreen( int g ) +{ + Color org = Value(); + org[ 1 ] = g; + m_pAttribute->SetValue( org ); +} + +inline void CDmaColor::SetBlue( int b ) +{ + Color org = Value(); + org[ 2 ] = b; + m_pAttribute->SetValue( org ); +} + +inline void CDmaColor::SetAlpha( int a ) +{ + Color org = Value(); + org[ 3 ] = a; + m_pAttribute->SetValue( org ); +} + +inline unsigned char CDmaColor::r() const +{ + return (unsigned char)Value().r(); +} + +inline unsigned char CDmaColor::g() const +{ + return (unsigned char)Value().g(); +} + +inline unsigned char CDmaColor::b() const +{ + return (unsigned char)Value().b(); +} + +inline unsigned char CDmaColor::a() const +{ + return (unsigned char)Value().a(); +} + +inline const unsigned char &CDmaColor::operator[](int index) const +{ + return Value()[index]; +} + +inline void CDmaColor::SetRawColor( int color ) +{ + Color clr; + clr.SetRawColor( color ); + m_pAttribute->SetValue( clr ); +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaObjectId +// +//----------------------------------------------------------------------------- +inline void CDmaObjectId::CreateObjectId( ) +{ + DmObjectId_t id; + CreateUniqueId( &id ); + m_pAttribute->SetValue( id ); +} + +inline void CDmaObjectId::Invalidate( ) +{ + DmObjectId_t id; + InvalidateUniqueId( &id ); + m_pAttribute->SetValue( id ); +} + +inline bool CDmaObjectId::IsValid( ) const +{ + return IsUniqueIdValid( Value() ); +} + +inline bool CDmaObjectId::IsEqual( const DmObjectId_t &id ) const +{ + return IsUniqueIdEqual( Value(), id ); +} + +inline const DmObjectId_t &CDmaObjectId::operator=( const DmObjectId_t& src ) +{ + m_pAttribute->SetValue( src ); + return Value(); +} + +inline const CDmaObjectId& CDmaObjectId::operator=( const CDmaObjectId& src ) +{ + m_pAttribute->SetValue( src.Get() ); + return *this; +} + +inline const DmObjectId_t& CDmaObjectId::Set( const DmObjectId_t &src ) +{ + m_pAttribute->SetValue( src ); + return Value(); +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaString +// +//----------------------------------------------------------------------------- +inline const char *CDmaString::Get( ) const +{ + return Value().Get(); +} + +inline CDmaString::operator const char*() const +{ + return Value().Get(); +} + +inline void CDmaString::Set( const char *pValue ) +{ + CUtlString str( pValue, pValue ? Q_strlen( pValue ) + 1 : 0 ); + m_pAttribute->SetValue( str ); +} + +// Returns strlen +inline int CDmaString::Length() const +{ + return Value().Length(); +} + +inline CDmaString &CDmaString::operator=( const char *src ) +{ + Set( src ); + return *this; +} + +inline const CDmaString& CDmaString::operator=( const CDmaString& src ) +{ + Set( src.Get() ); + return *this; +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaBinaryBlock +// +//----------------------------------------------------------------------------- +inline void CDmaBinaryBlock::Get( void *pValue, int nMaxLen ) const +{ + Value().Get( pValue, nMaxLen ); +} + +inline void CDmaBinaryBlock::Set( const void *pValue, int nLen ) +{ + CUtlBinaryBlock block( pValue, nLen ); + m_pAttribute->SetValue( block ); +} + +inline const void *CDmaBinaryBlock::Get() const +{ + return Value().Get(); +} + +inline const unsigned char& CDmaBinaryBlock::operator[]( int i ) const +{ + return Value()[i]; +} + +inline int CDmaBinaryBlock::Length() const +{ + return Value().Length(); +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaElement +// +//----------------------------------------------------------------------------- +template +inline void CDmaElement::InitAndCreate( CDmElement *pOwner, const char *pAttributeName, const char *pElementName, int flags ) +{ + Init( pOwner, pAttributeName ); + + DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID; + if ( !g_pDataModel->IsUnserializing() ) + { + hElement = g_pDataModel->CreateElement( T::GetStaticTypeSymbol(), pElementName, pOwner->GetFileId() ); + } + Assert( m_pAttribute ); + m_pAttribute->SetValue( hElement ); + + // this has to happen AFTER set so the set happens before FATTRIB_READONLY + m_pAttribute->AddFlag( flags | FATTRIB_MUSTCOPY ); +} + +template +inline void CDmaElement::Init( CDmElement *pOwner, const char *pAttributeName, int flags ) +{ + BaseClass::Init( pOwner, pAttributeName ); + + Assert( m_pAttribute ); + m_pAttribute->SetElementTypeSymbol( T::GetStaticTypeSymbol() ); + if ( flags ) + { + m_pAttribute->AddFlag( flags ); + } +} + +template +inline UtlSymId_t CDmaElement::GetElementType() const +{ + return this->Data().m_ElementType; +} + +template +inline T* CDmaElement::GetElement() const +{ + CDmElement *pElement = g_pDataModel->GetElement( Value() ); + Assert( !pElement || pElement->IsA( T::GetStaticTypeSymbol() ) ); + return static_cast< T* >( pElement ); +} + +template +inline T* CDmaElement::operator->() const +{ + return GetElement(); +} + +template +inline CDmaElement::operator T*() const +{ + return GetElement(); +} + +template +inline void CDmaElement::Set( T* pElement ) +{ + Assert( m_pAttribute ); + m_pAttribute->SetValue( pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID ); +} + +template +inline bool CDmaElement::operator!() const +{ + return ( GetElement() == NULL ); +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaArrayBase +// +//----------------------------------------------------------------------------- +template< class T, class B > +inline const CUtlVector& CDmaArrayConstBase::Get() const +{ + return this->Value(); +} + +template< class T, class B > +inline const T *CDmaArrayConstBase::Base() const +{ + return this->Value().Base(); +} + +template< class T, class B > +inline const T& CDmaArrayConstBase::operator[]( int i ) const +{ + return this->Value()[ i ]; +} + +template< class T, class B > +const T& CDmaArrayConstBase::Element( int i ) const +{ + return this->Value()[ i ]; +} + +template< class T, class B > +inline const T& CDmaArrayConstBase::Get( int i ) const +{ + return this->Value()[ i ]; +} + +template< class T, class B > +const void* CDmaArrayConstBase::GetUntyped( int i ) const +{ + return &( this->Value()[ i ] ); +} + +template< class T, class B > +inline int CDmaArrayConstBase::Count() const +{ + return this->Value().Count(); +} + +template< class T, class B > +inline bool CDmaArrayConstBase::IsValidIndex( int i ) const +{ + return this->Value().IsValidIndex( i ); +} + +template< class T, class B > +inline int CDmaArrayConstBase::InvalidIndex( void ) const +{ + return this->Value().InvalidIndex(); +} + +template< class T, class B > +inline const CDmAttribute *CDmaArrayConstBase::GetAttribute() const +{ + Assert( m_pAttribute ); + return m_pAttribute; +} + +template< class T, class B > +inline CDmElement *CDmaArrayConstBase::GetOwner() +{ + return m_pAttribute->GetOwner(); +} + +template< class T, class B > +inline bool CDmaArrayConstBase::IsDirty() const +{ + return m_pAttribute->IsFlagSet( FATTRIB_DIRTY ); +} + + +template< class T, class B > +inline CDmAttribute *CDmaArrayBase::GetAttribute() +{ + Assert( this->m_pAttribute ); + return this->m_pAttribute; +} + +template< class T, class B > +inline const CDmAttribute *CDmaArrayBase::GetAttribute() const +{ + Assert( this->m_pAttribute ); + return this->m_pAttribute; +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaStringArrayBase +// +//----------------------------------------------------------------------------- +template< class B > +inline const char *CDmaStringArrayConstBase::operator[]( int i ) const +{ + return this->Value()[ i ].Get(); +} + +template< class B > +inline const char *CDmaStringArrayConstBase::Element( int i ) const +{ + return this->Value()[ i ].Get(); +} + +template< class B > +inline const char *CDmaStringArrayConstBase::Get( int i ) const +{ + return this->Value()[ i ].Get(); +} + +template< class B > +inline const CUtlVector< CUtlString > &CDmaStringArrayConstBase::Get() const +{ + return this->Value(); +} + +// Returns strlen of element i +template< class B > +inline int CDmaStringArrayConstBase::Length( int i ) const +{ + return this->Value()[i].Length(); +} + +template< class B > +inline void CDmaStringArrayBase::Set( int i, const char * pValue ) +{ + CUtlString str( pValue, Q_strlen( pValue ) + 1 ); + BaseClass::Set( i, str ); +} + +// Adds an element, uses copy constructor +template< class B > +inline int CDmaStringArrayBase::AddToTail( const char *pValue ) +{ + CUtlString str( pValue, Q_strlen( pValue ) + 1 ); + return BaseClass::AddToTail( str ); +} + +template< class B > +inline int CDmaStringArrayBase::InsertBefore( int elem, const char *pValue ) +{ + CUtlString str( pValue, Q_strlen( pValue ) + 1 ); + return BaseClass::InsertBefore( elem, str ); +} + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmaElementArrayBase +// +//----------------------------------------------------------------------------- +template< class E, class B > +inline UtlSymId_t CDmaElementArrayConstBase::GetElementType() const +{ + return this->Data().m_ElementType; +} + +template< class E, class B > +inline E *CDmaElementArrayConstBase::operator[]( int i ) const +{ + return GetElement( this->Value()[i] ); +} + +template< class E, class B > +inline E *CDmaElementArrayConstBase::Element( int i ) const +{ + return GetElement( this->Value()[i] ); +} + +template< class E, class B > +inline E *CDmaElementArrayConstBase::Get( int i ) const +{ + return GetElement( this->Value()[i] ); +} + +template< class E, class B > +inline const DmElementHandle_t& CDmaElementArrayConstBase::GetHandle( int i ) const +{ + return this->Value()[i]; +} + +template< class E, class B > +inline const CUtlVector< DmElementHandle_t > &CDmaElementArrayConstBase::Get() const +{ + return this->Value(); +} + +// Search +template< class E, class B > +inline int CDmaElementArrayConstBase::Find( const E *pValue ) const +{ + if ( !pValue ) + return -1; + return B::Find( pValue->GetHandle() ); +} + +template< class E, class B > +inline int CDmaElementArrayConstBase::Find( DmElementHandle_t h ) const +{ + return B::Find( h ); +} + +template< class E, class B > +inline void CDmaElementArrayBase::SetHandle( int i, DmElementHandle_t h ) +{ + BaseClass::Set( i, h ); +} + +template< class E, class B > +inline void CDmaElementArrayBase::Set( int i, E *pElement ) +{ + BaseClass::Set( i, pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID ); +} + +// Adds an element, uses copy constructor +template< class E, class B > +inline int CDmaElementArrayBase::AddToTail( ) +{ + return BaseClass::AddToTail( ); +} + +template< class E, class B > +inline int CDmaElementArrayBase::AddToTail( E *pValue ) +{ + return BaseClass::AddToTail( pValue ? pValue->GetHandle() : DMELEMENT_HANDLE_INVALID ); +} + +template< class E, class B > +inline int CDmaElementArrayBase::AddToTail( DmElementHandle_t src ) +{ + return BaseClass::AddToTail( src ); +} + +template< class E, class B > +inline int CDmaElementArrayBase::InsertBefore( int elem ) +{ + return BaseClass::InsertBefore( elem ); +} + +template< class E, class B > +inline int CDmaElementArrayBase::InsertBefore( int elem, E *pValue ) +{ + return BaseClass::InsertBefore( elem, pValue ? pValue->GetHandle() : DMELEMENT_HANDLE_INVALID ); +} + +template< class E, class B > +inline int CDmaElementArrayBase::InsertBefore( int elem, DmElementHandle_t src ) +{ + return BaseClass::InsertBefore( elem, src ); +} + + + +//----------------------------------------------------------------------------- +// +// Inline methods for CDmrGenericArray +// +//----------------------------------------------------------------------------- +inline const CDmAttribute *CDmrGenericArrayConst::GetAttribute() const +{ + Assert( m_pAttribute ); + return m_pAttribute; +} + +inline bool CDmrGenericArrayConst::IsValid() const +{ + return m_pAttribute != NULL; +} + +inline CDmAttribute *CDmrGenericArray::GetAttribute() +{ + Assert( m_pAttribute ); + return m_pAttribute; +} + +inline const CDmAttribute *CDmrGenericArray::GetAttribute() const +{ + Assert( m_pAttribute ); + return m_pAttribute; +} + + +#endif // DMATTRIBUTEVAR_H diff --git a/public/datamodel/dmehandle.h b/public/datamodel/dmehandle.h new file mode 100644 index 0000000..f2b7898 --- /dev/null +++ b/public/datamodel/dmehandle.h @@ -0,0 +1,243 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef DMEHANDLE_H +#define DMEHANDLE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "datamodel/dmattribute.h" +#include "datamodel/dmattributevar.h" + + +//----------------------------------------------------------------------------- +// Purpose: CDmeHandle is a templatized wrapper around DmElementHandle_t +//----------------------------------------------------------------------------- +template< class DmeType, bool Counted = false > +class CDmeHandle : public CDmeElementRefHelper +{ +public: + CDmeHandle() : m_handle( DMELEMENT_HANDLE_INVALID ) + { + } + + explicit CDmeHandle( CDmElement *pObject ) : m_handle( DMELEMENT_HANDLE_INVALID ) + { + Set( pObject ); + } + + CDmeHandle( DmElementHandle_t h ) : m_handle( DMELEMENT_HANDLE_INVALID ) + { + Set( h ); + } + + CDmeHandle( const CDmeHandle< DmeType, Counted > &handle ) : m_handle( DMELEMENT_HANDLE_INVALID ) + { + Set( handle.m_handle ); + } + + template < class T, bool B > + CDmeHandle( const CDmeHandle< T, B > &handle ) : m_handle( DMELEMENT_HANDLE_INVALID ) + { + DmeType *p = ( T* )NULL; // triggers compiler error if converting from invalid handle type + NOTE_UNUSED( p ); + + Set( handle.GetHandle() ); + } + + ~CDmeHandle() + { + if ( !g_pDataModel ) + return; // some handles are static, and don't get destroyed until program termination + + Unref( m_handle, Counted ); + } + + template < class T, bool B > + CDmeHandle& operator=( const CDmeHandle< T, B > &handle ) + { + DmeType *p = ( T* )NULL; // triggers compiler error if converting from invalid handle type + NOTE_UNUSED( p ); + + Set( handle.GetHandle() ); + return *this; + } + + DmeType *Get() + { + return static_cast< DmeType* >( g_pDataModel->GetElement( m_handle ) ); + } + + const DmeType *Get() const + { + return static_cast< DmeType* >( g_pDataModel->GetElement( m_handle ) ); + } + + DmElementHandle_t GetHandle() const + { + return m_handle; + } + + void Set( CDmElement *pObject ) + { + Set( pObject ? pObject->GetHandle() : DMELEMENT_HANDLE_INVALID ); + } + + void Set( DmElementHandle_t h ) + { + if ( h == m_handle ) + return; + + Unref( m_handle, Counted ); + + m_handle = h; + if ( h != DMELEMENT_HANDLE_INVALID ) + { + CDmElement *pElement = g_pDataModel->GetElement( m_handle ); + Assert( pElement ); + if ( pElement && !pElement->IsA( DmeType::GetStaticTypeSymbol() ) ) + { + m_handle = DMELEMENT_HANDLE_INVALID; + } + } + + Ref( m_handle, Counted ); + } + + operator DmeType*() + { + return Get(); + } + + operator const DmeType*() const + { + return Get(); + } + + operator DmElementHandle_t() const + { + return m_handle; + } + + DmeType* operator->() + { + return Get(); + } + + const DmeType* operator->() const + { + return Get(); + } + + CDmeHandle& operator=( DmElementHandle_t h ) + { + Set( h ); + return *this; + } + + CDmeHandle& operator=( CDmElement *pObject ) + { + Set( pObject ); + return *this; + } + + bool operator==( const CDmeHandle< DmeType > &h ) const + { + return m_handle == h.m_handle; + } + + bool operator!=( const CDmeHandle< DmeType > &h ) const + { + return !operator==( h ); + } + + bool operator<( const CDmeHandle< DmeType > &h ) const + { + return m_handle < h.m_handle; + } + + bool operator==( DmeType *pObject ) const + { + DmElementHandle_t h = pObject ? pObject->GetHandle() : DMELEMENT_HANDLE_INVALID; + return m_handle == h; + } + + bool operator!=( DmeType *pObject ) const + { + return !operator==( pObject ); + } + + bool operator==( DmElementHandle_t h ) const + { + return ( m_handle == h ); + } + + bool operator!=( DmElementHandle_t h ) const + { + return ( m_handle != h ); + } + + operator bool() const + { + return ( Get() != NULL ); + } + + bool operator!() const + { + return ( Get() == NULL ); + } + +private: + DmElementHandle_t m_handle; +}; + +typedef CDmeHandle< CDmElement, true > CDmeCountedHandle; + + +//----------------------------------------------------------------------------- +// Vector of element handles +//----------------------------------------------------------------------------- +typedef CUtlVector< CDmeHandle > DmeHandleVec_t; + + + +//----------------------------------------------------------------------------- +// helper class for undo classes to allow them to hold onto refcounted element handles +//----------------------------------------------------------------------------- + +template< typename T > +class CDmAttributeUndoStorageType +{ +public: + typedef T UndoStorageType; +}; + +template<> +class CDmAttributeUndoStorageType< DmElementHandle_t > +{ +public: + typedef CDmeCountedHandle UndoStorageType; +}; + +template<> +class CDmAttributeUndoStorageType< CUtlVector< DmElementHandle_t > > +{ +public: + typedef CUtlVector< CDmeCountedHandle > UndoStorageType; +}; + +#endif // DMEHANDLE_H diff --git a/public/datamodel/dmelement.h b/public/datamodel/dmelement.h new file mode 100644 index 0000000..13a8bec --- /dev/null +++ b/public/datamodel/dmelement.h @@ -0,0 +1,618 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMELEMENT_H +#define DMELEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlmap.h" +#include "tier1/utlhash.h" +#include "tier1/utlvector.h" +#include "tier1/utlsymbol.h" +#include "datamodel/attributeflags.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmvar.h" + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +typedef bool (CDmElement::*pfnCommandMethod)( const char *command, const char *args ); + +// element/element array traversal path item - assumes the full path does NOT contain cycles +struct ElementPathItem_t +{ + ElementPathItem_t( DmElementHandle_t hElem = DMELEMENT_HANDLE_INVALID, + DmAttributeHandle_t hAttr = DMATTRIBUTE_HANDLE_INVALID, + int idx = -1 ) + : hElement( hElem ), hAttribute( hAttr ), nIndex( idx ) + { + } + + // only uses hElement so that it can be used to search for elements + bool operator==( const ElementPathItem_t &that ) const + { + return hElement == that.hElement; + } + + DmElementHandle_t hElement; + DmAttributeHandle_t hAttribute; + int nIndex; +}; + + +//----------------------------------------------------------------------------- +// singly-linked attribute list +//----------------------------------------------------------------------------- +struct DmAttributeList_t +{ + DmAttributeList_t() : m_hAttribute( DMATTRIBUTE_HANDLE_INVALID ), m_pNext( NULL ) {} + DmAttributeHandle_t m_hAttribute; + DmAttributeList_t *m_pNext; +}; + +//----------------------------------------------------------------------------- +// helper class to allow CDmeHandle access to g_pDataModelImp +//----------------------------------------------------------------------------- +class CDmeElementRefHelper +{ +protected: + void Ref ( DmElementHandle_t hElement, bool bStrong ); + void Unref( DmElementHandle_t hElement, bool bStrong ); +}; + +//----------------------------------------------------------------------------- +// element reference struct - containing attribute referrers and handle refcount +//----------------------------------------------------------------------------- +struct DmElementReference_t +{ + explicit DmElementReference_t( DmElementHandle_t hElement = DMELEMENT_HANDLE_INVALID ) : + m_hElement( hElement ), m_nWeakHandleCount( 0 ), m_nStrongHandleCount( 0 ) + { + } + DmElementReference_t( const DmElementReference_t &that ) : + m_hElement( that.m_hElement ), m_nWeakHandleCount( that.m_nWeakHandleCount ), + m_nStrongHandleCount( that.m_nStrongHandleCount ), m_attributes( that.m_attributes ) + { + } + DmElementReference_t &operator=( const DmElementReference_t &that ) + { + m_hElement = that.m_hElement; + m_nWeakHandleCount = that.m_nWeakHandleCount; + m_nStrongHandleCount = that.m_nStrongHandleCount; + m_attributes.m_hAttribute = that.m_attributes.m_hAttribute; + m_attributes.m_pNext = that.m_attributes.m_pNext; + return *this; + } + ~DmElementReference_t() + { + // Assert( !IsStronglyReferenced() ); + } + + void AddAttribute( CDmAttribute *pAttribute ); + void RemoveAttribute( CDmAttribute *pAttribute ); + + bool IsStronglyReferenced() // should this element be kept around (even if it's DmElementHandle_t is invalidated) + { + return m_attributes.m_hAttribute != DMATTRIBUTE_HANDLE_INVALID || m_nStrongHandleCount > 0; + } + + bool IsWeaklyReferenced() // should we keep this element's DmElementHandle_t mapped to it's id (even if the element is deleted) + { + return IsStronglyReferenced() || m_nWeakHandleCount > 0; + } + + int EstimateMemoryOverhead() + { + int nBytes = 0; + for ( DmAttributeList_t *pLink = m_attributes.m_pNext; pLink; pLink = pLink->m_pNext ) + { + nBytes += sizeof( DmAttributeList_t ); + } + return nBytes; + } + + DmElementHandle_t m_hElement; + unsigned short m_nWeakHandleCount; // CDmeHandle - for auto-hookup once the element comes back, mainly used by UI + unsigned short m_nStrongHandleCount; // CDmeCountedElementRef - for preventing elements from being truly deleted, mainly used by undo and file root + DmAttributeList_t m_attributes; +}; + + +//----------------------------------------------------------------------------- +// Base DmElement we inherit from in higher-level classes +//----------------------------------------------------------------------------- +class CDmElement +{ +public: + // Can be overridden by derived classes + virtual void OnAttributeChanged( CDmAttribute *pAttribute ) {} + virtual void PreAttributeChanged( CDmAttribute *pAttribute ) {} + virtual void OnAttributeArrayElementAdded( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {} + virtual void OnAttributeArrayElementRemoved( CDmAttribute *pAttribute, int nFirstElem, int nLastElem ) {} + virtual void Resolve() {} + virtual bool IsA( UtlSymId_t typeSymbol ) const; + virtual int GetInheritanceDepth( UtlSymId_t typeSymbol ) const; + virtual void OnElementUnserialized() {} + virtual int AllocatedSize() const { return sizeof( CDmElement ); } + + // Returns the element handle + DmElementHandle_t GetHandle() const; + + // Attribute iteration, finding + // NOTE: Passing a type into GetAttribute will return NULL if the attribute exists but isn't that type + bool HasAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const; + CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ); + const CDmAttribute *GetAttribute( const char *pAttributeName, DmAttributeType_t type = AT_UNKNOWN ) const; + int AttributeCount() const; + CDmAttribute* FirstAttribute(); + const CDmAttribute* FirstAttribute() const; + + // Element name, type, ID + // WARNING: SetType() should only be used by format conversion methods (dmxconvert) + UtlSymId_t GetType() const; + const char * GetTypeString() const; + const char * GetName() const; + const DmObjectId_t& GetId() const; + void SetType( const char *pType ); + void SetName( const char* pName ); + + // Attribute management + CDmAttribute * AddAttribute( const char *pAttributeName, DmAttributeType_t type ); + template< class E > CDmAttribute* AddAttributeElement( const char *pAttributeName ); + template< class E > CDmAttribute* AddAttributeElementArray( const char *pAttributeName ); + void RemoveAttribute( const char *pAttributeName ); + void RemoveAttributeByPtr( CDmAttribute *pAttributeName ); + void RenameAttribute( const char *pAttributeName, const char *pNewName ); + + // get attribute value + template< class T > const T& GetValue( const char *pAttributeName ) const; + template< class T > const T& GetValue( const char *pAttributeName, const T& defaultValue ) const; + const char * GetValueString( const char *pAttributeName ) const; + template< class E > E* GetValueElement( const char *pAttributeName ) const; + + // set attribute value + CDmAttribute* SetValue( const char *pAttributeName, const void *value, size_t size ); + template< class T > CDmAttribute* SetValue( const char *pAttributeName, const T& value ); + template< class E > CDmAttribute* SetValue( const char *pAttributeName, E* value ); + + // set attribute value if the attribute doesn't already exist + CDmAttribute* InitValue( const char *pAttributeName, const void *value, size_t size ); + template< class T > CDmAttribute* InitValue( const char *pAttributeName, const T& value ); + template< class E > CDmAttribute* InitValue( const char *pAttributeName, E* value ); + + // Parses an attribute from a string + // Doesn't create an attribute if it doesn't exist and always preserves attribute type + void SetValueFromString( const char *pAttributeName, const char *value ); + const char *GetValueAsString( const char *pAttributeName, char *pBuffer, size_t buflen ) const; + + // Helpers for our RTTI + template< class E > bool IsA() const; + bool IsA( const char *pTypeName ) const; + int GetInheritanceDepth( const char *pTypeName ) const; + static CUtlSymbol GetStaticTypeSymbol(); + + // Indicates whether this element should be copied or not + void SetShared( bool bShared ); + bool IsShared() const; + + // Copies an element and all its attributes + CDmElement* Copy( TraversalDepth_t depth = TD_DEEP ) const; + + // Copies attributes from a specified element + void CopyAttributesTo( CDmElement *pCopy, TraversalDepth_t depth = TD_DEEP ) const; + + // recursively set fileid's, with option to only change elements in the matched file + void SetFileId( DmFileId_t fileid, TraversalDepth_t depth, bool bOnlyIfMatch = false ); + DmFileId_t GetFileId() const; + + bool IsAccessible() const; + void MarkAccessible( bool bAccessible ); + void MarkAccessible( TraversalDepth_t depth = TD_ALL ); + + // returns the first path to the element found traversing all element/element + // array attributes - not necessarily the shortest. + // cycle-safe (skips any references to elements in the current path) + // but may re-traverse elements via different paths + bool FindElement( const CDmElement *pElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const; + bool FindReferer( DmElementHandle_t hElement, CUtlVector< ElementPathItem_t > &elementPath, TraversalDepth_t depth ) const; + void RemoveAllReferencesToElement( CDmElement *pElement ); + bool IsStronglyReferenced() { return m_ref.IsStronglyReferenced(); } + + // Estimates the memory usage of the element, its attributes, and child elements + int EstimateMemoryUsage( TraversalDepth_t depth = TD_DEEP ); + +protected: + // NOTE: These are protected to ensure that the factory is the only thing that can create these + CDmElement( DmElementHandle_t handle, const char *objectType, const DmObjectId_t &id, const char *objectName, DmFileId_t fileid ); + virtual ~CDmElement(); + + // Used by derived classes to do construction and setting up CDmaVars + void OnConstruction() { } + void OnDestruction() { } + virtual void PerformConstruction(); + virtual void PerformDestruction(); + + // Internal methods related to RTII + static void SetTypeSymbol( CUtlSymbol sym ); + static bool IsA_Implementation( CUtlSymbol typeSymbol ); + static int GetInheritanceDepth_Implementation( CUtlSymbol typeSymbol, int nCurrentDepth ); + + // Internal method for creating a copy of this element + CDmElement* CopyInternal( TraversalDepth_t depth = TD_DEEP ) const; + + // helper for making attributevarelementarray cleanup easier + template< class T > static void DeleteAttributeVarElementArray( T &array ); + +private: + typedef CUtlMap< DmElementHandle_t, DmElementHandle_t, int > CRefMap; + + // Bogus constructor + CDmElement(); + + // internal recursive copy method - builds refmap of old element's handle -> copy's handle, and uses it to fixup references + void CopyAttributesTo( CDmElement *pCopy, CRefMap &refmap, TraversalDepth_t depth ) const; + void CopyElementAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const; + void CopyElementArrayAttribute( const CDmAttribute *pAttr, CDmAttribute *pCopyAttr, CRefMap &refmap, TraversalDepth_t depth ) const; + void FixupReferences( CUtlHashFast< DmElementHandle_t > &visited, const CRefMap &refmap, TraversalDepth_t depth ); + + void SetFileId( DmFileId_t fileid ); + void SetFileId_R( CUtlHashFast< DmElementHandle_t > &visited, DmFileId_t fileid, TraversalDepth_t depth, DmFileId_t match, bool bOnlyIfMatch ); + + CDmAttribute* CreateAttribute( const char *pAttributeName, DmAttributeType_t type ); + void RemoveAttribute( CDmAttribute **pAttrRef ); + CDmAttribute* AddExternalAttribute( const char *pAttributeName, DmAttributeType_t type, void *pMemory ); + CDmAttribute *FindAttribute( const char *pAttributeName ) const; + + void Purge(); + void SetId( const DmObjectId_t &id ); + + bool IsDirty() const; + void MarkDirty( bool dirty = true ); + void MarkAttributesClean(); + void MarkBeingUnserialized( bool beingUnserialized = true ); + bool IsBeingUnserialized() const; + + // Used by the undo system only. + void AddAttributeByPtr( CDmAttribute *ptr ); + void RemoveAttributeByPtrNoDelete( CDmAttribute *ptr ); + + // Should only be called from datamodel, who will take care of changing the fileset entry as well + void ChangeHandle( DmElementHandle_t handle ); + + // returns element reference struct w/ list of referrers and handle count + DmElementReference_t* GetReference(); + void SetReference( const DmElementReference_t &ref ); + + // Estimates memory usage + int EstimateMemoryUsage( CUtlHash< DmElementHandle_t > &visited, TraversalDepth_t depth, int *pCategories ); + +protected: + CDmaString m_Name; + +private: + CDmAttribute *m_pAttributes; + DmElementReference_t m_ref; + UtlSymId_t m_Type; + bool m_bDirty : 1; + bool m_bBeingUnserialized : 1; + bool m_bIsAcessible : 1; + unsigned char m_nReserved; // Makes Id be quad aligned + DmObjectId_t m_Id; + DmFileId_t m_fileId; + + // Stores the type symbol + static CUtlSymbol m_classType; + + // Factories can access our constructors + template friend class CDmElementFactory; + template friend class CDmAbstractElementFactory; + template< class T > friend class CDmaVar; + template< class T > friend class CDmaArray; + template< class T > friend class CDmaElementArray; + template< class T, class B > friend class CDmaDecorator; + template< class T > friend class CDmrElementArray; + + friend class CDmElementFactoryDefault; + friend class CDmeElementAccessor; + friend class CDmeOperator; + + friend void CopyElements( const CUtlVector< CDmElement* > &from, CUtlVector< CDmElement* > &to, TraversalDepth_t depth ); +}; + + + +inline void DestroyElement( CDmElement *pElement ) +{ + if ( pElement ) + { + g_pDataModel->DestroyElement( pElement->GetHandle() ); + } +} + +void DestroyElement( CDmElement *pElement, TraversalDepth_t depth ); + + +//----------------------------------------------------------------------------- +// copy groups of elements together so that references between them are maintained +//----------------------------------------------------------------------------- +void CopyElements( const CUtlVector< CDmElement* > &from, CUtlVector< CDmElement* > &to, TraversalDepth_t depth = TD_DEEP ); + + +//----------------------------------------------------------------------------- +// allows elements to chain OnAttributeChanged up to their parents (or at least, referrers) +//----------------------------------------------------------------------------- +void InvokeOnAttributeChangedOnReferrers( DmElementHandle_t hElement, CDmAttribute *pChangedAttr ); + + + + + +//----------------------------------------------------------------------------- +// Returns the type, name, id, fileId +//----------------------------------------------------------------------------- +inline UtlSymId_t CDmElement::GetType() const +{ + return m_Type; +} + +inline const char *CDmElement::GetTypeString() const +{ + return g_pDataModel->GetString( m_Type ); +} + +inline const char *CDmElement::GetName() const +{ + return m_Name.Get(); +} + +inline void CDmElement::SetName( const char* pName ) +{ + m_Name.Set( pName ); +} + +inline const DmObjectId_t& CDmElement::GetId() const +{ + return m_Id; +} + +inline DmFileId_t CDmElement::GetFileId() const +{ + return m_fileId; +} + + +//----------------------------------------------------------------------------- +// Controls whether the element should be copied by default +//----------------------------------------------------------------------------- +inline void CDmElement::SetShared( bool bShared ) +{ + if ( bShared ) + { + SetValue< bool >( "shared", true ); + } + else + { + RemoveAttribute( "shared" ); + } +} + +inline bool CDmElement::IsShared() const +{ + return GetValue< bool >( "shared" ); // if attribute doesn't exist, returns default bool value, which is false +} + + +//----------------------------------------------------------------------------- +// Copies attributes from a specified element +//----------------------------------------------------------------------------- +inline CDmElement* CDmElement::Copy( TraversalDepth_t depth ) const +{ + return CopyInternal( depth ); +} + + +//----------------------------------------------------------------------------- +// RTTI +//----------------------------------------------------------------------------- +inline bool CDmElement::IsA_Implementation( CUtlSymbol typeSymbol ) +{ + return ( m_classType == typeSymbol ) || ( UTL_INVAL_SYMBOL == typeSymbol ); +} + +inline int CDmElement::GetInheritanceDepth_Implementation( CUtlSymbol typeSymbol, int nCurrentDepth ) +{ + return IsA_Implementation( typeSymbol ) ? nCurrentDepth : -1; +} + +inline CUtlSymbol CDmElement::GetStaticTypeSymbol() +{ + return m_classType; +} + +inline bool CDmElement::IsA( const char *pTypeName ) const +{ + CUtlSymbol typeSymbol = g_pDataModel->GetSymbol( pTypeName ); + return IsA( typeSymbol ); +} + +template< class E > inline bool CDmElement::IsA() const +{ + return IsA( E::GetStaticTypeSymbol() ); +} + + +//----------------------------------------------------------------------------- +// Helper for finding elements that refer to this element +//----------------------------------------------------------------------------- +template< class T > +T *FindReferringElement( CDmElement *pElement, const char *pAttrName, bool bMustBeInSameFile = true ) +{ + return FindReferringElement< T >( pElement, g_pDataModel->GetSymbol( pAttrName ), bMustBeInSameFile ); +} + + +void RemoveElementFromRefereringAttributes( CDmElement *pElement, bool bPreserveOrder = true ); + + + +//----------------------------------------------------------------------------- +// +// element-specific unique name generation methods +// +//----------------------------------------------------------------------------- + +// returns startindex if none found, 2 if only "prefix" found, and n+1 if "prefixn" found +int GenerateUniqueNameIndex( const char *prefix, const CUtlVector< DmElementHandle_t > &array, int startindex = -1 ); + +bool GenerateUniqueName( char *name, int memsize, const char *prefix, const CUtlVector< DmElementHandle_t > &array ); + +void MakeElementNameUnique( CDmElement *pElement, const char *prefix, const CUtlVector< DmElementHandle_t > &array, bool forceIndex = false ); + + +//----------------------------------------------------------------------------- +// helper for making attributevarelementarray cleanup easier +//----------------------------------------------------------------------------- +template< class T > +inline void CDmElement::DeleteAttributeVarElementArray( T &array ) +{ + int nElements = array.Count(); + for ( int i = 0; i < nElements; ++i ) + { + g_pDataModel->DestroyElement( array.GetHandle( i ) ); + } + array.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Default size computation +//----------------------------------------------------------------------------- +template< class T > +int DmeEstimateMemorySize( T* pElement ) +{ + return sizeof( T ); +} + + +//----------------------------------------------------------------------------- +// Helper macro to create an element; this is used for elements that are helper base classes +//----------------------------------------------------------------------------- +#define DEFINE_UNINSTANCEABLE_ELEMENT( className, baseClassName ) \ + protected: \ + className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \ + baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \ + { \ + } \ + virtual ~className() \ + { \ + } \ + void OnConstruction(); \ + void OnDestruction(); \ + virtual void PerformConstruction() \ + { \ + BaseClass::PerformConstruction(); \ + OnConstruction(); \ + } \ + virtual void PerformDestruction() \ + { \ + OnDestruction(); \ + BaseClass::PerformDestruction(); \ + } \ + virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \ + \ + private: \ + typedef baseClassName BaseClass; \ + + +//----------------------------------------------------------------------------- +// Helper macro to create the class factory +//----------------------------------------------------------------------------- +#define DEFINE_ELEMENT( className, baseClassName ) \ + public: \ + virtual bool IsA( UtlSymId_t typeSymbol ) const \ + { \ + return IsA_Implementation( typeSymbol );\ + } \ + \ + bool IsA( const char *pTypeName ) const \ + { \ + CUtlSymbol typeSymbol = g_pDataModel->GetSymbol( pTypeName ); \ + return IsA( typeSymbol ); \ + } \ + \ + template< class T > bool IsA() const \ + { \ + return IsA( T::GetStaticTypeSymbol() ); \ + } \ + \ + virtual int GetInheritanceDepth( UtlSymId_t typeSymbol ) const \ + { \ + return GetInheritanceDepth_Implementation( typeSymbol, 0 ); \ + } \ + \ + static CUtlSymbol GetStaticTypeSymbol( ) \ + { \ + return m_classType; \ + } \ + \ + className* Copy( TraversalDepth_t depth = TD_DEEP ) const \ + { \ + return static_cast< className* >( CopyInternal( depth ) ); \ + } \ + protected: \ + className( DmElementHandle_t handle, const char *pElementTypeName, const DmObjectId_t &id, const char *pElementName, DmFileId_t fileid ) : \ + baseClassName( handle, pElementTypeName, id, pElementName, fileid ) \ + { \ + } \ + virtual ~className() \ + { \ + } \ + void OnConstruction(); \ + void OnDestruction(); \ + virtual void PerformConstruction() \ + { \ + BaseClass::PerformConstruction(); \ + OnConstruction(); \ + } \ + virtual void PerformDestruction() \ + { \ + OnDestruction(); \ + BaseClass::PerformDestruction(); \ + } \ + static void SetTypeSymbol( CUtlSymbol typeSymbol ) \ + { \ + m_classType = typeSymbol; \ + } \ + \ + static bool IsA_Implementation( CUtlSymbol typeSymbol ) \ + { \ + if ( typeSymbol == m_classType ) \ + return true; \ + return BaseClass::IsA_Implementation( typeSymbol ); \ + } \ + \ + static int GetInheritanceDepth_Implementation( CUtlSymbol typeSymbol, int nCurrentDepth ) \ + { \ + if ( typeSymbol == m_classType ) \ + return nCurrentDepth; \ + return BaseClass::GetInheritanceDepth_Implementation( typeSymbol, nCurrentDepth+1 );\ + } \ + virtual int AllocatedSize() const { return DmeEstimateMemorySize( this ); } \ + \ + private: \ + typedef baseClassName BaseClass; \ + template friend class CDmElementFactory; \ + template friend class CDmAbstractElementFactory; \ + static CUtlSymbol m_classType + +#define IMPLEMENT_ELEMENT( className ) \ + CUtlSymbol className::m_classType = UTL_INVAL_SYMBOL; + + +#endif // DMELEMENT_H diff --git a/public/datamodel/dmelementfactoryhelper.h b/public/datamodel/dmelementfactoryhelper.h new file mode 100644 index 0000000..c4847cc --- /dev/null +++ b/public/datamodel/dmelementfactoryhelper.h @@ -0,0 +1,190 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMELEMENTFACTORYHELPER_H +#define DMELEMENTFACTORYHELPER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/idatamodel.h" +#include "datamodel/dmelement.h" +#include "datamodel/dmattribute.h" +#include "datamodel/dmattributevar.h" +#include "tier1/utlvector.h" +#include "tier1/utlsymbol.h" + + +//----------------------------------------------------------------------------- +// Internal interface for IDmElementFactory +//----------------------------------------------------------------------------- +class IDmElementFactoryInternal : public IDmElementFactory +{ +public: + virtual void SetElementTypeSymbol( CUtlSymbol sym ) = 0; + virtual bool IsAbstract() const = 0; +}; + + +//----------------------------------------------------------------------------- +// Class used to register factories into a global list +//----------------------------------------------------------------------------- +class CDmElementFactoryHelper +{ +public: + // Static list of helpers + static CDmElementFactoryHelper *s_pHelpers[2]; + + // Create all the hud elements + static void InstallFactories( ); + +public: + // Construction + CDmElementFactoryHelper( const char *pClassName, IDmElementFactoryInternal *pFactory, bool bIsStandardFactory ); + + // Accessors + CDmElementFactoryHelper *GetNext( void ); + + const char *GetClassname(); + IDmElementFactoryInternal *GetFactory(); + +private: + // Next factory in list + CDmElementFactoryHelper *m_pNext; + // Creation function to use for this technology + IDmElementFactoryInternal *m_pFactory; + const char *m_pszClassname; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline const char *CDmElementFactoryHelper::GetClassname() +{ + return m_pszClassname; +} + +inline IDmElementFactoryInternal *CDmElementFactoryHelper::GetFactory() +{ + return m_pFactory; +} + + +//----------------------------------------------------------------------------- +// Helper Template factory for simple creation of factories +//----------------------------------------------------------------------------- +template +class CDmElementFactory : public IDmElementFactoryInternal +{ +public: + CDmElementFactory( const char *pLookupName ) : m_pLookupName( pLookupName ) {} + + // Creation, destruction + virtual CDmElement* Create( DmElementHandle_t handle, const char *pElementType, const char *pElementName, DmFileId_t fileid, const DmObjectId_t &id ) + { + return new T( handle, m_pLookupName, id, pElementName, fileid ); + } + + virtual void Destroy( DmElementHandle_t hElement ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + if ( pElement ) + { + T *pActualElement = static_cast< T* >( pElement ); + delete pActualElement; + } + } + + // Sets the type symbol, used for "isa" implementation + virtual void SetElementTypeSymbol( CUtlSymbol sym ) + { + T::SetTypeSymbol( sym ); + } + + virtual bool IsAbstract() const { return false; } + +private: + const char *m_pLookupName; +}; + + +template < class T > +class CDmAbstractElementFactory : public IDmElementFactoryInternal +{ +public: + CDmAbstractElementFactory() {} + + // Creation, destruction + virtual CDmElement* Create( DmElementHandle_t handle, const char *pElementType, const char *pElementName, DmFileId_t fileid, const DmObjectId_t &id ) + { + return NULL; + } + + virtual void Destroy( DmElementHandle_t hElement ) + { + } + + // Sets the type symbol, used for "isa" implementation + virtual void SetElementTypeSymbol( CUtlSymbol sym ) + { + T::SetTypeSymbol( sym ); + } + + virtual bool IsAbstract() const { return true; } + +private: +}; + + +//----------------------------------------------------------------------------- +// Helper macro to create the class factory +//----------------------------------------------------------------------------- +#if defined( MOVIEOBJECTS_LIB ) || defined ( DATAMODEL_LIB ) || defined ( DMECONTROLS_LIB ) + +#define IMPLEMENT_ELEMENT_FACTORY( lookupName, className ) \ + IMPLEMENT_ELEMENT( className ) \ + CDmElementFactory< className > g_##className##_Factory( #lookupName ); \ + CDmElementFactoryHelper g_##className##_Helper( #lookupName, &g_##className##_Factory, true ); \ + className *g_##className##LinkerHack = NULL; + +#define IMPLEMENT_ABSTRACT_ELEMENT( lookupName, className ) \ + IMPLEMENT_ELEMENT( className ) \ + CDmAbstractElementFactory< className > g_##className##_Factory; \ + CDmElementFactoryHelper g_##className##_Helper( #lookupName, &g_##className##_Factory, true ); \ + className *g_##className##LinkerHack = NULL; + +#else + +#define IMPLEMENT_ELEMENT_FACTORY( lookupName, className ) \ + IMPLEMENT_ELEMENT( className ) \ + CDmElementFactory< className > g_##className##_Factory( #lookupName ); \ + CDmElementFactoryHelper g_##className##_Helper( #lookupName, &g_##className##_Factory, false ); \ + className *g_##className##LinkerHack = NULL; + +#define IMPLEMENT_ABSTRACT_ELEMENT( lookupName, className ) \ + IMPLEMENT_ELEMENT( className ) \ + CDmAbstractElementFactory< className > g_##className##_Factory; \ + CDmElementFactoryHelper g_##className##_Helper( #lookupName, &g_##className##_Factory, false ); \ + className *g_##className##LinkerHack = NULL; + +#endif + + +// Used by classes defined in movieobjects or scenedatabase that must be explicitly installed +#define IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( lookupName, className ) \ + IMPLEMENT_ELEMENT( className ) \ + CDmElementFactory< className > g_##className##_Factory( #lookupName ); \ + CDmElementFactoryHelper g_##className##_Helper( #lookupName, &g_##className##_Factory, false ); \ + className *g_##className##LinkerHack = NULL; + +//----------------------------------------------------------------------------- +// Installs dm element factories +//----------------------------------------------------------------------------- +void InstallDmElementFactories( ); + + +#endif // DMELEMENTFACTORYHELPER_H diff --git a/public/datamodel/dmelementhandle.h b/public/datamodel/dmelementhandle.h new file mode 100644 index 0000000..319f308 --- /dev/null +++ b/public/datamodel/dmelementhandle.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMELEMENTHANDLE_H +#define DMELEMENTHANDLE_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// handle to an CDmElement +//----------------------------------------------------------------------------- +#define PERFORM_HANDLE_TYPECHECKING 0 +#if PERFORM_HANDLE_TYPECHECKING + +// this is here to make sure we're being type-safe about element handles +// otherwise, the compiler lets us cast to bool incorrectly +// the other solution would be to redefine DmElementHandle_t s.t. DMELEMENT_HANDLE_INVALID==0 +struct DmElementHandle_t +{ + DmElementHandle_t() : handle( 0xffffffff ) {} + explicit DmElementHandle_t( int h ) : handle( h ) {} + inline bool operator==( const DmElementHandle_t &h ) const { return handle == h.handle; } + inline bool operator!=( const DmElementHandle_t &h ) const { return handle != h.handle; } + inline bool operator<( const DmElementHandle_t &h ) const { return handle < h.handle; } +// inline operator int() const { return handle; } // if we're okay with implicit int casts, uncomment this method + int handle; +}; +const DmElementHandle_t DMELEMENT_HANDLE_INVALID; + +#else // PERFORM_HANDLE_TYPECHECKING + +enum DmElementHandle_t +{ + DMELEMENT_HANDLE_INVALID = 0xffffffff +}; + +#endif // PERFORM_HANDLE_TYPECHECKING + + + +#endif // DMELEMENTHANDLE_H diff --git a/public/datamodel/dmvar.h b/public/datamodel/dmvar.h new file mode 100644 index 0000000..940e138 --- /dev/null +++ b/public/datamodel/dmvar.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMVAR_H +#define DMVAR_H +#ifdef _WIN32 +#pragma once +#endif + + +class CDmAttribute; + +//----------------------------------------------------------------------------- +// Helper template for external attributes +//----------------------------------------------------------------------------- +template< typename T > +class CDmaVar +{ + typedef typename CDmAttributeInfo< T >::StorageType_t D; + +public: + CDmaVar( ); + + // Setup to be used in OnConstruction methods of DmElements + void Init( CDmElement *pOwner, const char *pAttributeName, int flags = 0 ); + void InitAndSet( CDmElement *pOwner, const char *pAttributeName, const T &value, int flags = 0 ); + + // Set/get + const T& Set( const T &val ); + const T& Get() const; + + // Cast operators + operator const T&() const; + const T* operator->() const; + + // Assignment operator + const CDmaVar& operator=( const CDmaVar& src ); + + // Math utility operations + const T& operator=( const T &val ); + const T& operator+=( const T &val ); + const T& operator-=( const T &val ); + const T& operator/=( const T &val ); + const T& operator*=( const T &val ); + const T& operator^=( const T &val ); + const T& operator|=( const T &val ); + const T& operator&=( const T &val ); + T operator++(); + T operator--(); + T operator++( int ); // postfix version.. + T operator--( int ); // postfix version.. + + // Returns the attribute associated with the var + CDmAttribute *GetAttribute(); + const CDmAttribute *GetAttribute() const; + + // Is the attribute dirty? + bool IsDirty() const; + +protected: + const T& Value() const; + T& Value(); + const D& Storage() const; + D& Storage(); + +private: + D m_Storage; + +protected: + CDmAttribute *m_pAttribute; +}; + +//----------------------------------------------------------------------------- +// Specialization for string +//----------------------------------------------------------------------------- +class CDmaString : public CDmaVar< CUtlString > +{ +public: + const char *Get( ) const; + operator const char*() const; + + void Set( const char *pValue ); + CDmaString &operator=( const char *src ); + const CDmaString& operator=( const CDmaString& src ); + + // Returns strlen + int Length() const; +}; + +#endif // DMVAR_H diff --git a/public/datamodel/idatamodel.h b/public/datamodel/idatamodel.h new file mode 100644 index 0000000..16f2c73 --- /dev/null +++ b/public/datamodel/idatamodel.h @@ -0,0 +1,938 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IDATAMODEL_H +#define IDATAMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "tier1/utlvector.h" +#include "tier1/utlsymbol.h" +#include "appframework/IAppSystem.h" +#include "datamodel/dmattributetypes.h" + + +//----------------------------------------------------------------------------- +// Forward declarations: +//----------------------------------------------------------------------------- +class CDmAttribute; +class CDmElement; +class IDmeOperator; +class IElementForKeyValueCallback; + +struct DmValueBase_t; +class CUtlBuffer; +class KeyValues; +class CUtlSymbolTable; +class CUtlCharConversion; + + +//----------------------------------------------------------------------------- +// data file format info +//----------------------------------------------------------------------------- +#define DMX_LEGACY_VERSION_STARTING_TOKEN "" + +#define DMX_VERSION_STARTING_TOKEN "" + +#define GENERIC_DMX_FORMAT "dmx" + + +enum +{ + DMX_MAX_FORMAT_NAME_MAX_LENGTH = 64, + DMX_MAX_HEADER_LENGTH = 40 + 2 * DMX_MAX_FORMAT_NAME_MAX_LENGTH, +}; + +struct DmxHeader_t +{ + char encodingName[ DMX_MAX_FORMAT_NAME_MAX_LENGTH ]; + int nEncodingVersion; + char formatName[ DMX_MAX_FORMAT_NAME_MAX_LENGTH ]; + int nFormatVersion; + + DmxHeader_t() : nEncodingVersion( -1 ), nFormatVersion( -1 ) + { + encodingName[ 0 ] = formatName[ 0 ] = '\0'; + } +}; + + +//----------------------------------------------------------------------------- +// element framework phases +//----------------------------------------------------------------------------- +enum DmPhase_t +{ + PH_EDIT, + PH_EDIT_APPLY, + PH_EDIT_RESOLVE, + PH_DEPENDENCY, + PH_OPERATE, + PH_OPERATE_RESOLVE, + PH_OUTPUT, +}; + + +//----------------------------------------------------------------------------- +// file id - also used to refer to elements that don't have file associations +//----------------------------------------------------------------------------- +enum DmFileId_t +{ + DMFILEID_INVALID = 0xffffffff +}; + +//----------------------------------------------------------------------------- +// Handle to an CDmAttribute +//----------------------------------------------------------------------------- +enum DmAttributeHandle_t +{ + DMATTRIBUTE_HANDLE_INVALID = 0xffffffff +}; + +//----------------------------------------------------------------------------- +// Handle to an DmAttributeList_t +//----------------------------------------------------------------------------- +enum DmAttributeReferenceIterator_t +{ + DMATTRIBUTE_REFERENCE_ITERATOR_INVALID = 0 +}; + +//----------------------------------------------------------------------------- +// element framework interface +//----------------------------------------------------------------------------- +abstract_class IDmElementFramework : public IAppSystem +{ +public: + // Methods of IAppSystem + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + virtual DmPhase_t GetPhase() = 0; + + virtual void SetOperators( const CUtlVector< IDmeOperator* > &operators ) = 0; + + virtual void BeginEdit() = 0; // ends in edit phase, forces apply/resolve if from edit phase + virtual void Operate( bool bResolve ) = 0; // ends in output phase + virtual void Resolve() = 0; +}; + + +//----------------------------------------------------------------------------- +// Used only by aplpications to hook in the element framework +//----------------------------------------------------------------------------- +#define VDMELEMENTFRAMEWORK_VERSION "VDmElementFrameworkVersion001" + + +//----------------------------------------------------------------------------- +// Main interface +//----------------------------------------------------------------------------- +extern IDmElementFramework *g_pDmElementFramework; + + +//----------------------------------------------------------------------------- +// datamodel operator interface - for all elements that need to be sorted in the operator dependency graph +//----------------------------------------------------------------------------- +abstract_class IDmeOperator +{ +public: + virtual bool IsDirty() = 0; // ie needs to operate + virtual void Operate() = 0; + + virtual void GetInputAttributes ( CUtlVector< CDmAttribute * > &attrs ) = 0; + virtual void GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs ) = 0; +}; + +//----------------------------------------------------------------------------- +// Class factory methods: +//----------------------------------------------------------------------------- +class IDmElementFactory +{ +public: + // Creation, destruction + virtual CDmElement* Create( DmElementHandle_t handle, const char *pElementType, const char *pElementName, DmFileId_t fileid, const DmObjectId_t &id ) = 0; + virtual void Destroy( DmElementHandle_t hElement ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Various serialization methods can be installed into the data model factory +//----------------------------------------------------------------------------- +enum DmConflictResolution_t +{ + CR_DELETE_NEW, + CR_DELETE_OLD, + CR_COPY_NEW, + CR_FORCE_COPY, +}; + +// convert files to elements and back +// current file encodings supported: binary, xml, xml_flat, keyvalues2, keyvalues2_flat, keyvalues (vmf/vmt/actbusy), text? (qc/obj) +class IDmSerializer +{ +public: + virtual const char *GetName() const = 0; + virtual const char *GetDescription() const = 0; + virtual bool IsBinaryFormat() const = 0; + virtual bool StoresVersionInFile() const = 0; + virtual int GetCurrentVersion() const = 0; + + // Write into the UtlBuffer, return true if successful + // if we decide to implement non-identity conversions between formats on write, then the source and dest format will need to be passed in here + virtual bool Serialize( CUtlBuffer &buf, CDmElement *pRoot ) = 0; + + // Read from the UtlBuffer, return true if successful, and return the read-in root in ppRoot. + virtual bool Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion, + const char *pSourceFormatName, int nSourceFormatVersion, + DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot ) = 0; +}; + +// convert legacy elements to non-legacy elements +// legacy formats include: sfm_vN, binary_vN, keyvalues2_v1, keyvalues2_flat_v1, xml, xml_flat +// where N is a version number (1..9 for sfm, 1..2 for binary) +class IDmLegacyUpdater +{ +public: + virtual const char *GetName() const = 0; + virtual bool IsLatestVersion() const = 0; + + // Updates ppRoot to first non-legacy generic dmx format, returns false if the conversion fails + virtual bool Update( CDmElement **ppRoot ) = 0; +}; + +// converts old elements to new elements +// current formats include: sfm session, animset presets, particle definitions, exported maya character, etc. +class IDmFormatUpdater +{ +public: + virtual const char *GetName() const = 0; + virtual const char *GetDescription() const = 0; + virtual const char *GetExtension() const = 0; + virtual int GetCurrentVersion() const = 0; + virtual const char *GetDefaultEncoding() const = 0; + + // Converts pSourceRoot from nSourceVersion to the current version, returns false if the conversion fails + virtual bool Update( CDmElement **pRoot, int nSourceVersion ) = 0; +}; + +//----------------------------------------------------------------------------- +// Interface for callbacks to supply element types for specific keys inside keyvalues files +//----------------------------------------------------------------------------- +class IElementForKeyValueCallback +{ +public: + virtual const char *GetElementForKeyValue( const char *pszKeyName, int iNestingLevel ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Optional helper passed in with clipboard data which is called when it's time to clean up the clipboard data in case the application +// had some dynamically allocated data attached to a KV SetPtr object... +//----------------------------------------------------------------------------- +abstract_class IClipboardCleanup +{ +public: + virtual void ReleaseClipboardData( CUtlVector< KeyValues * >& list ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Can be installed to be called back when data changes +//----------------------------------------------------------------------------- +enum DmNotifySource_t +{ + // Sources + NOTIFY_SOURCE_APPLICATION = 0, + NOTIFY_SOURCE_UNDO, + NOTIFY_SOURCE_FIRST_DME_CONTROL_SOURCE = 4, // Sources from dme_controls starts here + NOTIFY_SOURCE_FIRST_APPLICATION_SOURCE = 8, // Sources from applications starts here +}; + +enum DmNotifyFlags_t +{ + // Does this dirty the document? + NOTIFY_SOURCE_BITS = 8, + NOTIFY_SETDIRTYFLAG = (1<& list ) = 0; + + virtual void AddUndoElement( IUndoElement *pElement ) = 0; + virtual UtlSymId_t GetUndoDescInternal( const char *context ) = 0; + virtual UtlSymId_t GetRedoDescInternal( const char *context ) = 0; + + virtual void EmptyClipboard() = 0; + virtual void SetClipboardData( CUtlVector< KeyValues * >& data, IClipboardCleanup *pfnOptionalCleanuFunction = 0 ) = 0; + virtual void AddToClipboardData( KeyValues *add ) = 0; + virtual void GetClipboardData( CUtlVector< KeyValues * >& data ) = 0; + virtual bool HasClipboardData() const = 0; + + // Handles to attributes + virtual CDmAttribute * GetAttribute( DmAttributeHandle_t h ) = 0; + virtual bool IsAttributeHandleValid( DmAttributeHandle_t h ) const = 0; + + // file id reference methods + virtual int NumFileIds() = 0; + virtual DmFileId_t GetFileId( int i ) = 0; + virtual DmFileId_t FindOrCreateFileId( const char *pFilename ) = 0; + virtual void RemoveFileId( DmFileId_t fileid ) = 0; + virtual DmFileId_t GetFileId( const char *pFilename ) = 0; + virtual const char * GetFileName( DmFileId_t fileid ) = 0; + virtual void SetFileName( DmFileId_t fileid, const char *pFileName ) = 0; + virtual const char * GetFileFormat( DmFileId_t fileid ) = 0; + virtual void SetFileFormat( DmFileId_t fileid, const char *pFormat ) = 0; + virtual DmElementHandle_t GetFileRoot( DmFileId_t fileid ) = 0; + virtual void SetFileRoot( DmFileId_t fileid, DmElementHandle_t hRoot ) = 0; + virtual bool IsFileLoaded( DmFileId_t fileid ) = 0; + virtual void MarkFileLoaded( DmFileId_t fileid ) = 0; + virtual void UnloadFile( DmFileId_t fileid ) = 0; + virtual int NumElementsInFile( DmFileId_t fileid ) = 0; + + virtual void DontAutoDelete( DmElementHandle_t hElement ) = 0; + + // handle validity methods - these shouldn't really be here, but the undo system needs them... + virtual void MarkHandleInvalid( DmElementHandle_t hElement ) = 0; + virtual void MarkHandleValid( DmElementHandle_t hElement ) = 0; + + virtual DmElementHandle_t FindElement( const DmObjectId_t &id ) = 0; + + virtual DmAttributeReferenceIterator_t FirstAttributeReferencingElement( DmElementHandle_t hElement ) = 0; + virtual DmAttributeReferenceIterator_t NextAttributeReferencingElement( DmAttributeReferenceIterator_t hAttrIter ) = 0; + virtual CDmAttribute * GetAttribute( DmAttributeReferenceIterator_t hAttrIter ) = 0; + + // Install, remove notify callbacks associated w/ undo contexts + virtual bool InstallNotificationCallback( IDmNotify *pNotify ) = 0; + virtual void RemoveNotificationCallback( IDmNotify *pNotify ) = 0; + virtual bool IsSuppressingNotify( ) const = 0; + virtual void SetSuppressingNotify( bool bSuppress ) = 0; + virtual void PushNotificationScope( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0; + virtual void PopNotificationScope( bool bAbort = false ) = 0; + virtual const char *GetUndoString( UtlSymId_t sym ) = 0; + + virtual bool HasElementFactory( const char *pElementType ) const = 0; + + // Call before you make any undo records + virtual void SetUndoDepth( int nSize ) = 0; + + // Displats memory stats to the console + virtual void DisplayMemoryStats() = 0; +}; + + +//----------------------------------------------------------------------------- +// Used only by applications to hook in the data model +//----------------------------------------------------------------------------- +#define VDATAMODEL_INTERFACE_VERSION "VDataModelVersion001" + + +//----------------------------------------------------------------------------- +// Main interface accessor +//----------------------------------------------------------------------------- +extern IDataModel *g_pDataModel; + + +//----------------------------------------------------------------------------- +// Allows clients to implement customized undo elements +//----------------------------------------------------------------------------- +class CUndoElement : public IUndoElement +{ +public: + CUndoElement( const char *pDesc ) + { + m_UndoDesc = g_pDataModel->GetUndoDescInternal( pDesc ); + m_RedoDesc = g_pDataModel->GetRedoDescInternal( pDesc ); + m_pDesc = pDesc; + m_bEndOfStream = false; + } + + virtual void Release() + { + delete this; + } + + virtual const char *UndoDesc() const + { + return g_pDataModel->GetUndoString( m_UndoDesc ); + } + + virtual const char *RedoDesc() const + { + return g_pDataModel->GetUndoString( m_RedoDesc ); + } + + virtual const char *GetDesc() const + { + return m_pDesc; + } + +protected: + virtual bool IsEndOfStream() const + { + return m_bEndOfStream; + } + + virtual void SetEndOfStream( bool end ) + { + m_bEndOfStream = end; + } + + const char *m_pDesc; + CUtlSymbol m_UndoDesc; + CUtlSymbol m_RedoDesc; + bool m_bEndOfStream; + +private: + friend class CUndoManager; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Simple helper class +//----------------------------------------------------------------------------- +class CUndoScopeGuard +{ +public: + explicit CUndoScopeGuard( const char *udesc, const char *rdesc = NULL ) + { + m_bReleased = false; + m_bNotify = false; + m_pNotify = NULL; + g_pDataModel->StartUndo( udesc, rdesc ? rdesc : udesc ); + } + + explicit CUndoScopeGuard( int nChainingID, char const *udesc ) + { + m_bReleased = false; + m_bNotify = false; + m_pNotify = NULL; + g_pDataModel->StartUndo( udesc, udesc, nChainingID ); + } + + explicit CUndoScopeGuard( int nNotifySource, int nNotifyFlags, const char *udesc, const char *rdesc = NULL, int nChainingID = 0 ) + { + m_bReleased = false; + m_bNotify = true; + m_pNotify = NULL; + g_pDataModel->StartUndo( udesc, rdesc ? rdesc : udesc, nChainingID ); + g_pDataModel->PushNotificationScope( udesc, nNotifySource, nNotifyFlags ); + } + + explicit CUndoScopeGuard( int nNotifySource, int nNotifyFlags, IDmNotify *pNotify, const char *udesc, const char *rdesc = NULL, int nChainingID = 0 ) + { + m_bReleased = false; + m_bNotify = true; + m_pNotify = NULL; + g_pDataModel->StartUndo( udesc, rdesc ? rdesc : udesc, nChainingID ); + if ( pNotify ) + { + if ( g_pDataModel->InstallNotificationCallback( pNotify ) ) + { + m_pNotify = pNotify; + } + } + g_pDataModel->PushNotificationScope( udesc, nNotifySource, nNotifyFlags ); + } + + ~CUndoScopeGuard() + { + Release(); + } + + void Release() + { + if ( !m_bReleased ) + { + g_pDataModel->FinishUndo(); + if ( m_bNotify ) + { + g_pDataModel->PopNotificationScope( ); + m_bNotify = false; + } + if ( m_pNotify ) + { + g_pDataModel->RemoveNotificationCallback( m_pNotify ); + m_pNotify = NULL; + } + m_bReleased = true; + } + } + + void Abort() + { + if ( !m_bReleased ) + { + g_pDataModel->AbortUndoableOperation(); + if ( m_bNotify ) + { + g_pDataModel->PopNotificationScope( true ); + m_bNotify = false; + } + if ( m_pNotify ) + { + g_pDataModel->RemoveNotificationCallback( m_pNotify ); + m_pNotify = NULL; + } + m_bReleased = true; + } + } + +private: + IDmNotify *m_pNotify; + bool m_bReleased; + bool m_bNotify; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Simple helper class to disable Undo/Redo operations when in scope +//----------------------------------------------------------------------------- +class CChangeUndoScopeGuard +{ +public: + CChangeUndoScopeGuard( bool bNewState ) + { + m_bReleased = false; + m_bNotify = false; + m_pNotify = NULL; + m_bOldValue = g_pDataModel->IsUndoEnabled(); + g_pDataModel->SetUndoEnabled( bNewState ); + }; + + CChangeUndoScopeGuard( bool bNewState, const char *pDesc, int nNotifySource, int nNotifyFlags, IDmNotify *pNotify = NULL ) + { + m_bReleased = false; + m_bOldValue = g_pDataModel->IsUndoEnabled(); + g_pDataModel->SetUndoEnabled( bNewState ); + + m_bNotify = true; + m_pNotify = NULL; + if ( pNotify ) + { + if ( g_pDataModel->InstallNotificationCallback( pNotify ) ) + { + m_pNotify = pNotify; + } + } + g_pDataModel->PushNotificationScope( pDesc, nNotifySource, nNotifyFlags ); + }; + + ~CChangeUndoScopeGuard() + { + Release(); + } + + void Release() + { + // Releases the guard... + if ( !m_bReleased ) + { + g_pDataModel->SetUndoEnabled( m_bOldValue ); + m_bReleased = true; + if ( m_bNotify ) + { + g_pDataModel->PopNotificationScope( ); + m_bNotify = false; + } + if ( m_pNotify ) + { + g_pDataModel->RemoveNotificationCallback( m_pNotify ); + m_pNotify = NULL; + } + } + } + +private: + IDmNotify *m_pNotify; + bool m_bOldValue; + bool m_bReleased; + bool m_bNotify; +}; + +class CDisableUndoScopeGuard : public CChangeUndoScopeGuard +{ + typedef CChangeUndoScopeGuard BaseClass; + +public: + CDisableUndoScopeGuard() : BaseClass( false ) { } + CDisableUndoScopeGuard( const char *pDesc, int nNotifySource, int nNotifyFlags, IDmNotify *pNotify = NULL ) : + BaseClass( false, pDesc, nNotifySource, nNotifyFlags, pNotify ) {} +}; + +class CEnableUndoScopeGuard : public CChangeUndoScopeGuard +{ + typedef CChangeUndoScopeGuard BaseClass; + +public: + CEnableUndoScopeGuard( ) : BaseClass( true ) { } + CEnableUndoScopeGuard( const char *pDesc, int nNotifySource, int nNotifyFlags, IDmNotify *pNotify = NULL ) : + BaseClass( true, pDesc, nNotifySource, nNotifyFlags, pNotify ) {} +}; + + +#define DEFINE_SOURCE_UNDO_SCOPE_GUARD( _classnameprefix, _source ) \ + class C ## _classnameprefix ## UndoScopeGuard : public CUndoScopeGuard \ + { \ + typedef CUndoScopeGuard BaseClass; \ + \ + public: \ + C ## _classnameprefix ## UndoScopeGuard( int nNotifyFlags, const char *pUndoDesc, const char *pRedoDesc = NULL, int nChainingID = 0 ) : \ + BaseClass( _source, nNotifyFlags, pUndoDesc, pRedoDesc, nChainingID ) \ + { \ + } \ + C ## _classnameprefix ## UndoScopeGuard( int nNotifyFlags, IDmNotify *pNotify, const char *pUndoDesc, const char *pRedoDesc = NULL, int nChainingID = 0 ) : \ + BaseClass( _source, nNotifyFlags, pNotify, pUndoDesc, pRedoDesc, nChainingID ) \ + { \ + } \ + C ## _classnameprefix ## UndoScopeGuard( int nNotifyFlags, const char *pUndoDesc, int nChainingID ) : \ + BaseClass( _source, nNotifyFlags, pUndoDesc, pUndoDesc, nChainingID ) \ + { \ + } \ + }; \ + class C ## _classnameprefix ## DisableUndoScopeGuard : public CDisableUndoScopeGuard \ + { \ + typedef CDisableUndoScopeGuard BaseClass; \ + \ + public: \ + C ## _classnameprefix ## DisableUndoScopeGuard( const char *pDesc, int nNotifyFlags, IDmNotify *pNotify = NULL ) : \ + BaseClass( pDesc, _source, nNotifyFlags, pNotify ) \ + { \ + } \ + }; \ + class C ## _classnameprefix ## EnableUndoScopeGuard : public CEnableUndoScopeGuard \ + { \ + typedef CEnableUndoScopeGuard BaseClass; \ + \ + public: \ + C ## _classnameprefix ## EnableUndoScopeGuard( const char *pDesc, int nNotifyFlags, IDmNotify *pNotify = NULL ) : \ + BaseClass( pDesc, _source, nNotifyFlags, pNotify ) \ + { \ + } \ + } + + +//----------------------------------------------------------------------------- +// Purpose: Simple helper class to disable NotifyDataChanged from current scope +//----------------------------------------------------------------------------- +class CNotifyScopeGuard +{ +public: + CNotifyScopeGuard( const char *pReason, int nNotifySource, int nNotifyFlags, IDmNotify *pNotify = NULL ) + { + m_bReleased = false; + m_pNotify = NULL; + g_pDataModel->PushNotificationScope( pReason, nNotifySource, nNotifyFlags ); + if ( pNotify ) + { + if ( g_pDataModel->InstallNotificationCallback( pNotify ) ) + { + m_pNotify = pNotify; + } + } + }; + + ~CNotifyScopeGuard() + { + Release(); + } + + void Release() + { + // Releases the guard... + if ( !m_bReleased ) + { + g_pDataModel->PopNotificationScope( ); + if ( m_pNotify ) + { + g_pDataModel->RemoveNotificationCallback( m_pNotify ); + m_pNotify = NULL; + } + m_bReleased = true; + } + } + +private: + CNotifyScopeGuard( const CNotifyScopeGuard& g ); + +private: + IDmNotify *m_pNotify; + bool m_bReleased; +}; + + +#define DEFINE_SOURCE_NOTIFY_SCOPE_GUARD( _classnameprefix, _source ) \ + class C ## _classnameprefix ## NotifyScopeGuard : public CNotifyScopeGuard \ + { \ + typedef CNotifyScopeGuard BaseClass; \ + \ + public: \ + C ## _classnameprefix ## NotifyScopeGuard( const char *pReason, int nNotifyFlags, IDmNotify *pNotify = NULL ) : \ + BaseClass( pReason, _source, nNotifyFlags, pNotify )\ + { \ + } \ + } + + +//----------------------------------------------------------------------------- +// Purpose: Simple helper class to disable notifications when in scope +//----------------------------------------------------------------------------- +class CChangeNotifyScopeGuard +{ +public: + CChangeNotifyScopeGuard( bool bNewState ) + { + m_bReleased = false; + m_bOldValue = g_pDataModel->IsSuppressingNotify(); + g_pDataModel->SetSuppressingNotify( bNewState ); + }; + + ~CChangeNotifyScopeGuard() + { + Release(); + } + + void Release() + { + // Releases the guard... + if ( !m_bReleased ) + { + g_pDataModel->SetSuppressingNotify( m_bOldValue ); + m_bReleased = true; + } + } + +private: + bool m_bOldValue; + bool m_bReleased; +}; + +class CDisableNotifyScopeGuard : public CChangeNotifyScopeGuard +{ + typedef CChangeNotifyScopeGuard BaseClass; + +public: + CDisableNotifyScopeGuard() : BaseClass( true ) { } + +private: + CDisableNotifyScopeGuard( const CDisableNotifyScopeGuard& g ); +}; + +class CEnableNotifyScopeGuard : public CChangeNotifyScopeGuard +{ + typedef CChangeNotifyScopeGuard BaseClass; + +public: + CEnableNotifyScopeGuard( ) : BaseClass( false ) { } + +private: + CEnableNotifyScopeGuard( const CEnableNotifyScopeGuard& g ); +}; + + +//----------------------------------------------------------------------------- +// Standard undo/notify guards for the application +//----------------------------------------------------------------------------- +DEFINE_SOURCE_UNDO_SCOPE_GUARD( App, NOTIFY_SOURCE_APPLICATION ); +DEFINE_SOURCE_NOTIFY_SCOPE_GUARD( App, NOTIFY_SOURCE_APPLICATION ); + + + +#endif // IDATAMODEL_H diff --git a/public/demofile/demoformat.h b/public/demofile/demoformat.h new file mode 100644 index 0000000..6ddbe56 --- /dev/null +++ b/public/demofile/demoformat.h @@ -0,0 +1,250 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DEMOFORMAT_H +#define DEMOFORMAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "utlvector.h" +#include "tier0/platform.h" + +#define DEMO_HEADER_ID "HL2DEMO" +#define DEMO_PROTOCOL 3 + +#if !defined( MAX_OSPATH ) +#define MAX_OSPATH 260 // max length of a filesystem pathname +#endif + +// Demo messages +enum +{ + // it's a startup message, process as fast as possible + dem_signon = 1, + // it's a normal network packet that we stored off + dem_packet, + // sync client clock to demo tick + dem_synctick, + // console command + dem_consolecmd, + // user input command + dem_usercmd, + // network data tables + dem_datatables, + // end of time. + dem_stop, + + dem_stringtables, + + // Last command + dem_lastcmd = dem_stringtables +}; + +struct demoheader_t +{ + char demofilestamp[8]; // Should be HL2DEMO + int demoprotocol; // Should be DEMO_PROTOCOL + int networkprotocol; // Should be PROTOCOL_VERSION + char servername[ MAX_OSPATH ]; // Name of server + char clientname[ MAX_OSPATH ]; // Name of client who recorded the game + char mapname[ MAX_OSPATH ]; // Name of map + char gamedirectory[ MAX_OSPATH ]; // Name of game directory (com_gamedir) + float playback_time; // Time of track + int playback_ticks; // # of ticks in track + int playback_frames; // # of frames in track + int signonlength; // length of sigondata in bytes +}; + +inline void ByteSwap_demoheader_t( demoheader_t &swap ) +{ + swap.demoprotocol = LittleDWord( swap.demoprotocol ); + swap.networkprotocol = LittleDWord( swap.networkprotocol ); + LittleFloat( &swap.playback_time, &swap.playback_time ); + swap.playback_ticks = LittleDWord( swap.playback_ticks ); + swap.playback_frames = LittleDWord( swap.playback_frames ); + swap.signonlength = LittleDWord( swap.signonlength ); +} + +#define FDEMO_NORMAL 0 +#define FDEMO_USE_ORIGIN2 (1<<0) +#define FDEMO_USE_ANGLES2 (1<<1) +#define FDEMO_NOINTERP (1<<2) // don't interpolate between this an last view + +struct democmdinfo_t +{ + // Default constructor + democmdinfo_t() + { + flags = FDEMO_NORMAL; + viewOrigin.Init(); + viewAngles.Init(); + localViewAngles.Init(); + + // Resampled origin/angles + viewOrigin2.Init(); + viewAngles2.Init(); + localViewAngles2.Init(); + } + + // Copy constructor + // Assignment + democmdinfo_t& operator=(const democmdinfo_t& src ) + { + if ( this == &src ) + return *this; + + flags = src.flags; + viewOrigin = src.viewOrigin; + viewAngles = src.viewAngles; + localViewAngles = src.localViewAngles; + viewOrigin2 = src.viewOrigin2; + viewAngles2 = src.viewAngles2; + localViewAngles2 = src.localViewAngles2; + + return *this; + } + + const Vector& GetViewOrigin() + { + if ( flags & FDEMO_USE_ORIGIN2 ) + { + return viewOrigin2; + } + return viewOrigin; + } + + const QAngle& GetViewAngles() + { + if ( flags & FDEMO_USE_ANGLES2 ) + { + return viewAngles2; + } + return viewAngles; + } + const QAngle& GetLocalViewAngles() + { + if ( flags & FDEMO_USE_ANGLES2 ) + { + return localViewAngles2; + } + return localViewAngles; + } + + void Reset( void ) + { + flags = 0; + viewOrigin2 = viewOrigin; + viewAngles2 = viewAngles; + localViewAngles2 = localViewAngles; + } + + int flags; + + // original origin/viewangles + Vector viewOrigin; + QAngle viewAngles; + QAngle localViewAngles; + + // Resampled origin/viewangles + Vector viewOrigin2; + QAngle viewAngles2; + QAngle localViewAngles2; +}; + +struct demosmoothing_t +{ + demosmoothing_t() + { + file_offset = 0; + frametick = 0; + selected = false; + samplepoint = false; + + vecmoved.Init(); + angmoved.Init(); + + targetpoint = false; + vectarget.Init(); + } + + demosmoothing_t& operator=(const demosmoothing_t& src ) + { + if ( this == &src ) + return *this; + + file_offset = src.file_offset; + frametick = src.frametick; + selected = src.selected; + samplepoint = src.samplepoint; + vecmoved = src.vecmoved; + angmoved = src.angmoved; + + targetpoint = src.targetpoint; + vectarget = src.vectarget; + + info = src.info; + + return *this; + } + + int file_offset; + + int frametick; + + bool selected; + + // For moved sample points + bool samplepoint; + Vector vecmoved; + QAngle angmoved; + + bool targetpoint; + Vector vectarget; + + democmdinfo_t info; +}; + +struct CSmoothingContext +{ + CSmoothingContext() + { + active = false; + filename[ 0 ] = 0; + m_nFirstSelectableSample = 0; + } + + CSmoothingContext& operator=(const CSmoothingContext& src ) + { + if ( this == &src ) + return *this; + + active = src.active; + Q_strncpy( filename, src.filename, sizeof( filename ) ); + + smooth.RemoveAll(); + int c = src.smooth.Count(); + int i; + for ( i = 0; i < c; i++ ) + { + demosmoothing_t newitem; + newitem = src.smooth[ i ]; + smooth.AddToTail( newitem ); + } + + m_nFirstSelectableSample = src.m_nFirstSelectableSample; + + return *this; + } + + bool active; + char filename[ 512 ]; + CUtlVector< demosmoothing_t > smooth; + int m_nFirstSelectableSample; +}; + +#endif // DEMOFORMAT_H diff --git a/public/disp_common.cpp b/public/disp_common.cpp new file mode 100644 index 0000000..0c2ac51 --- /dev/null +++ b/public/disp_common.cpp @@ -0,0 +1,1296 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "disp_common.h" +#include "disp_powerinfo.h" +#include "builddisp.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CNodeVert +{ +public: + CNodeVert() {} + CNodeVert( int ix, int iy ) {x=ix; y=iy;} + + inline int& operator[]( int i ) {return ((int*)this)[i];} + inline int const& operator[]( int i ) const {return ((int*)this)[i];} + + int x, y; +}; + +static CNodeVert const g_NodeChildLookup[4][2] = +{ + {CNodeVert(0,0), CNodeVert(1,1)}, + {CNodeVert(1,0), CNodeVert(2,1)}, + {CNodeVert(0,1), CNodeVert(1,2)}, + {CNodeVert(1,1), CNodeVert(2,2)} +}; + +static CNodeVert const g_NodeTriWinding[9] = +{ + CNodeVert(0, 1), + CNodeVert(0, 0), + CNodeVert(1, 0), + CNodeVert(2, 0), + CNodeVert(2, 1), + CNodeVert(2, 2), + CNodeVert(1, 2), + CNodeVert(0, 2), + CNodeVert(0, 1) +}; + +// Indexed by CORNER_. These store NEIGHBOREDGE_ defines and tell which edges butt up against the corner. +static int g_CornerEdges[4][2] = +{ + { NEIGHBOREDGE_BOTTOM, NEIGHBOREDGE_LEFT }, // CORNER_LOWER_LEFT + { NEIGHBOREDGE_TOP, NEIGHBOREDGE_LEFT }, // CORNER_UPPER_LEFT + { NEIGHBOREDGE_TOP, NEIGHBOREDGE_RIGHT }, // CORNER_UPPER_RIGHT + { NEIGHBOREDGE_BOTTOM, NEIGHBOREDGE_RIGHT } // CORNER_LOWER_RIGHT +}; + +int g_EdgeDims[4] = +{ + 0, // NEIGHBOREDGE_LEFT = X + 1, // NEIGHBOREDGE_TOP = Y + 0, // NEIGHBOREDGE_RIGHT = X + 1 // NEIGHBOREDGE_BOTTOM = Y +}; + +CShiftInfo g_ShiftInfos[3][3] = +{ + { + {0, 0, true}, // CORNER_TO_CORNER -> CORNER_TO_CORNER + {0, -1, true}, // CORNER_TO_CORNER -> CORNER_TO_MIDPOINT + {2, -1, true} // CORNER_TO_CORNER -> MIDPOINT_TO_CORNER + }, + + { + {0, 1, true}, // CORNER_TO_MIDPOINT -> CORNER_TO_CORNER + {0, 0, false}, // CORNER_TO_MIDPOINT -> CORNER_TO_MIDPOINT (invalid) + {0, 0, false} // CORNER_TO_MIDPOINT -> MIDPOINT_TO_CORNER (invalid) + }, + + { + {-1, 1, true}, // MIDPOINT_TO_CORNER -> CORNER_TO_CORNER + {0, 0, false}, // MIDPOINT_TO_CORNER -> CORNER_TO_MIDPOINT (invalid) + {0, 0, false} // MIDPOINT_TO_CORNER -> MIDPOINT_TO_CORNER (invalid) + } +}; + +int g_EdgeSideLenMul[4] = +{ + 0, + 1, + 1, + 0 +}; + + +// --------------------------------------------------------------------------------- // +// Helper functions. +// --------------------------------------------------------------------------------- // + +inline int SignedBitShift( int val, int shift ) +{ + if( shift > 0 ) + return val << shift; + else + return val >> -shift; +} + +static inline void RotateVertIndex( + NeighborOrientation neighor, + int sideLengthMinus1, + CVertIndex const &in, + CVertIndex &out ) +{ + if( neighor == ORIENTATION_CCW_0 ) + { + out = in; + } + else if( neighor == ORIENTATION_CCW_90 ) + { + out.x = in.y; + out.y = sideLengthMinus1 - in.x; + } + else if( neighor == ORIENTATION_CCW_180 ) + { + out.x = sideLengthMinus1 - in.x; + out.y = sideLengthMinus1 - in.y; + } + else + { + out.x = sideLengthMinus1 - in.y; + out.y = in.x; + } +} + +static inline void RotateVertIncrement( + NeighborOrientation neighor, + CVertIndex const &in, + CVertIndex &out ) +{ + if( neighor == ORIENTATION_CCW_0 ) + { + out = in; + } + else if( neighor == ORIENTATION_CCW_90 ) + { + out.x = in.y; + out.y = -in.x; + } + else if( neighor == ORIENTATION_CCW_180 ) + { + out.x = -in.x; + out.y = -in.y; + } + else + { + out.x = -in.y; + out.y = in.x; + } +} + + +// --------------------------------------------------------------------------------- // +// CDispHelper functions. +// --------------------------------------------------------------------------------- // + +int GetEdgeIndexFromPoint( CVertIndex const &index, int iMaxPower ) +{ + int sideLengthMinus1 = 1 << iMaxPower; + + if( index.x == 0 ) + return NEIGHBOREDGE_LEFT; + else if( index.y == sideLengthMinus1 ) + return NEIGHBOREDGE_TOP; + else if( index.x == sideLengthMinus1 ) + return NEIGHBOREDGE_RIGHT; + else if( index.y == 0 ) + return NEIGHBOREDGE_BOTTOM; + else + return -1; +} + + +int GetCornerIndexFromPoint( CVertIndex const &index, int iPower ) +{ + int sideLengthMinus1 = 1 << iPower; + + if( index.x == 0 && index.y == 0 ) + return CORNER_LOWER_LEFT; + + else if( index.x == 0 && index.y == sideLengthMinus1 ) + return CORNER_UPPER_LEFT; + + else if( index.x == sideLengthMinus1 && index.y == sideLengthMinus1 ) + return CORNER_UPPER_RIGHT; + + else if( index.x == sideLengthMinus1 && index.y == 0 ) + return CORNER_LOWER_RIGHT; + + else + return -1; +} + + +int GetNeighborEdgePower( CDispUtilsHelper *pDisp, int iEdge, int iSub ) +{ + CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge ); + CDispSubNeighbor *pSub = &pEdge->m_SubNeighbors[iSub]; + if ( !pSub->IsValid() ) + return -1; + + CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->GetNeighborIndex() ); + + CShiftInfo *pInfo = &g_ShiftInfos[pSub->m_Span][pSub->m_NeighborSpan]; + Assert( pInfo->m_bValid ); + + return pNeighbor->GetPower() + pInfo->m_PowerShiftAdd; +} + + +CDispUtilsHelper* SetupEdgeIncrements( + CDispUtilsHelper *pDisp, + int iEdge, + int iSub, + CVertIndex &myIndex, + CVertIndex &myInc, + CVertIndex &nbIndex, + CVertIndex &nbInc, + int &myEnd, + int &iFreeDim ) +{ + int iEdgeDim = g_EdgeDims[iEdge]; + iFreeDim = !iEdgeDim; + + CDispNeighbor *pSide = pDisp->GetEdgeNeighbor( iEdge ); + CDispSubNeighbor *pSub = &pSide->m_SubNeighbors[iSub]; + if ( !pSub->IsValid() ) + return NULL; + + CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->m_iNeighbor ); + + CShiftInfo *pShiftInfo = &g_ShiftInfos[pSub->m_Span][pSub->m_NeighborSpan]; + Assert( pShiftInfo->m_bValid ); + + // Setup a start point and edge increment (NOTE: just precalculate these + // and store them in the CDispSubNeighbors). + CVertIndex tempInc; + + const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo(); + myIndex[iEdgeDim] = g_EdgeSideLenMul[iEdge] * pPowerInfo->m_SideLengthM1; + myIndex[iFreeDim] = pPowerInfo->m_MidPoint * iSub; + TransformIntoSubNeighbor( pDisp, iEdge, iSub, myIndex, nbIndex ); + + int myPower = pDisp->GetPowerInfo()->m_Power; + int nbPower = pNeighbor->GetPowerInfo()->m_Power + pShiftInfo->m_PowerShiftAdd; + + myInc[iEdgeDim] = tempInc[iEdgeDim] = 0; + if( nbPower > myPower ) + { + myInc[iFreeDim] = 1; + tempInc[iFreeDim] = 1 << (nbPower - myPower); + } + else + { + myInc[iFreeDim] = 1 << (myPower - nbPower); + tempInc[iFreeDim] = 1; + } + RotateVertIncrement( pSub->GetNeighborOrientation(), tempInc, nbInc ); + + // Walk along the edge. + if( pSub->m_Span == CORNER_TO_MIDPOINT ) + myEnd = pDisp->GetPowerInfo()->m_SideLength >> 1; + else + myEnd = pDisp->GetPowerInfo()->m_SideLength - 1; + + return pNeighbor; +} + + +int GetSubNeighborIndex( + CDispUtilsHelper *pDisp, + int iEdge, + CVertIndex const &nodeIndex ) +{ + const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo(); + const CDispNeighbor *pSide = pDisp->GetEdgeNeighbor( iEdge ); + + // Figure out if this is a vertical or horizontal edge. + int iEdgeDim = g_EdgeDims[iEdge]; + int iFreeDim = !iEdgeDim; + + int iFreeIndex = nodeIndex[iFreeDim]; + + // Figure out which of the (up to two) neighbors it lies in. + int iSub = 0; + if( iFreeIndex == pPowerInfo->m_MidPoint ) + { + // If it's in the middle, we only are interested if there's one neighbor + // next to us (so we can enable its middle vert). If there are any neighbors + // that touch the midpoint, then we have no need to return them because it would + // touch their corner verts which are always active. + if( pSide->m_SubNeighbors[0].m_Span != CORNER_TO_CORNER ) + return -1; + } + else if ( iFreeIndex > pPowerInfo->m_MidPoint ) + { + iSub = 1; + } + + // Make sure we get a valid neighbor. + if( !pSide->m_SubNeighbors[iSub].IsValid() ) + { + if( iSub == 1 && + pSide->m_SubNeighbors[0].IsValid() && + pSide->m_SubNeighbors[0].m_Span == CORNER_TO_CORNER ) + { + iSub = 0; + } + else + { + return -1; + } + } + + return iSub; +} + + +void SetupSpan( int iPower, int iEdge, NeighborSpan span, CVertIndex &viStart, CVertIndex &viEnd ) +{ + int iFreeDim = !g_EdgeDims[iEdge]; + const CPowerInfo *pPowerInfo = GetPowerInfo( iPower ); + + viStart = pPowerInfo->GetCornerPointIndex( iEdge ); + viEnd = pPowerInfo->GetCornerPointIndex( (iEdge+1) & 3 );; + + if ( iEdge == NEIGHBOREDGE_RIGHT || iEdge == NEIGHBOREDGE_BOTTOM ) + { + // CORNER_TO_MIDPOINT and MIDPOINT_CORNER are defined where the edge moves up or right, + // but pPowerInfo->GetCornerPointIndex walks around the edges clockwise, so on the + // bottom and right edges (where GetCornerPointIndex has us moving down and left) we need to + // reverse the sense here to make sure we return the right span. + if ( span == CORNER_TO_MIDPOINT ) + viStart[iFreeDim] = pPowerInfo->GetMidPoint(); + else if ( span == MIDPOINT_TO_CORNER ) + viEnd[iFreeDim] = pPowerInfo->GetMidPoint(); + } + else + { + if ( span == CORNER_TO_MIDPOINT ) + viEnd[iFreeDim] = pPowerInfo->GetMidPoint(); + else if ( span == MIDPOINT_TO_CORNER ) + viStart[iFreeDim] = pPowerInfo->GetMidPoint(); + } +} + + +CDispUtilsHelper* TransformIntoSubNeighbor( + CDispUtilsHelper *pDisp, + int iEdge, + int iSub, + CVertIndex const &nodeIndex, + CVertIndex &out + ) +{ + const CDispSubNeighbor *pSub = &pDisp->GetEdgeNeighbor( iEdge )->m_SubNeighbors[iSub]; + + // Find the part of pDisp's edge that this neighbor covers. + CVertIndex viSrcStart, viSrcEnd; + SetupSpan( pDisp->GetPower(), iEdge, pSub->GetSpan(), viSrcStart, viSrcEnd ); + + // Find the corresponding parts on the neighbor. + CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->GetNeighborIndex() ); + int iNBEdge = (iEdge + 2 + pSub->GetNeighborOrientation()) & 3; + + CVertIndex viDestStart, viDestEnd; + SetupSpan( pNeighbor->GetPower(), iNBEdge, pSub->GetNeighborSpan(), viDestEnd, viDestStart ); + + + // Now map the one into the other. + int iFreeDim = !g_EdgeDims[iEdge]; + int fixedPercent = ((nodeIndex[iFreeDim] - viSrcStart[iFreeDim]) * (1<<16)) / (viSrcEnd[iFreeDim] - viSrcStart[iFreeDim]); + Assert( fixedPercent >= 0 && fixedPercent <= (1<<16) ); + + int nbDim = g_EdgeDims[iNBEdge]; + out[nbDim] = viDestStart[nbDim]; + out[!nbDim] = viDestStart[!nbDim] + ((viDestEnd[!nbDim] - viDestStart[!nbDim]) * fixedPercent) / (1<<16); + + Assert( out.x >= 0 && out.x < pNeighbor->GetSideLength() ); + Assert( out.y >= 0 && out.y < pNeighbor->GetSideLength() ); + + return pNeighbor; +} + + +CDispUtilsHelper* TransformIntoNeighbor( + CDispUtilsHelper *pDisp, + int iEdge, + CVertIndex const &nodeIndex, + CVertIndex &out + ) +{ + if ( iEdge == -1 ) + iEdge = GetEdgeIndexFromPoint( nodeIndex, pDisp->GetPower() ); + + int iSub = GetSubNeighborIndex( pDisp, iEdge, nodeIndex ); + if ( iSub == -1 ) + return NULL; + + CDispUtilsHelper *pRet = TransformIntoSubNeighbor( pDisp, iEdge, iSub, nodeIndex, out ); + +#if 0 + // Debug check.. make sure it comes back to the same point from the other side. + #if defined( _DEBUG ) + static bool bTesting = false; + if ( pRet && !bTesting ) + { + bTesting = true; + + // We could let TransformIntoNeighbor figure out the index but if this is a corner vert, then + // it may pick the wrong edge and we'd get a benign assert. + int nbOrientation = pDisp->GetEdgeNeighbor( iEdge )->m_SubNeighbors[iSub].GetNeighborOrientation(); + int iNeighborEdge = (iEdge + 2 + nbOrientation) & 3; + + CVertIndex testIndex; + CDispUtilsHelper *pTest = TransformIntoNeighbor( pRet, iNeighborEdge, out, testIndex ); + Assert( pTest == pDisp ); + Assert( testIndex == nodeIndex ); + + bTesting = false; + } + #endif +#endif + + return pRet; +} + + +bool DoesPointHaveAnyNeighbors( + CDispUtilsHelper *pDisp, + const CVertIndex &index ) +{ + // See if it connects to a neighbor on the edge. + CVertIndex dummy; + if ( TransformIntoNeighbor( pDisp, -1, index, dummy ) ) + return true; + + // See if it connects to a neighbor on a corner. + int iCorner = GetCornerIndexFromPoint( index, pDisp->GetPower() ); + if ( iCorner == -1 ) + return false; + + // If there are any neighbors on the specified corner, then the point has neighbors. + if ( pDisp->GetCornerNeighbors( iCorner )->m_nNeighbors > 0 ) + return true; + + // Since points on corners touch two edges, we actually want to test two edges to see + // if the point has a neighbor on either edge. + for ( int i=0; i < 2; i++ ) + { + if ( TransformIntoNeighbor( pDisp, g_CornerEdges[iCorner][i], index, dummy ) ) + return true; + } + + return false; +} + + +// ------------------------------------------------------------------------------------ // +// CDispSubEdgeIterator. +// ------------------------------------------------------------------------------------ // + +CDispSubEdgeIterator::CDispSubEdgeIterator() +{ + m_pNeighbor = 0; + m_FreeDim = m_Index.x = m_Inc.x = m_End = 0; // Setup so Next returns false. +} + + +void CDispSubEdgeIterator::Start( CDispUtilsHelper *pDisp, int iEdge, int iSub, bool bTouchCorners ) +{ + m_pNeighbor = SetupEdgeIncrements( pDisp, iEdge, iSub, m_Index, m_Inc, m_NBIndex, m_NBInc, m_End, m_FreeDim ); + if ( m_pNeighbor ) + { + if ( bTouchCorners ) + { + // Back up our current position by 1 so we hit the corner first, and extend the endpoint + // so we hit the other corner too. + m_Index -= m_Inc; + m_NBIndex -= m_NBInc; + + m_End += m_Inc[m_FreeDim]; + } + } + else + { + m_FreeDim = m_Index.x = m_Inc.x = m_End = 0; // Setup so Next returns false. + } +} + + +bool CDispSubEdgeIterator::Next() +{ + m_Index += m_Inc; + m_NBIndex += m_NBInc; + + // Were we just at the last point on the edge? + return m_Index[m_FreeDim] < m_End; +} + + +bool CDispSubEdgeIterator::IsLastVert() const +{ + return (m_Index[m_FreeDim] + m_Inc[m_FreeDim]) >= m_End; +} + + +// ------------------------------------------------------------------------------------ // +// CDispEdgeIterator. +// ------------------------------------------------------------------------------------ // + +CDispEdgeIterator::CDispEdgeIterator( CDispUtilsHelper *pDisp, int iEdge ) +{ + m_pDisp = pDisp; + m_iEdge = iEdge; + m_iCurSub = -1; +} + + +bool CDispEdgeIterator::Next() +{ + while ( !m_It.Next() ) + { + // Ok, move up to the next sub. + if ( m_iCurSub == 1 ) + return false; + + ++m_iCurSub; + m_It.Start( m_pDisp, m_iEdge, m_iCurSub ); + } + return true; +} + + +// ------------------------------------------------------------------------------------ // +// CDispCircumferenceIterator. +// ------------------------------------------------------------------------------------ // + +CDispCircumferenceIterator::CDispCircumferenceIterator( int sideLength ) +{ + m_iCurEdge = -1; + m_SideLengthM1 = sideLength - 1; +} + + +bool CDispCircumferenceIterator::Next() +{ + switch ( m_iCurEdge ) + { + case -1: + { + m_iCurEdge = NEIGHBOREDGE_LEFT; + m_VertIndex.Init( 0, 0 ); + } + break; + + case NEIGHBOREDGE_LEFT: + { + ++m_VertIndex.y; + if ( m_VertIndex.y == m_SideLengthM1 ) + m_iCurEdge = NEIGHBOREDGE_TOP; + } + break; + + case NEIGHBOREDGE_TOP: + { + ++m_VertIndex.x; + if ( m_VertIndex.x == m_SideLengthM1 ) + m_iCurEdge = NEIGHBOREDGE_RIGHT; + } + break; + + case NEIGHBOREDGE_RIGHT: + { + --m_VertIndex.y; + if ( m_VertIndex.y == 0 ) + m_iCurEdge = NEIGHBOREDGE_BOTTOM; + } + break; + + case NEIGHBOREDGE_BOTTOM: + { + --m_VertIndex.x; + if ( m_VertIndex.x == 0 ) + return false; // Done! + } + break; + } + + return true; +} + + + +// Helper function to setup an index either on the edges or the center +// of the box defined by [bottomleft,topRight]. +static inline void SetupCoordXY( CNodeVert &out, CNodeVert const &bottomLeft, CNodeVert const &topRight, CNodeVert const &info ) +{ + for( int i=0; i < 2; i++ ) + { + if( info[i] == 0 ) + out[i] = bottomLeft[i]; + else if( info[i] == 1 ) + out[i] = (bottomLeft[i] + topRight[i]) >> 1; + else + out[i] = topRight[i]; + } +} + + +static unsigned short* DispCommon_GenerateTriIndices_R( + CNodeVert const &bottomLeft, + CNodeVert const &topRight, + unsigned short *indices, + int power, + int sideLength ) +{ + if( power == 1 ) + { + // Ok, add triangles. All we do here is follow a list of verts (g_NodeTriWinding) + // around the center vert of this node and make triangles. + int iCurTri = 0; + CNodeVert verts[3]; + + // verts[0] is always the center vert. + SetupCoordXY( verts[0], bottomLeft, topRight, CNodeVert(1,1) ); + int iCurVert = 1; + + for( int i=0; i < 9; i++ ) + { + SetupCoordXY( verts[iCurVert], bottomLeft, topRight, g_NodeTriWinding[i] ); + ++iCurVert; + + if( iCurVert == 3 ) + { + for( int iTriVert=2; iTriVert >= 0; iTriVert-- ) + { + int index = verts[iTriVert].y * sideLength + verts[iTriVert].x; + *indices = index; + ++indices; + } + + // Setup for the next triangle. + verts[1] = verts[2]; + iCurVert = 2; + iCurTri++; + } + } + } + else + { + // Recurse into the children. + for( int i=0; i < 4; i++ ) + { + CNodeVert childBottomLeft, childTopRight; + SetupCoordXY( childBottomLeft, bottomLeft, topRight, g_NodeChildLookup[i][0] ); + SetupCoordXY( childTopRight, bottomLeft, topRight, g_NodeChildLookup[i][1] ); + + indices = DispCommon_GenerateTriIndices_R( childBottomLeft, childTopRight, indices, power-1, sideLength ); + } + } + + return indices; +} + + +// ------------------------------------------------------------------------------------------- // +// CDispUtilsHelper functions. +// ------------------------------------------------------------------------------------------- // + +int CDispUtilsHelper::GetPower() const +{ + return GetPowerInfo()->GetPower(); +} + +int CDispUtilsHelper::GetSideLength() const +{ + return GetPowerInfo()->GetSideLength(); +} + +const CVertIndex& CDispUtilsHelper::GetCornerPointIndex( int iCorner ) const +{ + return GetPowerInfo()->GetCornerPointIndex( iCorner ); +} + +int CDispUtilsHelper::VertIndexToInt( const CVertIndex &i ) const +{ + Assert( i.x >= 0 && i.x < GetSideLength() && i.y >= 0 && i.y < GetSideLength() ); + return i.y * GetSideLength() + i.x; +} + +CVertIndex CDispUtilsHelper::GetEdgeMidPoint( int iEdge ) const +{ + int end = GetSideLength() - 1; + int mid = GetPowerInfo()->GetMidPoint(); + + if ( iEdge == NEIGHBOREDGE_LEFT ) + return CVertIndex( 0, mid ); + + else if ( iEdge == NEIGHBOREDGE_TOP ) + return CVertIndex( mid, end ); + + else if ( iEdge == NEIGHBOREDGE_RIGHT ) + return CVertIndex( end, mid ); + + else if ( iEdge == NEIGHBOREDGE_BOTTOM ) + return CVertIndex( mid, 0 ); + + Assert( false ); + return CVertIndex( 0, 0 ); +} + +int DispCommon_GetNumTriIndices( int power ) +{ + return (1<GetEdgeNeighbor( i )->SetInvalid(); + pDisp->GetCornerNeighbors( i )->SetInvalid(); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void GetDispBox( CCoreDispInfo *pDisp, CDispBox &box ) +{ + // Calculate the bbox for this displacement. + Vector vMin( 1e24, 1e24, 1e24 ); + Vector vMax( -1e24, -1e24, -1e24 ); + + for ( int iVert = 0; iVert < 4; ++iVert ) + { + const Vector &vTest = pDisp->GetSurface()->GetPoint( iVert ); + VectorMin( vTest, vMin, vMin ); + VectorMax( vTest, vMax, vMax ); + } + + // Puff the box out a little. + static float flPuff = 0.1f; + vMin -= Vector( flPuff, flPuff, flPuff ); + vMax += Vector( flPuff, flPuff, flPuff ); + + box.m_Min = vMin; + box.m_Max = vMax; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void SetupDispBoxes( CCoreDispInfo **ppListBase, int nListSize, CUtlVector &out ) +{ + out.SetSize( nListSize ); + for ( int iDisp = 0; iDisp < nListSize; ++iDisp ) + { + CCoreDispInfo *pDisp = ppListBase[iDisp]; + GetDispBox( pDisp, out[iDisp] ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline bool DoBBoxesTouch( const CDispBox &a, const CDispBox &b ) +{ + for ( int i=0; i < 3; i++ ) + { + if ( a.m_Max[i] < b.m_Min[i] ) + return false; + + if ( a.m_Min[i] > b.m_Max[i] ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool FindEdge( CCoreDispInfo *pInfo, Vector const &vPoint1, Vector const &vPoint2, int &iEdge ) +{ + CCoreDispSurface *pSurface = pInfo->GetSurface(); + + for( iEdge=0; iEdge < 4; iEdge++ ) + { + if( VectorsAreEqual( vPoint1, pSurface->GetPoint( iEdge ), 0.01f ) && + VectorsAreEqual( vPoint2, pSurface->GetPoint( (iEdge+1) & 3), 0.01f ) ) + { + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +NeighborSpan NeighborSpanFlip( int iEdge, NeighborSpan span ) +{ + if ( g_bEdgeNeighborFlip[iEdge] ) + return g_SpanFlip[span]; + else + return span; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void AddNeighbor( CCoreDispInfo *pMain, + int iEdge, // Which of pMain's sides this is on. + int iSub, // Which sub neighbor this takes up in pSide. + NeighborSpan span, // What span this fills in pMain. + CCoreDispInfo *pOther, int iNeighborEdge, NeighborSpan nbSpan ) +{ + // The edge iteration before coming in here goes 0-1, 1-2, 2-3, 3-4. + // This flips the sense of CORNER_TO_MIDPOINT/MIDPOINT_TO_CORNER on the right and + // bottom edges and is undone here. + span = NeighborSpanFlip( iEdge, span ); + nbSpan = NeighborSpanFlip( iNeighborEdge, nbSpan ); + + // Get the subspan this fills on our displacement. + CDispSubNeighbor *pSub = &pMain->GetEdgeNeighbor(iEdge)->m_SubNeighbors[iSub]; + + // Which subspan does this use in the neighbor? + CDispSubNeighbor *pNeighborSub; + if ( nbSpan == MIDPOINT_TO_CORNER ) + { + pNeighborSub = &pOther->GetEdgeNeighbor(iNeighborEdge)->m_SubNeighbors[1]; + } + else + { + pNeighborSub = &pOther->GetEdgeNeighbor(iNeighborEdge)->m_SubNeighbors[0]; + } + + // Make sure this slot isn't used on either displacement. + if ( pSub->IsValid() || pNeighborSub->IsValid() ) + { + ExecuteOnce( Warning( "Found a displacement edge abutting multiple other edges.\n" ) ); + return; + } + + // Now just copy the data into each displacement. + pSub->m_iNeighbor = pOther->GetListIndex(); + pSub->m_NeighborOrientation = g_CoreDispNeighborOrientationMap[iEdge][iNeighborEdge]; + pSub->m_Span = span; + pSub->m_NeighborSpan = nbSpan; + + pNeighborSub->m_iNeighbor = pMain->GetListIndex(); + pNeighborSub->m_NeighborOrientation = g_CoreDispNeighborOrientationMap[iNeighborEdge][iEdge]; + pNeighborSub->m_Span = nbSpan; + pNeighborSub->m_NeighborSpan = span; + +#if defined( _DEBUG ) + // Walk an iterator over the new connection to make sure it works. + CDispSubEdgeIterator it; + it.Start( pMain, iEdge, iSub ); + while ( it.Next() ) + { + CVertIndex nbIndex; + TransformIntoNeighbor( pMain, iEdge, it.GetVertIndex(), nbIndex ); + } +#endif +} + +//----------------------------------------------------------------------------- +// This function is symmetric wrt pMain and pOther. It sets up valid neighboring data for +// the relationship between both of them. +//----------------------------------------------------------------------------- +void SetupEdgeNeighbors( CCoreDispInfo *pMain, CCoreDispInfo *pOther ) +{ + // Initialize.. + for( int iEdge=0; iEdge < 4; iEdge++ ) + { + // Setup the edge points and the midpoint. + Vector pt[2], mid; + pMain->GetSurface()->GetPoint( iEdge, pt[0] ); + pMain->GetSurface()->GetPoint( (iEdge + 1) & 3, pt[1] ); + mid = (pt[0] + pt[1]) * 0.5f; + + // Find neighbors. + int iNBEdge; + if( FindEdge( pOther, pt[1], pt[0], iNBEdge ) ) + { + AddNeighbor( pMain, iEdge, 0, CORNER_TO_CORNER, pOther, iNBEdge, CORNER_TO_CORNER ); + } + else + { + // Look for one that takes up our whole side. + if( FindEdge( pOther, pt[1], pt[0]*2 - pt[1], iNBEdge ) ) + { + AddNeighbor( pMain, iEdge, 0, CORNER_TO_CORNER, pOther, iNBEdge, CORNER_TO_MIDPOINT ); + } + else if( FindEdge( pOther, pt[1]*2 - pt[0], pt[0], iNBEdge ) ) + { + AddNeighbor( pMain, iEdge, 0, CORNER_TO_CORNER, pOther, iNBEdge, MIDPOINT_TO_CORNER ); + } + else + { + // Ok, look for 1 or two that abut this side. + if( FindEdge( pOther, mid, pt[0], iNBEdge ) ) + { + AddNeighbor( pMain, iEdge, g_bEdgeNeighborFlip[iEdge], CORNER_TO_MIDPOINT, pOther, iNBEdge, CORNER_TO_CORNER ); + } + + if( FindEdge( pOther, pt[1], mid, iNBEdge ) ) + { + AddNeighbor( pMain, iEdge, !g_bEdgeNeighborFlip[iEdge], MIDPOINT_TO_CORNER, pOther, iNBEdge, CORNER_TO_CORNER ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Returns true if the displacement has an edge neighbor with the given index. +//----------------------------------------------------------------------------- +bool HasEdgeNeighbor( const CCoreDispInfo *pMain, int iNeighbor ) +{ + for ( int i=0; i < 4; i++ ) + { + const CDispCornerNeighbors *pCorner = pMain->GetCornerNeighbors( i ); + for ( int iNB=0; iNB < pCorner->m_nNeighbors; iNB++ ) + if ( pCorner->m_Neighbors[iNB] == iNeighbor ) + return true; + + const CDispNeighbor *pEdge = pMain->GetEdgeNeighbor( i ); + if ( pEdge->m_SubNeighbors[0].GetNeighborIndex() == iNeighbor || + pEdge->m_SubNeighbors[1].GetNeighborIndex() == iNeighbor ) + { + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void SetupCornerNeighbors( CCoreDispInfo *pMain, CCoreDispInfo *pOther, int *nOverflows ) +{ + if ( HasEdgeNeighbor( pMain, pOther->GetListIndex() ) ) + return; + + // Do these two share a vertex? + int nShared = 0; + int iMainSharedCorner = -1; + int iOtherSharedCorner = -1; + + for ( int iMainCorner=0; iMainCorner < 4; iMainCorner++ ) + { + Vector const &vMainCorner = pMain->GetCornerPoint( iMainCorner ); + + for ( int iOtherCorner=0; iOtherCorner < 4; iOtherCorner++ ) + { + Vector const &vOtherCorner = pOther->GetCornerPoint( iOtherCorner ); + + if ( VectorsAreEqual( vMainCorner, vOtherCorner, 0.001f ) ) + { + iMainSharedCorner = iMainCorner; + iOtherSharedCorner = iOtherCorner; + ++nShared; + } + } + } + + if ( nShared == 1 ) + { + CDispCornerNeighbors *pMainCorner = pMain->GetCornerNeighbors( iMainSharedCorner ); + CDispCornerNeighbors *pOtherCorner = pOther->GetCornerNeighbors( iOtherSharedCorner ); + + if ( pMainCorner->m_nNeighbors < MAX_DISP_CORNER_NEIGHBORS && + pOtherCorner->m_nNeighbors < MAX_DISP_CORNER_NEIGHBORS ) + { + pMainCorner->m_Neighbors[pMainCorner->m_nNeighbors++] = pOther->GetListIndex(); + pOtherCorner->m_Neighbors[pOtherCorner->m_nNeighbors++] = pMain->GetListIndex(); + } + else + { + ++(*nOverflows); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool VerifyNeighborVertConnection( CDispUtilsHelper *pDisp, const CVertIndex &nodeIndex, + const CDispUtilsHelper *pTestNeighbor, const CVertIndex &testNeighborIndex, + int mySide ) +{ + CVertIndex nbIndex( -1, -1 ); + CDispUtilsHelper *pNeighbor = NULL; + if( (pNeighbor = TransformIntoNeighbor( pDisp, mySide, nodeIndex, nbIndex ) ) != NULL ) + { + if ( pTestNeighbor != pNeighbor || nbIndex != testNeighborIndex ) + return false; + + CVertIndex testIndex( -1, -1 ); + int iSide = GetEdgeIndexFromPoint( nbIndex, pNeighbor->GetPowerInfo()->m_Power ); + if ( iSide == -1 ) + { + return false; + } + + CDispUtilsHelper *pTest = TransformIntoNeighbor( pNeighbor, iSide, nbIndex, testIndex ); + + if( pTest != pDisp || nodeIndex != testIndex ) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void VerifyNeighborConnections( CCoreDispInfo **ppListBase, int nDisps ) +{ + while ( 1 ) + { + bool bHappy = true; + + int iDisp; + for ( iDisp = 0; iDisp < nDisps; ++iDisp ) + { + CCoreDispInfo *pDisp = ppListBase[iDisp]; + CDispUtilsHelper *pHelper = pDisp; + + for ( int iEdge=0; iEdge < 4; iEdge++ ) + { + CDispEdgeIterator it( pHelper, iEdge ); + while ( it.Next() ) + { + if ( !VerifyNeighborVertConnection( pHelper, it.GetVertIndex(), it.GetCurrentNeighbor(), it.GetNBVertIndex(), iEdge ) ) + { + pDisp->GetEdgeNeighbor( iEdge )->SetInvalid(); + Warning( "Warning: invalid neighbor connection on displacement near (%.2f %.2f %.2f)\n", VectorExpand( pDisp->GetCornerPoint(0) ) ); + bHappy = false; + } + } + } + } + + if ( bHappy ) + break; + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void FindNeighboringDispSurfs( CCoreDispInfo **ppListBase, int nListSize ) +{ + // First, clear all neighboring data. + int iDisp; + for ( iDisp = 0; iDisp < nListSize; ++iDisp ) + { + ClearNeighborData( ppListBase[iDisp] ); + } + + CUtlVector boxes; + SetupDispBoxes( ppListBase, nListSize, boxes ); + + int nCornerOverflows = 0; + + // Now test all pairs of displacements and setup neighboring relations between them. + for( iDisp = 0; iDisp < nListSize; ++iDisp ) + { + CCoreDispInfo *pMain = ppListBase[iDisp]; + + for ( int iDisp2 = iDisp+1; iDisp2 < nListSize; ++iDisp2 ) + { + CCoreDispInfo *pOther = ppListBase[iDisp2]; + + // Trivial reject. + if ( !DoBBoxesTouch( boxes[iDisp], boxes[iDisp2] ) ) + continue; + + SetupEdgeNeighbors( pMain, pOther ); + + // NOTE: this must come after SetupEdgeNeighbors because it makes sure not to add + // corner neighbors for disps that are already edge neighbors. + SetupCornerNeighbors( pMain, pOther, &nCornerOverflows ); + } + } + + if ( nCornerOverflows ) + { + Warning( "Warning: overflowed %d displacement corner-neighbor lists.", nCornerOverflows ); + } + + // Debug check.. make sure the neighbor connections are intact (make sure that any + // edge vert that gets mapped into a neighbor gets mapped back the same way). + VerifyNeighborConnections( ppListBase, nListSize ); +} + +//============================================================================= +// +// Allowable verts. +// + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int IsCorner( CVertIndex const &index, int sideLength ) +{ + if ( index.x == 0 ) + { + if ( index.y == 0 ) + return true; + else if ( index.y == sideLength-1 ) + return true; + } + else if ( index.x == sideLength-1 ) + { + if ( index.y == 0 ) + return true; + else if ( index.y == sideLength-1 ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool IsVertAllowed( CDispUtilsHelper *pDisp, CVertIndex const &sideVert, int iLevel ) +{ + if ( IsCorner( sideVert, pDisp->GetPowerInfo()->GetSideLength() ) ) + return true; + + int iSide = GetEdgeIndexFromPoint( sideVert, pDisp->GetPowerInfo()->GetPower() ); + if ( iSide == -1 ) + return true; + + int iSub = GetSubNeighborIndex( pDisp, iSide, sideVert ); + if ( iSub == -1 ) + return true; + + CDispSubNeighbor *pSub = &pDisp->GetEdgeNeighbor( iSide )->m_SubNeighbors[iSub]; + CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->m_iNeighbor ); + Assert( pNeighbor ); + + // Ok, there is a neighbor.. see if this vertex exists in the neighbor. + CShiftInfo *pShiftInfo = &g_ShiftInfos[pSub->m_Span][pSub->m_NeighborSpan]; + Assert( pShiftInfo->m_bValid ); + + if ( ( pNeighbor->GetPowerInfo()->GetPower() + pShiftInfo->m_PowerShiftAdd ) < ( iLevel+1 ) ) + { + return false; + } + + // Ok, it exists. Make sure the neighbor hasn't disallowed it. + CVertIndex nbIndex; + TransformIntoSubNeighbor( pDisp, iSide, iSub, sideVert, nbIndex ); + + CBitVec &allowedVerts = CCoreDispInfo::FromDispUtils( pNeighbor )->GetAllowedVerts(); + return !!allowedVerts.Get( pNeighbor->VertIndexToInt( nbIndex ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void UnallowVerts_R( CDispUtilsHelper *pDisp, CVertIndex const &nodeIndex, int &nUnallowed ) +{ + int iNodeIndex = pDisp->VertIndexToInt( nodeIndex ); + + CCoreDispInfo *pCoreDisp = CCoreDispInfo::FromDispUtils( pDisp ); + if ( !pCoreDisp->GetAllowedVerts().Get( iNodeIndex ) ) + return; + + nUnallowed++; + pCoreDisp->GetAllowedVerts().Clear( iNodeIndex ); + + for ( int iDep=0; iDep < CVertInfo::NUM_REVERSE_DEPENDENCIES; iDep++ ) + { + CVertDependency &dep = pDisp->GetPowerInfo()->m_pVertInfo[iNodeIndex].m_ReverseDependencies[iDep]; + + if( dep.m_iVert.x != -1 && dep.m_iNeighbor == -1 ) + { + UnallowVerts_R( pDisp, dep.m_iVert, nUnallowed ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void DisableUnallowedVerts_R( CDispUtilsHelper *pDisp, CVertIndex const &nodeIndex, int iLevel, int &nUnallowed ) +{ + int iNodeIndex = pDisp->VertIndexToInt( nodeIndex ); + + // This vertex is not allowed if it is on an edge with a neighbor + // that does not have this vertex. + + // Test side verts. + for( int iSide=0; iSide < 4; iSide++ ) + { + CVertIndex const &sideVert = pDisp->GetPowerInfo()->m_pSideVerts[iNodeIndex].m_Verts[iSide]; + + if( !IsVertAllowed( pDisp, sideVert, iLevel ) ) + { + // This vert (and its dependencies) can't exist. + UnallowVerts_R( pDisp, sideVert, nUnallowed ); + } + } + +#if 0 + // Test dependencies. + for( int iDep=0; iDep < 2; iDep++ ) + { + CVertDependency const &dep = pDisp->GetPowerInfo()->m_pVertInfo[iNodeIndex].m_Dependencies[iDep]; + + if( dep.m_iNeighbor == -1 && !IsVertAllowed( pDisp, dep.m_iVert, iLevel ) ) + { + UnallowVerts_R( pDisp, nodeIndex, nUnallowed ); + } + } +#endif + + // Recurse. + if( iLevel+1 < pDisp->GetPower() ) + { + for( int iChild=0; iChild < 4; iChild++ ) + { + DisableUnallowedVerts_R( pDisp, pDisp->GetPowerInfo()->m_pChildVerts[iNodeIndex].m_Verts[iChild], iLevel+1, nUnallowed ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void SetupAllowedVerts( CCoreDispInfo **ppListBase, int nListSize ) +{ + // Set all verts to allowed to start with. + int iDisp; + for ( iDisp = 0; iDisp < nListSize; ++iDisp ) + { + ppListBase[iDisp]->GetAllowedVerts().SetAll(); + } + + // Disable verts that need to be disabled so higher-powered displacements remove + // the necessary triangles when bordering lower-powered displacements. + // It is necessary to loop around here because disabling verts can accumulate into + // neighbors. + bool bContinue; + do + { + bContinue = false; + for( iDisp = 0; iDisp < nListSize; ++iDisp ) + { + CDispUtilsHelper *pDisp = ppListBase[iDisp]; + + int nUnallowed = 0; + DisableUnallowedVerts_R( pDisp, pDisp->GetPowerInfo()->m_RootNode, 0, nUnallowed ); + if ( nUnallowed ) + bContinue = true; + } + } while( bContinue ); +} diff --git a/public/disp_common.h b/public/disp_common.h new file mode 100644 index 0000000..6dd5561 --- /dev/null +++ b/public/disp_common.h @@ -0,0 +1,262 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DISP_COMMON_H +#define DISP_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "disp_vertindex.h" +#include "bspfile.h" +#include "utlvector.h" + +class CPowerInfo; +class CCoreDispInfo; + +// ----------------------------------------------------------------------------- // +// Classes. +// ----------------------------------------------------------------------------- // + +// This class provides a set of utility functions for displacements that work in the tools and the engine. +abstract_class CDispUtilsHelper +{ +// Derived classes must implement these. +public: + virtual const CPowerInfo* GetPowerInfo() const = 0; + virtual CDispNeighbor* GetEdgeNeighbor( int index ) = 0; + virtual CDispCornerNeighbors* GetCornerNeighbors( int index ) = 0; + virtual CDispUtilsHelper* GetDispUtilsByIndex( int index ) = 0; + +// Helper functions. +public: + + int GetPower() const; + int GetSideLength() const; + const CVertIndex& GetCornerPointIndex( int iCorner ) const; + int VertIndexToInt( const CVertIndex &i ) const; + CVertIndex GetEdgeMidPoint( int iEdge ) const; +}; + + +// Use this to walk along two neighboring displacements and touch all the +// common vertices. +class CDispSubEdgeIterator +{ +public: + + CDispSubEdgeIterator(); + + // Normally, this will iterate all shared verts along the edge except the corners. + // If you want the corners to be touched too, then pass in bTouchCorners=true. + void Start( CDispUtilsHelper *pDisp, int iEdge, int iSub, bool bTouchCorners = false ); + bool Next(); + + const CVertIndex& GetVertIndex() const { return m_Index; } // Get the vert index for the displacement in pUtils. + const CVertIndex& GetNBVertIndex() const { return m_NBIndex; } // Get the neighbor's vert index. + CDispUtilsHelper* GetNeighbor() const { return m_pNeighbor; } + + // Returns true if you're on the last vert (ie: the next Next() call will return false).ssssss + bool IsLastVert() const; + + +private: + CDispUtilsHelper *m_pNeighbor; // The neighbor to the edge we were setup on. + + CVertIndex m_Index; + CVertIndex m_Inc; + + CVertIndex m_NBIndex; + CVertIndex m_NBInc; + + int m_End; + int m_FreeDim; +}; + + +// Use this to walk along the edge of a displacement, touching the points in common +// between the two neighbors. Note: this won't hit the corner points of any of the displacements. +// (As a result, it won't hit the midpoint of pDisps's edge if there are 2 neighbors). +class CDispEdgeIterator +{ +public: + CDispEdgeIterator( CDispUtilsHelper *pDisp, int iEdge ); + + // Seek to the next point on the edge. + bool Next(); + + const CVertIndex& GetVertIndex() const { return m_It.GetVertIndex(); } // Get the vert index for the displacement in pUtils. + const CVertIndex& GetNBVertIndex() const { return m_It.GetNBVertIndex(); } // Get the neighbor's vert index. + + // What is the current neighbor? + CDispUtilsHelper* GetCurrentNeighbor() const { return m_It.GetNeighbor(); } + + +private: + CDispUtilsHelper *m_pDisp; + int m_iEdge; + int m_iCurSub; + + CDispSubEdgeIterator m_It; +}; + + +// Use this to walk all the corners and edge verts in the displacement. +// It walks the edges in the order of the NEIGHBOREDGE_ defines. +// Iterate like this: +// CDispCircumferenceIterator iterator( pDisp->GetSideLength() ); +// while ( iterator.Next() ) +// ... +class CDispCircumferenceIterator +{ +public: + CDispCircumferenceIterator( int sideLength ); + + // Seek to the next point. Returns false when there are no more points. + bool Next(); + + const CVertIndex& GetVertIndex() const { return m_VertIndex; } + + +private: + int m_SideLengthM1; + int m_iCurEdge; + CVertIndex m_VertIndex; +}; + + +// These store info about how to scale and shift coordinates between neighbors +// of different relations (in g_ShiftInfos). +class CShiftInfo +{ +public: + int m_MidPointScale; + int m_PowerShiftAdd; + bool m_bValid; +}; + +class CDispBox +{ +public: + Vector m_Min, m_Max; +}; + +// ----------------------------------------------------------------------------- // +// Globals. +// ----------------------------------------------------------------------------- // + + +extern int g_EdgeDims[4]; // This tells which dimension (0 or 1) is locked on an edge for each NEIGHBOREDGE_ enum. +extern CShiftInfo g_ShiftInfos[3][3]; // See CShiftInfo. +extern int g_EdgeSideLenMul[4];// Multiply these by the side length to get the index of the edge. + + +// ----------------------------------------------------------------------------- // +// Helper functions. +// ----------------------------------------------------------------------------- // + +// Reference implementation to generate triangle indices for a displacement. +int DispCommon_GetNumTriIndices( int power ); +void DispCommon_GenerateTriIndices( int power, unsigned short *indices ); + +// Returns a NEIGHBOREDGE_ value for the edge that the index is on. +// Returns -1 if the index is not on a side. +// If the point is on a corner, the edges are tested in the order of the NEIGHBOREDGE_ defines. +int GetEdgeIndexFromPoint( CVertIndex const &index, int iPower ); + +// Returns a CORNER_ value for the corner the point is on, or -1 if it's not on a corner. +int GetEdgeIndexFromPoint( CVertIndex const &index, int iPower ); + +// This returns the neighbor's power, possibly +1 or -1. +// +// It will add one if the neighbor takes up half of your edge (ie: if it took up your +// whole edge, its resolution would be twice what it really is). +// +// It will subtract one if you take up half of its edge (ie: you only touch half of its verts). +// +// Returns -1 if the edge connection is invalid. +int GetNeighborEdgePower( CDispUtilsHelper *pDisp, int iEdge, int iSub ); + +// This function sets you up so you can walk along an edge that joins two neighbors. +// Add myInc to myIndex and nbInc to nbIndex until myIndex[iFreeDim] >= myEnd. +// +// Returns the neighbor displacement, or NULL if the specified sub neighbor isn't valid. +CDispUtilsHelper* SetupEdgeIncrements( + CDispUtilsHelper *pDisp, + int iEdge, + int iSub, + CVertIndex &myIndex, + CVertIndex &myInc, + CVertIndex &nbIndex, + CVertIndex &nbInc, + int &myEnd, + int &iFreeDim ); + +// Figure out which sub neighbor nodeIndex touches. +// Returns -1 if there is no valid sub neighbor at the specified index. +int GetSubNeighborIndex( + CDispUtilsHelper *pDisp, + int iEdge, + CVertIndex const &nodeIndex + ); + +// Given a vert index and the CSubNeighbor the vert lies on, this +// transforms the specified vert into the neighbor's space. +// +// Note: for corner verts, there may be multiple neighbors touching the same vert, so the +// result you get depends on the edge you specify in iEdge (ie: if you specify the same +// node index but a different edge, you may get a different neighbor). +// +// Note: This only returns a point if the point at nodeIndex actually touches a neighbor point. +// An example where this might be unexpected is if pDisp is power 4 and its neighbor on iEdge +// is power 3, and nodeIndex points at a vert in between two of its neighbor's verts. +// In that case, even though there is a neighbor displacement, nodeIndex doesn't touch +// any points on it, so NULL is returned. +CDispUtilsHelper* TransformIntoSubNeighbor( + CDispUtilsHelper *pDisp, + int iEdge, + int iSub, + CVertIndex const &nodeIndex, + CVertIndex &out + ); + +// Transform pDisp's node at nodeIndex into its neighboring connection. +// Returns the neighbor displacement and sets out to the index in the neighbor. +// +// Note: for corner verts, there may be multiple neighbors touching the same vert, so the +// result you get depends on the edge you specify in iEdge (ie: if you specify the same +// node index but a different edge, you may get a different neighbor). +// +// Note: This only returns a point if the point at nodeIndex actually touches a neighbor point. +// An example where this might surprise you is if pDisp is power 4 and its neighbor on iEdge +// is power 3, and nodeIndex points at a vert in between two of its neighbor's verts. +// In that case, even though there is a neighbor displacement, nodeIndex doesn't touch +// any points on it, so NULL is returned. +CDispUtilsHelper* TransformIntoNeighbor( + CDispUtilsHelper *pDisp, + int iEdge, + CVertIndex const &nodeIndex, + CVertIndex &out ); + +// Returns true if the specified point has one or more neighbors. +bool DoesPointHaveAnyNeighbors( + CDispUtilsHelper *pDisp, + const CVertIndex &index ); + + +void FindNeighboringDispSurfs( CCoreDispInfo **ppListBase, int nListSize ); +void SetupAllowedVerts( CCoreDispInfo **ppListBase, int nListSize ); +void GetDispBox( CCoreDispInfo *pDisp, CDispBox &box ); + +// ----------------------------------------------------------------------------- // +// Inlines. +// ----------------------------------------------------------------------------- // + +#include "disp_powerinfo.h" + + +#endif // DISP_COMMON_H diff --git a/public/disp_powerinfo.cpp b/public/disp_powerinfo.cpp new file mode 100644 index 0000000..47119a9 --- /dev/null +++ b/public/disp_powerinfo.cpp @@ -0,0 +1,580 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "disp_powerinfo.h" +#include "disp_common.h" +#include "commonmacros.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// ------------------------------------------------------------------------ // +// Internal classes. +// ------------------------------------------------------------------------ // + +// These point at the vertices connecting to each of the [north,south,east,west] vertices. +class CVertCorners +{ +public: + short m_Corner1[2]; + short m_Corner2[2]; +}; + + +// ------------------------------------------------------------------------ // +// Globals. +// ------------------------------------------------------------------------ // + +// This points at vertices to the side of a node (north, south, east, west). +static short g_SideVertMul[4][2] = { {1,0}, {0,1}, {-1,0}, {0,-1} }; + +static CVertCorners g_SideVertCorners[4] = +{ + { {1,-1}, {1,1} }, + { {1,1}, {-1,1} }, + { {-1,1}, {-1,-1} }, + { {-1,-1}, {1,-1} } +}; + +// This is used in loops on child nodes. The indices point at the nodes: +// 0 = upper-right +// 1 = upper-left +// 2 = lower-left +// 3 = lower-right +static CVertIndex g_ChildNodeIndexMul[4] = +{ + CVertIndex(1,1), + CVertIndex(-1,1), + CVertIndex(-1,-1), + CVertIndex(1,-1) +}; + +// These are multipliers on vertMul (not nodeMul). +static CVertIndex g_ChildNodeDependencies[4][2] = +{ + { CVertIndex(1,0), CVertIndex(0,1) }, + { CVertIndex(0,1), CVertIndex(-1,0) }, + { CVertIndex(-1,0), CVertIndex(0,-1) }, + { CVertIndex(0,-1), CVertIndex(1,0) } +}; + +// 2x2 rotation matrices for each orientation. +static int g_OrientationRotations[4][2][2] = +{ + {{1, 0}, // CCW_0 + {0, 1}}, + + {{0, 1}, // CCW_90 + {-1,0}}, + + {{-1,0}, // CCW_180 + {0,-1}}, + + {{0, -1}, // CCW_270 + {1, 0}} +}; + + +// ------------------------------------------------------------------------ // +// Helper functions. +// ------------------------------------------------------------------------ // + +// Apply a 2D rotation to the specified CVertIndex around the specified centerpoint. +static CVertIndex Transform2D( + int const mat[2][2], + CVertIndex const &vert, + CVertIndex const ¢erPoint ) +{ + CVertIndex translated = vert - centerPoint; + + CVertIndex transformed( + translated.x*mat[0][0] + translated.y*mat[0][1], + translated.x*mat[1][0] + translated.y*mat[1][1] ); + + return transformed + centerPoint; +} + + +// Rotate a given CVertIndex with a specified orientation. +// Do this with a lookup table eventually! +static void GetEdgeVertIndex( int sideLength, int iEdge, int iVert, CVertIndex &out ) +{ + if( iEdge == NEIGHBOREDGE_RIGHT ) + { + out.x = sideLength - 1; + out.y = iVert; + } + else if( iEdge == NEIGHBOREDGE_TOP ) + { + out.x = iVert; + out.y = sideLength - 1; + } + else if( iEdge == NEIGHBOREDGE_LEFT ) + { + out.x = 0; + out.y = iVert; + } + else + { + out.x = iVert; + out.y = 0; + } +} + + +// Generate an index given a CVertIndex and the size of the displacement it resides in. +static int VertIndex( CVertIndex const &vert, int iMaxPower ) +{ + return vert.y * ((1 << iMaxPower) + 1) + vert.x; +} + + +static CVertIndex WrapVertIndex( CVertIndex const &in, int sideLength ) +{ + int out[2]; + + for( int i=0; i < 2; i++ ) + { + if( in[i] < 0 ) + out[i] = sideLength - 1 - (-in[i] % sideLength); + else if( in[i] >= sideLength ) + out[i] = in[i] % sideLength; + else + out[i] = in[i]; + } + + return CVertIndex( out[0], out[1] ); +} + + +static int GetFreeDependency( CVertDependency *pDep, int nElements ) +{ + for( int i=0; i < nElements; i++ ) + { + if( !pDep[i].IsValid() ) + return i; + } + + Assert( false ); + return 0; +} + + +static void AddDependency( + CVertInfo *dependencies, + int sideLength, + CVertIndex const &nodeIndex, + CVertIndex const &dependency, + int iMaxPower, + bool bCheckNeighborDependency, + bool bAddReverseDependency ) +{ + int iNodeIndex = VertIndex( nodeIndex, iMaxPower ); + CVertInfo *pNode = &dependencies[iNodeIndex]; + + int iDep = GetFreeDependency( pNode->m_Dependencies, sizeof(pNode->m_Dependencies)/sizeof(pNode->m_Dependencies[0]) ); + pNode->m_Dependencies[iDep].m_iVert = dependency; + pNode->m_Dependencies[iDep].m_iNeighbor = -1; + + if( bAddReverseDependency ) + { + CVertInfo *pDep = &dependencies[VertIndex( dependency, iMaxPower )]; + iDep = GetFreeDependency( pDep->m_ReverseDependencies, CVertInfo::NUM_REVERSE_DEPENDENCIES ); + pDep->m_ReverseDependencies[iDep].m_iVert = nodeIndex; + pDep->m_ReverseDependencies[iDep].m_iNeighbor = -1; + } + + // Edge verts automatically add a dependency for the neighbor. + // Internal verts wind up in here twice anyway so it doesn't need to + if( bCheckNeighborDependency ) + { + int iConnection = GetEdgeIndexFromPoint( nodeIndex, iMaxPower ); + if( iConnection != -1 ) + { + Assert( !pNode->m_Dependencies[1].IsValid() ); + + CVertIndex delta( nodeIndex.x - dependency.x, nodeIndex.y - dependency.y ); + CVertIndex newIndex( nodeIndex.x + delta.x, nodeIndex.y + delta.y ); + + int fullSideLength = (1 << iMaxPower) + 1; + pNode->m_Dependencies[1].m_iVert = WrapVertIndex( CVertIndex( newIndex.x, newIndex.y ), fullSideLength ); + pNode->m_Dependencies[1].m_iNeighbor = iConnection; + } + } +} + + +// --------------------------------------------------------------------------------- // +// CTesselateWinding stuff. +// --------------------------------------------------------------------------------- // + +CTesselateVert::CTesselateVert( CVertIndex const &index, int iNode ) + : m_Index( index ) +{ + m_iNode = iNode; +} + + +CVertInfo::CVertInfo() +{ + int i; + for( i=0; i < sizeof(m_Dependencies)/sizeof(m_Dependencies[0]); i++ ) + { + m_Dependencies[i].m_iVert = CVertIndex( -1, -1 ); + m_Dependencies[i].m_iNeighbor = -1; + } + + for( i=0; i < sizeof(m_ReverseDependencies)/sizeof(m_ReverseDependencies[0]); i++ ) + { + m_ReverseDependencies[i].m_iVert = CVertIndex( -1, -1 ); + m_ReverseDependencies[i].m_iNeighbor = -1; + } + + m_iParent.x = m_iParent.y = -1; + m_iNodeLevel = -1; +} + + +CTesselateVert g_TesselateVerts[] = +{ + CTesselateVert( CVertIndex(1,-1), CHILDNODE_LOWER_RIGHT), + CTesselateVert( CVertIndex(0,-1), -1), + CTesselateVert( CVertIndex(-1,-1), CHILDNODE_LOWER_LEFT), + CTesselateVert( CVertIndex(-1, 0), -1), + CTesselateVert( CVertIndex(-1, 1), CHILDNODE_UPPER_LEFT), + CTesselateVert( CVertIndex(0, 1), -1), + CTesselateVert( CVertIndex(1, 1), CHILDNODE_UPPER_RIGHT), + CTesselateVert( CVertIndex(1, 0), -1), + CTesselateVert( CVertIndex(1,-1), CHILDNODE_LOWER_RIGHT) +}; + +CTesselateWinding g_TWinding = +{ + g_TesselateVerts, + sizeof( g_TesselateVerts ) / sizeof( g_TesselateVerts[0] ) +}; + + + +// --------------------------------------------------------------------------------- // +// CPowerInfo stuff. +// --------------------------------------------------------------------------------- // + +// Precalculated info about each particular displacement size. +#define DECLARE_TABLES( size ) \ + static CVertInfo g_VertInfo_##size##x##size[ size*size ]; \ + static CFourVerts g_SideVerts_##size##x##size[ size*size ]; \ + static CFourVerts g_ChildVerts_##size##x##size[ size*size ]; \ + static CFourVerts g_SideVertCorners_##size##x##size[ size*size ]; \ + static CTwoUShorts g_ErrorEdges_##size##x##size[ size*size ]; \ + static CTriInfo g_TriInfos_##size##x##size[ (size-1)*(size-1)*2 ]; \ + static CPowerInfo g_PowerInfo_##size##x##size( \ + g_VertInfo_##size##x##size, \ + g_SideVerts_##size##x##size, \ + g_ChildVerts_##size##x##size, \ + g_SideVertCorners_##size##x##size,\ + g_ErrorEdges_##size##x##size, \ + g_TriInfos_##size##x##size \ + ) + +#define POWERINFO_ENTRY( size ) \ + (&g_PowerInfo_##size##x##size) + +DECLARE_TABLES( 5 ); +DECLARE_TABLES( 9 ); +DECLARE_TABLES( 17 ); + + +// Index by m_Power. +CPowerInfo *g_PowerInfos[NUM_POWERINFOS] = +{ + NULL, + NULL, + POWERINFO_ENTRY(5), + POWERINFO_ENTRY(9), + POWERINFO_ENTRY(17) +}; + + +CPowerInfo::CPowerInfo( + CVertInfo *pVertInfo, + CFourVerts *pSideVerts, + CFourVerts *pChildVerts, + CFourVerts *pSideVertCorners, + CTwoUShorts *pErrorEdges, + CTriInfo *pTriInfos ) +{ + m_pVertInfo = pVertInfo; + m_pSideVerts = pSideVerts; + m_pChildVerts = pChildVerts; + m_pSideVertCorners = pSideVertCorners; + m_pErrorEdges = pErrorEdges; + m_pTriInfos = pTriInfos; +} + +static void InitPowerInfoTriInfos_R( + CPowerInfo *pInfo, + CVertIndex const &nodeIndex, + CTriInfo* &pTriInfo, + int iMaxPower, + int iLevel ) +{ + int iNodeIndex = VertIndex( nodeIndex, iMaxPower ); + + if( iLevel+1 < iMaxPower ) + { + // Recurse into children. + for( int iChild=0; iChild < 4; iChild++ ) + { + InitPowerInfoTriInfos_R( + pInfo, + pInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild], + pTriInfo, + iMaxPower, + iLevel+1 ); + } + } + else + { + unsigned short indices[3]; + + int vertInc = 1 << ((iMaxPower - iLevel) - 1); + + // We're at a leaf, generate the tris. + CTesselateWinding *pWinding = &g_TWinding; + + // Starting at the bottom-left, wind clockwise picking up vertices and + // generating triangles. + int iCurTriVert = 0; + for( int iVert=0; iVert < pWinding->m_nVerts; iVert++ ) + { + CVertIndex sideVert = BuildOffsetVertIndex( nodeIndex, pWinding->m_Verts[iVert].m_Index, vertInc ); + + if( iCurTriVert == 1 ) + { + // Add this vert and finish the tri. + pTriInfo->m_Indices[0] = indices[0]; + pTriInfo->m_Indices[1] = VertIndex( sideVert, iMaxPower ); + pTriInfo->m_Indices[2] = iNodeIndex; + ++pTriInfo; + } + + indices[0] = VertIndex( sideVert, iMaxPower ); + iCurTriVert = 1; + } + } +} + + +static void InitPowerInfo_R( + CPowerInfo *pPowerInfo, + int iMaxPower, + CVertIndex const &nodeIndex, + CVertIndex const &dependency1, + CVertIndex const &dependency2, + CVertIndex const &nodeEdge1, + CVertIndex const &nodeEdge2, + CVertIndex const &iParent, + int iLevel ) +{ + int sideLength = ((1 << iMaxPower) + 1); + int iNodeIndex = VertIndex( nodeIndex, iMaxPower ); + + pPowerInfo->m_pVertInfo[iNodeIndex].m_iParent = iParent; + pPowerInfo->m_pVertInfo[iNodeIndex].m_iNodeLevel = iLevel + 1; + + pPowerInfo->m_pErrorEdges[iNodeIndex].m_Values[0] = (unsigned short)(VertIndex( nodeEdge1, iMaxPower )); + pPowerInfo->m_pErrorEdges[iNodeIndex].m_Values[1] = (unsigned short)(VertIndex( nodeEdge2, iMaxPower )); + + // Add this node's dependencies. + AddDependency( pPowerInfo->m_pVertInfo, sideLength, nodeIndex, dependency1, iMaxPower, false, true ); + AddDependency( pPowerInfo->m_pVertInfo, sideLength, nodeIndex, dependency2, iMaxPower, false, true ); + + // The 4 side vertices depend on this node. + int iPower = iMaxPower - iLevel; + int vertInc = 1 << (iPower - 1); + + for( int iSide=0; iSide < 4; iSide++ ) + { + // Store the side vert index. + CVertIndex sideVert( nodeIndex.x + g_SideVertMul[iSide][0]*vertInc, nodeIndex.y + g_SideVertMul[iSide][1]*vertInc ); + int iSideVert = VertIndex( sideVert, iMaxPower ); + + pPowerInfo->m_pSideVerts[iNodeIndex].m_Verts[iSide] = sideVert; + + // Store the side vert corners. + CVertIndex sideVertCorner0 = CVertIndex( nodeIndex.x + g_SideVertCorners[iSide].m_Corner1[0]*vertInc, nodeIndex.y + g_SideVertCorners[iSide].m_Corner1[1]*vertInc ); + CVertIndex sideVertCorner1 = CVertIndex( nodeIndex.x + g_SideVertCorners[iSide].m_Corner2[0]*vertInc, nodeIndex.y + g_SideVertCorners[iSide].m_Corner2[1]*vertInc ); + + pPowerInfo->m_pSideVertCorners[iNodeIndex].m_Verts[iSide] = sideVertCorner0; + + // Write the side vert corners into the error-edges list. + pPowerInfo->m_pErrorEdges[iSideVert].m_Values[0] = (unsigned short)VertIndex( sideVertCorner0, iMaxPower ); + pPowerInfo->m_pErrorEdges[iSideVert].m_Values[1] = (unsigned short)VertIndex( sideVertCorner1, iMaxPower ); + + AddDependency( + pPowerInfo->m_pVertInfo, + sideLength, + sideVert, + nodeIndex, + iMaxPower, + true, + true ); + } + + // Recurse into the children. + int nodeInc = vertInc >> 1; + if( nodeInc ) + { + for( int iChild=0; iChild < 4; iChild++ ) + { + CVertIndex childVert( nodeIndex.x + g_ChildNodeIndexMul[iChild].x * nodeInc, nodeIndex.y + g_ChildNodeIndexMul[iChild].y * nodeInc ); + + pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild] = childVert; + + InitPowerInfo_R( pPowerInfo, + iMaxPower, + childVert, + + CVertIndex(nodeIndex.x + g_ChildNodeDependencies[iChild][0].x*vertInc, nodeIndex.y + g_ChildNodeDependencies[iChild][0].y*vertInc), + CVertIndex(nodeIndex.x + g_ChildNodeDependencies[iChild][1].x*vertInc, nodeIndex.y + g_ChildNodeDependencies[iChild][1].y*vertInc), + + nodeIndex, + CVertIndex( nodeIndex.x + g_ChildNodeIndexMul[iChild].x * vertInc, nodeIndex.y + g_ChildNodeIndexMul[iChild].y * vertInc ), + + nodeIndex, + iLevel + 1 ); + } + } +} + + +void InitPowerInfo( CPowerInfo *pInfo, int iMaxPower ) +{ + int sideLength = (1 << iMaxPower) + 1; + + // Precalculate the dependency graph. + CVertIndex nodeDependency1( sideLength-1, sideLength-1 ); + CVertIndex nodeDependency2( 0, 0 ); + + pInfo->m_RootNode = CVertIndex( sideLength/2, sideLength/2 ); + pInfo->m_SideLength = sideLength; + pInfo->m_SideLengthM1 = sideLength - 1; + pInfo->m_MidPoint = sideLength / 2; + pInfo->m_MaxVerts = sideLength * sideLength; + + // Setup the corner indices. + pInfo->m_CornerPointIndices[CORNER_LOWER_LEFT].Init( 0, 0 ); + pInfo->m_CornerPointIndices[CORNER_UPPER_LEFT].Init( 0, sideLength-1 ); + pInfo->m_CornerPointIndices[CORNER_UPPER_RIGHT].Init( sideLength-1, sideLength-1 ); + pInfo->m_CornerPointIndices[CORNER_LOWER_RIGHT].Init( sideLength-1, 0 ); + + InitPowerInfo_R( + pInfo, + iMaxPower, + pInfo->m_RootNode, + + nodeDependency1, // dependencies + nodeDependency2, + + CVertIndex(0,0), // error edge + CVertIndex(sideLength-1, sideLength-1), + + CVertIndex(-1,-1), // parent + 0 ); + + pInfo->m_Power = iMaxPower; + + CTriInfo *pTriInfo = pInfo->m_pTriInfos; + InitPowerInfoTriInfos_R( pInfo, pInfo->m_RootNode, pTriInfo, iMaxPower, 0 ); + + for( int iEdge=0; iEdge < 4; iEdge++ ) + { + // Figure out the start vert and increment. + CVertIndex nextVert; + GetEdgeVertIndex( sideLength, iEdge, 0, pInfo->m_EdgeStartVerts[iEdge] ); + GetEdgeVertIndex( sideLength, iEdge, 1, nextVert ); + pInfo->m_EdgeIncrements[iEdge] = nextVert - pInfo->m_EdgeStartVerts[iEdge]; + + // Now get the neighbor's start vert and increment. + CVertIndex nbStartVert, nbNextVert, nbDelta; + GetEdgeVertIndex( sideLength, (iEdge+2)&3, 0, nbStartVert ); + GetEdgeVertIndex( sideLength, (iEdge+2)&3, 1, nbNextVert ); + nbDelta = nbNextVert - nbStartVert; + + // Rotate it for each orientation. + for( int orient=0; orient < 4; orient++ ) + { + pInfo->m_NeighborStartVerts[iEdge][orient] = Transform2D( + g_OrientationRotations[orient], + nbStartVert, + CVertIndex( sideLength/2, sideLength/2 ) ); + + pInfo->m_NeighborIncrements[iEdge][orient] = Transform2D( + g_OrientationRotations[orient], + nbDelta, + CVertIndex(0,0) ); + } + } + + + // Init the node index increments. + int curPowerOf4 = 1; + int curTotal = 0; + for( int i=0; i < iMaxPower-1; i++ ) + { + curTotal += curPowerOf4; + + pInfo->m_NodeIndexIncrements[iMaxPower-i-2] = curTotal; + + curPowerOf4 *= 4; + } + + // Store off the total node count + pInfo->m_NodeCount = curTotal + curPowerOf4; + + pInfo->m_nTriInfos = Square( 1 << iMaxPower ) * 2; +} + +class CPowerInfoInitializer +{ +public: + CPowerInfoInitializer() + { + Assert( MAX_MAP_DISP_POWER+1 == NUM_POWERINFOS ); + + for( int i=0; i <= MAX_MAP_DISP_POWER; i++ ) + { + if( g_PowerInfos[i] ) + { + InitPowerInfo( g_PowerInfos[i], i ); + } + } + } +}; + +static CPowerInfoInitializer g_PowerInfoInitializer; + + +const CPowerInfo* GetPowerInfo( int iPower ) +{ + Assert( iPower >= 0 && iPower < ARRAYSIZE( g_PowerInfos ) ); + Assert( g_PowerInfos[iPower] ); + return g_PowerInfos[iPower]; +} + + +// ------------------------------------------------------------------------------------------------ // +// CPowerInfo member function initialization. +// ------------------------------------------------------------------------------------------------ // + +const CVertIndex& CPowerInfo::GetCornerPointIndex( int iCorner ) const +{ + Assert( iCorner >= 0 && iCorner < 4 ); + return m_CornerPointIndices[iCorner]; +} + diff --git a/public/disp_powerinfo.h b/public/disp_powerinfo.h new file mode 100644 index 0000000..0abd035 --- /dev/null +++ b/public/disp_powerinfo.h @@ -0,0 +1,213 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This module defines the CPowerInfo class, which contains a +// whole bunch of precalculated data for each displacement power. +// It holds data that indicates how to tesselate, how to access +// neighbor displacements, etc. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DISP_POWERINFO_H +#define DISP_POWERINFO_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "disp_vertindex.h" +#include "bspfile.h" + + +#define NUM_POWERINFOS (MAX_MAP_DISP_POWER+1) + + +struct DispNodeInfo_t +{ + enum + { + // Indicates if any children at all have triangles + CHILDREN_HAVE_TRIANGLES = 0x1 + }; + + + // Indicates which tesselation indices are associated with a node + unsigned short m_FirstTesselationIndex; + unsigned char m_Count; + unsigned char m_Flags; +}; + + +// ------------------------------------------------------------------------ // +// CTesselateWindings are used to tell what order a node needs to visit +// vertices while tesselating. +// ------------------------------------------------------------------------ // +class CTesselateVert +{ +public: + CTesselateVert( CVertIndex const &index, int iNode ); + + CVertIndex m_Index; + short m_iNode; // Which node this vert is a part of (-1 on left, right, up, and down). +}; + + +class CTesselateWinding +{ +public: + CTesselateVert *m_Verts; + short m_nVerts; // (includes the last vert) +}; + + +class CVertDependency +{ +public: + + // Returns false if there is no dependency stored here. + bool IsValid() { return m_iVert.x != -1; } + + +public: + + // The vert index is in the same power as the source displacement. + // It is also wrapped, so for example, on the middle of the right edge + // of a 3x3, it will have a dependency on the 3x3's root node (1,1), and it + // will have another (1,1) entry that references a neighbor. + CVertIndex m_iVert; + + // This is -1 if the vert exists inside the source displacement. + // It is one of the NEIGHBOREDGE_ codes above if it reaches into a neighbor. + short m_iNeighbor; +}; + + +// Precalculated data about displacement vertices. +class CVertInfo +{ +public: + CVertInfo(); + + // These are the vertices that this vertex depends on (vertices that must be + // active for this vert to exist). + CVertDependency m_Dependencies[2]; + + // These are the vertices that have this vert in their m_Dependencies. + enum { NUM_REVERSE_DEPENDENCIES=4 }; + CVertDependency m_ReverseDependencies[NUM_REVERSE_DEPENDENCIES]; + + short m_iNodeLevel; // -1 if this is not a node. Otherwise, the recursion level + // of this node (root node = 1). + CVertIndex m_iParent; // x=-1 if this is a not a node or if it's the root node. +}; + + +class CTwoUShorts +{ +public: + unsigned short m_Values[2]; +}; + + +class CFourVerts +{ +public: + CVertIndex m_Verts[4]; +}; + + +// Used for referencing triangles in the fully-tesselated displacement by index. +class CTriInfo +{ +public: + unsigned short m_Indices[3]; +}; + + +// Precalculated data for displacements of a certain power. +class CPowerInfo +{ +public: + CPowerInfo( + CVertInfo *pVertInfo, + CFourVerts *pSideVerts, + CFourVerts *pChildVerts, + CFourVerts *pSideVertCorners, + CTwoUShorts *pErrorEdges, + CTriInfo *pTriInfos ); + + int GetPower() const { return m_Power; } + int GetSideLength() const { return m_SideLength; } + const CVertIndex& GetRootNode() const { return m_RootNode; } + int GetMidPoint() const { return m_MidPoint; } // Half the edge length. + + // Get at the tri list. + int GetNumTriInfos() const { return m_nTriInfos; } + const CTriInfo* GetTriInfo( int i ) const { return &m_pTriInfos[i]; } + + // Get the number of vertices in a displacement of this power. + int GetNumVerts() const { return m_MaxVerts; } + + // Return a corner point index. Indexed by the CORNER_ defines. + const CVertIndex& GetCornerPointIndex( int iCorner ) const; + + +public: + + CVertInfo *m_pVertInfo; + CFourVerts *m_pSideVerts; // The 4 side verts for each node. + CFourVerts *m_pChildVerts; // The 4 children for each node. + CFourVerts *m_pSideVertCorners; + CTwoUShorts *m_pErrorEdges; // These are the edges + // that are used to measure the screenspace + // error with respect to each vert. + + CTriInfo *m_pTriInfos; + int m_nTriInfos; + + int m_Power; + + CVertIndex m_RootNode; + int m_SideLength; + int m_SideLengthM1; // Side length minus 1. + int m_MidPoint; // Side length / 2. + int m_MaxVerts; // m_SideLength * m_SideLength + int m_NodeCount; // total # of nodes, including children + + // Precalculated increments if you're using a bit vector to represent nodes. + // Starting at level 0 of the tree, this stores the increment between the nodes at this + // level. Vectors holding node data are stored in preorder traversal, and these + // increments tell the number of elements between nodes at each level. + int m_NodeIndexIncrements[MAX_MAP_DISP_POWER]; + + CVertIndex m_EdgeStartVerts[4]; + CVertIndex m_EdgeIncrements[4]; + + CVertIndex m_NeighborStartVerts[4][4]; // [side][orientation] + CVertIndex m_NeighborIncrements[4][4]; // [side][orientation] + + +private: + friend void InitPowerInfo( CPowerInfo *pInfo, int iMaxPower ); + + CVertIndex m_CornerPointIndices[4]; +}; + + +// ----------------------------------------------------------------------------- // +// Globals. +// ----------------------------------------------------------------------------- // + +// Indexed by the TWINDING_ enums. +extern CTesselateWinding g_TWinding; + + +// ----------------------------------------------------------------------------- // +// Functions. +// ----------------------------------------------------------------------------- // + +// Valid indices are MIN_MAP_DISP_POWER through (and including) MAX_MAP_DISP_POWER. +const CPowerInfo* GetPowerInfo( int iPower ); + + +#endif // DISP_POWERINFO_H diff --git a/public/disp_tesselate.h b/public/disp_tesselate.h new file mode 100644 index 0000000..d2d3caf --- /dev/null +++ b/public/disp_tesselate.h @@ -0,0 +1,206 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DISP_TESSELATE_H +#define DISP_TESSELATE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "disp_powerinfo.h" + + +inline int InternalVertIndex( const CPowerInfo *pInfo, const CVertIndex &vert ) +{ + return vert.y * pInfo->m_SideLength + vert.x; +} + + +template< class TesselateHelper > +inline void InternalEndTriangle( + TesselateHelper *pHelper, + CVertIndex const &nodeIndex, + int &iCurTriVert ) +{ + // End our current triangle here. + Assert( iCurTriVert == 2 ); + + // Finish the triangle. + pHelper->m_TempIndices[2] = (unsigned short)InternalVertIndex( pHelper->m_pPowerInfo, nodeIndex ); + + pHelper->EndTriangle(); + + // Add on the last vertex to join to the next triangle. + pHelper->m_TempIndices[0] = pHelper->m_TempIndices[1]; + iCurTriVert = 1; +} + + +//----------------------------------------------------------------------------- +// Tesselates a single node, doesn't deal with hierarchy +//----------------------------------------------------------------------------- +template< class TesselateHelper > +inline void TesselateDisplacementNode( + TesselateHelper *pHelper, + CVertIndex const &nodeIndex, + int iLevel, + int *pActiveChildren ) +{ + int iPower = pHelper->m_pPowerInfo->m_Power - iLevel; + int vertInc = 1 << (iPower - 1); + + CTesselateWinding *pWinding = &g_TWinding; + + // Starting at the bottom-left, wind clockwise picking up vertices and + // generating triangles. + int iCurTriVert = 0; + for( int iVert=0; iVert < pWinding->m_nVerts; iVert++ ) + { + CVertIndex sideVert = BuildOffsetVertIndex( nodeIndex, pWinding->m_Verts[iVert].m_Index, vertInc ); + + int iVertNode = pWinding->m_Verts[iVert].m_iNode; + bool bNode = (iVertNode != -1) && pActiveChildren[iVertNode]; + if( bNode ) + { + if( iCurTriVert == 2 ) + InternalEndTriangle( pHelper, nodeIndex, iCurTriVert ); + + iCurTriVert = 0; + } + else + { + int iVertBit = InternalVertIndex( pHelper->m_pPowerInfo, sideVert ); + if( pHelper->m_pActiveVerts[iVertBit>>5] & (1 << (iVertBit & 31)) ) + { + // Ok, add a vert here. + pHelper->m_TempIndices[iCurTriVert] = (unsigned short)InternalVertIndex( pHelper->m_pPowerInfo, sideVert ); + iCurTriVert++; + if( iCurTriVert == 2 ) + InternalEndTriangle( pHelper, nodeIndex, iCurTriVert ); + } + } + } +} + + +//----------------------------------------------------------------------------- +// Tesselates in a *breadth first* fashion +//----------------------------------------------------------------------------- +template< class T > +inline void TesselateDisplacement_R( + T *pHelper, + const CVertIndex &nodeIndex, + int iNodeBitIndex, + int iLevel + ) +{ + // Here's the node info for our current node + Assert( iNodeBitIndex < pHelper->m_pPowerInfo->m_NodeCount ); + DispNodeInfo_t& nodeInfo = pHelper->GetNodeInfo( iNodeBitIndex ); + + // Store off the current number of indices + int oldIndexCount = pHelper->m_nIndices; + + // Go through each quadrant. If there is an active child node, recurse down. + int bActiveChildren[4]; + if( iLevel >= pHelper->m_pPowerInfo->m_Power - 1 ) + { + // This node has no children. + bActiveChildren[0] = bActiveChildren[1] = bActiveChildren[2] = bActiveChildren[3] = false; + } + else + { + int iNodeIndex = InternalVertIndex( pHelper->m_pPowerInfo, nodeIndex ); + + int iChildNodeBit = iNodeBitIndex + 1; + for( int iChild=0; iChild < 4; iChild++ ) + { + CVertIndex const &childNode = pHelper->m_pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild]; + + // Make sure we really can tesselate here (a smaller neighbor displacement could + // have inactivated certain edge verts. + int iVertBit = InternalVertIndex( pHelper->m_pPowerInfo, childNode ); + bActiveChildren[iChild] = ( pHelper->m_pActiveVerts[iVertBit>>5] & (1 << (iVertBit & 31)) ); + + if( bActiveChildren[iChild] ) + { + TesselateDisplacement_R( pHelper, childNode, iChildNodeBit, iLevel+1 ); + } + else + { + // Make sure the triangle counts are cleared on this one because it may visit this + // node in GenerateDecalFragments_R if nodeInfo's CHILDREN_HAVE_TRIANGLES flag is set. + DispNodeInfo_t &childInfo = pHelper->GetNodeInfo( iChildNodeBit ); + childInfo.m_Count = 0; + childInfo.m_Flags = 0; + } + + iChildNodeBit += pHelper->m_pPowerInfo->m_NodeIndexIncrements[iLevel]; + } + } + + // Set the child field + if ( pHelper->m_nIndices != oldIndexCount ) + { + nodeInfo.m_Flags = DispNodeInfo_t::CHILDREN_HAVE_TRIANGLES; + oldIndexCount = pHelper->m_nIndices; + } + else + { + nodeInfo.m_Flags = 0; + } + + // Now tesselate the node itself... + TesselateDisplacementNode( pHelper, nodeIndex, iLevel, bActiveChildren ); + + // Now that we've tesselated, figure out how many indices we've added at this node + nodeInfo.m_Count = pHelper->m_nIndices - oldIndexCount; + nodeInfo.m_FirstTesselationIndex = oldIndexCount; + Assert( nodeInfo.m_Count % 3 == 0 ); +} + + +class CBaseTesselateHelper +{ +public: + + // Functions your derived class must implement: + // void EndTriangle(); // (the 3 indices are in m_TempIndices). + // DispNodeInfo_t& GetNodeInfo( int iNodeBit ); + + + // Set these before calling TesselateDisplacement. + uint32 *m_pActiveVerts; // These bits control the tesselation. + const CPowerInfo *m_pPowerInfo; // Lots of precalculated data about a displacement this size. + + + // Used internally by TesselateDisplacement. + int m_nIndices; // After calling TesselateDisplacement, this is set to the # of indices generated. + unsigned short m_TempIndices[6]; +}; + + + +// This interface is shared betwixt VBSP and the engine. VBSP uses it to build the +// physics mesh and the engine uses it to render. +// +// To use this function, derive a class from CBaseTesselateHelper that supports the TesselateHelper functions. +template< class TesselateHelper > +inline void TesselateDisplacement( TesselateHelper *pHelper ) +{ + pHelper->m_nIndices = 0; + + TesselateDisplacement_R( + pHelper, + pHelper->m_pPowerInfo->m_RootNode, + 0, // node bit indexing CDispDecal::m_NodeIntersects + 0 ); +} + + +#endif // DISP_TESSELATE_H diff --git a/public/disp_vertindex.h b/public/disp_vertindex.h new file mode 100644 index 0000000..4d82cf2 --- /dev/null +++ b/public/disp_vertindex.h @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DISP_VERTINDEX_H +#define DISP_VERTINDEX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/dbg.h" + + +// ------------------------------------------------------------------------ // +// Helper class used for indexing vertices in the 2D grid. +// ------------------------------------------------------------------------ // + +class CVertIndex +{ +public: + CVertIndex(); + CVertIndex( short ix, short iy ); + + void Init( short ix, short iy ); + + short& operator[]( short i ); + short const& operator[]( short i ) const; + void operator+=( CVertIndex const &other ); + void operator-=( CVertIndex const &other ); + CVertIndex operator+( CVertIndex const &other ) const; + CVertIndex operator-( CVertIndex const &other ) const; + void operator<<=( int shift ); + void operator>>=( int shift ); + bool operator==( CVertIndex const &other ) const; + bool operator!=( CVertIndex const &other ) const; + + +public: + + short x, y; +}; + + +// ------------------------------------------------------------------ // +// Helper functions. +// ------------------------------------------------------------------ // + +inline CVertIndex BuildOffsetVertIndex( + CVertIndex const &nodeIndex, + CVertIndex const &offset, + int mul ) +{ + return CVertIndex( nodeIndex.x + offset.x * mul, nodeIndex.y + offset.y * mul ); +} + + +// ------------------------------------------------------------------ // +// CVertIndex inlines. +// ------------------------------------------------------------------ // + +inline CVertIndex::CVertIndex() +{ +} + + +inline CVertIndex::CVertIndex( short ix, short iy ) +{ + x = ix; + y = iy; +} + + +inline void CVertIndex::Init( short ix, short iy ) +{ + x = ix; + y = iy; +} + + +inline short& CVertIndex::operator[]( short i ) +{ + Assert( i >= 0 && i <= 1 ); + return ((short*)this)[i]; +} + + +inline short const& CVertIndex::operator[]( short i ) const +{ + Assert( i >= 0 && i <= 1 ); + return ((short*)this)[i]; +} + + +inline void CVertIndex::operator+=( CVertIndex const &other ) +{ + x += other.x; + y += other.y; +} + + +inline void CVertIndex::operator-=( CVertIndex const &other ) +{ + x -= other.x; + y -= other.y; +} + + +inline CVertIndex CVertIndex::operator+( CVertIndex const &other ) const +{ + return CVertIndex( x + other.x, y + other.y ); +} + + +inline CVertIndex CVertIndex::operator-( CVertIndex const &other ) const +{ + return CVertIndex( x - other.x, y - other.y ); +} + + +inline void CVertIndex::operator<<=( int shift ) +{ + x <<= shift; + y <<= shift; +} + + +inline void CVertIndex::operator>>=( int shift ) +{ + x >>= shift; + y >>= shift; +} + + +inline bool CVertIndex::operator==( CVertIndex const &other ) const +{ + return x==other.x && y==other.y; +} + + +inline bool CVertIndex::operator!=( CVertIndex const &other ) const +{ + return x!=other.x || y!=other.y; +} + + +#endif // DISP_VERTINDEX_H diff --git a/public/dispcoll.cpp b/public/dispcoll.cpp new file mode 100644 index 0000000..3583d4a --- /dev/null +++ b/public/dispcoll.cpp @@ -0,0 +1,1994 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "BuildDisp.h" +#include "DispColl.h" +#include "tier0/dbg.h" + +//============================================================================= + +const float CDispCollTree::COLLISION_EPSILON = 0.01f; +const float CDispCollTree::ONE_MINUS_COLLISION_EPSILON = 1.0f - COLLISION_EPSILON; + +//============================================================================= +// +// Displacement Collision Triangle Functions +// + + +//----------------------------------------------------------------------------- +// Purpose: initialize the displacement triangles +//----------------------------------------------------------------------------- +void CDispCollTri::Init( void ) +{ + for( int i = 0; i < 3; i++ ) + { + m_Points[i].x = 0.0f; m_Points[i].y = 0.0f; m_Points[i].z = 0.0f; + m_PointNormals[i].x = 0.0f; m_PointNormals[i].y = 0.0f; m_PointNormals[i].z = 0.0f; + } + + m_Normal.x = 0.0f; m_Normal.y = 0.0f; m_Normal.z = 0.0f; + m_Distance = 0.0f; + + m_ProjAxes[0] = -1; + m_ProjAxes[1] = -1; + + m_bIntersect = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollTri::SetPoint( int index, Vector const &vert ) +{ + Assert( index >= 0 ); + Assert( index < 3 ); + + m_Points[index].x = vert[0]; + m_Points[index].y = vert[1]; + m_Points[index].z = vert[2]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollTri::SetPointNormal( int index, Vector const &normal ) +{ + Assert( index >= 0 ); + Assert( index < 3 ); + + m_PointNormals[index].x = normal[0]; + m_PointNormals[index].y = normal[1]; + m_PointNormals[index].z = normal[2]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTri::CalcPlane( void ) +{ + // + // calculate the plane normal and distance + // + Vector segment1, segment2, cross; + + segment1 = m_Points[1] - m_Points[0]; + segment2 = m_Points[2] - m_Points[0]; + cross = segment1.Cross( segment2 ); + m_Normal = cross; + VectorNormalize(m_Normal); + + m_Distance = m_Normal.Dot( m_Points[0] ); + + // + // calculate the projection axes + // + if( FloatMakePositive( m_Normal[0] ) > FloatMakePositive( m_Normal[1] ) ) + { + if( FloatMakePositive( m_Normal[0] ) > FloatMakePositive( m_Normal[2] ) ) + { + m_ProjAxes[0] = 1; + m_ProjAxes[1] = 2; + } + else + { + m_ProjAxes[0] = 0; + m_ProjAxes[1] = 1; + } + } + else + { + if( FloatMakePositive( m_Normal[1] ) > FloatMakePositive( m_Normal[2] ) ) + { + m_ProjAxes[0] = 0; + m_ProjAxes[1] = 2; + } + else + { + m_ProjAxes[0] = 0; + m_ProjAxes[1] = 1; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollTri::SetIntersect( bool bIntersect ) +{ + m_bIntersect = bIntersect; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool CDispCollTri::IsIntersect( void ) +{ + return m_bIntersect; +} + + +//============================================================================= +// +// Displacement Collision Node Functions +// + + +//----------------------------------------------------------------------------- +// Purpose: constructor +//----------------------------------------------------------------------------- +CDispCollNode::CDispCollNode() +{ + m_Bounds[0].x = m_Bounds[0].y = m_Bounds[0].z = 99999.9f; + m_Bounds[1].x = m_Bounds[1].y = m_Bounds[1].z = -99999.9f; + + m_Tris[0].Init(); + m_Tris[1].Init(); + + m_bIsLeaf = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool CDispCollNode::IsLeaf( void ) +{ + return m_bIsLeaf; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollNode::SetBounds( Vector const &bMin, Vector const &bMax ) +{ + m_Bounds[0] = bMin; + m_Bounds[1] = bMax; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollNode::GetBounds( Vector &bMin, Vector &bMax ) +{ + bMin = m_Bounds[0]; + bMax = m_Bounds[1]; +} + + +//============================================================================= +// +// Displacement Collision Tree Functions +// + +//----------------------------------------------------------------------------- +// Purpose: constructor +//----------------------------------------------------------------------------- +CDispCollTree::CDispCollTree() +{ + m_Power = 0; + + m_NodeCount = 0; + m_pNodes = NULL; + + InitAABBData(); +} + + +//----------------------------------------------------------------------------- +// Purpose: deconstructor +//----------------------------------------------------------------------------- +CDispCollTree::~CDispCollTree() +{ + FreeNodes(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::InitAABBData( void ) +{ + m_AABBNormals[0].x = -1.0f; m_AABBNormals[0].y = 0.0f; m_AABBNormals[0].z = 0.0f; + m_AABBNormals[1].x = 1.0f; m_AABBNormals[1].y = 0.0f; m_AABBNormals[1].z = 0.0f; + + m_AABBNormals[2].x = 0.0f; m_AABBNormals[2].y = -1.0f; m_AABBNormals[2].z = 0.0f; + m_AABBNormals[3].x = 0.0f; m_AABBNormals[3].y = 1.0f; m_AABBNormals[3].z = 0.0f; + + m_AABBNormals[4].x = 0.0f; m_AABBNormals[4].y = 0.0f; m_AABBNormals[4].z = -1.0f; + m_AABBNormals[5].x = 0.0f; m_AABBNormals[5].y = 0.0f; m_AABBNormals[5].z = 1.0f; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::CalcBounds( CDispCollNode *pNode, int nodeIndex ) +{ + Vector bounds[2]; + bounds[0].Init( 99999.9f, 99999.9f, 99999.9f ); + bounds[1].Init( -99999.9f, -99999.9f, -99999.9f ); + + // + // handle leaves differently -- bounding volume defined by triangles + // + if( pNode->IsLeaf() ) + { + for( int i = 0; i < 2; i++ ) + { + for( int j = 0; j < 3; j++ ) + { + // + // minimum + // + if( bounds[0].x > pNode->m_Tris[i].m_Points[j].x ) { bounds[0].x = pNode->m_Tris[i].m_Points[j].x; } + if( bounds[0].y > pNode->m_Tris[i].m_Points[j].y ) { bounds[0].y = pNode->m_Tris[i].m_Points[j].y; } + if( bounds[0].z > pNode->m_Tris[i].m_Points[j].z ) { bounds[0].z = pNode->m_Tris[i].m_Points[j].z; } + + // + // maximum + // + if( bounds[1].x < pNode->m_Tris[i].m_Points[j].x ) { bounds[1].x = pNode->m_Tris[i].m_Points[j].x; } + if( bounds[1].y < pNode->m_Tris[i].m_Points[j].y ) { bounds[1].y = pNode->m_Tris[i].m_Points[j].y; } + if( bounds[1].z < pNode->m_Tris[i].m_Points[j].z ) { bounds[1].z = pNode->m_Tris[i].m_Points[j].z; } + } + } + } + // + // bounding volume defined by maxima and minima of children volumes + // + else + { + for( int i = 0; i < 4; i++ ) + { + int childIndex = GetChildNode( nodeIndex, i ); + CDispCollNode *pChildNode = &m_pNodes[childIndex]; + + Vector childBounds[2]; + pChildNode->GetBounds( childBounds[0], childBounds[1] ); + + // + // minimum + // + if( bounds[0].x > childBounds[0].x ) { bounds[0].x = childBounds[0].x; } + if( bounds[0].y > childBounds[0].y ) { bounds[0].y = childBounds[0].y; } + if( bounds[0].z > childBounds[0].z ) { bounds[0].z = childBounds[0].z; } + + // + // maximum + // + if( bounds[1].x < childBounds[1].x ) { bounds[1].x = childBounds[1].x; } + if( bounds[1].y < childBounds[1].y ) { bounds[1].y = childBounds[1].y; } + if( bounds[1].z < childBounds[1].z ) { bounds[1].z = childBounds[1].z; } + } + } + + pNode->SetBounds( bounds[0], bounds[1] ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::CreateNodes_r( CCoreDispInfo *pDisp, int nodeIndex, int termLevel ) +{ + int nodeLevel = GetNodeLevel( nodeIndex ); + + // + // terminating condition -- set node info (leaf or otherwise) + // + if( nodeLevel == termLevel ) + { + CDispCollNode *pNode = &m_pNodes[nodeIndex]; + CalcBounds( pNode, nodeIndex ); + + return; + } + + // + // recurse into children + // + for( int i = 0; i < 4; i++ ) + { + CreateNodes_r( pDisp, GetChildNode( nodeIndex, i ), termLevel ); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::CreateNodes( CCoreDispInfo *pDisp ) +{ + // + // create all nodes in tree + // + int power = pDisp->GetPower() + 1; + for( int level = power; level > 0; level-- ) + { + CreateNodes_r( pDisp, 0 /* rootIndex */, level ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CDispCollTree::GetNodeIndexFromComponents( int x, int y ) +{ + int index = 0; + + // Interleave bits from the x and y values to create the index: + + for( int shift = 0; x != 0; shift += 2, x >>= 1 ) + { + index |= ( x & 1 ) << shift; + } + + for( shift = 1; y != 0; shift += 2, y >>= 1 ) + { + index |= ( y & 1 ) << shift; + } + + return index; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::InitLeaves( CCoreDispInfo *pDisp ) +{ + // + // get power and width and displacement surface + // + int power = pDisp->GetPower(); + int width = pDisp->GetWidth(); + + // + // get leaf indices + // + int startIndex = CalcNodeCount( power - 1 ); + int endIndex = CalcNodeCount( power ); + + for( int index = startIndex; index < endIndex; index++ ) + { + // + // create triangles at leaves + // + int x = ( index - startIndex ) % ( width - 1 ); + int y = ( index - startIndex ) / ( width - 1 ); + + int nodeIndex = GetNodeIndexFromComponents( x, y ); + nodeIndex += startIndex; + + Vector vert; + Vector normal; + + // + // tri 1 + // + pDisp->GetVert( x + ( y * width ), vert ); + pDisp->GetNormal( x + ( y * width ), normal ); + m_pNodes[nodeIndex].m_Tris[0].SetPoint( 0, vert ); + m_pNodes[nodeIndex].m_Tris[0].SetPointNormal( 0, normal ); + + pDisp->GetVert( x + ( ( y + 1 ) * width ), vert ); + pDisp->GetNormal( x + ( ( y + 1 ) * width ), normal ); + m_pNodes[nodeIndex].m_Tris[0].SetPoint( 1, vert ); + m_pNodes[nodeIndex].m_Tris[0].SetPointNormal( 1, normal ); + + pDisp->GetVert( ( x + 1 ) + ( y * width ), vert ); + pDisp->GetNormal( ( x + 1 ) + ( y * width ), normal ); + m_pNodes[nodeIndex].m_Tris[0].SetPoint( 2, vert ); + m_pNodes[nodeIndex].m_Tris[0].SetPointNormal( 2, normal ); + + m_pNodes[nodeIndex].m_Tris[0].CalcPlane(); + + // + // tri 2 + // + pDisp->GetVert( ( x + 1 ) + ( y * width ), vert ); + pDisp->GetNormal( ( x + 1 ) + ( y * width ), normal ); + m_pNodes[nodeIndex].m_Tris[1].SetPoint( 0, vert ); + m_pNodes[nodeIndex].m_Tris[1].SetPointNormal( 0, normal ); + + pDisp->GetVert( x + ( ( y + 1 ) * width ), vert ); + pDisp->GetNormal( x + ( ( y + 1 ) * width ), normal ); + m_pNodes[nodeIndex].m_Tris[1].SetPoint( 1, vert ); + m_pNodes[nodeIndex].m_Tris[1].SetPointNormal( 1, normal ); + + pDisp->GetVert( ( x + 1 ) + ( ( y + 1 ) * width ), vert ); + pDisp->GetNormal( ( x + 1 ) + ( ( y + 1 ) * width ), normal ); + m_pNodes[nodeIndex].m_Tris[1].SetPoint( 2, vert ); + m_pNodes[nodeIndex].m_Tris[1].SetPointNormal( 2, normal ); + + m_pNodes[nodeIndex].m_Tris[1].CalcPlane(); + + // set node as leaf + m_pNodes[nodeIndex].m_bIsLeaf = true; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: allocate and initialize the displacement collision tree +// Input: power - size of the displacement surface +// Output: bool - success? (true/false) +//----------------------------------------------------------------------------- +bool CDispCollTree::Create( CCoreDispInfo *pDisp ) +{ + // + // calculate the number of nodes needed given the size of the displacement + // + m_Power = pDisp->GetPower(); + m_NodeCount = CalcNodeCount( m_Power ); + + // + // allocate tree space + // + if( !AllocNodes( m_NodeCount ) ) + return false; + + // initialize leaves + InitLeaves( pDisp ); + + // create tree nodes + CreateNodes( pDisp ); + + // tree successfully created! + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: allocate memory for the displacement collision tree +// Input: nodeCount - number of nodes to allocate +// Output: bool - success? (true/false) +//----------------------------------------------------------------------------- +bool CDispCollTree::AllocNodes( int nodeCount ) +{ + // sanity check + Assert( nodeCount != 0 ); + + m_pNodes = new CDispCollNode[nodeCount]; + if( !m_pNodes ) + return false; + + // tree successfully allocated! + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: release allocated memory for displacement collision tree +//----------------------------------------------------------------------------- +void CDispCollTree::FreeNodes( void ) +{ + if( m_pNodes ) + { + delete [] m_pNodes; + m_pNodes = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: calculate the number of tree nodes given the size of the +// displacement surface +// Input: power - size of the displacement surface +// Output: int - the number of tree nodes +//----------------------------------------------------------------------------- +inline int CDispCollTree::CalcNodeCount( int power ) +{ + // power range [2...4] + Assert( power > 0 ); + Assert( power < 5 ); + + return ( ( 1 << ( ( power + 1 ) << 1 ) ) / 3 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: get the parent node index given the current node +// Input: nodeIndex - current node index +// Output: int - the index of the parent node +//----------------------------------------------------------------------------- +inline int CDispCollTree::GetParentNode( int nodeIndex ) +{ + // node range [0...m_NodeCount) + Assert( nodeIndex >= 0 ); + Assert( nodeIndex < m_NodeCount ); + + // ( nodeIndex - 1 ) / 4 + return ( ( nodeIndex - 1 ) >> 2 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: get the child node index given the current node index and direction +// of the child (1 of 4) +// Input: nodeIndex - current node index +// direction - direction of the child ( [0...3] - SW, SE, NW, NE ) +// Output: int - the index of the child node +//----------------------------------------------------------------------------- +inline int CDispCollTree::GetChildNode( int nodeIndex, int direction ) +{ + // node range [0...m_NodeCount) + Assert( nodeIndex >= 0 ); + Assert( nodeIndex < m_NodeCount ); + + // ( nodeIndex * 4 ) + ( direction + 1 ) + return ( ( nodeIndex << 2 ) + ( direction + 1 ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline int CDispCollTree::GetNodeLevel( int nodeIndex ) +{ + // node range [0...m_NodeCount) + Assert( nodeIndex >= 0 ); + Assert( nodeIndex < m_NodeCount ); + + // level = 2^n + 1 + if( nodeIndex == 0 ) { return 1; } + if( nodeIndex < 5 ) { return 2; } + if( nodeIndex < 21 ) { return 3; } + if( nodeIndex < 85 ) { return 4; } + if( nodeIndex < 341 ) { return 5; } + + return -1; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CDispCollTree::RayTriTest( Vector const &rayStart, Vector const &rayDir, float const rayLength, + CDispCollTri const *pTri, float *fraction ) +{ + const float DET_EPSILON = 0.001f; + const float DIST_EPSILON = 0.001f; + + // + // calculate the edges + // + Vector edge1 = pTri->m_Points[1] - pTri->m_Points[0]; + Vector edge2 = pTri->m_Points[2] - pTri->m_Points[0]; + +// Vector faceNormal = edge1.Cross( edge2 ); +// Vector normNormal = faceNormal.Normalize(); + + // + // calculate the triangle's determinant + // + Vector pVec = rayDir.Cross( edge2 ); + float det = pVec.Dot( edge1 ); + + // if determinant is zero -- ray lies in plane + if( ( det > -DET_EPSILON ) && ( det < DET_EPSILON ) ) + return false; + + // + // utility calculations - inverse determinant and distance from v0 to ray start + // + double invDet = 1.0f / det; + Vector tVec = rayStart - pTri->m_Points[0]; + + // + // calculate the U parameter and test bounds + // + double u = pVec.Dot( tVec ) * invDet; + if( ( u < 0.0f ) || ( u > 1.0f ) ) + return false; + + Vector qVec = tVec.Cross( edge1 ); + + // + // calculate the V parameter and test bounds + // + double v = qVec.Dot( rayDir ) * invDet; + if( ( v < 0.0f ) || ( ( u + v ) > 1.0f ) ) + return false; + + // calculate where ray intersects triangle + *fraction = qVec.Dot( edge2 ) * invDet; + *fraction /= rayLength; + + if( ( *fraction < DIST_EPSILON ) || ( *fraction > ( 1.0f - DIST_EPSILON ) ) ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CDispCollTree::RayTriListTest( CDispCollTreeTempData *pTemp, CDispCollData *pData ) +{ + // save starting fraction -- to test for collision + float startFraction = pData->m_Fraction; + + // + // calculate the ray + // + Vector seg = pData->m_EndPos - pData->m_StartPos; + Vector rayDir = seg; + float rayLength = VectorNormalize( rayDir ); + + // + // test ray against all triangles in list + // + for( int i = 0; i < pTemp->m_TriListCount; i++ ) + { + float fraction = 1.0f; + bool bResult = RayTriTest( pData->m_StartPos, rayDir, rayLength, pTemp->m_ppTriList[i], &fraction ); + if( !bResult ) + continue; + + if( pData->m_bOcclude ) + { + return true; + } + + if( fraction < pData->m_Fraction ) + { + pData->m_Fraction = fraction; + pData->m_Normal = pTemp->m_ppTriList[i]->m_Normal; + pData->m_Distance = pTemp->m_ppTriList[i]->m_Distance; + } + } + + // collision! + if( pData->m_Fraction < startFraction ) + return true; + + // no collision! + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::RayAABBTest( CDispCollTreeTempData *pTemp, Vector &rayStart, Vector &rayEnd ) +{ + const float MY_DIST_EPSILON = 0.01f; + + for( int i = 0; i < 6; i++ ) + { + float dist1 = m_AABBNormals[i].Dot( rayStart ) - pTemp->m_AABBDistances[i]; + float dist2 = m_AABBNormals[i].Dot( rayEnd ) - pTemp->m_AABBDistances[i]; + + // + // entry intersection point - move ray start up to intersection + // + if( ( dist1 > MY_DIST_EPSILON ) && ( dist2 < -MY_DIST_EPSILON ) ) + { + float fraction = ( dist1 / ( dist1 - dist2 ) ); + + Vector segment, increment; + segment = ( rayEnd - rayStart ) * fraction; + increment = segment; + VectorNormalize(increment); + segment += increment; + rayStart += segment; + } + else if( ( dist1 > MY_DIST_EPSILON ) && ( dist2 > MY_DIST_EPSILON ) ) + { + return false; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::CreatePlanesFromBounds( CDispCollTreeTempData *pTemp, Vector const &bbMin, Vector const &bbMax ) +{ + // + // note -- these never change! + // +// m_AABBNormals[0].x = -1; +// m_AABBNormals[1].x = 1; + +// m_AABBNormals[2].y = -1; +// m_AABBNormals[3].y = 1; + +// m_AABBNormals[4].z = -1; +// m_AABBNormals[5].z = 1; + + pTemp->m_AABBDistances[0] = -bbMin.x; + pTemp->m_AABBDistances[1] = bbMax.x; + + pTemp->m_AABBDistances[2] = -bbMin.y; + pTemp->m_AABBDistances[3] = bbMax.y; + + pTemp->m_AABBDistances[4] = -bbMin.z; + pTemp->m_AABBDistances[5] = bbMax.z; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::RayNodeTest_r( CDispCollTreeTempData *pTemp, int nodeIndex, Vector rayStart, Vector rayEnd ) +{ + // get the current node + CDispCollNode *pNode = &m_pNodes[nodeIndex]; + + // + // get node bounding box and create collision planes + // + Vector bounds[2]; + pNode->GetBounds( bounds[0], bounds[1] ); + CreatePlanesFromBounds( pTemp, bounds[0], bounds[1] ); + + bool bIntersect = RayAABBTest( pTemp, rayStart, rayEnd ); + if( bIntersect ) + { + // done -- add triangles to triangle list + if( pNode->IsLeaf() ) + { + // Assert for now -- flush cache later!!!!! + Assert( pTemp->m_TriListCount >= 0 ); + Assert( pTemp->m_TriListCount < TRILIST_CACHE_SIZE ); + + pTemp->m_ppTriList[pTemp->m_TriListCount] = &pNode->m_Tris[0]; + pTemp->m_ppTriList[pTemp->m_TriListCount+1] = &pNode->m_Tris[1]; + pTemp->m_TriListCount += 2; + } + // continue recursion + else + { + for( int i = 0; i < 4; i++ ) + { + RayNodeTest_r( pTemp, GetChildNode( nodeIndex, i ), rayStart, rayEnd ); + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::RayTestAllTris( CDispCollData *pData, int power ) +{ + // + // get leaf indices + // + int startIndex = CalcNodeCount( power - 1 ); + int endIndex = CalcNodeCount( power ); + + // save incoming fraction + float startFraction = pData->m_Fraction; + float fraction = pData->m_Fraction; + + Vector ray = pData->m_EndPos - pData->m_StartPos; + Vector rayDir = ray; + float rayLength = VectorNormalize(rayDir); + + // + // test ray against all triangles in list + // + for( int index = startIndex; index < endIndex; index++ ) + { + for( int j = 0; j < 2; j++ ) + { + bool bResult = RayTriTest( pData->m_StartPos, rayDir, rayLength, &m_pNodes[index].m_Tris[j], &fraction ); + if( !bResult ) + continue; + + if( pData->m_bOcclude ) + { + return true; + } + + if( fraction < pData->m_Fraction ) + { + pData->m_Fraction = fraction; + pData->m_Normal = m_pNodes[index].m_Tris[j].m_Normal; + pData->m_Distance = m_pNodes[index].m_Tris[j].m_Distance; + } + } + } + + // collision! + if( pData->m_Fraction < startFraction ) + return true; + + // no collision! + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::RayTest( CDispCollData *pData ) +{ + // reset the triangle list count + CDispCollTreeTempData tmp; + tmp.m_TriListCount = 0; + + // trace against nodes (copy start, end because they change) + RayNodeTest_r( &tmp, 0, pData->m_StartPos, pData->m_EndPos ); + + // + // trace against tris (if need be) + // + if( tmp.m_TriListCount != 0 ) + { + bool result = RayTriListTest( &tmp, pData ); + return result; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::SweptAABBTriIntersect( Vector &rayStart, Vector &rayEnd, Vector &extents, + CDispCollTri const *pTri, Vector &plNormal, float *plDist, + float *fraction ) +{ + + // + // PUT A COPY HERE OF START AND END -- SINCE I CHANGE THEM!!!!!! + // + + + + + + int dir, ptIndex; + float closeValue; + float distStart, distEnd; + float t; + Vector rayPt; + + // get ray direction + Vector rayDir = rayEnd - rayStart; + + // initialize fraction + *fraction = 1.0f; + + // + // test for collision with axial planes (x, y, z) + // + for( dir = 0; dir < 3; dir++ ) + { + if( rayDir[dir] < 0.0f ) + { + closeValue = -99999.9f; + for( ptIndex = 0; ptIndex < 3; ptIndex++ ) + { + if( pTri->m_Points[ptIndex][dir] > closeValue ) + { + closeValue = pTri->m_Points[ptIndex][dir]; + } + } + + closeValue += extents[dir]; + + distStart = rayStart[dir] - closeValue; + distEnd = rayEnd[dir] - closeValue; + } + else + { + closeValue = 99999.9f; + for( ptIndex = 0; ptIndex < 3; ptIndex++ ) + { + if( pTri->m_Points[ptIndex][dir] < closeValue ) + { + closeValue = pTri->m_Points[ptIndex][dir]; + } + } + + closeValue -= extents[dir]; + + distStart = -( rayStart[dir] - closeValue ); + distEnd = -( rayEnd[dir] - closeValue ); + } + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal.Init(); + plNormal[dir] = 1.0f; + *plDist = closeValue; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + } + + // + // check for an early out + // + if( ( pTri->m_Normal[0] > ONE_MINUS_COLLISION_EPSILON ) || + ( pTri->m_Normal[1] > ONE_MINUS_COLLISION_EPSILON ) || + ( pTri->m_Normal[2] > ONE_MINUS_COLLISION_EPSILON ) ) + { + if( *fraction == 1.0f ) + return false; + + return true; + } + + // + // handle 9 edge tests + // + Vector normal; + Vector edge; + float dist; + + // find the closest box point + Vector boxPt( 0.0f, 0.0f, 0.0f ); + for( dir = 0; dir < 3; dir++ ) + { + if( rayDir[dir] < 0.0f ) + { + boxPt[dir] = extents[dir]; + } + else + { + boxPt[dir] = -extents[dir]; + } + } + + // + // edge 0 + // + edge = pTri->m_Points[1] - pTri->m_Points[0]; + + // cross x-edge + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + + // extents adjusted dist + dist = ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + // find distances from plane (start, end) + distStart = ( normal.y * rayStart.y ) + ( normal.z * rayStart.z ) - dist; + distEnd = ( normal.y * rayEnd.y ) + ( normal.z * rayEnd.z ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // cross y-edge + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + + // extents adjusted dist + dist = ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + // find distances from plane (start, end) + distStart = ( normal.x * rayStart.x ) + ( normal.z * rayStart.z ) - dist; + distEnd = ( normal.x * rayEnd.x ) + ( normal.z * rayEnd.z ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // cross z-edge + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + + // extents adjusted dist + dist = ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ); + + // find distances from plane (start, end) + distStart = ( normal.x * rayStart.x ) + ( normal.y * rayStart.y ) - dist; + distEnd = ( normal.x * rayEnd.x ) + ( normal.y * rayEnd.y ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // + // edge 1 + // + edge = pTri->m_Points[2] - pTri->m_Points[1]; + + // cross x-edge + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + + // extents adjusted dist + dist = ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + // find distances from plane (start, end) + distStart = ( normal.y * rayStart.y ) + ( normal.z * rayStart.z ) - dist; + distEnd = ( normal.y * rayEnd.y ) + ( normal.z * rayEnd.z ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // cross y-edge + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + + // extents adjusted dist + dist = ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + // find distances from plane (start, end) + distStart = ( normal.x * rayStart.x ) + ( normal.z * rayStart.z ) - dist; + distEnd = ( normal.x * rayEnd.x ) + ( normal.z * rayEnd.z ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // cross z-edge + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + + // extents adjusted dist + dist = ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ); + + // find distances from plane (start, end) + distStart = ( normal.x * rayStart.x ) + ( normal.y * rayStart.y ) - dist; + distEnd = ( normal.x * rayEnd.x ) + ( normal.y * rayEnd.y ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // + // edge 2 + // + edge = pTri->m_Points[0] - pTri->m_Points[2]; + + // cross x-edge + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + + // extents adjusted dist + dist = ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + // find distances from plane (start, end) + distStart = ( normal.y * rayStart.y ) + ( normal.z * rayStart.z ) - dist; + distEnd = ( normal.y * rayEnd.y ) + ( normal.z * rayEnd.z ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // cross y-edge + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + + // extents adjusted dist + dist = ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + // find distances from plane (start, end) + distStart = ( normal.x * rayStart.x ) + ( normal.z * rayStart.z ) - dist; + distEnd = ( normal.x * rayEnd.x ) + ( normal.z * rayEnd.z ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // cross z-edge + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + + // extents adjusted dist + dist = ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ); + + // find distances from plane (start, end) + distStart = ( normal.x * rayStart.x ) + ( normal.y * rayStart.y ) - dist; + distEnd = ( normal.x * rayEnd.x ) + ( normal.y * rayEnd.y ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // + // test face plane + // + dist = ( pTri->m_Normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + + ( pTri->m_Normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + + ( pTri->m_Normal.z * ( boxPt.z - pTri->m_Points[0].z ) ); + + distStart = pTri->m_Normal.Dot( rayStart ) - dist; + distEnd = pTri->m_Normal.Dot( rayEnd ) - dist; + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + t = ( distStart - COLLISION_EPSILON ) / ( distStart - distEnd ); + if( t > *fraction ) + { + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayStart ); + *fraction = t; + plNormal = normal; + *plDist = dist; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + t = ( distStart + COLLISION_EPSILON ) / ( distStart - distEnd ); + VectorScale( rayDir, t, rayPt ); + VectorAdd( rayStart, rayPt, rayEnd ); + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + if( *fraction == 1.0f ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBTriIntersect( CDispCollTreeTempData *pTemp, CDispCollData *pData ) +{ + bool bResult = false; + + Vector normal; + float fraction, dist; + + // + // sweep ABB against all triangles in list + // + for( int i = 0; i < pTemp->m_TriListCount; i++ ) + { + if( pTemp->m_ppTriList[i]->IsIntersect() ) + { + bResult = SweptAABBTriIntersect( pData->m_StartPos, pData->m_EndPos, pData->m_Extents, + pTemp->m_ppTriList[i], normal, &dist, &fraction ); + if( bResult ) + { + if( fraction < pData->m_Fraction ) + { + pData->m_Fraction = fraction; + pData->m_Normal = normal; + pData->m_Distance = dist; + } + } + } + } + + return bResult; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::IntersectAABBTriTest( Vector &rayStart, Vector &extents, + CDispCollTri const *pTri ) +{ + int dir, ptIndex; + float dist; + + // + // test axail planes (x, y, z) + // + + for( dir = 0; dir < 3; dir++ ) + { + // + // negative axial plane, component = dir + // + dist = rayStart[dir] - extents[dir]; + for( ptIndex = 0; ptIndex < 3; ptIndex++ ) + { + if( pTri->m_Points[ptIndex][dir] > dist ) + break; + } + + if( ptIndex == 3 ) + return false; + + // + // positive axial plane, component = dir + // + dist = rayStart[dir] + extents[dir]; + for( ptIndex = 0; ptIndex < 3; ptIndex++ ) + { + if( pTri->m_Points[ptIndex][dir] < dist ) + break; + } + + if( ptIndex == 3 ) + return false; + } + + // + // add a test here to see if triangle face normal is close to axial -- done if so!!! + // + if( ( pTri->m_Normal[0] > ONE_MINUS_COLLISION_EPSILON ) || + ( pTri->m_Normal[1] > ONE_MINUS_COLLISION_EPSILON ) || + ( pTri->m_Normal[2] > ONE_MINUS_COLLISION_EPSILON ) ) + return true; + + // find the closest point on the box (use negated tri face noraml) + Vector boxPt( 0.0f, 0.0f, 0.0f ); + for( dir = 0; dir < 3; dir++ ) + { + if( pTri->m_Normal[dir] < 0.0f ) + { + boxPt[dir] = extents[dir]; + } + else + { + boxPt[dir] = -extents[dir]; + } + } + + // + // triangle plane test + // + // do the opposite because the ray has been negated + if( ( ( pTri->m_Normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + + ( pTri->m_Normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + + ( pTri->m_Normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // + // test edge planes - 9 of them + // + Vector normal; + Vector edge; + + // + // edge 0 + // + edge = pTri->m_Points[1] - pTri->m_Points[0]; + + // cross x + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + if( ( ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // cross y + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + if( ( ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // cross z + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + if( ( ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) ) > 0.0f ) + return false; + + // + // edge 1 + // + edge = pTri->m_Points[2] - pTri->m_Points[1]; + + // cross x + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + if( ( ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // cross y + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + if( ( ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // cross z + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + if( ( ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) ) > 0.0f ) + return false; + + // + // edge 2 + // + edge = pTri->m_Points[0] - pTri->m_Points[2]; + + // cross x + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + if( ( ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // cross y + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + if( ( ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.z * ( boxPt.z - pTri->m_Points[0].z ) ) ) > 0.0f ) + return false; + + // cross z + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + if( ( ( normal.x * ( boxPt.x - pTri->m_Points[0].x ) ) + ( normal.y * ( boxPt.y - pTri->m_Points[0].y ) ) ) > 0.0f ) + return false; + + return true; +} + + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::SweptAABBTriTest( Vector &rayStart, Vector &rayEnd, Vector &extents, + CDispCollTri const *pTri ) +{ + // get ray direction + Vector rayDir = rayEnd - rayStart; + + // + // quick and dirty test -- test to see if the object is traveling away from triangle surface??? + // + if( pTri->m_Normal.Dot( rayDir ) > 0.0f ) + return false; + + // + // calc the swept triangle face (negate the ray -- opposite direction of box travel) + // + rayDir.Negate(); + + Vector points[3]; + points[0] = pTri->m_Points[0] + rayDir; + points[1] = pTri->m_Points[1] + rayDir; + points[2] = pTri->m_Points[2] + rayDir; + + // + // handle 4 faces tests (3 axial planes and triangle face) + // + int dir; + float dist; + + // + // axial planes tests (x, y, z) + // + for( dir = 0; dir < 3; dir++ ) + { + bool bOutside = true; + + if( rayDir[dir] < 0.0f ) + { + dist = rayStart[dir] - extents[dir]; + for( int ptIndex = 0; ptIndex < 3; ptIndex ) + { + if( points[ptIndex][dir] > dist ) + { + bOutside = false; + break; + } + } + } + else + { + dist = rayStart[dir] + extents[dir]; + for( int ptIndex = 0; ptIndex < 3; ptIndex ) + { + if( pTri->m_Points[ptIndex][dir] < dist ) + { + bOutside = false; + break; + } + } + } + + if( bOutside ) + return false; + } + + // + // add a test here to see if triangle face normal is close to axial -- done if so!!! + // + if( ( pTri->m_Normal[0] > ONE_MINUS_COLLISION_EPSILON ) || + ( pTri->m_Normal[1] > ONE_MINUS_COLLISION_EPSILON ) || + ( pTri->m_Normal[2] > ONE_MINUS_COLLISION_EPSILON ) ) + return true; + + // + // handle 9 edge tests - always use the newly swept face for this + // + Vector normal; + Vector edge; + + // find the closest box point - (is written opposite to normal due to negating ray) + Vector boxPt( 0.0f, 0.0f, 0.0f ); + for( dir = 0; dir < 3; dir++ ) + { + if( rayDir[dir] < 0.0f ) + { + boxPt[dir] = rayStart[dir] - extents[dir]; + } + else + { + boxPt[dir] = rayStart[dir] + extents[dir]; + } + } + + // + // edge 0 + // + edge = points[1] - points[0]; + + // cross x-edge + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + if( ( ( normal.y * ( boxPt.y - points[0].y ) ) + ( normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + // cross, y-edge + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + if( ( ( normal.x * ( boxPt.x - points[0].x ) ) + ( normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + // cross z-edge + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + if( ( ( normal.x * ( boxPt.x - points[0].x ) ) + ( normal.y * ( boxPt.y - points[0].y ) ) ) > 0.0f ) + return false; + + // + // edge 1 + // + edge = points[2] - points[1]; + + // cross x-edge + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + if( ( ( normal.y * ( boxPt.y - points[0].y ) ) + ( normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + // cross, y-edge + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + if( ( ( normal.x * ( boxPt.x - points[0].x ) ) + ( normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + // cross z-edge + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + if( ( ( normal.x * ( boxPt.x - points[0].x ) ) + ( normal.y * ( boxPt.y - points[0].y ) ) ) > 0.0f ) + return false; + + // + // edge 2 + // + edge = points[0] - points[2]; + + // cross x-edge + normal.x = 0.0f; + normal.y = -edge.z; + normal.z = edge.y; + if( ( ( normal.y * ( boxPt.y - points[0].y ) ) + ( normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + // cross, y-edge + normal.x = edge.z; + normal.y = 0.0f; + normal.z = edge.y; + if( ( ( normal.x * ( boxPt.x - points[0].x ) ) + ( normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + // cross z-edge + normal.x = -edge.y; + normal.y = edge.x; + normal.z = 0.0f; + if( ( ( normal.x * ( boxPt.x - points[0].x ) ) + ( normal.y * ( boxPt.y - points[0].y ) ) ) > 0.0f ) + return false; + + // + // triangle plane test + // + // do the opposite because the ray has been negated + if( ( ( pTri->m_Normal.x * ( boxPt.x - points[0].x ) ) + + ( pTri->m_Normal.y * ( boxPt.y - points[0].y ) ) + + ( pTri->m_Normal.z * ( boxPt.z - points[0].z ) ) ) > 0.0f ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::CullTriList( CDispCollTreeTempData *pTemp, Vector &rayStart, Vector &rayEnd, Vector &extents, bool bIntersect ) +{ + // + // intersect AABB with all triangles in list + // + if( bIntersect ) + { + for( int i = 0; i < pTemp->m_TriListCount; i++ ) + { + if( IntersectAABBTriTest( rayStart, extents, pTemp->m_ppTriList[i] ) ) + return true; + } + + return false; + } + // + // sweep AABB against all triangles in list + // + else + { + bool bResult = false; + + for( int i = 0; i < pTemp->m_TriListCount; i++ ) + { + if( SweptAABBTriTest( rayStart, rayEnd, extents, pTemp->m_ppTriList[i] ) ) + { + pTemp->m_ppTriList[i]->SetIntersect( true ); + bResult = true; + } + } + + return bResult; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::IntersectAABBAABBTest( CDispCollTreeTempData *pTemp, const Vector &pos, const Vector &extents ) +{ + float dist; + + for( int dir = 0; dir < 3; dir++ ) + { + // negative direction + dist = -( pos[dir] - ( pTemp->m_AABBDistances[(dir>>1)] - extents[dir] ) ); + if( dist > COLLISION_EPSILON ) + return false; + + // positive direction + dist = pos[dir] - ( pTemp->m_AABBDistances[(dir>>1)+1] + extents[dir] ); + if( dist > COLLISION_EPSILON ) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::SweptAABBAABBTest( CDispCollTreeTempData *pTemp, const Vector &rayStart, const Vector &rayEnd, const Vector &extents ) +{ + int dir; + float distStart, distEnd; + float fraction; + float deltas[3]; + float scalers[3]; + + // + // enter and exit fractions + // + float enterFraction = 0.0f; + float exitFraction = 0.0f; + + // + // de-normalize the paramter space so that we don't have to divide + // to find the fractional amount later (clamped for precision) + // + deltas[0] = rayEnd.x - rayStart.x; + deltas[1] = rayEnd.y - rayStart.y; + deltas[2] = rayEnd.z - rayStart.z; + if( ( deltas[0] < COLLISION_EPSILON ) && ( deltas[0] > -COLLISION_EPSILON ) ) { deltas[0] = 1.0f; } + if( ( deltas[1] < COLLISION_EPSILON ) && ( deltas[1] > -COLLISION_EPSILON ) ) { deltas[0] = 1.0f; } + if( ( deltas[2] < COLLISION_EPSILON ) && ( deltas[2] > -COLLISION_EPSILON ) ) { deltas[0] = 1.0f; } + scalers[0] = deltas[1] * deltas[2]; + scalers[1] = deltas[0] * deltas[2]; + scalers[2] = deltas[0] * deltas[1]; + + for( dir = 0; dir < 3; dir++ ) + { + // + // negative direction + // + distStart = -( rayStart[dir] - ( pTemp->m_AABBDistances[(dir>>1)] - extents[dir] ) ); + distEnd = -( rayEnd[dir] - ( pTemp->m_AABBDistances[(dir>>1)] - extents[dir] ) ); + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + fraction = distStart * scalers[dir]; + if( fraction > enterFraction ) + { + enterFraction = fraction; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + fraction = distStart * scalers[dir]; + if( fraction < exitFraction ) + { + exitFraction = fraction; + } + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + + // + // positive direction + // + distStart = rayStart[dir] - ( pTemp->m_AABBDistances[(dir>>1)+1] + extents[dir] ); + distEnd = rayEnd[dir] - ( pTemp->m_AABBDistances[(dir>>1)+1] + extents[dir] ); + + if( ( distStart > COLLISION_EPSILON ) && ( distEnd < -COLLISION_EPSILON ) ) + { + fraction = distStart * scalers[dir]; + if( fraction > enterFraction ) + { + enterFraction = fraction; + } + } + else if( ( distStart < -COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + fraction = distStart * scalers[dir]; + if( fraction < exitFraction ) + { + exitFraction = fraction; + } + } + else if( ( distStart > COLLISION_EPSILON ) && ( distEnd > COLLISION_EPSILON ) ) + { + return false; + } + } + + if( exitFraction < enterFraction ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::BuildTriList_r( CDispCollTreeTempData *pTemp, int nodeIndex, Vector &rayStart, Vector &rayEnd, Vector &extents, + bool bIntersect ) +{ + // + // get the current nodes bounds and create collision test planes + // (saved in the in class cache m_AABBNormals, m_AABBDistances) + // + Vector bounds[2]; + CDispCollNode *pNode = &m_pNodes[nodeIndex]; + pNode->GetBounds( bounds[0], bounds[1] ); + CreatePlanesFromBounds( pTemp, bounds[0], bounds[1] ); + + // + // interesect/sweep test + // + bool bResult; + if( bIntersect ) + { + bResult = IntersectAABBAABBTest( pTemp, rayStart, extents ); + } + else + { + bResult = SweptAABBAABBTest( pTemp, rayStart, rayEnd, extents ); + } + + if( bResult ) + { + // if leaf node -- add triangles to interstection test list + if( pNode->IsLeaf() ) + { + // Assert for now -- flush cache later!!!!! + Assert( pTemp->m_TriListCount >= 0 ); + Assert( pTemp->m_TriListCount < TRILIST_CACHE_SIZE ); + + pTemp->m_ppTriList[pTemp->m_TriListCount] = &pNode->m_Tris[0]; + pTemp->m_ppTriList[pTemp->m_TriListCount+1] = &pNode->m_Tris[1]; + pTemp->m_TriListCount += 2; + } + // continue recursion + else + { + BuildTriList_r( pTemp, GetChildNode( nodeIndex, 0 ), rayStart, rayEnd, extents, bIntersect ); + BuildTriList_r( pTemp, GetChildNode( nodeIndex, 1 ), rayStart, rayEnd, extents, bIntersect ); + BuildTriList_r( pTemp, GetChildNode( nodeIndex, 2 ), rayStart, rayEnd, extents, bIntersect ); + BuildTriList_r( pTemp, GetChildNode( nodeIndex, 3 ), rayStart, rayEnd, extents, bIntersect ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBSweep( CDispCollData *pData ) +{ + // reset the triangle lists counts + CDispCollTreeTempData tmp; + tmp.m_TriListCount = 0; + + // sweep the AABB against the tree + BuildTriList_r( &tmp, 0, pData->m_StartPos, pData->m_EndPos, pData->m_Extents, false ); + + // find collision triangles + if( CullTriList( &tmp, pData->m_StartPos, pData->m_EndPos, pData->m_Extents, false ) ) + { + // find closest intersection + return AABBTriIntersect( &tmp, pData ); + } + + return false; +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBIntersect( CDispCollData *pData ) +{ + // reset the triangle lists counts + CDispCollTreeTempData tmp; + tmp.m_TriListCount = 0; + + // sweep the AABB against the tree + BuildTriList_r( &tmp, 0, pData->m_StartPos, pData->m_StartPos, pData->m_Extents, true ); + + // find collision triangles + return CullTriList( &tmp, pData->m_StartPos, pData->m_StartPos, pData->m_Extents, true ); +} diff --git a/public/dispcoll.h b/public/dispcoll.h new file mode 100644 index 0000000..55b6d0b --- /dev/null +++ b/public/dispcoll.h @@ -0,0 +1,249 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DISPCOLL_H +#define DISPCOLL_H +#pragma once + +#include "mathlib/vector.h" + +class CCoreDispInfo; + +//============================================================================= +// +// Displacement Collision Triangle Data +// +class CDispCollTri +{ +public: + + void Init( void ); + inline void SetPoint( int index, Vector const& vert ); + inline void SetPointNormal( int index, Vector const& normal ); + void CalcPlane( void ); + + inline void SetIntersect( bool bIntersect ); + inline bool IsIntersect( void ); + + Vector m_Points[3]; // polygon points + Vector m_PointNormals[3]; // polygon point normals + Vector m_Normal; // plane normal + float m_Distance; // plane distance + short m_ProjAxes[2]; // projection axes (2 minor axes) + bool m_bIntersect; // intersected triangle??? +}; + +//============================================================================= +// +// Displacement Collision Node Data +// +class CDispCollNode +{ +public: + + CDispCollNode(); + inline bool IsLeaf( void ); + inline void SetBounds( Vector const &bMin, Vector const &bMax ); + inline void GetBounds( Vector &bMin, Vector &bMax ); + + Vector m_Bounds[2]; // node minimum and maximum + + bool m_bIsLeaf; // is the node a leaf? ( may have to make this an int for alignment!) + CDispCollTri m_Tris[2]; // two triangles contained in leaf node +}; + + +//============================================================================= +// +// Displacement Collision Data +// +class CDispCollData +{ +public: + + Vector m_StartPos; + Vector m_EndPos; + Vector m_Extents; + float m_Fraction; + int m_Contents; + Vector m_Normal; + float m_Distance; + bool m_bOcclude; +}; + + + +// HACKHACK: JAY: Moved this out of CDispCollTree to be thread safe in vrad +enum { TRILIST_CACHE_SIZE = 128 }; + +class CDispCollTreeTempData +{ +public: + // + // temps + // + int m_TriListCount; + CDispCollTri *m_ppTriList[TRILIST_CACHE_SIZE]; + + // collision tree node cache + float m_AABBDistances[6]; +}; + + +//============================================================================= +// +// Displacement Collision Tree +// +class CDispCollTree +{ +public: + + static const float COLLISION_EPSILON; + static const float ONE_MINUS_COLLISION_EPSILON; + + //========================================================================= + // + // Creation/Destruction + // + CDispCollTree(); + ~CDispCollTree(); + + virtual bool Create( CCoreDispInfo *pDisp ); + + //========================================================================= + // + // Collision Functions + // + bool RayTest( CDispCollData *pData ); + bool RayTestAllTris( CDispCollData *pData, int power ); + + bool AABBIntersect( CDispCollData *pData ); + bool AABBSweep( CDispCollData *pData ); + + //========================================================================= + // + // Attrib Functions + // + inline void SetPower( int power ); + inline int GetPower( void ); + + inline void SetCheckCount( int count ); + inline int GetCheckCount( void ); + + inline void GetBounds( Vector& boundMin, Vector& boundMax ); + +protected: + + int m_Power; + + int m_NodeCount; + CDispCollNode *m_pNodes; + + int m_CheckCount; + + // collision tree node cache + Vector m_AABBNormals[6]; + //========================================================================= + // + // Creation/Destruction + // + void InitAABBData( void ); + void InitLeaves( CCoreDispInfo *pDisp ); + void CreateNodes( CCoreDispInfo *pDisp ); + void CreateNodes_r( CCoreDispInfo *pDisp, int nodeIndex, int termLevel ); + void CalcBounds( CDispCollNode *pNode, int nodeIndex ); + + //========================================================================= + // + // Collision Functions + // + void CreatePlanesFromBounds( CDispCollTreeTempData *pTemp, Vector const &bbMin, Vector const &bbMax ); + +// void RayNodeTest_r( int nodeIndex, Vector &rayStart, Vector &rayEnd ); + void RayNodeTest_r( CDispCollTreeTempData *pTemp, int nodeIndex, Vector rayStart, Vector rayEnd ); + bool RayAABBTest( CDispCollTreeTempData *pTemp, Vector &rayStart, Vector &rayEnd ); + bool RayTriListTest( CDispCollTreeTempData *pTemp, CDispCollData *pData ); + bool RayTriTest( Vector const &rayStart, Vector const &rayDir, float const rayLength, CDispCollTri const *pTri, float *fraction ); + + void BuildTriList_r( CDispCollTreeTempData *pTemp, int nodeIndex, Vector &rayStart, Vector &rayEnd, Vector &extents, bool bIntersect ); + bool IntersectAABBAABBTest( CDispCollTreeTempData *pTemp, const Vector &pos, const Vector &extents ); + bool SweptAABBAABBTest( CDispCollTreeTempData *pTemp, const Vector &rayStart, const Vector &rayEnd, const Vector &extents ); + + bool CullTriList( CDispCollTreeTempData *pTemp, Vector &rayStart, Vector &rayEnd, Vector &extents, bool bIntersect ); + bool SweptAABBTriTest( Vector &rayStart, Vector &rayEnd, Vector &extents, CDispCollTri const *pTri ); + bool AABBTriIntersect( CDispCollTreeTempData *pTemp, CDispCollData *pData ); + bool IntersectAABBTriTest( Vector &rayStart, Vector &extents, CDispCollTri const *pTri ); + bool SweptAABBTriIntersect( Vector &rayStart, Vector &rayEnd, Vector &extents, + CDispCollTri const *pTri, Vector &plNormal, float *plDist, + float *fraction ); + + //========================================================================= + // + // Memory Functions + // + bool AllocNodes( int nodeCount ); + void FreeNodes( void ); + + //========================================================================= + // + // Utility Functions + // + inline int CalcNodeCount( int power ); + inline int GetParentNode( int nodeIndex ); + inline int GetChildNode( int nodeIndex, int direction ); + inline int GetNodeLevel( int nodeIndex ); + int GetNodeIndexFromComponents( int x, int y ); +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CDispCollTree::SetPower( int power ) +{ + m_Power = power; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CDispCollTree::GetPower( void ) +{ + return m_Power; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CDispCollTree::SetCheckCount( int count ) +{ + m_CheckCount = count; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int CDispCollTree::GetCheckCount( void ) +{ + return m_CheckCount; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void CDispCollTree::GetBounds( Vector& boundMin, Vector& boundMax ) +{ + boundMin[0] = m_pNodes[0].m_Bounds[0].x; + boundMin[1] = m_pNodes[0].m_Bounds[0].y; + boundMin[2] = m_pNodes[0].m_Bounds[0].z; + + boundMax[0] = m_pNodes[0].m_Bounds[1].x; + boundMax[1] = m_pNodes[0].m_Bounds[1].y; + boundMax[2] = m_pNodes[0].m_Bounds[1].z; +} + + +#endif // DISPCOLL_H \ No newline at end of file diff --git a/public/dispcoll_common.cpp b/public/dispcoll_common.cpp new file mode 100644 index 0000000..9131d4c --- /dev/null +++ b/public/dispcoll_common.cpp @@ -0,0 +1,1539 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cmodel.h" +#include "dispcoll_common.h" +#include "collisionutils.h" +#include "tier1/strtools.h" +#include "tier0/vprof.h" +#include "tier1/fmtstr.h" +#include "tier1/utlhash.h" +#include "tier1/generichash.h" +#include "tier0/fasttimer.h" +#include "vphysics/virtualmesh.h" +#include "tier1/datamanager.h" +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//============================================================================= +// Cache + +#ifdef ENGINE_DLL +CDataManager g_DispCollTriCache( 2048*1024 ); +#endif + + +struct DispCollPlaneIndex_t +{ + Vector vecPlane; + int index; +}; + +class CPlaneIndexHashFuncs +{ +public: + CPlaneIndexHashFuncs( int ) {} + + // Compare + bool operator()( const DispCollPlaneIndex_t &lhs, const DispCollPlaneIndex_t &rhs ) const + { + return ( lhs.vecPlane == rhs.vecPlane || lhs.vecPlane == -rhs.vecPlane ); + } + + // Hash + unsigned int operator()( const DispCollPlaneIndex_t &item ) const + { + return HashItem( item.vecPlane ) ^ HashItem( -item.vecPlane ); + } +}; + +CUtlHash g_DispCollPlaneIndexHash( 512 ); + + +//============================================================================= +// Displacement Collision Triangle + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDispCollTri::CDispCollTri() +{ + Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTri::Init( void ) +{ + m_vecNormal.Init(); + m_flDist = 0.0f; + m_TriData[0].m_IndexDummy = m_TriData[1].m_IndexDummy = m_TriData[2].m_IndexDummy = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTri::CalcPlane( CDispVector &m_aVerts ) +{ + Vector vecEdges[2]; + vecEdges[0] = m_aVerts[GetVert( 1 )] - m_aVerts[GetVert( 0 )]; + vecEdges[1] = m_aVerts[GetVert( 2 )] - m_aVerts[GetVert( 0 )]; + + m_vecNormal = vecEdges[1].Cross( vecEdges[0] ); + VectorNormalize( m_vecNormal ); + m_flDist = m_vecNormal.Dot( m_aVerts[GetVert( 0 )] ); + + // Calculate the signbits for the plane - fast test. + m_ucSignBits = 0; + m_ucPlaneType = PLANE_ANYZ; + for ( int iAxis = 0; iAxis < 3 ; ++iAxis ) + { + if ( m_vecNormal[iAxis] < 0.0f ) + { + m_ucSignBits |= 1 << iAxis; + } + + if ( m_vecNormal[iAxis] == 1.0f ) + { + m_ucPlaneType = iAxis; + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void FindMin( float v1, float v2, float v3, int &iMin ) +{ + float flMin = v1; + iMin = 0; + if( v2 < flMin ) { flMin = v2; iMin = 1; } + if( v3 < flMin ) { flMin = v3; iMin = 2; } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline void FindMax( float v1, float v2, float v3, int &iMax ) +{ + float flMax = v1; + iMax = 0; + if( v2 > flMax ) { flMax = v2; iMax = 1; } + if( v3 > flMax ) { flMax = v3; iMax = 2; } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTri::FindMinMax( CDispVector &m_aVerts ) +{ + int iMin, iMax; + FindMin( m_aVerts[GetVert(0)].x, m_aVerts[GetVert(1)].x, m_aVerts[GetVert(2)].x, iMin ); + FindMax( m_aVerts[GetVert(0)].x, m_aVerts[GetVert(1)].x, m_aVerts[GetVert(2)].x, iMax ); + SetMin( 0, iMin ); + SetMax( 0, iMax ); + + FindMin( m_aVerts[GetVert(0)].y, m_aVerts[GetVert(1)].y, m_aVerts[GetVert(2)].y, iMin ); + FindMax( m_aVerts[GetVert(0)].y, m_aVerts[GetVert(1)].y, m_aVerts[GetVert(2)].y, iMax ); + SetMin( 1, iMin ); + SetMax( 1, iMax ); + + FindMin( m_aVerts[GetVert(0)].z, m_aVerts[GetVert(1)].z, m_aVerts[GetVert(2)].z, iMin ); + FindMax( m_aVerts[GetVert(0)].z, m_aVerts[GetVert(1)].z, m_aVerts[GetVert(2)].z, iMax ); + SetMin( 2, iMin ); + SetMax( 2, iMax ); +} + + +// SIMD Routines for intersecting with the quad tree +FORCEINLINE int IntersectRayWithFourBoxes( const FourVectors &rayStart, const FourVectors &invDelta, const FourVectors &rayExtents, const FourVectors &boxMins, const FourVectors &boxMaxs ) +{ + // SIMD Test ray against all four boxes at once + // each node stores the bboxes of its four children + FourVectors hitMins = boxMins; + hitMins -= rayStart; + FourVectors hitMaxs = boxMaxs; + hitMaxs -= rayStart; + + // adjust for swept box by enlarging the child bounds to shrink the sweep down to a point + hitMins -= rayExtents; + hitMaxs += rayExtents; + + // compute the parametric distance along the ray of intersection in each dimension + hitMins *= invDelta; + hitMaxs *= invDelta; + + // Find the exit parametric intersection distance in each dimesion, for each box + FourVectors exitT = maximum(hitMins,hitMaxs); + // Find the entry parametric intersection distance in each dimesion, for each box + FourVectors entryT = minimum(hitMins,hitMaxs); + + // now find the max overall entry distance across all dimensions for each box + fltx4 minTemp = MaxSIMD(entryT.x, entryT.y); + fltx4 boxEntryT = MaxSIMD(minTemp, entryT.z); + + // now find the min overall exit distance across all dimensions for each box + fltx4 maxTemp = MinSIMD(exitT.x, exitT.y); + fltx4 boxExitT = MinSIMD(maxTemp, exitT.z); + + boxEntryT = MaxSIMD(boxEntryT,Four_Zeros); + boxExitT = MinSIMD(boxExitT,Four_Ones); + + // if entry<=exit for the box, we've got a hit + fltx4 active = CmpLeSIMD(boxEntryT,boxExitT); // mask of which boxes are active + + // hit at least one box? + return TestSignSIMD(active); +} + +// This does 4 simultaneous box intersections +// NOTE: This can be used as a 1 vs 4 test by replicating a single box into the one side +FORCEINLINE int IntersectFourBoxPairs( const FourVectors &mins0, const FourVectors &maxs0, const FourVectors &mins1, const FourVectors &maxs1 ) +{ + // find the max mins and min maxs in each dimension + FourVectors intersectMins = maximum(mins0,mins1); + FourVectors intersectMaxs = minimum(maxs0,maxs1); + + // if intersectMins <= intersectMaxs then the boxes overlap in this dimension + fltx4 overlapX = CmpLeSIMD(intersectMins.x,intersectMaxs.x); + fltx4 overlapY = CmpLeSIMD(intersectMins.y,intersectMaxs.y); + fltx4 overlapZ = CmpLeSIMD(intersectMins.z,intersectMaxs.z); + + // if the boxes overlap in all three dimensions, they intersect + fltx4 tmp = AndSIMD( overlapX, overlapY ); + fltx4 active = AndSIMD( tmp, overlapZ ); + + // hit at least one box? + return TestSignSIMD(active); +} + +// This does 4 simultaneous box vs. sphere intersections +// NOTE: This can be used as a 1 vs 4 test by replicating a single sphere/box into one side +FORCEINLINE int IntersectFourBoxSpherePairs( const FourVectors ¢er, const fltx4 &radiusSq, const FourVectors &mins, const FourVectors &maxs ) +{ + // for each dimension of each box, compute the clamped distance from the mins side to the center (must be >= 0) + FourVectors minDist = mins; + minDist -= center; + FourVectors dist; + dist.x = MaxSIMD(Four_Zeros, minDist.x); + dist.y = MaxSIMD(Four_Zeros, minDist.y); + dist.z = MaxSIMD(Four_Zeros, minDist.z); + + // now compute the distance from the maxs side to the center + FourVectors maxDist = center; + maxDist -= maxs; + // NOTE: Don't need to clamp here because we clamp against the minDist which must be >= 0, so the two clamps + // get folded together + FourVectors totalDist; + totalDist.x = MaxSIMD(dist.x, maxDist.x); + totalDist.y = MaxSIMD(dist.y, maxDist.y); + totalDist.z = MaxSIMD(dist.z, maxDist.z); + // get the total squred distance between each box & sphere center by summing the squares of each + // component/dimension + fltx4 distSq = totalDist * totalDist; + + // if squared distance between each sphere center & box is less than the radiusSquared for that sphere + // we have an intersection + fltx4 active = CmpLeSIMD(distSq,radiusSq); + + // at least one intersection? + return TestSignSIMD(active); +} + + +int FORCEINLINE CDispCollTree::BuildRayLeafList( int iNode, rayleaflist_t &list ) +{ + list.nodeList[0] = iNode; + int listIndex = 0; + list.maxIndex = 0; + while ( listIndex <= list.maxIndex ) + { + iNode = list.nodeList[listIndex]; + // the rest are all leaves + if ( IsLeafNode(iNode) ) + return listIndex; + listIndex++; + const CDispCollNode &node = m_nodes[iNode]; + int mask = IntersectRayWithFourBoxes( list.rayStart, list.invDelta, list.rayExtents, node.m_mins, node.m_maxs ); + if ( mask ) + { + int child = Nodes_GetChild( iNode, 0 ); + if ( mask & 1 ) + { + ++list.maxIndex; + list.nodeList[list.maxIndex] = child; + } + if ( mask & 2 ) + { + ++list.maxIndex; + list.nodeList[list.maxIndex] = child+1; + } + if ( mask & 4 ) + { + ++list.maxIndex; + list.nodeList[list.maxIndex] = child+2; + } + if ( mask & 8 ) + { + ++list.maxIndex; + list.nodeList[list.maxIndex] = child+3; + } + Assert(list.maxIndex < MAX_AABB_LIST); + } + } + + return listIndex; +} + + +//----------------------------------------------------------------------------- +// Purpose: Create the AABB tree. +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBTree_Create( CCoreDispInfo *pDisp ) +{ + // Copy the flags. + m_nFlags = pDisp->GetSurface()->GetFlags(); + + // Copy necessary displacement data. + AABBTree_CopyDispData( pDisp ); + + // Setup/create the leaf nodes first so the recusion can use this data to stop. + AABBTree_CreateLeafs(); + + // Create the bounding box of the displacement surface + the base face. + AABBTree_CalcBounds(); + + // Successful. + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::AABBTree_CopyDispData( CCoreDispInfo *pDisp ) +{ + // Displacement size. + m_nPower = pDisp->GetPower(); + + // Displacement base surface data. + CCoreDispSurface *pSurf = pDisp->GetSurface(); + m_nContents = pSurf->GetContents(); + pSurf->GetNormal( m_vecStabDir ); + for ( int iPoint = 0; iPoint < 4; iPoint++ ) + { + pSurf->GetPoint( iPoint, m_vecSurfPoints[iPoint] ); + } + + // Allocate collision tree data. + { + MEM_ALLOC_CREDIT(); + m_aVerts.SetSize( GetSize() ); + } + + { + MEM_ALLOC_CREDIT(); + m_aTris.SetSize( GetTriSize() ); + } + + { + MEM_ALLOC_CREDIT(); + int numLeaves = (GetWidth()-1) * (GetHeight()-1); + m_leaves.SetCount(numLeaves); + int numNodes = Nodes_CalcCount( m_nPower ); + numNodes -= numLeaves; + m_nodes.SetCount(numNodes); + } + + + // Setup size. + m_nSize = sizeof( this ); + m_nSize += sizeof( Vector ) * GetSize(); + m_nSize += sizeof( CDispCollTri ) * GetTriSize(); +#if OLD_DISP_AABB + m_nSize += sizeof( CDispCollAABBNode ) * Nodes_CalcCount( m_nPower ); +#endif + m_nSize += sizeof(m_nodes[0]) * m_nodes.Count(); + m_nSize += sizeof(m_leaves[0]) * m_leaves.Count(); + m_nSize += sizeof( CDispCollTri* ) * DISPCOLL_TREETRI_SIZE; + + // Copy vertex data. + for ( int iVert = 0; iVert < m_aVerts.Count(); iVert++ ) + { + pDisp->GetVert( iVert, m_aVerts[iVert] ); + } + + // Copy and setup triangle data. + unsigned short iVerts[3]; + for ( int iTri = 0; iTri < m_aTris.Count(); ++iTri ) + { + pDisp->GetTriIndices( iTri, iVerts[0], iVerts[1], iVerts[2] ); + m_aTris[iTri].SetVert( 0, iVerts[0] ); + m_aTris[iTri].SetVert( 1, iVerts[1] ); + m_aTris[iTri].SetVert( 2, iVerts[2] ); + m_aTris[iTri].m_uiFlags = pDisp->GetTriTagValue( iTri ); + + // Calculate the surface props and set flags. + float flTotalAlpha = 0.0f; + for ( int iVert = 0; iVert < 3; ++iVert ) + { + flTotalAlpha += pDisp->GetAlpha( m_aTris[iTri].GetVert( iVert ) ); + } + + if ( flTotalAlpha > DISP_ALPHA_PROP_DELTA ) + { + m_aTris[iTri].m_uiFlags |= DISPSURF_FLAG_SURFPROP2; + } + else + { + m_aTris[iTri].m_uiFlags |= DISPSURF_FLAG_SURFPROP1; + } + + // Add the displacement surface flag. + m_aTris[iTri].m_uiFlags |= DISPSURF_FLAG_SURFACE; + + // Calculate the plane normal and the min max. + m_aTris[iTri].CalcPlane( m_aVerts ); + m_aTris[iTri].FindMinMax( m_aVerts ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::AABBTree_CreateLeafs( void ) +{ + int numLeaves = (GetWidth()-1) * (GetHeight()-1); + m_leaves.SetCount(numLeaves); + int numNodes = Nodes_CalcCount( m_nPower ); + numNodes -= numLeaves; + m_nodes.SetCount(numNodes); + + // Get the width and height of the displacement. + int nWidth = GetWidth() - 1; + int nHeight = GetHeight() - 1; + + for ( int iHgt = 0; iHgt < nHeight; ++iHgt ) + { + for ( int iWid = 0; iWid < nWidth; ++iWid ) + { + int iLeaf = Nodes_GetIndexFromComponents( iWid, iHgt ); + int iIndex = iHgt * nWidth + iWid; + int iTri = iIndex * 2; + + m_leaves[iLeaf].m_tris[0] = iTri; + m_leaves[iLeaf].m_tris[1] = iTri + 1; + } + } +} + +void CDispCollTree::AABBTree_GenerateBoxes_r( int nodeIndex, Vector *pMins, Vector *pMaxs ) +{ + // leaf + ClearBounds( *pMins, *pMaxs ); + if ( nodeIndex >= m_nodes.Count() ) + { + int iLeaf = nodeIndex - m_nodes.Count(); + + for ( int iTri = 0; iTri < 2; ++iTri ) + { + int triIndex = m_leaves[iLeaf].m_tris[iTri]; + const CDispCollTri &tri = m_aTris[triIndex]; + AddPointToBounds( m_aVerts[tri.GetVert( 0 )], *pMins, *pMaxs ); + AddPointToBounds( m_aVerts[tri.GetVert( 1 )], *pMins, *pMaxs ); + AddPointToBounds( m_aVerts[tri.GetVert( 2 )], *pMins, *pMaxs ); + } + } + else // node + { + Vector childMins[4], childMaxs[4]; + for ( int i = 0; i < 4; i++ ) + { + int child = Nodes_GetChild( nodeIndex, i ); + AABBTree_GenerateBoxes_r( child, &childMins[i], &childMaxs[i] ); + AddPointToBounds( childMins[i], *pMins, *pMaxs ); + AddPointToBounds( childMaxs[i], *pMins, *pMaxs ); + } + m_nodes[nodeIndex].m_mins.LoadAndSwizzle( childMins[0], childMins[1], childMins[2], childMins[3] ); + m_nodes[nodeIndex].m_maxs.LoadAndSwizzle( childMaxs[0], childMaxs[1], childMaxs[2], childMaxs[3] ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::AABBTree_CalcBounds( void ) +{ + // Check data. + if ( ( m_aVerts.Count() == 0 ) || ( m_nodes.Count() == 0 ) ) + return; + + AABBTree_GenerateBoxes_r( 0, &m_mins, &m_maxs ); + +#if INCLUDE_SURFACE_IN_BOUNDS + // Add surface points to bounds. + for ( int iPoint = 0; iPoint < 4; ++iPoint ) + { + VectorMin( m_vecSurfPoints[iPoint], m_mins, m_mins ); + VectorMax( m_vecSurfPoints[iPoint], m_maxs, m_maxs ); + } +#endif + + // Bloat a little. + for ( int iAxis = 0; iAxis < 3; ++iAxis ) + { + m_mins[iAxis] -= 1.0f; + m_maxs[iAxis] += 1.0f; + } +} + +static CThreadFastMutex s_CacheMutex; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollTree::LockCache() +{ +#ifdef ENGINE_DLL + if ( !g_DispCollTriCache.LockResource( m_hCache ) ) + { + AUTO_LOCK_FM( s_CacheMutex ); + + // Cache may have just been created, so check once more + if ( !g_DispCollTriCache.LockResource( m_hCache ) ) + { + Cache(); + m_hCache = g_DispCollTriCache.CreateResource( this ); + g_DispCollTriCache.LockResource( m_hCache ); + //Msg( "Adding 0x%x to cache (actual %d) [%d, %d --> %.2f] %d total, %d unique\n", this, GetCacheMemorySize(), GetTriSize(), m_aEdgePlanes.Count(), (float)m_aEdgePlanes.Count()/(float)GetTriSize(), totals, uniques ); + } + } +#else + Cache(); +#endif +} + +inline void CDispCollTree::UnlockCache() +{ +#ifdef ENGINE_DLL + g_DispCollTriCache.UnlockResource( m_hCache ); +#endif +} +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::Cache( void ) +{ + if ( m_aTrisCache.Count() == GetTriSize() ) + { + return; + } + + VPROF( "CDispCollTree::Cache" ); + + // Alloc. +// int nSize = sizeof( CDispCollTriCache ) * GetTriSize(); + int nTriCount = GetTriSize(); + { + MEM_ALLOC_CREDIT(); + m_aTrisCache.SetSize( nTriCount ); + } + + for ( int iTri = 0; iTri < nTriCount; ++iTri ) + { + Cache_Create( &m_aTris[iTri], iTri ); + } + + g_DispCollPlaneIndexHash.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBTree_Ray( const Ray_t &ray, RayDispOutput_t &output ) +{ + if ( IsBoxIntersectingRay( m_mins, m_maxs, ray.m_Start, ray.m_Delta, DISPCOLL_DIST_EPSILON ) ) + { + return AABBTree_Ray( ray, ray.InvDelta(), output ); + } + return false; +} + +bool CDispCollTree::AABBTree_Ray( const Ray_t &ray, const Vector &vecInvDelta, RayDispOutput_t &output ) +{ + VPROF( "DispRayTest" ); + + // Check for ray test. + if ( CheckFlags( CCoreDispInfo::SURF_NORAY_COLL ) ) + return false; + + // Check for opacity. + if ( !( m_nContents & MASK_OPAQUE ) ) + return false; + + // Pre-calc the inverse delta for perf. + CDispCollTri *pImpactTri = NULL; + + AABBTree_TreeTrisRayBarycentricTest( ray, vecInvDelta, DISPCOLL_ROOTNODE_INDEX, output, &pImpactTri ); + + if ( pImpactTri ) + { + // Collision. + output.ndxVerts[0] = pImpactTri->GetVert( 0 ); + output.ndxVerts[1] = pImpactTri->GetVert( 2 ); + output.ndxVerts[2] = pImpactTri->GetVert( 1 ); + + Assert( (output.u <= 1.0f ) && ( output.v <= 1.0f ) ); + Assert( (output.u >= 0.0f ) && ( output.v >= 0.0f ) ); + + return true; + } + + // No collision. + return false; +} + +void CDispCollTree::AABBTree_TreeTrisRayBarycentricTest( const Ray_t &ray, const Vector &vecInvDelta, int iNode, RayDispOutput_t &output, CDispCollTri **pImpactTri ) +{ + rayleaflist_t list; + // NOTE: This part is loop invariant - should be hoisted up as far as possible + list.invDelta.DuplicateVector(vecInvDelta); + list.rayStart.DuplicateVector(ray.m_Start); + Vector ext = ray.m_Extents + Vector(DISPCOLL_DIST_EPSILON,DISPCOLL_DIST_EPSILON,DISPCOLL_DIST_EPSILON); + list.rayExtents.DuplicateVector(ext); + int listIndex = BuildRayLeafList( iNode, list ); + + float flU, flV, flT; + for ( ; listIndex <= list.maxIndex; listIndex++ ) + { + int leafIndex = list.nodeList[listIndex] - m_nodes.Count(); + CDispCollTri *pTri0 = &m_aTris[m_leaves[leafIndex].m_tris[0]]; + CDispCollTri *pTri1 = &m_aTris[m_leaves[leafIndex].m_tris[1]]; + + if ( ComputeIntersectionBarycentricCoordinates( ray, m_aVerts[pTri0->GetVert( 0 )], m_aVerts[pTri0->GetVert( 2 )], m_aVerts[pTri0->GetVert( 1 )], flU, flV, &flT ) ) + { + // Make sure it's inside the range + if ( ( flU >= 0.0f ) && ( flV >= 0.0f ) && ( ( flU + flV ) <= 1.0f ) ) + { + if( ( flT > 0.0f ) && ( flT < output.dist ) ) + { + (*pImpactTri) = pTri0; + output.u = flU; + output.v = flV; + output.dist = flT; + } + } + } + if ( ComputeIntersectionBarycentricCoordinates( ray, m_aVerts[pTri1->GetVert( 0 )], m_aVerts[pTri1->GetVert( 2 )], m_aVerts[pTri1->GetVert( 1 )], flU, flV, &flT ) ) + { + // Make sure it's inside the range + if ( ( flU >= 0.0f ) && ( flV >= 0.0f ) && ( ( flU + flV ) <= 1.0f ) ) + { + if( ( flT > 0.0f ) && ( flT < output.dist ) ) + { + (*pImpactTri) = pTri1; + output.u = flU; + output.v = flV; + output.dist = flT; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBTree_Ray( const Ray_t &ray, const Vector &vecInvDelta, CBaseTrace *pTrace, bool bSide ) +{ + VPROF("AABBTree_Ray"); + +// VPROF_BUDGET( "DispRayTraces", VPROF_BUDGETGROUP_DISP_RAYTRACES ); + + // Check for ray test. + if ( CheckFlags( CCoreDispInfo::SURF_NORAY_COLL ) ) + return false; + + // Check for opacity. + if ( !( m_nContents & MASK_OPAQUE ) ) + return false; + + // Pre-calc the inverse delta for perf. + CDispCollTri *pImpactTri = NULL; + + AABBTree_TreeTrisRayTest( ray, vecInvDelta, DISPCOLL_ROOTNODE_INDEX, pTrace, bSide, &pImpactTri ); + + if ( pImpactTri ) + { + // Collision. + VectorCopy( pImpactTri->m_vecNormal, pTrace->plane.normal ); + pTrace->plane.dist = pImpactTri->m_flDist; + pTrace->dispFlags = pImpactTri->m_uiFlags; + return true; + } + + // No collision. + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::AABBTree_TreeTrisRayTest( const Ray_t &ray, const Vector &vecInvDelta, int iNode, CBaseTrace *pTrace, bool bSide, CDispCollTri **pImpactTri ) +{ + rayleaflist_t list; + // NOTE: This part is loop invariant - should be hoisted up as far as possible + list.invDelta.DuplicateVector(vecInvDelta); + list.rayStart.DuplicateVector(ray.m_Start); + Vector ext = ray.m_Extents + Vector(DISPCOLL_DIST_EPSILON,DISPCOLL_DIST_EPSILON,DISPCOLL_DIST_EPSILON); + list.rayExtents.DuplicateVector(ext); + int listIndex = BuildRayLeafList( iNode, list ); + + for ( ;listIndex <= list.maxIndex; listIndex++ ) + { + int leafIndex = list.nodeList[listIndex] - m_nodes.Count(); + CDispCollTri *pTri0 = &m_aTris[m_leaves[leafIndex].m_tris[0]]; + CDispCollTri *pTri1 = &m_aTris[m_leaves[leafIndex].m_tris[1]]; + float flFrac = IntersectRayWithTriangle( ray, m_aVerts[pTri0->GetVert( 0 )], m_aVerts[pTri0->GetVert( 2 )], m_aVerts[pTri0->GetVert( 1 )], bSide ); + if( ( flFrac >= 0.0f ) && ( flFrac < pTrace->fraction ) ) + { + pTrace->fraction = flFrac; + (*pImpactTri) = pTri0; + } + + flFrac = IntersectRayWithTriangle( ray, m_aVerts[pTri1->GetVert( 0 )], m_aVerts[pTri1->GetVert( 2 )], m_aVerts[pTri1->GetVert( 1 )], bSide ); + if( ( flFrac >= 0.0f ) && ( flFrac < pTrace->fraction ) ) + { + pTrace->fraction = flFrac; + (*pImpactTri) = pTri1; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CDispCollTree::AABBTree_GetTrisInSphere( const Vector ¢er, float radius, unsigned short *pIndexOut, int indexMax ) +{ + return AABBTree_BuildTreeTrisInSphere_r( center, radius, DISPCOLL_ROOTNODE_INDEX, pIndexOut, indexMax ); +} + +int CDispCollTree::AABBTree_BuildTreeTrisInSphere_r( const Vector ¢er, float radius, int iNode, unsigned short *pIndexOut, unsigned short indexMax ) +{ + int nodeList[MAX_AABB_LIST]; + nodeList[0] = iNode; + int nTriCount = 0; + int listIndex = 0; + int maxIndex = 0; + // NOTE: This part is loop invariant - should be hoisted up as far as possible + FourVectors sphereCenters; + sphereCenters.DuplicateVector(center); + float radiusSq = radius * radius; + fltx4 sphereRadSq = ReplicateX4(radiusSq); + while ( listIndex <= maxIndex ) + { + iNode = nodeList[listIndex]; + listIndex++; + // the rest are all leaves + if ( IsLeafNode(iNode) ) + { + VPROF("Tris"); + for ( --listIndex; listIndex <= maxIndex; listIndex++ ) + { + if ( (nTriCount+2) <= indexMax ) + { + int leafIndex = nodeList[listIndex] - m_nodes.Count(); + pIndexOut[nTriCount] = m_leaves[leafIndex].m_tris[0]; + pIndexOut[nTriCount+1] = m_leaves[leafIndex].m_tris[1]; + nTriCount += 2; + } + } + break; + } + else + { + const CDispCollNode &node = m_nodes[iNode]; + int mask = IntersectFourBoxSpherePairs( sphereCenters, sphereRadSq, node.m_mins, node.m_maxs ); + if ( mask ) + { + int child = Nodes_GetChild( iNode, 0 ); + if ( mask & 1 ) + { + ++maxIndex; + nodeList[maxIndex] = child; + } + if ( mask & 2 ) + { + ++maxIndex; + nodeList[maxIndex] = child+1; + } + if ( mask & 4 ) + { + ++maxIndex; + nodeList[maxIndex] = child+2; + } + if ( mask & 8 ) + { + ++maxIndex; + nodeList[maxIndex] = child+3; + } + Assert(maxIndex < MAX_AABB_LIST); + } + } + } + return nTriCount; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBTree_IntersectAABB( const Vector &absMins, const Vector &absMaxs ) +{ + // Check for hull test. + if ( CheckFlags( CCoreDispInfo::SURF_NOHULL_COLL ) ) + return false; + + cplane_t plane; + Vector center = 0.5f *(absMins + absMaxs); + Vector extents = absMaxs - center; + + int nodeList[MAX_AABB_LIST]; + nodeList[0] = 0; + int listIndex = 0; + int maxIndex = 0; + + // NOTE: This part is loop invariant - should be hoisted up as far as possible + FourVectors mins0; + mins0.DuplicateVector(absMins); + FourVectors maxs0; + maxs0.DuplicateVector(absMaxs); + FourVectors rayExtents; + while ( listIndex <= maxIndex ) + { + int iNode = nodeList[listIndex]; + listIndex++; + // the rest are all leaves + if ( IsLeafNode(iNode) ) + { + VPROF("Tris"); + for ( --listIndex; listIndex <= maxIndex; listIndex++ ) + { + int leafIndex = nodeList[listIndex] - m_nodes.Count(); + CDispCollTri *pTri0 = &m_aTris[m_leaves[leafIndex].m_tris[0]]; + CDispCollTri *pTri1 = &m_aTris[m_leaves[leafIndex].m_tris[1]]; + + VectorCopy( pTri0->m_vecNormal, plane.normal ); + plane.dist = pTri0->m_flDist; + plane.signbits = pTri0->m_ucSignBits; + plane.type = pTri0->m_ucPlaneType; + + if ( IsBoxIntersectingTriangle( center, extents, + m_aVerts[pTri0->GetVert( 0 )], + m_aVerts[pTri0->GetVert( 2 )], + m_aVerts[pTri0->GetVert( 1 )], + plane, 0.0f ) ) + return true; + VectorCopy( pTri1->m_vecNormal, plane.normal ); + plane.dist = pTri1->m_flDist; + plane.signbits = pTri1->m_ucSignBits; + plane.type = pTri1->m_ucPlaneType; + + if ( IsBoxIntersectingTriangle( center, extents, + m_aVerts[pTri1->GetVert( 0 )], + m_aVerts[pTri1->GetVert( 2 )], + m_aVerts[pTri1->GetVert( 1 )], + plane, 0.0f ) ) + return true; + } + break; + } + else + { + const CDispCollNode &node = m_nodes[iNode]; + int mask = IntersectFourBoxPairs( mins0, maxs0, node.m_mins, node.m_maxs ); + if ( mask ) + { + int child = Nodes_GetChild( iNode, 0 ); + if ( mask & 1 ) + { + ++maxIndex; + nodeList[maxIndex] = child; + } + if ( mask & 2 ) + { + ++maxIndex; + nodeList[maxIndex] = child+1; + } + if ( mask & 4 ) + { + ++maxIndex; + nodeList[maxIndex] = child+2; + } + if ( mask & 8 ) + { + ++maxIndex; + nodeList[maxIndex] = child+3; + } + Assert(maxIndex < MAX_AABB_LIST); + } + } + } + + // no collision + return false; +} + +static const Vector g_Vec3DispCollEpsilons(DISPCOLL_DIST_EPSILON,DISPCOLL_DIST_EPSILON,DISPCOLL_DIST_EPSILON); +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::AABBTree_SweepAABB( const Ray_t &ray, const Vector &vecInvDelta, CBaseTrace *pTrace ) +{ + VPROF( "DispHullTest" ); + // VPROF_BUDGET( "DispHullTraces", VPROF_BUDGETGROUP_DISP_HULLTRACES ); + // Check for hull test. + if ( CheckFlags( CCoreDispInfo::SURF_NOHULL_COLL ) ) + return false; + + // Test ray against the triangles in the list. + Vector rayDir; + VectorCopy( ray.m_Delta, rayDir ); + VectorNormalize( rayDir ); + // Save fraction. + float flFrac = pTrace->fraction; + + rayleaflist_t list; + // NOTE: This part is loop invariant - should be hoisted up as far as possible + list.invDelta.DuplicateVector(vecInvDelta); + list.rayStart.DuplicateVector(ray.m_Start); + Vector ext = ray.m_Extents + g_Vec3DispCollEpsilons; + list.rayExtents.DuplicateVector(ext); + int listIndex = BuildRayLeafList( 0, list ); + + if ( listIndex <= list.maxIndex ) + { + LockCache(); + for ( ; listIndex <= list.maxIndex; listIndex++ ) + { + int leafIndex = list.nodeList[listIndex] - m_nodes.Count(); + int iTri0 = m_leaves[leafIndex].m_tris[0]; + int iTri1 = m_leaves[leafIndex].m_tris[1]; + CDispCollTri *pTri0 = &m_aTris[iTri0]; + CDispCollTri *pTri1 = &m_aTris[iTri1]; + + SweepAABBTriIntersect( ray, rayDir, iTri0, pTri0, pTrace ); + SweepAABBTriIntersect( ray, rayDir, iTri1, pTri1, pTrace ); + } + UnlockCache(); + } + + // Collision. + if ( pTrace->fraction < flFrac ) + return true; + + // No collision. + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CDispCollTree::ResolveRayPlaneIntersect( float flStart, float flEnd, const Vector &vecNormal, float flDist, CDispCollHelper *pHelper ) +{ + if( ( flStart > 0.0f ) && ( flEnd > 0.0f ) ) + return false; + + if( ( flStart < 0.0f ) && ( flEnd < 0.0f ) ) + return true; + + float flDenom = flStart - flEnd; + bool bDenomIsZero = ( flDenom == 0.0f ); + if( ( flStart >= 0.0f ) && ( flEnd <= 0.0f ) ) + { + // Find t - the parametric distance along the trace line. + float t = ( !bDenomIsZero ) ? ( flStart - DISPCOLL_DIST_EPSILON ) / flDenom : 0.0f; + if( t > pHelper->m_flStartFrac ) + { + pHelper->m_flStartFrac = t; + VectorCopy( vecNormal, pHelper->m_vecImpactNormal ); + pHelper->m_flImpactDist = flDist; + } + } + else + { + // Find t - the parametric distance along the trace line. + float t = ( !bDenomIsZero ) ? ( flStart + DISPCOLL_DIST_EPSILON ) / flDenom : 0.0f; + if( t < pHelper->m_flEndFrac ) + { + pHelper->m_flEndFrac = t; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool CDispCollTree::FacePlane( const Ray_t &ray, const Vector &rayDir, CDispCollTri *pTri, CDispCollHelper *pHelper ) +{ + // Calculate the closest point on box to plane (get extents in that direction). + Vector vecExtent; + CalcClosestExtents( pTri->m_vecNormal, ray.m_Extents, vecExtent ); + + float flExpandDist = pTri->m_flDist - pTri->m_vecNormal.Dot( vecExtent ); + + float flStart = pTri->m_vecNormal.Dot( ray.m_Start ) - flExpandDist; + float flEnd = pTri->m_vecNormal.Dot( ( ray.m_Start + ray.m_Delta ) ) - flExpandDist; + + return ResolveRayPlaneIntersect( flStart, flEnd, pTri->m_vecNormal, pTri->m_flDist, pHelper ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool FORCEINLINE CDispCollTree::AxisPlanesXYZ( const Ray_t &ray, CDispCollTri *pTri, CDispCollHelper *pHelper ) +{ + static const TableVector g_ImpactNormalVecs[2][3] = + { + { + { -1, 0, 0 }, + { 0, -1, 0 }, + { 0, 0, -1 }, + }, + + { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + } + }; + + Vector vecImpactNormal; + float flDist, flExpDist, flStart, flEnd; + + int iAxis; + for ( iAxis = 2; iAxis >= 0; --iAxis ) + { + const float rayStart = ray.m_Start[iAxis]; + const float rayExtent = ray.m_Extents[iAxis]; + const float rayDelta = ray.m_Delta[iAxis]; + + // Min + flDist = m_aVerts[pTri->GetVert(pTri->GetMin(iAxis))][iAxis]; + flExpDist = flDist - rayExtent; + flStart = flExpDist - rayStart; + flEnd = flStart - rayDelta; + + if ( !ResolveRayPlaneIntersect( flStart, flEnd, g_ImpactNormalVecs[0][iAxis], flDist, pHelper ) ) + return false; + + // Max + flDist = m_aVerts[pTri->GetVert(pTri->GetMax(iAxis))][iAxis]; + flExpDist = flDist + rayExtent; + flStart = rayStart - flExpDist; + flEnd = flStart + rayDelta; + + if ( !ResolveRayPlaneIntersect( flStart, flEnd, g_ImpactNormalVecs[1][iAxis], flDist, pHelper ) ) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Testing! +//----------------------------------------------------------------------------- +void CDispCollTree::Cache_Create( CDispCollTri *pTri, int iTri ) +{ + MEM_ALLOC_CREDIT(); + Vector *pVerts[3]; + pVerts[0] = &m_aVerts[pTri->GetVert( 0 )]; + pVerts[1] = &m_aVerts[pTri->GetVert( 1 )]; + pVerts[2] = &m_aVerts[pTri->GetVert( 2 )]; + + CDispCollTriCache *pCache = &m_aTrisCache[iTri]; + + Vector vecEdge; + + // Edge 1 + VectorSubtract( *pVerts[1], *pVerts[0], vecEdge ); + Cache_EdgeCrossAxisX( vecEdge, *pVerts[0], *pVerts[2], pTri, pCache->m_iCrossX[0] ); + Cache_EdgeCrossAxisY( vecEdge, *pVerts[0], *pVerts[2], pTri, pCache->m_iCrossY[0] ); + Cache_EdgeCrossAxisZ( vecEdge, *pVerts[0], *pVerts[2], pTri, pCache->m_iCrossZ[0] ); + + // Edge 2 + VectorSubtract( *pVerts[2], *pVerts[1], vecEdge ); + Cache_EdgeCrossAxisX( vecEdge, *pVerts[1], *pVerts[0], pTri, pCache->m_iCrossX[1] ); + Cache_EdgeCrossAxisY( vecEdge, *pVerts[1], *pVerts[0], pTri, pCache->m_iCrossY[1] ); + Cache_EdgeCrossAxisZ( vecEdge, *pVerts[1], *pVerts[0], pTri, pCache->m_iCrossZ[1] ); + + // Edge 3 + VectorSubtract( *pVerts[0], *pVerts[2], vecEdge ); + Cache_EdgeCrossAxisX( vecEdge, *pVerts[2], *pVerts[1], pTri, pCache->m_iCrossX[2] ); + Cache_EdgeCrossAxisY( vecEdge, *pVerts[2], *pVerts[1], pTri, pCache->m_iCrossY[2] ); + Cache_EdgeCrossAxisZ( vecEdge, *pVerts[2], *pVerts[1], pTri, pCache->m_iCrossZ[2] ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CDispCollTree::AddPlane( const Vector &vecNormal ) +{ + UtlHashHandle_t handle; + DispCollPlaneIndex_t planeIndex; + bool bDidInsert; + + planeIndex.vecPlane = vecNormal; + planeIndex.index = m_aEdgePlanes.Count(); + + handle = g_DispCollPlaneIndexHash.Insert( planeIndex, &bDidInsert ); + + if ( !bDidInsert ) + { + DispCollPlaneIndex_t &existingEntry = g_DispCollPlaneIndexHash[handle]; + if ( existingEntry.vecPlane == vecNormal ) + { + return existingEntry.index; + } + else + { + return ( existingEntry.index | 0x8000 ); + } + } + + return m_aEdgePlanes.AddToTail( vecNormal ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// NOTE: The plane distance get stored in the normal x position since it isn't +// used. +//----------------------------------------------------------------------------- +bool CDispCollTree::Cache_EdgeCrossAxisX( const Vector &vecEdge, const Vector &vecOnEdge, + const Vector &vecOffEdge, CDispCollTri *pTri, + unsigned short &iPlane ) +{ + // Calculate the normal - edge x axisX = ( 0.0, edgeZ, -edgeY ) + Vector vecNormal( 0.0f, vecEdge.z, -vecEdge.y ); + VectorNormalize( vecNormal ); + + // Check for zero length normals. + if( ( vecNormal.y == 0.0f ) || ( vecNormal.z == 0.0f ) ) + { + iPlane = DISPCOLL_NORMAL_UNDEF; + return false; + } + +// if ( pTri->m_vecNormal.Dot( vecNormal ) ) +// { +// iPlane = DISPCOLL_NORMAL_UNDEF; +// return false; +// } + + // Finish the plane definition - get distance. + float flDist = ( vecNormal.y * vecOnEdge.y ) + ( vecNormal.z * vecOnEdge.z ); + + // Special case the point off edge in plane + float flOffDist = ( vecNormal.y * vecOffEdge.y ) + ( vecNormal.z * vecOffEdge.z ); + if ( !( FloatMakePositive( flOffDist - flDist ) < DISPCOLL_DIST_EPSILON ) && ( flOffDist > flDist ) ) + { + // Adjust plane facing - triangle should be behind the plane. + vecNormal.x = -flDist; + vecNormal.y = -vecNormal.y; + vecNormal.z = -vecNormal.z; + } + else + { + vecNormal.x = flDist; + } + + // Add edge plane to edge plane list. + iPlane = static_cast( AddPlane( vecNormal ) ); + + // Created the cached edge. + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// NOTE: The plane distance get stored in the normal y position since it isn't +// used. +//----------------------------------------------------------------------------- +bool CDispCollTree::Cache_EdgeCrossAxisY( const Vector &vecEdge, const Vector &vecOnEdge, + const Vector &vecOffEdge, CDispCollTri *pTri, + unsigned short &iPlane ) +{ + // Calculate the normal - edge x axisY = ( -edgeZ, 0.0, edgeX ) + Vector vecNormal( -vecEdge.z, 0.0f, vecEdge.x ); + VectorNormalize( vecNormal ); + + // Check for zero length normals + if( ( vecNormal.x == 0.0f ) || ( vecNormal.z == 0.0f ) ) + { + iPlane = DISPCOLL_NORMAL_UNDEF; + return false; + } + +// if ( pTri->m_vecNormal.Dot( vecNormal ) ) +// { +// iPlane = DISPCOLL_NORMAL_UNDEF; +// return false; +// } + + // Finish the plane definition - get distance. + float flDist = ( vecNormal.x * vecOnEdge.x ) + ( vecNormal.z * vecOnEdge.z ); + + // Special case the point off edge in plane + float flOffDist = ( vecNormal.x * vecOffEdge.x ) + ( vecNormal.z * vecOffEdge.z ); + if ( !( FloatMakePositive( flOffDist - flDist ) < DISPCOLL_DIST_EPSILON ) && ( flOffDist > flDist ) ) + { + // Adjust plane facing if necessay - triangle should be behind the plane. + vecNormal.x = -vecNormal.x; + vecNormal.y = -flDist; + vecNormal.z = -vecNormal.z; + } + else + { + vecNormal.y = flDist; + } + + // Add edge plane to edge plane list. + iPlane = static_cast( AddPlane( vecNormal ) ); + + // Created the cached edge. + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::Cache_EdgeCrossAxisZ( const Vector &vecEdge, const Vector &vecOnEdge, + const Vector &vecOffEdge, CDispCollTri *pTri, + unsigned short &iPlane ) +{ + // Calculate the normal - edge x axisY = ( edgeY, -edgeX, 0.0 ) + Vector vecNormal( vecEdge.y, -vecEdge.x, 0.0f ); + VectorNormalize( vecNormal ); + + // Check for zero length normals + if( ( vecNormal.x == 0.0f ) || ( vecNormal.y == 0.0f ) ) + { + iPlane = DISPCOLL_NORMAL_UNDEF; + return false; + } + +// if ( pTri->m_vecNormal.Dot( vecNormal ) ) +// { +// iPlane = DISPCOLL_NORMAL_UNDEF; +// return false; +// } + + // Finish the plane definition - get distance. + float flDist = ( vecNormal.x * vecOnEdge.x ) + ( vecNormal.y * vecOnEdge.y ); + + // Special case the point off edge in plane + float flOffDist = ( vecNormal.x * vecOffEdge.x ) + ( vecNormal.y * vecOffEdge.y ); + if ( !( FloatMakePositive( flOffDist - flDist ) < DISPCOLL_DIST_EPSILON ) && ( flOffDist > flDist ) ) + { + // Adjust plane facing if necessay - triangle should be behind the plane. + vecNormal.x = -vecNormal.x; + vecNormal.y = -vecNormal.y; + vecNormal.z = -flDist; + } + else + { + vecNormal.z = flDist; + } + + // Add edge plane to edge plane list. + iPlane = static_cast( AddPlane( vecNormal ) ); + + // Created the cached edge. + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template +bool CDispCollTree::EdgeCrossAxis( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ) +{ + if ( iPlane == DISPCOLL_NORMAL_UNDEF ) + return true; + + // Get the edge plane. + Vector vecNormal; + if ( ( iPlane & 0x8000 ) != 0 ) + { + VectorCopy( m_aEdgePlanes[(iPlane&0x7fff)], vecNormal ); + vecNormal.Negate(); + } + else + { + VectorCopy( m_aEdgePlanes[iPlane], vecNormal ); + } + + const int OTHER_AXIS1 = ( AXIS + 1 ) % 3; + const int OTHER_AXIS2 = ( AXIS + 2 ) % 3; + + // Get the pland distance are "fix" the normal. + float flDist = vecNormal[AXIS]; + vecNormal[AXIS] = 0.0f; + + // Calculate the closest point on box to plane (get extents in that direction). + Vector vecExtent; + //vecExtent[AXIS] = 0.0f; + vecExtent[OTHER_AXIS1] = ( vecNormal[OTHER_AXIS1] < 0.0f ) ? ray.m_Extents[OTHER_AXIS1] : -ray.m_Extents[OTHER_AXIS1]; + vecExtent[OTHER_AXIS2] = ( vecNormal[OTHER_AXIS2] < 0.0f ) ? ray.m_Extents[OTHER_AXIS2] : -ray.m_Extents[OTHER_AXIS2]; + + // Expand the plane by the extents of the box to reduce the swept box/triangle + // test to a ray/extruded triangle test (one of the triangles extruded planes + // was just calculated above). + Vector vecEnd; + vecEnd[AXIS] = 0; + vecEnd[OTHER_AXIS1] = ray.m_Start[OTHER_AXIS1] + ray.m_Delta[OTHER_AXIS1]; + vecEnd[OTHER_AXIS2] = ray.m_Start[OTHER_AXIS2] + ray.m_Delta[OTHER_AXIS2]; + + float flExpandDist = flDist - ( ( vecNormal[OTHER_AXIS1] * vecExtent[OTHER_AXIS1] ) + ( vecNormal[OTHER_AXIS2] * vecExtent[OTHER_AXIS2] ) ); + float flStart = ( vecNormal[OTHER_AXIS1] * ray.m_Start[OTHER_AXIS1] ) + ( vecNormal[OTHER_AXIS2] * ray.m_Start[OTHER_AXIS2] ) - flExpandDist; + float flEnd = ( vecNormal[OTHER_AXIS1] * vecEnd[OTHER_AXIS1] ) + ( vecNormal[OTHER_AXIS2] * vecEnd[OTHER_AXIS2] ) - flExpandDist; + + return ResolveRayPlaneIntersect( flStart, flEnd, vecNormal, flDist, pHelper ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool CDispCollTree::EdgeCrossAxisX( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ) +{ + return EdgeCrossAxis<0>( ray, iPlane, pHelper ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool CDispCollTree::EdgeCrossAxisY( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ) +{ + return EdgeCrossAxis<1>( ray, iPlane, pHelper ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline bool CDispCollTree::EdgeCrossAxisZ( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ) +{ + return EdgeCrossAxis<2>( ray, iPlane, pHelper ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDispCollTree::SweepAABBTriIntersect( const Ray_t &ray, const Vector &rayDir, int iTri, CDispCollTri *pTri, CBaseTrace *pTrace ) +{ + // Init test data. + CDispCollHelper helper; + helper.m_flEndFrac = 1.0f; + helper.m_flStartFrac = DISPCOLL_INVALID_FRAC; + + // Make sure objects are traveling toward one another. + float flDistAlongNormal = pTri->m_vecNormal.Dot( ray.m_Delta ); + if( flDistAlongNormal > DISPCOLL_DIST_EPSILON ) + return; + + // Test against the axis planes. + if ( !AxisPlanesXYZ( ray, pTri, &helper ) ) + { + return; + } + + // + // There are 9 edge tests - edges 1, 2, 3 cross with the box edges (symmetry) 1, 2, 3. However, the box + // is axis-aligned resulting in axially directional edges -- thus each test is edges 1, 2, and 3 vs. + // axial planes x, y, and z + // + // There are potentially 9 more tests with edges, the edge's edges and the direction of motion! + // NOTE: I don't think these tests are necessary for a manifold surface. + // + + CDispCollTriCache *pCache = &m_aTrisCache[iTri]; + + // Edges 1-3, interleaved - axis tests are 2d tests + if ( !EdgeCrossAxisX( ray, pCache->m_iCrossX[0], &helper ) ) { return; } + if ( !EdgeCrossAxisX( ray, pCache->m_iCrossX[1], &helper ) ) { return; } + if ( !EdgeCrossAxisX( ray, pCache->m_iCrossX[2], &helper ) ) { return; } + + if ( !EdgeCrossAxisY( ray, pCache->m_iCrossY[0], &helper ) ) { return; } + if ( !EdgeCrossAxisY( ray, pCache->m_iCrossY[1], &helper ) ) { return; } + if ( !EdgeCrossAxisY( ray, pCache->m_iCrossY[2], &helper ) ) { return; } + + if ( !EdgeCrossAxisZ( ray, pCache->m_iCrossZ[0], &helper ) ) { return; } + if ( !EdgeCrossAxisZ( ray, pCache->m_iCrossZ[1], &helper ) ) { return; } + if ( !EdgeCrossAxisZ( ray, pCache->m_iCrossZ[2], &helper ) ) { return; } + + // Test against the triangle face plane. + if ( !FacePlane( ray, rayDir, pTri, &helper ) ) + return; + + if ( ( helper.m_flStartFrac < helper.m_flEndFrac ) || ( FloatMakePositive( helper.m_flStartFrac - helper.m_flEndFrac ) < 0.001f ) ) + { + if ( ( helper.m_flStartFrac != DISPCOLL_INVALID_FRAC ) && ( helper.m_flStartFrac < pTrace->fraction ) ) + { + // Clamp -- shouldn't really ever be here!??? + if ( helper.m_flStartFrac < 0.0f ) + { + helper.m_flStartFrac = 0.0f; + } + + pTrace->fraction = helper.m_flStartFrac; + VectorCopy( helper.m_vecImpactNormal, pTrace->plane.normal ); + pTrace->plane.dist = helper.m_flImpactDist; + pTrace->dispFlags = pTri->m_uiFlags; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: constructor +//----------------------------------------------------------------------------- +CDispCollTree::CDispCollTree() +{ + m_nPower = 0; + m_nFlags = 0; + + for ( int iPoint = 0; iPoint < 4; ++iPoint ) + { + m_vecSurfPoints[iPoint].Init(); + } + m_nContents = -1; + m_nSurfaceProps[0] = 0; + m_nSurfaceProps[1] = 0; + + m_vecStabDir.Init(); + m_mins.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + m_maxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX ); + + m_iCounter = 0; + + m_aVerts.Purge(); + m_aTris.Purge(); + m_aEdgePlanes.Purge(); +#ifdef ENGINE_DLL + m_hCache = INVALID_MEMHANDLE; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: deconstructor +//----------------------------------------------------------------------------- +CDispCollTree::~CDispCollTree() +{ +#ifdef ENGINE_DLL + if ( m_hCache != INVALID_MEMHANDLE ) + g_DispCollTriCache.DestroyResource( m_hCache ); +#endif + m_aVerts.Purge(); + m_aTris.Purge(); + m_aEdgePlanes.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::Create( CCoreDispInfo *pDisp ) +{ + // Create the AABB Tree. + return AABBTree_Create( pDisp ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDispCollTree::PointInBounds( const Vector &vecBoxCenter, const Vector &vecBoxMin, + const Vector &vecBoxMax, bool bPoint ) +{ + // Point test inside bounds. + if( bPoint ) + { + return IsPointInBox( vecBoxCenter, m_mins, m_maxs ); + } + + // Box test inside bounds + Vector vecExtents; + VectorSubtract( vecBoxMax, vecBoxMin, vecExtents ); + vecExtents *= 0.5f; + + Vector vecExpandBounds[2]; + vecExpandBounds[0] = m_mins - vecExtents; + vecExpandBounds[1] = m_maxs + vecExtents; + + return IsPointInBox( vecBoxCenter, vecExpandBounds[0], vecExpandBounds[1] ); +} + +void CDispCollTree::GetVirtualMeshList( virtualmeshlist_t *pList ) +{ + int i; + int triangleCount = GetTriSize(); + pList->indexCount = triangleCount * 3; + pList->triangleCount = triangleCount; + pList->vertexCount = m_aVerts.Count(); + pList->pVerts = m_aVerts.Base(); + pList->pHull = NULL; + pList->surfacePropsIndex = GetSurfaceProps(0); + int index = 0; + for ( i = 0 ; i < triangleCount; i++ ) + { + pList->indices[index+0] = m_aTris[i].GetVert(0); + pList->indices[index+1] = m_aTris[i].GetVert(1); + pList->indices[index+2] = m_aTris[i].GetVert(2); + index += 3; + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +#ifdef ENGINE_DLL +static int g_nTrees; +#endif +CDispCollTree *DispCollTrees_Alloc( int count ) +{ + CDispCollTree *pTrees = NULL; +#ifdef ENGINE_DLL + pTrees = (CDispCollTree *)Hunk_Alloc( count * sizeof(CDispCollTree), false ); + g_nTrees = count; + for ( int i = 0; i < g_nTrees; i++ ) + { + Construct( pTrees + i ); + } +#else + pTrees = new CDispCollTree[count]; +#endif + if( !pTrees ) + return NULL; + + for ( int i = 0; i < count; i++ ) + { + pTrees[i].m_iCounter = i; + } + return pTrees; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void DispCollTrees_Free( CDispCollTree *pTrees ) +{ +#ifdef ENGINE_DLL + for ( int i = 0; i < g_nTrees; i++ ) + { + Destruct( pTrees + i ); + } + g_nTrees = 0; +#else + if( pTrees ) + { + delete [] pTrees; + pTrees = NULL; + } +#endif +} diff --git a/public/dispcoll_common.h b/public/dispcoll_common.h new file mode 100644 index 0000000..2e54d88 --- /dev/null +++ b/public/dispcoll_common.h @@ -0,0 +1,456 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DISPCOLL_COMMON_H +#define DISPCOLL_COMMON_H +#pragma once + +#include "trace.h" +#include "builddisp.h" +#include "bitvec.h" +#ifdef ENGINE_DLL +#include "../engine/zone.h" +#endif + +#ifdef ENGINE_DLL +template +class CDispVector : public CUtlVector > +{ +}; +#else +template +class CDispVector : public CUtlVector > +{ +}; +#endif + +FORWARD_DECLARE_HANDLE( memhandle_t ); + +#define DISPCOLL_TREETRI_SIZE MAX_DISPTRIS +#define DISPCOLL_DIST_EPSILON 0.03125f +#define DISPCOLL_ROOTNODE_INDEX 0 +#define DISPCOLL_INVALID_TRI -1 +#define DISPCOLL_INVALID_FRAC -99999.9f +#define DISPCOLL_NORMAL_UNDEF 0xffff + +extern double g_flDispCollSweepTimer; +extern double g_flDispCollIntersectTimer; +extern double g_flDispCollInCallTimer; + +struct RayDispOutput_t +{ + short ndxVerts[4]; // 3 verts and a pad + float u, v; // the u, v paramters (edgeU = v1 - v0, edgeV = v2 - v0) + float dist; // intersection distance +}; + +// Assumptions: +// Max patch is 17x17, therefore 9 bits needed to represent a triangle index +// + +//============================================================================= +// Displacement Collision Triangle +class CDispCollTri +{ + + struct index_t + { + union + { + struct + { + unsigned short uiVert:9; + unsigned short uiMin:2; + unsigned short uiMax:2; + } m_Index; + + unsigned short m_IndexDummy; + }; + }; + + index_t m_TriData[3]; + +public: + unsigned short m_ucSignBits:3; // Plane test. + unsigned short m_ucPlaneType:3; // Axial test? + unsigned short m_uiFlags:5; // Uses 5-bits - maybe look into merging it with something? + + Vector m_vecNormal; // Triangle normal (plane normal). + float m_flDist; // Triangle plane dist. + + // Creation. + CDispCollTri(); + void Init( void ); + void CalcPlane( CDispVector &m_aVerts ); + void FindMinMax( CDispVector &m_aVerts ); + + // Triangle data. + inline void SetVert( int iPos, int iVert ) { Assert( ( iPos >= 0 ) && ( iPos < 3 ) ); Assert( ( iVert >= 0 ) && ( iVert < ( 1 << 9 ) ) ); m_TriData[iPos].m_Index.uiVert = iVert; } + inline int GetVert( int iPos ) const { Assert( ( iPos >= 0 ) && ( iPos < 3 ) ); return m_TriData[iPos].m_Index.uiVert; } + inline void SetMin( int iAxis, int iMin ) { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); Assert( ( iMin >= 0 ) && ( iMin < 3 ) ); m_TriData[iAxis].m_Index.uiMin = iMin; } + inline int GetMin( int iAxis ) const { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); return m_TriData[iAxis].m_Index.uiMin; } + inline void SetMax( int iAxis, int iMax ) { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); Assert( ( iMax >= 0 ) && ( iMax < 3 ) ); m_TriData[iAxis].m_Index.uiMax = iMax; } + inline int GetMax( int iAxis ) const { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); return m_TriData[iAxis].m_Index.uiMax; } +}; + +//============================================================================= +// Helper +class CDispCollHelper +{ +public: + + float m_flStartFrac; + float m_flEndFrac; + Vector m_vecImpactNormal; + float m_flImpactDist; +}; + +//============================================================================= +// Cache +#pragma pack(1) +class CDispCollTriCache +{ +public: + unsigned short m_iCrossX[3]; + unsigned short m_iCrossY[3]; + unsigned short m_iCrossZ[3]; +}; +#pragma pack() +#include "mathlib/ssemath.h" + +class CDispCollNode +{ +public: + FourVectors m_mins; + FourVectors m_maxs; +}; + +class CDispCollLeaf +{ +public: + short m_tris[2]; +}; + +// a power 4 displacement can have 341 nodes, pad out to 344 for 16-byte alignment +const int MAX_DISP_AABB_NODES = 341; +const int MAX_AABB_LIST = 344; + +struct rayleaflist_t +{ + FourVectors rayStart; + FourVectors rayExtents; + FourVectors invDelta; + int nodeList[MAX_AABB_LIST]; + int maxIndex; +}; + +//============================================================================= +// +// Displacement Collision Tree Data +// +class CDispCollTree +{ +public: + + // Creation/Destruction. + CDispCollTree(); + ~CDispCollTree(); + virtual bool Create( CCoreDispInfo *pDisp ); + + // Raycasts. + // NOTE: These assume you've precalculated invDelta as well as culled to the bounds of this disp + bool AABBTree_Ray( const Ray_t &ray, const Vector &invDelta, CBaseTrace *pTrace, bool bSide = true ); + bool AABBTree_Ray( const Ray_t &ray, const Vector &invDelta, RayDispOutput_t &output ); + // NOTE: Lower perf helper function, should not be used in the game runtime + bool AABBTree_Ray( const Ray_t &ray, RayDispOutput_t &output ); + + // Hull Sweeps. + // NOTE: These assume you've precalculated invDelta as well as culled to the bounds of this disp + bool AABBTree_SweepAABB( const Ray_t &ray, const Vector &invDelta, CBaseTrace *pTrace ); + + // Hull Intersection. + bool AABBTree_IntersectAABB( const Vector &absMins, const Vector &absMaxs ); + + // Point/Box vs. Bounds. + bool PointInBounds( Vector const &vecBoxCenter, Vector const &vecBoxMin, Vector const &vecBoxMax, bool bPoint ); + + // Utility. + inline void SetPower( int power ) { m_nPower = power; } + inline int GetPower( void ) { return m_nPower; } + + inline int GetFlags( void ) { return m_nFlags; } + inline void SetFlags( int nFlags ) { m_nFlags = nFlags; } + inline bool CheckFlags( int nFlags ) { return ( ( nFlags & GetFlags() ) != 0 ) ? true : false; } + + inline int GetWidth( void ) { return ( ( 1 << m_nPower ) + 1 ); } + inline int GetHeight( void ) { return ( ( 1 << m_nPower ) + 1 ); } + inline int GetSize( void ) { return ( ( 1 << m_nPower ) + 1 ) * ( ( 1 << m_nPower ) + 1 ); } + inline int GetTriSize( void ) { return ( ( 1 << m_nPower ) * ( 1 << m_nPower ) * 2 ); } + +// inline void SetTriFlags( short iTri, unsigned short nFlags ) { m_aTris[iTri].m_uiFlags = nFlags; } + + inline void GetStabDirection( Vector &vecDir ) { vecDir = m_vecStabDir; } + + inline void GetBounds( Vector &vecBoxMin, Vector &vecBoxMax ) { vecBoxMin = m_mins; vecBoxMax = m_maxs; } + inline int GetContents( void ) { return m_nContents; } + inline void SetSurfaceProps( int iProp, short nSurfProp ) { Assert( ( iProp >= 0 ) && ( iProp < 2 ) ); m_nSurfaceProps[iProp] = nSurfProp; } + inline short GetSurfaceProps( int iProp ) { return m_nSurfaceProps[iProp]; } + + inline unsigned int GetMemorySize( void ) { return m_nSize; } + inline unsigned int GetCacheMemorySize( void ) { return ( m_aTrisCache.Count() * sizeof(CDispCollTriCache) + m_aEdgePlanes.Count() * sizeof(Vector) ); } + + inline bool IsCached( void ) { return m_aTrisCache.Count() == m_aTris.Count(); } + + void GetVirtualMeshList( struct virtualmeshlist_t *pList ); + int AABBTree_GetTrisInSphere( const Vector ¢er, float radius, unsigned short *pIndexOut, int indexMax ); + +public: + + inline int Nodes_GetChild( int iNode, int nDirection ); + inline int Nodes_CalcCount( int nPower ); + inline int Nodes_GetParent( int iNode ); + inline int Nodes_GetLevel( int iNode ); + inline int Nodes_GetIndexFromComponents( int x, int y ); + + void LockCache(); + void UnlockCache(); + void Cache( void ); + void Uncache() { m_aTrisCache.Purge(); m_aEdgePlanes.Purge(); } + +#ifdef ENGINE_DLL + // Data manager methods + static size_t EstimatedSize( CDispCollTree *pTree ) + { + return pTree->GetCacheMemorySize(); + } + + static CDispCollTree *CreateResource( CDispCollTree *pTree ) + { + // Created ahead of time + return pTree; + } + + bool GetData() + { + return IsCached(); + } + + size_t Size() + { + return GetCacheMemorySize(); + } + + void DestroyResource() + { + Uncache(); + m_hCache = NULL; + } +#endif + +protected: + + bool AABBTree_Create( CCoreDispInfo *pDisp ); + void AABBTree_CopyDispData( CCoreDispInfo *pDisp ); + void AABBTree_CreateLeafs( void ); + void AABBTree_GenerateBoxes_r( int nodeIndex, Vector *pMins, Vector *pMaxs ); + void AABBTree_CalcBounds( void ); + + int AABBTree_BuildTreeTrisInSphere_r( const Vector ¢er, float radius, int iNode, unsigned short *pIndexOut, unsigned short indexMax ); + + void AABBTree_TreeTrisRayTest( const Ray_t &ray, const Vector &vecInvDelta, int iNode, CBaseTrace *pTrace, bool bSide, CDispCollTri **pImpactTri ); + void AABBTree_TreeTrisRayBarycentricTest( const Ray_t &ray, const Vector &vecInvDelta, int iNode, RayDispOutput_t &output, CDispCollTri **pImpactTri ); + + int FORCEINLINE BuildRayLeafList( int iNode, rayleaflist_t &list ); + + struct AABBTree_TreeTrisSweepTest_Args_t + { + AABBTree_TreeTrisSweepTest_Args_t( const Ray_t &ray, const Vector &vecInvDelta, const Vector &rayDir, CBaseTrace *pTrace ) + : ray( ray ), vecInvDelta( vecInvDelta ), rayDir( rayDir ), pTrace( pTrace ) {} + const Ray_t &ray; + const Vector &vecInvDelta; + const Vector &rayDir; + CBaseTrace *pTrace; + }; + +protected: + + void SweepAABBTriIntersect( const Ray_t &ray, const Vector &rayDir, int iTri, CDispCollTri *pTri, CBaseTrace *pTrace ); + + void Cache_Create( CDispCollTri *pTri, int iTri ); // Testing! + bool Cache_EdgeCrossAxisX( const Vector &vecEdge, const Vector &vecOnEdge, const Vector &vecOffEdge, CDispCollTri *pTri, unsigned short &iPlane ); + bool Cache_EdgeCrossAxisY( const Vector &vecEdge, const Vector &vecOnEdge, const Vector &vecOffEdge, CDispCollTri *pTri, unsigned short &iPlane ); + bool Cache_EdgeCrossAxisZ( const Vector &vecEdge, const Vector &vecOnEdge, const Vector &vecOffEdge, CDispCollTri *pTri, unsigned short &iPlane ); + + inline bool FacePlane( const Ray_t &ray, const Vector &rayDir, CDispCollTri *pTri, CDispCollHelper *pHelper ); + bool FORCEINLINE AxisPlanesXYZ( const Ray_t &ray, CDispCollTri *pTri, CDispCollHelper *pHelper ); + inline bool EdgeCrossAxisX( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ); + inline bool EdgeCrossAxisY( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ); + inline bool EdgeCrossAxisZ( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ); + + bool ResolveRayPlaneIntersect( float flStart, float flEnd, const Vector &vecNormal, float flDist, CDispCollHelper *pHelper ); + template bool FORCEINLINE TestOneAxisPlaneMin( const Ray_t &ray, CDispCollTri *pTri ); + template bool FORCEINLINE TestOneAxisPlaneMax( const Ray_t &ray, CDispCollTri *pTri ); + template bool EdgeCrossAxis( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper ); + + // Utility + inline void CalcClosestBoxPoint( const Vector &vecPlaneNormal, const Vector &vecBoxStart, const Vector &vecBoxExtents, Vector &vecBoxPoint ); + inline void CalcClosestExtents( const Vector &vecPlaneNormal, const Vector &vecBoxExtents, Vector &vecBoxPoint ); + int AddPlane( const Vector &vecNormal ); + bool FORCEINLINE IsLeafNode(int iNode); +public: + Vector m_mins; // Bounding box of the displacement surface and base face + int m_iCounter; + Vector m_maxs; // Bounding box of the displacement surface and base face +protected: + int m_nContents; // The displacement surface "contents" (solid, etc...) + +#ifdef ENGINE_DLL + memhandle_t m_hCache; +#endif + + int m_nPower; // Size of the displacement ( 2^power + 1 ) + int m_nFlags; + + Vector m_vecSurfPoints[4]; // Base surface points. + // Collision data. + Vector m_vecStabDir; // Direction to stab for this displacement surface (is the base face normal) + short m_nSurfaceProps[2]; // Surface properties (save off from texdata for impact responses) + +protected: + CDispVector m_aVerts; // Displacement verts. + CDispVector m_aTris; // Displacement triangles. + CDispVector m_nodes; // Nodes. + CDispVector m_leaves; // Leaves. + // Cache + CUtlVector m_aTrisCache; + CUtlVector m_aEdgePlanes; + + CDispCollHelper m_Helper; + + unsigned int m_nSize; + +}; + +FORCEINLINE bool CDispCollTree::IsLeafNode(int iNode) +{ + return iNode >= m_nodes.Count() ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: get the child node index given the current node index and direction +// of the child (1 of 4) +// Input: iNode - current node index +// nDirection - direction of the child ( [0...3] - SW, SE, NW, NE ) +// Output: int - the index of the child node +//----------------------------------------------------------------------------- +inline int CDispCollTree::Nodes_GetChild( int iNode, int nDirection ) +{ + // node range [0...m_NodeCount) + Assert( iNode >= 0 ); + Assert( iNode < m_nodes.Count() ); + + // ( node index * 4 ) + ( direction + 1 ) + return ( ( iNode << 2 ) + ( nDirection + 1 ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline int CDispCollTree::Nodes_CalcCount( int nPower ) +{ + Assert( nPower >= 1 ); + Assert( nPower <= 4 ); + + return ( ( 1 << ( ( nPower + 1 ) << 1 ) ) / 3 ); +} + +//----------------------------------------------------------------------------- +// Purpose: get the parent node index given the current node +// Input: iNode - current node index +// Output: int - the index of the parent node +//----------------------------------------------------------------------------- +inline int CDispCollTree::Nodes_GetParent( int iNode ) +{ + // node range [0...m_NodeCount) + Assert( iNode >= 0 ); + Assert( iNode < m_nodes.Count() ); + + // ( node index - 1 ) / 4 + return ( ( iNode - 1 ) >> 2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// TODO: should make this a function - not a hardcoded set of statements!!! +//----------------------------------------------------------------------------- +inline int CDispCollTree::Nodes_GetLevel( int iNode ) +{ + // node range [0...m_NodeCount) + Assert( iNode >= 0 ); + Assert( iNode < m_nodes.Count() ); + + // level = 2^n + 1 + if ( iNode == 0 ) { return 1; } + if ( iNode < 5 ) { return 2; } + if ( iNode < 21 ) { return 3; } + if ( iNode < 85 ) { return 4; } + if ( iNode < 341 ) { return 5; } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline int CDispCollTree::Nodes_GetIndexFromComponents( int x, int y ) +{ + int nIndex = 0; + + // Interleave bits from the x and y values to create the index + int iShift; + for( iShift = 0; x != 0; iShift += 2, x >>= 1 ) + { + nIndex |= ( x & 1 ) << iShift; + } + + for( iShift = 1; y != 0; iShift += 2, y >>= 1 ) + { + nIndex |= ( y & 1 ) << iShift; + } + + return nIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollTree::CalcClosestBoxPoint( const Vector &vecPlaneNormal, const Vector &vecBoxStart, + const Vector &vecBoxExtents, Vector &vecBoxPoint ) +{ + vecBoxPoint = vecBoxStart; + ( vecPlaneNormal[0] < 0.0f ) ? vecBoxPoint[0] += vecBoxExtents[0] : vecBoxPoint[0] -= vecBoxExtents[0]; + ( vecPlaneNormal[1] < 0.0f ) ? vecBoxPoint[1] += vecBoxExtents[1] : vecBoxPoint[1] -= vecBoxExtents[1]; + ( vecPlaneNormal[2] < 0.0f ) ? vecBoxPoint[2] += vecBoxExtents[2] : vecBoxPoint[2] -= vecBoxExtents[2]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CDispCollTree::CalcClosestExtents( const Vector &vecPlaneNormal, const Vector &vecBoxExtents, + Vector &vecBoxPoint ) +{ + ( vecPlaneNormal[0] < 0.0f ) ? vecBoxPoint[0] = vecBoxExtents[0] : vecBoxPoint[0] = -vecBoxExtents[0]; + ( vecPlaneNormal[1] < 0.0f ) ? vecBoxPoint[1] = vecBoxExtents[1] : vecBoxPoint[1] = -vecBoxExtents[1]; + ( vecPlaneNormal[2] < 0.0f ) ? vecBoxPoint[2] = vecBoxExtents[2] : vecBoxPoint[2] = -vecBoxExtents[2]; +} + +//============================================================================= +// Global Helper Functions +CDispCollTree *DispCollTrees_Alloc( int count ); +void DispCollTrees_Free( CDispCollTree *pTrees ); + +#endif // DISPCOLL_COMMON_H diff --git a/public/dlight.h b/public/dlight.h new file mode 100644 index 0000000..032cae6 --- /dev/null +++ b/public/dlight.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined ( DLIGHTH ) +#define DLIGHTH +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" + +//----------------------------------------------------------------------------- +// Dynamic light structure +//----------------------------------------------------------------------------- + +enum +{ + DLIGHT_NO_WORLD_ILLUMINATION = 0x1, + DLIGHT_NO_MODEL_ILLUMINATION = 0x2, + + // NOTE: These two features are used to dynamically tweak the alpha on displacements + // which is a special effect for selecting which texture to use. If + // we ever change how alpha is stored for displacements, we'll have to kill this feature + DLIGHT_ADD_DISPLACEMENT_ALPHA = 0x4, + DLIGHT_SUBTRACT_DISPLACEMENT_ALPHA = 0x8, + DLIGHT_DISPLACEMENT_MASK = (DLIGHT_ADD_DISPLACEMENT_ALPHA | DLIGHT_SUBTRACT_DISPLACEMENT_ALPHA), +}; + +// This is the lighting value that is used to determine when something can be +// culle from lighting because it is close enough to black to be virtually black. +//#define MIN_LIGHTING_VALUE (1.0f/256.0f) + +// This is the broken value of MIN_LIGHTING_VALUE that we have to take into consideration +// to make sure that the lighting for dlights look the same as they did in HL2. +// We'll use the real MIN_LIGHTING_VALUE above to calculate larger radii for dynamic +// light sources. +//#define HL2_BROKEN_MIN_LIGHTING_VALUE (20.0f/256.0f) + +struct dlight_t +{ + int flags; + Vector origin; + float radius; + ColorRGBExp32 color; // Light color with exponent + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + int style; // lightstyle + + // For spotlights. Use m_OuterAngle == 0 for point lights + Vector m_Direction; // center of the light cone + float m_InnerAngle; + float m_OuterAngle; + + // see comments above about HL2_BROKEN_MIN_LIGHTING_VALUE and MIN_LIGHTING_VALUE + // THIS SHOULD ONLY GET CALLED FROM THE ENGINE + float GetRadius() const + { +// return FastSqrt( radius * radius * ( HL2_BROKEN_MIN_LIGHTING_VALUE / MIN_LIGHTING_VALUE ) ); + return radius; + } + + // see comments above about HL2_BROKEN_MIN_LIGHTING_VALUE and MIN_LIGHTING_VALUE + // THIS SHOULD ONLY GET CALLED FROM THE ENGINE + float GetRadiusSquared() const + { +// return radius * radius * ( HL2_BROKEN_MIN_LIGHTING_VALUE / MIN_LIGHTING_VALUE ); + return radius * radius; + } + + // THIS SHOULD ONLY GET CALLED FROM THE ENGINE + float IsRadiusGreaterThanZero() const + { + // don't bother calculating the new radius if you just want to know if it is greater than zero. + return radius > 0.0f; + } +}; + +#endif diff --git a/public/dmserializers/idmserializers.h b/public/dmserializers/idmserializers.h new file mode 100644 index 0000000..f50f8de --- /dev/null +++ b/public/dmserializers/idmserializers.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Main header file for the serializers DLL +// +//============================================================================= + +#ifndef IDMSERIALIZERS_H +#define IDMSERIALIZERS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" + + +//----------------------------------------------------------------------------- +// Interface +//----------------------------------------------------------------------------- +class IDmSerializers : public IAppSystem +{ +}; + + +//----------------------------------------------------------------------------- +// Used only by applications to hook in DmSerializers +//----------------------------------------------------------------------------- +#define DMSERIALIZERS_INTERFACE_VERSION "VDmSerializers001" + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +extern IDmSerializers *g_pDmSerializers; + + +#endif // DMSERIALIZERS_H + + diff --git a/public/dmxloader/dmxattribute.h b/public/dmxloader/dmxattribute.h new file mode 100644 index 0000000..1752366 --- /dev/null +++ b/public/dmxloader/dmxattribute.h @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMXATTRIBUTE_H +#define DMXATTRIBUTE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/dmattributetypes.h" +#include "tier1/utlvector.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlsymbol.h" +#include "tier1/mempool.h" +#include "dmxloader/dmxloader.h" + + +//----------------------------------------------------------------------------- +// Forward declarations: +//----------------------------------------------------------------------------- +class CDmxElement; + + +//----------------------------------------------------------------------------- +// Attribute info, modified for use in mod code +//----------------------------------------------------------------------------- +DECLARE_ATTRIBUTE_TYPE( CDmxElement*, AT_ELEMENT, "element", value = 0; ) +DECLARE_ATTRIBUTE_ARRAY_TYPE( CDmxElement*, AT_ELEMENT_ARRAY, "element_array" ) + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CDmxAttribute +{ + DECLARE_DMX_ALLOCATOR( ); + +public: + // Returns attribute name and type + DmAttributeType_t GetType() const; + const char *GetTypeString() const; + template< class T > bool IsA() const; + + // Returns the name. NOTE: The utlsymbol + // can be turned into a string by using g_pDataModel->String(); + const char *GetName() const; + CUtlSymbol GetNameSymbol() const; + void SetName( const char *pName ); + + // Gets values + template< class T > const T& GetValue( ) const; + template< class T > const CUtlVector< T >& GetArray( ) const; + const char *GetValueString() const; + + // Sets values (+ type) + template< class T > void SetValue( const T& value ); + void SetValue( const char *pString ); + void SetValue( const void *pBuffer, size_t nLen ); + void SetValue( const CDmxAttribute *pAttribute ); + + // Method to set values in an array (just directly operate on the array) + // NOTE: This will create a new array of the appropriate type if + // the type doesn't match the current type + template< class T > CUtlVector< T >& GetArrayForEdit(); + + // Sets the attribute to its default value based on its type + void SetToDefaultValue(); + + // Convert to and from string + void SetValueFromString( const char *pValue ); + const char *GetValueAsString( char *pBuffer, size_t nBufLen ) const; + + // Gets the size of an array, returns 0 if it's not an array type + int GetArrayCount() const; + + // Read from file + bool Unserialize( DmAttributeType_t type, CUtlBuffer &buf ); + bool UnserializeElement( DmAttributeType_t type, CUtlBuffer &buf ); + bool Serialize( CUtlBuffer &buf ) const; + bool SerializeElement( int nIndex, CUtlBuffer &buf ) const; + bool SerializesOnMultipleLines() const; + + // Returns the size of the variables storing the various attribute types + static int AttributeDataSize( DmAttributeType_t type ); + +private: + CDmxAttribute( const char *pAttributeName ); + CDmxAttribute( CUtlSymbol attributeName ); + ~CDmxAttribute(); + + // Allocate, free memory for data + void AllocateDataMemory( DmAttributeType_t type ); + void FreeDataMemory( ); + + // Untyped method for setting used by unpack + void SetValue( DmAttributeType_t type, const void *pSrc, int nLen ); + + DmAttributeType_t m_Type; + CUtlSymbol m_Name; + void *m_pData; + + static CUtlSymbolTableMT s_AttributeNameSymbols; + + friend class CDmxElement; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline DmAttributeType_t CDmxAttribute::GetType() const +{ + return m_Type; +} + +template< class T > inline bool CDmxAttribute::IsA() const +{ + return GetType() == CDmAttributeInfo< T >::ATTRIBUTE_TYPE; +} + +inline CUtlSymbol CDmxAttribute::GetNameSymbol() const +{ + return m_Name; +} + + +//----------------------------------------------------------------------------- +// Sets a value in the attribute +//----------------------------------------------------------------------------- +template< class T > void CDmxAttribute::SetValue( const T& value ) +{ + AllocateDataMemory( CDmAttributeInfo::AttributeType() ); + CopyConstruct( (T*)m_pData, value ); +} + + +//----------------------------------------------------------------------------- +// Returns data in the attribute +//----------------------------------------------------------------------------- +inline const char *CDmxAttribute::GetValueString() const +{ + if ( m_Type == AT_STRING ) + return *(CUtlString*)m_pData; + return ""; +} + +template< class T > +inline const T& CDmxAttribute::GetValue( ) const +{ + if ( CDmAttributeInfo::AttributeType() == m_Type ) + return *(T*)m_pData; + + static T defaultValue; + CDmAttributeInfo::SetDefaultValue( defaultValue ); + return defaultValue; +} + +template< class T > +inline const CUtlVector< T >& CDmxAttribute::GetArray( ) const +{ + if ( CDmAttributeInfo< CUtlVector< T > >::AttributeType() == m_Type ) + return *( CUtlVector< T > *)m_pData; + + static CUtlVector defaultArray; + return defaultArray; +} + +template< class T > +inline CUtlVector< T >& CDmxAttribute::GetArrayForEdit( ) +{ + if ( CDmAttributeInfo< CUtlVector< T > >::AttributeType() == m_Type ) + return *( CUtlVector< T > *)m_pData; + + AllocateDataMemory( CDmAttributeInfo< CUtlVector< T > >::AttributeType() ); + Construct( (CUtlVector*)m_pData ); + return *(CUtlVector< T > *)m_pData; +} + +#endif // DMXATTRIBUTE_H diff --git a/public/dmxloader/dmxelement.h b/public/dmxloader/dmxelement.h new file mode 100644 index 0000000..666a117 --- /dev/null +++ b/public/dmxloader/dmxelement.h @@ -0,0 +1,310 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMXELEMENT_H +#define DMXELEMENT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "datamodel/dmattributetypes.h" +#include "tier1/utlvector.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlsymbol.h" +#include "tier1/mempool.h" +#include "tier1/UtlSortVector.h" +#include "dmxloader/dmxattribute.h" + + +//----------------------------------------------------------------------------- +// Sort functor class for attributes +//----------------------------------------------------------------------------- +class CDmxAttributeLess +{ +public: + bool Less( const CDmxAttribute * pAttribute1, const CDmxAttribute *pAttribute2, void *pContext ) + { + return pAttribute1->GetNameSymbol() < pAttribute2->GetNameSymbol(); + } +}; + + +//----------------------------------------------------------------------------- +// Used to unpack elements into a structure. Does not recurse +// Also does not work with arrays. +//----------------------------------------------------------------------------- +struct DmxElementUnpackStructure_t +{ + const char *m_pAttributeName; + const char *m_pDefaultString; + DmAttributeType_t m_AttributeType; + int m_nOffset; + int m_nSize; + const void *m_pUserData; // If you want to associate some app-specific data with each field +}; + +#define DECLARE_DMXELEMENT_UNPACK() \ + template friend DmxElementUnpackStructure_t *DmxElementUnpackInit(T *); + +#define BEGIN_DMXELEMENT_UNPACK( _structName ) \ + template DmxElementUnpackStructure_t *DmxElementUnpackInit(T *); \ + template <> DmxElementUnpackStructure_t *DmxElementUnpackInit<_structName>( _structName * ); \ + namespace _structName##_UnpackInit \ + { \ + static DmxElementUnpackStructure_t *s_pUnpack = DmxElementUnpackInit( (_structName *)NULL ); \ + } \ + \ + template <> DmxElementUnpackStructure_t *DmxElementUnpackInit<_structName>( _structName * ) \ + { \ + typedef _structName DestStructType_t; \ + static DmxElementUnpackStructure_t unpack[] = \ + { \ + +#define DMXELEMENT_UNPACK_FLTX4( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, CDmAttributeInfo::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( fltx4 ), NULL }, +#define DMXELEMENT_UNPACK_FIELD( _attributeName, _defaultString, _type, _varName ) \ + { _attributeName, _defaultString, CDmAttributeInfo<_type>::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NULL }, +#define DMXELEMENT_UNPACK_FIELD_STRING( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NULL }, + +#define DMXELEMENT_UNPACK_FIELD_USERDATA( _attributeName, _defaultString, _type, _varName, _userData ) \ + { _attributeName, _defaultString, CDmAttributeInfo<_type>::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), _userData }, +#define DMXELEMENT_UNPACK_FIELD_STRING_USERDATA( _attributeName, _defaultString, _varName, _userData ) \ + { _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), _userData }, + +#define END_DMXELEMENT_UNPACK( _structName, _varName ) \ + { NULL, NULL, AT_UNKNOWN, 0, 0, NULL } \ + }; \ + return unpack; \ + } \ + DmxElementUnpackStructure_t *_varName = _structName##_UnpackInit::s_pUnpack; + +#define END_DMXELEMENT_UNPACK_TEMPLATE( _structName, _varName ) \ + { NULL, NULL, AT_UNKNOWN, 0, 0, NULL } \ + }; \ + return unpack; \ + } \ + template<> DmxElementUnpackStructure_t *_varName = _structName##_UnpackInit::s_pUnpack; + + +//----------------------------------------------------------------------------- +// Element used to read dmx files from mod code. Similar to keyvalues. +//----------------------------------------------------------------------------- +class CDmxElement +{ + DECLARE_DMX_ALLOCATOR( ); + +public: + bool HasAttribute( const char *pAttributeName ) const; + CDmxAttribute *GetAttribute( const char *pAttributeName ); + const CDmxAttribute *GetAttribute( const char *pAttributeName ) const; + int AttributeCount() const; + CDmxAttribute *GetAttribute( int nIndex ); + const CDmxAttribute *GetAttribute( int nIndex ) const; + CUtlSymbol GetType() const; + const char* GetTypeString() const; + const char* GetName() const; + const DmObjectId_t &GetId() const; + + // Add+remove+rename can only occur during lock + // NOTE: AddAttribute will find or add; returning an existing attribute if + // one with the appropriate name exists + void LockForChanges( bool bLock ); + CDmxAttribute *AddAttribute( const char *pAttributeName ); + void RemoveAttribute( const char *pAttributeName ); + void RemoveAttributeByPtr( CDmxAttribute *pAttribute ); + void RemoveAllAttributes(); + void RenameAttribute( const char *pAttributeName, const char *pNewName ); + + // Simple methods to read attributes + const char *GetValueString( const char *pAttributeName ) const; + template< class T > const T& GetValue( const char *pAttributeName ) const; + template< class T > const T& GetValue( const char *pAttributeName, const T& defaultValue ) const; + + template< class T > const CUtlVector& GetArray( const char *pAttributeName ) const; + template< class T > const CUtlVector& GetArray( const char *pAttributeName, const CUtlVector& defaultValue ) const; + + // Set methods + CDmxAttribute* SetValue( const char *pAttributeName, const char *pString ); + CDmxAttribute* SetValue( const char *pAttributeName, void *pBuffer, int nLen ); + template< class T > CDmxAttribute* SetValue( const char *pAttributeName, const T& value ); + + // Method to unpack data into a structure + void UnpackIntoStructure( void *pData, size_t DataSizeInBytes, const DmxElementUnpackStructure_t *pUnpack ) const; + + // Creates attributes based on the unpack structure + template + void AddAttributesFromStructure( const T *pData, const DmxElementUnpackStructure_t *pUnpack ) + { + AddAttributesFromStructure_Internal( pData, sizeof(T), pUnpack ); + } + +private: + void AddAttributesFromStructure_Internal( const void *pData, size_t byteCount, const DmxElementUnpackStructure_t *pUnpack ); + typedef CUtlSortVector< CDmxAttribute*, CDmxAttributeLess > AttributeList_t; + + CDmxElement( const char *pType ); + ~CDmxElement(); + + // Removes all elements recursively + void RemoveAllElementsRecursive(); + + // Adds elements to delete to the deletion list + void AddElementsToDelete( CUtlVector< CDmxElement * >& elementsToDelete ); + + // Sorts the vector when a change has occurred + void Resort( ) const; + + // Finds an attribute by name + int FindAttribute( const char *pAttributeName ) const; + int FindAttribute( CUtlSymbol attributeName ) const; + + // Sets the object id + void SetId( const DmObjectId_t &id ); + + // Are we locked? + bool IsLocked() const; + + AttributeList_t m_Attributes; + DmObjectId_t m_Id; // We need this strictly because we support serialization + CUtlSymbol m_Type; + char m_nLockCount; + mutable bool m_bResortNeeded : 1; + bool m_bIsMarkedForDeletion : 1; + + static CUtlSymbolTableMT s_TypeSymbols; + + friend class CDmxSerializer; + friend class CDmxSerializerKeyValues2; + friend void CleanupDMX( CDmxElement* pElement ); + friend CDmxElement* CreateDmxElement( const char *pType ); +}; + + +//----------------------------------------------------------------------------- +// inline methods +//----------------------------------------------------------------------------- + +// Are we locked? +inline bool CDmxElement::IsLocked() const +{ + return m_nLockCount > 0; +} + +inline const char *CDmxElement::GetValueString( const char *pAttributeName ) const +{ + const CDmxAttribute* pAttribute = GetAttribute( pAttributeName ); + if ( pAttribute ) + return pAttribute->GetValueString(); + return ""; +} + +template< class T > +inline const T& CDmxElement::GetValue( const char *pAttributeName ) const +{ + const CDmxAttribute* pAttribute = GetAttribute( pAttributeName ); + if ( pAttribute ) + return pAttribute->GetValue(); + + static T defaultValue; + CDmAttributeInfo::SetDefaultValue( defaultValue ); + return defaultValue; +} + +template< class T > +inline const T& CDmxElement::GetValue( const char *pAttributeName, const T& defaultValue ) const +{ + const CDmxAttribute* pAttribute = GetAttribute( pAttributeName ); + if ( pAttribute ) + return pAttribute->GetValue(); + return defaultValue; +} + +template< class T > +inline const CUtlVector& CDmxElement::GetArray( const char *pAttributeName ) const +{ + const CDmxAttribute* pAttribute = GetAttribute( pAttributeName ); + if ( pAttribute ) + return pAttribute->GetArray(); + + static CUtlVector defaultValue; + return defaultValue; +} + +template< class T > +inline const CUtlVector& CDmxElement::GetArray( const char *pAttributeName, const CUtlVector& defaultValue ) const +{ + const CDmxAttribute* pAttribute = GetAttribute( pAttributeName ); + if ( pAttribute ) + return pAttribute->GetArray(); + return defaultValue; +} + + +//----------------------------------------------------------------------------- +// Creates a dmx element +//----------------------------------------------------------------------------- +CDmxElement* CreateDmxElement( const char *pType ); + + +//----------------------------------------------------------------------------- +// Helper class to lock elements for changes +//----------------------------------------------------------------------------- +class CDmxElementModifyScope +{ +public: + CDmxElementModifyScope( CDmxElement *pElement ) : m_pElement( pElement ) + { + m_pElement->LockForChanges( true ); + } + ~CDmxElementModifyScope() + { + Release(); + } + void Release() + { + if ( m_pElement ) + { + m_pElement->LockForChanges( false ); + m_pElement = NULL; + } + } +private: + CDmxElement *m_pElement; +}; + + +//----------------------------------------------------------------------------- +// Set methods +//----------------------------------------------------------------------------- +inline CDmxAttribute* CDmxElement::SetValue( const char *pAttributeName, const char *pString ) +{ + CDmxElementModifyScope modify( this ); + CDmxAttribute *pAttribute = AddAttribute( pAttributeName ); + pAttribute->SetValue( pString ); + return pAttribute; +} + +inline CDmxAttribute* CDmxElement::SetValue( const char *pAttributeName, void *pBuffer, int nLen ) +{ + CDmxElementModifyScope modify( this ); + CDmxAttribute *pAttribute = AddAttribute( pAttributeName ); + pAttribute->SetValue( pBuffer, nLen ); + return pAttribute; +} + +template< class T > +inline CDmxAttribute* CDmxElement::SetValue( const char *pAttributeName, const T& value ) +{ + CDmxElementModifyScope modify( this ); + CDmxAttribute *pAttribute = AddAttribute( pAttributeName ); + pAttribute->SetValue( value ); + return pAttribute; +} + + +#endif // DMXELEMENT_H diff --git a/public/dmxloader/dmxloader.h b/public/dmxloader/dmxloader.h new file mode 100644 index 0000000..54815ae --- /dev/null +++ b/public/dmxloader/dmxloader.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DMXLOADER_H +#define DMXLOADER_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; +class CDmxElement; + + +//----------------------------------------------------------------------------- +// Serialization/Unserialization +//----------------------------------------------------------------------------- +bool SerializeDMX( CUtlBuffer &buf, CDmxElement *pRoot, const char *pFileName = NULL ); +bool SerializeDMX( const char *pFileName, const char *pPathID, bool bTextMode, CDmxElement *pRoot ); + +bool UnserializeDMX( CUtlBuffer &buf, CDmxElement **ppRoot, const char *pFileName = NULL ); +bool UnserializeDMX( const char *pFileName, const char *pPathID, bool bTextMode, CDmxElement **ppRoot ); + +//----------------------------------------------------------------------------- +// DMX elements/attributes can only be accessed inside a dmx context +//----------------------------------------------------------------------------- +void BeginDMXContext( ); +void EndDMXContext( bool bDecommitMemory ); +void DecommitDMXMemory(); + + +//----------------------------------------------------------------------------- +// Helper macro +//----------------------------------------------------------------------------- +class CDMXContextHelper +{ +public: + CDMXContextHelper( bool bDecommitMemory ) { m_bDecommitMemory = bDecommitMemory; BeginDMXContext(); } + ~CDMXContextHelper() { EndDMXContext( m_bDecommitMemory ); } + +private: + bool m_bDecommitMemory; +}; + +#define DECLARE_DMX_CONTEXT( ) CDMXContextHelper __dmxContextHelper( true ); +#define DECLARE_DMX_CONTEXT_NODECOMMIT( ) CDMXContextHelper __dmxContextHelper( false ); +#define DECLARE_DMX_CONTEXT_DECOMMIT( _decommit ) CDMXContextHelper __dmxContextHelper( _decommit ); + + +//----------------------------------------------------------------------------- +// Used for allocation. All will be freed when we leave the DMX context +//----------------------------------------------------------------------------- +void* DMXAlloc( size_t size ); + + +//----------------------------------------------------------------------------- +// Helper macro +//----------------------------------------------------------------------------- +#define DECLARE_DMX_ALLOCATOR( ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_( "DMXAlloc" ); return DMXAlloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_( "DMXAlloc" ); return DMXAlloc(size); } \ + inline void operator delete( void* p ) { } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { } \ + +#endif // DMXLOADER_H \ No newline at end of file diff --git a/public/dt_common.h b/public/dt_common.h new file mode 100644 index 0000000..cee4013 --- /dev/null +++ b/public/dt_common.h @@ -0,0 +1,223 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef DATATABLE_COMMON_H +#define DATATABLE_COMMON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "tier0/dbg.h" +#include "tier1/strtools.h" +#include + +#ifdef LINUX +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +// Max number of properties in a datatable and its children. +#define MAX_DATATABLES 1024 // must be a power of 2. +#define MAX_DATATABLE_PROPS 4096 + +#define MAX_ARRAY_ELEMENTS 2048 // a network array should have more that 1024 elements + +#define HIGH_DEFAULT -121121.121121f + +#define BITS_FULLRES -1 // Use the full resolution of the type being encoded. +#define BITS_WORLDCOORD -2 // Encode as a world coordinate. + +#define DT_MAX_STRING_BITS 9 +#define DT_MAX_STRING_BUFFERSIZE (1<varName ) + +// Gets the size of a variable in a class. +#define PROPSIZEOF(className, varName) sizeof(((className*)0)->varName) + + +// SendProp::m_Flags. +#define SPROP_UNSIGNED (1<<0) // Unsigned integer data. + +#define SPROP_COORD (1<<1) // If this is set, the float/vector is treated like a world coordinate. + // Note that the bit count is ignored in this case. + +#define SPROP_NOSCALE (1<<2) // For floating point, don't scale into range, just take value as is. + +#define SPROP_ROUNDDOWN (1<<3) // For floating point, limit high value to range minus one bit unit + +#define SPROP_ROUNDUP (1<<4) // For floating point, limit low value to range minus one bit unit + +#define SPROP_NORMAL (1<<5) // If this is set, the vector is treated like a normal (only valid for vectors) + +#define SPROP_EXCLUDE (1<<6) // This is an exclude prop (not excludED, but it points at another prop to be excluded). + +#define SPROP_XYZE (1<<7) // Use XYZ/Exponent encoding for vectors. + +#define SPROP_INSIDEARRAY (1<<8) // This tells us that the property is inside an array, so it shouldn't be put into the + // flattened property list. Its array will point at it when it needs to. + +#define SPROP_PROXY_ALWAYS_YES (1<<9) // Set for datatable props using one of the default datatable proxies like + // SendProxy_DataTableToDataTable that always send the data to all clients. + +#define SPROP_CHANGES_OFTEN (1<<10) // this is an often changed field, moved to head of sendtable so it gets a small index + +#define SPROP_IS_A_VECTOR_ELEM (1<<11) // Set automatically if SPROP_VECTORELEM is used. + +#define SPROP_COLLAPSIBLE (1<<12) // Set automatically if it's a datatable with an offset of 0 that doesn't change the pointer + // (ie: for all automatically-chained base classes). + // In this case, it can get rid of this SendPropDataTable altogether and spare the + // trouble of walking the hierarchy more than necessary. + +#define SPROP_COORD_MP (1<<13) // Like SPROP_COORD, but special handling for multiplayer games +#define SPROP_COORD_MP_LOWPRECISION (1<<14) // Like SPROP_COORD, but special handling for multiplayer games where the fractional component only gets a 3 bits instead of 5 +#define SPROP_COORD_MP_INTEGRAL (1<<15) // SPROP_COORD_MP, but coordinates are rounded to integral boundaries + +#define SPROP_VARINT SPROP_NORMAL // reuse existing flag so we don't break demo. note you want to include SPROP_UNSIGNED if needed, its more efficient + +#define SPROP_NUMFLAGBITS_NETWORKED 16 + +// This is server side only, it's used to mark properties whose SendProxy_* functions encode against gpGlobals->tickcount (the only ones that currently do this are +// m_flAnimTime and m_flSimulationTime. MODs shouldn't need to mess with this probably +#define SPROP_ENCODED_AGAINST_TICKCOUNT (1<<16) + +// See SPROP_NUMFLAGBITS_NETWORKED for the ones which are networked +#define SPROP_NUMFLAGBITS 17 + +// Used by the SendProp and RecvProp functions to disable debug checks on type sizes. +#define SIZEOF_IGNORE -1 + + +// Use this to extern send and receive datatables, and reference them. +#define EXTERN_SEND_TABLE(tableName) namespace tableName {extern SendTable g_SendTable;} +#define EXTERN_RECV_TABLE(tableName) namespace tableName {extern RecvTable g_RecvTable;} + +#define REFERENCE_SEND_TABLE(tableName) tableName::g_SendTable +#define REFERENCE_RECV_TABLE(tableName) tableName::g_RecvTable + + +class SendProp; + +// The day we do this, we break all mods until they recompile. +//#define SUPPORTS_INT64 + +typedef enum +{ + DPT_Int=0, + DPT_Float, + DPT_Vector, + DPT_VectorXY, // Only encodes the XY of a vector, ignores Z + DPT_String, + DPT_Array, // An array of the base types (can't be of datatables). + DPT_DataTable, +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! + DPT_Quaternion, +#endif + +#ifdef SUPPORTS_INT64 + DPT_Int64, +#endif + + DPT_NUMSendPropTypes + +} SendPropType; + + +class DVariant +{ +public: + DVariant() {m_Type = DPT_Float;} + DVariant(float val) {m_Type = DPT_Float; m_Float = val;} + + const char *ToString() + { + static char text[128]; + + switch ( m_Type ) + { + case DPT_Int : + Q_snprintf( text, sizeof(text), "%i", m_Int ); + break; + case DPT_Float : + Q_snprintf( text, sizeof(text), "%.3f", m_Float ); + break; + case DPT_Vector : + Q_snprintf( text, sizeof(text), "(%.3f,%.3f,%.3f)", + m_Vector[0], m_Vector[1], m_Vector[2] ); + break; + case DPT_VectorXY : + Q_snprintf( text, sizeof(text), "(%.3f,%.3f)", + m_Vector[0], m_Vector[1] ); + break; +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! + case DPT_Quaternion : + Q_snprintf( text, sizeof(text), "(%.3f,%.3f,%.3f %.3f)", + m_Vector[0], m_Vector[1], m_Vector[2], m_Vector[3] ); + break; +#endif + case DPT_String : + if ( m_pString ) + return m_pString; + else + return "NULL"; + break; + case DPT_Array : + Q_snprintf( text, sizeof(text), "Array" ); + break; + case DPT_DataTable : + Q_snprintf( text, sizeof(text), "DataTable" ); + break; +#ifdef SUPPORTS_INT64 + case DPT_Int64: + Q_snprintf( text, sizeof(text), "%I64d", m_Int64 ); + break; +#endif + default : + Q_snprintf( text, sizeof(text), "DVariant type %i unknown", m_Type ); + break; + } + + return text; + } + + union + { + float m_Float; + int m_Int; + const char *m_pString; + void *m_pData; // For DataTables. +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! + float m_Vector[4]; +#else + float m_Vector[3]; +#endif + +#ifdef SUPPORTS_INT64 + int64 m_Int64; +#endif + }; + SendPropType m_Type; +}; + + +// This can be used to set the # of bits used to transmit a number between 0 and nMaxElements-1. +inline int NumBitsForCount( int nMaxElements ) +{ + int nBits = 0; + while ( nMaxElements > 0 ) + { + ++nBits; + nMaxElements >>= 1; + } + return nBits; +} + + +#endif // DATATABLE_COMMON_H diff --git a/public/dt_recv.cpp b/public/dt_recv.cpp new file mode 100644 index 0000000..8411b1d --- /dev/null +++ b/public/dt_recv.cpp @@ -0,0 +1,534 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "dt_recv.h" +#include "mathlib/vector.h" +#include "tier1/strtools.h" +#include "dt_utlvector_common.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if !defined(_STATIC_LINKED) || defined(CLIENT_DLL) + +const char *s_ClientElementNames[MAX_ARRAY_ELEMENTS] = +{ + "000", "001", "002", "003", "004", "005", "006", "007", "008", "009", + "010", "011", "012", "013", "014", "015", "016", "017", "018", "019", + "020", "021", "022", "023", "024", "025", "026", "027", "028", "029", + "030", "031", "032", "033", "034", "035", "036", "037", "038", "039", + "040", "041", "042", "043", "044", "045", "046", "047", "048", "049", + "050", "051", "052", "053", "054", "055", "056", "057", "058", "059", + "060", "061", "062", "063", "064", "065", "066", "067", "068", "069", + "070", "071", "072", "073", "074", "075", "076", "077", "078", "079", + "080", "081", "082", "083", "084", "085", "086", "087", "088", "089", + "090", "091", "092", "093", "094", "095", "096", "097", "098", "099", + "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", + "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", + "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", + "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", + "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", + "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", + "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", + "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", + "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", + "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", + "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", + "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", + "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", + "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", + "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", + "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", + "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", + "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", + "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", + "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", + "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", + "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", + "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", + "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", + "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", + "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", + "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", + "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", + "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", + "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", + "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", + "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", + "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", + "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", + "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", + "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", + "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", + "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", + "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", + "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", + "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", + "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", + "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", + "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", + "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", + "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", + "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", + "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", + "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", + "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", + "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", + "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", + "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", + "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", + "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", + "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", + "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", + "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", + "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", + "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", + "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", + "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", + "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", + "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", + "750", "751", "752", "753", "754", "755", "756", "757", "758", "759", + "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", + "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", + "780", "781", "782", "783", "784", "785", "786", "787", "788", "789", + "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", + "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", + "810", "811", "812", "813", "814", "815", "816", "817", "818", "819", + "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", + "830", "831", "832", "833", "834", "835", "836", "837", "838", "839", + "840", "841", "842", "843", "844", "845", "846", "847", "848", "849", + "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", + "860", "861", "862", "863", "864", "865", "866", "867", "868", "869", + "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", + "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", + "890", "891", "892", "893", "894", "895", "896", "897", "898", "899", + "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", + "910", "911", "912", "913", "914", "915", "916", "917", "918", "919", + "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", + "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", + "940", "941", "942", "943", "944", "945", "946", "947", "948", "949", + "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", + "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", + "970", "971", "972", "973", "974", "975", "976", "977", "978", "979", + "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", + "990", "991", "992", "993", "994", "995", "996", "997", "998", "999", + "1000", "1001", "1002", "1003", "1004", "1005", "1006", "1007", "1008", "1009", + "1010", "1011", "1012", "1013", "1014", "1015", "1016", "1017", "1018", "1019", + "1020", "1021", "1022", "1023" + +}; + +CStandardRecvProxies::CStandardRecvProxies() +{ + m_Int32ToInt8 = RecvProxy_Int32ToInt8; + m_Int32ToInt16 = RecvProxy_Int32ToInt16; + m_Int32ToInt32 = RecvProxy_Int32ToInt32; +#ifdef SUPPORTS_INT64 + m_Int64ToInt64 = RecvProxy_Int64ToInt64; +#endif + m_FloatToFloat = RecvProxy_FloatToFloat; + m_VectorToVector = RecvProxy_VectorToVector; +} + +CStandardRecvProxies g_StandardRecvProxies; + + +// ---------------------------------------------------------------------- // +// RecvProp. +// ---------------------------------------------------------------------- // +RecvProp::RecvProp() +{ + m_pExtraData = NULL; + m_pVarName = NULL; + m_Offset = 0; + m_RecvType = DPT_Int; + m_Flags = 0; + m_ProxyFn = NULL; + m_DataTableProxyFn = NULL; + m_pDataTable = NULL; + m_nElements = 1; + m_ElementStride = -1; + m_pArrayProp = NULL; + m_ArrayLengthProxy = NULL; + m_bInsideArray = false; +} + +// ---------------------------------------------------------------------- // +// RecvTable. +// ---------------------------------------------------------------------- // +RecvTable::RecvTable() +{ + Construct( NULL, 0, NULL ); +} + +RecvTable::RecvTable(RecvProp *pProps, int nProps, const char *pNetTableName) +{ + Construct( pProps, nProps, pNetTableName ); +} + +RecvTable::~RecvTable() +{ +} + +void RecvTable::Construct( RecvProp *pProps, int nProps, const char *pNetTableName ) +{ + m_pProps = pProps; + m_nProps = nProps; + m_pDecoder = NULL; + m_pNetTableName = pNetTableName; + m_bInitialized = false; + m_bInMainList = false; +} + + +// ---------------------------------------------------------------------- // +// Prop setup functions (for building tables). +// ---------------------------------------------------------------------- // + +RecvProp RecvPropFloat( + const char *pVarName, + int offset, + int sizeofVar, + int flags, + RecvVarProxyFn varProxy + ) +{ + RecvProp ret; + +#ifdef _DEBUG + if ( varProxy == RecvProxy_FloatToFloat ) + { + Assert( sizeofVar == 0 || sizeofVar == 4 ); + } +#endif + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_Float; + ret.m_Flags = flags; + ret.SetProxyFn( varProxy ); + + return ret; +} + +RecvProp RecvPropVector( + const char *pVarName, + int offset, + int sizeofVar, + int flags, + RecvVarProxyFn varProxy + ) +{ + RecvProp ret; + +#ifdef _DEBUG + if ( varProxy == RecvProxy_VectorToVector ) + { + Assert( sizeofVar == sizeof( Vector ) ); + } +#endif + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_Vector; + ret.m_Flags = flags; + ret.SetProxyFn( varProxy ); + + return ret; +} + +RecvProp RecvPropVectorXY( + const char *pVarName, + int offset, + int sizeofVar, + int flags, + RecvVarProxyFn varProxy + ) +{ + RecvProp ret; + +#ifdef _DEBUG + if ( varProxy == RecvProxy_VectorToVector ) + { + Assert( sizeofVar == sizeof( Vector ) ); + } +#endif + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_VectorXY; + ret.m_Flags = flags; + ret.SetProxyFn( varProxy ); + + return ret; +} + +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! + +RecvProp RecvPropQuaternion( + const char *pVarName, + int offset, + int sizeofVar, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother. + int flags, + RecvVarProxyFn varProxy + ) +{ + RecvProp ret; + +#ifdef _DEBUG + if ( varProxy == RecvProxy_QuaternionToQuaternion ) + { + Assert( sizeofVar == sizeof( Quaternion ) ); + } +#endif + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_Quaternion; + ret.m_Flags = flags; + ret.SetProxyFn( varProxy ); + + return ret; +} +#endif + +RecvProp RecvPropInt( + const char *pVarName, + int offset, + int sizeofVar, + int flags, + RecvVarProxyFn varProxy + ) +{ + RecvProp ret; + + // If they didn't specify a proxy, then figure out what type we're writing to. + if (varProxy == NULL) + { + if (sizeofVar == 1) + { + varProxy = RecvProxy_Int32ToInt8; + } + else if (sizeofVar == 2) + { + varProxy = RecvProxy_Int32ToInt16; + } + else if (sizeofVar == 4) + { + varProxy = RecvProxy_Int32ToInt32; + } +#ifdef SUPPORTS_INT64 + else if (sizeofVar == 8) + { + varProxy = RecvProxy_Int64ToInt64; + } +#endif + else + { + Assert(!"RecvPropInt var has invalid size"); + varProxy = RecvProxy_Int32ToInt8; // safest one... + } + } + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); +#ifdef SUPPORTS_INT64 + ret.m_RecvType = (sizeofVar == 8) ? DPT_Int64 : DPT_Int; +#else + ret.m_RecvType = DPT_Int; +#endif + ret.m_Flags = flags; + ret.SetProxyFn( varProxy ); + + return ret; +} + +RecvProp RecvPropString( + const char *pVarName, + int offset, + int bufferSize, + int flags, + RecvVarProxyFn varProxy + ) +{ + RecvProp ret; + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_String; + ret.m_Flags = flags; + ret.m_StringBufferSize = bufferSize; + ret.SetProxyFn( varProxy ); + + return ret; +} + +RecvProp RecvPropDataTable( + const char *pVarName, + int offset, + int flags, + RecvTable *pTable, + DataTableRecvVarProxyFn varProxy + ) +{ + RecvProp ret; + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_DataTable; + ret.m_Flags = flags; + ret.SetDataTableProxyFn( varProxy ); + ret.SetDataTable( pTable ); + + return ret; +} + +RecvProp RecvPropArray3( + const char *pVarName, + int offset, + int sizeofVar, + int elements, + RecvProp pArrayProp, + DataTableRecvVarProxyFn varProxy + ) +{ + RecvProp ret; + + Assert( elements <= MAX_ARRAY_ELEMENTS ); + + ret.m_pVarName = pVarName; + ret.SetOffset( offset ); + ret.m_RecvType = DPT_DataTable; + ret.SetDataTableProxyFn( varProxy ); + + RecvProp *pProps = new RecvProp[elements]; // TODO free that again + + const char *pParentArrayPropName = AllocateStringHelper( "%s", pVarName ); + + for ( int i=0; i < elements; i++ ) + { + pProps[i] = pArrayProp; // copy basic property settings + pProps[i].SetOffset( i * sizeofVar ); // adjust offset + pProps[i].m_pVarName = s_ClientElementNames[i]; // give unique name + pProps[i].SetParentArrayPropName( pParentArrayPropName ); // For debugging... + } + + RecvTable *pTable = new RecvTable( pProps, elements, pVarName ); // TODO free that again + + ret.SetDataTable( pTable ); + + return ret; +} + +RecvProp InternalRecvPropArray( + const int elementCount, + const int elementStride, + const char *pName, + ArrayLengthRecvProxyFn proxy + ) +{ + RecvProp ret; + + ret.InitArray( elementCount, elementStride ); + ret.m_pVarName = pName; + ret.SetArrayLengthProxy( proxy ); + + return ret; +} + + +// ---------------------------------------------------------------------- // +// Proxies. +// ---------------------------------------------------------------------- // + +void RecvProxy_FloatToFloat( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + Assert( IsFinite( pData->m_Value.m_Float ) ); + *((float*)pOut) = pData->m_Value.m_Float; +} + +void RecvProxy_VectorToVector( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + const float *v = pData->m_Value.m_Vector; + + Assert( IsFinite( v[0] ) && IsFinite( v[1] ) && IsFinite( v[2] ) ); + ((float*)pOut)[0] = v[0]; + ((float*)pOut)[1] = v[1]; + ((float*)pOut)[2] = v[2]; +} + +void RecvProxy_VectorXYToVectorXY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + const float *v = pData->m_Value.m_Vector; + + Assert( IsFinite( v[0] ) && IsFinite( v[1] ) ); + ((float*)pOut)[0] = v[0]; + ((float*)pOut)[1] = v[1]; +} + +void RecvProxy_QuaternionToQuaternion( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + const float *v = pData->m_Value.m_Vector; + + Assert( IsFinite( v[0] ) && IsFinite( v[1] ) && IsFinite( v[2] ) && IsFinite( v[3] ) ); + ((float*)pOut)[0] = v[0]; + ((float*)pOut)[1] = v[1]; + ((float*)pOut)[2] = v[2]; + ((float*)pOut)[3] = v[3]; +} + +void RecvProxy_Int32ToInt8( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + *((unsigned char*)pOut) = (unsigned char)pData->m_Value.m_Int; +} + +void RecvProxy_Int32ToInt16( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + *((unsigned short*)pOut) = (unsigned short)pData->m_Value.m_Int; +} + +void RecvProxy_Int32ToInt32( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + *((unsigned long*)pOut) = (unsigned long)pData->m_Value.m_Int; +} + +#ifdef SUPPORTS_INT64 +void RecvProxy_Int64ToInt64( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + *((int64*)pOut) = (int64)pData->m_Value.m_Int64; +} +#endif + +void RecvProxy_StringToString( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + char *pStrOut = (char*)pOut; + if ( pData->m_pRecvProp->m_StringBufferSize <= 0 ) + { + return; + } + + for ( int i=0; i < pData->m_pRecvProp->m_StringBufferSize; i++ ) + { + pStrOut[i] = pData->m_Value.m_pString[i]; + if ( pStrOut[i] == 0 ) + break; + } + + pStrOut[pData->m_pRecvProp->m_StringBufferSize-1] = 0; +} + +void DataTableRecvProxy_StaticDataTable( const RecvProp *pProp, void **pOut, void *pData, int objectID ) +{ + *pOut = pData; +} + +void DataTableRecvProxy_PointerDataTable( const RecvProp *pProp, void **pOut, void *pData, int objectID ) +{ + *pOut = *((void**)pData); +} + +#endif diff --git a/public/dt_recv.h b/public/dt_recv.h new file mode 100644 index 0000000..883b8f7 --- /dev/null +++ b/public/dt_recv.h @@ -0,0 +1,573 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef DATATABLE_RECV_H +#define DATATABLE_RECV_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dt_common.h" +#include "tier0/dbg.h" + + +#define ADDRESSPROXY_NONE -1 + + +class RecvTable; +class RecvProp; + + +// This is passed into RecvProxy functions. +class CRecvProxyData +{ +public: + const RecvProp *m_pRecvProp; // The property it's receiving. + + DVariant m_Value; // The value given to you to store. + + int m_iElement; // Which array element you're getting. + + int m_ObjectID; // The object being referred to. +}; + + +//----------------------------------------------------------------------------- +// pStruct = the base structure of the datatable this variable is in (like C_BaseEntity) +// pOut = the variable that this this proxy represents (like C_BaseEntity::m_SomeValue). +// +// Convert the network-standard-type value in m_Value into your own format in pStruct/pOut. +//----------------------------------------------------------------------------- +typedef void (*RecvVarProxyFn)( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +// ------------------------------------------------------------------------ // +// ArrayLengthRecvProxies are optionally used to get the length of the +// incoming array when it changes. +// ------------------------------------------------------------------------ // +typedef void (*ArrayLengthRecvProxyFn)( void *pStruct, int objectID, int currentArrayLength ); + + +// NOTE: DataTable receive proxies work differently than the other proxies. +// pData points at the object + the recv table's offset. +// pOut should be set to the location of the object to unpack the data table into. +// If the parent object just contains the child object, the default proxy just does *pOut = pData. +// If the parent object points at the child object, you need to dereference the pointer here. +// NOTE: don't ever return null from a DataTable receive proxy function. Bad things will happen. +typedef void (*DataTableRecvVarProxyFn)(const RecvProp *pProp, void **pOut, void *pData, int objectID); + + +// This is used to fork over the standard proxy functions to the engine so it can +// make some optimizations. +class CStandardRecvProxies +{ +public: + CStandardRecvProxies(); + + RecvVarProxyFn m_Int32ToInt8; + RecvVarProxyFn m_Int32ToInt16; + RecvVarProxyFn m_Int32ToInt32; + RecvVarProxyFn m_FloatToFloat; + RecvVarProxyFn m_VectorToVector; +#ifdef SUPPORTS_INT64 + RecvVarProxyFn m_Int64ToInt64; +#endif +}; +extern CStandardRecvProxies g_StandardRecvProxies; + + +class CRecvDecoder; + + +class RecvProp +{ +// This info comes from the receive data table. +public: + RecvProp(); + + void InitArray( int nElements, int elementStride ); + + int GetNumElements() const; + void SetNumElements( int nElements ); + + int GetElementStride() const; + void SetElementStride( int stride ); + + int GetFlags() const; + + const char* GetName() const; + SendPropType GetType() const; + + RecvTable* GetDataTable() const; + void SetDataTable( RecvTable *pTable ); + + RecvVarProxyFn GetProxyFn() const; + void SetProxyFn( RecvVarProxyFn fn ); + + DataTableRecvVarProxyFn GetDataTableProxyFn() const; + void SetDataTableProxyFn( DataTableRecvVarProxyFn fn ); + + int GetOffset() const; + void SetOffset( int o ); + + // Arrays only. + RecvProp* GetArrayProp() const; + void SetArrayProp( RecvProp *pProp ); + + // Arrays only. + void SetArrayLengthProxy( ArrayLengthRecvProxyFn proxy ); + ArrayLengthRecvProxyFn GetArrayLengthProxy() const; + + bool IsInsideArray() const; + void SetInsideArray(); + + // Some property types bind more data to the prop in here. + const void* GetExtraData() const; + void SetExtraData( const void *pData ); + + // If it's one of the numbered "000", "001", etc properties in an array, then + // these can be used to get its array property name for debugging. + const char* GetParentArrayPropName(); + void SetParentArrayPropName( const char *pArrayPropName ); + +public: + + const char *m_pVarName; + SendPropType m_RecvType; + int m_Flags; + int m_StringBufferSize; + + +private: + + bool m_bInsideArray; // Set to true by the engine if this property sits inside an array. + + // Extra data that certain special property types bind to the property here. + const void *m_pExtraData; + + // If this is an array (DPT_Array). + RecvProp *m_pArrayProp; + ArrayLengthRecvProxyFn m_ArrayLengthProxy; + + RecvVarProxyFn m_ProxyFn; + DataTableRecvVarProxyFn m_DataTableProxyFn; // For RDT_DataTable. + + RecvTable *m_pDataTable; // For RDT_DataTable. + int m_Offset; + + int m_ElementStride; + int m_nElements; + + // If it's one of the numbered "000", "001", etc properties in an array, then + // these can be used to get its array property name for debugging. + const char *m_pParentArrayPropName; +}; + + +class RecvTable +{ +public: + + typedef RecvProp PropType; + + RecvTable(); + RecvTable( RecvProp *pProps, int nProps, const char *pNetTableName ); + ~RecvTable(); + + void Construct( RecvProp *pProps, int nProps, const char *pNetTableName ); + + int GetNumProps(); + RecvProp* GetProp( int i ); + + const char* GetName(); + + // Used by the engine while initializing array props. + void SetInitialized( bool bInitialized ); + bool IsInitialized() const; + + // Used by the engine. + void SetInMainList( bool bInList ); + bool IsInMainList() const; + + +public: + + // Properties described in a table. + RecvProp *m_pProps; + int m_nProps; + + // The decoder. NOTE: this covers each RecvTable AND all its children (ie: its children + // will have their own decoders that include props for all their children). + CRecvDecoder *m_pDecoder; + + const char *m_pNetTableName; // The name matched between client and server. + + +private: + + bool m_bInitialized; + bool m_bInMainList; +}; + + +inline int RecvTable::GetNumProps() +{ + return m_nProps; +} + +inline RecvProp* RecvTable::GetProp( int i ) +{ + Assert( i >= 0 && i < m_nProps ); + return &m_pProps[i]; +} + +inline const char* RecvTable::GetName() +{ + return m_pNetTableName; +} + +inline void RecvTable::SetInitialized( bool bInitialized ) +{ + m_bInitialized = bInitialized; +} + +inline bool RecvTable::IsInitialized() const +{ + return m_bInitialized; +} + +inline void RecvTable::SetInMainList( bool bInList ) +{ + m_bInMainList = bInList; +} + +inline bool RecvTable::IsInMainList() const +{ + return m_bInMainList; +} + + +// ------------------------------------------------------------------------------------------------------ // +// See notes on BEGIN_SEND_TABLE for a description. These macros work similarly. +// ------------------------------------------------------------------------------------------------------ // +#define BEGIN_RECV_TABLE(className, tableName) \ + BEGIN_RECV_TABLE_NOBASE(className, tableName) \ + RecvPropDataTable("baseclass", 0, 0, className::BaseClass::m_pClassRecvTable, DataTableRecvProxy_StaticDataTable), + +#define BEGIN_RECV_TABLE_NOBASE(className, tableName) \ + template int ClientClassInit(T *); \ + namespace tableName { \ + struct ignored; \ + } \ + template <> int ClientClassInit(tableName::ignored *); \ + namespace tableName { \ + RecvTable g_RecvTable; \ + int g_RecvTableInit = ClientClassInit((tableName::ignored *)NULL); \ + } \ + template <> int ClientClassInit(tableName::ignored *) \ + { \ + typedef className currentRecvDTClass; \ + const char *pRecvTableName = #tableName; \ + RecvTable &RecvTable = tableName::g_RecvTable; \ + static RecvProp RecvProps[] = { \ + RecvPropInt("should_never_see_this", 0, sizeof(int)), // It adds a dummy property at the start so you can define "empty" SendTables. + +#define END_RECV_TABLE() \ + }; \ + RecvTable.Construct(RecvProps+1, sizeof(RecvProps) / sizeof(RecvProp) - 1, pRecvTableName); \ + return 1; \ + } + + +#define RECVINFO(varName) #varName, offsetof(currentRecvDTClass, varName), sizeof(((currentRecvDTClass*)0)->varName) +#define RECVINFO_NAME(varName, remoteVarName) #remoteVarName, offsetof(currentRecvDTClass, varName), sizeof(((currentRecvDTClass*)0)->varName) +#define RECVINFO_STRING(varName) #varName, offsetof(currentRecvDTClass, varName), STRINGBUFSIZE(currentRecvDTClass, varName) +#define RECVINFO_BASECLASS(tableName) RecvPropDataTable("this", 0, 0, &REFERENCE_RECV_TABLE(tableName)) +#define RECVINFO_ARRAY(varName) #varName, offsetof(currentRecvDTClass, varName), sizeof(((currentRecvDTClass*)0)->varName[0]), sizeof(((currentRecvDTClass*)0)->varName)/sizeof(((currentRecvDTClass*)0)->varName[0]) + +// Just specify the name and offset. Used for strings and data tables. +#define RECVINFO_NOSIZE(varName) #varName, offsetof(currentRecvDTClass, varName) +#define RECVINFO_DT(varName) RECVINFO_NOSIZE(varName) +#define RECVINFO_DTNAME(varName,remoteVarName) #remoteVarName, offsetof(currentRecvDTClass, varName) + + +void RecvProxy_FloatToFloat ( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_VectorToVector( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_VectorXYToVectorXY( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_QuaternionToQuaternion( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_Int32ToInt8 ( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_Int32ToInt16 ( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_StringToString( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_Int32ToInt32 ( const CRecvProxyData *pData, void *pStruct, void *pOut ); +#ifdef SUPPORTS_INT64 +void RecvProxy_Int64ToInt64 ( const CRecvProxyData *pData, void *pStruct, void *pOut ); +#endif + +// StaticDataTable does *pOut = pData. +void DataTableRecvProxy_StaticDataTable(const RecvProp *pProp, void **pOut, void *pData, int objectID); + +// PointerDataTable does *pOut = *((void**)pData) (ie: pData is a pointer to the object to decode into). +void DataTableRecvProxy_PointerDataTable(const RecvProp *pProp, void **pOut, void *pData, int objectID); + + +RecvProp RecvPropFloat( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother. + int flags=0, + RecvVarProxyFn varProxy=RecvProxy_FloatToFloat + ); + +RecvProp RecvPropVector( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother. + int flags=0, + RecvVarProxyFn varProxy=RecvProxy_VectorToVector + ); + +RecvProp RecvPropVectorXY( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother. + int flags=0, + RecvVarProxyFn varProxy=RecvProxy_VectorXYToVectorXY + ); + +// This is here so the RecvTable can look more like the SendTable. +#define RecvPropQAngles RecvPropVector + +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! + +RecvProp RecvPropQuaternion( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother. + int flags=0, + RecvVarProxyFn varProxy=RecvProxy_QuaternionToQuaternion + ); +#endif + +RecvProp RecvPropInt( + const char *pVarName, + int offset, + int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother. + int flags=0, + RecvVarProxyFn varProxy=0 + ); + +RecvProp RecvPropString( + const char *pVarName, + int offset, + int bufferSize, + int flags=0, + RecvVarProxyFn varProxy=RecvProxy_StringToString + ); + +RecvProp RecvPropDataTable( + const char *pVarName, + int offset, + int flags, + RecvTable *pTable, + DataTableRecvVarProxyFn varProxy=DataTableRecvProxy_StaticDataTable + ); + +RecvProp RecvPropArray3( + const char *pVarName, + int offset, + int sizeofVar, + int elements, + RecvProp pArrayProp, + DataTableRecvVarProxyFn varProxy=DataTableRecvProxy_StaticDataTable + ); + +// Use the macro to let it automatically generate a table name. You shouldn't +// ever need to reference the table name. If you want to exclude this array, then +// reference the name of the variable in varTemplate. +RecvProp InternalRecvPropArray( + const int elementCount, + const int elementStride, + const char *pName, + ArrayLengthRecvProxyFn proxy + ); + + +// +// Use this if you want to completely manage the way the array data is stored. +// You'll need to provide a proxy inside varTemplate that looks for 'iElement' +// to figure out where to store the specified element. +// +#define RecvPropVirtualArray( arrayLengthProxy, maxArrayLength, varTemplate, propertyName ) \ + varTemplate, \ + InternalRecvPropArray( \ + maxArrayLength, \ + 0, \ + #propertyName, \ + arrayLengthProxy \ + ) + + +// Use this and pass the array name and it will figure out the count and stride automatically. +#define RecvPropVariableLengthArray( arrayLengthProxy, varTemplate, arrayName ) \ + varTemplate, \ + InternalRecvPropArray( \ + sizeof(((currentRecvDTClass*)0)->arrayName) / PROPSIZEOF(currentRecvDTClass, arrayName[0]), \ + PROPSIZEOF(currentRecvDTClass, arrayName[0]), \ + #arrayName, \ + arrayLengthProxy \ + ) + + +// Use this and pass the array name and it will figure out the count and stride automatically. +#define RecvPropArray( varTemplate, arrayName ) \ + RecvPropVariableLengthArray( 0, varTemplate, arrayName ) + + +// Use this one to specify the element count and stride manually. +#define RecvPropArray2( arrayLengthProxy, varTemplate, elementCount, elementStride, arrayName ) \ + varTemplate, \ + InternalRecvPropArray( elementCount, elementStride, #arrayName, arrayLengthProxy ) + + +// ---------------------------------------------------------------------------------------- // +// Inlines. +// ---------------------------------------------------------------------------------------- // + +inline void RecvProp::InitArray( int nElements, int elementStride ) +{ + m_RecvType = DPT_Array; + m_nElements = nElements; + m_ElementStride = elementStride; +} + +inline int RecvProp::GetNumElements() const +{ + return m_nElements; +} + +inline void RecvProp::SetNumElements( int nElements ) +{ + m_nElements = nElements; +} + +inline int RecvProp::GetElementStride() const +{ + return m_ElementStride; +} + +inline void RecvProp::SetElementStride( int stride ) +{ + m_ElementStride = stride; +} + +inline int RecvProp::GetFlags() const +{ + return m_Flags; +} + +inline const char* RecvProp::GetName() const +{ + return m_pVarName; +} + +inline SendPropType RecvProp::GetType() const +{ + return m_RecvType; +} + +inline RecvTable* RecvProp::GetDataTable() const +{ + return m_pDataTable; +} + +inline void RecvProp::SetDataTable( RecvTable *pTable ) +{ + m_pDataTable = pTable; +} + +inline RecvVarProxyFn RecvProp::GetProxyFn() const +{ + return m_ProxyFn; +} + +inline void RecvProp::SetProxyFn( RecvVarProxyFn fn ) +{ + m_ProxyFn = fn; +} + +inline DataTableRecvVarProxyFn RecvProp::GetDataTableProxyFn() const +{ + return m_DataTableProxyFn; +} + +inline void RecvProp::SetDataTableProxyFn( DataTableRecvVarProxyFn fn ) +{ + m_DataTableProxyFn = fn; +} + +inline int RecvProp::GetOffset() const +{ + return m_Offset; +} + +inline void RecvProp::SetOffset( int o ) +{ + m_Offset = o; +} + +inline RecvProp* RecvProp::GetArrayProp() const +{ + return m_pArrayProp; +} + +inline void RecvProp::SetArrayProp( RecvProp *pProp ) +{ + m_pArrayProp = pProp; +} + +inline void RecvProp::SetArrayLengthProxy( ArrayLengthRecvProxyFn proxy ) +{ + m_ArrayLengthProxy = proxy; +} + +inline ArrayLengthRecvProxyFn RecvProp::GetArrayLengthProxy() const +{ + return m_ArrayLengthProxy; +} + +inline bool RecvProp::IsInsideArray() const +{ + return m_bInsideArray; +} + +inline void RecvProp::SetInsideArray() +{ + m_bInsideArray = true; +} + +inline const void* RecvProp::GetExtraData() const +{ + return m_pExtraData; +} + +inline void RecvProp::SetExtraData( const void *pData ) +{ + m_pExtraData = pData; +} + +inline const char* RecvProp::GetParentArrayPropName() +{ + return m_pParentArrayPropName; +} + +inline void RecvProp::SetParentArrayPropName( const char *pArrayPropName ) +{ + m_pParentArrayPropName = pArrayPropName; +} + +#endif // DATATABLE_RECV_H diff --git a/public/dt_send.cpp b/public/dt_send.cpp new file mode 100644 index 0000000..caad419 --- /dev/null +++ b/public/dt_send.cpp @@ -0,0 +1,881 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + + +#include "dt_send.h" +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "tier0/dbg.h" +#include "dt_utlvector_common.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if !defined(_STATIC_LINKED) || defined(GAME_DLL) + + +static CNonModifiedPointerProxy *s_pNonModifiedPointerProxyHead = NULL; + + +void SendProxy_UInt8ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID); +void SendProxy_UInt16ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID); +void SendProxy_UInt32ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID); +#ifdef SUPPORTS_INT64 +void SendProxy_UInt64ToInt64( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID); +#endif +const char *s_ElementNames[MAX_ARRAY_ELEMENTS] = +{ + "000", "001", "002", "003", "004", "005", "006", "007", "008", "009", + "010", "011", "012", "013", "014", "015", "016", "017", "018", "019", + "020", "021", "022", "023", "024", "025", "026", "027", "028", "029", + "030", "031", "032", "033", "034", "035", "036", "037", "038", "039", + "040", "041", "042", "043", "044", "045", "046", "047", "048", "049", + "050", "051", "052", "053", "054", "055", "056", "057", "058", "059", + "060", "061", "062", "063", "064", "065", "066", "067", "068", "069", + "070", "071", "072", "073", "074", "075", "076", "077", "078", "079", + "080", "081", "082", "083", "084", "085", "086", "087", "088", "089", + "090", "091", "092", "093", "094", "095", "096", "097", "098", "099", + "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", + "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", + "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", + "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", + "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", + "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", + "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", + "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", + "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", + "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", + "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", + "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", + "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", + "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", + "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", + "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", + "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", + "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", + "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", + "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", + "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", + "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", + "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", + "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", + "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", + "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", + "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", + "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", + "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", + "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", + "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", + "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", + "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", + "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", + "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", + "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", + "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", + "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", + "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", + "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", + "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", + "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", + "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", + "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", + "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", + "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", + "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", + "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", + "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", + "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", + "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", + "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", + "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", + "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", + "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", + "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", + "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", + "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", + "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", + "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", + "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", + "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", + "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", + "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", + "750", "751", "752", "753", "754", "755", "756", "757", "758", "759", + "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", + "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", + "780", "781", "782", "783", "784", "785", "786", "787", "788", "789", + "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", + "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", + "810", "811", "812", "813", "814", "815", "816", "817", "818", "819", + "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", + "830", "831", "832", "833", "834", "835", "836", "837", "838", "839", + "840", "841", "842", "843", "844", "845", "846", "847", "848", "849", + "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", + "860", "861", "862", "863", "864", "865", "866", "867", "868", "869", + "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", + "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", + "890", "891", "892", "893", "894", "895", "896", "897", "898", "899", + "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", + "910", "911", "912", "913", "914", "915", "916", "917", "918", "919", + "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", + "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", + "940", "941", "942", "943", "944", "945", "946", "947", "948", "949", + "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", + "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", + "970", "971", "972", "973", "974", "975", "976", "977", "978", "979", + "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", + "990", "991", "992", "993", "994", "995", "996", "997", "998", "999", + "1000", "1001", "1002", "1003", "1004", "1005", "1006", "1007", "1008", "1009", + "1010", "1011", "1012", "1013", "1014", "1015", "1016", "1017", "1018", "1019", + "1020", "1021", "1022", "1023" + +}; + + +CNonModifiedPointerProxy::CNonModifiedPointerProxy( SendTableProxyFn fn ) +{ + m_pNext = s_pNonModifiedPointerProxyHead; + s_pNonModifiedPointerProxyHead = this; + m_Fn = fn; +} + + +CStandardSendProxiesV1::CStandardSendProxiesV1() +{ + m_Int8ToInt32 = SendProxy_Int8ToInt32; + m_Int16ToInt32 = SendProxy_Int16ToInt32; + m_Int32ToInt32 = SendProxy_Int32ToInt32; +#ifdef SUPPORTS_INT64 + m_Int64ToInt64 = SendProxy_Int64ToInt64; +#endif + + m_UInt8ToInt32 = SendProxy_UInt8ToInt32; + m_UInt16ToInt32 = SendProxy_UInt16ToInt32; + m_UInt32ToInt32 = SendProxy_UInt32ToInt32; +#ifdef SUPPORTS_INT64 + m_UInt64ToInt64 = SendProxy_UInt64ToInt64; +#endif + + m_FloatToFloat = SendProxy_FloatToFloat; + m_VectorToVector = SendProxy_VectorToVector; +} + +CStandardSendProxies::CStandardSendProxies() +{ + m_DataTableToDataTable = SendProxy_DataTableToDataTable; + m_SendLocalDataTable = SendProxy_SendLocalDataTable; + m_ppNonModifiedPointerProxies = &s_pNonModifiedPointerProxyHead; + +} +CStandardSendProxies g_StandardSendProxies; + + +// ---------------------------------------------------------------------- // +// Proxies. +// ---------------------------------------------------------------------- // +void SendProxy_AngleToFloat( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + float angle; + + angle = *((float*)pData); + pOut->m_Float = anglemod( angle ); + + Assert( IsFinite( pOut->m_Float ) ); +} + +void SendProxy_FloatToFloat( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Float = *((float*)pData); + Assert( IsFinite( pOut->m_Float ) ); +} + +void SendProxy_QAngles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ) +{ + QAngle *v = (QAngle*)pData; + pOut->m_Vector[0] = anglemod( v->x ); + pOut->m_Vector[1] = anglemod( v->y ); + pOut->m_Vector[2] = anglemod( v->z ); +} + +void SendProxy_VectorToVector( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + Vector& v = *(Vector*)pData; + Assert( v.IsValid() ); + pOut->m_Vector[0] = v[0]; + pOut->m_Vector[1] = v[1]; + pOut->m_Vector[2] = v[2]; +} + +void SendProxy_VectorXYToVectorXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + Vector& v = *(Vector*)pData; + Assert( v.IsValid() ); + pOut->m_Vector[0] = v[0]; + pOut->m_Vector[1] = v[1]; +} + +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! +void SendProxy_QuaternionToQuaternion( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + Quaternion& q = *(Quaternion*)pData; + Assert( q.IsValid() ); + pOut->m_Vector[0] = q[0]; + pOut->m_Vector[1] = q[1]; + pOut->m_Vector[2] = q[2]; + pOut->m_Vector[3] = q[3]; +} +#endif + +void SendProxy_Int8ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Int = *((const char*)pData); +} + +void SendProxy_Int16ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Int = *((short*)pData); +} + +void SendProxy_Int32ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Int = *((int*)pData); +} + +#ifdef SUPPORTS_INT64 +void SendProxy_Int64ToInt64( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Int64 = *((int64*)pData); +} +#endif + +void SendProxy_UInt8ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Int = *((const unsigned char*)pData); +} + +void SendProxy_UInt16ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_Int = *((unsigned short*)pData); +} + +void SendProxy_UInt32ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + *((unsigned long*)&pOut->m_Int) = *((unsigned long*)pData); +} +#ifdef SUPPORTS_INT64 +void SendProxy_UInt64ToInt64( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + *((int64*)&pOut->m_Int64) = *((uint64*)pData); +} +#endif + +void SendProxy_StringToString( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ + pOut->m_pString = (const char*)pData; +} + +void* SendProxy_DataTableToDataTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ) +{ + return (void*)pData; +} + +void* SendProxy_DataTablePtrToDataTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ) +{ + return *((void**)pData); +} + +static void SendProxy_Empty( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: If the recipient is the same as objectID, go ahead and iterate down +// the m_Local stuff, otherwise, act like it wasn't there at all. +// This way, only the local player receives information about him/herself. +// Input : *pVarData - +// *pOut - +// objectID - +//----------------------------------------------------------------------------- + +void* SendProxy_SendLocalDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID ) +{ + pRecipients->SetOnly( objectID - 1 ); + return ( void * )pVarData; +} + + + + + +// ---------------------------------------------------------------------- // +// Prop setup functions (for building tables). +// ---------------------------------------------------------------------- // +float AssignRangeMultiplier( int nBits, double range ) +{ + unsigned long iHighValue; + if ( nBits == 32 ) + iHighValue = 0xFFFFFFFE; + else + iHighValue = ((1 << (unsigned long)nBits) - 1); + + float fHighLowMul = iHighValue / range; + if ( CloseEnough( range, 0 ) ) + fHighLowMul = iHighValue; + + // If the precision is messing us up, then adjust it so it won't. + if ( (unsigned long)(fHighLowMul * range) > iHighValue || + (fHighLowMul * range) > (double)iHighValue ) + { + // Squeeze it down smaller and smaller until it's going to produce an integer + // in the valid range when given the highest value. + float multipliers[] = { 0.9999, 0.99, 0.9, 0.8, 0.7 }; + int i; + for ( i=0; i < ARRAYSIZE( multipliers ); i++ ) + { + fHighLowMul = (float)( iHighValue / range ) * multipliers[i]; + if ( (unsigned long)(fHighLowMul * range) > iHighValue || + (fHighLowMul * range) > (double)iHighValue ) + { + } + else + { + break; + } + } + + if ( i == ARRAYSIZE( multipliers ) ) + { + // Doh! We seem to be unable to represent this range. + Assert( false ); + return 0; + } + } + + return fHighLowMul; +} + + + +SendProp SendPropFloat( + const char *pVarName, + // Variable name. + int offset, // Offset into container structure. + int sizeofVar, + int nBits, // Number of bits to use when encoding. + int flags, + float fLowValue, // For floating point, low and high values. + float fHighValue, // High value. If HIGH_DEFAULT, it's (1<m_Int = atoi(pUserStr); + +// pProp : the SendProp that has the proxy +// pStructBase : the base structure (like CBaseEntity*). +// pData : the address of the variable to proxy. +// pOut : where to output the proxied value. +// iElement : the element index if this data is part of an array (or 0 if not). +// objectID : entity index for debugging purposes. + +// Return false if you don't want the engine to register and send a delta to +// the clients for this property (regardless of whether it actually changed or not). +// ------------------------------------------------------------------------ // +typedef void (*SendVarProxyFn)( const SendProp *pProp, const void *pStructBase, const void *pData, DVariant *pOut, int iElement, int objectID ); + +// Return the pointer to the data for the datatable. +// If the proxy returns null, it's the same as if pRecipients->ClearAllRecipients() was called. +class CSendProxyRecipients; + +typedef void* (*SendTableProxyFn)( + const SendProp *pProp, + const void *pStructBase, + const void *pData, + CSendProxyRecipients *pRecipients, + int objectID ); + + +class CNonModifiedPointerProxy +{ +public: + CNonModifiedPointerProxy( SendTableProxyFn fn ); + +public: + + SendTableProxyFn m_Fn; + CNonModifiedPointerProxy *m_pNext; +}; + + +// This tells the engine that the send proxy will not modify the pointer +// - it only plays with the recipients. This must be set on proxies that work +// this way, otherwise the engine can't track which properties changed +// in NetworkStateChanged(). +#define REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( sendProxyFn ) static CNonModifiedPointerProxy __proxy_##sendProxyFn( sendProxyFn ); + + +class CStandardSendProxiesV1 +{ +public: + CStandardSendProxiesV1(); + + SendVarProxyFn m_Int8ToInt32; + SendVarProxyFn m_Int16ToInt32; + SendVarProxyFn m_Int32ToInt32; + + SendVarProxyFn m_UInt8ToInt32; + SendVarProxyFn m_UInt16ToInt32; + SendVarProxyFn m_UInt32ToInt32; + + SendVarProxyFn m_FloatToFloat; + SendVarProxyFn m_VectorToVector; + +#ifdef SUPPORTS_INT64 + SendVarProxyFn m_Int64ToInt64; + SendVarProxyFn m_UInt64ToInt64; +#endif +}; + +class CStandardSendProxies : public CStandardSendProxiesV1 +{ +public: + CStandardSendProxies(); + + SendTableProxyFn m_DataTableToDataTable; + SendTableProxyFn m_SendLocalDataTable; + CNonModifiedPointerProxy **m_ppNonModifiedPointerProxies; +}; + +extern CStandardSendProxies g_StandardSendProxies; + + +// Max # of datatable send proxies you can have in a tree. +#define MAX_DATATABLE_PROXIES 32 + +// ------------------------------------------------------------------------ // +// Datatable send proxies are used to tell the engine where the datatable's +// data is and to specify which clients should get the data. +// +// pRecipients is the object that allows you to specify which clients will +// receive the data. +// ------------------------------------------------------------------------ // +class CSendProxyRecipients +{ +public: + void SetAllRecipients(); // Note: recipients are all set by default when each proxy is called. + void ClearAllRecipients(); + + void SetRecipient( int iClient ); // Note: these are CLIENT indices, not entity indices (so the first player's index is 0). + void ClearRecipient( int iClient ); + + // Clear all recipients and set only the specified one. + void SetOnly( int iClient ); + +public: + // Make sure we have enough room for the max possible player count + CBitVec< ABSOLUTE_PLAYER_LIMIT > m_Bits; +}; + +inline void CSendProxyRecipients::SetAllRecipients() +{ + m_Bits.SetAll(); +} + +inline void CSendProxyRecipients::ClearAllRecipients() +{ + m_Bits.ClearAll(); +} + +inline void CSendProxyRecipients::SetRecipient( int iClient ) +{ + m_Bits.Set( iClient ); +} + +inline void CSendProxyRecipients::ClearRecipient( int iClient ) +{ + m_Bits.Clear( iClient ); +} + +inline void CSendProxyRecipients::SetOnly( int iClient ) +{ + m_Bits.ClearAll(); + m_Bits.Set( iClient ); +} + + + +// ------------------------------------------------------------------------ // +// ArrayLengthSendProxies are used when you want to specify an array's length +// dynamically. +// ------------------------------------------------------------------------ // +typedef int (*ArrayLengthSendProxyFn)( const void *pStruct, int objectID ); + + + +class RecvProp; +class SendTable; +class CSendTablePrecalc; + + +// -------------------------------------------------------------------------------------------------------------- // +// SendProp. +// -------------------------------------------------------------------------------------------------------------- // + +// If SendProp::GetDataTableProxyIndex() returns this, then the proxy is one that always sends +// the data to all clients, so we don't need to store the results. +#define DATATABLE_PROXY_INDEX_NOPROXY 255 +#define DATATABLE_PROXY_INDEX_INVALID 254 + +class SendProp +{ +public: + SendProp(); + virtual ~SendProp(); + + void Clear(); + + int GetOffset() const; + void SetOffset( int i ); + + SendVarProxyFn GetProxyFn() const; + void SetProxyFn( SendVarProxyFn f ); + + SendTableProxyFn GetDataTableProxyFn() const; + void SetDataTableProxyFn( SendTableProxyFn f ); + + SendTable* GetDataTable() const; + void SetDataTable( SendTable *pTable ); + + char const* GetExcludeDTName() const; + + // If it's one of the numbered "000", "001", etc properties in an array, then + // these can be used to get its array property name for debugging. + const char* GetParentArrayPropName() const; + void SetParentArrayPropName( char *pArrayPropName ); + + const char* GetName() const; + + bool IsSigned() const; + + bool IsExcludeProp() const; + + bool IsInsideArray() const; // Returns true if SPROP_INSIDEARRAY is set. + void SetInsideArray(); + + // Arrays only. + void SetArrayProp( SendProp *pProp ); + SendProp* GetArrayProp() const; + + // Arrays only. + void SetArrayLengthProxy( ArrayLengthSendProxyFn fn ); + ArrayLengthSendProxyFn GetArrayLengthProxy() const; + + int GetNumElements() const; + void SetNumElements( int nElements ); + + // Return the # of bits to encode an array length (must hold GetNumElements()). + int GetNumArrayLengthBits() const; + + int GetElementStride() const; + + SendPropType GetType() const; + + int GetFlags() const; + void SetFlags( int flags ); + + // Some property types bind more data to the SendProp in here. + const void* GetExtraData() const; + void SetExtraData( const void *pData ); + +public: + + RecvProp *m_pMatchingRecvProp; // This is temporary and only used while precalculating + // data for the decoders. + + SendPropType m_Type; + int m_nBits; + float m_fLowValue; + float m_fHighValue; + + SendProp *m_pArrayProp; // If this is an array, this is the property that defines each array element. + ArrayLengthSendProxyFn m_ArrayLengthProxy; // This callback returns the array length. + + int m_nElements; // Number of elements in the array (or 1 if it's not an array). + int m_ElementStride; // Pointer distance between array elements. + + const char *m_pExcludeDTName; // If this is an exclude prop, then this is the name of the datatable to exclude a prop from. + const char *m_pParentArrayPropName; + + const char *m_pVarName; + float m_fHighLowMul; + +private: + + int m_Flags; // SPROP_ flags. + + SendVarProxyFn m_ProxyFn; // NULL for DPT_DataTable. + SendTableProxyFn m_DataTableProxyFn; // Valid for DPT_DataTable. + + SendTable *m_pDataTable; + + // SENDPROP_VECTORELEM makes this negative to start with so we can detect that and + // set the SPROP_IS_VECTOR_ELEM flag. + int m_Offset; + + // Extra data bound to this property. + const void *m_pExtraData; +}; + + +inline int SendProp::GetOffset() const +{ + return m_Offset; +} + +inline void SendProp::SetOffset( int i ) +{ + m_Offset = i; +} + +inline SendVarProxyFn SendProp::GetProxyFn() const +{ + Assert( m_Type != DPT_DataTable ); + return m_ProxyFn; +} + +inline void SendProp::SetProxyFn( SendVarProxyFn f ) +{ + m_ProxyFn = f; +} + +inline SendTableProxyFn SendProp::GetDataTableProxyFn() const +{ + Assert( m_Type == DPT_DataTable ); + return m_DataTableProxyFn; +} + +inline void SendProp::SetDataTableProxyFn( SendTableProxyFn f ) +{ + m_DataTableProxyFn = f; +} + +inline SendTable* SendProp::GetDataTable() const +{ + return m_pDataTable; +} + +inline void SendProp::SetDataTable( SendTable *pTable ) +{ + m_pDataTable = pTable; +} + +inline char const* SendProp::GetExcludeDTName() const +{ + return m_pExcludeDTName; +} + +inline const char* SendProp::GetParentArrayPropName() const +{ + return m_pParentArrayPropName; +} + +inline void SendProp::SetParentArrayPropName( char *pArrayPropName ) +{ + Assert( !m_pParentArrayPropName ); + m_pParentArrayPropName = pArrayPropName; +} + +inline const char* SendProp::GetName() const +{ + return m_pVarName; +} + + +inline bool SendProp::IsSigned() const +{ + return !(m_Flags & SPROP_UNSIGNED); +} + +inline bool SendProp::IsExcludeProp() const +{ + return (m_Flags & SPROP_EXCLUDE) != 0; +} + +inline bool SendProp::IsInsideArray() const +{ + return (m_Flags & SPROP_INSIDEARRAY) != 0; +} + +inline void SendProp::SetInsideArray() +{ + m_Flags |= SPROP_INSIDEARRAY; +} + +inline void SendProp::SetArrayProp( SendProp *pProp ) +{ + m_pArrayProp = pProp; +} + +inline SendProp* SendProp::GetArrayProp() const +{ + return m_pArrayProp; +} + +inline void SendProp::SetArrayLengthProxy( ArrayLengthSendProxyFn fn ) +{ + m_ArrayLengthProxy = fn; +} + +inline ArrayLengthSendProxyFn SendProp::GetArrayLengthProxy() const +{ + return m_ArrayLengthProxy; +} + +inline int SendProp::GetNumElements() const +{ + return m_nElements; +} + +inline void SendProp::SetNumElements( int nElements ) +{ + m_nElements = nElements; +} + +inline int SendProp::GetElementStride() const +{ + return m_ElementStride; +} + +inline SendPropType SendProp::GetType() const +{ + return m_Type; +} + +inline int SendProp::GetFlags() const +{ + return m_Flags; +} + +inline void SendProp::SetFlags( int flags ) +{ + // Make sure they're using something from the valid set of flags. + Assert( !( flags & ~((1 << SPROP_NUMFLAGBITS) - 1) ) ); + m_Flags = flags; +} + +inline const void* SendProp::GetExtraData() const +{ + return m_pExtraData; +} + +inline void SendProp::SetExtraData( const void *pData ) +{ + m_pExtraData = pData; +} + + +// -------------------------------------------------------------------------------------------------------------- // +// SendTable. +// -------------------------------------------------------------------------------------------------------------- // + +class SendTable +{ +public: + + typedef SendProp PropType; + + SendTable(); + SendTable( SendProp *pProps, int nProps, const char *pNetTableName ); + ~SendTable(); + + void Construct( SendProp *pProps, int nProps, const char *pNetTableName ); + + const char* GetName() const; + + int GetNumProps() const; + SendProp* GetProp( int i ); + + // Used by the engine. + bool IsInitialized() const; + void SetInitialized( bool bInitialized ); + + // Used by the engine while writing info into the signon. + void SetWriteFlag(bool bHasBeenWritten); + bool GetWriteFlag() const; + + bool HasPropsEncodedAgainstTickCount() const; + void SetHasPropsEncodedAgainstTickcount( bool bState ); + +public: + + SendProp *m_pProps; + int m_nProps; + + const char *m_pNetTableName; // The name matched between client and server. + + // The engine hooks the SendTable here. + CSendTablePrecalc *m_pPrecalc; + + +protected: + bool m_bInitialized : 1; + bool m_bHasBeenWritten : 1; + bool m_bHasPropsEncodedAgainstCurrentTickCount : 1; // m_flSimulationTime and m_flAnimTime, e.g. +}; + + +inline const char* SendTable::GetName() const +{ + return m_pNetTableName; +} + + +inline int SendTable::GetNumProps() const +{ + return m_nProps; +} + + +inline SendProp* SendTable::GetProp( int i ) +{ + Assert( i >= 0 && i < m_nProps ); + return &m_pProps[i]; +} + + +inline bool SendTable::IsInitialized() const +{ + return m_bInitialized; +} + + +inline void SendTable::SetInitialized( bool bInitialized ) +{ + m_bInitialized = bInitialized; +} + + +inline bool SendTable::GetWriteFlag() const +{ + return m_bHasBeenWritten; +} + + +inline void SendTable::SetWriteFlag(bool bHasBeenWritten) +{ + m_bHasBeenWritten = bHasBeenWritten; +} + +inline bool SendTable::HasPropsEncodedAgainstTickCount() const +{ + return m_bHasPropsEncodedAgainstCurrentTickCount; +} + +inline void SendTable::SetHasPropsEncodedAgainstTickcount( bool bState ) +{ + m_bHasPropsEncodedAgainstCurrentTickCount = bState; +} + +// ------------------------------------------------------------------------------------------------------ // +// Use BEGIN_SEND_TABLE if you want to declare a SendTable and have it inherit all the properties from +// its base class. There are two requirements for this to work: + +// 1. Its base class must have a static SendTable pointer member variable called m_pClassSendTable which +// points to its send table. The DECLARE_SERVERCLASS and IMPLEMENT_SERVERCLASS macros do this automatically. + +// 2. Your class must typedef its base class as BaseClass. So it would look like this: +// class Derived : public CBaseEntity +// { +// typedef CBaseEntity BaseClass; +// }; + +// If you don't want to interit a base class's properties, use BEGIN_SEND_TABLE_NOBASE. +// ------------------------------------------------------------------------------------------------------ // +#define BEGIN_SEND_TABLE(className, tableName) \ + BEGIN_SEND_TABLE_NOBASE(className, tableName) \ + SendPropDataTable("baseclass", 0, className::BaseClass::m_pClassSendTable, SendProxy_DataTableToDataTable), + +#define BEGIN_SEND_TABLE_NOBASE(className, tableName) \ + template int ServerClassInit(T *); \ + namespace tableName { \ + struct ignored; \ + } \ + template <> int ServerClassInit(tableName::ignored *); \ + namespace tableName { \ + SendTable g_SendTable;\ + int g_SendTableInit = ServerClassInit((tableName::ignored *)NULL); \ + } \ + template <> int ServerClassInit(tableName::ignored *) \ + { \ + typedef className currentSendDTClass; \ + static const char *g_pSendTableName = #tableName; \ + SendTable &sendTable = tableName::g_SendTable; \ + static SendProp g_SendProps[] = { \ + SendPropInt("should_never_see_this", 0, sizeof(int)), // It adds a dummy property at the start so you can define "empty" SendTables. + +#define END_SEND_TABLE() \ + };\ + sendTable.Construct(g_SendProps+1, sizeof(g_SendProps) / sizeof(SendProp) - 1, g_pSendTableName);\ + return 1; \ + } + + +// These can simplify creating the variables. +// Note: currentSendDTClass::MakeANetworkVar_##varName equates to currentSendDTClass. It's +// there as a check to make sure all networked variables use the CNetworkXXXX macros in network_var.h. +#define SENDINFO(varName) #varName, offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName) +#define SENDINFO_ARRAY(varName) #varName, offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName[0]) +#define SENDINFO_ARRAY3(varName) #varName, offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName[0]), sizeof(((currentSendDTClass*)0)->varName)/sizeof(((currentSendDTClass*)0)->varName[0]) +#define SENDINFO_ARRAYELEM(varName, i) #varName "[" #i "]", offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName[i]), sizeof(((currentSendDTClass*)0)->varName[0]) +#define SENDINFO_NETWORKARRAYELEM(varName, i)#varName "[" #i "]", offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0]) + +// NOTE: Be VERY careful to specify any other vector elems for the same vector IN ORDER and +// right after each other, otherwise it might miss the Y or Z component in SP. +// +// Note: this macro specifies a negative offset so the engine can detect it and setup m_pNext +#define SENDINFO_VECTORELEM(varName, i) #varName "[" #i "]", -(int)offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0]) + +#define SENDINFO_STRUCTELEM(varName) #varName, offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName.m_Value) +#define SENDINFO_STRUCTARRAYELEM(varName, i)#varName "[" #i "]", offsetof(currentSendDTClass, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0]) + +// Use this when you're not using a CNetworkVar to represent the data you're sending. +#define SENDINFO_NOCHECK(varName) #varName, offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName) +#define SENDINFO_STRING_NOCHECK(varName) #varName, offsetof(currentSendDTClass, varName) +#define SENDINFO_DT(varName) #varName, offsetof(currentSendDTClass, varName) +#define SENDINFO_DT_NAME(varName, remoteVarName) #remoteVarName, offsetof(currentSendDTClass, varName) +#define SENDINFO_NAME(varName,remoteVarName) #remoteVarName, offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName) + + + + +// ------------------------------------------------------------------------ // +// Built-in proxy types. +// See the definition of SendVarProxyFn for information about these. +// ------------------------------------------------------------------------ // +void SendProxy_QAngles ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_AngleToFloat ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_FloatToFloat ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_VectorToVector ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_VectorXYToVectorXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!! +void SendProxy_QuaternionToQuaternion( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +#endif + +void SendProxy_Int8ToInt32 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_Int16ToInt32 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +void SendProxy_Int32ToInt32 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +#ifdef SUPPORTS_INT64 +void SendProxy_Int64ToInt64 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); +#endif +void SendProxy_StringToString ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); + +// pData is the address of a data table. +void* SendProxy_DataTableToDataTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ); + +// pData is the address of a pointer to a data table. +void* SendProxy_DataTablePtrToDataTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ); + +// Used on player entities - only sends the data to the local player (objectID-1). +void* SendProxy_SendLocalDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID ); + + +// ------------------------------------------------------------------------ // +// Use these functions to setup your data tables. +// ------------------------------------------------------------------------ // +SendProp SendPropFloat( + const char *pVarName, // Variable name. + int offset, // Offset into container structure. + int sizeofVar=SIZEOF_IGNORE, + int nBits=32, // Number of bits to use when encoding. + int flags=0, + float fLowValue=0.0f, // For floating point, low and high values. + float fHighValue=HIGH_DEFAULT, // High value. If HIGH_DEFAULT, it's (1<arrayName) / PROPSIZEOF(currentSendDTClass, arrayName[0]), \ + PROPSIZEOF(currentSendDTClass, arrayName[0]), \ + #arrayName, \ + arrayLengthSendProxy \ + ) + +// Use this one to specify the element count and stride manually. +#define SendPropArray2( arrayLengthSendProxy, varTemplate, elementCount, elementStride, arrayName ) \ + varTemplate, \ + InternalSendPropArray( elementCount, elementStride, #arrayName, arrayLengthSendProxy ) + + + + +// Use these to create properties that exclude other properties. This is useful if you want to use most of +// a base class's datatable data, but you want to override some of its variables. +SendProp SendPropExclude( + const char *pDataTableName, // Data table name (given to BEGIN_SEND_TABLE and BEGIN_RECV_TABLE). + const char *pPropName // Name of the property to exclude. + ); + + +#endif // DATATABLE_SEND_H diff --git a/public/dt_shared.cpp b/public/dt_shared.cpp new file mode 100644 index 0000000..3508d21 --- /dev/null +++ b/public/dt_shared.cpp @@ -0,0 +1,113 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "dt_shared.h" + +#if !defined (CLIENT_DLL) +#include "sendproxy.h" +#else +#include "recvproxy.h" +#endif + + +// ------------------------------------------------------------------------ // +// Just wrappers to make shared code look easier... +// ------------------------------------------------------------------------ // + +// Use these functions to setup your data tables. +DataTableProp PropFloat( + char *pVarName, // Variable name. + int offset, // Offset into container structure. + int sizeofVar, + int nBits, // Number of bits to use when encoding. + int flags, + float fLowValue, // For floating point, low and high values. + float fHighValue // High value. If HIGH_DEFAULT, it's (1< *g_STDict = 0; +static CUtlDict *g_RTDict = 0; + + +char* AllocateStringHelper2( const char *pFormat, va_list marker ) +{ + char str[512]; + _vsnprintf( str, sizeof( str ), pFormat, marker ); + str[ ARRAYSIZE(str) - 1 ] = 0; + + int len = strlen( str ) + 1; + char *pRet = new char[len]; + memcpy( pRet, str, len ); + + return pRet; +} + + +char* AllocateStringHelper( const char *pFormat, ... ) +{ + va_list marker; + va_start( marker, pFormat ); + char *pRet = AllocateStringHelper2( pFormat, marker ); + va_end( marker ); + + return pRet; +} + + +char* AllocateUniqueDataTableName( bool bSendTable, const char *pFormat, ... ) +{ + // Setup the string. + va_list marker; + va_start( marker, pFormat ); + char *pRet = AllocateStringHelper2( pFormat, marker ); + va_end( marker ); + + // Make sure it's unique. +#ifdef _DEBUG + // Have to allocate them here because if they're declared as straight global variables, + // their constructors won't have been called yet by the time we get in here. + if ( !g_STDict ) + { + g_STDict = new CUtlDict; + g_RTDict = new CUtlDict; + } + + CUtlDict *pDict = bSendTable ? g_STDict : g_RTDict; + if ( pDict->Find( pRet ) != pDict->InvalidIndex() ) + { + // If it hits this, then they have 2 utlvectors in different data tables with the same name and the + // same size limit. The names of + Assert( false ); + } + pDict->Insert( pRet, 0 ); +#endif + + return pRet; +} diff --git a/public/dt_utlvector_common.h b/public/dt_utlvector_common.h new file mode 100644 index 0000000..681ce04 --- /dev/null +++ b/public/dt_utlvector_common.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef DT_UTLVECTOR_COMMON_H +#define DT_UTLVECTOR_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "utlvector.h" + + +typedef void (*EnsureCapacityFn)( void *pVoid, int offsetToUtlVector, int len ); +typedef void (*ResizeUtlVectorFn)( void *pVoid, int offsetToUtlVector, int len ); + +template< class T > +void UtlVector_InitializeAllocatedElements( T *pBase, int count ) +{ + memset( reinterpret_cast( pBase ), 0, count * sizeof( T ) ); +} + +template< class T, class A > +class UtlVectorTemplate +{ +public: + static void ResizeUtlVector( void *pStruct, int offsetToUtlVector, int len ) + { + CUtlVector *pVec = (CUtlVector*)((char*)pStruct + offsetToUtlVector); + if ( pVec->Count() < len ) + pVec->AddMultipleToTail( len - pVec->Count() ); + else if ( pVec->Count() > len ) + pVec->RemoveMultiple( len, pVec->Count()-len ); + + // Ensure capacity + pVec->EnsureCapacity( len ); + + int nNumAllocated = pVec->NumAllocated(); + + // This is important to do because EnsureCapacity doesn't actually call the constructors + // on the elements, but we need them to be initialized, otherwise it'll have out-of-range + // values which will piss off the datatable encoder. + UtlVector_InitializeAllocatedElements( pVec->Base() + pVec->Count(), nNumAllocated - pVec->Count() ); + } + + static void EnsureCapacity( void *pStruct, int offsetToUtlVector, int len ) + { + CUtlVector *pVec = (CUtlVector*)((char*)pStruct + offsetToUtlVector); + + pVec->EnsureCapacity( len ); + + int nNumAllocated = pVec->NumAllocated(); + + // This is important to do because EnsureCapacity doesn't actually call the constructors + // on the elements, but we need them to be initialized, otherwise it'll have out-of-range + // values which will piss off the datatable encoder. + UtlVector_InitializeAllocatedElements( pVec->Base() + pVec->Count(), nNumAllocated - pVec->Count() ); + } +}; + +template< class T, class A > +inline ResizeUtlVectorFn GetResizeUtlVectorTemplate( CUtlVector &vec ) +{ + return &UtlVectorTemplate::ResizeUtlVector; +} + +template< class T, class A > +inline EnsureCapacityFn GetEnsureCapacityTemplate( CUtlVector &vec ) +{ + return &UtlVectorTemplate::EnsureCapacity; +} + + +// Format and allocate a string. +char* AllocateStringHelper( PRINTF_FORMAT_STRING const char *pFormat, ... ); + +// Allocates a string for a data table name. Data table names must be unique, so this will +// assert if you try to allocate a duplicate. +char* AllocateUniqueDataTableName( bool bSendTable, PRINTF_FORMAT_STRING const char *pFormat, ... ); + + +#endif // DT_UTLVECTOR_COMMON_H diff --git a/public/dt_utlvector_recv.cpp b/public/dt_utlvector_recv.cpp new file mode 100644 index 0000000..7fa86fd --- /dev/null +++ b/public/dt_utlvector_recv.cpp @@ -0,0 +1,157 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "dt_utlvector_recv.h" + +#include "tier0/memdbgon.h" + + +extern const char *s_ClientElementNames[MAX_ARRAY_ELEMENTS]; + + +class CRecvPropExtra_UtlVector +{ +public: + DataTableRecvVarProxyFn m_DataTableProxyFn; // If it's a datatable, then this is the proxy they specified. + RecvVarProxyFn m_ProxyFn; // If it's a non-datatable, then this is the proxy they specified. + ResizeUtlVectorFn m_ResizeFn; // The function used to resize the CUtlVector. + EnsureCapacityFn m_EnsureCapacityFn; + int m_ElementStride; // Distance between each element in the array. + int m_Offset; // Offset of the CUtlVector from its parent structure. + int m_nMaxElements; // For debugging... +}; + +void RecvProxy_UtlVectorLength( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pData->m_pRecvProp->GetExtraData(); + pExtra->m_ResizeFn( pStruct, pExtra->m_Offset, pData->m_Value.m_Int ); +} + +void RecvProxy_UtlVectorElement( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pData->m_pRecvProp->GetExtraData(); + + // Kind of lame overloading element stride to hold the element index, + // but we can easily move it into its SetExtraData stuff if we need to. + int iElement = pData->m_pRecvProp->GetElementStride(); + + // NOTE: this is cheesy, but it does the trick. + CUtlVector *pUtlVec = (CUtlVector*)((char*)pStruct + pExtra->m_Offset); + + // Call through to the proxy they passed in, making pStruct=the CUtlVector. + // Note: there should be space here as long as the element is < the max # elements + // that we ensured capacity for in DataTableRecvProxy_LengthProxy. + pExtra->m_ProxyFn( pData, pOut, (char*)pUtlVec->Base() + iElement*pExtra->m_ElementStride ); +} + +void RecvProxy_UtlVectorElement_DataTable( const RecvProp *pProp, void **pOut, void *pData, int objectID ) +{ + CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pProp->GetExtraData(); + + int iElement = pProp->GetElementStride(); + Assert( iElement < pExtra->m_nMaxElements ); + + // NOTE: this is cheesy, but it does the trick. + CUtlVector *pUtlVec = (CUtlVector*)((char*)pData + pExtra->m_Offset); + + // Call through to the proxy they passed in, making pStruct=the CUtlVector and forcing iElement to 0. + pExtra->m_DataTableProxyFn( pProp, pOut, (char*)pUtlVec->Base() + iElement*pExtra->m_ElementStride, objectID ); +} + + +void DataTableRecvProxy_LengthProxy( const RecvProp *pProp, void **pOut, void *pData, int objectID ) +{ + // This is VERY important - since it calls all the datatable proxies in the tree first, + // particularly BEFORE it calls our array length proxy, we need to make sure we return + // valid pointers that aren't going to change when it starts to copy the data into + // the datatable elements. + CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pProp->GetExtraData(); + pExtra->m_EnsureCapacityFn( pData, pExtra->m_Offset, pExtra->m_nMaxElements ); + + *pOut = pData; +} + + +RecvProp RecvPropUtlVector( + const char *pVarName, // Use RECVINFO_UTLVECTOR to generate these 4. + int offset, // Used to generate pData in the function specified in varProxy. + int sizeofVar, // The size of each element in the utlvector. + ResizeUtlVectorFn fn, + EnsureCapacityFn ensureFn, + int nMaxElements, // Max # of elements in the array. Keep this as low as possible. + RecvProp pArrayProp + ) +{ + RecvProp ret; + + Assert( nMaxElements <= MAX_ARRAY_ELEMENTS ); + + ret.m_RecvType = DPT_DataTable; + ret.m_pVarName = pVarName; + ret.SetOffset( 0 ); + ret.SetDataTableProxyFn( DataTableRecvProxy_StaticDataTable ); + + RecvProp *pProps = new RecvProp[nMaxElements+1]; // TODO free that again + + + // Extra data bound to each of the properties. + CRecvPropExtra_UtlVector *pExtraData = new CRecvPropExtra_UtlVector; + + pExtraData->m_nMaxElements = nMaxElements; + pExtraData->m_ElementStride = sizeofVar; + pExtraData->m_ResizeFn = fn; + pExtraData->m_EnsureCapacityFn = ensureFn; + pExtraData->m_Offset = offset; + + if ( pArrayProp.m_RecvType == DPT_DataTable ) + pExtraData->m_DataTableProxyFn = pArrayProp.GetDataTableProxyFn(); + else + pExtraData->m_ProxyFn = pArrayProp.GetProxyFn(); + + + // The first property is datatable with an int that tells the length of the array. + // It has to go in a datatable, otherwise if this array holds datatable properties, it will be received last. + RecvProp *pLengthProp = new RecvProp; + *pLengthProp = RecvPropInt( AllocateStringHelper( "lengthprop%d", nMaxElements ), 0, 0, 0, RecvProxy_UtlVectorLength ); + pLengthProp->SetExtraData( pExtraData ); + + char *pLengthProxyTableName = AllocateUniqueDataTableName( false, "_LPT_%s_%d", pVarName, nMaxElements ); + RecvTable *pLengthTable = new RecvTable( pLengthProp, 1, pLengthProxyTableName ); + pProps[0] = RecvPropDataTable( "lengthproxy", 0, 0, pLengthTable, DataTableRecvProxy_LengthProxy ); + pProps[0].SetExtraData( pExtraData ); + + // The first element is a sub-datatable. + for ( int i = 1; i < nMaxElements+1; i++ ) + { + pProps[i] = pArrayProp; // copy array element property setting + pProps[i].SetOffset( 0 ); // leave offset at 0 so pStructBase is always a pointer to the CUtlVector + pProps[i].m_pVarName = s_ClientElementNames[i-1]; // give unique name + pProps[i].SetExtraData( pExtraData ); + pProps[i].SetElementStride( i-1 ); // Kind of lame overloading element stride to hold the element index, + // but we can easily move it into its SetExtraData stuff if we need to. + + // We provide our own proxy here. + if ( pArrayProp.m_RecvType == DPT_DataTable ) + { + pProps[i].SetDataTableProxyFn( RecvProxy_UtlVectorElement_DataTable ); + } + else + { + pProps[i].SetProxyFn( RecvProxy_UtlVectorElement ); + } + } + + RecvTable *pTable = new RecvTable( + pProps, + nMaxElements+1, + AllocateUniqueDataTableName( false, "_ST_%s_%d", pVarName, nMaxElements ) + ); // TODO free that again + + ret.SetDataTable( pTable ); + return ret; +} diff --git a/public/dt_utlvector_recv.h b/public/dt_utlvector_recv.h new file mode 100644 index 0000000..6b27057 --- /dev/null +++ b/public/dt_utlvector_recv.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Player for HL1. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DT_UTLVECTOR_RECV_H +#define DT_UTLVECTOR_RECV_H +#pragma once + + +#include "dt_recv.h" +#include "dt_utlvector_common.h" + + + +#define RECVINFO_UTLVECTOR( varName ) #varName, \ + offsetof(currentRecvDTClass, varName), \ + sizeof(((currentRecvDTClass*)0)->varName[0]), \ + GetResizeUtlVectorTemplate( ((currentRecvDTClass*)0)->varName ), \ + GetEnsureCapacityTemplate( ((currentRecvDTClass*)0)->varName ) + +// Use this macro to specify a utlvector where you specify the function +// that gets called to make sure the size of the utlvector is correct. +// The size function looks like this: void ResizeUtlVector( void *pVoid, int len ) +#define RECVINFO_UTLVECTOR_SIZEFN( varName, resizeFn ) #varName, \ + offsetof(currentRecvDTClass, varName), \ + sizeof(((currentRecvDTClass*)0)->varName[0]), \ + resizeFn, \ + GetEnsureCapacityTemplate( ((currentRecvDTClass*)0)->varName ) + + +#define RecvPropUtlVectorDataTable( varName, nMaxElements, dataTableName ) \ + RecvPropUtlVector( RECVINFO_UTLVECTOR( varName ), nMaxElements, RecvPropDataTable(NULL,0,0, &REFERENCE_RECV_TABLE( dataTableName ) ) ) + + +// +// Receive a property sent with SendPropUtlVector. +// +// Example usage: +// +// RecvPropUtlVectorDataTable( m_StructArray, 11, DT_StructArray ) +// +// RecvPropUtlVector( RECVINFO_UTLVECTOR( m_FloatArray ), 16, RecvPropFloat(NULL,0,0) ) +// +RecvProp RecvPropUtlVector( + const char *pVarName, // Use RECVINFO_UTLVECTOR to generate these first 5 parameters. + int offset, + int sizeofVar, + ResizeUtlVectorFn fn, + EnsureCapacityFn ensureFn, + + int nMaxElements, // Max # of elements in the array. Keep this as low as possible. + RecvProp pArrayProp // The definition of the property you're receiving into. + // You can leave all of its parameters at 0 (name, offset, size, etc). + ); + + +#endif // DT_UTLVECTOR_RECV_H diff --git a/public/dt_utlvector_send.cpp b/public/dt_utlvector_send.cpp new file mode 100644 index 0000000..b10170d --- /dev/null +++ b/public/dt_utlvector_send.cpp @@ -0,0 +1,224 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "dt_utlvector_send.h" + +#include "tier0/memdbgon.h" + + +extern const char *s_ElementNames[MAX_ARRAY_ELEMENTS]; + +// This gets associated with SendProps inside a utlvector and stores extra data needed to make it work. +class CSendPropExtra_UtlVector +{ +public: + CSendPropExtra_UtlVector() : + m_DataTableProxyFn( NULL ), + m_ProxyFn( NULL ), + m_EnsureCapacityFn( NULL ), + m_ElementStride( 0 ), + m_Offset( 0 ), + m_nMaxElements( 0 ) + { + } + + SendTableProxyFn m_DataTableProxyFn; // If it's a datatable, then this is the proxy they specified. + SendVarProxyFn m_ProxyFn; // If it's a non-datatable, then this is the proxy they specified. + EnsureCapacityFn m_EnsureCapacityFn; + int m_ElementStride; // Distance between each element in the array. + int m_Offset; // # bytes from the parent structure to its utlvector. + int m_nMaxElements; // For debugging... +}; + + +void SendProxy_UtlVectorElement( + const SendProp *pProp, + const void *pStruct, + const void *pData, + DVariant *pOut, + int iElement, + int objectID ) +{ + CSendPropExtra_UtlVector *pExtra = (CSendPropExtra_UtlVector*)pProp->GetExtraData(); + Assert( pExtra ); + + // Kind of lame overloading element stride to hold the element index, + // but we can easily move it into its SetExtraData stuff if we need to. + iElement = pProp->GetElementStride(); + + // NOTE: this is cheesy, but it does the trick. + CUtlVector *pUtlVec = (CUtlVector*)((char*)pStruct + pExtra->m_Offset); + if ( iElement >= pUtlVec->Count() ) + { + // Pass in zero value. + memset( pOut, 0, sizeof( *pOut ) ); + } + else + { + // Call through to the proxy they passed in, making pStruct=the CUtlVector and forcing iElement to 0. + pExtra->m_ProxyFn( pProp, pData, (char*)pUtlVec->Base() + iElement*pExtra->m_ElementStride, pOut, 0, objectID ); + } +} + +void* SendProxy_UtlVectorElement_DataTable( + const SendProp *pProp, + const void *pStructBase, + const void *pData, + CSendProxyRecipients *pRecipients, + int objectID ) +{ + CSendPropExtra_UtlVector *pExtra = (CSendPropExtra_UtlVector*)pProp->GetExtraData(); + + int iElement = pProp->m_ElementStride; + Assert( iElement < pExtra->m_nMaxElements ); + + // This should have gotten called in SendProxy_LengthTable before we get here, so + // the capacity should be correct. +#ifdef _DEBUG + pExtra->m_EnsureCapacityFn( (void*)pStructBase, pExtra->m_Offset, pExtra->m_nMaxElements ); +#endif + + // NOTE: this is cheesy because we're assuming the type of the template class, but it does the trick. + CUtlVector *pUtlVec = (CUtlVector*)((char*)pStructBase + pExtra->m_Offset); + + // Call through to the proxy they passed in, making pStruct=the CUtlVector and forcing iElement to 0. + return pExtra->m_DataTableProxyFn( pProp, pData, (char*)pUtlVec->Base() + iElement*pExtra->m_ElementStride, pRecipients, objectID ); +} + +void SendProxy_UtlVectorLength( + const SendProp *pProp, + const void *pStruct, + const void *pData, + DVariant *pOut, + int iElement, + int objectID ) +{ + CSendPropExtra_UtlVector *pExtra = (CSendPropExtra_UtlVector*)pProp->GetExtraData(); + + // NOTE: this is cheesy because we're assuming the type of the template class, but it does the trick. + CUtlVector *pUtlVec = (CUtlVector*)((char*)pStruct + pExtra->m_Offset); + + // Don't let them overflow the buffer because they might expect that to get transmitted to the client. + pOut->m_Int = pUtlVec->Count(); + if ( pOut->m_Int > pExtra->m_nMaxElements ) + { + Assert( false ); + pOut->m_Int = pExtra->m_nMaxElements; + } +} + + +void* SendProxy_LengthTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ) +{ + // Make sure the array has space to hold all the elements. + CSendPropExtra_UtlVector *pExtra = (CSendPropExtra_UtlVector*)pProp->GetExtraData(); + pExtra->m_EnsureCapacityFn( (void*)pStructBase, pExtra->m_Offset, pExtra->m_nMaxElements ); + return (void*)pData; +} + + +// Note: your pArrayProp will NOT get iElement set to anything other than 0, because this function installs its +// own proxy in front of yours. pStruct will point at the CUtlVector and pData will point at the element in the CUtlVector.It will pass you the direct pointer to the element inside the CUtlVector. +// +// You can skip the first 3 parameters in pArrayProp because they're ignored. So your array specification +// could look like this: +// SendPropUtlVector( +// SENDINFO_UTLVECTOR( m_FloatArray ), +// SendPropFloat( NULL, 0, 0, 0 [# bits], SPROP_NOSCALE [flags] ) ); +// +// Note: you have to be DILIGENT about calling NetworkStateChanged whenever an element in your CUtlVector changes +// since CUtlVector doesn't do this automatically. +SendProp SendPropUtlVector( + char *pVarName, // Use SENDINFO_UTLVECTOR to generate these 4. + int offset, // Used to generate pData in the function specified in varProxy. + int sizeofVar, // The size of each element in the utlvector. + EnsureCapacityFn ensureFn, // This is the value returned for elements out of the array's current range. + int nMaxElements, // Max # of elements in the array. Keep this as low as possible. + SendProp pArrayProp, // Describe the data inside of each element in the array. + SendTableProxyFn varProxy // This can be overridden to control who the array is sent to. + ) +{ + SendProp ret; + + Assert( nMaxElements <= MAX_ARRAY_ELEMENTS ); + + ret.m_Type = DPT_DataTable; + ret.m_pVarName = pVarName; + ret.SetOffset( 0 ); + ret.SetDataTableProxyFn( varProxy ); + + // Handle special proxy types where they always let all clients get the results. + if ( varProxy == SendProxy_DataTableToDataTable || varProxy == SendProxy_DataTablePtrToDataTable ) + { + ret.SetFlags( SPROP_PROXY_ALWAYS_YES ); + } + + + // Extra data bound to each of the properties. + CSendPropExtra_UtlVector *pExtraData = new CSendPropExtra_UtlVector; + + pExtraData->m_nMaxElements = nMaxElements; + pExtraData->m_ElementStride = sizeofVar; + pExtraData->m_EnsureCapacityFn = ensureFn; + pExtraData->m_Offset = offset; + + if ( pArrayProp.m_Type == DPT_DataTable ) + pExtraData->m_DataTableProxyFn = pArrayProp.GetDataTableProxyFn(); + else + pExtraData->m_ProxyFn = pArrayProp.GetProxyFn(); + + + SendProp *pProps = new SendProp[nMaxElements+1]; // TODO free that again + + // The first property is datatable with an int that tells the length of the array. + // It has to go in a datatable, otherwise if this array holds datatable properties, it will be received last. + SendProp *pLengthProp = new SendProp; + *pLengthProp = SendPropInt( AllocateStringHelper( "lengthprop%d", nMaxElements ), 0, 0, NumBitsForCount( nMaxElements ), SPROP_UNSIGNED, SendProxy_UtlVectorLength ); + pLengthProp->SetExtraData( pExtraData ); + + char *pLengthProxyTableName = AllocateUniqueDataTableName( true, "_LPT_%s_%d", pVarName, nMaxElements ); + SendTable *pLengthTable = new SendTable( pLengthProp, 1, pLengthProxyTableName ); + pProps[0] = SendPropDataTable( "lengthproxy", 0, pLengthTable, SendProxy_LengthTable ); + pProps[0].SetExtraData( pExtraData ); + + // TERROR: + char *pParentArrayPropName = AllocateStringHelper( "%s", pVarName ); + Assert( pParentArrayPropName && *pParentArrayPropName ); // TERROR + + // The first element is a sub-datatable. + for ( int i = 1; i < nMaxElements+1; i++ ) + { + pProps[i] = pArrayProp; // copy array element property setting + pProps[i].SetOffset( 0 ); // leave offset at 0 so pStructBase is always a pointer to the CUtlVector + pProps[i].m_pVarName = s_ElementNames[i-1]; // give unique name + pProps[i].m_pParentArrayPropName = pParentArrayPropName; // TERROR: For debugging... + pProps[i].SetExtraData( pExtraData ); + pProps[i].m_ElementStride = i-1; // Kind of lame overloading element stride to hold the element index, + // but we can easily move it into its SetExtraData stuff if we need to. + + // We provide our own proxy here. + if ( pArrayProp.m_Type == DPT_DataTable ) + { + pProps[i].SetDataTableProxyFn( SendProxy_UtlVectorElement_DataTable ); + pProps[i].SetFlags( SPROP_PROXY_ALWAYS_YES ); + } + else + { + pProps[i].SetProxyFn( SendProxy_UtlVectorElement ); + } + } + + SendTable *pTable = new SendTable( + pProps, + nMaxElements+1, + AllocateUniqueDataTableName( true, "_ST_%s_%d", pVarName, nMaxElements ) + ); + + ret.SetDataTable( pTable ); + return ret; +} diff --git a/public/dt_utlvector_send.h b/public/dt_utlvector_send.h new file mode 100644 index 0000000..f2ba68c --- /dev/null +++ b/public/dt_utlvector_send.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Player for HL1. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DT_UTLVECTOR_SEND_H +#define DT_UTLVECTOR_SEND_H +#pragma once + + +#include "dt_send.h" +#include "dt_utlvector_common.h" + + +#define SENDINFO_UTLVECTOR( varName ) #varName, \ + offsetof(currentSendDTClass, varName), \ + sizeof(((currentSendDTClass*)0)->varName[0]), \ + GetEnsureCapacityTemplate( ((currentSendDTClass*)0)->varName ) + + + +#define SendPropUtlVectorDataTable( varName, nMaxElements, dataTableName ) \ + SendPropUtlVector( \ + SENDINFO_UTLVECTOR( varName ), \ + nMaxElements, \ + SendPropDataTable( NULL, 0, &REFERENCE_SEND_TABLE( dataTableName ) ) \ + ) + +// +// Set it up to transmit a CUtlVector of basic types or of structures. +// +// pArrayProp doesn't need a name, offset, or size. You can pass 0 for all those. +// Example usage: +// +// SendPropUtlVectorDataTable( m_StructArray, 11, DT_TestStruct ) +// +// SendPropUtlVector( +// SENDINFO_UTLVECTOR( m_FloatArray ), +// 16, // max elements +// SendPropFloat( NULL, 0, 0, 0, SPROP_NOSCALE ) +// ) +// +SendProp SendPropUtlVector( + char *pVarName, // Use SENDINFO_UTLVECTOR to generate these first 4 parameters. + int offset, + int sizeofVar, + EnsureCapacityFn ensureFn, + + int nMaxElements, // Max # of elements in the array. Keep this as low as possible. + SendProp pArrayProp, // Describe the data inside of each element in the array. + SendTableProxyFn varProxy=SendProxy_DataTableToDataTable // This can be overridden to control who the array is sent to. + ); + + +#endif // DT_UTLVECTOR_SEND_H diff --git a/public/edict.h b/public/edict.h new file mode 100644 index 0000000..37c701b --- /dev/null +++ b/public/edict.h @@ -0,0 +1,448 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef EDICT_H +#define EDICT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "cmodel.h" +#include "const.h" +#include "iserverentity.h" +#include "globalvars_base.h" +#include "engine/ICollideable.h" +#include "iservernetworkable.h" +#include "bitvec.h" + +struct edict_t; + + +//----------------------------------------------------------------------------- +// Purpose: Defines the ways that a map can be loaded. +//----------------------------------------------------------------------------- +enum MapLoadType_t +{ + MapLoad_NewGame = 0, + MapLoad_LoadGame, + MapLoad_Transition, + MapLoad_Background, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Global variables shared between the engine and the game .dll +//----------------------------------------------------------------------------- +class CGlobalVars : public CGlobalVarsBase +{ +public: + + CGlobalVars( bool bIsClient ); + +public: + + // Current map + string_t mapname; + int mapversion; + string_t startspot; + MapLoadType_t eLoadType; // How the current map was loaded + bool bMapLoadFailed; // Map has failed to load, we need to kick back to the main menu + + // game specific flags + bool deathmatch; + bool coop; + bool teamplay; + // current maxentities + int maxEntities; + + int serverCount; +}; + +inline CGlobalVars::CGlobalVars( bool bIsClient ) : + CGlobalVarsBase( bIsClient ) +{ + serverCount = 0; +} + + +class CPlayerState; +class IServerNetworkable; +class IServerEntity; + + +#define FL_EDICT_CHANGED (1<<0) // Game DLL sets this when the entity state changes + // Mutually exclusive with FL_EDICT_PARTIAL_CHANGE. + +#define FL_EDICT_FREE (1<<1) // this edict if free for reuse +#define FL_EDICT_FULL (1<<2) // this is a full server entity + +#define FL_EDICT_FULLCHECK (0<<0) // call ShouldTransmit() each time, this is a fake flag +#define FL_EDICT_ALWAYS (1<<3) // always transmit this entity +#define FL_EDICT_DONTSEND (1<<4) // don't transmit this entity +#define FL_EDICT_PVSCHECK (1<<5) // always transmit entity, but cull against PVS + +// Used by local network backdoor. +#define FL_EDICT_PENDING_DORMANT_CHECK (1<<6) + +// This is always set at the same time EFL_DIRTY_PVS_INFORMATION is set, but it +// gets cleared in a different place. +#define FL_EDICT_DIRTY_PVS_INFORMATION (1<<7) + +// This is used internally to edict_t to remember that it's carrying a +// "full change list" - all its properties might have changed their value. +#define FL_FULL_EDICT_CHANGED (1<<8) + + +// Max # of variable changes we'll track in an entity before we treat it +// like they all changed. +#define MAX_CHANGE_OFFSETS 19 +#define MAX_EDICT_CHANGE_INFOS 100 + + +class CEdictChangeInfo +{ +public: + // Edicts remember the offsets of properties that change + unsigned short m_ChangeOffsets[MAX_CHANGE_OFFSETS]; + unsigned short m_nChangeOffsets; +}; + +// Shared between engine and game DLL. +class CSharedEdictChangeInfo +{ +public: + CSharedEdictChangeInfo() + { + m_iSerialNumber = 1; + } + + // Matched against edict_t::m_iChangeInfoSerialNumber to determine if its + // change info is valid. + unsigned short m_iSerialNumber; + + CEdictChangeInfo m_ChangeInfos[MAX_EDICT_CHANGE_INFOS]; + unsigned short m_nChangeInfos; // How many are in use this frame. +}; +extern CSharedEdictChangeInfo *g_pSharedChangeInfo; + +class IChangeInfoAccessor +{ +public: + inline void SetChangeInfo( unsigned short info ) + { + m_iChangeInfo = info; + } + + inline void SetChangeInfoSerialNumber( unsigned short sn ) + { + m_iChangeInfoSerialNumber = sn; + } + + inline unsigned short GetChangeInfo() const + { + return m_iChangeInfo; + } + + inline unsigned short GetChangeInfoSerialNumber() const + { + return m_iChangeInfoSerialNumber; + } + +private: + unsigned short m_iChangeInfo; + unsigned short m_iChangeInfoSerialNumber; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +// NOTE: YOU CAN'T CHANGE THE LAYOUT OR SIZE OF CBASEEDICT AND REMAIN COMPATIBLE WITH HL2_VC6!!!!! +class CBaseEdict +{ +public: + + // Returns an IServerEntity if FL_FULLEDICT is set or NULL if this + // is a lightweight networking entity. + IServerEntity* GetIServerEntity(); + const IServerEntity* GetIServerEntity() const; + + IServerNetworkable* GetNetworkable(); + IServerUnknown* GetUnknown(); + + // Set when initting an entity. If it's only a networkable, this is false. + void SetEdict( IServerUnknown *pUnk, bool bFullEdict ); + + int AreaNum() const; + const char * GetClassName() const; + + bool IsFree() const; + void SetFree(); + void ClearFree(); + + bool HasStateChanged() const; + void ClearStateChanged(); + void StateChanged(); + void StateChanged( unsigned short offset ); + + void ClearTransmitState(); + + void SetChangeInfo( unsigned short info ); + void SetChangeInfoSerialNumber( unsigned short sn ); + unsigned short GetChangeInfo() const; + unsigned short GetChangeInfoSerialNumber() const; + +public: + + // NOTE: this is in the edict instead of being accessed by a virtual because the engine needs fast access to it. + // NOTE: YOU CAN'T CHANGE THE LAYOUT OR SIZE OF CBASEEDICT AND REMAIN COMPATIBLE WITH HL2_VC6!!!!! +#ifdef _XBOX + unsigned short m_fStateFlags; +#else + int m_fStateFlags; +#endif + + // NOTE: this is in the edict instead of being accessed by a virtual because the engine needs fast access to it. + // int m_NetworkSerialNumber; + + // NOTE: m_EdictIndex is an optimization since computing the edict index + // from a CBaseEdict* pointer otherwise requires divide-by-20. values for + // m_NetworkSerialNumber all fit within a 16-bit integer range, so we're + // repurposing the other 16 bits to cache off the index without changing + // the overall layout or size of this struct. existing mods compiled with + // a full 32-bit serial number field should still work. henryg 8/17/2011 +#if VALVE_LITTLE_ENDIAN + short m_NetworkSerialNumber; + short m_EdictIndex; +#else + short m_EdictIndex; + short m_NetworkSerialNumber; +#endif + + // NOTE: this is in the edict instead of being accessed by a virtual because the engine needs fast access to it. + IServerNetworkable *m_pNetworkable; + +protected: + IServerUnknown *m_pUnk; + + +public: + + IChangeInfoAccessor *GetChangeAccessor(); // The engine implements this and the game .dll implements as + const IChangeInfoAccessor *GetChangeAccessor() const; // The engine implements this and the game .dll implements as + // as callback through to the engine!!! + + // NOTE: YOU CAN'T CHANGE THE LAYOUT OR SIZE OF CBASEEDICT AND REMAIN COMPATIBLE WITH HL2_VC6!!!!! + // This breaks HL2_VC6!!!!! + // References a CEdictChangeInfo with a list of modified network props. + //unsigned short m_iChangeInfo; + //unsigned short m_iChangeInfoSerialNumber; + + friend void InitializeEntityDLLFields( edict_t *pEdict ); +}; + + +//----------------------------------------------------------------------------- +// CBaseEdict inlines. +//----------------------------------------------------------------------------- +inline IServerEntity* CBaseEdict::GetIServerEntity() +{ + if ( m_fStateFlags & FL_EDICT_FULL ) + return (IServerEntity*)m_pUnk; + else + return 0; +} + +inline bool CBaseEdict::IsFree() const +{ + return (m_fStateFlags & FL_EDICT_FREE) != 0; +} + + + +inline bool CBaseEdict::HasStateChanged() const +{ + return (m_fStateFlags & FL_EDICT_CHANGED) != 0; +} + +inline void CBaseEdict::ClearStateChanged() +{ + m_fStateFlags &= ~(FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED); + SetChangeInfoSerialNumber( 0 ); +} + +inline void CBaseEdict::StateChanged() +{ + // Note: this should only happen for properties in data tables that used some + // kind of pointer dereference. If the data is directly offsetable + m_fStateFlags |= (FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED); + SetChangeInfoSerialNumber( 0 ); +} + +inline void CBaseEdict::StateChanged( unsigned short offset ) +{ + if ( m_fStateFlags & FL_FULL_EDICT_CHANGED ) + return; + + m_fStateFlags |= FL_EDICT_CHANGED; + + IChangeInfoAccessor *accessor = GetChangeAccessor(); + + if ( accessor->GetChangeInfoSerialNumber() == g_pSharedChangeInfo->m_iSerialNumber ) + { + // Ok, I still own this one. + CEdictChangeInfo *p = &g_pSharedChangeInfo->m_ChangeInfos[accessor->GetChangeInfo()]; + + // Now add this offset to our list of changed variables. + for ( unsigned short i=0; i < p->m_nChangeOffsets; i++ ) + if ( p->m_ChangeOffsets[i] == offset ) + return; + + if ( p->m_nChangeOffsets == MAX_CHANGE_OFFSETS ) + { + // Invalidate our change info. + accessor->SetChangeInfoSerialNumber( 0 ); + m_fStateFlags |= FL_FULL_EDICT_CHANGED; // So we don't get in here again. + } + else + { + p->m_ChangeOffsets[p->m_nChangeOffsets++] = offset; + } + } + else + { + if ( g_pSharedChangeInfo->m_nChangeInfos == MAX_EDICT_CHANGE_INFOS ) + { + // Shucks.. have to mark the edict as fully changed because we don't have room to remember this change. + accessor->SetChangeInfoSerialNumber( 0 ); + m_fStateFlags |= FL_FULL_EDICT_CHANGED; + } + else + { + // Get a new CEdictChangeInfo and fill it out. + accessor->SetChangeInfo( g_pSharedChangeInfo->m_nChangeInfos ); + g_pSharedChangeInfo->m_nChangeInfos++; + + accessor->SetChangeInfoSerialNumber( g_pSharedChangeInfo->m_iSerialNumber ); + + CEdictChangeInfo *p = &g_pSharedChangeInfo->m_ChangeInfos[accessor->GetChangeInfo()]; + p->m_ChangeOffsets[0] = offset; + p->m_nChangeOffsets = 1; + } + } +} + + + +inline void CBaseEdict::SetFree() +{ + m_fStateFlags |= FL_EDICT_FREE; +} + +// WARNING: Make sure you don't really want to call ED_ClearFreeFlag which will also +// remove this edict from the g_FreeEdicts bitset. +inline void CBaseEdict::ClearFree() +{ + m_fStateFlags &= ~FL_EDICT_FREE; +} + +inline void CBaseEdict::ClearTransmitState() +{ + m_fStateFlags &= ~(FL_EDICT_ALWAYS|FL_EDICT_PVSCHECK|FL_EDICT_DONTSEND); +} + +inline const IServerEntity* CBaseEdict::GetIServerEntity() const +{ + if ( m_fStateFlags & FL_EDICT_FULL ) + return (IServerEntity*)m_pUnk; + else + return 0; +} + +inline IServerUnknown* CBaseEdict::GetUnknown() +{ + return m_pUnk; +} + +inline IServerNetworkable* CBaseEdict::GetNetworkable() +{ + return m_pNetworkable; +} + +inline void CBaseEdict::SetEdict( IServerUnknown *pUnk, bool bFullEdict ) +{ + m_pUnk = pUnk; + if ( (pUnk != NULL) && bFullEdict ) + { + m_fStateFlags = FL_EDICT_FULL; + } + else + { + m_fStateFlags = 0; + } +} + +inline int CBaseEdict::AreaNum() const +{ + if ( !m_pUnk ) + return 0; + + return m_pNetworkable->AreaNum(); +} + +inline const char * CBaseEdict::GetClassName() const +{ + if ( !m_pUnk ) + return ""; + return m_pNetworkable->GetClassName(); +} + +inline void CBaseEdict::SetChangeInfo( unsigned short info ) +{ + GetChangeAccessor()->SetChangeInfo( info ); +} + +inline void CBaseEdict::SetChangeInfoSerialNumber( unsigned short sn ) +{ + GetChangeAccessor()->SetChangeInfoSerialNumber( sn ); +} + +inline unsigned short CBaseEdict::GetChangeInfo() const +{ + return GetChangeAccessor()->GetChangeInfo(); +} + +inline unsigned short CBaseEdict::GetChangeInfoSerialNumber() const +{ + return GetChangeAccessor()->GetChangeInfoSerialNumber(); +} + +//----------------------------------------------------------------------------- +// Purpose: The engine's internal representation of an entity, including some +// basic collision and position info and a pointer to the class wrapped on top +// of the structure +//----------------------------------------------------------------------------- +struct edict_t : public CBaseEdict +{ +public: + ICollideable *GetCollideable(); + + // The server timestampe at which the edict was freed (so we can try to use other edicts before reallocating this one) + float freetime; +}; + +inline ICollideable *edict_t::GetCollideable() +{ + IServerEntity *pEnt = GetIServerEntity(); + if ( pEnt ) + return pEnt->GetCollideable(); + else + return NULL; +} + + +#endif // EDICT_H diff --git a/public/editor_sendcommand.cpp b/public/editor_sendcommand.cpp new file mode 100644 index 0000000..c08b5f5 --- /dev/null +++ b/public/editor_sendcommand.cpp @@ -0,0 +1,228 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements an interface to the map editor for the execution of +// editor shell commands from another application. Commands allow the +// creation and deletion of entities, AI nodes, and AI node connections. +// +// $NoKeywords: $ +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#if !defined(_X360) && defined(_WIN32) +#include +#endif +#include +#include "editor_sendcommand.h" +#include "tier1/strtools.h" +#include "mathlib/vector.h" + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +const int MAX_COMMAND_BUFFER = 2048; +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to begin an editing session +// of a given map. +// Input : pszMapName - Name of the bsp, without the path or extension: "c1a3a_port" +// nMapVersion - Map version number, from the BSP file. +// Output : Returns Editor_OK on success, an error code if the session was rejected. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_BeginSession(const char *pszMapName, int nMapVersion, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "session_begin %s %d", pszMapName, nMapVersion); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to verify the version and +// map name being edited. +// Input : pszMapName - Name of the bsp, without the path or extension: "c1a3a_port" +// nMapVersion - Map version number, from the BSP file. +// Output : Returns Editor_OK on success, an error code if the session was rejected. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_CheckVersion(const char *pszMapName, int nMapVersion, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "map_check_version %s %d", pszMapName, nMapVersion); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to create an entity at +// a given (x, y, z) coordinate. +// Input : pszEntity - Class name of entity to create, ie "info_player_start". +// x, y, z - World coordinates at which to create entity. +// Output : Returns Editor_OK on success, an error code on failure. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_CreateEntity(const char *pszEntity, float x, float y, float z, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "entity_create %s %g %g %g", pszEntity, x, y, z); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to create an entity at +// a given (x, y, z) coordinate. +// Input : pszNodeClass - Class name of node to create, ie "info_node". +// nID - Unique ID to assign the node. +// x, y, z - World coordinates at which to create node. +// Output : Returns Editor_OK on success, an error code on failure. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_CreateNode(const char *pszNodeClass, int nID, float x, float y, float z, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "node_create %s %d %g %g %g", pszNodeClass, nID, x, y, z); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to create an entity at +// a given (x, y, z) coordinate. +// Input : pszNodeClass - Class name of node to create, ie "info_node". +// nID - Unique ID to assign the node. +// x, y, z - World coordinates at which to create node. +// Output : Returns Editor_OK on success, an error code on failure. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_CreateNodeLink(int nStartID, int nEndID, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "nodelink_create %d %d", nStartID, nEndID); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to delete an entity at +// a given (x, y, z) coordinate. +// Input : pszEntity - Class name of entity to delete, ie "info_player_start". +// x, y, z - World coordinates of entity to delete. +// Output : Returns Editor_OK on success, an error code on failure. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_DeleteEntity(const char *pszEntity, float x, float y, float z, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "entity_delete %s %g %g %g", pszEntity, x, y, z); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +// sets an arbitrary key/value pair in the entity +EditorSendResult_t Editor_SetKeyValue(const char *pszEntity, float x, float y, float z, const char *pKey, const char *pValue, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "entity_set_keyvalue %s %f %f %f \"%s\" \"%s\"", pszEntity, x, y, z, pKey, pValue); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +// applies an incremental rotation to an entity +EditorSendResult_t Editor_RotateEntity(const char *pszEntity, float x, float y, float z, const QAngle &incrementalRotation, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "entity_rotate_incremental %s %f %f %f %f %f %f", pszEntity, x, y, z, incrementalRotation.x, incrementalRotation.y, incrementalRotation.z ); + return(Editor_SendCommand(szCommand, bShowUI)); +} +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to delete an entity at +// a given (x, y, z) coordinate. +// Input : nID - unique ID of node to delete. +// Output : Returns Editor_OK on success, an error code on failure. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_DeleteNode(int nID, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "node_delete %d", nID); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to delete an entity at +// a given (x, y, z) coordinate. +// Input : nStartID - unique ID of one node that the link is connected to. +// nEndID - unique ID of the other node that the link is connected to. +// Output : Returns Editor_OK on success, an error code on failure. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_DeleteNodeLink(int nStartID, int nEndID, bool bShowUI) +{ + char szCommand[MAX_COMMAND_BUFFER]; + Q_snprintf(szCommand,sizeof(szCommand), "nodelink_delete %d %d", nStartID, nEndID); + return(Editor_SendCommand(szCommand, bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a command to the editor (if running) to end the current remote +// editing session. +// Output : Returns Editor_OK on success, an error code if the session was rejected. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_EndSession(bool bShowUI) +{ + return(Editor_SendCommand("session_end", bShowUI)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Attempts to sends a shell command to the editor. +// Input : pszCommand - Shell command to send. +// bShowUI - Whether to display mesage boxes on failure. +// Output : Returns one of the following values: +// Editor_OK - The command was executed successfully. +// Editor_NotRunning - Unable to establish a communications channel with the editor. +// Editor_BadCommand - The editor did not accept the command. +//----------------------------------------------------------------------------- +EditorSendResult_t Editor_SendCommand(const char *pszCommand, bool bShowUI) +{ +#ifdef _WIN32 + HWND hwnd = FindWindow("Worldcraft_ShellMessageWnd", "Worldcraft_ShellMessageWnd"); + if (hwnd != NULL) + { + // + // Fill out the data structure to send to the editor. + // + + COPYDATASTRUCT CopyData; + CopyData.cbData = strlen(pszCommand) + 1; + CopyData.dwData = 0; + CopyData.lpData = (void *)pszCommand; + + if (!SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&CopyData)) + { + if (bShowUI) + { + char szError[1024]; + Q_snprintf(szError,sizeof(szError), "Worldcraft did not accept the command: \n\n\"%s\"\n\n Make sure the command is valid and that Worldcraft is still running properly.", pszCommand); + MessageBox(NULL, szError, "Editor_SendCommand Error", MB_OK); + } + + return(Editor_BadCommand); + } + } + else + { + if (bShowUI) + { + char szError[1024]; + Q_snprintf(szError,sizeof(szError), "Could not contact Worldcraft to send the command: \n\n\"%s\"\n\n Worldcraft does not appear to be running.", pszCommand); + MessageBox(NULL, szError, "Editor_SendCommand Error", MB_OK); + } + + return(Editor_NotRunning); + } +#endif + + return(Editor_OK); +} + +#endif // !_STATIC_LINKED || _SHARED_LIB diff --git a/public/editor_sendcommand.h b/public/editor_sendcommand.h new file mode 100644 index 0000000..3c944eb --- /dev/null +++ b/public/editor_sendcommand.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines an interface to the map editor for the execution of +// editor shell commands from another application. Commands allow the +// creation and deletion of entities, AI nodes, and AI node connections. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EDITOR_SENDCOMMAND_H +#define EDITOR_SENDCOMMAND_H +#pragma once + +class QAngle; + +// +// Result codes from Worldcraft_SendCommand. +// +enum EditorSendResult_t +{ + Editor_OK = 0, // Success. + Editor_NotRunning, // Unable to establish a communications channel with the editor. + Editor_BadCommand, // The editor did not accept the command. +}; + + +// +// Wrappers around specific commands for convenience. +// +EditorSendResult_t Editor_BeginSession(const char *pszMapName, int nMapVersion, bool bShowUI = false); +EditorSendResult_t Editor_EndSession(bool bShowUI); +EditorSendResult_t Editor_CheckVersion(const char *pszMapName, int nMapVersion, bool bShowUI = false); + +EditorSendResult_t Editor_CreateEntity(const char *pszEntity, float x, float y, float z, bool bShowUI = false); +EditorSendResult_t Editor_DeleteEntity(const char *pszEntity, float x, float y, float z, bool bShowUI = false); +EditorSendResult_t Editor_SetKeyValue(const char *pszEntity, float x, float y, float z, const char *pKey, const char *pValue, bool bShowUI = false); +EditorSendResult_t Editor_RotateEntity(const char *pszEntity, float x, float y, float z, const QAngle &incrementalRotation, bool bShowUI = false); + +EditorSendResult_t Editor_CreateNode(const char *pszNodeClass, int nID, float x, float y, float z, bool bShowUI = false); +EditorSendResult_t Editor_DeleteNode(int nID, bool bShowUI = false); + +EditorSendResult_t Editor_CreateNodeLink(int nStartID, int nEndID, bool bShowUI = false); +EditorSendResult_t Editor_DeleteNodeLink(int nStartID, int nEndID, bool bShowUI = false); + + +// +// Actually does the work. All the above commands route through this. +// +EditorSendResult_t Editor_SendCommand(const char *pszCommand, bool bShowUI); + + +#endif // EDITOR_SENDCOMMAND_H diff --git a/public/eiface.h b/public/eiface.h new file mode 100644 index 0000000..0a854e6 --- /dev/null +++ b/public/eiface.h @@ -0,0 +1,763 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef EIFACE_H +#define EIFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "icvar.h" +#include "edict.h" +#include "mathlib/vplane.h" +#include "iserverentity.h" +#include "engine/ivmodelinfo.h" +#include "soundflags.h" +#include "bitvec.h" +#include "engine/iserverplugin.h" +#include "tier1/bitbuf.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct typedescription_t; +class CSaveRestoreData; +struct datamap_t; +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +struct studiohdr_t; +class CBaseEntity; +class CRestore; +class CSave; +class variant_t; +struct vcollide_t; +class IRecipientFilter; +class CBaseEntity; +class ITraceFilter; +struct client_textmessage_t; +class INetChannelInfo; +class ISpatialPartition; +class IScratchPad3D; +class CStandardSendProxies; +class IAchievementMgr; +class CGamestatsData; +class CSteamID; +class IReplayFactory; +class IReplaySystem; +class IServer; +class IGet; +class CGMODDataTable; + +typedef struct player_info_s player_info_t; + +//----------------------------------------------------------------------------- +// defines +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +#define DLLEXPORT __stdcall +#else +#define DLLEXPORT /* */ +#endif + +#define INTERFACEVERSION_VENGINESERVER "VEngineServer021" +#define INTERFACEVERSION_VENGINESERVER_INT 21 + +struct bbox_t +{ + Vector mins; + Vector maxs; +}; + +//----------------------------------------------------------------------------- +// Purpose: Interface the engine exposes to the game DLL +//----------------------------------------------------------------------------- +abstract_class IVEngineServer +{ +public: + // Tell engine to change level ( "changelevel s1\n" or "changelevel2 s1 s2\n" ) + virtual void ChangeLevel( const char *s1, const char *s2 ) = 0; + + // Ask engine whether the specified map is a valid map file (exists and has valid version number). + virtual int IsMapValid( const char *filename ) = 0; + + // Is this a dedicated server? + virtual bool IsDedicatedServer( void ) = 0; + + // Is in Hammer editing mode? + virtual int IsInEditMode( void ) = 0; + + // Add to the server/client lookup/precache table, the specified string is given a unique index + // NOTE: The indices for PrecacheModel are 1 based + // a 0 returned from those methods indicates the model or sound was not correctly precached + // However, generic and decal are 0 based + // If preload is specified, the file is loaded into the server/client's cache memory before level startup, otherwise + // it'll only load when actually used (which can cause a disk i/o hitch if it occurs during play of a level). + virtual int PrecacheModel( const char *s, bool preload = false ) = 0; + virtual int PrecacheSentenceFile( const char *s, bool preload = false ) = 0; + virtual int PrecacheDecal( const char *name, bool preload = false ) = 0; + virtual int PrecacheGeneric( const char *s, bool preload = false ) = 0; + + // Check's if the name is precached, but doesn't actually precache the name if not... + virtual bool IsModelPrecached( char const *s ) const = 0; + virtual bool IsDecalPrecached( char const *s ) const = 0; + virtual bool IsGenericPrecached( char const *s ) const = 0; + + // Note that sounds are precached using the IEngineSound interface + + // Special purpose PVS checking + // Get the cluster # for the specified position + virtual int GetClusterForOrigin( const Vector &org ) = 0; + // Get the PVS bits for a specified cluster and copy the bits into outputpvs. Returns the number of bytes needed to pack the PVS + virtual int GetPVSForCluster( int cluster, int outputpvslength, unsigned char *outputpvs ) = 0; + // Check whether the specified origin is inside the specified PVS + virtual bool CheckOriginInPVS( const Vector &org, const unsigned char *checkpvs, int checkpvssize ) = 0; + // Check whether the specified worldspace bounding box is inside the specified PVS + virtual bool CheckBoxInPVS( const Vector &mins, const Vector &maxs, const unsigned char *checkpvs, int checkpvssize ) = 0; + + // Returns the server assigned userid for this player. Useful for logging frags, etc. + // returns -1 if the edict couldn't be found in the list of players. + virtual int GetPlayerUserId( const edict_t *e ) = 0; + virtual const char *GetPlayerNetworkIDString( const edict_t *e ) = 0; + + // Return the current number of used edict slots + virtual int GetEntityCount( void ) = 0; + // Given an edict, returns the entity index + virtual int IndexOfEdict( const edict_t *pEdict ) = 0; + // Given and entity index, returns the corresponding edict pointer + virtual edict_t *PEntityOfEntIndex( int iEntIndex ) = 0; + + // Get stats info interface for a client netchannel + virtual INetChannelInfo* GetPlayerNetInfo( int playerIndex ) = 0; + + // Allocate space for string and return index/offset of string in global string list + // If iForceEdictIndex is not -1, then it will return the edict with that index. If that edict index + // is already used, it'll return null. + virtual edict_t *CreateEdict( int iForceEdictIndex = -1 ) = 0; + // Remove the specified edict and place back into the free edict list + virtual void RemoveEdict( edict_t *e ) = 0; + + // Memory allocation for entity class data + virtual void *PvAllocEntPrivateData( long cb ) = 0; + virtual void FreeEntPrivateData( void *pEntity ) = 0; + + // Save/restore uses a special memory allocator (which zeroes newly allocated memory, etc.) + virtual void *SaveAllocMemory( size_t num, size_t size ) = 0; + virtual void SaveFreeMemory( void *pSaveMem ) = 0; + + // Emit an ambient sound associated with the specified entity + virtual void EmitAmbientSound( int entindex, const Vector &pos, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float delay = 0.0f ) = 0; + + // Fade out the client's volume level toward silence (or fadePercent) + virtual void FadeClientVolume( const edict_t *pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ) = 0; + + // Sentences / sentence groups + virtual int SentenceGroupPick( int groupIndex, char *name, int nameBufLen ) = 0; + virtual int SentenceGroupPickSequential( int groupIndex, char *name, int nameBufLen, int sentenceIndex, int reset ) = 0; + virtual int SentenceIndexFromName( const char *pSentenceName ) = 0; + virtual const char *SentenceNameFromIndex( int sentenceIndex ) = 0; + virtual int SentenceGroupIndexFromName( const char *pGroupName ) = 0; + virtual const char *SentenceGroupNameFromIndex( int groupIndex ) = 0; + virtual float SentenceLength( int sentenceIndex ) = 0; + + // Issue a command to the command parser as if it was typed at the server console. + virtual void ServerCommand( const char *str ) = 0; + // Execute any commands currently in the command parser immediately (instead of once per frame) + virtual void ServerExecute( void ) = 0; + // Issue the specified command to the specified client (mimics that client typing the command at the console). + virtual void ClientCommand( edict_t *pEdict, PRINTF_FORMAT_STRING const char *szFmt, ... ) = 0; + + // Set the lightstyle to the specified value and network the change to any connected clients. Note that val must not + // change place in memory (use MAKE_STRING) for anything that's not compiled into your mod. + virtual void LightStyle( int style, const char *val ) = 0; + + // Project a static decal onto the specified entity / model (for level placed decals in the .bsp) + virtual void StaticDecal( const Vector &originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority ) = 0; + + // Given the current PVS(or PAS) and origin, determine which players should hear/receive the message + virtual void Message_DetermineMulticastRecipients( bool usepas, const Vector& origin, CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ) = 0; + + // Begin a message from a server side entity to its client side counterpart (func_breakable glass, e.g.) + virtual bf_write *EntityMessageBegin( int ent_index, ServerClass * ent_class, bool reliable ) = 0; + // Begin a usermessage from the server to the client .dll + virtual bf_write *UserMessageBegin( IRecipientFilter *filter, int msg_type ) = 0; + // Finish the Entity or UserMessage and dispatch to network layer + virtual void MessageEnd( void ) = 0; + + // Print szMsg to the client console. + virtual void ClientPrintf( edict_t *pEdict, const char *szMsg ) = 0; + + // SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this) + // Prints the formatted string to the notification area of the screen ( down the right hand edge + // numbered lines starting at position 0 + virtual void Con_NPrintf( int pos, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + // SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this) + // Similar to Con_NPrintf, but allows specifying custom text color and duration information + virtual void Con_NXPrintf( const struct con_nprint_s *info, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // Change a specified player's "view entity" (i.e., use the view entity position/orientation for rendering the client view) + virtual void SetView( const edict_t *pClient, const edict_t *pViewent ) = 0; + + // Get a high precision timer for doing profiling work + virtual float Time( void ) = 0; + + // Set the player's crosshair angle + virtual void CrosshairAngle( const edict_t *pClient, float pitch, float yaw ) = 0; + + // Get the current game directory (hl2, tf2, hl1, cstrike, etc.) + virtual void GetGameDir( char *szGetGameDir, int maxlength ) = 0; + + // Used by AI node graph code to determine if .bsp and .ain files are out of date + virtual int CompareFileTime( const char *filename1, const char *filename2, int *iCompare ) = 0; + + // Locks/unlocks the network string tables (.e.g, when adding bots to server, this needs to happen). + // Be sure to reset the lock after executing your code!!! + virtual bool LockNetworkStringTables( bool lock ) = 0; + + // Create a bot with the given name. Returns NULL if fake client can't be created + virtual edict_t *CreateFakeClient( const char *netname ) = 0; + + // Get a convar keyvalue for s specified client + virtual const char *GetClientConVarValue( int clientIndex, const char *name ) = 0; + + // Parse a token from a file + virtual const char *ParseFile( const char *data, char *token, int maxlen ) = 0; + // Copies a file + virtual bool CopyFile( const char *source, const char *destination ) = 0; + + // Reset the pvs, pvssize is the size in bytes of the buffer pointed to by pvs. + // This should be called right before any calls to AddOriginToPVS + virtual void ResetPVS( byte *pvs, int pvssize ) = 0; + // Merge the pvs bits into the current accumulated pvs based on the specified origin ( not that each pvs origin has an 8 world unit fudge factor ) + virtual void AddOriginToPVS( const Vector &origin ) = 0; + + // Mark a specified area portal as open/closed. + // Use SetAreaPortalStates if you want to set a bunch of them at a time. + virtual void SetAreaPortalState( int portalNumber, int isOpen ) = 0; + + // Queue a temp entity for transmission + virtual void PlaybackTempEntity( IRecipientFilter& filter, float delay, const void *pSender, const SendTable *pST, int classID ) = 0; + // Given a node number and the specified PVS, return with the node is in the PVS + virtual int CheckHeadnodeVisible( int nodenum, const byte *pvs, int vissize ) = 0; + // Using area bits, cheeck whether area1 flows into area2 and vice versa (depends on area portal state) + virtual int CheckAreasConnected( int area1, int area2 ) = 0; + // Given an origin, determine which area index the origin is within + virtual int GetArea( const Vector &origin ) = 0; + // Get area portal bit set + virtual void GetAreaBits( int area, unsigned char *bits, int buflen ) = 0; + // Given a view origin (which tells us the area to start looking in) and a portal key, + // fill in the plane that leads out of this area (it points into whatever area it leads to). + virtual bool GetAreaPortalPlane( Vector const &vViewOrigin, int portalKey, VPlane *pPlane ) = 0; + + // Save/restore wrapper - FIXME: At some point we should move this to it's own interface + virtual bool LoadGameState( char const *pMapName, bool createPlayers ) = 0; + virtual void LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName ) = 0; + virtual void ClearSaveDir() = 0; + + // Get the pristine map entity lump string. (e.g., used by CS to reload the map entities when restarting a round.) + virtual const char* GetMapEntitiesString() = 0; + + // Text message system -- lookup the text message of the specified name + virtual client_textmessage_t *TextMessageGet( const char *pName ) = 0; + + // Print a message to the server log file + virtual void LogPrint( const char *msg ) = 0; + + // Builds PVS information for an entity + virtual void BuildEntityClusterList( edict_t *pEdict, PVSInfo_t *pPVSInfo ) = 0; + + // A solid entity moved, update spatial partition + virtual void SolidMoved( edict_t *pSolidEnt, ICollideable *pSolidCollide, const Vector* pPrevAbsOrigin, bool testSurroundingBoundsOnly ) = 0; + // A trigger entity moved, update spatial partition + virtual void TriggerMoved( edict_t *pTriggerEnt, bool testSurroundingBoundsOnly ) = 0; + + // Create/destroy a custom spatial partition + virtual ISpatialPartition *CreateSpatialPartition( const Vector& worldmin, const Vector& worldmax ) = 0; + virtual void DestroySpatialPartition( ISpatialPartition * ) = 0; + + // Draw the brush geometry in the map into the scratch pad. + // Flags is currently unused. + virtual void DrawMapToScratchPad( IScratchPad3D *pPad, unsigned long iFlags ) = 0; + + // This returns which entities, to the best of the server's knowledge, the client currently knows about. + // This is really which entities were in the snapshot that this client last acked. + // This returns a bit vector with one bit for each entity. + // + // USE WITH CARE. Whatever tick the client is really currently on is subject to timing and + // ordering differences, so you should account for about a quarter-second discrepancy in here. + // Also, this will return NULL if the client doesn't exist or if this client hasn't acked any frames yet. + // + // iClientIndex is the CLIENT index, so if you use pPlayer->entindex(), subtract 1. + virtual const CBitVec* GetEntityTransmitBitsForClient( int iClientIndex ) = 0; + + // Is the game paused? + virtual bool IsPaused() = 0; + + // Marks the filename for consistency checking. This should be called after precaching the file. + virtual void ForceExactFile( const char *s ) = 0; + virtual void ForceModelBounds( const char *s, const Vector &mins, const Vector &maxs ) = 0; + virtual void ClearSaveDirAfterClientLoad() = 0; + + // Sets a USERINFO client ConVar for a fakeclient + virtual void SetFakeClientConVarValue( edict_t *pEntity, const char *cvar, const char *value ) = 0; + + // Marks the material (vmt file) for consistency checking. If the client and server have different + // contents for the file, the client's vmt can only use the VertexLitGeneric shader, and can only + // contain $baseTexture and $bumpmap vars. + virtual void ForceSimpleMaterial( const char *s ) = 0; + + // Is the engine in Commentary mode? + virtual int IsInCommentaryMode( void ) = 0; + + + // Mark some area portals as open/closed. It's more efficient to use this + // than a bunch of individual SetAreaPortalState calls. + virtual void SetAreaPortalStates( const int *portalNumbers, const int *isOpen, int nPortals ) = 0; + + // Called when relevant edict state flags change. + virtual void NotifyEdictFlagsChange( int iEdict ) = 0; + + // Only valid during CheckTransmit. Also, only the PVS, networked areas, and + // m_pTransmitInfo are valid in the returned strucutre. + virtual const CCheckTransmitInfo* GetPrevCheckTransmitInfo( edict_t *pPlayerEdict ) = 0; + + virtual CSharedEdictChangeInfo* GetSharedEdictChangeInfo() = 0; + + // Tells the engine we can immdiately re-use all edict indices + // even though we may not have waited enough time + virtual void AllowImmediateEdictReuse( ) = 0; + + // Returns true if the engine is an internal build. i.e. is using the internal bugreporter. + virtual bool IsInternalBuild( void ) = 0; + + virtual IChangeInfoAccessor *GetChangeAccessor( const edict_t *pEdict ) = 0; + + // Name of most recently load .sav file + virtual char const *GetMostRecentlyLoadedFileName() = 0; + virtual char const *GetSaveFileName() = 0; + + // Matchmaking + virtual void MultiplayerEndGame() = 0; + virtual void ChangeTeam( const char *pTeamName ) = 0; + + // Cleans up the cluster list + virtual void CleanUpEntityClusterList( PVSInfo_t *pPVSInfo ) = 0; + + virtual void SetAchievementMgr( IAchievementMgr *pAchievementMgr ) =0; + virtual IAchievementMgr *GetAchievementMgr() = 0; + + virtual int GetAppID() = 0; + + virtual bool IsLowViolence() = 0; + + // Call this to find out the value of a cvar on the client. + // + // It is an asynchronous query, and it will call IServerGameDLL::OnQueryCvarValueFinished when + // the value comes in from the client. + // + // Store the return value if you want to match this specific query to the OnQueryCvarValueFinished call. + // Returns InvalidQueryCvarCookie if the entity is invalid. + virtual QueryCvarCookie_t StartQueryCvarValue( edict_t *pPlayerEntity, const char *pName ) = 0; + + virtual void InsertServerCommand( const char *str ) = 0; + + // Fill in the player info structure for the specified player index (name, model, etc.) + virtual bool GetPlayerInfo( int ent_num, player_info_t *pinfo ) = 0; + + // Returns true if this client has been fully authenticated by Steam + virtual bool IsClientFullyAuthenticated( edict_t *pEdict ) = 0; + + // This makes the host run 1 tick per frame instead of checking the system timer to see how many ticks to run in a certain frame. + // i.e. it does the same thing timedemo does. + virtual void SetDedicatedServerBenchmarkMode( bool bBenchmarkMode ) = 0; + + // Methods to set/get a gamestats data container so client & server running in same process can send combined data + virtual void SetGamestatsData( CGamestatsData *pGamestatsData ) = 0; + virtual CGamestatsData *GetGamestatsData() = 0; + + // Returns the SteamID of the specified player. It'll be NULL if the player hasn't authenticated yet. + virtual const CSteamID *GetClientSteamID( edict_t *pPlayerEdict ) = 0; + + // Returns the SteamID of the game server + virtual const CSteamID *GetGameServerSteamID() = 0; + + // Send a client command keyvalues + // keyvalues are deleted inside the function + virtual void ClientCommandKeyValues( edict_t *pEdict, KeyValues *pCommand ) = 0; + + // Returns the SteamID of the specified player. It'll be NULL if the player hasn't authenticated yet. + virtual const CSteamID *GetClientSteamIDByPlayerIndex( int entnum ) = 0; + // Gets a list of all clusters' bounds. Returns total number of clusters. + virtual int GetClusterCount() = 0; + virtual int GetAllClusterBounds( bbox_t *pBBoxList, int maxBBox ) = 0; + + // Create a bot with the given name. Returns NULL if fake client can't be created + virtual edict_t *CreateFakeClientEx( const char *netname, bool bReportFakeClient = true ) = 0; + + // Server version from the steam.inf, this will be compared to the GC version + virtual int GetServerVersion() const = 0; + + virtual float *GMOD_SetTimeManipulator( float fScaleFramerate ) = 0; + virtual void GMOD_SendToClient( IRecipientFilter *filter, const void *data, int dataSize ) = 0; + virtual void GMOD_SendToClient( int client, const void *data, int dataSize ) = 0; + virtual void GMOD_RawServerCommand( const char *command ) = 0; + virtual CGMODDataTable *GMOD_CreateDataTable() = 0; + virtual void GMOD_DestroyDataTable( CGMODDataTable *dataTable ) = 0; + virtual const char *GMOD_GetServerAddress() const = 0; + virtual void *GMOD_LoadModel( const char *path ) = 0; + + virtual void *GetReplay() const = 0; +}; + + +#define INTERFACEVERSION_SERVERGAMEDLL_VERSION_8 "ServerGameDLL008" +#define INTERFACEVERSION_SERVERGAMEDLL "ServerGameDLL009" +#define INTERFACEVERSION_SERVERGAMEDLL_INT 9 + +class IServerGCLobby; + +//----------------------------------------------------------------------------- +// Purpose: These are the interfaces that the game .dll exposes to the engine +//----------------------------------------------------------------------------- +abstract_class IServerGameDLL +{ +public: + // Why Garry's Mod, why?!! Not backwards compatible... + virtual void PreInit( CreateInterfaceFn, IGet * ) = 0; + + // Initialize the game (one-time call when the DLL is first loaded ) + // Return false if there is an error during startup. + virtual bool DLLInit( CreateInterfaceFn engineFactory, + CreateInterfaceFn physicsFactory, + CreateInterfaceFn fileSystemFactory, + CGlobalVars *pGlobals) = 0; + + // Setup replay interfaces on the server + virtual bool ReplayInit( CreateInterfaceFn fnReplayFactory ) = 0; + + // This is called when a new game is started. (restart, map) + virtual bool GameInit( void ) = 0; + + // Called any time a new level is started (after GameInit() also on level transitions within a game) + virtual bool LevelInit( char const *pMapName, + char const *pMapEntities, char const *pOldLevel, + char const *pLandmarkName, bool loadGame, bool background ) = 0; + + // The server is about to activate + virtual void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) = 0; + + // The server should run physics/think on all edicts + virtual void GameFrame( bool simulating ) = 0; + + // Called once per simulation frame on the final tick + virtual void PreClientUpdate( bool simulating ) = 0; + + // Called when a level is shutdown (including changing levels) + virtual void LevelShutdown( void ) = 0; + // This is called when a game ends (server disconnect, death, restart, load) + // NOT on level transitions within a game + virtual void GameShutdown( void ) = 0; + + // Called once during DLL shutdown + virtual void DLLShutdown( void ) = 0; + + // Get the simulation interval (must be compiled with identical values into both client and game .dll for MOD!!!) + // Right now this is only requested at server startup time so it can't be changed on the fly, etc. + virtual float GetTickInterval( void ) const = 0; + + // Give the list of datatable classes to the engine. The engine matches class names from here with + // edict_t::classname to figure out how to encode a class's data for networking + virtual ServerClass* GetAllServerClasses( void ) = 0; + + // Returns string describing current .dll. e.g., TeamFortress 2, Half-Life 2. + // Hey, it's more descriptive than just the name of the game directory + virtual const char *GetGameDescription( void ) = 0; + + // Let the game .dll allocate it's own network/shared string tables + virtual void CreateNetworkStringTables( void ) = 0; + + // Save/restore system hooks + virtual CSaveRestoreData *SaveInit( int size ) = 0; + virtual void SaveWriteFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveReadFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveGlobalState( CSaveRestoreData * ) = 0; + virtual void RestoreGlobalState( CSaveRestoreData * ) = 0; + virtual void PreSave( CSaveRestoreData * ) = 0; + virtual void Save( CSaveRestoreData * ) = 0; + virtual void GetSaveComment( char *comment, int maxlength, float flMinutes, float flSeconds, bool bNoTime = false ) = 0; + virtual void WriteSaveHeaders( CSaveRestoreData * ) = 0; + virtual void ReadRestoreHeaders( CSaveRestoreData * ) = 0; + virtual void Restore( CSaveRestoreData *, bool ) = 0; + virtual bool IsRestoring() = 0; + + // Returns the number of entities moved across the transition + virtual int CreateEntityTransitionList( CSaveRestoreData *, int ) = 0; + // Build the list of maps adjacent to the current map + virtual void BuildAdjacentMapList( void ) = 0; + + // Retrieve info needed for parsing the specified user message + virtual bool GetUserMessageInfo( int msg_type, char *name, int maxnamelength, int& size ) = 0; + + // Hand over the StandardSendProxies in the game DLL's module. + virtual CStandardSendProxies* GetStandardSendProxies() = 0; + + // Called once during startup, after the game .dll has been loaded and after the client .dll has also been loaded + virtual void PostInit() = 0; + // Called once per frame even when no level is loaded... + virtual void Think( bool finalTick ) = 0; + +#ifdef _XBOX + virtual void GetTitleName( const char *pMapName, char* pTitleBuff, int titleBuffSize ) = 0; +#endif + + virtual void PreSaveGameLoaded( char const *pSaveName, bool bCurrentlyInGame ) = 0; + + // Returns true if the game DLL wants the server not to be made public. + // Used by commentary system to hide multiplayer commentary servers from the master. + virtual bool ShouldHideServer( void ) = 0; + + virtual void InvalidateMdlCache() = 0; + + // * This function is new with version 6 of the interface. + // + // This is called when a query from IServerPluginHelpers::StartQueryCvarValue is finished. + // iCookie is the value returned by IServerPluginHelpers::StartQueryCvarValue. + // Added with version 2 of the interface. + virtual void OnQueryCvarValueFinished( QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue ) = 0; + + // Called after the steam API has been activated post-level startup + virtual void GameServerSteamAPIActivated( void ) = 0; + + // Called after the steam API has been shutdown post-level startup + virtual void GameServerSteamAPIShutdown( void ) = 0; + + virtual void SetServerHibernation( bool bHibernating ) = 0; + + // interface to the new GC based lobby system + virtual IServerGCLobby *GetServerGCLobby() = 0; + + // Return override string to show in the server browser + // "map" column, or NULL to just use the default value + // (the map name) + virtual const char *GetServerBrowserMapOverride() = 0; + + // Get gamedata string to send to the master serer updater. + virtual const char *GetServerBrowserGameData() = 0; + + virtual bool GMOD_CheckPassword( + unsigned long long steamID64, + const char *ipAddress, + const char *serverPassword, + const char *clientPassword, + const char *name, + char *rejectionMessage, + unsigned int rejectionMessageLen ) = 0; +}; + +typedef IServerGameDLL IServerGameDLL008; + +//----------------------------------------------------------------------------- +// Just an interface version name for the random number interface +// See vstdlib/random.h for the interface definition +// NOTE: If you change this, also change VENGINE_CLIENT_RANDOM_INTERFACE_VERSION in cdll_int.h +//----------------------------------------------------------------------------- +#define VENGINE_SERVER_RANDOM_INTERFACE_VERSION "VEngineRandom001" + +#define INTERFACEVERSION_SERVERGAMEENTS "ServerGameEnts001" +//----------------------------------------------------------------------------- +// Purpose: Interface to get at server entities +//----------------------------------------------------------------------------- +abstract_class IServerGameEnts +{ +public: + virtual ~IServerGameEnts() {} + + // Only for debugging. Set the edict base so you can get an edict's index in the debugger while debugging the game .dll + virtual void SetDebugEdictBase(edict_t *base) = 0; + + // The engine wants to mark two entities as touching + virtual void MarkEntitiesAsTouching( edict_t *e1, edict_t *e2 ) = 0; + + // Frees the entity attached to this edict + virtual void FreeContainingEntity( edict_t * ) = 0; + + // This allows the engine to get at edicts in a CGameTrace. + virtual edict_t* BaseEntityToEdict( CBaseEntity *pEnt ) = 0; + virtual CBaseEntity* EdictToBaseEntity( edict_t *pEdict ) = 0; + + // This sets a bit in pInfo for each edict in the list that wants to be transmitted to the + // client specified in pInfo. + // + // This is also where an entity can force other entities to be transmitted if it refers to them + // with ehandles. + virtual void CheckTransmit( CCheckTransmitInfo *pInfo, const unsigned short *pEdictIndices, int nEdicts ) = 0; +}; + +#define INTERFACEVERSION_SERVERGAMECLIENTS_VERSION_3 "ServerGameClients003" +#define INTERFACEVERSION_SERVERGAMECLIENTS "ServerGameClients004" + +//----------------------------------------------------------------------------- +// Purpose: Player / Client related functions +//----------------------------------------------------------------------------- +abstract_class IServerGameClients +{ +public: + // Get server maxplayers and lower bound for same + virtual void GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const = 0; + + // Client is connecting to server ( return false to reject the connection ) + // You can specify a rejection message by writing it into reject + virtual bool ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) = 0; + + // Client is going active + // If bLoadGame is true, don't spawn the player because its state is already setup. + virtual void ClientActive( edict_t *pEntity, bool bLoadGame ) = 0; + + // Client is disconnecting from server + virtual void ClientDisconnect( edict_t *pEntity ) = 0; + + // Client is connected and should be put in the game + virtual void ClientPutInServer( edict_t *pEntity, char const *playername ) = 0; + + // The client has typed a command at the console + virtual void ClientCommand( edict_t *pEntity, const CCommand &args ) = 0; + + // Sets the client index for the client who typed the command into his/her console + virtual void SetCommandClient( int index ) = 0; + + // A player changed one/several replicated cvars (name etc) + virtual void ClientSettingsChanged( edict_t *pEdict ) = 0; + + // Determine PVS origin and set PVS for the player/viewentity + virtual void ClientSetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char *pvs, int pvssize ) = 0; + + // A block of CUserCmds has arrived from the user, decode them and buffer for execution during player simulation + virtual float ProcessUsercmds( edict_t *player, bf_read *buf, int numcmds, int totalcmds, + int dropped_packets, bool ignore, bool paused ) = 0; + + // Let the game .dll do stuff after messages have been sent to all of the clients once the server frame is complete + virtual void PostClientMessagesSent_DEPRECIATED( void ) = 0; + + // For players, looks up the CPlayerState structure corresponding to the player + virtual CPlayerState *GetPlayerState( edict_t *player ) = 0; + + // Get the ear position for a specified client + virtual void ClientEarPosition( edict_t *pEntity, Vector *pEarOrigin ) = 0; + + // returns number of delay ticks if player is in Replay mode (0 = no delay) + virtual int GetReplayDelay( edict_t *player, int& entity ) = 0; + + // Anything this game .dll wants to add to the bug reporter text (e.g., the entity/model under the picker crosshair) + // can be added here + virtual void GetBugReportInfo( char *buf, int buflen ) = 0; + + // A user has had their network id setup and validated + virtual void NetworkIDValidated( const char *pszUserName, const char *pszNetworkID ) = 0; + + // The client has submitted a keyvalues command + virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ) = 0; + + // Hook for player spawning + virtual void ClientSpawned( edict_t *pPlayer ) = 0; +}; + +typedef IServerGameClients IServerGameClients003; + + +#define INTERFACEVERSION_UPLOADGAMESTATS "ServerUploadGameStats001" + +abstract_class IUploadGameStats +{ +public: + // Note that this call will block the server until the upload is completed, so use only at levelshutdown if at all. + virtual bool UploadGameStats( + char const *mapname, // Game map name + unsigned int blobversion, // Version of the binary blob data + unsigned int blobsize, // Size in bytes of blob data + const void *pvBlobData ) = 0; // Pointer to the blob data. + + // Call when created to init the CSER connection + virtual void InitConnection( void ) = 0; + + // Call periodically to poll steam for a CSER connection + virtual void UpdateConnection( void ) = 0; + + // If user has disabled stats tracking, do nothing + virtual bool IsGameStatsLoggingEnabled() = 0; + + // Gets a non-personally identifiable unique ID for this steam user, used for tracking total gameplay time across + // multiple stats sessions, but isn't trackable back to their Steam account or id. + // Buffer should be 16 bytes, ID will come back as a hexadecimal string version of a GUID + virtual void GetPseudoUniqueId( char *buf, size_t bufsize ) = 0; + + // For determining general % of users running using cyber cafe accounts... + virtual bool IsCyberCafeUser( void ) = 0; + + // Only works in single player + virtual bool IsHDREnabled( void ) = 0; +}; + +#define INTERFACEVERSION_PLUGINHELPERSCHECK "PluginHelpersCheck001" + +//----------------------------------------------------------------------------- +// Purpose: allows the game dll to control which plugin functions can be run +//----------------------------------------------------------------------------- +abstract_class IPluginHelpersCheck +{ +public: + virtual bool CreateMessage( const char *plugin, edict_t *pEntity, DIALOG_TYPE type, KeyValues *data ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Interface exposed from the client .dll back to the engine for specifying shared .dll IAppSystems (e.g., ISoundEmitterSystem) +//----------------------------------------------------------------------------- +abstract_class IServerDLLSharedAppSystems +{ +public: + virtual int Count() = 0; + virtual char const *GetDllName( int idx ) = 0; + virtual char const *GetInterfaceName( int idx ) = 0; +}; + +#define SERVER_DLL_SHARED_APPSYSTEMS "VServerDllSharedAppSystems001" + +#define INTERFACEVERSION_SERVERGAMETAGS "ServerGameTags001" + +//----------------------------------------------------------------------------- +// Purpose: querying the game dll for Server cvar tags +//----------------------------------------------------------------------------- +abstract_class IServerGameTags +{ +public: + // Get the list of cvars that require tags to show differently in the server browser + virtual void GetTaggedConVarList( KeyValues *pCvarTagList ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Provide hooks for the GC based lobby system +//----------------------------------------------------------------------------- +abstract_class IServerGCLobby +{ +public: + virtual bool HasLobby() const = 0; + virtual bool SteamIDAllowedToConnect( const CSteamID &steamId ) const = 0; + virtual void UpdateServerDetails(void) = 0; + virtual bool ShouldHibernate() = 0; +}; + +#endif // EIFACE_H diff --git a/public/eifacev21.h b/public/eifacev21.h new file mode 100644 index 0000000..7bb36cc --- /dev/null +++ b/public/eifacev21.h @@ -0,0 +1,614 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Defines entity interface between engine and DLLs. +// This header file included by engine files and DLL files. +// +// Before including this header, DLLs must: +// include edict.h +// This is conveniently done for them in extdll.h +// +// $NoKeywords: $ +// +//============================================================================= + +#ifndef EIFACEV21_H +#define EIFACEV21_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "icvar.h" +#include "edict.h" +#include "iserverentity.h" +#include "engine/ivmodelinfo.h" +#include "soundflags.h" +#include "bitvec.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct typedescription_t; +class CSaveRestoreData; +struct datamap_t; +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +struct studiohdr_t; +class CBaseEntity; +class CRestore; +class CSave; +class variant_t; +struct vcollide_t; +class bf_read; +class bf_write; +class IRecipientFilter; +class CBaseEntity; +class ITraceFilter; +struct client_textmessage_t; +class INetChannelInfo; +class ISpatialPartition; +class IScratchPad3D; +class CStandardSendProxiesV1; + + +// Terrain Modification Types +enum TerrainModType +{ + TMod_Sphere = 0, // sphere that pushes all vertices out along their normal. + TMod_Suck, + TMod_AABB +}; + +class CTerrainModParams +{ +public: + + // Flags for m_Flags. + enum + { + TMOD_SUCKTONORMAL = ( 1 << 0 ), // For TMod_Suck, suck into m_Normal rather than on +Z. + TMOD_STAYABOVEORIGINAL = ( 1 << 1 ) // For TMod_Suck, don't go below the original vert on Z. + }; + + CTerrainModParams() { m_Flags = 0; } // people always forget to init this + + Vector m_vCenter; + Vector m_vNormal; // If TMod_Suck and TMOD_SUCKTONORMAL is set. + int m_Flags; // Combination of TMOD_ flags. + float m_flRadius; + Vector m_vecMin; // Bounding box. + Vector m_vecMax; + float m_flStrength; // for TMod_Suck + float m_flMorphTime; // time over which the morph takes place +}; + +class CSpeculativeTerrainModVert +{ +public: + Vector m_vOriginal; // vertex position before any mods + Vector m_vCurrent; // current vertex position + Vector m_vNew; // vertex position if the mod were applied +}; + +//----------------------------------------------------------------------------- +// Terrain modification interface +//----------------------------------------------------------------------------- +class ITerrainMod +{ +public: + + //--------------------------------------------------------------------- + // Initialize the terrain modifier. + //--------------------------------------------------------------------- + virtual void Init( const CTerrainModParams ¶ms ) = 0; + + //--------------------------------------------------------------------- + // Apply the terrain modifier to the surface. The vertex should be + // moved from its original position to the target position. + // Return true if the position is modified. + //--------------------------------------------------------------------- + virtual bool ApplyMod( Vector &vecTargetPos, Vector const &vecOriginalPos ) = 0; + + //--------------------------------------------------------------------- + // Apply the terrain modifier to the surface. The vertex should from + // its original position toward the target position bassed on the + // morph time. + // Return true if the posistion is modified. + //--------------------------------------------------------------------- + virtual bool ApplyModAtMorphTime( Vector &vecTargetPos, const Vector&vecOriginalPos, + float flCurrentTime, float flMorphTime ) = 0; + + //--------------------------------------------------------------------- + // Get the bounding box for things that this mod can affect (note that + // it CAN move things outside of this bounding box). + //--------------------------------------------------------------------- + virtual void GetBBox( Vector &vecBBMin, Vector &vecBBMax ) = 0; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Interface the engine exposes to the game DLL +//----------------------------------------------------------------------------- +#define VENGINESERVER_INTERFACEVERSION_21 "VEngineServer021" + +namespace VEngineServerV21 +{ + +abstract_class IVEngineServer +{ +public: + // Tell engine to change level ( "changelevel s1\n" or "changelevel2 s1 s2\n" ) + virtual void ChangeLevel( const char *s1, const char *s2 ) = 0; + + // Ask engine whether the specified map is a valid map file (exists and has valid version number). + virtual int IsMapValid( const char *filename ) = 0; + + // Is this a dedicated server? + virtual bool IsDedicatedServer( void ) = 0; + + // Is in Hammer editing mode? + virtual int IsInEditMode( void ) = 0; + + // Add to the server/client lookup/precache table, the specified string is given a unique index + // NOTE: The indices for PrecacheModel are 1 based + // a 0 returned from those methods indicates the model or sound was not correctly precached + // However, generic and decal are 0 based + // If preload is specified, the file is loaded into the server/client's cache memory before level startup, otherwise + // it'll only load when actually used (which can cause a disk i/o hitch if it occurs during play of a level). + virtual int PrecacheModel( const char *s, bool preload = false ) = 0; + virtual int PrecacheSentenceFile( const char *s, bool preload = false ) = 0; + virtual int PrecacheDecal( const char *name, bool preload = false ) = 0; + virtual int PrecacheGeneric( const char *s, bool preload = false ) = 0; + + // Check's if the name is precached, but doesn't actually precache the name if not... + virtual bool IsModelPrecached( char const *s ) const = 0; + virtual bool IsDecalPrecached( char const *s ) const = 0; + virtual bool IsGenericPrecached( char const *s ) const = 0; + + // Note that sounds are precached using the IEngineSound interface + + // Special purpose PVS checking + // Get the cluster # for the specified position + virtual int GetClusterForOrigin( const Vector &org ) = 0; + // Get the PVS bits for a specified cluster and copy the bits into outputpvs. Returns the number of bytes needed to pack the PVS + virtual int GetPVSForCluster( int cluster, int outputpvslength, unsigned char *outputpvs ) = 0; + // Check whether the specified origin is inside the specified PVS + virtual bool CheckOriginInPVS( const Vector &org, const unsigned char *checkpvs, int checkpvssize ) = 0; + // Check whether the specified worldspace bounding box is inside the specified PVS + virtual bool CheckBoxInPVS( const Vector &mins, const Vector &maxs, const unsigned char *checkpvs, int checkpvssize ) = 0; + + // Returns the server assigned userid for this player. Useful for logging frags, etc. + // returns -1 if the edict couldn't be found in the list of players. + virtual int GetPlayerUserId( const edict_t *e ) = 0; + virtual const char *GetPlayerNetworkIDString( const edict_t *e ) = 0; + + // Return the current number of used edict slots + virtual int GetEntityCount( void ) = 0; + // Given an edict, returns the entity index + virtual int IndexOfEdict( const edict_t *pEdict ) = 0; + // Given and entity index, returns the corresponding edict pointer + virtual edict_t *PEntityOfEntIndex( int iEntIndex ) = 0; + + // Get stats info interface for a client netchannel + virtual INetChannelInfo* GetPlayerNetInfo( int playerIndex ) = 0; + + // Allocate space for string and return index/offset of string in global string list + // If iForceEdictIndex is not -1, then it will return the edict with that index. If that edict index + // is already used, it'll return null. + virtual edict_t *CreateEdict( int iForceEdictIndex = -1 ) = 0; + // Remove the specified edict and place back into the free edict list + virtual void RemoveEdict( edict_t *e ) = 0; + + // Memory allocation for entity class data + virtual void *PvAllocEntPrivateData( long cb ) = 0; + virtual void FreeEntPrivateData( void *pEntity ) = 0; + + // Save/restore uses a special memory allocator (which zeroes newly allocated memory, etc.) + virtual void *SaveAllocMemory( size_t num, size_t size ) = 0; + virtual void SaveFreeMemory( void *pSaveMem ) = 0; + + // Emit an ambient sound associated with the specified entity + virtual void EmitAmbientSound( int entindex, const Vector &pos, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float delay = 0.0f ) = 0; + + // Fade out the client's volume level toward silence (or fadePercent) + virtual void FadeClientVolume( const edict_t *pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ) = 0; + + // Sentences / sentence groups + virtual int SentenceGroupPick( int groupIndex, char *name, int nameBufLen ) = 0; + virtual int SentenceGroupPickSequential( int groupIndex, char *name, int nameBufLen, int sentenceIndex, int reset ) = 0; + virtual int SentenceIndexFromName( const char *pSentenceName ) = 0; + virtual const char *SentenceNameFromIndex( int sentenceIndex ) = 0; + virtual int SentenceGroupIndexFromName( const char *pGroupName ) = 0; + virtual const char *SentenceGroupNameFromIndex( int groupIndex ) = 0; + virtual float SentenceLength( int sentenceIndex ) = 0; + + // Issue a command to the command parser as if it was typed at the server console. + virtual void ServerCommand( const char *str ) = 0; + // Execute any commands currently in the command parser immediately (instead of once per frame) + virtual void ServerExecute( void ) = 0; + // Issue the specified command to the specified client (mimics that client typing the command at the console). + virtual void ClientCommand( edict_t *pEdict, PRINTF_FORMAT_STRING const char *szFmt, ... ) = 0; + + // Set the lightstyle to the specified value and network the change to any connected clients. Note that val must not + // change place in memory (use MAKE_STRING) for anything that's not compiled into your mod. + virtual void LightStyle( int style, const char *val ) = 0; + + // Project a static decal onto the specified entity / model (for level placed decals in the .bsp) + virtual void StaticDecal( const Vector &originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority ) = 0; + + // Given the current PVS(or PAS) and origin, determine which players should hear/receive the message + virtual void Message_DetermineMulticastRecipients( bool usepas, const Vector& origin, CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ) = 0; + + // Begin a message from a server side entity to its client side counterpart (func_breakable glass, e.g.) + virtual bf_write *EntityMessageBegin( int ent_index, ServerClass * ent_class, bool reliable ) = 0; + // Begin a usermessage from the server to the client .dll + virtual bf_write *UserMessageBegin( IRecipientFilter *filter, int msg_type ) = 0; + // Finish the Entity or UserMessage and dispatch to network layer + virtual void MessageEnd( void ) = 0; + + // Print szMsg to the client console. + virtual void ClientPrintf( edict_t *pEdict, const char *szMsg ) = 0; + + // SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this) + // Prints the formatted string to the notification area of the screen ( down the right hand edge + // numbered lines starting at position 0 + virtual void Con_NPrintf( int pos, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + // SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this) + // Similar to Con_NPrintf, but allows specifying custom text color and duration information + virtual void Con_NXPrintf( const struct con_nprint_s *info, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // For ConCommand parsing or parsing client commands issued by players typing at their console + // Retrieves the raw command string (untokenized) + virtual const char *Cmd_Args( void ) = 0; + // Returns the number of tokens in the command string + virtual int Cmd_Argc( void ) = 0; + // Retrieves a specified token + virtual char *Cmd_Argv( int argc ) = 0; + + // Change a specified player's "view entity" (i.e., use the view entity position/orientation for rendering the client view) + virtual void SetView( const edict_t *pClient, const edict_t *pViewent ) = 0; + + // Get a high precision timer for doing profiling work + virtual float Time( void ) = 0; + + // Set the player's crosshair angle + virtual void CrosshairAngle( const edict_t *pClient, float pitch, float yaw ) = 0; + + // Get the current game directory (hl2, tf2, hl1, cstrike, etc.) + virtual void GetGameDir( char *szGetGameDir, int maxlength ) = 0; + + // Used by AI node graph code to determine if .bsp and .ain files are out of date + virtual int CompareFileTime( const char *filename1, const char *filename2, int *iCompare ) = 0; + + // Locks/unlocks the network string tables (.e.g, when adding bots to server, this needs to happen). + // Be sure to reset the lock after executing your code!!! + virtual bool LockNetworkStringTables( bool lock ) = 0; + + // Create a bot with the given name. Returns NULL if fake client can't be created + virtual edict_t *CreateFakeClient( const char *netname ) = 0; + + // Get a convar keyvalue for s specified client + virtual const char *GetClientConVarValue( int clientIndex, const char *name ) = 0; + + // Parse a token from a file + virtual const char *ParseFile( const char *data, char *token, int maxlen ) = 0; + // Copies a file + virtual bool CopyFile( const char *source, const char *destination ) = 0; + + // Reset the pvs, pvssize is the size in bytes of the buffer pointed to by pvs. + // This should be called right before any calls to AddOriginToPVS + virtual void ResetPVS( byte *pvs, int pvssize ) = 0; + // Merge the pvs bits into the current accumulated pvs based on the specified origin ( not that each pvs origin has an 8 world unit fudge factor ) + virtual void AddOriginToPVS( const Vector &origin ) = 0; + // Mark a specified area portal as open/closes + virtual void SetAreaPortalState( int portalNumber, int isOpen ) = 0; + // Queue a temp entity for transmission + virtual void PlaybackTempEntity( IRecipientFilter& filter, float delay, const void *pSender, const SendTable *pST, int classID ) = 0; + // Given a node number and the specified PVS, return with the node is in the PVS + virtual int CheckHeadnodeVisible( int nodenum, const byte *pvs, int vissize ) = 0; + // Using area bits, cheeck whether area1 flows into area2 and vice versa (depends on area portal state) + virtual int CheckAreasConnected( int area1, int area2 ) = 0; + // Given an origin, determine which area index the origin is within + virtual int GetArea( const Vector &origin ) = 0; + // Get area portal bit set + virtual void GetAreaBits( int area, unsigned char *bits, int buflen ) = 0; + // Given a view origin (which tells us the area to start looking in) and a portal key, + // fill in the plane that leads out of this area (it points into whatever area it leads to). + virtual bool GetAreaPortalPlane( Vector const &vViewOrigin, int portalKey, VPlane *pPlane ) = 0; + + // Apply a modification to the terrain. + virtual void ApplyTerrainMod( TerrainModType type, CTerrainModParams const ¶ms ) = 0; + + // Save/restore wrapper - FIXME: At some point we should move this to it's own interface + virtual bool LoadGameState( char const *pMapName, bool createPlayers ) = 0; + virtual void LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName ) = 0; + virtual void ClearSaveDir() = 0; + + // Get the pristine map entity lump string. (e.g., used by CS to reload the map entities when restarting a round.) + virtual const char* GetMapEntitiesString() = 0; + + // Text message system -- lookup the text message of the specified name + virtual client_textmessage_t *TextMessageGet( const char *pName ) = 0; + + // Print a message to the server log file + virtual void LogPrint( const char *msg ) = 0; + + // Builds PVS information for an entity + virtual void BuildEntityClusterList( edict_t *pEdict, PVSInfo_t *pPVSInfo ) = 0; + + // A solid entity moved, update spatial partition + virtual void SolidMoved( edict_t *pSolidEnt, ICollideable *pSolidCollide, const Vector* pPrevAbsOrigin ) = 0; + // A trigger entity moved, update spatial partition + virtual void TriggerMoved( edict_t *pTriggerEnt ) = 0; + + // Create/destroy a custom spatial partition + virtual ISpatialPartition *CreateSpatialPartition( const Vector& worldmin, const Vector& worldmax ) = 0; + virtual void DestroySpatialPartition( ISpatialPartition * ) = 0; + + // Draw the brush geometry in the map into the scratch pad. + // Flags is currently unused. + virtual void DrawMapToScratchPad( IScratchPad3D *pPad, unsigned long iFlags ) = 0; + + // This returns which entities, to the best of the server's knowledge, the client currently knows about. + // This is really which entities were in the snapshot that this client last acked. + // This returns a bit vector with one bit for each entity. + // + // USE WITH CARE. Whatever tick the client is really currently on is subject to timing and + // ordering differences, so you should account for about a quarter-second discrepancy in here. + // Also, this will return NULL if the client doesn't exist or if this client hasn't acked any frames yet. + // + // iClientIndex is the CLIENT index, so if you use pPlayer->entindex(), subtract 1. + virtual const CBitVec* GetEntityTransmitBitsForClient( int iClientIndex ) = 0; + + // Is the game paused? + virtual bool IsPaused() = 0; + + // Marks the filename for consistency checking. This should be called after precaching the file. + virtual void ForceExactFile( const char *s ) = 0; + virtual void ForceModelBounds( const char *s, const Vector &mins, const Vector &maxs ) = 0; + virtual void ClearSaveDirAfterClientLoad() = 0; + + // Sets a USERINFO client ConVar for a fakeclient + virtual void SetFakeClientConVarValue( edict_t *pEntity, const char *cvar, const char *value ) = 0; + + virtual void InsertServerCommand( const char *str ) = 0; + + // Marks the material (vmt file) for consistency checking. If the client and server have different + // contents for the file, the client's vmt can only use the VertexLitGeneric shader, and can only + // contain $baseTexture and $bumpmap vars. + virtual void ForceSimpleMaterial( const char *s ) = 0; + + + // Is the engine in Commentary mode? + virtual int IsInCommentaryMode( void ) = 0; +}; + +} // end namespace + + +//----------------------------------------------------------------------------- +// Purpose: These are the interfaces that the game .dll exposes to the engine +//----------------------------------------------------------------------------- +#define SERVERGAMEDLL_INTERFACEVERSION_3 "ServerGameDLL003" + +namespace ServerGameDLLV3 +{ + +abstract_class IServerGameDLL +{ +public: + // Initialize the game (one-time call when the DLL is first loaded ) + // Return false if there is an error during startup. + virtual bool DLLInit( CreateInterfaceFn engineFactory, + CreateInterfaceFn physicsFactory, + CreateInterfaceFn fileSystemFactory, + CGlobalVars *pGlobals) = 0; + + // This is called when a new game is started. (restart, map) + virtual bool GameInit( void ) = 0; + + // Called any time a new level is started (after GameInit() also on level transitions within a game) + virtual bool LevelInit( char const *pMapName, + char const *pMapEntities, char const *pOldLevel, + char const *pLandmarkName, bool loadGame, bool background ) = 0; + + // The server is about to activate + virtual void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) = 0; + + // The server should run physics/think on all edicts + virtual void GameFrame( bool simulating ) = 0; + + // Called once per simulation frame on the final tick + virtual void PreClientUpdate( bool simulating ) = 0; + + // Called when a level is shutdown (including changing levels) + virtual void LevelShutdown( void ) = 0; + // This is called when a game ends (server disconnect, death, restart, load) + // NOT on level transitions within a game + virtual void GameShutdown( void ) = 0; + + // Called once during DLL shutdown + virtual void DLLShutdown( void ) = 0; + + // Get the simulation interval (must be compiled with identical values into both client and game .dll for MOD!!!) + // Right now this is only requested at server startup time so it can't be changed on the fly, etc. + virtual float GetTickInterval( void ) const = 0; + + // Give the list of datatable classes to the engine. The engine matches class names from here with + // edict_t::classname to figure out how to encode a class's data for networking + virtual ServerClass* GetAllServerClasses( void ) = 0; + + // Returns string describing current .dll. e.g., TeamFortress 2, Half-Life 2. + // Hey, it's more descriptive than just the name of the game directory + virtual const char *GetGameDescription( void ) = 0; + + // Let the game .dll allocate it's own network/shared string tables + virtual void CreateNetworkStringTables( void ) = 0; + + // Save/restore system hooks + virtual CSaveRestoreData *SaveInit( int size ) = 0; + virtual void SaveWriteFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveReadFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveGlobalState( CSaveRestoreData * ) = 0; + virtual void RestoreGlobalState( CSaveRestoreData * ) = 0; + virtual void PreSave( CSaveRestoreData * ) = 0; + virtual void Save( CSaveRestoreData * ) = 0; + virtual void GetSaveComment( char *comment, int maxlength ) = 0; + virtual void WriteSaveHeaders( CSaveRestoreData * ) = 0; + virtual void ReadRestoreHeaders( CSaveRestoreData * ) = 0; + virtual void Restore( CSaveRestoreData *, bool ) = 0; + virtual bool IsRestoring() = 0; + + // Returns the number of entities moved across the transition + virtual int CreateEntityTransitionList( CSaveRestoreData *, int ) = 0; + // Build the list of maps adjacent to the current map + virtual void BuildAdjacentMapList( void ) = 0; + + // Retrieve info needed for parsing the specified user message + virtual bool GetUserMessageInfo( int msg_type, char *name, int maxnamelength, int& size ) = 0; + + // Hand over the StandardSendProxies in the game DLL's module. + virtual CStandardSendProxiesV1* GetStandardSendProxies() = 0; +}; + +} // end namespace + + +//----------------------------------------------------------------------------- +// Just an interface version name for the random number interface +// See vstdlib/random.h for the interface definition +// NOTE: If you change this, also change VENGINE_CLIENT_RANDOM_INTERFACE_VERSION in cdll_int.h +//----------------------------------------------------------------------------- +#define VENGINE_SERVER_RANDOM_INTERFACE_VERSION_1 "VEngineRandom001" + +//----------------------------------------------------------------------------- +// Purpose: Interface to get at server entities +//----------------------------------------------------------------------------- +#define SERVERGAMEENTS_INTERFACEVERSION_1 "ServerGameEnts001" + +namespace ServerGameEntsV1 +{ + +abstract_class IServerGameEnts +{ +public: + virtual ~IServerGameEnts() {} + + // Only for debugging. Set the edict base so you can get an edict's index in the debugger while debugging the game .dll + virtual void SetDebugEdictBase(edict_t *base) = 0; + + // The engine wants to mark two entities as touching + virtual void MarkEntitiesAsTouching( edict_t *e1, edict_t *e2 ) = 0; + + // Frees the entity attached to this edict + virtual void FreeContainingEntity( edict_t * ) = 0; + + // This allows the engine to get at edicts in a CGameTrace. + virtual edict_t* BaseEntityToEdict( CBaseEntity *pEnt ) = 0; + virtual CBaseEntity* EdictToBaseEntity( edict_t *pEdict ) = 0; + + // This sets a bit in pInfo for each edict in the list that wants to be transmitted to the + // client specified in pInfo. + // + // This is also where an entity can force other entities to be transmitted if it refers to them + // with ehandles. + virtual void CheckTransmit( CCheckTransmitInfo *pInfo, const unsigned short *pEdictIndices, int nEdicts ) = 0; +}; + +} // end namespace ServerGameEntsV1 + + +//----------------------------------------------------------------------------- +// Purpose: Player / Client related functions +//----------------------------------------------------------------------------- +#define SERVERGAMECLIENTS_INTERFACEVERSION_3 "ServerGameClients003" + +namespace ServerGameClientsV3 +{ + +abstract_class IServerGameClients +{ +public: + // Get server maxplayers and lower bound for same + virtual void GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const = 0; + + // Client is connecting to server ( return false to reject the connection ) + // You can specify a rejection message by writing it into reject + virtual bool ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) = 0; + + // Client is going active + // If bLoadGame is true, don't spawn the player because its state is already setup. + virtual void ClientActive( edict_t *pEntity, bool bLoadGame ) = 0; + + // Client is disconnecting from server + virtual void ClientDisconnect( edict_t *pEntity ) = 0; + + // Client is connected and should be put in the game + virtual void ClientPutInServer( edict_t *pEntity, char const *playername ) = 0; + + // The client has typed a command at the console + virtual void ClientCommand( edict_t *pEntity ) = 0; + + // Sets the client index for the client who typed the command into his/her console + virtual void SetCommandClient( int index ) = 0; + + // A player changed one/several replicated cvars (name etc) + virtual void ClientSettingsChanged( edict_t *pEdict ) = 0; + + // Determine PVS origin and set PVS for the player/viewentity + virtual void ClientSetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char *pvs, int pvssize ) = 0; + + // A block of CUserCmds has arrived from the user, decode them and buffer for execution during player simulation + virtual float ProcessUsercmds( edict_t *player, bf_read *buf, int numcmds, int totalcmds, + int dropped_packets, bool ignore, bool paused ) = 0; + + // Let the game .dll do stuff after messages have been sent to all of the clients once the server frame is complete + virtual void PostClientMessagesSent_DEPRECIATED( void ) = 0; + + // For players, looks up the CPlayerState structure corresponding to the player + virtual CPlayerState *GetPlayerState( edict_t *player ) = 0; + + // Get the ear position for a specified client + virtual void ClientEarPosition( edict_t *pEntity, Vector *pEarOrigin ) = 0; + + // returns number of delay ticks if player is in Replay mode (0 = no delay) + virtual int GetReplayDelay( edict_t *player ) = 0; + + // Anything this game .dll wants to add to the bug reporter text (e.g., the entity/model under the picker crosshair) + // can be added here + virtual void GetBugReportInfo( char *buf, int buflen ) = 0; +}; + +} // end namespace ServerGameClientsV3 + + +#define UPLOADGAMESTATS_INTERFACEVERSION_1 "ServerUploadGameStats001" + +namespace UploadGameStatsV1 +{ + +abstract_class IUploadGameStats +{ +public: + // Note that this call will block the server until the upload is completed, so use only at levelshutdown if at all. + virtual bool UploadGameStats( + char const *mapname, // Game map name + unsigned int blobversion, // Version of the binary blob data + unsigned int blobsize, // Size in bytes of blob data + const void *pvBlobData ) = 0; // Pointer to the blob data. +}; + +} // end namespace UploadGameStatsV1 + + +#endif // EIFACEV21_H diff --git a/public/engine/IClientLeafSystem.h b/public/engine/IClientLeafSystem.h new file mode 100644 index 0000000..6efab6a --- /dev/null +++ b/public/engine/IClientLeafSystem.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +// +// This file contains code to allow us to associate client data with bsp leaves. +// +//=============================================================================// + +#if !defined( ICLIENTLEAFSYSTEM_H ) +#define ICLIENTLEAFSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "client_render_handle.h" + + +//----------------------------------------------------------------------------- +// Render groups +//----------------------------------------------------------------------------- +enum RenderGroup_Config_t +{ + // Number of buckets that are used to hold opaque entities + // and opaque static props by size. The bucketing should be used to reduce overdraw. + RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS = 4, +}; + +enum RenderGroup_t +{ + RENDER_GROUP_OPAQUE_STATIC_HUGE = 0, // Huge static prop + RENDER_GROUP_OPAQUE_ENTITY_HUGE = 1, // Huge opaque entity + RENDER_GROUP_OPAQUE_STATIC = RENDER_GROUP_OPAQUE_STATIC_HUGE + ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1 ) * 2, + RENDER_GROUP_OPAQUE_ENTITY, // Opaque entity (smallest size, or default) + + RENDER_GROUP_TRANSLUCENT_ENTITY, + RENDER_GROUP_TWOPASS, // Implied opaque and translucent in two passes + RENDER_GROUP_VIEW_MODEL_OPAQUE, // Solid weapon view models + RENDER_GROUP_VIEW_MODEL_TRANSLUCENT, // Transparent overlays etc + + RENDER_GROUP_OPAQUE_BRUSH, // Brushes + + RENDER_GROUP_OTHER, // Unclassfied. Won't get drawn. + + // This one's always gotta be last + RENDER_GROUP_COUNT +}; + +#define CLIENTLEAFSYSTEM_INTERFACE_VERSION_1 "ClientLeafSystem001" +#define CLIENTLEAFSYSTEM_INTERFACE_VERSION "ClientLeafSystem002" + + +//----------------------------------------------------------------------------- +// The client leaf system +//----------------------------------------------------------------------------- +abstract_class IClientLeafSystemEngine +{ +public: + // Adds and removes renderables from the leaf lists + // CreateRenderableHandle stores the handle inside pRenderable. + virtual void CreateRenderableHandle( IClientRenderable* pRenderable, bool bIsStaticProp = false ) = 0; + virtual void RemoveRenderable( ClientRenderHandle_t handle ) = 0; + virtual void AddRenderableToLeaves( ClientRenderHandle_t renderable, int nLeafCount, unsigned short *pLeaves ) = 0; + virtual void ChangeRenderableRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ) = 0; +}; + + +#endif // ICLIENTLEAFSYSTEM_H + + diff --git a/public/engine/ICollideable.h b/public/engine/ICollideable.h new file mode 100644 index 0000000..8906e5a --- /dev/null +++ b/public/engine/ICollideable.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENGINE_ICOLLIDEABLE_H +#define ENGINE_ICOLLIDEABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +enum SolidType_t; +class IHandleEntity; +struct Ray_t; +struct model_t; +class Vector; +class QAngle; +class CGameTrace; +typedef CGameTrace trace_t; +class IClientUnknown; + + +abstract_class ICollideable +{ +public: + // Gets at the entity handle associated with the collideable + virtual IHandleEntity *GetEntityHandle() = 0; + + // These methods return the bounds of an OBB measured in "collision" space + // which can be retreived through the CollisionToWorldTransform or + // GetCollisionOrigin/GetCollisionAngles methods + virtual const Vector& OBBMinsPreScaled() const = 0; + virtual const Vector& OBBMaxsPreScaled() const = 0; + virtual const Vector& OBBMins() const = 0; + virtual const Vector& OBBMaxs() const = 0; + + // Returns the bounds of a world-space box used when the collideable is being traced + // against as a trigger. It's only valid to call these methods if the solid flags + // have the FSOLID_USE_TRIGGER_BOUNDS flag set. + virtual void WorldSpaceTriggerBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) const = 0; + + // custom collision test + virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) = 0; + + // Perform hitbox test, returns true *if hitboxes were tested at all*!! + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) = 0; + + // Returns the BRUSH model index if this is a brush model. Otherwise, returns -1. + virtual int GetCollisionModelIndex() = 0; + + // Return the model, if it's a studio model. + virtual const model_t* GetCollisionModel() = 0; + + // Get angles and origin. + virtual const Vector& GetCollisionOrigin() const = 0; + virtual const QAngle& GetCollisionAngles() const = 0; + virtual const matrix3x4_t& CollisionToWorldTransform() const = 0; + + // Return a SOLID_ define. + virtual SolidType_t GetSolid() const = 0; + virtual int GetSolidFlags() const = 0; + + // Gets at the containing class... + virtual IClientUnknown* GetIClientUnknown() = 0; + + // We can filter out collisions based on collision group + virtual int GetCollisionGroup() const = 0; + + // Returns a world-aligned box guaranteed to surround *everything* in the collision representation + // Note that this will surround hitboxes, trigger bounds, physics. + // It may or may not be a tight-fitting box and its volume may suddenly change + virtual void WorldSpaceSurroundingBounds( Vector *pVecMins, Vector *pVecMaxs ) = 0; + + virtual bool ShouldTouchTrigger( int triggerSolidFlags ) const = 0; + + // returns NULL unless this collideable has specified FSOLID_ROOT_PARENT_ALIGNED + virtual const matrix3x4_t *GetRootParentToWorldTransform() const = 0; +}; + + +#endif // ENGINE_ICOLLIDEABLE_H diff --git a/public/engine/IEngineSound.h b/public/engine/IEngineSound.h new file mode 100644 index 0000000..ce8ac15 --- /dev/null +++ b/public/engine/IEngineSound.h @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client-server neutral sound interface +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IENGINESOUND_H +#define IENGINESOUND_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "basetypes.h" +#include "interface.h" +#include "soundflags.h" +#include "irecipientfilter.h" +#include "utlvector.h" +#include "engine/SndInfo.h" + +//----------------------------------------------------------------------------- +// forward declaration +//----------------------------------------------------------------------------- +class Vector; + +// Handy defines for EmitSound +#define SOUND_FROM_UI_PANEL -2 // Sound being played inside a UI panel on the client +#define SOUND_FROM_LOCAL_PLAYER -1 +#define SOUND_FROM_WORLD 0 + + + +// These are used to feed a soundlevel to the sound system and have it use +// goldsrc-type attenuation. We should use this as little as possible and +// phase it out as soon as possible. + +// Take a regular sndlevel and convert it to compatibility mode. +#define SNDLEVEL_TO_COMPATIBILITY_MODE( x ) ((soundlevel_t)(int)( (x) + 256 )) + +// Take a compatibility-mode sndlevel and get the REAL sndlevel out of it. +#define SNDLEVEL_FROM_COMPATIBILITY_MODE( x ) ((soundlevel_t)(int)( (x) - 256 )) + +// Tells if the given sndlevel is marked as compatibility mode. +#define SNDLEVEL_IS_COMPATIBILITY_MODE( x ) ( (x) >= soundlevel_t(256) ) + + + +//----------------------------------------------------------------------------- +// Client-server neutral effects interface +//----------------------------------------------------------------------------- +#define IENGINESOUND_CLIENT_INTERFACE_VERSION "IEngineSoundClient003" +#define IENGINESOUND_SERVER_INTERFACE_VERSION "IEngineSoundServer003" + +abstract_class IEngineSound +{ +public: + // Precache a particular sample + virtual bool PrecacheSound( const char *pSample, bool bPreload = false, bool bIsUISound = false ) = 0; + virtual bool IsSoundPrecached( const char *pSample ) = 0; + virtual void PrefetchSound( const char *pSample ) = 0; + + // Just loads the file header and checks for duration (not hooked up for .mp3's yet) + // Is accessible to server and client though + virtual float GetSoundDuration( const char *pSample ) = 0; + + // Pitch of 100 is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 + // down to 1 is a lower pitch. 150 to 70 is the realistic range. + // EmitSound with pitch != 100 should be used sparingly, as it's not quite as + // fast (the pitchshift mixer is not native coded). + + // NOTE: setting iEntIndex to -1 will cause the sound to be emitted from the local + // player (client-side only) + virtual void EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, + float flVolume, float flAttenuation, int iFlags = 0, int iPitch = PITCH_NORM, int iSpecialDSP = 0, + const Vector *pOrigin = NULL, const Vector *pDirection = NULL, CUtlVector< Vector >* pUtlVecOrigins = NULL, bool bUpdatePositions = true, float soundtime = 0.0f, int speakerentity = -1 ) = 0; + + virtual void EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, + float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM, int iSpecialDSP = 0, + const Vector *pOrigin = NULL, const Vector *pDirection = NULL, CUtlVector< Vector >* pUtlVecOrigins = NULL, bool bUpdatePositions = true, float soundtime = 0.0f, int speakerentity = -1 ) = 0; + + virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex, + float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM,int iSpecialDSP = 0, + const Vector *pOrigin = NULL, const Vector *pDirection = NULL, CUtlVector< Vector >* pUtlVecOrigins = NULL, bool bUpdatePositions = true, float soundtime = 0.0f, int speakerentity = -1 ) = 0; + + virtual void StopSound( int iEntIndex, int iChannel, const char *pSample ) = 0; + + // stop all active sounds (client only) + virtual void StopAllSounds(bool bClearBuffers) = 0; + + // Set the room type for a player (client only) + virtual void SetRoomType( IRecipientFilter& filter, int roomType ) = 0; + + // Set the dsp preset for a player (client only) + virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset ) = 0; + + // emit an "ambient" sound that isn't spatialized + // only available on the client, assert on server + virtual void EmitAmbientSound( const char *pSample, float flVolume, int iPitch = PITCH_NORM, int flags = 0, float soundtime = 0.0f ) = 0; + + +// virtual EntChannel_t CreateEntChannel() = 0; + + virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist ) = 0; + + // Client .dll only functions + virtual int GetGuidForLastSoundEmitted() = 0; + virtual bool IsSoundStillPlaying( int guid ) = 0; + virtual void StopSoundByGuid( int guid ) = 0; + // Set's master volume (0.0->1.0) + virtual void SetVolumeByGuid( int guid, float fvol ) = 0; + + // Retrieves list of all active sounds + virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist ) = 0; + + virtual void PrecacheSentenceGroup( const char *pGroupName ) = 0; + virtual void NotifyBeginMoviePlayback() = 0; + virtual void NotifyEndMoviePlayback() = 0; +}; + + +#endif // IENGINESOUND_H diff --git a/public/engine/IEngineTrace.h b/public/engine/IEngineTrace.h new file mode 100644 index 0000000..6e49771 --- /dev/null +++ b/public/engine/IEngineTrace.h @@ -0,0 +1,192 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ENGINE_IENGINETRACE_H +#define ENGINE_IENGINETRACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basehandle.h" +#include "utlvector.h" //need CUtlVector for IEngineTrace::GetBrushesIn*() +#include "mathlib/vector4d.h" + +class Vector; +class IHandleEntity; +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +class ICollideable; +class QAngle; +class CTraceListData; +class CPhysCollide; +struct cplane_t; + +//----------------------------------------------------------------------------- +// The standard trace filter... NOTE: Most normal traces inherit from CTraceFilter!!! +//----------------------------------------------------------------------------- +enum TraceType_t +{ + TRACE_EVERYTHING = 0, + TRACE_WORLD_ONLY, // NOTE: This does *not* test static props!!! + TRACE_ENTITIES_ONLY, // NOTE: This version will *not* test static props + TRACE_EVERYTHING_FILTER_PROPS, // NOTE: This version will pass the IHandleEntity for props through the filter, unlike all other filters +}; + +abstract_class ITraceFilter +{ +public: + virtual bool ShouldHitEntity( IHandleEntity *pEntity, int contentsMask ) = 0; + virtual TraceType_t GetTraceType() const = 0; +}; + + +//----------------------------------------------------------------------------- +// Classes are expected to inherit these + implement the ShouldHitEntity method +//----------------------------------------------------------------------------- + +// This is the one most normal traces will inherit from +class CTraceFilter : public ITraceFilter +{ +public: + virtual TraceType_t GetTraceType() const + { + return TRACE_EVERYTHING; + } +}; + +class CTraceFilterEntitiesOnly : public ITraceFilter +{ +public: + virtual TraceType_t GetTraceType() const + { + return TRACE_ENTITIES_ONLY; + } +}; + + +//----------------------------------------------------------------------------- +// Classes need not inherit from these +//----------------------------------------------------------------------------- +class CTraceFilterWorldOnly : public ITraceFilter +{ +public: + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + return false; + } + virtual TraceType_t GetTraceType() const + { + return TRACE_WORLD_ONLY; + } +}; + +class CTraceFilterWorldAndPropsOnly : public ITraceFilter +{ +public: + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + return false; + } + virtual TraceType_t GetTraceType() const + { + return TRACE_EVERYTHING; + } +}; + +class CTraceFilterHitAll : public CTraceFilter +{ +public: + virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + return true; + } +}; + + +//----------------------------------------------------------------------------- +// Enumeration interface for EnumerateLinkEntities +//----------------------------------------------------------------------------- +abstract_class IEntityEnumerator +{ +public: + // This gets called with each handle + virtual bool EnumEntity( IHandleEntity *pHandleEntity ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Interface the engine exposes to the game DLL +//----------------------------------------------------------------------------- +#define INTERFACEVERSION_ENGINETRACE_SERVER "EngineTraceServer003" +#define INTERFACEVERSION_ENGINETRACE_CLIENT "EngineTraceClient003" +abstract_class IEngineTrace +{ +public: + // Returns the contents mask + entity at a particular world-space position + virtual int GetPointContents( const Vector &vecAbsPosition, IHandleEntity** ppEntity = NULL ) = 0; + + // Get the point contents, but only test the specific entity. This works + // on static props and brush models. + // + // If the entity isn't a static prop or a brush model, it returns CONTENTS_EMPTY and sets + // bFailed to true if bFailed is non-null. + virtual int GetPointContents_Collideable( ICollideable *pCollide, const Vector &vecAbsPosition ) = 0; + + // Traces a ray against a particular entity + virtual void ClipRayToEntity( const Ray_t &ray, unsigned int fMask, IHandleEntity *pEnt, trace_t *pTrace ) = 0; + + // Traces a ray against a particular entity + virtual void ClipRayToCollideable( const Ray_t &ray, unsigned int fMask, ICollideable *pCollide, trace_t *pTrace ) = 0; + + // A version that simply accepts a ray (can work as a traceline or tracehull) + virtual void TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + + // A version that sets up the leaf and entity lists and allows you to pass those in for collision. + virtual void SetupLeafAndEntityListRay( const Ray_t &ray, CTraceListData &traceData ) = 0; + virtual void SetupLeafAndEntityListBox( const Vector &vecBoxMin, const Vector &vecBoxMax, CTraceListData &traceData ) = 0; + virtual void TraceRayAgainstLeafAndEntityList( const Ray_t &ray, CTraceListData &traceData, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + + // A version that sweeps a collideable through the world + // abs start + abs end represents the collision origins you want to sweep the collideable through + // vecAngles represents the collision angles of the collideable during the sweep + virtual void SweepCollideable( ICollideable *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd, + const QAngle &vecAngles, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + + // Enumerates over all entities along a ray + // If triggers == true, it enumerates all triggers along a ray + virtual void EnumerateEntities( const Ray_t &ray, bool triggers, IEntityEnumerator *pEnumerator ) = 0; + + // Same thing, but enumerate entitys within a box + virtual void EnumerateEntities( const Vector &vecAbsMins, const Vector &vecAbsMaxs, IEntityEnumerator *pEnumerator ) = 0; + + // Convert a handle entity to a collideable. Useful inside enumer + virtual ICollideable *GetCollideable( IHandleEntity *pEntity ) = 0; + + // HACKHACK: Temp for performance measurments + virtual int GetStatByIndex( int index, bool bClear ) = 0; + + + //finds brushes in an AABB, prone to some false positives + virtual void GetBrushesInAABB( const Vector &vMins, const Vector &vMaxs, CUtlVector *pOutput, int iContentsMask = 0xFFFFFFFF ) = 0; + + //Creates a CPhysCollide out of all displacements wholly or partially contained in the specified AABB + virtual CPhysCollide* GetCollidableFromDisplacementsInAABB( const Vector& vMins, const Vector& vMaxs ) = 0; + + //retrieve brush planes and contents, returns true if data is being returned in the output pointers, false if the brush doesn't exist + virtual bool GetBrushInfo( int iBrush, CUtlVector *pPlanesOut, int *pContentsOut ) = 0; + + virtual bool PointOutsideWorld( const Vector &ptTest ) = 0; //Tests a point to see if it's outside any playable area + + // Walks bsp to find the leaf containing the specified point + virtual int GetLeafContainingPoint( const Vector &ptTest ) = 0; +}; + + + +#endif // ENGINE_IENGINETRACE_H diff --git a/public/engine/IStaticPropMgr.h b/public/engine/IStaticPropMgr.h new file mode 100644 index 0000000..ed6cc3c --- /dev/null +++ b/public/engine/IStaticPropMgr.h @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IPROPS_H +#define IPROPS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib/vector.h" +#include "utlvector.h" +#include "basehandle.h" + + +struct vcollide_t; +struct Ray_t; +class IClientRenderable; +class CGameTrace; +typedef CGameTrace trace_t; +class IVPhysicsKeyHandler; +class IPhysicsEnvironment; +class ICollideable; + + +//----------------------------------------------------------------------------- +// Interface versions for static props +//----------------------------------------------------------------------------- +#define INTERFACEVERSION_STATICPROPMGR_CLIENT "StaticPropMgrClient004" +#define INTERFACEVERSION_STATICPROPMGR_SERVER "StaticPropMgrServer002" + + +//----------------------------------------------------------------------------- +// Interface for static props +//----------------------------------------------------------------------------- +abstract_class IStaticPropMgr +{ +public: + // Create physics representations of props + virtual void CreateVPhysicsRepresentations( IPhysicsEnvironment *physenv, IVPhysicsKeyHandler *pDefaults, void *pGameData ) = 0; + + // Purpose: Trace a ray against the specified static Prop. Returns point of intersection in trace_t + virtual void TraceRayAgainstStaticProp( const Ray_t& ray, int staticPropIndex, trace_t& tr ) = 0; + + // Is a base handle a static prop? + virtual bool IsStaticProp( IHandleEntity *pHandleEntity ) const = 0; + virtual bool IsStaticProp( CBaseHandle handle ) const = 0; + + // returns a collideable interface to static props + virtual ICollideable *GetStaticPropByIndex( int propIndex ) = 0; +}; + +abstract_class IStaticPropMgrClient : public IStaticPropMgr +{ +public: + // Recomputes the static prop opacity given a view origin + virtual void ComputePropOpacity( const Vector &viewOrigin, float factor ) = 0; + + // Adds decals to static props, returns point of decal in trace_t + virtual void AddDecalToStaticProp( const Vector& rayStart, const Vector& rayEnd, + int staticPropIndex, int decalIndex, bool doTrace, trace_t& tr ) = 0; + // Adds/removes shadows from static props + virtual void AddShadowToStaticProp( unsigned short shadowHandle, IClientRenderable* pRenderable ) = 0; + virtual void RemoveAllShadowsFromStaticProp( IClientRenderable* pRenderable ) = 0; + + // Gets the lighting + material color of a static prop + virtual void GetStaticPropMaterialColorAndLighting( trace_t* pTrace, + int staticPropIndex, Vector& lighting, Vector& matColor ) = 0; + + //Changes made specifically to support the Portal mod (smack Dave Kircher if something breaks) (Added separately to both client and server to not mess with versioning) + //=================================================================== + virtual void GetAllStaticProps( CUtlVector *pOutput ) = 0; //testing function that will eventually be removed + virtual void GetAllStaticPropsInAABB( const Vector &vMins, const Vector &vMaxs, CUtlVector *pOutput ) = 0; //get all static props that exist wholly or partially in an AABB + virtual void GetAllStaticPropsInOBB( const Vector &ptOrigin, const Vector &vExtent1, const Vector &vExtent2, const Vector &vExtent3, CUtlVector *pOutput ) = 0; //get all static props that exist wholly or partially in an OBB + //=================================================================== + + virtual void DrawStaticProps( IClientRenderable **pProps, int count, bool bShadowDepth, bool drawVCollideWireframe ) = 0; + virtual void AddColorDecalToStaticProp( Vector const& rayStart, Vector const& rayEnd, + int staticPropIndex, int decalIndex, bool doTrace, trace_t& tr, bool bUseColor, Color cColor ) = 0; +}; + +class IStaticPropMgrServer : public IStaticPropMgr +{ +public: + + + //Changes made specifically to support the Portal mod (smack Dave Kircher if something breaks) (Added separately to both client and server to not mess with versioning) + //=================================================================== + virtual void GetAllStaticProps( CUtlVector *pOutput ) = 0; //testing function that will eventually be removed + virtual void GetAllStaticPropsInAABB( const Vector &vMins, const Vector &vMaxs, CUtlVector *pOutput ) = 0; //get all static props that exist wholly or partially in an AABB + virtual void GetAllStaticPropsInOBB( const Vector &ptOrigin, const Vector &vExtent1, const Vector &vExtent2, const Vector &vExtent3, CUtlVector *pOutput ) = 0; //get all static props that exist wholly or partially in an OBB + //=================================================================== +}; + + +#endif // IPROPS_H diff --git a/public/engine/SndInfo.h b/public/engine/SndInfo.h new file mode 100644 index 0000000..a3628f2 --- /dev/null +++ b/public/engine/SndInfo.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SNDINFO_H +#define SNDINFO_H +#ifdef _WIN32 +#pragma once +#endif + +class Vector; +#include "utlsymbol.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side only +//----------------------------------------------------------------------------- +struct SndInfo_t +{ + // Sound Guid + int m_nGuid; + FileNameHandle_t m_filenameHandle; // filesystem filename handle - call IFilesystem to conver this to a string + int m_nSoundSource; + int m_nChannel; + // If a sound is being played through a speaker entity (e.g., on a monitor,), this is the + // entity upon which to show the lips moving, if the sound has sentence data + int m_nSpeakerEntity; + float m_flVolume; + float m_flLastSpatializedVolume; + // Radius of this sound effect (spatialization is different within the radius) + float m_flRadius; + int m_nPitch; + Vector *m_pOrigin; + Vector *m_pDirection; + + // if true, assume sound source can move and update according to entity + bool m_bUpdatePositions; + // true if playing linked sentence + bool m_bIsSentence; + // if true, bypass all dsp processing for this sound (ie: music) + bool m_bDryMix; + // true if sound is playing through in-game speaker entity. + bool m_bSpeaker; + // true if sound is playing with special DSP effect + bool m_bSpecialDSP; + // for snd_show, networked sounds get colored differently than local sounds + bool m_bFromServer; +}; + +#endif // SNDINFO_H diff --git a/public/engine/http.h b/public/engine/http.h new file mode 100644 index 0000000..79fd1dc --- /dev/null +++ b/public/engine/http.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#ifndef HTTP_H +#define HTTP_H + +#ifdef _WIN32 +#pragma once +#endif + +//-------------------------------------------------------------------------------------------------------------- +/** + * Status of the download thread, as set in RequestContext::status. + */ +enum HTTPStatus_t +{ + HTTP_INVALID = -1, + HTTP_CONNECTING = 0,///< This is set in the main thread before the download thread starts. + HTTP_FETCH, ///< The download thread sets this when it starts reading data. + HTTP_DONE, ///< The download thread sets this if it has read all the data successfully. + HTTP_ABORTED, ///< The download thread sets this if it aborts because it's RequestContext::shouldStop has been set. + HTTP_ERROR ///< The download thread sets this if there is an error connecting or downloading. Partial data may be present, so the main thread can check. +}; + +//-------------------------------------------------------------------------------------------------------------- +/** + * Error encountered in the download thread, as set in RequestContext::error. + */ +enum HTTPError_t +{ + HTTP_ERROR_NONE = 0, + HTTP_ERROR_ZERO_LENGTH_FILE, + HTTP_ERROR_CONNECTION_CLOSED, + HTTP_ERROR_INVALID_URL, ///< InternetCrackUrl failed + HTTP_ERROR_INVALID_PROTOCOL, ///< URL didn't start with http:// or https:// + HTTP_ERROR_CANT_BIND_SOCKET, + HTTP_ERROR_CANT_CONNECT, + HTTP_ERROR_NO_HEADERS, ///< Cannot read HTTP headers + HTTP_ERROR_FILE_NONEXISTENT, + HTTP_ERROR_MAX +}; + +#endif // HTTP_H diff --git a/public/engine/ienginevoice.h b/public/engine/ienginevoice.h new file mode 100644 index 0000000..aab5f99 --- /dev/null +++ b/public/engine/ienginevoice.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Engine voice interface +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IENGINEVOICE_H +#define IENGINEVOICE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "basetypes.h" + +#define IENGINEVOICE_INTERFACE_VERSION "IEngineVoice001" + +abstract_class IEngineVoice +{ +public: + virtual bool IsHeadsetPresent( int iController ) = 0; + virtual bool IsLocalPlayerTalking( int iController ) = 0; + + virtual void AddPlayerToVoiceList( XUID xPlayer, int iController ) = 0; + virtual void RemovePlayerFromVoiceList( XUID xPlayer, int iController ) = 0; + + virtual void GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers ) = 0; + + virtual bool VoiceUpdateData( int iController ) = 0; + virtual void GetVoiceData( int iController, const byte **ppvVoiceDataBuffer, unsigned int *pnumVoiceDataBytes ) = 0; + virtual void VoiceResetLocalData( int iController ) = 0; + + virtual void SetPlaybackPriority( XUID remoteTalker, int iController, int iAllowPlayback ) = 0; + virtual void PlayIncomingVoiceData( XUID xuid, const byte *pbData, unsigned int dwDataSize, const bool *bAudiblePlayers = NULL ) = 0; + + virtual void RemoveAllTalkers() = 0; +}; + + +#endif // IENGINEVOICE_H diff --git a/public/engine/imatchmaking.h b/public/engine/imatchmaking.h new file mode 100644 index 0000000..4c9aa81 --- /dev/null +++ b/public/engine/imatchmaking.h @@ -0,0 +1,117 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef IMATCHMAKING_H +#define IMATCHMAKING_H +#ifdef _WIN32 +#pragma once +#endif + +#include "const.h" +#include "vgui/VGUI.h" + +#if !defined( _X360 ) +#include "xbox/xboxstubs.h" +#endif + +class KeyValues; + +enum SESSION_NOTIFY +{ + SESSION_NOTIFY_FAIL_SEARCH, + SESSION_NOTIFY_SEARCH_COMPLETED, + SESSION_NOFIFY_MODIFYING_SESSION, + SESSION_NOTIFY_MODIFYING_COMPLETED_HOST, + SESSION_NOTIFY_MODIFYING_COMPLETED_CLIENT, + SESSION_NOTIFY_MIGRATION_COMPLETED, + SESSION_NOTIFY_CONNECT_SESSIONFULL, + SESSION_NOTIFY_CONNECT_NOTAVAILABLE, + SESSION_NOTIFY_CONNECTED_TOSESSION, + SESSION_NOTIFY_CONNECTED_TOSERVER, + SESSION_NOTIFY_CONNECT_FAILED, + SESSION_NOTIFY_FAIL_CREATE, + SESSION_NOTIFY_FAIL_MIGRATE, + SESSION_NOTIFY_REGISTER_COMPLETED, + SESSION_NOTIFY_FAIL_REGISTER, + SESSION_NOTIFY_CLIENT_KICKED, + SESSION_NOTIFY_CREATED_HOST, + SESSION_NOTIFY_CREATED_CLIENT, + SESSION_NOTIFY_LOST_HOST, + SESSION_NOTIFY_LOST_SERVER, + SESSION_NOTIFY_COUNTDOWN, + SESSION_NOTIFY_ENDGAME_RANKED, // Ranked + SESSION_NOTIFY_ENDGAME_HOST, // Unranked + SESSION_NOTIFY_ENDGAME_CLIENT, // Unranked + SESSION_NOTIFY_DUMPSTATS, // debugging + SESSION_NOTIFY_WELCOME, // Close all dialogs and show the welcome main menu +}; + +enum SESSION_PROPS +{ + SESSION_CONTEXT, + SESSION_PROPERTY, + SESSION_FLAG, +}; + +struct hostData_s +{ + char hostName[MAX_PLAYER_NAME_LENGTH]; + char scenario[MAX_MAP_NAME]; + int gameState; + int gameTime; + XUID xuid; +}; + +struct MM_QOS_t +{ + int nPingMsMin; // Minimum round-trip time in ms + int nPingMsMed; // Median round-trip time in ms + float flBwUpKbs; // Bandwidth upstream in kilobytes/s + float flBwDnKbs; // Bandwidth downstream in kilobytes/s + float flLoss; // Average packet loss in percents +}; + +#define NO_TIME_LIMIT 65000 + +abstract_class IMatchmaking +{ +public: + virtual void SessionNotification( const SESSION_NOTIFY notification, const int param = 0 ) = 0; + virtual void AddSessionProperty( const uint nType, const char *pID, const char *pValue, const char *pValueType ) = 0; + virtual void SetSessionProperties( KeyValues *pPropertyKeys ) = 0; + virtual void SelectSession( uint idx ) = 0; + virtual void ModifySession() = 0; + virtual void UpdateMuteList() = 0; + virtual void StartHost( bool bSystemLink = false ) = 0; + virtual void StartClient( bool bSystemLink = false ) = 0; + virtual bool StartGame() = 0; + virtual bool CancelStartGame() = 0; + virtual void ChangeTeam( const char *pTeamName ) = 0; + virtual void TellClientsToConnect() = 0; + virtual void CancelCurrentOperation() = 0; + virtual void KickPlayerFromSession( uint64 id ) = 0; + virtual void JoinInviteSession( XSESSION_INFO *pHostInfo ) = 0; + virtual void JoinInviteSessionByID( XNKID nSessionID ) = 0; + virtual void EndStatsReporting() = 0; + + // For Gameui + virtual KeyValues *GetSessionProperties() = 0; + + // For voice chat + virtual uint64 PlayerIdToXuid( int playerId ) = 0; + virtual bool IsPlayerMuted( int iUserId, XUID id ) = 0; + + // To determine host Quality-of-Service + virtual MM_QOS_t GetQosWithLIVE() = 0; + + // Used by non-'host' local machines which are starting a map to "prime" the caches. Will sit at near completion indefinitely -- + // the client is waiting for a TellClientsToConnect message + virtual bool PreventFullServerStartup() = 0; +}; + +#define VENGINE_MATCHMAKING_VERSION "VENGINE_MATCHMAKING_VERSION001" + +#endif // IMATCHMAKING_H diff --git a/public/engine/iserverplugin.h b/public/engine/iserverplugin.h new file mode 100644 index 0000000..608583b --- /dev/null +++ b/public/engine/iserverplugin.h @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ISERVERPLUGIN_H +#define ISERVERPLUGIN_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "edict.h" +#include "tier1/interface.h" +#include "tier1/KeyValues.h" + +class CCommand; + +// +// you will also want to listen for game events via IGameEventManager::AddListener() +// + +typedef enum +{ + PLUGIN_CONTINUE = 0, // keep going + PLUGIN_OVERRIDE, // run the game dll function but use our return value instead + PLUGIN_STOP, // don't run the game dll function at all +} PLUGIN_RESULT; + + +typedef enum +{ + eQueryCvarValueStatus_ValueIntact=0, // It got the value fine. + eQueryCvarValueStatus_CvarNotFound=1, + eQueryCvarValueStatus_NotACvar=2, // There's a ConCommand, but it's not a ConVar. + eQueryCvarValueStatus_CvarProtected=3 // The cvar was marked with FCVAR_SERVER_CAN_NOT_QUERY, so the server is not allowed to have its value. +} EQueryCvarValueStatus; + + +typedef int QueryCvarCookie_t; +#define InvalidQueryCvarCookie -1 + + +#define INTERFACEVERSION_ISERVERPLUGINCALLBACKS_VERSION_1 "ISERVERPLUGINCALLBACKS001" +#define INTERFACEVERSION_ISERVERPLUGINCALLBACKS_VERSION_2 "ISERVERPLUGINCALLBACKS002" +#define INTERFACEVERSION_ISERVERPLUGINCALLBACKS "ISERVERPLUGINCALLBACKS003" + +//----------------------------------------------------------------------------- +// Purpose: callbacks the engine exposes to the 3rd party plugins (ala MetaMod) +//----------------------------------------------------------------------------- +abstract_class IServerPluginCallbacks +{ +public: + // Initialize the plugin to run + // Return false if there is an error during startup. + virtual bool Load( CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory ) = 0; + + // Called when the plugin should be shutdown + virtual void Unload( void ) = 0; + + // called when a plugins execution is stopped but the plugin is not unloaded + virtual void Pause( void ) = 0; + + // called when a plugin should start executing again (sometime after a Pause() call) + virtual void UnPause( void ) = 0; + + // Returns string describing current plugin. e.g., Admin-Mod. + virtual const char *GetPluginDescription( void ) = 0; + + // Called any time a new level is started (after GameInit() also on level transitions within a game) + virtual void LevelInit( char const *pMapName ) = 0; + + // The server is about to activate + virtual void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) = 0; + + // The server should run physics/think on all edicts + virtual void GameFrame( bool simulating ) = 0; + + // Called when a level is shutdown (including changing levels) + virtual void LevelShutdown( void ) = 0; + + // Client is going active + virtual void ClientActive( edict_t *pEntity ) = 0; + + // Client is disconnecting from server + virtual void ClientDisconnect( edict_t *pEntity ) = 0; + + // Client is connected and should be put in the game + virtual void ClientPutInServer( edict_t *pEntity, char const *playername ) = 0; + + // Sets the client index for the client who typed the command into their console + virtual void SetCommandClient( int index ) = 0; + + // A player changed one/several replicated cvars (name etc) + virtual void ClientSettingsChanged( edict_t *pEdict ) = 0; + + // Client is connecting to server ( set retVal to false to reject the connection ) + // You can specify a rejection message by writing it into reject + virtual PLUGIN_RESULT ClientConnect( bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) = 0; + + // The client has typed a command at the console + virtual PLUGIN_RESULT ClientCommand( edict_t *pEntity, const CCommand &args ) = 0; + + // A user has had their network id setup and validated + virtual PLUGIN_RESULT NetworkIDValidated( const char *pszUserName, const char *pszNetworkID ) = 0; + + // This is called when a query from IServerPluginHelpers::StartQueryCvarValue is finished. + // iCookie is the value returned by IServerPluginHelpers::StartQueryCvarValue. + // Added with version 2 of the interface. + virtual void OnQueryCvarValueFinished( QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue ) = 0; + + // added with version 3 of the interface. + virtual void OnEdictAllocated( edict_t *edict ) = 0; + virtual void OnEdictFreed( const edict_t *edict ) = 0; +}; + +#define INTERFACEVERSION_ISERVERPLUGINHELPERS "ISERVERPLUGINHELPERS001" + + +typedef enum +{ + DIALOG_MSG = 0, // just an on screen message + DIALOG_MENU, // an options menu + DIALOG_TEXT, // a richtext dialog + DIALOG_ENTRY, // an entry box + DIALOG_ASKCONNECT // Ask the client to connect to a specified IP address. Only the "time" and "title" keys are used. +} DIALOG_TYPE; + +//----------------------------------------------------------------------------- +// Purpose: functions that only 3rd party plugins need +//----------------------------------------------------------------------------- +abstract_class IServerPluginHelpers +{ +public: + // creates an onscreen menu with various option buttons + // The keyvalues param can contain these fields: + // "title" - (string) the title to show in the hud and in the title bar + // "msg" - (string) a longer message shown in the GameUI + // "color" - (color) the color to display the message in the hud (white by default) + // "level" - (int) the priority of this message (closer to 0 is higher), only 1 message can be outstanding at a time + // "time" - (int) the time in seconds this message should stay active in the GameUI (min 10 sec, max 200 sec) + // + // For DIALOG_MENU add sub keys for each option with these fields: + // "command" - (string) client command to run if selected + // "msg" - (string) button text for this option + // + virtual void CreateMessage( edict_t *pEntity, DIALOG_TYPE type, KeyValues *data, IServerPluginCallbacks *plugin ) = 0; + virtual void ClientCommand( edict_t *pEntity, const char *cmd ) = 0; + + // Call this to find out the value of a cvar on the client. + // + // It is an asynchronous query, and it will call IServerPluginCallbacks::OnQueryCvarValueFinished when + // the value comes in from the client. + // + // Store the return value if you want to match this specific query to the OnQueryCvarValueFinished call. + // Returns InvalidQueryCvarCookie if the entity is invalid. + virtual QueryCvarCookie_t StartQueryCvarValue( edict_t *pEntity, const char *pName ) = 0; +}; + +#endif //ISERVERPLUGIN_H diff --git a/public/engine/ishadowmgr.h b/public/engine/ishadowmgr.h new file mode 100644 index 0000000..babac91 --- /dev/null +++ b/public/engine/ishadowmgr.h @@ -0,0 +1,189 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ISHADOWMGR_H +#define ISHADOWMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib/vmatrix.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class IMaterial; +class Vector; +class Vector2D; +struct model_t; +typedef unsigned short ModelInstanceHandle_t; +class IClientRenderable; +class ITexture; + +// change this when the new version is incompatable with the old +#define ENGINE_SHADOWMGR_INTERFACE_VERSION "VEngineShadowMgr002" + + +//----------------------------------------------------------------------------- +// Flags for the creation method +//----------------------------------------------------------------------------- +enum ShadowFlags_t +{ + SHADOW_FLAGS_FLASHLIGHT = (1 << 0), + SHADOW_FLAGS_SHADOW = (1 << 1), + // Update this if you add flags + SHADOW_FLAGS_LAST_FLAG = SHADOW_FLAGS_SHADOW +}; + +#define SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SHADOW ) + + +//----------------------------------------------------------------------------- +// +// Shadow-related functionality exported by the engine +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// This is a handle to shadows, clients can create as many as they want +//----------------------------------------------------------------------------- +typedef unsigned short ShadowHandle_t; + +enum +{ + SHADOW_HANDLE_INVALID = (ShadowHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Used for the creation Flags field of CreateShadow +//----------------------------------------------------------------------------- +enum ShadowCreateFlags_t +{ + SHADOW_CACHE_VERTS = ( 1 << 0 ), + SHADOW_FLASHLIGHT = ( 1 << 1 ), + + SHADOW_LAST_FLAG = SHADOW_FLASHLIGHT, +}; + + +//----------------------------------------------------------------------------- +// Information about a particular shadow +//----------------------------------------------------------------------------- +struct ShadowInfo_t +{ + // Transforms from world space into texture space of the shadow + VMatrix m_WorldToShadow; + + // The shadow should no longer be drawn once it's further than MaxDist + // along z in shadow texture coordinates. + float m_FalloffOffset; + float m_MaxDist; + float m_FalloffAmount; // how much to lighten the shadow maximally + Vector2D m_TexOrigin; + Vector2D m_TexSize; + unsigned char m_FalloffBias; +}; + +struct FlashlightState_t; + +//----------------------------------------------------------------------------- +// The engine's interface to the shadow manager +//----------------------------------------------------------------------------- +abstract_class IShadowMgr +{ +public: + // Create, destroy shadows (see ShadowCreateFlags_t for creationFlags) + virtual ShadowHandle_t CreateShadow( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags ) = 0; + virtual void DestroyShadow( ShadowHandle_t handle ) = 0; + + // Resets the shadow material (useful for shadow LOD.. doing blobby at distance) + virtual void SetShadowMaterial( ShadowHandle_t handle, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy ) = 0; + + // Shadow opacity +// virtual void SetShadowOpacity( ShadowHandle_t handle, float alpha ) = 0; +// virtual float GetShadowOpacity( ShadowHandle_t handle ) const = 0; + + // Project a shadow into the world + // The two points specify the upper left coordinate and the lower-right + // coordinate of the shadow specified in a shadow "viewplane". The + // projection matrix is a shadow viewplane->world transformation, + // and can be orthographic orperspective. + + // I expect that the client DLL will call this method any time the shadow + // changes because the light changes, or because the entity casting the + // shadow moves + + // Note that we can't really control the shadows from the engine because + // the engine only knows about pevs, which don't exist on the client + + // The shadow matrix specifies a world-space transform for the shadow + // the shadow is projected down the z direction, and the origin of the + // shadow matrix is the origin of the projection ray. The size indicates + // the shadow size measured in the space of the shadow matrix; the + // shadow goes from +/- size.x/2 along the x axis of the shadow matrix + // and +/- size.y/2 along the y axis of the shadow matrix. + virtual void ProjectShadow( ShadowHandle_t handle, const Vector &origin, + const Vector& projectionDir, const VMatrix& worldToShadow, const Vector2D& size, + int nLeafCount, const int *pLeafList, + float maxHeight, float falloffOffset, float falloffAmount, const Vector &vecCasterOrigin ) = 0; + + virtual void ProjectFlashlight( ShadowHandle_t handle, const VMatrix &worldToShadow, int nLeafCount, const int *pLeafList ) = 0; + + // Gets at information about a particular shadow + virtual const ShadowInfo_t &GetInfo( ShadowHandle_t handle ) = 0; + + virtual const Frustum_t &GetFlashlightFrustum( ShadowHandle_t handle ) = 0; + + // Methods related to shadows on brush models + virtual void AddShadowToBrushModel( ShadowHandle_t handle, + model_t* pModel, const Vector& origin, const QAngle& angles ) = 0; + + // Removes all shadows from a brush model + virtual void RemoveAllShadowsFromBrushModel( model_t* pModel ) = 0; + + // Sets the texture coordinate range for a shadow... + virtual void SetShadowTexCoord( ShadowHandle_t handle, float x, float y, float w, float h ) = 0; + + // Methods related to shadows on studio models + virtual void AddShadowToModel( ShadowHandle_t shadow, ModelInstanceHandle_t instance ) = 0; + virtual void RemoveAllShadowsFromModel( ModelInstanceHandle_t instance ) = 0; + + // Set extra clip planes related to shadows... + // These are used to prevent pokethru and back-casting + virtual void ClearExtraClipPlanes( ShadowHandle_t shadow ) = 0; + virtual void AddExtraClipPlane( ShadowHandle_t shadow, const Vector& normal, float dist ) = 0; + + // Allows us to disable particular shadows + virtual void EnableShadow( ShadowHandle_t shadow, bool bEnable ) = 0; + + // Set the darkness falloff bias + virtual void SetFalloffBias( ShadowHandle_t shadow, unsigned char ucBias ) = 0; + + // Update the state for a flashlight. + virtual void UpdateFlashlightState( ShadowHandle_t shadowHandle, const FlashlightState_t &lightState ) = 0; + + virtual void DrawFlashlightDepthTexture( ) = 0; + + virtual void AddFlashlightRenderable( ShadowHandle_t shadow, IClientRenderable *pRenderable ) = 0; + virtual ShadowHandle_t CreateShadowEx( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags ) = 0; + + virtual void SetFlashlightDepthTexture( ShadowHandle_t shadowHandle, ITexture *pFlashlightDepthTexture, unsigned char ucShadowStencilBit ) = 0; + + virtual const FlashlightState_t &GetFlashlightState( ShadowHandle_t handle ) = 0; + + virtual void SetFlashlightRenderState( ShadowHandle_t handle ) = 0; +}; + + +#endif diff --git a/public/engine/ivdebugoverlay.h b/public/engine/ivdebugoverlay.h new file mode 100644 index 0000000..c23e225 --- /dev/null +++ b/public/engine/ivdebugoverlay.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// cdll_int.h +// +// 4-23-98 +// JOHN: client dll interface declarations +// + +#ifndef IVDEBUGOVERLAY_H +#define IVDEBUGOVERLAY_H + +#ifdef _WIN32 +#pragma once +#endif + +class Vector; + +#define VDEBUG_OVERLAY_INTERFACE_VERSION "VDebugOverlay003" + +// When used as a duration by a server-side NDebugOverlay:: call, +// causes the overlay to persist until the next server update. +#define NDEBUG_PERSIST_TILL_NEXT_SERVER (0.0f) + +class OverlayText_t; + +abstract_class IVDebugOverlay +{ +public: + virtual void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, int r, int g, int b, int a, float duration) = 0; + virtual void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector& p3, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b,bool noDepthTest, float duration) = 0; + virtual void AddTextOverlay(const Vector& origin, float duration, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddTextOverlay(const Vector& origin, int line_offset, float duration, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char *text) = 0; + virtual void AddSweptBoxOverlay(const Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle & angles, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddGridOverlay(const Vector& origin) = 0; + virtual int ScreenPosition(const Vector& point, Vector& screen) = 0; + virtual int ScreenPosition(float flXPos, float flYPos, Vector& screen) = 0; + + virtual OverlayText_t *GetFirst( void ) = 0; + virtual OverlayText_t *GetNext( OverlayText_t *current ) = 0; + virtual void ClearDeadOverlays( void ) = 0; + virtual void ClearAllOverlays() = 0; + + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *format, ...) = 0; + + virtual void AddLineOverlayAlpha(const Vector& origin, const Vector& dest, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddBoxOverlay2( const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, const Color& faceColor, const Color& edgeColor, float duration ) = 0; + +private: + inline void AddTextOverlay(const Vector& origin, int line_offset, float duration, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *format, ...) {} /* catch improper use of bad interface. Needed because '0' duration can be resolved by compiler to NULL format string (i.e., compiles but calls wrong function) */ +}; + + +#endif // IVDEBUGOVERLAY_H diff --git a/public/engine/ivmodelinfo.h b/public/engine/ivmodelinfo.h new file mode 100644 index 0000000..6d53460 --- /dev/null +++ b/public/engine/ivmodelinfo.h @@ -0,0 +1,261 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef IVMODELINFO_H +#define IVMODELINFO_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "dbg.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class KeyValues; +struct vcollide_t; +struct model_t; +class Vector; +class QAngle; +class CGameTrace; +struct cplane_t; +typedef CGameTrace trace_t; +struct studiohdr_t; +struct virtualmodel_t; +typedef unsigned char byte; +struct virtualterrainparams_t; +class CPhysCollide; +typedef unsigned short MDLHandle_t; +class CUtlBuffer; +class IClientRenderable; + + +//----------------------------------------------------------------------------- +// Purpose: a callback class that is notified when a model has finished loading +//----------------------------------------------------------------------------- +abstract_class IModelLoadCallback +{ +public: + virtual void OnModelLoadComplete( const model_t* pModel ) = 0; + +protected: + // Protected destructor so that nobody tries to delete via this interface. + // Automatically unregisters if the callback is destroyed while still pending. + ~IModelLoadCallback(); +}; + + +//----------------------------------------------------------------------------- +// Purpose: Automate refcount tracking on a model index +//----------------------------------------------------------------------------- +class CRefCountedModelIndex +{ +private: + int m_nIndex; +public: + CRefCountedModelIndex() : m_nIndex( -1 ) { } + ~CRefCountedModelIndex() { Set( -1 ); } + + CRefCountedModelIndex( const CRefCountedModelIndex& src ) : m_nIndex( -1 ) { Set( src.m_nIndex ); } + CRefCountedModelIndex& operator=( const CRefCountedModelIndex& src ) { Set( src.m_nIndex ); return *this; } + + explicit CRefCountedModelIndex( int i ) : m_nIndex( -1 ) { Set( i ); } + CRefCountedModelIndex& operator=( int i ) { Set( i ); return *this; } + + int Get() const { return m_nIndex; } + void Set( int i ); + void Clear() { Set( -1 ); } + + operator int () const { return m_nIndex; } +}; + + +//----------------------------------------------------------------------------- +// Model info interface +//----------------------------------------------------------------------------- + +// change this when the new version is incompatable with the old +#define VMODELINFO_CLIENT_INTERFACE_VERSION "VModelInfoClient006" +#define VMODELINFO_SERVER_INTERFACE_VERSION_3 "VModelInfoServer003" +#define VMODELINFO_SERVER_INTERFACE_VERSION "VModelInfoServer004" + +// MODEL INDEX RULES +// If index >= 0, then index references the precached model string table +// If index == -1, then the model is invalid +// If index < -1, then the model is DYNAMIC and has a DYNAMIC INDEX of (-2 - index) +// - if the dynamic index is ODD, then the model is CLIENT ONLY +// and has a m_LocalDynamicModels lookup index of (dynamic index)>>1 +// - if the dynamic index is EVEN, then the model is NETWORKED +// and has a dynamic model string table index of (dynamic index)>>1 + +inline bool IsDynamicModelIndex( int modelindex ) { return modelindex < -1; } +inline bool IsClientOnlyModelIndex( int modelindex ) { return modelindex < -1 && (modelindex & 1); } + +abstract_class IVModelInfo +{ +public: + virtual ~IVModelInfo( void ) { } + + // Returns model_t* pointer for a model given a precached or dynamic model index. + virtual const model_t *GetModel( int modelindex ) = 0; + + // Returns index of model by name for precached or known dynamic models. + // Does not adjust reference count for dynamic models. + virtual int GetModelIndex( const char *name ) const = 0; + + // Returns name of model + virtual const char *GetModelName( const model_t *model ) const = 0; + virtual vcollide_t *GetVCollide( const model_t *model ) = 0; + virtual vcollide_t *GetVCollide( int modelindex ) = 0; + virtual void GetModelBounds( const model_t *model, Vector& mins, Vector& maxs ) const = 0; + virtual void GetModelRenderBounds( const model_t *model, Vector& mins, Vector& maxs ) const = 0; + virtual int GetModelFrameCount( const model_t *model ) const = 0; + virtual int GetModelType( const model_t *model ) const = 0; + virtual void *GetModelExtraData( const model_t *model ) = 0; + virtual bool ModelHasMaterialProxy( const model_t *model ) const = 0; + virtual bool IsTranslucent( model_t const* model ) const = 0; + virtual bool IsTranslucentTwoPass( const model_t *model ) const = 0; + virtual void RecomputeTranslucency( const model_t *model, int nSkin, int nBody, void /*IClientRenderable*/ *pClientRenderable, float fInstanceAlphaModulate=1.0f) = 0; + virtual int GetModelMaterialCount( const model_t* model ) const = 0; + virtual void GetModelMaterials( const model_t *model, int count, IMaterial** ppMaterial ) = 0; + virtual bool IsModelVertexLit( const model_t *model ) const = 0; + virtual const char *GetModelKeyValueText( const model_t *model ) = 0; + virtual bool GetModelKeyValue( const model_t *model, CUtlBuffer &buf ) = 0; // supports keyvalue blocks in submodels + virtual float GetModelRadius( const model_t *model ) = 0; + + virtual const studiohdr_t *FindModel( const studiohdr_t *pStudioHdr, void **cache, const char *modelname ) const = 0; + virtual const studiohdr_t *FindModel( void *cache ) const = 0; + virtual virtualmodel_t *GetVirtualModel( const studiohdr_t *pStudioHdr ) const = 0; + virtual byte *GetAnimBlock( const studiohdr_t *pStudioHdr, int iBlock ) const = 0; + + // Available on client only!!! + virtual void GetModelMaterialColorAndLighting( const model_t *model, Vector const& origin, + QAngle const& angles, trace_t* pTrace, + Vector& lighting, Vector& matColor ) = 0; + virtual void GetIlluminationPoint( const model_t *model, IClientRenderable *pRenderable, Vector const& origin, + QAngle const& angles, Vector* pLightingCenter ) = 0; + + virtual int GetModelContents( int modelIndex ) = 0; + virtual studiohdr_t *GetStudiomodel( const model_t *mod ) = 0; + virtual int GetModelSpriteWidth( const model_t *model ) const = 0; + virtual int GetModelSpriteHeight( const model_t *model ) const = 0; + + // Sets/gets a map-specified fade range (client only) + virtual void SetLevelScreenFadeRange( float flMinSize, float flMaxSize ) = 0; + virtual void GetLevelScreenFadeRange( float *pMinArea, float *pMaxArea ) const = 0; + + // Sets/gets a map-specified per-view fade range (client only) + virtual void SetViewScreenFadeRange( float flMinSize, float flMaxSize ) = 0; + + // Computes fade alpha based on distance fade + screen fade (client only) + virtual unsigned char ComputeLevelScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const = 0; + virtual unsigned char ComputeViewScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const = 0; + + // both client and server + virtual int GetAutoplayList( const studiohdr_t *pStudioHdr, unsigned short **pAutoplayList ) const = 0; + + // Gets a virtual terrain collision model (creates if necessary) + // NOTE: This may return NULL if the terrain model cannot be virtualized + virtual CPhysCollide *GetCollideForVirtualTerrain( int index ) = 0; + + virtual bool IsUsingFBTexture( const model_t *model, int nSkin, int nBody, void /*IClientRenderable*/ *pClientRenderable ) const = 0; + + // Obsolete methods. These are left in to maintain binary compatibility with clients using the IVModelInfo old version. + virtual const model_t *FindOrLoadModel( const char *name ) { Warning( "IVModelInfo::FindOrLoadModel is now obsolte.\n" ); return NULL; } + virtual void InitDynamicModels( ) { Warning( "IVModelInfo::InitDynamicModels is now obsolte.\n" ); } + virtual void ShutdownDynamicModels( ) { Warning( "IVModelInfo::ShutdownDynamicModels is now obsolte.\n" ); } + virtual void AddDynamicModel( const char *name, int nModelIndex = -1 ) { Warning( "IVModelInfo::AddDynamicModel is now obsolte.\n" ); } + virtual void ReferenceModel( int modelindex ) { Warning( "IVModelInfo::ReferenceModel is now obsolte.\n" ); } + virtual void UnreferenceModel( int modelindex ) { Warning( "IVModelInfo::UnreferenceModel is now obsolte.\n" ); } + virtual void CleanupDynamicModels( bool bForce = false ) { Warning( "IVModelInfo::CleanupDynamicModels is now obsolte.\n" ); } + + virtual MDLHandle_t GetCacheHandle( const model_t *model ) const = 0; + + // Returns planes of non-nodraw brush model surfaces + virtual int GetBrushModelPlaneCount( const model_t *model ) const = 0; + virtual void GetBrushModelPlane( const model_t *model, int nIndex, cplane_t &plane, Vector *pOrigin ) const = 0; + virtual int GetSurfacepropsForVirtualTerrain( int index ) = 0; + + // Poked by engine host system + virtual void OnLevelChange() = 0; + + virtual int GetModelClientSideIndex( const char *name ) const = 0; + + // Returns index of model by name, dynamically registered if not already known. + virtual int RegisterDynamicModel( const char *name, bool bClientSide ) = 0; + + virtual bool IsDynamicModelLoading( int modelIndex ) = 0; + + virtual void AddRefDynamicModel( int modelIndex ) = 0; + virtual void ReleaseDynamicModel( int modelIndex ) = 0; + + // Registers callback for when dynamic model has finished loading. + // Automatically adds reference, pair with ReleaseDynamicModel. + virtual bool RegisterModelLoadCallback( int modelindex, IModelLoadCallback* pCallback, bool bCallImmediatelyIfLoaded = true ) = 0; + virtual void UnregisterModelLoadCallback( int modelindex, IModelLoadCallback* pCallback ) = 0; +}; + +typedef IVModelInfo IVModelInfo003; + + +abstract_class IVModelInfoClient : public IVModelInfo +{ +public: + virtual void OnDynamicModelsStringTableChange( int nStringIndex, const char *pString, const void *pData ) = 0; + + // For tools only! + virtual const model_t *FindOrLoadModel( const char *name ) = 0; +}; + + +struct virtualterrainparams_t +{ + // UNDONE: Add grouping here, specified in BSP file? (test grouping to see if this is necessary) + int index; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Force removal from callback list on destruction to avoid crashes. +//----------------------------------------------------------------------------- +inline IModelLoadCallback::~IModelLoadCallback() +{ +#ifdef CLIENT_DLL + extern IVModelInfoClient *modelinfo; +#else + extern IVModelInfo *modelinfo; +#endif + if ( modelinfo ) + { + modelinfo->UnregisterModelLoadCallback( -1, this ); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Automate refcount tracking on a model index +//----------------------------------------------------------------------------- +inline void CRefCountedModelIndex::Set( int i ) +{ +#ifdef CLIENT_DLL + extern IVModelInfoClient *modelinfo; +#else + extern IVModelInfo *modelinfo; +#endif + if ( i == m_nIndex ) + return; + modelinfo->AddRefDynamicModel( i ); + modelinfo->ReleaseDynamicModel( m_nIndex ); + m_nIndex = i; +} + + +#endif // IVMODELINFO_H diff --git a/public/engine/ivmodelrender.h b/public/engine/ivmodelrender.h new file mode 100644 index 0000000..fabaa77 --- /dev/null +++ b/public/engine/ivmodelrender.h @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IVMODELRENDER_H +#define IVMODELRENDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib/mathlib.h" +#include "istudiorender.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +struct mstudioanimdesc_t; +struct mstudioseqdesc_t; +struct model_t; +class IClientRenderable; +class Vector; +struct studiohdr_t; +class IMaterial; +class CStudioHdr; + +FORWARD_DECLARE_HANDLE( LightCacheHandle_t ); + + +//----------------------------------------------------------------------------- +// Model rendering state +//----------------------------------------------------------------------------- +struct DrawModelState_t +{ + studiohdr_t* m_pStudioHdr; + studiohwdata_t* m_pStudioHWData; + IClientRenderable* m_pRenderable; + const matrix3x4_t *m_pModelToWorld; + StudioDecalHandle_t m_decals; + int m_drawFlags; + int m_lod; +}; + + +//----------------------------------------------------------------------------- +// Model Rendering + instance data +//----------------------------------------------------------------------------- + +// change this when the new version is incompatable with the old +#define VENGINE_HUDMODEL_INTERFACE_VERSION "VEngineModel016" + +typedef unsigned short ModelInstanceHandle_t; + +enum +{ + MODEL_INSTANCE_INVALID = (ModelInstanceHandle_t)~0 +}; + +struct ModelRenderInfo_t +{ + Vector origin; + QAngle angles; + IClientRenderable *pRenderable; + const model_t *pModel; + const matrix3x4_t *pModelToWorld; + const matrix3x4_t *pLightingOffset; + const Vector *pLightingOrigin; + int flags; + int entity_index; + int skin; + int body; + int hitboxset; + ModelInstanceHandle_t instance; + + ModelRenderInfo_t() + { + pModelToWorld = NULL; + pLightingOffset = NULL; + pLightingOrigin = NULL; + } +}; + +struct StaticPropRenderInfo_t +{ + const matrix3x4_t *pModelToWorld; + const model_t *pModel; + IClientRenderable *pRenderable; + Vector *pLightingOrigin; + short skin; + ModelInstanceHandle_t instance; +}; + +// UNDONE: Move this to hud export code, subsume previous functions +abstract_class IVModelRender +{ +public: + virtual int DrawModel( int flags, + IClientRenderable *pRenderable, + ModelInstanceHandle_t instance, + int entity_index, + const model_t *model, + Vector const& origin, + QAngle const& angles, + int skin, + int body, + int hitboxset, + const matrix3x4_t *modelToWorld = NULL, + const matrix3x4_t *pLightingOffset = NULL ) = 0; + + // This causes a material to be used when rendering the model instead + // of the materials the model was compiled with + virtual void ForcedMaterialOverride( IMaterial *newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL ) = 0; + + virtual void SetViewTarget( const CStudioHdr *pStudioHdr, int nBodyIndex, const Vector& target ) = 0; + + // Creates, destroys instance data to be associated with the model + virtual ModelInstanceHandle_t CreateInstance( IClientRenderable *pRenderable, LightCacheHandle_t *pCache = NULL ) = 0; + virtual void DestroyInstance( ModelInstanceHandle_t handle ) = 0; + + // Associates a particular lighting condition with a model instance handle. + // FIXME: This feature currently only works for static props. To make it work for entities, etc., + // we must clean up the lightcache handles as the model instances are removed. + // At the moment, since only the static prop manager uses this, it cleans up all LightCacheHandles + // at level shutdown. + virtual void SetStaticLighting( ModelInstanceHandle_t handle, LightCacheHandle_t* pHandle ) = 0; + virtual LightCacheHandle_t GetStaticLighting( ModelInstanceHandle_t handle ) = 0; + + // moves an existing InstanceHandle to a nex Renderable to keep decals etc. Models must be the same + virtual bool ChangeInstance( ModelInstanceHandle_t handle, IClientRenderable *pRenderable ) = 0; + + // Creates a decal on a model instance by doing a planar projection + // along the ray. The material is the decal material, the radius is the + // radius of the decal to create. + virtual void AddDecal( ModelInstanceHandle_t handle, Ray_t const& ray, + Vector const& decalUp, int decalIndex, int body, bool noPokeThru = false, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ) = 0; + + // Removes all the decals on a model instance + virtual void RemoveAllDecals( ModelInstanceHandle_t handle ) = 0; + + // Remove all decals from all models + virtual void RemoveAllDecalsFromAllModels() = 0; + + // Shadow rendering, DrawModelShadowSetup returns the address of the bone-to-world array, NULL in case of error + virtual matrix3x4_t* DrawModelShadowSetup( IClientRenderable *pRenderable, int body, int skin, DrawModelInfo_t *pInfo, matrix3x4_t *pCustomBoneToWorld = NULL ) = 0; + virtual void DrawModelShadow( IClientRenderable *pRenderable, const DrawModelInfo_t &info, matrix3x4_t *pCustomBoneToWorld = NULL ) = 0; + + // This gets called when overbright, etc gets changed to recompute static prop lighting. + virtual bool RecomputeStaticLighting( ModelInstanceHandle_t handle ) = 0; + + virtual void ReleaseAllStaticPropColorData( void ) = 0; + virtual void RestoreAllStaticPropColorData( void ) = 0; + + // Extended version of drawmodel + virtual int DrawModelEx( ModelRenderInfo_t &pInfo ) = 0; + + virtual int DrawModelExStaticProp( ModelRenderInfo_t &pInfo ) = 0; + + virtual bool DrawModelSetup( ModelRenderInfo_t &pInfo, DrawModelState_t *pState, matrix3x4_t *pCustomBoneToWorld, matrix3x4_t** ppBoneToWorldOut ) = 0; + virtual void DrawModelExecute( const DrawModelState_t &state, const ModelRenderInfo_t &pInfo, matrix3x4_t *pCustomBoneToWorld = NULL ) = 0; + + // Sets up lighting context for a point in space + virtual void SetupLighting( const Vector &vecCenter ) = 0; + + // doesn't support any debug visualization modes or other model options, but draws static props in the + // fastest way possible + virtual int DrawStaticPropArrayFast( StaticPropRenderInfo_t *pProps, int count, bool bShadowDepth ) = 0; + + // Allow client to override lighting state + virtual void SuppressEngineLighting( bool bSuppress ) = 0; + + virtual void SetupColorMeshes( int nTotalVerts ) = 0; + + virtual void AddColoredDecal( ModelInstanceHandle_t handle, Ray_t const& ray, + Vector const& decalUp, int decalIndex, int body, Color cColor, bool noPokeThru = false, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ) = 0; +}; + + +#endif // IVMODELRENDER_H diff --git a/public/engine/view_sharedv1.h b/public/engine/view_sharedv1.h new file mode 100644 index 0000000..cd5fd48 --- /dev/null +++ b/public/engine/view_sharedv1.h @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VIEW_SHAREDV1_H +#define VIEW_SHAREDV1_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Renderer setup data. +//----------------------------------------------------------------------------- +class CViewSetupV1 +{ +public: + CViewSetupV1() + { + m_bForceAspectRatio1To1 = false; + m_bRenderToSubrectOfLargerScreen = false; + bForceClearWholeRenderTarget = false; + m_bUseRenderTargetAspectRatio = false; + } + +// shared by 2D & 3D views + + // User specified context + int context; + + // left side of view window + int x; + // top side of view window + int y; + // width of view window + int width; + // height of view window + int height; + + // clear the color buffer before rendering this view? + bool clearColor; + // clear the Depth buffer before rendering this view? + bool clearDepth; + // NOTE: This is for a workaround on ATI with building cubemaps. Clearing just the viewport doesn't seem to work properly. + bool bForceClearWholeRenderTarget; + +// the rest are only used by 3D views + + // Orthographic projection? + bool m_bOrtho; + // View-space rectangle for ortho projection. + float m_OrthoLeft; + float m_OrthoTop; + float m_OrthoRight; + float m_OrthoBottom; + + // horizontal FOV in degrees + float fov; + // horizontal FOV in degrees for in-view model + float fovViewmodel; + + // 3D origin of camera + Vector origin; + // Origin gets reflected on the water surface, but things like + // displacement LOD need to be calculated from the viewer's + // real position. + Vector m_vUnreflectedOrigin; + + // heading of camera (pitch, yaw, roll) + QAngle angles; + // local Z coordinate of near plane of camera + float zNear; + // local Z coordinate of far plane of camera + float zFar; + + // local Z coordinate of near plane of camera ( when rendering view model ) + float zNearViewmodel; + // local Z coordinate of far plane of camera ( when rendering view model ) + float zFarViewmodel; + + bool m_bForceAspectRatio1To1; + + // set to true if this is to draw into a subrect of the larger screen + // this really is a hack, but no more than the rest of the way this class is used + bool m_bRenderToSubrectOfLargerScreen; + + // Use this for situations like water where you want to render the aspect ratio of the + // back buffer into a square (or otherwise) render target. + bool m_bUseRenderTargetAspectRatio; +}; + +#endif // VIEW_SHAREDV1_H diff --git a/public/engine_hlds_api.h b/public/engine_hlds_api.h new file mode 100644 index 0000000..8053595 --- /dev/null +++ b/public/engine_hlds_api.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ENGINE_HLDS_API_H +#define ENGINE_HLDS_API_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "appframework/IAppSystem.h" + + +#define VENGINE_HLDS_API_VERSION "VENGINE_HLDS_API_VERSION002" + + +struct ModInfo_t +{ + void *m_pInstance; + const char *m_pBaseDirectory; // Executable directory ("c:/program files/half-life 2", for example) + const char *m_pInitialMod; // Mod name ("cstrike", for example) + const char *m_pInitialGame; // Root game name ("hl2", for example, in the case of cstrike) + CAppSystemGroup *m_pParentAppSystemGroup; + bool m_bTextMode; +}; + + +//----------------------------------------------------------------------------- +// Purpose: This is the interface exported by the engine.dll to allow a dedicated server front end +// application to host it. +//----------------------------------------------------------------------------- +class IDedicatedServerAPI : public IAppSystem +{ +// Functions +public: + // Initialize the engine with the specified base directory and interface factories + virtual bool ModInit( ModInfo_t &info ) = 0; + // Shutdown the engine + virtual void ModShutdown( void ) = 0; + // Run a frame + virtual bool RunFrame( void ) = 0; + // Insert text into console + virtual void AddConsoleText( char *text ) = 0; + // Get current status to display in the hlds UI (console window title bar, e.g. ) + virtual void UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap, int maxlen ) = 0; + // Get current Hostname to display in the hlds UI (console window title bar, e.g. ) + virtual void UpdateHostname(char *pszHostname, int maxlen) = 0; +}; + +#endif // ENGINE_HLDS_API_H diff --git a/public/event_flags.h b/public/event_flags.h new file mode 100644 index 0000000..868abb5 --- /dev/null +++ b/public/event_flags.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef EVENT_FLAGS_H +#define EVENT_FLAGS_H + +#ifdef _WIN32 +#pragma once +#endif + + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +#endif // EVENT_FLAGS_H diff --git a/public/fgdlib/entitydefs.h b/public/fgdlib/entitydefs.h new file mode 100644 index 0000000..f2fcd8d --- /dev/null +++ b/public/fgdlib/entitydefs.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ENTITYDEFS_H +#define ENTITYDEFS_H +#ifdef _WIN32 +#pragma once +#endif + + +#define MAX_ENTITY_NAME_LEN 256 + +#define MAX_IO_NAME_LEN 256 + + +#endif // ENTITYDEFS_H diff --git a/public/fgdlib/fgdlib.h b/public/fgdlib/fgdlib.h new file mode 100644 index 0000000..76051cf --- /dev/null +++ b/public/fgdlib/fgdlib.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FGDLIB_H +#define FGDLIB_H +#ifdef _WIN32 +#pragma once +#endif + +#include "HelperInfo.h" +#include "GameData.h" +#include "GDClass.h" +#include "InputOutput.h" + +#endif // FGDLIB_H diff --git a/public/fgdlib/gamedata.h b/public/fgdlib/gamedata.h new file mode 100644 index 0000000..cf8b5be --- /dev/null +++ b/public/fgdlib/gamedata.h @@ -0,0 +1,159 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GAMEDATA_H +#define GAMEDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#pragma warning(push, 1) +#pragma warning(disable:4701 4702 4530) +#include +#pragma warning(pop) +#include "TokenReader.h" +#include "GDClass.h" +#include "InputOutput.h" +#include "UtlString.h" +#include "utlvector.h" + + +class MDkeyvalue; +class GameData; +class KeyValues; + +enum TEXTUREFORMAT; + + +typedef void (*GameDataMessageFunc_t)(int level, PRINTF_FORMAT_STRING const char *fmt, ...); + +// FGD-based AutoMaterialExclusion data + +struct FGDMatExlcusions_s +{ + char szDirectory[MAX_PATH]; // Where we store the material exclusion directories + bool bUserGenerated; // If the user specified this ( default: false -- FGD defined ) +}; + +// FGD-based AutoVisGroup data + +struct FGDVisGroupsBaseClass_s +{ + char szClass[MAX_PATH]; // i.e. Scene Logic, Sounds, etc "Custom\Point Entities\Lights" + CUtlStringList szEntities; // i.e. func_viscluster +}; + +struct FGDAutoVisGroups_s +{ + char szParent[MAX_PATH]; // i.e. Custom, SFM, etc + CUtlVector< FGDVisGroupsBaseClass_s > m_Classes; // i.e. Scene Logic, Sounds, etc +}; + +#define MAX_DIRECTORY_SIZE 32 + + +//----------------------------------------------------------------------------- +// Purpose: Contains the set of data that is loaded from a single FGD file. +//----------------------------------------------------------------------------- +class GameData +{ + public: + typedef enum + { + NAME_FIXUP_PREFIX = 0, + NAME_FIXUP_POSTFIX, + NAME_FIXUP_NONE + } TNameFixup; + + GameData(); + ~GameData(); + + BOOL Load(const char *pszFilename); + + GDclass *ClassForName(const char *pszName, int *piIndex = NULL); + + void ClearData(); + + inline int GetMaxMapCoord(void); + inline int GetMinMapCoord(void); + + inline int GetClassCount(); + inline GDclass *GetClass(int nIndex); + + GDclass *BeginInstanceRemap( const char *pszClassName, const char *pszInstancePrefix, Vector &Origin, QAngle &Angle ); + bool RemapKeyValue( const char *pszKey, const char *pszInValue, char *pszOutValue, TNameFixup NameFixup ); + bool RemapNameField( const char *pszInValue, char *pszOutValue, TNameFixup NameFixup ); + bool LoadFGDMaterialExclusions( TokenReader &tr ); + bool LoadFGDAutoVisGroups( TokenReader &tr ); + + + CUtlVector< FGDMatExlcusions_s > m_FGDMaterialExclusions; + + CUtlVector< FGDAutoVisGroups_s > m_FGDAutoVisGroups; + + private: + + bool ParseMapSize(TokenReader &tr); + + CUtlVector m_Classes; + + int m_nMinMapCoord; // Min & max map bounds as defined by the FGD. + int m_nMaxMapCoord; + + // Instance Remapping + Vector m_InstanceOrigin; // the origin offset of the instance + QAngle m_InstanceAngle; // the rotation of the the instance + matrix3x4_t m_InstanceMat; // matrix of the origin and rotation of rendering + char m_InstancePrefix[ 128 ]; // the prefix used for the instance name remapping + GDclass *m_InstanceClass; // the entity class that is being remapped +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline int GameData::GetClassCount() +{ + return m_Classes.Count(); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline GDclass *GameData::GetClass(int nIndex) +{ + if (nIndex >= m_Classes.Count()) + return NULL; + + return m_Classes.Element(nIndex); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int GameData::GetMinMapCoord(void) +{ + return m_nMinMapCoord; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int GameData::GetMaxMapCoord(void) +{ + return m_nMaxMapCoord; +} + + +void GDSetMessageFunc(GameDataMessageFunc_t pFunc); +bool GDError(TokenReader &tr, PRINTF_FORMAT_STRING const char *error, ...); +bool GDSkipToken(TokenReader &tr, trtoken_t ttexpecting = TOKENNONE, const char *pszExpecting = NULL); +bool GDGetToken(TokenReader &tr, char *pszStore, int nSize, trtoken_t ttexpecting = TOKENNONE, const char *pszExpecting = NULL); +bool GDGetTokenDynamic(TokenReader &tr, char **pszStore, trtoken_t ttexpecting, const char *pszExpecting = NULL); + + +#endif // GAMEDATA_H diff --git a/public/fgdlib/gdclass.h b/public/fgdlib/gdclass.h new file mode 100644 index 0000000..fe81bb3 --- /dev/null +++ b/public/fgdlib/gdclass.h @@ -0,0 +1,260 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the interface to a game class as defined by the game data +// file (FGD). Each class is type of entity that can be placed in +// the editor and has attributes such as: keys that may be set, +// the default size and color of the entity, inputs and outputs, +// and any default models that are created when the entity is placed. +// +// The game classes support multiple inheritence through aggregation +// of properties. +// +//=============================================================================// + +#ifndef GDCLASS_H +#define GDCLASS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "HelperInfo.h" +#include "TokenReader.h" +#include "GDVar.h" +#include "InputOutput.h" +#include "mathlib/vector.h" + +class CHelperInfo; +class GameData; +class GDinputvariable; + +const int GD_MAX_VARIABLES = 128; + + +class GDclass +{ + public: + + GDclass(void); + ~GDclass(void); + + // + // Interface to class information: + // + inline const char *GetName(void) { return(m_szName); } + inline const char *GetDescription(void); + + // + // Reading a class from the game data file: + // + BOOL InitFromTokens(TokenReader& tr, GameData*); + + // + // Interface to variable information (keys): + // + inline int GetVariableCount(void) { return(m_nVariables); } + GDinputvariable *GetVariableAt(int iIndex); + void GetHelperForGDVar( GDinputvariable *pVar, CUtlVector *helperName ); + GDinputvariable *VarForName(const char *pszName, int *piIndex = NULL); + BOOL AddVariable(GDinputvariable *pVar, GDclass *pBase, int iBaseIndex, int iVarIndex); + void AddBase(GDclass *pBase); + + // + // Interface to input information: + // + inline void AddInput(CClassInput *pInput); + CClassInput *FindInput(const char *szName); + inline int GetInputCount(void) { return(m_Inputs.Count()); } + CClassInput *GetInput(int nIndex); + + // + // Interface to output information: + // + inline void AddOutput(CClassOutput *pOutput); + CClassOutput *FindOutput(const char *szName); + inline int GetOutputCount(void) { return(m_Outputs.Count()); } + CClassOutput *GetOutput(int nIndex); + + GameData *Parent; + + // + // Interface to class attributes: + // + inline bool IsClass(const char *pszClass); + inline bool IsSolidClass(void) { return(m_bSolid); } + inline bool IsBaseClass(void) { return(m_bBase); } + inline bool IsMoveClass(void) { return(m_bMove); } + inline bool IsKeyFrameClass(void) { return(m_bKeyFrame); } + inline bool IsPointClass(void) { return(m_bPoint); } + inline bool IsNPCClass(void) { return(m_bNPC); } + inline bool IsFilterClass(void) { return(m_bFilter); } + inline bool IsNodeClass(void); + static inline bool IsNodeClass(const char *pszClassName); + + inline bool ShouldSnapToHalfGrid() { return m_bHalfGridSnap; } + + inline void SetNPCClass(bool bNPC) { m_bNPC = bNPC; } + inline void SetFilterClass(bool bFilter) { m_bFilter = bFilter; } + inline void SetPointClass(bool bPoint) { m_bPoint = bPoint; } + inline void SetSolidClass(bool bSolid) { m_bSolid = bSolid; } + inline void SetBaseClass(bool bBase) { m_bBase = bBase; } + inline void SetMoveClass(bool bMove) { m_bMove = bMove; } + inline void SetKeyFrameClass(bool bKeyFrame) { m_bKeyFrame = bKeyFrame; } + + inline const Vector &GetMins(void) { return(m_bmins); } + inline const Vector &GetMaxs(void) { return(m_bmaxs); } + + BOOL GetBoundBox(Vector& pfMins, Vector& pfMaxs); + bool HasBoundBox() const { return m_bGotSize; } + + inline color32 GetColor(void); + + // + // Interface to helper information: + // + inline void AddHelper(CHelperInfo *pHelper); + inline int GetHelperCount(void) { return(m_Helpers.Count()); } + CHelperInfo *GetHelper(int nIndex); + + protected: + + // + // Parsing the game data file: + // + bool ParseInput(TokenReader &tr); + bool ParseInputOutput(TokenReader &tr, CClassInputOutputBase *pInputOutput); + bool ParseOutput(TokenReader &tr); + bool ParseVariable(TokenReader &tr); + + private: + + bool ParseBase(TokenReader &tr); + bool ParseColor(TokenReader &tr); + bool ParseHelper(TokenReader &tr, char *pszHelperName); + bool ParseSize(TokenReader &tr); + bool ParseSpecifiers(TokenReader &tr); + bool ParseVariables(TokenReader &tr); + + color32 m_rgbColor; // Color of entity. + + bool m_bBase; // Base only - not available to user. + bool m_bSolid; // Tied to solids only. + bool m_bModel; // Properties of a single model. + bool m_bMove; // Animatable + bool m_bKeyFrame; // Animation keyframe + bool m_bPoint; // Point class, not tied to solids. + bool m_bNPC; // NPC class - used for populating lists of NPC classes. + bool m_bFilter; // filter class - used for populating lists of filters. + bool m_bHalfGridSnap; // Snaps to a 1/2 grid so it can be centered on any geometry. Used for hinges, etc. + + bool m_bGotSize; // Just for loading. + bool m_bGotColor; + + char m_szName[MAX_IDENT]; // Name of this class. + char *m_pszDescription; // Description of this class, dynamically allocated. + + CUtlVector m_Variables; // Variables for this class. + int m_nVariables; // Count of base & local variables combined. + CUtlVector m_Bases; // List of base classes this class inherits from. + + CClassInputList m_Inputs; + CClassOutputList m_Outputs; + + CHelperInfoList m_Helpers; // Helpers for this class. + + // + // [0] = base number from Bases, or -1 if not in a base. + // [1] = index into base's variables + // + signed short m_VariableMap[GD_MAX_VARIABLES][2]; + + Vector m_bmins; // 3D minima of object (pointclass). + Vector m_bmaxs; // 3D maxima of object (pointclass). +}; + + +void GDclass::AddInput(CClassInput *pInput) +{ + Assert(pInput != NULL); + if (pInput != NULL) + { + m_Inputs.AddToTail(pInput); + } +} + + +inline void GDclass::AddOutput(CClassOutput *pOutput) +{ + Assert(pOutput != NULL); + if (pOutput != NULL) + { + m_Outputs.AddToTail(pOutput); + } +} + + +inline void GDclass::AddHelper(CHelperInfo *pHelper) +{ + Assert(pHelper != NULL); + if (pHelper != NULL) + { + m_Helpers.AddToTail(pHelper); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the render color of this entity class. +//----------------------------------------------------------------------------- +color32 GDclass::GetColor(void) +{ + return m_rgbColor; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a description of this entity class, or the entity class name +// if no description exists. +//----------------------------------------------------------------------------- +const char *GDclass::GetDescription(void) +{ + if (m_pszDescription == NULL) + { + return(m_szName); + } + + return(m_pszDescription); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszClass - +//----------------------------------------------------------------------------- +bool GDclass::IsClass(const char *pszClass) +{ + Assert(pszClass != NULL); + return(!stricmp(pszClass, m_szName)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the given classname represents an AI node class, false if not. +//----------------------------------------------------------------------------- +bool GDclass::IsNodeClass(const char *pszClassName) +{ + return((strnicmp(pszClassName, "info_node", 9) == 0) && (stricmp(pszClassName, "info_node_link") != 0)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is an AI node class, false if not. +// +// HACK: if this is necessary, we should have a new @NodeClass FGD specifier (or something) +//----------------------------------------------------------------------------- +bool GDclass::IsNodeClass(void) +{ + return(IsNodeClass(m_szName)); +} + + +#endif // GDCLASS_H diff --git a/public/fgdlib/gdvar.h b/public/fgdlib/gdvar.h new file mode 100644 index 0000000..197ff30 --- /dev/null +++ b/public/fgdlib/gdvar.h @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GDVAR_H +#define GDVAR_H +#pragma once + +#include +#include // dvs: for MAX_STRING. Fix. + + +class MDkeyvalue; + + +enum GDIV_TYPE +{ + ivBadType = -1, + ivAngle, + ivTargetDest, + ivTargetNameOrClass, + ivTargetSrc, + ivInteger, + ivString, + ivChoices, + ivFlags, + ivDecal, + ivColor255, // components are 0-255 + ivColor1, // components are 0-1 + ivStudioModel, + ivSprite, + ivSound, + ivVector, + ivNPCClass, + ivFilterClass, + ivFloat, + ivMaterial, + ivScene, + ivSide, // One brush face ID. + ivSideList, // One or more brush face IDs, space delimited. + ivOrigin, // The origin of an entity, in the form "x y z". + ivVecLine, // An origin that draws a line back to the parent entity. + ivAxis, // The axis of rotation for a rotating entity, in the form "x0 y0 z0, x1 y1 z1". + ivPointEntityClass, + ivNodeDest, + ivInstanceFile, // used for hammer to know this field should display a browse button to find map files + ivAngleNegativePitch, // used for instance rotating when just a pitch value is present + ivInstanceVariable, // used for instance variables for easy hammer editing + ivInstanceParm, // used for instance parameter declaration + + ivMax // count of types +}; + + +//----------------------------------------------------------------------------- +// Defines an element in a choices/flags list. Choices values are strings; +// flags values are integers, hence the iValue and szValue members. +//----------------------------------------------------------------------------- +typedef struct +{ + unsigned long iValue; // Bitflag value for ivFlags + char szValue[MAX_STRING]; // String value for ivChoices + char szCaption[MAX_STRING]; // Name of this choice + BOOL bDefault; // Flag set by default? +} GDIVITEM; + + +class GDinputvariable +{ + public: + + GDinputvariable(); + GDinputvariable( const char *szType, const char *szName ); + ~GDinputvariable(); + + BOOL InitFromTokens(TokenReader& tr); + + // functions: + inline const char *GetName() { return m_szName; } + inline const char *GetLongName(void) { return m_szLongName; } + inline const char *GetDescription(void); + + inline int GetFlagCount() { return m_Items.Count(); } + inline int GetFlagMask(int nFlag); + inline const char *GetFlagCaption(int nFlag); + + inline int GetChoiceCount() { return m_Items.Count(); } + inline const char *GetChoiceCaption(int nChoice); + + inline GDIV_TYPE GetType() { return m_eType; } + const char *GetTypeText(void); + + inline void GetDefault(int *pnStore) + { + pnStore[0] = m_nDefault; + } + + inline void GetDefault(char *pszStore) + { + strcpy(pszStore, m_szDefault); + } + + GDIV_TYPE GetTypeFromToken(const char *pszToken); + trtoken_t GetStoreAsFromType(GDIV_TYPE eType); + + const char *ItemStringForValue(const char *szValue); + const char *ItemValueForString(const char *szString); + + BOOL IsFlagSet(unsigned int); + void SetFlag(unsigned int, BOOL bSet); + + void ResetDefaults(); + + void ToKeyValue(MDkeyvalue* pkv); + void FromKeyValue(MDkeyvalue* pkv); + + inline bool IsReportable(void); + inline bool IsReadOnly(void); + + GDinputvariable &operator =(GDinputvariable &Other); + void Merge(GDinputvariable &Other); + + static const char *GetVarTypeName( GDIV_TYPE eType ); + + private: + + // for choices/flags: + CUtlVector m_Items; + + static char *m_pszEmpty; + + char m_szName[MAX_IDENT]; + char m_szLongName[MAX_STRING]; + char *m_pszDescription; + + GDIV_TYPE m_eType; + + int m_nDefault; + char m_szDefault[MAX_STRING]; + + int m_nValue; + char m_szValue[MAX_STRING]; + + bool m_bReportable; + bool m_bReadOnly; + + friend class GDclass; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *GDinputvariable::GetDescription(void) +{ + if (m_pszDescription != NULL) + { + return(m_pszDescription); + } + + return(m_pszEmpty); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns whether or not this variable is read only. Read only variables +// cannot be edited in the Entity Properties dialog. +//----------------------------------------------------------------------------- +bool GDinputvariable::IsReadOnly(void) +{ + return(m_bReadOnly); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns whether or not this variable should be displayed in the Entity +// Report dialog. +//----------------------------------------------------------------------------- +bool GDinputvariable::IsReportable(void) +{ + return(m_bReportable); +} + + +//----------------------------------------------------------------------------- +// Returns the flag mask (eg 4096) for the flag at the given index. The +// array is packed, so it isn't just 1 >> nFlag. +//----------------------------------------------------------------------------- +int GDinputvariable::GetFlagMask(int nFlag) +{ + Assert(m_eType == ivFlags); + return m_Items.Element(nFlag).iValue; +} + + +//----------------------------------------------------------------------------- +// Returns the caption text (eg "Only break on trigger") for the flag at the given index. +//----------------------------------------------------------------------------- +const char *GDinputvariable::GetFlagCaption(int nFlag) +{ + Assert(m_eType == ivFlags); + return m_Items.Element(nFlag).szCaption; +} + + +//----------------------------------------------------------------------------- +// Returns the caption text (eg "Yes") for the choice at the given index. +//----------------------------------------------------------------------------- +const char *GDinputvariable::GetChoiceCaption(int nChoice) +{ + Assert(m_eType == ivChoices); + return m_Items.Element(nChoice).szCaption; +} + + +#endif // GDVAR_H diff --git a/public/fgdlib/helperinfo.h b/public/fgdlib/helperinfo.h new file mode 100644 index 0000000..affd566 --- /dev/null +++ b/public/fgdlib/helperinfo.h @@ -0,0 +1,128 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//============================================================================= + +#ifndef HELPERINFO_H +#define HELPERINFO_H +#pragma once + +#include +#include + + +#define MAX_HELPER_NAME_LEN 256 + + +typedef CUtlVector CParameterList; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHelperInfo +{ + public: + + inline CHelperInfo(void); + inline ~CHelperInfo(void); + + inline const char *GetName(void) const { return(m_szName); } + inline void SetName(const char *pszName); + + inline bool AddParameter(const char *pszParameter); + + inline int GetParameterCount(void) const { return(m_Parameters.Count()); } + inline const char *GetParameter(int nIndex) const; + + protected: + + char m_szName[MAX_HELPER_NAME_LEN]; + CParameterList m_Parameters; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline CHelperInfo::CHelperInfo(void) +{ + m_szName[0] = '\0'; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline CHelperInfo::~CHelperInfo(void) +{ + int nCount = m_Parameters.Count(); + for (int i = 0; i < nCount; i++) + { + char *pszParam = m_Parameters.Element(i); + Assert(pszParam != NULL); + if (pszParam != NULL) + { + delete [] pszParam; + } + } + + m_Parameters.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : char *pszParameter - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +inline bool CHelperInfo::AddParameter(const char *pszParameter) +{ + if ((pszParameter != NULL) && (pszParameter[0] != '\0')) + { + int nLen = strlen(pszParameter); + + if (nLen > 0) + { + char *pszNew = new char [nLen + 1]; + if (pszNew != NULL) + { + strcpy(pszNew, pszParameter); + m_Parameters.AddToTail(pszNew); + return(true); + } + } + } + + return(false); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +inline const char *CHelperInfo::GetParameter(int nIndex) const +{ + if (nIndex >= m_Parameters.Count()) + return NULL; + + return m_Parameters.Element(nIndex); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : char *pszName - +//----------------------------------------------------------------------------- +inline void CHelperInfo::SetName(const char *pszName) +{ + if (pszName != NULL) + { + strcpy(m_szName, pszName); + } +} + + +typedef CUtlVector CHelperInfoList; + + +#endif // HELPERINFO_H diff --git a/public/fgdlib/ieditortexture.h b/public/fgdlib/ieditortexture.h new file mode 100644 index 0000000..076839e --- /dev/null +++ b/public/fgdlib/ieditortexture.h @@ -0,0 +1,165 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the interface a given texture for the 3D renderer. Current +// implementations are for world textures (WADTexture.cpp) and sprite +// textures (Texture.cpp). +// +//============================================================================= + +#ifndef IEDITORTEXTURE_H +#define IEDITORTEXTURE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include + + +class CDC; +class CPalette; +class IMaterial; + +// FGDLIB: +#define DEFAULT_TEXTURE_SCALE 0.25 +#define DEFAULT_LIGHTMAP_SCALE 16 + + +// +// Set your texture ID to this in your implementation's constructor. +// +#define TEXTURE_ID_NONE -1 + + +// +// Texture formats. hack: MUST correlate with radio buttons in IDD_OPTIONS_CONFIGS. +// +enum TEXTUREFORMAT +{ + tfNone = -1, + tfWAD = 0, + tfWAL = 1, + tfWAD3 = 2, + tfWAD4 = 3, + tfWAD5 = 4, + tfVMT = 5, + tfSprite = 6 // dvs: not sure if I want to do it this way +}; + + +// +// Flags for DrawTexData_t. +// +#define drawCaption 0x01 +#define drawResizeAlways 0x02 +#define drawIcons 0x04 +#define drawErrors 0x08 +#define drawUsageCount 0x10 + + +struct DrawTexData_t +{ + int nFlags; + int nUsageCount; +}; + + +class IEditorTexture +{ + public: + + virtual ~IEditorTexture(void) + { + } + + // + // dvs: remove one of these + // + virtual int GetImageWidth( void ) const = 0; + virtual int GetImageHeight( void ) const = 0; + + virtual int GetWidth( void ) const = 0; + virtual int GetHeight( void ) const = 0; + + virtual float GetDecalScale( void ) const = 0; + + // + // dvs: Try to remove as many of these as possible: + // + virtual const char *GetName( void ) const = 0; + virtual int GetShortName( char *szShortName ) const = 0; + virtual int GetKeywords( char *szKeywords ) const = 0; + // FGDLIB: + //virtual void Draw(CDC *pDC, RECT &rect, int iFontHeight, int iIconHeight, DrawTexData_t &DrawTexData) = 0; + virtual TEXTUREFORMAT GetTextureFormat( void ) const = 0; + virtual int GetSurfaceAttributes( void ) const = 0; + virtual int GetSurfaceContents(void ) const = 0; + virtual int GetSurfaceValue( void ) const = 0; + virtual CPalette *GetPalette( void ) const = 0; + virtual bool HasData( void ) const = 0; + virtual bool HasPalette( void ) const = 0; + virtual bool Load( void ) = 0; // ensure that texture is loaded. could this be done internally? + virtual void Reload( void ) = 0; // The texture changed + virtual bool IsLoaded( void ) const = 0; + virtual const char *GetFileName( void ) const = 0; + + virtual bool IsWater( void ) const = 0; + + //----------------------------------------------------------------------------- + // Purpose: + // Input : pData - + // Output : + //----------------------------------------------------------------------------- + virtual int GetImageDataRGB( void *pData = NULL ) = 0; + + //----------------------------------------------------------------------------- + // Purpose: + // Input : pData - + // Output : + //----------------------------------------------------------------------------- + virtual int GetImageDataRGBA( void *pData = NULL ) = 0; + + //----------------------------------------------------------------------------- + // Purpose: Returns true if this texture has an alpha component, false if not. + //----------------------------------------------------------------------------- + virtual bool HasAlpha( void ) const = 0; + + //----------------------------------------------------------------------------- + // Purpose: Returns whether this texture is a dummy texture or not. Dummy textures + // serve as placeholders for textures that were found in the map, but + // not in the WAD (or the materials tree). The dummy texture enables us + // to bind the texture, find it by name, etc. + //----------------------------------------------------------------------------- + virtual bool IsDummy( void ) const = 0; // dvs: perhaps not the best name? + + //----------------------------------------------------------------------------- + // Purpose: Returns the unique texture ID for this texture object. The texture ID + // identifies the texture object across all renderers, and is assigned + // by the first renderer that actually binds the texture thru BindTexture. + // + // Only the renderer ever needs to call SetTextureID. + //----------------------------------------------------------------------------- + virtual int GetTextureID( void ) const = 0; + + //----------------------------------------------------------------------------- + // Purpose: Sets the unique texture ID for this texture object. The texture ID + // identifies the texture object across all renderers, and is assigned + // by the first renderer that actually binds the texture thru BindTexture. + // + // Only the renderer should ever call SetTextureID! + //----------------------------------------------------------------------------- + virtual void SetTextureID( int nTextureID ) = 0; + + //----------------------------------------------------------------------------- + // Returns the material system material associated with a texture + //----------------------------------------------------------------------------- + + virtual IMaterial* GetMaterial() { return 0; } +}; + + +typedef CUtlVector EditorTextureList_t; + + +#endif // IEDITORTEXTURE_H diff --git a/public/fgdlib/inputoutput.h b/public/fgdlib/inputoutput.h new file mode 100644 index 0000000..7438f08 --- /dev/null +++ b/public/fgdlib/inputoutput.h @@ -0,0 +1,105 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//============================================================================= + +#ifndef INPUTOUTPUT_H +#define INPUTOUTPUT_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "fgdlib/EntityDefs.h" + + +enum InputOutputType_t +{ + iotInvalid = -1, + iotVoid, + iotInt, + iotBool, + iotString, + iotFloat, + iotVector, + iotEHandle, + iotColor, +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CClassInputOutputBase +{ + public: + + CClassInputOutputBase(void); + CClassInputOutputBase(const char *pszName, InputOutputType_t eType); + virtual ~CClassInputOutputBase(void); + + inline const char *GetName(void) { return(m_szName); } + InputOutputType_t GetType(void) { return(m_eType); } + const char *GetTypeText(void); + inline const char *GetDescription(void); + + inline void SetName(const char *szName) { V_strcpy_safe(m_szName, szName); } + inline void SetType(InputOutputType_t eType) { m_eType = eType; } + InputOutputType_t SetType(const char *szType); + inline void SetDescription(char *pszDescription) { m_pszDescription = pszDescription; } + + CClassInputOutputBase &operator =(CClassInputOutputBase &); + + protected: + + static char *g_pszEmpty; + + char m_szName[MAX_IO_NAME_LEN]; + InputOutputType_t m_eType; + char *m_pszDescription; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Returns this I/O's long description. +//----------------------------------------------------------------------------- +const char *CClassInputOutputBase::GetDescription(void) +{ + if (m_pszDescription != NULL) + { + return(m_pszDescription); + } + + return(g_pszEmpty); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CClassInput : public CClassInputOutputBase +{ + public: + + CClassInput(void); + CClassInput(const char *pszName, InputOutputType_t eType); +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CClassOutput : public CClassInputOutputBase +{ + public: + + CClassOutput(void); + CClassOutput(const char *pszName, InputOutputType_t eType); +}; + + +typedef CUtlVector CClassInputList; +typedef CUtlVector CClassOutputList; + + +#endif // INPUTOUTPUT_H diff --git a/public/fgdlib/wckeyvalues.h b/public/fgdlib/wckeyvalues.h new file mode 100644 index 0000000..730d92d --- /dev/null +++ b/public/fgdlib/wckeyvalues.h @@ -0,0 +1,233 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WCKEYVALUES_H +#define WCKEYVALUES_H +#pragma once + + +#include +#include +#include +#pragma warning(push, 1) +#pragma warning(disable:4701 4702 4530) +#include +#pragma warning(pop) + + +#define KEYVALUE_MAX_KEY_LENGTH 80 +#define KEYVALUE_MAX_VALUE_LENGTH 512 + + +class MDkeyvalue +{ + public: + + // + // Constructors/Destructor. + // + inline MDkeyvalue(void); + inline MDkeyvalue(const char *pszKey, const char *pszValue); + ~MDkeyvalue(void); + + MDkeyvalue &operator =(const MDkeyvalue &other); + + inline void Set(const char *pszKey, const char *pszValue); + inline const char *Key(void) const; + inline const char *Value(void) const; + + // + // Serialization functions. + // + int SerializeRMF(std::fstream &f, BOOL bRMF); + int SerializeMAP(std::fstream &f, BOOL bRMF); + + char szKey[KEYVALUE_MAX_KEY_LENGTH]; // The name of this key. + char szValue[KEYVALUE_MAX_VALUE_LENGTH]; // The value of this key, stored as a string. +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. +//----------------------------------------------------------------------------- +MDkeyvalue::MDkeyvalue(void) +{ + szKey[0] = '\0'; + szValue[0] = '\0'; +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor with assignment. +//----------------------------------------------------------------------------- +MDkeyvalue::MDkeyvalue(const char *pszKey, const char *pszValue) +{ + szKey[0] = '\0'; + szValue[0] = '\0'; + + Set(pszKey, pszValue); +} + + +//----------------------------------------------------------------------------- +// Purpose: Assigns a key and value. +//----------------------------------------------------------------------------- +void MDkeyvalue::Set(const char *pszKey, const char *pszValue) +{ + Assert(pszKey); + Assert(pszValue); + + strcpy(szKey, pszKey); + strcpy(szValue, pszValue); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the string keyname. +//----------------------------------------------------------------------------- +const char *MDkeyvalue::Key(void) const +{ + return szKey; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the string value of this keyvalue. +//----------------------------------------------------------------------------- +const char *MDkeyvalue::Value(void) const +{ + return szValue; +} + + +typedef CUtlVector KeyValueArray; + + +// Used in cases where there can be duplicate key names. +class WCKVBase_Vector +{ +public: + + // Iteration helpers. + inline int GetCount() const { return m_KeyValues.Count(); } + inline int GetFirst() const { return m_KeyValues.Count() - 1; } + inline int GetNext( int i ) const { return i - 1; } + static inline int GetInvalidIndex() { return -1; } + + void RemoveKeyAt(int nIndex); + int FindByKeyName( const char *pKeyName ) const; // Returns the same value as GetInvalidIndex if not found. + + // Special function used for non-unique keyvalue lists. + void AddKeyValue(const char *pszKey, const char *pszValue); + +protected: + + void InsertKeyValue( const MDkeyvalue &kv ); + +protected: + CUtlVector m_KeyValues; +}; + +// Used for most key/value sets because it's fast. Does not allow duplicate key names. +class WCKVBase_Dict +{ +public: + + // Iteration helpers. Note that there is no GetCount() because you can't iterate + // these by incrementing a counter. + inline int GetFirst() const { return m_KeyValues.First(); } + inline int GetNext( int i ) const { return m_KeyValues.Next( i ); } + static inline int GetInvalidIndex() { return CUtlDict::InvalidIndex(); } + + int FindByKeyName( const char *pKeyName ) const; // Returns the same value as GetInvalidIndex if not found. + void RemoveKeyAt(int nIndex); + +protected: + void InsertKeyValue( const MDkeyvalue &kv ); + +protected: + CUtlDict m_KeyValues; +}; + + +// See below for typedefs of this class you can use. +template +class WCKeyValuesT : public Base +{ +public: + + WCKeyValuesT(void); + ~WCKeyValuesT(void); + + void RemoveAll(void); + void RemoveKey(const char *pszKey); + + void SetValue(const char *pszKey, const char *pszValue); + void SetValue(const char *pszKey, int iValue); + + const char *GetKey(int nIndex) const; + MDkeyvalue &GetKeyValue(int nIndex); + const MDkeyvalue& GetKeyValue(int nIndex) const; + const char *GetValue(int nIndex) const; + const char *GetValue(const char *pszKey, int *piIndex = NULL) const; +}; + + +// These have explicit template instantiations so you can use them. +typedef WCKeyValuesT WCKeyValues; +typedef WCKeyValuesT WCKeyValuesVector; + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nIndex - +//----------------------------------------------------------------------------- +template +inline const char *WCKeyValuesT::GetKey(int nIndex) const +{ + return(m_KeyValues.Element(nIndex).szKey); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nIndex - +// Output : MDKeyValue +//----------------------------------------------------------------------------- +template +inline MDkeyvalue &WCKeyValuesT::GetKeyValue(int nIndex) +{ + return(m_KeyValues.Element(nIndex)); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nIndex - +// Output : MDkeyvalue +//----------------------------------------------------------------------------- +template +inline const MDkeyvalue& WCKeyValuesT::GetKeyValue(int nIndex) const +{ + return(m_KeyValues.Element(nIndex)); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nIndex - +//----------------------------------------------------------------------------- +template +inline const char *WCKeyValuesT::GetValue(int nIndex) const +{ + return(m_KeyValues.Element(nIndex).szValue); +} + + +void StripEdgeWhiteSpace(char *psz); + + +#endif // WCKEYVALUES_H diff --git a/public/filesystem.h b/public/filesystem.h new file mode 100644 index 0000000..8c7d81b --- /dev/null +++ b/public/filesystem.h @@ -0,0 +1,1014 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H +#pragma once + +#include + +#include "tier0/threadtools.h" +#include "tier0/memalloc.h" +#include "tier1/interface.h" +#include "tier1/utlsymbol.h" +#include "tier1/utlstring.h" +#include "appframework/IAppSystem.h" +#include "tier1/checksum_crc.h" +#include "tier1/checksum_md5.h" +#include "tier1/refcount.h" + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +class CUtlBuffer; +class KeyValues; +class IFileList; +class IThreadPool; +class CMemoryFileBacking; + +typedef void * FileHandle_t; +typedef void * FileCacheHandle_t; +typedef int FileFindHandle_t; +typedef void (*FileSystemLoggingFunc_t)( const char *fileName, const char *accessType ); +typedef int WaitForResourcesHandle_t; + +#ifdef _X360 +typedef void* HANDLE; +#endif + +#define USE_CRC_FILE_TRACKING 0 + +// Turn on some extra pure server debug spew in certain builds. +// WARNING: This spew can be used by hackers to locate places to hack +// the code to bypas sv_pure! Be careful! +#if defined( _DEBUG ) || defined( STAGING_ONLY ) + #define PURE_SERVER_DEBUG_SPEW +#endif + +/// How strict will the pure server be for a particular set of files +enum EPureServerFileClass +{ + ePureServerFileClass_Unknown = -1, // dummy debugging value + ePureServerFileClass_Any = 0, + ePureServerFileClass_AnyTrusted, + ePureServerFileClass_CheckHash, +}; + +class IPureServerWhitelist +{ +public: + + // Reference counting + virtual void AddRef() = 0; + virtual void Release() = 0; + + // What should we do with a particular file? + virtual EPureServerFileClass GetFileClass( const char *pszFilename ) = 0; + + // Access list of trusted keys which we will allow to set trusted content + virtual int GetTrustedKeyCount() const = 0; + virtual const byte *GetTrustedKey( int iKeyIndex, int *nKeySize ) const = 0; +}; + +//----------------------------------------------------------------------------- +// Enums used by the interface +//----------------------------------------------------------------------------- + +#define FILESYSTEM_MAX_SEARCH_PATHS 128 + +enum FileSystemSeek_t +{ + FILESYSTEM_SEEK_HEAD = SEEK_SET, + FILESYSTEM_SEEK_CURRENT = SEEK_CUR, + FILESYSTEM_SEEK_TAIL = SEEK_END, +}; + +enum +{ + FILESYSTEM_INVALID_FIND_HANDLE = -1 +}; + +enum FileWarningLevel_t +{ + // A problem! + FILESYSTEM_WARNING = -1, + + // Don't print anything + FILESYSTEM_WARNING_QUIET = 0, + + // On shutdown, report names of files left unclosed + FILESYSTEM_WARNING_REPORTUNCLOSED, + + // Report number of times a file was opened, closed + FILESYSTEM_WARNING_REPORTUSAGE, + + // Report all open/close events to console ( !slow! ) + FILESYSTEM_WARNING_REPORTALLACCESSES, + + // Report all open/close/read events to the console ( !slower! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_READ, + + // Report all open/close/read/write events to the console ( !slower! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, + + // Report all open/close/read/write events and all async I/O file events to the console ( !slower(est)! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC, + +}; + +// search path filtering +enum PathTypeFilter_t +{ + FILTER_NONE = 0, // no filtering, all search path types match + FILTER_CULLPACK = 1, // pack based search paths are culled (maps and zips) + FILTER_CULLNONPACK = 2, // non-pack based search paths are culled +}; + +// search path querying (bit flags) +enum +{ + PATH_IS_NORMAL = 0x00, // normal path, not pack based + PATH_IS_PACKFILE = 0x01, // path is a pack file + PATH_IS_MAPPACKFILE = 0x02, // path is a map pack file + PATH_IS_REMOTE = 0x04, // path is the remote filesystem +}; +typedef uint32 PathTypeQuery_t; + +#define IS_PACKFILE( n ) ( n & ( PATH_IS_PACKFILE | PATH_IS_MAPPACKFILE ) ) +#define IS_REMOTE( n ) ( n & PATH_IS_REMOTE ) + +enum DVDMode_t +{ + DVDMODE_OFF = 0, // not using dvd + DVDMODE_STRICT = 1, // dvd device only + DVDMODE_DEV = 2, // dev mode, mutiple devices ok +}; + +// In non-retail builds, enable the file blocking access tracking stuff... +#if defined( TRACK_BLOCKING_IO ) +enum FileBlockingWarning_t +{ + // Report how long synchronous i/o took to complete + FILESYSTEM_BLOCKING_SYNCHRONOUS = 0, + // Report how long async i/o took to complete if AsyncFileFinished caused it to load via "blocking" i/o + FILESYSTEM_BLOCKING_ASYNCHRONOUS_BLOCK, + // Report how long async i/o took to complete + FILESYSTEM_BLOCKING_ASYNCHRONOUS, + // Report how long the async "callback" took + FILESYSTEM_BLOCKING_CALLBACKTIMING, + + FILESYSTEM_BLOCKING_NUMBINS, +}; + +#pragma pack(1) +class FileBlockingItem +{ +public: + enum + { + FB_ACCESS_OPEN = 1, + FB_ACCESS_CLOSE = 2, + FB_ACCESS_READ = 3, + FB_ACCESS_WRITE = 4, + FB_ACCESS_APPEND = 5, + FB_ACCESS_SIZE = 6 + }; + + FileBlockingItem() : + m_ItemType( (FileBlockingWarning_t)0 ), + m_flElapsed( 0.0f ), + m_nAccessType( 0 ) + { + SetFileName( NULL ); + } + + FileBlockingItem( int type, char const *filename, float elapsed, int accessType ) : + m_ItemType( (FileBlockingWarning_t)type ), + m_flElapsed( elapsed ), + m_nAccessType( accessType ) + { + SetFileName( filename ); + } + + void SetFileName( char const *filename ) + { + if ( !filename ) + { + m_szFilename[ 0 ] = 0; + return; + } + + int len = Q_strlen( filename ); + if ( len >= sizeof( m_szFilename ) ) + { + Q_strncpy( m_szFilename, &filename[ len - sizeof( m_szFilename ) + 1 ], sizeof( m_szFilename ) ); + } + else + { + Q_strncpy( m_szFilename, filename, sizeof( m_szFilename ) ); + } + } + + char const *GetFileName() const + { + return m_szFilename; + } + + FileBlockingWarning_t m_ItemType; + float m_flElapsed; + byte m_nAccessType; +private: + + char m_szFilename[ 32 ]; +}; +#pragma pack() + +class IBlockingFileItemList +{ +public: + + // You can't call any of the below calls without locking first + virtual void LockMutex() = 0; + virtual void UnlockMutex() = 0; + + virtual int First() const = 0; + virtual int Next( int i ) const = 0; + virtual int InvalidIndex() const = 0; + + virtual const FileBlockingItem& Get( int index ) const = 0; + + virtual void Reset() = 0; +}; + +#endif // TRACK_BLOCKING_IO + +enum FilesystemMountRetval_t +{ + FILESYSTEM_MOUNT_OK = 0, + FILESYSTEM_MOUNT_FAILED, +}; + +enum SearchPathAdd_t +{ + PATH_ADD_TO_HEAD, // First path searched + PATH_ADD_TO_TAIL, // Last path searched +}; + +enum FilesystemOpenExFlags_t +{ + FSOPEN_UNBUFFERED = (1 << 0), + FSOPEN_FORCE_TRACK_CRC = (1 << 1), // This makes it calculate a CRC for the file (if the file came from disk) regardless + // of the IFileList passed to RegisterFileWhitelist. + FSOPEN_NEVERINPACK = (1 << 2), // 360 only, hint to FS that file is not allowed to be in pack file +}; + +#define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 + +//----------------------------------------------------------------------------- +// Structures used by the interface +//----------------------------------------------------------------------------- + +struct FileSystemStatistics +{ + CInterlockedUInt nReads, + nWrites, + nBytesRead, + nBytesWritten, + nSeeks; +}; + +//----------------------------------------------------------------------------- +// File system allocation functions. Client must free on failure +//----------------------------------------------------------------------------- +typedef void *(*FSAllocFunc_t)( const char *pszFilename, unsigned nBytes ); + + +//----------------------------------------------------------------------------- +// Used to display dirty disk error functions +//----------------------------------------------------------------------------- +typedef void (*FSDirtyDiskReportFunc_t)(); + + +//----------------------------------------------------------------------------- +// Asynchronous support types +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE(FSAsyncControl_t); +DECLARE_POINTER_HANDLE(FSAsyncFile_t); +const FSAsyncFile_t FS_INVALID_ASYNC_FILE = (FSAsyncFile_t)(0x0000ffff); + + +//--------------------------------------------------------- +// Async file status +//--------------------------------------------------------- +enum FSAsyncStatus_t +{ + FSASYNC_ERR_NOT_MINE = -8, // Filename not part of the specified file system, try a different one. (Used internally to find the right filesystem) + FSASYNC_ERR_RETRY_LATER = -7, // Failure for a reason that might be temporary. You might retry, but not immediately. (E.g. Network problems) + FSASYNC_ERR_ALIGNMENT = -6, // read parameters invalid for unbuffered IO + FSASYNC_ERR_FAILURE = -5, // hard subsystem failure + FSASYNC_ERR_READING = -4, // read error on file + FSASYNC_ERR_NOMEMORY = -3, // out of memory for file read + FSASYNC_ERR_UNKNOWNID = -2, // caller's provided id is not recognized + FSASYNC_ERR_FILEOPEN = -1, // filename could not be opened (bad path, not exist, etc) + FSASYNC_OK = 0, // operation is successful + FSASYNC_STATUS_PENDING, // file is properly queued, waiting for service + FSASYNC_STATUS_INPROGRESS, // file is being accessed + FSASYNC_STATUS_ABORTED, // file was aborted by caller + FSASYNC_STATUS_UNSERVICED, // file is not yet queued +}; + +//--------------------------------------------------------- +// Async request flags +//--------------------------------------------------------- +enum FSAsyncFlags_t +{ + FSASYNC_FLAGS_ALLOCNOFREE = ( 1 << 0 ), // do the allocation for dataPtr, but don't free + FSASYNC_FLAGS_FREEDATAPTR = ( 1 << 1 ), // free the memory for the dataPtr post callback + FSASYNC_FLAGS_SYNC = ( 1 << 2 ), // Actually perform the operation synchronously. Used to simplify client code paths + FSASYNC_FLAGS_NULLTERMINATE = ( 1 << 3 ), // allocate an extra byte and null terminate the buffer read in +}; + +//--------------------------------------------------------- +// Return value for CheckFileCRC. +//--------------------------------------------------------- +enum EFileCRCStatus +{ + k_eFileCRCStatus_CantOpenFile, // We don't have this file. + k_eFileCRCStatus_GotCRC, + k_eFileCRCStatus_FileInVPK +}; + +// Used in CacheFileCRCs. +enum ECacheCRCType +{ + k_eCacheCRCType_SingleFile, + k_eCacheCRCType_Directory, + k_eCacheCRCType_Directory_Recursive +}; + +//--------------------------------------------------------- +// Optional completion callback for each async file serviced (or failed) +// call is not reentrant, async i/o guaranteed suspended until return +// Note: If you change the signature of the callback, you will have to account for it in FileSystemV12 (toml [4/18/2005] ) +//--------------------------------------------------------- +struct FileAsyncRequest_t; +typedef void (*FSAsyncCallbackFunc_t)(const FileAsyncRequest_t &request, int nBytesRead, FSAsyncStatus_t err); + +//--------------------------------------------------------- +// Description of an async request +//--------------------------------------------------------- +struct FileAsyncRequest_t +{ + FileAsyncRequest_t() { memset( this, 0, sizeof(*this) ); hSpecificAsyncFile = FS_INVALID_ASYNC_FILE; } + const char * pszFilename; // file system name + void * pData; // optional, system will alloc/free if NULL + int nOffset; // optional initial seek_set, 0=beginning + int nBytes; // optional read clamp, -1=exist test, 0=full read + FSAsyncCallbackFunc_t pfnCallback; // optional completion callback + void * pContext; // caller's unique file identifier + int priority; // inter list priority, 0=lowest + unsigned flags; // behavior modifier + const char * pszPathID; // path ID (NOTE: this field is here to remain binary compatible with release HL2 filesystem interface) + FSAsyncFile_t hSpecificAsyncFile; // Optional hint obtained using AsyncBeginRead() + FSAllocFunc_t pfnAlloc; // custom allocator. can be null. not compatible with FSASYNC_FLAGS_FREEDATAPTR +}; + + +struct FileHash_t +{ + enum EFileHashType_t + { + k_EFileHashTypeUnknown = 0, + k_EFileHashTypeEntireFile = 1, + k_EFileHashTypeIncompleteFile = 2, + }; + FileHash_t() + { + m_eFileHashType = FileHash_t::k_EFileHashTypeUnknown; + m_cbFileLen = 0; + m_PackFileID = 0; + m_nPackFileNumber = 0; + } + int m_eFileHashType; + CRC32_t m_crcIOSequence; + MD5Value_t m_md5contents; + int m_cbFileLen; + int m_PackFileID; + int m_nPackFileNumber; + + bool operator==( const FileHash_t &src ) const + { + return m_crcIOSequence == src.m_crcIOSequence && + m_md5contents == src.m_md5contents && + m_eFileHashType == src.m_eFileHashType; + } + bool operator!=( const FileHash_t &src ) const + { + return m_crcIOSequence != src.m_crcIOSequence || + m_md5contents != src.m_md5contents || + m_eFileHashType != src.m_eFileHashType; + } + +}; + +class CUnverifiedFileHash +{ +public: + char m_PathID[MAX_PATH]; + char m_Filename[MAX_PATH]; + int m_nFileFraction; + FileHash_t m_FileHash; +}; + +class CUnverifiedCRCFile +{ +public: + char m_PathID[MAX_PATH]; + char m_Filename[MAX_PATH]; + CRC32_t m_CRC; +}; + +class CUnverifiedMD5File +{ +public: + char m_PathID[MAX_PATH]; + char m_Filename[MAX_PATH]; + unsigned char bits[MD5_DIGEST_LENGTH]; +}; + +// Spew flags for SetWhitelistSpewFlags (set with the fs_whitelist_spew_flags cvar). +// Update the comment for the fs_whitelist_spew_flags cvar if you change these. +#define WHITELIST_SPEW_WHILE_LOADING 0x0001 // list files as they are added to the CRC tracker +#define WHITELIST_SPEW_RELOAD_FILES 0x0002 // show files the filesystem is telling the engine to reload +#define WHITELIST_SPEW_DONT_RELOAD_FILES 0x0004 // show files the filesystem is NOT telling the engine to reload + +//----------------------------------------------------------------------------- +// Interface to fetch a file asynchronously from any source. This is used +// as a hook +//----------------------------------------------------------------------------- + +abstract_class IAsyncFileFetch { +public: + typedef void *Handle; + + /// Initiate a request. Returns error status, or on success + /// returns an opaque handle used to terminate the job + /// + /// Should return FSASYNC_ERR_NOT_MINE if the filename isn't + /// handled by this interface + /// + /// The callback is required, and is the only mechanism to communicate + /// status. (No polling.) The request is automatically destroyed anytime + /// after the callback is executed. + virtual FSAsyncStatus_t Start( const FileAsyncRequest_t &request, Handle *pOutHandle, IThreadPool *pThreadPool ) = 0; + + /// Attempt to complete any active work, returning status. The callback WILL + /// be executed (this is necessary in case we allocated the buffer). + /// Afterwards, the request is automatically destroyed. + virtual FSAsyncStatus_t FinishSynchronous( Handle hControl ) = 0; + + /// Terminate any active work and destroy all resources and bookkeeping info. + /// The callback will NOT be executed. + virtual FSAsyncStatus_t Abort( Handle hControl ) = 0; +}; + +// This interface is for VPK files to communicate with FileTracker +abstract_class IThreadedFileMD5Processor +{ +public: + virtual int SubmitThreadedMD5Request( uint8 *pubBuffer, int cubBuffer, int PackFileID, int nPackFileNumber, int nPackFileFraction ) = 0; + virtual bool BlockUntilMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut ) = 0; + virtual bool IsMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut ) = 0; +}; + +//----------------------------------------------------------------------------- +// Base file system interface +//----------------------------------------------------------------------------- + +// This is the minimal interface that can be implemented to provide access to +// a named set of files. +#define BASEFILESYSTEM_INTERFACE_VERSION "VBaseFileSystem011" + +abstract_class IBaseFileSystem +{ +public: + virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; + virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; + + // if pathID is NULL, all paths will be searched for the file + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = 0 ) = 0; + virtual void Close( FileHandle_t file ) = 0; + + + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; + virtual unsigned int Tell( FileHandle_t file ) = 0; + virtual unsigned int Size( FileHandle_t file ) = 0; + virtual unsigned int Size( const char *pFileName, const char *pPathID = 0 ) = 0; + + virtual void Flush( FileHandle_t file ) = 0; + virtual bool Precache( const char *pFileName, const char *pPathID = 0 ) = 0; + + virtual bool FileExists( const char *pFileName, const char *pPathID = 0 ) = 0; + virtual bool IsFileWritable( char const *pFileName, const char *pPathID = 0 ) = 0; + virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID = 0 ) = 0; + + virtual long GetFileTime( const char *pFileName, const char *pPathID = 0 ) = 0; + + //-------------------------------------------------------- + // Reads/writes files to utlbuffers. Use this for optimal read performance when doing open/read/close + //-------------------------------------------------------- + virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; + virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf ) = 0; + virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Main file system interface +//----------------------------------------------------------------------------- + +#define FILESYSTEM_INTERFACE_VERSION "VFileSystem022" + +abstract_class IFileSystem : public IAppSystem, public IBaseFileSystem +{ +public: + //-------------------------------------------------------- + // Steam operations + //-------------------------------------------------------- + + virtual bool IsSteam() const = 0; + + // Supplying an extra app id will mount this app in addition + // to the one specified in the environment variable "steamappid" + // + // If nExtraAppId is < -1, then it will mount that app ID only. + // (Was needed by the dedicated server b/c the "SteamAppId" env var only gets passed to steam.dll + // at load time, so the dedicated couldn't pass it in that way). + virtual FilesystemMountRetval_t MountSteamContent( int nExtraAppId = -1 ) = 0; + + //-------------------------------------------------------- + // Search path manipulation + //-------------------------------------------------------- + + // Add paths in priority order (mod dir, game dir, ....) + // If one or more .pak files are in the specified directory, then they are + // added after the file system path + // If the path is the relative path to a .bsp file, then any previous .bsp file + // override is cleared and the current .bsp is searched for an embedded PAK file + // and this file becomes the highest priority search path ( i.e., it's looked at first + // even before the mod's file system path ). + virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType = PATH_ADD_TO_TAIL ) = 0; + virtual bool RemoveSearchPath( const char *pPath, const char *pathID = 0 ) = 0; + + // Remove all search paths (including write path?) + virtual void RemoveAllSearchPaths( void ) = 0; + + // Remove search paths associated with a given pathID + virtual void RemoveSearchPaths( const char *szPathID ) = 0; + + // This is for optimization. If you mark a path ID as "by request only", then files inside it + // will only be accessed if the path ID is specifically requested. Otherwise, it will be ignored. + // If there are currently no search paths with the specified path ID, then it will still + // remember it in case you add search paths with this path ID. + virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly ) = 0; + + // converts a partial path into a full path + // Prefer using the RelativePathToFullPath_safe template wrapper to calling this directly + virtual const char *RelativePathToFullPath( const char *pFileName, const char *pPathID, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL ) = 0; + template const char *RelativePathToFullPath_safe( const char *pFileName, const char *pPathID, OUT_Z_ARRAY char (&pDest)[maxLenInChars], PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL ) + { + return RelativePathToFullPath( pFileName, pPathID, pDest, (int)maxLenInChars, pathFilter, pPathType ); + } + + // Returns the search path, each path is separated by ;s. Returns the length of the string returned + // Prefer using the GetSearchPath_safe template wrapper to calling this directly + virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; + template int GetSearchPath_safe( const char *pathID, bool bGetPackFiles, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) + { + return GetSearchPath( pathID, bGetPackFiles, pDest, (int)maxLenInChars ); + } + + // interface for custom pack files > 4Gb + virtual bool AddPackFile( const char *fullpath, const char *pathID ) = 0; + + //-------------------------------------------------------- + // File manipulation operations + //-------------------------------------------------------- + + // Deletes a file (on the WritePath) + virtual void RemoveFile( char const* pRelativePath, const char *pathID = 0 ) = 0; + + // Renames a file (on the WritePath) + virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID = 0 ) = 0; + + // create a local directory structure + virtual void CreateDirHierarchy( const char *path, const char *pathID = 0 ) = 0; + + // File I/O and info + virtual bool IsDirectory( const char *pFileName, const char *pathID = 0 ) = 0; + + virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) = 0; + + //-------------------------------------------------------- + // Open file operations + //-------------------------------------------------------- + + virtual void SetBufferSize( FileHandle_t file, unsigned nBytes ) = 0; + + virtual bool IsOk( FileHandle_t file ) = 0; + + virtual bool EndOfFile( FileHandle_t file ) = 0; + + virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) = 0; + virtual int FPrintf( FileHandle_t file, PRINTF_FORMAT_STRING const char *pFormat, ... ) = 0; + + //-------------------------------------------------------- + // Dynamic library operations + //-------------------------------------------------------- + + // load/unload modules + virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID = 0, bool bValidatedDllOnly = true ) = 0; + virtual void UnloadModule( CSysModule *pModule ) = 0; + + //-------------------------------------------------------- + // File searching operations + //-------------------------------------------------------- + + // FindFirst/FindNext. Also see FindFirstEx. + virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle ) = 0; + virtual const char *FindNext( FileFindHandle_t handle ) = 0; + virtual bool FindIsDirectory( FileFindHandle_t handle ) = 0; + virtual void FindClose( FileFindHandle_t handle ) = 0; + + // Same as FindFirst, but you can filter by path ID, which can make it faster. + virtual const char *FindFirstEx( + const char *pWildCard, + const char *pPathID, + FileFindHandle_t *pHandle + ) = 0; + + //-------------------------------------------------------- + // File name and directory operations + //-------------------------------------------------------- + + // FIXME: This method is obsolete! Use RelativePathToFullPath instead! + // converts a partial path into a full path + // Prefer using the GetLocalPath_safe template wrapper to calling this directly + virtual const char *GetLocalPath( const char *pFileName, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; + template const char *GetLocalPath_safe( const char *pFileName, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) + { + return GetLocalPath( pFileName, pDest, (int)maxLenInChars ); + } + + // Returns true on success ( based on current list of search paths, otherwise false if + // it can't be resolved ) + // Prefer using the FullPathToRelativePath_safe template wrapper to calling this directly + virtual bool FullPathToRelativePath( const char *pFullpath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; + template bool FullPathToRelativePath_safe( const char *pFullpath, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) + { + return FullPathToRelativePath( pFullpath, pDest, (int)maxLenInChars ); + } + + // Gets the current working directory + virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) = 0; + + //-------------------------------------------------------- + // Filename dictionary operations + //-------------------------------------------------------- + + virtual FileNameHandle_t FindOrAddFileName( char const *pFileName ) = 0; + virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen ) = 0; + + //-------------------------------------------------------- + // Asynchronous file operations + //-------------------------------------------------------- + + //------------------------------------ + // Global operations + //------------------------------------ + FSAsyncStatus_t AsyncRead( const FileAsyncRequest_t &request, FSAsyncControl_t *phControl = NULL ) { return AsyncReadMultiple( &request, 1, phControl ); } + virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *phControls = NULL ) = 0; + virtual FSAsyncStatus_t AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl = NULL ) = 0; + virtual FSAsyncStatus_t AsyncAppendFile(const char *pAppendToFileName, const char *pAppendFromFileName, FSAsyncControl_t *pControl = NULL ) = 0; + virtual void AsyncFinishAll( int iToPriority = 0 ) = 0; + virtual void AsyncFinishAllWrites() = 0; + virtual FSAsyncStatus_t AsyncFlush() = 0; + virtual bool AsyncSuspend() = 0; + virtual bool AsyncResume() = 0; + + /// Add async fetcher interface. This gives apps a hook to intercept async requests and + /// pull the data from a source of their choosing. The immediate use case is to load + /// assets from the CDN via HTTP. + virtual void AsyncAddFetcher( IAsyncFileFetch *pFetcher ) = 0; + virtual void AsyncRemoveFetcher( IAsyncFileFetch *pFetcher ) = 0; + + //------------------------------------ + // Functions to hold a file open if planning on doing mutiple reads. Use is optional, + // and is taken only as a hint + //------------------------------------ + virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile ) = 0; + virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile ) = 0; + + //------------------------------------ + // Request management + //------------------------------------ + virtual FSAsyncStatus_t AsyncFinish( FSAsyncControl_t hControl, bool wait = true ) = 0; + virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize ) = 0; + virtual FSAsyncStatus_t AsyncAbort( FSAsyncControl_t hControl ) = 0; + virtual FSAsyncStatus_t AsyncStatus( FSAsyncControl_t hControl ) = 0; + // set a new priority for a file already in the queue + virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) = 0; + virtual void AsyncAddRef( FSAsyncControl_t hControl ) = 0; + virtual void AsyncRelease( FSAsyncControl_t hControl ) = 0; + + //-------------------------------------------------------- + // Remote resource management + //-------------------------------------------------------- + + // starts waiting for resources to be available + // returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on + virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) = 0; + // get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done + // returns false if no progress is available + // any calls after complete is true or on an invalid handle will return false, 0.0f, true + virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */ ) = 0; + // cancels a progress call + virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) = 0; + + // hints that a set of files will be loaded in near future + // HintResourceNeed() is not to be confused with resource precaching. + virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) = 0; + // returns true if a file is on disk + virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0; + + // copies file out of pak/bsp/steam cache onto disk (to be accessible by third-party code) + virtual void GetLocalCopy( const char *pFileName ) = 0; + + //-------------------------------------------------------- + // Debugging operations + //-------------------------------------------------------- + + // Dump to printf/OutputDebugString the list of files that have not been closed + virtual void PrintOpenedFiles( void ) = 0; + virtual void PrintSearchPaths( void ) = 0; + + // output + virtual void SetWarningFunc( void (*pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... ) ) = 0; + virtual void SetWarningLevel( FileWarningLevel_t level ) = 0; + virtual void AddLoggingFunc( void (*pfnLogFunc)( const char *fileName, const char *accessType ) ) = 0; + virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc ) = 0; + + // Returns the file system statistics retreived by the implementation. Returns NULL if not supported. + virtual const FileSystemStatistics *GetFilesystemStatistics() = 0; + + //-------------------------------------------------------- + // Start of new functions after Lost Coast release (7/05) + //-------------------------------------------------------- + + virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL ) = 0; + + // Extended version of read provides more context to allow for more optimal reading + virtual int ReadEx( void* pOutput, int sizeDest, int size, FileHandle_t file ) = 0; + virtual int ReadFileEx( const char *pFileName, const char *pPath, void **ppBuf, bool bNullTerminate = false, bool bOptimalAlloc = false, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; + + virtual FileNameHandle_t FindFileName( char const *pFileName ) = 0; + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking( bool state ) = 0; + virtual bool IsBlockingFileAccessEnabled() const = 0; + + virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo() = 0; +#endif + + virtual void SetupPreloadData() = 0; + virtual void DiscardPreloadData() = 0; + + // Fixme, we could do these via a string embedded into the compiled data, etc... + enum KeyValuesPreloadType_t + { + TYPE_VMT, + TYPE_SOUNDEMITTER, + TYPE_SOUNDSCAPE, + NUM_PRELOAD_TYPES + }; + + virtual void LoadCompiledKeyValues( KeyValuesPreloadType_t type, char const *archiveFile ) = 0; + + // If the "PreloadedData" hasn't been purged, then this'll try and instance the KeyValues using the fast path of compiled keyvalues loaded during startup. + // Otherwise, it'll just fall through to the regular KeyValues loading routines + virtual KeyValues *LoadKeyValues( KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) = 0; + virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) = 0; + virtual bool ExtractRootKeyName( KeyValuesPreloadType_t type, char *outbuf, size_t bufsize, char const *filename, char const *pPathID = 0 ) = 0; + + virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t *pControl = NULL ) = 0; + virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t *pControl = NULL ) = 0; + // Async read functions with memory blame + FSAsyncStatus_t AsyncReadCreditAlloc( const FileAsyncRequest_t &request, const char *pszFile, int line, FSAsyncControl_t *phControl = NULL ) { return AsyncReadMultipleCreditAlloc( &request, 1, pszFile, line, phControl ); } + virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *phControls = NULL ) = 0; + + virtual bool GetFileTypeForFullPath( char const *pFullPath, OUT_Z_BYTECAP(bufSizeInBytes) wchar_t *buf, size_t bufSizeInBytes ) = 0; + + //-------------------------------------------------------- + //-------------------------------------------------------- + virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; + + //-------------------------------------------------------- + // Optimal IO operations + //-------------------------------------------------------- + virtual bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign ) = 0; + inline unsigned GetOptimalReadSize( FileHandle_t hFile, unsigned nLogicalSize ); + virtual void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize = 0, unsigned nOffset = 0 ) = 0; + virtual void FreeOptimalReadBuffer( void * ) = 0; + + //-------------------------------------------------------- + // + //-------------------------------------------------------- + virtual void BeginMapAccess() = 0; + virtual void EndMapAccess() = 0; + + // Returns true on success, otherwise false if it can't be resolved + // Prefer using the FullPathToRelativePathEx_safe template wrapper to calling this directly + virtual bool FullPathToRelativePathEx( const char *pFullpath, const char *pPathId, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; + template bool FullPathToRelativePathEx_safe( const char *pFullpath, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) + { + return FullPathToRelativePathEx( pFullpath, pDest, (int)maxLenInChars ); + } + + virtual int GetPathIndex( const FileNameHandle_t &handle ) = 0; + virtual long GetPathTime( const char *pPath, const char *pPathID ) = 0; + + virtual DVDMode_t GetDVDMode() = 0; + + //-------------------------------------------------------- + // Whitelisting for pure servers. + //-------------------------------------------------------- + + // This should be called ONCE at startup. Multiplayer games (gameinfo.txt does not contain singleplayer_only) + // want to enable this so sv_pure works. + virtual void EnableWhitelistFileTracking( bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes ) = 0; + + // This is called when the client connects to a server using a pure_server_whitelist.txt file. + virtual void RegisterFileWhitelist( IPureServerWhitelist *pWhiteList, IFileList **pFilesToReload ) = 0; + + // Called when the client logs onto a server. Any files that came off disk should be marked as + // unverified because this server may have a different set of files it wants to guarantee. + virtual void MarkAllCRCsUnverified() = 0; + + // As the server loads whitelists when it transitions maps, it calls this to calculate CRCs for any files marked + // with check_crc. Then it calls CheckCachedFileCRC later when it gets client requests to verify CRCs. + virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter ) = 0; + virtual EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash ) = 0; + + // Fills in the list of files that have been loaded off disk and have not been verified. + // Returns the number of files filled in (between 0 and nMaxFiles). + // + // This also removes any files it's returning from the unverified CRC list, so they won't be + // returned from here again. + // The client sends batches of these to the server to verify. + virtual int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles ) = 0; + + // Control debug message output. + // Pass a combination of WHITELIST_SPEW_ flags. + virtual int GetWhitelistSpewFlags() = 0; + virtual void SetWhitelistSpewFlags( int flags ) = 0; + + // Installs a callback used to display a dirty disk dialog + virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func ) = 0; + + //-------------------------------------------------------- + // Low-level file caching. Cached files are loaded into memory and used + // to satisfy read requests (sync and async) until the cache is destroyed. + // NOTE: this could defeat file whitelisting, if a file were loaded in + // a non-whitelisted environment and then reused. Clients should not cache + // files across moves between pure/non-pure environments. + //-------------------------------------------------------- + virtual FileCacheHandle_t CreateFileCache() = 0; + virtual void AddFilesToFileCache( FileCacheHandle_t cacheId, const char **ppFileNames, int nFileNames, const char *pPathID ) = 0; + virtual bool IsFileCacheFileLoaded( FileCacheHandle_t cacheId, const char* pFileName ) = 0; + virtual bool IsFileCacheLoaded( FileCacheHandle_t cacheId ) = 0; + virtual void DestroyFileCache( FileCacheHandle_t cacheId ) = 0; + + // XXX For now, we assume that all path IDs are "GAME", never cache files + // outside of the game search path, and preferentially return those files + // whenever anyone searches for a match even if an on-disk file in another + // folder would have been found first in a traditional search. extending + // the memory cache to cover non-game files isn't necessary right now, but + // should just be a matter of defining a more complex key type. (henryg) + + // Register a CMemoryFileBacking; must balance with UnregisterMemoryFile. + // Returns false and outputs an ref-bumped pointer to the existing entry + // if the same file has already been registered by someone else; this must + // be Unregistered to maintain the balance. + virtual bool RegisterMemoryFile( CMemoryFileBacking *pFile, CMemoryFileBacking **ppExistingFileWithRef ) = 0; + + // Unregister a CMemoryFileBacking; must balance with RegisterMemoryFile. + virtual void UnregisterMemoryFile( CMemoryFileBacking *pFile ) = 0; + + virtual void CacheAllVPKFileHashes( bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes ) = 0; + virtual bool CheckVPKFileHash( int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t &md5Value ) = 0; + + // Called when we unload a file, to remove that file's info for pure server purposes. + virtual void NotifyFileUnloaded( const char *pszFilename, const char *pPathId ) = 0; + + /* + // Returns true on successfully retrieve case-sensitive full path, otherwise false + // Prefer using the GetCaseCorrectFullPath template wrapper to calling this directly + virtual bool GetCaseCorrectFullPath_Ptr( const char *pFullPath, OUT_Z_CAP( maxLenInChars ) char *pDest, int maxLenInChars ) = 0; + template bool GetCaseCorrectFullPath( const char *pFullPath, OUT_Z_ARRAY char( &pDest )[maxLenInChars] ) + { + return GetCaseCorrectFullPath_Ptr( pFullPath, pDest, (int)maxLenInChars ); + } + */ +}; + +//----------------------------------------------------------------------------- +// Memory file backing, which you can use to fake out the filesystem, caching data +// in memory and have it associated with a file +//----------------------------------------------------------------------------- +class CMemoryFileBacking : public CRefCounted +{ +public: + CMemoryFileBacking( IFileSystem* pFS ) : m_pFS( pFS ), m_nRegistered( 0 ), m_pFileName( NULL ), m_pData( NULL ), m_nLength( 0 ) { } + ~CMemoryFileBacking() { free( (char*) m_pFileName ); if ( m_pData ) m_pFS->FreeOptimalReadBuffer( (char*) m_pData ); } + + IFileSystem* m_pFS; + int m_nRegistered; + const char* m_pFileName; + const char* m_pData; + int m_nLength; + +private: + CMemoryFileBacking( const CMemoryFileBacking& ); // not defined + CMemoryFileBacking& operator=( const CMemoryFileBacking& ); // not defined +}; + +//----------------------------------------------------------------------------- + +#if defined( _X360 ) && !defined( _RETAIL ) +extern char g_szXboxProfileLastFileOpened[MAX_PATH]; +#define SetLastProfileFileRead( s ) Q_strncpy( g_szXboxProfileLastFileOpened, sizeof( g_szXboxProfileLastFileOpened), pFileName ) +#define GetLastProfileFileRead() (&g_szXboxProfileLastFileOpened[0]) +#else +#define SetLastProfileFileRead( s ) ((void)0) +#define GetLastProfileFileRead() NULL +#endif + +#if defined( _X360 ) && defined( _BASETSD_H_ ) +class CXboxDiskCacheSetter +{ +public: + CXboxDiskCacheSetter( SIZE_T newSize ) + { + m_oldSize = XGetFileCacheSize(); + XSetFileCacheSize( newSize ); + } + + ~CXboxDiskCacheSetter() + { + XSetFileCacheSize( m_oldSize ); + } +private: + SIZE_T m_oldSize; +}; +#define DISK_INTENSIVE() CXboxDiskCacheSetter cacheSetter( 1024*1024 ) +#else +#define DISK_INTENSIVE() ((void)0) +#endif + +//----------------------------------------------------------------------------- + +inline unsigned IFileSystem::GetOptimalReadSize( FileHandle_t hFile, unsigned nLogicalSize ) +{ + unsigned align; + if ( GetOptimalIOConstraints( hFile, &align, NULL, NULL ) ) + return AlignValue( nLogicalSize, align ); + else + return nLogicalSize; +} + +//----------------------------------------------------------------------------- + +// We include this here so it'll catch compile errors in VMPI early. +#include "filesystem_passthru.h" + +//----------------------------------------------------------------------------- +// Async memory tracking +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define AsyncRead( a, b ) AsyncReadCreditAlloc( a, __FILE__, __LINE__, b ) +#define AsyncReadMutiple( a, b, c ) AsyncReadMultipleCreditAlloc( a, b, __FILE__, __LINE__, c ) +#endif + +extern IFileSystem *g_pFullFileSystem; + +#endif // FILESYSTEM_H diff --git a/public/filesystem/IQueuedLoader.h b/public/filesystem/IQueuedLoader.h new file mode 100644 index 0000000..2d5580a --- /dev/null +++ b/public/filesystem/IQueuedLoader.h @@ -0,0 +1,156 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef QUEUEDLOADER_H +#define QUEUEDLOADER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "appframework/IAppSystem.h" + +class CFunctor; + +enum LoaderError_t +{ + LOADERERROR_NONE = 0, + LOADERERROR_FILEOPEN = -1, + LOADERERROR_READING = -2, +}; + +enum LoaderPriority_t +{ + LOADERPRIORITY_ANYTIME = 0, // low priority, job can finish during gameplay + LOADERPRIORITY_BEFOREPLAY = 1, // job must complete before load ends + LOADERPRIORITY_DURINGPRELOAD = 2, // job must be complete during preload phase +}; + +typedef void ( *QueuedLoaderCallback_t )( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError ); + +typedef void ( *DynamicResourceCallback_t )( const char *pFilename, void *pContext, void *pContext2 ); + +struct LoaderJob_t +{ + LoaderJob_t() + { + memset( this, 0, sizeof( *this ) ); + } + + const char *m_pFilename; // path to resource + const char *m_pPathID; // optional, can be NULL + QueuedLoaderCallback_t m_pCallback; // called at i/o delivery + void *m_pContext; // caller provided data + void *m_pContext2; // caller provided data + void *m_pTargetData; // optional, caller provided target buffer + int m_nBytesToRead; // optional read clamp, otherwise 0 + unsigned int m_nStartOffset; // optional start offset, otherwise 0 + LoaderPriority_t m_Priority; // data must arrive by specified interval + bool m_bPersistTargetData; // caller wants ownership of i/o buffer +}; + +enum ResourcePreload_t +{ + RESOURCEPRELOAD_UNKNOWN, + RESOURCEPRELOAD_SOUND, + RESOURCEPRELOAD_MATERIAL, + RESOURCEPRELOAD_MODEL, + RESOURCEPRELOAD_CUBEMAP, + RESOURCEPRELOAD_STATICPROPLIGHTING, + RESOURCEPRELOAD_ANONYMOUS, + RESOURCEPRELOAD_COUNT +}; + +abstract_class IResourcePreload +{ +public: + // Called during preload phase for ALL the resources expected by the level. + // Caller should not do i/o but generate AddJob() requests. Resources that already exist + // and are not referenced by this function would be candidates for purge. + virtual bool CreateResource( const char *pName ) = 0; + + // Sent as an event hint during preload, that creation has completed, AddJob() i/o is about to commence. + // Caller should purge any unreferenced resources before the AddJobs are performed. + // "Must Complete" data will be guaranteed finished, at preload conclusion, before the normal load phase commences. + virtual void PurgeUnreferencedResources() = 0; + + // Sent as an event hint that gameplay rendering is imminent. + // Low priority jobs may still be in async flight. + virtual void OnEndMapLoading( bool bAbort ) = 0; + + virtual void PurgeAll() = 0; +}; + +// Default implementation +class CResourcePreload : public IResourcePreload +{ + void PurgeUnreferencedResources() {} + void OnEndMapLoading( bool bAbort ) {} + void PurgeAll() {} +}; + +// UI can install progress notification +abstract_class ILoaderProgress +{ +public: + // implementation must ignore UpdateProgress() if not scoped by Begin/End + virtual void BeginProgress() = 0; + virtual void EndProgress() = 0; + virtual void UpdateProgress( float progress ) = 0; +}; + +// spew detail +#define LOADER_DETAIL_NONE 0 +#define LOADER_DETAIL_TIMING (1<<0) +#define LOADER_DETAIL_COMPLETIONS (1<<1) +#define LOADER_DETAIL_LATECOMPLETIONS (1<<2) +#define LOADER_DETAIL_PURGES (1<<3) + +#define QUEUEDLOADER_INTERFACE_VERSION "QueuedLoaderVersion004" +abstract_class IQueuedLoader : public IAppSystem +{ +public: + virtual void InstallLoader( ResourcePreload_t type, IResourcePreload *pLoader ) = 0; + virtual void InstallProgress( ILoaderProgress *pProgress ) = 0; + + // Set bOptimizeReload if you want appropriate data (such as static prop lighting) + // to persist - rather than being purged and reloaded - when going from map A to map A. + virtual bool BeginMapLoading( const char *pMapName, bool bLoadForHDR, bool bOptimizeMapReload ) = 0; + virtual void EndMapLoading( bool bAbort ) = 0; + virtual bool AddJob( const LoaderJob_t *pLoaderJob ) = 0; + + // injects a resource into the map's reslist, rejected if not understood + virtual void AddMapResource( const char *pFilename ) = 0; + + // dynamically load a map resource + virtual void DynamicLoadMapResource( const char *pFilename, DynamicResourceCallback_t pCallback, void *pContext, void *pContext2 ) = 0; + virtual void QueueDynamicLoadFunctor( CFunctor* pFunctor ) = 0; + virtual bool CompleteDynamicLoad() = 0; + + // callback is asynchronous + virtual bool ClaimAnonymousJob( const char *pFilename, QueuedLoaderCallback_t pCallback, void *pContext, void *pContext2 = NULL ) = 0; + // provides data if loaded, caller owns data + virtual bool ClaimAnonymousJob( const char *pFilename, void **pData, int *pDataSize, LoaderError_t *pError = NULL ) = 0; + + virtual bool IsMapLoading() const = 0; + virtual bool IsSameMapLoading() const = 0; + virtual bool IsFinished() const = 0; + + // callers can expect that jobs are not immediately started when batching + virtual bool IsBatching() const = 0; + + virtual bool IsDynamic() const = 0; + + // callers can conditionalize operational spew + virtual int GetSpewDetail() const = 0; + + virtual void PurgeAll() = 0; +}; + +extern IQueuedLoader *g_pQueuedLoader; + +#endif // QUEUEDLOADER_H diff --git a/public/filesystem_helpers.cpp b/public/filesystem_helpers.cpp new file mode 100644 index 0000000..5e4ac99 --- /dev/null +++ b/public/filesystem_helpers.cpp @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "filesystem.h" +#include "filesystem_helpers.h" +#include "characterset.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// wordbreak parsing set +static characterset_t g_BreakSet, g_BreakSetIncludingColons; + +static void InitializeCharacterSets() +{ + static bool s_CharacterSetInitialized = false; + if (!s_CharacterSetInitialized) + { + CharacterSetBuild( &g_BreakSet, "{}()'" ); + CharacterSetBuild( &g_BreakSetIncludingColons, "{}()':" ); + s_CharacterSetInitialized = true; + } +} + + +const char* ParseFileInternal( const char* pFileBytes, char* pTokenOut, bool* pWasQuoted, characterset_t *pCharSet, size_t nMaxTokenLen ) +{ + pTokenOut[0] = 0; + + if (pWasQuoted) + *pWasQuoted = false; + + if (!pFileBytes) + return 0; + + InitializeCharacterSets(); + + // YWB: Ignore colons as token separators in COM_Parse + static bool com_ignorecolons = false; + characterset_t& breaks = pCharSet ? *pCharSet : (com_ignorecolons ? g_BreakSet : g_BreakSetIncludingColons); + + int c; + unsigned int len = 0; + +// skip whitespace +skipwhite: + + while ( (c = *pFileBytes) <= ' ') + { + if (c == 0) + return 0; // end of file; + pFileBytes++; + } + +// skip // comments + if (c=='/' && pFileBytes[1] == '/') + { + while (*pFileBytes && *pFileBytes != '\n') + pFileBytes++; + goto skipwhite; + } + +// skip c-style comments + if (c=='/' && pFileBytes[1] == '*' ) + { + // Skip "/*" + pFileBytes += 2; + + while ( *pFileBytes ) + { + if ( *pFileBytes == '*' && + pFileBytes[1] == '/' ) + { + pFileBytes += 2; + break; + } + + pFileBytes++; + } + + goto skipwhite; + } + +// handle quoted strings specially + if (c == '\"') + { + if (pWasQuoted) + *pWasQuoted = true; + + pFileBytes++; + while (1) + { + c = *pFileBytes++; + if (c=='\"' || !c) + { + pTokenOut[len] = 0; + return pFileBytes; + } + pTokenOut[len] = c; + len += ( len < nMaxTokenLen-1 ) ? 1 : 0; + } + } + +// parse single characters + if ( IN_CHARACTERSET( breaks, c ) ) + { + pTokenOut[len] = c; + len += ( len < nMaxTokenLen-1 ) ? 1 : 0; + pTokenOut[len] = 0; + return pFileBytes+1; + } + +// parse a regular word + do + { + pTokenOut[len] = c; + pFileBytes++; + len += ( len < nMaxTokenLen-1 ) ? 1 : 0; + c = *pFileBytes; + if ( IN_CHARACTERSET( breaks, c ) ) + break; + } while (c>32); + + pTokenOut[len] = 0; + return pFileBytes; +} diff --git a/public/filesystem_helpers.h b/public/filesystem_helpers.h new file mode 100644 index 0000000..070e779 --- /dev/null +++ b/public/filesystem_helpers.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FILESYSTEM_HELPERS_H +#define FILESYSTEM_HELPERS_H + +#ifdef _WIN32 +#pragma once +#endif + +struct characterset_t; + +// Don't call this directly. You should (as long as your destination is an array) be +// able to call ParseFile, which is safer as it infers your array size for you. +const char* ParseFileInternal( const char* pFileBytes, OUT_Z_CAP(nMaxTokenLen) char* pTokenOut, bool* pWasQuoted, characterset_t *pCharSet, size_t nMaxTokenLen ); + +// Call until it returns NULL. Each time you call it, it will parse out a token. + +template +const char* ParseFile( const char* pFileBytes, OUT_Z_ARRAY char (&pTokenOut)[count], bool* pWasQuoted, characterset_t *pCharSet = NULL, unsigned int nMaxTokenLen = (unsigned int)-1 ) +{ + (void*)nMaxTokenLen; // Avoid unreferenced variable warnings. + return ParseFileInternal( pFileBytes, pTokenOut, pWasQuoted, pCharSet, count ); +} + +template +char* ParseFile( char* pFileBytes, OUT_Z_ARRAY char (&pTokenOut)[count], bool* pWasQuoted ) // (same exact thing as the const version) +{ + return const_cast( ParseFileInternal( pFileBytes, pTokenOut, pWasQuoted, NULL, count ) ); +} + +#endif // FILESYSTEM_HELPERS_H diff --git a/public/filesystem_init.cpp b/public/filesystem_init.cpp new file mode 100644 index 0000000..c1bcf3e --- /dev/null +++ b/public/filesystem_init.cpp @@ -0,0 +1,1241 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#undef PROTECTED_THINGS_ENABLE +#undef PROTECT_FILEIO_FUNCTIONS +#ifndef POSIX +#undef fopen +#endif + +#if defined( _WIN32 ) && !defined( _X360 ) +#include +#include +#include +#include +#elif defined( POSIX ) +#include +#define _chdir chdir +#define _access access +#endif +#include +#include +#include "tier1/strtools.h" +#include "tier1/utlbuffer.h" +#include "filesystem_init.h" +#include "tier0/icommandline.h" +#include "KeyValues.h" +#include "appframework/IAppSystemGroup.h" +#include "tier1/smartptr.h" +#if defined( _X360 ) +#include "xbox\xbox_win32stubs.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include + +#if !defined( _X360 ) +#define GAMEINFO_FILENAME "gameinfo.txt" +#else +// The .xtx file is a TCR requirement, as .txt files cannot live on the DVD. +// The .xtx file only exists outside the zips (same as .txt and is made during the image build) and is read to setup the search paths. +// So all other code should be able to safely expect gameinfo.txt after the zip is mounted as the .txt file exists inside the zips. +// The .xtx concept is private and should only have to occurr here. As a safety measure, if the .xtx file is not found +// a retry is made with the original .txt name +#define GAMEINFO_FILENAME "gameinfo.xtx" +#endif +#define GAMEINFO_FILENAME_ALTERNATE "gameinfo.txt" + +static char g_FileSystemError[256]; +static bool s_bUseVProjectBinDir = false; +static FSErrorMode_t g_FileSystemErrorMode = FS_ERRORMODE_VCONFIG; + +// Call this to use a bin directory relative to VPROJECT +void FileSystem_UseVProjectBinDir( bool bEnable ) +{ + s_bUseVProjectBinDir = bEnable; +} + +// This class lets you modify environment variables, and it restores the original value +// when it goes out of scope. +class CTempEnvVar +{ +public: + CTempEnvVar( const char *pVarName ) + { + m_bRestoreOriginalValue = true; + m_pVarName = pVarName; + + const char *pValue = NULL; + +#ifdef _WIN32 + // Use GetEnvironmentVariable instead of getenv because getenv doesn't pick up changes + // to the process environment after the DLL was loaded. + char szBuf[ 4096 ]; + if ( GetEnvironmentVariable( m_pVarName, szBuf, sizeof( szBuf ) ) != 0) + { + pValue = szBuf; + } +#else + // LINUX BUG: see above + pValue = getenv( pVarName ); +#endif + + if ( pValue ) + { + m_bExisted = true; + m_OriginalValue.SetSize( Q_strlen( pValue ) + 1 ); + memcpy( m_OriginalValue.Base(), pValue, m_OriginalValue.Count() ); + } + else + { + m_bExisted = false; + } + } + + ~CTempEnvVar() + { + if ( m_bRestoreOriginalValue ) + { + // Restore the original value. + if ( m_bExisted ) + { + SetValue( "%s", m_OriginalValue.Base() ); + } + else + { + ClearValue(); + } + } + } + + void SetRestoreOriginalValue( bool bRestore ) + { + m_bRestoreOriginalValue = bRestore; + } + + int GetValue(char *pszBuf, int nBufSize ) + { + if ( !pszBuf || ( nBufSize <= 0 ) ) + return 0; + +#ifdef _WIN32 + // Use GetEnvironmentVariable instead of getenv because getenv doesn't pick up changes + // to the process environment after the DLL was loaded. + return GetEnvironmentVariable( m_pVarName, pszBuf, nBufSize ); +#else + // LINUX BUG: see above + const char *pszOut = getenv( m_pVarName ); + if ( !pszOut ) + { + *pszBuf = '\0'; + return 0; + } + + Q_strncpy( pszBuf, pszOut, nBufSize ); + return Q_strlen( pszBuf ); +#endif + } + + void SetValue( const char *pValue, ... ) + { + char valueString[4096]; + va_list marker; + va_start( marker, pValue ); + Q_vsnprintf( valueString, sizeof( valueString ), pValue, marker ); + va_end( marker ); + +#ifdef WIN32 + char str[4096]; + Q_snprintf( str, sizeof( str ), "%s=%s", m_pVarName, valueString ); + _putenv( str ); +#else + setenv( m_pVarName, valueString, 1 ); +#endif + } + + void ClearValue() + { +#ifdef WIN32 + char str[512]; + Q_snprintf( str, sizeof( str ), "%s=", m_pVarName ); + _putenv( str ); +#else + setenv( m_pVarName, "", 1 ); +#endif + } + +private: + bool m_bRestoreOriginalValue; + const char *m_pVarName; + bool m_bExisted; + CUtlVector m_OriginalValue; +}; + + +class CSteamEnvVars +{ +public: + CSteamEnvVars() : + m_SteamAppId( "SteamAppId" ), + m_SteamUserPassphrase( "SteamUserPassphrase" ), + m_SteamAppUser( "SteamAppUser" ), + m_Path( "path" ) + { + } + + void SetRestoreOriginalValue_ALL( bool bRestore ) + { + m_SteamAppId.SetRestoreOriginalValue( bRestore ); + m_SteamUserPassphrase.SetRestoreOriginalValue( bRestore ); + m_SteamAppUser.SetRestoreOriginalValue( bRestore ); + m_Path.SetRestoreOriginalValue( bRestore ); + } + + CTempEnvVar m_SteamAppId; + CTempEnvVar m_SteamUserPassphrase; + CTempEnvVar m_SteamAppUser; + CTempEnvVar m_Path; +}; + +// ---------------------------------------------------------------------------------------------------- // +// Helpers. +// ---------------------------------------------------------------------------------------------------- // +void Q_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 ); +} + +// ---------------------------------------------------------------------------------------------------- // +// Module interface. +// ---------------------------------------------------------------------------------------------------- // + +CFSSearchPathsInit::CFSSearchPathsInit() +{ + m_pDirectoryName = NULL; + m_pLanguage = NULL; + m_ModPath[0] = 0; + m_bMountHDContent = m_bLowViolence = false; +} + + +CFSSteamSetupInfo::CFSSteamSetupInfo() +{ + m_pDirectoryName = NULL; + m_bOnlyUseDirectoryName = false; + m_bSteam = false; + m_bToolsMode = true; + m_bNoGameInfo = false; +} + + +CFSLoadModuleInfo::CFSLoadModuleInfo() +{ + m_pFileSystemDLLName = NULL; + m_pFileSystem = NULL; + m_pModule = NULL; +} + + +CFSMountContentInfo::CFSMountContentInfo() +{ + m_bToolsMode = true; + m_pDirectoryName = NULL; + m_pFileSystem = NULL; +} + + +const char *FileSystem_GetLastErrorString() +{ + return g_FileSystemError; +} + + +KeyValues* ReadKeyValuesFile( const char *pFilename ) +{ + // Read in the gameinfo.txt file and null-terminate it. + FILE *fp = fopen( pFilename, "rb" ); + if ( !fp ) + return NULL; + CUtlVector buf; + fseek( fp, 0, SEEK_END ); + buf.SetSize( ftell( fp ) + 1 ); + fseek( fp, 0, SEEK_SET ); + fread( buf.Base(), 1, buf.Count()-1, fp ); + fclose( fp ); + buf[buf.Count()-1] = 0; + + KeyValues *kv = new KeyValues( "" ); + if ( !kv->LoadFromBuffer( pFilename, buf.Base() ) ) + { + kv->deleteThis(); + return NULL; + } + + return kv; +} + +static bool Sys_GetExecutableName( char *out, int len ) +{ +#if defined( _WIN32 ) + if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, len ) ) + { + return false; + } +#else + if ( CommandLine()->GetParm(0) ) + { + Q_MakeAbsolutePath( out, len, CommandLine()->GetParm(0) ); + } + else + { + return false; + } +#endif + + return true; +} + +bool FileSystem_GetExecutableDir( char *exedir, int exeDirLen ) +{ + exedir[0] = 0; + + if ( s_bUseVProjectBinDir ) + { + const char *pProject = GetVProjectCmdLineValue(); + if ( !pProject ) + { + // Check their registry. + pProject = getenv( GAMEDIR_TOKEN ); + } + if ( pProject ) + { + Q_snprintf( exedir, exeDirLen, "%s%c..%cbin", pProject, CORRECT_PATH_SEPARATOR, CORRECT_PATH_SEPARATOR ); + return true; + } + return false; + } + + if ( !Sys_GetExecutableName( exedir, exeDirLen ) ) + return false; + Q_StripFilename( exedir ); + + if ( IsX360() ) + { + // The 360 can have its exe and dlls reside on different volumes + // use the optional basedir as the exe dir + if ( CommandLine()->FindParm( "-basedir" ) ) + { + strcpy( exedir, CommandLine()->ParmValue( "-basedir", "" ) ); + } + } + + Q_FixSlashes( exedir ); + + // Return the bin directory as the executable dir if it's not in there + // because that's really where we're running from... + char ext[MAX_PATH]; + Q_StrRight( exedir, 4, ext, sizeof( ext ) ); + if ( ext[0] != CORRECT_PATH_SEPARATOR || Q_stricmp( ext+1, "bin" ) != 0 ) + { + Q_strncat( exedir, CORRECT_PATH_SEPARATOR_S, exeDirLen, COPY_ALL_CHARACTERS ); + Q_strncat( exedir, "bin", exeDirLen, COPY_ALL_CHARACTERS ); + Q_FixSlashes( exedir ); + } + + return true; +} + +static bool FileSystem_GetBaseDir( char *baseDir, int baseDirLen ) +{ + if ( FileSystem_GetExecutableDir( baseDir, baseDirLen ) ) + { + Q_StripFilename( baseDir ); + return true; + } + + return false; +} + +void LaunchVConfig() +{ +#if defined( _WIN32 ) && !defined( _X360 ) + char vconfigExe[MAX_PATH]; + FileSystem_GetExecutableDir( vconfigExe, sizeof( vconfigExe ) ); + Q_AppendSlash( vconfigExe, sizeof( vconfigExe ) ); + Q_strncat( vconfigExe, "vconfig.exe", sizeof( vconfigExe ), COPY_ALL_CHARACTERS ); + + char *argv[] = + { + vconfigExe, + "-allowdebug", + NULL + }; + + _spawnv( _P_NOWAIT, vconfigExe, argv ); +#elif defined( _X360 ) + Msg( "Launching vconfig.exe not supported\n" ); +#endif +} + +const char* GetVProjectCmdLineValue() +{ + return CommandLine()->ParmValue( "-vproject", CommandLine()->ParmValue( "-game" ) ); +} + +FSReturnCode_t SetupFileSystemError( bool bRunVConfig, FSReturnCode_t retVal, const char *pMsg, ... ) +{ + va_list marker; + va_start( marker, pMsg ); + Q_vsnprintf( g_FileSystemError, sizeof( g_FileSystemError ), pMsg, marker ); + va_end( marker ); + + Warning( "%s\n", g_FileSystemError ); + + // Run vconfig? + // Don't do it if they specifically asked for it not to, or if they manually specified a vconfig with -game or -vproject. + if ( bRunVConfig && g_FileSystemErrorMode == FS_ERRORMODE_VCONFIG && !CommandLine()->FindParm( CMDLINEOPTION_NOVCONFIG ) && !GetVProjectCmdLineValue() ) + { + LaunchVConfig(); + } + + if ( g_FileSystemErrorMode == FS_ERRORMODE_AUTO || g_FileSystemErrorMode == FS_ERRORMODE_VCONFIG ) + { + Error( "%s\n", g_FileSystemError ); + } + + return retVal; +} + +FSReturnCode_t LoadGameInfoFile( + const char *pDirectoryName, + KeyValues *&pMainFile, + KeyValues *&pFileSystemInfo, + KeyValues *&pSearchPaths ) +{ + // If GameInfo.txt exists under pBaseDir, then this is their game directory. + // All the filesystem mappings will be in this file. + char gameinfoFilename[MAX_PATH]; + Q_strncpy( gameinfoFilename, pDirectoryName, sizeof( gameinfoFilename ) ); + Q_AppendSlash( gameinfoFilename, sizeof( gameinfoFilename ) ); + Q_strncat( gameinfoFilename, GAMEINFO_FILENAME, sizeof( gameinfoFilename ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( gameinfoFilename ); + pMainFile = ReadKeyValuesFile( gameinfoFilename ); + if ( IsX360() && !pMainFile ) + { + // try again + Q_strncpy( gameinfoFilename, pDirectoryName, sizeof( gameinfoFilename ) ); + Q_AppendSlash( gameinfoFilename, sizeof( gameinfoFilename ) ); + Q_strncat( gameinfoFilename, GAMEINFO_FILENAME_ALTERNATE, sizeof( gameinfoFilename ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( gameinfoFilename ); + pMainFile = ReadKeyValuesFile( gameinfoFilename ); + } + if ( !pMainFile ) + { + return SetupFileSystemError( true, FS_MISSING_GAMEINFO_FILE, "%s is missing.", gameinfoFilename ); + } + + pFileSystemInfo = pMainFile->FindKey( "FileSystem" ); + if ( !pFileSystemInfo ) + { + pMainFile->deleteThis(); + return SetupFileSystemError( true, FS_INVALID_GAMEINFO_FILE, "%s is not a valid format.", gameinfoFilename ); + } + + // Now read in all the search paths. + pSearchPaths = pFileSystemInfo->FindKey( "SearchPaths" ); + if ( !pSearchPaths ) + { + pMainFile->deleteThis(); + return SetupFileSystemError( true, FS_INVALID_GAMEINFO_FILE, "%s is not a valid format.", gameinfoFilename ); + } + return FS_OK; +} + + +static void FileSystem_AddLoadedSearchPath( + CFSSearchPathsInit &initInfo, + const char *pPathID, + const char *fullLocationPath, + bool bLowViolence ) +{ + + // Check for mounting LV game content in LV builds only + if ( V_stricmp( pPathID, "game_lv" ) == 0 ) + { + + // Not in LV build, don't mount + if ( !initInfo.m_bLowViolence ) + return; + + // Mount, as a game path + pPathID = "game"; + } + + // Check for mounting HD game content if enabled + if ( V_stricmp( pPathID, "game_hd" ) == 0 ) + { + + // Not in LV build, don't mount + if ( !initInfo.m_bMountHDContent ) + return; + + // Mount, as a game path + pPathID = "game"; + } + + + // Special processing for ordinary game folders + if ( V_stristr( fullLocationPath, ".vpk" ) == NULL && Q_stricmp( pPathID, "game" ) == 0 ) + { + if ( CommandLine()->FindParm( "-tempcontent" ) != 0 ) + { + char szPath[MAX_PATH]; + Q_snprintf( szPath, sizeof(szPath), "%s_tempcontent", fullLocationPath ); + initInfo.m_pFileSystem->AddSearchPath( szPath, pPathID, PATH_ADD_TO_TAIL ); + } + } + + + if ( initInfo.m_pLanguage && + Q_stricmp( initInfo.m_pLanguage, "english" ) && + V_strstr( fullLocationPath, "_english" ) != NULL ) + { + char szPath[MAX_PATH]; + char szLangString[MAX_PATH]; + + // Need to add a language version of this path first + + Q_snprintf( szLangString, sizeof(szLangString), "_%s", initInfo.m_pLanguage); + V_StrSubst( fullLocationPath, "_english", szLangString, szPath, sizeof( szPath ), true ); + initInfo.m_pFileSystem->AddSearchPath( szPath, pPathID, PATH_ADD_TO_TAIL ); + } + + initInfo.m_pFileSystem->AddSearchPath( fullLocationPath, pPathID, PATH_ADD_TO_TAIL ); +} + +static int SortStricmp( char * const * sz1, char * const * sz2 ) +{ + return V_stricmp( *sz1, *sz2 ); +} + +FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo ) +{ + if ( !initInfo.m_pFileSystem || !initInfo.m_pDirectoryName ) + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_LoadSearchPaths: Invalid parameters specified." ); + + KeyValues *pMainFile, *pFileSystemInfo, *pSearchPaths; + FSReturnCode_t retVal = LoadGameInfoFile( initInfo.m_pDirectoryName, pMainFile, pFileSystemInfo, pSearchPaths ); + if ( retVal != FS_OK ) + return retVal; + + // All paths except those marked with |gameinfo_path| are relative to the base dir. + char baseDir[MAX_PATH]; + if ( !FileSystem_GetBaseDir( baseDir, sizeof( baseDir ) ) ) + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); + + // The MOD directory is always the one that contains gameinfo.txt + Q_strncpy( initInfo.m_ModPath, initInfo.m_pDirectoryName, sizeof( initInfo.m_ModPath ) ); + + #define GAMEINFOPATH_TOKEN "|gameinfo_path|" + #define BASESOURCEPATHS_TOKEN "|all_source_engine_paths|" + + const char *pszExtraSearchPath = CommandLine()->ParmValue( "-insert_search_path" ); + if ( pszExtraSearchPath ) + { + CUtlStringList vecPaths; + V_SplitString( pszExtraSearchPath, ",", vecPaths ); + FOR_EACH_VEC( vecPaths, idxExtraPath ) + { + char szAbsSearchPath[MAX_PATH]; + Q_StripPrecedingAndTrailingWhitespace( vecPaths[ idxExtraPath ] ); + V_MakeAbsolutePath( szAbsSearchPath, sizeof( szAbsSearchPath ), vecPaths[ idxExtraPath ], baseDir ); + V_FixSlashes( szAbsSearchPath ); + if ( !V_RemoveDotSlashes( szAbsSearchPath ) ) + Error( "Bad -insert_search_path - Can't resolve pathname for '%s'", szAbsSearchPath ); + V_StripTrailingSlash( szAbsSearchPath ); + FileSystem_AddLoadedSearchPath( initInfo, "GAME", szAbsSearchPath, false ); + FileSystem_AddLoadedSearchPath( initInfo, "MOD", szAbsSearchPath, false ); + } + } + + bool bLowViolence = initInfo.m_bLowViolence; + for ( KeyValues *pCur=pSearchPaths->GetFirstValue(); pCur; pCur=pCur->GetNextValue() ) + { + const char *pLocation = pCur->GetString(); + const char *pszBaseDir = baseDir; + + if ( Q_stristr( pLocation, GAMEINFOPATH_TOKEN ) == pLocation ) + { + pLocation += strlen( GAMEINFOPATH_TOKEN ); + pszBaseDir = initInfo.m_pDirectoryName; + } + else if ( Q_stristr( pLocation, BASESOURCEPATHS_TOKEN ) == pLocation ) + { + // This is a special identifier that tells it to add the specified path for all source engine versions equal to or prior to this version. + // So in Orange Box, if they specified: + // |all_source_engine_paths|hl2 + // it would add the ep2\hl2 folder and the base (ep1-era) hl2 folder. + // + // We need a special identifier in the gameinfo.txt here because the base hl2 folder exists in different places. + // In the case of a game or a Steam-launched dedicated server, all the necessary prior engine content is mapped in with the Steam depots, + // so we can just use the path as-is. + pLocation += strlen( BASESOURCEPATHS_TOKEN ); + } + + CUtlStringList vecFullLocationPaths; + char szAbsSearchPath[MAX_PATH]; + V_MakeAbsolutePath( szAbsSearchPath, sizeof( szAbsSearchPath ), pLocation, pszBaseDir ); + + // Now resolve any ./'s. + V_FixSlashes( szAbsSearchPath ); + if ( !V_RemoveDotSlashes( szAbsSearchPath ) ) + Error( "FileSystem_AddLoadedSearchPath - Can't resolve pathname for '%s'", szAbsSearchPath ); + V_StripTrailingSlash( szAbsSearchPath ); + + // Don't bother doing any wildcard expansion unless it has wildcards. This avoids the weird + // thing with xxx_dir.vpk files being referred to simply as xxx.vpk. + if ( V_stristr( pLocation, "?") == NULL && V_stristr( pLocation, "*") == NULL ) + { + vecFullLocationPaths.CopyAndAddToTail( szAbsSearchPath ); + } + else + { + FileFindHandle_t findHandle = NULL; + const char *pszFoundShortName = initInfo.m_pFileSystem->FindFirst( szAbsSearchPath, &findHandle ); + if ( pszFoundShortName ) + { + do + { + + // We only know how to mount VPK's and directories + if ( pszFoundShortName[0] != '.' && ( initInfo.m_pFileSystem->FindIsDirectory( findHandle ) || V_stristr( pszFoundShortName, ".vpk" ) ) ) + { + char szAbsName[MAX_PATH]; + V_ExtractFilePath( szAbsSearchPath, szAbsName, sizeof( szAbsName ) ); + V_AppendSlash( szAbsName, sizeof(szAbsName) ); + V_strcat_safe( szAbsName, pszFoundShortName ); + + vecFullLocationPaths.CopyAndAddToTail( szAbsName ); + + // Check for a common mistake + if ( + !V_stricmp( pszFoundShortName, "materials" ) + || !V_stricmp( pszFoundShortName, "maps" ) + || !V_stricmp( pszFoundShortName, "resource" ) + || !V_stricmp( pszFoundShortName, "scripts" ) + || !V_stricmp( pszFoundShortName, "sound" ) + || !V_stricmp( pszFoundShortName, "models" ) ) + { + + char szReadme[MAX_PATH]; + V_ExtractFilePath( szAbsSearchPath, szReadme, sizeof( szReadme ) ); + V_AppendSlash( szReadme, sizeof(szReadme) ); + V_strcat_safe( szReadme, "readme.txt" ); + + Error( + "Tried to add %s as a search path.\n" + "\nThis is probably not what you intended.\n" + "\nCheck %s for more info\n", + szAbsName, szReadme ); + } + + } + pszFoundShortName = initInfo.m_pFileSystem->FindNext( findHandle ); + } while ( pszFoundShortName ); + initInfo.m_pFileSystem->FindClose( findHandle ); + } + + // Sort alphabetically. Also note that this will put + // all the xxx_000.vpk packs just before the corresponding + // xxx_dir.vpk + vecFullLocationPaths.Sort( SortStricmp ); + + // Now for any _dir.vpk files, remove the _nnn.vpk ones. + int idx = vecFullLocationPaths.Count()-1; + while ( idx > 0 ) + { + char szTemp[ MAX_PATH ]; + V_strcpy_safe( szTemp, vecFullLocationPaths[ idx ] ); + --idx; + + char *szDirVpk = V_stristr( szTemp, "_dir.vpk" ); + if ( szDirVpk != NULL ) + { + *szDirVpk = '\0'; + while ( idx >= 0 ) + { + char *pszPath = vecFullLocationPaths[ idx ]; + if ( V_stristr( pszPath, szTemp ) != pszPath ) + break; + delete pszPath; + vecFullLocationPaths.Remove( idx ); + --idx; + } + } + } + } + + // Parse Path ID list + CUtlStringList vecPathIDs; + V_SplitString( pCur->GetName(), "+", vecPathIDs ); + FOR_EACH_VEC( vecPathIDs, idxPathID ) + { + Q_StripPrecedingAndTrailingWhitespace( vecPathIDs[ idxPathID ] ); + } + + // Mount them. + FOR_EACH_VEC( vecFullLocationPaths, idxLocation ) + { + FOR_EACH_VEC( vecPathIDs, idxPathID ) + { + FileSystem_AddLoadedSearchPath( initInfo, vecPathIDs[ idxPathID ], vecFullLocationPaths[ idxLocation ], bLowViolence ); + } + } + } + + pMainFile->deleteThis(); + + // Also, mark specific path IDs as "by request only". That way, we won't waste time searching in them + // when people forget to specify a search path. + initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "executable_path", true ); + initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "gamebin", true ); + initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "download", true ); + initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "mod", true ); + initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "game_write", true ); + initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "mod_write", true ); + +#ifdef _DEBUG + // initInfo.m_pFileSystem->PrintSearchPaths(); +#endif + + return FS_OK; +} + +bool DoesFileExistIn( const char *pDirectoryName, const char *pFilename ) +{ + char filename[MAX_PATH]; + + Q_strncpy( filename, pDirectoryName, sizeof( filename ) ); + Q_AppendSlash( filename, sizeof( filename ) ); + Q_strncat( filename, pFilename, sizeof( filename ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( filename ); + bool bExist = ( _access( filename, 0 ) == 0 ); + + return ( bExist ); +} + +namespace +{ + SuggestGameInfoDirFn_t & GetSuggestGameInfoDirFn( void ) + { + static SuggestGameInfoDirFn_t s_pfnSuggestGameInfoDir = NULL; + return s_pfnSuggestGameInfoDir; + } +}; // `anonymous` namespace + +SuggestGameInfoDirFn_t SetSuggestGameInfoDirFn( SuggestGameInfoDirFn_t pfnNewFn ) +{ + SuggestGameInfoDirFn_t &rfn = GetSuggestGameInfoDirFn(); + SuggestGameInfoDirFn_t pfnOldFn = rfn; + rfn = pfnNewFn; + return pfnOldFn; +} + +static FSReturnCode_t TryLocateGameInfoFile( char *pOutDir, int outDirLen, bool bBubbleDir ) +{ + // Retain a copy of suggested path for further attempts + CArrayAutoPtr < char > spchCopyNameBuffer( new char [ outDirLen ] ); + Q_strncpy( spchCopyNameBuffer.Get(), pOutDir, outDirLen ); + spchCopyNameBuffer[ outDirLen - 1 ] = 0; + + // Make appropriate slashes ('/' - Linux style) + for ( char *pchFix = spchCopyNameBuffer.Get(), + *pchEnd = pchFix + outDirLen; + pchFix < pchEnd; ++ pchFix ) + { + if ( '\\' == *pchFix ) + { + *pchFix = '/'; + } + } + + // Have a look in supplied path + do + { + if ( DoesFileExistIn( pOutDir, GAMEINFO_FILENAME ) ) + { + return FS_OK; + } + if ( IsX360() && DoesFileExistIn( pOutDir, GAMEINFO_FILENAME_ALTERNATE ) ) + { + return FS_OK; + } + } + while ( bBubbleDir && Q_StripLastDir( pOutDir, outDirLen ) ); + + // Make an attempt to resolve from "content -> game" directory + Q_strncpy( pOutDir, spchCopyNameBuffer.Get(), outDirLen ); + pOutDir[ outDirLen - 1 ] = 0; + if ( char *pchContentFix = Q_stristr( pOutDir, "/content/" ) ) + { + sprintf( pchContentFix, "/game/" ); + memmove( pchContentFix + 6, pchContentFix + 9, pOutDir + outDirLen - (pchContentFix + 9) ); + + // Try in the mapped "game" directory + do + { + if ( DoesFileExistIn( pOutDir, GAMEINFO_FILENAME ) ) + { + return FS_OK; + } + if ( IsX360() && DoesFileExistIn( pOutDir, GAMEINFO_FILENAME_ALTERNATE ) ) + { + return FS_OK; + } + } + while ( bBubbleDir && Q_StripLastDir( pOutDir, outDirLen ) ); + } + + // Could not find it here + return FS_MISSING_GAMEINFO_FILE; +} + +FSReturnCode_t LocateGameInfoFile( const CFSSteamSetupInfo &fsInfo, char *pOutDir, int outDirLen ) +{ + // Engine and Hammer don't want to search around for it. + if ( fsInfo.m_bOnlyUseDirectoryName ) + { + if ( !fsInfo.m_pDirectoryName ) + return SetupFileSystemError( false, FS_MISSING_GAMEINFO_FILE, "bOnlyUseDirectoryName=1 and pDirectoryName=NULL." ); + + bool bExists = DoesFileExistIn( fsInfo.m_pDirectoryName, GAMEINFO_FILENAME ); + if ( IsX360() && !bExists ) + { + bExists = DoesFileExistIn( fsInfo.m_pDirectoryName, GAMEINFO_FILENAME_ALTERNATE ); + } + if ( !bExists ) + { + if ( IsX360() && CommandLine()->FindParm( "-basedir" ) ) + { + char basePath[MAX_PATH]; + strcpy( basePath, CommandLine()->ParmValue( "-basedir", "" ) ); + Q_AppendSlash( basePath, sizeof( basePath ) ); + Q_strncat( basePath, fsInfo.m_pDirectoryName, sizeof( basePath ), COPY_ALL_CHARACTERS ); + if ( DoesFileExistIn( basePath, GAMEINFO_FILENAME ) ) + { + Q_strncpy( pOutDir, basePath, outDirLen ); + return FS_OK; + } + if ( IsX360() && DoesFileExistIn( basePath, GAMEINFO_FILENAME_ALTERNATE ) ) + { + Q_strncpy( pOutDir, basePath, outDirLen ); + return FS_OK; + } + } + + return SetupFileSystemError( true, FS_MISSING_GAMEINFO_FILE, "Setup file '%s' doesn't exist in subdirectory '%s'.\nCheck your -game parameter or VCONFIG setting.", GAMEINFO_FILENAME, fsInfo.m_pDirectoryName ); + } + + Q_strncpy( pOutDir, fsInfo.m_pDirectoryName, outDirLen ); + return FS_OK; + } + + // First, check for overrides on the command line or environment variables. + const char *pProject = GetVProjectCmdLineValue(); + + if ( pProject ) + { + if ( DoesFileExistIn( pProject, GAMEINFO_FILENAME ) ) + { + Q_MakeAbsolutePath( pOutDir, outDirLen, pProject ); + return FS_OK; + } + if ( IsX360() && DoesFileExistIn( pProject, GAMEINFO_FILENAME_ALTERNATE ) ) + { + Q_MakeAbsolutePath( pOutDir, outDirLen, pProject ); + return FS_OK; + } + + if ( IsX360() && CommandLine()->FindParm( "-basedir" ) ) + { + char basePath[MAX_PATH]; + strcpy( basePath, CommandLine()->ParmValue( "-basedir", "" ) ); + Q_AppendSlash( basePath, sizeof( basePath ) ); + Q_strncat( basePath, pProject, sizeof( basePath ), COPY_ALL_CHARACTERS ); + if ( DoesFileExistIn( basePath, GAMEINFO_FILENAME ) ) + { + Q_strncpy( pOutDir, basePath, outDirLen ); + return FS_OK; + } + if ( DoesFileExistIn( basePath, GAMEINFO_FILENAME_ALTERNATE ) ) + { + Q_strncpy( pOutDir, basePath, outDirLen ); + return FS_OK; + } + } + + if ( fsInfo.m_bNoGameInfo ) + { + // fsInfo.m_bNoGameInfo is set by the Steam dedicated server, before it knows which mod to use. + // Steam dedicated server doesn't need a gameinfo.txt, because we'll ask which mod to use, even if + // -game is supplied on the command line. + Q_strncpy( pOutDir, "", outDirLen ); + return FS_OK; + } + else + { + // They either specified vproject on the command line or it's in their registry. Either way, + // we don't want to continue if they've specified it but it's not valid. + goto ShowError; + } + } + + if ( fsInfo.m_bNoGameInfo ) + { + Q_strncpy( pOutDir, "", outDirLen ); + return FS_OK; + } + + // Ask the application if it can provide us with a game info directory + { + bool bBubbleDir = true; + SuggestGameInfoDirFn_t pfnSuggestGameInfoDirFn = GetSuggestGameInfoDirFn(); + if ( pfnSuggestGameInfoDirFn && + ( * pfnSuggestGameInfoDirFn )( &fsInfo, pOutDir, outDirLen, &bBubbleDir ) && + FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, bBubbleDir ) ) + return FS_OK; + } + + // Try to use the environment variable / registry + if ( ( pProject = getenv( GAMEDIR_TOKEN ) ) != NULL && + ( Q_MakeAbsolutePath( pOutDir, outDirLen, pProject ), 1 ) && + FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, false ) ) + return FS_OK; + + if ( IsPC() ) + { + Warning( "Warning: falling back to auto detection of vproject directory.\n" ); + + // Now look for it in the directory they passed in. + if ( fsInfo.m_pDirectoryName ) + Q_MakeAbsolutePath( pOutDir, outDirLen, fsInfo.m_pDirectoryName ); + else + Q_MakeAbsolutePath( pOutDir, outDirLen, "." ); + + if ( FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, true ) ) + return FS_OK; + + // Use the CWD + Q_getwd( pOutDir, outDirLen ); + if ( FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, true ) ) + return FS_OK; + } + +ShowError: + return SetupFileSystemError( true, FS_MISSING_GAMEINFO_FILE, + "Unable to find %s. Solutions:\n\n" + "1. Read http://www.valve-erc.com/srcsdk/faq.html#NoGameDir\n" + "2. Run vconfig to specify which game you're working on.\n" + "3. Add -game on the command line where is the directory that %s is in.\n", + GAMEINFO_FILENAME, GAMEINFO_FILENAME ); +} + +bool DoesPathExistAlready( const char *pPathEnvVar, const char *pTestPath ) +{ + // Fix the slashes in the input arguments. + char correctedPathEnvVar[8192], correctedTestPath[MAX_PATH]; + Q_strncpy( correctedPathEnvVar, pPathEnvVar, sizeof( correctedPathEnvVar ) ); + Q_FixSlashes( correctedPathEnvVar ); + pPathEnvVar = correctedPathEnvVar; + + Q_strncpy( correctedTestPath, pTestPath, sizeof( correctedTestPath ) ); + Q_FixSlashes( correctedTestPath ); + if ( strlen( correctedTestPath ) > 0 && PATHSEPARATOR( correctedTestPath[strlen(correctedTestPath)-1] ) ) + correctedTestPath[ strlen(correctedTestPath) - 1 ] = 0; + + pTestPath = correctedTestPath; + + const char *pCurPos = pPathEnvVar; + while ( 1 ) + { + const char *pTestPos = Q_stristr( pCurPos, pTestPath ); + if ( !pTestPos ) + return false; + + // Ok, we found pTestPath in the path, but it's only valid if it's followed by an optional slash and a semicolon. + pTestPos += strlen( pTestPath ); + if ( pTestPos[0] == 0 || pTestPos[0] == ';' || (PATHSEPARATOR( pTestPos[0] ) && pTestPos[1] == ';') ) + return true; + + // Advance our marker.. + pCurPos = pTestPos; + } +} + + +FSReturnCode_t GetSteamCfgPath( char *steamCfgPath, int steamCfgPathLen ) +{ + steamCfgPath[0] = 0; + char executablePath[MAX_PATH]; + if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) + { + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); + } + Q_strncpy( steamCfgPath, executablePath, steamCfgPathLen ); + while ( 1 ) + { + if ( DoesFileExistIn( steamCfgPath, "steam.cfg" ) ) + break; + + if ( !Q_StripLastDir( steamCfgPath, steamCfgPathLen) ) + { + // the file isnt found, thats ok, its not mandatory + return FS_OK; + } + } + Q_AppendSlash( steamCfgPath, steamCfgPathLen ); + Q_strncat( steamCfgPath, "steam.cfg", steamCfgPathLen, COPY_ALL_CHARACTERS ); + + return FS_OK; +} + +void SetSteamAppUser( KeyValues *pSteamInfo, const char *steamInstallPath, CSteamEnvVars &steamEnvVars ) +{ + // Always inherit the Steam user if it's already set, since it probably means we (or the + // the app that launched us) were launched from Steam. + char appUser[MAX_PATH]; + if ( steamEnvVars.m_SteamAppUser.GetValue( appUser, sizeof( appUser ) ) ) + return; + + const char *pTempAppUser = NULL; + if ( pSteamInfo && (pTempAppUser = pSteamInfo->GetString( "SteamAppUser", NULL )) != NULL ) + { + Q_strncpy( appUser, pTempAppUser, sizeof( appUser ) ); + } + else + { + // They don't have SteamInfo.txt, or it's missing SteamAppUser. Try to figure out the user + // by looking in \config\SteamAppData.vdf. + char fullFilename[MAX_PATH]; + Q_strncpy( fullFilename, steamInstallPath, sizeof( fullFilename ) ); + Q_AppendSlash( fullFilename, sizeof( fullFilename ) ); + Q_strncat( fullFilename, "config\\SteamAppData.vdf", sizeof( fullFilename ), COPY_ALL_CHARACTERS ); + + KeyValues *pSteamAppData = ReadKeyValuesFile( fullFilename ); + if ( !pSteamAppData || (pTempAppUser = pSteamAppData->GetString( "AutoLoginUser", NULL )) == NULL ) + { + Error( "Can't find steam app user info." ); + } + Q_strncpy( appUser, pTempAppUser, sizeof( appUser ) ); + + pSteamAppData->deleteThis(); + } + + Q_strlower( appUser ); + steamEnvVars.m_SteamAppUser.SetValue( "%s", appUser ); +} + +void SetSteamUserPassphrase( KeyValues *pSteamInfo, CSteamEnvVars &steamEnvVars ) +{ + // Always inherit the passphrase if it's already set, since it probably means we (or the + // the app that launched us) were launched from Steam. + char szPassPhrase[ MAX_PATH ]; + if ( steamEnvVars.m_SteamUserPassphrase.GetValue( szPassPhrase, sizeof( szPassPhrase ) ) ) + return; + + // SteamUserPassphrase. + const char *pStr; + if ( pSteamInfo && (pStr = pSteamInfo->GetString( "SteamUserPassphrase", NULL )) != NULL ) + { + steamEnvVars.m_SteamUserPassphrase.SetValue( "%s", pStr ); + } +} + +FSReturnCode_t FileSystem_SetBasePaths( IFileSystem *pFileSystem ) +{ + pFileSystem->RemoveSearchPaths( "EXECUTABLE_PATH" ); + + char executablePath[MAX_PATH]; + if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); + + pFileSystem->AddSearchPath( executablePath, "EXECUTABLE_PATH" ); + + if ( !FileSystem_GetBaseDir( executablePath, sizeof( executablePath ) ) ) + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); + + pFileSystem->AddSearchPath( executablePath, "BASE_PATH" ); + + return FS_OK; +} + +//----------------------------------------------------------------------------- +// Returns the name of the file system DLL to use +//----------------------------------------------------------------------------- +FSReturnCode_t FileSystem_GetFileSystemDLLName( char *pFileSystemDLL, int nMaxLen, bool &bSteam ) +{ + bSteam = false; + + // Inside of here, we don't have a filesystem yet, so we have to assume that the filesystem_stdio or filesystem_steam + // is in this same directory with us. + char executablePath[MAX_PATH]; + if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); + + // Assume we'll use local files + Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_stdio" DLL_EXT_STRING, executablePath, CORRECT_PATH_SEPARATOR ); + + #if !defined( _X360 ) + + // Use filsystem_steam if it exists? + #if defined( OSX ) || defined( LINUX ) + struct stat statBuf; + #endif + if ( + #if defined( OSX ) || defined( LINUX ) + stat( pFileSystemDLL, &statBuf ) != 0 + #else + _access( pFileSystemDLL, 0 ) != 0 + #endif + ) { + Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_steam" DLL_EXT_STRING, executablePath, CORRECT_PATH_SEPARATOR ); + bSteam = true; + } + #endif + + return FS_OK; +} + + +//----------------------------------------------------------------------------- +// Sets up the steam environment + gets back the gameinfo.txt path +//----------------------------------------------------------------------------- +FSReturnCode_t FileSystem_SetupSteamEnvironment( CFSSteamSetupInfo &fsInfo ) +{ + // First, locate the directory with gameinfo.txt. + FSReturnCode_t ret = LocateGameInfoFile( fsInfo, fsInfo.m_GameInfoPath, sizeof( fsInfo.m_GameInfoPath ) ); + if ( ret != FS_OK ) + return ret; + + // This is so that processes spawned by this application will have the same VPROJECT +#ifdef WIN32 + char pEnvBuf[MAX_PATH+32]; + Q_snprintf( pEnvBuf, sizeof(pEnvBuf), "%s=%s", GAMEDIR_TOKEN, fsInfo.m_GameInfoPath ); + _putenv( pEnvBuf ); +#else + setenv( GAMEDIR_TOKEN, fsInfo.m_GameInfoPath, 1 ); +#endif + + return FS_OK; +} + + +//----------------------------------------------------------------------------- +// Loads the file system module +//----------------------------------------------------------------------------- +FSReturnCode_t FileSystem_LoadFileSystemModule( CFSLoadModuleInfo &fsInfo ) +{ + // First, locate the directory with gameinfo.txt. + FSReturnCode_t ret = FileSystem_SetupSteamEnvironment( fsInfo ); + if ( ret != FS_OK ) + return ret; + + // Now that the environment is setup, load the filesystem module. + if ( !Sys_LoadInterface( + fsInfo.m_pFileSystemDLLName, + FILESYSTEM_INTERFACE_VERSION, + &fsInfo.m_pModule, + (void**)&fsInfo.m_pFileSystem ) ) + { + return SetupFileSystemError( false, FS_UNABLE_TO_INIT, "Can't load %s.", fsInfo.m_pFileSystemDLLName ); + } + + if ( !fsInfo.m_pFileSystem->Connect( fsInfo.m_ConnectFactory ) ) + return SetupFileSystemError( false, FS_UNABLE_TO_INIT, "%s IFileSystem::Connect failed.", fsInfo.m_pFileSystemDLLName ); + + if ( fsInfo.m_pFileSystem->Init() != INIT_OK ) + return SetupFileSystemError( false, FS_UNABLE_TO_INIT, "%s IFileSystem::Init failed.", fsInfo.m_pFileSystemDLLName ); + + return FS_OK; +} + + +//----------------------------------------------------------------------------- +// Mounds a particular steam cache +//----------------------------------------------------------------------------- +FSReturnCode_t FileSystem_MountContent( CFSMountContentInfo &mountContentInfo ) +{ + // This part is Steam-only. + if ( mountContentInfo.m_pFileSystem->IsSteam() ) + { + return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "Should not be using filesystem_steam anymore!" ); + +// // Find out the "extra app id". This is for tools, which want to mount a base app's filesystem +// // like HL2, then mount the SDK content (tools materials and models, etc) in addition. +// int nExtraAppId = -1; +// if ( mountContentInfo.m_bToolsMode ) +// { +// // !FIXME! Here we need to mount the tools content (VPK's) in some way...? +// } +// +// // Set our working directory temporarily so Steam can remember it. +// // This is what Steam strips off absolute filenames like c:\program files\valve\steam\steamapps\username\sourcesdk +// // to get to the relative part of the path. +// char baseDir[MAX_PATH], oldWorkingDir[MAX_PATH]; +// if ( !FileSystem_GetBaseDir( baseDir, sizeof( baseDir ) ) ) +// return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); +// +// Q_getwd( oldWorkingDir, sizeof( oldWorkingDir ) ); +// _chdir( baseDir ); +// +// // Filesystem_tools needs to add dependencies in here beforehand. +// FilesystemMountRetval_t retVal = mountContentInfo.m_pFileSystem->MountSteamContent( nExtraAppId ); +// +// _chdir( oldWorkingDir ); +// +// if ( retVal != FILESYSTEM_MOUNT_OK ) +// return SetupFileSystemError( true, FS_UNABLE_TO_INIT, "Unable to mount Steam content in the file system" ); + } + + return FileSystem_SetBasePaths( mountContentInfo.m_pFileSystem ); +} + +void FileSystem_SetErrorMode( FSErrorMode_t errorMode ) +{ + g_FileSystemErrorMode = errorMode; +} + +void FileSystem_ClearSteamEnvVars() +{ + CSteamEnvVars envVars; + + // Change the values and don't restore the originals. + envVars.m_SteamAppId.SetValue( "" ); + envVars.m_SteamUserPassphrase.SetValue( "" ); + envVars.m_SteamAppUser.SetValue( "" ); + + envVars.SetRestoreOriginalValue_ALL( false ); +} + +//----------------------------------------------------------------------------- +// Adds the platform folder to the search path. +//----------------------------------------------------------------------------- +void FileSystem_AddSearchPath_Platform( IFileSystem *pFileSystem, const char *szGameInfoPath ) +{ + char platform[MAX_PATH]; + Q_strncpy( platform, szGameInfoPath, MAX_PATH ); + Q_StripTrailingSlash( platform ); + Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH ); + + pFileSystem->AddSearchPath( platform, "PLATFORM" ); +} diff --git a/public/filesystem_init.h b/public/filesystem_init.h new file mode 100644 index 0000000..9274a5c --- /dev/null +++ b/public/filesystem_init.h @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FILESYSTEM_INIT_H +#define FILESYSTEM_INIT_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "filesystem.h" + + +// If this option is on the command line, then filesystem_init won't bring up the vconfig +// dialog even if FS_ERRORMODE_VCONFIG is used. +#define CMDLINEOPTION_NOVCONFIG "-NoVConfig" + +#define GAMEDIR_TOKEN "VProject" + + +#if defined( _WIN32 ) || defined( WIN32 ) +#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/') +#else //_WIN32 +#define PATHSEPARATOR(c) ((c) == '/') +#endif //_WIN32 + + +enum FSReturnCode_t +{ + FS_OK, + FS_MISSING_GAMEINFO_FILE, + FS_INVALID_GAMEINFO_FILE, + FS_INVALID_PARAMETERS, + FS_UNABLE_TO_INIT, + FS_MISSING_STEAM_DLL +}; + + +enum FSErrorMode_t +{ + FS_ERRORMODE_AUTO, // Call Error() in case of an error. + FS_ERRORMODE_VCONFIG, // Call Error() for errors and run vconfig when appropriate. + FS_ERRORMODE_NONE, // Just return FSReturnCode values and setup the string for FileSystem_GetLastErrorString. +}; + + +class CFSSteamSetupInfo +{ +public: + CFSSteamSetupInfo(); + +// Inputs. +public: + // If this is set, then the init code will look in this directory up to the root for gameinfo.txt. + // It must be set for FileSystem_LoadSearchPaths to work. + // + // (default: null) + const char *m_pDirectoryName; + + // If this is true, then it won't look at -vproject, -game, or the vproject environment variable + // to find gameinfo.txt. If this is true, then m_pDirectoryName must be set. + // + // (default: false) + bool m_bOnlyUseDirectoryName; + + // If this is true, then: + // 1. It will set the environment variables that steam.dll looks at for startup info. + // 2. It will look for ToolsAppId in the gameinfo.txt file and load the + // steam caches associated with that cache if it's there. This is so apps like Hammer and hlmv + // can load the main steam caches (like for Counter-Strike or Half-Life 2), and also load the + // caches that include tools-specific materials (materials\editor, materials\debug, etc). + // + // (default: true - should be FALSE for the engine) + bool m_bToolsMode; + + // If this is true, and m_bToolsMode is false, then it will append the path to steam.dll to the + // PATH environment variable. This makes it so you can run the engine under Steam without + // having to copy steam.dll up into your hl2.exe folder. + // (default: false) + bool m_bSetSteamDLLPath; + + // Are we loading the Steam filesystem? This should be the same value that + // FileSystem_GetFileSystemDLLName gave you. + bool m_bSteam; + + // If this is true, then it won't look for a gameinfo.txt. + // + // (default: false) + bool m_bNoGameInfo; + +// Outputs (if it returns FS_OK). +public: + char m_GameInfoPath[512]; // The directory that gameinfo.txt lives in. +}; + + +class CFSLoadModuleInfo : public CFSSteamSetupInfo +{ +public: + CFSLoadModuleInfo(); + +// Inputs. +public: + // Full path to the file system DLL (gotten from FileSystem_GetFileSystemDLLName). + const char *m_pFileSystemDLLName; + + // Passed to IFileSystem::Connect. + CreateInterfaceFn m_ConnectFactory; + +// Outputs (if it returns FS_OK). +public: + // The filesystem you got from FileSystem_LoadFileSystemModule. + IFileSystem *m_pFileSystem; + CSysModule *m_pModule; +}; + + +class CFSMountContentInfo +{ +public: + CFSMountContentInfo(); + +// Inputs. +public: + + // See CFSLoadModuleInfo::m_bToolsMode (this valid should always be the same as you passed to CFSLoadModuleInfo::m_bToolsMode). + bool m_bToolsMode; + + // This specifies the directory where gameinfo.txt is. This must be set. + // It can come from CFSLoadModuleInfo::m_GameInfoPath. + const char *m_pDirectoryName; + + // Gotten from CFSLoadModuleInfo::m_pFileSystem. + IFileSystem *m_pFileSystem; +}; + + +class CFSSearchPathsInit +{ +public: + CFSSearchPathsInit(); + +// Inputs. +public: + // This specifies the directory where gameinfo.txt is. This must be set. + const char *m_pDirectoryName; + + // If this is set, then any search paths with a _english will be replaced with _m_pLanguage and added before the + // _english path + // (default: null) + const char *m_pLanguage; + + // This is the filesystem FileSystem_LoadSearchPaths is talking to. + IFileSystem *m_pFileSystem; + + bool m_bMountHDContent; + bool m_bLowViolence; + +// Outputs. +public: + // This is the location of the first search path called "game", which also becomes your "mod" search path. + char m_ModPath[512]; +}; + + +const char *GetVProjectCmdLineValue(); + + +// Call this to use a bin directory relative to VPROJECT +void FileSystem_UseVProjectBinDir( bool bEnable ); + +// This is used by all things that use the application framework: +// Note that the application framework automatically takes care of step 1 if you use CSteamApplication. +// Step 1: Ask filesystem_init for the name of the filesystem DLL to load +FSReturnCode_t FileSystem_GetFileSystemDLLName( char *pFileSystemDLL, int nMaxLen, bool &bSteam ); + +// Step 2: Use filesystem framework to load/connect/init that filesystem DLL +// -or- just set up the steam environment and get back the gameinfo.txt path +// The second method is used by the application framework, which wants to connect/init the filesystem itself +FSReturnCode_t FileSystem_LoadFileSystemModule( CFSLoadModuleInfo &info ); +FSReturnCode_t FileSystem_SetupSteamEnvironment( CFSSteamSetupInfo &info ); + +// Step 3: Ask filesystem_init to set up the executable search path, and mount the steam content based on the mod gameinfo.txt file +FSReturnCode_t FileSystem_MountContent( CFSMountContentInfo &fsInfo ); + +// Step 4: Load the search paths out of pGameDirectory\gameinfo.txt. +FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo ); + +// This is automatically done during step 3, but if you want to redo all the search +// paths (like Hammer does), you can call this to reset executable_path. +FSReturnCode_t FileSystem_SetBasePaths( IFileSystem *pFileSystem ); + +// Utility function to add the PLATFORM search path. +void FileSystem_AddSearchPath_Platform( IFileSystem *pFileSystem, const char *szGameInfoPath ); + +// See FSErrorMode_t. If you don't specify one here, then the default is FS_ERRORMODE_VCONFIG. +void FileSystem_SetErrorMode( FSErrorMode_t errorMode = FS_ERRORMODE_VCONFIG ); + +bool FileSystem_GetExecutableDir( char *exedir, int exeDirLen ); + +// Clear SteamAppUser, SteamUserPassphrase, and SteamAppId from this process's environment. +// TODO: always do this after LoadFileSysteModule.. there's no reason it should be +// in the environment. +void FileSystem_ClearSteamEnvVars(); + +// Find the steam.cfg above you for optional stuff +FSReturnCode_t GetSteamCfgPath( char *steamCfgPath, int steamCfgPathLen ); + +// Returns the last error. +const char *FileSystem_GetLastErrorString(); + +void Q_getwd( char *out, int outSize ); + +#endif // FILESYSTEM_INIT_H diff --git a/public/filesystem_passthru.h b/public/filesystem_passthru.h new file mode 100644 index 0000000..67d214b --- /dev/null +++ b/public/filesystem_passthru.h @@ -0,0 +1,264 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FILESYSTEM_PASSTHRU_H +#define FILESYSTEM_PASSTHRU_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "filesystem.h" +#include +#include + +#ifdef AsyncRead +#undef AsyncRead +#undef AsyncReadMutiple +#endif + +// +// These classes pass all filesystem interface calls through to another filesystem +// interface. They can be used anytime you want to override a couple things in +// a filesystem. VMPI uses this to override the base filesystem calls while +// allowing the rest of the filesystem functionality to work on the master. +// + +template +class CInternalFileSystemPassThru : public Base +{ +public: + CInternalFileSystemPassThru() + { + m_pBaseFileSystemPassThru = NULL; + } + virtual void InitPassThru( IBaseFileSystem *pBaseFileSystemPassThru ) + { + m_pBaseFileSystemPassThru = pBaseFileSystemPassThru; + } + virtual int Read( void* pOutput, int size, FileHandle_t file ) { return m_pBaseFileSystemPassThru->Read( pOutput, size, file ); } + virtual int Write( void const* pInput, int size, FileHandle_t file ) { return m_pBaseFileSystemPassThru->Write( pInput, size, file ); } + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID ) { return m_pBaseFileSystemPassThru->Open( pFileName, pOptions, pathID ); } + virtual void Close( FileHandle_t file ) { m_pBaseFileSystemPassThru->Close( file ); } + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) { m_pBaseFileSystemPassThru->Seek( file, pos, seekType ); } + virtual unsigned int Tell( FileHandle_t file ) { return m_pBaseFileSystemPassThru->Tell( file ); } + virtual unsigned int Size( FileHandle_t file ) { return m_pBaseFileSystemPassThru->Size( file ); } + virtual unsigned int Size( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->Size( pFileName, pPathID ); } + virtual void Flush( FileHandle_t file ) { m_pBaseFileSystemPassThru->Flush( file ); } + virtual bool Precache( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->Precache( pFileName, pPathID ); } + virtual bool FileExists( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->FileExists( pFileName, pPathID ); } + virtual bool IsFileWritable( char const *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->IsFileWritable( pFileName, pPathID ); } + virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID ) { return m_pBaseFileSystemPassThru->SetFileWritable( pFileName, writable, pPathID ); } + virtual long GetFileTime( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->GetFileTime( pFileName, pPathID ); } + virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) { return m_pBaseFileSystemPassThru->ReadFile( pFileName, pPath, buf, nMaxBytes, nStartingByte, pfnAlloc ); } + virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf ) { return m_pBaseFileSystemPassThru->WriteFile( pFileName, pPath, buf ); } + virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination ) { return m_pBaseFileSystemPassThru->UnzipFile( pFileName, pPath, pDestination ); } + +protected: + IBaseFileSystem *m_pBaseFileSystemPassThru; +}; + + +class CBaseFileSystemPassThru : public CInternalFileSystemPassThru +{ +public: +}; + + +class CFileSystemPassThru : public CInternalFileSystemPassThru +{ +public: + typedef CInternalFileSystemPassThru BaseClass; + + CFileSystemPassThru() + { + m_pFileSystemPassThru = NULL; + } + virtual void InitPassThru( IFileSystem *pFileSystemPassThru, bool bBaseOnly ) + { + if ( !bBaseOnly ) + m_pFileSystemPassThru = pFileSystemPassThru; + + BaseClass::InitPassThru( pFileSystemPassThru ); + } + + // IAppSystem stuff. + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) OVERRIDE { return m_pFileSystemPassThru->Connect( factory ); } + virtual void Disconnect() OVERRIDE { m_pFileSystemPassThru->Disconnect(); } + virtual void *QueryInterface( const char *pInterfaceName ) OVERRIDE { return m_pFileSystemPassThru->QueryInterface( pInterfaceName ); } + virtual InitReturnVal_t Init() OVERRIDE { return m_pFileSystemPassThru->Init(); } + virtual void Shutdown() OVERRIDE { m_pFileSystemPassThru->Shutdown(); } + + virtual void RemoveAllSearchPaths( void ) OVERRIDE { m_pFileSystemPassThru->RemoveAllSearchPaths(); } + virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType ) OVERRIDE { m_pFileSystemPassThru->AddSearchPath( pPath, pathID, addType ); } + virtual bool RemoveSearchPath( const char *pPath, const char *pathID ) OVERRIDE { return m_pFileSystemPassThru->RemoveSearchPath( pPath, pathID ); } + virtual void RemoveFile( char const* pRelativePath, const char *pathID ) OVERRIDE { m_pFileSystemPassThru->RemoveFile( pRelativePath, pathID ); } + virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID ) OVERRIDE { return m_pFileSystemPassThru->RenameFile( pOldPath, pNewPath, pathID ); } + virtual void CreateDirHierarchy( const char *path, const char *pathID ) OVERRIDE { m_pFileSystemPassThru->CreateDirHierarchy( path, pathID ); } + virtual bool IsDirectory( const char *pFileName, const char *pathID ) OVERRIDE { return m_pFileSystemPassThru->IsDirectory( pFileName, pathID ); } + virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) OVERRIDE { m_pFileSystemPassThru->FileTimeToString( pStrip, maxCharsIncludingTerminator, fileTime ); } + virtual void SetBufferSize( FileHandle_t file, unsigned nBytes ) OVERRIDE { m_pFileSystemPassThru->SetBufferSize( file, nBytes ); } + virtual bool IsOk( FileHandle_t file ) OVERRIDE { return m_pFileSystemPassThru->IsOk( file ); } + virtual bool EndOfFile( FileHandle_t file ) OVERRIDE { return m_pFileSystemPassThru->EndOfFile( file ); } + virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) OVERRIDE { return m_pFileSystemPassThru->ReadLine( pOutput, maxChars, file ); } + virtual int FPrintf( FileHandle_t file, PRINTF_FORMAT_STRING const char *pFormat, ... ) OVERRIDE + { + char str[8192]; + va_list marker; + va_start( marker, pFormat ); + _vsnprintf( str, sizeof( str ), pFormat, marker ); + va_end( marker ); + return m_pFileSystemPassThru->FPrintf( file, "%s", str ); + } + virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID, bool bValidatedDllOnly ) OVERRIDE { return m_pFileSystemPassThru->LoadModule( pFileName, pPathID, bValidatedDllOnly ); } + virtual void UnloadModule( CSysModule *pModule ) OVERRIDE { m_pFileSystemPassThru->UnloadModule( pModule ); } + virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle ) OVERRIDE { return m_pFileSystemPassThru->FindFirst( pWildCard, pHandle ); } + virtual const char *FindNext( FileFindHandle_t handle ) OVERRIDE { return m_pFileSystemPassThru->FindNext( handle ); } + virtual bool FindIsDirectory( FileFindHandle_t handle ) OVERRIDE { return m_pFileSystemPassThru->FindIsDirectory( handle ); } + virtual void FindClose( FileFindHandle_t handle ) OVERRIDE { m_pFileSystemPassThru->FindClose( handle ); } + virtual const char *GetLocalPath( const char *pFileName, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) OVERRIDE { return m_pFileSystemPassThru->GetLocalPath( pFileName, pDest, maxLenInChars ); } + virtual bool FullPathToRelativePath( const char *pFullpath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) OVERRIDE { return m_pFileSystemPassThru->FullPathToRelativePath( pFullpath, pDest, maxLenInChars ); } + //virtual bool GetCaseCorrectFullPath_Ptr( const char *pFullPath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) { return m_pFileSystemPassThru->GetCaseCorrectFullPath_Ptr( pFullPath, pDest, maxLenInChars ); } + virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) OVERRIDE { return m_pFileSystemPassThru->GetCurrentDirectory( pDirectory, maxlen ); } + virtual void PrintOpenedFiles( void ) OVERRIDE { m_pFileSystemPassThru->PrintOpenedFiles(); } + virtual void PrintSearchPaths( void ) OVERRIDE { m_pFileSystemPassThru->PrintSearchPaths(); } + virtual void SetWarningFunc( void (*pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... ) ) OVERRIDE { m_pFileSystemPassThru->SetWarningFunc( pfnWarning ); } + virtual void SetWarningLevel( FileWarningLevel_t level ) OVERRIDE { m_pFileSystemPassThru->SetWarningLevel( level ); } + virtual void AddLoggingFunc( void (*pfnLogFunc)( const char *fileName, const char *accessType ) ) OVERRIDE { m_pFileSystemPassThru->AddLoggingFunc( pfnLogFunc ); } + virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc ) OVERRIDE { m_pFileSystemPassThru->RemoveLoggingFunc( logFunc ); } + virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *pControls ) OVERRIDE { return m_pFileSystemPassThru->AsyncReadMultiple( pRequests, nRequests, pControls ); } + virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *pControls ) OVERRIDE { return m_pFileSystemPassThru->AsyncReadMultipleCreditAlloc( pRequests, nRequests, pszFile, line, pControls ); } + virtual FSAsyncStatus_t AsyncFinish(FSAsyncControl_t hControl, bool wait) OVERRIDE { return m_pFileSystemPassThru->AsyncFinish( hControl, wait ); } + virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize ) OVERRIDE { return m_pFileSystemPassThru->AsyncGetResult( hControl, ppData, pSize ); } + virtual FSAsyncStatus_t AsyncAbort(FSAsyncControl_t hControl) OVERRIDE { return m_pFileSystemPassThru->AsyncAbort( hControl ); } + virtual FSAsyncStatus_t AsyncStatus(FSAsyncControl_t hControl) OVERRIDE { return m_pFileSystemPassThru->AsyncStatus( hControl ); } + virtual FSAsyncStatus_t AsyncFlush() OVERRIDE { return m_pFileSystemPassThru->AsyncFlush(); } + virtual void AsyncAddRef( FSAsyncControl_t hControl ) OVERRIDE { m_pFileSystemPassThru->AsyncAddRef( hControl ); } + virtual void AsyncRelease( FSAsyncControl_t hControl ) OVERRIDE { m_pFileSystemPassThru->AsyncRelease( hControl ); } + virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile ) OVERRIDE { return m_pFileSystemPassThru->AsyncBeginRead( pszFile, phFile ); } + virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile ) OVERRIDE { return m_pFileSystemPassThru->AsyncEndRead( hFile ); } + virtual void AsyncAddFetcher( IAsyncFileFetch *pFetcher ) OVERRIDE { m_pFileSystemPassThru->AsyncAddFetcher( pFetcher ); } + virtual void AsyncRemoveFetcher( IAsyncFileFetch *pFetcher ) OVERRIDE { m_pFileSystemPassThru->AsyncRemoveFetcher( pFetcher ); } + virtual const FileSystemStatistics *GetFilesystemStatistics() OVERRIDE { return m_pFileSystemPassThru->GetFilesystemStatistics(); } + virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) OVERRIDE { return m_pFileSystemPassThru->WaitForResources( resourcelist ); } + virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, + float *progress, bool *complete ) OVERRIDE { return m_pFileSystemPassThru->GetWaitForResourcesProgress( handle, progress, complete ); } + virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) OVERRIDE { m_pFileSystemPassThru->CancelWaitForResources( handle ); } + virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) OVERRIDE { return m_pFileSystemPassThru->HintResourceNeed( hintlist, forgetEverything ); } + virtual bool IsFileImmediatelyAvailable(const char *pFileName) OVERRIDE { return m_pFileSystemPassThru->IsFileImmediatelyAvailable( pFileName ); } + virtual void GetLocalCopy( const char *pFileName ) OVERRIDE { m_pFileSystemPassThru->GetLocalCopy( pFileName ); } + virtual FileNameHandle_t FindOrAddFileName( char const *pFileName ) OVERRIDE { return m_pFileSystemPassThru->FindOrAddFileName( pFileName ); } + virtual FileNameHandle_t FindFileName( char const *pFileName ) OVERRIDE { return m_pFileSystemPassThru->FindFileName( pFileName ); } + virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen ) OVERRIDE { return m_pFileSystemPassThru->String( handle, buf, buflen ); } + virtual bool IsOk2( FileHandle_t file ) { return IsOk(file); } + virtual void RemoveSearchPaths( const char *szPathID ) OVERRIDE { m_pFileSystemPassThru->RemoveSearchPaths( szPathID ); } + virtual bool IsSteam() const OVERRIDE { return m_pFileSystemPassThru->IsSteam(); } + virtual FilesystemMountRetval_t MountSteamContent( int nExtraAppId = -1 ) OVERRIDE { return m_pFileSystemPassThru->MountSteamContent( nExtraAppId ); } + + virtual const char *FindFirstEx( + const char *pWildCard, + const char *pPathID, + FileFindHandle_t *pHandle + ) OVERRIDE { return m_pFileSystemPassThru->FindFirstEx( pWildCard, pPathID, pHandle ); } + virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly ) OVERRIDE { m_pFileSystemPassThru->MarkPathIDByRequestOnly( pPathID, bRequestOnly ); } + virtual bool AddPackFile( const char *fullpath, const char *pathID ) OVERRIDE { return m_pFileSystemPassThru->AddPackFile( fullpath, pathID ); } + virtual FSAsyncStatus_t AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl ) OVERRIDE { return m_pFileSystemPassThru->AsyncAppend( pFileName, pSrc, nSrcBytes, bFreeMemory, pControl); } + virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl ) OVERRIDE { return m_pFileSystemPassThru->AsyncWrite( pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl); } + virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl ) OVERRIDE { return m_pFileSystemPassThru->AsyncWriteFile( pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl); } + virtual FSAsyncStatus_t AsyncAppendFile(const char *pDestFileName, const char *pSrcFileName, FSAsyncControl_t *pControl ) OVERRIDE { return m_pFileSystemPassThru->AsyncAppendFile(pDestFileName, pSrcFileName, pControl); } + virtual void AsyncFinishAll( int iToPriority ) OVERRIDE { m_pFileSystemPassThru->AsyncFinishAll(iToPriority); } + virtual void AsyncFinishAllWrites() OVERRIDE { m_pFileSystemPassThru->AsyncFinishAllWrites(); } + virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) OVERRIDE { return m_pFileSystemPassThru->AsyncSetPriority(hControl, newPriority); } + virtual bool AsyncSuspend() OVERRIDE { return m_pFileSystemPassThru->AsyncSuspend(); } + virtual bool AsyncResume() OVERRIDE { return m_pFileSystemPassThru->AsyncResume(); } + virtual const char *RelativePathToFullPath( const char *pFileName, const char *pPathID, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL ) OVERRIDE { return m_pFileSystemPassThru->RelativePathToFullPath( pFileName, pPathID, pDest, maxLenInChars, pathFilter, pPathType ); } + virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) OVERRIDE { return m_pFileSystemPassThru->GetSearchPath( pathID, bGetPackFiles, pDest, maxLenInChars ); } + + virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL ) OVERRIDE { return m_pFileSystemPassThru->OpenEx( pFileName, pOptions, flags, pathID, ppszResolvedFilename );} + virtual int ReadEx( void* pOutput, int destSize, int size, FileHandle_t file ) OVERRIDE { return m_pFileSystemPassThru->ReadEx( pOutput, destSize, size, file ); } + virtual int ReadFileEx( const char *pFileName, const char *pPath, void **ppBuf, bool bNullTerminate, bool bOptimalAlloc, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) OVERRIDE { return m_pFileSystemPassThru->ReadFileEx( pFileName, pPath, ppBuf, bNullTerminate, bOptimalAlloc, nMaxBytes, nStartingByte, pfnAlloc ); } + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking( bool state ) { m_pFileSystemPassThru->EnableBlockingFileAccessTracking( state ); } + virtual bool IsBlockingFileAccessEnabled() const { return m_pFileSystemPassThru->IsBlockingFileAccessEnabled(); } + + virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo() { return m_pFileSystemPassThru->RetrieveBlockingFileAccessInfo(); } +#endif + virtual void SetupPreloadData() OVERRIDE {} + virtual void DiscardPreloadData() OVERRIDE {} + + virtual void LoadCompiledKeyValues( KeyValuesPreloadType_t type, char const *archiveFile ) OVERRIDE { m_pFileSystemPassThru->LoadCompiledKeyValues( type, archiveFile ); } + + // If the "PreloadedData" hasn't been purged, then this'll try and instance the KeyValues using the fast path of compiled keyvalues loaded during startup. + // Otherwise, it'll just fall through to the regular KeyValues loading routines + virtual KeyValues *LoadKeyValues( KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) OVERRIDE { return m_pFileSystemPassThru->LoadKeyValues( type, filename, pPathID ); } + virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) OVERRIDE { return m_pFileSystemPassThru->LoadKeyValues( head, type, filename, pPathID ); } + virtual bool ExtractRootKeyName( KeyValuesPreloadType_t type, char *outbuf, size_t bufsize, char const *filename, char const *pPathID = 0 ) OVERRIDE { return m_pFileSystemPassThru->ExtractRootKeyName( type, outbuf, bufsize, filename, pPathID ); } + + virtual bool GetFileTypeForFullPath( char const *pFullPath, wchar_t *buf, size_t bufSizeInBytes ) OVERRIDE { return m_pFileSystemPassThru->GetFileTypeForFullPath( pFullPath, buf, bufSizeInBytes ); } + + virtual bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign ) OVERRIDE { return m_pFileSystemPassThru->GetOptimalIOConstraints( hFile, pOffsetAlign, pSizeAlign, pBufferAlign ); } + virtual void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize, unsigned nOffset ) OVERRIDE { return m_pFileSystemPassThru->AllocOptimalReadBuffer( hFile, nOffset, nSize ); } + virtual void FreeOptimalReadBuffer( void *p ) OVERRIDE { m_pFileSystemPassThru->FreeOptimalReadBuffer( p ); } + + virtual void BeginMapAccess() OVERRIDE { m_pFileSystemPassThru->BeginMapAccess(); } + virtual void EndMapAccess() OVERRIDE { m_pFileSystemPassThru->EndMapAccess(); } + + virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL ) OVERRIDE { return m_pFileSystemPassThru->ReadToBuffer( hFile, buf, nMaxBytes, pfnAlloc ); } + virtual bool FullPathToRelativePathEx( const char *pFullPath, const char *pPathId, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) OVERRIDE { return m_pFileSystemPassThru->FullPathToRelativePathEx( pFullPath, pPathId, pDest, maxLenInChars ); } + virtual int GetPathIndex( const FileNameHandle_t &handle ) OVERRIDE { return m_pFileSystemPassThru->GetPathIndex( handle ); } + virtual long GetPathTime( const char *pPath, const char *pPathID ) OVERRIDE { return m_pFileSystemPassThru->GetPathTime( pPath, pPathID ); } + + virtual DVDMode_t GetDVDMode() OVERRIDE { return m_pFileSystemPassThru->GetDVDMode(); } + + virtual void EnableWhitelistFileTracking( bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes ) OVERRIDE + { m_pFileSystemPassThru->EnableWhitelistFileTracking( bEnable, bCacheAllVPKHashes, bRecalculateAndCheckHashes ); } + virtual void RegisterFileWhitelist( IPureServerWhitelist *pWhiteList, IFileList **ppFilesToReload ) OVERRIDE + { m_pFileSystemPassThru->RegisterFileWhitelist( pWhiteList, ppFilesToReload ); } + virtual void MarkAllCRCsUnverified() OVERRIDE + { m_pFileSystemPassThru->MarkAllCRCsUnverified(); } + virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter ) OVERRIDE + { return m_pFileSystemPassThru->CacheFileCRCs( pPathname, eType, pFilter ); } + virtual EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash ) OVERRIDE + { return m_pFileSystemPassThru->CheckCachedFileHash( pPathID, pRelativeFilename, nFileFraction, pFileHash ); } + virtual int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles ) OVERRIDE + { return m_pFileSystemPassThru->GetUnverifiedFileHashes( pFiles, nMaxFiles ); } + virtual int GetWhitelistSpewFlags() OVERRIDE + { return m_pFileSystemPassThru->GetWhitelistSpewFlags(); } + virtual void SetWhitelistSpewFlags( int spewFlags ) OVERRIDE + { m_pFileSystemPassThru->SetWhitelistSpewFlags( spewFlags ); } + virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func ) OVERRIDE { m_pFileSystemPassThru->InstallDirtyDiskReportFunc( func ); } + + virtual FileCacheHandle_t CreateFileCache() OVERRIDE { return m_pFileSystemPassThru->CreateFileCache(); } + virtual void AddFilesToFileCache( FileCacheHandle_t cacheId, const char **ppFileNames, int nFileNames, const char *pPathID ) OVERRIDE { m_pFileSystemPassThru->AddFilesToFileCache( cacheId, ppFileNames, nFileNames, pPathID ); } + virtual bool IsFileCacheFileLoaded( FileCacheHandle_t cacheId, const char *pFileName ) OVERRIDE { return m_pFileSystemPassThru->IsFileCacheFileLoaded( cacheId, pFileName ); } + virtual bool IsFileCacheLoaded( FileCacheHandle_t cacheId ) OVERRIDE { return m_pFileSystemPassThru->IsFileCacheLoaded( cacheId ); } + virtual void DestroyFileCache( FileCacheHandle_t cacheId ) OVERRIDE { m_pFileSystemPassThru->DestroyFileCache( cacheId ); } + + virtual bool RegisterMemoryFile( CMemoryFileBacking *pFile, CMemoryFileBacking **ppExistingFileWithRef ) OVERRIDE { return m_pFileSystemPassThru->RegisterMemoryFile( pFile, ppExistingFileWithRef ); } + virtual void UnregisterMemoryFile( CMemoryFileBacking *pFile ) OVERRIDE { m_pFileSystemPassThru->UnregisterMemoryFile( pFile ); } + virtual void CacheAllVPKFileHashes( bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes ) OVERRIDE + { return m_pFileSystemPassThru->CacheAllVPKFileHashes( bCacheAllVPKHashes, bRecalculateAndCheckHashes ); } + virtual bool CheckVPKFileHash( int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t &md5Value ) OVERRIDE + { return m_pFileSystemPassThru->CheckVPKFileHash( PackFileID, nPackFileNumber, nFileFraction, md5Value ); } + virtual void NotifyFileUnloaded( const char *pszFilename, const char *pPathId ) OVERRIDE + { m_pFileSystemPassThru->NotifyFileUnloaded( pszFilename, pPathId ); } + +protected: + IFileSystem *m_pFileSystemPassThru; +}; + + +// This is so people who change the filesystem interface are forced to add the passthru wrapper into CFileSystemPassThru, +// so they don't break VMPI. +inline void GiveMeACompileError() +{ + CFileSystemPassThru asdf; +} + + +#endif // FILESYSTEM_PASSTHRU_H diff --git a/public/filesystem_stdio.h b/public/filesystem_stdio.h new file mode 100644 index 0000000..a5559ea --- /dev/null +++ b/public/filesystem_stdio.h @@ -0,0 +1,357 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef GetCurrentDirectory +#undef AsyncRead + +class CPackFile; +class CBaseFileSystem; +class IGet; +struct FIND_DATA; + +enum FileMode_t +{ + FM_BINARY, + FM_TEXT +}; + +enum FileType_t +{ + FT_NORMAL, + FT_PACK_BINARY, + FT_PACK_TEXT +}; + +union Placeholder4 +{ + const uint8_t bytes[4]; + const char *string; + uint32_t integer; + void *pointer; +}; + +template class CThreadSafeRefCountedObject +{ +public: + CThreadSafeRefCountedObject( T initVal ) + { + m_RefCount = 0; + m_pObject = initVal; + m_RefCount = 0; + } + + void Init( T pObj ) + { + Assert( ThreadInMainThread() ); + Assert( !m_pObject ); + m_RefCount = 0; + m_pObject = pObj; + m_RefCount = 1; + } + + T AddRef() + { + if ( ++m_RefCount > 1 ) + return m_pObject; + + --m_RefCount; + return nullptr; + } + void ReleaseRef( T pObj ) + { + if ( --m_RefCount >= 1 ) + Assert( m_pObject == pObj ); + } + + T GetInMainThread() + { + Assert( ThreadInMainThread() ); + return m_pObject; + } + + void ResetWhenNoRemainingReferences( T newValue ) + { + Assert( ThreadInMainThread() ); + + while ( m_RefCount > 0 ) + CThread::Sleep( 20 ); + + m_pObject = newValue; + } + +private: + CInterlockedIntT m_RefCount; + T m_pObject; +}; + +class CPackFileHandle +{ +public: + int64_t m_nBase; + uint32_t m_nFilePointer; + CPackFile *m_pOwner; + uint32_t m_nLength; + uint32_t m_nIndex; +}; + +class CFileHandle +{ +public: +#if !defined( _RETAIL ) + char *m_pszTrueFileName; +#endif + + CPackFileHandle *m_pPackFileHandle; + int64_t m_nLength; + FileType_t m_type; + FILE *m_pFile; + CBaseFileSystem *m_fs; + + enum + { + MAGIC = 1128679521, // 'CFHa' + FREE_MAGIC = 1181902157 // 'FreM' + }; + + uint32_t m_nMagic; +}; + +class CPackFile : public CRefCounted +{ +public: + virtual ~CPackFile( ) = 0; + virtual CFileHandle *OpenFile( const char *pFileName, const char *pOptions = "rb" ) = 0; + virtual bool Prepare( int64_t fileLen = -1, int64_t nFileOfs = 0 ) = 0; + virtual bool FindFile( const char *pFilename, int32_t &nIndex, int64_t &nPosition, int32_t &nLength ) = 0; + virtual int32_t ReadFromPack( int32_t nIndex, void *buffer, int32_t nDestBytes, int32_t nBytes, int64_t nOffset ) = 0; + virtual bool IndexToFilename( int32_t nIndex, char *buffer, int32_t nBufferSize ) = 0; + virtual void SetupPreloadData( ) = 0; + virtual void DiscardPreloadData( ) = 0; + virtual int64_t GetPackFileBaseOffset( ) = 0; + + CThreadFastMutex m_mutex; // 8b + CUtlSymbol m_Path; // 4b + int64_t m_nBaseOffset; // 8b + CUtlString m_ZipName; // 4b + bool m_bIsMapPath; // 4b + int32_t m_lPackFileTime; // 4b + int32_t m_refCount; // 4b + int32_t m_nOpenFiles; // 4b + FILE *m_hPackFileHandle; // 4b + int64_t m_FileLength; // 8b + CBaseFileSystem *m_fs; // 4b +}; + +class CZipPackFile : public CPackFile +{ +public: + class CPackFileEntry + { + public: + uint32_t m_nPosition; + uint32_t m_nLength; + uint32_t m_HashName; + uint16_t m_nPreloadIdx; + uint16_t pad; +#if !defined( _RETAIL ) + FileNameHandle_t m_hDebugFilename; +#endif + }; + + class CPackFileLessFunc + { + public: + bool Less( const CPackFileEntry &src1, const CPackFileEntry &src2, void *pCtx ); + }; + + CUtlSortVector m_PackFiles; // 28b + int64_t m_nPreloadSectionOffset; // 8b + uint32_t m_nPreloadSectionSize; // 4b + struct ZIP_PreloadHeader *m_pPreloadHeader; // 4b + uint16_t *m_pPreloadRemapTable; // 4b + struct ZIP_PreloadDirectoryEntry *m_pPreloadDirectory; // 4b + void *m_pPreloadData; // 4b + CByteswap m_swap; // 4b + + Placeholder4 placeholders[13]; +}; + +class WilloxHallOfShame +{ +public: + void **vtable; + uint32_t refcounter; + uint32_t filepathid; + const char filepath[1]; +}; + +class CFileInfo; + +class CPathIDFileList +{ +public: + CUtlSymbol m_PathID; + CUtlDict m_Files; + CUtlLinkedList m_UnverifiedCRCFiles; +}; + +class CFileInfo +{ +public: + uint16_t m_Flags; + CRC32_t m_CRC; + CPathIDFileList *m_pPathIDFileList; + int32_t m_PathIDFileListDictIndex; + int32_t m_iNeedsVerificationListIndex; +}; + +class CFileTracker +{ + CUtlLinkedList m_NeedsVerificationList; + CUtlDict m_PathIDs; + CBaseFileSystem *m_pFileSystem; + CThreadMutex m_Mutex; +}; + +class CWhitelistSpecs +{ +public: + IFileList *m_pWantCRCList; + IFileList *m_pAllowFromDiskList; +}; +typedef CThreadSafeRefCountedObject CWhitelistHolder; + +class CBaseFileSystem : public CTier1AppSystem +{ +public: + class CPathIDInfo + { + public: + bool m_bByRequestOnly; + CUtlSymbol m_PathID; + const char *m_pDebugPathID; + }; + + class CSearchPath + { + public: + int32_t m_storeId; + CPathIDInfo *m_pPathIDInfo; + uint32_t enum1; + uint32_t enum2; + CUtlSymbol m_Path; + const char *m_pDebugPath; + bool m_bIsRemotePath; + WilloxHallOfShame *m_pPackFile; + }; + + struct FindData_t + { }; + + struct CompiledKeyValuesPreloaders_t + { + FileNameHandle_t m_CacheFile; + class CCompiledKeyValuesReader *m_pReader; + }; + + class COpenedFile + { + public: + FILE *m_pFile; + char *m_pName; + }; + + CWhitelistHolder m_FileWhitelist; + int32_t m_WhitelistSpewFlags; + CUtlVector m_LogFuncs; + CThreadMutex m_SearchPathsMutex; + CUtlLinkedList m_SearchPaths; + CUtlVector m_PathIDInfos; + CUtlLinkedList m_FindData; // DO NOT USE AT ALL! + int32_t m_iMapLoad; + CUtlVector m_ZipFiles; + FILE *m_pLogFile; + bool m_bOutputDebugString; + IThreadPool *m_pThreadPool; + CThreadFastMutex m_AsyncCallbackMutex; + FileSystemStatistics m_Stats; + //CUtlRBTree m_OpenedFiles; + CThreadMutex m_OpenedFilesMutex; + CUtlVector m_OpenedFiles; + FileWarningLevel_t m_fwLevel; + CUtlFilenameSymbolTable m_FileNames; + CFileTracker m_FileTracker; + int32_t m_WhitelistFileTrackingEnabled; + FSDirtyDiskReportFunc_t m_DirtyDiskReportFunc; + CompiledKeyValuesPreloaders_t m_PreloadData[IFileSystem::NUM_PRELOAD_TYPES]; +}; + +class CFileSystem_Stdio : public CBaseFileSystem +{ +public: + virtual void RemoveSearchPathsByGroup( int ) = 0; + virtual void SetGet( IGet * ) = 0; + virtual Addon::FileSystem *Addons( ) = 0; + virtual Gamemode::System *Gamemodes( ) = 0; + virtual GameDepot::System *Games( ) = 0; + virtual LegacyAddons::System *LegacyAddons( ) = 0; + virtual CLanguage *Language( ) = 0; + virtual void DoFilesystemRefresh( ) = 0; + virtual int LastFilesystemRefresh( ) = 0; + virtual void AddVPKFileFromPath( const char *, const char *, unsigned int ) = 0; + virtual void GMOD_SetupDefaultPaths( const char *, const char * ) = 0; + virtual void GMOD_FixPathCase( char *, uint ) = 0; + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = nullptr ) = 0; + virtual void Close( FileHandle_t file ) = 0; + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; + virtual unsigned int Tell( FileHandle_t file ) = 0; + virtual unsigned int Size( FileHandle_t file ) = 0; + virtual unsigned int Size( const char *pFileName, const char *pPathID = nullptr ) = 0; + virtual void Flush( FileHandle_t file ) = 0; + virtual bool Precache( const char *pFileName, const char *pPathID = nullptr ) = 0; + virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; + virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; + virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = nullptr ) = 0; + virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf ) = 0; + virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination ) = 0; + virtual bool FileExists( const char *pFileName, const char *pPathID = nullptr ) = 0; + virtual long GetFileTime( const char *pFileName, const char *pPathID = nullptr ) = 0; + virtual bool IsFileWritable( char const *pFileName, const char *pPathID = nullptr ) = 0; + virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID = nullptr ) = 0; + virtual void FixUpPath( const char *, char *, int ) = 0; + virtual FILE *FS_fopen( const char *, const char *, unsigned int, long long * ) = 0; + virtual void FS_setbufsize( FILE *, unsigned int ) = 0; + virtual void FS_fclose( FILE * ) = 0; + virtual void FS_fseek( FILE *, long long, int ) = 0; + virtual long FS_ftell( FILE * ) = 0; + virtual int FS_feof( FILE * ) = 0; + virtual void FS_fread( void *, unsigned long, unsigned long, FILE * ) = 0; + virtual void FS_fwrite( const void *, unsigned long, FILE * ) = 0; + virtual bool FS_setmode( FILE *, FileMode_t ) = 0; + virtual size_t FS_vfprintf( FILE *, const char *, char * ) = 0; + virtual int FS_ferror( FILE * ) = 0; + virtual int FS_fflush( FILE * ) = 0; + virtual char *FS_fgets( char *, int, FILE * ) = 0; + virtual int FS_stat( const char *, struct stat *, bool * ) = 0; + virtual int FS_chmod( const char *, int ) = 0; + virtual HANDLE FS_FindFirstFile( const char *, FIND_DATA * ) = 0; + virtual bool FS_FindNextFile( HANDLE, FIND_DATA * ) = 0; + virtual bool FS_FindClose( HANDLE ) = 0; + virtual int FS_GetSectorSize( FILE * ) = 0; + + bool m_bMounted; + bool m_bCanAsync; +}; diff --git a/public/g15/ig15.h b/public/g15/ig15.h new file mode 100644 index 0000000..51b77b7 --- /dev/null +++ b/public/g15/ig15.h @@ -0,0 +1,60 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef IG15_H +#define IG15_H +#ifdef _WIN32 +#pragma once +#endif + +typedef void * G15_HANDLE; + +typedef enum +{ + G15_BUTTON_1, G15_BUTTON_2, G15_BUTTON_3, G15_BUTTON_4 +} G15SoftButton; + +typedef enum +{ + G15_SMALL, G15_MEDIUM, G15_BIG +} G15TextSize; + +typedef enum +{ + G15_SCROLLING_TEXT, G15_STATIC_TEXT, G15_ICON, G15_PROGRESS_BAR, G15_UNKNOWN +} G15ObjectType; + +class IG15 +{ +public: + virtual void GetLCDSize( int &w, int &h ) = 0; + + // w, h should match the return value from GetLCDSize!!! + + // Creates the underlying object + virtual bool Init( char const *name ) = 0; + // Destroys the underlying object + virtual void Shutdown() = 0; + + virtual bool IsConnected() = 0; + + // Add/remove + virtual G15_HANDLE AddText(G15ObjectType type, G15TextSize size, int alignment, int maxLengthPixels) = 0; + virtual G15_HANDLE AddIcon( void *icon, int sizeX, int sizeY) = 0; + virtual void RemoveAndDestroyObject( G15_HANDLE hObject ) = 0; + + // Change + virtual int SetText(G15_HANDLE handle, char const * text) = 0; + virtual int SetOrigin(G15_HANDLE handle, int x, int y) = 0; + virtual int SetVisible(G15_HANDLE handle, bool visible) = 0; + + virtual bool ButtonTriggered(int button) = 0; + virtual void UpdateLCD( unsigned int dwTimestamp) = 0; +}; + +#define G15_INTERFACE_VERSION "G15_INTERFACE_VERSION001" + +#endif // IG15_H diff --git a/public/game/client/IGameClientExports.h b/public/game/client/IGameClientExports.h new file mode 100644 index 0000000..2679b6e --- /dev/null +++ b/public/game/client/IGameClientExports.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IGAMECLIENTEXPORTS_H +#define IGAMECLIENTEXPORTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Exports a set of functions for the GameUI interface to interact with the game client +//----------------------------------------------------------------------------- +abstract_class IGameClientExports : public IBaseInterface +{ +public: +#ifndef _XBOX + // ingame voice manipulation + virtual bool IsPlayerGameVoiceMuted(int playerIndex) = 0; + virtual void MutePlayerGameVoice(int playerIndex) = 0; + virtual void UnmutePlayerGameVoice(int playerIndex) = 0; + + // notification of gameui state changes + virtual void OnGameUIActivated() = 0; + virtual void OnGameUIHidden() = 0; +#endif + + //============================================================================= + // HPE_BEGIN + // [dwenger] Necessary for stats display + //============================================================================= + + virtual void CreateAchievementsPanel( vgui::Panel* pParent ) = 0; + virtual void DisplayAchievementPanel( ) = 0; + virtual void ShutdownAchievementPanel( ) = 0; + virtual int GetAchievementsPanelMinWidth( void ) const = 0; + + //============================================================================= + // HPE_END + //============================================================================= + + virtual const char *GetHolidayString() = 0; +}; + +#define GAMECLIENTEXPORTS_INTERFACE_VERSION "GameClientExports001" + + +#endif // IGAMECLIENTEXPORTS_H diff --git a/public/game/client/iclientrendertargets.h b/public/game/client/iclientrendertargets.h new file mode 100644 index 0000000..60a1447 --- /dev/null +++ b/public/game/client/iclientrendertargets.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Exposes interfaces to the engine which allow the client to setup their own render targets +// during the proper period of material system's init. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLIENTRENDERTARGETS_H +#define ICLIENTRENDERTARGETS_H +#ifdef _WIN32 + #pragma once +#endif + +#include "interface.h" // For base interface + +class IMaterialSystem; +class IMaterialSystemHardwareConfig; + +//--------------------------------------------------------------------------------------------------- +// Purpose: Exposes interfaces to the engine which allow the client to setup their own render targets +// during the proper period of material system's init. +//--------------------------------------------------------------------------------------------------- +abstract_class IClientRenderTargets +{ +public: + // Pass the material system interface to the client-- Their Material System singleton has not been created + // at the time they receive this call. + virtual void InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ) = 0; + + // Call shutdown on every created refrence-- Clients keep track of this themselves + // and should add shutdown code to this function whenever they add a new render target. + virtual void ShutdownClientRenderTargets( void ) = 0; + +}; + +#define CLIENTRENDERTARGETS_INTERFACE_VERSION "ClientRenderTargets001" + +extern IClientRenderTargets * g_pClientRenderTargets; + +#endif // ICLIENTRENDERTARGETS_H diff --git a/public/game/client/iviewport.h b/public/game/client/iviewport.h new file mode 100644 index 0000000..5e26f3a --- /dev/null +++ b/public/game/client/iviewport.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IVIEWPORT_H ) +#define IVIEWPORT_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +#include "viewport_panel_names.h" + +class KeyValues; + +abstract_class IViewPortPanel +{ + +public: + virtual ~IViewPortPanel() {}; + + virtual const char *GetName( void ) = 0;// return identifer name + virtual void SetData(KeyValues *data) = 0; // set ViewPortPanel data + virtual void Reset( void ) = 0; // clears internal state, deactivates it + virtual void Update( void ) = 0; // updates all (size, position, content, etc) + virtual bool NeedsUpdate( void ) = 0; // query panel if content needs to be updated + virtual bool HasInputElements( void ) = 0; // true if panel contains elments which accepts input + + virtual void ShowPanel( bool state ) = 0; // activate VGUI Frame + + // VGUI functions: + virtual vgui::VPANEL GetVPanel( void ) = 0; // returns VGUI panel handle + virtual bool IsVisible() = 0; // true if panel is visible + virtual void SetParent( vgui::VPANEL parent ) = 0; +}; + +abstract_class IViewPort +{ +public: + virtual void UpdateAllPanels( void ) = 0; + virtual void ShowPanel( const char *pName, bool state ) = 0; + virtual void ShowPanel( IViewPortPanel* pPanel, bool state ) = 0; + virtual void ShowBackGround(bool bShow) = 0; + virtual IViewPortPanel* FindPanelByName(const char *szPanelName) = 0; + virtual IViewPortPanel* GetActivePanel( void ) = 0; + virtual void PostMessageToPanel( const char *pName, KeyValues *pKeyValues ) = 0; +}; + +extern IViewPort *gViewPortInterface; + + +#endif // IVIEWPORT_H \ No newline at end of file diff --git a/public/game/server/ientityinfo.h b/public/game/server/ientityinfo.h new file mode 100644 index 0000000..04ab6b3 --- /dev/null +++ b/public/game/server/ientityinfo.h @@ -0,0 +1,150 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: provides an interface for plugins to query information about entities from the game dll +// +//===============================================================================================// +#ifndef IENTITYINFO_H +#define IENTITYINFO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "pluginvariant.h" + +abstract_class IEntityInfo +{ +public: + // returns true if entity is a player + virtual const int EntityIndex() = 0; + virtual const char *GetEntityName() = 0; + virtual const char *GetClassname() = 0; + virtual const char *GetModelName() = 0; +//TODO + virtual const char *GetTargetName() = 0; + virtual void SetModel(const char *modelName) = 0; + virtual bool IsPlayer() = 0; + virtual bool IsNPC() = 0; + virtual bool IsDead() = 0; + virtual bool IsAlive() = 0; + virtual bool IsInWorld() = 0; + virtual bool IsTemplate() = 0; + virtual int GetEFlags() = 0; + virtual void SetEFlags( int iEFlags ) = 0; + virtual void AddEFlags( int nEFlagMask ) = 0; + virtual bool IsEFlagSet( int EFlagMask ) = 0; + + virtual const int GetEffects( void ) = 0; + virtual void AddEffects( int nEffects ) = 0; + virtual void RemoveEffects( int nEffects ) = 0; + virtual void ClearEffects( void ) = 0; + virtual void SetEffects( int nEffects ) = 0; + virtual bool IsEffectActive( int nEffects ) = 0; + virtual int GetRenderMode() = 0; + virtual void SetRenderMode( int nRenderMode ) = 0; + + virtual void SetBlocksLOS( bool bBlocksLOS ) = 0; + virtual bool BlocksLOS( void ) = 0; + + virtual const int GetHealth() = 0; + virtual const int GetMaxHealth() = 0; + virtual void SetHealth( int iHealth ) = 0; + virtual void SetMaxHealth( int iMaxHealth ) = 0; + + // returns the team the entity is on + virtual int GetTeamIndex() = 0; + // changes the entity to a new team (if the game dll logic allows it) + virtual void ChangeTeam( int iTeamNum ) = 0; + + // positioning and sizes + virtual const Vector GetAbsOrigin() = 0; + virtual void SetAbsOrigin( Vector & vec ) = 0; + virtual const QAngle GetAbsAngles() = 0; + virtual void SetAbsAngles( QAngle & ang ) = 0; + virtual const Vector GetLocalOrigin() = 0; + virtual void SetLocalOrigin( const Vector& origin ) = 0; + virtual const QAngle GetLocalAngles() = 0; + virtual void SetLocalAngles( const QAngle& angles ) = 0; + virtual const Vector GetAbsVelocity() = 0; + virtual const Vector GetLocalVelocity() = 0; + virtual const QAngle GetLocalAngularVelocity() = 0; + virtual void EntityToWorldSpace( const Vector &in, Vector *pOut ) = 0; + virtual void WorldToEntitySpace( const Vector &in, Vector *pOut ) = 0; + virtual Vector EyePosition() = 0; + virtual QAngle EyeAngles() = 0; + virtual QAngle LocalEyeAngles() = 0; + virtual Vector EarPosition() = 0; + + // returns world aligned mins/maxs of this entity + virtual const Vector GetWorldMins() = 0; + virtual const Vector GetWorldMaxs() = 0; + virtual const Vector WorldSpaceCenter() = 0; + + virtual int GetWaterLevel() = 0; + + // if this entity has an owner, it returns their edict_t. + virtual edict_t *GetOwner() = 0; + virtual edict_t *GetParent() = 0; + virtual edict_t *GetMoveParent() = 0; + virtual edict_t *GetRootMoveParent() = 0; + + // if this entity is following another, returns that entities edict_t. + virtual edict_t *GetFollowedEntity() = 0; + virtual edict_t *GetGroundEntity() = 0; //returns the entity that this one is standing on - if set. + + // accessor to hook mod specific information about the entity. + virtual bool GetCustomInfo(int valueType, pluginvariant &outValue, pluginvariant options) = 0; + + // entity debugging stuff. + virtual const char *GetDebugName() = 0; + virtual void EntityText( int text_offset, const char *text, float flDuration, int r = 255, int g = 255, int b = 255, int a = 255 ) = 0; + + //Keyvalues + virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ) = 0; + + +}; + + +#define INTERFACEVERSION_ENTITYINFOMANAGER "EntityInfoManager001" +abstract_class IEntityInfoManager +{ +public: + virtual IEntityInfo *GetEntityInfo( edict_t *pEdict ) = 0; + virtual IEntityInfo *GetEntityInfo( int index ) = 0; //Retrieves the info + + //Experiment.. + virtual IServerUnknown *GetServerEntity( edict_t *pEdict ) = 0; + + //----------------------------------------------------------------------------- + // Purpose: Iterates the entities with a given classname. + // Input : pStartEntity - Last entity found, NULL to start a new iteration. + // szName - Classname to search for. + //----------------------------------------------------------------------------- + virtual edict_t *FindEntityByClassname( edict_t *pStartEntity, const char *szName ) = 0; + + //----------------------------------------------------------------------------- + // Purpose: Iterates the entities with a given name. + // Input : pStartEntity - Last entity found, NULL to start a new iteration. + // szName - Name to search for. + //----------------------------------------------------------------------------- + virtual edict_t *FindEntityByName( edict_t *pStartEntity, const char *szName ) = 0; + + //----------------------------------------------------------------------------- + // Purpose: Iterates the entities with a given model name. + // Input : pStartEntity - Last entity found, NULL to start a new iteration. + // szModelName - Model Name to search for. + //----------------------------------------------------------------------------- + virtual edict_t *FindEntityByModel( edict_t *pStartEntity, const char *szModelName ) = 0; + + //----------------------------------------------------------------------------- + // Purpose: Used to iterate all the entities within a sphere. + // Input : pStartEntity - + // vecCenter - + // flRadius - + //----------------------------------------------------------------------------- + virtual edict_t *FindEntityInSphere( edict_t *pStartEntity, const Vector &vecCenter, float flRadius ) = 0; + + virtual void GetWorldBounds( Vector &mins, Vector &maxs ) = 0; +}; +#endif // IENTITYINFO_H diff --git a/public/game/server/igameinfo.h b/public/game/server/igameinfo.h new file mode 100644 index 0000000..8218a1f --- /dev/null +++ b/public/game/server/igameinfo.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: provides an interface for plugins to query information about the gamerules in a simple +// and organized mannor. +// +//===============================================================================================// +#ifndef IGAMEINFO_H +#define IGAMEINFO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include "pluginvariant.h" + +//Tony; prefixing everything in this so that i can make IGameInfo an extension of CGameRules and not stomp on anything, since gamerules isn't an entity. +abstract_class IGameInfo +{ +public: + // returns an enumerated id for the current game type + virtual const int GetInfo_GameType() = 0; + // returns a name associated with the gametype, if defined. + virtual const char *GetInfo_GameTypeName() = 0; + // returns the team name associated with the number + virtual const char *GetInfo_GetTeamName(int teamNumber) = 0; + // returns how many teams the game has (typically always 4; 0 = unassigned, 1 = spectator, 2 = team1, 3 = team2) + virtual const int GetInfo_GetTeamCount() = 0; + // returns how many players are on a given team + virtual const int GetInfo_NumPlayersOnTeam(int teamNumber) = 0; + + // accessor to hook mod specific information about the rules. for TF2, fields such as + virtual bool GetInfo_Custom(int valueType, pluginvariant &outValue, pluginvariant options) = 0; + +}; + + +//Interface is very simple, there's not much really needed for the manager, this stuff is just in it's own interface so it's not mixed up with the entity +//or player managers. +#define INTERFACEVERSION_GAMEINFOMANAGER "GameInfoManager001" +abstract_class IGameInfoManager +{ +public: + virtual IGameInfo *GetGameInfo() = 0; +}; +#endif // IGAMEINFO_H diff --git a/public/game/server/iplayerinfo.h b/public/game/server/iplayerinfo.h new file mode 100644 index 0000000..8b32c5d --- /dev/null +++ b/public/game/server/iplayerinfo.h @@ -0,0 +1,195 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: provides an interface for dlls to query information about players from the game dll +// +//=============================================================================// +#ifndef IPLAYERINFO_H +#define IPLAYERINFO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" + +// helper class for user commands +class CBotCmd +{ +public: + CBotCmd() + { + Reset(); + } + + virtual ~CBotCmd() { }; + + void Reset() + { + command_number = 0; + tick_count = 0; + viewangles.Init(); + forwardmove = 0.0f; + sidemove = 0.0f; + upmove = 0.0f; + buttons = 0; + impulse = 0; + weaponselect = 0; + weaponsubtype = 0; + random_seed = 0; + mousedx = 0; + mousedy = 0; + + hasbeenpredicted = false; + } + + CBotCmd& operator =( const CBotCmd& src ) + { + if ( this == &src ) + return *this; + + command_number = src.command_number; + tick_count = src.tick_count; + viewangles = src.viewangles; + forwardmove = src.forwardmove; + sidemove = src.sidemove; + upmove = src.upmove; + buttons = src.buttons; + impulse = src.impulse; + weaponselect = src.weaponselect; + weaponsubtype = src.weaponsubtype; + random_seed = src.random_seed; + mousedx = src.mousedx; + mousedy = src.mousedy; + hasbeenpredicted = src.hasbeenpredicted; + return *this; + } + + // For matching server and client commands for debugging + int command_number; + + // the tick the client created this command + int tick_count; + + // Player instantaneous view angles. + QAngle viewangles; + // Intended velocities + // forward velocity. + float forwardmove; + // sideways velocity. + float sidemove; + // upward velocity. + float upmove; + // Attack button states + int buttons; + // Impulse command issued. + byte impulse; + // Current weapon id + int weaponselect; + int weaponsubtype; + + int random_seed; // For shared random functions + + short mousedx; // mouse accum in x from create move + short mousedy; // mouse accum in y from create move + + // Client only, tracks whether we've predicted this command at least once + bool hasbeenpredicted; +}; + + + + +abstract_class IPlayerInfo +{ +public: + // returns the players name (UTF-8 encoded) + virtual const char *GetName() = 0; + // returns the userid (slot number) + virtual int GetUserID() = 0; + // returns the string of their network (i.e Steam) ID + virtual const char *GetNetworkIDString() = 0; + // returns the team the player is on + virtual int GetTeamIndex() = 0; + // changes the player to a new team (if the game dll logic allows it) + virtual void ChangeTeam( int iTeamNum ) = 0; + // returns the number of kills this player has (exact meaning is mod dependent) + virtual int GetFragCount() = 0; + // returns the number of deaths this player has (exact meaning is mod dependent) + virtual int GetDeathCount() = 0; + // returns if this player slot is actually valid + virtual bool IsConnected() = 0; + // returns the armor/health of the player (exact meaning is mod dependent) + virtual int GetArmorValue() = 0; + + // extensions added to V2 + + // various player flags + virtual bool IsHLTV() = 0; + virtual bool IsPlayer() = 0; + virtual bool IsFakeClient() = 0; + virtual bool IsDead() = 0; + virtual bool IsInAVehicle() = 0; + virtual bool IsObserver() = 0; + + // player position and size + virtual const Vector GetAbsOrigin() = 0; + virtual const QAngle GetAbsAngles() = 0; + virtual const Vector GetPlayerMins() = 0; + virtual const Vector GetPlayerMaxs() = 0; + // the name of the weapon currently being carried + virtual const char *GetWeaponName() = 0; + // the name of the player model in use + virtual const char *GetModelName() = 0; + // current player health + virtual int GetHealth() = 0; + // max health value + virtual int GetMaxHealth() = 0; + // the last user input from this player + virtual CBotCmd GetLastUserCommand() = 0; + + virtual bool IsReplay() = 0; +}; + + +#define INTERFACEVERSION_PLAYERINFOMANAGER "PlayerInfoManager002" +abstract_class IPlayerInfoManager +{ +public: + virtual IPlayerInfo *GetPlayerInfo( edict_t *pEdict ) = 0; + virtual CGlobalVars *GetGlobalVars() = 0; +}; + + + + +abstract_class IBotController +{ +public: + // change the bots position + virtual void SetAbsOrigin( Vector & vec ) = 0; + virtual void SetAbsAngles( QAngle & ang ) = 0; + virtual void SetLocalOrigin( const Vector& origin ) = 0; + virtual const Vector GetLocalOrigin( void ) = 0; + virtual void SetLocalAngles( const QAngle& angles ) = 0; + virtual const QAngle GetLocalAngles( void ) = 0; + + // strip them of weapons, etc + virtual void RemoveAllItems( bool removeSuit ) = 0; + // give them a weapon + virtual void SetActiveWeapon( const char *WeaponName ) = 0; + // check various effect flags + virtual bool IsEFlagSet( int nEFlagMask ) = 0; + // fire a virtual move command to the bot + virtual void RunPlayerMove( CBotCmd *ucmd ) = 0; +}; + + +#define INTERFACEVERSION_PLAYERBOTMANAGER "BotManager001" +abstract_class IBotManager +{ +public: + virtual IBotController *GetBotController( edict_t *pEdict ) = 0; + // create a new bot and spawn it into the server + virtual edict_t *CreateBot( const char *botname ) = 0; +}; + +#endif // IPLAYERINFO_H diff --git a/public/game/server/pluginvariant.h b/public/game/server/pluginvariant.h new file mode 100644 index 0000000..b4a798c --- /dev/null +++ b/public/game/server/pluginvariant.h @@ -0,0 +1,165 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PLUGINVARIANT_H +#define PLUGINVARIANT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "stdstring.h" +#include "mathlib/vmatrix.h" + +/* +//Tony; including stdstring at this point (which I need) messes up the offsetof override in linux, so I need to reset it here. +#if defined( POSIX ) +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + */ +// +// A modified variant class for that functions almost identically to variant_t, for plugins to pass data back and forth. +// +class pluginvariant +{ + union + { + bool bVal; + int iVal; + float flVal; + float vecVal[3]; + color32 rgbaVal; + }; + //Tony; neither of these can be in the union because of constructors. + edict_t *eVal; + char iszVal[1024]; + + fieldtype_t fieldType; + +public: + + // constructor + pluginvariant() : fieldType(FIELD_VOID), iVal(0) {} + + inline bool Bool( void ) const { return( fieldType == FIELD_BOOLEAN ) ? bVal : false; } + inline const char *String( void ) const { return( ToString() ); } + inline int Int( void ) const { return( fieldType == FIELD_INTEGER ) ? iVal : 0; } + inline float Float( void ) const { return( fieldType == FIELD_FLOAT ) ? flVal : 0; } + inline const edict_t *Edict(void) const; + inline color32 Color32(void) const { return rgbaVal; } + inline void Vector3D(Vector &vec) const; + + fieldtype_t FieldType( void ) { return fieldType; } + + void SetBool( bool b ) { bVal = b; fieldType = FIELD_BOOLEAN; } + void SetString( char *str ) { Q_snprintf(iszVal, 1024, "%s", str); fieldType = FIELD_STRING; } + void SetInt( int val ) { iVal = val, fieldType = FIELD_INTEGER; } + void SetFloat( float val ) { flVal = val, fieldType = FIELD_FLOAT; } + void SetEdict( edict_t *val ) { eVal = val; fieldType = FIELD_EHANDLE; } + void SetVector3D( const Vector &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_VECTOR; } + void SetPositionVector3D( const Vector &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_POSITION_VECTOR; } + void SetColor32( color32 val ) { rgbaVal = val; fieldType = FIELD_COLOR32; } + void SetColor32( int r, int g, int b, int a ) { rgbaVal.r = r; rgbaVal.g = g; rgbaVal.b = b; rgbaVal.a = a; fieldType = FIELD_COLOR32; } + +protected: + + // + // Returns a string representation of the value without modifying the variant. + // + const char *ToString( void ) const + { + static char szBuf[512]; + + switch (fieldType) + { + case FIELD_STRING: + { + return (const char *)iszVal; + } + + case FIELD_BOOLEAN: + { + if (bVal == 0) + { + Q_strncpy(szBuf, "false",sizeof(szBuf)); + } + else + { + Q_strncpy(szBuf, "true",sizeof(szBuf)); + } + return(szBuf); + } + + case FIELD_INTEGER: + { + Q_snprintf( szBuf, sizeof( szBuf ), "%i", iVal ); + return(szBuf); + } + + case FIELD_FLOAT: + { + Q_snprintf(szBuf,sizeof(szBuf), "%g", flVal); + return(szBuf); + } + + case FIELD_COLOR32: + { + Q_snprintf(szBuf,sizeof(szBuf), "%d %d %d %d", (int)rgbaVal.r, (int)rgbaVal.g, (int)rgbaVal.b, (int)rgbaVal.a); + return(szBuf); + } + + case FIELD_VECTOR: + { + Q_snprintf(szBuf,sizeof(szBuf), "[%g %g %g]", (double)vecVal[0], (double)vecVal[1], (double)vecVal[2]); + return(szBuf); + } + + case FIELD_VOID: + { + szBuf[0] = '\0'; + return(szBuf); + } + } + + return("No conversion to string"); + } +}; + + +////////////////////////// pluginvariant implementation ////////////////////////// + + +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as a vector. +//----------------------------------------------------------------------------- +inline void pluginvariant::Vector3D(Vector &vec) const +{ + if (( fieldType == FIELD_VECTOR ) || ( fieldType == FIELD_POSITION_VECTOR )) + { + vec[0] = vecVal[0]; + vec[1] = vecVal[1]; + vec[2] = vecVal[2]; + } + else + { + vec = vec3_origin; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as an edict_t +//----------------------------------------------------------------------------- +inline const edict_t *pluginvariant::Edict(void) const +{ + if ( fieldType == FIELD_EHANDLE ) + return eVal; + + return NULL; +} + + +#endif // pluginvariant_H diff --git a/public/gamebspfile.h b/public/gamebspfile.h new file mode 100644 index 0000000..d9b1d2a --- /dev/null +++ b/public/gamebspfile.h @@ -0,0 +1,292 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines game-specific data +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef GAMEBSPFILE_H +#define GAMEBSPFILE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" +#include "basetypes.h" + + +//----------------------------------------------------------------------------- +// This enumerations defines all the four-CC codes for the client lump names +//----------------------------------------------------------------------------- +// TODO: We may have some endian considerations here! +#define GAMELUMP_MAKE_CODE(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d) << 0) +enum +{ + GAMELUMP_DETAIL_PROPS = GAMELUMP_MAKE_CODE('d', 'p', 'r', 'p'), + GAMELUMP_DETAIL_PROP_LIGHTING = GAMELUMP_MAKE_CODE('d', 'p', 'l', 't'), + GAMELUMP_STATIC_PROPS = GAMELUMP_MAKE_CODE('s', 'p', 'r', 'p'), + GAMELUMP_DETAIL_PROP_LIGHTING_HDR = GAMELUMP_MAKE_CODE('d', 'p', 'l', 'h'), +}; + +// Versions... +enum +{ + GAMELUMP_DETAIL_PROPS_VERSION = 4, + GAMELUMP_DETAIL_PROP_LIGHTING_VERSION = 0, + GAMELUMP_STATIC_PROPS_VERSION = 10, + GAMELUMP_STATIC_PROP_LIGHTING_VERSION = 0, + GAMELUMP_DETAIL_PROP_LIGHTING_HDR_VERSION = 0, +}; + + +//----------------------------------------------------------------------------- +// This is the data associated with the GAMELUMP_DETAIL_PROPS lump +//----------------------------------------------------------------------------- +#define DETAIL_NAME_LENGTH 128 + +enum DetailPropOrientation_t +{ + DETAIL_PROP_ORIENT_NORMAL = 0, + DETAIL_PROP_ORIENT_SCREEN_ALIGNED, + DETAIL_PROP_ORIENT_SCREEN_ALIGNED_VERTICAL, +}; + +// NOTE: If DetailPropType_t enum changes, change CDetailModel::QuadsToDraw +// in detailobjectsystem.cpp +enum DetailPropType_t +{ + DETAIL_PROP_TYPE_MODEL = 0, + DETAIL_PROP_TYPE_SPRITE, + DETAIL_PROP_TYPE_SHAPE_CROSS, + DETAIL_PROP_TYPE_SHAPE_TRI, +}; + +//----------------------------------------------------------------------------- +// Model index when using studiomdls for detail props +//----------------------------------------------------------------------------- +struct DetailObjectDictLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + char m_Name[DETAIL_NAME_LENGTH]; // model name +}; + +//----------------------------------------------------------------------------- +// Information about the sprite to render +//----------------------------------------------------------------------------- +struct DetailSpriteDictLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + // NOTE: All detail prop sprites must lie in the material detail/detailsprites + Vector2D m_UL; // Coordinate of upper left + Vector2D m_LR; // Coordinate of lower right + Vector2D m_TexUL; // Texcoords of upper left + Vector2D m_TexLR; // Texcoords of lower left +}; + +struct DetailObjectLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector m_Origin; + QAngle m_Angles; + unsigned short m_DetailModel; // either index into DetailObjectDictLump_t or DetailPropSpriteLump_t + unsigned short m_Leaf; + ColorRGBExp32 m_Lighting; + unsigned int m_LightStyles; + unsigned char m_LightStyleCount; + unsigned char m_SwayAmount; // how much do the details sway + unsigned char m_ShapeAngle; // angle param for shaped sprites + unsigned char m_ShapeSize; // size param for shaped sprites + unsigned char m_Orientation; // See DetailPropOrientation_t + unsigned char m_Padding2[3]; // FIXME: Remove when we rev the detail lump again.. + unsigned char m_Type; // See DetailPropType_t + unsigned char m_Padding3[3]; // FIXME: Remove when we rev the detail lump again.. + float m_flScale; // For sprites only currently +}; + +//----------------------------------------------------------------------------- +// This is the data associated with the GAMELUMP_DETAIL_PROP_LIGHTING lump +//----------------------------------------------------------------------------- +struct DetailPropLightstylesLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + ColorRGBExp32 m_Lighting; + unsigned char m_Style; +}; + +//----------------------------------------------------------------------------- +// This is the data associated with the GAMELUMP_STATIC_PROPS lump +//----------------------------------------------------------------------------- +enum +{ + STATIC_PROP_NAME_LENGTH = 128, + + // Flags field + // These are automatically computed + STATIC_PROP_FLAG_FADES = 0x1, + STATIC_PROP_USE_LIGHTING_ORIGIN = 0x2, + STATIC_PROP_NO_DRAW = 0x4, // computed at run time based on dx level + + // These are set in WC + STATIC_PROP_IGNORE_NORMALS = 0x8, + STATIC_PROP_NO_SHADOW = 0x10, + STATIC_PROP_SCREEN_SPACE_FADE = 0x20, + + STATIC_PROP_NO_PER_VERTEX_LIGHTING = 0x40, // in vrad, compute lighting at + // lighting origin, not for each vertex + + STATIC_PROP_NO_SELF_SHADOWING = 0x80, // disable self shadowing in vrad + + STATIC_PROP_NO_PER_TEXEL_LIGHTING = 0x100, // whether we should do per-texel lightmaps in vrad. + + STATIC_PROP_WC_MASK = 0x1d8, // all flags settable in hammer (?) +}; + +struct StaticPropDictLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + char m_Name[STATIC_PROP_NAME_LENGTH]; // model name +}; + +struct StaticPropLumpV4_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector m_Origin; + QAngle m_Angles; + unsigned short m_PropType; + unsigned short m_FirstLeaf; + unsigned short m_LeafCount; + unsigned char m_Solid; + unsigned char m_Flags; + int m_Skin; + float m_FadeMinDist; + float m_FadeMaxDist; + Vector m_LightingOrigin; +// int m_Lighting; // index into the GAMELUMP_STATIC_PROP_LIGHTING lump +}; + +struct StaticPropLumpV5_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector m_Origin; + QAngle m_Angles; + unsigned short m_PropType; + unsigned short m_FirstLeaf; + unsigned short m_LeafCount; + unsigned char m_Solid; + unsigned char m_Flags; + int m_Skin; + float m_FadeMinDist; + float m_FadeMaxDist; + Vector m_LightingOrigin; + float m_flForcedFadeScale; +// int m_Lighting; // index into the GAMELUMP_STATIC_PROP_LIGHTING lump +}; + +struct StaticPropLumpV6_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector m_Origin; + QAngle m_Angles; + unsigned short m_PropType; + unsigned short m_FirstLeaf; + unsigned short m_LeafCount; + unsigned char m_Solid; + unsigned char m_Flags; + int m_Skin; + float m_FadeMinDist; + float m_FadeMaxDist; + Vector m_LightingOrigin; + float m_flForcedFadeScale; + unsigned short m_nMinDXLevel; + unsigned short m_nMaxDXLevel; + // int m_Lighting; // index into the GAMELUMP_STATIC_PROP_LIGHTING lump +}; + +struct StaticPropLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector m_Origin; + QAngle m_Angles; + unsigned short m_PropType; + unsigned short m_FirstLeaf; + unsigned short m_LeafCount; + unsigned char m_Solid; + int m_Skin; + float m_FadeMinDist; + float m_FadeMaxDist; + Vector m_LightingOrigin; + float m_flForcedFadeScale; + unsigned short m_nMinDXLevel; + unsigned short m_nMaxDXLevel; + // int m_Lighting; // index into the GAMELUMP_STATIC_PROP_LIGHTING lump + unsigned int m_Flags; + unsigned short m_nLightmapResolutionX; + unsigned short m_nLightmapResolutionY; + + + StaticPropLump_t& operator=(const StaticPropLumpV4_t& _rhs) + { + m_Origin = _rhs.m_Origin; + m_Angles = _rhs.m_Angles; + m_PropType = _rhs.m_PropType; + m_FirstLeaf = _rhs.m_FirstLeaf; + m_LeafCount = _rhs.m_LeafCount; + m_Solid = _rhs.m_Solid; + m_Flags = _rhs.m_Flags; + m_Skin = _rhs.m_Skin; + m_FadeMinDist = _rhs.m_FadeMinDist; + m_FadeMaxDist = _rhs.m_FadeMaxDist; + m_LightingOrigin = _rhs.m_LightingOrigin; + + // These get potentially set twice--once here and once in the caller. + // Value judgement: This makes the code easier to work with, so unless it's a perf issue... + m_flForcedFadeScale = 1.0f; + m_nMinDXLevel = 0; + m_nMaxDXLevel = 0; + m_nLightmapResolutionX = 0; + m_nLightmapResolutionY = 0; + + // Older versions don't want this. + m_Flags |= STATIC_PROP_NO_PER_TEXEL_LIGHTING; + return *this; + } + + StaticPropLump_t& operator=(const StaticPropLumpV5_t& _rhs) + { + (*this) = reinterpret_cast(_rhs); + + m_flForcedFadeScale = _rhs.m_flForcedFadeScale; + return *this; + } + + StaticPropLump_t& operator=(const StaticPropLumpV6_t& _rhs) + { + (*this) = reinterpret_cast(_rhs); + + m_nMinDXLevel = _rhs.m_nMinDXLevel; + m_nMaxDXLevel = _rhs.m_nMaxDXLevel; + return *this; + } +}; + + + + +struct StaticPropLeafLump_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short m_Leaf; +}; + +//----------------------------------------------------------------------------- +// This is the data associated with the GAMELUMP_STATIC_PROP_LIGHTING lump +//----------------------------------------------------------------------------- +struct StaticPropLightstylesLump_t +{ + ColorRGBExp32 m_Lighting; +}; + +#endif // GAMEBSPFILE_H diff --git a/public/gametrace.h b/public/gametrace.h new file mode 100644 index 0000000..7fe4000 --- /dev/null +++ b/public/gametrace.h @@ -0,0 +1,176 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GAMETRACE_H +#define GAMETRACE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "cmodel.h" +#include "utlvector.h" +#include "ihandleentity.h" +#include "ispatialpartition.h" + +#if defined( CLIENT_DLL ) + class C_BaseEntity; +#else + class CBaseEntity; +#endif + + +//----------------------------------------------------------------------------- +// Purpose: A trace is returned when a box is swept through the world +// NOTE: eventually more of this class should be moved up into the base class!! +//----------------------------------------------------------------------------- +class CGameTrace : public CBaseTrace +{ +public: + + // Returns true if hEnt points at the world entity. + // If this returns true, then you can't use GetHitBoxIndex(). + bool DidHitWorld() const; + + // Returns true if we hit something and it wasn't the world. + bool DidHitNonWorldEntity() const; + + // Gets the entity's network index if the trace has hit an entity. + // If not, returns -1. + int GetEntityIndex() const; + + // Returns true if there was any kind of impact at all + bool DidHit() const; + + // The engine doesn't know what a CBaseEntity is, so it has a backdoor to + // let it get at the edict. +#if defined( ENGINE_DLL ) + void SetEdict( edict_t *pEdict ); + edict_t* GetEdict() const; +#endif + + +public: + + float fractionleftsolid; // time we left a solid, only valid if we started in solid + csurface_t surface; // surface hit (impact surface) + + int hitgroup; // 0 == generic, non-zero is specific body part + short physicsbone; // physics bone hit by trace in studio + +#if defined( CLIENT_DLL ) + C_BaseEntity *m_pEnt; +#else + CBaseEntity *m_pEnt; +#endif + + // NOTE: this member is overloaded. + // If hEnt points at the world entity, then this is the static prop index. + // Otherwise, this is the hitbox index. + int hitbox; // box hit by trace in studio + + CGameTrace() {} + +private: + // No copy constructors allowed + CGameTrace(const CGameTrace& vOther); +}; + + +//----------------------------------------------------------------------------- +// Returns true if there was any kind of impact at all +//----------------------------------------------------------------------------- +inline bool CGameTrace::DidHit() const +{ + return fraction < 1 || allsolid || startsolid; +} + + +typedef CGameTrace trace_t; + +//============================================================================= + +#define TLD_DEF_LEAF_MAX 256 +#define TLD_DEF_ENTITY_MAX 1024 + +class CTraceListData : public IPartitionEnumerator +{ +public: + + CTraceListData( int nLeafMax = TLD_DEF_LEAF_MAX, int nEntityMax = TLD_DEF_ENTITY_MAX ) + { + MEM_ALLOC_CREDIT(); + m_nLeafCount = 0; + m_aLeafList.SetSize( nLeafMax ); + + m_nEntityCount = 0; + m_aEntityList.SetSize( nEntityMax ); + } + + ~CTraceListData() + { + m_nLeafCount = 0; + m_aLeafList.RemoveAll(); + + m_nEntityCount = 0; + m_aEntityList.RemoveAll(); + } + + void Reset( void ) + { + m_nLeafCount = 0; + m_nEntityCount = 0; + } + + bool IsEmpty( void ) const { return ( m_nLeafCount == 0 && m_nEntityCount == 0 ); } + + int LeafCount( void ) const { return m_nLeafCount; } + int LeafCountMax( void ) const { return m_aLeafList.Count(); } + void LeafCountReset( void ) { m_nLeafCount = 0; } + + int EntityCount( void ) const { return m_nEntityCount; } + int EntityCountMax( void ) const { return m_aEntityList.Count(); } + void EntityCountReset( void ) { m_nEntityCount = 0; } + + // For leaves... + void AddLeaf( int iLeaf ) + { + if ( m_nLeafCount >= m_aLeafList.Count() ) + { + DevMsg( "CTraceListData: Max leaf count along ray exceeded!\n" ); + m_aLeafList.AddMultipleToTail( m_aLeafList.Count() ); + } + + m_aLeafList[m_nLeafCount] = iLeaf; + m_nLeafCount++; + } + + // For entities... + IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) + { + if ( m_nEntityCount >= m_aEntityList.Count() ) + { + DevMsg( "CTraceListData: Max entity count along ray exceeded!\n" ); + m_aEntityList.AddMultipleToTail( m_aEntityList.Count() ); + } + + m_aEntityList[m_nEntityCount] = pHandleEntity; + m_nEntityCount++; + + return ITERATION_CONTINUE; + } + +public: + + int m_nLeafCount; + CUtlVector m_aLeafList; + + int m_nEntityCount; + CUtlVector m_aEntityList; +}; + +#endif // GAMETRACE_H + diff --git a/public/globalvars_base.h b/public/globalvars_base.h new file mode 100644 index 0000000..7ba96cb --- /dev/null +++ b/public/globalvars_base.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GLOBALVARS_BASE_H +#define GLOBALVARS_BASE_H + +#ifdef _WIN32 +#pragma once +#endif + +class CSaveRestoreData; + +//----------------------------------------------------------------------------- +// Purpose: Global variables used by shared code +//----------------------------------------------------------------------------- +class CGlobalVarsBase +{ +public: + + CGlobalVarsBase( bool bIsClient ); + + // This can be used to filter debug output or to catch the client or server in the act. + bool IsClient() const; + + // for encoding m_flSimulationTime, m_flAnimTime + int GetNetworkBase( int nTick, int nEntity ); + +public: + + // Absolute time (per frame still - Use Plat_FloatTime() for a high precision real time + // perf clock, but not that it doesn't obey host_timescale/host_framerate) + float realtime; + // Absolute frame counter + int framecount; + // Non-paused frametime + float absoluteframetime; + + // Current time + // + // On the client, this (along with tickcount) takes a different meaning based on what + // piece of code you're in: + // + // - While receiving network packets (like in PreDataUpdate/PostDataUpdate and proxies), + // this is set to the SERVER TICKCOUNT for that packet. There is no interval between + // the server ticks. + // [server_current_Tick * tick_interval] + // + // - While rendering, this is the exact client clock + // [client_current_tick * tick_interval + interpolation_amount] + // + // - During prediction, this is based on the client's current tick: + // [client_current_tick * tick_interval] + float curtime; + + // Time spent on last server or client frame (has nothing to do with think intervals) + float frametime; + // current maxplayers setting + int maxClients; + + // Simulation ticks + int tickcount; + + // Simulation tick interval + float interval_per_tick; + + // interpolation amount ( client-only ) based on fraction of next tick which has elapsed + float interpolation_amount; + int simTicksThisFrame; + + int network_protocol; + + // current saverestore data + CSaveRestoreData *pSaveData; + +private: + // Set to true in client code. + bool m_bClient; + + // 100 (i.e., tickcount is rounded down to this base and then the "delta" from this base is networked + int nTimestampNetworkingBase; + // 32 (entindex() % nTimestampRandomizeWindow ) is subtracted from gpGlobals->tickcount to set the networking basis, prevents + // all of the entities from forcing a new PackedEntity on the same tick (i.e., prevents them from getting lockstepped on this) + int nTimestampRandomizeWindow; + +}; + +inline int CGlobalVarsBase::GetNetworkBase( int nTick, int nEntity ) +{ + int nEntityMod = nEntity % nTimestampRandomizeWindow; + int nBaseTick = nTimestampNetworkingBase * (int)( ( nTick - nEntityMod ) / nTimestampNetworkingBase ); + return nBaseTick; +} + +inline CGlobalVarsBase::CGlobalVarsBase( bool bIsClient ) : + m_bClient( bIsClient ), + nTimestampNetworkingBase( 100 ), + nTimestampRandomizeWindow( 32 ) +{ +} + +inline bool CGlobalVarsBase::IsClient() const +{ + return m_bClient; +} + +#endif // GLOBALVARS_BASE_H diff --git a/public/haptics/haptic_msgs.cpp b/public/haptics/haptic_msgs.cpp new file mode 100644 index 0000000..57b4bed --- /dev/null +++ b/public/haptics/haptic_msgs.cpp @@ -0,0 +1,192 @@ +#include "cbase.h" + +#ifdef CLIENT_DLL + #include "tier3/tier3.h" + #include "iviewrender.h" + #include "inputsystem/iinputsystem.h" + #include "vgui/IInputInternal.h" + #include "c_basecombatweapon.h" + #include "c_baseplayer.h" + #include "hud_macros.h" + #include "iclientvehicle.h" + #include "c_prop_vehicle.h" + #include "prediction.h" + #include "activitylist.h" +#ifdef TERROR + #include "ClientTerrorPlayer.h" +#endif +extern vgui::IInputInternal *g_InputInternal; +#else + #include "usermessages.h" +#endif + +#include "haptics/haptic_msgs.h" + +void RegisterHapticMessages(void) +{ + usermessages->Register( "SPHapWeapEvent", 4 ); + usermessages->Register( "HapDmg", -1 ); + usermessages->Register( "HapPunch", -1 ); + usermessages->Register( "HapSetDrag", -1 ); + usermessages->Register( "HapSetConst", -1 ); + usermessages->Register( "HapMeleeContact", 0); +} + +//----------------------------------------------------------------------------- +// Server +//----------------------------------------------------------------------------- +#ifndef CLIENT_DLL + +void HapticMsg_SendWeaponAnim( CBasePlayer *pPlayer, int iActivity ) +{ + //Send the haptics message + CSingleUserRecipientFilter user( pPlayer ); + user.MakeReliable(); + UserMessageBegin( user, "SPHapWeapEvent" ); + WRITE_LONG(iActivity); + MessageEnd(); +} + +void HapticMsg_SetDrag(CBasePlayer* pPlayer, float drag) +{ + CSingleUserRecipientFilter user( pPlayer ); + user.MakeReliable(); + UserMessageBegin( user, "HapSetDrag" ); + WRITE_FLOAT(drag); + MessageEnd(); +} + +void HapticMsg_SetConstantForce(CBasePlayer* pPlayer, Vector force) +{ + // portal does not network this. + CSingleUserRecipientFilter user( pPlayer ); + user.MakeReliable(); + UserMessageBegin( user, "HapSetConst" ); + WRITE_SHORT(force.x); + WRITE_SHORT(force.y); + WRITE_SHORT(force.z); + MessageEnd(); +} + +void HapticMsg_HapDmg(CBasePlayer* pPlayer, float pitch, float yaw, float dmg, float dmgType ) +{ + CSingleUserRecipientFilter user(pPlayer); + user.MakeReliable(); + UserMessageBegin(user,"HapDmg"); + + WRITE_FLOAT(pitch); + WRITE_FLOAT(yaw); + WRITE_FLOAT(dmg); + WRITE_LONG(dmgType); + MessageEnd(); +} + +void HapticMsg_Punch(CBasePlayer* pPlayer, float x, float y, float z) +{ + CSingleUserRecipientFilter user(pPlayer); + user.MakeReliable(); + UserMessageBegin(user,"HapPunch"); + + WRITE_FLOAT(x); + WRITE_FLOAT(y); + WRITE_FLOAT(z); + MessageEnd(); +} + +void HapticMsg_MeleeContact(CBasePlayer* pPlayer) +{ + CSingleUserRecipientFilter user(pPlayer); + user.MakeReliable(); + UserMessageBegin(user,"HapMeleeContact"); + MessageEnd(); +} + +#endif //!CLIENT_DLL + +//----------------------------------------------------------------------------- +// Client +//----------------------------------------------------------------------------- +#ifdef CLIENT_DLL +void HookHapticMessages(void) +{ + HOOK_MESSAGE(SPHapWeapEvent); + HOOK_MESSAGE(HapDmg); + HOOK_MESSAGE(HapPunch); + HOOK_MESSAGE(HapSetDrag); + HOOK_MESSAGE(HapSetConst); + HOOK_MESSAGE(HapMeleeContact); + +} + +// Defined in haptics_utils +#ifdef WIN32 +void HapticsHandleMsg_HapSetDrag( float drag ); +void HapticsHandleMsg_HapSetConst( Vector const &constant ); +void HapticsHandleMsg_SPHapWeapEvent( int iActivity ); +void HapticsHandleMsg_HapPunch( QAngle const &angle ); +void HapticsHandleMsg_HapDmg( float pitch, float yaw, float damage, int damageType ); +void HapticsHandleMsg_HapMeleeContact(); +#endif // WIN32 + +void __MsgFunc_HapSetDrag( bf_read &msg ) +{ +#ifdef WIN32 + float drag = msg.ReadFloat(); + HapticsHandleMsg_HapSetDrag( drag ); +#endif // WIN32 +} + +//Might be able to handle this better... +void __MsgFunc_HapSetConst( bf_read &msg ) +{ +#ifdef WIN32 + Vector constant; + constant.x = msg.ReadShort(); + constant.y = msg.ReadShort(); + constant.z = msg.ReadShort(); + + HapticsHandleMsg_HapSetConst( constant ); +#endif // WIN32 +} + +void __MsgFunc_SPHapWeapEvent( bf_read &msg ) +{ +#ifdef WIN32 + int iActivity = msg.ReadLong(); + + HapticsHandleMsg_SPHapWeapEvent( iActivity ); +#endif // WIN32 +} + +void __MsgFunc_HapPunch( bf_read &msg ) +{ +#ifdef WIN32 + float x = msg.ReadFloat(); + float y = msg.ReadFloat(); + float z = msg.ReadFloat(); + + HapticsHandleMsg_HapPunch( QAngle(x,y,z) ); +#endif // WIN32 +} + +void __MsgFunc_HapDmg( bf_read &msg ) +{ +#ifdef WIN32 + float pitch = msg.ReadFloat(); + float yaw = msg.ReadFloat(); + float damage = msg.ReadFloat(); + int damageType = msg.ReadLong(); + + HapticsHandleMsg_HapDmg( pitch, yaw, damage, damageType ); +#endif // WIN32 +} + +void __MsgFunc_HapMeleeContact( bf_read &msg ) +{ +#ifdef WIN32 + HapticsHandleMsg_HapMeleeContact(); +#endif // WIN32 +} +#endif // CLIENT_DLL + + diff --git a/public/haptics/haptic_msgs.h b/public/haptics/haptic_msgs.h new file mode 100644 index 0000000..a7e4df1 --- /dev/null +++ b/public/haptics/haptic_msgs.h @@ -0,0 +1,34 @@ +#ifndef HAPTIC_MSGS_H +#define HAPTIC_MSGS_H + +void RegisterHapticMessages(void); + +//----------------------------------------------------------------------------- +// Server +//----------------------------------------------------------------------------- +#ifndef CLIENT_DLL + void HapticMsg_SendWeaponAnim( CBasePlayer *pPlayer, int iActivity ); + void HapticMsg_SetDrag(CBasePlayer* pPlayer, float drag); + void HapticMsg_SetConstantForce(CBasePlayer* pPlayer, Vector force); + void HapticMsg_HapDmg(CBasePlayer* pPlayer, float pitch, float yaw, float dmg, float dmgType ); + void HapticMsg_Punch(CBasePlayer* pPlayer, float x, float y, float z); + void HapticMsg_MeleeContact(CBasePlayer* pPlayer); +#endif // !CLIENT_DLL + +//----------------------------------------------------------------------------- +// Client +//----------------------------------------------------------------------------- +#ifdef CLIENT_DLL + void HookHapticMessages(void); + + void __MsgFunc_SPHapWeapEvent( bf_read &HapticMsg ); + void __MsgFunc_HapDmg( bf_read &HapticMsg ); + void __MsgFunc_HapSetConst( bf_read &HapticMsg ); + void __MsgFunc_HapPunch( bf_read &HapticMsg ); + void __MsgFunc_HapGeneric( bf_read &HapticMsg ); + void __MsgFunc_HapSetDrag( bf_read &HapticMsg ); + void __MsgFunc_HapSetDrag( bf_read &HapticMsg ); + void __MsgFunc_HapMeleeContact( bf_read &HapticMsg ); +#endif // CLIENT_DLL + +#endif // HAPTIC_MSGS_H diff --git a/public/haptics/haptic_utils.cpp b/public/haptics/haptic_utils.cpp new file mode 100644 index 0000000..b9c72b2 --- /dev/null +++ b/public/haptics/haptic_utils.cpp @@ -0,0 +1,443 @@ +#include "cbase.h" + +#ifdef CLIENT_DLL + #include "tier3/tier3.h" + #include "iviewrender.h" + #include "inputsystem/iinputsystem.h" + #include "vgui/IInputInternal.h" + #include "c_basecombatweapon.h" + #include "c_baseplayer.h" + #include "haptics/ihaptics.h" + #include "hud_macros.h" + #include "iclientvehicle.h" + #include "c_prop_vehicle.h" + #include "prediction.h" + #include "activitylist.h" +#ifdef TERROR + #include "ClientTerrorPlayer.h" +#endif +extern vgui::IInputInternal *g_InputInternal; +#else + #include "usermessages.h" +#endif + +#include "haptics/haptic_utils.h" +#include "haptics/haptic_msgs.h" + +#ifndef TERROR +#ifndef FCVAR_RELEASE +#define FCVAR_RELEASE 0 +#endif +#endif + +#ifdef CLIENT_DLL +ConVar hap_HasDevice ( "hap_HasDevice", "0", FCVAR_USERINFO/*|FCVAR_HIDDEN*/, "falcon is connected" ); +// damage scale on a title basis. Convar referenced in the haptic dll. +#ifdef PORTAL +#define HAP_DEFAULT_DAMAGE_SCALE_GAME "0.75" +#elif TF_CLIENT_DLL +#define HAP_DEFAULT_DAMAGE_SCALE_GAME "0.3" +#else +#define HAP_DEFAULT_DAMAGE_SCALE_GAME "1.0" +#endif +ConVar hap_damagescale_game("hap_damagescale_game", HAP_DEFAULT_DAMAGE_SCALE_GAME); +#undef HAP_DEFAULT_DAMAGE_SCALE_GAME + +#endif + +void HapticSendWeaponAnim(CBaseCombatWeapon* weapon, int iActivity) +{ + //ignore idle + if(iActivity == ACT_VM_IDLE) + return; + + #if defined( CLIENT_DLL ) + //if(hap_PrintEvents.GetBool()) + // Msg("Client Activity :%s %s %s\n",weapon->GetName(),"Activities",VarArgs("%i",iActivity)); + if ( weapon->IsPredicted() ) + haptics->ProcessHapticWeaponActivity(weapon->GetName(),iActivity); + #else + if( !weapon->IsPredicted() && weapon->GetOwner() && weapon->GetOwner()->IsPlayer()) + { + HapticMsg_SendWeaponAnim( ToBasePlayer(weapon->GetOwner()), iActivity ); + } + #endif +} + + +void HapticSetDrag(CBasePlayer* pPlayer, float drag) +{ +#ifdef CLIENT_DLL + haptics->SetDrag(drag); +#else + HapticMsg_SetDrag( pPlayer, drag ); +#endif +} + +#ifdef CLIENT_DLL +void HapticsHandleMsg_HapSetDrag( float drag ) +{ + haptics->SetDrag(drag); +} +#endif + +void HapticSetConstantForce(CBasePlayer* pPlayer, Vector force) +{ +#ifdef CLIENT_DLL + haptics->SetConstantForce(force); +#else + HapticMsg_SetConstantForce( pPlayer, force ); +#endif +} + +#ifdef CLIENT_DLL + +#ifndef HAPTICS_TEST_PREFIX +#define HAPTICS_TEST_PREFIX +#endif +static CSysModule *pFalconModule =0; +void ConnectHaptics(CreateInterfaceFn appFactory) +{ + bool success = false; + // NVNT load haptics module + pFalconModule = Sys_LoadModule( HAPTICS_TEST_PREFIX HAPTICS_DLL_NAME ); + if(pFalconModule) + { + CreateInterfaceFn factory = Sys_GetFactory( pFalconModule ); + if(factory) + { + haptics = reinterpret_cast< IHaptics* >( factory( HAPTICS_INTERFACE_VERSION, NULL ) ); + if(haptics && + haptics->Initialize(engine, + view, + g_InputInternal, + gpGlobals, + appFactory, + g_pVGuiInput->GetIMEWindow(), + filesystem, + enginevgui, + ActivityList_IndexForName, + ActivityList_NameForIndex)) + { + success = true; + hap_HasDevice.SetValue(1); + } + } + } + if(!success) + { + Sys_UnloadModule(pFalconModule); + pFalconModule = 0; + haptics = new CHapticsStubbed; + } + + if(haptics->HasDevice()) + { + Assert( (void*)haptics == inputsystem->GetHapticsInterfaceAddress() ); + } + HookHapticMessages(); +} + +void DisconnectHaptics() +{ + haptics->ShutdownHaptics(); + if(pFalconModule) + { + Sys_UnloadModule(pFalconModule); + pFalconModule = 0; + }else{ + // delete the stub. + delete haptics; + } + haptics = NULL; +} +//Might be able to handle this better... +void HapticsHandleMsg_HapSetConst( Vector const &constant ) +{ + //Msg("__MsgFunc_HapSetConst: %f %f %f\n",constant.x,constant.y,constant.z); + haptics->SetConstantForce(constant); + //C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); +} + + +//Might be able to handle this better... +void HapticsHandleMsg_SPHapWeapEvent( int iActivity ) +{ + C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); + C_BaseCombatWeapon* weap = NULL; + if(pPlayer) + weap = pPlayer->GetActiveWeapon(); + if(weap) + haptics->ProcessHapticEvent(4,"Weapons",weap->GetName(),"Activities",VarArgs("%i",iActivity)); +} + +void HapticsHandleMsg_HapPunch( QAngle const &angle ) +{ + haptics->HapticsPunch(1,angle); + +} +#ifdef TERROR +ConVar hap_zombie_damage_scale("hap_zombie_damage_scale", "0.25", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING); +#endif +void HapticsHandleMsg_HapDmg( float pitch, float yaw, float damage, int damageType ) +{ + if(!haptics->HasDevice()) + return; + +#ifdef TERROR + C_TerrorPlayer *pPlayer = C_TerrorPlayer::GetLocalTerrorPlayer(); +#else + C_BasePlayer *pPlayer = CBasePlayer::GetLocalPlayer(); +#endif + + if(pPlayer) + { + Vector damageDirection; + + damageDirection.x = cos(pitch*M_PI/180.0)*sin(yaw*M_PI/180.0); + damageDirection.y = -sin(pitch*M_PI/180.0); + damageDirection.z = -(cos(pitch*M_PI/180.0)*cos(yaw*M_PI/180.0)); +#ifdef TERROR + if(pPlayer->GetTeamNumber()==TEAM_ZOMBIE) + { + damageDirection *= hap_zombie_damage_scale.GetFloat(); + } +#endif + + haptics->ApplyDamageEffect(damage, damageType, damageDirection); + } +} + +ConVar hap_melee_scale("hap_melee_scale", "0.8", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING); +void HapticsHandleMsg_HapMeleeContact() +{ + haptics->HapticsPunch(hap_melee_scale.GetFloat(), QAngle(0,0,0)); +} +ConVar hap_noclip_avatar_scale("hap_noclip_avatar_scale", "0.10f", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING); +void UpdateAvatarEffect(void) +{ + if(!haptics->HasDevice()) + return; + + Vector vel; + Vector vvel; + Vector evel; + QAngle eye; + C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); + if(!pPlayer) + return; + + eye = pPlayer->GetAbsAngles(); + + if(pPlayer->IsInAVehicle() && pPlayer->GetVehicle()) + { + pPlayer->GetVehicle()->GetVehicleEnt()->EstimateAbsVelocity(vvel); + eye = pPlayer->GetVehicle()->GetVehicleEnt()->EyeAngles(); + + if(!Q_stristr(pPlayer->GetVehicle()->GetVehicleEnt()->GetClassname(),"choreo")) + { + eye[YAW] += 90; + } + + + + } + else + { + vel = pPlayer->GetAbsVelocity(); + } + + Vector PlayerVel = pPlayer->GetAbsVelocity(); + + //Choreo vehicles use player avatar and don't produce their own velocity + if(!pPlayer->GetVehicle() || abs(vvel.Length()) == 0 ) + { + vel = PlayerVel; + } + else + vel = vvel; + + + + VectorYawRotate(vel, -90 -eye[YAW], vel ); + + vel.y = -vel.y; + vel.z = -vel.z; + + switch(pPlayer->GetMoveType()) { + case MOVETYPE_NOCLIP: + vel *= hap_noclip_avatar_scale.GetFloat(); + break; + default: + break; + } + + haptics->UpdateAvatarVelocity(vel); +} + +#endif + + +#ifndef CLIENT_DLL +void HapticsDamage(CBasePlayer* pPlayer, const CTakeDamageInfo &info) +{ +#if !defined(TF_DLL) && !defined(CSTRIKE_DLL) + if(!pPlayer->HasHaptics()) + return;// do not send to non haptic users. + + Vector DamageDirection(0,0,0); + CBaseEntity *eInflictor = info.GetInflictor(); + // Pat: nuero toxix crash fix + if(!eInflictor) { + return; + } + // Player Data + Vector playerPosition = pPlayer->GetLocalOrigin(); + Vector inflictorPosition = eInflictor->GetLocalOrigin(); + + Vector posWithDir = playerPosition + (playerPosition - inflictorPosition); + pPlayer->WorldToEntitySpace(posWithDir, &DamageDirection); + QAngle dir(0,0,0); + VectorAngles(DamageDirection, dir); + float yawAngle = dir[YAW]; + float pitchAngle = dir[PITCH]; + + int bitDamageType = info.GetDamageType(); + + if(bitDamageType & DMG_FALL) + { + pitchAngle = ((float)-90.0); // coming from beneath + } + else if(bitDamageType & DMG_BURN && (bitDamageType & ~DMG_BURN)==0) + { + // just burn, use the z axis here. + pitchAngle = 0.0; + } +#ifdef TERROR + else if( + (bitDamageType & ( DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN ) ) && + (bitDamageType & ~( DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN ) )==0 ) + { + // it is time based. and should not really do a punch. + return; + } +#endif + + float sendDamage = info.GetDamage(); + + if(sendDamage>0.0f) + { + HapticMsg_HapDmg( pPlayer, pitchAngle, -yawAngle, sendDamage, bitDamageType ); + } +#endif +} + +void HapticPunch(CBasePlayer* pPlayer, float x, float y, float z) +{ + HapticMsg_Punch( pPlayer, x, y, z ); +} + +void HapticMeleeContact(CBasePlayer* pPlayer) +{ + HapticMsg_MeleeContact( pPlayer ); +} + + + +#endif // NOT CLIENT_DLL + +void HapticProcessSound(const char* soundname, int entIndex) +{ +#ifdef CLIENT_DLL + if (prediction->InPrediction() && prediction->IsFirstTimePredicted()) + { + bool local = false; + C_BaseEntity *ent = C_BaseEntity::Instance( entIndex ); + if(ent) + local = (entIndex == -1 || ent == C_BasePlayer::GetLocalPlayer() || ent == C_BasePlayer::GetLocalPlayer()->GetActiveWeapon()); + + haptics->ProcessHapticEvent(2,"Sounds",soundname); + } +#endif +} + +#ifdef CLIENT_DLL + +// NVNT add || defined(OTHER_DEFINITION) if your game uses vehicles. +#if defined( HL2_CLIENT_DLL ) +#define HAPTIC_VEHICLE_DEFAULT "1" +#else +#define HAPTIC_VEHICLE_DEFAULT "0" +#endif + +// determines weather the vehicles control box option is faded +ConVar hap_ui_vehicles( "hap_ui_vehicles", + HAPTIC_VEHICLE_DEFAULT, + 0 + ); + +#undef HAPTIC_VEHICLE_DEFAULT + +void HapticsEnteredVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger ) +{ + if(!vehicle) + return; + + // NVNT notify haptics system of navigation change. + + C_PropVehicleDriveable* drivable = dynamic_cast(vehicle); + bool hasgun = false; + if(drivable) + hasgun = drivable->HasGun(); + + + + + + if(Q_stristr(vehicle->GetClassname(),"airboat")) + { + haptics->ProcessHapticEvent(2,"Movement","airboat"); + if(hasgun) + haptics->SetNavigationClass("vehicle_gun"); + else + haptics->SetNavigationClass("vehicle_airboat"); + } + else if(Q_stristr(vehicle->GetClassname(),"jeepepisodic")) + { + haptics->ProcessHapticEvent(2,"Movement","BaseVehicle"); + haptics->SetNavigationClass("vehicle_nogun"); + } + else if(Q_stristr(vehicle->GetClassname(),"jeep")) + { + haptics->ProcessHapticEvent(2,"Movement","BaseVehicle"); + haptics->SetNavigationClass("vehicle_gun"); + } + else if(Q_stristr(vehicle->GetClassname(),"choreo")) + { + haptics->ProcessHapticEvent(2,"Movement","ChoreoVehicle"); + haptics->SetNavigationClass("vehicle_gun_nofix");//Give this a bit of aiming + } + else + { + haptics->ProcessHapticEvent(2,"Movement","BaseVehicle"); + haptics->SetNavigationClass("vehicle_nogun"); + } + + Msg("VehicleType:%s:\n",vehicle->GetClassname()); +} + +void HapticsExitedVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger ) +{ + // NVNT notify haptics system of navigation change. + haptics->SetNavigationClass("on_foot"); + haptics->ProcessHapticEvent(2,"Movement","BasePlayer"); +} +#endif + + + + + + + + diff --git a/public/haptics/haptic_utils.h b/public/haptics/haptic_utils.h new file mode 100644 index 0000000..18a05ab --- /dev/null +++ b/public/haptics/haptic_utils.h @@ -0,0 +1,104 @@ +#ifndef HAPTIC_UTILS_H +#define HAPTIC_UTILS_H + + +#ifdef CLIENT_DLL + +#include "haptics/ihaptics.h" + +// forward decl. +class C_BaseEntity; +class C_BaseCombatCharacter; +class C_BasePlayer; +class bf_read; + +// use client side versions. +#ifndef CBasePlayer +#define CBasePlayer C_BasePlayer; +#endif +#ifndef CBaseCombatWeapon +#define CBaseCombatWeapon C_BaseCombatWeapon +#endif + +// stubbed version of haptics interface. Used when haptics is not available. +class CHapticsStubbed : public IHaptics +{ +public: +public: // Initialization. + virtual bool Initialize(IVEngineClient* newengine, + IViewRender *newview, + vgui::IInputInternal* newinput, + CGlobalVarsBase* newgpGlobals, + CreateInterfaceFn newengineFactory, + void *IMEWindow, + IFileSystem* filesystem, + IEngineVGui* newvgui, + ActivityList_IndexForName_t actIndexForName, + ActivityList_NameForIndex_t actNameForIndex) + {return false;}; + +public: // Device methods + virtual bool HasDevice(){return false;}; + virtual void ShutdownHaptics(){}; + +public: // Game input handling + virtual void CalculateMove(float &forward_move, float &side_move, float delta){}; + virtual void OnPlayerChanged(){} + virtual void SetNavigationClass(const char *defaultNavigationName){}; + virtual const char *GetNavigationClass(){ return 0; }; + virtual void GameProcess(){} + virtual void MenuProcess(){} + +public: // Effect methods + virtual void ProcessHapticEvent(int numArgs, ...){} + virtual void ProcessHapticWeaponActivity(const char *weapon, int activity){} + virtual void HapticsPunch(float strength, const QAngle &angle){} + virtual void ApplyDamageEffect(float damage, int damagetype, const Vector &angle){} + virtual void UpdateAvatarVelocity(const Vector &vel){} + virtual void RemoveAvatarEffect(){} + virtual void SetConstantForce(const Vector &force){} + virtual Vector GetConstantForce(){return Vector(0,0,0);} + virtual void SetDrag(float amount){} + virtual void SetShake(float scalar, float currentamount){} + virtual void SetHeld(float amount){} + virtual void SetMoveSurface(HapticSurfaceType_t surface){} + virtual HapticSurfaceType_t GetMoveSurface(){ return HST_NONE; } + virtual void SetDangling(float amount){}; + +public: // Notify methods + virtual void LocalPlayerReset(){}; + virtual void UpdatePlayerFOV(float fov){}; + virtual void WorldPrecache() {}; +}; +#else +// forward decl. +class CBasePlayer; +class CBaseCombatWeapon; +class CTakeDamageInfo; + +#endif // CLIENT_DLL + +void HapticSendWeaponAnim(class CBaseCombatWeapon* weapon, int iActivity); +void HapticSetConstantForce(class CBasePlayer* pPlayer,Vector force); +void HapticSetDrag(class CBasePlayer* pPlayer, float drag); + +// note: does nothing on server. +void HapticProcessSound(const char* soundname, int entIndex); + +#ifdef CLIENT_DLL + void ConnectHaptics(CreateInterfaceFn appFactory); + void DisconnectHaptics(); + + void UpdateAvatarEffect(void); + void HapticsExitedVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger ); + void HapticsEnteredVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger ); + + //bool value true if user is using a haptic device. + extern ConVar hap_HasDevice; +#else + void HapticsDamage(CBasePlayer* pPlayer, const CTakeDamageInfo &info); + void HapticPunch(CBasePlayer* pPlayer, float amount, float x, float y); + void HapticMeleeContact(CBasePlayer* pPlayer); +#endif + +#endif \ No newline at end of file diff --git a/public/haptics/ihaptics.h b/public/haptics/ihaptics.h new file mode 100644 index 0000000..d99017b --- /dev/null +++ b/public/haptics/ihaptics.h @@ -0,0 +1,144 @@ +#ifndef HAPTICS_INTERFACE_H +#define HAPTICS_INTERFACE_H + +#ifdef GAME_DLL +#pragma warning("IHaptics.h is only for client ussage"); +#endif + +#include "tier0/platform.h" +#include "appframework/IAppSystem.h" + +#define HAPTICS_INTERFACE_VERSION "HapticsInterface001" +#define HAPTICS_DLL_NAME "haptics" + +// systems forward decl. +class IVEngineClient; +class IViewRender; +class IInputInternal; +class CGlobalVarsBase; +class IFileSystem; +class IEngineVGui; + +// vgui forward decl +namespace vgui{ + class IInputInternal; +} + +// math types forward decl +class QAngle; +class Vector; + +typedef enum { + HST_NONE = 0, + HST_ROPE, +} HapticSurfaceType_t; + +typedef int (*ActivityList_IndexForName_t)( const char *pszActivityName ); +typedef const char *(*ActivityList_NameForIndex_t)( int iActivityIndex ); +// NVNT haptic system interface declaration +abstract_class IHaptics +{ +public: // Initialization. + virtual bool Initialize(IVEngineClient* newengine, + IViewRender *newview, + vgui::IInputInternal* newinput, + CGlobalVarsBase* newgpGlobals, + CreateInterfaceFn newengineFactory, + void *IMEWindow, + IFileSystem* filesystem, + IEngineVGui* newvgui, + ActivityList_IndexForName_t actIndexForName, + ActivityList_NameForIndex_t actNameForIndex) = 0; + +public: // Device methods + + // returns true if there is at least one device connected. + virtual bool HasDevice() = 0; + + // closes all haptic devices and effect processing + virtual void ShutdownHaptics() = 0; + +public: // Game input handling + + // computes view angles and adjusts forward_move and side_move + virtual void CalculateMove(float &forward_move, float &side_move, float delta) = 0; + + virtual void OnPlayerChanged()=0; + + // Sets the internal navigation class. + virtual void SetNavigationClass(const char *defaultNavigationName) = 0; + + // Turns the internal navigation off. ( clears navigation class ) + inline void ClearNavigationClass(); + + // Returns the active navigation class ( if none returns NULL ) + virtual const char *GetNavigationClass() = 0; + + // Should be called by the game input class after CalculateMove (when not in menu) + virtual void GameProcess() = 0; + + // Should be called by the game input class when in a menu + virtual void MenuProcess() = 0; + + +public: // Effect methods + + // process a haptic event. + virtual void ProcessHapticEvent(int numArgs, ...) = 0; + virtual void ProcessHapticWeaponActivity(const char *weapon, int activity) = 0; + + // send a haptic punch effect + virtual void HapticsPunch(float strength, const QAngle &angle) = 0; + + // trigger a damage effect + virtual void ApplyDamageEffect(float damage, int damagetype, const Vector &angle) = 0; + + // update the avatar ( acceleration ) effect by a velocity sample + virtual void UpdateAvatarVelocity(const Vector &velocity) = 0; + + // stop processing any running avatar effects + virtual void RemoveAvatarEffect() = 0; + + // sets the device's constant force effect to force vector + virtual void SetConstantForce(const Vector &force) = 0; + + // returns the last sent constant force + virtual Vector GetConstantForce() = 0; + + // set the amount of drag (viscosity) on the haptic devices + virtual void SetDrag(float amount) = 0; + + // set the values to the screen shake effect + virtual void SetShake(float scalar, float currentamount) = 0; + + // enable/disable device position lock. + virtual void SetHeld(float amount) = 0; + + // set anchor weight mass scaler. + virtual void SetMoveSurface(HapticSurfaceType_t surface) = 0; + + virtual HapticSurfaceType_t GetMoveSurface() = 0; + + // set dangling ( being hung, holding onto ledges ) + virtual void SetDangling(float amount) = 0; + +public: // Notify methods + + // notify the haptics system that we have been respawned. + virtual void LocalPlayerReset()=0; + + // notify the haptics system of the player's field of view angle + virtual void UpdatePlayerFOV(float fov)=0; + + virtual void WorldPrecache() = 0; + +}; + +inline void IHaptics::ClearNavigationClass( void ) +{ + SetNavigationClass(0); +} + +extern IHaptics* haptics; + +#endif// HAPTICS_INTERFACE_H \ No newline at end of file diff --git a/public/iachievementmgr.h b/public/iachievementmgr.h new file mode 100644 index 0000000..303eea4 --- /dev/null +++ b/public/iachievementmgr.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef IACHIEVEMENTMGR_H +#define IACHIEVEMENTMGR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmap.h" +#include "vgui_controls/Panel.h" + +class CBaseAchievement; + +abstract_class IAchievement +{ +public: + virtual int GetAchievementID() = 0; + virtual const char *GetName() = 0; + virtual int GetFlags() = 0; + virtual int GetGoal() = 0; + virtual int GetCount() = 0; + virtual bool IsAchieved() = 0; + virtual int GetPointValue() = 0; + virtual bool ShouldSaveWithGame() = 0; + virtual bool ShouldHideUntilAchieved() = 0; + virtual bool ShouldShowOnHUD() = 0; + virtual void SetShowOnHUD( bool bShow ) = 0; +}; + + +abstract_class IAchievementMgr +{ +public: + virtual IAchievement* GetAchievementByIndex( int index ) = 0; + virtual CBaseAchievement* GetAchievementByID ( int id ) = 0; + virtual int GetAchievementCount() = 0; + virtual void InitializeAchievements() = 0; + virtual void AwardAchievement( int iAchievementID ) = 0; + virtual void OnMapEvent( const char *pchEventName ) = 0; + virtual void DownloadUserData() = 0; + virtual void EnsureGlobalStateLoaded() = 0; + virtual void SaveGlobalStateIfDirty( bool bAsync ) = 0; + virtual bool HasAchieved( const char *pchName ) = 0; + virtual bool WereCheatsEverOn() = 0; +}; + +// flags for IAchievement::GetFlags + +#define ACH_LISTEN_KILL_EVENTS 0x0001 +#define ACH_LISTEN_MAP_EVENTS 0x0002 +#define ACH_LISTEN_COMPONENT_EVENTS 0x0004 +#define ACH_HAS_COMPONENTS 0x0020 +#define ACH_SAVE_WITH_GAME 0x0040 +#define ACH_SAVE_GLOBAL 0x0080 +#define ACH_FILTER_ATTACKER_IS_PLAYER 0x0100 +#define ACH_FILTER_VICTIM_IS_PLAYER_ENEMY 0x0200 +#define ACH_FILTER_FULL_ROUND_ONLY 0x0400 + +#define ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS ACH_LISTEN_KILL_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_FILTER_VICTIM_IS_PLAYER_ENEMY +#define ACH_LISTEN_KILL_ENEMY_EVENTS ACH_LISTEN_KILL_EVENTS | ACH_FILTER_VICTIM_IS_PLAYER_ENEMY + +// Update this for changes in either abstract class in this file +#define ACHIEVEMENTMGR_INTERFACE_VERSION "ACHIEVEMENTMGR_INTERFACE_VERSION001" + +#define ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( name ) \ + ( g_pVGuiLocalize->Find( CFmtStr( "#%s_NAME", name ) ) ) + +#define ACHIEVEMENT_LOCALIZED_NAME( pAchievement ) \ + ( ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pAchievement->GetName() ) ) + +#define ACHIEVEMENT_LOCALIZED_DESC_FROM_STR( name ) \ + ( g_pVGuiLocalize->Find( CFmtStr( "#%s_DESC", name ) ) ) + +#define ACHIEVEMENT_LOCALIZED_DESC( pAchievement ) \ + ( ACHIEVEMENT_LOCALIZED_DESC_FROM_STR( pAchievement->GetName() ) ) + +#endif // IACHIEVEMENTMGR_H diff --git a/public/ibsppack.h b/public/ibsppack.h new file mode 100644 index 0000000..3f115d7 --- /dev/null +++ b/public/ibsppack.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IBSPPACK_H +#define IBSPPACK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "utlvector.h" +#include "utlstring.h" + +class IFileSystem; + +abstract_class IBSPPack +{ +public: + virtual void LoadBSPFile( IFileSystem *pFileSystem, char *filename ) = 0; + virtual void WriteBSPFile( char *filename ) = 0; + virtual void ClearPackFile( void ) = 0; + virtual void AddFileToPack( const char *relativename, const char *fullpath ) = 0; + virtual void AddBufferToPack( const char *relativename, void *data, int length, bool bTextMode ) = 0; + virtual void SetHDRMode( bool bHDR ) = 0; + virtual bool SwapBSPFile( IFileSystem *pFileSystem, const char *filename, const char *swapFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc ) = 0; + + enum eRepackBSPFlags + { + eRepackBSP_CompressLumps = 1 << 0, + eRepackBSP_CompressPackfile = 1 << 1 + }; + virtual bool RepackBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, eRepackBSPFlags repackFlags ) = 0; + + // used to get/set the pak file from a BSP + virtual bool GetPakFileLump( IFileSystem *pFileSystem, const char *pBSPFilename, void **pPakData, int *pPakSize ) = 0; + virtual bool SetPakFileLump( IFileSystem *pFileSystem, const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize ) = 0; + + // populates list of files that bsp owns, i.e. world/cubmap materials, statis props, etc + virtual bool GetBSPDependants( IFileSystem *pFileSystem, const char *pBSPFilename, CUtlVector< CUtlString > *pList ) = 0; +}; + +#define IBSPPACK_VERSION_STRING "IBSPPACK004" + +#endif // IBSPPACK_H diff --git a/public/iclient.h b/public/iclient.h new file mode 100644 index 0000000..2ba39e2 --- /dev/null +++ b/public/iclient.h @@ -0,0 +1,92 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ICLIENT_H +#define ICLIENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier0/platform.h" +#include "userid.h" + +class IServer; +class INetMessage; + +abstract_class IClient : public INetChannelHandler +{ +public: + virtual ~IClient() {} + + // connect client + virtual void Connect(const char * szName, int nUserID, INetChannel *pNetChannel, bool bFakePlayer, int clientChallenge ) = 0; + + // set the client in a pending state waiting for a new game + virtual void Inactivate( void ) = 0; + + // Reconnect without dropiing the netchannel + virtual void Reconnect( void ) = 0; // froce reconnect + + // disconnects a client with a given reason + virtual void Disconnect( PRINTF_FORMAT_STRING const char *reason, ... ) = 0; + + virtual int GetPlayerSlot() const = 0; // returns client slot (usually entity number-1) + virtual int GetUserID() const = 0; // unique ID on this server + virtual const USERID_t GetNetworkID() const = 0; // network wide ID + virtual const char *GetClientName() const = 0; // returns client name + virtual INetChannel *GetNetChannel() = 0; // returns client netchannel + virtual IServer *GetServer() = 0; // returns the object server the client belongs to + virtual const char *GetUserSetting(const char *cvar) const = 0; // returns a clients FCVAR_USERINFO setting + virtual const char *GetNetworkIDString() const = 0; // returns a human readable representation of the network id + + // set/get client data rate in bytes/second + virtual void SetRate( int nRate, bool bForce ) = 0; + virtual int GetRate( void ) const = 0; + + // set/get updates/second rate + virtual void SetUpdateRate( int nUpdateRate, bool bForce ) = 0; + virtual int GetUpdateRate( void ) const = 0; + + // clear complete object & free all memory + virtual void Clear( void ) = 0; + + // returns the highest world tick number acknowledge by client + virtual int GetMaxAckTickCount() const = 0; + + // execute a client command + virtual bool ExecuteStringCommand( const char *s ) = 0; + // send client a network message + virtual bool SendNetMsg(INetMessage &msg, bool bForceReliable = false) = 0; + // send client a text message + virtual void ClientPrintf (PRINTF_FORMAT_STRING const char *fmt, ...) = 0; + + // client has established network channels, nothing else + virtual bool IsConnected( void ) const = 0; + // client is downloading signon data + virtual bool IsSpawned( void ) const = 0; + // client active is ingame, receiving snapshots + virtual bool IsActive( void ) const = 0; + // returns true, if client is not a real player + virtual bool IsFakeClient( void ) const = 0; + // returns true, if client is a HLTV proxy + virtual bool IsHLTV( void ) const = 0; +#if defined( REPLAY_ENABLED ) + // returns true, if client is a Replay proxy + virtual bool IsReplay( void ) const = 0; +#else + // !KLUDGE! Reduce number of #ifdefs required + inline bool IsReplay( void ) const { return false; } +#endif + // returns true, if client hears this player + virtual bool IsHearingClient(int index) const = 0; + // returns true, if client hears this player by proximity + virtual bool IsProximityHearingClient(int index) const = 0; + + virtual void SetMaxRoutablePayloadSize( int nMaxRoutablePayloadSize ) = 0; +}; + +#endif // ICLIENT_H diff --git a/public/icliententity.h b/public/icliententity.h new file mode 100644 index 0000000..213381f --- /dev/null +++ b/public/icliententity.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLIENTENTITY_H +#define ICLIENTENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iclientrenderable.h" +#include "iclientnetworkable.h" +#include "iclientthinkable.h" + +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +class CMouthInfo; +class IClientEntityInternal; +struct SpatializationInfo_t; + + +//----------------------------------------------------------------------------- +// Purpose: All client entities must implement this interface. +//----------------------------------------------------------------------------- +abstract_class IClientEntity : public IClientUnknown, public IClientRenderable, public IClientNetworkable, public IClientThinkable +{ +public: + // Delete yourself. + virtual void Release( void ) = 0; + + // Network origin + angles + virtual const Vector& GetAbsOrigin( void ) const = 0; + virtual const QAngle& GetAbsAngles( void ) const = 0; + + virtual CMouthInfo *GetMouth( void ) = 0; + + // Retrieve sound spatialization info for the specified sound on this entity + // Return false to indicate sound is not audible + virtual bool GetSoundSpatialization( SpatializationInfo_t& info ) = 0; +}; + + +#endif // ICLIENTENTITY_H diff --git a/public/icliententitylist.h b/public/icliententitylist.h new file mode 100644 index 0000000..1e0e258 --- /dev/null +++ b/public/icliententitylist.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( ICLIENTENTITYLIST_H ) +#define ICLIENTENTITYLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +class IClientEntity; +class ClientClass; +class IClientNetworkable; +class CBaseHandle; +class IClientUnknown; + + +//----------------------------------------------------------------------------- +// Purpose: Exposes IClientEntity's to engine +//----------------------------------------------------------------------------- +abstract_class IClientEntityList +{ +public: + // Get IClientNetworkable interface for specified entity + virtual IClientNetworkable* GetClientNetworkable( int entnum ) = 0; + virtual IClientNetworkable* GetClientNetworkableFromHandle( CBaseHandle hEnt ) = 0; + virtual IClientUnknown* GetClientUnknownFromHandle( CBaseHandle hEnt ) = 0; + + // NOTE: This function is only a convenience wrapper. + // It returns GetClientNetworkable( entnum )->GetIClientEntity(). + virtual IClientEntity* GetClientEntity( int entnum ) = 0; + virtual IClientEntity* GetClientEntityFromHandle( CBaseHandle hEnt ) = 0; + + // Returns number of entities currently in use + virtual int NumberOfEntities( bool bIncludeNonNetworkable ) = 0; + + // Returns highest index actually used + virtual int GetHighestEntityIndex( void ) = 0; + + // Sizes entity list to specified size + virtual void SetMaxEntities( int maxents ) = 0; + virtual int GetMaxEntities( ) = 0; +}; + +extern IClientEntityList *entitylist; + +#define VCLIENTENTITYLIST_INTERFACE_VERSION "VClientEntityList003" + +#endif // ICLIENTENTITYLIST_H diff --git a/public/iclientnetworkable.h b/public/iclientnetworkable.h new file mode 100644 index 0000000..6ecb362 --- /dev/null +++ b/public/iclientnetworkable.h @@ -0,0 +1,107 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLIENTNETWORKABLE_H +#define ICLIENTNETWORKABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iclientunknown.h" +#include "tier1/bitbuf.h" + + +class IClientEntity; +class ClientClass; + + +enum ShouldTransmitState_t +{ + SHOULDTRANSMIT_START=0, // The entity is starting to be transmitted (maybe it entered the PVS). + + SHOULDTRANSMIT_END // Called when the entity isn't being transmitted by the server. + // This signals a good time to hide the entity until next time + // the server wants to transmit its state. +}; + +// NOTE: All of these are commented out; NotifyShouldTransmit actually +// has all these in them. Left it as an enum in case we want to go back though +enum DataUpdateType_t +{ + DATA_UPDATE_CREATED = 0, // indicates it was created +and+ entered the pvs +// DATA_UPDATE_ENTERED_PVS, + DATA_UPDATE_DATATABLE_CHANGED, +// DATA_UPDATE_LEFT_PVS, +// DATA_UPDATE_DESTROYED, // FIXME: Could enable this, but it's a little worrying + // since it changes a bunch of existing code +}; + +abstract_class IClientNetworkable +{ +public: + // Gets at the containing class... + virtual IClientUnknown* GetIClientUnknown() = 0; + + // Called by the engine when the server deletes the entity. + virtual void Release() = 0; + + // Supplied automatically by the IMPLEMENT_CLIENTCLASS macros. + virtual ClientClass* GetClientClass() = 0; + + // This tells the entity what the server says for ShouldTransmit on this entity. + // Note: This used to be EntityEnteredPVS/EntityRemainedInPVS/EntityLeftPVS. + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ) = 0; + + + + // + // NOTE FOR ENTITY WRITERS: + // + // In 90% of the cases, you should hook OnPreDataChanged/OnDataChanged instead of + // PreDataUpdate/PostDataUpdate. + // + // The DataChanged events are only called once per frame whereas Pre/PostDataUpdate + // are called once per packet (and sometimes multiple times per frame). + // + // OnDataChanged is called during simulation where entity origins are correct and + // attachments can be used. whereas PostDataUpdate is called while parsing packets + // so attachments and other entity origins may not be valid yet. + // + + virtual void OnPreDataChanged( DataUpdateType_t updateType ) = 0; + virtual void OnDataChanged( DataUpdateType_t updateType ) = 0; + + // Called when data is being updated across the network. + // Only low-level entities should need to know about these. + virtual void PreDataUpdate( DataUpdateType_t updateType ) = 0; + virtual void PostDataUpdate( DataUpdateType_t updateType ) = 0; + + + // Objects become dormant on the client if they leave the PVS on the server. + virtual bool IsDormant( void ) = 0; + + // Ent Index is the server handle used to reference this entity. + // If the index is < 0, that indicates the entity is not known to the server + virtual int entindex( void ) const = 0; + + // Server to client entity message received + virtual void ReceiveMessage( int classID, bf_read &msg ) = 0; + + // Get the base pointer to the networked data that GetClientClass->m_pRecvTable starts at. + // (This is usually just the "this" pointer). + virtual void* GetDataTableBasePtr() = 0; + + // Tells the entity that it's about to be destroyed due to the client receiving + // an uncompressed update that's caused it to destroy all entities & recreate them. + virtual void SetDestroyedOnRecreateEntities( void ) = 0; + + virtual void OnDataUnchangedInPVS() = 0; +}; + + +#endif // ICLIENTNETWORKABLE_H diff --git a/public/iclientrenderable.h b/public/iclientrenderable.h new file mode 100644 index 0000000..77ce8f2 --- /dev/null +++ b/public/iclientrenderable.h @@ -0,0 +1,282 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ICLIENTRENDERABLE_H +#define ICLIENTRENDERABLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/mathlib.h" +#include "interface.h" +#include "iclientunknown.h" +#include "client_render_handle.h" +#include "engine/ivmodelrender.h" + +struct model_t; +struct matrix3x4_t; + +extern void DefaultRenderBoundsWorldspace( IClientRenderable *pRenderable, Vector &absMins, Vector &absMaxs ); + +//----------------------------------------------------------------------------- +// Handles to a client shadow +//----------------------------------------------------------------------------- +typedef unsigned short ClientShadowHandle_t; + +enum +{ + CLIENTSHADOW_INVALID_HANDLE = (ClientShadowHandle_t)~0 +}; + +//----------------------------------------------------------------------------- +// What kind of shadows to render? +//----------------------------------------------------------------------------- +enum ShadowType_t +{ + SHADOWS_NONE = 0, + SHADOWS_SIMPLE, + SHADOWS_RENDER_TO_TEXTURE, + SHADOWS_RENDER_TO_TEXTURE_DYNAMIC, // the shadow is always changing state + SHADOWS_RENDER_TO_DEPTH_TEXTURE, +}; + + +// This provides a way for entities to know when they've entered or left the PVS. +// Normally, server entities can use NotifyShouldTransmit to get this info, but client-only +// entities can use this. Store a CPVSNotifyInfo in your +// +// When bInPVS=true, it's being called DURING rendering. It might be after rendering any +// number of views. +// +// If no views had the entity, then it is called with bInPVS=false after rendering. +abstract_class IPVSNotify +{ +public: + virtual void OnPVSStatusChanged( bool bInPVS ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: All client entities must implement this interface. +//----------------------------------------------------------------------------- +abstract_class IClientRenderable +{ +public: + // Gets at the containing class... + virtual IClientUnknown* GetIClientUnknown() = 0; + + // Data accessors + virtual Vector const& GetRenderOrigin( void ) = 0; + virtual QAngle const& GetRenderAngles( void ) = 0; + virtual bool ShouldDraw( void ) = 0; + virtual bool IsTransparent( void ) = 0; + virtual bool UsesPowerOfTwoFrameBufferTexture() = 0; + virtual bool UsesFullFrameBufferTexture() = 0; + + virtual ClientShadowHandle_t GetShadowHandle() const = 0; + + // Used by the leaf system to store its render handle. + virtual ClientRenderHandle_t& RenderHandle() = 0; + + // Render baby! + virtual const model_t* GetModel( ) const = 0; + virtual int DrawModel( int flags ) = 0; + + // Get the body parameter + virtual int GetBody() = 0; + + // Determine alpha and blend amount for transparent objects based on render state info + virtual void ComputeFxBlend( ) = 0; + virtual int GetFxBlend( void ) = 0; + + // Determine the color modulation amount + virtual void GetColorModulation( float* color ) = 0; + + // Returns false if the entity shouldn't be drawn due to LOD. + // (NOTE: This is no longer used/supported, but kept in the vtable for backwards compat) + virtual bool LODTest() = 0; + + // Call this to get the current bone transforms for the model. + // currentTime parameter will affect interpolation + // nMaxBones specifies how many matrices pBoneToWorldOut can hold. (Should be greater than or + // equal to studiohdr_t::numbones. Use MAXSTUDIOBONES to be safe.) + virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) = 0; + + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) = 0; + virtual void DoAnimationEvents( void ) = 0; + + // Return this if you want PVS notifications. See IPVSNotify for more info. + // Note: you must always return the same value from this function. If you don't, + // undefined things will occur, and they won't be good. + virtual IPVSNotify* GetPVSNotifyInterface() = 0; + + // Returns the bounds relative to the origin (render bounds) + virtual void GetRenderBounds( Vector& mins, Vector& maxs ) = 0; + + // returns the bounds as an AABB in worldspace + virtual void GetRenderBoundsWorldspace( Vector& mins, Vector& maxs ) = 0; + + // These normally call through to GetRenderAngles/GetRenderBounds, but some entities custom implement them. + virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType ) = 0; + + // Should this object be able to have shadows cast onto it? + virtual bool ShouldReceiveProjectedTextures( int flags ) = 0; + + // These methods return true if we want a per-renderable shadow cast direction + distance + virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const = 0; + virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const = 0; + + // Other methods related to shadow rendering + virtual bool IsShadowDirty( ) = 0; + virtual void MarkShadowDirty( bool bDirty ) = 0; + + // Iteration over shadow hierarchy + virtual IClientRenderable *GetShadowParent() = 0; + virtual IClientRenderable *FirstShadowChild() = 0; + virtual IClientRenderable *NextShadowPeer() = 0; + + // Returns the shadow cast type + virtual ShadowType_t ShadowCastType() = 0; + + // Create/get/destroy model instance + virtual void CreateModelInstance() = 0; + virtual ModelInstanceHandle_t GetModelInstance() = 0; + + // Returns the transform from RenderOrigin/RenderAngles to world + virtual const matrix3x4_t &RenderableToWorldTransform() = 0; + + // Attachments + virtual int LookupAttachment( const char *pAttachmentName ) = 0; + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ) = 0; + virtual bool GetAttachment( int number, matrix3x4_t &matrix ) = 0; + + // Rendering clip plane, should be 4 floats, return value of NULL indicates a disabled render clip plane + virtual float *GetRenderClipPlane( void ) = 0; + + // Get the skin parameter + virtual int GetSkin() = 0; + + // Is this a two-pass renderable? + virtual bool IsTwoPass( void ) = 0; + + virtual void OnThreadedDrawSetup() = 0; + + virtual bool UsesFlexDelayedWeights() = 0; + + virtual void RecordToolMessage() = 0; + + virtual bool IgnoresZBuffer( void ) const = 0; +}; + + +// This class can be used to implement default versions of some of the +// functions of IClientRenderable. +abstract_class CDefaultClientRenderable : public IClientUnknown, public IClientRenderable +{ +public: + CDefaultClientRenderable() + { + m_hRenderHandle = INVALID_CLIENT_RENDER_HANDLE; + } + + virtual const Vector & GetRenderOrigin( void ) = 0; + virtual const QAngle & GetRenderAngles( void ) = 0; + virtual const matrix3x4_t & RenderableToWorldTransform() = 0; + virtual bool ShouldDraw( void ) = 0; + virtual bool IsTransparent( void ) = 0; + virtual bool IsTwoPass( void ) { return false; } + virtual void OnThreadedDrawSetup() {} + virtual bool UsesPowerOfTwoFrameBufferTexture( void ) { return false; } + virtual bool UsesFullFrameBufferTexture( void ) { return false; } + + virtual ClientShadowHandle_t GetShadowHandle() const + { + return CLIENTSHADOW_INVALID_HANDLE; + } + + virtual ClientRenderHandle_t& RenderHandle() + { + return m_hRenderHandle; + } + + virtual int GetBody() { return 0; } + virtual int GetSkin() { return 0; } + virtual bool UsesFlexDelayedWeights() { return false; } + + virtual const model_t* GetModel( ) const { return NULL; } + virtual int DrawModel( int flags ) { return 0; } + virtual void ComputeFxBlend( ) { return; } + virtual int GetFxBlend( ) { return 255; } + virtual bool LODTest() { return true; } + virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { return true; } + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) {} + virtual void DoAnimationEvents( void ) {} + virtual IPVSNotify* GetPVSNotifyInterface() { return NULL; } + virtual void GetRenderBoundsWorldspace( Vector& absMins, Vector& absMaxs ) { DefaultRenderBoundsWorldspace( this, absMins, absMaxs ); } + + // Determine the color modulation amount + virtual void GetColorModulation( float* color ) + { + Assert(color); + color[0] = color[1] = color[2] = 1.0f; + } + + // Should this object be able to have shadows cast onto it? + virtual bool ShouldReceiveProjectedTextures( int flags ) + { + return false; + } + + // These methods return true if we want a per-renderable shadow cast direction + distance + virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const { return false; } + virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const { return false; } + + virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType ) + { + GetRenderBounds( mins, maxs ); + } + + virtual bool IsShadowDirty( ) { return false; } + virtual void MarkShadowDirty( bool bDirty ) {} + virtual IClientRenderable *GetShadowParent() { return NULL; } + virtual IClientRenderable *FirstShadowChild(){ return NULL; } + virtual IClientRenderable *NextShadowPeer() { return NULL; } + virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } + virtual void CreateModelInstance() {} + virtual ModelInstanceHandle_t GetModelInstance() { return MODEL_INSTANCE_INVALID; } + + // Attachments + virtual int LookupAttachment( const char *pAttachmentName ) { return -1; } + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ) { return false; } + virtual bool GetAttachment( int number, matrix3x4_t &matrix ) { return false; } + + // Rendering clip plane, should be 4 floats, return value of NULL indicates a disabled render clip plane + virtual float *GetRenderClipPlane() { return NULL; } + + virtual void RecordToolMessage() {} + virtual bool IgnoresZBuffer( void ) const { return false; } + +// IClientUnknown implementation. +public: + virtual void SetRefEHandle( const CBaseHandle &handle ) { Assert( false ); } + virtual const CBaseHandle& GetRefEHandle() const { Assert( false ); return *((CBaseHandle*)0); } + + virtual IClientUnknown* GetIClientUnknown() { return this; } + virtual ICollideable* GetCollideable() { return 0; } + virtual IClientRenderable* GetClientRenderable() { return this; } + virtual IClientNetworkable* GetClientNetworkable() { return 0; } + virtual IClientEntity* GetIClientEntity() { return 0; } + virtual C_BaseEntity* GetBaseEntity() { return 0; } + virtual IClientThinkable* GetClientThinkable() { return 0; } + + +public: + ClientRenderHandle_t m_hRenderHandle; +}; + + +#endif // ICLIENTRENDERABLE_H diff --git a/public/iclientthinkable.h b/public/iclientthinkable.h new file mode 100644 index 0000000..4adc8bb --- /dev/null +++ b/public/iclientthinkable.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLIENTTHINKABLE_H +#define ICLIENTTHINKABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iclientunknown.h" + + +class CClientThinkHandlePtr; +typedef CClientThinkHandlePtr* ClientThinkHandle_t; + + +// Entities that implement this interface can be put into the client think list. +abstract_class IClientThinkable +{ +public: + // Gets at the containing class... + virtual IClientUnknown* GetIClientUnknown() = 0; + + virtual void ClientThink() = 0; + + // Called when you're added to the think list. + // GetThinkHandle's return value must be initialized to INVALID_THINK_HANDLE. + virtual ClientThinkHandle_t GetThinkHandle() = 0; + virtual void SetThinkHandle( ClientThinkHandle_t hThink ) = 0; + + // Called by the client when it deletes the entity. + virtual void Release() = 0; +}; + + +#endif // ICLIENTTHINKABLE_H diff --git a/public/iclientunknown.h b/public/iclientunknown.h new file mode 100644 index 0000000..ac7e1e8 --- /dev/null +++ b/public/iclientunknown.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ICLIENTUNKNOWN_H +#define ICLIENTUNKNOWN_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/platform.h" +#include "ihandleentity.h" + +class IClientNetworkable; +class C_BaseEntity; +class IClientRenderable; +class ICollideable; +class IClientEntity; +class IClientThinkable; + + + +// This is the client's version of IUnknown. We may want to use a QueryInterface-like +// mechanism if this gets big. +abstract_class IClientUnknown : public IHandleEntity +{ +public: + virtual ICollideable* GetCollideable() = 0; + virtual IClientNetworkable* GetClientNetworkable() = 0; + virtual IClientRenderable* GetClientRenderable() = 0; + virtual IClientEntity* GetIClientEntity() = 0; + virtual C_BaseEntity* GetBaseEntity() = 0; + virtual IClientThinkable* GetClientThinkable() = 0; +}; + + +#endif // ICLIENTUNKNOWN_H diff --git a/public/iclientvirtualreality.h b/public/iclientvirtualreality.h new file mode 100644 index 0000000..b24cd26 --- /dev/null +++ b/public/iclientvirtualreality.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains the IClientVirtualReality interface, which is implemented in +// client.dll and called by engine.dll +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ICLIENTVIRTUALREALITY_H +#define ICLIENTVIRTUALREALITY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "tier1/refcount.h" +#include "appframework/IAppSystem.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// important enumeration +//----------------------------------------------------------------------------- + +// NOTE NOTE NOTE!!!! If you up this, grep for "NEW_INTERFACE" to see if there is anything +// waiting to be enabled during an interface revision. +#define CLIENTVIRTUALREALITY_INTERFACE_VERSION "ClientVirtualReality001" + +//----------------------------------------------------------------------------- +// The ISourceVirtualReality interface +//----------------------------------------------------------------------------- + + + +abstract_class IClientVirtualReality : public IAppSystem +{ +public: + virtual ~IClientVirtualReality() {} + + // Placeholder for API revision + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + // the interface + + // Draw the main menu in VR mode + virtual void DrawMainMenu() = 0; +}; + + + +//----------------------------------------------------------------------------- + +extern IClientVirtualReality *g_pClientVR; + + +#endif // ICLIENTVIRTUALREALITY_H diff --git a/public/icvar.h b/public/icvar.h new file mode 100644 index 0000000..89bb59d --- /dev/null +++ b/public/icvar.h @@ -0,0 +1,216 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef ICVAR_H +#define ICVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" +#include "tier1/iconvar.h" + +class ConCommandBase; +class ConCommand; +class ConVar; +class Color; + + +//----------------------------------------------------------------------------- +// ConVars/ComCommands are marked as having a particular DLL identifier +//----------------------------------------------------------------------------- +typedef int CVarDLLIdentifier_t; + + +//----------------------------------------------------------------------------- +// Used to display console messages +//----------------------------------------------------------------------------- +abstract_class IConsoleDisplayFunc +{ +public: + virtual void ColorPrint( const Color& clr, const char *pMessage ) = 0; + virtual void Print( const char *pMessage ) = 0; + virtual void DPrint( const char *pMessage ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Applications can implement this to modify behavior in ICvar +//----------------------------------------------------------------------------- +#define CVAR_QUERY_INTERFACE_VERSION "VCvarQuery001" +abstract_class ICvarQuery : public IAppSystem +{ +public: + // Can these two convars be aliased? + virtual bool AreConVarsLinkable( const ConVar *child, const ConVar *parent ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: DLL interface to ConVars/ConCommands +//----------------------------------------------------------------------------- +abstract_class ICvar : public IAppSystem +{ +public: + // Allocate a unique DLL identifier + virtual CVarDLLIdentifier_t AllocateDLLIdentifier() = 0; + + // Register, unregister commands + virtual void RegisterConCommand( ConCommandBase *pCommandBase ) = 0; + virtual void UnregisterConCommand( ConCommandBase *pCommandBase ) = 0; + virtual void UnregisterConCommands( CVarDLLIdentifier_t id ) = 0; + + // If there is a + on the command line, this returns the value. + // Otherwise, it returns NULL. + virtual const char* GetCommandLineValue( const char *pVariableName ) = 0; + + // INTERFACE_UPDATE:23.02.2020 + //virtual void stub_005() = 0; + //virtual void stub_006() = 0; + + // Try to find the cvar pointer by name + virtual ConCommandBase *FindCommandBase( const char *name ) = 0; + virtual const ConCommandBase *FindCommandBase( const char *name ) const = 0; + virtual ConVar *FindVar ( const char *var_name ) = 0; + virtual const ConVar *FindVar ( const char *var_name ) const = 0; + virtual ConCommand *FindCommand( const char *name ) = 0; + virtual const ConCommand *FindCommand( const char *name ) const = 0; + + // Get first ConCommandBase to allow iteration + virtual ConCommandBase *GetCommands( void ) = 0; + virtual const ConCommandBase *GetCommands( void ) const = 0; + + // Install a global change callback (to be called when any convar changes) + virtual void InstallGlobalChangeCallback( FnChangeCallback_t callback ) = 0; + virtual void RemoveGlobalChangeCallback( FnChangeCallback_t callback ) = 0; + virtual void CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue ) = 0; + + // Install a console printer + virtual void InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ) = 0; + virtual void RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ) = 0; + //DON'T WORK + virtual void ConsoleColorPrintf( const Color& clr, PRINTF_FORMAT_STRING const char *pFormat, ... ) const FMTFUNCTION( 3, 4 ) = 0; + virtual void ConsolePrintf( PRINTF_FORMAT_STRING const char *pFormat, ... ) const FMTFUNCTION( 2, 3 ) = 0; + virtual void ConsoleDPrintf( PRINTF_FORMAT_STRING const char *pFormat, ... ) const FMTFUNCTION( 2, 3 ) = 0; + + // Reverts cvars which contain a specific flag + virtual void RevertFlaggedConVars( int nFlag ) = 0; + + // Method allowing the engine ICvarQuery interface to take over + // A little hacky, owing to the fact the engine is loaded + // well after ICVar, so we can't use the standard connect pattern + virtual void InstallCVarQuery( ICvarQuery *pQuery ) = 0; + +#if defined( _X360 ) + virtual void PublishToVXConsole( ) = 0; +#endif + // INTERFACE_UPDATE:23.02.2020 + virtual void stub_007() = 0; + virtual void stub_008() = 0; + virtual void stub_009() = 0; + virtual void stub_010() = 0; + //virtual void stub_011() = 0; + //virtual void stub_012() = 0; + + virtual bool IsMaterialThreadSetAllowed( ) const = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue ) = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, int nValue ) = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, float flValue ) = 0; + virtual bool HasQueuedMaterialThreadConVarSets() const = 0; + virtual int ProcessQueuedMaterialThreadConVarSets() = 0; //+6 + +protected: class ICVarIteratorInternal; +public: + /// Iteration over all cvars. + /// (THIS IS A SLOW OPERATION AND YOU SHOULD AVOID IT.) + /// usage: + /// { ICVar::Iterator iter(g_pCVar); + /// for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() ) + /// { + /// ConCommandBase *cmd = iter.Get(); + /// } + /// } + /// The Iterator class actually wraps the internal factory methods + /// so you don't need to worry about new/delete -- scope takes care + // of it. + /// We need an iterator like this because we can't simply return a + /// pointer to the internal data type that contains the cvars -- + /// it's a custom, protected class with unusual semantics and is + /// prone to change. + class Iterator + { + public: + inline Iterator(ICvar *icvar); + inline ~Iterator(void); + inline void SetFirst( void ); + inline void Next( void ); + inline bool IsValid( void ); + inline ConCommandBase *Get( void ); + private: + ICVarIteratorInternal *m_pIter; + }; + +protected: + // internals for ICVarIterator + class ICVarIteratorInternal + { + public: + // warning: delete called on 'ICvar::ICVarIteratorInternal' that is abstract but has non-virtual destructor [-Wdelete-non-virtual-dtor] + virtual ~ICVarIteratorInternal() {} + virtual void SetFirst( void ) = 0; + virtual void Next( void ) = 0; + virtual bool IsValid( void ) = 0; + virtual ConCommandBase *Get( void ) = 0; + }; + + virtual ICVarIteratorInternal *FactoryInternalIterator( void ) = 0; + friend class Iterator; +}; + +inline ICvar::Iterator::Iterator(ICvar *icvar) +{ + m_pIter = icvar->FactoryInternalIterator(); +} + +inline ICvar::Iterator::~Iterator( void ) +{ + delete m_pIter; +} + +inline void ICvar::Iterator::SetFirst( void ) +{ + m_pIter->SetFirst(); +} + +inline void ICvar::Iterator::Next( void ) +{ + m_pIter->Next(); +} + +inline bool ICvar::Iterator::IsValid( void ) +{ + return m_pIter->IsValid(); +} + +inline ConCommandBase * ICvar::Iterator::Get( void ) +{ + return m_pIter->Get(); +} + +#define CVAR_INTERFACE_VERSION "VEngineCvar007" // INTERFACE_UPDATE:23.02.2020 + + +//----------------------------------------------------------------------------- +// These global names are defined by tier1.h, duplicated here so you +// don't have to include tier1.h +//----------------------------------------------------------------------------- + +// These are marked DLL_EXPORT for Linux. +DLL_EXPORT ICvar *cvar; +extern ICvar *g_pCVar; + + +#endif // ICVAR_H diff --git a/public/idedicatedexports.h b/public/idedicatedexports.h new file mode 100644 index 0000000..817401f --- /dev/null +++ b/public/idedicatedexports.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IDEDICATEDEXPORTS_H +#define IDEDICATEDEXPORTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "appframework/IAppSystem.h" + + +abstract_class IDedicatedExports : public IAppSystem +{ +public: + virtual void Sys_Printf( char *text ) = 0; + virtual void RunServer() = 0; +}; + +#define VENGINE_DEDICATEDEXPORTS_API_VERSION "VENGINE_DEDICATEDEXPORTS_API_VERSION003" + + +#endif // IDEDICATEDEXPORTS_H diff --git a/public/iefx.h b/public/iefx.h new file mode 100644 index 0000000..8383538 --- /dev/null +++ b/public/iefx.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#if !defined( IEFX_H ) +#define IEFX_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib/vector.h" + +struct model_t; +struct dlight_t; +class IMaterial; + +#define MAX_DLIGHTS 32 + +//----------------------------------------------------------------------------- +// Purpose: Exposes effects api to client .dll +//----------------------------------------------------------------------------- +abstract_class IVEfx +{ +public: + // Retrieve decal texture index from decal by name + virtual int Draw_DecalIndexFromName ( char *name ) = 0; + + // Apply decal + virtual void DecalShoot ( int textureIndex, int entity, + const model_t *model, const Vector& model_origin, const QAngle& model_angles, + const Vector& position, const Vector *saxis, int flags ) = 0; + + // Apply colored decal + virtual void DecalColorShoot ( int textureIndex, int entity, + const model_t *model, const Vector& model_origin, const QAngle& model_angles, + const Vector& position, const Vector *saxis, int flags, const color32 &rgbaColor ) = 0; + + virtual void PlayerDecalShoot( IMaterial *material, void *userdata, int entity, const model_t *model, + const Vector& model_origin, const QAngle& model_angles, + const Vector& position, const Vector *saxis, int flags, const color32 &rgbaColor ) = 0; + + // Allocate a dynamic world light ( key is the entity to whom it is associated ) + virtual dlight_t *CL_AllocDlight ( int key ) = 0; + + // Allocate a dynamic entity light ( key is the entity to whom it is associated ) + virtual dlight_t *CL_AllocElight ( int key ) = 0; + + // Get a list of the currently-active dynamic lights. + virtual int CL_GetActiveDLights( dlight_t *pList[MAX_DLIGHTS] ) = 0; + + // Retrieve decal texture name from decal by index + virtual const char *Draw_DecalNameFromIndex( int nIndex ) = 0; + + // Given an elight key, find it. Does not search ordinary dlights. May return NULL. + virtual dlight_t *GetElightByKey( int key ) = 0; +}; + +#define VENGINE_EFFECTS_INTERFACE_VERSION "VEngineEffects001" + +extern IVEfx *effects; + +#endif // IEFX_H diff --git a/public/ienginevgui.h b/public/ienginevgui.h new file mode 100644 index 0000000..601ba27 --- /dev/null +++ b/public/ienginevgui.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( IENGINEVGUI_H ) +#define IENGINEVGUI_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "vgui/VGUI.h" + +// Forward declarations. +namespace vgui +{ + class Panel; +}; + +enum VGuiPanel_t +{ + PANEL_ROOT = 0, + PANEL_GAMEUIDLL, + PANEL_CLIENTDLL, + PANEL_TOOLS, + PANEL_INGAMESCREENS, + PANEL_GAMEDLL, + PANEL_CLIENTDLL_TOOLS +}; + +// In-game panels are cropped to the current engine viewport size +enum PaintMode_t +{ + PAINT_UIPANELS = (1<<0), + PAINT_INGAMEPANELS = (1<<1), + PAINT_CURSOR = (1<<2), // software cursor, if appropriate +}; + +abstract_class IEngineVGui +{ +public: + virtual ~IEngineVGui( void ) { } + + virtual vgui::VPANEL GetPanel( VGuiPanel_t type ) = 0; + + virtual bool IsGameUIVisible() = 0; +}; + +#define VENGINE_VGUI_VERSION "VEngineVGui001" + +#if defined(_STATIC_LINKED) && defined(CLIENT_DLL) +namespace Client +{ +extern IEngineVGui *enginevgui; +} +#else +extern IEngineVGui *enginevgui; +#endif + +#endif // IENGINEVGUI_H diff --git a/public/iexternaltest.h b/public/iexternaltest.h new file mode 100644 index 0000000..7417405 --- /dev/null +++ b/public/iexternaltest.h @@ -0,0 +1,279 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to external test DLLs +// +//============================================================================= + +#ifndef IEXTERNALTEST +#define IEXTERNALTEST +#ifdef _WIN32 +#pragma once +#endif + +#include "steam/isteamfriends.h" +#include "clientenums.h" + +// An equivalent to EConnectionPriority that can be used in +// external tests without needing to depend on Steam's version of the enum +enum EExternalTestConnectionPriority +{ + k_EExternalTestConnectionPriorityLow = 0, + k_EExternalTestConnectionPriorityMedium = 1, + k_EExternalTestConnectionPriorityHigh = 2, +}; + +// used to pass arbitrary buffers full of data back to the external test +typedef uint32 ExternalTestBuffer_t; +static const ExternalTestBuffer_t k_unExternalTestBufferInvalid = 0; + + +//----------------------------------------------------------------------------- +// Purpose: Represents a single test client (game client or game server) inside +// of a test. +//----------------------------------------------------------------------------- +class IExternalTestClient +{ +public: + virtual ~IExternalTestClient() {} + virtual void *GetISteamGenericInterface( const char *pchInterfaceVersion ) = 0; + virtual ISteamUserStats *GetISteamUserStats( const char *pchVersion ) = 0; + virtual ISteamGameServerStats *GetISteamGameServerStats( const char *pchVersion ) = 0; + virtual CSteamID GetSteamID() = 0; + virtual bool GetAccountName( char *pchBuf, int cchBuf ) = 0; + + virtual bool BLoggedOn() = 0; + virtual void YieldingLogOff() = 0; + virtual bool BYieldingLogOn() = 0; + virtual void RequestAppInfoUpdate() = 0; + virtual bool BGetAppInfoUpdateResult( EResult *peResult, uint32 *punAppsUpdated ) = 0; + virtual void GetServerDetails( AppId_t *pnAppIdServed, uint32 *punIPGameServer, uint16 *pusPortGameServer, bool *pbSecure ) = 0; + virtual bool BYieldingPrepareForApp( AppId_t unAppID ) = 0; + virtual void SetConnectionPriority( EExternalTestConnectionPriority eConnectionPriority ) = 0; + + // methods to manipulate friend/social stuff that isn't in ISteamFriends + virtual void SetPersonaState( EPersonaState ePersonaState ) = 0; + virtual void AddFriend( const CSteamID & steamIDFriend ) = 0; + virtual void RemoveFriend( const CSteamID & steamIDFriend ) = 0; + + // Removes every queued callback for this client + virtual void ClearCallbacks() = 0; + + // Sets this user as an admin in this universe + virtual void YieldingSetAsAdmin() = 0; + + // bans this user for the specified app ID + virtual void YieldingBan( AppId_t unAppID, int nDeltaSeconds, bool bOneYearBan ) = 0; + + virtual bool BYieldingAwaitNewCallback( void *pCallback, uint32 unCallbackSize, int nCallbackType ) = 0; + virtual bool BYieldingAwaitQueuedCallback( void * pCallback, uint32 unCallbackSize, int nCallbackType ) = 0; + virtual bool BGetQueuedCallbackOfType( void * pCallback, uint32 unCallbackSize, int nCallbackType ) = 0; + + // Retrieves the current status of the API call. Returns false if the call is still in progress + virtual bool BYieldingGetAPICallResult( SteamAPICall_t hSteamAPICall, void *pCallback, uint32 unCallbackSize, int nCallback, bool *pbAPICallFailed ) = 0; + + template< typename TCallback > + inline bool BYieldingAwaitQueuedCallback( TCallback & callback ) { return BYieldingAwaitQueuedCallback( &callback, sizeof(TCallback), TCallback::k_iCallback ); } + template< typename TCallback > + inline bool BYieldingAwaitNewCallback( TCallback & callback ) { return BYieldingAwaitNewCallback( &callback, sizeof(TCallback), TCallback::k_iCallback ); } + template< typename TCallback > + inline bool BGetQueuedCallbackOfType( TCallback & callback ) { return BGetQueuedCallbackOfType( &callback, sizeof(TCallback), TCallback::k_iCallback ); } + + // more friends stuff that isnt in ISteamFriends + virtual void SetIgnoreFriend( const CSteamID & steamIDFriend ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Helper functions for interacting with the steam client during tests +//----------------------------------------------------------------------------- +class IExternalTestUtils +{ +public: + virtual ~IExternalTestUtils() {} + + // creates a single user client that is logged into an optional gameserver + virtual IExternalTestClient *YieldingCreateUserClient( IExternalTestClient *pGameserver ) = 0; + + // creates a single gameserver client at the specified (fake) IP addr and port + virtual IExternalTestClient *YieldingCreateGameserverClient( uint32 unAddr, uint16 usPort ) = 0; + + // returns the ISteamClient object so the test can fetch other ISteam interfaces. + virtual ISteamClient *SteamClient() = 0; + + // deploys the gctest dll at the current AppID. This is probably not useful outside of the + // gctest tests. + virtual void YieldingDeployGC( ) = 0; + + // takes down the gctest dll at the current app DI + virtual void YieldingDownGC( ) = 0; + + // returns the app ID this test is running as + virtual AppId_t GetAppId() = 0; + + // draws a dot in the output + virtual void DrawProgressDot() = 0; + + // spews some text in the output + virtual void EmitTestOutput( const char *pchMessage ) = 0; + + // used by the external test framework to clean up some things between + // test cases. Test cases should not call this. + virtual void YieldingResetBetweenTests() = 0; + + // Checks a bool condition and spews if it fails. If this fails the test + // will be recorded as having failed. + virtual bool BCheck( bool bCondition ) = 0; + + // Yields until the stress test is finished. If this test is running as a + // regression test, this will return immediately. + virtual void YieldingWaitForTestToFinish() = 0; + + // used by the external test framework to record test success/failure in + // a file that buildbot can use to build reports. Tests should not call this directly. + virtual void UpdateProgressFile( const char *pchTestName, const char *pchStatus ) = 0; + + // Returns true if the test that ran most recently (and might still be running) passed. + virtual bool BLastTestPassed() = 0; + + // Called by a test to report that the test has reached the "running" state. This is only + // useful in stress tests. + virtual void MarkTestRunning() = 0; + + // Logs on a bunch of clients all at once and returns when they are all logged on. + virtual bool BYieldingCreateUserClientBatch( IExternalTestClient **prClients, int cClients, EExternalTestConnectionPriority eConnectionPriority ) = 0; + + // Logs on a bunch of gameservers all at once and returns when they are all logged on. + virtual bool BYieldingCreateGameserverClientBatch( IExternalTestClient **prClients, int cClients, EExternalTestConnectionPriority eConnectionPriority ) = 0; + + // returns true if the test is finished + virtual bool BIsStressTestFinished() = 0; + + // waits a single frame before resuming the test + virtual void YieldingWaitOneFrame() = 0; + + // reports a stress test action success/failure + virtual void ReportStressActionResult( uint32 unActionIndex, bool bResult, const char *pchFailureLocation ) = 0; + + // waits for the specified number of seconds to pass + virtual void YieldingWaitForRealTime( uint32 unSeconds ) = 0; + + // deploys the specified zip file as the GC for the specified app ID + virtual bool BYieldingGCDeploy( AppId_t appID, const char *pchGCZipFile ) = 0; + + // Downs the specified GC + virtual bool BYieldingGCDown( AppId_t appID ) = 0; + + // Revives the specified GC + virtual bool BYieldingGCRevive( AppId_t appID ) = 0; + + // Bounces the specified GC + virtual bool BYieldingGCBounce( AppId_t appID ) = 0; + + // returns the universe the tests are running in + virtual EUniverse GetUniverse() = 0; + + // returns the memory for a buffer + virtual void *GetPvBuffer( ExternalTestBuffer_t unBuffer ) = 0; + + // returns the memory for a buffer + virtual uint32 GetCubBuffer( ExternalTestBuffer_t unBuffer ) = 0; + + // makes a simulated WG request and returns the result + virtual ExternalTestBuffer_t YieldingSimulateWGRequest( const CSteamID & actorID, const void *pvRequestKV, uint32 cubRequestKV ) = 0; + + // Verifies that there is no support ticket for the specified steam ID + virtual void YieldingVerifyNoSupportTicket( const CSteamID & steamID ) = 0; + + // Verifies that there is a support event for the specified steam ID + virtual void YieldingVerifySupportEventRecord( const CSteamID & victimID, const CSteamID & actorID, ESupportEvent eAction, GID_t gidTxn, const char *pchNote ) = 0; + + // forces an appinfo update for the specified app. (Pass invalid to use the default app ID + virtual void YieldingForceAppInfoUpdate( AppId_t appId ) = 0; + + // returns the stats KV section serialized as a buffer + virtual ExternalTestBuffer_t YieldingGetAppInfoStats( AppId_t appId ) = 0; + + // makes a web request and returns the result + virtual bool BYieldingHTTPRequest( int nWebMethod, bool bUseSSL, const char *pchURL, const KeyValues *pkvPostParams, const char *pchAPIKey, const CSteamID & steamID, ExternalTestBuffer_t *punBuffer, int *pnResultCode ) = 0; + + // returns the full path to the DLL that these tests are running from + virtual const char *GetPchDllPath() = 0; + + // returns true if these tests are running in dev mode (i.e. the server was started with -etdev) + virtual bool BIsDevMode() = 0; + + // Sets the persona name for this user via the wg call so we can actually tell when + // it's been set. + virtual bool BYieldingSetPersonaName( const CSteamID & steamID, const char *pchPersonaName ) = 0; + + // waits for the writeback queue to clear + virtual bool BYieldingWaitForCacheWriteback() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for sending and receiving messages from the Game Coordinator +// for this application +//----------------------------------------------------------------------------- +class IExternalTest +{ +public: + + // returns the number of tests present in this DLL + virtual uint32 GetTestCount() = 0; + + // returns the name of the specified test + virtual const char *GetTestName( uint32 unTest ) = 0; + + // returns the short name (no suite prefix) of the specified test + virtual const char *GetTestShortName( uint32 unTest ) = 0; + + // returns the suite of the specified test + virtual const char *GetTestSuite( uint32 unTest ) = 0; + + // returns the flags for the specified test + virtual uint32 GetTestFlags( uint32 unTest ) = 0; + + // runs the specified tests. The tests should run to completion + // (yielding on a regular basis) and call pETestUtils->BCheck(false) + // on failure + virtual void BRunTests( uint32 *punTests, uint32 unTestCount, IExternalTestUtils * pETestUtils ) = 0; + + // Returns the name of a stress test action + virtual const char *GetStressActionName( uint32 unAction ) = 0; + +}; +#define EXTERNALTEST_INTERFACE_VERSION "IExternalTest001" + +// flags set by individual tests +static const uint32 k_unETFlag_ValidForStress = 1<<0; +static const uint32 k_unETFlag_ValidForRegression = 1<<1; + + +//----------------------------------------------------------------------------- +// Purpose: For one time init of an externaltests dll +//----------------------------------------------------------------------------- +class IExternalTestInitialize +{ +public: + virtual bool BDoBundleInit() = 0; // called once *PER ATS* at DLL Load time + virtual bool BDoOneTimeInit( IExternalTestUtils *pExternalTestUtils ) = 0; // called once PER TEST RUN by ATS0 + virtual bool BDoPerATSInit( IExternalTestUtils *pExternalTestUtils ) = 0; // called once PER TEST RUN PER ATS + virtual void Cleanup() = 0; +}; +#define EXTERNALTEST_INITIALIZE_INTERFACE_VERSION "IExternalTestInitialize001" + + +//----------------------------------------------------------------------------- +// Purpose: Allows an external test DLL to export its ability to validate its +// own allocations +//----------------------------------------------------------------------------- +class IExternalTestValidation +{ +public: + + virtual void Validate( CValidator &validator, const char *pchName ) = 0; +}; +#define EXTERNALTEST_VALIDATION_INTERFACE_VERSION "IExternalTestValidation001" + + +#endif // IEXTERNALTEST diff --git a/public/ifilelist.h b/public/ifilelist.h new file mode 100644 index 0000000..00dd20f --- /dev/null +++ b/public/ifilelist.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IFILELIST_H +#define IFILELIST_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class represents a group of files. Internally, it can represent whole folders of files +// that are in or out of the group. So you can't iterate the list, but you can ask the +// class if a particular filename is in the list. +class IFileList +{ +public: + virtual bool IsFileInList( const char *pFilename ) = 0; + virtual void Release() = 0; +}; + + +#endif // IFILELIST_H + + diff --git a/public/igameevents.h b/public/igameevents.h new file mode 100644 index 0000000..4746361 --- /dev/null +++ b/public/igameevents.h @@ -0,0 +1,193 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IGAMEEVENTS_H ) +#define IGAMEEVENTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" + +#define INTERFACEVERSION_GAMEEVENTSMANAGER "GAMEEVENTSMANAGER001" // old game event manager, don't use it! +#define INTERFACEVERSION_GAMEEVENTSMANAGER2 "GAMEEVENTSMANAGER002" // new game event manager, + +#include "tier1/bitbuf.h" +//----------------------------------------------------------------------------- +// Purpose: Engine interface into global game event management +//----------------------------------------------------------------------------- + +/* + +The GameEventManager keeps track and fires of all global game events. Game events +are fired by game.dll for events like player death or team wins. Each event has a +unique name and comes with a KeyValue structure providing informations about this +event. Some events are generated also by the engine. + +Events are networked to connected clients and invoked there to. Therefore you +have to specify all data fields and there data types in an public resource +file which is parsed by server and broadcasted to it's clients. A typical game +event is defined like this: + + "game_start" // a new game starts + { + "roundslimit" "long" // max round + "timelimit" "long" // time limit + "fraglimit" "long" // frag limit + "objective" "string" // round objective + } + +All events must have unique names (case sensitive) and may have a list +of data fields. each data field must specify a data type, so the engine +knows how to serialize/unserialize that event for network transmission. +Valid data types are string, float, long, short, byte & bool. If a +data field should not be broadcasted to clients, use the type "local". +*/ + + +#define MAX_EVENT_NAME_LENGTH 32 // max game event name length +#define MAX_EVENT_BITS 9 // max bits needed for an event index +#define MAX_EVENT_NUMBER (1< (fn) + +class INetMessage +{ +public: + virtual ~INetMessage() {}; + + // Use these to setup who can hear whose voice. + // Pass in client indices (which are their ent indices - 1). + + virtual void SetNetChannel(INetChannel * netchan) = 0; // netchannel this message is from/for + virtual void SetReliable( bool state ) = 0; // set to true if it's a reliable message + + virtual bool Process( void ) = 0; // calles the recently set handler to process this message + + virtual bool ReadFromBuffer( bf_read &buffer ) = 0; // returns true if parsing was OK + virtual bool WriteToBuffer( bf_write &buffer ) = 0; // returns true if writing was OK + + virtual bool IsReliable( void ) const = 0; // true, if message needs reliable handling + + virtual int GetType( void ) const = 0; // returns module specific header tag eg svc_serverinfo + virtual int GetGroup( void ) const = 0; // returns net message group of this message + virtual const char *GetName( void ) const = 0; // returns network message name, eg "svc_serverinfo" + virtual INetChannel *GetNetChannel( void ) const = 0; + virtual const char *ToString( void ) const = 0; // returns a human readable string about message content +}; + + +#endif + diff --git a/public/inetmsghandler.h b/public/inetmsghandler.h new file mode 100644 index 0000000..80181cc --- /dev/null +++ b/public/inetmsghandler.h @@ -0,0 +1,216 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( INETMSGHANDLER_H ) +#define INETMSGHANDLER_H +#ifdef _WIN32 +#pragma once +#endif + +class INetChannel; +typedef struct netpacket_s netpacket_t; + +class INetChannelHandler +{ +public: + virtual ~INetChannelHandler( void ) {}; + + virtual void ConnectionStart(INetChannel *chan) = 0; // called first time network channel is established + + virtual void ConnectionClosing(const char *reason) = 0; // network channel is being closed by remote site + + virtual void ConnectionCrashed(const char *reason) = 0; // network error occured + + virtual void PacketStart(int incoming_sequence, int outgoing_acknowledged) = 0; // called each time a new packet arrived + + virtual void PacketEnd( void ) = 0; // all messages has been parsed + + virtual void FileRequested(const char *fileName, unsigned int transferID ) = 0; // other side request a file for download + + virtual void FileReceived(const char *fileName, unsigned int transferID ) = 0; // we received a file + + virtual void FileDenied(const char *fileName, unsigned int transferID ) = 0; // a file request was denied by other side + + virtual void FileSent(const char *fileName, unsigned int transferID ) = 0; // we sent a file +}; + +#define PROCESS_NET_MESSAGE( name ) \ + virtual bool Process##name( NET_##name *msg ) + +#define PROCESS_SVC_MESSAGE( name ) \ + virtual bool Process##name( SVC_##name *msg ) + +#define PROCESS_CLC_MESSAGE( name ) \ + virtual bool Process##name( CLC_##name *msg ) + +#define PROCESS_MM_MESSAGE( name ) \ + virtual bool Process##name( MM_##name *msg ) + + +#define REGISTER_NET_MSG( name ) \ + NET_##name * p##name = new NET_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_SVC_MSG( name ) \ + SVC_##name * p##name = new SVC_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_CLC_MSG( name ) \ + CLC_##name * p##name = new CLC_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_MM_MSG( name ) \ + MM_##name * p##name = new MM_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +class NET_Tick; +class NET_StringCmd; +class NET_SetConVar; +class NET_SignonState; + + +class INetMessageHandler +{ +public: + virtual ~INetMessageHandler( void ) {}; + + PROCESS_NET_MESSAGE( Tick ) = 0; + PROCESS_NET_MESSAGE( StringCmd ) = 0; + PROCESS_NET_MESSAGE( SetConVar ) = 0; + PROCESS_NET_MESSAGE( SignonState ) = 0; +}; + +class CLC_ClientInfo; +class CLC_Move; +class CLC_VoiceData; +class CLC_BaselineAck; +class CLC_ListenEvents; +class CLC_RespondCvarValue; +class CLC_FileCRCCheck; +class CLC_FileMD5Check; +class CLC_SaveReplay; +class CLC_CmdKeyValues; + +class IClientMessageHandler : public INetMessageHandler +{ +public: + virtual ~IClientMessageHandler( void ) {}; + + PROCESS_CLC_MESSAGE( ClientInfo ) = 0; + PROCESS_CLC_MESSAGE( Move ) = 0; + PROCESS_CLC_MESSAGE( VoiceData ) = 0; + PROCESS_CLC_MESSAGE( BaselineAck ) = 0; + PROCESS_CLC_MESSAGE( ListenEvents ) = 0; + PROCESS_CLC_MESSAGE( RespondCvarValue ) = 0; + PROCESS_CLC_MESSAGE( FileCRCCheck ) = 0; + PROCESS_CLC_MESSAGE( FileMD5Check ) = 0; +#if defined( REPLAY_ENABLED ) + PROCESS_CLC_MESSAGE( SaveReplay ) = 0; +#endif + PROCESS_CLC_MESSAGE( CmdKeyValues ) = 0; +}; + +class SVC_Print; +class SVC_ServerInfo; +class SVC_SendTable; +class SVC_ClassInfo; +class SVC_SetPause; +class SVC_CreateStringTable; +class SVC_UpdateStringTable; +class SVC_VoiceInit; +class SVC_VoiceData; +class SVC_Sounds; +class SVC_SetView; +class SVC_FixAngle; +class SVC_CrosshairAngle; +class SVC_BSPDecal; +class SVC_GameEvent; +class SVC_UserMessage; +class SVC_EntityMessage; +class SVC_PacketEntities; +class SVC_TempEntities; +class SVC_Prefetch; +class SVC_Menu; +class SVC_GameEventList; +class SVC_GetCvarValue; +class SVC_CmdKeyValues; + +class IServerMessageHandler : public INetMessageHandler +{ +public: + virtual ~IServerMessageHandler( void ) {}; + + // Returns dem file protocol version, or, if not playing a demo, just returns PROTOCOL_VERSION + virtual int GetDemoProtocolVersion() const = 0; + + PROCESS_SVC_MESSAGE( Print ) = 0; + PROCESS_SVC_MESSAGE( ServerInfo ) = 0; + PROCESS_SVC_MESSAGE( SendTable ) = 0; + PROCESS_SVC_MESSAGE( ClassInfo ) = 0; + PROCESS_SVC_MESSAGE( SetPause ) = 0; + PROCESS_SVC_MESSAGE( CreateStringTable ) = 0; + PROCESS_SVC_MESSAGE( UpdateStringTable ) = 0; + PROCESS_SVC_MESSAGE( VoiceInit ) = 0; + PROCESS_SVC_MESSAGE( VoiceData ) = 0; + PROCESS_SVC_MESSAGE( Sounds ) = 0; + PROCESS_SVC_MESSAGE( SetView ) = 0; + PROCESS_SVC_MESSAGE( FixAngle ) = 0; + PROCESS_SVC_MESSAGE( CrosshairAngle ) = 0; + PROCESS_SVC_MESSAGE( BSPDecal ) = 0; + PROCESS_SVC_MESSAGE( GameEvent ) = 0; + PROCESS_SVC_MESSAGE( UserMessage ) = 0; + PROCESS_SVC_MESSAGE( EntityMessage ) = 0; + PROCESS_SVC_MESSAGE( PacketEntities ) = 0; + PROCESS_SVC_MESSAGE( TempEntities ) = 0; + PROCESS_SVC_MESSAGE( Prefetch ) = 0; + PROCESS_SVC_MESSAGE( Menu ) = 0; + PROCESS_SVC_MESSAGE( GameEventList ) = 0; + PROCESS_SVC_MESSAGE( GetCvarValue ) = 0; + PROCESS_SVC_MESSAGE( CmdKeyValues ) = 0; +}; + +class MM_Heartbeat; +class MM_ClientInfo; +class MM_JoinResponse; +class MM_RegisterResponse; +class MM_Migrate; +class MM_Mutelist; +class MM_Checkpoint; + +class IMatchmakingMessageHandler : public INetMessageHandler +{ +public: + virtual ~IMatchmakingMessageHandler( void ) {}; + + PROCESS_MM_MESSAGE( Heartbeat ) = 0; + PROCESS_MM_MESSAGE( ClientInfo ) = 0; + PROCESS_MM_MESSAGE( JoinResponse ) = 0; + PROCESS_MM_MESSAGE( RegisterResponse ) = 0; + PROCESS_MM_MESSAGE( Migrate ) = 0; + PROCESS_MM_MESSAGE( Mutelist ) = 0; + PROCESS_MM_MESSAGE( Checkpoint) = 0; +}; + +class IConnectionlessPacketHandler +{ +public: + virtual ~IConnectionlessPacketHandler( void ) {}; + + virtual bool ProcessConnectionlessPacket( netpacket_t *packet ) = 0; // process a connectionless packet +}; + + +#endif // INETMSGHANDLER_H diff --git a/public/inetwork.h b/public/inetwork.h new file mode 100644 index 0000000..5014e15 --- /dev/null +++ b/public/inetwork.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef INETWORK_H +#define INETWORK_H +#ifdef _WIN32 +#pragma once +#endif + +class IConnectionlessPacketHandler; + +abstract_class INetwork +{ +public: + virtual ~INetwork( void ) {}; + + virtual void Init( void ) = 0; + virtual void Config (bool multiplayer); + virtual void IsMultiplayer( void ) = 0; // true = full MP mode, false = loopback SP mode + virtual void IsEnabled( void ) = 0; + + // shuts down Network, closes all UPD/TCP channels + virtual void Shutdown( void ) = 0; + + // must be called each system frame to do any asynchronouse TCP stuff + virtual void RunFrame( double time ) = 0; + + virtual void ProcessSocket( netsrc_t sock, IConnectionlessPacketHandler * handler ) = 0; + + virtual void OutOfBandPrintf(netsrc_t sock, netadr_t &adr, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void SendConnectionless(netsrc_t sock, netadr_t &adr, unsigned char * data, int length ) = 0; + + virtual void LogBadPacket(netpacket_t * packet) = 0; + + // Address conversion + virtual bool StringToAdr ( const char *s, netadr_t *a) = 0; + + // Convert from host to network byte ordering + virtual unsigned short HostToNetShort( unsigned short us_in ); + + // and vice versa + virtual unsigned short NetToHostShort( unsigned short us_in ); + + + +}; + + +#endif // INETWORK_H diff --git a/public/inputsystem/AnalogCode.h b/public/inputsystem/AnalogCode.h new file mode 100644 index 0000000..51a8441 --- /dev/null +++ b/public/inputsystem/AnalogCode.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ANALOGCODE_H +#define ANALOGCODE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "inputsystem/InputEnums.h" + + +//----------------------------------------------------------------------------- +// Macro to get at joystick codes +//----------------------------------------------------------------------------- +#define JOYSTICK_AXIS_INTERNAL( _joystick, _axis ) ( JOYSTICK_FIRST_AXIS + ((_joystick) * MAX_JOYSTICK_AXES) + (_axis) ) +#define JOYSTICK_AXIS( _joystick, _axis ) ( (AnalogCode_t)JOYSTICK_AXIS_INTERNAL( _joystick, _axis ) ) + + +//----------------------------------------------------------------------------- +// Enumeration for analog input devices. Includes joysticks, mousewheel, mouse +//----------------------------------------------------------------------------- +enum AnalogCode_t +{ + ANALOG_CODE_INVALID = -1, + MOUSE_X = 0, + MOUSE_Y, + MOUSE_XY, // Invoked when either x or y changes + MOUSE_WHEEL, + + JOYSTICK_FIRST_AXIS, + JOYSTICK_LAST_AXIS = JOYSTICK_AXIS_INTERNAL( MAX_JOYSTICKS-1, MAX_JOYSTICK_AXES-1 ), + + ANALOG_CODE_LAST, +}; + + +#endif // ANALOGCODE_H diff --git a/public/inputsystem/ButtonCode.h b/public/inputsystem/ButtonCode.h new file mode 100644 index 0000000..39dc7e0 --- /dev/null +++ b/public/inputsystem/ButtonCode.h @@ -0,0 +1,378 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef BUTTONCODE_H +#define BUTTONCODE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "inputsystem/InputEnums.h" +#include "mathlib/mathlib.h" + +//----------------------------------------------------------------------------- +// Button enum. "Buttons" are binary-state input devices (mouse buttons, keyboard keys) +//----------------------------------------------------------------------------- +enum +{ + JOYSTICK_MAX_BUTTON_COUNT = 32, + JOYSTICK_POV_BUTTON_COUNT = 4, + JOYSTICK_AXIS_BUTTON_COUNT = MAX_JOYSTICK_AXES * 2, +}; + +#define JOYSTICK_BUTTON_INTERNAL( _joystick, _button ) ( JOYSTICK_FIRST_BUTTON + ((_joystick) * JOYSTICK_MAX_BUTTON_COUNT) + (_button) ) +#define JOYSTICK_POV_BUTTON_INTERNAL( _joystick, _button ) ( JOYSTICK_FIRST_POV_BUTTON + ((_joystick) * JOYSTICK_POV_BUTTON_COUNT) + (_button) ) +#define JOYSTICK_AXIS_BUTTON_INTERNAL( _joystick, _button ) ( JOYSTICK_FIRST_AXIS_BUTTON + ((_joystick) * JOYSTICK_AXIS_BUTTON_COUNT) + (_button) ) + +#define JOYSTICK_BUTTON( _joystick, _button ) ( (ButtonCode_t)JOYSTICK_BUTTON_INTERNAL( _joystick, _button ) ) +#define JOYSTICK_POV_BUTTON( _joystick, _button ) ( (ButtonCode_t)JOYSTICK_POV_BUTTON_INTERNAL( _joystick, _button ) ) +#define JOYSTICK_AXIS_BUTTON( _joystick, _button ) ( (ButtonCode_t)JOYSTICK_AXIS_BUTTON_INTERNAL( _joystick, _button ) ) + +enum ButtonCode_t +{ + BUTTON_CODE_INVALID = -1, + BUTTON_CODE_NONE = 0, + + KEY_FIRST = 0, + + KEY_NONE = KEY_FIRST, + KEY_0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_PAD_0, + KEY_PAD_1, + KEY_PAD_2, + KEY_PAD_3, + KEY_PAD_4, + KEY_PAD_5, + KEY_PAD_6, + KEY_PAD_7, + KEY_PAD_8, + KEY_PAD_9, + KEY_PAD_DIVIDE, + KEY_PAD_MULTIPLY, + KEY_PAD_MINUS, + KEY_PAD_PLUS, + KEY_PAD_ENTER, + KEY_PAD_DECIMAL, + KEY_LBRACKET, + KEY_RBRACKET, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_BACKQUOTE, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_BACKSLASH, + KEY_MINUS, + KEY_EQUAL, + KEY_ENTER, + KEY_SPACE, + KEY_BACKSPACE, + KEY_TAB, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_ESCAPE, + KEY_SCROLLLOCK, + KEY_INSERT, + KEY_DELETE, + KEY_HOME, + KEY_END, + KEY_PAGEUP, + KEY_PAGEDOWN, + KEY_BREAK, + KEY_LSHIFT, + KEY_RSHIFT, + KEY_LALT, + KEY_RALT, + KEY_LCONTROL, + KEY_RCONTROL, + KEY_LWIN, + KEY_RWIN, + KEY_APP, + KEY_UP, + KEY_LEFT, + KEY_DOWN, + KEY_RIGHT, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_CAPSLOCKTOGGLE, + KEY_NUMLOCKTOGGLE, + KEY_SCROLLLOCKTOGGLE, + + KEY_LAST = KEY_SCROLLLOCKTOGGLE, + KEY_COUNT = KEY_LAST - KEY_FIRST + 1, + + // Mouse + MOUSE_FIRST = KEY_LAST + 1, + + MOUSE_LEFT = MOUSE_FIRST, + MOUSE_RIGHT, + MOUSE_MIDDLE, + MOUSE_4, + MOUSE_5, + MOUSE_WHEEL_UP, // A fake button which is 'pressed' and 'released' when the wheel is moved up + MOUSE_WHEEL_DOWN, // A fake button which is 'pressed' and 'released' when the wheel is moved down + + MOUSE_LAST = MOUSE_WHEEL_DOWN, + MOUSE_COUNT = MOUSE_LAST - MOUSE_FIRST + 1, + + // Joystick + JOYSTICK_FIRST = MOUSE_LAST + 1, + + JOYSTICK_FIRST_BUTTON = JOYSTICK_FIRST, + JOYSTICK_LAST_BUTTON = JOYSTICK_BUTTON_INTERNAL( MAX_JOYSTICKS-1, JOYSTICK_MAX_BUTTON_COUNT-1 ), + JOYSTICK_FIRST_POV_BUTTON, + JOYSTICK_LAST_POV_BUTTON = JOYSTICK_POV_BUTTON_INTERNAL( MAX_JOYSTICKS-1, JOYSTICK_POV_BUTTON_COUNT-1 ), + JOYSTICK_FIRST_AXIS_BUTTON, + JOYSTICK_LAST_AXIS_BUTTON = JOYSTICK_AXIS_BUTTON_INTERNAL( MAX_JOYSTICKS-1, JOYSTICK_AXIS_BUTTON_COUNT-1 ), + + JOYSTICK_LAST = JOYSTICK_LAST_AXIS_BUTTON, + +#if !defined ( _X360 ) + NOVINT_FIRST = JOYSTICK_LAST + 2, // plus 1 missing key. +1 seems to cause issues on the first button. + + NOVINT_LOGO_0 = NOVINT_FIRST, + NOVINT_TRIANGLE_0, + NOVINT_BOLT_0, + NOVINT_PLUS_0, + NOVINT_LOGO_1, + NOVINT_TRIANGLE_1, + NOVINT_BOLT_1, + NOVINT_PLUS_1, + + NOVINT_LAST = NOVINT_PLUS_1, +#endif + + BUTTON_CODE_LAST, + BUTTON_CODE_COUNT = BUTTON_CODE_LAST - KEY_FIRST + 1, + + // Helpers for XBox 360 + KEY_XBUTTON_UP = JOYSTICK_FIRST_POV_BUTTON, // POV buttons + KEY_XBUTTON_RIGHT, + KEY_XBUTTON_DOWN, + KEY_XBUTTON_LEFT, + + KEY_XBUTTON_A = JOYSTICK_FIRST_BUTTON, // Buttons + KEY_XBUTTON_B, + KEY_XBUTTON_X, + KEY_XBUTTON_Y, + KEY_XBUTTON_LEFT_SHOULDER, + KEY_XBUTTON_RIGHT_SHOULDER, + KEY_XBUTTON_BACK, + KEY_XBUTTON_START, + KEY_XBUTTON_STICK1, + KEY_XBUTTON_STICK2, + + KEY_XSTICK1_RIGHT = JOYSTICK_FIRST_AXIS_BUTTON, // XAXIS POSITIVE + KEY_XSTICK1_LEFT, // XAXIS NEGATIVE + KEY_XSTICK1_DOWN, // YAXIS POSITIVE + KEY_XSTICK1_UP, // YAXIS NEGATIVE + KEY_XBUTTON_LTRIGGER, // ZAXIS POSITIVE + KEY_XBUTTON_RTRIGGER, // ZAXIS NEGATIVE + KEY_XSTICK2_RIGHT, // UAXIS POSITIVE + KEY_XSTICK2_LEFT, // UAXIS NEGATIVE + KEY_XSTICK2_DOWN, // VAXIS POSITIVE + KEY_XSTICK2_UP, // VAXIS NEGATIVE +}; + +inline bool IsAlpha( ButtonCode_t code ) +{ + return ( code >= KEY_A ) && ( code <= KEY_Z ); +} + +inline bool IsAlphaNumeric( ButtonCode_t code ) +{ + return ( code >= KEY_0 ) && ( code <= KEY_Z ); +} + +inline bool IsSpace( ButtonCode_t code ) +{ + return ( code == KEY_ENTER ) || ( code == KEY_TAB ) || ( code == KEY_SPACE ); +} + +inline bool IsKeypad( ButtonCode_t code ) +{ + return ( code >= MOUSE_FIRST ) && ( code <= KEY_PAD_DECIMAL ); +} + +inline bool IsPunctuation( ButtonCode_t code ) +{ + return ( code >= KEY_0 ) && ( code <= KEY_SPACE ) && !IsAlphaNumeric( code ) && !IsSpace( code ) && !IsKeypad( code ); +} + +inline bool IsKeyCode( ButtonCode_t code ) +{ + return ( code >= KEY_FIRST ) && ( code <= KEY_LAST ); +} + +inline bool IsMouseCode( ButtonCode_t code ) +{ + return ( code >= MOUSE_FIRST ) && ( code <= MOUSE_LAST ); +} + +inline bool IsNovintCode( ButtonCode_t code ) +{ +#if !defined ( _X360 ) + return ( ( code >= NOVINT_FIRST ) && ( code <= NOVINT_LAST ) ); +#else + return false; +#endif +} + +inline bool IsNovintButtonCode( ButtonCode_t code ) +{ +#if !defined ( _X360 ) + return IsNovintCode( code ); +#else + return false; +#endif +} + +inline bool IsJoystickCode( ButtonCode_t code ) +{ + return ( ( ( code >= JOYSTICK_FIRST ) && ( code <= JOYSTICK_LAST ) ) || IsNovintCode( code ) ); +} + +inline bool IsJoystickButtonCode( ButtonCode_t code ) +{ + return ( ( ( code >= JOYSTICK_FIRST_BUTTON ) && ( code <= JOYSTICK_LAST_BUTTON ) ) || IsNovintButtonCode( code ) ); +} + +inline bool IsJoystickPOVCode( ButtonCode_t code ) +{ + return ( code >= JOYSTICK_FIRST_POV_BUTTON ) && ( code <= JOYSTICK_LAST_POV_BUTTON ); +} + +inline bool IsJoystickAxisCode( ButtonCode_t code ) +{ + return ( code >= JOYSTICK_FIRST_AXIS_BUTTON ) && ( code <= JOYSTICK_LAST_AXIS_BUTTON ); +} + +inline ButtonCode_t GetBaseButtonCode( ButtonCode_t code ) +{ + if ( IsJoystickButtonCode( code ) ) + { + int offset = ( code - JOYSTICK_FIRST_BUTTON ) % JOYSTICK_MAX_BUTTON_COUNT; + return (ButtonCode_t)( JOYSTICK_FIRST_BUTTON + offset ); + } + + if ( IsJoystickPOVCode( code ) ) + { + int offset = ( code - JOYSTICK_FIRST_POV_BUTTON ) % JOYSTICK_POV_BUTTON_COUNT; + return (ButtonCode_t)( JOYSTICK_FIRST_POV_BUTTON + offset ); + } + + if ( IsJoystickAxisCode( code ) ) + { + int offset = ( code - JOYSTICK_FIRST_AXIS_BUTTON ) % JOYSTICK_AXIS_BUTTON_COUNT; + return (ButtonCode_t)( JOYSTICK_FIRST_AXIS_BUTTON + offset ); + } + + return code; +} + +inline int GetJoystickForCode( ButtonCode_t code ) +{ + if ( !IsJoystickCode( code ) ) + return 0; + + if ( IsJoystickButtonCode( code ) ) + { + int offset = ( code - JOYSTICK_FIRST_BUTTON ) / JOYSTICK_MAX_BUTTON_COUNT; + return offset; + } + if ( IsJoystickPOVCode( code ) ) + { + int offset = ( code - JOYSTICK_FIRST_POV_BUTTON ) / JOYSTICK_POV_BUTTON_COUNT; + return offset; + } + if ( IsJoystickAxisCode( code ) ) + { + int offset = ( code - JOYSTICK_FIRST_AXIS_BUTTON ) / JOYSTICK_AXIS_BUTTON_COUNT; + return offset; + } + + return 0; +} + +inline ButtonCode_t ButtonCodeToJoystickButtonCode( ButtonCode_t code, int nDesiredJoystick ) +{ + if ( !IsJoystickCode( code ) || nDesiredJoystick == 0 ) + return code; + + nDesiredJoystick = ::clamp( nDesiredJoystick, 0, MAX_JOYSTICKS - 1 ); + + code = GetBaseButtonCode( code ); + + // Now upsample it + if ( IsJoystickButtonCode( code ) ) + { + int nOffset = code - JOYSTICK_FIRST_BUTTON; + return JOYSTICK_BUTTON( nDesiredJoystick, nOffset ); + } + + if ( IsJoystickPOVCode( code ) ) + { + int nOffset = code - JOYSTICK_FIRST_POV_BUTTON; + return JOYSTICK_POV_BUTTON( nDesiredJoystick, nOffset ); + } + + if ( IsJoystickAxisCode( code ) ) + { + int nOffset = code - JOYSTICK_FIRST_AXIS_BUTTON; + return JOYSTICK_AXIS_BUTTON( nDesiredJoystick, nOffset ); + } + + return code; +} + +#endif // BUTTONCODE_H diff --git a/public/inputsystem/InputEnums.h b/public/inputsystem/InputEnums.h new file mode 100644 index 0000000..4da6866 --- /dev/null +++ b/public/inputsystem/InputEnums.h @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef INPUTENUMS_H +#define INPUTENUMS_H +#ifdef _WIN32 +#pragma once +#endif + +// Standard maximum +/- value of a joystick axis +#define MAX_BUTTONSAMPLE 32768 + +#if !defined( _X360 ) +#define INVALID_USER_ID -1 +#else +#define INVALID_USER_ID XBX_INVALID_USER_ID +#endif + +//----------------------------------------------------------------------------- +// Forward declarations: +//----------------------------------------------------------------------------- + +enum +{ + MAX_JOYSTICKS = 1, + MOUSE_BUTTON_COUNT = 5, + MAX_NOVINT_DEVICES = 2, +}; + +#if defined( LINUX ) +// Linux has a slightly different mapping order on the joystick axes +enum JoystickAxis_t +{ + JOY_AXIS_X = 0, + JOY_AXIS_Y, + JOY_AXIS_Z, + JOY_AXIS_U, + JOY_AXIS_R, + JOY_AXIS_V, + MAX_JOYSTICK_AXES, +}; +#else +enum JoystickAxis_t +{ + JOY_AXIS_X = 0, + JOY_AXIS_Y, + JOY_AXIS_Z, + JOY_AXIS_R, + JOY_AXIS_U, + JOY_AXIS_V, + MAX_JOYSTICK_AXES, +}; +#endif + + + +//----------------------------------------------------------------------------- +// Extra mouse codes +//----------------------------------------------------------------------------- +enum +{ + MS_WM_XBUTTONDOWN = 0x020B, + MS_WM_XBUTTONUP = 0x020C, + MS_WM_XBUTTONDBLCLK = 0x020D, + MS_MK_BUTTON4 = 0x0020, + MS_MK_BUTTON5 = 0x0040, +}; + +//----------------------------------------------------------------------------- +// Events +//----------------------------------------------------------------------------- +enum InputEventType_t +{ + IE_ButtonPressed = 0, // m_nData contains a ButtonCode_t + IE_ButtonReleased, // m_nData contains a ButtonCode_t + IE_ButtonDoubleClicked, // m_nData contains a ButtonCode_t + IE_AnalogValueChanged, // m_nData contains an AnalogCode_t, m_nData2 contains the value + + IE_FirstSystemEvent = 100, + IE_Quit = IE_FirstSystemEvent, + IE_ControllerInserted, // m_nData contains the controller ID + IE_ControllerUnplugged, // m_nData contains the controller ID + + IE_FirstVguiEvent = 1000, // Assign ranges for other systems that post user events here + IE_FirstAppEvent = 2000, +}; + +struct InputEvent_t +{ + int m_nType; // Type of the event (see InputEventType_t) + int m_nTick; // Tick on which the event occurred + int m_nData; // Generic 32-bit data, what it contains depends on the event + int m_nData2; // Generic 32-bit data, what it contains depends on the event + int m_nData3; // Generic 32-bit data, what it contains depends on the event +}; + +#endif // INPUTENUMS_H diff --git a/public/inputsystem/iinputsystem.h b/public/inputsystem/iinputsystem.h new file mode 100644 index 0000000..ab408e0 --- /dev/null +++ b/public/inputsystem/iinputsystem.h @@ -0,0 +1,130 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef IINPUTSYSTEM_H +#define IINPUTSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "appframework/IAppSystem.h" + +#include "inputsystem/InputEnums.h" +#include "inputsystem/ButtonCode.h" +#include "inputsystem/AnalogCode.h" + +//----------------------------------------------------------------------------- +// Main interface for input. This is a low-level interface +//----------------------------------------------------------------------------- +#define INPUTSYSTEM_INTERFACE_VERSION "InputSystemVersion001" +abstract_class IInputSystem : public IAppSystem +{ +public: + // Attach, detach input system from a particular window + // This window should be the root window for the application + // Only 1 window should be attached at any given time. + virtual void AttachToWindow( void* hWnd ) = 0; + virtual void DetachFromWindow( ) = 0; + + // Enables/disables input. PollInputState will not update current + // button/analog states when it is called if the system is disabled. + virtual void EnableInput( bool bEnable ) = 0; + + // Enables/disables the windows message pump. PollInputState will not + // Peek/Dispatch messages if this is disabled + virtual void EnableMessagePump( bool bEnable ) = 0; + + // Polls the current input state + virtual void PollInputState() = 0; + + // Gets the time of the last polling in ms + virtual int GetPollTick() const = 0; + + // Is a button down? "Buttons" are binary-state input devices (mouse buttons, keyboard keys) + virtual bool IsButtonDown( ButtonCode_t code ) const = 0; + + // Returns the tick at which the button was pressed and released + virtual int GetButtonPressedTick( ButtonCode_t code ) const = 0; + virtual int GetButtonReleasedTick( ButtonCode_t code ) const = 0; + + // Gets the value of an analog input device this frame + // Includes joysticks, mousewheel, mouse + virtual int GetAnalogValue( AnalogCode_t code ) const = 0; + + // Gets the change in a particular analog input device this frame + // Includes joysticks, mousewheel, mouse + virtual int GetAnalogDelta( AnalogCode_t code ) const = 0; + + // Returns the input events since the last poll + virtual int GetEventCount() const = 0; + virtual const InputEvent_t* GetEventData( ) const = 0; + + // Posts a user-defined event into the event queue; this is expected + // to be called in overridden wndprocs connected to the root panel. + virtual void PostUserEvent( const InputEvent_t &event ) = 0; + + // Returns the number of joysticks + virtual int GetJoystickCount() const = 0; + + // Enable/disable joystick, it has perf costs + virtual void EnableJoystickInput( int nJoystick, bool bEnable ) = 0; + + // Enable/disable diagonal joystick POV (simultaneous POV buttons down) + virtual void EnableJoystickDiagonalPOV( int nJoystick, bool bEnable ) = 0; + + // Sample the joystick and append events to the input queue + virtual void SampleDevices( void ) = 0; + + // FIXME: Currently force-feedback is only supported on the Xbox 360 + virtual void SetRumble( float fLeftMotor, float fRightMotor, int userId = INVALID_USER_ID ) = 0; + virtual void StopRumble( void ) = 0; + + // Resets the input state + virtual void ResetInputState() = 0; + + // Sets a player as the primary user - all other controllers will be ignored. + virtual void SetPrimaryUserId( int userId ) = 0; + + // Convert back + forth between ButtonCode/AnalogCode + strings + virtual const char *ButtonCodeToString( ButtonCode_t code ) const = 0; + virtual const char *AnalogCodeToString( AnalogCode_t code ) const = 0; + virtual ButtonCode_t StringToButtonCode( const char *pString ) const = 0; + virtual AnalogCode_t StringToAnalogCode( const char *pString ) const = 0; + + // Sleeps until input happens. Pass a negative number to sleep infinitely + virtual void SleepUntilInput( int nMaxSleepTimeMS = -1 ) = 0; + + // Convert back + forth between virtual codes + button codes + // FIXME: This is a temporary piece of code + virtual ButtonCode_t VirtualKeyToButtonCode( int nVirtualKey ) const = 0; + virtual int ButtonCodeToVirtualKey( ButtonCode_t code ) const = 0; + virtual ButtonCode_t ScanCodeToButtonCode( int lParam ) const = 0; + + // How many times have we called PollInputState? + virtual int GetPollCount() const = 0; + + // Sets the cursor position + virtual void SetCursorPosition( int x, int y ) = 0; + + // NVNT get address to haptics interface + virtual void *GetHapticsInterfaceAddress() const = 0; + + virtual void SetNovintPure( bool bPure ) = 0; + + // read and clear accumulated raw input values + virtual bool GetRawMouseAccumulators( int& accumX, int& accumY ) = 0; + + // tell the input system that we're not a game, we're console text mode. + // this is used for dedicated servers to not initialize joystick system. + // this needs to be called before CInputSystem::Init (e.g. in PreInit of + // some system) if you want ot prevent the joystick system from ever + // being initialized. + virtual void SetConsoleTextMode( bool bConsoleTextMode ) = 0; +}; + + +#endif // IINPUTSYSTEM_H diff --git a/public/interpolatortypes.cpp b/public/interpolatortypes.cpp new file mode 100644 index 0000000..e8227ed --- /dev/null +++ b/public/interpolatortypes.cpp @@ -0,0 +1,506 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "basetypes.h" +#include "tier1/strtools.h" +#include "interpolatortypes.h" +#include "tier0/dbg.h" +#include "mathlib/mathlib.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +struct InterpolatorNameMap_t +{ + int type; + char const *name; + char const *printname; +}; + +static InterpolatorNameMap_t g_InterpolatorNameMap[] = +{ + { INTERPOLATE_DEFAULT, "default", "Default" }, + { INTERPOLATE_CATMULL_ROM_NORMALIZEX, "catmullrom_normalize_x", "Catmull-Rom (Norm X)" }, + { INTERPOLATE_EASE_IN, "easein", "Ease In" }, + { INTERPOLATE_EASE_OUT, "easeout", "Ease Out" }, + { INTERPOLATE_EASE_INOUT, "easeinout", "Ease In/Out" }, + { INTERPOLATE_BSPLINE, "bspline", "B-Spline" }, + { INTERPOLATE_LINEAR_INTERP, "linear_interp", "Linear Interp." }, + { INTERPOLATE_KOCHANEK_BARTELS, "kochanek", "Kochanek-Bartels" }, + { INTERPOLATE_KOCHANEK_BARTELS_EARLY, "kochanek_early", "Kochanek-Bartels Early" }, + { INTERPOLATE_KOCHANEK_BARTELS_LATE, "kochanek_late", "Kochanek-Bartels Late" }, + { INTERPOLATE_SIMPLE_CUBIC, "simple_cubic", "Simple Cubic" }, + { INTERPOLATE_CATMULL_ROM, "catmullrom", "Catmull-Rom" }, + { INTERPOLATE_CATMULL_ROM_NORMALIZE, "catmullrom_normalize", "Catmull-Rom (Norm)" }, + { INTERPOLATE_CATMULL_ROM_TANGENT, "catmullrom_tangent", "Catmull-Rom (Tangent)" }, + { INTERPOLATE_EXPONENTIAL_DECAY, "exponential_decay", "Exponential Decay" }, + { INTERPOLATE_HOLD, "hold", "Hold" }, +}; + +int Interpolator_InterpolatorForName( char const *name ) +{ + for ( int i = 0; i < NUM_INTERPOLATE_TYPES; ++i ) + { + InterpolatorNameMap_t *slot = &g_InterpolatorNameMap[ i ]; + if ( !Q_stricmp( name, slot->name ) ) + return slot->type; + } + + Assert( !"Interpolator_InterpolatorForName failed!!!" ); + return INTERPOLATE_DEFAULT; +} + +char const *Interpolator_NameForInterpolator( int type, bool printname ) +{ + int i = (int)type; + int c = ARRAYSIZE( g_InterpolatorNameMap ); + if ( i < 0 || i >= c ) + { + Assert( "!Interpolator_NameForInterpolator: bogus type!" ); + // returns "unspecified!!!"; + return printname ? g_InterpolatorNameMap[ 0 ].printname : g_InterpolatorNameMap[ 0 ].name; + } + + return printname ? g_InterpolatorNameMap[ i ].printname : g_InterpolatorNameMap[ i ].name; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct CurveNameMap_t +{ + int type; + int hotkey; +}; + +static CurveNameMap_t g_CurveNameMap[] = +{ + { CURVE_CATMULL_ROM_TO_CATMULL_ROM, '1' }, + { CURVE_EASE_IN_TO_EASE_OUT, '2' }, + { CURVE_EASE_IN_TO_EASE_IN, '3' }, + { CURVE_EASE_OUT_TO_EASE_OUT, '4' }, + { CURVE_BSPLINE_TO_BSPLINE, '5' }, + { CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, '6' }, + { CURVE_KOCHANEK_BARTELS_TO_KOCHANEK_BARTELS, '7' }, + { CURVE_KOCHANEK_BARTELS_EARLY_TO_KOCHANEK_BARTELS_EARLY, '8' }, + { CURVE_KOCHANEK_BARTELS_LATE_TO_KOCHANEK_BARTELS_LATE, '9' }, + { CURVE_SIMPLE_CUBIC_TO_SIMPLE_CUBIC, '0' }, +}; + +// Turn enum into string and vice versa +int Interpolator_CurveTypeForName( const char *name ) +{ + char sz[ 128 ]; + Q_strncpy( sz, name, sizeof( sz ) ); + + int leftcurve = 0; + int rightcurve = 0; + + int skip = Q_strlen( "curve_" ); + + if ( !Q_strnicmp( sz, "curve_", skip ) ) + { + char *p = sz + skip; + char *second = Q_stristr( p, "_to_curve_" ); + + char save = *second; + *second = 0; + + leftcurve = Interpolator_InterpolatorForName( p ); + + *second = save; + + p = second + Q_strlen( "_to_curve_" ); + + rightcurve = Interpolator_InterpolatorForName( p ); + } + + return MAKE_CURVE_TYPE( leftcurve, rightcurve ); +} + +const char *Interpolator_NameForCurveType( int type, bool printname ) +{ + static char outname[ 256 ]; + + int leftside = GET_LEFT_CURVE( type ); + int rightside = GET_RIGHT_CURVE( type ); + + if ( !printname ) + { + Q_snprintf( outname, sizeof( outname ), "curve_%s_to_curve_%s", + Interpolator_NameForInterpolator( leftside, printname ), + Interpolator_NameForInterpolator( rightside, printname ) ); + } + else + { + Q_snprintf( outname, sizeof( outname ), "%s <-> %s", + Interpolator_NameForInterpolator( leftside, printname ), + Interpolator_NameForInterpolator( rightside, printname ) ); + } + + return outname; +} + +void Interpolator_CurveInterpolatorsForType( int type, int& inbound, int& outbound ) +{ + inbound = GET_LEFT_CURVE( type ); + outbound = GET_RIGHT_CURVE( type ); +} + +int Interpolator_CurveTypeForHotkey( int key ) +{ + int c = ARRAYSIZE( g_CurveNameMap ); + for ( int i = 0; i < c; ++i ) + { + CurveNameMap_t *slot = &g_CurveNameMap[ i ]; + if ( slot->hotkey == key ) + return slot->type; + } + + return -1; +} + +void Interpolator_GetKochanekBartelsParams( int interpolationType, float& tension, float& bias, float& continuity ) +{ + switch ( interpolationType ) + { + default: + tension = 0.0f; + bias = 0.0f; + continuity = 0.0f; + Assert( 0 ); + break; + case INTERPOLATE_KOCHANEK_BARTELS: + tension = 0.77f; + bias = 0.0f; + continuity = 0.77f; + break; + case INTERPOLATE_KOCHANEK_BARTELS_EARLY: + tension = 0.77f; + bias = -1.0f; + continuity = 0.77f; + break; + case INTERPOLATE_KOCHANEK_BARTELS_LATE: + tension = 0.77f; + bias = 1.0f; + continuity = 0.77f; + break; + } +} + +void Interpolator_CurveInterpolate( int interpolationType, + const Vector &vPre, + const Vector &vStart, + const Vector &vEnd, + const Vector &vNext, + float f, + Vector &vOut ) +{ + vOut.Init(); + + switch ( interpolationType ) + { + default: + Warning( "Unknown interpolation type %d\n", + (int)interpolationType ); + // break; // Fall through and use catmull_rom as default + case INTERPOLATE_DEFAULT: + case INTERPOLATE_CATMULL_ROM_NORMALIZEX: + Catmull_Rom_Spline_NormalizeX( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_CATMULL_ROM: + Catmull_Rom_Spline( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_CATMULL_ROM_NORMALIZE: + Catmull_Rom_Spline_Normalize( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_CATMULL_ROM_TANGENT: + Catmull_Rom_Spline_Tangent( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_EASE_IN: + { + f = sin( M_PI * f * 0.5f ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_EASE_OUT: + { + f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_EASE_INOUT: + { + f = SimpleSpline( f ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_LINEAR_INTERP: + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + break; + case INTERPOLATE_KOCHANEK_BARTELS: + case INTERPOLATE_KOCHANEK_BARTELS_EARLY: + case INTERPOLATE_KOCHANEK_BARTELS_LATE: + { + float t, b, c; + Interpolator_GetKochanekBartelsParams( interpolationType, t, b, c ); + Kochanek_Bartels_Spline_NormalizeX + ( + t, b, c, + vPre, + vStart, + vEnd, + vNext, + f, + vOut + ); + } + break; + case INTERPOLATE_SIMPLE_CUBIC: + Cubic_Spline_NormalizeX( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_BSPLINE: + BSpline( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_EXPONENTIAL_DECAY: + { + float dt = vEnd.x - vStart.x; + if ( dt > 0.0f ) + { + float val = 1.0f - ExponentialDecay( 0.001, dt, f * dt ); + vOut.y = vStart.y + val * ( vEnd.y - vStart.y ); + } + else + { + vOut.y = vStart.y; + } + } + break; + case INTERPOLATE_HOLD: + { + vOut.y = vStart.y; + } + break; + } +} + +void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, + const Vector &vPre, + const Vector &vStart, + const Vector &vEnd, + const Vector &vNext, + float f, + Vector &vOut ) +{ + vOut.Init(); + + switch ( interpolationType ) + { + default: + Warning( "Unknown interpolation type %d\n", + (int)interpolationType ); + // break; // Fall through and use catmull_rom as default + case INTERPOLATE_CATMULL_ROM_NORMALIZEX: + case INTERPOLATE_DEFAULT: + case INTERPOLATE_CATMULL_ROM: + case INTERPOLATE_CATMULL_ROM_NORMALIZE: + case INTERPOLATE_CATMULL_ROM_TANGENT: + Catmull_Rom_Spline( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_EASE_IN: + { + f = sin( M_PI * f * 0.5f ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_EASE_OUT: + { + f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_EASE_INOUT: + { + f = SimpleSpline( f ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_LINEAR_INTERP: + // Fixme, since this ignores vPre and vNext we could omit computing them aove + VectorLerp( vStart, vEnd, f, vOut ); + break; + case INTERPOLATE_KOCHANEK_BARTELS: + case INTERPOLATE_KOCHANEK_BARTELS_EARLY: + case INTERPOLATE_KOCHANEK_BARTELS_LATE: + { + float t, b, c; + Interpolator_GetKochanekBartelsParams( interpolationType, t, b, c ); + Kochanek_Bartels_Spline + ( + t, b, c, + vPre, + vStart, + vEnd, + vNext, + f, + vOut + ); + } + break; + case INTERPOLATE_SIMPLE_CUBIC: + Cubic_Spline( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_BSPLINE: + BSpline( + vPre, + vStart, + vEnd, + vNext, + f, + vOut ); + break; + case INTERPOLATE_EXPONENTIAL_DECAY: + { + float dt = vEnd.x - vStart.x; + if ( dt > 0.0f ) + { + float val = 1.0f - ExponentialDecay( 0.001, dt, f * dt ); + vOut.y = vStart.y + val * ( vEnd.y - vStart.y ); + } + else + { + vOut.y = vStart.y; + } + } + break; + case INTERPOLATE_HOLD: + { + vOut.y = vStart.y; + } + break; + } +} + + +void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, + const Quaternion &vPre, + const Quaternion &vStart, + const Quaternion &vEnd, + const Quaternion &vNext, + float f, + Quaternion &vOut ) +{ + vOut.Init(); + + switch ( interpolationType ) + { + default: + Warning( "Unknown interpolation type %d\n", + (int)interpolationType ); + // break; // Fall through and use catmull_rom as default + case INTERPOLATE_CATMULL_ROM_NORMALIZEX: + case INTERPOLATE_DEFAULT: + case INTERPOLATE_CATMULL_ROM: + case INTERPOLATE_CATMULL_ROM_NORMALIZE: + case INTERPOLATE_CATMULL_ROM_TANGENT: + case INTERPOLATE_KOCHANEK_BARTELS: + case INTERPOLATE_KOCHANEK_BARTELS_EARLY: + case INTERPOLATE_KOCHANEK_BARTELS_LATE: + case INTERPOLATE_SIMPLE_CUBIC: + case INTERPOLATE_BSPLINE: + // FIXME, since this ignores vPre and vNext we could omit computing them aove + QuaternionSlerp( vStart, vEnd, f, vOut ); + break; + case INTERPOLATE_EASE_IN: + { + f = sin( M_PI * f * 0.5f ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + QuaternionSlerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_EASE_OUT: + { + f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + QuaternionSlerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_EASE_INOUT: + { + f = SimpleSpline( f ); + // Fixme, since this ignores vPre and vNext we could omit computing them aove + QuaternionSlerp( vStart, vEnd, f, vOut ); + } + break; + case INTERPOLATE_LINEAR_INTERP: + // Fixme, since this ignores vPre and vNext we could omit computing them aove + QuaternionSlerp( vStart, vEnd, f, vOut ); + break; + case INTERPOLATE_EXPONENTIAL_DECAY: + vOut.Init(); + break; + case INTERPOLATE_HOLD: + { + vOut = vStart; + } + break; + } +} \ No newline at end of file diff --git a/public/interpolatortypes.h b/public/interpolatortypes.h new file mode 100644 index 0000000..74c667a --- /dev/null +++ b/public/interpolatortypes.h @@ -0,0 +1,102 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef INTERPOLATORTYPES_H +#define INTERPOLATORTYPES_H +#ifdef _WIN32 +#pragma once +#endif + +class Quaternion; + +enum +{ + INTERPOLATE_DEFAULT = 0, + INTERPOLATE_CATMULL_ROM_NORMALIZEX, + INTERPOLATE_EASE_IN, + INTERPOLATE_EASE_OUT, + INTERPOLATE_EASE_INOUT, + INTERPOLATE_BSPLINE, + INTERPOLATE_LINEAR_INTERP, + INTERPOLATE_KOCHANEK_BARTELS, + INTERPOLATE_KOCHANEK_BARTELS_EARLY, + INTERPOLATE_KOCHANEK_BARTELS_LATE, + INTERPOLATE_SIMPLE_CUBIC, + + INTERPOLATE_CATMULL_ROM, + INTERPOLATE_CATMULL_ROM_NORMALIZE, + INTERPOLATE_CATMULL_ROM_TANGENT, + + INTERPOLATE_EXPONENTIAL_DECAY, + + INTERPOLATE_HOLD, + + NUM_INTERPOLATE_TYPES, +}; + +#define MAKE_CURVE_TYPE( left, right ) ( ( right ) & 0xff ) | ( ( ( left ) & 0xff ) << 8 ) + +#define GET_RIGHT_CURVE(w) ( ( w ) & 0xff ) +#define GET_LEFT_CURVE(w) ( ( ( w ) >> 8) & 0xff ) + +// Presets used by faceposer +enum +{ + CURVE_DEFAULT = MAKE_CURVE_TYPE( INTERPOLATE_DEFAULT, INTERPOLATE_DEFAULT ), + CURVE_CATMULL_ROM_TO_CATMULL_ROM = MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX , INTERPOLATE_CATMULL_ROM_NORMALIZEX ), // hotkey 1 + CURVE_EASE_IN_TO_EASE_OUT = MAKE_CURVE_TYPE( INTERPOLATE_EASE_IN, INTERPOLATE_EASE_OUT ), // hotkey 2 + CURVE_EASE_IN_TO_EASE_IN = MAKE_CURVE_TYPE( INTERPOLATE_EASE_IN, INTERPOLATE_EASE_IN ), + CURVE_EASE_OUT_TO_EASE_OUT = MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_OUT ), + CURVE_BSPLINE_TO_BSPLINE = MAKE_CURVE_TYPE( INTERPOLATE_BSPLINE, INTERPOLATE_BSPLINE ), + CURVE_LINEAR_INTERP_TO_LINEAR_INTERP = MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ), + CURVE_KOCHANEK_BARTELS_TO_KOCHANEK_BARTELS = MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ), + CURVE_KOCHANEK_BARTELS_EARLY_TO_KOCHANEK_BARTELS_EARLY = MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS_EARLY, INTERPOLATE_KOCHANEK_BARTELS_EARLY ), + CURVE_KOCHANEK_BARTELS_LATE_TO_KOCHANEK_BARTELS_LATE = MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS_LATE, INTERPOLATE_KOCHANEK_BARTELS_LATE ), + CURVE_SIMPLE_CUBIC_TO_SIMPLE_CUBIC = MAKE_CURVE_TYPE( INTERPOLATE_SIMPLE_CUBIC, INTERPOLATE_SIMPLE_CUBIC ), + CURVE_LINEAR_TO_HOLD = MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_HOLD ), + CURVE_HOLD_TO_LINEAR = MAKE_CURVE_TYPE( INTERPOLATE_HOLD, INTERPOLATE_LINEAR_INTERP ), +}; + +// Turn enum into string and vice versa +int Interpolator_CurveTypeForName( const char *name ); +const char *Interpolator_NameForCurveType( int type, bool printname ); +void Interpolator_CurveInterpolatorsForType( int type, int& inbound, int& outbound ); +int Interpolator_CurveTypeForHotkey( int key ); + +int Interpolator_InterpolatorForName( char const *name ); +char const *Interpolator_NameForInterpolator( int type, bool printname ); + +void Interpolator_GetKochanekBartelsParams( int interpolatorType, float& tension, float& bias, float& continuity ); + +class Vector; +// Main spline interpolation function, assumes .x holds time and .y holds one dimensional value +void Interpolator_CurveInterpolate( int interpolationType, + const Vector &vPre, + const Vector &vStart, + const Vector &vEnd, + const Vector &vNext, + float f, + Vector &vOut ); + +// Main spline interpolation function for Vectors, doesn't assume time is in .x and doesn't do normalization +void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, + const Vector &vPre, + const Vector &vStart, + const Vector &vEnd, + const Vector &vNext, + float f, + Vector &vOut ); + +// Main spline interpolation function for Vectors, doesn't assume time is in .x and doesn't do normalization +void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, + const Quaternion &vPre, + const Quaternion &vStart, + const Quaternion &vEnd, + const Quaternion &vNext, + float f, + Quaternion &vOut ); + +#endif // INTERPOLATORTYPES_H diff --git a/public/iprediction.h b/public/iprediction.h new file mode 100644 index 0000000..858bff3 --- /dev/null +++ b/public/iprediction.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IPREDICTION_H ) +#define IPREDICTION_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "interface.h" +#include "mathlib/vector.h" // Solely to get at define for QAngle + + +class IMoveHelper; + +//----------------------------------------------------------------------------- +// Purpose: Engine interface into client side prediction system +//----------------------------------------------------------------------------- +abstract_class IPrediction +{ +public: + virtual ~IPrediction( void ) {}; + + virtual void Init( void ) = 0; + virtual void Shutdown( void ) = 0; + + // Run prediction + virtual void Update + ( + int startframe, // World update ( un-modded ) most recently received + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ) = 0; + + // We are about to get a network update from the server. We know the update #, so we can pull any + // data purely predicted on the client side and transfer it to the new from data state. + virtual void PreEntityPacketReceived( int commands_acknowledged, int current_world_update_packet ) = 0; + virtual void PostEntityPacketReceived( void ) = 0; + virtual void PostNetworkDataReceived( int commands_acknowledged ) = 0; + + virtual void OnReceivedUncompressedPacket( void ) = 0; + + // The engine needs to be able to access a few predicted values + virtual void GetViewOrigin( Vector& org ) = 0; + virtual void SetViewOrigin( Vector& org ) = 0; + virtual void GetViewAngles( QAngle& ang ) = 0; + virtual void SetViewAngles( QAngle& ang ) = 0; + virtual void GetLocalViewAngles( QAngle& ang ) = 0; + virtual void SetLocalViewAngles( QAngle& ang ) = 0; +}; + +extern IPrediction *g_pClientSidePrediction; + +#define VCLIENT_PREDICTION_INTERFACE_VERSION "VClientPrediction001" + +#endif // IPREDICTION_H diff --git a/public/irecipientfilter.h b/public/irecipientfilter.h new file mode 100644 index 0000000..001e0ce --- /dev/null +++ b/public/irecipientfilter.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IRECIPIENTFILTER_H +#define IRECIPIENTFILTER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Generic interface for routing messages to users +//----------------------------------------------------------------------------- +class IRecipientFilter +{ +public: + virtual ~IRecipientFilter() {} + + virtual bool IsReliable( void ) const = 0; + virtual bool IsInitMessage( void ) const = 0; + + virtual int GetRecipientCount( void ) const = 0; + virtual int GetRecipientIndex( int slot ) const = 0; +}; + +#endif // IRECIPIENTFILTER_H diff --git a/public/iregistry.h b/public/iregistry.h new file mode 100644 index 0000000..9280680 --- /dev/null +++ b/public/iregistry.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#if !defined( UTIL_REGISTRY_H ) +#define UTIL_REGISTRY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + + +//----------------------------------------------------------------------------- +// Purpose: Interface to registry +//----------------------------------------------------------------------------- +abstract_class IRegistry +{ +public: + // We have to have a virtual destructor since otherwise the derived class destructors + // will not be called. + virtual ~IRegistry() {} + + // Init/shutdown + virtual bool Init( const char *platformName ) = 0; + virtual void Shutdown( void ) = 0; + + // Read/write integers + virtual int ReadInt( const char *key, int defaultValue = 0 ) = 0; + virtual void WriteInt( const char *key, int value ) = 0; + + // Read/write strings + virtual const char *ReadString( const char *key, const char *defaultValue = 0 ) = 0; + virtual void WriteString( const char *key, const char *value ) = 0; + + // Read/write helper methods + virtual int ReadInt( const char *pKeyBase, const char *pKey, int defaultValue = 0 ) = 0; + virtual void WriteInt( const char *pKeyBase, const char *key, int value ) = 0; + virtual const char *ReadString( const char *pKeyBase, const char *key, const char *defaultValue ) = 0; + virtual void WriteString( const char *pKeyBase, const char *key, const char *value ) = 0; +}; + +extern IRegistry *registry; + +// Creates it and calls Init +IRegistry *InstanceRegistry( char const *subDirectoryUnderValve ); +// Calls Shutdown and deletes it +void ReleaseInstancedRegistry( IRegistry *reg ); + +#endif // UTIL_REGISTRY_H diff --git a/public/isaverestore.h b/public/isaverestore.h new file mode 100644 index 0000000..bfb40a1 --- /dev/null +++ b/public/isaverestore.h @@ -0,0 +1,387 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISAVERESTORE_H +#define ISAVERESTORE_H + +#include "string_t.h" +#include "datamap.h" +#include "mathlib/vmatrix.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifndef CLIENT_DLL +class SINGLE_INHERITANCE CBaseEntity; +#endif + +class Vector; +class VMatrix; +struct edict_t; +template< class T > class CHandle; +typedef CHandle EHANDLE; +struct matrix3x4_t; + +class CSaveRestoreData; +class CGameSaveRestoreInfo; + +class ISave; +class IRestore; + +//----------------------------------------------------------------------------- + +#pragma pack(push,1) + +struct SaveRestoreRecordHeader_t +{ + unsigned short size; + unsigned short symbol; +}; + + +#pragma pack(pop) + +//----------------------------------------------------------------------------- +// +// ISaveRestoreBlockHandler +// +//----------------------------------------------------------------------------- + +const int MAX_BLOCK_NAME_LEN = 31; +const int SIZE_BLOCK_NAME_BUF = 31 + 1; + +//------------------------------------- + +abstract_class ISaveRestoreBlockHandler +{ +public: + virtual const char *GetBlockName() = 0; + + virtual void PreSave( CSaveRestoreData * ) = 0; // Called immediately prior to save, generally used to set up any necessary tables + virtual void Save( ISave * ) = 0; + virtual void WriteSaveHeaders( ISave * ) = 0; // Called after save to allow the writing out of any dictionaries/tables/indexes generated during save + virtual void PostSave() = 0; + + virtual void PreRestore() = 0; + virtual void ReadRestoreHeaders( IRestore * ) = 0; // Called prior to Restore() + virtual void Restore( IRestore *, bool fCreatePlayers ) = 0; + virtual void PostRestore() = 0; +}; + +//------------------------------------- + +abstract_class ISaveRestoreBlockSet : public ISaveRestoreBlockHandler +{ +public: + virtual void AddBlockHandler( ISaveRestoreBlockHandler *pHandler ) = 0; + virtual void RemoveBlockHandler( ISaveRestoreBlockHandler *pHandler ) = 0; + virtual void CallBlockHandlerRestore( ISaveRestoreBlockHandler *pHandler, int baseFilePos, IRestore *pRestore, bool fCreatePlayers ) = 0; +}; + +extern ISaveRestoreBlockSet *g_pGameSaveRestoreBlockSet; + +//------------------------------------- + +abstract_class CDefSaveRestoreBlockHandler : public ISaveRestoreBlockHandler +{ + virtual const char *GetBlockName() = 0; + + virtual void PreSave( CSaveRestoreData * ) {} + virtual void Save( ISave * ) {} + virtual void WriteSaveHeaders( ISave * ) {} + virtual void PostSave() {} + + virtual void PreRestore() {} + virtual void ReadRestoreHeaders( IRestore * ) {} + virtual void Restore( IRestore *, bool fCreatePlayers ) {} + virtual void PostRestore() {} +}; + +//----------------------------------------------------------------------------- +// +// ISave +// +//----------------------------------------------------------------------------- + +abstract_class ISave +{ +public: + + //--------------------------------- + // Logging + virtual void StartLogging( const char *pszLogName ) = 0; + virtual void EndLogging( void ) = 0; + + //--------------------------------- + virtual bool IsAsync() = 0; + + //--------------------------------- + + virtual int GetWritePos() const = 0; + virtual void SetWritePos(int pos) = 0; + + //--------------------------------- + // Datamap based writing + // + + virtual int WriteAll( const void *pLeafObject, datamap_t *pLeafMap ) = 0; + virtual int WriteFields( const char *pname, const void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount ) = 0; + + template + int WriteAll( const T *pLeafObject ) + { + return WriteAll( pLeafObject, &pLeafObject->m_DataMap ); + } + + //--------------------------------- + // Block support + // + // Using these, one doesn't have to worry about queuing up the read pointer on restore if only + // a subset of the data is read + // + + virtual void StartBlock( const char *pszBlockName ) = 0; + virtual void StartBlock() = 0; + virtual void EndBlock() = 0; + + //--------------------------------- + // Primitive types + // + + virtual void WriteShort( const short *value, int count = 1 ) = 0; + virtual void WriteInt( const int *value, int count = 1 ) = 0; // Save an int + inline void WriteInt( const unsigned *value, int count = 1 ) { WriteInt( (int *)value, count ); } + virtual void WriteBool( const bool *value, int count = 1 ) = 0; // Save a bool + virtual void WriteFloat( const float *value, int count = 1 ) = 0; // Save a float + virtual void WriteData( const char *pdata, int size ) = 0; // Save a binary data block + virtual void WriteString( const char *pstring ) = 0; // Save a null-terminated string + virtual void WriteString( const string_t *stringId, int count = 1 ) = 0; // Save a null-terminated string (engine string) + virtual void WriteVector( const Vector &value ) = 0; // Save a vector + virtual void WriteVector( const Vector *value, int count = 1 ) = 0; // Save a vector array + virtual void WriteQuaternion( const Quaternion &value ) = 0; // Save a Quaternion + virtual void WriteQuaternion( const Quaternion *value, int count = 1 ) = 0; // Save a Quaternion array + + // Note: All of the following will write out both a header and the data. On restore, + // this needs to be cracked + virtual void WriteShort( const char *pname, const short *value, int count = 1 ) = 0; + virtual void WriteInt( const char *pname, const int *value, int count = 1 ) = 0; // Save an int + virtual void WriteBool( const char *pname, const bool *value, int count = 1 ) = 0; // Save a bool + virtual void WriteFloat( const char *pname, const float *value, int count = 1 ) = 0; // Save a float + virtual void WriteData( const char *pname, int size, const char *pdata ) = 0; // Save a binary data block + virtual void WriteString( const char *pname, const char *pstring ) = 0; // Save a null-terminated string + virtual void WriteString( const char *pname, const string_t *stringId, int count = 1 ) = 0; // Save a null-terminated string (engine string) + virtual void WriteVector( const char *pname, const Vector &value ) = 0; // Save a vector + virtual void WriteVector( const char *pname, const Vector *value, int count = 1 ) = 0; // Save a vector array + virtual void WriteQuaternion( const char *pname, const Quaternion &value ) = 0; // Save a Quaternion + virtual void WriteQuaternion( const char *pname, const Quaternion *value, int count = 1 ) = 0; // Save a Quaternion array + + //--------------------------------- + // Game types + // + + virtual void WriteTime( const char *pname, const float *value, int count = 1 ) = 0; // Save a float (timevalue) + virtual void WriteTick( const char *pname, const int *value, int count = 1 ) = 0; // Save a tick (timevalue) + virtual void WritePositionVector( const char *pname, const Vector &value ) = 0; // Offset for landmark if necessary + virtual void WritePositionVector( const char *pname, const Vector *value, int count = 1 ) = 0; // array of pos vectors + virtual void WriteFunction( datamap_t *pMap, const char *pname, inputfunc_t **value, int count = 1 ) = 0; // Save a function pointer + + virtual void WriteTime( const float *value, int count = 1 ) = 0; // Save a float (timevalue) + virtual void WriteTick( const int *value, int count = 1 ) = 0; // Save a tick (timevalue) + virtual void WritePositionVector( const Vector &value ) = 0; // Offset for landmark if necessary + virtual void WritePositionVector( const Vector *value, int count = 1 ) = 0; // array of pos vectors + + virtual void WriteEntityPtr( const char *pname, CBaseEntity **ppEntity, int count = 1 ) = 0; + virtual void WriteEdictPtr( const char *pname, edict_t **ppEdict, int count = 1 ) = 0; + virtual void WriteEHandle( const char *pname, const EHANDLE *pEHandle, int count = 1 ) = 0; + + virtual void WriteEntityPtr( CBaseEntity **ppEntity, int count = 1 ) = 0; + virtual void WriteEdictPtr( edict_t **ppEdict, int count = 1 ) = 0; + virtual void WriteEHandle( const EHANDLE *pEHandle, int count = 1 ) = 0; + + //--------------------------------- + // Back door to support somewhat awkward ownership of game save/restore data + virtual CGameSaveRestoreInfo *GetGameSaveRestoreInfo() = 0; + +protected: + virtual ~ISave() {}; +}; + +//----------------------------------------------------------------------------- +// +// IRestore +// +//----------------------------------------------------------------------------- + +abstract_class IRestore +{ +public: + + //--------------------------------- + + virtual int GetReadPos() const = 0; + virtual void SetReadPos( int pos ) = 0; + + //--------------------------------- + // Datamap based reading + // + + virtual int ReadAll( void *pLeafObject, datamap_t *pLeafMap ) = 0; + + virtual int ReadFields( const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldcount = 1 ) = 0; + virtual void EmptyFields( void *pBaseData, typedescription_t *pFields, int fieldcount = 1 ) = 0; + + template + int ReadAll( T *pLeafObject ) + { + return ReadAll( pLeafObject, &pLeafObject->m_DataMap ); + } + + //--------------------------------- + // Block support + // + + virtual void StartBlock( SaveRestoreRecordHeader_t *pHeader ) = 0; + virtual void StartBlock( char szBlockName[SIZE_BLOCK_NAME_BUF] ) = 0; + virtual void StartBlock() = 0; + virtual void EndBlock() = 0; + + //--------------------------------- + // Field header cracking + // + + virtual void ReadHeader( SaveRestoreRecordHeader_t *pheader ) = 0; + virtual int SkipHeader() = 0; // skips the header, but returns the size of the field + virtual const char *StringFromHeaderSymbol( int symbol ) = 0; + + //--------------------------------- + // Primitive types + // + + virtual short ReadShort( void ) = 0; + virtual int ReadShort( short *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadInt( int *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + inline int ReadInt( unsigned *pValue, int count = 1, int nBytesAvailable = 0 ) { return ReadInt( (int *)pValue, count, nBytesAvailable ); } + virtual int ReadInt( void ) = 0; + virtual int ReadBool( bool *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadFloat( float *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadData( char *pData, int size, int nBytesAvailable ) = 0; + virtual void ReadString( char *pDest, int nSizeDest, int nBytesAvailable ) = 0; // A null-terminated string + virtual int ReadString( string_t *pString, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadVector( Vector *pValue ) = 0; + virtual int ReadVector( Vector *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadQuaternion( Quaternion *pValue ) = 0; + virtual int ReadQuaternion( Quaternion *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + + //--------------------------------- + // Game types + // + + virtual int ReadTime( float *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadTick( int *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadPositionVector( Vector *pValue ) = 0; + virtual int ReadPositionVector( Vector *pValue, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadFunction( datamap_t *pMap, inputfunc_t **pValue, int count = 1, int nBytesAvailable = 0) = 0; + + virtual int ReadEntityPtr( CBaseEntity **ppEntity, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadEdictPtr( edict_t **ppEdict, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadEHandle( EHANDLE *pEHandle, int count = 1, int nBytesAvailable = 0 ) = 0; + virtual int ReadVMatrix( VMatrix *pValue, int count = 1, int nBytesAvailable = 0) = 0; + virtual int ReadVMatrixWorldspace( VMatrix *pValue, int count = 1, int nBytesAvailable = 0) = 0; + virtual int ReadMatrix3x4Worldspace( matrix3x4_t *pValue, int nElems = 1, int nBytesAvailable = 0 ) = 0; + + //--------------------------------- + + virtual bool GetPrecacheMode( void ) = 0; + + //--------------------------------- + // Back door to support somewhat awkward ownership of game save/restore data + virtual CGameSaveRestoreInfo *GetGameSaveRestoreInfo() = 0; + +protected: + virtual ~IRestore() {}; +}; + +//----------------------------------------------------------------------------- +// Purpose: The operations necessary to save and restore custom types (FIELD_CUSTOM) +// +// + +struct SaveRestoreFieldInfo_t +{ + void * pField; + + // Note that it is legal for the following two fields to be NULL, + // though it may be disallowed by implementors of ISaveRestoreOps + void * pOwner; + typedescription_t *pTypeDesc; +}; + +abstract_class ISaveRestoreOps +{ +public: + // save data type interface + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) = 0; + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) = 0; + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) = 0; + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) = 0; + virtual bool Parse( const SaveRestoreFieldInfo_t &fieldInfo, char const* szValue ) = 0; + + //--------------------------------- + + void Save( void *pField, ISave *pSave ) { SaveRestoreFieldInfo_t fieldInfo = { pField, NULL, NULL }; Save( fieldInfo, pSave ); } + void Restore( void *pField, IRestore *pRestore ) { SaveRestoreFieldInfo_t fieldInfo = { pField, NULL, NULL }; Restore( fieldInfo, pRestore ); } + + bool IsEmpty( void *pField) { SaveRestoreFieldInfo_t fieldInfo = { pField, NULL, NULL }; return IsEmpty( fieldInfo ); } + void MakeEmpty( void *pField) { SaveRestoreFieldInfo_t fieldInfo = { pField, NULL, NULL }; MakeEmpty( fieldInfo ); } + bool Parse( void *pField, char const *pszValue ) { SaveRestoreFieldInfo_t fieldInfo = { pField, NULL, NULL }; return Parse( fieldInfo, pszValue ); } +}; + +//------------------------------------- + +class CDefSaveRestoreOps : public ISaveRestoreOps +{ +public: + // save data type interface + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) {} + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) {} + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) { return false; } + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) {} + virtual bool Parse( const SaveRestoreFieldInfo_t &fieldInfo, char const* szValue ) { return false; } +}; + + +//----------------------------------------------------------------------------- +// Used by ops that deal with pointers +//----------------------------------------------------------------------------- +class CClassPtrSaveRestoreOps : public CDefSaveRestoreOps +{ +public: + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + void **ppClassPtr = (void **)fieldInfo.pField; + int nObjects = fieldInfo.pTypeDesc->fieldSize; + for ( int i = 0; i < nObjects; i++ ) + { + if ( ppClassPtr[i] != NULL ) + return false; + } + return true; + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + memset( fieldInfo.pField, 0, fieldInfo.pTypeDesc->fieldSize * sizeof( void * ) ); + } +}; + + +//============================================================================= + +#endif // ISAVERESTORE_H diff --git a/public/iscratchpad3d.h b/public/iscratchpad3d.h new file mode 100644 index 0000000..82e4365 --- /dev/null +++ b/public/iscratchpad3d.h @@ -0,0 +1,326 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISCRATCHPAD3D_H +#define ISCRATCHPAD3D_H +#ifdef _WIN32 +#pragma once +#endif + + +// IScratchPad3D will store drawing commands in a file to be viewed by ScratchPad3DViewer. +// It can be used while stepping through geometry code to visualize what is going on as +// drawing commands will be immediately visible in ScratchPad3DViewer even while you're stuck +// in the debugger + +// ScratchPad3DViewer initially orbits 100 inches from the origin, so it can be useful +// to call SetMapping to map what you're drawing input into this cube. + + +#include "mathlib/vector.h" +#include "mathlib/vector2d.h" +#include "utlvector.h" + +class IFileSystem; + + +class CSPColor +{ +public: + CSPColor() + { + m_flAlpha = 1; + } + CSPColor( const Vector &vColor, float flAlpha=1 ) + { + m_vColor = vColor; + m_flAlpha = flAlpha; + } + CSPColor( float r, float g, float b, float a=1 ) + { + m_vColor.Init( r, g, b ); + m_flAlpha = a; + } + + Vector m_vColor; + float m_flAlpha; +}; + + +class CSPVert +{ +public: + CSPVert(); + CSPVert( Vector const &vPos, const CSPColor &vColor=CSPColor( Vector(1, 1, 1), 1 ) ); + + void Init( Vector const &vPos, const CSPColor &vColor=CSPColor( Vector(1, 1, 1), 1 ) ); + +public: + Vector m_vPos; + CSPColor m_vColor; +}; + + +class CSPVertList +{ +public: + CSPVertList( int nVerts = 0 ); + CSPVertList(CSPVert const *pVerts, int nVerts); + CSPVertList(Vector const *pVerts, int nVerts, CSPColor vColor=CSPColor(1,1,1) ); + + CSPVertList(Vector const *pVerts, Vector const *pColors, int nVerts); + CSPVertList(Vector const *pVerts, CSPColor const *pColors, int nVerts); + + CSPVertList(Vector const &vert1, CSPColor const &color1, + Vector const &vert2, CSPColor const &color2, + Vector const &vert3, CSPColor const &color3); + + CUtlVector m_Verts; +}; + +class SPRGBA +{ +public: + unsigned char r,g,b,a; +}; + + +class CTextParams +{ +public: + CTextParams(); + + + Vector m_vColor; // Color of the string (starting color.. at some point, + // we can embed commands in the text itself to change the color). + float m_flAlpha; // Alpha of the whole thing. + + bool m_bSolidBackground; // Should the background be solid or alpha'd? + + // Draw an outline around the text? + bool m_bOutline; + + Vector m_vPos; // Where to render the text. + bool m_bCentered; // Centered on m_vPos, or is m_vPos the upper-left corner? + + QAngle m_vAngles; // Orientation of the text. + bool m_bTwoSided; // Render the text from both sides? + + float m_flLetterWidth; // Letter width in world space. +}; + + +abstract_class IScratchPad3D +{ +protected: + + virtual ~IScratchPad3D() {} + + +// Types. +public: + + enum RenderState + { + RS_FillMode=0, // val = one of the FillMode enums + RS_ZRead, + RS_ZBias // val = 0 - 16 to push Z towards viewer + }; + + enum FillMode + { + FillMode_Wireframe=0, + FillMode_Solid + }; + + +public: + + virtual void Release() = 0; + + // This sets up a mapping between input coordinates and output coordinates. + // This can be used to zoom into an area of interest where you'll be drawing things. + // An alternative is to press Z while in VisLibViewer to have it center and zoom on + // everything that has been drawn. + virtual void SetMapping( + Vector const &vInputMin, + Vector const &vInputMax, + Vector const &vOutputMin, + Vector const &vOutputMax ) = 0; + + // Enable/disable auto flush. When set to true (the default), all drawing commands + // are immediately written to the file and will show up in VisLibViewer right away. + // If you want to draw a lot of things, you can set this to false and call Flush() + // manually when you want the file written out. + // When you set auto flush to true, it calls Flush(). + virtual bool GetAutoFlush() = 0; + virtual void SetAutoFlush( bool bAutoFlush ) = 0; + + // Draw a point. Point size is (roughly) in world coordinates, so points + // get smaller as the viewer moves away. + virtual void DrawPoint( CSPVert const &v, float flPointSize ) = 0; + + // Draw a line. + virtual void DrawLine( CSPVert const &v1, CSPVert const &v2 ) = 0; + + // Draw a polygon. + virtual void DrawPolygon( CSPVertList const &verts ) = 0; + + // Draw 2D rectangles. + virtual void DrawRectYZ( float xPos, Vector2D const &vMin, Vector2D const &vMax, const CSPColor &vColor ) = 0; + virtual void DrawRectXZ( float yPos, Vector2D const &vMin, Vector2D const &vMax, const CSPColor &vColor ) = 0; + virtual void DrawRectXY( float zPos, Vector2D const &vMin, Vector2D const &vMax, const CSPColor &vColor ) = 0; + + // Draw a wireframe box. + virtual void DrawWireframeBox( Vector const &vMin, Vector const &vMax, Vector const &vColor ) = 0; + + // Draw some text. + virtual void DrawText( const char *pStr, const CTextParams ¶ms ) = 0; + + // Wireframe on/off. + virtual void SetRenderState( RenderState state, unsigned long val ) = 0; + + // Clear all the drawing commands. + virtual void Clear() = 0; + + // Calling this writes all the commands to the file. If AutoFlush is true, this is called + // automatically in all the drawing commands. + virtual void Flush() = 0; + + +// Primitives that build on the atomic primitives. +public: + + // Draw a black and white image. + // Corners are in this order: bottom-left, top-left, top-right, bottom-right. + // If the corners are NULL, then the image is drawn in the XY plane from (-100,-100) to (100,100). + virtual void DrawImageBW( + unsigned char const *pData, + int width, + int height, + int pitchInBytes, + bool bOutlinePixels=true, + bool bOutlineImage=false, + Vector *vCorners=NULL ) = 0; + + // Draw an RGBA image. + // Corners are in this order: bottom-left, top-left, top-right, bottom-right. + virtual void DrawImageRGBA( + SPRGBA *pData, + int width, + int height, + int pitchInBytes, + bool bOutlinePixels=true, + bool bOutlineImage=false, + Vector *vCorners=NULL ) = 0; +}; + + +// Just a helper for functions where you want to have a CScratchPad3D around +// and release it automatically when the function exits. +class CScratchPadAutoRelease +{ +public: + CScratchPadAutoRelease( IScratchPad3D *pPad ) { m_pPad = pPad; } + ~CScratchPadAutoRelease() { if( m_pPad ) m_pPad->Release(); } + + IScratchPad3D *m_pPad; +}; + + + +IScratchPad3D* ScratchPad3D_Create( char const *pFilename = "scratch.pad" ); + + + +// ------------------------------------------------------------------------------------ // +// Inlines. +// ------------------------------------------------------------------------------------ // + +inline CTextParams::CTextParams() +{ + m_vColor.Init( 1, 1, 1 ); + m_flAlpha = 1; + m_bSolidBackground = true; + m_bOutline = true; + m_vPos.Init(); + m_bCentered = true; + m_vAngles.Init(); + m_bTwoSided = true; + m_flLetterWidth = 3; +} + +inline CSPVert::CSPVert() +{ +} + +inline CSPVert::CSPVert( Vector const &vPos, const CSPColor &vColor ) +{ + Init( vPos, vColor ); +} + +inline void CSPVert::Init( Vector const &vPos, const CSPColor &vColor ) +{ + m_vPos = vPos; + m_vColor = vColor; +} + + +inline CSPVertList::CSPVertList( int nVerts ) +{ + if( nVerts ) + m_Verts.AddMultipleToTail( nVerts ); +} + +inline CSPVertList::CSPVertList(CSPVert const *pVerts, int nVerts ) +{ + m_Verts.CopyArray( pVerts, nVerts ); +} + +inline CSPVertList::CSPVertList(Vector const *pVerts, int nVerts, CSPColor vColor ) +{ + m_Verts.AddMultipleToTail( nVerts ); + for( int i=0; i < nVerts; i++ ) + { + m_Verts[i].m_vPos = pVerts[i]; + m_Verts[i].m_vColor = vColor; + } +} + +inline CSPVertList::CSPVertList( Vector const *pVerts, Vector const *pColors, int nVerts ) +{ + m_Verts.AddMultipleToTail( nVerts ); + for( int i=0; i < nVerts; i++ ) + { + m_Verts[i].m_vPos = pVerts[i]; + m_Verts[i].m_vColor = pColors[i]; + } +} + +inline CSPVertList::CSPVertList( Vector const *pVerts, CSPColor const *pColors, int nVerts ) +{ + m_Verts.AddMultipleToTail( nVerts ); + for( int i=0; i < nVerts; i++ ) + { + m_Verts[i].m_vPos = pVerts[i]; + m_Verts[i].m_vColor = pColors[i]; + } +} + +inline CSPVertList::CSPVertList( + Vector const &vert1, CSPColor const &color1, + Vector const &vert2, CSPColor const &color2, + Vector const &vert3, CSPColor const &color3 ) +{ + m_Verts.AddMultipleToTail( 3 ); + m_Verts[0].Init( vert1, color1 ); + m_Verts[1].Init( vert2, color2 ); + m_Verts[2].Init( vert3, color3 ); +} + + +#endif // ISCRATCHPAD3D_H diff --git a/public/iserver.h b/public/iserver.h new file mode 100644 index 0000000..9e59355 --- /dev/null +++ b/public/iserver.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ISERVER_H +#define ISERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +class INetMessage; +class IRecipientFilter; +class IClient; + +typedef struct player_info_s player_info_t; + +abstract_class IServer : public IConnectionlessPacketHandler +{ +public: + virtual ~IServer() {} + + virtual int GetNumClients( void ) const = 0; // returns current number of clients + virtual int GetNumProxies( void ) const = 0; // returns number of attached HLTV proxies + virtual int GetNumFakeClients() const = 0; // returns number of fake clients/bots + virtual int GetMaxClients( void ) const = 0; // returns current client limit + virtual IClient *GetClient( int index ) = 0; // returns interface to client + virtual int GetClientCount() const = 0; // returns number of clients slots (used & unused) + virtual int GetUDPPort( void ) const = 0; // returns current used UDP port + virtual float GetTime( void ) const = 0; // returns game world time + virtual int GetTick( void ) const = 0; // returns game world tick + virtual float GetTickInterval( void ) const = 0; // tick interval in seconds + virtual const char *GetName( void ) const = 0; // public server name + virtual const char *GetMapName( void ) const = 0; // current map name (BSP) + virtual int GetSpawnCount( void ) const = 0; + virtual int GetNumClasses( void ) const = 0; + virtual int GetClassBits( void ) const = 0; + virtual void GetNetStats( float &avgIn, float &avgOut ) = 0; // total net in/out in bytes/sec + virtual int GetNumPlayers() = 0; + virtual bool GetPlayerInfo( int nClientIndex, player_info_t *pinfo ) = 0; + + virtual bool IsActive( void ) const = 0; + virtual bool IsLoading( void ) const = 0; + virtual bool IsDedicated( void ) const = 0; + virtual bool IsPaused( void ) const = 0; + virtual bool IsMultiplayer( void ) const = 0; + virtual bool IsPausable() const = 0; + virtual bool IsHLTV() const = 0; + virtual bool IsReplay() const = 0; + + virtual const char * GetPassword() const = 0; // returns the password or NULL if none set + + virtual void SetPaused(bool paused) = 0; + virtual void SetPassword(const char *password) = 0; // set password (NULL to disable) + + virtual void BroadcastMessage( INetMessage &msg, bool onlyActive = false, bool reliable = false) = 0; + virtual void BroadcastMessage( INetMessage &msg, IRecipientFilter &filter ) = 0; + + virtual void DisconnectClient( IClient *client, const char *reason ) = 0; +}; + + +#endif // ISERVER_H diff --git a/public/iserverentity.h b/public/iserverentity.h new file mode 100644 index 0000000..a53e9c3 --- /dev/null +++ b/public/iserverentity.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISERVERENTITY_H +#define ISERVERENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iserverunknown.h" +#include "string_t.h" + + + +struct Ray_t; +class ServerClass; +class ICollideable; +class IServerNetworkable; +class Vector; +class QAngle; + +// This class is how the engine talks to entities in the game DLL. +// CBaseEntity implements this interface. +class IServerEntity : public IServerUnknown +{ +public: + virtual ~IServerEntity() {} + +// Previously in pev + virtual int GetModelIndex( void ) const = 0; + virtual string_t GetModelName( void ) const = 0; + + virtual void SetModelIndex( int index ) = 0; +}; + + +#endif // ISERVERENTITY_H diff --git a/public/iservernetworkable.h b/public/iservernetworkable.h new file mode 100644 index 0000000..cefa753 --- /dev/null +++ b/public/iservernetworkable.h @@ -0,0 +1,114 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISERVERNETWORKABLE_H +#define ISERVERNETWORKABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ihandleentity.h" +#include "basetypes.h" +#include "bitvec.h" +#include "const.h" +#include "bspfile.h" + + + +// Entities can span this many clusters before we revert to a slower area checking algorithm +#define MAX_FAST_ENT_CLUSTERS 4 +#define MAX_ENT_CLUSTERS 64 +#define MAX_WORLD_AREAS 8 + + +class ServerClass; +class SendTable; +struct edict_t; +class CBaseEntity; +class CSerialEntity; +class CBaseNetworkable; + + +class CCheckTransmitInfo +{ +public: + edict_t *m_pClientEnt; // pointer to receiver edict + byte m_PVS[PAD_NUMBER( MAX_MAP_CLUSTERS,8 ) / 8]; + int m_nPVSSize; // PVS size in bytes + + CBitVec *m_pTransmitEdict; // entity n is already marked for transmission + CBitVec *m_pTransmitAlways; // entity n is always sent even if not in PVS (HLTV and Replay only) + + int m_AreasNetworked; // number of networked areas + int m_Areas[MAX_WORLD_AREAS]; // the areas + + // This is used to determine visibility, so if the previous state + // is the same as the current state (along with pvs and areas networked), + // then the parts of the map that the player can see haven't changed. + byte m_AreaFloodNums[MAX_MAP_AREAS]; + int m_nMapAreas; +}; + +//----------------------------------------------------------------------------- +// Stores information necessary to perform PVS testing. +//----------------------------------------------------------------------------- +struct PVSInfo_t +{ + // headnode for the entity's bounding box + short m_nHeadNode; + + // number of clusters or -1 if too many + short m_nClusterCount; + + // cluster indices + unsigned short *m_pClusters; + + // For dynamic "area portals" + short m_nAreaNum; + short m_nAreaNum2; + + // current position + float m_vCenter[3]; + +private: + unsigned short m_pClustersInline[MAX_FAST_ENT_CLUSTERS]; + + friend class CVEngineServer; +}; + + +// IServerNetworkable is the interface the engine uses for all networkable data. +class IServerNetworkable +{ +// These functions are handled automatically by the server_class macros and CBaseNetworkable. +public: + // Gets at the entity handle associated with the collideable + virtual IHandleEntity *GetEntityHandle() = 0; + + // Tell the engine which class this object is. + virtual ServerClass* GetServerClass() = 0; + + virtual edict_t *GetEdict() const = 0; + + virtual const char* GetClassName() const = 0; + virtual void Release() = 0; + + virtual int AreaNum() const = 0; + + // In place of a generic QueryInterface. + virtual CBaseNetworkable* GetBaseNetworkable() = 0; + virtual CBaseEntity* GetBaseEntity() = 0; // Only used by game code. + virtual PVSInfo_t* GetPVSInfo() = 0; // get current visibilty data + +protected: + // Should never call delete on this! + virtual ~IServerNetworkable() {} +}; + + +#endif // ISERVERNETWORKABLE_H diff --git a/public/iserverunknown.h b/public/iserverunknown.h new file mode 100644 index 0000000..97f3c99 --- /dev/null +++ b/public/iserverunknown.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISERVERUNKNOWN_H +#define ISERVERUNKNOWN_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "ihandleentity.h" + +class ICollideable; +class IServerNetworkable; +class CBaseEntity; + + +// This is the server's version of IUnknown. We may want to use a QueryInterface-like +// mechanism if this gets big. +class IServerUnknown : public IHandleEntity +{ +public: + // Gets the interface to the collideable + networkable representation of the entity + virtual ICollideable* GetCollideable() = 0; + virtual IServerNetworkable* GetNetworkable() = 0; + virtual CBaseEntity* GetBaseEntity() = 0; +}; + + +#endif // ISERVERUNKNOWN_H diff --git a/public/ishadercompiledll.h b/public/ishadercompiledll.h new file mode 100644 index 0000000..03a1d1c --- /dev/null +++ b/public/ishadercompiledll.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ISHADERCOMPILEDLL_H +#define ISHADERCOMPILEDLL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "interface.h" + +#define SHADER_COMPILE_INTERFACE_VERSION "shadercompiledll_0" + +// This is the DLL interface to ShaderCompile +abstract_class IShaderCompileDLL +{ +public: + // All vrad.exe does is load the VRAD DLL and run this. + virtual int main( int argc, char **argv ) = 0; +}; + +#endif // ISHADERCOMPILEDLL_H diff --git a/public/isoundcombiner.h b/public/isoundcombiner.h new file mode 100644 index 0000000..8c90a29 --- /dev/null +++ b/public/isoundcombiner.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ISOUNDCOMBINER_H +#define ISOUNDCOMBINER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +class IFileSystem; + +struct CombinerEntry +{ + CombinerEntry() + { + wavefile[ 0 ] = 0; + startoffset = 0.0f; + } + + char wavefile[ MAX_PATH ]; + float startoffset; +}; + +abstract_class ISoundCombiner +{ +public: + virtual ~ISoundCombiner() {} + + virtual bool CombineSoundFiles( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ) = 0; + virtual bool IsCombinedFileChecksumValid( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ) = 0; +}; + +extern ISoundCombiner *soundcombiner; + +#endif // ISOUNDCOMBINER_H diff --git a/public/ispatialpartition.h b/public/ispatialpartition.h new file mode 100644 index 0000000..ff9bd7d --- /dev/null +++ b/public/ispatialpartition.h @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISPATIALPARTITION_H +#define ISPATIALPARTITION_H + +#include "interface.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class Vector; +struct Ray_t; +class IHandleEntity; + + +#define INTERFACEVERSION_SPATIALPARTITION "SpatialPartition001" + +//----------------------------------------------------------------------------- +// These are the various partition lists. Note some are server only, some +// are client only +//----------------------------------------------------------------------------- + +enum +{ + PARTITION_ENGINE_SOLID_EDICTS = (1 << 0), // every edict_t that isn't SOLID_TRIGGER or SOLID_NOT (and static props) + PARTITION_ENGINE_TRIGGER_EDICTS = (1 << 1), // every edict_t that IS SOLID_TRIGGER + PARTITION_CLIENT_SOLID_EDICTS = (1 << 2), + PARTITION_CLIENT_RESPONSIVE_EDICTS = (1 << 3), // these are client-side only objects that respond to being forces, etc. + PARTITION_ENGINE_NON_STATIC_EDICTS = (1 << 4), // everything in solid & trigger except the static props, includes SOLID_NOTs + PARTITION_CLIENT_STATIC_PROPS = (1 << 5), + PARTITION_ENGINE_STATIC_PROPS = (1 << 6), + PARTITION_CLIENT_NON_STATIC_EDICTS = (1 << 7), // everything except the static props +}; + +// Use this to look for all client edicts. +#define PARTITION_ALL_CLIENT_EDICTS ( \ + PARTITION_CLIENT_NON_STATIC_EDICTS | \ + PARTITION_CLIENT_STATIC_PROPS | \ + PARTITION_CLIENT_RESPONSIVE_EDICTS | \ + PARTITION_CLIENT_SOLID_EDICTS \ + ) + + +// These are the only handles in the spatial partition that the game is controlling (everything but static props) +// These masks are used to handle updating the dirty spatial partition list in each game DLL +#define PARTITION_CLIENT_GAME_EDICTS (PARTITION_ALL_CLIENT_EDICTS & ~PARTITION_CLIENT_STATIC_PROPS) +#define PARTITION_SERVER_GAME_EDICTS (PARTITION_ENGINE_SOLID_EDICTS|PARTITION_ENGINE_TRIGGER_EDICTS|PARTITION_ENGINE_NON_STATIC_EDICTS) + +//----------------------------------------------------------------------------- +// Clients that want to know about all elements within a particular +// volume must inherit from this +//----------------------------------------------------------------------------- + +enum IterationRetval_t +{ + ITERATION_CONTINUE = 0, + ITERATION_STOP, +}; + + +typedef unsigned short SpatialPartitionHandle_t; + +// A combination of the PARTITION_ flags above. +typedef int SpatialPartitionListMask_t; + +typedef int SpatialTempHandle_t; + + +//----------------------------------------------------------------------------- +// Any search in the CSpatialPartition must use this to filter out entities it doesn't want. +// You're forced to use listMasks because it can filter by listMasks really fast. Any other +// filtering can be done by EnumElement. +//----------------------------------------------------------------------------- + +class IPartitionEnumerator +{ +public: + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) = 0; + // XXX(johns): This should have a virtual destructor, but would be ABI breaking (non-versioned interface implemented + // by the game) + // virtual ~IPartitionEnumerator(){} +}; + + +//----------------------------------------------------------------------------- +// Installs a callback to call right before a spatial partition query occurs +//----------------------------------------------------------------------------- +class IPartitionQueryCallback +{ +public: + virtual void OnPreQuery_V1() = 0; + virtual void OnPreQuery( SpatialPartitionListMask_t listMask ) = 0; + virtual void OnPostQuery( SpatialPartitionListMask_t listMask ) = 0; +}; + + +//----------------------------------------------------------------------------- +// This is the spatial partition manager, groups objects into buckets +//----------------------------------------------------------------------------- +enum +{ + PARTITION_INVALID_HANDLE = (SpatialPartitionHandle_t)~0 +}; + + +abstract_class ISpatialPartition +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~ISpatialPartition() {} + + // Create/destroy a handle for this dude in our system. Destroy + // will also remove it from all lists it happens to be in + virtual SpatialPartitionHandle_t CreateHandle( IHandleEntity *pHandleEntity ) = 0; + + // A fast method of creating a handle + inserting into the tree in the right place + virtual SpatialPartitionHandle_t CreateHandle( IHandleEntity *pHandleEntity, + SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs ) = 0; + + virtual void DestroyHandle( SpatialPartitionHandle_t handle ) = 0; + + // Adds, removes an handle from a particular spatial partition list + // There can be multiple partition lists; each has a unique id + virtual void Insert( SpatialPartitionListMask_t listMask, + SpatialPartitionHandle_t handle ) = 0; + virtual void Remove( SpatialPartitionListMask_t listMask, + SpatialPartitionHandle_t handle ) = 0; + + // Same as calling Remove() then Insert(). For performance-sensitive areas where you want to save a call. + virtual void RemoveAndInsert( SpatialPartitionListMask_t removeMask, SpatialPartitionListMask_t insertMask, + SpatialPartitionHandle_t handle ) = 0; + + // This will remove a particular handle from all lists + virtual void Remove( SpatialPartitionHandle_t handle ) = 0; + + // Call this when an entity moves... + virtual void ElementMoved( SpatialPartitionHandle_t handle, + const Vector& mins, const Vector& maxs ) = 0; + + // A fast method to insert + remove a handle from the tree... + // This is used to suppress collision of a single model.. + virtual SpatialTempHandle_t HideElement( SpatialPartitionHandle_t handle ) = 0; + virtual void UnhideElement( SpatialPartitionHandle_t handle, SpatialTempHandle_t tempHandle ) = 0; + + // Installs callbacks to get called right before a query occurs + virtual void InstallQueryCallback_V1( IPartitionQueryCallback *pCallback ) = 0; + virtual void RemoveQueryCallback( IPartitionQueryCallback *pCallback ) = 0; + + // Gets all entities in a particular volume... + // if coarseTest == true, it'll return all elements that are in + // spatial partitions that intersect the box + // if coarseTest == false, it'll return only elements that truly intersect + virtual void EnumerateElementsInBox( + SpatialPartitionListMask_t listMask, + const Vector& mins, + const Vector& maxs, + bool coarseTest, + IPartitionEnumerator* pIterator + ) = 0; + + virtual void EnumerateElementsInSphere( + SpatialPartitionListMask_t listMask, + const Vector& origin, + float radius, + bool coarseTest, + IPartitionEnumerator* pIterator + ) = 0; + + virtual void EnumerateElementsAlongRay( + SpatialPartitionListMask_t listMask, + const Ray_t& ray, + bool coarseTest, + IPartitionEnumerator* pIterator + ) = 0; + + virtual void EnumerateElementsAtPoint( + SpatialPartitionListMask_t listMask, + const Vector& pt, + bool coarseTest, + IPartitionEnumerator* pIterator + ) = 0; + + // For debugging.... suppress queries on particular lists + virtual void SuppressLists( SpatialPartitionListMask_t nListMask, bool bSuppress ) = 0; + virtual SpatialPartitionListMask_t GetSuppressedLists() = 0; + + virtual void RenderAllObjectsInTree( float flTime ) = 0; + virtual void RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime ) = 0; + virtual void RenderLeafsForRayTraceStart( float flTime ) = 0; + virtual void RenderLeafsForRayTraceEnd( void ) = 0; + virtual void RenderLeafsForHullTraceStart( float flTime ) = 0; + virtual void RenderLeafsForHullTraceEnd( void ) = 0; + virtual void RenderLeafsForBoxStart( float flTime ) = 0; + virtual void RenderLeafsForBoxEnd( void ) = 0; + virtual void RenderLeafsForSphereStart( float flTime ) = 0; + virtual void RenderLeafsForSphereEnd( void ) = 0; + + virtual void RenderObjectsInBox( const Vector &vecMin, const Vector &vecMax, float flTime ) = 0; + virtual void RenderObjectsInSphere( const Vector &vecCenter, float flRadius, float flTime ) = 0; + virtual void RenderObjectsAlongRay( const Ray_t& ray, float flTime ) = 0; + + virtual void ReportStats( const char *pFileName ) = 0; + + virtual void InstallQueryCallback( IPartitionQueryCallback *pCallback ) = 0; +}; + +#endif + + + diff --git a/public/isqlwrapper.h b/public/isqlwrapper.h new file mode 100644 index 0000000..5e6603b --- /dev/null +++ b/public/isqlwrapper.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Sql wrapper, encapsulates basic SQL functionality +// +// $NoKeywords: $ +//============================================================================= +#ifndef ISQLWRAPPER_H +#define ISQLWRAPPER_H + +#include "tier0/platform.h" + +#ifdef _WIN32 +#pragma once +#endif + +// SQL column types +enum EColumnType +{ + SQL_NONE = 0, + SQL_INT, + SQL_STRING, + SQL_FLOAT, + SQL_TIME, + SQL_UINT64 +}; + + +//----------------------------------------------------------------------------- +// encapsulates a table's description +//----------------------------------------------------------------------------- +class ISQLTable +{ +public: + virtual int GetCSQLColumn() const = 0; + virtual const char *PchColumnName( int iSQLColumn ) const = 0; + virtual EColumnType GetEColumnType( int iSQLColumn ) const = 0; + virtual const char *PchName() const = 0; +}; + + +//----------------------------------------------------------------------------- +// encapsulates a database worth of tables +//----------------------------------------------------------------------------- +class ISQLTableSet +{ +public: + virtual int GetCSQLTable() const = 0; + virtual const ISQLTable *PSQLTable( int iSQLTable ) const = 0; +}; + + +//----------------------------------------------------------------------------- +// encapsulates a single returned row from a valid SQL query +//----------------------------------------------------------------------------- +class ISQLRow +{ +public: + virtual int GetCSQLRowData() const = 0; + virtual const char *PchData( int iSQLColumn ) const = 0; + virtual int NData( int iSQLColumn ) const = 0; + virtual uint64 UlData( int iSQLColumn ) const = 0; + virtual float FlData( int iSQLColumn ) const = 0; + virtual uint64 UlTime( int iSQLColumn ) const = 0; + virtual bool BData( int iSQLColumn ) const = 0; + virtual EColumnType GetEColumnType( int iSQLColumn ) const = 0; +}; + + +//----------------------------------------------------------------------------- +// encapsulates a result set, which is made up of a series of rows +// You need to call PNextResult() NRow() times to get all the results +// (there is no random access to the result set). +//----------------------------------------------------------------------------- +class IResultSet +{ +public: + virtual int GetCSQLRow() const = 0; + virtual const ISQLRow *PSQLRowNextResult() = 0; // note, not const on the class because it makes a new row object +}; + + +//----------------------------------------------------------------------------- +// This interface encapsulates a database connection and lets you operate on it. +// Use the ISQLWrapperFactory factory to get access to the interface. +// NOTE - you can only have one outstanding query at a time. When you are done with a query call FreeResult() +//----------------------------------------------------------------------------- +class ISQLWrapper +{ +public: + // run a SQL statement against the DB, typically an insert statement as no data is returned + virtual bool BInsert( const char *pchQueryString ) = 0; + // get a description of the tables associated with the db you connected to + virtual const ISQLTableSet *PSQLTableSetDescription() = 0; + // run a query against the db and then iterate the result set (you can only have 1 outstanding query at a time, and call FreeResults() when you are done) + virtual IResultSet *PResultSetQuery( const char *pchQueryString ) = 0; + // you MUST call then after you finish with the IResultSet from the above query + virtual void FreeResult() = 0; +}; + + +//----------------------------------------------------------------------------- +// This is a factory to create objects that let you interact with a MySQL database. +// Make sure you Free() any interfaces you create. +//----------------------------------------------------------------------------- +class ISQLWrapperFactory +{ +public: + // setup details about this db connection + virtual ISQLWrapper *Create( const char *pchDB, const char *pchHost, const char *pchUsername, const char *pchPassword ) = 0; + virtual void Free( ISQLWrapper *pSQLWrapper ) = 0; +}; + +#define INTERFACEVERSION_ISQLWRAPPER "ISQLWRAPPER001" + +#endif // ISQLWRAPPER_H + diff --git a/public/istudiorender.h b/public/istudiorender.h new file mode 100644 index 0000000..6be93c9 --- /dev/null +++ b/public/istudiorender.h @@ -0,0 +1,383 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ISTUDIORENDER_H +#define ISTUDIORENDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlvector.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include "appframework/IAppSystem.h" +#include "datacache/imdlcache.h" +#include "studio.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +struct studiohdr_t; +struct studiomeshdata_t; +class Vector; +struct LightDesc_t; +class IMaterial; +struct studiohwdata_t; +struct Ray_t; +class Vector4D; +class IMaterialSystem; +struct matrix3x4_t; +class IMesh; +struct vertexFileHeader_t; +struct FlashlightState_t; +class VMatrix; +namespace OptimizedModel { struct FileHeader_t; } +class IPooledVBAllocator; + +// undone: what's the standard for function type naming? +typedef void (*StudioRender_Printf_t)( PRINTF_FORMAT_STRING const char *fmt, ... ); + +struct StudioRenderConfig_t +{ + float fEyeShiftX; // eye X position + float fEyeShiftY; // eye Y position + float fEyeShiftZ; // eye Z position + float fEyeSize; // adjustment to iris textures + float fEyeGlintPixelWidthLODThreshold; + + int maxDecalsPerModel; + int drawEntities; + int skin; + int fullbright; + + bool bEyeMove : 1; // look around + bool bSoftwareSkin : 1; + bool bNoHardware : 1; + bool bNoSoftware : 1; + bool bTeeth : 1; + bool bEyes : 1; + bool bFlex : 1; + bool bWireframe : 1; + bool bDrawNormals : 1; + bool bDrawTangentFrame : 1; + bool bDrawZBufferedWireframe : 1; + bool bSoftwareLighting : 1; + bool bShowEnvCubemapOnly : 1; + bool bWireframeDecals : 1; + + // Reserved for future use + int m_nReserved[4]; +}; + + + +//----------------------------------------------------------------------------- +// Studio render interface +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE( StudioDecalHandle_t ); +#define STUDIORENDER_DECAL_INVALID ( (StudioDecalHandle_t)0 ) + +enum +{ + ADDDECAL_TO_ALL_LODS = -1 +}; + + +//----------------------------------------------------------------------------- +// DrawModel flags +//----------------------------------------------------------------------------- +enum +{ + STUDIORENDER_DRAW_ENTIRE_MODEL = 0, + STUDIORENDER_DRAW_OPAQUE_ONLY = 0x01, + STUDIORENDER_DRAW_TRANSLUCENT_ONLY = 0x02, + STUDIORENDER_DRAW_GROUP_MASK = 0x03, + + STUDIORENDER_DRAW_NO_FLEXES = 0x04, + STUDIORENDER_DRAW_STATIC_LIGHTING = 0x08, + + STUDIORENDER_DRAW_ACCURATETIME = 0x10, // Use accurate timing when drawing the model. + STUDIORENDER_DRAW_NO_SHADOWS = 0x20, + STUDIORENDER_DRAW_GET_PERF_STATS = 0x40, + + STUDIORENDER_DRAW_WIREFRAME = 0x80, + + STUDIORENDER_DRAW_ITEM_BLINK = 0x100, + + STUDIORENDER_SHADOWDEPTHTEXTURE = 0x200, + + STUDIORENDER_SSAODEPTHTEXTURE = 0x1000, + + STUDIORENDER_GENERATE_STATS = 0x8000, +}; + + +//----------------------------------------------------------------------------- +// Standard model vertex formats +//----------------------------------------------------------------------------- +// FIXME: remove these (materials/shaders should drive vertex format). Need to +// list required forcedmaterialoverrides in models/bsps (rather than +// all models supporting all possible overrides, as they do currently). +#define VERTEX_TEXCOORD0_2D ( ( (uint64) 2 ) << ( TEX_COORD_SIZE_BIT + ( 3*0 ) ) ) +enum MaterialVertexFormat_t +{ + MATERIAL_VERTEX_FORMAT_MODEL_SKINNED = (VertexFormat_t) VERTEX_POSITION | VERTEX_COLOR | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D | VERTEX_BONEWEIGHT(2) | VERTEX_BONE_INDEX | VERTEX_USERDATA_SIZE(4), + MATERIAL_VERTEX_FORMAT_MODEL_SKINNED_DX7 = (VertexFormat_t) VERTEX_POSITION | VERTEX_COLOR | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D | VERTEX_BONEWEIGHT(2) | VERTEX_BONE_INDEX, + MATERIAL_VERTEX_FORMAT_MODEL = (VertexFormat_t) VERTEX_POSITION | VERTEX_COLOR | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D | VERTEX_USERDATA_SIZE(4), + MATERIAL_VERTEX_FORMAT_MODEL_DX7 = (VertexFormat_t) VERTEX_POSITION | VERTEX_COLOR | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D, + MATERIAL_VERTEX_FORMAT_COLOR = (VertexFormat_t) VERTEX_SPECULAR +}; + + +//----------------------------------------------------------------------------- +// What kind of material override is it? +//----------------------------------------------------------------------------- +enum OverrideType_t +{ + OVERRIDE_NORMAL = 0, + OVERRIDE_BUILD_SHADOWS, + OVERRIDE_DEPTH_WRITE, + OVERRIDE_SSAO_DEPTH_WRITE, +}; + + +//----------------------------------------------------------------------------- +// DrawModel info +//----------------------------------------------------------------------------- + +// Special flag for studio models that have a compiled in shadow lod version +// It's negative 2 since positive numbers == use a regular slot and -1 means +// have studiorender compute a value instead +enum +{ + USESHADOWLOD = -2, +}; + +// beyond this number of materials, you won't get info back from DrawModel +#define MAX_DRAW_MODEL_INFO_MATERIALS 8 + +struct DrawModelResults_t +{ + int m_ActualTriCount; + int m_TextureMemoryBytes; + int m_NumHardwareBones; + int m_NumBatches; + int m_NumMaterials; + int m_nLODUsed; + int m_flLODMetric; + CFastTimer m_RenderTime; + CUtlVectorFixed m_Materials; +}; + +struct ColorTexelsInfo_t +{ + int m_nWidth; + int m_nHeight; + int m_nMipmapCount; + ImageFormat m_ImageFormat; + int m_nByteCount; + byte* m_pTexelData; +}; + +struct ColorMeshInfo_t +{ + // A given color mesh can own a unique Mesh, or it can use a shared Mesh + // (in which case it uses a sub-range defined by m_nVertOffset and m_nNumVerts) + IMesh * m_pMesh; + IPooledVBAllocator * m_pPooledVBAllocator; + int m_nVertOffsetInBytes; + int m_nNumVerts; + ITexture * m_pLightmap; + ColorTexelsInfo_t * m_pLightmapData; +}; + +struct DrawModelInfo_t +{ + studiohdr_t *m_pStudioHdr; + studiohwdata_t *m_pHardwareData; + StudioDecalHandle_t m_Decals; + int m_Skin; + int m_Body; + int m_HitboxSet; + void *m_pClientEntity; + int m_Lod; + ColorMeshInfo_t *m_pColorMeshes; + bool m_bStaticLighting; + Vector m_vecAmbientCube[6]; // ambient, and lights that aren't in locallight[] + int m_nLocalLightCount; + LightDesc_t m_LocalLightDescs[4]; +}; + +struct GetTriangles_Vertex_t +{ + Vector m_Position; + Vector m_Normal; + Vector4D m_TangentS; + Vector2D m_TexCoord; + Vector4D m_BoneWeight; + int m_BoneIndex[4]; + int m_NumBones; +}; + +struct GetTriangles_MaterialBatch_t +{ + IMaterial *m_pMaterial; + CUtlVector m_Verts; + CUtlVector m_TriListIndices; +}; + +struct GetTriangles_Output_t +{ + CUtlVector m_MaterialBatches; + matrix3x4_t m_PoseToWorld[MAXSTUDIOBONES]; +}; + + +struct model_array_instance_t +{ + matrix3x4_t modelToWorld; + + // UNDONE: Per instance lighting values? +}; + +//----------------------------------------------------------------------------- +// Cache Callback Function +// implementation can either statically persist data (tools) or lru cache (engine) it. +// caller returns base pointer to resident data. +// code expectes data to be dynamic and invokes cache callback prior to iterative access. +// virtualModel is member passed in via studiohdr_t and passed back for model identification. +//----------------------------------------------------------------------------- +#define STUDIO_DATA_CACHE_INTERFACE_VERSION "VStudioDataCache005" + +abstract_class IStudioDataCache : public IAppSystem +{ +public: + virtual bool VerifyHeaders( studiohdr_t *pStudioHdr ) = 0; + virtual vertexFileHeader_t *CacheVertexData( studiohdr_t *pStudioHdr ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Studio render interface +//----------------------------------------------------------------------------- +#define STUDIO_RENDER_INTERFACE_VERSION "VStudioRender025" + +abstract_class IStudioRender : public IAppSystem +{ +public: + virtual void BeginFrame( void ) = 0; + virtual void EndFrame( void ) = 0; + + // Used for the mat_stub console command. + virtual void Mat_Stub( IMaterialSystem *pMatSys ) = 0; + + // Updates the rendering configuration + virtual void UpdateConfig( const StudioRenderConfig_t& config ) = 0; + virtual void GetCurrentConfig( StudioRenderConfig_t& config ) = 0; + + // Load, unload model data + virtual bool LoadModel( studiohdr_t *pStudioHdr, void *pVtxData, studiohwdata_t *pHardwareData ) = 0; + virtual void UnloadModel( studiohwdata_t *pHardwareData ) = 0; + + // Refresh the studiohdr since it was lost... + virtual void RefreshStudioHdr( studiohdr_t* pStudioHdr, studiohwdata_t* pHardwareData ) = 0; + + // This is needed to do eyeglint and calculate the correct texcoords for the eyes. + virtual void SetEyeViewTarget( const studiohdr_t *pStudioHdr, int nBodyIndex, const Vector& worldPosition ) = 0; + + // Methods related to lighting state + // NOTE: SetAmbientLightColors assumes that the arraysize is the same as + // returned from GetNumAmbientLightSamples + virtual int GetNumAmbientLightSamples() = 0; + virtual const Vector *GetAmbientLightDirections() = 0; + virtual void SetAmbientLightColors( const Vector4D *pAmbientOnlyColors ) = 0; + virtual void SetAmbientLightColors( const Vector *pAmbientOnlyColors ) = 0; + virtual void SetLocalLights( int numLights, const LightDesc_t *pLights ) = 0; + + // Sets information about the camera location + orientation + virtual void SetViewState( const Vector& viewOrigin, const Vector& viewRight, + const Vector& viewUp, const Vector& viewPlaneNormal ) = 0; + + // Allocates flex weights for use in rendering + // NOTE: Pass in a non-null second parameter to lock delayed flex weights + virtual void LockFlexWeights( int nWeightCount, float **ppFlexWeights, float **ppFlexDelayedWeights = NULL ) = 0; + virtual void UnlockFlexWeights() = 0; + + // Used to allocate bone matrices to be used to pass into DrawModel + virtual matrix3x4_t* LockBoneMatrices( int nBoneCount ) = 0; + virtual void UnlockBoneMatrices() = 0; + + // LOD stuff + virtual int GetNumLODs( const studiohwdata_t &hardwareData ) const = 0; + virtual float GetLODSwitchValue( const studiohwdata_t &hardwareData, int lod ) const = 0; + virtual void SetLODSwitchValue( studiohwdata_t &hardwareData, int lod, float switchValue ) = 0; + + // Sets the color/alpha modulation + virtual void SetColorModulation( float const* pColor ) = 0; + virtual void SetAlphaModulation( float flAlpha ) = 0; + + // Draws the model + virtual void DrawModel( DrawModelResults_t *pResults, const DrawModelInfo_t& info, + matrix3x4_t *pBoneToWorld, float *pFlexWeights, float *pFlexDelayedWeights, const Vector &modelOrigin, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL ) = 0; + + // Methods related to static prop rendering + virtual void DrawModelStaticProp( const DrawModelInfo_t& drawInfo, const matrix3x4_t &modelToWorld, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL ) = 0; + virtual void DrawStaticPropDecals( const DrawModelInfo_t &drawInfo, const matrix3x4_t &modelToWorld ) = 0; + virtual void DrawStaticPropShadows( const DrawModelInfo_t &drawInfo, const matrix3x4_t &modelToWorld, int flags ) = 0; + + // Causes a material to be used instead of the materials the model was compiled with + virtual void ForcedMaterialOverride( IMaterial *newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL ) = 0; + + // Create, destroy list of decals for a particular model + virtual StudioDecalHandle_t CreateDecalList( studiohwdata_t *pHardwareData ) = 0; + virtual void DestroyDecalList( StudioDecalHandle_t handle ) = 0; + + // Add decals to a decal list by doing a planar projection along the ray + // The BoneToWorld matrices must be set before this is called + virtual void AddDecal( StudioDecalHandle_t handle, studiohdr_t *pStudioHdr, matrix3x4_t *pBoneToWorld, + const Ray_t & ray, const Vector& decalUp, IMaterial* pDecalMaterial, float radius, int body, bool noPokethru = false, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ) = 0; + + // Compute the lighting at a point and normal + virtual void ComputeLighting( const Vector* pAmbient, int lightCount, + LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting ) = 0; + + // Compute the lighting at a point, constant directional component is passed + // as flDirectionalAmount + virtual void ComputeLightingConstDirectional( const Vector* pAmbient, int lightCount, + LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting, float flDirectionalAmount ) = 0; + + // Shadow state (affects the models as they are rendered) + virtual void AddShadow( IMaterial* pMaterial, void* pProxyData, FlashlightState_t *m_pFlashlightState = NULL, VMatrix *pWorldToTexture = NULL, ITexture *pFlashlightDepthTexture = NULL ) = 0; + virtual void ClearAllShadows() = 0; + + // Gets the model LOD; pass in the screen size in pixels of a sphere + // of radius 1 that has the same origin as the model to get the LOD out... + virtual int ComputeModelLod( studiohwdata_t* pHardwareData, float unitSphereSize, float *pMetric = NULL ) = 0; + + // Return a number that is usable for budgets, etc. + // Things that we care about: + // 1) effective triangle count (factors in batch sizes, state changes, etc) + // 2) texture memory usage + // Get Triangles returns the LOD used + virtual void GetPerfStats( DrawModelResults_t *pResults, const DrawModelInfo_t &info, CUtlBuffer *pSpewBuf = NULL ) const = 0; + virtual void GetTriangles( const DrawModelInfo_t& info, matrix3x4_t *pBoneToWorld, GetTriangles_Output_t &out ) = 0; + + // Returns materials used by a particular model + virtual int GetMaterialList( studiohdr_t *pStudioHdr, int count, IMaterial** ppMaterials ) = 0; + virtual int GetMaterialListFromBodyAndSkin( MDLHandle_t studio, int nSkin, int nBody, int nCountOutputMaterials, IMaterial** ppOutputMaterials ) = 0; + // draw an array of models with the same state + virtual void DrawModelArray( const DrawModelInfo_t &drawInfo, int arrayCount, model_array_instance_t *pInstanceData, int instanceStride, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL ) = 0; +}; + +extern IStudioRender *g_pStudioRender; + +#endif // ISTUDIORENDER_H diff --git a/public/ivguicenterprint.h b/public/ivguicenterprint.h new file mode 100644 index 0000000..f1d9746 --- /dev/null +++ b/public/ivguicenterprint.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IVGUICENTERPRINT_H ) +#define IVGUICENTERPRINT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Engine Center Print Interface +//----------------------------------------------------------------------------- +abstract_class ICenterPrint +{ +public: + virtual void SetTextColor( int r, int g, int b, int a ) = 0; + virtual void Print( char *text ) = 0; + virtual void Print( wchar_t *text ) = 0; + virtual void ColorPrint( int r, int g, int b, int a, char *text ) = 0; + virtual void ColorPrint( int r, int g, int b, int a, wchar_t *text ) = 0; + virtual void Clear( void ) = 0; +}; + +extern ICenterPrint *centerprint; + +#define VCENTERPRINT_INTERFACE_VERSION "VCENTERPRINT002" + +#endif // IVGUICENTERPRINT_H \ No newline at end of file diff --git a/public/ivoiceserver.h b/public/ivoiceserver.h new file mode 100644 index 0000000..c0a48f7 --- /dev/null +++ b/public/ivoiceserver.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This module defines the IVoiceServer interface, which is used by +// game code to control which clients are listening to which other +// clients' voice streams. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVOICESERVER_H +#define IVOICESERVER_H + + +#include "interface.h" + + +#define INTERFACEVERSION_VOICESERVER "VoiceServer002" + + +abstract_class IVoiceServer +{ +public: + virtual ~IVoiceServer() {} + + // Use these to setup who can hear whose voice. + // Pass in client indices (which are their ent indices - 1). + virtual bool GetClientListening(int iReceiver, int iSender) = 0; + virtual bool SetClientListening(int iReceiver, int iSender, bool bListen) = 0; + virtual bool SetClientProximity(int iReceiver, int iSender, bool bUseProximity) = 0; +}; + + +#endif + diff --git a/public/ivoicetweak.h b/public/ivoicetweak.h new file mode 100644 index 0000000..4a4d0ea --- /dev/null +++ b/public/ivoicetweak.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVOICETWEAK_H +#define IVOICETWEAK_H +#ifdef _WIN32 +#pragma once +#endif + +// These provide access to the voice controls. +typedef enum +{ + MicrophoneVolume=0, // values 0-1. + OtherSpeakerScale, // values 0-1. Scales how loud other players are. + MicBoost, + SpeakingVolume, // values 0-1. Current voice volume received through Voice Tweak mode + +} VoiceTweakControl; + + +typedef struct IVoiceTweak_s +{ + // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back + // without sending to the server. + int (*StartVoiceTweakMode)(); // Returns 0 on error. + void (*EndVoiceTweakMode)(); + + // Get/set control values. + void (*SetControlFloat)(VoiceTweakControl iControl, float value); + float (*GetControlFloat)(VoiceTweakControl iControl); + + bool (*IsStillTweaking)(); // This can return false if the user restarts the sound system during voice tweak mode +} IVoiceTweak; + + +#endif // IVOICETWEAK_H diff --git a/public/ivraddll.h b/public/ivraddll.h new file mode 100644 index 0000000..4b91759 --- /dev/null +++ b/public/ivraddll.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVRADDLL_H +#define IVRADDLL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "interface.h" +#include "bspfile.h" + + +#define VRAD_INTERFACE_VERSION "vraddll_1" + + +class CBSPInfo +{ +public: + byte *dlightdata; + int lightdatasize; + + dface_t *dfaces; + unsigned char *m_pFacesTouched; // If non-null, then this has 1 byte for each face and + // tells which faces had their lightmaps updated. + int numfaces; + + dvertex_t *dvertexes; + int numvertexes; + + dedge_t *dedges; + int numedges; + + int *dsurfedges; + int numsurfedges; + + texinfo_t *texinfo; + int numtexinfo; + + dtexdata_t *dtexdata; + int numtexdata; + + ddispinfo_t *g_dispinfo; + int g_numdispinfo; + + char *texDataStringData; + int nTexDataStringData; + + int *texDataStringTable; + int nTexDataStringTable; +}; + + +// This is the DLL interface to VRAD. +class IVRadDLL +{ +public: + // All vrad.exe does is load the VRAD DLL and run this. + virtual int main( int argc, char **argv ) = 0; + + + // Load the BSP file into memory. + virtual bool Init( char const *pFilename ) = 0; + + // You must call this if you call Init(), to free resources. + virtual void Release() = 0; + + // Get some data from the BSP file that's in memory. + virtual void GetBSPInfo( CBSPInfo *pInfo ) = 0; + + // Incrementally relight the BSP file in memory given the new entity + // descriptions in pVMFFile. pVMFFile should only contain light entities. + // + // Returns true only if the lightmaps are updated. If the process is + // interrupted or there is an error, false is returned. + virtual bool DoIncrementalLight( char const *pVMFFile ) = 0; + + // Calling DoIncrementalLight doesn't actually write anything to disk. + // Calling this will write the incremental light file out and will write the + // current in-memory light data into the BSP. + // NOTE: if DoIncrementalLight never finished, this will do nothing and return false. + virtual bool Serialize() = 0; + + // Returns a 0-1 value telling how close it is to completing the task. + // This can be called from a separate thread than DoIncrementLight. + virtual float GetPercentComplete() = 0; + + // This can be called from a separate thread than the DoIncrementalLight thread. + // It asynchronously tells DoIncrementalLight to stop as soon as possible and exit. + virtual void Interrupt() = 0; +}; + + +#endif // IVRADDLL_H diff --git a/public/ivrenderview.h b/public/ivrenderview.h new file mode 100644 index 0000000..79dadc6 --- /dev/null +++ b/public/ivrenderview.h @@ -0,0 +1,330 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// +#if !defined( IVRENDERVIEW_H ) +#define IVRENDERVIEW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "mathlib/vplane.h" +#include "interface.h" +#include "materialsystem/imaterialsystem.h" +#include "const.h" +#include "tier1/refcount.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CViewSetup; +class CEngineSprite; +class IClientEntity; +class IMaterial; +struct model_t; +class IClientRenderable; + + +//----------------------------------------------------------------------------- +// Flags used by DrawWorldLists +//----------------------------------------------------------------------------- +enum +{ + DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER = 0x001, + DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER = 0x002, + DRAWWORLDLISTS_DRAW_INTERSECTSWATER = 0x004, + DRAWWORLDLISTS_DRAW_WATERSURFACE = 0x008, + DRAWWORLDLISTS_DRAW_SKYBOX = 0x010, + DRAWWORLDLISTS_DRAW_CLIPSKYBOX = 0x020, + DRAWWORLDLISTS_DRAW_SHADOWDEPTH = 0x040, + DRAWWORLDLISTS_DRAW_REFRACTION = 0x080, + DRAWWORLDLISTS_DRAW_REFLECTION = 0x100, + DRAWWORLDLISTS_DRAW_SSAO = 0x800, +}; + +enum +{ + MAT_SORT_GROUP_STRICTLY_ABOVEWATER = 0, + MAT_SORT_GROUP_STRICTLY_UNDERWATER, + MAT_SORT_GROUP_INTERSECTS_WATER_SURFACE, + MAT_SORT_GROUP_WATERSURFACE, + + MAX_MAT_SORT_GROUPS +}; + +enum ERenderDepthMode +{ + DEPTH_MODE_NORMAL = 0, + DEPTH_MODE_SHADOW = 1, + DEPTH_MODE_SSA0 = 2, + DEPTH_MODE_OVERRIDE = 3, + + DEPTH_MODE_MAX +}; + +typedef VPlane Frustum[FRUSTUM_NUMPLANES]; + + +//----------------------------------------------------------------------------- +// Leaf index +//----------------------------------------------------------------------------- +typedef unsigned short LeafIndex_t; +typedef short LeafFogVolume_t; +enum +{ + INVALID_LEAF_INDEX = (LeafIndex_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Describes the leaves to be rendered this view, set by BuildWorldLists +//----------------------------------------------------------------------------- +struct WorldListInfo_t +{ + int m_ViewFogVolume; + int m_LeafCount; + LeafIndex_t* m_pLeafList; + LeafFogVolume_t* m_pLeafFogVolume; +}; + +class IWorldRenderList : public IRefCounted +{ +}; + +//----------------------------------------------------------------------------- +// Describes the fog volume for a particular point +//----------------------------------------------------------------------------- +struct VisibleFogVolumeInfo_t +{ + int m_nVisibleFogVolume; + int m_nVisibleFogVolumeLeaf; + bool m_bEyeInFogVolume; + float m_flDistanceToWater; + float m_flWaterHeight; + IMaterial *m_pFogVolumeMaterial; +}; + + +//----------------------------------------------------------------------------- +// Vertex format for brush models +//----------------------------------------------------------------------------- +struct BrushVertex_t +{ + Vector m_Pos; + Vector m_Normal; + Vector m_TangentS; + Vector m_TangentT; + Vector2D m_TexCoord; + Vector2D m_LightmapCoord; + +private: + BrushVertex_t( const BrushVertex_t& src ); +}; + +//----------------------------------------------------------------------------- +// Visibility data for area portal culling +//----------------------------------------------------------------------------- +struct VisOverrideData_t +{ + Vector m_vecVisOrigin; // The point to to use as the viewpoint for area portal backface cull checks. + float m_fDistToAreaPortalTolerance; // The distance from an area portal before using the full screen as the viewable portion. +}; + + +//----------------------------------------------------------------------------- +// interface for asking about the Brush surfaces from the client DLL +//----------------------------------------------------------------------------- + +class IBrushSurface +{ +public: + // Computes texture coordinates + lightmap coordinates given a world position + virtual void ComputeTextureCoordinate( Vector const& worldPos, Vector2D& texCoord ) = 0; + virtual void ComputeLightmapCoordinate( Vector const& worldPos, Vector2D& lightmapCoord ) = 0; + + // Gets the vertex data for this surface + virtual int GetVertexCount() const = 0; + virtual void GetVertexData( BrushVertex_t* pVerts ) = 0; + + // Gets at the material properties for this surface + virtual IMaterial* GetMaterial() = 0; +}; + + +//----------------------------------------------------------------------------- +// interface for installing a new renderer for brush surfaces +//----------------------------------------------------------------------------- + +class IBrushRenderer +{ +public: + // Draws the surface; returns true if decals should be rendered on this surface + virtual bool RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface ) = 0; +}; + + +#define MAX_VIS_LEAVES 32 +//----------------------------------------------------------------------------- +// Purpose: Interface to client .dll to set up a rendering pass over world +// The client .dll can call Render multiple times to overlay one or more world +// views on top of one another +//----------------------------------------------------------------------------- +enum DrawBrushModelMode_t +{ + DBM_DRAW_ALL = 0, + DBM_DRAW_OPAQUE_ONLY, + DBM_DRAW_TRANSLUCENT_ONLY, +}; + +class IVRenderView +{ +public: + + // Draw normal brush model. + // If pMaterialOverride is non-null, then all the faces of the bmodel will + // set this material rather than their regular material. + virtual void DrawBrushModel( + IClientEntity *baseentity, + model_t *model, + const Vector& origin, + const QAngle& angles, + bool bUnused ) = 0; + + // Draw brush model that has no origin/angles change ( uses identity transform ) + // FIXME, Material proxy IClientEntity *baseentity is unused right now, use DrawBrushModel for brushes with + // proxies for now. + virtual void DrawIdentityBrushModel( IWorldRenderList *pList, model_t *model ) = 0; + + // Mark this dynamic light as having changed this frame ( so light maps affected will be recomputed ) + virtual void TouchLight( struct dlight_t *light ) = 0; + // Draw 3D Overlays + virtual void Draw3DDebugOverlays( void ) = 0; + // Sets global blending fraction + virtual void SetBlend( float blend ) = 0; + virtual float GetBlend( void ) = 0; + + // Sets global color modulation + virtual void SetColorModulation( float const* blend ) = 0; + virtual void GetColorModulation( float* blend ) = 0; + + // Wrap entire scene drawing + virtual void SceneBegin( void ) = 0; + virtual void SceneEnd( void ) = 0; + + // Gets the fog volume for a particular point + virtual void GetVisibleFogVolume( const Vector& eyePoint, VisibleFogVolumeInfo_t *pInfo ) = 0; + + // Wraps world drawing + // If iForceViewLeaf is not -1, then it uses the specified leaf as your starting area for setting up area portal culling. + // This is used by water since your reflected view origin is often in solid space, but we still want to treat it as though + // the first portal we're looking out of is a water portal, so our view effectively originates under the water. + virtual IWorldRenderList * CreateWorldList() = 0; + + virtual void BuildWorldLists( IWorldRenderList *pList, WorldListInfo_t* pInfo, int iForceFViewLeaf, const VisOverrideData_t* pVisData = NULL, bool bShadowDepth = false, float *pReflectionWaterHeight = NULL ) = 0; + virtual void DrawWorldLists( IWorldRenderList *pList, unsigned long flags, float waterZAdjust ) = 0; + + // Optimization for top view + virtual void DrawTopView( bool enable ) = 0; + virtual void TopViewBounds( Vector2D const& mins, Vector2D const& maxs ) = 0; + + // Draw lights + virtual void DrawLights( void ) = 0; + // FIXME: This function is a stub, doesn't do anything in the engine right now + virtual void DrawMaskEntities( void ) = 0; + + // Draw surfaces with alpha + virtual void DrawTranslucentSurfaces( IWorldRenderList *pList, int sortIndex, unsigned long flags, bool bShadowDepth ) = 0; + + // Draw Particles ( just draws the linefine for debugging map leaks ) + virtual void DrawLineFile( void ) = 0; + // Draw lightmaps + virtual void DrawLightmaps( IWorldRenderList *pList, int pageId ) = 0; + // Wraps view render sequence, sets up a view + virtual void ViewSetupVis( bool novis, int numorigins, const Vector origin[] ) = 0; + + // Return true if any of these leaves are visible in the current PVS. + virtual bool AreAnyLeavesVisible( int *leafList, int nLeaves ) = 0; + + virtual void VguiPaint( void ) = 0; + // Sets up view fade parameters + virtual void ViewDrawFade( byte *color, IMaterial *pMaterial ) = 0; + // Sets up the projection matrix for the specified field of view + virtual void OLD_SetProjectionMatrix( float fov, float zNear, float zFar ) = 0; + // Determine lighting at specified position + virtual colorVec GetLightAtPoint( Vector& pos ) = 0; + // Whose eyes are we looking through? + virtual int GetViewEntity( void ) = 0; + // Get engine field of view setting + virtual float GetFieldOfView( void ) = 0; + // 1 == ducking, 0 == not + virtual unsigned char **GetAreaBits( void ) = 0; + + // Set up fog for a particular leaf + virtual void SetFogVolumeState( int nVisibleFogVolume, bool bUseHeightFog ) = 0; + + // Installs a brush surface draw override method, null means use normal renderer + virtual void InstallBrushSurfaceRenderer( IBrushRenderer* pBrushRenderer ) = 0; + + // Draw brush model shadow + virtual void DrawBrushModelShadow( IClientRenderable *pRenderable ) = 0; + + // Does the leaf contain translucent surfaces? + virtual bool LeafContainsTranslucentSurfaces( IWorldRenderList *pList, int sortIndex, unsigned long flags ) = 0; + + virtual bool DoesBoxIntersectWaterVolume( const Vector &mins, const Vector &maxs, int leafWaterDataID ) = 0; + + virtual void SetAreaState( + unsigned char chAreaBits[MAX_AREA_STATE_BYTES], + unsigned char chAreaPortalBits[MAX_AREA_PORTAL_STATE_BYTES] ) = 0; + + // See i + virtual void VGui_Paint( int mode ) = 0; + + // Push, pop views (see PushViewFlags_t above for flags) + virtual void Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes ) = 0; + virtual void Push2DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes ) = 0; + virtual void PopView( Frustum frustumPlanes ) = 0; + + // Sets the main view + virtual void SetMainView( const Vector &vecOrigin, const QAngle &angles ) = 0; + + enum + { + VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS = 0x00000001 + }; + + // Wraps view render sequence, sets up a view + virtual void ViewSetupVisEx( bool novis, int numorigins, const Vector origin[], unsigned int &returnFlags ) = 0; + + //replaces the current view frustum with a rhyming replacement of your choice + virtual void OverrideViewFrustum( Frustum custom ) = 0; + + virtual void DrawBrushModelShadowDepth( IClientEntity *baseentity, model_t *model, const Vector& origin, const QAngle& angles, ERenderDepthMode DepthMode ) = 0; + virtual void UpdateBrushModelLightmap( model_t *model, IClientRenderable *pRenderable ) = 0; + virtual void BeginUpdateLightmaps( void ) = 0; + virtual void EndUpdateLightmaps( void ) = 0; + virtual void OLD_SetOffCenterProjectionMatrix( float fov, float zNear, float zFar, float flAspectRatio, float flBottom, float flTop, float flLeft, float flRight ) = 0; + virtual void OLD_SetProjectionMatrixOrtho( float left, float top, float right, float bottom, float zNear, float zFar ) = 0; + virtual void Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes, ITexture* pDepthTexture ) = 0; + virtual void GetMatricesForView( const CViewSetup &view, VMatrix *pWorldToView, VMatrix *pViewToProjection, VMatrix *pWorldToProjection, VMatrix *pWorldToPixels ) = 0; + virtual void DrawBrushModelEx( IClientEntity *baseentity, model_t *model, const Vector& origin, const QAngle& angles, DrawBrushModelMode_t mode ) = 0; +}; + +// change this when the new version is incompatable with the old +#define VENGINE_RENDERVIEW_INTERFACE_VERSION "VEngineRenderView014" + +#if defined(_STATIC_LINKED) && defined(CLIENT_DLL) +namespace Client +{ +extern IVRenderView *render; +} +#else +extern IVRenderView *render; +#endif + +#endif // IVRENDERVIEW_H diff --git a/public/ivtex.h b/public/ivtex.h new file mode 100644 index 0000000..b85b621 --- /dev/null +++ b/public/ivtex.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef IVTEX_H +#define IVTEX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "appframework/IAppSystem.h" + + +class IVTex : public IAppSystem +{ +public: + // For use by command-line tools + virtual int VTex( int argc, char **argv ) = 0; + + // For use by engine + virtual int VTex( CreateInterfaceFn filesystemFactory, const char *pGameDir, int argc, char **argv ) = 0; +}; + +#define IVTEX_VERSION_STRING "VTEX_003" + + +#endif // IVTEX_H diff --git a/public/ixboxsystem.h b/public/ixboxsystem.h new file mode 100644 index 0000000..009da96 --- /dev/null +++ b/public/ixboxsystem.h @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Interface to Xbox 360 system functions. Helps deal with the async system and Live +// functions by either providing a handle for the caller to check results or handling +// automatic cleanup of the async data when the caller doesn't care about the results. +// +//===========================================================================// + +#ifndef IXBOXSYSTEM_H +#define IXBOXSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#if !defined( _X360 ) +#include "xbox/xboxstubs.h" +#endif + +typedef void* AsyncHandle_t; +typedef void* XboxHandle_t; + +#ifdef POSIX +#define ERROR_SUCCESS 0 +#define ERROR_IO_PENDING 1 +#define ERROR_IO_INCOMPLETE 2 +#define ERROR_INSUFFICIENT_BUFFER 3 +#endif + +//----------------------------------------------------------------------------- +// Xbox system interface +//----------------------------------------------------------------------------- +abstract_class IXboxSystem +{ +public: + virtual AsyncHandle_t CreateAsyncHandle( void ) = 0; + virtual void ReleaseAsyncHandle( AsyncHandle_t handle ) = 0; + virtual int GetOverlappedResult( AsyncHandle_t handle, uint *pResultCode, bool bWait ) = 0; + virtual void CancelOverlappedOperation( AsyncHandle_t handle ) = 0; + + // Save/Load + virtual void GetModSaveContainerNames( const char *pchModName, const wchar_t **ppchDisplayName, const char **ppchName ) = 0; + virtual uint GetContainerRemainingSpace( void ) = 0; + virtual bool DeviceCapacityAdequate( DWORD nStorageID, const char *pModName ) = 0; + virtual DWORD DiscoverUserData( DWORD nUserID, const char *pModName ) = 0; + + // XUI + virtual bool ShowDeviceSelector( bool bForce, uint *pStorageID, AsyncHandle_t *pHandle ) = 0; + virtual void ShowSigninUI( uint nPanes, uint nFlags ) = 0; + + // Rich Presence and Matchmaking + virtual int UserSetContext( uint nUserIdx, uint nContextID, uint nContextValue, bool bAsync = true, AsyncHandle_t *pHandle = NULL ) = 0; + virtual int UserSetProperty( uint nUserIndex, uint nPropertyId, uint nBytes, const void *pvValue, bool bAsync = true, AsyncHandle_t *pHandle = NULL ) = 0; + + // Matchmaking + virtual int CreateSession( uint nFlags, uint nUserIdx, uint nMaxPublicSlots, uint nMaxPrivateSlots, uint64 *pNonce, void *pSessionInfo, XboxHandle_t *pSessionHandle, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual uint DeleteSession( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual uint SessionSearch( uint nProcedureIndex, uint nUserIndex, uint nNumResults, uint nNumUsers, uint nNumProperties, uint nNumContexts, XUSER_PROPERTY *pSearchProperties, XUSER_CONTEXT *pSearchContexts, uint *pcbResultsBuffer, XSESSION_SEARCHRESULT_HEADER *pSearchResults, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual uint SessionStart( XboxHandle_t hSession, uint nFlags, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual uint SessionEnd( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual int SessionJoinLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual int SessionJoinRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual int SessionLeaveLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual int SessionLeaveRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual int SessionMigrate( XboxHandle_t hSession, uint nUserIndex, void *pSessionInfo, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual int SessionArbitrationRegister( XboxHandle_t hSession, uint nFlags, uint64 nonce, uint *pBytes, void *pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + + // Stats + virtual int WriteStats( XboxHandle_t hSession, XUID xuid, uint nViews, void* pViews, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + + // Achievements + virtual int EnumerateAchievements( uint nUserIdx, uint64 xuid, uint nStartingIdx, uint nCount, void *pBuffer, uint nBufferBytes, bool bAsync = true, AsyncHandle_t *pAsyncHandle = NULL ) = 0; + virtual void AwardAchievement( uint nUserIdx, uint nAchievementId ) = 0; + + virtual void FinishContainerWrites( void ) = 0; + virtual uint GetContainerOpenResult( void ) = 0; + virtual uint OpenContainers( void ) = 0; + virtual void CloseContainers( void ) = 0; +}; + +#define XBOXSYSTEM_INTERFACE_VERSION "XboxSystemInterface001" + +#endif // IXBOXSYSTEM_H diff --git a/public/jigglebones.cpp b/public/jigglebones.cpp new file mode 100644 index 0000000..29b8647 --- /dev/null +++ b/public/jigglebones.cpp @@ -0,0 +1,808 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "tier1/convar.h" +#include "jigglebones.h" + +#ifdef CLIENT_DLL +#include "engine/ivdebugoverlay.h" +#include "cdll_client_int.h" +#endif // CLIENT_DLL + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifdef CLIENT_DLL +//----------------------------------------------------------------------------- +ConVar cl_jiggle_bone_debug( "cl_jiggle_bone_debug", "0", FCVAR_CHEAT, "Display physics-based 'jiggle bone' debugging information" ); +ConVar cl_jiggle_bone_debug_yaw_constraints( "cl_jiggle_bone_debug_yaw_constraints", "0", FCVAR_CHEAT, "Display physics-based 'jiggle bone' debugging information" ); +ConVar cl_jiggle_bone_debug_pitch_constraints( "cl_jiggle_bone_debug_pitch_constraints", "0", FCVAR_CHEAT, "Display physics-based 'jiggle bone' debugging information" ); +#endif // CLIENT_DLL + +ConVar cl_jiggle_bone_framerate_cutoff( "cl_jiggle_bone_framerate_cutoff", "20", 0, "Skip jiggle bone simulation if framerate drops below this value (frames/second)" ); + + +//----------------------------------------------------------------------------- +JiggleData * CJiggleBones::GetJiggleData( int bone, float currenttime, const Vector &initBasePos, const Vector &initTipPos ) +{ + FOR_EACH_LL( m_jiggleBoneState, it ) + { + if ( m_jiggleBoneState[it].bone == bone ) + { + return &m_jiggleBoneState[it]; + } + } + + JiggleData data; + data.Init( bone, currenttime, initBasePos, initTipPos ); + + // Start out using jiggle bones for at least 16 frames. + data.useGoalMatrixCount = 0; + data.useJiggleBoneCount = 16; + + int idx = m_jiggleBoneState.AddToHead( data ); + if ( idx == m_jiggleBoneState.InvalidIndex() ) + return NULL; + + return &m_jiggleBoneState[idx]; +} + + +//----------------------------------------------------------------------------- +/** + * Do spring physics calculations and update "jiggle bone" matrix + * (Michael Booth, Turtle Rock Studios) + */ +void CJiggleBones::BuildJiggleTransformations( int boneIndex, float currenttime, const mstudiojigglebone_t *jiggleInfo, const matrix3x4_t &goalMX, matrix3x4_t &boneMX ) +{ + Vector goalBasePosition; + MatrixPosition( goalMX, goalBasePosition ); + + Vector goalForward, goalUp, goalLeft; + MatrixGetColumn( goalMX, 0, goalLeft ); + MatrixGetColumn( goalMX, 1, goalUp ); + MatrixGetColumn( goalMX, 2, goalForward ); + + // compute goal tip position + Vector goalTip = goalBasePosition + jiggleInfo->length * goalForward; + + JiggleData *data = GetJiggleData( boneIndex, currenttime, goalBasePosition, goalTip ); + if ( !data ) + { + return; + } + + // if frames have been skipped since our last update, we were likely + // disabled and re-enabled, so re-init +#if defined(CLIENT_DLL) || defined(GAME_DLL) + float timeTolerance = 1.2f * gpGlobals->frametime; +#else + float timeTolerance = 0.5f; +#endif + + if ( currenttime - data->lastUpdate > timeTolerance ) + { + data->Init( boneIndex, currenttime, goalBasePosition, goalTip ); + } + + if ( data->lastLeft.IsZero() ) + { + data->lastLeft = goalLeft; + } + + // limit maximum deltaT to avoid simulation blowups + // if framerate is too low, skip jigglebones altogether, since movement will be too + // large between frames to simulate with a simple Euler integration + float deltaT = currenttime - data->lastUpdate; + + const float thousandHZ = 0.001f; + bool bMaxDeltaT = deltaT < thousandHZ; + bool bUseGoalMatrix = cl_jiggle_bone_framerate_cutoff.GetFloat() <= 0.0f || deltaT > ( 1.0f / cl_jiggle_bone_framerate_cutoff.GetFloat() ); + + if ( bUseGoalMatrix ) + { + // We hit the jiggle bone framerate cutoff. Reset the useGoalMatrixCount so we + // use the goal matrix at least 32 frames and don't flash back and forth. + data->useGoalMatrixCount = 32; + } + else if ( data->useGoalMatrixCount > 0 ) + { + // Below the cutoff, but still need to use the goal matrix a few more times. + bUseGoalMatrix = true; + data->useGoalMatrixCount--; + } + else + { + // Use real jiggle bones. Woot! + data->useJiggleBoneCount = 32; + } + + if ( data->useJiggleBoneCount > 0 ) + { + // Make sure we draw at least runs of 32 frames with real jiggle bones. + data->useJiggleBoneCount--; + data->useGoalMatrixCount = 0; + bUseGoalMatrix = false; + } + + if ( bMaxDeltaT ) + { + deltaT = thousandHZ; + } + else if ( bUseGoalMatrix ) + { + // disable jigglebone - just use goal matrix + boneMX = goalMX; + return; + } + + // we want lastUpdate here, so if jigglebones were skipped they get reinitialized if they turn back on + data->lastUpdate = currenttime; + + // + // Bone tip flex + // + if ( jiggleInfo->flags & ( JIGGLE_IS_FLEXIBLE | JIGGLE_IS_RIGID ) ) + { + // apply gravity in global space + data->tipAccel.z -= jiggleInfo->tipMass; + + if ( jiggleInfo->flags & JIGGLE_IS_FLEXIBLE ) + { + // decompose into local coordinates + Vector error = goalTip - data->tipPos; + + Vector localError; + localError.x = DotProduct( goalLeft, error ); + localError.y = DotProduct( goalUp, error ); + localError.z = DotProduct( goalForward, error ); + + Vector localVel; + localVel.x = DotProduct( goalLeft, data->tipVel ); + localVel.y = DotProduct( goalUp, data->tipVel ); + + // yaw spring + float yawAccel = jiggleInfo->yawStiffness * localError.x - jiggleInfo->yawDamping * localVel.x; + + // pitch spring + float pitchAccel = jiggleInfo->pitchStiffness * localError.y - jiggleInfo->pitchDamping * localVel.y; + + if ( jiggleInfo->flags & JIGGLE_HAS_LENGTH_CONSTRAINT ) + { + // drive tip towards goal tip position + data->tipAccel += yawAccel * goalLeft + pitchAccel * goalUp; + } + else + { + // allow flex along length of spring + localVel.z = DotProduct( goalForward, data->tipVel ); + + // along spring + float alongAccel = jiggleInfo->alongStiffness * localError.z - jiggleInfo->alongDamping * localVel.z; + + // drive tip towards goal tip position + data->tipAccel += yawAccel * goalLeft + pitchAccel * goalUp + alongAccel * goalForward; + } + } + + + // simple euler integration + data->tipVel += data->tipAccel * deltaT; + data->tipPos += data->tipVel * deltaT; + + // clear this timestep's accumulated accelerations + data->tipAccel = vec3_origin; + + // + // Apply optional constraints + // + if ( jiggleInfo->flags & ( JIGGLE_HAS_YAW_CONSTRAINT | JIGGLE_HAS_PITCH_CONSTRAINT ) ) + { + // find components of spring vector in local coordinate system + Vector along = data->tipPos - goalBasePosition; + Vector localAlong; + localAlong.x = DotProduct( goalLeft, along ); + localAlong.y = DotProduct( goalUp, along ); + localAlong.z = DotProduct( goalForward, along ); + + Vector localVel; + localVel.x = DotProduct( goalLeft, data->tipVel ); + localVel.y = DotProduct( goalUp, data->tipVel ); + localVel.z = DotProduct( goalForward, data->tipVel ); + + if ( jiggleInfo->flags & JIGGLE_HAS_YAW_CONSTRAINT ) + { + // enforce yaw constraints in local XZ plane + float yawError = atan2( localAlong.x, localAlong.z ); + + bool isAtLimit = false; + float yaw = 0.0f; + + if ( yawError < jiggleInfo->minYaw ) + { + // at angular limit + isAtLimit = true; + yaw = jiggleInfo->minYaw; + } + else if ( yawError > jiggleInfo->maxYaw ) + { + // at angular limit + isAtLimit = true; + yaw = jiggleInfo->maxYaw; + } + + if ( isAtLimit ) + { + float sy, cy; + SinCos( yaw, &sy, &cy ); + + // yaw matrix + matrix3x4_t yawMatrix; + + yawMatrix[0][0] = cy; + yawMatrix[1][0] = 0; + yawMatrix[2][0] = -sy; + + yawMatrix[0][1] = 0; + yawMatrix[1][1] = 1.0f; + yawMatrix[2][1] = 0; + + yawMatrix[0][2] = sy; + yawMatrix[1][2] = 0; + yawMatrix[2][2] = cy; + + yawMatrix[0][3] = 0; + yawMatrix[1][3] = 0; + yawMatrix[2][3] = 0; + + // global coordinates of limit + matrix3x4_t limitMatrix; + ConcatTransforms( goalMX, yawMatrix, limitMatrix ); + + Vector limitLeft( limitMatrix.m_flMatVal[0][0], + limitMatrix.m_flMatVal[1][0], + limitMatrix.m_flMatVal[2][0] ); + + Vector limitUp( limitMatrix.m_flMatVal[0][1], + limitMatrix.m_flMatVal[1][1], + limitMatrix.m_flMatVal[2][1] ); + + Vector limitForward( limitMatrix.m_flMatVal[0][2], + limitMatrix.m_flMatVal[1][2], + limitMatrix.m_flMatVal[2][2] ); + +#ifdef CLIENT_DLL + if ( cl_jiggle_bone_debug_yaw_constraints.GetBool() ) + { + float dT = 0.01f; + const float axisSize = 10.0f; + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * limitLeft, 0, 255, 255, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * limitUp, 255, 255, 0, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * limitForward, 255, 0, 255, true, dT ); + } +#endif // CLIENT_DLL + + Vector limitAlong( DotProduct( limitLeft, along ), + DotProduct( limitUp, along ), + DotProduct( limitForward, along ) ); + + // clip to limit plane + data->tipPos = goalBasePosition + limitAlong.y * limitUp + limitAlong.z * limitForward; + + // removed friction and velocity clipping against constraint - was causing simulation blowups (MSB 12/9/2010) + data->tipVel.Zero(); + + // update along vectors for use by pitch constraint + along = data->tipPos - goalBasePosition; + localAlong.x = DotProduct( goalLeft, along ); + localAlong.y = DotProduct( goalUp, along ); + localAlong.z = DotProduct( goalForward, along ); + + localVel.x = DotProduct( goalLeft, data->tipVel ); + localVel.y = DotProduct( goalUp, data->tipVel ); + localVel.z = DotProduct( goalForward, data->tipVel ); + } + } + + + if ( jiggleInfo->flags & JIGGLE_HAS_PITCH_CONSTRAINT ) + { + // enforce pitch constraints in local YZ plane + float pitchError = atan2( localAlong.y, localAlong.z ); + + bool isAtLimit = false; + float pitch = 0.0f; + + if ( pitchError < jiggleInfo->minPitch ) + { + // at angular limit + isAtLimit = true; + pitch = jiggleInfo->minPitch; + } + else if ( pitchError > jiggleInfo->maxPitch ) + { + // at angular limit + isAtLimit = true; + pitch = jiggleInfo->maxPitch; + } + + if ( isAtLimit ) + { + float sp, cp; + SinCos( pitch, &sp, &cp ); + + // pitch matrix + matrix3x4_t pitchMatrix; + + pitchMatrix[0][0] = 1.0f; + pitchMatrix[1][0] = 0; + pitchMatrix[2][0] = 0; + + pitchMatrix[0][1] = 0; + pitchMatrix[1][1] = cp; + pitchMatrix[2][1] = -sp; + + pitchMatrix[0][2] = 0; + pitchMatrix[1][2] = sp; + pitchMatrix[2][2] = cp; + + pitchMatrix[0][3] = 0; + pitchMatrix[1][3] = 0; + pitchMatrix[2][3] = 0; + + // global coordinates of limit + matrix3x4_t limitMatrix; + ConcatTransforms( goalMX, pitchMatrix, limitMatrix ); + + Vector limitLeft( limitMatrix.m_flMatVal[0][0], + limitMatrix.m_flMatVal[1][0], + limitMatrix.m_flMatVal[2][0] ); + + Vector limitUp( limitMatrix.m_flMatVal[0][1], + limitMatrix.m_flMatVal[1][1], + limitMatrix.m_flMatVal[2][1] ); + + Vector limitForward( limitMatrix.m_flMatVal[0][2], + limitMatrix.m_flMatVal[1][2], + limitMatrix.m_flMatVal[2][2] ); + +#ifdef CLIENT_DLL + if (cl_jiggle_bone_debug_pitch_constraints.GetBool()) + { + float dT = 0.01f; + const float axisSize = 10.0f; + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * limitLeft, 0, 255, 255, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * limitUp, 255, 255, 0, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * limitForward, 255, 0, 255, true, dT ); + } +#endif // CLIENT_DLL + + Vector limitAlong( DotProduct( limitLeft, along ), + DotProduct( limitUp, along ), + DotProduct( limitForward, along ) ); + + // clip to limit plane + data->tipPos = goalBasePosition + limitAlong.x * limitLeft + limitAlong.z * limitForward; + + // removed friction and velocity clipping against constraint - was causing simulation blowups (MSB 12/9/2010) + data->tipVel.Zero(); + } + } + } + + // needed for matrix assembly below + Vector forward = data->tipPos - goalBasePosition; + forward.NormalizeInPlace(); + + if ( jiggleInfo->flags & JIGGLE_HAS_ANGLE_CONSTRAINT ) + { + // enforce max angular error + Vector error = goalTip - data->tipPos; + float dot = DotProduct( forward, goalForward ); + float angleBetween = acos( dot ); + if ( dot < 0.0f ) + { + angleBetween = 2.0f * M_PI - angleBetween; + } + + if ( angleBetween > jiggleInfo->angleLimit ) + { + // at angular limit + float maxBetween = jiggleInfo->length * sin( jiggleInfo->angleLimit ); + + Vector delta = goalTip - data->tipPos; + delta.NormalizeInPlace(); + + data->tipPos = goalTip - maxBetween * delta; + + forward = data->tipPos - goalBasePosition; + forward.NormalizeInPlace(); + } + } + + if ( jiggleInfo->flags & JIGGLE_HAS_LENGTH_CONSTRAINT ) + { + // enforce spring length + data->tipPos = goalBasePosition + jiggleInfo->length * forward; + + // zero velocity along forward bone axis + data->tipVel -= DotProduct( data->tipVel, forward ) * forward; + } + + // + // Build bone matrix to align along current tip direction + // + Vector left = CrossProduct( goalUp, forward ); + left.NormalizeInPlace(); + + if ( DotProduct( left, data->lastLeft ) < 0.0f ) + { + // The bone has rotated so far its on the other side of the up vector + // resulting in the cross product result flipping 180 degrees around the up + // vector. Flip it back. + left = -left; + } + data->lastLeft = left; + +#ifdef CLIENT_DLL + if ( cl_jiggle_bone_debug.GetBool() ) + { + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + 10.0f * data->lastLeft, 255, 0, 255, true, 0.01f ); + } +#endif + + Vector up = CrossProduct( forward, left ); + + boneMX[0][0] = left.x; + boneMX[1][0] = left.y; + boneMX[2][0] = left.z; + boneMX[0][1] = up.x; + boneMX[1][1] = up.y; + boneMX[2][1] = up.z; + boneMX[0][2] = forward.x; + boneMX[1][2] = forward.y; + boneMX[2][2] = forward.z; + + boneMX[0][3] = goalBasePosition.x; + boneMX[1][3] = goalBasePosition.y; + boneMX[2][3] = goalBasePosition.z; + } + + + // + // Bone base flex + // + if ( jiggleInfo->flags & JIGGLE_HAS_BASE_SPRING ) + { + // gravity + data->baseAccel.z -= jiggleInfo->baseMass; + + // simple spring + Vector error = goalBasePosition - data->basePos; + data->baseAccel += jiggleInfo->baseStiffness * error - jiggleInfo->baseDamping * data->baseVel; + + data->baseVel += data->baseAccel * deltaT; + data->basePos += data->baseVel * deltaT; + + // clear this timestep's accumulated accelerations + data->baseAccel = vec3_origin; + + // constrain to limits + error = data->basePos - goalBasePosition; + Vector localError; + localError.x = DotProduct( goalLeft, error ); + localError.y = DotProduct( goalUp, error ); + localError.z = DotProduct( goalForward, error ); + + Vector localVel; + localVel.x = DotProduct( goalLeft, data->baseVel ); + localVel.y = DotProduct( goalUp, data->baseVel ); + localVel.z = DotProduct( goalForward, data->baseVel ); + + // horizontal constraint + if ( localError.x < jiggleInfo->baseMinLeft ) + { + localError.x = jiggleInfo->baseMinLeft; + + // friction + data->baseAccel -= jiggleInfo->baseLeftFriction * (localVel.y * goalUp + localVel.z * goalForward); + } + else if ( localError.x > jiggleInfo->baseMaxLeft ) + { + localError.x = jiggleInfo->baseMaxLeft; + + // friction + data->baseAccel -= jiggleInfo->baseLeftFriction * (localVel.y * goalUp + localVel.z * goalForward); + } + + if ( localError.y < jiggleInfo->baseMinUp ) + { + localError.y = jiggleInfo->baseMinUp; + + // friction + data->baseAccel -= jiggleInfo->baseUpFriction * (localVel.x * goalLeft + localVel.z * goalForward); + } + else if ( localError.y > jiggleInfo->baseMaxUp ) + { + localError.y = jiggleInfo->baseMaxUp; + + // friction + data->baseAccel -= jiggleInfo->baseUpFriction * (localVel.x * goalLeft + localVel.z * goalForward); + } + + if ( localError.z < jiggleInfo->baseMinForward ) + { + localError.z = jiggleInfo->baseMinForward; + + // friction + data->baseAccel -= jiggleInfo->baseForwardFriction * (localVel.x * goalLeft + localVel.y * goalUp); + } + else if ( localError.z > jiggleInfo->baseMaxForward ) + { + localError.z = jiggleInfo->baseMaxForward; + + // friction + data->baseAccel -= jiggleInfo->baseForwardFriction * (localVel.x * goalLeft + localVel.y * goalUp); + } + + data->basePos = goalBasePosition + localError.x * goalLeft + localError.y * goalUp + localError.z * goalForward; + + + // fix up velocity + data->baseVel = (data->basePos - data->baseLastPos) / deltaT; + data->baseLastPos = data->basePos; + + + if ( !( jiggleInfo->flags & ( JIGGLE_IS_FLEXIBLE | JIGGLE_IS_RIGID ) ) ) + { + // no tip flex - use bone's goal orientation + boneMX = goalMX; + } + + // update bone position + MatrixSetColumn( data->basePos, 3, boneMX ); + } + else if ( jiggleInfo->flags & JIGGLE_IS_BOING ) + { + // estimate velocity + Vector vel = goalBasePosition - data->lastBoingPos; + +#ifdef CLIENT_DLL + if ( cl_jiggle_bone_debug.GetBool() ) + { + debugoverlay->AddLineOverlay( data->lastBoingPos, goalBasePosition, 0, 128, ( gpGlobals->framecount & 0x1 ) ? 0 : 200, true, 999.9f ); + } +#endif + + data->lastBoingPos = goalBasePosition; + + float speed = vel.NormalizeInPlace(); + if ( speed < 0.00001f ) + { + vel = Vector( 0, 0, 1.0f ); + speed = 0.0f; + } + else + { + speed /= deltaT; + } + + data->boingTime += deltaT; + + // if velocity changed a lot, we impacted and should *boing* + const float minSpeed = 5.0f; // 15.0f; + const float minReBoingTime = 0.5f; + if ( ( speed > minSpeed || data->boingSpeed > minSpeed ) && data->boingTime > minReBoingTime ) + { + if ( fabs( data->boingSpeed - speed ) > jiggleInfo->boingImpactSpeed || DotProduct( vel, data->boingVelDir ) < jiggleInfo->boingImpactAngle ) + { + data->boingTime = 0.0f; + data->boingDir = -vel; + +#ifdef CLIENT_DLL + if ( cl_jiggle_bone_debug.GetBool() ) + { + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + 5.0f * data->boingDir, 255, 255, 0, true, 999.9f ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + Vector( 0.1, 0, 0 ), 128, 128, 0, true, 999.9f ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + Vector( 0, 0.1, 0 ), 128, 128, 0, true, 999.9f ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + Vector( 0, 0, 0.1 ), 128, 128, 0, true, 999.9f ); + } +#endif + } + } + + data->boingVelDir = vel; + data->boingSpeed = speed; + + float damping = 1.0f - ( jiggleInfo->boingDampingRate * data->boingTime ); + if ( damping < 0.01f ) + { + // boing has entirely damped out + boneMX = goalMX; + } + else + { + damping *= damping; + damping *= damping; + + float flex = jiggleInfo->boingAmplitude * cos( jiggleInfo->boingFrequency * data->boingTime ) * damping; + + float squash = 1.0f + flex; + float stretch = 1.0f - flex; + + + boneMX[0][0] = goalLeft.x; + boneMX[1][0] = goalLeft.y; + boneMX[2][0] = goalLeft.z; + + boneMX[0][1] = goalUp.x; + boneMX[1][1] = goalUp.y; + boneMX[2][1] = goalUp.z; + + boneMX[0][2] = goalForward.x; + boneMX[1][2] = goalForward.y; + boneMX[2][2] = goalForward.z; + + boneMX[0][3] = 0.0f; + boneMX[1][3] = 0.0f; + boneMX[2][3] = 0.0f; + + + // build transform into "boing space", where Z is along primary boing axis + Vector boingSide; + if ( fabs( data->boingDir.x ) < 0.9f ) + { + boingSide = CrossProduct( data->boingDir, Vector( 1.0f, 0, 0 ) ); + } + else + { + boingSide = CrossProduct( data->boingDir, Vector( 0, 0, 1.0f ) ); + } + boingSide.NormalizeInPlace(); + + Vector boingOtherSide = CrossProduct( data->boingDir, boingSide ); + + matrix3x4_t xfrmToBoingCoordsMX; + + xfrmToBoingCoordsMX[0][0] = boingSide.x; + xfrmToBoingCoordsMX[0][1] = boingSide.y; + xfrmToBoingCoordsMX[0][2] = boingSide.z; + + xfrmToBoingCoordsMX[1][0] = boingOtherSide.x; + xfrmToBoingCoordsMX[1][1] = boingOtherSide.y; + xfrmToBoingCoordsMX[1][2] = boingOtherSide.z; + + xfrmToBoingCoordsMX[2][0] = data->boingDir.x; + xfrmToBoingCoordsMX[2][1] = data->boingDir.y; + xfrmToBoingCoordsMX[2][2] = data->boingDir.z; + + xfrmToBoingCoordsMX[0][3] = 0.0f; + xfrmToBoingCoordsMX[1][3] = 0.0f; + xfrmToBoingCoordsMX[2][3] = 0.0f; + + // build squash and stretch transform in "boing space" + matrix3x4_t boingMX; + + boingMX[0][0] = squash; + boingMX[1][0] = 0.0f; + boingMX[2][0] = 0.0f; + + boingMX[0][1] = 0.0f; + boingMX[1][1] = squash; + boingMX[2][1] = 0.0f; + + boingMX[0][2] = 0.0f; + boingMX[1][2] = 0.0f; + boingMX[2][2] = stretch; + + boingMX[0][3] = 0.0f; + boingMX[1][3] = 0.0f; + boingMX[2][3] = 0.0f; + + // transform back from boing space (inverse is transpose since orthogonal) + matrix3x4_t xfrmFromBoingCoordsMX; + xfrmFromBoingCoordsMX[0][0] = xfrmToBoingCoordsMX[0][0]; + xfrmFromBoingCoordsMX[1][0] = xfrmToBoingCoordsMX[0][1]; + xfrmFromBoingCoordsMX[2][0] = xfrmToBoingCoordsMX[0][2]; + + xfrmFromBoingCoordsMX[0][1] = xfrmToBoingCoordsMX[1][0]; + xfrmFromBoingCoordsMX[1][1] = xfrmToBoingCoordsMX[1][1]; + xfrmFromBoingCoordsMX[2][1] = xfrmToBoingCoordsMX[1][2]; + + xfrmFromBoingCoordsMX[0][2] = xfrmToBoingCoordsMX[2][0]; + xfrmFromBoingCoordsMX[1][2] = xfrmToBoingCoordsMX[2][1]; + xfrmFromBoingCoordsMX[2][2] = xfrmToBoingCoordsMX[2][2]; + + xfrmFromBoingCoordsMX[0][3] = 0.0f; + xfrmFromBoingCoordsMX[1][3] = 0.0f; + xfrmFromBoingCoordsMX[2][3] = 0.0f; + + // put it all together + matrix3x4_t xfrmMX; + MatrixMultiply( xfrmToBoingCoordsMX, boingMX, xfrmMX ); + MatrixMultiply( xfrmMX, xfrmFromBoingCoordsMX, xfrmMX ); + MatrixMultiply( boneMX, xfrmMX, boneMX ); + +#ifdef CLIENT_DLL + if ( cl_jiggle_bone_debug.GetBool() ) + { + float dT = 0.01f; + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + 50.0f * data->boingDir, 255, 255, 0, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + 50.0f * boingSide, 255, 0, 255, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + 50.0f * boingOtherSide, 0, 255, 255, true, dT ); + } +#endif + + boneMX[0][3] = goalBasePosition.x; + boneMX[1][3] = goalBasePosition.y; + boneMX[2][3] = goalBasePosition.z; + } + } + else if ( !( jiggleInfo->flags & ( JIGGLE_IS_FLEXIBLE | JIGGLE_IS_RIGID ) ) ) + { + // no flex at all - just use goal matrix + boneMX = goalMX; + } + +#ifdef CLIENT_DLL + // debug display for client only so server doesn't try to also draw it + if ( cl_jiggle_bone_debug.GetBool() ) + { + float dT = 0.01f; + const float axisSize = 5.0f; + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * goalLeft, 255, 0, 0, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * goalUp, 0, 255, 0, true, dT ); + debugoverlay->AddLineOverlay( goalBasePosition, goalBasePosition + axisSize * goalForward, 0, 0, 255, true, dT ); + + if ( cl_jiggle_bone_debug.GetInt() > 1 ) + { + DevMsg( "Jiggle bone #%d, basePos( %3.2f, %3.2f, %3.2f ), tipPos( %3.2f, %3.2f, %3.2f ), left( %3.2f, %3.2f, %3.2f ), up( %3.2f, %3.2f, %3.2f ), forward( %3.2f, %3.2f, %3.2f )\n", + data->bone, + goalBasePosition.x, goalBasePosition.y, goalBasePosition.z, + data->tipPos.x, data->tipPos.y, data->tipPos.z, + goalLeft.x, goalLeft.y, goalLeft.z, + goalUp.x, goalUp.y, goalUp.z, + goalForward.x, goalForward.y, goalForward.z ); + } + + const float sz = 1.0f; + + if ( jiggleInfo->flags & ( JIGGLE_IS_FLEXIBLE | JIGGLE_IS_RIGID ) ) + { + debugoverlay->AddLineOverlay( goalBasePosition, + data->tipPos, 255, 255, 0, true, dT ); + + debugoverlay->AddLineOverlay( data->tipPos + Vector( -sz, 0, 0 ), + data->tipPos + Vector( sz, 0, 0 ), 0, 255, 255, true, dT ); + debugoverlay->AddLineOverlay( data->tipPos + Vector( 0, -sz, 0 ), + data->tipPos + Vector( 0, sz, 0 ), 0, 255, 255, true, dT ); + debugoverlay->AddLineOverlay( data->tipPos + Vector( 0, 0, -sz ), + data->tipPos + Vector( 0, 0, sz ), 0, 255, 255, true, dT ); + } + + if ( jiggleInfo->flags & JIGGLE_HAS_BASE_SPRING ) + { + debugoverlay->AddLineOverlay( data->basePos + Vector( -sz, 0, 0 ), + data->basePos + Vector( sz, 0, 0 ), 255, 0, 255, true, dT ); + debugoverlay->AddLineOverlay( data->basePos + Vector( 0, -sz, 0 ), + data->basePos + Vector( 0, sz, 0 ), 255, 0, 255, true, dT ); + debugoverlay->AddLineOverlay( data->basePos + Vector( 0, 0, -sz ), + data->basePos + Vector( 0, 0, sz ), 255, 0, 255, true, dT ); + } + + + if ( jiggleInfo->flags & JIGGLE_IS_BOING ) + { + if ( cl_jiggle_bone_debug.GetInt() > 2 ) + { + DevMsg( " boingSpeed = %3.2f, boingVelDir( %3.2f, %3.2f, %3.2f )\n", data->boingVelDir.Length() / deltaT, data->boingVelDir.x, data->boingVelDir.y, data->boingVelDir.z ); + } + } + } +#endif // CLIENT_DLL +} + diff --git a/public/jigglebones.h b/public/jigglebones.h new file mode 100644 index 0000000..037a486 --- /dev/null +++ b/public/jigglebones.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#ifndef C_JIGGLEBONES_H +#define C_JIGGLEBONES_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "studio.h" +#include "utlvector.h" +#include "utllinkedlist.h" + +//----------------------------------------------------------------------------- +/** + * JiggleData is the instance-specific data for a jiggle bone + */ +struct JiggleData +{ + void Init( int initBone, float currenttime, const Vector &initBasePos, const Vector &initTipPos ) + { + bone = initBone; + + lastUpdate = currenttime; + + basePos = initBasePos; + baseLastPos = basePos; + baseVel.Init(); + baseAccel.Init(); + + tipPos = initTipPos; + tipVel.Init(); + tipAccel.Init(); + + lastLeft = Vector( 0, 0, 0 ); + + lastBoingPos = initBasePos; + boingDir = Vector( 0.0f, 0.0f, 1.0f ); + boingVelDir.Init(); + boingSpeed = 0.0f; + boingTime = 0.0f; + } + + int bone; + + float lastUpdate; // based on gpGlobals->realtime + + Vector basePos; // position of the base of the jiggle bone + Vector baseLastPos; + Vector baseVel; + Vector baseAccel; + + Vector tipPos; // position of the tip of the jiggle bone + Vector tipVel; + Vector tipAccel; + Vector lastLeft; // previous up vector + + Vector lastBoingPos; // position of base of jiggle bone last update for tracking velocity + Vector boingDir; // current direction along which the boing effect is occurring + Vector boingVelDir; // current estimation of jiggle bone unit velocity vector for boing effect + float boingSpeed; // current estimation of jiggle bone speed for boing effect + float boingTime; + + int useGoalMatrixCount; // Count of times we need to fast draw using goal matrix. + int useJiggleBoneCount; // Count of times we need to draw using real jiggly bones. +}; + +class CJiggleBones +{ +public: + JiggleData * GetJiggleData( int bone, float currenttime, const Vector &initBasePos, const Vector &initTipPos ); + void BuildJiggleTransformations( int boneIndex, float currentime, const mstudiojigglebone_t *jiggleParams, const matrix3x4_t &goalMX, matrix3x4_t &boneMX ); + + CUtlLinkedList< JiggleData > m_jiggleBoneState; +}; + + +extern void DevMsgRT( PRINTF_FORMAT_STRING char const* pMsg, ... ); + +#endif // C_BASEANIMATING_H diff --git a/public/jpeglib/jconfig.h b/public/jpeglib/jconfig.h new file mode 100644 index 0000000..23ebaa6 --- /dev/null +++ b/public/jpeglib/jconfig.h @@ -0,0 +1,56 @@ +/* jconfig.h. Generated from jconfig.cfg by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.txt for explanations */ + +#define HAVE_PROTOTYPES 1 +#define HAVE_UNSIGNED_CHAR 1 +#define HAVE_UNSIGNED_SHORT 1 +/* #undef void */ +/* #undef const */ +/* #undef CHAR_IS_UNSIGNED */ +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_LOCALE_H 1 +/* #undef NEED_BSD_STRINGS */ +/* #undef NEED_SYS_TYPES_H */ +/* #undef NEED_FAR_POINTERS */ +/* #undef NEED_SHORT_EXTERNAL_NAMES */ +/* Define this if you get warnings about undefined structures. */ +/* #undef INCOMPLETE_TYPES_BROKEN */ + +/* Define "boolean" as unsigned char, not int, on Windows systems. */ +#ifdef _WIN32 +#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#ifdef JPEG_INTERNALS + +/* #undef RIGHT_SHIFT_IS_UNSIGNED */ +#ifdef __cplusplus +#define INLINE __inline__ +#endif +/* These are for configuring the JPEG memory manager. */ +/* #undef DEFAULT_MAX_MEM */ +/* #undef NO_MKTEMP */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +/* #undef RLE_SUPPORTED */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* #undef TWO_FILE_COMMANDLINE */ +/* #undef NEED_SIGNAL_CATCHER */ +/* #undef DONT_USE_B_MODE */ + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +/* #undef PROGRESS_REPORT */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/public/jpeglib/jmorecfg.h b/public/jpeglib/jmorecfg.h new file mode 100644 index 0000000..928d052 --- /dev/null +++ b/public/jpeglib/jmorecfg.h @@ -0,0 +1,371 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ +#ifndef _BASETSD_H /* MinGW is slightly different */ +#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ +typedef long INT32; +#endif +#endif +#endif +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifndef FAR +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/public/jpeglib/jpeglib.h b/public/jpeglib/jpeglib.h new file mode 100644 index 0000000..5039d4b --- /dev/null +++ b/public/jpeglib/jpeglib.h @@ -0,0 +1,1158 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2002-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +extern "C" { +#endif +#endif + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 80". + */ + +#define JPEG_LIB_VERSION 80 /* Version 8.0 */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples, + * reflecting any scaling we choose to apply during the DCT step. + * Values from 1 to 16 are supported. + * Note that different components may receive different DCT scalings. + */ + int DCT_h_scaled_size; + int DCT_v_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface); + * DCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_h_scaled_size/DCTSIZE) + * and similarly for height. + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + JDIMENSION jpeg_width; /* scaled JPEG image width */ + JDIMENSION jpeg_height; /* scaled JPEG image height */ + /* Dimensions of actual JPEG image that will be written to file, + * derived from input dimensions by scaling factors above. + * These fields are computed by jpeg_start_compress(). + * You can also use jpeg_calc_jpeg_dimensions() to determine these values + * in advance of calling jpeg_start_compress(). + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + int q_scale_factor[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined, + * and corresponding scale factors (percentage, initialized 100). + */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* These fields are derived from Se of first SOS marker. + */ + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array for entropy decode */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_mem_dest jMemDest +#define jpeg_mem_src jMemSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_default_qtables jDefQTables +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_calc_jpeg_dimensions jCjpegDimensions +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_core_output_dimensions jCoreDimensions +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Data source and destination managers: memory buffers. */ +EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, + unsigned char ** outbuffer, + unsigned long * outsize)); +EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, + unsigned char * inbuffer, + unsigned long insize)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Precalculate JPEG dimensions for current compression parameters. */ +EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.txt concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +} +#endif +#endif + +#endif /* JPEGLIB_H */ diff --git a/public/kevvaluescompiler.cpp b/public/kevvaluescompiler.cpp new file mode 100644 index 0000000..5645906 --- /dev/null +++ b/public/kevvaluescompiler.cpp @@ -0,0 +1,436 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "keyvaluescompiler.h" +#include "filesystem.h" +#include "tier1/KeyValues.h" + +extern IFileSystem *g_pFullFileSystem; + +bool CRunTimeKeyValuesStringTable::ReadStringTable( int numStrings, CUtlBuffer& buf ) +{ + Assert( m_Strings.Count() == 0 ); + + CUtlVector< int > offsets; + offsets.EnsureCapacity( numStrings ); + + offsets.CopyArray( (int *)( buf.PeekGet() ), numStrings ); + + // Skip over data + buf.SeekGet( CUtlBuffer::SEEK_HEAD, buf.TellGet() + numStrings * sizeof( int ) ); + + int stringSize = buf.GetInt(); + + // Read in the string table + m_Strings.EnsureCapacity( numStrings ); + int i; + for ( i = 0 ; i < numStrings; ++i ) + { + m_Strings.AddToTail( (const char *)buf.PeekGet( offsets[ i ] ) ); + } + + buf.SeekGet( CUtlBuffer::SEEK_HEAD, buf.TellGet() + stringSize ); + + return true; +} + +void CCompiledKeyValuesWriter::BuildKVData_R( KeyValues *kv, int parent ) +{ + // Add self + KVInfo_t info; + info.key = m_StringTable.AddString( kv->GetName() ); + info.value = m_StringTable.AddString( kv->GetString() ); + + info.SetSubTree( kv->GetFirstSubKey() != NULL ? true : false ); + info.SetParent( parent ); + + int newParent = m_Data.AddToTail( info ); + + // Then add children + for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) + { + BuildKVData_R( sub, newParent ); + } + + // Then add peers + if ( parent == -1 ) + { + if ( kv->GetNextKey() ) + { + BuildKVData_R( kv->GetNextKey(), parent ); + } + } +} + +void CCompiledKeyValuesWriter::Describe( const KVFile_t& file ) +{ + Msg( "file( %s )\n", m_StringTable.String( file.filename ) ); + + int c = file.numElements; + for ( int i = 0; i < c; ++i ) + { + KVInfo_t &info = m_Data[ file.firstElement + i ]; + if ( info.IsSubTree() ) + { + Msg( "%d: %s -> subtree at parent %i\n", + file.firstElement + i, + m_StringTable.String( info.key ), + info.GetParent() ); + } + else + { + Msg( "%d: %s -> %s at parent %i\n", + file.firstElement + i, + m_StringTable.String( info.key ), + m_StringTable.String( info.value ), + info.GetParent() ); + } + } +} + +void CCompiledKeyValuesWriter::AppendKeyValuesFile( char const *filename ) +{ + KVFile_t kvf; + kvf.filename = m_StringTable.AddString( filename ); + kvf.firstElement = m_Data.Count(); + + KeyValues *kv = new KeyValues( filename ); + if ( kv->LoadFromFile( g_pFullFileSystem, filename ) ) + { + // Add to dictionary + // do a depth first traversal of the keyvalues + BuildKVData_R( kv, -1 ); + } + kv->deleteThis(); + + kvf.numElements = m_Data.Count() - kvf.firstElement; + +// Describe( kvf ); + + m_Files.AddToTail( kvf ); +} + +void CCompiledKeyValuesWriter::WriteData( CUtlBuffer& buf ) +{ + int c = m_Data.Count(); + buf.PutInt( c ); + for ( int i = 0; i < c; ++i ) + { + KVInfo_t &info = m_Data[ i ]; + buf.PutShort( info.key ); + buf.PutShort( info.value ); + buf.PutShort( info.GetParent() ); + buf.PutChar( info.IsSubTree() ? 1 : 0 ); + } +} + +void CCompiledKeyValuesWriter::WriteFiles( CUtlBuffer &buf ) +{ + int c = m_Files.Count(); + buf.PutInt( c ); + for ( int i = 0; i < c; ++i ) + { + KVFile_t &file = m_Files[ i ]; + buf.PutShort( file.filename ); + buf.PutShort( file.firstElement ); + buf.PutShort( file.numElements ); + } +} + +void CCompiledKeyValuesWriter::WriteStringTable( CUtlBuffer& buf ) +{ + int i; + CUtlVector< int > offsets; + + CUtlBuffer stringBuffer; + + offsets.AddToTail( stringBuffer.TellPut() ); + + stringBuffer.PutString( "" ); + // save all the rest + int c = m_StringTable.GetNumStrings(); + for ( i = 1; i < c; i++) + { + offsets.AddToTail( stringBuffer.TellPut() ); + stringBuffer.PutString( m_StringTable.String( i ) ); + } + + buf.Put( offsets.Base(), offsets.Count() * sizeof( int ) ); + + buf.PutInt( stringBuffer.TellPut() ); + buf.Put( stringBuffer.Base(), stringBuffer.TellPut() ); +} + +void CCompiledKeyValuesWriter::WriteFile( char const *outfile ) +{ + CUtlBuffer buf; + + // Write the data file out + KVHeader_t header; + header.fileid = COMPILED_KEYVALUES_ID; + header.version = COMPILED_KEYVALUES_VERSION; + header.numStrings = m_StringTable.GetNumStrings(); + + buf.Put( &header, sizeof( header ) ); + + WriteStringTable( buf ); + WriteData( buf ); + WriteFiles( buf ); + + g_pFullFileSystem->WriteFile( outfile, NULL, buf ); +} + +CCompiledKeyValuesReader::CCompiledKeyValuesReader() + : m_Dict( 0, 0, FileInfo_t::Less ) +{ +} + +int CCompiledKeyValuesReader::First() const +{ + return m_Dict.FirstInorder(); +} + +int CCompiledKeyValuesReader::Next( int i ) const +{ + return m_Dict.NextInorder( i ); +} + +int CCompiledKeyValuesReader::InvalidIndex() const +{ + return m_Dict.InvalidIndex(); +} + +void CCompiledKeyValuesReader::GetFileName( int index, char *buf, size_t bufsize ) +{ + Assert( buf ); + buf[ 0 ] = 0; + FileNameHandle_t& handle = m_Dict[ index ].hFile; + g_pFullFileSystem->String( handle, buf, bufsize ); +} + +bool CCompiledKeyValuesReader::LoadFile( char const *filename ) +{ + int i; + m_LoadBuffer.Purge(); + + g_pFullFileSystem->ReadFile( filename, NULL, m_LoadBuffer ); + + KVHeader_t header; + m_LoadBuffer.Get( &header, sizeof( header ) ); + + if ( header.fileid != COMPILED_KEYVALUES_ID ) + { + return false; + } + + if ( header.version != COMPILED_KEYVALUES_VERSION ) + { + return false; + } + + if ( !m_StringTable.ReadStringTable( header.numStrings, m_LoadBuffer ) ) + { + return false; + } + + // Now parse the data + int dataCount = m_LoadBuffer.GetInt(); + m_Data.EnsureCapacity( dataCount ); + for ( i = 0; i < dataCount; ++i ) + { + KVInfo_t info; + info.key = m_LoadBuffer.GetShort(); + info.value = m_LoadBuffer.GetShort(); + info.SetParent( m_LoadBuffer.GetShort() ); + info.SetSubTree( m_LoadBuffer.GetChar() == 1 ? true : false ); + m_Data.AddToTail( info ); + } + + int fileCount = m_LoadBuffer.GetInt(); + for ( i = 0; i < fileCount; ++i ) + { + FileInfo_t kvf; + short fileNameString = m_LoadBuffer.GetShort(); + + kvf.hFile = g_pFullFileSystem->FindOrAddFileName( m_StringTable.Lookup( fileNameString ) ); + kvf.nFirstIndex = m_LoadBuffer.GetShort(); + kvf.nCount = m_LoadBuffer.GetShort(); + + m_Dict.Insert( kvf ); + } + + return true; +} + +struct CreateHelper_t +{ + int index; + KeyValues *kv; + KeyValues *tail; + + static bool Less( const CreateHelper_t& lhs, const CreateHelper_t& rhs ) + { + return lhs.index < rhs.index; + } +}; + +KeyValues *CCompiledKeyValuesReader::CreateFromData( const FileInfo_t& info ) +{ + KeyValues *head = new KeyValues( "" ); + if ( CreateInPlaceFromData( *head, info ) ) + { + return head; + } + else + { + head->deleteThis(); + return NULL; + } +} + +bool CCompiledKeyValuesReader::CreateInPlaceFromData( KeyValues& head, const FileInfo_t& info ) +{ + int first = info.nFirstIndex; + int num = info.nCount; + + KeyValues *root = NULL; + KeyValues *tail = NULL; + + CUtlRBTree< CreateHelper_t, int > helper( 0, 0, CreateHelper_t::Less ); + + for ( int i = 0; i < num; ++i ) + { + int offset = first + i; + KVInfo_t& info = m_Data[ offset ]; + + if ( info.GetParent() != -1 ) + { + CreateHelper_t search; + search.index = info.GetParent(); + int idx = helper.Find( search ); + if ( idx == helper.InvalidIndex() ) + { + return NULL; + } + + KeyValues *parent = helper[ idx ].kv; + Assert( parent ); + + KeyValues *sub = new KeyValues( m_StringTable.Lookup( info.key ) ); + + if ( !info.IsSubTree() ) + { + sub->SetStringValue(m_StringTable.Lookup( info.value ) ); + } + + if ( !parent->GetFirstSubKey() ) + { + parent->AddSubKey( sub ); + } + else + { + KeyValues *last = helper[ idx ].tail; + last->SetNextKey( sub ); + } + + helper[ idx ].tail = sub; + + CreateHelper_t insert; + insert.index = offset; + insert.kv = sub; + insert.tail = NULL; + helper.Insert( insert ); + } + else + { + if ( !root ) + { + root = &head; + root->SetName( m_StringTable.Lookup( info.key ) ); + tail = root; + + CreateHelper_t insert; + insert.index = offset; + insert.kv = root; + insert.tail = NULL; + helper.Insert( insert ); + } + else + { + CreateHelper_t insert; + insert.index = offset; + insert.kv = new KeyValues( m_StringTable.Lookup( info.key ) ); + insert.tail = NULL; + helper.Insert( insert ); + + tail->SetNextKey( insert.kv ); + tail = insert.kv; + } + } + } + return true; +} + + +bool CCompiledKeyValuesReader::InstanceInPlace( KeyValues& head, char const *kvfilename ) +{ + char sz[ 512 ]; + Q_strncpy( sz, kvfilename, sizeof( sz ) ); + Q_FixSlashes( sz ); + + FileInfo_t search; + search.hFile = g_pFullFileSystem->FindOrAddFileName( sz ); + + int idx = m_Dict.Find( search ); + if ( idx == m_Dict.InvalidIndex() ) + { + return false; + } + + const FileInfo_t& info = m_Dict[ idx ]; + + return CreateInPlaceFromData( head, info ); +} + +KeyValues *CCompiledKeyValuesReader::Instance( char const *kvfilename ) +{ + char sz[ 512 ]; + Q_strncpy( sz, kvfilename, sizeof( sz ) ); + Q_FixSlashes( sz ); + + FileInfo_t search; + search.hFile = g_pFullFileSystem->FindOrAddFileName( sz ); + + int idx = m_Dict.Find( search ); + if ( idx == m_Dict.InvalidIndex() ) + { + return NULL; + } + + const FileInfo_t& info = m_Dict[ idx ]; + + return CreateFromData( info ); +} + +bool CCompiledKeyValuesReader::LookupKeyValuesRootKeyName( char const *kvfilename, char *outbuf, size_t bufsize ) +{ + char sz[ 512 ]; + Q_strncpy( sz, kvfilename, sizeof( sz ) ); + Q_FixSlashes( sz ); + + FileInfo_t search; + search.hFile = g_pFullFileSystem->FindOrAddFileName( sz ); + + int idx = m_Dict.Find( search ); + if ( idx == m_Dict.InvalidIndex() ) + { + return false; + } + + const FileInfo_t& info = m_Dict[ idx ]; + + Q_strncpy( outbuf, m_StringTable.Lookup( m_Data[ info.nFirstIndex ].key ), bufsize ); + return true; +} diff --git a/public/keyframe/keyframe.cpp b/public/keyframe/keyframe.cpp new file mode 100644 index 0000000..1e08b0a --- /dev/null +++ b/public/keyframe/keyframe.cpp @@ -0,0 +1,501 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include +#include +#include +#include + +typedef unsigned char byte; +#pragma warning(disable:4244) + +#include "tier0/dbg.h" +#include "mathlib/vector.h" +#include "keyframe.h" +#include "mathlib/mathlib.h" +#include "rope_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// +// Implementation of keyframe.h interface +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Key Frames +//----------------------------------------------------------------------------- +#define HIGHEST_KEYFRAME 3 +#define LOWEST_KEYFRAME -3 + +#define TOTAL_KEYFRAMES (HIGHEST_KEYFRAME - LOWEST_KEYFRAME + 1) + +// + +struct KeyFrame_t +{ + Vector vPos; + Quaternion qRot; +}; + + +KeyFrame_t g_KeyFrames[ TOTAL_KEYFRAMES ]; +KeyFrame_t *g_KeyFramePtr = &g_KeyFrames[ -LOWEST_KEYFRAME ]; // points to the middle keyframe, keyframe 0 + +bool Motion_SetKeyAngles( int keyNum, Quaternion &quatAngles ) +{ + if ( keyNum > HIGHEST_KEYFRAME || keyNum < LOWEST_KEYFRAME ) + return false; + + g_KeyFramePtr[keyNum].qRot = quatAngles; + return true; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Time Modifier function enumeration & implementation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +typedef float (*TimeModifierFunc_t)(float); + +typedef struct +{ + const char *szName; + TimeModifierFunc_t pFunc; + +} TimeModifier_t; + +float TimeModifierFunc_Linear( float time ) +{ + return time; +} + +float TimeModifierFunc_Cosine( float time ) +{ + return ( cos((time+1) * M_PI) * 0.5 ) + 0.5; +} + +float TimeModifierFunc_TimeSquared( float time ) +{ + return (time * time); +} + +TimeModifier_t g_TimeModifiers[] = +{ + { "Linear", TimeModifierFunc_Linear }, + { "Accel/Deaccel (cosine)", TimeModifierFunc_Cosine }, + { "Accel (time*time)", TimeModifierFunc_TimeSquared }, +}; + +int Motion_GetNumberOfTimeModifiers( void ) +{ + return ARRAYSIZE(g_TimeModifiers); +} + +bool Motion_GetTimeModifierDetails( int timeInterpNum, const char **outName ) +{ + if ( timeInterpNum < 0 || timeInterpNum >= Motion_GetNumberOfTimeModifiers() ) + { + return false; + } + + if ( !g_TimeModifiers[0].szName || !g_TimeModifiers[0].pFunc ) + { + return false; + } + + if ( outName ) + *outName = g_TimeModifiers[0].szName; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : time - +// timeModifierFuncNum - +// *outNewTime - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool Motion_CalculateModifiedTime( float time, int timeModifierFuncNum, float *outNewTime ) +{ + *outNewTime = g_TimeModifiers[timeModifierFuncNum].pFunc( time ); + return true; +} + + + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Position interpolator function enumeration & implementation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +// ------------------------------------------------------------------------------------ // +// Linear position interpolator. +// ------------------------------------------------------------------------------------ // + +class CPositionInterpolator_Linear : public IPositionInterpolator +{ +public: + virtual void Release(); + virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ); + virtual void SetKeyPosition( int keyNum, Vector const &vPos ); + virtual void InterpolatePosition( float time, Vector &vOut ); + virtual bool ProcessKey( char const *pName, char const *pValue ) { return false; } +}; + +CPositionInterpolator_Linear g_LinearInterpolator; + +IPositionInterpolator* GetLinearInterpolator() +{ + return &g_LinearInterpolator; +} + +void CPositionInterpolator_Linear::Release() +{ +} + +void CPositionInterpolator_Linear::GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +{ + *outName = "Linear"; + *outMinKeyReq = 0; + *outMaxKeyReq = 1; +} + +void CPositionInterpolator_Linear::SetKeyPosition( int keyNum, Vector const &vPos ) +{ + Assert ( keyNum <= HIGHEST_KEYFRAME && keyNum >= LOWEST_KEYFRAME ); + VectorCopy( vPos, g_KeyFramePtr[keyNum].vPos ); +} + +void CPositionInterpolator_Linear::InterpolatePosition( float time, Vector &vOut ) +{ + VectorLerp( g_KeyFramePtr[0].vPos, g_KeyFramePtr[1].vPos, time, vOut ); +} + + + + + +// ------------------------------------------------------------------------------------ // +// Catmull-Rom position interpolator. +// ------------------------------------------------------------------------------------ // + +class CPositionInterpolator_CatmullRom : public IPositionInterpolator +{ +public: + virtual void Release(); + virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ); + virtual void SetKeyPosition( int keyNum, Vector const &vPos ); + virtual void InterpolatePosition( float time, Vector &vOut ); + virtual bool ProcessKey( char const *pName, char const *pValue ) { return false; } +}; + +CPositionInterpolator_CatmullRom g_CatmullRomInterpolator; + +IPositionInterpolator* GetCatmullRomInterpolator() +{ + return &g_CatmullRomInterpolator; +} + +void CPositionInterpolator_CatmullRom::Release() +{ +} + +void CPositionInterpolator_CatmullRom::GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +{ + *outName = "Catmull-Rom Spline"; + *outMinKeyReq = -1; + *outMaxKeyReq = 2; +} + +void CPositionInterpolator_CatmullRom::SetKeyPosition( int keyNum, Vector const &vPos ) +{ + Assert ( keyNum <= HIGHEST_KEYFRAME && keyNum >= LOWEST_KEYFRAME ); + VectorCopy( vPos, g_KeyFramePtr[keyNum].vPos ); +} + +void CPositionInterpolator_CatmullRom::InterpolatePosition( float time, Vector &vOut ) +{ + Catmull_Rom_Spline( + g_KeyFramePtr[-1].vPos, + g_KeyFramePtr[0].vPos, + g_KeyFramePtr[1].vPos, + g_KeyFramePtr[2].vPos, + time, + vOut ); +} + + + +// ------------------------------------------------------------------------------------ // +// Rope interpolator. +// ------------------------------------------------------------------------------------ // +#include "rope_physics.h" + +class CRopeDelegate : public CSimplePhysics::IHelper +{ +public: + virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ); + virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ); + + +public: + Vector m_CurEndPoints[2]; +}; + +void CRopeDelegate::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ) +{ + // Gravity. + pAccel->Init( 0, 0, -1500 ); +} + +void CRopeDelegate::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ) +{ + if( nNodes >= 2 ) + { + pNodes[0].m_vPos = m_CurEndPoints[0]; + pNodes[nNodes-1].m_vPos = m_CurEndPoints[1]; + } +} + + +class CPositionInterpolator_Rope : public IPositionInterpolator +{ +public: + CPositionInterpolator_Rope(); + + virtual void Release(); + virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ); + virtual void SetKeyPosition( int keyNum, Vector const &vPos ); + virtual void InterpolatePosition( float time, Vector &vOut ); + virtual bool ProcessKey( char const *pName, char const *pValue ); + + +private: + CRopePhysics<10> m_RopePhysics; + CRopeDelegate m_Delegate; + + float m_flSlack; // Extra length of rope. + + bool m_bChange; + int m_nSegments; +}; + +IPositionInterpolator* GetRopeInterpolator() +{ + return new CPositionInterpolator_Rope; +} + + +CPositionInterpolator_Rope::CPositionInterpolator_Rope() +{ + m_flSlack = 0; + m_bChange = false; + m_nSegments = 5; + + for( int i=0; i < 2; i++ ) + m_Delegate.m_CurEndPoints[i] = Vector( 1e24, 1e24, 1e24 ); +} + +void CPositionInterpolator_Rope::Release() +{ + delete this; +} + +void CPositionInterpolator_Rope::GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +{ + *outName = "Rope"; + *outMinKeyReq = 0; + *outMinKeyReq = 1; +} + +void CPositionInterpolator_Rope::SetKeyPosition( int keyNum, Vector const &vPos ) +{ + if( keyNum == 0 || keyNum == 1 ) + { + if( vPos != m_Delegate.m_CurEndPoints[keyNum] ) + m_bChange = true; + + m_Delegate.m_CurEndPoints[keyNum] = vPos; + } +} + +void CPositionInterpolator_Rope::InterpolatePosition( float time, Vector &vOut ) +{ + // Check if we need to resimulate.. + if( m_bChange ) + { + m_RopePhysics.SetNumNodes( m_nSegments ); + + // Init all the nodes. + for( int i=0; i < m_RopePhysics.NumNodes(); i++ ) + m_RopePhysics.GetNode(i)->m_vPos = m_RopePhysics.GetNode(i)->m_vPrevPos = m_Delegate.m_CurEndPoints[0]; + + float flDist = (m_Delegate.m_CurEndPoints[0] - m_Delegate.m_CurEndPoints[1]).Length(); + flDist += m_flSlack; + + m_RopePhysics.Restart(); + m_RopePhysics.SetupSimulation( flDist / (m_RopePhysics.NumNodes() - 1), &m_Delegate ); + + // Run the simulation for a while to let the rope settle down.. + m_RopePhysics.Simulate( 5 ); + + m_bChange = false; + } + + // Ok, now we have all the nodes setup.. + float flNode = time * (m_RopePhysics.NumNodes()-1); + int iNode = (int)( flNode ); + VectorLerp( + m_RopePhysics.GetNode(iNode)->m_vPredicted, + m_RopePhysics.GetNode(iNode+1)->m_vPredicted, + flNode - iNode, + vOut ); +} + +bool CPositionInterpolator_Rope::ProcessKey( char const *pName, char const *pValue ) +{ + if( stricmp( pName, "Slack" ) == 0 ) + { + m_flSlack = atof( pValue ) + ROPESLACK_FUDGEFACTOR; + m_bChange = true; + return true; + } + else if( stricmp( pName, "Type" ) == 0 ) + { + int iType = atoi( pValue ); + if( iType == 0 ) + m_nSegments = ROPE_MAX_SEGMENTS; + else if( iType == 1 ) + m_nSegments = ROPE_TYPE1_NUMSEGMENTS; + else + m_nSegments = ROPE_TYPE2_NUMSEGMENTS; + + m_bChange = true; + return true; + } + + return false; +} + + + +// ------------------------------------------------------------------------------------ // +// The global table of all the position interpolators. +// ------------------------------------------------------------------------------------ // + +typedef IPositionInterpolator* (*PositionInterpolatorCreateFn)(); +PositionInterpolatorCreateFn g_PositionInterpolatorCreateFns[] = +{ + GetLinearInterpolator, + GetCatmullRomInterpolator, + GetRopeInterpolator +}; + +int Motion_GetNumberOfPositionInterpolators( void ) +{ + return ARRAYSIZE(g_PositionInterpolatorCreateFns); +} + + +IPositionInterpolator* Motion_GetPositionInterpolator( int interpNum ) +{ + Assert( interpNum >= 0 && interpNum < Motion_GetNumberOfPositionInterpolators() ); + return g_PositionInterpolatorCreateFns[clamp( interpNum, 0, Motion_GetNumberOfPositionInterpolators() - 1 )](); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Rotation interpolator function enumeration & implementation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +typedef void (*RotationInterpolatorFunc_t)(float time, Quaternion &outRot); + +typedef struct +{ + char *szName; + RotationInterpolatorFunc_t pFunc; + + // defines the range of keys this interpolator needs to function + int iMinReqKeyFrame; + int iMaxReqKeyFrame; + +} RotationInterpolator_t; + +void RotationInterpolatorFunc_Linear( float time, Quaternion &outRot ) +{ + // basic 4D spherical linear interpolation + QuaternionSlerp( g_KeyFramePtr[0].qRot, g_KeyFramePtr[1].qRot, time, outRot ); +} + +RotationInterpolator_t g_RotationInterpolators[] = +{ + { "Linear", RotationInterpolatorFunc_Linear, 0, 1 }, +}; + +int Motion_GetNumberOfRotationInterpolators( void ) +{ + return ARRAYSIZE(g_RotationInterpolators); +} + +bool Motion_GetRotationInterpolatorDetails( int rotInterpNum, char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +{ + if ( rotInterpNum < 0 || rotInterpNum >= Motion_GetNumberOfRotationInterpolators() ) + { + return false; + } + + if ( !g_RotationInterpolators[rotInterpNum].szName || !g_RotationInterpolators[rotInterpNum].pFunc ) + { + return false; + } + + if ( outName ) + *outName = g_RotationInterpolators[rotInterpNum].szName; + + if ( outMinKeyReq ) + *outMinKeyReq = g_RotationInterpolators[rotInterpNum].iMinReqKeyFrame; + + if ( outMaxKeyReq ) + *outMaxKeyReq = g_RotationInterpolators[rotInterpNum].iMaxReqKeyFrame; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Interpolates a rotation +// Time is assumed to have already been modified by the TimeModifyFunc (above) +// Requires the keyframes be already set +// Input : time - value from 0..1 +// interpFuncNum - +// *outQuatRotation - result in quaternion form +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool Motion_InterpolateRotation( float time, int interpFuncNum, Quaternion &outQuatRotation ) +{ + if ( time < 0.0f || time > 1.0f ) + return false; + + g_RotationInterpolators[interpFuncNum].pFunc( time, outQuatRotation ); + return true; +} diff --git a/public/keyframe/keyframe.h b/public/keyframe/keyframe.h new file mode 100644 index 0000000..b2cfd27 --- /dev/null +++ b/public/keyframe/keyframe.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Keyframed animation header +// shared between game and tools +//=============================================================================// + +#ifndef KEYFRAME_H +#define KEYFRAME_H +#pragma once + + +class IPositionInterpolator +{ +public: + virtual void Release() = 0; + + virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) = 0; + virtual void SetKeyPosition( int keyNum, Vector const &vPos ) = 0; + virtual void InterpolatePosition( float time, Vector &vOut ) = 0; + + // Returns true if the key causes a change that changes the interpolated positions. + virtual bool ProcessKey( char const *pName, char const *pValue ) = 0; +}; + + +// Time modifiers. +int Motion_GetNumberOfTimeModifiers( void ); +bool Motion_GetTimeModifierDetails( int timeInterpNum, const char **outName ); +bool Motion_CalculateModifiedTime( float time, int timeModifierFuncNum, float *outNewTime ); + +// Position interpolators. +int Motion_GetNumberOfPositionInterpolators( void ); +IPositionInterpolator* Motion_GetPositionInterpolator( int interpNum ); + +// Rotation interpolators. +int Motion_GetNumberOfRotationInterpolators( void ); +bool Motion_GetRotationInterpolatorDetails( int rotInterpNum, char **outName, int *outMinKeyReq, int *outMaxKeyReq ); +bool Motion_InterpolateRotation( float time, int interpFuncNum, Quaternion &outQuatRotation ); +bool Motion_SetKeyAngles( int keyNum, Quaternion &quatAngles ); + + +#endif // KEYFRAME_H diff --git a/public/keyvaluescompiler.h b/public/keyvaluescompiler.h new file mode 100644 index 0000000..ff6cc40 --- /dev/null +++ b/public/keyvaluescompiler.h @@ -0,0 +1,188 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef KEYVALUESCOMPILER_H +#define KEYVALUESCOMPILER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlsymbol.h" +#include "tier1/utldict.h" + +class KeyValues; + +#define COMPILED_KEYVALUES_ID MAKEID( 'V', 'K', 'V', 'F' ) + +#define COMPILED_KEYVALUES_VERSION 1 + +struct KVHeader_t +{ + int fileid; + int version; + int numStrings; +}; + +#pragma pack(1) +struct KVFile_t +{ + KVFile_t() : + filename( 0 ), + firstElement( 0 ), + numElements( 0 ) + { + } + short filename; + short firstElement; + short numElements; +}; + +struct KVInfo_t +{ + KVInfo_t() : + key( 0 ), + value( 0 ), + parentIndex( -1 ), + issubtree( false ) + { + } + + inline void SetParent( int index ) + { + Assert( index <= 32768 ); + parentIndex = index; + } + + inline short GetParent() const + { + return parentIndex; + } + + inline void SetSubTree( bool state ) + { + issubtree = state; + } + + inline bool IsSubTree() const + { + return issubtree; + } + + short key; + short value; + +private: + + short parentIndex; + bool issubtree; +}; +#pragma pack() + +//----------------------------------------------------------------------------- +// Purpose: stringtable is a session global string table. +//----------------------------------------------------------------------------- +class CCompiledKeyValuesWriter +{ +public: + + CCompiledKeyValuesWriter() + { + m_StringTable.AddString( "" ); + } + + void AppendKeyValuesFile( char const *filename ); + void WriteFile( char const *outfile ); + +private: + + void Describe( const KVFile_t& file ); + + void BuildKVData_R( KeyValues *kv, int parent ); + + void WriteStringTable( CUtlBuffer& buf ); + void WriteData( CUtlBuffer& buf ); + void WriteFiles( CUtlBuffer &buf ); + + CUtlVector< KVFile_t > m_Files; + CUtlVector< KVInfo_t > m_Data; + + CUtlSymbolTable m_StringTable; +}; + + +class CRunTimeKeyValuesStringTable +{ +public: + + bool ReadStringTable( int numStrings, CUtlBuffer& buf ); + + inline int Count() const + { + return m_Strings.Count(); + } + + inline char const *Lookup( short index ) + { + return m_Strings[ index ]; + } + +private: + CUtlVector< const char * > m_Strings; +}; + +class CCompiledKeyValuesReader +{ +public: + + CCompiledKeyValuesReader(); + + bool LoadFile( char const *filename ); + + KeyValues *Instance( char const *kvfilename ); + bool InstanceInPlace( KeyValues& head, char const *kvfilename ); + bool LookupKeyValuesRootKeyName( char const *kvfilename, char *outbuf, size_t bufsize ); + + int First() const; + int Next( int i ) const; + int InvalidIndex() const; + + void GetFileName( int index, char *buf, size_t bufsize ); + +private: + + struct FileInfo_t + { + FileInfo_t() : + hFile( 0 ), + nFirstIndex( 0 ), + nCount( 0 ) + { + } + FileNameHandle_t hFile; + short nFirstIndex; + short nCount; + + static bool Less( const FileInfo_t& lhs, const FileInfo_t& rhs ) + { + return lhs.hFile < rhs.hFile; + } + }; + + KeyValues *CreateFromData( const FileInfo_t& info ); + bool CreateInPlaceFromData( KeyValues& head, const FileInfo_t& info ); + + // Now get the actual files + CUtlRBTree< FileInfo_t, unsigned short > m_Dict; + CUtlVector< KVInfo_t > m_Data; + + CRunTimeKeyValuesStringTable m_StringTable; + + CUtlBuffer m_LoadBuffer; +}; + +#endif // KEYVALUESCOMPILER_H diff --git a/public/list.h b/public/list.h new file mode 100644 index 0000000..af25411 --- /dev/null +++ b/public/list.h @@ -0,0 +1,352 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef __LIST_H__ +#define __LIST_H__ + +// TODO: +// GetPositionAtIndex needs to keep a cache of the previous call so +// that it doesn't do a linear search every time. + +#include + +// FIXME: change the name of this to something more specific. +typedef struct +{ +} _Position; +typedef _Position *Position; + +template class GList; +template class GListIterator; + +// GListNode: Class decleration and definition +template class GListNode +{ +private: + T data; + GListNode *next; + GListNode *prev; + GListNode(); + GListNode( T item ); + friend class GList; + friend class GListIterator; +}; + +template +GListNode::GListNode() +{ + next = NULL; + prev = NULL; +} + +template +GListNode::GListNode( T item ) +{ + data = item; + next = NULL; + prev = NULL; +} + +// GList: Class decleration and definition +template class GList +{ +public: + // Contructors/destructors + GList(); + + // + Position InsertAtHead( T ); + Position InsertAtTail( T ); + T Remove( Position position ); + void RemoveAll( void (*DeleteItem)( T ) ); + void RemoveSelectedItems( bool (*NeedsRemovalFunc)( T ), void (*DeleteItemFunc)( T ) ); + Position InsertAfter( T item, Position position ); + Position InsertBefore( T item, Position position ); + bool IsEmpty(); + int GetNumItems(); + T GetItemAtPosition( Position position ); + Position GetPositionAtIndex( int index ); + T GetItemAtIndex( int index ); + +protected: + GListNode *head; + GListNode *tail; + int numItems; + friend class GListIterator; +}; + +template +GList::GList() +{ + // Set up a dummy head node and a dummy tail node. + head = new GListNode; + tail = new GListNode; + head->next = tail; + head->prev = head; + tail->next = tail; + tail->prev = head; + numItems = 0; +} + +template +Position GList::InsertAtHead( T item ) +{ + GListNode *newNode = new GListNode( item ); + head->next->prev = newNode; + newNode->next = head->next; + newNode->prev = head; + head->next = newNode; + numItems++; + return ( Position )( void * )newNode; +} + +template +Position GList::InsertAtTail( T item ) +{ + GListNode *newNode = new GListNode( item ); + tail->prev->next = newNode; + newNode->prev = tail->prev; + tail->prev = newNode; + newNode->next = tail; + numItems++; + return ( Position )( void * )newNode; +} + +template +T GList::Remove( Position position ) +{ + GListNode *node = ( GListNode * )( void * )position; + node->prev->next = node->next; + node->next->prev = node->prev; + T data = node->data; + numItems--; + delete node; + return data; +} + +template +void GList::RemoveAll( void (*DeleteItemFunc)( T ) ) +{ + GListNode *tmpNode; + GListNode *node = head->next; + while( node != tail ) + { + if( DeleteItemFunc ) + { + DeleteItemFunc( node->data ); + } + tmpNode = node->next; + delete node; + node = tmpNode; + } + head->next = tail; + head->prev = head; + tail->next = tail; + tail->prev = head; + numItems = 0; +} + +template +void GList::RemoveSelectedItems( bool (*NeedsRemovalFunc)( T ), void (*DeleteItemFunc)( T ) ) +{ + GListNode *tmpNode; + GListNode *node = head->next; + while( node != tail ) + { + if( NeedsRemovalFunc( node->data ) ) + { + DeleteItemFunc( node->data ); + node->prev->next = node->next; + node->next->prev = node->prev; + tmpNode = node; + node = node->next; + delete tmpNode; + numItems--; + } + else + { + node = node->next; + } + } +} + +template +Position GList::InsertAfter( T item, Position position ) +{ + GListNode *node = ( GListNode * )( void * )position; + GListNode *newNode = new GListNode( item ); + newNode->prev = node; + newNode->next = node->next; + node->next->prev = newNode; + node->next = newNode; + numItems++; + return ( Position )( void * )newNode; +} + +template +Position GList::InsertBefore( T item, Position position ) +{ + GListNode *node = ( GListNode * )( void * )position; + GListNode *newNode = new GListNode( item ); + newNode->prev = node->prev; + newNode->next = node; + node->prev->next = newNode; + node->prev = newNode; + numItems++; + return ( Position )( void * )newNode; +} + +template +bool GList::IsEmpty() +{ + return ( numItems == 0 ); +} + +template +int GList::GetNumItems() +{ + return numItems; +} + +template +T GList::GetItemAtPosition( Position position ) +{ + return ( ( GListNode * )( void * )position )->data; +} + +template +Position GList::GetPositionAtIndex( int index ) +{ + int i; + GListNode *node = head->next; + for( i = 0; i < index; i++ ) + { + node = node->next; + } + return ( Position )( void * )node; +} + +template +T GList::GetItemAtIndex( int index ) +{ + return GetItemAtPosition( GetPositionAtIndex( index ) ); +} + +// GListIterator: Class decleration and definition +template class GListIterator +{ +public: + GListIterator( GList *GList ); + void GotoHead( void ); + void GotoTail( void ); + void Goto( int index ); + void Increment(); + void Decrement(); + T GetCurrentAndIncrement(); + T GetCurrentAndDecrement(); + T IncrementAndGetCurrent(); + T DecrementAndGetCurrent(); + // postfix + T operator++( int ) { return GetCurrentAndIncrement(); } + T operator--( int ) { return GetCurrentAndDecrement(); } + // prefix + T operator++() { return IncrementAndGetCurrent(); } + T operator--() { return DecrementAndGetCurrent(); } + T GetCurrent(); + bool AtEnd( void ); + bool AtBeginning( void ); +protected: + GList *list; + GListNode *currentNode; +}; + +template +GListIterator::GListIterator( GList *list ) +{ + this->list = list; + GotoHead(); +} + +template +void GListIterator::GotoHead() +{ + this->currentNode = list->head->next; +} + +template +void GListIterator::GotoTail() +{ + this->currentNode = list->tail->prev; +} + +template +void GListIterator::Goto( int index ) +{ + currentNode = ( GListNode * )( void * )list->GetPositionAtIndex( index ); +} + +template +void GListIterator::Increment() +{ + currentNode = currentNode->next; +} + +template +void GListIterator::Decrement() +{ + currentNode = currentNode->prev; +} + +template +T GListIterator::GetCurrentAndIncrement() +{ + T retval = currentNode->data; + Increment(); + return retval; +} + +template +T GListIterator::GetCurrentAndDecrement() +{ + T retval = currentNode->data; + Decrement(); + return retval; +} + +template +T GListIterator::IncrementAndGetCurrent() +{ + Increment(); + return GetCurrent(); +} + +template +T GListIterator::DecrementAndGetCurrent() +{ + Decrement(); + return GetCurrent(); +} + +template +T GListIterator::GetCurrent() +{ + return currentNode->data; +} + +template +bool GListIterator::AtEnd( void ) +{ + return currentNode->next == currentNode; +} + +template +bool GListIterator::AtBeginning( void ) +{ + return currentNode->prev == currentNode; +} + +#endif /* __LIST_H__ */ diff --git a/public/loadcmdline.cpp b/public/loadcmdline.cpp new file mode 100644 index 0000000..30c616f --- /dev/null +++ b/public/loadcmdline.cpp @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: loads additional command line options from a config file +// +// $NoKeywords: $ +//=============================================================================// + +#include "KeyValues.h" +#include "tier1/strtools.h" +#include "FileSystem_Tools.h" +#include "tier1/utlstring.h" + +// So we know whether or not we own argv's memory +static bool sFoundConfigArgs = false; + +//----------------------------------------------------------------------------- +// Purpose: Parses arguments and adds them to argv and argc +//----------------------------------------------------------------------------- +static void AddArguments( int &argc, char **&argv, const char *str ) +{ + char **args = 0; + char *argList = 0; + int argCt = argc; + + argList = V_strdup( str ); + + // Parse the arguments out of the string + char *token = strtok( argList, " " ); + while( token ) + { + ++argCt; + token = strtok( NULL, " " ); + } + + // Make sure someting was actually found in the file + if( argCt > argc ) + { + sFoundConfigArgs = true; + + // Allocate a new array for argv + args = new char*[ argCt ]; + + // Copy original arguments, up to the last one + int i; + for( i = 0; i < argc - 1; ++i ) + { + args[ i ] = V_strdup( argv[ i ] ); + } + + // copy new arguments + Q_strcpy( argList, str ); + token = strtok( argList, " " ); + for( ; i < argCt - 1; ++i ) + { + args[ i ] = V_strdup( token ); + token = strtok( NULL, " " ); + } + + // Copy the last original argument + args[ i ] = V_strdup( argv[ argc - 1 ] ); + + argc = argCt; + argv = args; + } + + delete [] argList; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads additional commandline arguments from a config file for an app. +// Filesystem must be initialized before calling this function. +// keyname: Name of the block containing the key/args pairs (ie map or model name) +// appname: Keyname for the commandline arguments to be loaded - typically the exe name. +//----------------------------------------------------------------------------- +void LoadCmdLineFromFile( int &argc, char **&argv, const char *keyname, const char *appname ) +{ + sFoundConfigArgs = false; + + assert( g_pFileSystem ); + if( !g_pFileSystem ) + return; + + // Load the cfg file, and find the keyname + KeyValues *kv = new KeyValues( "CommandLine" ); + + char filename[512]; + Q_snprintf( filename, sizeof( filename ), "%s/cfg/commandline.cfg", gamedir ); + + if ( kv->LoadFromFile( g_pFileSystem, filename ) ) + { + // Load the commandline arguments for this app + KeyValues *appKey = kv->FindKey( keyname ); + if( appKey ) + { + const char *str = appKey->GetString( appname ); + Msg( "Command Line found: %s\n", str ); + + AddArguments( argc, argv, str ); + } + } + + kv->deleteThis(); +} + +//----------------------------------------------------------------------------- +// Purpose: Cleans up any memory allocated for the new argv. Pass in the app's +// argc and argv - this is safe even if no extra arguments were loaded. +//----------------------------------------------------------------------------- +void DeleteCmdLine( int argc, char **argv ) +{ + if( !sFoundConfigArgs ) + return; + + for( int i = 0; i < argc; ++i ) + { + delete [] argv[i]; + } + delete [] argv; +} diff --git a/public/loadcmdline.h b/public/loadcmdline.h new file mode 100644 index 0000000..084e090 --- /dev/null +++ b/public/loadcmdline.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: loads additional command line options from a config file +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef LOADCMDLINE_H +#define LOADCMDLINE_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Loads additional commandline arguments from a config file for an app. +// keyname: Name of the block containing the key/args pairs (ie map or model name) +// appname: Keyname for the commandline arguments to be loaded - typically the exe name. +//----------------------------------------------------------------------------- +void LoadCmdLineFromFile( int &argc, char **&argv, const char *keyname, const char *appname ); + +//----------------------------------------------------------------------------- +// Purpose: Cleans up any memory allocated for the new argv. Pass in the app's +// argc and argv - this is safe even if no extra arguments were loaded. +//----------------------------------------------------------------------------- +void DeleteCmdLine( int argc, char **argv ); + +#endif // LOADCMDLINE_H \ No newline at end of file diff --git a/public/localflexcontroller.h b/public/localflexcontroller.h new file mode 100644 index 0000000..7afb1c9 --- /dev/null +++ b/public/localflexcontroller.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef LOCALFLEXCONTROLLER_H +#define LOCALFLEXCONTROLLER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +enum LocalFlexController_t +{ + // this isn't really an enum - its just a typed int. gcc will not accept it as a fwd decl, so we'll define one value + DUMMY_FLEX_CONTROLLER=0x7fffffff // make take 32 bits +}; + +inline LocalFlexController_t &operator++( LocalFlexController_t &a ) { return a = LocalFlexController_t( int( a ) + 1 ); } +inline LocalFlexController_t &operator--( LocalFlexController_t &a ) { return a = LocalFlexController_t( int( a ) - 1 ); } +inline LocalFlexController_t operator++( LocalFlexController_t &a, int ) { LocalFlexController_t t = a; a = LocalFlexController_t( int( a ) + 1 ); return t; } +inline LocalFlexController_t operator--( LocalFlexController_t &a, int ) { LocalFlexController_t t = a; a = LocalFlexController_t( int( a ) - 1 ); return t; } + + +#endif // LOCALFLEXCONTROLLER_H diff --git a/public/lumpfiles.cpp b/public/lumpfiles.cpp new file mode 100644 index 0000000..eb11e78 --- /dev/null +++ b/public/lumpfiles.cpp @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "bspfile.h" +#include "strtools.h" +#include "filesystem.h" +#include "lumpfiles.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Generate a lump file name for a given bsp & index +// Input : *bspfilename - +// *lumpfilename - +// iIndex - +//----------------------------------------------------------------------------- +void GenerateLumpFileName( const char *bspfilename, char *lumpfilename, int iBufferSize, int iIndex ) +{ + char lumppre[MAX_PATH]; + V_StripExtension( bspfilename, lumppre, MAX_PATH ); + Q_snprintf( lumpfilename, iBufferSize, "%s_l_%d.lmp", lumppre, iIndex ); +} + diff --git a/public/lumpfiles.h b/public/lumpfiles.h new file mode 100644 index 0000000..a251216 --- /dev/null +++ b/public/lumpfiles.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef LUMPFILES_H +#define LUMPFILES_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAX_LUMPFILES 128 + +//----------------------------------------------------------------------------- +// Lump files +//----------------------------------------------------------------------------- +void GenerateLumpFileName( const char *bspfilename, char *lumpfilename, int iBufferSize, int iIndex ); + +#endif // LUMPFILES_H diff --git a/public/map_utils.cpp b/public/map_utils.cpp new file mode 100644 index 0000000..a0022b5 --- /dev/null +++ b/public/map_utils.cpp @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "mathlib/vector.h" +#include "bspfile.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void SetupLightNormalFromProps( const QAngle &angles, float angle, float pitch, Vector &output ) +{ + if (angle == ANGLE_UP) + { + output[0] = output[1] = 0; + output[2] = 1; + } + else if (angle == ANGLE_DOWN) + { + output[0] = output[1] = 0; + output[2] = -1; + } + else + { + // if we don't have a specific "angle" use the "angles" YAW + if ( !angle ) + { + angle = angles[YAW]; + } + + output[2] = 0; + output[0] = (float)cos (angle/180*M_PI); + output[1] = (float)sin (angle/180*M_PI); + } + + if ( !pitch ) + { + // if we don't have a specific "pitch" use the "angles" PITCH + pitch = angles[PITCH]; + } + + output[2] = (float)sin(pitch/180*M_PI); + output[0] *= (float)cos(pitch/180*M_PI); + output[1] *= (float)cos(pitch/180*M_PI); +} + diff --git a/public/map_utils.h b/public/map_utils.h new file mode 100644 index 0000000..555ca23 --- /dev/null +++ b/public/map_utils.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MAP_UTILS_H +#define MAP_UTILS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" + + +// angles comes from the "angles" property +// +// yaw and pitch will override the values in angles if they are nonzero +// yaw comes from the (obsolete) "angle" property +// pitch comes from the "pitch" property +void SetupLightNormalFromProps( const QAngle &angles, float yaw, float pitch, Vector &output ); + + +#endif // MAP_UTILS_H diff --git a/public/materialsystem/IColorCorrection.h b/public/materialsystem/IColorCorrection.h new file mode 100644 index 0000000..1aa0c24 --- /dev/null +++ b/public/materialsystem/IColorCorrection.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef ICOLORCORRECTION_H +#define ICOLORCORRECTION_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "bitmap/imageformat.h" + +typedef unsigned int ColorCorrectionHandle_t; +struct ShaderColorCorrectionInfo_t; + +#define COLORCORRECTION_INTERFACE_VERSION "COLORCORRECTION_VERSION_1" + +abstract_class IColorCorrectionSystem +{ +public: + virtual void Init() = 0; + virtual void Shutdown() = 0; + + virtual ColorCorrectionHandle_t AddLookup( const char *pName ) = 0; + virtual bool RemoveLookup( ColorCorrectionHandle_t handle ) = 0; + + virtual void SetLookupWeight( ColorCorrectionHandle_t handle, float flWeight ) = 0; + virtual float GetLookupWeight( ColorCorrectionHandle_t handle ) = 0; + virtual float GetLookupWeight( int i ) = 0; + + virtual void LockLookup() = 0; + virtual void LockLookup( ColorCorrectionHandle_t handle ) = 0; + + virtual void UnlockLookup() = 0; + virtual void UnlockLookup( ColorCorrectionHandle_t handle ) = 0; + + virtual void SetLookup( RGBX5551_t inColor, color24 outColor ) = 0; + virtual void SetLookup( ColorCorrectionHandle_t handle, RGBX5551_t inColor, color24 outColor ) = 0; + + virtual color24 GetLookup( RGBX5551_t inColor ) = 0; + virtual color24 GetLookup( ColorCorrectionHandle_t handle, RGBX5551_t inColor ) = 0; + + virtual void LoadLookup( const char *pLookupName ) = 0; + virtual void LoadLookup( ColorCorrectionHandle_t handle, const char *pLookupName ) = 0; + + virtual void CopyLookup( const color24 *pSrcColorCorrection ) = 0; + virtual void CopyLookup( ColorCorrectionHandle_t handle, const color24 *pSrcColorCorrection ) = 0; + + virtual void ResetLookup( ColorCorrectionHandle_t handle ) = 0; + virtual void ResetLookup( ) = 0; + + virtual void ReleaseTextures( ) = 0; + virtual void RestoreTextures( ) = 0; + + virtual void ResetLookupWeights( ) = 0; + + virtual int GetNumLookups( ) = 0; + + virtual color24 ConvertToColor24( RGBX5551_t inColor ) = 0; + + virtual void SetResetable( ColorCorrectionHandle_t handle, bool bResetable ) = 0; + + virtual void EnableColorCorrection( bool bEnable ) = 0; + + // FIXME: Move this to a private interface only the material system can see? + virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo ) = 0; +}; + +#endif diff --git a/public/materialsystem/IShader.h b/public/materialsystem/IShader.h new file mode 100644 index 0000000..7815e8a --- /dev/null +++ b/public/materialsystem/IShader.h @@ -0,0 +1,105 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ISHADER_H +#define ISHADER_H + +#ifdef _WIN32 +#pragma once +#endif + +//================================================================================================== +// **this goes into both platforms which run the translator, either the real Mac client or +// the Windows client running with r_emulategl mode ** +// +// size of the VS register bank in ARB / GLSL we expose +// it's not 256, because you can't use all 256 slots in 10.5.x. +// use this constant everywhere you might normally use "256" in reference to a parameter array size. +// The highest shader constant is c218, plus we allocate c219 and c220 for two clip planes +#define DXABSTRACT_VS_PARAM_SLOTS 228 +#define DXABSTRACT_VS_FIRST_BONE_SLOT VERTEX_SHADER_MODEL +#define DXABSTRACT_VS_LAST_BONE_SLOT (VERTEX_SHADER_SHADER_SPECIFIC_CONST_13-1) + +// user clip plane 0 goes in DXABSTRACT_VS_CLIP_PLANE_BASE... plane 1 goes in the slot after that +// dxabstract uses these constants to check plane index limit and to deliver planes to shader for DP4 -> oCLP[n] +#define DXABSTRACT_VS_CLIP_PLANE_BASE (DXABSTRACT_VS_PARAM_SLOTS-2) + +//================================================================================================== + + +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/ishaderapi.h" +#include "materialsystem/ishadersystem_declarations.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterialVar; +class IShaderShadow; +class IShaderDynamicAPI; +class IShaderInit; +class CBasePerMaterialContextData; + +//----------------------------------------------------------------------------- +// Information about each shader parameter +//----------------------------------------------------------------------------- +struct ShaderParamInfo_t +{ + const char *m_pName; + const char *m_pHelp; + ShaderParamType_t m_Type; + const char *m_pDefaultValue; + int m_nFlags; +}; + + + +#define VERTEX_SHADER_BONE_TRANSFORM( k ) ( VERTEX_SHADER_MODEL + 3 * (k) ) + + +// The public methods exposed by each shader +//----------------------------------------------------------------------------- +abstract_class IShader +{ +public: + // Returns the shader name + virtual char const* GetName( ) const = 0; + + // returns the shader fallbacks + virtual char const* GetFallbackShader( IMaterialVar** params ) const = 0; + + // Shader parameters + virtual int GetNumParams( ) const = 0; + + // These functions must be implemented by the shader + virtual void InitShaderParams( IMaterialVar** ppParams, const char *pMaterialName ) = 0; + virtual void InitShaderInstance( IMaterialVar** ppParams, IShaderInit *pShaderInit, const char *pMaterialName, const char *pTextureGroupName ) = 0; + virtual void DrawElements( IMaterialVar **params, int nModulationFlags, + IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, CBasePerMaterialContextData **pContextDataPtr ) = 0; + + virtual char const* GetParamName( int paramIndex ) const = 0; + virtual char const* GetParamHelp( int paramIndex ) const = 0; + virtual ShaderParamType_t GetParamType( int paramIndex ) const = 0; + virtual char const* GetParamDefault( int paramIndex ) const = 0; + + // FIXME: Figure out a better way to do this? + virtual int ComputeModulationFlags( IMaterialVar** params, IShaderDynamicAPI* pShaderAPI ) = 0; + virtual bool NeedsPowerOfTwoFrameBufferTexture( IMaterialVar **params, bool bCheckSpecificToThisFrame = true ) const = 0; + virtual bool NeedsFullFrameBufferTexture( IMaterialVar **params, bool bCheckSpecificToThisFrame ) const = 0; + virtual bool IsTranslucent( IMaterialVar **params ) const = 0; + + virtual int GetParamFlags( int paramIndex ) const = 0; + + virtual int GetFlags() const = 0; + + // FIXME: Remove GetParamName, etc. above +// virtual const ShaderParamInfo_t& GetParamInfo( int paramIndex ) const = 0; +}; + +#endif // ISHADER_H diff --git a/public/materialsystem/MaterialSystemUtil.cpp b/public/materialsystem/MaterialSystemUtil.cpp new file mode 100644 index 0000000..ba63f00 --- /dev/null +++ b/public/materialsystem/MaterialSystemUtil.cpp @@ -0,0 +1,255 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// + +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imaterialsystem.h" +#include "tier1/KeyValues.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Little utility class to deal with material references +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CMaterialReference::CMaterialReference( char const* pMaterialName, const char *pTextureGroupName, bool bComplain ) : m_pMaterial( 0 ) +{ + if ( pMaterialName ) + { + Assert( pTextureGroupName ); + Init( pMaterialName, pTextureGroupName, bComplain ); + } +} + +CMaterialReference::~CMaterialReference() +{ + Shutdown(); +} + +//----------------------------------------------------------------------------- +// Attach to a material +//----------------------------------------------------------------------------- +void CMaterialReference::Init( char const* pMaterialName, const char *pTextureGroupName, bool bComplain ) +{ + IMaterial *pMaterial = materials->FindMaterial( pMaterialName, pTextureGroupName, bComplain); + if( IsErrorMaterial( pMaterial ) ) + { + if (IsOSX()) + { + printf("\n ##### CMaterialReference::Init got error material for %s in tex group %s", pMaterialName, pTextureGroupName ); + } + } + + Assert( pMaterial ); + Init( pMaterial ); +} + +void CMaterialReference::Init( const char *pMaterialName, KeyValues *pVMTKeyValues ) +{ + // CreateMaterial has a refcount of 1 + Shutdown(); + m_pMaterial = materials->CreateMaterial( pMaterialName, pVMTKeyValues ); +} + +void CMaterialReference::Init( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues ) +{ + IMaterial *pMaterial = materials->FindProceduralMaterial( pMaterialName, pTextureGroupName, pVMTKeyValues ); + Assert( pMaterial ); + Init( pMaterial ); +} + +void CMaterialReference::Init( IMaterial* pMaterial ) +{ + if ( m_pMaterial != pMaterial ) + { + Shutdown(); + m_pMaterial = pMaterial; + if ( m_pMaterial ) + { + m_pMaterial->IncrementReferenceCount(); + } + } +} + +void CMaterialReference::Init( CMaterialReference& ref ) +{ + if ( m_pMaterial != ref.m_pMaterial ) + { + Shutdown(); + m_pMaterial = ref.m_pMaterial; + if (m_pMaterial) + { + m_pMaterial->IncrementReferenceCount(); + } + } +} + +//----------------------------------------------------------------------------- +// Detach from a material +//----------------------------------------------------------------------------- +void CMaterialReference::Shutdown( ) +{ + if ( m_pMaterial && materials ) + { + m_pMaterial->DecrementReferenceCount(); + m_pMaterial = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Little utility class to deal with texture references +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CTextureReference::CTextureReference( ) : m_pTexture(NULL) +{ +} + +CTextureReference::CTextureReference( const CTextureReference &ref ) +{ + m_pTexture = ref.m_pTexture; + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } +} + +void CTextureReference::operator=( CTextureReference &ref ) +{ + m_pTexture = ref.m_pTexture; + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } +} + +CTextureReference::~CTextureReference( ) +{ + Shutdown(); +} + +//----------------------------------------------------------------------------- +// Attach to a texture +//----------------------------------------------------------------------------- +void CTextureReference::Init( char const* pTextureName, const char *pTextureGroupName, bool bComplain ) +{ + Shutdown(); + m_pTexture = materials->FindTexture( pTextureName, pTextureGroupName, bComplain ); + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } +} + +void CTextureReference::Init( ITexture* pTexture ) +{ + Shutdown(); + + m_pTexture = pTexture; + if (m_pTexture) + { + m_pTexture->IncrementReferenceCount(); + } +} + +void CTextureReference::InitProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags ) +{ + Shutdown(); + + m_pTexture = materials->CreateProceduralTexture( pTextureName, pTextureGroupName, w, h, fmt, nFlags ); + + // NOTE: The texture reference is already incremented internally above! + /* + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } + */ +} + +void CTextureReference::InitRenderTarget( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName /* = NULL */ ) +{ + Shutdown(); + + int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT; + if ( depth == MATERIAL_RT_DEPTH_ONLY ) + textureFlags |= TEXTUREFLAGS_POINTSAMPLE; + + int renderTargetFlags = bHDR ? CREATERENDERTARGETFLAGS_HDR : 0; + + // NOTE: Refcount returned by CreateRenderTargetTexture is 1 + m_pTexture = materials->CreateNamedRenderTargetTextureEx( pStrOptionalName, w, h, sizeMode, fmt, + depth, textureFlags, renderTargetFlags ); + + Assert( m_pTexture ); +} + +//----------------------------------------------------------------------------- +// Detach from a texture +//----------------------------------------------------------------------------- +void CTextureReference::Shutdown( bool bDeleteIfUnReferenced ) +{ + if ( m_pTexture && materials ) + { + m_pTexture->DecrementReferenceCount(); + if ( bDeleteIfUnReferenced ) + { + m_pTexture->DeleteIfUnreferenced(); + } + m_pTexture = NULL; + } +} + +//----------------------------------------------------------------------------- +// Builds ONLY the system ram render target. Used when caller is explicitly managing. +// The paired EDRAM surface can be built in an alternate format. +//----------------------------------------------------------------------------- +#if defined( _X360 ) +void CTextureReference::InitRenderTargetTexture( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName ) +{ + // other variants not implemented yet + Assert( depth == MATERIAL_RT_DEPTH_NONE || depth == MATERIAL_RT_DEPTH_SHARED ); + Assert( !bHDR ); + + int renderTargetFlags = CREATERENDERTARGETFLAGS_NOEDRAM; + + m_pTexture = materials->CreateNamedRenderTargetTextureEx( + pStrOptionalName, + w, + h, + sizeMode, + fmt, + depth, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + renderTargetFlags ); + Assert( m_pTexture ); +} +#endif + +//----------------------------------------------------------------------------- +// Builds ONLY the EDRAM render target surface. Used when caller is explicitly managing. +// The paired system memory texture can be built in an alternate format. +//----------------------------------------------------------------------------- +#if defined( _X360 ) +void CTextureReference::InitRenderTargetSurface( int width, int height, ImageFormat fmt, bool bSameAsTexture ) +{ + // texture has to be created first + Assert( m_pTexture && m_pTexture->IsRenderTarget() ); + + m_pTexture->CreateRenderTargetSurface( width, height, fmt, bSameAsTexture ); +} +#endif + diff --git a/public/materialsystem/MaterialSystemUtil.h b/public/materialsystem/MaterialSystemUtil.h new file mode 100644 index 0000000..3f22e91 --- /dev/null +++ b/public/materialsystem/MaterialSystemUtil.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// +#ifndef MATERIALSYSTEMUTIL_H +#define MATERIALSYSTEMUTIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" //ImageFormat enum definition +#include "materialsystem/imaterialsystem.h" // RenderTargetSizeMode_t and MaterialRenderTargetDepth_t definition + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class ITexture; +class KeyValues; + +class KeyValues; + + +//----------------------------------------------------------------------------- +// Little utility class to deal with material references +//----------------------------------------------------------------------------- +class CMaterialReference +{ +public: + // constructor, destructor + CMaterialReference( char const* pMaterialName = 0, const char *pTextureGroupName = 0, bool bComplain = true ); + ~CMaterialReference(); + + // Attach to a material + void Init( const char* pMaterialName, const char *pTextureGroupName, bool bComplain = true ); + void Init( const char *pMaterialName, KeyValues *pVMTKeyValues ); + void Init( IMaterial* pMaterial ); + void Init( CMaterialReference& ref ); + void Init( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues ); + + // Detach from a material + void Shutdown(); + bool IsValid() { return m_pMaterial != 0; } + + // Automatic casts to IMaterial + operator IMaterial*() { return m_pMaterial; } + operator IMaterial*() const { return m_pMaterial; } + operator IMaterial const*() const { return m_pMaterial; } + IMaterial* operator->() { return m_pMaterial; } + +private: + IMaterial* m_pMaterial; +}; + +//----------------------------------------------------------------------------- +// Little utility class to deal with texture references +//----------------------------------------------------------------------------- +class CTextureReference +{ +public: + // constructor, destructor + CTextureReference( ); + CTextureReference( const CTextureReference &ref ); + ~CTextureReference(); + + // Attach to a texture + void Init( char const* pTexture, const char *pTextureGroupName, bool bComplain = true ); + void InitProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags ); + void InitRenderTarget( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName = NULL ); +#if defined( _X360 ) + // used when RT coupling is disparate (texture is DDR based, surface is EDRAM based) + void InitRenderTargetTexture( int width, int height, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName = NULL ); + void InitRenderTargetSurface( int width, int height, ImageFormat fmt, bool bSameAsTexture ); +#endif + void Init( ITexture* pTexture ); + + // Detach from a texture + void Shutdown( bool bDeleteIfUnReferenced = false ); + bool IsValid() { return m_pTexture != 0; } + + // Automatic casts to ITexture + operator ITexture*() { return m_pTexture; } + operator ITexture const*() const { return m_pTexture; } + ITexture* operator->() { return m_pTexture; } + + // Assignment operator + void operator=( CTextureReference &ref ); + +private: + ITexture* m_pTexture; +}; + + +#endif // !MATERIALSYSTEMUTIL_H diff --git a/public/materialsystem/combineoperations.h b/public/materialsystem/combineoperations.h new file mode 100644 index 0000000..195f19f --- /dev/null +++ b/public/materialsystem/combineoperations.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMBINEOPERATIONS_H +#define COMBINEOPERATIONS_H +#pragma once + +// New combines can be written in the middle (and generally should be written before Error). +// Keep these in sync with cCombineMaterialName in ctexturecompositor.cpp +enum ECombineOperation +{ + ECO_Multiply = 0, + ECO_Add, + ECO_Lerp, + + ECO_Select, + + ECO_Legacy_Lerp_FirstPass, + ECO_Legacy_Lerp_SecondPass, + + ECO_Error, + ECO_COUNT +}; + +#endif /* COMBINEOPERATIONS_H */ diff --git a/public/materialsystem/deformations.h b/public/materialsystem/deformations.h new file mode 100644 index 0000000..083ceeb --- /dev/null +++ b/public/materialsystem/deformations.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef DEFORMATIONS_H +#define DEFORMATIONS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// nonlinear transformations which may be applied to model vertices when rendering. must be powers of two +enum DeformationType_t +{ + DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE = 1, // minxyz.minsoftness / maxxyz.maxsoftness +}; + + +struct DeformationBase_t // base class. don't use this +{ + DeformationType_t m_eType; +}; + + +struct BoxDeformation_t : DeformationBase_t +{ + // don't change the layout without changing code in shaderapidx8!!!! + Vector m_SourceMins; // cube to clamp within + float m_flPad0; + Vector m_SourceMaxes; + float m_flPad1; + + Vector m_ClampMins; + float m_flPad2; + Vector m_ClampMaxes; + float m_flPad3; + + FORCEINLINE BoxDeformation_t( void ) + { + m_eType = DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE; + // invalid cube + m_SourceMins.Init( 0,0,0 ); + m_SourceMaxes.Init( -1, -1, -1 ); + + // no clamp + m_ClampMins.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX ); + m_ClampMaxes.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + } + +}; + + + +#endif diff --git a/public/materialsystem/hardwaretexels.h b/public/materialsystem/hardwaretexels.h new file mode 100644 index 0000000..0821b41 --- /dev/null +++ b/public/materialsystem/hardwaretexels.h @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Hardware Texels +// +// Contains texture data that was encoded with the map. The initial use case +// is for per-texel lightmaps to allow static props to match the lighting +// of the surrounding BSP geometry. +// +//=============================================================================// + +#ifndef HARDWARETEXELS_H +#define HARDWARETEXELS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" +#include "datamap.h" + +// valve hardware texels +#define VHT_VERSION 0 + +namespace HardwareTexels +{ +#pragma pack(1) + +// ------------------------------------------------------------------------------------------------ +struct MeshHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + + // this mesh is part of this lod + unsigned int m_nLod; + + // starting at this offset + unsigned int m_nOffset; + + // this mesh consumes this many bytes + unsigned int m_nBytes; + + // with this width and height + unsigned int m_nWidth; + unsigned int m_nHeight; + + unsigned int m_nUnused[3]; +}; + +// ------------------------------------------------------------------------------------------------ +struct FileHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + + // file version as defined by VHV_VERSION + int m_nVersion; + + // must match checkSum in the .mdl header + unsigned int m_nChecksum; + + // all texels are encoded in the same format + // This is a value from ImageFormat. + unsigned int m_nTexelFormat; + + // Number of meshes + int m_nMeshes; + + inline MeshHeader_t *pMesh( int nMesh ) const + { + Assert(nMesh < m_nMeshes); + + return (MeshHeader_t *)(((byte *)this) + sizeof(FileHeader_t)) + nMesh; + }; + + inline void *pTexelBase( int nMesh ) const + { + return (void *)((byte *)this + pMesh( nMesh )->m_nOffset); + }; + + unsigned int m_nUnused[4]; +}; + +#pragma pack() + +}; // end namespace + +#endif // HARDWARETEXELS_H + diff --git a/public/materialsystem/hardwareverts.h b/public/materialsystem/hardwareverts.h new file mode 100644 index 0000000..c7a08fe --- /dev/null +++ b/public/materialsystem/hardwareverts.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Hardware Verts +// +// Contains data purposely formatted for a dma copy into a D3D Vertex Buffer. +// The file is divided into two partitions, the foremost contains the static +// portion (header), the latter contains the streamable compliant portion. +// The streamable component starts and ends on a sector (512) aligned boundary. +// The header identifies the vertex format of the data and the atomic sizes of each component. +// The hierarchial mesh is flattened for dma but the vertex counts are available +// per mesh to transfer each mesh individually. +//=============================================================================// + +#ifndef HARDWAREVERTS_H +#define HARDWAREVERTS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "datamap.h" + +// valve hardware vertexes +#define VHV_VERSION 2 + +namespace HardwareVerts +{ + +#pragma pack(1) + +struct MeshHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + + // this mesh is part of this lod + unsigned int m_nLod; + + // this mesh has this many vertexes + unsigned int m_nVertexes; + + // starting at this offset + unsigned int m_nOffset; + + unsigned int m_nUnused[4]; +}; + +struct FileHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + + // file version as defined by VHV_VERSION + int m_nVersion; + + // must match checkSum in the .mdl header + unsigned int m_nChecksum; + + // a vertex consists of these components + uint32 m_nVertexFlags; + + // the byte size of a single vertex + // this won't be adequate, need some concept of byte format i.e. rgbexp32 vs rgba8888 + unsigned int m_nVertexSize; + + // total number of vertexes + unsigned int m_nVertexes; + + int m_nMeshes; + inline MeshHeader_t *pMesh( int nMesh ) const + { + return (MeshHeader_t *)(((byte *)this) + sizeof(FileHeader_t)) + nMesh; + }; + + inline void *pVertexBase( int nMesh ) const + { + return (void *)((byte *)this + pMesh( nMesh )->m_nOffset); + }; + + unsigned int m_nUnused[4]; +}; + +#pragma pack() + +}; // end namespace + +#endif // HARDWAREVERTS_H + diff --git a/public/materialsystem/idebugtextureinfo.h b/public/materialsystem/idebugtextureinfo.h new file mode 100644 index 0000000..426486d --- /dev/null +++ b/public/materialsystem/idebugtextureinfo.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IDEBUGTEXTUREINFO_H +#define IDEBUGTEXTUREINFO_H +#ifdef _WIN32 +#pragma once +#endif + + +class KeyValues; + + +// This interface is actually exported by the shader API DLL. +#define DEBUG_TEXTURE_INFO_VERSION "DebugTextureInfo001" + + +abstract_class IDebugTextureInfo +{ +public: + + // Use this to turn on the mode where it builds the debug texture list. + // At the end of the next frame, GetDebugTextureList() will return a valid list of the textures. + virtual void EnableDebugTextureList( bool bEnable ) = 0; + + // If this is on, then it will return all textures that exist, not just the ones that were bound in the last frame. + // It is required to enable debug texture list to get this. + virtual void EnableGetAllTextures( bool bEnable ) = 0; + + // Use this to get the results of the texture list. + // Do NOT release the KeyValues after using them. + // There will be a bunch of subkeys, each with these values: + // Name - the texture's filename + // Binds - how many times the texture was bound + // Format - ImageFormat of the texture + // Width - Width of the texture + // Height - Height of the texture + // It is required to enable debug texture list to get this. + virtual KeyValues* GetDebugTextureList() = 0; + + // Texture memory usage + enum TextureMemoryType + { + MEMORY_RESERVED_MIN = 0, + MEMORY_BOUND_LAST_FRAME, // sums up textures bound last frame + MEMORY_TOTAL_LOADED, // total texture memory used + MEMORY_ESTIMATE_PICMIP_1, // estimate of running with "picmip 1" + MEMORY_ESTIMATE_PICMIP_2, // estimate of running with "picmip 2" + MEMORY_RESERVED_MAX + }; + + // This returns how much memory was used. + virtual int GetTextureMemoryUsed( TextureMemoryType eTextureMemory ) = 0; + + // Use this to determine if texture debug info was computed within last numFramesAllowed frames. + virtual bool IsDebugTextureListFresh( int numFramesAllowed = 1 ) = 0; + + // Enable debug texture rendering when texture binds should not count towards textures + // used during a frame. Returns the old state of debug texture rendering flag to use + // it for restoring the mode. + virtual bool SetDebugTextureRendering( bool bEnable ) = 0; + +}; + + +#endif // IDEBUGTEXTUREINFO_H diff --git a/public/materialsystem/imaterial.h b/public/materialsystem/imaterial.h new file mode 100644 index 0000000..7af7aa1 --- /dev/null +++ b/public/materialsystem/imaterial.h @@ -0,0 +1,612 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IMATERIAL_H +#define IMATERIAL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" +#include "materialsystem/imaterialsystem.h" + +//----------------------------------------------------------------------------- +// forward declaraions +//----------------------------------------------------------------------------- + +class IMaterialVar; +class ITexture; +class IMaterialProxy; +class Vector; + +//----------------------------------------------------------------------------- +// Flags for GetVertexFormat +//----------------------------------------------------------------------------- +#define VERTEX_POSITION 0x0001 +#define VERTEX_NORMAL 0x0002 +#define VERTEX_COLOR 0x0004 +#define VERTEX_SPECULAR 0x0008 + +#define VERTEX_TANGENT_S 0x0010 +#define VERTEX_TANGENT_T 0x0020 +#define VERTEX_TANGENT_SPACE ( VERTEX_TANGENT_S | VERTEX_TANGENT_T ) + +// Indicates we're using wrinkle +#define VERTEX_WRINKLE 0x0040 + +// Indicates we're using bone indices +#define VERTEX_BONE_INDEX 0x0080 + +// Indicates this is a vertex shader +#define VERTEX_FORMAT_VERTEX_SHADER 0x0100 + +// Indicates this format shouldn't be bloated to cache align it +// (only used for VertexUsage) +#define VERTEX_FORMAT_USE_EXACT_FORMAT 0x0200 + +// Indicates that compressed vertex elements are to be used (see also VertexCompressionType_t) +#define VERTEX_FORMAT_COMPRESSED 0x400 + +// Update this if you add or remove bits... +#define VERTEX_LAST_BIT 10 + +#define VERTEX_BONE_WEIGHT_BIT (VERTEX_LAST_BIT + 1) +#define USER_DATA_SIZE_BIT (VERTEX_LAST_BIT + 4) +#define TEX_COORD_SIZE_BIT (VERTEX_LAST_BIT + 7) + +#define VERTEX_BONE_WEIGHT_MASK ( 0x7 << VERTEX_BONE_WEIGHT_BIT ) +#define USER_DATA_SIZE_MASK ( 0x7 << USER_DATA_SIZE_BIT ) + +#define VERTEX_FORMAT_FIELD_MASK 0x0FF + +// If everything is off, it's an unknown vertex format +#define VERTEX_FORMAT_UNKNOWN 0 + + + +//----------------------------------------------------------------------------- +// Macros for construction.. +//----------------------------------------------------------------------------- +#define VERTEX_BONEWEIGHT( _n ) ((_n) << VERTEX_BONE_WEIGHT_BIT) +#define VERTEX_USERDATA_SIZE( _n ) ((_n) << USER_DATA_SIZE_BIT) +#define VERTEX_TEXCOORD_MASK( _coord ) (( 0x7ULL ) << ( TEX_COORD_SIZE_BIT + 3 * (_coord) )) + +inline VertexFormat_t VERTEX_TEXCOORD_SIZE( int nIndex, int nNumCoords ) +{ + uint64 n64=nNumCoords; + uint64 nShift=TEX_COORD_SIZE_BIT + (3*nIndex); + return n64 << nShift; +} + + + +//----------------------------------------------------------------------------- +// Gets at various vertex format info... +//----------------------------------------------------------------------------- +inline int VertexFlags( VertexFormat_t vertexFormat ) +{ + return static_cast ( vertexFormat & ( (1 << (VERTEX_LAST_BIT+1)) - 1 ) ); +} + +inline int NumBoneWeights( VertexFormat_t vertexFormat ) +{ + return static_cast ( (vertexFormat >> VERTEX_BONE_WEIGHT_BIT) & 0x7 ); +} + +inline int UserDataSize( VertexFormat_t vertexFormat ) +{ + return static_cast ( (vertexFormat >> USER_DATA_SIZE_BIT) & 0x7 ); +} + +inline int TexCoordSize( int nTexCoordIndex, VertexFormat_t vertexFormat ) +{ + return static_cast ( (vertexFormat >> (TEX_COORD_SIZE_BIT + 3*nTexCoordIndex) ) & 0x7 ); +} + +inline bool UsesVertexShader( VertexFormat_t vertexFormat ) +{ + return (vertexFormat & VERTEX_FORMAT_VERTEX_SHADER) != 0; +} + +inline VertexCompressionType_t CompressionType( VertexFormat_t vertexFormat ) +{ + // This is trivial now, but we may add multiple flavours of compressed vertex later on + if ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) + return VERTEX_COMPRESSION_ON; + else + return VERTEX_COMPRESSION_NONE; +} + + +//----------------------------------------------------------------------------- +// VertexElement_t (enumerates all usable vertex elements) +//----------------------------------------------------------------------------- +// FIXME: unify this with VertexFormat_t (i.e. construct the lower bits of VertexFormat_t with "1 << (VertexElement_t)element") +enum VertexElement_t +{ + VERTEX_ELEMENT_NONE = -1, + + // Deliberately explicitly numbered so it's a pain in the ass to change, so you read this: + // #!#!#NOTE#!#!# update GetVertexElementSize, VertexElementToDeclType and + // CVBAllocTracker (elementTable) when you update this! + VERTEX_ELEMENT_POSITION = 0, + VERTEX_ELEMENT_NORMAL = 1, + VERTEX_ELEMENT_COLOR = 2, + VERTEX_ELEMENT_SPECULAR = 3, + VERTEX_ELEMENT_TANGENT_S = 4, + VERTEX_ELEMENT_TANGENT_T = 5, + VERTEX_ELEMENT_WRINKLE = 6, + VERTEX_ELEMENT_BONEINDEX = 7, + VERTEX_ELEMENT_BONEWEIGHTS1 = 8, + VERTEX_ELEMENT_BONEWEIGHTS2 = 9, + VERTEX_ELEMENT_BONEWEIGHTS3 = 10, + VERTEX_ELEMENT_BONEWEIGHTS4 = 11, + VERTEX_ELEMENT_USERDATA1 = 12, + VERTEX_ELEMENT_USERDATA2 = 13, + VERTEX_ELEMENT_USERDATA3 = 14, + VERTEX_ELEMENT_USERDATA4 = 15, + VERTEX_ELEMENT_TEXCOORD1D_0 = 16, + VERTEX_ELEMENT_TEXCOORD1D_1 = 17, + VERTEX_ELEMENT_TEXCOORD1D_2 = 18, + VERTEX_ELEMENT_TEXCOORD1D_3 = 19, + VERTEX_ELEMENT_TEXCOORD1D_4 = 20, + VERTEX_ELEMENT_TEXCOORD1D_5 = 21, + VERTEX_ELEMENT_TEXCOORD1D_6 = 22, + VERTEX_ELEMENT_TEXCOORD1D_7 = 23, + VERTEX_ELEMENT_TEXCOORD2D_0 = 24, + VERTEX_ELEMENT_TEXCOORD2D_1 = 25, + VERTEX_ELEMENT_TEXCOORD2D_2 = 26, + VERTEX_ELEMENT_TEXCOORD2D_3 = 27, + VERTEX_ELEMENT_TEXCOORD2D_4 = 28, + VERTEX_ELEMENT_TEXCOORD2D_5 = 29, + VERTEX_ELEMENT_TEXCOORD2D_6 = 30, + VERTEX_ELEMENT_TEXCOORD2D_7 = 31, + VERTEX_ELEMENT_TEXCOORD3D_0 = 32, + VERTEX_ELEMENT_TEXCOORD3D_1 = 33, + VERTEX_ELEMENT_TEXCOORD3D_2 = 34, + VERTEX_ELEMENT_TEXCOORD3D_3 = 35, + VERTEX_ELEMENT_TEXCOORD3D_4 = 36, + VERTEX_ELEMENT_TEXCOORD3D_5 = 37, + VERTEX_ELEMENT_TEXCOORD3D_6 = 38, + VERTEX_ELEMENT_TEXCOORD3D_7 = 39, + VERTEX_ELEMENT_TEXCOORD4D_0 = 40, + VERTEX_ELEMENT_TEXCOORD4D_1 = 41, + VERTEX_ELEMENT_TEXCOORD4D_2 = 42, + VERTEX_ELEMENT_TEXCOORD4D_3 = 43, + VERTEX_ELEMENT_TEXCOORD4D_4 = 44, + VERTEX_ELEMENT_TEXCOORD4D_5 = 45, + VERTEX_ELEMENT_TEXCOORD4D_6 = 46, + VERTEX_ELEMENT_TEXCOORD4D_7 = 47, + + VERTEX_ELEMENT_NUMELEMENTS = 48 +}; + +inline void Detect_VertexElement_t_Changes( VertexElement_t element ) // GREPs for VertexElement_t will hit this +{ + // Make it harder for someone to change VertexElement_t without noticing that dependent code + // (GetVertexElementSize, VertexElementToDeclType, CVBAllocTracker) needs updating + Assert( VERTEX_ELEMENT_NUMELEMENTS == 48 ); + switch ( element ) + { + case VERTEX_ELEMENT_POSITION: Assert( VERTEX_ELEMENT_POSITION == 0 ); break; + case VERTEX_ELEMENT_NORMAL: Assert( VERTEX_ELEMENT_NORMAL == 1 ); break; + case VERTEX_ELEMENT_COLOR: Assert( VERTEX_ELEMENT_COLOR == 2 ); break; + case VERTEX_ELEMENT_SPECULAR: Assert( VERTEX_ELEMENT_SPECULAR == 3 ); break; + case VERTEX_ELEMENT_TANGENT_S: Assert( VERTEX_ELEMENT_TANGENT_S == 4 ); break; + case VERTEX_ELEMENT_TANGENT_T: Assert( VERTEX_ELEMENT_TANGENT_T == 5 ); break; + case VERTEX_ELEMENT_WRINKLE: Assert( VERTEX_ELEMENT_WRINKLE == 6 ); break; + case VERTEX_ELEMENT_BONEINDEX: Assert( VERTEX_ELEMENT_BONEINDEX == 7 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS1: Assert( VERTEX_ELEMENT_BONEWEIGHTS1 == 8 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS2: Assert( VERTEX_ELEMENT_BONEWEIGHTS2 == 9 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS3: Assert( VERTEX_ELEMENT_BONEWEIGHTS3 == 10 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS4: Assert( VERTEX_ELEMENT_BONEWEIGHTS4 == 11 ); break; + case VERTEX_ELEMENT_USERDATA1: Assert( VERTEX_ELEMENT_USERDATA1 == 12 ); break; + case VERTEX_ELEMENT_USERDATA2: Assert( VERTEX_ELEMENT_USERDATA2 == 13 ); break; + case VERTEX_ELEMENT_USERDATA3: Assert( VERTEX_ELEMENT_USERDATA3 == 14 ); break; + case VERTEX_ELEMENT_USERDATA4: Assert( VERTEX_ELEMENT_USERDATA4 == 15 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_0: Assert( VERTEX_ELEMENT_TEXCOORD1D_0 == 16 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_1: Assert( VERTEX_ELEMENT_TEXCOORD1D_1 == 17 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_2: Assert( VERTEX_ELEMENT_TEXCOORD1D_2 == 18 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_3: Assert( VERTEX_ELEMENT_TEXCOORD1D_3 == 19 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_4: Assert( VERTEX_ELEMENT_TEXCOORD1D_4 == 20 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_5: Assert( VERTEX_ELEMENT_TEXCOORD1D_5 == 21 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_6: Assert( VERTEX_ELEMENT_TEXCOORD1D_6 == 22 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_7: Assert( VERTEX_ELEMENT_TEXCOORD1D_7 == 23 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_0: Assert( VERTEX_ELEMENT_TEXCOORD2D_0 == 24 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_1: Assert( VERTEX_ELEMENT_TEXCOORD2D_1 == 25 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_2: Assert( VERTEX_ELEMENT_TEXCOORD2D_2 == 26 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_3: Assert( VERTEX_ELEMENT_TEXCOORD2D_3 == 27 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_4: Assert( VERTEX_ELEMENT_TEXCOORD2D_4 == 28 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_5: Assert( VERTEX_ELEMENT_TEXCOORD2D_5 == 29 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_6: Assert( VERTEX_ELEMENT_TEXCOORD2D_6 == 30 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_7: Assert( VERTEX_ELEMENT_TEXCOORD2D_7 == 31 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_0: Assert( VERTEX_ELEMENT_TEXCOORD3D_0 == 32 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_1: Assert( VERTEX_ELEMENT_TEXCOORD3D_1 == 33 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_2: Assert( VERTEX_ELEMENT_TEXCOORD3D_2 == 34 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_3: Assert( VERTEX_ELEMENT_TEXCOORD3D_3 == 35 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_4: Assert( VERTEX_ELEMENT_TEXCOORD3D_4 == 36 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_5: Assert( VERTEX_ELEMENT_TEXCOORD3D_5 == 37 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_6: Assert( VERTEX_ELEMENT_TEXCOORD3D_6 == 38 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_7: Assert( VERTEX_ELEMENT_TEXCOORD3D_7 == 39 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_0: Assert( VERTEX_ELEMENT_TEXCOORD4D_0 == 40 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_1: Assert( VERTEX_ELEMENT_TEXCOORD4D_1 == 41 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_2: Assert( VERTEX_ELEMENT_TEXCOORD4D_2 == 42 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_3: Assert( VERTEX_ELEMENT_TEXCOORD4D_3 == 43 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_4: Assert( VERTEX_ELEMENT_TEXCOORD4D_4 == 44 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_5: Assert( VERTEX_ELEMENT_TEXCOORD4D_5 == 45 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_6: Assert( VERTEX_ELEMENT_TEXCOORD4D_6 == 46 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_7: Assert( VERTEX_ELEMENT_TEXCOORD4D_7 == 47 ); break; + default: + Assert( 0 ); // Invalid input or VertexElement_t has definitely changed + break; + } +} + +// We're testing 2 normal compression methods +// One compressed normals+tangents into a SHORT2 each (8 bytes total) +// The other compresses them together, into a single UBYTE4 (4 bytes total) +// FIXME: pick one or the other, compare lighting quality in important cases +#define COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 0 +#define COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 1 +//#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 +#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 + +inline int GetVertexElementSize( VertexElement_t element, VertexCompressionType_t compressionType ) +{ + Detect_VertexElement_t_Changes( element ); + + if ( compressionType == VERTEX_COMPRESSION_ON ) + { + // Compressed-vertex element sizes + switch ( element ) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + case VERTEX_ELEMENT_NORMAL: + return ( 2 * sizeof( short ) ); + case VERTEX_ELEMENT_USERDATA4: + return ( 2 * sizeof( short ) ); +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // Normals and tangents (userdata4) are combined into a single UBYTE4 vertex element + case VERTEX_ELEMENT_NORMAL: + return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_USERDATA4: + return ( 0 ); +#endif + // Compressed bone weights use a SHORT2 vertex element: + case VERTEX_ELEMENT_BONEWEIGHTS1: + case VERTEX_ELEMENT_BONEWEIGHTS2: + return ( 2 * sizeof( short ) ); + default: + break; + } + } + + // Uncompressed-vertex element sizes + switch ( element ) + { + case VERTEX_ELEMENT_POSITION: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_NORMAL: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_COLOR: return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_SPECULAR: return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_TANGENT_S: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TANGENT_T: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_WRINKLE: return ( 1 * sizeof( float ) ); // Packed into Position.W + case VERTEX_ELEMENT_BONEINDEX: return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_BONEWEIGHTS1: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_BONEWEIGHTS2: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_BONEWEIGHTS3: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_BONEWEIGHTS4: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA1: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA2: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA3: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA4: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_0: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_1: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_2: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_3: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_4: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_5: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_6: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_7: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_0: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_1: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_2: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_3: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_4: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_5: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_6: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_7: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_0: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_1: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_2: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_3: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_4: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_5: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_6: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_7: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_0: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_1: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_2: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_3: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_4: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_5: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_6: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_7: return ( 4 * sizeof( float ) ); + default: + Assert(0); + return 0; + }; +} + + +//----------------------------------------------------------------------------- +// Shader state flags can be read from the FLAGS materialvar +// Also can be read or written to with the Set/GetMaterialVarFlags() call +// Also make sure you add/remove a string associated with each flag below to CShaderSystem::ShaderStateString in ShaderSystem.cpp +//----------------------------------------------------------------------------- +enum MaterialVarFlags_t +{ + MATERIAL_VAR_DEBUG = (1 << 0), + MATERIAL_VAR_NO_DEBUG_OVERRIDE = (1 << 1), + MATERIAL_VAR_NO_DRAW = (1 << 2), + MATERIAL_VAR_USE_IN_FILLRATE_MODE = (1 << 3), + + MATERIAL_VAR_VERTEXCOLOR = (1 << 4), + MATERIAL_VAR_VERTEXALPHA = (1 << 5), + MATERIAL_VAR_SELFILLUM = (1 << 6), + MATERIAL_VAR_ADDITIVE = (1 << 7), + MATERIAL_VAR_ALPHATEST = (1 << 8), + MATERIAL_VAR_MULTIPASS = (1 << 9), + MATERIAL_VAR_ZNEARER = (1 << 10), + MATERIAL_VAR_MODEL = (1 << 11), + MATERIAL_VAR_FLAT = (1 << 12), + MATERIAL_VAR_NOCULL = (1 << 13), + MATERIAL_VAR_NOFOG = (1 << 14), + MATERIAL_VAR_IGNOREZ = (1 << 15), + MATERIAL_VAR_DECAL = (1 << 16), + MATERIAL_VAR_ENVMAPSPHERE = (1 << 17), + MATERIAL_VAR_NOALPHAMOD = (1 << 18), + MATERIAL_VAR_ENVMAPCAMERASPACE = (1 << 19), + MATERIAL_VAR_BASEALPHAENVMAPMASK = (1 << 20), + MATERIAL_VAR_TRANSLUCENT = (1 << 21), + MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK = (1 << 22), + MATERIAL_VAR_NEEDS_SOFTWARE_SKINNING = (1 << 23), + MATERIAL_VAR_OPAQUETEXTURE = (1 << 24), + MATERIAL_VAR_ENVMAPMODE = (1 << 25), + MATERIAL_VAR_SUPPRESS_DECALS = (1 << 26), + MATERIAL_VAR_HALFLAMBERT = (1 << 27), + MATERIAL_VAR_WIREFRAME = (1 << 28), + MATERIAL_VAR_ALLOWALPHATOCOVERAGE = (1 << 29), + MATERIAL_VAR_IGNORE_ALPHA_MODULATION = (1 << 30), + + // NOTE: Only add flags here that either should be read from + // .vmts or can be set directly from client code. Other, internal + // flags should to into the flag enum in imaterialinternal.h +}; + + +//----------------------------------------------------------------------------- +// Internal flags not accessible from outside the material system. Stored in Flags2 +//----------------------------------------------------------------------------- +enum MaterialVarFlags2_t +{ + // NOTE: These are for $flags2!!!!! +// UNUSED = (1 << 0), + + MATERIAL_VAR2_LIGHTING_UNLIT = 0, + MATERIAL_VAR2_LIGHTING_VERTEX_LIT = (1 << 1), + MATERIAL_VAR2_LIGHTING_LIGHTMAP = (1 << 2), + MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP = (1 << 3), + MATERIAL_VAR2_LIGHTING_MASK = + ( MATERIAL_VAR2_LIGHTING_VERTEX_LIT | + MATERIAL_VAR2_LIGHTING_LIGHTMAP | + MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP ), + + // FIXME: Should this be a part of the above lighting enums? + MATERIAL_VAR2_DIFFUSE_BUMPMAPPED_MODEL = (1 << 4), + MATERIAL_VAR2_USES_ENV_CUBEMAP = (1 << 5), + MATERIAL_VAR2_NEEDS_TANGENT_SPACES = (1 << 6), + MATERIAL_VAR2_NEEDS_SOFTWARE_LIGHTING = (1 << 7), + // GR - HDR path puts lightmap alpha in separate texture... + MATERIAL_VAR2_BLEND_WITH_LIGHTMAP_ALPHA = (1 << 8), + MATERIAL_VAR2_NEEDS_BAKED_LIGHTING_SNAPSHOTS = (1 << 9), + MATERIAL_VAR2_USE_FLASHLIGHT = (1 << 10), + MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING = (1 << 11), + MATERIAL_VAR2_NEEDS_FIXED_FUNCTION_FLASHLIGHT = (1 << 12), + MATERIAL_VAR2_USE_EDITOR = (1 << 13), + MATERIAL_VAR2_NEEDS_POWER_OF_TWO_FRAME_BUFFER_TEXTURE = (1 << 14), + MATERIAL_VAR2_NEEDS_FULL_FRAME_BUFFER_TEXTURE = (1 << 15), + MATERIAL_VAR2_IS_SPRITECARD = (1 << 16), + MATERIAL_VAR2_USES_VERTEXID = (1 << 17), + MATERIAL_VAR2_SUPPORTS_HW_SKINNING = (1 << 18), + MATERIAL_VAR2_SUPPORTS_FLASHLIGHT = (1 << 19), +}; + + +//----------------------------------------------------------------------------- +// Preview image return values +//----------------------------------------------------------------------------- +enum PreviewImageRetVal_t +{ + MATERIAL_PREVIEW_IMAGE_BAD = 0, + MATERIAL_PREVIEW_IMAGE_OK, + MATERIAL_NO_PREVIEW_IMAGE, +}; + + +//----------------------------------------------------------------------------- +// material interface +//----------------------------------------------------------------------------- +abstract_class IMaterial +{ +public: + // Get the name of the material. This is a full path to + // the vmt file starting from "hl2/materials" (or equivalent) without + // a file extension. + virtual const char * GetName() const = 0; + virtual const char * GetTextureGroupName() const = 0; + + // Get the preferred size/bitDepth of a preview image of a material. + // This is the sort of image that you would use for a thumbnail view + // of a material, or in WorldCraft until it uses materials to render. + // separate this for the tools maybe + virtual PreviewImageRetVal_t GetPreviewImageProperties( int *width, int *height, + ImageFormat *imageFormat, bool* isTranslucent ) const = 0; + + // Get a preview image at the specified width/height and bitDepth. + // Will do resampling if necessary.(not yet!!! :) ) + // Will do color format conversion. (works now.) + virtual PreviewImageRetVal_t GetPreviewImage( unsigned char *data, + int width, int height, + ImageFormat imageFormat ) const = 0; + // + virtual int GetMappingWidth( ) = 0; + virtual int GetMappingHeight( ) = 0; + + virtual int GetNumAnimationFrames( ) = 0; + + // For material subrects (material pages). Offset(u,v) and scale(u,v) are normalized to texture. + virtual bool InMaterialPage( void ) = 0; + virtual void GetMaterialOffset( float *pOffset ) = 0; + virtual void GetMaterialScale( float *pScale ) = 0; + virtual IMaterial *GetMaterialPage( void ) = 0; + + // find a vmt variable. + // This is how game code affects how a material is rendered. + // The game code must know about the params that are used by + // the shader for the material that it is trying to affect. + virtual IMaterialVar * FindVar( const char *varName, bool *found, bool complain = true ) = 0; + + // The user never allocates or deallocates materials. Reference counting is + // used instead. Garbage collection is done upon a call to + // IMaterialSystem::UncacheUnusedMaterials. + virtual void IncrementReferenceCount( void ) = 0; + virtual void DecrementReferenceCount( void ) = 0; + + inline void AddRef() { IncrementReferenceCount(); } + inline void Release() { DecrementReferenceCount(); } + + // Each material is assigned a number that groups it with like materials + // for sorting in the application. + virtual int GetEnumerationID( void ) const = 0; + + virtual void GetLowResColorSample( float s, float t, float *color ) const = 0; + + // This computes the state snapshots for this material + virtual void RecomputeStateSnapshots() = 0; + + // Are we translucent? + virtual bool IsTranslucent() = 0; + + // Are we alphatested? + virtual bool IsAlphaTested() = 0; + + // Are we vertex lit? + virtual bool IsVertexLit() = 0; + + // Gets the vertex format + virtual VertexFormat_t GetVertexFormat() const = 0; + + // returns true if this material uses a material proxy + virtual bool HasProxy( void ) const = 0; + + virtual bool UsesEnvCubemap( void ) = 0; + + virtual bool NeedsTangentSpace( void ) = 0; + + virtual bool NeedsPowerOfTwoFrameBufferTexture( bool bCheckSpecificToThisFrame = true ) = 0; + virtual bool NeedsFullFrameBufferTexture( bool bCheckSpecificToThisFrame = true ) = 0; + + // returns true if the shader doesn't do skinning itself and requires + // the data that is sent to it to be preskinned. + virtual bool NeedsSoftwareSkinning( void ) = 0; + + // Apply constant color or alpha modulation + virtual void AlphaModulate( float alpha ) = 0; + virtual void ColorModulate( float r, float g, float b ) = 0; + + // Material Var flags... + virtual void SetMaterialVarFlag( MaterialVarFlags_t flag, bool on ) = 0; + virtual bool GetMaterialVarFlag( MaterialVarFlags_t flag ) const = 0; + + // Gets material reflectivity + virtual void GetReflectivity( Vector& reflect ) = 0; + + // Gets material property flags + virtual bool GetPropertyFlag( MaterialPropertyTypes_t type ) = 0; + + // Is the material visible from both sides? + virtual bool IsTwoSided() = 0; + + // Sets the shader associated with the material + virtual void SetShader( const char *pShaderName ) = 0; + + // Can't be const because the material might have to precache itself. + virtual int GetNumPasses( void ) = 0; + + // Can't be const because the material might have to precache itself. + virtual int GetTextureMemoryBytes( void ) = 0; + + // Meant to be used with materials created using CreateMaterial + // It updates the materials to reflect the current values stored in the material vars + virtual void Refresh() = 0; + + // GR - returns true is material uses lightmap alpha for blending + virtual bool NeedsLightmapBlendAlpha( void ) = 0; + + // returns true if the shader doesn't do lighting itself and requires + // the data that is sent to it to be prelighted + virtual bool NeedsSoftwareLighting( void ) = 0; + + // Gets at the shader parameters + virtual int ShaderParamCount() const = 0; + virtual IMaterialVar **GetShaderParams( void ) = 0; + + // Returns true if this is the error material you get back from IMaterialSystem::FindMaterial if + // the material can't be found. + virtual bool IsErrorMaterial() const = 0; + + virtual void SetUseFixedFunctionBakedLighting( bool bEnable ) = 0; + + // Gets the current alpha modulation + virtual float GetAlphaModulation() = 0; + virtual void GetColorModulation( float *r, float *g, float *b ) = 0; + + // Gets the morph format + virtual MorphFormat_t GetMorphFormat() const = 0; + + // fast find that stores the index of the found var in the string table in local cache + virtual IMaterialVar * FindVarFast( char const *pVarName, unsigned int *pToken ) = 0; + + // Sets new VMT shader parameters for the material + virtual void SetShaderAndParams( KeyValues *pKeyValues ) = 0; + virtual const char * GetShaderName() const = 0; + + virtual void DeleteIfUnreferenced() = 0; + + virtual bool IsSpriteCard() = 0; + + virtual void CallBindProxy( void *proxyData ) = 0; + + virtual IMaterial *CheckProxyReplacement( void *proxyData ) = 0; + + virtual void RefreshPreservingMaterialVars() = 0; + + virtual bool WasReloadedFromWhitelist() = 0; + + virtual bool IsPrecached() const = 0; +}; + + +inline bool IsErrorMaterial( IMaterial *pMat ) +{ + return !pMat || pMat->IsErrorMaterial(); +} + +#endif // IMATERIAL_H diff --git a/public/materialsystem/imaterialproxy.h b/public/materialsystem/imaterialproxy.h new file mode 100644 index 0000000..52c49be --- /dev/null +++ b/public/materialsystem/imaterialproxy.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMATERIALPROXY_H +#define IMATERIALPROXY_H +#pragma once + +#include "interface.h" + +#define IMATERIAL_PROXY_INTERFACE_VERSION "_IMaterialProxy003" + +class IMaterial; +class KeyValues; + +abstract_class IMaterialProxy +{ +public: + virtual bool Init( IMaterial* pMaterial, KeyValues *pKeyValues ) = 0; + virtual void OnBind( void * ) = 0; + virtual void Release() = 0; + virtual IMaterial * GetMaterial() = 0; + +protected: + // no one should call this directly + virtual ~IMaterialProxy() {} +}; + +#endif // IMATERIALPROXY_H diff --git a/public/materialsystem/imaterialproxyfactory.h b/public/materialsystem/imaterialproxyfactory.h new file mode 100644 index 0000000..4045cb0 --- /dev/null +++ b/public/materialsystem/imaterialproxyfactory.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMATERIALPROXYFACTORY_H +#define IMATERIALPROXYFACTORY_H +#pragma once + +#include "interface.h" + +#define IMATERIAL_PROXY_FACTOR_INTERFACE_VERSION "IMaterialProxyFactory001" + +class IMaterialProxy; + +abstract_class IMaterialProxyFactory +{ +public: + virtual IMaterialProxy *CreateProxy( const char *proxyName ) = 0; + virtual void DeleteProxy( IMaterialProxy *pProxy ) = 0; +}; + +#endif // IMATERIALPROXYFACTORY_H diff --git a/public/materialsystem/imaterialsystem.h b/public/materialsystem/imaterialsystem.h new file mode 100644 index 0000000..edf1502 --- /dev/null +++ b/public/materialsystem/imaterialsystem.h @@ -0,0 +1,1813 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IMATERIALSYSTEM_H +#define IMATERIALSYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#define OVERBRIGHT 2.0f +#define OO_OVERBRIGHT ( 1.0f / 2.0f ) +#define GAMMA 2.2f +#define TEXGAMMA 2.2f + +#include "tier1/interface.h" +#include "tier1/refcount.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "mathlib/vmatrix.h" +#include "appframework/IAppSystem.h" +#include "bitmap/imageformat.h" +#include "texture_group_names.h" +#include "vtf/vtf.h" +#include "materialsystem/deformations.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/IColorCorrection.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class IMesh; +class IVertexBuffer; +class IIndexBuffer; +struct MaterialSystem_Config_t; +class VMatrix; +struct matrix3x4_t; +class ITexture; +class ITextureCompositor; +struct MaterialSystemHardwareIdentifier_t; +class KeyValues; +class IShader; +class IVertexTexture; +class IMorph; +class IMatRenderContext; +class ICallQueue; +struct MorphWeight_t; +class IFileList; + + +//----------------------------------------------------------------------------- +// The vertex format type +//----------------------------------------------------------------------------- +typedef uint64 VertexFormat_t; + +//----------------------------------------------------------------------------- +// important enumeration +//----------------------------------------------------------------------------- + +// NOTE NOTE NOTE!!!! If you up this, grep for "NEW_INTERFACE" to see if there is anything +// waiting to be enabled during an interface revision. +#define MATERIAL_SYSTEM_INTERFACE_VERSION "VMaterialSystem080" + +#ifdef POSIX +#define ABSOLUTE_MINIMUM_DXLEVEL 90 +#else +#define ABSOLUTE_MINIMUM_DXLEVEL 80 +#endif + +enum ShaderParamType_t +{ + SHADER_PARAM_TYPE_TEXTURE, + SHADER_PARAM_TYPE_INTEGER, + SHADER_PARAM_TYPE_COLOR, + SHADER_PARAM_TYPE_VEC2, + SHADER_PARAM_TYPE_VEC3, + SHADER_PARAM_TYPE_VEC4, + SHADER_PARAM_TYPE_ENVMAP, // obsolete + SHADER_PARAM_TYPE_FLOAT, + SHADER_PARAM_TYPE_BOOL, + SHADER_PARAM_TYPE_FOURCC, + SHADER_PARAM_TYPE_MATRIX, + SHADER_PARAM_TYPE_MATERIAL, + SHADER_PARAM_TYPE_STRING, + SHADER_PARAM_TYPE_MATRIX4X2 +}; + +enum MaterialMatrixMode_t +{ + MATERIAL_VIEW = 0, + MATERIAL_PROJECTION, + + // Texture matrices + MATERIAL_TEXTURE0, + MATERIAL_TEXTURE1, + MATERIAL_TEXTURE2, + MATERIAL_TEXTURE3, + MATERIAL_TEXTURE4, + MATERIAL_TEXTURE5, + MATERIAL_TEXTURE6, + MATERIAL_TEXTURE7, + + MATERIAL_MODEL, + + // Total number of matrices + NUM_MATRIX_MODES = MATERIAL_MODEL+1, + + // Number of texture transforms + NUM_TEXTURE_TRANSFORMS = MATERIAL_TEXTURE7 - MATERIAL_TEXTURE0 + 1 +}; + +// FIXME: How do I specify the actual number of matrix modes? +const int NUM_MODEL_TRANSFORMS = 53; +const int MATERIAL_MODEL_MAX = MATERIAL_MODEL + NUM_MODEL_TRANSFORMS; + +enum MaterialPrimitiveType_t +{ + MATERIAL_POINTS = 0x0, + MATERIAL_LINES, + MATERIAL_TRIANGLES, + MATERIAL_TRIANGLE_STRIP, + MATERIAL_LINE_STRIP, + MATERIAL_LINE_LOOP, // a single line loop + MATERIAL_POLYGON, // this is a *single* polygon + MATERIAL_QUADS, + MATERIAL_INSTANCED_QUADS, // (X360) like MATERIAL_QUADS, but uses vertex instancing + + // This is used for static meshes that contain multiple types of + // primitive types. When calling draw, you'll need to specify + // a primitive type. + MATERIAL_HETEROGENOUS +}; + +enum MaterialPropertyTypes_t +{ + MATERIAL_PROPERTY_NEEDS_LIGHTMAP = 0, // bool + MATERIAL_PROPERTY_OPACITY, // int (enum MaterialPropertyOpacityTypes_t) + MATERIAL_PROPERTY_REFLECTIVITY, // vec3_t + MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS // bool +}; + +// acceptable property values for MATERIAL_PROPERTY_OPACITY +enum MaterialPropertyOpacityTypes_t +{ + MATERIAL_ALPHATEST = 0, + MATERIAL_OPAQUE, + MATERIAL_TRANSLUCENT +}; + +enum MaterialBufferTypes_t +{ + MATERIAL_FRONT = 0, + MATERIAL_BACK +}; + +enum MaterialCullMode_t +{ + MATERIAL_CULLMODE_CCW, // this culls polygons with counterclockwise winding + MATERIAL_CULLMODE_CW // this culls polygons with clockwise winding +}; + +enum MaterialIndexFormat_t +{ + MATERIAL_INDEX_FORMAT_UNKNOWN = -1, + MATERIAL_INDEX_FORMAT_16BIT = 0, + MATERIAL_INDEX_FORMAT_32BIT, +}; + +enum MaterialFogMode_t +{ + MATERIAL_FOG_NONE, + MATERIAL_FOG_LINEAR, + MATERIAL_FOG_LINEAR_BELOW_FOG_Z, +}; + +enum MaterialHeightClipMode_t +{ + MATERIAL_HEIGHTCLIPMODE_DISABLE, + MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT, + MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT +}; + +enum MaterialNonInteractiveMode_t +{ + MATERIAL_NON_INTERACTIVE_MODE_NONE = -1, + MATERIAL_NON_INTERACTIVE_MODE_STARTUP = 0, + MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD, + + MATERIAL_NON_INTERACTIVE_MODE_COUNT, +}; + + +//----------------------------------------------------------------------------- +// Special morph used in decalling pass +//----------------------------------------------------------------------------- +#define MATERIAL_MORPH_DECAL ( (IMorph*)1 ) + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +enum MaterialThreadMode_t +{ + MATERIAL_SINGLE_THREADED, + MATERIAL_QUEUED_SINGLE_THREADED, + MATERIAL_QUEUED_THREADED +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +enum MaterialContextType_t +{ + MATERIAL_HARDWARE_CONTEXT, + MATERIAL_QUEUED_CONTEXT, + MATERIAL_NULL_CONTEXT +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +enum MaterialFindContext_t +{ + MATERIAL_FINDCONTEXT_NONE, + MATERIAL_FINDCONTEXT_ISONAMODEL, +}; + +//----------------------------------------------------------------------------- +// Light structure +//----------------------------------------------------------------------------- +#include "mathlib/lightdesc.h" + +#if 0 +enum LightType_t +{ + MATERIAL_LIGHT_DISABLE = 0, + MATERIAL_LIGHT_POINT, + MATERIAL_LIGHT_DIRECTIONAL, + MATERIAL_LIGHT_SPOT, +}; + +enum LightType_OptimizationFlags_t +{ + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 = 1, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 = 2, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 = 4, +}; + + +struct LightDesc_t +{ + LightType_t m_Type; + Vector m_Color; + Vector m_Position; + Vector m_Direction; + float m_Range; + float m_Falloff; + float m_Attenuation0; + float m_Attenuation1; + float m_Attenuation2; + float m_Theta; + float m_Phi; + // These aren't used by DX8. . used for software lighting. + float m_ThetaDot; + float m_PhiDot; + unsigned int m_Flags; + + + LightDesc_t() {} + +private: + // No copy constructors allowed + LightDesc_t(const LightDesc_t& vOther); +}; +#endif + +#define CREATERENDERTARGETFLAGS_HDR 0x00000001 +#define CREATERENDERTARGETFLAGS_AUTOMIPMAP 0x00000002 +#define CREATERENDERTARGETFLAGS_UNFILTERABLE_OK 0x00000004 +// XBOX ONLY: +#define CREATERENDERTARGETFLAGS_NOEDRAM 0x00000008 // inhibit allocation in 360 EDRAM +#define CREATERENDERTARGETFLAGS_TEMP 0x00000010 // only allocates memory upon first resolve, destroyed at level end + +//----------------------------------------------------------------------------- +// allowed stencil operations. These match the d3d operations +//----------------------------------------------------------------------------- +enum StencilOperation_t +{ +#if !defined( _X360 ) + STENCILOPERATION_KEEP = 1, + STENCILOPERATION_ZERO = 2, + STENCILOPERATION_REPLACE = 3, + STENCILOPERATION_INCRSAT = 4, + STENCILOPERATION_DECRSAT = 5, + STENCILOPERATION_INVERT = 6, + STENCILOPERATION_INCR = 7, + STENCILOPERATION_DECR = 8, +#else + STENCILOPERATION_KEEP = D3DSTENCILOP_KEEP, + STENCILOPERATION_ZERO = D3DSTENCILOP_ZERO, + STENCILOPERATION_REPLACE = D3DSTENCILOP_REPLACE, + STENCILOPERATION_INCRSAT = D3DSTENCILOP_INCRSAT, + STENCILOPERATION_DECRSAT = D3DSTENCILOP_DECRSAT, + STENCILOPERATION_INVERT = D3DSTENCILOP_INVERT, + STENCILOPERATION_INCR = D3DSTENCILOP_INCR, + STENCILOPERATION_DECR = D3DSTENCILOP_DECR, +#endif + STENCILOPERATION_FORCE_DWORD = 0x7fffffff +}; + +enum StencilComparisonFunction_t +{ +#if !defined( _X360 ) + STENCILCOMPARISONFUNCTION_NEVER = 1, + STENCILCOMPARISONFUNCTION_LESS = 2, + STENCILCOMPARISONFUNCTION_EQUAL = 3, + STENCILCOMPARISONFUNCTION_LESSEQUAL = 4, + STENCILCOMPARISONFUNCTION_GREATER = 5, + STENCILCOMPARISONFUNCTION_NOTEQUAL = 6, + STENCILCOMPARISONFUNCTION_GREATEREQUAL = 7, + STENCILCOMPARISONFUNCTION_ALWAYS = 8, +#else + STENCILCOMPARISONFUNCTION_NEVER = D3DCMP_NEVER, + STENCILCOMPARISONFUNCTION_LESS = D3DCMP_LESS, + STENCILCOMPARISONFUNCTION_EQUAL = D3DCMP_EQUAL, + STENCILCOMPARISONFUNCTION_LESSEQUAL = D3DCMP_LESSEQUAL, + STENCILCOMPARISONFUNCTION_GREATER = D3DCMP_GREATER, + STENCILCOMPARISONFUNCTION_NOTEQUAL = D3DCMP_NOTEQUAL, + STENCILCOMPARISONFUNCTION_GREATEREQUAL = D3DCMP_GREATEREQUAL, + STENCILCOMPARISONFUNCTION_ALWAYS = D3DCMP_ALWAYS, +#endif + + STENCILCOMPARISONFUNCTION_FORCE_DWORD = 0x7fffffff +}; + + +//----------------------------------------------------------------------------- +// Enumeration for the various fields capable of being morphed +//----------------------------------------------------------------------------- +enum MorphFormatFlags_t +{ + MORPH_POSITION = 0x0001, // 3D + MORPH_NORMAL = 0x0002, // 3D + MORPH_WRINKLE = 0x0004, // 1D + MORPH_SPEED = 0x0008, // 1D + MORPH_SIDE = 0x0010, // 1D +}; + + +//----------------------------------------------------------------------------- +// The morph format type +//----------------------------------------------------------------------------- +typedef unsigned int MorphFormat_t; + + +//----------------------------------------------------------------------------- +// Standard lightmaps +//----------------------------------------------------------------------------- +enum StandardLightmap_t +{ + MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE = -1, + MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP = -2, + MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED = -3 +}; + + +struct MaterialSystem_SortInfo_t +{ + IMaterial *material; + int lightmapPageID; +}; + + +#define MAX_FB_TEXTURES 4 + +//----------------------------------------------------------------------------- +// Information about each adapter +//----------------------------------------------------------------------------- +enum +{ + MATERIAL_ADAPTER_NAME_LENGTH = 512 +}; + +struct MaterialAdapterInfo_t +{ + char m_pDriverName[MATERIAL_ADAPTER_NAME_LENGTH]; + unsigned int m_VendorID; + unsigned int m_DeviceID; + unsigned int m_SubSysID; + unsigned int m_Revision; + int m_nDXSupportLevel; // This is the *preferred* dx support level + int m_nMaxDXSupportLevel; + unsigned int m_nDriverVersionHigh; + unsigned int m_nDriverVersionLow; +}; + + +//----------------------------------------------------------------------------- +// Video mode info.. +//----------------------------------------------------------------------------- +struct MaterialVideoMode_t +{ + int m_Width; // if width and height are 0 and you select + int m_Height; // windowed mode, it'll use the window size + ImageFormat m_Format; // use ImageFormats (ignored for windowed mode) + int m_RefreshRate; // 0 == default (ignored for windowed mode) +}; + +// fixme: should move this into something else. +struct FlashlightState_t +{ + FlashlightState_t() + { + m_bEnableShadows = false; // Provide reasonable defaults for shadow depth mapping parameters + m_bDrawShadowFrustum = false; + m_flShadowMapResolution = 1024.0f; + m_flShadowFilterSize = 3.0f; + m_flShadowSlopeScaleDepthBias = 16.0f; + m_flShadowDepthBias = 0.0005f; + m_flShadowJitterSeed = 0.0f; + m_flShadowAtten = 0.0f; + m_bScissor = false; + m_nLeft = -1; + m_nTop = -1; + m_nRight = -1; + m_nBottom = -1; + m_nShadowQuality = 0; + } + + Vector m_vecLightOrigin; + Quaternion m_quatOrientation; + float m_NearZ; + float m_FarZ; + float m_fHorizontalFOVDegrees; + float m_fVerticalFOVDegrees; + float m_fQuadraticAtten; + float m_fLinearAtten; + float m_fConstantAtten; + float m_Color[4]; + ITexture *m_pSpotlightTexture; + int m_nSpotlightTextureFrame; + + // Shadow depth mapping parameters + bool m_bEnableShadows; + bool m_bDrawShadowFrustum; + float m_flShadowMapResolution; + float m_flShadowFilterSize; + float m_flShadowSlopeScaleDepthBias; + float m_flShadowDepthBias; + float m_flShadowJitterSeed; + float m_flShadowAtten; + int m_nShadowQuality; + + // Getters for scissor members + bool DoScissor() { return m_bScissor; } + int GetLeft() { return m_nLeft; } + int GetTop() { return m_nTop; } + int GetRight() { return m_nRight; } + int GetBottom() { return m_nBottom; } + +private: + + friend class CShadowMgr; + + bool m_bScissor; + int m_nLeft; + int m_nTop; + int m_nRight; + int m_nBottom; +}; + +// Passed as the callback object to Async functions in the material system +// so that callers don't have to worry about memory going out of scope before the +// results return. +abstract_class IAsyncTextureOperationReceiver : public IRefCounted +{ +public: + virtual void OnAsyncCreateComplete( ITexture* pTex, void* pExtraArgs ) = 0; + virtual void OnAsyncFindComplete( ITexture* pTex, void* pExtraArgs ) = 0; + virtual void OnAsyncMapComplete( ITexture* pTex, void* pExtraArgs, void* pMemory, int nPitch ) = 0; + virtual void OnAsyncReadbackBegin( ITexture* pDst, ITexture* pSrc, void* pExtraArgs ) = 0; + + virtual int GetRefCount() const = 0; +}; + + +//----------------------------------------------------------------------------- +// Flags to be used with the Init call +//----------------------------------------------------------------------------- +enum MaterialInitFlags_t +{ + MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE = 0x2, + MATERIAL_INIT_REFERENCE_RASTERIZER = 0x4, +}; + +//----------------------------------------------------------------------------- +// Flags to specify type of depth buffer used with RT +//----------------------------------------------------------------------------- + +// GR - this is to add RT with no depth buffer bound + +enum MaterialRenderTargetDepth_t +{ + MATERIAL_RT_DEPTH_SHARED = 0x0, + MATERIAL_RT_DEPTH_SEPARATE = 0x1, + MATERIAL_RT_DEPTH_NONE = 0x2, + MATERIAL_RT_DEPTH_ONLY = 0x3, +}; + +//----------------------------------------------------------------------------- +// A function to be called when we need to release all vertex buffers +// NOTE: The restore function will tell the caller if all the vertex formats +// changed so that it can flush caches, etc. if it needs to (for dxlevel support) +//----------------------------------------------------------------------------- +enum RestoreChangeFlags_t +{ + MATERIAL_RESTORE_VERTEX_FORMAT_CHANGED = 0x1, +}; + + +// NOTE: All size modes will force the render target to be smaller than or equal to +// the size of the framebuffer. +enum RenderTargetSizeMode_t +{ + RT_SIZE_NO_CHANGE=0, // Only allowed for render targets that don't want a depth buffer + // (because if they have a depth buffer, the render target must be less than or equal to the size of the framebuffer). + RT_SIZE_DEFAULT=1, // Don't play with the specified width and height other than making sure it fits in the framebuffer. + RT_SIZE_PICMIP=2, // Apply picmip to the render target's width and height. + RT_SIZE_HDR=3, // frame_buffer_width / 4 + RT_SIZE_FULL_FRAME_BUFFER=4, // Same size as frame buffer, or next lower power of 2 if we can't do that. + RT_SIZE_OFFSCREEN=5, // Target of specified size, don't mess with dimensions + RT_SIZE_FULL_FRAME_BUFFER_ROUNDED_UP=6, // Same size as the frame buffer, rounded up if necessary for systems that can't do non-power of two textures. + RT_SIZE_REPLAY_SCREENSHOT = 7, // Rounded down to power of 2, essentially... + RT_SIZE_LITERAL = 8, // Use the size passed in. Don't clamp it to the frame buffer size. Really. + RT_SIZE_LITERAL_PICMIP = 9 // Use the size passed in, don't clamp to the frame buffer size, but do apply picmip restrictions. + +}; + +typedef void (*MaterialBufferReleaseFunc_t)( ); +typedef void (*MaterialBufferRestoreFunc_t)( int nChangeFlags ); // see RestoreChangeFlags_t +typedef void (*ModeChangeCallbackFunc_t)( void ); + +typedef int VertexBufferHandle_t; +typedef unsigned short MaterialHandle_t; + +DECLARE_POINTER_HANDLE( OcclusionQueryObjectHandle_t ); +#define INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ( (OcclusionQueryObjectHandle_t)0 ) + +class IMaterialProxyFactory; +class ITexture; +class IMaterialSystemHardwareConfig; +class CShadowMgr; + +DECLARE_POINTER_HANDLE( MaterialLock_t ); + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +abstract_class IMaterialSystem : public IAppSystem +{ +public: + + // Placeholder for API revision + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + //--------------------------------------------------------- + // Initialization and shutdown + //--------------------------------------------------------- + + // Call this to initialize the material system + // returns a method to create interfaces in the shader dll + virtual CreateInterfaceFn Init( char const* pShaderAPIDLL, + IMaterialProxyFactory *pMaterialProxyFactory, + CreateInterfaceFn fileSystemFactory, + CreateInterfaceFn cvarFactory=NULL ) = 0; + + // Call this to set an explicit shader version to use + // Must be called before Init(). + virtual void SetShaderAPI( char const *pShaderAPIDLL ) = 0; + + // Must be called before Init(), if you're going to call it at all... + virtual void SetAdapter( int nAdapter, int nFlags ) = 0; + + // Call this when the mod has been set up, which may occur after init + // At this point, the game + gamebin paths have been set up + virtual void ModInit() = 0; + virtual void ModShutdown() = 0; + + //--------------------------------------------------------- + // + //--------------------------------------------------------- + virtual void SetThreadMode( MaterialThreadMode_t mode, int nServiceThread = -1 ) = 0; + virtual MaterialThreadMode_t GetThreadMode( ) = 0; + virtual bool IsRenderThreadSafe( ) = 0; + virtual void ExecuteQueued() = 0; + + //--------------------------------------------------------- + // Config management + //--------------------------------------------------------- + + virtual IMaterialSystemHardwareConfig *GetHardwareConfig( const char *pVersion, int *returnCode ) = 0; + + + // Call this before rendering each frame with the current config + // for the material system. + // Will do whatever is necessary to get the material system into the correct state + // upon configuration change. .doesn't much else otherwise. + virtual bool UpdateConfig( bool bForceUpdate ) = 0; + + // Force this to be the config; update all material system convars to match the state + // return true if lightmaps need to be redownloaded + virtual bool OverrideConfig( const MaterialSystem_Config_t &config, bool bForceUpdate ) = 0; + + // Get the current config for this video card (as last set by UpdateConfig) + virtual const MaterialSystem_Config_t &GetCurrentConfigForVideoCard() const = 0; + + // Gets *recommended* configuration information associated with the display card, + // given a particular dx level to run under. + // Use dxlevel 0 to use the recommended dx level. + // The function returns false if an invalid dxlevel was specified + + // UNDONE: To find out all convars affected by configuration, we'll need to change + // the dxsupport.pl program to output all column headers into a single keyvalue block + // and then we would read that in, and send it back to the client + virtual bool GetRecommendedConfigurationInfo( int nDXLevel, KeyValues * pKeyValues ) = 0; + + + // ----------------------------------------------------------- + // Device methods + // ----------------------------------------------------------- + + // Gets the number of adapters... + virtual int GetDisplayAdapterCount() const = 0; + + // Returns the current adapter in use + virtual int GetCurrentAdapter() const = 0; + + // Returns info about each adapter + virtual void GetDisplayAdapterInfo( int adapter, MaterialAdapterInfo_t& info ) const = 0; + + // Returns the number of modes + virtual int GetModeCount( int adapter ) const = 0; + + // Returns mode information.. + virtual void GetModeInfo( int adapter, int mode, MaterialVideoMode_t& info ) const = 0; + + virtual void AddModeChangeCallBack( ModeChangeCallbackFunc_t func ) = 0; + + // Returns the mode info for the current display device + virtual void GetDisplayMode( MaterialVideoMode_t& mode ) const = 0; + + // Sets the mode... + virtual bool SetMode( void* hwnd, const MaterialSystem_Config_t &config ) = 0; + + virtual bool SupportsMSAAMode( int nMSAAMode ) = 0; + + // FIXME: REMOVE! Get video card identitier + virtual const MaterialSystemHardwareIdentifier_t &GetVideoCardIdentifier( void ) const = 0; + + // Use this to spew information about the 3D layer + virtual void SpewDriverInfo() const = 0; + + virtual void GetDXLevelDefaults(uint &max_dxlevel,uint &recommended_dxlevel) = 0; + + // Get the image format of the back buffer. . useful when creating render targets, etc. + virtual void GetBackBufferDimensions( int &width, int &height) const = 0; + virtual ImageFormat GetBackBufferFormat() const = 0; + + virtual bool SupportsHDRMode( HDRType_t nHDRModede ) = 0; + + + // ----------------------------------------------------------- + // Window methods + // ----------------------------------------------------------- + + // Creates/ destroys a child window + virtual bool AddView( void* hwnd ) = 0; + virtual void RemoveView( void* hwnd ) = 0; + + // Sets the view + virtual void SetView( void* hwnd ) = 0; + + + // ----------------------------------------------------------- + // Control flow + // ----------------------------------------------------------- + + virtual void BeginFrame( float frameTime ) = 0; + virtual void EndFrame( ) = 0; + virtual void Flush( bool flushHardware = false ) = 0; + + /// FIXME: This stuff needs to be cleaned up and abstracted. + // Stuff that gets exported to the launcher through the engine + virtual void SwapBuffers( ) = 0; + + // Flushes managed textures from the texture cacher + virtual void EvictManagedResources() = 0; + + virtual void ReleaseResources(void) = 0; + virtual void ReacquireResources(void ) = 0; + + + // ----------------------------------------------------------- + // Device loss/restore + // ----------------------------------------------------------- + + // Installs a function to be called when we need to release vertex buffers + textures + virtual void AddReleaseFunc( MaterialBufferReleaseFunc_t func ) = 0; + virtual void RemoveReleaseFunc( MaterialBufferReleaseFunc_t func ) = 0; + + // Installs a function to be called when we need to restore vertex buffers + virtual void AddRestoreFunc( MaterialBufferRestoreFunc_t func ) = 0; + virtual void RemoveRestoreFunc( MaterialBufferRestoreFunc_t func ) = 0; + + // Release temporary HW memory... + virtual void ResetTempHWMemory( bool bExitingLevel = false ) = 0; + + // For dealing with device lost in cases where SwapBuffers isn't called all the time (Hammer) + virtual void HandleDeviceLost() = 0; + + + // ----------------------------------------------------------- + // Shaders + // ----------------------------------------------------------- + + // Used to iterate over all shaders for editing purposes + // GetShaders returns the number of shaders it actually found + virtual int ShaderCount() const = 0; + virtual int GetShaders( int nFirstShader, int nMaxCount, IShader **ppShaderList ) const = 0; + + // FIXME: Is there a better way of doing this? + // Returns shader flag names for editors to be able to edit them + virtual int ShaderFlagCount() const = 0; + virtual const char * ShaderFlagName( int nIndex ) const = 0; + + // Gets the actual shader fallback for a particular shader + virtual void GetShaderFallback( const char *pShaderName, char *pFallbackShader, int nFallbackLength ) = 0; + + + // ----------------------------------------------------------- + // Material proxies + // ----------------------------------------------------------- + + virtual IMaterialProxyFactory *GetMaterialProxyFactory() = 0; + + // Sets the material proxy factory. Calling this causes all materials to be uncached. + virtual void SetMaterialProxyFactory( IMaterialProxyFactory* pFactory ) = 0; + + + // ----------------------------------------------------------- + // Editor mode + // ----------------------------------------------------------- + + // Used to enable editor materials. Must be called before Init. + virtual void EnableEditorMaterials() = 0; + + + // ----------------------------------------------------------- + // Stub mode mode + // ----------------------------------------------------------- + + // Force it to ignore Draw calls. + virtual void SetInStubMode( bool bInStubMode ) = 0; + + + //--------------------------------------------------------- + // Debug support + //--------------------------------------------------------- + + virtual void DebugPrintUsedMaterials( const char *pSearchSubString, bool bVerbose ) = 0; + virtual void DebugPrintUsedTextures( void ) = 0; + + virtual void ToggleSuppressMaterial( char const* pMaterialName ) = 0; + virtual void ToggleDebugMaterial( char const* pMaterialName ) = 0; + + + //--------------------------------------------------------- + // Misc features + //--------------------------------------------------------- + //returns whether fast clipping is being used or not - needed to be exposed for better per-object clip behavior + virtual bool UsingFastClipping( void ) = 0; + + virtual int StencilBufferBits( void ) = 0; //number of bits per pixel in the stencil buffer + + + //--------------------------------------------------------- + // Material and texture management + //--------------------------------------------------------- + + // uncache all materials. . good for forcing reload of materials. + virtual void UncacheAllMaterials( ) = 0; + + // Remove any materials from memory that aren't in use as determined + // by the IMaterial's reference count. + virtual void UncacheUnusedMaterials( bool bRecomputeStateSnapshots = false ) = 0; + + // Load any materials into memory that are to be used as determined + // by the IMaterial's reference count. + virtual void CacheUsedMaterials( ) = 0; + + // Force all textures to be reloaded from disk. + virtual void ReloadTextures( ) = 0; + + // Reloads materials + virtual void ReloadMaterials( const char *pSubString = NULL ) = 0; + + // Create a procedural material. The keyvalues looks like a VMT file + virtual IMaterial * CreateMaterial( const char *pMaterialName, KeyValues *pVMTKeyValues ) = 0; + + // Find a material by name. + // The name of a material is a full path to + // the vmt file starting from "hl2/materials" (or equivalent) without + // a file extension. + // eg. "dev/dev_bumptest" refers to somethign similar to: + // "d:/hl2/hl2/materials/dev/dev_bumptest.vmt" + // + // Most of the texture groups for pTextureGroupName are listed in texture_group_names.h. + // + // Note: if the material can't be found, this returns a checkerboard material. You can + // find out if you have that material by calling IMaterial::IsErrorMaterial(). + // (Or use the global IsErrorMaterial function, which checks if it's null too). + virtual IMaterial * FindMaterial( char const* pMaterialName, const char *pTextureGroupName, bool complain = true, const char *pComplainPrefix = NULL ) = 0; + + // Query whether a material is loaded (eg, whether FindMaterial will be nonblocking) + virtual bool IsMaterialLoaded( char const* pMaterialName ) = 0; + + //--------------------------------- + // This is the interface for knowing what materials are available + // is to use the following functions to get a list of materials. The + // material names will have the full path to the material, and that is the + // only way that the directory structure of the materials will be seen through this + // interface. + // NOTE: This is mostly for worldcraft to get a list of materials to put + // in the "texture" browser.in Worldcraft + virtual MaterialHandle_t FirstMaterial() const = 0; + + // returns InvalidMaterial if there isn't another material. + // WARNING: you must call GetNextMaterial until it returns NULL, + // otherwise there will be a memory leak. + virtual MaterialHandle_t NextMaterial( MaterialHandle_t h ) const = 0; + + // This is the invalid material + virtual MaterialHandle_t InvalidMaterial() const = 0; + + // Returns a particular material + virtual IMaterial* GetMaterial( MaterialHandle_t h ) const = 0; + + // Get the total number of materials in the system. These aren't just the used + // materials, but the complete collection. + virtual int GetNumMaterials( ) const = 0; + + //--------------------------------- + + virtual void SetAsyncTextureLoadCache( void* hFileCache ) = 0; + + virtual ITexture * FindTexture( char const* pTextureName, const char *pTextureGroupName, bool complain = true, int nAdditionalCreationFlags = 0 ) = 0; + + // Checks to see if a particular texture is loaded + virtual bool IsTextureLoaded( char const* pTextureName ) const = 0; + + // Creates a procedural texture + virtual ITexture * CreateProceduralTexture( const char *pTextureName, + const char *pTextureGroupName, + int w, + int h, + ImageFormat fmt, + int nFlags ) = 0; + + // + // Render targets + // + virtual void BeginRenderTargetAllocation() = 0; + virtual void EndRenderTargetAllocation() = 0; // Simulate an Alt-Tab in here, which causes a release/restore of all resources + + // Creates a render target + // If depth == true, a depth buffer is also allocated. If not, then + // the screen's depth buffer is used. + // Creates a texture for use as a render target + virtual ITexture * CreateRenderTargetTexture( int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED ) = 0; + + virtual ITexture * CreateNamedRenderTargetTextureEx( const char *pRTName, // Pass in NULL here for an unnamed render target. + int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, + unsigned int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + unsigned int renderTargetFlags = 0 ) = 0; + + virtual ITexture * CreateNamedRenderTargetTexture( const char *pRTName, + int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, + bool bClampTexCoords = true, + bool bAutoMipMap = false ) = 0; + + // Must be called between the above Begin-End calls! + virtual ITexture * CreateNamedRenderTargetTextureEx2( const char *pRTName, // Pass in NULL here for an unnamed render target. + int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, + unsigned int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + unsigned int renderTargetFlags = 0 ) = 0; + + // ----------------------------------------------------------- + // Lightmaps + // ----------------------------------------------------------- + + // To allocate lightmaps, sort the whole world by material twice. + // The first time through, call AllocateLightmap for every surface. + // that has a lightmap. + // The second time through, call AllocateWhiteLightmap for every + // surface that expects to use shaders that expect lightmaps. + virtual void BeginLightmapAllocation( ) = 0; + virtual void EndLightmapAllocation( ) = 0; + + // returns the sorting id for this surface + virtual int AllocateLightmap( int width, int height, + int offsetIntoLightmapPage[2], + IMaterial *pMaterial ) = 0; + // returns the sorting id for this surface + virtual int AllocateWhiteLightmap( IMaterial *pMaterial ) = 0; + + // lightmaps are in linear color space + // lightmapPageID is returned by GetLightmapPageIDForSortID + // lightmapSize and offsetIntoLightmapPage are returned by AllocateLightmap. + // You should never call UpdateLightmap for a lightmap allocated through + // AllocateWhiteLightmap. + virtual void UpdateLightmap( int lightmapPageID, int lightmapSize[2], + int offsetIntoLightmapPage[2], + float *pFloatImage, float *pFloatImageBump1, + float *pFloatImageBump2, float *pFloatImageBump3 ) = 0; + + // fixme: could just be an array of ints for lightmapPageIDs since the material + // for a surface is already known. + virtual int GetNumSortIDs( ) = 0; + virtual void GetSortInfo( MaterialSystem_SortInfo_t *sortInfoArray ) = 0; + + // Read the page size of an existing lightmap by sort id (returned from AllocateLightmap()) + virtual void GetLightmapPageSize( int lightmap, int *width, int *height ) const = 0; + + virtual void ResetMaterialLightmapPageInfo() = 0; + + + + virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil = false ) = 0; + + // ----------------------------------------------------------- + // X360 specifics + // ----------------------------------------------------------- + +#if defined( _X360 ) + virtual void ListUsedMaterials( void ) = 0; + virtual HXUIFONT OpenTrueTypeFont( const char *pFontname, int tall, int style ) = 0; + virtual void CloseTrueTypeFont( HXUIFONT hFont ) = 0; + virtual bool GetTrueTypeFontMetrics( HXUIFONT hFont, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] ) = 0; + // Render a sequence of characters and extract the data into a buffer + // For each character, provide the width+height of the font texture subrect, + // an offset to apply when rendering the glyph, and an offset into a buffer to receive the RGBA data + virtual bool GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset ) = 0; + virtual void PersistDisplay() = 0; + virtual void *GetD3DDevice() = 0; + virtual bool OwnGPUResources( bool bEnable ) = 0; +#endif + + // ----------------------------------------------------------- + // Access the render contexts + // ----------------------------------------------------------- + virtual IMatRenderContext * GetRenderContext() = 0; + + virtual bool SupportsShadowDepthTextures( void ) = 0; + virtual void BeginUpdateLightmaps( void ) = 0; + virtual void EndUpdateLightmaps( void ) = 0; + + // ----------------------------------------------------------- + // Methods to force the material system into non-threaded, non-queued mode + // ----------------------------------------------------------- + virtual MaterialLock_t Lock() = 0; + virtual void Unlock( MaterialLock_t ) = 0; + + // Vendor-dependent shadow depth texture format + virtual ImageFormat GetShadowDepthTextureFormat() = 0; + + virtual bool SupportsFetch4( void ) = 0; + + // Create a custom render context. Cannot be used to create MATERIAL_HARDWARE_CONTEXT + virtual IMatRenderContext *CreateRenderContext( MaterialContextType_t type ) = 0; + + // Set a specified render context to be the global context for the thread. Returns the prior context. + virtual IMatRenderContext *SetRenderContext( IMatRenderContext * ) = 0; + + virtual bool SupportsCSAAMode( int nNumSamples, int nQualityLevel ) = 0; + + virtual void RemoveModeChangeCallBack( ModeChangeCallbackFunc_t func ) = 0; + + // Finds or create a procedural material. + virtual IMaterial * FindProceduralMaterial( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues ) = 0; + + virtual ImageFormat GetNullTextureFormat() = 0; + + virtual void AddTextureAlias( const char *pAlias, const char *pRealName ) = 0; + virtual void RemoveTextureAlias( const char *pAlias ) = 0; + + // returns a lightmap page ID for this allocation, -1 if none available + // frameID is a number that should be changed every frame to prevent locking any textures that are + // being used to draw in the previous frame + virtual int AllocateDynamicLightmap( int lightmapSize[2], int *pOutOffsetIntoPage, int frameID ) = 0; + + virtual void SetExcludedTextures( const char *pScriptName ) = 0; + virtual void UpdateExcludedTextures( void ) = 0; + + virtual bool IsInFrame( ) const = 0; + + virtual void CompactMemory() = 0; + + // For sv_pure mode. The filesystem figures out which files the client needs to reload to be "pure" ala the server's preferences. + virtual void ReloadFilesInList( IFileList *pFilesToReload ) = 0; + virtual bool AllowThreading( bool bAllow, int nServiceThread ) = 0; + + // Extended version of FindMaterial(). + // Contains context in so it can make decisions (i.e. if it's a model, ignore certain cheat parameters) + virtual IMaterial * FindMaterialEx( char const* pMaterialName, const char *pTextureGroupName, int nContext, bool complain = true, const char *pComplainPrefix = NULL ) = 0; + +#ifdef DX_TO_GL_ABSTRACTION + virtual void DoStartupShaderPreloading( void ) = 0; +#endif + + // Sets the override sizes for all render target size tests. These replace the frame buffer size. + // Set them when you are rendering primarily to something larger than the frame buffer (as in VR mode). + virtual void SetRenderTargetFrameBufferSizeOverrides( int nWidth, int nHeight ) = 0; + + // Returns the (possibly overridden) framebuffer size for render target sizing. + virtual void GetRenderTargetFrameBufferDimensions( int & nWidth, int & nHeight ) = 0; + + // returns the display device name that matches the adapter index we were started with + virtual char *GetDisplayDeviceName() const = 0; + + // creates a texture suitable for use with materials from a raw stream of bits. + // The bits will be retained by the material system and can be freed upon return. + virtual ITexture* CreateTextureFromBits(int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits) = 0; + + // Lie to the material system to pretend to be in render target allocation mode at the beginning of time. + // This was a thing that mattered a lot to old hardware, but doesn't matter at all to new hardware, + // where new is defined to be "anything from the last decade." However, we want to preserve legacy behavior + // for the old games because it's easier than testing them. + virtual void OverrideRenderTargetAllocation( bool rtAlloc ) = 0; + + // creates a texture compositor that will attempt to composite a new textuer from the steps of the specified KeyValues. + virtual ITextureCompositor* NewTextureCompositor( int w, int h, const char* pCompositeName, int nTeamNum, uint64 randomSeed, KeyValues* stageDesc, uint32 texCompositeCreateFlags = 0 ) = 0; + + // Loads the texture with the specified name, calls pRecipient->OnAsyncFindComplete with the result from the main thread. + // once the texture load is complete. If the texture cannot be found, the returned texture will return true for IsError(). + virtual void AsyncFindTexture( const char* pFilename, const char *pTextureGroupName, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs, bool bComplain = true, int nAdditionalCreationFlags = 0 ) = 0; + + // creates a texture suitable for use with materials from a raw stream of bits. + // The bits will be retained by the material system and can be freed upon return. + virtual ITexture* CreateNamedTextureFromBitsEx( const char* pName, const char *pTextureGroupName, int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits, int nFlags ) = 0; +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +abstract_class IMatRenderContext +{ +public: + virtual void BeginRender() = 0; + virtual void EndRender() = 0; + + virtual void Flush( bool flushHardware = false ) = 0; + + virtual void BindLocalCubemap( ITexture *pTexture ) = 0; + + // pass in an ITexture (that is build with "rendertarget" "1") or + // pass in NULL for the regular backbuffer. + virtual void SetRenderTarget( ITexture *pTexture ) = 0; + virtual ITexture * GetRenderTarget( void ) = 0; + + virtual void GetRenderTargetDimensions( int &width, int &height) const = 0; + + // Bind a material is current for rendering. + virtual void Bind( IMaterial *material, void *proxyData = 0 ) = 0; + // Bind a lightmap page current for rendering. You only have to + // do this for materials that require lightmaps. + virtual void BindLightmapPage( int lightmapPageID ) = 0; + + // inputs are between 0 and 1 + virtual void DepthRange( float zNear, float zFar ) = 0; + + virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil = false ) = 0; + + // read to a unsigned char rgb image. + virtual void ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat ) = 0; + + // Sets lighting + virtual void SetAmbientLight( float r, float g, float b ) = 0; + virtual void SetLight( int lightNum, const LightDesc_t& desc ) = 0; + + // The faces of the cube are specified in the same order as cubemap textures + virtual void SetAmbientLightCube( Vector4D cube[6] ) = 0; + + // Blit the backbuffer to the framebuffer texture + virtual void CopyRenderTargetToTexture( ITexture *pTexture ) = 0; + + // Set the current texture that is a copy of the framebuffer. + virtual void SetFrameBufferCopyTexture( ITexture *pTexture, int textureIndex = 0 ) = 0; + virtual ITexture *GetFrameBufferCopyTexture( int textureIndex ) = 0; + + // + // end vertex array api + // + + // matrix api + virtual void MatrixMode( MaterialMatrixMode_t matrixMode ) = 0; + virtual void PushMatrix( void ) = 0; + virtual void PopMatrix( void ) = 0; + virtual void LoadMatrix( VMatrix const& matrix ) = 0; + virtual void LoadMatrix( matrix3x4_t const& matrix ) = 0; + virtual void MultMatrix( VMatrix const& matrix ) = 0; + virtual void MultMatrix( matrix3x4_t const& matrix ) = 0; + virtual void MultMatrixLocal( VMatrix const& matrix ) = 0; + virtual void MultMatrixLocal( matrix3x4_t const& matrix ) = 0; + virtual void GetMatrix( MaterialMatrixMode_t matrixMode, VMatrix *matrix ) = 0; + virtual void GetMatrix( MaterialMatrixMode_t matrixMode, matrix3x4_t *matrix ) = 0; + virtual void LoadIdentity( void ) = 0; + virtual void Ortho( double left, double top, double right, double bottom, double zNear, double zFar ) = 0; + virtual void PerspectiveX( double fovx, double aspect, double zNear, double zFar ) = 0; + virtual void PickMatrix( int x, int y, int width, int height ) = 0; + virtual void Rotate( float angle, float x, float y, float z ) = 0; + virtual void Translate( float x, float y, float z ) = 0; + virtual void Scale( float x, float y, float z ) = 0; + // end matrix api + + // Sets/gets the viewport + virtual void Viewport( int x, int y, int width, int height ) = 0; + virtual void GetViewport( int& x, int& y, int& width, int& height ) const = 0; + + // The cull mode + virtual void CullMode( MaterialCullMode_t cullMode ) = 0; + + // end matrix api + + // This could easily be extended to a general user clip plane + virtual void SetHeightClipMode( MaterialHeightClipMode_t nHeightClipMode ) = 0; + // garymcthack : fog z is always used for heightclipz for now. + virtual void SetHeightClipZ( float z ) = 0; + + // Fog methods... + virtual void FogMode( MaterialFogMode_t fogMode ) = 0; + virtual void FogStart( float fStart ) = 0; + virtual void FogEnd( float fEnd ) = 0; + virtual void SetFogZ( float fogZ ) = 0; + virtual MaterialFogMode_t GetFogMode( void ) = 0; + + virtual void FogColor3f( float r, float g, float b ) = 0; + virtual void FogColor3fv( float const* rgb ) = 0; + virtual void FogColor3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void FogColor3ubv( unsigned char const* rgb ) = 0; + + virtual void GetFogColor( unsigned char *rgb ) = 0; + + // Sets the number of bones for skinning + virtual void SetNumBoneWeights( int numBones ) = 0; + + // Creates/destroys Mesh + virtual IMesh* CreateStaticMesh( VertexFormat_t fmt, const char *pTextureBudgetGroup, IMaterial * pMaterial = NULL ) = 0; + virtual void DestroyStaticMesh( IMesh* mesh ) = 0; + + // Gets the dynamic mesh associated with the currently bound material + // note that you've got to render the mesh before calling this function + // a second time. Clients should *not* call DestroyStaticMesh on the mesh + // returned by this call. + // Use buffered = false if you want to not have the mesh be buffered, + // but use it instead in the following pattern: + // meshBuilder.Begin + // meshBuilder.End + // Draw partial + // Draw partial + // Draw partial + // meshBuilder.Begin + // meshBuilder.End + // etc + // Use Vertex or Index Override to supply a static vertex or index buffer + // to use in place of the dynamic buffers. + // + // If you pass in a material in pAutoBind, it will automatically bind the + // material. This can be helpful since you must bind the material you're + // going to use BEFORE calling GetDynamicMesh. + virtual IMesh* GetDynamicMesh( + bool buffered = true, + IMesh* pVertexOverride = 0, + IMesh* pIndexOverride = 0, + IMaterial *pAutoBind = 0 ) = 0; + + // ------------ New Vertex/Index Buffer interface ---------------------------- + // Do we need support for bForceTempMesh and bSoftwareVertexShader? + // I don't think we use bSoftwareVertexShader anymore. .need to look into bForceTempMesh. + virtual IVertexBuffer *CreateStaticVertexBuffer( VertexFormat_t fmt, int nVertexCount, const char *pTextureBudgetGroup ) = 0; + virtual IIndexBuffer *CreateStaticIndexBuffer( MaterialIndexFormat_t fmt, int nIndexCount, const char *pTextureBudgetGroup ) = 0; + virtual void DestroyVertexBuffer( IVertexBuffer * ) = 0; + virtual void DestroyIndexBuffer( IIndexBuffer * ) = 0; + // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams? + virtual IVertexBuffer *GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered = true ) = 0; + virtual IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true ) = 0; + virtual void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 ) = 0; + virtual void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes ) = 0; + virtual void Draw( MaterialPrimitiveType_t primitiveType, int firstIndex, int numIndices ) = 0; + // ------------ End ---------------------------- + + // Selection mode methods + virtual int SelectionMode( bool selectionMode ) = 0; + virtual void SelectionBuffer( unsigned int* pBuffer, int size ) = 0; + virtual void ClearSelectionNames( ) = 0; + virtual void LoadSelectionName( int name ) = 0; + virtual void PushSelectionName( int name ) = 0; + virtual void PopSelectionName() = 0; + + // Sets the Clear Color for ClearBuffer.... + virtual void ClearColor3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) = 0; + + // Allows us to override the depth buffer setting of a material + virtual void OverrideDepthEnable( bool bEnable, bool bDepthEnable ) = 0; + + // FIXME: This is a hack required for NVidia/XBox, can they fix in drivers? + virtual void DrawScreenSpaceQuad( IMaterial* pMaterial ) = 0; + + // For debugging and building recording files. This will stuff a token into the recording file, + // then someone doing a playback can watch for the token. + virtual void SyncToken( const char *pToken ) = 0; + + // FIXME: REMOVE THIS FUNCTION! + // The only reason why it's not gone is because we're a week from ship when I found the bug in it + // and everything's tuned to use it. + // It's returning values which are 2x too big (it's returning sphere diameter x2) + // Use ComputePixelDiameterOfSphere below in all new code instead. + virtual float ComputePixelWidthOfSphere( const Vector& origin, float flRadius ) = 0; + + // + // Occlusion query support + // + + // Allocate and delete query objects. + virtual OcclusionQueryObjectHandle_t CreateOcclusionQueryObject( void ) = 0; + virtual void DestroyOcclusionQueryObject( OcclusionQueryObjectHandle_t ) = 0; + + // Bracket drawing with begin and end so that we can get counts next frame. + virtual void BeginOcclusionQueryDrawing( OcclusionQueryObjectHandle_t ) = 0; + virtual void EndOcclusionQueryDrawing( OcclusionQueryObjectHandle_t ) = 0; + + // Get the number of pixels rendered between begin and end on an earlier frame. + // Calling this in the same frame is a huge perf hit! + virtual int OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjectHandle_t ) = 0; + + virtual void SetFlashlightMode( bool bEnable ) = 0; + + virtual void SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture ) = 0; + + // Gets the current height clip mode + virtual MaterialHeightClipMode_t GetHeightClipMode( ) = 0; + + // This returns the diameter of the sphere in pixels based on + // the current model, view, + projection matrices and viewport. + virtual float ComputePixelDiameterOfSphere( const Vector& vecAbsOrigin, float flRadius ) = 0; + + // By default, the material system applies the VIEW and PROJECTION matrices to the user clip + // planes (which are specified in world space) to generate projection-space user clip planes + // Occasionally (for the particle system in hl2, for example), we want to override that + // behavior and explictly specify a ViewProj transform for user clip planes + virtual void EnableUserClipTransformOverride( bool bEnable ) = 0; + virtual void UserClipTransform( const VMatrix &worldToView ) = 0; + + virtual bool GetFlashlightMode() const = 0; + + // Used to make the handle think it's never had a successful query before + virtual void ResetOcclusionQueryObject( OcclusionQueryObjectHandle_t ) = 0; + + // FIXME: Remove + virtual void Unused3() {} + + // Creates/destroys morph data associated w/ a particular material + virtual IMorph *CreateMorph( MorphFormat_t format, const char *pDebugName ) = 0; + virtual void DestroyMorph( IMorph *pMorph ) = 0; + + // Binds the morph data for use in rendering + virtual void BindMorph( IMorph *pMorph ) = 0; + + // Sets flexweights for rendering + virtual void SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights ) = 0; + + // FIXME: Remove + virtual void Unused4() {}; + virtual void Unused5() {}; + virtual void Unused6() {}; + virtual void Unused7() {}; + virtual void Unused8() {}; + + // Read w/ stretch to a host-memory buffer + virtual void ReadPixelsAndStretch( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pBuffer, ImageFormat dstFormat, int nDstStride ) = 0; + + // Gets the window size + virtual void GetWindowSize( int &width, int &height ) const = 0; + + // This function performs a texture map from one texture map to the render destination, doing + // all the necessary pixel/texel coordinate fix ups. fractional values can be used for the + // src_texture coordinates to get linear sampling - integer values should produce 1:1 mappings + // for non-scaled operations. + virtual void DrawScreenSpaceRectangle( + IMaterial *pMaterial, + int destx, int desty, + int width, int height, + float src_texture_x0, float src_texture_y0, // which texel you want to appear at + // destx/y + float src_texture_x1, float src_texture_y1, // which texel you want to appear at + // destx+width-1, desty+height-1 + int src_texture_width, int src_texture_height, // needed for fixup + void *pClientRenderable = NULL, + int nXDice = 1, + int nYDice = 1 )=0; + + virtual void LoadBoneMatrix( int boneIndex, const matrix3x4_t& matrix ) = 0; + + // This version will push the current rendertarget + current viewport onto the stack + virtual void PushRenderTargetAndViewport( ) = 0; + + // This version will push a new rendertarget + a maximal viewport for that rendertarget onto the stack + virtual void PushRenderTargetAndViewport( ITexture *pTexture ) = 0; + + // This version will push a new rendertarget + a specified viewport onto the stack + virtual void PushRenderTargetAndViewport( ITexture *pTexture, int nViewX, int nViewY, int nViewW, int nViewH ) = 0; + + // This version will push a new rendertarget + a specified viewport onto the stack + virtual void PushRenderTargetAndViewport( ITexture *pTexture, ITexture *pDepthTexture, int nViewX, int nViewY, int nViewW, int nViewH ) = 0; + + // This will pop a rendertarget + viewport + virtual void PopRenderTargetAndViewport( void ) = 0; + + // Binds a particular texture as the current lightmap + virtual void BindLightmapTexture( ITexture *pLightmapTexture ) = 0; + + // Blit a subrect of the current render target to another texture + virtual void CopyRenderTargetToTextureEx( ITexture *pTexture, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect = NULL ) = 0; + virtual void CopyTextureToRenderTargetEx( int nRenderTargetID, ITexture *pTexture, Rect_t *pSrcRect, Rect_t *pDstRect = NULL ) = 0; + + // Special off-center perspective matrix for DoF, MSAA jitter and poster rendering + virtual void PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right ) = 0; + + // Rendering parameters control special drawing modes withing the material system, shader + // system, shaders, and engine. renderparm.h has their definitions. + virtual void SetFloatRenderingParameter(int parm_number, float value) = 0; + virtual void SetIntRenderingParameter(int parm_number, int value) = 0; + virtual void SetVectorRenderingParameter(int parm_number, Vector const &value) = 0; + + // stencil buffer operations. + virtual void SetStencilEnable(bool onoff) = 0; + virtual void SetStencilFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilZFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilPassOperation(StencilOperation_t op) = 0; + virtual void SetStencilCompareFunction(StencilComparisonFunction_t cmpfn) = 0; + virtual void SetStencilReferenceValue(int ref) = 0; + virtual void SetStencilTestMask(uint32 msk) = 0; + virtual void SetStencilWriteMask(uint32 msk) = 0; + virtual void ClearStencilBufferRectangle(int xmin, int ymin, int xmax, int ymax,int value) =0; + + virtual void SetRenderTargetEx( int nRenderTargetID, ITexture *pTexture ) = 0; + + // rendering clip planes, beware that only the most recently pushed plane will actually be used in a sizeable chunk of hardware configurations + // and that changes to the clip planes mid-frame while UsingFastClipping() is true will result unresolvable depth inconsistencies + virtual void PushCustomClipPlane( const float *pPlane ) = 0; + virtual void PopCustomClipPlane( void ) = 0; + + // Returns the number of vertices + indices we can render using the dynamic mesh + // Passing true in the second parameter will return the max # of vertices + indices + // we can use before a flush is provoked and may return different values + // if called multiple times in succession. + // Passing false into the second parameter will return + // the maximum possible vertices + indices that can be rendered in a single batch + virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices ) = 0; + + // Returns the max possible vertices + indices to render in a single draw call + virtual int GetMaxVerticesToRender( IMaterial *pMaterial ) = 0; + virtual int GetMaxIndicesToRender( ) = 0; + virtual void DisableAllLocalLights() = 0; + virtual int CompareMaterialCombos( IMaterial *pMaterial1, IMaterial *pMaterial2, int lightMapID1, int lightMapID2 ) = 0; + + virtual IMesh *GetFlexMesh() = 0; + + virtual void SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture ) = 0; + + // Returns the currently bound local cubemap + virtual ITexture *GetLocalCubemap( ) = 0; + + // This is a version of clear buffers which will only clear the buffer at pixels which pass the stencil test + virtual void ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth ) = 0; + + //enables/disables all entered clipping planes, returns the input from the last time it was called. + virtual bool EnableClipping( bool bEnable ) = 0; + + //get fog distances entered with FogStart(), FogEnd(), and SetFogZ() + virtual void GetFogDistances( float *fStart, float *fEnd, float *fFogZ ) = 0; + + // Hooks for firing PIX events from outside the Material System... + virtual void BeginPIXEvent( unsigned long color, const char *szName ) = 0; + virtual void EndPIXEvent() = 0; + virtual void SetPIXMarker( unsigned long color, const char *szName ) = 0; + + // Batch API + // from changelist 166623: + // - replaced obtuse material system batch usage with an explicit and easier to thread API + virtual void BeginBatch( IMesh* pIndices ) = 0; + virtual void BindBatch( IMesh* pVertices, IMaterial *pAutoBind = NULL ) = 0; + virtual void DrawBatch(int firstIndex, int numIndices ) = 0; + virtual void EndBatch() = 0; + + // Raw access to the call queue, which can be NULL if not in a queued mode + virtual ICallQueue *GetCallQueue() = 0; + + // Returns the world-space camera position + virtual void GetWorldSpaceCameraPosition( Vector *pCameraPos ) = 0; + virtual void GetWorldSpaceCameraVectors( Vector *pVecForward, Vector *pVecRight, Vector *pVecUp ) = 0; + + // Tone mapping + virtual void ResetToneMappingScale( float monoscale) = 0; // set scale to monoscale instantly with no chasing + virtual void SetGoalToneMappingScale( float monoscale) = 0; // set scale to monoscale instantly with no chasing + + // call TurnOnToneMapping before drawing the 3d scene to get the proper interpolated brightness + // value set. + virtual void TurnOnToneMapping() = 0; + + // Set a linear vector color scale for all 3D rendering. + // A value of [1.0f, 1.0f, 1.0f] should match non-tone-mapped rendering. + virtual void SetToneMappingScaleLinear( const Vector &scale ) = 0; + + virtual Vector GetToneMappingScaleLinear( void ) = 0; + virtual void SetShadowDepthBiasFactors( float fSlopeScaleDepthBias, float fDepthBias ) = 0; + + // Apply stencil operations to every pixel on the screen without disturbing depth or color buffers + virtual void PerformFullScreenStencilOperation( void ) = 0; + + // Sets lighting origin for the current model (needed to convert directional lights to points) + virtual void SetLightingOrigin( Vector vLightingOrigin ) = 0; + + // Set scissor rect for rendering + virtual void SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor ) = 0; + + // Methods used to build the morph accumulator that is read from when HW morph E* LockRenderDataTyped( int nCount, const E* pSrcData = NULL ); + + // Temp render data gets immediately freed after it's all unlocked in single core. + // This prevents it from being freed + virtual void AddRefRenderData() = 0; + virtual void ReleaseRenderData() = 0; + + // Returns whether a pointer is render data. NOTE: passing NULL returns true + virtual bool IsRenderData( const void *pData ) const = 0; + virtual void PrintfVA( char *fmt, va_list vargs ) = 0; + virtual void Printf( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + virtual float Knob( char *knobname, float *setvalue = NULL ) = 0; + // Allows us to override the alpha write setting of a material + virtual void OverrideAlphaWriteEnable( bool bEnable, bool bAlphaWriteEnable ) = 0; + virtual void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable ) = 0; + + virtual void ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth ) = 0; + + // Create a texture from the specified src render target, then call pRecipient->OnAsyncCreateComplete from the main thread. + // The texture will be created using the destination format, and will optionally have mipmaps generated. + // In case of error, the provided callback function will be called with the error texture. + virtual void AsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs ) = 0; +}; + +template< class E > inline E* IMatRenderContext::LockRenderDataTyped( int nCount, const E* pSrcData ) +{ + int nSizeInBytes = nCount * sizeof(E); + E *pDstData = (E*)LockRenderData( nSizeInBytes ); + if ( pSrcData && pDstData ) + { + memcpy( pDstData, pSrcData, nSizeInBytes ); + } + return pDstData; +} + + +//----------------------------------------------------------------------------- +// Utility class for addreffing/releasing render data (prevents freeing on single core) +//----------------------------------------------------------------------------- +class CMatRenderDataReference +{ +public: + CMatRenderDataReference(); + CMatRenderDataReference( IMatRenderContext* pRenderContext ); + ~CMatRenderDataReference(); + void Lock( IMatRenderContext *pRenderContext ); + void Release(); + +private: + IMatRenderContext *m_pRenderContext; +}; + + +inline CMatRenderDataReference::CMatRenderDataReference() +{ + m_pRenderContext = NULL; +} + +inline CMatRenderDataReference::CMatRenderDataReference( IMatRenderContext* pRenderContext ) +{ + m_pRenderContext = NULL; + Lock( pRenderContext ); +} + +inline CMatRenderDataReference::~CMatRenderDataReference() +{ + Release(); +} + +inline void CMatRenderDataReference::Lock( IMatRenderContext* pRenderContext ) +{ + if ( !m_pRenderContext ) + { + m_pRenderContext = pRenderContext; + m_pRenderContext->AddRefRenderData( ); + } +} + +inline void CMatRenderDataReference::Release() +{ + if ( m_pRenderContext ) + { + m_pRenderContext->ReleaseRenderData( ); + m_pRenderContext = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Utility class for locking/unlocking render data +//----------------------------------------------------------------------------- +template< typename E > +class CMatRenderData +{ +public: + CMatRenderData( IMatRenderContext* pRenderContext ); + CMatRenderData( IMatRenderContext* pRenderContext, int nCount, const E *pSrcData = NULL ); + ~CMatRenderData(); + E* Lock( int nCount, const E* pSrcData = NULL ); + void Release(); + bool IsValid() const; + const E* Base() const; + E* Base(); + const E& operator[]( int i ) const; + E& operator[]( int i ); + +private: + IMatRenderContext* m_pRenderContext; + E *m_pRenderData; + int m_nCount; + bool m_bNeedsUnlock; +}; + +template< typename E > +inline CMatRenderData::CMatRenderData( IMatRenderContext* pRenderContext ) +{ + m_pRenderContext = pRenderContext; + m_nCount = 0; + m_pRenderData = 0; + m_bNeedsUnlock = false; +} + +template< typename E > +inline CMatRenderData::CMatRenderData( IMatRenderContext* pRenderContext, int nCount, const E* pSrcData ) +{ + m_pRenderContext = pRenderContext; + m_nCount = 0; + m_pRenderData = 0; + m_bNeedsUnlock = false; + Lock( nCount, pSrcData ); +} + +template< typename E > +inline CMatRenderData::~CMatRenderData() +{ + Release(); +} + +template< typename E > +inline bool CMatRenderData::IsValid() const +{ + return m_pRenderData != NULL; +} + +template< typename E > +inline E* CMatRenderData::Lock( int nCount, const E* pSrcData ) +{ + m_nCount = nCount; + if ( pSrcData && m_pRenderContext->IsRenderData( pSrcData ) ) + { + // Yes, we're const-casting away, but that should be ok since + // the src data is render data + m_pRenderData = const_cast( pSrcData ); + m_pRenderContext->AddRefRenderData(); + m_bNeedsUnlock = false; + return m_pRenderData; + } + m_pRenderData = m_pRenderContext->LockRenderDataTyped( nCount, pSrcData ); + m_bNeedsUnlock = true; + return m_pRenderData; +} + +template< typename E > +inline void CMatRenderData::Release() +{ + if ( m_pRenderContext && m_pRenderData ) + { + if ( m_bNeedsUnlock ) + { + m_pRenderContext->UnlockRenderData( m_pRenderData ); + } + else + { + m_pRenderContext->ReleaseRenderData(); + } + } + m_pRenderData = NULL; + m_nCount = 0; + m_bNeedsUnlock = false; +} + +template< typename E > +inline E* CMatRenderData::Base() +{ + return m_pRenderData; +} + +template< typename E > +inline const E* CMatRenderData::Base() const +{ + return m_pRenderData; +} + +template< typename E > +inline E& CMatRenderData::operator[]( int i ) +{ + Assert( ( i >= 0 ) && ( i < m_nCount ) ); + return m_pRenderData[i]; +} + +template< typename E > +inline const E& CMatRenderData::operator[]( int i ) const +{ + Assert( ( i >= 0 ) && ( i < m_nCount ) ); + return m_pRenderData[i]; +} + + +//----------------------------------------------------------------------------- + +class CMatRenderContextPtr : public CBaseAutoPtr +{ + typedef CBaseAutoPtr BaseClass; +public: + CMatRenderContextPtr() {} + CMatRenderContextPtr( IMatRenderContext *pInit ) : BaseClass( pInit ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->BeginRender(); } + CMatRenderContextPtr( IMaterialSystem *pFrom ) : BaseClass( pFrom->GetRenderContext() ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->BeginRender(); } + ~CMatRenderContextPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->EndRender(); } + + IMatRenderContext *operator=( IMatRenderContext *p ) { if ( p ) p->BeginRender(); return BaseClass::operator=( p ); } + + void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->EndRender(); } + void AssignAddRef( IMatRenderContext *pFrom ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->EndRender(); BaseClass::m_pObject->BeginRender(); } + + void GetFrom( IMaterialSystem *pFrom ) { AssignAddRef( pFrom->GetRenderContext() ); } + + +private: + CMatRenderContextPtr( const CMatRenderContextPtr &from ); + void operator=( const CMatRenderContextPtr &from ); + +}; + +//----------------------------------------------------------------------------- +// Helper class for begin/end of pix event via constructor/destructor +//----------------------------------------------------------------------------- +#define PIX_VALVE_ORANGE 0xFFF5940F + +class PIXEvent +{ +public: + PIXEvent( IMatRenderContext *pRenderContext, const char *szName, unsigned long color = PIX_VALVE_ORANGE ) + { + m_pRenderContext = pRenderContext; + Assert( m_pRenderContext ); + Assert( szName ); + m_pRenderContext->BeginPIXEvent( color, szName ); + } + ~PIXEvent() + { + m_pRenderContext->EndPIXEvent(); + } +private: + IMatRenderContext *m_pRenderContext; +}; + + +// Also be sure to enable PIX_INSTRUMENTATION in shaderdevicedx8.h +//#define PIX_ENABLE 1 // set this to 1 and build engine/studiorender to enable pix events in the engine + +#if PIX_ENABLE +# define PIXEVENT PIXEvent _pixEvent +#else +# define PIXEVENT +#endif + +//----------------------------------------------------------------------------- + +#ifdef MATERIAL_SYSTEM_DEBUG_CALL_QUEUE +#include "tier1/callqueue.h" +#include "tier1/fmtstr.h" +static void DoMatSysQueueMark( IMaterialSystem *pMaterialSystem, const char *psz ) +{ + CMatRenderContextPtr pRenderContext( pMaterialSystem ); + if ( pRenderContext->GetCallQueue() ) + pRenderContext->GetCallQueue()->QueueCall( Plat_DebugString, CUtlEnvelope( psz ) ); +} + +#define MatSysQueueMark( pMaterialSystem, ...) DoMatSysQueueMark( pMaterialSystem, CFmtStr( __VA_ARGS__ ) ) +#else +#define MatSysQueueMark( msg, ...) ((void)0) +#endif + +//----------------------------------------------------------------------------- + +extern IMaterialSystem *materials; +extern IMaterialSystem *g_pMaterialSystem; + +#endif // IMATERIALSYSTEM_H diff --git a/public/materialsystem/imaterialsystemhardwareconfig.h b/public/materialsystem/imaterialsystemhardwareconfig.h new file mode 100644 index 0000000..699b9bd --- /dev/null +++ b/public/materialsystem/imaterialsystemhardwareconfig.h @@ -0,0 +1,212 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef IMATERIALSYSTEMHARDWARECONFIG_H +#define IMATERIALSYSTEMHARDWARECONFIG_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/interface.h" + +//----------------------------------------------------------------------------- +// GL helpers +//----------------------------------------------------------------------------- +FORCEINLINE bool IsEmulatingGL() +{ + static bool bIsEmulatingGL = ( Plat_GetCommandLineA() ) ? ( strstr( Plat_GetCommandLineA(), "-r_emulate_gl" ) != NULL ) : false; + return bIsEmulatingGL; +} + +FORCEINLINE bool IsOpenGL( void ) +{ + return IsPlatformOpenGL() || IsEmulatingGL(); +} + +//----------------------------------------------------------------------------- +// Material system interface version +//----------------------------------------------------------------------------- +#define MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION "MaterialSystemHardwareConfig012" + +// HDRFIXME NOTE: must match common_ps_fxc.h +enum HDRType_t +{ + HDR_TYPE_NONE, + HDR_TYPE_INTEGER, + HDR_TYPE_FLOAT, +}; + +// For now, vertex compression is simply "on or off" (for the sake of simplicity +// and MeshBuilder perf.), but later we may support multiple flavours. +enum VertexCompressionType_t +{ + // This indicates an uninitialized VertexCompressionType_t value + VERTEX_COMPRESSION_INVALID = 0xFFFFFFFF, + + // 'VERTEX_COMPRESSION_NONE' means that no elements of a vertex are compressed + VERTEX_COMPRESSION_NONE = 0, + + // Currently (more stuff may be added as needed), 'VERTEX_COMPRESSION_ON' means: + // - if a vertex contains VERTEX_ELEMENT_NORMAL, this is compressed + // (see CVertexBuilder::CompressedNormal3f) + // - if a vertex contains VERTEX_ELEMENT_USERDATA4 (and a normal - together defining a tangent + // frame, with the binormal reconstructed in the vertex shader), this is compressed + // (see CVertexBuilder::CompressedUserData) + // - if a vertex contains VERTEX_ELEMENT_BONEWEIGHTSx, this is compressed + // (see CVertexBuilder::CompressedBoneWeight3fv) + VERTEX_COMPRESSION_ON = 1 +}; + + +// use DEFCONFIGMETHOD to define time-critical methods that we want to make just return constants +// on the 360, so that the checks will happen at compile time. Not all methods are defined this way +// - just the ones that I perceive as being called often in the frame interval. +#ifdef _X360 +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) \ +FORCEINLINE ret_type method const \ +{ \ + return xbox_return_value; \ +} + + +#else +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) \ +virtual ret_type method const = 0; +#endif + + + +//----------------------------------------------------------------------------- +// Material system configuration +//----------------------------------------------------------------------------- +class IMaterialSystemHardwareConfig +{ +public: + // on xbox, some methods are inlined to return constants + + DEFCONFIGMETHOD( bool, HasDestAlphaBuffer(), true ); + DEFCONFIGMETHOD( bool, HasStencilBuffer(), true ); + virtual int GetFrameBufferColorDepth() const = 0; + virtual int GetSamplerCount() const = 0; + virtual bool HasSetDeviceGammaRamp() const = 0; + DEFCONFIGMETHOD( bool, SupportsCompressedTextures(), true ); + virtual VertexCompressionType_t SupportsCompressedVertices() const = 0; + DEFCONFIGMETHOD( bool, SupportsNormalMapCompression(), true ); + DEFCONFIGMETHOD( bool, SupportsVertexAndPixelShaders(), true ); + DEFCONFIGMETHOD( bool, SupportsPixelShaders_1_4(), true ); + DEFCONFIGMETHOD( bool, SupportsStaticControlFlow(), true ); + DEFCONFIGMETHOD( bool, SupportsPixelShaders_2_0(), true ); + DEFCONFIGMETHOD( bool, SupportsVertexShaders_2_0(), true ); + virtual int MaximumAnisotropicLevel() const = 0; // 0 means no anisotropic filtering + virtual int MaxTextureWidth() const = 0; + virtual int MaxTextureHeight() const = 0; + virtual int TextureMemorySize() const = 0; + virtual bool SupportsOverbright() const = 0; + virtual bool SupportsCubeMaps() const = 0; + virtual bool SupportsMipmappedCubemaps() const = 0; + virtual bool SupportsNonPow2Textures() const = 0; + + // The number of texture stages represents the number of computations + // we can do in the fixed-function pipeline, it is *not* related to the + // simultaneous number of textures we can use + virtual int GetTextureStageCount() const = 0; + virtual int NumVertexShaderConstants() const = 0; + virtual int NumPixelShaderConstants() const = 0; + virtual int MaxNumLights() const = 0; + virtual bool SupportsHardwareLighting() const = 0; + virtual int MaxBlendMatrices() const = 0; + virtual int MaxBlendMatrixIndices() const = 0; + virtual int MaxTextureAspectRatio() const = 0; + virtual int MaxVertexShaderBlendMatrices() const = 0; + virtual int MaxUserClipPlanes() const = 0; + virtual bool UseFastClipping() const = 0; + + // This here should be the major item looked at when checking for compat + // from anywhere other than the material system shaders + DEFCONFIGMETHOD( int, GetDXSupportLevel(), 98 ); + virtual const char *GetShaderDLLName() const = 0; + + virtual bool ReadPixelsFromFrontBuffer() const = 0; + + // Are dx dynamic textures preferred? + virtual bool PreferDynamicTextures() const = 0; + + DEFCONFIGMETHOD( bool, SupportsHDR(), true ); + + virtual bool HasProjectedBumpEnv() const = 0; + virtual bool SupportsSpheremapping() const = 0; + virtual bool NeedsAAClamp() const = 0; + virtual bool NeedsATICentroidHack() const = 0; + + virtual bool SupportsColorOnSecondStream() const = 0; + virtual bool SupportsStaticPlusDynamicLighting() const = 0; + + // Does our card have a hard time with fillrate + // relative to other cards w/ the same dx level? + virtual bool PreferReducedFillrate() const = 0; + + // This is the max dx support level supported by the card + virtual int GetMaxDXSupportLevel() const = 0; + + // Does the card specify fog color in linear space when sRGBWrites are enabled? + virtual bool SpecifiesFogColorInLinearSpace() const = 0; + + // Does the card support sRGB reads/writes? + DEFCONFIGMETHOD( bool, SupportsSRGB(), true ); + DEFCONFIGMETHOD( bool, FakeSRGBWrite(), false ); + DEFCONFIGMETHOD( bool, CanDoSRGBReadFromRTs(), true ); + + virtual bool SupportsGLMixedSizeTargets() const = 0; + + virtual bool IsAAEnabled() const = 0; // Is antialiasing being used? + + // NOTE: Anything after this was added after shipping HL2. + virtual int GetVertexTextureCount() const = 0; + virtual int GetMaxVertexTextureDimension() const = 0; + + virtual int MaxTextureDepth() const = 0; + + virtual HDRType_t GetHDRType() const = 0; + virtual HDRType_t GetHardwareHDRType() const = 0; + + DEFCONFIGMETHOD( bool, SupportsPixelShaders_2_b(), true ); + virtual bool SupportsStreamOffset() const = 0; + + virtual int StencilBufferBits() const = 0; + virtual int MaxViewports() const = 0; + + virtual void OverrideStreamOffsetSupport( bool bOverrideEnabled, bool bEnableSupport ) = 0; + + virtual int GetShadowFilterMode() const = 0; + + virtual int NeedsShaderSRGBConversion() const = 0; + + DEFCONFIGMETHOD( bool, UsesSRGBCorrectBlending(), true ); + + virtual bool SupportsShaderModel_3_0() const = 0; + virtual bool HasFastVertexTextures() const = 0; + virtual int MaxHWMorphBatchCount() const = 0; + + // Does the board actually support this? + DEFCONFIGMETHOD( bool, ActuallySupportsPixelShaders_2_b(), true ); + + virtual bool SupportsHDRMode( HDRType_t nHDRMode ) const = 0; + + virtual bool GetHDREnabled( void ) const = 0; + virtual void SetHDREnabled( bool bEnable ) = 0; + + virtual bool SupportsBorderColor( void ) const = 0; + virtual bool SupportsFetch4( void ) const = 0; + + inline bool ShouldAlwaysUseShaderModel2bShaders() const { return IsOpenGL(); } + inline bool PlatformRequiresNonNullPixelShaders() const { return IsOpenGL(); } +}; + +#endif // IMATERIALSYSTEMHARDWARECONFIG_H diff --git a/public/materialsystem/imaterialsystemstub.h b/public/materialsystem/imaterialsystemstub.h new file mode 100644 index 0000000..b289e1b --- /dev/null +++ b/public/materialsystem/imaterialsystemstub.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IMATERIALSYSTEMSTUB_H +#define IMATERIALSYSTEMSTUB_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "materialsystem/imaterialsystem.h" + + +// If you get this interface out of the material system, it'll return an IMaterialSystem +// with everything stubbed. This is used for running the client in text mode. +#define MATERIAL_SYSTEM_STUB_INTERFACE_VERSION "VMaterialSystemStub001" + + +class IMaterialSystemStub : public IMaterialSystem +{ +public: + // If this is called, then the stub will call through to the real material + // system in some functions. + virtual void SetRealMaterialSystem( IMaterialSystem *pSys ) = 0; +}; + + +#endif // IMATERIALSYSTEMSTUB_H diff --git a/public/materialsystem/imaterialvar.h b/public/materialsystem/imaterialvar.h new file mode 100644 index 0000000..4918d24 --- /dev/null +++ b/public/materialsystem/imaterialvar.h @@ -0,0 +1,245 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IMATERIALVAR_H +#define IMATERIALVAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/utlsymbol.h" +#include "mathlib/vector4d.h" +class IMaterial; +class VMatrix; +class ITexture; + +#define MAKE_MATERIALVAR_FOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned long)(ch0) | ((unsigned long)(ch1) << 8) | \ + ((unsigned long)(ch2) << 16) | ((unsigned long)(ch3) << 24 )) + +// This fourcc is reserved. +#define FOURCC_UNKNOWN MAKE_MATERIALVAR_FOURCC('U','N','K','N') + + +//----------------------------------------------------------------------------- +// Various material var types +//----------------------------------------------------------------------------- +enum MaterialVarType_t +{ + MATERIAL_VAR_TYPE_FLOAT = 0, + MATERIAL_VAR_TYPE_STRING, + MATERIAL_VAR_TYPE_VECTOR, + MATERIAL_VAR_TYPE_TEXTURE, + MATERIAL_VAR_TYPE_INT, + MATERIAL_VAR_TYPE_FOURCC, + MATERIAL_VAR_TYPE_UNDEFINED, + MATERIAL_VAR_TYPE_MATRIX, + MATERIAL_VAR_TYPE_MATERIAL, +}; + +typedef unsigned short MaterialVarSym_t; + +class IMaterialVar +{ +public: + typedef unsigned long FourCC; + +protected: + // base data and accessors + char* m_pStringVal; + int m_intVal; + Vector4D m_VecVal; + + // member data. total = 4 bytes + uint8 m_Type : 4; + uint8 m_nNumVectorComps : 3; + uint8 m_bFakeMaterialVar : 1; + uint8 m_nTempIndex; + CUtlSymbol m_Name; + +public: + // class factory methods + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, VMatrix const& matrix ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, char const* pVal ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, float* pVal, int numcomps ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, float val ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, int val ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey ); + static void Destroy( IMaterialVar* pVar ); + static MaterialVarSym_t GetSymbol( char const* pName ); + static MaterialVarSym_t FindSymbol( char const* pName ); + static bool SymbolMatches( char const* pName, MaterialVarSym_t symbol ); + static void DeleteUnreferencedTextures( bool enable ); + + virtual ITexture *GetTextureValue( void ) = 0; + + virtual char const * GetName( void ) const = 0; + virtual MaterialVarSym_t GetNameAsSymbol() const = 0; + + virtual void SetFloatValue( float val ) = 0; + + virtual void SetIntValue( int val ) = 0; + + virtual void SetStringValue( char const *val ) = 0; + virtual char const * GetStringValue( void ) const = 0; + + // Use FourCC values to pass app-defined data structures between + // the proxy and the shader. The shader should ignore the data if + // its FourCC type not correct. + virtual void SetFourCCValue( FourCC type, void *pData ) = 0; + virtual void GetFourCCValue( FourCC *type, void **ppData ) = 0; + + // Vec (dim 2-4) + virtual void SetVecValue( float const* val, int numcomps ) = 0; + virtual void SetVecValue( float x, float y ) = 0; + virtual void SetVecValue( float x, float y, float z ) = 0; + virtual void SetVecValue( float x, float y, float z, float w ) = 0; + virtual void GetLinearVecValue( float *val, int numcomps ) const = 0; + + // revisit: is this a good interface for textures? + virtual void SetTextureValue( ITexture * ) = 0; + + virtual IMaterial * GetMaterialValue( void ) = 0; + virtual void SetMaterialValue( IMaterial * ) = 0; + + virtual bool IsDefined() const = 0; + virtual void SetUndefined() = 0; + + // Matrix + virtual void SetMatrixValue( VMatrix const& matrix ) = 0; + virtual const VMatrix &GetMatrixValue( ) = 0; + virtual bool MatrixIsIdentity() const = 0; + + // Copy.... + virtual void CopyFrom( IMaterialVar *pMaterialVar ) = 0; + + virtual void SetValueAutodetectType( char const *val ) = 0; + + virtual IMaterial * GetOwningMaterial() = 0; + + //set just 1 component + virtual void SetVecComponentValue( float fVal, int nComponent ) = 0; + +protected: + virtual int GetIntValueInternal( void ) const = 0; + virtual float GetFloatValueInternal( void ) const = 0; + virtual float const* GetVecValueInternal( ) const = 0; + virtual void GetVecValueInternal( float *val, int numcomps ) const = 0; + virtual int VectorSizeInternal() const = 0; + +public: + FORCEINLINE MaterialVarType_t GetType( void ) const + { + return ( MaterialVarType_t )m_Type; + } + + FORCEINLINE bool IsTexture() const + { + return m_Type == MATERIAL_VAR_TYPE_TEXTURE; + } + + FORCEINLINE operator ITexture*() + { + return GetTextureValue(); + } + + // NOTE: Fast methods should only be called in thread-safe situations + FORCEINLINE int GetIntValueFast( void ) const + { + // Set methods for float and vector update this + return m_intVal; + } + + FORCEINLINE float GetFloatValueFast( void ) const + { + return m_VecVal[0]; + } + + FORCEINLINE float const* GetVecValueFast( ) const + { + return m_VecVal.Base(); + } + + FORCEINLINE void GetVecValueFast( float *val, int numcomps ) const + { + Assert( ( numcomps >0 ) && ( numcomps <= 4 ) ); + for( int i=0 ; i < numcomps; i++ ) + { + val[i] = m_VecVal[ i ]; + } + } + + FORCEINLINE int VectorSizeFast() const + { + return m_nNumVectorComps; + } + +#ifdef FAST_MATERIALVAR_ACCESS + FORCEINLINE int GetIntValue( void ) const + { + return GetIntValueFast(); + } + + FORCEINLINE float GetFloatValue( void ) const + { + return GetFloatValueFast(); + } + + FORCEINLINE float const* GetVecValue( ) const + { + return GetVecValueFast(); + } + + FORCEINLINE void GetVecValue( float *val, int numcomps ) const + { + GetVecValueFast( val, numcomps ); + } + + FORCEINLINE int VectorSize() const + { + return VectorSizeFast(); + } +#else // !FAST_MATERIALVAR_ACCESS + FORCEINLINE int GetIntValue( void ) const + { + return GetIntValueInternal(); + } + + FORCEINLINE float GetFloatValue( void ) const + { + return GetFloatValueInternal(); + } + + FORCEINLINE float const* GetVecValue( ) const + { + return GetVecValueInternal(); + } + + FORCEINLINE void GetVecValue( float *val, int numcomps ) const + { + return GetVecValueInternal( val, numcomps ); + } + + FORCEINLINE int VectorSize() const + { + return VectorSizeInternal(); + } +#endif + +private: + FORCEINLINE void SetTempIndex( int nIndex ) + { + m_nTempIndex = nIndex; + } + + friend void EnableThreadedMaterialVarAccess( bool bEnable, IMaterialVar **ppParams, int nVarCount ); +}; + +#endif // IMATERIALVAR_H diff --git a/public/materialsystem/imesh.h b/public/materialsystem/imesh.h new file mode 100644 index 0000000..3da443b --- /dev/null +++ b/public/materialsystem/imesh.h @@ -0,0 +1,4049 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef IMESH_H +#define IMESH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "materialsystem/imaterial.h" +#include +#include +#include "tier0/dbg.h" +#include "tier2/meshutils.h" +#include "mathlib/mathlib.h" + +#if defined( DX_TO_GL_ABSTRACTION ) +// Swap these so that we do color swapping on 10.6.2, which doesn't have EXT_vertex_array_bgra +#define OPENGL_SWAP_COLORS +#endif + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class CMeshBuilder; +class IMaterialVar; +typedef uint64 VertexFormat_t; + + +//----------------------------------------------------------------------------- +// Define this to find write-combine problems +//----------------------------------------------------------------------------- +#ifdef _DEBUG +//#ifndef DEBUG_WRITE_COMBINE +//#define DEBUG_WRITE_COMBINE 1 +//#endif +#endif + + +//----------------------------------------------------------------------------- +// The Vertex Buffer interface +//----------------------------------------------------------------------------- +enum +{ + VERTEX_MAX_TEXTURE_COORDINATES = 8, + BONE_MATRIX_INDEX_INVALID = 255 +}; + +// Internal maximums for sizes. Don't use directly, use IMaterialSystem::GetMaxToRender() +enum +{ + INDEX_BUFFER_SIZE = 32768, + DYNAMIC_VERTEX_BUFFER_MEMORY = ( 1024 + 512 ) * 1024, + DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL = 384 * 1024, // Only allocate this much during map transitions +}; + +// Vertex fields must be written in well-defined order to achieve write combining, +// which is a perf booster +enum WriteCombineOrdering_t +{ + MB_FIELD_NONE = -1, + MB_FIELD_POSITION = 0, + MB_FIELD_BONE_WEIGHTS, + MB_FIELD_BONE_INDEX, + MB_FIELD_NORMAL, + MB_FIELD_COLOR, + MB_FIELD_SPECULAR, + MB_FIELD_TEXCOORD_FIRST, + MB_FIELD_TEXCOORD_LAST = MB_FIELD_TEXCOORD_FIRST + VERTEX_MAX_TEXTURE_COORDINATES - 1, + MB_FIELD_TANGENT_S, + MB_FIELD_TANGENT_T, + MB_FIELD_USERDATA, +}; + +#define MB_FIELD_TEXCOORD( nStage ) ( MB_FIELD_TEXCOORD_FIRST + ( nStage ) ) + +struct VertexDesc_t +{ + // These can be set to zero if there are pointers to dummy buffers, when the + // actual buffer format doesn't contain the data but it needs to be safe to + // use all the CMeshBuilder functions. + int m_VertexSize_Position; + int m_VertexSize_BoneWeight; + int m_VertexSize_BoneMatrixIndex; + int m_VertexSize_Normal; + int m_VertexSize_Color; + int m_VertexSize_Specular; + int m_VertexSize_TexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + int m_VertexSize_TangentS; + int m_VertexSize_TangentT; + int m_VertexSize_Wrinkle; + + int m_VertexSize_UserData; + + int m_ActualVertexSize; // Size of the vertices.. Some of the m_VertexSize_ elements above + // are set to this value and some are set to zero depending on which + // fields exist in a buffer's vertex format. + + // The type of compression applied to this vertex data + VertexCompressionType_t m_CompressionType; + + // Number of bone weights per vertex... + int m_NumBoneWeights; + + // Pointers to our current vertex data + float *m_pPosition; + + float *m_pBoneWeight; + +#ifndef NEW_SKINNING + unsigned char *m_pBoneMatrixIndex; +#else + float *m_pBoneMatrixIndex; +#endif + + float *m_pNormal; + + unsigned char *m_pColor; + unsigned char *m_pSpecular; + float *m_pTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + + // Tangent space *associated with one particular set of texcoords* + float *m_pTangentS; + float *m_pTangentT; + + float *m_pWrinkle; + + // user data + float *m_pUserData; + + // The first vertex index (used for buffered vertex buffers, or cards that don't support stream offset) + int m_nFirstVertex; + + // The offset in bytes of the memory we're writing into + // from the start of the D3D buffer (will be 0 for static meshes) + unsigned int m_nOffset; + +#ifdef DEBUG_WRITE_COMBINE + int m_nLastWrittenField; + unsigned char* m_pLastWrittenAddress; +#endif +}; + +struct IndexDesc_t +{ + // Pointers to the index data + unsigned short *m_pIndices; + + // The offset in bytes of the memory we're writing into + // from the start of the D3D buffer (will be 0 for static meshes) + unsigned int m_nOffset; + + // The first index (used for buffered index buffers, or cards that don't support stream offset) + unsigned int m_nFirstIndex; + + // 1 if the device is active, 0 if the device isn't active. + // Faster than doing if checks for null m_pIndices if someone is + // trying to write the m_pIndices while the device is inactive. + unsigned char m_nIndexSize; +}; + + +//----------------------------------------------------------------------------- +// The Mesh memory descriptor +//----------------------------------------------------------------------------- +struct MeshDesc_t : public VertexDesc_t, public IndexDesc_t +{ +}; + + +//----------------------------------------------------------------------------- +// Standard vertex formats for models +//----------------------------------------------------------------------------- +struct ModelVertexDX7_t +{ + Vector m_vecPosition; + Vector2D m_flBoneWeights; + unsigned int m_nBoneIndices; + Vector m_vecNormal; + unsigned int m_nColor; // ARGB + Vector2D m_vecTexCoord; +}; + +struct ModelVertexDX8_t : public ModelVertexDX7_t +{ + Vector4D m_vecUserData; +}; + + +//----------------------------------------------------------------------------- +// Utility methods for buffer builders +//----------------------------------------------------------------------------- +inline float *OffsetFloatPointer( float *pBufferPointer, int nVertexCount, int vertexSize ) +{ + return reinterpret_cast( + reinterpret_cast(pBufferPointer) + + nVertexCount * vertexSize); +} + +inline const float *OffsetFloatPointer( const float *pBufferPointer, int nVertexCount, int vertexSize ) +{ + return reinterpret_cast( + reinterpret_cast(pBufferPointer) + + nVertexCount * vertexSize); +} + +inline void IncrementFloatPointer( float* &pBufferPointer, int vertexSize ) +{ + pBufferPointer = reinterpret_cast( reinterpret_cast( pBufferPointer ) + vertexSize ); +} + + +//----------------------------------------------------------------------------- +// Used in lists of indexed primitives. +//----------------------------------------------------------------------------- +class CPrimList +{ +public: + CPrimList(); + CPrimList( int nFirstIndex, int nIndexCount ); + + int m_FirstIndex; + int m_NumIndices; +}; + +inline CPrimList::CPrimList() +{ +} + +inline CPrimList::CPrimList( int nFirstIndex, int nIndexCount ) +{ + m_FirstIndex = nFirstIndex; + m_NumIndices = nIndexCount; +} + +abstract_class IVertexBuffer +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IVertexBuffer() {} + + // NOTE: The following two methods are only valid for static vertex buffers + // Returns the number of vertices and the format of the vertex buffer + virtual int VertexCount() const = 0; + virtual VertexFormat_t GetVertexFormat() const = 0; + + // Is this vertex buffer dynamic? + virtual bool IsDynamic() const = 0; + + // NOTE: For dynamic vertex buffers only! + // Casts the memory of the dynamic vertex buffer to the appropriate type + virtual void BeginCastBuffer( VertexFormat_t format ) = 0; + virtual void EndCastBuffer() = 0; + + // Returns the number of vertices that can still be written into the buffer + virtual int GetRoomRemaining() const = 0; + + virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc ) = 0; + virtual void Unlock( int nVertexCount, VertexDesc_t &desc ) = 0; + + // Spews the mesh data + virtual void Spew( int nVertexCount, const VertexDesc_t &desc ) = 0; + + // Call this in debug mode to make sure our data is good. + virtual void ValidateData( int nVertexCount, const VertexDesc_t & desc ) = 0; +}; + +abstract_class IIndexBuffer +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IIndexBuffer() {} + + // NOTE: The following two methods are only valid for static index buffers + // Returns the number of indices and the format of the index buffer + virtual int IndexCount() const = 0; + virtual MaterialIndexFormat_t IndexFormat() const = 0; + + // Is this index buffer dynamic? + virtual bool IsDynamic() const = 0; + + // NOTE: For dynamic index buffers only! + // Casts the memory of the dynamic index buffer to the appropriate type + virtual void BeginCastBuffer( MaterialIndexFormat_t format ) = 0; + virtual void EndCastBuffer() = 0; + + // Returns the number of indices that can still be written into the buffer + virtual int GetRoomRemaining() const = 0; + + // Locks, unlocks the index buffer + virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc ) = 0; + virtual void Unlock( int nWrittenIndexCount, IndexDesc_t &desc ) = 0; + + // FIXME: Remove this!! + // Locks, unlocks the index buffer for modify + virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) = 0; + virtual void ModifyEnd( IndexDesc_t& desc ) = 0; + + // Spews the mesh data + virtual void Spew( int nIndexCount, const IndexDesc_t &desc ) = 0; + + // Ensures the data in the index buffer is valid + virtual void ValidateData( int nIndexCount, const IndexDesc_t &desc ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Interface to the mesh - needs to contain an IVertexBuffer and an IIndexBuffer to emulate old mesh behavior +//----------------------------------------------------------------------------- +abstract_class IMesh : public IVertexBuffer, public IIndexBuffer +{ +public: + // ----------------------------------- + + // Sets/gets the primitive type + virtual void SetPrimitiveType( MaterialPrimitiveType_t type ) = 0; + + // Draws the mesh + virtual void Draw( int nFirstIndex = -1, int nIndexCount = 0 ) = 0; + + virtual void SetColorMesh( IMesh *pColorMesh, int nVertexOffset ) = 0; + + // Draw a list of (lists of) primitives. Batching your lists together that use + // the same lightmap, material, vertex and index buffers with multipass shaders + // can drastically reduce state-switching overhead. + // NOTE: this only works with STATIC meshes. + virtual void Draw( CPrimList *pLists, int nLists ) = 0; + + // Copy verts and/or indices to a mesh builder. This only works for temp meshes! + virtual void CopyToMeshBuilder( + int iStartVert, // Which vertices to copy. + int nVerts, + int iStartIndex, // Which indices to copy. + int nIndices, + int indexOffset, // This is added to each index. + CMeshBuilder &builder ) = 0; + + // Spews the mesh data + virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &desc ) = 0; + + // Call this in debug mode to make sure our data is good. + virtual void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t &desc ) = 0; + + // New version + // Locks/unlocks the mesh, providing space for nVertexCount and nIndexCount. + // nIndexCount of -1 means don't lock the index buffer... + virtual void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc ) = 0; + virtual void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc ) = 0; + virtual void ModifyEnd( MeshDesc_t& desc ) = 0; + virtual void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc ) = 0; + + virtual void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t &desc ) = 0; + + virtual void SetFlexMesh( IMesh *pMesh, int nVertexOffset ) = 0; + + virtual void DisableFlexMesh() = 0; + + virtual void MarkAsDrawn() = 0; + + virtual unsigned ComputeMemoryUsed() = 0; +}; + + +#include "meshreader.h" + +#define INVALID_BUFFER_OFFSET 0xFFFFFFFFUL + +// flags for advancevertex optimization +#define VTX_HAVEPOS 1 +#define VTX_HAVENORMAL 2 +#define VTX_HAVECOLOR 4 +#define VTX_HAVEALL ( VTX_HAVEPOS | VTX_HAVENORMAL | VTX_HAVECOLOR ) + + +//----------------------------------------------------------------------------- +// +// Helper class used to define vertex buffers +// +//----------------------------------------------------------------------------- +class CVertexBuilder : private VertexDesc_t +{ +public: + CVertexBuilder(); + CVertexBuilder( IVertexBuffer *pVertexBuffer, VertexFormat_t fmt = 0 ); + ~CVertexBuilder(); + + // Begins, ends modification of the index buffer (returns true if the lock succeeded) + // A lock may not succeed if append is set to true and there isn't enough room + // NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers + bool Lock( int nMaxIndexCount, bool bAppend = false ); + void Unlock(); + + // Spews the current data + // NOTE: Can only be called during a lock/unlock block + void SpewData(); + + // Returns the number of indices we can fit into the buffer without needing to discard + int GetRoomRemaining() const; + + // Binds this vertex buffer + void Bind( IMatRenderContext *pContext, int nStreamID, VertexFormat_t usage = 0 ); + + // Returns the byte offset + int Offset() const; + + // This must be called before Begin, if a vertex buffer with a compressed format is to be used + void SetCompressionType( VertexCompressionType_t compressionType ); + void ValidateCompressionType(); + + void Begin( IVertexBuffer *pVertexBuffer, int nVertexCount, int *nFirstVertex ); + void Begin( IVertexBuffer *pVertexBuffer, int nVertexCount ); + + // Use this when you're done writing + // Set bDraw to true to call m_pMesh->Draw automatically. + void End( bool bSpewData = false ); + + // Locks the vertex buffer to modify existing data + // Passing nVertexCount == -1 says to lock all the vertices for modification. + void BeginModify( IVertexBuffer *pVertexBuffer, int nFirstVertex = 0, int nVertexCount = -1 ); + void EndModify( bool bSpewData = false ); + + // returns the number of vertices + int VertexCount() const; + + // Returns the total number of vertices across all Locks() + int TotalVertexCount() const; + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + // Returns the size of the vertex + int VertexSize() { return m_ActualVertexSize; } + + // returns the data size of a given texture coordinate + int TextureCoordinateSize( int nTexCoordNumber ) { return m_VertexSize_TexCoord[ nTexCoordNumber ]; } + + // Returns the base vertex memory pointer + void* BaseVertexData(); + + // Selects the nth Vertex and Index + void SelectVertex( int idx ); + + // Advances the current vertex and index by one + void AdvanceVertex( void ); + template void AdvanceVertexF( void ); + void AdvanceVertices( int nVerts ); + + int GetCurrentVertex() const; + int GetFirstVertex() const; + + // Data retrieval... + const float *Position() const; + + const float *Normal() const; + + unsigned int Color() const; + + unsigned char *Specular() const; + + const float *TexCoord( int stage ) const; + + const float *TangentS() const; + const float *TangentT() const; + + const float *BoneWeight() const; + float Wrinkle() const; + + int NumBoneWeights() const; +#ifndef NEW_SKINNING + unsigned char *BoneMatrix() const; +#else + float *BoneMatrix() const; +#endif + + // position setting + void Position3f( float x, float y, float z ); + void Position3fv( const float *v ); + + // normal setting + void Normal3f( float nx, float ny, float nz ); + void Normal3fv( const float *n ); + void NormalDelta3fv( const float *n ); + void NormalDelta3f( float nx, float ny, float nz ); + // normal setting (templatized for code which needs to support compressed vertices) + template void CompressedNormal3f( float nx, float ny, float nz ); + template void CompressedNormal3fv( const float *n ); + + // color setting + void Color3f( float r, float g, float b ); + void Color3fv( const float *rgb ); + void Color4f( float r, float g, float b, float a ); + void Color4fv( const float *rgba ); + + // Faster versions of color + void Color3ub( unsigned char r, unsigned char g, unsigned char b ); + void Color3ubv( unsigned char const* rgb ); + void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Color4ubv( unsigned char const* rgba ); + + // specular color setting + void Specular3f( float r, float g, float b ); + void Specular3fv( const float *rgb ); + void Specular4f( float r, float g, float b, float a ); + void Specular4fv( const float *rgba ); + + // Faster version of specular + void Specular3ub( unsigned char r, unsigned char g, unsigned char b ); + void Specular3ubv( unsigned char const *c ); + void Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Specular4ubv( unsigned char const *c ); + + // texture coordinate setting + void TexCoord1f( int stage, float s ); + void TexCoord2f( int stage, float s, float t ); + void TexCoord2fv( int stage, const float *st ); + void TexCoord3f( int stage, float s, float t, float u ); + void TexCoord3fv( int stage, const float *stu ); + void TexCoord4f( int stage, float s, float t, float u, float w ); + void TexCoord4fv( int stage, const float *stuv ); + + void TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ); + void TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale ); + + // tangent space + void TangentS3f( float sx, float sy, float sz ); + void TangentS3fv( const float* s ); + + void TangentT3f( float tx, float ty, float tz ); + void TangentT3fv( const float* t ); + + // Wrinkle + void Wrinkle1f( float flWrinkle ); + + // bone weights + void BoneWeight( int idx, float weight ); + // bone weights (templatized for code which needs to support compressed vertices) + template void CompressedBoneWeight3fv( const float * pWeights ); + + // bone matrix index + void BoneMatrix( int idx, int matrixIndex ); + + // Generic per-vertex data + void UserData( const float* pData ); + // Generic per-vertex data (templatized for code which needs to support compressed vertices) + template void CompressedUserData( const float* pData ); + + // Fast Vertex! No need to call advance vertex, and no random access allowed. + // WARNING - these are low level functions that are intended only for use + // in the software vertex skinner. + void FastVertex( const ModelVertexDX7_t &vertex ); + void FastVertexSSE( const ModelVertexDX7_t &vertex ); + + // store 4 dx7 vertices fast. for special sse dx7 pipeline + void Fast4VerticesSSE( + ModelVertexDX7_t const *vtx_a, + ModelVertexDX7_t const *vtx_b, + ModelVertexDX7_t const *vtx_c, + ModelVertexDX7_t const *vtx_d); + + void FastVertex( const ModelVertexDX8_t &vertex ); + void FastVertexSSE( const ModelVertexDX8_t &vertex ); + + // Add number of verts and current vert since FastVertex routines do not update. + void FastAdvanceNVertices( int n ); + +#if defined( _X360 ) + void VertexDX8ToX360( const ModelVertexDX8_t &vertex ); +#endif + + // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. + void AttachBegin( IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t &desc ); + void AttachEnd(); + void AttachBeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t &desc ); + void AttachEndModify(); + +private: + // The vertex buffer we're modifying + IVertexBuffer *m_pVertexBuffer; + + // Used to make sure Begin/End calls and BeginModify/EndModify calls match. + bool m_bModify; + + // Max number of indices and vertices + int m_nMaxVertexCount; + + // Number of indices and vertices + int m_nVertexCount; + + // The current vertex and index + mutable int m_nCurrentVertex; + + // Optimization: Pointer to the current pos, norm, texcoord, and color + mutable float *m_pCurrPosition; + mutable float *m_pCurrNormal; + mutable float *m_pCurrTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + mutable unsigned char *m_pCurrColor; + + // Total number of vertices appended + int m_nTotalVertexCount; + + // First vertex buffer offset + index + unsigned int m_nBufferOffset; + unsigned int m_nBufferFirstVertex; + +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // Debug checks to make sure we write userdata4/tangents AFTER normals + bool m_bWrittenNormal : 1; + bool m_bWrittenUserData : 1; +#endif + + friend class CMeshBuilder; +}; + + +//----------------------------------------------------------------------------- +// +// Inline methods of CVertexBuilder +// +//----------------------------------------------------------------------------- +inline CVertexBuilder::CVertexBuilder() +{ + m_pVertexBuffer = NULL; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstVertex = 0; + m_nVertexCount = 0; + m_nCurrentVertex = 0; + m_nMaxVertexCount = 0; + m_nTotalVertexCount = 0; + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + m_bModify = false; +#endif +} + +inline CVertexBuilder::CVertexBuilder( IVertexBuffer *pVertexBuffer, VertexFormat_t fmt ) +{ + m_pVertexBuffer = pVertexBuffer; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstVertex = 0; + m_nVertexCount = 0; + m_nCurrentVertex = 0; + m_nMaxVertexCount = 0; + m_nTotalVertexCount = 0; + m_CompressionType = VERTEX_COMPRESSION_INVALID; + + if ( m_pVertexBuffer->IsDynamic() ) + { + m_pVertexBuffer->BeginCastBuffer( fmt ); + } + else + { + Assert( m_pVertexBuffer->GetVertexFormat() == fmt ); + } + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + m_bModify = false; +#endif +} + +inline CVertexBuilder::~CVertexBuilder() +{ + if ( m_pVertexBuffer && m_pVertexBuffer->IsDynamic() ) + { + m_pVertexBuffer->EndCastBuffer(); + } +} + +//----------------------------------------------------------------------------- +// Begins, ends modification of the index buffer +//----------------------------------------------------------------------------- +inline bool CVertexBuilder::Lock( int nMaxVertexCount, bool bAppend ) +{ + Assert( m_pVertexBuffer ); + m_bModify = false; + m_nMaxVertexCount = nMaxVertexCount; + bool bFirstLock = ( m_nBufferOffset == INVALID_BUFFER_OFFSET ); + if ( bFirstLock ) + { + bAppend = false; + } + if ( !bAppend ) + { + m_nTotalVertexCount = 0; + } + + // Lock the vertex buffer + if ( !m_pVertexBuffer->Lock( m_nMaxVertexCount, bAppend, *this ) ) + { + m_nMaxVertexCount = 0; + return false; + } + + Reset(); + + if ( bFirstLock ) + { + m_nBufferOffset = m_nOffset; + m_nBufferFirstVertex = m_nFirstVertex; + } + + return true; +} + +inline void CVertexBuilder::Unlock() +{ + Assert( !m_bModify && m_pVertexBuffer ); + +#ifdef _DEBUG + m_pVertexBuffer->ValidateData( m_nVertexCount, *this ); +#endif + + m_pVertexBuffer->Unlock( m_nVertexCount, *this ); + m_nTotalVertexCount += m_nVertexCount; + + m_nMaxVertexCount = 0; + +#ifdef _DEBUG + // Null out our data... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + +inline void CVertexBuilder::SpewData() +{ + m_pVertexBuffer->Spew( m_nVertexCount, *this ); +} + + +//----------------------------------------------------------------------------- +// Binds this vertex buffer +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Bind( IMatRenderContext *pContext, int nStreamID, VertexFormat_t usage ) +{ + if ( m_pVertexBuffer && ( m_nBufferOffset != INVALID_BUFFER_OFFSET ) ) + { + pContext->BindVertexBuffer( nStreamID, m_pVertexBuffer, m_nBufferOffset, + m_nFirstVertex, m_nTotalVertexCount, usage ? usage : m_pVertexBuffer->GetVertexFormat() ); + } + else + { + pContext->BindVertexBuffer( nStreamID, NULL, 0, 0, 0, 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Returns the byte offset +//----------------------------------------------------------------------------- +inline int CVertexBuilder::Offset() const +{ + return m_nBufferOffset; +} + +inline int CVertexBuilder::GetFirstVertex() const +{ + return m_nBufferFirstVertex; +} + +//----------------------------------------------------------------------------- +// Specify the type of vertex compression that this CMeshBuilder will perform +//----------------------------------------------------------------------------- +inline void CVertexBuilder::SetCompressionType( VertexCompressionType_t compressionType ) +{ + // The real purpose of this method is to allow us to emit a Warning in Begin() + m_CompressionType = compressionType; +} + +inline void CVertexBuilder::ValidateCompressionType() +{ +#ifdef _DEBUG + VertexCompressionType_t vbCompressionType = CompressionType( m_pVertexBuffer->GetVertexFormat() ); + if ( vbCompressionType != VERTEX_COMPRESSION_NONE ) + { + Assert( m_CompressionType == vbCompressionType ); + if ( m_CompressionType != vbCompressionType ) + { + Warning( "ERROR: CVertexBuilder::SetCompressionType() must be called to specify the same vertex compression type (%s) as the vertex buffer being modified." + "Junk vertices will be rendered, or there will be a crash in CVertexBuilder!\n", + vbCompressionType == VERTEX_COMPRESSION_ON ? "VERTEX_COMPRESSION_ON" : "VERTEX_COMPRESSION_NONE" ); + } + // Never use vertex compression for dynamic VBs (the conversions can really hurt perf) + Assert( !m_pVertexBuffer->IsDynamic() ); + } +#endif +} + +inline void CVertexBuilder::Begin( IVertexBuffer *pVertexBuffer, int nVertexCount ) +{ + Assert( pVertexBuffer && (!m_pVertexBuffer) ); + + m_pVertexBuffer = pVertexBuffer; + m_bModify = false; + + m_nMaxVertexCount = nVertexCount; + m_nVertexCount = 0; + + // Make sure SetCompressionType was called correctly, if this VB is compressed + ValidateCompressionType(); + + // Lock the vertex and index buffer + m_pVertexBuffer->Lock( m_nMaxVertexCount, false, *this ); + + // Point to the start of the buffers.. + Reset(); +} + + +//----------------------------------------------------------------------------- +// Use this when you're done modifying the mesh +//----------------------------------------------------------------------------- +inline void CVertexBuilder::End( bool bSpewData ) +{ + // Make sure they called Begin() + Assert( !m_bModify ); + + if ( bSpewData ) + { + m_pVertexBuffer->Spew( m_nVertexCount, *this ); + } + +#ifdef _DEBUG + m_pVertexBuffer->ValidateData( m_nVertexCount, *this ); +#endif + + // Unlock our buffers + m_pVertexBuffer->Unlock( m_nVertexCount, *this ); + + m_pVertexBuffer = 0; + m_nMaxVertexCount = 0; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + // Null out our pointers... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast< VertexDesc_t* >( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. +//----------------------------------------------------------------------------- +inline void CVertexBuilder::AttachBegin( IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t &desc ) +{ + VertexCompressionType_t compressionType = m_CompressionType; + + m_pVertexBuffer = pMesh; + memcpy( static_cast( this ), static_cast( &desc ), sizeof(VertexDesc_t) ); + m_nMaxVertexCount = nMaxVertexCount; + m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; // Two weights if any + m_nVertexCount = 0; + m_bModify = false; + + if ( compressionType != VERTEX_COMPRESSION_INVALID ) + m_CompressionType = compressionType; + + // Make sure SetCompressionType was called correctly, if this VB is compressed + ValidateCompressionType(); + + if ( m_nBufferOffset == INVALID_BUFFER_OFFSET ) + { + m_nTotalVertexCount = 0; + m_nBufferOffset = static_cast< const VertexDesc_t* >( &desc )->m_nOffset; + m_nBufferFirstVertex = desc.m_nFirstVertex; + } +} + +inline void CVertexBuilder::AttachEnd() +{ + // Make sure they called Begin() + Assert( !m_bModify ); + + m_nMaxVertexCount = 0; + m_pVertexBuffer = NULL; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + // Null out our pointers... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + +inline void CVertexBuilder::AttachBeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t &desc ) +{ + Assert( pMesh && (!m_pVertexBuffer) ); + + m_pVertexBuffer = pMesh; + memcpy( static_cast( this ), static_cast( &desc ), sizeof(VertexDesc_t) ); + m_nMaxVertexCount = m_nVertexCount = nVertexCount; + m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; // Two weights if any + m_bModify = true; + + // Make sure SetCompressionType was called correctly, if this VB is compressed + ValidateCompressionType(); +} + +inline void CVertexBuilder::AttachEndModify() +{ + Assert( m_pVertexBuffer ); + Assert( m_bModify ); // Make sure they called BeginModify. + + m_pVertexBuffer = 0; + m_nMaxVertexCount = 0; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + // Null out our pointers... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Computes the first min non-null address +//----------------------------------------------------------------------------- +inline unsigned char* FindMinAddress( void *pAddress1, void *pAddress2, int nAddress2Size ) +{ + if ( nAddress2Size == 0 ) + return (unsigned char*)pAddress1; + if ( !pAddress1 ) + return (unsigned char*)pAddress2; + return ( pAddress1 < pAddress2 ) ? (unsigned char*)pAddress1 : (unsigned char*)pAddress2; +} + +//----------------------------------------------------------------------------- +// Resets the vertex buffer builder so it points to the start of everything again +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Reset() +{ + m_nCurrentVertex = 0; + + m_pCurrPosition = m_pPosition; + m_pCurrNormal = m_pNormal; + for ( int i = 0; i < NELEMS( m_pCurrTexCoord ); i++ ) + { + m_pCurrTexCoord[i] = m_pTexCoord[i]; + } + m_pCurrColor = m_pColor; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif + +#ifdef DEBUG_WRITE_COMBINE + // Logic for m_pLastWrittenAddress is tricky. It really wants the min of the + // non-null address pointers. + m_nLastWrittenField = MB_FIELD_NONE; + m_pLastWrittenAddress = NULL; + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pPosition, m_VertexSize_Position ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pBoneWeight, m_VertexSize_BoneWeight ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pBoneMatrixIndex, m_VertexSize_BoneMatrixIndex ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pNormal, m_VertexSize_Normal ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pColor, m_VertexSize_Color ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pSpecular, m_VertexSize_Specular ); + for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i ) + { + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTexCoord[i], m_VertexSize_TexCoord[i] ); + } + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTangentS, m_VertexSize_TangentS ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTangentT, m_VertexSize_TangentT ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pUserData, m_VertexSize_UserData ); +#endif +} + + +//----------------------------------------------------------------------------- +// returns the number of vertices +//----------------------------------------------------------------------------- +inline int CVertexBuilder::VertexCount() const +{ + return m_nVertexCount; +} + + +//----------------------------------------------------------------------------- +// Returns the total number of vertices across all Locks() +//----------------------------------------------------------------------------- +inline int CVertexBuilder::TotalVertexCount() const +{ + return m_nTotalVertexCount; +} + + +//----------------------------------------------------------------------------- +// Returns the base vertex memory pointer +//----------------------------------------------------------------------------- +inline void* CVertexBuilder::BaseVertexData() +{ + // FIXME: If there's no position specified, we need to find + // the base address + Assert( m_pPosition ); + return m_pPosition; +} + + +//----------------------------------------------------------------------------- +// Selects the current vertex +//----------------------------------------------------------------------------- +inline void CVertexBuilder::SelectVertex( int nIndex ) +{ + // NOTE: This index is expected to be relative + Assert( (nIndex >= 0) && (nIndex < m_nMaxVertexCount) ); + m_nCurrentVertex = nIndex; + + m_pCurrPosition = OffsetFloatPointer( m_pPosition, m_nCurrentVertex, m_VertexSize_Position ); + m_pCurrNormal = OffsetFloatPointer( m_pNormal, m_nCurrentVertex, m_VertexSize_Normal ); + + COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 ); + m_pCurrTexCoord[0] = OffsetFloatPointer( m_pTexCoord[0], m_nCurrentVertex, m_VertexSize_TexCoord[0] ); + m_pCurrTexCoord[1] = OffsetFloatPointer( m_pTexCoord[1], m_nCurrentVertex, m_VertexSize_TexCoord[1] ); + m_pCurrTexCoord[2] = OffsetFloatPointer( m_pTexCoord[2], m_nCurrentVertex, m_VertexSize_TexCoord[2] ); + m_pCurrTexCoord[3] = OffsetFloatPointer( m_pTexCoord[3], m_nCurrentVertex, m_VertexSize_TexCoord[3] ); + m_pCurrTexCoord[4] = OffsetFloatPointer( m_pTexCoord[4], m_nCurrentVertex, m_VertexSize_TexCoord[4] ); + m_pCurrTexCoord[5] = OffsetFloatPointer( m_pTexCoord[5], m_nCurrentVertex, m_VertexSize_TexCoord[5] ); + m_pCurrTexCoord[6] = OffsetFloatPointer( m_pTexCoord[6], m_nCurrentVertex, m_VertexSize_TexCoord[6] ); + m_pCurrTexCoord[7] = OffsetFloatPointer( m_pTexCoord[7], m_nCurrentVertex, m_VertexSize_TexCoord[7] ); + m_pCurrColor = m_pColor + m_nCurrentVertex * m_VertexSize_Color; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +//----------------------------------------------------------------------------- +// Advances vertex after you're done writing to it. +//----------------------------------------------------------------------------- + +template FORCEINLINE void CVertexBuilder::AdvanceVertexF() +{ + if ( ++m_nCurrentVertex > m_nVertexCount ) + { + m_nVertexCount = m_nCurrentVertex; + } + + if ( nFlags & VTX_HAVEPOS ) + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + if ( nFlags & VTX_HAVENORMAL ) + IncrementFloatPointer( m_pCurrNormal, m_VertexSize_Normal ); + if ( nFlags & VTX_HAVECOLOR ) + m_pCurrColor += m_VertexSize_Color; + + COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 ); + if ( nNumTexCoords > 0 ) + IncrementFloatPointer( m_pCurrTexCoord[0], m_VertexSize_TexCoord[0] ); + if ( nNumTexCoords > 1 ) + IncrementFloatPointer( m_pCurrTexCoord[1], m_VertexSize_TexCoord[1] ); + if ( nNumTexCoords > 2 ) + IncrementFloatPointer( m_pCurrTexCoord[2], m_VertexSize_TexCoord[2] ); + if ( nNumTexCoords > 3 ) + IncrementFloatPointer( m_pCurrTexCoord[3], m_VertexSize_TexCoord[3] ); + if ( nNumTexCoords > 4 ) + IncrementFloatPointer( m_pCurrTexCoord[4], m_VertexSize_TexCoord[4] ); + if ( nNumTexCoords > 5 ) + IncrementFloatPointer( m_pCurrTexCoord[5], m_VertexSize_TexCoord[5] ); + if ( nNumTexCoords > 6 ) + IncrementFloatPointer( m_pCurrTexCoord[6], m_VertexSize_TexCoord[6] ); + if ( nNumTexCoords > 7 ) + IncrementFloatPointer( m_pCurrTexCoord[7], m_VertexSize_TexCoord[7] ); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::AdvanceVertex() +{ + AdvanceVertexF(); +} + + +inline void CVertexBuilder::AdvanceVertices( int nVerts ) +{ + m_nCurrentVertex += nVerts; + if ( m_nCurrentVertex > m_nVertexCount ) + { + m_nVertexCount = m_nCurrentVertex; + } + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position*nVerts ); + IncrementFloatPointer( m_pCurrNormal, m_VertexSize_Normal*nVerts ); + + COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 ); + IncrementFloatPointer( m_pCurrTexCoord[0], m_VertexSize_TexCoord[0]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[1], m_VertexSize_TexCoord[1]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[2], m_VertexSize_TexCoord[2]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[3], m_VertexSize_TexCoord[3]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[4], m_VertexSize_TexCoord[4]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[5], m_VertexSize_TexCoord[5]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[6], m_VertexSize_TexCoord[6]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[7], m_VertexSize_TexCoord[7]*nVerts ); + m_pCurrColor += m_VertexSize_Color*nVerts; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +//----------------------------------------------------------------------------- +// For use with the FastVertex methods, advances the current vertex by N +//----------------------------------------------------------------------------- +inline void CVertexBuilder::FastAdvanceNVertices( int n ) +{ + m_nCurrentVertex += n; + m_nVertexCount = m_nCurrentVertex; +} + + + +#ifndef COMPILER_MSVC64 +// Implement for 64-bit Windows if needed. +//----------------------------------------------------------------------------- +// Fast Vertex! No need to call advance vertex, and no random access allowed +//----------------------------------------------------------------------------- +inline void CVertexBuilder::FastVertex( const ModelVertexDX7_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movq mm0, [esi + 0] + movq mm1, [esi + 8] + movq mm2, [esi + 16] + movq mm3, [esi + 24] + movq mm4, [esi + 32] + movq mm5, [esi + 40] + + movntq [edi + 0], mm0 + movntq [edi + 8], mm1 + movntq [edi + 16], mm2 + movntq [edi + 24], mm3 + movntq [edi + 32], mm4 + movntq [edi + 40], mm5 + + emms + } +#elif defined(GNUC) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm__ __volatile__ ( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "emms\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error( "Implement CMeshBuilder::FastVertex(dx7) "); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + //m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX7_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + + movntps [edi + 0], xmm0 + movntps [edi + 16], xmm1 + movntps [edi + 32], xmm2 + } +#elif defined(GNUC) + const char *pRead = (char *)&vertex; + char *pCurrPos = (char *)m_pCurrPosition; + __m128 m1 = _mm_load_ps( (float *)pRead ); + __m128 m2 = _mm_load_ps( (float *)(pRead + 16) ); + __m128 m3 = _mm_load_ps( (float *)(pRead + 32) ); + _mm_stream_ps( (float *)pCurrPos, m1 ); + _mm_stream_ps( (float *)(pCurrPos + 16), m2 ); + _mm_stream_ps( (float *)(pCurrPos + 32), m3 ); +#else + Error( "Implement CMeshBuilder::FastVertexSSE(dx7)" ); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + //m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::Fast4VerticesSSE( + ModelVertexDX7_t const *vtx_a, + ModelVertexDX7_t const *vtx_b, + ModelVertexDX7_t const *vtx_c, + ModelVertexDX7_t const *vtx_d) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount-3 ); + +#if defined( _WIN32 ) && !defined( _X360 ) + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, vtx_a + mov ecx, vtx_b + + mov edi, pCurrPos + nop + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + movaps xmm3, [ecx + 0] + movaps xmm4, [ecx + 16] + movaps xmm5, [ecx + 32] + + mov esi, vtx_c + mov ecx, vtx_d + + movntps [edi + 0], xmm0 + movntps [edi + 16], xmm1 + movntps [edi + 32], xmm2 + movntps [edi + 48], xmm3 + movntps [edi + 64], xmm4 + movntps [edi + 80], xmm5 + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + movaps xmm3, [ecx + 0] + movaps xmm4, [ecx + 16] + movaps xmm5, [ecx + 32] + + movntps [edi + 0+96], xmm0 + movntps [edi + 16+96], xmm1 + movntps [edi + 32+96], xmm2 + movntps [edi + 48+96], xmm3 + movntps [edi + 64+96], xmm4 + movntps [edi + 80+96], xmm5 + + } +#else + Error( "Implement CMeshBuilder::Fast4VerticesSSE\n"); +#endif + IncrementFloatPointer( m_pCurrPosition, 4*m_VertexSize_Position ); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertex( const ModelVertexDX8_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movq mm0, [esi + 0] + movq mm1, [esi + 8] + movq mm2, [esi + 16] + movq mm3, [esi + 24] + movq mm4, [esi + 32] + movq mm5, [esi + 40] + movq mm6, [esi + 48] + movq mm7, [esi + 56] + + movntq [edi + 0], mm0 + movntq [edi + 8], mm1 + movntq [edi + 16], mm2 + movntq [edi + 24], mm3 + movntq [edi + 32], mm4 + movntq [edi + 40], mm5 + movntq [edi + 48], mm6 + movntq [edi + 56], mm7 + + emms + } +#elif defined(GNUC) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm__ __volatile__ ( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "movntq %%mm6, 48(%1)\n" + "movntq %%mm7, 56(%1)\n" + "emms\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error( "Implement CMeshBuilder::FastVertex(dx8)" ); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + // m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + movaps xmm3, [esi + 48] + + movntps [edi + 0], xmm0 + movntps [edi + 16], xmm1 + movntps [edi + 32], xmm2 + movntps [edi + 48], xmm3 + } +#elif defined(GNUC) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm__ __volatile__ ( + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error( "Implement CMeshBuilder::FastVertexSSE((dx8)" ); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + // m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} +#endif // COMPILER_MSVC64 + + +//----------------------------------------------------------------------------- +// Returns the current vertex +//----------------------------------------------------------------------------- +inline int CVertexBuilder::GetCurrentVertex() const +{ + return m_nCurrentVertex; +} + + +//----------------------------------------------------------------------------- +// Copies a vertex into the x360 format +//----------------------------------------------------------------------------- +#if defined( _X360 ) +inline void CVertexBuilder::VertexDX8ToX360( const ModelVertexDX8_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + + // get the start of the data + unsigned char *pDst = (unsigned char*)m_pCurrPosition; + + Assert( m_VertexSize_Position > 0 ); // Assume position is always present + Assert( GetVertexElementSize( VERTEX_ELEMENT_POSITION, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecPosition ) ); + memcpy( pDst, vertex.m_vecPosition.Base(), sizeof( vertex.m_vecPosition ) ); + pDst += sizeof( vertex.m_vecPosition ); + + if ( m_VertexSize_BoneWeight ) + { + Assert( vertex.m_flBoneWeights[0] >= 0 && vertex.m_flBoneWeights[0] <= 1.0f ); + Assert( vertex.m_flBoneWeights[1] >= 0 && vertex.m_flBoneWeights[1] <= 1.0f ); + Assert( GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_flBoneWeights ) ); + memcpy( pDst, vertex.m_flBoneWeights.Base(), sizeof( vertex.m_flBoneWeights ) ); + pDst += sizeof( vertex.m_flBoneWeights ); + + if ( m_VertexSize_BoneMatrixIndex ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_nBoneIndices ) ); + *(unsigned int*)pDst = vertex.m_nBoneIndices; + pDst += sizeof( vertex.m_nBoneIndices ); + } + } + + if ( m_VertexSize_Normal ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecNormal ) ); + memcpy( pDst, vertex.m_vecNormal.Base(), sizeof( vertex.m_vecNormal ) ); + pDst += sizeof( vertex.m_vecNormal ); + } + + if ( m_VertexSize_Color ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_COLOR, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_nColor ) ); + *(unsigned int*)pDst = vertex.m_nColor; + pDst += sizeof( vertex.m_nColor ); + } + + if ( m_VertexSize_TexCoord[0] ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecTexCoord ) ); + memcpy( pDst, vertex.m_vecTexCoord.Base(), sizeof( vertex.m_vecTexCoord ) ); + pDst += sizeof( vertex.m_vecTexCoord ); + } + + if ( m_VertexSize_UserData ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_USERDATA4, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecUserData ) ); + memcpy( pDst, vertex.m_vecUserData.Base(), sizeof( vertex.m_vecUserData ) ); + pDst += sizeof( vertex.m_vecUserData ); + } + + // ensure code is synced with the mesh builder that established the offsets + Assert( pDst - (unsigned char*)m_pCurrPosition == m_VertexSize_Position ); + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} +#endif + + +//----------------------------------------------------------------------------- +// Data retrieval... +//----------------------------------------------------------------------------- +inline const float* CVertexBuilder::Position() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pCurrPosition; +} + +inline const float* CVertexBuilder::Normal() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pCurrNormal; +} + +inline unsigned int CVertexBuilder::Color() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + // Swizzle it so it returns the same format as accepted by Color4ubv - rgba + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + unsigned int color; + if ( IsPC() || !IsX360() ) + { + color = (m_pCurrColor[3] << 24) | (m_pCurrColor[0] << 16) | (m_pCurrColor[1] << 8) | (m_pCurrColor[2]); + } + else + { + // in memory as argb, back to rgba + color = (m_pCurrColor[1] << 24) | (m_pCurrColor[2] << 16) | (m_pCurrColor[3] << 8) | (m_pCurrColor[0]); + } + return color; +} + +inline unsigned char *CVertexBuilder::Specular() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pSpecular + m_nCurrentVertex * m_VertexSize_Specular; +} + +inline const float* CVertexBuilder::TexCoord( int stage ) const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pCurrTexCoord[stage]; +} + +inline const float* CVertexBuilder::TangentS() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS ); +} + +inline const float* CVertexBuilder::TangentT() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT ); +} + +inline float CVertexBuilder::Wrinkle() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return *OffsetFloatPointer( m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle ); +} + +inline const float* CVertexBuilder::BoneWeight() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight ); +} + +inline int CVertexBuilder::NumBoneWeights() const +{ + return m_NumBoneWeights; +} + +#ifndef NEW_SKINNING +inline unsigned char* CVertexBuilder::BoneMatrix() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; +} +#else +inline float* CVertexBuilder::BoneMatrix() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; +} +#endif + + +//----------------------------------------------------------------------------- +// Position setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Position3f( float x, float y, float z ) +{ + Assert( m_pPosition && m_pCurrPosition ); + Assert( IsFinite(x) && IsFinite(y) && IsFinite(z) ); + float *pDst = m_pCurrPosition; + *pDst++ = x; + *pDst++ = y; + *pDst = z; +} + +inline void CVertexBuilder::Position3fv( const float *v ) +{ + Assert(v); + Assert( m_pPosition && m_pCurrPosition ); + + float *pDst = m_pCurrPosition; + *pDst++ = *v++; + *pDst++ = *v++; + *pDst = *v; +} + + +//----------------------------------------------------------------------------- +// Normal setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Normal3f( float nx, float ny, float nz ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( m_pNormal ); + Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) ); + Assert( nx >= -1.05f && nx <= 1.05f ); + Assert( ny >= -1.05f && ny <= 1.05f ); + Assert( nz >= -1.05f && nz <= 1.05f ); + + float *pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; +} + +inline void CVertexBuilder::Normal3fv( const float *n ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( n ); + Assert( m_pNormal && m_pCurrNormal ); + Assert( IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2]) ); + Assert( n[0] >= -1.05f && n[0] <= 1.05f ); + Assert( n[1] >= -1.05f && n[1] <= 1.05f ); + Assert( n[2] >= -1.05f && n[2] <= 1.05f ); + + float *pDst = m_pCurrNormal; + *pDst++ = *n++; + *pDst++ = *n++; + *pDst = *n; +} + +inline void CVertexBuilder::NormalDelta3f( float nx, float ny, float nz ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( m_pNormal ); + Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) ); + + float *pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; +} + +inline void CVertexBuilder::NormalDelta3fv( const float *n ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( n ); + Assert( m_pNormal && m_pCurrNormal ); + Assert( IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2]) ); + + float *pDst = m_pCurrNormal; + *pDst++ = *n++; + *pDst++ = *n++; + *pDst = *n; +} + +//----------------------------------------------------------------------------- +// Templatized normal setting methods which support compressed vertices +//----------------------------------------------------------------------------- +template inline void CVertexBuilder::CompressedNormal3f( float nx, float ny, float nz ) +{ + Assert( T == m_CompressionType ); + Assert( m_pNormal && m_pCurrNormal ); + Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) ); + Assert( nx >= -1.05f && nx <= 1.05f ); + Assert( ny >= -1.05f && ny <= 1.05f ); + Assert( nz >= -1.05f && nz <= 1.05f ); + // FIXME: studiorender is passing in non-unit normals + //float lengthSqd = nx*nx + ny*ny + nz*nz; + //Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f ); + + if ( T == VERTEX_COMPRESSION_ON ) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + PackNormal_SHORT2( nx, ny, nz, (unsigned int *)m_pCurrNormal ); + +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // NOTE: write the normal into the lower 16 bits of a word, clearing the top 16 bits - a userdata4 + // tangent must be written into the upper 16 bits by CompressedUserData() *AFTER* this. +#ifdef _DEBUG + Assert( m_bWrittenUserData == false ); + m_bWrittenNormal = true; +#endif + PackNormal_UBYTE4( nx, ny, nz, (unsigned int *)m_pCurrNormal ); +#endif + } + else + { + float *pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; + } +} + +template inline void CVertexBuilder::CompressedNormal3fv( const float *n ) +{ + Assert( n ); + CompressedNormal3f( n[0], n[1], n[2] ); +} + + +//----------------------------------------------------------------------------- +// Color setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Color3f( float r, float g, float b ) +{ + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | 0xFF000000; +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; +#endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color3fv( const float *rgb ) +{ + Assert(rgb); + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) ); + Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) ); + Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | 0xFF000000; +#else + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; +#endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4f( float r, float g, float b, float a ) +{ + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | (FastFToC(a) << 24); +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); +#endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4fv( const float *rgba ) +{ + Assert(rgba); + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(rgba[0]) && IsFinite(rgba[1]) && IsFinite(rgba[2]) && IsFinite(rgba[3]) ); + Assert( (rgba[0] >= 0.0) && (rgba[1] >= 0.0) && (rgba[2] >= 0.0) && (rgba[3] >= 0.0) ); + Assert( (rgba[0] <= 1.0) && (rgba[1] <= 1.0) && (rgba[2] <= 1.0) && (rgba[3] <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgba[0])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[2]) << 16) | (FastFToC(rgba[3]) << 24); +#else + int col = (FastFToC(rgba[2])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[0]) << 16) | (FastFToC(rgba[3]) << 24); +#endif + *(int*)m_pCurrColor = col; +} + + +//----------------------------------------------------------------------------- +// Faster versions of color +//----------------------------------------------------------------------------- + +// note that on the OSX target (OpenGL) whenever there is vertex data being written as bytes - they need to be written in R,G,B,A memory order + +inline void CVertexBuilder::Color3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | 0xFF000000; + #endif + + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color3ubv( unsigned char const* rgb ) +{ + Assert(rgb); + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16) | 0xFF000000; + #endif + + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | (a << 24); + #endif + + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4ubv( unsigned char const* rgba ) +{ + Assert( rgba ); + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = rgba[0] | (rgba[1] << 8) | (rgba[2] << 16) | (rgba[3] << 24); // r, g, b, a in memory + #else + int col = rgba[2] | (rgba[1] << 8) | (rgba[0] << 16) | (rgba[3] << 24); + #endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Specular3f( float r, float g, float b ) +{ + Assert( m_pSpecular ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | 0xFF000000; +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3fv( const float *rgb ) +{ + Assert(rgb); + Assert( m_pSpecular ); + Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) ); + Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) ); + Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | 0xFF000000; +#else + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4f( float r, float g, float b, float a ) +{ + Assert( m_pSpecular ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0f) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | (FastFToC(a) << 24); +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4fv( const float *rgb ) +{ + Assert(rgb); + Assert( m_pSpecular ); + Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) && IsFinite(rgb[3]) ); + Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) && (rgb[3] >= 0.0) ); + Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) && (rgb[3] <= 1.0) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | (FastFToC(rgb[3]) << 24); +#else + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | (FastFToC(rgb[3]) << 24); +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | 0xFF000000; + #endif + + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3ubv( unsigned char const *c ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = c[0] | (c[1] << 8) | (c[2] << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = c[2] | (c[1] << 8) | (c[0] << 16) | 0xFF000000; + #endif + + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | (a << 24); + #endif + + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4ubv( unsigned char const *c ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); + #else + int col = c[2] | (c[1] << 8) | (c[0] << 16) | (c[3] << 24); + #endif + + *(int*)pSpecular = col; +} + + +//----------------------------------------------------------------------------- +// Texture coordinate setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::TexCoord1f( int nStage, float s ) +{ + Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] ); + Assert( IsFinite(s) ); + + float *pDst = m_pCurrTexCoord[nStage]; + *pDst = s; +} + +inline void CVertexBuilder::TexCoord2f( int nStage, float s, float t ) +{ + Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] ); + Assert( IsFinite(s) && IsFinite(t) ); + + float *pDst = m_pCurrTexCoord[nStage]; + *pDst++ = s; + *pDst = t; +} + +inline void CVertexBuilder::TexCoord2fv( int nStage, const float *st ) +{ + Assert(st); + Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] ); + Assert( IsFinite(st[0]) && IsFinite(st[1]) ); + + float *pDst = m_pCurrTexCoord[nStage]; + *pDst++ = *st++; + *pDst = *st; +} + +inline void CVertexBuilder::TexCoord3f( int stage, float s, float t, float u ) +{ + // Tried to add too much! + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) ); + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = s; + *pDst++ = t; + *pDst = u; +} + +inline void CVertexBuilder::TexCoord3fv( int stage, const float *stu ) +{ + Assert(stu); + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(stu[0]) && IsFinite(stu[1]) && IsFinite(stu[2]) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = *stu++; + *pDst++ = *stu++; + *pDst = *stu; +} + +inline void CVertexBuilder::TexCoord4f( int stage, float s, float t, float u, float v ) +{ + // Tried to add too much! + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) ); + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = s; + *pDst++ = t; + *pDst++ = u; + *pDst = v; +} + +inline void CVertexBuilder::TexCoord4fv( int stage, const float *stuv ) +{ + Assert(stuv); + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(stuv[0]) && IsFinite(stuv[1]) && IsFinite(stuv[2]) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = *stuv++; + *pDst++ = *stuv++; + *pDst++ = *stuv++; + *pDst = *stuv; +} + + +inline void CVertexBuilder::TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ) +{ + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(s) && IsFinite(t) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = ( s * scaleS ) + offsetS; + *pDst = ( t * scaleT ) + offsetT; +} + +inline void CVertexBuilder::TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale ) +{ + Assert(st); + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(st[0]) && IsFinite(st[1]) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = ( *st++ * *scale++ ) + *offset++; + *pDst = ( *st * *scale ) + *offset; +} + + +//----------------------------------------------------------------------------- +// Tangent space setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::TangentS3f( float sx, float sy, float sz ) +{ + Assert( m_pTangentS ); + Assert( IsFinite(sx) && IsFinite(sy) && IsFinite(sz) ); + + float* pTangentS = OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS ); + *pTangentS++ = sx; + *pTangentS++ = sy; + *pTangentS = sz; +} + +inline void CVertexBuilder::TangentS3fv( const float* s ) +{ + Assert( s ); + Assert( m_pTangentS ); + Assert( IsFinite(s[0]) && IsFinite(s[1]) && IsFinite(s[2]) ); + + float* pTangentS = OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS ); + *pTangentS++ = *s++; + *pTangentS++ = *s++; + *pTangentS = *s; +} + +inline void CVertexBuilder::TangentT3f( float tx, float ty, float tz ) +{ + Assert( m_pTangentT ); + Assert( IsFinite(tx) && IsFinite(ty) && IsFinite(tz) ); + + float* pTangentT = OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT ); + *pTangentT++ = tx; + *pTangentT++ = ty; + *pTangentT = tz; +} + +inline void CVertexBuilder::TangentT3fv( const float* t ) +{ + Assert( t ); + Assert( m_pTangentT ); + Assert( IsFinite(t[0]) && IsFinite(t[1]) && IsFinite(t[2]) ); + + float* pTangentT = OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT ); + *pTangentT++ = *t++; + *pTangentT++ = *t++; + *pTangentT = *t; +} + + +//----------------------------------------------------------------------------- +// Wrinkle setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Wrinkle1f( float flWrinkle ) +{ + Assert( m_pWrinkle ); + Assert( IsFinite(flWrinkle) ); + + float *pWrinkle = OffsetFloatPointer( m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle ); + *pWrinkle = flWrinkle; +} + + +//----------------------------------------------------------------------------- +// Bone weight setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::BoneWeight( int idx, float weight ) +{ + Assert( m_pBoneWeight ); + Assert( IsFinite( weight ) ); + Assert( idx >= 0 ); + AssertOnce( m_NumBoneWeights == 2 ); + + // This test is here because we store N-1 bone weights (the Nth is computed in + // the vertex shader as "1 - C", where C is the sum of the (N-1) other weights) + if ( idx < m_NumBoneWeights ) + { + float* pBoneWeight = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight ); + pBoneWeight[idx] = weight; + } +} + +static int sg_IndexSwap[4] = { 2, 1, 0, 3 }; + +inline void CVertexBuilder::BoneMatrix( int idx, int matrixIdx ) +{ + Assert( m_pBoneMatrixIndex ); + Assert( idx >= 0 ); + Assert( idx < 4 ); + + // garymcthack + if ( matrixIdx == BONE_MATRIX_INDEX_INVALID ) + { + matrixIdx = 0; + } + Assert( (matrixIdx >= 0) && (matrixIdx < 53) ); + +#ifdef OPENGL_SWAP_COLORS + idx = sg_IndexSwap[idx]; +#endif + +#ifndef NEW_SKINNING + unsigned char* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + if ( IsX360() ) + { + // store sequentially as wzyx order, gpu delivers as xyzw + idx = 3-idx; + } + pBoneMatrix[idx] = (unsigned char)matrixIdx; +#else + float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + pBoneMatrix[idx] = matrixIdx; +#endif +} + +//----------------------------------------------------------------------------- +// Templatized bone weight setting methods which support compressed vertices +//----------------------------------------------------------------------------- +template inline void CVertexBuilder::CompressedBoneWeight3fv( const float * pWeights ) +{ + Assert( T == m_CompressionType ); + Assert( m_pBoneWeight ); + Assert( pWeights ); + + float *pDestWeights = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight ); + + if ( T == VERTEX_COMPRESSION_ON ) + { + // Quantize to 15 bits per weight (we use D3DDECLTYPE_SHORT2) + // NOTE: we perform careful normalization (weights sum to 1.0f in the vertex shader), so + // as to avoid cracking at boundaries between meshes with different numbers of weights + // per vertex. For example, (1) needs to yield the same normalized weights as (1,0), + // and (0.5,0.49) needs to normalize the same normalized weights as (0.5,0.49,0). + // The key is that values which are *computed* in the shader (e.g. the second weight + // in a 2-weight mesh) must exactly equal values which are *read* from the vertex + // stream (e.g. the second weight in a 3-weight mesh). + + // Only 1 or 2 weights (SHORT2N) supported for compressed verts so far + Assert( m_NumBoneWeights <= 2 ); + + const int WEIGHT0_SHIFT = IsX360() ? 16 : 0; + const int WEIGHT1_SHIFT = IsX360() ? 0 : 16; + unsigned int *weights = (unsigned int *)pDestWeights; + + // We scale our weights so that they sum to 32768, then subtract 1 (which gets added + // back in the shader), because dividing by 32767 introduces nasty rounding issues. + Assert( IsFinite( pWeights[0] ) && ( pWeights[0] >= 0.0f ) && ( pWeights[0] <= 1.0f ) ); + unsigned int weight0 = Float2Int( pWeights[0] * 32768.0f ); + *weights = ( 0x0000FFFF & (weight0 - 1) ) << WEIGHT0_SHIFT; + +#ifdef DEBUG + if ( m_NumBoneWeights == 1 ) + { + // Double-check the validity of the values that were passed in + Assert( IsFinite( pWeights[1] ) && ( pWeights[1] >= 0.0f ) && ( pWeights[1] <= 1.0f ) ); + unsigned int weight1 = Float2Int( pWeights[1] * 32768.0f ); + Assert( ( weight0 + weight1 ) <= 32768 ); + } +#endif + + if ( m_NumBoneWeights > 1 ) + { + // This path for 3 weights per vert (2 are stored and the 3rd is computed + // in the shader - we do post-quantization normalization here in such a + // way as to avoid mesh-boundary cracking) + Assert( m_NumBoneWeights == 2 ); + Assert( IsFinite( pWeights[1] ) && ( pWeights[1] >= 0.0f ) && ( pWeights[1] <= 1.0f ) ); + Assert( IsFinite( pWeights[2] ) && ( pWeights[2] >= 0.0f ) && ( pWeights[2] <= 1.0f ) ); + unsigned int weight1 = Float2Int( pWeights[1] * 32768.0f ); + unsigned int weight2 = Float2Int( pWeights[2] * 32768.0f ); + Assert( ( weight0 + weight1 + weight2 ) <= 32768 ); + unsigned int residual = 32768 - ( weight0 + weight1 + weight2 ); + weight1 += residual; // Normalize + *weights |= ( 0x0000FFFF & ( weight1 - 1 ) ) << WEIGHT1_SHIFT; + } + } + else // Uncompressed path + { + pDestWeights[0] = pWeights[0]; + pDestWeights[1] = pWeights[1]; + } +} + +//----------------------------------------------------------------------------- +// Generic per-vertex data setting method +//----------------------------------------------------------------------------- +inline void CVertexBuilder::UserData( const float* pData ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( pData ); + + int userDataSize = 4; // garymcthack + float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData ); + memcpy( pUserData, pData, sizeof( float ) * userDataSize ); +} + +//----------------------------------------------------------------------------- +// Templatized generic per-vertex data setting method which supports compressed vertices +//----------------------------------------------------------------------------- +template inline void CVertexBuilder::CompressedUserData( const float* pData ) +{ + Assert( T == m_CompressionType ); + Assert( pData ); + // This is always in fact a tangent vector, not generic 'userdata' + Assert( IsFinite(pData[0]) && IsFinite(pData[1]) && IsFinite(pData[2]) ); + Assert( pData[0] >= -1.05f && pData[0] <= 1.05f ); + Assert( pData[1] >= -1.05f && pData[1] <= 1.05f ); + Assert( pData[2] >= -1.05f && pData[2] <= 1.05f ); + Assert( pData[3] == +1.0f || pData[3] == -1.0f ); + // FIXME: studiorender is passing in non-unit normals + //float lengthSqd = pData[0]*pData[0] + pData[1]*pData[1] + pData[2]*pData[2]; + //Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f ); + + if ( T == VERTEX_COMPRESSION_ON ) + { + float binormalSign = pData[3]; + +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData ); + PackNormal_SHORT2( pData, (unsigned int *)pUserData, binormalSign ); +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // FIXME: add a combined CompressedNormalAndTangent() accessor, to avoid reading back from write-combined memory here + // The normal should have already been written into the lower 16 + // bits - here, we OR in the tangent into the upper 16 bits + unsigned int existingNormalData = *(unsigned int *)m_pCurrNormal; + Assert( ( existingNormalData & 0xFFFF0000 ) == 0 ); +#ifdef _DEBUG + Assert( m_bWrittenNormal == true ); + m_bWrittenUserData = true; +#endif + bool bIsTangent = true; + unsigned int tangentData = 0; + PackNormal_UBYTE4( pData, &tangentData, bIsTangent, binormalSign ); + *(unsigned int *)m_pCurrNormal = existingNormalData | tangentData; +#endif + } + else + { + int userDataSize = 4; // garymcthack + float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData ); + memcpy( pUserData, pData, sizeof( float ) * userDataSize ); + } +} + + +//----------------------------------------------------------------------------- +// +// Helper class used to define index buffers +// +//----------------------------------------------------------------------------- +class CIndexBuilder : private IndexDesc_t +{ +public: + CIndexBuilder(); + CIndexBuilder( IIndexBuffer *pIndexBuffer, MaterialIndexFormat_t fmt = MATERIAL_INDEX_FORMAT_UNKNOWN ); + ~CIndexBuilder(); + + // Begins, ends modification of the index buffer (returns true if the lock succeeded) + // A lock may not succeed if append is set to true and there isn't enough room + // NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers + bool Lock( int nMaxIndexCount, int nIndexOffset, bool bAppend = false ); + void Unlock(); + + // Spews the current data + // NOTE: Can only be called during a lock/unlock block + void SpewData(); + + // Returns the number of indices we can fit into the buffer without needing to discard + int GetRoomRemaining() const; + + // Binds this index buffer + void Bind( IMatRenderContext *pContext ); + + // Returns the byte offset + int Offset() const; + + // Begins, ends modification of the index buffer + // NOTE: IndexOffset is the number to add to all indices written into the buffer; + // useful when using dynamic vertex buffers. + void Begin( IIndexBuffer *pIndexBuffer, int nMaxIndexCount, int nIndexOffset = 0 ); + void End( bool bSpewData = false ); + + // Locks the index buffer to modify existing data + // Passing nVertexCount == -1 says to lock all the vertices for modification. + // Pass 0 for nIndexCount to not lock the index buffer. + void BeginModify( IIndexBuffer *pIndexBuffer, int nFirstIndex = 0, int nIndexCount = 0, int nIndexOffset = 0 ); + void EndModify( bool bSpewData = false ); + + // returns the number of indices + int IndexCount() const; + + // Returns the total number of indices across all Locks() + int TotalIndexCount() const; + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + // Selects the nth Index + void SelectIndex( int nBufferIndex ); + + // Advances the current index by one + void AdvanceIndex(); + void AdvanceIndices( int nIndexCount ); + + int GetCurrentIndex(); + int GetFirstIndex() const; + + unsigned short const* Index() const; + + // Used to define the indices (only used if you aren't using primitives) + void Index( unsigned short nIndex ); + + // Fast Index! No need to call advance index, and no random access allowed + void FastIndex( unsigned short nIndex ); + + // NOTE: This version is the one you really want to achieve write-combining; + // Write combining only works if you write in 4 bytes chunks. + void FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ); + + // Generates indices for a particular primitive type + void GenerateIndices( MaterialPrimitiveType_t primitiveType, int nIndexCount ); + + // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. + void AttachBegin( IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t &desc ); + void AttachEnd(); + void AttachBeginModify( IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t &desc ); + void AttachEndModify(); + + void FastTriangle( int startVert ); + void FastQuad( int startVert ); + void FastPolygon( int startVert, int numTriangles ); + void FastPolygonList( int startVert, int *pVertexCount, int polygonCount ); + void FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount ); + +private: + // The mesh we're modifying + IIndexBuffer *m_pIndexBuffer; + + // Max number of indices + int m_nMaxIndexCount; + + // Number of indices + int m_nIndexCount; + + // Offset to add to each index as it's written into the buffer + int m_nIndexOffset; + + // The current index + mutable int m_nCurrentIndex; + + // Total number of indices appended + int m_nTotalIndexCount; + + // First index buffer offset + first index + unsigned int m_nBufferOffset; + unsigned int m_nBufferFirstIndex; + + // Used to make sure Begin/End calls and BeginModify/EndModify calls match. + bool m_bModify; +}; + + +//----------------------------------------------------------------------------- +// +// Inline methods related to CIndexBuilder +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +inline CIndexBuilder::CIndexBuilder() : m_pIndexBuffer(0), m_nIndexCount(0), + m_nCurrentIndex(0), m_nMaxIndexCount(0) +{ + m_nTotalIndexCount = 0; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstIndex = 0; +#ifdef _DEBUG + m_bModify = false; +#endif +} + +inline CIndexBuilder::CIndexBuilder( IIndexBuffer *pIndexBuffer, MaterialIndexFormat_t fmt ) +{ + m_pIndexBuffer = pIndexBuffer; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstIndex = 0; + m_nIndexCount = 0; + m_nCurrentIndex = 0; + m_nMaxIndexCount = 0; + m_nTotalIndexCount = 0; + if ( m_pIndexBuffer->IsDynamic() ) + { + m_pIndexBuffer->BeginCastBuffer( fmt ); + } + else + { + Assert( m_pIndexBuffer->IndexFormat() == fmt ); + } +#ifdef _DEBUG + m_bModify = false; +#endif +} + +inline CIndexBuilder::~CIndexBuilder() +{ + if ( m_pIndexBuffer && m_pIndexBuffer->IsDynamic() ) + { + m_pIndexBuffer->EndCastBuffer(); + } +} + + +//----------------------------------------------------------------------------- +// Begins, ends modification of the index buffer +//----------------------------------------------------------------------------- +inline bool CIndexBuilder::Lock( int nMaxIndexCount, int nIndexOffset, bool bAppend ) +{ + Assert( m_pIndexBuffer ); + m_bModify = false; + m_nIndexOffset = nIndexOffset; + m_nMaxIndexCount = nMaxIndexCount; + bool bFirstLock = ( m_nBufferOffset == INVALID_BUFFER_OFFSET ); + if ( bFirstLock ) + { + bAppend = false; + } + if ( !bAppend ) + { + m_nTotalIndexCount = 0; + } + Reset(); + + // Lock the index buffer + if ( !m_pIndexBuffer->Lock( m_nMaxIndexCount, bAppend, *this ) ) + { + m_nMaxIndexCount = 0; + return false; + } + + if ( bFirstLock ) + { + m_nBufferOffset = m_nOffset; + m_nBufferFirstIndex = m_nFirstIndex; + } + + return true; +} + +inline void CIndexBuilder::Unlock() +{ + Assert( !m_bModify && m_pIndexBuffer ); + + m_pIndexBuffer->Unlock( m_nIndexCount, *this ); + m_nTotalIndexCount += m_nIndexCount; + + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + +inline void CIndexBuilder::SpewData() +{ + m_pIndexBuffer->Spew( m_nIndexCount, *this ); +} + + +//----------------------------------------------------------------------------- +// Binds this index buffer +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Bind( IMatRenderContext *pContext ) +{ + if ( m_pIndexBuffer && ( m_nBufferOffset != INVALID_BUFFER_OFFSET ) ) + { + pContext->BindIndexBuffer( m_pIndexBuffer, m_nBufferOffset ); + } + else + { + pContext->BindIndexBuffer( NULL, 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Returns the byte offset +//----------------------------------------------------------------------------- +inline int CIndexBuilder::Offset() const +{ + return m_nBufferOffset; +} + +inline int CIndexBuilder::GetFirstIndex() const +{ + return m_nBufferFirstIndex; +} + + +//----------------------------------------------------------------------------- +// Begins, ends modification of the index buffer +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Begin( IIndexBuffer *pIndexBuffer, int nMaxIndexCount, int nIndexOffset ) +{ + Assert( pIndexBuffer && (!m_pIndexBuffer) ); + + m_pIndexBuffer = pIndexBuffer; + m_nIndexCount = 0; + m_nMaxIndexCount = nMaxIndexCount; + m_nIndexOffset = nIndexOffset; + + m_bModify = false; + + // Lock the index buffer + m_pIndexBuffer->Lock( m_nMaxIndexCount, false, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::End( bool bSpewData ) +{ + // Make sure they called Begin() + Assert( !m_bModify ); + + if ( bSpewData ) + { + m_pIndexBuffer->Spew( m_nIndexCount, *this ); + } + + // Unlock our buffers + m_pIndexBuffer->Unlock( m_nIndexCount, *this ); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Begins, ends modification of an existing index buffer which has already been filled out +//----------------------------------------------------------------------------- +inline void CIndexBuilder::BeginModify( IIndexBuffer* pIndexBuffer, int nFirstIndex, int nIndexCount, int nIndexOffset ) +{ + m_pIndexBuffer = pIndexBuffer; + m_nIndexCount = nIndexCount; + m_nMaxIndexCount = nIndexCount; + m_nIndexOffset = nIndexOffset; + m_bModify = true; + + // Lock the vertex and index buffer + m_pIndexBuffer->ModifyBegin( false, nFirstIndex, nIndexCount, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::EndModify( bool bSpewData ) +{ + Assert( m_pIndexBuffer ); + Assert( m_bModify ); // Make sure they called BeginModify. + + if ( bSpewData ) + { + m_pIndexBuffer->Spew( m_nIndexCount, *this ); + } + + // Unlock our buffers + m_pIndexBuffer->ModifyEnd( *this ); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. +//----------------------------------------------------------------------------- +inline void CIndexBuilder::AttachBegin( IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t &desc ) +{ + m_pIndexBuffer = pMesh; + m_nIndexCount = 0; + m_nMaxIndexCount = nMaxIndexCount; + + m_bModify = false; + + // Copy relevant data from the mesh desc + m_nIndexOffset = desc.m_nFirstVertex; + m_pIndices = desc.m_pIndices; + m_nIndexSize = desc.m_nIndexSize; + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::AttachEnd() +{ + Assert( m_pIndexBuffer ); + Assert( !m_bModify ); // Make sure they called AttachBegin. + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + +inline void CIndexBuilder::AttachBeginModify( IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t &desc ) +{ + m_pIndexBuffer = pMesh; + m_nIndexCount = nIndexCount; + m_nMaxIndexCount = nIndexCount; + m_bModify = true; + + // Copy relevant data from the mesh desc + m_nIndexOffset = desc.m_nFirstVertex; + m_pIndices = desc.m_pIndices; + m_nIndexSize = desc.m_nIndexSize; + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::AttachEndModify() +{ + Assert( m_pIndexBuffer ); + Assert( m_bModify ); // Make sure they called AttachBeginModify. + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Resets the index buffer builder so it points to the start of everything again +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Reset() +{ + m_nCurrentIndex = 0; +} + + +//----------------------------------------------------------------------------- +// returns the number of indices +//----------------------------------------------------------------------------- +inline int CIndexBuilder::IndexCount() const +{ + return m_nIndexCount; +} + + +//----------------------------------------------------------------------------- +// Returns the total number of indices across all Locks() +//----------------------------------------------------------------------------- +inline int CIndexBuilder::TotalIndexCount() const +{ + return m_nTotalIndexCount; +} + + +//----------------------------------------------------------------------------- +// Advances the current index +//----------------------------------------------------------------------------- +inline void CIndexBuilder::AdvanceIndex() +{ + m_nCurrentIndex += m_nIndexSize; + if ( m_nCurrentIndex > m_nIndexCount ) + { + m_nIndexCount = m_nCurrentIndex; + } +} + +inline void CIndexBuilder::AdvanceIndices( int nIndices ) +{ + m_nCurrentIndex += nIndices * m_nIndexSize; + if ( m_nCurrentIndex > m_nIndexCount ) + { + m_nIndexCount = m_nCurrentIndex; + } +} + + +//----------------------------------------------------------------------------- +// Returns the current index +//----------------------------------------------------------------------------- +inline int CIndexBuilder::GetCurrentIndex() +{ + return m_nCurrentIndex; +} + +inline unsigned short const* CIndexBuilder::Index() const +{ + Assert( m_nCurrentIndex < m_nMaxIndexCount ); + return &m_pIndices[m_nCurrentIndex]; +} + +inline void CIndexBuilder::SelectIndex( int nIndex ) +{ + Assert( ( nIndex >= 0 ) && ( nIndex < m_nIndexCount ) ); + m_nCurrentIndex = nIndex * m_nIndexSize; +} + + +//----------------------------------------------------------------------------- +// Used to write data into the index buffer +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Index( unsigned short nIndex ) +{ + Assert( m_pIndices ); + Assert( m_nCurrentIndex < m_nMaxIndexCount ); + m_pIndices[ m_nCurrentIndex ] = (unsigned short)( m_nIndexOffset + nIndex ); +} + +// Fast Index! No need to call advance index +inline void CIndexBuilder::FastIndex( unsigned short nIndex ) +{ + Assert( m_pIndices ); + Assert( m_nCurrentIndex < m_nMaxIndexCount ); + m_pIndices[m_nCurrentIndex] = (unsigned short)( m_nIndexOffset + nIndex ); + m_nCurrentIndex += m_nIndexSize; + m_nIndexCount = m_nCurrentIndex; +} + +inline void CIndexBuilder::FastTriangle( int startVert ) +{ + startVert += m_nIndexOffset; + m_pIndices[m_nCurrentIndex+0] = startVert; + m_pIndices[m_nCurrentIndex+1] = startVert + 1; + m_pIndices[m_nCurrentIndex+2] = startVert + 2; + + AdvanceIndices(3); +} + +inline void CIndexBuilder::FastQuad( int startVert ) +{ + startVert += m_nIndexOffset; + m_pIndices[m_nCurrentIndex+0] = startVert; + m_pIndices[m_nCurrentIndex+1] = startVert + 1; + m_pIndices[m_nCurrentIndex+2] = startVert + 2; + m_pIndices[m_nCurrentIndex+3] = startVert; + m_pIndices[m_nCurrentIndex+4] = startVert + 2; + m_pIndices[m_nCurrentIndex+5] = startVert + 3; + AdvanceIndices(6); +} + +inline void CIndexBuilder::FastPolygon( int startVert, int triangleCount ) +{ + unsigned short *pIndex = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + if ( !IsX360() ) + { + // NOTE: IndexSize is 1 or 0 (0 for alt-tab) + // This prevents us from writing into bogus memory + Assert( m_nIndexSize == 0 || m_nIndexSize == 1 ); + triangleCount *= m_nIndexSize; + } + for ( int v = 0; v < triangleCount; ++v ) + { + *pIndex++ = startVert; + *pIndex++ = startVert + v + 1; + *pIndex++ = startVert + v + 2; + } + AdvanceIndices(triangleCount*3); +} + +inline void CIndexBuilder::FastPolygonList( int startVert, int *pVertexCount, int polygonCount ) +{ + unsigned short *pIndex = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + int indexOut = 0; + + if ( !IsX360() ) + { + // NOTE: IndexSize is 1 or 0 (0 for alt-tab) + // This prevents us from writing into bogus memory + Assert( m_nIndexSize == 0 || m_nIndexSize == 1 ); + polygonCount *= m_nIndexSize; + } + + for ( int i = 0; i < polygonCount; i++ ) + { + int vertexCount = pVertexCount[i]; + int triangleCount = vertexCount-2; + for ( int v = 0; v < triangleCount; ++v ) + { + *pIndex++ = startVert; + *pIndex++ = startVert + v + 1; + *pIndex++ = startVert + v + 2; + } + startVert += vertexCount; + indexOut += triangleCount * 3; + } + AdvanceIndices(indexOut); +} + +inline void CIndexBuilder::FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount ) +{ + unsigned short *pIndexOut = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + if ( !IsX360() ) + { + // NOTE: IndexSize is 1 or 0 (0 for alt-tab) + // This prevents us from writing into bogus memory + Assert( m_nIndexSize == 0 || m_nIndexSize == 1 ); + indexCount *= m_nIndexSize; + } + for ( int i = 0; i < indexCount; ++i ) + { + pIndexOut[i] = startVert + pIndexList[i]; + } + AdvanceIndices(indexCount); +} + + +//----------------------------------------------------------------------------- +// NOTE: This version is the one you really want to achieve write-combining; +// Write combining only works if you write in 4 bytes chunks. +//----------------------------------------------------------------------------- +inline void CIndexBuilder::FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ) +{ + Assert( m_pIndices ); + Assert( m_nCurrentIndex < m_nMaxIndexCount - 1 ); +// Assert( ( (int)( &m_pIndices[m_nCurrentIndex] ) & 0x3 ) == 0 ); + +#ifndef _X360 + unsigned int nIndices = ( (unsigned int)nIndex1 + m_nIndexOffset ) | ( ( (unsigned int)nIndex2 + m_nIndexOffset ) << 16 ); +#else + unsigned int nIndices = ( (unsigned int)nIndex2 + m_nIndexOffset ) | ( ( (unsigned int)nIndex1 + m_nIndexOffset ) << 16 ); +#endif + + *(int*)( &m_pIndices[m_nCurrentIndex] ) = nIndices; + m_nCurrentIndex += m_nIndexSize + m_nIndexSize; + m_nIndexCount = m_nCurrentIndex; +} + + +//----------------------------------------------------------------------------- +// Generates indices for a particular primitive type +//----------------------------------------------------------------------------- +inline void CIndexBuilder::GenerateIndices( MaterialPrimitiveType_t primitiveType, int nIndexCount ) +{ + // FIXME: How to make this work with short vs int sized indices? + // Don't generate indices if we've got an empty buffer + if ( m_nIndexSize == 0 ) + return; + + int nMaxIndices = m_nMaxIndexCount - m_nCurrentIndex; + nIndexCount = Min( nMaxIndices, nIndexCount ); + if ( nIndexCount == 0 ) + return; + + unsigned short *pIndices = &m_pIndices[m_nCurrentIndex]; + + switch( primitiveType ) + { + case MATERIAL_INSTANCED_QUADS: + Assert(0); // Shouldn't get here (this primtype is unindexed) + break; + case MATERIAL_QUADS: + GenerateQuadIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_POLYGON: + GeneratePolygonIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_LINE_STRIP: + GenerateLineStripIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_LINE_LOOP: + GenerateLineLoopIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_POINTS: + Assert(0); // Shouldn't get here (this primtype is unindexed) + break; + default: + GenerateSequentialIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + } + + AdvanceIndices( nIndexCount ); +} + + +//----------------------------------------------------------------------------- +// +// Helper class used to define meshes +// +//----------------------------------------------------------------------------- +//class CMeshBuilder : private MeshDesc_t +// hack fixme +class CMeshBuilder : public MeshDesc_t +{ +public: + CMeshBuilder(); + ~CMeshBuilder() { Assert(!m_pMesh); } // if this fires you did a Begin() without an End() + + operator CIndexBuilder&() { return m_IndexBuilder; } + + // This must be called before Begin, if a vertex buffer with a compressed format is to be used + void SetCompressionType( VertexCompressionType_t compressionType ); + + // Locks the vertex buffer + // (*cannot* use the Index() call below) + void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int numPrimitives ); + + // Locks the vertex buffer, can specify arbitrary index lists + // (must use the Index() call below) + void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ); + void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ); + + // forward compat + void Begin( IVertexBuffer *pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives ); + void Begin( IVertexBuffer *pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ); + void Begin( IVertexBuffer *pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ); + + // Use this when you're done writing + // Set bDraw to true to call m_pMesh->Draw automatically. + void End( bool bSpewData = false, bool bDraw = false ); + + // Locks the vertex buffer to modify existing data + // Passing nVertexCount == -1 says to lock all the vertices for modification. + // Pass 0 for nIndexCount to not lock the index buffer. + void BeginModify( IMesh *pMesh, int nFirstVertex = 0, int nVertexCount = -1, int nFirstIndex = 0, int nIndexCount = 0 ); + void EndModify( bool bSpewData = false ); + + // A helper method since this seems to be done a whole bunch. + void DrawQuad( IMesh* pMesh, const float *v1, const float *v2, + const float *v3, const float *v4, unsigned char const *pColor, bool wireframe = false ); + + // returns the number of indices and vertices + int VertexCount() const; + int IndexCount() const; + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + // Returns the size of the vertex + int VertexSize() { return m_ActualVertexSize; } + + // returns the data size of a given texture coordinate + int TextureCoordinateSize( int nTexCoordNumber ) { return m_VertexSize_TexCoord[ nTexCoordNumber ]; } + + // Returns the base vertex memory pointer + void* BaseVertexData(); + + // Selects the nth Vertex and Index + void SelectVertex( int idx ); + void SelectIndex( int idx ); + + // Given an index, point to the associated vertex + void SelectVertexFromIndex( int idx ); + + // Advances the current vertex and index by one + void AdvanceVertex(); + template void AdvanceVertexF(); + void AdvanceVertices( int nVerts ); + void AdvanceIndex(); + void AdvanceIndices( int nIndices ); + + int GetCurrentVertex(); + int GetCurrentIndex(); + + // Data retrieval... + const float *Position() const; + + const float *Normal() const; + + unsigned int Color() const; + + unsigned char *Specular() const; + + const float *TexCoord( int stage ) const; + + const float *TangentS() const; + const float *TangentT() const; + + const float *BoneWeight() const; + float Wrinkle() const; + + int NumBoneWeights() const; +#ifndef NEW_SKINNING + unsigned char *BoneMatrix() const; +#else + float *BoneMatrix() const; +#endif + unsigned short const *Index() const; + + // position setting + void Position3f( float x, float y, float z ); + void Position3fv( const float *v ); + + // normal setting + void Normal3f( float nx, float ny, float nz ); + void Normal3fv( const float *n ); + void NormalDelta3fv( const float *n ); + void NormalDelta3f( float nx, float ny, float nz ); + + // normal setting (templatized for code which needs to support compressed vertices) + template void CompressedNormal3f( float nx, float ny, float nz ); + template void CompressedNormal3fv( const float *n ); + + // color setting + void Color3f( float r, float g, float b ); + void Color3fv( const float *rgb ); + void Color4f( float r, float g, float b, float a ); + void Color4fv( const float *rgba ); + + // Faster versions of color + void Color3ub( unsigned char r, unsigned char g, unsigned char b ); + void Color3ubv( unsigned char const* rgb ); + void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Color4ubv( unsigned char const* rgba ); + + // specular color setting + void Specular3f( float r, float g, float b ); + void Specular3fv( const float *rgb ); + void Specular4f( float r, float g, float b, float a ); + void Specular4fv( const float *rgba ); + + // Faster version of specular + void Specular3ub( unsigned char r, unsigned char g, unsigned char b ); + void Specular3ubv( unsigned char const *c ); + void Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Specular4ubv( unsigned char const *c ); + + // texture coordinate setting + void TexCoord1f( int stage, float s ); + void TexCoord2f( int stage, float s, float t ); + void TexCoord2fv( int stage, const float *st ); + void TexCoord3f( int stage, float s, float t, float u ); + void TexCoord3fv( int stage, const float *stu ); + void TexCoord4f( int stage, float s, float t, float u, float w ); + void TexCoord4fv( int stage, const float *stuv ); + + void TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ); + void TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale ); + + // tangent space + void TangentS3f( float sx, float sy, float sz ); + void TangentS3fv( const float *s ); + + void TangentT3f( float tx, float ty, float tz ); + void TangentT3fv( const float *t ); + + // Wrinkle + void Wrinkle1f( float flWrinkle ); + + // bone weights + void BoneWeight( int idx, float weight ); + // bone weights (templatized for code which needs to support compressed vertices) + template void CompressedBoneWeight3fv( const float * pWeights ); + + // bone matrix index + void BoneMatrix( int idx, int matrixIndex ); + + // Generic per-vertex data + void UserData( const float *pData ); + // Generic per-vertex data (templatized for code which needs to support compressed vertices) + template void CompressedUserData( const float* pData ); + + // Used to define the indices (only used if you aren't using primitives) + void Index( unsigned short index ); + + // NOTE: Use this one to get write combining! Much faster than the other version of FastIndex + // Fast Index! No need to call advance index, and no random access allowed + void FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ); + + // Fast Index! No need to call advance index, and no random access allowed + void FastIndex( unsigned short index ); + + // Fast Vertex! No need to call advance vertex, and no random access allowed. + // WARNING - these are low level functions that are intended only for use + // in the software vertex skinner. + void FastVertex( const ModelVertexDX7_t &vertex ); + void FastVertexSSE( const ModelVertexDX7_t &vertex ); + + // store 4 dx7 vertices fast. for special sse dx7 pipeline + void Fast4VerticesSSE( + ModelVertexDX7_t const *vtx_a, + ModelVertexDX7_t const *vtx_b, + ModelVertexDX7_t const *vtx_c, + ModelVertexDX7_t const *vtx_d); + + void FastVertex( const ModelVertexDX8_t &vertex ); + void FastVertexSSE( const ModelVertexDX8_t &vertex ); + + // Add number of verts and current vert since FastVertexxx routines do not update. + void FastAdvanceNVertices(int n); + +#if defined( _X360 ) + void VertexDX8ToX360( const ModelVertexDX8_t &vertex ); +#endif + +private: + // Computes number of verts and indices + void ComputeNumVertsAndIndices( int *pMaxVertices, int *pMaxIndices, + MaterialPrimitiveType_t type, int nPrimitiveCount ); + int IndicesFromVertices( MaterialPrimitiveType_t type, int nVertexCount ); + + // The mesh we're modifying + IMesh *m_pMesh; + + MaterialPrimitiveType_t m_Type; + + // Generate indices? + bool m_bGenerateIndices; + + CIndexBuilder m_IndexBuilder; + CVertexBuilder m_VertexBuilder; +}; + + +//----------------------------------------------------------------------------- +// Forward compat +//----------------------------------------------------------------------------- +inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives ) +{ + Assert( 0 ); + // Begin( pVertexBuffer->GetMesh(), type, numPrimitives ); +} + +inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ) +{ + Assert( 0 ); + // Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount, nFirstVertex ); +} + +inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ) +{ + Assert( 0 ); + // Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +inline CMeshBuilder::CMeshBuilder() : m_pMesh(0), m_bGenerateIndices(false) +{ +} + + +//----------------------------------------------------------------------------- +// Computes the number of verts and indices based on primitive type and count +//----------------------------------------------------------------------------- +inline void CMeshBuilder::ComputeNumVertsAndIndices( int *pMaxVertices, int *pMaxIndices, + MaterialPrimitiveType_t type, int nPrimitiveCount ) +{ + switch(type) + { + case MATERIAL_POINTS: + *pMaxVertices = *pMaxIndices = nPrimitiveCount; + break; + + case MATERIAL_LINES: + *pMaxVertices = *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_LINE_STRIP: + *pMaxVertices = nPrimitiveCount + 1; + *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_LINE_LOOP: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_TRIANGLES: + *pMaxVertices = *pMaxIndices = nPrimitiveCount * 3; + break; + + case MATERIAL_TRIANGLE_STRIP: + *pMaxVertices = *pMaxIndices = nPrimitiveCount + 2; + break; + + case MATERIAL_QUADS: + *pMaxVertices = nPrimitiveCount * 4; + *pMaxIndices = nPrimitiveCount * 6; + break; + + case MATERIAL_INSTANCED_QUADS: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = 0; // This primtype is unindexed + break; + + case MATERIAL_POLYGON: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = (nPrimitiveCount - 2) * 3; + break; + + default: + *pMaxVertices = 0; + *pMaxIndices = 0; + Assert(0); + } + + // FIXME: need to get this from meshdx8.cpp, or move it to somewhere common + Assert( *pMaxVertices <= 32768 ); + Assert( *pMaxIndices <= 32768 ); +} + + +inline int CMeshBuilder::IndicesFromVertices( MaterialPrimitiveType_t type, int nVertexCount ) +{ + switch( type ) + { + case MATERIAL_QUADS: + Assert( (nVertexCount & 0x3) == 0 ); + return (nVertexCount * 6) / 4; + + case MATERIAL_INSTANCED_QUADS: + // This primtype is unindexed + return 0; + + case MATERIAL_POLYGON: + Assert( nVertexCount >= 3 ); + return (nVertexCount - 2) * 3; + + case MATERIAL_LINE_STRIP: + Assert( nVertexCount >= 2 ); + return (nVertexCount - 1) * 2; + + case MATERIAL_LINE_LOOP: + Assert( nVertexCount >= 3 ); + return nVertexCount * 2; + + default: + return nVertexCount; + } +} + +//----------------------------------------------------------------------------- +// Specify the type of vertex compression that this CMeshBuilder will perform +//----------------------------------------------------------------------------- +inline void CMeshBuilder::SetCompressionType( VertexCompressionType_t vertexCompressionType ) +{ + m_VertexBuilder.SetCompressionType( vertexCompressionType ); +} + +//----------------------------------------------------------------------------- +// Begins modifying the mesh +//----------------------------------------------------------------------------- +inline void CMeshBuilder::Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int numPrimitives ) +{ + Assert( pMesh && (!m_pMesh) ); + Assert( type != MATERIAL_HETEROGENOUS ); + + m_pMesh = pMesh; + m_bGenerateIndices = true; + m_Type = type; + + int nMaxVertexCount, nMaxIndexCount; + ComputeNumVertsAndIndices( &nMaxVertexCount, &nMaxIndexCount, type, numPrimitives ); + + switch( type ) + { + case MATERIAL_INSTANCED_QUADS: + m_pMesh->SetPrimitiveType( MATERIAL_INSTANCED_QUADS ); + break; + + case MATERIAL_QUADS: + case MATERIAL_POLYGON: + m_pMesh->SetPrimitiveType( MATERIAL_TRIANGLES ); + break; + + case MATERIAL_LINE_STRIP: + case MATERIAL_LINE_LOOP: + m_pMesh->SetPrimitiveType( MATERIAL_LINES ); + break; + + default: + m_pMesh->SetPrimitiveType( type ); + } + + // Lock the mesh + m_pMesh->LockMesh( nMaxVertexCount, nMaxIndexCount, *this ); + + m_IndexBuilder.AttachBegin( pMesh, nMaxIndexCount, *this ); + m_VertexBuilder.AttachBegin( pMesh, nMaxVertexCount, *this ); + + // Point to the start of the index and vertex buffers + Reset(); +} + +inline void CMeshBuilder::Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ) +{ + Begin( pMesh, type, nVertexCount, nIndexCount ); + + *nFirstVertex = m_VertexBuilder.m_nFirstVertex * m_VertexBuilder.VertexSize(); +} + +inline void CMeshBuilder::Begin( IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ) +{ + Assert( pMesh && (!m_pMesh) ); + + // NOTE: We can't specify the indices when we use quads, polygons, or + // linestrips; they aren't actually directly supported by + // the material system + Assert( (type != MATERIAL_QUADS) && (type != MATERIAL_INSTANCED_QUADS) && (type != MATERIAL_POLYGON) && + (type != MATERIAL_LINE_STRIP) && (type != MATERIAL_LINE_LOOP)); + + // Dx8 doesn't support indexed points... + Assert( type != MATERIAL_POINTS ); + + m_pMesh = pMesh; + m_bGenerateIndices = false; + m_Type = type; + + // Set the primitive type + m_pMesh->SetPrimitiveType( type ); + + // Lock the vertex and index buffer + m_pMesh->LockMesh( nVertexCount, nIndexCount, *this ); + + m_IndexBuilder.AttachBegin( pMesh, nIndexCount, *this ); + m_VertexBuilder.AttachBegin( pMesh, nVertexCount, *this ); + + // Point to the start of the buffers.. + Reset(); +} + + +//----------------------------------------------------------------------------- +// Use this when you're done modifying the mesh +//----------------------------------------------------------------------------- +inline void CMeshBuilder::End( bool bSpewData, bool bDraw ) +{ + if ( m_bGenerateIndices ) + { + int nIndexCount = IndicesFromVertices( m_Type, m_VertexBuilder.VertexCount() ); + m_IndexBuilder.GenerateIndices( m_Type, nIndexCount ); + } + + if ( bSpewData ) + { + m_pMesh->Spew( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); + } + +#ifdef _DEBUG + m_pMesh->ValidateData( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); +#endif + + // Unlock our buffers + m_pMesh->UnlockMesh( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); + + m_IndexBuilder.AttachEnd(); + m_VertexBuilder.AttachEnd(); + + if ( bDraw ) + { + m_pMesh->Draw(); + } + + m_pMesh = 0; + +#ifdef _DEBUG + memset( (MeshDesc_t*)this, 0, sizeof(MeshDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Locks the vertex buffer to modify existing data +//----------------------------------------------------------------------------- +inline void CMeshBuilder::BeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount ) +{ + Assert( pMesh && (!m_pMesh) ); + + if (nVertexCount < 0) + { + nVertexCount = pMesh->VertexCount(); + } + + m_pMesh = pMesh; + m_bGenerateIndices = false; + + // Locks mesh for modifying + pMesh->ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, *this ); + + m_IndexBuilder.AttachBeginModify( pMesh, nFirstIndex, nIndexCount, *this ); + m_VertexBuilder.AttachBeginModify( pMesh, nFirstVertex, nVertexCount, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CMeshBuilder::EndModify( bool bSpewData ) +{ + Assert( m_pMesh ); + + if (bSpewData) + { + m_pMesh->Spew( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); + } +#ifdef _DEBUG + m_pMesh->ValidateData( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); +#endif + + // Unlocks mesh + m_pMesh->ModifyEnd( *this ); + m_pMesh = 0; + + m_IndexBuilder.AttachEndModify(); + m_VertexBuilder.AttachEndModify(); + +#ifdef _DEBUG + // Null out our pointers... + memset( (MeshDesc_t*)this, 0, sizeof(MeshDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Resets the mesh builder so it points to the start of everything again +//----------------------------------------------------------------------------- +inline void CMeshBuilder::Reset() +{ + m_IndexBuilder.Reset(); + m_VertexBuilder.Reset(); +} + + +//----------------------------------------------------------------------------- +// Selects the current Vertex and Index +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::SelectVertex( int nIndex ) +{ + m_VertexBuilder.SelectVertex( nIndex ); +} + +inline void CMeshBuilder::SelectVertexFromIndex( int idx ) +{ + // NOTE: This index is expected to be relative + int vertIdx = idx - m_nFirstVertex; + SelectVertex( vertIdx ); +} + +FORCEINLINE void CMeshBuilder::SelectIndex( int idx ) +{ + m_IndexBuilder.SelectIndex( idx ); +} + + +//----------------------------------------------------------------------------- +// Advances the current vertex and index by one +//----------------------------------------------------------------------------- +template FORCEINLINE void CMeshBuilder::AdvanceVertexF() +{ + m_VertexBuilder.AdvanceVertexF(); +} +FORCEINLINE void CMeshBuilder::AdvanceVertex() +{ + m_VertexBuilder.AdvanceVertex(); +} + +FORCEINLINE void CMeshBuilder::AdvanceVertices( int nVertexCount ) +{ + m_VertexBuilder.AdvanceVertices( nVertexCount ); +} + +FORCEINLINE void CMeshBuilder::AdvanceIndex() +{ + m_IndexBuilder.AdvanceIndex(); +} + +FORCEINLINE void CMeshBuilder::AdvanceIndices( int nIndices ) +{ + m_IndexBuilder.AdvanceIndices( nIndices ); +} + +FORCEINLINE int CMeshBuilder::GetCurrentVertex() +{ + return m_VertexBuilder.GetCurrentVertex(); +} + +FORCEINLINE int CMeshBuilder::GetCurrentIndex() +{ + return m_IndexBuilder.GetCurrentIndex(); +} + + +//----------------------------------------------------------------------------- +// A helper method since this seems to be done a whole bunch. +//----------------------------------------------------------------------------- +inline void CMeshBuilder::DrawQuad( IMesh* pMesh, const float* v1, const float* v2, + const float* v3, const float* v4, unsigned char const* pColor, bool wireframe ) +{ + if (!wireframe) + { + Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 ); + + Position3fv (v1); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v2); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v4); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v3); + Color4ubv( pColor ); + AdvanceVertexF(); + } + else + { + Begin( pMesh, MATERIAL_LINE_LOOP, 4 ); + Position3fv (v1); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v2); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v3); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v4); + Color4ubv( pColor ); + AdvanceVertexF(); + } + + End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// returns the number of indices and vertices +//----------------------------------------------------------------------------- +FORCEINLINE int CMeshBuilder::VertexCount() const +{ + return m_VertexBuilder.VertexCount(); +} + +FORCEINLINE int CMeshBuilder::IndexCount() const +{ + return m_IndexBuilder.IndexCount(); +} + + +//----------------------------------------------------------------------------- +// Returns the base vertex memory pointer +//----------------------------------------------------------------------------- +FORCEINLINE void* CMeshBuilder::BaseVertexData() +{ + return m_VertexBuilder.BaseVertexData(); +} + +//----------------------------------------------------------------------------- +// Data retrieval... +//----------------------------------------------------------------------------- +FORCEINLINE const float* CMeshBuilder::Position() const +{ + return m_VertexBuilder.Position(); +} + +FORCEINLINE const float* CMeshBuilder::Normal() const +{ + return m_VertexBuilder.Normal(); +} + +FORCEINLINE unsigned int CMeshBuilder::Color() const +{ + return m_VertexBuilder.Color(); +} + +FORCEINLINE unsigned char *CMeshBuilder::Specular() const +{ + return m_VertexBuilder.Specular(); +} + +FORCEINLINE const float* CMeshBuilder::TexCoord( int nStage ) const +{ + return m_VertexBuilder.TexCoord( nStage ); +} + +FORCEINLINE const float* CMeshBuilder::TangentS() const +{ + return m_VertexBuilder.TangentS(); +} + +FORCEINLINE const float* CMeshBuilder::TangentT() const +{ + return m_VertexBuilder.TangentT(); +} + +FORCEINLINE float CMeshBuilder::Wrinkle() const +{ + return m_VertexBuilder.Wrinkle(); +} + +FORCEINLINE const float* CMeshBuilder::BoneWeight() const +{ + return m_VertexBuilder.BoneWeight(); +} + +FORCEINLINE int CMeshBuilder::NumBoneWeights() const +{ + return m_VertexBuilder.NumBoneWeights(); +} + +FORCEINLINE unsigned short const* CMeshBuilder::Index() const +{ + return m_IndexBuilder.Index(); +} + + +//----------------------------------------------------------------------------- +// Index +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::Index( unsigned short idx ) +{ + m_IndexBuilder.Index( idx ); +} + + +//----------------------------------------------------------------------------- +// Fast Index! No need to call advance index +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::FastIndex( unsigned short idx ) +{ + m_IndexBuilder.FastIndex( idx ); +} + +// NOTE: Use this one to get write combining! Much faster than the other version of FastIndex +// Fast Index! No need to call advance index, and no random access allowed +FORCEINLINE void CMeshBuilder::FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ) +{ + m_IndexBuilder.FastIndex2( nIndex1, nIndex2 ); +} + +//----------------------------------------------------------------------------- +// For use with the FastVertex methods, advances the current vertex by N +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::FastAdvanceNVertices( int nVertexCount ) +{ + m_VertexBuilder.FastAdvanceNVertices( nVertexCount ); +} + + +//----------------------------------------------------------------------------- +// Fast Vertex! No need to call advance vertex, and no random access allowed +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::FastVertex( const ModelVertexDX7_t &vertex ) +{ + m_VertexBuilder.FastVertex( vertex ); +} + +FORCEINLINE void CMeshBuilder::FastVertexSSE( const ModelVertexDX7_t &vertex ) +{ + m_VertexBuilder.FastVertexSSE( vertex ); +} + +FORCEINLINE void CMeshBuilder::Fast4VerticesSSE( + const ModelVertexDX7_t *vtx_a, const ModelVertexDX7_t *vtx_b, + const ModelVertexDX7_t *vtx_c, const ModelVertexDX7_t *vtx_d ) +{ + m_VertexBuilder.Fast4VerticesSSE( vtx_a, vtx_b, vtx_c, vtx_d ); +} + +FORCEINLINE void CMeshBuilder::FastVertex( const ModelVertexDX8_t &vertex ) +{ + m_VertexBuilder.FastVertex( vertex ); +} + +FORCEINLINE void CMeshBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex ) +{ + m_VertexBuilder.FastVertexSSE( vertex ); +} + +//----------------------------------------------------------------------------- +// Copies a vertex into the x360 format +//----------------------------------------------------------------------------- +#if defined( _X360 ) +inline void CMeshBuilder::VertexDX8ToX360( const ModelVertexDX8_t &vertex ) +{ + m_VertexBuilder.VertexDX8ToX360( vertex ); +} +#endif + +//----------------------------------------------------------------------------- +// Vertex field setting methods +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::Position3f( float x, float y, float z ) +{ + m_VertexBuilder.Position3f( x, y, z ); +} + +FORCEINLINE void CMeshBuilder::Position3fv( const float *v ) +{ + m_VertexBuilder.Position3fv( v ); +} + +FORCEINLINE void CMeshBuilder::Normal3f( float nx, float ny, float nz ) +{ + m_VertexBuilder.Normal3f( nx, ny, nz ); +} + +FORCEINLINE void CMeshBuilder::Normal3fv( const float *n ) +{ + m_VertexBuilder.Normal3fv( n ); +} + +FORCEINLINE void CMeshBuilder::NormalDelta3f( float nx, float ny, float nz ) +{ + m_VertexBuilder.NormalDelta3f( nx, ny, nz ); +} + +FORCEINLINE void CMeshBuilder::NormalDelta3fv( const float *n ) +{ + m_VertexBuilder.NormalDelta3fv( n ); +} + +FORCEINLINE void CMeshBuilder::Color3f( float r, float g, float b ) +{ + m_VertexBuilder.Color3f( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Color3fv( const float *rgb ) +{ + m_VertexBuilder.Color3fv( rgb ); +} + +FORCEINLINE void CMeshBuilder::Color4f( float r, float g, float b, float a ) +{ + m_VertexBuilder.Color4f( r, g ,b, a ); +} + +FORCEINLINE void CMeshBuilder::Color4fv( const float *rgba ) +{ + m_VertexBuilder.Color4fv( rgba ); +} + +FORCEINLINE void CMeshBuilder::Color3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + m_VertexBuilder.Color3ub( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Color3ubv( unsigned char const* rgb ) +{ + m_VertexBuilder.Color3ubv( rgb ); +} + +FORCEINLINE void CMeshBuilder::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + m_VertexBuilder.Color4ub( r, g, b, a ); +} + +FORCEINLINE void CMeshBuilder::Color4ubv( unsigned char const* rgba ) +{ + m_VertexBuilder.Color4ubv( rgba ); +} + +FORCEINLINE void CMeshBuilder::Specular3f( float r, float g, float b ) +{ + m_VertexBuilder.Specular3f( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Specular3fv( const float *rgb ) +{ + m_VertexBuilder.Specular3fv( rgb ); +} + +FORCEINLINE void CMeshBuilder::Specular4f( float r, float g, float b, float a ) +{ + m_VertexBuilder.Specular4f( r, g, b, a ); +} + +FORCEINLINE void CMeshBuilder::Specular4fv( const float *rgba ) +{ + m_VertexBuilder.Specular4fv( rgba ); +} + +FORCEINLINE void CMeshBuilder::Specular3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + m_VertexBuilder.Specular3ub( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Specular3ubv( unsigned char const *c ) +{ + m_VertexBuilder.Specular3ubv( c ); +} + +FORCEINLINE void CMeshBuilder::Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + m_VertexBuilder.Specular4ub( r, g, b, a ); +} + +FORCEINLINE void CMeshBuilder::Specular4ubv( unsigned char const *c ) +{ + m_VertexBuilder.Specular4ubv( c ); +} + +FORCEINLINE void CMeshBuilder::TexCoord1f( int nStage, float s ) +{ + m_VertexBuilder.TexCoord1f( nStage, s ); +} + +FORCEINLINE void CMeshBuilder::TexCoord2f( int nStage, float s, float t ) +{ + m_VertexBuilder.TexCoord2f( nStage, s, t ); +} + +FORCEINLINE void CMeshBuilder::TexCoord2fv( int nStage, const float *st ) +{ + m_VertexBuilder.TexCoord2fv( nStage, st ); +} + +FORCEINLINE void CMeshBuilder::TexCoord3f( int nStage, float s, float t, float u ) +{ + m_VertexBuilder.TexCoord3f( nStage, s, t, u ); +} + +FORCEINLINE void CMeshBuilder::TexCoord3fv( int nStage, const float *stu ) +{ + m_VertexBuilder.TexCoord3fv( nStage, stu ); +} + +FORCEINLINE void CMeshBuilder::TexCoord4f( int nStage, float s, float t, float u, float v ) +{ + m_VertexBuilder.TexCoord4f( nStage, s, t, u, v ); +} + +FORCEINLINE void CMeshBuilder::TexCoord4fv( int nStage, const float *stuv ) +{ + m_VertexBuilder.TexCoord4fv( nStage, stuv ); +} + +FORCEINLINE void CMeshBuilder::TexCoordSubRect2f( int nStage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ) +{ + m_VertexBuilder.TexCoordSubRect2f( nStage, s, t, offsetS, offsetT, scaleS, scaleT ); +} + +FORCEINLINE void CMeshBuilder::TexCoordSubRect2fv( int nStage, const float *st, const float *offset, const float *scale ) +{ + m_VertexBuilder.TexCoordSubRect2fv( nStage, st, offset, scale ); +} + +FORCEINLINE void CMeshBuilder::TangentS3f( float sx, float sy, float sz ) +{ + m_VertexBuilder.TangentS3f( sx, sy, sz ); +} + +FORCEINLINE void CMeshBuilder::TangentS3fv( const float* s ) +{ + m_VertexBuilder.TangentS3fv( s ); +} + +FORCEINLINE void CMeshBuilder::TangentT3f( float tx, float ty, float tz ) +{ + m_VertexBuilder.TangentT3f( tx, ty, tz ); +} + +FORCEINLINE void CMeshBuilder::TangentT3fv( const float* t ) +{ + m_VertexBuilder.TangentT3fv( t ); +} + +FORCEINLINE void CMeshBuilder::Wrinkle1f( float flWrinkle ) +{ + m_VertexBuilder.Wrinkle1f( flWrinkle ); +} + +FORCEINLINE void CMeshBuilder::BoneWeight( int nIndex, float flWeight ) +{ + m_VertexBuilder.BoneWeight( nIndex, flWeight ); +} + +template FORCEINLINE void CMeshBuilder::CompressedBoneWeight3fv( const float * pWeights ) +{ + m_VertexBuilder.CompressedBoneWeight3fv( pWeights ); +} + +FORCEINLINE void CMeshBuilder::BoneMatrix( int nIndex, int nMatrixIdx ) +{ + m_VertexBuilder.BoneMatrix( nIndex, nMatrixIdx ); +} + +FORCEINLINE void CMeshBuilder::UserData( const float* pData ) +{ + m_VertexBuilder.UserData( pData ); +} + +template FORCEINLINE void CMeshBuilder::CompressedUserData( const float* pData ) +{ + m_VertexBuilder.CompressedUserData( pData ); +} + +//----------------------------------------------------------------------------- +// Templatized vertex field setting methods which support compression +//----------------------------------------------------------------------------- + +template FORCEINLINE void CMeshBuilder::CompressedNormal3f( float nx, float ny, float nz ) +{ + m_VertexBuilder.CompressedNormal3f( nx, ny, nz ); +} + +template FORCEINLINE void CMeshBuilder::CompressedNormal3fv( const float *n ) +{ + m_VertexBuilder.CompressedNormal3fv( n ); +} + +#endif // IMESH_H diff --git a/public/materialsystem/imorph.h b/public/materialsystem/imorph.h new file mode 100644 index 0000000..c3bff78 --- /dev/null +++ b/public/materialsystem/imorph.h @@ -0,0 +1,251 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Interface used to construct morph buffers +//============================================================================= + +#ifndef IMORPH_H +#define IMORPH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include +#include "tier0/dbg.h" +#include "materialsystem/imaterial.h" + + +//----------------------------------------------------------------------------- +// Single morph data +//----------------------------------------------------------------------------- +struct MorphVertexInfo_t +{ + int m_nVertexId; // What vertex is this going to affect? + int m_nMorphTargetId; // What morph did it come from? + Vector m_PositionDelta; // Positional morph delta + Vector m_NormalDelta; // Normal morph delta + float m_flWrinkleDelta; // Wrinkle morph delta + float m_flSpeed; + float m_flSide; +}; + + +//----------------------------------------------------------------------------- +// Morph weight data +//----------------------------------------------------------------------------- +enum MorphWeightType_t +{ + MORPH_WEIGHT = 0, + MORPH_WEIGHT_LAGGED, + MORPH_WEIGHT_STEREO, + MORPH_WEIGHT_STEREO_LAGGED, + + MORPH_WEIGHT_COUNT, +}; + +struct MorphWeight_t +{ + float m_pWeight[MORPH_WEIGHT_COUNT]; +}; + + +//----------------------------------------------------------------------------- +// Interface to the morph +//----------------------------------------------------------------------------- +abstract_class IMorph +{ +public: + // Locks the morph, destroys any existing contents + virtual void Lock( float flFloatToFixedScale = 1.0f ) = 0; + + // Adds a morph + virtual void AddMorph( const MorphVertexInfo_t &info ) = 0; + + // Unlocks the morph + virtual void Unlock( ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Morph builders +//----------------------------------------------------------------------------- +class CMorphBuilder +{ +public: + CMorphBuilder(); + ~CMorphBuilder(); + + // Start building the morph + void Begin( IMorph *pMorph, float flFloatToFixedScale = 1.0f ); + + // End building the morph + void End(); + + void PositionDelta3fv( const float *pDelta ); + void PositionDelta3f( float dx, float dy, float dz ); + void PositionDelta3( const Vector &vec ); + + void NormalDelta3fv( const float *pDelta ); + void NormalDelta3f( float dx, float dy, float dz ); + void NormalDelta3( const Vector &vec ); + + void WrinkleDelta1f( float flWrinkle ); + + // Both are 0-1 values indicating which morph target to use (for stereo morph targets) + // and how much to blend between using lagged weights vs actual weights + // Speed: 0 - use lagged, 1 - use actual + void Speed1f( float flSpeed ); + void Side1f( float flSide ); + + void AdvanceMorph( int nSourceVertex, int nMorphTargetId ); + +private: + MorphVertexInfo_t m_Info; + IMorph *m_pMorph; +}; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +inline CMorphBuilder::CMorphBuilder() +{ + m_pMorph = NULL; +} + +inline CMorphBuilder::~CMorphBuilder() +{ + // You forgot to call End()! + Assert( !m_pMorph ); +} + + +//----------------------------------------------------------------------------- +// Start building the morph +//----------------------------------------------------------------------------- +inline void CMorphBuilder::Begin( IMorph *pMorph, float flFloatToFixedScale ) +{ + Assert( pMorph && !m_pMorph ); + m_pMorph = pMorph; + m_pMorph->Lock( flFloatToFixedScale ); + +#ifdef _DEBUG + m_Info.m_PositionDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_NormalDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_flWrinkleDelta = VEC_T_NAN; + m_Info.m_flSpeed = VEC_T_NAN; + m_Info.m_flSide = VEC_T_NAN; +#endif +} + +// End building the morph +inline void CMorphBuilder::End() +{ + Assert( m_pMorph ); + m_pMorph->Unlock(); + m_pMorph = NULL; +} + + +//----------------------------------------------------------------------------- +// Set position delta +//----------------------------------------------------------------------------- +inline void CMorphBuilder::PositionDelta3fv( const float *pDelta ) +{ + Assert( m_pMorph ); + m_Info.m_PositionDelta.Init( pDelta[0], pDelta[1], pDelta[2] ); +} + +inline void CMorphBuilder::PositionDelta3f( float dx, float dy, float dz ) +{ + Assert( m_pMorph ); + m_Info.m_PositionDelta.Init( dx, dy, dz ); +} + +inline void CMorphBuilder::PositionDelta3( const Vector &vec ) +{ + Assert( m_pMorph ); + m_Info.m_PositionDelta = vec; +} + + +//----------------------------------------------------------------------------- +// Set normal delta +//----------------------------------------------------------------------------- +inline void CMorphBuilder::NormalDelta3fv( const float *pDelta ) +{ + Assert( m_pMorph ); + m_Info.m_NormalDelta.Init( pDelta[0], pDelta[1], pDelta[2] ); +} + +inline void CMorphBuilder::NormalDelta3f( float dx, float dy, float dz ) +{ + Assert( m_pMorph ); + m_Info.m_NormalDelta.Init( dx, dy, dz ); +} + +inline void CMorphBuilder::NormalDelta3( const Vector &vec ) +{ + Assert( m_pMorph ); + m_Info.m_NormalDelta = vec; +} + + +//----------------------------------------------------------------------------- +// Set wrinkle delta +//----------------------------------------------------------------------------- +inline void CMorphBuilder::WrinkleDelta1f( float flWrinkle ) +{ + Assert( m_pMorph ); + m_Info.m_flWrinkleDelta = flWrinkle; +} + + +//----------------------------------------------------------------------------- +// Set speed,side data +//----------------------------------------------------------------------------- +inline void CMorphBuilder::Speed1f( float flSpeed ) +{ + Assert( m_pMorph ); + m_Info.m_flSpeed = flSpeed; +} + +inline void CMorphBuilder::Side1f( float flSide ) +{ + Assert( m_pMorph ); + m_Info.m_flSide = flSide; +} + + +//----------------------------------------------------------------------------- +// Advance morph +//----------------------------------------------------------------------------- +inline void CMorphBuilder::AdvanceMorph( int nSourceVertex, int nMorphTargetId ) +{ + Assert( m_pMorph ); + + m_Info.m_nVertexId = nSourceVertex; + m_Info.m_nMorphTargetId = nMorphTargetId; + + m_pMorph->AddMorph( m_Info ); + +#ifdef _DEBUG + m_Info.m_PositionDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_NormalDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_flWrinkleDelta = VEC_T_NAN; + m_Info.m_flSpeed = VEC_T_NAN; + m_Info.m_flSide = VEC_T_NAN; +#endif +} + + +#endif // IMORPH_H diff --git a/public/materialsystem/ishaderapi.h b/public/materialsystem/ishaderapi.h new file mode 100644 index 0000000..e16ad8c --- /dev/null +++ b/public/materialsystem/ishaderapi.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: NOTE: This file is for backward compat! +// We'll get rid of it soon. Most of the contents of this file were moved +// into shaderpi/ishadershadow.h, shaderapi/ishaderdynamic.h, or +// shaderapi/shareddefs.h +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERAPI_MS_H +#define ISHADERAPI_MS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterialVar; + + +//----------------------------------------------------------------------------- +// Methods that can be called from the SHADER_INIT blocks of shaders +//----------------------------------------------------------------------------- +abstract_class IShaderInit +{ +public: + // Loads up a texture + virtual void LoadTexture( IMaterialVar *pTextureVar, const char *pTextureGroupName, int nAdditionalCreationFlags = 0 ) = 0; + virtual void LoadBumpMap( IMaterialVar *pTextureVar, const char *pTextureGroupName ) = 0; + virtual void LoadCubeMap( IMaterialVar **ppParams, IMaterialVar *pTextureVar, int nAdditionalCreationFlags = 0 ) = 0; +}; + + +#endif // ISHADERAPI_MS_H diff --git a/public/materialsystem/ishadersystem_declarations.h b/public/materialsystem/ishadersystem_declarations.h new file mode 100644 index 0000000..3c54edc --- /dev/null +++ b/public/materialsystem/ishadersystem_declarations.h @@ -0,0 +1,131 @@ +//===== Copyright Valve Corporation, All rights reserved. ======// +#ifndef ISHADER_DECLARATIONS_HDR +#define ISHADER_DECLARATIONS_HDR + +//----------------------------------------------------------------------------- +// Standard vertex shader constants +//----------------------------------------------------------------------------- +enum +{ + // Standard vertex shader constants + VERTEX_SHADER_MATH_CONSTANTS0 = 0, + VERTEX_SHADER_MATH_CONSTANTS1 = 1, + VERTEX_SHADER_CAMERA_POS = 2, + VERTEX_SHADER_FLEXSCALE = 3, // DX9 only + VERTEX_SHADER_LIGHT_INDEX = 3, // DX8 only + VERTEX_SHADER_MODELVIEWPROJ = 4, + VERTEX_SHADER_VIEWPROJ = 8, + VERTEX_SHADER_MODELVIEWPROJ_THIRD_ROW = 12, + VERTEX_SHADER_VIEWPROJ_THIRD_ROW = 13, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_10 = 14, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_11 = 15, + VERTEX_SHADER_FOG_PARAMS = 16, + VERTEX_SHADER_VIEWMODEL = 17, + VERTEX_SHADER_AMBIENT_LIGHT = 21, + VERTEX_SHADER_LIGHTS = 27, + VERTEX_SHADER_LIGHT0_POSITION = 29, + VERTEX_SHADER_MODULATION_COLOR = 47, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_0 = 48, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_1 = 49, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_2 = 50, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_3 = 51, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_4 = 52, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_5 = 53, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_6 = 54, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_7 = 55, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_8 = 56, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_9 = 57, + VERTEX_SHADER_MODEL = 58, + // + // We reserve up through 216 for the 53 bones supported on DX9 + // + VERTEX_SHADER_SHADER_SPECIFIC_CONST_13 = 217, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_14 = 218, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_15 = 219, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_16 = 220, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_17 = 221, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_18 = 222, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_19 = 223, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_12 = 224, + + // 226 ClipPlane0 |------ OpenGL will jam clip planes into these two + // 227 ClipPlane1 | + + + VERTEX_SHADER_FLEX_WEIGHTS = 1024, + VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT = 512, +}; + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterialVar; +class IShaderShadow; +class IShaderDynamicAPI; +class IShaderInit; +class CBasePerMaterialContextData; + + +//----------------------------------------------------------------------------- +// Shader flags +//----------------------------------------------------------------------------- +enum ShaderFlags_t +{ + SHADER_NOT_EDITABLE = 0x1 +}; + + +//----------------------------------------------------------------------------- +// Shader parameter flags +//----------------------------------------------------------------------------- +enum ShaderParamFlags_t +{ + SHADER_PARAM_NOT_EDITABLE = 0x1 +}; + + + +//----------------------------------------------------------------------------- +// Standard vertex shader constants +//----------------------------------------------------------------------------- +enum +{ + // Standard vertex shader constants + VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST = 0, + VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST_COUNT = 4, + + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_0 = 4, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_1 = 5, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_2 = 6, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_3 = 7, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_4 = 8, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_5 = 9, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_6 = 10, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_7 = 11, +}; + + +//----------------------------------------------------------------------------- +// Shader dictionaries defined in DLLs +//----------------------------------------------------------------------------- +enum PrecompiledShaderType_t +{ + PRECOMPILED_VERTEX_SHADER = 0, + PRECOMPILED_PIXEL_SHADER, + + PRECOMPILED_SHADER_TYPE_COUNT, +}; + + +//----------------------------------------------------------------------------- +// Flags field of PrecompiledShader_t +//----------------------------------------------------------------------------- +enum +{ + // runtime flags + SHADER_IS_ASM = 0x1, + SHADER_FAILED_LOAD = 0x2, +}; + + +#endif \ No newline at end of file diff --git a/public/materialsystem/itexture.h b/public/materialsystem/itexture.h new file mode 100644 index 0000000..0e31544 --- /dev/null +++ b/public/materialsystem/itexture.h @@ -0,0 +1,143 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ITEXTURE_H +#define ITEXTURE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "bitmap/imageformat.h" // ImageFormat defn. + +class IVTFTexture; +class ITexture; +struct Rect_t; + +//----------------------------------------------------------------------------- +// This will get called on procedural textures to re-fill the textures +// with the appropriate bit pattern. Calling Download() will also +// cause this interface to be called. It will also be called upon +// mode switch, or on other occasions where the bits are discarded. +//----------------------------------------------------------------------------- +abstract_class ITextureRegenerator +{ +public: + // This will be called when the texture bits need to be regenerated. + // Use the VTFTexture interface, which has been set up with the + // appropriate texture size + format + // The rect specifies which part of the texture needs to be updated + // You can choose to update all of the bits if you prefer + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) = 0; + + // This will be called when the regenerator needs to be deleted + // which will happen when the texture is destroyed + virtual void Release() = 0; + + // (erics): This should have a virtual destructor, but would be ABI breaking (non-versioned interface implemented + // by the game) +// virtual ~ITextureRegenerator(){} +}; + +abstract_class ITexture +{ +public: + // Various texture polling methods + virtual const char *GetName( void ) const = 0; + virtual int GetMappingWidth() const = 0; + virtual int GetMappingHeight() const = 0; + virtual int GetActualWidth() const = 0; + virtual int GetActualHeight() const = 0; + virtual int GetNumAnimationFrames() const = 0; + virtual bool IsTranslucent() const = 0; + virtual bool IsMipmapped() const = 0; + + virtual void GetLowResColorSample( float s, float t, float *color ) const = 0; + + // Gets texture resource data of the specified type. + // Params: + // eDataType type of resource to retrieve. + // pnumBytes on return is the number of bytes available in the read-only data buffer or is undefined + // Returns: + // pointer to the resource data, or NULL + virtual void *GetResourceData( uint32 eDataType, size_t *pNumBytes ) const = 0; + + // Methods associated with reference count + virtual void IncrementReferenceCount( void ) = 0; + virtual void DecrementReferenceCount( void ) = 0; + + inline void AddRef() { IncrementReferenceCount(); } + inline void Release() { DecrementReferenceCount(); } + + // Used to modify the texture bits (procedural textures only) + virtual void SetTextureRegenerator( ITextureRegenerator *pTextureRegen ) = 0; + + // Reconstruct the texture bits in HW memory + + // If rect is not specified, reconstruct all bits, otherwise just + // reconstruct a subrect. + virtual void Download( Rect_t *pRect = 0, int nAdditionalCreationFlags = 0 ) = 0; + + // Uses for stats. . .get the approximate size of the texture in it's current format. + virtual int GetApproximateVidMemBytes( void ) const = 0; + + // Returns true if the texture data couldn't be loaded. + virtual bool IsError() const = 0; + + // NOTE: Stuff after this is added after shipping HL2. + + // For volume textures + virtual bool IsVolumeTexture() const = 0; + virtual int GetMappingDepth() const = 0; + virtual int GetActualDepth() const = 0; + + virtual ImageFormat GetImageFormat() const = 0; + virtual NormalDecodeMode_t GetNormalDecodeMode() const = 0; + + // Various information about the texture + virtual bool IsRenderTarget() const = 0; + virtual bool IsCubeMap() const = 0; + virtual bool IsNormalMap() const = 0; + virtual bool IsProcedural() const = 0; + + virtual void DeleteIfUnreferenced() = 0; + +#if defined( _X360 ) + virtual bool ClearTexture( int r, int g, int b, int a ) = 0; + virtual bool CreateRenderTargetSurface( int width, int height, ImageFormat format, bool bSameAsTexture ) = 0; +#endif + + // swap everything except the name with another texture + virtual void SwapContents( ITexture *pOther ) = 0; + + // Retrieve the vtf flags mask + virtual unsigned int GetFlags( void ) const = 0; + + // Force LOD override (automatically downloads the texture) + virtual void ForceLODOverride( int iNumLodsOverrideUpOrDown ) = 0; + + // Save texture to a file. + virtual bool SaveToFile( const char *fileName ) = 0; + + // Copy this texture, which must be a render target or a renderable texture, to the destination texture, + // which must have been created with the STAGING bit. + virtual void CopyToStagingTexture( ITexture* pDstTex ) = 0; + + // Set that this texture should return true for the call "IsError" + virtual void SetErrorTexture( bool bIsErrorTexture ) = 0; +}; + + +inline bool IsErrorTexture( ITexture *pTex ) +{ + return !pTex || pTex->IsError(); +} + + +#endif // ITEXTURE_H diff --git a/public/materialsystem/itexturecompositor.h b/public/materialsystem/itexturecompositor.h new file mode 100644 index 0000000..a158d36 --- /dev/null +++ b/public/materialsystem/itexturecompositor.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ================================== // +// +// Purpose: Defines a texture compositor infterface which uses simple operations and shaders to +// create complex procedural textures. +// +//============================================================================================== // + +#ifndef ITEXTURECOMPOSITOR_H +#define ITEXTURECOMPOSITOR_H +#pragma once + +#include "interface.h" +#include "itexture.h" + +#define ITEXTURE_COMPOSITOR_INTERFACE_VERSION "_ITextureCompositor000" + +enum ECompositeResolveStatus +{ + ECRS_Idle, + ECRS_Scheduled, + ECRS_PendingTextureLoads, + ECRS_PendingComposites, + ECRS_Error, + ECRS_Complete +}; + +enum TextureCompositeCreateFlags_t +{ + TEX_COMPOSITE_CREATE_FLAGS_FORCE = 0x00000001, + TEX_COMPOSITE_CREATE_FLAGS_NO_COMPRESSION = 0x00000002, + TEX_COMPOSITE_CREATE_FLAGS_NO_MIPMAPS = 0x00000004, +}; + +abstract_class ITextureCompositor +{ +public: + virtual int AddRef() = 0; + virtual int Release() = 0; + virtual int GetRefCount() const = 0; + + virtual void Update() = 0; + virtual ITexture* GetResultTexture() const = 0; + virtual ECompositeResolveStatus GetResolveStatus() const = 0; + virtual void ScheduleResolve() = 0; +protected: + virtual ~ITextureCompositor() {} +}; + + +#endif /* ITEXTURECOMPOSITOR_H */ diff --git a/public/materialsystem/ivballoctracker.h b/public/materialsystem/ivballoctracker.h new file mode 100644 index 0000000..7d07e25 --- /dev/null +++ b/public/materialsystem/ivballoctracker.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: tracks VB allocations (and compressed/uncompressed vertex memory usage) +// +//===========================================================================// + +#ifndef IVBALLOCTRACKER_H +#define IVBALLOCTRACKER_H + +#include "materialsystem/imaterialsystem.h" + +// By default, only enable this alloc tracking for a debug shaderapidx*.dll +// (it uses about 0.25MB to track ~7000 allocations) +#if defined(_DEBUG) +#define ENABLE_VB_ALLOC_TRACKER 1 +#else +#define ENABLE_VB_ALLOC_TRACKER 0 +#endif + +// This interface is actually exported by the shader API DLL. +#define VB_ALLOC_TRACKER_INTERFACE_VERSION "VBAllocTracker001" + +// Interface to the VB mem alloc tracker +abstract_class IVBAllocTracker +{ +public: + // This should be called wherever VertexBuffers are allocated + virtual void CountVB( void * buffer, bool isDynamic, int bufferSize, int vertexSize, VertexFormat_t fmt ) = 0; + // This should be called wherever VertexBuffers are freed + virtual void UnCountVB( void * buffer ) = 0; + // Track mesh allocations (set this before an allocation, clear it after) + virtual bool TrackMeshAllocations( const char * allocatorName ) = 0; +}; + +#endif // IVBALLOCTRACKER_H diff --git a/public/materialsystem/materialsystem_config.h b/public/materialsystem/materialsystem_config.h new file mode 100644 index 0000000..2908d2c --- /dev/null +++ b/public/materialsystem/materialsystem_config.h @@ -0,0 +1,229 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MATERIALSYSTEM_CONFIG_H +#define MATERIALSYSTEM_CONFIG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "materialsystem/imaterialsystem.h" + +#define MATERIALSYSTEM_CONFIG_VERSION "VMaterialSystemConfig002" + +enum MaterialSystem_Config_Flags_t +{ + MATSYS_VIDCFG_FLAGS_WINDOWED = ( 1 << 0 ), + MATSYS_VIDCFG_FLAGS_RESIZING = ( 1 << 1 ), + MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC = ( 1 << 3 ), + MATSYS_VIDCFG_FLAGS_STENCIL = ( 1 << 4 ), + MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR = ( 1 << 5 ), + MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC = ( 1 << 6 ), + MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR = ( 1 << 7 ), + MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP = ( 1 << 8 ), + MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING = ( 1 << 9 ), + MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL = ( 1 << 10 ), + MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE = ( 1 << 11 ), + MATSYS_VIDCFG_FLAGS_ENABLE_HDR = ( 1 << 12 ), + MATSYS_VIDCFG_FLAGS_LIMIT_WINDOWED_SIZE = ( 1 << 13 ), + MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION = ( 1 << 14 ), + MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS = ( 1 << 15 ), + MATSYS_VIDCFG_FLAGS_DISABLE_PHONG = ( 1 << 16 ), + MATSYS_VIDCFG_FLAGS_VR_MODE = ( 1 << 17 ), +}; + +struct MaterialSystemHardwareIdentifier_t +{ + char *m_pCardName; + unsigned int m_nVendorID; + unsigned int m_nDeviceID; +}; + +struct MaterialSystem_Config_t +{ + bool Windowed() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_WINDOWED ) != 0; } + bool Resizing() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_RESIZING ) != 0; } +#ifdef CSS_PERF_TEST + bool WaitForVSync() const { return false; }//( m_Flags & MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC ) == 0; } +#else + bool WaitForVSync() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC ) == 0; } +#endif + bool Stencil() const { return (m_Flags & MATSYS_VIDCFG_FLAGS_STENCIL ) != 0; } + bool ForceTrilinear() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR ) != 0; } + bool ForceHWSync() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC ) != 0; } + bool UseSpecular() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR ) == 0; } + bool UseBumpmapping() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP ) == 0; } + bool UseParallaxMapping() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING ) != 0; } + bool UseZPrefill() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL ) != 0; } + bool ReduceFillrate() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE ) != 0; } + bool HDREnabled() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_ENABLE_HDR ) != 0; } + bool LimitWindowedSize() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_LIMIT_WINDOWED_SIZE ) != 0; } + bool ScaleToOutputResolution() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION ) != 0; } + bool UsingMultipleWindows() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS ) != 0; } + bool UsePhong() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_PHONG ) == 0; } + bool VRMode() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_VR_MODE) != 0; } + bool ShadowDepthTexture() const { return m_bShadowDepthTexture; } + bool MotionBlur() const { return m_bMotionBlur; } + bool SupportFlashlight() const { return m_bSupportFlashlight; } + + void SetFlag( unsigned int flag, bool val ) + { + if( val ) + { + m_Flags |= flag; + } + else + { + m_Flags &= ~flag; + } + } + + // control panel stuff + MaterialVideoMode_t m_VideoMode; + float m_fMonitorGamma; + float m_fGammaTVRangeMin; + float m_fGammaTVRangeMax; + float m_fGammaTVExponent; + bool m_bGammaTVEnabled; + + int m_nAASamples; + int m_nForceAnisotropicLevel; + int skipMipLevels; + int dxSupportLevel; + unsigned int m_Flags; + bool bEditMode; // true if in Hammer. + unsigned char proxiesTestMode; // 0 = normal, 1 = no proxies, 2 = alpha test all, 3 = color mod all + bool bCompressedTextures; + bool bFilterLightmaps; + bool bFilterTextures; + bool bReverseDepth; + bool bBufferPrimitives; + bool bDrawFlat; + bool bMeasureFillRate; + bool bVisualizeFillRate; + bool bNoTransparency; + bool bSoftwareLighting; + bool bAllowCheats; + char nShowMipLevels; + bool bShowLowResImage; + bool bShowNormalMap; + bool bMipMapTextures; + unsigned char nFullbright; + bool m_bFastNoBump; + bool m_bSuppressRendering; + + // debug modes + bool bShowSpecular; // This is the fast version that doesn't require reloading materials + bool bShowDiffuse; // This is the fast version that doesn't require reloading materials + + // misc + int m_nReserved; // Currently unused + + // No depth bias + float m_SlopeScaleDepthBias_Normal; + float m_DepthBias_Normal; + + // Depth bias for rendering decals closer to the camera + float m_SlopeScaleDepthBias_Decal; + float m_DepthBias_Decal; + + // Depth bias for biasing shadow depth map rendering away from the camera + float m_SlopeScaleDepthBias_ShadowMap; + float m_DepthBias_ShadowMap; + + uint m_WindowedSizeLimitWidth; + uint m_WindowedSizeLimitHeight; + int m_nAAQuality; + bool m_bShadowDepthTexture; + bool m_bMotionBlur; + bool m_bSupportFlashlight; + + int m_nVRModeAdapter; + + MaterialSystem_Config_t() + { + memset( this, 0, sizeof( *this ) ); + + // video config defaults + SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_STENCIL, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_LIMIT_WINDOWED_SIZE, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_PHONG, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_VR_MODE, false ); + + m_VideoMode.m_Width = 640; + m_VideoMode.m_Height = 480; + m_VideoMode.m_RefreshRate = 60; + dxSupportLevel = 0; + bCompressedTextures = true; + bFilterTextures = true; + bFilterLightmaps = true; + bMipMapTextures = true; + bBufferPrimitives = true; + + m_fMonitorGamma = 2.2f; + m_fGammaTVRangeMin = 16.0f; + m_fGammaTVRangeMax = 255.0f; + m_fGammaTVExponent = 2.5; + m_bGammaTVEnabled = IsX360(); + + m_nAASamples = 1; + m_bShadowDepthTexture = false; + m_bMotionBlur = false; + m_bSupportFlashlight = true; + + m_nVRModeAdapter = -1; + + // misc defaults + bAllowCheats = false; + bCompressedTextures = true; + bEditMode = false; + + // debug modes + bShowSpecular = true; + bShowDiffuse = true; + nFullbright = 0; + bShowNormalMap = false; + bFilterLightmaps = true; + bFilterTextures = true; + bMipMapTextures = true; + nShowMipLevels = 0; + bShowLowResImage = false; + bReverseDepth = false; + bBufferPrimitives = true; + bDrawFlat = false; + bMeasureFillRate = false; + bVisualizeFillRate = false; + bSoftwareLighting = false; + bNoTransparency = false; + proxiesTestMode = 0; + m_bFastNoBump = false; + m_bSuppressRendering = false; + m_SlopeScaleDepthBias_Decal = -0.5f; + m_SlopeScaleDepthBias_Normal = 0.0f; + m_SlopeScaleDepthBias_ShadowMap = 0.5f; + m_DepthBias_Decal = -262144; + m_DepthBias_Normal = 0.0f; + m_DepthBias_ShadowMap = 262144; + m_WindowedSizeLimitWidth = 1280; + m_WindowedSizeLimitHeight = 1024; + } +}; + + +#endif // MATERIALSYSTEM_CONFIG_H diff --git a/public/materialsystem/meshreader.h b/public/materialsystem/meshreader.h new file mode 100644 index 0000000..15b6873 --- /dev/null +++ b/public/materialsystem/meshreader.h @@ -0,0 +1,268 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef MESHREADER_H +#define MESHREADER_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// This is used to read vertex and index data out of already-created meshes. +// xbox uses this a lot so it doesn't have to store sysmem backups of the +// vertex data. +//----------------------------------------------------------------------------- +class CBaseMeshReader : protected MeshDesc_t +{ +// Initialization. +public: + + CBaseMeshReader(); + ~CBaseMeshReader(); + + // Use BeginRead/EndRead to initialize the mesh reader. + void BeginRead( + IMesh* pMesh, + int firstVertex = 0, + int numVertices = 0, + int firstIndex = 0, + int numIndices = 0 ); + + void EndRead(); + + // PC can use this if it stores its own copy of meshes around, in case + // locking static buffers is too costly. + void BeginRead_Direct( const MeshDesc_t &desc, int numVertices, int nIndices ); + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + +protected: + IMesh *m_pMesh; + int m_MaxVertices; + int m_MaxIndices; +}; + + +// A bunch of accessors for the data that CBaseMeshReader sets up. +class CMeshReader : public CBaseMeshReader +{ +public: +// Access to vertex data. +public: + int NumIndices() const; + unsigned short Index( int index ) const; + + const Vector& Position( int iVertex ) const; + + unsigned int Color( int iVertex ) const; + + const float *TexCoord( int iVertex, int stage ) const; + void TexCoord2f( int iVertex, int stage, float &s, float &t ) const; + const Vector2D& TexCoordVector2D( int iVertex, int stage ) const; + + int NumBoneWeights() const; + float Wrinkle( int iVertex ) const; + + const Vector &Normal( int iVertex ) const; + void Normal( int iVertex, Vector &vNormal ) const; + + const Vector &TangentS( int iVertex ) const; + const Vector &TangentT( int iVertex ) const; + float BoneWeight( int iVertex ) const; + +#ifdef NEW_SKINNING + float* BoneMatrix( int iVertex ) const; +#else + unsigned char* BoneMatrix( int iVertex ) const; +#endif +}; + + +//----------------------------------------------------------------------------- +// CBaseMeshReader implementation. +//----------------------------------------------------------------------------- + +inline CBaseMeshReader::CBaseMeshReader() +{ + m_pMesh = NULL; +} + +inline CBaseMeshReader::~CBaseMeshReader() +{ + Assert( !m_pMesh ); +} + +inline void CBaseMeshReader::BeginRead( + IMesh* pMesh, + int firstVertex, + int numVertices, + int firstIndex, + int numIndices ) +{ + Assert( pMesh && (!m_pMesh) ); + + if ( numVertices < 0 ) + { + numVertices = pMesh->VertexCount(); + } + + if ( numIndices < 0 ) + { + numIndices = pMesh->IndexCount(); + } + + m_pMesh = pMesh; + m_MaxVertices = numVertices; + m_MaxIndices = numIndices; + + // UNDONE: support reading from compressed VBs if needed + VertexCompressionType_t compressionType = CompressionType( pMesh->GetVertexFormat() ); + Assert( compressionType == VERTEX_COMPRESSION_NONE ); + if ( compressionType != VERTEX_COMPRESSION_NONE ) + { + Warning( "Cannot use CBaseMeshReader with compressed vertices! Will get junk data or a crash.\n" ); + } + + // Locks mesh for modifying + pMesh->ModifyBeginEx( true, firstVertex, numVertices, firstIndex, numIndices, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CBaseMeshReader::EndRead() +{ + Assert( m_pMesh ); + m_pMesh->ModifyEnd( *this ); + m_pMesh = NULL; +} + +inline void CBaseMeshReader::BeginRead_Direct( const MeshDesc_t &desc, int nVertices, int nIndices ) +{ + MeshDesc_t *pThis = this; + *pThis = desc; + m_MaxVertices = nVertices; + m_MaxIndices = nIndices; + + // UNDONE: support reading from compressed verts if necessary + Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE ); + if ( desc.m_CompressionType != VERTEX_COMPRESSION_NONE ) + { + Warning( "Cannot use CBaseMeshReader with compressed vertices!\n" ); + } +} + +inline void CBaseMeshReader::Reset() +{ +} + + + + +// -------------------------------------------------------------------------------------- // +// CMeshReader implementation. +// -------------------------------------------------------------------------------------- // + +inline int CMeshReader::NumIndices() const +{ + return m_MaxIndices; +} + +inline unsigned short CMeshReader::Index( int index ) const +{ + Assert( (index >= 0) && (index < m_MaxIndices) ); + return m_pIndices[index * m_nIndexSize]; +} + +inline const Vector& CMeshReader::Position( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(Vector*)((char*)m_pPosition + iVertex * m_VertexSize_Position); +} + +inline unsigned int CMeshReader::Color( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + unsigned char *pColor = m_pColor + iVertex * m_VertexSize_Color; + return (pColor[0] << 16) | (pColor[1] << 8) | (pColor[2]) | (pColor[3] << 24); +} + +inline const float *CMeshReader::TexCoord( int iVertex, int iStage ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return (float*)( (char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage] ); +} + +inline void CMeshReader::TexCoord2f( int iVertex, int iStage, float &s, float &t ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + float *p = (float*)( (char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage] ); + s = p[0]; + t = p[1]; +} + +inline const Vector2D& CMeshReader::TexCoordVector2D( int iVertex, int iStage ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + Vector2D *p = (Vector2D*)( (char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage] ); + return *p; +} + +inline float CMeshReader::Wrinkle( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(float*)( (char*)m_pWrinkle + iVertex * m_VertexSize_Wrinkle ); +} + +inline int CMeshReader::NumBoneWeights() const +{ + return m_NumBoneWeights; +} + +inline const Vector &CMeshReader::Normal( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(const Vector *)(const float*)( (char*)m_pNormal + iVertex * m_VertexSize_Normal ); +} + +inline void CMeshReader::Normal( int iVertex, Vector &vNormal ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + const float *p = (const float*)( (char*)m_pNormal + iVertex * m_VertexSize_Normal ); + vNormal.Init( p[0], p[1], p[2] ); +} + +inline const Vector &CMeshReader::TangentS( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(const Vector*)( (char*)m_pTangentS + iVertex * m_VertexSize_TangentS ); +} + +inline const Vector &CMeshReader::TangentT( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(const Vector*)( (char*)m_pTangentT + iVertex * m_VertexSize_TangentT ); +} + +inline float CMeshReader::BoneWeight( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + float *p = (float*)( (char*)m_pBoneWeight + iVertex * m_VertexSize_BoneWeight ); + return *p; +} + +#endif // MESHREADER_H + + + + + + + diff --git a/public/materialsystem/shader_vcs_version.h b/public/materialsystem/shader_vcs_version.h new file mode 100644 index 0000000..eebad90 --- /dev/null +++ b/public/materialsystem/shader_vcs_version.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SHADER_VCS_VERSION_H +#define SHADER_VCS_VERSION_H +#ifdef _WIN32 +#pragma once +#endif + +// 1 = hl2 shipped +// 2 = compressed with diffs version (lostcoast) +// 3 = compressed with bzip +// 4 = v2 + crc32 +// 5 = v3 + crc32 +// 6 = v5 + duplicate static combo records +#define SHADER_VCS_VERSION_NUMBER 6 + +#define MAX_SHADER_UNPACKED_BLOCK_SIZE (1<<17) +#define MAX_SHADER_PACKED_SIZE (1+MAX_SHADER_UNPACKED_BLOCK_SIZE) + +#pragma pack(1) +struct ShaderHeader_t +{ + int32 m_nVersion; + int32 m_nTotalCombos; + int32 m_nDynamicCombos; + uint32 m_nFlags; + uint32 m_nCentroidMask; + uint32 m_nNumStaticCombos; // includes sentinal key + uint32 m_nSourceCRC32; // NOTE: If you move this, update copyshaders.pl, *_prep.pl, updateshaders.pl +}; +#pragma pack() + +#pragma pack(1) +struct ShaderHeader_t_v4 // still used for assembly shaders +{ + int32 m_nVersion; + int32 m_nTotalCombos; + int32 m_nDynamicCombos; + uint32 m_nFlags; + uint32 m_nCentroidMask; + uint32 m_nDiffReferenceSize; + uint32 m_nSourceCRC32; // NOTE: If you move this, update copyshaders.pl, *_prep.pl, updateshaders.pl +}; +#pragma pack() + +// for old format files +struct ShaderDictionaryEntry_t +{ + int m_Offset; + int m_Size; +}; + +// record for one static combo +struct StaticComboRecord_t +{ + uint32 m_nStaticComboID; + uint32 m_nFileOffset; +}; + + +struct StaticComboAliasRecord_t // for duplicate static combos +{ + uint32 m_nStaticComboID; // this combo + uint32 m_nSourceStaticCombo; // the combo it is the same as +}; + + + + +#endif // SHADER_VCS_VERSION_H + diff --git a/public/mathlib/IceKey.H b/public/mathlib/IceKey.H new file mode 100644 index 0000000..f8641d0 --- /dev/null +++ b/public/mathlib/IceKey.H @@ -0,0 +1,62 @@ +// Purpose: Header file for the C++ ICE encryption class. +// Taken from public domain code, as written by Matthew Kwan - July 1996 +// http://www.darkside.com.au/ice/ + +#ifndef _IceKey_H +#define _IceKey_H + +/* +The IceKey class is used for encrypting and decrypting 64-bit blocks of data +with the ICE (Information Concealment Engine) encryption algorithm. + +The constructor creates a new IceKey object that can be used to encrypt and decrypt data. +The level of encryption determines the size of the key, and hence its speed. +Level 0 uses the Thin-ICE variant, which is an 8-round cipher taking an 8-byte key. +This is the fastest option, and is generally considered to be at least as secure as DES, +although it is not yet certain whether it is as secure as its key size. + +For levels n greater than zero, a 16n-round cipher is used, taking 8n-byte keys. +Although not as fast as level 0, these are very very secure. + +Before an IceKey can be used to encrypt data, its key schedule must be set with the set() member function. +The length of the key required is determined by the level, as described above. + +The member functions encrypt() and decrypt() encrypt and decrypt respectively data +in blocks of eight chracters, using the specified key. + +Two functions keySize() and blockSize() are provided +which return the key and block size respectively, measured in bytes. +The key size is determined by the level, while the block size is always 8. + +The destructor zeroes out and frees up all memory associated with the key. +*/ + +class IceSubkey; + +class IceKey { + public: + IceKey (int n); + ~IceKey (); + + void set (const unsigned char *key); + + void encrypt (const unsigned char *plaintext, + unsigned char *ciphertext) const; + + void decrypt (const unsigned char *ciphertext, + unsigned char *plaintext) const; + + int keySize () const; + + int blockSize () const; + + private: + void scheduleBuild (unsigned short *k, int n, + const int *keyrot); + + int _size; + int _rounds; + IceSubkey *_keysched; +}; + +#endif diff --git a/public/mathlib/amd3dx.h b/public/mathlib/amd3dx.h new file mode 100644 index 0000000..9dab1bf --- /dev/null +++ b/public/mathlib/amd3dx.h @@ -0,0 +1,1188 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/****************************************************************************** + + Copyright (c) 1999 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com + +******************************************************************************* + + AMD3DX.H + + MACRO FORMAT + ============ + This file contains inline assembly macros that + generate AMD-3D instructions in binary format. + Therefore, C or C++ programmer can use AMD-3D instructions + without any penalty in their C or C++ source code. + + The macro's name and format conventions are as follow: + + + 1. First argument of macro is a destination and + second argument is a source operand. + ex) _asm PFCMPEQ (mm3, mm4) + | | + dst src + + 2. The destination operand can be m0 to m7 only. + The source operand can be any one of the register + m0 to m7 or _eax, _ecx, _edx, _ebx, _esi, or _edi + that contains effective address. + ex) _asm PFRCP (MM7, MM6) + ex) _asm PFRCPIT2 (mm0, mm4) + ex) _asm PFMUL (mm3, _edi) + + 3. The prefetch(w) takes one src operand _eax, ecx, _edx, + _ebx, _esi, or _edi that contains effective address. + ex) _asm PREFETCH (_edi) + + For WATCOM C/C++ users, when using #pragma aux instead if + _asm, all macro names should be prefixed by a p_ or P_. + Macros should not be enclosed in quotes. + ex) p_pfrcp (MM7,MM6) + + NOTE: Not all instruction macros, nor all possible + combinations of operands have been explicitely + tested. If any errors are found, please report + them. + + EXAMPLE + ======= + Following program doesn't do anything but it shows you + how to use inline assembly AMD-3D instructions in C. + Note that this will only work in flat memory model which + segment registers cs, ds, ss and es point to the same + linear address space total less than 4GB. + + Used Microsoft VC++ 5.0 + + #include + #include "amd3d.h" + + void main () + { + float x = (float)1.25; + float y = (float)1.25; + float z, zz; + + _asm { + movd mm1, x + movd mm2, y + pfmul (mm1, mm2) + movd z, mm1 + femms + } + + printf ("value of z = %f\n", z); + + // + // Demonstration of using the memory instead of + // multimedia register + // + _asm { + movd mm3, x + lea esi, y // load effective address of y + pfmul (mm3, _esi) + movd zz, mm3 + femms + } + + printf ("value of zz = %f\n", zz); + } + + #pragma aux EXAMPLE with WATCOM C/C++ v11.x + =========================================== + + extern void Add(float *__Dest, float *__A, float *__B); + #pragma aux Add = \ + p_femms \ + "movd mm6,[esi]" \ + p_pfadd(mm6,_edi) \ + "movd [ebx],mm6" \ + p_femms \ + parm [ebx] [esi] [edi]; + +*******************************************************************************/ + +#ifndef _K3DMACROSINCLUDED_ +#define _K3DMACROSINCLUDED_ + +#if defined (__WATCOMC__) + +// The WATCOM C/C++ version of the 3DNow! macros. +// +// The older, compbined register style for WATCOM C/C++ macros is not +// supported. + +/* Operand defines for instructions two operands */ +#define _k3d_mm0_mm0 0xc0 +#define _k3d_mm0_mm1 0xc1 +#define _k3d_mm0_mm2 0xc2 +#define _k3d_mm0_mm3 0xc3 +#define _k3d_mm0_mm4 0xc4 +#define _k3d_mm0_mm5 0xc5 +#define _k3d_mm0_mm6 0xc6 +#define _k3d_mm0_mm7 0xc7 +#define _k3d_mm0_eax 0x00 +#define _k3d_mm0_ecx 0x01 +#define _k3d_mm0_edx 0x02 +#define _k3d_mm0_ebx 0x03 +#define _k3d_mm0_esi 0x06 +#define _k3d_mm0_edi 0x07 +#define _k3d_mm1_mm0 0xc8 +#define _k3d_mm1_mm1 0xc9 +#define _k3d_mm1_mm2 0xca +#define _k3d_mm1_mm3 0xcb +#define _k3d_mm1_mm4 0xcc +#define _k3d_mm1_mm5 0xcd +#define _k3d_mm1_mm6 0xce +#define _k3d_mm1_mm7 0xcf +#define _k3d_mm1_eax 0x08 +#define _k3d_mm1_ecx 0x09 +#define _k3d_mm1_edx 0x0a +#define _k3d_mm1_ebx 0x0b +#define _k3d_mm1_esi 0x0e +#define _k3d_mm1_edi 0x0f +#define _k3d_mm2_mm0 0xd0 +#define _k3d_mm2_mm1 0xd1 +#define _k3d_mm2_mm2 0xd2 +#define _k3d_mm2_mm3 0xd3 +#define _k3d_mm2_mm4 0xd4 +#define _k3d_mm2_mm5 0xd5 +#define _k3d_mm2_mm6 0xd6 +#define _k3d_mm2_mm7 0xd7 +#define _k3d_mm2_eax 0x10 +#define _k3d_mm2_ecx 0x11 +#define _k3d_mm2_edx 0x12 +#define _k3d_mm2_ebx 0x13 +#define _k3d_mm2_esi 0x16 +#define _k3d_mm2_edi 0x17 +#define _k3d_mm3_mm0 0xd8 +#define _k3d_mm3_mm1 0xd9 +#define _k3d_mm3_mm2 0xda +#define _k3d_mm3_mm3 0xdb +#define _k3d_mm3_mm4 0xdc +#define _k3d_mm3_mm5 0xdd +#define _k3d_mm3_mm6 0xde +#define _k3d_mm3_mm7 0xdf +#define _k3d_mm3_eax 0x18 +#define _k3d_mm3_ecx 0x19 +#define _k3d_mm3_edx 0x1a +#define _k3d_mm3_ebx 0x1b +#define _k3d_mm3_esi 0x1e +#define _k3d_mm3_edi 0x1f +#define _k3d_mm4_mm0 0xe0 +#define _k3d_mm4_mm1 0xe1 +#define _k3d_mm4_mm2 0xe2 +#define _k3d_mm4_mm3 0xe3 +#define _k3d_mm4_mm4 0xe4 +#define _k3d_mm4_mm5 0xe5 +#define _k3d_mm4_mm6 0xe6 +#define _k3d_mm4_mm7 0xe7 +#define _k3d_mm4_eax 0x20 +#define _k3d_mm4_ecx 0x21 +#define _k3d_mm4_edx 0x22 +#define _k3d_mm4_ebx 0x23 +#define _k3d_mm4_esi 0x26 +#define _k3d_mm4_edi 0x27 +#define _k3d_mm5_mm0 0xe8 +#define _k3d_mm5_mm1 0xe9 +#define _k3d_mm5_mm2 0xea +#define _k3d_mm5_mm3 0xeb +#define _k3d_mm5_mm4 0xec +#define _k3d_mm5_mm5 0xed +#define _k3d_mm5_mm6 0xee +#define _k3d_mm5_mm7 0xef +#define _k3d_mm5_eax 0x28 +#define _k3d_mm5_ecx 0x29 +#define _k3d_mm5_edx 0x2a +#define _k3d_mm5_ebx 0x2b +#define _k3d_mm5_esi 0x2e +#define _k3d_mm5_edi 0x2f +#define _k3d_mm6_mm0 0xf0 +#define _k3d_mm6_mm1 0xf1 +#define _k3d_mm6_mm2 0xf2 +#define _k3d_mm6_mm3 0xf3 +#define _k3d_mm6_mm4 0xf4 +#define _k3d_mm6_mm5 0xf5 +#define _k3d_mm6_mm6 0xf6 +#define _k3d_mm6_mm7 0xf7 +#define _k3d_mm6_eax 0x30 +#define _k3d_mm6_ecx 0x31 +#define _k3d_mm6_edx 0x32 +#define _k3d_mm6_ebx 0x33 +#define _k3d_mm6_esi 0x36 +#define _k3d_mm6_edi 0x37 +#define _k3d_mm7_mm0 0xf8 +#define _k3d_mm7_mm1 0xf9 +#define _k3d_mm7_mm2 0xfa +#define _k3d_mm7_mm3 0xfb +#define _k3d_mm7_mm4 0xfc +#define _k3d_mm7_mm5 0xfd +#define _k3d_mm7_mm6 0xfe +#define _k3d_mm7_mm7 0xff +#define _k3d_mm7_eax 0x38 +#define _k3d_mm7_ecx 0x39 +#define _k3d_mm7_edx 0x3a +#define _k3d_mm7_ebx 0x3b +#define _k3d_mm7_esi 0x3e +#define _k3d_mm7_edi 0x3f + +#define _k3d_name_xlat_m0 _mm0 +#define _k3d_name_xlat_m1 _mm1 +#define _k3d_name_xlat_m2 _mm2 +#define _k3d_name_xlat_m3 _mm3 +#define _k3d_name_xlat_m4 _mm4 +#define _k3d_name_xlat_m5 _mm5 +#define _k3d_name_xlat_m6 _mm6 +#define _k3d_name_xlat_m7 _mm7 +#define _k3d_name_xlat_M0 _mm0 +#define _k3d_name_xlat_M1 _mm1 +#define _k3d_name_xlat_M2 _mm2 +#define _k3d_name_xlat_M3 _mm3 +#define _k3d_name_xlat_M4 _mm4 +#define _k3d_name_xlat_M5 _mm5 +#define _k3d_name_xlat_M6 _mm6 +#define _k3d_name_xlat_M7 _mm7 +#define _k3d_name_xlat_mm0 _mm0 +#define _k3d_name_xlat_mm1 _mm1 +#define _k3d_name_xlat_mm2 _mm2 +#define _k3d_name_xlat_mm3 _mm3 +#define _k3d_name_xlat_mm4 _mm4 +#define _k3d_name_xlat_mm5 _mm5 +#define _k3d_name_xlat_mm6 _mm6 +#define _k3d_name_xlat_mm7 _mm7 +#define _k3d_name_xlat_MM0 _mm0 +#define _k3d_name_xlat_MM1 _mm1 +#define _k3d_name_xlat_MM2 _mm2 +#define _k3d_name_xlat_MM3 _mm3 +#define _k3d_name_xlat_MM4 _mm4 +#define _k3d_name_xlat_MM5 _mm5 +#define _k3d_name_xlat_MM6 _mm6 +#define _k3d_name_xlat_MM7 _mm7 +#define _k3d_name_xlat_eax _eax +#define _k3d_name_xlat_ebx _ebx +#define _k3d_name_xlat_ecx _ecx +#define _k3d_name_xlat_edx _edx +#define _k3d_name_xlat_esi _esi +#define _k3d_name_xlat_edi _edi +#define _k3d_name_xlat_ebp _ebp +#define _k3d_name_xlat_EAX _eax +#define _k3d_name_xlat_EBX _ebx +#define _k3d_name_xlat_ECX _ecx +#define _k3d_name_xlat_EDX _edx +#define _k3d_name_xlat_ESI _esi +#define _k3d_name_xlat_EDI _edi +#define _k3d_name_xlat_EBP _ebp +#define _k3d_name_xlat__eax _eax +#define _k3d_name_xlat__ebx _ebx +#define _k3d_name_xlat__ecx _ecx +#define _k3d_name_xlat__edx _edx +#define _k3d_name_xlat__esi _esi +#define _k3d_name_xlat__edi _edi +#define _k3d_name_xlat__ebp _ebp +#define _k3d_name_xlat__EAX _eax +#define _k3d_name_xlat__EBX _ebx +#define _k3d_name_xlat__ECX _ecx +#define _k3d_name_xlat__EDX _edx +#define _k3d_name_xlat__ESI _esi +#define _k3d_name_xlat__EDI _edi +#define _k3d_name_xlat__EBP _ebp + +#define _k3d_xglue3(a,b,c) a##b##c +#define _k3d_glue3(a,b,c) _k3d_xglue3(a,b,c) +#define _k3d_MODRM(dst, src) _k3d_glue3(_k3d,_k3d_name_xlat_##dst,_k3d_name_xlat_##src) + +/* Operand defines for prefetch and prefetchw */ + +#define _k3d_pref_eax 0x00 +#define _k3d_pref_ecx 0x01 +#define _k3d_pref_edx 0x02 +#define _k3d_pref_ebx 0x03 +#define _k3d_pref_esi 0x06 +#define _k3d_pref_edi 0x07 +#define _k3d_pref_EAX 0x00 +#define _k3d_pref_ECX 0x01 +#define _k3d_pref_EDX 0x02 +#define _k3d_pref_EBX 0x03 +#define _k3d_pref_ESI 0x06 +#define _k3d_pref_EDI 0x07 +#define _k3d_prefw_eax 0x08 +#define _k3d_prefw_ecx 0x09 +#define _k3d_prefw_edx 0x0A +#define _k3d_prefw_ebx 0x0B +#define _k3d_prefw_esi 0x0E +#define _k3d_prefw_edi 0x0F +#define _k3d_prefw_EAX 0x08 +#define _k3d_prefw_ECX 0x09 +#define _k3d_prefw_EDX 0x0A +#define _k3d_prefw_EBX 0x0B +#define _k3d_prefw_ESI 0x0E +#define _k3d_prefw_EDI 0x0F + +/* Defines for 3DNow! instructions */ +#define PF2ID(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x1d +#define PFACC(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xae +#define PFADD(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x9e +#define PFCMPEQ(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xb0 +#define PFCMPGE(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x90 +#define PFCMPGT(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xa0 +#define PFMAX(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xa4 +#define PFMIN(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x94 +#define PFMUL(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xb4 +#define PFRCP(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x96 +#define PFRCPIT1(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xa6 +#define PFRCPIT2(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xb6 +#define PFRSQRT(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x97 +#define PFRSQIT1(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xa7 +#define PFSUB(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x9a +#define PFSUBR(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xaa +#define PI2FD(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0x0d +#define FEMMS db 0x0f, 0x0e +#define PAVGUSB(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xbf +#define PMULHRW(dst, src) db 0x0f, 0x0f, _k3d_MODRM(dst, src), 0xb7 +#define PREFETCH(src) db 0x0f, 0x0d, _k3d_pref_##src +#define PREFETCHW(src) db 0x0f, 0x0d, _k3d_prefw_##src +#define CPUID db 0x0f, 0xa2 + +/* Defines for new, K7 opcodes */ +#define PFNACC(dst,src) db 0x0f, 0x0f, _k3d_MODRM(dst,src), 0x8a +#define FPPNACC(dst,src) db 0x0f, 0x0f, _k3d_MODRM(dst,src), 0x8e +#define PSWAPD(dst,src) db 0x0f, 0x0f, _k3d_MODRM(dst,src), 0xbb +#define PMINUB(dst,src) db 0x0f, 0xda, _k3d_MODRM(dst,src) +#define PMAXUB(dst,src) db 0x0f, 0xde, _k3d_MODRM(dst,src) +#define PMINSW(dst,src) db 0x0f, 0xea, _k3d_MODRM(dst,src) +#define PMAXSW(dst,src) db 0x0f, 0xee, _k3d_MODRM(dst,src) +#define PMULHUW(dst,src) db 0x0f, 0xe4, _k3d_MODRM(dst,src) +#define PAVGB(dst,src) db 0x0f, 0xe0, _k3d_MODRM(dst,src) +#define PAVGW(dst,src) db 0x0f, 0xe3, _k3d_MODRM(dst,src) +#define PSADBW(dst,src) db 0x0f, 0xf6, _k3d_MODRM(dst,src) +#define PMOVMSKB(dst,src) db 0x0f, 0xd7, _k3d_MODRM(dst,src) +#define PMASKMOVQ(dst,src) db 0x0f, 0xf7, _k3d_MODRM(dst,src) +#define PINSRW(dst,src,msk) db 0x0f, 0xc4, _k3d_MODRM(dst,src), msk +#define PEXTRW(dst,src,msk) db 0x0f, 0xc5, _k3d_MODRM(dst,src), msk +#define PSHUFW(dst,src,msk) db 0x0f, 0x70, _k3d_MODRM(dst,src), msk +#define MOVNTQ(dst,src) db 0x0f, 0xe7, _k3d_MODRM(src,dst) +#define SFENCE db 0x0f, 0xae, 0xf8 + +/* Memory/offset versions of the opcodes */ +#define PF2IDM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x1d +#define PFACCM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xae +#define PFADDM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x9e +#define PFCMPEQM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xb0 +#define PFCMPGEM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x90 +#define PFCMPGTM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xa0 +#define PFMAXM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xa4 +#define PFMINM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x94 +#define PFMULM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xb4 +#define PFRCPM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x96 +#define PFRCPIT1M(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xa6 +#define PFRCPIT2M(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xb6 +#define PFRSQRTM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x97 +#define PFRSQIT1M(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xa7 +#define PFSUBM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x9a +#define PFSUBRM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xaa +#define PI2FDM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x0d +#define PAVGUSBM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xbf +#define PMULHRWM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xb7 + + +/* Memory/offset versions of the new, K7 opcodes */ +#define PFNACCM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x8a +#define FPPNACCM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0x8e +#define PSWAPDM(dst,src,off) db 0x0f, 0x0f, _k3d_MODRM(dst,src) | 0x40, off, 0xbb +#define PMINUBM(dst,src,off) db 0x0f, 0xda, _k3d_MODRM(dst,src) | 0x40, off +#define PMAXUBM(dst,src,off) db 0x0f, 0xde, _k3d_MODRM(dst,src) | 0x40, off +#define PMINSWM(dst,src,off) db 0x0f, 0xea, _k3d_MODRM(dst,src) | 0x40, off +#define PMAXSWM(dst,src,off) db 0x0f, 0xee, _k3d_MODRM(dst,src) | 0x40, off +#define PMULHUWM(dst,src,off) db 0x0f, 0xe4, _k3d_MODRM(dst,src) | 0x40, off +#define PAVGBM(dst,src,off) db 0x0f, 0xe0, _k3d_MODRM(dst,src) | 0x40, off +#define PAVGWM(dst,src,off) db 0x0f, 0xe3, _k3d_MODRM(dst,src) | 0x40, off +#define PSADBWM(dst,src,off) db 0x0f, 0xf6, _k3d_MODRM(dst,src) | 0x40, off +#define PMOVMSKBM(dst,src,off) db 0x0f, 0xd7, _k3d_MODRM(dst,src) | 0x40, off +#define PMASKMOVQM(dst,src,off) db 0x0f, 0xf7, _k3d_MODRM(dst,src) | 0x40, off +#define MOVNTQM(dst,src,off) db 0x0f, 0xe7, _k3d_MODRM(src,dst) | 0x40, off +#define PINSRWM(dst,src,off,msk) db 0x0f, 0xc4, _k3d_MODRM(dst,src) | 0x40, off, msk +#define PSHUFWM(dst,src,off,msk) db 0x0f, 0x70, _k3d_MODRM(dst,src) | 0x40, off, msk + + +/* Defines for 3DNow! instructions for use in pragmas */ +#define p_pf2id(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x1d +#define p_pfacc(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xae +#define p_pfadd(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x9e +#define p_pfcmpeq(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xb0 +#define p_pfcmpge(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x90 +#define p_pfcmpgt(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xa0 +#define p_pfmax(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xa4 +#define p_pfmin(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x94 +#define p_pfmul(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xb4 +#define p_pfrcp(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x96 +#define p_pfrcpit1(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xa6 +#define p_pfrcpit2(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xb6 +#define p_pfrsqrt(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x97 +#define p_pfrsqit1(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xa7 +#define p_pfsub(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x9a +#define p_pfsubr(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xaa +#define p_pi2fd(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0x0d +#define p_femms 0x0f 0x0e +#define p_pavgusb(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xbf +#define p_pmulhrw(dst,src) 0x0f 0x0f _k3d_MODRM(dst,src) 0xb7 +#define p_prefetch(src) 0x0f 0x0d _k3d_pref_##src +#define p_prefetchw(src) 0x0f 0x0d _k3d_prefw_##src +#define P_PFNACC(dst,src) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x8a +#define P_FPPNACC(dst,src) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x8e +#define P_PSWAPD(dst,src) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xbb +#define P_PMINUB(dst,src) 0x0f 0xda (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMAXUB(dst,src) 0x0f 0xde (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMINSW(dst,src) 0x0f 0xea (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMAXSW(dst,src) 0x0f 0xee (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMULHUW(dst,src) 0x0f 0xe4 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PAVGB(dst,src) 0x0f 0xe0 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PAVGW(dst,src) 0x0f 0xe3 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PSADBW(dst,src) 0x0f 0xf6 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMOVMSKB(dst,src) 0x0f 0xd7 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMASKMOVQ(dst,src) 0x0f 0xf7 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PINSRW(dst,src,msk) 0x0f 0xc4 (_k3d_MODRM(dst,src) | 0x40) off msk +#define P_PEXTRW(dst,src,msk) 0x0f 0xc5 (_k3d_MODRM(dst,src) | 0x40) off msk +#define P_PSHUFW(dst,src,msk) 0x0f 0x70 (_k3d_MODRM(dst,src) | 0x40) off msk +#define P_MOVNTQ(dst,src) 0x0f 0xe7 (_k3d_MODRM(src,dst) | 0x40) off + +#define P_PF2IDM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x1d +#define P_PFACCM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xae +#define P_PFADDM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x9e +#define P_PFCMPEQM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xb0 +#define P_PFCMPGEM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x90 +#define P_PFCMPGTM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xa0 +#define P_PFMAXM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xa4 +#define P_PFMINM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x94 +#define P_PFMULM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xb4 +#define P_PFRCPM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x96 +#define P_PFRCPIT1M(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xa6 +#define P_PFRCPIT2M(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xb6 +#define P_PFRSQRTM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x97 +#define P_PFRSQIT1M(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xa7 +#define P_PFSUBM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x9a +#define P_PFSUBRM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xaa +#define P_PI2FDM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x0d +#define P_PAVGUSBM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xbf +#define P_PMULHRWM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xb7 +#define P_PFNACCM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x8a +#define P_FPPNACCM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0x8e +#define P_PSWAPDM(dst,src,off) 0x0f 0x0f (_k3d_MODRM(dst,src) | 0x40) off 0xbb +#define P_PMINUBM(dst,src,off) 0x0f 0xda (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMAXUBM(dst,src,off) 0x0f 0xde (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMINSWM(dst,src,off) 0x0f 0xea (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMAXSWM(dst,src,off) 0x0f 0xee (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMULHUWM(dst,src,off) 0x0f 0xe4 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PAVGBM(dst,src,off) 0x0f 0xe0 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PAVGWM(dst,src,off) 0x0f 0xe3 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PSADBWM(dst,src,off) 0x0f 0xf6 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PMOVMSKBM(dst,src,off) 0x0f 0xd7 (_k3d_MODRM(dst,src) | 0x40) off +#define P_MOVNTQM(dst,src,off) 0x0f 0xe7 (_k3d_MODRM(src,dst) | 0x40) off +#define P_PMASKMOVQM(dst,src,off) 0x0f 0xf7 (_k3d_MODRM(dst,src) | 0x40) off +#define P_PINSRWM(dst,src,off,msk) 0x0f 0xc4 (_k3d_MODRM(dst,src) | 0x40) off msk +#define P_PSHUFWM(dst,src,off,msk) 0x0f 0x70 (_k3d_MODRM(dst,src) | 0x40) off msk + + +#define P_PF2ID(dst,src) p_pf2id(dst,src) +#define P_PFACC(dst,src) p_pfacc(dst,src) +#define P_PFADD(dst,src) p_pfadd(dst,src) +#define P_PFCMPEQ(dst,src) p_pfcmpeq(dst,src) +#define P_PFCMPGE(dst,src) p_pfcmpge(dst,src) +#define P_PFCMPGT(dst,src) p_pfcmpgt(dst,src) +#define P_PFMAX(dst,src) p_pfmax(dst,src) +#define P_PFMIN(dst,src) p_pfmin(dst,src) +#define P_PFMUL(dst,src) p_pfmul(dst,src) +#define P_PFRCP(dst,src) p_pfrcp(dst,src) +#define P_PFRCPIT1(dst,src) p_pfrcpit1(dst,src) +#define P_PFRCPIT2(dst,src) p_pfrcpit2(dst,src) +#define P_PFRSQRT(dst,src) p_pfrsqrt(dst,src) +#define P_PFRSQIT1(dst,src) p_pfrsqit1(dst,src) +#define P_PFSUB(dst,src) p_pfsub(dst,src) +#define P_PFSUBR(dst,src) p_pfsubr(dst,src) +#define P_PI2FD(dst,src) p_pi2fd(dst,src) +#define P_FEMMS p_femms +#define P_PAVGUSB(dst,src) p_pavgusb(dst,src) +#define P_PMULHRW(dst,src) p_pmulhrw(dst,src) +#define P_PREFETCH(src) p_prefetch(src) +#define P_PREFETCHW(src) p_prefetchw(src) +#define p_CPUID 0x0f 0xa2 +#define p_pf2idm(dst,src,off) P_PF2IDM(dst,src,off) +#define p_pfaccm(dst,src,off) P_PFACCM(dst,src,off) +#define p_pfaddm(dst,src,off) P_PFADDM(dst,src,off) +#define p_pfcmpeqm(dst,src,off) P_PFCMPEQM(dst,src,off) +#define p_pfcmpgem(dst,src,off) P_PFCMPGEM(dst,src,off) +#define p_pfcmpgtm(dst,src,off) P_PFCMPGTM(dst,src,off) +#define p_pfmaxm(dst,src,off) P_PFMAXM(dst,src,off) +#define p_pfminm(dst,src,off) P_PFMINM(dst,src,off) +#define p_pfmulm(dst,src,off) P_PFMULM(dst,src,off) +#define p_pfrcpm(dst,src,off) P_PFRCPM(dst,src,off) +#define p_pfrcpit1m(dst,src,off) P_PFRCPIT1M(dst,src,off) +#define p_pfrcpit2m(dst,src,off) P_PFRCPIT2M(dst,src,off) +#define p_pfrsqrtm(dst,src,off) P_PFRSQRTM(dst,src,off) +#define p_pfrsqit1m(dst,src,off) P_PFRSQIT1M(dst,src,off) +#define p_pfsubm(dst,src,off) P_PFSUBM(dst,src,off) +#define p_pfsubrm(dst,src,off) P_PFSUBRM(dst,src,off) +#define p_pi2fdm(dst,src,off) P_PI2FDM(dst,src,off) +#define p_pavgusbm(dst,src,off) P_PAVGUSBM(dst,src,off) +#define p_pmulhrwm(dst,src,off) P_PMULHRWM(dst,src,off) + +#define P_PFNACC(dst,src) p_pfnacc(dst,src) +#define P_FPPNACC(dst,src) p_pfpnacc(dst,src) +#define P_PSWAPD(dst,src) p_pswapd(dst,src) +#define P_PMINUB(dst,src) p_pminub(dst,src) +#define P_PMAXUB(dst,src) p_pmaxub(dst,src) +#define P_PMINSW(dst,src) p_pminsw(dst,src) +#define P_PMAXSW(dst,src) p_pmaxsw(dst,src) +#define P_PMULHUW(dst,src) p_pmulhuw(dst,src) +#define P_PAVGB(dst,src) p_pavgb(dst,src) +#define P_PAVGW(dst,src) p_avgw(dst,src) +#define P_PSADBW(dst,src) p_psadbw(dst,src) +#define P_PMOVMSKB(dst,src) p_pmovmskb(dst,src) +#define P_PMASKMOVQ(dst,src) p_pmaskmovq(dst,src) +#define P_PINSRW(dst,src,msk) p_pinsrw(dst,src) +#define P_PEXTRW(dst,src,msk) p_pextrw(dst,src) +#define P_PSHUFW(dst,src,msk) p_pshufw(dst,src) +#define P_MOVNTQ(dst,src) p_movntq(dst,src) + +#define P_PFNACCM(dst,src,off) p_pfnaccm(dst,src,off) +#define P_FPPNACCM(dst,src,off) p_pfpnaccm(dst,src,off) +#define P_PSWAPDM(dst,src,off) p_pswapdm(dst,src,off) +#define P_PMINUBM(dst,src,off) p_pminubm(dst,src,off) +#define P_PMAXUBM(dst,src,off) p_pmaxubm(dst,src,off) +#define P_PMINSWM(dst,src,off) p_pminswm(dst,src,off) +#define P_PMAXSWM(dst,src,off) p_pmaxswm(dst,src,off) +#define P_PMULHUWM(dst,src,off) p_pmulhuwm(dst,src,off) +#define P_PAVGBM(dst,src,off) p_pavgbm(dst,src,off) +#define P_PAVGWM(dst,src,off) p_avgwm(dst,src,off) +#define P_PSADBWM(dst,src,off) p_psadbwm(dst,src,off) +#define P_PMOVMSKBM(dst,src,off) p_pmovmskbm(dst,src,off) +#define P_PMASKMOVQM(dst,src,off) p_pmaskmovqm(dst,src,off) +#define P_PINSRWM(dst,src,off,msk) p_pinsrwm(dst,src,off,msk) +#define P_PSHUFWM(dst,src,off,msk) p_pshufwm(dst,src,off,msk) +#define P_MOVNTQM(dst,src,off) p_movntqm(dst,src,off) + +#elif defined (_MSC_VER) && !defined (__MWERKS__) +// The Microsoft Visual C++ version of the 3DNow! macros. + +// Stop the "no EMMS" warning, since it doesn't detect FEMMS properly +#pragma warning(disable:4799) + +// Defines for operands. +#define _K3D_MM0 0xc0 +#define _K3D_MM1 0xc1 +#define _K3D_MM2 0xc2 +#define _K3D_MM3 0xc3 +#define _K3D_MM4 0xc4 +#define _K3D_MM5 0xc5 +#define _K3D_MM6 0xc6 +#define _K3D_MM7 0xc7 +#define _K3D_mm0 0xc0 +#define _K3D_mm1 0xc1 +#define _K3D_mm2 0xc2 +#define _K3D_mm3 0xc3 +#define _K3D_mm4 0xc4 +#define _K3D_mm5 0xc5 +#define _K3D_mm6 0xc6 +#define _K3D_mm7 0xc7 +#define _K3D_EAX 0x00 +#define _K3D_ECX 0x01 +#define _K3D_EDX 0x02 +#define _K3D_EBX 0x03 +#define _K3D_ESI 0x06 +#define _K3D_EDI 0x07 +#define _K3D_eax 0x00 +#define _K3D_ecx 0x01 +#define _K3D_edx 0x02 +#define _K3D_ebx 0x03 +#define _K3D_esi 0x06 +#define _K3D_edi 0x07 + +// These defines are for compatibility with the previous version of the header file. +#define _K3D_M0 0xc0 +#define _K3D_M1 0xc1 +#define _K3D_M2 0xc2 +#define _K3D_M3 0xc3 +#define _K3D_M4 0xc4 +#define _K3D_M5 0xc5 +#define _K3D_M6 0xc6 +#define _K3D_M7 0xc7 +#define _K3D_m0 0xc0 +#define _K3D_m1 0xc1 +#define _K3D_m2 0xc2 +#define _K3D_m3 0xc3 +#define _K3D_m4 0xc4 +#define _K3D_m5 0xc5 +#define _K3D_m6 0xc6 +#define _K3D_m7 0xc7 +#define _K3D__EAX 0x00 +#define _K3D__ECX 0x01 +#define _K3D__EDX 0x02 +#define _K3D__EBX 0x03 +#define _K3D__ESI 0x06 +#define _K3D__EDI 0x07 +#define _K3D__eax 0x00 +#define _K3D__ecx 0x01 +#define _K3D__edx 0x02 +#define _K3D__ebx 0x03 +#define _K3D__esi 0x06 +#define _K3D__edi 0x07 + +// General 3DNow! instruction format that is supported by +// these macros. Note that only the most basic form of memory +// operands are supported by these macros. + +#define InjK3DOps(dst,src,inst) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((_K3D_##dst & 0x3f) << 3) | _K3D_##src \ + _asm _emit _3DNowOpcode##inst \ +} + +#define InjK3DMOps(dst,src,off,inst) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit (((_K3D_##dst & 0x3f) << 3) | _K3D_##src | 0x40) \ + _asm _emit off \ + _asm _emit _3DNowOpcode##inst \ +} + +#define InjMMXOps(dst,src,inst) \ +{ \ + _asm _emit 0x0f \ + _asm _emit _3DNowOpcode##inst \ + _asm _emit ((_K3D_##dst & 0x3f) << 3) | _K3D_##src \ +} + +#define InjMMXMOps(dst,src,off,inst) \ +{ \ + _asm _emit 0x0f \ + _asm _emit _3DNowOpcode##inst \ + _asm _emit (((_K3D_##dst & 0x3f) << 3) | _K3D_##src | 0x40) \ + _asm _emit off \ +} + +#define _3DNowOpcodePF2ID 0x1d +#define _3DNowOpcodePFACC 0xae +#define _3DNowOpcodePFADD 0x9e +#define _3DNowOpcodePFCMPEQ 0xb0 +#define _3DNowOpcodePFCMPGE 0x90 +#define _3DNowOpcodePFCMPGT 0xa0 +#define _3DNowOpcodePFMAX 0xa4 +#define _3DNowOpcodePFMIN 0x94 +#define _3DNowOpcodePFMUL 0xb4 +#define _3DNowOpcodePFRCP 0x96 +#define _3DNowOpcodePFRCPIT1 0xa6 +#define _3DNowOpcodePFRCPIT2 0xb6 +#define _3DNowOpcodePFRSQRT 0x97 +#define _3DNowOpcodePFRSQIT1 0xa7 +#define _3DNowOpcodePFSUB 0x9a +#define _3DNowOpcodePFSUBR 0xaa +#define _3DNowOpcodePI2FD 0x0d +#define _3DNowOpcodePAVGUSB 0xbf +#define _3DNowOpcodePMULHRW 0xb7 +#define _3DNowOpcodePFNACC 0x8a +#define _3DNowOpcodeFPPNACC 0x8e +#define _3DNowOpcodePSWAPD 0xbb +#define _3DNowOpcodePMINUB 0xda +#define _3DNowOpcodePMAXUB 0xde +#define _3DNowOpcodePMINSW 0xea +#define _3DNowOpcodePMAXSW 0xee +#define _3DNowOpcodePMULHUW 0xe4 +#define _3DNowOpcodePAVGB 0xe0 +#define _3DNowOpcodePAVGW 0xe3 +#define _3DNowOpcodePSADBW 0xf6 +#define _3DNowOpcodePMOVMSKB 0xd7 +#define _3DNowOpcodePMASKMOVQ 0xf7 +#define _3DNowOpcodePINSRW 0xc4 +#define _3DNowOpcodePEXTRW 0xc5 +#define _3DNowOpcodePSHUFW 0x70 +#define _3DNowOpcodeMOVNTQ 0xe7 +#define _3DNowOpcodePREFETCHT 0x18 + + +#define PF2ID(dst,src) InjK3DOps(dst, src, PF2ID) +#define PFACC(dst,src) InjK3DOps(dst, src, PFACC) +#define PFADD(dst,src) InjK3DOps(dst, src, PFADD) +#define PFCMPEQ(dst,src) InjK3DOps(dst, src, PFCMPEQ) +#define PFCMPGE(dst,src) InjK3DOps(dst, src, PFCMPGE) +#define PFCMPGT(dst,src) InjK3DOps(dst, src, PFCMPGT) +#define PFMAX(dst,src) InjK3DOps(dst, src, PFMAX) +#define PFMIN(dst,src) InjK3DOps(dst, src, PFMIN) +#define PFMUL(dst,src) InjK3DOps(dst, src, PFMUL) +#define PFRCP(dst,src) InjK3DOps(dst, src, PFRCP) +#define PFRCPIT1(dst,src) InjK3DOps(dst, src, PFRCPIT1) +#define PFRCPIT2(dst,src) InjK3DOps(dst, src, PFRCPIT2) +#define PFRSQRT(dst,src) InjK3DOps(dst, src, PFRSQRT) +#define PFRSQIT1(dst,src) InjK3DOps(dst, src, PFRSQIT1) +#define PFSUB(dst,src) InjK3DOps(dst, src, PFSUB) +#define PFSUBR(dst,src) InjK3DOps(dst, src, PFSUBR) +#define PI2FD(dst,src) InjK3DOps(dst, src, PI2FD) +#define PAVGUSB(dst,src) InjK3DOps(dst, src, PAVGUSB) +#define PMULHRW(dst,src) InjK3DOps(dst, src, PMULHRW) + +#define FEMMS \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0e \ +} + +#define PREFETCH(src) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit (_K3D_##src & 0x07) \ +} + +/* Prefetch with a short offset, < 127 or > -127 + Carefull! Doesn't check for your offset being + in range. */ + +#define PREFETCHM(src,off) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit (0x40 | (_K3D_##src & 0x07)) \ + _asm _emit off \ +} + +/* Prefetch with a long offset */ + +#define PREFETCHMLONG(src,off) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit (0x80 | (_K3D_##src & 0x07)) \ + _asm _emit (off & 0x000000ff) \ + _asm _emit (off & 0x0000ff00) >> 8 \ + _asm _emit (off & 0x00ff0000) >> 16 \ + _asm _emit (off & 0xff000000) >> 24 \ +} + +#define PREFETCHW(src) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit (0x08 | (_K3D_##src & 0x07)) \ +} + +#define PREFETCHWM(src,off) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit 0x48 | (_K3D_##src & 0x07) \ + _asm _emit off \ +} + +#define PREFETCHWMLONG(src,off) \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit 0x88 | (_K3D_##src & 0x07) \ + _asm _emit (off & 0x000000ff) \ + _asm _emit (off & 0x0000ff00) >> 8 \ + _asm _emit (off & 0x00ff0000) >> 16 \ + _asm _emit (off & 0xff000000) >> 24 \ +} + +#define CPUID \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0xa2 \ +} + + +/* Defines for new, K7 opcodes */ +#define SFENCE \ +{ \ + _asm _emit 0x0f \ + _asm _emit 0xae \ + _asm _emit 0xf8 \ +} + +#define PFNACC(dst,src) InjK3DOps(dst,src,PFNACC) +#define PFPNACC(dst,src) InjK3DOps(dst,src,PFPNACC) +#define PSWAPD(dst,src) InjK3DOps(dst,src,PSWAPD) +#define PMINUB(dst,src) InjMMXOps(dst,src,PMINUB) +#define PMAXUB(dst,src) InjMMXOps(dst,src,PMAXUB) +#define PMINSW(dst,src) InjMMXOps(dst,src,PMINSW) +#define PMAXSW(dst,src) InjMMXOps(dst,src,PMAXSW) +#define PMULHUW(dst,src) InjMMXOps(dst,src,PMULHUW) +#define PAVGB(dst,src) InjMMXOps(dst,src,PAVGB) +#define PAVGW(dst,src) InjMMXOps(dst,src,PAVGW) +#define PSADBW(dst,src) InjMMXOps(dst,src,PSADBW) +#define PMOVMSKB(dst,src) InjMMXOps(dst,src,PMOVMSKB) +#define PMASKMOVQ(dst,src) InjMMXOps(dst,src,PMASKMOVQ) +#define PINSRW(dst,src,msk) InjMMXOps(dst,src,PINSRW) _asm _emit msk +#define PEXTRW(dst,src,msk) InjMMXOps(dst,src,PEXTRW) _asm _emit msk +#define PSHUFW(dst,src,msk) InjMMXOps(dst,src,PSHUFW) _asm _emit msk +#define MOVNTQ(dst,src) InjMMXOps(src,dst,MOVNTQ) +#define PREFETCHNTA(mem) InjMMXOps(mm0,mem,PREFETCHT) +#define PREFETCHT0(mem) InjMMXOps(mm1,mem,PREFETCHT) +#define PREFETCHT1(mem) InjMMXOps(mm2,mem,PREFETCHT) +#define PREFETCHT2(mem) InjMMXOps(mm3,mem,PREFETCHT) + + +/* Memory/offset versions of the opcodes */ +#define PAVGUSBM(dst,src,off) InjK3DMOps(dst,src,off,PAVGUSB) +#define PF2IDM(dst,src,off) InjK3DMOps(dst,src,off,PF2ID) +#define PFACCM(dst,src,off) InjK3DMOps(dst,src,off,PFACC) +#define PFADDM(dst,src,off) InjK3DMOps(dst,src,off,PFADD) +#define PFCMPEQM(dst,src,off) InjK3DMOps(dst,src,off,PFCMPEQ) +#define PFCMPGEM(dst,src,off) InjK3DMOps(dst,src,off,PFCMPGE) +#define PFCMPGTM(dst,src,off) InjK3DMOps(dst,src,off,PFCMPGT) +#define PFMAXM(dst,src,off) InjK3DMOps(dst,src,off,PFMAX) +#define PFMINM(dst,src,off) InjK3DMOps(dst,src,off,PFMIN) +#define PFMULM(dst,src,off) InjK3DMOps(dst,src,off,PFMUL) +#define PFRCPM(dst,src,off) InjK3DMOps(dst,src,off,PFRCP) +#define PFRCPIT1M(dst,src,off) InjK3DMOps(dst,src,off,PFRCPIT1) +#define PFRCPIT2M(dst,src,off) InjK3DMOps(dst,src,off,PFRCPIT2) +#define PFRSQRTM(dst,src,off) InjK3DMOps(dst,src,off,PFRSQRT) +#define PFRSQIT1M(dst,src,off) InjK3DMOps(dst,src,off,PFRSQIT1) +#define PFSUBM(dst,src,off) InjK3DMOps(dst,src,off,PFSUB) +#define PFSUBRM(dst,src,off) InjK3DMOps(dst,src,off,PFSUBR) +#define PI2FDM(dst,src,off) InjK3DMOps(dst,src,off,PI2FD) +#define PMULHRWM(dst,src,off) InjK3DMOps(dst,src,off,PMULHRW) + + +/* Memory/offset versions of the K7 opcodes */ +#define PFNACCM(dst,src,off) InjK3DMOps(dst,src,off,PFNACC) +#define PFPNACCM(dst,src,off) InjK3DMOps(dst,src,off,PFPNACC) +#define PSWAPDM(dst,src,off) InjK3DMOps(dst,src,off,PSWAPD) +#define PMINUBM(dst,src,off) InjMMXMOps(dst,src,off,PMINUB) +#define PMAXUBM(dst,src,off) InjMMXMOps(dst,src,off,PMAXUB) +#define PMINSWM(dst,src,off) InjMMXMOps(dst,src,off,PMINSW) +#define PMAXSWM(dst,src,off) InjMMXMOps(dst,src,off,PMAXSW) +#define PMULHUWM(dst,src,off) InjMMXMOps(dst,src,off,PMULHUW) +#define PAVGBM(dst,src,off) InjMMXMOps(dst,src,off,PAVGB) +#define PAVGWM(dst,src,off) InjMMXMOps(dst,src,off,PAVGW) +#define PSADBWM(dst,src,off) InjMMXMOps(dst,src,off,PSADBW) +#define PMOVMSKBM(dst,src,off) InjMMXMOps(dst,src,off,PMOVMSKB) +#define PMASKMOVQM(dst,src,off) InjMMXMOps(dst,src,off,PMASKMOVQ) +#define PINSRWM(dst,src,off,msk) InjMMXMOps(dst,src,off,PINSRW) _asm _emit msk +#define PSHUFWM(dst,src,off,msk) InjMMXMOps(dst,src,off,PSHUFW) _asm _emit msk +#define MOVNTQM(dst,src,off) InjMMXMOps(src,dst,off,MOVNTQ) +#define PREFETCHNTAM(mem,off) InjMMXMOps(mm0,mem,off,PREFETCHT) +#define PREFETCHT0M(mem,off) InjMMXMOps(mm1,mem,off,PREFETCHT) +#define PREFETCHT1M(mem,off) InjMMXMOps(mm2,mem,off,PREFETCHT) +#define PREFETCHT2M(mem,off) InjMMXMOps(mm3,mem,off,PREFETCHT) + + +#else + +/* Assume built-in support for 3DNow! opcodes, replace macros with opcodes */ +#define PAVGUSB(dst,src) pavgusb dst,src +#define PF2ID(dst,src) pf2id dst,src +#define PFACC(dst,src) pfacc dst,src +#define PFADD(dst,src) pfadd dst,src +#define PFCMPEQ(dst,src) pfcmpeq dst,src +#define PFCMPGE(dst,src) pfcmpge dst,src +#define PFCMPGT(dst,src) pfcmpgt dst,src +#define PFMAX(dst,src) pfmax dst,src +#define PFMIN(dst,src) pfmin dst,src +#define PFMUL(dst,src) pfmul dst,src +#define PFRCP(dst,src) pfrcp dst,src +#define PFRCPIT1(dst,src) pfrcpit1 dst,src +#define PFRCPIT2(dst,src) pfrcpit2 dst,src +#define PFRSQRT(dst,src) pfrsqrt dst,src +#define PFRSQIT1(dst,src) pfrsqit1 dst,src +#define PFSUB(dst,src) pfsub dst,src +#define PFSUBR(dst,src) pfsubr dst,src +#define PI2FD(dst,src) pi2fd dst,src +#define PMULHRW(dst,src) pmulhrw dst,src +#define PREFETCH(src) prefetch src +#define PREFETCHW(src) prefetchw src + +#define PAVGUSBM(dst,src,off) pavgusb dst,[src+off] +#define PF2IDM(dst,src,off) PF2ID dst,[src+off] +#define PFACCM(dst,src,off) PFACC dst,[src+off] +#define PFADDM(dst,src,off) PFADD dst,[src+off] +#define PFCMPEQM(dst,src,off) PFCMPEQ dst,[src+off] +#define PFCMPGEM(dst,src,off) PFCMPGE dst,[src+off] +#define PFCMPGTM(dst,src,off) PFCMPGT dst,[src+off] +#define PFMAXM(dst,src,off) PFMAX dst,[src+off] +#define PFMINM(dst,src,off) PFMIN dst,[src+off] +#define PFMULM(dst,src,off) PFMUL dst,[src+off] +#define PFRCPM(dst,src,off) PFRCP dst,[src+off] +#define PFRCPIT1M(dst,src,off) PFRCPIT1 dst,[src+off] +#define PFRCPIT2M(dst,src,off) PFRCPIT2 dst,[src+off] +#define PFRSQRTM(dst,src,off) PFRSQRT dst,[src+off] +#define PFRSQIT1M(dst,src,off) PFRSQIT1 dst,[src+off] +#define PFSUBM(dst,src,off) PFSUB dst,[src+off] +#define PFSUBRM(dst,src,off) PFSUBR dst,[src+off] +#define PI2FDM(dst,src,off) PI2FD dst,[src+off] +#define PMULHRWM(dst,src,off) PMULHRW dst,[src+off] + + +#if defined (__MWERKS__) +// At the moment, CodeWarrior does not support these opcodes, so hand-assemble them + +// Defines for operands. +#define _K3D_MM0 0xc0 +#define _K3D_MM1 0xc1 +#define _K3D_MM2 0xc2 +#define _K3D_MM3 0xc3 +#define _K3D_MM4 0xc4 +#define _K3D_MM5 0xc5 +#define _K3D_MM6 0xc6 +#define _K3D_MM7 0xc7 +#define _K3D_mm0 0xc0 +#define _K3D_mm1 0xc1 +#define _K3D_mm2 0xc2 +#define _K3D_mm3 0xc3 +#define _K3D_mm4 0xc4 +#define _K3D_mm5 0xc5 +#define _K3D_mm6 0xc6 +#define _K3D_mm7 0xc7 +#define _K3D_EAX 0x00 +#define _K3D_ECX 0x01 +#define _K3D_EDX 0x02 +#define _K3D_EBX 0x03 +#define _K3D_ESI 0x06 +#define _K3D_EDI 0x07 +#define _K3D_eax 0x00 +#define _K3D_ecx 0x01 +#define _K3D_edx 0x02 +#define _K3D_ebx 0x03 +#define _K3D_esi 0x06 +#define _K3D_edi 0x07 +#define _K3D_EAX 0x00 +#define _K3D_ECX 0x01 +#define _K3D_EDX 0x02 +#define _K3D_EBX 0x03 +#define _K3D_ESI 0x06 +#define _K3D_EDI 0x07 +#define _K3D_eax 0x00 +#define _K3D_ecx 0x01 +#define _K3D_edx 0x02 +#define _K3D_ebx 0x03 +#define _K3D_esi 0x06 +#define _K3D_edi 0x07 + +#define InjK3DOps(dst,src,inst) \ + db 0x0f, 0x0f, (((_K3D_##dst & 0x3f) << 3) | _K3D_##src), _3DNowOpcode##inst + +#define InjK3DMOps(dst,src,off,inst) \ + db 0x0f, 0x0f, (((_K3D_##dst & 0x3f) << 3) | _K3D_##src | 0x40), off, _3DNowOpcode##inst + +#define InjMMXOps(dst,src,inst) \ + db 0x0f, _3DNowOpcode##inst, (((_K3D_##dst & 0x3f) << 3) | _K3D_##src) + +#define InjMMXMOps(dst,src,off,inst) \ + db 0x0f, _3DNowOpcode##inst, (((_K3D_##dst & 0x3f) << 3) | _K3D_##src | 0x40), off + +#define PFNACC(dst,src) InjK3DOps(dst,src,PFNACC) +#define PFPNACC(dst,src) InjK3DOps(dst,src,PFPNACC) +#define PSWAPD(dst,src) InjK3DOps(dst,src,PSWAPD) +#define PMINUB(dst,src) InjMMXOps(dst,src,PMINUB) +#define PMAXUB(dst,src) InjMMXOps(dst,src,PMAXUB) +#define PMINSW(dst,src) InjMMXOps(dst,src,PMINSW) +#define PMAXSW(dst,src) InjMMXOps(dst,src,PMAXSW) +#define PMULHUW(dst,src) InjMMXOps(dst,src,PMULHUW) +#define PAVGB(dst,src) InjMMXOps(dst,src,PAVGB) +#define PAVGW(dst,src) InjMMXOps(dst,src,PAVGW) +#define PSADBW(dst,src) InjMMXOps(dst,src,PSADBW) +#define PMOVMSKB(dst,src) InjMMXOps(dst,src,PMOVMSKB) +#define PMASKMOVQ(dst,src) InjMMXOps(dst,src,PMASKMOVQ) +#define PINSRW(dst,src,msk) InjMMXOps(dst,src,PINSRW) db msk +#define PEXTRW(dst,src,msk) InjMMXOps(dst,src,PEXTRW) db msk +#define PSHUFW(dst,src,msk) InjMMXOps(dst,src,PSHUFW) db msk +#define MOVNTQ(dst,src) InjMMXOps(src,dst,MOVNTQ) +#define PREFETCHNTA(mem) InjMMXOps(mm0,mem,PREFETCHT) +#define PREFETCHT0(mem) InjMMXOps(mm1,mem,PREFETCHT) +#define PREFETCHT1(mem) InjMMXOps(mm2,mem,PREFETCHT) +#define PREFETCHT2(mem) InjMMXOps(mm3,mem,PREFETCHT) + + +/* Memory/offset versions of the K7 opcodes */ +#define PFNACCM(dst,src,off) InjK3DMOps(dst,src,off,PFNACC) +#define PFPNACCM(dst,src,off) InjK3DMOps(dst,src,off,PFPNACC) +#define PSWAPDM(dst,src,off) InjK3DMOps(dst,src,off,PSWAPD) +#define PMINUBM(dst,src,off) InjMMXMOps(dst,src,off,PMINUB) +#define PMAXUBM(dst,src,off) InjMMXMOps(dst,src,off,PMAXUB) +#define PMINSWM(dst,src,off) InjMMXMOps(dst,src,off,PMINSW) +#define PMAXSWM(dst,src,off) InjMMXMOps(dst,src,off,PMAXSW) +#define PMULHUWM(dst,src,off) InjMMXMOps(dst,src,off,PMULHUW) +#define PAVGBM(dst,src,off) InjMMXMOps(dst,src,off,PAVGB) +#define PAVGWM(dst,src,off) InjMMXMOps(dst,src,off,PAVGW) +#define PSADBWM(dst,src,off) InjMMXMOps(dst,src,off,PSADBW) +#define PMOVMSKBM(dst,src,off) InjMMXMOps(dst,src,off,PMOVMSKB) +#define PMASKMOVQM(dst,src,off) InjMMXMOps(dst,src,off,PMASKMOVQ) +#define PINSRWM(dst,src,off,msk) InjMMXMOps(dst,src,off,PINSRW), msk +#define PEXTRWM(dst,src,off,msk) InjMMXMOps(dst,src,off,PEXTRW), msk +#define PSHUFWM(dst,src,off,msk) InjMMXMOps(dst,src,off,PSHUFW), msk +#define MOVNTQM(dst,src,off) InjMMXMOps(src,dst,off,MOVNTQ) +#define PREFETCHNTAM(mem,off) InjMMXMOps(mm0,mem,off,PREFETCHT) +#define PREFETCHT0M(mem,off) InjMMXMOps(mm1,mem,off,PREFETCHT) +#define PREFETCHT1M(mem,off) InjMMXMOps(mm2,mem,off,PREFETCHT) +#define PREFETCHT2M(mem,off) InjMMXMOps(mm3,mem,off,PREFETCHT) + + +#else + +#define PFNACC(dst,src) PFNACC dst,src +#define PFPNACC(dst,src) PFPNACC dst,src +#define PSWAPD(dst,src) PSWAPD dst,src +#define PMINUB(dst,src) PMINUB dst,src +#define PMAXUB(dst,src) PMAXUB dst,src +#define PMINSW(dst,src) PMINSW dst,src +#define PMAXSW(dst,src) PMAXSW dst,src +#define PMULHUW(dst,src) PMULHUW dst,src +#define PAVGB(dst,src) PAVGB dst,src +#define PAVGW(dst,src) PAVGW dst,src +#define PSADBW(dst,src) PSADBW dst,src +#define PMOVMSKB(dst,src) PMOVMSKB dst,src +#define PMASKMOVQ(dst,src) PMASKMOVQ dst,src +#define PINSRW(dst,src,msk) PINSRW dst,src,msk +#define PEXTRW(dst,src,msk) PEXTRW dst,src,msk +#define PSHUFW(dst,src,msk) PSHUFW dst,src,msk +#define MOVNTQ(dst,src) MOVNTQ dst,src + +#define PFNACCM(dst,src,off) PFNACC dst,[src+off] +#define PFPNACCM(dst,src,off) PFPNACC dst,[src+off] +#define PSWAPDM(dst,src,off) PSWAPD dst,[src+off] +#define PMINUBM(dst,src,off) PMINUB dst,[src+off] +#define PMAXUBM(dst,src,off) PMAXUB dst,[src+off] +#define PMINSWM(dst,src,off) PMINSW dst,[src+off] +#define PMAXSWM(dst,src,off) PMAXSW dst,[src+off] +#define PMULHUWM(dst,src,off) PMULHUW dst,[src+off] +#define PAVGBM(dst,src,off) PAVGB dst,[src+off] +#define PAVGWM(dst,src,off) PAVGW dst,[src+off] +#define PSADBWM(dst,src,off) PSADBW dst,[src+off] +#define PMOVMSKBM(dst,src,off) PMOVMSKB dst,[src+off] +#define PMASKMOVQM(dst,src,off) PMASKMOVQ dst,[src+off] +#define PINSRWM(dst,src,off,msk) PINSRW dst,[src+off],msk +#define PEXTRWM(dst,src,off,msk) PEXTRW dst,[src+off],msk +#define PSHUFWM(dst,src,off,msk) PSHUFW dst,[src+off],msk +#define MOVNTQM(dst,src,off) MOVNTQ dst,[src+off] + +#endif + +#endif + +/* Just to deal with lower case. */ +#define pf2id(dst,src) PF2ID(dst,src) +#define pfacc(dst,src) PFACC(dst,src) +#define pfadd(dst,src) PFADD(dst,src) +#define pfcmpeq(dst,src) PFCMPEQ(dst,src) +#define pfcmpge(dst,src) PFCMPGE(dst,src) +#define pfcmpgt(dst,src) PFCMPGT(dst,src) +#define pfmax(dst,src) PFMAX(dst,src) +#define pfmin(dst,src) PFMIN(dst,src) +#define pfmul(dst,src) PFMUL(dst,src) +#define pfrcp(dst,src) PFRCP(dst,src) +#define pfrcpit1(dst,src) PFRCPIT1(dst,src) +#define pfrcpit2(dst,src) PFRCPIT2(dst,src) +#define pfrsqrt(dst,src) PFRSQRT(dst,src) +#define pfrsqit1(dst,src) PFRSQIT1(dst,src) +#define pfsub(dst,src) PFSUB(dst,src) +#define pfsubr(dst,src) PFSUBR(dst,src) +#define pi2fd(dst,src) PI2FD(dst,src) +#define femms FEMMS +#define pavgusb(dst,src) PAVGUSB(dst,src) +#define pmulhrw(dst,src) PMULHRW(dst,src) +#define prefetch(src) PREFETCH(src) +#define prefetchw(src) PREFETCHW(src) + +#define prefetchm(src,off) PREFETCHM(src,off) +#define prefetchmlong(src,off) PREFETCHMLONG(src,off) +#define prefetchwm(src,off) PREFETCHWM(src,off) +#define prefetchwmlong(src,off) PREFETCHWMLONG(src,off) + +#define pfnacc(dst,src) PFNACC(dst,src) +#define pfpnacc(dst,src) PFPNACC(dst,src) +#define pswapd(dst,src) PSWAPD(dst,src) +#define pminub(dst,src) PMINUB(dst,src) +#define pmaxub(dst,src) PMAXUB(dst,src) +#define pminsw(dst,src) PMINSW(dst,src) +#define pmaxsw(dst,src) PMAXSW(dst,src) +#define pmulhuw(dst,src) PMULHUW(dst,src) +#define pavgb(dst,src) PAVGB(dst,src) +#define pavgw(dst,src) PAVGW(dst,src) +#define psadbw(dst,src) PSADBW(dst,src) +#define pmovmskb(dst,src) PMOVMSKB(dst,src) +#define pmaskmovq(dst,src) PMASKMOVQ(dst,src) +#define pinsrw(dst,src,msk) PINSRW(dst,src,msk) +#define pextrw(dst,src,msk) PEXTRW(dst,src,msk) +#define pshufw(dst,src,msk) PSHUFW(dst,src,msk) +#define movntq(dst,src) MOVNTQ(dst,src) +#define prefetchnta(mem) PREFETCHNTA(mem) +#define prefetcht0(mem) PREFETCHT0(mem) +#define prefetcht1(mem) PREFETCHT1(mem) +#define prefetcht2(mem) PREFETCHT2(mem) + + +#define pavgusbm(dst,src,off) PAVGUSBM(dst,src,off) +#define pf2idm(dst,src,off) PF2IDM(dst,src,off) +#define pfaccm(dst,src,off) PFACCM(dst,src,off) +#define pfaddm(dst,src,off) PFADDM(dst,src,off) +#define pfcmpeqm(dst,src,off) PFCMPEQM(dst,src,off) +#define pfcmpgem(dst,src,off) PFCMPGEM(dst,src,off) +#define pfcmpgtm(dst,src,off) PFCMPGTM(dst,src,off) +#define pfmaxm(dst,src,off) PFMAXM(dst,src,off) +#define pfminm(dst,src,off) PFMINM(dst,src,off) +#define pfmulm(dst,src,off) PFMULM(dst,src,off) +#define pfrcpm(dst,src,off) PFRCPM(dst,src,off) +#define pfrcpit1m(dst,src,off) PFRCPIT1M(dst,src,off) +#define pfrcpit2m(dst,src,off) PFRCPIT2M(dst,src,off) +#define pfrsqrtm(dst,src,off) PFRSQRTM(dst,src,off) +#define pfrsqit1m(dst,src,off) PFRSQIT1M(dst,src,off) +#define pfsubm(dst,src,off) PFSUBM(dst,src,off) +#define pfsubrm(dst,src,off) PFSUBRM(dst,src,off) +#define pi2fdm(dst,src,off) PI2FDM(dst,src,off) +#define pmulhrwm(dst,src,off) PMULHRWM(dst,src,off) +#define cpuid CPUID +#define sfence SFENCE + +#define pfnaccm(dst,src,off) PFNACCM(dst,src,off) +#define pfpnaccm(dst,src,off) PFPNACCM(dst,src,off) +#define pswapdm(dst,src,off) PSWAPDM(dst,src,off) +#define pminubm(dst,src,off) PMINUBM(dst,src,off) +#define pmaxubm(dst,src,off) PMAXUBM(dst,src,off) +#define pminswm(dst,src,off) PMINSWM(dst,src,off) +#define pmaxswm(dst,src,off) PMAXSWM(dst,src,off) +#define pmulhuwm(dst,src,off) PMULHUWM(dst,src,off) +#define pavgbm(dst,src,off) PAVGBM(dst,src,off) +#define pavgwm(dst,src,off) PAVGWM(dst,src,off) +#define psadbwm(dst,src,off) PSADBWM(dst,src,off) +#define pmovmskbm(dst,src,off) PMOVMSKBM(dst,src,off) +#define pmaskmovqm(dst,src,off) PMASKMOVQM(dst,src,off) +#define pinsrwm(dst,src,off,msk) PINSRWM(dst,src,off,msk) +#define pextrwm(dst,src,off,msk) PEXTRWM(dst,src,off,msk) +#define pshufwm(dst,src,off,msk) PSHUFWM(dst,src,off,msk) +#define movntqm(dst,src,off) MOVNTQM(dst,src,off) +#define prefetchntam(mem,off) PREFETCHNTA(mem,off) +#define prefetcht0m(mem,off) PREFETCHT0(mem,off) +#define prefetcht1m(mem,off) PREFETCHT1(mem,off) +#define prefetcht2m(mem,off) PREFETCHT2(mem,off) + +#endif diff --git a/public/mathlib/anorms.h b/public/mathlib/anorms.h new file mode 100644 index 0000000..4f65383 --- /dev/null +++ b/public/mathlib/anorms.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ANORMS_H +#define ANORMS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" + + +#define NUMVERTEXNORMALS 162 + +// the angle between consecutive g_anorms[] vectors is ~14.55 degrees +#define VERTEXNORMAL_CONE_INNER_ANGLE DEG2RAD(7.275) + +extern Vector g_anorms[NUMVERTEXNORMALS]; + + +#endif // ANORMS_H diff --git a/public/mathlib/bumpvects.h b/public/mathlib/bumpvects.h new file mode 100644 index 0000000..6939ca0 --- /dev/null +++ b/public/mathlib/bumpvects.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef BUMPVECTS_H +#define BUMPVECTS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/mathlib.h" + +#define OO_SQRT_2 0.70710676908493042f +#define OO_SQRT_3 0.57735025882720947f +#define OO_SQRT_6 0.40824821591377258f +// sqrt( 2 / 3 ) +#define OO_SQRT_2_OVER_3 0.81649661064147949f + +#define NUM_BUMP_VECTS 3 + +const TableVector g_localBumpBasis[NUM_BUMP_VECTS] = +{ + { OO_SQRT_2_OVER_3, 0.0f, OO_SQRT_3 }, + { -OO_SQRT_6, OO_SQRT_2, OO_SQRT_3 }, + { -OO_SQRT_6, -OO_SQRT_2, OO_SQRT_3 } +}; + +void GetBumpNormals( const Vector& sVect, const Vector& tVect, const Vector& flatNormal, + const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] ); + +#endif // BUMPVECTS_H diff --git a/public/mathlib/compressed_3d_unitvec.h b/public/mathlib/compressed_3d_unitvec.h new file mode 100644 index 0000000..a92dba2 --- /dev/null +++ b/public/mathlib/compressed_3d_unitvec.h @@ -0,0 +1,284 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef _3D_UNITVEC_H +#define _3D_UNITVEC_H + + +#define UNITVEC_DECLARE_STATICS \ + float cUnitVector::mUVAdjustment[0x2000]; \ + Vector cUnitVector::mTmpVec; + +// upper 3 bits +#define SIGN_MASK 0xe000 +#define XSIGN_MASK 0x8000 +#define YSIGN_MASK 0x4000 +#define ZSIGN_MASK 0x2000 + +// middle 6 bits - xbits +#define TOP_MASK 0x1f80 + +// lower 7 bits - ybits +#define BOTTOM_MASK 0x007f + +// unitcomp.cpp : A Unit Vector to 16-bit word conversion +// algorithm based on work of Rafael Baptista (rafael@oroboro.com) +// Accuracy improved by O.D. (punkfloyd@rocketmail.com) +// Used with Permission. + +// a compressed unit vector. reasonable fidelty for unit +// vectors in a 16 bit package. Good enough for surface normals +// we hope. +class cUnitVector // : public c3dMathObject +{ +public: + cUnitVector() { mVec = 0; } + cUnitVector( const Vector& vec ) + { + packVector( vec ); + } + cUnitVector( unsigned short val ) { mVec = val; } + + cUnitVector& operator=( const Vector& vec ) + { packVector( vec ); return *this; } + + operator Vector() + { + unpackVector( mTmpVec ); + return mTmpVec; + } + + void packVector( const Vector& vec ) + { + // convert from Vector to cUnitVector + + Assert( vec.IsValid()); + Vector tmp = vec; + + // input vector does not have to be unit length + // Assert( tmp.length() <= 1.001f ); + + mVec = 0; + if ( tmp.x < 0 ) { mVec |= XSIGN_MASK; tmp.x = -tmp.x; } + if ( tmp.y < 0 ) { mVec |= YSIGN_MASK; tmp.y = -tmp.y; } + if ( tmp.z < 0 ) { mVec |= ZSIGN_MASK; tmp.z = -tmp.z; } + + // project the normal onto the plane that goes through + // X0=(1,0,0),Y0=(0,1,0),Z0=(0,0,1). + // on that plane we choose an (projective!) coordinate system + // such that X0->(0,0), Y0->(126,0), Z0->(0,126),(0,0,0)->Infinity + + // a little slower... old pack was 4 multiplies and 2 adds. + // This is 2 multiplies, 2 adds, and a divide.... + float w = 126.0f / ( tmp.x + tmp.y + tmp.z ); + long xbits = (long)( tmp.x * w ); + long ybits = (long)( tmp.y * w ); + + Assert( xbits < 127 ); + Assert( xbits >= 0 ); + Assert( ybits < 127 ); + Assert( ybits >= 0 ); + + // Now we can be sure that 0<=xp<=126, 0<=yp<=126, 0<=xp+yp<=126 + // however for the sampling we want to transform this triangle + // into a rectangle. + if ( xbits >= 64 ) + { + xbits = 127 - xbits; + ybits = 127 - ybits; + } + + // now we that have xp in the range (0,127) and yp in + // the range (0,63), we can pack all the bits together + mVec |= ( xbits << 7 ); + mVec |= ybits; + } + + void unpackVector( Vector& vec ) + { + // if we do a straightforward backward transform + // we will get points on the plane X0,Y0,Z0 + // however we need points on a sphere that goes through + // these points. Therefore we need to adjust x,y,z so + // that x^2+y^2+z^2=1 by normalizing the vector. We have + // already precalculated the amount by which we need to + // scale, so all we do is a table lookup and a + // multiplication + + // get the x and y bits + long xbits = (( mVec & TOP_MASK ) >> 7 ); + long ybits = ( mVec & BOTTOM_MASK ); + + // map the numbers back to the triangle (0,0)-(0,126)-(126,0) + if (( xbits + ybits ) >= 127 ) + { + xbits = 127 - xbits; + ybits = 127 - ybits; + } + + // do the inverse transform and normalization + // costs 3 extra multiplies and 2 subtracts. No big deal. + float uvadj = mUVAdjustment[mVec & ~SIGN_MASK]; + vec.x = uvadj * (float) xbits; + vec.y = uvadj * (float) ybits; + vec.z = uvadj * (float)( 126 - xbits - ybits ); + + // set all the sign bits + if ( mVec & XSIGN_MASK ) vec.x = -vec.x; + if ( mVec & YSIGN_MASK ) vec.y = -vec.y; + if ( mVec & ZSIGN_MASK ) vec.z = -vec.z; + + Assert( vec.IsValid()); + } + + static void initializeStatics() + { + for ( int idx = 0; idx < 0x2000; idx++ ) + { + long xbits = idx >> 7; + long ybits = idx & BOTTOM_MASK; + + // map the numbers back to the triangle (0,0)-(0,127)-(127,0) + if (( xbits + ybits ) >= 127 ) + { + xbits = 127 - xbits; + ybits = 127 - ybits; + } + + // convert to 3D vectors + float x = (float)xbits; + float y = (float)ybits; + float z = (float)( 126 - xbits - ybits ); + + // calculate the amount of normalization required + mUVAdjustment[idx] = 1.0f / sqrtf( y*y + z*z + x*x ); + Assert( _finite( mUVAdjustment[idx])); + + //cerr << mUVAdjustment[idx] << "\t"; + //if ( xbits == 0 ) cerr << "\n"; + } + } + +#if 0 + void test() + { + #define TEST_RANGE 4 + #define TEST_RANDOM 100 + #define TEST_ANGERROR 1.0 + + float maxError = 0; + float avgError = 0; + int numVecs = 0; + + {for ( int x = -TEST_RANGE; x < TEST_RANGE; x++ ) + { + for ( int y = -TEST_RANGE; y < TEST_RANGE; y++ ) + { + for ( int z = -TEST_RANGE; z < TEST_RANGE; z++ ) + { + if (( x + y + z ) == 0 ) continue; + + Vector vec( (float)x, (float)y, (float)z ); + Vector vec2; + + vec.normalize(); + packVector( vec ); + unpackVector( vec2 ); + + float ang = vec.dot( vec2 ); + ang = (( fabs( ang ) > 0.99999f ) ? 0 : (float)acos(ang)); + + if (( ang > TEST_ANGERROR ) | ( !_finite( ang ))) + { + cerr << "error: " << ang << endl; + cerr << "orig vec: " << vec.x << ",\t" + << vec.y << ",\t" << vec.z << "\tmVec: " + << mVec << endl; + cerr << "quantized vec2: " << vec2.x + << ",\t" << vec2.y << ",\t" + << vec2.z << endl << endl; + } + avgError += ang; + numVecs++; + if ( maxError < ang ) maxError = ang; + } + } + }} + + for ( int w = 0; w < TEST_RANDOM; w++ ) + { + Vector vec( genRandom(), genRandom(), genRandom()); + Vector vec2; + vec.normalize(); + + packVector( vec ); + unpackVector( vec2 ); + + float ang =vec.dot( vec2 ); + ang = (( ang > 0.999f ) ? 0 : (float)acos(ang)); + + if (( ang > TEST_ANGERROR ) | ( !_finite( ang ))) + { + cerr << "error: " << ang << endl; + cerr << "orig vec: " << vec.x << ",\t" + << vec.y << ",\t" << vec.z << "\tmVec: " + << mVec << endl; + cerr << "quantized vec2: " << vec2.x << ",\t" + << vec2.y << ",\t" + << vec2.z << endl << endl; + } + avgError += ang; + numVecs++; + if ( maxError < ang ) maxError = ang; + } + + { for ( int x = 0; x < 50; x++ ) + { + Vector vec( (float)x, 25.0f, 0.0f ); + Vector vec2; + + vec.normalize(); + packVector( vec ); + unpackVector( vec2 ); + + float ang = vec.dot( vec2 ); + ang = (( fabs( ang ) > 0.999f ) ? 0 : (float)acos(ang)); + + if (( ang > TEST_ANGERROR ) | ( !_finite( ang ))) + { + cerr << "error: " << ang << endl; + cerr << "orig vec: " << vec.x << ",\t" + << vec.y << ",\t" << vec.z << "\tmVec: " + << mVec << endl; + cerr << " quantized vec2: " << vec2.x << ",\t" + << vec2.y << ",\t" << vec2.z << endl << endl; + } + + avgError += ang; + numVecs++; + if ( maxError < ang ) maxError = ang; + }} + + cerr << "max angle error: " << maxError + << ", average error: " << avgError / numVecs + << ", num tested vecs: " << numVecs << endl; + } + + friend ostream& operator<< ( ostream& os, const cUnitVector& vec ) + { os << vec.mVec; return os; } +#endif + +//protected: // !!!! + + unsigned short mVec; + static float mUVAdjustment[0x2000]; + static Vector mTmpVec; +}; + +#endif // _3D_VECTOR_H + + diff --git a/public/mathlib/compressed_light_cube.h b/public/mathlib/compressed_light_cube.h new file mode 100644 index 0000000..207f92d --- /dev/null +++ b/public/mathlib/compressed_light_cube.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef COMPRESSED_LIGHT_CUBE_H +#define COMPRESSED_LIGHT_CUBE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/mathlib.h" + + +struct CompressedLightCube +{ + DECLARE_BYTESWAP_DATADESC(); + ColorRGBExp32 m_Color[6]; +}; + + +#endif // COMPRESSED_LIGHT_CUBE_H diff --git a/public/mathlib/compressed_vector.h b/public/mathlib/compressed_vector.h new file mode 100644 index 0000000..8c290a3 --- /dev/null +++ b/public/mathlib/compressed_vector.h @@ -0,0 +1,608 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef COMPRESSED_VECTOR_H +#define COMPRESSED_VECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +// For vec_t, put this somewhere else? +#include "basetypes.h" + +// For rand(). We really need a library! +#include + +#include "tier0/dbg.h" +#include "mathlib/vector.h" + +#include "mathlib/mathlib.h" + +#if defined( _X360 ) +#pragma bitfield_order( push, lsb_to_msb ) +#endif +//========================================================= +// fit a 3D vector into 32 bits +//========================================================= + +class Vector32 +{ +public: + // Construction/destruction: + Vector32(void); + Vector32(vec_t X, vec_t Y, vec_t Z); + + // assignment + Vector32& operator=(const Vector &vOther); + operator Vector (); + +private: + unsigned short x:10; + unsigned short y:10; + unsigned short z:10; + unsigned short exp:2; +}; + +inline Vector32& Vector32::operator=(const Vector &vOther) +{ + CHECK_VALID(vOther); + + static float expScale[4] = { 4.0f, 16.0f, 32.f, 64.f }; + + float fmax = Max( fabs( vOther.x ), fabs( vOther.y ) ); + fmax = Max( fmax, (float)fabs( vOther.z ) ); + + for (exp = 0; exp < 3; exp++) + { + if (fmax < expScale[exp]) + break; + } + Assert( fmax < expScale[exp] ); + + float fexp = 512.0f / expScale[exp]; + + x = Clamp( (int)(vOther.x * fexp) + 512, 0, 1023 ); + y = Clamp( (int)(vOther.y * fexp) + 512, 0, 1023 ); + z = Clamp( (int)(vOther.z * fexp) + 512, 0, 1023 ); + return *this; +} + + +inline Vector32::operator Vector () +{ + Vector tmp; + + static float expScale[4] = { 4.0f, 16.0f, 32.f, 64.f }; + + float fexp = expScale[exp] / 512.0f; + + tmp.x = (((int)x) - 512) * fexp; + tmp.y = (((int)y) - 512) * fexp; + tmp.z = (((int)z) - 512) * fexp; + return tmp; +} + + +//========================================================= +// Fit a unit vector into 32 bits +//========================================================= + +class Normal32 +{ +public: + // Construction/destruction: + Normal32(void); + Normal32(vec_t X, vec_t Y, vec_t Z); + + // assignment + Normal32& operator=(const Vector &vOther); + operator Vector (); + +private: + unsigned short x:15; + unsigned short y:15; + unsigned short zneg:1; +}; + + +inline Normal32& Normal32::operator=(const Vector &vOther) +{ + CHECK_VALID(vOther); + + x = Clamp( (int)(vOther.x * 16384) + 16384, 0, 32767 ); + y = Clamp( (int)(vOther.y * 16384) + 16384, 0, 32767 ); + zneg = (vOther.z < 0); + //x = vOther.x; + //y = vOther.y; + //z = vOther.z; + return *this; +} + + +inline Normal32::operator Vector () +{ + Vector tmp; + + tmp.x = ((int)x - 16384) * (1 / 16384.0); + tmp.y = ((int)y - 16384) * (1 / 16384.0); + tmp.z = sqrt( 1 - tmp.x * tmp.x - tmp.y * tmp.y ); + if (zneg) + tmp.z = -tmp.z; + return tmp; +} + + +//========================================================= +// 64 bit Quaternion +//========================================================= + +class Quaternion64 +{ +public: + // Construction/destruction: + Quaternion64(void); + Quaternion64(vec_t X, vec_t Y, vec_t Z); + + // assignment + // Quaternion& operator=(const Quaternion64 &vOther); + Quaternion64& operator=(const Quaternion &vOther); + operator Quaternion (); +private: + uint64 x:21; + uint64 y:21; + uint64 z:21; + uint64 wneg:1; +}; + + +inline Quaternion64::operator Quaternion () +{ + Quaternion tmp; + + // shift to -1048576, + 1048575, then round down slightly to -1.0 < x < 1.0 + tmp.x = ((int)x - 1048576) * (1 / 1048576.5f); + tmp.y = ((int)y - 1048576) * (1 / 1048576.5f); + tmp.z = ((int)z - 1048576) * (1 / 1048576.5f); + tmp.w = sqrt( 1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z ); + if (wneg) + tmp.w = -tmp.w; + return tmp; +} + +inline Quaternion64& Quaternion64::operator=(const Quaternion &vOther) +{ + CHECK_VALID(vOther); + + x = Clamp( (int)(vOther.x * 1048576) + 1048576, 0, 2097151 ); + y = Clamp( (int)(vOther.y * 1048576) + 1048576, 0, 2097151 ); + z = Clamp( (int)(vOther.z * 1048576) + 1048576, 0, 2097151 ); + wneg = (vOther.w < 0); + return *this; +} + +//========================================================= +// 48 bit Quaternion +//========================================================= + +class Quaternion48 +{ +public: + // Construction/destruction: + Quaternion48(void); + Quaternion48(vec_t X, vec_t Y, vec_t Z); + + // assignment + // Quaternion& operator=(const Quaternion48 &vOther); + Quaternion48& operator=(const Quaternion &vOther); + operator Quaternion (); +private: + unsigned short x:16; + unsigned short y:16; + unsigned short z:15; + unsigned short wneg:1; +}; + + +inline Quaternion48::operator Quaternion () +{ + Quaternion tmp; + + tmp.x = ((int)x - 32768) * (1 / 32768.0); + tmp.y = ((int)y - 32768) * (1 / 32768.0); + tmp.z = ((int)z - 16384) * (1 / 16384.0); + tmp.w = sqrt( 1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z ); + if (wneg) + tmp.w = -tmp.w; + return tmp; +} + +inline Quaternion48& Quaternion48::operator=(const Quaternion &vOther) +{ + CHECK_VALID(vOther); + + x = Clamp( (int)(vOther.x * 32768) + 32768, 0, 65535 ); + y = Clamp( (int)(vOther.y * 32768) + 32768, 0, 65535 ); + z = Clamp( (int)(vOther.z * 16384) + 16384, 0, 32767 ); + wneg = (vOther.w < 0); + return *this; +} + +//========================================================= +// 32 bit Quaternion +//========================================================= + +class Quaternion32 +{ +public: + // Construction/destruction: + Quaternion32(void); + Quaternion32(vec_t X, vec_t Y, vec_t Z); + + // assignment + // Quaternion& operator=(const Quaternion48 &vOther); + Quaternion32& operator=(const Quaternion &vOther); + operator Quaternion (); +private: + unsigned int x:11; + unsigned int y:10; + unsigned int z:10; + unsigned int wneg:1; +}; + + +inline Quaternion32::operator Quaternion () +{ + Quaternion tmp; + + tmp.x = ((int)x - 1024) * (1 / 1024.0); + tmp.y = ((int)y - 512) * (1 / 512.0); + tmp.z = ((int)z - 512) * (1 / 512.0); + tmp.w = sqrt( 1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z ); + if (wneg) + tmp.w = -tmp.w; + return tmp; +} + +inline Quaternion32& Quaternion32::operator=(const Quaternion &vOther) +{ + CHECK_VALID(vOther); + + x = Clamp( (int)(vOther.x * 1024) + 1024, 0, 2047 ); + y = Clamp( (int)(vOther.y * 512) + 512, 0, 1023 ); + z = Clamp( (int)(vOther.z * 512) + 512, 0, 1023 ); + wneg = (vOther.w < 0); + return *this; +} + +//========================================================= +// 16 bit float +//========================================================= + + +const int float32bias = 127; +const int float16bias = 15; + +const float maxfloat16bits = 65504.0f; + +class float16 +{ +public: + //float16() {} + //float16( float f ) { m_storage.rawWord = ConvertFloatTo16bits(f); } + + void Init() { m_storage.rawWord = 0; } +// float16& operator=(const float16 &other) { m_storage.rawWord = other.m_storage.rawWord; return *this; } +// float16& operator=(const float &other) { m_storage.rawWord = ConvertFloatTo16bits(other); return *this; } +// operator unsigned short () { return m_storage.rawWord; } +// operator float () { return Convert16bitFloatTo32bits( m_storage.rawWord ); } + unsigned short GetBits() const + { + return m_storage.rawWord; + } + float GetFloat() const + { + return Convert16bitFloatTo32bits( m_storage.rawWord ); + } + void SetFloat( float in ) + { + m_storage.rawWord = ConvertFloatTo16bits( in ); + } + + bool IsInfinity() const + { + return m_storage.bits.biased_exponent == 31 && m_storage.bits.mantissa == 0; + } + bool IsNaN() const + { + return m_storage.bits.biased_exponent == 31 && m_storage.bits.mantissa != 0; + } + + bool operator==(const float16 other) const { return m_storage.rawWord == other.m_storage.rawWord; } + bool operator!=(const float16 other) const { return m_storage.rawWord != other.m_storage.rawWord; } + +// bool operator< (const float other) const { return GetFloat() < other; } +// bool operator> (const float other) const { return GetFloat() > other; } + +protected: + union float32bits + { + float rawFloat; + struct + { + unsigned int mantissa : 23; + unsigned int biased_exponent : 8; + unsigned int sign : 1; + } bits; + }; + + union float16bits + { + unsigned short rawWord; + struct + { + unsigned short mantissa : 10; + unsigned short biased_exponent : 5; + unsigned short sign : 1; + } bits; + }; + + static bool IsNaN( float16bits in ) + { + return in.bits.biased_exponent == 31 && in.bits.mantissa != 0; + } + static bool IsInfinity( float16bits in ) + { + return in.bits.biased_exponent == 31 && in.bits.mantissa == 0; + } + + // 0x0001 - 0x03ff + static unsigned short ConvertFloatTo16bits( float input ) + { + if ( input > maxfloat16bits ) + input = maxfloat16bits; + else if ( input < -maxfloat16bits ) + input = -maxfloat16bits; + + float16bits output; + float32bits inFloat; + + inFloat.rawFloat = input; + + output.bits.sign = inFloat.bits.sign; + + if ( (inFloat.bits.biased_exponent==0) && (inFloat.bits.mantissa==0) ) + { + // zero + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; + } + else if ( (inFloat.bits.biased_exponent==0) && (inFloat.bits.mantissa!=0) ) + { + // denorm -- denorm float maps to 0 half + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; + } + else if ( (inFloat.bits.biased_exponent==0xff) && (inFloat.bits.mantissa==0) ) + { +#if 0 + // infinity + output.bits.mantissa = 0; + output.bits.biased_exponent = 31; +#else + // infinity maps to maxfloat + output.bits.mantissa = 0x3ff; + output.bits.biased_exponent = 0x1e; +#endif + } + else if ( (inFloat.bits.biased_exponent==0xff) && (inFloat.bits.mantissa!=0) ) + { +#if 0 + // NaN + output.bits.mantissa = 1; + output.bits.biased_exponent = 31; +#else + // NaN maps to zero + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; +#endif + } + else + { + // regular number + int new_exp = inFloat.bits.biased_exponent-127; + + if (new_exp<-24) + { + // this maps to 0 + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; + } + + if (new_exp<-14) + { + // this maps to a denorm + output.bits.biased_exponent = 0; + unsigned int exp_val = ( unsigned int )( -14 - ( inFloat.bits.biased_exponent - float32bias ) ); + if( exp_val > 0 && exp_val < 11 ) + { + output.bits.mantissa = ( 1 << ( 10 - exp_val ) ) + ( inFloat.bits.mantissa >> ( 13 + exp_val ) ); + } + } + else if (new_exp>15) + { +#if 0 + // map this value to infinity + output.bits.mantissa = 0; + output.bits.biased_exponent = 31; +#else + // to big. . . maps to maxfloat + output.bits.mantissa = 0x3ff; + output.bits.biased_exponent = 0x1e; +#endif + } + else + { + output.bits.biased_exponent = new_exp+15; + output.bits.mantissa = (inFloat.bits.mantissa >> 13); + } + } + return output.rawWord; + } + + static float Convert16bitFloatTo32bits( unsigned short input ) + { + float32bits output; + const float16bits &inFloat = *((float16bits *)&input); + + if( IsInfinity( inFloat ) ) + { + return maxfloat16bits * ( ( inFloat.bits.sign == 1 ) ? -1.0f : 1.0f ); + } + if( IsNaN( inFloat ) ) + { + return 0.0; + } + if( inFloat.bits.biased_exponent == 0 && inFloat.bits.mantissa != 0 ) + { + // denorm + const float half_denorm = (1.0f/16384.0f); // 2^-14 + float mantissa = ((float)(inFloat.bits.mantissa)) / 1024.0f; + float sgn = (inFloat.bits.sign)? -1.0f :1.0f; + output.rawFloat = sgn*mantissa*half_denorm; + } + else + { + // regular number + unsigned mantissa = inFloat.bits.mantissa; + unsigned biased_exponent = inFloat.bits.biased_exponent; + unsigned sign = ((unsigned)inFloat.bits.sign) << 31; + biased_exponent = ( (biased_exponent - float16bias + float32bias) * (biased_exponent != 0) ) << 23; + mantissa <<= (23-10); + + *((unsigned *)&output) = ( mantissa | biased_exponent | sign ); + } + + return output.rawFloat; + } + + + float16bits m_storage; +}; + +class float16_with_assign : public float16 +{ +public: + float16_with_assign() {} + float16_with_assign( float f ) { m_storage.rawWord = ConvertFloatTo16bits(f); } + + float16& operator=(const float16 &other) { m_storage.rawWord = ((float16_with_assign &)other).m_storage.rawWord; return *this; } + float16& operator=(const float &other) { m_storage.rawWord = ConvertFloatTo16bits(other); return *this; } +// operator unsigned short () const { return m_storage.rawWord; } + operator float () const { return Convert16bitFloatTo32bits( m_storage.rawWord ); } +}; + +//========================================================= +// Fit a 3D vector in 48 bits +//========================================================= + +class Vector48 +{ +public: + // Construction/destruction: + Vector48(void) {} + Vector48(vec_t X, vec_t Y, vec_t Z) { x.SetFloat( X ); y.SetFloat( Y ); z.SetFloat( Z ); } + + // assignment + Vector48& operator=(const Vector &vOther); + operator Vector (); + + float operator[]( int i ) const { return (((float16 *)this)[i]).GetFloat(); } + + float16 x; + float16 y; + float16 z; +}; + +inline Vector48& Vector48::operator=(const Vector &vOther) +{ + CHECK_VALID(vOther); + + x.SetFloat( vOther.x ); + y.SetFloat( vOther.y ); + z.SetFloat( vOther.z ); + return *this; +} + + +inline Vector48::operator Vector () +{ + Vector tmp; + + tmp.x = x.GetFloat(); + tmp.y = y.GetFloat(); + tmp.z = z.GetFloat(); + + return tmp; +} + +//========================================================= +// Fit a 2D vector in 32 bits +//========================================================= + +class Vector2d32 +{ +public: + // Construction/destruction: + Vector2d32(void) {} + Vector2d32(vec_t X, vec_t Y) { x.SetFloat( X ); y.SetFloat( Y ); } + + // assignment + Vector2d32& operator=(const Vector &vOther); + Vector2d32& operator=(const Vector2D &vOther); + + operator Vector2D (); + + void Init( vec_t ix = 0.f, vec_t iy = 0.f); + + float16_with_assign x; + float16_with_assign y; +}; + +inline Vector2d32& Vector2d32::operator=(const Vector2D &vOther) +{ + x.SetFloat( vOther.x ); + y.SetFloat( vOther.y ); + return *this; +} + +inline Vector2d32::operator Vector2D () +{ + Vector2D tmp; + + tmp.x = x.GetFloat(); + tmp.y = y.GetFloat(); + + return tmp; +} + +inline void Vector2d32::Init( vec_t ix, vec_t iy ) +{ + x.SetFloat(ix); + y.SetFloat(iy); +} + +#if defined( _X360 ) +#pragma bitfield_order( pop ) +#endif + +#endif + diff --git a/public/mathlib/halton.h b/public/mathlib/halton.h new file mode 100644 index 0000000..762a1fc --- /dev/null +++ b/public/mathlib/halton.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// $Id$ + +// halton.h - classes, etc for generating numbers using the Halton pseudo-random sequence. See +// http://halton-sequences.wikiverse.org/. +// +// what this function is useful for is any sort of sampling/integration problem where +// you want to solve it by random sampling. Each call the NextValue() generates +// a random number between 0 and 1, in an unclumped manner, so that the space can be more +// or less evenly sampled with a minimum number of samples. +// +// It is NOT useful for generating random numbers dynamically, since the outputs aren't +// particularly random. +// +// To generate multidimensional sample values (points in a plane, etc), use two +// HaltonSequenceGenerator_t's, with different (primes) bases. + +#ifndef HALTON_H +#define HALTON_H + +#include +#include + +class HaltonSequenceGenerator_t +{ + int seed; + int base; + float fbase; //< base as a float + +public: + HaltonSequenceGenerator_t(int base); //< base MUST be prime, >=2 + + float GetElement(int element); + + inline float NextValue(void) + { + return GetElement(seed++); + } + +}; + + +class DirectionalSampler_t //< pseudo-random sphere sampling +{ + HaltonSequenceGenerator_t zdot; + HaltonSequenceGenerator_t vrot; +public: + DirectionalSampler_t(void) + : zdot(2),vrot(3) + { + } + + Vector NextValue(void) + { + float zvalue=zdot.NextValue(); + zvalue=2*zvalue-1.0f; // map from 0..1 to -1..1 + float phi=acos(zvalue); + // now, generate a random rotation angle for x/y + float theta = 2.0f*(float)M_PI*vrot.NextValue(); + float sin_p=sin(phi); + return Vector(cos(theta)*sin_p, + sin(theta)*sin_p, + zvalue); + + } +}; + + + + +#endif // halton_h diff --git a/public/mathlib/lightdesc.h b/public/mathlib/lightdesc.h new file mode 100644 index 0000000..1096d62 --- /dev/null +++ b/public/mathlib/lightdesc.h @@ -0,0 +1,173 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +// light structure definitions. +#ifndef LIGHTDESC_H +#define LIGHTDESC_H + +#include +#include + +//----------------------------------------------------------------------------- +// Light structure +//----------------------------------------------------------------------------- + +enum LightType_t +{ + MATERIAL_LIGHT_DISABLE = 0, + MATERIAL_LIGHT_POINT, + MATERIAL_LIGHT_DIRECTIONAL, + MATERIAL_LIGHT_SPOT, +}; + +enum LightType_OptimizationFlags_t +{ + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 = 1, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 = 2, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 = 4, + LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED = 8, +}; + +struct LightDesc_t +{ + LightType_t m_Type; //< MATERIAL_LIGHT_xxx + Vector m_Color; //< color+intensity + Vector m_Position; //< light source center position + Vector m_Direction; //< for SPOT, direction it is pointing + float m_Range; //< distance range for light.0=infinite + float m_Falloff; //< angular falloff exponent for spot lights + float m_Attenuation0; //< constant distance falloff term + float m_Attenuation1; //< linear term of falloff + float m_Attenuation2; //< quadatic term of falloff + float m_Theta; //< inner cone angle. no angular falloff + //< within this cone + float m_Phi; //< outer cone angle + + // the values below are derived from the above settings for optimizations + // These aren't used by DX8. . used for software lighting. + float m_ThetaDot; + float m_PhiDot; + unsigned int m_Flags; +protected: + float OneOver_ThetaDot_Minus_PhiDot; + float m_RangeSquared; +public: + + void RecalculateDerivedValues(void); // calculate m_xxDot, m_Type for changed parms + + LightDesc_t(void) + { + } + + // constructors for various useful subtypes + + // a point light with infinite range + LightDesc_t( const Vector &pos, const Vector &color ) + { + InitPoint( pos, color ); + } + + /// a simple light. cone boundaries in radians. you pass a look_at point and the + /// direciton is derived from that. + LightDesc_t( const Vector &pos, const Vector &color, const Vector &point_at, + float inner_cone_boundary, float outer_cone_boundary ) + { + InitSpot( pos, color, point_at, inner_cone_boundary, outer_cone_boundary ); + } + + void InitPoint( const Vector &pos, const Vector &color ); + void InitDirectional( const Vector &dir, const Vector &color ); + void InitSpot(const Vector &pos, const Vector &color, const Vector &point_at, + float inner_cone_boundary, float outer_cone_boundary ); + + /// Given 4 points and 4 normals, ADD lighting from this light into "color". + void ComputeLightAtPoints( const FourVectors &pos, const FourVectors &normal, + FourVectors &color, bool DoHalfLambert=false ) const; + void ComputeNonincidenceLightAtPoints( const FourVectors &pos, FourVectors &color ) const; + void ComputeLightAtPointsForDirectional( const FourVectors &pos, + const FourVectors &normal, + FourVectors &color, bool DoHalfLambert=false ) const; + + // warning - modifies color!!! set color first!! + void SetupOldStyleAttenuation( float fQuadatricAttn, float fLinearAttn, float fConstantAttn ); + + void SetupNewStyleAttenuation( float fFiftyPercentDistance, float fZeroPercentDistance ); + + +/// given a direction relative to the light source position, is this ray within the + /// light cone (for spotlights..non spots consider all rays to be within their cone) + bool IsDirectionWithinLightCone(const Vector &rdir) const + { + return ((m_Type!=MATERIAL_LIGHT_SPOT) || (rdir.Dot(m_Direction)>=m_PhiDot)); + } + + float OneOverThetaDotMinusPhiDot() const + { + return OneOver_ThetaDot_Minus_PhiDot; + } +}; + + +//----------------------------------------------------------------------------- +// a point light with infinite range +//----------------------------------------------------------------------------- +inline void LightDesc_t::InitPoint( const Vector &pos, const Vector &color ) +{ + m_Type=MATERIAL_LIGHT_POINT; + m_Color=color; + m_Position=pos; + m_Range=0.0; // infinite + m_Attenuation0=1.0; + m_Attenuation1=0; + m_Attenuation2=0; + RecalculateDerivedValues(); +} + + +//----------------------------------------------------------------------------- +// a directional light with infinite range +//----------------------------------------------------------------------------- +inline void LightDesc_t::InitDirectional( const Vector &dir, const Vector &color ) +{ + m_Type=MATERIAL_LIGHT_DIRECTIONAL; + m_Color=color; + m_Direction=dir; + m_Range=0.0; // infinite + m_Attenuation0=1.0; + m_Attenuation1=0; + m_Attenuation2=0; + RecalculateDerivedValues(); +} + + +//----------------------------------------------------------------------------- +// a simple light. cone boundaries in radians. you pass a look_at point and the +// direciton is derived from that. +//----------------------------------------------------------------------------- +inline void LightDesc_t::InitSpot(const Vector &pos, const Vector &color, const Vector &point_at, + float inner_cone_boundary, float outer_cone_boundary) +{ + m_Type=MATERIAL_LIGHT_SPOT; + m_Color=color; + m_Position=pos; + m_Direction=point_at; + m_Direction-=pos; + VectorNormalizeFast(m_Direction); + m_Falloff=5.0; // linear angle falloff + m_Theta=inner_cone_boundary; + m_Phi=outer_cone_boundary; + + m_Range=0.0; // infinite + + m_Attenuation0=1.0; + m_Attenuation1=0; + m_Attenuation2=0; + RecalculateDerivedValues(); +} + + +#endif + diff --git a/public/mathlib/math_pfns.h b/public/mathlib/math_pfns.h new file mode 100644 index 0000000..d43411c --- /dev/null +++ b/public/mathlib/math_pfns.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef _MATH_PFNS_H_ +#define _MATH_PFNS_H_ + +#if defined( _X360 ) +#include +#endif + +#if !defined( _X360 ) + +// These globals are initialized by mathlib and redirected based on available fpu features +extern float (*pfSqrt)(float x); +extern float (*pfRSqrt)(float x); +extern float (*pfRSqrtFast)(float x); +extern void (*pfFastSinCos)(float x, float *s, float *c); +extern float (*pfFastCos)(float x); + +// The following are not declared as macros because they are often used in limiting situations, +// and sometimes the compiler simply refuses to inline them for some reason +#define FastSqrt(x) (*pfSqrt)(x) +#define FastRSqrt(x) (*pfRSqrt)(x) +#define FastRSqrtFast(x) (*pfRSqrtFast)(x) +#define FastSinCos(x,s,c) (*pfFastSinCos)(x,s,c) +#define FastCos(x) (*pfFastCos)(x) + +#if defined(__i386__) || defined(_M_IX86) +// On x86, the inline FPU or SSE sqrt instruction is faster than +// the overhead of setting up a function call and saving/restoring +// the FPU or SSE register state and can be scheduled better, too. +#undef FastSqrt +#define FastSqrt(x) ::sqrtf(x) +#endif + +#endif // !_X360 + +#if defined( _X360 ) + +FORCEINLINE float _VMX_Sqrt( float x ) +{ + return __fsqrts( x ); +} + +FORCEINLINE float _VMX_RSqrt( float x ) +{ + float rroot = __frsqrte( x ); + + // Single iteration NewtonRaphson on reciprocal square root estimate + return (0.5f * rroot) * (3.0f - (x * rroot) * rroot); +} + +FORCEINLINE float _VMX_RSqrtFast( float x ) +{ + return __frsqrte( x ); +} + +FORCEINLINE void _VMX_SinCos( float a, float *pS, float *pC ) +{ + XMScalarSinCos( pS, pC, a ); +} + +FORCEINLINE float _VMX_Cos( float a ) +{ + return XMScalarCos( a ); +} + +// the 360 has fixed hw and calls directly +#define FastSqrt(x) _VMX_Sqrt(x) +#define FastRSqrt(x) _VMX_RSqrt(x) +#define FastRSqrtFast(x) _VMX_RSqrtFast(x) +#define FastSinCos(x,s,c) _VMX_SinCos(x,s,c) +#define FastCos(x) _VMX_Cos(x) + +#endif // _X360 + +#endif // _MATH_PFNS_H_ diff --git a/public/mathlib/mathlib.h b/public/mathlib/mathlib.h new file mode 100644 index 0000000..32a7778 --- /dev/null +++ b/public/mathlib/mathlib.h @@ -0,0 +1,2186 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef MATH_LIB_H +#define MATH_LIB_H + +#include +#include "tier0/basetypes.h" +#include "tier0/commonmacros.h" +#include "mathlib/vector.h" +#include "mathlib/vector2d.h" +#include "tier0/dbg.h" + +#include "mathlib/math_pfns.h" + +#if defined(__i386__) || defined(_M_IX86) +// For MMX intrinsics +#include +#endif + +// XXX remove me +#undef clamp + +// Uncomment this to enable FP exceptions in parts of the code. +// This can help track down FP bugs. However the code is not +// FP exception clean so this not a turnkey operation. +//#define FP_EXCEPTIONS_ENABLED + + +#ifdef FP_EXCEPTIONS_ENABLED +#include // For _clearfp and _controlfp_s +#endif + +// FPExceptionDisabler and FPExceptionEnabler taken from my blog post +// at http://www.altdevblogaday.com/2012/04/20/exceptional-floating-point/ + +// Declare an object of this type in a scope in order to suppress +// all floating-point exceptions temporarily. The old exception +// state will be reset at the end. +class FPExceptionDisabler +{ +public: +#ifdef FP_EXCEPTIONS_ENABLED + FPExceptionDisabler(); + ~FPExceptionDisabler(); + +private: + unsigned int mOldValues; +#else + FPExceptionDisabler() {} + ~FPExceptionDisabler() {} +#endif + +private: + // Make the copy constructor and assignment operator private + // and unimplemented to prohibit copying. + FPExceptionDisabler(const FPExceptionDisabler&); + FPExceptionDisabler& operator=(const FPExceptionDisabler&); +}; + +// Declare an object of this type in a scope in order to enable a +// specified set of floating-point exceptions temporarily. The old +// exception state will be reset at the end. +// This class can be nested. +class FPExceptionEnabler +{ +public: + // Overflow, divide-by-zero, and invalid-operation are the FP + // exceptions most frequently associated with bugs. +#ifdef FP_EXCEPTIONS_ENABLED + FPExceptionEnabler(unsigned int enableBits = _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID); + ~FPExceptionEnabler(); + +private: + unsigned int mOldValues; +#else + FPExceptionEnabler(unsigned int = 0) + { + } + ~FPExceptionEnabler() + { + } +#endif + +private: + // Make the copy constructor and assignment operator private + // and unimplemented to prohibit copying. + FPExceptionEnabler(const FPExceptionEnabler&); + FPExceptionEnabler& operator=(const FPExceptionEnabler&); +}; + + + +#ifdef DEBUG // stop crashing edit-and-continue +FORCEINLINE float clamp( float val, float minVal, float maxVal ) +{ + if ( maxVal < minVal ) + return maxVal; + else if( val < minVal ) + return minVal; + else if( val > maxVal ) + return maxVal; + else + return val; +} +#else // DEBUG +FORCEINLINE float clamp( float val, float minVal, float maxVal ) +{ +#if defined(__i386__) || defined(_M_IX86) + _mm_store_ss( &val, + _mm_min_ss( + _mm_max_ss( + _mm_load_ss(&val), + _mm_load_ss(&minVal) ), + _mm_load_ss(&maxVal) ) ); +#else + val = fpmax(minVal, val); + val = fpmin(maxVal, val); +#endif + return val; +} +#endif // DEBUG + +// +// Returns a clamped value in the range [min, max]. +// +template< class T > +inline T clamp( T const &val, T const &minVal, T const &maxVal ) +{ + if ( maxVal < minVal ) + return maxVal; + else if( val < minVal ) + return minVal; + else if( val > maxVal ) + return maxVal; + else + return val; +} + + +// plane_t structure +// !!! if this is changed, it must be changed in asm code too !!! +// FIXME: does the asm code even exist anymore? +// FIXME: this should move to a different file +struct cplane_t +{ + Vector normal; + float dist; + byte type; // for fast side tests + byte signbits; // signx + (signy<<1) + (signz<<1) + byte pad[2]; + +#ifdef VECTOR_NO_SLOW_OPERATIONS + cplane_t() {} + +private: + // No copy constructors allowed if we're in optimal mode + cplane_t(const cplane_t& vOther); +#endif +}; + +// structure offset for asm code +#define CPLANE_NORMAL_X 0 +#define CPLANE_NORMAL_Y 4 +#define CPLANE_NORMAL_Z 8 +#define CPLANE_DIST 12 +#define CPLANE_TYPE 16 +#define CPLANE_SIGNBITS 17 +#define CPLANE_PAD0 18 +#define CPLANE_PAD1 19 + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + + +//----------------------------------------------------------------------------- +// Frustum plane indices. +// WARNING: there is code that depends on these values +//----------------------------------------------------------------------------- + +enum +{ + FRUSTUM_RIGHT = 0, + FRUSTUM_LEFT = 1, + FRUSTUM_TOP = 2, + FRUSTUM_BOTTOM = 3, + FRUSTUM_NEARZ = 4, + FRUSTUM_FARZ = 5, + FRUSTUM_NUMPLANES = 6 +}; + +extern int SignbitsForPlane( cplane_t *out ); + +class Frustum_t +{ +public: + void SetPlane( int i, int nType, const Vector &vecNormal, float dist ) + { + m_Plane[i].normal = vecNormal; + m_Plane[i].dist = dist; + m_Plane[i].type = (byte)nType; + m_Plane[i].signbits = (byte)SignbitsForPlane( &m_Plane[i] ); + m_AbsNormal[i].Init( fabsf(vecNormal.x), fabsf(vecNormal.y), fabsf(vecNormal.z) ); + } + + inline const cplane_t *GetPlane( int i ) const { return &m_Plane[i]; } + inline const Vector &GetAbsNormal( int i ) const { return m_AbsNormal[i]; } + +private: + cplane_t m_Plane[FRUSTUM_NUMPLANES]; + Vector m_AbsNormal[FRUSTUM_NUMPLANES]; +}; + +// Computes Y fov from an X fov and a screen aspect ratio + X from Y +float CalcFovY( float flFovX, float flScreenAspect ); +float CalcFovX( float flFovY, float flScreenAspect ); + +// Generate a frustum based on perspective view parameters +// NOTE: FOV is specified in degrees, as the *full* view angle (not half-angle) +void GeneratePerspectiveFrustum( const Vector& origin, const QAngle &angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t &frustum ); +void GeneratePerspectiveFrustum( const Vector& origin, const Vector &forward, const Vector &right, const Vector &up, float flZNear, float flZFar, float flFovX, float flFovY, Frustum_t &frustum ); + +// Cull the world-space bounding box to the specified frustum. +bool R_CullBox( const Vector& mins, const Vector& maxs, const Frustum_t &frustum ); +bool R_CullBoxSkipNear( const Vector& mins, const Vector& maxs, const Frustum_t &frustum ); + +struct matrix3x4_t +{ + matrix3x4_t() {} + matrix3x4_t( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23 ) + { + m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03; + m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13; + m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23; + } + + //----------------------------------------------------------------------------- + // Creates a matrix where the X axis = forward + // the Y axis = left, and the Z axis = up + //----------------------------------------------------------------------------- + void Init( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin ) + { + m_flMatVal[0][0] = xAxis.x; m_flMatVal[0][1] = yAxis.x; m_flMatVal[0][2] = zAxis.x; m_flMatVal[0][3] = vecOrigin.x; + m_flMatVal[1][0] = xAxis.y; m_flMatVal[1][1] = yAxis.y; m_flMatVal[1][2] = zAxis.y; m_flMatVal[1][3] = vecOrigin.y; + m_flMatVal[2][0] = xAxis.z; m_flMatVal[2][1] = yAxis.z; m_flMatVal[2][2] = zAxis.z; m_flMatVal[2][3] = vecOrigin.z; + } + + //----------------------------------------------------------------------------- + // Creates a matrix where the X axis = forward + // the Y axis = left, and the Z axis = up + //----------------------------------------------------------------------------- + matrix3x4_t( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin ) + { + Init( xAxis, yAxis, zAxis, vecOrigin ); + } + + inline void Invalidate( void ) + { + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 4; j++) + { + m_flMatVal[i][j] = VEC_T_NAN; + } + } + } + + float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; } + const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; } + float *Base() { return &m_flMatVal[0][0]; } + const float *Base() const { return &m_flMatVal[0][0]; } + + float m_flMatVal[3][4]; +}; + + +#ifndef M_PI + #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#define M_PI_F ((float)(M_PI)) // Shouldn't collide with anything. + +// NJS: Inlined to prevent floats from being autopromoted to doubles, as with the old system. +#ifndef RAD2DEG + #define RAD2DEG( x ) ( (float)(x) * (float)(180.f / M_PI_F) ) +#endif + +#ifndef DEG2RAD + #define DEG2RAD( x ) ( (float)(x) * (float)(M_PI_F / 180.f) ) +#endif + +// Used to represent sides of things like planes. +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 +#define SIDE_CROSS -2 // necessary for polylib.c + +#define ON_VIS_EPSILON 0.01 // necessary for vvis (flow.c) -- again look into moving later! +#define EQUAL_EPSILON 0.001 // necessary for vbsp (faces.c) -- should look into moving it there? + +extern bool s_bMathlibInitialized; + +extern const Vector vec3_origin; +extern const QAngle vec3_angle; +extern const Quaternion quat_identity; +extern const Vector vec3_invalid; +extern const int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +FORCEINLINE vec_t DotProduct(const vec_t *v1, const vec_t *v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} +FORCEINLINE void VectorSubtract(const vec_t *a, const vec_t *b, vec_t *c) +{ + c[0]=a[0]-b[0]; + c[1]=a[1]-b[1]; + c[2]=a[2]-b[2]; +} +FORCEINLINE void VectorAdd(const vec_t *a, const vec_t *b, vec_t *c) +{ + c[0]=a[0]+b[0]; + c[1]=a[1]+b[1]; + c[2]=a[2]+b[2]; +} +FORCEINLINE void VectorCopy(const vec_t *a, vec_t *b) +{ + b[0]=a[0]; + b[1]=a[1]; + b[2]=a[2]; +} +FORCEINLINE void VectorClear(vec_t *a) +{ + a[0]=a[1]=a[2]=0; +} + +FORCEINLINE float VectorMaximum(const vec_t *v) +{ + return vmax( v[0], vmax( v[1], v[2] ) ); +} + +FORCEINLINE float VectorMaximum(const Vector& v) +{ + return vmax( v.x, vmax( v.y, v.z ) ); +} + +FORCEINLINE void VectorScale (const float* in, vec_t scale, float* out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + + +// Cannot be forceinline as they have overloads: +inline void VectorFill(vec_t *a, float b) +{ + a[0]=a[1]=a[2]=b; +} + +inline void VectorNegate(vec_t *a) +{ + a[0]=-a[0]; + a[1]=-a[1]; + a[2]=-a[2]; +} + + +//#define VectorMaximum(a) ( vmax( (a)[0], vmax( (a)[1], (a)[2] ) ) ) +#define Vector2Clear(x) {(x)[0]=(x)[1]=0;} +#define Vector2Negate(x) {(x)[0]=-((x)[0]);(x)[1]=-((x)[1]);} +#define Vector2Copy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];} +#define Vector2Subtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];} +#define Vector2Add(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];} +#define Vector2Scale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];} + +// NJS: Some functions in VBSP still need to use these for dealing with mixing vec4's and shorts with vec_t's. +// remove when no longer needed. +#define VECTOR_COPY( A, B ) do { (B)[0] = (A)[0]; (B)[1] = (A)[1]; (B)[2]=(A)[2]; } while(0) +#define DOT_PRODUCT( A, B ) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] ) + +FORCEINLINE void VectorMAInline( const float* start, float scale, const float* direction, float* dest ) +{ + dest[0]=start[0]+direction[0]*scale; + dest[1]=start[1]+direction[1]*scale; + dest[2]=start[2]+direction[2]*scale; +} + +FORCEINLINE void VectorMAInline( const Vector& start, float scale, const Vector& direction, Vector& dest ) +{ + dest.x=start.x+direction.x*scale; + dest.y=start.y+direction.y*scale; + dest.z=start.z+direction.z*scale; +} + +FORCEINLINE void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest ) +{ + VectorMAInline(start, scale, direction, dest); +} + +FORCEINLINE void VectorMA( const float * start, float scale, const float *direction, float *dest ) +{ + VectorMAInline(start, scale, direction, dest); +} + + +int VectorCompare (const float *v1, const float *v2); + +inline float VectorLength(const float *v) +{ + return FastSqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + FLT_EPSILON ); +} + +void CrossProduct (const float *v1, const float *v2, float *cross); + +qboolean VectorsEqual( const float *v1, const float *v2 ); + +inline vec_t RoundInt (vec_t in) +{ + return floorf(in + 0.5f); +} + +int Q_log2(int val); + +// Math routines done in optimized assembly math package routines +void inline SinCos( float radians, float *sine, float *cosine ) +{ +#if defined( _X360 ) + XMScalarSinCos( sine, cosine, radians ); +#elif defined( PLATFORM_WINDOWS_PC32 ) + _asm + { + fld DWORD PTR [radians] + fsincos + + mov edx, DWORD PTR [cosine] + mov eax, DWORD PTR [sine] + + fstp DWORD PTR [edx] + fstp DWORD PTR [eax] + } +#elif defined( PLATFORM_WINDOWS_PC64 ) + *sine = sin( radians ); + *cosine = cos( radians ); +#elif defined( POSIX ) + double __cosr, __sinr; + __asm ("fsincos" : "=t" (__cosr), "=u" (__sinr) : "0" (radians)); + + *sine = __sinr; + *cosine = __cosr; +#endif +} + +#define SIN_TABLE_SIZE 256 +#define FTOIBIAS 12582912.f +extern float SinCosTable[SIN_TABLE_SIZE]; + +inline float TableCos( float theta ) +{ + union + { + int i; + float f; + } ftmp; + + // ideally, the following should compile down to: theta * constant + constant, changing any of these constants from defines sometimes fubars this. + ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + ( FTOIBIAS + ( SIN_TABLE_SIZE / 4 ) ); + return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ]; +} + +inline float TableSin( float theta ) +{ + union + { + int i; + float f; + } ftmp; + + // ideally, the following should compile down to: theta * constant + constant + ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + FTOIBIAS; + return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ]; +} + +template +FORCEINLINE T Square( T const &a ) +{ + return a * a; +} + + +// return the smallest power of two >= x. +// returns 0 if x == 0 or x > 0x80000000 (ie numbers that would be negative if x was signed) +// NOTE: the old code took an int, and if you pass in an int of 0x80000000 casted to a uint, +// you'll get 0x80000000, which is correct for uints, instead of 0, which was correct for ints +FORCEINLINE uint SmallestPowerOfTwoGreaterOrEqual( uint x ) +{ + x -= 1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} + +// return the largest power of two <= x. Will return 0 if passed 0 +FORCEINLINE uint LargestPowerOfTwoLessThanOrEqual( uint x ) +{ + if ( x >= 0x80000000 ) + return 0x80000000; + + return SmallestPowerOfTwoGreaterOrEqual( x + 1 ) >> 1; +} + + +// Math routines for optimizing division +void FloorDivMod (double numer, double denom, int *quotient, int *rem); +int GreatestCommonDivisor (int i1, int i2); + +// Test for FPU denormal mode +bool IsDenormal( const float &val ); + +// MOVEMENT INFO +enum +{ + PITCH = 0, // up / down + YAW, // left / right + ROLL // fall over +}; + +void MatrixAngles( const matrix3x4_t & matrix, float *angles ); // !!!! +void MatrixVectors( const matrix3x4_t &matrix, Vector* pForward, Vector *pRight, Vector *pUp ); +void VectorTransform (const float *in1, const matrix3x4_t & in2, float *out); +void VectorITransform (const float *in1, const matrix3x4_t & in2, float *out); +void VectorRotate( const float *in1, const matrix3x4_t & in2, float *out); +void VectorRotate( const Vector &in1, const QAngle &in2, Vector &out ); +void VectorRotate( const Vector &in1, const Quaternion &in2, Vector &out ); +void VectorIRotate( const float *in1, const matrix3x4_t & in2, float *out); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +QAngle TransformAnglesToLocalSpace( const QAngle &angles, const matrix3x4_t &parentMatrix ); +QAngle TransformAnglesToWorldSpace( const QAngle &angles, const matrix3x4_t &parentMatrix ); + +#endif + +void MatrixInitialize( matrix3x4_t &mat, const Vector &vecOrigin, const Vector &vecXAxis, const Vector &vecYAxis, const Vector &vecZAxis ); +void MatrixCopy( const matrix3x4_t &in, matrix3x4_t &out ); +void MatrixInvert( const matrix3x4_t &in, matrix3x4_t &out ); + +// Matrix equality test +bool MatricesAreEqual( const matrix3x4_t &src1, const matrix3x4_t &src2, float flTolerance = 1e-5 ); + +void MatrixGetColumn( const matrix3x4_t &in, int column, Vector &out ); +void MatrixSetColumn( const Vector &in, int column, matrix3x4_t &out ); + +inline void MatrixGetTranslation( const matrix3x4_t &in, Vector &out ) +{ + MatrixGetColumn ( in, 3, out ); +} + +inline void MatrixSetTranslation( const Vector &in, matrix3x4_t &out ) +{ + MatrixSetColumn ( in, 3, out ); +} + +void MatrixScaleBy ( const float flScale, matrix3x4_t &out ); +void MatrixScaleByZero ( matrix3x4_t &out ); + +//void DecomposeRotation( const matrix3x4_t &mat, float *out ); +void ConcatRotations (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out); +void ConcatTransforms (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out); + +// For identical interface w/ VMatrix +inline void MatrixMultiply ( const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out ) +{ + ConcatTransforms( in1, in2, out ); +} + +void QuaternionSlerp( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionSlerpNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionBlend( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionBlendNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionIdentityBlend( const Quaternion &p, float t, Quaternion &qt ); +float QuaternionAngleDiff( const Quaternion &p, const Quaternion &q ); +void QuaternionScale( const Quaternion &p, float t, Quaternion &q ); +void QuaternionAlign( const Quaternion &p, const Quaternion &q, Quaternion &qt ); +float QuaternionDotProduct( const Quaternion &p, const Quaternion &q ); +void QuaternionConjugate( const Quaternion &p, Quaternion &q ); +void QuaternionInvert( const Quaternion &p, Quaternion &q ); +float QuaternionNormalize( Quaternion &q ); +void QuaternionAdd( const Quaternion &p, const Quaternion &q, Quaternion &qt ); +void QuaternionMult( const Quaternion &p, const Quaternion &q, Quaternion &qt ); +void QuaternionMatrix( const Quaternion &q, matrix3x4_t &matrix ); +void QuaternionMatrix( const Quaternion &q, const Vector &pos, matrix3x4_t &matrix ); +void QuaternionAngles( const Quaternion &q, QAngle &angles ); +void AngleQuaternion( const QAngle& angles, Quaternion &qt ); +void QuaternionAngles( const Quaternion &q, RadianEuler &angles ); +void AngleQuaternion( RadianEuler const &angles, Quaternion &qt ); +void QuaternionAxisAngle( const Quaternion &q, Vector &axis, float &angle ); +void AxisAngleQuaternion( const Vector &axis, float angle, Quaternion &q ); +void BasisToQuaternion( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Quaternion &q ); +void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q ); + +// A couple methods to find the dot product of a vector with a matrix row or column... +inline float MatrixRowDotProduct( const matrix3x4_t &in1, int row, const Vector& in2 ) +{ + Assert( (row >= 0) && (row < 3) ); + return DotProduct( in1[row], in2.Base() ); +} + +inline float MatrixColumnDotProduct( const matrix3x4_t &in1, int col, const Vector& in2 ) +{ + Assert( (col >= 0) && (col < 4) ); + return in1[0][col] * in2[0] + in1[1][col] * in2[1] + in1[2][col] * in2[2]; +} + +int __cdecl BoxOnPlaneSide (const float *emins, const float *emaxs, const cplane_t *plane); + +inline float anglemod(float a) +{ + a = (360.f/65536) * ((int)(a*(65536.f/360.0f)) & 65535); + return a; +} + +// Remap a value in the range [A,B] to [C,D]. +inline float RemapVal( float val, float A, float B, float C, float D) +{ + if ( A == B ) + return val >= B ? D : C; + return C + (D - C) * (val - A) / (B - A); +} + +inline float RemapValClamped( float val, float A, float B, float C, float D) +{ + if ( A == B ) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + cVal = clamp( cVal, 0.0f, 1.0f ); + + return C + (D - C) * cVal; +} + +// Returns A + (B-A)*flPercent. +// float Lerp( float flPercent, float A, float B ); +template +FORCEINLINE T Lerp( float flPercent, T const &A, T const &B ) +{ + return A + (B - A) * flPercent; +} + +FORCEINLINE float Sqr( float f ) +{ + return f*f; +} + +// 5-argument floating point linear interpolation. +// FLerp(f1,f2,i1,i2,x)= +// f1 at x=i1 +// f2 at x=i2 +// smooth lerp between f1 and f2 at x>i1 and xi2 +// +// If you know a function f(x)'s value (f1) at position i1, and its value (f2) at position i2, +// the function can be linearly interpolated with FLerp(f1,f2,i1,i2,x) +// i2=i1 will cause a divide by zero. +static inline float FLerp(float f1, float f2, float i1, float i2, float x) +{ + return f1+(f2-f1)*(x-i1)/(i2-i1); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +// YWB: Specialization for interpolating euler angles via quaternions... +template<> FORCEINLINE QAngle Lerp( float flPercent, const QAngle& q1, const QAngle& q2 ) +{ + // Avoid precision errors + if ( q1 == q2 ) + return q1; + + Quaternion src, dest; + + // Convert to quaternions + AngleQuaternion( q1, src ); + AngleQuaternion( q2, dest ); + + Quaternion result; + + // Slerp + QuaternionSlerp( src, dest, flPercent, result ); + + // Convert to euler + QAngle output; + QuaternionAngles( result, output ); + return output; +} + +#else + +#pragma error + +// NOTE NOTE: I haven't tested this!! It may not work! Check out interpolatedvar.cpp in the client dll to try it +template<> FORCEINLINE QAngleByValue Lerp( float flPercent, const QAngleByValue& q1, const QAngleByValue& q2 ) +{ + // Avoid precision errors + if ( q1 == q2 ) + return q1; + + Quaternion src, dest; + + // Convert to quaternions + AngleQuaternion( q1, src ); + AngleQuaternion( q2, dest ); + + Quaternion result; + + // Slerp + QuaternionSlerp( src, dest, flPercent, result ); + + // Convert to euler + QAngleByValue output; + QuaternionAngles( result, output ); + return output; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +/// Same as swap(), but won't cause problems with std::swap +template +FORCEINLINE void V_swap( T& x, T& y ) +{ + T temp = x; + x = y; + y = temp; +} + +template FORCEINLINE T AVG(T a, T b) +{ + return (a+b)/2; +} + +// number of elements in an array of static size +#define NELEMS(x) ARRAYSIZE(x) + +// XYZ macro, for printf type functions - ex printf("%f %f %f",XYZ(myvector)); +#define XYZ(v) (v).x,(v).y,(v).z + + +inline float Sign( float x ) +{ + return (x <0.0f) ? -1.0f : 1.0f; +} + +// +// Clamps the input integer to the given array bounds. +// Equivalent to the following, but without using any branches: +// +// if( n < 0 ) return 0; +// else if ( n > maxindex ) return maxindex; +// else return n; +// +// This is not always a clear performance win, but when you have situations where a clamped +// value is thrashing against a boundary this is a big win. (ie, valid, invalid, valid, invalid, ...) +// +// Note: This code has been run against all possible integers. +// +inline int ClampArrayBounds( int n, unsigned maxindex ) +{ + // mask is 0 if less than 4096, 0xFFFFFFFF if greater than + unsigned int inrangemask = 0xFFFFFFFF + (((unsigned) n) > maxindex ); + unsigned int lessthan0mask = 0xFFFFFFFF + ( n >= 0 ); + + // If the result was valid, set the result, (otherwise sets zero) + int result = (inrangemask & n); + + // if the result was out of range or zero. + result |= ((~inrangemask) & (~lessthan0mask)) & maxindex; + + return result; +} + + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) + +//----------------------------------------------------------------------------- +// FIXME: Vector versions.... the float versions will go away hopefully soon! +//----------------------------------------------------------------------------- + +void AngleVectors (const QAngle& angles, Vector *forward); +void AngleVectors (const QAngle& angles, Vector *forward, Vector *right, Vector *up); +void AngleVectorsTranspose (const QAngle& angles, Vector *forward, Vector *right, Vector *up); +void AngleMatrix (const QAngle &angles, matrix3x4_t &mat ); +void AngleMatrix( const QAngle &angles, const Vector &position, matrix3x4_t &mat ); +void AngleMatrix (const RadianEuler &angles, matrix3x4_t &mat ); +void AngleMatrix( RadianEuler const &angles, const Vector &position, matrix3x4_t &mat ); +void AngleIMatrix (const QAngle &angles, matrix3x4_t &mat ); +void AngleIMatrix (const QAngle &angles, const Vector &position, matrix3x4_t &mat ); +void AngleIMatrix (const RadianEuler &angles, matrix3x4_t &mat ); +void VectorAngles( const Vector &forward, QAngle &angles ); +void VectorAngles( const Vector &forward, const Vector &pseudoup, QAngle &angles ); +void VectorMatrix( const Vector &forward, matrix3x4_t &mat ); +void VectorVectors( const Vector &forward, Vector &right, Vector &up ); +void SetIdentityMatrix( matrix3x4_t &mat ); +void SetScaleMatrix( float x, float y, float z, matrix3x4_t &dst ); +void MatrixBuildRotationAboutAxis( const Vector &vAxisOfRot, float angleDegrees, matrix3x4_t &dst ); + +inline void SetScaleMatrix( float flScale, matrix3x4_t &dst ) +{ + SetScaleMatrix( flScale, flScale, flScale, dst ); +} + +inline void SetScaleMatrix( const Vector& scale, matrix3x4_t &dst ) +{ + SetScaleMatrix( scale.x, scale.y, scale.z, dst ); +} + +// Computes the inverse transpose +void MatrixTranspose( matrix3x4_t& mat ); +void MatrixTranspose( const matrix3x4_t& src, matrix3x4_t& dst ); +void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst ); + +inline void PositionMatrix( const Vector &position, matrix3x4_t &mat ) +{ + MatrixSetColumn( position, 3, mat ); +} + +inline void MatrixPosition( const matrix3x4_t &matrix, Vector &position ) +{ + MatrixGetColumn( matrix, 3, position ); +} + +inline void VectorRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorRotate( &in1.x, in2, &out.x ); +} + +inline void VectorIRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorIRotate( &in1.x, in2, &out.x ); +} + +inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles ) +{ + MatrixAngles( matrix, &angles.x ); +} + +inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles, Vector &position ) +{ + MatrixAngles( matrix, angles ); + MatrixPosition( matrix, position ); +} + +inline void MatrixAngles( const matrix3x4_t &matrix, RadianEuler &angles ) +{ + MatrixAngles( matrix, &angles.x ); + + angles.Init( DEG2RAD( angles.z ), DEG2RAD( angles.x ), DEG2RAD( angles.y ) ); +} + +void MatrixAngles( const matrix3x4_t &mat, RadianEuler &angles, Vector &position ); + +void MatrixAngles( const matrix3x4_t &mat, Quaternion &q, Vector &position ); + +inline int VectorCompare (const Vector& v1, const Vector& v2) +{ + return v1 == v2; +} + +inline void VectorTransform (const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorTransform( &in1.x, in2, &out.x ); +} + +inline void VectorITransform (const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorITransform( &in1.x, in2, &out.x ); +} + +/* +inline void DecomposeRotation( const matrix3x4_t &mat, Vector &out ) +{ + DecomposeRotation( mat, &out.x ); +} +*/ + +inline int BoxOnPlaneSide (const Vector& emins, const Vector& emaxs, const cplane_t *plane ) +{ + return BoxOnPlaneSide( &emins.x, &emaxs.x, plane ); +} + +inline void VectorFill(Vector& a, float b) +{ + a[0]=a[1]=a[2]=b; +} + +inline void VectorNegate(Vector& a) +{ + a[0] = -a[0]; + a[1] = -a[1]; + a[2] = -a[2]; +} + +inline vec_t VectorAvg(Vector& a) +{ + return ( a[0] + a[1] + a[2] ) / 3; +} + +//----------------------------------------------------------------------------- +// Box/plane test (slow version) +//----------------------------------------------------------------------------- +inline int FASTCALL BoxOnPlaneSide2 (const Vector& emins, const Vector& emaxs, const cplane_t *p, float tolerance = 0.f ) +{ + Vector corners[2]; + + if (p->normal[0] < 0) + { + corners[0][0] = emins[0]; + corners[1][0] = emaxs[0]; + } + else + { + corners[1][0] = emins[0]; + corners[0][0] = emaxs[0]; + } + + if (p->normal[1] < 0) + { + corners[0][1] = emins[1]; + corners[1][1] = emaxs[1]; + } + else + { + corners[1][1] = emins[1]; + corners[0][1] = emaxs[1]; + } + + if (p->normal[2] < 0) + { + corners[0][2] = emins[2]; + corners[1][2] = emaxs[2]; + } + else + { + corners[1][2] = emins[2]; + corners[0][2] = emaxs[2]; + } + + int sides = 0; + + float dist1 = DotProduct (p->normal, corners[0]) - p->dist; + if (dist1 >= tolerance) + sides = 1; + + float dist2 = DotProduct (p->normal, corners[1]) - p->dist; + if (dist2 < -tolerance) + sides |= 2; + + return sides; +} + +//----------------------------------------------------------------------------- +// Helpers for bounding box construction +//----------------------------------------------------------------------------- + +void ClearBounds (Vector& mins, Vector& maxs); +void AddPointToBounds (const Vector& v, Vector& mins, Vector& maxs); + +// +// COLORSPACE/GAMMA CONVERSION STUFF +// +void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright ); + +// convert texture to linear 0..1 value +inline float TexLightToLinear( int c, int exponent ) +{ + extern float power2_n[256]; + Assert( exponent >= -128 && exponent <= 127 ); + return ( float )c * power2_n[exponent+128]; +} + + +// convert texture to linear 0..1 value +int LinearToTexture( float f ); +// converts 0..1 linear value to screen gamma (0..255) +int LinearToScreenGamma( float f ); +float TextureToLinear( int c ); + +// compressed color format +struct ColorRGBExp32 +{ + byte r, g, b; + signed char exponent; +}; + +void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out ); +void VectorToColorRGBExp32( const Vector& v, ColorRGBExp32 &c ); + +// solve for "x" where "a x^2 + b x + c = 0", return true if solution exists +bool SolveQuadratic( float a, float b, float c, float &root1, float &root2 ); + +// solves for "a, b, c" where "a x^2 + b x + c = y", return true if solution exists +bool SolveInverseQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c ); + +// solves for a,b,c specified as above, except that it always creates a monotonically increasing or +// decreasing curve if the data is monotonically increasing or decreasing. In order to enforce the +// monoticity condition, it is possible that the resulting quadratic will only approximate the data +// instead of interpolating it. This code is not especially fast. +bool SolveInverseQuadraticMonotonic( float x1, float y1, float x2, float y2, + float x3, float y3, float &a, float &b, float &c ); + + + + +// solves for "a, b, c" where "1/(a x^2 + b x + c ) = y", return true if solution exists +bool SolveInverseReciprocalQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c ); + +// rotate a vector around the Z axis (YAW) +void VectorYawRotate( const Vector& in, float flYaw, Vector &out); + + +// Bias takes an X value between 0 and 1 and returns another value between 0 and 1 +// The curve is biased towards 0 or 1 based on biasAmt, which is between 0 and 1. +// Lower values of biasAmt bias the curve towards 0 and higher values bias it towards 1. +// +// For example, with biasAmt = 0.2, the curve looks like this: +// +// 1 +// | * +// | * +// | * +// | ** +// | ** +// | **** +// |********* +// |___________________ +// 0 1 +// +// +// With biasAmt = 0.8, the curve looks like this: +// +// 1 +// | ************** +// | ** +// | * +// | * +// |* +// |* +// |* +// |___________________ +// 0 1 +// +// With a biasAmt of 0.5, Bias returns X. +float Bias( float x, float biasAmt ); + + +// Gain is similar to Bias, but biasAmt biases towards or away from 0.5. +// Lower bias values bias towards 0.5 and higher bias values bias away from it. +// +// For example, with biasAmt = 0.2, the curve looks like this: +// +// 1 +// | * +// | * +// | ** +// | *************** +// | ** +// | * +// |* +// |___________________ +// 0 1 +// +// +// With biasAmt = 0.8, the curve looks like this: +// +// 1 +// | ***** +// | *** +// | * +// | * +// | * +// | *** +// |***** +// |___________________ +// 0 1 +float Gain( float x, float biasAmt ); + + +// SmoothCurve maps a 0-1 value into another 0-1 value based on a cosine wave +// where the derivatives of the function at 0 and 1 (and 0.5) are 0. This is useful for +// any fadein/fadeout effect where it should start and end smoothly. +// +// The curve looks like this: +// +// 1 +// | ** +// | * * +// | * * +// | * * +// | * * +// | ** ** +// |*** *** +// |___________________ +// 0 1 +// +float SmoothCurve( float x ); + + +// This works like SmoothCurve, with two changes: +// +// 1. Instead of the curve peaking at 0.5, it will peak at flPeakPos. +// (So if you specify flPeakPos=0.2, then the peak will slide to the left). +// +// 2. flPeakSharpness is a 0-1 value controlling the sharpness of the peak. +// Low values blunt the peak and high values sharpen the peak. +float SmoothCurve_Tweak( float x, float flPeakPos=0.5, float flPeakSharpness=0.5 ); + + +//float ExponentialDecay( float halflife, float dt ); +//float ExponentialDecay( float decayTo, float decayTime, float dt ); + +// halflife is time for value to reach 50% +inline float ExponentialDecay( float halflife, float dt ) +{ + // log(0.5) == -0.69314718055994530941723212145818 + return expf( -0.69314718f / halflife * dt); +} + +// decayTo is factor the value should decay to in decayTime +inline float ExponentialDecay( float decayTo, float decayTime, float dt ) +{ + return expf( logf( decayTo ) / decayTime * dt); +} + +// Get the integrated distanced traveled +// decayTo is factor the value should decay to in decayTime +// dt is the time relative to the last velocity update +inline float ExponentialDecayIntegral( float decayTo, float decayTime, float dt ) +{ + return (powf( decayTo, dt / decayTime) * decayTime - decayTime) / logf( decayTo ); +} + +// hermite basis function for smooth interpolation +// Similar to Gain() above, but very cheap to call +// value should be between 0 & 1 inclusive +inline float SimpleSpline( float value ) +{ + float valueSquared = value * value; + + // Nice little ease-in, ease-out spline-like curve + return (3 * valueSquared - 2 * valueSquared * value); +} + +// remaps a value in [startInterval, startInterval+rangeInterval] from linear to +// spline using SimpleSpline +inline float SimpleSplineRemapVal( float val, float A, float B, float C, float D) +{ + if ( A == B ) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + return C + (D - C) * SimpleSpline( cVal ); +} + +// remaps a value in [startInterval, startInterval+rangeInterval] from linear to +// spline using SimpleSpline +inline float SimpleSplineRemapValClamped( float val, float A, float B, float C, float D ) +{ + if ( A == B ) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + cVal = clamp( cVal, 0.0f, 1.0f ); + return C + (D - C) * SimpleSpline( cVal ); +} + +FORCEINLINE int RoundFloatToInt(float f) +{ +#if defined(__i386__) || defined(_M_IX86) || defined( PLATFORM_WINDOWS_PC64 ) || defined(__x86_64__) + return _mm_cvtss_si32(_mm_load_ss(&f)); +#elif defined( _X360 ) +#ifdef Assert + Assert( IsFPUControlWordSet() ); +#endif + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw( f ); + return pResult[1]; +#else +#error Unknown architecture +#endif +} + +FORCEINLINE unsigned char RoundFloatToByte(float f) +{ + int nResult = RoundFloatToInt(f); +#ifdef Assert + Assert( (nResult & ~0xFF) == 0 ); +#endif + return (unsigned char) nResult; +} + +FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f) +{ +#if defined( _X360 ) +#ifdef Assert + Assert( IsFPUControlWordSet() ); +#endif + union + { + double flResult; + int pIntResult[2]; + unsigned long pResult[2]; + }; + flResult = __fctiw( f ); + Assert( pIntResult[1] >= 0 ); + return pResult[1]; +#else // !X360 + +#if defined( PLATFORM_WINDOWS_PC64 ) + uint nRet = ( uint ) f; + if ( nRet & 1 ) + { + if ( ( f - floor( f ) >= 0.5 ) ) + { + nRet++; + } + } + else + { + if ( ( f - floor( f ) > 0.5 ) ) + { + nRet++; + } + } + return nRet; +#else // PLATFORM_WINDOWS_PC64 + unsigned char nResult[8]; + + #if defined( _WIN32 ) + __asm + { + fld f + fistp qword ptr nResult + } + #elif POSIX + __asm __volatile__ ( + "fistpl %0;": "=m" (nResult): "t" (f) : "st" + ); + #endif + + return *((unsigned long*)nResult); +#endif // PLATFORM_WINDOWS_PC64 +#endif // !X360 +} + +FORCEINLINE bool IsIntegralValue( float flValue, float flTolerance = 0.001f ) +{ + return fabs( RoundFloatToInt( flValue ) - flValue ) < flTolerance; +} + +// Fast, accurate ftol: +FORCEINLINE int Float2Int( float a ) +{ +#if defined( _X360 ) + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiwz( a ); + return pResult[1]; +#else // !X360 + // Rely on compiler to generate CVTTSS2SI on x86 + return (int) a; +#endif +} + +// Over 15x faster than: (int)floor(value) +inline int Floor2Int( float a ) +{ + int RetVal; +#if defined( __i386__ ) + // Convert to int and back, compare, subtract one if too big + __m128 a128 = _mm_set_ss(a); + RetVal = _mm_cvtss_si32(a128); + __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal); + RetVal -= _mm_comigt_ss( rounded128, a128 ); +#else + RetVal = static_cast( floor(a) ); +#endif + return RetVal; +} + +//----------------------------------------------------------------------------- +// Fast color conversion from float to unsigned char +//----------------------------------------------------------------------------- +FORCEINLINE unsigned int FastFToC( float c ) +{ +#if defined( __i386__ ) + // IEEE float bit manipulation works for values between [0, 1<<23) + union { float f; int i; } convert = { c*255.0f + (float)(1<<23) }; + return convert.i & 255; +#else + // consoles CPUs suffer from load-hit-store penalty + return Float2Int( c * 255.0f ); +#endif +} + +//----------------------------------------------------------------------------- +// Fast conversion from float to integer with magnitude less than 2**22 +//----------------------------------------------------------------------------- +FORCEINLINE int FastFloatToSmallInt( float c ) +{ +#if defined( __i386__ ) + // IEEE float bit manipulation works for values between [-1<<22, 1<<22) + union { float f; int i; } convert = { c + (float)(3<<22) }; + return (convert.i & ((1<<23)-1)) - (1<<22); +#else + // consoles CPUs suffer from load-hit-store penalty + return Float2Int( c ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Bound input float to .001 (millisecond) boundary +// Input : in - +// Output : inline float +//----------------------------------------------------------------------------- +inline float ClampToMsec( float in ) +{ + int msec = Floor2Int( in * 1000.0f + 0.5f ); + return 0.001f * msec; +} + +// Over 15x faster than: (int)ceil(value) +inline int Ceil2Int( float a ) +{ + int RetVal; +#if defined( __i386__ ) + // Convert to int and back, compare, add one if too small + __m128 a128 = _mm_load_ss(&a); + RetVal = _mm_cvtss_si32(a128); + __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal); + RetVal += _mm_comilt_ss( rounded128, a128 ); +#else + RetVal = static_cast( ceil(a) ); +#endif + return RetVal; +} + + +// Regular signed area of triangle +#define TriArea2D( A, B, C ) \ + ( 0.5f * ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) ) + +// This version doesn't premultiply by 0.5f, so it's the area of the rectangle instead +#define TriArea2DTimesTwo( A, B, C ) \ + ( ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) ) + + +// Get the barycentric coordinates of "pt" in triangle [A,B,C]. +inline void GetBarycentricCoords2D( + Vector2D const &A, + Vector2D const &B, + Vector2D const &C, + Vector2D const &pt, + float bcCoords[3] ) +{ + // Note, because to top and bottom are both x2, the issue washes out in the composite + float invTriArea = 1.0f / TriArea2DTimesTwo( A, B, C ); + + // NOTE: We assume here that the lightmap coordinate vertices go counterclockwise. + // If not, TriArea2D() is negated so this works out right. + bcCoords[0] = TriArea2DTimesTwo( B, C, pt ) * invTriArea; + bcCoords[1] = TriArea2DTimesTwo( C, A, pt ) * invTriArea; + bcCoords[2] = TriArea2DTimesTwo( A, B, pt ) * invTriArea; +} + + +// Return true of the sphere might touch the box (the sphere is actually treated +// like a box itself, so this may return true if the sphere's bounding box touches +// a corner of the box but the sphere itself doesn't). +inline bool QuickBoxSphereTest( + const Vector& vOrigin, + float flRadius, + const Vector& bbMin, + const Vector& bbMax ) +{ + return vOrigin.x - flRadius < bbMax.x && vOrigin.x + flRadius > bbMin.x && + vOrigin.y - flRadius < bbMax.y && vOrigin.y + flRadius > bbMin.y && + vOrigin.z - flRadius < bbMax.z && vOrigin.z + flRadius > bbMin.z; +} + + +// Return true of the boxes intersect (but not if they just touch). +inline bool QuickBoxIntersectTest( + const Vector& vBox1Min, + const Vector& vBox1Max, + const Vector& vBox2Min, + const Vector& vBox2Max ) +{ + return + vBox1Min.x < vBox2Max.x && vBox1Max.x > vBox2Min.x && + vBox1Min.y < vBox2Max.y && vBox1Max.y > vBox2Min.y && + vBox1Min.z < vBox2Max.z && vBox1Max.z > vBox2Min.z; +} + + +extern float GammaToLinearFullRange( float gamma ); +extern float LinearToGammaFullRange( float linear ); +extern float GammaToLinear( float gamma ); +extern float LinearToGamma( float linear ); + +extern float SrgbGammaToLinear( float flSrgbGammaValue ); +extern float SrgbLinearToGamma( float flLinearValue ); +extern float X360GammaToLinear( float fl360GammaValue ); +extern float X360LinearToGamma( float flLinearValue ); +extern float SrgbGammaTo360Gamma( float flSrgbGammaValue ); + +// linear (0..4) to screen corrected vertex space (0..1?) +FORCEINLINE float LinearToVertexLight( float f ) +{ + extern float lineartovertex[4096]; + + // Gotta clamp before the multiply; could overflow... + // assume 0..4 range + int i = RoundFloatToInt( f * 1024.f ); + + // Presumably the comman case will be not to clamp, so check that first: + if( (unsigned)i > 4095 ) + { + if ( i < 0 ) + i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream + else + i = 4095; + } + + return lineartovertex[i]; +} + + +FORCEINLINE unsigned char LinearToLightmap( float f ) +{ + extern unsigned char lineartolightmap[4096]; + + // Gotta clamp before the multiply; could overflow... + int i = RoundFloatToInt( f * 1024.f ); // assume 0..4 range + + // Presumably the comman case will be not to clamp, so check that first: + if ( (unsigned)i > 4095 ) + { + if ( i < 0 ) + i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream + else + i = 4095; + } + + return lineartolightmap[i]; +} + +FORCEINLINE void ColorClamp( Vector& color ) +{ + float maxc = vmax( color.x, vmax( color.y, color.z ) ); + if ( maxc > 1.0f ) + { + float ooMax = 1.0f / maxc; + color.x *= ooMax; + color.y *= ooMax; + color.z *= ooMax; + } + + if ( color[0] < 0.f ) color[0] = 0.f; + if ( color[1] < 0.f ) color[1] = 0.f; + if ( color[2] < 0.f ) color[2] = 0.f; +} + +inline void ColorClampTruncate( Vector& color ) +{ + if (color[0] > 1.0f) color[0] = 1.0f; else if (color[0] < 0.0f) color[0] = 0.0f; + if (color[1] > 1.0f) color[1] = 1.0f; else if (color[1] < 0.0f) color[1] = 0.0f; + if (color[2] > 1.0f) color[2] = 1.0f; else if (color[2] < 0.0f) color[2] = 0.0f; +} + +// Interpolate a Catmull-Rom spline. +// t is a [0,1] value and interpolates a curve between p2 and p3. +void Catmull_Rom_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// Interpolate a Catmull-Rom spline. +// Returns the tangent of the point at t of the spline +void Catmull_Rom_Spline_Tangent( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// area under the curve [0..t] +void Catmull_Rom_Spline_Integral( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// area under the curve [0..1] +void Catmull_Rom_Spline_Integral( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + Vector& output ); + +// Interpolate a Catmull-Rom spline. +// Normalize p2->p1 and p3->p4 to be the same length as p2->p3 +void Catmull_Rom_Spline_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// area under the curve [0..t] +// Normalize p2->p1 and p3->p4 to be the same length as p2->p3 +void Catmull_Rom_Spline_Integral_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// Interpolate a Catmull-Rom spline. +// Normalize p2.x->p1.x and p3.x->p4.x to be the same length as p2.x->p3.x +void Catmull_Rom_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// area under the curve [0..t] +void Catmull_Rom_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// Interpolate a Hermite spline. +// t is a [0,1] value and interpolates a curve between p1 and p2 with the deltas d1 and d2. +void Hermite_Spline( + const Vector &p1, + const Vector &p2, + const Vector &d1, + const Vector &d2, + float t, + Vector& output ); + +float Hermite_Spline( + float p1, + float p2, + float d1, + float d2, + float t ); + +// t is a [0,1] value and interpolates a curve between p1 and p2 with the slopes p0->p1 and p1->p2 +void Hermite_Spline( + const Vector &p0, + const Vector &p1, + const Vector &p2, + float t, + Vector& output ); + +float Hermite_Spline( + float p0, + float p1, + float p2, + float t ); + + +void Hermite_SplineBasis( float t, float basis[] ); + +void Hermite_Spline( + const Quaternion &q0, + const Quaternion &q1, + const Quaternion &q2, + float t, + Quaternion &output ); + + +// See http://en.wikipedia.org/wiki/Kochanek-Bartels_curves +// +// Tension: -1 = Round -> 1 = Tight +// Bias: -1 = Pre-shoot (bias left) -> 1 = Post-shoot (bias right) +// Continuity: -1 = Box corners -> 1 = Inverted corners +// +// If T=B=C=0 it's the same matrix as Catmull-Rom. +// If T=1 & B=C=0 it's the same as Cubic. +// If T=B=0 & C=-1 it's just linear interpolation +// +// See http://news.povray.org/povray.binaries.tutorials/attachment/%3CXns91B880592482seed7@povray.org%3E/Splines.bas.txt +// for example code and descriptions of various spline types... +// +void Kochanek_Bartels_Spline( + float tension, + float bias, + float continuity, + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void Kochanek_Bartels_Spline_NormalizeX( + float tension, + float bias, + float continuity, + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// See link at Kochanek_Bartels_Spline for info on the basis matrix used +void Cubic_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void Cubic_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// See link at Kochanek_Bartels_Spline for info on the basis matrix used +void BSpline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void BSpline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// See link at Kochanek_Bartels_Spline for info on the basis matrix used +void Parabolic_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void Parabolic_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// quintic interpolating polynomial from Perlin. +// 0->0, 1->1, smooth-in between with smooth tangents +FORCEINLINE float QuinticInterpolatingPolynomial(float t) +{ + // 6t^5-15t^4+10t^3 + return t * t * t *( t * ( t* 6.0f - 15.0f ) + 10.0f ); +} + +// given a table of sorted tabulated positions, return the two indices and blendfactor to linear +// interpolate. Does a search. Can be used to find the blend value to interpolate between +// keyframes. +void GetInterpolationData( float const *pKnotPositions, + float const *pKnotValues, + int nNumValuesinList, + int nInterpolationRange, + float flPositionToInterpolateAt, + bool bWrap, + float *pValueA, + float *pValueB, + float *pInterpolationValue); + +float RangeCompressor( float flValue, float flMin, float flMax, float flBase ); + +// Get the minimum distance from vOrigin to the bounding box defined by [mins,maxs] +// using voronoi regions. +// 0 is returned if the origin is inside the box. +float CalcSqrDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point ); +void CalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut ); +void CalcSqrDistAndClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut, float &distSqrOut ); + +inline float CalcDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point ) +{ + float flDistSqr = CalcSqrDistanceToAABB( mins, maxs, point ); + return sqrtf(flDistSqr); +} + +// Get the closest point from P to the (infinite) line through vLineA and vLineB and +// calculate the shortest distance from P to the line. +// If you pass in a value for t, it will tell you the t for (A + (B-A)t) to get the closest point. +// If the closest point lies on the segment between A and B, then 0 <= t <= 1. +void CalcClosestPointOnLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 ); +float CalcDistanceToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); +float CalcDistanceSqrToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); + +// The same three functions as above, except now the line is closed between A and B. +void CalcClosestPointOnLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 ); +float CalcDistanceToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); +float CalcDistanceSqrToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); + +// A function to compute the closes line segment connnection two lines (or false if the lines are parallel, etc.) +bool CalcLineToLineIntersectionSegment( + const Vector& p1,const Vector& p2,const Vector& p3,const Vector& p4,Vector *s1,Vector *s2, + float *t1, float *t2 ); + +// The above functions in 2D +void CalcClosestPointOnLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 ); +float CalcDistanceToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); +float CalcDistanceSqrToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); +void CalcClosestPointOnLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 ); +float CalcDistanceToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); +float CalcDistanceSqrToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); + +// Init the mathlib +void MathLib_Init( float gamma = 2.2f, float texGamma = 2.2f, float brightness = 0.0f, int overbright = 2.0f, bool bAllow3DNow = true, bool bAllowSSE = true, bool bAllowSSE2 = true, bool bAllowMMX = true ); +bool MathLib_3DNowEnabled( void ); +bool MathLib_MMXEnabled( void ); +bool MathLib_SSEEnabled( void ); +bool MathLib_SSE2Enabled( void ); + +float Approach( float target, float value, float speed ); +float ApproachAngle( float target, float value, float speed ); +float AngleDiff( float destAngle, float srcAngle ); +float AngleDistance( float next, float cur ); +float AngleNormalize( float angle ); + +// ensure that 0 <= angle <= 360 +float AngleNormalizePositive( float angle ); + +bool AnglesAreEqual( float a, float b, float tolerance = 0.0f ); + + +void RotationDeltaAxisAngle( const QAngle &srcAngles, const QAngle &destAngles, Vector &deltaAxis, float &deltaAngle ); +void RotationDelta( const QAngle &srcAngles, const QAngle &destAngles, QAngle *out ); + +void ComputeTrianglePlane( const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept ); +int PolyFromPlane( Vector *outVerts, const Vector& normal, float dist, float fHalfScale = 9000.0f ); +int ClipPolyToPlane( Vector *inVerts, int vertCount, Vector *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon = 0.1f ); +int ClipPolyToPlane_Precise( double *inVerts, int vertCount, double *outVerts, const double *normal, double dist, double fOnPlaneEpsilon = 0.1 ); + +//----------------------------------------------------------------------------- +// Computes a reasonable tangent space for a triangle +//----------------------------------------------------------------------------- +void CalcTriangleTangentSpace( const Vector &p0, const Vector &p1, const Vector &p2, + const Vector2D &t0, const Vector2D &t1, const Vector2D& t2, + Vector &sVect, Vector &tVect ); + +//----------------------------------------------------------------------------- +// Transforms a AABB into another space; which will inherently grow the box. +//----------------------------------------------------------------------------- +void TransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Uses the inverse transform of in1 +//----------------------------------------------------------------------------- +void ITransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Rotates a AABB into another space; which will inherently grow the box. +// (same as TransformAABB, but doesn't take the translation into account) +//----------------------------------------------------------------------------- +void RotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Uses the inverse transform of in1 +//----------------------------------------------------------------------------- +void IRotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Transform a plane +//----------------------------------------------------------------------------- +inline void MatrixTransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane ) +{ + // What we want to do is the following: + // 1) transform the normal into the new space. + // 2) Determine a point on the old plane given by plane dist * plane normal + // 3) Transform that point into the new space + // 4) Plane dist = DotProduct( new normal, new point ) + + // An optimized version, which works if the plane is orthogonal. + // 1) Transform the normal into the new space + // 2) Realize that transforming the old plane point into the new space + // is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ] + // where d = old plane dist, n' = transformed normal, Tn = translational component of transform + // 3) Compute the new plane dist using the dot product of the normal result of #2 + + // For a correct result, this should be an inverse-transpose matrix + // but that only matters if there are nonuniform scale or skew factors in this matrix. + VectorRotate( inPlane.normal, src, outPlane.normal ); + outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal ); + outPlane.dist += outPlane.normal.x * src[0][3] + outPlane.normal.y * src[1][3] + outPlane.normal.z * src[2][3]; +} + +inline void MatrixITransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane ) +{ + // The trick here is that Tn = translational component of transform, + // but for an inverse transform, Tn = - R^-1 * T + Vector vecTranslation; + MatrixGetColumn( src, 3, vecTranslation ); + + Vector vecInvTranslation; + VectorIRotate( vecTranslation, src, vecInvTranslation ); + + VectorIRotate( inPlane.normal, src, outPlane.normal ); + outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal ); + outPlane.dist -= outPlane.normal.x * vecInvTranslation[0] + outPlane.normal.y * vecInvTranslation[1] + outPlane.normal.z * vecInvTranslation[2]; +} + +int CeilPow2( int in ); +int FloorPow2( int in ); + +FORCEINLINE float * UnpackNormal_HEND3N( const unsigned int *pPackedNormal, float *pNormal ) +{ + int temp[3]; + temp[0] = ((*pPackedNormal >> 0L) & 0x7ff); + if ( temp[0] & 0x400 ) + { + temp[0] = 2048 - temp[0]; + } + temp[1] = ((*pPackedNormal >> 11L) & 0x7ff); + if ( temp[1] & 0x400 ) + { + temp[1] = 2048 - temp[1]; + } + temp[2] = ((*pPackedNormal >> 22L) & 0x3ff); + if ( temp[2] & 0x200 ) + { + temp[2] = 1024 - temp[2]; + } + pNormal[0] = (float)temp[0] * 1.0f/1023.0f; + pNormal[1] = (float)temp[1] * 1.0f/1023.0f; + pNormal[2] = (float)temp[2] * 1.0f/511.0f; + return pNormal; +} + +FORCEINLINE unsigned int * PackNormal_HEND3N( const float *pNormal, unsigned int *pPackedNormal ) +{ + int temp[3]; + + temp[0] = Float2Int( pNormal[0] * 1023.0f ); + temp[1] = Float2Int( pNormal[1] * 1023.0f ); + temp[2] = Float2Int( pNormal[2] * 511.0f ); + + // the normal is out of bounds, determine the source and fix + // clamping would be even more of a slowdown here + Assert( temp[0] >= -1023 && temp[0] <= 1023 ); + Assert( temp[1] >= -1023 && temp[1] <= 1023 ); + Assert( temp[2] >= -511 && temp[2] <= 511 ); + + *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) | + ( ( temp[1] & 0x7ff ) << 11L ) | + ( ( temp[0] & 0x7ff ) << 0L ); + return pPackedNormal; +} + +FORCEINLINE unsigned int * PackNormal_HEND3N( float nx, float ny, float nz, unsigned int *pPackedNormal ) +{ + int temp[3]; + + temp[0] = Float2Int( nx * 1023.0f ); + temp[1] = Float2Int( ny * 1023.0f ); + temp[2] = Float2Int( nz * 511.0f ); + + // the normal is out of bounds, determine the source and fix + // clamping would be even more of a slowdown here + Assert( temp[0] >= -1023 && temp[0] <= 1023 ); + Assert( temp[1] >= -1023 && temp[1] <= 1023 ); + Assert( temp[2] >= -511 && temp[2] <= 511 ); + + *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) | + ( ( temp[1] & 0x7ff ) << 11L ) | + ( ( temp[0] & 0x7ff ) << 0L ); + return pPackedNormal; +} + +FORCEINLINE float * UnpackNormal_SHORT2( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE ) +{ + // Unpacks from Jason's 2-short format (fills in a 4th binormal-sign (+1/-1) value, if this is a tangent vector) + + // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits) + short iX = (*pPackedNormal & 0x0000FFFF); + short iY = (*pPackedNormal & 0xFFFF0000) >> 16; + + float zSign = +1; + if ( iX < 0 ) + { + zSign = -1; + iX = -iX; + } + float tSign = +1; + if ( iY < 0 ) + { + tSign = -1; + iY = -iY; + } + + pNormal[0] = ( iX - 16384.0f ) / 16384.0f; + pNormal[1] = ( iY - 16384.0f ) / 16384.0f; + pNormal[2] = zSign*sqrtf( 1.0f - ( pNormal[0]*pNormal[0] + pNormal[1]*pNormal[1] ) ); + if ( bIsTangent ) + { + pNormal[3] = tSign; + } + + return pNormal; +} + +FORCEINLINE unsigned int * PackNormal_SHORT2( float nx, float ny, float nz, unsigned int *pPackedNormal, float binormalSign = +1.0f ) +{ + // Pack a vector (ASSUMED TO BE NORMALIZED) into Jason's 4-byte (SHORT2) format. + // This simply reconstructs Z from X & Y. It uses the sign bits of the X & Y coords + // to reconstruct the sign of Z and, if this is a tangent vector, the sign of the + // binormal (this is needed because tangent/binormal vectors are supposed to follow + // UV gradients, but shaders reconstruct the binormal from the tangent and normal + // assuming that they form a right-handed basis). + + nx += 1; // [-1,+1] -> [0,2] + ny += 1; + nx *= 16384.0f; // [ 0, 2] -> [0,32768] + ny *= 16384.0f; + + // '0' and '32768' values are invalid encodings + nx = vmax( nx, 1.0f ); // Make sure there are no zero values + ny = vmax( ny, 1.0f ); + nx = vmin( nx, 32767.0f ); // Make sure there are no 32768 values + ny = vmin( ny, 32767.0f ); + + if ( nz < 0.0f ) + nx = -nx; // Set the sign bit for z + + ny *= binormalSign; // Set the sign bit for the binormal (use when encoding a tangent vector) + + // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits), also use Float2Int() + short sX = (short)nx; // signed short [1,32767] + short sY = (short)ny; + + *pPackedNormal = ( sX & 0x0000FFFF ) | ( sY << 16 ); // NOTE: The mask is necessary (if sX is negative and cast to an int...) + + return pPackedNormal; +} + +FORCEINLINE unsigned int * PackNormal_SHORT2( const float *pNormal, unsigned int *pPackedNormal, float binormalSign = +1.0f ) +{ + return PackNormal_SHORT2( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, binormalSign ); +} + +// Unpacks a UBYTE4 normal (for a tangent, the result's fourth component receives the binormal 'sign') +FORCEINLINE float * UnpackNormal_UBYTE4( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE ) +{ + unsigned char cX, cY; + if ( bIsTangent ) + { + cX = (unsigned char)(*pPackedNormal >> 16); // Unpack Z + cY = (unsigned char)(*pPackedNormal >> 24); // Unpack W + } + else + { + cX = (unsigned char)(*pPackedNormal >> 0); // Unpack X + cY = (unsigned char)(*pPackedNormal >> 8); // Unpack Y + } + + float x = cX - 128.0f; + float y = cY - 128.0f; + float z; + + float zSignBit = x < 0 ? 1.0f : 0.0f; // z and t negative bits (like slt asm instruction) + float tSignBit = y < 0 ? 1.0f : 0.0f; + float zSign = -( 2*zSignBit - 1 ); // z and t signs + float tSign = -( 2*tSignBit - 1 ); + + x = x*zSign - zSignBit; // 0..127 + y = y*tSign - tSignBit; + x = x - 64; // -64..63 + y = y - 64; + + float xSignBit = x < 0 ? 1.0f : 0.0f; // x and y negative bits (like slt asm instruction) + float ySignBit = y < 0 ? 1.0f : 0.0f; + float xSign = -( 2*xSignBit - 1 ); // x and y signs + float ySign = -( 2*ySignBit - 1 ); + + x = ( x*xSign - xSignBit ) / 63.0f; // 0..1 range + y = ( y*ySign - ySignBit ) / 63.0f; + z = 1.0f - x - y; + + float oolen = 1.0f / sqrtf( x*x + y*y + z*z ); // Normalize and + x *= oolen * xSign; // Recover signs + y *= oolen * ySign; + z *= oolen * zSign; + + pNormal[0] = x; + pNormal[1] = y; + pNormal[2] = z; + if ( bIsTangent ) + { + pNormal[3] = tSign; + } + + return pNormal; +} + +////////////////////////////////////////////////////////////////////////////// +// See: http://www.oroboro.com/rafael/docserv.php/index/programming/article/unitv2 +// +// UBYTE4 encoding, using per-octant projection onto x+y+z=1 +// Assume input vector is already unit length +// +// binormalSign specifies 'sign' of binormal, stored in t sign bit of tangent +// (lets the shader know whether norm/tan/bin form a right-handed basis) +// +// bIsTangent is used to specify which WORD of the output to store the data +// The expected usage is to call once with the normal and once with +// the tangent and binormal sign flag, bitwise OR'ing the returned DWORDs +FORCEINLINE unsigned int * PackNormal_UBYTE4( float nx, float ny, float nz, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f ) +{ + float xSign = nx < 0.0f ? -1.0f : 1.0f; // -1 or 1 sign + float ySign = ny < 0.0f ? -1.0f : 1.0f; + float zSign = nz < 0.0f ? -1.0f : 1.0f; + float tSign = binormalSign; + Assert( ( binormalSign == +1.0f ) || ( binormalSign == -1.0f ) ); + + float xSignBit = 0.5f*( 1 - xSign ); // [-1,+1] -> [1,0] + float ySignBit = 0.5f*( 1 - ySign ); // 1 is negative bit (like slt instruction) + float zSignBit = 0.5f*( 1 - zSign ); + float tSignBit = 0.5f*( 1 - binormalSign ); + + float absX = xSign*nx; // 0..1 range (abs) + float absY = ySign*ny; + float absZ = zSign*nz; + + float xbits = absX / ( absX + absY + absZ ); // Project onto x+y+z=1 plane + float ybits = absY / ( absX + absY + absZ ); + + xbits *= 63; // 0..63 + ybits *= 63; + + xbits = xbits * xSign - xSignBit; // -64..63 range + ybits = ybits * ySign - ySignBit; + xbits += 64.0f; // 0..127 range + ybits += 64.0f; + + xbits = xbits * zSign - zSignBit; // Negate based on z and t + ybits = ybits * tSign - tSignBit; // -128..127 range + + xbits += 128.0f; // 0..255 range + ybits += 128.0f; + + unsigned char cX = (unsigned char) xbits; + unsigned char cY = (unsigned char) ybits; + + if ( !bIsTangent ) + *pPackedNormal = (cX << 0) | (cY << 8); // xy for normal + else + *pPackedNormal = (cX << 16) | (cY << 24); // zw for tangent + + return pPackedNormal; +} + +FORCEINLINE unsigned int * PackNormal_UBYTE4( const float *pNormal, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f ) +{ + return PackNormal_UBYTE4( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, bIsTangent, binormalSign ); +} + + +//----------------------------------------------------------------------------- +// Convert RGB to HSV +//----------------------------------------------------------------------------- +void RGBtoHSV( const Vector &rgb, Vector &hsv ); + + +//----------------------------------------------------------------------------- +// Convert HSV to RGB +//----------------------------------------------------------------------------- +void HSVtoRGB( const Vector &hsv, Vector &rgb ); + + +//----------------------------------------------------------------------------- +// Fast version of pow and log +//----------------------------------------------------------------------------- + +float FastLog2(float i); // log2( i ) +float FastPow2(float i); // 2^i +float FastPow(float a, float b); // a^b +float FastPow10( float i ); // 10^i + +//----------------------------------------------------------------------------- +// For testing float equality +//----------------------------------------------------------------------------- + +inline bool CloseEnough( float a, float b, float epsilon = EQUAL_EPSILON ) +{ + return fabs( a - b ) <= epsilon; +} + +inline bool CloseEnough( const Vector &a, const Vector &b, float epsilon = EQUAL_EPSILON ) +{ + return fabs( a.x - b.x ) <= epsilon && + fabs( a.y - b.y ) <= epsilon && + fabs( a.z - b.z ) <= epsilon; +} + +// Fast compare +// maxUlps is the maximum error in terms of Units in the Last Place. This +// specifies how big an error we are willing to accept in terms of the value +// of the least significant digit of the floating point numbers +// representation. maxUlps can also be interpreted in terms of how many +// representable floats we are willing to accept between A and B. +// This function will allow maxUlps-1 floats between A and B. +bool AlmostEqual(float a, float b, int maxUlps = 10); + +inline bool AlmostEqual( const Vector &a, const Vector &b, int maxUlps = 10) +{ + return AlmostEqual( a.x, b.x, maxUlps ) && + AlmostEqual( a.y, b.y, maxUlps ) && + AlmostEqual( a.z, b.z, maxUlps ); +} + + +#endif // MATH_BASE_H + diff --git a/public/mathlib/matrixmath.h b/public/mathlib/matrixmath.h new file mode 100644 index 0000000..9c7f207 --- /dev/null +++ b/public/mathlib/matrixmath.h @@ -0,0 +1,385 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// A set of generic, template-based matrix functions. +//===========================================================================// + +#ifndef MATRIXMATH_H +#define MATRIXMATH_H + +#include + +// The operations in this file can perform basic matrix operations on matrices represented +// using any class that supports the necessary operations: +// +// .Element( row, col ) - return the element at a given matrox position +// .SetElement( row, col, val ) - modify an element +// .Width(), .Height() - get dimensions +// .SetDimensions( nrows, ncols) - set a matrix to be un-initted and the appropriate size +// +// Generally, vectors can be used with these functions by using N x 1 matrices to represent them. +// Matrices are addressed as row, column, and indices are 0-based +// +// +// Note that the template versions of these routines are defined for generality - it is expected +// that template specialization is used for common high performance cases. + +namespace MatrixMath +{ + /// M *= flScaleValue + template + void ScaleMatrix( MATRIXCLASS &matrix, float flScaleValue ) + { + for( int i = 0; i < matrix.Height(); i++ ) + { + for( int j = 0; j < matrix.Width(); j++ ) + { + matrix.SetElement( i, j, flScaleValue * matrix.Element( i, j ) ); + } + } + } + + /// AppendElementToMatrix - same as setting the element, except only works when all calls + /// happen in top to bottom left to right order, end you have to call FinishedAppending when + /// done. For normal matrix classes this is not different then SetElement, but for + /// CSparseMatrix, it is an accelerated way to fill a matrix from scratch. + template + FORCEINLINE void AppendElement( MATRIXCLASS &matrix, int nRow, int nCol, float flValue ) + { + matrix.SetElement( nRow, nCol, flValue ); // default implementation + } + + template + FORCEINLINE void FinishedAppending( MATRIXCLASS &matrix ) {} // default implementation + + /// M += fl + template + void AddToMatrix( MATRIXCLASS &matrix, float flAddend ) + { + for( int i = 0; i < matrix.Height(); i++ ) + { + for( int j = 0; j < matrix.Width(); j++ ) + { + matrix.SetElement( i, j, flAddend + matrix.Element( i, j ) ); + } + } + } + + /// transpose + template + void TransposeMatrix( MATRIXCLASSIN const &matrixIn, MATRIXCLASSOUT *pMatrixOut ) + { + pMatrixOut->SetDimensions( matrixIn.Width(), matrixIn.Height() ); + for( int i = 0; i < pMatrixOut->Height(); i++ ) + { + for( int j = 0; j < pMatrixOut->Width(); j++ ) + { + AppendElement( *pMatrixOut, i, j, matrixIn.Element( j, i ) ); + } + } + FinishedAppending( *pMatrixOut ); + } + + /// copy + template + void CopyMatrix( MATRIXCLASSIN const &matrixIn, MATRIXCLASSOUT *pMatrixOut ) + { + pMatrixOut->SetDimensions( matrixIn.Height(), matrixIn.Width() ); + for( int i = 0; i < matrixIn.Height(); i++ ) + { + for( int j = 0; j < matrixIn.Width(); j++ ) + { + AppendElement( *pMatrixOut, i, j, matrixIn.Element( i, j ) ); + } + } + FinishedAppending( *pMatrixOut ); + } + + + + /// M+=M + template + void AddMatrixToMatrix( MATRIXCLASSIN const &matrixIn, MATRIXCLASSOUT *pMatrixOut ) + { + for( int i = 0; i < matrixIn.Height(); i++ ) + { + for( int j = 0; j < matrixIn.Width(); j++ ) + { + pMatrixOut->SetElement( i, j, pMatrixOut->Element( i, j ) + matrixIn.Element( i, j ) ); + } + } + } + + // M += scale * M + template + void AddScaledMatrixToMatrix( float flScale, MATRIXCLASSIN const &matrixIn, MATRIXCLASSOUT *pMatrixOut ) + { + for( int i = 0; i < matrixIn.Height(); i++ ) + { + for( int j = 0; j < matrixIn.Width(); j++ ) + { + pMatrixOut->SetElement( i, j, pMatrixOut->Element( i, j ) + flScale * matrixIn.Element( i, j ) ); + } + } + } + + + // simple way to initialize a matrix with constants from code. + template + void SetMatrixToIdentity( MATRIXCLASSOUT *pMatrixOut, float flDiagonalValue = 1.0 ) + { + for( int i = 0; i < pMatrixOut->Height(); i++ ) + { + for( int j = 0; j < pMatrixOut->Width(); j++ ) + { + AppendElement( *pMatrixOut, i, j, ( i == j ) ? flDiagonalValue : 0 ); + } + } + FinishedAppending( *pMatrixOut ); + } + + //// simple way to initialize a matrix with constants from code + template + void SetMatrixValues( MATRIXCLASSOUT *pMatrix, int nRows, int nCols, ... ) + { + va_list argPtr; + va_start( argPtr, nCols ); + + pMatrix->SetDimensions( nRows, nCols ); + for( int nRow = 0; nRow < nRows; nRow++ ) + { + for( int nCol = 0; nCol < nCols; nCol++ ) + { + double flNewValue = va_arg( argPtr, double ); + pMatrix->SetElement( nRow, nCol, flNewValue ); + } + } + va_end( argPtr ); + } + + + /// row and colum accessors. treat a row or a column as a column vector + template class MatrixRowAccessor + { + public: + FORCEINLINE MatrixRowAccessor( MATRIXTYPE const &matrix, int nRow ) + { + m_pMatrix = &matrix; + m_nRow = nRow; + } + + FORCEINLINE float Element( int nRow, int nCol ) const + { + Assert( nCol == 0 ); + return m_pMatrix->Element( m_nRow, nRow ); + } + + FORCEINLINE int Width( void ) const { return 1; }; + FORCEINLINE int Height( void ) const { return m_pMatrix->Width(); } + + private: + MATRIXTYPE const *m_pMatrix; + int m_nRow; + }; + + template class MatrixColumnAccessor + { + public: + FORCEINLINE MatrixColumnAccessor( MATRIXTYPE const &matrix, int nColumn ) + { + m_pMatrix = &matrix; + m_nColumn = nColumn; + } + + FORCEINLINE float Element( int nRow, int nColumn ) const + { + Assert( nColumn == 0 ); + return m_pMatrix->Element( nRow, m_nColumn ); + } + + FORCEINLINE int Width( void ) const { return 1; } + FORCEINLINE int Height( void ) const { return m_pMatrix->Height(); } + private: + MATRIXTYPE const *m_pMatrix; + int m_nColumn; + }; + + /// this translator acts as a proxy for the transposed matrix + template class MatrixTransposeAccessor + { + public: + FORCEINLINE MatrixTransposeAccessor( MATRIXTYPE const & matrix ) + { + m_pMatrix = &matrix; + } + + FORCEINLINE float Element( int nRow, int nColumn ) const + { + return m_pMatrix->Element( nColumn, nRow ); + } + + FORCEINLINE int Width( void ) const { return m_pMatrix->Height(); } + FORCEINLINE int Height( void ) const { return m_pMatrix->Width(); } + private: + MATRIXTYPE const *m_pMatrix; + }; + + /// this tranpose returns a wrapper around it's argument, allowing things like AddMatrixToMatrix( Transpose( matA ), &matB ) without an extra copy + template + MatrixTransposeAccessor TransposeMatrix( MATRIXCLASSIN const &matrixIn ) + { + return MatrixTransposeAccessor( matrixIn ); + } + + + /// retrieve rows and columns + template + FORCEINLINE MatrixColumnAccessor MatrixColumn( MATRIXTYPE const &matrix, int nColumn ) + { + return MatrixColumnAccessor( matrix, nColumn ); + } + + template + FORCEINLINE MatrixRowAccessor MatrixRow( MATRIXTYPE const &matrix, int nRow ) + { + return MatrixRowAccessor( matrix, nRow ); + } + + //// dot product between vectors (or rows and/or columns via accessors) + template + float InnerProduct( MATRIXACCESSORATYPE const &vecA, MATRIXACCESSORBTYPE const &vecB ) + { + Assert( vecA.Width() == 1 ); + Assert( vecB.Width() == 1 ); + Assert( vecA.Height() == vecB.Height() ); + double flResult = 0; + for( int i = 0; i < vecA.Height(); i++ ) + { + flResult += vecA.Element( i, 0 ) * vecB.Element( i, 0 ); + } + return flResult; + } + + + + /// matrix x matrix multiplication + template + void MatrixMultiply( MATRIXATYPE const &matA, MATRIXBTYPE const &matB, MATRIXOUTTYPE *pMatrixOut ) + { + Assert( matA.Width() == matB.Height() ); + pMatrixOut->SetDimensions( matA.Height(), matB.Width() ); + for( int i = 0; i < matA.Height(); i++ ) + { + for( int j = 0; j < matB.Width(); j++ ) + { + pMatrixOut->SetElement( i, j, InnerProduct( MatrixRow( matA, i ), MatrixColumn( matB, j ) ) ); + } + } + } + + /// solve Ax=B via the conjugate graident method. Code and naming conventions based on the + /// wikipedia article. + template + void ConjugateGradient( ATYPE const &matA, BTYPE const &vecB, XTYPE &vecX, float flTolerance = 1.0e-20 ) + { + XTYPE vecR; + vecR.SetDimensions( vecX.Height(), 1 ); + MatrixMultiply( matA, vecX, &vecR ); + ScaleMatrix( vecR, -1 ); + AddMatrixToMatrix( vecB, &vecR ); + XTYPE vecP; + CopyMatrix( vecR, &vecP ); + float flRsOld = InnerProduct( vecR, vecR ); + for( int nIter = 0; nIter < 100; nIter++ ) + { + XTYPE vecAp; + MatrixMultiply( matA, vecP, &vecAp ); + float flDivisor = InnerProduct( vecAp, vecP ); + float flAlpha = flRsOld / flDivisor; + AddScaledMatrixToMatrix( flAlpha, vecP, &vecX ); + AddScaledMatrixToMatrix( -flAlpha, vecAp, &vecR ); + float flRsNew = InnerProduct( vecR, vecR ); + if ( flRsNew < flTolerance ) + { + break; + } + ScaleMatrix( vecP, flRsNew / flRsOld ); + AddMatrixToMatrix( vecR, &vecP ); + flRsOld = flRsNew; + } + } + + /// solve (A'*A) x=B via the conjugate gradient method. Code and naming conventions based on + /// the wikipedia article. Same as Conjugate gradient but allows passing in two matrices whose + /// product is used as the A matrix (in order to preserve sparsity) + template + void ConjugateGradient( ATYPE const &matA, APRIMETYPE const &matAPrime, BTYPE const &vecB, XTYPE &vecX, float flTolerance = 1.0e-20 ) + { + XTYPE vecR1; + vecR1.SetDimensions( vecX.Height(), 1 ); + MatrixMultiply( matA, vecX, &vecR1 ); + XTYPE vecR; + vecR.SetDimensions( vecR1.Height(), 1 ); + MatrixMultiply( matAPrime, vecR1, &vecR ); + ScaleMatrix( vecR, -1 ); + AddMatrixToMatrix( vecB, &vecR ); + XTYPE vecP; + CopyMatrix( vecR, &vecP ); + float flRsOld = InnerProduct( vecR, vecR ); + for( int nIter = 0; nIter < 100; nIter++ ) + { + XTYPE vecAp1; + MatrixMultiply( matA, vecP, &vecAp1 ); + XTYPE vecAp; + MatrixMultiply( matAPrime, vecAp1, &vecAp ); + float flDivisor = InnerProduct( vecAp, vecP ); + float flAlpha = flRsOld / flDivisor; + AddScaledMatrixToMatrix( flAlpha, vecP, &vecX ); + AddScaledMatrixToMatrix( -flAlpha, vecAp, &vecR ); + float flRsNew = InnerProduct( vecR, vecR ); + if ( flRsNew < flTolerance ) + { + break; + } + ScaleMatrix( vecP, flRsNew / flRsOld ); + AddMatrixToMatrix( vecR, &vecP ); + flRsOld = flRsNew; + } + } + + + template + void LeastSquaresFit( ATYPE const &matA, BTYPE const &vecB, XTYPE &vecX ) + { + // now, generate the normal equations + BTYPE vecBeta; + MatrixMath::MatrixMultiply( MatrixMath::TransposeMatrix( matA ), vecB, &vecBeta ); + + vecX.SetDimensions( matA.Width(), 1 ); + MatrixMath::SetMatrixToIdentity( &vecX ); + + ATYPE matATransposed; + TransposeMatrix( matA, &matATransposed ); + ConjugateGradient( matA, matATransposed, vecBeta, vecX, 1.0e-20 ); + } + +}; + +/// a simple fixed-size matrix class +template class CFixedMatrix +{ +public: + FORCEINLINE int Width( void ) const { return NUMCOLS; } + FORCEINLINE int Height( void ) const { return NUMROWS; } + FORCEINLINE float Element( int nRow, int nCol ) const { return m_flValues[nRow][nCol]; } + FORCEINLINE void SetElement( int nRow, int nCol, float flValue ) { m_flValues[nRow][nCol] = flValue; } + FORCEINLINE void SetDimensions( int nNumRows, int nNumCols ) { Assert( ( nNumRows == NUMROWS ) && ( nNumCols == NUMCOLS ) ); } + +private: + float m_flValues[NUMROWS][NUMCOLS]; +}; + + + +#endif //matrixmath_h diff --git a/public/mathlib/noise.h b/public/mathlib/noise.h new file mode 100644 index 0000000..19d3f72 --- /dev/null +++ b/public/mathlib/noise.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef NOISE_H +#define NOISE_H + +#include +#include "basetypes.h" +#include "mathlib/vector.h" +#include "tier0/dbg.h" + + +// The following code is the c-ification of Ken Perlin's new noise algorithm +// "JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN" +// as available here: http://mrl.nyu.edu/~perlin/noise/ +// it generates a single octave of noise in the -1..1 range +// this should at some point probably replace SparseConvolutionNoise - jd +float ImprovedPerlinNoise( Vector const &pnt ); + +// get the noise value at a point. Output range is 0..1. +float SparseConvolutionNoise( Vector const &pnt ); + +// get the noise value at a point, passing a custom noise shaping function. The noise shaping +// function should map the domain 0..1 to 0..1. +float SparseConvolutionNoise(Vector const &pnt, float (*pNoiseShapeFunction)(float) ); + +// returns a 1/f noise. more octaves take longer +float FractalNoise( Vector const &pnt, int n_octaves ); + +// returns a abs(f)*1/f noise i.e. turbulence +float Turbulence( Vector const &pnt, int n_octaves ); +#endif // NOISE_H diff --git a/public/mathlib/polyhedron.h b/public/mathlib/polyhedron.h new file mode 100644 index 0000000..38b465c --- /dev/null +++ b/public/mathlib/polyhedron.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef POLYHEDRON_H_ +#define POLYHEDRON_H_ + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/mathlib.h" + + + +struct Polyhedron_IndexedLine_t +{ + unsigned short iPointIndices[2]; +}; + +struct Polyhedron_IndexedLineReference_t +{ + unsigned short iLineIndex; + unsigned char iEndPointIndex; //since two polygons reference any one line, one needs to traverse the line backwards, this flags that behavior +}; + +struct Polyhedron_IndexedPolygon_t +{ + unsigned short iFirstIndex; + unsigned short iIndexCount; + Vector polyNormal; +}; + +class CPolyhedron //made into a class because it's going virtual to support distinctions between temp and permanent versions +{ +public: + Vector *pVertices; + Polyhedron_IndexedLine_t *pLines; + Polyhedron_IndexedLineReference_t *pIndices; + Polyhedron_IndexedPolygon_t *pPolygons; + + unsigned short iVertexCount; + unsigned short iLineCount; + unsigned short iIndexCount; + unsigned short iPolygonCount; + + virtual ~CPolyhedron( void ) {}; + virtual void Release( void ) = 0; + Vector Center( void ); +}; + +class CPolyhedron_AllocByNew : public CPolyhedron +{ +public: + virtual void Release( void ); + static CPolyhedron_AllocByNew *Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ); //creates the polyhedron along with enough memory to hold all it's data in a single allocation + +private: + CPolyhedron_AllocByNew( void ) { }; //CPolyhedron_AllocByNew::Allocate() is the only way to create one of these. +}; + +CPolyhedron *GeneratePolyhedronFromPlanes( const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory = false ); //be sure to polyhedron->Release() +CPolyhedron *ClipPolyhedron( const CPolyhedron *pExistingPolyhedron, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory = false ); //this does NOT modify/delete the existing polyhedron + +CPolyhedron *GetTempPolyhedron( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ); //grab the temporary polyhedron. Avoids new/delete for quick work. Can only be in use by one chunk of code at a time + + +#endif //#ifndef POLYHEDRON_H_ + diff --git a/public/mathlib/quantize.h b/public/mathlib/quantize.h new file mode 100644 index 0000000..5e5b742 --- /dev/null +++ b/public/mathlib/quantize.h @@ -0,0 +1,141 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef QUANTIZE_H +#define QUANTIZE_H + +#ifndef STRING_H +#include +#endif + +#define MAXDIMS 768 +#define MAXQUANT 16000 + + +#include + +struct Sample; + +struct QuantizedValue { + double MinError; // minimum possible error. used + // for neighbor searches. + struct QuantizedValue *Children[2]; // splits + int32 value; // only exists for leaf nodes + struct Sample *Samples; // every sample quantized into this + // entry + int32 NSamples; // how many were quantized to this. + int32 TotSamples; + double *ErrorMeasure; // variance measure for each dimension + double TotalError; // sum of errors + uint8 *Mean; // average value of each dimension + uint8 *Mins; // min box for children and this + uint8 *Maxs; // max box for children and this + int NQuant; // the number of samples which were + // quantzied to this node since the + // last time OptimizeQuantizer() + // was called. + int *Sums; // sum used by OptimizeQuantizer + int sortdim; // dimension currently sorted along. +}; + +struct Sample { + int32 ID; // identifier of this sample. can + // be used for any purpose. + int32 Count; // number of samples this sample + // represents + int32 QNum; // what value this sample ended up quantized + // to. + struct QuantizedValue *qptr; // ptr to what this was quantized to. + uint8 Value[1]; // array of values for multi-dimensional + // variables. +}; + +void FreeQuantization(struct QuantizedValue *t); + +struct QuantizedValue *Quantize(struct Sample *s, int nsamples, int ndims, + int nvalues, uint8 *weights, int value0=0); + +int CompressSamples(struct Sample *s, int nsamples, int ndims); + +struct QuantizedValue *FindMatch(uint8 const *sample, + int ndims,uint8 *weights, + struct QuantizedValue *QTable); +void PrintSamples(struct Sample const *s, int nsamples, int ndims); + +struct QuantizedValue *FindQNode(struct QuantizedValue const *q, int32 code); + +inline struct Sample *NthSample(struct Sample *s, int i, int nd) +{ + uint8 *r=(uint8 *) s; + r+=i*(sizeof(*s)+(nd-1)); + return (struct Sample *) r; +} + +inline struct Sample *AllocSamples(int ns, int nd) +{ + size_t size5=(sizeof(struct Sample)+(nd-1))*ns; + void *ret=new uint8[size5]; + memset(ret,0,size5); + for(int i=0;iCount=1; + return (struct Sample *) ret; +} + + +// MinimumError: what is the min error which will occur if quantizing +// a sample to the given qnode? This is just the error if the qnode +// is a leaf. +double MinimumError(struct QuantizedValue const *q, uint8 const *sample, + int ndims, uint8 const *weights); +double MaximumError(struct QuantizedValue const *q, uint8 const *sample, + int ndims, uint8 const *weights); + +void PrintQTree(struct QuantizedValue const *p,int idlevel=0); +void OptimizeQuantizer(struct QuantizedValue *q, int ndims); + +// RecalculateVelues: update the means in a sample tree, based upon +// the samples. can be used to reoptimize when samples are deleted, +// for instance. + +void RecalculateValues(struct QuantizedValue *q, int ndims); + +extern double SquaredError; // may be reset and examined. updated by + // FindMatch() + + + + +// the routines below can be used for uniform quantization via dart-throwing. +typedef void (*GENERATOR)(void *); // generate a random sample +typedef double (*COMPARER)(void const *a, void const *b); + +void *DartThrow(int NResults, int NTries, size_t itemsize, GENERATOR gen, + COMPARER cmp); +void *FindClosestDart(void *items,int NResults, size_t itemsize, + COMPARER cmp, void *lookfor, int *idx); + + + + +// color quantization of 24 bit images +#define QUANTFLAGS_NODITHER 1 // don't do Floyd-steinberg dither + +extern void ColorQuantize( +uint8 const *pImage, // 4 byte pixels ARGB +int nWidth, +int nHeight, +int nFlags, // QUANTFLAGS_xxx +int nColors, // # of colors to fill in in palette +uint8 *pOutPixels, // where to store resulting 8 bit pixels +uint8 *pOutPalette, // where to store resulting 768-byte palette +int nFirstColor); // first color to use in mapping + + + + + +#endif diff --git a/public/mathlib/simdvectormatrix.h b/public/mathlib/simdvectormatrix.h new file mode 100644 index 0000000..f88cd32 --- /dev/null +++ b/public/mathlib/simdvectormatrix.h @@ -0,0 +1,142 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Provide a class (SSE/SIMD only) holding a 2d matrix of class FourVectors, +// for high speed processing in tools. +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef SIMDVECTORMATRIX_H +#define SIMDVECTORMATRIX_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier1/utlsoacontainer.h" +#include "mathlib/ssemath.h" + +class CSIMDVectorMatrix +{ +public: + int m_nWidth; // in actual vectors + int m_nHeight; + + int m_nPaddedWidth; // # of 4x wide elements + + FourVectors *m_pData; + +protected: + void Init( void ) + { + m_pData = NULL; + m_nWidth = 0; + m_nHeight = 0; + m_nPaddedWidth = 0; + } + + int NVectors( void ) const + { + return m_nHeight * m_nPaddedWidth; + } + +public: + // constructors and destructors + CSIMDVectorMatrix( void ) + { + Init(); + } + + ~CSIMDVectorMatrix( void ) + { + if ( m_pData ) + delete[] m_pData; + } + + // set up storage and fields for m x n matrix. destroys old data + void SetSize( int width, int height ) + { + if ( ( ! m_pData ) || ( width != m_nWidth ) || ( height != m_nHeight ) ) + { + if ( m_pData ) + delete[] m_pData; + + m_nWidth = width; + m_nHeight = height; + + m_nPaddedWidth = ( m_nWidth + 3) >> 2; + m_pData = NULL; + if ( width && height ) + m_pData = new FourVectors[ m_nPaddedWidth * m_nHeight ]; + } + } + + CSIMDVectorMatrix( int width, int height ) + { + Init(); + SetSize( width, height ); + } + + CSIMDVectorMatrix &operator=( CSIMDVectorMatrix const &src ) + { + SetSize( src.m_nWidth, src.m_nHeight ); + if ( m_pData ) + memcpy( m_pData, src.m_pData, m_nHeight*m_nPaddedWidth*sizeof(m_pData[0]) ); + return *this; + } + + CSIMDVectorMatrix &operator+=( CSIMDVectorMatrix const &src ); + + CSIMDVectorMatrix &operator*=( Vector const &src ); + + // create from an RGBA float bitmap. alpha ignored. + void CreateFromRGBA_FloatImageData(int srcwidth, int srcheight, float const *srcdata ); + + // create from 3 fields in a csoa + void CreateFromCSOAAttributes( CSOAContainer const *pSrc, + int nAttrIdx0, int nAttrIdx1, int nAttrIdx2 ); + + // Element access. If you are calling this a lot, you don't want to use this class, because + // you're not getting the sse advantage + Vector Element(int x, int y) const + { + Assert( m_pData ); + Assert( x < m_nWidth ); + Assert( y < m_nHeight ); + Vector ret; + FourVectors const *pData=m_pData+y*m_nPaddedWidth+(x >> 2); + + int xo=(x & 3); + ret.x=pData->X( xo ); + ret.y=pData->Y( xo ); + ret.z=pData->Z( xo ); + return ret; + } + + //addressing the individual fourvectors elements + FourVectors &CompoundElement(int x, int y) + { + Assert( m_pData ); + Assert( y < m_nHeight ); + Assert( x < m_nPaddedWidth ); + return m_pData[x + m_nPaddedWidth*y ]; + } + + // math operations on the whole image + void Clear( void ) + { + Assert( m_pData ); + memset( m_pData, 0, m_nHeight*m_nPaddedWidth*sizeof(m_pData[0]) ); + } + + void RaiseToPower( float power ); +}; + + + +#endif diff --git a/public/mathlib/spherical_geometry.h b/public/mathlib/spherical_geometry.h new file mode 100644 index 0000000..04310f4 --- /dev/null +++ b/public/mathlib/spherical_geometry.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Functions for spherical geometry. +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef SPHERICAL_GEOMETRY_H +#define SPHERICAL_GEOMETRY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +// see http://mathworld.wolfram.com/SphericalTrigonometry.html + +// return the spherical distance, in radians, between 2 points on the unit sphere. +FORCEINLINE float UnitSphereLineSegmentLength( Vector const &a, Vector const &b ) +{ + // check unit length + Assert( fabs( VectorLength( a ) - 1.0 ) < 1.0e-3 ); + Assert( fabs( VectorLength( b ) - 1.0 ) < 1.0e-3 ); + return acos( DotProduct( a, b ) ); +} + + +// given 3 points on the unit sphere, return the spherical area (in radians) of the triangle they form. +// valid for "small" triangles. +FORCEINLINE float UnitSphereTriangleArea( Vector const &a, Vector const &b , Vector const &c ) +{ + float flLengthA = UnitSphereLineSegmentLength( b, c ); + float flLengthB = UnitSphereLineSegmentLength( c, a ); + float flLengthC = UnitSphereLineSegmentLength( a, b ); + + if ( ( flLengthA == 0. ) || ( flLengthB == 0. ) || ( flLengthC == 0. ) ) + return 0.; // zero area triangle + + // now, find the 3 incribed angles for the triangle + float flHalfSumLens = 0.5 * ( flLengthA + flLengthB + flLengthC ); + float flSinSums = sin( flHalfSumLens ); + float flSinSMinusA= sin( flHalfSumLens - flLengthA ); + float flSinSMinusB= sin( flHalfSumLens - flLengthB ); + float flSinSMinusC= sin( flHalfSumLens - flLengthC ); + + float flTanAOver2 = sqrt ( ( flSinSMinusB * flSinSMinusC ) / ( flSinSums * flSinSMinusA ) ); + float flTanBOver2 = sqrt ( ( flSinSMinusA * flSinSMinusC ) / ( flSinSums * flSinSMinusB ) ); + float flTanCOver2 = sqrt ( ( flSinSMinusA * flSinSMinusB ) / ( flSinSums * flSinSMinusC ) ); + + // Girards formula : area = sum of angles - pi. + return 2.0 * ( atan( flTanAOver2 ) + atan( flTanBOver2 ) + atan( flTanCOver2 ) ) - M_PI; +} + +// spherical harmonics-related functions. Best explanation at http://www.research.scea.com/gdc2003/spherical-harmonic-lighting.pdf + +// Evaluate associated legendre polynomial P( l, m ) at flX, using recurrence relation +float AssociatedLegendrePolynomial( int nL, int nM, float flX ); + +// Evaluate order N spherical harmonic with spherical coordinates +// nL = band, 0..N +// nM = -nL .. nL +// theta = 0..M_PI +// phi = 0.. 2 * M_PHI +float SphericalHarmonic( int nL, int nM, float flTheta, float flPhi ); + +// evaluate spherical harmonic with normalized vector direction +float SphericalHarmonic( int nL, int nM, Vector const &vecDirection ); + + +#endif // SPHERICAL_GEOMETRY_H diff --git a/public/mathlib/ssemath.h b/public/mathlib/ssemath.h new file mode 100644 index 0000000..7ef9db1 --- /dev/null +++ b/public/mathlib/ssemath.h @@ -0,0 +1,3098 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: - defines SIMD "structure of arrays" classes and functions. +// +//===========================================================================// +#ifndef SSEMATH_H +#define SSEMATH_H + +#if defined( _X360 ) +#include +#else +#include +#endif + +#include +#include + +#if defined(GNUC) +#define USE_STDC_FOR_SIMD 0 +#else +#define USE_STDC_FOR_SIMD 0 +#endif + +#if (!defined(_X360) && (USE_STDC_FOR_SIMD == 0)) +#define _SSE1 1 +#endif + +// I thought about defining a class/union for the SIMD packed floats instead of using fltx4, +// but decided against it because (a) the nature of SIMD code which includes comparisons is to blur +// the relationship between packed floats and packed integer types and (b) not sure that the +// compiler would handle generating good code for the intrinsics. + +#if USE_STDC_FOR_SIMD + +typedef union +{ + float m128_f32[4]; + uint32 m128_u32[4]; +} fltx4; + +typedef fltx4 i32x4; +typedef fltx4 u32x4; + +#elif ( defined( _X360 ) ) + +typedef union +{ + // This union allows float/int access (which generally shouldn't be done in inner loops) + __vector4 vmx; + float m128_f32[4]; + uint32 m128_u32[4]; +} fltx4_union; + +typedef __vector4 fltx4; +typedef __vector4 i32x4; // a VMX register; just a way of making it explicit that we're doing integer ops. +typedef __vector4 u32x4; // a VMX register; just a way of making it explicit that we're doing unsigned integer ops. + +#else + +typedef __m128 fltx4; +typedef __m128 i32x4; +typedef __m128 u32x4; + +#endif + +// The FLTX4 type is a fltx4 used as a parameter to a function. +// On the 360, the best way to do this is pass-by-copy on the registers. +// On the PC, the best way is to pass by const reference. +// The compiler will sometimes, but not always, replace a pass-by-const-ref +// with a pass-in-reg on the 360; to avoid this confusion, you can +// explicitly use a FLTX4 as the parameter type. +#ifdef _X360 +typedef __vector4 FLTX4; +#else +typedef const fltx4 & FLTX4; +#endif + +// A 16-byte aligned int32 datastructure +// (for use when writing out fltx4's as SIGNED +// ints). +struct ALIGN16 intx4 +{ + int32 m_i32[4]; + + inline int & operator[](int which) + { + return m_i32[which]; + } + + inline const int & operator[](int which) const + { + return m_i32[which]; + } + + inline int32 *Base() { + return m_i32; + } + + inline const int32 *Base() const + { + return m_i32; + } + + inline const bool operator==(const intx4 &other) const + { + return m_i32[0] == other.m_i32[0] && + m_i32[1] == other.m_i32[1] && + m_i32[2] == other.m_i32[2] && + m_i32[3] == other.m_i32[3] ; + } +} ALIGN16_POST; + + +#if defined( _DEBUG ) && defined( _X360 ) +FORCEINLINE void TestVPUFlags() +{ + // Check that the VPU is in the appropriate (Java-compliant) mode (see 3.2.1 in altivec_pem.pdf on xds.xbox.com) + __vector4 a; + __asm + { + mfvscr a; + } + unsigned int * flags = (unsigned int *)&a; + unsigned int controlWord = flags[3]; + Assert(controlWord == 0); +} +#else // _DEBUG +FORCEINLINE void TestVPUFlags() {} +#endif // _DEBUG + + +// useful constants in SIMD packed float format: +// (note: some of these aren't stored on the 360, +// but are manufactured directly in one or two +// instructions, saving a load and possible L2 +// miss.) +#ifndef _X360 +extern const fltx4 Four_Zeros; // 0 0 0 0 +extern const fltx4 Four_Ones; // 1 1 1 1 +extern const fltx4 Four_Twos; // 2 2 2 2 +extern const fltx4 Four_Threes; // 3 3 3 3 +extern const fltx4 Four_Fours; // guess. +extern const fltx4 Four_Point225s; // .225 .225 .225 .225 +extern const fltx4 Four_PointFives; // .5 .5 .5 .5 +extern const fltx4 Four_Epsilons; // FLT_EPSILON FLT_EPSILON FLT_EPSILON FLT_EPSILON +extern const fltx4 Four_2ToThe21s; // (1<<21).. +extern const fltx4 Four_2ToThe22s; // (1<<22).. +extern const fltx4 Four_2ToThe23s; // (1<<23).. +extern const fltx4 Four_2ToThe24s; // (1<<24).. +extern const fltx4 Four_Origin; // 0 0 0 1 (origin point, like vr0 on the PS2) +extern const fltx4 Four_NegativeOnes; // -1 -1 -1 -1 +#else +#define Four_Zeros XMVectorZero() // 0 0 0 0 +#define Four_Ones XMVectorSplatOne() // 1 1 1 1 +extern const fltx4 Four_Twos; // 2 2 2 2 +extern const fltx4 Four_Threes; // 3 3 3 3 +extern const fltx4 Four_Fours; // guess. +extern const fltx4 Four_Point225s; // .225 .225 .225 .225 +extern const fltx4 Four_PointFives; // .5 .5 .5 .5 +extern const fltx4 Four_Epsilons; // FLT_EPSILON FLT_EPSILON FLT_EPSILON FLT_EPSILON +extern const fltx4 Four_2ToThe21s; // (1<<21).. +extern const fltx4 Four_2ToThe22s; // (1<<22).. +extern const fltx4 Four_2ToThe23s; // (1<<23).. +extern const fltx4 Four_2ToThe24s; // (1<<24).. +extern const fltx4 Four_Origin; // 0 0 0 1 (origin point, like vr0 on the PS2) +extern const fltx4 Four_NegativeOnes; // -1 -1 -1 -1 +#endif +extern const fltx4 Four_FLT_MAX; // FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX +extern const fltx4 Four_Negative_FLT_MAX; // -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX +extern const fltx4 g_SIMD_0123; // 0 1 2 3 as float + +// external aligned integer constants +extern const ALIGN16 int32 g_SIMD_clear_signmask[] ALIGN16_POST; // 0x7fffffff x 4 +extern const ALIGN16 int32 g_SIMD_signmask[] ALIGN16_POST; // 0x80000000 x 4 +extern const ALIGN16 int32 g_SIMD_lsbmask[] ALIGN16_POST; // 0xfffffffe x 4 +extern const ALIGN16 int32 g_SIMD_clear_wmask[] ALIGN16_POST; // -1 -1 -1 0 +extern const ALIGN16 int32 g_SIMD_ComponentMask[4][4] ALIGN16_POST; // [0xFFFFFFFF 0 0 0], [0 0xFFFFFFFF 0 0], [0 0 0xFFFFFFFF 0], [0 0 0 0xFFFFFFFF] +extern const ALIGN16 int32 g_SIMD_AllOnesMask[] ALIGN16_POST; // ~0,~0,~0,~0 +extern const ALIGN16 int32 g_SIMD_Low16BitsMask[] ALIGN16_POST; // 0xffff x 4 + +// this mask is used for skipping the tail of things. If you have N elements in an array, and wish +// to mask out the tail, g_SIMD_SkipTailMask[N & 3] what you want to use for the last iteration. +extern const int32 ALIGN16 g_SIMD_SkipTailMask[4][4] ALIGN16_POST; + +// Define prefetch macros. +// The characteristics of cache and prefetch are completely +// different between the different platforms, so you DO NOT +// want to just define one macro that maps to every platform +// intrinsic under the hood -- you need to prefetch at different +// intervals between x86 and PPC, for example, and that is +// a higher level code change. +// On the other hand, I'm tired of typing #ifdef _X360 +// all over the place, so this is just a nop on Intel, PS3. +#ifdef _X360 +#define PREFETCH360(address, offset) __dcbt(offset,address) +#else +#define PREFETCH360(x,y) // nothing +#endif + +#if USE_STDC_FOR_SIMD + +//--------------------------------------------------------------------- +// Standard C (fallback/Linux) implementation (only there for compat - slow) +//--------------------------------------------------------------------- + +FORCEINLINE float SubFloat( const fltx4 & a, int idx ) +{ + return a.m128_f32[ idx ]; +} + +FORCEINLINE float & SubFloat( fltx4 & a, int idx ) +{ + return a.m128_f32[idx]; +} + +FORCEINLINE uint32 SubInt( const fltx4 & a, int idx ) +{ + return a.m128_u32[idx]; +} + +FORCEINLINE uint32 & SubInt( fltx4 & a, int idx ) +{ + return a.m128_u32[idx]; +} + +// Return one in the fastest way -- on the x360, faster even than loading. +FORCEINLINE fltx4 LoadZeroSIMD( void ) +{ + return Four_Zeros; +} + +// Return one in the fastest way -- on the x360, faster even than loading. +FORCEINLINE fltx4 LoadOneSIMD( void ) +{ + return Four_Ones; +} + +FORCEINLINE fltx4 SplatXSIMD( const fltx4 & a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = SubFloat( a, 0 ); + SubFloat( retVal, 1 ) = SubFloat( a, 0 ); + SubFloat( retVal, 2 ) = SubFloat( a, 0 ); + SubFloat( retVal, 3 ) = SubFloat( a, 0 ); + return retVal; +} + +FORCEINLINE fltx4 SplatYSIMD( fltx4 a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = SubFloat( a, 1 ); + SubFloat( retVal, 1 ) = SubFloat( a, 1 ); + SubFloat( retVal, 2 ) = SubFloat( a, 1 ); + SubFloat( retVal, 3 ) = SubFloat( a, 1 ); + return retVal; +} + +FORCEINLINE fltx4 SplatZSIMD( fltx4 a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = SubFloat( a, 2 ); + SubFloat( retVal, 1 ) = SubFloat( a, 2 ); + SubFloat( retVal, 2 ) = SubFloat( a, 2 ); + SubFloat( retVal, 3 ) = SubFloat( a, 2 ); + return retVal; +} + +FORCEINLINE fltx4 SplatWSIMD( fltx4 a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = SubFloat( a, 3 ); + SubFloat( retVal, 1 ) = SubFloat( a, 3 ); + SubFloat( retVal, 2 ) = SubFloat( a, 3 ); + SubFloat( retVal, 3 ) = SubFloat( a, 3 ); + return retVal; +} + +FORCEINLINE fltx4 SetXSIMD( const fltx4& a, const fltx4& x ) +{ + fltx4 result = a; + SubFloat( result, 0 ) = SubFloat( x, 0 ); + return result; +} + +FORCEINLINE fltx4 SetYSIMD( const fltx4& a, const fltx4& y ) +{ + fltx4 result = a; + SubFloat( result, 1 ) = SubFloat( y, 1 ); + return result; +} + +FORCEINLINE fltx4 SetZSIMD( const fltx4& a, const fltx4& z ) +{ + fltx4 result = a; + SubFloat( result, 2 ) = SubFloat( z, 2 ); + return result; +} + +FORCEINLINE fltx4 SetWSIMD( const fltx4& a, const fltx4& w ) +{ + fltx4 result = a; + SubFloat( result, 3 ) = SubFloat( w, 3 ); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD( const fltx4& a, int nComponent, float flValue ) +{ + fltx4 result = a; + SubFloat( result, nComponent ) = flValue; + return result; +} + +// a b c d -> b c d a +FORCEINLINE fltx4 RotateLeft( const fltx4 & a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = SubFloat( a, 1 ); + SubFloat( retVal, 1 ) = SubFloat( a, 2 ); + SubFloat( retVal, 2 ) = SubFloat( a, 3 ); + SubFloat( retVal, 3 ) = SubFloat( a, 0 ); + return retVal; +} + +// a b c d -> c d a b +FORCEINLINE fltx4 RotateLeft2( const fltx4 & a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = SubFloat( a, 2 ); + SubFloat( retVal, 1 ) = SubFloat( a, 3 ); + SubFloat( retVal, 2 ) = SubFloat( a, 0 ); + SubFloat( retVal, 3 ) = SubFloat( a, 1 ); + return retVal; +} + +#define BINOP(op) \ + fltx4 retVal; \ + SubFloat( retVal, 0 ) = ( SubFloat( a, 0 ) op SubFloat( b, 0 ) ); \ + SubFloat( retVal, 1 ) = ( SubFloat( a, 1 ) op SubFloat( b, 1 ) ); \ + SubFloat( retVal, 2 ) = ( SubFloat( a, 2 ) op SubFloat( b, 2 ) ); \ + SubFloat( retVal, 3 ) = ( SubFloat( a, 3 ) op SubFloat( b, 3 ) ); \ + return retVal; + +#define IBINOP(op) \ + fltx4 retVal; \ + SubInt( retVal, 0 ) = ( SubInt( a, 0 ) op SubInt ( b, 0 ) ); \ + SubInt( retVal, 1 ) = ( SubInt( a, 1 ) op SubInt ( b, 1 ) ); \ + SubInt( retVal, 2 ) = ( SubInt( a, 2 ) op SubInt ( b, 2 ) ); \ + SubInt( retVal, 3 ) = ( SubInt( a, 3 ) op SubInt ( b, 3 ) ); \ + return retVal; + +FORCEINLINE fltx4 AddSIMD( const fltx4 & a, const fltx4 & b ) +{ + BINOP(+); +} + +FORCEINLINE fltx4 SubSIMD( const fltx4 & a, const fltx4 & b ) // a-b +{ + BINOP(-); +}; + +FORCEINLINE fltx4 MulSIMD( const fltx4 & a, const fltx4 & b ) // a*b +{ + BINOP(*); +} + +FORCEINLINE fltx4 DivSIMD( const fltx4 & a, const fltx4 & b ) // a/b +{ + BINOP(/); +} + + +FORCEINLINE fltx4 MaddSIMD( const fltx4 & a, const fltx4 & b, const fltx4 & c ) // a*b + c +{ + return AddSIMD( MulSIMD(a,b), c ); +} + +FORCEINLINE fltx4 MsubSIMD( const fltx4 & a, const fltx4 & b, const fltx4 & c ) // c - a*b +{ + return SubSIMD( c, MulSIMD(a,b) ); +}; + + +FORCEINLINE fltx4 SinSIMD( const fltx4 &radians ) +{ + fltx4 result; + SubFloat( result, 0 ) = sin( SubFloat( radians, 0 ) ); + SubFloat( result, 1 ) = sin( SubFloat( radians, 1 ) ); + SubFloat( result, 2 ) = sin( SubFloat( radians, 2 ) ); + SubFloat( result, 3 ) = sin( SubFloat( radians, 3 ) ); + return result; +} + +FORCEINLINE void SinCos3SIMD( fltx4 &sine, fltx4 &cosine, const fltx4 &radians ) +{ + SinCos( SubFloat( radians, 0 ), &SubFloat( sine, 0 ), &SubFloat( cosine, 0 ) ); + SinCos( SubFloat( radians, 1 ), &SubFloat( sine, 1 ), &SubFloat( cosine, 1 ) ); + SinCos( SubFloat( radians, 2 ), &SubFloat( sine, 2 ), &SubFloat( cosine, 2 ) ); +} + +FORCEINLINE void SinCosSIMD( fltx4 &sine, fltx4 &cosine, const fltx4 &radians ) +{ + SinCos( SubFloat( radians, 0 ), &SubFloat( sine, 0 ), &SubFloat( cosine, 0 ) ); + SinCos( SubFloat( radians, 1 ), &SubFloat( sine, 1 ), &SubFloat( cosine, 1 ) ); + SinCos( SubFloat( radians, 2 ), &SubFloat( sine, 2 ), &SubFloat( cosine, 2 ) ); + SinCos( SubFloat( radians, 3 ), &SubFloat( sine, 3 ), &SubFloat( cosine, 3 ) ); +} + +FORCEINLINE fltx4 ArcSinSIMD( const fltx4 &sine ) +{ + fltx4 result; + SubFloat( result, 0 ) = asin( SubFloat( sine, 0 ) ); + SubFloat( result, 1 ) = asin( SubFloat( sine, 1 ) ); + SubFloat( result, 2 ) = asin( SubFloat( sine, 2 ) ); + SubFloat( result, 3 ) = asin( SubFloat( sine, 3 ) ); + return result; +} + +FORCEINLINE fltx4 ArcCosSIMD( const fltx4 &cs ) +{ + fltx4 result; + SubFloat( result, 0 ) = acos( SubFloat( cs, 0 ) ); + SubFloat( result, 1 ) = acos( SubFloat( cs, 1 ) ); + SubFloat( result, 2 ) = acos( SubFloat( cs, 2 ) ); + SubFloat( result, 3 ) = acos( SubFloat( cs, 3 ) ); + return result; +} + +// tan^1(a/b) .. ie, pass sin in as a and cos in as b +FORCEINLINE fltx4 ArcTan2SIMD( const fltx4 &a, const fltx4 &b ) +{ + fltx4 result; + SubFloat( result, 0 ) = atan2( SubFloat( a, 0 ), SubFloat( b, 0 ) ); + SubFloat( result, 1 ) = atan2( SubFloat( a, 1 ), SubFloat( b, 1 ) ); + SubFloat( result, 2 ) = atan2( SubFloat( a, 2 ), SubFloat( b, 2 ) ); + SubFloat( result, 3 ) = atan2( SubFloat( a, 3 ), SubFloat( b, 3 ) ); + return result; +} + +FORCEINLINE fltx4 MaxSIMD( const fltx4 & a, const fltx4 & b ) // max(a,b) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = vmax( SubFloat( a, 0 ), SubFloat( b, 0 ) ); + SubFloat( retVal, 1 ) = vmax( SubFloat( a, 1 ), SubFloat( b, 1 ) ); + SubFloat( retVal, 2 ) = vmax( SubFloat( a, 2 ), SubFloat( b, 2 ) ); + SubFloat( retVal, 3 ) = vmax( SubFloat( a, 3 ), SubFloat( b, 3 ) ); + return retVal; +} + +FORCEINLINE fltx4 MinSIMD( const fltx4 & a, const fltx4 & b ) // min(a,b) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = vmin( SubFloat( a, 0 ), SubFloat( b, 0 ) ); + SubFloat( retVal, 1 ) = vmin( SubFloat( a, 1 ), SubFloat( b, 1 ) ); + SubFloat( retVal, 2 ) = vmin( SubFloat( a, 2 ), SubFloat( b, 2 ) ); + SubFloat( retVal, 3 ) = vmin( SubFloat( a, 3 ), SubFloat( b, 3 ) ); + return retVal; +} + +FORCEINLINE fltx4 AndSIMD( const fltx4 & a, const fltx4 & b ) // a & b +{ + IBINOP(&); +} + +FORCEINLINE fltx4 AndNotSIMD( const fltx4 & a, const fltx4 & b ) // ~a & b +{ + fltx4 retVal; + SubInt( retVal, 0 ) = ~SubInt( a, 0 ) & SubInt( b, 0 ); + SubInt( retVal, 1 ) = ~SubInt( a, 1 ) & SubInt( b, 1 ); + SubInt( retVal, 2 ) = ~SubInt( a, 2 ) & SubInt( b, 2 ); + SubInt( retVal, 3 ) = ~SubInt( a, 3 ) & SubInt( b, 3 ); + return retVal; +} + +FORCEINLINE fltx4 XorSIMD( const fltx4 & a, const fltx4 & b ) // a ^ b +{ + IBINOP(^); +} + +FORCEINLINE fltx4 OrSIMD( const fltx4 & a, const fltx4 & b ) // a | b +{ + IBINOP(|); +} + +FORCEINLINE fltx4 NegSIMD(const fltx4 &a) // negate: -a +{ + fltx4 retval; + SubFloat( retval, 0 ) = -SubFloat( a, 0 ); + SubFloat( retval, 1 ) = -SubFloat( a, 1 ); + SubFloat( retval, 2 ) = -SubFloat( a, 2 ); + SubFloat( retval, 3 ) = -SubFloat( a, 3 ); + + return retval; +} + +FORCEINLINE bool IsAllZeros( const fltx4 & a ) // all floats of a zero? +{ + return ( SubFloat( a, 0 ) == 0.0 ) && + ( SubFloat( a, 1 ) == 0.0 ) && + ( SubFloat( a, 2 ) == 0.0 ) && + ( SubFloat( a, 3 ) == 0.0 ) ; +} + + +// for branching when a.xyzw > b.xyzw +FORCEINLINE bool IsAllGreaterThan( const fltx4 &a, const fltx4 &b ) +{ + return SubFloat(a,0) > SubFloat(b,0) && + SubFloat(a,1) > SubFloat(b,1) && + SubFloat(a,2) > SubFloat(b,2) && + SubFloat(a,3) > SubFloat(b,3); +} + +// for branching when a.xyzw >= b.xyzw +FORCEINLINE bool IsAllGreaterThanOrEq( const fltx4 &a, const fltx4 &b ) +{ + return SubFloat(a,0) >= SubFloat(b,0) && + SubFloat(a,1) >= SubFloat(b,1) && + SubFloat(a,2) >= SubFloat(b,2) && + SubFloat(a,3) >= SubFloat(b,3); +} + +// For branching if all a.xyzw == b.xyzw +FORCEINLINE bool IsAllEqual( const fltx4 & a, const fltx4 & b ) +{ + return SubFloat(a,0) == SubFloat(b,0) && + SubFloat(a,1) == SubFloat(b,1) && + SubFloat(a,2) == SubFloat(b,2) && + SubFloat(a,3) == SubFloat(b,3); +} + +FORCEINLINE int TestSignSIMD( const fltx4 & a ) // mask of which floats have the high bit set +{ + int nRet = 0; + + nRet |= ( SubInt( a, 0 ) & 0x80000000 ) >> 31; // sign(x) -> bit 0 + nRet |= ( SubInt( a, 1 ) & 0x80000000 ) >> 30; // sign(y) -> bit 1 + nRet |= ( SubInt( a, 2 ) & 0x80000000 ) >> 29; // sign(z) -> bit 2 + nRet |= ( SubInt( a, 3 ) & 0x80000000 ) >> 28; // sign(w) -> bit 3 + + return nRet; +} + +FORCEINLINE bool IsAnyNegative( const fltx4 & a ) // (a.x < 0) || (a.y < 0) || (a.z < 0) || (a.w < 0) +{ + return (0 != TestSignSIMD( a )); +} + +FORCEINLINE fltx4 CmpEqSIMD( const fltx4 & a, const fltx4 & b ) // (a==b) ? ~0:0 +{ + fltx4 retVal; + SubInt( retVal, 0 ) = ( SubFloat( a, 0 ) == SubFloat( b, 0 )) ? ~0 : 0; + SubInt( retVal, 1 ) = ( SubFloat( a, 1 ) == SubFloat( b, 1 )) ? ~0 : 0; + SubInt( retVal, 2 ) = ( SubFloat( a, 2 ) == SubFloat( b, 2 )) ? ~0 : 0; + SubInt( retVal, 3 ) = ( SubFloat( a, 3 ) == SubFloat( b, 3 )) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpGtSIMD( const fltx4 & a, const fltx4 & b ) // (a>b) ? ~0:0 +{ + fltx4 retVal; + SubInt( retVal, 0 ) = ( SubFloat( a, 0 ) > SubFloat( b, 0 )) ? ~0 : 0; + SubInt( retVal, 1 ) = ( SubFloat( a, 1 ) > SubFloat( b, 1 )) ? ~0 : 0; + SubInt( retVal, 2 ) = ( SubFloat( a, 2 ) > SubFloat( b, 2 )) ? ~0 : 0; + SubInt( retVal, 3 ) = ( SubFloat( a, 3 ) > SubFloat( b, 3 )) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpGeSIMD( const fltx4 & a, const fltx4 & b ) // (a>=b) ? ~0:0 +{ + fltx4 retVal; + SubInt( retVal, 0 ) = ( SubFloat( a, 0 ) >= SubFloat( b, 0 )) ? ~0 : 0; + SubInt( retVal, 1 ) = ( SubFloat( a, 1 ) >= SubFloat( b, 1 )) ? ~0 : 0; + SubInt( retVal, 2 ) = ( SubFloat( a, 2 ) >= SubFloat( b, 2 )) ? ~0 : 0; + SubInt( retVal, 3 ) = ( SubFloat( a, 3 ) >= SubFloat( b, 3 )) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpLtSIMD( const fltx4 & a, const fltx4 & b ) // (a= -b) ? ~0 : 0 +{ + fltx4 retVal; + SubInt( retVal, 0 ) = ( SubFloat( a, 0 ) <= SubFloat( b, 0 ) && SubFloat( a, 0 ) >= -SubFloat( b, 0 ) ) ? ~0 : 0; + SubInt( retVal, 1 ) = ( SubFloat( a, 1 ) <= SubFloat( b, 1 ) && SubFloat( a, 1 ) >= -SubFloat( b, 1 ) ) ? ~0 : 0; + SubInt( retVal, 2 ) = ( SubFloat( a, 2 ) <= SubFloat( b, 2 ) && SubFloat( a, 2 ) >= -SubFloat( b, 2 ) ) ? ~0 : 0; + SubInt( retVal, 3 ) = ( SubFloat( a, 3 ) <= SubFloat( b, 3 ) && SubFloat( a, 3 ) >= -SubFloat( b, 3 ) ) ? ~0 : 0; + return retVal; +} + + +FORCEINLINE fltx4 MaskedAssign( const fltx4 & ReplacementMask, const fltx4 & NewValue, const fltx4 & OldValue ) +{ + return OrSIMD( + AndSIMD( ReplacementMask, NewValue ), + AndNotSIMD( ReplacementMask, OldValue ) ); +} + +FORCEINLINE fltx4 ReplicateX4( float flValue ) // a,a,a,a +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = flValue; + SubFloat( retVal, 1 ) = flValue; + SubFloat( retVal, 2 ) = flValue; + SubFloat( retVal, 3 ) = flValue; + return retVal; +} + +/// replicate a single 32 bit integer value to all 4 components of an m128 +FORCEINLINE fltx4 ReplicateIX4( int nValue ) +{ + fltx4 retVal; + SubInt( retVal, 0 ) = nValue; + SubInt( retVal, 1 ) = nValue; + SubInt( retVal, 2 ) = nValue; + SubInt( retVal, 3 ) = nValue; + return retVal; + +} + +// Round towards positive infinity +FORCEINLINE fltx4 CeilSIMD( const fltx4 &a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = ceil( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = ceil( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = ceil( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = ceil( SubFloat( a, 3 ) ); + return retVal; + +} + +// Round towards negative infinity +FORCEINLINE fltx4 FloorSIMD( const fltx4 &a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = floor( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = floor( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = floor( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = floor( SubFloat( a, 3 ) ); + return retVal; + +} + +FORCEINLINE fltx4 SqrtEstSIMD( const fltx4 & a ) // sqrt(a), more or less +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = sqrt( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = sqrt( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = sqrt( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = sqrt( SubFloat( a, 3 ) ); + return retVal; +} + +FORCEINLINE fltx4 SqrtSIMD( const fltx4 & a ) // sqrt(a) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = sqrt( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = sqrt( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = sqrt( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = sqrt( SubFloat( a, 3 ) ); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD( const fltx4 & a ) // 1/sqrt(a), more or less +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / sqrt( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = 1.0 / sqrt( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = 1.0 / sqrt( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = 1.0 / sqrt( SubFloat( a, 3 ) ); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD( const fltx4 & a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / sqrt( SubFloat( a, 0 ) != 0.0f ? SubFloat( a, 0 ) : FLT_EPSILON ); + SubFloat( retVal, 1 ) = 1.0 / sqrt( SubFloat( a, 1 ) != 0.0f ? SubFloat( a, 1 ) : FLT_EPSILON ); + SubFloat( retVal, 2 ) = 1.0 / sqrt( SubFloat( a, 2 ) != 0.0f ? SubFloat( a, 2 ) : FLT_EPSILON ); + SubFloat( retVal, 3 ) = 1.0 / sqrt( SubFloat( a, 3 ) != 0.0f ? SubFloat( a, 3 ) : FLT_EPSILON ); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD( const fltx4 & a ) // 1/sqrt(a) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / sqrt( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = 1.0 / sqrt( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = 1.0 / sqrt( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = 1.0 / sqrt( SubFloat( a, 3 ) ); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD( const fltx4 & a ) // 1/a, more or less +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / SubFloat( a, 0 ); + SubFloat( retVal, 1 ) = 1.0 / SubFloat( a, 1 ); + SubFloat( retVal, 2 ) = 1.0 / SubFloat( a, 2 ); + SubFloat( retVal, 3 ) = 1.0 / SubFloat( a, 3 ); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSIMD( const fltx4 & a ) // 1/a +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / SubFloat( a, 0 ); + SubFloat( retVal, 1 ) = 1.0 / SubFloat( a, 1 ); + SubFloat( retVal, 2 ) = 1.0 / SubFloat( a, 2 ); + SubFloat( retVal, 3 ) = 1.0 / SubFloat( a, 3 ); + return retVal; +} + +/// 1/x for all 4 values. +/// 1/0 will result in a big but NOT infinite result +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD( const fltx4 & a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / (SubFloat( a, 0 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 0 )); + SubFloat( retVal, 1 ) = 1.0 / (SubFloat( a, 1 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 1 )); + SubFloat( retVal, 2 ) = 1.0 / (SubFloat( a, 2 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 2 )); + SubFloat( retVal, 3 ) = 1.0 / (SubFloat( a, 3 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 3 )); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD( const fltx4 & a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = 1.0 / (SubFloat( a, 0 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 0 )); + SubFloat( retVal, 1 ) = 1.0 / (SubFloat( a, 1 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 1 )); + SubFloat( retVal, 2 ) = 1.0 / (SubFloat( a, 2 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 2 )); + SubFloat( retVal, 3 ) = 1.0 / (SubFloat( a, 3 ) == 0.0f ? FLT_EPSILON : SubFloat( a, 3 )); + return retVal; +} + +// 2^x for all values (the antilog) +FORCEINLINE fltx4 ExpSIMD( const fltx4 &toPower ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = powf( 2, SubFloat(toPower, 0) ); + SubFloat( retVal, 1 ) = powf( 2, SubFloat(toPower, 1) ); + SubFloat( retVal, 2 ) = powf( 2, SubFloat(toPower, 2) ); + SubFloat( retVal, 3 ) = powf( 2, SubFloat(toPower, 3) ); + + return retVal; +} + +FORCEINLINE fltx4 Dot3SIMD( const fltx4 &a, const fltx4 &b ) +{ + float flDot = SubFloat( a, 0 ) * SubFloat( b, 0 ) + + SubFloat( a, 1 ) * SubFloat( b, 1 ) + + SubFloat( a, 2 ) * SubFloat( b, 2 ); + return ReplicateX4( flDot ); +} + +FORCEINLINE fltx4 Dot4SIMD( const fltx4 &a, const fltx4 &b ) +{ + float flDot = SubFloat( a, 0 ) * SubFloat( b, 0 ) + + SubFloat( a, 1 ) * SubFloat( b, 1 ) + + SubFloat( a, 2 ) * SubFloat( b, 2 ) + + SubFloat( a, 3 ) * SubFloat( b, 3 ); + return ReplicateX4( flDot ); +} + +// Clamps the components of a vector to a specified minimum and maximum range. +FORCEINLINE fltx4 ClampVectorSIMD( FLTX4 in, FLTX4 min, FLTX4 max) +{ + return MaxSIMD( min, MinSIMD( max, in ) ); +} + +// Squelch the w component of a vector to +0.0. +// Most efficient when you say a = SetWToZeroSIMD(a) (avoids a copy) +FORCEINLINE fltx4 SetWToZeroSIMD( const fltx4 & a ) +{ + fltx4 retval; + retval = a; + SubFloat( retval, 0 ) = 0; + return retval; +} + +FORCEINLINE fltx4 LoadUnalignedSIMD( const void *pSIMD ) +{ + return *( reinterpret_cast< const fltx4 *> ( pSIMD ) ); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD( const void *pSIMD ) +{ + return *( reinterpret_cast< const fltx4 *> ( pSIMD ) ); +} + +FORCEINLINE fltx4 LoadAlignedSIMD( const void *pSIMD ) +{ + return *( reinterpret_cast< const fltx4 *> ( pSIMD ) ); +} + +// for the transitional class -- load a 3-by VectorAligned and squash its w component +FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned & pSIMD ) +{ + fltx4 retval = LoadAlignedSIMD(pSIMD.Base()); + // squelch w + SubInt( retval, 3 ) = 0; + return retval; +} + +FORCEINLINE void StoreAlignedSIMD( float *pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< fltx4 *> ( pSIMD ) ) = a; +} + +FORCEINLINE void StoreUnalignedSIMD( float *pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< fltx4 *> ( pSIMD ) ) = a; +} + +FORCEINLINE void StoreUnaligned3SIMD( float *pSIMD, const fltx4 & a ) +{ + *pSIMD = SubFloat(a, 0); + *(pSIMD+1) = SubFloat(a, 1); + *(pSIMD+2) = SubFloat(a, 2); +} + +// strongly typed -- syntactic castor oil used for typechecking as we transition to SIMD +FORCEINLINE void StoreAligned3SIMD( VectorAligned * RESTRICT pSIMD, const fltx4 & a ) +{ + StoreAlignedSIMD(pSIMD->Base(),a); +} + +FORCEINLINE void TransposeSIMD( fltx4 & x, fltx4 & y, fltx4 & z, fltx4 & w ) +{ +#define SWAP_FLOATS( _a_, _ia_, _b_, _ib_ ) { float tmp = SubFloat( _a_, _ia_ ); SubFloat( _a_, _ia_ ) = SubFloat( _b_, _ib_ ); SubFloat( _b_, _ib_ ) = tmp; } + SWAP_FLOATS( x, 1, y, 0 ); + SWAP_FLOATS( x, 2, z, 0 ); + SWAP_FLOATS( x, 3, w, 0 ); + SWAP_FLOATS( y, 2, z, 1 ); + SWAP_FLOATS( y, 3, w, 1 ); + SWAP_FLOATS( z, 3, w, 2 ); +} + +// find the lowest component of a.x, a.y, a.z, +// and replicate it to the whole return value. +FORCEINLINE fltx4 FindLowestSIMD3( const fltx4 & a ) +{ + float lowest = vmin( vmin( SubFloat(a, 0), SubFloat(a, 1) ), SubFloat(a, 2)); + return ReplicateX4(lowest); +} + +// find the highest component of a.x, a.y, a.z, +// and replicate it to the whole return value. +FORCEINLINE fltx4 FindHighestSIMD3( const fltx4 & a ) +{ + float highest = vmax( vmax( SubFloat(a, 0), SubFloat(a, 1) ), SubFloat(a, 2)); + return ReplicateX4(highest); +} + +// Fixed-point conversion and save as SIGNED INTS. +// pDest->x = Int (vSrc.x) +// note: some architectures have means of doing +// fixed point conversion when the fix depth is +// specified as an immediate.. but there is no way +// to guarantee an immediate as a parameter to function +// like this. +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4 * RESTRICT pDest, const fltx4 &vSrc) +{ + (*pDest)[0] = SubFloat(vSrc, 0); + (*pDest)[1] = SubFloat(vSrc, 1); + (*pDest)[2] = SubFloat(vSrc, 2); + (*pDest)[3] = SubFloat(vSrc, 3); +} + +// ------------------------------------ +// INTEGER SIMD OPERATIONS. +// ------------------------------------ +// splat all components of a vector to a signed immediate int number. +FORCEINLINE fltx4 IntSetImmediateSIMD( int nValue ) +{ + fltx4 retval; + SubInt( retval, 0 ) = SubInt( retval, 1 ) = SubInt( retval, 2 ) = SubInt( retval, 3) = nValue; + return retval; +} + +// Load 4 aligned words into a SIMD register +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void * RESTRICT pSIMD) +{ + return *( reinterpret_cast< const i32x4 *> ( pSIMD ) ); +} + +// Load 4 unaligned words into a SIMD register +FORCEINLINE i32x4 LoadUnalignedIntSIMD( const void * RESTRICT pSIMD) +{ + return *( reinterpret_cast< const i32x4 *> ( pSIMD ) ); +} + +// save into four words, 16-byte aligned +FORCEINLINE void StoreAlignedIntSIMD( int32 *pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< i32x4 *> ( pSIMD ) ) = a; +} + +FORCEINLINE void StoreAlignedIntSIMD( intx4 &pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< i32x4 *> ( pSIMD.Base() ) ) = a; +} + +FORCEINLINE void StoreUnalignedIntSIMD( int32 *pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< i32x4 *> ( pSIMD ) ) = a; +} + +// Take a fltx4 containing fixed-point uints and +// return them as single precision floats. No +// fixed point conversion is done. +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD( const u32x4 &vSrcA ) +{ + Assert(0); /* pc has no such operation */ + fltx4 retval; + SubFloat( retval, 0 ) = ( (float) SubInt( retval, 0 ) ); + SubFloat( retval, 1 ) = ( (float) SubInt( retval, 1 ) ); + SubFloat( retval, 2 ) = ( (float) SubInt( retval, 2 ) ); + SubFloat( retval, 3 ) = ( (float) SubInt( retval, 3 ) ); + return retval; +} + + +#if 0 /* pc has no such op */ +// Take a fltx4 containing fixed-point sints and +// return them as single precision floats. No +// fixed point conversion is done. +FORCEINLINE fltx4 SignedIntConvertToFltSIMD( const i32x4 &vSrcA ) +{ + fltx4 retval; + SubFloat( retval, 0 ) = ( (float) (reinterpret_cast(&vSrcA.m128_s32[0])) ); + SubFloat( retval, 1 ) = ( (float) (reinterpret_cast(&vSrcA.m128_s32[1])) ); + SubFloat( retval, 2 ) = ( (float) (reinterpret_cast(&vSrcA.m128_s32[2])) ); + SubFloat( retval, 3 ) = ( (float) (reinterpret_cast(&vSrcA.m128_s32[3])) ); + return retval; +} + + +/* + works on fltx4's as if they are four uints. + the first parameter contains the words to be shifted, + the second contains the amount to shift by AS INTS + + for i = 0 to 3 + shift = vSrcB_i*32:(i*32)+4 + vReturned_i*32:(i*32)+31 = vSrcA_i*32:(i*32)+31 << shift +*/ +FORCEINLINE i32x4 IntShiftLeftWordSIMD(const i32x4 &vSrcA, const i32x4 &vSrcB) +{ + i32x4 retval; + SubInt(retval, 0) = SubInt(vSrcA, 0) << SubInt(vSrcB, 0); + SubInt(retval, 1) = SubInt(vSrcA, 1) << SubInt(vSrcB, 1); + SubInt(retval, 2) = SubInt(vSrcA, 2) << SubInt(vSrcB, 2); + SubInt(retval, 3) = SubInt(vSrcA, 3) << SubInt(vSrcB, 3); + + + return retval; +} +#endif + +#elif ( defined( _X360 ) ) + +//--------------------------------------------------------------------- +// X360 implementation +//--------------------------------------------------------------------- + +FORCEINLINE float & FloatSIMD( fltx4 & a, int idx ) +{ + fltx4_union & a_union = (fltx4_union &)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE unsigned int & UIntSIMD( fltx4 & a, int idx ) +{ + fltx4_union & a_union = (fltx4_union &)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE fltx4 AddSIMD( const fltx4 & a, const fltx4 & b ) +{ + return __vaddfp( a, b ); +} + +FORCEINLINE fltx4 SubSIMD( const fltx4 & a, const fltx4 & b ) // a-b +{ + return __vsubfp( a, b ); +} + +FORCEINLINE fltx4 MulSIMD( const fltx4 & a, const fltx4 & b ) // a*b +{ + return __vmulfp( a, b ); +} + +FORCEINLINE fltx4 MaddSIMD( const fltx4 & a, const fltx4 & b, const fltx4 & c ) // a*b + c +{ + return __vmaddfp( a, b, c ); +} + +FORCEINLINE fltx4 MsubSIMD( const fltx4 & a, const fltx4 & b, const fltx4 & c ) // c - a*b +{ + return __vnmsubfp( a, b, c ); +}; + +FORCEINLINE fltx4 Dot3SIMD( const fltx4 &a, const fltx4 &b ) +{ + return __vmsum3fp( a, b ); +} + +FORCEINLINE fltx4 Dot4SIMD( const fltx4 &a, const fltx4 &b ) +{ + return __vmsum4fp( a, b ); +} + +FORCEINLINE fltx4 SinSIMD( const fltx4 &radians ) +{ + return XMVectorSin( radians ); +} + +FORCEINLINE void SinCos3SIMD( fltx4 &sine, fltx4 &cosine, const fltx4 &radians ) +{ + XMVectorSinCos( &sine, &cosine, radians ); +} + +FORCEINLINE void SinCosSIMD( fltx4 &sine, fltx4 &cosine, const fltx4 &radians ) +{ + XMVectorSinCos( &sine, &cosine, radians ); +} + +FORCEINLINE void CosSIMD( fltx4 &cosine, const fltx4 &radians ) +{ + cosine = XMVectorCos( radians ); +} + +FORCEINLINE fltx4 ArcSinSIMD( const fltx4 &sine ) +{ + return XMVectorASin( sine ); +} + +FORCEINLINE fltx4 ArcCosSIMD( const fltx4 &cs ) +{ + return XMVectorACos( cs ); +} + +// tan^1(a/b) .. ie, pass sin in as a and cos in as b +FORCEINLINE fltx4 ArcTan2SIMD( const fltx4 &a, const fltx4 &b ) +{ + return XMVectorATan2( a, b ); +} + +// DivSIMD defined further down, since it uses ReciprocalSIMD + +FORCEINLINE fltx4 MaxSIMD( const fltx4 & a, const fltx4 & b ) // max(a,b) +{ + return __vmaxfp( a, b ); +} + +FORCEINLINE fltx4 MinSIMD( const fltx4 & a, const fltx4 & b ) // min(a,b) +{ + return __vminfp( a, b ); +} + +FORCEINLINE fltx4 AndSIMD( const fltx4 & a, const fltx4 & b ) // a & b +{ + return __vand( a, b ); +} + +FORCEINLINE fltx4 AndNotSIMD( const fltx4 & a, const fltx4 & b ) // ~a & b +{ + // NOTE: a and b are swapped in the call: SSE complements the first argument, VMX the second + return __vandc( b, a ); +} + +FORCEINLINE fltx4 XorSIMD( const fltx4 & a, const fltx4 & b ) // a ^ b +{ + return __vxor( a, b ); +} + +FORCEINLINE fltx4 OrSIMD( const fltx4 & a, const fltx4 & b ) // a | b +{ + return __vor( a, b ); +} + +FORCEINLINE fltx4 NegSIMD(const fltx4 &a) // negate: -a +{ + return XMVectorNegate(a); +} + +FORCEINLINE bool IsAllZeros( const fltx4 & a ) // all floats of a zero? +{ + unsigned int equalFlags = 0; + __vcmpeqfpR( a, Four_Zeros, &equalFlags ); + return XMComparisonAllTrue( equalFlags ); +} + +FORCEINLINE bool IsAnyZeros( const fltx4 & a ) // any floats are zero? +{ + unsigned int conditionregister; + XMVectorEqualR(&conditionregister, a, XMVectorZero()); + return XMComparisonAnyTrue(conditionregister); +} + +FORCEINLINE bool IsAnyXYZZero( const fltx4 &a ) // are any of x,y,z zero? +{ + // copy a's x component into w, in case w was zero. + fltx4 temp = __vrlimi(a, a, 1, 1); + unsigned int conditionregister; + XMVectorEqualR(&conditionregister, temp, XMVectorZero()); + return XMComparisonAnyTrue(conditionregister); +} + +// for branching when a.xyzw > b.xyzw +FORCEINLINE bool IsAllGreaterThan( const fltx4 &a, const fltx4 &b ) +{ + unsigned int cr; + XMVectorGreaterR(&cr,a,b); + return XMComparisonAllTrue(cr); +} + +// for branching when a.xyzw >= b.xyzw +FORCEINLINE bool IsAllGreaterThanOrEq( const fltx4 &a, const fltx4 &b ) +{ + unsigned int cr; + XMVectorGreaterOrEqualR(&cr,a,b); + return XMComparisonAllTrue(cr); +} + +// For branching if all a.xyzw == b.xyzw +FORCEINLINE bool IsAllEqual( const fltx4 & a, const fltx4 & b ) +{ + unsigned int cr; + XMVectorEqualR(&cr,a,b); + return XMComparisonAllTrue(cr); +} + + +FORCEINLINE int TestSignSIMD( const fltx4 & a ) // mask of which floats have the high bit set +{ + // NOTE: this maps to SSE way better than it does to VMX (most code uses IsAnyNegative(), though) + int nRet = 0; + + const fltx4_union & a_union = (const fltx4_union &)a; + nRet |= ( a_union.m128_u32[0] & 0x80000000 ) >> 31; // sign(x) -> bit 0 + nRet |= ( a_union.m128_u32[1] & 0x80000000 ) >> 30; // sign(y) -> bit 1 + nRet |= ( a_union.m128_u32[2] & 0x80000000 ) >> 29; // sign(z) -> bit 2 + nRet |= ( a_union.m128_u32[3] & 0x80000000 ) >> 28; // sign(w) -> bit 3 + + return nRet; +} + +// Squelch the w component of a vector to +0.0. +// Most efficient when you say a = SetWToZeroSIMD(a) (avoids a copy) +FORCEINLINE fltx4 SetWToZeroSIMD( const fltx4 & a ) +{ + return __vrlimi( a, __vzero(), 1, 0 ); +} + +FORCEINLINE bool IsAnyNegative( const fltx4 & a ) // (a.x < 0) || (a.y < 0) || (a.z < 0) || (a.w < 0) +{ + // NOTE: this tests the top bits of each vector element using integer math + // (so it ignores NaNs - it will return true for "-NaN") + unsigned int equalFlags = 0; + fltx4 signMask = __vspltisw( -1 ); // 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF (low order 5 bits of each element = 31) + signMask = __vslw( signMask, signMask ); // 0x80000000 0x80000000 0x80000000 0x80000000 + __vcmpequwR( Four_Zeros, __vand( signMask, a ), &equalFlags ); + return !XMComparisonAllTrue( equalFlags ); +} + +FORCEINLINE fltx4 CmpEqSIMD( const fltx4 & a, const fltx4 & b ) // (a==b) ? ~0:0 +{ + return __vcmpeqfp( a, b ); +} + + +FORCEINLINE fltx4 CmpGtSIMD( const fltx4 & a, const fltx4 & b ) // (a>b) ? ~0:0 +{ + return __vcmpgtfp( a, b ); +} + +FORCEINLINE fltx4 CmpGeSIMD( const fltx4 & a, const fltx4 & b ) // (a>=b) ? ~0:0 +{ + return __vcmpgefp( a, b ); +} + +FORCEINLINE fltx4 CmpLtSIMD( const fltx4 & a, const fltx4 & b ) // (a= -b) ? ~0 : 0 +{ + return XMVectorInBounds( a, b ); +} + +// returned[i] = ReplacementMask[i] == 0 ? OldValue : NewValue +FORCEINLINE fltx4 MaskedAssign( const fltx4 & ReplacementMask, const fltx4 & NewValue, const fltx4 & OldValue ) +{ + return __vsel( OldValue, NewValue, ReplacementMask ); +} + +// AKA "Broadcast", "Splat" +FORCEINLINE fltx4 ReplicateX4( float flValue ) // a,a,a,a +{ + // NOTE: if flValue comes from a register, this causes a Load-Hit-Store stall (don't mix fpu/vpu math!) + float * pValue = &flValue; + Assert( pValue ); + Assert( ((unsigned int)pValue & 3) == 0); + return __vspltw( __lvlx( pValue, 0 ), 0 ); +} + +FORCEINLINE fltx4 ReplicateX4( const float *pValue ) // a,a,a,a +{ + Assert( pValue ); + return __vspltw( __lvlx( pValue, 0 ), 0 ); +} + +/// replicate a single 32 bit integer value to all 4 components of an m128 +FORCEINLINE fltx4 ReplicateIX4( int nValue ) +{ + // NOTE: if nValue comes from a register, this causes a Load-Hit-Store stall (should not mix ints with fltx4s!) + int * pValue = &nValue; + Assert( pValue ); + Assert( ((unsigned int)pValue & 3) == 0); + return __vspltw( __lvlx( pValue, 0 ), 0 ); +} + +// Round towards positive infinity +FORCEINLINE fltx4 CeilSIMD( const fltx4 &a ) +{ + return __vrfip(a); +} + +// Round towards nearest integer +FORCEINLINE fltx4 RoundSIMD( const fltx4 &a ) +{ + return __vrfin(a); +} + +// Round towards negative infinity +FORCEINLINE fltx4 FloorSIMD( const fltx4 &a ) +{ + return __vrfim(a); +} + +FORCEINLINE fltx4 SqrtEstSIMD( const fltx4 & a ) // sqrt(a), more or less +{ + // This is emulated from rsqrt + return XMVectorSqrtEst( a ); +} + +FORCEINLINE fltx4 SqrtSIMD( const fltx4 & a ) // sqrt(a) +{ + // This is emulated from rsqrt + return XMVectorSqrt( a ); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD( const fltx4 & a ) // 1/sqrt(a), more or less +{ + return __vrsqrtefp( a ); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD( const fltx4 & a ) +{ + // Convert zeros to epsilons + fltx4 zero_mask = CmpEqSIMD( a, Four_Zeros ); + fltx4 a_safe = OrSIMD( a, AndSIMD( Four_Epsilons, zero_mask ) ); + return ReciprocalSqrtEstSIMD( a_safe ); +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD( const fltx4 & a ) // 1/sqrt(a) +{ + // This uses Newton-Raphson to improve the HW result + return XMVectorReciprocalSqrt( a ); +} + +FORCEINLINE fltx4 ReciprocalEstSIMD( const fltx4 & a ) // 1/a, more or less +{ + return __vrefp( a ); +} + +/// 1/x for all 4 values. uses reciprocal approximation instruction plus newton iteration. +/// No error checking! +FORCEINLINE fltx4 ReciprocalSIMD( const fltx4 & a ) // 1/a +{ + // This uses Newton-Raphson to improve the HW result + return XMVectorReciprocal( a ); +} + +// FIXME: on 360, this is very slow, since it uses ReciprocalSIMD (do we need DivEstSIMD?) +FORCEINLINE fltx4 DivSIMD( const fltx4 & a, const fltx4 & b ) // a/b +{ + return MulSIMD( ReciprocalSIMD( b ), a ); +} + +/// 1/x for all 4 values. +/// 1/0 will result in a big but NOT infinite result +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD( const fltx4 & a ) +{ + // Convert zeros to epsilons + fltx4 zero_mask = CmpEqSIMD( a, Four_Zeros ); + fltx4 a_safe = OrSIMD( a, AndSIMD( Four_Epsilons, zero_mask ) ); + return ReciprocalEstSIMD( a_safe ); +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD( const fltx4 & a ) +{ + // Convert zeros to epsilons + fltx4 zero_mask = CmpEqSIMD( a, Four_Zeros ); + fltx4 a_safe = OrSIMD( a, AndSIMD( Four_Epsilons, zero_mask ) ); + return ReciprocalSIMD( a_safe ); + + // FIXME: This could be faster (BUT: it doesn't preserve the sign of -0.0, whereas the above does) + // fltx4 zeroMask = CmpEqSIMD( Four_Zeros, a ); + // fltx4 a_safe = XMVectorSelect( a, Four_Epsilons, zeroMask ); + // return ReciprocalSIMD( a_safe ); +} + +// CHRISG: is it worth doing integer bitfiddling for this? +// 2^x for all values (the antilog) +FORCEINLINE fltx4 ExpSIMD( const fltx4 &toPower ) +{ + return XMVectorExp(toPower); +} + +// Clamps the components of a vector to a specified minimum and maximum range. +FORCEINLINE fltx4 ClampVectorSIMD( FLTX4 in, FLTX4 min, FLTX4 max) +{ + return XMVectorClamp(in, min, max); +} + +FORCEINLINE fltx4 LoadUnalignedSIMD( const void *pSIMD ) +{ + return XMLoadVector4( pSIMD ); +} + +// load a 3-vector (as opposed to LoadUnalignedSIMD, which loads a 4-vec). +FORCEINLINE fltx4 LoadUnaligned3SIMD( const void *pSIMD ) +{ + return XMLoadVector3( pSIMD ); +} + +FORCEINLINE fltx4 LoadAlignedSIMD( const void *pSIMD ) +{ + return *( reinterpret_cast< const fltx4 *> ( pSIMD ) ); +} + +// for the transitional class -- load a 3-by VectorAligned and squash its w component +FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned & pSIMD ) +{ + fltx4 out = XMLoadVector3A(pSIMD.Base()); + // squelch w + return __vrlimi( out, __vzero(), 1, 0 ); +} + +// for the transitional class -- load a 3-by VectorAligned and squash its w component +FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned * RESTRICT pSIMD ) +{ + fltx4 out = XMLoadVector3A(pSIMD); + // squelch w + return __vrlimi( out, __vzero(), 1, 0 ); +} + +FORCEINLINE void StoreAlignedSIMD( float *pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< fltx4 *> ( pSIMD ) ) = a; +} + +FORCEINLINE void StoreUnalignedSIMD( float *pSIMD, const fltx4 & a ) +{ + XMStoreVector4( pSIMD, a ); +} + +FORCEINLINE void StoreUnaligned3SIMD( float *pSIMD, const fltx4 & a ) +{ + XMStoreVector3( pSIMD, a ); +} + + +// strongly typed -- for typechecking as we transition to SIMD +FORCEINLINE void StoreAligned3SIMD( VectorAligned * RESTRICT pSIMD, const fltx4 & a ) +{ + XMStoreVector3A(pSIMD->Base(),a); +} + + +// Fixed-point conversion and save as SIGNED INTS. +// pDest->x = Int (vSrc.x) +// note: some architectures have means of doing +// fixed point conversion when the fix depth is +// specified as an immediate.. but there is no way +// to guarantee an immediate as a parameter to function +// like this. +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4 * RESTRICT pDest, const fltx4 &vSrc) +{ + fltx4 asInt = __vctsxs( vSrc, 0 ); + XMStoreVector4A(pDest->Base(), asInt); +} + +FORCEINLINE void TransposeSIMD( fltx4 & x, fltx4 & y, fltx4 & z, fltx4 & w ) +{ + XMMATRIX xyzwMatrix = _XMMATRIX( x, y, z, w ); + xyzwMatrix = XMMatrixTranspose( xyzwMatrix ); + x = xyzwMatrix.r[0]; + y = xyzwMatrix.r[1]; + z = xyzwMatrix.r[2]; + w = xyzwMatrix.r[3]; +} + +// Return one in the fastest way -- faster even than loading. +FORCEINLINE fltx4 LoadZeroSIMD( void ) +{ + return XMVectorZero(); +} + +// Return one in the fastest way -- faster even than loading. +FORCEINLINE fltx4 LoadOneSIMD( void ) +{ + return XMVectorSplatOne(); +} + +FORCEINLINE fltx4 SplatXSIMD( fltx4 a ) +{ + return XMVectorSplatX( a ); +} + +FORCEINLINE fltx4 SplatYSIMD( fltx4 a ) +{ + return XMVectorSplatY( a ); +} + +FORCEINLINE fltx4 SplatZSIMD( fltx4 a ) +{ + return XMVectorSplatZ( a ); +} + +FORCEINLINE fltx4 SplatWSIMD( fltx4 a ) +{ + return XMVectorSplatW( a ); +} + +FORCEINLINE fltx4 SetXSIMD( const fltx4& a, const fltx4& x ) +{ + fltx4 result = __vrlimi(a, x, 8, 0); + return result; +} + +FORCEINLINE fltx4 SetYSIMD( const fltx4& a, const fltx4& y ) +{ + fltx4 result = __vrlimi(a, y, 4, 0); + return result; +} + +FORCEINLINE fltx4 SetZSIMD( const fltx4& a, const fltx4& z ) +{ + fltx4 result = __vrlimi(a, z, 2, 0); + return result; +} + +FORCEINLINE fltx4 SetWSIMD( const fltx4& a, const fltx4& w ) +{ + fltx4 result = __vrlimi(a, w, 1, 0); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD( const fltx4& a, int nComponent, float flValue ) +{ + static int s_nVrlimiMask[4] = { 8, 4, 2, 1 }; + fltx4 val = ReplicateX4( flValue ); + fltx4 result = __vrlimi(a, val, s_nVrlimiMask[nComponent], 0); + return result; +} + +FORCEINLINE fltx4 RotateLeft( const fltx4 & a ) +{ + fltx4 compareOne = a; + return __vrlimi( compareOne, a, 8 | 4 | 2 | 1, 1 ); +} + +FORCEINLINE fltx4 RotateLeft2( const fltx4 & a ) +{ + fltx4 compareOne = a; + return __vrlimi( compareOne, a, 8 | 4 | 2 | 1, 2 ); +} + + + +// find the lowest component of a.x, a.y, a.z, +// and replicate it to the whole return value. +// ignores a.w. +// Though this is only five instructions long, +// they are all dependent, making this stall city. +// Forcing this inline should hopefully help with scheduling. +FORCEINLINE fltx4 FindLowestSIMD3( const fltx4 & a ) +{ + // a is [x,y,z,G] (where G is garbage) + // rotate left by one + fltx4 compareOne = a ; + compareOne = __vrlimi( compareOne, a, 8 | 4 , 1 ); + // compareOne is [y,z,G,G] + fltx4 retval = MinSIMD( a, compareOne ); + // retVal is [min(x,y), min(y,z), G, G] + compareOne = __vrlimi( compareOne, a, 8 , 2); + // compareOne is [z, G, G, G] + retval = MinSIMD( retval, compareOne ); + // retVal = [ min(min(x,y),z), G, G, G ] + + // splat the x component out to the whole vector and return + return SplatXSIMD( retval ); +} + +// find the highest component of a.x, a.y, a.z, +// and replicate it to the whole return value. +// ignores a.w. +// Though this is only five instructions long, +// they are all dependent, making this stall city. +// Forcing this inline should hopefully help with scheduling. +FORCEINLINE fltx4 FindHighestSIMD3( const fltx4 & a ) +{ + // a is [x,y,z,G] (where G is garbage) + // rotate left by one + fltx4 compareOne = a ; + compareOne = __vrlimi( compareOne, a, 8 | 4 , 1 ); + // compareOne is [y,z,G,G] + fltx4 retval = MaxSIMD( a, compareOne ); + // retVal is [max(x,y), max(y,z), G, G] + compareOne = __vrlimi( compareOne, a, 8 , 2); + // compareOne is [z, G, G, G] + retval = MaxSIMD( retval, compareOne ); + // retVal = [ max(max(x,y),z), G, G, G ] + + // splat the x component out to the whole vector and return + return SplatXSIMD( retval ); +} + + +// Transform many (horizontal) points in-place by a 3x4 matrix, +// here already loaded onto three fltx4 registers. +// The points must be stored as 16-byte aligned. They are points +// and not vectors because we assume the w-component to be 1. +// To spare yourself the annoyance of loading the matrix yourself, +// use one of the overloads below. +void TransformManyPointsBy(VectorAligned * RESTRICT pVectors, unsigned int numVectors, FLTX4 mRow1, FLTX4 mRow2, FLTX4 mRow3); + +// Transform many (horizontal) points in-place by a 3x4 matrix. +// The points must be stored as 16-byte aligned. They are points +// and not vectors because we assume the w-component to be 1. +// In this function, the matrix need not be aligned. +FORCEINLINE void TransformManyPointsBy(VectorAligned * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t &pMatrix) +{ + return TransformManyPointsBy(pVectors, numVectors, + LoadUnalignedSIMD( pMatrix[0] ), LoadUnalignedSIMD( pMatrix[1] ), LoadUnalignedSIMD( pMatrix[2] ) ); +} + +// Transform many (horizontal) points in-place by a 3x4 matrix. +// The points must be stored as 16-byte aligned. They are points +// and not vectors because we assume the w-component to be 1. +// In this function, the matrix must itself be aligned on a 16-byte +// boundary. +FORCEINLINE void TransformManyPointsByA(VectorAligned * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t &pMatrix) +{ + return TransformManyPointsBy(pVectors, numVectors, + LoadAlignedSIMD( pMatrix[0] ), LoadAlignedSIMD( pMatrix[1] ), LoadAlignedSIMD( pMatrix[2] ) ); +} + +// ------------------------------------ +// INTEGER SIMD OPERATIONS. +// ------------------------------------ + +// Load 4 aligned words into a SIMD register +FORCEINLINE i32x4 LoadAlignedIntSIMD( const void * RESTRICT pSIMD) +{ + return XMLoadVector4A(pSIMD); +} + +// Load 4 unaligned words into a SIMD register +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void * RESTRICT pSIMD) +{ + return XMLoadVector4( pSIMD ); +} + +// save into four words, 16-byte aligned +FORCEINLINE void StoreAlignedIntSIMD( int32 *pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< i32x4 *> ( pSIMD ) ) = a; +} + +FORCEINLINE void StoreAlignedIntSIMD( intx4 &pSIMD, const fltx4 & a ) +{ + *( reinterpret_cast< i32x4 *> ( pSIMD.Base() ) ) = a; +} + +FORCEINLINE void StoreUnalignedIntSIMD( int32 *pSIMD, const fltx4 & a ) +{ + XMStoreVector4(pSIMD, a); +} + + +// Take a fltx4 containing fixed-point uints and +// return them as single precision floats. No +// fixed point conversion is done. +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD( const i32x4 &vSrcA ) +{ + return __vcfux( vSrcA, 0 ); +} + + +// Take a fltx4 containing fixed-point sints and +// return them as single precision floats. No +// fixed point conversion is done. +FORCEINLINE fltx4 SignedIntConvertToFltSIMD( const i32x4 &vSrcA ) +{ + return __vcfsx( vSrcA, 0 ); +} + +// Take a fltx4 containing fixed-point uints and +// return them as single precision floats. Each uint +// will be divided by 2^immed after conversion +// (eg, this is fixed point math). +/* as if: + FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD( const i32x4 &vSrcA, unsigned int uImmed ) + { + return __vcfux( vSrcA, uImmed ); + } +*/ +#define UnsignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (__vcfux( (vSrcA), (uImmed) )) + +// Take a fltx4 containing fixed-point sints and +// return them as single precision floats. Each int +// will be divided by 2^immed (eg, this is fixed point +// math). +/* as if: + FORCEINLINE fltx4 SignedIntConvertToFltSIMD( const i32x4 &vSrcA, unsigned int uImmed ) + { + return __vcfsx( vSrcA, uImmed ); + } +*/ +#define SignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (__vcfsx( (vSrcA), (uImmed) )) + +// set all components of a vector to a signed immediate int number. +/* as if: + FORCEINLINE fltx4 IntSetImmediateSIMD(int toImmediate) + { + return __vspltisw( toImmediate ); + } +*/ +#define IntSetImmediateSIMD(x) (__vspltisw(x)) + +/* + works on fltx4's as if they are four uints. + the first parameter contains the words to be shifted, + the second contains the amount to shift by AS INTS + + for i = 0 to 3 + shift = vSrcB_i*32:(i*32)+4 + vReturned_i*32:(i*32)+31 = vSrcA_i*32:(i*32)+31 << shift +*/ +FORCEINLINE fltx4 IntShiftLeftWordSIMD(fltx4 vSrcA, fltx4 vSrcB) +{ + return __vslw(vSrcA, vSrcB); +} + +FORCEINLINE float SubFloat( const fltx4 & a, int idx ) +{ + // NOTE: if the output goes into a register, this causes a Load-Hit-Store stall (don't mix fpu/vpu math!) + const fltx4_union & a_union = (const fltx4_union &)a; + return a_union.m128_f32[ idx ]; +} + +FORCEINLINE float & SubFloat( fltx4 & a, int idx ) +{ + fltx4_union & a_union = (fltx4_union &)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE uint32 SubFloatConvertToInt( const fltx4 & a, int idx ) +{ + fltx4 t = __vctuxs( a, 0 ); + const fltx4_union & a_union = (const fltx4_union &)t; + return a_union.m128_u32[idx]; +} + + +FORCEINLINE uint32 SubInt( const fltx4 & a, int idx ) +{ + const fltx4_union & a_union = (const fltx4_union &)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE uint32 & SubInt( fltx4 & a, int idx ) +{ + fltx4_union & a_union = (fltx4_union &)a; + return a_union.m128_u32[idx]; +} + +#else + +//--------------------------------------------------------------------- +// Intel/SSE implementation +//--------------------------------------------------------------------- + +FORCEINLINE void StoreAlignedSIMD( float * RESTRICT pSIMD, const fltx4 & a ) +{ + _mm_store_ps( pSIMD, a ); +} + +FORCEINLINE void StoreUnalignedSIMD( float * RESTRICT pSIMD, const fltx4 & a ) +{ + _mm_storeu_ps( pSIMD, a ); +} + + +FORCEINLINE fltx4 RotateLeft( const fltx4 & a ); +FORCEINLINE fltx4 RotateLeft2( const fltx4 & a ); + +FORCEINLINE void StoreUnaligned3SIMD( float *pSIMD, const fltx4 & a ) +{ + _mm_store_ss(pSIMD, a); + _mm_store_ss(pSIMD+1, RotateLeft(a)); + _mm_store_ss(pSIMD+2, RotateLeft2(a)); +} + +// strongly typed -- syntactic castor oil used for typechecking as we transition to SIMD +FORCEINLINE void StoreAligned3SIMD( VectorAligned * RESTRICT pSIMD, const fltx4 & a ) +{ + StoreAlignedSIMD( pSIMD->Base(),a ); +} + +FORCEINLINE fltx4 LoadAlignedSIMD( const void *pSIMD ) +{ + return _mm_load_ps( reinterpret_cast< const float *> ( pSIMD ) ); +} + +FORCEINLINE fltx4 AndSIMD( const fltx4 & a, const fltx4 & b ) // a & b +{ + return _mm_and_ps( a, b ); +} + +FORCEINLINE fltx4 AndNotSIMD( const fltx4 & a, const fltx4 & b ) // ~a & b +{ + return _mm_andnot_ps( a, b ); +} + +FORCEINLINE fltx4 XorSIMD( const fltx4 & a, const fltx4 & b ) // a ^ b +{ + return _mm_xor_ps( a, b ); +} + +FORCEINLINE fltx4 OrSIMD( const fltx4 & a, const fltx4 & b ) // a | b +{ + return _mm_or_ps( a, b ); +} + +// Squelch the w component of a vector to +0.0. +// Most efficient when you say a = SetWToZeroSIMD(a) (avoids a copy) +FORCEINLINE fltx4 SetWToZeroSIMD( const fltx4 & a ) +{ + return AndSIMD( a, LoadAlignedSIMD( g_SIMD_clear_wmask ) ); +} + +// for the transitional class -- load a 3-by VectorAligned and squash its w component +FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned & pSIMD ) +{ + return SetWToZeroSIMD( LoadAlignedSIMD(pSIMD.Base()) ); +} + +FORCEINLINE fltx4 LoadUnalignedSIMD( const void *pSIMD ) +{ + return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD( const void *pSIMD ) +{ + return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); +} + +/// replicate a single 32 bit integer value to all 4 components of an m128 +FORCEINLINE fltx4 ReplicateIX4( int i ) +{ + fltx4 value = _mm_set_ss( * ( ( float *) &i ) );; + return _mm_shuffle_ps( value, value, 0); +} + + +FORCEINLINE fltx4 ReplicateX4( float flValue ) +{ + __m128 value = _mm_set_ss( flValue ); + return _mm_shuffle_ps( value, value, 0 ); +} + + +FORCEINLINE float SubFloat( const fltx4 & a, int idx ) +{ + // NOTE: if the output goes into a register, this causes a Load-Hit-Store stall (don't mix fpu/vpu math!) +#ifndef POSIX + return a.m128_f32[ idx ]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE float & SubFloat( fltx4 & a, int idx ) +{ +#ifndef POSIX + return a.m128_f32[ idx ]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE uint32 SubFloatConvertToInt( const fltx4 & a, int idx ) +{ + return (uint32)SubFloat(a,idx); +} + +FORCEINLINE uint32 SubInt( const fltx4 & a, int idx ) +{ +#ifndef POSIX + return a.m128_u32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE uint32 & SubInt( fltx4 & a, int idx ) +{ +#ifndef POSIX + return a.m128_u32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +// Return one in the fastest way -- on the x360, faster even than loading. +FORCEINLINE fltx4 LoadZeroSIMD( void ) +{ + return Four_Zeros; +} + +// Return one in the fastest way -- on the x360, faster even than loading. +FORCEINLINE fltx4 LoadOneSIMD( void ) +{ + return Four_Ones; +} + +FORCEINLINE fltx4 MaskedAssign( const fltx4 & ReplacementMask, const fltx4 & NewValue, const fltx4 & OldValue ) +{ + return OrSIMD( + AndSIMD( ReplacementMask, NewValue ), + AndNotSIMD( ReplacementMask, OldValue ) ); +} + +// remember, the SSE numbers its words 3 2 1 0 +// The way we want to specify shuffles is backwards from the default +// MM_SHUFFLE_REV is in array index order (default is reversed) +#define MM_SHUFFLE_REV(a,b,c,d) _MM_SHUFFLE(d,c,b,a) + +FORCEINLINE fltx4 SplatXSIMD( fltx4 const & a ) +{ + return _mm_shuffle_ps( a, a, MM_SHUFFLE_REV( 0, 0, 0, 0 ) ); +} + +FORCEINLINE fltx4 SplatYSIMD( fltx4 const &a ) +{ + return _mm_shuffle_ps( a, a, MM_SHUFFLE_REV( 1, 1, 1, 1 ) ); +} + +FORCEINLINE fltx4 SplatZSIMD( fltx4 const &a ) +{ + return _mm_shuffle_ps( a, a, MM_SHUFFLE_REV( 2, 2, 2, 2 ) ); +} + +FORCEINLINE fltx4 SplatWSIMD( fltx4 const &a ) +{ + return _mm_shuffle_ps( a, a, _MM_SHUFFLE( 3, 3, 3, 3 ) ); +} + +FORCEINLINE fltx4 SetXSIMD( const fltx4& a, const fltx4& x ) +{ + fltx4 result = MaskedAssign( LoadAlignedSIMD( g_SIMD_ComponentMask[0] ), x, a ); + return result; +} + +FORCEINLINE fltx4 SetYSIMD( const fltx4& a, const fltx4& y ) +{ + fltx4 result = MaskedAssign( LoadAlignedSIMD( g_SIMD_ComponentMask[1] ), y, a ); + return result; +} + +FORCEINLINE fltx4 SetZSIMD( const fltx4& a, const fltx4& z ) +{ + fltx4 result = MaskedAssign( LoadAlignedSIMD( g_SIMD_ComponentMask[2] ), z, a ); + return result; +} + +FORCEINLINE fltx4 SetWSIMD( const fltx4& a, const fltx4& w ) +{ + fltx4 result = MaskedAssign( LoadAlignedSIMD( g_SIMD_ComponentMask[3] ), w, a ); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD( const fltx4& a, int nComponent, float flValue ) +{ + fltx4 val = ReplicateX4( flValue ); + fltx4 result = MaskedAssign( LoadAlignedSIMD( g_SIMD_ComponentMask[nComponent] ), val, a ); + return result; +} + +// a b c d -> b c d a +FORCEINLINE fltx4 RotateLeft( const fltx4 & a ) +{ + return _mm_shuffle_ps( a, a, MM_SHUFFLE_REV( 1, 2, 3, 0 ) ); +} + +// a b c d -> c d a b +FORCEINLINE fltx4 RotateLeft2( const fltx4 & a ) +{ + return _mm_shuffle_ps( a, a, MM_SHUFFLE_REV( 2, 3, 0, 1 ) ); +} + +// a b c d -> d a b c +FORCEINLINE fltx4 RotateRight( const fltx4 & a ) +{ + return _mm_shuffle_ps( a, a, _MM_SHUFFLE( 0, 3, 2, 1) ); +} + +// a b c d -> c d a b +FORCEINLINE fltx4 RotateRight2( const fltx4 & a ) +{ + return _mm_shuffle_ps( a, a, _MM_SHUFFLE( 1, 0, 3, 2 ) ); +} + + +FORCEINLINE fltx4 AddSIMD( const fltx4 & a, const fltx4 & b ) // a+b +{ + return _mm_add_ps( a, b ); +}; + +FORCEINLINE fltx4 SubSIMD( const fltx4 & a, const fltx4 & b ) // a-b +{ + return _mm_sub_ps( a, b ); +}; + +FORCEINLINE fltx4 MulSIMD( const fltx4 & a, const fltx4 & b ) // a*b +{ + return _mm_mul_ps( a, b ); +}; + +FORCEINLINE fltx4 DivSIMD( const fltx4 & a, const fltx4 & b ) // a/b +{ + return _mm_div_ps( a, b ); +}; + +FORCEINLINE fltx4 MaddSIMD( const fltx4 & a, const fltx4 & b, const fltx4 & c ) // a*b + c +{ + return AddSIMD( MulSIMD(a,b), c ); +} + +FORCEINLINE fltx4 MsubSIMD( const fltx4 & a, const fltx4 & b, const fltx4 & c ) // c - a*b +{ + return SubSIMD( c, MulSIMD(a,b) ); +}; + +FORCEINLINE fltx4 Dot3SIMD( const fltx4 &a, const fltx4 &b ) +{ + fltx4 m = MulSIMD( a, b ); + float flDot = SubFloat( m, 0 ) + SubFloat( m, 1 ) + SubFloat( m, 2 ); + return ReplicateX4( flDot ); +} + +FORCEINLINE fltx4 Dot4SIMD( const fltx4 &a, const fltx4 &b ) +{ + fltx4 m = MulSIMD( a, b ); + float flDot = SubFloat( m, 0 ) + SubFloat( m, 1 ) + SubFloat( m, 2 ) + SubFloat( m, 3 ); + return ReplicateX4( flDot ); +} + +//TODO: implement as four-way Taylor series (see xbox implementation) +FORCEINLINE fltx4 SinSIMD( const fltx4 &radians ) +{ + fltx4 result; + SubFloat( result, 0 ) = sin( SubFloat( radians, 0 ) ); + SubFloat( result, 1 ) = sin( SubFloat( radians, 1 ) ); + SubFloat( result, 2 ) = sin( SubFloat( radians, 2 ) ); + SubFloat( result, 3 ) = sin( SubFloat( radians, 3 ) ); + return result; +} + +FORCEINLINE void SinCos3SIMD( fltx4 &sine, fltx4 &cosine, const fltx4 &radians ) +{ + // FIXME: Make a fast SSE version + SinCos( SubFloat( radians, 0 ), &SubFloat( sine, 0 ), &SubFloat( cosine, 0 ) ); + SinCos( SubFloat( radians, 1 ), &SubFloat( sine, 1 ), &SubFloat( cosine, 1 ) ); + SinCos( SubFloat( radians, 2 ), &SubFloat( sine, 2 ), &SubFloat( cosine, 2 ) ); +} + +FORCEINLINE void SinCosSIMD( fltx4 &sine, fltx4 &cosine, const fltx4 &radians ) // a*b + c +{ + // FIXME: Make a fast SSE version + SinCos( SubFloat( radians, 0 ), &SubFloat( sine, 0 ), &SubFloat( cosine, 0 ) ); + SinCos( SubFloat( radians, 1 ), &SubFloat( sine, 1 ), &SubFloat( cosine, 1 ) ); + SinCos( SubFloat( radians, 2 ), &SubFloat( sine, 2 ), &SubFloat( cosine, 2 ) ); + SinCos( SubFloat( radians, 3 ), &SubFloat( sine, 3 ), &SubFloat( cosine, 3 ) ); +} + +//TODO: implement as four-way Taylor series (see xbox implementation) +FORCEINLINE fltx4 ArcSinSIMD( const fltx4 &sine ) +{ + // FIXME: Make a fast SSE version + fltx4 result; + SubFloat( result, 0 ) = asin( SubFloat( sine, 0 ) ); + SubFloat( result, 1 ) = asin( SubFloat( sine, 1 ) ); + SubFloat( result, 2 ) = asin( SubFloat( sine, 2 ) ); + SubFloat( result, 3 ) = asin( SubFloat( sine, 3 ) ); + return result; +} + +FORCEINLINE fltx4 ArcCosSIMD( const fltx4 &cs ) +{ + fltx4 result; + SubFloat( result, 0 ) = acos( SubFloat( cs, 0 ) ); + SubFloat( result, 1 ) = acos( SubFloat( cs, 1 ) ); + SubFloat( result, 2 ) = acos( SubFloat( cs, 2 ) ); + SubFloat( result, 3 ) = acos( SubFloat( cs, 3 ) ); + return result; +} + +// tan^1(a/b) .. ie, pass sin in as a and cos in as b +FORCEINLINE fltx4 ArcTan2SIMD( const fltx4 &a, const fltx4 &b ) +{ + fltx4 result; + SubFloat( result, 0 ) = atan2( SubFloat( a, 0 ), SubFloat( b, 0 ) ); + SubFloat( result, 1 ) = atan2( SubFloat( a, 1 ), SubFloat( b, 1 ) ); + SubFloat( result, 2 ) = atan2( SubFloat( a, 2 ), SubFloat( b, 2 ) ); + SubFloat( result, 3 ) = atan2( SubFloat( a, 3 ), SubFloat( b, 3 ) ); + return result; +} + +FORCEINLINE fltx4 NegSIMD(const fltx4 &a) // negate: -a +{ + return SubSIMD(LoadZeroSIMD(),a); +} + +FORCEINLINE int TestSignSIMD( const fltx4 & a ) // mask of which floats have the high bit set +{ + return _mm_movemask_ps( a ); +} + +FORCEINLINE bool IsAnyNegative( const fltx4 & a ) // (a.x < 0) || (a.y < 0) || (a.z < 0) || (a.w < 0) +{ + return (0 != TestSignSIMD( a )); +} + +FORCEINLINE fltx4 CmpEqSIMD( const fltx4 & a, const fltx4 & b ) // (a==b) ? ~0:0 +{ + return _mm_cmpeq_ps( a, b ); +} + +FORCEINLINE fltx4 CmpGtSIMD( const fltx4 & a, const fltx4 & b ) // (a>b) ? ~0:0 +{ + return _mm_cmpgt_ps( a, b ); +} + +FORCEINLINE fltx4 CmpGeSIMD( const fltx4 & a, const fltx4 & b ) // (a>=b) ? ~0:0 +{ + return _mm_cmpge_ps( a, b ); +} + +FORCEINLINE fltx4 CmpLtSIMD( const fltx4 & a, const fltx4 & b ) // (a b.xyzw +FORCEINLINE bool IsAllGreaterThan( const fltx4 &a, const fltx4 &b ) +{ + return TestSignSIMD( CmpLeSIMD( a, b ) ) == 0; +} + +// for branching when a.xyzw >= b.xyzw +FORCEINLINE bool IsAllGreaterThanOrEq( const fltx4 &a, const fltx4 &b ) +{ + return TestSignSIMD( CmpLtSIMD( a, b ) ) == 0; +} + +// For branching if all a.xyzw == b.xyzw +FORCEINLINE bool IsAllEqual( const fltx4 & a, const fltx4 & b ) +{ + return TestSignSIMD( CmpEqSIMD( a, b ) ) == 0xf; +} + +FORCEINLINE fltx4 CmpInBoundsSIMD( const fltx4 & a, const fltx4 & b ) // (a <= b && a >= -b) ? ~0 : 0 +{ + return AndSIMD( CmpLeSIMD(a,b), CmpGeSIMD(a, NegSIMD(b)) ); +} + +FORCEINLINE fltx4 MinSIMD( const fltx4 & a, const fltx4 & b ) // min(a,b) +{ + return _mm_min_ps( a, b ); +} + +FORCEINLINE fltx4 MaxSIMD( const fltx4 & a, const fltx4 & b ) // max(a,b) +{ + return _mm_max_ps( a, b ); +} + + + +// SSE lacks rounding operations. +// Really. +// You can emulate them by setting the rounding mode for the +// whole processor and then converting to int, and then back again. +// But every time you set the rounding mode, you clear out the +// entire pipeline. So, I can't do them per operation. You +// have to do it once, before the loop that would call these. +// Round towards positive infinity +FORCEINLINE fltx4 CeilSIMD( const fltx4 &a ) +{ + fltx4 retVal; + SubFloat( retVal, 0 ) = ceil( SubFloat( a, 0 ) ); + SubFloat( retVal, 1 ) = ceil( SubFloat( a, 1 ) ); + SubFloat( retVal, 2 ) = ceil( SubFloat( a, 2 ) ); + SubFloat( retVal, 3 ) = ceil( SubFloat( a, 3 ) ); + return retVal; + +} + +fltx4 fabs( const fltx4 & x ); +// Round towards negative infinity +// This is the implementation that was here before; it assumes +// you are in round-to-floor mode, which I guess is usually the +// case for us vis-a-vis SSE. It's totally unnecessary on +// VMX, which has a native floor op. +FORCEINLINE fltx4 FloorSIMD( const fltx4 &val ) +{ + fltx4 fl4Abs = fabs( val ); + fltx4 ival = SubSIMD( AddSIMD( fl4Abs, Four_2ToThe23s ), Four_2ToThe23s ); + ival = MaskedAssign( CmpGtSIMD( ival, fl4Abs ), SubSIMD( ival, Four_Ones ), ival ); + return XorSIMD( ival, XorSIMD( val, fl4Abs ) ); // restore sign bits +} + + + +inline bool IsAllZeros( const fltx4 & var ) +{ + return TestSignSIMD( CmpEqSIMD( var, Four_Zeros ) ) == 0xF; +} + +FORCEINLINE fltx4 SqrtEstSIMD( const fltx4 & a ) // sqrt(a), more or less +{ + return _mm_sqrt_ps( a ); +} + +FORCEINLINE fltx4 SqrtSIMD( const fltx4 & a ) // sqrt(a) +{ + return _mm_sqrt_ps( a ); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD( const fltx4 & a ) // 1/sqrt(a), more or less +{ + return _mm_rsqrt_ps( a ); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD( const fltx4 & a ) +{ + fltx4 zero_mask = CmpEqSIMD( a, Four_Zeros ); + fltx4 ret = OrSIMD( a, AndSIMD( Four_Epsilons, zero_mask ) ); + ret = ReciprocalSqrtEstSIMD( ret ); + return ret; +} + +/// uses newton iteration for higher precision results than ReciprocalSqrtEstSIMD +FORCEINLINE fltx4 ReciprocalSqrtSIMD( const fltx4 & a ) // 1/sqrt(a) +{ + fltx4 guess = ReciprocalSqrtEstSIMD( a ); + // newton iteration for 1/sqrt(a) : y(n+1) = 1/2 (y(n)*(3-a*y(n)^2)); + guess = MulSIMD( guess, SubSIMD( Four_Threes, MulSIMD( a, MulSIMD( guess, guess )))); + guess = MulSIMD( Four_PointFives, guess); + return guess; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD( const fltx4 & a ) // 1/a, more or less +{ + return _mm_rcp_ps( a ); +} + +/// 1/x for all 4 values, more or less +/// 1/0 will result in a big but NOT infinite result +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD( const fltx4 & a ) +{ + fltx4 zero_mask = CmpEqSIMD( a, Four_Zeros ); + fltx4 ret = OrSIMD( a, AndSIMD( Four_Epsilons, zero_mask ) ); + ret = ReciprocalEstSIMD( ret ); + return ret; +} + +/// 1/x for all 4 values. uses reciprocal approximation instruction plus newton iteration. +/// No error checking! +FORCEINLINE fltx4 ReciprocalSIMD( const fltx4 & a ) // 1/a +{ + fltx4 ret = ReciprocalEstSIMD( a ); + // newton iteration is: Y(n+1) = 2*Y(n)-a*Y(n)^2 + ret = SubSIMD( AddSIMD( ret, ret ), MulSIMD( a, MulSIMD( ret, ret ) ) ); + return ret; +} + +/// 1/x for all 4 values. +/// 1/0 will result in a big but NOT infinite result +FORCEINLINE fltx4 ReciprocalSaturateSIMD( const fltx4 & a ) +{ + fltx4 zero_mask = CmpEqSIMD( a, Four_Zeros ); + fltx4 ret = OrSIMD( a, AndSIMD( Four_Epsilons, zero_mask ) ); + ret = ReciprocalSIMD( ret ); + return ret; +} + +// CHRISG: is it worth doing integer bitfiddling for this? +// 2^x for all values (the antilog) +FORCEINLINE fltx4 ExpSIMD( const fltx4 &toPower ) +{ + fltx4 retval; + SubFloat( retval, 0 ) = powf( 2, SubFloat(toPower, 0) ); + SubFloat( retval, 1 ) = powf( 2, SubFloat(toPower, 1) ); + SubFloat( retval, 2 ) = powf( 2, SubFloat(toPower, 2) ); + SubFloat( retval, 3 ) = powf( 2, SubFloat(toPower, 3) ); + + return retval; +} + +// Clamps the components of a vector to a specified minimum and maximum range. +FORCEINLINE fltx4 ClampVectorSIMD( FLTX4 in, FLTX4 min, FLTX4 max) +{ + return MaxSIMD( min, MinSIMD( max, in ) ); +} + +FORCEINLINE void TransposeSIMD( fltx4 & x, fltx4 & y, fltx4 & z, fltx4 & w) +{ + _MM_TRANSPOSE4_PS( x, y, z, w ); +} + +FORCEINLINE fltx4 FindLowestSIMD3( const fltx4 &a ) +{ + // a is [x,y,z,G] (where G is garbage) + // rotate left by one + fltx4 compareOne = RotateLeft( a ); + // compareOne is [y,z,G,x] + fltx4 retval = MinSIMD( a, compareOne ); + // retVal is [min(x,y), ... ] + compareOne = RotateLeft2( a ); + // compareOne is [z, G, x, y] + retval = MinSIMD( retval, compareOne ); + // retVal = [ min(min(x,y),z)..] + // splat the x component out to the whole vector and return + return SplatXSIMD( retval ); + +} + +FORCEINLINE fltx4 FindHighestSIMD3( const fltx4 &a ) +{ + // a is [x,y,z,G] (where G is garbage) + // rotate left by one + fltx4 compareOne = RotateLeft( a ); + // compareOne is [y,z,G,x] + fltx4 retval = MaxSIMD( a, compareOne ); + // retVal is [max(x,y), ... ] + compareOne = RotateLeft2( a ); + // compareOne is [z, G, x, y] + retval = MaxSIMD( retval, compareOne ); + // retVal = [ max(max(x,y),z)..] + // splat the x component out to the whole vector and return + return SplatXSIMD( retval ); + +} + +// ------------------------------------ +// INTEGER SIMD OPERATIONS. +// ------------------------------------ + + +#if 0 /* pc does not have these ops */ +// splat all components of a vector to a signed immediate int number. +FORCEINLINE fltx4 IntSetImmediateSIMD(int to) +{ + //CHRISG: SSE2 has this, but not SSE1. What to do? + fltx4 retval; + SubInt( retval, 0 ) = to; + SubInt( retval, 1 ) = to; + SubInt( retval, 2 ) = to; + SubInt( retval, 3 ) = to; + return retval; +} +#endif + +// Load 4 aligned words into a SIMD register +FORCEINLINE i32x4 LoadAlignedIntSIMD( const void * RESTRICT pSIMD) +{ + return _mm_load_ps( reinterpret_cast(pSIMD) ); +} + +// Load 4 unaligned words into a SIMD register +FORCEINLINE i32x4 LoadUnalignedIntSIMD( const void * RESTRICT pSIMD) +{ + return _mm_loadu_ps( reinterpret_cast(pSIMD) ); +} + +// save into four words, 16-byte aligned +FORCEINLINE void StoreAlignedIntSIMD( int32 * RESTRICT pSIMD, const fltx4 & a ) +{ + _mm_store_ps( reinterpret_cast(pSIMD), a ); +} + +FORCEINLINE void StoreAlignedIntSIMD( intx4 &pSIMD, const fltx4 & a ) +{ + _mm_store_ps( reinterpret_cast(pSIMD.Base()), a ); +} + +FORCEINLINE void StoreUnalignedIntSIMD( int32 * RESTRICT pSIMD, const fltx4 & a ) +{ + _mm_storeu_ps( reinterpret_cast(pSIMD), a ); +} + + +// CHRISG: the conversion functions all seem to operate on m64's only... +// how do we make them work here? + +// Take a fltx4 containing fixed-point uints and +// return them as single precision floats. No +// fixed point conversion is done. +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD( const u32x4 &vSrcA ) +{ + fltx4 retval; + SubFloat( retval, 0 ) = ( (float) SubInt( retval, 0 ) ); + SubFloat( retval, 1 ) = ( (float) SubInt( retval, 1 ) ); + SubFloat( retval, 2 ) = ( (float) SubInt( retval, 2 ) ); + SubFloat( retval, 3 ) = ( (float) SubInt( retval, 3 ) ); + return retval; +} + + +// Take a fltx4 containing fixed-point sints and +// return them as single precision floats. No +// fixed point conversion is done. +FORCEINLINE fltx4 SignedIntConvertToFltSIMD( const i32x4 &vSrcA ) +{ + fltx4 retval; + SubFloat( retval, 0 ) = ( (float) (reinterpret_cast(&vSrcA)[0])); + SubFloat( retval, 1 ) = ( (float) (reinterpret_cast(&vSrcA)[1])); + SubFloat( retval, 2 ) = ( (float) (reinterpret_cast(&vSrcA)[2])); + SubFloat( retval, 3 ) = ( (float) (reinterpret_cast(&vSrcA)[3])); + return retval; +} + +/* + works on fltx4's as if they are four uints. + the first parameter contains the words to be shifted, + the second contains the amount to shift by AS INTS + + for i = 0 to 3 + shift = vSrcB_i*32:(i*32)+4 + vReturned_i*32:(i*32)+31 = vSrcA_i*32:(i*32)+31 << shift +*/ +FORCEINLINE i32x4 IntShiftLeftWordSIMD(const i32x4 &vSrcA, const i32x4 &vSrcB) +{ + i32x4 retval; + SubInt(retval, 0) = SubInt(vSrcA, 0) << SubInt(vSrcB, 0); + SubInt(retval, 1) = SubInt(vSrcA, 1) << SubInt(vSrcB, 1); + SubInt(retval, 2) = SubInt(vSrcA, 2) << SubInt(vSrcB, 2); + SubInt(retval, 3) = SubInt(vSrcA, 3) << SubInt(vSrcB, 3); + + + return retval; +} + + +// Fixed-point conversion and save as SIGNED INTS. +// pDest->x = Int (vSrc.x) +// note: some architectures have means of doing +// fixed point conversion when the fix depth is +// specified as an immediate.. but there is no way +// to guarantee an immediate as a parameter to function +// like this. +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4 * RESTRICT pDest, const fltx4 &vSrc) +{ + __m64 bottom = _mm_cvttps_pi32( vSrc ); + __m64 top = _mm_cvttps_pi32( _mm_movehl_ps(vSrc,vSrc) ); + + *reinterpret_cast<__m64 *>(&(*pDest)[0]) = bottom; + *reinterpret_cast<__m64 *>(&(*pDest)[2]) = top; + + _mm_empty(); +} + + + +#endif + + + +/// class FourVectors stores 4 independent vectors for use in SIMD processing. These vectors are +/// stored in the format x x x x y y y y z z z z so that they can be efficiently SIMD-accelerated. +class ALIGN16 FourVectors +{ +public: + fltx4 x, y, z; + + FORCEINLINE void DuplicateVector(Vector const &v) //< set all 4 vectors to the same vector value + { + x=ReplicateX4(v.x); + y=ReplicateX4(v.y); + z=ReplicateX4(v.z); + } + + FORCEINLINE fltx4 const & operator[](int idx) const + { + return *((&x)+idx); + } + + FORCEINLINE fltx4 & operator[](int idx) + { + return *((&x)+idx); + } + + FORCEINLINE void operator+=(FourVectors const &b) //< add 4 vectors to another 4 vectors + { + x=AddSIMD(x,b.x); + y=AddSIMD(y,b.y); + z=AddSIMD(z,b.z); + } + + FORCEINLINE void operator-=(FourVectors const &b) //< subtract 4 vectors from another 4 + { + x=SubSIMD(x,b.x); + y=SubSIMD(y,b.y); + z=SubSIMD(z,b.z); + } + + FORCEINLINE void operator*=(FourVectors const &b) //< scale all four vectors per component scale + { + x=MulSIMD(x,b.x); + y=MulSIMD(y,b.y); + z=MulSIMD(z,b.z); + } + + FORCEINLINE void operator*=(const fltx4 & scale) //< scale + { + x=MulSIMD(x,scale); + y=MulSIMD(y,scale); + z=MulSIMD(z,scale); + } + + FORCEINLINE void operator*=(float scale) //< uniformly scale all 4 vectors + { + fltx4 scalepacked = ReplicateX4(scale); + *this *= scalepacked; + } + + FORCEINLINE fltx4 operator*(FourVectors const &b) const //< 4 dot products + { + fltx4 dot=MulSIMD(x,b.x); + dot=MaddSIMD(y,b.y,dot); + dot=MaddSIMD(z,b.z,dot); + return dot; + } + + FORCEINLINE fltx4 operator*(Vector const &b) const //< dot product all 4 vectors with 1 vector + { + fltx4 dot=MulSIMD(x,ReplicateX4(b.x)); + dot=MaddSIMD(y,ReplicateX4(b.y), dot); + dot=MaddSIMD(z,ReplicateX4(b.z), dot); + return dot; + } + + FORCEINLINE void VProduct(FourVectors const &b) //< component by component mul + { + x=MulSIMD(x,b.x); + y=MulSIMD(y,b.y); + z=MulSIMD(z,b.z); + } + FORCEINLINE void MakeReciprocal(void) //< (x,y,z)=(1/x,1/y,1/z) + { + x=ReciprocalSIMD(x); + y=ReciprocalSIMD(y); + z=ReciprocalSIMD(z); + } + + FORCEINLINE void MakeReciprocalSaturate(void) //< (x,y,z)=(1/x,1/y,1/z), 1/0=1.0e23 + { + x=ReciprocalSaturateSIMD(x); + y=ReciprocalSaturateSIMD(y); + z=ReciprocalSaturateSIMD(z); + } + + // Assume the given matrix is a rotation, and rotate these vectors by it. + // If you have a long list of FourVectors structures that you all want + // to rotate by the same matrix, use FourVectors::RotateManyBy() instead. + inline void RotateBy(const matrix3x4_t& matrix); + + /// You can use this to rotate a long array of FourVectors all by the same + /// matrix. The first parameter is the head of the array. The second is the + /// number of vectors to rotate. The third is the matrix. + static void RotateManyBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix ); + + /// Assume the vectors are points, and transform them in place by the matrix. + inline void TransformBy(const matrix3x4_t& matrix); + + /// You can use this to Transform a long array of FourVectors all by the same + /// matrix. The first parameter is the head of the array. The second is the + /// number of vectors to rotate. The third is the matrix. The fourth is the + /// output buffer, which must not overlap the pVectors buffer. This is not + /// an in-place transformation. + static void TransformManyBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors * RESTRICT pOut ); + + /// You can use this to Transform a long array of FourVectors all by the same + /// matrix. The first parameter is the head of the array. The second is the + /// number of vectors to rotate. The third is the matrix. The fourth is the + /// output buffer, which must not overlap the pVectors buffer. + /// This is an in-place transformation. + static void TransformManyBy(FourVectors * RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix ); + + // X(),Y(),Z() - get at the desired component of the i'th (0..3) vector. + FORCEINLINE const float & X(int idx) const + { + // NOTE: if the output goes into a register, this causes a Load-Hit-Store stall (don't mix fpu/vpu math!) + return SubFloat( (fltx4 &)x, idx ); + } + + FORCEINLINE const float & Y(int idx) const + { + return SubFloat( (fltx4 &)y, idx ); + } + + FORCEINLINE const float & Z(int idx) const + { + return SubFloat( (fltx4 &)z, idx ); + } + + FORCEINLINE float & X(int idx) + { + return SubFloat( x, idx ); + } + + FORCEINLINE float & Y(int idx) + { + return SubFloat( y, idx ); + } + + FORCEINLINE float & Z(int idx) + { + return SubFloat( z, idx ); + } + + FORCEINLINE Vector Vec(int idx) const //< unpack one of the vectors + { + return Vector( X(idx), Y(idx), Z(idx) ); + } + + FourVectors(void) + { + } + + FourVectors( FourVectors const &src ) + { + x=src.x; + y=src.y; + z=src.z; + } + + FORCEINLINE void operator=( FourVectors const &src ) + { + x=src.x; + y=src.y; + z=src.z; + } + + /// LoadAndSwizzle - load 4 Vectors into a FourVectors, performing transpose op + FORCEINLINE void LoadAndSwizzle(Vector const &a, Vector const &b, Vector const &c, Vector const &d) + { + // TransposeSIMD has large sub-expressions that the compiler can't eliminate on x360 + // use an unfolded implementation here +#if _X360 + fltx4 tx = LoadUnalignedSIMD( &a.x ); + fltx4 ty = LoadUnalignedSIMD( &b.x ); + fltx4 tz = LoadUnalignedSIMD( &c.x ); + fltx4 tw = LoadUnalignedSIMD( &d.x ); + fltx4 r0 = __vmrghw(tx, tz); + fltx4 r1 = __vmrghw(ty, tw); + fltx4 r2 = __vmrglw(tx, tz); + fltx4 r3 = __vmrglw(ty, tw); + + x = __vmrghw(r0, r1); + y = __vmrglw(r0, r1); + z = __vmrghw(r2, r3); +#else + x = LoadUnalignedSIMD( &( a.x )); + y = LoadUnalignedSIMD( &( b.x )); + z = LoadUnalignedSIMD( &( c.x )); + fltx4 w = LoadUnalignedSIMD( &( d.x )); + // now, matrix is: + // x y z ? + // x y z ? + // x y z ? + // x y z ? + TransposeSIMD(x, y, z, w); +#endif + } + + /// LoadAndSwizzleAligned - load 4 Vectors into a FourVectors, performing transpose op. + /// all 4 vectors must be 128 bit boundary + FORCEINLINE void LoadAndSwizzleAligned(const float *RESTRICT a, const float *RESTRICT b, const float *RESTRICT c, const float *RESTRICT d) + { +#if _X360 + fltx4 tx = LoadAlignedSIMD(a); + fltx4 ty = LoadAlignedSIMD(b); + fltx4 tz = LoadAlignedSIMD(c); + fltx4 tw = LoadAlignedSIMD(d); + fltx4 r0 = __vmrghw(tx, tz); + fltx4 r1 = __vmrghw(ty, tw); + fltx4 r2 = __vmrglw(tx, tz); + fltx4 r3 = __vmrglw(ty, tw); + + x = __vmrghw(r0, r1); + y = __vmrglw(r0, r1); + z = __vmrghw(r2, r3); +#else + x = LoadAlignedSIMD( a ); + y = LoadAlignedSIMD( b ); + z = LoadAlignedSIMD( c ); + fltx4 w = LoadAlignedSIMD( d ); + // now, matrix is: + // x y z ? + // x y z ? + // x y z ? + // x y z ? + TransposeSIMD( x, y, z, w ); +#endif + } + + FORCEINLINE void LoadAndSwizzleAligned(Vector const &a, Vector const &b, Vector const &c, Vector const &d) + { + LoadAndSwizzleAligned( &a.x, &b.x, &c.x, &d.x ); + } + + /// return the squared length of all 4 vectors + FORCEINLINE fltx4 length2(void) const + { + return (*this)*(*this); + } + + /// return the approximate length of all 4 vectors. uses the sqrt approximation instruction + FORCEINLINE fltx4 length(void) const + { + return SqrtEstSIMD(length2()); + } + + /// normalize all 4 vectors in place. not mega-accurate (uses reciprocal approximation instruction) + FORCEINLINE void VectorNormalizeFast(void) + { + fltx4 mag_sq=(*this)*(*this); // length^2 + (*this) *= ReciprocalSqrtEstSIMD(mag_sq); // *(1.0/sqrt(length^2)) + } + + /// normalize all 4 vectors in place. + FORCEINLINE void VectorNormalize(void) + { + fltx4 mag_sq=(*this)*(*this); // length^2 + (*this) *= ReciprocalSqrtSIMD(mag_sq); // *(1.0/sqrt(length^2)) + } + + /// construct a FourVectors from 4 separate Vectors + FORCEINLINE FourVectors(Vector const &a, Vector const &b, Vector const &c, Vector const &d) + { + LoadAndSwizzle(a,b,c,d); + } + + /// construct a FourVectors from 4 separate Vectors + FORCEINLINE FourVectors(VectorAligned const &a, VectorAligned const &b, VectorAligned const &c, VectorAligned const &d) + { + LoadAndSwizzleAligned(a,b,c,d); + } + + FORCEINLINE fltx4 DistToSqr( FourVectors const &pnt ) + { + fltx4 fl4dX = SubSIMD( pnt.x, x ); + fltx4 fl4dY = SubSIMD( pnt.y, y ); + fltx4 fl4dZ = SubSIMD( pnt.z, z ); + return AddSIMD( MulSIMD( fl4dX, fl4dX), AddSIMD( MulSIMD( fl4dY, fl4dY ), MulSIMD( fl4dZ, fl4dZ ) ) ); + + } + + FORCEINLINE fltx4 TValueOfClosestPointOnLine( FourVectors const &p0, FourVectors const &p1 ) const + { + FourVectors lineDelta = p1; + lineDelta -= p0; + fltx4 OOlineDirDotlineDir = ReciprocalSIMD( p1 * p1 ); + FourVectors v4OurPnt = *this; + v4OurPnt -= p0; + return MulSIMD( OOlineDirDotlineDir, v4OurPnt * lineDelta ); + } + + FORCEINLINE fltx4 DistSqrToLineSegment( FourVectors const &p0, FourVectors const &p1 ) const + { + FourVectors lineDelta = p1; + FourVectors v4OurPnt = *this; + v4OurPnt -= p0; + lineDelta -= p0; + + fltx4 OOlineDirDotlineDir = ReciprocalSIMD( lineDelta * lineDelta ); + + fltx4 fl4T = MulSIMD( OOlineDirDotlineDir, v4OurPnt * lineDelta ); + + fl4T = MinSIMD( fl4T, Four_Ones ); + fl4T = MaxSIMD( fl4T, Four_Zeros ); + lineDelta *= fl4T; + return v4OurPnt.DistToSqr( lineDelta ); + } + +}; + +/// form 4 cross products +inline FourVectors operator ^(const FourVectors &a, const FourVectors &b) +{ + FourVectors ret; + ret.x=SubSIMD(MulSIMD(a.y,b.z),MulSIMD(a.z,b.y)); + ret.y=SubSIMD(MulSIMD(a.z,b.x),MulSIMD(a.x,b.z)); + ret.z=SubSIMD(MulSIMD(a.x,b.y),MulSIMD(a.y,b.x)); + return ret; +} + +/// component-by-componentwise MAX operator +inline FourVectors maximum(const FourVectors &a, const FourVectors &b) +{ + FourVectors ret; + ret.x=MaxSIMD(a.x,b.x); + ret.y=MaxSIMD(a.y,b.y); + ret.z=MaxSIMD(a.z,b.z); + return ret; +} + +/// component-by-componentwise MIN operator +inline FourVectors minimum(const FourVectors &a, const FourVectors &b) +{ + FourVectors ret; + ret.x=MinSIMD(a.x,b.x); + ret.y=MinSIMD(a.y,b.y); + ret.z=MinSIMD(a.z,b.z); + return ret; +} + +/// calculate reflection vector. incident and normal dir assumed normalized +FORCEINLINE FourVectors VectorReflect( const FourVectors &incident, const FourVectors &normal ) +{ + FourVectors ret = incident; + fltx4 iDotNx2 = incident * normal; + iDotNx2 = AddSIMD( iDotNx2, iDotNx2 ); + FourVectors nPart = normal; + nPart *= iDotNx2; + ret -= nPart; // i-2(n*i)n + return ret; +} + +/// calculate slide vector. removes all components of a vector which are perpendicular to a normal vector. +FORCEINLINE FourVectors VectorSlide( const FourVectors &incident, const FourVectors &normal ) +{ + FourVectors ret = incident; + fltx4 iDotN = incident * normal; + FourVectors nPart = normal; + nPart *= iDotN; + ret -= nPart; // i-(n*i)n + return ret; +} + + +// Assume the given matrix is a rotation, and rotate these vectors by it. +// If you have a long list of FourVectors structures that you all want +// to rotate by the same matrix, use FourVectors::RotateManyBy() instead. +void FourVectors::RotateBy(const matrix3x4_t& matrix) +{ + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the tranpose row of + // the matrix, but we don't really care about that. + fltx4 matCol0 = LoadUnalignedSIMD( matrix[0] ); + fltx4 matCol1 = LoadUnalignedSIMD( matrix[1] ); + fltx4 matCol2 = LoadUnalignedSIMD( matrix[2] ); + + matSplat00 = SplatXSIMD( matCol0 ); + matSplat01 = SplatYSIMD( matCol0 ); + matSplat02 = SplatZSIMD( matCol0 ); + + matSplat10 = SplatXSIMD( matCol1 ); + matSplat11 = SplatYSIMD( matCol1 ); + matSplat12 = SplatZSIMD( matCol1 ); + + matSplat20 = SplatXSIMD( matCol2 ); + matSplat21 = SplatYSIMD( matCol2 ); + matSplat22 = SplatZSIMD( matCol2 ); + } + + // Trust in the compiler to schedule these operations correctly: + fltx4 outX, outY, outZ; + outX = AddSIMD( AddSIMD( MulSIMD( x, matSplat00 ), MulSIMD( y, matSplat01 ) ), MulSIMD( z, matSplat02 ) ); + outY = AddSIMD( AddSIMD( MulSIMD( x, matSplat10 ), MulSIMD( y, matSplat11 ) ), MulSIMD( z, matSplat12 ) ); + outZ = AddSIMD( AddSIMD( MulSIMD( x, matSplat20 ), MulSIMD( y, matSplat21 ) ), MulSIMD( z, matSplat22 ) ); + + x = outX; + y = outY; + z = outZ; +} + +// Assume the given matrix is a rotation, and rotate these vectors by it. +// If you have a long list of FourVectors structures that you all want +// to rotate by the same matrix, use FourVectors::RotateManyBy() instead. +void FourVectors::TransformBy(const matrix3x4_t& matrix) +{ + // Splat out each of the entries in the matrix to a fltx4. Do this + // in the order that we will need them, to hide latency. I'm + // avoiding making an array of them, so that they'll remain in + // registers. + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + { + // Load the matrix into local vectors. Sadly, matrix3x4_ts are + // often unaligned. The w components will be the tranpose row of + // the matrix, but we don't really care about that. + fltx4 matCol0 = LoadUnalignedSIMD( matrix[0] ); + fltx4 matCol1 = LoadUnalignedSIMD( matrix[1] ); + fltx4 matCol2 = LoadUnalignedSIMD( matrix[2] ); + + matSplat00 = SplatXSIMD( matCol0 ); + matSplat01 = SplatYSIMD( matCol0 ); + matSplat02 = SplatZSIMD( matCol0 ); + + matSplat10 = SplatXSIMD( matCol1 ); + matSplat11 = SplatYSIMD( matCol1 ); + matSplat12 = SplatZSIMD( matCol1 ); + + matSplat20 = SplatXSIMD( matCol2 ); + matSplat21 = SplatYSIMD( matCol2 ); + matSplat22 = SplatZSIMD( matCol2 ); + } + + // Trust in the compiler to schedule these operations correctly: + fltx4 outX, outY, outZ; + + outX = MaddSIMD( z, matSplat02, AddSIMD( MulSIMD( x, matSplat00 ), MulSIMD( y, matSplat01 ) ) ); + outY = MaddSIMD( z, matSplat12, AddSIMD( MulSIMD( x, matSplat10 ), MulSIMD( y, matSplat11 ) ) ); + outZ = MaddSIMD( z, matSplat22, AddSIMD( MulSIMD( x, matSplat20 ), MulSIMD( y, matSplat21 ) ) ); + + x = AddSIMD( outX, ReplicateX4( matrix[0][3] )); + y = AddSIMD( outY, ReplicateX4( matrix[1][3] )); + z = AddSIMD( outZ, ReplicateX4( matrix[2][3] )); +} + + + +/// quick, low quality perlin-style noise() function suitable for real time use. +/// return value is -1..1. Only reliable around +/- 1 million or so. +fltx4 NoiseSIMD( const fltx4 & x, const fltx4 & y, const fltx4 & z ); +fltx4 NoiseSIMD( FourVectors const &v ); + +// vector valued noise direction +FourVectors DNoiseSIMD( FourVectors const &v ); + +// vector value "curl" noise function. see http://hyperphysics.phy-astr.gsu.edu/hbase/curl.html +FourVectors CurlNoiseSIMD( FourVectors const &v ); + + +/// calculate the absolute value of a packed single +inline fltx4 fabs( const fltx4 & x ) +{ + return AndSIMD( x, LoadAlignedSIMD( g_SIMD_clear_signmask ) ); +} + +/// negate all four components of a SIMD packed single +inline fltx4 fnegate( const fltx4 & x ) +{ + return XorSIMD( x, LoadAlignedSIMD( g_SIMD_signmask ) ); +} + + +fltx4 Pow_FixedPoint_Exponent_SIMD( const fltx4 & x, int exponent); + +// PowSIMD - raise a SIMD register to a power. This is analogous to the C pow() function, with some +// restictions: fractional exponents are only handled with 2 bits of precision. Basically, +// fractions of 0,.25,.5, and .75 are handled. PowSIMD(x,.30) will be the same as PowSIMD(x,.25). +// negative and fractional powers are handled by the SIMD reciprocal and square root approximation +// instructions and so are not especially accurate ----Note that this routine does not raise +// numeric exceptions because it uses SIMD--- This routine is O(log2(exponent)). +inline fltx4 PowSIMD( const fltx4 & x, float exponent ) +{ + return Pow_FixedPoint_Exponent_SIMD(x,(int) (4.0*exponent)); +} + + + +// random number generation - generate 4 random numbers quickly. + +void SeedRandSIMD(uint32 seed); // seed the random # generator +fltx4 RandSIMD( int nContext = 0 ); // return 4 numbers in the 0..1 range + +// for multithreaded, you need to use these and use the argument form of RandSIMD: +int GetSIMDRandContext( void ); +void ReleaseSIMDRandContext( int nContext ); + +FORCEINLINE fltx4 RandSignedSIMD( void ) // -1..1 +{ + return SubSIMD( MulSIMD( Four_Twos, RandSIMD() ), Four_Ones ); +} + + +// SIMD versions of mathlib simplespline functions +// hermite basis function for smooth interpolation +// Similar to Gain() above, but very cheap to call +// value should be between 0 & 1 inclusive +inline fltx4 SimpleSpline( const fltx4 & value ) +{ + // Arranged to avoid a data dependency between these two MULs: + fltx4 valueDoubled = MulSIMD( value, Four_Twos ); + fltx4 valueSquared = MulSIMD( value, value ); + + // Nice little ease-in, ease-out spline-like curve + return SubSIMD( + MulSIMD( Four_Threes, valueSquared ), + MulSIMD( valueDoubled, valueSquared ) ); +} + +// remaps a value in [startInterval, startInterval+rangeInterval] from linear to +// spline using SimpleSpline +inline fltx4 SimpleSplineRemapValWithDeltas( const fltx4 & val, + const fltx4 & A, const fltx4 & BMinusA, + const fltx4 & OneOverBMinusA, const fltx4 & C, + const fltx4 & DMinusC ) +{ +// if ( A == B ) +// return val >= B ? D : C; + fltx4 cVal = MulSIMD( SubSIMD( val, A), OneOverBMinusA ); + return AddSIMD( C, MulSIMD( DMinusC, SimpleSpline( cVal ) ) ); +} + +inline fltx4 SimpleSplineRemapValWithDeltasClamped( const fltx4 & val, + const fltx4 & A, const fltx4 & BMinusA, + const fltx4 & OneOverBMinusA, const fltx4 & C, + const fltx4 & DMinusC ) +{ +// if ( A == B ) +// return val >= B ? D : C; + fltx4 cVal = MulSIMD( SubSIMD( val, A), OneOverBMinusA ); + cVal = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, cVal ) ); + return AddSIMD( C, MulSIMD( DMinusC, SimpleSpline( cVal ) ) ); +} + +FORCEINLINE fltx4 FracSIMD( const fltx4 &val ) +{ + fltx4 fl4Abs = fabs( val ); + fltx4 ival = SubSIMD( AddSIMD( fl4Abs, Four_2ToThe23s ), Four_2ToThe23s ); + ival = MaskedAssign( CmpGtSIMD( ival, fl4Abs ), SubSIMD( ival, Four_Ones ), ival ); + return XorSIMD( SubSIMD( fl4Abs, ival ), XorSIMD( val, fl4Abs ) ); // restore sign bits +} + +FORCEINLINE fltx4 Mod2SIMD( const fltx4 &val ) +{ + fltx4 fl4Abs = fabs( val ); + fltx4 ival = SubSIMD( AndSIMD( LoadAlignedSIMD( (float *) g_SIMD_lsbmask ), AddSIMD( fl4Abs, Four_2ToThe23s ) ), Four_2ToThe23s ); + ival = MaskedAssign( CmpGtSIMD( ival, fl4Abs ), SubSIMD( ival, Four_Twos ), ival ); + return XorSIMD( SubSIMD( fl4Abs, ival ), XorSIMD( val, fl4Abs ) ); // restore sign bits +} + +FORCEINLINE fltx4 Mod2SIMDPositiveInput( const fltx4 &val ) +{ + fltx4 ival = SubSIMD( AndSIMD( LoadAlignedSIMD( g_SIMD_lsbmask ), AddSIMD( val, Four_2ToThe23s ) ), Four_2ToThe23s ); + ival = MaskedAssign( CmpGtSIMD( ival, val ), SubSIMD( ival, Four_Twos ), ival ); + return SubSIMD( val, ival ); +} + + +// approximate sin of an angle, with -1..1 representing the whole sin wave period instead of -pi..pi. +// no range reduction is done - for values outside of 0..1 you won't like the results +FORCEINLINE fltx4 _SinEst01SIMD( const fltx4 &val ) +{ + // really rough approximation - x*(4-x*4) - a parabola. s(0) = 0, s(.5) = 1, s(1)=0, smooth in-between. + // sufficient for simple oscillation. + return MulSIMD( val, SubSIMD( Four_Fours, MulSIMD( val, Four_Fours ) ) ); +} + +FORCEINLINE fltx4 _Sin01SIMD( const fltx4 &val ) +{ + // not a bad approximation : parabola always over-estimates. Squared parabola always + // underestimates. So lets blend between them: goodsin = badsin + .225*( badsin^2-badsin) + fltx4 fl4BadEst = MulSIMD( val, SubSIMD( Four_Fours, MulSIMD( val, Four_Fours ) ) ); + return AddSIMD( MulSIMD( Four_Point225s, SubSIMD( MulSIMD( fl4BadEst, fl4BadEst ), fl4BadEst ) ), fl4BadEst ); +} + +// full range useable implementations +FORCEINLINE fltx4 SinEst01SIMD( const fltx4 &val ) +{ + fltx4 fl4Abs = fabs( val ); + fltx4 fl4Reduced2 = Mod2SIMDPositiveInput( fl4Abs ); + fltx4 fl4OddMask = CmpGeSIMD( fl4Reduced2, Four_Ones ); + fltx4 fl4val = SubSIMD( fl4Reduced2, AndSIMD( Four_Ones, fl4OddMask ) ); + fltx4 fl4Sin = _SinEst01SIMD( fl4val ); + fl4Sin = XorSIMD( fl4Sin, AndSIMD( LoadAlignedSIMD( g_SIMD_signmask ), XorSIMD( val, fl4OddMask ) ) ); + return fl4Sin; + +} + +FORCEINLINE fltx4 Sin01SIMD( const fltx4 &val ) +{ + fltx4 fl4Abs = fabs( val ); + fltx4 fl4Reduced2 = Mod2SIMDPositiveInput( fl4Abs ); + fltx4 fl4OddMask = CmpGeSIMD( fl4Reduced2, Four_Ones ); + fltx4 fl4val = SubSIMD( fl4Reduced2, AndSIMD( Four_Ones, fl4OddMask ) ); + fltx4 fl4Sin = _Sin01SIMD( fl4val ); + fl4Sin = XorSIMD( fl4Sin, AndSIMD( LoadAlignedSIMD( g_SIMD_signmask ), XorSIMD( val, fl4OddMask ) ) ); + return fl4Sin; + +} + +// Schlick style Bias approximation see graphics gems 4 : bias(t,a)= t/( (1/a-2)*(1-t)+1) + +FORCEINLINE fltx4 PreCalcBiasParameter( const fltx4 &bias_parameter ) +{ + // convert perlin-style-bias parameter to the value right for the approximation + return SubSIMD( ReciprocalSIMD( bias_parameter ), Four_Twos ); +} + +FORCEINLINE fltx4 BiasSIMD( const fltx4 &val, const fltx4 &precalc_param ) +{ + // similar to bias function except pass precalced bias value from calling PreCalcBiasParameter. + + //!!speed!! use reciprocal est? + //!!speed!! could save one op by precalcing _2_ values + return DivSIMD( val, AddSIMD( MulSIMD( precalc_param, SubSIMD( Four_Ones, val ) ), Four_Ones ) ); +} + +//----------------------------------------------------------------------------- +// Box/plane test +// NOTE: The w component of emins + emaxs must be 1 for this to work +//----------------------------------------------------------------------------- +FORCEINLINE int BoxOnPlaneSideSIMD( const fltx4& emins, const fltx4& emaxs, const cplane_t *p, float tolerance = 0.f ) +{ + fltx4 corners[2]; + fltx4 normal = LoadUnalignedSIMD( p->normal.Base() ); + fltx4 dist = ReplicateX4( -p->dist ); + normal = SetWSIMD( normal, dist ); + fltx4 t4 = ReplicateX4( tolerance ); + fltx4 negt4 = ReplicateX4( -tolerance ); + fltx4 cmp = CmpGeSIMD( normal, Four_Zeros ); + corners[0] = MaskedAssign( cmp, emaxs, emins ); + corners[1] = MaskedAssign( cmp, emins, emaxs ); + fltx4 dot1 = Dot4SIMD( normal, corners[0] ); + fltx4 dot2 = Dot4SIMD( normal, corners[1] ); + cmp = CmpGeSIMD( dot1, t4 ); + fltx4 cmp2 = CmpGtSIMD( negt4, dot2 ); + fltx4 result = MaskedAssign( cmp, Four_Ones, Four_Zeros ); + fltx4 result2 = MaskedAssign( cmp2, Four_Twos, Four_Zeros ); + result = AddSIMD( result, result2 ); + intx4 sides; + ConvertStoreAsIntsSIMD( &sides, result ); + return sides[0]; +} + +#endif // _ssemath_h diff --git a/public/mathlib/ssequaternion.h b/public/mathlib/ssequaternion.h new file mode 100644 index 0000000..18750f8 --- /dev/null +++ b/public/mathlib/ssequaternion.h @@ -0,0 +1,367 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: - defines SIMD "structure of arrays" classes and functions. +// +//===========================================================================// +#ifndef SSEQUATMATH_H +#define SSEQUATMATH_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/ssemath.h" + +// Use this #define to allow SSE versions of Quaternion math +// to exist on PC. +// On PC, certain horizontal vector operations are not supported. +// This causes the SSE implementation of quaternion math to mix the +// vector and scalar floating point units, which is extremely +// performance negative if you don't compile to native SSE2 (which +// we don't as of Sept 1, 2007). So, it's best not to allow these +// functions to exist at all. It's not good enough to simply replace +// the contents of the functions with scalar math, because each call +// to LoadAligned and StoreAligned will result in an unnecssary copy +// of the quaternion, and several moves to and from the XMM registers. +// +// Basically, the problem you run into is that for efficient SIMD code, +// you need to load the quaternions and vectors into SIMD registers and +// keep them there as long as possible while doing only SIMD math, +// whereas for efficient scalar code, each time you copy onto or ever +// use a fltx4, it hoses your pipeline. So the difference has to be +// in the management of temporary variables in the calling function, +// not inside the math functions. +// +// If you compile assuming the presence of SSE2, the MSVC will abandon +// the traditional x87 FPU operations altogether and make everything use +// the SSE2 registers, which lessens this problem a little. + +// permitted only on 360, as we've done careful tuning on its Altivec math: +#ifdef _X360 +#define ALLOW_SIMD_QUATERNION_MATH 1 // not on PC! +#endif + + + +//--------------------------------------------------------------------- +// Load/store quaternions +//--------------------------------------------------------------------- +#ifndef _X360 +#if ALLOW_SIMD_QUATERNION_MATH +// Using STDC or SSE +FORCEINLINE fltx4 LoadAlignedSIMD( const QuaternionAligned & pSIMD ) +{ + fltx4 retval = LoadAlignedSIMD( pSIMD.Base() ); + return retval; +} + +FORCEINLINE fltx4 LoadAlignedSIMD( const QuaternionAligned * RESTRICT pSIMD ) +{ + fltx4 retval = LoadAlignedSIMD( pSIMD ); + return retval; +} + +FORCEINLINE void StoreAlignedSIMD( QuaternionAligned * RESTRICT pSIMD, const fltx4 & a ) +{ + StoreAlignedSIMD( pSIMD->Base(), a ); +} +#endif +#else + +// for the transitional class -- load a QuaternionAligned +FORCEINLINE fltx4 LoadAlignedSIMD( const QuaternionAligned & pSIMD ) +{ + fltx4 retval = XMLoadVector4A( pSIMD.Base() ); + return retval; +} + +FORCEINLINE fltx4 LoadAlignedSIMD( const QuaternionAligned * RESTRICT pSIMD ) +{ + fltx4 retval = XMLoadVector4A( pSIMD ); + return retval; +} + +FORCEINLINE void StoreAlignedSIMD( QuaternionAligned * RESTRICT pSIMD, const fltx4 & a ) +{ + XMStoreVector4A( pSIMD->Base(), a ); +} + +#endif + + +#if ALLOW_SIMD_QUATERNION_MATH +//--------------------------------------------------------------------- +// Make sure quaternions are within 180 degrees of one another, if not, reverse q +//--------------------------------------------------------------------- +FORCEINLINE fltx4 QuaternionAlignSIMD( const fltx4 &p, const fltx4 &q ) +{ + // decide if one of the quaternions is backwards + fltx4 a = SubSIMD( p, q ); + fltx4 b = AddSIMD( p, q ); + a = Dot4SIMD( a, a ); + b = Dot4SIMD( b, b ); + fltx4 cmp = CmpGtSIMD( a, b ); + fltx4 result = MaskedAssign( cmp, NegSIMD(q), q ); + return result; +} + +//--------------------------------------------------------------------- +// Normalize Quaternion +//--------------------------------------------------------------------- +#if USE_STDC_FOR_SIMD + +FORCEINLINE fltx4 QuaternionNormalizeSIMD( const fltx4 &q ) +{ + fltx4 radius, result; + radius = Dot4SIMD( q, q ); + + if ( SubFloat( radius, 0 ) ) // > FLT_EPSILON && ((radius < 1.0f - 4*FLT_EPSILON) || (radius > 1.0f + 4*FLT_EPSILON)) + { + float iradius = 1.0f / sqrt( SubFloat( radius, 0 ) ); + result = ReplicateX4( iradius ); + result = MulSIMD( result, q ); + return result; + } + return q; +} + +#else + +// SSE + X360 implementation +FORCEINLINE fltx4 QuaternionNormalizeSIMD( const fltx4 &q ) +{ + fltx4 radius, result, mask; + radius = Dot4SIMD( q, q ); + mask = CmpEqSIMD( radius, Four_Zeros ); // all ones iff radius = 0 + result = ReciprocalSqrtSIMD( radius ); + result = MulSIMD( result, q ); + return MaskedAssign( mask, q, result ); // if radius was 0, just return q +} + +#endif + + +//--------------------------------------------------------------------- +// 0.0 returns p, 1.0 return q. +//--------------------------------------------------------------------- +FORCEINLINE fltx4 QuaternionBlendNoAlignSIMD( const fltx4 &p, const fltx4 &q, float t ) +{ + fltx4 sclp, sclq, result; + sclq = ReplicateX4( t ); + sclp = SubSIMD( Four_Ones, sclq ); + result = MulSIMD( sclp, p ); + result = MaddSIMD( sclq, q, result ); + return QuaternionNormalizeSIMD( result ); +} + + +//--------------------------------------------------------------------- +// Blend Quaternions +//--------------------------------------------------------------------- +FORCEINLINE fltx4 QuaternionBlendSIMD( const fltx4 &p, const fltx4 &q, float t ) +{ + // decide if one of the quaternions is backwards + fltx4 q2, result; + q2 = QuaternionAlignSIMD( p, q ); + result = QuaternionBlendNoAlignSIMD( p, q2, t ); + return result; +} + + +//--------------------------------------------------------------------- +// Multiply Quaternions +//--------------------------------------------------------------------- +#ifndef _X360 + +// SSE and STDC +FORCEINLINE fltx4 QuaternionMultSIMD( const fltx4 &p, const fltx4 &q ) +{ + // decide if one of the quaternions is backwards + fltx4 q2, result; + q2 = QuaternionAlignSIMD( p, q ); + SubFloat( result, 0 ) = SubFloat( p, 0 ) * SubFloat( q2, 3 ) + SubFloat( p, 1 ) * SubFloat( q2, 2 ) - SubFloat( p, 2 ) * SubFloat( q2, 1 ) + SubFloat( p, 3 ) * SubFloat( q2, 0 ); + SubFloat( result, 1 ) = -SubFloat( p, 0 ) * SubFloat( q2, 2 ) + SubFloat( p, 1 ) * SubFloat( q2, 3 ) + SubFloat( p, 2 ) * SubFloat( q2, 0 ) + SubFloat( p, 3 ) * SubFloat( q2, 1 ); + SubFloat( result, 2 ) = SubFloat( p, 0 ) * SubFloat( q2, 1 ) - SubFloat( p, 1 ) * SubFloat( q2, 0 ) + SubFloat( p, 2 ) * SubFloat( q2, 3 ) + SubFloat( p, 3 ) * SubFloat( q2, 2 ); + SubFloat( result, 3 ) = -SubFloat( p, 0 ) * SubFloat( q2, 0 ) - SubFloat( p, 1 ) * SubFloat( q2, 1 ) - SubFloat( p, 2 ) * SubFloat( q2, 2 ) + SubFloat( p, 3 ) * SubFloat( q2, 3 ); + return result; +} + +#else + +// X360 +extern const fltx4 g_QuatMultRowSign[4]; +FORCEINLINE fltx4 QuaternionMultSIMD( const fltx4 &p, const fltx4 &q ) +{ + fltx4 q2, row, result; + q2 = QuaternionAlignSIMD( p, q ); + + row = XMVectorSwizzle( q2, 3, 2, 1, 0 ); + row = MulSIMD( row, g_QuatMultRowSign[0] ); + result = Dot4SIMD( row, p ); + + row = XMVectorSwizzle( q2, 2, 3, 0, 1 ); + row = MulSIMD( row, g_QuatMultRowSign[1] ); + row = Dot4SIMD( row, p ); + result = __vrlimi( result, row, 4, 0 ); + + row = XMVectorSwizzle( q2, 1, 0, 3, 2 ); + row = MulSIMD( row, g_QuatMultRowSign[2] ); + row = Dot4SIMD( row, p ); + result = __vrlimi( result, row, 2, 0 ); + + row = MulSIMD( q2, g_QuatMultRowSign[3] ); + row = Dot4SIMD( row, p ); + result = __vrlimi( result, row, 1, 0 ); + return result; +} + +#endif + + +//--------------------------------------------------------------------- +// Quaternion scale +//--------------------------------------------------------------------- +#ifndef _X360 + +// SSE and STDC +FORCEINLINE fltx4 QuaternionScaleSIMD( const fltx4 &p, float t ) +{ + float r; + fltx4 q; + + // FIXME: nick, this isn't overly sensitive to accuracy, and it may be faster to + // use the cos part (w) of the quaternion (sin(omega)*N,cos(omega)) to figure the new scale. + float sinom = sqrt( SubFloat( p, 0 ) * SubFloat( p, 0 ) + SubFloat( p, 1 ) * SubFloat( p, 1 ) + SubFloat( p, 2 ) * SubFloat( p, 2 ) ); + sinom = vmin( sinom, 1.f ); + + float sinsom = sin( asin( sinom ) * t ); + + t = sinsom / (sinom + FLT_EPSILON); + SubFloat( q, 0 ) = t * SubFloat( p, 0 ); + SubFloat( q, 1 ) = t * SubFloat( p, 1 ); + SubFloat( q, 2 ) = t * SubFloat( p, 2 ); + + // rescale rotation + r = 1.0f - sinsom * sinsom; + + // Assert( r >= 0 ); + if (r < 0.0f) + r = 0.0f; + r = sqrt( r ); + + // keep sign of rotation + SubFloat( q, 3 ) = fsel( SubFloat( p, 3 ), r, -r ); + return q; +} + +#else + +// X360 +FORCEINLINE fltx4 QuaternionScaleSIMD( const fltx4 &p, float t ) +{ + fltx4 sinom = Dot3SIMD( p, p ); + sinom = SqrtSIMD( sinom ); + sinom = MinSIMD( sinom, Four_Ones ); + fltx4 sinsom = ArcSinSIMD( sinom ); + fltx4 t4 = ReplicateX4( t ); + sinsom = MulSIMD( sinsom, t4 ); + sinsom = SinSIMD( sinsom ); + sinom = AddSIMD( sinom, Four_Epsilons ); + sinom = ReciprocalSIMD( sinom ); + t4 = MulSIMD( sinsom, sinom ); + fltx4 result = MulSIMD( p, t4 ); + + // rescale rotation + sinsom = MulSIMD( sinsom, sinsom ); + fltx4 r = SubSIMD( Four_Ones, sinsom ); + r = MaxSIMD( r, Four_Zeros ); + r = SqrtSIMD( r ); + + // keep sign of rotation + fltx4 cmp = CmpGeSIMD( p, Four_Zeros ); + r = MaskedAssign( cmp, r, NegSIMD( r ) ); + + result = __vrlimi(result, r, 1, 0); + return result; +} + +#endif + + +//----------------------------------------------------------------------------- +// Quaternion sphereical linear interpolation +//----------------------------------------------------------------------------- +#ifndef _X360 + +// SSE and STDC +FORCEINLINE fltx4 QuaternionSlerpNoAlignSIMD( const fltx4 &p, const fltx4 &q, float t ) +{ + float omega, cosom, sinom, sclp, sclq; + + fltx4 result; + + // 0.0 returns p, 1.0 return q. + cosom = SubFloat( p, 0 ) * SubFloat( q, 0 ) + SubFloat( p, 1 ) * SubFloat( q, 1 ) + + SubFloat( p, 2 ) * SubFloat( q, 2 ) + SubFloat( p, 3 ) * SubFloat( q, 3 ); + + if ( (1.0f + cosom ) > 0.000001f ) + { + if ( (1.0f - cosom ) > 0.000001f ) + { + omega = acos( cosom ); + sinom = sin( omega ); + sclp = sin( (1.0f - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else + { + // TODO: add short circuit for cosom == 1.0f? + sclp = 1.0f - t; + sclq = t; + } + SubFloat( result, 0 ) = sclp * SubFloat( p, 0 ) + sclq * SubFloat( q, 0 ); + SubFloat( result, 1 ) = sclp * SubFloat( p, 1 ) + sclq * SubFloat( q, 1 ); + SubFloat( result, 2 ) = sclp * SubFloat( p, 2 ) + sclq * SubFloat( q, 2 ); + SubFloat( result, 3 ) = sclp * SubFloat( p, 3 ) + sclq * SubFloat( q, 3 ); + } + else + { + SubFloat( result, 0 ) = -SubFloat( q, 1 ); + SubFloat( result, 1 ) = SubFloat( q, 0 ); + SubFloat( result, 2 ) = -SubFloat( q, 3 ); + SubFloat( result, 3 ) = SubFloat( q, 2 ); + sclp = sin( (1.0f - t) * (0.5f * M_PI)); + sclq = sin( t * (0.5f * M_PI)); + SubFloat( result, 0 ) = sclp * SubFloat( p, 0 ) + sclq * SubFloat( result, 0 ); + SubFloat( result, 1 ) = sclp * SubFloat( p, 1 ) + sclq * SubFloat( result, 1 ); + SubFloat( result, 2 ) = sclp * SubFloat( p, 2 ) + sclq * SubFloat( result, 2 ); + } + + return result; +} + +#else + +// X360 +FORCEINLINE fltx4 QuaternionSlerpNoAlignSIMD( const fltx4 &p, const fltx4 &q, float t ) +{ + return XMQuaternionSlerp( p, q, t ); +} + +#endif + + +FORCEINLINE fltx4 QuaternionSlerpSIMD( const fltx4 &p, const fltx4 &q, float t ) +{ + fltx4 q2, result; + q2 = QuaternionAlignSIMD( p, q ); + result = QuaternionSlerpNoAlignSIMD( p, q2, t ); + return result; +} + + +#endif // ALLOW_SIMD_QUATERNION_MATH + +#endif // SSEQUATMATH_H + diff --git a/public/mathlib/vector.h b/public/mathlib/vector.h new file mode 100644 index 0000000..5922a2f --- /dev/null +++ b/public/mathlib/vector.h @@ -0,0 +1,2309 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VECTOR_H +#define VECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +// For vec_t, put this somewhere else? +#include "tier0/basetypes.h" + +// For rand(). We really need a library! +#include + +#ifndef _X360 +// For MMX intrinsics +#include +#endif + +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "mathlib/vector2d.h" +#include "mathlib/math_pfns.h" +#include "minmax.h" + +// Uncomment this to add extra Asserts to check for NANs, uninitialized vecs, etc. +//#define VECTOR_PARANOIA 1 + +// Uncomment this to make sure we don't do anything slow with our vectors +//#define VECTOR_NO_SLOW_OPERATIONS 1 + + +// Used to make certain code easier to read. +#define X_INDEX 0 +#define Y_INDEX 1 +#define Z_INDEX 2 + + +#ifdef VECTOR_PARANOIA +#define CHECK_VALID( _v) Assert( (_v).IsValid() ) +#else +#ifdef GNUC +#define CHECK_VALID( _v) +#else +#define CHECK_VALID( _v) 0 +#endif +#endif + +#define VecToString(v) (static_cast(CFmtStr("(%f, %f, %f)", (v).x, (v).y, (v).z))) // ** Note: this generates a temporary, don't hold reference! + +class VectorByValue; + +//========================================================= +// 3D Vector +//========================================================= +class Vector +{ +public: + // Members + vec_t x, y, z; + + // Construction/destruction: + Vector(void); + Vector(vec_t X, vec_t Y, vec_t Z); + explicit Vector(vec_t XYZ); ///< broadcast initialize + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f); + // TODO (Ilya): Should there be an init that takes a single float for consistency? + + // Got any nasty NAN's? + bool IsValid() const; + void Invalidate(); + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + vec_t* Base(); + vec_t const* Base() const; + + // Cast to Vector2D... + Vector2D& AsVector2D(); + const Vector2D& AsVector2D() const; + + // Initialization methods + void Random( vec_t minVal, vec_t maxVal ); + inline void Zero(); ///< zero out a vector + + // equality + bool operator==(const Vector& v) const; + bool operator!=(const Vector& v) const; + + // arithmetic operations + FORCEINLINE Vector& operator+=(const Vector &v); + FORCEINLINE Vector& operator-=(const Vector &v); + FORCEINLINE Vector& operator*=(const Vector &v); + FORCEINLINE Vector& operator*=(float s); + FORCEINLINE Vector& operator/=(const Vector &v); + FORCEINLINE Vector& operator/=(float s); + FORCEINLINE Vector& operator+=(float fl) ; ///< broadcast add + FORCEINLINE Vector& operator-=(float fl) ; ///< broadcast sub + +// negate the vector components + void Negate(); + + // Get the vector's magnitude. + inline vec_t Length() const; + + // Get the vector's magnitude squared. + FORCEINLINE vec_t LengthSqr(void) const + { + CHECK_VALID(*this); + return (x*x + y*y + z*z); + } + + // return true if this vector is (0,0,0) within tolerance + bool IsZero( float tolerance = 0.01f ) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance && + z > -tolerance && z < tolerance); + } + + vec_t NormalizeInPlace(); + Vector Normalized() const; + bool IsLengthGreaterThan( float val ) const; + bool IsLengthLessThan( float val ) const; + + // check if a vector is within the box defined by two other vectors + FORCEINLINE bool WithinAABox( Vector const &boxmin, Vector const &boxmax); + + // Get the distance from this vector to the other one. + vec_t DistTo(const Vector &vOther) const; + + // Get the distance from this vector to the other one squared. + // NJS: note, VC wasn't inlining it correctly in several deeply nested inlines due to being an 'out of line' inline. + // may be able to tidy this up after switching to VC7 + FORCEINLINE vec_t DistToSqr(const Vector &vOther) const + { + Vector delta; + + delta.x = x - vOther.x; + delta.y = y - vOther.y; + delta.z = z - vOther.z; + + return delta.LengthSqr(); + } + + // Copy + void CopyToArray(float* rgfl) const; + + // Multiply, add, and assign to this (ie: *this = a + b * scalar). This + // is about 12% faster than the actual vector equation (because it's done per-component + // rather than per-vector). + void MulAdd(const Vector& a, const Vector& b, float scalar); + + // Dot product. + vec_t Dot(const Vector& vOther) const; + + // assignment + Vector& operator=(const Vector &vOther); + + // 2d + vec_t Length2D(void) const; + vec_t Length2DSqr(void) const; + + operator VectorByValue &() { return *((VectorByValue *)(this)); } + operator const VectorByValue &() const { return *((const VectorByValue *)(this)); } + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // copy constructors +// Vector(const Vector &vOther); + + // arithmetic operations + Vector operator-(void) const; + + Vector operator+(const Vector& v) const; + Vector operator-(const Vector& v) const; + Vector operator*(const Vector& v) const; + Vector operator/(const Vector& v) const; + Vector operator*(float fl) const; + Vector operator/(float fl) const; + + // Cross product between two vectors. + Vector Cross(const Vector &vOther) const; + + // Returns a vector with the min or max in X, Y, and Z. + Vector Min(const Vector &vOther) const; + Vector Max(const Vector &vOther) const; + +#else + +private: + // No copy constructors allowed if we're in optimal mode + Vector(const Vector& vOther); +#endif +}; + +FORCEINLINE void NetworkVarConstruct( Vector &v ) { v.Zero(); } + + + +//========================================================= +// 4D Short Vector (aligned on 8-byte boundary) +//========================================================= +class ALIGN8 ShortVector +{ +public: + + short x, y, z, w; + + // Initialization + void Init(short ix = 0, short iy = 0, short iz = 0, short iw = 0 ); + + +#if !defined( _X360 ) + __m64 &AsM64() { return *(__m64*)&x; } + const __m64 &AsM64() const { return *(const __m64*)&x; } +#endif + + // Setter + void Set( const ShortVector& vOther ); + void Set( const short ix, const short iy, const short iz, const short iw ); + + // array access... + short operator[](int i) const; + short& operator[](int i); + + // Base address... + short* Base(); + short const* Base() const; + + // equality + bool operator==(const ShortVector& v) const; + bool operator!=(const ShortVector& v) const; + + // Arithmetic operations + FORCEINLINE ShortVector& operator+=(const ShortVector &v); + FORCEINLINE ShortVector& operator-=(const ShortVector &v); + FORCEINLINE ShortVector& operator*=(const ShortVector &v); + FORCEINLINE ShortVector& operator*=(float s); + FORCEINLINE ShortVector& operator/=(const ShortVector &v); + FORCEINLINE ShortVector& operator/=(float s); + FORCEINLINE ShortVector operator*(float fl) const; + +private: + + // No copy constructors allowed if we're in optimal mode +// ShortVector(ShortVector const& vOther); + + // No assignment operators either... +// ShortVector& operator=( ShortVector const& src ); + +} ALIGN8_POST; + + + + + + +//========================================================= +// 4D Integer Vector +//========================================================= +class IntVector4D +{ +public: + + int x, y, z, w; + + // Initialization + void Init(int ix = 0, int iy = 0, int iz = 0, int iw = 0 ); + +#if !defined( _X360 ) + __m64 &AsM64() { return *(__m64*)&x; } + const __m64 &AsM64() const { return *(const __m64*)&x; } +#endif + + // Setter + void Set( const IntVector4D& vOther ); + void Set( const int ix, const int iy, const int iz, const int iw ); + + // array access... + int operator[](int i) const; + int& operator[](int i); + + // Base address... + int* Base(); + int const* Base() const; + + // equality + bool operator==(const IntVector4D& v) const; + bool operator!=(const IntVector4D& v) const; + + // Arithmetic operations + FORCEINLINE IntVector4D& operator+=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator-=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator*=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator*=(float s); + FORCEINLINE IntVector4D& operator/=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator/=(float s); + FORCEINLINE IntVector4D operator*(float fl) const; + +private: + + // No copy constructors allowed if we're in optimal mode + // IntVector4D(IntVector4D const& vOther); + + // No assignment operators either... + // IntVector4D& operator=( IntVector4D const& src ); + +}; + + + +//----------------------------------------------------------------------------- +// Allows us to specifically pass the vector by value when we need to +//----------------------------------------------------------------------------- +class VectorByValue : public Vector +{ +public: + // Construction/destruction: + VectorByValue(void) : Vector() {} + VectorByValue(vec_t X, vec_t Y, vec_t Z) : Vector( X, Y, Z ) {} + VectorByValue(const VectorByValue& vOther) : Vector( vOther.x, vOther.y, vOther.z ) {} +}; + + +//----------------------------------------------------------------------------- +// Utility to simplify table construction. No constructor means can use +// traditional C-style initialization +//----------------------------------------------------------------------------- +class TableVector +{ +public: + vec_t x, y, z; + + operator Vector &() { return *((Vector *)(this)); } + operator const Vector &() const { return *((const Vector *)(this)); } + + // array access... + inline vec_t& operator[](int i) + { + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; + } + + inline vec_t operator[](int i) const + { + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; + } +}; + + +//----------------------------------------------------------------------------- +// Here's where we add all those lovely SSE optimized routines +//----------------------------------------------------------------------------- + +class ALIGN16 VectorAligned : public Vector +{ +public: + inline VectorAligned(void) {}; + inline VectorAligned(vec_t X, vec_t Y, vec_t Z) + { + Init(X,Y,Z); + } + +#ifdef VECTOR_NO_SLOW_OPERATIONS + +private: + // No copy constructors allowed if we're in optimal mode + VectorAligned(const VectorAligned& vOther); + VectorAligned(const Vector &vOther); + +#else +public: + explicit VectorAligned(const Vector &vOther) + { + Init(vOther.x, vOther.y, vOther.z); + } + + VectorAligned& operator=(const Vector &vOther) + { + Init(vOther.x, vOther.y, vOther.z); + return *this; + } + +#endif + float w; // this space is used anyway +} ALIGN16_POST; + +//----------------------------------------------------------------------------- +// Vector related operations +//----------------------------------------------------------------------------- + +// Vector clear +FORCEINLINE void VectorClear( Vector& a ); + +// Copy +FORCEINLINE void VectorCopy( const Vector& src, Vector& dst ); + +// Vector arithmetic +FORCEINLINE void VectorAdd( const Vector& a, const Vector& b, Vector& result ); +FORCEINLINE void VectorSubtract( const Vector& a, const Vector& b, Vector& result ); +FORCEINLINE void VectorMultiply( const Vector& a, vec_t b, Vector& result ); +FORCEINLINE void VectorMultiply( const Vector& a, const Vector& b, Vector& result ); +FORCEINLINE void VectorDivide( const Vector& a, vec_t b, Vector& result ); +FORCEINLINE void VectorDivide( const Vector& a, const Vector& b, Vector& result ); +inline void VectorScale ( const Vector& in, vec_t scale, Vector& result ); +// Don't mark this as inline in its function declaration. That's only necessary on its +// definition, and 'inline' here leads to gcc warnings. +void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest ); + +// Vector equality with tolerance +bool VectorsAreEqual( const Vector& src1, const Vector& src2, float tolerance = 0.0f ); + +#define VectorExpand(v) (v).x, (v).y, (v).z + + +// Normalization +// FIXME: Can't use quite yet +//vec_t VectorNormalize( Vector& v ); + +// Length +inline vec_t VectorLength( const Vector& v ); + +// Dot Product +FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b); + +// Cross product +void CrossProduct(const Vector& a, const Vector& b, Vector& result ); + +// Store the min or max of each of x, y, and z into the result. +void VectorMin( const Vector &a, const Vector &b, Vector &result ); +void VectorMax( const Vector &a, const Vector &b, Vector &result ); + +// Linearly interpolate between two vectors +void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest ); +Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t ); + +FORCEINLINE Vector ReplicateToVector( float x ) +{ + return Vector( x, x, x ); +} + +// check if a point is in the field of a view of an object. supports up to 180 degree fov. +FORCEINLINE bool PointWithinViewAngle( Vector const &vecSrcPosition, + Vector const &vecTargetPosition, + Vector const &vecLookDirection, float flCosHalfFOV ) +{ + Vector vecDelta = vecTargetPosition - vecSrcPosition; + float cosDiff = DotProduct( vecLookDirection, vecDelta ); + + if ( cosDiff < 0 ) + return false; + + float flLen2 = vecDelta.LengthSqr(); + + // a/sqrt(b) > c == a^2 > b * c ^2 + return ( cosDiff * cosDiff > flLen2 * flCosHalfFOV * flCosHalfFOV ); + +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +// Cross product +Vector CrossProduct( const Vector& a, const Vector& b ); + +// Random vector creation +Vector RandomVector( vec_t minVal, vec_t maxVal ); + +#endif + +float RandomVectorInUnitSphere( Vector *pVector ); +float RandomVectorInUnitCircle( Vector2D *pVector ); + + +//----------------------------------------------------------------------------- +// +// Inlined Vector methods +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +inline Vector::Vector(void) +{ +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + // Initialize to NAN to catch errors + x = y = z = VEC_T_NAN; +#endif +#endif +} + +inline Vector::Vector(vec_t X, vec_t Y, vec_t Z) +{ + x = X; y = Y; z = Z; + CHECK_VALID(*this); +} + +inline Vector::Vector(vec_t XYZ) +{ + x = y = z = XYZ; + CHECK_VALID(*this); +} + +//inline Vector::Vector(const float *pFloat) +//{ +// Assert( pFloat ); +// x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; +// CHECK_VALID(*this); +//} + +#if 0 +//----------------------------------------------------------------------------- +// copy constructor +//----------------------------------------------------------------------------- + +inline Vector::Vector(const Vector &vOther) +{ + CHECK_VALID(vOther); + x = vOther.x; y = vOther.y; z = vOther.z; +} +#endif + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- + +inline void Vector::Init( vec_t ix, vec_t iy, vec_t iz ) +{ + x = ix; y = iy; z = iz; + CHECK_VALID(*this); +} + +inline void Vector::Random( vec_t minVal, vec_t maxVal ) +{ + x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + z = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + CHECK_VALID(*this); +} + +// This should really be a single opcode on the PowerPC (move r0 onto the vec reg) +inline void Vector::Zero() +{ + x = y = z = 0.0f; +} + +inline void VectorClear( Vector& a ) +{ + a.x = a.y = a.z = 0.0f; +} + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- + +inline Vector& Vector::operator=(const Vector &vOther) +{ + CHECK_VALID(vOther); + x=vOther.x; y=vOther.y; z=vOther.z; + return *this; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& Vector::operator[](int i) +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector::operator[](int i) const +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline vec_t* Vector::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector::Base() const +{ + return (vec_t const*)this; +} + +//----------------------------------------------------------------------------- +// Cast to Vector2D... +//----------------------------------------------------------------------------- + +inline Vector2D& Vector::AsVector2D() +{ + return *(Vector2D*)this; +} + +inline const Vector2D& Vector::AsVector2D() const +{ + return *(const Vector2D*)this; +} + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- + +inline bool Vector::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +//----------------------------------------------------------------------------- +// Invalidate +//----------------------------------------------------------------------------- + +inline void Vector::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +//#endif +//#endif +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool Vector::operator==( const Vector& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +inline bool Vector::operator!=( const Vector& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- + +FORCEINLINE void VectorCopy( const Vector& src, Vector& dst ) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void Vector::CopyToArray(float* rgfl) const +{ + Assert( rgfl ); + CHECK_VALID(*this); + rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; +} + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- +// #pragma message("TODO: these should be SSE") + +inline void Vector::Negate() +{ + CHECK_VALID(*this); + x = -x; y = -y; z = -z; +} + +FORCEINLINE Vector& Vector::operator+=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x+=v.x; y+=v.y; z += v.z; + return *this; +} + +FORCEINLINE Vector& Vector::operator-=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x-=v.x; y-=v.y; z -= v.z; + return *this; +} + +FORCEINLINE Vector& Vector::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator*=(const Vector& v) +{ + CHECK_VALID(v); + x *= v.x; + y *= v.y; + z *= v.z; + CHECK_VALID(*this); + return *this; +} + +// this ought to be an opcode. +FORCEINLINE Vector& Vector::operator+=(float fl) +{ + x += fl; + y += fl; + z += fl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator-=(float fl) +{ + x -= fl; + y -= fl; + z -= fl; + CHECK_VALID(*this); + return *this; +} + + + +FORCEINLINE Vector& Vector::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator/=(const Vector& v) +{ + CHECK_VALID(v); + Assert( v.x != 0.0f && v.y != 0.0f && v.z != 0.0f ); + x /= v.x; + y /= v.y; + z /= v.z; + CHECK_VALID(*this); + return *this; +} + + + +//----------------------------------------------------------------------------- +// +// Inlined Short Vector methods +// +//----------------------------------------------------------------------------- + + +inline void ShortVector::Init( short ix, short iy, short iz, short iw ) +{ + x = ix; y = iy; z = iz; w = iw; +} + +FORCEINLINE void ShortVector::Set( const ShortVector& vOther ) +{ + x = vOther.x; + y = vOther.y; + z = vOther.z; + w = vOther.w; +} + +FORCEINLINE void ShortVector::Set( const short ix, const short iy, const short iz, const short iw ) +{ + x = ix; + y = iy; + z = iz; + w = iw; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline short ShortVector::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((short*)this)[i]; +} + +inline short& ShortVector::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((short*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline short* ShortVector::Base() +{ + return (short*)this; +} + +inline short const* ShortVector::Base() const +{ + return (short const*)this; +} + + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool ShortVector::operator==( const ShortVector& src ) const +{ + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool ShortVector::operator!=( const ShortVector& src ) const +{ + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +FORCEINLINE ShortVector& ShortVector::operator+=(const ShortVector& v) +{ + x+=v.x; y+=v.y; z += v.z; w += v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator-=(const ShortVector& v) +{ + x-=v.x; y-=v.y; z -= v.z; w -= v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator*=(float fl) +{ + x = (short)(x * fl); + y = (short)(y * fl); + z = (short)(z * fl); + w = (short)(w * fl); + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator*=(const ShortVector& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x = (short)(x * oofl); + y = (short)(y * oofl); + z = (short)(z * oofl); + w = (short)(w * oofl); + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator/=(const ShortVector& v) +{ + Assert( v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0 ); + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; + return *this; +} + +FORCEINLINE void ShortVectorMultiply( const ShortVector& src, float fl, ShortVector& res ) +{ + Assert( IsFinite(fl) ); + res.x = (short)(src.x * fl); + res.y = (short)(src.y * fl); + res.z = (short)(src.z * fl); + res.w = (short)(src.w * fl); +} + +FORCEINLINE ShortVector ShortVector::operator*(float fl) const +{ + ShortVector res; + ShortVectorMultiply( *this, fl, res ); + return res; +} + + + + + + +//----------------------------------------------------------------------------- +// +// Inlined Integer Vector methods +// +//----------------------------------------------------------------------------- + + +inline void IntVector4D::Init( int ix, int iy, int iz, int iw ) +{ + x = ix; y = iy; z = iz; w = iw; +} + +FORCEINLINE void IntVector4D::Set( const IntVector4D& vOther ) +{ + x = vOther.x; + y = vOther.y; + z = vOther.z; + w = vOther.w; +} + +FORCEINLINE void IntVector4D::Set( const int ix, const int iy, const int iz, const int iw ) +{ + x = ix; + y = iy; + z = iz; + w = iw; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline int IntVector4D::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((int*)this)[i]; +} + +inline int& IntVector4D::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((int*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline int* IntVector4D::Base() +{ + return (int*)this; +} + +inline int const* IntVector4D::Base() const +{ + return (int const*)this; +} + + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool IntVector4D::operator==( const IntVector4D& src ) const +{ + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool IntVector4D::operator!=( const IntVector4D& src ) const +{ + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +FORCEINLINE IntVector4D& IntVector4D::operator+=(const IntVector4D& v) +{ + x+=v.x; y+=v.y; z += v.z; w += v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator-=(const IntVector4D& v) +{ + x-=v.x; y-=v.y; z -= v.z; w -= v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator*=(float fl) +{ + x = (int)(x * fl); + y = (int)(y * fl); + z = (int)(z * fl); + w = (int)(w * fl); + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator*=(const IntVector4D& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x = (int)(x * oofl); + y = (int)(y * oofl); + z = (int)(z * oofl); + w = (int)(w * oofl); + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator/=(const IntVector4D& v) +{ + Assert( v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0 ); + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; + return *this; +} + +FORCEINLINE void IntVector4DMultiply( const IntVector4D& src, float fl, IntVector4D& res ) +{ + Assert( IsFinite(fl) ); + res.x = (int)(src.x * fl); + res.y = (int)(src.y * fl); + res.z = (int)(src.z * fl); + res.w = (int)(src.w * fl); +} + +FORCEINLINE IntVector4D IntVector4D::operator*(float fl) const +{ + IntVector4D res; + IntVector4DMultiply( *this, fl, res ); + return res; +} + + + +// ======================= + + +FORCEINLINE void VectorAdd( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x + b.x; + c.y = a.y + b.y; + c.z = a.z + b.z; +} + +FORCEINLINE void VectorSubtract( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x - b.x; + c.y = a.y - b.y; + c.z = a.z - b.z; +} + +FORCEINLINE void VectorMultiply( const Vector& a, vec_t b, Vector& c ) +{ + CHECK_VALID(a); + Assert( IsFinite(b) ); + c.x = a.x * b; + c.y = a.y * b; + c.z = a.z * b; +} + +FORCEINLINE void VectorMultiply( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; +} + +// for backwards compatability +inline void VectorScale ( const Vector& in, vec_t scale, Vector& result ) +{ + VectorMultiply( in, scale, result ); +} + + +FORCEINLINE void VectorDivide( const Vector& a, vec_t b, Vector& c ) +{ + CHECK_VALID(a); + Assert( b != 0.0f ); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; + c.z = a.z * oob; +} + +FORCEINLINE void VectorDivide( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + Assert( (b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f) ); + c.x = a.x / b.x; + c.y = a.y / b.y; + c.z = a.z / b.z; +} + +// FIXME: Remove +// For backwards compatability +inline void Vector::MulAdd(const Vector& a, const Vector& b, float scalar) +{ + CHECK_VALID(a); + CHECK_VALID(b); + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; + z = a.z + b.z * scalar; +} + +inline void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest ) +{ + CHECK_VALID(src1); + CHECK_VALID(src2); + dest.x = src1.x + (src2.x - src1.x) * t; + dest.y = src1.y + (src2.y - src1.y) * t; + dest.z = src1.z + (src2.z - src1.z) * t; +} + +inline Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t ) +{ + Vector result; + VectorLerp( src1, src2, t, result ); + return result; +} + +//----------------------------------------------------------------------------- +// Temporary storage for vector results so const Vector& results can be returned +//----------------------------------------------------------------------------- +inline Vector &AllocTempVector() +{ + static Vector s_vecTemp[128]; + static CInterlockedInt s_nIndex; + + int nIndex; + for (;;) + { + int nOldIndex = s_nIndex; + nIndex = ( (nOldIndex + 0x10001) & 0x7F ); + + if ( s_nIndex.AssignIf( nOldIndex, nIndex ) ) + { + break; + } + ThreadPause(); + } + return s_vecTemp[nIndex]; +} + + + +//----------------------------------------------------------------------------- +// dot, cross +//----------------------------------------------------------------------------- +FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b) +{ + CHECK_VALID(a); + CHECK_VALID(b); + return( a.x*b.x + a.y*b.y + a.z*b.z ); +} + +// for backwards compatability +inline vec_t Vector::Dot( const Vector& vOther ) const +{ + CHECK_VALID(vOther); + return DotProduct( *this, vOther ); +} + +inline void CrossProduct(const Vector& a, const Vector& b, Vector& result ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + Assert( &a != &result ); + Assert( &b != &result ); + result.x = a.y*b.z - a.z*b.y; + result.y = a.z*b.x - a.x*b.z; + result.z = a.x*b.y - a.y*b.x; +} + +inline vec_t DotProductAbs( const Vector &v0, const Vector &v1 ) +{ + CHECK_VALID(v0); + CHECK_VALID(v1); + return FloatMakePositive(v0.x*v1.x) + FloatMakePositive(v0.y*v1.y) + FloatMakePositive(v0.z*v1.z); +} + +inline vec_t DotProductAbs( const Vector &v0, const float *v1 ) +{ + return FloatMakePositive(v0.x * v1[0]) + FloatMakePositive(v0.y * v1[1]) + FloatMakePositive(v0.z * v1[2]); +} + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- + +inline vec_t VectorLength( const Vector& v ) +{ + CHECK_VALID(v); + return (vec_t)FastSqrt(v.x*v.x + v.y*v.y + v.z*v.z); +} + + +inline vec_t Vector::Length(void) const +{ + CHECK_VALID(*this); + return VectorLength( *this ); +} + + +//----------------------------------------------------------------------------- +// Normalization +//----------------------------------------------------------------------------- + +/* +// FIXME: Can't use until we're un-macroed in mathlib.h +inline vec_t VectorNormalize( Vector& v ) +{ + Assert( v.IsValid() ); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + // FIXME: + // Just copying the existing implemenation; shouldn't res.z == 0? + v.x = v.y = 0.0f; v.z = 1.0f; + } + return l; +} +*/ + + +// check a point against a box +bool Vector::WithinAABox( Vector const &boxmin, Vector const &boxmax) +{ + return ( + ( x >= boxmin.x ) && ( x <= boxmax.x) && + ( y >= boxmin.y ) && ( y <= boxmax.y) && + ( z >= boxmin.z ) && ( z <= boxmax.z) + ); +} + +//----------------------------------------------------------------------------- +// Get the distance from this vector to the other one +//----------------------------------------------------------------------------- +inline vec_t Vector::DistTo(const Vector &vOther) const +{ + Vector delta; + VectorSubtract( *this, vOther, delta ); + return delta.Length(); +} + + +//----------------------------------------------------------------------------- +// Vector equality with tolerance +//----------------------------------------------------------------------------- +inline bool VectorsAreEqual( const Vector& src1, const Vector& src2, float tolerance ) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + return (FloatMakePositive(src1.z - src2.z) <= tolerance); +} + + +//----------------------------------------------------------------------------- +// Computes the closest point to vecTarget no farther than flMaxDist from vecStart +//----------------------------------------------------------------------------- +inline void ComputeClosestPoint( const Vector& vecStart, float flMaxDist, const Vector& vecTarget, Vector *pResult ) +{ + Vector vecDelta; + VectorSubtract( vecTarget, vecStart, vecDelta ); + float flDistSqr = vecDelta.LengthSqr(); + if ( flDistSqr <= flMaxDist * flMaxDist ) + { + *pResult = vecTarget; + } + else + { + vecDelta /= FastSqrt( flDistSqr ); + VectorMA( vecStart, flMaxDist, vecDelta, *pResult ); + } +} + + +//----------------------------------------------------------------------------- +// Takes the absolute value of a vector +//----------------------------------------------------------------------------- +inline void VectorAbs( const Vector& src, Vector& dst ) +{ + dst.x = FloatMakePositive(src.x); + dst.y = FloatMakePositive(src.y); + dst.z = FloatMakePositive(src.z); +} + + +//----------------------------------------------------------------------------- +// +// Slow methods +// +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +//----------------------------------------------------------------------------- +// Returns a vector with the min or max in X, Y, and Z. +//----------------------------------------------------------------------------- +inline Vector Vector::Min(const Vector &vOther) const +{ + return Vector(x < vOther.x ? x : vOther.x, + y < vOther.y ? y : vOther.y, + z < vOther.z ? z : vOther.z); +} + +inline Vector Vector::Max(const Vector &vOther) const +{ + return Vector(x > vOther.x ? x : vOther.x, + y > vOther.y ? y : vOther.y, + z > vOther.z ? z : vOther.z); +} + + +//----------------------------------------------------------------------------- +// arithmetic operations +//----------------------------------------------------------------------------- + +inline Vector Vector::operator-(void) const +{ + return Vector(-x,-y,-z); +} + +inline Vector Vector::operator+(const Vector& v) const +{ + Vector res; + VectorAdd( *this, v, res ); + return res; +} + +inline Vector Vector::operator-(const Vector& v) const +{ + Vector res; + VectorSubtract( *this, v, res ); + return res; +} + +inline Vector Vector::operator*(float fl) const +{ + Vector res; + VectorMultiply( *this, fl, res ); + return res; +} + +inline Vector Vector::operator*(const Vector& v) const +{ + Vector res; + VectorMultiply( *this, v, res ); + return res; +} + +inline Vector Vector::operator/(float fl) const +{ + Vector res; + VectorDivide( *this, fl, res ); + return res; +} + +inline Vector Vector::operator/(const Vector& v) const +{ + Vector res; + VectorDivide( *this, v, res ); + return res; +} + +inline Vector operator*(float fl, const Vector& v) +{ + return v * fl; +} + +//----------------------------------------------------------------------------- +// cross product +//----------------------------------------------------------------------------- + +inline Vector Vector::Cross(const Vector& vOther) const +{ + Vector res; + CrossProduct( *this, vOther, res ); + return res; +} + +//----------------------------------------------------------------------------- +// 2D +//----------------------------------------------------------------------------- + +inline vec_t Vector::Length2D(void) const +{ + return (vec_t)FastSqrt(x*x + y*y); +} + +inline vec_t Vector::Length2DSqr(void) const +{ + return (x*x + y*y); +} + +inline Vector CrossProduct(const Vector& a, const Vector& b) +{ + return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); +} + +inline void VectorMin( const Vector &a, const Vector &b, Vector &result ) +{ + result.x = fpmin(a.x, b.x); + result.y = fpmin(a.y, b.y); + result.z = fpmin(a.z, b.z); +} + +inline void VectorMax( const Vector &a, const Vector &b, Vector &result ) +{ + result.x = fpmax(a.x, b.x); + result.y = fpmax(a.y, b.y); + result.z = fpmax(a.z, b.z); +} + +inline float ComputeVolume( const Vector &vecMins, const Vector &vecMaxs ) +{ + Vector vecDelta; + VectorSubtract( vecMaxs, vecMins, vecDelta ); + return DotProduct( vecDelta, vecDelta ); +} + +// Get a random vector. +inline Vector RandomVector( float minVal, float maxVal ) +{ + Vector random; + random.Random( minVal, maxVal ); + return random; +} + +#endif //slow + +//----------------------------------------------------------------------------- +// Helper debugging stuff.... +//----------------------------------------------------------------------------- + +inline bool operator==( float const*, const Vector& ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + +inline bool operator==( const Vector&, float const* ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + +inline bool operator!=( float const*, const Vector& ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + +inline bool operator!=( const Vector&, float const* ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + + +//----------------------------------------------------------------------------- +// AngularImpulse +//----------------------------------------------------------------------------- +// AngularImpulse are exponetial maps (an axis scaled by a "twist" angle in degrees) +typedef Vector AngularImpulse; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline AngularImpulse RandomAngularImpulse( float minVal, float maxVal ) +{ + AngularImpulse angImp; + angImp.Random( minVal, maxVal ); + return angImp; +} + +#endif + + +//----------------------------------------------------------------------------- +// Quaternion +//----------------------------------------------------------------------------- + +class RadianEuler; + +class Quaternion // same data-layout as engine's vec4_t, +{ // which is a vec_t[4] +public: + inline Quaternion(void) { + + // Initialize to NAN to catch errors +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + x = y = z = w = VEC_T_NAN; +#endif +#endif + } + inline Quaternion(vec_t ix, vec_t iy, vec_t iz, vec_t iw) : x(ix), y(iy), z(iz), w(iw) { } + inline Quaternion(RadianEuler const &angle); // evil auto type promotion!!! + + inline void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f, vec_t iw=0.0f) { x = ix; y = iy; z = iz; w = iw; } + + bool IsValid() const; + void Invalidate(); + + bool operator==( const Quaternion &src ) const; + bool operator!=( const Quaternion &src ) const; + + vec_t* Base() { return (vec_t*)this; } + const vec_t* Base() const { return (vec_t*)this; } + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t x, y, z, w; +}; + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& Quaternion::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Quaternion::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Equality test +//----------------------------------------------------------------------------- +inline bool Quaternion::operator==( const Quaternion &src ) const +{ + return ( x == src.x ) && ( y == src.y ) && ( z == src.z ) && ( w == src.w ); +} + +inline bool Quaternion::operator!=( const Quaternion &src ) const +{ + return !operator==( src ); +} + + +//----------------------------------------------------------------------------- +// Quaternion equality with tolerance +//----------------------------------------------------------------------------- +inline bool QuaternionsAreEqual( const Quaternion& src1, const Quaternion& src2, float tolerance ) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + if (FloatMakePositive(src1.z - src2.z) > tolerance) + return false; + return (FloatMakePositive(src1.w - src2.w) <= tolerance); +} + + +//----------------------------------------------------------------------------- +// Here's where we add all those lovely SSE optimized routines +//----------------------------------------------------------------------------- +class ALIGN16 QuaternionAligned : public Quaternion +{ +public: + inline QuaternionAligned(void) {}; + inline QuaternionAligned(vec_t X, vec_t Y, vec_t Z, vec_t W) + { + Init(X,Y,Z,W); + } + +#ifdef VECTOR_NO_SLOW_OPERATIONS + +private: + // No copy constructors allowed if we're in optimal mode + QuaternionAligned(const QuaternionAligned& vOther); + QuaternionAligned(const Quaternion &vOther); + +#else +public: + explicit QuaternionAligned(const Quaternion &vOther) + { + Init(vOther.x, vOther.y, vOther.z, vOther.w); + } + + QuaternionAligned& operator=(const Quaternion &vOther) + { + Init(vOther.x, vOther.y, vOther.z, vOther.w); + return *this; + } + +#endif +} ALIGN16_POST; + + +//----------------------------------------------------------------------------- +// Radian Euler angle aligned to axis (NOT ROLL/PITCH/YAW) +//----------------------------------------------------------------------------- +class QAngle; +class RadianEuler +{ +public: + inline RadianEuler(void) { } + inline RadianEuler(vec_t X, vec_t Y, vec_t Z) { x = X; y = Y; z = Z; } + inline RadianEuler(Quaternion const &q); // evil auto type promotion!!! + inline RadianEuler(QAngle const &angles); // evil auto type promotion!!! + + // Initialization + inline void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f) { x = ix; y = iy; z = iz; } + + // conversion to qangle + QAngle ToQAngle( void ) const; + bool IsValid() const; + void Invalidate(); + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t x, y, z; +}; + + +extern void AngleQuaternion( RadianEuler const &angles, Quaternion &qt ); +extern void QuaternionAngles( Quaternion const &q, RadianEuler &angles ); + +FORCEINLINE void NetworkVarConstruct( Quaternion &q ) { q.x = q.y = q.z = q.w = 0.0f; } + +inline Quaternion::Quaternion(RadianEuler const &angle) +{ + AngleQuaternion( angle, *this ); +} + +inline bool Quaternion::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w); +} + +inline void Quaternion::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = w = VEC_T_NAN; +//#endif +//#endif +} + +inline RadianEuler::RadianEuler(Quaternion const &q) +{ + QuaternionAngles( q, *this ); +} + +inline void VectorCopy( RadianEuler const& src, RadianEuler &dst ) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void VectorScale( RadianEuler const& src, float b, RadianEuler &dst ) +{ + CHECK_VALID(src); + Assert( IsFinite(b) ); + dst.x = src.x * b; + dst.y = src.y * b; + dst.z = src.z * b; +} + +inline bool RadianEuler::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +inline void RadianEuler::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +//#endif +//#endif +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& RadianEuler::operator[](int i) +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + +inline vec_t RadianEuler::operator[](int i) const +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Degree Euler QAngle pitch, yaw, roll +//----------------------------------------------------------------------------- +class QAngleByValue; + +class QAngle +{ +public: + // Members + vec_t x, y, z; + + // Construction/destruction + QAngle(void); + QAngle(vec_t X, vec_t Y, vec_t Z); +// QAngle(RadianEuler const &angles); // evil auto type promotion!!! + + // Allow pass-by-value + operator QAngleByValue &() { return *((QAngleByValue *)(this)); } + operator const QAngleByValue &() const { return *((const QAngleByValue *)(this)); } + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f); + void Random( vec_t minVal, vec_t maxVal ); + + // Got any nasty NAN's? + bool IsValid() const; + void Invalidate(); + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + vec_t* Base(); + vec_t const* Base() const; + + // equality + bool operator==(const QAngle& v) const; + bool operator!=(const QAngle& v) const; + + // arithmetic operations + QAngle& operator+=(const QAngle &v); + QAngle& operator-=(const QAngle &v); + QAngle& operator*=(float s); + QAngle& operator/=(float s); + + // Get the vector's magnitude. + vec_t Length() const; + vec_t LengthSqr() const; + + // negate the QAngle components + //void Negate(); + + // No assignment operators either... + QAngle& operator=( const QAngle& src ); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // copy constructors + + // arithmetic operations + QAngle operator-(void) const; + + QAngle operator+(const QAngle& v) const; + QAngle operator-(const QAngle& v) const; + QAngle operator*(float fl) const; + QAngle operator/(float fl) const; +#else + +private: + // No copy constructors allowed if we're in optimal mode + QAngle(const QAngle& vOther); + +#endif +}; + +FORCEINLINE void NetworkVarConstruct( QAngle &q ) { q.x = q.y = q.z = 0.0f; } + +//----------------------------------------------------------------------------- +// Allows us to specifically pass the vector by value when we need to +//----------------------------------------------------------------------------- +class QAngleByValue : public QAngle +{ +public: + // Construction/destruction: + QAngleByValue(void) : QAngle() {} + QAngleByValue(vec_t X, vec_t Y, vec_t Z) : QAngle( X, Y, Z ) {} + QAngleByValue(const QAngleByValue& vOther) : QAngle( vOther.x, vOther.y, vOther.z ) {} +}; + + +inline void VectorAdd( const QAngle& a, const QAngle& b, QAngle& result ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + result.x = a.x + b.x; + result.y = a.y + b.y; + result.z = a.z + b.z; +} + +inline void VectorMA( const QAngle &start, float scale, const QAngle &direction, QAngle &dest ) +{ + CHECK_VALID(start); + CHECK_VALID(direction); + dest.x = start.x + scale * direction.x; + dest.y = start.y + scale * direction.y; + dest.z = start.z + scale * direction.z; +} + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +inline QAngle::QAngle(void) +{ +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + // Initialize to NAN to catch errors + x = y = z = VEC_T_NAN; +#endif +#endif +} + +inline QAngle::QAngle(vec_t X, vec_t Y, vec_t Z) +{ + x = X; y = Y; z = Z; + CHECK_VALID(*this); +} + + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- +inline void QAngle::Init( vec_t ix, vec_t iy, vec_t iz ) +{ + x = ix; y = iy; z = iz; + CHECK_VALID(*this); +} + +inline void QAngle::Random( vec_t minVal, vec_t maxVal ) +{ + x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + z = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + CHECK_VALID(*this); +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline QAngle RandomAngle( float minVal, float maxVal ) +{ + Vector random; + random.Random( minVal, maxVal ); + QAngle ret( random.x, random.y, random.z ); + return ret; +} + +#endif + + +inline RadianEuler::RadianEuler(QAngle const &angles) +{ + Init( + angles.z * 3.14159265358979323846f / 180.f, + angles.x * 3.14159265358979323846f / 180.f, + angles.y * 3.14159265358979323846f / 180.f ); +} + + + + +inline QAngle RadianEuler::ToQAngle( void) const +{ + return QAngle( + y * 180.f / 3.14159265358979323846f, + z * 180.f / 3.14159265358979323846f, + x * 180.f / 3.14159265358979323846f ); +} + + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- +inline QAngle& QAngle::operator=(const QAngle &vOther) +{ + CHECK_VALID(vOther); + x=vOther.x; y=vOther.y; z=vOther.z; + return *this; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& QAngle::operator[](int i) +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + +inline vec_t QAngle::operator[](int i) const +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline vec_t* QAngle::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* QAngle::Base() const +{ + return (vec_t const*)this; +} + + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- +inline bool QAngle::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +//----------------------------------------------------------------------------- +// Invalidate +//----------------------------------------------------------------------------- + +inline void QAngle::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +//#endif +//#endif +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- +inline bool QAngle::operator==( const QAngle& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +inline bool QAngle::operator!=( const QAngle& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- +inline void VectorCopy( const QAngle& src, QAngle& dst ) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- +inline QAngle& QAngle::operator+=(const QAngle& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x+=v.x; y+=v.y; z += v.z; + return *this; +} + +inline QAngle& QAngle::operator-=(const QAngle& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x-=v.x; y-=v.y; z -= v.z; + return *this; +} + +inline QAngle& QAngle::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +inline QAngle& QAngle::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- +inline vec_t QAngle::Length( ) const +{ + CHECK_VALID(*this); + return (vec_t)FastSqrt( LengthSqr( ) ); +} + + +inline vec_t QAngle::LengthSqr( ) const +{ + CHECK_VALID(*this); + return x * x + y * y + z * z; +} + + +//----------------------------------------------------------------------------- +// Vector equality with tolerance +//----------------------------------------------------------------------------- +inline bool QAnglesAreEqual( const QAngle& src1, const QAngle& src2, float tolerance = 0.0f ) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + return (FloatMakePositive(src1.z - src2.z) <= tolerance); +} + + +//----------------------------------------------------------------------------- +// arithmetic operations (SLOW!!) +//----------------------------------------------------------------------------- +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline QAngle QAngle::operator-(void) const +{ + QAngle ret(-x,-y,-z); + return ret; +} + +inline QAngle QAngle::operator+(const QAngle& v) const +{ + QAngle res; + res.x = x + v.x; + res.y = y + v.y; + res.z = z + v.z; + return res; +} + +inline QAngle QAngle::operator-(const QAngle& v) const +{ + QAngle res; + res.x = x - v.x; + res.y = y - v.y; + res.z = z - v.z; + return res; +} + +inline QAngle QAngle::operator*(float fl) const +{ + QAngle res; + res.x = x * fl; + res.y = y * fl; + res.z = z * fl; + return res; +} + +inline QAngle QAngle::operator/(float fl) const +{ + QAngle res; + res.x = x / fl; + res.y = y / fl; + res.z = z / fl; + return res; +} + +inline QAngle operator*(float fl, const QAngle& v) +{ + QAngle ret( v * fl ); + return ret; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +//----------------------------------------------------------------------------- +// NOTE: These are not completely correct. The representations are not equivalent +// unless the QAngle represents a rotational impulse along a coordinate axis (x,y,z) +inline void QAngleToAngularImpulse( const QAngle &angles, AngularImpulse &impulse ) +{ + impulse.x = angles.z; + impulse.y = angles.x; + impulse.z = angles.y; +} + +inline void AngularImpulseToQAngle( const AngularImpulse &impulse, QAngle &angles ) +{ + angles.x = impulse.y; + angles.y = impulse.z; + angles.z = impulse.x; +} + +#if !defined( _X360 ) + +FORCEINLINE vec_t InvRSquared( float const *v ) +{ +#if defined(__i386__) || defined(_M_IX86) + float sqrlen = v[0]*v[0]+v[1]*v[1]+v[2]*v[2] + 1.0e-10f, result; + _mm_store_ss(&result, _mm_rcp_ss( _mm_max_ss( _mm_set_ss(1.0f), _mm_load_ss(&sqrlen) ) )); + return result; +#else + return 1.f/fpmax(1.f, v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); +#endif +} + +FORCEINLINE vec_t InvRSquared( const Vector &v ) +{ + return InvRSquared(&v.x); +} + +#if defined(__i386__) || defined(_M_IX86) +inline void _SSE_RSqrtInline( float a, float* out ) +{ + __m128 xx = _mm_load_ss( &a ); + __m128 xr = _mm_rsqrt_ss( xx ); + __m128 xt; + xt = _mm_mul_ss( xr, xr ); + xt = _mm_mul_ss( xt, xx ); + xt = _mm_sub_ss( _mm_set_ss(3.f), xt ); + xt = _mm_mul_ss( xt, _mm_set_ss(0.5f) ); + xr = _mm_mul_ss( xr, xt ); + _mm_store_ss( out, xr ); +} +#endif + +// FIXME: Change this back to a #define once we get rid of the vec_t version +FORCEINLINE float VectorNormalize( Vector& vec ) +{ +#ifndef DEBUG // stop crashing my edit-and-continue! + #if defined(__i386__) || defined(_M_IX86) + #define DO_SSE_OPTIMIZATION + #endif +#endif + +#if defined( DO_SSE_OPTIMIZATION ) + float sqrlen = vec.LengthSqr() + 1.0e-10f, invlen; + _SSE_RSqrtInline(sqrlen, &invlen); + vec.x *= invlen; + vec.y *= invlen; + vec.z *= invlen; + return sqrlen * invlen; +#else + extern float (FASTCALL *pfVectorNormalize)(Vector& v); + return (*pfVectorNormalize)(vec); +#endif +} + +// FIXME: Obsolete version of VectorNormalize, once we remove all the friggin float*s +FORCEINLINE float VectorNormalize( float * v ) +{ + return VectorNormalize(*(reinterpret_cast(v))); +} + +FORCEINLINE void VectorNormalizeFast( Vector &vec ) +{ + VectorNormalize(vec); +} + +#else + +FORCEINLINE float _VMX_InvRSquared( const Vector &v ) +{ + XMVECTOR xmV = XMVector3ReciprocalLength( XMLoadVector3( v.Base() ) ); + xmV = XMVector3Dot( xmV, xmV ); + return xmV.x; +} + +// call directly +FORCEINLINE float _VMX_VectorNormalize( Vector &vec ) +{ + float mag = XMVector3Length( XMLoadVector3( vec.Base() ) ).x; + float den = 1.f / (mag + FLT_EPSILON ); + vec.x *= den; + vec.y *= den; + vec.z *= den; + return mag; +} + +#define InvRSquared(x) _VMX_InvRSquared(x) + +// FIXME: Change this back to a #define once we get rid of the vec_t version +FORCEINLINE float VectorNormalize( Vector& v ) +{ + return _VMX_VectorNormalize( v ); +} +// FIXME: Obsolete version of VectorNormalize, once we remove all the friggin float*s +FORCEINLINE float VectorNormalize( float *pV ) +{ + return _VMX_VectorNormalize(*(reinterpret_cast(pV))); +} + +// call directly +FORCEINLINE void VectorNormalizeFast( Vector &vec ) +{ + XMVECTOR xmV = XMVector3LengthEst( XMLoadVector3( vec.Base() ) ); + float den = 1.f / (xmV.x + FLT_EPSILON); + vec.x *= den; + vec.y *= den; + vec.z *= den; +} + +#endif // _X360 + + +inline vec_t Vector::NormalizeInPlace() +{ + return VectorNormalize( *this ); +} + +inline Vector Vector::Normalized() const +{ + Vector norm = *this; + VectorNormalize( norm ); + return norm; +} + +inline bool Vector::IsLengthGreaterThan( float val ) const +{ + return LengthSqr() > val*val; +} + +inline bool Vector::IsLengthLessThan( float val ) const +{ + return LengthSqr() < val*val; +} + +#endif + diff --git a/public/mathlib/vector2d.h b/public/mathlib/vector2d.h new file mode 100644 index 0000000..4138558 --- /dev/null +++ b/public/mathlib/vector2d.h @@ -0,0 +1,670 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +// For vec_t, put this somewhere else? +#include "tier0/basetypes.h" + +// For rand(). We really need a library! +#include + +#include "tier0/dbg.h" +#include "mathlib/math_pfns.h" + +//========================================================= +// 2D Vector2D +//========================================================= + +class Vector2D +{ +public: + // Members + vec_t x, y; + + // Construction/destruction + Vector2D(void); + Vector2D(vec_t X, vec_t Y); + Vector2D(const float *pFloat); + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f); + + // Got any nasty NAN's? + bool IsValid() const; + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + vec_t* Base(); + vec_t const* Base() const; + + // Initialization methods + void Random( float minVal, float maxVal ); + + // equality + bool operator==(const Vector2D& v) const; + bool operator!=(const Vector2D& v) const; + + // arithmetic operations + Vector2D& operator+=(const Vector2D &v); + Vector2D& operator-=(const Vector2D &v); + Vector2D& operator*=(const Vector2D &v); + Vector2D& operator*=(float s); + Vector2D& operator/=(const Vector2D &v); + Vector2D& operator/=(float s); + + // negate the Vector2D components + void Negate(); + + // Get the Vector2D's magnitude. + vec_t Length() const; + + // Get the Vector2D's magnitude squared. + vec_t LengthSqr(void) const; + + // return true if this vector is (0,0) within tolerance + bool IsZero( float tolerance = 0.01f ) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance); + } + + // Normalize in place and return the old length. + vec_t NormalizeInPlace(); + + // Compare length. + bool IsLengthGreaterThan( float val ) const; + bool IsLengthLessThan( float val ) const; + + // Get the distance from this Vector2D to the other one. + vec_t DistTo(const Vector2D &vOther) const; + + // Get the distance from this Vector2D to the other one squared. + vec_t DistToSqr(const Vector2D &vOther) const; + + // Copy + void CopyToArray(float* rgfl) const; + + // Multiply, add, and assign to this (ie: *this = a + b * scalar). This + // is about 12% faster than the actual Vector2D equation (because it's done per-component + // rather than per-Vector2D). + void MulAdd(const Vector2D& a, const Vector2D& b, float scalar); + + // Dot product. + vec_t Dot(const Vector2D& vOther) const; + + // assignment + Vector2D& operator=(const Vector2D &vOther); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // copy constructors + Vector2D(const Vector2D &vOther); + + // arithmetic operations + Vector2D operator-(void) const; + + Vector2D operator+(const Vector2D& v) const; + Vector2D operator-(const Vector2D& v) const; + Vector2D operator*(const Vector2D& v) const; + Vector2D operator/(const Vector2D& v) const; + Vector2D operator*(float fl) const; + Vector2D operator/(float fl) const; + + // Cross product between two vectors. + Vector2D Cross(const Vector2D &vOther) const; + + // Returns a Vector2D with the min or max in X, Y, and Z. + Vector2D Min(const Vector2D &vOther) const; + Vector2D Max(const Vector2D &vOther) const; + +#else + +private: + // No copy constructors allowed if we're in optimal mode + Vector2D(const Vector2D& vOther); +#endif +}; + +//----------------------------------------------------------------------------- + +const Vector2D vec2_origin(0,0); +const Vector2D vec2_invalid( FLT_MAX, FLT_MAX ); + +//----------------------------------------------------------------------------- +// Vector2D related operations +//----------------------------------------------------------------------------- + +// Vector2D clear +void Vector2DClear( Vector2D& a ); + +// Copy +void Vector2DCopy( const Vector2D& src, Vector2D& dst ); + +// Vector2D arithmetic +void Vector2DAdd( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DSubtract( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DMultiply( const Vector2D& a, vec_t b, Vector2D& result ); +void Vector2DMultiply( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DDivide( const Vector2D& a, vec_t b, Vector2D& result ); +void Vector2DDivide( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DMA( const Vector2D& start, float s, const Vector2D& dir, Vector2D& result ); + +// Store the min or max of each of x, y, and z into the result. +void Vector2DMin( const Vector2D &a, const Vector2D &b, Vector2D &result ); +void Vector2DMax( const Vector2D &a, const Vector2D &b, Vector2D &result ); + +#define Vector2DExpand( v ) (v).x, (v).y + +// Normalization +vec_t Vector2DNormalize( Vector2D& v ); + +// Length +vec_t Vector2DLength( const Vector2D& v ); + +// Dot Product +vec_t DotProduct2D(const Vector2D& a, const Vector2D& b); + +// Linearly interpolate between two vectors +void Vector2DLerp(const Vector2D& src1, const Vector2D& src2, vec_t t, Vector2D& dest ); + + +//----------------------------------------------------------------------------- +// +// Inlined Vector2D methods +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- + +inline Vector2D::Vector2D(void) +{ +#ifdef _DEBUG + // Initialize to NAN to catch errors + x = y = VEC_T_NAN; +#endif +} + +inline Vector2D::Vector2D(vec_t X, vec_t Y) +{ + x = X; y = Y; + Assert( IsValid() ); +} + +inline Vector2D::Vector2D(const float *pFloat) +{ + Assert( pFloat ); + x = pFloat[0]; y = pFloat[1]; + Assert( IsValid() ); +} + + +//----------------------------------------------------------------------------- +// copy constructor +//----------------------------------------------------------------------------- + +inline Vector2D::Vector2D(const Vector2D &vOther) +{ + Assert( vOther.IsValid() ); + x = vOther.x; y = vOther.y; +} + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- + +inline void Vector2D::Init( vec_t ix, vec_t iy ) +{ + x = ix; y = iy; + Assert( IsValid() ); +} + +inline void Vector2D::Random( float minVal, float maxVal ) +{ + x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); +} + +inline void Vector2DClear( Vector2D& a ) +{ + a.x = a.y = 0.0f; +} + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- + +inline Vector2D& Vector2D::operator=(const Vector2D &vOther) +{ + Assert( vOther.IsValid() ); + x=vOther.x; y=vOther.y; + return *this; +} + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- + +inline vec_t& Vector2D::operator[](int i) +{ + Assert( (i >= 0) && (i < 2) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector2D::operator[](int i) const +{ + Assert( (i >= 0) && (i < 2) ); + return ((vec_t*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- + +inline vec_t* Vector2D::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector2D::Base() const +{ + return (vec_t const*)this; +} + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- + +inline bool Vector2D::IsValid() const +{ + return IsFinite(x) && IsFinite(y); +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool Vector2D::operator==( const Vector2D& src ) const +{ + Assert( src.IsValid() && IsValid() ); + return (src.x == x) && (src.y == y); +} + +inline bool Vector2D::operator!=( const Vector2D& src ) const +{ + Assert( src.IsValid() && IsValid() ); + return (src.x != x) || (src.y != y); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- + +inline void Vector2DCopy( const Vector2D& src, Vector2D& dst ) +{ + Assert( src.IsValid() ); + dst.x = src.x; + dst.y = src.y; +} + +inline void Vector2D::CopyToArray(float* rgfl) const +{ + Assert( IsValid() ); + Assert( rgfl ); + rgfl[0] = x; rgfl[1] = y; +} + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +inline void Vector2D::Negate() +{ + Assert( IsValid() ); + x = -x; y = -y; +} + +inline Vector2D& Vector2D::operator+=(const Vector2D& v) +{ + Assert( IsValid() && v.IsValid() ); + x+=v.x; y+=v.y; + return *this; +} + +inline Vector2D& Vector2D::operator-=(const Vector2D& v) +{ + Assert( IsValid() && v.IsValid() ); + x-=v.x; y-=v.y; + return *this; +} + +inline Vector2D& Vector2D::operator*=(float fl) +{ + x *= fl; + y *= fl; + Assert( IsValid() ); + return *this; +} + +inline Vector2D& Vector2D::operator*=(const Vector2D& v) +{ + x *= v.x; + y *= v.y; + Assert( IsValid() ); + return *this; +} + +inline Vector2D& Vector2D::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + Assert( IsValid() ); + return *this; +} + +inline Vector2D& Vector2D::operator/=(const Vector2D& v) +{ + Assert( v.x != 0.0f && v.y != 0.0f ); + x /= v.x; + y /= v.y; + Assert( IsValid() ); + return *this; +} + +inline void Vector2DAdd( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x + b.x; + c.y = a.y + b.y; +} + +inline void Vector2DSubtract( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x - b.x; + c.y = a.y - b.y; +} + +inline void Vector2DMultiply( const Vector2D& a, vec_t b, Vector2D& c ) +{ + Assert( a.IsValid() && IsFinite(b) ); + c.x = a.x * b; + c.y = a.y * b; +} + +inline void Vector2DMultiply( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x * b.x; + c.y = a.y * b.y; +} + + +inline void Vector2DDivide( const Vector2D& a, vec_t b, Vector2D& c ) +{ + Assert( a.IsValid() ); + Assert( b != 0.0f ); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; +} + +inline void Vector2DDivide( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() ); + Assert( (b.x != 0.0f) && (b.y != 0.0f) ); + c.x = a.x / b.x; + c.y = a.y / b.y; +} + +inline void Vector2DMA( const Vector2D& start, float s, const Vector2D& dir, Vector2D& result ) +{ + Assert( start.IsValid() && IsFinite(s) && dir.IsValid() ); + result.x = start.x + s*dir.x; + result.y = start.y + s*dir.y; +} + +// FIXME: Remove +// For backwards compatability +inline void Vector2D::MulAdd(const Vector2D& a, const Vector2D& b, float scalar) +{ + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; +} + +inline void Vector2DLerp(const Vector2D& src1, const Vector2D& src2, vec_t t, Vector2D& dest ) +{ + dest[0] = src1[0] + (src2[0] - src1[0]) * t; + dest[1] = src1[1] + (src2[1] - src1[1]) * t; +} + +//----------------------------------------------------------------------------- +// dot, cross +//----------------------------------------------------------------------------- +inline vec_t DotProduct2D(const Vector2D& a, const Vector2D& b) +{ + Assert( a.IsValid() && b.IsValid() ); + return( a.x*b.x + a.y*b.y ); +} + +// for backwards compatability +inline vec_t Vector2D::Dot( const Vector2D& vOther ) const +{ + return DotProduct2D( *this, vOther ); +} + + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- +inline vec_t Vector2DLength( const Vector2D& v ) +{ + Assert( v.IsValid() ); + return (vec_t)FastSqrt(v.x*v.x + v.y*v.y); +} + +inline vec_t Vector2D::LengthSqr(void) const +{ + Assert( IsValid() ); + return (x*x + y*y); +} + +inline vec_t Vector2D::NormalizeInPlace() +{ + return Vector2DNormalize( *this ); +} + +inline bool Vector2D::IsLengthGreaterThan( float val ) const +{ + return LengthSqr() > val*val; +} + +inline bool Vector2D::IsLengthLessThan( float val ) const +{ + return LengthSqr() < val*val; +} + +inline vec_t Vector2D::Length(void) const +{ + return Vector2DLength( *this ); +} + + +inline void Vector2DMin( const Vector2D &a, const Vector2D &b, Vector2D &result ) +{ + result.x = (a.x < b.x) ? a.x : b.x; + result.y = (a.y < b.y) ? a.y : b.y; +} + + +inline void Vector2DMax( const Vector2D &a, const Vector2D &b, Vector2D &result ) +{ + result.x = (a.x > b.x) ? a.x : b.x; + result.y = (a.y > b.y) ? a.y : b.y; +} + + +//----------------------------------------------------------------------------- +// Normalization +//----------------------------------------------------------------------------- +inline vec_t Vector2DNormalize( Vector2D& v ) +{ + Assert( v.IsValid() ); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + v.x = v.y = 0.0f; + } + return l; +} + + +//----------------------------------------------------------------------------- +// Get the distance from this Vector2D to the other one +//----------------------------------------------------------------------------- +inline vec_t Vector2D::DistTo(const Vector2D &vOther) const +{ + Vector2D delta; + Vector2DSubtract( *this, vOther, delta ); + return delta.Length(); +} + +inline vec_t Vector2D::DistToSqr(const Vector2D &vOther) const +{ + Vector2D delta; + Vector2DSubtract( *this, vOther, delta ); + return delta.LengthSqr(); +} + + +//----------------------------------------------------------------------------- +// Computes the closest point to vecTarget no farther than flMaxDist from vecStart +//----------------------------------------------------------------------------- +inline void ComputeClosestPoint2D( const Vector2D& vecStart, float flMaxDist, const Vector2D& vecTarget, Vector2D *pResult ) +{ + Vector2D vecDelta; + Vector2DSubtract( vecTarget, vecStart, vecDelta ); + float flDistSqr = vecDelta.LengthSqr(); + if ( flDistSqr <= flMaxDist * flMaxDist ) + { + *pResult = vecTarget; + } + else + { + vecDelta /= FastSqrt( flDistSqr ); + Vector2DMA( vecStart, flMaxDist, vecDelta, *pResult ); + } +} + + + +//----------------------------------------------------------------------------- +// +// Slow methods +// +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +//----------------------------------------------------------------------------- +// Returns a Vector2D with the min or max in X, Y, and Z. +//----------------------------------------------------------------------------- + +inline Vector2D Vector2D::Min(const Vector2D &vOther) const +{ + return Vector2D(x < vOther.x ? x : vOther.x, + y < vOther.y ? y : vOther.y); +} + +inline Vector2D Vector2D::Max(const Vector2D &vOther) const +{ + return Vector2D(x > vOther.x ? x : vOther.x, + y > vOther.y ? y : vOther.y); +} + + +//----------------------------------------------------------------------------- +// arithmetic operations +//----------------------------------------------------------------------------- + +inline Vector2D Vector2D::operator-(void) const +{ + return Vector2D(-x,-y); +} + +inline Vector2D Vector2D::operator+(const Vector2D& v) const +{ + Vector2D res; + Vector2DAdd( *this, v, res ); + return res; +} + +inline Vector2D Vector2D::operator-(const Vector2D& v) const +{ + Vector2D res; + Vector2DSubtract( *this, v, res ); + return res; +} + +inline Vector2D Vector2D::operator*(float fl) const +{ + Vector2D res; + Vector2DMultiply( *this, fl, res ); + return res; +} + +inline Vector2D Vector2D::operator*(const Vector2D& v) const +{ + Vector2D res; + Vector2DMultiply( *this, v, res ); + return res; +} + +inline Vector2D Vector2D::operator/(float fl) const +{ + Vector2D res; + Vector2DDivide( *this, fl, res ); + return res; +} + +inline Vector2D Vector2D::operator/(const Vector2D& v) const +{ + Vector2D res; + Vector2DDivide( *this, v, res ); + return res; +} + +inline Vector2D operator*(float fl, const Vector2D& v) +{ + return v * fl; +} + +#endif //slow + +#endif // VECTOR2D_H + diff --git a/public/mathlib/vector4d.h b/public/mathlib/vector4d.h new file mode 100644 index 0000000..2b20c88 --- /dev/null +++ b/public/mathlib/vector4d.h @@ -0,0 +1,686 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VECTOR4D_H +#define VECTOR4D_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include // For rand(). We really need a library! +#include +#if !defined( _X360 ) +#include // For SSE +#endif +#include "basetypes.h" // For vec_t, put this somewhere else? +#include "tier0/dbg.h" +#include "mathlib/math_pfns.h" + +// forward declarations +class Vector; +class Vector2D; + +//========================================================= +// 4D Vector4D +//========================================================= + +class Vector4D +{ +public: + // Members + vec_t x, y, z, w; + + // Construction/destruction + Vector4D(void); + Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W); + Vector4D(const float *pFloat); + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f, vec_t iw=0.0f); + + // Got any nasty NAN's? + bool IsValid() const; + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + inline vec_t* Base(); + inline vec_t const* Base() const; + + // Cast to Vector and Vector2D... + Vector& AsVector3D(); + Vector const& AsVector3D() const; + + Vector2D& AsVector2D(); + Vector2D const& AsVector2D() const; + + // Initialization methods + void Random( vec_t minVal, vec_t maxVal ); + + // equality + bool operator==(const Vector4D& v) const; + bool operator!=(const Vector4D& v) const; + + // arithmetic operations + Vector4D& operator+=(const Vector4D &v); + Vector4D& operator-=(const Vector4D &v); + Vector4D& operator*=(const Vector4D &v); + Vector4D& operator*=(float s); + Vector4D& operator/=(const Vector4D &v); + Vector4D& operator/=(float s); + + // negate the Vector4D components + void Negate(); + + // Get the Vector4D's magnitude. + vec_t Length() const; + + // Get the Vector4D's magnitude squared. + vec_t LengthSqr(void) const; + + // return true if this vector is (0,0,0,0) within tolerance + bool IsZero( float tolerance = 0.01f ) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance && + z > -tolerance && z < tolerance && + w > -tolerance && w < tolerance); + } + + // Get the distance from this Vector4D to the other one. + vec_t DistTo(const Vector4D &vOther) const; + + // Get the distance from this Vector4D to the other one squared. + vec_t DistToSqr(const Vector4D &vOther) const; + + // Copy + void CopyToArray(float* rgfl) const; + + // Multiply, add, and assign to this (ie: *this = a + b * scalar). This + // is about 12% faster than the actual Vector4D equation (because it's done per-component + // rather than per-Vector4D). + void MulAdd(Vector4D const& a, Vector4D const& b, float scalar); + + // Dot product. + vec_t Dot(Vector4D const& vOther) const; + + // No copy constructors allowed if we're in optimal mode +#ifdef VECTOR_NO_SLOW_OPERATIONS +private: +#else +public: +#endif + Vector4D(Vector4D const& vOther); + + // No assignment operators either... + Vector4D& operator=( Vector4D const& src ); +}; + +const Vector4D vec4_origin( 0.0f, 0.0f, 0.0f, 0.0f ); +const Vector4D vec4_invalid( FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX ); + +//----------------------------------------------------------------------------- +// SSE optimized routines +//----------------------------------------------------------------------------- + +class ALIGN16 Vector4DAligned : public Vector4D +{ +public: + Vector4DAligned(void) {} + Vector4DAligned( vec_t X, vec_t Y, vec_t Z, vec_t W ); + + inline void Set( vec_t X, vec_t Y, vec_t Z, vec_t W ); + inline void InitZero( void ); + + inline __m128 &AsM128() { return *(__m128*)&x; } + inline const __m128 &AsM128() const { return *(const __m128*)&x; } + +private: + // No copy constructors allowed if we're in optimal mode + Vector4DAligned( Vector4DAligned const& vOther ); + + // No assignment operators either... + Vector4DAligned& operator=( Vector4DAligned const& src ); +} ALIGN16_POST; + +//----------------------------------------------------------------------------- +// Vector4D related operations +//----------------------------------------------------------------------------- + +// Vector4D clear +void Vector4DClear( Vector4D& a ); + +// Copy +void Vector4DCopy( Vector4D const& src, Vector4D& dst ); + +// Vector4D arithmetic +void Vector4DAdd( Vector4D const& a, Vector4D const& b, Vector4D& result ); +void Vector4DSubtract( Vector4D const& a, Vector4D const& b, Vector4D& result ); +void Vector4DMultiply( Vector4D const& a, vec_t b, Vector4D& result ); +void Vector4DMultiply( Vector4D const& a, Vector4D const& b, Vector4D& result ); +void Vector4DDivide( Vector4D const& a, vec_t b, Vector4D& result ); +void Vector4DDivide( Vector4D const& a, Vector4D const& b, Vector4D& result ); +void Vector4DMA( Vector4D const& start, float s, Vector4D const& dir, Vector4D& result ); + +// Vector4DAligned arithmetic +void Vector4DMultiplyAligned( Vector4DAligned const& a, vec_t b, Vector4DAligned& result ); + + +#define Vector4DExpand( v ) (v).x, (v).y, (v).z, (v).w + +// Normalization +vec_t Vector4DNormalize( Vector4D& v ); + +// Length +vec_t Vector4DLength( Vector4D const& v ); + +// Dot Product +vec_t DotProduct4D(Vector4D const& a, Vector4D const& b); + +// Linearly interpolate between two vectors +void Vector4DLerp(Vector4D const& src1, Vector4D const& src2, vec_t t, Vector4D& dest ); + + +//----------------------------------------------------------------------------- +// +// Inlined Vector4D methods +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- + +inline Vector4D::Vector4D(void) +{ +#ifdef _DEBUG + // Initialize to NAN to catch errors + x = y = z = w = VEC_T_NAN; +#endif +} + +inline Vector4D::Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W ) +{ + x = X; y = Y; z = Z; w = W; + Assert( IsValid() ); +} + +inline Vector4D::Vector4D(const float *pFloat) +{ + Assert( pFloat ); + x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; w = pFloat[3]; + Assert( IsValid() ); +} + + +//----------------------------------------------------------------------------- +// copy constructor +//----------------------------------------------------------------------------- + +inline Vector4D::Vector4D(const Vector4D &vOther) +{ + Assert( vOther.IsValid() ); + x = vOther.x; y = vOther.y; z = vOther.z; w = vOther.w; +} + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- + +inline void Vector4D::Init( vec_t ix, vec_t iy, vec_t iz, vec_t iw ) +{ + x = ix; y = iy; z = iz; w = iw; + Assert( IsValid() ); +} + +inline void Vector4D::Random( vec_t minVal, vec_t maxVal ) +{ + x = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + z = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + w = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); +} + +inline void Vector4DClear( Vector4D& a ) +{ + a.x = a.y = a.z = a.w = 0.0f; +} + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- + +inline Vector4D& Vector4D::operator=(const Vector4D &vOther) +{ + Assert( vOther.IsValid() ); + x=vOther.x; y=vOther.y; z=vOther.z; w=vOther.w; + return *this; +} + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- + +inline vec_t& Vector4D::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector4D::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((vec_t*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Cast to Vector and Vector2D... +//----------------------------------------------------------------------------- + +inline Vector& Vector4D::AsVector3D() +{ + return *(Vector*)this; +} + +inline Vector const& Vector4D::AsVector3D() const +{ + return *(Vector const*)this; +} + +inline Vector2D& Vector4D::AsVector2D() +{ + return *(Vector2D*)this; +} + +inline Vector2D const& Vector4D::AsVector2D() const +{ + return *(Vector2D const*)this; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- + +inline vec_t* Vector4D::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector4D::Base() const +{ + return (vec_t const*)this; +} + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- + +inline bool Vector4D::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w); +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool Vector4D::operator==( Vector4D const& src ) const +{ + Assert( src.IsValid() && IsValid() ); + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool Vector4D::operator!=( Vector4D const& src ) const +{ + Assert( src.IsValid() && IsValid() ); + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- + +inline void Vector4DCopy( Vector4D const& src, Vector4D& dst ) +{ + Assert( src.IsValid() ); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = src.w; +} + +inline void Vector4D::CopyToArray(float* rgfl) const +{ + Assert( IsValid() ); + Assert( rgfl ); + rgfl[0] = x; rgfl[1] = y; rgfl[2] = z; rgfl[3] = w; +} + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +inline void Vector4D::Negate() +{ + Assert( IsValid() ); + x = -x; y = -y; z = -z; w = -w; +} + +inline Vector4D& Vector4D::operator+=(const Vector4D& v) +{ + Assert( IsValid() && v.IsValid() ); + x+=v.x; y+=v.y; z += v.z; w += v.w; + return *this; +} + +inline Vector4D& Vector4D::operator-=(const Vector4D& v) +{ + Assert( IsValid() && v.IsValid() ); + x-=v.x; y-=v.y; z -= v.z; w -= v.w; + return *this; +} + +inline Vector4D& Vector4D::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + w *= fl; + Assert( IsValid() ); + return *this; +} + +inline Vector4D& Vector4D::operator*=(Vector4D const& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + Assert( IsValid() ); + return *this; +} + +inline Vector4D& Vector4D::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + w *= oofl; + Assert( IsValid() ); + return *this; +} + +inline Vector4D& Vector4D::operator/=(Vector4D const& v) +{ + Assert( v.x != 0.0f && v.y != 0.0f && v.z != 0.0f && v.w != 0.0f ); + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; + Assert( IsValid() ); + return *this; +} + +inline void Vector4DAdd( Vector4D const& a, Vector4D const& b, Vector4D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x + b.x; + c.y = a.y + b.y; + c.z = a.z + b.z; + c.w = a.w + b.w; +} + +inline void Vector4DSubtract( Vector4D const& a, Vector4D const& b, Vector4D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x - b.x; + c.y = a.y - b.y; + c.z = a.z - b.z; + c.w = a.w - b.w; +} + +inline void Vector4DMultiply( Vector4D const& a, vec_t b, Vector4D& c ) +{ + Assert( a.IsValid() && IsFinite(b) ); + c.x = a.x * b; + c.y = a.y * b; + c.z = a.z * b; + c.w = a.w * b; +} + +inline void Vector4DMultiply( Vector4D const& a, Vector4D const& b, Vector4D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; + c.w = a.w * b.w; +} + +inline void Vector4DDivide( Vector4D const& a, vec_t b, Vector4D& c ) +{ + Assert( a.IsValid() ); + Assert( b != 0.0f ); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; + c.z = a.z * oob; + c.w = a.w * oob; +} + +inline void Vector4DDivide( Vector4D const& a, Vector4D const& b, Vector4D& c ) +{ + Assert( a.IsValid() ); + Assert( (b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f) && (b.w != 0.0f) ); + c.x = a.x / b.x; + c.y = a.y / b.y; + c.z = a.z / b.z; + c.w = a.w / b.w; +} + +inline void Vector4DMA( Vector4D const& start, float s, Vector4D const& dir, Vector4D& result ) +{ + Assert( start.IsValid() && IsFinite(s) && dir.IsValid() ); + result.x = start.x + s*dir.x; + result.y = start.y + s*dir.y; + result.z = start.z + s*dir.z; + result.w = start.w + s*dir.w; +} + +// FIXME: Remove +// For backwards compatability +inline void Vector4D::MulAdd(Vector4D const& a, Vector4D const& b, float scalar) +{ + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; + z = a.z + b.z * scalar; + w = a.w + b.w * scalar; +} + +inline void Vector4DLerp(const Vector4D& src1, const Vector4D& src2, vec_t t, Vector4D& dest ) +{ + dest[0] = src1[0] + (src2[0] - src1[0]) * t; + dest[1] = src1[1] + (src2[1] - src1[1]) * t; + dest[2] = src1[2] + (src2[2] - src1[2]) * t; + dest[3] = src1[3] + (src2[3] - src1[3]) * t; +} + +//----------------------------------------------------------------------------- +// dot, cross +//----------------------------------------------------------------------------- + +inline vec_t DotProduct4D(const Vector4D& a, const Vector4D& b) +{ + Assert( a.IsValid() && b.IsValid() ); + return( a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w ); +} + +// for backwards compatability +inline vec_t Vector4D::Dot( Vector4D const& vOther ) const +{ + return DotProduct4D( *this, vOther ); +} + + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- + +inline vec_t Vector4DLength( Vector4D const& v ) +{ + Assert( v.IsValid() ); + return (vec_t)FastSqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); +} + +inline vec_t Vector4D::LengthSqr(void) const +{ + Assert( IsValid() ); + return (x*x + y*y + z*z + w*w); +} + +inline vec_t Vector4D::Length(void) const +{ + return Vector4DLength( *this ); +} + + +//----------------------------------------------------------------------------- +// Normalization +//----------------------------------------------------------------------------- + +// FIXME: Can't use until we're un-macroed in mathlib.h +inline vec_t Vector4DNormalize( Vector4D& v ) +{ + Assert( v.IsValid() ); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + v.x = v.y = v.z = v.w = 0.0f; + } + return l; +} + +//----------------------------------------------------------------------------- +// Get the distance from this Vector4D to the other one +//----------------------------------------------------------------------------- + +inline vec_t Vector4D::DistTo(const Vector4D &vOther) const +{ + Vector4D delta; + Vector4DSubtract( *this, vOther, delta ); + return delta.Length(); +} + +inline vec_t Vector4D::DistToSqr(const Vector4D &vOther) const +{ + Vector4D delta; + Vector4DSubtract( *this, vOther, delta ); + return delta.LengthSqr(); +} + + +//----------------------------------------------------------------------------- +// Vector4DAligned routines +//----------------------------------------------------------------------------- + +inline Vector4DAligned::Vector4DAligned( vec_t X, vec_t Y, vec_t Z, vec_t W ) +{ + x = X; y = Y; z = Z; w = W; + Assert( IsValid() ); +} + +inline void Vector4DAligned::Set( vec_t X, vec_t Y, vec_t Z, vec_t W ) +{ + x = X; y = Y; z = Z; w = W; + Assert( IsValid() ); +} + +inline void Vector4DAligned::InitZero( void ) +{ +#if !defined( _X360 ) + this->AsM128() = _mm_set1_ps( 0.0f ); +#else + this->AsM128() = __vspltisw( 0 ); +#endif + Assert( IsValid() ); +} + +inline void Vector4DMultiplyAligned( Vector4DAligned const& a, Vector4DAligned const& b, Vector4DAligned& c ) +{ + Assert( a.IsValid() && b.IsValid() ); +#if !defined( _X360 ) + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; + c.w = a.w * b.w; +#else + c.AsM128() = __vmulfp( a.AsM128(), b.AsM128() ); +#endif +} + +inline void Vector4DWeightMAD( vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB ) +{ + Assert( vInA.IsValid() && vInB.IsValid() && IsFinite(w) ); + +#if !defined( _X360 ) + vOutA.x += vInA.x * w; + vOutA.y += vInA.y * w; + vOutA.z += vInA.z * w; + vOutA.w += vInA.w * w; + + vOutB.x += vInB.x * w; + vOutB.y += vInB.y * w; + vOutB.z += vInB.z * w; + vOutB.w += vInB.w * w; +#else + __vector4 temp; + + temp = __lvlx( &w, 0 ); + temp = __vspltw( temp, 0 ); + + vOutA.AsM128() = __vmaddfp( vInA.AsM128(), temp, vOutA.AsM128() ); + vOutB.AsM128() = __vmaddfp( vInB.AsM128(), temp, vOutB.AsM128() ); +#endif +} + +inline void Vector4DWeightMADSSE( vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB ) +{ + Assert( vInA.IsValid() && vInB.IsValid() && IsFinite(w) ); + +#if !defined( _X360 ) + // Replicate scalar float out to 4 components + __m128 packed = _mm_set1_ps( w ); + + // 4D SSE Vector MAD + vOutA.AsM128() = _mm_add_ps( vOutA.AsM128(), _mm_mul_ps( vInA.AsM128(), packed ) ); + vOutB.AsM128() = _mm_add_ps( vOutB.AsM128(), _mm_mul_ps( vInB.AsM128(), packed ) ); +#else + __vector4 temp; + + temp = __lvlx( &w, 0 ); + temp = __vspltw( temp, 0 ); + + vOutA.AsM128() = __vmaddfp( vInA.AsM128(), temp, vOutA.AsM128() ); + vOutB.AsM128() = __vmaddfp( vInB.AsM128(), temp, vOutB.AsM128() ); +#endif +} + +#endif // VECTOR4D_H + diff --git a/public/mathlib/vmatrix.h b/public/mathlib/vmatrix.h new file mode 100644 index 0000000..e49a888 --- /dev/null +++ b/public/mathlib/vmatrix.h @@ -0,0 +1,947 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// VMatrix always postmultiply vectors as in Ax = b. +// Given a set of basis vectors ((F)orward, (L)eft, (U)p), and a (T)ranslation, +// a matrix to transform a vector into that space looks like this: +// Fx Lx Ux Tx +// Fy Ly Uy Ty +// Fz Lz Uz Tz +// 0 0 0 1 + +// Note that concatenating matrices needs to multiply them in reverse order. +// ie: if I want to apply matrix A, B, then C, the equation needs to look like this: +// C * B * A * v +// ie: +// v = A * v; +// v = B * v; +// v = C * v; +//============================================================================= + +#ifndef VMATRIX_H +#define VMATRIX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "mathlib/vector.h" +#include "mathlib/vplane.h" +#include "mathlib/vector4d.h" +#include "mathlib/mathlib.h" + +struct cplane_t; + + +class VMatrix +{ +public: + + VMatrix(); + VMatrix( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33 + ); + + // Creates a matrix where the X axis = forward + // the Y axis = left, and the Z axis = up + VMatrix( const Vector& forward, const Vector& left, const Vector& up ); + VMatrix( const Vector& forward, const Vector& left, const Vector& up, const Vector& translation ); + + // Construct from a 3x4 matrix + VMatrix( const matrix3x4_t& matrix3x4 ); + + // Set the values in the matrix. + void Init( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33 + ); + + + // Initialize from a 3x4 + void Init( const matrix3x4_t& matrix3x4 ); + + // array access + inline float* operator[](int i) + { + return m[i]; + } + + inline const float* operator[](int i) const + { + return m[i]; + } + + // Get a pointer to m[0][0] + inline float *Base() + { + return &m[0][0]; + } + + inline const float *Base() const + { + return &m[0][0]; + } + + void SetLeft(const Vector &vLeft); + void SetUp(const Vector &vUp); + void SetForward(const Vector &vForward); + + void GetBasisVectors(Vector &vForward, Vector &vLeft, Vector &vUp) const; + void SetBasisVectors(const Vector &vForward, const Vector &vLeft, const Vector &vUp); + + // Get/set the translation. + Vector & GetTranslation( Vector &vTrans ) const; + void SetTranslation(const Vector &vTrans); + + void PreTranslate(const Vector &vTrans); + void PostTranslate(const Vector &vTrans); + + const matrix3x4_t& As3x4() const; + void CopyFrom3x4( const matrix3x4_t &m3x4 ); + void Set3x4( matrix3x4_t& matrix3x4 ) const; + + bool operator==( const VMatrix& src ) const; + bool operator!=( const VMatrix& src ) const { return !( *this == src ); } + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // Access the basis vectors. + Vector GetLeft() const; + Vector GetUp() const; + Vector GetForward() const; + Vector GetTranslation() const; +#endif + + +// Matrix->vector operations. +public: + // Multiply by a 3D vector (same as operator*). + void V3Mul(const Vector &vIn, Vector &vOut) const; + + // Multiply by a 4D vector. + void V4Mul(const Vector4D &vIn, Vector4D &vOut) const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // Applies the rotation (ignores translation in the matrix). (This just calls VMul3x3). + Vector ApplyRotation(const Vector &vVec) const; + + // Multiply by a vector (divides by w, assumes input w is 1). + Vector operator*(const Vector &vVec) const; + + // Multiply by the upper 3x3 part of the matrix (ie: only apply rotation). + Vector VMul3x3(const Vector &vVec) const; + + // Apply the inverse (transposed) rotation (only works on pure rotation matrix) + Vector VMul3x3Transpose(const Vector &vVec) const; + + // Multiply by the upper 3 rows. + Vector VMul4x3(const Vector &vVec) const; + + // Apply the inverse (transposed) transformation (only works on pure rotation/translation) + Vector VMul4x3Transpose(const Vector &vVec) const; +#endif + + +// Matrix->plane operations. +public: + // Transform the plane. The matrix can only contain translation and rotation. + void TransformPlane( const VPlane &inPlane, VPlane &outPlane ) const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // Just calls TransformPlane and returns the result. + VPlane operator*(const VPlane &thePlane) const; +#endif + +// Matrix->matrix operations. +public: + + VMatrix& operator=(const VMatrix &mOther); + + // Multiply two matrices (out = this * vm). + void MatrixMul( const VMatrix &vm, VMatrix &out ) const; + + // Add two matrices. + const VMatrix& operator+=(const VMatrix &other); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // Just calls MatrixMul and returns the result. + VMatrix operator*(const VMatrix &mOther) const; + + // Add/Subtract two matrices. + VMatrix operator+(const VMatrix &other) const; + VMatrix operator-(const VMatrix &other) const; + + // Negation. + VMatrix operator-() const; + + // Return inverse matrix. Be careful because the results are undefined + // if the matrix doesn't have an inverse (ie: InverseGeneral returns false). + VMatrix operator~() const; +#endif + +// Matrix operations. +public: + // Set to identity. + void Identity(); + + bool IsIdentity() const; + + // Setup a matrix for origin and angles. + void SetupMatrixOrgAngles( const Vector &origin, const QAngle &vAngles ); + + // Setup a matrix for angles and no translation. + void SetupMatrixAngles( const QAngle &vAngles ); + + // General inverse. This may fail so check the return! + bool InverseGeneral(VMatrix &vInverse) const; + + // Does a fast inverse, assuming the matrix only contains translation and rotation. + void InverseTR( VMatrix &mRet ) const; + + // Usually used for debug checks. Returns true if the upper 3x3 contains + // unit vectors and they are all orthogonal. + bool IsRotationMatrix() const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // This calls the other InverseTR and returns the result. + VMatrix InverseTR() const; + + // Get the scale of the matrix's basis vectors. + Vector GetScale() const; + + // (Fast) multiply by a scaling matrix setup from vScale. + VMatrix Scale(const Vector &vScale); + + // Normalize the basis vectors. + VMatrix NormalizeBasisVectors() const; + + // Transpose. + VMatrix Transpose() const; + + // Transpose upper-left 3x3. + VMatrix Transpose3x3() const; +#endif + +public: + // The matrix. + vec_t m[4][4]; +}; + + + +//----------------------------------------------------------------------------- +// Helper functions. +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +// Setup an identity matrix. +VMatrix SetupMatrixIdentity(); + +// Setup as a scaling matrix. +VMatrix SetupMatrixScale(const Vector &vScale); + +// Setup a translation matrix. +VMatrix SetupMatrixTranslation(const Vector &vTranslation); + +// Setup a matrix to reflect around the plane. +VMatrix SetupMatrixReflection(const VPlane &thePlane); + +// Setup a matrix to project from vOrigin onto thePlane. +VMatrix SetupMatrixProjection(const Vector &vOrigin, const VPlane &thePlane); + +// Setup a matrix to rotate the specified amount around the specified axis. +VMatrix SetupMatrixAxisRot(const Vector &vAxis, vec_t fDegrees); + +// Setup a matrix from euler angles. Just sets identity and calls MatrixAngles. +VMatrix SetupMatrixAngles(const QAngle &vAngles); + +// Setup a matrix for origin and angles. +VMatrix SetupMatrixOrgAngles(const Vector &origin, const QAngle &vAngles); + +#endif + +#define VMatToString(mat) (static_cast(CFmtStr("[ (%f, %f, %f), (%f, %f, %f), (%f, %f, %f), (%f, %f, %f) ]", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3] ))) // ** Note: this generates a temporary, don't hold reference! + +//----------------------------------------------------------------------------- +// Returns the point at the intersection on the 3 planes. +// Returns false if it can't be solved (2 or more planes are parallel). +//----------------------------------------------------------------------------- +bool PlaneIntersection( const VPlane &vp1, const VPlane &vp2, const VPlane &vp3, Vector &vOut ); + + +//----------------------------------------------------------------------------- +// These methods are faster. Use them if you want faster code +//----------------------------------------------------------------------------- +void MatrixSetIdentity( VMatrix &dst ); +void MatrixTranspose( const VMatrix& src, VMatrix& dst ); +void MatrixCopy( const VMatrix& src, VMatrix& dst ); +void MatrixMultiply( const VMatrix& src1, const VMatrix& src2, VMatrix& dst ); + +// Accessors +void MatrixGetColumn( const VMatrix &src, int nCol, Vector *pColumn ); +void MatrixSetColumn( VMatrix &src, int nCol, const Vector &column ); +void MatrixGetRow( const VMatrix &src, int nCol, Vector *pColumn ); +void MatrixSetRow( VMatrix &src, int nCol, const Vector &column ); + +// Vector3DMultiply treats src2 as if it's a direction vector +void Vector3DMultiply( const VMatrix& src1, const Vector& src2, Vector& dst ); + +// Vector3DMultiplyPosition treats src2 as if it's a point (adds the translation) +inline void Vector3DMultiplyPosition( const VMatrix& src1, const VectorByValue src2, Vector& dst ); + +// Vector3DMultiplyPositionProjective treats src2 as if it's a point +// and does the perspective divide at the end +void Vector3DMultiplyPositionProjective( const VMatrix& src1, const Vector &src2, Vector& dst ); + +// Vector3DMultiplyPosition treats src2 as if it's a direction +// and does the perspective divide at the end +// NOTE: src1 had better be an inverse transpose to use this correctly +void Vector3DMultiplyProjective( const VMatrix& src1, const Vector &src2, Vector& dst ); + +void Vector4DMultiply( const VMatrix& src1, const Vector4D& src2, Vector4D& dst ); + +// Same as Vector4DMultiply except that src2 has an implicit W of 1 +void Vector4DMultiplyPosition( const VMatrix& src1, const Vector &src2, Vector4D& dst ); + +// Multiplies the vector by the transpose of the matrix +void Vector3DMultiplyTranspose( const VMatrix& src1, const Vector& src2, Vector& dst ); +void Vector4DMultiplyTranspose( const VMatrix& src1, const Vector4D& src2, Vector4D& dst ); + +// Transform a plane +void MatrixTransformPlane( const VMatrix &src, const cplane_t &inPlane, cplane_t &outPlane ); + +// Transform a plane that has an axis-aligned normal +void MatrixTransformAxisAlignedPlane( const VMatrix &src, int nDim, float flSign, float flDist, cplane_t &outPlane ); + +void MatrixBuildTranslation( VMatrix& dst, float x, float y, float z ); +void MatrixBuildTranslation( VMatrix& dst, const Vector &translation ); + +inline void MatrixTranslate( VMatrix& dst, const Vector &translation ) +{ + VMatrix matTranslation, temp; + MatrixBuildTranslation( matTranslation, translation ); + MatrixMultiply( dst, matTranslation, temp ); + dst = temp; +} + + +void MatrixBuildRotationAboutAxis( VMatrix& dst, const Vector& vAxisOfRot, float angleDegrees ); +void MatrixBuildRotateZ( VMatrix& dst, float angleDegrees ); + +inline void MatrixRotate( VMatrix& dst, const Vector& vAxisOfRot, float angleDegrees ) +{ + VMatrix rotation, temp; + MatrixBuildRotationAboutAxis( rotation, vAxisOfRot, angleDegrees ); + MatrixMultiply( dst, rotation, temp ); + dst = temp; +} + +// Builds a rotation matrix that rotates one direction vector into another +void MatrixBuildRotation( VMatrix &dst, const Vector& initialDirection, const Vector& finalDirection ); + +// Builds a scale matrix +void MatrixBuildScale( VMatrix &dst, float x, float y, float z ); +void MatrixBuildScale( VMatrix &dst, const Vector& scale ); + +// Build a perspective matrix. +// zNear and zFar are assumed to be positive. +// You end up looking down positive Z, X is to the right, Y is up. +// X range: [0..1] +// Y range: [0..1] +// Z range: [0..1] +void MatrixBuildPerspective( VMatrix &dst, float fovX, float fovY, float zNear, float zFar ); + +//----------------------------------------------------------------------------- +// Given a projection matrix, take the extremes of the space in transformed into world space and +// get a bounding box. +//----------------------------------------------------------------------------- +void CalculateAABBFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pMins, Vector *pMaxs ); + +//----------------------------------------------------------------------------- +// Given a projection matrix, take the extremes of the space in transformed into world space and +// get a bounding sphere. +//----------------------------------------------------------------------------- +void CalculateSphereFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pCenter, float *pflRadius ); + +//----------------------------------------------------------------------------- +// Given an inverse projection matrix, take the extremes of the space in transformed into world space and +// get a bounding box. +//----------------------------------------------------------------------------- +void CalculateAABBFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pMins, Vector *pMaxs ); + +//----------------------------------------------------------------------------- +// Given an inverse projection matrix, take the extremes of the space in transformed into world space and +// get a bounding sphere. +//----------------------------------------------------------------------------- +void CalculateSphereFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pCenter, float *pflRadius ); + +//----------------------------------------------------------------------------- +// Calculate frustum planes given a clip->world space transform. +//----------------------------------------------------------------------------- +void FrustumPlanesFromMatrix( const VMatrix &clipToWorld, Frustum_t &frustum ); + +//----------------------------------------------------------------------------- +// Setup a matrix from euler angles. +//----------------------------------------------------------------------------- +void MatrixFromAngles( const QAngle& vAngles, VMatrix& dst ); + +//----------------------------------------------------------------------------- +// Creates euler angles from a matrix +//----------------------------------------------------------------------------- +void MatrixToAngles( const VMatrix& src, QAngle& vAngles ); + +//----------------------------------------------------------------------------- +// Does a fast inverse, assuming the matrix only contains translation and rotation. +//----------------------------------------------------------------------------- +void MatrixInverseTR( const VMatrix& src, VMatrix &dst ); + +//----------------------------------------------------------------------------- +// Inverts any matrix at all +//----------------------------------------------------------------------------- +bool MatrixInverseGeneral(const VMatrix& src, VMatrix& dst); + +//----------------------------------------------------------------------------- +// Computes the inverse transpose +//----------------------------------------------------------------------------- +void MatrixInverseTranspose( const VMatrix& src, VMatrix& dst ); + + + +//----------------------------------------------------------------------------- +// VMatrix inlines. +//----------------------------------------------------------------------------- +inline VMatrix::VMatrix() +{ +} + +inline VMatrix::VMatrix( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33) +{ + Init( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33 + ); +} + + +inline VMatrix::VMatrix( const matrix3x4_t& matrix3x4 ) +{ + Init( matrix3x4 ); +} + + +//----------------------------------------------------------------------------- +// Creates a matrix where the X axis = forward +// the Y axis = left, and the Z axis = up +//----------------------------------------------------------------------------- +inline VMatrix::VMatrix( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis ) +{ + Init( + xAxis.x, yAxis.x, zAxis.x, 0.0f, + xAxis.y, yAxis.y, zAxis.y, 0.0f, + xAxis.z, yAxis.z, zAxis.z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); +} + +inline VMatrix::VMatrix( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector& translation ) +{ + Init( + xAxis.x, yAxis.x, zAxis.x, translation.x, + xAxis.y, yAxis.y, zAxis.y, translation.y, + xAxis.z, yAxis.z, zAxis.z, translation.z, + 0.0f, 0.0f, 0.0f, 1.0f + ); +} + + +inline void VMatrix::Init( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33 + ) +{ + m[0][0] = m00; + m[0][1] = m01; + m[0][2] = m02; + m[0][3] = m03; + + m[1][0] = m10; + m[1][1] = m11; + m[1][2] = m12; + m[1][3] = m13; + + m[2][0] = m20; + m[2][1] = m21; + m[2][2] = m22; + m[2][3] = m23; + + m[3][0] = m30; + m[3][1] = m31; + m[3][2] = m32; + m[3][3] = m33; +} + + +//----------------------------------------------------------------------------- +// Initialize from a 3x4 +//----------------------------------------------------------------------------- +inline void VMatrix::Init( const matrix3x4_t& matrix3x4 ) +{ + memcpy(m, matrix3x4.Base(), sizeof( matrix3x4_t ) ); + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + + +//----------------------------------------------------------------------------- +// Methods related to the basis vectors of the matrix +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::GetForward() const +{ + return Vector(m[0][0], m[1][0], m[2][0]); +} + +inline Vector VMatrix::GetLeft() const +{ + return Vector(m[0][1], m[1][1], m[2][1]); +} + +inline Vector VMatrix::GetUp() const +{ + return Vector(m[0][2], m[1][2], m[2][2]); +} + +#endif + +inline void VMatrix::SetForward(const Vector &vForward) +{ + m[0][0] = vForward.x; + m[1][0] = vForward.y; + m[2][0] = vForward.z; +} + +inline void VMatrix::SetLeft(const Vector &vLeft) +{ + m[0][1] = vLeft.x; + m[1][1] = vLeft.y; + m[2][1] = vLeft.z; +} + +inline void VMatrix::SetUp(const Vector &vUp) +{ + m[0][2] = vUp.x; + m[1][2] = vUp.y; + m[2][2] = vUp.z; +} + +inline void VMatrix::GetBasisVectors(Vector &vForward, Vector &vLeft, Vector &vUp) const +{ + vForward.Init( m[0][0], m[1][0], m[2][0] ); + vLeft.Init( m[0][1], m[1][1], m[2][1] ); + vUp.Init( m[0][2], m[1][2], m[2][2] ); +} + +inline void VMatrix::SetBasisVectors(const Vector &vForward, const Vector &vLeft, const Vector &vUp) +{ + SetForward(vForward); + SetLeft(vLeft); + SetUp(vUp); +} + + +//----------------------------------------------------------------------------- +// Methods related to the translation component of the matrix +//----------------------------------------------------------------------------- +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::GetTranslation() const +{ + return Vector(m[0][3], m[1][3], m[2][3]); +} + +#endif + +inline Vector& VMatrix::GetTranslation( Vector &vTrans ) const +{ + vTrans.x = m[0][3]; + vTrans.y = m[1][3]; + vTrans.z = m[2][3]; + return vTrans; +} + +inline void VMatrix::SetTranslation(const Vector &vTrans) +{ + m[0][3] = vTrans.x; + m[1][3] = vTrans.y; + m[2][3] = vTrans.z; +} + + +//----------------------------------------------------------------------------- +// appply translation to this matrix in the input space +//----------------------------------------------------------------------------- +inline void VMatrix::PreTranslate(const Vector &vTrans) +{ + Vector tmp; + Vector3DMultiplyPosition( *this, vTrans, tmp ); + m[0][3] = tmp.x; + m[1][3] = tmp.y; + m[2][3] = tmp.z; +} + + +//----------------------------------------------------------------------------- +// appply translation to this matrix in the output space +//----------------------------------------------------------------------------- +inline void VMatrix::PostTranslate(const Vector &vTrans) +{ + m[0][3] += vTrans.x; + m[1][3] += vTrans.y; + m[2][3] += vTrans.z; +} + +inline const matrix3x4_t& VMatrix::As3x4() const +{ + return *((const matrix3x4_t*)this); +} + +inline void VMatrix::CopyFrom3x4( const matrix3x4_t &m3x4 ) +{ + memcpy( m, m3x4.Base(), sizeof( matrix3x4_t ) ); + m[3][0] = m[3][1] = m[3][2] = 0; + m[3][3] = 1; +} + +inline void VMatrix::Set3x4( matrix3x4_t& matrix3x4 ) const +{ + memcpy(matrix3x4.Base(), m, sizeof( matrix3x4_t ) ); +} + + +//----------------------------------------------------------------------------- +// Matrix math operations +//----------------------------------------------------------------------------- +inline const VMatrix& VMatrix::operator+=(const VMatrix &other) +{ + for(int i=0; i < 4; i++) + { + for(int j=0; j < 4; j++) + { + m[i][j] += other.m[i][j]; + } + } + + return *this; +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline VMatrix VMatrix::operator+(const VMatrix &other) const +{ + VMatrix ret; + for(int i=0; i < 16; i++) + { + ((float*)ret.m)[i] = ((float*)m)[i] + ((float*)other.m)[i]; + } + return ret; +} + +inline VMatrix VMatrix::operator-(const VMatrix &other) const +{ + VMatrix ret; + + for(int i=0; i < 4; i++) + { + for(int j=0; j < 4; j++) + { + ret.m[i][j] = m[i][j] - other.m[i][j]; + } + } + + return ret; +} + +inline VMatrix VMatrix::operator-() const +{ + VMatrix ret; + for( int i=0; i < 16; i++ ) + { + ((float*)ret.m)[i] = ((float*)m)[i]; + } + return ret; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +//----------------------------------------------------------------------------- +// Vector transformation +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::operator*(const Vector &vVec) const +{ + Vector vRet; + vRet.x = m[0][0]*vVec.x + m[0][1]*vVec.y + m[0][2]*vVec.z + m[0][3]; + vRet.y = m[1][0]*vVec.x + m[1][1]*vVec.y + m[1][2]*vVec.z + m[1][3]; + vRet.z = m[2][0]*vVec.x + m[2][1]*vVec.y + m[2][2]*vVec.z + m[2][3]; + + return vRet; +} + +inline Vector VMatrix::VMul4x3(const Vector &vVec) const +{ + Vector vResult; + Vector3DMultiplyPosition( *this, vVec, vResult ); + return vResult; +} + + +inline Vector VMatrix::VMul4x3Transpose(const Vector &vVec) const +{ + Vector tmp = vVec; + tmp.x -= m[0][3]; + tmp.y -= m[1][3]; + tmp.z -= m[2][3]; + + return Vector( + m[0][0]*tmp.x + m[1][0]*tmp.y + m[2][0]*tmp.z, + m[0][1]*tmp.x + m[1][1]*tmp.y + m[2][1]*tmp.z, + m[0][2]*tmp.x + m[1][2]*tmp.y + m[2][2]*tmp.z + ); +} + +inline Vector VMatrix::VMul3x3(const Vector &vVec) const +{ + return Vector( + m[0][0]*vVec.x + m[0][1]*vVec.y + m[0][2]*vVec.z, + m[1][0]*vVec.x + m[1][1]*vVec.y + m[1][2]*vVec.z, + m[2][0]*vVec.x + m[2][1]*vVec.y + m[2][2]*vVec.z + ); +} + +inline Vector VMatrix::VMul3x3Transpose(const Vector &vVec) const +{ + return Vector( + m[0][0]*vVec.x + m[1][0]*vVec.y + m[2][0]*vVec.z, + m[0][1]*vVec.x + m[1][1]*vVec.y + m[2][1]*vVec.z, + m[0][2]*vVec.x + m[1][2]*vVec.y + m[2][2]*vVec.z + ); +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +inline void VMatrix::V3Mul(const Vector &vIn, Vector &vOut) const +{ + vec_t rw; + + rw = 1.0f / (m[3][0]*vIn.x + m[3][1]*vIn.y + m[3][2]*vIn.z + m[3][3]); + vOut.x = (m[0][0]*vIn.x + m[0][1]*vIn.y + m[0][2]*vIn.z + m[0][3]) * rw; + vOut.y = (m[1][0]*vIn.x + m[1][1]*vIn.y + m[1][2]*vIn.z + m[1][3]) * rw; + vOut.z = (m[2][0]*vIn.x + m[2][1]*vIn.y + m[2][2]*vIn.z + m[2][3]) * rw; +} + +inline void VMatrix::V4Mul(const Vector4D &vIn, Vector4D &vOut) const +{ + vOut[0] = m[0][0]*vIn[0] + m[0][1]*vIn[1] + m[0][2]*vIn[2] + m[0][3]*vIn[3]; + vOut[1] = m[1][0]*vIn[0] + m[1][1]*vIn[1] + m[1][2]*vIn[2] + m[1][3]*vIn[3]; + vOut[2] = m[2][0]*vIn[0] + m[2][1]*vIn[1] + m[2][2]*vIn[2] + m[2][3]*vIn[3]; + vOut[3] = m[3][0]*vIn[0] + m[3][1]*vIn[1] + m[3][2]*vIn[2] + m[3][3]*vIn[3]; +} + + +//----------------------------------------------------------------------------- +// Plane transformation +//----------------------------------------------------------------------------- +inline void VMatrix::TransformPlane( const VPlane &inPlane, VPlane &outPlane ) const +{ + Vector vTrans; + Vector3DMultiply( *this, inPlane.m_Normal, outPlane.m_Normal ); + outPlane.m_Dist = inPlane.m_Dist * DotProduct( outPlane.m_Normal, outPlane.m_Normal ); + outPlane.m_Dist += DotProduct( outPlane.m_Normal, GetTranslation( vTrans ) ); +} + + +//----------------------------------------------------------------------------- +// Other random stuff +//----------------------------------------------------------------------------- +inline void VMatrix::Identity() +{ + MatrixSetIdentity( *this ); +} + + +inline bool VMatrix::IsIdentity() const +{ + return + m[0][0] == 1.0f && m[0][1] == 0.0f && m[0][2] == 0.0f && m[0][3] == 0.0f && + m[1][0] == 0.0f && m[1][1] == 1.0f && m[1][2] == 0.0f && m[1][3] == 0.0f && + m[2][0] == 0.0f && m[2][1] == 0.0f && m[2][2] == 1.0f && m[2][3] == 0.0f && + m[3][0] == 0.0f && m[3][1] == 0.0f && m[3][2] == 0.0f && m[3][3] == 1.0f; +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::ApplyRotation(const Vector &vVec) const +{ + return VMul3x3(vVec); +} + +inline VMatrix VMatrix::operator~() const +{ + VMatrix mRet; + InverseGeneral(mRet); + return mRet; +} + +#endif + + +//----------------------------------------------------------------------------- +// Accessors +//----------------------------------------------------------------------------- +inline void MatrixGetColumn( const VMatrix &src, int nCol, Vector *pColumn ) +{ + Assert( (nCol >= 0) && (nCol <= 3) ); + + pColumn->x = src[0][nCol]; + pColumn->y = src[1][nCol]; + pColumn->z = src[2][nCol]; +} + +inline void MatrixSetColumn( VMatrix &src, int nCol, const Vector &column ) +{ + Assert( (nCol >= 0) && (nCol <= 3) ); + + src.m[0][nCol] = column.x; + src.m[1][nCol] = column.y; + src.m[2][nCol] = column.z; +} + +inline void MatrixGetRow( const VMatrix &src, int nRow, Vector *pRow ) +{ + Assert( (nRow >= 0) && (nRow <= 3) ); + *pRow = *(Vector*)src[nRow]; +} + +inline void MatrixSetRow( VMatrix &dst, int nRow, const Vector &row ) +{ + Assert( (nRow >= 0) && (nRow <= 3) ); + *(Vector*)dst[nRow] = row; +} + + +//----------------------------------------------------------------------------- +// Vector3DMultiplyPosition treats src2 as if it's a point (adds the translation) +//----------------------------------------------------------------------------- +// NJS: src2 is passed in as a full vector rather than a reference to prevent the need +// for 2 branches and a potential copy in the body. (ie, handling the case when the src2 +// reference is the same as the dst reference ). +inline void Vector3DMultiplyPosition( const VMatrix& src1, const VectorByValue src2, Vector& dst ) +{ + dst[0] = src1[0][0] * src2.x + src1[0][1] * src2.y + src1[0][2] * src2.z + src1[0][3]; + dst[1] = src1[1][0] * src2.x + src1[1][1] * src2.y + src1[1][2] * src2.z + src1[1][3]; + dst[2] = src1[2][0] * src2.x + src1[2][1] * src2.y + src1[2][2] * src2.z + src1[2][3]; +} + + +//----------------------------------------------------------------------------- +// Transform a plane that has an axis-aligned normal +//----------------------------------------------------------------------------- +inline void MatrixTransformAxisAlignedPlane( const VMatrix &src, int nDim, float flSign, float flDist, cplane_t &outPlane ) +{ + // See MatrixTransformPlane in the .cpp file for an explanation of the algorithm. + MatrixGetColumn( src, nDim, &outPlane.normal ); + outPlane.normal *= flSign; + outPlane.dist = flDist * DotProduct( outPlane.normal, outPlane.normal ); + + // NOTE: Writing this out by hand because it doesn't inline (inline depth isn't large enough) + // This should read outPlane.dist += DotProduct( outPlane.normal, src.GetTranslation ); + outPlane.dist += outPlane.normal.x * src.m[0][3] + outPlane.normal.y * src.m[1][3] + outPlane.normal.z * src.m[2][3]; +} + + +//----------------------------------------------------------------------------- +// Matrix equality test +//----------------------------------------------------------------------------- +inline bool MatricesAreEqual( const VMatrix &src1, const VMatrix &src2, float flTolerance ) +{ + for ( int i = 0; i < 3; ++i ) + { + for ( int j = 0; j < 3; ++j ) + { + if ( fabs( src1[i][j] - src2[i][j] ) > flTolerance ) + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void MatrixBuildOrtho( VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar ); +void MatrixBuildPerspectiveX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar ); +void MatrixBuildPerspectiveOffCenterX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right ); +void MatrixBuildPerspectiveZRange( VMatrix& dst, double flZNear, double flZFar ); + +inline void MatrixOrtho( VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar ) +{ + VMatrix mat; + MatrixBuildOrtho( mat, left, top, right, bottom, zNear, zFar ); + + VMatrix temp; + MatrixMultiply( dst, mat, temp ); + dst = temp; +} + +inline void MatrixPerspectiveX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar ) +{ + VMatrix mat; + MatrixBuildPerspectiveX( mat, flFovX, flAspect, flZNear, flZFar ); + + VMatrix temp; + MatrixMultiply( dst, mat, temp ); + dst = temp; +} + +inline void MatrixPerspectiveOffCenterX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right ) +{ + VMatrix mat; + MatrixBuildPerspectiveOffCenterX( mat, flFovX, flAspect, flZNear, flZFar, bottom, top, left, right ); + + VMatrix temp; + MatrixMultiply( dst, mat, temp ); + dst = temp; +} + +#endif + + diff --git a/public/mathlib/vplane.h b/public/mathlib/vplane.h new file mode 100644 index 0000000..dd3d4a9 --- /dev/null +++ b/public/mathlib/vplane.h @@ -0,0 +1,182 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPLANE_H +#define VPLANE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" + +typedef int SideType; + +// Used to represent sides of things like planes. +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + +#define VP_EPSILON 0.01f + + +class VPlane +{ +public: + VPlane(); + VPlane(const Vector &vNormal, vec_t dist); + + void Init(const Vector &vNormal, vec_t dist); + + // Return the distance from the point to the plane. + vec_t DistTo(const Vector &vVec) const; + + // Copy. + VPlane& operator=(const VPlane &thePlane); + + // Returns SIDE_ON, SIDE_FRONT, or SIDE_BACK. + // The epsilon for SIDE_ON can be passed in. + SideType GetPointSide(const Vector &vPoint, vec_t sideEpsilon=VP_EPSILON) const; + + // Returns SIDE_FRONT or SIDE_BACK. + SideType GetPointSideExact(const Vector &vPoint) const; + + // Classify the box with respect to the plane. + // Returns SIDE_ON, SIDE_FRONT, or SIDE_BACK + SideType BoxOnPlaneSide(const Vector &vMin, const Vector &vMax) const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // Flip the plane. + VPlane Flip(); + + // Get a point on the plane (normal*dist). + Vector GetPointOnPlane() const; + + // Snap the specified point to the plane (along the plane's normal). + Vector SnapPointToPlane(const Vector &vPoint) const; +#endif + +public: + Vector m_Normal; + vec_t m_Dist; + +#ifdef VECTOR_NO_SLOW_OPERATIONS +private: + // No copy constructors allowed if we're in optimal mode + VPlane(const VPlane& vOther); +#endif +}; + + +//----------------------------------------------------------------------------- +// Inlines. +//----------------------------------------------------------------------------- +inline VPlane::VPlane() +{ +} + +inline VPlane::VPlane(const Vector &vNormal, vec_t dist) +{ + m_Normal = vNormal; + m_Dist = dist; +} + +inline void VPlane::Init(const Vector &vNormal, vec_t dist) +{ + m_Normal = vNormal; + m_Dist = dist; +} + +inline vec_t VPlane::DistTo(const Vector &vVec) const +{ + return vVec.Dot(m_Normal) - m_Dist; +} + +inline VPlane& VPlane::operator=(const VPlane &thePlane) +{ + m_Normal = thePlane.m_Normal; + m_Dist = thePlane.m_Dist; + return *this; +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline VPlane VPlane::Flip() +{ + return VPlane(-m_Normal, -m_Dist); +} + +inline Vector VPlane::GetPointOnPlane() const +{ + return m_Normal * m_Dist; +} + +inline Vector VPlane::SnapPointToPlane(const Vector &vPoint) const +{ + return vPoint - m_Normal * DistTo(vPoint); +} + +#endif + +inline SideType VPlane::GetPointSide(const Vector &vPoint, vec_t sideEpsilon) const +{ + vec_t fDist; + + fDist = DistTo(vPoint); + if(fDist >= sideEpsilon) + return SIDE_FRONT; + else if(fDist <= -sideEpsilon) + return SIDE_BACK; + else + return SIDE_ON; +} + +inline SideType VPlane::GetPointSideExact(const Vector &vPoint) const +{ + return DistTo(vPoint) > 0.0f ? SIDE_FRONT : SIDE_BACK; +} + + +// BUGBUG: This should either simply use the implementation in mathlib or cease to exist. +// mathlib implementation is much more efficient. Check to see that VPlane isn't used in +// performance critical code. +inline SideType VPlane::BoxOnPlaneSide(const Vector &vMin, const Vector &vMax) const +{ + int i, firstSide, side; + TableVector vPoints[8] = + { + { vMin.x, vMin.y, vMin.z }, + { vMin.x, vMin.y, vMax.z }, + { vMin.x, vMax.y, vMax.z }, + { vMin.x, vMax.y, vMin.z }, + + { vMax.x, vMin.y, vMin.z }, + { vMax.x, vMin.y, vMax.z }, + { vMax.x, vMax.y, vMax.z }, + { vMax.x, vMax.y, vMin.z }, + }; + + firstSide = GetPointSideExact(vPoints[0]); + for(i=1; i < 8; i++) + { + side = GetPointSideExact(vPoints[i]); + + // Does the box cross the plane? + if(side != firstSide) + return SIDE_ON; + } + + // Ok, they're all on the same side, return that. + return firstSide; +} + + + + +#endif // VPLANE_H diff --git a/public/matsys_controls/QCGenerator.h b/public/matsys_controls/QCGenerator.h new file mode 100644 index 0000000..d6b69d2 --- /dev/null +++ b/public/matsys_controls/QCGenerator.h @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef QCGENERATOR_H +#define QCGENERATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/Frame.h" +#include "vgui_controls/Button.h" +#include "tier1/utlstring.h" +#include "vgui_controls/TextEntry.h" + +class CQCGenerator; + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class Panel; +} + +class CBrowseButton : public vgui::Button +{ + DECLARE_CLASS_SIMPLE( CBrowseButton, vgui::Button ); + +public: + CBrowseButton( vgui::Panel *pParent ); + ~CBrowseButton(); + void InitBrowseInfo( int x, int y, const char *pszName, const char *pszDir, const char *pszFilter, const char *pszField ); + +private: + char *pszStartingDirectory; + char *pszFileFilter; + char *pszTargetField; + + char **GetStartingDirectory(){ return &pszStartingDirectory; } + char **GetFileFilter(){ return &pszFileFilter; } + char **GetTargetField(){ return &pszTargetField; } + void SetCharVar( char **pVar, const char *pszNewText ); + void SetActionMessage(); +}; + +struct LODInfo +{ + char pszFilename[MAX_PATH]; + int iLOD; +}; + +struct QCInfo +{ + CQCGenerator *pQCGenerator; + + char pszSMDPath[MAX_PATH]; + char pszCollisionPath[MAX_PATH]; + char pszSurfaceProperty[MAX_PATH]; + char pszMaterialPath[MAX_PATH]; + char pszSceneName[MAX_PATH]; + + bool bStaticProp; + bool bMostlyOpaque; + bool bDisableCollision; + bool bReferenceAsPhys; + bool bConcave; + bool bAutomass; + bool bNoAnimation; + + CUtlVector LODs; + + float fScale; + float fMass; + void Init( CQCGenerator *pPanel ) + { + pQCGenerator = pPanel; + + V_strcpy_safe( pszSMDPath, "" ); + V_strcpy_safe( pszCollisionPath, "" ); + V_strcpy_safe( pszSurfaceProperty, "default" ); + bStaticProp = false; + bMostlyOpaque = false; + bDisableCollision = false; + bReferenceAsPhys = false; + bConcave = false; + bAutomass = false; + bNoAnimation = true; + + fScale = 1.0; + fMass = 10.0; + } + void SyncToControls(); + void SyncFromControls(); +}; + +//----------------------------------------------------------------------------- +// Purpose: Base class for generating QC files +//----------------------------------------------------------------------------- +class CQCGenerator : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CQCGenerator, vgui::EditablePanel ); + +public: + CQCGenerator( vgui::Panel *pParent, const char *pszPath, const char *pszScene ); + ~CQCGenerator(); + + // overridden frame functions +// virtual void Activate(); + + virtual void OnCommand( const char *command ); + + // Purpose: +// virtual void OnKeyCodeTyped( vgui::KeyCode code ); + + MESSAGE_FUNC( OnNewLODText, "TextNewLine" ); + MESSAGE_FUNC_PARAMS( OnBrowse, "browse", data ); + MESSAGE_FUNC_PARAMS( OnFileSelected, "FileSelected", data ); + MESSAGE_FUNC_PARAMS( OnDirectorySelected, "DirectorySelected", data ); + + bool GenerateQCFile(); +// void BrowseDirectory( KeyValues *data ); + void BrowseFile( KeyValues *data ); + + void DeleteLOD( ); + void EditLOD(); + virtual void OnKeyCodeTyped( vgui::KeyCode code); + void InitializeSMDPaths( const char *pszPath, const char *pszScene ); + +protected: + // Creates standard controls. Allows the derived class to + // add these controls to various splitter windows + void CreateStandardControls( vgui::Panel *pParent ); + +private: + + CBrowseButton *m_pCollisionBrowseButton; + char m_szTargetField[MAX_PATH]; + vgui::ListPanel *m_pLODPanel; + + vgui::TextEntry *m_pLODEdit; + + int m_nSelectedSequence; + int m_nSelectedColumn; + + QCInfo m_QCInfo_t; +}; + + + + +#endif // QCGENERATOR_H diff --git a/public/matsys_controls/assetpicker.h b/public/matsys_controls/assetpicker.h new file mode 100644 index 0000000..967fd2b --- /dev/null +++ b/public/matsys_controls/assetpicker.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ASSETPICKER_H +#define ASSETPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "matsys_controls/baseassetpicker.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class Panel; +} + + +//----------------------------------------------------------------------------- +// Purpose: Base class for choosing raw assets +//----------------------------------------------------------------------------- +class CAssetPicker : public CBaseAssetPicker +{ + DECLARE_CLASS_SIMPLE( CAssetPicker, CBaseAssetPicker ); + +public: + CAssetPicker( vgui::Panel *pParent, const char *pAssetType, + const char *pExt, const char *pSubDir, const char *pTextType ); +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for asset picker +//----------------------------------------------------------------------------- +class CAssetPickerFrame : public CBaseAssetPickerFrame +{ + DECLARE_CLASS_SIMPLE( CAssetPickerFrame, CBaseAssetPickerFrame ); + +public: + CAssetPickerFrame( vgui::Panel *pParent, const char *pTitle, + const char *pAssetType, const char *pExt, const char *pSubDir, const char *pTextType ); +}; + + +#endif // ASSETPICKER_H diff --git a/public/matsys_controls/baseassetpicker.h b/public/matsys_controls/baseassetpicker.h new file mode 100644 index 0000000..31cdcc9 --- /dev/null +++ b/public/matsys_controls/baseassetpicker.h @@ -0,0 +1,195 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef BASEASSETPICKER_H +#define BASEASSETPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/Frame.h" +#include "tier1/utlstring.h" +#include "tier1/utllinkedlist.h" +#include "filesystem.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CAssetTreeView; +namespace vgui +{ + class Panel; +} +FORWARD_DECLARE_HANDLE( AssetList_t ); + +typedef unsigned short DirHandle_t; + + +//----------------------------------------------------------------------------- +// Purpose: Base class for choosing raw assets +//----------------------------------------------------------------------------- +class CBaseAssetPicker : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CBaseAssetPicker, vgui::EditablePanel ); + +public: + CBaseAssetPicker( vgui::Panel *pParent, const char *pAssetType, + const char *pExt, const char *pSubDir, const char *pTextType ); + ~CBaseAssetPicker(); + + // overridden frame functions + virtual void OnTick(); + virtual bool HasUserConfigSettings(); + virtual void ApplyUserConfigSettings( KeyValues *pUserConfig ); + virtual void GetUserConfigSettings( KeyValues *pUserConfig ); + virtual void OnCommand( const char *pCommand ); + + // Purpose: + virtual void OnKeyCodePressed( vgui::KeyCode code ); + + // Returns the selected asset name + int GetSelectedAssetCount(); + const char *GetSelectedAsset( int nAssetIndex = -1 ); + + // Is multiselect enabled? + bool IsMultiselectEnabled() const; + + // Sets the initial selected asset + void SetInitialSelection( const char *pAssetName ); + + // Set/get the filter + void SetFilter( const char *pFilter ); + const char *GetFilter(); + + // Purpose: refreshes the file tree + void RefreshFileTree(); + + virtual void Activate(); + +protected: + // Creates standard controls. Allows the derived class to + // add these controls to various splitter windows + void CreateStandardControls( vgui::Panel *pParent, bool bAllowMultiselect = false ); + + // Allows the picker to browse multiple asset types + void AddExtension( const char *pExtension ); + + // Derived classes have this called when the previewed asset changes + virtual void OnSelectedAssetPicked( const char *pAssetName ) {} + + // Derived classes have this called when the next selected asset is selected by default + virtual void OnNextSelectionIsDefault() {} + + // Request focus of the filter box + void RequestFilterFocus(); + + // Rescan assets + void RescanAssets(); + + const char *GetModPath( int nModIndex ); + + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv ); + MESSAGE_FUNC_PARAMS( OnItemSelected, "ItemSelected", kv ); + MESSAGE_FUNC_PARAMS( OnCheckButtonChecked, "CheckButtonChecked", kv ); + MESSAGE_FUNC( OnFileSelected, "TreeViewItemSelected" ); + +protected: + struct AssetInfo_t + { + int m_nAssetIndex; + int m_nItemId; + }; + + void BuildAssetNameList(); + void RefreshAssetList( ); + int GetSelectedAssetModIndex( ); + + // Is a particular asset visible? + bool IsAssetVisible( int nAssetIndex ); + + // Recursively add all files matching the wildcard under this directory + void AddAssetToList( int nAssetIndex ); + + // Update column headers + void UpdateAssetColumnHeader( ); + + vgui::Splitter *m_pAssetSplitter; + CAssetTreeView* m_pFileTree; + vgui::CheckButton* m_pSubDirCheck; + vgui::TextEntry *m_pFilter; + vgui::ListPanel *m_pAssetBrowser; + vgui::TextEntry *m_pFullPath; + vgui::ComboBox *m_pModSelector; + vgui::Button *m_pRescanButton; + + AssetList_t m_hAssetList; + CUtlString m_FolderFilter; + CUtlString m_Filter; + CUtlString m_SelectedAsset; + CUtlVector< AssetInfo_t > m_AssetList; + const char *m_pAssetType; + const char *m_pAssetTextType; + const char *m_pAssetExt; + const char *m_pAssetSubDir; + CUtlVector< const char * > m_ExtraAssetExt; + bool m_bBuiltAssetList : 1; + bool m_bFirstAssetScan : 1; + bool m_bFinishedAssetListScan : 1; + int m_nCurrentModFilter; + int m_nMatchingAssets; + bool m_bSubDirCheck; + + friend class CBaseAssetPickerFrame; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for asset picker +//----------------------------------------------------------------------------- +class CBaseAssetPickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CBaseAssetPickerFrame, vgui::Frame ); + +public: + CBaseAssetPickerFrame( vgui::Panel *pParent ); + ~CBaseAssetPickerFrame(); + + // Inherited from Frame + virtual void OnCommand( const char *pCommand ); + + // Purpose: Activate the dialog + // The message "AssetSelected" will be sent if an asset is picked + // Pass in optional keyvalues to add to the message + void DoModal( KeyValues *pContextKeyValues = NULL ); + + // Sets the initial selected asset + void SetInitialSelection( const char *pAssetName ); + + // Set/get the filter + void SetFilter( const char *pFilter ); + const char *GetFilter(); + +protected: + // Allows the derived class to create the picker + void SetAssetPicker( CBaseAssetPicker* pPicker ); + CBaseAssetPicker* GetAssetPicker() { return m_pPicker; } + + // Posts a message (passing the key values) + void PostMessageAndClose( KeyValues *pKeyValues ); + +private: + void CleanUpMessage(); + + CBaseAssetPicker *m_pPicker; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + KeyValues *m_pContextKeyValues; +}; + + +#endif // BASEASSETPICKER_H diff --git a/public/matsys_controls/colorpickerpanel.h b/public/matsys_controls/colorpickerpanel.h new file mode 100644 index 0000000..6b79b17 --- /dev/null +++ b/public/matsys_controls/colorpickerpanel.h @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef COLORPICKERPANEL_H +#define COLORPICKERPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/Frame.h" +#include "vgui_controls/Button.h" +#include "bitmap/imageformat.h" +#include "mathlib/vector.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CColorXYPreview; +class CColorZPreview; + +namespace vgui +{ + class RadioButton; + class TextEntry; + class IScheme; +} + + +//----------------------------------------------------------------------------- +// +// Color picker panel +// +//----------------------------------------------------------------------------- +class CColorPickerPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CColorPickerPanel, vgui::EditablePanel ); + +public: + // constructor + CColorPickerPanel( vgui::Panel *pParent, const char *pName ); + void SetInitialColor( Color initialColor ); + void GetCurrentColor( Color *pColor ); + void GetInitialColor( Color *pColor ); + + // Inherited from Panel + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnMousePressed( vgui::MouseCode code ); + +private: + MESSAGE_FUNC_PARAMS( OnRadioButtonChecked, "RadioButtonChecked", kv ); + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + MESSAGE_FUNC_PARAMS( OnHSVSelected, "HSVSelected", data ); + MESSAGE_FUNC_PARAMS( OnColorSelected, "ColorSelected", data ); + + // Called when the color changes + void OnColorChanged( vgui::TextEntry *pChanged = NULL ); + + // Updates the preview colors + void UpdatePreviewColors(); + + CColorXYPreview *m_pColorXYPreview; + CColorZPreview *m_pColorZPreview; + vgui::RadioButton* m_pHueRadio; + vgui::RadioButton* m_pSaturationRadio; + vgui::RadioButton* m_pValueRadio; + vgui::RadioButton* m_pRedRadio; + vgui::RadioButton* m_pGreenRadio; + vgui::RadioButton* m_pBlueRadio; + vgui::TextEntry* m_pHueText; + vgui::TextEntry* m_pSaturationText; + vgui::TextEntry* m_pValueText; + vgui::TextEntry* m_pRedText; + vgui::TextEntry* m_pGreenText; + vgui::TextEntry* m_pBlueText; + vgui::Panel* m_pInitialColor; + vgui::Panel* m_pCurrentColor; + vgui::TextEntry* m_pAlphaText; + + RGB888_t m_InitialColor; + RGB888_t m_CurrentColor; + unsigned char m_InitialAlpha; + unsigned char m_CurrentAlpha; + Vector m_CurrentHSVColor; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for picker +//----------------------------------------------------------------------------- +class CColorPickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CColorPickerFrame, vgui::Frame ); + +public: + CColorPickerFrame( vgui::Panel *pParent, const char *pTitle ); + ~CColorPickerFrame(); + + // Inherited from Frame + virtual void OnCommand( const char *pCommand ); + + // Purpose: Activate the dialog + // If a color is picked, the message 'ColorPickerPicked' is sent with the "color" field set to the color + // If cancel is hit, the message 'ColorPickerCancel' is sent + // If the color is changed in the preview, the message 'ColorPickerPreview' is sent with the "color" field set to the color + void DoModal( Color initialColor, KeyValues *pContextKeys = NULL ); + + // Gets the initial color + void GetInitialColor( Color *pColor ); + +private: + void CleanUpMessage(); + + CColorPickerPanel *m_pPicker; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + KeyValues *m_pContextKeys; +}; + + +//----------------------------------------------------------------------------- +// Purpose: A button which brings up the color picker +//----------------------------------------------------------------------------- +class CColorPickerButton : public vgui::Button +{ + DECLARE_CLASS_SIMPLE( CColorPickerButton, vgui::Button ); + + /* + NOTE: Sends ColorPickerPicked message when a color is picked + color - picked color + Sends ColorPickerPreview message when a color is previewed + color - current preview color + Sends ColorPickerCancelled message when the cancel button was hit + startingColor - color before the picking occurred + */ + +public: + CColorPickerButton( vgui::Panel *pParent, const char *pName, vgui::Panel *pActionSignalTarget = NULL ); + ~CColorPickerButton(); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void DoClick(); + + void SetColor( const Color& clr ); + void SetColor( int r, int g, int b, int a ); + Color GetColor( void ) { return m_CurrentColor; } + +private: + MESSAGE_FUNC_PARAMS( OnPicked, "ColorPickerPicked", data ); + MESSAGE_FUNC_PARAMS( OnPreview, "ColorPickerPreview", data ); + MESSAGE_FUNC( OnCancelled, "ColorPickerCancel" ); + + void UpdateButtonColor(); + Color m_CurrentColor; +}; + +#endif // COLORPICKERPANEL_H \ No newline at end of file diff --git a/public/matsys_controls/curveeditorpanel.h b/public/matsys_controls/curveeditorpanel.h new file mode 100644 index 0000000..fb76369 --- /dev/null +++ b/public/matsys_controls/curveeditorpanel.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef CURVEEDITORPANEL_H +#define CURVEEDITORPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_controls/Panel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct BGRA8888_t; + + +//----------------------------------------------------------------------------- +// +// Curve editor image panel +// +//----------------------------------------------------------------------------- +class CCurveEditorPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CCurveEditorPanel, vgui::Panel ); + +public: + // constructor + CCurveEditorPanel( vgui::Panel *pParent, const char *pName ); + ~CCurveEditorPanel(); + + virtual void Paint( void ); + virtual void PaintBackground( void ); + + virtual void OnCursorMoved( int x,int y ); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + virtual void OnKeyCodePressed( vgui::KeyCode code ); + +protected: + // Control points + values... + virtual int FindOrAddControlPoint( float flIn, float flTolerance, float flOut ) = 0; + virtual int FindControlPoint( float flIn, float flTolerance ) = 0; + virtual int ModifyControlPoint( int nPoint, float flIn, float flOut ) = 0; + virtual void RemoveControlPoint( int nPoint ) = 0; + virtual float GetValue( float flIn ) = 0; + virtual int ControlPointCount() = 0; + virtual void GetControlPoint( int nPoint, float *pIn, float *pOut ) = 0; + +private: + // Converts screen location to normalized values and back + void ScreenToValue( int x, int y, float *pIn, float *pOut ); + void ValueToScreen( float flIn, float flOut, int *x, int *y ); + + int m_nSelectedPoint; + int m_nHighlightedPoint; // Used when not selecting +}; + + + +#endif // CURVEEDITORPANEL_H diff --git a/public/matsys_controls/gamefiletreeview.h b/public/matsys_controls/gamefiletreeview.h new file mode 100644 index 0000000..a9563ce --- /dev/null +++ b/public/matsys_controls/gamefiletreeview.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef GAMEFILETREEVIEW_H +#define GAMEFILETREEVIEW_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/utlstring.h" +#include "vgui_controls/TreeView.h" +#include "vgui_controls/ImageList.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class IScheme; +} + + +//----------------------------------------------------------------------------- +// Purpose: Handles file view for game files +//----------------------------------------------------------------------------- +class CGameFileTreeView : public vgui::TreeView +{ + DECLARE_CLASS_SIMPLE( CGameFileTreeView, vgui::TreeView ); + +public: + CGameFileTreeView( vgui::Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir, const char *pExtension = NULL ); + + // Inherited from base classes + virtual void GenerateChildrenOfNode( int itemIndex ); + virtual void GenerateContextMenu( int itemIndex, int x, int y ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + // Purpose: Refreshes the active file list + void RefreshFileList(); + + // Sets an item to be colored as if its a menu + void SetItemColorForDirectories( int itemID ); + + // Gets the number of root directories + int GetRootDirectoryCount(); + + // Gets the ith root directory + const char *GetRootDirectory( int nIndex ); + + // Selects the root folder + void SelectRoot(); + +private: + // Populate the root node (necessary since tree view can't have multiple roots) + void PopulateRootNode( int itemIndex ); + + // Populate the root node with directories + void AddDirectoriesOfNode( int itemIndex, const char *pFilePath ); + + // Populate the root node with directories + bool DoesDirectoryHaveSubdirectories( const char *pFilePath ); + + // Populate the root node with files + void AddFilesOfNode( int itemIndex, const char *pFilePath, const char *pExt ); + + CUtlString m_RootDir; + CUtlString m_Ext; + CUtlString m_RootFolderName; + vgui::ImageList m_Images; + bool m_bUseExt; // To differentiate "" from NULL in m_Ext +}; + + +#endif // GAMEFILETREEVIEW_H + diff --git a/public/matsys_controls/manipulator.h b/public/matsys_controls/manipulator.h new file mode 100644 index 0000000..f030509 --- /dev/null +++ b/public/matsys_controls/manipulator.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef MANIPULATOR_H +#define MANIPULATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Panel.h" +#include "mathlib/vector.h" + +//----------------------------------------------------------------------------- +// Manipulator interface +//----------------------------------------------------------------------------- +class IManipulator +{ +public: + virtual ~IManipulator(){} + virtual void OnBeginManipulation( void ) = 0; + virtual void OnAcceptManipulation( void ) = 0; + virtual void OnCancelManipulation( void ) = 0; + + virtual void OnTick( void ) = 0; + + virtual void OnCursorMoved( int x, int y ) = 0; + virtual void OnMousePressed( vgui::MouseCode code, int x, int y ) = 0; + virtual void OnMouseReleased( vgui::MouseCode code, int x, int y ) = 0; + virtual void OnMouseWheeled( int delta ) = 0; + + virtual void SetViewportSize( int w, int h ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Base class helper for implementing manipulators +//----------------------------------------------------------------------------- +class CBaseManipulator : public IManipulator +{ +public: + CBaseManipulator() + { + m_nViewport[ 0 ] = m_nViewport[ 1 ] = 0; + } + + virtual void OnTick( void ) {}; + + virtual void OnBeginManipulation( void ) {} + virtual void OnAcceptManipulation( void ) {}; + virtual void OnCancelManipulation( void ) {}; + + virtual void OnCursorMoved( int x, int y ) {}; + virtual void OnMousePressed( vgui::MouseCode code, int x, int y ) {}; + virtual void OnMouseReleased( vgui::MouseCode code, int x, int y ) {}; + virtual void OnMouseWheeled( int delta ) {}; + + virtual void SetViewportSize( int w, int h ) + { + m_nViewport[ 0 ] = w; + m_nViewport[ 1 ] = h; + } + +protected: + int m_nViewport[ 2 ]; +}; + + +//----------------------------------------------------------------------------- +// Base class for manipulators which operate on transforms +//----------------------------------------------------------------------------- +class CTransformManipulator : public CBaseManipulator +{ +public: + CTransformManipulator( matrix3x4_t *pTransform ); + + void SetTransform( matrix3x4_t *transform ); + matrix3x4_t *GetTransform(); + +protected: + matrix3x4_t *m_pTransform; +}; + + +//----------------------------------------------------------------------------- +// Standard maya-like transform manipulator +//----------------------------------------------------------------------------- +class CPotteryWheelManip : public CTransformManipulator +{ +public: + CPotteryWheelManip( matrix3x4_t *pTransform ); + + virtual void OnBeginManipulation( void ); + virtual void OnAcceptManipulation( void ); + virtual void OnCancelManipulation( void ); + + virtual void OnTick( void ); + + virtual void OnCursorMoved( int x, int y ); + virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); + virtual void OnMouseReleased( vgui::MouseCode code, int x, int y ); + virtual void OnMouseWheeled( int delta ); + + // Sets the zoom level + void SetZoom( float flZoom ); + +protected: + int m_lastx, m_lasty; + + float m_zoom; + float m_altitude, m_azimuth; + //vec3 m_lookat + + float m_prevZoom; + float m_prevAltitude, m_prevAzimuth; + + float m_flLastMouseTime; + float m_flLastTickTime; + float m_flSpin; + bool m_bSpin; + + void UpdateTransform( void ); + void UpdateZoom( float delta ); +}; + + +#endif // MANIPULATOR_H diff --git a/public/matsys_controls/matsyscontrols.h b/public/matsys_controls/matsyscontrols.h new file mode 100644 index 0000000..85fa580 --- /dev/null +++ b/public/matsys_controls/matsyscontrols.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MATSYSCONTROLS_H +#define MATSYSCONTROLS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterialSystem; +class IMaterialSystemHardwareConfig; +class IMDLCache; +class IMatSystemSurface; +class IStudioRender; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// handles the initialization of the vgui interfaces. +// NOTE: Calls into VGui_InitInterfacesList +// interfaces (listed below) are first attempted to be loaded from primaryProvider, then secondaryProvider +// moduleName should be the name of the module that this instance of the vgui_controls has been compiled into +//----------------------------------------------------------------------------- +bool VGui_InitMatSysInterfacesList( const char *moduleName, CreateInterfaceFn *factoryList, int numFactories ); + + +//----------------------------------------------------------------------------- +// set of accessor functions to matsys interfaces +// the appropriate header file for each is listed above the item +//----------------------------------------------------------------------------- + +// #include +IMaterialSystem *MaterialSystem(); + +// #include +IMDLCache *MDLCache(); + +// #include +IMatSystemSurface *MatSystemSurface(); + +// #include +IMaterialSystemHardwareConfig *MaterialSystemHardwareConfig(); + +} // end namespace vgui + + +//----------------------------------------------------------------------------- +// predeclare all the matsys control class names +//----------------------------------------------------------------------------- +class CMDLPanel; +class CMDLSequencePicker; +class CMDLPicker; +class CSequencePicker; +class CGameFileTreeView; + + +#endif // MATSYSCONTROLS_H diff --git a/public/matsys_controls/mdlpanel.h b/public/matsys_controls/mdlpanel.h new file mode 100644 index 0000000..6006856 --- /dev/null +++ b/public/matsys_controls/mdlpanel.h @@ -0,0 +1,157 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef MDLPANEL_H +#define MDLPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_controls/Panel.h" +#include "datacache/imdlcache.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "matsys_controls/potterywheelpanel.h" +#include "tier3/mdlutils.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class IScheme; +} + +// +struct MDLAnimEventState_t +{ + int m_nEventSequence; + float m_flPrevEventCycle; +}; + +//----------------------------------------------------------------------------- +// MDL Viewer Panel +//----------------------------------------------------------------------------- +class CMDLPanel : public CPotteryWheelPanel +{ + DECLARE_CLASS_SIMPLE( CMDLPanel, CPotteryWheelPanel ); + +public: + // constructor, destructor + CMDLPanel( vgui::Panel *pParent, const char *pName ); + virtual ~CMDLPanel(); + + // Overriden methods of vgui::Panel + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + virtual void OnTick(); + + virtual void Paint(); + + // Sets the current mdl + virtual void SetMDL( MDLHandle_t handle, void *pProxyData = NULL ); + virtual void SetMDL( const char *pMDLName, void *pProxyData = NULL ); + + // Sets the camera to look at the model + void LookAtMDL( ); + + // Sets the current LOD + void SetLOD( int nLOD ); + + // Sets the current sequence + void SetSequence( int nSequence, bool bResetSequence = false ); + + // Set the pose parameters + void SetPoseParameters( const float *pPoseParameters, int nCount ); + bool SetPoseParameterByName( const char *pszName, float fValue ); + + // Set the overlay sequence layers + void SetSequenceLayers( const MDLSquenceLayer_t *pSequenceLayers, int nCount ); + + void SetCollsionModel( bool bVisible ); + void SetGroundGrid( bool bVisible ); + void SetWireFrame( bool bVisible ); + void SetLockView( bool bLocked ); + void SetSkin( int nSkin ); + void SetLookAtCamera( bool bLookAtCamera ); + void SetIgnoreDoubleClick( bool bState ); + void SetThumbnailSafeZone( bool bVisible ); + + // Bounds. + bool GetBoundingBox( Vector &vecBoundsMin, Vector &vecBoundsMax ); + bool GetBoundingSphere( Vector &vecCenter, float &flRadius ); + + virtual void SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos ); + + // Attached models. + void SetMergeMDL( MDLHandle_t handle, void *pProxyData = NULL, int nSkin = -1 ); + MDLHandle_t SetMergeMDL( const char *pMDLName, void *pProxyData = NULL, int nSkin = -1 ); + int GetMergeMDLIndex( void *pProxyData ); + int GetMergeMDLIndex( MDLHandle_t handle ); + CMDL *GetMergeMDL(MDLHandle_t handle ); + void ClearMergeMDLs( void ); + + virtual void SetupFlexWeights( void ) { return; } + + // Events + void DoAnimationEvents(); + void DoAnimationEvents( CStudioHdr *pStudioHdr, int nSeqNum, float flTime, bool bNoLoop, MDLAnimEventState_t *pEventState ); + virtual void FireEvent( const char *pszEventName, const char *pszEventOptions ) { } + void ResetAnimationEventState( MDLAnimEventState_t *pEventState ); + +protected: + + virtual void SetupRenderState( int nDisplayWidth, int nDisplayHeight ) OVERRIDE; + + struct MDLData_t + { + CMDL m_MDL; + matrix3x4_t m_MDLToWorld; + bool m_bDisabled; + float m_flCycleStartTime; + }; + + MDLData_t m_RootMDL; + CUtlVector m_aMergeMDLs; + + static const int MAX_SEQUENCE_LAYERS = 8; + int m_nNumSequenceLayers; + MDLSquenceLayer_t m_SequenceLayers[ MAX_SEQUENCE_LAYERS ]; + + MDLAnimEventState_t m_EventState; + MDLAnimEventState_t m_SequenceLayerEventState[ MAX_SEQUENCE_LAYERS ]; + +private: + // paint it! + virtual void OnPaint3D(); + virtual void PrePaint3D( IMatRenderContext *pRenderContext ) { }; + virtual void PostPaint3D( IMatRenderContext *pRenderContext ) { }; + virtual void RenderingRootModel( IMatRenderContext *pRenderContext, CStudioHdr *pStudioHdr, MDLHandle_t mdlHandle, matrix3x4_t *pWorldMatrix ) { }; + virtual void RenderingMergedModel( IMatRenderContext *pRenderContext, CStudioHdr *pStudioHdr, MDLHandle_t mdlHandle, matrix3x4_t *pWorldMatrix ) { }; + + void OnMouseDoublePressed( vgui::MouseCode code ); + + void DrawCollisionModel(); + void UpdateStudioRenderConfig( void ); + + CTextureReference m_DefaultEnvCubemap; + CTextureReference m_DefaultHDREnvCubemap; + + bool m_bDrawCollisionModel : 1; + bool m_bGroundGrid : 1; + bool m_bLockView : 1; + bool m_bWireFrame : 1; + bool m_bLookAtCamera : 1; + bool m_bIgnoreDoubleClick : 1; + bool m_bThumbnailSafeZone : 1; + + float m_PoseParameters[ MAXSTUDIOPOSEPARAM ]; +}; + + +#endif // MDLPANEL_H diff --git a/public/matsys_controls/mdlpicker.h b/public/matsys_controls/mdlpicker.h new file mode 100644 index 0000000..fcacfc9 --- /dev/null +++ b/public/matsys_controls/mdlpicker.h @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef MDLPICKER_H +#define MDLPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlstring.h" +#include "vgui_controls/Frame.h" +#include "matsys_controls/baseassetpicker.h" +#include "datacache/imdlcache.h" + + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class Splitter; +} + +class CMDLPanel; + +const int MAX_SELECTED_MODELS = 2; + +//----------------------------------------------------------------------------- +// Purpose: Main app window +//----------------------------------------------------------------------------- +class CMDLPicker : public CBaseAssetPicker +{ + DECLARE_CLASS_SIMPLE( CMDLPicker, CBaseAssetPicker ); + +public: + + enum PageType_t + { + PAGE_NONE = 0, + PAGE_RENDER = 0x1, + PAGE_SEQUENCES = 0x2, + PAGE_ACTIVITIES = 0x4, + PAGE_SKINS = 0x8, + PAGE_INFO = 0x10, + PAGE_SCREEN_CAPS = 0x20, + PAGE_ALL = 0xFFFFFFFF, + }; + + CMDLPicker( vgui::Panel *pParent, int nFlags = PAGE_ALL ); + ~CMDLPicker(); + + // overridden frame functions + virtual void PerformLayout(); + virtual void OnCommand( const char *pCommand ); + + // Get current model + void GetSelectedMDLName( char *pBuffer, int nMaxLen ); + + // get current selected options page + int GetSelectedPage(); + + // Allows external apps to select a MDL + void SelectMDL( const char *pRelativePath, bool bDoLookAt = true, int nSelectSecondary = 0 ); + + // Set/Get Sequence + void SelectSequence( const char *pSequenceName ); + const char *GetSelectedSequenceName(); + + // Set/Get Activity + void SelectActivity( const char *pActivityName ); + const char *GetSelectedActivityName(); + + void SelectSkin( int nSkin ); + int GetSelectedSkin(); + +private: + MESSAGE_FUNC_PARAMS( OnAssetSelected, "AssetSelected", params ); + + virtual void OnSelectedAssetPicked( const char *pMDLName ); + + void RefreshActivitiesAndSequencesList(); + void RefreshRenderSettings(); + int UpdateSkinsList(); + void UpdateInfoTab(); + int UpdatePropDataList( const char* pszPropData, bool &bIsStatic ); + + // Plays the selected activity + void PlaySelectedActivity( ); + + // Plays the selected sequence + void PlaySelectedSequence( ); + + const char *CaptureModel( int nModIndex, const char *AssetName, const char *OutputPath, int Width, int Height, Color BackgroundColor, bool bSelectedOnly ); + void CaptureScreenCaps( void ); + void SaveCaps( const char *szFileName ); + bool RestoreCaps( const char *szFileName ); + + void WriteBackbackVMTFiles( const char *assetName ); + void GenerateBackpackIcons( void ); + CUtlString GetOutputFileSuffix(); + + MESSAGE_FUNC_PARAMS( OnCheckButtonChecked, "CheckButtonChecked", kv ); + MESSAGE_FUNC_PARAMS( OnItemSelected, "ItemSelected", kv ); + MESSAGE_FUNC( OnPageChanged, "PageChanged" ); + MESSAGE_FUNC_CHARPTR( OnDirectorySelected, "DirectorySelected", dir ); + + CMDLPanel *m_pMDLPreview; + vgui::Splitter* m_pFileBrowserSplitter; + vgui::Splitter* m_pPreviewSplitter; + + vgui::PropertySheet *m_pViewsSheet; + vgui::PropertyPage *m_pRenderPage; + vgui::PropertyPage *m_pSequencesPage; + vgui::PropertyPage *m_pActivitiesPage; + vgui::PropertyPage *m_pSkinsPage; + vgui::PropertyPage *m_pInfoPage; + vgui::PropertyPage *m_pScreenCapsPage; + + + vgui::ListPanel *m_pSequencesList; + vgui::ListPanel *m_pActivitiesList; + vgui::ListPanel *m_pSkinsList; + vgui::ListPanel *m_pPropDataList; + + MDLHandle_t m_hSelectedMDL[ MAX_SELECTED_MODELS ]; + + vgui::DHANDLE< vgui::DirectorySelectDialog > m_hDirectorySelectDialog; + + int m_nFlags; + + friend class CMDLPickerFrame; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Main app window +//----------------------------------------------------------------------------- +class CMDLPickerFrame : public CBaseAssetPickerFrame +{ + DECLARE_CLASS_SIMPLE( CMDLPickerFrame, CBaseAssetPickerFrame ); + +public: + CMDLPickerFrame( vgui::Panel *pParent, const char *pTitle, int nFlags = CMDLPicker::PAGE_ALL ); + virtual ~CMDLPickerFrame(); + + // Allows external apps to select a MDL + void SelectMDL( const char *pRelativePath ); +}; + + +#endif // MDLPICKER_H diff --git a/public/matsys_controls/mdlsequencepicker.h b/public/matsys_controls/mdlsequencepicker.h new file mode 100644 index 0000000..3150f16 --- /dev/null +++ b/public/matsys_controls/mdlsequencepicker.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef MDLSEQUENCEPICKER_H +#define MDLSEQUENCEPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/ImageList.h" +#include "vgui_controls/Frame.h" +#include "datacache/imdlcache.h" +#include "matsys_controls/mdlpanel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class Splitter; + class Button; +} + +class CGameFileTreeView; + + +//----------------------------------------------------------------------------- +// Purpose: Main app window +//----------------------------------------------------------------------------- +class CMDLSequencePicker : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CMDLSequencePicker, vgui::EditablePanel ); +public: + CMDLSequencePicker( vgui::Panel *pParent ); + virtual ~CMDLSequencePicker(); + + // overridden frame functions + virtual void Activate(); + virtual void OnClose(); + virtual void PerformLayout(); + virtual void OnTick(); + + char const *GetModelName(); + char const *GetSequenceName(); + int GetSequenceNumber(); + +private: + void SelectMDL( const char *pMDLName ); + void RefreshFileList(); + void RefreshActivitiesAndSequencesList(); + + // Plays the selected activity + void PlaySelectedActivity( ); + + // Plays the selected sequence + void PlaySelectedSequence( ); + + MESSAGE_FUNC( OnFileSelected, "TreeViewItemSelected" ); + MESSAGE_FUNC_PTR_CHARPTR( OnTextChanged, "TextChanged", Panel, text ); + MESSAGE_FUNC_PARAMS( OnItemSelected, "ItemSelected", kv ); + MESSAGE_FUNC( OnPageChanged, "PageChanged" ); + + // changes +// MESSAGE_FUNC_INT( CloakFolder, "CloakFolder", item ); +// MESSAGE_FUNC_INT( OpenFileForEdit, "EditFile", item ); +// MESSAGE_FUNC_INT( OpenFileForDelete, "DeleteFile", item ); + + CMDLPanel *m_pMDLPreview; + vgui::ComboBox *m_pFilterList; + CGameFileTreeView *m_pFileTree; + vgui::ImageList m_Images; + vgui::Splitter* m_pMDLSplitter; + vgui::Splitter* m_pSequenceSplitter; + vgui::PropertySheet *m_pViewsSheet; + vgui::PropertyPage *m_pSequencesPage; + vgui::PropertyPage *m_pActivitiesPage; + + vgui::ListPanel *m_pSequencesList; + vgui::ListPanel *m_pActivitiesList; + + MDLHandle_t m_hSelectedMDL; + + friend class CMDLSequencePickerFrame; +}; + +//----------------------------------------------------------------------------- +// Model sequence picker frame +//----------------------------------------------------------------------------- +class CMDLSequencePickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CMDLSequencePickerFrame, vgui::Frame ); +public: + CMDLSequencePickerFrame( vgui::Panel *parent, char const *title ); + virtual ~CMDLSequencePickerFrame(); + + virtual void PerformLayout(); + +protected: + + virtual void OnTick(); + + MESSAGE_FUNC( OnOK, "OnOK" ); + MESSAGE_FUNC( OnCancel, "OnCancel" ); + +private: + CMDLSequencePicker *m_pMDLSequencePicker; + + vgui::Button *m_pOK; + vgui::Button *m_pCancel; +}; + +#endif // MDLSEQUENCEPICKER_H diff --git a/public/matsys_controls/picker.h b/public/matsys_controls/picker.h new file mode 100644 index 0000000..380e3bf --- /dev/null +++ b/public/matsys_controls/picker.h @@ -0,0 +1,133 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: An arbitrary picker +// +//============================================================================= + +#ifndef PICKER_H +#define PICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/Frame.h" +#include "tier1/utlstring.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class Panel; +} + + +//----------------------------------------------------------------------------- +// List of strings to appear in the picker +//----------------------------------------------------------------------------- +enum PickerChoiceType_t +{ + PICKER_CHOICE_STRING = 0, + PICKER_CHOICE_PTR, +}; + +struct PickerInfo_t +{ + const char *m_pChoiceString; // This is what displays in the dialog + union + { + const char *m_pChoiceValue; + void *m_pChoiceValuePtr; + }; +}; + +struct PickerList_t +{ + PickerList_t() : m_Type( PICKER_CHOICE_STRING ) {} + PickerList_t( int nGrowSize, int nInitSize ) : m_Choices( nGrowSize, nInitSize ), m_Type( PICKER_CHOICE_STRING ) {} + + int Count() const { return m_Choices.Count(); } + PickerInfo_t& operator[]( int i ) { return m_Choices[i]; } + const PickerInfo_t& operator[]( int i ) const { return m_Choices[i]; } + int AddToTail() { return m_Choices.AddToTail(); } + void RemoveAll() { return m_Choices.RemoveAll(); } + + PickerChoiceType_t m_Type; + CUtlVector< PickerInfo_t > m_Choices; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Base class for choosing raw assets +//----------------------------------------------------------------------------- +class CPicker : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CPicker, vgui::EditablePanel ); + +public: + CPicker( vgui::Panel *pParent, const char *pColumnHeader, const char *pTextType ); + ~CPicker(); + + // Sets the list of strings to display + void SetStringList( const PickerList_t &list ); + + // Purpose: + virtual void OnKeyCodePressed( vgui::KeyCode code ); + + // Returns the selected string + PickerChoiceType_t GetSelectionType() const; + const char *GetSelectedString( ) const; + void *GetSelectedPtr( ) const; + + // Returns the index of the selected string + int GetSelectedIndex(); + +private: + void RefreshChoiceList( ); + MESSAGE_FUNC( OnTextChanged, "TextChanged" ); + + vgui::TextEntry *m_pFilterList; + vgui::ListPanel *m_pPickerBrowser; + CUtlString m_Filter; + const char *m_pPickerType; + const char *m_pPickerTextType; + const char *m_pPickerExt; + const char *m_pPickerSubDir; + PickerChoiceType_t m_Type; + + friend class CPickerFrame; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for picker +//----------------------------------------------------------------------------- +class CPickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CPickerFrame, vgui::Frame ); + +public: + CPickerFrame( vgui::Panel *pParent, const char *pTitle, const char *pColumnHeader, const char *pTextType ); + ~CPickerFrame(); + + // Inherited from Frame + virtual void OnCommand( const char *pCommand ); + + // Purpose: Activate the dialog + // The message "Picked" will be sent if something is picked. + // You can pass in keyvalues to get added to the message also. + void DoModal( const PickerList_t &list, KeyValues *pContextKeyValues = NULL ); + +private: + void CleanUpMessage(); + + CPicker *m_pPicker; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + KeyValues *m_pContextKeyValues; +}; + + +#endif // PICKER_H diff --git a/public/matsys_controls/potterywheelpanel.h b/public/matsys_controls/potterywheelpanel.h new file mode 100644 index 0000000..5da55e4 --- /dev/null +++ b/public/matsys_controls/potterywheelpanel.h @@ -0,0 +1,170 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef POTTERYWHEELPANEL_H +#define POTTERYWHEELPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_controls/EditablePanel.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "tier2/camerautils.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IManipulator; +class CPotteryWheelManip; +class CBaseManipulator; +class CTransformManipulator; +class CDmxElement; + +namespace vgui +{ + class IScheme; +} + + +//----------------------------------------------------------------------------- +// Pottery wheel Panel +//----------------------------------------------------------------------------- +class CPotteryWheelPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CPotteryWheelPanel, vgui::EditablePanel ); + +public: + // constructor, destructor + CPotteryWheelPanel( vgui::Panel *pParent, const char *pName ); + virtual ~CPotteryWheelPanel(); + + // Overriden methods of vgui::Panel + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void Init( int x, int y, int wide, int tall ); + virtual void Paint(); + + virtual void OnKeyCodePressed ( vgui::KeyCode code ); + virtual void OnKeyCodeReleased( vgui::KeyCode code ); + virtual void OnMousePressed ( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + virtual void OnCursorMoved( int x, int y ); + virtual void OnMouseWheeled( int delta ); + virtual void OnTick(); + + virtual void OnMouseCaptureLost(); + + // Sets the camera to look at the the thing we're spinning around + void LookAt( const Vector &vecCenter, float flRadius ); + void LookAt( float flRadius ); + + void ComputePanelPosition( const Vector &vecPosition, Vector2D *pPanelPos ); + + void SetBackgroundColor( int r, int g, int b ); + void SetBackgroundColor( const Color& c ); + const Color& GetBackgroundColor() const; + + // Light probe + void SetLightProbe( CDmxElement *pLightProbe ); + + // Camera. + int GetCameraFOV( void ); + void SetCameraFOV( float flFOV ); + void SetCameraPositionAndAngles( const Vector &vecPos, const QAngle &angDir, bool syncManipulators = true ); + void GetCameraPositionAndAngles( Vector &vecPos, QAngle &angDir ); + void SetCameraOffset( const Vector &vecOffset ); + void GetCameraOffset( Vector &vecOffset ); + void ResetCameraPivot( void ); + void ComputeCameraTransform( matrix3x4_t *pWorldToCamera ); + void UpdateCameraTransform(); + +private: + // Inherited classes must implement this + virtual void OnPaint3D() = 0; + +protected: + + enum + { + MAX_LIGHT_COUNT = 4 + }; + + struct LightInfo_t + { + LightDesc_t m_Desc; + matrix3x4_t m_LightToWorld; + }; + + + + enum ManipulationMode_t + { + CAMERA_ROTATE, + CAMERA_TRANSLATE, + CAMERA_ZOOM, + LIGHT_MODE, + }; + + virtual void EnterManipulationMode( ManipulationMode_t manipMode, bool bMouseCapture = true, vgui::MouseCode mouseCode = vgui::MouseCode( -1 ) ); + void Select(); + void AcceptManipulation( bool bReleaseMouseCapture = true ); + void CancelManipulation(); + void EnableMouseCapture( bool enable, vgui::MouseCode code = vgui::MouseCode( -1 ) ); + bool WarpMouse( int &x, int &y ); + IManipulator *m_pCurrentManip; + int m_nManipStartX, m_nManipStartY; + int m_nClickStartX, m_nClickStartY; + + // Re-apply the manipulators on a new model + void ApplyManipulation(); + + // Synchronize the manipulators with the current transform + void SyncManipulation(); + + bool HasLightProbe() const; + ITexture *GetLightProbeCubemap( bool bHDR ); + void DrawGrid(); + CMaterialReference m_Wireframe; + + bool m_bRenderToTexture; + + virtual void SetupRenderState( int nDisplayWidth, int nDisplayHeight ); + +private: + void CreateDefaultLights(); + void DestroyLights(); + void ParseLightsFromKV( KeyValues *pLightsKV ); + + CMaterialReference m_LightProbeBackground; + CMaterialReference m_LightProbeHDRBackground; + CTextureReference m_LightProbeCubemap; + CTextureReference m_LightProbeHDRCubemap; + + Camera_t m_Camera; + matrix3x4_t m_CameraPivot; + int m_nLightCount; + LightInfo_t m_Lights[MAX_LIGHT_COUNT]; + Vector4D m_vecAmbientCube[6]; + + Color m_ClearColor; + Vector m_vecCameraOffset; + CTransformManipulator *m_pCameraRotate; + CTransformManipulator *m_pCameraTranslate; + CBaseManipulator *m_pCameraZoom; + CPotteryWheelManip *m_pLightManip; + vgui::MouseCode m_nCaptureMouseCode; + + int m_xoffset, m_yoffset; + + bool m_bHasLightProbe : 1; + + CPanelAnimationVar( bool, m_bUseParentBG, "useparentbg", "0" ); +}; + + +#endif // SIMPLEPOTTERYWHEELPANEL_H diff --git a/public/matsys_controls/proceduraltexturepanel.h b/public/matsys_controls/proceduraltexturepanel.h new file mode 100644 index 0000000..3941be3 --- /dev/null +++ b/public/matsys_controls/proceduraltexturepanel.h @@ -0,0 +1,92 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef PROCEDURALTEXTUREPANEL_H +#define PROCEDURALTEXTUREPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "materialsystem/itexture.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "vgui_controls/EditablePanel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct BGRA8888_t; + + +//----------------------------------------------------------------------------- +// +// Procedural texture image panel +// +//----------------------------------------------------------------------------- +class CProceduralTexturePanel : public vgui::EditablePanel, public ITextureRegenerator +{ + DECLARE_CLASS_SIMPLE( CProceduralTexturePanel, vgui::EditablePanel ); + +public: + // constructor + CProceduralTexturePanel( vgui::Panel *pParent, const char *pName ); + ~CProceduralTexturePanel(); + + // Methods of ITextureRegenerator + virtual void Release() {} + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ); + + // initialization, shutdown + virtual bool Init( int nWidth, int nHeight, bool bAllocateImageBuffer ); + virtual void Shutdown(); + + // Returns the image buffer + dimensions + BGRA8888_t *GetImageBuffer(); + int GetImageWidth() const; + int GetImageHeight() const; + + // Redownloads the procedural texture + void DownloadTexture(); + + // Sets the rectangle to paint. Use null to fill the entire panel + void SetPaintRect( const Rect_t *pPaintRect = NULL ); + + // Sets the texcoords to use with the procedural texture + void SetTextureSubRect( const Rect_t &subRect ); + + // Maintain proportions when drawing + void MaintainProportions( bool bEnable ); + + virtual void Paint( void ); + virtual void PaintBackground( void ) {} + +private: + void CleanUp(); + +protected: + // Image buffer + BGRA8888_t *m_pImageBuffer; + int m_nWidth; + int m_nHeight; + + // Paint rectangle + Rect_t m_PaintRect; + + // Texture coordinate rectangle + Rect_t m_TextureSubRect; + + CTextureReference m_ProceduralTexture; + CMaterialReference m_ProceduralMaterial; + + int m_nTextureID; + bool m_bMaintainProportions; + bool m_bUsePaintRect; +}; + + +#endif // PROCEDURALTEXTUREPANEL_H diff --git a/public/matsys_controls/sequencepicker.h b/public/matsys_controls/sequencepicker.h new file mode 100644 index 0000000..68e4729 --- /dev/null +++ b/public/matsys_controls/sequencepicker.h @@ -0,0 +1,111 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SEQUENCEPICKER_H +#define SEQUENCEPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlstring.h" +#include "vgui_controls/Frame.h" +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/ImageList.h" +#include "datacache/imdlcache.h" +#include "matsys_controls/mdlpanel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class Splitter; +} + + +//----------------------------------------------------------------------------- +// Purpose: Sequence picker panel +//----------------------------------------------------------------------------- +class CSequencePicker : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CSequencePicker, vgui::EditablePanel ); + +public: + enum PickType_t + { + PICK_NONE = 0, + PICK_SEQUENCES = 0x1, + PICK_ACTIVITIES = 0x2, + PICK_ALL = 0xFFFFFFFF, + }; + + // Flags come from PickType_t + CSequencePicker( vgui::Panel *pParent, int nFlags = PICK_ALL ); + ~CSequencePicker(); + + // overridden frame functions + virtual void PerformLayout(); + + // Sets the MDL to preview sequences for + void SetMDL( const char *pMDLName ); + + // Gets the selected activity/sequence + PickType_t GetSelectedSequenceType(); + const char *GetSelectedSequenceName( ); + +private: + void RefreshActivitiesAndSequencesList(); + + // Plays the selected activity + void PlayActivity( const char *pActivityName ); + + // Plays the selected sequence + void PlaySequence( const char *pSequenceName ); + + MESSAGE_FUNC_PARAMS( OnItemSelected, "ItemSelected", kv ); + MESSAGE_FUNC( OnPageChanged, "PageChanged" ); + + CMDLPanel *m_pMDLPreview; + vgui::Splitter* m_pPreviewSplitter; + vgui::PropertySheet *m_pViewsSheet; + vgui::PropertyPage *m_pSequencesPage; + vgui::PropertyPage *m_pActivitiesPage; + vgui::ListPanel *m_pSequencesList; + vgui::ListPanel *m_pActivitiesList; + MDLHandle_t m_hSelectedMDL; + CUtlString m_Filter; + + friend class CSequencePickerFrame; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Main app window +//----------------------------------------------------------------------------- +class CSequencePickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CSequencePickerFrame, vgui::Frame ); + +public: + CSequencePickerFrame( vgui::Panel *pParent, int nFlags ); + + // Inherited from Frame + virtual void OnCommand( const char *pCommand ); + + // Purpose: Activate the dialog + void DoModal( const char *pMDLName ); + +private: + MESSAGE_FUNC_PARAMS( OnSequencePreviewChanged, "SequencePreviewChanged", kv ); + + CSequencePicker *m_pPicker; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; +}; + + +#endif // SEQUENCEPICKER_H diff --git a/public/matsys_controls/tgapreviewpanel.h b/public/matsys_controls/tgapreviewpanel.h new file mode 100644 index 0000000..fc52adf --- /dev/null +++ b/public/matsys_controls/tgapreviewpanel.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TGAPREVIEWPANEL_H +#define TGAPREVIEWPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "matsys_controls/proceduraltexturepanel.h" +#include "tier1/utlstring.h" + + +//----------------------------------------------------------------------------- +// +// TGA Preview panel +// +//----------------------------------------------------------------------------- +class CTGAPreviewPanel : public CProceduralTexturePanel +{ + DECLARE_CLASS_SIMPLE( CTGAPreviewPanel, CProceduralTexturePanel ); + +public: + // constructor + CTGAPreviewPanel( vgui::Panel *pParent, const char *pName ); + void SetTGA( const char *pFullPath ); + const char *GetTGA() const; + +private: + CUtlString m_TGAName; +}; + + +#endif // TGAPREVIEWPANEL_H \ No newline at end of file diff --git a/public/matsys_controls/vmtpanel.h b/public/matsys_controls/vmtpanel.h new file mode 100644 index 0000000..ee2e6cc --- /dev/null +++ b/public/matsys_controls/vmtpanel.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef VMTPANEL_H +#define VMTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "matsys_controls/potterywheelpanel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class CMeshBuilder; +class Vector; + +namespace vgui +{ + class ScrollBar; + class IScheme; +} + + +//----------------------------------------------------------------------------- +// Material Viewer Panel +//----------------------------------------------------------------------------- +class CVMTPanel : public CPotteryWheelPanel +{ + DECLARE_CLASS_SIMPLE( CVMTPanel, CPotteryWheelPanel ); + +public: + // constructor, destructor + CVMTPanel( vgui::Panel *pParent, const char *pName ); + virtual ~CVMTPanel(); + + // Set the material to draw + void SetMaterial( IMaterial *pMaterial ); + + // Set rendering mode (stretch to full screen, or use actual size) + void RenderUsingActualSize( bool bEnable ); + + // performs the layout + virtual void PerformLayout(); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +private: + // paint it stretched to the window size + void DrawStretchedToPanel( CMeshBuilder &meshBuilder ); + + // paint it actual size + void DrawActualSize( CMeshBuilder &meshBuilder ); + + // Draw it on a sphere + void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi ); + + // paint it! + virtual void OnPaint3D(); + +private: + // The material to draw + IMaterial *m_pMaterial; + + // A texture to use for a lightmap + CTextureReference m_pLightmapTexture; + + // The default env_cubemap + CTextureReference m_DefaultEnvCubemap; + + // Are we using actual size or not? + bool m_bUseActualSize; + + // Scroll bars + vgui::ScrollBar *m_pHorizontalBar; + vgui::ScrollBar *m_pVerticalBar; + + // The viewable size + int m_iViewableWidth; + int m_iViewableHeight; +}; + +#endif // VMTPANEL_H + \ No newline at end of file diff --git a/public/matsys_controls/vmtpicker.h b/public/matsys_controls/vmtpicker.h new file mode 100644 index 0000000..51499bf --- /dev/null +++ b/public/matsys_controls/vmtpicker.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VMTPICKER_H +#define VMTPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "matsys_controls/baseassetpicker.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CVMTPreviewPanel; + +namespace vgui +{ + class Splitter; +} + + +//----------------------------------------------------------------------------- +// Purpose: Base class for choosing raw assets +//----------------------------------------------------------------------------- +class CVMTPicker : public CBaseAssetPicker +{ + DECLARE_CLASS_SIMPLE( CVMTPicker, CBaseAssetPicker ); + +public: + CVMTPicker( vgui::Panel *pParent, bool bAllowMultiselect = false ); + virtual ~CVMTPicker(); + +private: + // Derived classes have this called when the previewed asset changes + virtual void OnSelectedAssetPicked( const char *pAssetName ); + + CVMTPreviewPanel *m_pVMTPreview2D; + CVMTPreviewPanel *m_pVMTPreview3D; + vgui::Splitter *m_p2D3DSplitter; + vgui::Splitter *m_pPreviewSplitter; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for asset picker +//----------------------------------------------------------------------------- +class CVMTPickerFrame : public CBaseAssetPickerFrame +{ + DECLARE_CLASS_SIMPLE( CVMTPickerFrame, CBaseAssetPickerFrame ); + +public: + CVMTPickerFrame( vgui::Panel *pParent, const char *pTitle, bool bAllowMultiselect = false ); +}; + + +#endif // VMTPICKER_H diff --git a/public/matsys_controls/vmtpreviewpanel.h b/public/matsys_controls/vmtpreviewpanel.h new file mode 100644 index 0000000..f080d6c --- /dev/null +++ b/public/matsys_controls/vmtpreviewpanel.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VMTPREVIEWPANEL_H +#define VMTPREVIEWPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_controls/Panel.h" +#include "tier1/utlstring.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "mathlib/vector.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// +// VMT Preview panel +// +//----------------------------------------------------------------------------- +class CVMTPreviewPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CVMTPreviewPanel, vgui::Panel ); + +public: + // constructor + CVMTPreviewPanel( vgui::Panel *pParent, const char *pName ); + void SetVMT( const char *pMaterialName ); + const char *GetVMT() const; + + // Paints the texture + virtual void Paint( void ); + + // View it in 3D or 2D mode + void DrawIn3DMode( bool b3DMode ); + +private: + // Two different preview methods + void DrawSphere( void ); + void DrawRectangle( void ); + + // Set up a projection matrix for a 90 degree fov + void SetupProjectionMatrix( int nWidth, int nHeight ); + void SetupOrthoMatrix( int nWidth, int nHeight ); + + // Sets the camera to look at the the thing we're spinning around + void LookAt( const Vector &vecLookAt, float flRadius ); + + // Sets up lighting state + void SetupLightingState(); + + // Draw a sphere + void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi ); + + // Draw sprite-card based materials + void RenderSpriteCard( const Vector &vCenter, float flRadius ); + + CUtlString m_VMTName; + CMaterialReference m_Material; + CTextureReference m_pLightmapTexture; + CTextureReference m_DefaultEnvCubemap; + Vector m_LightDirection; + Color m_LightColor; + float m_flLightIntensity; + Vector m_vecCameraDirection; + float m_flLastRotationTime; + bool m_bDrawIn3DMode; +}; + + +#endif // VMTPREVIEWPANEL_H \ No newline at end of file diff --git a/public/matsys_controls/vtfpicker.h b/public/matsys_controls/vtfpicker.h new file mode 100644 index 0000000..ce8478a --- /dev/null +++ b/public/matsys_controls/vtfpicker.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VTFPICKER_H +#define VTFPICKER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "matsys_controls/baseassetpicker.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CVTFPreviewPanel; + +namespace vgui +{ + class Splitter; +} + + +//----------------------------------------------------------------------------- +// Purpose: Base class for choosing raw assets +//----------------------------------------------------------------------------- +class CVTFPicker : public CBaseAssetPicker +{ + DECLARE_CLASS_SIMPLE( CVTFPicker, CBaseAssetPicker ); + +public: + CVTFPicker( vgui::Panel *pParent ); + virtual ~CVTFPicker(); + +private: + // Derived classes have this called when the previewed asset changes + virtual void OnSelectedAssetPicked( const char *pAssetName ); + + CVTFPreviewPanel *m_pVTFPreview; + vgui::Splitter *m_pPreviewSplitter; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for asset picker +//----------------------------------------------------------------------------- +class CVTFPickerFrame : public CBaseAssetPickerFrame +{ + DECLARE_CLASS_SIMPLE( CVTFPickerFrame, CBaseAssetPickerFrame ); + +public: + CVTFPickerFrame( vgui::Panel *pParent, const char *pTitle ); +}; + + +#endif // VTFPICKER_H diff --git a/public/matsys_controls/vtfpreviewpanel.h b/public/matsys_controls/vtfpreviewpanel.h new file mode 100644 index 0000000..7fdccbc --- /dev/null +++ b/public/matsys_controls/vtfpreviewpanel.h @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VTFPREVIEWPANEL_H +#define VTFPREVIEWPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_controls/Panel.h" +#include "tier1/utlstring.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "mathlib/vector.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// +// VTF Preview panel +// +//----------------------------------------------------------------------------- +class CVTFPreviewPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CVTFPreviewPanel, vgui::Panel ); + +public: + // constructor + CVTFPreviewPanel( vgui::Panel *pParent, const char *pName ); + virtual ~CVTFPreviewPanel(); + + void SetVTF( const char *pFullPath, bool bLoadImmediately = true ); + const char *GetVTF() const; + + // Paints the texture + virtual void Paint( void ); + +private: + void PaintNormalMapTexture( void ); + void PaintCubeTexture( void ); + void PaintStandardTexture( void ); + void PaintVolumeTexture( void ); + + // Set up a projection matrix for a 90 degree fov + void SetupProjectionMatrix( int nWidth, int nHeight ); + + // Sets the camera to look at the the thing we're spinning around + void LookAt( const Vector &vecLookAt, float flRadius ); + + // Draw a sphere + void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi ); + + CUtlString m_VTFName; + CTextureReference m_PreviewTexture; + CMaterialReference m_PreviewMaterial; + int m_nTextureID; + Vector m_vecCameraDirection; + float m_flLastRotationTime; +}; + + +#endif // VTFPREVIEWPANEL_H \ No newline at end of file diff --git a/public/maya/IMayaVGui.h b/public/maya/IMayaVGui.h new file mode 100644 index 0000000..eda8f25 --- /dev/null +++ b/public/maya/IMayaVGui.h @@ -0,0 +1,67 @@ +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Interface for dealing with vgui focus issues across all plugins +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef IMAYAVGUI_H +#define IMAYAVGUI_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/platform.h" +#include "appframework/iappsystem.h" +#include "vgui_controls/Frame.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class EditablePanel; +} + +class CVsVGuiWindowBase; + + +//----------------------------------------------------------------------------- +// Factory for creating vgui windows +//----------------------------------------------------------------------------- +abstract_class IMayaVguiWindowFactory +{ +public: + virtual void CreateVguiWindow( const char *pPanelName ) = 0; + virtual void DestroyVguiWindow( const char *pPanelName ) = 0; + virtual vgui::Frame *GetVGuiPanel( const char *pPanelName = NULL ) = 0; + virtual CVsVGuiWindowBase *GetVGuiWindow( const char *pPanelName = NULL ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Interface for dealing with vgui focus issues across all plugins +//----------------------------------------------------------------------------- +#define MAYA_VGUI_INTERFACE_VERSION "VMayaVGui001" +abstract_class IMayaVGui : public IAppSystem +{ +public: + virtual void InstallVguiWindowFactory( const char *pWindowTypeName, IMayaVguiWindowFactory *pFactory ) = 0; + virtual void RemoveVguiWindowFactory( const char *pWindowTypeName, IMayaVguiWindowFactory *pFactory ) = 0; + virtual void SetFocus( void *hWnd, int hVGuiContext ) = 0; + virtual bool HasFocus( void *hWnd ) = 0; + + // In this mode, maya's in a strange re-entrant mode waiting for a modal dialog + // We still get WM_PAINT messages, but we're in the middle of a callstack + // deep in the bowels of VGUI + virtual void SetModalMode( bool bEnable ) = 0; + virtual bool IsInModalMode( ) const = 0; +}; + +extern IMayaVGui* g_pMayaVGui; + + +#endif // IMAYAVGUI_H diff --git a/public/maya/VsMayaDmx.h b/public/maya/VsMayaDmx.h new file mode 100644 index 0000000..9037df2 --- /dev/null +++ b/public/maya/VsMayaDmx.h @@ -0,0 +1,30 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef VSMAYADMX_H +#define VSMAYADMX_H + +#ifdef _WIN32 +#pragma once +#endif + +// Maya includes + +#include + +// Valve includes + +#include "movieobjects/dmemesh.h" + +class VsMayaDmx +{ + static CDmeMesh *MayaMeshToDmeMesh( + const MDagPath &i_mDagPath, + DmFileId_t fileId ); + +}; + +#endif // VSMAYADMX_H \ No newline at end of file diff --git a/public/maya/VsMayaMPxFactory.h b/public/maya/VsMayaMPxFactory.h new file mode 100644 index 0000000..dc0ca0a --- /dev/null +++ b/public/maya/VsMayaMPxFactory.h @@ -0,0 +1,1120 @@ +//======= Copyright 1996-2006, Valve Corporation, All rights reserved. ====== +// +// Purpose: Utility classes for creating, registering & deregistering +// Maya MPx* derived classes +// +//============================================================================= + +#ifndef VSMAYAMPXFACTORY_H +#define VSMAYAMPXFACTORY_H +#if defined( _WIN32 ) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if MAYA_API_VERSION >= 200800 +#include +#endif //MAYA_API_VERSION >= 200800 + +//----------------------------------------------------------------------------- +// +// Forward declarations +// +//----------------------------------------------------------------------------- +class MFnPlugin; +namespace ValveMaya +{ + class CMSyntaxHelp; +} + + +//============================================================================= +// +// Base class for Maya MPx factories +// +//============================================================================= +class CVsMayaMPxFactoryBase +{ +public: + // Registers all MPx derived things that have been allocated + static MStatus RegisterEverything( MFnPlugin &pluginFn ); + + // Deregisters all MPx derived things that have been allocated + static MStatus DeregisterEverything( MFnPlugin &pluginFn ); + + // Displays a list of stuff in the plugin + static void DisplaySummary( const MString &pluginName ); + + // Types of things the MPxFactory can create + enum Type + { + // NOTE: Ensure this list of enums stays in sync with GetTypeName() array + kCommand, + kFileTranslator, + kDependencyNode, + kShaderNode, + kTransform, + kLocatorNode, + kImageFile, + // Insert new ones above here + kUnknown + }; + + void Enable( bool bEnabled ) { m_bEnabled = bEnabled; } + + bool IsEnabled() const { return m_bEnabled; } + +protected: + // Constructor + CVsMayaMPxFactoryBase(); + +private: + // The next factory + CVsMayaMPxFactoryBase* m_pNextFactory; + + // The starting factory + static CVsMayaMPxFactoryBase *s_pFirstFactory; + + // Register the thing associated with this factory + virtual MStatus Register( MFnPlugin &pluginFn ) const = 0; + + // Deregister the thing associated with this factory + virtual MStatus Deregister( MFnPlugin &pluginFn ) const = 0; + + // Everything has a name + virtual const MString &GetName() const = 0; + + // Everything has a description + virtual const MString &GetDesc() const = 0; + + // Everything has a type + virtual Type GetType() const = 0; + + // Everything has a type (map types to names) + MString GetTypeName() const; + + // Whether this factory is enabled or not + bool m_bEnabled; +}; + + +//----------------------------------------------------------------------------- +// +// Templatized helpers for creating MPx derived classes +// +//----------------------------------------------------------------------------- +template< class T > +class CVsMayaMPxFactory : public CVsMayaMPxFactoryBase +{ +private: + // Register the thing associated with this factory + virtual MStatus Register( MFnPlugin &pluginFn ) const + { + return T::Register( pluginFn ); + } + + // Deregister the thing associated with this factory + virtual MStatus Deregister( MFnPlugin &pluginFn ) const + { + return T::Deregister( pluginFn ); + } + + virtual const MString &GetName() const + { + return T::s_name; + } + + virtual const MString &GetDesc() const + { + return T::s_desc; + } + + virtual Type GetType() const + { + return T::GetType(); + } +}; + + +//============================================================================ +// +// Base class for Valve Maya commands ( CVsMayaMPxCommand ) +// +//============================================================================ +class CVsMayaMPxCommand : public MPxCommand +{ +public: + virtual const MString &GetName() const { return m_nullStr; } + virtual const MString &GetDesc() const { return m_nullStr; } + +protected: + // Derived classes must specify this to override syntax + virtual void SpecifySyntax( MSyntax &mSyntax, ValveMaya::CMSyntaxHelp &help ); + ValveMaya::CMSyntaxHelp *GetSyntaxHelp() { return m_pSyntaxHelp; } + +private: + ValveMaya::CMSyntaxHelp *m_pSyntaxHelp; + + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + MCreatorFunction creatorFunction, + MCreateSyntaxFunction createSyntaxFunction = NULL ); + + static MStatus Deregister( MFnPlugin &pluginFn, const MString &name ); + + template < class T > friend class CVsMayaMPxCommandDecorator; + + MString m_nullStr; +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya commands ( CVsMayaMPxCommandDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxCommandDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + static const MString &Desc() { return s_desc; }; + + virtual const MString &GetName() const { return Name(); }; + virtual const MString &GetDesc() const { return Desc(); }; + + static CVsMayaMPxFactoryBase::Type GetType() { return CVsMayaMPxFactoryBase::kCommand; } + +private: + friend class CVsMayaMPxFactoryBase; + template < class U > friend class CVsMayaMPxFactory; + + // These should be const but it's not because the CVsMayaMPxFactoryCommand class + // only knows its name and therefore it's description at runtime + + static MString s_name; + static MString s_desc; + static ValveMaya::CMSyntaxHelp s_mSyntaxHelp; // Keeps track of command line flags + + static void *Create() + { + CVsMayaMPxCommandDecorator *pDecorator = new CVsMayaMPxCommandDecorator< T >; + pDecorator->m_pSyntaxHelp = &s_mSyntaxHelp; + return pDecorator; + } + + static MSyntax CreateSyntax() + { + // Maya will simply never call this unless the 'hasSyntax()' virtual returns true + // doesn't matter if a syntaxCreator is registered or not, and an empty + // MSyntax is fine too. Also note the return is by value and not reference. + // Also... even when Maya does call this, it is only ever called once, the + // first time Maya needs to know what the syntax is (when the command is + // invoked or when help cmd is done + + MSyntax mSyntax; + T().SpecifySyntax( mSyntax, s_mSyntaxHelp ); + return mSyntax; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, Create, T().hasSyntax() ? CreateSyntax : NULL ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_name ); + } +}; + + +//============================================================================ +// +// Base class for Valve Maya commands ( CVsMayaMPxToolCommand ) +// +//============================================================================ +class CVsMayaMPxToolCommand : public MPxToolCommand +{ +public: + virtual const MString &GetName() const { return m_nullStr; } + virtual const MString &GetDesc() const { return m_nullStr; } + +protected: + // Derived classes must specify this to override syntax + virtual void SpecifySyntax( MSyntax &mSyntax, ValveMaya::CMSyntaxHelp &help ); + ValveMaya::CMSyntaxHelp *GetSyntaxHelp() { return m_pSyntaxHelp; } + +private: + ValveMaya::CMSyntaxHelp *m_pSyntaxHelp; + + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + MCreatorFunction creatorFunction, + MCreateSyntaxFunction createSyntaxFunction = NULL ); + + static MStatus Deregister( MFnPlugin &pluginFn, const MString &name ); + + template < class T > friend class CVsMayaMPxToolCommandDecorator; + + MString m_nullStr; +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya commands ( CVsMayaMPxToolCommandDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxToolCommandDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + static const MString &Desc() { return s_desc; }; + + virtual const MString &GetName() const { return Name(); }; + virtual const MString &GetDesc() const { return Desc(); }; + + static CVsMayaMPxFactoryBase::Type GetType() { return CVsMayaMPxFactoryBase::kCommand; } + +private: + friend class CVsMayaMPxFactoryBase; + template < class U > friend class CVsMayaMPxFactory; + + // These should be const but it's not because the CVsMayaMPxFactoryCommand class + // only knows its name and therefore it's description at runtime + + static MString s_name; + static MString s_desc; + static ValveMaya::CMSyntaxHelp s_mSyntaxHelp; // Keeps track of command line flags + + static void *Create() + { + CVsMayaMPxToolCommandDecorator *pDecorator = new CVsMayaMPxToolCommandDecorator< T >; + pDecorator->m_pSyntaxHelp = &s_mSyntaxHelp; + return pDecorator; + } + + static MSyntax CreateSyntax() + { + // Maya will simply never call this unless the 'hasSyntax()' virtual returns true + // doesn't matter if a syntaxCreator is registered or not, and an empty + // MSyntax is fine too. Also note the return is by value and not reference. + // Also... even when Maya does call this, it is only ever called once, the + // first time Maya needs to know what the syntax is (when the command is + // invoked or when help cmd is done + + MSyntax mSyntax; + T().SpecifySyntax( mSyntax, s_mSyntaxHelp ); + return mSyntax; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, Create, T().hasSyntax() ? CreateSyntax : NULL ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_name ); + } +}; + + +//============================================================================= +// +// Base class for Valve Maya file translators ( CVsMayaMPxFileTranslator ) +// +//============================================================================= +class CVsMayaMPxFileTranslator : public MPxFileTranslator +{ +public: + virtual const MString &GetName() const = 0; + virtual const MString &GetGUIName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MString &guiName, + MCreatorFunction creatorFunction ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MString &name ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya file translators ( CVsMayaMPxFileTranslatorDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxFileTranslatorDecorator : public T +{ +public: + virtual const MString &GetName() const { return s_name; }; + + virtual const MString &GetGUIName() const { return s_guiName; }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() { return CVsMayaMPxFactoryBase::kFileTranslator; } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MString s_guiName; + + static void *Create() + { + return new CVsMayaMPxFileTranslatorDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, s_guiName, Create ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_guiName ); + } +}; + + +//============================================================================= +// +// Base class for Valve Maya Dependency Nodes ( CVsMayaMPxNode ) +// +//============================================================================ +class CVsMayaMPxNode : public MPxNode +{ +public: + virtual const MString &GetName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MTypeId &mTypeId, + MCreatorFunction creatorFunction, + MInitializeFunction initFunction, + const MString &classification ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MTypeId &mTypeId ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya nodes ( CVsMayaMPxNodeDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxNodeDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() + { + return s_classification.length() ? CVsMayaMPxFactoryBase::kShaderNode : CVsMayaMPxFactoryBase::kDependencyNode; + } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MTypeId s_mTypeId; + + static const MInitializeFunction s_mInitializeFunction; + + static const MString s_classification; + + static void *Create() + { + return new CVsMayaMPxNodeDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, s_mTypeId, Create, s_mInitializeFunction, s_classification ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_mTypeId ); + } +}; + + +//============================================================================= +// +// Base class for Valve Maya Transform Nodes ( CVsMayaMPxTransform ) +// +//============================================================================ +class CVsMayaMPxTransform : public MPxTransform +{ +public: + virtual const MString &GetName() const = 0; + +protected: + +#if MAYA_API_VERSION >= 200900 + + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MTypeId &mTypeId, + MCreatorFunction creatorFunction, + MInitializeFunction initFunction, + MCreateXformMatrixFunction xformCreatorFunction = MPxTransformationMatrix::creator, + const MTypeId &xformMTypeId = MPxTransformationMatrix::baseTransformationMatrixId, + const MString *classification = NULL ); + +#else // #if MAYA_API_VERSION >= 200900 + + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MTypeId &mTypeId, + MCreatorFunction creatorFunction, + MInitializeFunction initFunction, + MCreatorFunction xformCreatorFunction = MPxTransformationMatrix::creator, + const MTypeId &xformMTypeId = MPxTransformationMatrix::baseTransformationMatrixId, + const MString *classification = NULL ); + +#endif // #if MAYA_API_VERSION >= 200900 + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MTypeId &mTypeId ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya commands ( CVsMayaMPxCommandDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxTransformDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() { return CVsMayaMPxFactoryBase::kTransform; } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MTypeId s_mTypeId; + + static const MInitializeFunction s_mInitializeFunction; + +#if MAYA_API_VERSION >= 200900 + + static const MCreateXformMatrixFunction s_xformMCreatorFunction; + +#else // #if MAYA_API_VERSION >= 200900 + + static const MCreatorFunction s_xformMCreatorFunction; + +#endif // #if MAYA_API_VERSION >= 200900 + + static const MTypeId s_xformMTypeId; + + static void *Create() + { + return new CVsMayaMPxTransformDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, s_mTypeId, Create, s_mInitializeFunction, s_xformMCreatorFunction, s_xformMTypeId ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_mTypeId ); + } +}; + + +//============================================================================= +// +// Base class for Valve Maya Locator Nodes ( CVsMayaMPxLocatorNode ) +// +//============================================================================ +class CVsMayaMPxLocatorNode : public MPxLocatorNode +{ +public: + virtual const MString &GetName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MTypeId &mTypeId, + MCreatorFunction creatorFunction, + MInitializeFunction initFunction ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MTypeId &mTypeId ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya nodes ( CVsMayaMPxLocatorNodeDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxLocatorNodeDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() + { + return CVsMayaMPxFactoryBase::kLocatorNode; + } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MTypeId s_mTypeId; + + static const MInitializeFunction s_mInitializeFunction; + + static void *Create() + { + return new CVsMayaMPxLocatorNodeDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, s_mTypeId, Create, s_mInitializeFunction ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_mTypeId ); + } +}; + + +//============================================================================= +// +// Base class for Valve Maya Drag And Drop Behaviors ( CVsMayaMPxDragAndDropBehavior ) +// +//============================================================================ +class CVsMayaMPxDragAndDropBehavior : public MPxDragAndDropBehavior +{ +public: + virtual const MString &GetName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + MCreatorFunction creatorFunction ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MString &name ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya drag and drop behaviors ( CVsMayaMPxDragAndDropBehavior ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxDragAndDropBehaviorDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() + { + return CVsMayaMPxFactoryBase::kLocatorNode; + } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MInitializeFunction s_mInitializeFunction; + + static void *Create() + { + return new CVsMayaMPxDragAndDropBehaviorDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, Create ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_name ); + } +}; + + +//============================================================================= +// +// Base class for Valve Maya Shape Nodes ( CVsMayaMPxShapeNode ) +// +//============================================================================ +class CVsMayaMPxShapeNode : public MPxSurfaceShape +{ +public: + virtual const MString &GetName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MTypeId &mTypeId, + MCreatorFunction creatorFunction, + MInitializeFunction initFunction, + MCreatorFunction uiCreatorFunction ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MTypeId &mTypeId ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya shape nodes ( CVsMayaMPxShapeNodeDecorator ) +// +//----------------------------------------------------------------------------- +template < class T, class U > +class CVsMayaMPxShapeNodeDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() + { + return CVsMayaMPxFactoryBase::kLocatorNode; + } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MTypeId s_mTypeId; + + static const MInitializeFunction s_mInitializeFunction; + + static const MCreatorFunction s_uiCreatorFunction; + + static void *Create() + { + return new CVsMayaMPxShapeNodeDecorator< T, U >; + } + + static void *CreateUI() + { + return new U; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, s_mTypeId, Create, s_mInitializeFunction, CreateUI ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_mTypeId ); + } +}; + +#if MAYA_API_VERSION >= 200800 +//============================================================================= +// +// Base class for Valve Maya Image File Types ( CVsMayaMPxImageFile ) +// +//============================================================================ +class CVsMayaMPxImageFile : public MPxImageFile +{ +public: + virtual const MString &GetName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + MCreatorFunction creatorFunction, + const MStringArray &extensions ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MString &name ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya Image Files ( CVsMayaMPxImageFileDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxImageFileDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() + { + return CVsMayaMPxFactoryBase::kImageFile; + } + +private: + template < class T > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MStringArray s_extensions; + + static const MCreatorFunction s_creatorFunction; + + static void *Create() + { + return new CVsMayaMPxImageFileDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, Create, s_extensions ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_name ); + } +}; + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate an image file +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXIMAGEFILE( _class, _name, _extensions, _desc ) \ + const MString CVsMayaMPxImageFileDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxImageFileDecorator< _class >::s_desc( _desc ); \ + const MStringArray CVsMayaMPxImageFileDecorator< _class >::s_extensions( _extensions ); \ + static CVsMayaMPxFactory< CVsMayaMPxImageFileDecorator< _class > > s_##_name##_Factory + + +#endif // MAYA_API_VERSION >= 200800 + + +//============================================================================= +// +// Base class for Valve Maya Dependency Nodes ( CVsMayaMPxNode ) +// +//============================================================================ +class CVsMayaMPxDeformerNode : public MPxDeformerNode +{ +public: + virtual const MString &GetName() const = 0; + +protected: + static MStatus Register( + MFnPlugin &pluginFn, + const MString &name, + const MTypeId &mTypeId, + MCreatorFunction creatorFunction, + MInitializeFunction initFunction, + const MString &classification ); + + static MStatus Deregister( + MFnPlugin &pluginFn, + const MTypeId &mTypeId ); +}; + + +//----------------------------------------------------------------------------- +// +// Decorator class for Valve Maya nodes ( CVsMayaMPxDeformerNodeDecorator ) +// +//----------------------------------------------------------------------------- +template < class T > +class CVsMayaMPxDeformerNodeDecorator : public T +{ +public: + static const MString &Name() { return s_name; }; + + virtual const MString &GetName() const { return Name(); }; + + virtual const MString &GetDesc() const { return s_desc; }; + + static CVsMayaMPxFactoryBase::Type GetType() + { + return s_classification.length() ? CVsMayaMPxFactoryBase::kShaderNode : CVsMayaMPxFactoryBase::kDependencyNode; + } + +private: + template < class U > friend class CVsMayaMPxFactory; + + static const MString s_name; + + static const MString s_desc; + + static const MTypeId s_mTypeId; + + static const MInitializeFunction s_mInitializeFunction; + + static const MString s_classification; + + static void *Create() + { + return new CVsMayaMPxDeformerNodeDecorator< T >; + } + + static MStatus Register( MFnPlugin &pluginFn ) + { + return T::Register( pluginFn, s_name, s_mTypeId, Create, s_mInitializeFunction, s_classification ); + } + + static MStatus Deregister( MFnPlugin &pluginFn ) + { + return T::Deregister( pluginFn, s_mTypeId ); + } +}; + + +//============================================================================= +// +// Helper Macros +// +//============================================================================= + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a command +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXCOMMAND( _class, _name, _desc ) \ + MString CVsMayaMPxCommandDecorator< _class >::s_name( #_name ); \ + MString CVsMayaMPxCommandDecorator< _class >::s_desc( _desc ); \ + ValveMaya::CMSyntaxHelp CVsMayaMPxCommandDecorator< _class >::s_mSyntaxHelp; \ + static CVsMayaMPxFactory< CVsMayaMPxCommandDecorator< _class > > s_##_name##_Factory + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a command +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXTOOLCOMMAND( _class, _name, _desc ) \ + MString CVsMayaMPxToolCommandDecorator< _class >::s_name( #_name ); \ + MString CVsMayaMPxToolCommandDecorator< _class >::s_desc( _desc ); \ + ValveMaya::CMSyntaxHelp CVsMayaMPxToolCommandDecorator< _class >::s_mSyntaxHelp; \ + static CVsMayaMPxFactory< CVsMayaMPxToolCommandDecorator< _class > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a translator +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXFILETRANSLATOR( _class, _name, _guiName, _desc ) \ + const MString CVsMayaMPxFileTranslatorDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxFileTranslatorDecorator< _class >::s_desc( _desc ); \ + const MString CVsMayaMPxFileTranslatorDecorator< _class >::s_guiName( _guiName ); \ + static CVsMayaMPxFactory< CVsMayaMPxFileTranslatorDecorator< _class > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a regular dependency node +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXNODE( _class, _name, _typeId, _initializeFunction, _desc ) \ + const MString CVsMayaMPxNodeDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxNodeDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxNodeDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxNodeDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MString CVsMayaMPxNodeDecorator< _class >::s_classification( "" ); \ + static CVsMayaMPxFactory< CVsMayaMPxNodeDecorator< _class > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a shader dependency node +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXSHADERNODE( _class, _name, _typeId, _initializeFunction, _classification, _desc ) \ + const MString CVsMayaMPxNodeDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxNodeDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxNodeDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxNodeDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MString CVsMayaMPxNodeDecorator< _class >::s_classification( _classification ); \ + static CVsMayaMPxFactory< CVsMayaMPxNodeDecorator< _class > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a transform node +//----------------------------------------------------------------------------- +#if MAYA_API_VERSION >= 200900 + +#define INSTALL_MAYA_MPXTRANSFORM( _class, _name, _typeId, _initializeFunction, _desc ) \ + const MString CVsMayaMPxTransformDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxTransformDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxTransformDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MCreateXformMatrixFunction CVsMayaMPxTransformDecorator< _class >::s_xformMCreatorFunction( MPxTransformationMatrix::creator ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_xformMTypeId( MPxTransformationMatrix::baseTransformationMatrixId ); \ + static CVsMayaMPxFactory< CVsMayaMPxTransformDecorator< _class > > s_##_name##_Factory + +#else // #if MAYA_API_VERSION >= 200900 + +#define INSTALL_MAYA_MPXTRANSFORM( _class, _name, _typeId, _initializeFunction, _desc ) \ + const MString CVsMayaMPxTransformDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxTransformDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxTransformDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MCreatorFunction CVsMayaMPxTransformDecorator< _class >::s_xformMCreatorFunction( MPxTransformationMatrix::creator ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_xformMTypeId( MPxTransformationMatrix::baseTransformationMatrixId ); \ + static CVsMayaMPxFactory< CVsMayaMPxTransformDecorator< _class > > s_##_name##_Factory + +#endif // #if MAYA_API_VERSION >= 200900 + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a transform node with a custom transformation matrix +// TODO: Make CVsMayaMPxTransformationMatrix and create the MCreatorFunction for the user +//----------------------------------------------------------------------------- +#if MAYA_API_VERSION >= 200900 + +#define INSTALL_MAYA_MPXTRANSFORM_WITHMATRIX( _class, _name, _typeId, _initializeFunction, _xformCreatorFunction, _xformTypeId, _desc ) \ + const MString CVsMayaMPxTransformDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxTransformDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxTransformDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MCreateXformMatrixFunction CVsMayaMPxTransformDecorator< _class >::s_xformMCreatorFunction( _xformCreatorFunction ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_xformMTypeId( _xformTypeId ); \ + static CVsMayaMPxFactory< CVsMayaMPxTransformDecorator< _class > > s_##_name##_Factory + +#else // #if MAYA_API_VERSION >= 200900 + +#define INSTALL_MAYA_MPXTRANSFORM_WITHMATRIX( _class, _name, _typeId, _initializeFunction, _xformCreatorFunction, _xformTypeId, _desc ) \ + const MString CVsMayaMPxTransformDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxTransformDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxTransformDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MCreatorFunction CVsMayaMPxTransformDecorator< _class >::s_xformMCreatorFunction( _xformCreatorFunction ); \ + const MTypeId CVsMayaMPxTransformDecorator< _class >::s_xformMTypeId( _xformTypeId ); \ + static CVsMayaMPxFactory< CVsMayaMPxTransformDecorator< _class > > s_##_name##_Factory + +#endif // #if MAYA_API_VERSION >= 200900 + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a locator node +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXLOCATORNODE( _class, _name, _typeId, _initializeFunction, _desc ) \ + const MString CVsMayaMPxLocatorNodeDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxLocatorNodeDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxLocatorNodeDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxLocatorNodeDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + static CVsMayaMPxFactory< CVsMayaMPxLocatorNodeDecorator< _class > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a drag and drop behavior +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXDRAGANDDROPBEHAVIOR( _class, _name, _desc ) \ + const MString CVsMayaMPxDragAndDropBehaviorDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxDragAndDropBehaviorDecorator< _class >::s_desc( _desc ); \ + static CVsMayaMPxFactory< CVsMayaMPxDragAndDropBehaviorDecorator< _class > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a shape node +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXSHAPENODE( _class, _name, _typeId, _initializeFunction, _uiClass, _desc ) \ + const MString CVsMayaMPxShapeNodeDecorator< _class, _uiClass >::s_name( #_name ); \ + const MString CVsMayaMPxShapeNodeDecorator< _class, _uiClass >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxShapeNodeDecorator< _class, _uiClass >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxShapeNodeDecorator< _class, _uiClass >::s_mInitializeFunction( _initializeFunction ); \ + static CVsMayaMPxFactory< CVsMayaMPxShapeNodeDecorator< _class, _uiClass > > s_##_name##_Factory + + +//----------------------------------------------------------------------------- +// Helper macro to instantiate a deformer dependency node +//----------------------------------------------------------------------------- +#define INSTALL_MAYA_MPXDEFORMERNODE( _class, _name, _typeId, _initializeFunction, _desc ) \ + const MString CVsMayaMPxDeformerNodeDecorator< _class >::s_name( #_name ); \ + const MString CVsMayaMPxDeformerNodeDecorator< _class >::s_desc( _desc ); \ + const MTypeId CVsMayaMPxDeformerNodeDecorator< _class >::s_mTypeId( _typeId ); \ + const MInitializeFunction CVsMayaMPxDeformerNodeDecorator< _class >::s_mInitializeFunction( _initializeFunction ); \ + const MString CVsMayaMPxDeformerNodeDecorator< _class >::s_classification( "" ); \ + static CVsMayaMPxFactory< CVsMayaMPxDeformerNodeDecorator< _class > > s_##_name##_Factory + + +#endif // VSMAYAMPXFACTORY_H \ No newline at end of file diff --git a/public/maya/VsVGuiWindow.h b/public/maya/VsVGuiWindow.h new file mode 100644 index 0000000..e33446d --- /dev/null +++ b/public/maya/VsVGuiWindow.h @@ -0,0 +1,195 @@ +//===== Copyright 1996-2006, Valve Corporation, All rights reserved. ======// +// +// Base class for windows that draw vgui in Maya +// +//===========================================================================// + +#ifndef VSVGUIWINDOW_H +#define VSVGUIWINDOW_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "imayavgui.h" +#include "vgui_controls/Frame.h" +#include "tier1/utlmap.h" +#include "valveMaya.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMayaVGui; + + +//----------------------------------------------------------------------------- +// The singleton is defined here twice just so we don't have to include valvemaya.h also +//----------------------------------------------------------------------------- +extern IMayaVGui *g_pMayaVGui; + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class EditablePanel; +} + + +class CVsVGuiWindowBase +{ +public: + virtual void SetPeriod( float flPeriod ) = 0; + virtual void StartTick() = 0; + virtual void StartTick( float flPeriod ) = 0; + virtual void StopTick() = 0; + virtual void Tick( float flElapsedTime ) = 0; + virtual void NonTimerTick() = 0; +}; + + +//----------------------------------------------------------------------------- +// Creates, destroys a maya vgui window +//----------------------------------------------------------------------------- +CVsVGuiWindowBase *CreateMayaVGuiWindow( vgui::EditablePanel *pRootPanel, const char *pPanelName ); +void DestroyMayaVGuiWindow( const char *pPanelName ); + + +//----------------------------------------------------------------------------- +// Factory used to install vgui windows easily +//----------------------------------------------------------------------------- +class CVsVguiWindowFactoryBase : public IMayaVguiWindowFactory +{ +public: + CVsVguiWindowFactoryBase( const char *pWindowTypeName, const char *pDccStartupCommand ); + + // Returns the DCC command + const char *GetDccStartupCommand() const; + + // Registers/deregisters all vgui windows + static void RegisterAllVguiWindows( ); + static void UnregisterAllVguiWindows( ); + +protected: + const char *m_pWindowTypeName; + const char *m_pDccStartupCommand; + +private: + CVsVguiWindowFactoryBase *m_pNext; + static CVsVguiWindowFactoryBase *s_pFirstCommandFactory; +}; + +template< class T > +class CVsVguiWindowFactory : public CVsVguiWindowFactoryBase +{ + typedef CVsVguiWindowFactoryBase BaseClass; + + static bool StringLessFunc( const CUtlString &a, const CUtlString &b ) + { + return StringLessThan( a.Get(), b.Get() ); + } + + +public: + CVsVguiWindowFactory( const char *pWindowTypeName, const char *pDccCommand ) + : BaseClass( pWindowTypeName, pDccCommand ) + , m_panelMap( StringLessFunc ) + { + } + + struct PanelMapElem_s + { + CVsVGuiWindowBase *m_pVGuiWindow; + T *m_pPanel; + }; + + typedef CUtlMap< CUtlString, PanelMapElem_s > PanelMap_t; + + virtual void CreateVguiWindow( const char *pPanelName ) + { + T *pVGuiPanel = new T( NULL, pPanelName ); + vgui::Frame *pFrame = dynamic_cast< vgui::Frame * >( pVGuiPanel ); + + if ( pFrame ) + { + pFrame->SetSizeable( false ); + pFrame->SetCloseButtonVisible( false ); + pFrame->SetMoveable( false ); + + CVsVGuiWindowBase *pVGuiWindow = CreateMayaVGuiWindow( pVGuiPanel, pPanelName ); + + const CUtlString panelName( pPanelName ); + + PanelMap_t::IndexType_t nIndex = m_panelMap.Find( panelName ); + if ( m_panelMap.IsValidIndex( nIndex ) ) + { + merr << "[vsVguiWindow]: Panel \"" << pPanelName << "\" of Type: \"" << m_pWindowTypeName << "\" Already Exists!!!" << std::endl; + } + else + { + PanelMap_t::ElemType_t &element = m_panelMap.Element( m_panelMap.Insert( panelName ) ); + element.m_pVGuiWindow = pVGuiWindow; + element.m_pPanel = pVGuiPanel; + } + } + } + + virtual void DestroyVguiWindow( const char *pPanelName ) + { + PanelMap_t::IndexType_t nIndex = m_panelMap.Find( pPanelName ); + if ( !m_panelMap.IsValidIndex( nIndex ) ) + return; + + PanelMap_t::ElemType_t &element = m_panelMap.Element( nIndex ); + delete element.m_pPanel; + + m_panelMap.Remove( CUtlString( pPanelName ) ); + DestroyMayaVGuiWindow( pPanelName ); + } + + virtual vgui::Frame *GetVGuiPanel( const char *pPanelName = NULL ) + { + if ( pPanelName ) + { + PanelMap_t::IndexType_t nPanelIndex = m_panelMap.Find( CUtlString( pPanelName ) ); + if ( m_panelMap.IsValidIndex( nPanelIndex ) ) + return dynamic_cast< vgui::Frame * >( m_panelMap.Element( nPanelIndex ).m_pPanel ); + } + else if ( m_panelMap.Count() > 0 ) + { + return dynamic_cast< vgui::Frame * >( m_panelMap.Element( m_panelMap.FirstInorder() ).m_pPanel ); + } + + return NULL; + } + + virtual CVsVGuiWindowBase *GetVGuiWindow( const char *pPanelName = NULL ) + { + if ( pPanelName ) + { + PanelMap_t::IndexType_t nPanelIndex = m_panelMap.Find( CUtlString( pPanelName ) ); + if ( m_panelMap.IsValidIndex( nPanelIndex ) ) + return m_panelMap.Element( nPanelIndex ).m_pVGuiWindow; + } + else if ( m_panelMap.Count() > 0 ) + { + return m_panelMap.Element( m_panelMap.FirstInorder() ).m_pVGuiWindow; + } + + return NULL; + } + +private: + + PanelMap_t m_panelMap; +}; + + +#define INSTALL_MAYA_VGUI_WINDOW( _className, _windowTypeName, _dccCommand ) \ + static CVsVguiWindowFactory< _className > s_VsVguiWindowFactory##_className##( _windowTypeName, _dccCommand ) + + +#endif // VSVGUIWINDOW_H diff --git a/public/maya/valveMaya.h b/public/maya/valveMaya.h new file mode 100644 index 0000000..036ab2f --- /dev/null +++ b/public/maya/valveMaya.h @@ -0,0 +1,672 @@ +//======= Copyright 1996-2006, Valve Corporation, All rights reserved. ====== +// +// Purpose: +// +//============================================================================= + +#ifndef VALVEMAYA_H +#define VALVEMAYA_H + +#if defined( _WIN32 ) +#pragma once +#endif + +// Maya Includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Valve Includes + +#include "tier1/stringpool.h" +#include "tier1/utlstring.h" +#include "tier1/utlstringmap.h" +#include "tier1/utlvector.h" +#include "tier1/interface.h" +#include "mathlib/mathlib.h" + +#include "ValveMaya/Undo.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMayaVGui; + + +//----------------------------------------------------------------------------- +// Maya-specific library singletons +//----------------------------------------------------------------------------- +extern IMayaVGui *g_pMayaVGui; + + +//----------------------------------------------------------------------------- +// +// Purpose: Group a bunch of functions into the Valve Maya Namespace +// +//----------------------------------------------------------------------------- + + +namespace ValveMaya +{ + //----------------------------------------------------------------------------- + // Forward declarations + //----------------------------------------------------------------------------- + class CUndo; + + //----------------------------------------------------------------------------- + // Statics + //----------------------------------------------------------------------------- + extern const MQuaternion v2mQuat; // Valve Engine -> Maya Quaternion + extern const MQuaternion m2vQuat; // Maya -> Valve Engine Quaternion + extern const MMatrix v2mMat; // Valve Engine -> Maya Matrix + extern const MMatrix m2vMat; // Maya -> Valve Engine Matrix + + extern const MQuaternion vc2mcQuat; // Valve Engine Camera -> Maya Camera Quaternion + extern const MQuaternion mc2vcQuat; // Maya Camera -> Valve Camera Engine Quaternion + extern const MMatrix vc2mcMat; // Valve Engine Camera -> Maya Camera Quaternion + extern const MMatrix mc2vcMat; // Maya Camera -> Valve Camera Engine Quaternion + + inline MQuaternion ValveToMaya( const MQuaternion &q ) { return q * v2mQuat; } + inline MQuaternion ValveCameraToMayaCamera( const MQuaternion &q ) { return vc2mcQuat * q * v2mQuat; } + inline MQuaternion MayaToValve( const MQuaternion &q ) { return q * m2vQuat; } + inline MQuaternion MayaCameraToValveCamera( const MQuaternion &q ) { return mc2vcQuat * q * m2vQuat; } + + inline MVector ValveToMaya( const MVector &p ) { return p.rotateBy( v2mQuat ); } + inline MVector ValveCameraToMayaCamera( const MVector &p ) { return p.rotateBy( v2mQuat ); } + inline MVector MayaToValve( const MVector &p ) { return p.rotateBy( m2vQuat ); } + inline MVector MayaCameraToValveCamera( const MVector &p ) { return p.rotateBy( m2vQuat ); } + +//----------------------------------------------------------------------------- +// Connect, disconnect +//----------------------------------------------------------------------------- +bool ConnectLibraries( CreateInterfaceFn factory ); +void DisconnectLibraries(); + +MStatus CreateDagNode( + const char *const i_nodeType, + const char *const i_transformName = NULL, + const MObject &i_parentObj = MObject::kNullObj, + MObject *o_pTransformObj = NULL, + MObject *o_pShapeObj = NULL, + MDagModifier *i_mDagModifier = NULL); + +inline MStatus CreateDagNode( + CUndo &undo, + const char *const i_nodeType, + const char *const i_transformName = NULL, + const MObject &i_parentObj = MObject::kNullObj, + MObject *o_pTransformObj = NULL, + MObject *o_pShapeObj = NULL ) +{ + return CreateDagNode( i_nodeType, i_transformName, i_parentObj, o_pTransformObj, o_pShapeObj, &undo.DagModifier() ); +} + +bool IsNodeVisible( const MDagPath &mDagPath, bool bTemplateAsInvisible = true ); +bool IsPathVisible( MDagPath mDagPath, bool bTemplateAsInvisible = true ); + +class CMSyntaxHelp +{ +public: + CMSyntaxHelp() + : m_groupedHelp( false ) // Make case sensitive + , m_helpCount( 0 ) + , m_shortNameLength( 0 ) + {} + + void Clear(); + + MStatus AddFlag( + MSyntax &i_mSyntax, + const char *i_shortName, + const char *i_longName, + const char *i_group, + const char *i_help, + const MSyntax::MArgType i_argType1 = MSyntax::kNoArg, + const MSyntax::MArgType i_argType2 = MSyntax::kNoArg, + const MSyntax::MArgType i_argType3 = MSyntax::kNoArg, + const MSyntax::MArgType i_argType4 = MSyntax::kNoArg, + const MSyntax::MArgType i_argType5 = MSyntax::kNoArg, + const MSyntax::MArgType i_argType6 = MSyntax::kNoArg); + + void PrintHelp( + const char *const i_cmdName, + const char *const i_cmdDesc, + int i_lineLength = 0U); + + void PrintHelp( + const MString &i_cmdName, + const MString &i_cmdDesc, + int i_lineLength = 0U) + { + PrintHelp( i_cmdName.asChar(), i_cmdDesc.asChar(), i_lineLength ); + } + +protected: +public: +protected: + CCountedStringPool m_stringPool; + + struct HelpData_t + { + const char *m_shortName; + const char *m_longName; + const char *m_help; + CUtlVector m_argTypes; + }; + + CUtlVector m_groupOrder; + CUtlStringMap > m_groupedHelp; + int m_helpCount; + int m_shortNameLength; +}; + +MString RemoveNameSpace( const MString &mString ); + +MString &BackslashToSlash( MString &mString ); + +template < class T_t > bool IsDefault( T_t &, const MPlug & ); + +bool IsDefault( const MPlug &aPlug ); + +uint NextAvailable( MPlug &mPlug ); + +MPlug NextAvailablePlug( MPlug &mPlug ); + +MObject AddColorSetToMesh( + const MString &colorSetName, + const MDagPath &mDagPath, + MDagModifier &mDagModifier ); + +MString GetMaterialPath( + const MObject &shadingGroupObj, + MObject *pSurfaceShaderObj, + MObject *pFileObj, + MObject *pPlace2dTextureObj, + MObject *pVmtObj, + bool *pbTransparent, + MString *pDebugWhy ); + +// Returns the first node that is connected to the specified plug as input or output +MObject FindConnectedNode( const MPlug &mPlug ); + +// Returns the plug connected to the specified plug as an input, a NULL plug if no plug is connected +MPlug FindInputPlug( const MPlug &dstPlug ); + +MPlug FindInputPlug( const MObject &dstNodeObj, const MString &dstPlugName ); + +MObject FindInputNode( const MPlug &dstPlug ); + +MObject FindInputNode( const MObject &dstNodeObj, const MString &dstPlugName ); + +MObject FindInputAttr( const MPlug &dstPlug ); + +MObject FindInputAttr( const MObject &dstNodeObj, const MString &dstPlugName ); + +// Returns the first found node MObject of the specified type in the history of the specified node +MObject FindInputNodeOfType( const MObject &dstNodeObj, const MString &typeName, const MString &dstPlugName ); + +MObject FindInputNodeOfType( const MObject &dstNodeObj, const MString &typeName, MSelectionList &doneList ); + +// Creates a deformer of the specified type and deforms the specified shape with an optional component +MObject DeformShape( ValveMaya::CUndo &undo, const MString &deformerType, const MDagPath &inOrigDagPath, MObject &origCompObj = MObject::kNullObj ); + +bool Substitute( MString &str, const MString &searchStr, const MString &replaceStr ); + +bool SubstituteCaseInsensitive( MString &str, const MString &searchStr, const MString &replaceStr ); + +bool SubstituteAll( MString &str, const MString &searchStr, const MString &replaceStr ); + +bool SubstituteAllCaseInsensitive( MString &str, const MString &searchStr, const MString &replaceStr ); + +void FixSlashes( MString &str, char correctPathSeparator = '/' ); + +//----------------------------------------------------------------------------- +// Converts a Maya MMatrix to a Valve matrix3x4_t (transpose) +//----------------------------------------------------------------------------- +inline void MatrixMayaToValve( matrix3x4_t &mValve, const MMatrix &mMaya ) +{ + mValve[0][0] = mMaya[0][0]; mValve[0][1] = mMaya[1][0]; mValve[0][2] = mMaya[2][0]; mValve[0][3] = mMaya[3][0]; + mValve[1][0] = mMaya[0][1]; mValve[1][1] = mMaya[1][1]; mValve[1][2] = mMaya[2][1]; mValve[1][3] = mMaya[3][1]; + mValve[2][0] = mMaya[0][2]; mValve[2][1] = mMaya[1][2]; mValve[2][2] = mMaya[2][2]; mValve[2][3] = mMaya[3][2]; +} + + +//----------------------------------------------------------------------------- +// Converts a Valve matrix3x4_t to a Maya MMatrix (transpose) +//----------------------------------------------------------------------------- +inline void MatrixValveToMaya( MMatrix &mMaya, const matrix3x4_t &mValve ) +{ + mMaya[0][0] = mValve[0][0]; mMaya[0][1] = mValve[1][0]; mMaya[0][2] = mValve[2][0]; mMaya[3][0] = 0.0; + mMaya[1][0] = mValve[0][1]; mMaya[1][1] = mValve[1][1]; mMaya[1][2] = mValve[2][1]; mMaya[3][1] = 0.0; + mMaya[2][0] = mValve[0][2]; mMaya[2][1] = mValve[1][2]; mMaya[2][2] = mValve[2][2]; mMaya[3][2] = 0.0; + mMaya[3][0] = mValve[0][3]; mMaya[3][1] = mValve[1][3]; mMaya[3][2] = mValve[2][3]; mMaya[3][3] = 1.0; +} + + +//----------------------------------------------------------------------------- +// Converts a Maya MVector to a Valve Vector +//----------------------------------------------------------------------------- +inline void VectorMayaToValve( Vector &vValve, const MVector &vMaya ) +{ + vValve.x = vMaya.x; + vValve.y = vMaya.y; + vValve.z = vMaya.z; +} + + +//----------------------------------------------------------------------------- +// Converts a Valve Vector to a Maya MVector +//----------------------------------------------------------------------------- +inline void VectorValveToMaya( MVector &vMaya, const Vector &vValve ) +{ + vMaya.x = vValve.x; + vMaya.y = vValve.y; + vMaya.z = vValve.z; +} + + +//----------------------------------------------------------------------------- +// Converts a Maya MQuaternion to a Valve Quaternion +//----------------------------------------------------------------------------- +inline void QuaternionMayaToValve( Quaternion &qValve, const MQuaternion &qMaya ) +{ + qValve.x = qMaya.x; + qValve.y = qMaya.y; + qValve.z = qMaya.z; + qValve.w = qMaya.w; +} + + +//----------------------------------------------------------------------------- +// Converts a Maya MQuaternion to a Valve Quaternion +//----------------------------------------------------------------------------- +inline void QuaternionMayaToValve( Quaternion &qValve, const MEulerRotation &eMaya ) +{ + const MQuaternion qMaya = eMaya.asQuaternion(); + + qValve.x = qMaya.x; + qValve.y = qMaya.y; + qValve.z = qMaya.z; + qValve.w = qMaya.w; +} + + +//----------------------------------------------------------------------------- +// Converts a Valve Quaternion to a Maya MQuaternion +//----------------------------------------------------------------------------- +inline void QuaternionValveToMaya( MQuaternion &qMaya, const Quaternion &qValve ) +{ + qMaya.x = qValve.x; + qMaya.y = qValve.y; + qMaya.z = qValve.z; + qMaya.w = qValve.w; +} + + +//----------------------------------------------------------------------------- +// Converts a Valve Quaternion to a Maya MQuaternion +//----------------------------------------------------------------------------- +inline void QuaternionValveToMaya( MEulerRotation &eMaya, const Quaternion &qValve ) +{ + MQuaternion qMaya; + QuaternionValveToMaya( qMaya, qValve ); + + const MEulerRotation::RotationOrder roTmp = eMaya.order; + + eMaya = qMaya; + + if ( eMaya.order != roTmp ) + { + eMaya.reorder( roTmp ); + } +} + + +//----------------------------------------------------------------------------- +// Converts a Maya MEulerRotation to a Valve RadianEuler +//----------------------------------------------------------------------------- +inline void RadianEulerMayaToValve( RadianEuler &eValve, const MEulerRotation &eMaya ) +{ + if ( eMaya.order == MEulerRotation::kXYZ ) + { + eValve.x = eMaya.x; + eValve.y = eMaya.y; + eValve.z = eMaya.z; + } + else + { + MEulerRotation eTmp = eMaya; + eTmp.reorder( MEulerRotation::kXYZ ); + + eValve.x = eTmp.x; + eValve.y = eTmp.y; + eValve.z = eTmp.z; + } +} + + +//----------------------------------------------------------------------------- +// Converts a Valve RadianEuler to a Maya MEulerRotation +//----------------------------------------------------------------------------- +inline void RadianEulerValveToMaya( MEulerRotation &eMaya, const RadianEuler &eValve ) +{ + const MEulerRotation::RotationOrder roTmp = eMaya.order; + + if ( roTmp == MEulerRotation::kXYZ ) + { + eMaya.x = eValve.x; + eMaya.y = eValve.y; + eMaya.z = eValve.z; + } + else + { + eMaya.reorder( MEulerRotation::kXYZ ); + + eMaya.x = eValve.x; + eMaya.y = eValve.y; + eMaya.z = eValve.z; + + eMaya.reorder( roTmp ); + } +} + + +} // end namespace ValveMaya + + +// Make an alias for the ValveMaya namespace + +namespace vm = ValveMaya; + + +//----------------------------------------------------------------------------- +// A simple stream class for printing information to the Maya script editor +//----------------------------------------------------------------------------- +class CMayaStream +{ +public: + enum StreamType { kInfo, kWarning, kError }; + + CMayaStream( const StreamType i_streamType = kInfo ) + : m_streamType( i_streamType ) + {} + + template < class T_t > + CMayaStream &operator<<( const T_t &v ); + + // This is a hack so CMayaStream << std::endl works as expected + CMayaStream &operator<<( std::ostream &(*StdEndl_t)( std::ostream & ) ) + { + return flush(); + } + + CMayaStream &flush() { return outputString(); } + +protected: + CMayaStream &outputString() + { + // Always ensure it's terminated with a newline + if ( *( m_string.asChar() + m_string.length() - 1 ) != '\n' ) + { + m_string += "\n"; + } + + const char *pBegin = m_string.asChar(); + const char *const pEnd = pBegin + m_string.length(); + const char *pCurr = pBegin; + + while ( *pCurr && pCurr < pEnd ) + { + if ( *pCurr == '\n' ) + { + switch ( m_streamType ) + { + case kWarning: + MGlobal::displayWarning( MString( pBegin, pCurr - pBegin ) ); + break; + case kError: + MGlobal::displayError( MString( pBegin, pCurr - pBegin ) ); + break; + default: + MGlobal::displayInfo( MString( pBegin, pCurr - pBegin ) ); + break; + } + + ++pCurr; + pBegin = pCurr; + } + else + { + ++pCurr; + } + } + + m_string.clear(); + + return *this; + } + + CMayaStream &checkForFlush() + { + const char *pCurr = m_string.asChar(); + const char *pEnd = pCurr + m_string.length(); + while ( *pCurr && pCurr != pEnd ) + { + if ( *pCurr == '\n' ) + { + return outputString(); + } + + ++pCurr; + } + + return *this; + } + + StreamType m_streamType; + MString m_string; +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CMayaWarnStream : public CMayaStream +{ +public: + CMayaWarnStream() + : CMayaStream( CMayaStream::kWarning ) + {} + +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CMayaErrStream : public CMayaStream +{ +public: + CMayaErrStream() + : CMayaStream( CMayaStream::kError ) + {} +}; + + +//----------------------------------------------------------------------------- +// Specialization for std::string +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const std::string &v ) +{ + *this << v.c_str(); + return *this; +} + + +//----------------------------------------------------------------------------- +// Specialization for char +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const char &v ) +{ + m_string += MString( &v, 1 ); + return *this; +} + + +//----------------------------------------------------------------------------- +// Specialization for MVector +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const MVector &v ) +{ + m_string += v.x; + m_string += " "; + m_string += v.y; + m_string += " "; + m_string += v.z; + return *this; +} + + +//----------------------------------------------------------------------------- +// Specialization for MFloatVector +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const MFloatVector &v ) +{ + m_string += v.x; + m_string += " "; + m_string += v.y; + m_string += " "; + m_string += v.z; + return *this; +} + + +//----------------------------------------------------------------------------- +// Specialization for MEulerRotation +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const MEulerRotation &e ) +{ + m_string += MAngle( e.x, MAngle::kRadians ).asDegrees(); + m_string += " "; + m_string += MAngle( e.y, MAngle::kRadians ).asDegrees(); + m_string += " "; + m_string += MAngle( e.z, MAngle::kRadians ).asDegrees(); + switch ( e.order ) + { + case MEulerRotation::kXYZ: + m_string += " (XYZ)"; + break; + case MEulerRotation::kXZY: + m_string += " (XZY)"; + break; + case MEulerRotation::kYXZ: + m_string += " (YXZ)"; + break; + case MEulerRotation::kYZX: + m_string += " (YZX)"; + break; + case MEulerRotation::kZXY: + m_string += " (ZXY)"; + break; + case MEulerRotation::kZYX: + m_string += " (ZYX)"; + break; + default: + m_string += " (Unknown)"; + break; + } + return *this; +} + + +//----------------------------------------------------------------------------- +// Specialization for MQuaternion +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const MQuaternion &q ) +{ + m_string += q.x; + m_string += " "; + m_string += q.y; + m_string += " "; + m_string += q.z; + m_string += " "; + m_string += q.w; + + m_string += " ("; + operator<<( q.asEulerRotation() ); + m_string += ")"; + + return *this; +} + + +//----------------------------------------------------------------------------- +// Specialization for Quaternion +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const Quaternion &q ) +{ + return operator<<( MQuaternion( q.x, q.y, q.z, q.w ) ); +} + + +//----------------------------------------------------------------------------- +// Specialization for RadianEuler +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const RadianEuler &e ) +{ + return operator<<( MEulerRotation( e.x, e.y, e.z ) ); +} + +//----------------------------------------------------------------------------- +// Specialization for RadianEuler +//----------------------------------------------------------------------------- +template <> +inline CMayaStream &CMayaStream::operator<<( const Vector &v ) +{ + return operator<<( MVector( v.x, v.y, v.z ) ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +template < class T_t > +inline CMayaStream &CMayaStream::operator<<( const T_t &v ) +{ + m_string += v; + return checkForFlush(); +} + + +//----------------------------------------------------------------------------- +// +// minfo, mwarn & merr are ostreams which can be used to send stuff to +// the Maya history window +// +//----------------------------------------------------------------------------- + +extern CMayaStream minfo; +extern CMayaWarnStream mwarn; +extern CMayaErrStream merr; + + +#endif // VALVEMAYA_H diff --git a/public/mdllib/mdllib.h b/public/mdllib/mdllib.h new file mode 100644 index 0000000..7d86f23 --- /dev/null +++ b/public/mdllib/mdllib.h @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef MDLLIB_H +#define MDLLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlbuffer.h" +#include "appframework/IAppSystem.h" + +// +// Forward interface declarations +// +abstract_class IMdlLib; + +abstract_class IMdlStripInfo; + + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing model data operations +//----------------------------------------------------------------------------- +#define MDLLIB_INTERFACE_VERSION "VMDLLIB001" + +abstract_class IMdlLib : public IAppSystem +{ + // + // Stripping routines + // +public: + + // + // StripModelBuffers + // The main function that strips the model buffers + // mdlBuffer - mdl buffer, updated, no size change + // vvdBuffer - vvd buffer, updated, size reduced + // vtxBuffer - vtx buffer, updated, size reduced + // ppStripInfo - if nonzero on return will be filled with the stripping info + // + virtual bool StripModelBuffers( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, IMdlStripInfo **ppStripInfo ) = 0; + + // + // CreateNewStripInfo + // Creates an empty strip info or resets an existing strip info so that it can be reused. + // + virtual bool CreateNewStripInfo( IMdlStripInfo **ppStripInfo ) = 0; + +}; + + +abstract_class IMdlStripInfo +{ + // + // Serialization + // +public: + // Save the strip info to the buffer (appends to the end) + virtual bool Serialize( CUtlBuffer &bufStorage ) const = 0; + + // Load the strip info from the buffer (reads from the current position as much as needed) + virtual bool UnSerialize( CUtlBuffer &bufData ) = 0; + + // + // Stripping info state + // +public: + // Returns the checksums that the stripping info was generated for: + // plChecksumOriginal if non-NULL will hold the checksum of the original model submitted for stripping + // plChecksumStripped if non-NULL will hold the resulting checksum of the stripped model + virtual bool GetCheckSum( long *plChecksumOriginal, long *plChecksumStripped ) const = 0; + + // + // Stripping + // +public: + + // + // StripHardwareVertsBuffer + // The main function that strips the vhv buffer + // vhvBuffer - vhv buffer, updated, size reduced + // + virtual bool StripHardwareVertsBuffer( CUtlBuffer &vhvBuffer ) = 0; + + // + // StripModelBuffer + // The main function that strips the mdl buffer + // mdlBuffer - mdl buffer, updated + // + virtual bool StripModelBuffer( CUtlBuffer &mdlBuffer ) = 0; + + // + // StripVertexDataBuffer + // The main function that strips the vvd buffer + // vvdBuffer - vvd buffer, updated, size reduced + // + virtual bool StripVertexDataBuffer( CUtlBuffer &vvdBuffer ) = 0; + + // + // StripOptimizedModelBuffer + // The main function that strips the vtx buffer + // vtxBuffer - vtx buffer, updated, size reduced + // + virtual bool StripOptimizedModelBuffer( CUtlBuffer &vtxBuffer ) = 0; + + // + // Release the object with "delete this" + // +public: + virtual void DeleteThis() = 0; +}; + + + +#endif // MDLLIB_H diff --git a/public/measure_section.cpp b/public/measure_section.cpp new file mode 100644 index 0000000..e43a16a --- /dev/null +++ b/public/measure_section.cpp @@ -0,0 +1,271 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#include +#include +#include "basetypes.h" +#include "measure_section.h" +#include "convar.h" + + +// Static members +CMeasureSection *CMeasureSection::s_pSections = 0; +int CMeasureSection::s_nCount = 0; +double CMeasureSection::m_dNextResort = 0.0; + +ConVar measure_resort( "measure_resort", "1.0", 0, "How often to re-sort profiling sections\n" ); +ConVar game_speeds( "game_speeds","0" ); +extern ConVar host_speeds; + +//----------------------------------------------------------------------------- +// Purpose: Creates a profiling section +// Input : *name - name of the section ( allocated on stack hopefully ) +//----------------------------------------------------------------------------- +CMeasureSection::CMeasureSection( const char *name ) +{ + // Just point at name since it's static + m_pszName = name; + + // Clear accumulators + Reset(); + SortReset(); + m_dMaxTime.Init(); + + // Link into master list + m_pNext = s_pSections; + s_pSections = this; + // Update count + s_nCount++; +} + +//----------------------------------------------------------------------------- +// Purpose: Destroys the object +//----------------------------------------------------------------------------- +CMeasureSection::~CMeasureSection( void ) +{ + m_pNext = NULL; + s_nCount--; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMeasureSection::UpdateMax( void ) +{ + if (m_dMaxTime.IsLessThan(m_dAccumulatedTime)) + { + m_dMaxTime.Init(); + CCycleCount::Add(m_dMaxTime,m_dAccumulatedTime,m_dMaxTime); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMeasureSection::Reset( void ) +{ + m_dAccumulatedTime.Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMeasureSection::SortReset( void ) +{ + m_dTotalTime.Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char *CMeasureSection::GetName( void ) +{ + return m_pszName; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CCycleCount const& CMeasureSection::GetTotalTime( void ) +{ + return m_dTotalTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CCycleCount const& CMeasureSection::GetTime( void ) +{ + return m_dAccumulatedTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +CCycleCount const& CMeasureSection::GetMaxTime( void ) +{ + return m_dMaxTime; +} + +//----------------------------------------------------------------------------- +// Purpose: Accumulates a timeslice +// Input : time - +//----------------------------------------------------------------------------- +void CMeasureSection::AddTime( CCycleCount const &rCount ) +{ + CCycleCount::Add(m_dAccumulatedTime, rCount, m_dAccumulatedTime); + CCycleCount::Add(m_dTotalTime, rCount, m_dTotalTime); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CMeasureSection +//----------------------------------------------------------------------------- +CMeasureSection *CMeasureSection::GetNext( void ) +{ + return m_pNext; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CMeasureSection +//----------------------------------------------------------------------------- +CMeasureSection *CMeasureSection::GetList( void ) +{ + return s_pSections; +} + +//----------------------------------------------------------------------------- +// Purpose: Compares accumulated time for two sections +// Input : ppms1 - +// ppms2 - +// Output : static int +//----------------------------------------------------------------------------- +static int SectionCompare( const void* ppms1,const void* ppms2 ) +{ + CMeasureSection* pms1 = *(CMeasureSection**)ppms1; + CMeasureSection* pms2 = *(CMeasureSection**)ppms2; + + if ( pms1->GetTotalTime().IsLessThan(pms2->GetTotalTime()) ) + return 1; + else + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: Sorts sections by time usage +//----------------------------------------------------------------------------- +void CMeasureSection::SortSections( void ) +{ + // Not enough to be sortable + if ( s_nCount <= 1 ) + return; + + CMeasureSection *sortarray[ 128 ]; + CMeasureSection *ms; + + memset(sortarray,sizeof(CMeasureSection*)*128,0); + + ms = GetList(); + int i; + int c = 0; + while ( ms ) + { + sortarray[ c++ ] = ms; + ms = ms->GetNext(); + } + + // Sort the array alphabetically + qsort( sortarray, c , sizeof( CMeasureSection * ), SectionCompare ); + + // Fix next pointers + for ( i = 0; i < c-1; i++ ) + { + sortarray[ i ]->m_pNext = sortarray[ i + 1 ]; + } + sortarray[i]->m_pNext = NULL; + + // Point head of list at it + s_pSections = sortarray[ 0 ]; +} + +//----------------------------------------------------------------------------- +// Purpose: Creates an instance for timing a section +// Input : *ms - +//----------------------------------------------------------------------------- +CMeasureSectionInstance::CMeasureSectionInstance( CMeasureSection *ms ) +{ + // Remember where to put accumulated time + m_pMS = ms; + + if ( host_speeds.GetInt() < 3 && !game_speeds.GetInt()) + return; + + // Get initial timestamp + m_Timer.Start(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMeasureSectionInstance::~CMeasureSectionInstance( void ) +{ + if ( host_speeds.GetInt() < 3 && !game_speeds.GetInt()) + return; + + // Get final timestamp + m_Timer.End(); + + // Add time to section + m_pMS->AddTime( m_Timer.GetDuration() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Re-sort all data and determine whether sort keys should be reset too ( after +// re-doing sort if needed ). +//----------------------------------------------------------------------------- +void ResetTimeMeasurements( void ) +{ +#if defined( _DEBUG ) || defined( FORCE_MEASURE ) + bool sort_reset = false; + + // Time to redo sort? + if ( measure_resort.GetFloat() > 0.0 && + GetRealTime() >= CMeasureSection::m_dNextResort ) + { + // Redo it + CMeasureSection::SortSections(); + // Set next time + CMeasureSection::m_dNextResort = GetRealTime() + measure_resort.GetFloat(); + // Flag to reset sort accumulator, too + sort_reset = true; + } + + // Iterate through the sections now + CMeasureSection *p = CMeasureSection::GetList(); + while ( p ) + { + // Reset regular accum. + p->Reset(); + // Reset sort accum less often + if ( sort_reset ) + { + p->SortReset(); + } + p = p->GetNext(); + } +#endif +} \ No newline at end of file diff --git a/public/measure_section.h b/public/measure_section.h new file mode 100644 index 0000000..4fb2362 --- /dev/null +++ b/public/measure_section.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( MEASURE_SECTION_H ) +#define MEASURE_SECTION_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/fasttimer.h" +#include "convar.h" + + +// This is the macro to use in your code to measure until the code goes +// out of scope +#if defined( _DEBUG ) || defined( FORCE_MEASURE ) +#define MEASURECODE( description ) \ + static CMeasureSection _xxx_ms( description ); \ + CMeasureSectionInstance _xxx_ms_inst( &_xxx_ms ); +#else +#define MEASURECODE( description ) +#endif + + +// ------------------------------------------------------------------------------------ // +// These things must exist in the executable for the CMeasureSection code to work. +// ------------------------------------------------------------------------------------ // +float GetRealTime(); // Get the clock's time. + +extern ConVar game_speeds; +extern ConVar measure_resort; +// ------------------------------------------------------------------------------------ // + + + +// Called once per frame to allow any necessary measurements to latch +void ResetTimeMeasurements( void ); + +//----------------------------------------------------------------------------- +// Purpose: Accumulates time for the named section +//----------------------------------------------------------------------------- +class CMeasureSection +{ +public: + // Allows for measuring named section + CMeasureSection( const char *name ); + virtual ~CMeasureSection( void ); + + + // Update max value hit + void UpdateMax( void ); + // Reset totals + void Reset( void ); + // Reset sortable totals + void SortReset( void ); + // Get static name of section + const char *GetName( void ); + + // Get accumulated time + CCycleCount const& GetTotalTime( void ); + + CCycleCount const& GetTime(); + + CCycleCount const& GetMaxTime(); + + // Add in some time + void AddTime( CCycleCount const &rCount ); + + // Get next section in chain + CMeasureSection *GetNext( void ); + + // Get head of list of all sections + static CMeasureSection *GetList( void ); + // Sort all sections by most time consuming + static void SortSections( void ); + +public: + // Time when list should be sorted again + static double m_dNextResort; + +private: + // Accumulated time for section + CCycleCount m_dAccumulatedTime; + + // Max time for section + CCycleCount m_dMaxTime; + + // Elapsed time for section + CCycleCount m_dTotalTime; + + // Name of section + const char *m_pszName; + // Next section in chain + CMeasureSection *m_pNext; + // Head of section list + static CMeasureSection *s_pSections; + // Quick total for doing sorts faster + static int s_nCount; +}; + +//----------------------------------------------------------------------------- +// Purpose: On construction marks time and on destruction adds time to +// parent CMeasureSection object +//----------------------------------------------------------------------------- +class CMeasureSectionInstance +{ +public: + // Constructor: Points to object to accumulate time into + CMeasureSectionInstance( CMeasureSection *ms ); + // Destructor: Latches accumulated time + virtual ~CMeasureSectionInstance( void ); + +private: + // Time of construction + CFastTimer m_Timer; + + // Where to place elapsed time + CMeasureSection *m_pMS; +}; + +#endif // MEASURE_SECTION_H \ No newline at end of file diff --git a/public/minmax.h b/public/minmax.h new file mode 100644 index 0000000..e8c017d --- /dev/null +++ b/public/minmax.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MINMAX_H +#define MINMAX_H + +#ifndef vmin +#define vmin(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef vmax +#define vmax(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif // MINMAX_H diff --git a/public/model_types.h b/public/model_types.h new file mode 100644 index 0000000..54f3891 --- /dev/null +++ b/public/model_types.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( MODEL_TYPES_H ) +#define MODEL_TYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#define STUDIO_NONE 0x00000000 +#define STUDIO_RENDER 0x00000001 +#define STUDIO_VIEWXFORMATTACHMENTS 0x00000002 +#define STUDIO_DRAWTRANSLUCENTSUBMODELS 0x00000004 +#define STUDIO_TWOPASS 0x00000008 +#define STUDIO_STATIC_LIGHTING 0x00000010 +#define STUDIO_WIREFRAME 0x00000020 +#define STUDIO_ITEM_BLINK 0x00000040 +#define STUDIO_NOSHADOWS 0x00000080 +#define STUDIO_WIREFRAME_VCOLLIDE 0x00000100 + +// Not a studio flag, but used to flag when we want studio stats +#define STUDIO_GENERATE_STATS 0x01000000 + +// Not a studio flag, but used to flag model as using shadow depth material override +#define STUDIO_SSAODEPTHTEXTURE 0x08000000 + +// Not a studio flag, but used to flag model as using shadow depth material override +#define STUDIO_SHADOWDEPTHTEXTURE 0x40000000 + +// Not a studio flag, but used to flag model as a non-sorting brush model +#define STUDIO_TRANSPARENCY 0x80000000 + + +enum modtype_t +{ + mod_bad = 0, + mod_brush, + mod_sprite, + mod_studio +}; + +#endif // MODEL_TYPES_H diff --git a/public/modes.h b/public/modes.h new file mode 100644 index 0000000..ba09200 --- /dev/null +++ b/public/modes.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( MODES_H ) +#define MODES_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct vmode_s +{ + int width; + int height; + int bpp; + int refreshRate; +} vmode_t; + +#endif // MODES_H diff --git a/public/mouthinfo.h b/public/mouthinfo.h new file mode 100644 index 0000000..e474db7 --- /dev/null +++ b/public/mouthinfo.h @@ -0,0 +1,197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( MOUTHINFO_H ) +#define MOUTHINFO_H +#ifdef _WIN32 +#pragma once +#endif + +class CAudioSource; + +#pragma pack(push,4) +class CVoiceData +{ +public: + CVoiceData( void ) + { + m_flElapsed = 0.0f; + m_pAudioSource = NULL; + m_bIgnorePhonemes = false; + } + + void SetElapsedTime( float t ) + { + m_flElapsed = t; + } + + float GetElapsedTime() const + { + return m_flElapsed; + } + + void SetSource( CAudioSource *source, bool bIgnorePhonemes ) + { + m_pAudioSource = source; + m_bIgnorePhonemes = bIgnorePhonemes; + } + + bool ShouldIgnorePhonemes() const + { + return m_bIgnorePhonemes; + } + + CAudioSource *GetSource() + { + return m_pAudioSource; + } + +private: + float m_flElapsed; + CAudioSource *m_pAudioSource; + bool m_bIgnorePhonemes; +}; + +#define UNKNOWN_VOICE_SOURCE -1 + +//----------------------------------------------------------------------------- +// Purpose: Describes position of mouth for lip syncing +//----------------------------------------------------------------------------- +class CMouthInfo +{ +public: + // 0 = mouth closed, 255 = mouth agape + byte mouthopen; + // counter for running average + byte sndcount; + // running average + int sndavg; + +public: + CMouthInfo( void ) { m_nVoiceSources = 0; m_needsEnvelope = false; } + virtual ~CMouthInfo( void ) { ClearVoiceSources(); } + + int GetNumVoiceSources( void ); + CVoiceData *GetVoiceSource( int number ); + + void ClearVoiceSources( void ); + int GetIndexForSource( CAudioSource *source ); + bool IsSourceReferenced( CAudioSource *source ); + + CVoiceData *AddSource( CAudioSource *source, bool bIgnorePhonemes ); + + void RemoveSource( CAudioSource *source ); + void RemoveSourceByIndex( int index ); + + bool IsActive( void ); + bool NeedsEnvelope() { return m_needsEnvelope != 0; } + void ActivateEnvelope() { m_needsEnvelope = true; } + +private: + enum + { + MAX_VOICE_DATA = 4 + }; + + short m_nVoiceSources; + short m_needsEnvelope; + CVoiceData m_VoiceSources[ MAX_VOICE_DATA ]; +}; +#pragma pack(pop) + + +inline bool CMouthInfo::IsActive( void ) +{ + return ( GetNumVoiceSources() > 0 ) ? true : false; +} + +inline int CMouthInfo::GetNumVoiceSources( void ) +{ + return m_nVoiceSources; +} + +inline CVoiceData *CMouthInfo::GetVoiceSource( int number ) +{ + if ( number < 0 || number >= m_nVoiceSources ) + return NULL; + + return &m_VoiceSources[ number ]; +} + +inline void CMouthInfo::ClearVoiceSources( void ) +{ + m_nVoiceSources = 0; +} + +inline int CMouthInfo::GetIndexForSource( CAudioSource *source ) +{ + for ( int i = 0; i < m_nVoiceSources; i++ ) + { + CVoiceData *v = &m_VoiceSources[ i ]; + if ( !v ) + continue; + + if ( v->GetSource() == source ) + return i; + } + + return UNKNOWN_VOICE_SOURCE; +} + +inline bool CMouthInfo::IsSourceReferenced( CAudioSource *source ) +{ + if ( GetIndexForSource( source ) != UNKNOWN_VOICE_SOURCE ) + return true; + + return false; +} + +inline void CMouthInfo::RemoveSource( CAudioSource *source ) +{ + int idx = GetIndexForSource( source ); + if ( idx == UNKNOWN_VOICE_SOURCE ) + return; + + RemoveSourceByIndex( idx ); +} + +inline void CMouthInfo::RemoveSourceByIndex( int index ) +{ + if ( index < 0 || index >= m_nVoiceSources ) + return; + + m_VoiceSources[ index ] = m_VoiceSources[ --m_nVoiceSources ]; +} + +inline CVoiceData *CMouthInfo::AddSource( CAudioSource *source, bool bIgnorePhonemes ) +{ + int idx = GetIndexForSource( source ); + if ( idx == UNKNOWN_VOICE_SOURCE ) + { + if ( m_nVoiceSources < MAX_VOICE_DATA ) + { + idx = m_nVoiceSources++; + } + else + { + // No room! + return NULL; + } + } + + CVoiceData *data = &m_VoiceSources[ idx ]; + data->SetSource( source, bIgnorePhonemes ); + data->SetElapsedTime( 0.0f ); + return data; +} + +#endif // MOUTHINFO_H \ No newline at end of file diff --git a/public/networkstringtabledefs.h b/public/networkstringtabledefs.h new file mode 100644 index 0000000..d82df2e --- /dev/null +++ b/public/networkstringtabledefs.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NETWORKSTRINGTABLEDEFS_H +#define NETWORKSTRINGTABLEDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +typedef int TABLEID; + +#define INVALID_STRING_TABLE -1 +const unsigned short INVALID_STRING_INDEX = (unsigned short )-1; + +// table index is sent in log2(MAX_TABLES) bits +#define MAX_TABLES 32 // Table id is 4 bits + +#define INTERFACENAME_NETWORKSTRINGTABLESERVER "VEngineServerStringTable001" +#define INTERFACENAME_NETWORKSTRINGTABLECLIENT "VEngineClientStringTable001" + +class INetworkStringTable; + +typedef void (*pfnStringChanged)( void *object, INetworkStringTable *stringTable, int stringNumber, char const *newString, void const *newData ); + +//----------------------------------------------------------------------------- +// Purpose: Game .dll shared string table interfaces +//----------------------------------------------------------------------------- +class INetworkStringTable +{ +public: + + virtual ~INetworkStringTable( void ) {}; + + // Table Info + virtual const char *GetTableName( void ) const = 0; + virtual TABLEID GetTableId( void ) const = 0; + virtual int GetNumStrings( void ) const = 0; + virtual int GetMaxStrings( void ) const = 0; + virtual int GetEntryBits( void ) const = 0; + + // Networking + virtual void SetTick( int tick ) = 0; + virtual bool ChangedSinceTick( int tick ) const = 0; + + // Accessors (length -1 means don't change user data if string already exits) + virtual int AddString( bool bIsServer, const char *value, int length = -1, const void *userdata = 0 ) = 0; + + virtual const char *GetString( int stringNumber ) = 0; + virtual void SetStringUserData( int stringNumber, int length, const void *userdata ) = 0; + virtual const void *GetStringUserData( int stringNumber, int *length ) = 0; + virtual int FindStringIndex( char const *string ) = 0; // returns INVALID_STRING_INDEX if not found + + // Callbacks + virtual void SetStringChangedCallback( void *object, pfnStringChanged changeFunc ) = 0; +}; + +class INetworkStringTableContainer +{ +public: + + virtual ~INetworkStringTableContainer( void ) {}; + + // table creation/destruction + virtual INetworkStringTable *CreateStringTable( const char *tableName, int maxentries, int userdatafixedsize = 0, int userdatanetworkbits = 0 ) = 0; + virtual void RemoveAllTables( void ) = 0; + + // table infos + virtual INetworkStringTable *FindTable( const char *tableName ) const = 0; + virtual INetworkStringTable *GetTable( TABLEID stringTable ) const = 0; + virtual int GetNumTables( void ) const = 0; + + virtual INetworkStringTable *CreateStringTableEx( const char *tableName, int maxentries, int userdatafixedsize = 0, int userdatanetworkbits = 0, bool bIsFilenames = false ) = 0; + virtual void SetAllowClientSideAddString( INetworkStringTable *table, bool bAllowClientSideAddString ) = 0; +}; + +#endif // NETWORKSTRINGTABLEDEFS_H diff --git a/public/networkvar.cpp b/public/networkvar.cpp new file mode 100644 index 0000000..65cb1d6 --- /dev/null +++ b/public/networkvar.cpp @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + + +bool g_bUseNetworkVars = true; + +#endif + + + diff --git a/public/networkvar.h b/public/networkvar.h new file mode 100644 index 0000000..142b35e --- /dev/null +++ b/public/networkvar.h @@ -0,0 +1,781 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NETWORKVAR_H +#define NETWORKVAR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/dbg.h" +#include "convar.h" + +#if defined( CLIENT_DLL ) || defined( GAME_DLL ) + #include "basehandle.h" +#endif + + +#pragma warning( disable : 4284 ) // warning C4284: return type for 'CNetworkVarT::operator ->' is 'int *' (ie; not a UDT or reference to a UDT. Will produce errors if applied using infix notation) + +#define MyOffsetOf( type, var ) ( (int)&((type*)0)->var ) + +#ifdef _DEBUG + extern bool g_bUseNetworkVars; + #define CHECK_USENETWORKVARS if(g_bUseNetworkVars) +#else + #define CHECK_USENETWORKVARS // don't check for g_bUseNetworkVars +#endif + + + +inline int InternalCheckDeclareClass( const char *pClassName, const char *pClassNameMatch, void *pTestPtr, void *pBasePtr ) +{ + // This makes sure that casting from ThisClass to BaseClass works right. You'll get a compiler error if it doesn't + // work at all, and you'll get a runtime error if you use multiple inheritance. + Assert( pTestPtr == pBasePtr ); + + // This is triggered by IMPLEMENT_SERVER_CLASS. It does DLLClassName::CheckDeclareClass( #DLLClassName ). + // If they didn't do a DECLARE_CLASS in DLLClassName, then it'll be calling its base class's version + // and the class names won't match. + Assert( (void*)pClassName == (void*)pClassNameMatch ); + return 0; +} + + +template +inline int CheckDeclareClass_Access( T *, const char *pShouldBe ) +{ + return T::CheckDeclareClass( pShouldBe ); +} + +#ifndef _STATIC_LINKED +#ifdef _MSC_VER +#if defined(_DEBUG) && (_MSC_VER > 1200 ) + #define VALIDATE_DECLARE_CLASS 1 +#endif +#endif +#endif + +#ifdef VALIDATE_DECLARE_CLASS + + #define DECLARE_CLASS( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ + template friend int CheckDeclareClass_Access(T *, const char *pShouldBe); \ + static int CheckDeclareClass( const char *pShouldBe ) \ + { \ + InternalCheckDeclareClass( pShouldBe, #className, (ThisClass*)0xFFFFF, (BaseClass*)(ThisClass*)0xFFFFF ); \ + return CheckDeclareClass_Access( (BaseClass *)NULL, #baseClassName ); \ + } + + // Use this macro when you have a base class, but it's part of a library that doesn't use network vars + // or any of the things that use ThisClass or BaseClass. + #define DECLARE_CLASS_GAMEROOT( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ + template friend int CheckDeclareClass_Access(T *, const char *pShouldBe); \ + static int CheckDeclareClass( const char *pShouldBe ) \ + { \ + return InternalCheckDeclareClass( pShouldBe, #className, (ThisClass*)0xFFFFF, (BaseClass*)(ThisClass*)0xFFFFF ); \ + } + + // Deprecated macro formerly used to work around VC++98 bug + #define DECLARE_CLASS_NOFRIEND( className, baseClassName ) \ + DECLARE_CLASS( className, baseClassName ) + + #define DECLARE_CLASS_NOBASE( className ) \ + typedef className ThisClass; \ + template friend int CheckDeclareClass_Access(T *, const char *pShouldBe); \ + static int CheckDeclareClass( const char *pShouldBe ) \ + { \ + return InternalCheckDeclareClass( pShouldBe, #className, 0, 0 ); \ + } + +#else + #define DECLARE_CLASS( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; + + #define DECLARE_CLASS_GAMEROOT( className, baseClassName ) DECLARE_CLASS( className, baseClassName ) + #define DECLARE_CLASS_NOFRIEND( className, baseClassName ) DECLARE_CLASS( className, baseClassName ) + + #define DECLARE_CLASS_NOBASE( className ) typedef className ThisClass; +#endif + + + + +// All classes that contain CNetworkVars need a NetworkStateChanged() function. If the class is not an entity, +// it needs to forward the call to the entity it's in. These macros can help. + + // These macros setup an entity pointer in your class. Use IMPLEMENT_NETWORKVAR_CHAIN before you do + // anything inside the class itself. + class CBaseEntity; + class CAutoInitEntPtr + { + public: + CAutoInitEntPtr() + { + m_pEnt = NULL; + } + CBaseEntity *m_pEnt; + }; + + //TODO: Currently, these don't get the benefit of tracking changes to individual vars. + // Would be nice if they did. + #define DECLARE_NETWORKVAR_CHAIN() \ + CAutoInitEntPtr __m_pChainEntity; \ + void NetworkStateChanged() { CHECK_USENETWORKVARS __m_pChainEntity.m_pEnt->NetworkStateChanged(); } \ + void NetworkStateChanged( void *pVar ) { CHECK_USENETWORKVARS __m_pChainEntity.m_pEnt->NetworkStateChanged(); } + + #define IMPLEMENT_NETWORKVAR_CHAIN( varName ) \ + (varName)->__m_pChainEntity.m_pEnt = this; + + + +// Use this macro when you want to embed a structure inside your entity and have CNetworkVars in it. +template< class T > +static inline void DispatchNetworkStateChanged( T *pObj ) +{ + CHECK_USENETWORKVARS pObj->NetworkStateChanged(); +} +template< class T > +static inline void DispatchNetworkStateChanged( T *pObj, void *pVar ) +{ + CHECK_USENETWORKVARS pObj->NetworkStateChanged( pVar ); +} + + +#define DECLARE_EMBEDDED_NETWORKVAR() \ + template friend int ServerClassInit(T *); \ + template friend int ClientClassInit(T *); \ + virtual void NetworkStateChanged() {} virtual void NetworkStateChanged( void *pProp ) {} + +// NOTE: Assignment operator is disabled because it doesn't call copy constructors of scalar types within the aggregate, so they are not marked changed +#define CNetworkVarEmbedded( type, name ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + static inline int GetOffset_##name() { return MyOffsetOf(ThisClass,name); } \ + typedef ThisClass ThisClass_##name; \ + class NetworkVar_##name : public type \ + { \ + template< class T > NetworkVar_##name& operator=( const T &val ) { *((type*)this) = val; return *this; } \ + public: \ + void CopyFrom( const type &src ) { *((type *)this) = src; NetworkStateChanged(); } \ + virtual void NetworkStateChanged() \ + { \ + DispatchNetworkStateChanged( (ThisClass_##name*)( ((char*)this) - GetOffset_##name() ) ); \ + } \ + virtual void NetworkStateChanged( void *pVar ) \ + { \ + DispatchNetworkStateChanged( (ThisClass_##name*)( ((char*)this) - GetOffset_##name() ), pVar ); \ + } \ + }; \ + NetworkVar_##name name; + +template +FORCEINLINE void NetworkVarConstruct( T &x ) { x = T(0); } +FORCEINLINE void NetworkVarConstruct( color32_s &x ) { x.r = x.g = x.b = x.a = 0; } + +template< class Type, class Changer > +class CNetworkVarBase +{ +public: + inline CNetworkVarBase() + { + NetworkVarConstruct( m_Value ); + } + + template< class C > + const Type& operator=( const C &val ) + { + return Set( ( const Type )val ); + } + + template< class C > + const Type& operator=( const CNetworkVarBase< C, Changer > &val ) + { + return Set( ( const Type )val.m_Value ); + } + + const Type& Set( const Type &val ) + { + if ( memcmp( &m_Value, &val, sizeof(Type) ) ) + { + NetworkStateChanged(); + m_Value = val; + } + return m_Value; + } + + Type& GetForModify() + { + NetworkStateChanged(); + return m_Value; + } + + template< class C > + const Type& operator+=( const C &val ) + { + return Set( m_Value + ( const Type )val ); + } + + template< class C > + const Type& operator-=( const C &val ) + { + return Set( m_Value - ( const Type )val ); + } + + template< class C > + const Type& operator/=( const C &val ) + { + return Set( m_Value / ( const Type )val ); + } + + template< class C > + const Type& operator*=( const C &val ) + { + return Set( m_Value * ( const Type )val ); + } + + template< class C > + const Type& operator^=( const C &val ) + { + return Set( m_Value ^ ( const Type )val ); + } + + template< class C > + const Type& operator|=( const C &val ) + { + return Set( m_Value | ( const Type )val ); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++( int ) // postfix version.. + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--( int ) // postfix version.. + { + Type val = m_Value; + (*this -= 1); + return val; + } + + // For some reason the compiler only generates type conversion warnings for this operator when used like + // CNetworkVarBase = 0x1 + // (it warns about converting from an int to an unsigned char). + template< class C > + const Type& operator&=( const C &val ) + { + return Set( m_Value & ( const Type )val ); + } + + operator const Type&() const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +protected: + inline void NetworkStateChanged() + { + Changer::NetworkStateChanged( this ); + } +}; + + +template< class Type, class Changer > +class CNetworkColor32Base : public CNetworkVarBase< Type, Changer > +{ +public: + inline void Init( byte rVal, byte gVal, byte bVal ) + { + SetR( rVal ); + SetG( gVal ); + SetB( bVal ); + } + inline void Init( byte rVal, byte gVal, byte bVal, byte aVal ) + { + SetR( rVal ); + SetG( gVal ); + SetB( bVal ); + SetA( aVal ); + } + + const Type& operator=( const Type &val ) + { + return this->Set( val ); + } + + const Type& operator=( const CNetworkColor32Base &val ) + { + return CNetworkVarBase::Set( val.m_Value ); + } + + inline byte GetR() const { return CNetworkColor32Base::m_Value.r; } + inline byte GetG() const { return CNetworkColor32Base::m_Value.g; } + inline byte GetB() const { return CNetworkColor32Base::m_Value.b; } + inline byte GetA() const { return CNetworkColor32Base::m_Value.a; } + inline void SetR( byte val ) { SetVal( CNetworkColor32Base::m_Value.r, val ); } + inline void SetG( byte val ) { SetVal( CNetworkColor32Base::m_Value.g, val ); } + inline void SetB( byte val ) { SetVal( CNetworkColor32Base::m_Value.b, val ); } + inline void SetA( byte val ) { SetVal( CNetworkColor32Base::m_Value.a, val ); } + +protected: + inline void SetVal( byte &out, const byte &in ) + { + if ( out != in ) + { + CNetworkVarBase< Type, Changer >::NetworkStateChanged(); + out = in; + } + } +}; + + +// Network vector wrapper. +template< class Type, class Changer > +class CNetworkVectorBase : public CNetworkVarBase< Type, Changer > +{ +public: + inline void Init( float ix=0, float iy=0, float iz=0 ) + { + SetX( ix ); + SetY( iy ); + SetZ( iz ); + } + + const Type& operator=( const Type &val ) + { + return CNetworkVarBase< Type, Changer >::Set( val ); + } + + const Type& operator=( const CNetworkVectorBase &val ) + { + return CNetworkVarBase::Set( val.m_Value ); + } + + inline float GetX() const { return CNetworkVectorBase::m_Value.x; } + inline float GetY() const { return CNetworkVectorBase::m_Value.y; } + inline float GetZ() const { return CNetworkVectorBase::m_Value.z; } + inline float operator[]( int i ) const { return CNetworkVectorBase::m_Value[i]; } + + inline void SetX( float val ) { DetectChange( CNetworkVectorBase::m_Value.x, val ); } + inline void SetY( float val ) { DetectChange( CNetworkVectorBase::m_Value.y, val ); } + inline void SetZ( float val ) { DetectChange( CNetworkVectorBase::m_Value.z, val ); } + inline void Set( int i, float val ) { DetectChange( CNetworkVectorBase::m_Value[i], val ); } + + bool operator==( const Type &val ) const + { + return CNetworkVectorBase::m_Value == (Type)val; + } + + bool operator!=( const Type &val ) const + { + return CNetworkVectorBase::m_Value != (Type)val; + } + + const Type operator+( const Type &val ) const + { + return CNetworkVectorBase::m_Value + val; + } + + const Type operator-( const Type &val ) const + { + return CNetworkVectorBase::m_Value - val; + } + + const Type operator*( const Type &val ) const + { + return CNetworkVectorBase::m_Value * val; + } + + const Type& operator*=( float val ) + { + return CNetworkVarBase< Type, Changer >::Set( CNetworkVectorBase::m_Value * val ); + } + + const Type operator*( float val ) const + { + return CNetworkVectorBase::m_Value * val; + } + + const Type operator/( const Type &val ) const + { + return CNetworkVectorBase::m_Value / val; + } + +private: + inline void DetectChange( float &out, float in ) + { + if ( out != in ) + { + CNetworkVectorBase::NetworkStateChanged(); + out = in; + } + } +}; + + +// Network vector wrapper. +template< class Type, class Changer > +class CNetworkQuaternionBase : public CNetworkVarBase< Type, Changer > +{ +public: + inline void Init( float ix=0, float iy=0, float iz=0, float iw = 0 ) + { + SetX( ix ); + SetY( iy ); + SetZ( iz ); + SetW( iw ); + } + + const Type& operator=( const Type &val ) + { + return CNetworkVarBase< Type, Changer >::Set( val ); + } + + const Type& operator=( const CNetworkQuaternionBase &val ) + { + return CNetworkVarBase::Set( val.m_Value ); + } + + inline float GetX() const { return CNetworkQuaternionBase::m_Value.x; } + inline float GetY() const { return CNetworkQuaternionBase::m_Value.y; } + inline float GetZ() const { return CNetworkQuaternionBase::m_Value.z; } + inline float GetW() const { return CNetworkQuaternionBase::m_Value.w; } + inline float operator[]( int i ) const { return CNetworkQuaternionBase::m_Value[i]; } + + inline void SetX( float val ) { DetectChange( CNetworkQuaternionBase::m_Value.x, val ); } + inline void SetY( float val ) { DetectChange( CNetworkQuaternionBase::m_Value.y, val ); } + inline void SetZ( float val ) { DetectChange( CNetworkQuaternionBase::m_Value.z, val ); } + inline void SetW( float val ) { DetectChange( CNetworkQuaternionBase::m_Value.w, val ); } + inline void Set( int i, float val ) { DetectChange( CNetworkQuaternionBase::m_Value[i], val ); } + + bool operator==( const Type &val ) const + { + return CNetworkQuaternionBase::m_Value == (Type)val; + } + + bool operator!=( const Type &val ) const + { + return CNetworkQuaternionBase::m_Value != (Type)val; + } + + const Type operator+( const Type &val ) const + { + return CNetworkQuaternionBase::m_Value + val; + } + + const Type operator-( const Type &val ) const + { + return CNetworkQuaternionBase::m_Value - val; + } + + const Type operator*( const Type &val ) const + { + return CNetworkQuaternionBase::m_Value * val; + } + + const Type& operator*=( float val ) + { + return CNetworkQuaternionBase< Type, Changer >::Set( CNetworkQuaternionBase::m_Value * val ); + } + + const Type operator*( float val ) const + { + return CNetworkQuaternionBase::m_Value * val; + } + + const Type operator/( const Type &val ) const + { + return CNetworkQuaternionBase::m_Value / val; + } + +private: + inline void DetectChange( float &out, float in ) + { + if ( out != in ) + { + CNetworkQuaternionBase::NetworkStateChanged(); + out = in; + } + } +}; + + +// Network ehandle wrapper. +#if defined( CLIENT_DLL ) || defined( GAME_DLL ) + inline void NetworkVarConstruct( CBaseHandle &x ) {} + + template< class Type, class Changer > + class CNetworkHandleBase : public CNetworkVarBase< CBaseHandle, Changer > + { + public: + const Type* operator=( const Type *val ) + { + return Set( val ); + } + + const Type& operator=( const CNetworkHandleBase &val ) + { + const CBaseHandle &handle = CNetworkVarBase::Set( val.m_Value ); + return *(const Type*)handle.Get(); + } + + bool operator !() const + { + return !CNetworkHandleBase::m_Value.Get(); + } + + operator Type*() const + { + return static_cast< Type* >( CNetworkHandleBase::m_Value.Get() ); + } + + const Type* Set( const Type *val ) + { + if ( CNetworkHandleBase::m_Value != val ) + { + this->NetworkStateChanged(); + CNetworkHandleBase::m_Value = val; + } + return val; + } + + Type* Get() const + { + return static_cast< Type* >( CNetworkHandleBase::m_Value.Get() ); + } + + Type* operator->() const + { + return static_cast< Type* >( CNetworkHandleBase::m_Value.Get() ); + } + + bool operator==( const Type *val ) const + { + return CNetworkHandleBase::m_Value == val; + } + + bool operator!=( const Type *val ) const + { + return CNetworkHandleBase::m_Value != val; + } + }; + + + + #define CNetworkHandle( type, name ) CNetworkHandleInternal( type, name, NetworkStateChanged ) + + #define CNetworkHandleInternal( type, name, stateChangedFn ) \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkHandleBase, stateChangedFn ) +#endif + + +// Use this macro to define a network variable. +#define CNetworkVar( type, name ) \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVarBase, NetworkStateChanged ) + + +// Use this macro when you have a base class with a variable, and it doesn't have that variable in a SendTable, +// but a derived class does. Then, the entity is only flagged as changed when the variable is changed in +// an entity that wants to transmit the variable. + #define CNetworkVarForDerived( type, name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVarBase, NetworkStateChanged_##name ) + + #define CNetworkVectorForDerived( name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + CNetworkVectorInternal( Vector, name, NetworkStateChanged_##name ) + + #define CNetworkHandleForDerived( type, name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + CNetworkHandleInternal( type, name, NetworkStateChanged_##name ) + + #define CNetworkArrayForDerived( type, name, count ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + CNetworkArrayInternal( type, name, count, NetworkStateChanged_##name ) + + #define IMPLEMENT_NETWORK_VAR_FOR_DERIVED( name ) \ + virtual void NetworkStateChanged_##name() { CHECK_USENETWORKVARS NetworkStateChanged(); } \ + virtual void NetworkStateChanged_##name( void *pVar ) { CHECK_USENETWORKVARS NetworkStateChanged( pVar ); } + + +// This virtualizes the change detection on the variable, but it is ON by default. +// Use this when you have a base class in which MOST of its derived classes use this variable +// in their SendTables, but there are a couple that don't (and they +// can use DISABLE_NETWORK_VAR_FOR_DERIVED). + #define CNetworkVarForDerived_OnByDefault( type, name ) \ + virtual void NetworkStateChanged_##name() { CHECK_USENETWORKVARS NetworkStateChanged(); } \ + virtual void NetworkStateChanged_##name( void *pVar ) { CHECK_USENETWORKVARS NetworkStateChanged( pVar ); } \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVarBase, NetworkStateChanged_##name ) + + #define DISABLE_NETWORK_VAR_FOR_DERIVED( name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} + + + +// Vectors + some convenient helper functions. +#define CNetworkVector( name ) CNetworkVectorInternal( Vector, name, NetworkStateChanged ) +#define CNetworkQAngle( name ) CNetworkVectorInternal( QAngle, name, NetworkStateChanged ) + +#define CNetworkVectorInternal( type, name, stateChangedFn ) \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVectorBase, stateChangedFn ) + +#define CNetworkQuaternion( name ) \ + NETWORK_VAR_START( Quaternion, name ) \ + NETWORK_VAR_END( Quaternion, name, CNetworkQuaternionBase, NetworkStateChanged ) + +// Helper for color32's. Contains GetR(), SetR(), etc.. functions. +#define CNetworkColor32( name ) \ + NETWORK_VAR_START( color32, name ) \ + NETWORK_VAR_END( color32, name, CNetworkColor32Base, NetworkStateChanged ) + + +#define CNetworkString( name, length ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + typedef ThisClass MakeANetworkVar_##name; \ + class NetworkVar_##name \ + { \ + public: \ + NetworkVar_##name() { m_Value[0] = '\0'; } \ + operator const char*() const { return m_Value; } \ + const char* Get() const { return m_Value; } \ + char* GetForModify() \ + { \ + NetworkStateChanged(); \ + return m_Value; \ + } \ + protected: \ + inline void NetworkStateChanged() \ + { \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)this) - MyOffsetOf(ThisClass,name)))->NetworkStateChanged(); \ + } \ + private: \ + char m_Value[length]; \ + }; \ + NetworkVar_##name name; + + + + +// Use this to define networked arrays. +// You can access elements for reading with operator[], and you can set elements with the Set() function. +#define CNetworkArrayInternal( type, name, count, stateChangedFn ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + typedef ThisClass MakeANetworkVar_##name; \ + class NetworkVar_##name \ + { \ + public: \ + inline NetworkVar_##name() \ + { \ + for ( int i = 0 ; i < count ; ++i ) \ + NetworkVarConstruct( m_Value[i] ); \ + } \ + template friend int ServerClassInit(T *); \ + const type& operator[]( int i ) const \ + { \ + return Get( i ); \ + } \ + \ + const type& Get( int i ) const \ + { \ + Assert( i >= 0 && i < count ); \ + return m_Value[i]; \ + } \ + \ + type& GetForModify( int i ) \ + { \ + Assert( i >= 0 && i < count ); \ + NetworkStateChanged( i ); \ + return m_Value[i]; \ + } \ + \ + void Set( int i, const type &val ) \ + { \ + Assert( i >= 0 && i < count ); \ + if( memcmp( &m_Value[i], &val, sizeof(type) ) ) \ + { \ + NetworkStateChanged( i ); \ + m_Value[i] = val; \ + } \ + } \ + const type* Base() const { return m_Value; } \ + int Count() const { return count; } \ + protected: \ + inline void NetworkStateChanged( int index ) \ + { \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)this) - MyOffsetOf(ThisClass,name)))->stateChangedFn( &m_Value[index] ); \ + } \ + type m_Value[count]; \ + }; \ + NetworkVar_##name name; + + +#define CNetworkArray( type, name, count ) CNetworkArrayInternal( type, name, count, NetworkStateChanged ) + + +// Internal macros used in definitions of network vars. +#define NETWORK_VAR_START( type, name ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + typedef ThisClass MakeANetworkVar_##name; \ + class NetworkVar_##name \ + { \ + public: \ + template friend int ServerClassInit(T *); + + +#define NETWORK_VAR_END( type, name, base, stateChangedFn ) \ + public: \ + static inline void NetworkStateChanged( void *ptr ) \ + { \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)ptr) - MyOffsetOf(ThisClass,name)))->stateChangedFn( ptr ); \ + } \ + }; \ + base< type, NetworkVar_##name > name; + + + +#endif // NETWORKVAR_H diff --git a/public/nmatrix.h b/public/nmatrix.h new file mode 100644 index 0000000..2b8d206 --- /dev/null +++ b/public/nmatrix.h @@ -0,0 +1,332 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NMATRIX_H +#define NMATRIX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "nvector.h" + + +#define NMatrixMN NMatrix + + +template +class NMatrix +{ +public: + + NMatrixMN() {} + + static NMatrixMN SetupNMatrixNull(); // Return a matrix of all zeros. + static NMatrixMN SetupNMatrixIdentity(); // Return an identity matrix. + + NMatrixMN const& operator=( NMatrixMN const &other ); + + NMatrixMN operator+( NMatrixMN const &v ) const; + NMatrixMN const& operator+=( NMatrixMN const &v ); + + NMatrixMN operator-() const; + NMatrixMN operator-( NMatrixMN const &v ) const; + + // Multiplies the column vector on the right-hand side. + NVector operator*( NVector const &v ) const; + + // Can't get the compiler to work with a real MxN * NxR matrix multiply... + NMatrix operator*( NMatrix const &b ) const; + + NMatrixMN operator*( float val ) const; + + bool InverseGeneral( NMatrixMN &mInverse ) const; + NMatrix Transpose() const; + + +public: + + float m[M][N]; +}; + + + +// Return the matrix generated by multiplying a column vector 'a' by row vector 'b'. +template +inline NMatrix OuterProduct( NVectorN const &a, NVectorN const &b ) +{ + NMatrix ret; + + for( int i=0; i < N; i++ ) + for( int j=0; j < N; j++ ) + ret.m[i][j] = a.v[i] * b.v[j]; + + return ret; +} + + +// -------------------------------------------------------------------------------- // +// NMatrix inlines. +// -------------------------------------------------------------------------------- // + +template +inline NMatrixMN NMatrixMN::SetupNMatrixNull() +{ + NMatrix ret; + memset( ret.m, 0, sizeof(float)*M*N ); + return ret; +} + + +template +inline NMatrixMN NMatrixMN::SetupNMatrixIdentity() +{ + assert( M == N ); // Identity matrices must be square. + + NMatrix ret; + memset( ret.m, 0, sizeof(float)*M*N ); + for( int i=0; i < N; i++ ) + ret.m[i][i] = 1; + return ret; +} + + +template +inline NMatrixMN const &NMatrixMN::operator=( NMatrixMN const &v ) +{ + memcpy( m, v.m, sizeof(float)*M*N ); + return *this; +} + + +template +inline NMatrixMN NMatrixMN::operator+( NMatrixMN const &v ) const +{ + NMatrixMN ret; + for( int i=0; i < M; i++ ) + for( int j=0; j < N; j++ ) + ret.m[i][j] = m[i][j] + v.m[i][j]; + + return ret; +} + + +template +inline NMatrixMN const &NMatrixMN::operator+=( NMatrixMN const &v ) +{ + for( int i=0; i < M; i++ ) + for( int j=0; j < N; j++ ) + m[i][j] += v.m[i][j]; + + return *this; +} + + +template +inline NMatrixMN NMatrixMN::operator-() const +{ + NMatrixMN ret; + + for( int i=0; i < M*N; i++ ) + ((float*)ret.m)[i] = -((float*)m)[i]; + + return ret; +} + + +template +inline NMatrixMN NMatrixMN::operator-( NMatrixMN const &v ) const +{ + NMatrixMN ret; + for( int i=0; i < M; i++ ) + for( int j=0; j < N; j++ ) + ret.m[i][j] = m[i][j] - v.m[i][j]; + return ret; +} + + +template +inline NVector NMatrixMN::operator*( NVectorN const &v ) const +{ + NVectorN ret; + + for( int i=0; i < M; i++ ) + { + ret.v[i] = 0; + + for( int j=0; j < N; j++ ) + ret.v[i] += m[i][j] * v.v[j]; + } + + return ret; +} + + +template +inline NMatrix NMatrixMN::operator*( NMatrix const &b ) const +{ + NMatrix ret; + + for( int myRow=0; myRow < M; myRow++ ) + { + for( int otherCol=0; otherCol < M; otherCol++ ) + { + ret[myRow][otherCol] = 0; + for( int i=0; i < N; i++ ) + ret[myRow][otherCol] += a.m[myRow][i] * b.m[i][otherCol]; + } + } + + return ret; +} + + +template +inline NMatrixMN NMatrixMN::operator*( float val ) const +{ + NMatrixMN ret; + + for( int i=0; i < N*M; i++ ) + ((float*)ret.m)[i] = ((float*)m)[i] * val; + + return ret; +} + + +template +bool NMatrixMN::InverseGeneral( NMatrixMN &mInverse ) const +{ + int iRow, i, j, iTemp, iTest; + float mul, fTest, fLargest; + float mat[N][2*N]; + int rowMap[N], iLargest; + float *pOut, *pRow, *pScaleRow; + + + // Can only invert square matrices. + if( M != N ) + { + assert( !"Tried to invert a non-square matrix" ); + return false; + } + + + // How it's done. + // AX = I + // A = this + // X = the matrix we're looking for + // I = identity + + // Setup AI + for(i=0; i < N; i++) + { + const float *pIn = m[i]; + pOut = mat[i]; + + for(j=0; j < N; j++) + { + pOut[j] = pIn[j]; + } + + for(j=N; j < 2*N; j++) + pOut[j] = 0; + + pOut[i+N] = 1.0f; + + rowMap[i] = i; + } + + // Use row operations to get to reduced row-echelon form using these rules: + // 1. Multiply or divide a row by a nonzero number. + // 2. Add a multiple of one row to another. + // 3. Interchange two rows. + + for(iRow=0; iRow < N; iRow++) + { + // Find the row with the largest element in this column. + fLargest = 0.001f; + iLargest = -1; + for(iTest=iRow; iTest < N; iTest++) + { + fTest = (float)fabs(mat[rowMap[iTest]][iRow]); + if(fTest > fLargest) + { + iLargest = iTest; + fLargest = fTest; + } + } + + // They're all too small.. sorry. + if(iLargest == -1) + { + return false; + } + + // Swap the rows. + iTemp = rowMap[iLargest]; + rowMap[iLargest] = rowMap[iRow]; + rowMap[iRow] = iTemp; + + pRow = mat[rowMap[iRow]]; + + // Divide this row by the element. + mul = 1.0f / pRow[iRow]; + for(j=0; j < 2*N; j++) + pRow[j] *= mul; + + pRow[iRow] = 1.0f; // Preserve accuracy... + + // Eliminate this element from the other rows using operation 2. + for(i=0; i < N; i++) + { + if(i == iRow) + continue; + + pScaleRow = mat[rowMap[i]]; + + // Multiply this row by -(iRow*the element). + mul = -pScaleRow[iRow]; + for(j=0; j < 2*N; j++) + { + pScaleRow[j] += pRow[j] * mul; + } + + pScaleRow[iRow] = 0.0f; // Preserve accuracy... + } + } + + // The inverse is on the right side of AX now (the identity is on the left). + for(i=0; i < N; i++) + { + const float *pIn = mat[rowMap[i]] + N; + pOut = mInverse.m[i]; + + for(j=0; j < N; j++) + { + pOut[j] = pIn[j]; + } + } + + return true; +} + + +template +inline NMatrix NMatrixMN::Transpose() const +{ + NMatrix ret; + + for( int i=0; i < M; i++ ) + for( int j=0; j < N; j++ ) + ret.m[j][i] = m[i][j]; + + return ret; +} + +#endif // NMATRIX_H + diff --git a/public/ntree.h b/public/ntree.h new file mode 100644 index 0000000..3fb448a --- /dev/null +++ b/public/ntree.h @@ -0,0 +1,316 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef __TREE_H__ +#define __TREE_H__ + +#include "List.h" +#include "ArrayStack.h" + +// NTreeNode: Class decleration and definition +template class NTreeNode +{ +public: + // constructor + NTreeNode( T data ); + + NTreeNode *PrependChild( NTreeNode *node ); + NTreeNode *AppendChild( NTreeNode *node ); + NTreeNode *InsertChildAfterIndex( NTreeNode *node, int index ); + NTreeNode *InsertChildBeforeIndex( NTreeNode *node, int index ); + NTreeNode *RemoveChild( Position position ); + NTreeNode *RemoveChild( int index ); + Position InsertAfter( NTreeNode *node, Position position ); + Position InsertBefore( NTreeNode *node, Position position ); + int GetNumChildren(); + Position GetChildPosition( int childNum ); + NTreeNode *GetChild( int childNum ); + NTreeNode *GetChild( Position position ); + int GetIndexRelativeToParent(); + T GetItem(); + NTreeNode *GetParent(); + NTreeNode *GetRoot(); + NTreeNode *GetNextSibling(); + void Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth ); + NTreeNode *ReentrantTraversalGetFirst( int maxTreeDepth ); + NTreeNode *ReentrantTraversalGetNext( void ); + +protected: + GList * > *list; + T data; + NTreeNode *parent; + ArrayStack *> *reentrantStack; +}; + +template +NTreeNode::NTreeNode( T data ) +{ + list = new GList * >; + this->data = data; + this->parent = NULL; + this->reentrantStack = NULL; +} + +template +NTreeNode *NTreeNode::PrependChild( NTreeNode *node ) +{ + node->parent = this; + return list->GetItemAtPosition( list->InsertAtHead( node ) ); +} + +template +NTreeNode *NTreeNode::AppendChild( NTreeNode *node ) +{ + node->parent = this; + return list->GetItemAtPosition( list->InsertAtTail( node ) ); +} + +template +NTreeNode *NTreeNode::InsertChildAfterIndex( NTreeNode *node, int index ) +{ + node->parent = this; + if( index < 0 ) + { + // if out of range in the negative direction, prepend + this->PrependChild( node ); + } + else if( index > list->GetNumItems() - 1 ) + { + // if out of range, just append. + this->AppendChild( node ); + } + else + { + Position pos; + pos = list->GetPositionAtIndex( index ); + list->InsertAfter( node, pos ); + } + return node; +} + +template +NTreeNode *NTreeNode::InsertChildBeforeIndex( NTreeNode *node, int index ) +{ + node->parent = this; + if( index < 0 ) + { + // if out of range in the negative direction, prepend + this->PrependChild( node ); + } + else if( index > list->GetNumItems() - 1 ) + { + // if out of range, just append. + this->AppendChild( node ); + } + else + { + Position pos; + pos = list->GetPositionAtIndex( index ); + list->InsertBefore( node, pos ); + } + return node; +} + +template +NTreeNode *NTreeNode::RemoveChild( Position position ) +{ + NTreeNode **node = ( NTreeNode ** )( void * )position; + ( *node )->parent = NULL; + return list->Remove( position ); +} + +template +NTreeNode *NTreeNode::RemoveChild( int index ) +{ + Position position = list->GetPositionAtIndex( index ); + NTreeNode **node = ( NTreeNode ** )( void * )position; + ( *node )->parent = NULL; + return list->Remove( position ); +} + +template +Position NTreeNode::InsertAfter( NTreeNode *node, Position position ) +{ + node->parent = this; + return list->InsertAfter( node, position ); +} + +template +Position NTreeNode::InsertBefore( NTreeNode *node, Position position ) +{ + node->parent = this; + return list->InsertBefore( node, position ); +} + +template +int NTreeNode::GetNumChildren() +{ + return list->GetNumItems(); +} + +template +Position NTreeNode::GetChildPosition( int childNum ) +{ + return list->GetPositionAtIndex( childNum ); +} + +template +NTreeNode *NTreeNode::GetChild( int childNum ) +{ + return list->GetItemAtIndex( childNum ); +} + +template +NTreeNode *NTreeNode::GetChild( Position position ) +{ + return list->GetItemAtIndex( position ); +} + +template +int NTreeNode::GetIndexRelativeToParent() +{ + if( !parent ) + { + assert( 0 ); // hack + return -1; + } + GListIterator *> iterator( parent->list ); + int i; + for( i = 0, iterator.GotoHead(); !iterator.AtEnd(); iterator++, i++ ) + { + if( iterator.GetCurrent() == this ) + { + return i; + } + } + assert( 0 ); // hack + return -1; +} + +template +T NTreeNode::GetItem() +{ + return data; +} + +template +NTreeNode *NTreeNode::GetParent() +{ + return parent; +} + +template +NTreeNode *NTreeNode::GetRoot() +{ + NTreeNode *node; + node = this; + while( node->GetParent() ) + { + node = node->GetParent(); + } + return node; +} + +template +NTreeNode *NTreeNode::GetNextSibling() +{ + int currentID, siblingID; + NTreeNode *parent; + parent = this->GetParent(); + if( !parent ) + { + return NULL; + } + currentID = this->GetIndexRelativeToParent(); + siblingID = currentID + 1; + if( siblingID < parent->GetNumChildren() ) + { + return parent->GetChild( siblingID ); + } + else + { + return NULL; + } +} + +template +void NTreeNode::Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth ) +{ + ArrayStack *> stack( maxTreeDepth ); + NTreeNode *current, *nextSibling; + + stack.Push( this ); + Visit( this->GetItem(), 0 ); + while( !stack.IsEmpty() ) + { + current = stack.Pop(); + if( current->GetNumChildren() > 0 ) + { + stack.Push( current ); + stack.Push( current->GetChild( 0 ) ); + Visit( current->GetChild( 0 )->GetItem(), stack.GetDepth() - 1 ); + } + else + { + while( !stack.IsEmpty() && !( nextSibling = current->GetNextSibling() ) ) + { + current = stack.Pop(); + } + if( !stack.IsEmpty() ) + { + stack.Push( nextSibling ); + Visit( nextSibling->GetItem(), stack.GetDepth() - 1 ); + } + } + } +} + +template +NTreeNode *NTreeNode::ReentrantTraversalGetFirst( int maxTreeDepth ) +{ + if( reentrantStack ) + { + delete reentrantStack; + } + reentrantStack = new ArrayStack *>( maxTreeDepth ); + reentrantStack->Push( this ); + return this; +} + +template +NTreeNode *NTreeNode::ReentrantTraversalGetNext( void ) +{ + NTreeNode *current, *nextSibling; + + while( !reentrantStack->IsEmpty() ) + { + current = reentrantStack->Pop(); + if( current->GetNumChildren() > 0 ) + { + reentrantStack->Push( current ); + reentrantStack->Push( current->GetChild( 0 ) ); + return current->GetChild( 0 ); + } + else + { + while( !reentrantStack->IsEmpty() && !( nextSibling = current->GetNextSibling() ) ) + { + current = reentrantStack->Pop(); + } + if( !reentrantStack->IsEmpty() ) + { + reentrantStack->Push( nextSibling ); + return nextSibling; + } + } + } + delete reentrantStack; + reentrantStack = NULL; + return NULL; +} + +#endif /* __TREE_H__ */ diff --git a/public/nvector.h b/public/nvector.h new file mode 100644 index 0000000..e80b317 --- /dev/null +++ b/public/nvector.h @@ -0,0 +1,203 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef NVECTOR_H +#define NVECTOR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include + + +#define NVectorN NVector +#define NVector3 NVector<3> + + +// N-dimensional vector. +template +class NVector +{ +public: + + NVectorN() {} + + float& operator[]( int i ); + float const& operator[]( int i ) const; + + float Dot( NVectorN const &b ) const; + NVectorN Cross( NVectorN const &b ) const; + NVectorN Normalize() const; + float Length() const; + + NVectorN operator-() const; + NVectorN operator+( NVectorN const &b ) const; + NVectorN const &operator+=( NVectorN const &b ); + NVectorN operator-( NVectorN const &b ) const; + NVectorN operator*( float val ) const; + + +// Static helpers. +public: + + static NVectorN SetupNVectorNull(); // Returns a vector of all zeros. + + +public: + + float v[N]; +}; + + +template +inline float NDot( NVector const &a, NVector const &b ) +{ + float ret = 0; + for( int i=0; i < N; i++ ) + ret += a.v[i] * b.v[i]; + return ret; +} + +template +Vector& ToVec( NVector &vec ) {assert( N >= 3 ); return *((Vector*)&vec);} + +template +Vector const& ToVec( NVector const &vec ){assert( N >= 3 ); return *((Vector const*)&vec);} + +NVector<3>& ToNVec( Vector &vec ) {return *((NVector<3>*)&vec);} +NVector<3> const& ToNVec( Vector const &vec ) {return *((NVector<3> const*)&vec);} + + +// ------------------------------------------------------------------------------------ // +// NVector inlines. +// ------------------------------------------------------------------------------------ // + +template +NVectorN NVectorN::SetupNVectorNull() +{ + NVector ret; + memset( ret.v, 0, sizeof(float)*N ); + return ret; +} + + +template +float& NVectorN::operator[]( int i ) +{ + assert( i >= 0 && i < N ); + return v[i]; +} + + +template +float const& NVectorN::operator[]( int i ) const +{ + assert( i >= 0 && i < N ); + return v[i]; +} + + +template +float NVectorN::Dot( NVectorN const &b ) const +{ + float ret = 0; + + for( int i=0; i < N; i++ ) + ret += v[i]*b.v[i]; + + return ret; +} + + +template +NVectorN NVectorN::Cross( NVectorN const &b ) const +{ + NVector ret; + NMatrix mat; + + for( int i=0; i < N; i++ ) + { + for( y=0; y < N; y++ ) + for( x=0; x < N; x++ ) + mat.m[y][x] = + + ret.v[i] = v[i]*b.v[i]; + } + + return ret; +} + + +template +NVectorN NVectorN::Normalize() const +{ + return *this * (1.0f / Length()); +} + + +template +float NVectorN::Length() const +{ + return (float)sqrt( Dot(*this) ); +} + + +template +NVectorN NVectorN::operator-() const +{ + NVectorN ret; + for( int i=0; i < N; i++ ) + ret.v[i] = -v[i]; + return ret; +} + + +template +NVectorN NVectorN::operator+( NVectorN const &b ) const +{ + NVectorN ret; + + for( int i=0; i < N; i++ ) + ret.v[i] = v[i]+b.v[i]; + + return ret; +} + + +template +NVectorN const &NVectorN::operator+=( NVectorN const &b ) +{ + for( int i=0; i < N; i++ ) + v[i] += b.v[i]; + return *this; +} + + +template +NVectorN NVectorN::operator-( NVectorN const &b ) const +{ + NVectorN ret; + + for( int i=0; i < N; i++ ) + ret.v[i] = v[i]-b.v[i]; + + return ret; +} + +template +NVectorN NVectorN::operator*( float val ) const +{ + NVectorN ret; + for( int i=0; i < N; i++ ) + ret.v[i] = v[i] * val; + return ret; +} + + +#endif // NVECTOR_H + diff --git a/public/nvtc.h b/public/nvtc.h new file mode 100644 index 0000000..fd1c980 --- /dev/null +++ b/public/nvtc.h @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/* + * Copyright (c) 1997-8 S3 Inc. All Rights Reserved. + * + * Module Name: s3_intrf.h + * + * Purpose: Constant, structure, and prototype definitions for S3TC + * interface to DX surface + * + * Author: Dan Hung, Martin Hoffesommer + * + * Revision History: + * version Beta 1.00.00-98-03-26 + */ + +// Highlevel interface + +#ifndef NVTC_H +#define NVTC_H + +#if defined( _WIN32 ) && !defined( _X360 ) +#include +#endif + +// RGB encoding types +#define S3TC_ENCODE_RGB_FULL 0x0 +#define S3TC_ENCODE_RGB_COLOR_KEY 0x1 +#define S3TC_ENCODE_RGB_ALPHA_COMPARE 0x2 +#define _S3TC_ENCODE_RGB_MASK 0xff + +// alpha encoding types +#define S3TC_ENCODE_ALPHA_NONE 0x000 +#define S3TC_ENCODE_ALPHA_EXPLICIT 0x100 +#define S3TC_ENCODE_ALPHA_INTERPOLATED 0x200 +#define _S3TC_ENCODE_ALPHA_MASK 0xff00 + + +#if defined( _WIN32 ) && !defined( _X360 ) +// common encoding types +//@@@TBD + +// error codes +#define ERROR_ABORTED -1 + +// Progress Callback for S3TCencode +typedef BOOL (* LP_S3TC_PROGRESS_CALLBACK)(float fProgress, LPVOID lpUser1, LPVOID lpUser2); + +// set alpha reference value for alpha compare encoding +void S3TCsetAlphaReference(int nRef); + +// determine number of bytes needed to compress given source image +unsigned int S3TCgetEncodeSize(DDSURFACEDESC *lpDesc, // [in] + unsigned int dwEncodeType // [in] + ); + +// encode (compress) given source image to given destination surface +void S3TCencode(DDSURFACEDESC *lpSrc, // [in] + PALETTEENTRY *lpPal, // [in], may be NULL + DDSURFACEDESC *lpDest, // [out] + void *lpDestBuf, // [in] + unsigned int dwEncodeType, // [in] + float *weight // [in] + ); + +int S3TCencodeEx(DDSURFACEDESC *lpSrc, // [in] + PALETTEENTRY *lpPal, // [in], may be NULL + DDSURFACEDESC *lpDest, // [out] + void *lpDestBuf, // [in] + unsigned int dwEncodeType, // [in] + float *weight, // [in] + LP_S3TC_PROGRESS_CALLBACK lpS3TCProgressProc, // [in], may be NULL + LPVOID lpArg1, // in + LPVOID lpArg2 // in + ); + +// determine number of bytes needed do decompress given compressed image +unsigned int S3TCgetDecodeSize(DDSURFACEDESC *lpDesc); + +// decode (decompress) to ARGB8888 +void S3TCdecode(DDSURFACEDESC *lpSrc, // [in] + DDSURFACEDESC *lpDest, // [out] + void *lpDestBuf // [in] + ); + +#endif // _WIN32 + +#endif // NVTC_H diff --git a/public/optimize.h b/public/optimize.h new file mode 100644 index 0000000..4a14bf3 --- /dev/null +++ b/public/optimize.h @@ -0,0 +1,257 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef OPTIMIZE_H +#define OPTIMIZE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "studio.h" + + +// NOTE: You can change this without affecting the vtx file format. +#define MAX_NUM_BONES_PER_TRI ( MAX_NUM_BONES_PER_VERT * 3 ) +#define MAX_NUM_BONES_PER_STRIP 512 + +#define OPTIMIZED_MODEL_FILE_VERSION 7 + +extern bool g_bDumpGLViewFiles; + +struct s_bodypart_t; + +namespace OptimizedModel +{ + +#pragma pack(1) + +struct BoneStateChangeHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int hardwareID; + int newBoneID; +}; + +struct Vertex_t +{ + DECLARE_BYTESWAP_DATADESC(); + // these index into the mesh's vert[origMeshVertID]'s bones + unsigned char boneWeightIndex[MAX_NUM_BONES_PER_VERT]; + unsigned char numBones; + + unsigned short origMeshVertID; + + // for sw skinned verts, these are indices into the global list of bones + // for hw skinned verts, these are hardware bone indices + char boneID[MAX_NUM_BONES_PER_VERT]; +}; + +enum StripHeaderFlags_t { + STRIP_IS_TRILIST = 0x01, + STRIP_IS_TRISTRIP = 0x02 +}; + +// a strip is a piece of a stripgroup that is divided by bones +// (and potentially tristrips if we remove some degenerates.) +struct StripHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + // indexOffset offsets into the mesh's index array. + int numIndices; + int indexOffset; + + // vertexOffset offsets into the mesh's vert array. + int numVerts; + int vertOffset; + + // use this to enable/disable skinning. + // May decide (in optimize.cpp) to put all with 1 bone in a different strip + // than those that need skinning. + short numBones; + + unsigned char flags; + + int numBoneStateChanges; + int boneStateChangeOffset; + inline BoneStateChangeHeader_t *pBoneStateChange( int i ) const + { + return (BoneStateChangeHeader_t *)(((byte *)this) + boneStateChangeOffset) + i; + }; +}; + +enum StripGroupFlags_t +{ + STRIPGROUP_IS_FLEXED = 0x01, + STRIPGROUP_IS_HWSKINNED = 0x02, + STRIPGROUP_IS_DELTA_FLEXED = 0x04, + STRIPGROUP_SUPPRESS_HW_MORPH = 0x08, // NOTE: This is a temporary flag used at run time. +}; + +// a locking group +// a single vertex buffer +// a single index buffer +struct StripGroupHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + // These are the arrays of all verts and indices for this mesh. strips index into this. + int numVerts; + int vertOffset; + inline Vertex_t *pVertex( int i ) const + { + return (Vertex_t *)(((byte *)this) + vertOffset) + i; + }; + + int numIndices; + int indexOffset; + inline unsigned short *pIndex( int i ) const + { + return (unsigned short *)(((byte *)this) + indexOffset) + i; + }; + + int numStrips; + int stripOffset; + inline StripHeader_t *pStrip( int i ) const + { + return (StripHeader_t *)(((byte *)this) + stripOffset) + i; + }; + + unsigned char flags; +}; + +enum MeshFlags_t { + // these are both material properties, and a mesh has a single material. + MESH_IS_TEETH = 0x01, + MESH_IS_EYES = 0x02 +}; + +// a collection of locking groups: +// up to 4: +// non-flexed, hardware skinned +// flexed, hardware skinned +// non-flexed, software skinned +// flexed, software skinned +// +// A mesh has a material associated with it. +struct MeshHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int numStripGroups; + int stripGroupHeaderOffset; + inline StripGroupHeader_t *pStripGroup( int i ) const + { + StripGroupHeader_t *pDebug = (StripGroupHeader_t *)(((byte *)this) + stripGroupHeaderOffset) + i; + return pDebug; + }; + unsigned char flags; +}; + +struct ModelLODHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int numMeshes; + int meshOffset; + float switchPoint; + inline MeshHeader_t *pMesh( int i ) const + { + MeshHeader_t *pDebug = (MeshHeader_t *)(((byte *)this) + meshOffset) + i; + return pDebug; + }; +}; + +// This maps one to one with models in the mdl file. +// There are a bunch of model LODs stored inside potentially due to the qc $lod command +struct ModelHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int numLODs; // garymcthack - this is also specified in FileHeader_t + int lodOffset; + inline ModelLODHeader_t *pLOD( int i ) const + { + ModelLODHeader_t *pDebug = ( ModelLODHeader_t *)(((byte *)this) + lodOffset) + i; + return pDebug; + }; +}; + +struct BodyPartHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int numModels; + int modelOffset; + inline ModelHeader_t *pModel( int i ) const + { + ModelHeader_t *pDebug = (ModelHeader_t *)(((byte *)this) + modelOffset) + i; + return pDebug; + }; +}; + +struct MaterialReplacementHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + short materialID; + int replacementMaterialNameOffset; + inline const char *pMaterialReplacementName( void ) + { + const char *pDebug = (const char *)(((byte *)this) + replacementMaterialNameOffset); + return pDebug; + } +}; + +struct MaterialReplacementListHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int numReplacements; + int replacementOffset; + inline MaterialReplacementHeader_t *pMaterialReplacement( int i ) const + { + MaterialReplacementHeader_t *pDebug = ( MaterialReplacementHeader_t *)(((byte *)this) + replacementOffset) + i; + return pDebug; + } +}; + +struct FileHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + // file version as defined by OPTIMIZED_MODEL_FILE_VERSION + int version; + + // hardware params that affect how the model is to be optimized. + int vertCacheSize; + unsigned short maxBonesPerStrip; + unsigned short maxBonesPerTri; + int maxBonesPerVert; + + // must match checkSum in the .mdl + int checkSum; + + int numLODs; // garymcthack - this is also specified in ModelHeader_t and should match + + // one of these for each LOD + int materialReplacementListOffset; + MaterialReplacementListHeader_t *pMaterialReplacementList( int lodID ) const + { + MaterialReplacementListHeader_t *pDebug = + (MaterialReplacementListHeader_t *)(((byte *)this) + materialReplacementListOffset) + lodID; + return pDebug; + } + + int numBodyParts; + int bodyPartOffset; + inline BodyPartHeader_t *pBodyPart( int i ) const + { + BodyPartHeader_t *pDebug = (BodyPartHeader_t *)(((byte *)this) + bodyPartOffset) + i; + return pDebug; + }; +}; + +#pragma pack() + +void WriteOptimizedFiles( studiohdr_t *phdr, s_bodypart_t *pSrcBodyParts ); + +}; // namespace OptimizedModel + +#endif // OPTIMIZE_H diff --git a/public/overlaytext.h b/public/overlaytext.h new file mode 100644 index 0000000..d720652 --- /dev/null +++ b/public/overlaytext.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( OVERLAYTEXT_H ) +#define OVERLAYTEXT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" + +class OverlayText_t +{ +public: + OverlayText_t() + { + nextOverlayText = 0; + origin.Init(); + bUseOrigin = false; + lineOffset = 0; + flXPos = 0; + flYPos = 0; + text[ 0 ] = 0; + m_flEndTime = 0.0f; + m_nServerCount = -1; + m_nCreationTick = -1; + r = g = b = a = 255; + } + + bool IsDead(); + void SetEndTime( float duration ); + + Vector origin; + bool bUseOrigin; + int lineOffset; + float flXPos; + float flYPos; + char text[512]; + float m_flEndTime; // When does this text go away + int m_nCreationTick; // If > 0, show only one server frame + int m_nServerCount; // compare server spawn count to remove stale overlays + int r; + int g; + int b; + int a; + OverlayText_t *nextOverlayText; +}; + +#endif // OVERLAYTEXT_H \ No newline at end of file diff --git a/public/p4lib/ip4.h b/public/p4lib/ip4.h new file mode 100644 index 0000000..d37ab39 --- /dev/null +++ b/public/p4lib/ip4.h @@ -0,0 +1,193 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IP4_H +#define IP4_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlsymbol.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" +#include "appframework/IAppSystem.h" + + +//----------------------------------------------------------------------------- +// Current perforce file state +//----------------------------------------------------------------------------- +enum P4FileState_t +{ + P4FILE_UNOPENED = 0, + P4FILE_OPENED_FOR_ADD, + P4FILE_OPENED_FOR_EDIT, + P4FILE_OPENED_FOR_DELETE, + P4FILE_OPENED_FOR_INTEGRATE, +}; + + +//----------------------------------------------------------------------------- +// Purpose: definition of a file +//----------------------------------------------------------------------------- +struct P4File_t +{ + CUtlSymbol m_sName; // file name + CUtlSymbol m_sPath; // residing folder + CUtlSymbol m_sDepotFile; // the name in the depot + CUtlSymbol m_sClientFile; // the name on the client in Perforce syntax + CUtlSymbol m_sLocalFile; // the name on the client in local syntax + CUtlSymbol m_sFileType; // the type according to the server, see p4 help filetypes + int m_iHeadRevision; // head revision number + int m_iHaveRevision; // the revision the clientspec has synced locally + bool m_bDir; // directory + bool m_bDeleted; // deleted + P4FileState_t m_eOpenState; // current change state + int m_iChangelist; // changelist current opened in +}; + + +//----------------------------------------------------------------------------- +// Purpose: a single revision of a file +//----------------------------------------------------------------------------- +struct P4Revision_t +{ + int m_iChange; // changelist number + int m_nYear, m_nMonth, m_nDay; + int m_nHour, m_nMinute, m_nSecond; + + CUtlSymbol m_sUser; // submitting user + CUtlSymbol m_sClient; // submitting client + CUtlString m_Description; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a single clientspec +//----------------------------------------------------------------------------- +struct P4Client_t +{ + CUtlSymbol m_sName; + CUtlSymbol m_sUser; + CUtlSymbol m_sHost; // machine name this client is on + CUtlSymbol m_sLocalRoot; // local path +}; + + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing P4 commands +//----------------------------------------------------------------------------- +#define P4_INTERFACE_VERSION "VP4002" + +abstract_class IP4 : public IAppSystem +{ +public: + // name of the current clientspec + virtual P4Client_t &GetActiveClient() = 0; + + // changes the current client + virtual void SetActiveClient(const char *clientname) = 0; + + // Refreshes the current client from p4 settings + virtual void RefreshActiveClient() = 0; + + // translate filespecs into the desired syntax + virtual void GetDepotFilePath(char *depotFilePath, const char *filespec, int size) = 0; + virtual void GetClientFilePath(char *clientFilePath, const char *filespec, int size) = 0; + virtual void GetLocalFilePath(char *localFilePath, const char *filespec, int size) = 0; + + // retreives the list of files in a path + virtual CUtlVector &GetFileList( const char *path ) = 0; + + // returns the list of files opened for edit/integrate/delete + virtual void GetOpenedFileList( CUtlVector &fileList ) = 0; + virtual void GetOpenedFileList( const char *pRootDirectory, CUtlVector &fileList ) = 0; + virtual void GetOpenedFileListInPath( const char *pPathID, CUtlVector &fileList ) = 0; + + // retrieves revision history for a file or directory + virtual CUtlVector &GetRevisionList( const char *path, bool bIsDir ) = 0; + + // returns a list of clientspecs + virtual CUtlVector &GetClientList() = 0; + + // changes the clientspec to remove the specified path (cloaking) + virtual void RemovePathFromActiveClientspec( const char *path ) = 0; + + // sets the name of the changelist to open files under, NULL for "Default" changelist + virtual void SetOpenFileChangeList(const char *pChangeListName) = 0; + + // file manipulation + virtual bool OpenFileForAdd( const char *pFullPath ) = 0; + virtual bool OpenFileForEdit( const char *pFullPath ) = 0; + virtual bool OpenFileForDelete( const char *pFullPath ) = 0; + + // submit/revert + virtual bool SubmitFile( const char *pFullPath, const char *pDescription ) = 0; + virtual bool RevertFile( const char *pFullPath ) = 0; + + // file checkin/checkout for multiple files + virtual bool OpenFilesForAdd( int nCount, const char **ppFullPathList ) = 0; + virtual bool OpenFilesForEdit( int nCount, const char **ppFullPathList ) = 0; + virtual bool OpenFilesForDelete( int nCount, const char **ppFullPathList ) = 0; + + // submit/revert for multiple files + virtual bool SubmitFiles( int nCount, const char **ppFullPathList, const char *pDescription ) = 0; + virtual bool RevertFiles( int nCount, const char **ppFullPathList ) = 0; + + // Is this file in perforce? + virtual bool IsFileInPerforce( const char *pFullPath ) = 0; + + // Get the perforce file state + virtual P4FileState_t GetFileState( const char *pFullPath ) = 0; + + // depot root + virtual const char *GetDepotRoot() = 0; + virtual int GetDepotRootLength() = 0; + + // local root + virtual const char *GetLocalRoot() = 0; + virtual int GetLocalRootLength() = 0; + + // Gets a string for a symbol + virtual const char *String( CUtlSymbol s ) const = 0; + + // Returns which clientspec a file lies under. This will + // search for p4config files in root directories of the file + // It returns false if it didn't find a p4config file. + virtual bool GetClientSpecForFile( const char *pFullPath, char *pClientSpec, int nMaxLen ) = 0; + virtual bool GetClientSpecForDirectory( const char *pFullPathDir, char *pClientSpec, int nMaxLen ) = 0; + + // Returns which clientspec a filesystem path ID lies under. This will + // search for p4config files in all root directories of the all paths in + // the search path. NOTE: All directories in a path need to use the same clientspec + // or this function will return false. + // It returns false if it didn't find a p4config file. + virtual bool GetClientSpecForPath( const char *pPathId, char *pClientSpec, int nMaxLen ) = 0; + + // Opens a file in p4 win + virtual void OpenFileInP4Win( const char *pFullPath ) = 0; + + // have we connected? if not, nothing works + virtual bool IsConnectedToServer( bool bRetry = true ) = 0; + + // Returns file information for a single file + virtual bool GetFileInfo( const char *pFullPath, P4File_t *pFileInfo ) = 0; + + // Reopens a file for edit or add with the specified filetype. To see the valid strings for + // filetypes, see p4 help fileinfo. Perforce has to know about files before the filetype can + // be changed (so for new files, they must be added first, then the filetype modified). + virtual bool SetFileType( const char *pFullPath, const char *pFileType ) = 0; + + // retreives the list of files in a path, using a known client spec + virtual CUtlVector &GetFileListUsingClientSpec( const char *pPath, const char *pClientSpec ) = 0; + + // retrieves the last error from the last op (which is likely to span multiple lines) + // this is only valid after OpenFile[s]For{Add,Edit,Delete} or {Submit,Revert}File[s] + virtual const char *GetLastError() = 0; +}; + + + +#endif // IP4_H diff --git a/public/particles/particles.h b/public/particles/particles.h new file mode 100644 index 0000000..4066d85 --- /dev/null +++ b/public/particles/particles.h @@ -0,0 +1,2264 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: particle system definitions +// +//===========================================================================// + +#ifndef PARTICLES_H +#define PARTICLES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "mathlib/ssemath.h" +#include "materialsystem/imaterialsystem.h" +#include "dmxloader/dmxelement.h" +#include "tier1/utlintrusivelist.h" +#include "vstdlib/random.h" +#include "tier1/utlobjectreference.h" +#include "tier1/UtlStringMap.h" +#include "tier1/utlmap.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "trace.h" +#include "tier1/utlsoacontainer.h" + +#if defined( CLIENT_DLL ) +#include "c_pixel_visibility.h" +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct DmxElementUnpackStructure_t; +class CParticleSystemDefinition; +class CParticleCollection; +class CParticleOperatorInstance; +class CParticleSystemDictionary; +class CUtlBuffer; +class IParticleOperatorDefinition; +class CSheet; +class CMeshBuilder; +extern float s_pRandomFloats[]; + + +//----------------------------------------------------------------------------- +// Random numbers +//----------------------------------------------------------------------------- +#define MAX_RANDOM_FLOATS 4096 +#define RANDOM_FLOAT_MASK ( MAX_RANDOM_FLOATS - 1 ) + + +//----------------------------------------------------------------------------- +// Particle attributes +//----------------------------------------------------------------------------- +#define MAX_PARTICLE_ATTRIBUTES 32 + +#define DEFPARTICLE_ATTRIBUTE( name, bit ) \ + const int PARTICLE_ATTRIBUTE_##name##_MASK = (1 << bit); \ + const int PARTICLE_ATTRIBUTE_##name = bit; + +// required +DEFPARTICLE_ATTRIBUTE( XYZ, 0 ); + +// particle lifetime (duration) of particle as a float. +DEFPARTICLE_ATTRIBUTE( LIFE_DURATION, 1 ); + +// prev coordinates for verlet integration +DEFPARTICLE_ATTRIBUTE( PREV_XYZ, 2 ); + +// radius of particle +DEFPARTICLE_ATTRIBUTE( RADIUS, 3 ); + +// rotation angle of particle +DEFPARTICLE_ATTRIBUTE( ROTATION, 4 ); + +// rotation speed of particle +DEFPARTICLE_ATTRIBUTE( ROTATION_SPEED, 5 ); + +// tint of particle +DEFPARTICLE_ATTRIBUTE( TINT_RGB, 6 ); + +// alpha tint of particle +DEFPARTICLE_ATTRIBUTE( ALPHA, 7 ); + +// creation time stamp (relative to particle system creation) +DEFPARTICLE_ATTRIBUTE( CREATION_TIME, 8 ); + +// sequnece # (which animation sequence number this particle uses ) +DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER, 9 ); + +// length of the trail +DEFPARTICLE_ATTRIBUTE( TRAIL_LENGTH, 10 ); + +// unique particle identifier +DEFPARTICLE_ATTRIBUTE( PARTICLE_ID, 11 ); + +// unique rotation around up vector +DEFPARTICLE_ATTRIBUTE( YAW, 12 ); + +// second sequnece # (which animation sequence number this particle uses ) +DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER1, 13 ); + +// hit box index +DEFPARTICLE_ATTRIBUTE( HITBOX_INDEX, 14 ); + +DEFPARTICLE_ATTRIBUTE( HITBOX_RELATIVE_XYZ, 15 ); + +DEFPARTICLE_ATTRIBUTE( ALPHA2, 16 ); + +// particle trace caching fields +DEFPARTICLE_ATTRIBUTE( TRACE_P0, 17 ); // start pnt of trace +DEFPARTICLE_ATTRIBUTE( TRACE_P1, 18 ); // end pnt of trace +DEFPARTICLE_ATTRIBUTE( TRACE_HIT_T, 19 ); // 0..1 if hit +DEFPARTICLE_ATTRIBUTE( TRACE_HIT_NORMAL, 20 ); // 0 0 0 if no hit + + +#define MAX_PARTICLE_CONTROL_POINTS 64 + +#define ATTRIBUTES_WHICH_ARE_VEC3S_MASK ( PARTICLE_ATTRIBUTE_TRACE_P0_MASK | PARTICLE_ATTRIBUTE_TRACE_P1_MASK | \ + PARTICLE_ATTRIBUTE_TRACE_HIT_NORMAL | PARTICLE_ATTRIBUTE_XYZ_MASK | \ + PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | \ + PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK ) +#define ATTRIBUTES_WHICH_ARE_0_TO_1 (PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK) +#define ATTRIBUTES_WHICH_ARE_ANGLES (PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK ) +#define ATTRIBUTES_WHICH_ARE_INTS (PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK ) + +#if defined( _X360 ) +#define MAX_PARTICLES_IN_A_SYSTEM 2000 +#else +#define MAX_PARTICLES_IN_A_SYSTEM 5000 +#endif + +// Set this to 1 or 0 to enable or disable particle profiling. +// Note that this profiling is expensive on Linux, and some anti-virus +// products can make this *extremely* expensive on Windows. +#define MEASURE_PARTICLE_PERF 0 + + +//----------------------------------------------------------------------------- +// Particle function types +//----------------------------------------------------------------------------- +enum ParticleFunctionType_t +{ + FUNCTION_RENDERER = 0, + FUNCTION_OPERATOR, + FUNCTION_INITIALIZER, + FUNCTION_EMITTER, + FUNCTION_CHILDREN, // NOTE: This one is a fake function type, only here to help eliminate a ton of duplicated code in the editor + FUNCTION_FORCEGENERATOR, + FUNCTION_CONSTRAINT, + PARTICLE_FUNCTION_COUNT +}; + +struct CParticleVisibilityInputs +{ + float m_flCameraBias; + float m_flInputMin; + float m_flInputMax; + float m_flAlphaScaleMin; + float m_flAlphaScaleMax; + float m_flRadiusScaleMin; + float m_flRadiusScaleMax; + float m_flProxyRadius; + float m_flBBoxScale; + bool m_bUseBBox; + int m_nCPin; +}; + +struct ModelHitBoxInfo_t +{ + Vector m_vecBoxMins; + Vector m_vecBoxMaxes; + matrix3x4_t m_Transform; +}; + +class CModelHitBoxesInfo +{ +public: + float m_flLastUpdateTime; + float m_flPrevLastUpdateTime; + int m_nNumHitBoxes; + int m_nNumPrevHitBoxes; + ModelHitBoxInfo_t *m_pHitBoxes; + ModelHitBoxInfo_t *m_pPrevBoxes; + + bool CurAndPrevValid( void ) const + { + return ( m_nNumHitBoxes && ( m_nNumPrevHitBoxes == m_nNumHitBoxes ) ); + } + + CModelHitBoxesInfo( void ) + { + m_flLastUpdateTime = -1; + m_nNumHitBoxes = 0; + m_nNumPrevHitBoxes = 0; + m_pHitBoxes = NULL; + m_pPrevBoxes = NULL; + } + + ~CModelHitBoxesInfo( void ) + { + if ( m_pHitBoxes ) + delete[] m_pHitBoxes; + if ( m_pPrevBoxes ) + delete[] m_pPrevBoxes; + } + +}; + + + + +//----------------------------------------------------------------------------- +// Interface to allow the particle system to call back into the client +//----------------------------------------------------------------------------- + +#define PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION "VParticleSystemQuery001" + +class IParticleSystemQuery : public IAppSystem +{ +public: + virtual void GetLightingAtPoint( const Vector& vecOrigin, Color &tint ) = 0; + virtual void TraceLine( const Vector& vecAbsStart, + const Vector& vecAbsEnd, unsigned int mask, + const class IHandleEntity *ignore, + int collisionGroup, + CBaseTrace *ptr ) = 0; + + // given a possible spawn point, tries to movie it to be on or in the source object. returns + // true if it succeeded + virtual bool MovePointInsideControllingObject( CParticleCollection *pParticles, + void *pObject, + Vector *pPnt ) + { + return true; + } + + virtual bool IsPointInControllingObjectHitBox( + CParticleCollection *pParticles, + int nControlPointNumber, Vector vecPos, bool bBBoxOnly = false ) + { + return true; + } + + virtual int GetCollisionGroupFromName( const char *pszCollisionGroupName ) + { + return 0; // == COLLISION_GROUP_NONE + } + + virtual void GetRandomPointsOnControllingObjectHitBox( + CParticleCollection *pParticles, + int nControlPointNumber, + int nNumPtsOut, + float flBBoxScale, + int nNumTrysToGetAPointInsideTheModel, + Vector *pPntsOut, + Vector vecDirectionBias, + Vector *pHitBoxRelativeCoordOut = NULL, + int *pHitBoxIndexOut = NULL ) = 0; + + + virtual int GetControllingObjectHitBoxInfo( + CParticleCollection *pParticles, + int nControlPointNumber, + int nBufSize, // # of output slots available + ModelHitBoxInfo_t *pHitBoxOutputBuffer ) + { + // returns number of hit boxes output + return 0; + } + + virtual Vector GetLocalPlayerPos( void ) + { + return vec3_origin; + } + + virtual void GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL ) + { + *pForward = vec3_origin; + *pRight = vec3_origin; + *pUp = vec3_origin; + } + + virtual float GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale ) = 0; + + virtual void SetUpLightingEnvironment( const Vector& pos ) + { + } +}; + + +//----------------------------------------------------------------------------- +// +// Particle system manager. Using a class because tools need it that way +// so the SFM and PET tools can share managers despite being linked to +// separate particle system .libs +// +//----------------------------------------------------------------------------- +typedef int ParticleSystemHandle_t; + +class CParticleSystemMgr +{ +public: + // Constructor, destructor + CParticleSystemMgr(); + ~CParticleSystemMgr(); + + // Initialize the particle system + bool Init( IParticleSystemQuery *pQuery ); + + // methods to add builtin operators. If you don't call these at startup, you won't be able to sim or draw. These are done separately from Init, so that + // the server can omit the code needed for rendering/simulation, if desired. + void AddBuiltinSimulationOperators( void ); + void AddBuiltinRenderingOperators( void ); + + + + // Registration of known operators + void AddParticleOperator( ParticleFunctionType_t nOpType, IParticleOperatorDefinition *pOpFactory ); + + // Read a particle config file, add it to the list of particle configs + bool ReadParticleConfigFile( const char *pFileName, bool bPrecache, bool bDecommitTempMemory = true ); + bool ReadParticleConfigFile( CUtlBuffer &buf, bool bPrecache, bool bDecommitTempMemory = true, const char *pFileName = NULL ); + void DecommitTempMemory(); + + // For recording, write a specific particle system to a CUtlBuffer in DMX format + bool WriteParticleConfigFile( const char *pParticleSystemName, CUtlBuffer &buf, bool bPreventNameBasedLookup = false ); + bool WriteParticleConfigFile( const DmObjectId_t& id, CUtlBuffer &buf, bool bPreventNameBasedLookup = false ); + + // create a particle system by name. returns null if one of that name does not exist + CParticleCollection *CreateParticleCollection( const char *pParticleSystemName, float flDelay = 0.0f, int nRandomSeed = 0 ); + + // create a particle system given a particle system id + CParticleCollection *CreateParticleCollection( const DmObjectId_t &id, float flDelay = 0.0f, int nRandomSeed = 0 ); + + // Is a particular particle system defined? + bool IsParticleSystemDefined( const char *pParticleSystemName ); + bool IsParticleSystemDefined( const DmObjectId_t &id ); + + // Returns the index of the specified particle system. + ParticleSystemHandle_t GetParticleSystemIndex( const char *pParticleSystemName ); + + // Returns the name of the specified particle system. + const char *GetParticleSystemNameFromIndex( ParticleSystemHandle_t iIndex ); + + // Return the number of particle systems in our dictionary + int GetParticleSystemCount( void ); + + // call to get available particle operator definitions + // NOTE: FUNCTION_CHILDREN will return a faked one, for ease of writing the editor + CUtlVector< IParticleOperatorDefinition *> &GetAvailableParticleOperatorList( ParticleFunctionType_t nWhichList ); + + // Returns the unpack structure for a particle system definition + const DmxElementUnpackStructure_t *GetParticleSystemDefinitionUnpackStructure(); + + // Particle sheet management + void ShouldLoadSheets( bool bLoadSheets ); + CSheet *FindOrLoadSheet( char const *pszFname, ITexture *pTexture ); + CSheet *FindOrLoadSheet( IMaterial *pMaterial ); + void FlushAllSheets( void ); + + + // Render cache used to render opaque particle collections + void ResetRenderCache( void ); + void AddToRenderCache( CParticleCollection *pParticles ); + void DrawRenderCache( bool bShadowDepth ); + + IParticleSystemQuery *Query( void ) { return m_pQuery; } + + // return the particle field name + const char* GetParticleFieldName( int nParticleField ) const; + + // WARNING: the pointer returned by this function may be invalidated + // *at any time* by the editor, so do not ever cache it. + CParticleSystemDefinition* FindParticleSystem( const char *pName ); + CParticleSystemDefinition* FindParticleSystem( const DmObjectId_t& id ); + + void CommitProfileInformation( bool bCommit ); // call after simulation, if you want + // sim time recorded. if oyu pass + // flase, info will be thrown away and + // uncomitted time reset. Having this + // function lets you only record + // profile data for slow frames if + // desired. + + + void DumpProfileInformation( void ); // write particle_profile.csv + + // Cache/uncache materials used by particle systems + void PrecacheParticleSystem( const char *pName ); + void UncacheAllParticleSystems(); + + // Sets the last simulation time, used for particle system sleeping logic + void SetLastSimulationTime( float flTime ); + float GetLastSimulationTime() const; + + int Debug_GetTotalParticleCount() const; + bool Debug_FrameWarningNeededTestAndReset(); + float ParticleThrottleScaling() const; // Returns 1.0 = not restricted, 0.0 = fully restricted (i.e. don't draw!) + bool ParticleThrottleRandomEnable() const; // Retruns a randomish bool to say if you should draw this particle. + + void TallyParticlesRendered( int nVertexCount, int nIndexCount = 0 ); + +private: + struct RenderCache_t + { + IMaterial *m_pMaterial; + CUtlVector< CParticleCollection * > m_ParticleCollections; + }; + + struct BatchStep_t + { + CParticleCollection *m_pParticles; + CParticleOperatorInstance *m_pRenderer; + void *m_pContext; + int m_nFirstParticle; + int m_nParticleCount; + int m_nVertCount; + }; + + struct Batch_t + { + int m_nVertCount; + int m_nIndexCount; + CUtlVector< BatchStep_t > m_BatchStep; + }; + + // Unserialization-related methods + bool ReadParticleDefinitions( CUtlBuffer &buf, const char *pFileName, bool bPrecache, bool bDecommitTempMemory ); + void AddParticleSystem( CDmxElement *pParticleSystem ); + + // Serialization-related methods + CDmxElement *CreateParticleDmxElement( const DmObjectId_t &id ); + CDmxElement *CreateParticleDmxElement( const char *pParticleSystemName ); + + bool WriteParticleConfigFile( CDmxElement *pParticleSystem, CUtlBuffer &buf, bool bPreventNameBasedLookup ); + + // Builds a list of batches to render + void BuildBatchList( int iRenderCache, IMatRenderContext *pRenderContext, CUtlVector< Batch_t >& batches ); + + // Known operators + CUtlVector m_ParticleOperators[PARTICLE_FUNCTION_COUNT]; + + // Particle system dictionary + CParticleSystemDictionary *m_pParticleSystemDictionary; + + // typedef CUtlMap< ITexture *, CSheet* > SheetsCache; + typedef CUtlStringMap< CSheet* > SheetsCache_t; + SheetsCache_t m_SheetList; + + // attaching and dtaching killlists. when simulating, a particle system gets a kill list. after + // simulating, the memory for that will be used for the next particle system. This matters for + // threaded particles, because we don't want to share the same kill list between simultaneously + // simulating particle systems. + void AttachKillList( CParticleCollection *pParticles); + void DetachKillList( CParticleCollection *pParticles); + + // For visualization (currently can only visualize one operator at a time) + CParticleCollection *m_pVisualizedParticles; + DmObjectId_t m_VisualizedOperatorId; + IParticleSystemQuery *m_pQuery; + CUtlVector< RenderCache_t > m_RenderCache; + IMaterial *m_pShadowDepthMaterial; + float m_flLastSimulationTime; + + bool m_bDidInit; + bool m_bUsingDefaultQuery; + bool m_bShouldLoadSheets; + + int m_nNumFramesMeasured; + + enum { c_nNumFramesTracked = 10 }; + int m_nParticleVertexCountHistory[c_nNumFramesTracked]; + float m_fParticleCountScaling; + int m_nParticleIndexCount; + int m_nParticleVertexCount; + bool m_bFrameWarningNeeded; + + friend class CParticleSystemDefinition; + friend class CParticleCollection; +}; + +extern CParticleSystemMgr *g_pParticleSystemMgr; + + +//----------------------------------------------------------------------------- +// A particle system can only have 1 operator using a particular ID +//----------------------------------------------------------------------------- +enum ParticleOperatorId_t +{ + // Generic IDs + OPERATOR_GENERIC = -2, // Can have as many of these as you want + OPERATOR_SINGLETON = -1, // Can only have 1 operator with the same name as this one + + // Renderer operator IDs + + // Operator IDs + + // Initializer operator IDs + OPERATOR_PI_POSITION, // Particle initializer: position (can only have 1 position setter) + OPERATOR_PI_RADIUS, + OPERATOR_PI_ALPHA, + OPERATOR_PI_TINT_RGB, + OPERATOR_PI_ROTATION, + OPERATOR_PI_YAW, + + // Emitter IDs + + OPERATOR_ID_COUNT, +}; + + +//----------------------------------------------------------------------------- +// Class factory for particle operators +//----------------------------------------------------------------------------- +class IParticleOperatorDefinition +{ +public: + virtual const char *GetName() const = 0; + virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const = 0; +// virtual void DestroyInstance( CParticleOperatorInstance *pInstance ) const = 0; + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const = 0; + virtual ParticleOperatorId_t GetId() const = 0; + virtual bool IsObsolete() const = 0; + virtual size_t GetClassSize() const = 0; + +#if MEASURE_PARTICLE_PERF + // performance monitoring + float m_flMaxExecutionTime; + float m_flTotalExecutionTime; + float m_flUncomittedTime; + + FORCEINLINE void RecordExecutionTime( float flETime ) + { + m_flUncomittedTime += flETime; + m_flMaxExecutionTime = MAX( m_flMaxExecutionTime, flETime ); + } + + FORCEINLINE float TotalRecordedExecutionTime( void ) const + { + return m_flTotalExecutionTime; + } + + FORCEINLINE float MaximumRecordedExecutionTime( void ) const + { + return m_flMaxExecutionTime; + } +#endif +}; + + +//----------------------------------------------------------------------------- +// Particle operators +//----------------------------------------------------------------------------- +class CParticleOperatorInstance +{ +public: + // custom allocators so we can be simd aligned + void *operator new( size_t nSize ); + void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ); + void operator delete( void *pData ); + void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ); + + // unpack structure will be applied by creator. add extra initialization needed here + virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement ) + { + } + + virtual size_t GetRequiredContextBytes( ) const + { + return 0; + } + + virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const + { + } + + virtual uint32 GetWrittenAttributes( void ) const = 0; + virtual uint32 GetReadAttributes( void ) const = 0; + virtual uint64 GetReadControlPointMask() const + { + return 0; + } + + // Used when an operator needs to read the attributes of a particle at spawn time + virtual uint32 GetReadInitialAttributes( void ) const + { + return 0; + } + + // a particle simulator does this + virtual void Operate( CParticleCollection *pParticles, float flOpStrength, void *pContext ) const + { + } + + // a renderer overrides this + virtual void Render( IMatRenderContext *pRenderContext, + CParticleCollection *pParticles, void *pContext ) const + { + } + + virtual bool IsBatchable() const + { + return true; + } + + virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const + { + } + + // Returns the number of verts + indices to render + virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const + { + *pVertsUsed = 0; + *pIndicesUsed = 0; + return 0; + } + + + // emitters over-ride this. Return a mask of what fields you initted + virtual uint32 Emit( CParticleCollection *pParticles, float flOpCurStrength, + void *pContext ) const + { + return 0; + } + + // emitters over-ride this. + virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const + { + } + virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const + { + } + virtual void Restart( CParticleCollection *pParticles, void *pContext ) {} + + // initters over-ride this + virtual void InitParticleSystem( CParticleCollection *pParticles, void *pContext ) const + { + } + + + // a force generator does this. It accumulates in the force array + virtual void AddForces( FourVectors *AccumulatedForces, + CParticleCollection *pParticles, + int nBlocks, + float flCurStrength, + void *pContext ) const + { + } + + + // this is called for each constarint every frame. It can set up data like nearby world traces, + // etc + virtual void SetupConstraintPerFrameData( CParticleCollection *pParticles, + void *pContext ) const + { + } + + + // a constraint overrides this. It shold return a true if it did anything + virtual bool EnforceConstraint( int nStartBlock, + int nNumBlocks, + CParticleCollection *pParticles, + void *pContext, + int nNumValidParticlesInLastChunk ) const + { + return false; + } + + // should the constraint be run only once after all other constraints? + virtual bool IsFinalConstraint( void ) const + { + return false; + } + + // determines if a mask needs to be initialized multiple times. + virtual bool InitMultipleOverride() + { + return false; + } + + + // Indicates if this initializer is scrub-safe (initializers don't use random numbers, for example) + virtual bool IsScrubSafe() + { + return false; + } + + // particle-initters over-ride this + virtual void InitNewParticlesScalar( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void *pContext ) const + { + } + + // init new particles in blocks of 4. initters that have sse smarts should over ride this. the scalar particle initter will still be cllaed for head/tail. + virtual void InitNewParticlesBlock( CParticleCollection *pParticles, int start_block, int n_blocks, int attribute_write_mask, void *pContext ) const + { + // default behaviour is to call the scalar one 4x times + InitNewParticlesScalar( pParticles, 4*start_block, 4*n_blocks, attribute_write_mask, pContext ); + } + + // splits particle initialization up into scalar and block sections, callingt he right code + void InitNewParticles( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask , void *pContext) const; + + + // this function is queried to determine if a particle system is over and doen with. A particle + // system is done with when it has noparticles and no operators intend to create any more + virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const + { + return false; + } + + // Returns the operator definition that spawned this operator + const IParticleOperatorDefinition *GetDefinition() + { + return m_pDef; + } + + virtual bool ShouldRunBeforeEmitters( void ) const + { + return false; + } + + // Does this operator require that particles remain in the order they were emitted? + virtual bool RequiresOrderInvariance( void ) const + { + return false; + } + + // Called when the SFM wants to skip forward in time + virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const {} + + // Returns a unique ID for this definition + const DmObjectId_t& GetId() { return m_Id; } + + // Used for editing + debugging to visualize the operator in 3D + virtual void Render( CParticleCollection *pParticles ) const {} + + // Used as a debugging mechanism to prevent bogus calls to RandomInt or RandomFloat inside operators + // Use CParticleCollection::RandomInt/RandomFloat instead + int RandomInt( int nMin, int nMax ) + { + // NOTE: Use CParticleCollection::RandomInt! + Assert(0); + return 0; + } + + float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ) + { + // NOTE: Use CParticleCollection::RandomFloat! + Assert(0); + return 0.0f; + } + + float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ) + { + // NOTE: Use CParticleCollection::RandomFloatExp! + Assert(0); + return 0.0f; + } + + float m_flOpStartFadeInTime; + float m_flOpEndFadeInTime; + float m_flOpStartFadeOutTime; + float m_flOpEndFadeOutTime; + float m_flOpFadeOscillatePeriod; + + virtual ~CParticleOperatorInstance( void ) + { + // so that sheet references, etc can be cleaned up + } + +protected: + // utility function for initting a scalar attribute to a random range in an sse fashion + void InitScalarAttributeRandomRangeBlock( int nAttributeId, float fMinValue, float fMaxValue, + CParticleCollection *pParticles, int nStartBlock, int nBlockCount ) const; + void InitScalarAttributeRandomRangeExpBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp, + CParticleCollection *pParticles, int nStartBlock, int nBlockCount ) const; + void AddScalarAttributeRandomRangeBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp, + CParticleCollection *pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert ) const; + +private: + friend class CParticleCollection; + + const IParticleOperatorDefinition *m_pDef; + void SetDefinition( const IParticleOperatorDefinition * pDef, const DmObjectId_t &id ) + { + m_pDef = pDef; + CopyUniqueId( id, &m_Id ); + } + + DmObjectId_t m_Id; + + template friend class CParticleOperatorDefinition; +}; + +class CParticleRenderOperatorInstance : public CParticleOperatorInstance +{ +public: + + CParticleVisibilityInputs VisibilityInputs; +}; + +//----------------------------------------------------------------------------- +// Helper macro for creating particle operator factories +//----------------------------------------------------------------------------- +template < class T > +class CParticleOperatorDefinition : public IParticleOperatorDefinition +{ +public: + CParticleOperatorDefinition( const char *pFactoryName, ParticleOperatorId_t id, bool bIsObsolete ) : m_pFactoryName( pFactoryName ), m_Id( id ) + { +#if MEASURE_PARTICLE_PERF + m_flTotalExecutionTime = 0.0f; + m_flMaxExecutionTime = 0.0f; + m_flUncomittedTime = 0.0f; +#endif + m_bIsObsolete = bIsObsolete; + } + + virtual const char *GetName() const + { + return m_pFactoryName; + } + + virtual ParticleOperatorId_t GetId() const + { + return m_Id; + } + + virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const + { + CParticleOperatorInstance *pOp = new T; + pOp->SetDefinition( this, id ); + return pOp; + } + + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const + { + return m_pUnpackParams; + } + + // Editor won't display obsolete operators + virtual bool IsObsolete() const + { + return m_bIsObsolete; + } + + virtual size_t GetClassSize() const + { + return sizeof( T ); + } + +private: + const char *m_pFactoryName; + ParticleOperatorId_t m_Id; + bool m_bIsObsolete; + static DmxElementUnpackStructure_t *m_pUnpackParams; +}; + +#define DECLARE_PARTICLE_OPERATOR( _className ) \ + DECLARE_DMXELEMENT_UNPACK() \ + friend class CParticleOperatorDefinition<_className > + +#define DEFINE_PARTICLE_OPERATOR( _className, _operatorName, _id ) \ + static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, false ) + +#define DEFINE_PARTICLE_OPERATOR_OBSOLETE( _className, _operatorName, _id ) \ + static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, true ) + +#define BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \ + BEGIN_DMXELEMENT_UNPACK( _className ) \ + DMXELEMENT_UNPACK_FIELD( "operator start fadein","0", float, m_flOpStartFadeInTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator end fadein","0", float, m_flOpEndFadeInTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator start fadeout","0", float, m_flOpStartFadeOutTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator end fadeout","0", float, m_flOpEndFadeOutTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator fade oscillate","0", float, m_flOpFadeOscillatePeriod ) + +#define END_PARTICLE_OPERATOR_UNPACK( _className ) \ + END_DMXELEMENT_UNPACK_TEMPLATE( _className, CParticleOperatorDefinition<_className>::m_pUnpackParams ) + +#define BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( _className ) \ + BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Input Control Point Number", "-1", int, VisibilityInputs.m_nCPin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Radius", "1.0", float, VisibilityInputs.m_flProxyRadius ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility input minimum","0", float, VisibilityInputs.m_flInputMin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility input maximum","1", float, VisibilityInputs.m_flInputMax ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale minimum","0", float, VisibilityInputs.m_flAlphaScaleMin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale maximum","1", float, VisibilityInputs.m_flAlphaScaleMax ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale minimum","1", float, VisibilityInputs.m_flRadiusScaleMin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale maximum","1", float, VisibilityInputs.m_flRadiusScaleMax ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Camera Depth Bias", "0", float, VisibilityInputs.m_flCameraBias ) + +// DMXELEMENT_UNPACK_FIELD( "Visibility Use Bounding Box for Proxy", "0", bool, VisibilityInputs.m_bUseBBox ) +// DMXELEMENT_UNPACK_FIELD( "Visibility Bounding Box Scale", "1.0", float, VisibilityInputs.m_flBBoxScale ) + +#define REGISTER_PARTICLE_OPERATOR( _type, _className ) \ + g_pParticleSystemMgr->AddParticleOperator( _type, &s_##_className##Factory ) + + +// need to think about particle constraints in terms of segregating affected particles so as to +// run multi-pass constraints on only a subset + + +//----------------------------------------------------------------------------- +// flags for particle systems +//----------------------------------------------------------------------------- +enum +{ + PCFLAGS_FIRST_FRAME = 0x1, + PCFLAGS_PREV_CONTROL_POINTS_INITIALIZED = 0x2, +}; + + + +#define DEBUG_PARTICLE_SORT 0 + +// sorting functionality for rendering. Call GetRenderList( bool bSorted ) to get the list of +// particles to render (sorted or not, including children). +// **do not casually change this structure**. The sorting code treats it interchangably as an SOA +// and accesses it using sse. Any changes to this struct need the sort code updated.** +struct ParticleRenderData_t +{ + float m_flSortKey; // what we sort by + int m_nIndex; // index or fudged index (for child particles) + float m_flRadius; // effective radius, using visibility +#if VALVE_LITTLE_ENDIAN + uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255 + uint8 m_nAlphaPad[3]; // this will be written to +#else + uint8 m_nAlphaPad[3]; // this will be written to + uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255 +#endif +}; + +struct ExtendedParticleRenderData_t : ParticleRenderData_t +{ + float m_flX; + float m_flY; + float m_flZ; + float m_flPad; +}; + + +typedef struct ALIGN16 _FourInts +{ + int32 m_nValue[4]; +} ALIGN16_POST FourInts; + + + +// structure describing the parameter block used by operators which use the path between two points to +// control particles. +struct CPathParameters +{ + int m_nStartControlPointNumber; + int m_nEndControlPointNumber; + int m_nBulgeControl; + float m_flBulge; + float m_flMidPoint; + + void ClampControlPointIndices( void ) + { + m_nStartControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartControlPointNumber ) ); + m_nEndControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndControlPointNumber ) ); + } +}; + +struct CParticleVisibilityData +{ + float m_flAlphaVisibility; + float m_flRadiusVisibility; + float m_flCameraBias; + bool m_bUseVisibility; +}; + +struct CParticleControlPoint +{ + Vector m_Position; + Vector m_PrevPosition; + + // orientation + Vector m_ForwardVector; + Vector m_UpVector; + Vector m_RightVector; + + // reference to entity or whatever this control point comes from + void *m_pObject; + + // parent for hierarchies + int m_nParent; +}; + + +// struct for simd xform to transform a point from an identitiy coordinate system to that of the control point +struct CParticleSIMDTransformation +{ + FourVectors m_v4Origin; + FourVectors m_v4Fwd; + FourVectors m_v4Up; + FourVectors m_v4Right; + + + FORCEINLINE void VectorRotate( FourVectors &InPnt ) + { + fltx4 fl4OutX = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.x ), MulSIMD( InPnt.z, m_v4Up.x ) ), MulSIMD( InPnt.y, m_v4Right.x ) ); + fltx4 fl4OutY = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.y ), MulSIMD( InPnt.z, m_v4Up.y ) ), MulSIMD( InPnt.y, m_v4Right.y ) ); + InPnt.z = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.z ), MulSIMD( InPnt.z, m_v4Up.z ) ), MulSIMD( InPnt.y, m_v4Right.z ) ); + InPnt.x = fl4OutX; + InPnt.y = fl4OutY; + } + + FORCEINLINE void VectorTransform( FourVectors &InPnt ) + { + VectorRotate( InPnt ); + InPnt.x = AddSIMD( InPnt.x, m_v4Origin.x ); + InPnt.y = AddSIMD( InPnt.y, m_v4Origin.y ); + InPnt.z = AddSIMD( InPnt.z, m_v4Origin.z ); + } +}; + +#define NUM_COLLISION_CACHE_MODES 4 + +//----------------------------------------------------------------------------- +// +// CParticleCollection +// +//----------------------------------------------------------------------------- +class CParticleCollection +{ +public: + ~CParticleCollection( void ); + + // Restarts the particle collection, stopping all non-continuous emitters + void Restart(); + + // compute bounds from particle list + void RecomputeBounds( void ); + + void SetControlPoint( int nWhichPoint, const Vector &v ); + void SetControlPointObject( int nWhichPoint, void *pObject ); + + void SetControlPointOrientation( int nWhichPoint, const Vector &forward, + const Vector &right, const Vector &up ); + void SetControlPointOrientation( int nWhichPoint, const Quaternion &q ); + void SetControlPointForwardVector( int nWhichPoint, const Vector &v ); + void SetControlPointUpVector( int nWhichPoint, const Vector &v ); + void SetControlPointRightVector( int nWhichPoint, const Vector &v ); + void SetControlPointParent( int nWhichPoint, int n ); + + // get the pointer to an attribute for a given particle. + // !!speed!! if you find yourself calling this anywhere that matters, + // you're not handling the simd-ness of the particle system well + // and will have bad perf. + const float *GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const; + const int *GetIntAttributePtr( int nAttribute, int nParticleNumber ) const; + const fltx4 *GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const; + const FourVectors *Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const; + const FourInts *Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const; + const int *GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const; + + + int *GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber ); + + float *GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber ); + fltx4 *GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut ); + FourVectors *Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut ); + + const float *GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const; + const fltx4 *GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const; + const FourVectors *GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const; + float *GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber ); + fltx4 *GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut ); + + void Simulate( float dt, bool updateBboxOnly ); + void SkipToTime( float t ); + + // the camera objetc may be compared for equality against control point objects + void Render( IMatRenderContext *pRenderContext, bool bTranslucentOnly = false, void *pCameraObject = NULL ); + + bool IsValid( void ) const; + const char *GetName() const; + + // IsFinished returns true when a system has no particles and won't be creating any more + bool IsFinished( void ); + + // Used to make sure we're accessing valid memory + bool IsValidAttributePtr( int nAttribute, const void *pPtr ) const; + + void SwapPosAndPrevPos( void ); + + void SetNActiveParticles( int nCount ); + void KillParticle(int nPidx); + + void StopEmission( bool bInfiniteOnly = false, bool bRemoveAllParticles = false, bool bWakeOnStop = false ); + void StartEmission( bool bInfiniteOnly = false ); + void SetDormant( bool bDormant ); + + const Vector& GetControlPointAtCurrentTime( int nControlPoint ) const; + void GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const; + void GetControlPointTransformAtCurrentTime( int nControlPoint, matrix3x4_t *pMat ); + void GetControlPointTransformAtCurrentTime( int nControlPoint, VMatrix *pMat ); + int GetControlPointParent( int nControlPoint ) const; + + // Used to retrieve the position of a control point + // somewhere between m_fCurTime and m_fCurTime - m_fPreviousDT + void GetControlPointAtTime( int nControlPoint, float flTime, Vector *pControlPoint ) const; + void GetControlPointAtPrevTime( int nControlPoint, Vector *pControlPoint ) const; + void GetControlPointOrientationAtTime( int nControlPoint, float flTime, Vector *pForward, Vector *pRight, Vector *pUp ); + void GetControlPointTransformAtTime( int nControlPoint, float flTime, matrix3x4_t *pMat ); + void GetControlPointTransformAtTime( int nControlPoint, float flTime, VMatrix *pMat ); + void GetControlPointTransformAtTime( int nControlPoint, float flTime, CParticleSIMDTransformation *pXForm ); + int GetHighestControlPoint( void ) const; + + // Has this particle moved recently (since the last simulation?) + bool HasMoved() const; + + // Control point accessed: + // NOTE: Unlike the definition's version of these methods, + // these OR-in the masks of their children. + bool ReadsControlPoint( int nPoint ) const; + + // Used by particle systems to generate random numbers. Do not call these methods - use sse + // code + int RandomInt( int nMin, int nMax ); + float RandomFloat( float flMin, float flMax ); + float RandomFloatExp( float flMin, float flMax, float flExponent ); + void RandomVector( float flMin, float flMax, Vector *pVector ); + void RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector ); + float RandomVectorInUnitSphere( Vector *pVector ); // Returns the length sqr of the vector + + // NOTE: These versions will produce the *same random numbers* if you give it the same random + // sample id. do not use these methods. + int RandomInt( int nRandomSampleId, int nMin, int nMax ); + float RandomFloat( int nRandomSampleId, float flMin, float flMax ); + float RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent ); + void RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector ); + void RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector ); + float RandomVectorInUnitSphere( int nRandomSampleId, Vector *pVector ); // Returns the length sqr of the vector + + fltx4 RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset ); + + + // Random number offset (for use in getting Random #s in operators) + int OperatorRandomSampleOffset() const; + + // Returns the render bounds + void GetBounds( Vector *pMin, Vector *pMax ); + + // Visualize operators (for editing/debugging) + void VisualizeOperator( const DmObjectId_t *pOpId = NULL ); + + // Does the particle system use the power of two frame buffer texture (refraction?) + bool UsesPowerOfTwoFrameBufferTexture( bool bThisFrame ) const; + + // Does the particle system use the full frame buffer texture (soft particles) + bool UsesFullFrameBufferTexture( bool bThisFrame ) const; + + // Is the particle system translucent? + bool IsTranslucent() const; + + // Is the particle system two-pass? + bool IsTwoPass() const; + + // Is the particle system batchable? + bool IsBatchable() const; + + // Renderer iteration + int GetRendererCount() const; + CParticleOperatorInstance *GetRenderer( int i ); + void *GetRendererContext( int i ); + + + bool CheckIfOperatorShouldRun( CParticleOperatorInstance const * op, float *pflCurStrength = NULL ); + + Vector TransformAxis( const Vector &SrcAxis, bool bLocalSpace, int nControlPointNumber = 0); + + // return backwards-sorted particle list. use --addressing + const ParticleRenderData_t *GetRenderList( IMatRenderContext *pRenderContext, bool bSorted, int *pNparticles, CParticleVisibilityData *pVisibilityData ); + + // calculate the points of a curve for a path + void CalculatePathValues( CPathParameters const &PathIn, + float flTimeStamp, + Vector *pStartPnt, + Vector *pMidPnt, + Vector *pEndPnt + ); + + int GetGroupID() const; + + void InitializeNewParticles( int nFirstParticle, int nParticleCount, uint32 nInittedMask ); + + // update hit boxes for control point if not updated yet for this sim step + void UpdateHitBoxInfo( int nControlPointNumber ); + + // Used by particle system definitions to manage particle collection lists + void UnlinkFromDefList( ); + + CParticleCollection *GetNextCollectionUsingSameDef() { return m_pNextDef; } + + CUtlReference< CSheet > m_Sheet; + + + +protected: + CParticleCollection( ); + + // Used by client code + bool Init( const char *pParticleSystemName ); + bool Init( CParticleSystemDefinition *pDef ); + + // Bloat the bounding box by bounds around the control point + void BloatBoundsUsingControlPoint(); + +private: + void GenerateSortedIndexList( Vector vecCameraPos, CParticleVisibilityData *pVisibilityData, bool bSorted ); + + void Init( CParticleSystemDefinition *pDef, float flDelay, int nRandomSeed ); + void InitStorage( CParticleSystemDefinition *pDef ); + void InitParticleCreationTime( int nFirstParticle, int nNumToInit ); + void CopyInitialAttributeValues( int nStartParticle, int nNumParticles ); + void ApplyKillList( void ); + void SetAttributeToConstant( int nAttribute, float fValue ); + void SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ ); + void InitParticleAttributes( int nStartParticle, int nNumParticles, int nAttrsLeftToInit ); + + // initialize this attribute for all active particles + void FillAttributeWithConstant( int nAttribute, float fValue ); + + // Updates the previous control points + void UpdatePrevControlPoints( float dt ); + + // Returns the memory for a particular constant attribute + float *GetConstantAttributeMemory( int nAttribute ); + + // Swaps two particles in the particle list + void SwapAdjacentParticles( int hParticle ); + + // Unlinks a particle from the list + void UnlinkParticle( int hParticle ); + + // Inserts a particle before another particle in the list + void InsertParticleBefore( int hParticle, int hBefore ); + + // Move a particle from one index to another + void MoveParticle( int nInitialIndex, int nNewIndex ); + + // Computes the sq distance to a particle position + float ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const; + + // Grows the dist sq range for all particles + void GrowDistSqrBounds( float flDistSqr ); + + // Simulates the first frame + void SimulateFirstFrame( ); + + bool SystemContainsParticlesWithBoolSet( bool CParticleCollection::*pField ) const; + // Does the particle collection contain opaque particle systems + bool ContainsOpaqueCollections(); + bool ComputeUsesPowerOfTwoFrameBufferTexture(); + bool ComputeUsesFullFrameBufferTexture(); + bool ComputeIsTranslucent(); + bool ComputeIsTwoPass(); + bool ComputeIsBatchable(); + bool ComputeRequiresOrderInvariance(); + + void LabelTextureUsage( void ); + + void LinkIntoDefList( ); + +public: + fltx4 m_fl4CurTime; // accumulated time + + int m_nPaddedActiveParticles; // # of groups of 4 particles + float m_flCurTime; // accumulated time + + int m_nActiveParticles; // # of active particles + float m_flDt; + float m_flPreviousDt; + float m_flNextSleepTime; // time to go to sleep if not drawn + + CUtlReference< CParticleSystemDefinition > m_pDef; + int m_nAllocatedParticles; + int m_nMaxAllowedParticles; + bool m_bDormant; + bool m_bEmissionStopped; + bool m_bRequiresOrderInvariance; + + int m_LocalLightingCP; + Color m_LocalLighting; + + // control point data. Don't set these directly, or they won't propagate down to children + // particle control points can act as emitter centers, repulsions points, etc. what they are + // used for depends on what operators and parameters your system has. + CParticleControlPoint m_ControlPoints[MAX_PARTICLE_CONTROL_POINTS]; + + CModelHitBoxesInfo m_ControlPointHitBoxes[MAX_PARTICLE_CONTROL_POINTS]; + + // public so people can call methods + uint8 *m_pOperatorContextData; + CParticleCollection *m_pNext; // for linking children together + CParticleCollection *m_pPrev; // for linking children together + + struct CWorldCollideContextData *m_pCollisionCacheData[NUM_COLLISION_CACHE_MODES]; // children can share collision caches w/ parent + CParticleCollection *m_pParent; + + CUtlIntrusiveDList m_Children; // list for all child particle systems + + void *operator new(size_t nSize); + void *operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ); + void operator delete(void *pData); + void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ); + + +protected: + // current bounds for the particle system + bool m_bBoundsValid; + Vector m_MinBounds; + Vector m_MaxBounds; + int m_nHighestCP; //Highest CP set externally. Needs to assert if a system calls to an unassigned CP. + +private: + + + unsigned char *m_pParticleMemory; // fixed size at initialization. Must be aligned for SSE + unsigned char *m_pParticleInitialMemory; // fixed size at initialization. Must be aligned for SSE + unsigned char *m_pConstantMemory; + + int m_nPerParticleInitializedAttributeMask; + int m_nPerParticleUpdatedAttributeMask; + int m_nPerParticleReadInitialAttributeMask; // What fields do operators want to see initial attribute values for? + float *m_pParticleAttributes[MAX_PARTICLE_ATTRIBUTES]; + float *m_pParticleInitialAttributes[MAX_PARTICLE_ATTRIBUTES]; + size_t m_nParticleFloatStrides[MAX_PARTICLE_ATTRIBUTES]; + size_t m_nParticleInitialFloatStrides[MAX_PARTICLE_ATTRIBUTES]; + + float *m_pConstantAttributes; + + uint64 m_nControlPointReadMask; // Mask indicating which control points have been accessed + int m_nParticleFlags; // PCFLAGS_xxx + bool m_bIsScrubbable : 1; + bool m_bIsRunningInitializers : 1; + bool m_bIsRunningOperators : 1; + bool m_bIsTranslucent : 1; + bool m_bIsTwoPass : 1; + bool m_bAnyUsesPowerOfTwoFrameBufferTexture : 1; // whether or not we or any children use this + bool m_bAnyUsesFullFrameBufferTexture : 1; + bool m_bIsBatchable : 1; + + bool m_bUsesPowerOfTwoFrameBufferTexture; // whether or not we use this, _not_ our children + bool m_bUsesFullFrameBufferTexture; + + // How many frames have we drawn? + int m_nDrawnFrames; + int m_nSimulatedFrames; + + Vector m_Center; // average of particle centers + + // Used to assign unique ids to each particle + int m_nUniqueParticleId; + + // Used to generate random numbers + int m_nRandomQueryCount; + int m_nRandomSeed; + int m_nOperatorRandomSampleOffset; + + float m_flMinDistSqr; + float m_flMaxDistSqr; + float m_flOOMaxDistSqr; + Vector m_vecLastCameraPos; + float m_flLastMinDistSqr; + float m_flLastMaxDistSqr; + + // Particle collection kill list. set up by particle system mgr + int m_nNumParticlesToKill; + int *m_pParticleKillList; + + // Used to build a list of all particle collections that have the same particle def + CParticleCollection *m_pNextDef; + CParticleCollection *m_pPrevDef; + + void LoanKillListTo( CParticleCollection *pBorrower ) const; + bool HasAttachedKillList( void ) const; + + + // For debugging + CParticleOperatorInstance *m_pRenderOp; + friend class CParticleSystemMgr; + friend class CParticleOperatorInstance; +}; + + + +class CM128InitialAttributeIterator : public CStridedConstPtr +{ +public: + FORCEINLINE CM128InitialAttributeIterator( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->GetInitialM128AttributePtr( nAttribute, &m_nStride ); + } +}; + + +class CM128AttributeIterator : public CStridedConstPtr +{ +public: + FORCEINLINE CM128AttributeIterator( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->GetM128AttributePtr( nAttribute, &m_nStride ); + } +}; + +class C4IAttributeIterator : public CStridedConstPtr +{ +public: + FORCEINLINE C4IAttributeIterator( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->Get4IAttributePtr( nAttribute, &m_nStride ); + } +}; + +class CM128AttributeWriteIterator : public CStridedPtr +{ +public: + FORCEINLINE CM128AttributeWriteIterator( void ) + { + } + FORCEINLINE void Init ( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->GetM128AttributePtrForWrite( nAttribute, &m_nStride ); + } + FORCEINLINE CM128AttributeWriteIterator( int nAttribute, CParticleCollection *pParticles ) + { + Init( nAttribute, pParticles ); + } +}; + +class C4VAttributeIterator : public CStridedConstPtr +{ +public: + FORCEINLINE C4VAttributeIterator( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->Get4VAttributePtr( nAttribute, &m_nStride ); + } +}; + +class C4VInitialAttributeIterator : public CStridedConstPtr +{ +public: + FORCEINLINE C4VInitialAttributeIterator( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->GetInitial4VAttributePtr( nAttribute, &m_nStride ); + } +}; + +class C4VAttributeWriteIterator : public CStridedPtr +{ +public: + FORCEINLINE C4VAttributeWriteIterator( int nAttribute, CParticleCollection *pParticles ) + { + m_pData = pParticles->Get4VAttributePtrForWrite( nAttribute, &m_nStride ); + } +}; + + +//----------------------------------------------------------------------------- +// Inline methods of CParticleCollection +//----------------------------------------------------------------------------- + +inline bool CParticleCollection::HasAttachedKillList( void ) const +{ + return m_pParticleKillList != NULL; +} + +inline bool CParticleCollection::ReadsControlPoint( int nPoint ) const +{ + return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0; +} + +inline void CParticleCollection::SetNActiveParticles( int nCount ) +{ + Assert( nCount <= m_nMaxAllowedParticles ); + m_nActiveParticles = nCount; + m_nPaddedActiveParticles = ( nCount+3 )/4; +} + +inline void CParticleCollection::SwapPosAndPrevPos( void ) +{ + // strides better be the same! + Assert( m_nParticleFloatStrides[PARTICLE_ATTRIBUTE_XYZ] == m_nParticleFloatStrides[ PARTICLE_ATTRIBUTE_PREV_XYZ ] ); + V_swap( m_pParticleAttributes[ PARTICLE_ATTRIBUTE_XYZ ], m_pParticleAttributes[ PARTICLE_ATTRIBUTE_PREV_XYZ ] ); +} + +inline void CParticleCollection::LoanKillListTo( CParticleCollection *pBorrower ) const +{ + Assert(! pBorrower->m_pParticleKillList ); + pBorrower->m_nNumParticlesToKill = 0; + pBorrower->m_pParticleKillList = m_pParticleKillList; +} + +inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValue ) +{ + float *fconst = m_pConstantAttributes + 4*3*nAttribute; + fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValue; +} + +inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ ) +{ + float *fconst = m_pConstantAttributes + 4*3*nAttribute; + fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValueX; + fconst[4] = fconst[5] = fconst[6] = fconst[7] = fValueY; + fconst[8] = fconst[9] = fconst[10] = fconst[11] = fValueZ; +} + +inline void CParticleCollection::SetControlPoint( int nWhichPoint, const Vector &v ) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + m_nHighestCP = MAX( m_nHighestCP, nWhichPoint ); + m_ControlPoints[ nWhichPoint ].m_Position = v; + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPoint( nWhichPoint, v ); + } +} + +inline void CParticleCollection::SetControlPointObject( int nWhichPoint, void *pObject ) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + m_ControlPoints[ nWhichPoint ].m_pObject = pObject; + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPointObject( nWhichPoint, pObject ); + } +} + +inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Vector &forward, + const Vector &right, const Vector &up ) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + + // check perpendicular + if ( fabs( DotProduct( forward, up ) ) <= 0.1f + && fabs( DotProduct( forward, right ) ) <= 0.1f + && fabs( DotProduct( right, up ) ) <= 0.1f ) + { + m_ControlPoints[ nWhichPoint ].m_ForwardVector = forward; + m_ControlPoints[ nWhichPoint ].m_UpVector = up; + m_ControlPoints[ nWhichPoint ].m_RightVector = right; + + // make sure all children are finished + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPointOrientation( nWhichPoint, forward, right, up ); + } + } + else + { + Warning( "Attempt to set particle collection %s to invalid orientation matrix\n", GetName() ); + } +} + +inline Vector CParticleCollection::TransformAxis( const Vector &SrcAxis, bool bLocalSpace, + int nControlPointNumber) +{ + if ( bLocalSpace ) + { + return // mxmul + ( SrcAxis.x*m_ControlPoints[nControlPointNumber].m_RightVector )+ + ( SrcAxis.y*m_ControlPoints[nControlPointNumber].m_ForwardVector )+ + ( SrcAxis.z*m_ControlPoints[nControlPointNumber].m_UpVector ); + } + else + return SrcAxis; +} + + +inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Quaternion &q ) +{ + matrix3x4_t mat; + Vector vecForward, vecUp, vecRight; + QuaternionMatrix( q, mat ); + MatrixVectors( mat, &vecForward, &vecRight, &vecUp ); + SetControlPointOrientation( nWhichPoint, vecForward, vecRight, vecUp ); +} + +inline void CParticleCollection::SetControlPointForwardVector( int nWhichPoint, const Vector &v) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + m_ControlPoints[ nWhichPoint ].m_ForwardVector = v; + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPointForwardVector( nWhichPoint, v ); + } +} + +inline void CParticleCollection::SetControlPointUpVector( int nWhichPoint, const Vector &v) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + m_ControlPoints[ nWhichPoint ].m_UpVector = v; + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPointUpVector( nWhichPoint, v ); + } +} + +inline void CParticleCollection::SetControlPointRightVector( int nWhichPoint, const Vector &v) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + m_ControlPoints[ nWhichPoint ].m_RightVector = v; + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPointRightVector( nWhichPoint, v ); + } +} + +inline void CParticleCollection::SetControlPointParent( int nWhichPoint, int n ) +{ + Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) ); + m_ControlPoints[ nWhichPoint ].m_nParent = n; + for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext ) + { + i->SetControlPointParent( nWhichPoint, n ); + } +} + + +// Returns the memory for a particular constant attribute +inline float *CParticleCollection::GetConstantAttributeMemory( int nAttribute ) +{ + return m_pConstantAttributes + 3 * 4 * nAttribute; +} + +// Random number offset (for use in getting Random #s in operators) +inline int CParticleCollection::OperatorRandomSampleOffset() const +{ + return m_nOperatorRandomSampleOffset; +} + +// Used by particle systems to generate random numbers +inline int CParticleCollection::RandomInt( int nRandomSampleId, int nMin, int nMax ) +{ + // do not call + float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ]; + flRand *= ( nMax + 1 - nMin ); + int nRand = (int)flRand + nMin; + return nRand; +} + +inline float CParticleCollection::RandomFloat( int nRandomSampleId, float flMin, float flMax ) +{ + // do not call + float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ]; + flRand *= ( flMax - flMin ); + flRand += flMin; + return flRand; +} + +inline fltx4 CParticleCollection::RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset ) +{ + fltx4 Retval; + int nOfs=m_nRandomSeed+nRandomSampleOffset; + SubFloat( Retval, 0 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[0] ) & RANDOM_FLOAT_MASK ]; + SubFloat( Retval, 1 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[1] ) & RANDOM_FLOAT_MASK ]; + SubFloat( Retval, 2 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[2] ) & RANDOM_FLOAT_MASK ]; + SubFloat( Retval, 3 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[3] ) & RANDOM_FLOAT_MASK ]; + return Retval; +} + + +inline float CParticleCollection::RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent ) +{ + // do not call + float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ]; + flRand = powf( flRand, flExponent ); + flRand *= ( flMax - flMin ); + flRand += flMin; + return flRand; +} + +inline void CParticleCollection::RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector ) +{ + // do not call + float flDelta = flMax - flMin; + int nBaseId = m_nRandomSeed + nRandomSampleId; + + pVector->x = s_pRandomFloats[ nBaseId & RANDOM_FLOAT_MASK ]; + pVector->x *= flDelta; + pVector->x += flMin; + + pVector->y = s_pRandomFloats[ ( nBaseId + 1 ) & RANDOM_FLOAT_MASK ]; + pVector->y *= flDelta; + pVector->y += flMin; + + pVector->z = s_pRandomFloats[ ( nBaseId + 2 ) & RANDOM_FLOAT_MASK ]; + pVector->z *= flDelta; + pVector->z += flMin; +} + +inline void CParticleCollection::RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector ) +{ + // do not call + int nBaseId = m_nRandomSeed + nRandomSampleId; + pVector->x = RandomFloat( nBaseId, vecMin.x, vecMax.x ); + pVector->y = RandomFloat( nBaseId + 1, vecMin.y, vecMax.y ); + pVector->z = RandomFloat( nBaseId + 2, vecMin.z, vecMax.z ); +} + +// Used by particle systems to generate random numbers +inline int CParticleCollection::RandomInt( int nMin, int nMax ) +{ + // do not call + return RandomInt( m_nRandomQueryCount++, nMin, nMax ); +} + +inline float CParticleCollection::RandomFloat( float flMin, float flMax ) +{ + // do not call + return RandomFloat( m_nRandomQueryCount++, flMin, flMax ); +} + +inline float CParticleCollection::RandomFloatExp( float flMin, float flMax, float flExponent ) +{ + // do not call + return RandomFloatExp( m_nRandomQueryCount++, flMin, flMax, flExponent ); +} + +inline void CParticleCollection::RandomVector( float flMin, float flMax, Vector *pVector ) +{ + // do not call + RandomVector( m_nRandomQueryCount++, flMin, flMax, pVector ); +} + +inline void CParticleCollection::RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector ) +{ + // do not call + RandomVector( m_nRandomQueryCount++, vecMin, vecMax, pVector ); +} + +inline float CParticleCollection::RandomVectorInUnitSphere( Vector *pVector ) +{ + // do not call + return RandomVectorInUnitSphere( m_nRandomQueryCount++, pVector ); +} + + +// get the pointer to an attribute for a given particle. !!speed!! if you find yourself +// calling this anywhere that matters, you're not handling the simd-ness of the particle system +// well and will have bad perf. +inline const float *CParticleCollection::GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const +{ + Assert( nParticleNumber < m_nAllocatedParticles ); + int block_ofs = nParticleNumber/4; + return m_pParticleAttributes[ nAttribute ] + + m_nParticleFloatStrides[ nAttribute ] * block_ofs + + ( nParticleNumber & 3 ); +} + +inline int *CParticleCollection::GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber ) +{ + return reinterpret_cast< int* >( GetFloatAttributePtrForWrite( nAttribute, nParticleNumber ) ); +} + +inline const int *CParticleCollection::GetIntAttributePtr( int nAttribute, int nParticleNumber ) const +{ + return (int*)GetFloatAttributePtr( nAttribute, nParticleNumber ); +} + +inline const fltx4 *CParticleCollection::GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const +{ + *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4; + return reinterpret_cast( m_pParticleAttributes[ nAttribute ] ); +} + +inline const FourInts *CParticleCollection::Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const +{ + *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4; + return reinterpret_cast( m_pParticleAttributes[ nAttribute ] ); +} + +inline const int32 *CParticleCollection::GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const +{ + *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]; + return reinterpret_cast( m_pParticleAttributes[ nAttribute ] ); +} + +inline const FourVectors *CParticleCollection::Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const +{ + *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/12; + return reinterpret_cast( m_pParticleAttributes[ nAttribute ] ); +} + +inline FourVectors *CParticleCollection::Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut ) +{ + *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/12; + return reinterpret_cast( m_pParticleAttributes[ nAttribute ] ); +} + +inline const FourVectors *CParticleCollection::GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const +{ + *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ]/12; + return reinterpret_cast( m_pParticleInitialAttributes[ nAttribute ] ); +} + +inline float *CParticleCollection::GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber ) +{ + // NOTE: If you hit this assertion, it means your particle operator isn't returning + // the appropriate fields in the RequiredAttributesMask call + Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) ); + Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) ); + + Assert( m_nParticleFloatStrides[nAttribute] != 0 ); + + Assert( nParticleNumber < m_nAllocatedParticles ); + int block_ofs = nParticleNumber/4; + return m_pParticleAttributes[ nAttribute ] + + m_nParticleFloatStrides[ nAttribute ] * block_ofs + + ( nParticleNumber & 3 ); +} + +inline fltx4 *CParticleCollection::GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut ) +{ + // NOTE: If you hit this assertion, it means your particle operator isn't returning + // the appropriate fields in the RequiredAttributesMask call + if ( !HushAsserts() ) + { + Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) ); + Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) ); + Assert( m_nParticleFloatStrides[nAttribute] != 0 ); + } + + *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4; + return reinterpret_cast( m_pParticleAttributes[ nAttribute ] ); +} + +inline const float *CParticleCollection::GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const +{ + Assert( nParticleNumber < m_nAllocatedParticles ); + int block_ofs = nParticleNumber / 4; + return m_pParticleInitialAttributes[ nAttribute ] + m_nParticleInitialFloatStrides[ nAttribute ] * block_ofs + ( nParticleNumber & 3 ); +} + +inline const fltx4 *CParticleCollection::GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const +{ + *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ]/4; + return reinterpret_cast( m_pParticleInitialAttributes[ nAttribute ] ); +} + +inline float *CParticleCollection::GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber ) +{ + Assert( nParticleNumber < m_nAllocatedParticles ); + Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) ); + int block_ofs = nParticleNumber / 4; + return m_pParticleInitialAttributes[ nAttribute ] + m_nParticleInitialFloatStrides[ nAttribute ] * block_ofs + ( nParticleNumber & 3 ); +} + +inline fltx4 *CParticleCollection::GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut ) +{ + Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) ); + *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ] / 4; + return reinterpret_cast( m_pParticleInitialAttributes[ nAttribute ] ); +} + +// Used to make sure we're accessing valid memory +inline bool CParticleCollection::IsValidAttributePtr( int nAttribute, const void *pPtr ) const +{ + if ( pPtr < m_pParticleAttributes[nAttribute] ) + return false; + + size_t nArraySize = m_nParticleFloatStrides[nAttribute] * m_nAllocatedParticles / 4; + void *pMaxPtr = m_pParticleAttributes[nAttribute] + nArraySize; + return ( pPtr <= pMaxPtr ); +} + + +FORCEINLINE void CParticleCollection::KillParticle( int nPidx ) +{ + // add a particle to the sorted kill list. entries must be added in sorted order. + // within a particle operator, this is safe to call. Outside of one, you have to call + // the ApplyKillList() method yourself. The storage for the kill list is global between + // all particle systems, so you can't kill a particle in 2 different CParticleCollections + // w/o calling ApplyKillList + + // That said, we only expect the particle index to be at most more than 3 larger than the + // particle count + Assert( nPidx < m_nActiveParticles + 4 ); + + // note that it is permissible to kill particles with indices>the number of active + // particles, in order to faciliate easy sse coding + Assert( m_nNumParticlesToKill < MAX_PARTICLES_IN_A_SYSTEM ); + m_pParticleKillList[ m_nNumParticlesToKill++ ] = nPidx; +} + +// initialize this attribute for all active particles +inline void CParticleCollection::FillAttributeWithConstant( int nAttribute, float fValue ) +{ + size_t stride; + fltx4 *pAttr = GetM128AttributePtrForWrite( nAttribute, &stride ); + fltx4 fill=ReplicateX4( fValue ); + for( int i = 0; i < m_nPaddedActiveParticles; i++ ) + { + *(pAttr) = fill; + pAttr += stride; + } +} + + +//----------------------------------------------------------------------------- +// Helper to set vector attribute values +//----------------------------------------------------------------------------- +FORCEINLINE void SetVectorAttribute( float *pAttribute, float x, float y, float z ) +{ + pAttribute[0] = x; + pAttribute[4] = y; + pAttribute[8] = z; +} + +FORCEINLINE void SetVectorAttribute( float *pAttribute, const Vector &v ) +{ + pAttribute[0] = v.x; + pAttribute[4] = v.y; + pAttribute[8] = v.z; +} + +FORCEINLINE void SetVectorFromAttribute( Vector &v, const float *pAttribute ) +{ + v.x = pAttribute[0]; + v.y = pAttribute[4]; + v.z = pAttribute[8]; +} + + +//----------------------------------------------------------------------------- +// Computes the sq distance to a particle position +//----------------------------------------------------------------------------- +FORCEINLINE float CParticleCollection::ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const +{ + const float *xyz = GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, hParticle ); + Vector vecParticlePosition( xyz[0], xyz[4], xyz[8] ); + return vecParticlePosition.DistToSqr( vecPosition ); +} + + +//----------------------------------------------------------------------------- +// Grows the dist sq range for all particles +//----------------------------------------------------------------------------- +FORCEINLINE void CParticleCollection::GrowDistSqrBounds( float flDistSqr ) +{ + if ( m_flLastMinDistSqr > flDistSqr ) + { + m_flLastMinDistSqr = flDistSqr; + } + else if ( m_flLastMaxDistSqr < flDistSqr ) + { + m_flLastMaxDistSqr = flDistSqr; + } +} + + + + +//----------------------------------------------------------------------------- +// Data associated with children particle systems +//----------------------------------------------------------------------------- +struct ParticleChildrenInfo_t +{ + DmObjectId_t m_Id; + CUtlString m_Name; + bool m_bUseNameBasedLookup; + float m_flDelay; // How much to delay this system after the parent starts +}; + + +//----------------------------------------------------------------------------- +// A template describing how a particle system will function +//----------------------------------------------------------------------------- +class CParticleSystemDefinition +{ + DECLARE_DMXELEMENT_UNPACK(); + DECLARE_REFERENCED_CLASS( CParticleSystemDefinition ); + + +public: + CParticleSystemDefinition( void ); + ~CParticleSystemDefinition( void ); + + // Serialization, unserialization + void Read( CDmxElement *pElement ); + CDmxElement *Write(); + + const char *MaterialName() const; + IMaterial *GetMaterial() const; + const char *GetName() const; + const DmObjectId_t& GetId() const; + + // Does the particle system use the power of two frame buffer texture (refraction?) + bool UsesPowerOfTwoFrameBufferTexture(); + + // Does the particle system use the full frame buffer texture (soft particles) + bool UsesFullFrameBufferTexture(); + + // Should we always precache this? + bool ShouldAlwaysPrecache() const; + + // Should we batch particle collections using this definition up? + bool ShouldBatch() const; + + // Is the particle system rendered on the viewmodel? + bool IsViewModelEffect() const; + + // Used to iterate over all particle collections using the same def + CParticleCollection *FirstCollection(); + + // What's the effective cull size + fill cost? + // Used for early retirement + float GetCullRadius() const; + float GetCullFillCost() const; + int GetCullControlPoint() const; + const char *GetCullReplacementDefinition() const; + + // Retirement + bool HasRetirementBeenChecked( int nFrame ) const; + void MarkRetirementCheck( int nFrame ); + + // Control point read + void MarkReadsControlPoint( int nPoint ); + bool ReadsControlPoint( int nPoint ) const; + +private: + void Precache(); + void Uncache(); + bool IsPrecached() const; + + void UnlinkAllCollections(); + + void SetupContextData( ); + void ParseChildren( CDmxElement *pElement ); + void ParseOperators( const char *pszName, ParticleFunctionType_t nFunctionType, + CDmxElement *pElement, CUtlVector &out_list ); + void WriteChildren( CDmxElement *pElement ); + void WriteOperators( CDmxElement *pElement, const char *pOpKeyName, + const CUtlVector &inList ); + CUtlVector *GetOperatorList( ParticleFunctionType_t type ); + CParticleOperatorInstance *FindOperatorById( ParticleFunctionType_t type, const DmObjectId_t &id ); + +private: + int m_nInitialParticles; + int m_nPerParticleUpdatedAttributeMask; + int m_nPerParticleInitializedAttributeMask; + int m_nInitialAttributeReadMask; + int m_nAttributeReadMask; + uint64 m_nControlPointReadMask; + Vector m_BoundingBoxMin; + Vector m_BoundingBoxMax; + char m_pszMaterialName[MAX_PATH]; + CMaterialReference m_Material; + CParticleCollection *m_pFirstCollection; + char m_pszCullReplacementName[128]; + float m_flCullRadius; + float m_flCullFillCost; + int m_nCullControlPoint; + int m_nRetireCheckFrame; + + // Default attribute values + Color m_ConstantColor; + float m_flConstantRadius; + float m_flConstantRotation; + float m_flConstantRotationSpeed; + int m_nConstantSequenceNumber; + int m_nConstantSequenceNumber1; + int m_nGroupID; + float m_flMaximumTimeStep; + float m_flMaximumSimTime; // maximum time to sim before drawing first frame. + float m_flMinimumSimTime; // minimum time to sim before drawing first frame - prevents all + // capped particles from drawing at 0 time. + + int m_nMinimumFrames; // number of frames to apply max/min simulation times + + + // Is the particle system rendered on the viewmodel? + bool m_bViewModelEffect; + + + size_t m_nContextDataSize; + DmObjectId_t m_Id; + +public: + float m_flMaxDrawDistance; // distance at which to not draw. + float m_flNoDrawTimeToGoToSleep; // after not beeing seen for this long, the system will sleep + + int m_nMaxParticles; + int m_nSkipRenderControlPoint; // if the camera is attached to the + // object associated with this control + // point, don't render the system + + CUtlString m_Name; + + CUtlVector m_Operators; + CUtlVector m_Renderers; + CUtlVector m_Initializers; + CUtlVector m_Emitters; + CUtlVector m_ForceGenerators; + CUtlVector m_Constraints; + CUtlVector m_Children; + + CUtlVector m_nOperatorsCtxOffsets; + CUtlVector m_nRenderersCtxOffsets; + CUtlVector m_nInitializersCtxOffsets; + CUtlVector m_nEmittersCtxOffsets; + CUtlVector m_nForceGeneratorsCtxOffsets; + CUtlVector m_nConstraintsCtxOffsets; + + // profiling information + float m_flTotalSimTime; + float m_flUncomittedTotalSimTime; + float m_flMaxMeasuredSimTime; + int m_nMaximumActiveParticles; + bool m_bShouldSort; + bool m_bShouldBatch; + bool m_bIsPrecached : 1; + bool m_bAlwaysPrecache : 1; + + friend class CParticleCollection; + friend class CParticleSystemMgr; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline CParticleSystemDefinition::CParticleSystemDefinition( void ) +{ + m_nControlPointReadMask = 0; + m_nInitialAttributeReadMask = 0; + m_nPerParticleInitializedAttributeMask = 0; + m_nPerParticleUpdatedAttributeMask = 0; + m_nAttributeReadMask = 0; + m_flTotalSimTime = 0.0; + m_flMaxMeasuredSimTime = 0.0; + m_nMaximumActiveParticles = 0; + m_bIsPrecached = false; + m_bAlwaysPrecache = false; + m_bShouldBatch = false; + m_bShouldSort = true; + m_pFirstCollection = NULL; + m_flCullRadius = 0.0f; + m_flCullFillCost = 1.0f; + m_nRetireCheckFrame = 0; +} + +inline CParticleSystemDefinition::~CParticleSystemDefinition( void ) +{ + UnlinkAllCollections(); + m_Operators.PurgeAndDeleteElements(); + m_Renderers.PurgeAndDeleteElements(); + m_Initializers.PurgeAndDeleteElements(); + m_Emitters.PurgeAndDeleteElements(); + m_ForceGenerators.PurgeAndDeleteElements(); + m_Constraints.PurgeAndDeleteElements(); +} + +// Used to iterate over all particle collections using the same def +inline CParticleCollection *CParticleSystemDefinition::FirstCollection() +{ + return m_pFirstCollection; +} + +inline float CParticleSystemDefinition::GetCullRadius() const +{ + return m_flCullRadius; +} + +inline float CParticleSystemDefinition::GetCullFillCost() const +{ + return m_flCullFillCost; +} + +inline const char *CParticleSystemDefinition::GetCullReplacementDefinition() const +{ + return m_pszCullReplacementName; +} + +inline int CParticleSystemDefinition::GetCullControlPoint() const +{ + return m_nCullControlPoint; +} + +inline void CParticleSystemDefinition::MarkReadsControlPoint( int nPoint ) +{ + m_nControlPointReadMask |= ( 1ULL << nPoint ); +} + +inline bool CParticleSystemDefinition::ReadsControlPoint( int nPoint ) const +{ + return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0; +} + +// Retirement +inline bool CParticleSystemDefinition::HasRetirementBeenChecked( int nFrame ) const +{ + return m_nRetireCheckFrame == nFrame; +} + +inline void CParticleSystemDefinition::MarkRetirementCheck( int nFrame ) +{ + m_nRetireCheckFrame = nFrame; +} + +inline bool CParticleSystemDefinition::ShouldBatch() const +{ + return m_bShouldBatch; +} + +inline bool CParticleSystemDefinition::IsViewModelEffect() const +{ + return m_bViewModelEffect; +} + +inline const char *CParticleSystemDefinition::MaterialName() const +{ + return m_pszMaterialName; +} + +inline const DmObjectId_t& CParticleSystemDefinition::GetId() const +{ + return m_Id; +} + +inline int CParticleCollection::GetGroupID( void ) const +{ + return m_pDef->m_nGroupID; +} + +FORCEINLINE const Vector& CParticleCollection::GetControlPointAtCurrentTime( int nControlPoint ) const +{ + Assert( nControlPoint <= GetHighestControlPoint() ); + Assert( m_pDef->ReadsControlPoint( nControlPoint ) ); + return m_ControlPoints[nControlPoint].m_Position; +} + +FORCEINLINE void CParticleCollection::GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const +{ + Assert( nControlPoint <= GetHighestControlPoint() ); + Assert( m_pDef->ReadsControlPoint( nControlPoint ) ); + + // FIXME: Use quaternion lerp to get control point transform at time + *pForward = m_ControlPoints[nControlPoint].m_ForwardVector; + *pRight = m_ControlPoints[nControlPoint].m_RightVector; + *pUp = m_ControlPoints[nControlPoint].m_UpVector; +} + +FORCEINLINE int CParticleCollection::GetControlPointParent( int nControlPoint ) const +{ + Assert( nControlPoint <= GetHighestControlPoint() ); + Assert( m_pDef->ReadsControlPoint( nControlPoint ) ); + return m_ControlPoints[nControlPoint].m_nParent; +} + +FORCEINLINE bool CParticleCollection::IsValid( void ) const +{ + return ( m_pDef != NULL && m_pDef->GetMaterial() ); +} + + +#endif // PARTICLES_H diff --git a/public/phonemeconverter.cpp b/public/phonemeconverter.cpp new file mode 100644 index 0000000..2253155 --- /dev/null +++ b/public/phonemeconverter.cpp @@ -0,0 +1,202 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include +#include +#include "tier0/dbg.h" + +struct PhonemeMap_t +{ + const char *string; + int code; + float weight; + bool isStandard; + const char *desc; +}; + +static PhonemeMap_t g_Phonemes[] = +{ + { "b", 'b', 0.8f, true, "Big : voiced alveolar stop" }, + { "m", 'm', 1.0f, true, "Mat : voiced bilabial nasal" }, + { "p", 'p', 0.8f, true, "Put; voiceless alveolar stop" }, + { "w", 'w', 1.0f, true, "With : voiced labial-velar approximant" }, + { "f", 'f', 0.8f, true, "Fork : voiceless labiodental fricative" }, + { "v", 'v', 0.8f, true, "Val : voiced labialdental fricative" }, + { "r", 0x0279, 1.0f, true, "Red : voiced alveolar approximant" }, + { "r2", 'r', 1.0f, true, "Red : voiced alveolar trill" }, + { "r3", 0x027b, 1.0f, true, "Red : voiced retroflex approximant" }, + { "er", 0x025a, 1.2f, true, "URn : rhotacized schwa" }, + { "er2", 0x025d, 1.2f, true, "URn : rhotacized lower-mid central vowel" }, + { "dh", 0x00f0, 1.0f, true, "THen : voiced dental fricative" }, + { "th", 0x03b8, 1.0f, true, "THin : voiceless dental fricative" }, + { "sh", 0x0283, 1.0f, true, "SHe : voiceless postalveolar fricative" }, + { "jh", 0x02a4, 1.0f, true, "Joy : voiced postalveolar afficate" }, + { "ch", 0x02a7, 1.0f, true, "CHin : voiceless postalveolar affricate" }, + { "s", 's', 0.8f, true, "Sit : voiceless alveolar fricative" }, + { "z", 'z', 0.8f, true, "Zap : voiced alveolar fricative" }, + { "d", 'd', 0.8f, true, "Dig : voiced bilabial stop" }, + { "d2", 0x027e, 0.8f, true, "Dig : voiced alveolar flap or tap" }, + { "l", 'l', 0.8f, true, "Lid : voiced alveolar lateral approximant" }, + { "l2", 0x026b, 0.8f, true, "Lid : velarized voiced alveolar lateral approximant" }, + { "n", 'n', 0.8f, true, "No : voiced alveolar nasal" }, + { "t", 't', 0.8f, true, "Talk : voiceless bilabial stop" }, + { "ow", 'o', 1.2f, true, "gO : upper-mid back rounded vowel" }, + { "uw", 'u', 1.2f, true, "tOO : high back rounded vowel" }, + { "ey", 'e', 1.0f, true, "Ate : upper-mid front unrounded vowel" }, + { "ae", 0x00e6, 1.0f, true, "cAt : semi-low front unrounded vowel" }, + { "aa", 0x0251, 1.0f, true, "fAther : low back unrounded vowel" }, + { "aa2", 'a', 1.0f, true, "fAther : low front unrounded vowel" }, + { "iy", 'i', 1.0f, true, "fEEl : high front unrounded vowel" }, + { "y", 'j', 0.7f, true, "Yacht : voiced palatal approximant" }, + { "ah", 0x028c, 1.0f, true, "cUt : lower-mid back unrounded vowel" }, + { "ao", 0x0254, 1.2f, true, "dOg : lower-mid back rounded vowel" }, + { "ax", 0x0259, 1.0f, true, "Ago : mid-central unrounded vowel" }, + { "ax2", 0x025c, 1.0f, true, "Ago : lower-mid central unrounded vowel" }, + { "eh", 0x025b, 1.0f, true, "pEt : lower-mid front unrounded vowel"}, + { "ih", 0x026a, 1.0f, true, "fIll : semi-high front unrounded vowel" }, + { "ih2", 0x0268, 1.0f, true, "fIll : high central unrounded vowel" }, + { "uh", 0x028a, 1.0f, true, "bOOk : semi-high back rounded vowel" }, + { "g", 'g', 0.8f, true, "taG : voiced velar stop" }, + { "g2", 0x0261, 1.0f, true, "taG : voiced velar stop" }, + { "hh", 'h', 0.8f, true, "Help : voiceless glottal fricative" }, + { "hh2", 0x0266, 0.8f, true, "Help : breathy-voiced glottal fricative" }, + { "c", 'k', 0.6f, true, "Cut : voiceless velar stop" }, + { "nx", 0x014b, 1.0f, true, "siNG : voiced velar nasal" }, + { "zh", 0x0292, 1.0f, true, "aZure : voiced postalveolar fricative" }, + + // Added + { "h", 'h', 0.8f, false, "Help : voiceless glottal fricative" }, + { "k", 'k', 0.6f, false, "Cut : voiceless velar stop" }, + { "ay", 0x0251, 1.0f, false, "fAther : low back unrounded vowel" }, // or possibly +0x026a (ih) + { "ng", 0x014b, 1.0f, false, "siNG : voiced velar nasal" }, // nx + { "aw", 0x0251, 1.2f, false, "fAther : low back unrounded vowel" }, // // vOWel, // aa + uh??? + { "oy", 'u', 1.2f, false, "tOO : high back rounded vowel" }, + + // Silence + { "", '_', 1.0f, true, "silence" }, +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : code - +// Output : const char +//----------------------------------------------------------------------------- +const char *ConvertPhoneme( int code ) +{ + for ( int i = 0; i < ARRAYSIZE( g_Phonemes ); ++i ) + { + PhonemeMap_t *test = &g_Phonemes[ i ]; + if ( test->code == code ) + return test->string; + } + + Warning( "Unrecognized phoneme code %i\n", code ); + return ""; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +// Output : int +//----------------------------------------------------------------------------- +int TextToPhoneme( const char *text ) +{ + for ( int i = 0; i < ARRAYSIZE( g_Phonemes ); ++i ) + { + PhonemeMap_t *test = &g_Phonemes[ i ]; + if ( !stricmp( test->string, text ) ) + return test->code; + } + + Warning( "Unrecognized phoneme %s\n", text ); + return '_'; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : code - +// Output : float +//----------------------------------------------------------------------------- +float WeightForPhonemeCode( int code ) +{ + for ( int i = 0; i < ARRAYSIZE( g_Phonemes ); ++i ) + { + PhonemeMap_t *test = &g_Phonemes[ i ]; + if ( test->code == code ) + return test->weight; + } + + Warning( "Unrecognized phoneme code %i\n", code ); + return 1.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +// Output : float +//----------------------------------------------------------------------------- +float WeightForPhoneme( char *text ) +{ + for ( int i = 0; i < ARRAYSIZE( g_Phonemes ); ++i ) + { + PhonemeMap_t *test = &g_Phonemes[ i ]; + if ( !stricmp( test->string, text ) ) + return test->weight; + } + + Warning( "WeightForPhoneme:: Unrecognized phoneme %s\n", text ); + return 1.0f; +} + +int NumPhonemes() +{ + return ARRAYSIZE( g_Phonemes ); +} + +const char *NameForPhonemeByIndex( int index ) +{ + Assert( index >= 0 && index < NumPhonemes() ); + return g_Phonemes[ index ].string; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +// Output : int +//----------------------------------------------------------------------------- +int TextToPhonemeIndex( const char *text ) +{ + for ( int i = 0; i < ARRAYSIZE( g_Phonemes ); ++i ) + { + PhonemeMap_t *test = &g_Phonemes[ i ]; + if ( !stricmp( test->string, text ) ) + return i; + } + + return -1; +} + +int CodeForPhonemeByIndex( int index ) +{ + if ( index < 0 || index >= NumPhonemes() ) + return '_'; + return g_Phonemes[ index ].code; +} + +bool IsStandardPhoneme( int index ) +{ + if ( index < 0 || index >= NumPhonemes() ) + return false; + return g_Phonemes[ index ].isStandard; +} + +const char *DescForPhonemeByIndex( int index ) +{ + if ( index < 0 || index >= NumPhonemes() ) + return NULL; + return g_Phonemes[ index ].desc; +} \ No newline at end of file diff --git a/public/phonemeconverter.h b/public/phonemeconverter.h new file mode 100644 index 0000000..5b71082 --- /dev/null +++ b/public/phonemeconverter.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PHONEMECONVERTER_H +#define PHONEMECONVERTER_H +#ifdef _WIN32 +#pragma once +#endif + +const char *ConvertPhoneme( int code ); +int TextToPhoneme( const char *text ); +float WeightForPhonemeCode( int code ); +float WeightForPhoneme( char *text ); + +int NumPhonemes(); +int TextToPhonemeIndex( const char *text ); +const char *NameForPhonemeByIndex( int index ); +int CodeForPhonemeByIndex( int index ); +const char *DescForPhonemeByIndex( int index ); +bool IsStandardPhoneme( int index ); + +#endif // PHONEMECONVERTER_H diff --git a/public/phonemeextractor/phonemeextractor.h b/public/phonemeextractor/phonemeextractor.h new file mode 100644 index 0000000..a82476a --- /dev/null +++ b/public/phonemeextractor/phonemeextractor.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHONEMEEXTRACTOR_H +#define PHONEMEEXTRACTOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +class CSentence; + +typedef enum +{ + SPEECH_API_SAPI = 0, + SPEECH_API_LIPSINC, +} PE_APITYPE; + +typedef enum +{ + SR_RESULT_NORESULT = 0, + SR_RESULT_ERROR, + SR_RESULT_SUCCESS, + SR_RESULT_FAILED +} SR_RESULT; + +abstract_class IPhonemeExtractor +{ +public: + virtual PE_APITYPE GetAPIType() const = 0; + + // Used for menus, etc + virtual char const *GetName() const = 0; + + virtual SR_RESULT Extract( + const char *wavfile, + int numsamples, + void (*pfnPrint)( PRINTF_FORMAT_STRING const char *fmt, ... ), + CSentence& inwords, + CSentence& outwords ) = 0; +}; + +#define VPHONEME_EXTRACTOR_INTERFACE "PHONEME_EXTRACTOR_001" + +#endif // PHONEMEEXTRACTOR_H diff --git a/public/phyfile.h b/public/phyfile.h new file mode 100644 index 0000000..c6b3772 --- /dev/null +++ b/public/phyfile.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHYFILE_H +#define PHYFILE_H +#pragma once + +#include "datamap.h" + +typedef struct phyheader_s +{ + DECLARE_BYTESWAP_DATADESC(); + int size; + int id; + int solidCount; + long checkSum; // checksum of source .mdl file +} phyheader_t; + +#endif // PHYFILE_H diff --git a/public/pixelwriter.h b/public/pixelwriter.h new file mode 100644 index 0000000..5c51055 --- /dev/null +++ b/public/pixelwriter.h @@ -0,0 +1,883 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef PIXELWRITER_H +#define PIXELWRITER_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _WIN32 +#define FORCEINLINE_PIXEL FORCEINLINE +#elif POSIX +#define FORCEINLINE_PIXEL inline +#else +#error "implement me" +#endif + +#include "bitmap/imageformat.h" +#include "tier0/dbg.h" +#include "mathlib/compressed_vector.h" +#include "mathlib/ssemath.h" + +//----------------------------------------------------------------------------- +// Color writing class +//----------------------------------------------------------------------------- + +class CPixelWriter +{ +public: + FORCEINLINE void SetPixelMemory( ImageFormat format, void* pMemory, int stride ); + FORCEINLINE void *GetPixelMemory() { return m_pBase; } + + // this is no longer used: +#if 0 // defined( _X360 ) + // set after SetPixelMemory() + FORCEINLINE void ActivateByteSwapping( bool bSwap ); +#endif + + FORCEINLINE void Seek( int x, int y ); + FORCEINLINE void* SkipBytes( int n ); + FORCEINLINE void SkipPixels( int n ); + FORCEINLINE void WritePixel( int r, int g, int b, int a = 255 ); + FORCEINLINE void WritePixelNoAdvance( int r, int g, int b, int a = 255 ); + FORCEINLINE void WritePixelSigned( int r, int g, int b, int a = 255 ); + FORCEINLINE void WritePixelNoAdvanceSigned( int r, int g, int b, int a = 255 ); + FORCEINLINE void ReadPixelNoAdvance( int &r, int &g, int &b, int &a ); + + // Floating point formats + FORCEINLINE void WritePixelNoAdvanceF( float r, float g, float b, float a = 1.0f ); + FORCEINLINE void WritePixelF( float r, float g, float b, float a = 1.0f ); + + // SIMD formats + FORCEINLINE void WritePixel( FLTX4 rgba ); + FORCEINLINE void WritePixelNoAdvance( FLTX4 rgba ); +#ifdef _X360 + // here are some explicit formats so we can avoid the switch: + FORCEINLINE void WritePixelNoAdvance_RGBA8888( FLTX4 rgba ); + FORCEINLINE void WritePixelNoAdvance_BGRA8888( FLTX4 rgba ); + // as above, but with m_pBits passed in to avoid a LHS + FORCEINLINE void WritePixelNoAdvance_BGRA8888( FLTX4 rgba, void *pBits ); + // for writing entire SIMD registers at once when they have + // already been packed, and when m_pBits is vector-aligned + // (which is a requirement for write-combined memory) + // offset is added to m_pBits (saving you from the obligatory + // LHS of a SkipBytes) + FORCEINLINE void WriteFourPixelsExplicitLocation_BGRA8888( FLTX4 rgba, int offset ); +#endif + + + FORCEINLINE unsigned char GetPixelSize() { return m_Size; } + + FORCEINLINE bool IsUsingFloatFormat() const; + FORCEINLINE unsigned char *GetCurrentPixel() { return m_pBits; } + +private: + enum + { + PIXELWRITER_USING_FLOAT_FORMAT = 0x01, + PIXELWRITER_USING_16BIT_FLOAT_FORMAT = 0x02, + PIXELWRITER_SWAPBYTES = 0x04, + }; + + unsigned char* m_pBase; + unsigned char* m_pBits; + unsigned short m_BytesPerRow; + unsigned char m_Size; + unsigned char m_nFlags; + signed short m_RShift; + signed short m_GShift; + signed short m_BShift; + signed short m_AShift; + unsigned int m_RMask; + unsigned int m_GMask; + unsigned int m_BMask; + unsigned int m_AMask; + +#ifdef _X360 + ImageFormat m_Format; +public: + inline const ImageFormat &GetFormat() { return m_Format; } +private: +#endif +}; + +FORCEINLINE_PIXEL bool CPixelWriter::IsUsingFloatFormat() const +{ + return (m_nFlags & PIXELWRITER_USING_FLOAT_FORMAT) != 0; +} + +FORCEINLINE_PIXEL void CPixelWriter::SetPixelMemory( ImageFormat format, void* pMemory, int stride ) +{ + m_pBits = (unsigned char*)pMemory; + m_pBase = m_pBits; + m_BytesPerRow = (unsigned short)stride; + m_nFlags = 0; +#ifdef _X360 + m_Format = format; +#endif + + switch ( format ) + { + case IMAGE_FORMAT_R32F: // NOTE! : the low order bits are first in this naming convention. + m_Size = 4; + m_RShift = 0; + m_GShift = 0; + m_BShift = 0; + m_AShift = 0; + m_RMask = 0xFFFFFFFF; + m_GMask = 0x0; + m_BMask = 0x0; + m_AMask = 0x0; + m_nFlags |= PIXELWRITER_USING_FLOAT_FORMAT; + break; + + case IMAGE_FORMAT_RGBA32323232F: + m_Size = 16; + m_RShift = 0; + m_GShift = 32; + m_BShift = 64; + m_AShift = 96; + m_RMask = 0xFFFFFFFF; + m_GMask = 0xFFFFFFFF; + m_BMask = 0xFFFFFFFF; + m_AMask = 0xFFFFFFFF; + m_nFlags |= PIXELWRITER_USING_FLOAT_FORMAT; + break; + + case IMAGE_FORMAT_RGBA16161616F: + m_Size = 8; + m_RShift = 0; + m_GShift = 16; + m_BShift = 32; + m_AShift = 48; + m_RMask = 0xFFFF; + m_GMask = 0xFFFF; + m_BMask = 0xFFFF; + m_AMask = 0xFFFF; + m_nFlags |= PIXELWRITER_USING_FLOAT_FORMAT | PIXELWRITER_USING_16BIT_FLOAT_FORMAT; + break; + + case IMAGE_FORMAT_RGBA8888: +#if defined( _X360 ) + case IMAGE_FORMAT_LINEAR_RGBA8888: +#endif + m_Size = 4; + m_RShift = 0; + m_GShift = 8; + m_BShift = 16; + m_AShift = 24; + m_RMask = 0xFF; + m_GMask = 0xFF; + m_BMask = 0xFF; + m_AMask = 0xFF; + break; + + case IMAGE_FORMAT_BGRA8888: // NOTE! : the low order bits are first in this naming convention. +#if defined( _X360 ) + case IMAGE_FORMAT_LINEAR_BGRA8888: +#endif + m_Size = 4; + m_RShift = 16; + m_GShift = 8; + m_BShift = 0; + m_AShift = 24; + m_RMask = 0xFF; + m_GMask = 0xFF; + m_BMask = 0xFF; + m_AMask = 0xFF; + break; + + case IMAGE_FORMAT_BGRX8888: +#if defined( _X360 ) + case IMAGE_FORMAT_LINEAR_BGRX8888: +#endif + m_Size = 4; + m_RShift = 16; + m_GShift = 8; + m_BShift = 0; + m_AShift = 24; + m_RMask = 0xFF; + m_GMask = 0xFF; + m_BMask = 0xFF; + m_AMask = 0x00; + break; + + case IMAGE_FORMAT_BGRA4444: + m_Size = 2; + m_RShift = 4; + m_GShift = 0; + m_BShift = -4; + m_AShift = 8; + m_RMask = 0xF0; + m_GMask = 0xF0; + m_BMask = 0xF0; + m_AMask = 0xF0; + break; + + case IMAGE_FORMAT_BGR888: + m_Size = 3; + m_RShift = 16; + m_GShift = 8; + m_BShift = 0; + m_AShift = 0; + m_RMask = 0xFF; + m_GMask = 0xFF; + m_BMask = 0xFF; + m_AMask = 0x00; + break; + + case IMAGE_FORMAT_BGR565: + m_Size = 2; + m_RShift = 8; + m_GShift = 3; + m_BShift = -3; + m_AShift = 0; + m_RMask = 0xF8; + m_GMask = 0xFC; + m_BMask = 0xF8; + m_AMask = 0x00; + break; + + case IMAGE_FORMAT_BGRA5551: + case IMAGE_FORMAT_BGRX5551: + m_Size = 2; + m_RShift = 7; + m_GShift = 2; + m_BShift = -3; + m_AShift = 8; + m_RMask = 0xF8; + m_GMask = 0xF8; + m_BMask = 0xF8; + m_AMask = 0x80; + break; + + // GR - alpha format for HDR support + case IMAGE_FORMAT_A8: + m_Size = 1; + m_RShift = 0; + m_GShift = 0; + m_BShift = 0; + m_AShift = 0; + m_RMask = 0x00; + m_GMask = 0x00; + m_BMask = 0x00; + m_AMask = 0xFF; + break; + + case IMAGE_FORMAT_UVWQ8888: + m_Size = 4; + m_RShift = 0; + m_GShift = 8; + m_BShift = 16; + m_AShift = 24; + m_RMask = 0xFF; + m_GMask = 0xFF; + m_BMask = 0xFF; + m_AMask = 0xFF; + break; + + case IMAGE_FORMAT_RGBA16161616: +#if defined( _X360 ) + case IMAGE_FORMAT_LINEAR_RGBA16161616: +#endif + m_Size = 8; + if ( !IsX360() ) + { + m_RShift = 0; + m_GShift = 16; + m_BShift = 32; + m_AShift = 48; + } + else + { + m_RShift = 48; + m_GShift = 32; + m_BShift = 16; + m_AShift = 0; + } + m_RMask = 0xFFFF; + m_GMask = 0xFFFF; + m_BMask = 0xFFFF; + m_AMask = 0xFFFF; + break; + + case IMAGE_FORMAT_I8: + // whatever goes into R is considered the intensity. + m_Size = 1; + m_RShift = 0; + m_GShift = 0; + m_BShift = 0; + m_AShift = 0; + m_RMask = 0xFF; + m_GMask = 0x00; + m_BMask = 0x00; + m_AMask = 0x00; + break; + // FIXME: Add more color formats as need arises + default: + { + static bool format_error_printed[NUM_IMAGE_FORMATS]; + if ( !format_error_printed[format] ) + { + Assert( 0 ); + Msg( "CPixelWriter::SetPixelMemory: Unsupported image format %i\n", format ); + format_error_printed[format] = true; + } + m_Size = 0; // set to zero so that we don't stomp memory for formats that we don't understand. + m_RShift = 0; + m_GShift = 0; + m_BShift = 0; + m_AShift = 0; + m_RMask = 0x00; + m_GMask = 0x00; + m_BMask = 0x00; + m_AMask = 0x00; + } + break; + } +} + +#if 0 // defined( _X360 ) +FORCEINLINE void CPixelWriter::ActivateByteSwapping( bool bSwap ) +{ + // X360TBD: Who is trying to use this? + // Purposely not hooked up because PixelWriter has been ported to read/write native pixels only + Assert( 0 ); + + if ( bSwap && !(m_nFlags & PIXELWRITER_SWAPBYTES ) ) + { + m_nFlags |= PIXELWRITER_SWAPBYTES; + + // only tested with 4 byte formats + Assert( m_Size == 4 ); + } + else if ( !bSwap && (m_nFlags & PIXELWRITER_SWAPBYTES ) ) + { + m_nFlags &= ~PIXELWRITER_SWAPBYTES; + } + else + { + // same state + return; + } + + // swap the shifts + m_RShift = 24-m_RShift; + m_GShift = 24-m_GShift; + m_BShift = 24-m_BShift; + m_AShift = 24-m_AShift; +} +#endif + +//----------------------------------------------------------------------------- +// Sets where we're writing to +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::Seek( int x, int y ) +{ + m_pBits = m_pBase + y * m_BytesPerRow + x * m_Size; +} + + +//----------------------------------------------------------------------------- +// Skips n bytes: +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void* CPixelWriter::SkipBytes( int n ) RESTRICT +{ + m_pBits += n; + return m_pBits; +} + + +//----------------------------------------------------------------------------- +// Skips n pixels: +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::SkipPixels( int n ) +{ + SkipBytes( n * m_Size ); +} + + +//----------------------------------------------------------------------------- +// Writes a pixel without advancing the index PC ONLY +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvanceF( float r, float g, float b, float a ) +{ + Assert( IsUsingFloatFormat() ); + + // X360TBD: Not ported + Assert( IsPC() ); + + if (PIXELWRITER_USING_16BIT_FLOAT_FORMAT & m_nFlags) + { + float16 fp16[4]; + fp16[0].SetFloat( r ); + fp16[1].SetFloat( g ); + fp16[2].SetFloat( b ); + fp16[3].SetFloat( a ); + // fp16 + unsigned short pBuf[4] = { 0, 0, 0, 0 }; + pBuf[ m_RShift >> 4 ] |= (fp16[0].GetBits() & m_RMask) << ( m_RShift & 0xF ); + pBuf[ m_GShift >> 4 ] |= (fp16[1].GetBits() & m_GMask) << ( m_GShift & 0xF ); + pBuf[ m_BShift >> 4 ] |= (fp16[2].GetBits() & m_BMask) << ( m_BShift & 0xF ); + pBuf[ m_AShift >> 4 ] |= (fp16[3].GetBits() & m_AMask) << ( m_AShift & 0xF ); + memcpy( m_pBits, pBuf, m_Size ); + } + else + { + // fp32 + int pBuf[4] = { 0, 0, 0, 0 }; + pBuf[ m_RShift >> 5 ] |= (FloatBits(r) & m_RMask) << ( m_RShift & 0x1F ); + pBuf[ m_GShift >> 5 ] |= (FloatBits(g) & m_GMask) << ( m_GShift & 0x1F ); + pBuf[ m_BShift >> 5 ] |= (FloatBits(b) & m_BMask) << ( m_BShift & 0x1F ); + pBuf[ m_AShift >> 5 ] |= (FloatBits(a) & m_AMask) << ( m_AShift & 0x1F ); + memcpy( m_pBits, pBuf, m_Size ); + } +} + +//----------------------------------------------------------------------------- +// Writes a pixel, advances the write index +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixelF( float r, float g, float b, float a ) +{ + WritePixelNoAdvanceF(r, g, b, a); + m_pBits += m_Size; +} + + +//----------------------------------------------------------------------------- +// Writes a pixel, advances the write index +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixel( int r, int g, int b, int a ) +{ + WritePixelNoAdvance(r,g,b,a); + m_pBits += m_Size; +} + +//----------------------------------------------------------------------------- +// Writes a pixel, advances the write index +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixelSigned( int r, int g, int b, int a ) +{ + WritePixelNoAdvanceSigned(r,g,b,a); + m_pBits += m_Size; +} + + +//----------------------------------------------------------------------------- +// Writes a pixel without advancing the index +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvance( int r, int g, int b, int a ) +{ + Assert( !IsUsingFloatFormat() ); + + if ( m_Size <= 0 ) + { + return; + } + if ( m_Size < 5 ) + { + unsigned int val = (r & m_RMask) << m_RShift; + val |= (g & m_GMask) << m_GShift; + val |= (m_BShift > 0) ? ((b & m_BMask) << m_BShift) : ((b & m_BMask) >> -m_BShift); + val |= (a & m_AMask) << m_AShift; + + switch( m_Size ) + { + default: + Assert( 0 ); + return; + case 1: + { + m_pBits[0] = (unsigned char)((val & 0xff)); + return; + } + case 2: + { + ((unsigned short *)m_pBits)[0] = (unsigned short)((val & 0xffff)); + return; + } + case 3: + { + if ( IsPC() || !IsX360() ) + { + ((unsigned short *)m_pBits)[0] = (unsigned short)((val & 0xffff)); + m_pBits[2] = (unsigned char)((val >> 16) & 0xff); + } + else + { + m_pBits[0] = (unsigned char)(((val >> 16) & 0xff)); + m_pBits[1] = (unsigned char)(((val >> 8 ) & 0xff)); + m_pBits[2] = (unsigned char)(val & 0xff); + } + return; + } + case 4: + { + ((unsigned int *)m_pBits)[0] = val; + return; + } + } + } + else // RGBA32323232 or RGBA16161616 -- PC only. + { + AssertMsg(!IsX360(), "Unsupported lightmap format used in WritePixelNoAdvance(). This is a severe performance fault.\n"); + + int64 val = ( ( int64 )(r & m_RMask) ) << m_RShift; + val |= ( ( int64 )(g & m_GMask) ) << m_GShift; + val |= (m_BShift > 0) ? ((( int64 )( b & m_BMask)) << m_BShift) : (((int64)( b & m_BMask)) >> -m_BShift); + val |= ( ( int64 )(a & m_AMask) ) << m_AShift; + + switch( m_Size ) + { + case 6: + { + if ( IsPC() || !IsX360() ) + { + ((unsigned int *)m_pBits)[0] = val & 0xffffffff; + ((unsigned short *)m_pBits)[2] = (unsigned short)( ( val >> 32 ) & 0xffff ); + } + else + { + ((unsigned int *)m_pBits)[0] = (val >> 16) & 0xffffffff; + ((unsigned short *)m_pBits)[2] = (unsigned short)( val & 0xffff ); + } + return; + } + case 8: + { + if ( IsPC() || !IsX360() ) + { + ((unsigned int *)m_pBits)[0] = val & 0xffffffff; + ((unsigned int *)m_pBits)[1] = ( val >> 32 ) & 0xffffffff; + } + else + { + ((unsigned int *)m_pBits)[0] = ( val >> 32 ) & 0xffffffff; + ((unsigned int *)m_pBits)[1] = val & 0xffffffff; + } + return; + } + default: + Assert( 0 ); + return; + } + } +} + +#ifdef _X360 +// There isn't a PC port of these because of the many varied +// pixel formats the PC deals with. If you write SSE versions +// of all the various necessary packers, then this can be made +// to work on PC. + +//----------------------------------------------------------------------------- +// Writes a pixel, advances the write index +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixel( FLTX4 rgba ) RESTRICT +{ + WritePixelNoAdvance(rgba); + m_pBits += m_Size; +} + +//----------------------------------------------------------------------------- +// Writes a pixel without advancing the index +// rgba are four float values, each on the range 0..255 (though they may leak +// fractionally over 255 due to numerical errors earlier) +//----------------------------------------------------------------------------- +FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvance( FLTX4 rgba ) RESTRICT +{ + Assert( !IsUsingFloatFormat() ); + + switch (m_Size) + { + case 0: + return; + case 4: + { + AssertMsg((reinterpret_cast(m_pBits) & 0x03) == 0,"Unaligned m_pBits in WritePixelNoAdvance!"); + switch ( m_Format ) + { + // note: format names are low-order-byte first. + case IMAGE_FORMAT_RGBA8888: + case IMAGE_FORMAT_LINEAR_RGBA8888: + WritePixelNoAdvance_RGBA8888(rgba); + break; + + case IMAGE_FORMAT_BGRA8888: // NOTE! : the low order bits are first in this naming convention. + case IMAGE_FORMAT_LINEAR_BGRA8888: + WritePixelNoAdvance_BGRA8888(rgba); + break; + + + default: + AssertMsg1(false, "Unknown four-byte pixel format %d in lightmap write.\n", m_Format); + } + break; + } + + default: + AssertMsg1(false, "WritePixelNoAdvance on unsupported 360 %d-byte format\n", m_Size); + break; + } + +} + + +// here are some explicit formats so we can avoid the switch: +FORCEINLINE void CPixelWriter::WritePixelNoAdvance_RGBA8888( FLTX4 rgba ) +{ + // it's easier to do tiered convert-saturates here + // than the d3d color convertor op + + // first permute + const static fltx4 permReverse = XMVectorPermuteControl(3,2,1,0); + fltx4 N = XMVectorPermute(rgba, rgba, permReverse); + + N = __vctuxs(N, 0); // convert to unsigned fixed point 0 w/ saturate + N = __vpkuwus(N, N); // convert to halfword saturate + N = __vpkuhus(N, N); // convert to byte saturate + N = __vspltw(N, 0); // splat w-word to all four + + __stvewx(N, m_pBits, 0); // store whatever word happens to be aligned with m_pBits to that word +} + +FORCEINLINE void CPixelWriter::WritePixelNoAdvance_BGRA8888( FLTX4 rgba ) +{ + WritePixelNoAdvance_BGRA8888( rgba, m_pBits ); +} + +FORCEINLINE void CPixelWriter::WritePixelNoAdvance_BGRA8888( FLTX4 rgba, void * RESTRICT pBits ) RESTRICT +{ + // this happens to be in an order such that we can use the handy builtin packing op + // clamp to 0..255 (coz it might have leaked over) + static const fltx4 vTwoFiftyFive = {255.0f, 255.0f, 255.0f, 255.0f}; + fltx4 N = MinSIMD(vTwoFiftyFive, rgba); + + // the magic number such that when mul-accummulated against rbga, + // gets us a representation 3.0 + (r)*2^-22 -- puts the bits at + // the bottom of the float + static CONST XMVECTOR PackScale = { (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22))}; // 255.0f / (FLOAT)(1 << 22) + static const XMVECTOR Three = {3.0f, 3.0f, 3.0f, 3.0f}; + + N = __vmaddfp(N, PackScale, Three); + N = __vpkd3d(N, N, VPACK_D3DCOLOR, VPACK_32, 3); // pack to X word + N = __vspltw(N, 0); // splat X + + // this is a nasty thing to work around the April XDK bug in __stvewx + { + void * RESTRICT copyOfPBits = pBits; + __stvewx(N, copyOfPBits, 0); + } + +} + +// for writing entire SIMD registers at once +FORCEINLINE void CPixelWriter::WriteFourPixelsExplicitLocation_BGRA8888 ( FLTX4 rgba, int offset ) +{ + Assert( (reinterpret_cast(m_pBits) & 15) == 0 ); // assert alignment + XMStoreVector4A( m_pBits + offset , rgba ); +} + + +#endif + +//----------------------------------------------------------------------------- +// Writes a signed pixel without advancing the index +//----------------------------------------------------------------------------- + +FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvanceSigned( int r, int g, int b, int a ) +{ + Assert( !IsUsingFloatFormat() ); + + if ( m_Size <= 0 ) + { + return; + } + + if ( m_Size < 5 ) + { + int val = (r & m_RMask) << m_RShift; + val |= (g & m_GMask) << m_GShift; + val |= (m_BShift > 0) ? ((b & m_BMask) << m_BShift) : ((b & m_BMask) >> -m_BShift); + val |= (a & m_AMask) << m_AShift; + signed char *pSignedBits = (signed char *)m_pBits; + + if ( IsPC() || !IsX360() ) + { + switch ( m_Size ) + { + case 4: + pSignedBits[3] = (signed char)((val >> 24) & 0xff); + // fall through intentionally. + case 3: + pSignedBits[2] = (signed char)((val >> 16) & 0xff); + // fall through intentionally. + case 2: + pSignedBits[1] = (signed char)((val >> 8) & 0xff); + // fall through intentionally. + case 1: + pSignedBits[0] = (signed char)((val & 0xff)); + // fall through intentionally. + return; + } + } + else + { + switch ( m_Size ) + { + case 4: + pSignedBits[0] = (signed char)((val >> 24) & 0xff); + pSignedBits[1] = (signed char)((val >> 16) & 0xff); + pSignedBits[2] = (signed char)((val >> 8) & 0xff); + pSignedBits[3] = (signed char)(val & 0xff); + break; + case 3: + pSignedBits[0] = (signed char)((val >> 16) & 0xff); + pSignedBits[1] = (signed char)((val >> 8) & 0xff); + pSignedBits[2] = (signed char)(val & 0xff); + break; + case 2: + pSignedBits[0] = (signed char)((val >> 8) & 0xff); + pSignedBits[1] = (signed char)(val & 0xff); + break; + case 1: + pSignedBits[0] = (signed char)(val & 0xff); + break; + } + } + } + else + { + int64 val = ( ( int64 )(r & m_RMask) ) << m_RShift; + val |= ( ( int64 )(g & m_GMask) ) << m_GShift; + val |= (m_BShift > 0) ? ((( int64 )( b & m_BMask)) << m_BShift) : (((int64)( b & m_BMask)) >> -m_BShift); + val |= ( ( int64 )(a & m_AMask) ) << m_AShift; + signed char *pSignedBits = ( signed char * )m_pBits; + + if ( IsPC() || !IsX360() ) + { + switch( m_Size ) + { + case 8: + pSignedBits[7] = (signed char)((val >> 56) & 0xff); + pSignedBits[6] = (signed char)((val >> 48) & 0xff); + // fall through intentionally. + case 6: + pSignedBits[5] = (signed char)((val >> 40) & 0xff); + pSignedBits[4] = (signed char)((val >> 32) & 0xff); + // fall through intentionally. + case 4: + pSignedBits[3] = (signed char)((val >> 24) & 0xff); + // fall through intentionally. + case 3: + pSignedBits[2] = (signed char)((val >> 16) & 0xff); + // fall through intentionally. + case 2: + pSignedBits[1] = (signed char)((val >> 8) & 0xff); + // fall through intentionally. + case 1: + pSignedBits[0] = (signed char)((val & 0xff)); + break; + default: + Assert( 0 ); + return; + } + } + else + { + switch( m_Size ) + { + case 8: + pSignedBits[0] = (signed char)((val >> 56) & 0xff); + pSignedBits[1] = (signed char)((val >> 48) & 0xff); + pSignedBits[2] = (signed char)((val >> 40) & 0xff); + pSignedBits[3] = (signed char)((val >> 32) & 0xff); + pSignedBits[4] = (signed char)((val >> 24) & 0xff); + pSignedBits[5] = (signed char)((val >> 16) & 0xff); + pSignedBits[6] = (signed char)((val >> 8) & 0xff); + pSignedBits[7] = (signed char)(val & 0xff); + break; + case 6: + pSignedBits[0] = (signed char)((val >> 40) & 0xff); + pSignedBits[1] = (signed char)((val >> 32) & 0xff); + pSignedBits[2] = (signed char)((val >> 24) & 0xff); + pSignedBits[3] = (signed char)((val >> 16) & 0xff); + pSignedBits[4] = (signed char)((val >> 8) & 0xff); + pSignedBits[5] = (signed char)(val & 0xff); + break; + case 4: + pSignedBits[0] = (signed char)((val >> 24) & 0xff); + pSignedBits[1] = (signed char)((val >> 16) & 0xff); + pSignedBits[2] = (signed char)((val >> 8) & 0xff); + pSignedBits[3] = (signed char)(val & 0xff); + break; + case 3: + pSignedBits[0] = (signed char)((val >> 16) & 0xff); + pSignedBits[1] = (signed char)((val >> 8) & 0xff); + pSignedBits[2] = (signed char)(val & 0xff); + break; + case 2: + pSignedBits[0] = (signed char)((val >> 8) & 0xff); + pSignedBits[1] = (signed char)(val & 0xff); + break; + case 1: + pSignedBits[0] = (signed char)(val & 0xff); + break; + default: + Assert( 0 ); + return; + } + } + } +} + +FORCEINLINE_PIXEL void CPixelWriter::ReadPixelNoAdvance( int &r, int &g, int &b, int &a ) +{ + Assert( !IsUsingFloatFormat() ); + + int val = m_pBits[0]; + if ( m_Size > 1 ) + { + if ( IsPC() || !IsX360() ) + { + val |= (int)m_pBits[1] << 8; + if ( m_Size > 2 ) + { + val |= (int)m_pBits[2] << 16; + if ( m_Size > 3 ) + { + val |= (int)m_pBits[3] << 24; + } + } + } + else + { + val <<= 8; + val |= (int)m_pBits[1]; + if ( m_Size > 2 ) + { + val <<= 8; + val |= (int)m_pBits[2]; + if ( m_Size > 3 ) + { + val <<= 8; + val |= (int)m_pBits[3]; + } + } + } + } + + r = (val>>m_RShift) & m_RMask; + g = (val>>m_GShift) & m_GMask; + b = (val>>m_BShift) & m_BMask; + a = (val>>m_AShift) & m_AMask; +} + +#endif // PIXELWRITER_H; diff --git a/public/posedebugger.cpp b/public/posedebugger.cpp new file mode 100644 index 0000000..b8a7d1e --- /dev/null +++ b/public/posedebugger.cpp @@ -0,0 +1,655 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "mathlib/mathlib.h" +#include "tier0/tslist.h" +#include "tier1/utlmap.h" +#include "tier1/convar.h" + +#include "bone_setup.h" + +#include "con_nprint.h" +#include "cdll_int.h" +#include "globalvars_base.h" + +#include "posedebugger.h" + +#include "iclientnetworkable.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +extern IVEngineClient *engine; +extern CGlobalVarsBase *gpGlobals; + +static ConVar ui_posedebug_fade_in_time( "ui_posedebug_fade_in_time", "0.2", + FCVAR_CHEAT | FCVAR_DONTRECORD, + "Time during which a new pose activity layer is shown in green in +posedebug UI" ); +static ConVar ui_posedebug_fade_out_time( "ui_posedebug_fade_out_time", "0.8", + FCVAR_CHEAT | FCVAR_DONTRECORD, + "Time to keep a no longer active pose activity layer in red until removing it from +posedebug UI" ); + + +////////////////////////////////////////////////////////////////////////// +// +// CPoseDebuggerStub : IPoseDebugger +// empty interface implementation +// +////////////////////////////////////////////////////////////////////////// + +class CPoseDebuggerStub : public IPoseDebugger +{ +public: + virtual void StartBlending( IClientNetworkable *pEntity, const CStudioHdr *pStudioHdr ) { } + virtual void AccumulatePose( + const CStudioHdr *pStudioHdr, + CIKContext *pIKContext, + Vector pos[], + Quaternion q[], + int sequence, + float cycle, + const float poseParameter[], + int boneMask, + float flWeight, + float flTime + ) { } +}; + +static CPoseDebuggerStub s_PoseDebuggerStub; +IPoseDebugger *g_pPoseDebugger = &s_PoseDebuggerStub; + +////////////////////////////////////////////////////////////////////////// +// +// CPoseDebuggerImpl : IPoseDebugger +// Purpose: Main implementation of the pose debugger +// Declaration +// +////////////////////////////////////////////////////////////////////////// + +class ModelPoseDebugInfo +{ +public: + ModelPoseDebugInfo() : m_iEntNum( 0 ), m_iCurrentText( 0 ) { } + + +public: + // Entity number + int m_iEntNum; + + // Currently processed text + int m_iCurrentText; + + // Info Text Flags + enum InfoTextFlags + { + F_SEEN_THIS_FRAME = 1 << 0, + F_SEEN_LAST_FRAME = 1 << 1, + }; + + struct InfoText + { + InfoText() { memset( this, 0, sizeof( *this ) ); } + + // Flags + uint32 m_uiFlags; + + // Time seen + float m_flTimeToLive, m_flTimeAlive; + + // Activity/label + int m_iActivity; + char m_chActivity[100]; + char m_chLabel[100]; + + // Text + char m_chTextLines[4][256]; + enum + { + MAX_TEXT_LINES = 4 + }; + }; + + CCopyableUtlVector< InfoText > m_arrTxt; + + +public: + // Add an info text + void AddInfoText( InfoText *x, ModelPoseDebugInfo *pOld ); + + // Lookup an info text + InfoText *LookupInfoText( InfoText *x ); + + // Print pending info text + void PrintPendingInfoText( int &rnPosPrint ); +}; + +void ModelPoseDebugInfo::AddInfoText( InfoText *x, ModelPoseDebugInfo *pOld ) +{ + if ( x ) + { + // Try to set the proper flags on the info text + x->m_uiFlags &= ~F_SEEN_LAST_FRAME; + x->m_uiFlags |= F_SEEN_THIS_FRAME; + } + + // If we have smth to compare against + if ( pOld ) + { + // Search for the same activity/label in the other model pose debug info + ModelPoseDebugInfo &o = *pOld; + int k = o.m_iCurrentText; + if ( x ) + { + for ( ; k < o.m_arrTxt.Count(); ++ k ) + { + InfoText &txt = o.m_arrTxt[k]; + if ( ( txt.m_uiFlags & F_SEEN_THIS_FRAME ) && + !stricmp( x->m_chActivity, txt.m_chActivity ) && + !stricmp( x->m_chLabel, txt.m_chLabel ) && + ( x->m_iActivity == txt.m_iActivity ) ) + { + x->m_flTimeAlive = txt.m_flTimeAlive; + break; + } + } + } + else + { + k = o.m_arrTxt.Count(); + } + + // Range of finished activities + int iFinishedRange[2] = { o.m_iCurrentText, k }; + + // Check whether this is a new message + if ( k == o.m_arrTxt.Count() ) + { + if ( !x ) + { + o.m_iCurrentText = k; + } + else + { + // Don't update the current when insertion happens and don't have finished commands + iFinishedRange[1] = iFinishedRange[0]; + } + } + else + { + o.m_iCurrentText = k + 1; + if ( x ) + { + x->m_uiFlags |= F_SEEN_LAST_FRAME; + x->m_flTimeAlive += gpGlobals->frametime; + } + } + + // Everything before finished + for ( int iFinished = iFinishedRange[0]; iFinished < iFinishedRange[1]; ++ iFinished ) + { + InfoText &txtFinished = o.m_arrTxt[ iFinished ]; + + if ( txtFinished.m_uiFlags & F_SEEN_THIS_FRAME ) + txtFinished.m_uiFlags |= F_SEEN_LAST_FRAME; + + txtFinished.m_uiFlags &= ~F_SEEN_THIS_FRAME; + + txtFinished.m_flTimeToLive -= gpGlobals->frametime; + txtFinished.m_flTimeAlive += gpGlobals->frametime; + + if ( txtFinished.m_flTimeToLive >= 0.0f ) + m_arrTxt.AddToTail( txtFinished ); + } + } + + if ( x ) + { + // Now add it to the array + x->m_flTimeToLive = ui_posedebug_fade_out_time.GetFloat(); + m_arrTxt.AddToTail( *x ); + } +} + +ModelPoseDebugInfo::InfoText * ModelPoseDebugInfo::LookupInfoText( InfoText *x ) +{ + int k = m_iCurrentText; + if ( x ) + { + for ( ; k < m_arrTxt.Count(); ++ k ) + { + InfoText &txt = m_arrTxt[k]; + if ( ( txt.m_uiFlags & F_SEEN_THIS_FRAME ) && + !stricmp( x->m_chActivity, txt.m_chActivity ) && + !stricmp( x->m_chLabel, txt.m_chLabel ) && + ( x->m_iActivity == txt.m_iActivity ) ) + { + return &txt; + } + } + } + return NULL; +} + +void ModelPoseDebugInfo::PrintPendingInfoText( int &rnPosPrint ) +{ + con_nprint_s nxPrn = { 0 }; + nxPrn.time_to_live = -1; + nxPrn.color[0] = 1.0f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 1.0f; + nxPrn.fixed_width_font = true; + + float const flFadeInTime = ui_posedebug_fade_in_time.GetFloat(); + float const flFadeOutTime = ui_posedebug_fade_out_time.GetFloat(); + + // Now print all the accumulated spew + for ( int k = m_iCurrentText; k < m_arrTxt.Count(); ++ k ) + { + InfoText &prntxt = m_arrTxt[k]; + + switch( prntxt.m_uiFlags & ( F_SEEN_LAST_FRAME | F_SEEN_THIS_FRAME ) ) + { + case ( F_SEEN_LAST_FRAME | F_SEEN_THIS_FRAME ) : + nxPrn.color[0] = 1.f; + nxPrn.color[1] = 1.f; + nxPrn.color[2] = 1.f; + if ( prntxt.m_flTimeAlive > flFadeInTime ) + break; + else + NULL; // Fall-through to keep showing in green + case F_SEEN_THIS_FRAME : + if ( flFadeInTime > 0.f ) + { + nxPrn.color[0] = 1.f * prntxt.m_flTimeAlive / flFadeInTime; + nxPrn.color[1] = 1.f; + nxPrn.color[2] = 1.f * prntxt.m_flTimeAlive / flFadeInTime; + } + else + { + nxPrn.color[0] = ( prntxt.m_flTimeAlive > 0.0f ) ? 1.f : 0.f; + nxPrn.color[1] = 1.f; + nxPrn.color[2] = ( prntxt.m_flTimeAlive > 0.0f ) ? 1.f : 0.f; + } + break; + case F_SEEN_LAST_FRAME : + case 0: + if ( flFadeOutTime > 0.f ) + nxPrn.color[0] = 1.f * prntxt.m_flTimeToLive / flFadeOutTime; + else + nxPrn.color[0] = ( prntxt.m_flTimeToLive > 0.0f ) ? 1.f : 0.f; + nxPrn.color[1] = 0.f; + nxPrn.color[2] = 0.f; + break; + } + + nxPrn.index = ( rnPosPrint += 1 ); + engine->Con_NXPrintf( &nxPrn, "%s", prntxt.m_chTextLines[0] ); + + for ( int iLine = 1; iLine < ModelPoseDebugInfo::InfoText::MAX_TEXT_LINES; ++ iLine) + { + if ( !prntxt.m_chTextLines[iLine][0] ) + break; + + nxPrn.index = ( rnPosPrint += 1 ); + engine->Con_NXPrintf( &nxPrn, "%s", prntxt.m_chTextLines[iLine] ); + } + } + + m_iCurrentText = m_arrTxt.Count(); +} + + + +class CPoseDebuggerImpl : public IPoseDebugger +{ +public: + CPoseDebuggerImpl(); + ~CPoseDebuggerImpl(); + +public: + void ShowAllModels( bool bShow ); + void ShowModel( int iEntNum, bool bShow ); + bool IsModelShown( int iEntNum ) const; + +public: + virtual void StartBlending( IClientNetworkable *pEntity, const CStudioHdr *pStudioHdr ); + virtual void AccumulatePose( + const CStudioHdr *pStudioHdr, + CIKContext *pIKContext, + Vector pos[], + Quaternion q[], + int sequence, + float cycle, + const float poseParameter[], + int boneMask, + float flWeight, + float flTime + ); + +protected: + typedef CUtlMap< CStudioHdr const *, ModelPoseDebugInfo > MapModel; + MapModel m_mapModel, m_mapModelOld; + int m_nPosPrint; + + CBitVec< MAX_EDICTS > m_uiMaskShowModels; + + CStudioHdr const *m_pLastModel; +}; + +static CPoseDebuggerImpl s_PoseDebuggerImpl; + +////////////////////////////////////////////////////////////////////////// +// +// CPoseDebuggerImpl +// Implementation +// +////////////////////////////////////////////////////////////////////////// + +CPoseDebuggerImpl::CPoseDebuggerImpl() : + m_mapModel( DefLessFunc( CStudioHdr const * ) ), + m_mapModelOld( DefLessFunc( CStudioHdr const * ) ), + m_nPosPrint( 0 ), + m_pLastModel( NULL ) +{ + m_uiMaskShowModels.SetAll(); +} + +CPoseDebuggerImpl::~CPoseDebuggerImpl() +{ + // g_pPoseDebugger = &s_PoseDebuggerStub; +} + +void CPoseDebuggerImpl::ShowAllModels( bool bShow ) +{ + bShow ? m_uiMaskShowModels.SetAll() : m_uiMaskShowModels.ClearAll(); +} + +void CPoseDebuggerImpl::ShowModel( int iEntNum, bool bShow ) +{ + Assert( iEntNum < MAX_EDICTS ); + if ( iEntNum < MAX_EDICTS ) + m_uiMaskShowModels.Set( iEntNum, bShow ); +} + +bool CPoseDebuggerImpl::IsModelShown( int iEntNum ) const +{ + Assert( iEntNum < MAX_EDICTS ); + if ( iEntNum >= 0 && iEntNum < MAX_EDICTS ) + return m_uiMaskShowModels.IsBitSet( iEntNum ); + else + return false; +} + +void CPoseDebuggerImpl::StartBlending( IClientNetworkable *pEntity, const CStudioHdr *pStudioHdr ) +{ +// virtualmodel_t const *pVMdl = pStudioHdr->GetVirtualModel(); +// if ( !pVMdl ) +// return; + + // If we are starting a new model then finalize the previous one + if ( pStudioHdr != m_pLastModel && m_pLastModel ) + { + MapModel::IndexType_t idx = m_mapModel.Find( m_pLastModel ); + if ( idx != m_mapModel.InvalidIndex() ) + { + ModelPoseDebugInfo &mpi = m_mapModel.Element( idx ); + ModelPoseDebugInfo *pMpiOld = NULL; + MapModel::IndexType_t idxMapModelOld = m_mapModelOld.Find( m_pLastModel ); + if ( idxMapModelOld != m_mapModelOld.InvalidIndex() ) + { + pMpiOld = &m_mapModelOld.Element( idxMapModelOld ); + } + mpi.AddInfoText( NULL, pMpiOld ); + mpi.PrintPendingInfoText( m_nPosPrint ); + } + } + m_pLastModel = pStudioHdr; + + // Go ahead with the new model + studiohdr_t const *pRMdl = pStudioHdr->GetRenderHdr(); + if ( !pRMdl || + !pRMdl->numincludemodels ) + return; + + // Entity number + int iEntNum = pEntity->entindex(); + if ( !IsModelShown( iEntNum ) ) + return; + + // Check if we saw the model + if ( m_mapModel.Find( pStudioHdr ) != m_mapModel.InvalidIndex() ) + { + // Initialize the printing position + m_nPosPrint = 9; + + // Swap the maps + m_mapModelOld.RemoveAll(); + m_mapModelOld.Swap( m_mapModel ); + + // Zero out the text on the old map + for ( int k = m_mapModelOld.FirstInorder(); + k != m_mapModelOld.InvalidIndex(); + k = m_mapModelOld.NextInorder( k ) ) + { + ModelPoseDebugInfo &mpi = m_mapModelOld[k]; + mpi.m_iCurrentText = 0; + } + } + else + { + // Next model + m_nPosPrint += 3; + } + + ModelPoseDebugInfo mpi; + mpi.m_iEntNum = iEntNum; + m_mapModel.Insert( pStudioHdr, mpi ); + + con_nprint_s nxPrn = { 0 }; + nxPrn.index = m_nPosPrint; + nxPrn.time_to_live = -1; + nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f; + nxPrn.fixed_width_font = false; + + engine->Con_NXPrintf( &nxPrn, "[ %2d ] Model: %s", iEntNum, pRMdl->pszName() ); + m_nPosPrint += 3; +} + +void CPoseDebuggerImpl::AccumulatePose( const CStudioHdr *pStudioHdr, CIKContext *pIKContext, + Vector pos[], Quaternion q[], int sequence, float cycle, + const float poseParameter[], int boneMask, + float flWeight, float flTime ) +{ +// virtualmodel_t const *pVMdl = pStudioHdr->GetVirtualModel(); +// if ( !pVMdl ) +// return; + + studiohdr_t const *pRMdl = pStudioHdr->GetRenderHdr(); + if ( !pRMdl || + !pRMdl->numincludemodels ) + return; + + MapModel::IndexType_t idxMapModel = m_mapModel.Find( pStudioHdr ); + if ( idxMapModel == m_mapModel.InvalidIndex() ) + return; + + ModelPoseDebugInfo &mpi = m_mapModel.Element( idxMapModel ); + if ( !IsModelShown( mpi.m_iEntNum ) ) + return; + + ModelPoseDebugInfo *pMpiOld = NULL; + MapModel::IndexType_t idxMapModelOld = m_mapModelOld.Find( pStudioHdr ); + if ( idxMapModelOld != m_mapModelOld.InvalidIndex() ) + { + pMpiOld = &m_mapModelOld.Element( idxMapModelOld ); + } + + + // + // Actual processing + // + + mstudioseqdesc_t &seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( sequence ); + + if ( sequence >= pStudioHdr->GetNumSeq() ) + { + sequence = 0; + seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( sequence ); + } + + enum + { + widthActivity = 35, + widthLayer = 35, + widthIks = 60, + widthPercent = 6, + }; + + // Prepare the text + char chBuffer[256]; + ModelPoseDebugInfo::InfoText txt; + int numLines = 0; + + txt.m_iActivity = seqdesc.activity; + sprintf( txt.m_chActivity, "%s", seqdesc.pszActivityName() ); + sprintf( txt.m_chLabel, "%s", seqdesc.pszLabel() ); + + if ( !txt.m_chActivity[0] ) + { + // Try to find the last seen activity and re-use it + for ( int iLast = mpi.m_arrTxt.Count(); iLast --> 0; ) + { + ModelPoseDebugInfo::InfoText &lastSeenTxt = mpi.m_arrTxt[iLast]; + if ( lastSeenTxt.m_uiFlags & ModelPoseDebugInfo::F_SEEN_THIS_FRAME && + lastSeenTxt.m_chActivity[0] ) + { + sprintf( txt.m_chActivity, "%s", lastSeenTxt.m_chActivity ); + break; + } + } + } + + // The layer information + ModelPoseDebugInfo::InfoText *pOldTxt = pMpiOld ? pMpiOld->LookupInfoText( &txt ) : NULL; + sprintf( txt.m_chTextLines[numLines], + "%-*s %-*s %*.2f %*.1f/%-*d %*.0f%% ", + widthActivity, + seqdesc.pszActivityName(), + widthLayer, + seqdesc.pszLabel(), + 7, + pOldTxt ? pOldTxt->m_flTimeAlive : 0.f, + 5, + cycle * ( ((CStudioHdr *)pStudioHdr)->pAnimdesc( seqdesc.anim( 0, 0 ) ).numframes - 1 ), + 3, + ((CStudioHdr *)pStudioHdr)->pAnimdesc( seqdesc.anim( 0, 0 ) ).numframes, + widthPercent, + flWeight * 100.0f + ); + ++ numLines; + + if ( seqdesc.numiklocks ) + { + sprintf( chBuffer, + "iklocks : %-2d : ", + seqdesc.numiklocks ); + + for ( int k = 0; k < seqdesc.numiklocks; ++ k ) + { + mstudioiklock_t *plock = seqdesc.pIKLock( k ); + mstudioikchain_t *pchain = pStudioHdr->pIKChain( plock->chain ); + + sprintf( chBuffer + strlen( chBuffer ), "%s ", pchain->pszName() ); + // plock->flPosWeight; + // plock->flLocalQWeight; + } + + sprintf( txt.m_chTextLines[numLines], + "%-*s", + widthIks, + chBuffer + ); + ++ numLines; + } + + if ( seqdesc.numikrules ) + { + sprintf( chBuffer, "ikrules : %-2d", + seqdesc.numikrules ); + + sprintf( txt.m_chTextLines[numLines], + "%-*s", + widthIks, + chBuffer + ); + ++ numLines; + } + + + // Now add the accumulated text into the container + mpi.AddInfoText( &txt, pMpiOld ); + mpi.PrintPendingInfoText( m_nPosPrint ); +} + + +////////////////////////////////////////////////////////////////////////// +// +// Con-commands +// +////////////////////////////////////////////////////////////////////////// + +static void IN_PoseDebuggerStart( const CCommand &args ) +{ + if ( args.ArgC() <= 1 ) + { + // No args, enable all + s_PoseDebuggerImpl.ShowAllModels( true ); + } + else + { + // If explicitly showing the pose debugger when it was disabled + if ( g_pPoseDebugger != &s_PoseDebuggerImpl ) + { + s_PoseDebuggerImpl.ShowAllModels( false ); + } + + // Show only specific models + for ( int k = 1; k < args.ArgC(); ++ k ) + { + int iEntNum = atoi( args.Arg( k ) ); + s_PoseDebuggerImpl.ShowModel( iEntNum, true ); + } + } + + g_pPoseDebugger = &s_PoseDebuggerImpl; +} + +static void IN_PoseDebuggerEnd( const CCommand &args ) +{ + if ( args.ArgC() <= 1 ) + { + // No args, disable all + s_PoseDebuggerImpl.ShowAllModels( false ); + + // Set the stub pointer + g_pPoseDebugger = &s_PoseDebuggerStub; + } + else + { + // Hide only specific models + for ( int k = 1; k < args.ArgC(); ++ k ) + { + int iEntNum = atoi( args.Arg( k ) ); + s_PoseDebuggerImpl.ShowModel( iEntNum, false ); + } + } +} + +static ConCommand posedebuggerstart( "+posedebug", IN_PoseDebuggerStart, "Turn on pose debugger or add ents to pose debugger UI", FCVAR_CHEAT ); +static ConCommand posedebuggerend ( "-posedebug", IN_PoseDebuggerEnd, "Turn off pose debugger or hide ents from pose debugger UI", FCVAR_CHEAT ); diff --git a/public/posedebugger.h b/public/posedebugger.h new file mode 100644 index 0000000..f8b8153 --- /dev/null +++ b/public/posedebugger.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef POSEDEBUGGER_H +#define POSEDEBUGGER_H +#ifdef _WIN32 +#pragma once +#endif + +class IClientNetworkable; + +abstract_class IPoseDebugger +{ +public: + virtual void StartBlending( IClientNetworkable *pEntity, const CStudioHdr *pStudioHdr ) = 0; + + virtual void AccumulatePose( + const CStudioHdr *pStudioHdr, + CIKContext *pIKContext, + Vector pos[], + Quaternion q[], + int sequence, + float cycle, + const float poseParameter[], + int boneMask, + float flWeight, + float flTime + ) = 0; +}; + +extern IPoseDebugger *g_pPoseDebugger; + +#endif // #ifndef POSEDEBUGGER_H diff --git a/public/r_efx.h b/public/r_efx.h new file mode 100644 index 0000000..fea2384 --- /dev/null +++ b/public/r_efx.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#if !defined ( EFXH ) +#define EFXH +#ifdef _WIN32 +#pragma once +#endif + +#include "iefx.h" + +class IMaterial; +struct dlight_t; + +class CVEfx : public IVEfx +{ +public: + virtual ~CVEfx() {} + + virtual int Draw_DecalIndexFromName ( char *name ); + virtual void DecalShoot ( int textureIndex, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, const Vector *saxis, int flags); + virtual void DecalColorShoot ( int textureIndex, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, const Vector *saxis, int flags, const color32 &rgbaColor); + virtual void PlayerDecalShoot ( IMaterial *material, void *userdata, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, + const Vector& position, const Vector *saxis, int flags, const color32 &rgbaColor ); + virtual dlight_t *CL_AllocDlight ( int key ); + virtual dlight_t *CL_AllocElight ( int key ); + virtual int CL_GetActiveDLights ( dlight_t *pList[MAX_DLIGHTS] ); + virtual const char *Draw_DecalNameFromIndex ( int nIndex ); + virtual dlight_t *GetElightByKey ( int key ); +}; + +extern CVEfx *g_pEfx; + +#endif \ No newline at end of file diff --git a/public/raytrace.h b/public/raytrace.h new file mode 100644 index 0000000..9692b8d --- /dev/null +++ b/public/raytrace.h @@ -0,0 +1,390 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// $Id:$ + +#ifndef RAYTRACE_H +#define RAYTRACE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +// fast SSE-ONLY ray tracing module. Based upon various "real time ray tracing" research. +//#define DEBUG_RAYTRACE 1 + +class FourRays +{ +public: + FourVectors origin; + FourVectors direction; + + inline void Check(void) const + { + // in order to be valid to trace as a group, all four rays must have the same signs in all + // of their direction components +#ifndef NDEBUG + for(int c=1;c<4;c++) + { + Assert(direction.X(0)*direction.X(c)>=0); + Assert(direction.Y(0)*direction.Y(c)>=0); + Assert(direction.Z(0)*direction.Z(c)>=0); + } +#endif + } + // returns direction sign mask for 4 rays. returns -1 if the rays can not be traced as a + // bundle. + int CalculateDirectionSignMask(void) const; + +}; + +/// The format a triangle is stored in for intersections. size of this structure is important. +/// This structure can be in one of two forms. Before the ray tracing environment is set up, the +/// ProjectedEdgeEquations hold the coordinates of the 3 vertices, for facilitating bounding box +/// checks needed while building the tree. afterwards, they are changed into the projected ege +/// equations for intersection purposes. +enum triangleflags +{ + FCACHETRI_TRANSPARENT = 0x01, + FCACHETRI_NEGATIVE_NORMAL = 0x02, +}; + + +struct TriIntersectData_t +{ + // this structure is 16longs=64 bytes for cache line packing. + float m_flNx, m_flNy, m_flNz; // plane equation + float m_flD; + + int32 m_nTriangleID; // id of the triangle. + + float m_ProjectedEdgeEquations[6]; // A,B,C for each edge equation. a + // point is inside the triangle if + // a*c1+b*c2+c is negative for all 3 + // edges. + + uint8 m_nCoordSelect0,m_nCoordSelect1; // the triangle is projected onto a 2d + // plane for edge testing. These are + // the indices (0..2) of the + // coordinates preserved in the + // projection + + uint8 m_nFlags; // triangle flags + uint8 m_unused0; // no longer used +}; + + +struct TriGeometryData_t +{ + int32 m_nTriangleID; // id of the triangle. + + float m_VertexCoordData[9]; // can't use a vector in a union + + uint8 m_nFlags; // triangle flags + signed char m_nTmpData0; // used by kd-tree builder + signed char m_nTmpData1; // used by kd-tree builder + + + // accessors to get around union annoyance + FORCEINLINE Vector &Vertex(int idx) + { + return * ( reinterpret_cast ( m_VertexCoordData+3*idx ) ); + } + +}; + + +struct CacheOptimizedTriangle +{ + + union + { + TriIntersectData_t m_IntersectData; + TriGeometryData_t m_GeometryData; + } m_Data; + + // accessors to get around union annoyance + FORCEINLINE Vector &Vertex(int idx) + { + return * ( reinterpret_cast (m_Data.m_GeometryData.m_VertexCoordData+3*idx ) ); + } + + FORCEINLINE const Vector &Vertex(int idx) const + { + return * ( reinterpret_cast (m_Data.m_GeometryData.m_VertexCoordData+3*idx ) ); + } + + void ChangeIntoIntersectionFormat(void); // change information storage format for + // computing intersections. + + int ClassifyAgainstAxisSplit(int split_plane, float split_value); // PLANECHECK_xxx below + +}; + +#define PLANECHECK_POSITIVE 1 +#define PLANECHECK_NEGATIVE -1 +#define PLANECHECK_STRADDLING 0 + +#define KDNODE_STATE_XSPLIT 0 // this node is an x split +#define KDNODE_STATE_YSPLIT 1 // this node is a ysplit +#define KDNODE_STATE_ZSPLIT 2 // this node is a zsplit +#define KDNODE_STATE_LEAF 3 // this node is a leaf + +struct CacheOptimizedKDNode +{ + // this is the cache intensive data structure. "Tricks" are used to fit it into 8 bytes: + // + // A) the right child is always stored after the left child, which means we only need one + // pointer + // B) The type of node (KDNODE_xx) is stored in the lower 2 bits of the pointer. + // C) for leaf nodes, we store the number of triangles in the leaf in the same place as the floating + // point splitting parameter is stored in a non-leaf node + + int32 Children; // child idx, or'ed with flags above + float SplittingPlaneValue; // for non-leaf nodes, the nodes on the + // "high" side of the splitting plane + // are on the right + +#ifdef DEBUG_RAYTRACE + Vector vecMins; + Vector vecMaxs; +#endif + + inline int NodeType(void) const + + { + return Children & 3; + } + + inline int32 TriangleIndexStart(void) const + { + assert(NodeType()==KDNODE_STATE_LEAF); + return Children>>2; + } + + inline int LeftChild(void) const + { + assert(NodeType()!=KDNODE_STATE_LEAF); + return Children>>2; + } + + inline int RightChild(void) const + { + return LeftChild()+1; + } + + inline int NumberOfTrianglesInLeaf(void) const + { + assert(NodeType()==KDNODE_STATE_LEAF); + return *((int32 *) &SplittingPlaneValue); + } + + inline void SetNumberOfTrianglesInLeafNode(int n) + { + *((int32 *) &SplittingPlaneValue)=n; + } + +protected: + + +}; + + +struct RayTracingSingleResult +{ + Vector surface_normal; // surface normal at intersection + int32 HitID; // -1=no hit. otherwise, triangle index + float HitDistance; // distance to intersection + float ray_length; // leng of initial ray +}; + +struct RayTracingResult +{ + FourVectors surface_normal; // surface normal at intersection + ALIGN16 int32 HitIds[4] ALIGN16_POST; // -1=no hit. otherwise, triangle index + fltx4 HitDistance; // distance to intersection +}; + + +class RayTraceLight +{ +public: + FourVectors Position; + FourVectors Intensity; +}; + + +#define RTE_FLAGS_FAST_TREE_GENERATION 1 +#define RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS 2 // saves memory if not needed +#define RTE_FLAGS_DONT_STORE_TRIANGLE_MATERIALS 4 + +enum RayTraceLightingMode_t { + DIRECT_LIGHTING, // just dot product lighting + DIRECT_LIGHTING_WITH_SHADOWS, // with shadows + GLOBAL_LIGHTING // global light w/ shadows +}; + + +class RayStream +{ + friend class RayTracingEnvironment; + + RayTracingSingleResult *PendingStreamOutputs[8][4]; + int n_in_stream[8]; + FourRays PendingRays[8]; + +public: + RayStream(void) + { + memset(n_in_stream,0,sizeof(n_in_stream)); + } +}; + +// When transparent triangles are in the list, the caller can provide a callback that will get called at each triangle +// allowing the callback to stop processing if desired. +// UNDONE: This is not currently SIMD - it really only supports single rays +// Also for efficiency FourRays really needs some kind of active mask for the cases where rays get unbundled +class ITransparentTriangleCallback +{ +public: + virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *hitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID ) = 0; +}; + +class RayTracingEnvironment +{ +public: + uint32 Flags; // RTE_FLAGS_xxx above + Vector m_MinBound; + Vector m_MaxBound; + + FourVectors BackgroundColor; //< color where no intersection + CUtlVector OptimizedKDTree; //< the packed kdtree. root is 0 + CUtlBlockVector OptimizedTriangleList; //< the packed triangles + CUtlVector TriangleIndexList; //< the list of triangle indices. + CUtlVector LightList; //< the list of lights + CUtlVector TriangleColors; //< color of tries + CUtlVector TriangleMaterials; //< material index of tries + +public: + RayTracingEnvironment() : OptimizedTriangleList( 1024 ) + { + BackgroundColor.DuplicateVector(Vector(1,0,0)); // red + Flags=0; + } + + + // call AddTriangle to set up the world + void AddTriangle(int32 id, const Vector &v1, const Vector &v2, const Vector &v3, + const Vector &color); + + // Adds a triangle with flags & material + void AddTriangle(int32 id, const Vector &v1, const Vector &v2, const Vector &v3, + const Vector &color, uint16 flags, int32 materialIndex); + + + void AddQuad(int32 id, const Vector &v1, const Vector &v2, const Vector &v3, + const Vector &v4, // specify vertices in cw or ccw order + const Vector &color); + + // for ease of testing. + void AddAxisAlignedRectangularSolid(int id,Vector mincoord, Vector Maxcoord, + const Vector &color); + + + // SetupAccelerationStructure to prepare for tracing + void SetupAccelerationStructure(void); + + + // lowest level intersection routine - fire 4 rays through the scene. all 4 rays must pass the + // Check() function, and t extents must be initialized. skipid can be set to exclude a + // particular id (such as the origin surface). This function finds the closest intersection. + void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax,int DirectionSignMask, + RayTracingResult *rslt_out, + int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL); + + // higher level intersection routine that handles computing the mask and handling rays which do not match in direciton sign + void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax, + RayTracingResult *rslt_out, + int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL); + + // compute virtual light sources to model inter-reflection + void ComputeVirtualLightSources(void); + + + // high level interface - pass viewing parameters, rendering flags, and a destination frame + // buffer, and get a ray traced scene in 32-bit rgba format + void RenderScene(int width, int height, // width and height of desired rendering + int stride, // actual width in pixels of target buffer + uint32 *output_buffer, // pointer to destination + Vector CameraOrigin, // eye position + Vector ULCorner, // word space coordinates of upper left + // monitor corner + Vector URCorner, // top right corner + Vector LLCorner, // lower left + Vector LRCorner, // lower right + RayTraceLightingMode_t lightmode=DIRECT_LIGHTING); + + + /// raytracing stream - lets you trace an array of rays by feeding them to this function. + /// results will not be returned until FinishStream is called. This function handles sorting + /// the rays by direction, tracing them 4 at a time, and de-interleaving the results. + + void AddToRayStream(RayStream &s, + Vector const &start,Vector const &end,RayTracingSingleResult *rslt_out); + + inline void FlushStreamEntry(RayStream &s,int msk); + + /// call this when you are done. handles all cleanup. After this is called, all rslt ptrs + /// previously passed to AddToRaySteam will have been filled in. + void FinishRayStream(RayStream &s); + + + int MakeLeafNode(int first_tri, int last_tri); + + + float CalculateCostsOfSplit( + int split_plane,int32 const *tri_list,int ntris, + Vector MinBound,Vector MaxBound, float &split_value, + int &nleft, int &nright, int &nboth); + + void RefineNode(int node_number,int32 const *tri_list,int ntris, + Vector MinBound,Vector MaxBound, int depth); + + void CalculateTriangleListBounds(int32 const *tris,int ntris, + Vector &minout, Vector &maxout); + + void AddInfinitePointLight(Vector position, // light center + Vector intensity); // rgb amount + + // use the global variables set by LoadBSPFile to populated the RayTracingEnvironment with + // faces. + void InitializeFromLoadedBSP(void); + + void AddBSPFace(int id,dface_t const &face); + + // MakeRoomForTriangles - a hint telling it how many triangles we are going to add so that + // the utl vectors used can be pre-allocated + void MakeRoomForTriangles( int ntriangles ); + + const CacheOptimizedTriangle &GetTriangle( int32 triID ) + { + return OptimizedTriangleList[triID]; + } + + int32 GetTriangleMaterial( int32 triID ) + { + return TriangleMaterials[triID]; + } + const Vector &GetTriangleColor( int triID ) + { + return TriangleColors[triID]; + } + +}; + + + +#endif diff --git a/public/registry.cpp b/public/registry.cpp new file mode 100644 index 0000000..be4286c --- /dev/null +++ b/public/registry.cpp @@ -0,0 +1,421 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#if defined( WIN32 ) && !defined( _X360 ) +#include +#endif +#include "tier0/platform.h" +#include "tier0/vcrmode.h" +#include "iregistry.h" +#include "tier0/dbg.h" +#include "tier1/strtools.h" +#include +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Exposes registry interface to rest of launcher +//----------------------------------------------------------------------------- +class CRegistry : public IRegistry +{ +public: + CRegistry( void ); + virtual ~CRegistry( void ); + + virtual bool Init( const char *platformName ); + virtual bool DirectInit( const char *subDirectoryUnderValve ); + virtual void Shutdown( void ); + + virtual int ReadInt( const char *key, int defaultValue = 0); + virtual void WriteInt( const char *key, int value ); + + virtual const char *ReadString( const char *key, const char *defaultValue = NULL ); + virtual void WriteString( const char *key, const char *value ); + + // Read/write helper methods + virtual int ReadInt( const char *pKeyBase, const char *pKey, int defaultValue = 0 ); + virtual void WriteInt( const char *pKeyBase, const char *key, int value ); + virtual const char *ReadString( const char *pKeyBase, const char *key, const char *defaultValue ); + virtual void WriteString( const char *pKeyBase, const char *key, const char *value ); + +private: + bool m_bValid; +#ifdef WIN32 + HKEY m_hKey; +#endif +}; + +// Creates it and calls Init +IRegistry *InstanceRegistry( char const *subDirectoryUnderValve ) +{ + CRegistry *instance = new CRegistry(); + instance->DirectInit( subDirectoryUnderValve ); + return instance; +} + +// Calls Shutdown and deletes it +void ReleaseInstancedRegistry( IRegistry *reg ) +{ + if ( !reg ) + { + Assert( !"ReleaseInstancedRegistry( reg == NULL )!" ); + return; + } + + reg->Shutdown(); + delete reg; +} + +// Expose to launcher +static CRegistry g_Registry; +IRegistry *registry = ( IRegistry * )&g_Registry; + +//----------------------------------------------------------------------------- +// Read/write helper methods +//----------------------------------------------------------------------------- +int CRegistry::ReadInt( const char *pKeyBase, const char *pKey, int defaultValue ) +{ + int nLen = strlen( pKeyBase ); + int nKeyLen = strlen( pKey ); + char *pFullKey = (char*)_alloca( nLen + nKeyLen + 2 ); + Q_snprintf( pFullKey, nLen + nKeyLen + 2, "%s\\%s", pKeyBase, pKey ); + return ReadInt( pFullKey, defaultValue ); +} + +void CRegistry::WriteInt( const char *pKeyBase, const char *pKey, int value ) +{ + int nLen = strlen( pKeyBase ); + int nKeyLen = strlen( pKey ); + char *pFullKey = (char*)_alloca( nLen + nKeyLen + 2 ); + Q_snprintf( pFullKey, nLen + nKeyLen + 2, "%s\\%s", pKeyBase, pKey ); + WriteInt( pFullKey, value ); +} + +const char *CRegistry::ReadString( const char *pKeyBase, const char *pKey, const char *defaultValue ) +{ + int nLen = strlen( pKeyBase ); + int nKeyLen = strlen( pKey ); + char *pFullKey = (char*)_alloca( nLen + nKeyLen + 2 ); + Q_snprintf( pFullKey, nLen + nKeyLen + 2, "%s\\%s", pKeyBase, pKey ); + return ReadString( pFullKey, defaultValue ); +} + +void CRegistry::WriteString( const char *pKeyBase, const char *pKey, const char *value ) +{ + int nLen = strlen( pKeyBase ); + int nKeyLen = strlen( pKey ); + char *pFullKey = (char*)_alloca( nLen + nKeyLen + 2 ); + Q_snprintf( pFullKey, nLen + nKeyLen + 2, "%s\\%s", pKeyBase, pKey ); + WriteString( pFullKey, value ); +} + +#ifndef POSIX + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRegistry::CRegistry( void ) +{ + // Assume failure + m_bValid = false; + m_hKey = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRegistry::~CRegistry( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Read integer from registry +// Input : *key - +// defaultValue - +// Output : int +//----------------------------------------------------------------------------- +int CRegistry::ReadInt( const char *key, int defaultValue /*= 0*/ ) +{ + LONG lResult; // Registry function result code + DWORD dwType; // Type of key + DWORD dwSize; // Size of element data + + int value; + + if ( !m_bValid ) + { + return defaultValue; + } + + dwSize = sizeof( DWORD ); + + lResult = VCRHook_RegQueryValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + &dwType, // type buffer + (LPBYTE)&value, // data buffer + &dwSize ); // size of data buffer + + if (lResult != ERROR_SUCCESS) // Failure + return defaultValue; + + if (dwType != REG_DWORD) + return defaultValue; + + return value; +} + +//----------------------------------------------------------------------------- +// Purpose: Save integer to registry +// Input : *key - +// value - +//----------------------------------------------------------------------------- +void CRegistry::WriteInt( const char *key, int value ) +{ + // Size of element data + DWORD dwSize; + + if ( !m_bValid ) + { + return; + } + + dwSize = sizeof( DWORD ); + + VCRHook_RegSetValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + REG_DWORD, // type buffer + (LPBYTE)&value, // data buffer + dwSize ); // size of data buffer +} + +//----------------------------------------------------------------------------- +// Purpose: Read string value from registry +// Input : *key - +// *defaultValue - +// Output : const char +//----------------------------------------------------------------------------- +const char *CRegistry::ReadString( const char *key, const char *defaultValue /* = NULL */ ) +{ + LONG lResult; + // Type of key + DWORD dwType; + // Size of element data + DWORD dwSize = 512; + + static char value[ 512 ]; + + value[0] = 0; + + if ( !m_bValid ) + { + return defaultValue; + } + + lResult = VCRHook_RegQueryValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + &dwType, // type buffer + (unsigned char *)value, // data buffer + &dwSize ); // size of data buffer + + if ( lResult != ERROR_SUCCESS ) + { + return defaultValue; + } + + if ( dwType != REG_SZ ) + { + return defaultValue; + } + + return value; +} + +//----------------------------------------------------------------------------- +// Purpose: Save string to registry +// Input : *key - +// *value - +//----------------------------------------------------------------------------- +void CRegistry::WriteString( const char *key, const char *value ) +{ + DWORD dwSize; // Size of element data + + if ( !m_bValid ) + { + return; + } + + dwSize = (DWORD)( strlen( value ) + 1 ); + + VCRHook_RegSetValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + REG_SZ, // type buffer + (LPBYTE)value, // data buffer + dwSize ); // size of data buffer +} + + + + +bool CRegistry::DirectInit( const char *subDirectoryUnderValve ) +{ + LONG lResult; // Registry function result code + ULONG dwDisposition; // Type of key opening event + + char szModelKey[ 1024 ]; + wsprintf( szModelKey, "Software\\Valve\\%s", subDirectoryUnderValve ); + + lResult = VCRHook_RegCreateKeyEx( + HKEY_CURRENT_USER, // handle of open key + szModelKey, // address of name of subkey to open + 0ul, // DWORD ulOptions, // reserved + NULL, // Type of value + REG_OPTION_NON_VOLATILE, // Store permanently in reg. + KEY_ALL_ACCESS, // REGSAM samDesired, // security access mask + NULL, + &m_hKey, // Key we are creating + &dwDisposition ); // Type of creation + + if ( lResult != ERROR_SUCCESS ) + { + m_bValid = false; + return false; + } + + // Success + m_bValid = true; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Open default launcher key based on game directory +//----------------------------------------------------------------------------- +bool CRegistry::Init( const char *platformName ) +{ + char subDir[ 512 ]; + wsprintf( subDir, "%s\\Settings", platformName ); + return DirectInit( subDir ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRegistry::Shutdown( void ) +{ + if ( !m_bValid ) + return; + + // Make invalid + m_bValid = false; + VCRHook_RegCloseKey( m_hKey ); +} + +#else + + + + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRegistry::CRegistry( void ) +{ + // Assume failure + m_bValid = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRegistry::~CRegistry( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Read integer from registry +// Input : *key - +// defaultValue - +// Output : int +//----------------------------------------------------------------------------- +int CRegistry::ReadInt( const char *key, int defaultValue /*= 0*/ ) +{ + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Save integer to registry +// Input : *key - +// value - +//----------------------------------------------------------------------------- +void CRegistry::WriteInt( const char *key, int value ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Read string value from registry +// Input : *key - +// *defaultValue - +// Output : const char +//----------------------------------------------------------------------------- +const char *CRegistry::ReadString( const char *key, const char *defaultValue /* = NULL */ ) +{ + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Save string to registry +// Input : *key - +// *value - +//----------------------------------------------------------------------------- +void CRegistry::WriteString( const char *key, const char *value ) +{ +} + + + +bool CRegistry::DirectInit( const char *subDirectoryUnderValve ) +{ + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Open default launcher key based on game directory +//----------------------------------------------------------------------------- +bool CRegistry::Init( const char *platformName ) +{ + char subDir[ 512 ]; + snprintf( subDir, sizeof(subDir), "%s\\Settings", platformName ); + return DirectInit( subDir ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRegistry::Shutdown( void ) +{ + if ( !m_bValid ) + return; + + // Make invalid + m_bValid = false; +} +#endif // POSIX + diff --git a/public/renamed_recvtable_compat.cpp b/public/renamed_recvtable_compat.cpp new file mode 100644 index 0000000..6e5e08d --- /dev/null +++ b/public/renamed_recvtable_compat.cpp @@ -0,0 +1,12 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "renamed_recvtable_compat.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CRenamedRecvTableInfo *g_pRenamedRecvTableInfoHead = 0; + + diff --git a/public/renamed_recvtable_compat.h b/public/renamed_recvtable_compat.h new file mode 100644 index 0000000..63d2374 --- /dev/null +++ b/public/renamed_recvtable_compat.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// +#if !defined( RENAMED_RECVTABLE_COMPAT_H ) +#define RENAMED_RECVTABLE_COMPAT_H +#ifdef _WIN32 +#pragma once +#endif + +class CRenamedRecvTableInfo; + +extern CRenamedRecvTableInfo *g_pRenamedRecvTableInfoHead; + +//----------------------------------------------------------------------------- +// Purpose: Used by NOTE_RENAMED_RECVTABLE() macro. +//----------------------------------------------------------------------------- +class CRenamedRecvTableInfo +{ +public: + CRenamedRecvTableInfo( const char *pOldName, const char *pNewName ) + : m_pOldName( pOldName ), + m_pNewName( pNewName ) + { + m_pNext = g_pRenamedRecvTableInfoHead; + g_pRenamedRecvTableInfoHead = this; + } + +public: + const char *m_pOldName; + const char *m_pNewName; + CRenamedRecvTableInfo *m_pNext; +}; + +//----------------------------------------------------------------------------- +// Purpose: To keep from breaking older demos, use this macro to allow the +// engine to find the new datatable from the old name. +//----------------------------------------------------------------------------- +#define NOTE_RENAMED_RECVTABLE( oldname_, newname_ ) \ + static CRenamedRecvTableInfo g_##oldname_##Register( \ + #oldname_, \ + #newname_ \ + ); + + +#endif // RENAMED_RECVTABLE_COMPAT_H diff --git a/public/renderparm.h b/public/renderparm.h new file mode 100644 index 0000000..a473c29 --- /dev/null +++ b/public/renderparm.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: defines constants to use for the materialsystem and shaderapi +// SetxxxRenderingParameter functions +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef RENDERPARM_H +#define RENDERPARM_H + +#ifndef _WIN32 +#pragma once +#endif + + +enum RenderParamVector_t +{ + VECTOR_RENDERPARM_HMDWARP_LEFT_CENTRE = 0, + VECTOR_RENDERPARM_HMDWARP_LEFT_COEFF012, + VECTOR_RENDERPARM_HMDWARP_LEFT_COEFF34_RED_OFFSET, + VECTOR_RENDERPARM_HMDWARP_RIGHT_CENTRE, + VECTOR_RENDERPARM_HMDWARP_RIGHT_COEFF012, + VECTOR_RENDERPARM_HMDWARP_RIGHT_COEFF34_BLUE_OFFSET, + VECTOR_RENDERPARM_HMDWARP_GROW_OUTIN, + VECTOR_RENDERPARM_HMDWARP_GROW_ABOVEBELOW, + VECTOR_RENDERPARM_HMDWARP_ASPECT, + INT_RENDERPARM_DISTORTION_TYPE, + + MAX_VECTOR_RENDER_PARMS = 20 +}; + + +#define MAX_FLOAT_RENDER_PARMS 20 + +enum RenderParamInt_t +{ + INT_RENDERPARM_ENABLE_FIXED_LIGHTING = 0, + INT_RENDERPARM_MORPH_ACCUMULATOR_X_OFFSET, + INT_RENDERPARM_MORPH_ACCUMULATOR_Y_OFFSET, + INT_RENDERPARM_MORPH_ACCUMULATOR_SUBRECT_WIDTH, + INT_RENDERPARM_MORPH_ACCUMULATOR_SUBRECT_HEIGHT, + INT_RENDERPARM_MORPH_ACCUMULATOR_4TUPLE_COUNT, + + INT_RENDERPARM_MORPH_WEIGHT_X_OFFSET, + INT_RENDERPARM_MORPH_WEIGHT_Y_OFFSET, + INT_RENDERPARM_MORPH_WEIGHT_SUBRECT_WIDTH, + INT_RENDERPARM_MORPH_WEIGHT_SUBRECT_HEIGHT, + + INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, + + INT_RENDERPARM_BACK_BUFFER_INDEX, + + MAX_INT_RENDER_PARMS = 20 +}; + +// for INT_RENDERPARM_BACK_BUFFER_INDEX +#define BACK_BUFFER_INDEX_DEFAULT 0 +#define BACK_BUFFER_INDEX_HDR 1 + +enum RenderParamTexture_t +{ + TEXTURE_RENDERPARM_AMBIENT_OCCLUSION = 0, + + MAX_TEXTURE_RENDER_PARMS = 2 +}; + +// ENABLE_FIXED_LIGHTING modes: +#define ENABLE_FIXED_LIGHTING_NONE 0 +#define ENABLE_FIXED_LIGHTING_BASICLIGHT 1 +#define ENABLE_FIXED_LIGHTING_OUTPUTMRTS_FOR_DEFERRED_LIGHTING 2 +#define ENABLE_FIXED_LIGHTING_OUTPUTNORMAL_AND_DEPTH 3 + +#endif // RENDERPARM_H diff --git a/public/rope_physics.cpp b/public/rope_physics.cpp new file mode 100644 index 0000000..82669dc --- /dev/null +++ b/public/rope_physics.cpp @@ -0,0 +1,152 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + + +#include "rope_physics.h" +#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CBaseRopePhysics::CBaseRopePhysics( CSimplePhysics::CNode *pNodes, int nNodes, CRopeSpring *pSprings, float *flSpringDistsSqr ) +{ + m_pNodes = pNodes; + m_pSprings = pSprings; + m_flNodeSpringDistsSqr = flSpringDistsSqr; + m_flSpringDist = m_flSpringDistSqr = 1; + Restart(); + + // Initialize the nodes. + for ( int i=0; i < nNodes; i++ ) + { + pNodes[i].m_vPos.Init(); + pNodes[i].m_vPrevPos.Init(); + pNodes[i].m_vPredicted.Init(); + } + + SetNumNodes( nNodes ); + + m_pDelegate = NULL; +} + + +void CBaseRopePhysics::SetNumNodes( int nNodes ) +{ + m_nNodes = nNodes; + + // Setup the springs. + for( int i=0; i < NumSprings(); i++ ) + { + m_pSprings[i].m_pNode1 = &m_pNodes[i].m_vPos; + m_pSprings[i].m_pNode2 = &m_pNodes[i+1].m_vPos; + Assert( m_pSprings[i].m_pNode1->IsValid() ); + Assert( m_pSprings[i].m_pNode2->IsValid() ); + + m_flNodeSpringDistsSqr[i] = m_flSpringDistSqr / NumSprings(); + } +} + + +void CBaseRopePhysics::Restart() +{ + m_Physics.Init( 1.0 / 50 ); +} + + +void CBaseRopePhysics::ResetSpringLength( float flSpringDist ) +{ + m_flSpringDist = vmax( flSpringDist, 0 ); + m_flSpringDistSqr = m_flSpringDist * m_flSpringDist; + + for( int i=0; i < NumSprings(); i++ ) + { + m_flNodeSpringDistsSqr[i] = m_flSpringDistSqr / NumSprings(); + } +} + +float CBaseRopePhysics::GetSpringLength() const +{ + return m_flSpringDist; +} + +void CBaseRopePhysics::ResetNodeSpringLength( int iStartNode, float flSpringDist ) +{ + m_flNodeSpringDistsSqr[iStartNode] = flSpringDist * flSpringDist; +} + +void CBaseRopePhysics::SetupSimulation( float flSpringDist, CSimplePhysics::IHelper *pDelegate ) +{ + ResetSpringLength( flSpringDist ); + SetDelegate( pDelegate ); +} + + +void CBaseRopePhysics::SetDelegate( CSimplePhysics::IHelper *pDelegate ) +{ + m_pDelegate = pDelegate; +} + + +void CBaseRopePhysics::Simulate( float dt ) +{ + static float flEnergy = 0.98; + m_Physics.Simulate( m_pNodes, m_nNodes, this, dt, flEnergy ); +} + + +void CBaseRopePhysics::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ) +{ + if( m_pDelegate ) + m_pDelegate->GetNodeForces( pNodes, iNode, pAccel ); + else + pAccel->Init( 0, 0, 0 ); +} + + +void CBaseRopePhysics::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ) +{ + // Handle springs.. + // + // Iterate multiple times here. If we don't, then gravity tends to + // win over the constraint solver and it's impossible to get straight ropes. + static int nIterations = 3; + for( int iIteration=0; iIteration < nIterations; iIteration++ ) + { + for( int i=0; i < NumSprings(); i++ ) + { + CRopeSpring *s = &m_pSprings[i]; + + Vector vTo = *s->m_pNode1 - *s->m_pNode2; + + float flDistSqr = vTo.LengthSqr(); + + // If we don't have an overall spring distance, see if we have a per-node one + float flSpringDist = m_flSpringDistSqr; + if ( !flSpringDist ) + { + // TODO: This still isn't enough. Ropes with different spring lengths + // per-node will oscillate forever. + flSpringDist = m_flNodeSpringDistsSqr[i]; + } + + if( flDistSqr > flSpringDist ) + { + float flDist = (float)sqrt( flDistSqr ); + vTo *= 1 - (m_flSpringDist / flDist); + + *s->m_pNode1 -= vTo * 0.5f; + *s->m_pNode2 += vTo * 0.5f; + } + } + + if( m_pDelegate ) + m_pDelegate->ApplyConstraints( pNodes, nNodes ); + } +} + + diff --git a/public/rope_physics.h b/public/rope_physics.h new file mode 100644 index 0000000..68f6a5d --- /dev/null +++ b/public/rope_physics.h @@ -0,0 +1,117 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ROPE_PHYSICS_H +#define ROPE_PHYSICS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "simple_physics.h" +#include "networkvar.h" + + +class CRopeSpring +{ +public: + Vector *m_pNode1; + Vector *m_pNode2; +}; + + +class CBaseRopePhysics : public CSimplePhysics::IHelper +{ +public: + DECLARE_CLASS_NOBASE( CBaseRopePhysics ); + + CBaseRopePhysics( + CSimplePhysics::CNode *pNodes, + int nNodes, + CRopeSpring *pSprings, + float *flSpringDistsSqr ); + + // nNodes should be less than or equal to what you passed into the constructor. + void SetNumNodes( int nNodes ); + + // Restart timers and such. + void Restart(); + + void ResetSpringLength(float flSpringDist ); + float GetSpringLength() const; + void ResetNodeSpringLength( int iStartNode, float flSpringDist ); + + // Set simulation parameters. + // If you pass in a delegate, you can be called to apply constraints. + void SetupSimulation( float flSpringDist, CSimplePhysics::IHelper *pDelegate=0 ); + + // Set the physics delegate. + void SetDelegate( CSimplePhysics::IHelper *pDelegate ); + + void Simulate( float dt ); + + int NumNodes() { return m_nNodes; } + CSimplePhysics::CNode* GetNode( int iNode ) { return &m_pNodes[iNode]; } + CSimplePhysics::CNode* GetFirstNode() { return &m_pNodes[0]; } + CSimplePhysics::CNode* GetLastNode() { return &m_pNodes[ m_nNodes-1 ]; } + + + +public: + + virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ); + virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ); + + +private: + + int NumSprings() {return m_nNodes - 1;} + + +protected: + + CSimplePhysics::IHelper *m_pDelegate; + + CSimplePhysics::CNode *m_pNodes; + int m_nNodes; + + CRopeSpring *m_pSprings; + + float m_flSpringDist; + float m_flSpringDistSqr; + + // Spring lengths per node + float *m_flNodeSpringDistsSqr; + + CSimplePhysics m_Physics; +}; + + + + + +template< int NUM_NODES > +class CRopePhysics : public CBaseRopePhysics +{ +public: + + CRopePhysics(); + + CSimplePhysics::CNode m_Nodes[NUM_NODES]; + CRopeSpring m_Springs[NUM_NODES - 1]; + float m_SpringDistsSqr[NUM_NODES - 1]; +}; + + +template< int NUM_NODES > +CRopePhysics::CRopePhysics() : + CBaseRopePhysics( m_Nodes, NUM_NODES, m_Springs, m_SpringDistsSqr ) +{ +} + + +#endif // ROPE_PHYSICS_H diff --git a/public/rope_shared.h b/public/rope_shared.h new file mode 100644 index 0000000..54c2882 --- /dev/null +++ b/public/rope_shared.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ROPE_SHARED_H +#define ROPE_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +// Shared definitions for rope. +#define ROPE_MAX_SEGMENTS 10 +#define ROPE_TYPE1_NUMSEGMENTS 4 +#define ROPE_TYPE2_NUMSEGMENTS 2 + +// Default rope gravity vector. +#define ROPE_GRAVITY 0, 0, -1500 + + +// Rope flags. +#define ROPE_RESIZE (1<<0) // Try to keep the rope dangling the same amount + // even as the rope length changes. +#define ROPE_BARBED (1<<1) // Hack option to draw like a barbed wire. +#define ROPE_COLLIDE (1<<2) // Collide with the world? +#define ROPE_SIMULATE (1<<3) // Is the rope valid? +#define ROPE_BREAKABLE (1<<4) // Can the endpoints detach? +#define ROPE_NO_WIND (1<<5) // No wind simulation on this rope. +#define ROPE_INITIAL_HANG (1<<6) // By default, ropes will simulate for a bit internally when they + // are created so they sag, but dynamically created ropes for things + // like harpoons don't want this. +#define ROPE_PLAYER_WPN_ATTACH (1<<7) // If this flag is set, then the second attachment must be a player. + // The rope will attach to "buff_attach" on the player's active weapon. + // (This is a flag because it requires special code on the client to + // find the weapon). +#define ROPE_NO_GRAVITY (1<<8) // Disable gravity on this rope. +#define ROPE_NUMFLAGS 9 + + +// This is added to all rope slacks so when a level designer enters a +// slack of zero in the entity, it doesn't dangle so low. +#define ROPESLACK_FUDGEFACTOR -100 + + +// Rope shader IDs. +#define ROPESHADER_BLACKCABLE 0 +#define ROPESHADER_ROPE 1 +#define ROPESHADER_CHAIN 2 + + +// Rope locked points +enum +{ + ROPE_LOCK_START_POINT = 0x1, + ROPE_LOCK_END_POINT = 0x2, + ROPE_LOCK_START_DIRECTION = 0x4, + ROPE_LOCK_END_DIRECTION = 0x8, +}; + + +// Rope attachment points. +#define ROPE_ATTACHMENT_START_POINT 1 +#define ROPE_ATTACHMENT_END_POINT 2 + + +#endif // ROPE_SHARED_H diff --git a/public/savegame_version.h b/public/savegame_version.h new file mode 100644 index 0000000..44253dc --- /dev/null +++ b/public/savegame_version.h @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( SAVEGAME_VERSION_H ) +#define SAVEGAME_VERSION_H +#ifdef _WIN32 +#pragma once +#endif + +#define SAVEGAME_VERSION 0x0073 // Version 0.73 + +#endif // SAVEGAME_VERSION_H diff --git a/public/saverestoretypes.h b/public/saverestoretypes.h new file mode 100644 index 0000000..7868e2f --- /dev/null +++ b/public/saverestoretypes.h @@ -0,0 +1,547 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// @Note (toml 12-02-02): For now, all of the methods in the types defined here +// are inline to permit simple cross-DLL usage +//=============================================================================// + +#ifndef SAVERESTORETYPES_H +#define SAVERESTORETYPES_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1/utlhash.h" + +#include // NULL_STRING define +struct edict_t; + + +#ifdef EHANDLE_H // not available to engine +#define SR_ENTS_VISIBLE 1 +#endif + + +//----------------------------------------------------------------------------- +// +// class CSaveRestoreSegment +// + +class CSaveRestoreSegment +{ +public: + CSaveRestoreSegment(); + + //--------------------------------- + // Buffer operations + // + void Init( void *pNewBase, int nBytes ); + void Rebase(); + void Rewind( int nBytes ); + char *GetBuffer(); + int BytesAvailable() const; + int SizeBuffer() const; + bool Write( const void *pData, int nBytes ); + bool Read( void *pOutput, int nBytes ); + int GetCurPos(); + char *AccessCurPos(); + bool Seek( int absPosition ); + void MoveCurPos( int nBytes ); + + //--------------------------------- + // Symbol table operations + // + void InitSymbolTable( char **pNewTokens, int sizeTable); + char **DetachSymbolTable(); + int SizeSymbolTable(); + bool DefineSymbol( const char *pszToken, int token ); + unsigned short FindCreateSymbol( const char *pszToken ); + const char *StringFromSymbol( int token ); + +private: +#ifndef _WIN32 + unsigned _rotr ( unsigned val, int shift); +#endif + unsigned int HashString( const char *pszToken ); + + //--------------------------------- + // Buffer data + // + char *pBaseData; // Start of all entity save data + char *pCurrentData; // Current buffer pointer for sequential access + int size; // Current data size, aka, pCurrentData - pBaseData + int bufferSize; // Total space for data + + //--------------------------------- + // Symbol table + // + int tokenCount; // Number of elements in the pTokens table + char **pTokens; // Hash table of entity strings (sparse) +}; + + +//----------------------------------------------------------------------------- +// +// class CGameSaveRestoreInfo +// + +struct levellist_t +{ + DECLARE_SIMPLE_DATADESC(); + + char mapName[ MAX_MAP_NAME_SAVE ]; + char landmarkName[ 32 ]; + edict_t *pentLandmark; + Vector vecLandmarkOrigin; +}; + +#define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of entitytable_t->flags + +//------------------------------------- + +struct EHandlePlaceholder_t // Engine does some of the game writing (alas, probably shouldn't), but can't see ehandle.h +{ + unsigned long i; +}; + +//------------------------------------- + +struct entitytable_t +{ + void Clear() + { + id = -1; + edictindex = -1; + saveentityindex = -1; + restoreentityindex = -1; + location = 0; + size = 0; + flags = 0; + classname = NULL_STRING; + globalname = NULL_STRING; + landmarkModelSpace.Init(); + modelname = NULL_STRING; + } + + int id; // Ordinal ID of this entity (used for entity <--> pointer conversions) + int edictindex; // saved for if the entity requires a certain edict number when restored (players, world) + + int saveentityindex; // the entity index the entity had at save time ( for fixing up client side entities ) + int restoreentityindex; // the entity index given to this entity at restore time + +#ifdef SR_ENTS_VISIBLE + EHANDLE hEnt; // Pointer to the in-game entity +#else + EHandlePlaceholder_t hEnt; +#endif + + int location; // Offset from the base data of this entity + int size; // Byte size of this entity's data + int flags; // This could be a short -- bit mask of transitions that this entity is in the PVS of + string_t classname; // entity class name + string_t globalname; // entity global name + Vector landmarkModelSpace; // a fixed position in model space for comparison + // NOTE: Brush models can be built in different coordiante systems + // in different levels, so this fixes up local quantities to match + // those differences. + string_t modelname; + + DECLARE_SIMPLE_DATADESC(); +}; + +#define FENTTABLE_PLAYER 0x80000000 +#define FENTTABLE_REMOVED 0x40000000 +#define FENTTABLE_MOVEABLE 0x20000000 +#define FENTTABLE_GLOBAL 0x10000000 +#define FENTTABLE_PLAYERCHILD 0x08000000 // this entity is connected to a player, so it must be spawned with it +#define FENTTABLE_LEVELMASK 0x0000FFFF // reserve bits for 16 level connections +//------------------------------------- + +struct saverestorelevelinfo_t +{ + int connectionCount;// Number of elements in the levelList[] + levellist_t levelList[ MAX_LEVEL_CONNECTIONS ]; // List of connections from this level + + // smooth transition + int fUseLandmark; + char szLandmarkName[20]; // landmark we'll spawn near in next level + Vector vecLandmarkOffset; // for landmark transitions + float time; + char szCurrentMapName[MAX_MAP_NAME_SAVE]; // To check global entities + int mapVersion; +}; + +//------------------------------------- + +class CGameSaveRestoreInfo +{ +public: + CGameSaveRestoreInfo() + : tableCount( 0 ), pTable( 0 ), m_pCurrentEntity( 0 ), m_EntityToIndex( 1024 ) + { + memset( &levelInfo, 0, sizeof( levelInfo ) ); + modelSpaceOffset.Init( 0, 0, 0 ); + } + + void InitEntityTable( entitytable_t *pNewTable = NULL, int size = 0 ) + { + pTable = pNewTable; + tableCount = size; + + for ( int i = 0; i < NumEntities(); i++ ) + { + GetEntityInfo( i )->Clear(); + } + } + + entitytable_t *DetachEntityTable() + { + entitytable_t *pReturn = pTable; + pTable = NULL; + tableCount = 0; + return pReturn; + } + + CBaseEntity *GetCurrentEntityContext() { return m_pCurrentEntity; } + void SetCurrentEntityContext(CBaseEntity *pEntity) { m_pCurrentEntity = pEntity; } + + int NumEntities() { return tableCount; } + entitytable_t *GetEntityInfo( int i ) { return (pTable + i); } + float GetBaseTime() const { return levelInfo.time; } + Vector GetLandmark() const { return ( levelInfo.fUseLandmark ) ? levelInfo.vecLandmarkOffset : vec3_origin; } + + void BuildEntityHash() + { +#ifdef GAME_DLL + int i; + entitytable_t *pTable; + int nEntities = NumEntities(); + + for ( i = 0; i < nEntities; i++ ) + { + pTable = GetEntityInfo( i ); + m_EntityToIndex.Insert( CHashElement( pTable->hEnt.Get(), i ) ); + } +#endif + } + + void PurgeEntityHash() + { + m_EntityToIndex.Purge(); + } + + int GetEntityIndex( const CBaseEntity *pEntity ) + { +#ifdef SR_ENTS_VISIBLE + if ( pEntity ) + { + if ( m_EntityToIndex.Count() ) + { + UtlHashHandle_t hElement = m_EntityToIndex.Find( CHashElement( pEntity ) ); + if ( hElement != m_EntityToIndex.InvalidHandle() ) + { + return m_EntityToIndex.Element( hElement ).index; + } + } + else + { + int i; + entitytable_t *pTable; + + int nEntities = NumEntities(); + for ( i = 0; i < nEntities; i++ ) + { + pTable = GetEntityInfo( i ); + if ( pTable->hEnt == pEntity ) + return pTable->id; + } + } + } +#endif + return -1; + } + + saverestorelevelinfo_t levelInfo; + Vector modelSpaceOffset; // used only for globaly entity brushes modelled in different coordinate systems. + +private: + int tableCount; // Number of elements in the entity table + entitytable_t *pTable; // Array of entitytable_t elements (1 for each entity) + CBaseEntity *m_pCurrentEntity; // only valid during the save functions of this entity, NULL otherwise + + + struct CHashElement + { + const CBaseEntity *pEntity; + int index; + + CHashElement( const CBaseEntity *pEntity, int index) : pEntity(pEntity), index(index) {} + CHashElement( const CBaseEntity *pEntity ) : pEntity(pEntity) {} + CHashElement() {} + }; + + class CHashFuncs + { + public: + CHashFuncs( int ) {} + + // COMPARE + bool operator()( const CHashElement &lhs, const CHashElement &rhs ) const + { + return lhs.pEntity == rhs.pEntity; + } + + // HASH + unsigned int operator()( const CHashElement &item ) const + { + return HashItem( item.pEntity ); + } + }; + + typedef CUtlHash CEntityToIndexHash; + + CEntityToIndexHash m_EntityToIndex; +}; + +//----------------------------------------------------------------------------- + + +class CSaveRestoreData : public CSaveRestoreSegment, + public CGameSaveRestoreInfo +{ +public: + CSaveRestoreData() : bAsync( false ) {} + + + bool bAsync; +}; + +inline CSaveRestoreData *MakeSaveRestoreData( void *pMemory ) +{ + return new (pMemory) CSaveRestoreData; +} + +//----------------------------------------------------------------------------- +// +// class CSaveRestoreSegment, inline functions +// + +inline CSaveRestoreSegment::CSaveRestoreSegment() +{ + memset( this, 0, sizeof(*this) ); +} + +inline void CSaveRestoreSegment::Init( void *pNewBase, int nBytes ) +{ + pCurrentData = pBaseData = (char *)pNewBase; + size = 0; + bufferSize = nBytes; +} + +inline void CSaveRestoreSegment::MoveCurPos( int nBytes ) +{ + pCurrentData += nBytes; + size += nBytes; +} + +inline void CSaveRestoreSegment::Rebase() +{ + pBaseData = pCurrentData; + bufferSize -= size; + size = 0; +} + +inline void CSaveRestoreSegment::Rewind( int nBytes ) +{ + if ( size < nBytes ) + nBytes = size; + + MoveCurPos( -nBytes ); +} + +inline char *CSaveRestoreSegment::GetBuffer() +{ + return pBaseData; +} + +inline int CSaveRestoreSegment::BytesAvailable() const +{ + return (bufferSize - size); +} + +inline int CSaveRestoreSegment::SizeBuffer() const +{ + return bufferSize; +} + +inline bool CSaveRestoreSegment::Write( const void *pData, int nBytes ) +{ + if ( nBytes > BytesAvailable() ) + { + size = bufferSize; + return false; + } + + memcpy( pCurrentData, pData, nBytes ); + MoveCurPos( nBytes ); + + return true; +} + +inline bool CSaveRestoreSegment::Read( void *pOutput, int nBytes ) +{ + if ( !BytesAvailable() ) + return false; + + if ( nBytes > BytesAvailable() ) + { + size = bufferSize; + return false; + } + + if ( pOutput ) + memcpy( pOutput, pCurrentData, nBytes ); + MoveCurPos( nBytes ); + return true; +} + +inline int CSaveRestoreSegment::GetCurPos() +{ + return size; +} + +inline char *CSaveRestoreSegment::AccessCurPos() +{ + return pCurrentData; +} + +inline bool CSaveRestoreSegment::Seek( int absPosition ) +{ + if ( absPosition < 0 || absPosition >= bufferSize ) + return false; + + size = absPosition; + pCurrentData = pBaseData + size; + return true; +} + +inline void CSaveRestoreSegment::InitSymbolTable( char **pNewTokens, int sizeTable) +{ + Assert( !pTokens ); + tokenCount = sizeTable; + pTokens = pNewTokens; + memset( pTokens, 0, sizeTable * sizeof( pTokens[0]) ); +} + +inline char **CSaveRestoreSegment::DetachSymbolTable() +{ + char **pResult = pTokens; + tokenCount = 0; + pTokens = NULL; + return pResult; +} + +inline int CSaveRestoreSegment::SizeSymbolTable() +{ + return tokenCount; +} + +inline bool CSaveRestoreSegment::DefineSymbol( const char *pszToken, int token ) +{ + if ( pTokens[token] == NULL ) + { + pTokens[token] = (char *)pszToken; + return true; + } + Assert( 0 ); + return false; +} + +inline unsigned short CSaveRestoreSegment::FindCreateSymbol( const char *pszToken ) +{ + unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)tokenCount ); + +#if _DEBUG + static int tokensparsed = 0; + tokensparsed++; + if ( !tokenCount || !pTokens ) + { + AssertMsg( 0, ("No token table array in TokenHash()!") ); + } +#endif + + for ( int i=0; i 50 && !beentheredonethat ) + { + beentheredonethat = true; + AssertMsg( 0, ("CSaveRestoreBuffer::TokenHash() is getting too full!" ) ); + } +#endif + + int index = hash + i; + if ( index >= tokenCount ) + index -= tokenCount; + + if ( !pTokens[index] || strcmp( pszToken, pTokens[index] ) == 0 ) + { + pTokens[index] = (char *)pszToken; + return index; + } + } + + // Token hash table full!!! + // [Consider doing overflow table(s) after the main table & limiting linear hash table search] + Warning( "CSaveRestoreBuffer::TokenHash() is COMPLETELY FULL!" ); + Assert( 0 ); + return 0; +} + +inline const char *CSaveRestoreSegment::StringFromSymbol( int token ) +{ + if ( token >= 0 && token < tokenCount ) + return pTokens[token]; + Assert( 0 ); + return "<>"; +} + +#ifndef _WIN32 +inline unsigned CSaveRestoreSegment::_rotr ( unsigned val, int shift) +{ + unsigned lobit; /* non-zero means lo bit set */ + unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while (shift--) + { + lobit = num & 1; /* get high bit */ + num >>= 1; /* shift right one bit */ + if (lobit) + num |= 0x80000000; /* set hi bit if lo bit was set */ + } + + return num; +} +#endif + +inline unsigned int CSaveRestoreSegment::HashString( const char *pszToken ) +{ + unsigned int hash = 0; + + while ( *pszToken ) + hash = _rotr( hash, 4 ) ^ *pszToken++; + + return hash; +} + +//============================================================================= + +#endif // SAVERESTORETYPES_H diff --git a/public/scenefilecache/ISceneFileCache.h b/public/scenefilecache/ISceneFileCache.h new file mode 100644 index 0000000..973c6ef --- /dev/null +++ b/public/scenefilecache/ISceneFileCache.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ISCENEFILECACHE_H +#define ISCENEFILECACHE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "appframework/IAppSystem.h" + +// the file cache can support persisting some calcs +struct SceneCachedData_t +{ + unsigned int msecs; + int numSounds; + int sceneId; +}; + +class ISceneFileCache : public IAppSystem +{ +public: + + // async implemenation + virtual size_t GetSceneBufferSize( char const *filename ) = 0; + virtual bool GetSceneData( char const *filename, byte *buf, size_t bufsize ) = 0; + + // persisted scene data, returns true if valid, false otherwise + virtual bool GetSceneCachedData( char const *pFilename, SceneCachedData_t *pData ) = 0; + virtual short GetSceneCachedSound( int iScene, int iSound ) = 0; + virtual const char *GetSceneString( short stringId ) = 0; + + // Physically reloads image from disk + virtual void Reload() = 0; +}; + +#define SCENE_FILE_CACHE_INTERFACE_VERSION "SceneFileCache002" + +#endif // ISCENEFILECACHE_H diff --git a/public/scenefilecache/SceneImageFile.h b/public/scenefilecache/SceneImageFile.h new file mode 100644 index 0000000..26cce48 --- /dev/null +++ b/public/scenefilecache/SceneImageFile.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A Scene Image file aggregates all the compiled binary VCD files into +// a single file. +// +//=====================================================================================// +#ifndef SCENE_IMAGE_FILE_H +#define SCENE_IMAGE_FILE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "commonmacros.h" +#include "tier1/checksum_crc.h" + +#define SCENE_IMAGE_ID MAKEID( 'V','S','I','F' ) +#define SCENE_IMAGE_VERSION 2 + +// scene summary: cached calcs for commmon startup queries, variable sized +struct SceneImageSummary_t +{ + unsigned int msecs; + int numSounds; + int soundStrings[1]; // has numSounds +}; + +// stored sorted by crc filename for binary search +struct SceneImageEntry_t +{ + CRC32_t crcFilename; // expected to be normalized as scenes\???.vcd + int nDataOffset; // offset to dword aligned data from start + int nDataLength; + int nSceneSummaryOffset; // offset to summary +}; + +struct SceneImageHeader_t +{ + int nId; + int nVersion; + int nNumScenes; // number of scene files + int nNumStrings; // number of unique strings in table + int nSceneEntryOffset; + + inline const char *String( short iString ) + { + if ( iString < 0 || iString >= nNumStrings ) + { + Assert( 0 ); + return NULL; + } + + // access string table (after header) to access pool + unsigned int *pTable = (unsigned int *)((byte *)this + sizeof( SceneImageHeader_t )); + return (char *)this + pTable[iString]; + } +}; + +#endif // SCENE_IMAGE_FILE_H diff --git a/public/scratchpad3d.cpp b/public/scratchpad3d.cpp new file mode 100644 index 0000000..96db217 --- /dev/null +++ b/public/scratchpad3d.cpp @@ -0,0 +1,635 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include +#include "scratchpad3d.h" +#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifndef POSIX +// NOTE - linux doesn't need any of this code! + +extern "C" +{ + extern void __stdcall Sleep( unsigned long ms ); +}; + + +class CFileRead +{ +public: + CFileRead( IFileSystem* pFileSystem, FileHandle_t fp ) + { + m_pFileSystem = pFileSystem; + m_fp = fp; + m_Pos = 0; + } + + bool Read( void *pDest, int len ) + { + int count = m_pFileSystem->Read( pDest, len, m_fp ); + m_Pos += count; + return count == len; + } + + IFileSystem* m_pFileSystem; + FileHandle_t m_fp; + int m_Pos; +}; + + +// ------------------------------------------------------------------------ // +// CCommand_Point. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::CCommand_Point::Read( CFileRead *pFile ) +{ + pFile->Read( &m_flPointSize, sizeof(m_flPointSize) ); + pFile->Read( &m_Vert, sizeof(m_Vert) ); +} + +void CScratchPad3D::CCommand_Point::Write( IFileSystem* pFileSystem, FileHandle_t fp ) +{ + pFileSystem->Write( &m_flPointSize, sizeof(m_flPointSize), fp ); + pFileSystem->Write( &m_Vert, sizeof(m_Vert), fp ); +} + + +// ------------------------------------------------------------------------ // +// CCommand_Line. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::CCommand_Line::Read( CFileRead *pFile ) +{ + pFile->Read( m_Verts, sizeof(m_Verts) ); +} + +void CScratchPad3D::CCommand_Line::Write( IFileSystem* pFileSystem, FileHandle_t fp ) +{ + pFileSystem->Write( m_Verts, sizeof(m_Verts), fp ); +} + + +// ------------------------------------------------------------------------ // +// CCommand_Polygon. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::CCommand_Polygon::Read( CFileRead *pFile ) +{ + int count; + pFile->Read( &count, sizeof(count) ); + m_Verts.RemoveAll(); + m_Verts.AddMultipleToTail( count ); + + if( count ) + pFile->Read( &m_Verts[0], sizeof(CSPVert)*count ); +} + +void CScratchPad3D::CCommand_Polygon::Write( IFileSystem* pFileSystem, FileHandle_t fp ) +{ + int count = m_Verts.Size(); + pFileSystem->Write( &count, sizeof(count), fp ); + + if( count ) + pFileSystem->Write( &m_Verts[0], sizeof(CSPVert)*count, fp ); +} + + +// ------------------------------------------------------------------------ // +// CCommand_Matrix. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::CCommand_Matrix::Read( CFileRead *pFile ) +{ + pFile->Read( &m_mMatrix, sizeof(m_mMatrix) ); +} + +void CScratchPad3D::CCommand_Matrix::Write( IFileSystem* pFileSystem, FileHandle_t fp ) +{ + pFileSystem->Write( &m_mMatrix, sizeof(m_mMatrix), fp ); +} + + +// ------------------------------------------------------------------------ // +// CCommand_RenderState. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::CCommand_RenderState::Read( CFileRead *pFile ) +{ + pFile->Read( &m_State, sizeof(m_State) ); + pFile->Read( &m_Val, sizeof(m_Val) ); +} + +void CScratchPad3D::CCommand_RenderState::Write( IFileSystem* pFileSystem, FileHandle_t fp ) +{ + pFileSystem->Write( &m_State, sizeof(m_State), fp ); + pFileSystem->Write( &m_Val, sizeof(m_Val), fp ); +} + + +// ------------------------------------------------------------------------ // +// CCommand_Text. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::CCommand_Text::Read( CFileRead *pFile ) +{ + int strLen; + pFile->Read( &strLen, sizeof( strLen ) ); + m_String.SetSize( strLen ); + pFile->Read( m_String.Base(), strLen ); + + pFile->Read( &m_TextParams, sizeof( m_TextParams ) ); +} + + +void CScratchPad3D::CCommand_Text::Write( IFileSystem* pFileSystem, FileHandle_t fp ) +{ + int strLen = m_String.Count(); + pFileSystem->Write( &strLen, sizeof( strLen ), fp ); + pFileSystem->Write( m_String.Base(), strLen, fp ); + + pFileSystem->Write( &m_TextParams, sizeof( m_TextParams ), fp ); +} + + +// ------------------------------------------------------------------------ // +// CScratchPad3D internals. +// ------------------------------------------------------------------------ // + +CScratchPad3D::CScratchPad3D( char const *pFilename, IFileSystem* pFileSystem, bool bAutoClear ) +{ + m_pFileSystem = pFileSystem; + m_pFilename = pFilename; + m_bAutoFlush = true; + + if( bAutoClear ) + Clear(); // Clear whatever is in the file.. +} + +void CScratchPad3D::AutoFlush() +{ + if( m_bAutoFlush ) + Flush(); +} + +void CScratchPad3D::DrawRectGeneric( int iPlane, int otherDim1, int otherDim2, float planeDist, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor ) +{ + Vector verts[4]; + + verts[0][iPlane] = verts[1][iPlane] = verts[2][iPlane] = verts[3][iPlane] = planeDist; + + verts[0][otherDim1] = vMin.x; + verts[0][otherDim2] = vMin.y; + + verts[1][otherDim1] = vMin.x; + verts[1][otherDim2] = vMax.y; + + verts[2][otherDim1] = vMax.x; + verts[2][otherDim2] = vMax.y; + + verts[3][otherDim1] = vMax.x; + verts[3][otherDim2] = vMin.y; + + DrawPolygon( CSPVertList(verts, 4, vColor) ); +} + +void CScratchPad3D::DeleteCommands() +{ + for( int i=0; i < m_Commands.Size(); i++ ) + delete m_Commands[i]; + + m_Commands.RemoveAll(); +} + +bool CScratchPad3D::LoadCommandsFromFile( ) +{ + DeleteCommands(); + + FileHandle_t fp = m_pFileSystem->Open( m_pFilename, "rb" ); + if( !fp ) + return false; + + long fileEndPos = m_pFileSystem->Size( fp ); + + CFileRead fileRead( m_pFileSystem, fp ); + while( fileRead.m_Pos != fileEndPos ) + { + unsigned char iCommand; + fileRead.Read( &iCommand, sizeof(iCommand) ); + + CBaseCommand *pCmd = NULL; + if( iCommand == COMMAND_POINT ) + pCmd = new CCommand_Point; + else if( iCommand == COMMAND_LINE ) + pCmd = new CCommand_Line; + else if( iCommand == COMMAND_POLYGON ) + pCmd = new CCommand_Polygon; + else if( iCommand == COMMAND_MATRIX ) + pCmd = new CCommand_Matrix; + else if( iCommand == COMMAND_RENDERSTATE ) + pCmd = new CCommand_RenderState; + else if ( iCommand == COMMAND_TEXT ) + pCmd = new CCommand_Text; + + if( !pCmd ) + { + Assert( !"LoadCommandsFromFile: invalid file" ); + m_pFileSystem->Close( fp ); + return false; + } + + pCmd->Read( &fileRead ); + m_Commands.AddToTail( pCmd ); + } + + m_pFileSystem->Close( fp ); + return true; +} + + +// ------------------------------------------------------------------------ // +// CScratchPad3D's IScratchPad3D implementation. +// ------------------------------------------------------------------------ // + +void CScratchPad3D::Release() +{ + Flush(); + delete this; +} + +void CScratchPad3D::SetMapping( + const Vector &vInputMin, + const Vector &vInputMax, + const Vector &vOutputMin, + const Vector &vOutputMax ) +{ + CCommand_Matrix *cmd = new CCommand_Matrix; + m_Commands.AddToTail( cmd ); + + Vector vDivisor(1,1,1); + for( int i=0; i < 3; i++ ) + vDivisor[i] = fabs(vInputMax[i] - vInputMin[i]) < 0.0001f ? 0.001f : (vInputMax[i] - vInputMin[i]); + + Vector vScale = (vOutputMax - vOutputMin) / vDivisor; + Vector vShift = -vInputMin * vScale + vOutputMin; + + cmd->m_mMatrix.Init( + vScale.x, 0, 0, vShift.x, + 0, vScale.y, 0, vShift.y, + 0, 0, vScale.z, vShift.z, + 0, 0, 0, 1 ); + + + AutoFlush(); +} + +bool CScratchPad3D::GetAutoFlush() +{ + return m_bAutoFlush; +} + +void CScratchPad3D::SetAutoFlush( bool bAutoFlush ) +{ + m_bAutoFlush = bAutoFlush; + if( m_bAutoFlush ) + Flush(); +} + +void CScratchPad3D::DrawPoint( CSPVert const &v, float flPointSize ) +{ + CCommand_Point *cmd = new CCommand_Point; + m_Commands.AddToTail( cmd ); + + cmd->m_Vert = v; + cmd->m_flPointSize = flPointSize; + + AutoFlush(); +} + +void CScratchPad3D::DrawLine( CSPVert const &v1, CSPVert const &v2 ) +{ + CCommand_Line *cmd = new CCommand_Line; + m_Commands.AddToTail( cmd ); + + cmd->m_Verts[0] = v1; + cmd->m_Verts[1] = v2; + + AutoFlush(); +} + +void CScratchPad3D::DrawPolygon( CSPVertList const &verts ) +{ + CCommand_Polygon *cmd = new CCommand_Polygon; + m_Commands.AddToTail( cmd ); + + cmd->m_Verts.AddVectorToTail( verts.m_Verts ); + + AutoFlush(); +} + +void CScratchPad3D::DrawRectYZ( float xPos, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor ) +{ + DrawRectGeneric( 0, 1, 2, xPos, vMin, vMax, vColor ); +} + +void CScratchPad3D::DrawRectXZ( float yPos, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor ) +{ + DrawRectGeneric( 1, 0, 2, yPos, vMin, vMax, vColor ); +} + +void CScratchPad3D::DrawRectXY( float zPos, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor ) +{ + DrawRectGeneric( 2, 0, 1, zPos, vMin, vMax, vColor ); +} + +void CScratchPad3D::SetRenderState( RenderState state, unsigned long val ) +{ + CCommand_RenderState *cmd = new CCommand_RenderState; + m_Commands.AddToTail( cmd ); + + cmd->m_State = (unsigned long)state; + cmd->m_Val = val; +} + +void CScratchPad3D::DrawWireframeBox( const Vector &vMin, const Vector &vMax, const Vector &vColor ) +{ + // Bottom 4. + DrawLine( + CSPVert(Vector(vMin.x, vMin.y, vMin.z), vColor), + CSPVert(Vector(vMax.x, vMin.y, vMin.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMin.x, vMin.y, vMin.z), vColor), + CSPVert(Vector(vMin.x, vMax.y, vMin.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMax.x, vMin.y, vMin.z), vColor), + CSPVert(Vector(vMax.x, vMax.y, vMin.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMax.x, vMax.y, vMin.z), vColor), + CSPVert(Vector(vMin.x, vMax.y, vMin.z), vColor) ); + + // Top 4. + DrawLine( + CSPVert(Vector(vMin.x, vMin.y, vMax.z), vColor), + CSPVert(Vector(vMax.x, vMin.y, vMax.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMin.x, vMin.y, vMax.z), vColor), + CSPVert(Vector(vMin.x, vMax.y, vMax.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMax.x, vMin.y, vMax.z), vColor), + CSPVert(Vector(vMax.x, vMax.y, vMax.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMax.x, vMax.y, vMax.z), vColor), + CSPVert(Vector(vMin.x, vMax.y, vMax.z), vColor) ); + + // Connecting 4. + DrawLine( + CSPVert(Vector(vMin.x, vMin.y, vMin.z), vColor), + CSPVert(Vector(vMin.x, vMin.y, vMax.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMin.x, vMax.y, vMin.z), vColor), + CSPVert(Vector(vMin.x, vMax.y, vMax.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMax.x, vMax.y, vMin.z), vColor), + CSPVert(Vector(vMax.x, vMax.y, vMax.z), vColor) ); + + DrawLine( + CSPVert(Vector(vMax.x, vMin.y, vMin.z), vColor), + CSPVert(Vector(vMax.x, vMin.y, vMax.z), vColor) ); +} + + +void CScratchPad3D::DrawText( const char *pStr, const CTextParams ¶ms ) +{ + CCommand_Text *cmd = new CCommand_Text; + m_Commands.AddToTail( cmd ); + + cmd->m_String.CopyArray( pStr, strlen( pStr ) + 1 ); + cmd->m_TextParams = params; + + AutoFlush(); +} + + +void CScratchPad3D::Clear() +{ + FileHandle_t fp; + + while( ( fp = m_pFileSystem->Open(m_pFilename, "wb") ) == NULL ) + { +#ifdef _WIN32 + Sleep( 5 ); +#elif POSIX + usleep( 5 ); +#endif + } + + m_pFileSystem->Close( fp ); + + DeleteCommands(); +} + + +void CScratchPad3D::Flush() +{ + FileHandle_t fp; + + while( ( fp = m_pFileSystem->Open(m_pFilename, "ab+") ) == NULL ) + { +#ifdef _WIN32 + Sleep( 5 ); +#elif POSIX + usleep( 5 ); +#endif + } + + // Append the new commands to the file. + for( int i=0; i < m_Commands.Size(); i++ ) + { + m_pFileSystem->Write( &m_Commands[i]->m_iCommand, sizeof(m_Commands[i]->m_iCommand), fp ); + m_Commands[i]->Write( m_pFileSystem, fp ); + } + + m_pFileSystem->Close( fp ); + + DeleteCommands(); +} + +void CScratchPad3D::DrawImageBW( + unsigned char const *pData, + int width, + int height, + int pitchInBytes, + bool bOutlinePixels, + bool bOutlineImage, + Vector *vCorners ) +{ + SPRGBA *pRGBA = new SPRGBA[width*height]; + for( int y=0; y < height; y++ ) + { + SPRGBA *pDest = &pRGBA[ y * width ]; + unsigned char const *pSrc = &pData[ y * pitchInBytes ]; + for( int x=0; x < width; x++ ) + { + pDest->r = pDest->g = pDest->b = *pSrc; + ++pSrc; + ++pDest; + } + } + + DrawImageRGBA( pRGBA, width, height, width*sizeof(SPRGBA), bOutlinePixels, bOutlineImage, vCorners ); + delete [] pRGBA; +} + + +void CScratchPad3D::DrawPolygonsForPixels( + SPRGBA *pData, + int width, + int height, + int pitchInBytes, + Vector *vCorners ) +{ + // Scan top-down. + Vector vCurLeft = vCorners[1]; + Vector vCurRight = vCorners[2]; + + Vector vLeftInc = (vCorners[0] - vCorners[1]) / height; + Vector vRightInc = (vCorners[3] - vCorners[2]) / height; + + Vector vNextLeft = vCurLeft + vLeftInc; + Vector vNextRight = vCurRight + vRightInc; + + Vector vPolyBox[4]; + Vector &vTopLeft = vPolyBox[0]; + Vector &vTopRight = vPolyBox[1]; + Vector &vBottomRight = vPolyBox[2]; + Vector &vBottomLeft = vPolyBox[3]; + + for( int y=0; y < height; y++ ) + { + vTopLeft = vCurLeft; + vBottomLeft = vNextLeft; + + Vector vTopXInc = (vCurRight - vCurLeft) / width; + Vector vBottomXInc = (vNextRight - vNextLeft) / width; + + vTopRight = vTopLeft + vTopXInc; + vBottomRight = vBottomLeft + vBottomXInc; + + SPRGBA *pSrc = &pData[ y * (pitchInBytes/sizeof(SPRGBA)) ]; + for( int x=0; x < width; x++ ) + { + if ( pData ) + DrawPolygon( CSPVertList( vPolyBox, 4, Vector(pSrc->r/255.1f, pSrc->g/255.1f, pSrc->b/255.1f) ) ); + else + DrawPolygon( CSPVertList( vPolyBox, 4, Vector(1,1,1) ) ); + + ++pSrc; + vTopLeft += vTopXInc; + vTopRight += vTopXInc; + vBottomLeft += vBottomXInc; + vBottomRight += vBottomXInc; + } + + vCurLeft += vLeftInc; + vNextLeft += vLeftInc; + vCurRight += vRightInc; + vNextRight += vRightInc; + } +} + + +void CScratchPad3D::DrawImageRGBA( + SPRGBA *pData, + int width, + int height, + int pitchInBytes, + bool bOutlinePixels, + bool bOutlineImage, + Vector *vCorners ) +{ + Assert( pitchInBytes % sizeof(SPRGBA) == 0 ); + + Vector vDefaultCorners[4]; + if ( !vCorners ) + { + vCorners = vDefaultCorners; + vDefaultCorners[0].Init( -100, -100 ); + vDefaultCorners[1].Init( -100, 100 ); + vDefaultCorners[2].Init( 100, 100 ); + vDefaultCorners[3].Init( 100, -100 ); + } + + // Don't auto-flush while drawing all these primitives. + bool bOldAutoFlush = m_bAutoFlush; + m_bAutoFlush = false; + + // Draw solids. + SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Solid ); + DrawPolygonsForPixels( pData, width, height, pitchInBytes, vCorners ); + + // Draw wireframe. + if ( bOutlinePixels ) + { + SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Wireframe ); + DrawPolygonsForPixels( NULL, width, height, pitchInBytes, vCorners ); + } + + // Draw an outline around the whole image. + if ( bOutlineImage ) + { + SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Wireframe ); + DrawPolygon( CSPVertList( vCorners, 4 ) ); + } + + // Restore the old auto-flush state. + m_bAutoFlush = bOldAutoFlush; + AutoFlush(); +} + + +// ------------------------------------------------------------------------ // +// Global functions. +// ------------------------------------------------------------------------ // +IFileSystem* ScratchPad3D_SetupFileSystem() +{ + // Get a filesystem interface. + CSysModule *pModule = Sys_LoadModule( "filesystem_stdio" ); + if( !pModule ) + return NULL; + + CreateInterfaceFn fn = Sys_GetFactory( pModule ); + IFileSystem *pFileSystem; + if( !fn || (pFileSystem = (IFileSystem *)fn( FILESYSTEM_INTERFACE_VERSION, NULL )) == NULL ) + { + Sys_UnloadModule( pModule ); + return NULL; + } + + return pFileSystem; +} + +IScratchPad3D* ScratchPad3D_Create( char const *pFilename ) +{ + IFileSystem *pFileSystem = ScratchPad3D_SetupFileSystem(); + if( !pFileSystem ) + return NULL; + + CScratchPad3D *pRet = new CScratchPad3D( pFilename, pFileSystem, true ); + return pRet; +} +#endif // POSIX + diff --git a/public/scratchpad3d.h b/public/scratchpad3d.h new file mode 100644 index 0000000..7e9aad6 --- /dev/null +++ b/public/scratchpad3d.h @@ -0,0 +1,224 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SCRATCHPAD3D_H +#define SCRATCHPAD3D_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "iscratchpad3d.h" +#include "mathlib/vmatrix.h" +#include "filesystem.h" + +class CFileRead; + + +class CScratchPad3D : public IScratchPad3D +{ +// Commands that can go in the file. +public: + + enum + { + COMMAND_POINT=0, + COMMAND_LINE, + COMMAND_POLYGON, + COMMAND_MATRIX, + COMMAND_RENDERSTATE, + COMMAND_TEXT, + COMMAND_NUMCOMMANDS + }; + + class ICachedRenderData + { + public: + virtual void Release() = 0; + }; + + class CBaseCommand + { + public: + CBaseCommand( unsigned char iCommand ) + { + m_iCommand = (unsigned char)iCommand; + m_pCachedRenderData = NULL; + } + + ~CBaseCommand() + { + ReleaseCachedRenderData(); + } + + virtual void Read( CFileRead *pFile ) = 0; + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ) = 0; + + // Release cached render data. Usually used for releasing things like textures when + // the app is resizing.. + void ReleaseCachedRenderData() + { + if ( m_pCachedRenderData ) + { + m_pCachedRenderData->Release(); + m_pCachedRenderData = NULL; + } + } + + public: + + unsigned char m_iCommand; // One of the COMMAND_ defines. + + // The renderer can cache data with the commands to speedup the rendering after + // the first time (text uses this big time). + ICachedRenderData *m_pCachedRenderData; + }; + + class CCommand_Point : public CBaseCommand + { + public: + CCommand_Point() : CBaseCommand( COMMAND_POINT ) {} + + virtual void Read( CFileRead *pFile ); + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ); + + float m_flPointSize; + CSPVert m_Vert; + }; + + class CCommand_Line : public CBaseCommand + { + public: + CCommand_Line() : CBaseCommand( COMMAND_LINE ) {} + + virtual void Read( CFileRead *pFile ); + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ); + + CSPVert m_Verts[2]; + }; + + class CCommand_Polygon : public CBaseCommand + { + public: + CCommand_Polygon() : CBaseCommand( COMMAND_POLYGON ) {} + + virtual void Read( CFileRead *pFile ); + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ); + + CUtlVector m_Verts; + }; + + class CCommand_Matrix : public CBaseCommand + { + public: + CCommand_Matrix() : CBaseCommand( COMMAND_MATRIX ) {} + + virtual void Read( CFileRead *pFile ); + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ); + + VMatrix m_mMatrix; + }; + + class CCommand_RenderState : public CBaseCommand + { + public: + CCommand_RenderState() : CBaseCommand( COMMAND_RENDERSTATE ) {} + + virtual void Read( CFileRead *pFile ); + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ); + + unsigned long m_State; // One of the RS_ enums. + unsigned long m_Val; + }; + + class CCommand_Text : public CBaseCommand + { + public: + CCommand_Text() : CBaseCommand( COMMAND_TEXT ) {} + + virtual void Read( CFileRead *pFile ); + virtual void Write( IFileSystem* pFileSystem, FileHandle_t fp ); + + CUtlVector m_String; // The string to render. + CTextParams m_TextParams; + }; + + +public: + + CScratchPad3D( char const *pFilename, IFileSystem *pFileSystem, bool bAutoClear ); + + void AutoFlush(); + void DrawRectGeneric( int iPlane, int otherDim1, int otherDim2, float planeDist, Vector2D const &vMin, Vector2D const &vMax, CSPColor const &vColor ); + void DeleteCommands(); + + // Load a file... + bool LoadCommandsFromFile( ); + + +public: + + virtual void Release(); + + virtual void SetMapping( + Vector const &vInputMin, + Vector const &vInputMax, + Vector const &vOutputMin, + Vector const &vOutputMax ); + virtual bool GetAutoFlush(); + virtual void SetAutoFlush( bool bAutoFlush ); + virtual void DrawPoint( CSPVert const &v, float flPointSize ); + virtual void DrawLine( CSPVert const &v1, CSPVert const &v2 ); + virtual void DrawPolygon( CSPVertList const &verts ); + virtual void DrawRectYZ( float xPos, Vector2D const &vMin, Vector2D const &vMax, CSPColor const &vColor ); + virtual void DrawRectXZ( float yPos, Vector2D const &vMin, Vector2D const &vMax, CSPColor const &vColor ); + virtual void DrawRectXY( float zPos, Vector2D const &vMin, Vector2D const &vMax, CSPColor const &vColor ); + virtual void DrawWireframeBox( Vector const &vMin, Vector const &vMax, Vector const &vColor ); + virtual void DrawText( const char *pStr, const CTextParams ¶ms ); + virtual void SetRenderState( RenderState state, unsigned long val ); + virtual void Clear(); + virtual void Flush(); + virtual void DrawImageBW( + unsigned char const *pData, + int width, + int height, + int pitchInBytes, + bool bOutlinePixels=true, + bool bOutlineImage=false, + Vector *vCorners=NULL ); + + // Draw an RGBA image. + // Corners are in this order: bottom-left, top-left, top-right, bottom-right. + virtual void DrawImageRGBA( + SPRGBA *pData, + int width, + int height, + int pitchInBytes, + bool bOutlinePixels=true, + bool bOutlineImage=false, + Vector *vCorners=NULL ); + + void DrawPolygonsForPixels( + SPRGBA *pData, + int width, + int height, + int pitchInBytes, + Vector *vCorners ); + +public: + IFileSystem* m_pFileSystem; + char const *m_pFilename; + CUtlVector m_Commands; + bool m_bAutoFlush; +}; + + +IFileSystem* ScratchPad3D_SetupFileSystem(); + + +#endif // SCRATCHPAD3D_H diff --git a/public/sentence.cpp b/public/sentence.cpp new file mode 100644 index 0000000..c845e60 --- /dev/null +++ b/public/sentence.cpp @@ -0,0 +1,1768 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#include +#include "commonmacros.h" +#include "basetypes.h" +#include "sentence.h" +#include "utlbuffer.h" +#include +#include "mathlib/vector.h" +#include "mathlib/mathlib.h" +#include +#include "checksum_crc.h" +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: converts an english string to unicode +//----------------------------------------------------------------------------- +int ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSize); + +#if PHONEME_EDITOR +void CEmphasisSample::SetSelected( bool isSelected ) +{ + selected = isSelected; +} +void CPhonemeTag::SetSelected( bool isSelected ) +{ + m_bSelected = isSelected; +} +bool CPhonemeTag::GetSelected() const +{ + return m_bSelected; +} +void CPhonemeTag::SetStartAndEndBytes( unsigned int start, unsigned int end ) +{ + m_uiStartByte = start; + m_uiEndByte = end; +} +unsigned int CPhonemeTag::GetStartByte() const +{ + return m_uiStartByte; +} +unsigned int CPhonemeTag::GetEndByte() const +{ + return m_uiEndByte; +} +void CWordTag::SetSelected( bool isSelected ) +{ + m_bSelected = isSelected; +} +bool CWordTag::GetSelected() const +{ + return m_bSelected; +} +void CWordTag::SetStartAndEndBytes( unsigned int start, unsigned int end ) +{ + m_uiStartByte = start; + m_uiEndByte = end; +} +unsigned int CWordTag::GetStartByte() const +{ + return m_uiStartByte; +} +unsigned int CWordTag::GetEndByte() const +{ + return m_uiEndByte; +} +#else +// xbox doesn't store this data +void CEmphasisSample::SetSelected( bool isSelected ) {} +void CPhonemeTag::SetSelected( bool isSelected ) {} +bool CPhonemeTag::GetSelected() const { return false; } +void CPhonemeTag::SetStartAndEndBytes( unsigned int start, unsigned int end ) {} +unsigned int CPhonemeTag::GetStartByte() const { return 0; } +unsigned int CPhonemeTag::GetEndByte() const { return 0; } +void CWordTag::SetSelected( bool isSelected ) {} +bool CWordTag::GetSelected() const { return false; } +void CWordTag::SetStartAndEndBytes( unsigned int start, unsigned int end ) {} +unsigned int CWordTag::GetStartByte() const { return 0; } +unsigned int CWordTag::GetEndByte() const { return 0; } +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWordTag::CWordTag( void ) +{ + m_pszWord = NULL; + + SetStartAndEndBytes( 0, 0 ); + + m_flStartTime = 0.0f; + m_flEndTime = 0.0f; + + SetSelected( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : from - +//----------------------------------------------------------------------------- +CWordTag::CWordTag( const CWordTag& from ) +{ + m_pszWord = NULL; + SetWord( from.m_pszWord ); + + SetStartAndEndBytes( from.GetStartByte(), from.GetEndByte() ); + + m_flStartTime = from.m_flStartTime; + m_flEndTime = from.m_flEndTime; + + SetSelected( from.GetSelected() ); + + for ( int p = 0; p < from.m_Phonemes.Size(); p++ ) + { + CPhonemeTag *newPhoneme = new CPhonemeTag( *from.m_Phonemes[ p ] ); + m_Phonemes.AddToTail( newPhoneme ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *word - +//----------------------------------------------------------------------------- +CWordTag::CWordTag( const char *word ) +{ + SetStartAndEndBytes( 0, 0 ); + + m_flStartTime = 0.0f; + m_flEndTime = 0.0f; + + m_pszWord = NULL; + + SetSelected( false ); + + SetWord( word ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWordTag::~CWordTag( void ) +{ + delete[] m_pszWord; + + while ( m_Phonemes.Size() > 0 ) + { + delete m_Phonemes[ 0 ]; + m_Phonemes.Remove( 0 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *tag - +// Output : int +//----------------------------------------------------------------------------- +int CWordTag::IndexOfPhoneme( CPhonemeTag *tag ) +{ + for ( int i = 0 ; i < m_Phonemes.Size(); i++ ) + { + CPhonemeTag *p = m_Phonemes[ i ]; + if ( p == tag ) + return i; + } + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *word - +//----------------------------------------------------------------------------- +void CWordTag::SetWord( const char *word ) +{ + delete[] m_pszWord; + m_pszWord = NULL; + if ( !word || !word[ 0 ] ) + return; + + int len = strlen( word ) + 1; + m_pszWord = new char[ len ]; + Assert( m_pszWord ); + Q_strncpy( m_pszWord, word, len ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char *CWordTag::GetWord() const +{ + return m_pszWord ? m_pszWord : ""; +} + + +unsigned int CWordTag::ComputeDataCheckSum() +{ + int i; + int c; + CRC32_t crc; + CRC32_Init( &crc ); + + // Checksum the text + if ( m_pszWord != NULL ) + { + CRC32_ProcessBuffer( &crc, m_pszWord, Q_strlen( m_pszWord ) ); + } + // Checksum phonemes + c = m_Phonemes.Count(); + for ( i = 0; i < c; ++i ) + { + CPhonemeTag *phoneme = m_Phonemes[ i ]; + unsigned int phonemeCheckSum = phoneme->ComputeDataCheckSum(); + CRC32_ProcessBuffer( &crc, &phonemeCheckSum, sizeof( unsigned int ) ); + } + // Checksum timestamps + CRC32_ProcessBuffer( &crc, &m_flStartTime, sizeof( float ) ); + CRC32_ProcessBuffer( &crc, &m_flEndTime, sizeof( float ) ); + + CRC32_Final( &crc ); + + return ( unsigned int )crc; +} + +CBasePhonemeTag::CBasePhonemeTag() +{ + m_flStartTime = 0; + m_flEndTime = 0; + + m_nPhonemeCode = 0; +} + +CBasePhonemeTag::CBasePhonemeTag( const CBasePhonemeTag& from ) +{ + memcpy( this, &from, sizeof(*this) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CPhonemeTag::CPhonemeTag( void ) +{ + m_szPhoneme = NULL; + + SetStartAndEndBytes( 0, 0 ); + + SetSelected( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : from - +//----------------------------------------------------------------------------- +CPhonemeTag::CPhonemeTag( const CPhonemeTag& from ) : + BaseClass( from ) +{ + SetStartAndEndBytes( from.GetStartByte(), from.GetEndByte() ); + + SetSelected( from.GetSelected() ); + + m_szPhoneme = NULL; + SetTag( from.GetTag() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *phoneme - +//----------------------------------------------------------------------------- +CPhonemeTag::CPhonemeTag( const char *phoneme ) +{ + SetStartAndEndBytes( 0, 0 ); + + SetStartTime( 0.0f ); + SetEndTime( 0.0f ); + + SetSelected( false ); + + SetPhonemeCode( 0 ); + + m_szPhoneme = NULL; + SetTag( phoneme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CPhonemeTag::~CPhonemeTag( void ) +{ + delete[] m_szPhoneme; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *phoneme - +//----------------------------------------------------------------------------- +void CPhonemeTag::SetTag( const char *phoneme ) +{ + delete m_szPhoneme; + m_szPhoneme = NULL; + if ( !phoneme || !phoneme [ 0 ] ) + return; + + int len = Q_strlen( phoneme ) + 1; + m_szPhoneme = new char[ len ]; + Assert( m_szPhoneme ); + Q_strncpy( m_szPhoneme, phoneme, len ); +} + +char const *CPhonemeTag::GetTag() const +{ + return m_szPhoneme ? m_szPhoneme : ""; +} + + +unsigned int CPhonemeTag::ComputeDataCheckSum() +{ + CRC32_t crc; + CRC32_Init( &crc ); + + // Checksum the text + CRC32_ProcessBuffer( &crc, m_szPhoneme, Q_strlen( m_szPhoneme ) ); + int phonemeCode = GetPhonemeCode(); + CRC32_ProcessBuffer( &crc, &phonemeCode, sizeof( int ) ); + + // Checksum timestamps + float startTime = GetStartTime(); + float endTime = GetEndTime(); + CRC32_ProcessBuffer( &crc, &startTime, sizeof( float ) ); + CRC32_ProcessBuffer( &crc, &endTime, sizeof( float ) ); + + CRC32_Final( &crc ); + + return ( unsigned int )crc; +} + +//----------------------------------------------------------------------------- +// Purpose: Simple language to string and string to language lookup dictionary +//----------------------------------------------------------------------------- +#pragma pack(1) + +struct CCLanguage +{ + int type; + char const *name; + unsigned char r, g, b; // For faceposer, indicator color for this language +}; + +static CCLanguage g_CCLanguageLookup[] = +{ + { CC_ENGLISH, "english", 0, 0, 0 }, + { CC_FRENCH, "french", 150, 0, 0 }, + { CC_GERMAN, "german", 0, 150, 0 }, + { CC_ITALIAN, "italian", 0, 150, 150 }, + { CC_KOREAN, "koreana", 150, 0, 150 }, + { CC_SCHINESE, "schinese", 150, 0, 150 }, + { CC_SPANISH, "spanish", 0, 0, 150 }, + { CC_TCHINESE, "tchinese", 150, 0, 150 }, + { CC_JAPANESE, "japanese", 250, 150, 0 }, + { CC_RUSSIAN, "russian", 0, 250, 150 }, + { CC_THAI, "thai", 0 , 150, 250 }, + { CC_PORTUGUESE,"portuguese", 0 , 0, 150 }, +}; + +#pragma pack() + +void CSentence::ColorForLanguage( int language, unsigned char& r, unsigned char& g, unsigned char& b ) +{ + r = g = b = 0; + + if ( language < 0 || language >= CC_NUM_LANGUAGES ) + { + return; + } + + r = g_CCLanguageLookup[ language ].r; + g = g_CCLanguageLookup[ language ].g; + b = g_CCLanguageLookup[ language ].b; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : language - +// Output : char const +//----------------------------------------------------------------------------- +char const *CSentence::NameForLanguage( int language ) +{ + if ( language < 0 || language >= CC_NUM_LANGUAGES ) + return "unknown_language"; + + CCLanguage *entry = &g_CCLanguageLookup[ language ]; + Assert( entry->type == language ); + return entry->name; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// Output : int +//----------------------------------------------------------------------------- +int CSentence::LanguageForName( char const *name ) +{ + int l; + for ( l = 0; l < CC_NUM_LANGUAGES; l++ ) + { + CCLanguage *entry = &g_CCLanguageLookup[ l ]; + Assert( entry->type == l ); + if ( !stricmp( entry->name, name ) ) + return l; + } + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CSentence::CSentence( void ) +{ +#if PHONEME_EDITOR + m_nResetWordBase = 0; + m_szText = 0; + m_uCheckSum = 0; +#endif + m_bShouldVoiceDuck = false; + m_bStoreCheckSum = false; + m_bIsValid = false; + m_bIsCached = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CSentence::~CSentence( void ) +{ + Reset(); +#if PHONEME_EDITOR + delete[] m_szText; +#endif +} + + +void CSentence::ParsePlaintext( CUtlBuffer& buf ) +{ + char token[ 4096 ]; + char text[ 4096 ]; + text[ 0 ] = 0; + while ( 1 ) + { + buf.GetString( token ); + if ( !stricmp( token, "}" ) ) + break; + + Q_strncat( text, token, sizeof( text ), COPY_ALL_CHARACTERS ); + Q_strncat( text, " ", sizeof( text ), COPY_ALL_CHARACTERS ); + } + + SetText( text ); +} + +void CSentence::ParseWords( CUtlBuffer& buf ) +{ + char token[ 4096 ]; + char word[ 256 ]; + float start, end; + + while ( 1 ) + { + buf.GetString( token ); + if ( !stricmp( token, "}" ) ) + break; + + if ( stricmp( token, "WORD" ) ) + break; + + buf.GetString( token ); + Q_strncpy( word, token, sizeof( word ) ); + + buf.GetString( token ); + start = atof( token ); + buf.GetString( token ); + end = atof( token ); + + CWordTag *wt = new CWordTag( word ); + assert( wt ); + wt->m_flStartTime = start; + wt->m_flEndTime = end; + + AddWordTag( wt ); + + buf.GetString( token ); + if ( stricmp( token, "{" ) ) + break; + + while ( 1 ) + { + buf.GetString( token ); + if ( !stricmp( token, "}" ) ) + break; + + // Parse phoneme + int code; + char phonemename[ 256 ]; + float start, end; + float volume; + + code = atoi( token ); + + buf.GetString( token ); + Q_strncpy( phonemename, token, sizeof( phonemename ) ); + buf.GetString( token ); + start = atof( token ); + buf.GetString( token ); + end = atof( token ); + buf.GetString( token ); + volume = atof( token ); + + CPhonemeTag *pt = new CPhonemeTag(); + assert( pt ); + pt->SetPhonemeCode( code ); + pt->SetTag( phonemename ); + pt->SetStartTime( start ); + pt->SetEndTime( end ); + + AddPhonemeTag( wt, pt ); + } + } +} + +void CSentence::ParseEmphasis( CUtlBuffer& buf ) +{ + char token[ 4096 ]; + while ( 1 ) + { + buf.GetString( token ); + if ( !stricmp( token, "}" ) ) + break; + + char t[ 256 ]; + Q_strncpy( t, token, sizeof( t ) ); + buf.GetString( token ); + + char value[ 256 ]; + Q_strncpy( value, token, sizeof( value ) ); + + CEmphasisSample sample; + sample.SetSelected( false ); + sample.time = atof( t ); + sample.value = atof( value ); + + + m_EmphasisSamples.AddToTail( sample ); + + } +} + +// This is obsolete, so it doesn't do anything with the data which is parsed. +void CSentence::ParseCloseCaption( CUtlBuffer& buf ) +{ + char token[ 4096 ]; + while ( 1 ) + { + // Format is + // language_name + // { + // PHRASE char streamlength "streambytes" starttime endtime + // PHRASE unicode streamlength "streambytes" starttime endtime + // } + buf.GetString( token ); + if ( !stricmp( token, "}" ) ) + break; + + buf.GetString( token ); + if ( stricmp( token, "{" ) ) + break; + + buf.GetString( token ); + while ( 1 ) + { + if ( !stricmp( token, "}" ) ) + break; + + if ( stricmp( token, "PHRASE" ) ) + break; + + char cc_type[32]; + char cc_stream[ 4096 ]; + int cc_length; + + memset( cc_stream, 0, sizeof( cc_stream ) ); + + buf.GetString( token ); + Q_strncpy( cc_type, token, sizeof( cc_type ) ); + + bool unicode = false; + if ( !stricmp( cc_type, "unicode" ) ) + { + unicode = true; + } + else if ( stricmp( cc_type, "char" ) ) + { + Assert( 0 ); + } + + buf.GetString( token ); + cc_length = atoi( token ); + Assert( cc_length >= 0 && cc_length < sizeof( cc_stream ) ); + // Skip space + buf.GetChar(); + buf.Get( cc_stream, cc_length ); + cc_stream[ cc_length ] = 0; + + // Skip space + buf.GetChar(); + buf.GetString( token ); + buf.GetString( token ); + + buf.GetString( token ); + } + } +} + +void CSentence::ParseOptions( CUtlBuffer& buf ) +{ + char token[ 4096 ]; + while ( 1 ) + { + buf.GetString( token ); + if ( !stricmp( token, "}" ) ) + break; + + if ( Q_strlen( token ) == 0 ) + break; + + char key[ 256 ]; + Q_strncpy( key, token, sizeof( key ) ); + char value[ 256 ]; + buf.GetString( token ); + Q_strncpy( value, token, sizeof( value ) ); + + if ( !strcmpi( key, "voice_duck" ) ) + { + SetVoiceDuck( atoi(value) ? true : false ); + } + else if ( !strcmpi( key, "checksum" ) ) + { + SetDataCheckSum( (unsigned int)atoi( value ) ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: VERSION 1.0 parser, need to implement new ones if +// file format changes!!! +// Input : buf - +//----------------------------------------------------------------------------- +void CSentence::ParseDataVersionOnePointZero( CUtlBuffer& buf ) +{ + char token[ 4096 ]; + + while ( 1 ) + { + buf.GetString( token ); + if ( strlen( token ) <= 0 ) + break; + + // end of block, return + if ( !V_strcmp( token, "}" ) ) + break; + + char section[ 256 ]; + Q_strncpy( section, token, sizeof( section ) ); + + buf.GetString( token ); + if ( stricmp( token, "{" ) ) + break; + + if ( !stricmp( section, "PLAINTEXT" ) ) + { + ParsePlaintext( buf ); + } + else if ( !stricmp( section, "WORDS" ) ) + { + ParseWords( buf ); + } + else if ( !stricmp( section, "EMPHASIS" ) ) + { + ParseEmphasis( buf ); + } + else if ( !stricmp( section, "CLOSECAPTION" ) ) + { + // NOTE: CLOSECAPTION IS NO LONGER VALID + // This just skips the section of data. + ParseCloseCaption( buf ); + } + else if ( !stricmp( section, "OPTIONS" ) ) + { + ParseOptions( buf ); + } + } +} + +// This is a compressed save of just the data needed to drive phonemes in the engine (no word / sentence text, etc ) +//----------------------------------------------------------------------------- +// Purpose: +// Input : buf - +//----------------------------------------------------------------------------- +void CSentence::CacheSaveToBuffer( CUtlBuffer& buf, int version ) +{ + Assert( !buf.IsText() ); + Assert( m_bIsCached ); + + int i; + unsigned short pcount = GetRuntimePhonemeCount(); + + // header + if ( version == CACHED_SENTENCE_VERSION_ALIGNED ) + { + buf.PutChar( version ); + buf.PutChar( 0 ); + buf.PutChar( 0 ); + buf.PutChar( 0 ); + buf.PutInt( pcount ); + } + else + { + buf.PutChar( version ); + buf.PutShort( pcount ); + } + + // phoneme + if ( version == CACHED_SENTENCE_VERSION_ALIGNED ) + { + for ( i = 0; i < pcount; ++i ) + { + const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i ); + Assert( phoneme ); + buf.PutInt( phoneme->GetPhonemeCode() ); + buf.PutFloat( phoneme->GetStartTime() ); + buf.PutFloat( phoneme->GetEndTime() ); + } + } + else + { + for ( i = 0; i < pcount; ++i ) + { + const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i ); + Assert( phoneme ); + buf.PutShort( phoneme->GetPhonemeCode() ); + buf.PutFloat( phoneme->GetStartTime() ); + buf.PutFloat( phoneme->GetEndTime() ); + } + } + + // emphasis samples and voice duck + int c = m_EmphasisSamples.Count(); + Assert( c <= 32767 ); + + if ( version == CACHED_SENTENCE_VERSION_ALIGNED ) + { + buf.PutInt( c ); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample *sample = &m_EmphasisSamples[i]; + Assert( sample ); + buf.PutFloat( sample->time ); + buf.PutFloat( sample->value ); + } + buf.PutInt( GetVoiceDuck() ? 1 : 0 ); + } + else + { + buf.PutShort( c ); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample *sample = &m_EmphasisSamples[i]; + Assert( sample ); + buf.PutFloat( sample->time ); + short scaledValue = clamp( (short)( sample->value * 32767 ), (short)0, (short)32767 ); + buf.PutShort( scaledValue ); + } + buf.PutChar( GetVoiceDuck() ? 1 : 0 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : buf - +//----------------------------------------------------------------------------- +void CSentence::CacheRestoreFromBuffer( CUtlBuffer& buf ) +{ + Assert( !buf.IsText() ); + + Reset(); + + m_bIsCached = true; + + // determine format + int version = buf.GetChar(); + if ( version != CACHED_SENTENCE_VERSION && version != CACHED_SENTENCE_VERSION_ALIGNED ) + { + // Uh oh, version changed... + m_bIsValid = false; + return; + } + + unsigned short pcount; + if ( version == CACHED_SENTENCE_VERSION_ALIGNED ) + { + buf.GetChar(); + buf.GetChar(); + buf.GetChar(); + pcount = buf.GetInt(); + } + else + { + pcount = (unsigned short)buf.GetShort(); + } + + // phonemes + CPhonemeTag pt; + int i; + if ( version == CACHED_SENTENCE_VERSION_ALIGNED ) + { + for ( i = 0; i < pcount; ++i ) + { + int code = buf.GetInt(); + float st = buf.GetFloat(); + float et = buf.GetFloat(); + + pt.SetPhonemeCode( code ); + pt.SetStartTime( st ); + pt.SetEndTime( et ); + AddRuntimePhoneme( &pt ); + } + } + else + { + for ( i = 0; i < pcount; ++i ) + { + unsigned short code = buf.GetShort(); + float st = buf.GetFloat(); + float et = buf.GetFloat(); + + pt.SetPhonemeCode( code ); + pt.SetStartTime( st ); + pt.SetEndTime( et ); + AddRuntimePhoneme( &pt ); + } + } + + // emphasis samples and voice duck + int c; + if ( version == CACHED_SENTENCE_VERSION_ALIGNED ) + { + c = buf.GetInt(); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample sample; + sample.SetSelected( false ); + sample.time = buf.GetFloat(); + sample.value = buf.GetFloat(); + m_EmphasisSamples.AddToTail( sample ); + } + SetVoiceDuck( buf.GetInt() == 0 ? false : true ); + } + else + { + c = buf.GetShort(); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample sample; + sample.SetSelected( false ); + sample.time = buf.GetFloat(); + sample.value = (float)buf.GetShort() / 32767.0f; + m_EmphasisSamples.AddToTail( sample ); + } + SetVoiceDuck( buf.GetChar() == 0 ? false : true ); + } + + m_bIsValid = true; +} + +int CSentence::GetRuntimePhonemeCount() const +{ + return m_RunTimePhonemes.Count(); +} + +const CBasePhonemeTag *CSentence::GetRuntimePhoneme( int i ) const +{ + Assert( m_bIsCached ); + return m_RunTimePhonemes[ i ]; +} + +void CSentence::ClearRuntimePhonemes() +{ + while ( m_RunTimePhonemes.Count() > 0 ) + { + CBasePhonemeTag *tag = m_RunTimePhonemes[ 0 ]; + delete tag; + m_RunTimePhonemes.Remove( 0 ); + } +} + +void CSentence::AddRuntimePhoneme( const CPhonemeTag *src ) +{ + Assert( m_bIsCached ); + + CBasePhonemeTag *tag = new CBasePhonemeTag(); + *tag = *src; + + m_RunTimePhonemes.AddToTail( tag ); +} + +void CSentence::MakeRuntimeOnly() +{ + m_bIsCached = true; +#if PHONEME_EDITOR + delete m_szText; + m_szText = NULL; + + int c = m_Words.Count(); + for ( int i = 0; i < c; ++i ) + { + CWordTag *word = m_Words[ i ]; + Assert( word ); + int pcount = word->m_Phonemes.Count(); + for ( int j = 0; j < pcount; ++j ) + { + CPhonemeTag *phoneme = word->m_Phonemes[ j ]; + assert( phoneme ); + + AddRuntimePhoneme( phoneme ); + } + } + + // Remove all existing words + while ( m_Words.Count() > 0 ) + { + CWordTag *word = m_Words[ 0 ]; + delete word; + m_Words.Remove( 0 ); + } +#endif + m_bIsValid = true; +} + + +void CSentence::SaveToBuffer( CUtlBuffer& buf ) +{ +#if PHONEME_EDITOR + Assert( !m_bIsCached ); + + int i, j; + + buf.Printf( "VERSION 1.0\n" ); + + buf.Printf( "PLAINTEXT\n" ); + buf.Printf( "{\n" ); + buf.Printf( "%s\n", GetText() ); + buf.Printf( "}\n" ); + buf.Printf( "WORDS\n" ); + buf.Printf( "{\n" ); + for ( i = 0; i < m_Words.Size(); i++ ) + { + CWordTag *word = m_Words[ i ]; + Assert( word ); + + buf.Printf( "WORD %s %.3f %.3f\n", + word->GetWord(), + word->m_flStartTime, + word->m_flEndTime ); + + buf.Printf( "{\n" ); + for ( j = 0; j < word->m_Phonemes.Size(); j++ ) + { + CPhonemeTag *phoneme = word->m_Phonemes[ j ]; + Assert( phoneme ); + + buf.Printf( "%i %s %.3f %.3f 1\n", + phoneme->GetPhonemeCode(), + phoneme->GetTag(), + phoneme->GetStartTime(), + phoneme->GetEndTime() ); + } + + buf.Printf( "}\n" ); + } + buf.Printf( "}\n" ); + buf.Printf( "EMPHASIS\n" ); + buf.Printf( "{\n" ); + int c = m_EmphasisSamples.Count(); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample *sample = &m_EmphasisSamples[ i ]; + Assert( sample ); + + buf.Printf( "%f %f\n", sample->time, sample->value ); + } + + buf.Printf( "}\n" ); + buf.Printf( "OPTIONS\n" ); + buf.Printf( "{\n" ); + buf.Printf( "voice_duck %d\n", GetVoiceDuck() ? 1 : 0 ); + if ( m_bStoreCheckSum ) + { + buf.Printf( "checksum %d\n", m_uCheckSum ); + } + buf.Printf( "}\n" ); +#else + Assert( 0 ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *data - +// size - +//----------------------------------------------------------------------------- +void CSentence::InitFromDataChunk( void *data, int size ) +{ + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + buf.EnsureCapacity( size ); + buf.Put( data, size ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, size ); + + InitFromBuffer( buf ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : buf - +//----------------------------------------------------------------------------- +void CSentence::InitFromBuffer( CUtlBuffer& buf ) +{ + Assert( buf.IsText() ); + + Reset(); + + char token[ 4096 ]; + buf.GetString( token ); + + if ( stricmp( token, "VERSION" ) ) + return; + + buf.GetString( token ); + if ( atof( token ) == 1.0f ) + { + ParseDataVersionOnePointZero( buf ); + m_bIsValid = true; + } + else + { + assert( 0 ); + return; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CSentence::GetWordBase( void ) +{ +#if PHONEME_EDITOR + return m_nResetWordBase; +#else + Assert( 0 ); + return 0; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSentence::ResetToBase( void ) +{ +#if PHONEME_EDITOR + // Delete everything after m_nResetWordBase + while ( m_Words.Size() > m_nResetWordBase ) + { + delete m_Words[ m_Words.Size() - 1 ]; + m_Words.Remove( m_Words.Size() - 1 ); + } +#endif + ClearRuntimePhonemes(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSentence::MarkNewPhraseBase( void ) +{ +#if PHONEME_EDITOR + m_nResetWordBase = vmax( m_Words.Size(), 0 ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSentence::Reset( void ) +{ +#if PHONEME_EDITOR + m_nResetWordBase = 0; + + while ( m_Words.Size() > 0 ) + { + delete m_Words[ 0 ]; + m_Words.Remove( 0 ); + } +#endif + m_EmphasisSamples.RemoveAll(); + + ClearRuntimePhonemes(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *tag - +//----------------------------------------------------------------------------- +void CSentence::AddPhonemeTag( CWordTag *word, CPhonemeTag *tag ) +{ + word->m_Phonemes.AddToTail( tag ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *tag - +//----------------------------------------------------------------------------- +void CSentence::AddWordTag( CWordTag *tag ) +{ +#if PHONEME_EDITOR + m_Words.AddToTail( tag ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CSentence::CountPhonemes( void ) +{ + int c = 0; +#if PHONEME_EDITOR + for( int i = 0; i < m_Words.Size(); i++ ) + { + CWordTag *word = m_Words[ i ]; + c += word->m_Phonemes.Size(); + } +#endif + return c; +} + +//----------------------------------------------------------------------------- +// Purpose: // For legacy loading, try to find a word that contains the time +// Input : time - +// Output : CWordTag +//----------------------------------------------------------------------------- +CWordTag *CSentence::EstimateBestWord( float time ) +{ +#if PHONEME_EDITOR + CWordTag *bestWord = NULL; + + for( int i = 0; i < m_Words.Size(); i++ ) + { + CWordTag *word = m_Words[ i ]; + if ( !word ) + continue; + + if ( word->m_flStartTime <= time && word->m_flEndTime >= time ) + return word; + + if ( time < word->m_flStartTime ) + { + bestWord = word; + } + + if ( time > word->m_flEndTime && bestWord ) + return bestWord; + } + + // return best word if we found one + if ( bestWord ) + { + return bestWord; + } + + // Return last word + if ( m_Words.Size() >= 1 ) + { + return m_Words[ m_Words.Size() - 1 ]; + } +#endif + // Oh well + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *phoneme - +// Output : CWordTag +//----------------------------------------------------------------------------- +CWordTag *CSentence::GetWordForPhoneme( CPhonemeTag *phoneme ) +{ +#if PHONEME_EDITOR + for( int i = 0; i < m_Words.Size(); i++ ) + { + CWordTag *word = m_Words[ i ]; + if ( !word ) + continue; + + for ( int j = 0 ; j < word->m_Phonemes.Size() ; j++ ) + { + CPhonemeTag *p = word->m_Phonemes[ j ]; + if ( p == phoneme ) + { + return word; + } + } + + } +#endif + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Assignment operator +// Input : src - +// Output : CSentence& +//----------------------------------------------------------------------------- +CSentence& CSentence::operator=( const CSentence& src ) +{ + int i; + + // Clear current stuff + Reset(); + + int c; + +#if PHONEME_EDITOR + // Copy everything + for ( i = 0 ; i < src.m_Words.Size(); i++ ) + { + CWordTag *word = src.m_Words[ i ]; + + CWordTag *newWord = new CWordTag( *word ); + + AddWordTag( newWord ); + } + + SetText( src.GetText() ); + m_nResetWordBase = src.m_nResetWordBase; + + c = src.m_EmphasisSamples.Size(); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample s = src.m_EmphasisSamples[ i ]; + m_EmphasisSamples.AddToTail( s ); + } +#endif + + m_bIsCached = src.m_bIsCached; + + c = src.GetRuntimePhonemeCount(); + for ( i = 0; i < c; i++ ) + { + Assert( m_bIsCached ); + + const CBasePhonemeTag *tag = src.GetRuntimePhoneme( i ); + CPhonemeTag full; + ((CBasePhonemeTag &)(full)) = *tag; + + AddRuntimePhoneme( &full ); + } + + m_bShouldVoiceDuck = src.m_bShouldVoiceDuck; +#if PHONEME_EDITOR + m_bStoreCheckSum = src.m_bStoreCheckSum; + m_uCheckSum = src.m_uCheckSum; +#endif + m_bIsValid = src.m_bIsValid; + + return (*this); +} + +void CSentence::Append( float starttime, const CSentence& src ) +{ +#if PHONEME_EDITOR + int i; + // Combine + for ( i = 0 ; i < src.m_Words.Size(); i++ ) + { + CWordTag *word = src.m_Words[ i ]; + + CWordTag *newWord = new CWordTag( *word ); + + newWord->m_flStartTime += starttime; + newWord->m_flEndTime += starttime; + + // Offset times + int c = newWord->m_Phonemes.Count(); + for ( int i = 0; i < c; ++i ) + { + CPhonemeTag *tag = newWord->m_Phonemes[ i ]; + tag->AddStartTime( starttime ); + tag->AddEndTime( starttime ); + } + + AddWordTag( newWord ); + } + + if ( src.GetText()[ 0 ] ) + { + char fulltext[ 4096 ]; + if ( GetText()[ 0 ] ) + { + Q_snprintf( fulltext, sizeof( fulltext ), "%s %s", GetText(), src.GetText() ); + } + else + { + Q_strncpy( fulltext, src.GetText(), sizeof( fulltext ) ); + } + SetText( fulltext ); + } + + int c = src.m_EmphasisSamples.Size(); + for ( i = 0; i < c; i++ ) + { + CEmphasisSample s = src.m_EmphasisSamples[ i ]; + + s.time += starttime; + + m_EmphasisSamples.AddToTail( s ); + } + + // Or in voice duck settings + m_bShouldVoiceDuck |= src.m_bShouldVoiceDuck; +#else + Assert( 0 ); +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *text - +//----------------------------------------------------------------------------- +void CSentence::SetText( const char *text ) +{ +#if PHONEME_EDITOR + delete[] m_szText; + m_szText = NULL; + + if ( !text || !text[ 0 ] ) + { + return; + } + + int len = Q_strlen( text ) + 1; + + m_szText = new char[ len ]; + Assert( m_szText ); + Q_strncpy( m_szText, text, len ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char *CSentence::GetText( void ) const +{ +#if PHONEME_EDITOR + return m_szText ? m_szText : ""; +#else + return ""; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSentence::SetTextFromWords( void ) +{ +#if PHONEME_EDITOR + char fulltext[ 1024 ]; + fulltext[ 0 ] = 0; + for ( int i = 0 ; i < m_Words.Size(); i++ ) + { + CWordTag *word = m_Words[ i ]; + + Q_strncat( fulltext, word->GetWord(), sizeof( fulltext ), COPY_ALL_CHARACTERS ); + + if ( i != m_Words.Size() ) + { + Q_strncat( fulltext, " ", sizeof( fulltext ), COPY_ALL_CHARACTERS ); + } + } + + SetText( fulltext ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSentence::Resort( void ) +{ + int c = m_EmphasisSamples.Size(); + for ( int i = 0; i < c; i++ ) + { + for ( int j = i + 1; j < c; j++ ) + { + CEmphasisSample src = m_EmphasisSamples[ i ]; + CEmphasisSample dest = m_EmphasisSamples[ j ]; + + if ( src.time > dest.time ) + { + m_EmphasisSamples[ i ] = dest; + m_EmphasisSamples[ j ] = src; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : number - +// Output : CEmphasisSample +//----------------------------------------------------------------------------- +CEmphasisSample *CSentence::GetBoundedSample( int number, float endtime ) +{ + // Search for two samples which span time f + static CEmphasisSample nullstart; + nullstart.time = 0.0f; + nullstart.value = 0.5f; + static CEmphasisSample nullend; + nullend.time = endtime; + nullend.value = 0.5f; + + if ( number < 0 ) + { + return &nullstart; + } + else if ( number >= GetNumSamples() ) + { + return &nullend; + } + + return GetSample( number ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : time - +// type - +// Output : float +//----------------------------------------------------------------------------- +float CSentence::GetIntensity( float time, float endtime ) +{ + float zeroValue = 0.5f; + + int c = GetNumSamples(); + + if ( c <= 0 ) + { + return zeroValue; + } + + int i; + for ( i = -1 ; i < c; i++ ) + { + CEmphasisSample *s = GetBoundedSample( i, endtime ); + CEmphasisSample *n = GetBoundedSample( i + 1, endtime ); + if ( !s || !n ) + continue; + + if ( time >= s->time && time <= n->time ) + { + break; + } + } + + int prev = i - 1; + int start = i; + int end = i + 1; + int next = i + 2; + + prev = vmax( -1, prev ); + start = vmax( -1, start ); + end = vmin( end, GetNumSamples() ); + next = vmin( next, GetNumSamples() ); + + CEmphasisSample *esPre = GetBoundedSample( prev, endtime ); + CEmphasisSample *esStart = GetBoundedSample( start, endtime ); + CEmphasisSample *esEnd = GetBoundedSample( end, endtime ); + CEmphasisSample *esNext = GetBoundedSample( next, endtime ); + + float dt = esEnd->time - esStart->time; + dt = clamp( dt, 0.01f, 1.0f ); + + Vector vPre( esPre->time, esPre->value, 0 ); + Vector vStart( esStart->time, esStart->value, 0 ); + Vector vEnd( esEnd->time, esEnd->value, 0 ); + Vector vNext( esNext->time, esNext->value, 0 ); + + float f2 = ( time - esStart->time ) / ( dt ); + f2 = clamp( f2, 0.0f, 1.0f ); + + Vector vOut; + Catmull_Rom_Spline( + vPre, + vStart, + vEnd, + vNext, + f2, + vOut ); + + float retval = clamp( vOut.y, 0.0f, 1.0f ); + return retval; +} + +int CSentence::GetNumSamples( void ) +{ + return m_EmphasisSamples.Count(); +} + +CEmphasisSample *CSentence::GetSample( int index ) +{ + if ( index < 0 || index >= GetNumSamples() ) + return NULL; + + return &m_EmphasisSamples[ index ]; +} + +void CSentence::GetEstimatedTimes( float& start, float &end ) +{ +#if PHONEME_EDITOR + float beststart = 100000.0f; + float bestend = -100000.0f; + + int c = m_Words.Count(); + if ( !c ) + { + start = end = 0.0f; + return; + } + + for ( int i = 0; i< c; i++ ) + { + CWordTag *w = m_Words[ i ]; + Assert( w ); + if ( w->m_flStartTime < beststart ) + { + beststart = w->m_flStartTime; + } + if ( w->m_flEndTime > bestend ) + { + bestend = w->m_flEndTime; + } + } + + if ( beststart == 100000.0f ) + { + Assert( 0 ); + beststart = 0.0f; + } + if ( bestend == -100000.0f ) + { + Assert( 0 ); + bestend = 1.0f; + } + start = beststart; + end = bestend; +#endif +} + +void CSentence::SetDataCheckSum( unsigned int chk ) +{ +#if PHONEME_EDITOR + m_bStoreCheckSum = true; + m_uCheckSum = chk; +#endif +} + +unsigned int CSentence::ComputeDataCheckSum() +{ +#if PHONEME_EDITOR + int i; + int c; + CRC32_t crc; + CRC32_Init( &crc ); + + // Checksum the text + CRC32_ProcessBuffer( &crc, GetText(), Q_strlen( GetText() ) ); + // Checsum words and phonemes + c = m_Words.Count(); + for ( i = 0; i < c; ++i ) + { + CWordTag *word = m_Words[ i ]; + unsigned int wordCheckSum = word->ComputeDataCheckSum(); + CRC32_ProcessBuffer( &crc, &wordCheckSum, sizeof( unsigned int ) ); + } + + // Checksum emphasis data + c = m_EmphasisSamples.Count(); + for ( i = 0; i < c; ++i ) + { + CRC32_ProcessBuffer( &crc, &m_EmphasisSamples[ i ].time, sizeof( float ) ); + CRC32_ProcessBuffer( &crc, &m_EmphasisSamples[ i ].value, sizeof( float ) ); + } + + CRC32_Final( &crc ); + + return ( unsigned int )crc; +#else + Assert( 0 ); + return 0; +#endif +} + +unsigned int CSentence::GetDataCheckSum() const +{ +#if PHONEME_EDITOR + Assert( m_bStoreCheckSum ); + Assert( m_uCheckSum != 0 ); + return m_uCheckSum; +#else + Assert( 0 ); + return 0; +#endif +} + +#define STARTEND_TIMEGAP 0.1 + +int CSentence::CountWords( char const *str ) +{ + if ( !str || !str[ 0 ] ) + return 0; + + int c = 1; + + unsigned char *p = (unsigned char *)str; + while ( *p ) + { + if ( *p <= 32 ) + { + c++; + + while ( *p && *p <= 32 ) + { + p++; + } + } + + if ( !(*p) ) + break; + + p++; + } + + return c; +} + + +//----------------------------------------------------------------------------- +// Purpose: Static method +// Input : in - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CSentence::ShouldSplitWord( char in ) +{ + if ( in <= 32 ) + return true; + + if ( (unsigned char)in > SCHAR_MAX ) + return true; + + if ( ispunct( in ) ) + { + // don't split on apostrophe + if ( in == '\'' ) + return false; + return true; + } + + return false; +} + +void CSentence::CreateEventWordDistribution( char const *pszText, float flSentenceDuration ) +{ + Assert( pszText ); + if ( !pszText ) + return; + + int wordCount = CountWords( pszText ); + if ( wordCount <= 0 ) + return; + + float wordLength = ( flSentenceDuration - 2 * STARTEND_TIMEGAP) / (float)wordCount; + float wordStart = STARTEND_TIMEGAP; + + Reset(); + + char word[ 256 ]; + unsigned char const *in = (unsigned char *)pszText; + char *out = word; + + while ( *in ) + { + if ( !ShouldSplitWord( *in ) ) + { + *out++ = *in++; + } + else + { + *out = 0; + + // Skip over splitters + while ( *in && ( ShouldSplitWord( *in ) ) ) + { + in++; + } + + if ( strlen( word ) > 0 ) + { + CWordTag *w = new CWordTag(); + Assert( w ); + w->SetWord( word ); + w->m_flStartTime = wordStart; + w->m_flEndTime = wordStart + wordLength; + + AddWordTag( w ); + + wordStart += wordLength; + } + + out = word; + } + } + + *out = 0; + + if ( strlen( word ) > 0 ) + { + CWordTag *w = new CWordTag(); + Assert( w ); + w->SetWord( word ); + w->m_flStartTime = wordStart; + w->m_flEndTime = wordStart + wordLength; + + AddWordTag( w ); + + wordStart += wordLength; + } +} + + +#endif // !_STATIC_LINKED || _SHARED_LIB \ No newline at end of file diff --git a/public/sentence.h b/public/sentence.h new file mode 100644 index 0000000..de0f8d9 --- /dev/null +++ b/public/sentence.h @@ -0,0 +1,302 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SENTENCE_H +#define SENTENCE_H +#ifdef _WIN32 +#pragma once +#endif + +// X360 optimizes out the extra memory needed by the editors in these types +#ifndef _X360 +#define PHONEME_EDITOR 1 +#endif + +#include "utlvector.h" + +class CUtlBuffer; + +#define CACHED_SENTENCE_VERSION 1 +#define CACHED_SENTENCE_VERSION_ALIGNED 4 + +//----------------------------------------------------------------------------- +// Purpose: A sample point +//----------------------------------------------------------------------------- +// Can't do this due to backward compat issues +//#ifdef _WIN32 +//#pragma pack (1) +//#endif + +struct CEmphasisSample +{ + float time; + float value; + + void SetSelected( bool isSelected ); +#if PHONEME_EDITOR + // Used by editors only + bool selected; +#endif +}; + +class CBasePhonemeTag +{ +public: + CBasePhonemeTag(); + CBasePhonemeTag( const CBasePhonemeTag& from ); + + CBasePhonemeTag &operator=( const CBasePhonemeTag &from ) { memcpy( this, &from, sizeof(*this) ); return *this; } + + float GetStartTime() const { return m_flStartTime; } + void SetStartTime( float startTime ) { m_flStartTime = startTime; } + void AddStartTime( float startTime ) { m_flStartTime += startTime; } + + float GetEndTime() const { return m_flEndTime; } + void SetEndTime( float endTime ) { m_flEndTime = endTime; } + void AddEndTime( float startTime ) { m_flEndTime += startTime; } + + int GetPhonemeCode() const { return m_nPhonemeCode; } + void SetPhonemeCode( int phonemeCode ) { m_nPhonemeCode = phonemeCode; } + +private: + float m_flStartTime; + float m_flEndTime; + unsigned short m_nPhonemeCode; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CPhonemeTag : public CBasePhonemeTag +{ + typedef CBasePhonemeTag BaseClass; +public: + + CPhonemeTag( void ); + CPhonemeTag( const char *phoneme ); + CPhonemeTag( const CPhonemeTag& from ); + ~CPhonemeTag( void ); + + void SetTag( const char *phoneme ); + char const *GetTag() const; + + unsigned int ComputeDataCheckSum(); +#if PHONEME_EDITOR + bool m_bSelected; + unsigned int m_uiStartByte; + unsigned int m_uiEndByte; +#endif + void SetSelected( bool isSelected ); + bool GetSelected() const; + void SetStartAndEndBytes( unsigned int start, unsigned int end ); + unsigned int GetStartByte() const; + unsigned int GetEndByte() const; + +private: + char *m_szPhoneme; + +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CWordTag +{ +public: + CWordTag( void ); + CWordTag( const char *word ); + CWordTag( const CWordTag& from ); + ~CWordTag( void ); + + void SetWord( const char *word ); + const char *GetWord() const; + + int IndexOfPhoneme( CPhonemeTag *tag ); + + unsigned int ComputeDataCheckSum(); + + float m_flStartTime; + float m_flEndTime; + + CUtlVector < CPhonemeTag *> m_Phonemes; +#if PHONEME_EDITOR + bool m_bSelected; + unsigned int m_uiStartByte; + unsigned int m_uiEndByte; +#endif + void SetSelected( bool isSelected ); + bool GetSelected() const; + void SetStartAndEndBytes( unsigned int start, unsigned int end ); + unsigned int GetStartByte() const; + unsigned int GetEndByte() const; + +private: + char *m_pszWord; +}; + +// A sentence can be closed captioned +// The default case is the entire sentence shown at start time +// +// "The default case" +// "is the entire sentence shown at start time" + +// Commands that aren't closed at end of phrase are automatically terminated +// +// Commands +// The line should persist for 2.0 seconds beyond m_flEndTime +// Don't go to new line for next phrase on stack +// Push current color onto stack and start drawing with new +// color until we reach the next marker or a with no commands which +// means restore the previous color +// Underline text (start/end) +// Italics text (start/end) +// Bold text (start/end) +// Draw caption at special location ??? needed +// Go to new line + +// Close Captioning Support +// The phonemes drive the mouth in english, but the CC text can +// be one of several languages +enum +{ + CC_ENGLISH = 0, + CC_FRENCH, + CC_GERMAN, + CC_ITALIAN, + CC_KOREAN, + CC_SCHINESE, // Simplified Chinese + CC_SPANISH, + CC_TCHINESE, // Traditional Chinese + CC_JAPANESE, + CC_RUSSIAN, + CC_THAI, + CC_PORTUGUESE, + // etc etc + + CC_NUM_LANGUAGES +}; + +//----------------------------------------------------------------------------- +// Purpose: A sentence is a box of words, and words contain phonemes +//----------------------------------------------------------------------------- +class CSentence +{ +public: + static char const *NameForLanguage( int language ); + static int LanguageForName( char const *name ); + static void ColorForLanguage( int language, unsigned char& r, unsigned char& g, unsigned char& b ); + + // Construction + CSentence( void ); + ~CSentence( void ); + + // Assignment operator + CSentence& operator =(const CSentence& src ); + + void Append( float starttime, const CSentence& src ); + + void SetText( const char *text ); + const char *GetText( void ) const; + + void InitFromDataChunk( void *data, int size ); + void InitFromBuffer( CUtlBuffer& buf ); + void SaveToBuffer( CUtlBuffer& buf ); + + // This strips out all of the stuff used by the editor, leaving just one blank work, no sentence text, and just + // the phonemes without the phoneme text...(same as the cacherestore version below) + void MakeRuntimeOnly(); + + // This is a compressed save of just the data needed to drive phonemes in the engine (no word / sentence text, etc ) + void CacheSaveToBuffer( CUtlBuffer& buf, int version ); + void CacheRestoreFromBuffer( CUtlBuffer& buf ); + + // Add word/phoneme to sentence + void AddPhonemeTag( CWordTag *word, CPhonemeTag *tag ); + void AddWordTag( CWordTag *tag ); + + void Reset( void ); + + void ResetToBase( void ); + + void MarkNewPhraseBase( void ); + + int GetWordBase( void ); + + int CountPhonemes( void ); + + // For legacy loading, try to find a word that contains the time + CWordTag *EstimateBestWord( float time ); + + CWordTag *GetWordForPhoneme( CPhonemeTag *phoneme ); + + void SetTextFromWords( void ); + + float GetIntensity( float time, float endtime ); + void Resort( void ); + CEmphasisSample *GetBoundedSample( int number, float endtime ); + int GetNumSamples( void ); + CEmphasisSample *GetSample( int index ); + + // Compute start and endtime based on all words + void GetEstimatedTimes( float& start, float &end ); + + void SetVoiceDuck( bool shouldDuck ) { m_bShouldVoiceDuck = shouldDuck; } + bool GetVoiceDuck() const { return m_bShouldVoiceDuck; } + + unsigned int ComputeDataCheckSum(); + + void SetDataCheckSum( unsigned int chk ); + unsigned int GetDataCheckSum() const; + + int GetRuntimePhonemeCount() const; + const CBasePhonemeTag *GetRuntimePhoneme( int i ) const; + void ClearRuntimePhonemes(); + void AddRuntimePhoneme( const CPhonemeTag *src ); + + void CreateEventWordDistribution( char const *pszText, float flSentenceDuration ); + static int CountWords( char const *pszText ); + static bool ShouldSplitWord( char in ); + +public: +#if PHONEME_EDITOR + char *m_szText; + + CUtlVector< CWordTag * > m_Words; +#endif + CUtlVector < CBasePhonemeTag *> m_RunTimePhonemes; + +#if PHONEME_EDITOR + int m_nResetWordBase; +#endif + // Phoneme emphasis data + CUtlVector< CEmphasisSample > m_EmphasisSamples; + +#if PHONEME_EDITOR + unsigned int m_uCheckSum; +#endif + bool m_bIsValid : 8; + bool m_bStoreCheckSum : 8; + bool m_bShouldVoiceDuck : 8; + bool m_bIsCached : 8; + +private: + void ParseDataVersionOnePointZero( CUtlBuffer& buf ); + void ParsePlaintext( CUtlBuffer& buf ); + void ParseWords( CUtlBuffer& buf ); + void ParseEmphasis( CUtlBuffer& buf ); + void ParseOptions( CUtlBuffer& buf ); + void ParseCloseCaption( CUtlBuffer& buf ); + + void ResetCloseCaptionAll( void ); + + friend class PhonemeEditor; +}; + +//#ifdef _WIN32 +//#pragma pack () +//#endif + +#endif // SENTENCE_H diff --git a/public/server_class.cpp b/public/server_class.cpp new file mode 100644 index 0000000..5932f5b --- /dev/null +++ b/public/server_class.cpp @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "server_class.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ServerClass *g_pServerClassHead=0; + + diff --git a/public/server_class.h b/public/server_class.h new file mode 100644 index 0000000..ac96136 --- /dev/null +++ b/public/server_class.h @@ -0,0 +1,146 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef SERVER_CLASS_H +#define SERVER_CLASS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "dt_send.h" +#include "networkstringtabledefs.h" + + +class ServerClass; +class SendTable; + +extern ServerClass *g_pServerClassHead; + + +class ServerClass +{ +public: + ServerClass( const char *pNetworkName, SendTable *pTable ) + { + m_pNetworkName = pNetworkName; + m_pTable = pTable; + m_InstanceBaselineIndex = INVALID_STRING_INDEX; + // g_pServerClassHead is sorted alphabetically, so find the correct place to insert + if ( !g_pServerClassHead ) + { + g_pServerClassHead = this; + m_pNext = NULL; + } + else + { + ServerClass *p1 = g_pServerClassHead; + ServerClass *p2 = p1->m_pNext; + + // use _stricmp because Q_stricmp isn't hooked up properly yet + if ( _stricmp( p1->GetName(), pNetworkName ) > 0) + { + m_pNext = g_pServerClassHead; + g_pServerClassHead = this; + p1 = NULL; + } + + while( p1 ) + { + if ( p2 == NULL || _stricmp( p2->GetName(), pNetworkName ) > 0) + { + m_pNext = p2; + p1->m_pNext = this; + break; + } + p1 = p2; + p2 = p2->m_pNext; + } + } + } + + const char* GetName() { return m_pNetworkName; } + + +public: + const char *m_pNetworkName; + SendTable *m_pTable; + ServerClass *m_pNext; + int m_ClassID; // Managed by the engine. + + // This is an index into the network string table (sv.GetInstanceBaselineTable()). + int m_InstanceBaselineIndex; // INVALID_STRING_INDEX if not initialized yet. +}; + + +class CBaseNetworkable; + +// If you do a DECLARE_SERVERCLASS, you need to do this inside the class definition. +#define DECLARE_SERVERCLASS() \ + public: \ + virtual ServerClass* GetServerClass(); \ + static SendTable *m_pClassSendTable; \ + template friend int ServerClassInit(T *); \ + virtual int YouForgotToImplementOrDeclareServerClass(); \ + +#define DECLARE_SERVERCLASS_NOBASE() \ + public: \ + template friend int ServerClassInit(T *); \ + +// Use this macro to expose your class's data across the network. +#define IMPLEMENT_SERVERCLASS( DLLClassName, sendTable ) \ + IMPLEMENT_SERVERCLASS_INTERNAL( DLLClassName, sendTable ) + +// You can use this instead of BEGIN_SEND_TABLE and it will do a DECLARE_SERVERCLASS automatically. +#define IMPLEMENT_SERVERCLASS_ST(DLLClassName, sendTable) \ + IMPLEMENT_SERVERCLASS_INTERNAL( DLLClassName, sendTable )\ + BEGIN_SEND_TABLE(DLLClassName, sendTable) + +#define IMPLEMENT_SERVERCLASS_ST_NOBASE(DLLClassName, sendTable) \ + IMPLEMENT_SERVERCLASS_INTERNAL( DLLClassName, sendTable )\ + BEGIN_SEND_TABLE_NOBASE( DLLClassName, sendTable ) + + +#ifdef VALIDATE_DECLARE_CLASS + #define CHECK_DECLARE_CLASS( DLLClassName, sendTable ) \ + template int CheckDeclareClass_Access(T *); \ + template <> int CheckDeclareClass_Access(sendTable::ignored *, const char *pIgnored) \ + { \ + return DLLClassName::CheckDeclareClass( #DLLClassName ); \ + } \ + namespace sendTable \ + { \ + int verifyDeclareClass = CheckDeclareClass_Access( (sendTable::ignored*)0 ); \ + } +#else + #define CHECK_DECLARE_CLASS( DLLClassName, sendTable ) +#endif + + +#define IMPLEMENT_SERVERCLASS_INTERNAL( DLLClassName, sendTable ) \ + namespace sendTable \ + { \ + struct ignored; \ + extern SendTable g_SendTable; \ + } \ + CHECK_DECLARE_CLASS( DLLClassName, sendTable ) \ + static ServerClass g_##DLLClassName##_ClassReg(\ + #DLLClassName, \ + &sendTable::g_SendTable\ + ); \ + \ + ServerClass* DLLClassName::GetServerClass() {return &g_##DLLClassName##_ClassReg;} \ + SendTable *DLLClassName::m_pClassSendTable = &sendTable::g_SendTable;\ + int DLLClassName::YouForgotToImplementOrDeclareServerClass() {return 0;} + + +#endif + + + diff --git a/public/shaderapi/IShaderDevice.h b/public/shaderapi/IShaderDevice.h new file mode 100644 index 0000000..832e6ac --- /dev/null +++ b/public/shaderapi/IShaderDevice.h @@ -0,0 +1,390 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERDEVICE_H +#define ISHADERDEVICE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "appframework/IAppSystem.h" +#include "bitmap/imageformat.h" +#include "tier1/utlbuffer.h" +#include "materialsystem/imaterial.h" +#include "shaderapi/ishaderdynamic.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +struct MaterialAdapterInfo_t; +class IMesh; +class KeyValues; + + +//----------------------------------------------------------------------------- +// Describes how to set the mode +//----------------------------------------------------------------------------- +#define SHADER_DISPLAY_MODE_VERSION 1 + +struct ShaderDisplayMode_t +{ + ShaderDisplayMode_t() { memset( this, 0, sizeof(ShaderDisplayMode_t) ); m_nVersion = SHADER_DISPLAY_MODE_VERSION; } + + int m_nVersion; + int m_nWidth; // 0 when running windowed means use desktop resolution + int m_nHeight; + ImageFormat m_Format; // use ImageFormats (ignored for windowed mode) + int m_nRefreshRateNumerator; // Refresh rate. Use 0 in numerator + denominator for a default setting. + int m_nRefreshRateDenominator; // Refresh rate = numerator / denominator. +}; + + +//----------------------------------------------------------------------------- +// Describes how to set the device +//----------------------------------------------------------------------------- +#define SHADER_DEVICE_INFO_VERSION 1 + +struct ShaderDeviceInfo_t +{ + ShaderDeviceInfo_t() { memset( this, 0, sizeof(ShaderDeviceInfo_t) ); m_nVersion = SHADER_DEVICE_INFO_VERSION; m_DisplayMode.m_nVersion = SHADER_DISPLAY_MODE_VERSION; } + + int m_nVersion; + ShaderDisplayMode_t m_DisplayMode; + int m_nBackBufferCount; // valid values are 1 or 2 [2 results in triple buffering] + int m_nAASamples; // Number of AA samples to use + int m_nAAQuality; // AA quality level + int m_nDXLevel; // 0 means use recommended DX level for this adapter + int m_nWindowedSizeLimitWidth; // Used if m_bLimitWindowedSize is set, defines max bounds for the back buffer + int m_nWindowedSizeLimitHeight; + + bool m_bWindowed : 1; + bool m_bResizing : 1; // Only is meaningful when using windowed mode; means the window can be resized. + bool m_bUseStencil : 1; + bool m_bLimitWindowedSize : 1; // In windowed mode, should we prevent the back buffer from getting too large? + bool m_bWaitForVSync : 1; // Would we not present until vsync? + bool m_bScaleToOutputResolution : 1; // 360 ONLY: sets up hardware scaling + bool m_bProgressive : 1; // 360 ONLY: interlaced or progressive + bool m_bUsingMultipleWindows : 1; // Forces D3DPresent to use _COPY instead +}; + + +//----------------------------------------------------------------------------- +// Info for non-interactive mode +//----------------------------------------------------------------------------- +struct ShaderNonInteractiveInfo_t +{ + ShaderAPITextureHandle_t m_hTempFullscreenTexture; + int m_nPacifierCount; + ShaderAPITextureHandle_t m_pPacifierTextures[64]; + float m_flNormalizedX; + float m_flNormalizedY; + float m_flNormalizedSize; +}; + + +//----------------------------------------------------------------------------- +// For vertex/index buffers. What type is it? +// (NOTE: mirror this with a similarly named enum at the material system level for backwards compatability.) +//----------------------------------------------------------------------------- +enum ShaderBufferType_t +{ + SHADER_BUFFER_TYPE_STATIC = 0, + SHADER_BUFFER_TYPE_DYNAMIC, + SHADER_BUFFER_TYPE_STATIC_TEMP, + SHADER_BUFFER_TYPE_DYNAMIC_TEMP, + + SHADER_BUFFER_TYPE_COUNT, +}; + +inline bool IsDynamicBufferType( ShaderBufferType_t type ) +{ + return ( ( type == SHADER_BUFFER_TYPE_DYNAMIC ) || ( type == SHADER_BUFFER_TYPE_DYNAMIC_TEMP ) ); +} + + +//----------------------------------------------------------------------------- +// Handle to a vertex, pixel, and geometry shader +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE( VertexShaderHandle_t ); +DECLARE_POINTER_HANDLE( GeometryShaderHandle_t ); +DECLARE_POINTER_HANDLE( PixelShaderHandle_t ); + +#define VERTEX_SHADER_HANDLE_INVALID ( (VertexShaderHandle_t)0 ) +#define GEOMETRY_SHADER_HANDLE_INVALID ( (GeometryShaderHandle_t)0 ) +#define PIXEL_SHADER_HANDLE_INVALID ( (PixelShaderHandle_t)0 ) + + +//----------------------------------------------------------------------------- +// A shader buffer returns a block of memory which must be released when done with it +//----------------------------------------------------------------------------- +abstract_class IShaderBuffer +{ +public: + virtual size_t GetSize() const = 0; + virtual const void* GetBits() const = 0; + virtual void Release() = 0; +}; + + +//----------------------------------------------------------------------------- +// Mode chance callback +//----------------------------------------------------------------------------- +typedef void (*ShaderModeChangeCallbackFunc_t)( void ); + + +//----------------------------------------------------------------------------- +// Methods related to discovering and selecting devices +//----------------------------------------------------------------------------- +#define SHADER_DEVICE_MGR_INTERFACE_VERSION "ShaderDeviceMgr001" +abstract_class IShaderDeviceMgr : public IAppSystem +{ +public: + // Gets the number of adapters... + virtual int GetAdapterCount() const = 0; + + // Returns info about each adapter + virtual void GetAdapterInfo( int nAdapter, MaterialAdapterInfo_t& info ) const = 0; + + // Gets recommended congifuration for a particular adapter at a particular dx level + virtual bool GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, KeyValues *pConfiguration ) = 0; + + // Returns the number of modes + virtual int GetModeCount( int nAdapter ) const = 0; + + // Returns mode information.. + virtual void GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int nMode ) const = 0; + + // Returns the current mode info for the requested adapter + virtual void GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const = 0; + + // Initialization, shutdown + virtual bool SetAdapter( int nAdapter, int nFlags ) = 0; + + // Sets the mode + // Use the returned factory to get at an IShaderDevice and an IShaderRender + // and any other interfaces we decide to create. + // A returned factory of NULL indicates the mode was not set properly. + virtual CreateInterfaceFn SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode ) = 0; + + // Installs a callback to get called + virtual void AddModeChangeCallback( ShaderModeChangeCallbackFunc_t func ) = 0; + virtual void RemoveModeChangeCallback( ShaderModeChangeCallbackFunc_t func ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Methods related to control of the device +//----------------------------------------------------------------------------- +#define SHADER_DEVICE_INTERFACE_VERSION "ShaderDevice001" +abstract_class IShaderDevice +{ +public: + // Releases/reloads resources when other apps want some memory + virtual void ReleaseResources() = 0; + virtual void ReacquireResources() = 0; + + // returns the backbuffer format and dimensions + virtual ImageFormat GetBackBufferFormat() const = 0; + virtual void GetBackBufferDimensions( int& width, int& height ) const = 0; + + // Returns the current adapter in use + virtual int GetCurrentAdapter() const = 0; + + // Are we using graphics? + virtual bool IsUsingGraphics() const = 0; + + // Use this to spew information about the 3D layer + virtual void SpewDriverInfo() const = 0; + + // What's the bit depth of the stencil buffer? + virtual int StencilBufferBits() const = 0; + + // Are we using a mode that uses MSAA + virtual bool IsAAEnabled() const = 0; + + // Does a page flip + virtual void Present() = 0; + + // Returns the window size + virtual void GetWindowSize( int &nWidth, int &nHeight ) const = 0; + + // Gamma ramp control + virtual void SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled ) = 0; + + // Creates/ destroys a child window + virtual bool AddView( void* hWnd ) = 0; + virtual void RemoveView( void* hWnd ) = 0; + + // Activates a view + virtual void SetView( void* hWnd ) = 0; + + // Shader compilation + virtual IShaderBuffer* CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ) = 0; + + // Shader creation, destruction + virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer* pShaderBuffer ) = 0; + virtual void DestroyVertexShader( VertexShaderHandle_t hShader ) = 0; + virtual GeometryShaderHandle_t CreateGeometryShader( IShaderBuffer* pShaderBuffer ) = 0; + virtual void DestroyGeometryShader( GeometryShaderHandle_t hShader ) = 0; + virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer ) = 0; + virtual void DestroyPixelShader( PixelShaderHandle_t hShader ) = 0; + + // Utility methods to make shader creation simpler + // NOTE: For the utlbuffer version, use a binary buffer for a compiled shader + // and a text buffer for a source-code (.fxc) shader + VertexShaderHandle_t CreateVertexShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ); + VertexShaderHandle_t CreateVertexShader( CUtlBuffer &buf, const char *pShaderVersion = NULL ); + GeometryShaderHandle_t CreateGeometryShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ); + GeometryShaderHandle_t CreateGeometryShader( CUtlBuffer &buf, const char *pShaderVersion = NULL ); + PixelShaderHandle_t CreatePixelShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ); + PixelShaderHandle_t CreatePixelShader( CUtlBuffer &buf, const char *pShaderVersion = NULL ); + + // NOTE: Deprecated!! Use CreateVertexBuffer/CreateIndexBuffer instead + // Creates/destroys Mesh + virtual IMesh* CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial * pMaterial = NULL ) = 0; + virtual void DestroyStaticMesh( IMesh* mesh ) = 0; + + // Creates/destroys static vertex + index buffers + virtual IVertexBuffer *CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup ) = 0; + virtual void DestroyVertexBuffer( IVertexBuffer *pVertexBuffer ) = 0; + + virtual IIndexBuffer *CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup ) = 0; + virtual void DestroyIndexBuffer( IIndexBuffer *pIndexBuffer ) = 0; + + // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams? + virtual IVertexBuffer *GetDynamicVertexBuffer( int nStreamID, VertexFormat_t vertexFormat, bool bBuffered = true ) = 0; + virtual IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true ) = 0; + + // A special path used to tick the front buffer while loading on the 360 + virtual void EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode, ShaderNonInteractiveInfo_t *pInfo = NULL ) = 0; + virtual void RefreshFrontBufferNonInteractive( ) = 0; + virtual void HandleThreadEvent( uint32 threadEvent ) = 0; + +#ifdef DX_TO_GL_ABSTRACTION + virtual void DoStartupShaderPreloading( void ) = 0; +#endif + virtual char *GetDisplayDeviceName() = 0; + +}; + + +//----------------------------------------------------------------------------- +// Helper wrapper for IShaderBuffer for reading precompiled shader files +// NOTE: This is meant to be instanced on the stack; so don't call Release! +//----------------------------------------------------------------------------- +class CUtlShaderBuffer : public IShaderBuffer +{ +public: + CUtlShaderBuffer( CUtlBuffer &buf ) : m_pBuf( &buf ) {} + + virtual size_t GetSize() const + { + return m_pBuf->TellMaxPut(); + } + + virtual const void* GetBits() const + { + return m_pBuf->Base(); + } + + virtual void Release() + { + Assert( 0 ); + } + +private: + CUtlBuffer *m_pBuf; +}; + + +//----------------------------------------------------------------------------- +// Inline methods of IShaderDevice +//----------------------------------------------------------------------------- +inline VertexShaderHandle_t IShaderDevice::CreateVertexShader( CUtlBuffer &buf, const char *pShaderVersion ) +{ + // NOTE: Text buffers are assumed to have source-code shader files + // Binary buffers are assumed to have compiled shader files + if ( buf.IsText() ) + { + Assert( pShaderVersion ); + return CreateVertexShader( (const char *)buf.Base(), buf.TellMaxPut(), pShaderVersion ); + } + + CUtlShaderBuffer shaderBuffer( buf ); + return CreateVertexShader( &shaderBuffer ); +} + +inline VertexShaderHandle_t IShaderDevice::CreateVertexShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ) +{ + VertexShaderHandle_t hVertexShader = VERTEX_SHADER_HANDLE_INVALID; + IShaderBuffer* pShaderBuffer = CompileShader( pProgram, nBufLen, pShaderVersion ); + if ( pShaderBuffer ) + { + hVertexShader = CreateVertexShader( pShaderBuffer ); + pShaderBuffer->Release(); + } + return hVertexShader; +} + +inline GeometryShaderHandle_t IShaderDevice::CreateGeometryShader( CUtlBuffer &buf, const char *pShaderVersion ) +{ + // NOTE: Text buffers are assumed to have source-code shader files + // Binary buffers are assumed to have compiled shader files + if ( buf.IsText() ) + { + Assert( pShaderVersion ); + return CreateGeometryShader( (const char *)buf.Base(), buf.TellMaxPut(), pShaderVersion ); + } + + CUtlShaderBuffer shaderBuffer( buf ); + return CreateGeometryShader( &shaderBuffer ); +} + +inline GeometryShaderHandle_t IShaderDevice::CreateGeometryShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ) +{ + GeometryShaderHandle_t hGeometryShader = GEOMETRY_SHADER_HANDLE_INVALID; + IShaderBuffer* pShaderBuffer = CompileShader( pProgram, nBufLen, pShaderVersion ); + if ( pShaderBuffer ) + { + hGeometryShader = CreateGeometryShader( pShaderBuffer ); + pShaderBuffer->Release(); + } + return hGeometryShader; +} + +inline PixelShaderHandle_t IShaderDevice::CreatePixelShader( CUtlBuffer &buf, const char *pShaderVersion ) +{ + // NOTE: Text buffers are assumed to have source-code shader files + // Binary buffers are assumed to have compiled shader files + if ( buf.IsText() ) + { + Assert( pShaderVersion ); + return CreatePixelShader( (const char *)buf.Base(), buf.TellMaxPut(), pShaderVersion ); + } + + CUtlShaderBuffer shaderBuffer( buf ); + return CreatePixelShader( &shaderBuffer ); +} + +inline PixelShaderHandle_t IShaderDevice::CreatePixelShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ) +{ + PixelShaderHandle_t hPixelShader = PIXEL_SHADER_HANDLE_INVALID; + IShaderBuffer* pShaderBuffer = CompileShader( pProgram, nBufLen, pShaderVersion ); + if ( pShaderBuffer ) + { + hPixelShader = CreatePixelShader( pShaderBuffer ); + pShaderBuffer->Release(); + } + return hPixelShader; +} + + +#endif // ISHADERDEVICE_H diff --git a/public/shaderapi/commandbuffer.h b/public/shaderapi/commandbuffer.h new file mode 100644 index 0000000..de79915 --- /dev/null +++ b/public/shaderapi/commandbuffer.h @@ -0,0 +1,108 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// This file defines a number of constants and structured which are used to build up a command +// buffer to pass to ShaderAPI for state setting and other operations. Since the prupose of these +// command buffers is to minimize and optimize calls into shaderapi, their structure is not +// abstract - they are built out by the calling process. +// +//===========================================================================// + +#ifndef COMMANDBUFFER_H +#define COMMANDBUFFER_H + + +#ifdef _WIN32 +#pragma once +#endif + +// all commands defined with their struct +enum CommandBufferCommand_t +{ + // flow control commands. + CBCMD_END = 0, // end of stream + CBCMD_JUMP = 1, // int cmd, void *adr. jump to another + // stream. Can be used to implement + // non-sequentially allocated storage + CBCMD_JSR = 2, // int cmd, void *adr. subroutine call to another stream. + + // constant setting commands + CBCMD_SET_PIXEL_SHADER_FLOAT_CONST = 256, // int cmd,int first_reg, int nregs, float values[nregs*4] + + + CBCMD_SET_VERTEX_SHADER_FLOAT_CONST = 257, // int cmd,int first_reg, int nregs, float values[nregs*4] + CBCMD_SET_VERTEX_SHADER_FLOAT_CONST_REF = 258, // int cmd,int first_reg, int nregs, &float values[nregs*4] + CBCMD_SETPIXELSHADERFOGPARAMS = 259, // int cmd, int regdest + CBCMD_STORE_EYE_POS_IN_PSCONST = 260, // int cmd, int regdest + CBCMD_COMMITPIXELSHADERLIGHTING = 261, // int cmd, int regdest + CBCMD_SETPIXELSHADERSTATEAMBIENTLIGHTCUBE = 262, // int cmd, int regdest + CBCMD_SETAMBIENTCUBEDYNAMICSTATEVERTEXSHADER = 263, // int cmd + CBCMD_SET_DEPTH_FEATHERING_CONST = 264, // int cmd, int constant register, float blend scale + + // texture binding + CBCMD_BIND_STANDARD_TEXTURE = 512, // cmd, sampler, texture id + CBCMD_BIND_SHADERAPI_TEXTURE_HANDLE = 513, // cmd, sampler, texture handle + + // shaders + CBCMD_SET_PSHINDEX = 1024, // cmd, idx + CBCMD_SET_VSHINDEX = 1025, // cmd, idx + + // commands from mainline. In mainline commands no longer have + // command id's specified like this. So I make up numbers... + CBCMD_SET_VERTEX_SHADER_FLASHLIGHT_STATE = 2000, // cmd, int first_reg (for worldToTexture matrix) + CBCMD_SET_PIXEL_SHADER_FLASHLIGHT_STATE = 2001, // cmd, int color reg, int atten reg, int origin reg, sampler (for flashlight texture) + + CBCMD_SET_PIXEL_SHADER_UBERLIGHT_STATE = 2002, // cmd + + CBCMD_SET_VERTEX_SHADER_NEARZFARZ_STATE = 2003, // cmd + +}; + +//----------------------------------------------------------------------------- +// Commands used by the per-instance command buffer +// NOTE: If you add commands, you probably want to change the size of +// CInstanceStorageBuffer and/or the choice of making it a fixed-size allocation +// see shaderlib/baseshader.* +// +// FIXME!! NOTE that this whole scheme here generates a dependency of the +// shaders on internal guts of shaderapidx8, since it's responsible for +// setting various pixel shader + vertex shader constants based on the +// commands below. We need to remove this dependency as it's way too restrictive +// and puts the smarts in the wrong place (see CBICMD_SETPIXELSHADERGLINTDAMPING +// as an example). Not going to solve this for l4d though, as I don't anticipate +// a large amount of new shader writing for that product. +//----------------------------------------------------------------------------- +enum CommandBufferInstanceCommand_t +{ + CBICMD_END = 0, // end of stream + CBICMD_JUMP, // int cmd, void *adr. jump to another + // stream. Can be used to implement + // non-sequentially allocated storage + CBICMD_JSR, // int cmd, void *adr. subroutine call to another stream. + + CBICMD_SETSKINNINGMATRICES, // int cmd + + CBICMD_SETVERTEXSHADERLOCALLIGHTING, // int cmd + CBICMD_SETPIXELSHADERLOCALLIGHTING, // int cmd, int regdest + CBICMD_SETVERTEXSHADERAMBIENTLIGHTCUBE, // int cmd + CBICMD_SETPIXELSHADERAMBIENTLIGHTCUBE, // int cmd, int regdest + CBICMD_SETPIXELSHADERAMBIENTLIGHTCUBELUMINANCE, // int cmd, int regdest + CBICMD_SETPIXELSHADERGLINTDAMPING, // int cmd, int regdest + + CBICMD_BIND_ENV_CUBEMAP_TEXTURE, // cmd, sampler + + CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE, + CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARCOLORSPACE_LINEARSCALE, // int cmd, int constant register, Vector color2 + CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARCOLORSPACE, // int cmd, int constant register, Vector color2 + CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARSCALE, // int cmd, int constant register, Vector color2, float scale + CBICMD_SETMODULATIONVERTEXSHADERDYNAMICSTATE, // int cmd, int constant register, Vector color2 + CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_IDENTITY, // int cmd, int constant register + CBICMD_SETMODULATIONVERTEXSHADERDYNAMICSTATE_LINEARSCALE, // int cmd, int constant register, Vector color2, float scale + // This must be last + CBICMD_COUNT, +}; + +#endif // commandbuffer_h diff --git a/public/shaderapi/ishaderapi.h b/public/shaderapi/ishaderapi.h new file mode 100644 index 0000000..1a90cae --- /dev/null +++ b/public/shaderapi/ishaderapi.h @@ -0,0 +1,624 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERAPI_H +#define ISHADERAPI_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector4d.h" +#include "shaderapi/ishaderdynamic.h" +#include "shaderapi/IShaderDevice.h" +#include "materialsystem/deformations.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IShaderUtil; +class IFileSystem; +class CPixelWriter; +class CMeshBuilder; +struct MaterialVideoMode_t; +class IMesh; +class IVertexBuffer; +class IIndexBuffer; +struct MeshDesc_t; +enum MaterialCullMode_t; +class IDataCache; +struct MorphWeight_t; +class IVTFTexture; + + +//----------------------------------------------------------------------------- +// This must match the definition in playback.cpp! +//----------------------------------------------------------------------------- +enum ShaderRenderTarget_t +{ + SHADER_RENDERTARGET_BACKBUFFER = -1, + SHADER_RENDERTARGET_DEPTHBUFFER = -1, + // GR - no RT, used to disable depth buffer + SHADER_RENDERTARGET_NONE = -2, +}; + + +//----------------------------------------------------------------------------- +// This must match the definition in playback.cpp! +//----------------------------------------------------------------------------- +typedef int ShaderAPITextureHandle_t; +#define INVALID_SHADERAPI_TEXTURE_HANDLE 0 + + +//----------------------------------------------------------------------------- +// The state snapshot handle +//----------------------------------------------------------------------------- +typedef short StateSnapshot_t; + + +//----------------------------------------------------------------------------- +// The state snapshot handle +//----------------------------------------------------------------------------- +typedef int ShaderDLL_t; + + +//----------------------------------------------------------------------------- +// Texture creation +//----------------------------------------------------------------------------- +enum CreateTextureFlags_t +{ + TEXTURE_CREATE_CUBEMAP = 0x0001, + TEXTURE_CREATE_RENDERTARGET = 0x0002, + TEXTURE_CREATE_MANAGED = 0x0004, + TEXTURE_CREATE_DEPTHBUFFER = 0x0008, + TEXTURE_CREATE_DYNAMIC = 0x0010, + TEXTURE_CREATE_AUTOMIPMAP = 0x0020, + TEXTURE_CREATE_VERTEXTEXTURE = 0x0040, // for internal use only + TEXTURE_CREATE_FALLBACK = 0x0080, // 360 only + TEXTURE_CREATE_NOD3DMEMORY = 0x0100, // 360 only + TEXTURE_CREATE_SYSMEM = 0x0200, // This texture should be alloc'd in the sysmem pool + TEXTURE_CREATE_UNUSED4 = 0x0400, // Dead + TEXTURE_CREATE_UNUSED5 = 0x0800, // Dead + TEXTURE_CREATE_UNFILTERABLE_OK = 0x1000, + TEXTURE_CREATE_CANCONVERTFORMAT = 0x2000, // 360 only, allow format conversions at load + TEXTURE_CREATE_SRGB = 0x4000, // Posix/GL only, for textures which are SRGB-readable + +}; + + + +//----------------------------------------------------------------------------- +// Fill modes +//----------------------------------------------------------------------------- +enum ShaderFillMode_t +{ + SHADER_FILL_SOLID = 0, + SHADER_FILL_WIREFRAME, +}; + + +//----------------------------------------------------------------------------- +// Rasterization state object +//----------------------------------------------------------------------------- +struct ShaderRasterState_t +{ + ShaderFillMode_t m_FillMode; + MaterialCullMode_t m_CullMode; + bool m_bCullEnable : 1; + bool m_bDepthBias : 1; + bool m_bScissorEnable : 1; + bool m_bMultisampleEnable : 1; +}; + + +//----------------------------------------------------------------------------- +// Used for occlusion queries +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE( ShaderAPIOcclusionQuery_t ); +#define INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ( (ShaderAPIOcclusionQuery_t)0 ) + +enum ShaderAPIOcclusionQueryResult_t +{ + OCCLUSION_QUERY_RESULT_PENDING = -1, + OCCLUSION_QUERY_RESULT_ERROR = -2 +}; +#define OCCLUSION_QUERY_FINISHED( iQueryResult ) ( ( iQueryResult ) != OCCLUSION_QUERY_RESULT_PENDING ) + + +//----------------------------------------------------------------------------- +// This is what the material system gets to see. +//----------------------------------------------------------------------------- +#define SHADERAPI_INTERFACE_VERSION "ShaderApi030" +abstract_class IShaderAPI : public IShaderDynamicAPI +{ +public: + // + // NOTE: These methods have been ported to DX10 + // + + // Viewport methods + virtual void SetViewports( int nCount, const ShaderViewport_t* pViewports ) = 0; + virtual int GetViewports( ShaderViewport_t* pViewports, int nMax ) const = 0; + + // Buffer clearing + virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight ) = 0; + virtual void ClearColor3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) = 0; + + // Methods related to binding shaders + virtual void BindVertexShader( VertexShaderHandle_t hVertexShader ) = 0; + virtual void BindGeometryShader( GeometryShaderHandle_t hGeometryShader ) = 0; + virtual void BindPixelShader( PixelShaderHandle_t hPixelShader ) = 0; + + // Methods related to state objects + virtual void SetRasterState( const ShaderRasterState_t& state ) = 0; + + // + // NOTE: These methods have not yet been ported to DX10 + // + + // Sets the mode... + virtual bool SetMode( void* hwnd, int nAdapter, const ShaderDeviceInfo_t &info ) = 0; + + virtual void ChangeVideoMode( const ShaderDeviceInfo_t &info ) = 0; + + // Returns the snapshot id for the shader state + virtual StateSnapshot_t TakeSnapshot( ) = 0; + + virtual void TexMinFilter( ShaderTexFilterMode_t texFilterMode ) = 0; + virtual void TexMagFilter( ShaderTexFilterMode_t texFilterMode ) = 0; + virtual void TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode ) = 0; + + virtual void CopyRenderTargetToTexture( ShaderAPITextureHandle_t textureHandle ) = 0; + + // Binds a particular material to render with + virtual void Bind( IMaterial* pMaterial ) = 0; + + // Flushes any primitives that are buffered + virtual void FlushBufferedPrimitives() = 0; + + // Gets the dynamic mesh; note that you've got to render the mesh + // before calling this function a second time. Clients should *not* + // call DestroyStaticMesh on the mesh returned by this call. + virtual IMesh* GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool bBuffered = true, + IMesh* pVertexOverride = 0, IMesh* pIndexOverride = 0) = 0; + virtual IMesh* GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount, + bool bBuffered = true, IMesh* pVertexOverride = 0, IMesh* pIndexOverride = 0 ) = 0; + + // Methods to ask about particular state snapshots + virtual bool IsTranslucent( StateSnapshot_t id ) const = 0; + virtual bool IsAlphaTested( StateSnapshot_t id ) const = 0; + virtual bool UsesVertexAndPixelShaders( StateSnapshot_t id ) const = 0; + virtual bool IsDepthWriteEnabled( StateSnapshot_t id ) const = 0; + + // Gets the vertex format for a set of snapshot ids + virtual VertexFormat_t ComputeVertexFormat( int numSnapshots, StateSnapshot_t* pIds ) const = 0; + + // What fields in the vertex do we actually use? + virtual VertexFormat_t ComputeVertexUsage( int numSnapshots, StateSnapshot_t* pIds ) const = 0; + + // Begins a rendering pass + virtual void BeginPass( StateSnapshot_t snapshot ) = 0; + + // Renders a single pass of a material + virtual void RenderPass( int nPass, int nPassCount ) = 0; + + // Set the number of bone weights + virtual void SetNumBoneWeights( int numBones ) = 0; + + // Sets the lights + virtual void SetLight( int lightNum, const LightDesc_t& desc ) = 0; + + // Lighting origin for the current model + virtual void SetLightingOrigin( Vector vLightingOrigin ) = 0; + + virtual void SetAmbientLight( float r, float g, float b ) = 0; + virtual void SetAmbientLightCube( Vector4D cube[6] ) = 0; + + // The shade mode + virtual void ShadeMode( ShaderShadeMode_t mode ) = 0; + + // The cull mode + virtual void CullMode( MaterialCullMode_t cullMode ) = 0; + + // Force writes only when z matches. . . useful for stenciling things out + // by rendering the desired Z values ahead of time. + virtual void ForceDepthFuncEquals( bool bEnable ) = 0; + + // Forces Z buffering to be on or off + virtual void OverrideDepthEnable( bool bEnable, bool bDepthEnable ) = 0; + + virtual void SetHeightClipZ( float z ) = 0; + virtual void SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode ) = 0; + + virtual void SetClipPlane( int index, const float *pPlane ) = 0; + virtual void EnableClipPlane( int index, bool bEnable ) = 0; + + // Put all the model matrices into vertex shader constants. + virtual void SetSkinningMatrices() = 0; + + // Returns the nearest supported format + virtual ImageFormat GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired = true ) const = 0; + virtual ImageFormat GetNearestRenderTargetFormat( ImageFormat fmt ) const = 0; + + // When AA is enabled, render targets are not AA and require a separate + // depth buffer. + virtual bool DoRenderTargetsNeedSeparateDepthBuffer() const = 0; + + // Texture management methods + // For CreateTexture also see CreateTextures below + virtual ShaderAPITextureHandle_t CreateTexture( + int width, + int height, + int depth, + ImageFormat dstImageFormat, + int numMipLevels, + int numCopies, + int flags, + const char *pDebugName, + const char *pTextureGroupName ) = 0; + + virtual void DeleteTexture( ShaderAPITextureHandle_t textureHandle ) = 0; + + virtual ShaderAPITextureHandle_t CreateDepthTexture( + ImageFormat renderTargetFormat, + int width, + int height, + const char *pDebugName, + bool bTexture ) = 0; + + virtual bool IsTexture( ShaderAPITextureHandle_t textureHandle ) = 0; + virtual bool IsTextureResident( ShaderAPITextureHandle_t textureHandle ) = 0; + + // Indicates we're going to be modifying this texture + // TexImage2D, TexSubImage2D, TexWrap, TexMinFilter, and TexMagFilter + // all use the texture specified by this function. + virtual void ModifyTexture( ShaderAPITextureHandle_t textureHandle ) = 0; + + virtual void TexImage2D( + int level, + int cubeFaceID, + ImageFormat dstFormat, + int zOffset, + int width, + int height, + ImageFormat srcFormat, + bool bSrcIsTiled, // NOTE: for X360 only + void *imageData ) = 0; + + virtual void TexSubImage2D( + int level, + int cubeFaceID, + int xOffset, + int yOffset, + int zOffset, + int width, + int height, + ImageFormat srcFormat, + int srcStride, + bool bSrcIsTiled, // NOTE: for X360 only + void *imageData ) = 0; + + virtual void TexImageFromVTF( IVTFTexture* pVTF, int iVTFFrame ) = 0; + + // An alternate (and faster) way of writing image data + // (locks the current Modify Texture). Use the pixel writer to write the data + // after Lock is called + // Doesn't work for compressed textures + virtual bool TexLock( int level, int cubeFaceID, int xOffset, int yOffset, + int width, int height, CPixelWriter& writer ) = 0; + virtual void TexUnlock( ) = 0; + + // These are bound to the texture + virtual void TexSetPriority( int priority ) = 0; + + // Sets the texture state + virtual void BindTexture( Sampler_t sampler, ShaderAPITextureHandle_t textureHandle ) = 0; + + // Set the render target to a texID. + // Set to SHADER_RENDERTARGET_BACKBUFFER if you want to use the regular framebuffer. + // Set to SHADER_RENDERTARGET_DEPTHBUFFER if you want to use the regular z buffer. + virtual void SetRenderTarget( ShaderAPITextureHandle_t colorTextureHandle = SHADER_RENDERTARGET_BACKBUFFER, + ShaderAPITextureHandle_t depthTextureHandle = SHADER_RENDERTARGET_DEPTHBUFFER ) = 0; + + // stuff that isn't to be used from within a shader + virtual void ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth ) = 0; + virtual void ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat ) = 0; + virtual void ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *data, ImageFormat dstFormat, int nDstStride ) = 0; + + virtual void FlushHardware() = 0; + + // Use this to begin and end the frame + virtual void BeginFrame() = 0; + virtual void EndFrame() = 0; + + // Selection mode methods + virtual int SelectionMode( bool selectionMode ) = 0; + virtual void SelectionBuffer( unsigned int* pBuffer, int size ) = 0; + virtual void ClearSelectionNames( ) = 0; + virtual void LoadSelectionName( int name ) = 0; + virtual void PushSelectionName( int name ) = 0; + virtual void PopSelectionName() = 0; + + // Force the hardware to finish whatever it's doing + virtual void ForceHardwareSync() = 0; + + // Used to clear the transition table when we know it's become invalid. + virtual void ClearSnapshots() = 0; + + virtual void FogStart( float fStart ) = 0; + virtual void FogEnd( float fEnd ) = 0; + virtual void SetFogZ( float fogZ ) = 0; + // Scene fog state. + virtual void SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void GetSceneFogColor( unsigned char *rgb ) = 0; + virtual void SceneFogMode( MaterialFogMode_t fogMode ) = 0; + + // Can we download textures? + virtual bool CanDownloadTextures() const = 0; + + virtual void ResetRenderState( bool bFullReset = true ) = 0; + + // We use smaller dynamic VBs during level transitions, to free up memory + virtual int GetCurrentDynamicVBSize( void ) = 0; + virtual void DestroyVertexBuffers( bool bExitingLevel = false ) = 0; + + virtual void EvictManagedResources() = 0; + + // Level of anisotropic filtering + virtual void SetAnisotropicLevel( int nAnisotropyLevel ) = 0; + + // For debugging and building recording files. This will stuff a token into the recording file, + // then someone doing a playback can watch for the token. + virtual void SyncToken( const char *pToken ) = 0; + + // Setup standard vertex shader constants (that don't change) + // This needs to be called anytime that overbright changes. + virtual void SetStandardVertexShaderConstants( float fOverbright ) = 0; + + // + // Occlusion query support + // + + // Allocate and delete query objects. + virtual ShaderAPIOcclusionQuery_t CreateOcclusionQueryObject( void ) = 0; + virtual void DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t ) = 0; + + // Bracket drawing with begin and end so that we can get counts next frame. + virtual void BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t ) = 0; + virtual void EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t ) = 0; + + // OcclusionQuery_GetNumPixelsRendered + // Get the number of pixels rendered between begin and end on an earlier frame. + // Calling this in the same frame is a huge perf hit! + // Returns iQueryResult: + // iQueryResult >= 0 - iQueryResult is the number of pixels rendered + // OCCLUSION_QUERY_RESULT_PENDING - query results are not available yet + // OCCLUSION_QUERY_RESULT_ERROR - query failed + // Use OCCLUSION_QUERY_FINISHED( iQueryResult ) to test if query finished. + virtual int OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t hQuery, bool bFlush = false ) = 0; + + virtual void SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture ) = 0; + + virtual void ClearVertexAndPixelShaderRefCounts() = 0; + virtual void PurgeUnusedVertexAndPixelShaders() = 0; + + // Called when the dx support level has changed + virtual void DXSupportLevelChanged() = 0; + + // By default, the material system applies the VIEW and PROJECTION matrices to the user clip + // planes (which are specified in world space) to generate projection-space user clip planes + // Occasionally (for the particle system in hl2, for example), we want to override that + // behavior and explictly specify a View transform for user clip planes. The PROJECTION + // will be mutliplied against this instead of the normal VIEW matrix. + virtual void EnableUserClipTransformOverride( bool bEnable ) = 0; + virtual void UserClipTransform( const VMatrix &worldToView ) = 0; + + // ---------------------------------------------------------------------------------- + // Everything after this point added after HL2 shipped. + // ---------------------------------------------------------------------------------- + + // What fields in the morph do we actually use? + virtual MorphFormat_t ComputeMorphFormat( int numSnapshots, StateSnapshot_t* pIds ) const = 0; + + // Set the render target to a texID. + // Set to SHADER_RENDERTARGET_BACKBUFFER if you want to use the regular framebuffer. + // Set to SHADER_RENDERTARGET_DEPTHBUFFER if you want to use the regular z buffer. + virtual void SetRenderTargetEx( int nRenderTargetID, + ShaderAPITextureHandle_t colorTextureHandle = SHADER_RENDERTARGET_BACKBUFFER, + ShaderAPITextureHandle_t depthTextureHandle = SHADER_RENDERTARGET_DEPTHBUFFER ) = 0; + + virtual void CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t textureHandle, int nRenderTargetID, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL ) = 0; + virtual void CopyTextureToRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL ) = 0; + + // For dealing with device lost in cases where SwapBuffers isn't called all the time (Hammer) + virtual void HandleDeviceLost() = 0; + + virtual void EnableLinearColorSpaceFrameBuffer( bool bEnable ) = 0; + + // Lets the shader know about the full-screen texture so it can + virtual void SetFullScreenTextureHandle( ShaderAPITextureHandle_t h ) = 0; + + // Rendering parameters control special drawing modes withing the material system, shader + // system, shaders, and engine. renderparm.h has their definitions. + virtual void SetFloatRenderingParameter(int parm_number, float value) = 0; + virtual void SetIntRenderingParameter(int parm_number, int value) = 0; + virtual void SetVectorRenderingParameter(int parm_number, Vector const &value) = 0; + + virtual float GetFloatRenderingParameter(int parm_number) const = 0; + virtual int GetIntRenderingParameter(int parm_number) const = 0; + virtual Vector GetVectorRenderingParameter(int parm_number) const = 0; + + virtual void SetFastClipPlane( const float *pPlane ) = 0; + virtual void EnableFastClip( bool bEnable ) = 0; + + // Returns the number of vertices + indices we can render using the dynamic mesh + // Passing true in the second parameter will return the max # of vertices + indices + // we can use before a flush is provoked and may return different values + // if called multiple times in succession. + // Passing false into the second parameter will return + // the maximum possible vertices + indices that can be rendered in a single batch + virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices ) = 0; + + // Returns the max number of vertices we can render for a given material + virtual int GetMaxVerticesToRender( IMaterial *pMaterial ) = 0; + virtual int GetMaxIndicesToRender( ) = 0; + + // stencil methods + virtual void SetStencilEnable(bool onoff) = 0; + virtual void SetStencilFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilZFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilPassOperation(StencilOperation_t op) = 0; + virtual void SetStencilCompareFunction(StencilComparisonFunction_t cmpfn) = 0; + virtual void SetStencilReferenceValue(int ref) = 0; + virtual void SetStencilTestMask(uint32 msk) = 0; + virtual void SetStencilWriteMask(uint32 msk) = 0; + virtual void ClearStencilBufferRectangle(int xmin, int ymin, int xmax, int ymax, int value) = 0; + + // disables all local lights + virtual void DisableAllLocalLights() = 0; + virtual int CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 ) = 0; + + virtual IMesh *GetFlexMesh() = 0; + + virtual void SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture ) = 0; + + virtual bool SupportsMSAAMode( int nMSAAMode ) = 0; + +#if defined( _X360 ) + virtual HXUIFONT OpenTrueTypeFont( const char *pFontname, int tall, int style ) = 0; + virtual void CloseTrueTypeFont( HXUIFONT hFont ) = 0; + virtual bool GetTrueTypeFontMetrics( HXUIFONT hFont, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] ) = 0; + // Render a sequence of characters and extract the data into a buffer + // For each character, provide the width+height of the font texture subrect, + // an offset to apply when rendering the glyph, and an offset into a buffer to receive the RGBA data + virtual bool GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset ) = 0; + virtual ShaderAPITextureHandle_t CreateRenderTargetSurface( int width, int height, ImageFormat format, const char *pDebugName, const char *pTextureGroupName ) = 0; + virtual void PersistDisplay() = 0; + virtual bool PostQueuedTexture( const void *pData, int nSize, ShaderAPITextureHandle_t *pHandles, int nHandles, int nWidth, int nHeight, int nDepth, int nMips, int *pRefCount ) = 0; + virtual void *GetD3DDevice() = 0; + + virtual void PushVertexShaderGPRAllocation( int iVertexShaderCount = 64 ) = 0; + virtual void PopVertexShaderGPRAllocation( void ) = 0; + + virtual void EnableVSync_360( bool bEnable ) = 0; //360 allows us to bypass vsync blocking up to 60 fps without creating a new device +#endif + + virtual bool OwnGPUResources( bool bEnable ) = 0; + + //get fog distances entered with FogStart(), FogEnd(), and SetFogZ() + virtual void GetFogDistances( float *fStart, float *fEnd, float *fFogZ ) = 0; + + // Hooks for firing PIX events from outside the Material System... + virtual void BeginPIXEvent( unsigned long color, const char *szName ) = 0; + virtual void EndPIXEvent() = 0; + virtual void SetPIXMarker( unsigned long color, const char *szName ) = 0; + + // Enables and disables for Alpha To Coverage + virtual void EnableAlphaToCoverage() = 0; + virtual void DisableAlphaToCoverage() = 0; + + // Computes the vertex buffer pointers + virtual void ComputeVertexDescription( unsigned char* pBuffer, VertexFormat_t vertexFormat, MeshDesc_t& desc ) const = 0; + + virtual bool SupportsShadowDepthTextures( void ) = 0; + + virtual void SetDisallowAccess( bool ) = 0; + virtual void EnableShaderShaderMutex( bool ) = 0; + virtual void ShaderLock() = 0; + virtual void ShaderUnlock() = 0; + + virtual ImageFormat GetShadowDepthTextureFormat( void ) = 0; + + virtual bool SupportsFetch4( void ) = 0; + virtual void SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias ) = 0; + +// ------------ New Vertex/Index Buffer interface ---------------------------- + virtual void BindVertexBuffer( int nStreamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 ) = 0; + virtual void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes ) = 0; + virtual void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount ) = 0; +// ------------ End ---------------------------- + + + // Apply stencil operations to every pixel on the screen without disturbing depth or color buffers + virtual void PerformFullScreenStencilOperation( void ) = 0; + + virtual void SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor ) = 0; + + // nVidia CSAA modes, different from SupportsMSAAMode() + virtual bool SupportsCSAAMode( int nNumSamples, int nQualityLevel ) = 0; + + //Notifies the shaderapi to invalidate the current set of delayed constants because we just finished a draw pass. Either actual or not. + virtual void InvalidateDelayedShaderConstants( void ) = 0; + + // Gamma<->Linear conversions according to the video hardware we're running on + virtual float GammaToLinear_HardwareSpecific( float fGamma ) const =0; + virtual float LinearToGamma_HardwareSpecific( float fLinear ) const =0; + + //Set's the linear->gamma conversion textures to use for this hardware for both srgb writes enabled and disabled(identity) + virtual void SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture ) = 0; + + virtual ImageFormat GetNullTextureFormat( void ) = 0; + + virtual void BindVertexTexture( VertexTextureSampler_t nSampler, ShaderAPITextureHandle_t textureHandle ) = 0; + + // Enables hardware morphing + virtual void EnableHWMorphing( bool bEnable ) = 0; + + // Sets flexweights for rendering + virtual void SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights ) = 0; + + virtual void FogMaxDensity( float flMaxDensity ) = 0; + + // Create a multi-frame texture (equivalent to calling "CreateTexture" multiple times, but more efficient) + virtual void CreateTextures( + ShaderAPITextureHandle_t *pHandles, + int count, + int width, + int height, + int depth, + ImageFormat dstImageFormat, + int numMipLevels, + int numCopies, + int flags, + const char *pDebugName, + const char *pTextureGroupName ) = 0; + + virtual void AcquireThreadOwnership() = 0; + virtual void ReleaseThreadOwnership() = 0; + + virtual bool SupportsNormalMapCompression() const = 0; + + // Only does anything on XBox360. This is useful to eliminate stalls + virtual void EnableBuffer2FramesAhead( bool bEnable ) = 0; + + virtual void SetDepthFeatheringPixelShaderConstant( int iConstant, float fDepthBlendScale ) = 0; + + // debug logging + // only implemented in some subclasses + virtual void PrintfVA( char *fmt, va_list vargs ) = 0; + virtual void Printf( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + virtual float Knob( char *knobname, float *setvalue = NULL ) = 0; + // Allows us to override the alpha write setting of a material + virtual void OverrideAlphaWriteEnable( bool bEnable, bool bAlphaWriteEnable ) = 0; + virtual void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable ) = 0; + + //extended clear buffers function with alpha independent from color + virtual void ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth ) = 0; + + // Allows copying a render target to another texture by specifying them both. + virtual void CopyRenderTargetToScratchTexture( ShaderAPITextureHandle_t srcRt, ShaderAPITextureHandle_t dstTex, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL ) = 0; + + // Allows locking and unlocking of very specific surface types. + virtual void LockRect( void** pOutBits, int* pOutPitch, ShaderAPITextureHandle_t texHandle, int mipmap, int x, int y, int w, int h, bool bWrite, bool bRead ) = 0; + virtual void UnlockRect( ShaderAPITextureHandle_t texHandle, int mipmap ) = 0; +}; + + +#endif // ISHADERAPI_H diff --git a/public/shaderapi/ishaderdynamic.h b/public/shaderapi/ishaderdynamic.h new file mode 100644 index 0000000..b78942d --- /dev/null +++ b/public/shaderapi/ishaderdynamic.h @@ -0,0 +1,349 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERDYNAMIC_H +#define ISHADERDYNAMIC_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "shaderapi/shareddefs.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include "tier0/basetypes.h" + + +typedef int ShaderAPITextureHandle_t; + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class CMeshBuilder; +class IMaterialVar; +struct LightDesc_t; + + +//----------------------------------------------------------------------------- +// State from ShaderAPI used to select proper vertex and pixel shader combos +//----------------------------------------------------------------------------- +struct LightState_t +{ + int m_nNumLights; + bool m_bAmbientLight; + bool m_bStaticLightVertex; + bool m_bStaticLightTexel; + inline int HasDynamicLight() { return (m_bAmbientLight || (m_nNumLights > 0)) ? 1 : 0; } +}; + + +//----------------------------------------------------------------------------- +// Color correction info +//----------------------------------------------------------------------------- +struct ShaderColorCorrectionInfo_t +{ + bool m_bIsEnabled; + int m_nLookupCount; + float m_flDefaultWeight; + float m_pLookupWeights[4]; +}; + + +//----------------------------------------------------------------------------- +// the 3D shader API interface +// This interface is all that shaders see. +//----------------------------------------------------------------------------- +enum StandardTextureId_t +{ + // Lightmaps + TEXTURE_LIGHTMAP = 0, + TEXTURE_LIGHTMAP_FULLBRIGHT, + TEXTURE_LIGHTMAP_BUMPED, + TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT, + + // Flat colors + TEXTURE_WHITE, + TEXTURE_BLACK, + TEXTURE_GREY, + TEXTURE_GREY_ALPHA_ZERO, + + // Normalmaps + TEXTURE_NORMALMAP_FLAT, + + // Normalization + TEXTURE_NORMALIZATION_CUBEMAP, + TEXTURE_NORMALIZATION_CUBEMAP_SIGNED, + + // Frame-buffer textures + TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0, + TEXTURE_FRAME_BUFFER_FULL_TEXTURE_1, + + // Color correction + TEXTURE_COLOR_CORRECTION_VOLUME_0, + TEXTURE_COLOR_CORRECTION_VOLUME_1, + TEXTURE_COLOR_CORRECTION_VOLUME_2, + TEXTURE_COLOR_CORRECTION_VOLUME_3, + + // An alias to the Back Frame Buffer + TEXTURE_FRAME_BUFFER_ALIAS, + + // Noise for shadow mapping algorithm + TEXTURE_SHADOW_NOISE_2D, + + // A texture in which morph data gets accumulated (vs30, fast vertex textures required) + TEXTURE_MORPH_ACCUMULATOR, + + // A texture which contains morph weights + TEXTURE_MORPH_WEIGHTS, + + // A snapshot of the frame buffer's depth. Currently only valid on the 360 + TEXTURE_FRAME_BUFFER_FULL_DEPTH, + + // A snapshot of the frame buffer's depth. Currently only valid on the 360 + TEXTURE_IDENTITY_LIGHTWARP, + + // Equivalent to the debug material for mat_luxels, in convenient texture form. + TEXTURE_DEBUG_LUXELS, + + TEXTURE_MAX_STD_TEXTURES = 32 +}; + +//----------------------------------------------------------------------------- +// Viewport structure +//----------------------------------------------------------------------------- +#define SHADER_VIEWPORT_VERSION 1 +struct ShaderViewport_t +{ + int m_nVersion; + int m_nTopLeftX; + int m_nTopLeftY; + int m_nWidth; + int m_nHeight; + float m_flMinZ; + float m_flMaxZ; + + ShaderViewport_t() : m_nVersion( SHADER_VIEWPORT_VERSION ) {} + + void Init() + { + memset( this, 0, sizeof(ShaderViewport_t) ); + m_nVersion = SHADER_VIEWPORT_VERSION; + } + + void Init( int x, int y, int nWidth, int nHeight, float flMinZ = 0.0f, float flMaxZ = 1.0f ) + { + m_nVersion = SHADER_VIEWPORT_VERSION; + m_nTopLeftX = x; m_nTopLeftY = y; m_nWidth = nWidth; m_nHeight = nHeight; + m_flMinZ = flMinZ; + m_flMaxZ = flMaxZ; + } +}; + + +//----------------------------------------------------------------------------- +// The Shader interface versions +//----------------------------------------------------------------------------- +#define SHADERDYNAMIC_INTERFACE_VERSION "ShaderDynamic001" +abstract_class IShaderDynamicAPI +{ +public: + + virtual void SetViewports( int nCount, const ShaderViewport_t* pViewports ) = 0; + virtual int GetViewports( ShaderViewport_t* pViewports, int nMax ) const = 0; + + // returns the current time in seconds.... + virtual double CurrentTime() const = 0; + + // Gets the lightmap dimensions + virtual void GetLightmapDimensions( int *w, int *h ) = 0; + + // Scene fog state. + // This is used by the shaders for picking the proper vertex shader for fogging based on dynamic state. + virtual MaterialFogMode_t GetSceneFogMode( ) = 0; + virtual void GetSceneFogColor( unsigned char *rgb ) = 0; + + // stuff related to matrix stacks + virtual void MatrixMode( MaterialMatrixMode_t matrixMode ) = 0; + virtual void PushMatrix() = 0; + virtual void PopMatrix() = 0; + virtual void LoadMatrix( float *m ) = 0; + virtual void MultMatrix( float *m ) = 0; + virtual void MultMatrixLocal( float *m ) = 0; + virtual void GetMatrix( MaterialMatrixMode_t matrixMode, float *dst ) = 0; + virtual void LoadIdentity( void ) = 0; + virtual void LoadCameraToWorld( void ) = 0; + virtual void Ortho( double left, double right, double bottom, double top, double zNear, double zFar ) = 0; + virtual void PerspectiveX( double fovx, double aspect, double zNear, double zFar ) = 0; + virtual void PickMatrix( int x, int y, int width, int height ) = 0; + virtual void Rotate( float angle, float x, float y, float z ) = 0; + virtual void Translate( float x, float y, float z ) = 0; + virtual void Scale( float x, float y, float z ) = 0; + virtual void ScaleXY( float x, float y ) = 0; + + // Sets the color to modulate by + virtual void Color3f( float r, float g, float b ) = 0; + virtual void Color3fv( float const* pColor ) = 0; + virtual void Color4f( float r, float g, float b, float a ) = 0; + virtual void Color4fv( float const* pColor ) = 0; + + virtual void Color3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void Color3ubv( unsigned char const* pColor ) = 0; + virtual void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) = 0; + virtual void Color4ubv( unsigned char const* pColor ) = 0; + + // Sets the constant register for vertex and pixel shaders + virtual void SetVertexShaderConstant( int var, float const* pVec, int numConst = 1, bool bForce = false ) = 0; + virtual void SetPixelShaderConstant( int var, float const* pVec, int numConst = 1, bool bForce = false ) = 0; + + // Sets the default *dynamic* state + virtual void SetDefaultState() = 0; + + // Get the current camera position in world space. + virtual void GetWorldSpaceCameraPosition( float* pPos ) const = 0; + + virtual int GetCurrentNumBones( void ) const = 0; + virtual int GetCurrentLightCombo( void ) const = 0; + + virtual MaterialFogMode_t GetCurrentFogType( void ) const = 0; + + // fixme: move this to shadow state + virtual void SetTextureTransformDimension( TextureStage_t textureStage, int dimension, bool projected ) = 0; + virtual void DisableTextureTransform( TextureStage_t textureStage ) = 0; + virtual void SetBumpEnvMatrix( TextureStage_t textureStage, float m00, float m01, float m10, float m11 ) = 0; + + // Sets the vertex and pixel shaders + virtual void SetVertexShaderIndex( int vshIndex = -1 ) = 0; + virtual void SetPixelShaderIndex( int pshIndex = 0 ) = 0; + + // Get the dimensions of the back buffer. + virtual void GetBackBufferDimensions( int& width, int& height ) const = 0; + + // FIXME: The following 6 methods used to live in IShaderAPI + // and were moved for stdshader_dx8. Let's try to move them back! + + // Get the lights + virtual int GetMaxLights( void ) const = 0; + virtual const LightDesc_t& GetLight( int lightNum ) const = 0; + + virtual void SetPixelShaderFogParams( int reg ) = 0; + + // Render state for the ambient light cube + virtual void SetVertexShaderStateAmbientLightCube() = 0; + virtual void SetPixelShaderStateAmbientLightCube( int pshReg, bool bForceToBlack = false ) = 0; + virtual void CommitPixelShaderLighting( int pshReg ) = 0; + + // Use this to get the mesh builder that allows us to modify vertex data + virtual CMeshBuilder* GetVertexModifyBuilder() = 0; + virtual bool InFlashlightMode() const = 0; + virtual const FlashlightState_t &GetFlashlightState( VMatrix &worldToTexture ) const = 0; + virtual bool InEditorMode() const = 0; + + // Gets the bound morph's vertex format; returns 0 if no morph is bound + virtual MorphFormat_t GetBoundMorphFormat() = 0; + + // Binds a standard texture + virtual void BindStandardTexture( Sampler_t sampler, StandardTextureId_t id ) = 0; + + virtual ITexture *GetRenderTargetEx( int nRenderTargetID ) = 0; + + virtual void SetToneMappingScaleLinear( const Vector &scale ) = 0; + virtual const Vector &GetToneMappingScaleLinear( void ) const = 0; + virtual float GetLightMapScaleFactor( void ) const = 0; + + virtual void LoadBoneMatrix( int boneIndex, const float *m ) = 0; + + virtual void PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right ) = 0; + + virtual void SetFloatRenderingParameter(int parm_number, float value) = 0; + + virtual void SetIntRenderingParameter(int parm_number, int value) = 0 ; + virtual void SetVectorRenderingParameter(int parm_number, Vector const &value) = 0 ; + + virtual float GetFloatRenderingParameter(int parm_number) const = 0 ; + + virtual int GetIntRenderingParameter(int parm_number) const = 0 ; + + virtual Vector GetVectorRenderingParameter(int parm_number) const = 0 ; + + // stencil buffer operations. + virtual void SetStencilEnable(bool onoff) = 0; + virtual void SetStencilFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilZFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilPassOperation(StencilOperation_t op) = 0; + virtual void SetStencilCompareFunction(StencilComparisonFunction_t cmpfn) = 0; + virtual void SetStencilReferenceValue(int ref) = 0; + virtual void SetStencilTestMask(uint32 msk) = 0; + virtual void SetStencilWriteMask(uint32 msk) = 0; + virtual void ClearStencilBufferRectangle( int xmin, int ymin, int xmax, int ymax,int value) = 0; + + virtual void GetDXLevelDefaults(uint &max_dxlevel,uint &recommended_dxlevel) = 0; + + virtual const FlashlightState_t &GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **pFlashlightDepthTexture ) const = 0; + + virtual float GetAmbientLightCubeLuminance() = 0; + + virtual void GetDX9LightState( LightState_t *state ) const = 0; + virtual int GetPixelFogCombo( ) = 0; //0 is either range fog, or no fog simulated with rigged range fog values. 1 is height fog + + virtual void BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id ) = 0; + + // Is hardware morphing enabled? + virtual bool IsHWMorphingEnabled( ) const = 0; + + virtual void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id ) = 0; + + virtual void SetBooleanVertexShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false ) = 0; + virtual void SetIntegerVertexShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false ) = 0; + virtual void SetBooleanPixelShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false ) = 0; + virtual void SetIntegerPixelShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false ) = 0; + + //Are we in a configuration that needs access to depth data through the alpha channel later? + virtual bool ShouldWriteDepthToDestAlpha( void ) const = 0; + + + // deformations + virtual void PushDeformation( DeformationBase_t const *Deformation ) = 0; + virtual void PopDeformation( ) = 0; + virtual int GetNumActiveDeformations() const =0; + + + // for shaders to set vertex shader constants. returns a packed state which can be used to set + // the dynamic combo. returns # of active deformations + virtual int GetPackedDeformationInformation( int nMaskOfUnderstoodDeformations, + float *pConstantValuesOut, + int nBufferSize, + int nMaximumDeformations, + int *pNumDefsOut ) const = 0; + + // This lets the lower level system that certain vertex fields requested + // in the shadow state aren't actually being read given particular state + // known only at dynamic state time. It's here only to silence warnings. + virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords ) = 0; + + + virtual void ExecuteCommandBuffer( uint8 *pCmdBuffer ) =0; + + // interface for mat system to tell shaderapi about standard texture handles + virtual void SetStandardTextureHandle( StandardTextureId_t nId, ShaderAPITextureHandle_t nHandle ) =0; + + // Interface for mat system to tell shaderapi about color correction + virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo ) = 0; + + virtual void SetPSNearAndFarZ( int pshReg ) = 0; + + virtual void SetDepthFeatheringPixelShaderConstant( int iConstant, float fDepthBlendScale ) = 0; +}; +// end class IShaderDynamicAPI + +//----------------------------------------------------------------------------- +// Software vertex shaders +//----------------------------------------------------------------------------- +typedef void (*SoftwareVertexShader_t)( CMeshBuilder& meshBuilder, IMaterialVar **params, IShaderDynamicAPI *pShaderAPI ); + + +#endif // ISHADERDYNAMIC_H diff --git a/public/shaderapi/ishadershadow.h b/public/shaderapi/ishadershadow.h new file mode 100644 index 0000000..170988f --- /dev/null +++ b/public/shaderapi/ishadershadow.h @@ -0,0 +1,368 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERSHADOW_H +#define ISHADERSHADOW_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "shaderapi/shareddefs.h" +#include + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class CMeshBuilder; +class IMaterialVar; +struct LightDesc_t; + + +//----------------------------------------------------------------------------- +// important enumerations +//----------------------------------------------------------------------------- +enum ShaderDepthFunc_t +{ + SHADER_DEPTHFUNC_NEVER, + SHADER_DEPTHFUNC_NEARER, + SHADER_DEPTHFUNC_EQUAL, + SHADER_DEPTHFUNC_NEAREROREQUAL, + SHADER_DEPTHFUNC_FARTHER, + SHADER_DEPTHFUNC_NOTEQUAL, + SHADER_DEPTHFUNC_FARTHEROREQUAL, + SHADER_DEPTHFUNC_ALWAYS +}; + +enum ShaderBlendFactor_t +{ + SHADER_BLEND_ZERO, + SHADER_BLEND_ONE, + SHADER_BLEND_DST_COLOR, + SHADER_BLEND_ONE_MINUS_DST_COLOR, + SHADER_BLEND_SRC_ALPHA, + SHADER_BLEND_ONE_MINUS_SRC_ALPHA, + SHADER_BLEND_DST_ALPHA, + SHADER_BLEND_ONE_MINUS_DST_ALPHA, + SHADER_BLEND_SRC_ALPHA_SATURATE, + SHADER_BLEND_SRC_COLOR, + SHADER_BLEND_ONE_MINUS_SRC_COLOR +}; + +enum ShaderBlendOp_t +{ + SHADER_BLEND_OP_ADD, + SHADER_BLEND_OP_SUBTRACT, + SHADER_BLEND_OP_REVSUBTRACT, + SHADER_BLEND_OP_MIN, + SHADER_BLEND_OP_MAX +}; + +enum ShaderAlphaFunc_t +{ + SHADER_ALPHAFUNC_NEVER, + SHADER_ALPHAFUNC_LESS, + SHADER_ALPHAFUNC_EQUAL, + SHADER_ALPHAFUNC_LEQUAL, + SHADER_ALPHAFUNC_GREATER, + SHADER_ALPHAFUNC_NOTEQUAL, + SHADER_ALPHAFUNC_GEQUAL, + SHADER_ALPHAFUNC_ALWAYS +}; + +enum ShaderStencilFunc_t +{ + SHADER_STENCILFUNC_NEVER = 0, + SHADER_STENCILFUNC_LESS, + SHADER_STENCILFUNC_EQUAL, + SHADER_STENCILFUNC_LEQUAL, + SHADER_STENCILFUNC_GREATER, + SHADER_STENCILFUNC_NOTEQUAL, + SHADER_STENCILFUNC_GEQUAL, + SHADER_STENCILFUNC_ALWAYS +}; + +enum ShaderStencilOp_t +{ + SHADER_STENCILOP_KEEP = 0, + SHADER_STENCILOP_ZERO, + SHADER_STENCILOP_SET_TO_REFERENCE, + SHADER_STENCILOP_INCREMENT_CLAMP, + SHADER_STENCILOP_DECREMENT_CLAMP, + SHADER_STENCILOP_INVERT, + SHADER_STENCILOP_INCREMENT_WRAP, + SHADER_STENCILOP_DECREMENT_WRAP, +}; + +enum ShaderTexChannel_t +{ + SHADER_TEXCHANNEL_COLOR = 0, + SHADER_TEXCHANNEL_ALPHA +}; + +enum ShaderPolyModeFace_t +{ + SHADER_POLYMODEFACE_FRONT, + SHADER_POLYMODEFACE_BACK, + SHADER_POLYMODEFACE_FRONT_AND_BACK, +}; + +enum ShaderPolyMode_t +{ + SHADER_POLYMODE_POINT, + SHADER_POLYMODE_LINE, + SHADER_POLYMODE_FILL +}; + +enum ShaderTexArg_t +{ + SHADER_TEXARG_TEXTURE = 0, + SHADER_TEXARG_VERTEXCOLOR, + SHADER_TEXARG_SPECULARCOLOR, + SHADER_TEXARG_CONSTANTCOLOR, + SHADER_TEXARG_PREVIOUSSTAGE, + SHADER_TEXARG_NONE, + SHADER_TEXARG_ZERO, + SHADER_TEXARG_TEXTUREALPHA, + SHADER_TEXARG_INVTEXTUREALPHA, + SHADER_TEXARG_ONE, +}; + +enum ShaderTexOp_t +{ + // DX5 shaders support these + SHADER_TEXOP_MODULATE = 0, + SHADER_TEXOP_MODULATE2X, + SHADER_TEXOP_MODULATE4X, + SHADER_TEXOP_SELECTARG1, + SHADER_TEXOP_SELECTARG2, + SHADER_TEXOP_DISABLE, + + // DX6 shaders support these + SHADER_TEXOP_ADD, + SHADER_TEXOP_SUBTRACT, + SHADER_TEXOP_ADDSIGNED2X, + SHADER_TEXOP_BLEND_CONSTANTALPHA, + SHADER_TEXOP_BLEND_TEXTUREALPHA, + SHADER_TEXOP_BLEND_PREVIOUSSTAGEALPHA, + SHADER_TEXOP_MODULATECOLOR_ADDALPHA, + SHADER_TEXOP_MODULATEINVCOLOR_ADDALPHA, + + // DX7 + SHADER_TEXOP_DOTPRODUCT3 +}; + +enum ShaderTexGenParam_t +{ + SHADER_TEXGENPARAM_OBJECT_LINEAR, + SHADER_TEXGENPARAM_EYE_LINEAR, + SHADER_TEXGENPARAM_SPHERE_MAP, + SHADER_TEXGENPARAM_CAMERASPACEREFLECTIONVECTOR, + SHADER_TEXGENPARAM_CAMERASPACENORMAL +}; + +enum ShaderDrawBitField_t +{ + SHADER_DRAW_POSITION = 0x0001, + SHADER_DRAW_NORMAL = 0x0002, + SHADER_DRAW_COLOR = 0x0004, + SHADER_DRAW_SPECULAR = 0x0008, + + SHADER_DRAW_TEXCOORD0 = 0x0010, + SHADER_DRAW_TEXCOORD1 = 0x0020, + SHADER_DRAW_TEXCOORD2 = 0x0040, + SHADER_DRAW_TEXCOORD3 = 0x0080, + + SHADER_DRAW_LIGHTMAP_TEXCOORD0 = 0x0100, + SHADER_DRAW_LIGHTMAP_TEXCOORD1 = 0x0200, + SHADER_DRAW_LIGHTMAP_TEXCOORD2 = 0x0400, + SHADER_DRAW_LIGHTMAP_TEXCOORD3 = 0x0800, + + SHADER_DRAW_SECONDARY_TEXCOORD0 = 0x1000, + SHADER_DRAW_SECONDARY_TEXCOORD1 = 0x2000, + SHADER_DRAW_SECONDARY_TEXCOORD2 = 0x4000, + SHADER_DRAW_SECONDARY_TEXCOORD3 = 0x8000, + + SHADER_TEXCOORD_MASK = SHADER_DRAW_TEXCOORD0 | SHADER_DRAW_TEXCOORD1 | + SHADER_DRAW_TEXCOORD2 | SHADER_DRAW_TEXCOORD3, + + SHADER_LIGHTMAP_TEXCOORD_MASK = SHADER_DRAW_LIGHTMAP_TEXCOORD0 | + SHADER_DRAW_LIGHTMAP_TEXCOORD1 | + SHADER_DRAW_LIGHTMAP_TEXCOORD2 | + SHADER_DRAW_LIGHTMAP_TEXCOORD3, + + SHADER_SECONDARY_TEXCOORD_MASK = SHADER_DRAW_SECONDARY_TEXCOORD0 | + SHADER_DRAW_SECONDARY_TEXCOORD1 | + SHADER_DRAW_SECONDARY_TEXCOORD2 | + SHADER_DRAW_SECONDARY_TEXCOORD3, +}; + + +enum ShaderFogMode_t +{ + SHADER_FOGMODE_DISABLED = 0, + SHADER_FOGMODE_OO_OVERBRIGHT, + SHADER_FOGMODE_BLACK, + SHADER_FOGMODE_GREY, + SHADER_FOGMODE_FOGCOLOR, + SHADER_FOGMODE_WHITE, + SHADER_FOGMODE_NUMFOGMODES +}; + +enum ShaderMaterialSource_t +{ + SHADER_MATERIALSOURCE_MATERIAL = 0, + SHADER_MATERIALSOURCE_COLOR1, + SHADER_MATERIALSOURCE_COLOR2, +}; + + +// m_ZBias has only two bits in ShadowState_t, so be careful extending this enum +enum PolygonOffsetMode_t +{ + SHADER_POLYOFFSET_DISABLE = 0x0, + SHADER_POLYOFFSET_DECAL = 0x1, + SHADER_POLYOFFSET_SHADOW_BIAS = 0x2, + SHADER_POLYOFFSET_RESERVED = 0x3 // Reserved for future use +}; + + +//----------------------------------------------------------------------------- +// The Shader interface versions +//----------------------------------------------------------------------------- +#define SHADERSHADOW_INTERFACE_VERSION "ShaderShadow010" + + +//----------------------------------------------------------------------------- +// the shader API interface (methods called from shaders) +//----------------------------------------------------------------------------- +abstract_class IShaderShadow +{ +public: + // Sets the default *shadow* state + virtual void SetDefaultState() = 0; + + // Methods related to depth buffering + virtual void DepthFunc( ShaderDepthFunc_t depthFunc ) = 0; + virtual void EnableDepthWrites( bool bEnable ) = 0; + virtual void EnableDepthTest( bool bEnable ) = 0; + virtual void EnablePolyOffset( PolygonOffsetMode_t nOffsetMode ) = 0; + + // These methods for controlling stencil are obsolete and stubbed to do nothing. Stencil + // control is via the shaderapi/material system now, not part of the shadow state. + // Methods related to stencil + virtual void EnableStencil( bool bEnable ) = 0; + virtual void StencilFunc( ShaderStencilFunc_t stencilFunc ) = 0; + virtual void StencilPassOp( ShaderStencilOp_t stencilOp ) = 0; + virtual void StencilFailOp( ShaderStencilOp_t stencilOp ) = 0; + virtual void StencilDepthFailOp( ShaderStencilOp_t stencilOp ) = 0; + virtual void StencilReference( int nReference ) = 0; + virtual void StencilMask( int nMask ) = 0; + virtual void StencilWriteMask( int nMask ) = 0; + + // Suppresses/activates color writing + virtual void EnableColorWrites( bool bEnable ) = 0; + virtual void EnableAlphaWrites( bool bEnable ) = 0; + + // Methods related to alpha blending + virtual void EnableBlending( bool bEnable ) = 0; + virtual void BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor ) = 0; + // More below... + + // Alpha testing + virtual void EnableAlphaTest( bool bEnable ) = 0; + virtual void AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ ) = 0; + + // Wireframe/filled polygons + virtual void PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode ) = 0; + + // Back face culling + virtual void EnableCulling( bool bEnable ) = 0; + + // constant color + transparency + virtual void EnableConstantColor( bool bEnable ) = 0; + + // Indicates the vertex format for use with a vertex shader + // The flags to pass in here come from the VertexFormatFlags_t enum + // If pTexCoordDimensions is *not* specified, we assume all coordinates + // are 2-dimensional + virtual void VertexShaderVertexFormat( unsigned int nFlags, + int nTexCoordCount, int* pTexCoordDimensions, int nUserDataSize ) = 0; + + // Pixel and vertex shader methods + virtual void SetVertexShader( const char* pFileName, int nStaticVshIndex ) = 0; + virtual void SetPixelShader( const char* pFileName, int nStaticPshIndex = 0 ) = 0; + + // Indicates we're going to light the model + virtual void EnableLighting( bool bEnable ) = 0; + + // Enables specular lighting (lighting has also got to be enabled) + virtual void EnableSpecular( bool bEnable ) = 0; + + // Convert from linear to gamma color space on writes to frame buffer. + virtual void EnableSRGBWrite( bool bEnable ) = 0; + + // Convert from gamma to linear on texture fetch. + virtual void EnableSRGBRead( Sampler_t sampler, bool bEnable ) = 0; + + // Activate/deactivate skinning. Indexed blending is automatically + // enabled if it's available for this hardware. When blending is enabled, + // we allocate enough room for 3 weights (max allowed) + virtual void EnableVertexBlend( bool bEnable ) = 0; + + // per texture unit stuff + virtual void OverbrightValue( TextureStage_t stage, float value ) = 0; + virtual void EnableTexture( Sampler_t sampler, bool bEnable ) = 0; + virtual void EnableTexGen( TextureStage_t stage, bool bEnable ) = 0; + virtual void TexGen( TextureStage_t stage, ShaderTexGenParam_t param ) = 0; + + // alternate method of specifying per-texture unit stuff, more flexible and more complicated + // Can be used to specify different operation per channel (alpha/color)... + virtual void EnableCustomPixelPipe( bool bEnable ) = 0; + virtual void CustomTextureStages( int stageCount ) = 0; + virtual void CustomTextureOperation( TextureStage_t stage, ShaderTexChannel_t channel, + ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 ) = 0; + + // indicates what per-vertex data we're providing + virtual void DrawFlags( unsigned int drawFlags ) = 0; + + // A simpler method of dealing with alpha modulation + virtual void EnableAlphaPipe( bool bEnable ) = 0; + virtual void EnableConstantAlpha( bool bEnable ) = 0; + virtual void EnableVertexAlpha( bool bEnable ) = 0; + virtual void EnableTextureAlpha( TextureStage_t stage, bool bEnable ) = 0; + + // GR - Separate alpha blending + virtual void EnableBlendingSeparateAlpha( bool bEnable ) = 0; + virtual void BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor ) = 0; + virtual void FogMode( ShaderFogMode_t fogMode ) = 0; + + virtual void SetDiffuseMaterialSource( ShaderMaterialSource_t materialSource ) = 0; + + // Indicates the morph format for use with a vertex shader + // The flags to pass in here come from the MorphFormatFlags_t enum + virtual void SetMorphFormat( MorphFormat_t flags ) = 0; + + virtual void DisableFogGammaCorrection( bool bDisable ) = 0; //some blending modes won't work properly with corrected fog + + // Alpha to coverage + virtual void EnableAlphaToCoverage( bool bEnable ) = 0; + + // Shadow map filtering + virtual void SetShadowDepthFiltering( Sampler_t stage ) = 0; + + // More alpha blending state + virtual void BlendOp( ShaderBlendOp_t blendOp ) = 0; + virtual void BlendOpSeparateAlpha( ShaderBlendOp_t blendOp ) = 0; +}; +// end class IShaderShadow + + + +#endif // ISHADERSHADOW_H diff --git a/public/shaderapi/ishaderutil.h b/public/shaderapi/ishaderutil.h new file mode 100644 index 0000000..5fe0199 --- /dev/null +++ b/public/shaderapi/ishaderutil.h @@ -0,0 +1,131 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERUTIL_H +#define ISHADERUTIL_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "materialsystem/imaterial.h" +#include "appframework/IAppSystem.h" +#include "shaderapi/ishaderapi.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class ITexture; +struct MaterialSystem_Config_t; +struct ImageFormatInfo_t; +enum Sampler_t; +enum VertexTextureSampler_t; +enum StandardTextureId_t; +class CPrimList; +struct ShaderColorCorrectionInfo_t; + +#define SHADER_UTIL_INTERFACE_VERSION "VShaderUtil001" + +enum shaderthreadevent_t +{ + SHADER_THREAD_RELEASE_RESOURCES = 1, + SHADER_THREAD_ACQUIRE_RESOURCES = 2, + SHADER_THREAD_DEVICE_LOST = 3, + SHADER_THREAD_EVICT_RESOURCES = 4, + SHADER_THREAD_OTHER_APP_START = 5, + SHADER_THREAD_OTHER_APP_END = 6, + SHADER_THREAD_RESET_RENDER_STATE = 7, +}; + +abstract_class IShaderUtil : public IAppSystem +{ +public: + // Method to allow clients access to the MaterialSystem_Config + virtual MaterialSystem_Config_t& GetConfig() = 0; + + // Allows us to convert image formats + virtual bool ConvertImageFormat( unsigned char *src, enum ImageFormat srcImageFormat, + unsigned char *dst, enum ImageFormat dstImageFormat, + int width, int height, int srcStride = 0, int dstStride = 0 ) = 0; + + // Figures out the amount of memory needed by a bitmap + virtual int GetMemRequired( int width, int height, int depth, ImageFormat format, bool mipmap ) = 0; + + // Gets image format info + virtual const ImageFormatInfo_t& ImageFormatInfo( ImageFormat fmt ) const = 0; + + // Bind standard textures + virtual void BindStandardTexture( Sampler_t sampler, StandardTextureId_t id ) = 0; + + // What are the lightmap dimensions? + virtual void GetLightmapDimensions( int *w, int *h ) = 0; + + // These methods are called when the shader must eject + restore HW memory + virtual void ReleaseShaderObjects() = 0; + virtual void RestoreShaderObjects( CreateInterfaceFn shaderFactory, int nChangeFlags = 0 ) = 0; + + // Used to prevent meshes from drawing. + virtual bool IsInStubMode() = 0; + virtual bool InFlashlightMode() const = 0; + + // For the shader API to shove the current version of aniso level into the + // "definitive" place (g_config) when the shader API decides to change it. + // Eventually, we should have a better system of who owns the definitive + // versions of config vars. + virtual void NoteAnisotropicLevel( int currentLevel ) = 0; + + // NOTE: Stuff after this is added after shipping HL2. + + // Are we rendering through the editor? + virtual bool InEditorMode() const = 0; + + // Gets the bound morph's vertex format; returns 0 if no morph is bound + virtual MorphFormat_t GetBoundMorphFormat() = 0; + + virtual ITexture *GetRenderTargetEx( int nRenderTargetID ) = 0; + + // Tells the material system to draw a buffer clearing quad + virtual void DrawClearBufferQuad( unsigned char r, unsigned char g, unsigned char b, unsigned char a, bool bClearColor, bool bClearAlpha, bool bClearDepth ) = 0; + +#if defined( _X360 ) + virtual void ReadBackBuffer( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pData, ImageFormat dstFormat, int nDstStride ) = 0; +#endif + + // Calls from meshes to material system to handle queing/threading + virtual bool OnDrawMesh( IMesh *pMesh, int firstIndex, int numIndices ) = 0; + virtual bool OnDrawMesh( IMesh *pMesh, CPrimList *pLists, int nLists ) = 0; + virtual bool OnSetFlexMesh( IMesh *pStaticMesh, IMesh *pMesh, int nVertexOffsetInBytes ) = 0; + virtual bool OnSetColorMesh( IMesh *pStaticMesh, IMesh *pMesh, int nVertexOffsetInBytes ) = 0; + virtual bool OnSetPrimitiveType( IMesh *pMesh, MaterialPrimitiveType_t type ) = 0; + virtual bool OnFlushBufferedPrimitives() = 0; + + + virtual void SyncMatrices() = 0; + virtual void SyncMatrix( MaterialMatrixMode_t ) = 0; + + virtual void BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id ) = 0; + virtual void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id ) = 0; + + virtual int MaxHWMorphBatchCount() const = 0; + + // Interface for mat system to tell shaderapi about color correction + virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo ) = 0; + // received an event while not in owning thread, handle this outside + virtual void OnThreadEvent( uint32 threadEvent ) = 0; + + virtual MaterialThreadMode_t GetThreadMode( ) = 0; + virtual bool IsRenderThreadSafe( ) = 0; + + // Remove any materials from memory that aren't in use as determined + // by the IMaterial's reference count. + virtual void UncacheUnusedMaterials( bool bRecomputeStateSnapshots = false ) = 0; +}; + +#endif // ISHADERUTIL_H diff --git a/public/shaderapi/shareddefs.h b/public/shaderapi/shareddefs.h new file mode 100644 index 0000000..663fbfa --- /dev/null +++ b/public/shaderapi/shareddefs.h @@ -0,0 +1,111 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: NOTE: This file is for backward compat! +// We'll get rid of it soon. Most of the contents of this file were moved +// into shaderpi/ishadershadow.h, shaderapi/ishaderdynamic.h, or +// shaderapi/shareddefs.h +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef SHADERAPI_SHAREDDEFS_H +#define SHADERAPI_SHAREDDEFS_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Important enumerations +//----------------------------------------------------------------------------- +enum ShaderShadeMode_t +{ + SHADER_FLAT = 0, + SHADER_SMOOTH +}; + +enum ShaderTexCoordComponent_t +{ + SHADER_TEXCOORD_S = 0, + SHADER_TEXCOORD_T, + SHADER_TEXCOORD_U +}; + +enum ShaderTexFilterMode_t +{ + SHADER_TEXFILTERMODE_NEAREST, + SHADER_TEXFILTERMODE_LINEAR, + SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST, + SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST, + SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR, + SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR, + SHADER_TEXFILTERMODE_ANISOTROPIC +}; + +enum ShaderTexWrapMode_t +{ + SHADER_TEXWRAPMODE_CLAMP, + SHADER_TEXWRAPMODE_REPEAT, + SHADER_TEXWRAPMODE_BORDER + // MIRROR? - probably don't need it. +}; + + +//----------------------------------------------------------------------------- +// Sampler + texture stage identifiers +// NOTE: Texture stages are used only by fixed function shading algorithms +// Samplers are used to enable and bind textures + by programmable shading algorithms +//----------------------------------------------------------------------------- +enum TextureStage_t +{ + SHADER_TEXTURE_STAGE0 = 0, + SHADER_TEXTURE_STAGE1, +}; + +enum Sampler_t +{ + SHADER_SAMPLER0 = 0, + SHADER_SAMPLER1, + SHADER_SAMPLER2, + SHADER_SAMPLER3, + SHADER_SAMPLER4, + SHADER_SAMPLER5, + SHADER_SAMPLER6, + SHADER_SAMPLER7, + SHADER_SAMPLER8, + SHADER_SAMPLER9, + SHADER_SAMPLER10, + SHADER_SAMPLER11, + SHADER_SAMPLER12, + SHADER_SAMPLER13, + SHADER_SAMPLER14, + SHADER_SAMPLER15, +}; + +//----------------------------------------------------------------------------- +// Vertex texture sampler identifiers +//----------------------------------------------------------------------------- +enum VertexTextureSampler_t +{ + SHADER_VERTEXTEXTURE_SAMPLER0 = 0, + SHADER_VERTEXTEXTURE_SAMPLER1, + SHADER_VERTEXTEXTURE_SAMPLER2, + SHADER_VERTEXTEXTURE_SAMPLER3, +}; + + +#if defined( _X360 ) +#define REVERSE_DEPTH_ON_X360 //uncomment to use D3DFMT_D24FS8 with an inverted depth viewport for better performance. Keep this in sync with the same named #define in materialsystem/stdshaders/common_fxc.h +#endif + +#if defined( REVERSE_DEPTH_ON_X360 ) +#define ReverseDepthOnX360() true +#else +#define ReverseDepthOnX360() false +#endif + + + +#endif // SHADERAPI_SHAREDDEFS_H diff --git a/public/shaderlib/BaseShader.h b/public/shaderlib/BaseShader.h new file mode 100644 index 0000000..6119183 --- /dev/null +++ b/public/shaderlib/BaseShader.h @@ -0,0 +1,341 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// This is what all shaders inherit from. +//===========================================================================// + +#ifndef BASESHADER_H +#define BASESHADER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "materialsystem/IShader.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/ishaderapi.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "shaderlib/BaseShader.h" +#include "convar.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterialVar; + +//----------------------------------------------------------------------------- +// Standard material vars +//----------------------------------------------------------------------------- +// Note: if you add to these, add to s_StandardParams in CBaseShader.cpp +enum ShaderMaterialVars_t +{ + FLAGS = 0, + FLAGS_DEFINED, // mask indicating if the flag was specified + FLAGS2, + FLAGS_DEFINED2, + COLOR, + ALPHA, + BASETEXTURE, + FRAME, + BASETEXTURETRANSFORM, + FLASHLIGHTTEXTURE, + FLASHLIGHTTEXTUREFRAME, + COLOR2, + SRGBTINT, + + NUM_SHADER_MATERIAL_VARS +}; + + +// Alpha belnd mode enums. Moved from basevsshader +enum BlendType_t +{ + // no alpha blending + BT_NONE = 0, + + + + // src * srcAlpha + dst * (1-srcAlpha) + // two passes for HDR: + // pass 1: + // color: src * srcAlpha + dst * (1-srcAlpha) + // alpha: srcAlpha * zero + dstAlpha * (1-srcAlpha) + // pass 2: + // color: none + // alpha: srcAlpha * one + dstAlpha * one + // + BT_BLEND, + + + + // src * one + dst * one + // one pass for HDR + BT_ADD, + + + + // Why do we ever use this instead of using premultiplied alpha? + // src * srcAlpha + dst * one + // two passes for HDR + // pass 1: + // color: src * srcAlpha + dst * one + // alpha: srcAlpha * one + dstAlpha * one + // pass 2: + // color: none + // alpha: srcAlpha * one + dstAlpha * one + BT_BLENDADD +}; + + +//----------------------------------------------------------------------------- +// Base class for shaders, contains helper methods. +//----------------------------------------------------------------------------- +class CBaseShader : public IShader +{ +public: + // constructor + CBaseShader(); + + // Methods inherited from IShader + virtual char const* GetFallbackShader( IMaterialVar** params ) const { return 0; } + virtual int GetNumParams( ) const; + virtual char const* GetParamName( int paramIndex ) const; + virtual char const* GetParamHelp( int paramIndex ) const; + virtual ShaderParamType_t GetParamType( int paramIndex ) const; + virtual char const* GetParamDefault( int paramIndex ) const; + virtual int GetParamFlags( int nParamIndex ) const; + + virtual void InitShaderParams( IMaterialVar** ppParams, const char *pMaterialName ); + virtual void InitShaderInstance( IMaterialVar** ppParams, IShaderInit *pShaderInit, const char *pMaterialName, const char *pTextureGroupName ); + virtual void DrawElements( IMaterialVar **params, int nModulationFlags, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, + VertexCompressionType_t vertexCompression, CBasePerMaterialContextData **pContext ); + + virtual const SoftwareVertexShader_t GetSoftwareVertexShader() const { return m_SoftwareVertexShader; } + + virtual int ComputeModulationFlags( IMaterialVar** params, IShaderDynamicAPI* pShaderAPI ); + virtual bool NeedsPowerOfTwoFrameBufferTexture( IMaterialVar **params, bool bCheckSpecificToThisFrame = true ) const; + virtual bool NeedsFullFrameBufferTexture( IMaterialVar **params, bool bCheckSpecificToThisFrame = true ) const; + virtual bool IsTranslucent( IMaterialVar **params ) const; + +public: + // These functions must be implemented by the shader + virtual void OnInitShaderParams( IMaterialVar** ppParams, const char *pMaterialName ) {} + virtual void OnInitShaderInstance( IMaterialVar** ppParams, IShaderInit *pShaderInit, const char *pMaterialName ) = 0; + virtual void OnDrawElements( IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, CBasePerMaterialContextData **pContextDataPtr ) = 0; + + // Sets the default shadow state + void SetInitialShadowState( ); + + // Draws a snapshot + void Draw( bool bMakeActualDrawCall = true ); + + // Are we currently taking a snapshot? + bool IsSnapshotting() const; + + // Gets at the current materialvar flags + int CurrentMaterialVarFlags() const; + + // Finds a particular parameter (works because the lowest parameters match the shader) + int FindParamIndex( const char *pName ) const; + + // Are we using graphics? + bool IsUsingGraphics(); + + // Are we using editor materials? + bool CanUseEditorMaterials(); + + // Gets the builder... + CMeshBuilder* MeshBuilder(); + + // Loads a texture + void LoadTexture( int nTextureVar, int nAdditionalCreationFlags = 0 ); + + // Loads a bumpmap + void LoadBumpMap( int nTextureVar ); + + // Loads a cubemap + void LoadCubeMap( int nTextureVar, int nAdditionalCreationFlags = 0 ); + + // get the shaderapi handle for a texture. BE CAREFUL WITH THIS. + ShaderAPITextureHandle_t GetShaderAPITextureBindHandle( int nTextureVar, int nFrameVar, int nTextureChannel = 0 ); + + + // Binds a texture + void BindTexture( Sampler_t sampler1, Sampler_t sampler2, int nTextureVar, int nFrameVar = -1 ); + void BindTexture( Sampler_t sampler1, int nTextureVar, int nFrameVar = -1 ); + void BindTexture( Sampler_t sampler1, ITexture *pTexture, int nFrame = 0 ); + void BindTexture( Sampler_t sampler1, Sampler_t sampler2, ITexture *pTexture, int nFrame = 0 ); + + void GetTextureDimensions( float* pOutWidth, float* pOutHeight, int nTextureVar ); + + // Is the texture translucent? + bool TextureIsTranslucent( int textureVar, bool isBaseTexture ); + + // Returns the translucency... + float GetAlpha( IMaterialVar** params = NULL ); + + // Is the color var white? + bool IsWhite( int colorVar ); + + // Helper methods for fog + void FogToOOOverbright( void ); + void FogToWhite( void ); + void FogToBlack( void ); + void FogToGrey( void ); + void FogToFogColor( void ); + void DisableFog( void ); + void DefaultFog( void ); + + // Helpers for alpha blending + void EnableAlphaBlending( ShaderBlendFactor_t src, ShaderBlendFactor_t dst ); + void DisableAlphaBlending(); + + void SetBlendingShadowState( BlendType_t nMode ); + + void SetNormalBlendingShadowState( int textureVar = -1, bool isBaseTexture = true ); + void SetAdditiveBlendingShadowState( int textureVar = -1, bool isBaseTexture = true ); + void SetDefaultBlendingShadowState( int textureVar = -1, bool isBaseTexture = true ); + void SingleTextureLightmapBlendMode( ); + + // Helpers for color modulation + void SetColorState( int colorVar, bool setAlpha = false ); + bool IsAlphaModulating(); + bool IsColorModulating(); + void ComputeModulationColor( float* color ); + void SetModulationShadowState( int tintVar = -1 ); + void SetModulationDynamicState( int tintVar = -1 ); + + // Helpers for HDR + bool IsHDREnabled( void ); + + // Loads the identity matrix into the texture + void LoadIdentity( MaterialMatrixMode_t matrixMode ); + + // Loads the camera to world transform + void LoadCameraToWorldTransform( MaterialMatrixMode_t matrixMode ); + void LoadCameraSpaceSphereMapTransform( MaterialMatrixMode_t matrixMode ); + + // Sets a texture translation transform in fixed function + void SetFixedFunctionTextureTranslation( MaterialMatrixMode_t mode, int translationVar ); + void SetFixedFunctionTextureScale( MaterialMatrixMode_t mode, int scaleVar ); + void SetFixedFunctionTextureScaledTransform( MaterialMatrixMode_t textureTransform, int transformVar, int scaleVar ); + void SetFixedFunctionTextureTransform( MaterialMatrixMode_t textureTransform, int transformVar ); + + void CleanupDynamicStateFixedFunction( ); + + // Fixed function Base * detail pass + void FixedFunctionBaseTimesDetailPass( int baseTextureVar, int frameVar, + int baseTextureTransformVar, int detailVar, int detailScaleVar ); + + // Fixed function Self illumination pass + void FixedFunctionSelfIlluminationPass( Sampler_t sampler, + int baseTextureVar, int frameVar, int baseTextureTransformVar, int selfIllumTintVar ); + + // Masked environment map + void FixedFunctionMaskedEnvmapPass( int envMapVar, int envMapMaskVar, + int baseTextureVar, int envMapFrameVar, int envMapMaskFrameVar, + int frameVar, int maskOffsetVar, int maskScaleVar, int tintVar = -1 ); + + // Additive masked environment map + void FixedFunctionAdditiveMaskedEnvmapPass( int envMapVar, int envMapMaskVar, + int baseTextureVar, int envMapFrameVar, int envMapMaskFrameVar, + int frameVar, int maskOffsetVar, int maskScaleVar, int tintVar = -1 ); + + // Modulate by detail texture pass + void FixedFunctionMultiplyByDetailPass( int baseTextureVar, int frameVar, + int textureOffsetVar, int detailVar, int detailScaleVar ); + + // Multiply by lightmap pass + void FixedFunctionMultiplyByLightmapPass( int baseTextureVar, int frameVar, + int baseTextureTransformVar, float alphaOverride = -1 ); + + // Helper methods for environment mapping + int SetShadowEnvMappingState( int envMapMaskVar, int tintVar = -1 ); + void SetDynamicEnvMappingState( int envMapVar, int envMapMaskVar, + int baseTextureVar, int envMapFrameVar, int envMapMaskFrameVar, + int frameVar, int maskOffsetVar, int maskScaleVar, int tintVar = -1 ); + + bool UsingFlashlight( IMaterialVar **params ) const; + bool UsingEditor( IMaterialVar **params ) const; + + void DrawFlashlight_dx70( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, + IShaderShadow* pShaderShadow, + int flashlightTextureVar, int flashlightTextureFrameVar, + bool suppress_lighting = false ); + + void SetFlashlightFixedFunctionTextureTransform( MaterialMatrixMode_t matrix ); + + void GetColorParameter( IMaterialVar** params, float *pColorOut ) const; // return tint color (color*color2) + void ApplyColor2Factor( float *pColorOut ) const; // (*pColorOut) *= COLOR2 + + static IMaterialVar **s_ppParams; + +protected: + SoftwareVertexShader_t m_SoftwareVertexShader; + + static const char *s_pTextureGroupName; // Current material's texture group name. + static IShaderShadow *s_pShaderShadow; + static IShaderDynamicAPI *s_pShaderAPI; + static IShaderInit *s_pShaderInit; + +private: + static int s_nModulationFlags; + static CMeshBuilder *s_pMeshBuilder; +}; + + +//----------------------------------------------------------------------------- +// Gets at the current materialvar flags +//----------------------------------------------------------------------------- +inline int CBaseShader::CurrentMaterialVarFlags() const +{ + return s_ppParams[FLAGS]->GetIntValue(); +} + +//----------------------------------------------------------------------------- +// Are we currently taking a snapshot? +//----------------------------------------------------------------------------- +inline bool CBaseShader::IsSnapshotting() const +{ + return (s_pShaderShadow != NULL); +} + +//----------------------------------------------------------------------------- +// Is the color var white? +//----------------------------------------------------------------------------- +inline bool CBaseShader::IsWhite( int colorVar ) +{ + if (colorVar < 0) + return true; + + if (!s_ppParams[colorVar]->IsDefined()) + return true; + + float color[3]; + s_ppParams[colorVar]->GetVecValue( color, 3 ); + return (color[0] >= 1.0f) && (color[1] >= 1.0f) && (color[2] >= 1.0f); +} + + +class CBasePerMaterialContextData // shaders can keep per material data in classes descended from this +{ + public: + uint32 m_nVarChangeID; + bool m_bMaterialVarsChanged; // set by mat system when material vars change. shader should rehtink and then clear the var + + FORCEINLINE CBasePerMaterialContextData( void ) + { + m_bMaterialVarsChanged = true; + m_nVarChangeID = 0xffffffff; + } + + // virtual destructor so that derived classes can have their own data to be cleaned up on + // delete of material + virtual ~CBasePerMaterialContextData( void ) + { + } +}; + +#endif // BASESHADER_H diff --git a/public/shaderlib/ShaderDLL.h b/public/shaderlib/ShaderDLL.h new file mode 100644 index 0000000..69520d9 --- /dev/null +++ b/public/shaderlib/ShaderDLL.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SHADERDLL_H +#define SHADERDLL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IShader; +class ICvar; + +//----------------------------------------------------------------------------- +// The standard implementation of CShaderDLL +//----------------------------------------------------------------------------- +class IShaderDLL +{ +public: + // Adds a shader to the list of shaders + virtual void InsertShader( IShader *pShader ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +IShaderDLL *GetShaderDLL(); + +//----------------------------------------------------------------------------- +// Singleton interface for CVars +//----------------------------------------------------------------------------- +ICvar *GetCVar(); + + + + + +#endif // SHADERDLL_H diff --git a/public/shaderlib/cshader.h b/public/shaderlib/cshader.h new file mode 100644 index 0000000..9c69363 --- /dev/null +++ b/public/shaderlib/cshader.h @@ -0,0 +1,492 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CSHADER_H +#define CSHADER_H + +#ifdef _WIN32 +#pragma once +#endif + +// uncomment this if you want to build for nv3x +//#define NV3X 1 + +// This is what all shaders include. +// CBaseShader will become CShader in this file. +#include "materialsystem/ishaderapi.h" +#include "utlvector.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/imaterial.h" +#include "BaseShader.h" + +#include "materialsystem/itexture.h" + +// Included for convenience because they are used in a bunch of shaders +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/materialsystem_config.h" +#include "shaderlib/ShaderDLL.h" + +// make "local variable is initialized but not referenced" warnings errors for combo checking macros +#pragma warning ( error : 4189 ) + +//----------------------------------------------------------------------------- +// Global interfaces +//----------------------------------------------------------------------------- +extern IMaterialSystemHardwareConfig *g_pHardwareConfig; +extern const MaterialSystem_Config_t *g_pConfig; +extern bool g_shaderConfigDumpEnable; + +// Helper method +bool IsUsingGraphics(); + +#define SOFTWARE_VERTEX_SHADER(name) \ + static void SoftwareVertexShader_ ## name( CMeshBuilder &meshBuilder, IMaterialVar **params, IShaderDynamicAPI* pShaderAPI ) + +#define FORWARD_DECLARE_SOFTWARE_VERTEX_SHADER(name)\ + static void SoftwareVertexShader_ ## name( CMeshBuilder &meshBuilder, IMaterialVar **params, IShaderDynamicAPI* pShaderAPI ); + +#define USE_SOFTWARE_VERTEX_SHADER(name) \ + m_SoftwareVertexShader = SoftwareVertexShader_ ## name + +#define SHADER_INIT_PARAMS() \ + virtual void OnInitShaderParams( IMaterialVar **params, const char *pMaterialName ) + +#define SHADER_FALLBACK \ + virtual char const* GetFallbackShader( IMaterialVar** params ) const + +// Typesafe flag setting +inline void CShader_SetFlags( IMaterialVar **params, MaterialVarFlags_t _flag ) +{ + params[FLAGS]->SetIntValue( params[FLAGS]->GetIntValue() | (_flag) ); +} + +inline bool CShader_IsFlagSet( IMaterialVar **params, MaterialVarFlags_t _flag ) +{ + return ((params[FLAGS]->GetIntValue() & (_flag) ) != 0); +} + +#define SET_FLAGS( _flag ) CShader_SetFlags( params, _flag ) +#define CLEAR_FLAGS( _flag ) params[FLAGS]->SetIntValue( params[FLAGS]->GetIntValue() & ~(_flag) ) +#define IS_FLAG_SET( _flag ) CShader_IsFlagSet( params, _flag ) +#define IS_FLAG_DEFINED( _flag ) ((params[FLAGS_DEFINED]->GetIntValue() & (_flag) ) != 0) + +#define IS_PARAM_DEFINED( _param ) ( ( ( _param >= 0 ) && ( params[_param]->IsDefined() ) ) ) + +#define SET_PARAM_STRING_IF_NOT_DEFINED( nParamIndex, kDefaultValue ) \ + if ( ( nParamIndex != -1 ) && ( !params[nParamIndex]->IsDefined() ) ) \ + { \ + params[nParamIndex]->SetStringValue( kDefaultValue ); \ + } + +#define SET_PARAM_INT_IF_NOT_DEFINED( nParamIndex, kDefaultValue ) \ + if ( ( nParamIndex != -1 ) && ( !params[nParamIndex]->IsDefined() ) ) \ + { \ + params[nParamIndex]->SetIntValue( kDefaultValue ); \ + } + +#define SET_PARAM_FLOAT_IF_NOT_DEFINED( nParamIndex, kDefaultValue ) \ + if ( ( nParamIndex != -1 ) && ( !params[nParamIndex]->IsDefined() ) ) \ + { \ + params[nParamIndex]->SetFloatValue( kDefaultValue ); \ + } + +#define SET_PARAM_VEC_IF_NOT_DEFINED( nParamIndex, kDefaultValue, nSize ) \ + if ( ( nParamIndex != -1 ) && ( !params[nParamIndex]->IsDefined() ) ) \ + { \ + params[nParamIndex]->SetVecValue( kDefaultValue, nSize ); \ + } + +// Typesafe flag setting +inline void CShader_SetFlags2( IMaterialVar **params, MaterialVarFlags2_t _flag ) +{ + params[FLAGS2]->SetIntValue( params[FLAGS2]->GetIntValue() | (_flag) ); +} + +inline bool CShader_IsFlag2Set( IMaterialVar **params, MaterialVarFlags2_t _flag ) +{ + return ((params[FLAGS2]->GetIntValue() & (_flag) ) != 0); +} + +#define SET_FLAGS2( _flag ) CShader_SetFlags2( params, _flag ) +#define CLEAR_FLAGS2( _flag ) params[FLAGS2]->SetIntValue( params[FLAGS2]->GetIntValue() & ~(_flag) ) +#define IS_FLAG2_SET( _flag ) CShader_IsFlag2Set( params, _flag ) +#define IS_FLAG2_DEFINED( _flag ) ((params[FLAGS_DEFINED2]->GetIntValue() & (_flag) ) != 0) + +#define __BEGIN_SHADER_INTERNAL(_baseclass, name, help, flags) \ + namespace name \ + {\ + typedef _baseclass CBaseClass;\ + static const char *s_HelpString = help; \ + static const char *s_Name = #name; \ + static int s_nFlags = flags; \ + class CShaderParam;\ + static CUtlVector s_ShaderParams;\ + static CShaderParam *s_pShaderParamOverrides[NUM_SHADER_MATERIAL_VARS];\ + class CShaderParam\ + {\ + public:\ + CShaderParam( ShaderMaterialVars_t var, ShaderParamType_t type, const char *pDefaultParam, const char *pHelp, int nFlags )\ + {\ + m_Info.m_pName = "override";\ + m_Info.m_Type = type;\ + m_Info.m_pDefaultValue = pDefaultParam;\ + m_Info.m_pHelp = pHelp;\ + m_Info.m_nFlags = nFlags;\ + AssertMsg( !s_pShaderParamOverrides[var], ( "Shader parameter override duplicately defined!" ) );\ + s_pShaderParamOverrides[var] = this;\ + m_Index = var;\ + }\ + CShaderParam( const char *pName, ShaderParamType_t type, const char *pDefaultParam, const char *pHelp, int nFlags )\ + {\ + m_Info.m_pName = pName;\ + m_Info.m_Type = type;\ + m_Info.m_pDefaultValue = pDefaultParam;\ + m_Info.m_pHelp = pHelp;\ + m_Info.m_nFlags = nFlags;\ + m_Index = NUM_SHADER_MATERIAL_VARS + s_ShaderParams.Count();\ + s_ShaderParams.AddToTail( this );\ + }\ + operator int() \ + {\ + return m_Index;\ + }\ + const char *GetName()\ + {\ + return m_Info.m_pName;\ + }\ + ShaderParamType_t GetType()\ + {\ + return m_Info.m_Type;\ + }\ + const char *GetDefault()\ + {\ + return m_Info.m_pDefaultValue;\ + }\ + int GetFlags() const\ + {\ + return m_Info.m_nFlags;\ + }\ + const char *GetHelp()\ + {\ + return m_Info.m_pHelp;\ + }\ + private:\ + ShaderParamInfo_t m_Info; \ + int m_Index;\ + };\ + +#define BEGIN_SHADER(name,help) __BEGIN_SHADER_INTERNAL( CBaseShader, name, help, 0 ) +#define BEGIN_SHADER_FLAGS(name,help,flags) __BEGIN_SHADER_INTERNAL( CBaseShader, name, help, flags ) + +#define BEGIN_SHADER_PARAMS + +#define SHADER_PARAM( param, paramtype, paramdefault, paramhelp ) \ + static CShaderParam param( "$" #param, paramtype, paramdefault, paramhelp, 0 ); + +#define SHADER_PARAM_FLAGS( param, paramtype, paramdefault, paramhelp, flags ) \ + static CShaderParam param( "$" #param, paramtype, paramdefault, paramhelp, flags ); + +#define SHADER_PARAM_OVERRIDE( param, paramtype, paramdefault, paramhelp, flags ) \ + static CShaderParam param( (ShaderMaterialVars_t) ::param, paramtype, paramdefault, paramhelp, flags ); + + // regarding the macro above: the "::" was added to the first argument in order to disambiguate it for GCC. + // for example, in cloak.cpp, this usage appears: + // SHADER_PARAM_OVERRIDE( COLOR, SHADER_PARAM_TYPE_COLOR, "{255 255 255}", "unused", SHADER_PARAM_NOT_EDITABLE ) + // which in turn tries to ask the compiler to instantiate an object like so: + // static CShaderParam COLOR( (ShaderMaterialVars_t)COLOR, SHADER_PARAM_TYPE_COLOR, "{255 255 255}", "unused", SHADER_PARAM_NOT_EDITABLE ) + // and GCC thinks that the reference to COLOR in the arg list is actually a reference to the object we're in the middle of making. + // and you get --> error: invalid cast from type ‘Cloak_DX90::CShaderParam’ to type ‘ShaderMaterialVars_t’ + // Resolved: add the "::" so compiler knows that reference is to the enum, not to the name of the object being made. + + +#define END_SHADER_PARAMS \ + class CShader : public CBaseClass\ + {\ + public: + +#define END_SHADER }; \ + static CShader s_ShaderInstance;\ +} // namespace + + +#define SHADER_INIT \ + char const* GetName() const \ + { \ + return s_Name; \ + } \ + int GetFlags() const \ + { \ + return s_nFlags; \ + } \ + int GetNumParams() const \ + {\ + return CBaseClass::GetNumParams() + s_ShaderParams.Count();\ + }\ + char const* GetParamName( int param ) const \ + {\ + int nBaseClassParamCount = CBaseClass::GetNumParams(); \ + if (param < nBaseClassParamCount) \ + return CBaseClass::GetParamName(param); \ + else \ + return s_ShaderParams[param - nBaseClassParamCount]->GetName(); \ + }\ + char const* GetParamHelp( int param ) const \ + {\ + int nBaseClassParamCount = CBaseClass::GetNumParams(); \ + if (param < nBaseClassParamCount) \ + { \ + if ( !s_pShaderParamOverrides[param] ) \ + return CBaseClass::GetParamHelp( param ); \ + else \ + return s_pShaderParamOverrides[param]->GetHelp(); \ + } \ + else \ + return s_ShaderParams[param - nBaseClassParamCount]->GetHelp(); \ + }\ + ShaderParamType_t GetParamType( int param ) const \ + {\ + int nBaseClassParamCount = CBaseClass::GetNumParams(); \ + if (param < nBaseClassParamCount) \ + return CBaseClass::GetParamType( param ); \ + else \ + return s_ShaderParams[param - nBaseClassParamCount]->GetType(); \ + }\ + char const* GetParamDefault( int param ) const \ + {\ + int nBaseClassParamCount = CBaseClass::GetNumParams(); \ + if (param < nBaseClassParamCount) \ + { \ + if ( !s_pShaderParamOverrides[param] ) \ + return CBaseClass::GetParamDefault( param ); \ + else \ + return s_pShaderParamOverrides[param]->GetDefault(); \ + } \ + else \ + return s_ShaderParams[param - nBaseClassParamCount]->GetDefault(); \ + }\ + int GetParamFlags( int param ) const \ + {\ + int nBaseClassParamCount = CBaseClass::GetNumParams(); \ + if (param < nBaseClassParamCount) \ + { \ + if ( !s_pShaderParamOverrides[param] ) \ + return CBaseClass::GetParamFlags( param ); \ + else \ + return s_pShaderParamOverrides[param]->GetFlags(); \ + } \ + else \ + return s_ShaderParams[param - nBaseClassParamCount]->GetFlags(); \ + }\ + void OnInitShaderInstance( IMaterialVar **params, IShaderInit *pShaderInit, const char *pMaterialName ) + +#define SHADER_DRAW \ + void OnDrawElements( IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, CBasePerMaterialContextData **pContextDataPtr ) + +#define SHADOW_STATE if (pShaderShadow) +#define DYNAMIC_STATE if (pShaderAPI) + +#define ShaderWarning if (pShaderShadow) Warning + +//----------------------------------------------------------------------------- +// Used to easily define a shader which *always* falls back +//----------------------------------------------------------------------------- +#define DEFINE_FALLBACK_SHADER( _shadername, _fallbackshadername ) \ + BEGIN_SHADER( _shadername, "" ) \ + BEGIN_SHADER_PARAMS \ + END_SHADER_PARAMS \ + SHADER_FALLBACK { return #_fallbackshadername; } \ + SHADER_INIT {} \ + SHADER_DRAW {} \ + END_SHADER + + +//----------------------------------------------------------------------------- +// Used to easily define a shader which inherits from another shader +//----------------------------------------------------------------------------- + +// FIXME: There's a compiler bug preventing this from working. +// Maybe it'll work under VC7! + +/* +//#define BEGIN_INHERITED_SHADER( name, _baseclass, help ) \ +// namespace _baseclass \ +// {\ +// __BEGIN_SHADER_INTERNAL( _baseclass::CShader, name, help ) +*/ + +//#define END_INHERITED_SHADER END_SHADER } + +//#define CHAIN_SHADER_INIT_PARAMS() CBaseClass::OnInitShaderParams( params, pMaterialName ) +//#define CHAIN_SHADER_FALLBACK() CBaseClass::GetFallbackShader( params ) +//#define CHAIN_SHADER_INIT() CBaseClass::OnInitShaderInstance( params, pShaderInit, pMaterialName ) +//#define CHAIN_SHADER_DRAW() CBaseClass::OnDrawElements( params, pShaderShadow, pShaderAPI ) + +// A dumbed-down version which does what I need now which works +// This version doesn't allow you to do chain *anything* down to the base class +#define BEGIN_INHERITED_SHADER_FLAGS( _name, _base, _help, _flags ) \ + namespace _base\ + {\ + namespace _name\ + {\ + static const char *s_Name = #_name; \ + static const char *s_HelpString = _help;\ + static int s_nFlags = _flags;\ + class CShader : public _base::CShader\ + {\ + public:\ + char const* GetName() const \ + { \ + return s_Name; \ + } \ + int GetFlags() const \ + { \ + return s_nFlags; \ + } + +#define BEGIN_INHERITED_SHADER( _name, _base, _help ) BEGIN_INHERITED_SHADER_FLAGS( _name, _base, _help, 0 ) +#define END_INHERITED_SHADER END_SHADER } + +// psh ## shader is used here to generate a warning if you don't ever call SET_DYNAMIC_PIXEL_SHADER +#define DECLARE_DYNAMIC_PIXEL_SHADER( shader ) \ + int declaredynpixshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( declaredynpixshader_ ## shader ## _missingcurlybraces ); \ + shader ## _Dynamic_Index _pshIndex; \ + int psh ## shader = 0 + +// vsh ## shader is used here to generate a warning if you don't ever call SET_DYNAMIC_VERTEX_SHADER +#define DECLARE_DYNAMIC_VERTEX_SHADER( shader ) \ + int declaredynvertshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( declaredynvertshader_ ## shader ## _missingcurlybraces ); \ + shader ## _Dynamic_Index _vshIndex; \ + int vsh ## shader = 0 + + +// psh ## shader is used here to generate a warning if you don't ever call SET_STATIC_PIXEL_SHADER +#define DECLARE_STATIC_PIXEL_SHADER( shader ) \ + int declarestaticpixshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( declarestaticpixshader_ ## shader ## _missingcurlybraces ); \ + shader ## _Static_Index _pshIndex; \ + int psh ## shader = 0 + +// vsh ## shader is used here to generate a warning if you don't ever call SET_STATIC_VERTEX_SHADER +#define DECLARE_STATIC_VERTEX_SHADER( shader ) \ + int declarestaticvertshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( declarestaticvertshader_ ## shader ## _missingcurlybraces ); \ + shader ## _Static_Index _vshIndex; \ + int vsh ## shader = 0 + + +// psh_forgot_to_set_dynamic_ ## var is used to make sure that you set all +// all combos. If you don't, you will get an undefined variable used error +// in the SET_DYNAMIC_PIXEL_SHADER block. +#define SET_DYNAMIC_PIXEL_SHADER_COMBO( var, val ) \ + int dynpixshadercombo_ ## var ## _missingcurlybraces = 0; \ + NOTE_UNUSED( dynpixshadercombo_ ## var ## _missingcurlybraces ); \ + _pshIndex.Set ## var( ( val ) ); if(g_shaderConfigDumpEnable){printf("\n PS dyn var %s = %d (%s)", #var, (int) val, #val );}; \ + int psh_forgot_to_set_dynamic_ ## var = 0 + +// vsh_forgot_to_set_dynamic_ ## var is used to make sure that you set all +// all combos. If you don't, you will get an undefined variable used error +// in the SET_DYNAMIC_VERTEX_SHADER block. +#define SET_DYNAMIC_VERTEX_SHADER_COMBO( var, val ) \ + int dynvertshadercombo_ ## var ## _missingcurlybraces = 0; \ + NOTE_UNUSED( dynvertshadercombo_ ## var ## _missingcurlybraces ); \ + _vshIndex.Set ## var( ( val ) ); if(g_shaderConfigDumpEnable){printf("\n VS dyn var %s = %d (%s)", #var, (int) val, #val );}; \ + int vsh_forgot_to_set_dynamic_ ## var = 0 + + +// psh_forgot_to_set_static_ ## var is used to make sure that you set all +// all combos. If you don't, you will get an undefined variable used error +// in the SET_STATIC_PIXEL_SHADER block. +#define SET_STATIC_PIXEL_SHADER_COMBO( var, val ) \ + int staticpixshadercombo_ ## var ## _missingcurlybraces = 0; \ + NOTE_UNUSED( staticpixshadercombo_ ## var ## _missingcurlybraces ); \ + _pshIndex.Set ## var( ( val ) ); if(g_shaderConfigDumpEnable){printf("\n PS stat var %s = %d (%s)", #var, (int) val, #val );}; \ + int psh_forgot_to_set_static_ ## var = 0 + +// vsh_forgot_to_set_static_ ## var is used to make sure that you set all +// all combos. If you don't, you will get an undefined variable used error +// in the SET_STATIC_VERTEX_SHADER block. +#define SET_STATIC_VERTEX_SHADER_COMBO( var, val ) \ + int staticvertshadercombo_ ## var ## _missingcurlybraces = 0; \ + NOTE_UNUSED( staticvertshadercombo_ ## var ## _missingcurlybraces ); \ + _vshIndex.Set ## var( ( val ) ); if(g_shaderConfigDumpEnable){printf("\n VS stat var %s = %d (%s)", #var, (int) val, #val );}; \ + int vsh_forgot_to_set_static_ ## var = 0 + + +// psh_testAllCombos adds up all of the psh_forgot_to_set_dynamic_ ## var's from +// SET_DYNAMIC_PIXEL_SHADER_COMBO so that an error is generated if they aren't set. +// psh_testAllCombos is set to itself to avoid an unused variable warning. +// psh ## shader being set to itself ensures that DECLARE_DYNAMIC_PIXEL_SHADER +// was called for this particular shader. +#define SET_DYNAMIC_PIXEL_SHADER( shader ) \ + int dynamicpixshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( dynamicpixshader_ ## shader ## _missingcurlybraces ); \ + int psh_testAllCombos = shaderDynamicTest_ ## shader; \ + NOTE_UNUSED( psh_testAllCombos ); \ + NOTE_UNUSED( psh ## shader ); \ + pShaderAPI->SetPixelShaderIndex( _pshIndex.GetIndex() ) + +#define SET_DYNAMIC_PIXEL_SHADER_CMD( cmdstream, shader ) \ + int dynamicpixshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( dynamicpixshader_ ## shader ## _missingcurlybraces ); \ + int psh_testAllCombos = shaderDynamicTest_ ## shader; \ + NOTE_UNUSED( psh_testAllCombos ); \ + NOTE_UNUSED( psh ## shader ); \ + cmdstream.SetPixelShaderIndex( _pshIndex.GetIndex() ) + + +// vsh_testAllCombos adds up all of the vsh_forgot_to_set_dynamic_ ## var's from +// SET_DYNAMIC_VERTEX_SHADER_COMBO so that an error is generated if they aren't set. +// vsh_testAllCombos is set to itself to avoid an unused variable warning. +// vsh ## shader being set to itself ensures that DECLARE_DYNAMIC_VERTEX_SHADER +// was called for this particular shader. +#define SET_DYNAMIC_VERTEX_SHADER( shader ) \ + int dynamicvertshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( dynamicvertshader_ ## shader ## _missingcurlybraces ); \ + int vsh_testAllCombos = shaderDynamicTest_ ## shader; \ + NOTE_UNUSED( vsh_testAllCombos ); \ + NOTE_UNUSED( vsh ## shader ); \ + pShaderAPI->SetVertexShaderIndex( _vshIndex.GetIndex() ) + +#define SET_DYNAMIC_VERTEX_SHADER_CMD( cmdstream, shader ) \ + int dynamicvertshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( dynamicvertshader_ ## shader ## _missingcurlybraces ); \ + int vsh_testAllCombos = shaderDynamicTest_ ## shader; \ + NOTE_UNUSED( vsh_testAllCombos ); \ + NOTE_UNUSED( vsh ## shader ); \ + cmdstream.SetVertexShaderIndex( _vshIndex.GetIndex() ) + + +// psh_testAllCombos adds up all of the psh_forgot_to_set_static_ ## var's from +// SET_STATIC_PIXEL_SHADER_COMBO so that an error is generated if they aren't set. +// psh_testAllCombos is set to itself to avoid an unused variable warning. +// psh ## shader being set to itself ensures that DECLARE_STATIC_PIXEL_SHADER +// was called for this particular shader. +#define SET_STATIC_PIXEL_SHADER( shader ) \ + int staticpixshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( staticpixshader_ ## shader ## _missingcurlybraces ); \ + int psh_testAllCombos = shaderStaticTest_ ## shader; \ + NOTE_UNUSED( psh_testAllCombos ); \ + NOTE_UNUSED( psh ## shader ); \ + pShaderShadow->SetPixelShader( #shader, _pshIndex.GetIndex() ) + +// vsh_testAllCombos adds up all of the vsh_forgot_to_set_static_ ## var's from +// SET_STATIC_VERTEX_SHADER_COMBO so that an error is generated if they aren't set. +// vsh_testAllCombos is set to itself to avoid an unused variable warning. +// vsh ## shader being set to itself ensures that DECLARE_STATIC_VERTEX_SHADER +// was called for this particular shader. +#define SET_STATIC_VERTEX_SHADER( shader ) \ + int staticvertshader_ ## shader ## _missingcurlybraces = 0; \ + NOTE_UNUSED( staticvertshader_ ## shader ## _missingcurlybraces ); \ + int vsh_testAllCombos = shaderStaticTest_ ## shader; \ + NOTE_UNUSED( vsh_testAllCombos ); \ + NOTE_UNUSED( vsh ## shader ); \ + pShaderShadow->SetVertexShader( #shader, _vshIndex.GetIndex() ) + +#endif // CSHADER_H diff --git a/public/shake.h b/public/shake.h new file mode 100644 index 0000000..8283d8d --- /dev/null +++ b/public/shake.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Network data for screen shake and screen fade. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SHAKE_H +#define SHAKE_H +#ifdef _WIN32 +#pragma once +#endif + + +// +// Commands for the screen shake effect. +// + +struct ScreenShake_t +{ + int command; + float amplitude; + float frequency; + float duration; +}; + +enum ShakeCommand_t +{ + SHAKE_START = 0, // Starts the screen shake for all players within the radius. + SHAKE_STOP, // Stops the screen shake for all players within the radius. + SHAKE_AMPLITUDE, // Modifies the amplitude of an active screen shake for all players within the radius. + SHAKE_FREQUENCY, // Modifies the frequency of an active screen shake for all players within the radius. + SHAKE_START_RUMBLEONLY, // Starts a shake effect that only rumbles the controller, no screen effect. + SHAKE_START_NORUMBLE, // Starts a shake that does NOT rumble the controller. +}; + + +// +// Screen shake message. +// +extern int gmsgShake; + +// Fade in/out +extern int gmsgFade; + +#define FFADE_IN 0x0001 // Just here so we don't pass 0 into the function +#define FFADE_OUT 0x0002 // Fade out (not in) +#define FFADE_MODULATE 0x0004 // Modulate (don't blend) +#define FFADE_STAYOUT 0x0008 // ignores the duration, stays faded out until new ScreenFade message received +#define FFADE_PURGE 0x0010 // Purges all other fades, replacing them with this one + +#define SCREENFADE_FRACBITS 9 // which leaves 16-this for the integer part +// This structure is sent over the net to describe a screen fade event +struct ScreenFade_t +{ + unsigned short duration; // FIXED 16 bit, with SCREENFADE_FRACBITS fractional, seconds duration + unsigned short holdTime; // FIXED 16 bit, with SCREENFADE_FRACBITS fractional, seconds duration until reset (fade & hold) + short fadeFlags; // flags + byte r, g, b, a; // fade to color ( max alpha ) +}; + + +#endif // SHAKE_H diff --git a/public/shattersurfacetypes.h b/public/shattersurfacetypes.h new file mode 100644 index 0000000..eb5c55b --- /dev/null +++ b/public/shattersurfacetypes.h @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined ( SHATTERSURFACETYPES_H ) +#define SHATTERSURFACETYPES_H +#ifdef _WIN32 +#pragma once +#endif + +enum ShatterSurface_t +{ + // Note: This much match with the client entity + SHATTERSURFACE_GLASS = 0, + SHATTERSURFACE_TILE = 1, +}; + +#endif diff --git a/public/simple_physics.cpp b/public/simple_physics.cpp new file mode 100644 index 0000000..0d1eed3 --- /dev/null +++ b/public/simple_physics.cpp @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "simple_physics.h" +#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CSimplePhysics::CSimplePhysics() +{ + Init( 1.0f / 30.0f ); // default is 30 steps per second +} + + +void CSimplePhysics::Init( float flTimeStep ) +{ + m_flPredictedTime = 0; + m_iCurTimeStep = 0; + m_flTimeStep = flTimeStep; + m_flTimeStepMul = m_flTimeStep*m_flTimeStep*0.5f; +} + + +void CSimplePhysics::Simulate( + CSimplePhysics::CNode *pNodes, + int nNodes, + CSimplePhysics::IHelper *pHelper, + float dt, + float flDamp ) +{ + // Figure out how many time steps to run. + m_flPredictedTime += dt; + int newTimeStep = (int)ceil( m_flPredictedTime / m_flTimeStep ); + int nTimeSteps = newTimeStep - m_iCurTimeStep; + for( int iTimeStep=0; iTimeStep < nTimeSteps; iTimeStep++ ) + { + // Simulate everything.. + for( int iNode=0; iNode < nNodes; iNode++ ) + { + CSimplePhysics::CNode *pNode = &pNodes[iNode]; + + // Apply forces. + Vector vAccel; + pHelper->GetNodeForces( pNodes, iNode, &vAccel ); + Assert( vAccel.IsValid() ); + + Vector vPrevPos = pNode->m_vPos; + pNode->m_vPos = pNode->m_vPos + (pNode->m_vPos - pNode->m_vPrevPos) * flDamp + vAccel * m_flTimeStepMul; + pNode->m_vPrevPos = vPrevPos; + } + + // Apply constraints. + pHelper->ApplyConstraints( pNodes, nNodes ); + } + m_iCurTimeStep = newTimeStep; + + // Setup predicted positions. + float flInterpolant = (m_flPredictedTime - (GetCurTime() - m_flTimeStep)) / m_flTimeStep; + for( int iNode=0; iNode < nNodes; iNode++ ) + { + CSimplePhysics::CNode *pNode = &pNodes[iNode]; + VectorLerp( pNode->m_vPrevPos, pNode->m_vPos, flInterpolant, pNode->m_vPredicted ); + } +} + + diff --git a/public/simple_physics.h b/public/simple_physics.h new file mode 100644 index 0000000..fd40b18 --- /dev/null +++ b/public/simple_physics.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SIMPLE_PHYSICS_H +#define SIMPLE_PHYSICS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/vector.h" + + +// CSimplePhysics is a framework for simplified physics simulation. +// It simulates at a fixed timestep and uses the Verlet integrator. +// +// To use it, create your nodes and implement your constraints and +// forces in an IHelper, then call Simulate each frame. +// CSimplePhysics will figure out how many timesteps to run and will +// provide predicted positions of things for you. +class CSimplePhysics +{ +public: + + class CNode + { + public: + + // Call this when initializing the nodes with their starting positions. + void Init( const Vector &vPos ) + { + m_vPos = m_vPrevPos = m_vPredicted = vPos; + } + + Vector m_vPos; // At time t + Vector m_vPrevPos; // At time t - m_flTimeStep + Vector m_vPredicted; // Predicted position + }; + + class IHelper + { + public: + virtual void GetNodeForces( CNode *pNodes, int iNode, Vector *pAccel ) = 0; + virtual void ApplyConstraints( CNode *pNodes, int nNodes ) = 0; + }; + + +public: + + CSimplePhysics(); + + void Init( float flTimeStep ); + + void Simulate( + CNode *pNodes, + int nNodes, + IHelper *pHelper, + float dt, + float flDamp ); + + +private: + + double GetCurTime() { return m_flTimeStep * m_iCurTimeStep; } + + +private: + + double m_flPredictedTime; // (GetCurTime()-m_flTimeStep) <= m_flPredictedTime <= GetCurTime() + int m_iCurTimeStep; + + float m_flTimeStep; + float m_flTimeStepMul; // dt*dt*0.5 +}; + + +#endif // SIMPLE_PHYSICS_H diff --git a/public/smooth_average.h b/public/smooth_average.h new file mode 100644 index 0000000..52f32a1 --- /dev/null +++ b/public/smooth_average.h @@ -0,0 +1,222 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SMOOTH_AVERAGE_H +#define SMOOTH_AVERAGE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "utldict.h" + + + +// Use this macro around any value, and it'll queue up the results given to it nTimes and +// provide a running average. +#define SMOOTH_AVERAGE( value, nCount ) CalcSmoothAverage( value, nCount, __FILE__, __LINE__ ) + + +// Same as their counterpart functions but they return more info in a CTimingInfo structure. +#define SMOOTH_AVERAGE_STRUCT( value, nCount ) CalcSmoothAverage_Struct( value, nCount, __FILE__, __LINE__ ) +#define SUM_OVER_TIME_INTERVAL_STRUCT( value, nSeconds ) SumOverTimeInterval_Struct( value, nSeconds, __FILE__, __LINE__ ) + + +template< class T > +class CTimingInfo +{ +public: + T m_AverageValue; // Note: this will be the SUM of the values if using SUM_OVER_TIME_INTERVAL. + + // The high and low points for m_AverageValue over the time interval. + T m_HighAverage; + T m_LowAverage; + + // The high and low points for the value itself over the time interval. + T m_HighValue; + T m_LowValue; +}; + + +template< class T > +class CAveragesInfo +{ +public: + class CEntry + { + public: + T m_Average; + T m_Value; + }; + +public: + CUtlVector< CEntry > m_Values; + int m_iCurValue; +}; + + +template< class T > +class CAveragesInfo_TimeBased +{ +public: + class CEntry + { + public: + CCycleCount m_Time; // When this sample was taken. + T m_Value; + T m_Average; + }; + + CUtlVector m_Values; +}; + + +#if 0 +template< class T > +inline CTimingInfo< T > CalcSmoothAverage_Struct( const T &value, int nTimes, const char *pFilename, int iLine ) +{ + // Find an entry at this file and line. + char fullStr[1024]; + Q_snprintf( fullStr, sizeof( fullStr ), "%s_%i", pFilename, iLine ); + + int index = s_SmoothAverages.Find( fullStr ); + CAveragesInfo *pInfo; + if ( index == s_SmoothAverages.InvalidIndex() ) + { + pInfo = new CAveragesInfo; + index = s_SmoothAverages.Insert( fullStr, pInfo ); + } + else + { + pInfo = (CAveragesInfo*)s_SmoothAverages[index]; + } + + // Add the new value. + int newValueIndex; + CAveragesInfo< T >::CEntry entry; + entry.m_Value = value; + if ( pInfo->m_Values.Count() < nTimes ) + { + newValueIndex = pInfo->m_Values.AddToTail( entry ); + pInfo->m_iCurValue = 0; + } + else + { + newValueIndex = pInfo->m_iCurValue; + pInfo->m_Values[pInfo->m_iCurValue] = entry; + pInfo->m_iCurValue = (pInfo->m_iCurValue+1) % pInfo->m_Values.Count(); + } + + CTimingInfo< T > info; + info.m_AverageValue = pInfo->m_Values[0].m_Value; + + info.m_HighAverage = pInfo->m_Values[0].m_Average; + info.m_LowAverage = pInfo->m_Values[0].m_Average; + + info.m_HighValue = pInfo->m_Values[0].m_Value; + info.m_LowValue = pInfo->m_Values[0].m_Value; + + for ( int i=1; i < pInfo->m_Values.Count(); i++ ) + { + if ( i != newValueIndex ) + { + info.m_HighAverage = vmax( pInfo->m_Values[i].m_Average, info.m_HighAverage ); + info.m_LowAverage = vmin( pInfo->m_Values[i].m_Average, info.m_LowAverage ); + } + + info.m_HighValue = vmax( pInfo->m_Values[i].m_Value, info.m_HighValue ); + info.m_LowValue = vmin( pInfo->m_Values[i].m_Value, info.m_LowValue ); + + info.m_AverageValue += pInfo->m_Values[i].m_Value; + } + + info.m_AverageValue /= pInfo->m_Values.Count(); + pInfo->m_Values[newValueIndex].m_Average = info.m_AverageValue; + return info; +} +#endif + +template< class T > +inline T CalcSmoothAverage( const T &value, int nTimes, const char *pFilename, int iLine ) +{ + CTimingInfo< T > info = CalcSmoothAverage_Struct( value, nTimes, pFilename, iLine ); + return info.m_AverageValue; +}; + + +template< class T > +inline CTimingInfo< T > SumOverTimeInterval_Struct( const T &value, float nSeconds, const char *pFilename, int iLine ) +{ + static CUtlDict< CAveragesInfo_TimeBased< T >*, int > s_SmoothAverages; + + char fullStr[1024]; + Q_snprintf( fullStr, sizeof( fullStr ), "%s_%i", pFilename, iLine ); + + int index = s_SmoothAverages.Find( fullStr ); + CAveragesInfo_TimeBased *pInfo; + if ( index == s_SmoothAverages.InvalidIndex() ) + { + pInfo = new CAveragesInfo_TimeBased; + index = s_SmoothAverages.Insert( fullStr, pInfo ); + } + else + { + pInfo = s_SmoothAverages[index]; + } + + // Get the current time now. + CCycleCount curTime; + curTime.Sample(); + + // Get rid of old samples. + while ( pInfo->m_Values.Count() > 0 && (curTime.GetSeconds() - pInfo->m_Values[0].m_Time.GetSeconds()) > nSeconds ) + pInfo->m_Values.Remove( 0 ); + + // Add on the new sample. + typename CAveragesInfo_TimeBased< T >::CEntry newEntry; + newEntry.m_Time = curTime; + newEntry.m_Value = value; + int newValueIndex = pInfo->m_Values.AddToTail( newEntry ); + + CTimingInfo< T > info; + info.m_AverageValue = pInfo->m_Values[0].m_Value; + + info.m_HighAverage = pInfo->m_Values[0].m_Average; + info.m_LowAverage = pInfo->m_Values[0].m_Average; + + info.m_HighValue = pInfo->m_Values[0].m_Value; + info.m_LowValue = pInfo->m_Values[0].m_Value; + + for ( int i=1; i < pInfo->m_Values.Count(); i++ ) + { + if ( i != newValueIndex ) + { + info.m_HighAverage = vmax( pInfo->m_Values[i].m_Average, info.m_HighAverage ); + info.m_LowAverage = vmin( pInfo->m_Values[i].m_Average, info.m_LowAverage ); + } + + info.m_HighValue = vmax( pInfo->m_Values[i].m_Value, info.m_HighValue ); + info.m_LowValue = vmin( pInfo->m_Values[i].m_Value, info.m_LowValue ); + + info.m_AverageValue += pInfo->m_Values[i].m_Value; + } + + info.m_AverageValue /= pInfo->m_Values.Count(); + pInfo->m_Values[newValueIndex].m_Average = info.m_AverageValue; + return info; +} + + +template< class T > +inline CTimingInfo< T > SumOverTimeInterval( const T &value, float nSeconds, const char *pFilename, int iLine ) +{ + CTimingInfo< T > info = SumOverTimeInterval_Struct( value, nSeconds, pFilename, iLine ); + return info.m_AverageValue; +} + + +#endif // SMOOTH_AVERAGE_H + diff --git a/public/soundchars.h b/public/soundchars.h new file mode 100644 index 0000000..cca7779 --- /dev/null +++ b/public/soundchars.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SOUNDCHARS_H +#define SOUNDCHARS_H +#ifdef _WIN32 +#pragma once +#endif + +#define CHAR_STREAM '*' // as one of 1st 2 chars in name, indicates streaming wav data +#define CHAR_USERVOX '?' // as one of 1st 2 chars in name, indicates user realtime voice data +#define CHAR_SENTENCE '!' // as one of 1st 2 chars in name, indicates sentence wav +#define CHAR_DRYMIX '#' // as one of 1st 2 chars in name, indicates wav bypasses dsp fx +#define CHAR_DOPPLER '>' // as one of 1st 2 chars in name, indicates doppler encoded stereo wav: left wav (incomming) and right wav (outgoing). +#define CHAR_DIRECTIONAL '<' // as one of 1st 2 chars in name, indicates stereo wav has direction cone: mix left wav (front facing) with right wav (rear facing) based on soundfacing direction +#define CHAR_DISTVARIANT '^' // as one of 1st 2 chars in name, indicates distance variant encoded stereo wav (left is close, right is far) +#define CHAR_OMNI '@' // as one of 1st 2 chars in name, indicates non-directional wav (default mono or stereo) +#define CHAR_SPATIALSTEREO ')' // as one of 1st 2 chars in name, indicates spatialized stereo wav +#define CHAR_FAST_PITCH '}' // as one of 1st 2 chars in name, forces low quality, non-interpolated pitch shift + +inline bool IsSoundChar(char c) +{ + bool b; + + b = (c == CHAR_STREAM || c == CHAR_USERVOX || c == CHAR_SENTENCE || c == CHAR_DRYMIX || c == CHAR_OMNI ); + b = b || (c == CHAR_DOPPLER || c == CHAR_DIRECTIONAL || c == CHAR_DISTVARIANT || c == CHAR_SPATIALSTEREO || c == CHAR_FAST_PITCH ); + + return b; +} + +// return pointer to first valid character in file name +// by skipping over CHAR_STREAM...CHAR_DRYMIX + +inline char *PSkipSoundChars(const char *pch) +{ + char *pcht = (char *)pch; + + while ( 1 ) + { + if (!IsSoundChar(*pcht)) + break; + pcht++; + } + + return pcht; +} + + +inline bool TestSoundChar(const char *pch, char c) +{ + char *pcht = (char *)pch; + + while ( 1 ) + { + if (!IsSoundChar(*pcht)) + break; + if (*pcht == c) + return true; + pcht++; + } + + return false; +} + +#endif // SOUNDCHARS_H diff --git a/public/soundcombiner.cpp b/public/soundcombiner.cpp new file mode 100644 index 0000000..61d897b --- /dev/null +++ b/public/soundcombiner.cpp @@ -0,0 +1,823 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "cbase.h" +#include "isoundcombiner.h" +#include "sentence.h" +#include "filesystem.h" +#include "tier2/riff.h" +#include "tier1/utlbuffer.h" +#include "snd_audio_source.h" +#include "snd_wave_source.h" +#include "AudioWaveOutput.h" +#include "ifaceposersound.h" +#include "vstdlib/random.h" +#include "checksum_crc.h" + +#define WAVEOUTPUT_BITSPERCHANNEL 16 +#define WAVEOUTPUT_FREQUENCY 44100 + +class CSoundCombiner : public ISoundCombiner +{ +public: + CSoundCombiner() : + m_pWaveOutput( NULL ), + m_pOutRIFF( NULL ), + m_pOutIterator( NULL ) + { + m_szOutFile[ 0 ] = 0; + } + + virtual bool CombineSoundFiles( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ); + virtual bool IsCombinedFileChecksumValid( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ); + +private: + + struct CombinerWork + { + CombinerWork() : + sentence(), + duration( 0.0 ), + wave( 0 ), + mixer( 0 ), + entry( 0 ) + { + } + CSentence sentence; + float duration; + CAudioSource *wave; + CAudioMixer *mixer; + CombinerEntry *entry; + }; + + bool InternalCombineSoundFiles( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ); + bool VerifyFilesExist( IFileSystem *filesystem, CUtlVector< CombinerEntry >& info ); + bool CreateWorkList( IFileSystem *filesystem, CUtlVector< CombinerEntry >& info ); + + bool PerformSplicingOnWorkItems( IFileSystem *filesystem ); + void CleanupWork(); + + // .wav file utils + int ComputeBestNumChannels(); + void ParseSentence( CSentence& sentence, IterateRIFF &walk ); + bool LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io ); + bool LoadSentenceFromWavFile( char const *wavfile, CSentence& sentence ); + void StoreValveDataChunk( CSentence& sentence ); +// bool SaveSentenceToWavFile( char const *wavfile, CSentence& sentence ); + + bool InitSplicer( IFileSystem *filesystem, int samplerate, int numchannels, int bitspersample ); + bool LoadSpliceAudioSources(); + bool AppendSilence( int ¤tsample, float duration ); + bool AppendStereo16Data( short samples[ 2 ] ); + bool AppendWaveData( int& currentsample, CAudioSource *wave, CAudioMixer *mixer ); + void AddSentenceToCombined( float offset, CSentence& sentence ); + + unsigned int CheckSumWork( IFileSystem *filesystem, CUtlVector< CombinerEntry >& info ); + unsigned int ComputeChecksum(); + + CUtlVector< CombinerWork * > m_Work; + CSentence m_Combined; + + CAudioWaveOutput *m_pWaveOutput; + + OutFileRIFF *m_pOutRIFF; + IterateOutputRIFF *m_pOutIterator; + + int m_nSampleRate; + int m_nNumChannels; + int m_nBitsPerSample; + int m_nBytesPerSample; + char m_szOutFile[ MAX_PATH ]; +}; + +static CSoundCombiner g_SoundCombiner; +ISoundCombiner *soundcombiner = &g_SoundCombiner; + +bool CSoundCombiner::CreateWorkList( IFileSystem *filesystem, CUtlVector< CombinerEntry >& info ) +{ + m_Work.RemoveAll(); + + int c = info.Count(); + for ( int i = 0; i < c; ++i ) + { + CombinerWork *workitem = new CombinerWork(); + + char fullpath[ MAX_PATH ]; + Q_strncpy( fullpath, info[ i ].wavefile, sizeof( fullpath ) ); + filesystem->GetLocalPath( info[ i ].wavefile, fullpath, sizeof( fullpath ) ); + + if ( !LoadSentenceFromWavFile( fullpath, workitem->sentence ) ) + { + Warning( "CSoundCombiner::CreateWorkList couldn't load %s for work item (%d)\n", + fullpath, i ); + return false; + } + + workitem->entry = &info[ i ]; + + m_Work.AddToTail( workitem ); + } + + return true; +} + +void CSoundCombiner::CleanupWork() +{ + int c = m_Work.Count(); + for ( int i = 0; i < c; ++i ) + { + CombinerWork *workitem = m_Work[ i ]; + delete workitem->mixer; + delete workitem->wave; + + delete m_Work[ i ]; + } + m_Work.RemoveAll(); + + delete m_pOutIterator; + m_pOutIterator = NULL; + + delete m_pOutRIFF; + m_pOutRIFF = NULL; +} + +bool CSoundCombiner::InternalCombineSoundFiles( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ) +{ + Q_strncpy( m_szOutFile, outfile, sizeof( m_szOutFile ) ); + if ( info.Count() <= 0 ) + { + Warning( "CSoundCombiner::InternalCombineSoundFiles: work item count is zero\n" ); + return false; + } + + if ( !VerifyFilesExist( filesystem, info ) ) + { + return false; + } + + if ( !CreateWorkList( filesystem, info ) ) + { + return false; + } + + PerformSplicingOnWorkItems( filesystem ); + + return true; +} + +bool CSoundCombiner::CombineSoundFiles( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ) +{ + bool bret = InternalCombineSoundFiles( filesystem, outfile, info ); + CleanupWork(); + return bret; +} + +unsigned int CSoundCombiner::ComputeChecksum() +{ + CRC32_t crc; + CRC32_Init( &crc ); + + int c = m_Work.Count(); + for ( int i = 0; i < c; ++i ) + { + CombinerWork *curitem = m_Work[ i ]; + unsigned int chk = curitem->sentence.ComputeDataCheckSum(); + + // Msg( " %i -> sentence %u, startoffset %f fn %s\n", + // i, chk, curitem->entry->startoffset, curitem->entry->wavefile ); + + CRC32_ProcessBuffer( &crc, &chk, sizeof( unsigned long ) ); + CRC32_ProcessBuffer( &crc, &curitem->entry->startoffset, sizeof( float ) ); + CRC32_ProcessBuffer( &crc, curitem->entry->wavefile, Q_strlen( curitem->entry->wavefile ) ); + } + + CRC32_Final( &crc ); + return ( unsigned int )crc; +} + +unsigned int CSoundCombiner::CheckSumWork( IFileSystem *filesystem, CUtlVector< CombinerEntry >& info ) +{ + if ( info.Count() <= 0 ) + { + Warning( "CSoundCombiner::CheckSumWork: work item count is zero\n" ); + return 0; + } + + if ( !VerifyFilesExist( filesystem, info ) ) + { + return 0; + } + + if ( !CreateWorkList( filesystem, info ) ) + { + return 0; + } + + // Checkum work items + unsigned int checksum = ComputeChecksum(); + + return checksum; +} + +bool CSoundCombiner::IsCombinedFileChecksumValid( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info ) +{ + unsigned int computedChecksum = CheckSumWork( filesystem, info ); + + char fullpath[ MAX_PATH ]; + Q_strncpy( fullpath, outfile, sizeof( fullpath ) ); + filesystem->GetLocalPath( outfile, fullpath, sizeof( fullpath ) ); + + CSentence sentence; + + bool valid = false; + + if ( LoadSentenceFromWavFile( fullpath, sentence ) ) + { + unsigned int diskFileEmbeddedChecksum = sentence.GetDataCheckSum(); + + valid = computedChecksum == diskFileEmbeddedChecksum; + + if ( !valid ) + { + Warning( " checksum computed %u, disk %u\n", + computedChecksum, diskFileEmbeddedChecksum ); + } + } + else + { + Warning( "CSoundCombiner::IsCombinedFileChecksumValid: Unabled to load %s\n", fullpath ); + } + + CleanupWork(); + return valid; +} + +bool CSoundCombiner::VerifyFilesExist( IFileSystem *filesystem, CUtlVector< CombinerEntry >& info ) +{ + int c = info.Count(); + for ( int i = 0 ; i < c; ++i ) + { + CombinerEntry& entry = info[ i ]; + if ( !filesystem->FileExists( entry.wavefile ) ) + { + Warning( "CSoundCombiner::VerifyFilesExist: missing file %s\n", entry.wavefile ); + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Implements the RIFF i/o interface on stdio +//----------------------------------------------------------------------------- +class StdIOReadBinary : public IFileReadBinary +{ +public: + int open( const char *pFileName ) + { + return (int)filesystem->Open( pFileName, "rb" ); + } + + int read( void *pOutput, int size, int file ) + { + if ( !file ) + return 0; + + return filesystem->Read( pOutput, size, (FileHandle_t)file ); + } + + void seek( int file, int pos ) + { + if ( !file ) + return; + + filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); + } + + unsigned int tell( int file ) + { + if ( !file ) + return 0; + + return filesystem->Tell( (FileHandle_t)file ); + } + + unsigned int size( int file ) + { + if ( !file ) + return 0; + + return filesystem->Size( (FileHandle_t)file ); + } + + void close( int file ) + { + if ( !file ) + return; + + filesystem->Close( (FileHandle_t)file ); + } +}; + +class StdIOWriteBinary : public IFileWriteBinary +{ +public: + int create( const char *pFileName ) + { + return (int)filesystem->Open( pFileName, "wb" ); + } + + int write( void *pData, int size, int file ) + { + return filesystem->Write( pData, size, (FileHandle_t)file ); + } + + void close( int file ) + { + filesystem->Close( (FileHandle_t)file ); + } + + void seek( int file, int pos ) + { + filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); + } + + unsigned int tell( int file ) + { + return filesystem->Tell( (FileHandle_t)file ); + } +}; + +static StdIOReadBinary io_in; +static StdIOWriteBinary io_out; + +#define RIFF_WAVE MAKEID('W','A','V','E') +#define WAVE_FMT MAKEID('f','m','t',' ') +#define WAVE_DATA MAKEID('d','a','t','a') +#define WAVE_FACT MAKEID('f','a','c','t') +#define WAVE_CUE MAKEID('c','u','e',' ') + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &walk - +//----------------------------------------------------------------------------- +void CSoundCombiner::ParseSentence( CSentence& sentence, IterateRIFF &walk ) +{ + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + + buf.EnsureCapacity( walk.ChunkSize() ); + walk.ChunkRead( buf.Base() ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, walk.ChunkSize() ); + + sentence.InitFromDataChunk( buf.Base(), buf.TellPut() ); +} + +bool CSoundCombiner::LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io ) +{ + sentence.Reset(); + + InFileRIFF riff( wavfile, io ); + + // UNDONE: Don't use printf to handle errors + if ( riff.RIFFName() != RIFF_WAVE ) + { + return false; + } + + // set up the iterator for the whole file (root RIFF is a chunk) + IterateRIFF walk( riff, riff.RIFFSize() ); + + // This chunk must be first as it contains the wave's format + // break out when we've parsed it + bool found = false; + while ( walk.ChunkAvailable() && !found ) + { + switch( walk.ChunkName() ) + { + case WAVE_VALVEDATA: + { + found = true; + CSoundCombiner::ParseSentence( sentence, walk ); + } + break; + } + walk.ChunkNext(); + } + + return true; +} + +bool CSoundCombiner::LoadSentenceFromWavFile( char const *wavfile, CSentence& sentence ) +{ + return CSoundCombiner::LoadSentenceFromWavFileUsingIO( wavfile, sentence, io_in ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : store - +//----------------------------------------------------------------------------- +void CSoundCombiner::StoreValveDataChunk( CSentence& sentence ) +{ + // Buffer and dump data + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + + sentence.SaveToBuffer( buf ); + + // Copy into store + m_pOutIterator->ChunkWriteData( buf.Base(), buf.TellPut() ); +} + +/* +bool CSoundCombiner::SaveSentenceToWavFile( char const *wavfile, CSentence& sentence ) +{ + char tempfile[ 512 ]; + + Q_StripExtension( wavfile, tempfile, sizeof( tempfile ) ); + Q_DefaultExtension( tempfile, ".tmp", sizeof( tempfile ) ); + + if ( filesystem->FileExists( tempfile, NULL ) ) + { + filesystem->RemoveFile( tempfile, NULL ); + } + + if ( !filesystem->IsFileWritable( wavfile ) ) + { + Msg( "%s is not writable, can't save sentence data to file\n", wavfile ); + return false; + } + + // Rename original wavfile to temp + filesystem->RenameFile( wavfile, tempfile, NULL ); + + // NOTE: Put this in it's own scope so that the destructor for outfileRFF actually closes the file!!!! + { + // Read from Temp + InFileRIFF riff( tempfile, io_in ); + Assert( riff.RIFFName() == RIFF_WAVE ); + + // set up the iterator for the whole file (root RIFF is a chunk) + IterateRIFF walk( riff, riff.RIFFSize() ); + + // And put data back into original wavfile by name + OutFileRIFF riffout( wavfile, io_out ); + + IterateOutputRIFF store( riffout ); + + bool wordtrackwritten = false; + + // Walk input chunks and copy to output + while ( walk.ChunkAvailable() ) + { + m_pOutIterator->ChunkStart( walk.ChunkName() ); + + switch ( walk.ChunkName() ) + { + case WAVE_VALVEDATA: + { + // Overwrite data + CSoundCombiner::StoreValveDataChunk( sentence ); + wordtrackwritten = true; + } + break; + default: + m_pOutIterator->CopyChunkData( walk ); + break; + } + + m_pOutIterator->ChunkFinish(); + + walk.ChunkNext(); + } + + // If we didn't write it above, write it now + if ( !wordtrackwritten ) + { + m_pOutIterator->ChunkStart( WAVE_VALVEDATA ); + CSoundCombiner::StoreValveDataChunk( sentence ); + m_pOutIterator->ChunkFinish(); + } + } + + // Remove temp file + filesystem->RemoveFile( tempfile, NULL ); + + return true; +} +*/ + +typedef struct channel_s +{ + int leftvol; + int rightvol; + int rleftvol; + int rrightvol; + float pitch; +} channel_t; + +bool CSoundCombiner::InitSplicer( IFileSystem *filesystem, int samplerate, int numchannels, int bitspersample ) +{ + m_nSampleRate = samplerate; + m_nNumChannels = numchannels; + m_nBitsPerSample = bitspersample; + m_nBytesPerSample = bitspersample >> 3; + + m_pWaveOutput = ( CAudioWaveOutput * )sound->GetAudioOutput(); + if ( !m_pWaveOutput ) + { + Warning( "CSoundCombiner::InitSplicer m_pWaveOutput == NULL\n" ); + return false; + } + + // Make sure the directory exists + char basepath[ 512 ]; + Q_ExtractFilePath( m_szOutFile, basepath, sizeof( basepath ) ); + filesystem->CreateDirHierarchy( basepath, "GAME" ); + + // Create out put file + m_pOutRIFF = new OutFileRIFF( m_szOutFile, io_out ); + if ( !m_pOutRIFF ) + { + Warning( "CSoundCombiner::InitSplicer m_pOutRIFF == NULL\n" ); + return false; + } + + // Create output iterator + m_pOutIterator = new IterateOutputRIFF( *m_pOutRIFF ); + if ( !m_pOutIterator ) + { + Warning( "CSoundCombiner::InitSplicer m_pOutIterator == NULL\n" ); + return false; + } + + WAVEFORMATEX format; + format.cbSize = sizeof( format ); + + format.wFormatTag = WAVE_FORMAT_PCM; + format.nAvgBytesPerSec = m_nSampleRate * m_nNumChannels * m_nBytesPerSample; + format.nChannels = m_nNumChannels; + format.wBitsPerSample = m_nBitsPerSample; + format.nSamplesPerSec = m_nSampleRate; + format.nBlockAlign = 1; + + // Always store the format chunk first + m_pOutIterator->ChunkWrite( WAVE_FMT, &format, sizeof( format ) ); + + return true; +} + +bool CSoundCombiner::LoadSpliceAudioSources() +{ + int c = m_Work.Count(); + for ( int i = 0; i < c; ++i ) + { + CombinerWork *item = m_Work[ i ]; + + CAudioSource *wave = sound->LoadSound( item->entry->wavefile ); + if ( !wave ) + { + Warning( "CSoundCombiner::LoadSpliceAudioSources LoadSound failed '%s'\n", item->entry->wavefile ); + return false; + } + + CAudioMixer *pMixer = wave->CreateMixer(); + if ( !pMixer ) + { + Warning( "CSoundCombiner::LoadSpliceAudioSources CreateMixer failed '%s'\n", item->entry->wavefile ); + return false; + } + + item->wave = wave; + item->mixer = pMixer; + item->duration = wave->GetRunningLength(); + } + + return true; +} + +bool CSoundCombiner::AppendSilence( int ¤tsample, float duration ) +{ + int numSamples = duration * m_nSampleRate; + +#define MOTION_RANGE 150 +#define MOTION_MAXSTEP 20 + int currentValue = 32767; + int maxValue = currentValue + ( MOTION_RANGE / 2 ); + int minValue = currentValue - ( MOTION_RANGE / 2 ); + + short samples[ 2 ]; + + while ( --numSamples >= 0 ) + { + currentValue += random->RandomInt( -MOTION_MAXSTEP, MOTION_MAXSTEP ); + currentValue = vmin( maxValue, currentValue ); + currentValue = vmax( minValue, currentValue ); + + // Downsample to 0 65556 range + short s = (float)currentValue / 32768.0f; + + samples[ 0 ] = s; + samples[ 1 ] = s; + + AppendStereo16Data( samples ); + } + + return true; +} + +bool CSoundCombiner::AppendStereo16Data( short samples[ 2 ] ) +{ +// Convert from 16 bit, 2 channels to output size + if ( m_nNumChannels == 1 ) + { + if ( m_nBytesPerSample == 1 ) + { + // Convert to 8 bit mono + // left + right (2 channels ) * 16 bits + float s1 = (float)( samples[ 0 ] >> 8 ); + float s2 = (float)( samples[ 1 ] >> 8 ); + + float avg = ( s1 + s2 ) * 0.5f; + avg = clamp( avg, -127.0f, 127.0f ); + byte chopped = (byte)( avg+ 127 ); + + m_pOutIterator->ChunkWriteData( &chopped, sizeof( byte ) ); + } + else if ( m_nBytesPerSample == 2 ) + { + // Conver to 16 bit mono + float s1 = (float)( samples[ 0 ] ); + float s2 = (float)( samples[ 1 ] ); + + float avg = ( s1 + s2 ) * 0.5f; + unsigned short chopped = (unsigned short)( avg ); + + m_pOutIterator->ChunkWriteData( &chopped, sizeof( unsigned short ) ); + } + else + { + Assert( 0 ); + return false; + } + } + else if ( m_nNumChannels == 2 ) + { + if ( m_nBytesPerSample == 1 ) + { + // Convert to 8 bit stereo + // left + right (2 channels ) * 16 bits + float s1 = (float)( samples[ 0 ] >> 8 ); + float s2 = (float)( samples[ 1 ] >> 8 ); + + s1 = clamp( s1, -127.0f, 127.0f ); + s2 = clamp( s2, -127.0f, 127.0f ); + + byte chopped1 = (byte)( s1 + 127.0f ); + byte chopped2 = (byte)( s2 + 127.0f ); + + m_pOutIterator->ChunkWriteData( &chopped1, sizeof( byte ) ); + m_pOutIterator->ChunkWriteData( &chopped2, sizeof( byte ) ); + } + else if ( m_nBytesPerSample == 2 ) + { + // Leave as 16 bit stereo + // Directly store values + m_pOutIterator->ChunkWriteData( &samples[ 0 ], sizeof( unsigned short ) ); + m_pOutIterator->ChunkWriteData( &samples[ 1 ], sizeof( unsigned short ) ); + } + else + { + Assert( 0 ); + return false; + } + } + else + { + Assert( 0 ); + return false; + } + + return true; +} + +bool CSoundCombiner::AppendWaveData( int& currentsample, CAudioSource *wave, CAudioMixer *mixer ) +{ + // need a bit of space + short samples[ 2 ]; + channel_t channel; + memset( &channel, 0, sizeof( channel ) ); + channel.leftvol = 255; + channel.rightvol = 255; + channel.pitch = 1.0; + + while ( 1 ) + { + m_pWaveOutput->m_audioDevice.MixBegin(); + + if ( !mixer->MixDataToDevice( &m_pWaveOutput->m_audioDevice, &channel, currentsample, 1, wave->SampleRate(), true ) ) + break; + + m_pWaveOutput->m_audioDevice.TransferBufferStereo16( samples, 1 ); + + currentsample = mixer->GetSamplePosition(); + + AppendStereo16Data( samples ); + } + + return true; +} + +int CSoundCombiner::ComputeBestNumChannels() +{ + // We prefer mono output unless one of the source wav files is stereo, then we'll do stereo output + int c = m_Work.Count(); + for ( int i = 0; i < c; ++i ) + { + CombinerWork *curitem = m_Work[ i ]; + + if ( curitem->wave->GetNumChannels() == 2 ) + { + return 2; + } + } + return 1; +} + +bool CSoundCombiner::PerformSplicingOnWorkItems( IFileSystem *filesystem ) +{ + if ( !LoadSpliceAudioSources() ) + { + return false; + } + + int bestNumChannels = ComputeBestNumChannels(); + int bitsPerChannel = WAVEOUTPUT_BITSPERCHANNEL; + + // Pull in data and write it out + if ( !InitSplicer( filesystem, WAVEOUTPUT_FREQUENCY, bestNumChannels, bitsPerChannel ) ) + { + return false; + } + + m_pOutIterator->ChunkStart( WAVE_DATA ); + + float timeoffset = 0.0f; + + m_Combined.Reset(); + m_Combined.SetText( "" ); + + int c = m_Work.Count(); + for ( int i = 0; i < c; ++i ) + { + int currentsample = 0; + + CombinerWork *curitem = m_Work[ i ]; + CombinerWork *nextitem = NULL; + if ( i != c - 1 ) + { + nextitem = m_Work[ i + 1 ]; + } + + float duration = curitem->duration; + + AppendWaveData( currentsample, curitem->wave, curitem->mixer ); + + AddSentenceToCombined( timeoffset, curitem->sentence ); + + timeoffset += duration; + + if ( nextitem != NULL ) + { + float nextstart = nextitem->entry->startoffset; + float silence_time = nextstart - timeoffset; + + AppendSilence( currentsample, silence_time ); + + timeoffset += silence_time; + } + } + + m_pOutIterator->ChunkFinish(); + + // Checksum the work items + unsigned int checksum = ComputeChecksum(); + + // Make sure the checksum is embedded in the data file + m_Combined.SetDataCheckSum( checksum ); + + // Msg( " checksum computed %u\n", checksum ); + + m_pOutIterator->ChunkStart( WAVE_VALVEDATA ); + StoreValveDataChunk( m_Combined ); + m_pOutIterator->ChunkFinish(); + + + return true; +} + +void CSoundCombiner::AddSentenceToCombined( float offset, CSentence& sentence ) +{ + m_Combined.Append( offset, sentence ); +} diff --git a/public/soundflags.h b/public/soundflags.h new file mode 100644 index 0000000..71ae119 --- /dev/null +++ b/public/soundflags.h @@ -0,0 +1,161 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SOUNDFLAGS_H +#define SOUNDFLAGS_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// channels +//----------------------------------------------------------------------------- +enum +{ + CHAN_REPLACE = -1, + CHAN_AUTO = 0, + CHAN_WEAPON = 1, + CHAN_VOICE = 2, + CHAN_ITEM = 3, + CHAN_BODY = 4, + CHAN_STREAM = 5, // allocate stream channel from the static or dynamic area + CHAN_STATIC = 6, // allocate channel from the static area + CHAN_VOICE2 = 7, + CHAN_VOICE_BASE = 8, // allocate channel for network voice data + CHAN_USER_BASE = (CHAN_VOICE_BASE+128) // Anything >= this number is allocated to game code. +}; + +//----------------------------------------------------------------------------- +// common volume values +//----------------------------------------------------------------------------- +#define VOL_NORM 1.0f + + +//----------------------------------------------------------------------------- +// common attenuation values +//----------------------------------------------------------------------------- +#define ATTN_NONE 0.0f +#define ATTN_NORM 0.8f +#define ATTN_IDLE 2.0f +#define ATTN_STATIC 1.25f +#define ATTN_RICOCHET 1.5f + +// HL2 world is 8x bigger now! We want to hear gunfire from farther. +// Don't change this without consulting Kelly or Wedge (sjb). +#define ATTN_GUNFIRE 0.27f + +enum soundlevel_t +{ + SNDLVL_NONE = 0, + + SNDLVL_20dB = 20, // rustling leaves + SNDLVL_25dB = 25, // whispering + SNDLVL_30dB = 30, // library + SNDLVL_35dB = 35, + SNDLVL_40dB = 40, + SNDLVL_45dB = 45, // refrigerator + + SNDLVL_50dB = 50, // 3.9 // average home + SNDLVL_55dB = 55, // 3.0 + + SNDLVL_IDLE = 60, // 2.0 + SNDLVL_60dB = 60, // 2.0 // normal conversation, clothes dryer + + SNDLVL_65dB = 65, // 1.5 // washing machine, dishwasher + SNDLVL_STATIC = 66, // 1.25 + + SNDLVL_70dB = 70, // 1.0 // car, vacuum cleaner, mixer, electric sewing machine + + SNDLVL_NORM = 75, + SNDLVL_75dB = 75, // 0.8 // busy traffic + + SNDLVL_80dB = 80, // 0.7 // mini-bike, alarm clock, noisy restaurant, office tabulator, outboard motor, passing snowmobile + SNDLVL_TALKING = 80, // 0.7 + SNDLVL_85dB = 85, // 0.6 // average factory, electric shaver + SNDLVL_90dB = 90, // 0.5 // screaming child, passing motorcycle, convertible ride on frw + SNDLVL_95dB = 95, + SNDLVL_100dB = 100, // 0.4 // subway train, diesel truck, woodworking shop, pneumatic drill, boiler shop, jackhammer + SNDLVL_105dB = 105, // helicopter, power mower + SNDLVL_110dB = 110, // snowmobile drvrs seat, inboard motorboat, sandblasting + SNDLVL_120dB = 120, // auto horn, propeller aircraft + SNDLVL_130dB = 130, // air raid siren + + SNDLVL_GUNFIRE = 140, // 0.27 // THRESHOLD OF PAIN, gunshot, jet engine + SNDLVL_140dB = 140, // 0.2 + + SNDLVL_150dB = 150, // 0.2 + + SNDLVL_180dB = 180, // rocket launching + + // NOTE: Valid soundlevel_t values are 0-255. + // 256-511 are reserved for sounds using goldsrc compatibility attenuation. +}; + +#define MAX_SNDLVL_BITS 9 // Used to encode 0-255 for regular soundlevel_t's and 256-511 for goldsrc-compatible ones. +#define MIN_SNDLVL_VALUE 0 +#define MAX_SNDLVL_VALUE ((1< 50) ? (20.0f / (float)(a - 50)) : 4.0 ) + +// This is a limit due to network encoding. +// It encodes attenuation * 64 in 8 bits, so the maximum is (255 / 64) +#define MAX_ATTENUATION 3.98f + +//----------------------------------------------------------------------------- +// Flags to be or-ed together for the iFlags field +//----------------------------------------------------------------------------- +enum SoundFlags_t +{ + SND_NOFLAGS = 0, // to keep the compiler happy + SND_CHANGE_VOL = (1<<0), // change sound vol + SND_CHANGE_PITCH = (1<<1), // change sound pitch + SND_STOP = (1<<2), // stop the sound + SND_SPAWNING = (1<<3), // we're spawning, used in some cases for ambients + // not sent over net, only a param between dll and server. + SND_DELAY = (1<<4), // sound has an initial delay + SND_STOP_LOOPING = (1<<5), // stop all looping sounds on the entity. + SND_SPEAKER = (1<<6), // being played again by a microphone through a speaker + + SND_SHOULDPAUSE = (1<<7), // this sound should be paused if the game is paused + SND_IGNORE_PHONEMES = (1<<8), + SND_IGNORE_NAME = (1<<9), // used to change all sounds emitted by an entity, regardless of scriptname + + SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL = (1<<10), +}; + +#define SND_FLAG_BITS_ENCODE 11 + +#define MAX_SOUND_INDEX_BITS 14 +#define MAX_SOUNDS (1<name ) \ + buffer.WriteOneBit(0); \ + else \ + { \ + buffer.WriteOneBit(1); \ + buffer.WriteUBitLong( name, length ); \ + } + +#define READ_DELTA_UINT( name, length ) \ + if ( buffer.ReadOneBit() != 0 ) \ + { name = buffer.ReadUBitLong( length ); }\ + else { name = delta->name; } + +#define WRITE_DELTA_SINT( name, length ) \ + if ( name == delta->name ) \ + buffer.WriteOneBit(0); \ + else \ + { \ + buffer.WriteOneBit(1); \ + buffer.WriteSBitLong( name, length ); \ + } + +#define WRITE_DELTA_SINT_SCALE( name, scale, length ) \ + if ( name == delta->name ) \ + buffer.WriteOneBit(0); \ + else \ + { \ + buffer.WriteOneBit(1); \ + buffer.WriteSBitLong( name / scale, length ); \ + } + +#define READ_DELTA_SINT( name, length ) \ + if ( buffer.ReadOneBit() != 0 ) \ + { name = buffer.ReadSBitLong( length ); } \ + else { name = delta->name; } + +#define READ_DELTA_SINT_SCALE( name, scale, length ) \ + if ( buffer.ReadOneBit() != 0 ) \ + { name = scale * buffer.ReadSBitLong( length ); } \ + else { name = delta->name; } + +#define SOUND_SEQNUMBER_BITS 10 +#define SOUND_SEQNUMBER_MASK ( (1<nEntityIndex ) + { + buffer.WriteOneBit( 0 ); + } + else + { + buffer.WriteOneBit( 1 ); + + if ( nEntityIndex <= 31) + { + buffer.WriteOneBit( 1 ); + buffer.WriteUBitLong( nEntityIndex, 5 ); + } + else + { + buffer.WriteOneBit( 0 ); + buffer.WriteUBitLong( nEntityIndex, MAX_EDICT_BITS ); + } + } + + WRITE_DELTA_UINT( nSoundNum, MAX_SOUND_INDEX_BITS ); + + WRITE_DELTA_UINT( nFlags, SND_FLAG_BITS_ENCODE ); + + WRITE_DELTA_UINT( nChannel, 3 ); + + buffer.WriteOneBit( bIsAmbient?1:0 ); + buffer.WriteOneBit( bIsSentence?1:0 ); // NOTE: SND_STOP behavior is different depending on this flag + + if ( nFlags != SND_STOP ) + { + if ( nSequenceNumber == delta->nSequenceNumber ) + { + // didn't change, most often case + buffer.WriteOneBit( 1 ); + } + else if ( nSequenceNumber == (delta->nSequenceNumber+1) ) + { + // increased by one + buffer.WriteOneBit( 0 ); + buffer.WriteOneBit( 1 ); + } + else + { + // send full seqnr + buffer.WriteUBitLong( 0, 2 ); // 2 zero bits + buffer.WriteUBitLong( nSequenceNumber, SOUND_SEQNUMBER_BITS ); + } + + if ( fVolume == delta->fVolume ) + { + buffer.WriteOneBit( 0 ); + } + else + { + buffer.WriteOneBit( 1 ); + buffer.WriteUBitLong( (unsigned int)(fVolume*127.0f), 7 ); + } + + WRITE_DELTA_UINT( Soundlevel, MAX_SNDLVL_BITS ); + + WRITE_DELTA_UINT( nPitch, 8 ); + + WRITE_DELTA_UINT( nSpecialDSP, 8 ); + + if ( fDelay == delta->fDelay ) + { + buffer.WriteOneBit( 0 ); + } + else + { + buffer.WriteOneBit( 1 ); + + // skipahead works in 10 ms increments + // bias results so that we only incur the precision loss on relatively large skipaheads + fDelay += SOUND_DELAY_OFFSET; + + // Convert to msecs + int iDelay = fDelay * 1000.0f; + + iDelay = clamp( iDelay, (int)(-10 * MAX_SOUND_DELAY_MSEC), (int)(MAX_SOUND_DELAY_MSEC) ); + + if ( iDelay < 0 ) + { + iDelay /=10; + } + + buffer.WriteSBitLong( iDelay , MAX_SOUND_DELAY_MSEC_ENCODE_BITS ); + } + + // don't transmit sounds with high precision + WRITE_DELTA_SINT_SCALE( vOrigin.x, 8.0f, COORD_INTEGER_BITS - 2 ); + WRITE_DELTA_SINT_SCALE( vOrigin.y, 8.0f, COORD_INTEGER_BITS - 2 ); + WRITE_DELTA_SINT_SCALE( vOrigin.z, 8.0f, COORD_INTEGER_BITS - 2 ); + + WRITE_DELTA_SINT( nSpeakerEntity, MAX_EDICT_BITS + 1 ); + } + else + { + ClearStopFields(); + } + }; + + void ReadDelta( SoundInfo_t *delta, bf_read &buffer, int nProtoVersion ) + { + if ( !buffer.ReadOneBit() ) + { + nEntityIndex = delta->nEntityIndex; + } + else + { + if ( buffer.ReadOneBit() ) + { + nEntityIndex = buffer.ReadUBitLong( 5 ); + } + else + { + nEntityIndex = buffer.ReadUBitLong( MAX_EDICT_BITS ); + } + } + + if ( nProtoVersion > 22 ) + { + READ_DELTA_UINT( nSoundNum, MAX_SOUND_INDEX_BITS ); + } + else + { + READ_DELTA_UINT( nSoundNum, 13 ); + } + + if ( nProtoVersion > 18 ) + { + READ_DELTA_UINT( nFlags, SND_FLAG_BITS_ENCODE ); + } + else + { + // There was 9 flag bits for version 18 and below (prior to Halloween 2011) + READ_DELTA_UINT( nFlags, 9 ); + } + + READ_DELTA_UINT( nChannel, 3 ); + + bIsAmbient = buffer.ReadOneBit() != 0; + bIsSentence = buffer.ReadOneBit() != 0; // NOTE: SND_STOP behavior is different depending on this flag + + if ( nFlags != SND_STOP ) + { + if ( buffer.ReadOneBit() != 0 ) + { + nSequenceNumber = delta->nSequenceNumber; + } + else if ( buffer.ReadOneBit() != 0 ) + { + nSequenceNumber = delta->nSequenceNumber + 1; + } + else + { + nSequenceNumber = buffer.ReadUBitLong( SOUND_SEQNUMBER_BITS ); + } + + if ( buffer.ReadOneBit() != 0 ) + { + fVolume = (float)buffer.ReadUBitLong( 7 )/127.0f; + } + else + { + fVolume = delta->fVolume; + } + + if ( buffer.ReadOneBit() != 0 ) + { + Soundlevel = (soundlevel_t)buffer.ReadUBitLong( MAX_SNDLVL_BITS ); + } + else + { + Soundlevel = delta->Soundlevel; + } + + READ_DELTA_UINT( nPitch, 8 ); + + if ( nProtoVersion > 21 ) + { + // These bit weren't written in version 19 and below + READ_DELTA_UINT( nSpecialDSP, 8 ); + } + + if ( buffer.ReadOneBit() != 0 ) + { + // Up to 4096 msec delay + fDelay = (float)buffer.ReadSBitLong( MAX_SOUND_DELAY_MSEC_ENCODE_BITS ) / 1000.0f; ; + + if ( fDelay < 0 ) + { + fDelay *= 10.0f; + } + // bias results so that we only incur the precision loss on relatively large skipaheads + fDelay -= SOUND_DELAY_OFFSET; + } + else + { + fDelay = delta->fDelay; + } + + READ_DELTA_SINT_SCALE( vOrigin.x, 8.0f, COORD_INTEGER_BITS - 2 ); + READ_DELTA_SINT_SCALE( vOrigin.y, 8.0f, COORD_INTEGER_BITS - 2 ); + READ_DELTA_SINT_SCALE( vOrigin.z, 8.0f, COORD_INTEGER_BITS - 2 ); + + READ_DELTA_SINT( nSpeakerEntity, MAX_EDICT_BITS + 1 ); + } + else + { + ClearStopFields(); + } + } +}; + +struct SpatializationInfo_t +{ + typedef enum + { + SI_INCREATION = 0, + SI_INSPATIALIZATION + } SPATIALIZATIONTYPE; + + // Inputs + SPATIALIZATIONTYPE type; + // Info about the sound, channel, origin, direction, etc. + SoundInfo_t info; + + // Requested Outputs ( NULL == not requested ) + Vector *pOrigin; + QAngle *pAngles; + float *pflRadius; +}; +#pragma pack() + +#endif // SOUNDINFO_H diff --git a/public/soundsystem/isoundsystem.h b/public/soundsystem/isoundsystem.h new file mode 100644 index 0000000..8a37090 --- /dev/null +++ b/public/soundsystem/isoundsystem.h @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef ISOUNDSYSTEM_H +#define ISOUNDSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/iappsystem.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IAudioDevice; +class CAudioSource; +class CAudioMixer; + + +//----------------------------------------------------------------------------- +// Sound handle +//----------------------------------------------------------------------------- +typedef unsigned short AudioSourceHandle_t; +enum +{ + AUDIOSOURCEHANDLE_INVALID = (AudioSourceHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Flags for FindAudioSource +//----------------------------------------------------------------------------- +enum FindAudioSourceFlags_t +{ + FINDAUDIOSOURCE_NODELAY = 0x1, + FINDAUDIOSOURCE_PREFETCH = 0x2, + FINDAUDIOSOURCE_PLAYONCE = 0x4, +}; + + +//----------------------------------------------------------------------------- +// Purpose: DLL interface for low-level sound utilities +//----------------------------------------------------------------------------- +#define SOUNDSYSTEM_INTERFACE_VERSION "SoundSystem001" + +abstract_class ISoundSystem : public IAppSystem +{ +public: + virtual void Update( float time ) = 0; + virtual void Flush( void ) = 0; + + virtual CAudioSource *FindOrAddSound( const char *filename ) = 0; + virtual CAudioSource *LoadSound( const char *wavfile ) = 0; + + virtual void PlaySound( CAudioSource *source, float volume, CAudioMixer **ppMixer ) = 0; + + virtual bool IsSoundPlaying( CAudioMixer *pMixer ) = 0; + virtual CAudioMixer *FindMixer( CAudioSource *source ) = 0; + + virtual void StopAll( void ) = 0; + virtual void StopSound( CAudioMixer *mixer ) = 0; +}; + + + +#endif // ISOUNDSYSTEM_H diff --git a/public/soundsystem/snd_audio_source.h b/public/soundsystem/snd_audio_source.h new file mode 100644 index 0000000..11e4621 --- /dev/null +++ b/public/soundsystem/snd_audio_source.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef SND_AUDIO_SOURCE_H +#define SND_AUDIO_SOURCE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CAudioSource; +class IAudioDevice; +struct channel_t; + + +//----------------------------------------------------------------------------- +// Purpose: This is an instance of an audio source. +// Mixers are attached to channels and reference an audio source. +// Mixers are specific to the sample format and source format. +// Mixers are never re-used, so they can track instance data like +// sample position, fractional sample, stream cache, faders, etc. +//----------------------------------------------------------------------------- +abstract_class CAudioMixer +{ +public: + virtual ~CAudioMixer( void ) {} + + // UNDONE: time compress + virtual bool MixDataToDevice( IAudioDevice *pDevice, channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward = true ) = 0; + virtual void IncrementSamples( channel_t *pChannel, int startSample, int sampleCount,int outputRate, bool forward = true ) = 0; + virtual bool SkipSamples( IAudioDevice *pDevice, channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward = true ) = 0; + + virtual CAudioSource *GetSource( void ) = 0; + + virtual int GetSamplePosition( void ) = 0; + virtual int GetScubPosition( void ) = 0; + + virtual bool SetSamplePosition( int position, bool scrubbing = false ) = 0; + virtual void SetLoopPosition( int position ) = 0; + virtual int GetStartPosition( void ) = 0; + + virtual bool GetActive( void ) = 0; + virtual void SetActive( bool active ) = 0; + + virtual void SetModelIndex( int index ) = 0; + virtual int GetModelIndex( void ) const = 0; + + virtual void SetDirection( bool forward ) = 0; + virtual bool GetDirection( void ) const = 0; + + virtual void SetAutoDelete( bool autodelete ) = 0; + virtual bool GetAutoDelete( void ) const = 0; + + virtual void SetVolume( float volume ) = 0; + virtual channel_t *GetChannel() = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: A source is an abstraction for a stream, cached file, or procedural +// source of audio. +//----------------------------------------------------------------------------- +class CSentence; + +abstract_class CAudioSource +{ +public: + CAudioSource( void ); + virtual ~CAudioSource( void ); + + // Create an instance (mixer) of this audio source + virtual CAudioMixer *CreateMixer( void ) = 0; + virtual int GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward = true ) = 0; + virtual int SampleRate( void ) = 0; + virtual int SampleSize( void ) = 0; + virtual int SampleCount( void ) = 0; + virtual float TrueSampleSize( void ) = 0; + virtual bool IsLooped( void ) = 0; + virtual bool IsStreaming( void ) = 0; + virtual float GetRunningLength( void ) = 0; + virtual int GetNumChannels() = 0; + + virtual CSentence *GetSentence( void ) { return NULL; }; + +}; + + +extern CAudioSource *AudioSource_Create( const char *pName ); + +#endif // SND_AUDIO_SOURCE_H diff --git a/public/soundsystem/snd_device.h b/public/soundsystem/snd_device.h new file mode 100644 index 0000000..fa85589 --- /dev/null +++ b/public/soundsystem/snd_device.h @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef SND_DEVICE_H +#define SND_DEVICE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +//----------------------------------------------------------------------------- +// 4.28 fixed point stuff for real-time resampling +//----------------------------------------------------------------------------- +#define FIX_BITS 28 +#define FIX_SCALE (1 << FIX_BITS) +#define FIX_MASK ((1 << FIX_BITS)-1) +#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE)) +#define FIX(a) (((int)(a)) << FIX_BITS) +#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS) +#define FIX_FRACTION(a,b) (FIX(a)/(b)) +#define FIX_FRACPART(a) ((a) & FIX_MASK) + +typedef unsigned int fixedint; + + +//----------------------------------------------------------------------------- +// sound rate defines +//----------------------------------------------------------------------------- +#define SOUND_DMA_SPEED 44100 // hardware playback rate +#define SOUND_11k 11025 // 11khz sample rate +#define SOUND_22k 22050 // 22khz sample rate +#define SOUND_44k 44100 // 44khz sample rate +#define SOUND_ALL_RATES 1 // mix all sample rates + + +//----------------------------------------------------------------------------- +// Information about the channel +//----------------------------------------------------------------------------- +struct channel_t +{ + int leftvol; + int rightvol; + float pitch; +}; + + +//----------------------------------------------------------------------------- +// The audio device is responsible for mixing +//----------------------------------------------------------------------------- +abstract_class IAudioDevice +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IAudioDevice() {} + + // This initializes the sound hardware. true on success, false on failure + virtual bool Init( void ) = 0; + + // This releases all sound hardware + virtual void Shutdown( void ) = 0; + + // device parameters + virtual const char *DeviceName( void ) const = 0; + virtual int DeviceChannels( void ) const = 0; // 1 = mono, 2 = stereo + virtual int DeviceSampleBits( void ) const = 0; // bits per sample (8 or 16) + virtual int DeviceSampleBytes( void ) const = 0; // above / 8 + virtual int DeviceSampleRate( void ) const = 0; // Actual DMA speed + virtual int DeviceSampleCount( void ) const = 0; // Total samples in buffer + + // Called each time a new paint buffer is mixed (may be multiple times per frame) + virtual void MixBegin( void ) = 0; + + // Main mixing routines + virtual void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0; + virtual void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0; + virtual void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0; + virtual void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0; + + // Size of the paint buffer in samples + virtual int PaintBufferSampleCount( void ) const = 0; + + // Adds a mixer to be mixed + virtual void AddSource( CAudioMixer *pSource ) = 0; + + // Stops all sounds + virtual void StopSounds( void ) = 0; + + // Updates sound mixing + virtual void Update( float time ) = 0; + + // Resets the device + virtual void Flush( void ) = 0; + + virtual int FindSourceIndex( CAudioMixer *pSource ) = 0; + virtual CAudioMixer *GetMixerForSource( CAudioSource *source ) = 0; + virtual void FreeChannel( int channelIndex ) = 0; +}; + + +#endif // SND_DEVICE_H diff --git a/public/sourcevr/isourcevirtualreality.h b/public/sourcevr/isourcevirtualreality.h new file mode 100644 index 0000000..e22c670 --- /dev/null +++ b/public/sourcevr/isourcevirtualreality.h @@ -0,0 +1,175 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains the IHeadTrack interface, which is implemented in headtrack.dll +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISOURCEVIRTUALREALITY_H +#define ISOURCEVIRTUALREALITY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "tier1/refcount.h" +#include "appframework/IAppSystem.h" +#include "mathlib/vmatrix.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class ITexture; +class IMaterialSystem; + +//----------------------------------------------------------------------------- +// important enumeration +//----------------------------------------------------------------------------- + +struct VRRect_t +{ + int32 nX; + int32 nY; + int32 nWidth; + int32 nHeight; +}; + + +// NOTE NOTE NOTE!!!! If you up this, grep for "NEW_INTERFACE" to see if there is anything +// waiting to be enabled during an interface revision. +#define SOURCE_VIRTUAL_REALITY_INTERFACE_VERSION "SourceVirtualReality001" + +//----------------------------------------------------------------------------- +// The ISourceVirtualReality interface +//----------------------------------------------------------------------------- + + + +abstract_class ISourceVirtualReality : public IAppSystem +{ +public: + virtual ~ISourceVirtualReality() {} + + // Placeholder for API revision + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + // This enum is used to tell some of the other calls in this interface which eye + // is being requested. + enum VREye + { + VREye_Left = 0, + VREye_Right + }; + + // Which texture is being requested in GetRenderTarget? + enum EWhichRenderTarget + { + RT_Color = 0, + RT_Depth, + }; + + + // ---------------------------------------------------------------------- + // General utilities + // ---------------------------------------------------------------------- + + // Returns true if the game should run in VR mode + virtual bool ShouldRunInVR() = 0; + + // Returns true if there is a compatible HMD connected + virtual bool IsHmdConnected() = 0; + + // The size and position of the viewport for the specified eye + virtual void GetViewportBounds( VREye eEye, int *pnX, int *pnY, int *pnWidth, int *pnHeight ) = 0; + + // Performs the distortion post-processing. + virtual bool DoDistortionProcessing ( VREye eEye ) = 0; + + // Composites the HUD directly onto the backbuffer / render target, including undistort. + virtual bool CompositeHud ( VREye eEye, float ndcHudBounds[4], bool bDoUndistort, bool bBlackout, bool bTranslucent ) = 0; + + // ---------------------------------------------------------------------- + // Getting the current pose + // ---------------------------------------------------------------------- + + // returns the pose relative to the zero point + virtual VMatrix GetMideyePose() = 0; + + // All-in-one interfaces (they call GetCameraPoseZeroFromCurrent) + // Grabs the current tracking data and sets up state for the Override* calls. + virtual bool SampleTrackingState ( float PlayerGameFov, float fPredictionSeconds ) = 0; + + // ---------------------------------------------------------------------- + // Information about the display + // ---------------------------------------------------------------------- + + // Passes back the bounds of the window that the game should create. This might + // span two displays if we're dealing with a two-input display. Returns true + // if the bounds were set. + virtual bool GetDisplayBounds( VRRect_t *pRect ) = 0; + + // Computes and returns the projection matrix for the eye + virtual bool GetEyeProjectionMatrix ( VMatrix *pResult, VREye, float zNear, float zFar, float fovScale ) = 0; + + // Returns the transform from the mid-eye to the specified eye. Multiply this by + // the tweaked (for mouse rotation and WASD translation) mideye position to get the + // view matrix. This matrix takes the user's IPD into account. + virtual VMatrix GetMidEyeFromEye( VREye eEye ) = 0; + + // returns the adapter index to use for VR mode + virtual int GetVRModeAdapter() = 0; + + // ---------------------------------------------------------------------- + // Information about the tracker + // ---------------------------------------------------------------------- + + virtual bool WillDriftInYaw() = 0; + + // ---------------------------------------------------------------------- + // Methods about oversized offscreen rendering + // ---------------------------------------------------------------------- + + // Sets up the pre-distortion render targets. + virtual void CreateRenderTargets( IMaterialSystem *pMaterialSystem ) = 0; + virtual void ShutdownRenderTargets() = 0; + + // fetches the render target for the specified eye + virtual ITexture *GetRenderTarget( VREye eEye, EWhichRenderTarget eWhich ) = 0; + + // Returns the (possibly overridden) framebuffer size for render target sizing. + virtual void GetRenderTargetFrameBufferDimensions( int & nWidth, int & nHeight ) = 0; + + // ---------------------------------------------------------------------- + // Enter/leave VR mode + // ---------------------------------------------------------------------- + virtual bool Activate() = 0; + virtual void Deactivate() = 0; + + virtual bool ShouldForceVRMode() = 0; + virtual void SetShouldForceVRMode() = 0; + +}; + + + +//----------------------------------------------------------------------------- + +extern ISourceVirtualReality *g_pSourceVR; + +inline bool UseVR() +{ + return g_pSourceVR != NULL && g_pSourceVR->ShouldRunInVR(); +} + +inline bool ShouldForceVRActive() +{ + return g_pSourceVR != NULL && g_pSourceVR->ShouldForceVRMode(); +} + +#endif // ISOURCEVIRTUALREALITY_H diff --git a/public/stdstring.h b/public/stdstring.h new file mode 100644 index 0000000..c72320f --- /dev/null +++ b/public/stdstring.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "isaverestore.h" + +#ifndef STDSTRING_H +#define STDSTRING_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifdef _WIN32 +#pragma warning(push) +#include // warnings get enabled in yvals.h +#pragma warning(disable:4663) +#pragma warning(disable:4530) +#pragma warning(disable:4245) +#pragma warning(disable:4018) +#pragma warning(disable:4511) +#endif + +#include "tier0/valve_minmax_off.h" // GCC 4.2.2 headers screw up our min/max defs. +#include +#include "tier0/valve_minmax_on.h" // GCC 4.2.2 headers screw up our min/max defs. + +#ifdef _WIN32 +#pragma warning(pop) +#endif + +class CStdStringSaveRestoreOps : public CDefSaveRestoreOps +{ +public: + enum + { + MAX_SAVE_LEN = 4096, + }; + + // save data type interface + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + std::string *pString = (std::string *)fieldInfo.pField; + Assert( pString->length() < MAX_SAVE_LEN - 1 ); + if ( pString->length() < MAX_SAVE_LEN - 1 ) + pSave->WriteString( pString->c_str() ); + else + pSave->WriteString( "<>" ); + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + std::string *pString = (std::string *)fieldInfo.pField; + char szString[MAX_SAVE_LEN]; + pRestore->ReadString( szString, sizeof(szString), 0 ); + szString[MAX_SAVE_LEN - 1] = 0; + pString->assign( szString ); + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + std::string *pString = (std::string *)fieldInfo.pField; + pString->erase(); + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + std::string *pString = (std::string *)fieldInfo.pField; + return pString->empty(); + } +}; + +//------------------------------------- + +inline ISaveRestoreOps *GetStdStringDataOps() +{ + static CStdStringSaveRestoreOps ops; + return &ops; +} + +//------------------------------------- + +#define DEFINE_STDSTRING(name) \ + { FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, GetStdStringDataOps(), NULL } + +#endif // STDSTRING_H diff --git a/public/steam/isteamapplist.h b/public/steam/isteamapplist.h new file mode 100644 index 0000000..45441bb --- /dev/null +++ b/public/steam/isteamapplist.h @@ -0,0 +1,67 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to app data in Steam +// +//============================================================================= + +#ifndef ISTEAMAPPLIST_H +#define ISTEAMAPPLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "steamtypes.h" + +//----------------------------------------------------------------------------- +// Purpose: This is a restricted interface that can only be used by previously approved apps, +// contact your Steam Account Manager if you believe you need access to this API. +// This interface lets you detect installed apps for the local Steam client, useful for debugging tools +// to offer lists of apps to debug via Steam. +//----------------------------------------------------------------------------- +class ISteamAppList +{ +public: + virtual uint32 GetNumInstalledApps() = 0; + virtual uint32 GetInstalledApps( AppId_t *pvecAppID, uint32 unMaxAppIDs ) = 0; + + virtual int GetAppName( AppId_t nAppID, STEAM_OUT_STRING() char *pchName, int cchNameMax ) = 0; // returns -1 if no name was found + virtual int GetAppInstallDir( AppId_t nAppID, char *pchDirectory, int cchNameMax ) = 0; // returns -1 if no dir was found + + virtual int GetAppBuildId( AppId_t nAppID ) = 0; // return the buildid of this app, may change at any time based on backend updates to the game +}; + +#define STEAMAPPLIST_INTERFACE_VERSION "STEAMAPPLIST_INTERFACE_VERSION001" + +// Global interface accessor +inline ISteamAppList *SteamAppList(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamAppList *, SteamAppList, STEAMAPPLIST_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +//--------------------------------------------------------------------------------- +// Purpose: Sent when a new app is installed +//--------------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( SteamAppInstalled_t, k_iSteamAppListCallbacks + 1 ); + STEAM_CALLBACK_MEMBER( 0, AppId_t, m_nAppID ) // ID of the app that installs +STEAM_CALLBACK_END(1) + + +//--------------------------------------------------------------------------------- +// Purpose: Sent when an app is uninstalled +//--------------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( SteamAppUninstalled_t, k_iSteamAppListCallbacks + 2 ); + STEAM_CALLBACK_MEMBER( 0, AppId_t, m_nAppID ) // ID of the app that installs +STEAM_CALLBACK_END(1) + + +#pragma pack( pop ) +#endif // ISTEAMAPPLIST_H diff --git a/public/steam/isteamapps.h b/public/steam/isteamapps.h new file mode 100644 index 0000000..550cb8f --- /dev/null +++ b/public/steam/isteamapps.h @@ -0,0 +1,202 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to app data in Steam +// +//============================================================================= + +#ifndef ISTEAMAPPS_H +#define ISTEAMAPPS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +const int k_cubAppProofOfPurchaseKeyMax = 240; // max supported length of a legacy cd key + + +//----------------------------------------------------------------------------- +// Purpose: interface to app data +//----------------------------------------------------------------------------- +class ISteamApps +{ +public: + virtual bool BIsSubscribed() = 0; + virtual bool BIsLowViolence() = 0; + virtual bool BIsCybercafe() = 0; + virtual bool BIsVACBanned() = 0; + virtual const char *GetCurrentGameLanguage() = 0; + virtual const char *GetAvailableGameLanguages() = 0; + + // only use this member if you need to check ownership of another game related to yours, a demo for example + virtual bool BIsSubscribedApp( AppId_t appID ) = 0; + + // Takes AppID of DLC and checks if the user owns the DLC & if the DLC is installed + virtual bool BIsDlcInstalled( AppId_t appID ) = 0; + + // returns the Unix time of the purchase of the app + virtual uint32 GetEarliestPurchaseUnixTime( AppId_t nAppID ) = 0; + + // Checks if the user is subscribed to the current app through a free weekend + // This function will return false for users who have a retail or other type of license + // Before using, please ask your Valve technical contact how to package and secure your free weekened + virtual bool BIsSubscribedFromFreeWeekend() = 0; + + // Returns the number of DLC pieces for the running app + virtual int GetDLCCount() = 0; + + // Returns metadata for DLC by index, of range [0, GetDLCCount()] + virtual bool BGetDLCDataByIndex( int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize ) = 0; + + // Install/Uninstall control for optional DLC + virtual void InstallDLC( AppId_t nAppID ) = 0; + virtual void UninstallDLC( AppId_t nAppID ) = 0; + + // Request legacy cd-key for yourself or owned DLC. If you are interested in this + // data then make sure you provide us with a list of valid keys to be distributed + // to users when they purchase the game, before the game ships. + // You'll receive an AppProofOfPurchaseKeyResponse_t callback when + // the key is available (which may be immediately). + virtual void RequestAppProofOfPurchaseKey( AppId_t nAppID ) = 0; + + virtual bool GetCurrentBetaName( char *pchName, int cchNameBufferSize ) = 0; // returns current beta branch name, 'public' is the default branch + virtual bool MarkContentCorrupt( bool bMissingFilesOnly ) = 0; // signal Steam that game files seems corrupt or missing + virtual uint32 GetInstalledDepots( AppId_t appID, DepotId_t *pvecDepots, uint32 cMaxDepots ) = 0; // return installed depots in mount order + + // returns current app install folder for AppID, returns folder name length + virtual uint32 GetAppInstallDir( AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize ) = 0; + virtual bool BIsAppInstalled( AppId_t appID ) = 0; // returns true if that app is installed (not necessarily owned) + + // returns the SteamID of the original owner. If this CSteamID is different from ISteamUser::GetSteamID(), + // the user has a temporary license borrowed via Family Sharing + virtual CSteamID GetAppOwner() = 0; + + // Returns the associated launch param if the game is run via steam://run///?param1=value1¶m2=value2¶m3=value3 etc. + // Parameter names starting with the character '@' are reserved for internal use and will always return and empty string. + // Parameter names starting with an underscore '_' are reserved for steam features -- they can be queried by the game, + // but it is advised that you not param names beginning with an underscore for your own features. + // Check for new launch parameters on callback NewUrlLaunchParameters_t + virtual const char *GetLaunchQueryParam( const char *pchKey ) = 0; + + // get download progress for optional DLC + virtual bool GetDlcDownloadProgress( AppId_t nAppID, uint64 *punBytesDownloaded, uint64 *punBytesTotal ) = 0; + + // return the buildid of this app, may change at any time based on backend updates to the game + virtual int GetAppBuildId() = 0; + + // Request all proof of purchase keys for the calling appid and asociated DLC. + // A series of AppProofOfPurchaseKeyResponse_t callbacks will be sent with + // appropriate appid values, ending with a final callback where the m_nAppId + // member is k_uAppIdInvalid (zero). + virtual void RequestAllProofOfPurchaseKeys() = 0; + + STEAM_CALL_RESULT( FileDetailsResult_t ) + virtual SteamAPICall_t GetFileDetails( const char* pszFileName ) = 0; + + // Get command line if game was launched via Steam URL, e.g. steam://run////. + // This method of passing a connect string (used when joining via rich presence, accepting an + // invite, etc) is preferable to passing the connect string on the operating system command + // line, which is a security risk. In order for rich presence joins to go through this + // path and not be placed on the OS command line, you must set a value in your app's + // configuration on Steam. Ask Valve for help with this. + // + // If game was already running and launched again, the NewUrlLaunchParameters_t will be fired. + virtual int GetLaunchCommandLine( char *pszCommandLine, int cubCommandLine ) = 0; + + // Check if user borrowed this game via Family Sharing, If true, call GetAppOwner() to get the lender SteamID + virtual bool BIsSubscribedFromFamilySharing() = 0; +}; + +#define STEAMAPPS_INTERFACE_VERSION "STEAMAPPS_INTERFACE_VERSION008" + +// Global interface accessor +inline ISteamApps *SteamApps(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamApps *, SteamApps, STEAMAPPS_INTERFACE_VERSION ); + +// Global accessor for the gameserver client +inline ISteamApps *SteamGameServerApps(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamApps *, SteamGameServerApps, STEAMAPPS_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif +//----------------------------------------------------------------------------- +// Purpose: posted after the user gains ownership of DLC & that DLC is installed +//----------------------------------------------------------------------------- +struct DlcInstalled_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 5 }; + AppId_t m_nAppID; // AppID of the DLC +}; + + +//----------------------------------------------------------------------------- +// Purpose: possible results when registering an activation code +//----------------------------------------------------------------------------- +enum ERegisterActivationCodeResult +{ + k_ERegisterActivationCodeResultOK = 0, + k_ERegisterActivationCodeResultFail = 1, + k_ERegisterActivationCodeResultAlreadyRegistered = 2, + k_ERegisterActivationCodeResultTimeout = 3, + k_ERegisterActivationCodeAlreadyOwned = 4, +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to RegisterActivationCode() +//----------------------------------------------------------------------------- +struct RegisterActivationCodeResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 8 }; + ERegisterActivationCodeResult m_eResult; + uint32 m_unPackageRegistered; // package that was registered. Only set on success +}; + + +//--------------------------------------------------------------------------------- +// Purpose: posted after the user gains executes a Steam URL with command line or query parameters +// such as steam://run///-commandline/?param1=value1¶m2=value2¶m3=value3 etc +// while the game is already running. The new params can be queried +// with GetLaunchQueryParam and GetLaunchCommandLine +//--------------------------------------------------------------------------------- +struct NewUrlLaunchParameters_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 14 }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to RequestAppProofOfPurchaseKey/RequestAllProofOfPurchaseKeys +// for supporting third-party CD keys, or other proof-of-purchase systems. +//----------------------------------------------------------------------------- +struct AppProofOfPurchaseKeyResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 21 }; + EResult m_eResult; + uint32 m_nAppID; + uint32 m_cchKeyLength; + char m_rgchKey[k_cubAppProofOfPurchaseKeyMax]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to GetFileDetails +//----------------------------------------------------------------------------- +struct FileDetailsResult_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 23 }; + EResult m_eResult; + uint64 m_ulFileSize; // original file size in bytes + uint8 m_FileSHA[20]; // original file SHA1 hash + uint32 m_unFlags; // +}; + + +#pragma pack( pop ) +#endif // ISTEAMAPPS_H diff --git a/public/steam/isteamappticket.h b/public/steam/isteamappticket.h new file mode 100644 index 0000000..21fb9e1 --- /dev/null +++ b/public/steam/isteamappticket.h @@ -0,0 +1,28 @@ +//====== Copyright 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: a private, but well versioned, interface to get at critical bits +// of a steam3 appticket - consumed by the simple drm wrapper to let it +// ask about ownership with greater confidence. +// +//============================================================================= + +#ifndef ISTEAMAPPTICKET_H +#define ISTEAMAPPTICKET_H +#pragma once + +//----------------------------------------------------------------------------- +// Purpose: hand out a reasonable "future proof" view of an app ownership ticket +// the raw (signed) buffer, and indices into that buffer where the appid and +// steamid are located. the sizes of the appid and steamid are implicit in +// (each version of) the interface - currently uin32 appid and uint64 steamid +//----------------------------------------------------------------------------- +class ISteamAppTicket +{ +public: + virtual uint32 GetAppOwnershipTicketData( uint32 nAppID, void *pvBuffer, uint32 cbBufferLength, uint32 *piAppId, uint32 *piSteamId, uint32 *piSignature, uint32 *pcbSignature ) = 0; +}; + +#define STEAMAPPTICKET_INTERFACE_VERSION "STEAMAPPTICKET_INTERFACE_VERSION001" + + +#endif // ISTEAMAPPTICKET_H diff --git a/public/steam/isteamclient.h b/public/steam/isteamclient.h new file mode 100644 index 0000000..562b2f1 --- /dev/null +++ b/public/steam/isteamclient.h @@ -0,0 +1,177 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Internal low-level access to Steamworks interfaces. +// +// Most users of the Steamworks SDK do not need to include this file. +// You should only include this if you are doing something special. +//============================================================================= + +#ifndef ISTEAMCLIENT_H +#define ISTEAMCLIENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +//----------------------------------------------------------------------------- +// Purpose: Interface to creating a new steam instance, or to +// connect to an existing steam instance, whether it's in a +// different process or is local. +// +// For most scenarios this is all handled automatically via SteamAPI_Init(). +// You'll only need these APIs if you have a more complex versioning scheme, +// or if you want to implement a multiplexed gameserver where a single process +// is handling multiple games at once with independent gameserver SteamIDs. +//----------------------------------------------------------------------------- +class ISteamClient +{ +public: + // Creates a communication pipe to the Steam client. + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual HSteamPipe CreateSteamPipe() = 0; + + // Releases a previously created communications pipe + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual bool BReleaseSteamPipe( HSteamPipe hSteamPipe ) = 0; + + // connects to an existing global user, failing if none exists + // used by the game to coordinate with the steamUI + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual HSteamUser ConnectToGlobalUser( HSteamPipe hSteamPipe ) = 0; + + // used by game servers, create a steam user that won't be shared with anyone else + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual HSteamUser CreateLocalUser( HSteamPipe *phSteamPipe, EAccountType eAccountType ) = 0; + + // removes an allocated user + // NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling + virtual void ReleaseUser( HSteamPipe hSteamPipe, HSteamUser hUser ) = 0; + + // retrieves the ISteamUser interface associated with the handle + virtual ISteamUser *GetISteamUser( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // retrieves the ISteamGameServer interface associated with the handle + virtual ISteamGameServer *GetISteamGameServer( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // set the local IP and Port to bind to + // this must be set before CreateLocalUser() + virtual void SetLocalIPBinding( uint32 unIP, uint16 usPort ) = 0; + + // returns the ISteamFriends interface + virtual ISteamFriends *GetISteamFriends( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamUtils interface + virtual ISteamUtils *GetISteamUtils( HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamMatchmaking interface + virtual ISteamMatchmaking *GetISteamMatchmaking( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamMatchmakingServers interface + virtual ISteamMatchmakingServers *GetISteamMatchmakingServers( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the a generic interface + virtual void *GetISteamGenericInterface( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamUserStats interface + virtual ISteamUserStats *GetISteamUserStats( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamGameServerStats interface + virtual ISteamGameServerStats *GetISteamGameServerStats( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns apps interface + virtual ISteamApps *GetISteamApps( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // networking + virtual ISteamNetworking *GetISteamNetworking( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // remote storage + virtual ISteamRemoteStorage *GetISteamRemoteStorage( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // user screenshots + virtual ISteamScreenshots *GetISteamScreenshots( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // game search + virtual ISteamGameSearch *GetISteamGameSearch( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Deprecated. Applications should use SteamAPI_RunCallbacks() or SteamGameServer_RunCallbacks() instead. + STEAM_PRIVATE_API( virtual void RunFrame() = 0; ) + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message. + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Trigger global shutdown for the DLL + virtual bool BShutdownIfAllPipesClosed() = 0; + + // Expose HTTP interface + virtual ISteamHTTP *GetISteamHTTP( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Deprecated - the ISteamUnifiedMessages interface is no longer intended for public consumption. + STEAM_PRIVATE_API( virtual void *DEPRECATED_GetISteamUnifiedMessages( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0 ; ) + + // Exposes the ISteamController interface - deprecated in favor of Steam Input + virtual ISteamController *GetISteamController( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Exposes the ISteamUGC interface + virtual ISteamUGC *GetISteamUGC( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns app list interface, only available on specially registered apps + virtual ISteamAppList *GetISteamAppList( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Music Player + virtual ISteamMusic *GetISteamMusic( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Music Player Remote + virtual ISteamMusicRemote *GetISteamMusicRemote(HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion) = 0; + + // html page display + virtual ISteamHTMLSurface *GetISteamHTMLSurface(HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion) = 0; + + // Helper functions for internal Steam usage + STEAM_PRIVATE_API( virtual void DEPRECATED_Set_SteamAPI_CPostAPIResultInProcess( void (*)() ) = 0; ) + STEAM_PRIVATE_API( virtual void DEPRECATED_Remove_SteamAPI_CPostAPIResultInProcess( void (*)() ) = 0; ) + STEAM_PRIVATE_API( virtual void Set_SteamAPI_CCheckCallbackRegisteredInProcess( SteamAPI_CheckCallbackRegistered_t func ) = 0; ) + + // inventory + virtual ISteamInventory *GetISteamInventory( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Video + virtual ISteamVideo *GetISteamVideo( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Parental controls + virtual ISteamParentalSettings *GetISteamParentalSettings( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Exposes the Steam Input interface for controller support + virtual ISteamInput *GetISteamInput( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Steam Parties interface + virtual ISteamParties *GetISteamParties( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Steam Remote Play interface + virtual ISteamRemotePlay *GetISteamRemotePlay( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + +}; +#define STEAMCLIENT_INTERFACE_VERSION "SteamClient018" + +#ifndef STEAM_API_EXPORTS + +// Global ISteamClient interface accessor +inline ISteamClient *SteamClient(); +STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamClient *, SteamClient, SteamInternal_CreateInterface( STEAMCLIENT_INTERFACE_VERSION ) ); + +// The internal ISteamClient used for the gameserver interface. +// (This is actually the same thing. You really shouldn't need to access any of this stuff directly.) +inline ISteamClient *SteamGameServerClient() { return SteamClient(); } + +#endif + +#endif // ISTEAMCLIENT_H diff --git a/public/steam/isteamcontroller.h b/public/steam/isteamcontroller.h new file mode 100644 index 0000000..0ff9c00 --- /dev/null +++ b/public/steam/isteamcontroller.h @@ -0,0 +1,619 @@ +//====== Copyright 1996-2018, Valve Corporation, All rights reserved. ======= +// Note: The older ISteamController interface has been deprecated in favor of ISteamInput - this interface +// was updated in this SDK but will be removed from future SDK's. The Steam Client will retain +// compatibility with the older interfaces so your any existing integrations should be unaffected. +// +// Purpose: Steam Input is a flexible input API that supports over three hundred devices including all +// common variants of Xbox, Playstation, Nintendo Switch Pro, and Steam Controllers. +// For more info including a getting started guide for developers +// please visit: https://partner.steamgames.com/doc/features/steam_controller +// +//============================================================================= + +#ifndef ISTEAMCONTROLLER_H +#define ISTEAMCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "isteaminput.h" + +#define STEAM_CONTROLLER_MAX_COUNT 16 + +#define STEAM_CONTROLLER_MAX_ANALOG_ACTIONS 16 + +#define STEAM_CONTROLLER_MAX_DIGITAL_ACTIONS 128 + +#define STEAM_CONTROLLER_MAX_ORIGINS 8 + +#define STEAM_CONTROLLER_MAX_ACTIVE_LAYERS 16 + +// When sending an option to a specific controller handle, you can send to all controllers via this command +#define STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS UINT64_MAX + +#define STEAM_CONTROLLER_MIN_ANALOG_ACTION_DATA -1.0f +#define STEAM_CONTROLLER_MAX_ANALOG_ACTION_DATA 1.0f + +#ifndef ISTEAMINPUT_H +enum ESteamControllerPad +{ + k_ESteamControllerPad_Left, + k_ESteamControllerPad_Right +}; +#endif + +enum EControllerSource +{ + k_EControllerSource_None, + k_EControllerSource_LeftTrackpad, + k_EControllerSource_RightTrackpad, + k_EControllerSource_Joystick, + k_EControllerSource_ABXY, + k_EControllerSource_Switch, + k_EControllerSource_LeftTrigger, + k_EControllerSource_RightTrigger, + k_EControllerSource_LeftBumper, + k_EControllerSource_RightBumper, + k_EControllerSource_Gyro, + k_EControllerSource_CenterTrackpad, // PS4 + k_EControllerSource_RightJoystick, // Traditional Controllers + k_EControllerSource_DPad, // Traditional Controllers + k_EControllerSource_Key, // Keyboards with scan codes - Unused + k_EControllerSource_Mouse, // Traditional mouse - Unused + k_EControllerSource_LeftGyro, // Secondary Gyro - Switch - Unused + k_EControllerSource_Count +}; + +enum EControllerSourceMode +{ + k_EControllerSourceMode_None, + k_EControllerSourceMode_Dpad, + k_EControllerSourceMode_Buttons, + k_EControllerSourceMode_FourButtons, + k_EControllerSourceMode_AbsoluteMouse, + k_EControllerSourceMode_RelativeMouse, + k_EControllerSourceMode_JoystickMove, + k_EControllerSourceMode_JoystickMouse, + k_EControllerSourceMode_JoystickCamera, + k_EControllerSourceMode_ScrollWheel, + k_EControllerSourceMode_Trigger, + k_EControllerSourceMode_TouchMenu, + k_EControllerSourceMode_MouseJoystick, + k_EControllerSourceMode_MouseRegion, + k_EControllerSourceMode_RadialMenu, + k_EControllerSourceMode_SingleButton, + k_EControllerSourceMode_Switches +}; + +// Note: Please do not use action origins as a way to identify controller types. There is no +// guarantee that they will be added in a contiguous manner - use GetInputTypeForHandle instead +// Versions of Steam that add new controller types in the future will extend this enum if you're +// using a lookup table please check the bounds of any origins returned by Steam. +enum EControllerActionOrigin +{ + // Steam Controller + k_EControllerActionOrigin_None, + k_EControllerActionOrigin_A, + k_EControllerActionOrigin_B, + k_EControllerActionOrigin_X, + k_EControllerActionOrigin_Y, + k_EControllerActionOrigin_LeftBumper, + k_EControllerActionOrigin_RightBumper, + k_EControllerActionOrigin_LeftGrip, + k_EControllerActionOrigin_RightGrip, + k_EControllerActionOrigin_Start, + k_EControllerActionOrigin_Back, + k_EControllerActionOrigin_LeftPad_Touch, + k_EControllerActionOrigin_LeftPad_Swipe, + k_EControllerActionOrigin_LeftPad_Click, + k_EControllerActionOrigin_LeftPad_DPadNorth, + k_EControllerActionOrigin_LeftPad_DPadSouth, + k_EControllerActionOrigin_LeftPad_DPadWest, + k_EControllerActionOrigin_LeftPad_DPadEast, + k_EControllerActionOrigin_RightPad_Touch, + k_EControllerActionOrigin_RightPad_Swipe, + k_EControllerActionOrigin_RightPad_Click, + k_EControllerActionOrigin_RightPad_DPadNorth, + k_EControllerActionOrigin_RightPad_DPadSouth, + k_EControllerActionOrigin_RightPad_DPadWest, + k_EControllerActionOrigin_RightPad_DPadEast, + k_EControllerActionOrigin_LeftTrigger_Pull, + k_EControllerActionOrigin_LeftTrigger_Click, + k_EControllerActionOrigin_RightTrigger_Pull, + k_EControllerActionOrigin_RightTrigger_Click, + k_EControllerActionOrigin_LeftStick_Move, + k_EControllerActionOrigin_LeftStick_Click, + k_EControllerActionOrigin_LeftStick_DPadNorth, + k_EControllerActionOrigin_LeftStick_DPadSouth, + k_EControllerActionOrigin_LeftStick_DPadWest, + k_EControllerActionOrigin_LeftStick_DPadEast, + k_EControllerActionOrigin_Gyro_Move, + k_EControllerActionOrigin_Gyro_Pitch, + k_EControllerActionOrigin_Gyro_Yaw, + k_EControllerActionOrigin_Gyro_Roll, + + // PS4 Dual Shock + k_EControllerActionOrigin_PS4_X, + k_EControllerActionOrigin_PS4_Circle, + k_EControllerActionOrigin_PS4_Triangle, + k_EControllerActionOrigin_PS4_Square, + k_EControllerActionOrigin_PS4_LeftBumper, + k_EControllerActionOrigin_PS4_RightBumper, + k_EControllerActionOrigin_PS4_Options, //Start + k_EControllerActionOrigin_PS4_Share, //Back + k_EControllerActionOrigin_PS4_LeftPad_Touch, + k_EControllerActionOrigin_PS4_LeftPad_Swipe, + k_EControllerActionOrigin_PS4_LeftPad_Click, + k_EControllerActionOrigin_PS4_LeftPad_DPadNorth, + k_EControllerActionOrigin_PS4_LeftPad_DPadSouth, + k_EControllerActionOrigin_PS4_LeftPad_DPadWest, + k_EControllerActionOrigin_PS4_LeftPad_DPadEast, + k_EControllerActionOrigin_PS4_RightPad_Touch, + k_EControllerActionOrigin_PS4_RightPad_Swipe, + k_EControllerActionOrigin_PS4_RightPad_Click, + k_EControllerActionOrigin_PS4_RightPad_DPadNorth, + k_EControllerActionOrigin_PS4_RightPad_DPadSouth, + k_EControllerActionOrigin_PS4_RightPad_DPadWest, + k_EControllerActionOrigin_PS4_RightPad_DPadEast, + k_EControllerActionOrigin_PS4_CenterPad_Touch, + k_EControllerActionOrigin_PS4_CenterPad_Swipe, + k_EControllerActionOrigin_PS4_CenterPad_Click, + k_EControllerActionOrigin_PS4_CenterPad_DPadNorth, + k_EControllerActionOrigin_PS4_CenterPad_DPadSouth, + k_EControllerActionOrigin_PS4_CenterPad_DPadWest, + k_EControllerActionOrigin_PS4_CenterPad_DPadEast, + k_EControllerActionOrigin_PS4_LeftTrigger_Pull, + k_EControllerActionOrigin_PS4_LeftTrigger_Click, + k_EControllerActionOrigin_PS4_RightTrigger_Pull, + k_EControllerActionOrigin_PS4_RightTrigger_Click, + k_EControllerActionOrigin_PS4_LeftStick_Move, + k_EControllerActionOrigin_PS4_LeftStick_Click, + k_EControllerActionOrigin_PS4_LeftStick_DPadNorth, + k_EControllerActionOrigin_PS4_LeftStick_DPadSouth, + k_EControllerActionOrigin_PS4_LeftStick_DPadWest, + k_EControllerActionOrigin_PS4_LeftStick_DPadEast, + k_EControllerActionOrigin_PS4_RightStick_Move, + k_EControllerActionOrigin_PS4_RightStick_Click, + k_EControllerActionOrigin_PS4_RightStick_DPadNorth, + k_EControllerActionOrigin_PS4_RightStick_DPadSouth, + k_EControllerActionOrigin_PS4_RightStick_DPadWest, + k_EControllerActionOrigin_PS4_RightStick_DPadEast, + k_EControllerActionOrigin_PS4_DPad_North, + k_EControllerActionOrigin_PS4_DPad_South, + k_EControllerActionOrigin_PS4_DPad_West, + k_EControllerActionOrigin_PS4_DPad_East, + k_EControllerActionOrigin_PS4_Gyro_Move, + k_EControllerActionOrigin_PS4_Gyro_Pitch, + k_EControllerActionOrigin_PS4_Gyro_Yaw, + k_EControllerActionOrigin_PS4_Gyro_Roll, + + // XBox One + k_EControllerActionOrigin_XBoxOne_A, + k_EControllerActionOrigin_XBoxOne_B, + k_EControllerActionOrigin_XBoxOne_X, + k_EControllerActionOrigin_XBoxOne_Y, + k_EControllerActionOrigin_XBoxOne_LeftBumper, + k_EControllerActionOrigin_XBoxOne_RightBumper, + k_EControllerActionOrigin_XBoxOne_Menu, //Start + k_EControllerActionOrigin_XBoxOne_View, //Back + k_EControllerActionOrigin_XBoxOne_LeftTrigger_Pull, + k_EControllerActionOrigin_XBoxOne_LeftTrigger_Click, + k_EControllerActionOrigin_XBoxOne_RightTrigger_Pull, + k_EControllerActionOrigin_XBoxOne_RightTrigger_Click, + k_EControllerActionOrigin_XBoxOne_LeftStick_Move, + k_EControllerActionOrigin_XBoxOne_LeftStick_Click, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadNorth, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadSouth, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadWest, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadEast, + k_EControllerActionOrigin_XBoxOne_RightStick_Move, + k_EControllerActionOrigin_XBoxOne_RightStick_Click, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadNorth, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadSouth, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadWest, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadEast, + k_EControllerActionOrigin_XBoxOne_DPad_North, + k_EControllerActionOrigin_XBoxOne_DPad_South, + k_EControllerActionOrigin_XBoxOne_DPad_West, + k_EControllerActionOrigin_XBoxOne_DPad_East, + + // XBox 360 + k_EControllerActionOrigin_XBox360_A, + k_EControllerActionOrigin_XBox360_B, + k_EControllerActionOrigin_XBox360_X, + k_EControllerActionOrigin_XBox360_Y, + k_EControllerActionOrigin_XBox360_LeftBumper, + k_EControllerActionOrigin_XBox360_RightBumper, + k_EControllerActionOrigin_XBox360_Start, //Start + k_EControllerActionOrigin_XBox360_Back, //Back + k_EControllerActionOrigin_XBox360_LeftTrigger_Pull, + k_EControllerActionOrigin_XBox360_LeftTrigger_Click, + k_EControllerActionOrigin_XBox360_RightTrigger_Pull, + k_EControllerActionOrigin_XBox360_RightTrigger_Click, + k_EControllerActionOrigin_XBox360_LeftStick_Move, + k_EControllerActionOrigin_XBox360_LeftStick_Click, + k_EControllerActionOrigin_XBox360_LeftStick_DPadNorth, + k_EControllerActionOrigin_XBox360_LeftStick_DPadSouth, + k_EControllerActionOrigin_XBox360_LeftStick_DPadWest, + k_EControllerActionOrigin_XBox360_LeftStick_DPadEast, + k_EControllerActionOrigin_XBox360_RightStick_Move, + k_EControllerActionOrigin_XBox360_RightStick_Click, + k_EControllerActionOrigin_XBox360_RightStick_DPadNorth, + k_EControllerActionOrigin_XBox360_RightStick_DPadSouth, + k_EControllerActionOrigin_XBox360_RightStick_DPadWest, + k_EControllerActionOrigin_XBox360_RightStick_DPadEast, + k_EControllerActionOrigin_XBox360_DPad_North, + k_EControllerActionOrigin_XBox360_DPad_South, + k_EControllerActionOrigin_XBox360_DPad_West, + k_EControllerActionOrigin_XBox360_DPad_East, + + // SteamController V2 + k_EControllerActionOrigin_SteamV2_A, + k_EControllerActionOrigin_SteamV2_B, + k_EControllerActionOrigin_SteamV2_X, + k_EControllerActionOrigin_SteamV2_Y, + k_EControllerActionOrigin_SteamV2_LeftBumper, + k_EControllerActionOrigin_SteamV2_RightBumper, + k_EControllerActionOrigin_SteamV2_LeftGrip_Lower, + k_EControllerActionOrigin_SteamV2_LeftGrip_Upper, + k_EControllerActionOrigin_SteamV2_RightGrip_Lower, + k_EControllerActionOrigin_SteamV2_RightGrip_Upper, + k_EControllerActionOrigin_SteamV2_LeftBumper_Pressure, + k_EControllerActionOrigin_SteamV2_RightBumper_Pressure, + k_EControllerActionOrigin_SteamV2_LeftGrip_Pressure, + k_EControllerActionOrigin_SteamV2_RightGrip_Pressure, + k_EControllerActionOrigin_SteamV2_LeftGrip_Upper_Pressure, + k_EControllerActionOrigin_SteamV2_RightGrip_Upper_Pressure, + k_EControllerActionOrigin_SteamV2_Start, + k_EControllerActionOrigin_SteamV2_Back, + k_EControllerActionOrigin_SteamV2_LeftPad_Touch, + k_EControllerActionOrigin_SteamV2_LeftPad_Swipe, + k_EControllerActionOrigin_SteamV2_LeftPad_Click, + k_EControllerActionOrigin_SteamV2_LeftPad_Pressure, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadNorth, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadSouth, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadWest, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadEast, + k_EControllerActionOrigin_SteamV2_RightPad_Touch, + k_EControllerActionOrigin_SteamV2_RightPad_Swipe, + k_EControllerActionOrigin_SteamV2_RightPad_Click, + k_EControllerActionOrigin_SteamV2_RightPad_Pressure, + k_EControllerActionOrigin_SteamV2_RightPad_DPadNorth, + k_EControllerActionOrigin_SteamV2_RightPad_DPadSouth, + k_EControllerActionOrigin_SteamV2_RightPad_DPadWest, + k_EControllerActionOrigin_SteamV2_RightPad_DPadEast, + k_EControllerActionOrigin_SteamV2_LeftTrigger_Pull, + k_EControllerActionOrigin_SteamV2_LeftTrigger_Click, + k_EControllerActionOrigin_SteamV2_RightTrigger_Pull, + k_EControllerActionOrigin_SteamV2_RightTrigger_Click, + k_EControllerActionOrigin_SteamV2_LeftStick_Move, + k_EControllerActionOrigin_SteamV2_LeftStick_Click, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadNorth, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadSouth, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadWest, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadEast, + k_EControllerActionOrigin_SteamV2_Gyro_Move, + k_EControllerActionOrigin_SteamV2_Gyro_Pitch, + k_EControllerActionOrigin_SteamV2_Gyro_Yaw, + k_EControllerActionOrigin_SteamV2_Gyro_Roll, + + // Switch - Pro or Joycons used as a single input device. + // This does not apply to a single joycon + k_EControllerActionOrigin_Switch_A, + k_EControllerActionOrigin_Switch_B, + k_EControllerActionOrigin_Switch_X, + k_EControllerActionOrigin_Switch_Y, + k_EControllerActionOrigin_Switch_LeftBumper, + k_EControllerActionOrigin_Switch_RightBumper, + k_EControllerActionOrigin_Switch_Plus, //Start + k_EControllerActionOrigin_Switch_Minus, //Back + k_EControllerActionOrigin_Switch_Capture, + k_EControllerActionOrigin_Switch_LeftTrigger_Pull, + k_EControllerActionOrigin_Switch_LeftTrigger_Click, + k_EControllerActionOrigin_Switch_RightTrigger_Pull, + k_EControllerActionOrigin_Switch_RightTrigger_Click, + k_EControllerActionOrigin_Switch_LeftStick_Move, + k_EControllerActionOrigin_Switch_LeftStick_Click, + k_EControllerActionOrigin_Switch_LeftStick_DPadNorth, + k_EControllerActionOrigin_Switch_LeftStick_DPadSouth, + k_EControllerActionOrigin_Switch_LeftStick_DPadWest, + k_EControllerActionOrigin_Switch_LeftStick_DPadEast, + k_EControllerActionOrigin_Switch_RightStick_Move, + k_EControllerActionOrigin_Switch_RightStick_Click, + k_EControllerActionOrigin_Switch_RightStick_DPadNorth, + k_EControllerActionOrigin_Switch_RightStick_DPadSouth, + k_EControllerActionOrigin_Switch_RightStick_DPadWest, + k_EControllerActionOrigin_Switch_RightStick_DPadEast, + k_EControllerActionOrigin_Switch_DPad_North, + k_EControllerActionOrigin_Switch_DPad_South, + k_EControllerActionOrigin_Switch_DPad_West, + k_EControllerActionOrigin_Switch_DPad_East, + k_EControllerActionOrigin_Switch_ProGyro_Move, // Primary Gyro in Pro Controller, or Right JoyCon + k_EControllerActionOrigin_Switch_ProGyro_Pitch, // Primary Gyro in Pro Controller, or Right JoyCon + k_EControllerActionOrigin_Switch_ProGyro_Yaw, // Primary Gyro in Pro Controller, or Right JoyCon + k_EControllerActionOrigin_Switch_ProGyro_Roll, // Primary Gyro in Pro Controller, or Right JoyCon + // Switch JoyCon Specific + k_EControllerActionOrigin_Switch_RightGyro_Move, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EControllerActionOrigin_Switch_RightGyro_Pitch, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EControllerActionOrigin_Switch_RightGyro_Yaw, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EControllerActionOrigin_Switch_RightGyro_Roll, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EControllerActionOrigin_Switch_LeftGyro_Move, + k_EControllerActionOrigin_Switch_LeftGyro_Pitch, + k_EControllerActionOrigin_Switch_LeftGyro_Yaw, + k_EControllerActionOrigin_Switch_LeftGyro_Roll, + k_EControllerActionOrigin_Switch_LeftGrip_Lower, // Left JoyCon SR Button + k_EControllerActionOrigin_Switch_LeftGrip_Upper, // Left JoyCon SL Button + k_EControllerActionOrigin_Switch_RightGrip_Lower, // Right JoyCon SL Button + k_EControllerActionOrigin_Switch_RightGrip_Upper, // Right JoyCon SR Button + + // Added in SDK 1.45 + k_EControllerActionOrigin_PS4_DPad_Move, + k_EControllerActionOrigin_XBoxOne_DPad_Move, + k_EControllerActionOrigin_XBox360_DPad_Move, + k_EControllerActionOrigin_Switch_DPad_Move, + + k_EControllerActionOrigin_Count, // If Steam has added support for new controllers origins will go here. + k_EControllerActionOrigin_MaximumPossibleValue = 32767, // Origins are currently a maximum of 16 bits. +}; + +#ifndef ISTEAMINPUT_H +enum EXboxOrigin +{ + k_EXboxOrigin_A, + k_EXboxOrigin_B, + k_EXboxOrigin_X, + k_EXboxOrigin_Y, + k_EXboxOrigin_LeftBumper, + k_EXboxOrigin_RightBumper, + k_EXboxOrigin_Menu, //Start + k_EXboxOrigin_View, //Back + k_EXboxOrigin_LeftTrigger_Pull, + k_EXboxOrigin_LeftTrigger_Click, + k_EXboxOrigin_RightTrigger_Pull, + k_EXboxOrigin_RightTrigger_Click, + k_EXboxOrigin_LeftStick_Move, + k_EXboxOrigin_LeftStick_Click, + k_EXboxOrigin_LeftStick_DPadNorth, + k_EXboxOrigin_LeftStick_DPadSouth, + k_EXboxOrigin_LeftStick_DPadWest, + k_EXboxOrigin_LeftStick_DPadEast, + k_EXboxOrigin_RightStick_Move, + k_EXboxOrigin_RightStick_Click, + k_EXboxOrigin_RightStick_DPadNorth, + k_EXboxOrigin_RightStick_DPadSouth, + k_EXboxOrigin_RightStick_DPadWest, + k_EXboxOrigin_RightStick_DPadEast, + k_EXboxOrigin_DPad_North, + k_EXboxOrigin_DPad_South, + k_EXboxOrigin_DPad_West, + k_EXboxOrigin_DPad_East, +}; + +enum ESteamInputType +{ + k_ESteamInputType_Unknown, + k_ESteamInputType_SteamController, + k_ESteamInputType_XBox360Controller, + k_ESteamInputType_XBoxOneController, + k_ESteamInputType_GenericGamepad, // DirectInput controllers + k_ESteamInputType_PS4Controller, + k_ESteamInputType_AppleMFiController, // Unused + k_ESteamInputType_AndroidController, // Unused + k_ESteamInputType_SwitchJoyConPair, // Unused + k_ESteamInputType_SwitchJoyConSingle, // Unused + k_ESteamInputType_SwitchProController, + k_ESteamInputType_MobileTouch, // Steam Link App On-screen Virtual Controller + k_ESteamInputType_PS3Controller, // Currently uses PS4 Origins + k_ESteamInputType_Count, + k_ESteamInputType_MaximumPossibleValue = 255, +}; +#endif + +enum ESteamControllerLEDFlag +{ + k_ESteamControllerLEDFlag_SetColor, + k_ESteamControllerLEDFlag_RestoreUserDefault +}; + +// ControllerHandle_t is used to refer to a specific controller. +// This handle will consistently identify a controller, even if it is disconnected and re-connected +typedef uint64 ControllerHandle_t; + + +// These handles are used to refer to a specific in-game action or action set +// All action handles should be queried during initialization for performance reasons +typedef uint64 ControllerActionSetHandle_t; +typedef uint64 ControllerDigitalActionHandle_t; +typedef uint64 ControllerAnalogActionHandle_t; + +#pragma pack( push, 1 ) + +#ifdef ISTEAMINPUT_H +#define ControllerAnalogActionData_t InputAnalogActionData_t +#define ControllerDigitalActionData_t InputDigitalActionData_t +#define ControllerMotionData_t InputMotionData_t +#else +struct ControllerAnalogActionData_t +{ + // Type of data coming from this action, this will match what got specified in the action set + EControllerSourceMode eMode; + + // The current state of this action; will be delta updates for mouse actions + float x, y; + + // Whether or not this action is currently available to be bound in the active action set + bool bActive; +}; + +struct ControllerDigitalActionData_t +{ + // The current state of this action; will be true if currently pressed + bool bState; + + // Whether or not this action is currently available to be bound in the active action set + bool bActive; +}; + +struct ControllerMotionData_t +{ + // Sensor-fused absolute rotation; will drift in heading + float rotQuatX; + float rotQuatY; + float rotQuatZ; + float rotQuatW; + + // Positional acceleration + float posAccelX; + float posAccelY; + float posAccelZ; + + // Angular velocity + float rotVelX; + float rotVelY; + float rotVelZ; +}; +#endif +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Steam Input API +//----------------------------------------------------------------------------- +class ISteamController +{ +public: + + // Init and Shutdown must be called when starting/ending use of this interface + virtual bool Init() = 0; + virtual bool Shutdown() = 0; + + // Synchronize API state with the latest Steam Controller inputs available. This + // is performed automatically by SteamAPI_RunCallbacks, but for the absolute lowest + // possible latency, you call this directly before reading controller state. This must + // be called from somewhere before GetConnectedControllers will return any handles + virtual void RunFrame() = 0; + + // Enumerate currently connected controllers + // handlesOut should point to a STEAM_CONTROLLER_MAX_COUNT sized array of ControllerHandle_t handles + // Returns the number of handles written to handlesOut + virtual int GetConnectedControllers( STEAM_OUT_ARRAY_COUNT( STEAM_CONTROLLER_MAX_COUNT, Receives list of connected controllers ) ControllerHandle_t *handlesOut ) = 0; + + //----------------------------------------------------------------------------- + // ACTION SETS + //----------------------------------------------------------------------------- + + // Lookup the handle for an Action Set. Best to do this once on startup, and store the handles for all future API calls. + virtual ControllerActionSetHandle_t GetActionSetHandle( const char *pszActionSetName ) = 0; + + // Reconfigure the controller to use the specified action set (ie 'Menu', 'Walk' or 'Drive') + // This is cheap, and can be safely called repeatedly. It's often easier to repeatedly call it in + // your state loops, instead of trying to place it in all of your state transitions. + virtual void ActivateActionSet( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle ) = 0; + virtual ControllerActionSetHandle_t GetCurrentActionSet( ControllerHandle_t controllerHandle ) = 0; + + // ACTION SET LAYERS + virtual void ActivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ) = 0; + virtual void DeactivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ) = 0; + virtual void DeactivateAllActionSetLayers( ControllerHandle_t controllerHandle ) = 0; + // Enumerate currently active layers + // handlesOut should point to a STEAM_CONTROLLER_MAX_ACTIVE_LAYERS sized array of ControllerActionSetHandle_t handles. + // Returns the number of handles written to handlesOut + virtual int GetActiveActionSetLayers( ControllerHandle_t controllerHandle, STEAM_OUT_ARRAY_COUNT( STEAM_CONTROLLER_MAX_ACTIVE_LAYERS, Receives list of active layers ) ControllerActionSetHandle_t *handlesOut ) = 0; + + //----------------------------------------------------------------------------- + // ACTIONS + //----------------------------------------------------------------------------- + + // Lookup the handle for a digital action. Best to do this once on startup, and store the handles for all future API calls. + virtual ControllerDigitalActionHandle_t GetDigitalActionHandle( const char *pszActionName ) = 0; + + // Returns the current state of the supplied digital game action + virtual ControllerDigitalActionData_t GetDigitalActionData( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle ) = 0; + + // Get the origin(s) for a digital action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. + // originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles. The EControllerActionOrigin enum will get extended as support for new controller controllers gets added to + // the Steam client and will exceed the values from this header, please check bounds if you are using a look up table. + virtual int GetDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, STEAM_OUT_ARRAY_COUNT( STEAM_CONTROLLER_MAX_ORIGINS, Receives list of aciton origins ) EControllerActionOrigin *originsOut ) = 0; + + // Lookup the handle for an analog action. Best to do this once on startup, and store the handles for all future API calls. + virtual ControllerAnalogActionHandle_t GetAnalogActionHandle( const char *pszActionName ) = 0; + + // Returns the current state of these supplied analog game action + virtual ControllerAnalogActionData_t GetAnalogActionData( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle ) = 0; + + // Get the origin(s) for an analog action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. + // originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles. The EControllerActionOrigin enum will get extended as support for new controller controllers gets added to + // the Steam client and will exceed the values from this header, please check bounds if you are using a look up table. + virtual int GetAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, STEAM_OUT_ARRAY_COUNT( STEAM_CONTROLLER_MAX_ORIGINS, Receives list of action origins ) EControllerActionOrigin *originsOut ) = 0; + + // Get a local path to art for on-screen glyph for a particular origin - this call is cheap + virtual const char *GetGlyphForActionOrigin( EControllerActionOrigin eOrigin ) = 0; + + // Returns a localized string (from Steam's language setting) for the specified origin - this call is serialized + virtual const char *GetStringForActionOrigin( EControllerActionOrigin eOrigin ) = 0; + + virtual void StopAnalogActionMomentum( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction ) = 0; + + // Returns raw motion data from the specified controller + virtual ControllerMotionData_t GetMotionData( ControllerHandle_t controllerHandle ) = 0; + + //----------------------------------------------------------------------------- + // OUTPUTS + //----------------------------------------------------------------------------- + + // Trigger a haptic pulse on a controller + virtual void TriggerHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ) = 0; + + // Trigger a pulse with a duty cycle of usDurationMicroSec / usOffMicroSec, unRepeat times. + // nFlags is currently unused and reserved for future use. + virtual void TriggerRepeatedHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ) = 0; + + // Trigger a vibration event on supported controllers. + virtual void TriggerVibration( ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed ) = 0; + + // Set the controller LED color on supported controllers. + virtual void SetLEDColor( ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags ) = 0; + + //----------------------------------------------------------------------------- + // Utility functions availible without using the rest of Steam Input API + //----------------------------------------------------------------------------- + + // Invokes the Steam overlay and brings up the binding screen if the user is using Big Picture Mode + // If the user is not in Big Picture Mode it will open up the binding in a new window + virtual bool ShowBindingPanel( ControllerHandle_t controllerHandle ) = 0; + + // Returns the input type for a particular handle + virtual ESteamInputType GetInputTypeForHandle( ControllerHandle_t controllerHandle ) = 0; + + // Returns the associated controller handle for the specified emulated gamepad - can be used with the above 2 functions + // to identify controllers presented to your game over Xinput. Returns 0 if the Xinput index isn't associated with Steam Input + virtual ControllerHandle_t GetControllerForGamepadIndex( int nIndex ) = 0; + + // Returns the associated gamepad index for the specified controller, if emulating a gamepad or -1 if not associated with an Xinput index + virtual int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle ) = 0; + + // Returns a localized string (from Steam's language setting) for the specified Xbox controller origin. + virtual const char *GetStringForXboxOrigin( EXboxOrigin eOrigin ) = 0; + + // Get a local path to art for on-screen glyph for a particular Xbox controller origin. + virtual const char *GetGlyphForXboxOrigin( EXboxOrigin eOrigin ) = 0; + + // Get the equivalent ActionOrigin for a given Xbox controller origin this can be chained with GetGlyphForActionOrigin to provide future proof glyphs for + // non-Steam Input API action games. Note - this only translates the buttons directly and doesn't take into account any remapping a user has made in their configuration + virtual EControllerActionOrigin GetActionOriginFromXboxOrigin( ControllerHandle_t controllerHandle, EXboxOrigin eOrigin ) = 0; + + // Convert an origin to another controller type - for inputs not present on the other controller type this will return k_EControllerActionOrigin_None + virtual EControllerActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EControllerActionOrigin eSourceOrigin ) = 0; + + // Get the binding revision for a given device. Returns false if the handle was not valid or if a mapping is not yet loaded for the device + virtual bool GetControllerBindingRevision( ControllerHandle_t controllerHandle, int *pMajor, int *pMinor ) = 0; +}; + +#define STEAMCONTROLLER_INTERFACE_VERSION "SteamController007" + +// Global interface accessor +inline ISteamController *SteamController(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamController *, SteamController, STEAMCONTROLLER_INTERFACE_VERSION ); + +#endif // ISTEAMCONTROLLER_H diff --git a/public/steam/isteamfriends.h b/public/steam/isteamfriends.h new file mode 100644 index 0000000..8a280c3 --- /dev/null +++ b/public/steam/isteamfriends.h @@ -0,0 +1,675 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Purpose: interface to both friends list data and general information about users +// +//============================================================================= + +#ifndef ISTEAMFRIENDS_H +#define ISTEAMFRIENDS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +//----------------------------------------------------------------------------- +// Purpose: set of relationships to other users +//----------------------------------------------------------------------------- +enum EFriendRelationship +{ + k_EFriendRelationshipNone = 0, + k_EFriendRelationshipBlocked = 1, // this doesn't get stored; the user has just done an Ignore on an friendship invite + k_EFriendRelationshipRequestRecipient = 2, + k_EFriendRelationshipFriend = 3, + k_EFriendRelationshipRequestInitiator = 4, + k_EFriendRelationshipIgnored = 5, // this is stored; the user has explicit blocked this other user from comments/chat/etc + k_EFriendRelationshipIgnoredFriend = 6, + k_EFriendRelationshipSuggested_DEPRECATED = 7, // was used by the original implementation of the facebook linking feature, but now unused. + + // keep this updated + k_EFriendRelationshipMax = 8, +}; + +// maximum length of friend group name (not including terminating nul!) +const int k_cchMaxFriendsGroupName = 64; + +// maximum number of groups a single user is allowed +const int k_cFriendsGroupLimit = 100; + +// friends group identifier type +typedef int16 FriendsGroupID_t; + +// invalid friends group identifier constant +const FriendsGroupID_t k_FriendsGroupID_Invalid = -1; + +const int k_cEnumerateFollowersMax = 50; + + +//----------------------------------------------------------------------------- +// Purpose: list of states a friend can be in +//----------------------------------------------------------------------------- +enum EPersonaState +{ + k_EPersonaStateOffline = 0, // friend is not currently logged on + k_EPersonaStateOnline = 1, // friend is logged on + k_EPersonaStateBusy = 2, // user is on, but busy + k_EPersonaStateAway = 3, // auto-away feature + k_EPersonaStateSnooze = 4, // auto-away for a long time + k_EPersonaStateLookingToTrade = 5, // Online, trading + k_EPersonaStateLookingToPlay = 6, // Online, wanting to play + k_EPersonaStateInvisible = 7, // Online, but appears offline to friends. This status is never published to clients. + k_EPersonaStateMax, +}; + + +//----------------------------------------------------------------------------- +// Purpose: flags for enumerating friends list, or quickly checking a the relationship between users +//----------------------------------------------------------------------------- +enum EFriendFlags +{ + k_EFriendFlagNone = 0x00, + k_EFriendFlagBlocked = 0x01, + k_EFriendFlagFriendshipRequested = 0x02, + k_EFriendFlagImmediate = 0x04, // "regular" friend + k_EFriendFlagClanMember = 0x08, + k_EFriendFlagOnGameServer = 0x10, + // k_EFriendFlagHasPlayedWith = 0x20, // not currently used + // k_EFriendFlagFriendOfFriend = 0x40, // not currently used + k_EFriendFlagRequestingFriendship = 0x80, + k_EFriendFlagRequestingInfo = 0x100, + k_EFriendFlagIgnored = 0x200, + k_EFriendFlagIgnoredFriend = 0x400, + // k_EFriendFlagSuggested = 0x800, // not used + k_EFriendFlagChatMember = 0x1000, + k_EFriendFlagAll = 0xFFFF, +}; + + +// friend game played information +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif +struct FriendGameInfo_t +{ + CGameID m_gameID; + uint32 m_unGameIP; + uint16 m_usGamePort; + uint16 m_usQueryPort; + CSteamID m_steamIDLobby; +}; +#pragma pack( pop ) + +// maximum number of characters in a user's name. Two flavors; one for UTF-8 and one for UTF-16. +// The UTF-8 version has to be very generous to accomodate characters that get large when encoded +// in UTF-8. +enum +{ + k_cchPersonaNameMax = 128, + k_cwchPersonaNameMax = 32, +}; + +//----------------------------------------------------------------------------- +// Purpose: user restriction flags +//----------------------------------------------------------------------------- +enum EUserRestriction +{ + k_nUserRestrictionNone = 0, // no known chat/content restriction + k_nUserRestrictionUnknown = 1, // we don't know yet (user offline) + k_nUserRestrictionAnyChat = 2, // user is not allowed to (or can't) send/recv any chat + k_nUserRestrictionVoiceChat = 4, // user is not allowed to (or can't) send/recv voice chat + k_nUserRestrictionGroupChat = 8, // user is not allowed to (or can't) send/recv group chat + k_nUserRestrictionRating = 16, // user is too young according to rating in current region + k_nUserRestrictionGameInvites = 32, // user cannot send or recv game invites (e.g. mobile) + k_nUserRestrictionTrading = 64, // user cannot participate in trading (console, mobile) +}; + +//----------------------------------------------------------------------------- +// Purpose: information about user sessions +//----------------------------------------------------------------------------- +struct FriendSessionStateInfo_t +{ + uint32 m_uiOnlineSessionInstances; + uint8 m_uiPublishedToFriendsSessionInstance; +}; + + + +// size limit on chat room or member metadata +const uint32 k_cubChatMetadataMax = 8192; + +// size limits on Rich Presence data +enum { k_cchMaxRichPresenceKeys = 30 }; +enum { k_cchMaxRichPresenceKeyLength = 64 }; +enum { k_cchMaxRichPresenceValueLength = 256 }; + +// These values are passed as parameters to the store +enum EOverlayToStoreFlag +{ + k_EOverlayToStoreFlag_None = 0, + k_EOverlayToStoreFlag_AddToCart = 1, + k_EOverlayToStoreFlag_AddToCartAndShow = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Tells Steam where to place the browser window inside the overlay +//----------------------------------------------------------------------------- +enum EActivateGameOverlayToWebPageMode +{ + k_EActivateGameOverlayToWebPageMode_Default = 0, // Browser will open next to all other windows that the user has open in the overlay. + // The window will remain open, even if the user closes then re-opens the overlay. + + k_EActivateGameOverlayToWebPageMode_Modal = 1 // Browser will be opened in a special overlay configuration which hides all other windows + // that the user has open in the overlay. When the user closes the overlay, the browser window + // will also close. When the user closes the browser window, the overlay will automatically close. +}; + + +//----------------------------------------------------------------------------- +// Purpose: interface to accessing information about individual users, +// that can be a friend, in a group, on a game server or in a lobby with the local user +//----------------------------------------------------------------------------- +class ISteamFriends +{ +public: + // returns the local players name - guaranteed to not be NULL. + // this is the same name as on the users community profile page + // this is stored in UTF-8 format + // like all the other interface functions that return a char *, it's important that this pointer is not saved + // off; it will eventually be free'd or re-allocated + virtual const char *GetPersonaName() = 0; + + // Sets the player name, stores it on the server and publishes the changes to all friends who are online. + // Changes take place locally immediately, and a PersonaStateChange_t is posted, presuming success. + // + // The final results are available through the return value SteamAPICall_t, using SetPersonaNameResponse_t. + // + // If the name change fails to happen on the server, then an additional global PersonaStateChange_t will be posted + // to change the name back, in addition to the SetPersonaNameResponse_t callback. + STEAM_CALL_RESULT( SetPersonaNameResponse_t ) + virtual SteamAPICall_t SetPersonaName( const char *pchPersonaName ) = 0; + + // gets the status of the current user + virtual EPersonaState GetPersonaState() = 0; + + // friend iteration + // takes a set of k_EFriendFlags, and returns the number of users the client knows about who meet that criteria + // then GetFriendByIndex() can then be used to return the id's of each of those users + virtual int GetFriendCount( int iFriendFlags ) = 0; + + // returns the steamID of a user + // iFriend is a index of range [0, GetFriendCount()) + // iFriendsFlags must be the same value as used in GetFriendCount() + // the returned CSteamID can then be used by all the functions below to access details about the user + virtual CSteamID GetFriendByIndex( int iFriend, int iFriendFlags ) = 0; + + // returns a relationship to a user + virtual EFriendRelationship GetFriendRelationship( CSteamID steamIDFriend ) = 0; + + // returns the current status of the specified user + // this will only be known by the local user if steamIDFriend is in their friends list; on the same game server; in a chat room or lobby; or in a small group with the local user + virtual EPersonaState GetFriendPersonaState( CSteamID steamIDFriend ) = 0; + + // returns the name another user - guaranteed to not be NULL. + // same rules as GetFriendPersonaState() apply as to whether or not the user knowns the name of the other user + // note that on first joining a lobby, chat room or game server the local user will not known the name of the other users automatically; that information will arrive asyncronously + // + virtual const char *GetFriendPersonaName( CSteamID steamIDFriend ) = 0; + + // returns true if the friend is actually in a game, and fills in pFriendGameInfo with an extra details + virtual bool GetFriendGamePlayed( CSteamID steamIDFriend, STEAM_OUT_STRUCT() FriendGameInfo_t *pFriendGameInfo ) = 0; + // accesses old friends names - returns an empty string when their are no more items in the history + virtual const char *GetFriendPersonaNameHistory( CSteamID steamIDFriend, int iPersonaName ) = 0; + // friends steam level + virtual int GetFriendSteamLevel( CSteamID steamIDFriend ) = 0; + + // Returns nickname the current user has set for the specified player. Returns NULL if the no nickname has been set for that player. + // DEPRECATED: GetPersonaName follows the Steam nickname preferences, so apps shouldn't need to care about nicknames explicitly. + virtual const char *GetPlayerNickname( CSteamID steamIDPlayer ) = 0; + + // friend grouping (tag) apis + // returns the number of friends groups + virtual int GetFriendsGroupCount() = 0; + // returns the friends group ID for the given index (invalid indices return k_FriendsGroupID_Invalid) + virtual FriendsGroupID_t GetFriendsGroupIDByIndex( int iFG ) = 0; + // returns the name for the given friends group (NULL in the case of invalid friends group IDs) + virtual const char *GetFriendsGroupName( FriendsGroupID_t friendsGroupID ) = 0; + // returns the number of members in a given friends group + virtual int GetFriendsGroupMembersCount( FriendsGroupID_t friendsGroupID ) = 0; + // gets up to nMembersCount members of the given friends group, if fewer exist than requested those positions' SteamIDs will be invalid + virtual void GetFriendsGroupMembersList( FriendsGroupID_t friendsGroupID, STEAM_OUT_ARRAY_CALL(nMembersCount, GetFriendsGroupMembersCount, friendsGroupID ) CSteamID *pOutSteamIDMembers, int nMembersCount ) = 0; + + // returns true if the specified user meets any of the criteria specified in iFriendFlags + // iFriendFlags can be the union (binary or, |) of one or more k_EFriendFlags values + virtual bool HasFriend( CSteamID steamIDFriend, int iFriendFlags ) = 0; + + // clan (group) iteration and access functions + virtual int GetClanCount() = 0; + virtual CSteamID GetClanByIndex( int iClan ) = 0; + virtual const char *GetClanName( CSteamID steamIDClan ) = 0; + virtual const char *GetClanTag( CSteamID steamIDClan ) = 0; + // returns the most recent information we have about what's happening in a clan + virtual bool GetClanActivityCounts( CSteamID steamIDClan, int *pnOnline, int *pnInGame, int *pnChatting ) = 0; + // for clans a user is a member of, they will have reasonably up-to-date information, but for others you'll have to download the info to have the latest + virtual SteamAPICall_t DownloadClanActivityCounts( STEAM_ARRAY_COUNT(cClansToRequest) CSteamID *psteamIDClans, int cClansToRequest ) = 0; + + // iterators for getting users in a chat room, lobby, game server or clan + // note that large clans that cannot be iterated by the local user + // note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby + // steamIDSource can be the steamID of a group, game server, lobby or chat room + virtual int GetFriendCountFromSource( CSteamID steamIDSource ) = 0; + virtual CSteamID GetFriendFromSourceByIndex( CSteamID steamIDSource, int iFriend ) = 0; + + // returns true if the local user can see that steamIDUser is a member or in steamIDSource + virtual bool IsUserInSource( CSteamID steamIDUser, CSteamID steamIDSource ) = 0; + + // User is in a game pressing the talk button (will suppress the microphone for all voice comms from the Steam friends UI) + virtual void SetInGameVoiceSpeaking( CSteamID steamIDUser, bool bSpeaking ) = 0; + + // activates the game overlay, with an optional dialog to open + // valid options include "Friends", "Community", "Players", "Settings", "OfficialGameGroup", "Stats", "Achievements", + // "chatroomgroup/nnnn" + virtual void ActivateGameOverlay( const char *pchDialog ) = 0; + + // activates game overlay to a specific place + // valid options are + // "steamid" - opens the overlay web browser to the specified user or groups profile + // "chat" - opens a chat window to the specified user, or joins the group chat + // "jointrade" - opens a window to a Steam Trading session that was started with the ISteamEconomy/StartTrade Web API + // "stats" - opens the overlay web browser to the specified user's stats + // "achievements" - opens the overlay web browser to the specified user's achievements + // "friendadd" - opens the overlay in minimal mode prompting the user to add the target user as a friend + // "friendremove" - opens the overlay in minimal mode prompting the user to remove the target friend + // "friendrequestaccept" - opens the overlay in minimal mode prompting the user to accept an incoming friend invite + // "friendrequestignore" - opens the overlay in minimal mode prompting the user to ignore an incoming friend invite + virtual void ActivateGameOverlayToUser( const char *pchDialog, CSteamID steamID ) = 0; + + // activates game overlay web browser directly to the specified URL + // full address with protocol type is required, e.g. http://www.steamgames.com/ + virtual void ActivateGameOverlayToWebPage( const char *pchURL, EActivateGameOverlayToWebPageMode eMode = k_EActivateGameOverlayToWebPageMode_Default ) = 0; + + // activates game overlay to store page for app + virtual void ActivateGameOverlayToStore( AppId_t nAppID, EOverlayToStoreFlag eFlag ) = 0; + + // Mark a target user as 'played with'. This is a client-side only feature that requires that the calling user is + // in game + virtual void SetPlayedWith( CSteamID steamIDUserPlayedWith ) = 0; + + // activates game overlay to open the invite dialog. Invitations will be sent for the provided lobby. + virtual void ActivateGameOverlayInviteDialog( CSteamID steamIDLobby ) = 0; + + // gets the small (32x32) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + virtual int GetSmallFriendAvatar( CSteamID steamIDFriend ) = 0; + + // gets the medium (64x64) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + virtual int GetMediumFriendAvatar( CSteamID steamIDFriend ) = 0; + + // gets the large (184x184) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + // returns -1 if this image has yet to be loaded, in this case wait for a AvatarImageLoaded_t callback and then call this again + virtual int GetLargeFriendAvatar( CSteamID steamIDFriend ) = 0; + + // requests information about a user - persona name & avatar + // if bRequireNameOnly is set, then the avatar of a user isn't downloaded + // - it's a lot slower to download avatars and churns the local cache, so if you don't need avatars, don't request them + // if returns true, it means that data is being requested, and a PersonaStateChanged_t callback will be posted when it's retrieved + // if returns false, it means that we already have all the details about that user, and functions can be called immediately + virtual bool RequestUserInformation( CSteamID steamIDUser, bool bRequireNameOnly ) = 0; + + // requests information about a clan officer list + // when complete, data is returned in ClanOfficerListResponse_t call result + // this makes available the calls below + // you can only ask about clans that a user is a member of + // note that this won't download avatars automatically; if you get an officer, + // and no avatar image is available, call RequestUserInformation( steamID, false ) to download the avatar + STEAM_CALL_RESULT( ClanOfficerListResponse_t ) + virtual SteamAPICall_t RequestClanOfficerList( CSteamID steamIDClan ) = 0; + + // iteration of clan officers - can only be done when a RequestClanOfficerList() call has completed + + // returns the steamID of the clan owner + virtual CSteamID GetClanOwner( CSteamID steamIDClan ) = 0; + // returns the number of officers in a clan (including the owner) + virtual int GetClanOfficerCount( CSteamID steamIDClan ) = 0; + // returns the steamID of a clan officer, by index, of range [0,GetClanOfficerCount) + virtual CSteamID GetClanOfficerByIndex( CSteamID steamIDClan, int iOfficer ) = 0; + // if current user is chat restricted, he can't send or receive any text/voice chat messages. + // the user can't see custom avatars. But the user can be online and send/recv game invites. + // a chat restricted user can't add friends or join any groups. + virtual uint32 GetUserRestrictions() = 0; + + // Rich Presence data is automatically shared between friends who are in the same game + // Each user has a set of Key/Value pairs + // Note the following limits: k_cchMaxRichPresenceKeys, k_cchMaxRichPresenceKeyLength, k_cchMaxRichPresenceValueLength + // There are two magic keys: + // "status" - a UTF-8 string that will show up in the 'view game info' dialog in the Steam friends list + // "connect" - a UTF-8 string that contains the command-line for how a friend can connect to a game + // GetFriendRichPresence() returns an empty string "" if no value is set + // SetRichPresence() to a NULL or an empty string deletes the key + // You can iterate the current set of keys for a friend with GetFriendRichPresenceKeyCount() + // and GetFriendRichPresenceKeyByIndex() (typically only used for debugging) + virtual bool SetRichPresence( const char *pchKey, const char *pchValue ) = 0; + virtual void ClearRichPresence() = 0; + virtual const char *GetFriendRichPresence( CSteamID steamIDFriend, const char *pchKey ) = 0; + virtual int GetFriendRichPresenceKeyCount( CSteamID steamIDFriend ) = 0; + virtual const char *GetFriendRichPresenceKeyByIndex( CSteamID steamIDFriend, int iKey ) = 0; + // Requests rich presence for a specific user. + virtual void RequestFriendRichPresence( CSteamID steamIDFriend ) = 0; + + // Rich invite support. + // If the target accepts the invite, a GameRichPresenceJoinRequested_t callback is posted containing the connect string. + // (Or you can configure yout game so that it is passed on the command line instead. This is a deprecated path; ask us if you really need this.) + // Invites can only be sent to friends. + virtual bool InviteUserToGame( CSteamID steamIDFriend, const char *pchConnectString ) = 0; + + // recently-played-with friends iteration + // this iterates the entire list of users recently played with, across games + // GetFriendCoplayTime() returns as a unix time + virtual int GetCoplayFriendCount() = 0; + virtual CSteamID GetCoplayFriend( int iCoplayFriend ) = 0; + virtual int GetFriendCoplayTime( CSteamID steamIDFriend ) = 0; + virtual AppId_t GetFriendCoplayGame( CSteamID steamIDFriend ) = 0; + + // chat interface for games + // this allows in-game access to group (clan) chats from in the game + // the behavior is somewhat sophisticated, because the user may or may not be already in the group chat from outside the game or in the overlay + // use ActivateGameOverlayToUser( "chat", steamIDClan ) to open the in-game overlay version of the chat + STEAM_CALL_RESULT( JoinClanChatRoomCompletionResult_t ) + virtual SteamAPICall_t JoinClanChatRoom( CSteamID steamIDClan ) = 0; + virtual bool LeaveClanChatRoom( CSteamID steamIDClan ) = 0; + virtual int GetClanChatMemberCount( CSteamID steamIDClan ) = 0; + virtual CSteamID GetChatMemberByIndex( CSteamID steamIDClan, int iUser ) = 0; + virtual bool SendClanChatMessage( CSteamID steamIDClanChat, const char *pchText ) = 0; + virtual int GetClanChatMessage( CSteamID steamIDClanChat, int iMessage, void *prgchText, int cchTextMax, EChatEntryType *peChatEntryType, STEAM_OUT_STRUCT() CSteamID *psteamidChatter ) = 0; + virtual bool IsClanChatAdmin( CSteamID steamIDClanChat, CSteamID steamIDUser ) = 0; + + // interact with the Steam (game overlay / desktop) + virtual bool IsClanChatWindowOpenInSteam( CSteamID steamIDClanChat ) = 0; + virtual bool OpenClanChatWindowInSteam( CSteamID steamIDClanChat ) = 0; + virtual bool CloseClanChatWindowInSteam( CSteamID steamIDClanChat ) = 0; + + // peer-to-peer chat interception + // this is so you can show P2P chats inline in the game + virtual bool SetListenForFriendsMessages( bool bInterceptEnabled ) = 0; + virtual bool ReplyToFriendMessage( CSteamID steamIDFriend, const char *pchMsgToSend ) = 0; + virtual int GetFriendMessage( CSteamID steamIDFriend, int iMessageID, void *pvData, int cubData, EChatEntryType *peChatEntryType ) = 0; + + // following apis + STEAM_CALL_RESULT( FriendsGetFollowerCount_t ) + virtual SteamAPICall_t GetFollowerCount( CSteamID steamID ) = 0; + STEAM_CALL_RESULT( FriendsIsFollowing_t ) + virtual SteamAPICall_t IsFollowing( CSteamID steamID ) = 0; + STEAM_CALL_RESULT( FriendsEnumerateFollowingList_t ) + virtual SteamAPICall_t EnumerateFollowingList( uint32 unStartIndex ) = 0; + + virtual bool IsClanPublic( CSteamID steamIDClan ) = 0; + virtual bool IsClanOfficialGameGroup( CSteamID steamIDClan ) = 0; + + /// Return the number of chats (friends or chat rooms) with unread messages. + /// A "priority" message is one that would generate some sort of toast or + /// notification, and depends on user settings. + /// + /// You can register for UnreadChatMessagesChanged_t callbacks to know when this + /// has potentially changed. + virtual int GetNumChatsWithUnreadPriorityMessages() = 0; +}; + +#define STEAMFRIENDS_INTERFACE_VERSION "SteamFriends017" + +// Global interface accessor +inline ISteamFriends *SteamFriends(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamFriends *, SteamFriends, STEAMFRIENDS_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a friends' status changes +//----------------------------------------------------------------------------- +struct PersonaStateChange_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 4 }; + + uint64 m_ulSteamID; // steamID of the friend who changed + int m_nChangeFlags; // what's changed +}; + + +// used in PersonaStateChange_t::m_nChangeFlags to describe what's changed about a user +// these flags describe what the client has learned has changed recently, so on startup you'll see a name, avatar & relationship change for every friend +enum EPersonaChange +{ + k_EPersonaChangeName = 0x0001, + k_EPersonaChangeStatus = 0x0002, + k_EPersonaChangeComeOnline = 0x0004, + k_EPersonaChangeGoneOffline = 0x0008, + k_EPersonaChangeGamePlayed = 0x0010, + k_EPersonaChangeGameServer = 0x0020, + k_EPersonaChangeAvatar = 0x0040, + k_EPersonaChangeJoinedSource= 0x0080, + k_EPersonaChangeLeftSource = 0x0100, + k_EPersonaChangeRelationshipChanged = 0x0200, + k_EPersonaChangeNameFirstSet = 0x0400, + k_EPersonaChangeBroadcast = 0x0800, + k_EPersonaChangeNickname = 0x1000, + k_EPersonaChangeSteamLevel = 0x2000, + k_EPersonaChangeRichPresence = 0x4000, +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted when game overlay activates or deactivates +// the game can use this to be pause or resume single player games +//----------------------------------------------------------------------------- +struct GameOverlayActivated_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 31 }; + uint8 m_bActive; // true if it's just been activated, false otherwise +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a different game server from their friends list +// game client should attempt to connect to specified server when this is received +//----------------------------------------------------------------------------- +struct GameServerChangeRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 32 }; + char m_rgchServer[64]; // server address ("127.0.0.1:27015", "tf2.valvesoftware.com") + char m_rgchPassword[64]; // server password, if any +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a lobby from their friends list +// game client should attempt to connect to specified lobby when this is received +//----------------------------------------------------------------------------- +struct GameLobbyJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 33 }; + CSteamID m_steamIDLobby; + + // The friend they did the join via (will be invalid if not directly via a friend) + // + // On PS3, the friend will be invalid if this was triggered by a PSN invite via the XMB, but + // the account type will be console user so you can tell at least that this was from a PSN friend + // rather than a Steam friend. + CSteamID m_steamIDFriend; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when an avatar is loaded in from a previous GetLargeFriendAvatar() call +// if the image wasn't already available +//----------------------------------------------------------------------------- +struct AvatarImageLoaded_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 34 }; + CSteamID m_steamID; // steamid the avatar has been loaded for + int m_iImage; // the image index of the now loaded image + int m_iWide; // width of the loaded image + int m_iTall; // height of the loaded image +}; + + +//----------------------------------------------------------------------------- +// Purpose: marks the return of a request officer list call +//----------------------------------------------------------------------------- +struct ClanOfficerListResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 35 }; + CSteamID m_steamIDClan; + int m_cOfficers; + uint8 m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating updated data about friends rich presence information +//----------------------------------------------------------------------------- +struct FriendRichPresenceUpdate_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 36 }; + CSteamID m_steamIDFriend; // friend who's rich presence has changed + AppId_t m_nAppID; // the appID of the game (should always be the current game) +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a game from their friends list +// rich presence will have been set with the "connect" key which is set here +//----------------------------------------------------------------------------- +struct GameRichPresenceJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 37 }; + CSteamID m_steamIDFriend; // the friend they did the join via (will be invalid if not directly via a friend) + char m_rgchConnect[k_cchMaxRichPresenceValueLength]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received for a clan chat the game has joined +//----------------------------------------------------------------------------- +struct GameConnectedClanChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 38 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has joined a clan chat +//----------------------------------------------------------------------------- +struct GameConnectedChatJoin_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 39 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has left the chat we're in +//----------------------------------------------------------------------------- +struct GameConnectedChatLeave_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 40 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + bool m_bKicked; // true if admin kicked + bool m_bDropped; // true if Steam connection dropped +}; + + +//----------------------------------------------------------------------------- +// Purpose: a DownloadClanActivityCounts() call has finished +//----------------------------------------------------------------------------- +struct DownloadClanActivityCountsResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 41 }; + bool m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a JoinClanChatRoom() call has finished +//----------------------------------------------------------------------------- +struct JoinClanChatRoomCompletionResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 42 }; + CSteamID m_steamIDClanChat; + EChatRoomEnterResponse m_eChatRoomEnterResponse; +}; + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received from a user +//----------------------------------------------------------------------------- +struct GameConnectedFriendChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 43 }; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +struct FriendsGetFollowerCount_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 44 }; + EResult m_eResult; + CSteamID m_steamID; + int m_nCount; +}; + + +struct FriendsIsFollowing_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 45 }; + EResult m_eResult; + CSteamID m_steamID; + bool m_bIsFollowing; +}; + + +struct FriendsEnumerateFollowingList_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 46 }; + EResult m_eResult; + CSteamID m_rgSteamID[ k_cEnumerateFollowersMax ]; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; +}; + +//----------------------------------------------------------------------------- +// Purpose: reports the result of an attempt to change the user's persona name +//----------------------------------------------------------------------------- +struct SetPersonaNameResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 47 }; + + bool m_bSuccess; // true if name change succeeded completely. + bool m_bLocalSuccess; // true if name change was retained locally. (We might not have been able to communicate with Steam) + EResult m_result; // detailed result code +}; + +//----------------------------------------------------------------------------- +// Purpose: Invoked when the status of unread messages changes +//----------------------------------------------------------------------------- +struct UnreadChatMessagesChanged_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 48 }; +}; + +#pragma pack( pop ) + +#endif // ISTEAMFRIENDS_H diff --git a/public/steam/isteamgamecoordinator.h b/public/steam/isteamgamecoordinator.h new file mode 100644 index 0000000..89b740d --- /dev/null +++ b/public/steam/isteamgamecoordinator.h @@ -0,0 +1,74 @@ +//====== Copyright , Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to the game coordinator for this application +// +//============================================================================= + +#ifndef ISTEAMGAMECOORDINATOR +#define ISTEAMGAMECOORDINATOR +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + + +// list of possible return values from the ISteamGameCoordinator API +enum EGCResults +{ + k_EGCResultOK = 0, + k_EGCResultNoMessage = 1, // There is no message in the queue + k_EGCResultBufferTooSmall = 2, // The buffer is too small for the requested message + k_EGCResultNotLoggedOn = 3, // The client is not logged onto Steam + k_EGCResultInvalidMessage = 4, // Something was wrong with the message being sent with SendMessage +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for sending and receiving messages from the Game Coordinator +// for this application +//----------------------------------------------------------------------------- +class ISteamGameCoordinator +{ +public: + + // sends a message to the Game Coordinator + virtual EGCResults SendMessage( uint32 unMsgType, const void *pubData, uint32 cubData ) = 0; + + // returns true if there is a message waiting from the game coordinator + virtual bool IsMessageAvailable( uint32 *pcubMsgSize ) = 0; + + // fills the provided buffer with the first message in the queue and returns k_EGCResultOK or + // returns k_EGCResultNoMessage if there is no message waiting. pcubMsgSize is filled with the message size. + // If the provided buffer is not large enough to fit the entire message, k_EGCResultBufferTooSmall is returned + // and the message remains at the head of the queue. + virtual EGCResults RetrieveMessage( uint32 *punMsgType, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0; + +}; +#define STEAMGAMECOORDINATOR_INTERFACE_VERSION "SteamGameCoordinator001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +// callback notification - A new message is available for reading from the message queue +struct GCMessageAvailable_t +{ + enum { k_iCallback = k_iSteamGameCoordinatorCallbacks + 1 }; + uint32 m_nMessageSize; +}; + +// callback notification - A message failed to make it to the GC. It may be down temporarily +struct GCMessageFailed_t +{ + enum { k_iCallback = k_iSteamGameCoordinatorCallbacks + 2 }; +}; + +#pragma pack( pop ) + +#endif // ISTEAMGAMECOORDINATOR diff --git a/public/steam/isteamgameserver.h b/public/steam/isteamgameserver.h new file mode 100644 index 0000000..6a0aada --- /dev/null +++ b/public/steam/isteamgameserver.h @@ -0,0 +1,391 @@ +//====== Copyright (c) 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam for game servers +// +//============================================================================= + +#ifndef ISTEAMGAMESERVER_H +#define ISTEAMGAMESERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +#define MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE ((uint16)-1) + +//----------------------------------------------------------------------------- +// Purpose: Functions for authenticating users via Steam to play on a game server +//----------------------------------------------------------------------------- +class ISteamGameServer +{ +public: + +// +// Basic server data. These properties, if set, must be set before before calling LogOn. They +// may not be changed after logged in. +// + + /// This is called by SteamGameServer_Init, and you will usually not need to call it directly + virtual bool InitGameServer( uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString ) = 0; + + /// Game product identifier. This is currently used by the master server for version checking purposes. + /// It's a required field, but will eventually will go away, and the AppID will be used for this purpose. + virtual void SetProduct( const char *pszProduct ) = 0; + + /// Description of the game. This is a required field and is displayed in the steam server browser....for now. + /// This is a required field, but it will go away eventually, as the data should be determined from the AppID. + virtual void SetGameDescription( const char *pszGameDescription ) = 0; + + /// If your game is a "mod," pass the string that identifies it. The default is an empty string, meaning + /// this application is the original game, not a mod. + /// + /// @see k_cbMaxGameServerGameDir + virtual void SetModDir( const char *pszModDir ) = 0; + + /// Is this is a dedicated server? The default value is false. + virtual void SetDedicatedServer( bool bDedicated ) = 0; + +// +// Login +// + + /// Begin process to login to a persistent game server account + /// + /// You need to register for callbacks to determine the result of this operation. + /// @see SteamServersConnected_t + /// @see SteamServerConnectFailure_t + /// @see SteamServersDisconnected_t + virtual void LogOn( const char *pszToken ) = 0; + + /// Login to a generic, anonymous account. + /// + /// Note: in previous versions of the SDK, this was automatically called within SteamGameServer_Init, + /// but this is no longer the case. + virtual void LogOnAnonymous() = 0; + + /// Begin process of logging game server out of steam + virtual void LogOff() = 0; + + // status functions + virtual bool BLoggedOn() = 0; + virtual bool BSecure() = 0; + virtual CSteamID GetSteamID() = 0; + + /// Returns true if the master server has requested a restart. + /// Only returns true once per request. + virtual bool WasRestartRequested() = 0; + +// +// Server state. These properties may be changed at any time. +// + + /// Max player count that will be reported to server browser and client queries + virtual void SetMaxPlayerCount( int cPlayersMax ) = 0; + + /// Number of bots. Default value is zero + virtual void SetBotPlayerCount( int cBotplayers ) = 0; + + /// Set the name of server as it will appear in the server browser + /// + /// @see k_cbMaxGameServerName + virtual void SetServerName( const char *pszServerName ) = 0; + + /// Set name of map to report in the server browser + /// + /// @see k_cbMaxGameServerName + virtual void SetMapName( const char *pszMapName ) = 0; + + /// Let people know if your server will require a password + virtual void SetPasswordProtected( bool bPasswordProtected ) = 0; + + /// Spectator server. The default value is zero, meaning the service + /// is not used. + virtual void SetSpectatorPort( uint16 unSpectatorPort ) = 0; + + /// Name of the spectator server. (Only used if spectator port is nonzero.) + /// + /// @see k_cbMaxGameServerMapName + virtual void SetSpectatorServerName( const char *pszSpectatorServerName ) = 0; + + /// Call this to clear the whole list of key/values that are sent in rules queries. + virtual void ClearAllKeyValues() = 0; + + /// Call this to add/update a key/value pair. + virtual void SetKeyValue( const char *pKey, const char *pValue ) = 0; + + /// Sets a string defining the "gametags" for this server, this is optional, but if it is set + /// it allows users to filter in the matchmaking/server-browser interfaces based on the value + /// + /// @see k_cbMaxGameServerTags + virtual void SetGameTags( const char *pchGameTags ) = 0; + + /// Sets a string defining the "gamedata" for this server, this is optional, but if it is set + /// it allows users to filter in the matchmaking/server-browser interfaces based on the value + /// don't set this unless it actually changes, its only uploaded to the master once (when + /// acknowledged) + /// + /// @see k_cbMaxGameServerGameData + virtual void SetGameData( const char *pchGameData ) = 0; + + /// Region identifier. This is an optional field, the default value is empty, meaning the "world" region + virtual void SetRegion( const char *pszRegion ) = 0; + +// +// Player list management / authentication +// + + // Handles receiving a new connection from a Steam user. This call will ask the Steam + // servers to validate the users identity, app ownership, and VAC status. If the Steam servers + // are off-line, then it will validate the cached ticket itself which will validate app ownership + // and identity. The AuthBlob here should be acquired on the game client using SteamUser()->InitiateGameConnection() + // and must then be sent up to the game server for authentication. + // + // Return Value: returns true if the users ticket passes basic checks. pSteamIDUser will contain the Steam ID of this user. pSteamIDUser must NOT be NULL + // If the call succeeds then you should expect a GSClientApprove_t or GSClientDeny_t callback which will tell you whether authentication + // for the user has succeeded or failed (the steamid in the callback will match the one returned by this call) + virtual bool SendUserConnectAndAuthenticate( uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser ) = 0; + + // Creates a fake user (ie, a bot) which will be listed as playing on the server, but skips validation. + // + // Return Value: Returns a SteamID for the user to be tracked with, you should call HandleUserDisconnect() + // when this user leaves the server just like you would for a real user. + virtual CSteamID CreateUnauthenticatedUserConnection() = 0; + + // Should be called whenever a user leaves our game server, this lets Steam internally + // track which users are currently on which servers for the purposes of preventing a single + // account being logged into multiple servers, showing who is currently on a server, etc. + virtual void SendUserDisconnect( CSteamID steamIDUser ) = 0; + + // Update the data to be displayed in the server browser and matchmaking interfaces for a user + // currently connected to the server. For regular users you must call this after you receive a + // GSUserValidationSuccess callback. + // + // Return Value: true if successful, false if failure (ie, steamIDUser wasn't for an active player) + virtual bool BUpdateUserData( CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore ) = 0; + + // New auth system APIs - do not mix with the old auth system APIs. + // ---------------------------------------------------------------- + + // Retrieve ticket to be sent to the entity who wishes to authenticate you ( using BeginAuthSession API ). + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Authenticate ticket ( from GetAuthSessionTicket ) from entity steamID to be sure it is valid and isnt reused + // Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // After receiving a user's authentication data, and passing it to SendUserConnectAndAuthenticate, use this function + // to determine if the user owns downloadable content specified by the provided AppID. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // Ask if a user in in the specified group, results returns async by GSUserGroupStatus_t + // returns false if we're not connected to the steam servers and thus cannot ask + virtual bool RequestUserGroupStatus( CSteamID steamIDUser, CSteamID steamIDGroup ) = 0; + + + // these two functions s are deprecated, and will not return results + // they will be removed in a future version of the SDK + virtual void GetGameplayStats( ) = 0; + STEAM_CALL_RESULT( GSReputation_t ) + virtual SteamAPICall_t GetServerReputation() = 0; + + // Returns the public IP of the server according to Steam, useful when the server is + // behind NAT and you want to advertise its IP in a lobby for other clients to directly + // connect to + virtual uint32 GetPublicIP() = 0; + +// These are in GameSocketShare mode, where instead of ISteamGameServer creating its own +// socket to talk to the master server on, it lets the game use its socket to forward messages +// back and forth. This prevents us from requiring server ops to open up yet another port +// in their firewalls. +// +// the IP address and port should be in host order, i.e 127.0.0.1 == 0x7f000001 + + // These are used when you've elected to multiplex the game server's UDP socket + // rather than having the master server updater use its own sockets. + // + // Source games use this to simplify the job of the server admins, so they + // don't have to open up more ports on their firewalls. + + // Call this when a packet that starts with 0xFFFFFFFF comes in. That means + // it's for us. + virtual bool HandleIncomingPacket( const void *pData, int cbData, uint32 srcIP, uint16 srcPort ) = 0; + + // AFTER calling HandleIncomingPacket for any packets that came in that frame, call this. + // This gets a packet that the master server updater needs to send out on UDP. + // It returns the length of the packet it wants to send, or 0 if there are no more packets to send. + // Call this each frame until it returns 0. + virtual int GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort ) = 0; + +// +// Control heartbeats / advertisement with master server +// + + // Call this as often as you like to tell the master server updater whether or not + // you want it to be active (default: off). + virtual void EnableHeartbeats( bool bActive ) = 0; + + // You usually don't need to modify this. + // Pass -1 to use the default value for iHeartbeatInterval. + // Some mods change this. + virtual void SetHeartbeatInterval( int iHeartbeatInterval ) = 0; + + // Force a heartbeat to steam at the next opportunity + virtual void ForceHeartbeat() = 0; + + // associate this game server with this clan for the purposes of computing player compat + STEAM_CALL_RESULT( AssociateWithClanResult_t ) + virtual SteamAPICall_t AssociateWithClan( CSteamID steamIDClan ) = 0; + + // ask if any of the current players dont want to play with this new player - or vice versa + STEAM_CALL_RESULT( ComputeNewPlayerCompatibilityResult_t ) + virtual SteamAPICall_t ComputeNewPlayerCompatibility( CSteamID steamIDNewPlayer ) = 0; + +}; + +#define STEAMGAMESERVER_INTERFACE_VERSION "SteamGameServer012" + +// Global accessor +inline ISteamGameServer *SteamGameServer(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamGameServer *, SteamGameServer, STEAMGAMESERVER_INTERFACE_VERSION ); + +// game server flags +const uint32 k_unServerFlagNone = 0x00; +const uint32 k_unServerFlagActive = 0x01; // server has users playing +const uint32 k_unServerFlagSecure = 0x02; // server wants to be secure +const uint32 k_unServerFlagDedicated = 0x04; // server is dedicated +const uint32 k_unServerFlagLinux = 0x08; // linux build +const uint32 k_unServerFlagPassworded = 0x10; // password protected +const uint32 k_unServerFlagPrivate = 0x20; // server shouldn't list on master server and + // won't enforce authentication of users that connect to the server. + // Useful when you run a server where the clients may not + // be connected to the internet but you want them to play (i.e LANs) + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +// client has been approved to connect to this game server +struct GSClientApprove_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 1 }; + CSteamID m_SteamID; // SteamID of approved player + CSteamID m_OwnerSteamID; // SteamID of original owner for game license +}; + + +// client has been denied to connection to this game server +struct GSClientDeny_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 2 }; + CSteamID m_SteamID; + EDenyReason m_eDenyReason; + char m_rgchOptionalText[128]; +}; + + +// request the game server should kick the user +struct GSClientKick_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 3 }; + CSteamID m_SteamID; + EDenyReason m_eDenyReason; +}; + +// NOTE: callback values 4 and 5 are skipped because they are used for old deprecated callbacks, +// do not reuse them here. + + +// client achievement info +struct GSClientAchievementStatus_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 6 }; + uint64 m_SteamID; + char m_pchAchievement[128]; + bool m_bUnlocked; +}; + +// received when the game server requests to be displayed as secure (VAC protected) +// m_bSecure is true if the game server should display itself as secure to users, false otherwise +struct GSPolicyResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 15 }; + uint8 m_bSecure; +}; + +// GS gameplay stats info +struct GSGameplayStats_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 7 }; + EResult m_eResult; // Result of the call + int32 m_nRank; // Overall rank of the server (0-based) + uint32 m_unTotalConnects; // Total number of clients who have ever connected to the server + uint32 m_unTotalMinutesPlayed; // Total number of minutes ever played on the server +}; + +// send as a reply to RequestUserGroupStatus() +struct GSClientGroupStatus_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 8 }; + CSteamID m_SteamIDUser; + CSteamID m_SteamIDGroup; + bool m_bMember; + bool m_bOfficer; +}; + +// Sent as a reply to GetServerReputation() +struct GSReputation_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 9 }; + EResult m_eResult; // Result of the call; + uint32 m_unReputationScore; // The reputation score for the game server + bool m_bBanned; // True if the server is banned from the Steam + // master servers + + // The following members are only filled out if m_bBanned is true. They will all + // be set to zero otherwise. Master server bans are by IP so it is possible to be + // banned even when the score is good high if there is a bad server on another port. + // This information can be used to determine which server is bad. + + uint32 m_unBannedIP; // The IP of the banned server + uint16 m_usBannedPort; // The port of the banned server + uint64 m_ulBannedGameID; // The game ID the banned server is serving + uint32 m_unBanExpires; // Time the ban expires, expressed in the Unix epoch (seconds since 1/1/1970) +}; + +// Sent as a reply to AssociateWithClan() +struct AssociateWithClanResult_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 10 }; + EResult m_eResult; // Result of the call; +}; + +// Sent as a reply to ComputeNewPlayerCompatibility() +struct ComputeNewPlayerCompatibilityResult_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 11 }; + EResult m_eResult; // Result of the call; + int m_cPlayersThatDontLikeCandidate; + int m_cPlayersThatCandidateDoesntLike; + int m_cClanPlayersThatDontLikeCandidate; + CSteamID m_SteamIDCandidate; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMGAMESERVER_H diff --git a/public/steam/isteamgameserverstats.h b/public/steam/isteamgameserverstats.h new file mode 100644 index 0000000..aacac4b --- /dev/null +++ b/public/steam/isteamgameserverstats.h @@ -0,0 +1,105 @@ +//====== Copyright Valve Corporation, All rights reserved. ======= +// +// Purpose: interface for game servers to steam stats and achievements +// +//============================================================================= + +#ifndef ISTEAMGAMESERVERSTATS_H +#define ISTEAMGAMESERVERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +//----------------------------------------------------------------------------- +// Purpose: Functions for authenticating users via Steam to play on a game server +//----------------------------------------------------------------------------- +class ISteamGameServerStats +{ +public: + // downloads stats for the user + // returns a GSStatsReceived_t callback when completed + // if the user has no stats, GSStatsReceived_t.m_eResult will be set to k_EResultFail + // these stats will only be auto-updated for clients playing on the server. For other + // users you'll need to call RequestUserStats() again to refresh any data + STEAM_CALL_RESULT( GSStatsReceived_t ) + virtual SteamAPICall_t RequestUserStats( CSteamID steamIDUser ) = 0; + + // requests stat information for a user, usable after a successful call to RequestUserStats() + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData ) = 0; + virtual bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved ) = 0; + + // Set / update stats and achievements. + // Note: These updates will work only on stats game servers are allowed to edit and only for + // game servers that have been declared as officially controlled by the game creators. + // Set the IP range of your official servers on the Steamworks page + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, int32 nData ) = 0; + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, float fData ) = 0; + virtual bool UpdateUserAvgRateStat( CSteamID steamIDUser, const char *pchName, float flCountThisSession, double dSessionLength ) = 0; + + virtual bool SetUserAchievement( CSteamID steamIDUser, const char *pchName ) = 0; + virtual bool ClearUserAchievement( CSteamID steamIDUser, const char *pchName ) = 0; + + // Store the current data on the server, will get a GSStatsStored_t callback when set. + // + // If the callback has a result of k_EResultInvalidParam, one or more stats + // uploaded has been rejected, either because they broke constraints + // or were out of date. In this case the server sends back updated values. + // The stats should be re-iterated to keep in sync. + STEAM_CALL_RESULT( GSStatsStored_t ) + virtual SteamAPICall_t StoreUserStats( CSteamID steamIDUser ) = 0; +}; +#define STEAMGAMESERVERSTATS_INTERFACE_VERSION "SteamGameServerStats001" + +// Global accessor +inline ISteamGameServerStats *SteamGameServerStats(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamGameServerStats *, SteamGameServerStats, STEAMGAMESERVERSTATS_INTERFACE_VERSION ); + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when the latests stats and achievements have been received +// from the server +//----------------------------------------------------------------------------- +struct GSStatsReceived_t +{ + enum { k_iCallback = k_iSteamGameServerStatsCallbacks }; + EResult m_eResult; // Success / error fetching the stats + CSteamID m_steamIDUser; // The user for whom the stats are retrieved for +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the user stats for a game +//----------------------------------------------------------------------------- +struct GSStatsStored_t +{ + enum { k_iCallback = k_iSteamGameServerStatsCallbacks + 1 }; + EResult m_eResult; // success / error + CSteamID m_steamIDUser; // The user for whom the stats were stored +}; + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that a user's stats have been unloaded. +// Call RequestUserStats again to access stats for this user +//----------------------------------------------------------------------------- +struct GSStatsUnloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 8 }; + CSteamID m_steamIDUser; // User whose stats have been unloaded +}; + +#pragma pack( pop ) + + +#endif // ISTEAMGAMESERVERSTATS_H diff --git a/public/steam/isteamhtmlsurface.h b/public/steam/isteamhtmlsurface.h new file mode 100644 index 0000000..086a842 --- /dev/null +++ b/public/steam/isteamhtmlsurface.h @@ -0,0 +1,480 @@ +//====== Copyright 1996-2013, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to display html pages in a texture +// +//============================================================================= + +#ifndef ISTEAMHTMLSURFACE_H +#define ISTEAMHTMLSURFACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +typedef uint32 HHTMLBrowser; +const uint32 INVALID_HTMLBROWSER = 0; + +//----------------------------------------------------------------------------- +// Purpose: Functions for displaying HTML pages and interacting with them +//----------------------------------------------------------------------------- +class ISteamHTMLSurface +{ +public: + virtual ~ISteamHTMLSurface() {} + + // Must call init and shutdown when starting/ending use of the interface + virtual bool Init() = 0; + virtual bool Shutdown() = 0; + + // Create a browser object for display of a html page, when creation is complete the call handle + // will return a HTML_BrowserReady_t callback for the HHTMLBrowser of your new browser. + // The user agent string is a substring to be added to the general user agent string so you can + // identify your client on web servers. + // The userCSS string lets you apply a CSS style sheet to every displayed page, leave null if + // you do not require this functionality. + // + // YOU MUST HAVE IMPLEMENTED HANDLERS FOR HTML_BrowserReady_t, HTML_StartRequest_t, + // HTML_JSAlert_t, HTML_JSConfirm_t, and HTML_FileOpenDialog_t! See the CALLBACKS + // section of this interface (AllowStartRequest, etc) for more details. If you do + // not implement these callback handlers, the browser may appear to hang instead of + // navigating to new pages or triggering javascript popups. + // + STEAM_CALL_RESULT( HTML_BrowserReady_t ) + virtual SteamAPICall_t CreateBrowser( const char *pchUserAgent, const char *pchUserCSS ) = 0; + + // Call this when you are done with a html surface, this lets us free the resources being used by it + virtual void RemoveBrowser( HHTMLBrowser unBrowserHandle ) = 0; + + // Navigate to this URL, results in a HTML_StartRequest_t as the request commences + virtual void LoadURL( HHTMLBrowser unBrowserHandle, const char *pchURL, const char *pchPostData ) = 0; + + // Tells the surface the size in pixels to display the surface + virtual void SetSize( HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight ) = 0; + + // Stop the load of the current html page + virtual void StopLoad( HHTMLBrowser unBrowserHandle ) = 0; + // Reload (most likely from local cache) the current page + virtual void Reload( HHTMLBrowser unBrowserHandle ) = 0; + // navigate back in the page history + virtual void GoBack( HHTMLBrowser unBrowserHandle ) = 0; + // navigate forward in the page history + virtual void GoForward( HHTMLBrowser unBrowserHandle ) = 0; + + // add this header to any url requests from this browser + virtual void AddHeader( HHTMLBrowser unBrowserHandle, const char *pchKey, const char *pchValue ) = 0; + // run this javascript script in the currently loaded page + virtual void ExecuteJavascript( HHTMLBrowser unBrowserHandle, const char *pchScript ) = 0; + + enum EHTMLMouseButton + { + eHTMLMouseButton_Left = 0, + eHTMLMouseButton_Right = 1, + eHTMLMouseButton_Middle = 2, + }; + + // Mouse click and mouse movement commands + virtual void MouseUp( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton ) = 0; + virtual void MouseDown( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton ) = 0; + virtual void MouseDoubleClick( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton ) = 0; + // x and y are relative to the HTML bounds + virtual void MouseMove( HHTMLBrowser unBrowserHandle, int x, int y ) = 0; + // nDelta is pixels of scroll + virtual void MouseWheel( HHTMLBrowser unBrowserHandle, int32 nDelta ) = 0; + + enum EMouseCursor + { + dc_user = 0, + dc_none, + dc_arrow, + dc_ibeam, + dc_hourglass, + dc_waitarrow, + dc_crosshair, + dc_up, + dc_sizenw, + dc_sizese, + dc_sizene, + dc_sizesw, + dc_sizew, + dc_sizee, + dc_sizen, + dc_sizes, + dc_sizewe, + dc_sizens, + dc_sizeall, + dc_no, + dc_hand, + dc_blank, // don't show any custom cursor, just use your default + dc_middle_pan, + dc_north_pan, + dc_north_east_pan, + dc_east_pan, + dc_south_east_pan, + dc_south_pan, + dc_south_west_pan, + dc_west_pan, + dc_north_west_pan, + dc_alias, + dc_cell, + dc_colresize, + dc_copycur, + dc_verticaltext, + dc_rowresize, + dc_zoomin, + dc_zoomout, + dc_help, + dc_custom, + + dc_last, // custom cursors start from this value and up + }; + + enum EHTMLKeyModifiers + { + k_eHTMLKeyModifier_None = 0, + k_eHTMLKeyModifier_AltDown = 1 << 0, + k_eHTMLKeyModifier_CtrlDown = 1 << 1, + k_eHTMLKeyModifier_ShiftDown = 1 << 2, + }; + + // keyboard interactions, native keycode is the virtual key code value from your OS, system key flags the key to not + // be sent as a typed character as well as a key down + virtual void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers, bool bIsSystemKey = false ) = 0; + virtual void KeyUp( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers ) = 0; + // cUnicodeChar is the unicode character point for this keypress (and potentially multiple chars per press) + virtual void KeyChar( HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, EHTMLKeyModifiers eHTMLKeyModifiers ) = 0; + + // programmatically scroll this many pixels on the page + virtual void SetHorizontalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll ) = 0; + virtual void SetVerticalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll ) = 0; + + // tell the html control if it has key focus currently, controls showing the I-beam cursor in text controls amongst other things + virtual void SetKeyFocus( HHTMLBrowser unBrowserHandle, bool bHasKeyFocus ) = 0; + + // open the current pages html code in the local editor of choice, used for debugging + virtual void ViewSource( HHTMLBrowser unBrowserHandle ) = 0; + // copy the currently selected text on the html page to the local clipboard + virtual void CopyToClipboard( HHTMLBrowser unBrowserHandle ) = 0; + // paste from the local clipboard to the current html page + virtual void PasteFromClipboard( HHTMLBrowser unBrowserHandle ) = 0; + + // find this string in the browser, if bCurrentlyInFind is true then instead cycle to the next matching element + virtual void Find( HHTMLBrowser unBrowserHandle, const char *pchSearchStr, bool bCurrentlyInFind, bool bReverse ) = 0; + // cancel a currently running find + virtual void StopFind( HHTMLBrowser unBrowserHandle ) = 0; + + // return details about the link at position x,y on the current page + virtual void GetLinkAtPosition( HHTMLBrowser unBrowserHandle, int x, int y ) = 0; + + // set a webcookie for the hostname in question + virtual void SetCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath = "/", RTime32 nExpires = 0, bool bSecure = false, bool bHTTPOnly = false ) = 0; + + // Zoom the current page by flZoom ( from 0.0 to 2.0, so to zoom to 120% use 1.2 ), zooming around point X,Y in the page (use 0,0 if you don't care) + virtual void SetPageScaleFactor( HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY ) = 0; + + // Enable/disable low-resource background mode, where javascript and repaint timers are throttled, resources are + // more aggressively purged from memory, and audio/video elements are paused. When background mode is enabled, + // all HTML5 video and audio objects will execute ".pause()" and gain the property "._steam_background_paused = 1". + // When background mode is disabled, any video or audio objects with that property will resume with ".play()". + virtual void SetBackgroundMode( HHTMLBrowser unBrowserHandle, bool bBackgroundMode ) = 0; + + // Scale the output display space by this factor, this is useful when displaying content on high dpi devices. + // Specifies the ratio between physical and logical pixels. + virtual void SetDPIScalingFactor( HHTMLBrowser unBrowserHandle, float flDPIScaling ) = 0; + + // Open HTML/JS developer tools + virtual void OpenDeveloperTools( HHTMLBrowser unBrowserHandle ) = 0; + + // CALLBACKS + // + // These set of functions are used as responses to callback requests + // + + // You MUST call this in response to a HTML_StartRequest_t callback + // Set bAllowed to true to allow this navigation, false to cancel it and stay + // on the current page. You can use this feature to limit the valid pages + // allowed in your HTML surface. + virtual void AllowStartRequest( HHTMLBrowser unBrowserHandle, bool bAllowed ) = 0; + + // You MUST call this in response to a HTML_JSAlert_t or HTML_JSConfirm_t callback + // Set bResult to true for the OK option of a confirm, use false otherwise + virtual void JSDialogResponse( HHTMLBrowser unBrowserHandle, bool bResult ) = 0; + + // You MUST call this in response to a HTML_FileOpenDialog_t callback + STEAM_IGNOREATTR() + virtual void FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelectedFiles ) = 0; +}; + +#define STEAMHTMLSURFACE_INTERFACE_VERSION "STEAMHTMLSURFACE_INTERFACE_VERSION_005" + +// Global interface accessor +inline ISteamHTMLSurface *SteamHTMLSurface(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamHTMLSurface *, SteamHTMLSurface, STEAMHTMLSURFACE_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +//----------------------------------------------------------------------------- +// Purpose: The browser is ready for use +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_BrowserReady_t, k_iSteamHTMLSurfaceCallbacks + 1 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // this browser is now fully created and ready to navigate to pages +STEAM_CALLBACK_END(1) + + +//----------------------------------------------------------------------------- +// Purpose: the browser has a pending paint +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN(HTML_NeedsPaint_t, k_iSteamHTMLSurfaceCallbacks + 2) +STEAM_CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the browser that needs the paint +STEAM_CALLBACK_MEMBER(1, const char *, pBGRA ) // a pointer to the B8G8R8A8 data for this surface, valid until SteamAPI_RunCallbacks is next called +STEAM_CALLBACK_MEMBER(2, uint32, unWide) // the total width of the pBGRA texture +STEAM_CALLBACK_MEMBER(3, uint32, unTall) // the total height of the pBGRA texture +STEAM_CALLBACK_MEMBER(4, uint32, unUpdateX) // the offset in X for the damage rect for this update +STEAM_CALLBACK_MEMBER(5, uint32, unUpdateY) // the offset in Y for the damage rect for this update +STEAM_CALLBACK_MEMBER(6, uint32, unUpdateWide) // the width of the damage rect for this update +STEAM_CALLBACK_MEMBER(7, uint32, unUpdateTall) // the height of the damage rect for this update +STEAM_CALLBACK_MEMBER(8, uint32, unScrollX) // the page scroll the browser was at when this texture was rendered +STEAM_CALLBACK_MEMBER(9, uint32, unScrollY) // the page scroll the browser was at when this texture was rendered +STEAM_CALLBACK_MEMBER(10, float, flPageScale) // the page scale factor on this page when rendered +STEAM_CALLBACK_MEMBER(11, uint32, unPageSerial) // incremented on each new page load, you can use this to reject draws while navigating to new pages +STEAM_CALLBACK_END(12) + + +//----------------------------------------------------------------------------- +// Purpose: The browser wanted to navigate to a new page +// NOTE - you MUST call AllowStartRequest in response to this callback +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN(HTML_StartRequest_t, k_iSteamHTMLSurfaceCallbacks + 3) +STEAM_CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the handle of the surface navigating +STEAM_CALLBACK_MEMBER(1, const char *, pchURL) // the url they wish to navigate to +STEAM_CALLBACK_MEMBER(2, const char *, pchTarget) // the html link target type (i.e _blank, _self, _parent, _top ) +STEAM_CALLBACK_MEMBER(3, const char *, pchPostData ) // any posted data for the request +STEAM_CALLBACK_MEMBER(4, bool, bIsRedirect) // true if this was a http/html redirect from the last load request +STEAM_CALLBACK_END(5) + + +//----------------------------------------------------------------------------- +// Purpose: The browser has been requested to close due to user interaction (usually from a javascript window.close() call) +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN(HTML_CloseBrowser_t, k_iSteamHTMLSurfaceCallbacks + 4) +STEAM_CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the handle of the surface +STEAM_CALLBACK_END(1) + + +//----------------------------------------------------------------------------- +// Purpose: the browser is navigating to a new url +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_URLChanged_t, k_iSteamHTMLSurfaceCallbacks + 5 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface navigating +STEAM_CALLBACK_MEMBER( 1, const char *, pchURL ) // the url they wish to navigate to +STEAM_CALLBACK_MEMBER( 2, const char *, pchPostData ) // any posted data for the request +STEAM_CALLBACK_MEMBER( 3, bool, bIsRedirect ) // true if this was a http/html redirect from the last load request +STEAM_CALLBACK_MEMBER( 4, const char *, pchPageTitle ) // the title of the page +STEAM_CALLBACK_MEMBER( 5, bool, bNewNavigation ) // true if this was from a fresh tab and not a click on an existing page +STEAM_CALLBACK_END(6) + + +//----------------------------------------------------------------------------- +// Purpose: A page is finished loading +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_FinishedRequest_t, k_iSteamHTMLSurfaceCallbacks + 6 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchURL ) // +STEAM_CALLBACK_MEMBER( 2, const char *, pchPageTitle ) // +STEAM_CALLBACK_END(3) + + +//----------------------------------------------------------------------------- +// Purpose: a request to load this url in a new tab +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_OpenLinkInNewTab_t, k_iSteamHTMLSurfaceCallbacks + 7 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchURL ) // +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: the page has a new title now +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_ChangedTitle_t, k_iSteamHTMLSurfaceCallbacks + 8 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchTitle ) // +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: results from a search +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_SearchResults_t, k_iSteamHTMLSurfaceCallbacks + 9 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, uint32, unResults ) // +STEAM_CALLBACK_MEMBER( 2, uint32, unCurrentMatch ) // +STEAM_CALLBACK_END(3) + + +//----------------------------------------------------------------------------- +// Purpose: page history status changed on the ability to go backwards and forward +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_CanGoBackAndForward_t, k_iSteamHTMLSurfaceCallbacks + 10 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, bool, bCanGoBack ) // +STEAM_CALLBACK_MEMBER( 2, bool, bCanGoForward ) // +STEAM_CALLBACK_END(3) + + +//----------------------------------------------------------------------------- +// Purpose: details on the visibility and size of the horizontal scrollbar +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_HorizontalScroll_t, k_iSteamHTMLSurfaceCallbacks + 11 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, uint32, unScrollMax ) // +STEAM_CALLBACK_MEMBER( 2, uint32, unScrollCurrent ) // +STEAM_CALLBACK_MEMBER( 3, float, flPageScale ) // +STEAM_CALLBACK_MEMBER( 4, bool , bVisible ) // +STEAM_CALLBACK_MEMBER( 5, uint32, unPageSize ) // +STEAM_CALLBACK_END(6) + + +//----------------------------------------------------------------------------- +// Purpose: details on the visibility and size of the vertical scrollbar +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_VerticalScroll_t, k_iSteamHTMLSurfaceCallbacks + 12 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, uint32, unScrollMax ) // +STEAM_CALLBACK_MEMBER( 2, uint32, unScrollCurrent ) // +STEAM_CALLBACK_MEMBER( 3, float, flPageScale ) // +STEAM_CALLBACK_MEMBER( 4, bool, bVisible ) // +STEAM_CALLBACK_MEMBER( 5, uint32, unPageSize ) // +STEAM_CALLBACK_END(6) + + +//----------------------------------------------------------------------------- +// Purpose: response to GetLinkAtPosition call +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_LinkAtPosition_t, k_iSteamHTMLSurfaceCallbacks + 13 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, uint32, x ) // NOTE - Not currently set +STEAM_CALLBACK_MEMBER( 2, uint32, y ) // NOTE - Not currently set +STEAM_CALLBACK_MEMBER( 3, const char *, pchURL ) // +STEAM_CALLBACK_MEMBER( 4, bool, bInput ) // +STEAM_CALLBACK_MEMBER( 5, bool, bLiveLink ) // +STEAM_CALLBACK_END(6) + + + +//----------------------------------------------------------------------------- +// Purpose: show a Javascript alert dialog, call JSDialogResponse +// when the user dismisses this dialog (or right away to ignore it) +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_JSAlert_t, k_iSteamHTMLSurfaceCallbacks + 14 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchMessage ) // +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: show a Javascript confirmation dialog, call JSDialogResponse +// when the user dismisses this dialog (or right away to ignore it) +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_JSConfirm_t, k_iSteamHTMLSurfaceCallbacks + 15 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchMessage ) // +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: when received show a file open dialog +// then call FileLoadDialogResponse with the file(s) the user selected. +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_FileOpenDialog_t, k_iSteamHTMLSurfaceCallbacks + 16 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchTitle ) // +STEAM_CALLBACK_MEMBER( 2, const char *, pchInitialFile ) // +STEAM_CALLBACK_END(3) + + +//----------------------------------------------------------------------------- +// Purpose: a new html window is being created. +// +// IMPORTANT NOTE: at this time, the API does not allow you to acknowledge or +// render the contents of this new window, so the new window is always destroyed +// immediately. The URL and other parameters of the new window are passed here +// to give your application the opportunity to call CreateBrowser and set up +// a new browser in response to the attempted popup, if you wish to do so. +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_NewWindow_t, k_iSteamHTMLSurfaceCallbacks + 21 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the current surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchURL ) // the page to load +STEAM_CALLBACK_MEMBER( 2, uint32, unX ) // the x pos into the page to display the popup +STEAM_CALLBACK_MEMBER( 3, uint32, unY ) // the y pos into the page to display the popup +STEAM_CALLBACK_MEMBER( 4, uint32, unWide ) // the total width of the pBGRA texture +STEAM_CALLBACK_MEMBER( 5, uint32, unTall ) // the total height of the pBGRA texture +STEAM_CALLBACK_MEMBER( 6, HHTMLBrowser, unNewWindow_BrowserHandle_IGNORE ) +STEAM_CALLBACK_END(7) + + +//----------------------------------------------------------------------------- +// Purpose: change the cursor to display +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_SetCursor_t, k_iSteamHTMLSurfaceCallbacks + 22 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, uint32, eMouseCursor ) // the EMouseCursor to display +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: informational message from the browser +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_StatusText_t, k_iSteamHTMLSurfaceCallbacks + 23 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: show a tooltip +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_ShowToolTip_t, k_iSteamHTMLSurfaceCallbacks + 24 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: update the text of an existing tooltip +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_UpdateToolTip_t, k_iSteamHTMLSurfaceCallbacks + 25 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +STEAM_CALLBACK_END(2) + + +//----------------------------------------------------------------------------- +// Purpose: hide the tooltip you are showing +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_HideToolTip_t, k_iSteamHTMLSurfaceCallbacks + 26 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +STEAM_CALLBACK_END(1) + + +//----------------------------------------------------------------------------- +// Purpose: The browser has restarted due to an internal failure, use this new handle value +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( HTML_BrowserRestarted_t, k_iSteamHTMLSurfaceCallbacks + 27 ) +STEAM_CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // this is the new browser handle after the restart +STEAM_CALLBACK_MEMBER( 1, HHTMLBrowser, unOldBrowserHandle ) // the handle for the browser before the restart, if your handle was this then switch to using unBrowserHandle for API calls +STEAM_CALLBACK_END(2) + + +#pragma pack( pop ) + + +#endif // ISTEAMHTMLSURFACE_H diff --git a/public/steam/isteamhttp.h b/public/steam/isteamhttp.h new file mode 100644 index 0000000..26a02b3 --- /dev/null +++ b/public/steam/isteamhttp.h @@ -0,0 +1,219 @@ +//====== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to http client +// +//============================================================================= + +#ifndef ISTEAMHTTP_H +#define ISTEAMHTTP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "steamhttpenums.h" + +// Handle to a HTTP Request handle +typedef uint32 HTTPRequestHandle; +#define INVALID_HTTPREQUEST_HANDLE 0 + +typedef uint32 HTTPCookieContainerHandle; +#define INVALID_HTTPCOOKIE_HANDLE 0 + +//----------------------------------------------------------------------------- +// Purpose: interface to http client +//----------------------------------------------------------------------------- +class ISteamHTTP +{ +public: + + // Initializes a new HTTP request, returning a handle to use in further operations on it. Requires + // the method (GET or POST) and the absolute URL for the request. Both http and https are supported, + // so this string must start with http:// or https:// and should look like http://store.steampowered.com/app/250/ + // or such. + virtual HTTPRequestHandle CreateHTTPRequest( EHTTPMethod eHTTPRequestMethod, const char *pchAbsoluteURL ) = 0; + + // Set a context value for the request, which will be returned in the HTTPRequestCompleted_t callback after + // sending the request. This is just so the caller can easily keep track of which callbacks go with which request data. + virtual bool SetHTTPRequestContextValue( HTTPRequestHandle hRequest, uint64 ulContextValue ) = 0; + + // Set a timeout in seconds for the HTTP request, must be called prior to sending the request. Default + // timeout is 60 seconds if you don't call this. Returns false if the handle is invalid, or the request + // has already been sent. + virtual bool SetHTTPRequestNetworkActivityTimeout( HTTPRequestHandle hRequest, uint32 unTimeoutSeconds ) = 0; + + // Set a request header value for the request, must be called prior to sending the request. Will + // return false if the handle is invalid or the request is already sent. + virtual bool SetHTTPRequestHeaderValue( HTTPRequestHandle hRequest, const char *pchHeaderName, const char *pchHeaderValue ) = 0; + + // Set a GET or POST parameter value on the request, which is set will depend on the EHTTPMethod specified + // when creating the request. Must be called prior to sending the request. Will return false if the + // handle is invalid or the request is already sent. + virtual bool SetHTTPRequestGetOrPostParameter( HTTPRequestHandle hRequest, const char *pchParamName, const char *pchParamValue ) = 0; + + // Sends the HTTP request, will return false on a bad handle, otherwise use SteamCallHandle to wait on + // asynchronous response via callback. + // + // Note: If the user is in offline mode in Steam, then this will add a only-if-cached cache-control + // header and only do a local cache lookup rather than sending any actual remote request. + virtual bool SendHTTPRequest( HTTPRequestHandle hRequest, SteamAPICall_t *pCallHandle ) = 0; + + // Sends the HTTP request, will return false on a bad handle, otherwise use SteamCallHandle to wait on + // asynchronous response via callback for completion, and listen for HTTPRequestHeadersReceived_t and + // HTTPRequestDataReceived_t callbacks while streaming. + virtual bool SendHTTPRequestAndStreamResponse( HTTPRequestHandle hRequest, SteamAPICall_t *pCallHandle ) = 0; + + // Defers a request you have sent, the actual HTTP client code may have many requests queued, and this will move + // the specified request to the tail of the queue. Returns false on invalid handle, or if the request is not yet sent. + virtual bool DeferHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Prioritizes a request you have sent, the actual HTTP client code may have many requests queued, and this will move + // the specified request to the head of the queue. Returns false on invalid handle, or if the request is not yet sent. + virtual bool PrioritizeHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Checks if a response header is present in a HTTP response given a handle from HTTPRequestCompleted_t, also + // returns the size of the header value if present so the caller and allocate a correctly sized buffer for + // GetHTTPResponseHeaderValue. + virtual bool GetHTTPResponseHeaderSize( HTTPRequestHandle hRequest, const char *pchHeaderName, uint32 *unResponseHeaderSize ) = 0; + + // Gets header values from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // header is not present or if your buffer is too small to contain it's value. You should first call + // BGetHTTPResponseHeaderSize to check for the presence of the header and to find out the size buffer needed. + virtual bool GetHTTPResponseHeaderValue( HTTPRequestHandle hRequest, const char *pchHeaderName, uint8 *pHeaderValueBuffer, uint32 unBufferSize ) = 0; + + // Gets the size of the body data from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // handle is invalid. + virtual bool GetHTTPResponseBodySize( HTTPRequestHandle hRequest, uint32 *unBodySize ) = 0; + + // Gets the body data from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // handle is invalid or is to a streaming response, or if the provided buffer is not the correct size. Use BGetHTTPResponseBodySize first to find out + // the correct buffer size to use. + virtual bool GetHTTPResponseBodyData( HTTPRequestHandle hRequest, uint8 *pBodyDataBuffer, uint32 unBufferSize ) = 0; + + // Gets the body data from a streaming HTTP response given a handle from HTTPRequestDataReceived_t. Will return false if the + // handle is invalid or is to a non-streaming response (meaning it wasn't sent with SendHTTPRequestAndStreamResponse), or if the buffer size and offset + // do not match the size and offset sent in HTTPRequestDataReceived_t. + virtual bool GetHTTPStreamingResponseBodyData( HTTPRequestHandle hRequest, uint32 cOffset, uint8 *pBodyDataBuffer, uint32 unBufferSize ) = 0; + + // Releases an HTTP response handle, should always be called to free resources after receiving a HTTPRequestCompleted_t + // callback and finishing using the response. + virtual bool ReleaseHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Gets progress on downloading the body for the request. This will be zero unless a response header has already been + // received which included a content-length field. For responses that contain no content-length it will report + // zero for the duration of the request as the size is unknown until the connection closes. + virtual bool GetHTTPDownloadProgressPct( HTTPRequestHandle hRequest, float *pflPercentOut ) = 0; + + // Sets the body for an HTTP Post request. Will fail and return false on a GET request, and will fail if POST params + // have already been set for the request. Setting this raw body makes it the only contents for the post, the pchContentType + // parameter will set the content-type header for the request so the server may know how to interpret the body. + virtual bool SetHTTPRequestRawPostBody( HTTPRequestHandle hRequest, const char *pchContentType, uint8 *pubBody, uint32 unBodyLen ) = 0; + + // Creates a cookie container handle which you must later free with ReleaseCookieContainer(). If bAllowResponsesToModify=true + // than any response to your requests using this cookie container may add new cookies which may be transmitted with + // future requests. If bAllowResponsesToModify=false than only cookies you explicitly set will be sent. This API is just for + // during process lifetime, after steam restarts no cookies are persisted and you have no way to access the cookie container across + // repeat executions of your process. + virtual HTTPCookieContainerHandle CreateCookieContainer( bool bAllowResponsesToModify ) = 0; + + // Release a cookie container you are finished using, freeing it's memory + virtual bool ReleaseCookieContainer( HTTPCookieContainerHandle hCookieContainer ) = 0; + + // Adds a cookie to the specified cookie container that will be used with future requests. + virtual bool SetCookie( HTTPCookieContainerHandle hCookieContainer, const char *pchHost, const char *pchUrl, const char *pchCookie ) = 0; + + // Set the cookie container to use for a HTTP request + virtual bool SetHTTPRequestCookieContainer( HTTPRequestHandle hRequest, HTTPCookieContainerHandle hCookieContainer ) = 0; + + // Set the extra user agent info for a request, this doesn't clobber the normal user agent, it just adds the extra info on the end + virtual bool SetHTTPRequestUserAgentInfo( HTTPRequestHandle hRequest, const char *pchUserAgentInfo ) = 0; + + // Disable or re-enable verification of SSL/TLS certificates. + // By default, certificates are checked for all HTTPS requests. + virtual bool SetHTTPRequestRequiresVerifiedCertificate( HTTPRequestHandle hRequest, bool bRequireVerifiedCertificate ) = 0; + + // Set an absolute timeout on the HTTP request, this is just a total time timeout different than the network activity timeout + // which can bump everytime we get more data + virtual bool SetHTTPRequestAbsoluteTimeoutMS( HTTPRequestHandle hRequest, uint32 unMilliseconds ) = 0; + + // Check if the reason the request failed was because we timed it out (rather than some harder failure) + virtual bool GetHTTPRequestWasTimedOut( HTTPRequestHandle hRequest, bool *pbWasTimedOut ) = 0; +}; + +#define STEAMHTTP_INTERFACE_VERSION "STEAMHTTP_INTERFACE_VERSION003" + +// Global interface accessor +inline ISteamHTTP *SteamHTTP(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamHTTP *, SteamHTTP, STEAMHTTP_INTERFACE_VERSION ); + +// Global accessor for the gameserver client +inline ISteamHTTP *SteamGameServerHTTP(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamHTTP *, SteamGameServerHTTP, STEAMHTTP_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +struct HTTPRequestCompleted_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 1 }; + + // Handle value for the request that has completed. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + // This will be true if we actually got any sort of response from the server (even an error). + // It will be false if we failed due to an internal error or client side network failure. + bool m_bRequestSuccessful; + + // Will be the HTTP status code value returned by the server, k_EHTTPStatusCode200OK is the normal + // OK response, if you get something else you probably need to treat it as a failure. + EHTTPStatusCode m_eStatusCode; + + uint32 m_unBodySize; // Same as GetHTTPResponseBodySize() +}; + + +struct HTTPRequestHeadersReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 2 }; + + // Handle value for the request that has received headers. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; +}; + +struct HTTPRequestDataReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 3 }; + + // Handle value for the request that has received data. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + + // Offset to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cOffset; + + // Size to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cBytesReceived; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMHTTP_H \ No newline at end of file diff --git a/public/steam/isteaminput.h b/public/steam/isteaminput.h new file mode 100644 index 0000000..5f2c6c8 --- /dev/null +++ b/public/steam/isteaminput.h @@ -0,0 +1,631 @@ +//====== Copyright 1996-2018, Valve Corporation, All rights reserved. ======= +// +// Purpose: Steam Input is a flexible input API that supports over three hundred devices including all +// common variants of Xbox, Playstation, Nintendo Switch Pro, and Steam Controllers. +// For more info including a getting started guide for developers +// please visit: https://partner.steamgames.com/doc/features/steam_controller +// +//============================================================================= + +#ifndef ISTEAMINPUT_H +#define ISTEAMINPUT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +#define STEAM_INPUT_MAX_COUNT 16 + +#define STEAM_INPUT_MAX_ANALOG_ACTIONS 16 + +#define STEAM_INPUT_MAX_DIGITAL_ACTIONS 128 + +#define STEAM_INPUT_MAX_ORIGINS 8 + +#define STEAM_INPUT_MAX_ACTIVE_LAYERS 16 + +// When sending an option to a specific controller handle, you can send to all devices via this command +#define STEAM_INPUT_HANDLE_ALL_CONTROLLERS UINT64_MAX + +#define STEAM_INPUT_MIN_ANALOG_ACTION_DATA -1.0f +#define STEAM_INPUT_MAX_ANALOG_ACTION_DATA 1.0f + +enum EInputSource +{ + k_EInputSource_None, + k_EInputSource_LeftTrackpad, + k_EInputSource_RightTrackpad, + k_EInputSource_Joystick, + k_EInputSource_ABXY, + k_EInputSource_Switch, + k_EInputSource_LeftTrigger, + k_EInputSource_RightTrigger, + k_EInputSource_LeftBumper, + k_EInputSource_RightBumper, + k_EInputSource_Gyro, + k_EInputSource_CenterTrackpad, // PS4 + k_EInputSource_RightJoystick, // Traditional Controllers + k_EInputSource_DPad, // Traditional Controllers + k_EInputSource_Key, // Keyboards with scan codes - Unused + k_EInputSource_Mouse, // Traditional mouse - Unused + k_EInputSource_LeftGyro, // Secondary Gyro - Switch - Unused + k_EInputSource_Count +}; + +enum EInputSourceMode +{ + k_EInputSourceMode_None, + k_EInputSourceMode_Dpad, + k_EInputSourceMode_Buttons, + k_EInputSourceMode_FourButtons, + k_EInputSourceMode_AbsoluteMouse, + k_EInputSourceMode_RelativeMouse, + k_EInputSourceMode_JoystickMove, + k_EInputSourceMode_JoystickMouse, + k_EInputSourceMode_JoystickCamera, + k_EInputSourceMode_ScrollWheel, + k_EInputSourceMode_Trigger, + k_EInputSourceMode_TouchMenu, + k_EInputSourceMode_MouseJoystick, + k_EInputSourceMode_MouseRegion, + k_EInputSourceMode_RadialMenu, + k_EInputSourceMode_SingleButton, + k_EInputSourceMode_Switches +}; + +// Note: Please do not use action origins as a way to identify controller types. There is no +// guarantee that they will be added in a contiguous manner - use GetInputTypeForHandle instead. +// Versions of Steam that add new controller types in the future will extend this enum so if you're +// using a lookup table please check the bounds of any origins returned by Steam. +enum EInputActionOrigin +{ + // Steam Controller + k_EInputActionOrigin_None, + k_EInputActionOrigin_SteamController_A, + k_EInputActionOrigin_SteamController_B, + k_EInputActionOrigin_SteamController_X, + k_EInputActionOrigin_SteamController_Y, + k_EInputActionOrigin_SteamController_LeftBumper, + k_EInputActionOrigin_SteamController_RightBumper, + k_EInputActionOrigin_SteamController_LeftGrip, + k_EInputActionOrigin_SteamController_RightGrip, + k_EInputActionOrigin_SteamController_Start, + k_EInputActionOrigin_SteamController_Back, + k_EInputActionOrigin_SteamController_LeftPad_Touch, + k_EInputActionOrigin_SteamController_LeftPad_Swipe, + k_EInputActionOrigin_SteamController_LeftPad_Click, + k_EInputActionOrigin_SteamController_LeftPad_DPadNorth, + k_EInputActionOrigin_SteamController_LeftPad_DPadSouth, + k_EInputActionOrigin_SteamController_LeftPad_DPadWest, + k_EInputActionOrigin_SteamController_LeftPad_DPadEast, + k_EInputActionOrigin_SteamController_RightPad_Touch, + k_EInputActionOrigin_SteamController_RightPad_Swipe, + k_EInputActionOrigin_SteamController_RightPad_Click, + k_EInputActionOrigin_SteamController_RightPad_DPadNorth, + k_EInputActionOrigin_SteamController_RightPad_DPadSouth, + k_EInputActionOrigin_SteamController_RightPad_DPadWest, + k_EInputActionOrigin_SteamController_RightPad_DPadEast, + k_EInputActionOrigin_SteamController_LeftTrigger_Pull, + k_EInputActionOrigin_SteamController_LeftTrigger_Click, + k_EInputActionOrigin_SteamController_RightTrigger_Pull, + k_EInputActionOrigin_SteamController_RightTrigger_Click, + k_EInputActionOrigin_SteamController_LeftStick_Move, + k_EInputActionOrigin_SteamController_LeftStick_Click, + k_EInputActionOrigin_SteamController_LeftStick_DPadNorth, + k_EInputActionOrigin_SteamController_LeftStick_DPadSouth, + k_EInputActionOrigin_SteamController_LeftStick_DPadWest, + k_EInputActionOrigin_SteamController_LeftStick_DPadEast, + k_EInputActionOrigin_SteamController_Gyro_Move, + k_EInputActionOrigin_SteamController_Gyro_Pitch, + k_EInputActionOrigin_SteamController_Gyro_Yaw, + k_EInputActionOrigin_SteamController_Gyro_Roll, + k_EInputActionOrigin_SteamController_Reserved0, + k_EInputActionOrigin_SteamController_Reserved1, + k_EInputActionOrigin_SteamController_Reserved2, + k_EInputActionOrigin_SteamController_Reserved3, + k_EInputActionOrigin_SteamController_Reserved4, + k_EInputActionOrigin_SteamController_Reserved5, + k_EInputActionOrigin_SteamController_Reserved6, + k_EInputActionOrigin_SteamController_Reserved7, + k_EInputActionOrigin_SteamController_Reserved8, + k_EInputActionOrigin_SteamController_Reserved9, + k_EInputActionOrigin_SteamController_Reserved10, + + // PS4 Dual Shock + k_EInputActionOrigin_PS4_X, + k_EInputActionOrigin_PS4_Circle, + k_EInputActionOrigin_PS4_Triangle, + k_EInputActionOrigin_PS4_Square, + k_EInputActionOrigin_PS4_LeftBumper, + k_EInputActionOrigin_PS4_RightBumper, + k_EInputActionOrigin_PS4_Options, //Start + k_EInputActionOrigin_PS4_Share, //Back + k_EInputActionOrigin_PS4_LeftPad_Touch, + k_EInputActionOrigin_PS4_LeftPad_Swipe, + k_EInputActionOrigin_PS4_LeftPad_Click, + k_EInputActionOrigin_PS4_LeftPad_DPadNorth, + k_EInputActionOrigin_PS4_LeftPad_DPadSouth, + k_EInputActionOrigin_PS4_LeftPad_DPadWest, + k_EInputActionOrigin_PS4_LeftPad_DPadEast, + k_EInputActionOrigin_PS4_RightPad_Touch, + k_EInputActionOrigin_PS4_RightPad_Swipe, + k_EInputActionOrigin_PS4_RightPad_Click, + k_EInputActionOrigin_PS4_RightPad_DPadNorth, + k_EInputActionOrigin_PS4_RightPad_DPadSouth, + k_EInputActionOrigin_PS4_RightPad_DPadWest, + k_EInputActionOrigin_PS4_RightPad_DPadEast, + k_EInputActionOrigin_PS4_CenterPad_Touch, + k_EInputActionOrigin_PS4_CenterPad_Swipe, + k_EInputActionOrigin_PS4_CenterPad_Click, + k_EInputActionOrigin_PS4_CenterPad_DPadNorth, + k_EInputActionOrigin_PS4_CenterPad_DPadSouth, + k_EInputActionOrigin_PS4_CenterPad_DPadWest, + k_EInputActionOrigin_PS4_CenterPad_DPadEast, + k_EInputActionOrigin_PS4_LeftTrigger_Pull, + k_EInputActionOrigin_PS4_LeftTrigger_Click, + k_EInputActionOrigin_PS4_RightTrigger_Pull, + k_EInputActionOrigin_PS4_RightTrigger_Click, + k_EInputActionOrigin_PS4_LeftStick_Move, + k_EInputActionOrigin_PS4_LeftStick_Click, + k_EInputActionOrigin_PS4_LeftStick_DPadNorth, + k_EInputActionOrigin_PS4_LeftStick_DPadSouth, + k_EInputActionOrigin_PS4_LeftStick_DPadWest, + k_EInputActionOrigin_PS4_LeftStick_DPadEast, + k_EInputActionOrigin_PS4_RightStick_Move, + k_EInputActionOrigin_PS4_RightStick_Click, + k_EInputActionOrigin_PS4_RightStick_DPadNorth, + k_EInputActionOrigin_PS4_RightStick_DPadSouth, + k_EInputActionOrigin_PS4_RightStick_DPadWest, + k_EInputActionOrigin_PS4_RightStick_DPadEast, + k_EInputActionOrigin_PS4_DPad_North, + k_EInputActionOrigin_PS4_DPad_South, + k_EInputActionOrigin_PS4_DPad_West, + k_EInputActionOrigin_PS4_DPad_East, + k_EInputActionOrigin_PS4_Gyro_Move, + k_EInputActionOrigin_PS4_Gyro_Pitch, + k_EInputActionOrigin_PS4_Gyro_Yaw, + k_EInputActionOrigin_PS4_Gyro_Roll, + k_EInputActionOrigin_PS4_DPad_Move, + k_EInputActionOrigin_PS4_Reserved1, + k_EInputActionOrigin_PS4_Reserved2, + k_EInputActionOrigin_PS4_Reserved3, + k_EInputActionOrigin_PS4_Reserved4, + k_EInputActionOrigin_PS4_Reserved5, + k_EInputActionOrigin_PS4_Reserved6, + k_EInputActionOrigin_PS4_Reserved7, + k_EInputActionOrigin_PS4_Reserved8, + k_EInputActionOrigin_PS4_Reserved9, + k_EInputActionOrigin_PS4_Reserved10, + + // XBox One + k_EInputActionOrigin_XBoxOne_A, + k_EInputActionOrigin_XBoxOne_B, + k_EInputActionOrigin_XBoxOne_X, + k_EInputActionOrigin_XBoxOne_Y, + k_EInputActionOrigin_XBoxOne_LeftBumper, + k_EInputActionOrigin_XBoxOne_RightBumper, + k_EInputActionOrigin_XBoxOne_Menu, //Start + k_EInputActionOrigin_XBoxOne_View, //Back + k_EInputActionOrigin_XBoxOne_LeftTrigger_Pull, + k_EInputActionOrigin_XBoxOne_LeftTrigger_Click, + k_EInputActionOrigin_XBoxOne_RightTrigger_Pull, + k_EInputActionOrigin_XBoxOne_RightTrigger_Click, + k_EInputActionOrigin_XBoxOne_LeftStick_Move, + k_EInputActionOrigin_XBoxOne_LeftStick_Click, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadNorth, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadSouth, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadWest, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadEast, + k_EInputActionOrigin_XBoxOne_RightStick_Move, + k_EInputActionOrigin_XBoxOne_RightStick_Click, + k_EInputActionOrigin_XBoxOne_RightStick_DPadNorth, + k_EInputActionOrigin_XBoxOne_RightStick_DPadSouth, + k_EInputActionOrigin_XBoxOne_RightStick_DPadWest, + k_EInputActionOrigin_XBoxOne_RightStick_DPadEast, + k_EInputActionOrigin_XBoxOne_DPad_North, + k_EInputActionOrigin_XBoxOne_DPad_South, + k_EInputActionOrigin_XBoxOne_DPad_West, + k_EInputActionOrigin_XBoxOne_DPad_East, + k_EInputActionOrigin_XBoxOne_DPad_Move, + k_EInputActionOrigin_XBoxOne_Reserved1, + k_EInputActionOrigin_XBoxOne_Reserved2, + k_EInputActionOrigin_XBoxOne_Reserved3, + k_EInputActionOrigin_XBoxOne_Reserved4, + k_EInputActionOrigin_XBoxOne_Reserved5, + k_EInputActionOrigin_XBoxOne_Reserved6, + k_EInputActionOrigin_XBoxOne_Reserved7, + k_EInputActionOrigin_XBoxOne_Reserved8, + k_EInputActionOrigin_XBoxOne_Reserved9, + k_EInputActionOrigin_XBoxOne_Reserved10, + + // XBox 360 + k_EInputActionOrigin_XBox360_A, + k_EInputActionOrigin_XBox360_B, + k_EInputActionOrigin_XBox360_X, + k_EInputActionOrigin_XBox360_Y, + k_EInputActionOrigin_XBox360_LeftBumper, + k_EInputActionOrigin_XBox360_RightBumper, + k_EInputActionOrigin_XBox360_Start, //Start + k_EInputActionOrigin_XBox360_Back, //Back + k_EInputActionOrigin_XBox360_LeftTrigger_Pull, + k_EInputActionOrigin_XBox360_LeftTrigger_Click, + k_EInputActionOrigin_XBox360_RightTrigger_Pull, + k_EInputActionOrigin_XBox360_RightTrigger_Click, + k_EInputActionOrigin_XBox360_LeftStick_Move, + k_EInputActionOrigin_XBox360_LeftStick_Click, + k_EInputActionOrigin_XBox360_LeftStick_DPadNorth, + k_EInputActionOrigin_XBox360_LeftStick_DPadSouth, + k_EInputActionOrigin_XBox360_LeftStick_DPadWest, + k_EInputActionOrigin_XBox360_LeftStick_DPadEast, + k_EInputActionOrigin_XBox360_RightStick_Move, + k_EInputActionOrigin_XBox360_RightStick_Click, + k_EInputActionOrigin_XBox360_RightStick_DPadNorth, + k_EInputActionOrigin_XBox360_RightStick_DPadSouth, + k_EInputActionOrigin_XBox360_RightStick_DPadWest, + k_EInputActionOrigin_XBox360_RightStick_DPadEast, + k_EInputActionOrigin_XBox360_DPad_North, + k_EInputActionOrigin_XBox360_DPad_South, + k_EInputActionOrigin_XBox360_DPad_West, + k_EInputActionOrigin_XBox360_DPad_East, + k_EInputActionOrigin_XBox360_DPad_Move, + k_EInputActionOrigin_XBox360_Reserved1, + k_EInputActionOrigin_XBox360_Reserved2, + k_EInputActionOrigin_XBox360_Reserved3, + k_EInputActionOrigin_XBox360_Reserved4, + k_EInputActionOrigin_XBox360_Reserved5, + k_EInputActionOrigin_XBox360_Reserved6, + k_EInputActionOrigin_XBox360_Reserved7, + k_EInputActionOrigin_XBox360_Reserved8, + k_EInputActionOrigin_XBox360_Reserved9, + k_EInputActionOrigin_XBox360_Reserved10, + + + // Switch - Pro or Joycons used as a single input device. + // This does not apply to a single joycon + k_EInputActionOrigin_Switch_A, + k_EInputActionOrigin_Switch_B, + k_EInputActionOrigin_Switch_X, + k_EInputActionOrigin_Switch_Y, + k_EInputActionOrigin_Switch_LeftBumper, + k_EInputActionOrigin_Switch_RightBumper, + k_EInputActionOrigin_Switch_Plus, //Start + k_EInputActionOrigin_Switch_Minus, //Back + k_EInputActionOrigin_Switch_Capture, + k_EInputActionOrigin_Switch_LeftTrigger_Pull, + k_EInputActionOrigin_Switch_LeftTrigger_Click, + k_EInputActionOrigin_Switch_RightTrigger_Pull, + k_EInputActionOrigin_Switch_RightTrigger_Click, + k_EInputActionOrigin_Switch_LeftStick_Move, + k_EInputActionOrigin_Switch_LeftStick_Click, + k_EInputActionOrigin_Switch_LeftStick_DPadNorth, + k_EInputActionOrigin_Switch_LeftStick_DPadSouth, + k_EInputActionOrigin_Switch_LeftStick_DPadWest, + k_EInputActionOrigin_Switch_LeftStick_DPadEast, + k_EInputActionOrigin_Switch_RightStick_Move, + k_EInputActionOrigin_Switch_RightStick_Click, + k_EInputActionOrigin_Switch_RightStick_DPadNorth, + k_EInputActionOrigin_Switch_RightStick_DPadSouth, + k_EInputActionOrigin_Switch_RightStick_DPadWest, + k_EInputActionOrigin_Switch_RightStick_DPadEast, + k_EInputActionOrigin_Switch_DPad_North, + k_EInputActionOrigin_Switch_DPad_South, + k_EInputActionOrigin_Switch_DPad_West, + k_EInputActionOrigin_Switch_DPad_East, + k_EInputActionOrigin_Switch_ProGyro_Move, // Primary Gyro in Pro Controller, or Right JoyCon + k_EInputActionOrigin_Switch_ProGyro_Pitch, // Primary Gyro in Pro Controller, or Right JoyCon + k_EInputActionOrigin_Switch_ProGyro_Yaw, // Primary Gyro in Pro Controller, or Right JoyCon + k_EInputActionOrigin_Switch_ProGyro_Roll, // Primary Gyro in Pro Controller, or Right JoyCon + k_EInputActionOrigin_Switch_DPad_Move, + k_EInputActionOrigin_Switch_Reserved1, + k_EInputActionOrigin_Switch_Reserved2, + k_EInputActionOrigin_Switch_Reserved3, + k_EInputActionOrigin_Switch_Reserved4, + k_EInputActionOrigin_Switch_Reserved5, + k_EInputActionOrigin_Switch_Reserved6, + k_EInputActionOrigin_Switch_Reserved7, + k_EInputActionOrigin_Switch_Reserved8, + k_EInputActionOrigin_Switch_Reserved9, + k_EInputActionOrigin_Switch_Reserved10, + + // Switch JoyCon Specific + k_EInputActionOrigin_Switch_RightGyro_Move, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EInputActionOrigin_Switch_RightGyro_Pitch, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EInputActionOrigin_Switch_RightGyro_Yaw, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EInputActionOrigin_Switch_RightGyro_Roll, // Right JoyCon Gyro generally should correspond to Pro's single gyro + k_EInputActionOrigin_Switch_LeftGyro_Move, + k_EInputActionOrigin_Switch_LeftGyro_Pitch, + k_EInputActionOrigin_Switch_LeftGyro_Yaw, + k_EInputActionOrigin_Switch_LeftGyro_Roll, + k_EInputActionOrigin_Switch_LeftGrip_Lower, // Left JoyCon SR Button + k_EInputActionOrigin_Switch_LeftGrip_Upper, // Left JoyCon SL Button + k_EInputActionOrigin_Switch_RightGrip_Lower, // Right JoyCon SL Button + k_EInputActionOrigin_Switch_RightGrip_Upper, // Right JoyCon SR Button + k_EInputActionOrigin_Switch_Reserved11, + k_EInputActionOrigin_Switch_Reserved12, + k_EInputActionOrigin_Switch_Reserved13, + k_EInputActionOrigin_Switch_Reserved14, + k_EInputActionOrigin_Switch_Reserved15, + k_EInputActionOrigin_Switch_Reserved16, + k_EInputActionOrigin_Switch_Reserved17, + k_EInputActionOrigin_Switch_Reserved18, + k_EInputActionOrigin_Switch_Reserved19, + k_EInputActionOrigin_Switch_Reserved20, + + k_EInputActionOrigin_Count, // If Steam has added support for new controllers origins will go here. + k_EInputActionOrigin_MaximumPossibleValue = 32767, // Origins are currently a maximum of 16 bits. +}; + +enum EXboxOrigin +{ + k_EXboxOrigin_A, + k_EXboxOrigin_B, + k_EXboxOrigin_X, + k_EXboxOrigin_Y, + k_EXboxOrigin_LeftBumper, + k_EXboxOrigin_RightBumper, + k_EXboxOrigin_Menu, //Start + k_EXboxOrigin_View, //Back + k_EXboxOrigin_LeftTrigger_Pull, + k_EXboxOrigin_LeftTrigger_Click, + k_EXboxOrigin_RightTrigger_Pull, + k_EXboxOrigin_RightTrigger_Click, + k_EXboxOrigin_LeftStick_Move, + k_EXboxOrigin_LeftStick_Click, + k_EXboxOrigin_LeftStick_DPadNorth, + k_EXboxOrigin_LeftStick_DPadSouth, + k_EXboxOrigin_LeftStick_DPadWest, + k_EXboxOrigin_LeftStick_DPadEast, + k_EXboxOrigin_RightStick_Move, + k_EXboxOrigin_RightStick_Click, + k_EXboxOrigin_RightStick_DPadNorth, + k_EXboxOrigin_RightStick_DPadSouth, + k_EXboxOrigin_RightStick_DPadWest, + k_EXboxOrigin_RightStick_DPadEast, + k_EXboxOrigin_DPad_North, + k_EXboxOrigin_DPad_South, + k_EXboxOrigin_DPad_West, + k_EXboxOrigin_DPad_East, + k_EXboxOrigin_Count, +}; + +enum ESteamControllerPad +{ + k_ESteamControllerPad_Left, + k_ESteamControllerPad_Right +}; + +enum ESteamInputType +{ + k_ESteamInputType_Unknown, + k_ESteamInputType_SteamController, + k_ESteamInputType_XBox360Controller, + k_ESteamInputType_XBoxOneController, + k_ESteamInputType_GenericGamepad, // DirectInput controllers + k_ESteamInputType_PS4Controller, + k_ESteamInputType_AppleMFiController, // Unused + k_ESteamInputType_AndroidController, // Unused + k_ESteamInputType_SwitchJoyConPair, // Unused + k_ESteamInputType_SwitchJoyConSingle, // Unused + k_ESteamInputType_SwitchProController, + k_ESteamInputType_MobileTouch, // Steam Link App On-screen Virtual Controller + k_ESteamInputType_PS3Controller, // Currently uses PS4 Origins + k_ESteamInputType_Count, + k_ESteamInputType_MaximumPossibleValue = 255, +}; + +// These values are passed into SetLEDColor +enum ESteamInputLEDFlag +{ + k_ESteamInputLEDFlag_SetColor, + // Restore the LED color to the user's preference setting as set in the controller personalization menu. + // This also happens automatically on exit of your game. + k_ESteamInputLEDFlag_RestoreUserDefault +}; + +// InputHandle_t is used to refer to a specific controller. +// This handle will consistently identify a controller, even if it is disconnected and re-connected +typedef uint64 InputHandle_t; + + +// These handles are used to refer to a specific in-game action or action set +// All action handles should be queried during initialization for performance reasons +typedef uint64 InputActionSetHandle_t; +typedef uint64 InputDigitalActionHandle_t; +typedef uint64 InputAnalogActionHandle_t; + +#pragma pack( push, 1 ) + +struct InputAnalogActionData_t +{ + // Type of data coming from this action, this will match what got specified in the action set + EInputSourceMode eMode; + + // The current state of this action; will be delta updates for mouse actions + float x, y; + + // Whether or not this action is currently available to be bound in the active action set + bool bActive; +}; + +struct InputDigitalActionData_t +{ + // The current state of this action; will be true if currently pressed + bool bState; + + // Whether or not this action is currently available to be bound in the active action set + bool bActive; +}; + +struct InputMotionData_t +{ + // Sensor-fused absolute rotation; will drift in heading + float rotQuatX; + float rotQuatY; + float rotQuatZ; + float rotQuatW; + + // Positional acceleration + float posAccelX; + float posAccelY; + float posAccelZ; + + // Angular velocity + float rotVelX; + float rotVelY; + float rotVelZ; +}; + +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Steam Input API +//----------------------------------------------------------------------------- +class ISteamInput +{ +public: + + // Init and Shutdown must be called when starting/ending use of this interface + virtual bool Init() = 0; + virtual bool Shutdown() = 0; + + // Synchronize API state with the latest Steam Controller inputs available. This + // is performed automatically by SteamAPI_RunCallbacks, but for the absolute lowest + // possible latency, you call this directly before reading controller state. This must + // be called from somewhere before GetConnectedControllers will return any handles + virtual void RunFrame() = 0; + + // Enumerate currently connected Steam Input enabled devices - developers can opt in controller by type (ex: Xbox/Playstation/etc) via + // the Steam Input settings in the Steamworks site or users can opt-in in their controller settings in Steam. + // handlesOut should point to a STEAM_INPUT_MAX_COUNT sized array of InputHandle_t handles + // Returns the number of handles written to handlesOut + virtual int GetConnectedControllers( STEAM_OUT_ARRAY_COUNT( STEAM_INPUT_MAX_COUNT, Receives list of connected controllers ) InputHandle_t *handlesOut ) = 0; + + //----------------------------------------------------------------------------- + // ACTION SETS + //----------------------------------------------------------------------------- + + // Lookup the handle for an Action Set. Best to do this once on startup, and store the handles for all future API calls. + virtual InputActionSetHandle_t GetActionSetHandle( const char *pszActionSetName ) = 0; + + // Reconfigure the controller to use the specified action set (ie 'Menu', 'Walk' or 'Drive') + // This is cheap, and can be safely called repeatedly. It's often easier to repeatedly call it in + // your state loops, instead of trying to place it in all of your state transitions. + virtual void ActivateActionSet( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle ) = 0; + virtual InputActionSetHandle_t GetCurrentActionSet( InputHandle_t inputHandle ) = 0; + + // ACTION SET LAYERS + virtual void ActivateActionSetLayer( InputHandle_t inputHandle, InputActionSetHandle_t actionSetLayerHandle ) = 0; + virtual void DeactivateActionSetLayer( InputHandle_t inputHandle, InputActionSetHandle_t actionSetLayerHandle ) = 0; + virtual void DeactivateAllActionSetLayers( InputHandle_t inputHandle ) = 0; + // Enumerate currently active layers. + // handlesOut should point to a STEAM_INPUT_MAX_ACTIVE_LAYERS sized array of ControllerActionSetHandle_t handles + // Returns the number of handles written to handlesOut + virtual int GetActiveActionSetLayers( InputHandle_t inputHandle, STEAM_OUT_ARRAY_COUNT( STEAM_INPUT_MAX_ACTIVE_LAYERS, Receives list of active layers ) InputActionSetHandle_t *handlesOut ) = 0; + + //----------------------------------------------------------------------------- + // ACTIONS + //----------------------------------------------------------------------------- + + // Lookup the handle for a digital action. Best to do this once on startup, and store the handles for all future API calls. + virtual InputDigitalActionHandle_t GetDigitalActionHandle( const char *pszActionName ) = 0; + + // Returns the current state of the supplied digital game action + virtual InputDigitalActionData_t GetDigitalActionData( InputHandle_t inputHandle, InputDigitalActionHandle_t digitalActionHandle ) = 0; + + // Get the origin(s) for a digital action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. + // originsOut should point to a STEAM_INPUT_MAX_ORIGINS sized array of EInputActionOrigin handles. The EInputActionOrigin enum will get extended as support for new controller controllers gets added to + // the Steam client and will exceed the values from this header, please check bounds if you are using a look up table. + virtual int GetDigitalActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputDigitalActionHandle_t digitalActionHandle, STEAM_OUT_ARRAY_COUNT( STEAM_INPUT_MAX_ORIGINS, Receives list of action origins ) EInputActionOrigin *originsOut ) = 0; + + // Lookup the handle for an analog action. Best to do this once on startup, and store the handles for all future API calls. + virtual InputAnalogActionHandle_t GetAnalogActionHandle( const char *pszActionName ) = 0; + + // Returns the current state of these supplied analog game action + virtual InputAnalogActionData_t GetAnalogActionData( InputHandle_t inputHandle, InputAnalogActionHandle_t analogActionHandle ) = 0; + + // Get the origin(s) for an analog action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action. + // originsOut should point to a STEAM_INPUT_MAX_ORIGINS sized array of EInputActionOrigin handles. The EInputActionOrigin enum will get extended as support for new controller controllers gets added to + // the Steam client and will exceed the values from this header, please check bounds if you are using a look up table. + virtual int GetAnalogActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputAnalogActionHandle_t analogActionHandle, STEAM_OUT_ARRAY_COUNT( STEAM_INPUT_MAX_ORIGINS, Receives list of action origins ) EInputActionOrigin *originsOut ) = 0; + + // Get a local path to art for on-screen glyph for a particular origin + virtual const char *GetGlyphForActionOrigin( EInputActionOrigin eOrigin ) = 0; + + // Returns a localized string (from Steam's language setting) for the specified origin. + virtual const char *GetStringForActionOrigin( EInputActionOrigin eOrigin ) = 0; + + // Stop analog momentum for the action if it is a mouse action in trackball mode + virtual void StopAnalogActionMomentum( InputHandle_t inputHandle, InputAnalogActionHandle_t eAction ) = 0; + + // Returns raw motion data from the specified device + virtual InputMotionData_t GetMotionData( InputHandle_t inputHandle ) = 0; + + //----------------------------------------------------------------------------- + // OUTPUTS + //----------------------------------------------------------------------------- + + // Trigger a vibration event on supported controllers - Steam will translate these commands into haptic pulses for Steam Controllers + virtual void TriggerVibration( InputHandle_t inputHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed ) = 0; + + // Set the controller LED color on supported controllers. nFlags is a bitmask of values from ESteamInputLEDFlag - 0 will default to setting a color. Steam will handle + // the behavior on exit of your program so you don't need to try restore the default as you are shutting down + virtual void SetLEDColor( InputHandle_t inputHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags ) = 0; + + // Trigger a haptic pulse on a Steam Controller - if you are approximating rumble you may want to use TriggerVibration instead. + // Good uses for Haptic pulses include chimes, noises, or directional gameplay feedback (taking damage, footstep locations, etc). + virtual void TriggerHapticPulse( InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ) = 0; + + // Trigger a haptic pulse with a duty cycle of usDurationMicroSec / usOffMicroSec, unRepeat times. If you are approximating rumble you may want to use TriggerVibration instead. + // nFlags is currently unused and reserved for future use. + virtual void TriggerRepeatedHapticPulse( InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ) = 0; + + //----------------------------------------------------------------------------- + // Utility functions availible without using the rest of Steam Input API + //----------------------------------------------------------------------------- + + // Invokes the Steam overlay and brings up the binding screen if the user is using Big Picture Mode + // If the user is not in Big Picture Mode it will open up the binding in a new window + virtual bool ShowBindingPanel( InputHandle_t inputHandle ) = 0; + + // Returns the input type for a particular handle + virtual ESteamInputType GetInputTypeForHandle( InputHandle_t inputHandle ) = 0; + + // Returns the associated controller handle for the specified emulated gamepad - can be used with the above 2 functions + // to identify controllers presented to your game over Xinput. Returns 0 if the Xinput index isn't associated with Steam Input + virtual InputHandle_t GetControllerForGamepadIndex( int nIndex ) = 0; + + // Returns the associated gamepad index for the specified controller, if emulating a gamepad or -1 if not associated with an Xinput index + virtual int GetGamepadIndexForController( InputHandle_t ulinputHandle ) = 0; + + // Returns a localized string (from Steam's language setting) for the specified Xbox controller origin. + virtual const char *GetStringForXboxOrigin( EXboxOrigin eOrigin ) = 0; + + // Get a local path to art for on-screen glyph for a particular Xbox controller origin + virtual const char *GetGlyphForXboxOrigin( EXboxOrigin eOrigin ) = 0; + + // Get the equivalent ActionOrigin for a given Xbox controller origin this can be chained with GetGlyphForActionOrigin to provide future proof glyphs for + // non-Steam Input API action games. Note - this only translates the buttons directly and doesn't take into account any remapping a user has made in their configuration + virtual EInputActionOrigin GetActionOriginFromXboxOrigin( InputHandle_t inputHandle, EXboxOrigin eOrigin ) = 0; + + // Convert an origin to another controller type - for inputs not present on the other controller type this will return k_EInputActionOrigin_None + // When a new input type is added you will be able to pass in k_ESteamInputType_Unknown and the closest origin that your version of the SDK recognized will be returned + // ex: if a Playstation 5 controller was released this function would return Playstation 4 origins. + virtual EInputActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EInputActionOrigin eSourceOrigin ) = 0; + + // Get the binding revision for a given device. Returns false if the handle was not valid or if a mapping is not yet loaded for the device + virtual bool GetDeviceBindingRevision( InputHandle_t inputHandle, int *pMajor, int *pMinor ) = 0; + + // Get the Steam Remote Play session ID associated with a device, or 0 if there is no session associated with it + // See isteamremoteplay.h for more information on Steam Remote Play sessions + virtual uint32 GetRemotePlaySessionID( InputHandle_t inputHandle ) = 0; +}; + +#define STEAMINPUT_INTERFACE_VERSION "SteamInput001" + +// Global interface accessor +inline ISteamInput *SteamInput(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamInput *, SteamInput, STEAMINPUT_INTERFACE_VERSION ); + +#endif // ISTEAMINPUT_H diff --git a/public/steam/isteaminventory.h b/public/steam/isteaminventory.h new file mode 100644 index 0000000..1cd21b8 --- /dev/null +++ b/public/steam/isteaminventory.h @@ -0,0 +1,437 @@ +//====== Copyright 1996-2014 Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to Steam Inventory +// +//============================================================================= + +#ifndef ISTEAMINVENTORY_H +#define ISTEAMINVENTORY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +// Every individual instance of an item has a globally-unique ItemInstanceID. +// This ID is unique to the combination of (player, specific item instance) +// and will not be transferred to another player or re-used for another item. +typedef uint64 SteamItemInstanceID_t; + +static const SteamItemInstanceID_t k_SteamItemInstanceIDInvalid = (SteamItemInstanceID_t)~0; + +// Types of items in your game are identified by a 32-bit "item definition number". +// Valid definition numbers are between 1 and 999999999; numbers less than or equal to +// zero are invalid, and numbers greater than or equal to one billion (1x10^9) are +// reserved for internal Steam use. +typedef int32 SteamItemDef_t; + + +enum ESteamItemFlags +{ + // Item status flags - these flags are permanently attached to specific item instances + k_ESteamItemNoTrade = 1 << 0, // This item is account-locked and cannot be traded or given away. + + // Action confirmation flags - these flags are set one time only, as part of a result set + k_ESteamItemRemoved = 1 << 8, // The item has been destroyed, traded away, expired, or otherwise invalidated + k_ESteamItemConsumed = 1 << 9, // The item quantity has been decreased by 1 via ConsumeItem API. + + // All other flag bits are currently reserved for internal Steam use at this time. + // Do not assume anything about the state of other flags which are not defined here. +}; + +struct SteamItemDetails_t +{ + SteamItemInstanceID_t m_itemId; + SteamItemDef_t m_iDefinition; + uint16 m_unQuantity; + uint16 m_unFlags; // see ESteamItemFlags +}; + +typedef int32 SteamInventoryResult_t; + +static const SteamInventoryResult_t k_SteamInventoryResultInvalid = -1; + +typedef uint64 SteamInventoryUpdateHandle_t; +const SteamInventoryUpdateHandle_t k_SteamInventoryUpdateHandleInvalid = 0xffffffffffffffffull; + +//----------------------------------------------------------------------------- +// Purpose: Steam Inventory query and manipulation API +//----------------------------------------------------------------------------- +class ISteamInventory +{ +public: + + // INVENTORY ASYNC RESULT MANAGEMENT + // + // Asynchronous inventory queries always output a result handle which can be used with + // GetResultStatus, GetResultItems, etc. A SteamInventoryResultReady_t callback will + // be triggered when the asynchronous result becomes ready (or fails). + // + + // Find out the status of an asynchronous inventory result handle. Possible values: + // k_EResultPending - still in progress + // k_EResultOK - done, result ready + // k_EResultExpired - done, result ready, maybe out of date (see DeserializeResult) + // k_EResultInvalidParam - ERROR: invalid API call parameters + // k_EResultServiceUnavailable - ERROR: service temporarily down, you may retry later + // k_EResultLimitExceeded - ERROR: operation would exceed per-user inventory limits + // k_EResultFail - ERROR: unknown / generic error + STEAM_METHOD_DESC(Find out the status of an asynchronous inventory result handle.) + virtual EResult GetResultStatus( SteamInventoryResult_t resultHandle ) = 0; + + // Copies the contents of a result set into a flat array. The specific + // contents of the result set depend on which query which was used. + STEAM_METHOD_DESC(Copies the contents of a result set into a flat array. The specific contents of the result set depend on which query which was used.) + virtual bool GetResultItems( SteamInventoryResult_t resultHandle, + STEAM_OUT_ARRAY_COUNT( punOutItemsArraySize,Output array) SteamItemDetails_t *pOutItemsArray, + uint32 *punOutItemsArraySize ) = 0; + + // In combination with GetResultItems, you can use GetResultItemProperty to retrieve + // dynamic string properties for a given item returned in the result set. + // + // Property names are always composed of ASCII letters, numbers, and/or underscores. + // + // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available + // property names. + // + // If pchValueBuffer is NULL, *punValueBufferSize will contain the + // suggested buffer size. Otherwise it will be the number of bytes actually copied + // to pchValueBuffer. If the results do not fit in the given buffer, partial + // results may be copied. + virtual bool GetResultItemProperty( SteamInventoryResult_t resultHandle, + uint32 unItemIndex, + const char *pchPropertyName, + STEAM_OUT_STRING_COUNT( punValueBufferSizeOut ) char *pchValueBuffer, uint32 *punValueBufferSizeOut ) = 0; + + // Returns the server time at which the result was generated. Compare against + // the value of IClientUtils::GetServerRealTime() to determine age. + STEAM_METHOD_DESC(Returns the server time at which the result was generated. Compare against the value of IClientUtils::GetServerRealTime() to determine age.) + virtual uint32 GetResultTimestamp( SteamInventoryResult_t resultHandle ) = 0; + + // Returns true if the result belongs to the target steam ID, false if the + // result does not. This is important when using DeserializeResult, to verify + // that a remote player is not pretending to have a different user's inventory. + STEAM_METHOD_DESC(Returns true if the result belongs to the target steam ID or false if the result does not. This is important when using DeserializeResult to verify that a remote player is not pretending to have a different users inventory.) + virtual bool CheckResultSteamID( SteamInventoryResult_t resultHandle, CSteamID steamIDExpected ) = 0; + + // Destroys a result handle and frees all associated memory. + STEAM_METHOD_DESC(Destroys a result handle and frees all associated memory.) + virtual void DestroyResult( SteamInventoryResult_t resultHandle ) = 0; + + + // INVENTORY ASYNC QUERY + // + + // Captures the entire state of the current user's Steam inventory. + // You must call DestroyResult on this handle when you are done with it. + // Returns false and sets *pResultHandle to zero if inventory is unavailable. + // Note: calls to this function are subject to rate limits and may return + // cached results if called too frequently. It is suggested that you call + // this function only when you are about to display the user's full inventory, + // or if you expect that the inventory may have changed. + STEAM_METHOD_DESC(Captures the entire state of the current users Steam inventory.) + virtual bool GetAllItems( SteamInventoryResult_t *pResultHandle ) = 0; + + + // Captures the state of a subset of the current user's Steam inventory, + // identified by an array of item instance IDs. The results from this call + // can be serialized and passed to other players to "prove" that the current + // user owns specific items, without exposing the user's entire inventory. + // For example, you could call GetItemsByID with the IDs of the user's + // currently equipped cosmetic items and serialize this to a buffer, and + // then transmit this buffer to other players upon joining a game. + STEAM_METHOD_DESC(Captures the state of a subset of the current users Steam inventory identified by an array of item instance IDs.) + virtual bool GetItemsByID( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT( unCountInstanceIDs ) const SteamItemInstanceID_t *pInstanceIDs, uint32 unCountInstanceIDs ) = 0; + + + // RESULT SERIALIZATION AND AUTHENTICATION + // + // Serialized result sets contain a short signature which can't be forged + // or replayed across different game sessions. A result set can be serialized + // on the local client, transmitted to other players via your game networking, + // and deserialized by the remote players. This is a secure way of preventing + // hackers from lying about posessing rare/high-value items. + + // Serializes a result set with signature bytes to an output buffer. Pass + // NULL as an output buffer to get the required size via punOutBufferSize. + // The size of a serialized result depends on the number items which are being + // serialized. When securely transmitting items to other players, it is + // recommended to use "GetItemsByID" first to create a minimal result set. + // Results have a built-in timestamp which will be considered "expired" after + // an hour has elapsed. See DeserializeResult for expiration handling. + virtual bool SerializeResult( SteamInventoryResult_t resultHandle, STEAM_OUT_BUFFER_COUNT(punOutBufferSize) void *pOutBuffer, uint32 *punOutBufferSize ) = 0; + + // Deserializes a result set and verifies the signature bytes. Returns false + // if bRequireFullOnlineVerify is set but Steam is running in Offline mode. + // Otherwise returns true and then delivers error codes via GetResultStatus. + // + // The bRESERVED_MUST_BE_FALSE flag is reserved for future use and should not + // be set to true by your game at this time. + // + // DeserializeResult has a potential soft-failure mode where the handle status + // is set to k_EResultExpired. GetResultItems() still succeeds in this mode. + // The "expired" result could indicate that the data may be out of date - not + // just due to timed expiration (one hour), but also because one of the items + // in the result set may have been traded or consumed since the result set was + // generated. You could compare the timestamp from GetResultTimestamp() to + // ISteamUtils::GetServerRealTime() to determine how old the data is. You could + // simply ignore the "expired" result code and continue as normal, or you + // could challenge the player with expired data to send an updated result set. + virtual bool DeserializeResult( SteamInventoryResult_t *pOutResultHandle, STEAM_BUFFER_COUNT(punOutBufferSize) const void *pBuffer, uint32 unBufferSize, bool bRESERVED_MUST_BE_FALSE = false ) = 0; + + + // INVENTORY ASYNC MODIFICATION + // + + // GenerateItems() creates one or more items and then generates a SteamInventoryCallback_t + // notification with a matching nCallbackContext parameter. This API is only intended + // for prototyping - it is only usable by Steam accounts that belong to the publisher group + // for your game. + // If punArrayQuantity is not NULL, it should be the same length as pArrayItems and should + // describe the quantity of each item to generate. + virtual bool GenerateItems( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, STEAM_ARRAY_COUNT(unArrayLength) const uint32 *punArrayQuantity, uint32 unArrayLength ) = 0; + + // GrantPromoItems() checks the list of promotional items for which the user may be eligible + // and grants the items (one time only). On success, the result set will include items which + // were granted, if any. If no items were granted because the user isn't eligible for any + // promotions, this is still considered a success. + STEAM_METHOD_DESC(GrantPromoItems() checks the list of promotional items for which the user may be eligible and grants the items (one time only).) + virtual bool GrantPromoItems( SteamInventoryResult_t *pResultHandle ) = 0; + + // AddPromoItem() / AddPromoItems() are restricted versions of GrantPromoItems(). Instead of + // scanning for all eligible promotional items, the check is restricted to a single item + // definition or set of item definitions. This can be useful if your game has custom UI for + // showing a specific promo item to the user. + virtual bool AddPromoItem( SteamInventoryResult_t *pResultHandle, SteamItemDef_t itemDef ) = 0; + virtual bool AddPromoItems( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, uint32 unArrayLength ) = 0; + + // ConsumeItem() removes items from the inventory, permanently. They cannot be recovered. + // Not for the faint of heart - if your game implements item removal at all, a high-friction + // UI confirmation process is highly recommended. + STEAM_METHOD_DESC(ConsumeItem() removes items from the inventory permanently.) + virtual bool ConsumeItem( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemConsume, uint32 unQuantity ) = 0; + + // ExchangeItems() is an atomic combination of item generation and consumption. + // It can be used to implement crafting recipes or transmutations, or items which unpack + // themselves into other items (e.g., a chest). + // Exchange recipes are defined in the ItemDef, and explicitly list the required item + // types and resulting generated type. + // Exchange recipes are evaluated atomically by the Inventory Service; if the supplied + // components do not match the recipe, or do not contain sufficient quantity, the + // exchange will fail. + virtual bool ExchangeItems( SteamInventoryResult_t *pResultHandle, + STEAM_ARRAY_COUNT(unArrayGenerateLength) const SteamItemDef_t *pArrayGenerate, STEAM_ARRAY_COUNT(unArrayGenerateLength) const uint32 *punArrayGenerateQuantity, uint32 unArrayGenerateLength, + STEAM_ARRAY_COUNT(unArrayDestroyLength) const SteamItemInstanceID_t *pArrayDestroy, STEAM_ARRAY_COUNT(unArrayDestroyLength) const uint32 *punArrayDestroyQuantity, uint32 unArrayDestroyLength ) = 0; + + + // TransferItemQuantity() is intended for use with items which are "stackable" (can have + // quantity greater than one). It can be used to split a stack into two, or to transfer + // quantity from one stack into another stack of identical items. To split one stack into + // two, pass k_SteamItemInstanceIDInvalid for itemIdDest and a new item will be generated. + virtual bool TransferItemQuantity( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemIdSource, uint32 unQuantity, SteamItemInstanceID_t itemIdDest ) = 0; + + + // TIMED DROPS AND PLAYTIME CREDIT + // + + // Deprecated. Calling this method is not required for proper playtime accounting. + STEAM_METHOD_DESC( Deprecated method. Playtime accounting is performed on the Steam servers. ) + virtual void SendItemDropHeartbeat() = 0; + + // Playtime credit must be consumed and turned into item drops by your game. Only item + // definitions which are marked as "playtime item generators" can be spawned. The call + // will return an empty result set if there is not enough playtime credit for a drop. + // Your game should call TriggerItemDrop at an appropriate time for the user to receive + // new items, such as between rounds or while the player is dead. Note that players who + // hack their clients could modify the value of "dropListDefinition", so do not use it + // to directly control rarity. + // See your Steamworks configuration to set playtime drop rates for individual itemdefs. + // The client library will suppress too-frequent calls to this method. + STEAM_METHOD_DESC(Playtime credit must be consumed and turned into item drops by your game.) + virtual bool TriggerItemDrop( SteamInventoryResult_t *pResultHandle, SteamItemDef_t dropListDefinition ) = 0; + + + // Deprecated. This method is not supported. + virtual bool TradeItems( SteamInventoryResult_t *pResultHandle, CSteamID steamIDTradePartner, + STEAM_ARRAY_COUNT(nArrayGiveLength) const SteamItemInstanceID_t *pArrayGive, STEAM_ARRAY_COUNT(nArrayGiveLength) const uint32 *pArrayGiveQuantity, uint32 nArrayGiveLength, + STEAM_ARRAY_COUNT(nArrayGetLength) const SteamItemInstanceID_t *pArrayGet, STEAM_ARRAY_COUNT(nArrayGetLength) const uint32 *pArrayGetQuantity, uint32 nArrayGetLength ) = 0; + + + // ITEM DEFINITIONS + // + // Item definitions are a mapping of "definition IDs" (integers between 1 and 1000000) + // to a set of string properties. Some of these properties are required to display items + // on the Steam community web site. Other properties can be defined by applications. + // Use of these functions is optional; there is no reason to call LoadItemDefinitions + // if your game hardcodes the numeric definition IDs (eg, purple face mask = 20, blue + // weapon mod = 55) and does not allow for adding new item types without a client patch. + // + + // LoadItemDefinitions triggers the automatic load and refresh of item definitions. + // Every time new item definitions are available (eg, from the dynamic addition of new + // item types while players are still in-game), a SteamInventoryDefinitionUpdate_t + // callback will be fired. + STEAM_METHOD_DESC(LoadItemDefinitions triggers the automatic load and refresh of item definitions.) + virtual bool LoadItemDefinitions() = 0; + + // GetItemDefinitionIDs returns the set of all defined item definition IDs (which are + // defined via Steamworks configuration, and not necessarily contiguous integers). + // If pItemDefIDs is null, the call will return true and *punItemDefIDsArraySize will + // contain the total size necessary for a subsequent call. Otherwise, the call will + // return false if and only if there is not enough space in the output array. + virtual bool GetItemDefinitionIDs( + STEAM_OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs, + STEAM_DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize ) = 0; + + // GetItemDefinitionProperty returns a string property from a given item definition. + // Note that some properties (for example, "name") may be localized and will depend + // on the current Steam language settings (see ISteamApps::GetCurrentGameLanguage). + // Property names are always composed of ASCII letters, numbers, and/or underscores. + // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available + // property names. If pchValueBuffer is NULL, *punValueBufferSize will contain the + // suggested buffer size. Otherwise it will be the number of bytes actually copied + // to pchValueBuffer. If the results do not fit in the given buffer, partial + // results may be copied. + virtual bool GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPropertyName, + STEAM_OUT_STRING_COUNT(punValueBufferSizeOut) char *pchValueBuffer, uint32 *punValueBufferSizeOut ) = 0; + + // Request the list of "eligible" promo items that can be manually granted to the given + // user. These are promo items of type "manual" that won't be granted automatically. + // An example usage of this is an item that becomes available every week. + STEAM_CALL_RESULT( SteamInventoryEligiblePromoItemDefIDs_t ) + virtual SteamAPICall_t RequestEligiblePromoItemDefinitionsIDs( CSteamID steamID ) = 0; + + // After handling a SteamInventoryEligiblePromoItemDefIDs_t call result, use this + // function to pull out the list of item definition ids that the user can be + // manually granted via the AddPromoItems() call. + virtual bool GetEligiblePromoItemDefinitionIDs( + CSteamID steamID, + STEAM_OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs, + STEAM_DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize ) = 0; + + // Starts the purchase process for the given item definitions. The callback SteamInventoryStartPurchaseResult_t + // will be posted if Steam was able to initialize the transaction. + // + // Once the purchase has been authorized and completed by the user, the callback SteamInventoryResultReady_t + // will be posted. + STEAM_CALL_RESULT( SteamInventoryStartPurchaseResult_t ) + virtual SteamAPICall_t StartPurchase( STEAM_ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, STEAM_ARRAY_COUNT(unArrayLength) const uint32 *punArrayQuantity, uint32 unArrayLength ) = 0; + + // Request current prices for all applicable item definitions + STEAM_CALL_RESULT( SteamInventoryRequestPricesResult_t ) + virtual SteamAPICall_t RequestPrices() = 0; + + // Returns the number of items with prices. Need to call RequestPrices() first. + virtual uint32 GetNumItemsWithPrices() = 0; + + // Returns item definition ids and their prices in the user's local currency. + // Need to call RequestPrices() first. + virtual bool GetItemsWithPrices( STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pArrayItemDefs, Items with prices) SteamItemDef_t *pArrayItemDefs, + STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pPrices, List of prices for the given item defs) uint64 *pCurrentPrices, + STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pPrices, List of prices for the given item defs) uint64 *pBasePrices, + uint32 unArrayLength ) = 0; + + // Retrieves the price for the item definition id + // Returns false if there is no price stored for the item definition. + virtual bool GetItemPrice( SteamItemDef_t iDefinition, uint64 *pCurrentPrice, uint64 *pBasePrice ) = 0; + + // Create a request to update properties on items + virtual SteamInventoryUpdateHandle_t StartUpdateProperties() = 0; + // Remove the property on the item + virtual bool RemoveProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName ) = 0; + // Accessor methods to set properties on items + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, const char *pchPropertyValue ) = 0; + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, bool bValue ) = 0; + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, int64 nValue ) = 0; + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, float flValue ) = 0; + // Submit the update request by handle + virtual bool SubmitUpdateProperties( SteamInventoryUpdateHandle_t handle, SteamInventoryResult_t * pResultHandle ) = 0; + +}; + +#define STEAMINVENTORY_INTERFACE_VERSION "STEAMINVENTORY_INTERFACE_V003" + +// Global interface accessor +inline ISteamInventory *SteamInventory(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamInventory *, SteamInventory, STEAMINVENTORY_INTERFACE_VERSION ); + +// Global accessor for the gameserver client +inline ISteamInventory *SteamGameServerInventory(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamInventory *, SteamGameServerInventory, STEAMINVENTORY_INTERFACE_VERSION ); + +// SteamInventoryResultReady_t callbacks are fired whenever asynchronous +// results transition from "Pending" to "OK" or an error state. There will +// always be exactly one callback per handle. +struct SteamInventoryResultReady_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 0 }; + SteamInventoryResult_t m_handle; + EResult m_result; +}; + + +// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems +// successfully returns a result which is newer / fresher than the last +// known result. (It will not trigger if the inventory hasn't changed, +// or if results from two overlapping calls are reversed in flight and +// the earlier result is already known to be stale/out-of-date.) +// The normal ResultReady callback will still be triggered immediately +// afterwards; this is an additional notification for your convenience. +struct SteamInventoryFullUpdate_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 1 }; + SteamInventoryResult_t m_handle; +}; + + +// A SteamInventoryDefinitionUpdate_t callback is triggered whenever +// item definitions have been updated, which could be in response to +// LoadItemDefinitions() or any other async request which required +// a definition update in order to process results from the server. +struct SteamInventoryDefinitionUpdate_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 2 }; +}; + +// Returned +struct SteamInventoryEligiblePromoItemDefIDs_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 3 }; + EResult m_result; + CSteamID m_steamID; + int m_numEligiblePromoItemDefs; + bool m_bCachedData; // indicates that the data was retrieved from the cache and not the server +}; + +// Triggered from StartPurchase call +struct SteamInventoryStartPurchaseResult_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 4 }; + EResult m_result; + uint64 m_ulOrderID; + uint64 m_ulTransID; +}; + + +// Triggered from RequestPrices +struct SteamInventoryRequestPricesResult_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 5 }; + EResult m_result; + char m_rgchCurrency[4]; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMCONTROLLER_H diff --git a/public/steam/isteammasterserverupdater.h b/public/steam/isteammasterserverupdater.h new file mode 100644 index 0000000..4be0ca5 --- /dev/null +++ b/public/steam/isteammasterserverupdater.h @@ -0,0 +1 @@ +#error "This file isn't used any more" diff --git a/public/steam/isteammatchmaking.h b/public/steam/isteammatchmaking.h new file mode 100644 index 0000000..248fc5f --- /dev/null +++ b/public/steam/isteammatchmaking.h @@ -0,0 +1,1088 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam managing game server/client match making +// +//============================================================================= + +#ifndef ISTEAMMATCHMAKING +#define ISTEAMMATCHMAKING +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "matchmakingtypes.h" +#include "isteamfriends.h" + +// lobby type description +enum ELobbyType +{ + k_ELobbyTypePrivate = 0, // only way to join the lobby is to invite to someone else + k_ELobbyTypeFriendsOnly = 1, // shows for friends or invitees, but not in lobby list + k_ELobbyTypePublic = 2, // visible for friends and in lobby list + k_ELobbyTypeInvisible = 3, // returned by search, but not visible to other friends + // useful if you want a user in two lobbies, for example matching groups together + // a user can be in only one regular lobby, and up to two invisible lobbies + k_ELobbyTypePrivateUnique = 4, // private, unique and does not delete when empty - only one of these may exist per unique keypair set + // can only create from webapi +}; + +// lobby search filter tools +enum ELobbyComparison +{ + k_ELobbyComparisonEqualToOrLessThan = -2, + k_ELobbyComparisonLessThan = -1, + k_ELobbyComparisonEqual = 0, + k_ELobbyComparisonGreaterThan = 1, + k_ELobbyComparisonEqualToOrGreaterThan = 2, + k_ELobbyComparisonNotEqual = 3, +}; + +// lobby search distance. Lobby results are sorted from closest to farthest. +enum ELobbyDistanceFilter +{ + k_ELobbyDistanceFilterClose, // only lobbies in the same immediate region will be returned + k_ELobbyDistanceFilterDefault, // only lobbies in the same region or near by regions + k_ELobbyDistanceFilterFar, // for games that don't have many latency requirements, will return lobbies about half-way around the globe + k_ELobbyDistanceFilterWorldwide, // no filtering, will match lobbies as far as India to NY (not recommended, expect multiple seconds of latency between the clients) +}; + +// maximum number of characters a lobby metadata key can be +#define k_nMaxLobbyKeyLength 255 + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to favorites +// and to operate on game lobbies. +//----------------------------------------------------------------------------- +class ISteamMatchmaking +{ +public: + // game server favorites storage + // saves basic details about a multiplayer game server locally + + // returns the number of favorites servers the user has stored + virtual int GetFavoriteGameCount() = 0; + + // returns the details of the game server + // iGame is of range [0,GetFavoriteGameCount()) + // *pnIP, *pnConnPort are filled in the with IP:port of the game server + // *punFlags specify whether the game server was stored as an explicit favorite or in the history of connections + // *pRTime32LastPlayedOnServer is filled in the with the Unix time the favorite was added + virtual bool GetFavoriteGame( int iGame, AppId_t *pnAppID, uint32 *pnIP, uint16 *pnConnPort, uint16 *pnQueryPort, uint32 *punFlags, uint32 *pRTime32LastPlayedOnServer ) = 0; + + // adds the game server to the local list; updates the time played of the server if it already exists in the list + virtual int AddFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags, uint32 rTime32LastPlayedOnServer ) = 0; + + // removes the game server from the local storage; returns true if one was removed + virtual bool RemoveFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags ) = 0; + + /////// + // Game lobby functions + + // Get a list of relevant lobbies + // this is an asynchronous request + // results will be returned by LobbyMatchList_t callback & call result, with the number of lobbies found + // this will never return lobbies that are full + // to add more filter, the filter calls below need to be call before each and every RequestLobbyList() call + // use the CCallResult<> object in steam_api.h to match the SteamAPICall_t call result to a function in an object, e.g. + /* + class CMyLobbyListManager + { + CCallResult m_CallResultLobbyMatchList; + void FindLobbies() + { + // SteamMatchmaking()->AddRequestLobbyListFilter*() functions would be called here, before RequestLobbyList() + SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList(); + m_CallResultLobbyMatchList.Set( hSteamAPICall, this, &CMyLobbyListManager::OnLobbyMatchList ); + } + + void OnLobbyMatchList( LobbyMatchList_t *pLobbyMatchList, bool bIOFailure ) + { + // lobby list has be retrieved from Steam back-end, use results + } + } + */ + // + STEAM_CALL_RESULT( LobbyMatchList_t ) + virtual SteamAPICall_t RequestLobbyList() = 0; + // filters for lobbies + // this needs to be called before RequestLobbyList() to take effect + // these are cleared on each call to RequestLobbyList() + virtual void AddRequestLobbyListStringFilter( const char *pchKeyToMatch, const char *pchValueToMatch, ELobbyComparison eComparisonType ) = 0; + // numerical comparison + virtual void AddRequestLobbyListNumericalFilter( const char *pchKeyToMatch, int nValueToMatch, ELobbyComparison eComparisonType ) = 0; + // returns results closest to the specified value. Multiple near filters can be added, with early filters taking precedence + virtual void AddRequestLobbyListNearValueFilter( const char *pchKeyToMatch, int nValueToBeCloseTo ) = 0; + // returns only lobbies with the specified number of slots available + virtual void AddRequestLobbyListFilterSlotsAvailable( int nSlotsAvailable ) = 0; + // sets the distance for which we should search for lobbies (based on users IP address to location map on the Steam backed) + virtual void AddRequestLobbyListDistanceFilter( ELobbyDistanceFilter eLobbyDistanceFilter ) = 0; + // sets how many results to return, the lower the count the faster it is to download the lobby results & details to the client + virtual void AddRequestLobbyListResultCountFilter( int cMaxResults ) = 0; + + virtual void AddRequestLobbyListCompatibleMembersFilter( CSteamID steamIDLobby ) = 0; + + // returns the CSteamID of a lobby, as retrieved by a RequestLobbyList call + // should only be called after a LobbyMatchList_t callback is received + // iLobby is of the range [0, LobbyMatchList_t::m_nLobbiesMatching) + // the returned CSteamID::IsValid() will be false if iLobby is out of range + virtual CSteamID GetLobbyByIndex( int iLobby ) = 0; + + // Create a lobby on the Steam servers. + // If private, then the lobby will not be returned by any RequestLobbyList() call; the CSteamID + // of the lobby will need to be communicated via game channels or via InviteUserToLobby() + // this is an asynchronous request + // results will be returned by LobbyCreated_t callback and call result; lobby is joined & ready to use at this point + // a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) + STEAM_CALL_RESULT( LobbyCreated_t ) + virtual SteamAPICall_t CreateLobby( ELobbyType eLobbyType, int cMaxMembers ) = 0; + + // Joins an existing lobby + // this is an asynchronous request + // results will be returned by LobbyEnter_t callback & call result, check m_EChatRoomEnterResponse to see if was successful + // lobby metadata is available to use immediately on this call completing + STEAM_CALL_RESULT( LobbyEnter_t ) + virtual SteamAPICall_t JoinLobby( CSteamID steamIDLobby ) = 0; + + // Leave a lobby; this will take effect immediately on the client side + // other users in the lobby will be notified by a LobbyChatUpdate_t callback + virtual void LeaveLobby( CSteamID steamIDLobby ) = 0; + + // Invite another user to the lobby + // the target user will receive a LobbyInvite_t callback + // will return true if the invite is successfully sent, whether or not the target responds + // returns false if the local user is not connected to the Steam servers + // if the other user clicks the join link, a GameLobbyJoinRequested_t will be posted if the user is in-game, + // or if the game isn't running yet the game will be launched with the parameter +connect_lobby <64-bit lobby id> + virtual bool InviteUserToLobby( CSteamID steamIDLobby, CSteamID steamIDInvitee ) = 0; + + // Lobby iteration, for viewing details of users in a lobby + // only accessible if the lobby user is a member of the specified lobby + // persona information for other lobby members (name, avatar, etc.) will be asynchronously received + // and accessible via ISteamFriends interface + + // returns the number of users in the specified lobby + virtual int GetNumLobbyMembers( CSteamID steamIDLobby ) = 0; + // returns the CSteamID of a user in the lobby + // iMember is of range [0,GetNumLobbyMembers()) + // note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby + virtual CSteamID GetLobbyMemberByIndex( CSteamID steamIDLobby, int iMember ) = 0; + + // Get data associated with this lobby + // takes a simple key, and returns the string associated with it + // "" will be returned if no value is set, or if steamIDLobby is invalid + virtual const char *GetLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0; + // Sets a key/value pair in the lobby metadata + // each user in the lobby will be broadcast this new value, and any new users joining will receive any existing data + // this can be used to set lobby names, map, etc. + // to reset a key, just set it to "" + // other users in the lobby will receive notification of the lobby data change via a LobbyDataUpdate_t callback + virtual bool SetLobbyData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0; + + // returns the number of metadata keys set on the specified lobby + virtual int GetLobbyDataCount( CSteamID steamIDLobby ) = 0; + + // returns a lobby metadata key/values pair by index, of range [0, GetLobbyDataCount()) + virtual bool GetLobbyDataByIndex( CSteamID steamIDLobby, int iLobbyData, char *pchKey, int cchKeyBufferSize, char *pchValue, int cchValueBufferSize ) = 0; + + // removes a metadata key from the lobby + virtual bool DeleteLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0; + + // Gets per-user metadata for someone in this lobby + virtual const char *GetLobbyMemberData( CSteamID steamIDLobby, CSteamID steamIDUser, const char *pchKey ) = 0; + // Sets per-user metadata (for the local user implicitly) + virtual void SetLobbyMemberData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0; + + // Broadcasts a chat message to the all the users in the lobby + // users in the lobby (including the local user) will receive a LobbyChatMsg_t callback + // returns true if the message is successfully sent + // pvMsgBody can be binary or text data, up to 4k + // if pvMsgBody is text, cubMsgBody should be strlen( text ) + 1, to include the null terminator + virtual bool SendLobbyChatMsg( CSteamID steamIDLobby, const void *pvMsgBody, int cubMsgBody ) = 0; + // Get a chat message as specified in a LobbyChatMsg_t callback + // iChatID is the LobbyChatMsg_t::m_iChatID value in the callback + // *pSteamIDUser is filled in with the CSteamID of the member + // *pvData is filled in with the message itself + // return value is the number of bytes written into the buffer + virtual int GetLobbyChatEntry( CSteamID steamIDLobby, int iChatID, STEAM_OUT_STRUCT() CSteamID *pSteamIDUser, void *pvData, int cubData, EChatEntryType *peChatEntryType ) = 0; + + // Refreshes metadata for a lobby you're not necessarily in right now + // you never do this for lobbies you're a member of, only if your + // this will send down all the metadata associated with a lobby + // this is an asynchronous call + // returns false if the local user is not connected to the Steam servers + // results will be returned by a LobbyDataUpdate_t callback + // if the specified lobby doesn't exist, LobbyDataUpdate_t::m_bSuccess will be set to false + virtual bool RequestLobbyData( CSteamID steamIDLobby ) = 0; + + // sets the game server associated with the lobby + // usually at this point, the users will join the specified game server + // either the IP/Port or the steamID of the game server has to be valid, depending on how you want the clients to be able to connect + virtual void SetLobbyGameServer( CSteamID steamIDLobby, uint32 unGameServerIP, uint16 unGameServerPort, CSteamID steamIDGameServer ) = 0; + // returns the details of a game server set in a lobby - returns false if there is no game server set, or that lobby doesn't exist + virtual bool GetLobbyGameServer( CSteamID steamIDLobby, uint32 *punGameServerIP, uint16 *punGameServerPort, STEAM_OUT_STRUCT() CSteamID *psteamIDGameServer ) = 0; + + // set the limit on the # of users who can join the lobby + virtual bool SetLobbyMemberLimit( CSteamID steamIDLobby, int cMaxMembers ) = 0; + // returns the current limit on the # of users who can join the lobby; returns 0 if no limit is defined + virtual int GetLobbyMemberLimit( CSteamID steamIDLobby ) = 0; + + // updates which type of lobby it is + // only lobbies that are k_ELobbyTypePublic or k_ELobbyTypeInvisible, and are set to joinable, will be returned by RequestLobbyList() calls + virtual bool SetLobbyType( CSteamID steamIDLobby, ELobbyType eLobbyType ) = 0; + + // sets whether or not a lobby is joinable - defaults to true for a new lobby + // if set to false, no user can join, even if they are a friend or have been invited + virtual bool SetLobbyJoinable( CSteamID steamIDLobby, bool bLobbyJoinable ) = 0; + + // returns the current lobby owner + // you must be a member of the lobby to access this + // there always one lobby owner - if the current owner leaves, another user will become the owner + // it is possible (bur rare) to join a lobby just as the owner is leaving, thus entering a lobby with self as the owner + virtual CSteamID GetLobbyOwner( CSteamID steamIDLobby ) = 0; + + // changes who the lobby owner is + // you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby + // after completion, the local user will no longer be the owner + virtual bool SetLobbyOwner( CSteamID steamIDLobby, CSteamID steamIDNewOwner ) = 0; + + // link two lobbies for the purposes of checking player compatibility + // you must be the lobby owner of both lobbies + virtual bool SetLinkedLobby( CSteamID steamIDLobby, CSteamID steamIDLobbyDependent ) = 0; + +#ifdef _PS3 + // changes who the lobby owner is + // you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby + // after completion, the local user will no longer be the owner + virtual void CheckForPSNGameBootInvite( unsigned int iGameBootAttributes ) = 0; +#endif + STEAM_CALL_BACK( LobbyChatUpdate_t ) +}; +#define STEAMMATCHMAKING_INTERFACE_VERSION "SteamMatchMaking009" + +// Global interface accessor +inline ISteamMatchmaking *SteamMatchmaking(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamMatchmaking *, SteamMatchmaking, STEAMMATCHMAKING_INTERFACE_VERSION ); + +//----------------------------------------------------------------------------- +// Callback interfaces for server list functions (see ISteamMatchmakingServers below) +// +// The idea here is that your game code implements objects that implement these +// interfaces to receive callback notifications after calling asynchronous functions +// inside the ISteamMatchmakingServers() interface below. +// +// This is different than normal Steam callback handling due to the potentially +// large size of server lists. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typedef for handle type you will receive when requesting server list. +//----------------------------------------------------------------------------- +typedef void* HServerListRequest; + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after a server list refresh +// or an individual server update. +// +// Since you get these callbacks after requesting full list refreshes you will +// usually implement this interface inside an object like CServerBrowser. If that +// object is getting destructed you should use ISteamMatchMakingServers()->CancelQuery() +// to cancel any in-progress queries so you don't get a callback into the destructed +// object and crash. +//----------------------------------------------------------------------------- +class ISteamMatchmakingServerListResponse +{ +public: + // Server has responded ok with updated data + virtual void ServerResponded( HServerListRequest hRequest, int iServer ) = 0; + + // Server has failed to respond + virtual void ServerFailedToRespond( HServerListRequest hRequest, int iServer ) = 0; + + // A list refresh you had initiated is now 100% completed + virtual void RefreshComplete( HServerListRequest hRequest, EMatchMakingServerResponse response ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after pinging an individual server +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->PingServer() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingPingResponse +{ +public: + // Server has responded successfully and has updated data + virtual void ServerResponded( gameserveritem_t &server ) = 0; + + // Server failed to respond to the ping request + virtual void ServerFailedToRespond() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after requesting details on +// who is playing on a particular server. +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->PlayerDetails() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingPlayersResponse +{ +public: + // Got data on a new player on the server -- you'll get this callback once per player + // on the server which you have requested player data on. + virtual void AddPlayerToList( const char *pchName, int nScore, float flTimePlayed ) = 0; + + // The server failed to respond to the request for player details + virtual void PlayersFailedToRespond() = 0; + + // The server has finished responding to the player details request + // (ie, you won't get anymore AddPlayerToList callbacks) + virtual void PlayersRefreshComplete() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after requesting rules +// details on a particular server. +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->ServerRules() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingRulesResponse +{ +public: + // Got data on a rule on the server -- you'll get one of these per rule defined on + // the server you are querying + virtual void RulesResponded( const char *pchRule, const char *pchValue ) = 0; + + // The server failed to respond to the request for rule details + virtual void RulesFailedToRespond() = 0; + + // The server has finished responding to the rule details request + // (ie, you won't get anymore RulesResponded callbacks) + virtual void RulesRefreshComplete() = 0; +}; + + +//----------------------------------------------------------------------------- +// Typedef for handle type you will receive when querying details on an individual server. +//----------------------------------------------------------------------------- +typedef int HServerQuery; +const int HSERVERQUERY_INVALID = 0xffffffff; + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to game lists and details +//----------------------------------------------------------------------------- +class ISteamMatchmakingServers +{ +public: + // Request a new list of servers of a particular type. These calls each correspond to one of the EMatchMakingType values. + // Each call allocates a new asynchronous request object. + // Request object must be released by calling ReleaseRequest( hServerListRequest ) + virtual HServerListRequest RequestInternetServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestLANServerList( AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFriendsServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFavoritesServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestHistoryServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestSpectatorServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + + // Releases the asynchronous request object and cancels any pending query on it if there's a pending query in progress. + // RefreshComplete callback is not posted when request is released. + virtual void ReleaseRequest( HServerListRequest hServerListRequest ) = 0; + + /* the filter operation codes that go in the key part of MatchMakingKeyValuePair_t should be one of these: + + "map" + - Server passes the filter if the server is playing the specified map. + "gamedataand" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) contains all of the + specified strings. The value field is a comma-delimited list of strings to match. + "gamedataor" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) contains at least one of the + specified strings. The value field is a comma-delimited list of strings to match. + "gamedatanor" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) does not contain any + of the specified strings. The value field is a comma-delimited list of strings to check. + "gametagsand" + - Server passes the filter if the server's game tags (ISteamGameServer::SetGameTags) contains all + of the specified strings. The value field is a comma-delimited list of strings to check. + "gametagsnor" + - Server passes the filter if the server's game tags (ISteamGameServer::SetGameTags) does not contain any + of the specified strings. The value field is a comma-delimited list of strings to check. + "and" (x1 && x2 && ... && xn) + "or" (x1 || x2 || ... || xn) + "nand" !(x1 && x2 && ... && xn) + "nor" !(x1 || x2 || ... || xn) + - Performs Boolean operation on the following filters. The operand to this filter specifies + the "size" of the Boolean inputs to the operation, in Key/value pairs. (The keyvalue + pairs must immediately follow, i.e. this is a prefix logical operator notation.) + In the simplest case where Boolean expressions are not nested, this is simply + the number of operands. + + For example, to match servers on a particular map or with a particular tag, would would + use these filters. + + ( server.map == "cp_dustbowl" || server.gametags.contains("payload") ) + "or", "2" + "map", "cp_dustbowl" + "gametagsand", "payload" + + If logical inputs are nested, then the operand specifies the size of the entire + "length" of its operands, not the number of immediate children. + + ( server.map == "cp_dustbowl" || ( server.gametags.contains("payload") && !server.gametags.contains("payloadrace") ) ) + "or", "4" + "map", "cp_dustbowl" + "and", "2" + "gametagsand", "payload" + "gametagsnor", "payloadrace" + + Unary NOT can be achieved using either "nand" or "nor" with a single operand. + + "addr" + - Server passes the filter if the server's query address matches the specified IP or IP:port. + "gameaddr" + - Server passes the filter if the server's game address matches the specified IP or IP:port. + + The following filter operations ignore the "value" part of MatchMakingKeyValuePair_t + + "dedicated" + - Server passes the filter if it passed true to SetDedicatedServer. + "secure" + - Server passes the filter if the server is VAC-enabled. + "notfull" + - Server passes the filter if the player count is less than the reported max player count. + "hasplayers" + - Server passes the filter if the player count is greater than zero. + "noplayers" + - Server passes the filter if it doesn't have any players. + "linux" + - Server passes the filter if it's a linux server + */ + + // Get details on a given server in the list, you can get the valid range of index + // values by calling GetServerCount(). You will also receive index values in + // ISteamMatchmakingServerListResponse::ServerResponded() callbacks + virtual gameserveritem_t *GetServerDetails( HServerListRequest hRequest, int iServer ) = 0; + + // Cancel an request which is operation on the given list type. You should call this to cancel + // any in-progress requests before destructing a callback object that may have been passed + // to one of the above list request calls. Not doing so may result in a crash when a callback + // occurs on the destructed object. + // Canceling a query does not release the allocated request handle. + // The request handle must be released using ReleaseRequest( hRequest ) + virtual void CancelQuery( HServerListRequest hRequest ) = 0; + + // Ping every server in your list again but don't update the list of servers + // Query callback installed when the server list was requested will be used + // again to post notifications and RefreshComplete, so the callback must remain + // valid until another RefreshComplete is called on it or the request + // is released with ReleaseRequest( hRequest ) + virtual void RefreshQuery( HServerListRequest hRequest ) = 0; + + // Returns true if the list is currently refreshing its server list + virtual bool IsRefreshing( HServerListRequest hRequest ) = 0; + + // How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1 + virtual int GetServerCount( HServerListRequest hRequest ) = 0; + + // Refresh a single server inside of a query (rather than all the servers ) + virtual void RefreshServer( HServerListRequest hRequest, int iServer ) = 0; + + + //----------------------------------------------------------------------------- + // Queries to individual servers directly via IP/Port + //----------------------------------------------------------------------------- + + // Request updated ping time and other details from a single server + virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0; + + // Request the list of players currently playing on a server + virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0; + + // Request the list of rules that the server is running (See ISteamGameServer::SetKeyValue() to set the rules server side) + virtual HServerQuery ServerRules( uint32 unIP, uint16 usPort, ISteamMatchmakingRulesResponse *pRequestServersResponse ) = 0; + + // Cancel an outstanding Ping/Players/Rules query from above. You should call this to cancel + // any in-progress requests before destructing a callback object that may have been passed + // to one of the above calls to avoid crashing when callbacks occur. + virtual void CancelServerQuery( HServerQuery hServerQuery ) = 0; +}; +#define STEAMMATCHMAKINGSERVERS_INTERFACE_VERSION "SteamMatchMakingServers002" + +// Global interface accessor +inline ISteamMatchmakingServers *SteamMatchmakingServers(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamMatchmakingServers *, SteamMatchmakingServers, STEAMMATCHMAKINGSERVERS_INTERFACE_VERSION ); + +// game server flags +const uint32 k_unFavoriteFlagNone = 0x00; +const uint32 k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list +const uint32 k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list + + +//----------------------------------------------------------------------------- +// Purpose: Used in ChatInfo messages - fields specific to a chat member - must fit in a uint32 +//----------------------------------------------------------------------------- +enum EChatMemberStateChange +{ + // Specific to joining / leaving the chatroom + k_EChatMemberStateChangeEntered = 0x0001, // This user has joined or is joining the chat room + k_EChatMemberStateChangeLeft = 0x0002, // This user has left or is leaving the chat room + k_EChatMemberStateChangeDisconnected = 0x0004, // User disconnected without leaving the chat first + k_EChatMemberStateChangeKicked = 0x0008, // User kicked + k_EChatMemberStateChangeBanned = 0x0010, // User kicked and banned +}; + +// returns true of the flags indicate that a user has been removed from the chat +#define BChatMemberStateChangeRemoved( rgfChatMemberStateChangeFlags ) ( rgfChatMemberStateChangeFlags & ( k_EChatMemberStateChangeDisconnected | k_EChatMemberStateChangeLeft | k_EChatMemberStateChangeKicked | k_EChatMemberStateChangeBanned ) ) + + + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to favorites +// and to operate on game lobbies. +//----------------------------------------------------------------------------- +class ISteamGameSearch +{ +public: + // ============================================================================================= + // Game Player APIs + + // a keyname and a list of comma separated values: one of which is must be found in order for the match to qualify + // fails if a search is currently in progress + virtual EGameSearchErrorCode_t AddGameSearchParams( const char *pchKeyToFind, const char *pchValuesToFind ) = 0; + + // all players in lobby enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress + // if not the owner of the lobby or search already in progress this call fails + // periodic callbacks will be sent as queue time estimates change + virtual EGameSearchErrorCode_t SearchForGameWithLobby( CSteamID steamIDLobby, int nPlayerMin, int nPlayerMax ) = 0; + + // user enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress + // periodic callbacks will be sent as queue time estimates change + virtual EGameSearchErrorCode_t SearchForGameSolo( int nPlayerMin, int nPlayerMax ) = 0; + + // after receiving SearchForGameResultCallback_t, accept or decline the game + // multiple SearchForGameResultCallback_t will follow as players accept game until the host starts or cancels the game + virtual EGameSearchErrorCode_t AcceptGame() = 0; + virtual EGameSearchErrorCode_t DeclineGame() = 0; + + // after receiving GameStartedByHostCallback_t get connection details to server + virtual EGameSearchErrorCode_t RetrieveConnectionDetails( CSteamID steamIDHost, char *pchConnectionDetails, int cubConnectionDetails ) = 0; + + // leaves queue if still waiting + virtual EGameSearchErrorCode_t EndGameSearch() = 0; + + // ============================================================================================= + // Game Host APIs + + // a keyname and a list of comma separated values: all the values you allow + virtual EGameSearchErrorCode_t SetGameHostParams( const char *pchKey, const char *pchValue ) = 0; + + // set connection details for players once game is found so they can connect to this server + virtual EGameSearchErrorCode_t SetConnectionDetails( const char *pchConnectionDetails, int cubConnectionDetails ) = 0; + + // mark server as available for more players with nPlayerMin,nPlayerMax desired + // accept no lobbies with playercount greater than nMaxTeamSize + // the set of lobbies returned must be partitionable into teams of no more than nMaxTeamSize + // RequestPlayersForGameNotificationCallback_t callback will be sent when the search has started + // multple RequestPlayersForGameResultCallback_t callbacks will follow when players are found + virtual EGameSearchErrorCode_t RequestPlayersForGame( int nPlayerMin, int nPlayerMax, int nMaxTeamSize ) = 0; + + // accept the player list and release connection details to players + // players will only be given connection details and host steamid when this is called + // ( allows host to accept after all players confirm, some confirm, or none confirm. decision is entirely up to the host ) + virtual EGameSearchErrorCode_t HostConfirmGameStart( uint64 ullUniqueGameID ) = 0; + + // cancel request and leave the pool of game hosts looking for players + // if a set of players has already been sent to host, all players will receive SearchForGameHostFailedToConfirm_t + virtual EGameSearchErrorCode_t CancelRequestPlayersForGame() = 0; + + // submit a result for one player. does not end the game. ullUniqueGameID continues to describe this game + virtual EGameSearchErrorCode_t SubmitPlayerResult( uint64 ullUniqueGameID, CSteamID steamIDPlayer, EPlayerResult_t EPlayerResult ) = 0; + + // ends the game. no further SubmitPlayerResults for ullUniqueGameID will be accepted + // any future requests will provide a new ullUniqueGameID + virtual EGameSearchErrorCode_t EndGame( uint64 ullUniqueGameID ) = 0; + +}; +#define STEAMGAMESEARCH_INTERFACE_VERSION "SteamMatchGameSearch001" + +// Global interface accessor +inline ISteamGameSearch *SteamGameSearch(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamGameSearch *, SteamGameSearch, STEAMGAMESEARCH_INTERFACE_VERSION ); + + +//----------------------------------------------------------------------------- +// Purpose: Functions for quickly creating a Party with friends or acquaintances, +// EG from chat rooms. +//----------------------------------------------------------------------------- +enum ESteamPartyBeaconLocationType +{ + k_ESteamPartyBeaconLocationType_Invalid = 0, + k_ESteamPartyBeaconLocationType_ChatGroup = 1, + + k_ESteamPartyBeaconLocationType_Max, +}; + + +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +struct SteamPartyBeaconLocation_t +{ + ESteamPartyBeaconLocationType m_eType; + uint64 m_ulLocationID; +}; + +enum ESteamPartyBeaconLocationData +{ + k_ESteamPartyBeaconLocationDataInvalid = 0, + k_ESteamPartyBeaconLocationDataName = 1, + k_ESteamPartyBeaconLocationDataIconURLSmall = 2, + k_ESteamPartyBeaconLocationDataIconURLMedium = 3, + k_ESteamPartyBeaconLocationDataIconURLLarge = 4, +}; + +class ISteamParties +{ +public: + + // ============================================================================================= + // Party Client APIs + + // Enumerate any active beacons for parties you may wish to join + virtual uint32 GetNumActiveBeacons() = 0; + virtual PartyBeaconID_t GetBeaconByIndex( uint32 unIndex ) = 0; + virtual bool GetBeaconDetails( PartyBeaconID_t ulBeaconID, CSteamID *pSteamIDBeaconOwner, STEAM_OUT_STRUCT() SteamPartyBeaconLocation_t *pLocation, STEAM_OUT_STRING_COUNT(cchMetadata) char *pchMetadata, int cchMetadata ) = 0; + + // Join an open party. Steam will reserve one beacon slot for your SteamID, + // and return the necessary JoinGame string for you to use to connect + STEAM_CALL_RESULT( JoinPartyCallback_t ) + virtual SteamAPICall_t JoinParty( PartyBeaconID_t ulBeaconID ) = 0; + + // ============================================================================================= + // Party Host APIs + + // Get a list of possible beacon locations + virtual bool GetNumAvailableBeaconLocations( uint32 *puNumLocations ) = 0; + virtual bool GetAvailableBeaconLocations( SteamPartyBeaconLocation_t *pLocationList, uint32 uMaxNumLocations ) = 0; + + // Create a new party beacon and activate it in the selected location. + // unOpenSlots is the maximum number of users that Steam will send to you. + // When people begin responding to your beacon, Steam will send you + // PartyReservationCallback_t callbacks to let you know who is on the way. + STEAM_CALL_RESULT( CreateBeaconCallback_t ) + virtual SteamAPICall_t CreateBeacon( uint32 unOpenSlots, SteamPartyBeaconLocation_t *pBeaconLocation, const char *pchConnectString, const char *pchMetadata ) = 0; + + // Call this function when a user that had a reservation (see callback below) + // has successfully joined your party. + // Steam will manage the remaining open slots automatically. + virtual void OnReservationCompleted( PartyBeaconID_t ulBeacon, CSteamID steamIDUser ) = 0; + + // To cancel a reservation (due to timeout or user input), call this. + // Steam will open a new reservation slot. + // Note: The user may already be in-flight to your game, so it's possible they will still connect and try to join your party. + virtual void CancelReservation( PartyBeaconID_t ulBeacon, CSteamID steamIDUser ) = 0; + + // Change the number of open beacon reservation slots. + // Call this if, for example, someone without a reservation joins your party (eg a friend, or via your own matchmaking system). + STEAM_CALL_RESULT( ChangeNumOpenSlotsCallback_t ) + virtual SteamAPICall_t ChangeNumOpenSlots( PartyBeaconID_t ulBeacon, uint32 unOpenSlots ) = 0; + + // Turn off the beacon. + virtual bool DestroyBeacon( PartyBeaconID_t ulBeacon ) = 0; + + // Utils + virtual bool GetBeaconLocationData( SteamPartyBeaconLocation_t BeaconLocation, ESteamPartyBeaconLocationData eData, STEAM_OUT_STRING_COUNT(cchDataStringOut) char *pchDataStringOut, int cchDataStringOut ) = 0; + +}; +#define STEAMPARTIES_INTERFACE_VERSION "SteamParties002" + +// Global interface accessor +inline ISteamParties *SteamParties(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamParties *, SteamParties, STEAMPARTIES_INTERFACE_VERSION ); + + +//----------------------------------------------------------------------------- +// Callbacks for ISteamMatchmaking (which go through the regular Steam callback registration system) + +//----------------------------------------------------------------------------- +// Purpose: a server was added/removed from the favorites list, you should refresh now +//----------------------------------------------------------------------------- +struct FavoritesListChanged_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 2 }; + uint32 m_nIP; // an IP of 0 means reload the whole list, any other value means just one server + uint32 m_nQueryPort; + uint32 m_nConnPort; + uint32 m_nAppID; + uint32 m_nFlags; + bool m_bAdd; // true if this is adding the entry, otherwise it is a remove + AccountID_t m_unAccountId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Someone has invited you to join a Lobby +// normally you don't need to do anything with this, since +// the Steam UI will also display a ' has invited you to the lobby, join?' dialog +// +// if the user outside a game chooses to join, your game will be launched with the parameter "+connect_lobby <64-bit lobby id>", +// or with the callback GameLobbyJoinRequested_t if they're already in-game +//----------------------------------------------------------------------------- +struct LobbyInvite_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 3 }; + + uint64 m_ulSteamIDUser; // Steam ID of the person making the invite + uint64 m_ulSteamIDLobby; // Steam ID of the Lobby + uint64 m_ulGameID; // GameID of the Lobby +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent on entering a lobby, or on failing to enter +// m_EChatRoomEnterResponse will be set to k_EChatRoomEnterResponseSuccess on success, +// or a higher value on failure (see enum EChatRoomEnterResponse) +//----------------------------------------------------------------------------- +struct LobbyEnter_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 4 }; + + uint64 m_ulSteamIDLobby; // SteamID of the Lobby you have entered + uint32 m_rgfChatPermissions; // Permissions of the current user + bool m_bLocked; // If true, then only invited users may join + uint32 m_EChatRoomEnterResponse; // EChatRoomEnterResponse +}; + + +//----------------------------------------------------------------------------- +// Purpose: The lobby metadata has changed +// if m_ulSteamIDMember is the steamID of a lobby member, use GetLobbyMemberData() to access per-user details +// if m_ulSteamIDMember == m_ulSteamIDLobby, use GetLobbyData() to access lobby metadata +//----------------------------------------------------------------------------- +struct LobbyDataUpdate_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 5 }; + + uint64 m_ulSteamIDLobby; // steamID of the Lobby + uint64 m_ulSteamIDMember; // steamID of the member whose data changed, or the room itself + uint8 m_bSuccess; // true if we lobby data was successfully changed; + // will only be false if RequestLobbyData() was called on a lobby that no longer exists +}; + + +//----------------------------------------------------------------------------- +// Purpose: The lobby chat room state has changed +// this is usually sent when a user has joined or left the lobby +//----------------------------------------------------------------------------- +struct LobbyChatUpdate_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 6 }; + + uint64 m_ulSteamIDLobby; // Lobby ID + uint64 m_ulSteamIDUserChanged; // user who's status in the lobby just changed - can be recipient + uint64 m_ulSteamIDMakingChange; // Chat member who made the change (different from SteamIDUserChange if kicking, muting, etc.) + // for example, if one user kicks another from the lobby, this will be set to the id of the user who initiated the kick + uint32 m_rgfChatMemberStateChange; // bitfield of EChatMemberStateChange values +}; + + +//----------------------------------------------------------------------------- +// Purpose: A chat message for this lobby has been sent +// use GetLobbyChatEntry( m_iChatID ) to retrieve the contents of this message +//----------------------------------------------------------------------------- +struct LobbyChatMsg_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 7 }; + + uint64 m_ulSteamIDLobby; // the lobby id this is in + uint64 m_ulSteamIDUser; // steamID of the user who has sent this message + uint8 m_eChatEntryType; // type of message + uint32 m_iChatID; // index of the chat entry to lookup +}; + + +//----------------------------------------------------------------------------- +// Purpose: A game created a game for all the members of the lobby to join, +// as triggered by a SetLobbyGameServer() +// it's up to the individual clients to take action on this; the usual +// game behavior is to leave the lobby and connect to the specified game server +//----------------------------------------------------------------------------- +struct LobbyGameCreated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 9 }; + + uint64 m_ulSteamIDLobby; // the lobby we were in + uint64 m_ulSteamIDGameServer; // the new game server that has been created or found for the lobby members + uint32 m_unIP; // IP & Port of the game server (if any) + uint16 m_usPort; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Number of matching lobbies found +// iterate the returned lobbies with GetLobbyByIndex(), from values 0 to m_nLobbiesMatching-1 +//----------------------------------------------------------------------------- +struct LobbyMatchList_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 10 }; + uint32 m_nLobbiesMatching; // Number of lobbies that matched search criteria and we have SteamIDs for +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted if a user is forcefully removed from a lobby +// can occur if a user loses connection to Steam +//----------------------------------------------------------------------------- +struct LobbyKicked_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 12 }; + uint64 m_ulSteamIDLobby; // Lobby + uint64 m_ulSteamIDAdmin; // User who kicked you - possibly the ID of the lobby itself + uint8 m_bKickedDueToDisconnect; // true if you were kicked from the lobby due to the user losing connection to Steam (currently always true) +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result of our request to create a Lobby +// m_eResult == k_EResultOK on success +// at this point, the lobby has been joined and is ready for use +// a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) +//----------------------------------------------------------------------------- +struct LobbyCreated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 13 }; + + EResult m_eResult; // k_EResultOK - the lobby was successfully created + // k_EResultNoConnection - your Steam client doesn't have a connection to the back-end + // k_EResultTimeout - you the message to the Steam servers, but it didn't respond + // k_EResultFail - the server responded, but with an unknown internal error + // k_EResultAccessDenied - your game isn't set to allow lobbies, or your client does haven't rights to play the game + // k_EResultLimitExceeded - your game client has created too many lobbies + + uint64 m_ulSteamIDLobby; // chat room, zero if failed +}; + +// used by now obsolete RequestFriendsLobbiesResponse_t +// enum { k_iCallback = k_iSteamMatchmakingCallbacks + 14 }; + + +//----------------------------------------------------------------------------- +// Purpose: Result of CheckForPSNGameBootInvite +// m_eResult == k_EResultOK on success +// at this point, the local user may not have finishing joining this lobby; +// game code should wait until the subsequent LobbyEnter_t callback is received +//----------------------------------------------------------------------------- +struct PSNGameBootInviteResult_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 15 }; + + bool m_bGameBootInviteExists; + CSteamID m_steamIDLobby; // Should be valid if m_bGameBootInviteExists == true +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result of our request to create a Lobby +// m_eResult == k_EResultOK on success +// at this point, the lobby has been joined and is ready for use +// a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) +//----------------------------------------------------------------------------- +struct FavoritesListAccountsUpdated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 16 }; + + EResult m_eResult; +}; + + + +//----------------------------------------------------------------------------- +// Callbacks for ISteamGameSearch (which go through the regular Steam callback registration system) + +struct SearchForGameProgressCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 1 }; + + uint64 m_ullSearchID; // all future callbacks referencing this search will include this Search ID + + EResult m_eResult; // if search has started this result will be k_EResultOK, any other value indicates search has failed to start or has terminated + CSteamID m_lobbyID; // lobby ID if lobby search, invalid steamID otherwise + CSteamID m_steamIDEndedSearch; // if search was terminated, steamID that terminated search + + int32 m_nSecondsRemainingEstimate; + int32 m_cPlayersSearching; +}; + +// notification to all players searching that a game has been found +struct SearchForGameResultCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 2 }; + + uint64 m_ullSearchID; + + EResult m_eResult; // if game/host was lost this will be an error value + + // if m_bGameFound is true the following are non-zero + int32 m_nCountPlayersInGame; + int32 m_nCountAcceptedGame; + // if m_steamIDHost is valid the host has started the game + CSteamID m_steamIDHost; + bool m_bFinalCallback; +}; + + +//----------------------------------------------------------------------------- +// ISteamGameSearch : Game Host API callbacks + +// callback from RequestPlayersForGame when the matchmaking service has started or ended search +// callback will also follow a call from CancelRequestPlayersForGame - m_bSearchInProgress will be false +struct RequestPlayersForGameProgressCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 11 }; + + EResult m_eResult; // m_ullSearchID will be non-zero if this is k_EResultOK + uint64 m_ullSearchID; // all future callbacks referencing this search will include this Search ID +}; + +// callback from RequestPlayersForGame +// one of these will be sent per player +// followed by additional callbacks when players accept or decline the game +struct RequestPlayersForGameResultCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 12 }; + + EResult m_eResult; // m_ullSearchID will be non-zero if this is k_EResultOK + uint64 m_ullSearchID; + + CSteamID m_SteamIDPlayerFound; // player steamID + CSteamID m_SteamIDLobby; // if the player is in a lobby, the lobby ID + enum PlayerAcceptState_t + { + k_EStateUnknown = 0, + k_EStatePlayerAccepted = 1, + k_EStatePlayerDeclined = 2, + }; + PlayerAcceptState_t m_ePlayerAcceptState; + int32 m_nPlayerIndex; + int32 m_nTotalPlayersFound; // expect this many callbacks at minimum + int32 m_nTotalPlayersAcceptedGame; + int32 m_nSuggestedTeamIndex; + uint64 m_ullUniqueGameID; +}; + + +struct RequestPlayersForGameFinalResultCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 13 }; + + EResult m_eResult; + uint64 m_ullSearchID; + uint64 m_ullUniqueGameID; +}; + + + +// this callback confirms that results were received by the matchmaking service for this player +struct SubmitPlayerResultResultCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 14 }; + + EResult m_eResult; + uint64 ullUniqueGameID; + CSteamID steamIDPlayer; +}; + + +// this callback confirms that the game is recorded as complete on the matchmaking service +// the next call to RequestPlayersForGame will generate a new unique game ID +struct EndGameResultCallback_t +{ + enum { k_iCallback = k_iSteamGameSearchCallbacks + 15 }; + + EResult m_eResult; + uint64 ullUniqueGameID; +}; + + +// Steam has responded to the user request to join a party via the given Beacon ID. +// If successful, the connect string contains game-specific instructions to connect +// to the game with that party. +struct JoinPartyCallback_t +{ + enum { k_iCallback = k_iSteamPartiesCallbacks + 1 }; + + EResult m_eResult; + PartyBeaconID_t m_ulBeaconID; + CSteamID m_SteamIDBeaconOwner; + char m_rgchConnectString[256]; +}; + +// Response to CreateBeacon request. If successful, the beacon ID is provided. +struct CreateBeaconCallback_t +{ + enum { k_iCallback = k_iSteamPartiesCallbacks + 2 }; + + EResult m_eResult; + PartyBeaconID_t m_ulBeaconID; +}; + +// Someone has used the beacon to join your party - they are in-flight now +// and we've reserved one of the open slots for them. +// You should confirm when they join your party by calling OnReservationCompleted(). +// Otherwise, Steam may timeout their reservation eventually. +struct ReservationNotificationCallback_t +{ + enum { k_iCallback = k_iSteamPartiesCallbacks + 3 }; + + PartyBeaconID_t m_ulBeaconID; + CSteamID m_steamIDJoiner; +}; + +// Response to ChangeNumOpenSlots call +struct ChangeNumOpenSlotsCallback_t +{ + enum { k_iCallback = k_iSteamPartiesCallbacks + 4 }; + + EResult m_eResult; +}; + +// The list of possible Party beacon locations has changed +struct AvailableBeaconLocationsUpdated_t +{ + enum { k_iCallback = k_iSteamPartiesCallbacks + 5 }; +}; + +// The list of active beacons may have changed +struct ActiveBeaconsUpdated_t +{ + enum { k_iCallback = k_iSteamPartiesCallbacks + 6 }; +}; + + +#pragma pack( pop ) + + +#endif // ISTEAMMATCHMAKING diff --git a/public/steam/isteammusic.h b/public/steam/isteammusic.h new file mode 100644 index 0000000..ffa49a0 --- /dev/null +++ b/public/steam/isteammusic.h @@ -0,0 +1,71 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMMUSIC_H +#define ISTEAMMUSIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum AudioPlayback_Status +{ + AudioPlayback_Undefined = 0, + AudioPlayback_Playing = 1, + AudioPlayback_Paused = 2, + AudioPlayback_Idle = 3 +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions to control music playback in the steam client +//----------------------------------------------------------------------------- +class ISteamMusic +{ +public: + virtual bool BIsEnabled() = 0; + virtual bool BIsPlaying() = 0; + + virtual AudioPlayback_Status GetPlaybackStatus() = 0; + + virtual void Play() = 0; + virtual void Pause() = 0; + virtual void PlayPrevious() = 0; + virtual void PlayNext() = 0; + + // volume is between 0.0 and 1.0 + virtual void SetVolume( float flVolume ) = 0; + virtual float GetVolume() = 0; + +}; + +#define STEAMMUSIC_INTERFACE_VERSION "STEAMMUSIC_INTERFACE_VERSION001" + +// Global interface accessor +inline ISteamMusic *SteamMusic(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamMusic *, SteamMusic, STEAMMUSIC_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +STEAM_CALLBACK_BEGIN( PlaybackStatusHasChanged_t, k_iSteamMusicCallbacks + 1 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( VolumeHasChanged_t, k_iSteamMusicCallbacks + 2 ) + STEAM_CALLBACK_MEMBER( 0, float, m_flNewVolume ) +STEAM_CALLBACK_END(1) + +#pragma pack( pop ) + + +#endif // #define ISTEAMMUSIC_H diff --git a/public/steam/isteammusicremote.h b/public/steam/isteammusicremote.h new file mode 100644 index 0000000..a36f4f8 --- /dev/null +++ b/public/steam/isteammusicremote.h @@ -0,0 +1,133 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMMUSICREMOTE_H +#define ISTEAMMUSICREMOTE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "isteammusic.h" + +#define k_SteamMusicNameMaxLength 255 +#define k_SteamMusicPNGMaxLength 65535 + + +class ISteamMusicRemote +{ +public: + // Service Definition + virtual bool RegisterSteamMusicRemote( const char *pchName ) = 0; + virtual bool DeregisterSteamMusicRemote() = 0; + virtual bool BIsCurrentMusicRemote() = 0; + virtual bool BActivationSuccess( bool bValue ) = 0; + + virtual bool SetDisplayName( const char *pchDisplayName ) = 0; + virtual bool SetPNGIcon_64x64( void *pvBuffer, uint32 cbBufferLength ) = 0; + + // Abilities for the user interface + virtual bool EnablePlayPrevious(bool bValue) = 0; + virtual bool EnablePlayNext( bool bValue ) = 0; + virtual bool EnableShuffled( bool bValue ) = 0; + virtual bool EnableLooped( bool bValue ) = 0; + virtual bool EnableQueue( bool bValue ) = 0; + virtual bool EnablePlaylists( bool bValue ) = 0; + + // Status + virtual bool UpdatePlaybackStatus( AudioPlayback_Status nStatus ) = 0; + virtual bool UpdateShuffled( bool bValue ) = 0; + virtual bool UpdateLooped( bool bValue ) = 0; + virtual bool UpdateVolume( float flValue ) = 0; // volume is between 0.0 and 1.0 + + // Current Entry + virtual bool CurrentEntryWillChange() = 0; + virtual bool CurrentEntryIsAvailable( bool bAvailable ) = 0; + virtual bool UpdateCurrentEntryText( const char *pchText ) = 0; + virtual bool UpdateCurrentEntryElapsedSeconds( int nValue ) = 0; + virtual bool UpdateCurrentEntryCoverArt( void *pvBuffer, uint32 cbBufferLength ) = 0; + virtual bool CurrentEntryDidChange() = 0; + + // Queue + virtual bool QueueWillChange() = 0; + virtual bool ResetQueueEntries() = 0; + virtual bool SetQueueEntry( int nID, int nPosition, const char *pchEntryText ) = 0; + virtual bool SetCurrentQueueEntry( int nID ) = 0; + virtual bool QueueDidChange() = 0; + + // Playlist + virtual bool PlaylistWillChange() = 0; + virtual bool ResetPlaylistEntries() = 0; + virtual bool SetPlaylistEntry( int nID, int nPosition, const char *pchEntryText ) = 0; + virtual bool SetCurrentPlaylistEntry( int nID ) = 0; + virtual bool PlaylistDidChange() = 0; +}; + +#define STEAMMUSICREMOTE_INTERFACE_VERSION "STEAMMUSICREMOTE_INTERFACE_VERSION001" + +// Global interface accessor +inline ISteamMusicRemote *SteamMusicRemote(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamMusicRemote *, SteamMusicRemote, STEAMMUSICREMOTE_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +STEAM_CALLBACK_BEGIN( MusicPlayerRemoteWillActivate_t, k_iSteamMusicRemoteCallbacks + 1) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerRemoteWillDeactivate_t, k_iSteamMusicRemoteCallbacks + 2 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerRemoteToFront_t, k_iSteamMusicRemoteCallbacks + 3 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerWillQuit_t, k_iSteamMusicRemoteCallbacks + 4 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsPlay_t, k_iSteamMusicRemoteCallbacks + 5 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsPause_t, k_iSteamMusicRemoteCallbacks + 6 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsPlayPrevious_t, k_iSteamMusicRemoteCallbacks + 7 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsPlayNext_t, k_iSteamMusicRemoteCallbacks + 8 ) +STEAM_CALLBACK_END(0) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsShuffled_t, k_iSteamMusicRemoteCallbacks + 9 ) + STEAM_CALLBACK_MEMBER( 0, bool, m_bShuffled ) +STEAM_CALLBACK_END(1) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsLooped_t, k_iSteamMusicRemoteCallbacks + 10 ) + STEAM_CALLBACK_MEMBER(0, bool, m_bLooped ) +STEAM_CALLBACK_END(1) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsVolume_t, k_iSteamMusicCallbacks + 11 ) + STEAM_CALLBACK_MEMBER(0, float, m_flNewVolume) +STEAM_CALLBACK_END(1) + +STEAM_CALLBACK_BEGIN( MusicPlayerSelectsQueueEntry_t, k_iSteamMusicCallbacks + 12 ) + STEAM_CALLBACK_MEMBER(0, int, nID ) +STEAM_CALLBACK_END(1) + +STEAM_CALLBACK_BEGIN( MusicPlayerSelectsPlaylistEntry_t, k_iSteamMusicCallbacks + 13 ) + STEAM_CALLBACK_MEMBER(0, int, nID ) +STEAM_CALLBACK_END(1) + +STEAM_CALLBACK_BEGIN( MusicPlayerWantsPlayingRepeatStatus_t, k_iSteamMusicRemoteCallbacks + 14 ) + STEAM_CALLBACK_MEMBER(0, int, m_nPlayingRepeatStatus ) +STEAM_CALLBACK_END(1) + +#pragma pack( pop ) + + + +#endif // #define ISTEAMMUSICREMOTE_H diff --git a/public/steam/isteamnetworking.h b/public/steam/isteamnetworking.h new file mode 100644 index 0000000..b1bf5fa --- /dev/null +++ b/public/steam/isteamnetworking.h @@ -0,0 +1,325 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam managing network connections between game clients & servers +// +//============================================================================= + +#ifndef ISTEAMNETWORKING +#define ISTEAMNETWORKING +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +// list of possible errors returned by SendP2PPacket() API +// these will be posted in the P2PSessionConnectFail_t callback +enum EP2PSessionError +{ + k_EP2PSessionErrorNone = 0, + k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game + k_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running + k_EP2PSessionErrorDestinationNotLoggedIn = 3, // target user isn't connected to Steam + k_EP2PSessionErrorTimeout = 4, // target isn't responding, perhaps not calling AcceptP2PSessionWithUser() + // corporate firewalls can also block this (NAT traversal is not firewall traversal) + // make sure that UDP ports 3478, 4379, and 4380 are open in an outbound direction + k_EP2PSessionErrorMax = 5 +}; + +// SendP2PPacket() send types +// Typically k_EP2PSendUnreliable is what you want for UDP-like packets, k_EP2PSendReliable for TCP-like packets +enum EP2PSend +{ + // Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare). + // The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or + // there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again. + k_EP2PSendUnreliable = 0, + + // As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first + // packet sent to a remote host almost guarantees the packet will be dropped. + // This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets + k_EP2PSendUnreliableNoDelay = 1, + + // Reliable message send. Can send up to 1MB of data in a single message. + // Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data. + k_EP2PSendReliable = 2, + + // As above, but applies the Nagle algorithm to the send - sends will accumulate + // until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm). + // Useful if you want to send a set of smaller messages but have the coalesced into a single packet + // Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then + // do a normal k_EP2PSendReliable to force all the buffered data to be sent. + k_EP2PSendReliableWithBuffering = 3, + +}; + + +// connection state to a specified user, returned by GetP2PSessionState() +// this is under-the-hood info about what's going on with a SendP2PPacket(), shouldn't be needed except for debuggin +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif +struct P2PSessionState_t +{ + uint8 m_bConnectionActive; // true if we've got an active open connection + uint8 m_bConnecting; // true if we're currently trying to establish a connection + uint8 m_eP2PSessionError; // last error recorded (see enum above) + uint8 m_bUsingRelay; // true if it's going through a relay server (TURN) + int32 m_nBytesQueuedForSend; + int32 m_nPacketsQueuedForSend; + uint32 m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server. + uint16 m_nRemotePort; // Only exists for compatibility with older authentication api's +}; +#pragma pack( pop ) + + +// handle to a socket +typedef uint32 SNetSocket_t; // CreateP2PConnectionSocket() +typedef uint32 SNetListenSocket_t; // CreateListenSocket() + +// connection progress indicators, used by CreateP2PConnectionSocket() +enum ESNetSocketState +{ + k_ESNetSocketStateInvalid = 0, + + // communication is valid + k_ESNetSocketStateConnected = 1, + + // states while establishing a connection + k_ESNetSocketStateInitiated = 10, // the connection state machine has started + + // p2p connections + k_ESNetSocketStateLocalCandidatesFound = 11, // we've found our local IP info + k_ESNetSocketStateReceivedRemoteCandidates = 12,// we've received information from the remote machine, via the Steam back-end, about their IP info + + // direct connections + k_ESNetSocketStateChallengeHandshake = 15, // we've received a challenge packet from the server + + // failure states + k_ESNetSocketStateDisconnecting = 21, // the API shut it down, and we're in the process of telling the other end + k_ESNetSocketStateLocalDisconnect = 22, // the API shut it down, and we've completed shutdown + k_ESNetSocketStateTimeoutDuringConnect = 23, // we timed out while trying to creating the connection + k_ESNetSocketStateRemoteEndDisconnected = 24, // the remote end has disconnected from us + k_ESNetSocketStateConnectionBroken = 25, // connection has been broken; either the other end has disappeared or our local network connection has broke + +}; + +// describes how the socket is currently connected +enum ESNetSocketConnectionType +{ + k_ESNetSocketConnectionTypeNotConnected = 0, + k_ESNetSocketConnectionTypeUDP = 1, + k_ESNetSocketConnectionTypeUDPRelay = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for making connections and sending data between clients, +// traversing NAT's where possible +//----------------------------------------------------------------------------- +class ISteamNetworking +{ +public: + //////////////////////////////////////////////////////////////////////////////////////////// + // + // UDP-style (connectionless) networking interface. These functions send messages using + // an API organized around the destination. Reliable and unreliable messages are supported. + // + // For a more TCP-style interface (meaning you have a connection handle), see the functions below. + // Both interface styles can send both reliable and unreliable messages. + // + // Automatically establishes NAT-traversing or Relay server connections + + // Sends a P2P packet to the specified user + // UDP-like, unreliable and a max packet size of 1200 bytes + // the first packet send may be delayed as the NAT-traversal code runs + // if we can't get through to the user, an error will be posted via the callback P2PSessionConnectFail_t + // see EP2PSend enum above for the descriptions of the different ways of sending packets + // + // nChannel is a routing number you can use to help route message to different systems - you'll have to call ReadP2PPacket() + // with the same channel number in order to retrieve the data on the other end + // using different channels to talk to the same user will still use the same underlying p2p connection, saving on resources + virtual bool SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel = 0 ) = 0; + + // returns true if any data is available for read, and the amount of data that will need to be read + virtual bool IsP2PPacketAvailable( uint32 *pcubMsgSize, int nChannel = 0 ) = 0; + + // reads in a packet that has been sent from another user via SendP2PPacket() + // returns the size of the message and the steamID of the user who sent it in the last two parameters + // if the buffer passed in is too small, the message will be truncated + // this call is not blocking, and will return false if no data is available + virtual bool ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote, int nChannel = 0 ) = 0; + + // AcceptP2PSessionWithUser() should only be called in response to a P2PSessionRequest_t callback + // P2PSessionRequest_t will be posted if another user tries to send you a packet that you haven't talked to yet + // if you don't want to talk to the user, just ignore the request + // if the user continues to send you packets, another P2PSessionRequest_t will be posted periodically + // this may be called multiple times for a single user + // (if you've called SendP2PPacket() on the other user, this implicitly accepts the session request) + virtual bool AcceptP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PSessionWithUser() when you're done talking to a user, will free up resources under-the-hood + // if the remote user tries to send data to you again, another P2PSessionRequest_t callback will be posted + virtual bool CloseP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PChannelWithUser() when you're done talking to a user on a specific channel. Once all channels + // open channels to a user have been closed, the open session to the user will be closed and new data from this + // user will trigger a P2PSessionRequest_t callback + virtual bool CloseP2PChannelWithUser( CSteamID steamIDRemote, int nChannel ) = 0; + + // fills out P2PSessionState_t structure with details about the underlying connection to the user + // should only needed for debugging purposes + // returns false if no connection exists to the specified user + virtual bool GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState ) = 0; + + // Allow P2P connections to fall back to being relayed through the Steam servers if a direct connection + // or NAT-traversal cannot be established. Only applies to connections created after setting this value, + // or to existing connections that need to automatically reconnect after this value is set. + // + // P2P packet relay is allowed by default + virtual bool AllowP2PPacketRelay( bool bAllow ) = 0; + + + //////////////////////////////////////////////////////////////////////////////////////////// + // + // LISTEN / CONNECT connection-oriented interface functions + // + // These functions are more like a client-server TCP API. One side is the "server" + // and "listens" for incoming connections, which then must be "accepted." The "client" + // initiates a connection by "connecting." Sending and receiving is done through a + // connection handle. + // + // For a more UDP-style interface, where you do not track connection handles but + // simply send messages to a SteamID, use the UDP-style functions above. + // + // Both methods can send both reliable and unreliable methods. + // + //////////////////////////////////////////////////////////////////////////////////////////// + + + // creates a socket and listens others to connect + // will trigger a SocketStatusCallback_t callback on another client connecting + // nVirtualP2PPort is the unique ID that the client will connect to, in case you have multiple ports + // this can usually just be 0 unless you want multiple sets of connections + // unIP is the local IP address to bind to + // pass in 0 if you just want the default local IP + // unPort is the port to use + // pass in 0 if you don't want users to be able to connect via IP/Port, but expect to be always peer-to-peer connections only + virtual SNetListenSocket_t CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay ) = 0; + + // creates a socket and begin connection to a remote destination + // can connect via a known steamID (client or game server), or directly to an IP + // on success will trigger a SocketStatusCallback_t callback + // on failure or timeout will trigger a SocketStatusCallback_t callback with a failure code in m_eSNetSocketState + virtual SNetSocket_t CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay ) = 0; + virtual SNetSocket_t CreateConnectionSocket( uint32 nIP, uint16 nPort, int nTimeoutSec ) = 0; + + // disconnects the connection to the socket, if any, and invalidates the handle + // any unread data on the socket will be thrown away + // if bNotifyRemoteEnd is set, socket will not be completely destroyed until the remote end acknowledges the disconnect + virtual bool DestroySocket( SNetSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + // destroying a listen socket will automatically kill all the regular sockets generated from it + virtual bool DestroyListenSocket( SNetListenSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + + // sending data + // must be a handle to a connected socket + // data is all sent via UDP, and thus send sizes are limited to 1200 bytes; after this, many routers will start dropping packets + // use the reliable flag with caution; although the resend rate is pretty aggressive, + // it can still cause stalls in receiving data (like TCP) + virtual bool SendDataOnSocket( SNetSocket_t hSocket, void *pubData, uint32 cubData, bool bReliable ) = 0; + + // receiving data + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + virtual bool IsDataAvailableOnSocket( SNetSocket_t hSocket, uint32 *pcubMsgSize ) = 0; + + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + virtual bool RetrieveDataFromSocket( SNetSocket_t hSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0; + + // checks for data from any socket that has been connected off this listen socket + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + // fills out *phSocket with the socket that data is available on + virtual bool IsDataAvailable( SNetListenSocket_t hListenSocket, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // retrieves data from any socket that has been connected off this listen socket + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + // fills out *phSocket with the socket that data is available on + virtual bool RetrieveData( SNetListenSocket_t hListenSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // returns information about the specified socket, filling out the contents of the pointers + virtual bool GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, uint32 *punIPRemote, uint16 *punPortRemote ) = 0; + + // returns which local port the listen socket is bound to + // *pnIP and *pnPort will be 0 if the socket is set to listen for P2P connections only + virtual bool GetListenSocketInfo( SNetListenSocket_t hListenSocket, uint32 *pnIP, uint16 *pnPort ) = 0; + + // returns true to describe how the socket ended up connecting + virtual ESNetSocketConnectionType GetSocketConnectionType( SNetSocket_t hSocket ) = 0; + + // max packet size, in bytes + virtual int GetMaxPacketSize( SNetSocket_t hSocket ) = 0; +}; +#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking005" + +// Global interface accessor +inline ISteamNetworking *SteamNetworking(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworking *, SteamNetworking, STEAMNETWORKING_INTERFACE_VERSION ); + +// Global accessor for the gameserver client +inline ISteamNetworking *SteamGameServerNetworking(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworking *, SteamGameServerNetworking, STEAMNETWORKING_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +// callback notification - a user wants to talk to us over the P2P channel via the SendP2PPacket() API +// in response, a call to AcceptP2PPacketsFromUser() needs to be made, if you want to talk with them +struct P2PSessionRequest_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 2 }; + CSteamID m_steamIDRemote; // user who wants to talk to us +}; + + +// callback notification - packets can't get through to the specified user via the SendP2PPacket() API +// all packets queued packets unsent at this point will be dropped +// further attempts to send will retry making the connection (but will be dropped if we fail again) +struct P2PSessionConnectFail_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 3 }; + CSteamID m_steamIDRemote; // user we were sending packets to + uint8 m_eP2PSessionError; // EP2PSessionError indicating why we're having trouble +}; + + +// callback notification - status of a socket has changed +// used as part of the CreateListenSocket() / CreateP2PConnectionSocket() +struct SocketStatusCallback_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 1 }; + SNetSocket_t m_hSocket; // the socket used to send/receive data to the remote host + SNetListenSocket_t m_hListenSocket; // this is the server socket that we were listening on; NULL if this was an outgoing connection + CSteamID m_steamIDRemote; // remote steamID we have connected to, if it has one + int m_eSNetSocketState; // socket state, ESNetSocketState +}; + +#pragma pack( pop ) + +#endif // ISTEAMNETWORKING diff --git a/public/steam/isteamnetworkingsockets.h b/public/steam/isteamnetworkingsockets.h new file mode 100644 index 0000000..179f216 --- /dev/null +++ b/public/steam/isteamnetworkingsockets.h @@ -0,0 +1,603 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Networking API similar to Berkeley sockets, but for games. +// - connection-oriented API (like TCP, not UDP) +// - but unlike TCP, it's message-oriented, not stream-oriented +// - mix of reliable and unreliable messages +// - fragmentation and reassembly +// - Supports connectivity over plain UDPv4 +// - Also supports SDR ("Steam Datagram Relay") connections, which are +// addressed by SteamID. There is a "P2P" use case and also a "hosted +// dedicated server" use case. +// +//============================================================================= + +#ifndef ISTEAMNETWORKINGSOCKETS +#define ISTEAMNETWORKINGSOCKETS +#ifdef _WIN32 +#pragma once +#endif + +#include "steamnetworkingtypes.h" + +class ISteamNetworkingSocketsCallbacks; +struct SteamNetAuthenticationStatus_t; + +//----------------------------------------------------------------------------- +/// Lower level networking interface that more closely mirrors the standard +/// Berkeley sockets model. Sockets are hard! You should probably only use +/// this interface under the existing circumstances: +/// +/// - You have an existing socket-based codebase you want to port, or coexist with. +/// - You want to be able to connect based on IP address, rather than (just) Steam ID. +/// - You need low-level control of bandwidth utilization, when to drop packets, etc. +/// +/// Note that neither of the terms "connection" and "socket" will correspond +/// one-to-one with an underlying UDP socket. An attempt has been made to +/// keep the semantics as similar to the standard socket model when appropriate, +/// but some deviations do exist. +class ISteamNetworkingSockets +{ +public: + + /// Creates a "server" socket that listens for clients to connect to by + /// calling ConnectByIPAddress, over ordinary UDP (IPv4 or IPv6) + /// + /// You must select a specific local port to listen on and set it + /// the port field of the local address. + /// + /// Usually you wil set the IP portion of the address to zero, (SteamNetworkingIPAddr::Clear()). + /// This means that you will not bind to any particular local interface. In addition, + /// if possible the socket will be bound in "dual stack" mode, which means that it can + /// accept both IPv4 and IPv6 clients. If you wish to bind a particular interface, then + /// set the local address to the appropriate IPv4 or IPv6 IP. + /// + /// When a client attempts to connect, a SteamNetConnectionStatusChangedCallback_t + /// will be posted. The connection will be in the connecting state. + virtual HSteamListenSocket CreateListenSocketIP( const SteamNetworkingIPAddr &localAddress ) = 0; + + /// Creates a connection and begins talking to a "server" over UDP at the + /// given IPv4 or IPv6 address. The remote host must be listening with a + /// matching call to CreateListenSocketIP on the specified port. + /// + /// A SteamNetConnectionStatusChangedCallback_t callback will be triggered when we start + /// connecting, and then another one on either timeout or successful connection. + /// + /// If the server does not have any identity configured, then their network address + /// will be the only identity in use. Or, the network host may provide a platform-specific + /// identity with or without a valid certificate to authenticate that identity. (These + /// details will be contained in the SteamNetConnectionStatusChangedCallback_t.) It's + /// up to your application to decide whether to allow the connection. + /// + /// By default, all connections will get basic encryption sufficient to prevent + /// casual eavesdropping. But note that without certificates (or a shared secret + /// distributed through some other out-of-band mechanism), you don't have any + /// way of knowing who is actually on the other end, and thus are vulnerable to + /// man-in-the-middle attacks. + virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address ) = 0; + +#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR + /// Like CreateListenSocketIP, but clients will connect using ConnectP2P + /// + /// nVirtualPort specifies how clients can connect to this socket using + /// ConnectP2P. It's very common for applications to only have one listening socket; + /// in that case, use zero. If you need to open multiple listen sockets and have clients + /// be able to connect to one or the other, then nVirtualPort should be a small integer (<1000) + /// unique to each listen socket you create. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + virtual HSteamListenSocket CreateListenSocketP2P( int nVirtualPort ) = 0; + + /// Begin connecting to a server that is identified using a platform-specific identifier. + /// This requires some sort of third party rendezvous service, and will depend on the + /// platform and what other libraries and services you are integrating with. + /// + /// At the time of this writing, there is only one supported rendezvous service: Steam. + /// Set the SteamID (whether "user" or "gameserver") and Steam will determine if the + /// client is online and facilitate a relay connection. Note that all P2P connections on + /// Steam are currently relayed. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nVirtualPort ) = 0; +#endif + + /// Accept an incoming connection that has been received on a listen socket. + /// + /// When a connection attempt is received (perhaps after a few basic handshake + /// packets have been exchanged to prevent trivial spoofing), a connection interface + /// object is created in the k_ESteamNetworkingConnectionState_Connecting state + /// and a SteamNetConnectionStatusChangedCallback_t is posted. At this point, your + /// application MUST either accept or close the connection. (It may not ignore it.) + /// Accepting the connection will transition it either into the connected state, + /// or the finding route state, depending on the connection type. + /// + /// You should take action within a second or two, because accepting the connection is + /// what actually sends the reply notifying the client that they are connected. If you + /// delay taking action, from the client's perspective it is the same as the network + /// being unresponsive, and the client may timeout the connection attempt. In other + /// words, the client cannot distinguish between a delay caused by network problems + /// and a delay caused by the application. + /// + /// This means that if your application goes for more than a few seconds without + /// processing callbacks (for example, while loading a map), then there is a chance + /// that a client may attempt to connect in that interval and fail due to timeout. + /// + /// If the application does not respond to the connection attempt in a timely manner, + /// and we stop receiving communication from the client, the connection attempt will + /// be timed out locally, transitioning the connection to the + /// k_ESteamNetworkingConnectionState_ProblemDetectedLocally state. The client may also + /// close the connection before it is accepted, and a transition to the + /// k_ESteamNetworkingConnectionState_ClosedByPeer is also possible depending the exact + /// sequence of events. + /// + /// Returns k_EResultInvalidParam if the handle is invalid. + /// Returns k_EResultInvalidState if the connection is not in the appropriate state. + /// (Remember that the connection state could change in between the time that the + /// notification being posted to the queue and when it is received by the application.) + virtual EResult AcceptConnection( HSteamNetConnection hConn ) = 0; + + /// Disconnects from the remote host and invalidates the connection handle. + /// Any unread data on the connection is discarded. + /// + /// nReason is an application defined code that will be received on the other + /// end and recorded (when possible) in backend analytics. The value should + /// come from a restricted range. (See ESteamNetConnectionEnd.) If you don't need + /// to communicate any information to the remote host, and do not want analytics to + /// be able to distinguish "normal" connection terminations from "exceptional" ones, + /// You may pass zero, in which case the generic value of + /// k_ESteamNetConnectionEnd_App_Generic will be used. + /// + /// pszDebug is an optional human-readable diagnostic string that will be received + /// by the remote host and recorded (when possible) in backend analytics. + /// + /// If you wish to put the socket into a "linger" state, where an attempt is made to + /// flush any remaining sent data, use bEnableLinger=true. Otherwise reliable data + /// is not flushed. + /// + /// If the connection has already ended and you are just freeing up the + /// connection interface, the reason code, debug string, and linger flag are + /// ignored. + virtual bool CloseConnection( HSteamNetConnection hPeer, int nReason, const char *pszDebug, bool bEnableLinger ) = 0; + + /// Destroy a listen socket. All the connections that were accepting on the listen + /// socket are closed ungracefully. + virtual bool CloseListenSocket( HSteamListenSocket hSocket ) = 0; + + /// Set connection user data. the data is returned in the following places + /// - You can query it using GetConnectionUserData. + /// - The SteamNetworkingmessage_t structure. + /// - The SteamNetConnectionInfo_t structure. (Which is a member of SteamNetConnectionStatusChangedCallback_t.) + /// + /// Returns false if the handle is invalid. + virtual bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData ) = 0; + + /// Fetch connection user data. Returns -1 if handle is invalid + /// or if you haven't set any userdata on the connection. + virtual int64 GetConnectionUserData( HSteamNetConnection hPeer ) = 0; + + /// Set a name for the connection, used mostly for debugging + virtual void SetConnectionName( HSteamNetConnection hPeer, const char *pszName ) = 0; + + /// Fetch connection name. Returns false if handle is invalid + virtual bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen ) = 0; + + /// Send a message to the remote host on the specified connection. + /// + /// nSendFlags determines the delivery guarantees that will be provided, + /// when data should be buffered, etc. E.g. k_nSteamNetworkingSend_Unreliable + /// + /// Note that the semantics we use for messages are not precisely + /// the same as the semantics of a standard "stream" socket. + /// (SOCK_STREAM) For an ordinary stream socket, the boundaries + /// between chunks are not considered relevant, and the sizes of + /// the chunks of data written will not necessarily match up to + /// the sizes of the chunks that are returned by the reads on + /// the other end. The remote host might read a partial chunk, + /// or chunks might be coalesced. For the message semantics + /// used here, however, the sizes WILL match. Each send call + /// will match a successful read call on the remote host + /// one-for-one. If you are porting existing stream-oriented + /// code to the semantics of reliable messages, your code should + /// work the same, since reliable message semantics are more + /// strict than stream semantics. The only caveat is related to + /// performance: there is per-message overhead to retain the + /// message sizes, and so if your code sends many small chunks + /// of data, performance will suffer. Any code based on stream + /// sockets that does not write excessively small chunks will + /// work without any changes. + /// + /// Returns: + /// - k_EResultInvalidParam: invalid connection handle, or the individual message is too big. + /// (See k_cbMaxSteamNetworkingSocketsMessageSizeSend) + /// - k_EResultInvalidState: connection is in an invalid state + /// - k_EResultNoConnection: connection has ended + /// - k_EResultIgnored: You used k_nSteamNetworkingSend_NoDelay, and the message was dropped because + /// we were not ready to send it. + /// - k_EResultLimitExceeded: there was already too much data queued to be sent. + /// (See k_ESteamNetworkingConfig_SendBufferSize) + virtual EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, int nSendFlags ) = 0; + + /// Flush any messages waiting on the Nagle timer and send them + /// at the next transmission opportunity (often that means right now). + /// + /// If Nagle is enabled (it's on by default) then when calling + /// SendMessageToConnection the message will be buffered, up to the Nagle time + /// before being sent, to merge small messages into the same packet. + /// (See k_ESteamNetworkingConfig_NagleTime) + /// + /// Returns: + /// k_EResultInvalidParam: invalid connection handle + /// k_EResultInvalidState: connection is in an invalid state + /// k_EResultNoConnection: connection has ended + /// k_EResultIgnored: We weren't (yet) connected, so this operation has no effect. + virtual EResult FlushMessagesOnConnection( HSteamNetConnection hConn ) = 0; + + /// Fetch the next available message(s) from the connection, if any. + /// Returns the number of messages returned into your array, up to nMaxMessages. + /// If the connection handle is invalid, -1 is returned. + /// + /// The order of the messages returned in the array is relevant. + /// Reliable messages will be received in the order they were sent (and with the + /// same sizes --- see SendMessageToConnection for on this subtle difference from a stream socket). + /// + /// Unreliable messages may be dropped, or delivered out of order withrespect to + /// each other or with respect to reliable messages. The same unreliable message + /// may be received multiple times. + /// + /// If any messages are returned, you MUST call SteamNetworkingMessage_t::Release() on each + /// of them free up resources after you are done. It is safe to keep the object alive for + /// a little while (put it into some queue, etc), and you may call Release() from any thread. + virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + /// Same as ReceiveMessagesOnConnection, but will return the next message available + /// on any connection that was accepted through the specified listen socket. Examine + /// SteamNetworkingMessage_t::m_conn to know which client connection. + /// + /// Delivery order of messages among different clients is not defined. They may + /// be returned in an order different from what they were actually received. (Delivery + /// order of messages from the same client is well defined, and thus the order of the + /// messages is relevant!) + virtual int ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + /// Returns basic information about the high-level state of the connection. + virtual bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo ) = 0; + + /// Returns a small set of information about the real-time state of the connection + /// Returns false if the connection handle is invalid, or the connection has ended. + virtual bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats ) = 0; + + /// Returns detailed connection stats in text format. Useful + /// for dumping to a log, etc. + /// + /// Returns: + /// -1 failure (bad connection handle) + /// 0 OK, your buffer was filled in and '\0'-terminated + /// >0 Your buffer was either nullptr, or it was too small and the text got truncated. + /// Try again with a buffer of at least N bytes. + virtual int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf ) = 0; + + /// Returns local IP and port that a listen socket created using CreateListenSocketIP is bound to. + /// + /// An IPv6 address of ::0 means "any IPv4 or IPv6" + /// An IPv6 address of ::ffff:0000:0000 means "any IPv4" + virtual bool GetListenSocketAddress( HSteamListenSocket hSocket, SteamNetworkingIPAddr *address ) = 0; + + /// Create a pair of connections that are talking to each other, e.g. a loopback connection. + /// This is very useful for testing, or so that your client/server code can work the same + /// even when you are running a local "server". + /// + /// The two connections will immediately be placed into the connected state, and no callbacks + /// will be posted immediately. After this, if you close either connection, the other connection + /// will receive a callback, exactly as if they were communicating over the network. You must + /// close *both* sides in order to fully clean up the resources! + /// + /// By default, internal buffers are used, completely bypassing the network, the chopping up of + /// messages into packets, encryption, copying the payload, etc. This means that loopback + /// packets, by default, will not simulate lag or loss. Passing true for bUseNetworkLoopback will + /// cause the socket pair to send packets through the local network loopback device (127.0.0.1) + /// on ephemeral ports. Fake lag and loss are supported in this case, and CPU time is expended + /// to encrypt and decrypt. + /// + /// If you wish to assign a specific identity to either connection, you may pass a particular + /// identity. Otherwise, if you pass nullptr, the respective connection will assume a generic + /// "localhost" identity. If you use real network loopback, this might be translated to the + /// actual bound loopback port. Otherwise, the port will be zero. + virtual bool CreateSocketPair( HSteamNetConnection *pOutConnection1, HSteamNetConnection *pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity *pIdentity1, const SteamNetworkingIdentity *pIdentity2 ) = 0; + + /// Get the identity assigned to this interface. + /// E.g. on Steam, this is the user's SteamID, or for the gameserver interface, the SteamID assigned + /// to the gameserver. Returns false and sets the result to an invalid identity if we don't know + /// our identity yet. (E.g. GameServer has not logged in. On Steam, the user will know their SteamID + /// even if they are not signed into Steam.) + virtual bool GetIdentity( SteamNetworkingIdentity *pIdentity ) = 0; + + /// Indicate our desire to be ready participate in authenticated communications. + /// If we are currently not ready, then steps will be taken to obtain the necessary + /// certificates. (This includes a certificate for us, as well as any CA certificates + /// needed to authenticate peers.) + /// + /// You can call this at program init time if you know that you are going to + /// be making authenticated connections, so that we will be ready immediately when + /// those connections are attempted. (Note that essentially all connections require + /// authentication, with the exception of ordinary UDP connections with authentication + /// disabled using k_ESteamNetworkingConfig_IP_AllowWithoutAuth.) If you don't call + /// this function, we will wait until a feature is utilized that that necessitates + /// these resources. + /// + /// You can also call this function to force a retry, if failure has occurred. + /// Once we make an attempt and fail, we will not automatically retry. + /// In this respect, the behavior of the system after trying and failing is the same + /// as before the first attempt: attempting authenticated communication or calling + /// this function will call the system to attempt to acquire the necessary resources. + /// + /// You can use GetAuthenticationStatus or listen for SteamNetAuthenticationStatus_t + /// to monitor the status. + /// + /// Returns the current value that would be returned from GetAuthenticationStatus. + virtual ESteamNetworkingAvailability InitAuthentication() = 0; + + /// Query our readiness to participate in authenticated communications. A + /// SteamNetAuthenticationStatus_t callback is posted any time this status changes, + /// but you can use this function to query it at any time. + /// + /// The value of SteamNetAuthenticationStatus_t::m_eAvail is returned. If you only + /// want this high level status, you can pass NULL for pDetails. If you want further + /// details, pass non-NULL to receive them. + virtual ESteamNetworkingAvailability GetAuthenticationStatus( SteamNetAuthenticationStatus_t *pDetails ) = 0; + +/// Certificate provision by the application. (On Steam, Steam will handle all this automatically) +#ifndef STEAMNETWORKINGSOCKETS_STEAM + + /// Get blob that describes a certificate request. You can send this to your game coordinator. + /// Upon entry, *pcbBlob should contain the size of the buffer. On successful exit, it will + /// return the number of bytes that were populated. You can pass pBlob=NULL to query for the required + /// size. (256 bytes is a very conservative estimate.) + /// + /// Pass this blob to your game coordinator and call SteamDatagram_CreateCert. + virtual bool GetCertificateRequest( int *pcbBlob, void *pBlob, SteamNetworkingErrMsg &errMsg ) = 0; + + /// Set the certificate. The certificate blob should be the output of + /// SteamDatagram_CreateCert. + virtual bool SetCertificate( const void *pCertificate, int cbCertificate, SteamNetworkingErrMsg &errMsg ) = 0; + +#endif + +#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR + + // + // Clients connecting to dedicated servers hosted in a data center, + // using central-authority-granted tickets. + // + + /// Call this when you receive a ticket from your backend / matchmaking system. Puts the + /// ticket into a persistent cache, and optionally returns the parsed ticket. + /// + /// See stamdatagram_ticketgen.h for more details. + virtual bool ReceivedRelayAuthTicket( const void *pvTicket, int cbTicket, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0; + + /// Search cache for a ticket to talk to the server on the specified virtual port. + /// If found, returns the number of seconds until the ticket expires, and optionally + /// the complete cracked ticket. Returns 0 if we don't have a ticket. + /// + /// Typically this is useful just to confirm that you have a ticket, before you + /// call ConnectToHostedDedicatedServer to connect to the server. + virtual int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket ) = 0; + + /// Client call to connect to a server hosted in a Valve data center, on the specified virtual + /// port. You must have placed a ticket for this server into the cache, or else this connect attempt will fail! + /// + /// You may wonder why tickets are stored in a cache, instead of simply being passed as an argument + /// here. The reason is to make reconnection to a gameserver robust, even if the client computer loses + /// connection to Steam or the central backend, or the app is restarted or crashes, etc. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nVirtualPort ) = 0; + + // + // Servers hosted in data centers known to the Valve relay network + // + + /// Returns the value of the SDR_LISTEN_PORT environment variable. This + /// is the UDP server your server will be listening on. This will + /// configured automatically for you in production environments. + /// + /// In development, you'll need to set it yourself. See + /// https://partner.steamgames.com/doc/api/ISteamNetworkingSockets + /// for more information on how to configure dev environments. + virtual uint16 GetHostedDedicatedServerPort() = 0; + + /// Returns 0 if SDR_LISTEN_PORT is not set. Otherwise, returns the data center the server + /// is running in. This will be k_SteamDatagramPOPID_dev in non-production envirionment. + virtual SteamNetworkingPOPID GetHostedDedicatedServerPOPID() = 0; + + /// Return info about the hosted server. This contains the PoPID of the server, + /// and opaque routing information that can be used by the relays to send traffic + /// to your server. + /// + /// You will need to send this information to your backend, and put it in tickets, + /// so that the relays will know how to forward traffic from + /// clients to your server. See SteamDatagramRelayAuthTicket for more info. + /// + /// Also, note that the routing information is contained in SteamDatagramGameCoordinatorServerLogin, + /// so if possible, it's preferred to use GetGameCoordinatorServerLogin to send this info + /// to your game coordinator service, and also login securely at the same time. + /// + /// On a successful exit, k_EResultOK is returned + /// + /// Unsuccessful exit: + /// - Something other than k_EResultOK is returned. + /// - k_EResultInvalidState: We are not configured to listen for SDR (SDR_LISTEN_SOCKET + /// is not set.) + /// - k_EResultPending: we do not (yet) have the authentication information needed. + /// (See GetAuthenticationStatus.) If you use environment variables to pre-fetch + /// the network config, this data should always be available immediately. + /// - A non-localized diagnostic debug message will be placed in m_data that describes + /// the cause of the failure. + /// + /// NOTE: The returned blob is not encrypted. Send it to your backend, but don't + /// directly share it with clients. + virtual EResult GetHostedDedicatedServerAddress( SteamDatagramHostedAddress *pRouting ) = 0; + + /// Create a listen socket on the specified virtual port. The physical UDP port to use + /// will be determined by the SDR_LISTEN_PORT environment variable. If a UDP port is not + /// configured, this call will fail. + /// + /// Note that this call MUST be made through the SteamGameServerNetworkingSockets() interface + virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nVirtualPort ) = 0; + + /// Generate an authentication blob that can be used to securely login with + /// your backend, using SteamDatagram_ParseHostedServerLogin. (See + /// steamdatagram_gamecoordinator.h) + /// + /// Before calling the function: + /// - Populate the app data in pLoginInfo (m_cbAppData and m_appData). You can leave + /// all other fields uninitialized. + /// - *pcbSignedBlob contains the size of the buffer at pBlob. (It should be + /// at least k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized.) + /// + /// On a successful exit: + /// - k_EResultOK is returned + /// - All of the remaining fields of pLoginInfo will be filled out. + /// - *pcbSignedBlob contains the size of the serialized blob that has been + /// placed into pBlob. + /// + /// Unsuccessful exit: + /// - Something other than k_EResultOK is returned. + /// - k_EResultNotLoggedOn: you are not logged in (yet) + /// - See GetHostedDedicatedServerAddress for more potential failure return values. + /// - A non-localized diagnostic debug message will be placed in pBlob that describes + /// the cause of the failure. + /// + /// This works by signing the contents of the SteamDatagramGameCoordinatorServerLogin + /// with the cert that is issued to this server. In dev environments, it's OK if you do + /// not have a cert. (You will need to enable insecure dev login in SteamDatagram_ParseHostedServerLogin.) + /// Otherwise, you will need a signed cert. + /// + /// NOTE: The routing blob returned here is not encrypted. Send it to your backend + /// and don't share it directly with clients. + virtual EResult GetGameCoordinatorServerLogin( SteamDatagramGameCoordinatorServerLogin *pLoginInfo, int *pcbSignedBlob, void *pBlob ) = 0; + +#endif // #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR + + // Invoke all callbacks queued for this interface. + // On Steam, callbacks are dispatched via the ordinary Steamworks callbacks mechanism. + // So if you have code that is also targeting Steam, you should call this at about the + // same time you would call SteamAPI_RunCallbacks and SteamGameServer_RunCallbacks. +#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB + virtual void RunCallbacks( ISteamNetworkingSocketsCallbacks *pCallbacks ) = 0; +#endif +protected: + ~ISteamNetworkingSockets(); // Silence some warnings +}; +#define STEAMNETWORKINGSOCKETS_INTERFACE_VERSION "SteamNetworkingSockets004" + +extern "C" { + +// Global accessor. +#if defined( STEAMNETWORKINGSOCKETS_PARTNER ) + + // Standalone lib. Use different symbol name, so that we can dynamically switch between steamclient.dll + // and the standalone lib + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamNetworkingSockets_Lib(); + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamGameServerNetworkingSockets_Lib(); + inline ISteamNetworkingSockets *SteamNetworkingSockets() { return SteamNetworkingSockets_Lib(); } + inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets() { return SteamGameServerNetworkingSockets_Lib(); } + +#elif defined( STEAMNETWORKINGSOCKETS_OPENSOURCE ) + + // Opensource GameNetworkingSockets + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamNetworkingSockets(); + +#else + + // Steamworks SDK + inline ISteamNetworkingSockets *SteamNetworkingSockets(); + STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamNetworkingSockets, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION ); + inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets(); + STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamGameServerNetworkingSockets, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION ); +#endif + +/// Callback struct used to notify when a connection has changed state +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error "Must define VALVE_CALLBACK_PACK_SMALL or VALVE_CALLBACK_PACK_LARGE" +#endif + +/// This callback is posted whenever a connection is created, destroyed, or changes state. +/// The m_info field will contain a complete description of the connection at the time the +/// change occurred and the callback was posted. In particular, m_eState will have the +/// new connection state. +/// +/// You will usually need to listen for this callback to know when: +/// - A new connection arrives on a listen socket. +/// m_info.m_hListenSocket will be set, m_eOldState = k_ESteamNetworkingConnectionState_None, +/// and m_info.m_eState = k_ESteamNetworkingConnectionState_Connecting. +/// See ISteamNetworkigSockets::AcceptConnection. +/// - A connection you initiated has been accepted by the remote host. +/// m_eOldState = k_ESteamNetworkingConnectionState_Connecting, and +/// m_info.m_eState = k_ESteamNetworkingConnectionState_Connected. +/// Some connections might transition to k_ESteamNetworkingConnectionState_FindingRoute first. +/// - A connection has been actively rejected or closed by the remote host. +/// m_eOldState = k_ESteamNetworkingConnectionState_Connecting or k_ESteamNetworkingConnectionState_Connected, +/// and m_info.m_eState = k_ESteamNetworkingConnectionState_ClosedByPeer. m_info.m_eEndReason +/// and m_info.m_szEndDebug will have for more details. +/// NOTE: upon receiving this callback, you must still destroy the connection using +/// ISteamNetworkingSockets::CloseConnection to free up local resources. (The details +/// passed to the function are not used in this case, since the connection is already closed.) +/// - A problem was detected with the connection, and it has been closed by the local host. +/// The most common failure is timeout, but other configuration or authentication failures +/// can cause this. m_eOldState = k_ESteamNetworkingConnectionState_Connecting or +/// k_ESteamNetworkingConnectionState_Connected, and m_info.m_eState = k_ESteamNetworkingConnectionState_ProblemDetectedLocally. +/// m_info.m_eEndReason and m_info.m_szEndDebug will have for more details. +/// NOTE: upon receiving this callback, you must still destroy the connection using +/// ISteamNetworkingSockets::CloseConnection to free up local resources. (The details +/// passed to the function are not used in this case, since the connection is already closed.) +/// +/// Remember that callbacks are posted to a queue, and networking connections can +/// change at any time. It is possible that the connection has already changed +/// state by the time you process this callback. +/// +/// Also note that callbacks will be posted when connections are created and destroyed by your own API calls. +struct SteamNetConnectionStatusChangedCallback_t +{ + enum { k_iCallback = k_iSteamNetworkingSocketsCallbacks + 1 }; + + /// Connection handle + HSteamNetConnection m_hConn; + + /// Full connection info + SteamNetConnectionInfo_t m_info; + + /// Previous state. (Current state is in m_info.m_eState) + ESteamNetworkingConnectionState m_eOldState; +}; + +/// A struct used to describe our readiness to participate in authenticated, +/// encrypted communication. In order to do this we need: +/// +/// - The list of trusted CA certificates that might be relevant for this +/// app. +/// - A valid certificate issued by a CA. +struct SteamNetAuthenticationStatus_t +{ + enum { k_iCallback = k_iSteamNetworkingSocketsCallbacks + 2 }; + + /// Status + ESteamNetworkingAvailability m_eAvail; + + /// Non-localized English language status. For diagnostic/debugging + /// purposes only. + char m_debugMsg[ 256 ]; +}; + +#pragma pack( pop ) + +} + +#endif // ISTEAMNETWORKINGSOCKETS diff --git a/public/steam/isteamnetworkingutils.h b/public/steam/isteamnetworkingutils.h new file mode 100644 index 0000000..6f47821 --- /dev/null +++ b/public/steam/isteamnetworkingutils.h @@ -0,0 +1,342 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Purpose: misc networking utilities +// +//============================================================================= + +#ifndef ISTEAMNETWORKINGUTILS +#define ISTEAMNETWORKINGUTILS +#ifdef _WIN32 +#pragma once +#endif + +#include + +#include "steamnetworkingtypes.h" +struct SteamDatagramRelayAuthTicket; +struct SteamRelayNetworkStatus_t; + +//----------------------------------------------------------------------------- +/// Misc networking utilities for checking the local networking environment +/// and estimating pings. +class ISteamNetworkingUtils +{ +public: +#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR + + // + // Initialization and status check + // + + /// If you know that you are going to be using the relay network, call + /// this to initialize the relay network or check if that initialization + /// has completed. If you do not call this, the initialization will + /// happen the first time you use a feature that requires access to the + /// relay network, and that use will be delayed. + /// + /// Use GetRelayNetworkStatus or listen for SteamRelayNetworkStatus_t + /// callbacks to know when initialization has completed. + /// Typically initialization completes in a few seconds. + /// + /// Note: dedicated servers hosted in known data centers do *not* need + /// to call this, since they do not make routing decisions. However, if + /// the dedicated server will be using P2P functionality, it will act as + /// a "client" and this should be called. + inline void InitRelayNetworkAccess(); + + /// Fetch current status of the relay network. + /// + /// SteamRelayNetworkStatus_t is also a callback. It will be triggered on + /// both the user and gameserver interfaces any time the status changes, or + /// ping measurement starts or stops. + /// + /// SteamRelayNetworkStatus_t::m_eAvail is returned. If you want + /// more details, you can pass a non-NULL value. + virtual ESteamNetworkingAvailability GetRelayNetworkStatus( SteamRelayNetworkStatus_t *pDetails ) = 0; + + // + // "Ping location" functions + // + // We use the ping times to the valve relays deployed worldwide to + // generate a "marker" that describes the location of an Internet host. + // Given two such markers, we can estimate the network latency between + // two hosts, without sending any packets. The estimate is based on the + // optimal route that is found through the Valve network. If you are + // using the Valve network to carry the traffic, then this is precisely + // the ping you want. If you are not, then the ping time will probably + // still be a reasonable estimate. + // + // This is extremely useful to select peers for matchmaking! + // + // The markers can also be converted to a string, so they can be transmitted. + // We have a separate library you can use on your app's matchmaking/coordinating + // server to manipulate these objects. (See steamdatagram_gamecoordinator.h) + + /// Return location info for the current host. Returns the approximate + /// age of the data, in seconds, or -1 if no data is available. + /// + /// It takes a few seconds to initialize access to the relay network. If + /// you call this very soon after calling InitRelayNetworkAccess, + /// the data may not be available yet. + /// + /// This always return the most up-to-date information we have available + /// right now, even if we are in the middle of re-calculating ping times. + virtual float GetLocalPingLocation( SteamNetworkPingLocation_t &result ) = 0; + + /// Estimate the round-trip latency between two arbitrary locations, in + /// milliseconds. This is a conservative estimate, based on routing through + /// the relay network. For most basic relayed connections, this ping time + /// will be pretty accurate, since it will be based on the route likely to + /// be actually used. + /// + /// If a direct IP route is used (perhaps via NAT traversal), then the route + /// will be different, and the ping time might be better. Or it might actually + /// be a bit worse! Standard IP routing is frequently suboptimal! + /// + /// But even in this case, the estimate obtained using this method is a + /// reasonable upper bound on the ping time. (Also it has the advantage + /// of returning immediately and not sending any packets.) + /// + /// In a few cases we might not able to estimate the route. In this case + /// a negative value is returned. k_nSteamNetworkingPing_Failed means + /// the reason was because of some networking difficulty. (Failure to + /// ping, etc) k_nSteamNetworkingPing_Unknown is returned if we cannot + /// currently answer the question for some other reason. + /// + /// Do you need to be able to do this from a backend/matchmaking server? + /// You are looking for the "ticketgen" library. + virtual int EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 ) = 0; + + /// Same as EstimatePingTime, but assumes that one location is the local host. + /// This is a bit faster, especially if you need to calculate a bunch of + /// these in a loop to find the fastest one. + /// + /// In rare cases this might return a slightly different estimate than combining + /// GetLocalPingLocation with EstimatePingTimeBetweenTwoLocations. That's because + /// this function uses a slightly more complete set of information about what + /// route would be taken. + virtual int EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation ) = 0; + + /// Convert a ping location into a text format suitable for sending over the wire. + /// The format is a compact and human readable. However, it is subject to change + /// so please do not parse it yourself. Your buffer must be at least + /// k_cchMaxSteamNetworkingPingLocationString bytes. + virtual void ConvertPingLocationToString( const SteamNetworkPingLocation_t &location, char *pszBuf, int cchBufSize ) = 0; + + /// Parse back SteamNetworkPingLocation_t string. Returns false if we couldn't understand + /// the string. + virtual bool ParsePingLocationString( const char *pszString, SteamNetworkPingLocation_t &result ) = 0; + + /// Check if the ping data of sufficient recency is available, and if + /// it's too old, start refreshing it. + /// + /// Please only call this function when you *really* do need to force an + /// immediate refresh of the data. (For example, in response to a specific + /// user input to refresh this information.) Don't call it "just in case", + /// before every connection, etc. That will cause extra traffic to be sent + /// for no benefit. The library will automatically refresh the information + /// as needed. + /// + /// Returns true if sufficiently recent data is already available. + /// + /// Returns false if sufficiently recent data is not available. In this + /// case, ping measurement is initiated, if it is not already active. + /// (You cannot restart a measurement already in progress.) + /// + /// You can use GetRelayNetworkStatus or listen for SteamRelayNetworkStatus_t + /// to know when ping measurement completes. + virtual bool CheckPingDataUpToDate( float flMaxAgeSeconds ) = 0; + + // + // List of Valve data centers, and ping times to them. This might + // be useful to you if you are use our hosting, or just need to measure + // latency to a cloud data center where we are running relays. + // + + /// Fetch ping time of best available relayed route from this host to + /// the specified data center. + virtual int GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP ) = 0; + + /// Get *direct* ping time to the relays at the data center. + virtual int GetDirectPingToPOP( SteamNetworkingPOPID popID ) = 0; + + /// Get number of network points of presence in the config + virtual int GetPOPCount() = 0; + + /// Get list of all POP IDs. Returns the number of entries that were filled into + /// your list. + virtual int GetPOPList( SteamNetworkingPOPID *list, int nListSz ) = 0; +#endif // #ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR + + // + // Misc + // + + /// Fetch current timestamp. This timer has the following properties: + /// + /// - Monotonicity is guaranteed. + /// - The initial value will be at least 24*3600*30*1e6, i.e. about + /// 30 days worth of microseconds. In this way, the timestamp value of + /// 0 will always be at least "30 days ago". Also, negative numbers + /// will never be returned. + /// - Wraparound / overflow is not a practical concern. + /// + /// If you are running under the debugger and stop the process, the clock + /// might not advance the full wall clock time that has elapsed between + /// calls. If the process is not blocked from normal operation, the + /// timestamp values will track wall clock time, even if you don't call + /// the function frequently. + /// + /// The value is only meaningful for this run of the process. Don't compare + /// it to values obtained on another computer, or other runs of the same process. + virtual SteamNetworkingMicroseconds GetLocalTimestamp() = 0; + + /// Set a function to receive network-related information that is useful for debugging. + /// This can be very useful during development, but it can also be useful for troubleshooting + /// problems with tech savvy end users. If you have a console or other log that customers + /// can examine, these log messages can often be helpful to troubleshoot network issues. + /// (Especially any warning/error messages.) + /// + /// The detail level indicates what message to invoke your callback on. Lower numeric + /// value means more important, and the value you pass is the lowest priority (highest + /// numeric value) you wish to receive callbacks for. + /// + /// Except when debugging, you should only use k_ESteamNetworkingSocketsDebugOutputType_Msg + /// or k_ESteamNetworkingSocketsDebugOutputType_Warning. For best performance, do NOT + /// request a high detail level and then filter out messages in your callback. Instead, + /// call function function to adjust the desired level of detail. + /// + /// IMPORTANT: This may be called from a service thread, while we own a mutex, etc. + /// Your output function must be threadsafe and fast! Do not make any other + /// Steamworks calls from within the handler. + virtual void SetDebugOutputFunction( ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc ) = 0; + + // + // Set and get configuration values, see ESteamNetworkingConfigValue for individual descriptions. + // + + // Shortcuts for common cases. (Implemented as inline functions below) + bool SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val ); + bool SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val ); + bool SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val ); + bool SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ); + bool SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ); + bool SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val ); + + /// Set a configuration value. + /// - eValue: which value is being set + /// - eScope: Onto what type of object are you applying the setting? + /// - scopeArg: Which object you want to change? (Ignored for global scope). E.g. connection handle, listen socket handle, interface pointer, etc. + /// - eDataType: What type of data is in the buffer at pValue? This must match the type of the variable exactly! + /// - pArg: Value to set it to. You can pass NULL to remove a non-global sett at this scope, + /// causing the value for that object to use global defaults. Or at global scope, passing NULL + /// will reset any custom value and restore it to the system default. + /// NOTE: When setting callback functions, do not pass the function pointer directly. + /// Your argument should be a pointer to a function pointer. + virtual bool SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, + ESteamNetworkingConfigDataType eDataType, const void *pArg ) = 0; + + /// Get a configuration value. + /// - eValue: which value to fetch + /// - eScopeType: query setting on what type of object + /// - eScopeArg: the object to query the setting for + /// - pOutDataType: If non-NULL, the data type of the value is returned. + /// - pResult: Where to put the result. Pass NULL to query the required buffer size. (k_ESteamNetworkingGetConfigValue_BufferTooSmall will be returned.) + /// - cbResult: IN: the size of your buffer. OUT: the number of bytes filled in or required. + virtual ESteamNetworkingGetConfigValueResult GetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, + ESteamNetworkingConfigDataType *pOutDataType, void *pResult, size_t *cbResult ) = 0; + + /// Returns info about a configuration value. Returns false if the value does not exist. + /// pOutNextValue can be used to iterate through all of the known configuration values. + /// (Use GetFirstConfigValue() to begin the iteration, will be k_ESteamNetworkingConfig_Invalid on the last value) + /// Any of the output parameters can be NULL if you do not need that information. + virtual bool GetConfigValueInfo( ESteamNetworkingConfigValue eValue, const char **pOutName, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope, ESteamNetworkingConfigValue *pOutNextValue ) = 0; + + /// Return the lowest numbered configuration value available in the current environment. + virtual ESteamNetworkingConfigValue GetFirstConfigValue() = 0; + + // String conversions. You'll usually access these using the respective + // inline methods. + virtual void SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr &addr, char *buf, size_t cbBuf, bool bWithPort ) = 0; + virtual bool SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr ) = 0; + virtual void SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf ) = 0; + virtual bool SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, const char *pszStr ) = 0; + +protected: + ~ISteamNetworkingUtils(); // Silence some warnings +}; +#define STEAMNETWORKINGUTILS_INTERFACE_VERSION "SteamNetworkingUtils002" + +// Global accessor. +#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB + + // Standalone lib + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingUtils *SteamNetworkingUtils_Lib(); + inline ISteamNetworkingUtils *SteamNetworkingUtils() { return SteamNetworkingUtils_Lib(); } + +#else + + // Steamworks SDK + inline ISteamNetworkingUtils *SteamNetworkingUtils(); + STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamNetworkingUtils *, SteamNetworkingUtils, SteamInternal_FindOrCreateUserInterface( 0, STEAMNETWORKINGUTILS_INTERFACE_VERSION ) ); +#endif + +/// A struct used to describe our readiness to use the relay network. +/// To do this we first need to fetch the network configuration, +/// which describes what POPs are available. +struct SteamRelayNetworkStatus_t +{ + enum { k_iCallback = k_iSteamNetworkingUtilsCallbacks + 1 }; + + /// Summary status. When this is "current", initialization has + /// completed. Anything else means you are not ready yet, or + /// there is a significant problem. + ESteamNetworkingAvailability m_eAvail; + + /// Nonzero if latency measurement is in progress (or pending, + /// awaiting a prerequisite). + int m_bPingMeasurementInProgress; + + /// Status obtaining the network config. This is a prerequisite + /// for relay network access. + /// + /// Failure to obtain the network config almost always indicates + /// a problem with the local internet connection. + ESteamNetworkingAvailability m_eAvailNetworkConfig; + + /// Current ability to communicate with ANY relay. Note that + /// the complete failure to communicate with any relays almost + /// always indicates a problem with the local Internet connection. + /// (However, just because you can reach a single relay doesn't + /// mean that the local connection is in perfect health.) + ESteamNetworkingAvailability m_eAvailAnyRelay; + + /// Non-localized English language status. For diagnostic/debugging + /// purposes only. + char m_debugMsg[ 256 ]; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// +// Internal stuff + +#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR +inline void ISteamNetworkingUtils::InitRelayNetworkAccess() { CheckPingDataUpToDate( 1e10f ); } +#endif + +inline bool ISteamNetworkingUtils::SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Int32, &val ); } +inline bool ISteamNetworkingUtils::SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Float, &val ); } +inline bool ISteamNetworkingUtils::SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_String, val ); } +inline bool ISteamNetworkingUtils::SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_Int32, &val ); } +inline bool ISteamNetworkingUtils::SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_Float, &val ); } +inline bool ISteamNetworkingUtils::SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Connection, hConn, k_ESteamNetworkingConfig_String, val ); } + +#if !defined( STEAMNETWORKINGSOCKETS_STATIC_LINK ) && defined( STEAMNETWORKINGSOCKETS_STEAMCLIENT ) +inline void SteamNetworkingIPAddr::ToString( char *buf, size_t cbBuf, bool bWithPort ) const { SteamNetworkingUtils()->SteamNetworkingIPAddr_ToString( *this, buf, cbBuf, bWithPort ); } +inline bool SteamNetworkingIPAddr::ParseString( const char *pszStr ) { return SteamNetworkingUtils()->SteamNetworkingIPAddr_ParseString( this, pszStr ); } +inline void SteamNetworkingIdentity::ToString( char *buf, size_t cbBuf ) const { SteamNetworkingUtils()->SteamNetworkingIdentity_ToString( *this, buf, cbBuf ); } +inline bool SteamNetworkingIdentity::ParseString( const char *pszStr ) { return SteamNetworkingUtils()->SteamNetworkingIdentity_ParseString( this, pszStr ); } +#endif + +#endif // ISTEAMNETWORKINGUTILS diff --git a/public/steam/isteamparentalsettings.h b/public/steam/isteamparentalsettings.h new file mode 100644 index 0000000..c965e32 --- /dev/null +++ b/public/steam/isteamparentalsettings.h @@ -0,0 +1,62 @@ +//====== Copyright � 2013-, Valve Corporation, All rights reserved. ======= +// +// Purpose: Interface to Steam parental settings (Family View) +// +//============================================================================= + +#ifndef ISTEAMPARENTALSETTINGS_H +#define ISTEAMPARENTALSETTINGS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +// Feature types for parental settings +enum EParentalFeature +{ + k_EFeatureInvalid = 0, + k_EFeatureStore = 1, + k_EFeatureCommunity = 2, + k_EFeatureProfile = 3, + k_EFeatureFriends = 4, + k_EFeatureNews = 5, + k_EFeatureTrading = 6, + k_EFeatureSettings = 7, + k_EFeatureConsole = 8, + k_EFeatureBrowser = 9, + k_EFeatureParentalSetup = 10, + k_EFeatureLibrary = 11, + k_EFeatureTest = 12, + k_EFeatureMax +}; + +class ISteamParentalSettings +{ +public: + virtual bool BIsParentalLockEnabled() = 0; + virtual bool BIsParentalLockLocked() = 0; + + virtual bool BIsAppBlocked( AppId_t nAppID ) = 0; + virtual bool BIsAppInBlockList( AppId_t nAppID ) = 0; + + virtual bool BIsFeatureBlocked( EParentalFeature eFeature ) = 0; + virtual bool BIsFeatureInBlockList( EParentalFeature eFeature ) = 0; +}; + +#define STEAMPARENTALSETTINGS_INTERFACE_VERSION "STEAMPARENTALSETTINGS_INTERFACE_VERSION001" + +// Global interface accessor +inline ISteamParentalSettings *SteamParentalSettings(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamParentalSettings *, SteamParentalSettings, STEAMPARENTALSETTINGS_INTERFACE_VERSION ); + +//----------------------------------------------------------------------------- +// Purpose: Callback for querying UGC +//----------------------------------------------------------------------------- +struct SteamParentalSettingsChanged_t +{ + enum { k_iCallback = k_ISteamParentalSettingsCallbacks + 1 }; +}; + + +#endif // ISTEAMPARENTALSETTINGS_H diff --git a/public/steam/isteamps3overlayrenderer.h b/public/steam/isteamps3overlayrenderer.h new file mode 100644 index 0000000..4e07d4a --- /dev/null +++ b/public/steam/isteamps3overlayrenderer.h @@ -0,0 +1,91 @@ +//====== Copyright 1996-2010, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface the game must provide Steam with on PS3 in order for the +// Steam overlay to render. +// +//============================================================================= + +#ifndef ISTEAMPS3OVERLAYRENDERER_H +#define ISTEAMPS3OVERLAYRENDERER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cell/pad.h" + +//----------------------------------------------------------------------------- +// Purpose: Enum for supported gradient directions +//----------------------------------------------------------------------------- +enum EOverlayGradientDirection +{ + k_EOverlayGradientHorizontal = 1, + k_EOverlayGradientVertical = 2, + k_EOverlayGradientNone = 3, +}; + +// Helpers for fetching individual color components from ARGB packed DWORD colors Steam PS3 overlay renderer uses. +#define STEAM_COLOR_RED( color ) \ + (int)(((color)>>16)&0xff) + +#define STEAM_COLOR_GREEN( color ) \ + (int)(((color)>>8)&0xff) + +#define STEAM_COLOR_BLUE( color ) \ + (int)((color)&0xff) + +#define STEAM_COLOR_ALPHA( color ) \ + (int)(((color)>>24)&0xff) + + +//----------------------------------------------------------------------------- +// Purpose: Interface the game must expose to Steam for rendering +//----------------------------------------------------------------------------- +class ISteamPS3OverlayRenderHost +{ +public: + + // Interface for game engine to implement which Steam requires to render. + + // Draw a textured rect. This may use only part of the texture and will pass texture coords, it will also possibly request a gradient and will specify colors for vertexes. + virtual void DrawTexturedRect( int x0, int y0, int x1, int y1, float u0, float v0, float u1, float v1, int32 iTextureID, DWORD colorStart, DWORD colorEnd, EOverlayGradientDirection eDirection ) = 0; + + // Load a RGBA texture for Steam, or update a previously loaded one. Updates may be partial. You must not evict or remove this texture once Steam has uploaded it. + virtual void LoadOrUpdateTexture( int32 iTextureID, bool bIsFullTexture, int x0, int y0, uint32 uWidth, uint32 uHeight, int32 iBytes, char *pData ) = 0; + + // Delete a texture Steam previously uploaded + virtual void DeleteTexture( int32 iTextureID ) = 0; + + // Delete all previously uploaded textures + virtual void DeleteAllTextures() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Interface Steam exposes for the game to tell it when to render, etc. +//----------------------------------------------------------------------------- +class ISteamPS3OverlayRender +{ +public: + + // Call once at startup to initialize the Steam overlay and pass it your host interface ptr + virtual bool BHostInitialize( uint32 unScreenWidth, uint32 unScreenHeight, uint32 unRefreshRate, ISteamPS3OverlayRenderHost *pRenderHost, void *CellFontLib ) = 0; + + // Call this once a frame when you are ready for the Steam overlay to render (ie, right before flipping buffers, after all your rendering) + virtual void Render() = 0; + + // Call this everytime you read input on PS3. + // + // If this returns true, then the overlay is active and has consumed the input, your game + // should then ignore all the input until BHandleCellPadData once again returns false, which + // will mean the overlay is deactivated. + virtual bool BHandleCellPadData( const CellPadData &padData ) = 0; + + // Call this if you detect no controllers connected or that the XMB is intercepting input + // + // This is important to clear input state for the overlay, so keys left down during XMB activation + // are not continued to be processed. + virtual bool BResetInputState() = 0; +}; + + +#endif // ISTEAMPS3OVERLAYRENDERER_H \ No newline at end of file diff --git a/public/steam/isteamremoteplay.h b/public/steam/isteamremoteplay.h new file mode 100644 index 0000000..96225fa --- /dev/null +++ b/public/steam/isteamremoteplay.h @@ -0,0 +1,81 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMREMOTEPLAY_H +#define ISTEAMREMOTEPLAY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + + +//----------------------------------------------------------------------------- +// Purpose: The form factor of a device +//----------------------------------------------------------------------------- +enum ESteamDeviceFormFactor +{ + k_ESteamDeviceFormFactorUnknown, + k_ESteamDeviceFormFactorPhone, + k_ESteamDeviceFormFactorTablet, + k_ESteamDeviceFormFactorComputer, + k_ESteamDeviceFormFactorTV, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions to provide information about Steam Remote Play sessions +//----------------------------------------------------------------------------- +class ISteamRemotePlay +{ +public: + // Get the number of currently connected Steam Remote Play sessions + virtual uint32 GetSessionCount() = 0; + + // Get the currently connected Steam Remote Play session ID at the specified index. Returns zero if index is out of bounds. + virtual uint32 GetSessionID( int iSessionIndex ) = 0; + + // Get the SteamID of the connected user + virtual CSteamID GetSessionSteamID( uint32 unSessionID ) = 0; + + // Get the name of the session client device + // This returns NULL if the sessionID is not valid + virtual const char *GetSessionClientName( uint32 unSessionID ) = 0; + + // Get the form factor of the session client device + virtual ESteamDeviceFormFactor GetSessionClientFormFactor( uint32 unSessionID ) = 0; + + // Get the resolution, in pixels, of the session client device + // This is set to 0x0 if the resolution is not available + virtual bool BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY ) = 0; +}; + +#define STEAMREMOTEPLAY_INTERFACE_VERSION "STEAMREMOTEPLAY_INTERFACE_VERSION001" + +// Global interface accessor +inline ISteamRemotePlay *SteamRemotePlay(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamRemotePlay *, SteamRemotePlay, STEAMREMOTEPLAY_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +STEAM_CALLBACK_BEGIN( SteamRemotePlaySessionConnected_t, k_iSteamRemotePlayCallbacks + 1 ) + STEAM_CALLBACK_MEMBER( 0, uint32, m_unSessionID ) +STEAM_CALLBACK_END( 0 ) + + +STEAM_CALLBACK_BEGIN( SteamRemotePlaySessionDisconnected_t, k_iSteamRemotePlayCallbacks + 2 ) + STEAM_CALLBACK_MEMBER( 0, uint32, m_unSessionID ) +STEAM_CALLBACK_END( 0 ) + + +#pragma pack( pop ) + + +#endif // #define ISTEAMREMOTEPLAY_H diff --git a/public/steam/isteamremotestorage.h b/public/steam/isteamremotestorage.h new file mode 100644 index 0000000..8707bb2 --- /dev/null +++ b/public/steam/isteamremotestorage.h @@ -0,0 +1,686 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: public interface to user remote file storage in Steam +// +//============================================================================= + +#ifndef ISTEAMREMOTESTORAGE_H +#define ISTEAMREMOTESTORAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + + +//----------------------------------------------------------------------------- +// Purpose: Defines the largest allowed file size. Cloud files cannot be written +// in a single chunk over 100MB (and cannot be over 200MB total.) +//----------------------------------------------------------------------------- +const uint32 k_unMaxCloudFileChunkSize = 100 * 1024 * 1024; + + +//----------------------------------------------------------------------------- +// Purpose: Structure that contains an array of const char * strings and the number of those strings +//----------------------------------------------------------------------------- +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif +struct SteamParamStringArray_t +{ + const char ** m_ppStrings; + int32 m_nNumStrings; +}; +#pragma pack( pop ) + +// A handle to a piece of user generated content +typedef uint64 UGCHandle_t; +typedef uint64 PublishedFileUpdateHandle_t; +typedef uint64 PublishedFileId_t; +const PublishedFileId_t k_PublishedFileIdInvalid = 0; +const UGCHandle_t k_UGCHandleInvalid = 0xffffffffffffffffull; +const PublishedFileUpdateHandle_t k_PublishedFileUpdateHandleInvalid = 0xffffffffffffffffull; + +// Handle for writing to Steam Cloud +typedef uint64 UGCFileWriteStreamHandle_t; +const UGCFileWriteStreamHandle_t k_UGCFileStreamHandleInvalid = 0xffffffffffffffffull; + +const uint32 k_cchPublishedDocumentTitleMax = 128 + 1; +const uint32 k_cchPublishedDocumentDescriptionMax = 8000; +const uint32 k_cchPublishedDocumentChangeDescriptionMax = 8000; +const uint32 k_unEnumeratePublishedFilesMaxResults = 50; +const uint32 k_cchTagListMax = 1024 + 1; +const uint32 k_cchFilenameMax = 260; +const uint32 k_cchPublishedFileURLMax = 256; + + +enum ERemoteStoragePlatform +{ + k_ERemoteStoragePlatformNone = 0, + k_ERemoteStoragePlatformWindows = (1 << 0), + k_ERemoteStoragePlatformOSX = (1 << 1), + k_ERemoteStoragePlatformPS3 = (1 << 2), + k_ERemoteStoragePlatformLinux = (1 << 3), + k_ERemoteStoragePlatformReserved2 = (1 << 4), + k_ERemoteStoragePlatformAndroid = (1 << 5), + k_ERemoteStoragePlatformIOS = (1 << 6), + + k_ERemoteStoragePlatformAll = 0xffffffff +}; + +enum ERemoteStoragePublishedFileVisibility +{ + k_ERemoteStoragePublishedFileVisibilityPublic = 0, + k_ERemoteStoragePublishedFileVisibilityFriendsOnly = 1, + k_ERemoteStoragePublishedFileVisibilityPrivate = 2, +}; + + +enum EWorkshopFileType +{ + k_EWorkshopFileTypeFirst = 0, + + k_EWorkshopFileTypeCommunity = 0, // normal Workshop item that can be subscribed to + k_EWorkshopFileTypeMicrotransaction = 1, // Workshop item that is meant to be voted on for the purpose of selling in-game + k_EWorkshopFileTypeCollection = 2, // a collection of Workshop or Greenlight items + k_EWorkshopFileTypeArt = 3, // artwork + k_EWorkshopFileTypeVideo = 4, // external video + k_EWorkshopFileTypeScreenshot = 5, // screenshot + k_EWorkshopFileTypeGame = 6, // Greenlight game entry + k_EWorkshopFileTypeSoftware = 7, // Greenlight software entry + k_EWorkshopFileTypeConcept = 8, // Greenlight concept + k_EWorkshopFileTypeWebGuide = 9, // Steam web guide + k_EWorkshopFileTypeIntegratedGuide = 10, // application integrated guide + k_EWorkshopFileTypeMerch = 11, // Workshop merchandise meant to be voted on for the purpose of being sold + k_EWorkshopFileTypeControllerBinding = 12, // Steam Controller bindings + k_EWorkshopFileTypeSteamworksAccessInvite = 13, // internal + k_EWorkshopFileTypeSteamVideo = 14, // Steam video + k_EWorkshopFileTypeGameManagedItem = 15, // managed completely by the game, not the user, and not shown on the web + + // Update k_EWorkshopFileTypeMax if you add values. + k_EWorkshopFileTypeMax = 16 + +}; + +enum EWorkshopVote +{ + k_EWorkshopVoteUnvoted = 0, + k_EWorkshopVoteFor = 1, + k_EWorkshopVoteAgainst = 2, + k_EWorkshopVoteLater = 3, +}; + +enum EWorkshopFileAction +{ + k_EWorkshopFileActionPlayed = 0, + k_EWorkshopFileActionCompleted = 1, +}; + +enum EWorkshopEnumerationType +{ + k_EWorkshopEnumerationTypeRankedByVote = 0, + k_EWorkshopEnumerationTypeRecent = 1, + k_EWorkshopEnumerationTypeTrending = 2, + k_EWorkshopEnumerationTypeFavoritesOfFriends = 3, + k_EWorkshopEnumerationTypeVotedByFriends = 4, + k_EWorkshopEnumerationTypeContentByFriends = 5, + k_EWorkshopEnumerationTypeRecentFromFollowedUsers = 6, +}; + +enum EWorkshopVideoProvider +{ + k_EWorkshopVideoProviderNone = 0, + k_EWorkshopVideoProviderYoutube = 1 +}; + + +enum EUGCReadAction +{ + // Keeps the file handle open unless the last byte is read. You can use this when reading large files (over 100MB) in sequential chunks. + // If the last byte is read, this will behave the same as k_EUGCRead_Close. Otherwise, it behaves the same as k_EUGCRead_ContinueReading. + // This value maintains the same behavior as before the EUGCReadAction parameter was introduced. + k_EUGCRead_ContinueReadingUntilFinished = 0, + + // Keeps the file handle open. Use this when using UGCRead to seek to different parts of the file. + // When you are done seeking around the file, make a final call with k_EUGCRead_Close to close it. + k_EUGCRead_ContinueReading = 1, + + // Frees the file handle. Use this when you're done reading the content. + // To read the file from Steam again you will need to call UGCDownload again. + k_EUGCRead_Close = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing, reading and writing files stored remotely +// and cached locally +//----------------------------------------------------------------------------- +class ISteamRemoteStorage +{ + public: + // NOTE + // + // Filenames are case-insensitive, and will be converted to lowercase automatically. + // So "foo.bar" and "Foo.bar" are the same file, and if you write "Foo.bar" then + // iterate the files, the filename returned will be "foo.bar". + // + + // file operations + virtual bool FileWrite( const char *pchFile, const void *pvData, int32 cubData ) = 0; + virtual int32 FileRead( const char *pchFile, void *pvData, int32 cubDataToRead ) = 0; + + STEAM_CALL_RESULT( RemoteStorageFileWriteAsyncComplete_t ) + virtual SteamAPICall_t FileWriteAsync( const char *pchFile, const void *pvData, uint32 cubData ) = 0; + + STEAM_CALL_RESULT( RemoteStorageFileReadAsyncComplete_t ) + virtual SteamAPICall_t FileReadAsync( const char *pchFile, uint32 nOffset, uint32 cubToRead ) = 0; + virtual bool FileReadAsyncComplete( SteamAPICall_t hReadCall, void *pvBuffer, uint32 cubToRead ) = 0; + + virtual bool FileForget( const char *pchFile ) = 0; + virtual bool FileDelete( const char *pchFile ) = 0; + STEAM_CALL_RESULT( RemoteStorageFileShareResult_t ) + virtual SteamAPICall_t FileShare( const char *pchFile ) = 0; + virtual bool SetSyncPlatforms( const char *pchFile, ERemoteStoragePlatform eRemoteStoragePlatform ) = 0; + + // file operations that cause network IO + virtual UGCFileWriteStreamHandle_t FileWriteStreamOpen( const char *pchFile ) = 0; + virtual bool FileWriteStreamWriteChunk( UGCFileWriteStreamHandle_t writeHandle, const void *pvData, int32 cubData ) = 0; + virtual bool FileWriteStreamClose( UGCFileWriteStreamHandle_t writeHandle ) = 0; + virtual bool FileWriteStreamCancel( UGCFileWriteStreamHandle_t writeHandle ) = 0; + + // file information + virtual bool FileExists( const char *pchFile ) = 0; + virtual bool FilePersisted( const char *pchFile ) = 0; + virtual int32 GetFileSize( const char *pchFile ) = 0; + virtual int64 GetFileTimestamp( const char *pchFile ) = 0; + virtual ERemoteStoragePlatform GetSyncPlatforms( const char *pchFile ) = 0; + + // iteration + virtual int32 GetFileCount() = 0; + virtual const char *GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes ) = 0; + + // configuration management + virtual bool GetQuota( uint64 *pnTotalBytes, uint64 *puAvailableBytes ) = 0; + virtual bool IsCloudEnabledForAccount() = 0; + virtual bool IsCloudEnabledForApp() = 0; + virtual void SetCloudEnabledForApp( bool bEnabled ) = 0; + + // user generated content + + // Downloads a UGC file. A priority value of 0 will download the file immediately, + // otherwise it will wait to download the file until all downloads with a lower priority + // value are completed. Downloads with equal priority will occur simultaneously. + STEAM_CALL_RESULT( RemoteStorageDownloadUGCResult_t ) + virtual SteamAPICall_t UGCDownload( UGCHandle_t hContent, uint32 unPriority ) = 0; + + // Gets the amount of data downloaded so far for a piece of content. pnBytesExpected can be 0 if function returns false + // or if the transfer hasn't started yet, so be careful to check for that before dividing to get a percentage + virtual bool GetUGCDownloadProgress( UGCHandle_t hContent, int32 *pnBytesDownloaded, int32 *pnBytesExpected ) = 0; + + // Gets metadata for a file after it has been downloaded. This is the same metadata given in the RemoteStorageDownloadUGCResult_t call result + virtual bool GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID, STEAM_OUT_STRING() char **ppchName, int32 *pnFileSizeInBytes, STEAM_OUT_STRUCT() CSteamID *pSteamIDOwner ) = 0; + + // After download, gets the content of the file. + // Small files can be read all at once by calling this function with an offset of 0 and cubDataToRead equal to the size of the file. + // Larger files can be read in chunks to reduce memory usage (since both sides of the IPC client and the game itself must allocate + // enough memory for each chunk). Once the last byte is read, the file is implicitly closed and further calls to UGCRead will fail + // unless UGCDownload is called again. + // For especially large files (anything over 100MB) it is a requirement that the file is read in chunks. + virtual int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset, EUGCReadAction eAction ) = 0; + + // Functions to iterate through UGC that has finished downloading but has not yet been read via UGCRead() + virtual int32 GetCachedUGCCount() = 0; + virtual UGCHandle_t GetCachedUGCHandle( int32 iCachedContent ) = 0; + + // The following functions are only necessary on the Playstation 3. On PC & Mac, the Steam client will handle these operations for you + // On Playstation 3, the game controls which files are stored in the cloud, via FilePersist, FileFetch, and FileForget. + +#if defined(_PS3) || defined(_SERVER) + // Connect to Steam and get a list of files in the Cloud - results in a RemoteStorageAppSyncStatusCheck_t callback + virtual void GetFileListFromServer() = 0; + // Indicate this file should be downloaded in the next sync + virtual bool FileFetch( const char *pchFile ) = 0; + // Indicate this file should be persisted in the next sync + virtual bool FilePersist( const char *pchFile ) = 0; + // Pull any requested files down from the Cloud - results in a RemoteStorageAppSyncedClient_t callback + virtual bool SynchronizeToClient() = 0; + // Upload any requested files to the Cloud - results in a RemoteStorageAppSyncedServer_t callback + virtual bool SynchronizeToServer() = 0; + // Reset any fetch/persist/etc requests + virtual bool ResetFileRequestState() = 0; +#endif + + // publishing UGC + STEAM_CALL_RESULT( RemoteStoragePublishFileProgress_t ) + virtual SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags, EWorkshopFileType eWorkshopFileType ) = 0; + virtual PublishedFileUpdateHandle_t CreatePublishedFileUpdateRequest( PublishedFileId_t unPublishedFileId ) = 0; + virtual bool UpdatePublishedFileFile( PublishedFileUpdateHandle_t updateHandle, const char *pchFile ) = 0; + virtual bool UpdatePublishedFilePreviewFile( PublishedFileUpdateHandle_t updateHandle, const char *pchPreviewFile ) = 0; + virtual bool UpdatePublishedFileTitle( PublishedFileUpdateHandle_t updateHandle, const char *pchTitle ) = 0; + virtual bool UpdatePublishedFileDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchDescription ) = 0; + virtual bool UpdatePublishedFileVisibility( PublishedFileUpdateHandle_t updateHandle, ERemoteStoragePublishedFileVisibility eVisibility ) = 0; + virtual bool UpdatePublishedFileTags( PublishedFileUpdateHandle_t updateHandle, SteamParamStringArray_t *pTags ) = 0; + STEAM_CALL_RESULT( RemoteStorageUpdatePublishedFileResult_t ) + virtual SteamAPICall_t CommitPublishedFileUpdate( PublishedFileUpdateHandle_t updateHandle ) = 0; + // Gets published file details for the given publishedfileid. If unMaxSecondsOld is greater than 0, + // cached data may be returned, depending on how long ago it was cached. A value of 0 will force a refresh. + // A value of k_WorkshopForceLoadPublishedFileDetailsFromCache will use cached data if it exists, no matter how old it is. + STEAM_CALL_RESULT( RemoteStorageGetPublishedFileDetailsResult_t ) + virtual SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld ) = 0; + STEAM_CALL_RESULT( RemoteStorageDeletePublishedFileResult_t ) + virtual SteamAPICall_t DeletePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + // enumerate the files that the current user published with this app + STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) + virtual SteamAPICall_t EnumerateUserPublishedFiles( uint32 unStartIndex ) = 0; + STEAM_CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t ) + virtual SteamAPICall_t SubscribePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + STEAM_CALL_RESULT( RemoteStorageEnumerateUserSubscribedFilesResult_t ) + virtual SteamAPICall_t EnumerateUserSubscribedFiles( uint32 unStartIndex ) = 0; + STEAM_CALL_RESULT( RemoteStorageUnsubscribePublishedFileResult_t ) + virtual SteamAPICall_t UnsubscribePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + virtual bool UpdatePublishedFileSetChangeDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchChangeDescription ) = 0; + STEAM_CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t ) + virtual SteamAPICall_t GetPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) = 0; + STEAM_CALL_RESULT( RemoteStorageUpdateUserPublishedItemVoteResult_t ) + virtual SteamAPICall_t UpdateUserPublishedItemVote( PublishedFileId_t unPublishedFileId, bool bVoteUp ) = 0; + STEAM_CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t ) + virtual SteamAPICall_t GetUserPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) = 0; + STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) + virtual SteamAPICall_t EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) = 0; + STEAM_CALL_RESULT( RemoteStoragePublishFileProgress_t ) + virtual SteamAPICall_t PublishVideo( EWorkshopVideoProvider eVideoProvider, const char *pchVideoAccount, const char *pchVideoIdentifier, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) = 0; + STEAM_CALL_RESULT( RemoteStorageSetUserPublishedFileActionResult_t ) + virtual SteamAPICall_t SetUserPublishedFileAction( PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction ) = 0; + STEAM_CALL_RESULT( RemoteStorageEnumeratePublishedFilesByUserActionResult_t ) + virtual SteamAPICall_t EnumeratePublishedFilesByUserAction( EWorkshopFileAction eAction, uint32 unStartIndex ) = 0; + // this method enumerates the public view of workshop files + STEAM_CALL_RESULT( RemoteStorageEnumerateWorkshopFilesResult_t ) + virtual SteamAPICall_t EnumeratePublishedWorkshopFiles( EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, SteamParamStringArray_t *pTags, SteamParamStringArray_t *pUserTags ) = 0; + + STEAM_CALL_RESULT( RemoteStorageDownloadUGCResult_t ) + virtual SteamAPICall_t UGCDownloadToLocation( UGCHandle_t hContent, const char *pchLocation, uint32 unPriority ) = 0; +}; + +#define STEAMREMOTESTORAGE_INTERFACE_VERSION "STEAMREMOTESTORAGE_INTERFACE_VERSION014" + +// Global interface accessor +inline ISteamRemoteStorage *SteamRemoteStorage(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamRemoteStorage *, SteamRemoteStorage, STEAMREMOTESTORAGE_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +//----------------------------------------------------------------------------- +// Purpose: sent when the local file cache is fully synced with the server for an app +// That means that an application can be started and has all latest files +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncedClient_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 1 }; + AppId_t m_nAppID; + EResult m_eResult; + int m_unNumDownloads; +}; + +//----------------------------------------------------------------------------- +// Purpose: sent when the server is fully synced with the local file cache for an app +// That means that we can shutdown Steam and our data is stored on the server +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncedServer_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 2 }; + AppId_t m_nAppID; + EResult m_eResult; + int m_unNumUploads; +}; + +//----------------------------------------------------------------------------- +// Purpose: Status of up and downloads during a sync session +// +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncProgress_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 3 }; + char m_rgchCurrentFile[k_cchFilenameMax]; // Current file being transferred + AppId_t m_nAppID; // App this info relates to + uint32 m_uBytesTransferredThisChunk; // Bytes transferred this chunk + double m_dAppPercentComplete; // Percent complete that this app's transfers are + bool m_bUploading; // if false, downloading +}; + +// +// IMPORTANT! k_iClientRemoteStorageCallbacks + 4 is used, see iclientremotestorage.h +// + + +//----------------------------------------------------------------------------- +// Purpose: Sent after we've determined the list of files that are out of sync +// with the server. +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncStatusCheck_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 5 }; + AppId_t m_nAppID; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to FileShare() +//----------------------------------------------------------------------------- +struct RemoteStorageFileShareResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 7 }; + EResult m_eResult; // The result of the operation + UGCHandle_t m_hFile; // The handle that can be shared with users and features + char m_rgchFilename[k_cchFilenameMax]; // The name of the file that was shared +}; + + +// k_iClientRemoteStorageCallbacks + 8 is deprecated! Do not reuse + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to PublishFile() +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 9 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to DeletePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageDeletePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 11 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to EnumerateUserPublishedFiles() +//----------------------------------------------------------------------------- +struct RemoteStorageEnumerateUserPublishedFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 12 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to SubscribePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageSubscribePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 13 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to EnumerateSubscribePublishedFiles() +//----------------------------------------------------------------------------- +struct RemoteStorageEnumerateUserSubscribedFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 14 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + uint32 m_rgRTimeSubscribed[ k_unEnumeratePublishedFilesMaxResults ]; +}; + +#if defined(VALVE_CALLBACK_PACK_SMALL) + VALVE_COMPILE_TIME_ASSERT( sizeof( RemoteStorageEnumerateUserSubscribedFilesResult_t ) == (1 + 1 + 1 + 50 + 100) * 4 ); +#elif defined(VALVE_CALLBACK_PACK_LARGE) + VALVE_COMPILE_TIME_ASSERT( sizeof( RemoteStorageEnumerateUserSubscribedFilesResult_t ) == (1 + 1 + 1 + 50 + 100) * 4 + 4 ); +#else +#warning You must first include steam_api_common.h +#endif + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UnsubscribePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageUnsubscribePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 15 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to CommitPublishedFileUpdate() +//----------------------------------------------------------------------------- +struct RemoteStorageUpdatePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 16 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UGCDownload() +//----------------------------------------------------------------------------- +struct RemoteStorageDownloadUGCResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 17 }; + EResult m_eResult; // The result of the operation. + UGCHandle_t m_hFile; // The handle to the file that was attempted to be downloaded. + AppId_t m_nAppID; // ID of the app that created this file. + int32 m_nSizeInBytes; // The size of the file that was downloaded, in bytes. + char m_pchFileName[k_cchFilenameMax]; // The name of the file that was downloaded. + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetPublishedFileDetails() +//----------------------------------------------------------------------------- +struct RemoteStorageGetPublishedFileDetailsResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 18 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nCreatorAppID; // ID of the app that created this file. + AppId_t m_nConsumerAppID; // ID of the app that will consume this file. + char m_rgchTitle[k_cchPublishedDocumentTitleMax]; // title of document + char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; // description of document + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + ERemoteStoragePublishedFileVisibility m_eVisibility; + bool m_bBanned; + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + bool m_bTagsTruncated; // whether the list of tags was too long to be returned in the provided buffer + char m_pchFileName[k_cchFilenameMax]; // The name of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + char m_rgchURL[k_cchPublishedFileURLMax]; // URL (for a video or a website) + EWorkshopFileType m_eFileType; // Type of the file + bool m_bAcceptedForUse; // developer has specifically flagged this item as accepted in the Workshop +}; + + +struct RemoteStorageEnumerateWorkshopFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 19 }; + EResult m_eResult; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + float m_rgScore[ k_unEnumeratePublishedFilesMaxResults ]; + AppId_t m_nAppId; + uint32 m_unStartIndex; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of GetPublishedItemVoteDetails +//----------------------------------------------------------------------------- +struct RemoteStorageGetPublishedItemVoteDetailsResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 20 }; + EResult m_eResult; + PublishedFileId_t m_unPublishedFileId; + int32 m_nVotesFor; + int32 m_nVotesAgainst; + int32 m_nReports; + float m_fScore; +}; + + +//----------------------------------------------------------------------------- +// Purpose: User subscribed to a file for the app (from within the app or on the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileSubscribed_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 21 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + +//----------------------------------------------------------------------------- +// Purpose: User unsubscribed from a file for the app (from within the app or on the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileUnsubscribed_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 22 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + + +//----------------------------------------------------------------------------- +// Purpose: Published file that a user owns was deleted (from within the app or the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileDeleted_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 23 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UpdateUserPublishedItemVote() +//----------------------------------------------------------------------------- +struct RemoteStorageUpdateUserPublishedItemVoteResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 24 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetUserPublishedItemVoteDetails() +//----------------------------------------------------------------------------- +struct RemoteStorageUserVoteDetails_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 25 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id + EWorkshopVote m_eVote; // what the user voted +}; + +struct RemoteStorageEnumerateUserSharedWorkshopFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 26 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; +}; + +struct RemoteStorageSetUserPublishedFileActionResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 27 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id + EWorkshopFileAction m_eAction; // the action that was attempted +}; + +struct RemoteStorageEnumeratePublishedFilesByUserActionResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 28 }; + EResult m_eResult; // The result of the operation. + EWorkshopFileAction m_eAction; // the action that was filtered on + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + uint32 m_rgRTimeUpdated[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Called periodically while a PublishWorkshopFile is in progress +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileProgress_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 29 }; + double m_dPercentFile; + bool m_bPreview; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Called when the content for a published file is updated +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileUpdated_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 30 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. + uint64 m_ulUnused; // not used anymore +}; + +//----------------------------------------------------------------------------- +// Purpose: Called when a FileWriteAsync completes +//----------------------------------------------------------------------------- +struct RemoteStorageFileWriteAsyncComplete_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 31 }; + EResult m_eResult; // result +}; + +//----------------------------------------------------------------------------- +// Purpose: Called when a FileReadAsync completes +//----------------------------------------------------------------------------- +struct RemoteStorageFileReadAsyncComplete_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 32 }; + SteamAPICall_t m_hFileReadAsync; // call handle of the async read which was made + EResult m_eResult; // result + uint32 m_nOffset; // offset in the file this read was at + uint32 m_cubRead; // amount read - will the <= the amount requested +}; + +#pragma pack( pop ) + + +#endif // ISTEAMREMOTESTORAGE_H diff --git a/public/steam/isteamscreenshots.h b/public/steam/isteamscreenshots.h new file mode 100644 index 0000000..1824268 --- /dev/null +++ b/public/steam/isteamscreenshots.h @@ -0,0 +1,120 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: public interface to user remote file storage in Steam +// +//============================================================================= + +#ifndef ISTEAMSCREENSHOTS_H +#define ISTEAMSCREENSHOTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +const uint32 k_nScreenshotMaxTaggedUsers = 32; +const uint32 k_nScreenshotMaxTaggedPublishedFiles = 32; +const int k_cubUFSTagTypeMax = 255; +const int k_cubUFSTagValueMax = 255; + +// Required with of a thumbnail provided to AddScreenshotToLibrary. If you do not provide a thumbnail +// one will be generated. +const int k_ScreenshotThumbWidth = 200; + +// Handle is valid for the lifetime of your process and no longer +typedef uint32 ScreenshotHandle; +#define INVALID_SCREENSHOT_HANDLE 0 + +enum EVRScreenshotType +{ + k_EVRScreenshotType_None = 0, + k_EVRScreenshotType_Mono = 1, + k_EVRScreenshotType_Stereo = 2, + k_EVRScreenshotType_MonoCubemap = 3, + k_EVRScreenshotType_MonoPanorama = 4, + k_EVRScreenshotType_StereoPanorama = 5 +}; + +//----------------------------------------------------------------------------- +// Purpose: Functions for adding screenshots to the user's screenshot library +//----------------------------------------------------------------------------- +class ISteamScreenshots +{ +public: + // Writes a screenshot to the user's screenshot library given the raw image data, which must be in RGB format. + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + virtual ScreenshotHandle WriteScreenshot( void *pubRGB, uint32 cubRGB, int nWidth, int nHeight ) = 0; + + // Adds a screenshot to the user's screenshot library from disk. If a thumbnail is provided, it must be 200 pixels wide and the same aspect ratio + // as the screenshot, otherwise a thumbnail will be generated if the user uploads the screenshot. The screenshots must be in either JPEG or TGA format. + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + // JPEG, TGA, and PNG formats are supported. + virtual ScreenshotHandle AddScreenshotToLibrary( const char *pchFilename, const char *pchThumbnailFilename, int nWidth, int nHeight ) = 0; + + // Causes the Steam overlay to take a screenshot. If screenshots are being hooked by the game then a ScreenshotRequested_t callback is sent back to the game instead. + virtual void TriggerScreenshot() = 0; + + // Toggles whether the overlay handles screenshots when the user presses the screenshot hotkey, or the game handles them. If the game is hooking screenshots, + // then the ScreenshotRequested_t callback will be sent if the user presses the hotkey, and the game is expected to call WriteScreenshot or AddScreenshotToLibrary + // in response. + virtual void HookScreenshots( bool bHook ) = 0; + + // Sets metadata about a screenshot's location (for example, the name of the map) + virtual bool SetLocation( ScreenshotHandle hScreenshot, const char *pchLocation ) = 0; + + // Tags a user as being visible in the screenshot + virtual bool TagUser( ScreenshotHandle hScreenshot, CSteamID steamID ) = 0; + + // Tags a published file as being visible in the screenshot + virtual bool TagPublishedFile( ScreenshotHandle hScreenshot, PublishedFileId_t unPublishedFileID ) = 0; + + // Returns true if the app has hooked the screenshot + virtual bool IsScreenshotsHooked() = 0; + + // Adds a VR screenshot to the user's screenshot library from disk in the supported type. + // pchFilename should be the normal 2D image used in the library view + // pchVRFilename should contain the image that matches the correct type + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + // JPEG, TGA, and PNG formats are supported. + virtual ScreenshotHandle AddVRScreenshotToLibrary( EVRScreenshotType eType, const char *pchFilename, const char *pchVRFilename ) = 0; +}; + +#define STEAMSCREENSHOTS_INTERFACE_VERSION "STEAMSCREENSHOTS_INTERFACE_VERSION003" + +// Global interface accessor +inline ISteamScreenshots *SteamScreenshots(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamScreenshots *, SteamScreenshots, STEAMSCREENSHOTS_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif +//----------------------------------------------------------------------------- +// Purpose: Screenshot successfully written or otherwise added to the library +// and can now be tagged +//----------------------------------------------------------------------------- +struct ScreenshotReady_t +{ + enum { k_iCallback = k_iSteamScreenshotsCallbacks + 1 }; + ScreenshotHandle m_hLocal; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: Screenshot has been requested by the user. Only sent if +// HookScreenshots() has been called, in which case Steam will not take +// the screenshot itself. +//----------------------------------------------------------------------------- +struct ScreenshotRequested_t +{ + enum { k_iCallback = k_iSteamScreenshotsCallbacks + 2 }; +}; + +#pragma pack( pop ) + +#endif // ISTEAMSCREENSHOTS_H + diff --git a/public/steam/isteamugc.h b/public/steam/isteamugc.h new file mode 100644 index 0000000..e52388f --- /dev/null +++ b/public/steam/isteamugc.h @@ -0,0 +1,562 @@ +//====== Copyright 1996-2013, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to steam ugc +// +//============================================================================= + +#ifndef ISTEAMUGC_H +#define ISTEAMUGC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "isteamremotestorage.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + +typedef uint64 UGCQueryHandle_t; +typedef uint64 UGCUpdateHandle_t; + + +const UGCQueryHandle_t k_UGCQueryHandleInvalid = 0xffffffffffffffffull; +const UGCUpdateHandle_t k_UGCUpdateHandleInvalid = 0xffffffffffffffffull; + + +// Matching UGC types for queries +enum EUGCMatchingUGCType +{ + k_EUGCMatchingUGCType_Items = 0, // both mtx items and ready-to-use items + k_EUGCMatchingUGCType_Items_Mtx = 1, + k_EUGCMatchingUGCType_Items_ReadyToUse = 2, + k_EUGCMatchingUGCType_Collections = 3, + k_EUGCMatchingUGCType_Artwork = 4, + k_EUGCMatchingUGCType_Videos = 5, + k_EUGCMatchingUGCType_Screenshots = 6, + k_EUGCMatchingUGCType_AllGuides = 7, // both web guides and integrated guides + k_EUGCMatchingUGCType_WebGuides = 8, + k_EUGCMatchingUGCType_IntegratedGuides = 9, + k_EUGCMatchingUGCType_UsableInGame = 10, // ready-to-use items and integrated guides + k_EUGCMatchingUGCType_ControllerBindings = 11, + k_EUGCMatchingUGCType_GameManagedItems = 12, // game managed items (not managed by users) + k_EUGCMatchingUGCType_All = ~0, // return everything +}; + +// Different lists of published UGC for a user. +// If the current logged in user is different than the specified user, then some options may not be allowed. +enum EUserUGCList +{ + k_EUserUGCList_Published, + k_EUserUGCList_VotedOn, + k_EUserUGCList_VotedUp, + k_EUserUGCList_VotedDown, + k_EUserUGCList_WillVoteLater, + k_EUserUGCList_Favorited, + k_EUserUGCList_Subscribed, + k_EUserUGCList_UsedOrPlayed, + k_EUserUGCList_Followed, +}; + +// Sort order for user published UGC lists (defaults to creation order descending) +enum EUserUGCListSortOrder +{ + k_EUserUGCListSortOrder_CreationOrderDesc, + k_EUserUGCListSortOrder_CreationOrderAsc, + k_EUserUGCListSortOrder_TitleAsc, + k_EUserUGCListSortOrder_LastUpdatedDesc, + k_EUserUGCListSortOrder_SubscriptionDateDesc, + k_EUserUGCListSortOrder_VoteScoreDesc, + k_EUserUGCListSortOrder_ForModeration, +}; + +// Combination of sorting and filtering for queries across all UGC +enum EUGCQuery +{ + k_EUGCQuery_RankedByVote = 0, + k_EUGCQuery_RankedByPublicationDate = 1, + k_EUGCQuery_AcceptedForGameRankedByAcceptanceDate = 2, + k_EUGCQuery_RankedByTrend = 3, + k_EUGCQuery_FavoritedByFriendsRankedByPublicationDate = 4, + k_EUGCQuery_CreatedByFriendsRankedByPublicationDate = 5, + k_EUGCQuery_RankedByNumTimesReported = 6, + k_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate = 7, + k_EUGCQuery_NotYetRated = 8, + k_EUGCQuery_RankedByTotalVotesAsc = 9, + k_EUGCQuery_RankedByVotesUp = 10, + k_EUGCQuery_RankedByTextSearch = 11, + k_EUGCQuery_RankedByTotalUniqueSubscriptions = 12, + k_EUGCQuery_RankedByPlaytimeTrend = 13, + k_EUGCQuery_RankedByTotalPlaytime = 14, + k_EUGCQuery_RankedByAveragePlaytimeTrend = 15, + k_EUGCQuery_RankedByLifetimeAveragePlaytime = 16, + k_EUGCQuery_RankedByPlaytimeSessionsTrend = 17, + k_EUGCQuery_RankedByLifetimePlaytimeSessions = 18, +}; + +enum EItemUpdateStatus +{ + k_EItemUpdateStatusInvalid = 0, // The item update handle was invalid, job might be finished, listen too SubmitItemUpdateResult_t + k_EItemUpdateStatusPreparingConfig = 1, // The item update is processing configuration data + k_EItemUpdateStatusPreparingContent = 2, // The item update is reading and processing content files + k_EItemUpdateStatusUploadingContent = 3, // The item update is uploading content changes to Steam + k_EItemUpdateStatusUploadingPreviewFile = 4, // The item update is uploading new preview file image + k_EItemUpdateStatusCommittingChanges = 5 // The item update is committing all changes +}; + +enum EItemState +{ + k_EItemStateNone = 0, // item not tracked on client + k_EItemStateSubscribed = 1, // current user is subscribed to this item. Not just cached. + k_EItemStateLegacyItem = 2, // item was created with ISteamRemoteStorage + k_EItemStateInstalled = 4, // item is installed and usable (but maybe out of date) + k_EItemStateNeedsUpdate = 8, // items needs an update. Either because it's not installed yet or creator updated content + k_EItemStateDownloading = 16, // item update is currently downloading + k_EItemStateDownloadPending = 32, // DownloadItem() was called for this item, content isn't available until DownloadItemResult_t is fired +}; + +enum EItemStatistic +{ + k_EItemStatistic_NumSubscriptions = 0, + k_EItemStatistic_NumFavorites = 1, + k_EItemStatistic_NumFollowers = 2, + k_EItemStatistic_NumUniqueSubscriptions = 3, + k_EItemStatistic_NumUniqueFavorites = 4, + k_EItemStatistic_NumUniqueFollowers = 5, + k_EItemStatistic_NumUniqueWebsiteViews = 6, + k_EItemStatistic_ReportScore = 7, + k_EItemStatistic_NumSecondsPlayed = 8, + k_EItemStatistic_NumPlaytimeSessions = 9, + k_EItemStatistic_NumComments = 10, + k_EItemStatistic_NumSecondsPlayedDuringTimePeriod = 11, + k_EItemStatistic_NumPlaytimeSessionsDuringTimePeriod = 12, +}; + +enum EItemPreviewType +{ + k_EItemPreviewType_Image = 0, // standard image file expected (e.g. jpg, png, gif, etc.) + k_EItemPreviewType_YouTubeVideo = 1, // video id is stored + k_EItemPreviewType_Sketchfab = 2, // model id is stored + k_EItemPreviewType_EnvironmentMap_HorizontalCross = 3, // standard image file expected - cube map in the layout + // +---+---+-------+ + // | |Up | | + // +---+---+---+---+ + // | L | F | R | B | + // +---+---+---+---+ + // | |Dn | | + // +---+---+---+---+ + k_EItemPreviewType_EnvironmentMap_LatLong = 4, // standard image file expected + k_EItemPreviewType_ReservedMax = 255, // you can specify your own types above this value +}; + +const uint32 kNumUGCResultsPerPage = 50; +const uint32 k_cchDeveloperMetadataMax = 5000; + +// Details for a single published file/UGC +struct SteamUGCDetails_t +{ + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; // The result of the operation. + EWorkshopFileType m_eFileType; // Type of the file + AppId_t m_nCreatorAppID; // ID of the app that created this file. + AppId_t m_nConsumerAppID; // ID of the app that will consume this file. + char m_rgchTitle[k_cchPublishedDocumentTitleMax]; // title of document + char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; // description of document + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + uint32 m_rtimeAddedToUserList; // time when the user added the published file to their list (not always applicable) + ERemoteStoragePublishedFileVisibility m_eVisibility; // visibility + bool m_bBanned; // whether the file was banned + bool m_bAcceptedForUse; // developer has specifically flagged this item as accepted in the Workshop + bool m_bTagsTruncated; // whether the list of tags was too long to be returned in the provided buffer + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + // file/url information + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + char m_pchFileName[k_cchFilenameMax]; // The cloud filename of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + char m_rgchURL[k_cchPublishedFileURLMax]; // URL (for a video or a website) + // voting information + uint32 m_unVotesUp; // number of votes up + uint32 m_unVotesDown; // number of votes down + float m_flScore; // calculated score + // collection details + uint32 m_unNumChildren; +}; + +//----------------------------------------------------------------------------- +// Purpose: Steam UGC support API +//----------------------------------------------------------------------------- +class ISteamUGC +{ +public: + + // Query UGC associated with a user. Creator app id or consumer app id must be valid and be set to the current running app. unPage should start at 1. + virtual UGCQueryHandle_t CreateQueryUserUGCRequest( AccountID_t unAccountID, EUserUGCList eListType, EUGCMatchingUGCType eMatchingUGCType, EUserUGCListSortOrder eSortOrder, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ) = 0; + + // Query for all matching UGC. Creator app id or consumer app id must be valid and be set to the current running app. unPage should start at 1. + virtual UGCQueryHandle_t CreateQueryAllUGCRequest( EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ) = 0; + + // Query for all matching UGC using the new deep paging interface. Creator app id or consumer app id must be valid and be set to the current running app. pchCursor should be set to NULL or "*" to get the first result set. + virtual UGCQueryHandle_t CreateQueryAllUGCRequest( EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, const char *pchCursor = NULL ) = 0; + + // Query for the details of the given published file ids (the RequestUGCDetails call is deprecated and replaced with this) + virtual UGCQueryHandle_t CreateQueryUGCDetailsRequest( PublishedFileId_t *pvecPublishedFileID, uint32 unNumPublishedFileIDs ) = 0; + + // Send the query to Steam + STEAM_CALL_RESULT( SteamUGCQueryCompleted_t ) + virtual SteamAPICall_t SendQueryUGCRequest( UGCQueryHandle_t handle ) = 0; + + // Retrieve an individual result after receiving the callback for querying UGC + virtual bool GetQueryUGCResult( UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t *pDetails ) = 0; + virtual bool GetQueryUGCPreviewURL( UGCQueryHandle_t handle, uint32 index, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchURL, uint32 cchURLSize ) = 0; + virtual bool GetQueryUGCMetadata( UGCQueryHandle_t handle, uint32 index, STEAM_OUT_STRING_COUNT(cchMetadatasize) char *pchMetadata, uint32 cchMetadatasize ) = 0; + virtual bool GetQueryUGCChildren( UGCQueryHandle_t handle, uint32 index, PublishedFileId_t* pvecPublishedFileID, uint32 cMaxEntries ) = 0; + virtual bool GetQueryUGCStatistic( UGCQueryHandle_t handle, uint32 index, EItemStatistic eStatType, uint64 *pStatValue ) = 0; + virtual uint32 GetQueryUGCNumAdditionalPreviews( UGCQueryHandle_t handle, uint32 index ) = 0; + virtual bool GetQueryUGCAdditionalPreview( UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchURLOrVideoID, uint32 cchURLSize, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchOriginalFileName, uint32 cchOriginalFileNameSize, EItemPreviewType *pPreviewType ) = 0; + virtual uint32 GetQueryUGCNumKeyValueTags( UGCQueryHandle_t handle, uint32 index ) = 0; + virtual bool GetQueryUGCKeyValueTag( UGCQueryHandle_t handle, uint32 index, uint32 keyValueTagIndex, STEAM_OUT_STRING_COUNT(cchKeySize) char *pchKey, uint32 cchKeySize, STEAM_OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) = 0; + // Return the first value matching the pchKey. Note that a key may map to multiple values. Returns false if there was an error or no matching value was found. + virtual bool GetQueryUGCKeyValueTag( UGCQueryHandle_t handle, uint32 index, const char *pchKey, STEAM_OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) = 0; + + // Release the request to free up memory, after retrieving results + virtual bool ReleaseQueryUGCRequest( UGCQueryHandle_t handle ) = 0; + + // Options to set for querying UGC + virtual bool AddRequiredTag( UGCQueryHandle_t handle, const char *pTagName ) = 0; + virtual bool AddExcludedTag( UGCQueryHandle_t handle, const char *pTagName ) = 0; + virtual bool SetReturnOnlyIDs( UGCQueryHandle_t handle, bool bReturnOnlyIDs ) = 0; + virtual bool SetReturnKeyValueTags( UGCQueryHandle_t handle, bool bReturnKeyValueTags ) = 0; + virtual bool SetReturnLongDescription( UGCQueryHandle_t handle, bool bReturnLongDescription ) = 0; + virtual bool SetReturnMetadata( UGCQueryHandle_t handle, bool bReturnMetadata ) = 0; + virtual bool SetReturnChildren( UGCQueryHandle_t handle, bool bReturnChildren ) = 0; + virtual bool SetReturnAdditionalPreviews( UGCQueryHandle_t handle, bool bReturnAdditionalPreviews ) = 0; + virtual bool SetReturnTotalOnly( UGCQueryHandle_t handle, bool bReturnTotalOnly ) = 0; + virtual bool SetReturnPlaytimeStats( UGCQueryHandle_t handle, uint32 unDays ) = 0; + virtual bool SetLanguage( UGCQueryHandle_t handle, const char *pchLanguage ) = 0; + virtual bool SetAllowCachedResponse( UGCQueryHandle_t handle, uint32 unMaxAgeSeconds ) = 0; + + // Options only for querying user UGC + virtual bool SetCloudFileNameFilter( UGCQueryHandle_t handle, const char *pMatchCloudFileName ) = 0; + + // Options only for querying all UGC + virtual bool SetMatchAnyTag( UGCQueryHandle_t handle, bool bMatchAnyTag ) = 0; + virtual bool SetSearchText( UGCQueryHandle_t handle, const char *pSearchText ) = 0; + virtual bool SetRankedByTrendDays( UGCQueryHandle_t handle, uint32 unDays ) = 0; + virtual bool AddRequiredKeyValueTag( UGCQueryHandle_t handle, const char *pKey, const char *pValue ) = 0; + + // DEPRECATED - Use CreateQueryUGCDetailsRequest call above instead! + virtual SteamAPICall_t RequestUGCDetails( PublishedFileId_t nPublishedFileID, uint32 unMaxAgeSeconds ) = 0; + + // Steam Workshop Creator API + STEAM_CALL_RESULT( CreateItemResult_t ) + virtual SteamAPICall_t CreateItem( AppId_t nConsumerAppId, EWorkshopFileType eFileType ) = 0; // create new item for this app with no content attached yet + + virtual UGCUpdateHandle_t StartItemUpdate( AppId_t nConsumerAppId, PublishedFileId_t nPublishedFileID ) = 0; // start an UGC item update. Set changed properties before commiting update with CommitItemUpdate() + + virtual bool SetItemTitle( UGCUpdateHandle_t handle, const char *pchTitle ) = 0; // change the title of an UGC item + virtual bool SetItemDescription( UGCUpdateHandle_t handle, const char *pchDescription ) = 0; // change the description of an UGC item + virtual bool SetItemUpdateLanguage( UGCUpdateHandle_t handle, const char *pchLanguage ) = 0; // specify the language of the title or description that will be set + virtual bool SetItemMetadata( UGCUpdateHandle_t handle, const char *pchMetaData ) = 0; // change the metadata of an UGC item (max = k_cchDeveloperMetadataMax) + virtual bool SetItemVisibility( UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVisibility eVisibility ) = 0; // change the visibility of an UGC item + virtual bool SetItemTags( UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t *pTags ) = 0; // change the tags of an UGC item + virtual bool SetItemContent( UGCUpdateHandle_t handle, const char *pszContentFolder ) = 0; // update item content from this local folder + virtual bool SetItemPreview( UGCUpdateHandle_t handle, const char *pszPreviewFile ) = 0; // change preview image file for this item. pszPreviewFile points to local image file, which must be under 1MB in size + virtual bool SetAllowLegacyUpload( UGCUpdateHandle_t handle, bool bAllowLegacyUpload ) = 0; // use legacy upload for a single small file. The parameter to SetItemContent() should either be a directory with one file or the full path to the file. The file must also be less than 10MB in size. + virtual bool RemoveAllItemKeyValueTags( UGCUpdateHandle_t handle ) = 0; // remove all existing key-value tags (you can add new ones via the AddItemKeyValueTag function) + virtual bool RemoveItemKeyValueTags( UGCUpdateHandle_t handle, const char *pchKey ) = 0; // remove any existing key-value tags with the specified key + virtual bool AddItemKeyValueTag( UGCUpdateHandle_t handle, const char *pchKey, const char *pchValue ) = 0; // add new key-value tags for the item. Note that there can be multiple values for a tag. + virtual bool AddItemPreviewFile( UGCUpdateHandle_t handle, const char *pszPreviewFile, EItemPreviewType type ) = 0; // add preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size + virtual bool AddItemPreviewVideo( UGCUpdateHandle_t handle, const char *pszVideoID ) = 0; // add preview video for this item + virtual bool UpdateItemPreviewFile( UGCUpdateHandle_t handle, uint32 index, const char *pszPreviewFile ) = 0; // updates an existing preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size + virtual bool UpdateItemPreviewVideo( UGCUpdateHandle_t handle, uint32 index, const char *pszVideoID ) = 0; // updates an existing preview video for this item + virtual bool RemoveItemPreview( UGCUpdateHandle_t handle, uint32 index ) = 0; // remove a preview by index starting at 0 (previews are sorted) + + STEAM_CALL_RESULT( SubmitItemUpdateResult_t ) + virtual SteamAPICall_t SubmitItemUpdate( UGCUpdateHandle_t handle, const char *pchChangeNote ) = 0; // commit update process started with StartItemUpdate() + virtual EItemUpdateStatus GetItemUpdateProgress( UGCUpdateHandle_t handle, uint64 *punBytesProcessed, uint64* punBytesTotal ) = 0; + + // Steam Workshop Consumer API + STEAM_CALL_RESULT( SetUserItemVoteResult_t ) + virtual SteamAPICall_t SetUserItemVote( PublishedFileId_t nPublishedFileID, bool bVoteUp ) = 0; + STEAM_CALL_RESULT( GetUserItemVoteResult_t ) + virtual SteamAPICall_t GetUserItemVote( PublishedFileId_t nPublishedFileID ) = 0; + STEAM_CALL_RESULT( UserFavoriteItemsListChanged_t ) + virtual SteamAPICall_t AddItemToFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) = 0; + STEAM_CALL_RESULT( UserFavoriteItemsListChanged_t ) + virtual SteamAPICall_t RemoveItemFromFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) = 0; + STEAM_CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t ) + virtual SteamAPICall_t SubscribeItem( PublishedFileId_t nPublishedFileID ) = 0; // subscribe to this item, will be installed ASAP + STEAM_CALL_RESULT( RemoteStorageUnsubscribePublishedFileResult_t ) + virtual SteamAPICall_t UnsubscribeItem( PublishedFileId_t nPublishedFileID ) = 0; // unsubscribe from this item, will be uninstalled after game quits + virtual uint32 GetNumSubscribedItems() = 0; // number of subscribed items + virtual uint32 GetSubscribedItems( PublishedFileId_t* pvecPublishedFileID, uint32 cMaxEntries ) = 0; // all subscribed item PublishFileIDs + + // get EItemState flags about item on this client + virtual uint32 GetItemState( PublishedFileId_t nPublishedFileID ) = 0; + + // get info about currently installed content on disc for items that have k_EItemStateInstalled set + // if k_EItemStateLegacyItem is set, pchFolder contains the path to the legacy file itself (not a folder) + virtual bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDisk, STEAM_OUT_STRING_COUNT( cchFolderSize ) char *pchFolder, uint32 cchFolderSize, uint32 *punTimeStamp ) = 0; + + // get info about pending update for items that have k_EItemStateNeedsUpdate set. punBytesTotal will be valid after download started once + virtual bool GetItemDownloadInfo( PublishedFileId_t nPublishedFileID, uint64 *punBytesDownloaded, uint64 *punBytesTotal ) = 0; + + // download new or update already installed item. If function returns true, wait for DownloadItemResult_t. If the item is already installed, + // then files on disk should not be used until callback received. If item is not subscribed to, it will be cached for some time. + // If bHighPriority is set, any other item download will be suspended and this item downloaded ASAP. + virtual bool DownloadItem( PublishedFileId_t nPublishedFileID, bool bHighPriority ) = 0; + + // game servers can set a specific workshop folder before issuing any UGC commands. + // This is helpful if you want to support multiple game servers running out of the same install folder + virtual bool BInitWorkshopForGameServer( DepotId_t unWorkshopDepotID, const char *pszFolder ) = 0; + + // SuspendDownloads( true ) will suspend all workshop downloads until SuspendDownloads( false ) is called or the game ends + virtual void SuspendDownloads( bool bSuspend ) = 0; + + // usage tracking + STEAM_CALL_RESULT( StartPlaytimeTrackingResult_t ) + virtual SteamAPICall_t StartPlaytimeTracking( PublishedFileId_t *pvecPublishedFileID, uint32 unNumPublishedFileIDs ) = 0; + STEAM_CALL_RESULT( StopPlaytimeTrackingResult_t ) + virtual SteamAPICall_t StopPlaytimeTracking( PublishedFileId_t *pvecPublishedFileID, uint32 unNumPublishedFileIDs ) = 0; + STEAM_CALL_RESULT( StopPlaytimeTrackingResult_t ) + virtual SteamAPICall_t StopPlaytimeTrackingForAllItems() = 0; + + // parent-child relationship or dependency management + STEAM_CALL_RESULT( AddUGCDependencyResult_t ) + virtual SteamAPICall_t AddDependency( PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ) = 0; + STEAM_CALL_RESULT( RemoveUGCDependencyResult_t ) + virtual SteamAPICall_t RemoveDependency( PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ) = 0; + + // add/remove app dependence/requirements (usually DLC) + STEAM_CALL_RESULT( AddAppDependencyResult_t ) + virtual SteamAPICall_t AddAppDependency( PublishedFileId_t nPublishedFileID, AppId_t nAppID ) = 0; + STEAM_CALL_RESULT( RemoveAppDependencyResult_t ) + virtual SteamAPICall_t RemoveAppDependency( PublishedFileId_t nPublishedFileID, AppId_t nAppID ) = 0; + // request app dependencies. note that whatever callback you register for GetAppDependenciesResult_t may be called multiple times + // until all app dependencies have been returned + STEAM_CALL_RESULT( GetAppDependenciesResult_t ) + virtual SteamAPICall_t GetAppDependencies( PublishedFileId_t nPublishedFileID ) = 0; + + // delete the item without prompting the user + STEAM_CALL_RESULT( DeleteItemResult_t ) + virtual SteamAPICall_t DeleteItem( PublishedFileId_t nPublishedFileID ) = 0; +}; + +#define STEAMUGC_INTERFACE_VERSION "STEAMUGC_INTERFACE_VERSION012" + +// Global interface accessor +inline ISteamUGC *SteamUGC(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamUGC *, SteamUGC, STEAMUGC_INTERFACE_VERSION ); + +// Global accessor for the gameserver client +inline ISteamUGC *SteamGameServerUGC(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamUGC *, SteamGameServerUGC, STEAMUGC_INTERFACE_VERSION ); + +//----------------------------------------------------------------------------- +// Purpose: Callback for querying UGC +//----------------------------------------------------------------------------- +struct SteamUGCQueryCompleted_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 1 }; + UGCQueryHandle_t m_handle; + EResult m_eResult; + uint32 m_unNumResultsReturned; + uint32 m_unTotalMatchingResults; + bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache + char m_rgchNextCursor[k_cchPublishedFileURLMax]; // If a paging cursor was used, then this will be the next cursor to get the next result set. +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback for requesting details on one piece of UGC +//----------------------------------------------------------------------------- +struct SteamUGCRequestUGCDetailsResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 2 }; + SteamUGCDetails_t m_details; + bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache +}; + + +//----------------------------------------------------------------------------- +// Purpose: result for ISteamUGC::CreateItem() +//----------------------------------------------------------------------------- +struct CreateItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 3 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; // new item got this UGC PublishFileID + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: result for ISteamUGC::SubmitItemUpdate() +//----------------------------------------------------------------------------- +struct SubmitItemUpdateResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 4 }; + EResult m_eResult; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a Workshop item has been installed or updated +//----------------------------------------------------------------------------- +struct ItemInstalled_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 5 }; + AppId_t m_unAppID; + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of DownloadItem(), existing item files can be accessed again +//----------------------------------------------------------------------------- +struct DownloadItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 6 }; + AppId_t m_unAppID; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: result of AddItemToFavorites() or RemoveItemFromFavorites() +//----------------------------------------------------------------------------- +struct UserFavoriteItemsListChanged_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 7 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bWasAddRequest; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to SetUserItemVote() +//----------------------------------------------------------------------------- +struct SetUserItemVoteResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 8 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bVoteUp; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetUserItemVote() +//----------------------------------------------------------------------------- +struct GetUserItemVoteResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 9 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bVotedUp; + bool m_bVotedDown; + bool m_bVoteSkipped; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to StartPlaytimeTracking() +//----------------------------------------------------------------------------- +struct StartPlaytimeTrackingResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 10 }; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to StopPlaytimeTracking() +//----------------------------------------------------------------------------- +struct StopPlaytimeTrackingResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 11 }; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to AddDependency +//----------------------------------------------------------------------------- +struct AddUGCDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 12 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + PublishedFileId_t m_nChildPublishedFileId; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to RemoveDependency +//----------------------------------------------------------------------------- +struct RemoveUGCDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 13 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + PublishedFileId_t m_nChildPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to AddAppDependency +//----------------------------------------------------------------------------- +struct AddAppDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 14 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nAppID; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to RemoveAppDependency +//----------------------------------------------------------------------------- +struct RemoveAppDependencyResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 15 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nAppID; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetAppDependencies. Callback may be called +// multiple times until all app dependencies have been returned. +//----------------------------------------------------------------------------- +struct GetAppDependenciesResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 16 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; + AppId_t m_rgAppIDs[32]; + uint32 m_nNumAppDependencies; // number returned in this struct + uint32 m_nTotalNumAppDependencies; // total found +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to DeleteItem +//----------------------------------------------------------------------------- +struct DeleteItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 17 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; +}; + +#pragma pack( pop ) + +#endif // ISTEAMUGC_H diff --git a/public/steam/isteamuser.h b/public/steam/isteamuser.h new file mode 100644 index 0000000..aa81f1c --- /dev/null +++ b/public/steam/isteamuser.h @@ -0,0 +1,415 @@ +//====== Copyright (c) 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to user account information in Steam +// +//============================================================================= + +#ifndef ISTEAMUSER_H +#define ISTEAMUSER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +// structure that contains client callback data +// see callbacks documentation for more details +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif +struct CallbackMsg_t +{ + HSteamUser m_hSteamUser; + int m_iCallback; + uint8 *m_pubParam; + int m_cubParam; +}; +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing and manipulating a steam account +// associated with one client instance +//----------------------------------------------------------------------------- +class ISteamUser +{ +public: + // returns the HSteamUser this interface represents + // this is only used internally by the API, and by a few select interfaces that support multi-user + virtual HSteamUser GetHSteamUser() = 0; + + // returns true if the Steam client current has a live connection to the Steam servers. + // If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy. + // The Steam client will automatically be trying to recreate the connection as often as possible. + virtual bool BLoggedOn() = 0; + + // returns the CSteamID of the account currently logged into the Steam client + // a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API + virtual CSteamID GetSteamID() = 0; + + // Multiplayer Authentication functions + + // InitiateGameConnection() starts the state machine for authenticating the game client with the game server + // It is the client portion of a three-way handshake between the client, the game server, and the steam servers + // + // Parameters: + // void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token. + // int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes. + // CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client + // CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( ) + // uint32 unIPServer, uint16 usPortServer - the IP address of the game server + // bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running) + // + // return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed + // The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process. + virtual int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0; + + // notify of disconnect + // needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call + virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0; + + // Legacy functions + + // used by only a few games to track usage events + virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0; + + // get the local storage folder for current Steam account to write application data, e.g. save games, configs etc. + // this will usually be something like "C:\Progam Files\Steam\userdata\\\local" + virtual bool GetUserDataFolder( char *pchBuffer, int cubBuffer ) = 0; + + // Starts voice recording. Once started, use GetVoice() to get the data + virtual void StartVoiceRecording( ) = 0; + + // Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for + // a little bit after this function is called. GetVoice() should continue to be called until it returns + // k_eVoiceResultNotRecording + virtual void StopVoiceRecording( ) = 0; + + // Determine the size of captured audio data that is available from GetVoice. + // Most applications will only use compressed data and should ignore the other + // parameters, which exist primarily for backwards compatibility. See comments + // below for further explanation of "uncompressed" data. + virtual EVoiceResult GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed_Deprecated = 0, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated = 0 ) = 0; + + // --------------------------------------------------------------------------- + // NOTE: "uncompressed" audio is a deprecated feature and should not be used + // by most applications. It is raw single-channel 16-bit PCM wave data which + // may have been run through preprocessing filters and/or had silence removed, + // so the uncompressed audio could have a shorter duration than you expect. + // There may be no data at all during long periods of silence. Also, fetching + // uncompressed audio will cause GetVoice to discard any leftover compressed + // audio, so you must fetch both types at once. Finally, GetAvailableVoice is + // not precisely accurate when the uncompressed size is requested. So if you + // really need to use uncompressed audio, you should call GetVoice frequently + // with two very large (20kb+) output buffers instead of trying to allocate + // perfectly-sized buffers. But most applications should ignore all of these + // details and simply leave the "uncompressed" parameters as NULL/zero. + // --------------------------------------------------------------------------- + + // Read captured audio data from the microphone buffer. This should be called + // at least once per frame, and preferably every few milliseconds, to keep the + // microphone input delay as low as possible. Most applications will only use + // compressed data and should pass NULL/zero for the "uncompressed" parameters. + // Compressed data can be transmitted by your application and decoded into raw + // using the DecompressVoice function below. + virtual EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed_Deprecated = false, void *pUncompressedDestBuffer_Deprecated = 0, uint32 cbUncompressedDestBufferSize_Deprecated = 0, uint32 *nUncompressBytesWritten_Deprecated = 0, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated = 0 ) = 0; + + // Decodes the compressed voice data returned by GetVoice. The output data is + // raw single-channel 16-bit PCM audio. The decoder supports any sample rate + // from 11025 to 48000; see GetVoiceOptimalSampleRate() below for details. + // If the output buffer is not large enough, then *nBytesWritten will be set + // to the required buffer size, and k_EVoiceResultBufferTooSmall is returned. + // It is suggested to start with a 20kb buffer and reallocate as necessary. + virtual EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate ) = 0; + + // This returns the native sample rate of the Steam voice decompressor; using + // this sample rate for DecompressVoice will perform the least CPU processing. + // However, the final audio quality will depend on how well the audio device + // (and/or your application's audio output SDK) deals with lower sample rates. + // You may find that you get the best audio output quality when you ignore + // this function and use the native sample rate of your audio output device, + // which is usually 48000 or 44100. + virtual uint32 GetVoiceOptimalSampleRate() = 0; + + // Retrieve ticket to be sent to the entity who wishes to authenticate you. + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Authenticate ticket from entity steamID to be sure it is valid and isnt reused + // Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // After receiving a user's authentication data, and passing it to BeginAuthSession, use this function + // to determine if the user owns downloadable content specified by the provided AppID. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam + // (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT. + virtual bool BIsBehindNAT() = 0; + + // set data to be replicated to friends so that they can join your game + // CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client + // uint32 unIPServer, uint16 usPortServer - the IP address of the game server + virtual void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer ) = 0; + + // Requests a ticket encrypted with an app specific shared key + // pDataToInclude, cbDataToInclude will be encrypted into the ticket + // ( This is asynchronous, you must wait for the ticket to be completed by the server ) + STEAM_CALL_RESULT( EncryptedAppTicketResponse_t ) + virtual SteamAPICall_t RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude ) = 0; + + // retrieve a finished ticket + virtual bool GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Trading Card badges data access + // if you only have one set of cards, the series will be 1 + // the user has can have two different badges for a series; the regular (max level 5) and the foil (max level 1) + virtual int GetGameBadgeLevel( int nSeries, bool bFoil ) = 0; + + // gets the Steam Level of the user, as shown on their profile + virtual int GetPlayerSteamLevel() = 0; + + // Requests a URL which authenticates an in-game browser for store check-out, + // and then redirects to the specified URL. As long as the in-game browser + // accepts and handles session cookies, Steam microtransaction checkout pages + // will automatically recognize the user instead of presenting a login page. + // The result of this API call will be a StoreAuthURLResponse_t callback. + // NOTE: The URL has a very short lifetime to prevent history-snooping attacks, + // so you should only call this API when you are about to launch the browser, + // or else immediately navigate to the result URL using a hidden browser window. + // NOTE 2: The resulting authorization cookie has an expiration time of one day, + // so it would be a good idea to request and visit a new auth URL every 12 hours. + STEAM_CALL_RESULT( StoreAuthURLResponse_t ) + virtual SteamAPICall_t RequestStoreAuthURL( const char *pchRedirectURL ) = 0; + + // gets whether the users phone number is verified + virtual bool BIsPhoneVerified() = 0; + + // gets whether the user has two factor enabled on their account + virtual bool BIsTwoFactorEnabled() = 0; + + // gets whether the users phone number is identifying + virtual bool BIsPhoneIdentifying() = 0; + + // gets whether the users phone number is awaiting (re)verification + virtual bool BIsPhoneRequiringVerification() = 0; + + STEAM_CALL_RESULT( MarketEligibilityResponse_t ) + virtual SteamAPICall_t GetMarketEligibility() = 0; + + // Retrieves anti indulgence / duration control for current user + STEAM_CALL_RESULT( DurationControl_t ) + virtual SteamAPICall_t GetDurationControl() = 0; + +}; + +#define STEAMUSER_INTERFACE_VERSION "SteamUser020" + +// Global interface accessor +inline ISteamUser *SteamUser(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamUser *, SteamUser, STEAMUSER_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a connections to the Steam back-end has been established +// this means the Steam client now has a working connection to the Steam servers +// usually this will have occurred before the game has launched, and should +// only be seen if the user has dropped connection due to a networking issue +// or a Steam server update +//----------------------------------------------------------------------------- +struct SteamServersConnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 1 }; +}; + +//----------------------------------------------------------------------------- +// Purpose: called when a connection attempt has failed +// this will occur periodically if the Steam client is not connected, +// and has failed in it's retry to establish a connection +//----------------------------------------------------------------------------- +struct SteamServerConnectFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 2 }; + EResult m_eResult; + bool m_bStillRetrying; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called if the client has lost connection to the Steam servers +// real-time services will be disabled until a matching SteamServersConnected_t has been posted +//----------------------------------------------------------------------------- +struct SteamServersDisconnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 3 }; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent by the Steam server to the client telling it to disconnect from the specified game server, +// which it may be in the process of or already connected to. +// The game client should immediately disconnect upon receiving this message. +// This can usually occur if the user doesn't have rights to play on the game server. +//----------------------------------------------------------------------------- +struct ClientGameServerDeny_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 13 }; + + uint32 m_uAppID; + uint32 m_unGameServerIP; + uint16 m_usGameServerPort; + uint16 m_bSecure; + uint32 m_uReason; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the callback system for this client is in an error state (and has flushed pending callbacks) +// When getting this message the client should disconnect from Steam, reset any stored Steam state and reconnect. +// This usually occurs in the rare event the Steam client has some kind of fatal error. +//----------------------------------------------------------------------------- +struct IPCFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 17 }; + enum EFailureType + { + k_EFailureFlushedCallbackQueue, + k_EFailurePipeFail, + }; + uint8 m_eFailureType; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Signaled whenever licenses change +//----------------------------------------------------------------------------- +struct LicensesUpdated_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 25 }; +}; + + +//----------------------------------------------------------------------------- +// callback for BeginAuthSession +//----------------------------------------------------------------------------- +struct ValidateAuthTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 43 }; + CSteamID m_SteamID; + EAuthSessionResponse m_eAuthSessionResponse; + CSteamID m_OwnerSteamID; // different from m_SteamID if borrowed +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a user has responded to a microtransaction authorization request +//----------------------------------------------------------------------------- +struct MicroTxnAuthorizationResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 52 }; + + uint32 m_unAppID; // AppID for this microtransaction + uint64 m_ulOrderID; // OrderID provided for the microtransaction + uint8 m_bAuthorized; // if user authorized transaction +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result from RequestEncryptedAppTicket +//----------------------------------------------------------------------------- +struct EncryptedAppTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 54 }; + + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// callback for GetAuthSessionTicket +//----------------------------------------------------------------------------- +struct GetAuthSessionTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 63 }; + HAuthTicket m_hAuthTicket; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: sent to your game in response to a steam://gamewebcallback/ command +//----------------------------------------------------------------------------- +struct GameWebCallback_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 64 }; + char m_szURL[256]; +}; + +//----------------------------------------------------------------------------- +// Purpose: sent to your game in response to ISteamUser::RequestStoreAuthURL +//----------------------------------------------------------------------------- +struct StoreAuthURLResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 65 }; + char m_szURL[512]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: sent in response to ISteamUser::GetMarketEligibility +//----------------------------------------------------------------------------- +struct MarketEligibilityResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 66 }; + bool m_bAllowed; + EMarketNotAllowedReasonFlags m_eNotAllowedReason; + RTime32 m_rtAllowedAtTime; + + int m_cdaySteamGuardRequiredDays; // The number of days any user is required to have had Steam Guard before they can use the market + int m_cdayNewDeviceCooldown; // The number of days after initial device authorization a user must wait before using the market on that device +}; + + +//----------------------------------------------------------------------------- +// Purpose: sent for games with enabled anti indulgence / duration control, for +// enabled users. Lets the game know whether persistent rewards or XP should be +// granted at normal rate, half rate, or zero rate. +// +// This callback is fired asynchronously in response to timers triggering. +// It is also fired in response to calls to GetDurationControl(). +//----------------------------------------------------------------------------- +struct DurationControl_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 67 }; + + EResult m_eResult; // result of call (always k_EResultOK for asynchronous timer-based notifications) + AppId_t m_appid; // appid generating playtime + + bool m_bApplicable; // is duration control applicable to user + game combination + int32 m_csecsLast5h; // playtime in trailing 5 hour window plus current session, in seconds + EDurationControlProgress m_progress; // recommended progress + EDurationControlNotification m_notification; // notification to show, if any (always k_EDurationControlNotification_None for API calls) +}; + + +#pragma pack( pop ) + +#endif // ISTEAMUSER_H diff --git a/public/steam/isteamuserstats.h b/public/steam/isteamuserstats.h new file mode 100644 index 0000000..d8daa04 --- /dev/null +++ b/public/steam/isteamuserstats.h @@ -0,0 +1,480 @@ +//====== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to stats, achievements, and leaderboards +// +//============================================================================= + +#ifndef ISTEAMUSERSTATS_H +#define ISTEAMUSERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" +#include "isteamremotestorage.h" + +// size limit on stat or achievement name (UTF-8 encoded) +enum { k_cchStatNameMax = 128 }; + +// maximum number of bytes for a leaderboard name (UTF-8 encoded) +enum { k_cchLeaderboardNameMax = 128 }; + +// maximum number of details int32's storable for a single leaderboard entry +enum { k_cLeaderboardDetailsMax = 64 }; + +// handle to a single leaderboard +typedef uint64 SteamLeaderboard_t; + +// handle to a set of downloaded entries in a leaderboard +typedef uint64 SteamLeaderboardEntries_t; + +// type of data request, when downloading leaderboard entries +enum ELeaderboardDataRequest +{ + k_ELeaderboardDataRequestGlobal = 0, + k_ELeaderboardDataRequestGlobalAroundUser = 1, + k_ELeaderboardDataRequestFriends = 2, + k_ELeaderboardDataRequestUsers = 3 +}; + +// the sort order of a leaderboard +enum ELeaderboardSortMethod +{ + k_ELeaderboardSortMethodNone = 0, + k_ELeaderboardSortMethodAscending = 1, // top-score is lowest number + k_ELeaderboardSortMethodDescending = 2, // top-score is highest number +}; + +// the display type (used by the Steam Community web site) for a leaderboard +enum ELeaderboardDisplayType +{ + k_ELeaderboardDisplayTypeNone = 0, + k_ELeaderboardDisplayTypeNumeric = 1, // simple numerical score + k_ELeaderboardDisplayTypeTimeSeconds = 2, // the score represents a time, in seconds + k_ELeaderboardDisplayTypeTimeMilliSeconds = 3, // the score represents a time, in milliseconds +}; + +enum ELeaderboardUploadScoreMethod +{ + k_ELeaderboardUploadScoreMethodNone = 0, + k_ELeaderboardUploadScoreMethodKeepBest = 1, // Leaderboard will keep user's best score + k_ELeaderboardUploadScoreMethodForceUpdate = 2, // Leaderboard will always replace score with specified +}; + +// a single entry in a leaderboard, as returned by GetDownloadedLeaderboardEntry() +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +struct LeaderboardEntry_t +{ + CSteamID m_steamIDUser; // user with the entry - use SteamFriends()->GetFriendPersonaName() & SteamFriends()->GetFriendAvatar() to get more info + int32 m_nGlobalRank; // [1..N], where N is the number of users with an entry in the leaderboard + int32 m_nScore; // score as set in the leaderboard + int32 m_cDetails; // number of int32 details available for this entry + UGCHandle_t m_hUGC; // handle for UGC attached to the entry +}; + +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing stats, achievements, and leaderboard information +//----------------------------------------------------------------------------- +class ISteamUserStats +{ +public: + // Ask the server to send down this user's data and achievements for this game + STEAM_CALL_BACK( UserStatsReceived_t ) + virtual bool RequestCurrentStats() = 0; + + // Data accessors + virtual bool GetStat( const char *pchName, int32 *pData ) = 0; + virtual bool GetStat( const char *pchName, float *pData ) = 0; + + // Set / update data + virtual bool SetStat( const char *pchName, int32 nData ) = 0; + virtual bool SetStat( const char *pchName, float fData ) = 0; + virtual bool UpdateAvgRateStat( const char *pchName, float flCountThisSession, double dSessionLength ) = 0; + + // Achievement flag accessors + virtual bool GetAchievement( const char *pchName, bool *pbAchieved ) = 0; + virtual bool SetAchievement( const char *pchName ) = 0; + virtual bool ClearAchievement( const char *pchName ) = 0; + + // Get the achievement status, and the time it was unlocked if unlocked. + // If the return value is true, but the unlock time is zero, that means it was unlocked before Steam + // began tracking achievement unlock times (December 2009). Time is seconds since January 1, 1970. + virtual bool GetAchievementAndUnlockTime( const char *pchName, bool *pbAchieved, uint32 *punUnlockTime ) = 0; + + // Store the current data on the server, will get a callback when set + // And one callback for every new achievement + // + // If the callback has a result of k_EResultInvalidParam, one or more stats + // uploaded has been rejected, either because they broke constraints + // or were out of date. In this case the server sends back updated values. + // The stats should be re-iterated to keep in sync. + virtual bool StoreStats() = 0; + + // Achievement / GroupAchievement metadata + + // Gets the icon of the achievement, which is a handle to be used in ISteamUtils::GetImageRGBA(), or 0 if none set. + // A return value of 0 may indicate we are still fetching data, and you can wait for the UserAchievementIconFetched_t callback + // which will notify you when the bits are ready. If the callback still returns zero, then there is no image set for the + // specified achievement. + virtual int GetAchievementIcon( const char *pchName ) = 0; + + // Get general attributes for an achievement. Accepts the following keys: + // - "name" and "desc" for retrieving the localized achievement name and description (returned in UTF8) + // - "hidden" for retrieving if an achievement is hidden (returns "0" when not hidden, "1" when hidden) + virtual const char *GetAchievementDisplayAttribute( const char *pchName, const char *pchKey ) = 0; + + // Achievement progress - triggers an AchievementProgress callback, that is all. + // Calling this w/ N out of N progress will NOT set the achievement, the game must still do that. + virtual bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint32 nMaxProgress ) = 0; + + // Used for iterating achievements. In general games should not need these functions because they should have a + // list of existing achievements compiled into them + virtual uint32 GetNumAchievements() = 0; + // Get achievement name iAchievement in [0,GetNumAchievements) + virtual const char *GetAchievementName( uint32 iAchievement ) = 0; + + // Friends stats & achievements + + // downloads stats for the user + // returns a UserStatsReceived_t received when completed + // if the other user has no stats, UserStatsReceived_t.m_eResult will be set to k_EResultFail + // these stats won't be auto-updated; you'll need to call RequestUserStats() again to refresh any data + STEAM_CALL_RESULT( UserStatsReceived_t ) + virtual SteamAPICall_t RequestUserStats( CSteamID steamIDUser ) = 0; + + // requests stat information for a user, usable after a successful call to RequestUserStats() + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData ) = 0; + virtual bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved ) = 0; + // See notes for GetAchievementAndUnlockTime above + virtual bool GetUserAchievementAndUnlockTime( CSteamID steamIDUser, const char *pchName, bool *pbAchieved, uint32 *punUnlockTime ) = 0; + + // Reset stats + virtual bool ResetAllStats( bool bAchievementsToo ) = 0; + + // Leaderboard functions + + // asks the Steam back-end for a leaderboard by name, and will create it if it's not yet + // This call is asynchronous, with the result returned in LeaderboardFindResult_t + STEAM_CALL_RESULT(LeaderboardFindResult_t) + virtual SteamAPICall_t FindOrCreateLeaderboard( const char *pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType ) = 0; + + // as above, but won't create the leaderboard if it's not found + // This call is asynchronous, with the result returned in LeaderboardFindResult_t + STEAM_CALL_RESULT( LeaderboardFindResult_t ) + virtual SteamAPICall_t FindLeaderboard( const char *pchLeaderboardName ) = 0; + + // returns the name of a leaderboard + virtual const char *GetLeaderboardName( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the total number of entries in a leaderboard, as of the last request + virtual int GetLeaderboardEntryCount( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the sort method of the leaderboard + virtual ELeaderboardSortMethod GetLeaderboardSortMethod( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the display type of the leaderboard + virtual ELeaderboardDisplayType GetLeaderboardDisplayType( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // Asks the Steam back-end for a set of rows in the leaderboard. + // This call is asynchronous, with the result returned in LeaderboardScoresDownloaded_t + // LeaderboardScoresDownloaded_t will contain a handle to pull the results from GetDownloadedLeaderboardEntries() (below) + // You can ask for more entries than exist, and it will return as many as do exist. + // k_ELeaderboardDataRequestGlobal requests rows in the leaderboard from the full table, with nRangeStart & nRangeEnd in the range [1, TotalEntries] + // k_ELeaderboardDataRequestGlobalAroundUser requests rows around the current user, nRangeStart being negate + // e.g. DownloadLeaderboardEntries( hLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -3, 3 ) will return 7 rows, 3 before the user, 3 after + // k_ELeaderboardDataRequestFriends requests all the rows for friends of the current user + STEAM_CALL_RESULT( LeaderboardScoresDownloaded_t ) + virtual SteamAPICall_t DownloadLeaderboardEntries( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardDataRequest eLeaderboardDataRequest, int nRangeStart, int nRangeEnd ) = 0; + // as above, but downloads leaderboard entries for an arbitrary set of users - ELeaderboardDataRequest is k_ELeaderboardDataRequestUsers + // if a user doesn't have a leaderboard entry, they won't be included in the result + // a max of 100 users can be downloaded at a time, with only one outstanding call at a time + STEAM_METHOD_DESC(Downloads leaderboard entries for an arbitrary set of users - ELeaderboardDataRequest is k_ELeaderboardDataRequestUsers) + STEAM_CALL_RESULT( LeaderboardScoresDownloaded_t ) + virtual SteamAPICall_t DownloadLeaderboardEntriesForUsers( SteamLeaderboard_t hSteamLeaderboard, + STEAM_ARRAY_COUNT_D(cUsers, Array of users to retrieve) CSteamID *prgUsers, int cUsers ) = 0; + + // Returns data about a single leaderboard entry + // use a for loop from 0 to LeaderboardScoresDownloaded_t::m_cEntryCount to get all the downloaded entries + // e.g. + // void OnLeaderboardScoresDownloaded( LeaderboardScoresDownloaded_t *pLeaderboardScoresDownloaded ) + // { + // for ( int index = 0; index < pLeaderboardScoresDownloaded->m_cEntryCount; index++ ) + // { + // LeaderboardEntry_t leaderboardEntry; + // int32 details[3]; // we know this is how many we've stored previously + // GetDownloadedLeaderboardEntry( pLeaderboardScoresDownloaded->m_hSteamLeaderboardEntries, index, &leaderboardEntry, details, 3 ); + // assert( leaderboardEntry.m_cDetails == 3 ); + // ... + // } + // once you've accessed all the entries, the data will be free'd, and the SteamLeaderboardEntries_t handle will become invalid + virtual bool GetDownloadedLeaderboardEntry( SteamLeaderboardEntries_t hSteamLeaderboardEntries, int index, LeaderboardEntry_t *pLeaderboardEntry, int32 *pDetails, int cDetailsMax ) = 0; + + // Uploads a user score to the Steam back-end. + // This call is asynchronous, with the result returned in LeaderboardScoreUploaded_t + // Details are extra game-defined information regarding how the user got that score + // pScoreDetails points to an array of int32's, cScoreDetailsCount is the number of int32's in the list + STEAM_CALL_RESULT( LeaderboardScoreUploaded_t ) + virtual SteamAPICall_t UploadLeaderboardScore( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32 *pScoreDetails, int cScoreDetailsCount ) = 0; + + // Attaches a piece of user generated content the user's entry on a leaderboard. + // hContent is a handle to a piece of user generated content that was shared using ISteamUserRemoteStorage::FileShare(). + // This call is asynchronous, with the result returned in LeaderboardUGCSet_t. + STEAM_CALL_RESULT( LeaderboardUGCSet_t ) + virtual SteamAPICall_t AttachLeaderboardUGC( SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC ) = 0; + + // Retrieves the number of players currently playing your game (online + offline) + // This call is asynchronous, with the result returned in NumberOfCurrentPlayers_t + STEAM_CALL_RESULT( NumberOfCurrentPlayers_t ) + virtual SteamAPICall_t GetNumberOfCurrentPlayers() = 0; + + // Requests that Steam fetch data on the percentage of players who have received each achievement + // for the game globally. + // This call is asynchronous, with the result returned in GlobalAchievementPercentagesReady_t. + STEAM_CALL_RESULT( GlobalAchievementPercentagesReady_t ) + virtual SteamAPICall_t RequestGlobalAchievementPercentages() = 0; + + // Get the info on the most achieved achievement for the game, returns an iterator index you can use to fetch + // the next most achieved afterwards. Will return -1 if there is no data on achievement + // percentages (ie, you haven't called RequestGlobalAchievementPercentages and waited on the callback). + virtual int GetMostAchievedAchievementInfo( char *pchName, uint32 unNameBufLen, float *pflPercent, bool *pbAchieved ) = 0; + + // Get the info on the next most achieved achievement for the game. Call this after GetMostAchievedAchievementInfo or another + // GetNextMostAchievedAchievementInfo call passing the iterator from the previous call. Returns -1 after the last + // achievement has been iterated. + virtual int GetNextMostAchievedAchievementInfo( int iIteratorPrevious, char *pchName, uint32 unNameBufLen, float *pflPercent, bool *pbAchieved ) = 0; + + // Returns the percentage of users who have achieved the specified achievement. + virtual bool GetAchievementAchievedPercent( const char *pchName, float *pflPercent ) = 0; + + // Requests global stats data, which is available for stats marked as "aggregated". + // This call is asynchronous, with the results returned in GlobalStatsReceived_t. + // nHistoryDays specifies how many days of day-by-day history to retrieve in addition + // to the overall totals. The limit is 60. + STEAM_CALL_RESULT( GlobalStatsReceived_t ) + virtual SteamAPICall_t RequestGlobalStats( int nHistoryDays ) = 0; + + // Gets the lifetime totals for an aggregated stat + virtual bool GetGlobalStat( const char *pchStatName, int64 *pData ) = 0; + virtual bool GetGlobalStat( const char *pchStatName, double *pData ) = 0; + + // Gets history for an aggregated stat. pData will be filled with daily values, starting with today. + // So when called, pData[0] will be today, pData[1] will be yesterday, and pData[2] will be two days ago, + // etc. cubData is the size in bytes of the pubData buffer. Returns the number of + // elements actually set. + virtual int32 GetGlobalStatHistory( const char *pchStatName, STEAM_ARRAY_COUNT(cubData) int64 *pData, uint32 cubData ) = 0; + virtual int32 GetGlobalStatHistory( const char *pchStatName, STEAM_ARRAY_COUNT(cubData) double *pData, uint32 cubData ) = 0; + +#ifdef _PS3 + // Call to kick off installation of the PS3 trophies. This call is asynchronous, and the results will be returned in a PS3TrophiesInstalled_t + // callback. + virtual bool InstallPS3Trophies() = 0; + + // Returns the amount of space required at boot to install trophies. This value can be used when comparing the amount of space needed + // by the game to the available space value passed to the game at boot. The value is set during InstallPS3Trophies(). + virtual uint64 GetTrophySpaceRequiredBeforeInstall() = 0; + + // On PS3, user stats & achievement progress through Steam must be stored with the user's saved game data. + // At startup, before calling RequestCurrentStats(), you must pass the user's stats data to Steam via this method. + // If you do not have any user data, call this function with pvData = NULL and cubData = 0 + virtual bool SetUserStatsData( const void *pvData, uint32 cubData ) = 0; + + // Call to get the user's current stats data. You should retrieve this data after receiving successful UserStatsReceived_t & UserStatsStored_t + // callbacks, and store the data with the user's save game data. You can call this method with pvData = NULL and cubData = 0 to get the required + // buffer size. + virtual bool GetUserStatsData( void *pvData, uint32 cubData, uint32 *pcubWritten ) = 0; +#endif +}; + +#define STEAMUSERSTATS_INTERFACE_VERSION "STEAMUSERSTATS_INTERFACE_VERSION011" + +// Global interface accessor +inline ISteamUserStats *SteamUserStats(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamUserStats *, SteamUserStats, STEAMUSERSTATS_INTERFACE_VERSION ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when the latests stats and achievements have been received +// from the server +//----------------------------------------------------------------------------- +struct UserStatsReceived_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 1 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // Success / error fetching the stats + CSteamID m_steamIDUser; // The user for whom the stats are retrieved for +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the user stats for a game +//----------------------------------------------------------------------------- +struct UserStatsStored_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 2 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // success / error +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the achievements for a game, or an +// "indicate progress" call. If both m_nCurProgress and m_nMaxProgress +// are zero, that means the achievement has been fully unlocked. +//----------------------------------------------------------------------------- +struct UserAchievementStored_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 3 }; + + uint64 m_nGameID; // Game this is for + bool m_bGroupAchievement; // if this is a "group" achievement + char m_rgchAchievementName[k_cchStatNameMax]; // name of the achievement + uint32 m_nCurProgress; // current progress towards the achievement + uint32 m_nMaxProgress; // "out of" this many +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result for finding a leaderboard, returned as a result of FindOrCreateLeaderboard() or FindLeaderboard() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardFindResult_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 4 }; + SteamLeaderboard_t m_hSteamLeaderboard; // handle to the leaderboard serarched for, 0 if no leaderboard found + uint8 m_bLeaderboardFound; // 0 if no leaderboard found +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating scores for a leaderboard have been downloaded and are ready to be retrieved, returned as a result of DownloadLeaderboardEntries() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardScoresDownloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 5 }; + SteamLeaderboard_t m_hSteamLeaderboard; + SteamLeaderboardEntries_t m_hSteamLeaderboardEntries; // the handle to pass into GetDownloadedLeaderboardEntries() + int m_cEntryCount; // the number of entries downloaded +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating scores has been uploaded, returned as a result of UploadLeaderboardScore() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardScoreUploaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 6 }; + uint8 m_bSuccess; // 1 if the call was successful + SteamLeaderboard_t m_hSteamLeaderboard; // the leaderboard handle that was + int32 m_nScore; // the score that was attempted to set + uint8 m_bScoreChanged; // true if the score in the leaderboard change, false if the existing score was better + int m_nGlobalRankNew; // the new global rank of the user in this leaderboard + int m_nGlobalRankPrevious; // the previous global rank of the user in this leaderboard; 0 if the user had no existing entry in the leaderboard +}; + +struct NumberOfCurrentPlayers_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 7 }; + uint8 m_bSuccess; // 1 if the call was successful + int32 m_cPlayers; // Number of players currently playing +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that a user's stats have been unloaded. +// Call RequestUserStats again to access stats for this user +//----------------------------------------------------------------------------- +struct UserStatsUnloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 8 }; + CSteamID m_steamIDUser; // User whose stats have been unloaded +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that an achievement icon has been fetched +//----------------------------------------------------------------------------- +struct UserAchievementIconFetched_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 9 }; + + CGameID m_nGameID; // Game this is for + char m_rgchAchievementName[k_cchStatNameMax]; // name of the achievement + bool m_bAchieved; // Is the icon for the achieved or not achieved version? + int m_nIconHandle; // Handle to the image, which can be used in SteamUtils()->GetImageRGBA(), 0 means no image is set for the achievement +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that global achievement percentages are fetched +//----------------------------------------------------------------------------- +struct GlobalAchievementPercentagesReady_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 10 }; + + uint64 m_nGameID; // Game this is for + EResult m_eResult; // Result of the operation +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating UGC has been uploaded, returned as a result of SetLeaderboardUGC() +//----------------------------------------------------------------------------- +struct LeaderboardUGCSet_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 11 }; + EResult m_eResult; // The result of the operation + SteamLeaderboard_t m_hSteamLeaderboard; // the leaderboard handle that was +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating that PS3 trophies have been installed +//----------------------------------------------------------------------------- +struct PS3TrophiesInstalled_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 12 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // The result of the operation + uint64 m_ulRequiredDiskSpace; // If m_eResult is k_EResultDiskFull, will contain the amount of space needed to install trophies + +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating global stats have been received. +// Returned as a result of RequestGlobalStats() +//----------------------------------------------------------------------------- +struct GlobalStatsReceived_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 12 }; + uint64 m_nGameID; // Game global stats were requested for + EResult m_eResult; // The result of the request +}; + +#pragma pack( pop ) + + +#endif // ISTEAMUSER_H diff --git a/public/steam/isteamutils.h b/public/steam/isteamutils.h new file mode 100644 index 0000000..c4f23cc --- /dev/null +++ b/public/steam/isteamutils.h @@ -0,0 +1,286 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to utility functions in Steam +// +//============================================================================= + +#ifndef ISTEAMUTILS_H +#define ISTEAMUTILS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + + +// Steam API call failure results +enum ESteamAPICallFailure +{ + k_ESteamAPICallFailureNone = -1, // no failure + k_ESteamAPICallFailureSteamGone = 0, // the local Steam process has gone away + k_ESteamAPICallFailureNetworkFailure = 1, // the network connection to Steam has been broken, or was already broken + // SteamServersDisconnected_t callback will be sent around the same time + // SteamServersConnected_t will be sent when the client is able to talk to the Steam servers again + k_ESteamAPICallFailureInvalidHandle = 2, // the SteamAPICall_t handle passed in no longer exists + k_ESteamAPICallFailureMismatchedCallback = 3,// GetAPICallResult() was called with the wrong callback type for this API call +}; + + +// Input modes for the Big Picture gamepad text entry +enum EGamepadTextInputMode +{ + k_EGamepadTextInputModeNormal = 0, + k_EGamepadTextInputModePassword = 1 +}; + + +// Controls number of allowed lines for the Big Picture gamepad text entry +enum EGamepadTextInputLineMode +{ + k_EGamepadTextInputLineModeSingleLine = 0, + k_EGamepadTextInputLineModeMultipleLines = 1 +}; + + +// function prototype for warning message hook +#if defined( POSIX ) +#define __cdecl +#endif +extern "C" typedef void (__cdecl *SteamAPIWarningMessageHook_t)(int, const char *); + +//----------------------------------------------------------------------------- +// Purpose: interface to user independent utility functions +//----------------------------------------------------------------------------- +class ISteamUtils +{ +public: + // return the number of seconds since the user + virtual uint32 GetSecondsSinceAppActive() = 0; + virtual uint32 GetSecondsSinceComputerActive() = 0; + + // the universe this client is connecting to + virtual EUniverse GetConnectedUniverse() = 0; + + // Steam server time. Number of seconds since January 1, 1970, GMT (i.e unix time) + virtual uint32 GetServerRealTime() = 0; + + // returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database) + // e.g "US" or "UK". + virtual const char *GetIPCountry() = 0; + + // returns true if the image exists, and valid sizes were filled out + virtual bool GetImageSize( int iImage, uint32 *pnWidth, uint32 *pnHeight ) = 0; + + // returns true if the image exists, and the buffer was successfully filled out + // results are returned in RGBA format + // the destination buffer size should be 4 * height * width * sizeof(char) + virtual bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize ) = 0; + + // returns the IP of the reporting server for valve - currently only used in Source engine games + virtual bool GetCSERIPPort( uint32 *unIP, uint16 *usPort ) = 0; + + // return the amount of battery power left in the current system in % [0..100], 255 for being on AC power + virtual uint8 GetCurrentBatteryPower() = 0; + + // returns the appID of the current process + virtual uint32 GetAppID() = 0; + + // Sets the position where the overlay instance for the currently calling game should show notifications. + // This position is per-game and if this function is called from outside of a game context it will do nothing. + virtual void SetOverlayNotificationPosition( ENotificationPosition eNotificationPosition ) = 0; + + // API asynchronous call results + // can be used directly, but more commonly used via the callback dispatch API (see steam_api.h) + virtual bool IsAPICallCompleted( SteamAPICall_t hSteamAPICall, bool *pbFailed ) = 0; + virtual ESteamAPICallFailure GetAPICallFailureReason( SteamAPICall_t hSteamAPICall ) = 0; + virtual bool GetAPICallResult( SteamAPICall_t hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed ) = 0; + + // Deprecated. Applications should use SteamAPI_RunCallbacks() instead. Game servers do not need to call this function. + STEAM_PRIVATE_API( virtual void RunFrame() = 0; ) + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Returns true if the overlay is running & the user can access it. The overlay process could take a few seconds to + // start & hook the game process, so this function will initially return false while the overlay is loading. + virtual bool IsOverlayEnabled() = 0; + + // Normally this call is unneeded if your game has a constantly running frame loop that calls the + // D3D Present API, or OGL SwapBuffers API every frame. + // + // However, if you have a game that only refreshes the screen on an event driven basis then that can break + // the overlay, as it uses your Present/SwapBuffers calls to drive it's internal frame loop and it may also + // need to Present() to the screen any time an even needing a notification happens or when the overlay is + // brought up over the game by a user. You can use this API to ask the overlay if it currently need a present + // in that case, and then you can check for this periodically (roughly 33hz is desirable) and make sure you + // refresh the screen with Present or SwapBuffers to allow the overlay to do it's work. + virtual bool BOverlayNeedsPresent() = 0; + + // Asynchronous call to check if an executable file has been signed using the public key set on the signing tab + // of the partner site, for example to refuse to load modified executable files. + // The result is returned in CheckFileSignature_t. + // k_ECheckFileSignatureNoSignaturesFoundForThisApp - This app has not been configured on the signing tab of the partner site to enable this function. + // k_ECheckFileSignatureNoSignaturesFoundForThisFile - This file is not listed on the signing tab for the partner site. + // k_ECheckFileSignatureFileNotFound - The file does not exist on disk. + // k_ECheckFileSignatureInvalidSignature - The file exists, and the signing tab has been set for this file, but the file is either not signed or the signature does not match. + // k_ECheckFileSignatureValidSignature - The file is signed and the signature is valid. + STEAM_CALL_RESULT( CheckFileSignature_t ) + virtual SteamAPICall_t CheckFileSignature( const char *szFileName ) = 0; + + // Activates the Big Picture text input dialog which only supports gamepad input + virtual bool ShowGamepadTextInput( EGamepadTextInputMode eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32 unCharMax, const char *pchExistingText ) = 0; + + // Returns previously entered text & length + virtual uint32 GetEnteredGamepadTextLength() = 0; + virtual bool GetEnteredGamepadTextInput( char *pchText, uint32 cchText ) = 0; + + // returns the language the steam client is running in, you probably want ISteamApps::GetCurrentGameLanguage instead, this is for very special usage cases + virtual const char *GetSteamUILanguage() = 0; + + // returns true if Steam itself is running in VR mode + virtual bool IsSteamRunningInVR() = 0; + + // Sets the inset of the overlay notification from the corner specified by SetOverlayNotificationPosition. + virtual void SetOverlayNotificationInset( int nHorizontalInset, int nVerticalInset ) = 0; + + // returns true if Steam & the Steam Overlay are running in Big Picture mode + // Games much be launched through the Steam client to enable the Big Picture overlay. During development, + // a game can be added as a non-steam game to the developers library to test this feature + virtual bool IsSteamInBigPictureMode() = 0; + + // ask SteamUI to create and render its OpenVR dashboard + virtual void StartVRDashboard() = 0; + + // Returns true if the HMD content will be streamed via Steam In-Home Streaming + virtual bool IsVRHeadsetStreamingEnabled() = 0; + + // Set whether the HMD content will be streamed via Steam In-Home Streaming + // If this is set to true, then the scene in the HMD headset will be streamed, and remote input will not be allowed. + // If this is set to false, then the application window will be streamed instead, and remote input will be allowed. + // The default is true unless "VRHeadsetStreaming" "0" is in the extended appinfo for a game. + // (this is useful for games that have asymmetric multiplayer gameplay) + virtual void SetVRHeadsetStreamingEnabled( bool bEnabled ) = 0; + + // Returns whether this steam client is a Steam China specific client, vs the global client. + virtual bool IsSteamChinaLauncher() = 0; + + // Initializes text filtering. + // Returns false if filtering is unavailable for the language the user is currently running in. + virtual bool InitFilterText() = 0; + + // Filters the provided input message and places the filtered result into pchOutFilteredText. + // pchOutFilteredText is where the output will be placed, even if no filtering or censoring is performed + // nByteSizeOutFilteredText is the size (in bytes) of pchOutFilteredText + // pchInputText is the input string that should be filtered, which can be ASCII or UTF-8 + // bLegalOnly should be false if you want profanity and legally required filtering (where required) and true if you want legally required filtering only + // Returns the number of characters (not bytes) filtered. + virtual int FilterText( char* pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly ) = 0; +}; + +#define STEAMUTILS_INTERFACE_VERSION "SteamUtils009" + +// Global interface accessor +inline ISteamUtils *SteamUtils(); +STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamUtils *, SteamUtils, SteamInternal_FindOrCreateUserInterface( 0, STEAMUTILS_INTERFACE_VERSION ) ); + +// Global accessor for the gameserver client +inline ISteamUtils *SteamGameServerUtils(); +STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamUtils *, SteamGameServerUtils, SteamInternal_FindOrCreateGameServerInterface( 0, STEAMUTILS_INTERFACE_VERSION ) ); + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + +//----------------------------------------------------------------------------- +// Purpose: The country of the user changed +//----------------------------------------------------------------------------- +struct IPCountry_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 1 }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Fired when running on a laptop and less than 10 minutes of battery is left, fires then every minute +//----------------------------------------------------------------------------- +struct LowBatteryPower_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 2 }; + uint8 m_nMinutesBatteryLeft; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a SteamAsyncCall_t has completed (or failed) +//----------------------------------------------------------------------------- +struct SteamAPICallCompleted_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 3 }; + SteamAPICall_t m_hAsyncCall; + int m_iCallback; + uint32 m_cubParam; +}; + + +//----------------------------------------------------------------------------- +// called when Steam wants to shutdown +//----------------------------------------------------------------------------- +struct SteamShutdown_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 4 }; +}; + +//----------------------------------------------------------------------------- +// results for CheckFileSignature +//----------------------------------------------------------------------------- +enum ECheckFileSignature +{ + k_ECheckFileSignatureInvalidSignature = 0, + k_ECheckFileSignatureValidSignature = 1, + k_ECheckFileSignatureFileNotFound = 2, + k_ECheckFileSignatureNoSignaturesFoundForThisApp = 3, + k_ECheckFileSignatureNoSignaturesFoundForThisFile = 4, +}; + +//----------------------------------------------------------------------------- +// callback for CheckFileSignature +//----------------------------------------------------------------------------- +struct CheckFileSignature_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 5 }; + ECheckFileSignature m_eCheckFileSignature; +}; + + +// k_iSteamUtilsCallbacks + 13 is taken + + +//----------------------------------------------------------------------------- +// Big Picture gamepad text input has been closed +//----------------------------------------------------------------------------- +struct GamepadTextInputDismissed_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 14 }; + bool m_bSubmitted; // true if user entered & accepted text (Call ISteamUtils::GetEnteredGamepadTextInput() for text), false if canceled input + uint32 m_unSubmittedText; +}; + +// k_iSteamUtilsCallbacks + 15 is taken + +#pragma pack( pop ) + +#endif // ISTEAMUTILS_H diff --git a/public/steam/isteamvideo.h b/public/steam/isteamvideo.h new file mode 100644 index 0000000..3dbe987 --- /dev/null +++ b/public/steam/isteamvideo.h @@ -0,0 +1,68 @@ +//====== Copyright 1996-2014 Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to Steam Video +// +//============================================================================= + +#ifndef ISTEAMVIDEO_H +#define ISTEAMVIDEO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api_common.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx +#endif + + + + +//----------------------------------------------------------------------------- +// Purpose: Steam Video API +//----------------------------------------------------------------------------- +class ISteamVideo +{ +public: + + // Get a URL suitable for streaming the given Video app ID's video + virtual void GetVideoURL( AppId_t unVideoAppID ) = 0; + + // returns true if user is uploading a live broadcast + virtual bool IsBroadcasting( int *pnNumViewers ) = 0; + + // Get the OPF Details for 360 Video Playback + STEAM_CALL_BACK( GetOPFSettingsResult_t ) + virtual void GetOPFSettings( AppId_t unVideoAppID ) = 0; + virtual bool GetOPFStringForApp( AppId_t unVideoAppID, char *pchBuffer, int32 *pnBufferSize ) = 0; +}; + +#define STEAMVIDEO_INTERFACE_VERSION "STEAMVIDEO_INTERFACE_V002" + +// Global interface accessor +inline ISteamVideo *SteamVideo(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamVideo *, SteamVideo, STEAMVIDEO_INTERFACE_VERSION ); + +STEAM_CALLBACK_BEGIN( GetVideoURLResult_t, k_iClientVideoCallbacks + 11 ) + STEAM_CALLBACK_MEMBER( 0, EResult, m_eResult ) + STEAM_CALLBACK_MEMBER( 1, AppId_t, m_unVideoAppID ) + STEAM_CALLBACK_MEMBER( 2, char, m_rgchURL[256] ) +STEAM_CALLBACK_END(3) + + +STEAM_CALLBACK_BEGIN( GetOPFSettingsResult_t, k_iClientVideoCallbacks + 24 ) + STEAM_CALLBACK_MEMBER( 0, EResult, m_eResult ) + STEAM_CALLBACK_MEMBER( 1, AppId_t, m_unVideoAppID ) +STEAM_CALLBACK_END(2) + + +#pragma pack( pop ) + + +#endif // ISTEAMVIDEO_H diff --git a/public/steam/matchmakingtypes.h b/public/steam/matchmakingtypes.h new file mode 100644 index 0000000..e52cfc6 --- /dev/null +++ b/public/steam/matchmakingtypes.h @@ -0,0 +1,251 @@ +//========= Copyright � 1996-2008, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef MATCHMAKINGTYPES_H +#define MATCHMAKINGTYPES_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef POSIX +#ifndef _snprintf +#define _snprintf snprintf +#endif +#endif + +#include +#include + +// +// Max size (in bytes of UTF-8 data, not in characters) of server fields, including null terminator. +// WARNING: These cannot be changed easily, without breaking clients using old interfaces. +// +const int k_cbMaxGameServerGameDir = 32; +const int k_cbMaxGameServerMapName = 32; +const int k_cbMaxGameServerGameDescription = 64; +const int k_cbMaxGameServerName = 64; +const int k_cbMaxGameServerTags = 128; +const int k_cbMaxGameServerGameData = 2048; + +/// Store key/value pair used in matchmaking queries. +/// +/// Actually, the name Key/Value is a bit misleading. The "key" is better +/// understood as "filter operation code" and the "value" is the operand to this +/// filter operation. The meaning of the operand depends upon the filter. +struct MatchMakingKeyValuePair_t +{ + MatchMakingKeyValuePair_t() { m_szKey[0] = m_szValue[0] = 0; } + MatchMakingKeyValuePair_t( const char *pchKey, const char *pchValue ) + { + strncpy( m_szKey, pchKey, sizeof(m_szKey) ); // this is a public header, use basic c library string funcs only! + m_szKey[ sizeof( m_szKey ) - 1 ] = '\0'; + strncpy( m_szValue, pchValue, sizeof(m_szValue) ); + m_szValue[ sizeof( m_szValue ) - 1 ] = '\0'; + } + char m_szKey[ 256 ]; + char m_szValue[ 256 ]; +}; + + +enum EMatchMakingServerResponse +{ + eServerResponded = 0, + eServerFailedToRespond, + eNoServersListedOnMasterServer // for the Internet query type, returned in response callback if no servers of this type match +}; + +// servernetadr_t is all the addressing info the serverbrowser needs to know about a game server, +// namely: its IP, its connection port, and its query port. +class servernetadr_t +{ +public: + + servernetadr_t() : m_usConnectionPort( 0 ), m_usQueryPort( 0 ), m_unIP( 0 ) {} + + void Init( unsigned int ip, uint16 usQueryPort, uint16 usConnectionPort ); +#ifdef NETADR_H + netadr_t GetIPAndQueryPort(); +#endif + + // Access the query port. + uint16 GetQueryPort() const; + void SetQueryPort( uint16 usPort ); + + // Access the connection port. + uint16 GetConnectionPort() const; + void SetConnectionPort( uint16 usPort ); + + // Access the IP + uint32 GetIP() const; + void SetIP( uint32 ); + + // This gets the 'a.b.c.d:port' string with the connection port (instead of the query port). + const char *GetConnectionAddressString() const; + const char *GetQueryAddressString() const; + + // Comparison operators and functions. + bool operator<(const servernetadr_t &netadr) const; + void operator=( const servernetadr_t &that ) + { + m_usConnectionPort = that.m_usConnectionPort; + m_usQueryPort = that.m_usQueryPort; + m_unIP = that.m_unIP; + } + + +private: + const char *ToString( uint32 unIP, uint16 usPort ) const; + uint16 m_usConnectionPort; // (in HOST byte order) + uint16 m_usQueryPort; + uint32 m_unIP; +}; + + +inline void servernetadr_t::Init( unsigned int ip, uint16 usQueryPort, uint16 usConnectionPort ) +{ + m_unIP = ip; + m_usQueryPort = usQueryPort; + m_usConnectionPort = usConnectionPort; +} + +#ifdef NETADR_H +inline netadr_t servernetadr_t::GetIPAndQueryPort() +{ + return netadr_t( m_unIP, m_usQueryPort ); +} +#endif + +inline uint16 servernetadr_t::GetQueryPort() const +{ + return m_usQueryPort; +} + +inline void servernetadr_t::SetQueryPort( uint16 usPort ) +{ + m_usQueryPort = usPort; +} + +inline uint16 servernetadr_t::GetConnectionPort() const +{ + return m_usConnectionPort; +} + +inline void servernetadr_t::SetConnectionPort( uint16 usPort ) +{ + m_usConnectionPort = usPort; +} + +inline uint32 servernetadr_t::GetIP() const +{ + return m_unIP; +} + +inline void servernetadr_t::SetIP( uint32 unIP ) +{ + m_unIP = unIP; +} + +inline const char *servernetadr_t::ToString( uint32 unIP, uint16 usPort ) const +{ + static char s[4][64]; + static int nBuf = 0; + unsigned char *ipByte = (unsigned char *)&unIP; +#ifdef VALVE_BIG_ENDIAN + _snprintf (s[nBuf], sizeof( s[nBuf] ), "%u.%u.%u.%u:%i", (int)(ipByte[0]), (int)(ipByte[1]), (int)(ipByte[2]), (int)(ipByte[3]), usPort ); +#else + _snprintf (s[nBuf], sizeof( s[nBuf] ), "%u.%u.%u.%u:%i", (int)(ipByte[3]), (int)(ipByte[2]), (int)(ipByte[1]), (int)(ipByte[0]), usPort ); +#endif + const char *pchRet = s[nBuf]; + ++nBuf; + nBuf %= ( (sizeof(s)/sizeof(s[0])) ); + return pchRet; +} + +inline const char* servernetadr_t::GetConnectionAddressString() const +{ + return ToString( m_unIP, m_usConnectionPort ); +} + +inline const char* servernetadr_t::GetQueryAddressString() const +{ + return ToString( m_unIP, m_usQueryPort ); +} + +inline bool servernetadr_t::operator<(const servernetadr_t &netadr) const +{ + return ( m_unIP < netadr.m_unIP ) || ( m_unIP == netadr.m_unIP && m_usQueryPort < netadr.m_usQueryPort ); +} + +//----------------------------------------------------------------------------- +// Purpose: Data describing a single server +//----------------------------------------------------------------------------- +class gameserveritem_t +{ +public: + gameserveritem_t(); + + const char* GetName() const; + void SetName( const char *pName ); + +public: + servernetadr_t m_NetAdr; ///< IP/Query Port/Connection Port for this server + int m_nPing; ///< current ping time in milliseconds + bool m_bHadSuccessfulResponse; ///< server has responded successfully in the past + bool m_bDoNotRefresh; ///< server is marked as not responding and should no longer be refreshed + char m_szGameDir[k_cbMaxGameServerGameDir]; ///< current game directory + char m_szMap[k_cbMaxGameServerMapName]; ///< current map + char m_szGameDescription[k_cbMaxGameServerGameDescription]; ///< game description + uint32 m_nAppID; ///< Steam App ID of this server + int m_nPlayers; ///< total number of players currently on the server. INCLUDES BOTS!! + int m_nMaxPlayers; ///< Maximum players that can join this server + int m_nBotPlayers; ///< Number of bots (i.e simulated players) on this server + bool m_bPassword; ///< true if this server needs a password to join + bool m_bSecure; ///< Is this server protected by VAC + uint32 m_ulTimeLastPlayed; ///< time (in unix time) when this server was last played on (for favorite/history servers) + int m_nServerVersion; ///< server version as reported to Steam + +private: + + /// Game server name + char m_szServerName[k_cbMaxGameServerName]; + + // For data added after SteamMatchMaking001 add it here +public: + /// the tags this server exposes + char m_szGameTags[k_cbMaxGameServerTags]; + + /// steamID of the game server - invalid if it's doesn't have one (old server, or not connected to Steam) + CSteamID m_steamID; +}; + + +inline gameserveritem_t::gameserveritem_t() +{ + m_szGameDir[0] = m_szMap[0] = m_szGameDescription[0] = m_szServerName[0] = 0; + m_bHadSuccessfulResponse = m_bDoNotRefresh = m_bPassword = m_bSecure = false; + m_nPing = m_nAppID = m_nPlayers = m_nMaxPlayers = m_nBotPlayers = m_ulTimeLastPlayed = m_nServerVersion = 0; + m_szGameTags[0] = 0; +} + +inline const char* gameserveritem_t::GetName() const +{ + // Use the IP address as the name if nothing is set yet. + if ( m_szServerName[0] == 0 ) + return m_NetAdr.GetConnectionAddressString(); + else + return m_szServerName; +} + +inline void gameserveritem_t::SetName( const char *pName ) +{ + strncpy( m_szServerName, pName, sizeof( m_szServerName ) ); + m_szServerName[ sizeof( m_szServerName ) - 1 ] = '\0'; +} + + +#endif // MATCHMAKINGTYPES_H diff --git a/public/steam/steam_api.h b/public/steam/steam_api.h new file mode 100644 index 0000000..9a3405a --- /dev/null +++ b/public/steam/steam_api.h @@ -0,0 +1,246 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// This header includes *all* of the interfaces and callback structures +// in the Steamworks SDK, and some high level functions to control the SDK +// (init, shutdown, etc) that you probably only need in one or two files. +// +// To save your compile times, we recommend that you not include this file +// in header files. Instead, include the specific headers for the interfaces +// and callback structures you need. The one file you might consider including +// in your precompiled header (e.g. stdafx.h) is steam_api_common.h +// +//============================================================================= + +#ifndef STEAM_API_H +#define STEAM_API_H +#ifdef _WIN32 +#pragma once +#endif + +// Basic stuff +#include "steam_api_common.h" + +// All of the interfaces +#include "isteamclient.h" +#include "isteamuser.h" +#include "isteamfriends.h" +#include "isteamutils.h" +#include "isteammatchmaking.h" +#include "isteamuserstats.h" +#include "isteamapps.h" +#include "isteamnetworking.h" +#include "isteamremotestorage.h" +#include "isteamscreenshots.h" +#include "isteammusic.h" +#include "isteammusicremote.h" +#include "isteamhttp.h" +#include "isteamcontroller.h" +#include "isteamugc.h" +#include "isteamapplist.h" +#include "isteamhtmlsurface.h" +#include "isteaminventory.h" +#include "isteamvideo.h" +#include "isteamparentalsettings.h" +#include "isteaminput.h" +#include "isteamremoteplay.h" + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// Steam API setup & shutdown +// +// These functions manage loading, initializing and shutdown of the steamclient.dll +// +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + + +// SteamAPI_Init must be called before using any other API functions. If it fails, an +// error message will be output to the debugger (or stderr) with further information. +S_API bool S_CALLTYPE SteamAPI_Init(); + +// SteamAPI_Shutdown should be called during process shutdown if possible. +S_API void S_CALLTYPE SteamAPI_Shutdown(); + +// SteamAPI_RestartAppIfNecessary ensures that your executable was launched through Steam. +// +// Returns true if the current process should terminate. Steam is now re-launching your application. +// +// Returns false if no action needs to be taken. This means that your executable was started through +// the Steam client, or a steam_appid.txt file is present in your game's directory (for development). +// Your current process should continue if false is returned. +// +// NOTE: If you use the Steam DRM wrapper on your primary executable file, this check is unnecessary +// since the DRM wrapper will ensure that your application was launched properly through Steam. +S_API bool S_CALLTYPE SteamAPI_RestartAppIfNecessary( uint32 unOwnAppID ); + +// Many Steam API functions allocate a small amount of thread-local memory for parameter storage. +// SteamAPI_ReleaseCurrentThreadMemory() will free API memory associated with the calling thread. +// This function is also called automatically by SteamAPI_RunCallbacks(), so a single-threaded +// program never needs to explicitly call this function. +S_API void S_CALLTYPE SteamAPI_ReleaseCurrentThreadMemory(); + + +// crash dump recording functions +S_API void S_CALLTYPE SteamAPI_WriteMiniDump( uint32 uStructuredExceptionCode, void* pvExceptionInfo, uint32 uBuildID ); +S_API void S_CALLTYPE SteamAPI_SetMiniDumpComment( const char *pchMsg ); + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// steamclient.dll private wrapper functions +// +// The following functions are part of abstracting API access to the steamclient.dll, but should only be used in very specific cases +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// SteamAPI_IsSteamRunning() returns true if Steam is currently running +S_API bool S_CALLTYPE SteamAPI_IsSteamRunning(); + +// Pumps out all the steam messages, calling registered callbacks. +// NOT THREADSAFE - do not call from multiple threads simultaneously. +S_API void Steam_RunCallbacks( HSteamPipe hSteamPipe, bool bGameServerCallbacks ); + +// register the callback funcs to use to interact with the steam dll +S_API void Steam_RegisterInterfaceFuncs( void *hModule ); + +// returns the HSteamUser of the last user to dispatch a callback +S_API HSteamUser Steam_GetHSteamUserCurrent(); + +// returns the filename path of the current running Steam process, used if you need to load an explicit steam dll by name. +// DEPRECATED - implementation is Windows only, and the path returned is a UTF-8 string which must be converted to UTF-16 for use with Win32 APIs +S_API const char *SteamAPI_GetSteamInstallPath(); + +// sets whether or not Steam_RunCallbacks() should do a try {} catch (...) {} around calls to issuing callbacks +S_API void SteamAPI_SetTryCatchCallbacks( bool bTryCatchCallbacks ); + +// backwards compat export, passes through to SteamAPI_ variants +S_API HSteamPipe GetHSteamPipe(); +S_API HSteamUser GetHSteamUser(); + + +#if defined( VERSION_SAFE_STEAM_API_INTERFACES ) +// exists only for backwards compat with code written against older SDKs +S_API bool S_CALLTYPE SteamAPI_InitSafe(); +#endif + +#if defined(USE_BREAKPAD_HANDLER) || defined(STEAM_API_EXPORTS) +// this should be called before the game initialized the steam APIs +// pchDate should be of the format "Mmm dd yyyy" (such as from the __ DATE __ macro ) +// pchTime should be of the format "hh:mm:ss" (such as from the __ TIME __ macro ) +// bFullMemoryDumps (Win32 only) -- writes out a uuid-full.dmp in the client/dumps folder +// pvContext-- can be NULL, will be the void * context passed into m_pfnPreMinidumpCallback +// PFNPreMinidumpCallback m_pfnPreMinidumpCallback -- optional callback which occurs just before a .dmp file is written during a crash. Applications can hook this to allow adding additional information into the .dmp comment stream. +S_API void S_CALLTYPE SteamAPI_UseBreakpadCrashHandler( char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback ); +S_API void S_CALLTYPE SteamAPI_SetBreakpadAppID( uint32 unAppID ); +#endif + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// +// CSteamAPIContext +// +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +#ifndef STEAM_API_EXPORTS + +// Deprecated! Use the global accessors directly +inline bool CSteamAPIContext::Init() +{ + m_pSteamClient = ::SteamClient(); + if ( !m_pSteamClient ) + return false; + + m_pSteamUser = ::SteamUser(); + if ( !m_pSteamUser ) + return false; + + m_pSteamFriends = ::SteamFriends(); + if ( !m_pSteamFriends ) + return false; + + m_pSteamUtils = ::SteamUtils(); + if ( !m_pSteamUtils ) + return false; + + m_pSteamMatchmaking = ::SteamMatchmaking(); + if ( !m_pSteamMatchmaking ) + return false; + + m_pSteamGameSearch = ::SteamGameSearch(); + if ( !m_pSteamGameSearch ) + return false; + +#if !defined( IOSALL) // Not yet supported on iOS. + m_pSteamMatchmakingServers = ::SteamMatchmakingServers(); + if ( !m_pSteamMatchmakingServers ) + return false; +#endif + + m_pSteamUserStats = ::SteamUserStats(); + if ( !m_pSteamUserStats ) + return false; + + m_pSteamApps = ::SteamApps(); + if ( !m_pSteamApps ) + return false; + + m_pSteamNetworking = ::SteamNetworking(); + if ( !m_pSteamNetworking ) + return false; + + m_pSteamRemoteStorage = ::SteamRemoteStorage(); + if ( !m_pSteamRemoteStorage ) + return false; + + m_pSteamScreenshots = ::SteamScreenshots(); + if ( !m_pSteamScreenshots ) + return false; + + m_pSteamHTTP = ::SteamHTTP(); + if ( !m_pSteamHTTP ) + return false; + + m_pController = ::SteamController(); + if ( !m_pController ) + return false; + + m_pSteamUGC = ::SteamUGC(); + if ( !m_pSteamUGC ) + return false; + + m_pSteamAppList = ::SteamAppList(); + if ( !m_pSteamAppList ) + return false; + + m_pSteamMusic = ::SteamMusic(); + if ( !m_pSteamMusic ) + return false; + + m_pSteamMusicRemote = ::SteamMusicRemote(); + if ( !m_pSteamMusicRemote ) + return false; + +#if !defined( ANDROID ) && !defined( IOSALL) // Not yet supported on Android or ios. + m_pSteamHTMLSurface = ::SteamHTMLSurface(); + if ( !m_pSteamHTMLSurface ) + return false; +#endif + + m_pSteamInventory = ::SteamInventory(); + if ( !m_pSteamInventory ) + return false; + + m_pSteamVideo = ::SteamVideo(); + if ( !m_pSteamVideo ) + return false; + + m_pSteamParentalSettings = ::SteamParentalSettings(); + if ( !m_pSteamParentalSettings ) + return false; + + m_pSteamInput = ::SteamInput(); + if ( !m_pSteamInput ) + return false; + + return true; +} + +#endif + +#endif // STEAM_API_H diff --git a/public/steam/steam_api.json b/public/steam/steam_api.json new file mode 100644 index 0000000..38f2263 --- /dev/null +++ b/public/steam/steam_api.json @@ -0,0 +1,9452 @@ +{"typedefs":[{"typedef": "uint8","type": "unsigned char"} +,{"typedef": "uint8","type": "unsigned char"} +,{"typedef": "int8","type": "signed char"} +,{"typedef": "int16","type": "short"} +,{"typedef": "uint16","type": "unsigned short"} +,{"typedef": "int32","type": "int"} +,{"typedef": "uint32","type": "unsigned int"} +,{"typedef": "int64","type": "long long"} +,{"typedef": "uint64","type": "unsigned long long"} +,{"typedef": "lint64","type": "int64"} +,{"typedef": "ulint64","type": "uint64"} +,{"typedef": "intp","type": "long long"} +,{"typedef": "uintp","type": "unsigned long long"} +,{"typedef": "Salt_t","type": "uint8 [8]"} +,{"typedef": "GID_t","type": "uint64"} +,{"typedef": "JobID_t","type": "uint64"} +,{"typedef": "TxnID_t","type": "GID_t"} +,{"typedef": "PackageId_t","type": "uint32"} +,{"typedef": "BundleId_t","type": "uint32"} +,{"typedef": "AppId_t","type": "uint32"} +,{"typedef": "AssetClassId_t","type": "uint64"} +,{"typedef": "PhysicalItemId_t","type": "uint32"} +,{"typedef": "DepotId_t","type": "uint32"} +,{"typedef": "RTime32","type": "uint32"} +,{"typedef": "CellID_t","type": "uint32"} +,{"typedef": "SteamAPICall_t","type": "uint64"} +,{"typedef": "AccountID_t","type": "uint32"} +,{"typedef": "PartnerId_t","type": "uint32"} +,{"typedef": "ManifestId_t","type": "uint64"} +,{"typedef": "SiteId_t","type": "uint64"} +,{"typedef": "PartyBeaconID_t","type": "uint64"} +,{"typedef": "HAuthTicket","type": "uint32"} +,{"typedef": "PFNLegacyKeyRegistration","type": "void (*)(const char *, const char *)"} +,{"typedef": "PFNLegacyKeyInstalled","type": "_Bool (*)(void)"} +,{"typedef": "PFNPreMinidumpCallback","type": "void (*)(void *)"} +,{"typedef": "BREAKPAD_HANDLE","type": "void *"} +,{"typedef": "ValvePackingSentinel_t","type": "struct ValvePackingSentinel_t"} +,{"typedef": "compile_time_assert_type","type": "char [1]"} +,{"typedef": "HSteamPipe","type": "int32"} +,{"typedef": "HSteamUser","type": "int32"} +,{"typedef": "SteamAPIWarningMessageHook_t","type": "void (*)(int, const char *) __attribute__((cdecl))"} +,{"typedef": "SteamAPI_CheckCallbackRegistered_t","type": "uint32 (*)(int)"} +,{"typedef": "CCallResult::func_t","type": "void (T::*)(P *, _Bool)"} +,{"typedef": "CCallback::func_t","type": "void (T::*)(P *)"} +,{"typedef": "FriendsGroupID_t","type": "int16"} +,{"typedef": "SteamAPIWarningMessageHook_t","type": "void (*)(int, const char *) __attribute__((cdecl))"} +,{"typedef": "HServerListRequest","type": "void *"} +,{"typedef": "HServerQuery","type": "int"} +,{"typedef": "UGCHandle_t","type": "uint64"} +,{"typedef": "PublishedFileUpdateHandle_t","type": "uint64"} +,{"typedef": "PublishedFileId_t","type": "uint64"} +,{"typedef": "UGCFileWriteStreamHandle_t","type": "uint64"} +,{"typedef": "compile_time_assert_type","type": "char [1]"} +,{"typedef": "SteamLeaderboard_t","type": "uint64"} +,{"typedef": "SteamLeaderboardEntries_t","type": "uint64"} +,{"typedef": "SNetSocket_t","type": "uint32"} +,{"typedef": "SNetListenSocket_t","type": "uint32"} +,{"typedef": "ScreenshotHandle","type": "uint32"} +,{"typedef": "HTTPRequestHandle","type": "uint32"} +,{"typedef": "HTTPCookieContainerHandle","type": "uint32"} +,{"typedef": "InputHandle_t","type": "uint64"} +,{"typedef": "InputActionSetHandle_t","type": "uint64"} +,{"typedef": "InputDigitalActionHandle_t","type": "uint64"} +,{"typedef": "InputAnalogActionHandle_t","type": "uint64"} +,{"typedef": "ControllerHandle_t","type": "uint64"} +,{"typedef": "ControllerActionSetHandle_t","type": "uint64"} +,{"typedef": "ControllerDigitalActionHandle_t","type": "uint64"} +,{"typedef": "ControllerAnalogActionHandle_t","type": "uint64"} +,{"typedef": "UGCQueryHandle_t","type": "uint64"} +,{"typedef": "UGCUpdateHandle_t","type": "uint64"} +,{"typedef": "HHTMLBrowser","type": "uint32"} +,{"typedef": "SteamItemInstanceID_t","type": "uint64"} +,{"typedef": "SteamItemDef_t","type": "int32"} +,{"typedef": "SteamInventoryResult_t","type": "int32"} +,{"typedef": "SteamInventoryUpdateHandle_t","type": "uint64"} +], +"enums":[ + {"enumname": "EUniverse","values": [ + {"name": "k_EUniverseInvalid","value": "0"} + ,{"name": "k_EUniversePublic","value": "1"} + ,{"name": "k_EUniverseBeta","value": "2"} + ,{"name": "k_EUniverseInternal","value": "3"} + ,{"name": "k_EUniverseDev","value": "4"} + ,{"name": "k_EUniverseMax","value": "5"} +]} +, {"enumname": "EResult","values": [ + {"name": "k_EResultOK","value": "1"} + ,{"name": "k_EResultFail","value": "2"} + ,{"name": "k_EResultNoConnection","value": "3"} + ,{"name": "k_EResultInvalidPassword","value": "5"} + ,{"name": "k_EResultLoggedInElsewhere","value": "6"} + ,{"name": "k_EResultInvalidProtocolVer","value": "7"} + ,{"name": "k_EResultInvalidParam","value": "8"} + ,{"name": "k_EResultFileNotFound","value": "9"} + ,{"name": "k_EResultBusy","value": "10"} + ,{"name": "k_EResultInvalidState","value": "11"} + ,{"name": "k_EResultInvalidName","value": "12"} + ,{"name": "k_EResultInvalidEmail","value": "13"} + ,{"name": "k_EResultDuplicateName","value": "14"} + ,{"name": "k_EResultAccessDenied","value": "15"} + ,{"name": "k_EResultTimeout","value": "16"} + ,{"name": "k_EResultBanned","value": "17"} + ,{"name": "k_EResultAccountNotFound","value": "18"} + ,{"name": "k_EResultInvalidSteamID","value": "19"} + ,{"name": "k_EResultServiceUnavailable","value": "20"} + ,{"name": "k_EResultNotLoggedOn","value": "21"} + ,{"name": "k_EResultPending","value": "22"} + ,{"name": "k_EResultEncryptionFailure","value": "23"} + ,{"name": "k_EResultInsufficientPrivilege","value": "24"} + ,{"name": "k_EResultLimitExceeded","value": "25"} + ,{"name": "k_EResultRevoked","value": "26"} + ,{"name": "k_EResultExpired","value": "27"} + ,{"name": "k_EResultAlreadyRedeemed","value": "28"} + ,{"name": "k_EResultDuplicateRequest","value": "29"} + ,{"name": "k_EResultAlreadyOwned","value": "30"} + ,{"name": "k_EResultIPNotFound","value": "31"} + ,{"name": "k_EResultPersistFailed","value": "32"} + ,{"name": "k_EResultLockingFailed","value": "33"} + ,{"name": "k_EResultLogonSessionReplaced","value": "34"} + ,{"name": "k_EResultConnectFailed","value": "35"} + ,{"name": "k_EResultHandshakeFailed","value": "36"} + ,{"name": "k_EResultIOFailure","value": "37"} + ,{"name": "k_EResultRemoteDisconnect","value": "38"} + ,{"name": "k_EResultShoppingCartNotFound","value": "39"} + ,{"name": "k_EResultBlocked","value": "40"} + ,{"name": "k_EResultIgnored","value": "41"} + ,{"name": "k_EResultNoMatch","value": "42"} + ,{"name": "k_EResultAccountDisabled","value": "43"} + ,{"name": "k_EResultServiceReadOnly","value": "44"} + ,{"name": "k_EResultAccountNotFeatured","value": "45"} + ,{"name": "k_EResultAdministratorOK","value": "46"} + ,{"name": "k_EResultContentVersion","value": "47"} + ,{"name": "k_EResultTryAnotherCM","value": "48"} + ,{"name": "k_EResultPasswordRequiredToKickSession","value": "49"} + ,{"name": "k_EResultAlreadyLoggedInElsewhere","value": "50"} + ,{"name": "k_EResultSuspended","value": "51"} + ,{"name": "k_EResultCancelled","value": "52"} + ,{"name": "k_EResultDataCorruption","value": "53"} + ,{"name": "k_EResultDiskFull","value": "54"} + ,{"name": "k_EResultRemoteCallFailed","value": "55"} + ,{"name": "k_EResultPasswordUnset","value": "56"} + ,{"name": "k_EResultExternalAccountUnlinked","value": "57"} + ,{"name": "k_EResultPSNTicketInvalid","value": "58"} + ,{"name": "k_EResultExternalAccountAlreadyLinked","value": "59"} + ,{"name": "k_EResultRemoteFileConflict","value": "60"} + ,{"name": "k_EResultIllegalPassword","value": "61"} + ,{"name": "k_EResultSameAsPreviousValue","value": "62"} + ,{"name": "k_EResultAccountLogonDenied","value": "63"} + ,{"name": "k_EResultCannotUseOldPassword","value": "64"} + ,{"name": "k_EResultInvalidLoginAuthCode","value": "65"} + ,{"name": "k_EResultAccountLogonDeniedNoMail","value": "66"} + ,{"name": "k_EResultHardwareNotCapableOfIPT","value": "67"} + ,{"name": "k_EResultIPTInitError","value": "68"} + ,{"name": "k_EResultParentalControlRestricted","value": "69"} + ,{"name": "k_EResultFacebookQueryError","value": "70"} + ,{"name": "k_EResultExpiredLoginAuthCode","value": "71"} + ,{"name": "k_EResultIPLoginRestrictionFailed","value": "72"} + ,{"name": "k_EResultAccountLockedDown","value": "73"} + ,{"name": "k_EResultAccountLogonDeniedVerifiedEmailRequired","value": "74"} + ,{"name": "k_EResultNoMatchingURL","value": "75"} + ,{"name": "k_EResultBadResponse","value": "76"} + ,{"name": "k_EResultRequirePasswordReEntry","value": "77"} + ,{"name": "k_EResultValueOutOfRange","value": "78"} + ,{"name": "k_EResultUnexpectedError","value": "79"} + ,{"name": "k_EResultDisabled","value": "80"} + ,{"name": "k_EResultInvalidCEGSubmission","value": "81"} + ,{"name": "k_EResultRestrictedDevice","value": "82"} + ,{"name": "k_EResultRegionLocked","value": "83"} + ,{"name": "k_EResultRateLimitExceeded","value": "84"} + ,{"name": "k_EResultAccountLoginDeniedNeedTwoFactor","value": "85"} + ,{"name": "k_EResultItemDeleted","value": "86"} + ,{"name": "k_EResultAccountLoginDeniedThrottle","value": "87"} + ,{"name": "k_EResultTwoFactorCodeMismatch","value": "88"} + ,{"name": "k_EResultTwoFactorActivationCodeMismatch","value": "89"} + ,{"name": "k_EResultAccountAssociatedToMultiplePartners","value": "90"} + ,{"name": "k_EResultNotModified","value": "91"} + ,{"name": "k_EResultNoMobileDevice","value": "92"} + ,{"name": "k_EResultTimeNotSynced","value": "93"} + ,{"name": "k_EResultSmsCodeFailed","value": "94"} + ,{"name": "k_EResultAccountLimitExceeded","value": "95"} + ,{"name": "k_EResultAccountActivityLimitExceeded","value": "96"} + ,{"name": "k_EResultPhoneActivityLimitExceeded","value": "97"} + ,{"name": "k_EResultRefundToWallet","value": "98"} + ,{"name": "k_EResultEmailSendFailure","value": "99"} + ,{"name": "k_EResultNotSettled","value": "100"} + ,{"name": "k_EResultNeedCaptcha","value": "101"} + ,{"name": "k_EResultGSLTDenied","value": "102"} + ,{"name": "k_EResultGSOwnerDenied","value": "103"} + ,{"name": "k_EResultInvalidItemType","value": "104"} + ,{"name": "k_EResultIPBanned","value": "105"} + ,{"name": "k_EResultGSLTExpired","value": "106"} + ,{"name": "k_EResultInsufficientFunds","value": "107"} + ,{"name": "k_EResultTooManyPending","value": "108"} + ,{"name": "k_EResultNoSiteLicensesFound","value": "109"} + ,{"name": "k_EResultWGNetworkSendExceeded","value": "110"} + ,{"name": "k_EResultAccountNotFriends","value": "111"} + ,{"name": "k_EResultLimitedUserAccount","value": "112"} + ,{"name": "k_EResultCantRemoveItem","value": "113"} +]} +, {"enumname": "EVoiceResult","values": [ + {"name": "k_EVoiceResultOK","value": "0"} + ,{"name": "k_EVoiceResultNotInitialized","value": "1"} + ,{"name": "k_EVoiceResultNotRecording","value": "2"} + ,{"name": "k_EVoiceResultNoData","value": "3"} + ,{"name": "k_EVoiceResultBufferTooSmall","value": "4"} + ,{"name": "k_EVoiceResultDataCorrupted","value": "5"} + ,{"name": "k_EVoiceResultRestricted","value": "6"} + ,{"name": "k_EVoiceResultUnsupportedCodec","value": "7"} + ,{"name": "k_EVoiceResultReceiverOutOfDate","value": "8"} + ,{"name": "k_EVoiceResultReceiverDidNotAnswer","value": "9"} +]} +, {"enumname": "EDenyReason","values": [ + {"name": "k_EDenyInvalid","value": "0"} + ,{"name": "k_EDenyInvalidVersion","value": "1"} + ,{"name": "k_EDenyGeneric","value": "2"} + ,{"name": "k_EDenyNotLoggedOn","value": "3"} + ,{"name": "k_EDenyNoLicense","value": "4"} + ,{"name": "k_EDenyCheater","value": "5"} + ,{"name": "k_EDenyLoggedInElseWhere","value": "6"} + ,{"name": "k_EDenyUnknownText","value": "7"} + ,{"name": "k_EDenyIncompatibleAnticheat","value": "8"} + ,{"name": "k_EDenyMemoryCorruption","value": "9"} + ,{"name": "k_EDenyIncompatibleSoftware","value": "10"} + ,{"name": "k_EDenySteamConnectionLost","value": "11"} + ,{"name": "k_EDenySteamConnectionError","value": "12"} + ,{"name": "k_EDenySteamResponseTimedOut","value": "13"} + ,{"name": "k_EDenySteamValidationStalled","value": "14"} + ,{"name": "k_EDenySteamOwnerLeftGuestUser","value": "15"} +]} +, {"enumname": "EBeginAuthSessionResult","values": [ + {"name": "k_EBeginAuthSessionResultOK","value": "0"} + ,{"name": "k_EBeginAuthSessionResultInvalidTicket","value": "1"} + ,{"name": "k_EBeginAuthSessionResultDuplicateRequest","value": "2"} + ,{"name": "k_EBeginAuthSessionResultInvalidVersion","value": "3"} + ,{"name": "k_EBeginAuthSessionResultGameMismatch","value": "4"} + ,{"name": "k_EBeginAuthSessionResultExpiredTicket","value": "5"} +]} +, {"enumname": "EAuthSessionResponse","values": [ + {"name": "k_EAuthSessionResponseOK","value": "0"} + ,{"name": "k_EAuthSessionResponseUserNotConnectedToSteam","value": "1"} + ,{"name": "k_EAuthSessionResponseNoLicenseOrExpired","value": "2"} + ,{"name": "k_EAuthSessionResponseVACBanned","value": "3"} + ,{"name": "k_EAuthSessionResponseLoggedInElseWhere","value": "4"} + ,{"name": "k_EAuthSessionResponseVACCheckTimedOut","value": "5"} + ,{"name": "k_EAuthSessionResponseAuthTicketCanceled","value": "6"} + ,{"name": "k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed","value": "7"} + ,{"name": "k_EAuthSessionResponseAuthTicketInvalid","value": "8"} + ,{"name": "k_EAuthSessionResponsePublisherIssuedBan","value": "9"} +]} +, {"enumname": "EUserHasLicenseForAppResult","values": [ + {"name": "k_EUserHasLicenseResultHasLicense","value": "0"} + ,{"name": "k_EUserHasLicenseResultDoesNotHaveLicense","value": "1"} + ,{"name": "k_EUserHasLicenseResultNoAuth","value": "2"} +]} +, {"enumname": "EAccountType","values": [ + {"name": "k_EAccountTypeInvalid","value": "0"} + ,{"name": "k_EAccountTypeIndividual","value": "1"} + ,{"name": "k_EAccountTypeMultiseat","value": "2"} + ,{"name": "k_EAccountTypeGameServer","value": "3"} + ,{"name": "k_EAccountTypeAnonGameServer","value": "4"} + ,{"name": "k_EAccountTypePending","value": "5"} + ,{"name": "k_EAccountTypeContentServer","value": "6"} + ,{"name": "k_EAccountTypeClan","value": "7"} + ,{"name": "k_EAccountTypeChat","value": "8"} + ,{"name": "k_EAccountTypeConsoleUser","value": "9"} + ,{"name": "k_EAccountTypeAnonUser","value": "10"} + ,{"name": "k_EAccountTypeMax","value": "11"} +]} +, {"enumname": "EAppReleaseState","values": [ + {"name": "k_EAppReleaseState_Unknown","value": "0"} + ,{"name": "k_EAppReleaseState_Unavailable","value": "1"} + ,{"name": "k_EAppReleaseState_Prerelease","value": "2"} + ,{"name": "k_EAppReleaseState_PreloadOnly","value": "3"} + ,{"name": "k_EAppReleaseState_Released","value": "4"} +]} +, {"enumname": "EAppOwnershipFlags","values": [ + {"name": "k_EAppOwnershipFlags_None","value": "0"} + ,{"name": "k_EAppOwnershipFlags_OwnsLicense","value": "1"} + ,{"name": "k_EAppOwnershipFlags_FreeLicense","value": "2"} + ,{"name": "k_EAppOwnershipFlags_RegionRestricted","value": "4"} + ,{"name": "k_EAppOwnershipFlags_LowViolence","value": "8"} + ,{"name": "k_EAppOwnershipFlags_InvalidPlatform","value": "16"} + ,{"name": "k_EAppOwnershipFlags_SharedLicense","value": "32"} + ,{"name": "k_EAppOwnershipFlags_FreeWeekend","value": "64"} + ,{"name": "k_EAppOwnershipFlags_RetailLicense","value": "128"} + ,{"name": "k_EAppOwnershipFlags_LicenseLocked","value": "256"} + ,{"name": "k_EAppOwnershipFlags_LicensePending","value": "512"} + ,{"name": "k_EAppOwnershipFlags_LicenseExpired","value": "1024"} + ,{"name": "k_EAppOwnershipFlags_LicensePermanent","value": "2048"} + ,{"name": "k_EAppOwnershipFlags_LicenseRecurring","value": "4096"} + ,{"name": "k_EAppOwnershipFlags_LicenseCanceled","value": "8192"} + ,{"name": "k_EAppOwnershipFlags_AutoGrant","value": "16384"} + ,{"name": "k_EAppOwnershipFlags_PendingGift","value": "32768"} + ,{"name": "k_EAppOwnershipFlags_RentalNotActivated","value": "65536"} + ,{"name": "k_EAppOwnershipFlags_Rental","value": "131072"} + ,{"name": "k_EAppOwnershipFlags_SiteLicense","value": "262144"} +]} +, {"enumname": "EAppType","values": [ + {"name": "k_EAppType_Invalid","value": "0"} + ,{"name": "k_EAppType_Game","value": "1"} + ,{"name": "k_EAppType_Application","value": "2"} + ,{"name": "k_EAppType_Tool","value": "4"} + ,{"name": "k_EAppType_Demo","value": "8"} + ,{"name": "k_EAppType_Media_DEPRECATED","value": "16"} + ,{"name": "k_EAppType_DLC","value": "32"} + ,{"name": "k_EAppType_Guide","value": "64"} + ,{"name": "k_EAppType_Driver","value": "128"} + ,{"name": "k_EAppType_Config","value": "256"} + ,{"name": "k_EAppType_Hardware","value": "512"} + ,{"name": "k_EAppType_Franchise","value": "1024"} + ,{"name": "k_EAppType_Video","value": "2048"} + ,{"name": "k_EAppType_Plugin","value": "4096"} + ,{"name": "k_EAppType_Music","value": "8192"} + ,{"name": "k_EAppType_Series","value": "16384"} + ,{"name": "k_EAppType_Comic","value": "32768"} + ,{"name": "k_EAppType_Beta","value": "65536"} + ,{"name": "k_EAppType_Shortcut","value": "1073741824"} + ,{"name": "k_EAppType_DepotOnly","value": "-2147483648"} +]} +, {"enumname": "ESteamUserStatType","values": [ + {"name": "k_ESteamUserStatTypeINVALID","value": "0"} + ,{"name": "k_ESteamUserStatTypeINT","value": "1"} + ,{"name": "k_ESteamUserStatTypeFLOAT","value": "2"} + ,{"name": "k_ESteamUserStatTypeAVGRATE","value": "3"} + ,{"name": "k_ESteamUserStatTypeACHIEVEMENTS","value": "4"} + ,{"name": "k_ESteamUserStatTypeGROUPACHIEVEMENTS","value": "5"} + ,{"name": "k_ESteamUserStatTypeMAX","value": "6"} +]} +, {"enumname": "EChatEntryType","values": [ + {"name": "k_EChatEntryTypeInvalid","value": "0"} + ,{"name": "k_EChatEntryTypeChatMsg","value": "1"} + ,{"name": "k_EChatEntryTypeTyping","value": "2"} + ,{"name": "k_EChatEntryTypeInviteGame","value": "3"} + ,{"name": "k_EChatEntryTypeEmote","value": "4"} + ,{"name": "k_EChatEntryTypeLeftConversation","value": "6"} + ,{"name": "k_EChatEntryTypeEntered","value": "7"} + ,{"name": "k_EChatEntryTypeWasKicked","value": "8"} + ,{"name": "k_EChatEntryTypeWasBanned","value": "9"} + ,{"name": "k_EChatEntryTypeDisconnected","value": "10"} + ,{"name": "k_EChatEntryTypeHistoricalChat","value": "11"} + ,{"name": "k_EChatEntryTypeLinkBlocked","value": "14"} +]} +, {"enumname": "EChatRoomEnterResponse","values": [ + {"name": "k_EChatRoomEnterResponseSuccess","value": "1"} + ,{"name": "k_EChatRoomEnterResponseDoesntExist","value": "2"} + ,{"name": "k_EChatRoomEnterResponseNotAllowed","value": "3"} + ,{"name": "k_EChatRoomEnterResponseFull","value": "4"} + ,{"name": "k_EChatRoomEnterResponseError","value": "5"} + ,{"name": "k_EChatRoomEnterResponseBanned","value": "6"} + ,{"name": "k_EChatRoomEnterResponseLimited","value": "7"} + ,{"name": "k_EChatRoomEnterResponseClanDisabled","value": "8"} + ,{"name": "k_EChatRoomEnterResponseCommunityBan","value": "9"} + ,{"name": "k_EChatRoomEnterResponseMemberBlockedYou","value": "10"} + ,{"name": "k_EChatRoomEnterResponseYouBlockedMember","value": "11"} + ,{"name": "k_EChatRoomEnterResponseRatelimitExceeded","value": "15"} +]} +, {"enumname": "EChatSteamIDInstanceFlags","values": [ + {"name": "k_EChatAccountInstanceMask","value": "4095"} + ,{"name": "k_EChatInstanceFlagClan","value": "524288"} + ,{"name": "k_EChatInstanceFlagLobby","value": "262144"} + ,{"name": "k_EChatInstanceFlagMMSLobby","value": "131072"} +]} +, {"enumname": "EMarketingMessageFlags","values": [ + {"name": "k_EMarketingMessageFlagsNone","value": "0"} + ,{"name": "k_EMarketingMessageFlagsHighPriority","value": "1"} + ,{"name": "k_EMarketingMessageFlagsPlatformWindows","value": "2"} + ,{"name": "k_EMarketingMessageFlagsPlatformMac","value": "4"} + ,{"name": "k_EMarketingMessageFlagsPlatformLinux","value": "8"} + ,{"name": "k_EMarketingMessageFlagsPlatformRestrictions","value": "14"} +]} +, {"enumname": "ENotificationPosition","values": [ + {"name": "k_EPositionTopLeft","value": "0"} + ,{"name": "k_EPositionTopRight","value": "1"} + ,{"name": "k_EPositionBottomLeft","value": "2"} + ,{"name": "k_EPositionBottomRight","value": "3"} +]} +, {"enumname": "EBroadcastUploadResult","values": [ + {"name": "k_EBroadcastUploadResultNone","value": "0"} + ,{"name": "k_EBroadcastUploadResultOK","value": "1"} + ,{"name": "k_EBroadcastUploadResultInitFailed","value": "2"} + ,{"name": "k_EBroadcastUploadResultFrameFailed","value": "3"} + ,{"name": "k_EBroadcastUploadResultTimeout","value": "4"} + ,{"name": "k_EBroadcastUploadResultBandwidthExceeded","value": "5"} + ,{"name": "k_EBroadcastUploadResultLowFPS","value": "6"} + ,{"name": "k_EBroadcastUploadResultMissingKeyFrames","value": "7"} + ,{"name": "k_EBroadcastUploadResultNoConnection","value": "8"} + ,{"name": "k_EBroadcastUploadResultRelayFailed","value": "9"} + ,{"name": "k_EBroadcastUploadResultSettingsChanged","value": "10"} + ,{"name": "k_EBroadcastUploadResultMissingAudio","value": "11"} + ,{"name": "k_EBroadcastUploadResultTooFarBehind","value": "12"} + ,{"name": "k_EBroadcastUploadResultTranscodeBehind","value": "13"} + ,{"name": "k_EBroadcastUploadResultNotAllowedToPlay","value": "14"} + ,{"name": "k_EBroadcastUploadResultBusy","value": "15"} + ,{"name": "k_EBroadcastUploadResultBanned","value": "16"} + ,{"name": "k_EBroadcastUploadResultAlreadyActive","value": "17"} + ,{"name": "k_EBroadcastUploadResultForcedOff","value": "18"} + ,{"name": "k_EBroadcastUploadResultAudioBehind","value": "19"} + ,{"name": "k_EBroadcastUploadResultShutdown","value": "20"} + ,{"name": "k_EBroadcastUploadResultDisconnect","value": "21"} + ,{"name": "k_EBroadcastUploadResultVideoInitFailed","value": "22"} + ,{"name": "k_EBroadcastUploadResultAudioInitFailed","value": "23"} +]} +, {"enumname": "ELaunchOptionType","values": [ + {"name": "k_ELaunchOptionType_None","value": "0"} + ,{"name": "k_ELaunchOptionType_Default","value": "1"} + ,{"name": "k_ELaunchOptionType_SafeMode","value": "2"} + ,{"name": "k_ELaunchOptionType_Multiplayer","value": "3"} + ,{"name": "k_ELaunchOptionType_Config","value": "4"} + ,{"name": "k_ELaunchOptionType_OpenVR","value": "5"} + ,{"name": "k_ELaunchOptionType_Server","value": "6"} + ,{"name": "k_ELaunchOptionType_Editor","value": "7"} + ,{"name": "k_ELaunchOptionType_Manual","value": "8"} + ,{"name": "k_ELaunchOptionType_Benchmark","value": "9"} + ,{"name": "k_ELaunchOptionType_Option1","value": "10"} + ,{"name": "k_ELaunchOptionType_Option2","value": "11"} + ,{"name": "k_ELaunchOptionType_Option3","value": "12"} + ,{"name": "k_ELaunchOptionType_OculusVR","value": "13"} + ,{"name": "k_ELaunchOptionType_OpenVROverlay","value": "14"} + ,{"name": "k_ELaunchOptionType_OSVR","value": "15"} + ,{"name": "k_ELaunchOptionType_Dialog","value": "1000"} +]} +, {"enumname": "EVRHMDType","values": [ + {"name": "k_eEVRHMDType_None","value": "-1"} + ,{"name": "k_eEVRHMDType_Unknown","value": "0"} + ,{"name": "k_eEVRHMDType_HTC_Dev","value": "1"} + ,{"name": "k_eEVRHMDType_HTC_VivePre","value": "2"} + ,{"name": "k_eEVRHMDType_HTC_Vive","value": "3"} + ,{"name": "k_eEVRHMDType_HTC_VivePro","value": "4"} + ,{"name": "k_eEVRHMDType_HTC_ViveCosmos","value": "5"} + ,{"name": "k_eEVRHMDType_HTC_Unknown","value": "20"} + ,{"name": "k_eEVRHMDType_Oculus_DK1","value": "21"} + ,{"name": "k_eEVRHMDType_Oculus_DK2","value": "22"} + ,{"name": "k_eEVRHMDType_Oculus_Rift","value": "23"} + ,{"name": "k_eEVRHMDType_Oculus_RiftS","value": "24"} + ,{"name": "k_eEVRHMDType_Oculus_Unknown","value": "40"} + ,{"name": "k_eEVRHMDType_Acer_Unknown","value": "50"} + ,{"name": "k_eEVRHMDType_Acer_WindowsMR","value": "51"} + ,{"name": "k_eEVRHMDType_Dell_Unknown","value": "60"} + ,{"name": "k_eEVRHMDType_Dell_Visor","value": "61"} + ,{"name": "k_eEVRHMDType_Lenovo_Unknown","value": "70"} + ,{"name": "k_eEVRHMDType_Lenovo_Explorer","value": "71"} + ,{"name": "k_eEVRHMDType_HP_Unknown","value": "80"} + ,{"name": "k_eEVRHMDType_HP_WindowsMR","value": "81"} + ,{"name": "k_eEVRHMDType_Samsung_Unknown","value": "90"} + ,{"name": "k_eEVRHMDType_Samsung_Odyssey","value": "91"} + ,{"name": "k_eEVRHMDType_Unannounced_Unknown","value": "100"} + ,{"name": "k_eEVRHMDType_Unannounced_WindowsMR","value": "101"} + ,{"name": "k_eEVRHMDType_vridge","value": "110"} + ,{"name": "k_eEVRHMDType_Huawei_Unknown","value": "120"} + ,{"name": "k_eEVRHMDType_Huawei_VR2","value": "121"} + ,{"name": "k_eEVRHMDType_Huawei_EndOfRange","value": "129"} + ,{"name": "k_eEVRHmdType_Valve_Unknown","value": "130"} + ,{"name": "k_eEVRHmdType_Valve_Index","value": "131"} +]} +, {"enumname": "EMarketNotAllowedReasonFlags","values": [ + {"name": "k_EMarketNotAllowedReason_None","value": "0"} + ,{"name": "k_EMarketNotAllowedReason_TemporaryFailure","value": "1"} + ,{"name": "k_EMarketNotAllowedReason_AccountDisabled","value": "2"} + ,{"name": "k_EMarketNotAllowedReason_AccountLockedDown","value": "4"} + ,{"name": "k_EMarketNotAllowedReason_AccountLimited","value": "8"} + ,{"name": "k_EMarketNotAllowedReason_TradeBanned","value": "16"} + ,{"name": "k_EMarketNotAllowedReason_AccountNotTrusted","value": "32"} + ,{"name": "k_EMarketNotAllowedReason_SteamGuardNotEnabled","value": "64"} + ,{"name": "k_EMarketNotAllowedReason_SteamGuardOnlyRecentlyEnabled","value": "128"} + ,{"name": "k_EMarketNotAllowedReason_RecentPasswordReset","value": "256"} + ,{"name": "k_EMarketNotAllowedReason_NewPaymentMethod","value": "512"} + ,{"name": "k_EMarketNotAllowedReason_InvalidCookie","value": "1024"} + ,{"name": "k_EMarketNotAllowedReason_UsingNewDevice","value": "2048"} + ,{"name": "k_EMarketNotAllowedReason_RecentSelfRefund","value": "4096"} + ,{"name": "k_EMarketNotAllowedReason_NewPaymentMethodCannotBeVerified","value": "8192"} + ,{"name": "k_EMarketNotAllowedReason_NoRecentPurchases","value": "16384"} + ,{"name": "k_EMarketNotAllowedReason_AcceptedWalletGift","value": "32768"} +]} +, {"enumname": "EDurationControlProgress","values": [ + {"name": "k_EDurationControlProgress_Full","value": "0"} + ,{"name": "k_EDurationControlProgress_Half","value": "1"} + ,{"name": "k_EDurationControlProgress_None","value": "2"} +]} +, {"enumname": "EDurationControlNotification","values": [ + {"name": "k_EDurationControlNotification_None","value": "0"} + ,{"name": "k_EDurationControlNotification_1Hour","value": "1"} + ,{"name": "k_EDurationControlNotification_3Hours","value": "2"} + ,{"name": "k_EDurationControlNotification_HalfProgress","value": "3"} + ,{"name": "k_EDurationControlNotification_NoProgress","value": "4"} +]} +, {"enumname": "CGameID::EGameIDType","values": [ + {"name": "k_EGameIDTypeApp","value": "0"} + ,{"name": "k_EGameIDTypeGameMod","value": "1"} + ,{"name": "k_EGameIDTypeShortcut","value": "2"} + ,{"name": "k_EGameIDTypeP2P","value": "3"} +]} +, {"enumname": "EGameSearchErrorCode_t","values": [ + {"name": "k_EGameSearchErrorCode_OK","value": "1"} + ,{"name": "k_EGameSearchErrorCode_Failed_Search_Already_In_Progress","value": "2"} + ,{"name": "k_EGameSearchErrorCode_Failed_No_Search_In_Progress","value": "3"} + ,{"name": "k_EGameSearchErrorCode_Failed_Not_Lobby_Leader","value": "4"} + ,{"name": "k_EGameSearchErrorCode_Failed_No_Host_Available","value": "5"} + ,{"name": "k_EGameSearchErrorCode_Failed_Search_Params_Invalid","value": "6"} + ,{"name": "k_EGameSearchErrorCode_Failed_Offline","value": "7"} + ,{"name": "k_EGameSearchErrorCode_Failed_NotAuthorized","value": "8"} + ,{"name": "k_EGameSearchErrorCode_Failed_Unknown_Error","value": "9"} +]} +, {"enumname": "EPlayerResult_t","values": [ + {"name": "k_EPlayerResultFailedToConnect","value": "1"} + ,{"name": "k_EPlayerResultAbandoned","value": "2"} + ,{"name": "k_EPlayerResultKicked","value": "3"} + ,{"name": "k_EPlayerResultIncomplete","value": "4"} + ,{"name": "k_EPlayerResultCompleted","value": "5"} +]} +, {"enumname": "IPCFailure_t::EFailureType","values": [ + {"name": "k_EFailureFlushedCallbackQueue","value": "0"} + ,{"name": "k_EFailurePipeFail","value": "1"} +]} +, {"enumname": "EFriendRelationship","values": [ + {"name": "k_EFriendRelationshipNone","value": "0"} + ,{"name": "k_EFriendRelationshipBlocked","value": "1"} + ,{"name": "k_EFriendRelationshipRequestRecipient","value": "2"} + ,{"name": "k_EFriendRelationshipFriend","value": "3"} + ,{"name": "k_EFriendRelationshipRequestInitiator","value": "4"} + ,{"name": "k_EFriendRelationshipIgnored","value": "5"} + ,{"name": "k_EFriendRelationshipIgnoredFriend","value": "6"} + ,{"name": "k_EFriendRelationshipSuggested_DEPRECATED","value": "7"} + ,{"name": "k_EFriendRelationshipMax","value": "8"} +]} +, {"enumname": "EPersonaState","values": [ + {"name": "k_EPersonaStateOffline","value": "0"} + ,{"name": "k_EPersonaStateOnline","value": "1"} + ,{"name": "k_EPersonaStateBusy","value": "2"} + ,{"name": "k_EPersonaStateAway","value": "3"} + ,{"name": "k_EPersonaStateSnooze","value": "4"} + ,{"name": "k_EPersonaStateLookingToTrade","value": "5"} + ,{"name": "k_EPersonaStateLookingToPlay","value": "6"} + ,{"name": "k_EPersonaStateInvisible","value": "7"} + ,{"name": "k_EPersonaStateMax","value": "8"} +]} +, {"enumname": "EFriendFlags","values": [ + {"name": "k_EFriendFlagNone","value": "0"} + ,{"name": "k_EFriendFlagBlocked","value": "1"} + ,{"name": "k_EFriendFlagFriendshipRequested","value": "2"} + ,{"name": "k_EFriendFlagImmediate","value": "4"} + ,{"name": "k_EFriendFlagClanMember","value": "8"} + ,{"name": "k_EFriendFlagOnGameServer","value": "16"} + ,{"name": "k_EFriendFlagRequestingFriendship","value": "128"} + ,{"name": "k_EFriendFlagRequestingInfo","value": "256"} + ,{"name": "k_EFriendFlagIgnored","value": "512"} + ,{"name": "k_EFriendFlagIgnoredFriend","value": "1024"} + ,{"name": "k_EFriendFlagChatMember","value": "4096"} + ,{"name": "k_EFriendFlagAll","value": "65535"} +]} +, {"enumname": "EUserRestriction","values": [ + {"name": "k_nUserRestrictionNone","value": "0"} + ,{"name": "k_nUserRestrictionUnknown","value": "1"} + ,{"name": "k_nUserRestrictionAnyChat","value": "2"} + ,{"name": "k_nUserRestrictionVoiceChat","value": "4"} + ,{"name": "k_nUserRestrictionGroupChat","value": "8"} + ,{"name": "k_nUserRestrictionRating","value": "16"} + ,{"name": "k_nUserRestrictionGameInvites","value": "32"} + ,{"name": "k_nUserRestrictionTrading","value": "64"} +]} +, {"enumname": "EOverlayToStoreFlag","values": [ + {"name": "k_EOverlayToStoreFlag_None","value": "0"} + ,{"name": "k_EOverlayToStoreFlag_AddToCart","value": "1"} + ,{"name": "k_EOverlayToStoreFlag_AddToCartAndShow","value": "2"} +]} +, {"enumname": "EActivateGameOverlayToWebPageMode","values": [ + {"name": "k_EActivateGameOverlayToWebPageMode_Default","value": "0"} + ,{"name": "k_EActivateGameOverlayToWebPageMode_Modal","value": "1"} +]} +, {"enumname": "EPersonaChange","values": [ + {"name": "k_EPersonaChangeName","value": "1"} + ,{"name": "k_EPersonaChangeStatus","value": "2"} + ,{"name": "k_EPersonaChangeComeOnline","value": "4"} + ,{"name": "k_EPersonaChangeGoneOffline","value": "8"} + ,{"name": "k_EPersonaChangeGamePlayed","value": "16"} + ,{"name": "k_EPersonaChangeGameServer","value": "32"} + ,{"name": "k_EPersonaChangeAvatar","value": "64"} + ,{"name": "k_EPersonaChangeJoinedSource","value": "128"} + ,{"name": "k_EPersonaChangeLeftSource","value": "256"} + ,{"name": "k_EPersonaChangeRelationshipChanged","value": "512"} + ,{"name": "k_EPersonaChangeNameFirstSet","value": "1024"} + ,{"name": "k_EPersonaChangeBroadcast","value": "2048"} + ,{"name": "k_EPersonaChangeNickname","value": "4096"} + ,{"name": "k_EPersonaChangeSteamLevel","value": "8192"} + ,{"name": "k_EPersonaChangeRichPresence","value": "16384"} +]} +, {"enumname": "ESteamAPICallFailure","values": [ + {"name": "k_ESteamAPICallFailureNone","value": "-1"} + ,{"name": "k_ESteamAPICallFailureSteamGone","value": "0"} + ,{"name": "k_ESteamAPICallFailureNetworkFailure","value": "1"} + ,{"name": "k_ESteamAPICallFailureInvalidHandle","value": "2"} + ,{"name": "k_ESteamAPICallFailureMismatchedCallback","value": "3"} +]} +, {"enumname": "EGamepadTextInputMode","values": [ + {"name": "k_EGamepadTextInputModeNormal","value": "0"} + ,{"name": "k_EGamepadTextInputModePassword","value": "1"} +]} +, {"enumname": "EGamepadTextInputLineMode","values": [ + {"name": "k_EGamepadTextInputLineModeSingleLine","value": "0"} + ,{"name": "k_EGamepadTextInputLineModeMultipleLines","value": "1"} +]} +, {"enumname": "ECheckFileSignature","values": [ + {"name": "k_ECheckFileSignatureInvalidSignature","value": "0"} + ,{"name": "k_ECheckFileSignatureValidSignature","value": "1"} + ,{"name": "k_ECheckFileSignatureFileNotFound","value": "2"} + ,{"name": "k_ECheckFileSignatureNoSignaturesFoundForThisApp","value": "3"} + ,{"name": "k_ECheckFileSignatureNoSignaturesFoundForThisFile","value": "4"} +]} +, {"enumname": "EMatchMakingServerResponse","values": [ + {"name": "eServerResponded","value": "0"} + ,{"name": "eServerFailedToRespond","value": "1"} + ,{"name": "eNoServersListedOnMasterServer","value": "2"} +]} +, {"enumname": "ELobbyType","values": [ + {"name": "k_ELobbyTypePrivate","value": "0"} + ,{"name": "k_ELobbyTypeFriendsOnly","value": "1"} + ,{"name": "k_ELobbyTypePublic","value": "2"} + ,{"name": "k_ELobbyTypeInvisible","value": "3"} + ,{"name": "k_ELobbyTypePrivateUnique","value": "4"} +]} +, {"enumname": "ELobbyComparison","values": [ + {"name": "k_ELobbyComparisonEqualToOrLessThan","value": "-2"} + ,{"name": "k_ELobbyComparisonLessThan","value": "-1"} + ,{"name": "k_ELobbyComparisonEqual","value": "0"} + ,{"name": "k_ELobbyComparisonGreaterThan","value": "1"} + ,{"name": "k_ELobbyComparisonEqualToOrGreaterThan","value": "2"} + ,{"name": "k_ELobbyComparisonNotEqual","value": "3"} +]} +, {"enumname": "ELobbyDistanceFilter","values": [ + {"name": "k_ELobbyDistanceFilterClose","value": "0"} + ,{"name": "k_ELobbyDistanceFilterDefault","value": "1"} + ,{"name": "k_ELobbyDistanceFilterFar","value": "2"} + ,{"name": "k_ELobbyDistanceFilterWorldwide","value": "3"} +]} +, {"enumname": "EChatMemberStateChange","values": [ + {"name": "k_EChatMemberStateChangeEntered","value": "1"} + ,{"name": "k_EChatMemberStateChangeLeft","value": "2"} + ,{"name": "k_EChatMemberStateChangeDisconnected","value": "4"} + ,{"name": "k_EChatMemberStateChangeKicked","value": "8"} + ,{"name": "k_EChatMemberStateChangeBanned","value": "16"} +]} +, {"enumname": "ESteamPartyBeaconLocationType","values": [ + {"name": "k_ESteamPartyBeaconLocationType_Invalid","value": "0"} + ,{"name": "k_ESteamPartyBeaconLocationType_ChatGroup","value": "1"} + ,{"name": "k_ESteamPartyBeaconLocationType_Max","value": "2"} +]} +, {"enumname": "ESteamPartyBeaconLocationData","values": [ + {"name": "k_ESteamPartyBeaconLocationDataInvalid","value": "0"} + ,{"name": "k_ESteamPartyBeaconLocationDataName","value": "1"} + ,{"name": "k_ESteamPartyBeaconLocationDataIconURLSmall","value": "2"} + ,{"name": "k_ESteamPartyBeaconLocationDataIconURLMedium","value": "3"} + ,{"name": "k_ESteamPartyBeaconLocationDataIconURLLarge","value": "4"} +]} +, {"enumname": "RequestPlayersForGameResultCallback_t::PlayerAcceptState_t","values": [ + {"name": "k_EStateUnknown","value": "0"} + ,{"name": "k_EStatePlayerAccepted","value": "1"} + ,{"name": "k_EStatePlayerDeclined","value": "2"} +]} +, {"enumname": "ERemoteStoragePlatform","values": [ + {"name": "k_ERemoteStoragePlatformNone","value": "0"} + ,{"name": "k_ERemoteStoragePlatformWindows","value": "1"} + ,{"name": "k_ERemoteStoragePlatformOSX","value": "2"} + ,{"name": "k_ERemoteStoragePlatformPS3","value": "4"} + ,{"name": "k_ERemoteStoragePlatformLinux","value": "8"} + ,{"name": "k_ERemoteStoragePlatformReserved2","value": "16"} + ,{"name": "k_ERemoteStoragePlatformAndroid","value": "32"} + ,{"name": "k_ERemoteStoragePlatformIOS","value": "64"} + ,{"name": "k_ERemoteStoragePlatformAll","value": "-1"} +]} +, {"enumname": "ERemoteStoragePublishedFileVisibility","values": [ + {"name": "k_ERemoteStoragePublishedFileVisibilityPublic","value": "0"} + ,{"name": "k_ERemoteStoragePublishedFileVisibilityFriendsOnly","value": "1"} + ,{"name": "k_ERemoteStoragePublishedFileVisibilityPrivate","value": "2"} +]} +, {"enumname": "EWorkshopFileType","values": [ + {"name": "k_EWorkshopFileTypeFirst","value": "0"} + ,{"name": "k_EWorkshopFileTypeCommunity","value": "0"} + ,{"name": "k_EWorkshopFileTypeMicrotransaction","value": "1"} + ,{"name": "k_EWorkshopFileTypeCollection","value": "2"} + ,{"name": "k_EWorkshopFileTypeArt","value": "3"} + ,{"name": "k_EWorkshopFileTypeVideo","value": "4"} + ,{"name": "k_EWorkshopFileTypeScreenshot","value": "5"} + ,{"name": "k_EWorkshopFileTypeGame","value": "6"} + ,{"name": "k_EWorkshopFileTypeSoftware","value": "7"} + ,{"name": "k_EWorkshopFileTypeConcept","value": "8"} + ,{"name": "k_EWorkshopFileTypeWebGuide","value": "9"} + ,{"name": "k_EWorkshopFileTypeIntegratedGuide","value": "10"} + ,{"name": "k_EWorkshopFileTypeMerch","value": "11"} + ,{"name": "k_EWorkshopFileTypeControllerBinding","value": "12"} + ,{"name": "k_EWorkshopFileTypeSteamworksAccessInvite","value": "13"} + ,{"name": "k_EWorkshopFileTypeSteamVideo","value": "14"} + ,{"name": "k_EWorkshopFileTypeGameManagedItem","value": "15"} + ,{"name": "k_EWorkshopFileTypeMax","value": "16"} +]} +, {"enumname": "EWorkshopVote","values": [ + {"name": "k_EWorkshopVoteUnvoted","value": "0"} + ,{"name": "k_EWorkshopVoteFor","value": "1"} + ,{"name": "k_EWorkshopVoteAgainst","value": "2"} + ,{"name": "k_EWorkshopVoteLater","value": "3"} +]} +, {"enumname": "EWorkshopFileAction","values": [ + {"name": "k_EWorkshopFileActionPlayed","value": "0"} + ,{"name": "k_EWorkshopFileActionCompleted","value": "1"} +]} +, {"enumname": "EWorkshopEnumerationType","values": [ + {"name": "k_EWorkshopEnumerationTypeRankedByVote","value": "0"} + ,{"name": "k_EWorkshopEnumerationTypeRecent","value": "1"} + ,{"name": "k_EWorkshopEnumerationTypeTrending","value": "2"} + ,{"name": "k_EWorkshopEnumerationTypeFavoritesOfFriends","value": "3"} + ,{"name": "k_EWorkshopEnumerationTypeVotedByFriends","value": "4"} + ,{"name": "k_EWorkshopEnumerationTypeContentByFriends","value": "5"} + ,{"name": "k_EWorkshopEnumerationTypeRecentFromFollowedUsers","value": "6"} +]} +, {"enumname": "EWorkshopVideoProvider","values": [ + {"name": "k_EWorkshopVideoProviderNone","value": "0"} + ,{"name": "k_EWorkshopVideoProviderYoutube","value": "1"} +]} +, {"enumname": "EUGCReadAction","values": [ + {"name": "k_EUGCRead_ContinueReadingUntilFinished","value": "0"} + ,{"name": "k_EUGCRead_ContinueReading","value": "1"} + ,{"name": "k_EUGCRead_Close","value": "2"} +]} +, {"enumname": "ELeaderboardDataRequest","values": [ + {"name": "k_ELeaderboardDataRequestGlobal","value": "0"} + ,{"name": "k_ELeaderboardDataRequestGlobalAroundUser","value": "1"} + ,{"name": "k_ELeaderboardDataRequestFriends","value": "2"} + ,{"name": "k_ELeaderboardDataRequestUsers","value": "3"} +]} +, {"enumname": "ELeaderboardSortMethod","values": [ + {"name": "k_ELeaderboardSortMethodNone","value": "0"} + ,{"name": "k_ELeaderboardSortMethodAscending","value": "1"} + ,{"name": "k_ELeaderboardSortMethodDescending","value": "2"} +]} +, {"enumname": "ELeaderboardDisplayType","values": [ + {"name": "k_ELeaderboardDisplayTypeNone","value": "0"} + ,{"name": "k_ELeaderboardDisplayTypeNumeric","value": "1"} + ,{"name": "k_ELeaderboardDisplayTypeTimeSeconds","value": "2"} + ,{"name": "k_ELeaderboardDisplayTypeTimeMilliSeconds","value": "3"} +]} +, {"enumname": "ELeaderboardUploadScoreMethod","values": [ + {"name": "k_ELeaderboardUploadScoreMethodNone","value": "0"} + ,{"name": "k_ELeaderboardUploadScoreMethodKeepBest","value": "1"} + ,{"name": "k_ELeaderboardUploadScoreMethodForceUpdate","value": "2"} +]} +, {"enumname": "ERegisterActivationCodeResult","values": [ + {"name": "k_ERegisterActivationCodeResultOK","value": "0"} + ,{"name": "k_ERegisterActivationCodeResultFail","value": "1"} + ,{"name": "k_ERegisterActivationCodeResultAlreadyRegistered","value": "2"} + ,{"name": "k_ERegisterActivationCodeResultTimeout","value": "3"} + ,{"name": "k_ERegisterActivationCodeAlreadyOwned","value": "4"} +]} +, {"enumname": "EP2PSessionError","values": [ + {"name": "k_EP2PSessionErrorNone","value": "0"} + ,{"name": "k_EP2PSessionErrorNotRunningApp","value": "1"} + ,{"name": "k_EP2PSessionErrorNoRightsToApp","value": "2"} + ,{"name": "k_EP2PSessionErrorDestinationNotLoggedIn","value": "3"} + ,{"name": "k_EP2PSessionErrorTimeout","value": "4"} + ,{"name": "k_EP2PSessionErrorMax","value": "5"} +]} +, {"enumname": "EP2PSend","values": [ + {"name": "k_EP2PSendUnreliable","value": "0"} + ,{"name": "k_EP2PSendUnreliableNoDelay","value": "1"} + ,{"name": "k_EP2PSendReliable","value": "2"} + ,{"name": "k_EP2PSendReliableWithBuffering","value": "3"} +]} +, {"enumname": "ESNetSocketState","values": [ + {"name": "k_ESNetSocketStateInvalid","value": "0"} + ,{"name": "k_ESNetSocketStateConnected","value": "1"} + ,{"name": "k_ESNetSocketStateInitiated","value": "10"} + ,{"name": "k_ESNetSocketStateLocalCandidatesFound","value": "11"} + ,{"name": "k_ESNetSocketStateReceivedRemoteCandidates","value": "12"} + ,{"name": "k_ESNetSocketStateChallengeHandshake","value": "15"} + ,{"name": "k_ESNetSocketStateDisconnecting","value": "21"} + ,{"name": "k_ESNetSocketStateLocalDisconnect","value": "22"} + ,{"name": "k_ESNetSocketStateTimeoutDuringConnect","value": "23"} + ,{"name": "k_ESNetSocketStateRemoteEndDisconnected","value": "24"} + ,{"name": "k_ESNetSocketStateConnectionBroken","value": "25"} +]} +, {"enumname": "ESNetSocketConnectionType","values": [ + {"name": "k_ESNetSocketConnectionTypeNotConnected","value": "0"} + ,{"name": "k_ESNetSocketConnectionTypeUDP","value": "1"} + ,{"name": "k_ESNetSocketConnectionTypeUDPRelay","value": "2"} +]} +, {"enumname": "EVRScreenshotType","values": [ + {"name": "k_EVRScreenshotType_None","value": "0"} + ,{"name": "k_EVRScreenshotType_Mono","value": "1"} + ,{"name": "k_EVRScreenshotType_Stereo","value": "2"} + ,{"name": "k_EVRScreenshotType_MonoCubemap","value": "3"} + ,{"name": "k_EVRScreenshotType_MonoPanorama","value": "4"} + ,{"name": "k_EVRScreenshotType_StereoPanorama","value": "5"} +]} +, {"enumname": "AudioPlayback_Status","values": [ + {"name": "AudioPlayback_Undefined","value": "0"} + ,{"name": "AudioPlayback_Playing","value": "1"} + ,{"name": "AudioPlayback_Paused","value": "2"} + ,{"name": "AudioPlayback_Idle","value": "3"} +]} +, {"enumname": "EHTTPMethod","values": [ + {"name": "k_EHTTPMethodInvalid","value": "0"} + ,{"name": "k_EHTTPMethodGET","value": "1"} + ,{"name": "k_EHTTPMethodHEAD","value": "2"} + ,{"name": "k_EHTTPMethodPOST","value": "3"} + ,{"name": "k_EHTTPMethodPUT","value": "4"} + ,{"name": "k_EHTTPMethodDELETE","value": "5"} + ,{"name": "k_EHTTPMethodOPTIONS","value": "6"} + ,{"name": "k_EHTTPMethodPATCH","value": "7"} +]} +, {"enumname": "EHTTPStatusCode","values": [ + {"name": "k_EHTTPStatusCodeInvalid","value": "0"} + ,{"name": "k_EHTTPStatusCode100Continue","value": "100"} + ,{"name": "k_EHTTPStatusCode101SwitchingProtocols","value": "101"} + ,{"name": "k_EHTTPStatusCode200OK","value": "200"} + ,{"name": "k_EHTTPStatusCode201Created","value": "201"} + ,{"name": "k_EHTTPStatusCode202Accepted","value": "202"} + ,{"name": "k_EHTTPStatusCode203NonAuthoritative","value": "203"} + ,{"name": "k_EHTTPStatusCode204NoContent","value": "204"} + ,{"name": "k_EHTTPStatusCode205ResetContent","value": "205"} + ,{"name": "k_EHTTPStatusCode206PartialContent","value": "206"} + ,{"name": "k_EHTTPStatusCode300MultipleChoices","value": "300"} + ,{"name": "k_EHTTPStatusCode301MovedPermanently","value": "301"} + ,{"name": "k_EHTTPStatusCode302Found","value": "302"} + ,{"name": "k_EHTTPStatusCode303SeeOther","value": "303"} + ,{"name": "k_EHTTPStatusCode304NotModified","value": "304"} + ,{"name": "k_EHTTPStatusCode305UseProxy","value": "305"} + ,{"name": "k_EHTTPStatusCode307TemporaryRedirect","value": "307"} + ,{"name": "k_EHTTPStatusCode400BadRequest","value": "400"} + ,{"name": "k_EHTTPStatusCode401Unauthorized","value": "401"} + ,{"name": "k_EHTTPStatusCode402PaymentRequired","value": "402"} + ,{"name": "k_EHTTPStatusCode403Forbidden","value": "403"} + ,{"name": "k_EHTTPStatusCode404NotFound","value": "404"} + ,{"name": "k_EHTTPStatusCode405MethodNotAllowed","value": "405"} + ,{"name": "k_EHTTPStatusCode406NotAcceptable","value": "406"} + ,{"name": "k_EHTTPStatusCode407ProxyAuthRequired","value": "407"} + ,{"name": "k_EHTTPStatusCode408RequestTimeout","value": "408"} + ,{"name": "k_EHTTPStatusCode409Conflict","value": "409"} + ,{"name": "k_EHTTPStatusCode410Gone","value": "410"} + ,{"name": "k_EHTTPStatusCode411LengthRequired","value": "411"} + ,{"name": "k_EHTTPStatusCode412PreconditionFailed","value": "412"} + ,{"name": "k_EHTTPStatusCode413RequestEntityTooLarge","value": "413"} + ,{"name": "k_EHTTPStatusCode414RequestURITooLong","value": "414"} + ,{"name": "k_EHTTPStatusCode415UnsupportedMediaType","value": "415"} + ,{"name": "k_EHTTPStatusCode416RequestedRangeNotSatisfiable","value": "416"} + ,{"name": "k_EHTTPStatusCode417ExpectationFailed","value": "417"} + ,{"name": "k_EHTTPStatusCode4xxUnknown","value": "418"} + ,{"name": "k_EHTTPStatusCode429TooManyRequests","value": "429"} + ,{"name": "k_EHTTPStatusCode500InternalServerError","value": "500"} + ,{"name": "k_EHTTPStatusCode501NotImplemented","value": "501"} + ,{"name": "k_EHTTPStatusCode502BadGateway","value": "502"} + ,{"name": "k_EHTTPStatusCode503ServiceUnavailable","value": "503"} + ,{"name": "k_EHTTPStatusCode504GatewayTimeout","value": "504"} + ,{"name": "k_EHTTPStatusCode505HTTPVersionNotSupported","value": "505"} + ,{"name": "k_EHTTPStatusCode5xxUnknown","value": "599"} +]} +, {"enumname": "EInputSource","values": [ + {"name": "k_EInputSource_None","value": "0"} + ,{"name": "k_EInputSource_LeftTrackpad","value": "1"} + ,{"name": "k_EInputSource_RightTrackpad","value": "2"} + ,{"name": "k_EInputSource_Joystick","value": "3"} + ,{"name": "k_EInputSource_ABXY","value": "4"} + ,{"name": "k_EInputSource_Switch","value": "5"} + ,{"name": "k_EInputSource_LeftTrigger","value": "6"} + ,{"name": "k_EInputSource_RightTrigger","value": "7"} + ,{"name": "k_EInputSource_LeftBumper","value": "8"} + ,{"name": "k_EInputSource_RightBumper","value": "9"} + ,{"name": "k_EInputSource_Gyro","value": "10"} + ,{"name": "k_EInputSource_CenterTrackpad","value": "11"} + ,{"name": "k_EInputSource_RightJoystick","value": "12"} + ,{"name": "k_EInputSource_DPad","value": "13"} + ,{"name": "k_EInputSource_Key","value": "14"} + ,{"name": "k_EInputSource_Mouse","value": "15"} + ,{"name": "k_EInputSource_LeftGyro","value": "16"} + ,{"name": "k_EInputSource_Count","value": "17"} +]} +, {"enumname": "EInputSourceMode","values": [ + {"name": "k_EInputSourceMode_None","value": "0"} + ,{"name": "k_EInputSourceMode_Dpad","value": "1"} + ,{"name": "k_EInputSourceMode_Buttons","value": "2"} + ,{"name": "k_EInputSourceMode_FourButtons","value": "3"} + ,{"name": "k_EInputSourceMode_AbsoluteMouse","value": "4"} + ,{"name": "k_EInputSourceMode_RelativeMouse","value": "5"} + ,{"name": "k_EInputSourceMode_JoystickMove","value": "6"} + ,{"name": "k_EInputSourceMode_JoystickMouse","value": "7"} + ,{"name": "k_EInputSourceMode_JoystickCamera","value": "8"} + ,{"name": "k_EInputSourceMode_ScrollWheel","value": "9"} + ,{"name": "k_EInputSourceMode_Trigger","value": "10"} + ,{"name": "k_EInputSourceMode_TouchMenu","value": "11"} + ,{"name": "k_EInputSourceMode_MouseJoystick","value": "12"} + ,{"name": "k_EInputSourceMode_MouseRegion","value": "13"} + ,{"name": "k_EInputSourceMode_RadialMenu","value": "14"} + ,{"name": "k_EInputSourceMode_SingleButton","value": "15"} + ,{"name": "k_EInputSourceMode_Switches","value": "16"} +]} +, {"enumname": "EInputActionOrigin","values": [ + {"name": "k_EInputActionOrigin_None","value": "0"} + ,{"name": "k_EInputActionOrigin_SteamController_A","value": "1"} + ,{"name": "k_EInputActionOrigin_SteamController_B","value": "2"} + ,{"name": "k_EInputActionOrigin_SteamController_X","value": "3"} + ,{"name": "k_EInputActionOrigin_SteamController_Y","value": "4"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftBumper","value": "5"} + ,{"name": "k_EInputActionOrigin_SteamController_RightBumper","value": "6"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftGrip","value": "7"} + ,{"name": "k_EInputActionOrigin_SteamController_RightGrip","value": "8"} + ,{"name": "k_EInputActionOrigin_SteamController_Start","value": "9"} + ,{"name": "k_EInputActionOrigin_SteamController_Back","value": "10"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_Touch","value": "11"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_Swipe","value": "12"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_Click","value": "13"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_DPadNorth","value": "14"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_DPadSouth","value": "15"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_DPadWest","value": "16"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftPad_DPadEast","value": "17"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_Touch","value": "18"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_Swipe","value": "19"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_Click","value": "20"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_DPadNorth","value": "21"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_DPadSouth","value": "22"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_DPadWest","value": "23"} + ,{"name": "k_EInputActionOrigin_SteamController_RightPad_DPadEast","value": "24"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftTrigger_Pull","value": "25"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftTrigger_Click","value": "26"} + ,{"name": "k_EInputActionOrigin_SteamController_RightTrigger_Pull","value": "27"} + ,{"name": "k_EInputActionOrigin_SteamController_RightTrigger_Click","value": "28"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftStick_Move","value": "29"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftStick_Click","value": "30"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftStick_DPadNorth","value": "31"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftStick_DPadSouth","value": "32"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftStick_DPadWest","value": "33"} + ,{"name": "k_EInputActionOrigin_SteamController_LeftStick_DPadEast","value": "34"} + ,{"name": "k_EInputActionOrigin_SteamController_Gyro_Move","value": "35"} + ,{"name": "k_EInputActionOrigin_SteamController_Gyro_Pitch","value": "36"} + ,{"name": "k_EInputActionOrigin_SteamController_Gyro_Yaw","value": "37"} + ,{"name": "k_EInputActionOrigin_SteamController_Gyro_Roll","value": "38"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved0","value": "39"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved1","value": "40"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved2","value": "41"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved3","value": "42"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved4","value": "43"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved5","value": "44"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved6","value": "45"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved7","value": "46"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved8","value": "47"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved9","value": "48"} + ,{"name": "k_EInputActionOrigin_SteamController_Reserved10","value": "49"} + ,{"name": "k_EInputActionOrigin_PS4_X","value": "50"} + ,{"name": "k_EInputActionOrigin_PS4_Circle","value": "51"} + ,{"name": "k_EInputActionOrigin_PS4_Triangle","value": "52"} + ,{"name": "k_EInputActionOrigin_PS4_Square","value": "53"} + ,{"name": "k_EInputActionOrigin_PS4_LeftBumper","value": "54"} + ,{"name": "k_EInputActionOrigin_PS4_RightBumper","value": "55"} + ,{"name": "k_EInputActionOrigin_PS4_Options","value": "56"} + ,{"name": "k_EInputActionOrigin_PS4_Share","value": "57"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_Touch","value": "58"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_Swipe","value": "59"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_Click","value": "60"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_DPadNorth","value": "61"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_DPadSouth","value": "62"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_DPadWest","value": "63"} + ,{"name": "k_EInputActionOrigin_PS4_LeftPad_DPadEast","value": "64"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_Touch","value": "65"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_Swipe","value": "66"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_Click","value": "67"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_DPadNorth","value": "68"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_DPadSouth","value": "69"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_DPadWest","value": "70"} + ,{"name": "k_EInputActionOrigin_PS4_RightPad_DPadEast","value": "71"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_Touch","value": "72"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_Swipe","value": "73"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_Click","value": "74"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_DPadNorth","value": "75"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_DPadSouth","value": "76"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_DPadWest","value": "77"} + ,{"name": "k_EInputActionOrigin_PS4_CenterPad_DPadEast","value": "78"} + ,{"name": "k_EInputActionOrigin_PS4_LeftTrigger_Pull","value": "79"} + ,{"name": "k_EInputActionOrigin_PS4_LeftTrigger_Click","value": "80"} + ,{"name": "k_EInputActionOrigin_PS4_RightTrigger_Pull","value": "81"} + ,{"name": "k_EInputActionOrigin_PS4_RightTrigger_Click","value": "82"} + ,{"name": "k_EInputActionOrigin_PS4_LeftStick_Move","value": "83"} + ,{"name": "k_EInputActionOrigin_PS4_LeftStick_Click","value": "84"} + ,{"name": "k_EInputActionOrigin_PS4_LeftStick_DPadNorth","value": "85"} + ,{"name": "k_EInputActionOrigin_PS4_LeftStick_DPadSouth","value": "86"} + ,{"name": "k_EInputActionOrigin_PS4_LeftStick_DPadWest","value": "87"} + ,{"name": "k_EInputActionOrigin_PS4_LeftStick_DPadEast","value": "88"} + ,{"name": "k_EInputActionOrigin_PS4_RightStick_Move","value": "89"} + ,{"name": "k_EInputActionOrigin_PS4_RightStick_Click","value": "90"} + ,{"name": "k_EInputActionOrigin_PS4_RightStick_DPadNorth","value": "91"} + ,{"name": "k_EInputActionOrigin_PS4_RightStick_DPadSouth","value": "92"} + ,{"name": "k_EInputActionOrigin_PS4_RightStick_DPadWest","value": "93"} + ,{"name": "k_EInputActionOrigin_PS4_RightStick_DPadEast","value": "94"} + ,{"name": "k_EInputActionOrigin_PS4_DPad_North","value": "95"} + ,{"name": "k_EInputActionOrigin_PS4_DPad_South","value": "96"} + ,{"name": "k_EInputActionOrigin_PS4_DPad_West","value": "97"} + ,{"name": "k_EInputActionOrigin_PS4_DPad_East","value": "98"} + ,{"name": "k_EInputActionOrigin_PS4_Gyro_Move","value": "99"} + ,{"name": "k_EInputActionOrigin_PS4_Gyro_Pitch","value": "100"} + ,{"name": "k_EInputActionOrigin_PS4_Gyro_Yaw","value": "101"} + ,{"name": "k_EInputActionOrigin_PS4_Gyro_Roll","value": "102"} + ,{"name": "k_EInputActionOrigin_PS4_DPad_Move","value": "103"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved1","value": "104"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved2","value": "105"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved3","value": "106"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved4","value": "107"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved5","value": "108"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved6","value": "109"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved7","value": "110"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved8","value": "111"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved9","value": "112"} + ,{"name": "k_EInputActionOrigin_PS4_Reserved10","value": "113"} + ,{"name": "k_EInputActionOrigin_XBoxOne_A","value": "114"} + ,{"name": "k_EInputActionOrigin_XBoxOne_B","value": "115"} + ,{"name": "k_EInputActionOrigin_XBoxOne_X","value": "116"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Y","value": "117"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftBumper","value": "118"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightBumper","value": "119"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Menu","value": "120"} + ,{"name": "k_EInputActionOrigin_XBoxOne_View","value": "121"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftTrigger_Pull","value": "122"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftTrigger_Click","value": "123"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightTrigger_Pull","value": "124"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightTrigger_Click","value": "125"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftStick_Move","value": "126"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftStick_Click","value": "127"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftStick_DPadNorth","value": "128"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftStick_DPadSouth","value": "129"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftStick_DPadWest","value": "130"} + ,{"name": "k_EInputActionOrigin_XBoxOne_LeftStick_DPadEast","value": "131"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightStick_Move","value": "132"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightStick_Click","value": "133"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightStick_DPadNorth","value": "134"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightStick_DPadSouth","value": "135"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightStick_DPadWest","value": "136"} + ,{"name": "k_EInputActionOrigin_XBoxOne_RightStick_DPadEast","value": "137"} + ,{"name": "k_EInputActionOrigin_XBoxOne_DPad_North","value": "138"} + ,{"name": "k_EInputActionOrigin_XBoxOne_DPad_South","value": "139"} + ,{"name": "k_EInputActionOrigin_XBoxOne_DPad_West","value": "140"} + ,{"name": "k_EInputActionOrigin_XBoxOne_DPad_East","value": "141"} + ,{"name": "k_EInputActionOrigin_XBoxOne_DPad_Move","value": "142"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved1","value": "143"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved2","value": "144"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved3","value": "145"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved4","value": "146"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved5","value": "147"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved6","value": "148"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved7","value": "149"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved8","value": "150"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved9","value": "151"} + ,{"name": "k_EInputActionOrigin_XBoxOne_Reserved10","value": "152"} + ,{"name": "k_EInputActionOrigin_XBox360_A","value": "153"} + ,{"name": "k_EInputActionOrigin_XBox360_B","value": "154"} + ,{"name": "k_EInputActionOrigin_XBox360_X","value": "155"} + ,{"name": "k_EInputActionOrigin_XBox360_Y","value": "156"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftBumper","value": "157"} + ,{"name": "k_EInputActionOrigin_XBox360_RightBumper","value": "158"} + ,{"name": "k_EInputActionOrigin_XBox360_Start","value": "159"} + ,{"name": "k_EInputActionOrigin_XBox360_Back","value": "160"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftTrigger_Pull","value": "161"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftTrigger_Click","value": "162"} + ,{"name": "k_EInputActionOrigin_XBox360_RightTrigger_Pull","value": "163"} + ,{"name": "k_EInputActionOrigin_XBox360_RightTrigger_Click","value": "164"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftStick_Move","value": "165"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftStick_Click","value": "166"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftStick_DPadNorth","value": "167"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftStick_DPadSouth","value": "168"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftStick_DPadWest","value": "169"} + ,{"name": "k_EInputActionOrigin_XBox360_LeftStick_DPadEast","value": "170"} + ,{"name": "k_EInputActionOrigin_XBox360_RightStick_Move","value": "171"} + ,{"name": "k_EInputActionOrigin_XBox360_RightStick_Click","value": "172"} + ,{"name": "k_EInputActionOrigin_XBox360_RightStick_DPadNorth","value": "173"} + ,{"name": "k_EInputActionOrigin_XBox360_RightStick_DPadSouth","value": "174"} + ,{"name": "k_EInputActionOrigin_XBox360_RightStick_DPadWest","value": "175"} + ,{"name": "k_EInputActionOrigin_XBox360_RightStick_DPadEast","value": "176"} + ,{"name": "k_EInputActionOrigin_XBox360_DPad_North","value": "177"} + ,{"name": "k_EInputActionOrigin_XBox360_DPad_South","value": "178"} + ,{"name": "k_EInputActionOrigin_XBox360_DPad_West","value": "179"} + ,{"name": "k_EInputActionOrigin_XBox360_DPad_East","value": "180"} + ,{"name": "k_EInputActionOrigin_XBox360_DPad_Move","value": "181"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved1","value": "182"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved2","value": "183"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved3","value": "184"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved4","value": "185"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved5","value": "186"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved6","value": "187"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved7","value": "188"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved8","value": "189"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved9","value": "190"} + ,{"name": "k_EInputActionOrigin_XBox360_Reserved10","value": "191"} + ,{"name": "k_EInputActionOrigin_Switch_A","value": "192"} + ,{"name": "k_EInputActionOrigin_Switch_B","value": "193"} + ,{"name": "k_EInputActionOrigin_Switch_X","value": "194"} + ,{"name": "k_EInputActionOrigin_Switch_Y","value": "195"} + ,{"name": "k_EInputActionOrigin_Switch_LeftBumper","value": "196"} + ,{"name": "k_EInputActionOrigin_Switch_RightBumper","value": "197"} + ,{"name": "k_EInputActionOrigin_Switch_Plus","value": "198"} + ,{"name": "k_EInputActionOrigin_Switch_Minus","value": "199"} + ,{"name": "k_EInputActionOrigin_Switch_Capture","value": "200"} + ,{"name": "k_EInputActionOrigin_Switch_LeftTrigger_Pull","value": "201"} + ,{"name": "k_EInputActionOrigin_Switch_LeftTrigger_Click","value": "202"} + ,{"name": "k_EInputActionOrigin_Switch_RightTrigger_Pull","value": "203"} + ,{"name": "k_EInputActionOrigin_Switch_RightTrigger_Click","value": "204"} + ,{"name": "k_EInputActionOrigin_Switch_LeftStick_Move","value": "205"} + ,{"name": "k_EInputActionOrigin_Switch_LeftStick_Click","value": "206"} + ,{"name": "k_EInputActionOrigin_Switch_LeftStick_DPadNorth","value": "207"} + ,{"name": "k_EInputActionOrigin_Switch_LeftStick_DPadSouth","value": "208"} + ,{"name": "k_EInputActionOrigin_Switch_LeftStick_DPadWest","value": "209"} + ,{"name": "k_EInputActionOrigin_Switch_LeftStick_DPadEast","value": "210"} + ,{"name": "k_EInputActionOrigin_Switch_RightStick_Move","value": "211"} + ,{"name": "k_EInputActionOrigin_Switch_RightStick_Click","value": "212"} + ,{"name": "k_EInputActionOrigin_Switch_RightStick_DPadNorth","value": "213"} + ,{"name": "k_EInputActionOrigin_Switch_RightStick_DPadSouth","value": "214"} + ,{"name": "k_EInputActionOrigin_Switch_RightStick_DPadWest","value": "215"} + ,{"name": "k_EInputActionOrigin_Switch_RightStick_DPadEast","value": "216"} + ,{"name": "k_EInputActionOrigin_Switch_DPad_North","value": "217"} + ,{"name": "k_EInputActionOrigin_Switch_DPad_South","value": "218"} + ,{"name": "k_EInputActionOrigin_Switch_DPad_West","value": "219"} + ,{"name": "k_EInputActionOrigin_Switch_DPad_East","value": "220"} + ,{"name": "k_EInputActionOrigin_Switch_ProGyro_Move","value": "221"} + ,{"name": "k_EInputActionOrigin_Switch_ProGyro_Pitch","value": "222"} + ,{"name": "k_EInputActionOrigin_Switch_ProGyro_Yaw","value": "223"} + ,{"name": "k_EInputActionOrigin_Switch_ProGyro_Roll","value": "224"} + ,{"name": "k_EInputActionOrigin_Switch_DPad_Move","value": "225"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved1","value": "226"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved2","value": "227"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved3","value": "228"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved4","value": "229"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved5","value": "230"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved6","value": "231"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved7","value": "232"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved8","value": "233"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved9","value": "234"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved10","value": "235"} + ,{"name": "k_EInputActionOrigin_Switch_RightGyro_Move","value": "236"} + ,{"name": "k_EInputActionOrigin_Switch_RightGyro_Pitch","value": "237"} + ,{"name": "k_EInputActionOrigin_Switch_RightGyro_Yaw","value": "238"} + ,{"name": "k_EInputActionOrigin_Switch_RightGyro_Roll","value": "239"} + ,{"name": "k_EInputActionOrigin_Switch_LeftGyro_Move","value": "240"} + ,{"name": "k_EInputActionOrigin_Switch_LeftGyro_Pitch","value": "241"} + ,{"name": "k_EInputActionOrigin_Switch_LeftGyro_Yaw","value": "242"} + ,{"name": "k_EInputActionOrigin_Switch_LeftGyro_Roll","value": "243"} + ,{"name": "k_EInputActionOrigin_Switch_LeftGrip_Lower","value": "244"} + ,{"name": "k_EInputActionOrigin_Switch_LeftGrip_Upper","value": "245"} + ,{"name": "k_EInputActionOrigin_Switch_RightGrip_Lower","value": "246"} + ,{"name": "k_EInputActionOrigin_Switch_RightGrip_Upper","value": "247"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved11","value": "248"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved12","value": "249"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved13","value": "250"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved14","value": "251"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved15","value": "252"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved16","value": "253"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved17","value": "254"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved18","value": "255"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved19","value": "256"} + ,{"name": "k_EInputActionOrigin_Switch_Reserved20","value": "257"} + ,{"name": "k_EInputActionOrigin_Count","value": "258"} + ,{"name": "k_EInputActionOrigin_MaximumPossibleValue","value": "32767"} +]} +, {"enumname": "EXboxOrigin","values": [ + {"name": "k_EXboxOrigin_A","value": "0"} + ,{"name": "k_EXboxOrigin_B","value": "1"} + ,{"name": "k_EXboxOrigin_X","value": "2"} + ,{"name": "k_EXboxOrigin_Y","value": "3"} + ,{"name": "k_EXboxOrigin_LeftBumper","value": "4"} + ,{"name": "k_EXboxOrigin_RightBumper","value": "5"} + ,{"name": "k_EXboxOrigin_Menu","value": "6"} + ,{"name": "k_EXboxOrigin_View","value": "7"} + ,{"name": "k_EXboxOrigin_LeftTrigger_Pull","value": "8"} + ,{"name": "k_EXboxOrigin_LeftTrigger_Click","value": "9"} + ,{"name": "k_EXboxOrigin_RightTrigger_Pull","value": "10"} + ,{"name": "k_EXboxOrigin_RightTrigger_Click","value": "11"} + ,{"name": "k_EXboxOrigin_LeftStick_Move","value": "12"} + ,{"name": "k_EXboxOrigin_LeftStick_Click","value": "13"} + ,{"name": "k_EXboxOrigin_LeftStick_DPadNorth","value": "14"} + ,{"name": "k_EXboxOrigin_LeftStick_DPadSouth","value": "15"} + ,{"name": "k_EXboxOrigin_LeftStick_DPadWest","value": "16"} + ,{"name": "k_EXboxOrigin_LeftStick_DPadEast","value": "17"} + ,{"name": "k_EXboxOrigin_RightStick_Move","value": "18"} + ,{"name": "k_EXboxOrigin_RightStick_Click","value": "19"} + ,{"name": "k_EXboxOrigin_RightStick_DPadNorth","value": "20"} + ,{"name": "k_EXboxOrigin_RightStick_DPadSouth","value": "21"} + ,{"name": "k_EXboxOrigin_RightStick_DPadWest","value": "22"} + ,{"name": "k_EXboxOrigin_RightStick_DPadEast","value": "23"} + ,{"name": "k_EXboxOrigin_DPad_North","value": "24"} + ,{"name": "k_EXboxOrigin_DPad_South","value": "25"} + ,{"name": "k_EXboxOrigin_DPad_West","value": "26"} + ,{"name": "k_EXboxOrigin_DPad_East","value": "27"} + ,{"name": "k_EXboxOrigin_Count","value": "28"} +]} +, {"enumname": "ESteamControllerPad","values": [ + {"name": "k_ESteamControllerPad_Left","value": "0"} + ,{"name": "k_ESteamControllerPad_Right","value": "1"} +]} +, {"enumname": "ESteamInputType","values": [ + {"name": "k_ESteamInputType_Unknown","value": "0"} + ,{"name": "k_ESteamInputType_SteamController","value": "1"} + ,{"name": "k_ESteamInputType_XBox360Controller","value": "2"} + ,{"name": "k_ESteamInputType_XBoxOneController","value": "3"} + ,{"name": "k_ESteamInputType_GenericGamepad","value": "4"} + ,{"name": "k_ESteamInputType_PS4Controller","value": "5"} + ,{"name": "k_ESteamInputType_AppleMFiController","value": "6"} + ,{"name": "k_ESteamInputType_AndroidController","value": "7"} + ,{"name": "k_ESteamInputType_SwitchJoyConPair","value": "8"} + ,{"name": "k_ESteamInputType_SwitchJoyConSingle","value": "9"} + ,{"name": "k_ESteamInputType_SwitchProController","value": "10"} + ,{"name": "k_ESteamInputType_MobileTouch","value": "11"} + ,{"name": "k_ESteamInputType_PS3Controller","value": "12"} + ,{"name": "k_ESteamInputType_Count","value": "13"} + ,{"name": "k_ESteamInputType_MaximumPossibleValue","value": "255"} +]} +, {"enumname": "ESteamInputLEDFlag","values": [ + {"name": "k_ESteamInputLEDFlag_SetColor","value": "0"} + ,{"name": "k_ESteamInputLEDFlag_RestoreUserDefault","value": "1"} +]} +, {"enumname": "EControllerSource","values": [ + {"name": "k_EControllerSource_None","value": "0"} + ,{"name": "k_EControllerSource_LeftTrackpad","value": "1"} + ,{"name": "k_EControllerSource_RightTrackpad","value": "2"} + ,{"name": "k_EControllerSource_Joystick","value": "3"} + ,{"name": "k_EControllerSource_ABXY","value": "4"} + ,{"name": "k_EControllerSource_Switch","value": "5"} + ,{"name": "k_EControllerSource_LeftTrigger","value": "6"} + ,{"name": "k_EControllerSource_RightTrigger","value": "7"} + ,{"name": "k_EControllerSource_LeftBumper","value": "8"} + ,{"name": "k_EControllerSource_RightBumper","value": "9"} + ,{"name": "k_EControllerSource_Gyro","value": "10"} + ,{"name": "k_EControllerSource_CenterTrackpad","value": "11"} + ,{"name": "k_EControllerSource_RightJoystick","value": "12"} + ,{"name": "k_EControllerSource_DPad","value": "13"} + ,{"name": "k_EControllerSource_Key","value": "14"} + ,{"name": "k_EControllerSource_Mouse","value": "15"} + ,{"name": "k_EControllerSource_LeftGyro","value": "16"} + ,{"name": "k_EControllerSource_Count","value": "17"} +]} +, {"enumname": "EControllerSourceMode","values": [ + {"name": "k_EControllerSourceMode_None","value": "0"} + ,{"name": "k_EControllerSourceMode_Dpad","value": "1"} + ,{"name": "k_EControllerSourceMode_Buttons","value": "2"} + ,{"name": "k_EControllerSourceMode_FourButtons","value": "3"} + ,{"name": "k_EControllerSourceMode_AbsoluteMouse","value": "4"} + ,{"name": "k_EControllerSourceMode_RelativeMouse","value": "5"} + ,{"name": "k_EControllerSourceMode_JoystickMove","value": "6"} + ,{"name": "k_EControllerSourceMode_JoystickMouse","value": "7"} + ,{"name": "k_EControllerSourceMode_JoystickCamera","value": "8"} + ,{"name": "k_EControllerSourceMode_ScrollWheel","value": "9"} + ,{"name": "k_EControllerSourceMode_Trigger","value": "10"} + ,{"name": "k_EControllerSourceMode_TouchMenu","value": "11"} + ,{"name": "k_EControllerSourceMode_MouseJoystick","value": "12"} + ,{"name": "k_EControllerSourceMode_MouseRegion","value": "13"} + ,{"name": "k_EControllerSourceMode_RadialMenu","value": "14"} + ,{"name": "k_EControllerSourceMode_SingleButton","value": "15"} + ,{"name": "k_EControllerSourceMode_Switches","value": "16"} +]} +, {"enumname": "EControllerActionOrigin","values": [ + {"name": "k_EControllerActionOrigin_None","value": "0"} + ,{"name": "k_EControllerActionOrigin_A","value": "1"} + ,{"name": "k_EControllerActionOrigin_B","value": "2"} + ,{"name": "k_EControllerActionOrigin_X","value": "3"} + ,{"name": "k_EControllerActionOrigin_Y","value": "4"} + ,{"name": "k_EControllerActionOrigin_LeftBumper","value": "5"} + ,{"name": "k_EControllerActionOrigin_RightBumper","value": "6"} + ,{"name": "k_EControllerActionOrigin_LeftGrip","value": "7"} + ,{"name": "k_EControllerActionOrigin_RightGrip","value": "8"} + ,{"name": "k_EControllerActionOrigin_Start","value": "9"} + ,{"name": "k_EControllerActionOrigin_Back","value": "10"} + ,{"name": "k_EControllerActionOrigin_LeftPad_Touch","value": "11"} + ,{"name": "k_EControllerActionOrigin_LeftPad_Swipe","value": "12"} + ,{"name": "k_EControllerActionOrigin_LeftPad_Click","value": "13"} + ,{"name": "k_EControllerActionOrigin_LeftPad_DPadNorth","value": "14"} + ,{"name": "k_EControllerActionOrigin_LeftPad_DPadSouth","value": "15"} + ,{"name": "k_EControllerActionOrigin_LeftPad_DPadWest","value": "16"} + ,{"name": "k_EControllerActionOrigin_LeftPad_DPadEast","value": "17"} + ,{"name": "k_EControllerActionOrigin_RightPad_Touch","value": "18"} + ,{"name": "k_EControllerActionOrigin_RightPad_Swipe","value": "19"} + ,{"name": "k_EControllerActionOrigin_RightPad_Click","value": "20"} + ,{"name": "k_EControllerActionOrigin_RightPad_DPadNorth","value": "21"} + ,{"name": "k_EControllerActionOrigin_RightPad_DPadSouth","value": "22"} + ,{"name": "k_EControllerActionOrigin_RightPad_DPadWest","value": "23"} + ,{"name": "k_EControllerActionOrigin_RightPad_DPadEast","value": "24"} + ,{"name": "k_EControllerActionOrigin_LeftTrigger_Pull","value": "25"} + ,{"name": "k_EControllerActionOrigin_LeftTrigger_Click","value": "26"} + ,{"name": "k_EControllerActionOrigin_RightTrigger_Pull","value": "27"} + ,{"name": "k_EControllerActionOrigin_RightTrigger_Click","value": "28"} + ,{"name": "k_EControllerActionOrigin_LeftStick_Move","value": "29"} + ,{"name": "k_EControllerActionOrigin_LeftStick_Click","value": "30"} + ,{"name": "k_EControllerActionOrigin_LeftStick_DPadNorth","value": "31"} + ,{"name": "k_EControllerActionOrigin_LeftStick_DPadSouth","value": "32"} + ,{"name": "k_EControllerActionOrigin_LeftStick_DPadWest","value": "33"} + ,{"name": "k_EControllerActionOrigin_LeftStick_DPadEast","value": "34"} + ,{"name": "k_EControllerActionOrigin_Gyro_Move","value": "35"} + ,{"name": "k_EControllerActionOrigin_Gyro_Pitch","value": "36"} + ,{"name": "k_EControllerActionOrigin_Gyro_Yaw","value": "37"} + ,{"name": "k_EControllerActionOrigin_Gyro_Roll","value": "38"} + ,{"name": "k_EControllerActionOrigin_PS4_X","value": "39"} + ,{"name": "k_EControllerActionOrigin_PS4_Circle","value": "40"} + ,{"name": "k_EControllerActionOrigin_PS4_Triangle","value": "41"} + ,{"name": "k_EControllerActionOrigin_PS4_Square","value": "42"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftBumper","value": "43"} + ,{"name": "k_EControllerActionOrigin_PS4_RightBumper","value": "44"} + ,{"name": "k_EControllerActionOrigin_PS4_Options","value": "45"} + ,{"name": "k_EControllerActionOrigin_PS4_Share","value": "46"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_Touch","value": "47"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_Swipe","value": "48"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_Click","value": "49"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_DPadNorth","value": "50"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_DPadSouth","value": "51"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_DPadWest","value": "52"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftPad_DPadEast","value": "53"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_Touch","value": "54"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_Swipe","value": "55"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_Click","value": "56"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_DPadNorth","value": "57"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_DPadSouth","value": "58"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_DPadWest","value": "59"} + ,{"name": "k_EControllerActionOrigin_PS4_RightPad_DPadEast","value": "60"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_Touch","value": "61"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_Swipe","value": "62"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_Click","value": "63"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_DPadNorth","value": "64"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_DPadSouth","value": "65"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_DPadWest","value": "66"} + ,{"name": "k_EControllerActionOrigin_PS4_CenterPad_DPadEast","value": "67"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftTrigger_Pull","value": "68"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftTrigger_Click","value": "69"} + ,{"name": "k_EControllerActionOrigin_PS4_RightTrigger_Pull","value": "70"} + ,{"name": "k_EControllerActionOrigin_PS4_RightTrigger_Click","value": "71"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftStick_Move","value": "72"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftStick_Click","value": "73"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftStick_DPadNorth","value": "74"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftStick_DPadSouth","value": "75"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftStick_DPadWest","value": "76"} + ,{"name": "k_EControllerActionOrigin_PS4_LeftStick_DPadEast","value": "77"} + ,{"name": "k_EControllerActionOrigin_PS4_RightStick_Move","value": "78"} + ,{"name": "k_EControllerActionOrigin_PS4_RightStick_Click","value": "79"} + ,{"name": "k_EControllerActionOrigin_PS4_RightStick_DPadNorth","value": "80"} + ,{"name": "k_EControllerActionOrigin_PS4_RightStick_DPadSouth","value": "81"} + ,{"name": "k_EControllerActionOrigin_PS4_RightStick_DPadWest","value": "82"} + ,{"name": "k_EControllerActionOrigin_PS4_RightStick_DPadEast","value": "83"} + ,{"name": "k_EControllerActionOrigin_PS4_DPad_North","value": "84"} + ,{"name": "k_EControllerActionOrigin_PS4_DPad_South","value": "85"} + ,{"name": "k_EControllerActionOrigin_PS4_DPad_West","value": "86"} + ,{"name": "k_EControllerActionOrigin_PS4_DPad_East","value": "87"} + ,{"name": "k_EControllerActionOrigin_PS4_Gyro_Move","value": "88"} + ,{"name": "k_EControllerActionOrigin_PS4_Gyro_Pitch","value": "89"} + ,{"name": "k_EControllerActionOrigin_PS4_Gyro_Yaw","value": "90"} + ,{"name": "k_EControllerActionOrigin_PS4_Gyro_Roll","value": "91"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_A","value": "92"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_B","value": "93"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_X","value": "94"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_Y","value": "95"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftBumper","value": "96"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightBumper","value": "97"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_Menu","value": "98"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_View","value": "99"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftTrigger_Pull","value": "100"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftTrigger_Click","value": "101"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightTrigger_Pull","value": "102"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightTrigger_Click","value": "103"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftStick_Move","value": "104"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftStick_Click","value": "105"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftStick_DPadNorth","value": "106"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftStick_DPadSouth","value": "107"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftStick_DPadWest","value": "108"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_LeftStick_DPadEast","value": "109"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightStick_Move","value": "110"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightStick_Click","value": "111"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightStick_DPadNorth","value": "112"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightStick_DPadSouth","value": "113"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightStick_DPadWest","value": "114"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_RightStick_DPadEast","value": "115"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_DPad_North","value": "116"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_DPad_South","value": "117"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_DPad_West","value": "118"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_DPad_East","value": "119"} + ,{"name": "k_EControllerActionOrigin_XBox360_A","value": "120"} + ,{"name": "k_EControllerActionOrigin_XBox360_B","value": "121"} + ,{"name": "k_EControllerActionOrigin_XBox360_X","value": "122"} + ,{"name": "k_EControllerActionOrigin_XBox360_Y","value": "123"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftBumper","value": "124"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightBumper","value": "125"} + ,{"name": "k_EControllerActionOrigin_XBox360_Start","value": "126"} + ,{"name": "k_EControllerActionOrigin_XBox360_Back","value": "127"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftTrigger_Pull","value": "128"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftTrigger_Click","value": "129"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightTrigger_Pull","value": "130"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightTrigger_Click","value": "131"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftStick_Move","value": "132"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftStick_Click","value": "133"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftStick_DPadNorth","value": "134"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftStick_DPadSouth","value": "135"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftStick_DPadWest","value": "136"} + ,{"name": "k_EControllerActionOrigin_XBox360_LeftStick_DPadEast","value": "137"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightStick_Move","value": "138"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightStick_Click","value": "139"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightStick_DPadNorth","value": "140"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightStick_DPadSouth","value": "141"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightStick_DPadWest","value": "142"} + ,{"name": "k_EControllerActionOrigin_XBox360_RightStick_DPadEast","value": "143"} + ,{"name": "k_EControllerActionOrigin_XBox360_DPad_North","value": "144"} + ,{"name": "k_EControllerActionOrigin_XBox360_DPad_South","value": "145"} + ,{"name": "k_EControllerActionOrigin_XBox360_DPad_West","value": "146"} + ,{"name": "k_EControllerActionOrigin_XBox360_DPad_East","value": "147"} + ,{"name": "k_EControllerActionOrigin_SteamV2_A","value": "148"} + ,{"name": "k_EControllerActionOrigin_SteamV2_B","value": "149"} + ,{"name": "k_EControllerActionOrigin_SteamV2_X","value": "150"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Y","value": "151"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftBumper","value": "152"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightBumper","value": "153"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftGrip_Lower","value": "154"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftGrip_Upper","value": "155"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightGrip_Lower","value": "156"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightGrip_Upper","value": "157"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftBumper_Pressure","value": "158"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightBumper_Pressure","value": "159"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftGrip_Pressure","value": "160"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightGrip_Pressure","value": "161"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftGrip_Upper_Pressure","value": "162"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightGrip_Upper_Pressure","value": "163"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Start","value": "164"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Back","value": "165"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_Touch","value": "166"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_Swipe","value": "167"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_Click","value": "168"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_Pressure","value": "169"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_DPadNorth","value": "170"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_DPadSouth","value": "171"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_DPadWest","value": "172"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftPad_DPadEast","value": "173"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_Touch","value": "174"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_Swipe","value": "175"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_Click","value": "176"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_Pressure","value": "177"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_DPadNorth","value": "178"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_DPadSouth","value": "179"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_DPadWest","value": "180"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightPad_DPadEast","value": "181"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftTrigger_Pull","value": "182"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftTrigger_Click","value": "183"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightTrigger_Pull","value": "184"} + ,{"name": "k_EControllerActionOrigin_SteamV2_RightTrigger_Click","value": "185"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftStick_Move","value": "186"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftStick_Click","value": "187"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftStick_DPadNorth","value": "188"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftStick_DPadSouth","value": "189"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftStick_DPadWest","value": "190"} + ,{"name": "k_EControllerActionOrigin_SteamV2_LeftStick_DPadEast","value": "191"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Gyro_Move","value": "192"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Gyro_Pitch","value": "193"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Gyro_Yaw","value": "194"} + ,{"name": "k_EControllerActionOrigin_SteamV2_Gyro_Roll","value": "195"} + ,{"name": "k_EControllerActionOrigin_Switch_A","value": "196"} + ,{"name": "k_EControllerActionOrigin_Switch_B","value": "197"} + ,{"name": "k_EControllerActionOrigin_Switch_X","value": "198"} + ,{"name": "k_EControllerActionOrigin_Switch_Y","value": "199"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftBumper","value": "200"} + ,{"name": "k_EControllerActionOrigin_Switch_RightBumper","value": "201"} + ,{"name": "k_EControllerActionOrigin_Switch_Plus","value": "202"} + ,{"name": "k_EControllerActionOrigin_Switch_Minus","value": "203"} + ,{"name": "k_EControllerActionOrigin_Switch_Capture","value": "204"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftTrigger_Pull","value": "205"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftTrigger_Click","value": "206"} + ,{"name": "k_EControllerActionOrigin_Switch_RightTrigger_Pull","value": "207"} + ,{"name": "k_EControllerActionOrigin_Switch_RightTrigger_Click","value": "208"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftStick_Move","value": "209"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftStick_Click","value": "210"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftStick_DPadNorth","value": "211"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftStick_DPadSouth","value": "212"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftStick_DPadWest","value": "213"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftStick_DPadEast","value": "214"} + ,{"name": "k_EControllerActionOrigin_Switch_RightStick_Move","value": "215"} + ,{"name": "k_EControllerActionOrigin_Switch_RightStick_Click","value": "216"} + ,{"name": "k_EControllerActionOrigin_Switch_RightStick_DPadNorth","value": "217"} + ,{"name": "k_EControllerActionOrigin_Switch_RightStick_DPadSouth","value": "218"} + ,{"name": "k_EControllerActionOrigin_Switch_RightStick_DPadWest","value": "219"} + ,{"name": "k_EControllerActionOrigin_Switch_RightStick_DPadEast","value": "220"} + ,{"name": "k_EControllerActionOrigin_Switch_DPad_North","value": "221"} + ,{"name": "k_EControllerActionOrigin_Switch_DPad_South","value": "222"} + ,{"name": "k_EControllerActionOrigin_Switch_DPad_West","value": "223"} + ,{"name": "k_EControllerActionOrigin_Switch_DPad_East","value": "224"} + ,{"name": "k_EControllerActionOrigin_Switch_ProGyro_Move","value": "225"} + ,{"name": "k_EControllerActionOrigin_Switch_ProGyro_Pitch","value": "226"} + ,{"name": "k_EControllerActionOrigin_Switch_ProGyro_Yaw","value": "227"} + ,{"name": "k_EControllerActionOrigin_Switch_ProGyro_Roll","value": "228"} + ,{"name": "k_EControllerActionOrigin_Switch_RightGyro_Move","value": "229"} + ,{"name": "k_EControllerActionOrigin_Switch_RightGyro_Pitch","value": "230"} + ,{"name": "k_EControllerActionOrigin_Switch_RightGyro_Yaw","value": "231"} + ,{"name": "k_EControllerActionOrigin_Switch_RightGyro_Roll","value": "232"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftGyro_Move","value": "233"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftGyro_Pitch","value": "234"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftGyro_Yaw","value": "235"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftGyro_Roll","value": "236"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftGrip_Lower","value": "237"} + ,{"name": "k_EControllerActionOrigin_Switch_LeftGrip_Upper","value": "238"} + ,{"name": "k_EControllerActionOrigin_Switch_RightGrip_Lower","value": "239"} + ,{"name": "k_EControllerActionOrigin_Switch_RightGrip_Upper","value": "240"} + ,{"name": "k_EControllerActionOrigin_PS4_DPad_Move","value": "241"} + ,{"name": "k_EControllerActionOrigin_XBoxOne_DPad_Move","value": "242"} + ,{"name": "k_EControllerActionOrigin_XBox360_DPad_Move","value": "243"} + ,{"name": "k_EControllerActionOrigin_Switch_DPad_Move","value": "244"} + ,{"name": "k_EControllerActionOrigin_Count","value": "245"} + ,{"name": "k_EControllerActionOrigin_MaximumPossibleValue","value": "32767"} +]} +, {"enumname": "ESteamControllerLEDFlag","values": [ + {"name": "k_ESteamControllerLEDFlag_SetColor","value": "0"} + ,{"name": "k_ESteamControllerLEDFlag_RestoreUserDefault","value": "1"} +]} +, {"enumname": "EUGCMatchingUGCType","values": [ + {"name": "k_EUGCMatchingUGCType_Items","value": "0"} + ,{"name": "k_EUGCMatchingUGCType_Items_Mtx","value": "1"} + ,{"name": "k_EUGCMatchingUGCType_Items_ReadyToUse","value": "2"} + ,{"name": "k_EUGCMatchingUGCType_Collections","value": "3"} + ,{"name": "k_EUGCMatchingUGCType_Artwork","value": "4"} + ,{"name": "k_EUGCMatchingUGCType_Videos","value": "5"} + ,{"name": "k_EUGCMatchingUGCType_Screenshots","value": "6"} + ,{"name": "k_EUGCMatchingUGCType_AllGuides","value": "7"} + ,{"name": "k_EUGCMatchingUGCType_WebGuides","value": "8"} + ,{"name": "k_EUGCMatchingUGCType_IntegratedGuides","value": "9"} + ,{"name": "k_EUGCMatchingUGCType_UsableInGame","value": "10"} + ,{"name": "k_EUGCMatchingUGCType_ControllerBindings","value": "11"} + ,{"name": "k_EUGCMatchingUGCType_GameManagedItems","value": "12"} + ,{"name": "k_EUGCMatchingUGCType_All","value": "-1"} +]} +, {"enumname": "EUserUGCList","values": [ + {"name": "k_EUserUGCList_Published","value": "0"} + ,{"name": "k_EUserUGCList_VotedOn","value": "1"} + ,{"name": "k_EUserUGCList_VotedUp","value": "2"} + ,{"name": "k_EUserUGCList_VotedDown","value": "3"} + ,{"name": "k_EUserUGCList_WillVoteLater","value": "4"} + ,{"name": "k_EUserUGCList_Favorited","value": "5"} + ,{"name": "k_EUserUGCList_Subscribed","value": "6"} + ,{"name": "k_EUserUGCList_UsedOrPlayed","value": "7"} + ,{"name": "k_EUserUGCList_Followed","value": "8"} +]} +, {"enumname": "EUserUGCListSortOrder","values": [ + {"name": "k_EUserUGCListSortOrder_CreationOrderDesc","value": "0"} + ,{"name": "k_EUserUGCListSortOrder_CreationOrderAsc","value": "1"} + ,{"name": "k_EUserUGCListSortOrder_TitleAsc","value": "2"} + ,{"name": "k_EUserUGCListSortOrder_LastUpdatedDesc","value": "3"} + ,{"name": "k_EUserUGCListSortOrder_SubscriptionDateDesc","value": "4"} + ,{"name": "k_EUserUGCListSortOrder_VoteScoreDesc","value": "5"} + ,{"name": "k_EUserUGCListSortOrder_ForModeration","value": "6"} +]} +, {"enumname": "EUGCQuery","values": [ + {"name": "k_EUGCQuery_RankedByVote","value": "0"} + ,{"name": "k_EUGCQuery_RankedByPublicationDate","value": "1"} + ,{"name": "k_EUGCQuery_AcceptedForGameRankedByAcceptanceDate","value": "2"} + ,{"name": "k_EUGCQuery_RankedByTrend","value": "3"} + ,{"name": "k_EUGCQuery_FavoritedByFriendsRankedByPublicationDate","value": "4"} + ,{"name": "k_EUGCQuery_CreatedByFriendsRankedByPublicationDate","value": "5"} + ,{"name": "k_EUGCQuery_RankedByNumTimesReported","value": "6"} + ,{"name": "k_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate","value": "7"} + ,{"name": "k_EUGCQuery_NotYetRated","value": "8"} + ,{"name": "k_EUGCQuery_RankedByTotalVotesAsc","value": "9"} + ,{"name": "k_EUGCQuery_RankedByVotesUp","value": "10"} + ,{"name": "k_EUGCQuery_RankedByTextSearch","value": "11"} + ,{"name": "k_EUGCQuery_RankedByTotalUniqueSubscriptions","value": "12"} + ,{"name": "k_EUGCQuery_RankedByPlaytimeTrend","value": "13"} + ,{"name": "k_EUGCQuery_RankedByTotalPlaytime","value": "14"} + ,{"name": "k_EUGCQuery_RankedByAveragePlaytimeTrend","value": "15"} + ,{"name": "k_EUGCQuery_RankedByLifetimeAveragePlaytime","value": "16"} + ,{"name": "k_EUGCQuery_RankedByPlaytimeSessionsTrend","value": "17"} + ,{"name": "k_EUGCQuery_RankedByLifetimePlaytimeSessions","value": "18"} +]} +, {"enumname": "EItemUpdateStatus","values": [ + {"name": "k_EItemUpdateStatusInvalid","value": "0"} + ,{"name": "k_EItemUpdateStatusPreparingConfig","value": "1"} + ,{"name": "k_EItemUpdateStatusPreparingContent","value": "2"} + ,{"name": "k_EItemUpdateStatusUploadingContent","value": "3"} + ,{"name": "k_EItemUpdateStatusUploadingPreviewFile","value": "4"} + ,{"name": "k_EItemUpdateStatusCommittingChanges","value": "5"} +]} +, {"enumname": "EItemState","values": [ + {"name": "k_EItemStateNone","value": "0"} + ,{"name": "k_EItemStateSubscribed","value": "1"} + ,{"name": "k_EItemStateLegacyItem","value": "2"} + ,{"name": "k_EItemStateInstalled","value": "4"} + ,{"name": "k_EItemStateNeedsUpdate","value": "8"} + ,{"name": "k_EItemStateDownloading","value": "16"} + ,{"name": "k_EItemStateDownloadPending","value": "32"} +]} +, {"enumname": "EItemStatistic","values": [ + {"name": "k_EItemStatistic_NumSubscriptions","value": "0"} + ,{"name": "k_EItemStatistic_NumFavorites","value": "1"} + ,{"name": "k_EItemStatistic_NumFollowers","value": "2"} + ,{"name": "k_EItemStatistic_NumUniqueSubscriptions","value": "3"} + ,{"name": "k_EItemStatistic_NumUniqueFavorites","value": "4"} + ,{"name": "k_EItemStatistic_NumUniqueFollowers","value": "5"} + ,{"name": "k_EItemStatistic_NumUniqueWebsiteViews","value": "6"} + ,{"name": "k_EItemStatistic_ReportScore","value": "7"} + ,{"name": "k_EItemStatistic_NumSecondsPlayed","value": "8"} + ,{"name": "k_EItemStatistic_NumPlaytimeSessions","value": "9"} + ,{"name": "k_EItemStatistic_NumComments","value": "10"} + ,{"name": "k_EItemStatistic_NumSecondsPlayedDuringTimePeriod","value": "11"} + ,{"name": "k_EItemStatistic_NumPlaytimeSessionsDuringTimePeriod","value": "12"} +]} +, {"enumname": "EItemPreviewType","values": [ + {"name": "k_EItemPreviewType_Image","value": "0"} + ,{"name": "k_EItemPreviewType_YouTubeVideo","value": "1"} + ,{"name": "k_EItemPreviewType_Sketchfab","value": "2"} + ,{"name": "k_EItemPreviewType_EnvironmentMap_HorizontalCross","value": "3"} + ,{"name": "k_EItemPreviewType_EnvironmentMap_LatLong","value": "4"} + ,{"name": "k_EItemPreviewType_ReservedMax","value": "255"} +]} +, {"enumname": "ISteamHTMLSurface::EHTMLMouseButton","values": [ + {"name": "eHTMLMouseButton_Left","value": "0"} + ,{"name": "eHTMLMouseButton_Right","value": "1"} + ,{"name": "eHTMLMouseButton_Middle","value": "2"} +]} +, {"enumname": "ISteamHTMLSurface::EMouseCursor","values": [ + {"name": "dc_user","value": "0"} + ,{"name": "dc_none","value": "1"} + ,{"name": "dc_arrow","value": "2"} + ,{"name": "dc_ibeam","value": "3"} + ,{"name": "dc_hourglass","value": "4"} + ,{"name": "dc_waitarrow","value": "5"} + ,{"name": "dc_crosshair","value": "6"} + ,{"name": "dc_up","value": "7"} + ,{"name": "dc_sizenw","value": "8"} + ,{"name": "dc_sizese","value": "9"} + ,{"name": "dc_sizene","value": "10"} + ,{"name": "dc_sizesw","value": "11"} + ,{"name": "dc_sizew","value": "12"} + ,{"name": "dc_sizee","value": "13"} + ,{"name": "dc_sizen","value": "14"} + ,{"name": "dc_sizes","value": "15"} + ,{"name": "dc_sizewe","value": "16"} + ,{"name": "dc_sizens","value": "17"} + ,{"name": "dc_sizeall","value": "18"} + ,{"name": "dc_no","value": "19"} + ,{"name": "dc_hand","value": "20"} + ,{"name": "dc_blank","value": "21"} + ,{"name": "dc_middle_pan","value": "22"} + ,{"name": "dc_north_pan","value": "23"} + ,{"name": "dc_north_east_pan","value": "24"} + ,{"name": "dc_east_pan","value": "25"} + ,{"name": "dc_south_east_pan","value": "26"} + ,{"name": "dc_south_pan","value": "27"} + ,{"name": "dc_south_west_pan","value": "28"} + ,{"name": "dc_west_pan","value": "29"} + ,{"name": "dc_north_west_pan","value": "30"} + ,{"name": "dc_alias","value": "31"} + ,{"name": "dc_cell","value": "32"} + ,{"name": "dc_colresize","value": "33"} + ,{"name": "dc_copycur","value": "34"} + ,{"name": "dc_verticaltext","value": "35"} + ,{"name": "dc_rowresize","value": "36"} + ,{"name": "dc_zoomin","value": "37"} + ,{"name": "dc_zoomout","value": "38"} + ,{"name": "dc_help","value": "39"} + ,{"name": "dc_custom","value": "40"} + ,{"name": "dc_last","value": "41"} +]} +, {"enumname": "ISteamHTMLSurface::EHTMLKeyModifiers","values": [ + {"name": "k_eHTMLKeyModifier_None","value": "0"} + ,{"name": "k_eHTMLKeyModifier_AltDown","value": "1"} + ,{"name": "k_eHTMLKeyModifier_CtrlDown","value": "2"} + ,{"name": "k_eHTMLKeyModifier_ShiftDown","value": "4"} +]} +, {"enumname": "ESteamItemFlags","values": [ + {"name": "k_ESteamItemNoTrade","value": "1"} + ,{"name": "k_ESteamItemRemoved","value": "256"} + ,{"name": "k_ESteamItemConsumed","value": "512"} +]} +, {"enumname": "ESteamTVRegionBehavior","values": [ + {"name": "k_ESteamVideoRegionBehaviorInvalid","value": "-1"} + ,{"name": "k_ESteamVideoRegionBehaviorHover","value": "0"} + ,{"name": "k_ESteamVideoRegionBehaviorClickPopup","value": "1"} + ,{"name": "k_ESteamVideoRegionBehaviorClickSurroundingRegion","value": "2"} +]} +, {"enumname": "EParentalFeature","values": [ + {"name": "k_EFeatureInvalid","value": "0"} + ,{"name": "k_EFeatureStore","value": "1"} + ,{"name": "k_EFeatureCommunity","value": "2"} + ,{"name": "k_EFeatureProfile","value": "3"} + ,{"name": "k_EFeatureFriends","value": "4"} + ,{"name": "k_EFeatureNews","value": "5"} + ,{"name": "k_EFeatureTrading","value": "6"} + ,{"name": "k_EFeatureSettings","value": "7"} + ,{"name": "k_EFeatureConsole","value": "8"} + ,{"name": "k_EFeatureBrowser","value": "9"} + ,{"name": "k_EFeatureParentalSetup","value": "10"} + ,{"name": "k_EFeatureLibrary","value": "11"} + ,{"name": "k_EFeatureTest","value": "12"} + ,{"name": "k_EFeatureMax","value": "13"} +]} +, {"enumname": "ESteamDeviceFormFactor","values": [ + {"name": "k_ESteamDeviceFormFactorUnknown","value": "0"} + ,{"name": "k_ESteamDeviceFormFactorPhone","value": "1"} + ,{"name": "k_ESteamDeviceFormFactorTablet","value": "2"} + ,{"name": "k_ESteamDeviceFormFactorComputer","value": "3"} + ,{"name": "k_ESteamDeviceFormFactorTV","value": "4"} +]} +], +"consts":[{ + "constname": "k_iSteamUserCallbacks","consttype": "int", "constval": "100"} +,{ + "constname": "k_iSteamGameServerCallbacks","consttype": "int", "constval": "200"} +,{ + "constname": "k_iSteamFriendsCallbacks","consttype": "int", "constval": "300"} +,{ + "constname": "k_iSteamBillingCallbacks","consttype": "int", "constval": "400"} +,{ + "constname": "k_iSteamMatchmakingCallbacks","consttype": "int", "constval": "500"} +,{ + "constname": "k_iSteamContentServerCallbacks","consttype": "int", "constval": "600"} +,{ + "constname": "k_iSteamUtilsCallbacks","consttype": "int", "constval": "700"} +,{ + "constname": "k_iClientFriendsCallbacks","consttype": "int", "constval": "800"} +,{ + "constname": "k_iClientUserCallbacks","consttype": "int", "constval": "900"} +,{ + "constname": "k_iSteamAppsCallbacks","consttype": "int", "constval": "1000"} +,{ + "constname": "k_iSteamUserStatsCallbacks","consttype": "int", "constval": "1100"} +,{ + "constname": "k_iSteamNetworkingCallbacks","consttype": "int", "constval": "1200"} +,{ + "constname": "k_iSteamNetworkingSocketsCallbacks","consttype": "int", "constval": "1220"} +,{ + "constname": "k_iSteamNetworkingMessagesCallbacks","consttype": "int", "constval": "1250"} +,{ + "constname": "k_iSteamNetworkingUtilsCallbacks","consttype": "int", "constval": "1280"} +,{ + "constname": "k_iClientRemoteStorageCallbacks","consttype": "int", "constval": "1300"} +,{ + "constname": "k_iClientDepotBuilderCallbacks","consttype": "int", "constval": "1400"} +,{ + "constname": "k_iSteamGameServerItemsCallbacks","consttype": "int", "constval": "1500"} +,{ + "constname": "k_iClientUtilsCallbacks","consttype": "int", "constval": "1600"} +,{ + "constname": "k_iSteamGameCoordinatorCallbacks","consttype": "int", "constval": "1700"} +,{ + "constname": "k_iSteamGameServerStatsCallbacks","consttype": "int", "constval": "1800"} +,{ + "constname": "k_iSteam2AsyncCallbacks","consttype": "int", "constval": "1900"} +,{ + "constname": "k_iSteamGameStatsCallbacks","consttype": "int", "constval": "2000"} +,{ + "constname": "k_iClientHTTPCallbacks","consttype": "int", "constval": "2100"} +,{ + "constname": "k_iClientScreenshotsCallbacks","consttype": "int", "constval": "2200"} +,{ + "constname": "k_iSteamScreenshotsCallbacks","consttype": "int", "constval": "2300"} +,{ + "constname": "k_iClientAudioCallbacks","consttype": "int", "constval": "2400"} +,{ + "constname": "k_iClientUnifiedMessagesCallbacks","consttype": "int", "constval": "2500"} +,{ + "constname": "k_iSteamStreamLauncherCallbacks","consttype": "int", "constval": "2600"} +,{ + "constname": "k_iClientControllerCallbacks","consttype": "int", "constval": "2700"} +,{ + "constname": "k_iSteamControllerCallbacks","consttype": "int", "constval": "2800"} +,{ + "constname": "k_iClientParentalSettingsCallbacks","consttype": "int", "constval": "2900"} +,{ + "constname": "k_iClientDeviceAuthCallbacks","consttype": "int", "constval": "3000"} +,{ + "constname": "k_iClientNetworkDeviceManagerCallbacks","consttype": "int", "constval": "3100"} +,{ + "constname": "k_iClientMusicCallbacks","consttype": "int", "constval": "3200"} +,{ + "constname": "k_iClientRemoteClientManagerCallbacks","consttype": "int", "constval": "3300"} +,{ + "constname": "k_iClientUGCCallbacks","consttype": "int", "constval": "3400"} +,{ + "constname": "k_iSteamStreamClientCallbacks","consttype": "int", "constval": "3500"} +,{ + "constname": "k_IClientProductBuilderCallbacks","consttype": "int", "constval": "3600"} +,{ + "constname": "k_iClientShortcutsCallbacks","consttype": "int", "constval": "3700"} +,{ + "constname": "k_iClientRemoteControlManagerCallbacks","consttype": "int", "constval": "3800"} +,{ + "constname": "k_iSteamAppListCallbacks","consttype": "int", "constval": "3900"} +,{ + "constname": "k_iSteamMusicCallbacks","consttype": "int", "constval": "4000"} +,{ + "constname": "k_iSteamMusicRemoteCallbacks","consttype": "int", "constval": "4100"} +,{ + "constname": "k_iClientVRCallbacks","consttype": "int", "constval": "4200"} +,{ + "constname": "k_iClientGameNotificationCallbacks","consttype": "int", "constval": "4300"} +,{ + "constname": "k_iSteamGameNotificationCallbacks","consttype": "int", "constval": "4400"} +,{ + "constname": "k_iSteamHTMLSurfaceCallbacks","consttype": "int", "constval": "4500"} +,{ + "constname": "k_iClientVideoCallbacks","consttype": "int", "constval": "4600"} +,{ + "constname": "k_iClientInventoryCallbacks","consttype": "int", "constval": "4700"} +,{ + "constname": "k_iClientBluetoothManagerCallbacks","consttype": "int", "constval": "4800"} +,{ + "constname": "k_iClientSharedConnectionCallbacks","consttype": "int", "constval": "4900"} +,{ + "constname": "k_ISteamParentalSettingsCallbacks","consttype": "int", "constval": "5000"} +,{ + "constname": "k_iClientShaderCallbacks","consttype": "int", "constval": "5100"} +,{ + "constname": "k_iSteamGameSearchCallbacks","consttype": "int", "constval": "5200"} +,{ + "constname": "k_iSteamPartiesCallbacks","consttype": "int", "constval": "5300"} +,{ + "constname": "k_iClientPartiesCallbacks","consttype": "int", "constval": "5400"} +,{ + "constname": "k_iSteamSTARCallbacks","consttype": "int", "constval": "5500"} +,{ + "constname": "k_iClientSTARCallbacks","consttype": "int", "constval": "5600"} +,{ + "constname": "k_iSteamRemotePlayCallbacks","consttype": "int", "constval": "5700"} +,{ + "constname": "k_cchPersonaNameMax","consttype": "int", "constval": "128"} +,{ + "constname": "k_cwchPersonaNameMax","consttype": "int", "constval": "32"} +,{ + "constname": "k_cchMaxRichPresenceKeys","consttype": "int", "constval": "30"} +,{ + "constname": "k_cchMaxRichPresenceKeyLength","consttype": "int", "constval": "64"} +,{ + "constname": "k_cchMaxRichPresenceValueLength","consttype": "int", "constval": "256"} +,{ + "constname": "k_cchStatNameMax","consttype": "int", "constval": "128"} +,{ + "constname": "k_cchLeaderboardNameMax","consttype": "int", "constval": "128"} +,{ + "constname": "k_cLeaderboardDetailsMax","consttype": "int", "constval": "64"} +,{ + "constname": "k_SteamItemInstanceIDInvalid","consttype": "const SteamItemInstanceID_t", "constval": "18446744073709551615"} +,{ + "constname": "k_SteamInventoryResultInvalid","consttype": "const SteamInventoryResult_t", "constval": "-1"} +,{ + "constname": "k_cchBroadcastGameDataMax","consttype": "int", "constval": "8192"} +], +"structs":[{"struct": "CSteamID","fields": [ +{ "fieldname": "m_steamid", "fieldtype": "union SteamID_t"}]} +,{"struct": "CSteamID::SteamID_t","fields": [ +{ "fieldname": "m_comp", "fieldtype": "struct SteamIDComponent_t"}, +{ "fieldname": "m_unAll64Bits", "fieldtype": "uint64"}]} +,{"struct": "CSteamID::SteamID_t::SteamIDComponent_t","fields": [ +{ "fieldname": "m_unAccountID", "fieldtype": "uint32"}, +{ "fieldname": "m_unAccountInstance", "fieldtype": "unsigned int"}, +{ "fieldname": "m_EAccountType", "fieldtype": "unsigned int"}, +{ "fieldname": "m_EUniverse", "fieldtype": "enum EUniverse"}]} +,{"struct": "CGameID::GameID_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "unsigned int"}, +{ "fieldname": "m_nType", "fieldtype": "unsigned int"}, +{ "fieldname": "m_nModID", "fieldtype": "unsigned int"}]} +,{"struct": "CGameID::(anonymous)","fields": [ +{ "fieldname": "m_ulGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_gameID", "fieldtype": "struct CGameID::GameID_t"}]} +,{"struct": "ValvePackingSentinel_t","fields": [ +{ "fieldname": "m_u32", "fieldtype": "uint32"}, +{ "fieldname": "m_u64", "fieldtype": "uint64"}, +{ "fieldname": "m_u16", "fieldtype": "uint16"}, +{ "fieldname": "m_d", "fieldtype": "double"}]} +,{"struct": "CCallbackBase","fields": [ +{ "fieldname": "m_nCallbackFlags", "fieldtype": "uint8"}, +{ "fieldname": "m_iCallback", "fieldtype": "int"}]} +,{"struct": "CCallResult","fields": [ +{ "fieldname": "m_hAPICall", "fieldtype": "SteamAPICall_t"}, +{ "fieldname": "m_pObj", "fieldtype": "T *"}, +{ "fieldname": "m_Func", "fieldtype": "func_t"}]} +,{"struct": "CCallback","fields": [ +{ "fieldname": "m_pObj", "fieldtype": "T *"}, +{ "fieldname": "m_Func", "fieldtype": "func_t"}]} +,{"struct": "CSteamAPIContext","fields": [ +{ "fieldname": "m_pSteamClient", "fieldtype": "class ISteamClient *"}, +{ "fieldname": "m_pSteamUser", "fieldtype": "class ISteamUser *"}, +{ "fieldname": "m_pSteamFriends", "fieldtype": "class ISteamFriends *"}, +{ "fieldname": "m_pSteamUtils", "fieldtype": "class ISteamUtils *"}, +{ "fieldname": "m_pSteamMatchmaking", "fieldtype": "class ISteamMatchmaking *"}, +{ "fieldname": "m_pSteamGameSearch", "fieldtype": "class ISteamGameSearch *"}, +{ "fieldname": "m_pSteamUserStats", "fieldtype": "class ISteamUserStats *"}, +{ "fieldname": "m_pSteamApps", "fieldtype": "class ISteamApps *"}, +{ "fieldname": "m_pSteamMatchmakingServers", "fieldtype": "class ISteamMatchmakingServers *"}, +{ "fieldname": "m_pSteamNetworking", "fieldtype": "class ISteamNetworking *"}, +{ "fieldname": "m_pSteamRemoteStorage", "fieldtype": "class ISteamRemoteStorage *"}, +{ "fieldname": "m_pSteamScreenshots", "fieldtype": "class ISteamScreenshots *"}, +{ "fieldname": "m_pSteamHTTP", "fieldtype": "class ISteamHTTP *"}, +{ "fieldname": "m_pController", "fieldtype": "class ISteamController *"}, +{ "fieldname": "m_pSteamUGC", "fieldtype": "class ISteamUGC *"}, +{ "fieldname": "m_pSteamAppList", "fieldtype": "class ISteamAppList *"}, +{ "fieldname": "m_pSteamMusic", "fieldtype": "class ISteamMusic *"}, +{ "fieldname": "m_pSteamMusicRemote", "fieldtype": "class ISteamMusicRemote *"}, +{ "fieldname": "m_pSteamHTMLSurface", "fieldtype": "class ISteamHTMLSurface *"}, +{ "fieldname": "m_pSteamInventory", "fieldtype": "class ISteamInventory *"}, +{ "fieldname": "m_pSteamVideo", "fieldtype": "class ISteamVideo *"}, +{ "fieldname": "m_pSteamTV", "fieldtype": "class ISteamTV *"}, +{ "fieldname": "m_pSteamParentalSettings", "fieldtype": "class ISteamParentalSettings *"}, +{ "fieldname": "m_pSteamInput", "fieldtype": "class ISteamInput *"}]} +,{"struct": "CSteamGameServerAPIContext","fields": [ +{ "fieldname": "m_pSteamClient", "fieldtype": "class ISteamClient *"}, +{ "fieldname": "m_pSteamGameServer", "fieldtype": "class ISteamGameServer *"}, +{ "fieldname": "m_pSteamGameServerUtils", "fieldtype": "class ISteamUtils *"}, +{ "fieldname": "m_pSteamGameServerNetworking", "fieldtype": "class ISteamNetworking *"}, +{ "fieldname": "m_pSteamGameServerStats", "fieldtype": "class ISteamGameServerStats *"}, +{ "fieldname": "m_pSteamHTTP", "fieldtype": "class ISteamHTTP *"}, +{ "fieldname": "m_pSteamInventory", "fieldtype": "class ISteamInventory *"}, +{ "fieldname": "m_pSteamUGC", "fieldtype": "class ISteamUGC *"}, +{ "fieldname": "m_pSteamApps", "fieldtype": "class ISteamApps *"}]} +,{"struct": "CallbackMsg_t","fields": [ +{ "fieldname": "m_hSteamUser", "fieldtype": "HSteamUser"}, +{ "fieldname": "m_iCallback", "fieldtype": "int"}, +{ "fieldname": "m_pubParam", "fieldtype": "uint8 *"}, +{ "fieldname": "m_cubParam", "fieldtype": "int"}]} +,{"struct": "SteamServerConnectFailure_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_bStillRetrying", "fieldtype": "_Bool"}]} +,{"struct": "SteamServersDisconnected_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "ClientGameServerDeny_t","fields": [ +{ "fieldname": "m_uAppID", "fieldtype": "uint32"}, +{ "fieldname": "m_unGameServerIP", "fieldtype": "uint32"}, +{ "fieldname": "m_usGameServerPort", "fieldtype": "uint16"}, +{ "fieldname": "m_bSecure", "fieldtype": "uint16"}, +{ "fieldname": "m_uReason", "fieldtype": "uint32"}]} +,{"struct": "ValidateAuthTicketResponse_t","fields": [ +{ "fieldname": "m_SteamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_eAuthSessionResponse", "fieldtype": "enum EAuthSessionResponse"}, +{ "fieldname": "m_OwnerSteamID", "fieldtype": "class CSteamID"}]} +,{"struct": "MicroTxnAuthorizationResponse_t","fields": [ +{ "fieldname": "m_unAppID", "fieldtype": "uint32"}, +{ "fieldname": "m_ulOrderID", "fieldtype": "uint64"}, +{ "fieldname": "m_bAuthorized", "fieldtype": "uint8"}]} +,{"struct": "EncryptedAppTicketResponse_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "GetAuthSessionTicketResponse_t","fields": [ +{ "fieldname": "m_hAuthTicket", "fieldtype": "HAuthTicket"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "GameWebCallback_t","fields": [ +{ "fieldname": "m_szURL", "fieldtype": "char [256]"}]} +,{"struct": "StoreAuthURLResponse_t","fields": [ +{ "fieldname": "m_szURL", "fieldtype": "char [512]"}]} +,{"struct": "MarketEligibilityResponse_t","fields": [ +{ "fieldname": "m_bAllowed", "fieldtype": "_Bool"}, +{ "fieldname": "m_eNotAllowedReason", "fieldtype": "enum EMarketNotAllowedReasonFlags"}, +{ "fieldname": "m_rtAllowedAtTime", "fieldtype": "RTime32"}, +{ "fieldname": "m_cdaySteamGuardRequiredDays", "fieldtype": "int"}, +{ "fieldname": "m_cdayNewDeviceCooldown", "fieldtype": "int"}]} +,{"struct": "DurationControl_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_appid", "fieldtype": "AppId_t"}, +{ "fieldname": "m_bApplicable", "fieldtype": "_Bool"}, +{ "fieldname": "m_csecsLast5h", "fieldtype": "int32"}, +{ "fieldname": "m_progress", "fieldtype": "enum EDurationControlProgress"}, +{ "fieldname": "m_notification", "fieldtype": "enum EDurationControlNotification"}]} +,{"struct": "FriendGameInfo_t","fields": [ +{ "fieldname": "m_gameID", "fieldtype": "class CGameID"}, +{ "fieldname": "m_unGameIP", "fieldtype": "uint32"}, +{ "fieldname": "m_usGamePort", "fieldtype": "uint16"}, +{ "fieldname": "m_usQueryPort", "fieldtype": "uint16"}, +{ "fieldname": "m_steamIDLobby", "fieldtype": "class CSteamID"}]} +,{"struct": "FriendSessionStateInfo_t","fields": [ +{ "fieldname": "m_uiOnlineSessionInstances", "fieldtype": "uint32"}, +{ "fieldname": "m_uiPublishedToFriendsSessionInstance", "fieldtype": "uint8"}]} +,{"struct": "PersonaStateChange_t","fields": [ +{ "fieldname": "m_ulSteamID", "fieldtype": "uint64"}, +{ "fieldname": "m_nChangeFlags", "fieldtype": "int"}]} +,{"struct": "GameOverlayActivated_t","fields": [ +{ "fieldname": "m_bActive", "fieldtype": "uint8"}]} +,{"struct": "GameServerChangeRequested_t","fields": [ +{ "fieldname": "m_rgchServer", "fieldtype": "char [64]"}, +{ "fieldname": "m_rgchPassword", "fieldtype": "char [64]"}]} +,{"struct": "GameLobbyJoinRequested_t","fields": [ +{ "fieldname": "m_steamIDLobby", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_steamIDFriend", "fieldtype": "class CSteamID"}]} +,{"struct": "AvatarImageLoaded_t","fields": [ +{ "fieldname": "m_steamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_iImage", "fieldtype": "int"}, +{ "fieldname": "m_iWide", "fieldtype": "int"}, +{ "fieldname": "m_iTall", "fieldtype": "int"}]} +,{"struct": "ClanOfficerListResponse_t","fields": [ +{ "fieldname": "m_steamIDClan", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_cOfficers", "fieldtype": "int"}, +{ "fieldname": "m_bSuccess", "fieldtype": "uint8"}]} +,{"struct": "FriendRichPresenceUpdate_t","fields": [ +{ "fieldname": "m_steamIDFriend", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "GameRichPresenceJoinRequested_t","fields": [ +{ "fieldname": "m_steamIDFriend", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_rgchConnect", "fieldtype": "char [256]"}]} +,{"struct": "GameConnectedClanChatMsg_t","fields": [ +{ "fieldname": "m_steamIDClanChat", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_iMessageID", "fieldtype": "int"}]} +,{"struct": "GameConnectedChatJoin_t","fields": [ +{ "fieldname": "m_steamIDClanChat", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}]} +,{"struct": "GameConnectedChatLeave_t","fields": [ +{ "fieldname": "m_steamIDClanChat", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_bKicked", "fieldtype": "_Bool"}, +{ "fieldname": "m_bDropped", "fieldtype": "_Bool"}]} +,{"struct": "DownloadClanActivityCountsResult_t","fields": [ +{ "fieldname": "m_bSuccess", "fieldtype": "_Bool"}]} +,{"struct": "JoinClanChatRoomCompletionResult_t","fields": [ +{ "fieldname": "m_steamIDClanChat", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_eChatRoomEnterResponse", "fieldtype": "enum EChatRoomEnterResponse"}]} +,{"struct": "GameConnectedFriendChatMsg_t","fields": [ +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_iMessageID", "fieldtype": "int"}]} +,{"struct": "FriendsGetFollowerCount_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_steamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_nCount", "fieldtype": "int"}]} +,{"struct": "FriendsIsFollowing_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_steamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_bIsFollowing", "fieldtype": "_Bool"}]} +,{"struct": "FriendsEnumerateFollowingList_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_rgSteamID", "fieldtype": "class CSteamID [50]"}, +{ "fieldname": "m_nResultsReturned", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalResultCount", "fieldtype": "int32"}]} +,{"struct": "SetPersonaNameResponse_t","fields": [ +{ "fieldname": "m_bSuccess", "fieldtype": "_Bool"}, +{ "fieldname": "m_bLocalSuccess", "fieldtype": "_Bool"}, +{ "fieldname": "m_result", "fieldtype": "enum EResult"}]} +,{"struct": "LowBatteryPower_t","fields": [ +{ "fieldname": "m_nMinutesBatteryLeft", "fieldtype": "uint8"}]} +,{"struct": "SteamAPICallCompleted_t","fields": [ +{ "fieldname": "m_hAsyncCall", "fieldtype": "SteamAPICall_t"}, +{ "fieldname": "m_iCallback", "fieldtype": "int"}, +{ "fieldname": "m_cubParam", "fieldtype": "uint32"}]} +,{"struct": "CheckFileSignature_t","fields": [ +{ "fieldname": "m_eCheckFileSignature", "fieldtype": "enum ECheckFileSignature"}]} +,{"struct": "GamepadTextInputDismissed_t","fields": [ +{ "fieldname": "m_bSubmitted", "fieldtype": "_Bool"}, +{ "fieldname": "m_unSubmittedText", "fieldtype": "uint32"}]} +,{"struct": "MatchMakingKeyValuePair_t","fields": [ +{ "fieldname": "m_szKey", "fieldtype": "char [256]"}, +{ "fieldname": "m_szValue", "fieldtype": "char [256]"}]} +,{"struct": "servernetadr_t","fields": [ +{ "fieldname": "m_usConnectionPort", "fieldtype": "uint16"}, +{ "fieldname": "m_usQueryPort", "fieldtype": "uint16"}, +{ "fieldname": "m_unIP", "fieldtype": "uint32"}]} +,{"struct": "gameserveritem_t","fields": [ +{ "fieldname": "m_NetAdr", "fieldtype": "class servernetadr_t"}, +{ "fieldname": "m_nPing", "fieldtype": "int"}, +{ "fieldname": "m_bHadSuccessfulResponse", "fieldtype": "_Bool"}, +{ "fieldname": "m_bDoNotRefresh", "fieldtype": "_Bool"}, +{ "fieldname": "m_szGameDir", "fieldtype": "char [32]"}, +{ "fieldname": "m_szMap", "fieldtype": "char [32]"}, +{ "fieldname": "m_szGameDescription", "fieldtype": "char [64]"}, +{ "fieldname": "m_nAppID", "fieldtype": "uint32"}, +{ "fieldname": "m_nPlayers", "fieldtype": "int"}, +{ "fieldname": "m_nMaxPlayers", "fieldtype": "int"}, +{ "fieldname": "m_nBotPlayers", "fieldtype": "int"}, +{ "fieldname": "m_bPassword", "fieldtype": "_Bool"}, +{ "fieldname": "m_bSecure", "fieldtype": "_Bool"}, +{ "fieldname": "m_ulTimeLastPlayed", "fieldtype": "uint32"}, +{ "fieldname": "m_nServerVersion", "fieldtype": "int"}, +{ "fieldname": "m_szServerName", "fieldtype": "char [64]"}, +{ "fieldname": "m_szGameTags", "fieldtype": "char [128]"}, +{ "fieldname": "m_steamID", "fieldtype": "class CSteamID"}]} +,{"struct": "SteamPartyBeaconLocation_t","fields": [ +{ "fieldname": "m_eType", "fieldtype": "enum ESteamPartyBeaconLocationType"}, +{ "fieldname": "m_ulLocationID", "fieldtype": "uint64"}]} +,{"struct": "FavoritesListChanged_t","fields": [ +{ "fieldname": "m_nIP", "fieldtype": "uint32"}, +{ "fieldname": "m_nQueryPort", "fieldtype": "uint32"}, +{ "fieldname": "m_nConnPort", "fieldtype": "uint32"}, +{ "fieldname": "m_nAppID", "fieldtype": "uint32"}, +{ "fieldname": "m_nFlags", "fieldtype": "uint32"}, +{ "fieldname": "m_bAdd", "fieldtype": "_Bool"}, +{ "fieldname": "m_unAccountId", "fieldtype": "AccountID_t"}]} +,{"struct": "LobbyInvite_t","fields": [ +{ "fieldname": "m_ulSteamIDUser", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_ulGameID", "fieldtype": "uint64"}]} +,{"struct": "LobbyEnter_t","fields": [ +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_rgfChatPermissions", "fieldtype": "uint32"}, +{ "fieldname": "m_bLocked", "fieldtype": "_Bool"}, +{ "fieldname": "m_EChatRoomEnterResponse", "fieldtype": "uint32"}]} +,{"struct": "LobbyDataUpdate_t","fields": [ +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDMember", "fieldtype": "uint64"}, +{ "fieldname": "m_bSuccess", "fieldtype": "uint8"}]} +,{"struct": "LobbyChatUpdate_t","fields": [ +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDUserChanged", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDMakingChange", "fieldtype": "uint64"}, +{ "fieldname": "m_rgfChatMemberStateChange", "fieldtype": "uint32"}]} +,{"struct": "LobbyChatMsg_t","fields": [ +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDUser", "fieldtype": "uint64"}, +{ "fieldname": "m_eChatEntryType", "fieldtype": "uint8"}, +{ "fieldname": "m_iChatID", "fieldtype": "uint32"}]} +,{"struct": "LobbyGameCreated_t","fields": [ +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDGameServer", "fieldtype": "uint64"}, +{ "fieldname": "m_unIP", "fieldtype": "uint32"}, +{ "fieldname": "m_usPort", "fieldtype": "uint16"}]} +,{"struct": "LobbyMatchList_t","fields": [ +{ "fieldname": "m_nLobbiesMatching", "fieldtype": "uint32"}]} +,{"struct": "LobbyKicked_t","fields": [ +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}, +{ "fieldname": "m_ulSteamIDAdmin", "fieldtype": "uint64"}, +{ "fieldname": "m_bKickedDueToDisconnect", "fieldtype": "uint8"}]} +,{"struct": "LobbyCreated_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ulSteamIDLobby", "fieldtype": "uint64"}]} +,{"struct": "PSNGameBootInviteResult_t","fields": [ +{ "fieldname": "m_bGameBootInviteExists", "fieldtype": "_Bool"}, +{ "fieldname": "m_steamIDLobby", "fieldtype": "class CSteamID"}]} +,{"struct": "FavoritesListAccountsUpdated_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "SearchForGameProgressCallback_t","fields": [ +{ "fieldname": "m_ullSearchID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_lobbyID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_steamIDEndedSearch", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_nSecondsRemainingEstimate", "fieldtype": "int32"}, +{ "fieldname": "m_cPlayersSearching", "fieldtype": "int32"}]} +,{"struct": "SearchForGameResultCallback_t","fields": [ +{ "fieldname": "m_ullSearchID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nCountPlayersInGame", "fieldtype": "int32"}, +{ "fieldname": "m_nCountAcceptedGame", "fieldtype": "int32"}, +{ "fieldname": "m_steamIDHost", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_bFinalCallback", "fieldtype": "_Bool"}]} +,{"struct": "RequestPlayersForGameProgressCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ullSearchID", "fieldtype": "uint64"}]} +,{"struct": "RequestPlayersForGameResultCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ullSearchID", "fieldtype": "uint64"}, +{ "fieldname": "m_SteamIDPlayerFound", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_SteamIDLobby", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_ePlayerAcceptState", "fieldtype": "enum RequestPlayersForGameResultCallback_t::PlayerAcceptState_t"}, +{ "fieldname": "m_nPlayerIndex", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalPlayersFound", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalPlayersAcceptedGame", "fieldtype": "int32"}, +{ "fieldname": "m_nSuggestedTeamIndex", "fieldtype": "int32"}, +{ "fieldname": "m_ullUniqueGameID", "fieldtype": "uint64"}]} +,{"struct": "RequestPlayersForGameFinalResultCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ullSearchID", "fieldtype": "uint64"}, +{ "fieldname": "m_ullUniqueGameID", "fieldtype": "uint64"}]} +,{"struct": "SubmitPlayerResultResultCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "ullUniqueGameID", "fieldtype": "uint64"}, +{ "fieldname": "steamIDPlayer", "fieldtype": "class CSteamID"}]} +,{"struct": "EndGameResultCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "ullUniqueGameID", "fieldtype": "uint64"}]} +,{"struct": "JoinPartyCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ulBeaconID", "fieldtype": "PartyBeaconID_t"}, +{ "fieldname": "m_SteamIDBeaconOwner", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_rgchConnectString", "fieldtype": "char [256]"}]} +,{"struct": "CreateBeaconCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ulBeaconID", "fieldtype": "PartyBeaconID_t"}]} +,{"struct": "ReservationNotificationCallback_t","fields": [ +{ "fieldname": "m_ulBeaconID", "fieldtype": "PartyBeaconID_t"}, +{ "fieldname": "m_steamIDJoiner", "fieldtype": "class CSteamID"}]} +,{"struct": "ChangeNumOpenSlotsCallback_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "SteamParamStringArray_t","fields": [ +{ "fieldname": "m_ppStrings", "fieldtype": "const char **"}, +{ "fieldname": "m_nNumStrings", "fieldtype": "int32"}]} +,{"struct": "RemoteStorageAppSyncedClient_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unNumDownloads", "fieldtype": "int"}]} +,{"struct": "RemoteStorageAppSyncedServer_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unNumUploads", "fieldtype": "int"}]} +,{"struct": "RemoteStorageAppSyncProgress_t","fields": [ +{ "fieldname": "m_rgchCurrentFile", "fieldtype": "char [260]"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_uBytesTransferredThisChunk", "fieldtype": "uint32"}, +{ "fieldname": "m_dAppPercentComplete", "fieldtype": "double"}, +{ "fieldname": "m_bUploading", "fieldtype": "_Bool"}]} +,{"struct": "RemoteStorageAppSyncStatusCheck_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "RemoteStorageFileShareResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_hFile", "fieldtype": "UGCHandle_t"}, +{ "fieldname": "m_rgchFilename", "fieldtype": "char [260]"}]} +,{"struct": "RemoteStoragePublishFileResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype": "_Bool"}]} +,{"struct": "RemoteStorageDeletePublishedFileResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "RemoteStorageEnumerateUserPublishedFilesResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nResultsReturned", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalResultCount", "fieldtype": "int32"}, +{ "fieldname": "m_rgPublishedFileId", "fieldtype": "PublishedFileId_t [50]"}]} +,{"struct": "RemoteStorageSubscribePublishedFileResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "RemoteStorageEnumerateUserSubscribedFilesResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nResultsReturned", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalResultCount", "fieldtype": "int32"}, +{ "fieldname": "m_rgPublishedFileId", "fieldtype": "PublishedFileId_t [50]"}, +{ "fieldname": "m_rgRTimeSubscribed", "fieldtype": "uint32 [50]"}]} +,{"struct": "RemoteStorageUnsubscribePublishedFileResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "RemoteStorageUpdatePublishedFileResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype": "_Bool"}]} +,{"struct": "RemoteStorageDownloadUGCResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_hFile", "fieldtype": "UGCHandle_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_nSizeInBytes", "fieldtype": "int32"}, +{ "fieldname": "m_pchFileName", "fieldtype": "char [260]"}, +{ "fieldname": "m_ulSteamIDOwner", "fieldtype": "uint64"}]} +,{"struct": "RemoteStorageGetPublishedFileDetailsResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nCreatorAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_nConsumerAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_rgchTitle", "fieldtype": "char [129]"}, +{ "fieldname": "m_rgchDescription", "fieldtype": "char [8000]"}, +{ "fieldname": "m_hFile", "fieldtype": "UGCHandle_t"}, +{ "fieldname": "m_hPreviewFile", "fieldtype": "UGCHandle_t"}, +{ "fieldname": "m_ulSteamIDOwner", "fieldtype": "uint64"}, +{ "fieldname": "m_rtimeCreated", "fieldtype": "uint32"}, +{ "fieldname": "m_rtimeUpdated", "fieldtype": "uint32"}, +{ "fieldname": "m_eVisibility", "fieldtype": "enum ERemoteStoragePublishedFileVisibility"}, +{ "fieldname": "m_bBanned", "fieldtype": "_Bool"}, +{ "fieldname": "m_rgchTags", "fieldtype": "char [1025]"}, +{ "fieldname": "m_bTagsTruncated", "fieldtype": "_Bool"}, +{ "fieldname": "m_pchFileName", "fieldtype": "char [260]"}, +{ "fieldname": "m_nFileSize", "fieldtype": "int32"}, +{ "fieldname": "m_nPreviewFileSize", "fieldtype": "int32"}, +{ "fieldname": "m_rgchURL", "fieldtype": "char [256]"}, +{ "fieldname": "m_eFileType", "fieldtype": "enum EWorkshopFileType"}, +{ "fieldname": "m_bAcceptedForUse", "fieldtype": "_Bool"}]} +,{"struct": "RemoteStorageEnumerateWorkshopFilesResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nResultsReturned", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalResultCount", "fieldtype": "int32"}, +{ "fieldname": "m_rgPublishedFileId", "fieldtype": "PublishedFileId_t [50]"}, +{ "fieldname": "m_rgScore", "fieldtype": "float [50]"}, +{ "fieldname": "m_nAppId", "fieldtype": "AppId_t"}, +{ "fieldname": "m_unStartIndex", "fieldtype": "uint32"}]} +,{"struct": "RemoteStorageGetPublishedItemVoteDetailsResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nVotesFor", "fieldtype": "int32"}, +{ "fieldname": "m_nVotesAgainst", "fieldtype": "int32"}, +{ "fieldname": "m_nReports", "fieldtype": "int32"}, +{ "fieldname": "m_fScore", "fieldtype": "float"}]} +,{"struct": "RemoteStoragePublishedFileSubscribed_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "RemoteStoragePublishedFileUnsubscribed_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "RemoteStoragePublishedFileDeleted_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "RemoteStorageUpdateUserPublishedItemVoteResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "RemoteStorageUserVoteDetails_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eVote", "fieldtype": "enum EWorkshopVote"}]} +,{"struct": "RemoteStorageEnumerateUserSharedWorkshopFilesResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nResultsReturned", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalResultCount", "fieldtype": "int32"}, +{ "fieldname": "m_rgPublishedFileId", "fieldtype": "PublishedFileId_t [50]"}]} +,{"struct": "RemoteStorageSetUserPublishedFileActionResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eAction", "fieldtype": "enum EWorkshopFileAction"}]} +,{"struct": "RemoteStorageEnumeratePublishedFilesByUserActionResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_eAction", "fieldtype": "enum EWorkshopFileAction"}, +{ "fieldname": "m_nResultsReturned", "fieldtype": "int32"}, +{ "fieldname": "m_nTotalResultCount", "fieldtype": "int32"}, +{ "fieldname": "m_rgPublishedFileId", "fieldtype": "PublishedFileId_t [50]"}, +{ "fieldname": "m_rgRTimeUpdated", "fieldtype": "uint32 [50]"}]} +,{"struct": "RemoteStoragePublishFileProgress_t","fields": [ +{ "fieldname": "m_dPercentFile", "fieldtype": "double"}, +{ "fieldname": "m_bPreview", "fieldtype": "_Bool"}]} +,{"struct": "RemoteStoragePublishedFileUpdated_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_ulUnused", "fieldtype": "uint64"}]} +,{"struct": "RemoteStorageFileWriteAsyncComplete_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "RemoteStorageFileReadAsyncComplete_t","fields": [ +{ "fieldname": "m_hFileReadAsync", "fieldtype": "SteamAPICall_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nOffset", "fieldtype": "uint32"}, +{ "fieldname": "m_cubRead", "fieldtype": "uint32"}]} +,{"struct": "LeaderboardEntry_t","fields": [ +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_nGlobalRank", "fieldtype": "int32"}, +{ "fieldname": "m_nScore", "fieldtype": "int32"}, +{ "fieldname": "m_cDetails", "fieldtype": "int32"}, +{ "fieldname": "m_hUGC", "fieldtype": "UGCHandle_t"}]} +,{"struct": "UserStatsReceived_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}]} +,{"struct": "UserStatsStored_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "UserAchievementStored_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_bGroupAchievement", "fieldtype": "_Bool"}, +{ "fieldname": "m_rgchAchievementName", "fieldtype": "char [128]"}, +{ "fieldname": "m_nCurProgress", "fieldtype": "uint32"}, +{ "fieldname": "m_nMaxProgress", "fieldtype": "uint32"}]} +,{"struct": "LeaderboardFindResult_t","fields": [ +{ "fieldname": "m_hSteamLeaderboard", "fieldtype": "SteamLeaderboard_t"}, +{ "fieldname": "m_bLeaderboardFound", "fieldtype": "uint8"}]} +,{"struct": "LeaderboardScoresDownloaded_t","fields": [ +{ "fieldname": "m_hSteamLeaderboard", "fieldtype": "SteamLeaderboard_t"}, +{ "fieldname": "m_hSteamLeaderboardEntries", "fieldtype": "SteamLeaderboardEntries_t"}, +{ "fieldname": "m_cEntryCount", "fieldtype": "int"}]} +,{"struct": "LeaderboardScoreUploaded_t","fields": [ +{ "fieldname": "m_bSuccess", "fieldtype": "uint8"}, +{ "fieldname": "m_hSteamLeaderboard", "fieldtype": "SteamLeaderboard_t"}, +{ "fieldname": "m_nScore", "fieldtype": "int32"}, +{ "fieldname": "m_bScoreChanged", "fieldtype": "uint8"}, +{ "fieldname": "m_nGlobalRankNew", "fieldtype": "int"}, +{ "fieldname": "m_nGlobalRankPrevious", "fieldtype": "int"}]} +,{"struct": "NumberOfCurrentPlayers_t","fields": [ +{ "fieldname": "m_bSuccess", "fieldtype": "uint8"}, +{ "fieldname": "m_cPlayers", "fieldtype": "int32"}]} +,{"struct": "UserStatsUnloaded_t","fields": [ +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}]} +,{"struct": "UserAchievementIconFetched_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "class CGameID"}, +{ "fieldname": "m_rgchAchievementName", "fieldtype": "char [128]"}, +{ "fieldname": "m_bAchieved", "fieldtype": "_Bool"}, +{ "fieldname": "m_nIconHandle", "fieldtype": "int"}]} +,{"struct": "GlobalAchievementPercentagesReady_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "LeaderboardUGCSet_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_hSteamLeaderboard", "fieldtype": "SteamLeaderboard_t"}]} +,{"struct": "PS3TrophiesInstalled_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ulRequiredDiskSpace", "fieldtype": "uint64"}]} +,{"struct": "GlobalStatsReceived_t","fields": [ +{ "fieldname": "m_nGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "DlcInstalled_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "RegisterActivationCodeResponse_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum ERegisterActivationCodeResult"}, +{ "fieldname": "m_unPackageRegistered", "fieldtype": "uint32"}]} +,{"struct": "AppProofOfPurchaseKeyResponse_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nAppID", "fieldtype": "uint32"}, +{ "fieldname": "m_cchKeyLength", "fieldtype": "uint32"}, +{ "fieldname": "m_rgchKey", "fieldtype": "char [240]"}]} +,{"struct": "FileDetailsResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ulFileSize", "fieldtype": "uint64"}, +{ "fieldname": "m_FileSHA", "fieldtype": "uint8 [20]"}, +{ "fieldname": "m_unFlags", "fieldtype": "uint32"}]} +,{"struct": "P2PSessionState_t","fields": [ +{ "fieldname": "m_bConnectionActive", "fieldtype": "uint8"}, +{ "fieldname": "m_bConnecting", "fieldtype": "uint8"}, +{ "fieldname": "m_eP2PSessionError", "fieldtype": "uint8"}, +{ "fieldname": "m_bUsingRelay", "fieldtype": "uint8"}, +{ "fieldname": "m_nBytesQueuedForSend", "fieldtype": "int32"}, +{ "fieldname": "m_nPacketsQueuedForSend", "fieldtype": "int32"}, +{ "fieldname": "m_nRemoteIP", "fieldtype": "uint32"}, +{ "fieldname": "m_nRemotePort", "fieldtype": "uint16"}]} +,{"struct": "P2PSessionRequest_t","fields": [ +{ "fieldname": "m_steamIDRemote", "fieldtype": "class CSteamID"}]} +,{"struct": "P2PSessionConnectFail_t","fields": [ +{ "fieldname": "m_steamIDRemote", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_eP2PSessionError", "fieldtype": "uint8"}]} +,{"struct": "SocketStatusCallback_t","fields": [ +{ "fieldname": "m_hSocket", "fieldtype": "SNetSocket_t"}, +{ "fieldname": "m_hListenSocket", "fieldtype": "SNetListenSocket_t"}, +{ "fieldname": "m_steamIDRemote", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_eSNetSocketState", "fieldtype": "int"}]} +,{"struct": "ScreenshotReady_t","fields": [ +{ "fieldname": "m_hLocal", "fieldtype": "ScreenshotHandle"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "VolumeHasChanged_t","fields": [ +{ "fieldname": "m_flNewVolume", "fieldtype": "float"}]} +,{"struct": "MusicPlayerWantsShuffled_t","fields": [ +{ "fieldname": "m_bShuffled", "fieldtype": "_Bool"}]} +,{"struct": "MusicPlayerWantsLooped_t","fields": [ +{ "fieldname": "m_bLooped", "fieldtype": "_Bool"}]} +,{"struct": "MusicPlayerWantsVolume_t","fields": [ +{ "fieldname": "m_flNewVolume", "fieldtype": "float"}]} +,{"struct": "MusicPlayerSelectsQueueEntry_t","fields": [ +{ "fieldname": "nID", "fieldtype": "int"}]} +,{"struct": "MusicPlayerSelectsPlaylistEntry_t","fields": [ +{ "fieldname": "nID", "fieldtype": "int"}]} +,{"struct": "MusicPlayerWantsPlayingRepeatStatus_t","fields": [ +{ "fieldname": "m_nPlayingRepeatStatus", "fieldtype": "int"}]} +,{"struct": "HTTPRequestCompleted_t","fields": [ +{ "fieldname": "m_hRequest", "fieldtype": "HTTPRequestHandle"}, +{ "fieldname": "m_ulContextValue", "fieldtype": "uint64"}, +{ "fieldname": "m_bRequestSuccessful", "fieldtype": "_Bool"}, +{ "fieldname": "m_eStatusCode", "fieldtype": "enum EHTTPStatusCode"}, +{ "fieldname": "m_unBodySize", "fieldtype": "uint32"}]} +,{"struct": "HTTPRequestHeadersReceived_t","fields": [ +{ "fieldname": "m_hRequest", "fieldtype": "HTTPRequestHandle"}, +{ "fieldname": "m_ulContextValue", "fieldtype": "uint64"}]} +,{"struct": "HTTPRequestDataReceived_t","fields": [ +{ "fieldname": "m_hRequest", "fieldtype": "HTTPRequestHandle"}, +{ "fieldname": "m_ulContextValue", "fieldtype": "uint64"}, +{ "fieldname": "m_cOffset", "fieldtype": "uint32"}, +{ "fieldname": "m_cBytesReceived", "fieldtype": "uint32"}]} +,{"struct": "SteamUGCDetails_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_eFileType", "fieldtype": "enum EWorkshopFileType"}, +{ "fieldname": "m_nCreatorAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_nConsumerAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_rgchTitle", "fieldtype": "char [129]"}, +{ "fieldname": "m_rgchDescription", "fieldtype": "char [8000]"}, +{ "fieldname": "m_ulSteamIDOwner", "fieldtype": "uint64"}, +{ "fieldname": "m_rtimeCreated", "fieldtype": "uint32"}, +{ "fieldname": "m_rtimeUpdated", "fieldtype": "uint32"}, +{ "fieldname": "m_rtimeAddedToUserList", "fieldtype": "uint32"}, +{ "fieldname": "m_eVisibility", "fieldtype": "enum ERemoteStoragePublishedFileVisibility"}, +{ "fieldname": "m_bBanned", "fieldtype": "_Bool"}, +{ "fieldname": "m_bAcceptedForUse", "fieldtype": "_Bool"}, +{ "fieldname": "m_bTagsTruncated", "fieldtype": "_Bool"}, +{ "fieldname": "m_rgchTags", "fieldtype": "char [1025]"}, +{ "fieldname": "m_hFile", "fieldtype": "UGCHandle_t"}, +{ "fieldname": "m_hPreviewFile", "fieldtype": "UGCHandle_t"}, +{ "fieldname": "m_pchFileName", "fieldtype": "char [260]"}, +{ "fieldname": "m_nFileSize", "fieldtype": "int32"}, +{ "fieldname": "m_nPreviewFileSize", "fieldtype": "int32"}, +{ "fieldname": "m_rgchURL", "fieldtype": "char [256]"}, +{ "fieldname": "m_unVotesUp", "fieldtype": "uint32"}, +{ "fieldname": "m_unVotesDown", "fieldtype": "uint32"}, +{ "fieldname": "m_flScore", "fieldtype": "float"}, +{ "fieldname": "m_unNumChildren", "fieldtype": "uint32"}]} +,{"struct": "SteamUGCQueryCompleted_t","fields": [ +{ "fieldname": "m_handle", "fieldtype": "UGCQueryHandle_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unNumResultsReturned", "fieldtype": "uint32"}, +{ "fieldname": "m_unTotalMatchingResults", "fieldtype": "uint32"}, +{ "fieldname": "m_bCachedData", "fieldtype": "_Bool"}, +{ "fieldname": "m_rgchNextCursor", "fieldtype": "char [256]"}]} +,{"struct": "SteamUGCRequestUGCDetailsResult_t","fields": [ +{ "fieldname": "m_details", "fieldtype": "struct SteamUGCDetails_t"}, +{ "fieldname": "m_bCachedData", "fieldtype": "_Bool"}]} +,{"struct": "CreateItemResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype": "_Bool"}]} +,{"struct": "SubmitItemUpdateResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype": "_Bool"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "DownloadItemResult_t","fields": [ +{ "fieldname": "m_unAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "UserFavoriteItemsListChanged_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_bWasAddRequest", "fieldtype": "_Bool"}]} +,{"struct": "SetUserItemVoteResult_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_bVoteUp", "fieldtype": "_Bool"}]} +,{"struct": "GetUserItemVoteResult_t","fields": [ +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_bVotedUp", "fieldtype": "_Bool"}, +{ "fieldname": "m_bVotedDown", "fieldtype": "_Bool"}, +{ "fieldname": "m_bVoteSkipped", "fieldtype": "_Bool"}]} +,{"struct": "StartPlaytimeTrackingResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "StopPlaytimeTrackingResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "AddUGCDependencyResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nChildPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "RemoveUGCDependencyResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nChildPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "AddAppDependencyResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "RemoveAppDependencyResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "GetAppDependenciesResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}, +{ "fieldname": "m_rgAppIDs", "fieldtype": "AppId_t [32]"}, +{ "fieldname": "m_nNumAppDependencies", "fieldtype": "uint32"}, +{ "fieldname": "m_nTotalNumAppDependencies", "fieldtype": "uint32"}]} +,{"struct": "DeleteItemResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nPublishedFileId", "fieldtype": "PublishedFileId_t"}]} +,{"struct": "SteamAppInstalled_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "SteamAppUninstalled_t","fields": [ +{ "fieldname": "m_nAppID", "fieldtype": "AppId_t"}]} +,{"struct": "HTML_BrowserReady_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}]} +,{"struct": "HTML_NeedsPaint_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pBGRA", "fieldtype": "const char *"}, +{ "fieldname": "unWide", "fieldtype": "uint32"}, +{ "fieldname": "unTall", "fieldtype": "uint32"}, +{ "fieldname": "unUpdateX", "fieldtype": "uint32"}, +{ "fieldname": "unUpdateY", "fieldtype": "uint32"}, +{ "fieldname": "unUpdateWide", "fieldtype": "uint32"}, +{ "fieldname": "unUpdateTall", "fieldtype": "uint32"}, +{ "fieldname": "unScrollX", "fieldtype": "uint32"}, +{ "fieldname": "unScrollY", "fieldtype": "uint32"}, +{ "fieldname": "flPageScale", "fieldtype": "float"}, +{ "fieldname": "unPageSerial", "fieldtype": "uint32"}]} +,{"struct": "HTML_StartRequest_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchURL", "fieldtype": "const char *"}, +{ "fieldname": "pchTarget", "fieldtype": "const char *"}, +{ "fieldname": "pchPostData", "fieldtype": "const char *"}, +{ "fieldname": "bIsRedirect", "fieldtype": "_Bool"}]} +,{"struct": "HTML_CloseBrowser_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}]} +,{"struct": "HTML_URLChanged_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchURL", "fieldtype": "const char *"}, +{ "fieldname": "pchPostData", "fieldtype": "const char *"}, +{ "fieldname": "bIsRedirect", "fieldtype": "_Bool"}, +{ "fieldname": "pchPageTitle", "fieldtype": "const char *"}, +{ "fieldname": "bNewNavigation", "fieldtype": "_Bool"}]} +,{"struct": "HTML_FinishedRequest_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchURL", "fieldtype": "const char *"}, +{ "fieldname": "pchPageTitle", "fieldtype": "const char *"}]} +,{"struct": "HTML_OpenLinkInNewTab_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchURL", "fieldtype": "const char *"}]} +,{"struct": "HTML_ChangedTitle_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchTitle", "fieldtype": "const char *"}]} +,{"struct": "HTML_SearchResults_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "unResults", "fieldtype": "uint32"}, +{ "fieldname": "unCurrentMatch", "fieldtype": "uint32"}]} +,{"struct": "HTML_CanGoBackAndForward_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "bCanGoBack", "fieldtype": "_Bool"}, +{ "fieldname": "bCanGoForward", "fieldtype": "_Bool"}]} +,{"struct": "HTML_HorizontalScroll_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "unScrollMax", "fieldtype": "uint32"}, +{ "fieldname": "unScrollCurrent", "fieldtype": "uint32"}, +{ "fieldname": "flPageScale", "fieldtype": "float"}, +{ "fieldname": "bVisible", "fieldtype": "_Bool"}, +{ "fieldname": "unPageSize", "fieldtype": "uint32"}]} +,{"struct": "HTML_VerticalScroll_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "unScrollMax", "fieldtype": "uint32"}, +{ "fieldname": "unScrollCurrent", "fieldtype": "uint32"}, +{ "fieldname": "flPageScale", "fieldtype": "float"}, +{ "fieldname": "bVisible", "fieldtype": "_Bool"}, +{ "fieldname": "unPageSize", "fieldtype": "uint32"}]} +,{"struct": "HTML_LinkAtPosition_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "x", "fieldtype": "uint32"}, +{ "fieldname": "y", "fieldtype": "uint32"}, +{ "fieldname": "pchURL", "fieldtype": "const char *"}, +{ "fieldname": "bInput", "fieldtype": "_Bool"}, +{ "fieldname": "bLiveLink", "fieldtype": "_Bool"}]} +,{"struct": "HTML_JSAlert_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchMessage", "fieldtype": "const char *"}]} +,{"struct": "HTML_JSConfirm_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchMessage", "fieldtype": "const char *"}]} +,{"struct": "HTML_FileOpenDialog_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchTitle", "fieldtype": "const char *"}, +{ "fieldname": "pchInitialFile", "fieldtype": "const char *"}]} +,{"struct": "HTML_NewWindow_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchURL", "fieldtype": "const char *"}, +{ "fieldname": "unX", "fieldtype": "uint32"}, +{ "fieldname": "unY", "fieldtype": "uint32"}, +{ "fieldname": "unWide", "fieldtype": "uint32"}, +{ "fieldname": "unTall", "fieldtype": "uint32"}, +{ "fieldname": "unNewWindow_BrowserHandle_IGNORE", "fieldtype": "HHTMLBrowser"}]} +,{"struct": "HTML_SetCursor_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "eMouseCursor", "fieldtype": "uint32"}]} +,{"struct": "HTML_StatusText_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchMsg", "fieldtype": "const char *"}]} +,{"struct": "HTML_ShowToolTip_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchMsg", "fieldtype": "const char *"}]} +,{"struct": "HTML_UpdateToolTip_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "pchMsg", "fieldtype": "const char *"}]} +,{"struct": "HTML_HideToolTip_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}]} +,{"struct": "HTML_BrowserRestarted_t","fields": [ +{ "fieldname": "unBrowserHandle", "fieldtype": "HHTMLBrowser"}, +{ "fieldname": "unOldBrowserHandle", "fieldtype": "HHTMLBrowser"}]} +,{"struct": "SteamItemDetails_t","fields": [ +{ "fieldname": "m_itemId", "fieldtype": "SteamItemInstanceID_t"}, +{ "fieldname": "m_iDefinition", "fieldtype": "SteamItemDef_t"}, +{ "fieldname": "m_unQuantity", "fieldtype": "uint16"}, +{ "fieldname": "m_unFlags", "fieldtype": "uint16"}]} +,{"struct": "SteamInventoryResultReady_t","fields": [ +{ "fieldname": "m_handle", "fieldtype": "SteamInventoryResult_t"}, +{ "fieldname": "m_result", "fieldtype": "enum EResult"}]} +,{"struct": "SteamInventoryFullUpdate_t","fields": [ +{ "fieldname": "m_handle", "fieldtype": "SteamInventoryResult_t"}]} +,{"struct": "SteamInventoryEligiblePromoItemDefIDs_t","fields": [ +{ "fieldname": "m_result", "fieldtype": "enum EResult"}, +{ "fieldname": "m_steamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_numEligiblePromoItemDefs", "fieldtype": "int"}, +{ "fieldname": "m_bCachedData", "fieldtype": "_Bool"}]} +,{"struct": "SteamInventoryStartPurchaseResult_t","fields": [ +{ "fieldname": "m_result", "fieldtype": "enum EResult"}, +{ "fieldname": "m_ulOrderID", "fieldtype": "uint64"}, +{ "fieldname": "m_ulTransID", "fieldtype": "uint64"}]} +,{"struct": "SteamInventoryRequestPricesResult_t","fields": [ +{ "fieldname": "m_result", "fieldtype": "enum EResult"}, +{ "fieldname": "m_rgchCurrency", "fieldtype": "char [4]"}]} +,{"struct": "GetVideoURLResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unVideoAppID", "fieldtype": "AppId_t"}, +{ "fieldname": "m_rgchURL", "fieldtype": "char [256]"}]} +,{"struct": "GetOPFSettingsResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unVideoAppID", "fieldtype": "AppId_t"}]} +,{"struct": "SteamTVRegion_t","fields": [ +{ "fieldname": "unMinX", "fieldtype": "uint32"}, +{ "fieldname": "unMinY", "fieldtype": "uint32"}, +{ "fieldname": "unMaxX", "fieldtype": "uint32"}, +{ "fieldname": "unMaxY", "fieldtype": "uint32"}]} +,{"struct": "BroadcastUploadStart_t","fields": [ +{ "fieldname": "m_bIsRTMP", "fieldtype": "_Bool"}]} +,{"struct": "BroadcastUploadStop_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EBroadcastUploadResult"}]} +,{"struct": "SteamRemotePlaySessionConnected_t","fields": [ +{ "fieldname": "m_unSessionID", "fieldtype": "uint32"}]} +,{"struct": "SteamRemotePlaySessionDisconnected_t","fields": [ +{ "fieldname": "m_unSessionID", "fieldtype": "uint32"}]} +,{"struct": "GSClientApprove_t","fields": [ +{ "fieldname": "m_SteamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_OwnerSteamID", "fieldtype": "class CSteamID"}]} +,{"struct": "GSClientDeny_t","fields": [ +{ "fieldname": "m_SteamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_eDenyReason", "fieldtype": "enum EDenyReason"}, +{ "fieldname": "m_rgchOptionalText", "fieldtype": "char [128]"}]} +,{"struct": "GSClientKick_t","fields": [ +{ "fieldname": "m_SteamID", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_eDenyReason", "fieldtype": "enum EDenyReason"}]} +,{"struct": "GSClientAchievementStatus_t","fields": [ +{ "fieldname": "m_SteamID", "fieldtype": "uint64"}, +{ "fieldname": "m_pchAchievement", "fieldtype": "char [128]"}, +{ "fieldname": "m_bUnlocked", "fieldtype": "_Bool"}]} +,{"struct": "GSPolicyResponse_t","fields": [ +{ "fieldname": "m_bSecure", "fieldtype": "uint8"}]} +,{"struct": "GSGameplayStats_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_nRank", "fieldtype": "int32"}, +{ "fieldname": "m_unTotalConnects", "fieldtype": "uint32"}, +{ "fieldname": "m_unTotalMinutesPlayed", "fieldtype": "uint32"}]} +,{"struct": "GSClientGroupStatus_t","fields": [ +{ "fieldname": "m_SteamIDUser", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_SteamIDGroup", "fieldtype": "class CSteamID"}, +{ "fieldname": "m_bMember", "fieldtype": "_Bool"}, +{ "fieldname": "m_bOfficer", "fieldtype": "_Bool"}]} +,{"struct": "GSReputation_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_unReputationScore", "fieldtype": "uint32"}, +{ "fieldname": "m_bBanned", "fieldtype": "_Bool"}, +{ "fieldname": "m_unBannedIP", "fieldtype": "uint32"}, +{ "fieldname": "m_usBannedPort", "fieldtype": "uint16"}, +{ "fieldname": "m_ulBannedGameID", "fieldtype": "uint64"}, +{ "fieldname": "m_unBanExpires", "fieldtype": "uint32"}]} +,{"struct": "AssociateWithClanResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}]} +,{"struct": "ComputeNewPlayerCompatibilityResult_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_cPlayersThatDontLikeCandidate", "fieldtype": "int"}, +{ "fieldname": "m_cPlayersThatCandidateDoesntLike", "fieldtype": "int"}, +{ "fieldname": "m_cClanPlayersThatDontLikeCandidate", "fieldtype": "int"}, +{ "fieldname": "m_SteamIDCandidate", "fieldtype": "class CSteamID"}]} +,{"struct": "GSStatsReceived_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}]} +,{"struct": "GSStatsStored_t","fields": [ +{ "fieldname": "m_eResult", "fieldtype": "enum EResult"}, +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}]} +,{"struct": "GSStatsUnloaded_t","fields": [ +{ "fieldname": "m_steamIDUser", "fieldtype": "class CSteamID"}]} +], +"methods":[{ + "classname": "ISteamClient", + "methodname": "CreateSteamPipe", + "returntype": "HSteamPipe" +} +,{ + "classname": "ISteamClient", + "methodname": "BReleaseSteamPipe", + "returntype": "bool", + "params": [ +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "ConnectToGlobalUser", + "returntype": "HSteamUser", + "params": [ +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "CreateLocalUser", + "returntype": "HSteamUser", + "params": [ +{ "paramname": "phSteamPipe" ,"paramtype": "HSteamPipe *"}, +{ "paramname": "eAccountType" ,"paramtype": "EAccountType"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "ReleaseUser", + "returntype": "void", + "params": [ +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "hUser" ,"paramtype": "HSteamUser"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamUser", + "returntype": "class ISteamUser *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamGameServer", + "returntype": "class ISteamGameServer *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "SetLocalIPBinding", + "returntype": "void", + "params": [ +{ "paramname": "unIP" ,"paramtype": "uint32"}, +{ "paramname": "usPort" ,"paramtype": "uint16"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamFriends", + "returntype": "class ISteamFriends *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamUtils", + "returntype": "class ISteamUtils *", + "params": [ +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamMatchmaking", + "returntype": "class ISteamMatchmaking *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamMatchmakingServers", + "returntype": "class ISteamMatchmakingServers *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamGenericInterface", + "returntype": "void *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamUserStats", + "returntype": "class ISteamUserStats *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamGameServerStats", + "returntype": "class ISteamGameServerStats *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamApps", + "returntype": "class ISteamApps *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamNetworking", + "returntype": "class ISteamNetworking *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamRemoteStorage", + "returntype": "class ISteamRemoteStorage *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamScreenshots", + "returntype": "class ISteamScreenshots *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamGameSearch", + "returntype": "class ISteamGameSearch *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetIPCCallCount", + "returntype": "uint32" +} +,{ + "classname": "ISteamClient", + "methodname": "SetWarningMessageHook", + "returntype": "void", + "params": [ +{ "paramname": "pFunction" ,"paramtype": "SteamAPIWarningMessageHook_t"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "BShutdownIfAllPipesClosed", + "returntype": "bool" +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamHTTP", + "returntype": "class ISteamHTTP *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamController", + "returntype": "class ISteamController *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamUGC", + "returntype": "class ISteamUGC *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamAppList", + "returntype": "class ISteamAppList *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamMusic", + "returntype": "class ISteamMusic *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamMusicRemote", + "returntype": "class ISteamMusicRemote *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamHTMLSurface", + "returntype": "class ISteamHTMLSurface *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamInventory", + "returntype": "class ISteamInventory *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamVideo", + "returntype": "class ISteamVideo *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamParentalSettings", + "returntype": "class ISteamParentalSettings *", + "params": [ +{ "paramname": "hSteamuser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamInput", + "returntype": "class ISteamInput *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamParties", + "returntype": "class ISteamParties *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamClient", + "methodname": "GetISteamRemotePlay", + "returntype": "class ISteamRemotePlay *", + "params": [ +{ "paramname": "hSteamUser" ,"paramtype": "HSteamUser"}, +{ "paramname": "hSteamPipe" ,"paramtype": "HSteamPipe"}, +{ "paramname": "pchVersion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetHSteamUser", + "returntype": "HSteamUser" +} +,{ + "classname": "ISteamUser", + "methodname": "BLoggedOn", + "returntype": "bool" +} +,{ + "classname": "ISteamUser", + "methodname": "GetSteamID", + "returntype": "class CSteamID" +} +,{ + "classname": "ISteamUser", + "methodname": "InitiateGameConnection", + "returntype": "int", + "params": [ +{ "paramname": "pAuthBlob" ,"paramtype": "void *"}, +{ "paramname": "cbMaxAuthBlob" ,"paramtype": "int"}, +{ "paramname": "steamIDGameServer" ,"paramtype": "class CSteamID"}, +{ "paramname": "unIPServer" ,"paramtype": "uint32"}, +{ "paramname": "usPortServer" ,"paramtype": "uint16"}, +{ "paramname": "bSecure" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "TerminateGameConnection", + "returntype": "void", + "params": [ +{ "paramname": "unIPServer" ,"paramtype": "uint32"}, +{ "paramname": "usPortServer" ,"paramtype": "uint16"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "TrackAppUsageEvent", + "returntype": "void", + "params": [ +{ "paramname": "gameID" ,"paramtype": "class CGameID"}, +{ "paramname": "eAppUsageEvent" ,"paramtype": "int"}, +{ "paramname": "pchExtraInfo" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetUserDataFolder", + "returntype": "bool", + "params": [ +{ "paramname": "pchBuffer" ,"paramtype": "char *"}, +{ "paramname": "cubBuffer" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "StartVoiceRecording", + "returntype": "void" +} +,{ + "classname": "ISteamUser", + "methodname": "StopVoiceRecording", + "returntype": "void" +} +,{ + "classname": "ISteamUser", + "methodname": "GetAvailableVoice", + "returntype": "EVoiceResult", + "params": [ +{ "paramname": "pcbCompressed" ,"paramtype": "uint32 *"}, +{ "paramname": "pcbUncompressed_Deprecated" ,"paramtype": "uint32 *"}, +{ "paramname": "nUncompressedVoiceDesiredSampleRate_Deprecated" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetVoice", + "returntype": "EVoiceResult", + "params": [ +{ "paramname": "bWantCompressed" ,"paramtype": "bool"}, +{ "paramname": "pDestBuffer" ,"paramtype": "void *"}, +{ "paramname": "cbDestBufferSize" ,"paramtype": "uint32"}, +{ "paramname": "nBytesWritten" ,"paramtype": "uint32 *"}, +{ "paramname": "bWantUncompressed_Deprecated" ,"paramtype": "bool"}, +{ "paramname": "pUncompressedDestBuffer_Deprecated" ,"paramtype": "void *"}, +{ "paramname": "cbUncompressedDestBufferSize_Deprecated" ,"paramtype": "uint32"}, +{ "paramname": "nUncompressBytesWritten_Deprecated" ,"paramtype": "uint32 *"}, +{ "paramname": "nUncompressedVoiceDesiredSampleRate_Deprecated" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "DecompressVoice", + "returntype": "EVoiceResult", + "params": [ +{ "paramname": "pCompressed" ,"paramtype": "const void *"}, +{ "paramname": "cbCompressed" ,"paramtype": "uint32"}, +{ "paramname": "pDestBuffer" ,"paramtype": "void *"}, +{ "paramname": "cbDestBufferSize" ,"paramtype": "uint32"}, +{ "paramname": "nBytesWritten" ,"paramtype": "uint32 *"}, +{ "paramname": "nDesiredSampleRate" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetVoiceOptimalSampleRate", + "returntype": "uint32" +} +,{ + "classname": "ISteamUser", + "methodname": "GetAuthSessionTicket", + "returntype": "HAuthTicket", + "params": [ +{ "paramname": "pTicket" ,"paramtype": "void *"}, +{ "paramname": "cbMaxTicket" ,"paramtype": "int"}, +{ "paramname": "pcbTicket" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "BeginAuthSession", + "returntype": "EBeginAuthSessionResult", + "params": [ +{ "paramname": "pAuthTicket" ,"paramtype": "const void *"}, +{ "paramname": "cbAuthTicket" ,"paramtype": "int"}, +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "EndAuthSession", + "returntype": "void", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "CancelAuthTicket", + "returntype": "void", + "params": [ +{ "paramname": "hAuthTicket" ,"paramtype": "HAuthTicket"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "UserHasLicenseForApp", + "returntype": "EUserHasLicenseForAppResult", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"}, +{ "paramname": "appID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "BIsBehindNAT", + "returntype": "bool" +} +,{ + "classname": "ISteamUser", + "methodname": "AdvertiseGame", + "returntype": "void", + "params": [ +{ "paramname": "steamIDGameServer" ,"paramtype": "class CSteamID"}, +{ "paramname": "unIPServer" ,"paramtype": "uint32"}, +{ "paramname": "usPortServer" ,"paramtype": "uint16"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "RequestEncryptedAppTicket", "callresult": "EncryptedAppTicketResponse_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pDataToInclude" ,"paramtype": "void *"}, +{ "paramname": "cbDataToInclude" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetEncryptedAppTicket", + "returntype": "bool", + "params": [ +{ "paramname": "pTicket" ,"paramtype": "void *"}, +{ "paramname": "cbMaxTicket" ,"paramtype": "int"}, +{ "paramname": "pcbTicket" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetGameBadgeLevel", + "returntype": "int", + "params": [ +{ "paramname": "nSeries" ,"paramtype": "int"}, +{ "paramname": "bFoil" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "GetPlayerSteamLevel", + "returntype": "int" +} +,{ + "classname": "ISteamUser", + "methodname": "RequestStoreAuthURL", "callresult": "StoreAuthURLResponse_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchRedirectURL" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUser", + "methodname": "BIsPhoneVerified", + "returntype": "bool" +} +,{ + "classname": "ISteamUser", + "methodname": "BIsTwoFactorEnabled", + "returntype": "bool" +} +,{ + "classname": "ISteamUser", + "methodname": "BIsPhoneIdentifying", + "returntype": "bool" +} +,{ + "classname": "ISteamUser", + "methodname": "BIsPhoneRequiringVerification", + "returntype": "bool" +} +,{ + "classname": "ISteamUser", + "methodname": "GetMarketEligibility", "callresult": "MarketEligibilityResponse_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamUser", + "methodname": "GetDurationControl", "callresult": "DurationControl_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamFriends", + "methodname": "GetPersonaName", + "returntype": "const char *" +} +,{ + "classname": "ISteamFriends", + "methodname": "SetPersonaName", "callresult": "SetPersonaNameResponse_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchPersonaName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetPersonaState", + "returntype": "EPersonaState" +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendCount", + "returntype": "int", + "params": [ +{ "paramname": "iFriendFlags" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "iFriend" ,"paramtype": "int"}, +{ "paramname": "iFriendFlags" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendRelationship", + "returntype": "EFriendRelationship", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendPersonaState", + "returntype": "EPersonaState", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendPersonaName", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendGamePlayed", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "pFriendGameInfo" ,"out_struct": " " ,"paramtype": "struct FriendGameInfo_t *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendPersonaNameHistory", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "iPersonaName" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendSteamLevel", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetPlayerNickname", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDPlayer" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendsGroupCount", + "returntype": "int" +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendsGroupIDByIndex", + "returntype": "FriendsGroupID_t", + "params": [ +{ "paramname": "iFG" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendsGroupName", + "returntype": "const char *", + "params": [ +{ "paramname": "friendsGroupID" ,"paramtype": "FriendsGroupID_t"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendsGroupMembersCount", + "returntype": "int", + "params": [ +{ "paramname": "friendsGroupID" ,"paramtype": "FriendsGroupID_t"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendsGroupMembersList", + "returntype": "void", + "params": [ +{ "paramname": "friendsGroupID" ,"paramtype": "FriendsGroupID_t"}, +{ "paramname": "pOutSteamIDMembers" ,"out_array_call": "nMembersCount,GetFriendsGroupMembersCount,friendsGroupID" ,"paramtype": "class CSteamID *"}, +{ "paramname": "nMembersCount" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "HasFriend", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "iFriendFlags" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanCount", + "returntype": "int" +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "iClan" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanName", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanTag", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanActivityCounts", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"}, +{ "paramname": "pnOnline" ,"paramtype": "int *"}, +{ "paramname": "pnInGame" ,"paramtype": "int *"}, +{ "paramname": "pnChatting" ,"paramtype": "int *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "DownloadClanActivityCounts", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "psteamIDClans" ,"array_count": "cClansToRequest" ,"paramtype": "class CSteamID *"}, +{ "paramname": "cClansToRequest" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendCountFromSource", + "returntype": "int", + "params": [ +{ "paramname": "steamIDSource" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendFromSourceByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "steamIDSource" ,"paramtype": "class CSteamID"}, +{ "paramname": "iFriend" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "IsUserInSource", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDSource" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "SetInGameVoiceSpeaking", + "returntype": "void", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "bSpeaking" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ActivateGameOverlay", + "returntype": "void", + "params": [ +{ "paramname": "pchDialog" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ActivateGameOverlayToUser", + "returntype": "void", + "params": [ +{ "paramname": "pchDialog" ,"paramtype": "const char *"}, +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ActivateGameOverlayToWebPage", + "returntype": "void", + "params": [ +{ "paramname": "pchURL" ,"paramtype": "const char *"}, +{ "paramname": "eMode" ,"paramtype": "EActivateGameOverlayToWebPageMode"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ActivateGameOverlayToStore", + "returntype": "void", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "eFlag" ,"paramtype": "EOverlayToStoreFlag"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "SetPlayedWith", + "returntype": "void", + "params": [ +{ "paramname": "steamIDUserPlayedWith" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ActivateGameOverlayInviteDialog", + "returntype": "void", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetSmallFriendAvatar", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetMediumFriendAvatar", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetLargeFriendAvatar", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "RequestUserInformation", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "bRequireNameOnly" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "RequestClanOfficerList", "callresult": "ClanOfficerListResponse_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanOwner", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanOfficerCount", + "returntype": "int", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanOfficerByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"}, +{ "paramname": "iOfficer" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetUserRestrictions", + "returntype": "uint32" +} +,{ + "classname": "ISteamFriends", + "methodname": "SetRichPresence", + "returntype": "bool", + "params": [ +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ClearRichPresence", + "returntype": "void" +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendRichPresence", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendRichPresenceKeyCount", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendRichPresenceKeyByIndex", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "iKey" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "RequestFriendRichPresence", + "returntype": "void", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "InviteUserToGame", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchConnectString" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetCoplayFriendCount", + "returntype": "int" +} +,{ + "classname": "ISteamFriends", + "methodname": "GetCoplayFriend", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "iCoplayFriend" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendCoplayTime", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendCoplayGame", + "returntype": "AppId_t", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "JoinClanChatRoom", "callresult": "JoinClanChatRoomCompletionResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "LeaveClanChatRoom", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanChatMemberCount", + "returntype": "int", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetChatMemberByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"}, +{ "paramname": "iUser" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "SendClanChatMessage", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClanChat" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchText" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetClanChatMessage", + "returntype": "int", + "params": [ +{ "paramname": "steamIDClanChat" ,"paramtype": "class CSteamID"}, +{ "paramname": "iMessage" ,"paramtype": "int"}, +{ "paramname": "prgchText" ,"paramtype": "void *"}, +{ "paramname": "cchTextMax" ,"paramtype": "int"}, +{ "paramname": "peChatEntryType" ,"paramtype": "EChatEntryType *"}, +{ "paramname": "psteamidChatter" ,"out_struct": " " ,"paramtype": "class CSteamID *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "IsClanChatAdmin", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClanChat" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "IsClanChatWindowOpenInSteam", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClanChat" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "OpenClanChatWindowInSteam", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClanChat" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "CloseClanChatWindowInSteam", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClanChat" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "SetListenForFriendsMessages", + "returntype": "bool", + "params": [ +{ "paramname": "bInterceptEnabled" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "ReplyToFriendMessage", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchMsgToSend" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFriendMessage", + "returntype": "int", + "params": [ +{ "paramname": "steamIDFriend" ,"paramtype": "class CSteamID"}, +{ "paramname": "iMessageID" ,"paramtype": "int"}, +{ "paramname": "pvData" ,"paramtype": "void *"}, +{ "paramname": "cubData" ,"paramtype": "int"}, +{ "paramname": "peChatEntryType" ,"paramtype": "EChatEntryType *"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetFollowerCount", "callresult": "FriendsGetFollowerCount_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "IsFollowing", "callresult": "FriendsIsFollowing_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "EnumerateFollowingList", "callresult": "FriendsEnumerateFollowingList_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unStartIndex" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "IsClanPublic", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "IsClanOfficialGameGroup", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamFriends", + "methodname": "GetNumChatsWithUnreadPriorityMessages", + "returntype": "int" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetSecondsSinceAppActive", + "returntype": "uint32" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetSecondsSinceComputerActive", + "returntype": "uint32" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetConnectedUniverse", + "returntype": "EUniverse" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetServerRealTime", + "returntype": "uint32" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetIPCountry", + "returntype": "const char *" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetImageSize", + "returntype": "bool", + "params": [ +{ "paramname": "iImage" ,"paramtype": "int"}, +{ "paramname": "pnWidth" ,"paramtype": "uint32 *"}, +{ "paramname": "pnHeight" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetImageRGBA", + "returntype": "bool", + "params": [ +{ "paramname": "iImage" ,"paramtype": "int"}, +{ "paramname": "pubDest" ,"paramtype": "uint8 *"}, +{ "paramname": "nDestBufferSize" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetCSERIPPort", + "returntype": "bool", + "params": [ +{ "paramname": "unIP" ,"paramtype": "uint32 *"}, +{ "paramname": "usPort" ,"paramtype": "uint16 *"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetCurrentBatteryPower", + "returntype": "uint8" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetAppID", + "returntype": "uint32" +} +,{ + "classname": "ISteamUtils", + "methodname": "SetOverlayNotificationPosition", + "returntype": "void", + "params": [ +{ "paramname": "eNotificationPosition" ,"paramtype": "ENotificationPosition"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "IsAPICallCompleted", + "returntype": "bool", + "params": [ +{ "paramname": "hSteamAPICall" ,"paramtype": "SteamAPICall_t"}, +{ "paramname": "pbFailed" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetAPICallFailureReason", + "returntype": "ESteamAPICallFailure", + "params": [ +{ "paramname": "hSteamAPICall" ,"paramtype": "SteamAPICall_t"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetAPICallResult", + "returntype": "bool", + "params": [ +{ "paramname": "hSteamAPICall" ,"paramtype": "SteamAPICall_t"}, +{ "paramname": "pCallback" ,"paramtype": "void *"}, +{ "paramname": "cubCallback" ,"paramtype": "int"}, +{ "paramname": "iCallbackExpected" ,"paramtype": "int"}, +{ "paramname": "pbFailed" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetIPCCallCount", + "returntype": "uint32" +} +,{ + "classname": "ISteamUtils", + "methodname": "SetWarningMessageHook", + "returntype": "void", + "params": [ +{ "paramname": "pFunction" ,"paramtype": "SteamAPIWarningMessageHook_t"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "IsOverlayEnabled", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "BOverlayNeedsPresent", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "CheckFileSignature", "callresult": "CheckFileSignature_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "szFileName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "ShowGamepadTextInput", + "returntype": "bool", + "params": [ +{ "paramname": "eInputMode" ,"paramtype": "EGamepadTextInputMode"}, +{ "paramname": "eLineInputMode" ,"paramtype": "EGamepadTextInputLineMode"}, +{ "paramname": "pchDescription" ,"paramtype": "const char *"}, +{ "paramname": "unCharMax" ,"paramtype": "uint32"}, +{ "paramname": "pchExistingText" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetEnteredGamepadTextLength", + "returntype": "uint32" +} +,{ + "classname": "ISteamUtils", + "methodname": "GetEnteredGamepadTextInput", + "returntype": "bool", + "params": [ +{ "paramname": "pchText" ,"paramtype": "char *"}, +{ "paramname": "cchText" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "GetSteamUILanguage", + "returntype": "const char *" +} +,{ + "classname": "ISteamUtils", + "methodname": "IsSteamRunningInVR", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "SetOverlayNotificationInset", + "returntype": "void", + "params": [ +{ "paramname": "nHorizontalInset" ,"paramtype": "int"}, +{ "paramname": "nVerticalInset" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "IsSteamInBigPictureMode", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "StartVRDashboard", + "returntype": "void" +} +,{ + "classname": "ISteamUtils", + "methodname": "IsVRHeadsetStreamingEnabled", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "SetVRHeadsetStreamingEnabled", + "returntype": "void", + "params": [ +{ "paramname": "bEnabled" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUtils", + "methodname": "IsSteamChinaLauncher", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "InitFilterText", + "returntype": "bool" +} +,{ + "classname": "ISteamUtils", + "methodname": "FilterText", + "returntype": "int", + "params": [ +{ "paramname": "pchOutFilteredText" ,"paramtype": "char *"}, +{ "paramname": "nByteSizeOutFilteredText" ,"paramtype": "uint32"}, +{ "paramname": "pchInputMessage" ,"paramtype": "const char *"}, +{ "paramname": "bLegalOnly" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetFavoriteGameCount", + "returntype": "int" +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetFavoriteGame", + "returntype": "bool", + "params": [ +{ "paramname": "iGame" ,"paramtype": "int"}, +{ "paramname": "pnAppID" ,"paramtype": "AppId_t *"}, +{ "paramname": "pnIP" ,"paramtype": "uint32 *"}, +{ "paramname": "pnConnPort" ,"paramtype": "uint16 *"}, +{ "paramname": "pnQueryPort" ,"paramtype": "uint16 *"}, +{ "paramname": "punFlags" ,"paramtype": "uint32 *"}, +{ "paramname": "pRTime32LastPlayedOnServer" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddFavoriteGame", + "returntype": "int", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "nIP" ,"paramtype": "uint32"}, +{ "paramname": "nConnPort" ,"paramtype": "uint16"}, +{ "paramname": "nQueryPort" ,"paramtype": "uint16"}, +{ "paramname": "unFlags" ,"paramtype": "uint32"}, +{ "paramname": "rTime32LastPlayedOnServer" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "RemoveFavoriteGame", + "returntype": "bool", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "nIP" ,"paramtype": "uint32"}, +{ "paramname": "nConnPort" ,"paramtype": "uint16"}, +{ "paramname": "nQueryPort" ,"paramtype": "uint16"}, +{ "paramname": "unFlags" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "RequestLobbyList", "callresult": "LobbyMatchList_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListStringFilter", + "returntype": "void", + "params": [ +{ "paramname": "pchKeyToMatch" ,"paramtype": "const char *"}, +{ "paramname": "pchValueToMatch" ,"paramtype": "const char *"}, +{ "paramname": "eComparisonType" ,"paramtype": "ELobbyComparison"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListNumericalFilter", + "returntype": "void", + "params": [ +{ "paramname": "pchKeyToMatch" ,"paramtype": "const char *"}, +{ "paramname": "nValueToMatch" ,"paramtype": "int"}, +{ "paramname": "eComparisonType" ,"paramtype": "ELobbyComparison"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListNearValueFilter", + "returntype": "void", + "params": [ +{ "paramname": "pchKeyToMatch" ,"paramtype": "const char *"}, +{ "paramname": "nValueToBeCloseTo" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListFilterSlotsAvailable", + "returntype": "void", + "params": [ +{ "paramname": "nSlotsAvailable" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListDistanceFilter", + "returntype": "void", + "params": [ +{ "paramname": "eLobbyDistanceFilter" ,"paramtype": "ELobbyDistanceFilter"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListResultCountFilter", + "returntype": "void", + "params": [ +{ "paramname": "cMaxResults" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "AddRequestLobbyListCompatibleMembersFilter", + "returntype": "void", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "iLobby" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "CreateLobby", "callresult": "LobbyCreated_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "eLobbyType" ,"paramtype": "ELobbyType"}, +{ "paramname": "cMaxMembers" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "JoinLobby", "callresult": "LobbyEnter_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "LeaveLobby", + "returntype": "void", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "InviteUserToLobby", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDInvitee" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetNumLobbyMembers", + "returntype": "int", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyMemberByIndex", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "iMember" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyData", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyData", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyDataCount", + "returntype": "int", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyDataByIndex", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "iLobbyData" ,"paramtype": "int"}, +{ "paramname": "pchKey" ,"paramtype": "char *"}, +{ "paramname": "cchKeyBufferSize" ,"paramtype": "int"}, +{ "paramname": "pchValue" ,"paramtype": "char *"}, +{ "paramname": "cchValueBufferSize" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "DeleteLobbyData", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyMemberData", + "returntype": "const char *", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyMemberData", + "returntype": "void", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SendLobbyChatMsg", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "pvMsgBody" ,"paramtype": "const void *"}, +{ "paramname": "cubMsgBody" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyChatEntry", + "returntype": "int", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "iChatID" ,"paramtype": "int"}, +{ "paramname": "pSteamIDUser" ,"out_struct": " " ,"paramtype": "class CSteamID *"}, +{ "paramname": "pvData" ,"paramtype": "void *"}, +{ "paramname": "cubData" ,"paramtype": "int"}, +{ "paramname": "peChatEntryType" ,"paramtype": "EChatEntryType *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "RequestLobbyData", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyGameServer", + "returntype": "void", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "unGameServerIP" ,"paramtype": "uint32"}, +{ "paramname": "unGameServerPort" ,"paramtype": "uint16"}, +{ "paramname": "steamIDGameServer" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyGameServer", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "punGameServerIP" ,"paramtype": "uint32 *"}, +{ "paramname": "punGameServerPort" ,"paramtype": "uint16 *"}, +{ "paramname": "psteamIDGameServer" ,"out_struct": " " ,"paramtype": "class CSteamID *"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyMemberLimit", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "cMaxMembers" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyMemberLimit", + "returntype": "int", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyType", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "eLobbyType" ,"paramtype": "ELobbyType"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyJoinable", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "bLobbyJoinable" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "GetLobbyOwner", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLobbyOwner", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDNewOwner" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmaking", + "methodname": "SetLinkedLobby", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDLobbyDependent" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamMatchmakingServerListResponse", + "methodname": "ServerResponded", + "returntype": "void", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"}, +{ "paramname": "iServer" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmakingServerListResponse", + "methodname": "ServerFailedToRespond", + "returntype": "void", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"}, +{ "paramname": "iServer" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmakingServerListResponse", + "methodname": "RefreshComplete", + "returntype": "void", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"}, +{ "paramname": "response" ,"paramtype": "EMatchMakingServerResponse"} + ] +} +,{ + "classname": "ISteamMatchmakingPingResponse", + "methodname": "ServerResponded", + "returntype": "void", + "params": [ +{ "paramname": "server" ,"paramtype": "class gameserveritem_t &"} + ] +} +,{ + "classname": "ISteamMatchmakingPingResponse", + "methodname": "ServerFailedToRespond", + "returntype": "void" +} +,{ + "classname": "ISteamMatchmakingPlayersResponse", + "methodname": "AddPlayerToList", + "returntype": "void", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "nScore" ,"paramtype": "int"}, +{ "paramname": "flTimePlayed" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamMatchmakingPlayersResponse", + "methodname": "PlayersFailedToRespond", + "returntype": "void" +} +,{ + "classname": "ISteamMatchmakingPlayersResponse", + "methodname": "PlayersRefreshComplete", + "returntype": "void" +} +,{ + "classname": "ISteamMatchmakingRulesResponse", + "methodname": "RulesResponded", + "returntype": "void", + "params": [ +{ "paramname": "pchRule" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMatchmakingRulesResponse", + "methodname": "RulesFailedToRespond", + "returntype": "void" +} +,{ + "classname": "ISteamMatchmakingRulesResponse", + "methodname": "RulesRefreshComplete", + "returntype": "void" +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RequestInternetServerList", + "returntype": "HServerListRequest", + "params": [ +{ "paramname": "iApp" ,"paramtype": "AppId_t"}, +{ "paramname": "ppchFilters" ,"array_count": "nFilters" ,"paramtype": "struct MatchMakingKeyValuePair_t **"}, +{ "paramname": "nFilters" ,"paramtype": "uint32"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingServerListResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RequestLANServerList", + "returntype": "HServerListRequest", + "params": [ +{ "paramname": "iApp" ,"paramtype": "AppId_t"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingServerListResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RequestFriendsServerList", + "returntype": "HServerListRequest", + "params": [ +{ "paramname": "iApp" ,"paramtype": "AppId_t"}, +{ "paramname": "ppchFilters" ,"array_count": "nFilters" ,"paramtype": "struct MatchMakingKeyValuePair_t **"}, +{ "paramname": "nFilters" ,"paramtype": "uint32"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingServerListResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RequestFavoritesServerList", + "returntype": "HServerListRequest", + "params": [ +{ "paramname": "iApp" ,"paramtype": "AppId_t"}, +{ "paramname": "ppchFilters" ,"array_count": "nFilters" ,"paramtype": "struct MatchMakingKeyValuePair_t **"}, +{ "paramname": "nFilters" ,"paramtype": "uint32"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingServerListResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RequestHistoryServerList", + "returntype": "HServerListRequest", + "params": [ +{ "paramname": "iApp" ,"paramtype": "AppId_t"}, +{ "paramname": "ppchFilters" ,"array_count": "nFilters" ,"paramtype": "struct MatchMakingKeyValuePair_t **"}, +{ "paramname": "nFilters" ,"paramtype": "uint32"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingServerListResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RequestSpectatorServerList", + "returntype": "HServerListRequest", + "params": [ +{ "paramname": "iApp" ,"paramtype": "AppId_t"}, +{ "paramname": "ppchFilters" ,"array_count": "nFilters" ,"paramtype": "struct MatchMakingKeyValuePair_t **"}, +{ "paramname": "nFilters" ,"paramtype": "uint32"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingServerListResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "ReleaseRequest", + "returntype": "void", + "params": [ +{ "paramname": "hServerListRequest" ,"paramtype": "HServerListRequest"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "GetServerDetails", + "returntype": "class gameserveritem_t *", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"}, +{ "paramname": "iServer" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "CancelQuery", + "returntype": "void", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RefreshQuery", + "returntype": "void", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "IsRefreshing", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "GetServerCount", + "returntype": "int", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "RefreshServer", + "returntype": "void", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HServerListRequest"}, +{ "paramname": "iServer" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "PingServer", + "returntype": "HServerQuery", + "params": [ +{ "paramname": "unIP" ,"paramtype": "uint32"}, +{ "paramname": "usPort" ,"paramtype": "uint16"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingPingResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "PlayerDetails", + "returntype": "HServerQuery", + "params": [ +{ "paramname": "unIP" ,"paramtype": "uint32"}, +{ "paramname": "usPort" ,"paramtype": "uint16"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingPlayersResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "ServerRules", + "returntype": "HServerQuery", + "params": [ +{ "paramname": "unIP" ,"paramtype": "uint32"}, +{ "paramname": "usPort" ,"paramtype": "uint16"}, +{ "paramname": "pRequestServersResponse" ,"paramtype": "class ISteamMatchmakingRulesResponse *"} + ] +} +,{ + "classname": "ISteamMatchmakingServers", + "methodname": "CancelServerQuery", + "returntype": "void", + "params": [ +{ "paramname": "hServerQuery" ,"paramtype": "HServerQuery"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "AddGameSearchParams", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "pchKeyToFind" ,"paramtype": "const char *"}, +{ "paramname": "pchValuesToFind" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "SearchForGameWithLobby", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "steamIDLobby" ,"paramtype": "class CSteamID"}, +{ "paramname": "nPlayerMin" ,"paramtype": "int"}, +{ "paramname": "nPlayerMax" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "SearchForGameSolo", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "nPlayerMin" ,"paramtype": "int"}, +{ "paramname": "nPlayerMax" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "AcceptGame", + "returntype": "EGameSearchErrorCode_t" +} +,{ + "classname": "ISteamGameSearch", + "methodname": "DeclineGame", + "returntype": "EGameSearchErrorCode_t" +} +,{ + "classname": "ISteamGameSearch", + "methodname": "RetrieveConnectionDetails", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "steamIDHost" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchConnectionDetails" ,"paramtype": "char *"}, +{ "paramname": "cubConnectionDetails" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "EndGameSearch", + "returntype": "EGameSearchErrorCode_t" +} +,{ + "classname": "ISteamGameSearch", + "methodname": "SetGameHostParams", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "SetConnectionDetails", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "pchConnectionDetails" ,"paramtype": "const char *"}, +{ "paramname": "cubConnectionDetails" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "RequestPlayersForGame", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "nPlayerMin" ,"paramtype": "int"}, +{ "paramname": "nPlayerMax" ,"paramtype": "int"}, +{ "paramname": "nMaxTeamSize" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "HostConfirmGameStart", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "ullUniqueGameID" ,"paramtype": "uint64"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "CancelRequestPlayersForGame", + "returntype": "EGameSearchErrorCode_t" +} +,{ + "classname": "ISteamGameSearch", + "methodname": "SubmitPlayerResult", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "ullUniqueGameID" ,"paramtype": "uint64"}, +{ "paramname": "steamIDPlayer" ,"paramtype": "class CSteamID"}, +{ "paramname": "EPlayerResult" ,"paramtype": "EPlayerResult_t"} + ] +} +,{ + "classname": "ISteamGameSearch", + "methodname": "EndGame", + "returntype": "EGameSearchErrorCode_t", + "params": [ +{ "paramname": "ullUniqueGameID" ,"paramtype": "uint64"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "GetNumActiveBeacons", + "returntype": "uint32" +} +,{ + "classname": "ISteamParties", + "methodname": "GetBeaconByIndex", + "returntype": "PartyBeaconID_t", + "params": [ +{ "paramname": "unIndex" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "GetBeaconDetails", + "returntype": "bool", + "params": [ +{ "paramname": "ulBeaconID" ,"paramtype": "PartyBeaconID_t"}, +{ "paramname": "pSteamIDBeaconOwner" ,"paramtype": "class CSteamID *"}, +{ "paramname": "pLocation" ,"out_struct": " " ,"paramtype": "struct SteamPartyBeaconLocation_t *"}, +{ "paramname": "pchMetadata" ,"out_string_count": "cchMetadata" ,"paramtype": "char *"}, +{ "paramname": "cchMetadata" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "JoinParty", "callresult": "JoinPartyCallback_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "ulBeaconID" ,"paramtype": "PartyBeaconID_t"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "GetNumAvailableBeaconLocations", + "returntype": "bool", + "params": [ +{ "paramname": "puNumLocations" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "GetAvailableBeaconLocations", + "returntype": "bool", + "params": [ +{ "paramname": "pLocationList" ,"paramtype": "struct SteamPartyBeaconLocation_t *"}, +{ "paramname": "uMaxNumLocations" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "CreateBeacon", "callresult": "CreateBeaconCallback_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unOpenSlots" ,"paramtype": "uint32"}, +{ "paramname": "pBeaconLocation" ,"paramtype": "struct SteamPartyBeaconLocation_t *"}, +{ "paramname": "pchConnectString" ,"paramtype": "const char *"}, +{ "paramname": "pchMetadata" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "OnReservationCompleted", + "returntype": "void", + "params": [ +{ "paramname": "ulBeacon" ,"paramtype": "PartyBeaconID_t"}, +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "CancelReservation", + "returntype": "void", + "params": [ +{ "paramname": "ulBeacon" ,"paramtype": "PartyBeaconID_t"}, +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "ChangeNumOpenSlots", "callresult": "ChangeNumOpenSlotsCallback_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "ulBeacon" ,"paramtype": "PartyBeaconID_t"}, +{ "paramname": "unOpenSlots" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "DestroyBeacon", + "returntype": "bool", + "params": [ +{ "paramname": "ulBeacon" ,"paramtype": "PartyBeaconID_t"} + ] +} +,{ + "classname": "ISteamParties", + "methodname": "GetBeaconLocationData", + "returntype": "bool", + "params": [ +{ "paramname": "BeaconLocation" ,"paramtype": "struct SteamPartyBeaconLocation_t"}, +{ "paramname": "eData" ,"paramtype": "ESteamPartyBeaconLocationData"}, +{ "paramname": "pchDataStringOut" ,"out_string_count": "cchDataStringOut" ,"paramtype": "char *"}, +{ "paramname": "cchDataStringOut" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileWrite", + "returntype": "bool", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"}, +{ "paramname": "pvData" ,"paramtype": "const void *"}, +{ "paramname": "cubData" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileRead", + "returntype": "int32", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"}, +{ "paramname": "pvData" ,"paramtype": "void *"}, +{ "paramname": "cubDataToRead" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileWriteAsync", "callresult": "RemoteStorageFileWriteAsyncComplete_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"}, +{ "paramname": "pvData" ,"paramtype": "const void *"}, +{ "paramname": "cubData" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileReadAsync", "callresult": "RemoteStorageFileReadAsyncComplete_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"}, +{ "paramname": "nOffset" ,"paramtype": "uint32"}, +{ "paramname": "cubToRead" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileReadAsyncComplete", + "returntype": "bool", + "params": [ +{ "paramname": "hReadCall" ,"paramtype": "SteamAPICall_t"}, +{ "paramname": "pvBuffer" ,"paramtype": "void *"}, +{ "paramname": "cubToRead" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileForget", + "returntype": "bool", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileDelete", + "returntype": "bool", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileShare", "callresult": "RemoteStorageFileShareResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "SetSyncPlatforms", + "returntype": "bool", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"}, +{ "paramname": "eRemoteStoragePlatform" ,"paramtype": "ERemoteStoragePlatform"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileWriteStreamOpen", + "returntype": "UGCFileWriteStreamHandle_t", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileWriteStreamWriteChunk", + "returntype": "bool", + "params": [ +{ "paramname": "writeHandle" ,"paramtype": "UGCFileWriteStreamHandle_t"}, +{ "paramname": "pvData" ,"paramtype": "const void *"}, +{ "paramname": "cubData" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileWriteStreamClose", + "returntype": "bool", + "params": [ +{ "paramname": "writeHandle" ,"paramtype": "UGCFileWriteStreamHandle_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileWriteStreamCancel", + "returntype": "bool", + "params": [ +{ "paramname": "writeHandle" ,"paramtype": "UGCFileWriteStreamHandle_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FileExists", + "returntype": "bool", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "FilePersisted", + "returntype": "bool", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetFileSize", + "returntype": "int32", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetFileTimestamp", + "returntype": "int64", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetSyncPlatforms", + "returntype": "ERemoteStoragePlatform", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetFileCount", + "returntype": "int32" +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetFileNameAndSize", + "returntype": "const char *", + "params": [ +{ "paramname": "iFile" ,"paramtype": "int"}, +{ "paramname": "pnFileSizeInBytes" ,"paramtype": "int32 *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetQuota", + "returntype": "bool", + "params": [ +{ "paramname": "pnTotalBytes" ,"paramtype": "uint64 *"}, +{ "paramname": "puAvailableBytes" ,"paramtype": "uint64 *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "IsCloudEnabledForAccount", + "returntype": "bool" +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "IsCloudEnabledForApp", + "returntype": "bool" +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "SetCloudEnabledForApp", + "returntype": "void", + "params": [ +{ "paramname": "bEnabled" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UGCDownload", "callresult": "RemoteStorageDownloadUGCResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "hContent" ,"paramtype": "UGCHandle_t"}, +{ "paramname": "unPriority" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetUGCDownloadProgress", + "returntype": "bool", + "params": [ +{ "paramname": "hContent" ,"paramtype": "UGCHandle_t"}, +{ "paramname": "pnBytesDownloaded" ,"paramtype": "int32 *"}, +{ "paramname": "pnBytesExpected" ,"paramtype": "int32 *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetUGCDetails", + "returntype": "bool", + "params": [ +{ "paramname": "hContent" ,"paramtype": "UGCHandle_t"}, +{ "paramname": "pnAppID" ,"paramtype": "AppId_t *"}, +{ "paramname": "ppchName" ,"out_string": " " ,"paramtype": "char **"}, +{ "paramname": "pnFileSizeInBytes" ,"paramtype": "int32 *"}, +{ "paramname": "pSteamIDOwner" ,"out_struct": " " ,"paramtype": "class CSteamID *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UGCRead", + "returntype": "int32", + "params": [ +{ "paramname": "hContent" ,"paramtype": "UGCHandle_t"}, +{ "paramname": "pvData" ,"paramtype": "void *"}, +{ "paramname": "cubDataToRead" ,"paramtype": "int32"}, +{ "paramname": "cOffset" ,"paramtype": "uint32"}, +{ "paramname": "eAction" ,"paramtype": "EUGCReadAction"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetCachedUGCCount", + "returntype": "int32" +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetCachedUGCHandle", + "returntype": "UGCHandle_t", + "params": [ +{ "paramname": "iCachedContent" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "PublishWorkshopFile", "callresult": "RemoteStoragePublishFileProgress_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchFile" ,"paramtype": "const char *"}, +{ "paramname": "pchPreviewFile" ,"paramtype": "const char *"}, +{ "paramname": "nConsumerAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "pchTitle" ,"paramtype": "const char *"}, +{ "paramname": "pchDescription" ,"paramtype": "const char *"}, +{ "paramname": "eVisibility" ,"paramtype": "ERemoteStoragePublishedFileVisibility"}, +{ "paramname": "pTags" ,"paramtype": "struct SteamParamStringArray_t *"}, +{ "paramname": "eWorkshopFileType" ,"paramtype": "EWorkshopFileType"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "CreatePublishedFileUpdateRequest", + "returntype": "PublishedFileUpdateHandle_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFileFile", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "pchFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFilePreviewFile", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "pchPreviewFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFileTitle", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "pchTitle" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFileDescription", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "pchDescription" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFileVisibility", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "eVisibility" ,"paramtype": "ERemoteStoragePublishedFileVisibility"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFileTags", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "pTags" ,"paramtype": "struct SteamParamStringArray_t *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "CommitPublishedFileUpdate", "callresult": "RemoteStorageUpdatePublishedFileResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetPublishedFileDetails", "callresult": "RemoteStorageGetPublishedFileDetailsResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "unMaxSecondsOld" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "DeletePublishedFile", "callresult": "RemoteStorageDeletePublishedFileResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "EnumerateUserPublishedFiles", "callresult": "RemoteStorageEnumerateUserPublishedFilesResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unStartIndex" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "SubscribePublishedFile", "callresult": "RemoteStorageSubscribePublishedFileResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "EnumerateUserSubscribedFiles", "callresult": "RemoteStorageEnumerateUserSubscribedFilesResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unStartIndex" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UnsubscribePublishedFile", "callresult": "RemoteStorageUnsubscribePublishedFileResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdatePublishedFileSetChangeDescription", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "PublishedFileUpdateHandle_t"}, +{ "paramname": "pchChangeDescription" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetPublishedItemVoteDetails", "callresult": "RemoteStorageGetPublishedItemVoteDetailsResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UpdateUserPublishedItemVote", "callresult": "RemoteStorageUpdateUserPublishedItemVoteResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "bVoteUp" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "GetUserPublishedItemVoteDetails", "callresult": "RemoteStorageGetPublishedItemVoteDetailsResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "EnumerateUserSharedWorkshopFiles", "callresult": "RemoteStorageEnumerateUserPublishedFilesResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamId" ,"paramtype": "class CSteamID"}, +{ "paramname": "unStartIndex" ,"paramtype": "uint32"}, +{ "paramname": "pRequiredTags" ,"paramtype": "struct SteamParamStringArray_t *"}, +{ "paramname": "pExcludedTags" ,"paramtype": "struct SteamParamStringArray_t *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "PublishVideo", "callresult": "RemoteStoragePublishFileProgress_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "eVideoProvider" ,"paramtype": "EWorkshopVideoProvider"}, +{ "paramname": "pchVideoAccount" ,"paramtype": "const char *"}, +{ "paramname": "pchVideoIdentifier" ,"paramtype": "const char *"}, +{ "paramname": "pchPreviewFile" ,"paramtype": "const char *"}, +{ "paramname": "nConsumerAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "pchTitle" ,"paramtype": "const char *"}, +{ "paramname": "pchDescription" ,"paramtype": "const char *"}, +{ "paramname": "eVisibility" ,"paramtype": "ERemoteStoragePublishedFileVisibility"}, +{ "paramname": "pTags" ,"paramtype": "struct SteamParamStringArray_t *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "SetUserPublishedFileAction", "callresult": "RemoteStorageSetUserPublishedFileActionResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "unPublishedFileId" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "eAction" ,"paramtype": "EWorkshopFileAction"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "EnumeratePublishedFilesByUserAction", "callresult": "RemoteStorageEnumeratePublishedFilesByUserActionResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "eAction" ,"paramtype": "EWorkshopFileAction"}, +{ "paramname": "unStartIndex" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "EnumeratePublishedWorkshopFiles", "callresult": "RemoteStorageEnumerateWorkshopFilesResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "eEnumerationType" ,"paramtype": "EWorkshopEnumerationType"}, +{ "paramname": "unStartIndex" ,"paramtype": "uint32"}, +{ "paramname": "unCount" ,"paramtype": "uint32"}, +{ "paramname": "unDays" ,"paramtype": "uint32"}, +{ "paramname": "pTags" ,"paramtype": "struct SteamParamStringArray_t *"}, +{ "paramname": "pUserTags" ,"paramtype": "struct SteamParamStringArray_t *"} + ] +} +,{ + "classname": "ISteamRemoteStorage", + "methodname": "UGCDownloadToLocation", "callresult": "RemoteStorageDownloadUGCResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "hContent" ,"paramtype": "UGCHandle_t"}, +{ "paramname": "pchLocation" ,"paramtype": "const char *"}, +{ "paramname": "unPriority" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "RequestCurrentStats", "callback": "UserStatsReceived_t", + "returntype": "bool" +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "int32 *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "float *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "SetStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "nData" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "SetStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "fData" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "UpdateAvgRateStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "flCountThisSession" ,"paramtype": "float"}, +{ "paramname": "dSessionLength" ,"paramtype": "double"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "SetAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "ClearAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetAchievementAndUnlockTime", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"}, +{ "paramname": "punUnlockTime" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "StoreStats", + "returntype": "bool" +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetAchievementIcon", + "returntype": "int", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetAchievementDisplayAttribute", + "returntype": "const char *", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "IndicateAchievementProgress", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "nCurProgress" ,"paramtype": "uint32"}, +{ "paramname": "nMaxProgress" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetNumAchievements", + "returntype": "uint32" +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetAchievementName", + "returntype": "const char *", + "params": [ +{ "paramname": "iAchievement" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "RequestUserStats", "callresult": "UserStatsReceived_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetUserStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "int32 *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetUserStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "float *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetUserAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetUserAchievementAndUnlockTime", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"}, +{ "paramname": "punUnlockTime" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "ResetAllStats", + "returntype": "bool", + "params": [ +{ "paramname": "bAchievementsToo" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "FindOrCreateLeaderboard", "callresult": "LeaderboardFindResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchLeaderboardName" ,"paramtype": "const char *"}, +{ "paramname": "eLeaderboardSortMethod" ,"paramtype": "ELeaderboardSortMethod"}, +{ "paramname": "eLeaderboardDisplayType" ,"paramtype": "ELeaderboardDisplayType"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "FindLeaderboard", "callresult": "LeaderboardFindResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchLeaderboardName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetLeaderboardName", + "returntype": "const char *", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetLeaderboardEntryCount", + "returntype": "int", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetLeaderboardSortMethod", + "returntype": "ELeaderboardSortMethod", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetLeaderboardDisplayType", + "returntype": "ELeaderboardDisplayType", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "DownloadLeaderboardEntries", "callresult": "LeaderboardScoresDownloaded_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"}, +{ "paramname": "eLeaderboardDataRequest" ,"paramtype": "ELeaderboardDataRequest"}, +{ "paramname": "nRangeStart" ,"paramtype": "int"}, +{ "paramname": "nRangeEnd" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "DownloadLeaderboardEntriesForUsers", "callresult": "LeaderboardScoresDownloaded_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"}, +{ "paramname": "prgUsers" ,"array_count": "cUsers" ,"desc": "Array of users to retrieve" ,"paramtype": "class CSteamID *"}, +{ "paramname": "cUsers" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetDownloadedLeaderboardEntry", + "returntype": "bool", + "params": [ +{ "paramname": "hSteamLeaderboardEntries" ,"paramtype": "SteamLeaderboardEntries_t"}, +{ "paramname": "index" ,"paramtype": "int"}, +{ "paramname": "pLeaderboardEntry" ,"paramtype": "struct LeaderboardEntry_t *"}, +{ "paramname": "pDetails" ,"paramtype": "int32 *"}, +{ "paramname": "cDetailsMax" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "UploadLeaderboardScore", "callresult": "LeaderboardScoreUploaded_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"}, +{ "paramname": "eLeaderboardUploadScoreMethod" ,"paramtype": "ELeaderboardUploadScoreMethod"}, +{ "paramname": "nScore" ,"paramtype": "int32"}, +{ "paramname": "pScoreDetails" ,"paramtype": "const int32 *"}, +{ "paramname": "cScoreDetailsCount" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "AttachLeaderboardUGC", "callresult": "LeaderboardUGCSet_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "hSteamLeaderboard" ,"paramtype": "SteamLeaderboard_t"}, +{ "paramname": "hUGC" ,"paramtype": "UGCHandle_t"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetNumberOfCurrentPlayers", "callresult": "NumberOfCurrentPlayers_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamUserStats", + "methodname": "RequestGlobalAchievementPercentages", "callresult": "GlobalAchievementPercentagesReady_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetMostAchievedAchievementInfo", + "returntype": "int", + "params": [ +{ "paramname": "pchName" ,"paramtype": "char *"}, +{ "paramname": "unNameBufLen" ,"paramtype": "uint32"}, +{ "paramname": "pflPercent" ,"paramtype": "float *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetNextMostAchievedAchievementInfo", + "returntype": "int", + "params": [ +{ "paramname": "iIteratorPrevious" ,"paramtype": "int"}, +{ "paramname": "pchName" ,"paramtype": "char *"}, +{ "paramname": "unNameBufLen" ,"paramtype": "uint32"}, +{ "paramname": "pflPercent" ,"paramtype": "float *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetAchievementAchievedPercent", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pflPercent" ,"paramtype": "float *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "RequestGlobalStats", "callresult": "GlobalStatsReceived_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nHistoryDays" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetGlobalStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchStatName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "int64 *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetGlobalStat", + "returntype": "bool", + "params": [ +{ "paramname": "pchStatName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "double *"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetGlobalStatHistory", + "returntype": "int32", + "params": [ +{ "paramname": "pchStatName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"array_count": "cubData" ,"paramtype": "int64 *"}, +{ "paramname": "cubData" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUserStats", + "methodname": "GetGlobalStatHistory", + "returntype": "int32", + "params": [ +{ "paramname": "pchStatName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"array_count": "cubData" ,"paramtype": "double *"}, +{ "paramname": "cubData" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "BIsSubscribed", + "returntype": "bool" +} +,{ + "classname": "ISteamApps", + "methodname": "BIsLowViolence", + "returntype": "bool" +} +,{ + "classname": "ISteamApps", + "methodname": "BIsCybercafe", + "returntype": "bool" +} +,{ + "classname": "ISteamApps", + "methodname": "BIsVACBanned", + "returntype": "bool" +} +,{ + "classname": "ISteamApps", + "methodname": "GetCurrentGameLanguage", + "returntype": "const char *" +} +,{ + "classname": "ISteamApps", + "methodname": "GetAvailableGameLanguages", + "returntype": "const char *" +} +,{ + "classname": "ISteamApps", + "methodname": "BIsSubscribedApp", + "returntype": "bool", + "params": [ +{ "paramname": "appID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "BIsDlcInstalled", + "returntype": "bool", + "params": [ +{ "paramname": "appID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetEarliestPurchaseUnixTime", + "returntype": "uint32", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "BIsSubscribedFromFreeWeekend", + "returntype": "bool" +} +,{ + "classname": "ISteamApps", + "methodname": "GetDLCCount", + "returntype": "int" +} +,{ + "classname": "ISteamApps", + "methodname": "BGetDLCDataByIndex", + "returntype": "bool", + "params": [ +{ "paramname": "iDLC" ,"paramtype": "int"}, +{ "paramname": "pAppID" ,"paramtype": "AppId_t *"}, +{ "paramname": "pbAvailable" ,"paramtype": "bool *"}, +{ "paramname": "pchName" ,"paramtype": "char *"}, +{ "paramname": "cchNameBufferSize" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "InstallDLC", + "returntype": "void", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "UninstallDLC", + "returntype": "void", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "RequestAppProofOfPurchaseKey", + "returntype": "void", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetCurrentBetaName", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "char *"}, +{ "paramname": "cchNameBufferSize" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "MarkContentCorrupt", + "returntype": "bool", + "params": [ +{ "paramname": "bMissingFilesOnly" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetInstalledDepots", + "returntype": "uint32", + "params": [ +{ "paramname": "appID" ,"paramtype": "AppId_t"}, +{ "paramname": "pvecDepots" ,"paramtype": "DepotId_t *"}, +{ "paramname": "cMaxDepots" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetAppInstallDir", + "returntype": "uint32", + "params": [ +{ "paramname": "appID" ,"paramtype": "AppId_t"}, +{ "paramname": "pchFolder" ,"paramtype": "char *"}, +{ "paramname": "cchFolderBufferSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "BIsAppInstalled", + "returntype": "bool", + "params": [ +{ "paramname": "appID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetAppOwner", + "returntype": "class CSteamID" +} +,{ + "classname": "ISteamApps", + "methodname": "GetLaunchQueryParam", + "returntype": "const char *", + "params": [ +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetDlcDownloadProgress", + "returntype": "bool", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "punBytesDownloaded" ,"paramtype": "uint64 *"}, +{ "paramname": "punBytesTotal" ,"paramtype": "uint64 *"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetAppBuildId", + "returntype": "int" +} +,{ + "classname": "ISteamApps", + "methodname": "RequestAllProofOfPurchaseKeys", + "returntype": "void" +} +,{ + "classname": "ISteamApps", + "methodname": "GetFileDetails", "callresult": "FileDetailsResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pszFileName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "GetLaunchCommandLine", + "returntype": "int", + "params": [ +{ "paramname": "pszCommandLine" ,"paramtype": "char *"}, +{ "paramname": "cubCommandLine" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamApps", + "methodname": "BIsSubscribedFromFamilySharing", + "returntype": "bool" +} +,{ + "classname": "ISteamNetworking", + "methodname": "SendP2PPacket", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDRemote" ,"paramtype": "class CSteamID"}, +{ "paramname": "pubData" ,"paramtype": "const void *"}, +{ "paramname": "cubData" ,"paramtype": "uint32"}, +{ "paramname": "eP2PSendType" ,"paramtype": "EP2PSend"}, +{ "paramname": "nChannel" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "IsP2PPacketAvailable", + "returntype": "bool", + "params": [ +{ "paramname": "pcubMsgSize" ,"paramtype": "uint32 *"}, +{ "paramname": "nChannel" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "ReadP2PPacket", + "returntype": "bool", + "params": [ +{ "paramname": "pubDest" ,"paramtype": "void *"}, +{ "paramname": "cubDest" ,"paramtype": "uint32"}, +{ "paramname": "pcubMsgSize" ,"paramtype": "uint32 *"}, +{ "paramname": "psteamIDRemote" ,"paramtype": "class CSteamID *"}, +{ "paramname": "nChannel" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "AcceptP2PSessionWithUser", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDRemote" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "CloseP2PSessionWithUser", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDRemote" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "CloseP2PChannelWithUser", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDRemote" ,"paramtype": "class CSteamID"}, +{ "paramname": "nChannel" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "GetP2PSessionState", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDRemote" ,"paramtype": "class CSteamID"}, +{ "paramname": "pConnectionState" ,"paramtype": "struct P2PSessionState_t *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "AllowP2PPacketRelay", + "returntype": "bool", + "params": [ +{ "paramname": "bAllow" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "CreateListenSocket", + "returntype": "SNetListenSocket_t", + "params": [ +{ "paramname": "nVirtualP2PPort" ,"paramtype": "int"}, +{ "paramname": "nIP" ,"paramtype": "uint32"}, +{ "paramname": "nPort" ,"paramtype": "uint16"}, +{ "paramname": "bAllowUseOfPacketRelay" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "CreateP2PConnectionSocket", + "returntype": "SNetSocket_t", + "params": [ +{ "paramname": "steamIDTarget" ,"paramtype": "class CSteamID"}, +{ "paramname": "nVirtualPort" ,"paramtype": "int"}, +{ "paramname": "nTimeoutSec" ,"paramtype": "int"}, +{ "paramname": "bAllowUseOfPacketRelay" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "CreateConnectionSocket", + "returntype": "SNetSocket_t", + "params": [ +{ "paramname": "nIP" ,"paramtype": "uint32"}, +{ "paramname": "nPort" ,"paramtype": "uint16"}, +{ "paramname": "nTimeoutSec" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "DestroySocket", + "returntype": "bool", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"}, +{ "paramname": "bNotifyRemoteEnd" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "DestroyListenSocket", + "returntype": "bool", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetListenSocket_t"}, +{ "paramname": "bNotifyRemoteEnd" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "SendDataOnSocket", + "returntype": "bool", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"}, +{ "paramname": "pubData" ,"paramtype": "void *"}, +{ "paramname": "cubData" ,"paramtype": "uint32"}, +{ "paramname": "bReliable" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "IsDataAvailableOnSocket", + "returntype": "bool", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"}, +{ "paramname": "pcubMsgSize" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "RetrieveDataFromSocket", + "returntype": "bool", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"}, +{ "paramname": "pubDest" ,"paramtype": "void *"}, +{ "paramname": "cubDest" ,"paramtype": "uint32"}, +{ "paramname": "pcubMsgSize" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "IsDataAvailable", + "returntype": "bool", + "params": [ +{ "paramname": "hListenSocket" ,"paramtype": "SNetListenSocket_t"}, +{ "paramname": "pcubMsgSize" ,"paramtype": "uint32 *"}, +{ "paramname": "phSocket" ,"paramtype": "SNetSocket_t *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "RetrieveData", + "returntype": "bool", + "params": [ +{ "paramname": "hListenSocket" ,"paramtype": "SNetListenSocket_t"}, +{ "paramname": "pubDest" ,"paramtype": "void *"}, +{ "paramname": "cubDest" ,"paramtype": "uint32"}, +{ "paramname": "pcubMsgSize" ,"paramtype": "uint32 *"}, +{ "paramname": "phSocket" ,"paramtype": "SNetSocket_t *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "GetSocketInfo", + "returntype": "bool", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"}, +{ "paramname": "pSteamIDRemote" ,"paramtype": "class CSteamID *"}, +{ "paramname": "peSocketStatus" ,"paramtype": "int *"}, +{ "paramname": "punIPRemote" ,"paramtype": "uint32 *"}, +{ "paramname": "punPortRemote" ,"paramtype": "uint16 *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "GetListenSocketInfo", + "returntype": "bool", + "params": [ +{ "paramname": "hListenSocket" ,"paramtype": "SNetListenSocket_t"}, +{ "paramname": "pnIP" ,"paramtype": "uint32 *"}, +{ "paramname": "pnPort" ,"paramtype": "uint16 *"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "GetSocketConnectionType", + "returntype": "ESNetSocketConnectionType", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"} + ] +} +,{ + "classname": "ISteamNetworking", + "methodname": "GetMaxPacketSize", + "returntype": "int", + "params": [ +{ "paramname": "hSocket" ,"paramtype": "SNetSocket_t"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "WriteScreenshot", + "returntype": "ScreenshotHandle", + "params": [ +{ "paramname": "pubRGB" ,"paramtype": "void *"}, +{ "paramname": "cubRGB" ,"paramtype": "uint32"}, +{ "paramname": "nWidth" ,"paramtype": "int"}, +{ "paramname": "nHeight" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "AddScreenshotToLibrary", + "returntype": "ScreenshotHandle", + "params": [ +{ "paramname": "pchFilename" ,"paramtype": "const char *"}, +{ "paramname": "pchThumbnailFilename" ,"paramtype": "const char *"}, +{ "paramname": "nWidth" ,"paramtype": "int"}, +{ "paramname": "nHeight" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "TriggerScreenshot", + "returntype": "void" +} +,{ + "classname": "ISteamScreenshots", + "methodname": "HookScreenshots", + "returntype": "void", + "params": [ +{ "paramname": "bHook" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "SetLocation", + "returntype": "bool", + "params": [ +{ "paramname": "hScreenshot" ,"paramtype": "ScreenshotHandle"}, +{ "paramname": "pchLocation" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "TagUser", + "returntype": "bool", + "params": [ +{ "paramname": "hScreenshot" ,"paramtype": "ScreenshotHandle"}, +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "TagPublishedFile", + "returntype": "bool", + "params": [ +{ "paramname": "hScreenshot" ,"paramtype": "ScreenshotHandle"}, +{ "paramname": "unPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamScreenshots", + "methodname": "IsScreenshotsHooked", + "returntype": "bool" +} +,{ + "classname": "ISteamScreenshots", + "methodname": "AddVRScreenshotToLibrary", + "returntype": "ScreenshotHandle", + "params": [ +{ "paramname": "eType" ,"paramtype": "EVRScreenshotType"}, +{ "paramname": "pchFilename" ,"paramtype": "const char *"}, +{ "paramname": "pchVRFilename" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMusic", + "methodname": "BIsEnabled", + "returntype": "bool" +} +,{ + "classname": "ISteamMusic", + "methodname": "BIsPlaying", + "returntype": "bool" +} +,{ + "classname": "ISteamMusic", + "methodname": "GetPlaybackStatus", + "returntype": "AudioPlayback_Status" +} +,{ + "classname": "ISteamMusic", + "methodname": "Play", + "returntype": "void" +} +,{ + "classname": "ISteamMusic", + "methodname": "Pause", + "returntype": "void" +} +,{ + "classname": "ISteamMusic", + "methodname": "PlayPrevious", + "returntype": "void" +} +,{ + "classname": "ISteamMusic", + "methodname": "PlayNext", + "returntype": "void" +} +,{ + "classname": "ISteamMusic", + "methodname": "SetVolume", + "returntype": "void", + "params": [ +{ "paramname": "flVolume" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamMusic", + "methodname": "GetVolume", + "returntype": "float" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "RegisterSteamMusicRemote", + "returntype": "bool", + "params": [ +{ "paramname": "pchName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "DeregisterSteamMusicRemote", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "BIsCurrentMusicRemote", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "BActivationSuccess", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "SetDisplayName", + "returntype": "bool", + "params": [ +{ "paramname": "pchDisplayName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "SetPNGIcon_64x64", + "returntype": "bool", + "params": [ +{ "paramname": "pvBuffer" ,"paramtype": "void *"}, +{ "paramname": "cbBufferLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "EnablePlayPrevious", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "EnablePlayNext", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "EnableShuffled", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "EnableLooped", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "EnableQueue", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "EnablePlaylists", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdatePlaybackStatus", + "returntype": "bool", + "params": [ +{ "paramname": "nStatus" ,"paramtype": "AudioPlayback_Status"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdateShuffled", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdateLooped", + "returntype": "bool", + "params": [ +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdateVolume", + "returntype": "bool", + "params": [ +{ "paramname": "flValue" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "CurrentEntryWillChange", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "CurrentEntryIsAvailable", + "returntype": "bool", + "params": [ +{ "paramname": "bAvailable" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdateCurrentEntryText", + "returntype": "bool", + "params": [ +{ "paramname": "pchText" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdateCurrentEntryElapsedSeconds", + "returntype": "bool", + "params": [ +{ "paramname": "nValue" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "UpdateCurrentEntryCoverArt", + "returntype": "bool", + "params": [ +{ "paramname": "pvBuffer" ,"paramtype": "void *"}, +{ "paramname": "cbBufferLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "CurrentEntryDidChange", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "QueueWillChange", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "ResetQueueEntries", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "SetQueueEntry", + "returntype": "bool", + "params": [ +{ "paramname": "nID" ,"paramtype": "int"}, +{ "paramname": "nPosition" ,"paramtype": "int"}, +{ "paramname": "pchEntryText" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "SetCurrentQueueEntry", + "returntype": "bool", + "params": [ +{ "paramname": "nID" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "QueueDidChange", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "PlaylistWillChange", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "ResetPlaylistEntries", + "returntype": "bool" +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "SetPlaylistEntry", + "returntype": "bool", + "params": [ +{ "paramname": "nID" ,"paramtype": "int"}, +{ "paramname": "nPosition" ,"paramtype": "int"}, +{ "paramname": "pchEntryText" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "SetCurrentPlaylistEntry", + "returntype": "bool", + "params": [ +{ "paramname": "nID" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamMusicRemote", + "methodname": "PlaylistDidChange", + "returntype": "bool" +} +,{ + "classname": "ISteamHTTP", + "methodname": "CreateHTTPRequest", + "returntype": "HTTPRequestHandle", + "params": [ +{ "paramname": "eHTTPRequestMethod" ,"paramtype": "EHTTPMethod"}, +{ "paramname": "pchAbsoluteURL" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestContextValue", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "ulContextValue" ,"paramtype": "uint64"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestNetworkActivityTimeout", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "unTimeoutSeconds" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestHeaderValue", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pchHeaderName" ,"paramtype": "const char *"}, +{ "paramname": "pchHeaderValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestGetOrPostParameter", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pchParamName" ,"paramtype": "const char *"}, +{ "paramname": "pchParamValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SendHTTPRequest", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pCallHandle" ,"paramtype": "SteamAPICall_t *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SendHTTPRequestAndStreamResponse", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pCallHandle" ,"paramtype": "SteamAPICall_t *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "DeferHTTPRequest", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "PrioritizeHTTPRequest", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPResponseHeaderSize", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pchHeaderName" ,"paramtype": "const char *"}, +{ "paramname": "unResponseHeaderSize" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPResponseHeaderValue", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pchHeaderName" ,"paramtype": "const char *"}, +{ "paramname": "pHeaderValueBuffer" ,"paramtype": "uint8 *"}, +{ "paramname": "unBufferSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPResponseBodySize", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "unBodySize" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPResponseBodyData", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pBodyDataBuffer" ,"paramtype": "uint8 *"}, +{ "paramname": "unBufferSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPStreamingResponseBodyData", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "cOffset" ,"paramtype": "uint32"}, +{ "paramname": "pBodyDataBuffer" ,"paramtype": "uint8 *"}, +{ "paramname": "unBufferSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "ReleaseHTTPRequest", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPDownloadProgressPct", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pflPercentOut" ,"paramtype": "float *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestRawPostBody", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pchContentType" ,"paramtype": "const char *"}, +{ "paramname": "pubBody" ,"paramtype": "uint8 *"}, +{ "paramname": "unBodyLen" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "CreateCookieContainer", + "returntype": "HTTPCookieContainerHandle", + "params": [ +{ "paramname": "bAllowResponsesToModify" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "ReleaseCookieContainer", + "returntype": "bool", + "params": [ +{ "paramname": "hCookieContainer" ,"paramtype": "HTTPCookieContainerHandle"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetCookie", + "returntype": "bool", + "params": [ +{ "paramname": "hCookieContainer" ,"paramtype": "HTTPCookieContainerHandle"}, +{ "paramname": "pchHost" ,"paramtype": "const char *"}, +{ "paramname": "pchUrl" ,"paramtype": "const char *"}, +{ "paramname": "pchCookie" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestCookieContainer", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "hCookieContainer" ,"paramtype": "HTTPCookieContainerHandle"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestUserAgentInfo", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pchUserAgentInfo" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestRequiresVerifiedCertificate", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "bRequireVerifiedCertificate" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "SetHTTPRequestAbsoluteTimeoutMS", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "unMilliseconds" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTTP", + "methodname": "GetHTTPRequestWasTimedOut", + "returntype": "bool", + "params": [ +{ "paramname": "hRequest" ,"paramtype": "HTTPRequestHandle"}, +{ "paramname": "pbWasTimedOut" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "Init", + "returntype": "bool" +} +,{ + "classname": "ISteamInput", + "methodname": "Shutdown", + "returntype": "bool" +} +,{ + "classname": "ISteamInput", + "methodname": "RunFrame", + "returntype": "void" +} +,{ + "classname": "ISteamInput", + "methodname": "GetConnectedControllers", + "returntype": "int", + "params": [ +{ "paramname": "handlesOut" ,"out_array_count": "STEAM_INPUT_MAX_COUNT" ,"desc": "Receives list of connected controllers" ,"paramtype": "InputHandle_t *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetActionSetHandle", + "returntype": "InputActionSetHandle_t", + "params": [ +{ "paramname": "pszActionSetName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "ActivateActionSet", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "actionSetHandle" ,"paramtype": "InputActionSetHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetCurrentActionSet", + "returntype": "InputActionSetHandle_t", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "ActivateActionSetLayer", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "actionSetLayerHandle" ,"paramtype": "InputActionSetHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "DeactivateActionSetLayer", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "actionSetLayerHandle" ,"paramtype": "InputActionSetHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "DeactivateAllActionSetLayers", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetActiveActionSetLayers", + "returntype": "int", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "handlesOut" ,"out_array_count": "STEAM_INPUT_MAX_ACTIVE_LAYERS" ,"desc": "Receives list of active layers" ,"paramtype": "InputActionSetHandle_t *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetDigitalActionHandle", + "returntype": "InputDigitalActionHandle_t", + "params": [ +{ "paramname": "pszActionName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetDigitalActionData", + "returntype": "struct InputDigitalActionData_t", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "digitalActionHandle" ,"paramtype": "InputDigitalActionHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetDigitalActionOrigins", + "returntype": "int", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "actionSetHandle" ,"paramtype": "InputActionSetHandle_t"}, +{ "paramname": "digitalActionHandle" ,"paramtype": "InputDigitalActionHandle_t"}, +{ "paramname": "originsOut" ,"out_array_count": "STEAM_INPUT_MAX_ORIGINS" ,"desc": "Receives list of action origins" ,"paramtype": "EInputActionOrigin *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetAnalogActionHandle", + "returntype": "InputAnalogActionHandle_t", + "params": [ +{ "paramname": "pszActionName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetAnalogActionData", + "returntype": "struct InputAnalogActionData_t", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "analogActionHandle" ,"paramtype": "InputAnalogActionHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetAnalogActionOrigins", + "returntype": "int", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "actionSetHandle" ,"paramtype": "InputActionSetHandle_t"}, +{ "paramname": "analogActionHandle" ,"paramtype": "InputAnalogActionHandle_t"}, +{ "paramname": "originsOut" ,"out_array_count": "STEAM_INPUT_MAX_ORIGINS" ,"desc": "Receives list of action origins" ,"paramtype": "EInputActionOrigin *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetGlyphForActionOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EInputActionOrigin"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetStringForActionOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EInputActionOrigin"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "StopAnalogActionMomentum", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "eAction" ,"paramtype": "InputAnalogActionHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetMotionData", + "returntype": "struct InputMotionData_t", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "TriggerVibration", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "usLeftSpeed" ,"paramtype": "unsigned short"}, +{ "paramname": "usRightSpeed" ,"paramtype": "unsigned short"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "SetLEDColor", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "nColorR" ,"paramtype": "uint8"}, +{ "paramname": "nColorG" ,"paramtype": "uint8"}, +{ "paramname": "nColorB" ,"paramtype": "uint8"}, +{ "paramname": "nFlags" ,"paramtype": "unsigned int"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "TriggerHapticPulse", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "eTargetPad" ,"paramtype": "ESteamControllerPad"}, +{ "paramname": "usDurationMicroSec" ,"paramtype": "unsigned short"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "TriggerRepeatedHapticPulse", + "returntype": "void", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "eTargetPad" ,"paramtype": "ESteamControllerPad"}, +{ "paramname": "usDurationMicroSec" ,"paramtype": "unsigned short"}, +{ "paramname": "usOffMicroSec" ,"paramtype": "unsigned short"}, +{ "paramname": "unRepeat" ,"paramtype": "unsigned short"}, +{ "paramname": "nFlags" ,"paramtype": "unsigned int"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "ShowBindingPanel", + "returntype": "bool", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetInputTypeForHandle", + "returntype": "ESteamInputType", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetControllerForGamepadIndex", + "returntype": "InputHandle_t", + "params": [ +{ "paramname": "nIndex" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetGamepadIndexForController", + "returntype": "int", + "params": [ +{ "paramname": "ulinputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetStringForXboxOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EXboxOrigin"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetGlyphForXboxOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EXboxOrigin"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetActionOriginFromXboxOrigin", + "returntype": "EInputActionOrigin", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "eOrigin" ,"paramtype": "EXboxOrigin"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "TranslateActionOrigin", + "returntype": "EInputActionOrigin", + "params": [ +{ "paramname": "eDestinationInputType" ,"paramtype": "ESteamInputType"}, +{ "paramname": "eSourceOrigin" ,"paramtype": "EInputActionOrigin"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetDeviceBindingRevision", + "returntype": "bool", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"}, +{ "paramname": "pMajor" ,"paramtype": "int *"}, +{ "paramname": "pMinor" ,"paramtype": "int *"} + ] +} +,{ + "classname": "ISteamInput", + "methodname": "GetRemotePlaySessionID", + "returntype": "uint32", + "params": [ +{ "paramname": "inputHandle" ,"paramtype": "InputHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "Init", + "returntype": "bool" +} +,{ + "classname": "ISteamController", + "methodname": "Shutdown", + "returntype": "bool" +} +,{ + "classname": "ISteamController", + "methodname": "RunFrame", + "returntype": "void" +} +,{ + "classname": "ISteamController", + "methodname": "GetConnectedControllers", + "returntype": "int", + "params": [ +{ "paramname": "handlesOut" ,"out_array_count": "STEAM_CONTROLLER_MAX_COUNT" ,"desc": "Receives list of connected controllers" ,"paramtype": "ControllerHandle_t *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetActionSetHandle", + "returntype": "ControllerActionSetHandle_t", + "params": [ +{ "paramname": "pszActionSetName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "ActivateActionSet", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "actionSetHandle" ,"paramtype": "ControllerActionSetHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetCurrentActionSet", + "returntype": "ControllerActionSetHandle_t", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "ActivateActionSetLayer", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "actionSetLayerHandle" ,"paramtype": "ControllerActionSetHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "DeactivateActionSetLayer", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "actionSetLayerHandle" ,"paramtype": "ControllerActionSetHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "DeactivateAllActionSetLayers", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetActiveActionSetLayers", + "returntype": "int", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "handlesOut" ,"out_array_count": "STEAM_CONTROLLER_MAX_ACTIVE_LAYERS" ,"desc": "Receives list of active layers" ,"paramtype": "ControllerActionSetHandle_t *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetDigitalActionHandle", + "returntype": "ControllerDigitalActionHandle_t", + "params": [ +{ "paramname": "pszActionName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetDigitalActionData", + "returntype": "struct InputDigitalActionData_t", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "digitalActionHandle" ,"paramtype": "ControllerDigitalActionHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetDigitalActionOrigins", + "returntype": "int", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "actionSetHandle" ,"paramtype": "ControllerActionSetHandle_t"}, +{ "paramname": "digitalActionHandle" ,"paramtype": "ControllerDigitalActionHandle_t"}, +{ "paramname": "originsOut" ,"out_array_count": "STEAM_CONTROLLER_MAX_ORIGINS" ,"desc": "Receives list of aciton origins" ,"paramtype": "EControllerActionOrigin *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetAnalogActionHandle", + "returntype": "ControllerAnalogActionHandle_t", + "params": [ +{ "paramname": "pszActionName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetAnalogActionData", + "returntype": "struct InputAnalogActionData_t", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "analogActionHandle" ,"paramtype": "ControllerAnalogActionHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetAnalogActionOrigins", + "returntype": "int", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "actionSetHandle" ,"paramtype": "ControllerActionSetHandle_t"}, +{ "paramname": "analogActionHandle" ,"paramtype": "ControllerAnalogActionHandle_t"}, +{ "paramname": "originsOut" ,"out_array_count": "STEAM_CONTROLLER_MAX_ORIGINS" ,"desc": "Receives list of action origins" ,"paramtype": "EControllerActionOrigin *"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetGlyphForActionOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EControllerActionOrigin"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetStringForActionOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EControllerActionOrigin"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "StopAnalogActionMomentum", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "eAction" ,"paramtype": "ControllerAnalogActionHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetMotionData", + "returntype": "struct InputMotionData_t", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "TriggerHapticPulse", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "eTargetPad" ,"paramtype": "ESteamControllerPad"}, +{ "paramname": "usDurationMicroSec" ,"paramtype": "unsigned short"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "TriggerRepeatedHapticPulse", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "eTargetPad" ,"paramtype": "ESteamControllerPad"}, +{ "paramname": "usDurationMicroSec" ,"paramtype": "unsigned short"}, +{ "paramname": "usOffMicroSec" ,"paramtype": "unsigned short"}, +{ "paramname": "unRepeat" ,"paramtype": "unsigned short"}, +{ "paramname": "nFlags" ,"paramtype": "unsigned int"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "TriggerVibration", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "usLeftSpeed" ,"paramtype": "unsigned short"}, +{ "paramname": "usRightSpeed" ,"paramtype": "unsigned short"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "SetLEDColor", + "returntype": "void", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "nColorR" ,"paramtype": "uint8"}, +{ "paramname": "nColorG" ,"paramtype": "uint8"}, +{ "paramname": "nColorB" ,"paramtype": "uint8"}, +{ "paramname": "nFlags" ,"paramtype": "unsigned int"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "ShowBindingPanel", + "returntype": "bool", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetInputTypeForHandle", + "returntype": "ESteamInputType", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetControllerForGamepadIndex", + "returntype": "ControllerHandle_t", + "params": [ +{ "paramname": "nIndex" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetGamepadIndexForController", + "returntype": "int", + "params": [ +{ "paramname": "ulControllerHandle" ,"paramtype": "ControllerHandle_t"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetStringForXboxOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EXboxOrigin"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetGlyphForXboxOrigin", + "returntype": "const char *", + "params": [ +{ "paramname": "eOrigin" ,"paramtype": "EXboxOrigin"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetActionOriginFromXboxOrigin", + "returntype": "EControllerActionOrigin", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "eOrigin" ,"paramtype": "EXboxOrigin"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "TranslateActionOrigin", + "returntype": "EControllerActionOrigin", + "params": [ +{ "paramname": "eDestinationInputType" ,"paramtype": "ESteamInputType"}, +{ "paramname": "eSourceOrigin" ,"paramtype": "EControllerActionOrigin"} + ] +} +,{ + "classname": "ISteamController", + "methodname": "GetControllerBindingRevision", + "returntype": "bool", + "params": [ +{ "paramname": "controllerHandle" ,"paramtype": "ControllerHandle_t"}, +{ "paramname": "pMajor" ,"paramtype": "int *"}, +{ "paramname": "pMinor" ,"paramtype": "int *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "CreateQueryUserUGCRequest", + "returntype": "UGCQueryHandle_t", + "params": [ +{ "paramname": "unAccountID" ,"paramtype": "AccountID_t"}, +{ "paramname": "eListType" ,"paramtype": "EUserUGCList"}, +{ "paramname": "eMatchingUGCType" ,"paramtype": "EUGCMatchingUGCType"}, +{ "paramname": "eSortOrder" ,"paramtype": "EUserUGCListSortOrder"}, +{ "paramname": "nCreatorAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "nConsumerAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "unPage" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "CreateQueryAllUGCRequest", + "returntype": "UGCQueryHandle_t", + "params": [ +{ "paramname": "eQueryType" ,"paramtype": "EUGCQuery"}, +{ "paramname": "eMatchingeMatchingUGCTypeFileType" ,"paramtype": "EUGCMatchingUGCType"}, +{ "paramname": "nCreatorAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "nConsumerAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "unPage" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "CreateQueryAllUGCRequest", + "returntype": "UGCQueryHandle_t", + "params": [ +{ "paramname": "eQueryType" ,"paramtype": "EUGCQuery"}, +{ "paramname": "eMatchingeMatchingUGCTypeFileType" ,"paramtype": "EUGCMatchingUGCType"}, +{ "paramname": "nCreatorAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "nConsumerAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "pchCursor" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "CreateQueryUGCDetailsRequest", + "returntype": "UGCQueryHandle_t", + "params": [ +{ "paramname": "pvecPublishedFileID" ,"paramtype": "PublishedFileId_t *"}, +{ "paramname": "unNumPublishedFileIDs" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SendQueryUGCRequest", "callresult": "SteamUGCQueryCompleted_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCResult", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pDetails" ,"paramtype": "struct SteamUGCDetails_t *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCPreviewURL", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pchURL" ,"out_string_count": "cchURLSize" ,"paramtype": "char *"}, +{ "paramname": "cchURLSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCMetadata", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pchMetadata" ,"out_string_count": "cchMetadatasize" ,"paramtype": "char *"}, +{ "paramname": "cchMetadatasize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCChildren", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pvecPublishedFileID" ,"paramtype": "PublishedFileId_t *"}, +{ "paramname": "cMaxEntries" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCStatistic", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "eStatType" ,"paramtype": "EItemStatistic"}, +{ "paramname": "pStatValue" ,"paramtype": "uint64 *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCNumAdditionalPreviews", + "returntype": "uint32", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCAdditionalPreview", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "previewIndex" ,"paramtype": "uint32"}, +{ "paramname": "pchURLOrVideoID" ,"out_string_count": "cchURLSize" ,"paramtype": "char *"}, +{ "paramname": "cchURLSize" ,"paramtype": "uint32"}, +{ "paramname": "pchOriginalFileName" ,"out_string_count": "cchURLSize" ,"paramtype": "char *"}, +{ "paramname": "cchOriginalFileNameSize" ,"paramtype": "uint32"}, +{ "paramname": "pPreviewType" ,"paramtype": "EItemPreviewType *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCNumKeyValueTags", + "returntype": "uint32", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCKeyValueTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "keyValueTagIndex" ,"paramtype": "uint32"}, +{ "paramname": "pchKey" ,"out_string_count": "cchKeySize" ,"paramtype": "char *"}, +{ "paramname": "cchKeySize" ,"paramtype": "uint32"}, +{ "paramname": "pchValue" ,"out_string_count": "cchValueSize" ,"paramtype": "char *"}, +{ "paramname": "cchValueSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetQueryUGCKeyValueTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"out_string_count": "cchValueSize" ,"paramtype": "char *"}, +{ "paramname": "cchValueSize" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "ReleaseQueryUGCRequest", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddRequiredTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "pTagName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddExcludedTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "pTagName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnOnlyIDs", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnOnlyIDs" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnKeyValueTags", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnKeyValueTags" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnLongDescription", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnLongDescription" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnMetadata", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnMetadata" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnChildren", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnChildren" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnAdditionalPreviews", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnAdditionalPreviews" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnTotalOnly", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bReturnTotalOnly" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetReturnPlaytimeStats", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "unDays" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetLanguage", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "pchLanguage" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetAllowCachedResponse", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "unMaxAgeSeconds" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetCloudFileNameFilter", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "pMatchCloudFileName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetMatchAnyTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "bMatchAnyTag" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetSearchText", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "pSearchText" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetRankedByTrendDays", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "unDays" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddRequiredKeyValueTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCQueryHandle_t"}, +{ "paramname": "pKey" ,"paramtype": "const char *"}, +{ "paramname": "pValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RequestUGCDetails", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "unMaxAgeSeconds" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "CreateItem", "callresult": "CreateItemResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nConsumerAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "eFileType" ,"paramtype": "EWorkshopFileType"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "StartItemUpdate", + "returntype": "UGCUpdateHandle_t", + "params": [ +{ "paramname": "nConsumerAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemTitle", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchTitle" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemDescription", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchDescription" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemUpdateLanguage", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchLanguage" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemMetadata", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchMetaData" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemVisibility", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "eVisibility" ,"paramtype": "ERemoteStoragePublishedFileVisibility"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemTags", + "returntype": "bool", + "params": [ +{ "paramname": "updateHandle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pTags" ,"paramtype": "const struct SteamParamStringArray_t *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemContent", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pszContentFolder" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetItemPreview", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pszPreviewFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetAllowLegacyUpload", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "bAllowLegacyUpload" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RemoveAllItemKeyValueTags", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RemoveItemKeyValueTags", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddItemKeyValueTag", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddItemPreviewFile", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pszPreviewFile" ,"paramtype": "const char *"}, +{ "paramname": "type" ,"paramtype": "EItemPreviewType"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddItemPreviewVideo", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pszVideoID" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "UpdateItemPreviewFile", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pszPreviewFile" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "UpdateItemPreviewVideo", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"}, +{ "paramname": "pszVideoID" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RemoveItemPreview", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "index" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SubmitItemUpdate", "callresult": "SubmitItemUpdateResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "pchChangeNote" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetItemUpdateProgress", + "returntype": "EItemUpdateStatus", + "params": [ +{ "paramname": "handle" ,"paramtype": "UGCUpdateHandle_t"}, +{ "paramname": "punBytesProcessed" ,"paramtype": "uint64 *"}, +{ "paramname": "punBytesTotal" ,"paramtype": "uint64 *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SetUserItemVote", "callresult": "SetUserItemVoteResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "bVoteUp" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetUserItemVote", "callresult": "GetUserItemVoteResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddItemToFavorites", "callresult": "UserFavoriteItemsListChanged_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RemoveItemFromFavorites", "callresult": "UserFavoriteItemsListChanged_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SubscribeItem", "callresult": "RemoteStorageSubscribePublishedFileResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "UnsubscribeItem", "callresult": "RemoteStorageUnsubscribePublishedFileResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetNumSubscribedItems", + "returntype": "uint32" +} +,{ + "classname": "ISteamUGC", + "methodname": "GetSubscribedItems", + "returntype": "uint32", + "params": [ +{ "paramname": "pvecPublishedFileID" ,"paramtype": "PublishedFileId_t *"}, +{ "paramname": "cMaxEntries" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetItemState", + "returntype": "uint32", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetItemInstallInfo", + "returntype": "bool", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "punSizeOnDisk" ,"paramtype": "uint64 *"}, +{ "paramname": "pchFolder" ,"out_string_count": "cchFolderSize" ,"paramtype": "char *"}, +{ "paramname": "cchFolderSize" ,"paramtype": "uint32"}, +{ "paramname": "punTimeStamp" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetItemDownloadInfo", + "returntype": "bool", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "punBytesDownloaded" ,"paramtype": "uint64 *"}, +{ "paramname": "punBytesTotal" ,"paramtype": "uint64 *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "DownloadItem", + "returntype": "bool", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "bHighPriority" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "BInitWorkshopForGameServer", + "returntype": "bool", + "params": [ +{ "paramname": "unWorkshopDepotID" ,"paramtype": "DepotId_t"}, +{ "paramname": "pszFolder" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "SuspendDownloads", + "returntype": "void", + "params": [ +{ "paramname": "bSuspend" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "StartPlaytimeTracking", "callresult": "StartPlaytimeTrackingResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pvecPublishedFileID" ,"paramtype": "PublishedFileId_t *"}, +{ "paramname": "unNumPublishedFileIDs" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "StopPlaytimeTracking", "callresult": "StopPlaytimeTrackingResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pvecPublishedFileID" ,"paramtype": "PublishedFileId_t *"}, +{ "paramname": "unNumPublishedFileIDs" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "StopPlaytimeTrackingForAllItems", "callresult": "StopPlaytimeTrackingResult_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamUGC", + "methodname": "AddDependency", "callresult": "AddUGCDependencyResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nParentPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "nChildPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RemoveDependency", "callresult": "RemoveUGCDependencyResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nParentPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "nChildPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "AddAppDependency", "callresult": "AddAppDependencyResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "RemoveAppDependency", "callresult": "RemoveAppDependencyResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"}, +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "GetAppDependencies", "callresult": "GetAppDependenciesResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamUGC", + "methodname": "DeleteItem", "callresult": "DeleteItemResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "nPublishedFileID" ,"paramtype": "PublishedFileId_t"} + ] +} +,{ + "classname": "ISteamAppList", + "methodname": "GetNumInstalledApps", + "returntype": "uint32" +} +,{ + "classname": "ISteamAppList", + "methodname": "GetInstalledApps", + "returntype": "uint32", + "params": [ +{ "paramname": "pvecAppID" ,"paramtype": "AppId_t *"}, +{ "paramname": "unMaxAppIDs" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamAppList", + "methodname": "GetAppName", + "returntype": "int", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "pchName" ,"out_string": " " ,"paramtype": "char *"}, +{ "paramname": "cchNameMax" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamAppList", + "methodname": "GetAppInstallDir", + "returntype": "int", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "pchDirectory" ,"paramtype": "char *"}, +{ "paramname": "cchNameMax" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamAppList", + "methodname": "GetAppBuildId", + "returntype": "int", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "DestructISteamHTMLSurface", + "returntype": "void" +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "Init", + "returntype": "bool" +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "Shutdown", + "returntype": "bool" +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "CreateBrowser", "callresult": "HTML_BrowserReady_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pchUserAgent" ,"paramtype": "const char *"}, +{ "paramname": "pchUserCSS" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "RemoveBrowser", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "LoadURL", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "pchURL" ,"paramtype": "const char *"}, +{ "paramname": "pchPostData" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetSize", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "unWidth" ,"paramtype": "uint32"}, +{ "paramname": "unHeight" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "StopLoad", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "Reload", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "GoBack", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "GoForward", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "AddHeader", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "ExecuteJavascript", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "pchScript" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "MouseUp", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "eMouseButton" ,"paramtype": "ISteamHTMLSurface::EHTMLMouseButton"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "MouseDown", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "eMouseButton" ,"paramtype": "ISteamHTMLSurface::EHTMLMouseButton"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "MouseDoubleClick", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "eMouseButton" ,"paramtype": "ISteamHTMLSurface::EHTMLMouseButton"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "MouseMove", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "x" ,"paramtype": "int"}, +{ "paramname": "y" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "MouseWheel", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "nDelta" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "KeyDown", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "nNativeKeyCode" ,"paramtype": "uint32"}, +{ "paramname": "eHTMLKeyModifiers" ,"paramtype": "ISteamHTMLSurface::EHTMLKeyModifiers"}, +{ "paramname": "bIsSystemKey" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "KeyUp", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "nNativeKeyCode" ,"paramtype": "uint32"}, +{ "paramname": "eHTMLKeyModifiers" ,"paramtype": "ISteamHTMLSurface::EHTMLKeyModifiers"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "KeyChar", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "cUnicodeChar" ,"paramtype": "uint32"}, +{ "paramname": "eHTMLKeyModifiers" ,"paramtype": "ISteamHTMLSurface::EHTMLKeyModifiers"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetHorizontalScroll", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "nAbsolutePixelScroll" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetVerticalScroll", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "nAbsolutePixelScroll" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetKeyFocus", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "bHasKeyFocus" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "ViewSource", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "CopyToClipboard", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "PasteFromClipboard", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "Find", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "pchSearchStr" ,"paramtype": "const char *"}, +{ "paramname": "bCurrentlyInFind" ,"paramtype": "bool"}, +{ "paramname": "bReverse" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "StopFind", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "GetLinkAtPosition", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "x" ,"paramtype": "int"}, +{ "paramname": "y" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetCookie", + "returntype": "void", + "params": [ +{ "paramname": "pchHostname" ,"paramtype": "const char *"}, +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"}, +{ "paramname": "pchPath" ,"paramtype": "const char *"}, +{ "paramname": "nExpires" ,"paramtype": "RTime32"}, +{ "paramname": "bSecure" ,"paramtype": "bool"}, +{ "paramname": "bHTTPOnly" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetPageScaleFactor", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "flZoom" ,"paramtype": "float"}, +{ "paramname": "nPointX" ,"paramtype": "int"}, +{ "paramname": "nPointY" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetBackgroundMode", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "bBackgroundMode" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "SetDPIScalingFactor", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "flDPIScaling" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "OpenDeveloperTools", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "AllowStartRequest", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "bAllowed" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamHTMLSurface", + "methodname": "JSDialogResponse", + "returntype": "void", + "params": [ +{ "paramname": "unBrowserHandle" ,"paramtype": "HHTMLBrowser"}, +{ "paramname": "bResult" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetResultStatus", "desc": "Find out the status of an asynchronous inventory result handle.", + "returntype": "EResult", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetResultItems", "desc": "Copies the contents of a result set into a flat array. The specific contents of the result set depend on which query which was used.", + "returntype": "bool", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"}, +{ "paramname": "pOutItemsArray" ,"out_array_count": "punOutItemsArraySize" ,"desc": "Output array" ,"paramtype": "struct SteamItemDetails_t *"}, +{ "paramname": "punOutItemsArraySize" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetResultItemProperty", + "returntype": "bool", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"}, +{ "paramname": "unItemIndex" ,"paramtype": "uint32"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"}, +{ "paramname": "pchValueBuffer" ,"out_string_count": "punValueBufferSizeOut" ,"paramtype": "char *"}, +{ "paramname": "punValueBufferSizeOut" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetResultTimestamp", "desc": "Returns the server time at which the result was generated. Compare against the value of IClientUtils::GetServerRealTime() to determine age.", + "returntype": "uint32", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "CheckResultSteamID", "desc": "Returns true if the result belongs to the target steam ID or false if the result does not. This is important when using DeserializeResult to verify that a remote player is not pretending to have a different users inventory.", + "returntype": "bool", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"}, +{ "paramname": "steamIDExpected" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "DestroyResult", "desc": "Destroys a result handle and frees all associated memory.", + "returntype": "void", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetAllItems", "desc": "Captures the entire state of the current users Steam inventory.", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetItemsByID", "desc": "Captures the state of a subset of the current users Steam inventory identified by an array of item instance IDs.", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "pInstanceIDs" ,"array_count": "unCountInstanceIDs" ,"paramtype": "const SteamItemInstanceID_t *"}, +{ "paramname": "unCountInstanceIDs" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SerializeResult", + "returntype": "bool", + "params": [ +{ "paramname": "resultHandle" ,"paramtype": "SteamInventoryResult_t"}, +{ "paramname": "pOutBuffer" ,"out_buffer_count": "punOutBufferSize" ,"paramtype": "void *"}, +{ "paramname": "punOutBufferSize" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "DeserializeResult", + "returntype": "bool", + "params": [ +{ "paramname": "pOutResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "pBuffer" ,"buffer_count": "punOutBufferSize" ,"paramtype": "const void *"}, +{ "paramname": "unBufferSize" ,"paramtype": "uint32"}, +{ "paramname": "bRESERVED_MUST_BE_FALSE" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GenerateItems", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "pArrayItemDefs" ,"array_count": "unArrayLength" ,"paramtype": "const SteamItemDef_t *"}, +{ "paramname": "punArrayQuantity" ,"array_count": "unArrayLength" ,"paramtype": "const uint32 *"}, +{ "paramname": "unArrayLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GrantPromoItems", "desc": "GrantPromoItems() checks the list of promotional items for which the user may be eligible and grants the items (one time only).", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "AddPromoItem", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "itemDef" ,"paramtype": "SteamItemDef_t"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "AddPromoItems", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "pArrayItemDefs" ,"array_count": "unArrayLength" ,"paramtype": "const SteamItemDef_t *"}, +{ "paramname": "unArrayLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "ConsumeItem", "desc": "ConsumeItem() removes items from the inventory permanently.", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "itemConsume" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "unQuantity" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "ExchangeItems", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "pArrayGenerate" ,"array_count": "unArrayGenerateLength" ,"paramtype": "const SteamItemDef_t *"}, +{ "paramname": "punArrayGenerateQuantity" ,"array_count": "unArrayGenerateLength" ,"paramtype": "const uint32 *"}, +{ "paramname": "unArrayGenerateLength" ,"paramtype": "uint32"}, +{ "paramname": "pArrayDestroy" ,"array_count": "unArrayDestroyLength" ,"paramtype": "const SteamItemInstanceID_t *"}, +{ "paramname": "punArrayDestroyQuantity" ,"array_count": "unArrayDestroyLength" ,"paramtype": "const uint32 *"}, +{ "paramname": "unArrayDestroyLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "TransferItemQuantity", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "itemIdSource" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "unQuantity" ,"paramtype": "uint32"}, +{ "paramname": "itemIdDest" ,"paramtype": "SteamItemInstanceID_t"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SendItemDropHeartbeat", "desc": "Deprecated method. Playtime accounting is performed on the Steam servers.", + "returntype": "void" +} +,{ + "classname": "ISteamInventory", + "methodname": "TriggerItemDrop", "desc": "Playtime credit must be consumed and turned into item drops by your game.", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "dropListDefinition" ,"paramtype": "SteamItemDef_t"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "TradeItems", + "returntype": "bool", + "params": [ +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"}, +{ "paramname": "steamIDTradePartner" ,"paramtype": "class CSteamID"}, +{ "paramname": "pArrayGive" ,"array_count": "nArrayGiveLength" ,"paramtype": "const SteamItemInstanceID_t *"}, +{ "paramname": "pArrayGiveQuantity" ,"array_count": "nArrayGiveLength" ,"paramtype": "const uint32 *"}, +{ "paramname": "nArrayGiveLength" ,"paramtype": "uint32"}, +{ "paramname": "pArrayGet" ,"array_count": "nArrayGetLength" ,"paramtype": "const SteamItemInstanceID_t *"}, +{ "paramname": "pArrayGetQuantity" ,"array_count": "nArrayGetLength" ,"paramtype": "const uint32 *"}, +{ "paramname": "nArrayGetLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "LoadItemDefinitions", "desc": "LoadItemDefinitions triggers the automatic load and refresh of item definitions.", + "returntype": "bool" +} +,{ + "classname": "ISteamInventory", + "methodname": "GetItemDefinitionIDs", + "returntype": "bool", + "params": [ +{ "paramname": "pItemDefIDs" ,"out_array_count": "punItemDefIDsArraySize" ,"desc": "List of item definition IDs" ,"paramtype": "SteamItemDef_t *"}, +{ "paramname": "punItemDefIDsArraySize" ,"desc": "Size of array is passed in and actual size used is returned in this param" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetItemDefinitionProperty", + "returntype": "bool", + "params": [ +{ "paramname": "iDefinition" ,"paramtype": "SteamItemDef_t"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"}, +{ "paramname": "pchValueBuffer" ,"out_string_count": "punValueBufferSizeOut" ,"paramtype": "char *"}, +{ "paramname": "punValueBufferSizeOut" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "RequestEligiblePromoItemDefinitionsIDs", "callresult": "SteamInventoryEligiblePromoItemDefIDs_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetEligiblePromoItemDefinitionIDs", + "returntype": "bool", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"}, +{ "paramname": "pItemDefIDs" ,"out_array_count": "punItemDefIDsArraySize" ,"desc": "List of item definition IDs" ,"paramtype": "SteamItemDef_t *"}, +{ "paramname": "punItemDefIDsArraySize" ,"desc": "Size of array is passed in and actual size used is returned in this param" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "StartPurchase", "callresult": "SteamInventoryStartPurchaseResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "pArrayItemDefs" ,"array_count": "unArrayLength" ,"paramtype": "const SteamItemDef_t *"}, +{ "paramname": "punArrayQuantity" ,"array_count": "unArrayLength" ,"paramtype": "const uint32 *"}, +{ "paramname": "unArrayLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "RequestPrices", "callresult": "SteamInventoryRequestPricesResult_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamInventory", + "methodname": "GetNumItemsWithPrices", + "returntype": "uint32" +} +,{ + "classname": "ISteamInventory", + "methodname": "GetItemsWithPrices", + "returntype": "bool", + "params": [ +{ "paramname": "pArrayItemDefs" ,"out_array_count": "pArrayItemDefs" ,"desc": "Items with prices" ,"paramtype": "SteamItemDef_t *"}, +{ "paramname": "pCurrentPrices" ,"out_array_count": "pPrices" ,"desc": "List of prices for the given item defs" ,"paramtype": "uint64 *"}, +{ "paramname": "pBasePrices" ,"out_array_count": "pPrices" ,"desc": "List of prices for the given item defs" ,"paramtype": "uint64 *"}, +{ "paramname": "unArrayLength" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "GetItemPrice", + "returntype": "bool", + "params": [ +{ "paramname": "iDefinition" ,"paramtype": "SteamItemDef_t"}, +{ "paramname": "pCurrentPrice" ,"paramtype": "uint64 *"}, +{ "paramname": "pBasePrice" ,"paramtype": "uint64 *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "StartUpdateProperties", + "returntype": "SteamInventoryUpdateHandle_t" +} +,{ + "classname": "ISteamInventory", + "methodname": "RemoveProperty", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "SteamInventoryUpdateHandle_t"}, +{ "paramname": "nItemID" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SetProperty", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "SteamInventoryUpdateHandle_t"}, +{ "paramname": "nItemID" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"}, +{ "paramname": "pchPropertyValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SetProperty", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "SteamInventoryUpdateHandle_t"}, +{ "paramname": "nItemID" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"}, +{ "paramname": "bValue" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SetProperty", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "SteamInventoryUpdateHandle_t"}, +{ "paramname": "nItemID" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"}, +{ "paramname": "nValue" ,"paramtype": "int64"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SetProperty", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "SteamInventoryUpdateHandle_t"}, +{ "paramname": "nItemID" ,"paramtype": "SteamItemInstanceID_t"}, +{ "paramname": "pchPropertyName" ,"paramtype": "const char *"}, +{ "paramname": "flValue" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamInventory", + "methodname": "SubmitUpdateProperties", + "returntype": "bool", + "params": [ +{ "paramname": "handle" ,"paramtype": "SteamInventoryUpdateHandle_t"}, +{ "paramname": "pResultHandle" ,"paramtype": "SteamInventoryResult_t *"} + ] +} +,{ + "classname": "ISteamVideo", + "methodname": "GetVideoURL", + "returntype": "void", + "params": [ +{ "paramname": "unVideoAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamVideo", + "methodname": "IsBroadcasting", + "returntype": "bool", + "params": [ +{ "paramname": "pnNumViewers" ,"paramtype": "int *"} + ] +} +,{ + "classname": "ISteamVideo", + "methodname": "GetOPFSettings", "callback": "GetOPFSettingsResult_t", + "returntype": "void", + "params": [ +{ "paramname": "unVideoAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamVideo", + "methodname": "GetOPFStringForApp", + "returntype": "bool", + "params": [ +{ "paramname": "unVideoAppID" ,"paramtype": "AppId_t"}, +{ "paramname": "pchBuffer" ,"paramtype": "char *"}, +{ "paramname": "pnBufferSize" ,"paramtype": "int32 *"} + ] +} +,{ + "classname": "ISteamTV", + "methodname": "IsBroadcasting", + "returntype": "bool", + "params": [ +{ "paramname": "pnNumViewers" ,"paramtype": "int *"} + ] +} +,{ + "classname": "ISteamTV", + "methodname": "AddBroadcastGameData", + "returntype": "void", + "params": [ +{ "paramname": "pchKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamTV", + "methodname": "RemoveBroadcastGameData", + "returntype": "void", + "params": [ +{ "paramname": "pchKey" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamTV", + "methodname": "AddTimelineMarker", + "returntype": "void", + "params": [ +{ "paramname": "pchTemplateName" ,"paramtype": "const char *"}, +{ "paramname": "bPersistent" ,"paramtype": "bool"}, +{ "paramname": "nColorR" ,"paramtype": "uint8"}, +{ "paramname": "nColorG" ,"paramtype": "uint8"}, +{ "paramname": "nColorB" ,"paramtype": "uint8"} + ] +} +,{ + "classname": "ISteamTV", + "methodname": "RemoveTimelineMarker", + "returntype": "void" +} +,{ + "classname": "ISteamTV", + "methodname": "AddRegion", + "returntype": "uint32", + "params": [ +{ "paramname": "pchElementName" ,"paramtype": "const char *"}, +{ "paramname": "pchTimelineDataSection" ,"paramtype": "const char *"}, +{ "paramname": "pSteamTVRegion" ,"paramtype": "const struct SteamTVRegion_t *"}, +{ "paramname": "eSteamTVRegionBehavior" ,"paramtype": "ESteamTVRegionBehavior"} + ] +} +,{ + "classname": "ISteamTV", + "methodname": "RemoveRegion", + "returntype": "void", + "params": [ +{ "paramname": "unRegionHandle" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamParentalSettings", + "methodname": "BIsParentalLockEnabled", + "returntype": "bool" +} +,{ + "classname": "ISteamParentalSettings", + "methodname": "BIsParentalLockLocked", + "returntype": "bool" +} +,{ + "classname": "ISteamParentalSettings", + "methodname": "BIsAppBlocked", + "returntype": "bool", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamParentalSettings", + "methodname": "BIsAppInBlockList", + "returntype": "bool", + "params": [ +{ "paramname": "nAppID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamParentalSettings", + "methodname": "BIsFeatureBlocked", + "returntype": "bool", + "params": [ +{ "paramname": "eFeature" ,"paramtype": "EParentalFeature"} + ] +} +,{ + "classname": "ISteamParentalSettings", + "methodname": "BIsFeatureInBlockList", + "returntype": "bool", + "params": [ +{ "paramname": "eFeature" ,"paramtype": "EParentalFeature"} + ] +} +,{ + "classname": "ISteamRemotePlay", + "methodname": "GetSessionCount", + "returntype": "uint32" +} +,{ + "classname": "ISteamRemotePlay", + "methodname": "GetSessionID", + "returntype": "uint32", + "params": [ +{ "paramname": "iSessionIndex" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamRemotePlay", + "methodname": "GetSessionSteamID", + "returntype": "class CSteamID", + "params": [ +{ "paramname": "unSessionID" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemotePlay", + "methodname": "GetSessionClientName", + "returntype": "const char *", + "params": [ +{ "paramname": "unSessionID" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemotePlay", + "methodname": "GetSessionClientFormFactor", + "returntype": "ESteamDeviceFormFactor", + "params": [ +{ "paramname": "unSessionID" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamRemotePlay", + "methodname": "BGetSessionClientResolution", + "returntype": "bool", + "params": [ +{ "paramname": "unSessionID" ,"paramtype": "uint32"}, +{ "paramname": "pnResolutionX" ,"paramtype": "int *"}, +{ "paramname": "pnResolutionY" ,"paramtype": "int *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "InitGameServer", + "returntype": "bool", + "params": [ +{ "paramname": "unIP" ,"paramtype": "uint32"}, +{ "paramname": "usGamePort" ,"paramtype": "uint16"}, +{ "paramname": "usQueryPort" ,"paramtype": "uint16"}, +{ "paramname": "unFlags" ,"paramtype": "uint32"}, +{ "paramname": "nGameAppId" ,"paramtype": "AppId_t"}, +{ "paramname": "pchVersionString" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetProduct", + "returntype": "void", + "params": [ +{ "paramname": "pszProduct" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetGameDescription", + "returntype": "void", + "params": [ +{ "paramname": "pszGameDescription" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetModDir", + "returntype": "void", + "params": [ +{ "paramname": "pszModDir" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetDedicatedServer", + "returntype": "void", + "params": [ +{ "paramname": "bDedicated" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "LogOn", + "returntype": "void", + "params": [ +{ "paramname": "pszToken" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "LogOnAnonymous", + "returntype": "void" +} +,{ + "classname": "ISteamGameServer", + "methodname": "LogOff", + "returntype": "void" +} +,{ + "classname": "ISteamGameServer", + "methodname": "BLoggedOn", + "returntype": "bool" +} +,{ + "classname": "ISteamGameServer", + "methodname": "BSecure", + "returntype": "bool" +} +,{ + "classname": "ISteamGameServer", + "methodname": "GetSteamID", + "returntype": "class CSteamID" +} +,{ + "classname": "ISteamGameServer", + "methodname": "WasRestartRequested", + "returntype": "bool" +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetMaxPlayerCount", + "returntype": "void", + "params": [ +{ "paramname": "cPlayersMax" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetBotPlayerCount", + "returntype": "void", + "params": [ +{ "paramname": "cBotplayers" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetServerName", + "returntype": "void", + "params": [ +{ "paramname": "pszServerName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetMapName", + "returntype": "void", + "params": [ +{ "paramname": "pszMapName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetPasswordProtected", + "returntype": "void", + "params": [ +{ "paramname": "bPasswordProtected" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetSpectatorPort", + "returntype": "void", + "params": [ +{ "paramname": "unSpectatorPort" ,"paramtype": "uint16"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetSpectatorServerName", + "returntype": "void", + "params": [ +{ "paramname": "pszSpectatorServerName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "ClearAllKeyValues", + "returntype": "void" +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetKeyValue", + "returntype": "void", + "params": [ +{ "paramname": "pKey" ,"paramtype": "const char *"}, +{ "paramname": "pValue" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetGameTags", + "returntype": "void", + "params": [ +{ "paramname": "pchGameTags" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetGameData", + "returntype": "void", + "params": [ +{ "paramname": "pchGameData" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetRegion", + "returntype": "void", + "params": [ +{ "paramname": "pszRegion" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SendUserConnectAndAuthenticate", + "returntype": "bool", + "params": [ +{ "paramname": "unIPClient" ,"paramtype": "uint32"}, +{ "paramname": "pvAuthBlob" ,"paramtype": "const void *"}, +{ "paramname": "cubAuthBlobSize" ,"paramtype": "uint32"}, +{ "paramname": "pSteamIDUser" ,"paramtype": "class CSteamID *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "CreateUnauthenticatedUserConnection", + "returntype": "class CSteamID" +} +,{ + "classname": "ISteamGameServer", + "methodname": "SendUserDisconnect", + "returntype": "void", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "BUpdateUserData", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchPlayerName" ,"paramtype": "const char *"}, +{ "paramname": "uScore" ,"paramtype": "uint32"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "GetAuthSessionTicket", + "returntype": "HAuthTicket", + "params": [ +{ "paramname": "pTicket" ,"paramtype": "void *"}, +{ "paramname": "cbMaxTicket" ,"paramtype": "int"}, +{ "paramname": "pcbTicket" ,"paramtype": "uint32 *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "BeginAuthSession", + "returntype": "EBeginAuthSessionResult", + "params": [ +{ "paramname": "pAuthTicket" ,"paramtype": "const void *"}, +{ "paramname": "cbAuthTicket" ,"paramtype": "int"}, +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "EndAuthSession", + "returntype": "void", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "CancelAuthTicket", + "returntype": "void", + "params": [ +{ "paramname": "hAuthTicket" ,"paramtype": "HAuthTicket"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "UserHasLicenseForApp", + "returntype": "EUserHasLicenseForAppResult", + "params": [ +{ "paramname": "steamID" ,"paramtype": "class CSteamID"}, +{ "paramname": "appID" ,"paramtype": "AppId_t"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "RequestUserGroupStatus", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "steamIDGroup" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "GetGameplayStats", + "returntype": "void" +} +,{ + "classname": "ISteamGameServer", + "methodname": "GetServerReputation", "callresult": "GSReputation_t", + "returntype": "SteamAPICall_t" +} +,{ + "classname": "ISteamGameServer", + "methodname": "GetPublicIP", + "returntype": "uint32" +} +,{ + "classname": "ISteamGameServer", + "methodname": "HandleIncomingPacket", + "returntype": "bool", + "params": [ +{ "paramname": "pData" ,"paramtype": "const void *"}, +{ "paramname": "cbData" ,"paramtype": "int"}, +{ "paramname": "srcIP" ,"paramtype": "uint32"}, +{ "paramname": "srcPort" ,"paramtype": "uint16"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "GetNextOutgoingPacket", + "returntype": "int", + "params": [ +{ "paramname": "pOut" ,"paramtype": "void *"}, +{ "paramname": "cbMaxOut" ,"paramtype": "int"}, +{ "paramname": "pNetAdr" ,"paramtype": "uint32 *"}, +{ "paramname": "pPort" ,"paramtype": "uint16 *"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "EnableHeartbeats", + "returntype": "void", + "params": [ +{ "paramname": "bActive" ,"paramtype": "bool"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "SetHeartbeatInterval", + "returntype": "void", + "params": [ +{ "paramname": "iHeartbeatInterval" ,"paramtype": "int"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "ForceHeartbeat", + "returntype": "void" +} +,{ + "classname": "ISteamGameServer", + "methodname": "AssociateWithClan", "callresult": "AssociateWithClanResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDClan" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServer", + "methodname": "ComputeNewPlayerCompatibility", "callresult": "ComputeNewPlayerCompatibilityResult_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDNewPlayer" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "RequestUserStats", "callresult": "GSStatsReceived_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "GetUserStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "int32 *"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "GetUserStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pData" ,"paramtype": "float *"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "GetUserAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "pbAchieved" ,"paramtype": "bool *"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "SetUserStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "nData" ,"paramtype": "int32"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "SetUserStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "fData" ,"paramtype": "float"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "UpdateUserAvgRateStat", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"}, +{ "paramname": "flCountThisSession" ,"paramtype": "float"}, +{ "paramname": "dSessionLength" ,"paramtype": "double"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "SetUserAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "ClearUserAchievement", + "returntype": "bool", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"}, +{ "paramname": "pchName" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "ISteamGameServerStats", + "methodname": "StoreUserStats", "callresult": "GSStatsStored_t", + "returntype": "SteamAPICall_t", + "params": [ +{ "paramname": "steamIDUser" ,"paramtype": "class CSteamID"} + ] +} +] +} \ No newline at end of file diff --git a/public/steam/steam_api_common.h b/public/steam/steam_api_common.h new file mode 100644 index 0000000..cc936de --- /dev/null +++ b/public/steam/steam_api_common.h @@ -0,0 +1,231 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Steamworks SDK minimal include +// +// Defines the minimal set of things we need to use any single interface +// or register for any callback. +// +//============================================================================= + +#ifndef STEAM_API_COMMON_H +#define STEAM_API_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" + +// S_API defines the linkage and calling conventions for steam_api.dll exports +#if defined( _WIN32 ) && !defined( _X360 ) + #if defined( STEAM_API_EXPORTS ) + #define S_API extern "C" __declspec( dllexport ) + #elif defined( STEAM_API_NODLL ) + #define S_API extern "C" + #else + #define S_API extern "C" __declspec( dllimport ) + #endif // STEAM_API_EXPORTS +#elif defined( GNUC ) + #if defined( STEAM_API_EXPORTS ) + #define S_API extern "C" __attribute__ ((visibility("default"))) + #else + #define S_API extern "C" + #endif // STEAM_API_EXPORTS +#else // !WIN32 + #if defined( STEAM_API_EXPORTS ) + #define S_API extern "C" + #else + #define S_API extern "C" + #endif // STEAM_API_EXPORTS +#endif + +#if ( defined(STEAM_API_EXPORTS) || defined(STEAM_API_NODLL) ) && !defined(API_GEN) +#define STEAM_PRIVATE_API( ... ) __VA_ARGS__ +#elif defined(STEAM_API_EXPORTS) && defined(API_GEN) +#define STEAM_PRIVATE_API( ... ) +#else +#define STEAM_PRIVATE_API( ... ) protected: __VA_ARGS__ public: +#endif + +// handle to a communication pipe to the Steam client +typedef int32 HSteamPipe; +// handle to single instance of a steam user +typedef int32 HSteamUser; +// function prototype +#if defined( POSIX ) +#define __cdecl +#endif +extern "C" typedef void (__cdecl *SteamAPIWarningMessageHook_t)(int, const char *); +extern "C" typedef uint32 ( *SteamAPI_CheckCallbackRegistered_t )( int iCallbackNum ); +#if defined( __SNC__ ) + #pragma diag_suppress=1700 // warning 1700: class "%s" has virtual functions but non-virtual destructor +#endif + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// steam callback and call-result helpers +// +// The following macros and classes are used to register your application for +// callbacks and call-results, which are delivered in a predictable manner. +// +// STEAM_CALLBACK macros are meant for use inside of a C++ class definition. +// They map a Steam notification callback directly to a class member function +// which is automatically prototyped as "void func( callback_type *pParam )". +// +// CCallResult is used with specific Steam APIs that return "result handles". +// The handle can be passed to a CCallResult object's Set function, along with +// an object pointer and member-function pointer. The member function will +// be executed once the results of the Steam API call are available. +// +// CCallback and CCallbackManual classes can be used instead of STEAM_CALLBACK +// macros if you require finer control over registration and unregistration. +// +// Callbacks and call-results are queued automatically and are only +// delivered/executed when your application calls SteamAPI_RunCallbacks(). +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// Dispatch all queued Steamworks callbacks. +// +// This is safe to call from multiple threads simultaneously, +// but if you choose to do this, callback code could be executed on any thread. +// One alternative is to call SteamAPI_RunCallbacks from the main thread only, +// and call SteamAPI_ReleaseCurrentThreadMemory regularly on other threads. +S_API void S_CALLTYPE SteamAPI_RunCallbacks(); + +// Declares a callback member function plus a helper member variable which +// registers the callback on object creation and unregisters on destruction. +// The optional fourth 'var' param exists only for backwards-compatibility +// and can be ignored. +#define STEAM_CALLBACK( thisclass, func, .../*callback_type, [deprecated] var*/ ) \ + _STEAM_CALLBACK_SELECT( ( __VA_ARGS__, 4, 3 ), ( /**/, thisclass, func, __VA_ARGS__ ) ) + +// Declares a callback function and a named CCallbackManual variable which +// has Register and Unregister functions instead of automatic registration. +#define STEAM_CALLBACK_MANUAL( thisclass, func, callback_type, var ) \ + CCallbackManual< thisclass, callback_type > var; void func( callback_type *pParam ) + +// Dispatch callbacks relevant to the gameserver client and interfaces. +// To register for these, you need to use STEAM_GAMESERVER_CALLBACK. +// (Or call SetGameserverFlag on your CCallbackBase object.) +S_API void S_CALLTYPE SteamGameServer_RunCallbacks(); + +// Same as STEAM_CALLBACK, but for callbacks on the gameserver interface. +// These will be dispatched during SteamGameServer_RunCallbacks +#define STEAM_GAMESERVER_CALLBACK( thisclass, func, /*callback_type, [deprecated] var*/... ) \ + _STEAM_CALLBACK_SELECT( ( __VA_ARGS__, GS, 3 ), ( this->SetGameserverFlag();, thisclass, func, __VA_ARGS__ ) ) +#define STEAM_GAMESERVER_CALLBACK_MANUAL( thisclass, func, callback_type, var ) \ + CCallbackManual< thisclass, callback_type, true > var; void func( callback_type *pParam ) + +//----------------------------------------------------------------------------- +// Purpose: base for callbacks and call results - internal implementation detail +//----------------------------------------------------------------------------- +class CCallbackBase +{ +public: + CCallbackBase() { m_nCallbackFlags = 0; m_iCallback = 0; } + // don't add a virtual destructor because we export this binary interface across dll's + virtual void Run( void *pvParam ) = 0; + virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) = 0; + int GetICallback() { return m_iCallback; } + virtual int GetCallbackSizeBytes() = 0; + +protected: + enum { k_ECallbackFlagsRegistered = 0x01, k_ECallbackFlagsGameServer = 0x02 }; + uint8 m_nCallbackFlags; + int m_iCallback; + friend class CCallbackMgr; + +private: + CCallbackBase( const CCallbackBase& ); + CCallbackBase& operator=( const CCallbackBase& ); +}; + +//----------------------------------------------------------------------------- +// Purpose: templated base for callbacks - internal implementation detail +//----------------------------------------------------------------------------- +template< int sizeof_P > +class CCallbackImpl : protected CCallbackBase +{ +public: + virtual ~CCallbackImpl() { if ( m_nCallbackFlags & k_ECallbackFlagsRegistered ) SteamAPI_UnregisterCallback( this ); } + void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; } + +protected: + virtual void Run( void *pvParam ) = 0; + virtual void Run( void *pvParam, bool /*bIOFailure*/, SteamAPICall_t /*hSteamAPICall*/ ) { Run( pvParam ); } + virtual int GetCallbackSizeBytes() { return sizeof_P; } +}; + + +//----------------------------------------------------------------------------- +// Purpose: maps a steam async call result to a class member function +// template params: T = local class, P = parameter struct +//----------------------------------------------------------------------------- +template< class T, class P > +class CCallResult : private CCallbackBase +{ +public: + typedef void (T::*func_t)( P*, bool ); + + CCallResult(); + ~CCallResult(); + + void Set( SteamAPICall_t hAPICall, T *p, func_t func ); + bool IsActive() const; + void Cancel(); + + void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; } +private: + virtual void Run( void *pvParam ); + virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ); + virtual int GetCallbackSizeBytes() { return sizeof( P ); } + + SteamAPICall_t m_hAPICall; + T *m_pObj; + func_t m_Func; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: maps a steam callback to a class member function +// template params: T = local class, P = parameter struct, +// bGameserver = listen for gameserver callbacks instead of client callbacks +//----------------------------------------------------------------------------- +template< class T, class P, bool bGameserver = false > +class CCallback : public CCallbackImpl< sizeof( P ) > +{ +public: + typedef void (T::*func_t)(P*); + + // NOTE: If you can't provide the correct parameters at construction time, you should + // use the CCallbackManual callback object (STEAM_CALLBACK_MANUAL macro) instead. + CCallback( T *pObj, func_t func ); + + void Register( T *pObj, func_t func ); + void Unregister(); + +protected: + virtual void Run( void *pvParam ); + + T *m_pObj; + func_t m_Func; +}; + + +//----------------------------------------------------------------------------- +// Purpose: subclass of CCallback which allows default-construction in +// an unregistered state; you must call Register manually +//----------------------------------------------------------------------------- +template< class T, class P, bool bGameServer = false > +class CCallbackManual : public CCallback< T, P, bGameServer > +{ +public: + CCallbackManual() : CCallback< T, P, bGameServer >( nullptr, nullptr ) {} + + // Inherits public Register and Unregister functions from base class +}; + +// Internal implementation details for all of the above +#include "steam_api_internal.h" + +#endif // STEAM_API_COMMON_H diff --git a/public/steam/steam_api_flat.h b/public/steam/steam_api_flat.h new file mode 100644 index 0000000..9bb3e18 --- /dev/null +++ b/public/steam/steam_api_flat.h @@ -0,0 +1,953 @@ +//====== Copyright (c) 1996-2014, Valve Corporation, All rights reserved. ======= +// +// Purpose: Header for flatted SteamAPI. Use this for binding to other languages. +// This file is auto-generated, do not edit it. +// +//============================================================================= + +#ifndef STEAMAPIFLAT_H +#define STEAMAPIFLAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include + + +typedef unsigned char uint8; +typedef unsigned char uint8; +typedef signed char int8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; +typedef int64 lint64; +typedef uint64 ulint64; +typedef uint8 Salt_t[8]; +typedef uint64 GID_t; +typedef uint64 JobID_t; +typedef GID_t TxnID_t; +typedef uint32 PackageId_t; +typedef uint32 BundleId_t; +typedef uint32 AppId_t; +typedef uint64 AssetClassId_t; +typedef uint32 PhysicalItemId_t; +typedef uint32 DepotId_t; +typedef uint32 RTime32; +typedef uint32 CellID_t; +typedef uint64 SteamAPICall_t; +typedef uint32 AccountID_t; +typedef uint32 PartnerId_t; +typedef uint64 ManifestId_t; +typedef uint64 SiteId_t; +typedef uint64 PartyBeaconID_t; +typedef uint32 HAuthTicket; +typedef void * BREAKPAD_HANDLE; +typedef char compile_time_assert_type[1]; +typedef int32 HSteamPipe; +typedef int32 HSteamUser; +typedef int16 FriendsGroupID_t; +typedef void * HServerListRequest; +typedef int HServerQuery; +typedef uint64 UGCHandle_t; +typedef uint64 PublishedFileUpdateHandle_t; +typedef uint64 PublishedFileId_t; +typedef uint64 UGCFileWriteStreamHandle_t; +typedef char compile_time_assert_type[1]; +typedef uint64 SteamLeaderboard_t; +typedef uint64 SteamLeaderboardEntries_t; +typedef uint32 SNetSocket_t; +typedef uint32 SNetListenSocket_t; +typedef uint32 ScreenshotHandle; +typedef uint32 HTTPRequestHandle; +typedef uint32 HTTPCookieContainerHandle; +typedef uint64 InputHandle_t; +typedef uint64 InputActionSetHandle_t; +typedef uint64 InputDigitalActionHandle_t; +typedef uint64 InputAnalogActionHandle_t; +typedef uint64 ControllerHandle_t; +typedef uint64 ControllerActionSetHandle_t; +typedef uint64 ControllerDigitalActionHandle_t; +typedef uint64 ControllerAnalogActionHandle_t; +typedef uint64 UGCQueryHandle_t; +typedef uint64 UGCUpdateHandle_t; +typedef uint32 HHTMLBrowser; +typedef uint64 SteamItemInstanceID_t; +typedef int32 SteamItemDef_t; +typedef int32 SteamInventoryResult_t; +typedef uint64 SteamInventoryUpdateHandle_t; +// OpenVR Constants +int const_k_iSteamUserCallbacks = 100; +int const_k_iSteamGameServerCallbacks = 200; +int const_k_iSteamFriendsCallbacks = 300; +int const_k_iSteamBillingCallbacks = 400; +int const_k_iSteamMatchmakingCallbacks = 500; +int const_k_iSteamContentServerCallbacks = 600; +int const_k_iSteamUtilsCallbacks = 700; +int const_k_iClientFriendsCallbacks = 800; +int const_k_iClientUserCallbacks = 900; +int const_k_iSteamAppsCallbacks = 1000; +int const_k_iSteamUserStatsCallbacks = 1100; +int const_k_iSteamNetworkingCallbacks = 1200; +int const_k_iSteamNetworkingSocketsCallbacks = 1220; +int const_k_iSteamNetworkingMessagesCallbacks = 1250; +int const_k_iSteamNetworkingUtilsCallbacks = 1280; +int const_k_iClientRemoteStorageCallbacks = 1300; +int const_k_iClientDepotBuilderCallbacks = 1400; +int const_k_iSteamGameServerItemsCallbacks = 1500; +int const_k_iClientUtilsCallbacks = 1600; +int const_k_iSteamGameCoordinatorCallbacks = 1700; +int const_k_iSteamGameServerStatsCallbacks = 1800; +int const_k_iSteam2AsyncCallbacks = 1900; +int const_k_iSteamGameStatsCallbacks = 2000; +int const_k_iClientHTTPCallbacks = 2100; +int const_k_iClientScreenshotsCallbacks = 2200; +int const_k_iSteamScreenshotsCallbacks = 2300; +int const_k_iClientAudioCallbacks = 2400; +int const_k_iClientUnifiedMessagesCallbacks = 2500; +int const_k_iSteamStreamLauncherCallbacks = 2600; +int const_k_iClientControllerCallbacks = 2700; +int const_k_iSteamControllerCallbacks = 2800; +int const_k_iClientParentalSettingsCallbacks = 2900; +int const_k_iClientDeviceAuthCallbacks = 3000; +int const_k_iClientNetworkDeviceManagerCallbacks = 3100; +int const_k_iClientMusicCallbacks = 3200; +int const_k_iClientRemoteClientManagerCallbacks = 3300; +int const_k_iClientUGCCallbacks = 3400; +int const_k_iSteamStreamClientCallbacks = 3500; +int const_k_IClientProductBuilderCallbacks = 3600; +int const_k_iClientShortcutsCallbacks = 3700; +int const_k_iClientRemoteControlManagerCallbacks = 3800; +int const_k_iSteamAppListCallbacks = 3900; +int const_k_iSteamMusicCallbacks = 4000; +int const_k_iSteamMusicRemoteCallbacks = 4100; +int const_k_iClientVRCallbacks = 4200; +int const_k_iClientGameNotificationCallbacks = 4300; +int const_k_iSteamGameNotificationCallbacks = 4400; +int const_k_iSteamHTMLSurfaceCallbacks = 4500; +int const_k_iClientVideoCallbacks = 4600; +int const_k_iClientInventoryCallbacks = 4700; +int const_k_iClientBluetoothManagerCallbacks = 4800; +int const_k_iClientSharedConnectionCallbacks = 4900; +int const_k_ISteamParentalSettingsCallbacks = 5000; +int const_k_iClientShaderCallbacks = 5100; +int const_k_iSteamGameSearchCallbacks = 5200; +int const_k_iSteamPartiesCallbacks = 5300; +int const_k_iClientPartiesCallbacks = 5400; +int const_k_iSteamSTARCallbacks = 5500; +int const_k_iClientSTARCallbacks = 5600; +int const_k_iSteamRemotePlayCallbacks = 5700; +int const_k_cchPersonaNameMax = 128; +int const_k_cwchPersonaNameMax = 32; +int const_k_cchMaxRichPresenceKeys = 30; +int const_k_cchMaxRichPresenceKeyLength = 64; +int const_k_cchMaxRichPresenceValueLength = 256; +int const_k_cchStatNameMax = 128; +int const_k_cchLeaderboardNameMax = 128; +int const_k_cLeaderboardDetailsMax = 64; +unsigned long const_k_SteamItemInstanceIDInvalid = 0xffffffff; +int const_k_SteamInventoryResultInvalid = -1; +int const_k_cchBroadcastGameDataMax = 8192; + + + +// OpenVR Enums +// OpenVR Structs + + + +S_API HSteamPipe SteamAPI_ISteamClient_CreateSteamPipe(intptr_t instancePtr); +S_API bool SteamAPI_ISteamClient_BReleaseSteamPipe(intptr_t instancePtr, HSteamPipe hSteamPipe); +S_API HSteamUser SteamAPI_ISteamClient_ConnectToGlobalUser(intptr_t instancePtr, HSteamPipe hSteamPipe); +S_API HSteamUser SteamAPI_ISteamClient_CreateLocalUser(intptr_t instancePtr, HSteamPipe * phSteamPipe, EAccountType eAccountType); +S_API void SteamAPI_ISteamClient_ReleaseUser(intptr_t instancePtr, HSteamPipe hSteamPipe, HSteamUser hUser); +S_API class ISteamUser * SteamAPI_ISteamClient_GetISteamUser(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamGameServer * SteamAPI_ISteamClient_GetISteamGameServer(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API void SteamAPI_ISteamClient_SetLocalIPBinding(intptr_t instancePtr, uint32 unIP, uint16 usPort); +S_API class ISteamFriends * SteamAPI_ISteamClient_GetISteamFriends(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamUtils * SteamAPI_ISteamClient_GetISteamUtils(intptr_t instancePtr, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamMatchmaking * SteamAPI_ISteamClient_GetISteamMatchmaking(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamMatchmakingServers * SteamAPI_ISteamClient_GetISteamMatchmakingServers(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API void * SteamAPI_ISteamClient_GetISteamGenericInterface(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamUserStats * SteamAPI_ISteamClient_GetISteamUserStats(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamGameServerStats * SteamAPI_ISteamClient_GetISteamGameServerStats(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamApps * SteamAPI_ISteamClient_GetISteamApps(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamNetworking * SteamAPI_ISteamClient_GetISteamNetworking(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamRemoteStorage * SteamAPI_ISteamClient_GetISteamRemoteStorage(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamScreenshots * SteamAPI_ISteamClient_GetISteamScreenshots(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamGameSearch * SteamAPI_ISteamClient_GetISteamGameSearch(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API uint32 SteamAPI_ISteamClient_GetIPCCallCount(intptr_t instancePtr); +S_API void SteamAPI_ISteamClient_SetWarningMessageHook(intptr_t instancePtr, SteamAPIWarningMessageHook_t pFunction); +S_API bool SteamAPI_ISteamClient_BShutdownIfAllPipesClosed(intptr_t instancePtr); +S_API class ISteamHTTP * SteamAPI_ISteamClient_GetISteamHTTP(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamController * SteamAPI_ISteamClient_GetISteamController(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamUGC * SteamAPI_ISteamClient_GetISteamUGC(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamAppList * SteamAPI_ISteamClient_GetISteamAppList(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamMusic * SteamAPI_ISteamClient_GetISteamMusic(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamMusicRemote * SteamAPI_ISteamClient_GetISteamMusicRemote(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamHTMLSurface * SteamAPI_ISteamClient_GetISteamHTMLSurface(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamInventory * SteamAPI_ISteamClient_GetISteamInventory(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamVideo * SteamAPI_ISteamClient_GetISteamVideo(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamParentalSettings * SteamAPI_ISteamClient_GetISteamParentalSettings(intptr_t instancePtr, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamInput * SteamAPI_ISteamClient_GetISteamInput(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamParties * SteamAPI_ISteamClient_GetISteamParties(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API class ISteamRemotePlay * SteamAPI_ISteamClient_GetISteamRemotePlay(intptr_t instancePtr, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion); +S_API HSteamUser SteamAPI_ISteamUser_GetHSteamUser(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUser_BLoggedOn(intptr_t instancePtr); +S_API uint64 SteamAPI_ISteamUser_GetSteamID(intptr_t instancePtr); +S_API int SteamAPI_ISteamUser_InitiateGameConnection(intptr_t instancePtr, void * pAuthBlob, int cbMaxAuthBlob, class CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure); +S_API void SteamAPI_ISteamUser_TerminateGameConnection(intptr_t instancePtr, uint32 unIPServer, uint16 usPortServer); +S_API void SteamAPI_ISteamUser_TrackAppUsageEvent(intptr_t instancePtr, class CGameID gameID, int eAppUsageEvent, const char * pchExtraInfo); +S_API bool SteamAPI_ISteamUser_GetUserDataFolder(intptr_t instancePtr, char * pchBuffer, int cubBuffer); +S_API void SteamAPI_ISteamUser_StartVoiceRecording(intptr_t instancePtr); +S_API void SteamAPI_ISteamUser_StopVoiceRecording(intptr_t instancePtr); +S_API EVoiceResult SteamAPI_ISteamUser_GetAvailableVoice(intptr_t instancePtr, uint32 * pcbCompressed, uint32 * pcbUncompressed_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated); +S_API EVoiceResult SteamAPI_ISteamUser_GetVoice(intptr_t instancePtr, bool bWantCompressed, void * pDestBuffer, uint32 cbDestBufferSize, uint32 * nBytesWritten, bool bWantUncompressed_Deprecated, void * pUncompressedDestBuffer_Deprecated, uint32 cbUncompressedDestBufferSize_Deprecated, uint32 * nUncompressBytesWritten_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated); +S_API EVoiceResult SteamAPI_ISteamUser_DecompressVoice(intptr_t instancePtr, const void * pCompressed, uint32 cbCompressed, void * pDestBuffer, uint32 cbDestBufferSize, uint32 * nBytesWritten, uint32 nDesiredSampleRate); +S_API uint32 SteamAPI_ISteamUser_GetVoiceOptimalSampleRate(intptr_t instancePtr); +S_API HAuthTicket SteamAPI_ISteamUser_GetAuthSessionTicket(intptr_t instancePtr, void * pTicket, int cbMaxTicket, uint32 * pcbTicket); +S_API EBeginAuthSessionResult SteamAPI_ISteamUser_BeginAuthSession(intptr_t instancePtr, const void * pAuthTicket, int cbAuthTicket, class CSteamID steamID); +S_API void SteamAPI_ISteamUser_EndAuthSession(intptr_t instancePtr, class CSteamID steamID); +S_API void SteamAPI_ISteamUser_CancelAuthTicket(intptr_t instancePtr, HAuthTicket hAuthTicket); +S_API EUserHasLicenseForAppResult SteamAPI_ISteamUser_UserHasLicenseForApp(intptr_t instancePtr, class CSteamID steamID, AppId_t appID); +S_API bool SteamAPI_ISteamUser_BIsBehindNAT(intptr_t instancePtr); +S_API void SteamAPI_ISteamUser_AdvertiseGame(intptr_t instancePtr, class CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer); +S_API SteamAPICall_t SteamAPI_ISteamUser_RequestEncryptedAppTicket(intptr_t instancePtr, void * pDataToInclude, int cbDataToInclude); +S_API bool SteamAPI_ISteamUser_GetEncryptedAppTicket(intptr_t instancePtr, void * pTicket, int cbMaxTicket, uint32 * pcbTicket); +S_API int SteamAPI_ISteamUser_GetGameBadgeLevel(intptr_t instancePtr, int nSeries, bool bFoil); +S_API int SteamAPI_ISteamUser_GetPlayerSteamLevel(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamUser_RequestStoreAuthURL(intptr_t instancePtr, const char * pchRedirectURL); +S_API bool SteamAPI_ISteamUser_BIsPhoneVerified(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUser_BIsTwoFactorEnabled(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUser_BIsPhoneIdentifying(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUser_BIsPhoneRequiringVerification(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamUser_GetMarketEligibility(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamUser_GetDurationControl(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamFriends_GetPersonaName(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamFriends_SetPersonaName(intptr_t instancePtr, const char * pchPersonaName); +S_API EPersonaState SteamAPI_ISteamFriends_GetPersonaState(intptr_t instancePtr); +S_API int SteamAPI_ISteamFriends_GetFriendCount(intptr_t instancePtr, int iFriendFlags); +S_API uint64 SteamAPI_ISteamFriends_GetFriendByIndex(intptr_t instancePtr, int iFriend, int iFriendFlags); +S_API EFriendRelationship SteamAPI_ISteamFriends_GetFriendRelationship(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API EPersonaState SteamAPI_ISteamFriends_GetFriendPersonaState(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API const char * SteamAPI_ISteamFriends_GetFriendPersonaName(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API bool SteamAPI_ISteamFriends_GetFriendGamePlayed(intptr_t instancePtr, class CSteamID steamIDFriend, struct FriendGameInfo_t * pFriendGameInfo); +S_API const char * SteamAPI_ISteamFriends_GetFriendPersonaNameHistory(intptr_t instancePtr, class CSteamID steamIDFriend, int iPersonaName); +S_API int SteamAPI_ISteamFriends_GetFriendSteamLevel(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API const char * SteamAPI_ISteamFriends_GetPlayerNickname(intptr_t instancePtr, class CSteamID steamIDPlayer); +S_API int SteamAPI_ISteamFriends_GetFriendsGroupCount(intptr_t instancePtr); +S_API FriendsGroupID_t SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex(intptr_t instancePtr, int iFG); +S_API const char * SteamAPI_ISteamFriends_GetFriendsGroupName(intptr_t instancePtr, FriendsGroupID_t friendsGroupID); +S_API int SteamAPI_ISteamFriends_GetFriendsGroupMembersCount(intptr_t instancePtr, FriendsGroupID_t friendsGroupID); +S_API void SteamAPI_ISteamFriends_GetFriendsGroupMembersList(intptr_t instancePtr, FriendsGroupID_t friendsGroupID, class CSteamID * pOutSteamIDMembers, int nMembersCount); +S_API bool SteamAPI_ISteamFriends_HasFriend(intptr_t instancePtr, class CSteamID steamIDFriend, int iFriendFlags); +S_API int SteamAPI_ISteamFriends_GetClanCount(intptr_t instancePtr); +S_API uint64 SteamAPI_ISteamFriends_GetClanByIndex(intptr_t instancePtr, int iClan); +S_API const char * SteamAPI_ISteamFriends_GetClanName(intptr_t instancePtr, class CSteamID steamIDClan); +S_API const char * SteamAPI_ISteamFriends_GetClanTag(intptr_t instancePtr, class CSteamID steamIDClan); +S_API bool SteamAPI_ISteamFriends_GetClanActivityCounts(intptr_t instancePtr, class CSteamID steamIDClan, int * pnOnline, int * pnInGame, int * pnChatting); +S_API SteamAPICall_t SteamAPI_ISteamFriends_DownloadClanActivityCounts(intptr_t instancePtr, class CSteamID * psteamIDClans, int cClansToRequest); +S_API int SteamAPI_ISteamFriends_GetFriendCountFromSource(intptr_t instancePtr, class CSteamID steamIDSource); +S_API uint64 SteamAPI_ISteamFriends_GetFriendFromSourceByIndex(intptr_t instancePtr, class CSteamID steamIDSource, int iFriend); +S_API bool SteamAPI_ISteamFriends_IsUserInSource(intptr_t instancePtr, class CSteamID steamIDUser, class CSteamID steamIDSource); +S_API void SteamAPI_ISteamFriends_SetInGameVoiceSpeaking(intptr_t instancePtr, class CSteamID steamIDUser, bool bSpeaking); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlay(intptr_t instancePtr, const char * pchDialog); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayToUser(intptr_t instancePtr, const char * pchDialog, class CSteamID steamID); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage(intptr_t instancePtr, const char * pchURL, EActivateGameOverlayToWebPageMode eMode); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayToStore(intptr_t instancePtr, AppId_t nAppID, EOverlayToStoreFlag eFlag); +S_API void SteamAPI_ISteamFriends_SetPlayedWith(intptr_t instancePtr, class CSteamID steamIDUserPlayedWith); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API int SteamAPI_ISteamFriends_GetSmallFriendAvatar(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API int SteamAPI_ISteamFriends_GetMediumFriendAvatar(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API int SteamAPI_ISteamFriends_GetLargeFriendAvatar(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API bool SteamAPI_ISteamFriends_RequestUserInformation(intptr_t instancePtr, class CSteamID steamIDUser, bool bRequireNameOnly); +S_API SteamAPICall_t SteamAPI_ISteamFriends_RequestClanOfficerList(intptr_t instancePtr, class CSteamID steamIDClan); +S_API uint64 SteamAPI_ISteamFriends_GetClanOwner(intptr_t instancePtr, class CSteamID steamIDClan); +S_API int SteamAPI_ISteamFriends_GetClanOfficerCount(intptr_t instancePtr, class CSteamID steamIDClan); +S_API uint64 SteamAPI_ISteamFriends_GetClanOfficerByIndex(intptr_t instancePtr, class CSteamID steamIDClan, int iOfficer); +S_API uint32 SteamAPI_ISteamFriends_GetUserRestrictions(intptr_t instancePtr); +S_API bool SteamAPI_ISteamFriends_SetRichPresence(intptr_t instancePtr, const char * pchKey, const char * pchValue); +S_API void SteamAPI_ISteamFriends_ClearRichPresence(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamFriends_GetFriendRichPresence(intptr_t instancePtr, class CSteamID steamIDFriend, const char * pchKey); +S_API int SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API const char * SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex(intptr_t instancePtr, class CSteamID steamIDFriend, int iKey); +S_API void SteamAPI_ISteamFriends_RequestFriendRichPresence(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API bool SteamAPI_ISteamFriends_InviteUserToGame(intptr_t instancePtr, class CSteamID steamIDFriend, const char * pchConnectString); +S_API int SteamAPI_ISteamFriends_GetCoplayFriendCount(intptr_t instancePtr); +S_API uint64 SteamAPI_ISteamFriends_GetCoplayFriend(intptr_t instancePtr, int iCoplayFriend); +S_API int SteamAPI_ISteamFriends_GetFriendCoplayTime(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API AppId_t SteamAPI_ISteamFriends_GetFriendCoplayGame(intptr_t instancePtr, class CSteamID steamIDFriend); +S_API SteamAPICall_t SteamAPI_ISteamFriends_JoinClanChatRoom(intptr_t instancePtr, class CSteamID steamIDClan); +S_API bool SteamAPI_ISteamFriends_LeaveClanChatRoom(intptr_t instancePtr, class CSteamID steamIDClan); +S_API int SteamAPI_ISteamFriends_GetClanChatMemberCount(intptr_t instancePtr, class CSteamID steamIDClan); +S_API uint64 SteamAPI_ISteamFriends_GetChatMemberByIndex(intptr_t instancePtr, class CSteamID steamIDClan, int iUser); +S_API bool SteamAPI_ISteamFriends_SendClanChatMessage(intptr_t instancePtr, class CSteamID steamIDClanChat, const char * pchText); +S_API int SteamAPI_ISteamFriends_GetClanChatMessage(intptr_t instancePtr, class CSteamID steamIDClanChat, int iMessage, void * prgchText, int cchTextMax, EChatEntryType * peChatEntryType, class CSteamID * psteamidChatter); +S_API bool SteamAPI_ISteamFriends_IsClanChatAdmin(intptr_t instancePtr, class CSteamID steamIDClanChat, class CSteamID steamIDUser); +S_API bool SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam(intptr_t instancePtr, class CSteamID steamIDClanChat); +S_API bool SteamAPI_ISteamFriends_OpenClanChatWindowInSteam(intptr_t instancePtr, class CSteamID steamIDClanChat); +S_API bool SteamAPI_ISteamFriends_CloseClanChatWindowInSteam(intptr_t instancePtr, class CSteamID steamIDClanChat); +S_API bool SteamAPI_ISteamFriends_SetListenForFriendsMessages(intptr_t instancePtr, bool bInterceptEnabled); +S_API bool SteamAPI_ISteamFriends_ReplyToFriendMessage(intptr_t instancePtr, class CSteamID steamIDFriend, const char * pchMsgToSend); +S_API int SteamAPI_ISteamFriends_GetFriendMessage(intptr_t instancePtr, class CSteamID steamIDFriend, int iMessageID, void * pvData, int cubData, EChatEntryType * peChatEntryType); +S_API SteamAPICall_t SteamAPI_ISteamFriends_GetFollowerCount(intptr_t instancePtr, class CSteamID steamID); +S_API SteamAPICall_t SteamAPI_ISteamFriends_IsFollowing(intptr_t instancePtr, class CSteamID steamID); +S_API SteamAPICall_t SteamAPI_ISteamFriends_EnumerateFollowingList(intptr_t instancePtr, uint32 unStartIndex); +S_API bool SteamAPI_ISteamFriends_IsClanPublic(intptr_t instancePtr, class CSteamID steamIDClan); +S_API bool SteamAPI_ISteamFriends_IsClanOfficialGameGroup(intptr_t instancePtr, class CSteamID steamIDClan); +S_API int SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamUtils_GetSecondsSinceAppActive(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamUtils_GetSecondsSinceComputerActive(intptr_t instancePtr); +S_API EUniverse SteamAPI_ISteamUtils_GetConnectedUniverse(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamUtils_GetServerRealTime(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamUtils_GetIPCountry(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUtils_GetImageSize(intptr_t instancePtr, int iImage, uint32 * pnWidth, uint32 * pnHeight); +S_API bool SteamAPI_ISteamUtils_GetImageRGBA(intptr_t instancePtr, int iImage, uint8 * pubDest, int nDestBufferSize); +S_API bool SteamAPI_ISteamUtils_GetCSERIPPort(intptr_t instancePtr, uint32 * unIP, uint16 * usPort); +S_API uint8 SteamAPI_ISteamUtils_GetCurrentBatteryPower(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamUtils_GetAppID(intptr_t instancePtr); +S_API void SteamAPI_ISteamUtils_SetOverlayNotificationPosition(intptr_t instancePtr, ENotificationPosition eNotificationPosition); +S_API bool SteamAPI_ISteamUtils_IsAPICallCompleted(intptr_t instancePtr, SteamAPICall_t hSteamAPICall, bool * pbFailed); +S_API ESteamAPICallFailure SteamAPI_ISteamUtils_GetAPICallFailureReason(intptr_t instancePtr, SteamAPICall_t hSteamAPICall); +S_API bool SteamAPI_ISteamUtils_GetAPICallResult(intptr_t instancePtr, SteamAPICall_t hSteamAPICall, void * pCallback, int cubCallback, int iCallbackExpected, bool * pbFailed); +S_API uint32 SteamAPI_ISteamUtils_GetIPCCallCount(intptr_t instancePtr); +S_API void SteamAPI_ISteamUtils_SetWarningMessageHook(intptr_t instancePtr, SteamAPIWarningMessageHook_t pFunction); +S_API bool SteamAPI_ISteamUtils_IsOverlayEnabled(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUtils_BOverlayNeedsPresent(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamUtils_CheckFileSignature(intptr_t instancePtr, const char * szFileName); +S_API bool SteamAPI_ISteamUtils_ShowGamepadTextInput(intptr_t instancePtr, EGamepadTextInputMode eInputMode, EGamepadTextInputLineMode eLineInputMode, const char * pchDescription, uint32 unCharMax, const char * pchExistingText); +S_API uint32 SteamAPI_ISteamUtils_GetEnteredGamepadTextLength(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUtils_GetEnteredGamepadTextInput(intptr_t instancePtr, char * pchText, uint32 cchText); +S_API const char * SteamAPI_ISteamUtils_GetSteamUILanguage(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUtils_IsSteamRunningInVR(intptr_t instancePtr); +S_API void SteamAPI_ISteamUtils_SetOverlayNotificationInset(intptr_t instancePtr, int nHorizontalInset, int nVerticalInset); +S_API bool SteamAPI_ISteamUtils_IsSteamInBigPictureMode(intptr_t instancePtr); +S_API void SteamAPI_ISteamUtils_StartVRDashboard(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled(intptr_t instancePtr); +S_API void SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled(intptr_t instancePtr, bool bEnabled); +S_API bool SteamAPI_ISteamUtils_IsSteamChinaLauncher(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUtils_InitFilterText(intptr_t instancePtr); +S_API int SteamAPI_ISteamUtils_FilterText(intptr_t instancePtr, char * pchOutFilteredText, uint32 nByteSizeOutFilteredText, const char * pchInputMessage, bool bLegalOnly); +S_API int SteamAPI_ISteamMatchmaking_GetFavoriteGameCount(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMatchmaking_GetFavoriteGame(intptr_t instancePtr, int iGame, AppId_t * pnAppID, uint32 * pnIP, uint16 * pnConnPort, uint16 * pnQueryPort, uint32 * punFlags, uint32 * pRTime32LastPlayedOnServer); +S_API int SteamAPI_ISteamMatchmaking_AddFavoriteGame(intptr_t instancePtr, AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags, uint32 rTime32LastPlayedOnServer); +S_API bool SteamAPI_ISteamMatchmaking_RemoveFavoriteGame(intptr_t instancePtr, AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags); +S_API SteamAPICall_t SteamAPI_ISteamMatchmaking_RequestLobbyList(intptr_t instancePtr); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter(intptr_t instancePtr, const char * pchKeyToMatch, const char * pchValueToMatch, ELobbyComparison eComparisonType); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter(intptr_t instancePtr, const char * pchKeyToMatch, int nValueToMatch, ELobbyComparison eComparisonType); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter(intptr_t instancePtr, const char * pchKeyToMatch, int nValueToBeCloseTo); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable(intptr_t instancePtr, int nSlotsAvailable); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter(intptr_t instancePtr, ELobbyDistanceFilter eLobbyDistanceFilter); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter(intptr_t instancePtr, int cMaxResults); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API uint64 SteamAPI_ISteamMatchmaking_GetLobbyByIndex(intptr_t instancePtr, int iLobby); +S_API SteamAPICall_t SteamAPI_ISteamMatchmaking_CreateLobby(intptr_t instancePtr, ELobbyType eLobbyType, int cMaxMembers); +S_API SteamAPICall_t SteamAPI_ISteamMatchmaking_JoinLobby(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API void SteamAPI_ISteamMatchmaking_LeaveLobby(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API bool SteamAPI_ISteamMatchmaking_InviteUserToLobby(intptr_t instancePtr, class CSteamID steamIDLobby, class CSteamID steamIDInvitee); +S_API int SteamAPI_ISteamMatchmaking_GetNumLobbyMembers(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API uint64 SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex(intptr_t instancePtr, class CSteamID steamIDLobby, int iMember); +S_API const char * SteamAPI_ISteamMatchmaking_GetLobbyData(intptr_t instancePtr, class CSteamID steamIDLobby, const char * pchKey); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyData(intptr_t instancePtr, class CSteamID steamIDLobby, const char * pchKey, const char * pchValue); +S_API int SteamAPI_ISteamMatchmaking_GetLobbyDataCount(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API bool SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex(intptr_t instancePtr, class CSteamID steamIDLobby, int iLobbyData, char * pchKey, int cchKeyBufferSize, char * pchValue, int cchValueBufferSize); +S_API bool SteamAPI_ISteamMatchmaking_DeleteLobbyData(intptr_t instancePtr, class CSteamID steamIDLobby, const char * pchKey); +S_API const char * SteamAPI_ISteamMatchmaking_GetLobbyMemberData(intptr_t instancePtr, class CSteamID steamIDLobby, class CSteamID steamIDUser, const char * pchKey); +S_API void SteamAPI_ISteamMatchmaking_SetLobbyMemberData(intptr_t instancePtr, class CSteamID steamIDLobby, const char * pchKey, const char * pchValue); +S_API bool SteamAPI_ISteamMatchmaking_SendLobbyChatMsg(intptr_t instancePtr, class CSteamID steamIDLobby, const void * pvMsgBody, int cubMsgBody); +S_API int SteamAPI_ISteamMatchmaking_GetLobbyChatEntry(intptr_t instancePtr, class CSteamID steamIDLobby, int iChatID, class CSteamID * pSteamIDUser, void * pvData, int cubData, EChatEntryType * peChatEntryType); +S_API bool SteamAPI_ISteamMatchmaking_RequestLobbyData(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API void SteamAPI_ISteamMatchmaking_SetLobbyGameServer(intptr_t instancePtr, class CSteamID steamIDLobby, uint32 unGameServerIP, uint16 unGameServerPort, class CSteamID steamIDGameServer); +S_API bool SteamAPI_ISteamMatchmaking_GetLobbyGameServer(intptr_t instancePtr, class CSteamID steamIDLobby, uint32 * punGameServerIP, uint16 * punGameServerPort, class CSteamID * psteamIDGameServer); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit(intptr_t instancePtr, class CSteamID steamIDLobby, int cMaxMembers); +S_API int SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyType(intptr_t instancePtr, class CSteamID steamIDLobby, ELobbyType eLobbyType); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyJoinable(intptr_t instancePtr, class CSteamID steamIDLobby, bool bLobbyJoinable); +S_API uint64 SteamAPI_ISteamMatchmaking_GetLobbyOwner(intptr_t instancePtr, class CSteamID steamIDLobby); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyOwner(intptr_t instancePtr, class CSteamID steamIDLobby, class CSteamID steamIDNewOwner); +S_API bool SteamAPI_ISteamMatchmaking_SetLinkedLobby(intptr_t instancePtr, class CSteamID steamIDLobby, class CSteamID steamIDLobbyDependent); +S_API void SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded(intptr_t instancePtr, HServerListRequest hRequest, int iServer); +S_API void SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond(intptr_t instancePtr, HServerListRequest hRequest, int iServer); +S_API void SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete(intptr_t instancePtr, HServerListRequest hRequest, EMatchMakingServerResponse response); +S_API void SteamAPI_ISteamMatchmakingPingResponse_ServerResponded(intptr_t instancePtr, class gameserveritem_t & server); +S_API void SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond(intptr_t instancePtr); +S_API void SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList(intptr_t instancePtr, const char * pchName, int nScore, float flTimePlayed); +S_API void SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond(intptr_t instancePtr); +S_API void SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete(intptr_t instancePtr); +S_API void SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded(intptr_t instancePtr, const char * pchRule, const char * pchValue); +S_API void SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond(intptr_t instancePtr); +S_API void SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete(intptr_t instancePtr); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestInternetServerList(intptr_t instancePtr, AppId_t iApp, struct MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, class ISteamMatchmakingServerListResponse * pRequestServersResponse); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestLANServerList(intptr_t instancePtr, AppId_t iApp, class ISteamMatchmakingServerListResponse * pRequestServersResponse); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList(intptr_t instancePtr, AppId_t iApp, struct MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, class ISteamMatchmakingServerListResponse * pRequestServersResponse); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList(intptr_t instancePtr, AppId_t iApp, struct MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, class ISteamMatchmakingServerListResponse * pRequestServersResponse); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList(intptr_t instancePtr, AppId_t iApp, struct MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, class ISteamMatchmakingServerListResponse * pRequestServersResponse); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList(intptr_t instancePtr, AppId_t iApp, struct MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, class ISteamMatchmakingServerListResponse * pRequestServersResponse); +S_API void SteamAPI_ISteamMatchmakingServers_ReleaseRequest(intptr_t instancePtr, HServerListRequest hServerListRequest); +S_API class gameserveritem_t * SteamAPI_ISteamMatchmakingServers_GetServerDetails(intptr_t instancePtr, HServerListRequest hRequest, int iServer); +S_API void SteamAPI_ISteamMatchmakingServers_CancelQuery(intptr_t instancePtr, HServerListRequest hRequest); +S_API void SteamAPI_ISteamMatchmakingServers_RefreshQuery(intptr_t instancePtr, HServerListRequest hRequest); +S_API bool SteamAPI_ISteamMatchmakingServers_IsRefreshing(intptr_t instancePtr, HServerListRequest hRequest); +S_API int SteamAPI_ISteamMatchmakingServers_GetServerCount(intptr_t instancePtr, HServerListRequest hRequest); +S_API void SteamAPI_ISteamMatchmakingServers_RefreshServer(intptr_t instancePtr, HServerListRequest hRequest, int iServer); +S_API HServerQuery SteamAPI_ISteamMatchmakingServers_PingServer(intptr_t instancePtr, uint32 unIP, uint16 usPort, class ISteamMatchmakingPingResponse * pRequestServersResponse); +S_API HServerQuery SteamAPI_ISteamMatchmakingServers_PlayerDetails(intptr_t instancePtr, uint32 unIP, uint16 usPort, class ISteamMatchmakingPlayersResponse * pRequestServersResponse); +S_API HServerQuery SteamAPI_ISteamMatchmakingServers_ServerRules(intptr_t instancePtr, uint32 unIP, uint16 usPort, class ISteamMatchmakingRulesResponse * pRequestServersResponse); +S_API void SteamAPI_ISteamMatchmakingServers_CancelServerQuery(intptr_t instancePtr, HServerQuery hServerQuery); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_AddGameSearchParams(intptr_t instancePtr, const char * pchKeyToFind, const char * pchValuesToFind); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SearchForGameWithLobby(intptr_t instancePtr, class CSteamID steamIDLobby, int nPlayerMin, int nPlayerMax); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SearchForGameSolo(intptr_t instancePtr, int nPlayerMin, int nPlayerMax); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_AcceptGame(intptr_t instancePtr); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_DeclineGame(intptr_t instancePtr); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_RetrieveConnectionDetails(intptr_t instancePtr, class CSteamID steamIDHost, char * pchConnectionDetails, int cubConnectionDetails); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_EndGameSearch(intptr_t instancePtr); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SetGameHostParams(intptr_t instancePtr, const char * pchKey, const char * pchValue); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SetConnectionDetails(intptr_t instancePtr, const char * pchConnectionDetails, int cubConnectionDetails); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_RequestPlayersForGame(intptr_t instancePtr, int nPlayerMin, int nPlayerMax, int nMaxTeamSize); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_HostConfirmGameStart(intptr_t instancePtr, uint64 ullUniqueGameID); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame(intptr_t instancePtr); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SubmitPlayerResult(intptr_t instancePtr, uint64 ullUniqueGameID, class CSteamID steamIDPlayer, EPlayerResult_t EPlayerResult); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_EndGame(intptr_t instancePtr, uint64 ullUniqueGameID); +S_API uint32 SteamAPI_ISteamParties_GetNumActiveBeacons(intptr_t instancePtr); +S_API PartyBeaconID_t SteamAPI_ISteamParties_GetBeaconByIndex(intptr_t instancePtr, uint32 unIndex); +S_API bool SteamAPI_ISteamParties_GetBeaconDetails(intptr_t instancePtr, PartyBeaconID_t ulBeaconID, class CSteamID * pSteamIDBeaconOwner, struct SteamPartyBeaconLocation_t * pLocation, char * pchMetadata, int cchMetadata); +S_API SteamAPICall_t SteamAPI_ISteamParties_JoinParty(intptr_t instancePtr, PartyBeaconID_t ulBeaconID); +S_API bool SteamAPI_ISteamParties_GetNumAvailableBeaconLocations(intptr_t instancePtr, uint32 * puNumLocations); +S_API bool SteamAPI_ISteamParties_GetAvailableBeaconLocations(intptr_t instancePtr, struct SteamPartyBeaconLocation_t * pLocationList, uint32 uMaxNumLocations); +S_API SteamAPICall_t SteamAPI_ISteamParties_CreateBeacon(intptr_t instancePtr, uint32 unOpenSlots, struct SteamPartyBeaconLocation_t * pBeaconLocation, const char * pchConnectString, const char * pchMetadata); +S_API void SteamAPI_ISteamParties_OnReservationCompleted(intptr_t instancePtr, PartyBeaconID_t ulBeacon, class CSteamID steamIDUser); +S_API void SteamAPI_ISteamParties_CancelReservation(intptr_t instancePtr, PartyBeaconID_t ulBeacon, class CSteamID steamIDUser); +S_API SteamAPICall_t SteamAPI_ISteamParties_ChangeNumOpenSlots(intptr_t instancePtr, PartyBeaconID_t ulBeacon, uint32 unOpenSlots); +S_API bool SteamAPI_ISteamParties_DestroyBeacon(intptr_t instancePtr, PartyBeaconID_t ulBeacon); +S_API bool SteamAPI_ISteamParties_GetBeaconLocationData(intptr_t instancePtr, struct SteamPartyBeaconLocation_t BeaconLocation, ESteamPartyBeaconLocationData eData, char * pchDataStringOut, int cchDataStringOut); +S_API bool SteamAPI_ISteamRemoteStorage_FileWrite(intptr_t instancePtr, const char * pchFile, const void * pvData, int32 cubData); +S_API int32 SteamAPI_ISteamRemoteStorage_FileRead(intptr_t instancePtr, const char * pchFile, void * pvData, int32 cubDataToRead); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_FileWriteAsync(intptr_t instancePtr, const char * pchFile, const void * pvData, uint32 cubData); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_FileReadAsync(intptr_t instancePtr, const char * pchFile, uint32 nOffset, uint32 cubToRead); +S_API bool SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete(intptr_t instancePtr, SteamAPICall_t hReadCall, void * pvBuffer, uint32 cubToRead); +S_API bool SteamAPI_ISteamRemoteStorage_FileForget(intptr_t instancePtr, const char * pchFile); +S_API bool SteamAPI_ISteamRemoteStorage_FileDelete(intptr_t instancePtr, const char * pchFile); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_FileShare(intptr_t instancePtr, const char * pchFile); +S_API bool SteamAPI_ISteamRemoteStorage_SetSyncPlatforms(intptr_t instancePtr, const char * pchFile, ERemoteStoragePlatform eRemoteStoragePlatform); +S_API UGCFileWriteStreamHandle_t SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen(intptr_t instancePtr, const char * pchFile); +S_API bool SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk(intptr_t instancePtr, UGCFileWriteStreamHandle_t writeHandle, const void * pvData, int32 cubData); +S_API bool SteamAPI_ISteamRemoteStorage_FileWriteStreamClose(intptr_t instancePtr, UGCFileWriteStreamHandle_t writeHandle); +S_API bool SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel(intptr_t instancePtr, UGCFileWriteStreamHandle_t writeHandle); +S_API bool SteamAPI_ISteamRemoteStorage_FileExists(intptr_t instancePtr, const char * pchFile); +S_API bool SteamAPI_ISteamRemoteStorage_FilePersisted(intptr_t instancePtr, const char * pchFile); +S_API int32 SteamAPI_ISteamRemoteStorage_GetFileSize(intptr_t instancePtr, const char * pchFile); +S_API int64 SteamAPI_ISteamRemoteStorage_GetFileTimestamp(intptr_t instancePtr, const char * pchFile); +S_API ERemoteStoragePlatform SteamAPI_ISteamRemoteStorage_GetSyncPlatforms(intptr_t instancePtr, const char * pchFile); +S_API int32 SteamAPI_ISteamRemoteStorage_GetFileCount(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamRemoteStorage_GetFileNameAndSize(intptr_t instancePtr, int iFile, int32 * pnFileSizeInBytes); +S_API bool SteamAPI_ISteamRemoteStorage_GetQuota(intptr_t instancePtr, uint64 * pnTotalBytes, uint64 * puAvailableBytes); +S_API bool SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount(intptr_t instancePtr); +S_API bool SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp(intptr_t instancePtr); +S_API void SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp(intptr_t instancePtr, bool bEnabled); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UGCDownload(intptr_t instancePtr, UGCHandle_t hContent, uint32 unPriority); +S_API bool SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress(intptr_t instancePtr, UGCHandle_t hContent, int32 * pnBytesDownloaded, int32 * pnBytesExpected); +S_API bool SteamAPI_ISteamRemoteStorage_GetUGCDetails(intptr_t instancePtr, UGCHandle_t hContent, AppId_t * pnAppID, char ** ppchName, int32 * pnFileSizeInBytes, class CSteamID * pSteamIDOwner); +S_API int32 SteamAPI_ISteamRemoteStorage_UGCRead(intptr_t instancePtr, UGCHandle_t hContent, void * pvData, int32 cubDataToRead, uint32 cOffset, EUGCReadAction eAction); +S_API int32 SteamAPI_ISteamRemoteStorage_GetCachedUGCCount(intptr_t instancePtr); +S_API UGCHandle_t SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle(intptr_t instancePtr, int32 iCachedContent); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_PublishWorkshopFile(intptr_t instancePtr, const char * pchFile, const char * pchPreviewFile, AppId_t nConsumerAppId, const char * pchTitle, const char * pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, struct SteamParamStringArray_t * pTags, EWorkshopFileType eWorkshopFileType); +S_API PublishedFileUpdateHandle_t SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest(intptr_t instancePtr, PublishedFileId_t unPublishedFileId); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, const char * pchFile); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, const char * pchPreviewFile); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, const char * pchTitle); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, const char * pchDescription); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, ERemoteStoragePublishedFileVisibility eVisibility); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, struct SteamParamStringArray_t * pTags); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails(intptr_t instancePtr, PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_DeletePublishedFile(intptr_t instancePtr, PublishedFileId_t unPublishedFileId); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles(intptr_t instancePtr, uint32 unStartIndex); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_SubscribePublishedFile(intptr_t instancePtr, PublishedFileId_t unPublishedFileId); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles(intptr_t instancePtr, uint32 unStartIndex); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile(intptr_t instancePtr, PublishedFileId_t unPublishedFileId); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription(intptr_t instancePtr, PublishedFileUpdateHandle_t updateHandle, const char * pchChangeDescription); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails(intptr_t instancePtr, PublishedFileId_t unPublishedFileId); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote(intptr_t instancePtr, PublishedFileId_t unPublishedFileId, bool bVoteUp); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails(intptr_t instancePtr, PublishedFileId_t unPublishedFileId); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles(intptr_t instancePtr, class CSteamID steamId, uint32 unStartIndex, struct SteamParamStringArray_t * pRequiredTags, struct SteamParamStringArray_t * pExcludedTags); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_PublishVideo(intptr_t instancePtr, EWorkshopVideoProvider eVideoProvider, const char * pchVideoAccount, const char * pchVideoIdentifier, const char * pchPreviewFile, AppId_t nConsumerAppId, const char * pchTitle, const char * pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, struct SteamParamStringArray_t * pTags); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction(intptr_t instancePtr, PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction(intptr_t instancePtr, EWorkshopFileAction eAction, uint32 unStartIndex); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles(intptr_t instancePtr, EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, struct SteamParamStringArray_t * pTags, struct SteamParamStringArray_t * pUserTags); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation(intptr_t instancePtr, UGCHandle_t hContent, const char * pchLocation, uint32 unPriority); +S_API bool SteamAPI_ISteamUserStats_RequestCurrentStats(intptr_t instancePtr); +S_API bool SteamAPI_ISteamUserStats_GetStat(intptr_t instancePtr, const char * pchName, int32 * pData); +S_API bool SteamAPI_ISteamUserStats_GetStat0(intptr_t instancePtr, const char * pchName, float * pData); +S_API bool SteamAPI_ISteamUserStats_SetStat(intptr_t instancePtr, const char * pchName, int32 nData); +S_API bool SteamAPI_ISteamUserStats_SetStat0(intptr_t instancePtr, const char * pchName, float fData); +S_API bool SteamAPI_ISteamUserStats_UpdateAvgRateStat(intptr_t instancePtr, const char * pchName, float flCountThisSession, double dSessionLength); +S_API bool SteamAPI_ISteamUserStats_GetAchievement(intptr_t instancePtr, const char * pchName, bool * pbAchieved); +S_API bool SteamAPI_ISteamUserStats_SetAchievement(intptr_t instancePtr, const char * pchName); +S_API bool SteamAPI_ISteamUserStats_ClearAchievement(intptr_t instancePtr, const char * pchName); +S_API bool SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime(intptr_t instancePtr, const char * pchName, bool * pbAchieved, uint32 * punUnlockTime); +S_API bool SteamAPI_ISteamUserStats_StoreStats(intptr_t instancePtr); +S_API int SteamAPI_ISteamUserStats_GetAchievementIcon(intptr_t instancePtr, const char * pchName); +S_API const char * SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute(intptr_t instancePtr, const char * pchName, const char * pchKey); +S_API bool SteamAPI_ISteamUserStats_IndicateAchievementProgress(intptr_t instancePtr, const char * pchName, uint32 nCurProgress, uint32 nMaxProgress); +S_API uint32 SteamAPI_ISteamUserStats_GetNumAchievements(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamUserStats_GetAchievementName(intptr_t instancePtr, uint32 iAchievement); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_RequestUserStats(intptr_t instancePtr, class CSteamID steamIDUser); +S_API bool SteamAPI_ISteamUserStats_GetUserStat(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, int32 * pData); +S_API bool SteamAPI_ISteamUserStats_GetUserStat0(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, float * pData); +S_API bool SteamAPI_ISteamUserStats_GetUserAchievement(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, bool * pbAchieved); +S_API bool SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, bool * pbAchieved, uint32 * punUnlockTime); +S_API bool SteamAPI_ISteamUserStats_ResetAllStats(intptr_t instancePtr, bool bAchievementsToo); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_FindOrCreateLeaderboard(intptr_t instancePtr, const char * pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_FindLeaderboard(intptr_t instancePtr, const char * pchLeaderboardName); +S_API const char * SteamAPI_ISteamUserStats_GetLeaderboardName(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard); +S_API int SteamAPI_ISteamUserStats_GetLeaderboardEntryCount(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard); +S_API ELeaderboardSortMethod SteamAPI_ISteamUserStats_GetLeaderboardSortMethod(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard); +S_API ELeaderboardDisplayType SteamAPI_ISteamUserStats_GetLeaderboardDisplayType(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_DownloadLeaderboardEntries(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard, ELeaderboardDataRequest eLeaderboardDataRequest, int nRangeStart, int nRangeEnd); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard, class CSteamID * prgUsers, int cUsers); +S_API bool SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry(intptr_t instancePtr, SteamLeaderboardEntries_t hSteamLeaderboardEntries, int index, struct LeaderboardEntry_t * pLeaderboardEntry, int32 * pDetails, int cDetailsMax); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_UploadLeaderboardScore(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32 * pScoreDetails, int cScoreDetailsCount); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_AttachLeaderboardUGC(intptr_t instancePtr, SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages(intptr_t instancePtr); +S_API int SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo(intptr_t instancePtr, char * pchName, uint32 unNameBufLen, float * pflPercent, bool * pbAchieved); +S_API int SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo(intptr_t instancePtr, int iIteratorPrevious, char * pchName, uint32 unNameBufLen, float * pflPercent, bool * pbAchieved); +S_API bool SteamAPI_ISteamUserStats_GetAchievementAchievedPercent(intptr_t instancePtr, const char * pchName, float * pflPercent); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_RequestGlobalStats(intptr_t instancePtr, int nHistoryDays); +S_API bool SteamAPI_ISteamUserStats_GetGlobalStat(intptr_t instancePtr, const char * pchStatName, int64 * pData); +S_API bool SteamAPI_ISteamUserStats_GetGlobalStat0(intptr_t instancePtr, const char * pchStatName, double * pData); +S_API int32 SteamAPI_ISteamUserStats_GetGlobalStatHistory(intptr_t instancePtr, const char * pchStatName, int64 * pData, uint32 cubData); +S_API int32 SteamAPI_ISteamUserStats_GetGlobalStatHistory0(intptr_t instancePtr, const char * pchStatName, double * pData, uint32 cubData); +S_API bool SteamAPI_ISteamApps_BIsSubscribed(intptr_t instancePtr); +S_API bool SteamAPI_ISteamApps_BIsLowViolence(intptr_t instancePtr); +S_API bool SteamAPI_ISteamApps_BIsCybercafe(intptr_t instancePtr); +S_API bool SteamAPI_ISteamApps_BIsVACBanned(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamApps_GetCurrentGameLanguage(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamApps_GetAvailableGameLanguages(intptr_t instancePtr); +S_API bool SteamAPI_ISteamApps_BIsSubscribedApp(intptr_t instancePtr, AppId_t appID); +S_API bool SteamAPI_ISteamApps_BIsDlcInstalled(intptr_t instancePtr, AppId_t appID); +S_API uint32 SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime(intptr_t instancePtr, AppId_t nAppID); +S_API bool SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend(intptr_t instancePtr); +S_API int SteamAPI_ISteamApps_GetDLCCount(intptr_t instancePtr); +S_API bool SteamAPI_ISteamApps_BGetDLCDataByIndex(intptr_t instancePtr, int iDLC, AppId_t * pAppID, bool * pbAvailable, char * pchName, int cchNameBufferSize); +S_API void SteamAPI_ISteamApps_InstallDLC(intptr_t instancePtr, AppId_t nAppID); +S_API void SteamAPI_ISteamApps_UninstallDLC(intptr_t instancePtr, AppId_t nAppID); +S_API void SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey(intptr_t instancePtr, AppId_t nAppID); +S_API bool SteamAPI_ISteamApps_GetCurrentBetaName(intptr_t instancePtr, char * pchName, int cchNameBufferSize); +S_API bool SteamAPI_ISteamApps_MarkContentCorrupt(intptr_t instancePtr, bool bMissingFilesOnly); +S_API uint32 SteamAPI_ISteamApps_GetInstalledDepots(intptr_t instancePtr, AppId_t appID, DepotId_t * pvecDepots, uint32 cMaxDepots); +S_API uint32 SteamAPI_ISteamApps_GetAppInstallDir(intptr_t instancePtr, AppId_t appID, char * pchFolder, uint32 cchFolderBufferSize); +S_API bool SteamAPI_ISteamApps_BIsAppInstalled(intptr_t instancePtr, AppId_t appID); +S_API uint64 SteamAPI_ISteamApps_GetAppOwner(intptr_t instancePtr); +S_API const char * SteamAPI_ISteamApps_GetLaunchQueryParam(intptr_t instancePtr, const char * pchKey); +S_API bool SteamAPI_ISteamApps_GetDlcDownloadProgress(intptr_t instancePtr, AppId_t nAppID, uint64 * punBytesDownloaded, uint64 * punBytesTotal); +S_API int SteamAPI_ISteamApps_GetAppBuildId(intptr_t instancePtr); +S_API void SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamApps_GetFileDetails(intptr_t instancePtr, const char * pszFileName); +S_API int SteamAPI_ISteamApps_GetLaunchCommandLine(intptr_t instancePtr, char * pszCommandLine, int cubCommandLine); +S_API bool SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing(intptr_t instancePtr); +S_API bool SteamAPI_ISteamNetworking_SendP2PPacket(intptr_t instancePtr, class CSteamID steamIDRemote, const void * pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel); +S_API bool SteamAPI_ISteamNetworking_IsP2PPacketAvailable(intptr_t instancePtr, uint32 * pcubMsgSize, int nChannel); +S_API bool SteamAPI_ISteamNetworking_ReadP2PPacket(intptr_t instancePtr, void * pubDest, uint32 cubDest, uint32 * pcubMsgSize, class CSteamID * psteamIDRemote, int nChannel); +S_API bool SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser(intptr_t instancePtr, class CSteamID steamIDRemote); +S_API bool SteamAPI_ISteamNetworking_CloseP2PSessionWithUser(intptr_t instancePtr, class CSteamID steamIDRemote); +S_API bool SteamAPI_ISteamNetworking_CloseP2PChannelWithUser(intptr_t instancePtr, class CSteamID steamIDRemote, int nChannel); +S_API bool SteamAPI_ISteamNetworking_GetP2PSessionState(intptr_t instancePtr, class CSteamID steamIDRemote, struct P2PSessionState_t * pConnectionState); +S_API bool SteamAPI_ISteamNetworking_AllowP2PPacketRelay(intptr_t instancePtr, bool bAllow); +S_API SNetListenSocket_t SteamAPI_ISteamNetworking_CreateListenSocket(intptr_t instancePtr, int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay); +S_API SNetSocket_t SteamAPI_ISteamNetworking_CreateP2PConnectionSocket(intptr_t instancePtr, class CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay); +S_API SNetSocket_t SteamAPI_ISteamNetworking_CreateConnectionSocket(intptr_t instancePtr, uint32 nIP, uint16 nPort, int nTimeoutSec); +S_API bool SteamAPI_ISteamNetworking_DestroySocket(intptr_t instancePtr, SNetSocket_t hSocket, bool bNotifyRemoteEnd); +S_API bool SteamAPI_ISteamNetworking_DestroyListenSocket(intptr_t instancePtr, SNetListenSocket_t hSocket, bool bNotifyRemoteEnd); +S_API bool SteamAPI_ISteamNetworking_SendDataOnSocket(intptr_t instancePtr, SNetSocket_t hSocket, void * pubData, uint32 cubData, bool bReliable); +S_API bool SteamAPI_ISteamNetworking_IsDataAvailableOnSocket(intptr_t instancePtr, SNetSocket_t hSocket, uint32 * pcubMsgSize); +S_API bool SteamAPI_ISteamNetworking_RetrieveDataFromSocket(intptr_t instancePtr, SNetSocket_t hSocket, void * pubDest, uint32 cubDest, uint32 * pcubMsgSize); +S_API bool SteamAPI_ISteamNetworking_IsDataAvailable(intptr_t instancePtr, SNetListenSocket_t hListenSocket, uint32 * pcubMsgSize, SNetSocket_t * phSocket); +S_API bool SteamAPI_ISteamNetworking_RetrieveData(intptr_t instancePtr, SNetListenSocket_t hListenSocket, void * pubDest, uint32 cubDest, uint32 * pcubMsgSize, SNetSocket_t * phSocket); +S_API bool SteamAPI_ISteamNetworking_GetSocketInfo(intptr_t instancePtr, SNetSocket_t hSocket, class CSteamID * pSteamIDRemote, int * peSocketStatus, uint32 * punIPRemote, uint16 * punPortRemote); +S_API bool SteamAPI_ISteamNetworking_GetListenSocketInfo(intptr_t instancePtr, SNetListenSocket_t hListenSocket, uint32 * pnIP, uint16 * pnPort); +S_API ESNetSocketConnectionType SteamAPI_ISteamNetworking_GetSocketConnectionType(intptr_t instancePtr, SNetSocket_t hSocket); +S_API int SteamAPI_ISteamNetworking_GetMaxPacketSize(intptr_t instancePtr, SNetSocket_t hSocket); +S_API ScreenshotHandle SteamAPI_ISteamScreenshots_WriteScreenshot(intptr_t instancePtr, void * pubRGB, uint32 cubRGB, int nWidth, int nHeight); +S_API ScreenshotHandle SteamAPI_ISteamScreenshots_AddScreenshotToLibrary(intptr_t instancePtr, const char * pchFilename, const char * pchThumbnailFilename, int nWidth, int nHeight); +S_API void SteamAPI_ISteamScreenshots_TriggerScreenshot(intptr_t instancePtr); +S_API void SteamAPI_ISteamScreenshots_HookScreenshots(intptr_t instancePtr, bool bHook); +S_API bool SteamAPI_ISteamScreenshots_SetLocation(intptr_t instancePtr, ScreenshotHandle hScreenshot, const char * pchLocation); +S_API bool SteamAPI_ISteamScreenshots_TagUser(intptr_t instancePtr, ScreenshotHandle hScreenshot, class CSteamID steamID); +S_API bool SteamAPI_ISteamScreenshots_TagPublishedFile(intptr_t instancePtr, ScreenshotHandle hScreenshot, PublishedFileId_t unPublishedFileID); +S_API bool SteamAPI_ISteamScreenshots_IsScreenshotsHooked(intptr_t instancePtr); +S_API ScreenshotHandle SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary(intptr_t instancePtr, EVRScreenshotType eType, const char * pchFilename, const char * pchVRFilename); +S_API bool SteamAPI_ISteamMusic_BIsEnabled(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusic_BIsPlaying(intptr_t instancePtr); +S_API AudioPlayback_Status SteamAPI_ISteamMusic_GetPlaybackStatus(intptr_t instancePtr); +S_API void SteamAPI_ISteamMusic_Play(intptr_t instancePtr); +S_API void SteamAPI_ISteamMusic_Pause(intptr_t instancePtr); +S_API void SteamAPI_ISteamMusic_PlayPrevious(intptr_t instancePtr); +S_API void SteamAPI_ISteamMusic_PlayNext(intptr_t instancePtr); +S_API void SteamAPI_ISteamMusic_SetVolume(intptr_t instancePtr, float flVolume); +S_API float SteamAPI_ISteamMusic_GetVolume(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote(intptr_t instancePtr, const char * pchName); +S_API bool SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_BActivationSuccess(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_SetDisplayName(intptr_t instancePtr, const char * pchDisplayName); +S_API bool SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64(intptr_t instancePtr, void * pvBuffer, uint32 cbBufferLength); +S_API bool SteamAPI_ISteamMusicRemote_EnablePlayPrevious(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_EnablePlayNext(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_EnableShuffled(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_EnableLooped(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_EnableQueue(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_EnablePlaylists(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus(intptr_t instancePtr, AudioPlayback_Status nStatus); +S_API bool SteamAPI_ISteamMusicRemote_UpdateShuffled(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_UpdateLooped(intptr_t instancePtr, bool bValue); +S_API bool SteamAPI_ISteamMusicRemote_UpdateVolume(intptr_t instancePtr, float flValue); +S_API bool SteamAPI_ISteamMusicRemote_CurrentEntryWillChange(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable(intptr_t instancePtr, bool bAvailable); +S_API bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText(intptr_t instancePtr, const char * pchText); +S_API bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds(intptr_t instancePtr, int nValue); +S_API bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt(intptr_t instancePtr, void * pvBuffer, uint32 cbBufferLength); +S_API bool SteamAPI_ISteamMusicRemote_CurrentEntryDidChange(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_QueueWillChange(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_ResetQueueEntries(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_SetQueueEntry(intptr_t instancePtr, int nID, int nPosition, const char * pchEntryText); +S_API bool SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry(intptr_t instancePtr, int nID); +S_API bool SteamAPI_ISteamMusicRemote_QueueDidChange(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_PlaylistWillChange(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_ResetPlaylistEntries(intptr_t instancePtr); +S_API bool SteamAPI_ISteamMusicRemote_SetPlaylistEntry(intptr_t instancePtr, int nID, int nPosition, const char * pchEntryText); +S_API bool SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry(intptr_t instancePtr, int nID); +S_API bool SteamAPI_ISteamMusicRemote_PlaylistDidChange(intptr_t instancePtr); +S_API HTTPRequestHandle SteamAPI_ISteamHTTP_CreateHTTPRequest(intptr_t instancePtr, EHTTPMethod eHTTPRequestMethod, const char * pchAbsoluteURL); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestContextValue(intptr_t instancePtr, HTTPRequestHandle hRequest, uint64 ulContextValue); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout(intptr_t instancePtr, HTTPRequestHandle hRequest, uint32 unTimeoutSeconds); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue(intptr_t instancePtr, HTTPRequestHandle hRequest, const char * pchHeaderName, const char * pchHeaderValue); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter(intptr_t instancePtr, HTTPRequestHandle hRequest, const char * pchParamName, const char * pchParamValue); +S_API bool SteamAPI_ISteamHTTP_SendHTTPRequest(intptr_t instancePtr, HTTPRequestHandle hRequest, SteamAPICall_t * pCallHandle); +S_API bool SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse(intptr_t instancePtr, HTTPRequestHandle hRequest, SteamAPICall_t * pCallHandle); +S_API bool SteamAPI_ISteamHTTP_DeferHTTPRequest(intptr_t instancePtr, HTTPRequestHandle hRequest); +S_API bool SteamAPI_ISteamHTTP_PrioritizeHTTPRequest(intptr_t instancePtr, HTTPRequestHandle hRequest); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize(intptr_t instancePtr, HTTPRequestHandle hRequest, const char * pchHeaderName, uint32 * unResponseHeaderSize); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue(intptr_t instancePtr, HTTPRequestHandle hRequest, const char * pchHeaderName, uint8 * pHeaderValueBuffer, uint32 unBufferSize); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseBodySize(intptr_t instancePtr, HTTPRequestHandle hRequest, uint32 * unBodySize); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseBodyData(intptr_t instancePtr, HTTPRequestHandle hRequest, uint8 * pBodyDataBuffer, uint32 unBufferSize); +S_API bool SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData(intptr_t instancePtr, HTTPRequestHandle hRequest, uint32 cOffset, uint8 * pBodyDataBuffer, uint32 unBufferSize); +S_API bool SteamAPI_ISteamHTTP_ReleaseHTTPRequest(intptr_t instancePtr, HTTPRequestHandle hRequest); +S_API bool SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct(intptr_t instancePtr, HTTPRequestHandle hRequest, float * pflPercentOut); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody(intptr_t instancePtr, HTTPRequestHandle hRequest, const char * pchContentType, uint8 * pubBody, uint32 unBodyLen); +S_API HTTPCookieContainerHandle SteamAPI_ISteamHTTP_CreateCookieContainer(intptr_t instancePtr, bool bAllowResponsesToModify); +S_API bool SteamAPI_ISteamHTTP_ReleaseCookieContainer(intptr_t instancePtr, HTTPCookieContainerHandle hCookieContainer); +S_API bool SteamAPI_ISteamHTTP_SetCookie(intptr_t instancePtr, HTTPCookieContainerHandle hCookieContainer, const char * pchHost, const char * pchUrl, const char * pchCookie); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer(intptr_t instancePtr, HTTPRequestHandle hRequest, HTTPCookieContainerHandle hCookieContainer); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo(intptr_t instancePtr, HTTPRequestHandle hRequest, const char * pchUserAgentInfo); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate(intptr_t instancePtr, HTTPRequestHandle hRequest, bool bRequireVerifiedCertificate); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS(intptr_t instancePtr, HTTPRequestHandle hRequest, uint32 unMilliseconds); +S_API bool SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut(intptr_t instancePtr, HTTPRequestHandle hRequest, bool * pbWasTimedOut); +S_API bool SteamAPI_ISteamInput_Init(intptr_t instancePtr); +S_API bool SteamAPI_ISteamInput_Shutdown(intptr_t instancePtr); +S_API void SteamAPI_ISteamInput_RunFrame(intptr_t instancePtr); +S_API int SteamAPI_ISteamInput_GetConnectedControllers(intptr_t instancePtr, InputHandle_t * handlesOut); +S_API InputActionSetHandle_t SteamAPI_ISteamInput_GetActionSetHandle(intptr_t instancePtr, const char * pszActionSetName); +S_API void SteamAPI_ISteamInput_ActivateActionSet(intptr_t instancePtr, InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle); +S_API InputActionSetHandle_t SteamAPI_ISteamInput_GetCurrentActionSet(intptr_t instancePtr, InputHandle_t inputHandle); +S_API void SteamAPI_ISteamInput_ActivateActionSetLayer(intptr_t instancePtr, InputHandle_t inputHandle, InputActionSetHandle_t actionSetLayerHandle); +S_API void SteamAPI_ISteamInput_DeactivateActionSetLayer(intptr_t instancePtr, InputHandle_t inputHandle, InputActionSetHandle_t actionSetLayerHandle); +S_API void SteamAPI_ISteamInput_DeactivateAllActionSetLayers(intptr_t instancePtr, InputHandle_t inputHandle); +S_API int SteamAPI_ISteamInput_GetActiveActionSetLayers(intptr_t instancePtr, InputHandle_t inputHandle, InputActionSetHandle_t * handlesOut); +S_API InputDigitalActionHandle_t SteamAPI_ISteamInput_GetDigitalActionHandle(intptr_t instancePtr, const char * pszActionName); +S_API struct InputDigitalActionData_t SteamAPI_ISteamInput_GetDigitalActionData(intptr_t instancePtr, InputHandle_t inputHandle, InputDigitalActionHandle_t digitalActionHandle); +S_API int SteamAPI_ISteamInput_GetDigitalActionOrigins(intptr_t instancePtr, InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputDigitalActionHandle_t digitalActionHandle, EInputActionOrigin * originsOut); +S_API InputAnalogActionHandle_t SteamAPI_ISteamInput_GetAnalogActionHandle(intptr_t instancePtr, const char * pszActionName); +S_API struct InputAnalogActionData_t SteamAPI_ISteamInput_GetAnalogActionData(intptr_t instancePtr, InputHandle_t inputHandle, InputAnalogActionHandle_t analogActionHandle); +S_API int SteamAPI_ISteamInput_GetAnalogActionOrigins(intptr_t instancePtr, InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputAnalogActionHandle_t analogActionHandle, EInputActionOrigin * originsOut); +S_API const char * SteamAPI_ISteamInput_GetGlyphForActionOrigin(intptr_t instancePtr, EInputActionOrigin eOrigin); +S_API const char * SteamAPI_ISteamInput_GetStringForActionOrigin(intptr_t instancePtr, EInputActionOrigin eOrigin); +S_API void SteamAPI_ISteamInput_StopAnalogActionMomentum(intptr_t instancePtr, InputHandle_t inputHandle, InputAnalogActionHandle_t eAction); +S_API struct InputMotionData_t SteamAPI_ISteamInput_GetMotionData(intptr_t instancePtr, InputHandle_t inputHandle); +S_API void SteamAPI_ISteamInput_TriggerVibration(intptr_t instancePtr, InputHandle_t inputHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed); +S_API void SteamAPI_ISteamInput_SetLEDColor(intptr_t instancePtr, InputHandle_t inputHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags); +S_API void SteamAPI_ISteamInput_TriggerHapticPulse(intptr_t instancePtr, InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec); +S_API void SteamAPI_ISteamInput_TriggerRepeatedHapticPulse(intptr_t instancePtr, InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags); +S_API bool SteamAPI_ISteamInput_ShowBindingPanel(intptr_t instancePtr, InputHandle_t inputHandle); +S_API ESteamInputType SteamAPI_ISteamInput_GetInputTypeForHandle(intptr_t instancePtr, InputHandle_t inputHandle); +S_API InputHandle_t SteamAPI_ISteamInput_GetControllerForGamepadIndex(intptr_t instancePtr, int nIndex); +S_API int SteamAPI_ISteamInput_GetGamepadIndexForController(intptr_t instancePtr, InputHandle_t ulinputHandle); +S_API const char * SteamAPI_ISteamInput_GetStringForXboxOrigin(intptr_t instancePtr, EXboxOrigin eOrigin); +S_API const char * SteamAPI_ISteamInput_GetGlyphForXboxOrigin(intptr_t instancePtr, EXboxOrigin eOrigin); +S_API EInputActionOrigin SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin(intptr_t instancePtr, InputHandle_t inputHandle, EXboxOrigin eOrigin); +S_API EInputActionOrigin SteamAPI_ISteamInput_TranslateActionOrigin(intptr_t instancePtr, ESteamInputType eDestinationInputType, EInputActionOrigin eSourceOrigin); +S_API bool SteamAPI_ISteamInput_GetDeviceBindingRevision(intptr_t instancePtr, InputHandle_t inputHandle, int * pMajor, int * pMinor); +S_API uint32 SteamAPI_ISteamInput_GetRemotePlaySessionID(intptr_t instancePtr, InputHandle_t inputHandle); +S_API bool SteamAPI_ISteamController_Init(intptr_t instancePtr); +S_API bool SteamAPI_ISteamController_Shutdown(intptr_t instancePtr); +S_API void SteamAPI_ISteamController_RunFrame(intptr_t instancePtr); +S_API int SteamAPI_ISteamController_GetConnectedControllers(intptr_t instancePtr, ControllerHandle_t * handlesOut); +S_API ControllerActionSetHandle_t SteamAPI_ISteamController_GetActionSetHandle(intptr_t instancePtr, const char * pszActionSetName); +S_API void SteamAPI_ISteamController_ActivateActionSet(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle); +S_API ControllerActionSetHandle_t SteamAPI_ISteamController_GetCurrentActionSet(intptr_t instancePtr, ControllerHandle_t controllerHandle); +S_API void SteamAPI_ISteamController_ActivateActionSetLayer(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle); +S_API void SteamAPI_ISteamController_DeactivateActionSetLayer(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle); +S_API void SteamAPI_ISteamController_DeactivateAllActionSetLayers(intptr_t instancePtr, ControllerHandle_t controllerHandle); +S_API int SteamAPI_ISteamController_GetActiveActionSetLayers(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t * handlesOut); +S_API ControllerDigitalActionHandle_t SteamAPI_ISteamController_GetDigitalActionHandle(intptr_t instancePtr, const char * pszActionName); +S_API struct InputDigitalActionData_t SteamAPI_ISteamController_GetDigitalActionData(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle); +S_API int SteamAPI_ISteamController_GetDigitalActionOrigins(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, EControllerActionOrigin * originsOut); +S_API ControllerAnalogActionHandle_t SteamAPI_ISteamController_GetAnalogActionHandle(intptr_t instancePtr, const char * pszActionName); +S_API struct InputAnalogActionData_t SteamAPI_ISteamController_GetAnalogActionData(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle); +S_API int SteamAPI_ISteamController_GetAnalogActionOrigins(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin * originsOut); +S_API const char * SteamAPI_ISteamController_GetGlyphForActionOrigin(intptr_t instancePtr, EControllerActionOrigin eOrigin); +S_API const char * SteamAPI_ISteamController_GetStringForActionOrigin(intptr_t instancePtr, EControllerActionOrigin eOrigin); +S_API void SteamAPI_ISteamController_StopAnalogActionMomentum(intptr_t instancePtr, ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction); +S_API struct InputMotionData_t SteamAPI_ISteamController_GetMotionData(intptr_t instancePtr, ControllerHandle_t controllerHandle); +S_API void SteamAPI_ISteamController_TriggerHapticPulse(intptr_t instancePtr, ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec); +S_API void SteamAPI_ISteamController_TriggerRepeatedHapticPulse(intptr_t instancePtr, ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags); +S_API void SteamAPI_ISteamController_TriggerVibration(intptr_t instancePtr, ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed); +S_API void SteamAPI_ISteamController_SetLEDColor(intptr_t instancePtr, ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags); +S_API bool SteamAPI_ISteamController_ShowBindingPanel(intptr_t instancePtr, ControllerHandle_t controllerHandle); +S_API ESteamInputType SteamAPI_ISteamController_GetInputTypeForHandle(intptr_t instancePtr, ControllerHandle_t controllerHandle); +S_API ControllerHandle_t SteamAPI_ISteamController_GetControllerForGamepadIndex(intptr_t instancePtr, int nIndex); +S_API int SteamAPI_ISteamController_GetGamepadIndexForController(intptr_t instancePtr, ControllerHandle_t ulControllerHandle); +S_API const char * SteamAPI_ISteamController_GetStringForXboxOrigin(intptr_t instancePtr, EXboxOrigin eOrigin); +S_API const char * SteamAPI_ISteamController_GetGlyphForXboxOrigin(intptr_t instancePtr, EXboxOrigin eOrigin); +S_API EControllerActionOrigin SteamAPI_ISteamController_GetActionOriginFromXboxOrigin(intptr_t instancePtr, ControllerHandle_t controllerHandle, EXboxOrigin eOrigin); +S_API EControllerActionOrigin SteamAPI_ISteamController_TranslateActionOrigin(intptr_t instancePtr, ESteamInputType eDestinationInputType, EControllerActionOrigin eSourceOrigin); +S_API bool SteamAPI_ISteamController_GetControllerBindingRevision(intptr_t instancePtr, ControllerHandle_t controllerHandle, int * pMajor, int * pMinor); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryUserUGCRequest(intptr_t instancePtr, AccountID_t unAccountID, EUserUGCList eListType, EUGCMatchingUGCType eMatchingUGCType, EUserUGCListSortOrder eSortOrder, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryAllUGCRequest(intptr_t instancePtr, EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryAllUGCRequest0(intptr_t instancePtr, EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, const char * pchCursor); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest(intptr_t instancePtr, PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SendQueryUGCRequest(intptr_t instancePtr, UGCQueryHandle_t handle); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCResult(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, struct SteamUGCDetails_t * pDetails); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCPreviewURL(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, char * pchURL, uint32 cchURLSize); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCMetadata(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, char * pchMetadata, uint32 cchMetadatasize); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCChildren(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, PublishedFileId_t * pvecPublishedFileID, uint32 cMaxEntries); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCStatistic(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, EItemStatistic eStatType, uint64 * pStatValue); +S_API uint32 SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, char * pchURLOrVideoID, uint32 cchURLSize, char * pchOriginalFileName, uint32 cchOriginalFileNameSize, EItemPreviewType * pPreviewType); +S_API uint32 SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, uint32 keyValueTagIndex, char * pchKey, uint32 cchKeySize, char * pchValue, uint32 cchValueSize); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag0(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 index, const char * pchKey, char * pchValue, uint32 cchValueSize); +S_API bool SteamAPI_ISteamUGC_ReleaseQueryUGCRequest(intptr_t instancePtr, UGCQueryHandle_t handle); +S_API bool SteamAPI_ISteamUGC_AddRequiredTag(intptr_t instancePtr, UGCQueryHandle_t handle, const char * pTagName); +S_API bool SteamAPI_ISteamUGC_AddExcludedTag(intptr_t instancePtr, UGCQueryHandle_t handle, const char * pTagName); +S_API bool SteamAPI_ISteamUGC_SetReturnOnlyIDs(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnOnlyIDs); +S_API bool SteamAPI_ISteamUGC_SetReturnKeyValueTags(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnKeyValueTags); +S_API bool SteamAPI_ISteamUGC_SetReturnLongDescription(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnLongDescription); +S_API bool SteamAPI_ISteamUGC_SetReturnMetadata(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnMetadata); +S_API bool SteamAPI_ISteamUGC_SetReturnChildren(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnChildren); +S_API bool SteamAPI_ISteamUGC_SetReturnAdditionalPreviews(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnAdditionalPreviews); +S_API bool SteamAPI_ISteamUGC_SetReturnTotalOnly(intptr_t instancePtr, UGCQueryHandle_t handle, bool bReturnTotalOnly); +S_API bool SteamAPI_ISteamUGC_SetReturnPlaytimeStats(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 unDays); +S_API bool SteamAPI_ISteamUGC_SetLanguage(intptr_t instancePtr, UGCQueryHandle_t handle, const char * pchLanguage); +S_API bool SteamAPI_ISteamUGC_SetAllowCachedResponse(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 unMaxAgeSeconds); +S_API bool SteamAPI_ISteamUGC_SetCloudFileNameFilter(intptr_t instancePtr, UGCQueryHandle_t handle, const char * pMatchCloudFileName); +S_API bool SteamAPI_ISteamUGC_SetMatchAnyTag(intptr_t instancePtr, UGCQueryHandle_t handle, bool bMatchAnyTag); +S_API bool SteamAPI_ISteamUGC_SetSearchText(intptr_t instancePtr, UGCQueryHandle_t handle, const char * pSearchText); +S_API bool SteamAPI_ISteamUGC_SetRankedByTrendDays(intptr_t instancePtr, UGCQueryHandle_t handle, uint32 unDays); +S_API bool SteamAPI_ISteamUGC_AddRequiredKeyValueTag(intptr_t instancePtr, UGCQueryHandle_t handle, const char * pKey, const char * pValue); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RequestUGCDetails(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, uint32 unMaxAgeSeconds); +S_API SteamAPICall_t SteamAPI_ISteamUGC_CreateItem(intptr_t instancePtr, AppId_t nConsumerAppId, EWorkshopFileType eFileType); +S_API UGCUpdateHandle_t SteamAPI_ISteamUGC_StartItemUpdate(intptr_t instancePtr, AppId_t nConsumerAppId, PublishedFileId_t nPublishedFileID); +S_API bool SteamAPI_ISteamUGC_SetItemTitle(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchTitle); +S_API bool SteamAPI_ISteamUGC_SetItemDescription(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchDescription); +S_API bool SteamAPI_ISteamUGC_SetItemUpdateLanguage(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchLanguage); +S_API bool SteamAPI_ISteamUGC_SetItemMetadata(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchMetaData); +S_API bool SteamAPI_ISteamUGC_SetItemVisibility(intptr_t instancePtr, UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVisibility eVisibility); +S_API bool SteamAPI_ISteamUGC_SetItemTags(intptr_t instancePtr, UGCUpdateHandle_t updateHandle, const struct SteamParamStringArray_t * pTags); +S_API bool SteamAPI_ISteamUGC_SetItemContent(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pszContentFolder); +S_API bool SteamAPI_ISteamUGC_SetItemPreview(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pszPreviewFile); +S_API bool SteamAPI_ISteamUGC_SetAllowLegacyUpload(intptr_t instancePtr, UGCUpdateHandle_t handle, bool bAllowLegacyUpload); +S_API bool SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags(intptr_t instancePtr, UGCUpdateHandle_t handle); +S_API bool SteamAPI_ISteamUGC_RemoveItemKeyValueTags(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchKey); +S_API bool SteamAPI_ISteamUGC_AddItemKeyValueTag(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchKey, const char * pchValue); +S_API bool SteamAPI_ISteamUGC_AddItemPreviewFile(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pszPreviewFile, EItemPreviewType type); +S_API bool SteamAPI_ISteamUGC_AddItemPreviewVideo(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pszVideoID); +S_API bool SteamAPI_ISteamUGC_UpdateItemPreviewFile(intptr_t instancePtr, UGCUpdateHandle_t handle, uint32 index, const char * pszPreviewFile); +S_API bool SteamAPI_ISteamUGC_UpdateItemPreviewVideo(intptr_t instancePtr, UGCUpdateHandle_t handle, uint32 index, const char * pszVideoID); +S_API bool SteamAPI_ISteamUGC_RemoveItemPreview(intptr_t instancePtr, UGCUpdateHandle_t handle, uint32 index); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SubmitItemUpdate(intptr_t instancePtr, UGCUpdateHandle_t handle, const char * pchChangeNote); +S_API EItemUpdateStatus SteamAPI_ISteamUGC_GetItemUpdateProgress(intptr_t instancePtr, UGCUpdateHandle_t handle, uint64 * punBytesProcessed, uint64 * punBytesTotal); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SetUserItemVote(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, bool bVoteUp); +S_API SteamAPICall_t SteamAPI_ISteamUGC_GetUserItemVote(intptr_t instancePtr, PublishedFileId_t nPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_AddItemToFavorites(intptr_t instancePtr, AppId_t nAppId, PublishedFileId_t nPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RemoveItemFromFavorites(intptr_t instancePtr, AppId_t nAppId, PublishedFileId_t nPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SubscribeItem(intptr_t instancePtr, PublishedFileId_t nPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_UnsubscribeItem(intptr_t instancePtr, PublishedFileId_t nPublishedFileID); +S_API uint32 SteamAPI_ISteamUGC_GetNumSubscribedItems(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamUGC_GetSubscribedItems(intptr_t instancePtr, PublishedFileId_t * pvecPublishedFileID, uint32 cMaxEntries); +S_API uint32 SteamAPI_ISteamUGC_GetItemState(intptr_t instancePtr, PublishedFileId_t nPublishedFileID); +S_API bool SteamAPI_ISteamUGC_GetItemInstallInfo(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, uint64 * punSizeOnDisk, char * pchFolder, uint32 cchFolderSize, uint32 * punTimeStamp); +S_API bool SteamAPI_ISteamUGC_GetItemDownloadInfo(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, uint64 * punBytesDownloaded, uint64 * punBytesTotal); +S_API bool SteamAPI_ISteamUGC_DownloadItem(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, bool bHighPriority); +S_API bool SteamAPI_ISteamUGC_BInitWorkshopForGameServer(intptr_t instancePtr, DepotId_t unWorkshopDepotID, const char * pszFolder); +S_API void SteamAPI_ISteamUGC_SuspendDownloads(intptr_t instancePtr, bool bSuspend); +S_API SteamAPICall_t SteamAPI_ISteamUGC_StartPlaytimeTracking(intptr_t instancePtr, PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs); +S_API SteamAPICall_t SteamAPI_ISteamUGC_StopPlaytimeTracking(intptr_t instancePtr, PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs); +S_API SteamAPICall_t SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamUGC_AddDependency(intptr_t instancePtr, PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RemoveDependency(intptr_t instancePtr, PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_AddAppDependency(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, AppId_t nAppID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RemoveAppDependency(intptr_t instancePtr, PublishedFileId_t nPublishedFileID, AppId_t nAppID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_GetAppDependencies(intptr_t instancePtr, PublishedFileId_t nPublishedFileID); +S_API SteamAPICall_t SteamAPI_ISteamUGC_DeleteItem(intptr_t instancePtr, PublishedFileId_t nPublishedFileID); +S_API uint32 SteamAPI_ISteamAppList_GetNumInstalledApps(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamAppList_GetInstalledApps(intptr_t instancePtr, AppId_t * pvecAppID, uint32 unMaxAppIDs); +S_API int SteamAPI_ISteamAppList_GetAppName(intptr_t instancePtr, AppId_t nAppID, char * pchName, int cchNameMax); +S_API int SteamAPI_ISteamAppList_GetAppInstallDir(intptr_t instancePtr, AppId_t nAppID, char * pchDirectory, int cchNameMax); +S_API int SteamAPI_ISteamAppList_GetAppBuildId(intptr_t instancePtr, AppId_t nAppID); +S_API void SteamAPI_ISteamHTMLSurface_DestructISteamHTMLSurface(intptr_t instancePtr); +S_API bool SteamAPI_ISteamHTMLSurface_Init(intptr_t instancePtr); +S_API bool SteamAPI_ISteamHTMLSurface_Shutdown(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamHTMLSurface_CreateBrowser(intptr_t instancePtr, const char * pchUserAgent, const char * pchUserCSS); +S_API void SteamAPI_ISteamHTMLSurface_RemoveBrowser(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_LoadURL(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, const char * pchURL, const char * pchPostData); +S_API void SteamAPI_ISteamHTMLSurface_SetSize(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight); +S_API void SteamAPI_ISteamHTMLSurface_StopLoad(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_Reload(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_GoBack(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_GoForward(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_AddHeader(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, const char * pchKey, const char * pchValue); +S_API void SteamAPI_ISteamHTMLSurface_ExecuteJavascript(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, const char * pchScript); +S_API void SteamAPI_ISteamHTMLSurface_MouseUp(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, ISteamHTMLSurface::EHTMLMouseButton eMouseButton); +S_API void SteamAPI_ISteamHTMLSurface_MouseDown(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, ISteamHTMLSurface::EHTMLMouseButton eMouseButton); +S_API void SteamAPI_ISteamHTMLSurface_MouseDoubleClick(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, ISteamHTMLSurface::EHTMLMouseButton eMouseButton); +S_API void SteamAPI_ISteamHTMLSurface_MouseMove(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, int x, int y); +S_API void SteamAPI_ISteamHTMLSurface_MouseWheel(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, int32 nDelta); +S_API void SteamAPI_ISteamHTMLSurface_KeyDown(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, ISteamHTMLSurface::EHTMLKeyModifiers eHTMLKeyModifiers, bool bIsSystemKey); +S_API void SteamAPI_ISteamHTMLSurface_KeyUp(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, ISteamHTMLSurface::EHTMLKeyModifiers eHTMLKeyModifiers); +S_API void SteamAPI_ISteamHTMLSurface_KeyChar(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, ISteamHTMLSurface::EHTMLKeyModifiers eHTMLKeyModifiers); +S_API void SteamAPI_ISteamHTMLSurface_SetHorizontalScroll(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll); +S_API void SteamAPI_ISteamHTMLSurface_SetVerticalScroll(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll); +S_API void SteamAPI_ISteamHTMLSurface_SetKeyFocus(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, bool bHasKeyFocus); +S_API void SteamAPI_ISteamHTMLSurface_ViewSource(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_CopyToClipboard(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_PasteFromClipboard(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_Find(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, const char * pchSearchStr, bool bCurrentlyInFind, bool bReverse); +S_API void SteamAPI_ISteamHTMLSurface_StopFind(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_GetLinkAtPosition(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, int x, int y); +S_API void SteamAPI_ISteamHTMLSurface_SetCookie(intptr_t instancePtr, const char * pchHostname, const char * pchKey, const char * pchValue, const char * pchPath, RTime32 nExpires, bool bSecure, bool bHTTPOnly); +S_API void SteamAPI_ISteamHTMLSurface_SetPageScaleFactor(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY); +S_API void SteamAPI_ISteamHTMLSurface_SetBackgroundMode(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, bool bBackgroundMode); +S_API void SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, float flDPIScaling); +S_API void SteamAPI_ISteamHTMLSurface_OpenDeveloperTools(intptr_t instancePtr, HHTMLBrowser unBrowserHandle); +S_API void SteamAPI_ISteamHTMLSurface_AllowStartRequest(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, bool bAllowed); +S_API void SteamAPI_ISteamHTMLSurface_JSDialogResponse(intptr_t instancePtr, HHTMLBrowser unBrowserHandle, bool bResult); +S_API EResult SteamAPI_ISteamInventory_GetResultStatus(intptr_t instancePtr, SteamInventoryResult_t resultHandle); +S_API bool SteamAPI_ISteamInventory_GetResultItems(intptr_t instancePtr, SteamInventoryResult_t resultHandle, struct SteamItemDetails_t * pOutItemsArray, uint32 * punOutItemsArraySize); +S_API bool SteamAPI_ISteamInventory_GetResultItemProperty(intptr_t instancePtr, SteamInventoryResult_t resultHandle, uint32 unItemIndex, const char * pchPropertyName, char * pchValueBuffer, uint32 * punValueBufferSizeOut); +S_API uint32 SteamAPI_ISteamInventory_GetResultTimestamp(intptr_t instancePtr, SteamInventoryResult_t resultHandle); +S_API bool SteamAPI_ISteamInventory_CheckResultSteamID(intptr_t instancePtr, SteamInventoryResult_t resultHandle, class CSteamID steamIDExpected); +S_API void SteamAPI_ISteamInventory_DestroyResult(intptr_t instancePtr, SteamInventoryResult_t resultHandle); +S_API bool SteamAPI_ISteamInventory_GetAllItems(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle); +S_API bool SteamAPI_ISteamInventory_GetItemsByID(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, const SteamItemInstanceID_t * pInstanceIDs, uint32 unCountInstanceIDs); +S_API bool SteamAPI_ISteamInventory_SerializeResult(intptr_t instancePtr, SteamInventoryResult_t resultHandle, void * pOutBuffer, uint32 * punOutBufferSize); +S_API bool SteamAPI_ISteamInventory_DeserializeResult(intptr_t instancePtr, SteamInventoryResult_t * pOutResultHandle, const void * pBuffer, uint32 unBufferSize, bool bRESERVED_MUST_BE_FALSE); +S_API bool SteamAPI_ISteamInventory_GenerateItems(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, const SteamItemDef_t * pArrayItemDefs, const uint32 * punArrayQuantity, uint32 unArrayLength); +S_API bool SteamAPI_ISteamInventory_GrantPromoItems(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle); +S_API bool SteamAPI_ISteamInventory_AddPromoItem(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, SteamItemDef_t itemDef); +S_API bool SteamAPI_ISteamInventory_AddPromoItems(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, const SteamItemDef_t * pArrayItemDefs, uint32 unArrayLength); +S_API bool SteamAPI_ISteamInventory_ConsumeItem(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, SteamItemInstanceID_t itemConsume, uint32 unQuantity); +S_API bool SteamAPI_ISteamInventory_ExchangeItems(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, const SteamItemDef_t * pArrayGenerate, const uint32 * punArrayGenerateQuantity, uint32 unArrayGenerateLength, const SteamItemInstanceID_t * pArrayDestroy, const uint32 * punArrayDestroyQuantity, uint32 unArrayDestroyLength); +S_API bool SteamAPI_ISteamInventory_TransferItemQuantity(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, SteamItemInstanceID_t itemIdSource, uint32 unQuantity, SteamItemInstanceID_t itemIdDest); +S_API void SteamAPI_ISteamInventory_SendItemDropHeartbeat(intptr_t instancePtr); +S_API bool SteamAPI_ISteamInventory_TriggerItemDrop(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, SteamItemDef_t dropListDefinition); +S_API bool SteamAPI_ISteamInventory_TradeItems(intptr_t instancePtr, SteamInventoryResult_t * pResultHandle, class CSteamID steamIDTradePartner, const SteamItemInstanceID_t * pArrayGive, const uint32 * pArrayGiveQuantity, uint32 nArrayGiveLength, const SteamItemInstanceID_t * pArrayGet, const uint32 * pArrayGetQuantity, uint32 nArrayGetLength); +S_API bool SteamAPI_ISteamInventory_LoadItemDefinitions(intptr_t instancePtr); +S_API bool SteamAPI_ISteamInventory_GetItemDefinitionIDs(intptr_t instancePtr, SteamItemDef_t * pItemDefIDs, uint32 * punItemDefIDsArraySize); +S_API bool SteamAPI_ISteamInventory_GetItemDefinitionProperty(intptr_t instancePtr, SteamItemDef_t iDefinition, const char * pchPropertyName, char * pchValueBuffer, uint32 * punValueBufferSizeOut); +S_API SteamAPICall_t SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs(intptr_t instancePtr, class CSteamID steamID); +S_API bool SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs(intptr_t instancePtr, class CSteamID steamID, SteamItemDef_t * pItemDefIDs, uint32 * punItemDefIDsArraySize); +S_API SteamAPICall_t SteamAPI_ISteamInventory_StartPurchase(intptr_t instancePtr, const SteamItemDef_t * pArrayItemDefs, const uint32 * punArrayQuantity, uint32 unArrayLength); +S_API SteamAPICall_t SteamAPI_ISteamInventory_RequestPrices(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamInventory_GetNumItemsWithPrices(intptr_t instancePtr); +S_API bool SteamAPI_ISteamInventory_GetItemsWithPrices(intptr_t instancePtr, SteamItemDef_t * pArrayItemDefs, uint64 * pCurrentPrices, uint64 * pBasePrices, uint32 unArrayLength); +S_API bool SteamAPI_ISteamInventory_GetItemPrice(intptr_t instancePtr, SteamItemDef_t iDefinition, uint64 * pCurrentPrice, uint64 * pBasePrice); +S_API SteamInventoryUpdateHandle_t SteamAPI_ISteamInventory_StartUpdateProperties(intptr_t instancePtr); +S_API bool SteamAPI_ISteamInventory_RemoveProperty(intptr_t instancePtr, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName); +S_API bool SteamAPI_ISteamInventory_SetProperty(intptr_t instancePtr, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, const char * pchPropertyValue); +S_API bool SteamAPI_ISteamInventory_SetProperty0(intptr_t instancePtr, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, bool bValue); +S_API bool SteamAPI_ISteamInventory_SetProperty1(intptr_t instancePtr, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, int64 nValue); +S_API bool SteamAPI_ISteamInventory_SetProperty2(intptr_t instancePtr, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, float flValue); +S_API bool SteamAPI_ISteamInventory_SubmitUpdateProperties(intptr_t instancePtr, SteamInventoryUpdateHandle_t handle, SteamInventoryResult_t * pResultHandle); +S_API void SteamAPI_ISteamVideo_GetVideoURL(intptr_t instancePtr, AppId_t unVideoAppID); +S_API bool SteamAPI_ISteamVideo_IsBroadcasting(intptr_t instancePtr, int * pnNumViewers); +S_API void SteamAPI_ISteamVideo_GetOPFSettings(intptr_t instancePtr, AppId_t unVideoAppID); +S_API bool SteamAPI_ISteamVideo_GetOPFStringForApp(intptr_t instancePtr, AppId_t unVideoAppID, char * pchBuffer, int32 * pnBufferSize); +S_API bool SteamAPI_ISteamTV_IsBroadcasting(intptr_t instancePtr, int * pnNumViewers); +S_API void SteamAPI_ISteamTV_AddBroadcastGameData(intptr_t instancePtr, const char * pchKey, const char * pchValue); +S_API void SteamAPI_ISteamTV_RemoveBroadcastGameData(intptr_t instancePtr, const char * pchKey); +S_API void SteamAPI_ISteamTV_AddTimelineMarker(intptr_t instancePtr, const char * pchTemplateName, bool bPersistent, uint8 nColorR, uint8 nColorG, uint8 nColorB); +S_API void SteamAPI_ISteamTV_RemoveTimelineMarker(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamTV_AddRegion(intptr_t instancePtr, const char * pchElementName, const char * pchTimelineDataSection, const struct SteamTVRegion_t * pSteamTVRegion, ESteamTVRegionBehavior eSteamTVRegionBehavior); +S_API void SteamAPI_ISteamTV_RemoveRegion(intptr_t instancePtr, uint32 unRegionHandle); +S_API bool SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled(intptr_t instancePtr); +S_API bool SteamAPI_ISteamParentalSettings_BIsParentalLockLocked(intptr_t instancePtr); +S_API bool SteamAPI_ISteamParentalSettings_BIsAppBlocked(intptr_t instancePtr, AppId_t nAppID); +S_API bool SteamAPI_ISteamParentalSettings_BIsAppInBlockList(intptr_t instancePtr, AppId_t nAppID); +S_API bool SteamAPI_ISteamParentalSettings_BIsFeatureBlocked(intptr_t instancePtr, EParentalFeature eFeature); +S_API bool SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList(intptr_t instancePtr, EParentalFeature eFeature); +S_API uint32 SteamAPI_ISteamRemotePlay_GetSessionCount(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamRemotePlay_GetSessionID(intptr_t instancePtr, int iSessionIndex); +S_API uint64 SteamAPI_ISteamRemotePlay_GetSessionSteamID(intptr_t instancePtr, uint32 unSessionID); +S_API const char * SteamAPI_ISteamRemotePlay_GetSessionClientName(intptr_t instancePtr, uint32 unSessionID); +S_API ESteamDeviceFormFactor SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor(intptr_t instancePtr, uint32 unSessionID); +S_API bool SteamAPI_ISteamRemotePlay_BGetSessionClientResolution(intptr_t instancePtr, uint32 unSessionID, int * pnResolutionX, int * pnResolutionY); +S_API bool SteamAPI_ISteamGameServer_InitGameServer(intptr_t instancePtr, uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char * pchVersionString); +S_API void SteamAPI_ISteamGameServer_SetProduct(intptr_t instancePtr, const char * pszProduct); +S_API void SteamAPI_ISteamGameServer_SetGameDescription(intptr_t instancePtr, const char * pszGameDescription); +S_API void SteamAPI_ISteamGameServer_SetModDir(intptr_t instancePtr, const char * pszModDir); +S_API void SteamAPI_ISteamGameServer_SetDedicatedServer(intptr_t instancePtr, bool bDedicated); +S_API void SteamAPI_ISteamGameServer_LogOn(intptr_t instancePtr, const char * pszToken); +S_API void SteamAPI_ISteamGameServer_LogOnAnonymous(intptr_t instancePtr); +S_API void SteamAPI_ISteamGameServer_LogOff(intptr_t instancePtr); +S_API bool SteamAPI_ISteamGameServer_BLoggedOn(intptr_t instancePtr); +S_API bool SteamAPI_ISteamGameServer_BSecure(intptr_t instancePtr); +S_API uint64 SteamAPI_ISteamGameServer_GetSteamID(intptr_t instancePtr); +S_API bool SteamAPI_ISteamGameServer_WasRestartRequested(intptr_t instancePtr); +S_API void SteamAPI_ISteamGameServer_SetMaxPlayerCount(intptr_t instancePtr, int cPlayersMax); +S_API void SteamAPI_ISteamGameServer_SetBotPlayerCount(intptr_t instancePtr, int cBotplayers); +S_API void SteamAPI_ISteamGameServer_SetServerName(intptr_t instancePtr, const char * pszServerName); +S_API void SteamAPI_ISteamGameServer_SetMapName(intptr_t instancePtr, const char * pszMapName); +S_API void SteamAPI_ISteamGameServer_SetPasswordProtected(intptr_t instancePtr, bool bPasswordProtected); +S_API void SteamAPI_ISteamGameServer_SetSpectatorPort(intptr_t instancePtr, uint16 unSpectatorPort); +S_API void SteamAPI_ISteamGameServer_SetSpectatorServerName(intptr_t instancePtr, const char * pszSpectatorServerName); +S_API void SteamAPI_ISteamGameServer_ClearAllKeyValues(intptr_t instancePtr); +S_API void SteamAPI_ISteamGameServer_SetKeyValue(intptr_t instancePtr, const char * pKey, const char * pValue); +S_API void SteamAPI_ISteamGameServer_SetGameTags(intptr_t instancePtr, const char * pchGameTags); +S_API void SteamAPI_ISteamGameServer_SetGameData(intptr_t instancePtr, const char * pchGameData); +S_API void SteamAPI_ISteamGameServer_SetRegion(intptr_t instancePtr, const char * pszRegion); +S_API bool SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate(intptr_t instancePtr, uint32 unIPClient, const void * pvAuthBlob, uint32 cubAuthBlobSize, class CSteamID * pSteamIDUser); +S_API uint64 SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection(intptr_t instancePtr); +S_API void SteamAPI_ISteamGameServer_SendUserDisconnect(intptr_t instancePtr, class CSteamID steamIDUser); +S_API bool SteamAPI_ISteamGameServer_BUpdateUserData(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchPlayerName, uint32 uScore); +S_API HAuthTicket SteamAPI_ISteamGameServer_GetAuthSessionTicket(intptr_t instancePtr, void * pTicket, int cbMaxTicket, uint32 * pcbTicket); +S_API EBeginAuthSessionResult SteamAPI_ISteamGameServer_BeginAuthSession(intptr_t instancePtr, const void * pAuthTicket, int cbAuthTicket, class CSteamID steamID); +S_API void SteamAPI_ISteamGameServer_EndAuthSession(intptr_t instancePtr, class CSteamID steamID); +S_API void SteamAPI_ISteamGameServer_CancelAuthTicket(intptr_t instancePtr, HAuthTicket hAuthTicket); +S_API EUserHasLicenseForAppResult SteamAPI_ISteamGameServer_UserHasLicenseForApp(intptr_t instancePtr, class CSteamID steamID, AppId_t appID); +S_API bool SteamAPI_ISteamGameServer_RequestUserGroupStatus(intptr_t instancePtr, class CSteamID steamIDUser, class CSteamID steamIDGroup); +S_API void SteamAPI_ISteamGameServer_GetGameplayStats(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamGameServer_GetServerReputation(intptr_t instancePtr); +S_API uint32 SteamAPI_ISteamGameServer_GetPublicIP(intptr_t instancePtr); +S_API bool SteamAPI_ISteamGameServer_HandleIncomingPacket(intptr_t instancePtr, const void * pData, int cbData, uint32 srcIP, uint16 srcPort); +S_API int SteamAPI_ISteamGameServer_GetNextOutgoingPacket(intptr_t instancePtr, void * pOut, int cbMaxOut, uint32 * pNetAdr, uint16 * pPort); +S_API void SteamAPI_ISteamGameServer_EnableHeartbeats(intptr_t instancePtr, bool bActive); +S_API void SteamAPI_ISteamGameServer_SetHeartbeatInterval(intptr_t instancePtr, int iHeartbeatInterval); +S_API void SteamAPI_ISteamGameServer_ForceHeartbeat(intptr_t instancePtr); +S_API SteamAPICall_t SteamAPI_ISteamGameServer_AssociateWithClan(intptr_t instancePtr, class CSteamID steamIDClan); +S_API SteamAPICall_t SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility(intptr_t instancePtr, class CSteamID steamIDNewPlayer); +S_API SteamAPICall_t SteamAPI_ISteamGameServerStats_RequestUserStats(intptr_t instancePtr, class CSteamID steamIDUser); +S_API bool SteamAPI_ISteamGameServerStats_GetUserStat(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, int32 * pData); +S_API bool SteamAPI_ISteamGameServerStats_GetUserStat0(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, float * pData); +S_API bool SteamAPI_ISteamGameServerStats_GetUserAchievement(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, bool * pbAchieved); +S_API bool SteamAPI_ISteamGameServerStats_SetUserStat(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, int32 nData); +S_API bool SteamAPI_ISteamGameServerStats_SetUserStat0(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, float fData); +S_API bool SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName, float flCountThisSession, double dSessionLength); +S_API bool SteamAPI_ISteamGameServerStats_SetUserAchievement(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName); +S_API bool SteamAPI_ISteamGameServerStats_ClearUserAchievement(intptr_t instancePtr, class CSteamID steamIDUser, const char * pchName); +S_API SteamAPICall_t SteamAPI_ISteamGameServerStats_StoreUserStats(intptr_t instancePtr, class CSteamID steamIDUser); +#endif // STEAMAPIFLAT_H + + diff --git a/public/steam/steam_api_internal.h b/public/steam/steam_api_internal.h new file mode 100644 index 0000000..5559413 --- /dev/null +++ b/public/steam/steam_api_internal.h @@ -0,0 +1,393 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Internal implementation details of the steamworks SDK. +// +// You should be able to figure out how to use the SDK by reading +// steam_api_common.h, and should not need to understand anything in here. +// +//----------------------------------------------------------------------------- + +#ifdef STEAM_CALLBACK_BEGIN +#error "This file should only be included from steam_api_common.h" +#endif + +#include + +// Internal functions used by the utility CCallback objects to receive callbacks +S_API void S_CALLTYPE SteamAPI_RegisterCallback( class CCallbackBase *pCallback, int iCallback ); +S_API void S_CALLTYPE SteamAPI_UnregisterCallback( class CCallbackBase *pCallback ); +// Internal functions used by the utility CCallResult objects to receive async call results +S_API void S_CALLTYPE SteamAPI_RegisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall ); +S_API void S_CALLTYPE SteamAPI_UnregisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall ); + +S_API HSteamPipe S_CALLTYPE SteamAPI_GetHSteamPipe(); +S_API HSteamUser S_CALLTYPE SteamAPI_GetHSteamUser(); +S_API HSteamPipe S_CALLTYPE SteamGameServer_GetHSteamPipe(); +S_API HSteamUser S_CALLTYPE SteamGameServer_GetHSteamUser(); +S_API void *S_CALLTYPE SteamInternal_ContextInit( void *pContextInitData ); +S_API void *S_CALLTYPE SteamInternal_CreateInterface( const char *ver ); +S_API void *S_CALLTYPE SteamInternal_FindOrCreateUserInterface( HSteamUser hSteamUser, const char *pszVersion ); +S_API void *S_CALLTYPE SteamInternal_FindOrCreateGameServerInterface( HSteamUser hSteamUser, const char *pszVersion ); + +// disable this warning; this pattern need for steam callback registration +#ifdef _MSVC_VER +#pragma warning( push ) +#pragma warning( disable: 4355 ) // 'this' : used in base member initializer list +#endif + +#define _STEAM_CALLBACK_AUTO_HOOK( thisclass, func, param ) +#define _STEAM_CALLBACK_HELPER( _1, _2, SELECTED, ... ) _STEAM_CALLBACK_##SELECTED +#define _STEAM_CALLBACK_SELECT( X, Y ) _STEAM_CALLBACK_HELPER X Y +#define _STEAM_CALLBACK_3( extra_code, thisclass, func, param ) \ + struct CCallbackInternal_ ## func : private CCallbackImpl< sizeof( param ) > { \ + CCallbackInternal_ ## func () { extra_code SteamAPI_RegisterCallback( this, param::k_iCallback ); } \ + CCallbackInternal_ ## func ( const CCallbackInternal_ ## func & ) { extra_code SteamAPI_RegisterCallback( this, param::k_iCallback ); } \ + CCallbackInternal_ ## func & operator=( const CCallbackInternal_ ## func & ) { return *this; } \ + private: virtual void Run( void *pvParam ) { _STEAM_CALLBACK_AUTO_HOOK( thisclass, func, param ) \ + thisclass *pOuter = reinterpret_cast( reinterpret_cast(this) - offsetof( thisclass, m_steamcallback_ ## func ) ); \ + pOuter->func( reinterpret_cast( pvParam ) ); \ + } \ + } m_steamcallback_ ## func ; void func( param *pParam ) +#define _STEAM_CALLBACK_4( _, thisclass, func, param, var ) \ + CCallback< thisclass, param > var; void func( param *pParam ) +#define _STEAM_CALLBACK_GS( _, thisclass, func, param, var ) \ + CCallback< thisclass, param, true > var; void func( param *pParam ) + +template< class T, class P > +inline CCallResult::CCallResult() +{ + m_hAPICall = k_uAPICallInvalid; + m_pObj = nullptr; + m_Func = nullptr; + m_iCallback = P::k_iCallback; +} + +template< class T, class P > +inline void CCallResult::Set( SteamAPICall_t hAPICall, T *p, func_t func ) +{ + if ( m_hAPICall ) + SteamAPI_UnregisterCallResult( this, m_hAPICall ); + + m_hAPICall = hAPICall; + m_pObj = p; + m_Func = func; + + if ( hAPICall ) + SteamAPI_RegisterCallResult( this, hAPICall ); +} + +template< class T, class P > +inline bool CCallResult::IsActive() const +{ + return (m_hAPICall != k_uAPICallInvalid); +} + +template< class T, class P > +inline void CCallResult::Cancel() +{ + if ( m_hAPICall != k_uAPICallInvalid ) + { + SteamAPI_UnregisterCallResult( this, m_hAPICall ); + m_hAPICall = k_uAPICallInvalid; + } +} + +template< class T, class P > +inline CCallResult::~CCallResult() +{ + Cancel(); +} + +template< class T, class P > +inline void CCallResult::Run( void *pvParam ) +{ + m_hAPICall = k_uAPICallInvalid; // caller unregisters for us + (m_pObj->*m_Func)((P *)pvParam, false); +} + +template< class T, class P > +inline void CCallResult::Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) +{ + if ( hSteamAPICall == m_hAPICall ) + { + m_hAPICall = k_uAPICallInvalid; // caller unregisters for us + (m_pObj->*m_Func)((P *)pvParam, bIOFailure); + } +} + +template< class T, class P, bool bGameserver > +inline CCallback< T, P, bGameserver >::CCallback( T *pObj, func_t func ) + : m_pObj( nullptr ), m_Func( nullptr ) +{ + if ( bGameserver ) + { + this->SetGameserverFlag(); + } + Register( pObj, func ); +} + +template< class T, class P, bool bGameserver > +inline void CCallback< T, P, bGameserver >::Register( T *pObj, func_t func ) +{ + if ( !pObj || !func ) + return; + + if ( this->m_nCallbackFlags & CCallbackBase::k_ECallbackFlagsRegistered ) + Unregister(); + + m_pObj = pObj; + m_Func = func; + // SteamAPI_RegisterCallback sets k_ECallbackFlagsRegistered + SteamAPI_RegisterCallback( this, P::k_iCallback ); +} + +template< class T, class P, bool bGameserver > +inline void CCallback< T, P, bGameserver >::Unregister() +{ + // SteamAPI_UnregisterCallback removes k_ECallbackFlagsRegistered + SteamAPI_UnregisterCallback( this ); +} + +template< class T, class P, bool bGameserver > +inline void CCallback< T, P, bGameserver >::Run( void *pvParam ) +{ + (m_pObj->*m_Func)((P *)pvParam); +} + +//----------------------------------------------------------------------------- +// Macros to define steam callback structures. Used internally for debugging +//----------------------------------------------------------------------------- + +#ifdef STEAM_CALLBACK_INSPECTION_ENABLED + #include "../../clientdll/steam_api_callback_inspection.h" +#else + #define STEAM_CALLBACK_BEGIN( callbackname, callbackid ) struct callbackname { enum { k_iCallback = callbackid }; + #define STEAM_CALLBACK_MEMBER( varidx, vartype, varname ) vartype varname ; + #define STEAM_CALLBACK_MEMBER_ARRAY( varidx, vartype, varname, varcount ) vartype varname [ varcount ]; + #define STEAM_CALLBACK_END(nArgs) }; +#endif + +// Forward declare all of the Steam interfaces. (Do we really need to do this?) +class ISteamClient; +class ISteamUser; +class ISteamGameServer; +class ISteamFriends; +class ISteamUtils; +class ISteamMatchmaking; +class ISteamContentServer; +class ISteamMatchmakingServers; +class ISteamUserStats; +class ISteamApps; +class ISteamNetworking; +class ISteamRemoteStorage; +class ISteamScreenshots; +class ISteamMusic; +class ISteamMusicRemote; +class ISteamGameServerStats; +class ISteamPS3OverlayRender; +class ISteamHTTP; +class ISteamController; +class ISteamUGC; +class ISteamAppList; +class ISteamHTMLSurface; +class ISteamInventory; +class ISteamVideo; +class ISteamParentalSettings; +class ISteamGameSearch; +class ISteamInput; +class ISteamParties; +class ISteamTV; +class ISteamRemotePlay; + +//----------------------------------------------------------------------------- +// Purpose: Base values for callback identifiers, each callback must +// have a unique ID. +//----------------------------------------------------------------------------- +enum { k_iSteamUserCallbacks = 100 }; +enum { k_iSteamGameServerCallbacks = 200 }; +enum { k_iSteamFriendsCallbacks = 300 }; +enum { k_iSteamBillingCallbacks = 400 }; +enum { k_iSteamMatchmakingCallbacks = 500 }; +enum { k_iSteamContentServerCallbacks = 600 }; +enum { k_iSteamUtilsCallbacks = 700 }; +enum { k_iClientFriendsCallbacks = 800 }; +enum { k_iClientUserCallbacks = 900 }; +enum { k_iSteamAppsCallbacks = 1000 }; +enum { k_iSteamUserStatsCallbacks = 1100 }; +enum { k_iSteamNetworkingCallbacks = 1200 }; +enum { k_iSteamNetworkingSocketsCallbacks = 1220 }; +enum { k_iSteamNetworkingMessagesCallbacks = 1250 }; +enum { k_iSteamNetworkingUtilsCallbacks = 1280 }; +enum { k_iClientRemoteStorageCallbacks = 1300 }; +enum { k_iClientDepotBuilderCallbacks = 1400 }; +enum { k_iSteamGameServerItemsCallbacks = 1500 }; +enum { k_iClientUtilsCallbacks = 1600 }; +enum { k_iSteamGameCoordinatorCallbacks = 1700 }; +enum { k_iSteamGameServerStatsCallbacks = 1800 }; +enum { k_iSteam2AsyncCallbacks = 1900 }; +enum { k_iSteamGameStatsCallbacks = 2000 }; +enum { k_iClientHTTPCallbacks = 2100 }; +enum { k_iClientScreenshotsCallbacks = 2200 }; +enum { k_iSteamScreenshotsCallbacks = 2300 }; +enum { k_iClientAudioCallbacks = 2400 }; +enum { k_iClientUnifiedMessagesCallbacks = 2500 }; +enum { k_iSteamStreamLauncherCallbacks = 2600 }; +enum { k_iClientControllerCallbacks = 2700 }; +enum { k_iSteamControllerCallbacks = 2800 }; +enum { k_iClientParentalSettingsCallbacks = 2900 }; +enum { k_iClientDeviceAuthCallbacks = 3000 }; +enum { k_iClientNetworkDeviceManagerCallbacks = 3100 }; +enum { k_iClientMusicCallbacks = 3200 }; +enum { k_iClientRemoteClientManagerCallbacks = 3300 }; +enum { k_iClientUGCCallbacks = 3400 }; +enum { k_iSteamStreamClientCallbacks = 3500 }; +enum { k_IClientProductBuilderCallbacks = 3600 }; +enum { k_iClientShortcutsCallbacks = 3700 }; +enum { k_iClientRemoteControlManagerCallbacks = 3800 }; +enum { k_iSteamAppListCallbacks = 3900 }; +enum { k_iSteamMusicCallbacks = 4000 }; +enum { k_iSteamMusicRemoteCallbacks = 4100 }; +enum { k_iClientVRCallbacks = 4200 }; +enum { k_iClientGameNotificationCallbacks = 4300 }; +enum { k_iSteamGameNotificationCallbacks = 4400 }; +enum { k_iSteamHTMLSurfaceCallbacks = 4500 }; +enum { k_iClientVideoCallbacks = 4600 }; +enum { k_iClientInventoryCallbacks = 4700 }; +enum { k_iClientBluetoothManagerCallbacks = 4800 }; +enum { k_iClientSharedConnectionCallbacks = 4900 }; +enum { k_ISteamParentalSettingsCallbacks = 5000 }; +enum { k_iClientShaderCallbacks = 5100 }; +enum { k_iSteamGameSearchCallbacks = 5200 }; +enum { k_iSteamPartiesCallbacks = 5300 }; +enum { k_iClientPartiesCallbacks = 5400 }; +enum { k_iSteamSTARCallbacks = 5500 }; +enum { k_iClientSTARCallbacks = 5600 }; +enum { k_iSteamRemotePlayCallbacks = 5700 }; + +// Macro used to define a type-safe accessor that will always return the version +// of the interface of the *header file* you are compiling with! We also bounce +// through a safety function that checks for interfaces being created or destroyed. +#ifndef STEAM_API_EXPORTS + // SteamInternal_ContextInit takes a base pointer for the equivalent of + // struct { void (*pFn)(void* pCtx); uintp counter; CSteamAPIContext ctx; } + // Do not change layout of 2 + sizeof... or add non-pointer aligned data! + // NOTE: declaring "static CSteamAPIConext" creates a large function + // which queries the initialization status of the object. We know that + // it is pointer-aligned and fully memset with zeros, so just alias a + // static buffer of the appropriate size and call it a CSteamAPIContext. + #define STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, expr ) \ + inline void S_CALLTYPE SteamInternal_Init_ ## name( type *p ) { *p = (type)( expr ); } \ + inline type name() { \ + static void* s_CallbackCounterAndContext[ 3 ] = { (void*)&SteamInternal_Init_ ## name, 0, 0 }; \ + return *(type*)SteamInternal_ContextInit( s_CallbackCounterAndContext ); \ + } + +#else + // Stub when we're compiling steam_api.dll itself. These are inline + // functions defined when the header is included. not functions exported + // by the lib! + #define STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, expr ) +#endif + +#define STEAM_DEFINE_USER_INTERFACE_ACCESSOR( type, name, version ) \ + STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, SteamInternal_FindOrCreateUserInterface( SteamAPI_GetHSteamUser(), version ) ) +#define STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( type, name, version ) \ + STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, SteamInternal_FindOrCreateGameServerInterface( SteamGameServer_GetHSteamUser(), version ) ) + +#ifdef _MSVC_VER +#pragma warning( pop ) +#endif + +// CSteamAPIContext encapsulates the Steamworks API global accessors into +// a single object. +// +// DEPRECATED: Used the global interface accessors instead! +// +// This will be removed in a future iteration of the SDK +class CSteamAPIContext +{ +public: + CSteamAPIContext() { Clear(); } + inline void Clear() { memset( this, 0, sizeof(*this) ); } + inline bool Init(); // NOTE: This is defined in steam_api.h, to avoid this file having to include everything + ISteamClient* SteamClient() const { return m_pSteamClient; } + ISteamUser* SteamUser() const { return m_pSteamUser; } + ISteamFriends* SteamFriends() const { return m_pSteamFriends; } + ISteamUtils* SteamUtils() const { return m_pSteamUtils; } + ISteamMatchmaking* SteamMatchmaking() const { return m_pSteamMatchmaking; } + ISteamGameSearch* SteamGameSearch() const { return m_pSteamGameSearch; } + ISteamUserStats* SteamUserStats() const { return m_pSteamUserStats; } + ISteamApps* SteamApps() const { return m_pSteamApps; } + ISteamMatchmakingServers* SteamMatchmakingServers() const { return m_pSteamMatchmakingServers; } + ISteamNetworking* SteamNetworking() const { return m_pSteamNetworking; } + ISteamRemoteStorage* SteamRemoteStorage() const { return m_pSteamRemoteStorage; } + ISteamScreenshots* SteamScreenshots() const { return m_pSteamScreenshots; } + ISteamHTTP* SteamHTTP() const { return m_pSteamHTTP; } + ISteamController* SteamController() const { return m_pController; } + ISteamUGC* SteamUGC() const { return m_pSteamUGC; } + ISteamAppList* SteamAppList() const { return m_pSteamAppList; } + ISteamMusic* SteamMusic() const { return m_pSteamMusic; } + ISteamMusicRemote* SteamMusicRemote() const { return m_pSteamMusicRemote; } + ISteamHTMLSurface* SteamHTMLSurface() const { return m_pSteamHTMLSurface; } + ISteamInventory* SteamInventory() const { return m_pSteamInventory; } + ISteamVideo* SteamVideo() const { return m_pSteamVideo; } + ISteamTV* SteamTV() const { return m_pSteamTV; } + ISteamParentalSettings* SteamParentalSettings() const { return m_pSteamParentalSettings; } + ISteamInput* SteamInput() const { return m_pSteamInput; } +private: + ISteamClient *m_pSteamClient; + ISteamUser *m_pSteamUser; + ISteamFriends *m_pSteamFriends; + ISteamUtils *m_pSteamUtils; + ISteamMatchmaking *m_pSteamMatchmaking; + ISteamGameSearch *m_pSteamGameSearch; + ISteamUserStats *m_pSteamUserStats; + ISteamApps *m_pSteamApps; + ISteamMatchmakingServers *m_pSteamMatchmakingServers; + ISteamNetworking *m_pSteamNetworking; + ISteamRemoteStorage *m_pSteamRemoteStorage; + ISteamScreenshots *m_pSteamScreenshots; + ISteamHTTP *m_pSteamHTTP; + ISteamController *m_pController; + ISteamUGC *m_pSteamUGC; + ISteamAppList *m_pSteamAppList; + ISteamMusic *m_pSteamMusic; + ISteamMusicRemote *m_pSteamMusicRemote; + ISteamHTMLSurface *m_pSteamHTMLSurface; + ISteamInventory *m_pSteamInventory; + ISteamVideo *m_pSteamVideo; + ISteamTV *m_pSteamTV; + ISteamParentalSettings *m_pSteamParentalSettings; + ISteamInput *m_pSteamInput; +}; + +class CSteamGameServerAPIContext +{ +public: + CSteamGameServerAPIContext() { Clear(); } + inline void Clear() { memset( this, 0, sizeof(*this) ); } + inline bool Init(); // NOTE: This is defined in steam_gameserver.h, to avoid this file having to include everything + + ISteamClient *SteamClient() const { return m_pSteamClient; } + ISteamGameServer *SteamGameServer() const { return m_pSteamGameServer; } + ISteamUtils *SteamGameServerUtils() const { return m_pSteamGameServerUtils; } + ISteamNetworking *SteamGameServerNetworking() const { return m_pSteamGameServerNetworking; } + ISteamGameServerStats *SteamGameServerStats() const { return m_pSteamGameServerStats; } + ISteamHTTP *SteamHTTP() const { return m_pSteamHTTP; } + ISteamInventory *SteamInventory() const { return m_pSteamInventory; } + ISteamUGC *SteamUGC() const { return m_pSteamUGC; } + ISteamApps *SteamApps() const { return m_pSteamApps; } + +private: + ISteamClient *m_pSteamClient; + ISteamGameServer *m_pSteamGameServer; + ISteamUtils *m_pSteamGameServerUtils; + ISteamNetworking *m_pSteamGameServerNetworking; + ISteamGameServerStats *m_pSteamGameServerStats; + ISteamHTTP *m_pSteamHTTP; + ISteamInventory *m_pSteamInventory; + ISteamUGC *m_pSteamUGC; + ISteamApps *m_pSteamApps; +}; + + diff --git a/public/steam/steam_api_interop.cs b/public/steam/steam_api_interop.cs new file mode 100644 index 0000000..225765f --- /dev/null +++ b/public/steam/steam_api_interop.cs @@ -0,0 +1,13135 @@ +//====== Copyright 1996-2016, Valve Corporation, All rights reserved. ======= +// +// Purpose: This file contains C#/managed code bindings for the SteamAPI interfaces +// This file is auto-generated, do not edit it. +// +//============================================================================= + +using System; +using System.Runtime.InteropServices; +using Valve.Steamworks; +using Valve.Interop; + +namespace Valve.Interop +{ + +public class NativeEntrypoints +{ + + +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_CreateSteamPipe")] +internal static extern uint SteamAPI_ISteamClient_CreateSteamPipe(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_BReleaseSteamPipe")] +internal static extern bool SteamAPI_ISteamClient_BReleaseSteamPipe(IntPtr instancePtr, uint hSteamPipe); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_ConnectToGlobalUser")] +internal static extern uint SteamAPI_ISteamClient_ConnectToGlobalUser(IntPtr instancePtr, uint hSteamPipe); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_CreateLocalUser")] +internal static extern uint SteamAPI_ISteamClient_CreateLocalUser(IntPtr instancePtr, ref uint phSteamPipe, uint eAccountType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_ReleaseUser")] +internal static extern void SteamAPI_ISteamClient_ReleaseUser(IntPtr instancePtr, uint hSteamPipe, uint hUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamUser")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamUser(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamGameServer")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamGameServer(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_SetLocalIPBinding")] +internal static extern void SteamAPI_ISteamClient_SetLocalIPBinding(IntPtr instancePtr, uint unIP, char usPort); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamFriends")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamFriends(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamUtils")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamUtils(IntPtr instancePtr, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamMatchmaking")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamMatchmaking(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamMatchmakingServers")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamMatchmakingServers(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamGenericInterface")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamGenericInterface(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamUserStats")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamUserStats(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamGameServerStats")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamGameServerStats(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamApps")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamApps(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamNetworking")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamNetworking(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamRemoteStorage")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamRemoteStorage(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamScreenshots")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamScreenshots(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamGameSearch")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamGameSearch(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetIPCCallCount")] +internal static extern uint SteamAPI_ISteamClient_GetIPCCallCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_SetWarningMessageHook")] +internal static extern void SteamAPI_ISteamClient_SetWarningMessageHook(IntPtr instancePtr, IntPtr pFunction); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_BShutdownIfAllPipesClosed")] +internal static extern bool SteamAPI_ISteamClient_BShutdownIfAllPipesClosed(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamHTTP")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamHTTP(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamController")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamController(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamUGC")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamUGC(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamAppList")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamAppList(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamMusic")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamMusic(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamMusicRemote")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamMusicRemote(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamHTMLSurface")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamHTMLSurface(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamInventory")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamInventory(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamVideo")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamVideo(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamParentalSettings")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamParentalSettings(IntPtr instancePtr, uint hSteamuser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamInput")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamInput(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamParties")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamParties(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamClient_GetISteamRemotePlay")] +internal static extern IntPtr SteamAPI_ISteamClient_GetISteamRemotePlay(IntPtr instancePtr, uint hSteamUser, uint hSteamPipe, string pchVersion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetHSteamUser")] +internal static extern uint SteamAPI_ISteamUser_GetHSteamUser(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BLoggedOn")] +internal static extern bool SteamAPI_ISteamUser_BLoggedOn(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetSteamID")] +internal static extern ulong SteamAPI_ISteamUser_GetSteamID(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_InitiateGameConnection")] +internal static extern int SteamAPI_ISteamUser_InitiateGameConnection(IntPtr instancePtr, IntPtr pAuthBlob, int cbMaxAuthBlob, ulong steamIDGameServer, uint unIPServer, char usPortServer, bool bSecure); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_TerminateGameConnection")] +internal static extern void SteamAPI_ISteamUser_TerminateGameConnection(IntPtr instancePtr, uint unIPServer, char usPortServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_TrackAppUsageEvent")] +internal static extern void SteamAPI_ISteamUser_TrackAppUsageEvent(IntPtr instancePtr, ulong gameID, int eAppUsageEvent, string pchExtraInfo); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetUserDataFolder")] +internal static extern bool SteamAPI_ISteamUser_GetUserDataFolder(IntPtr instancePtr, string pchBuffer, int cubBuffer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_StartVoiceRecording")] +internal static extern void SteamAPI_ISteamUser_StartVoiceRecording(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_StopVoiceRecording")] +internal static extern void SteamAPI_ISteamUser_StopVoiceRecording(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetAvailableVoice")] +internal static extern uint SteamAPI_ISteamUser_GetAvailableVoice(IntPtr instancePtr, ref uint pcbCompressed, ref uint pcbUncompressed_Deprecated, uint nUncompressedVoiceDesiredSampleRate_Deprecated); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetVoice")] +internal static extern uint SteamAPI_ISteamUser_GetVoice(IntPtr instancePtr, bool bWantCompressed, IntPtr pDestBuffer, uint cbDestBufferSize, ref uint nBytesWritten, bool bWantUncompressed_Deprecated, IntPtr pUncompressedDestBuffer_Deprecated, uint cbUncompressedDestBufferSize_Deprecated, ref uint nUncompressBytesWritten_Deprecated, uint nUncompressedVoiceDesiredSampleRate_Deprecated); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_DecompressVoice")] +internal static extern uint SteamAPI_ISteamUser_DecompressVoice(IntPtr instancePtr, IntPtr pCompressed, uint cbCompressed, IntPtr pDestBuffer, uint cbDestBufferSize, ref uint nBytesWritten, uint nDesiredSampleRate); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetVoiceOptimalSampleRate")] +internal static extern uint SteamAPI_ISteamUser_GetVoiceOptimalSampleRate(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetAuthSessionTicket")] +internal static extern uint SteamAPI_ISteamUser_GetAuthSessionTicket(IntPtr instancePtr, IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BeginAuthSession")] +internal static extern uint SteamAPI_ISteamUser_BeginAuthSession(IntPtr instancePtr, IntPtr pAuthTicket, int cbAuthTicket, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_EndAuthSession")] +internal static extern void SteamAPI_ISteamUser_EndAuthSession(IntPtr instancePtr, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_CancelAuthTicket")] +internal static extern void SteamAPI_ISteamUser_CancelAuthTicket(IntPtr instancePtr, uint hAuthTicket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_UserHasLicenseForApp")] +internal static extern uint SteamAPI_ISteamUser_UserHasLicenseForApp(IntPtr instancePtr, ulong steamID, uint appID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BIsBehindNAT")] +internal static extern bool SteamAPI_ISteamUser_BIsBehindNAT(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_AdvertiseGame")] +internal static extern void SteamAPI_ISteamUser_AdvertiseGame(IntPtr instancePtr, ulong steamIDGameServer, uint unIPServer, char usPortServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_RequestEncryptedAppTicket")] +internal static extern ulong SteamAPI_ISteamUser_RequestEncryptedAppTicket(IntPtr instancePtr, IntPtr pDataToInclude, int cbDataToInclude); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetEncryptedAppTicket")] +internal static extern bool SteamAPI_ISteamUser_GetEncryptedAppTicket(IntPtr instancePtr, IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetGameBadgeLevel")] +internal static extern int SteamAPI_ISteamUser_GetGameBadgeLevel(IntPtr instancePtr, int nSeries, bool bFoil); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetPlayerSteamLevel")] +internal static extern int SteamAPI_ISteamUser_GetPlayerSteamLevel(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_RequestStoreAuthURL")] +internal static extern ulong SteamAPI_ISteamUser_RequestStoreAuthURL(IntPtr instancePtr, string pchRedirectURL); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BIsPhoneVerified")] +internal static extern bool SteamAPI_ISteamUser_BIsPhoneVerified(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BIsTwoFactorEnabled")] +internal static extern bool SteamAPI_ISteamUser_BIsTwoFactorEnabled(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BIsPhoneIdentifying")] +internal static extern bool SteamAPI_ISteamUser_BIsPhoneIdentifying(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_BIsPhoneRequiringVerification")] +internal static extern bool SteamAPI_ISteamUser_BIsPhoneRequiringVerification(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetMarketEligibility")] +internal static extern ulong SteamAPI_ISteamUser_GetMarketEligibility(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUser_GetDurationControl")] +internal static extern ulong SteamAPI_ISteamUser_GetDurationControl(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetPersonaName")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetPersonaName(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_SetPersonaName")] +internal static extern ulong SteamAPI_ISteamFriends_SetPersonaName(IntPtr instancePtr, string pchPersonaName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetPersonaState")] +internal static extern uint SteamAPI_ISteamFriends_GetPersonaState(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendCount")] +internal static extern int SteamAPI_ISteamFriends_GetFriendCount(IntPtr instancePtr, int iFriendFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendByIndex")] +internal static extern ulong SteamAPI_ISteamFriends_GetFriendByIndex(IntPtr instancePtr, int iFriend, int iFriendFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendRelationship")] +internal static extern uint SteamAPI_ISteamFriends_GetFriendRelationship(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendPersonaState")] +internal static extern uint SteamAPI_ISteamFriends_GetFriendPersonaState(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendPersonaName")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetFriendPersonaName(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendGamePlayed")] +internal static extern bool SteamAPI_ISteamFriends_GetFriendGamePlayed(IntPtr instancePtr, ulong steamIDFriend, ref FriendGameInfo_t pFriendGameInfo); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendPersonaNameHistory")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetFriendPersonaNameHistory(IntPtr instancePtr, ulong steamIDFriend, int iPersonaName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendSteamLevel")] +internal static extern int SteamAPI_ISteamFriends_GetFriendSteamLevel(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetPlayerNickname")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetPlayerNickname(IntPtr instancePtr, ulong steamIDPlayer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupCount")] +internal static extern int SteamAPI_ISteamFriends_GetFriendsGroupCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex")] +internal static extern char SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex(IntPtr instancePtr, int iFG); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupName")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetFriendsGroupName(IntPtr instancePtr, char friendsGroupID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupMembersCount")] +internal static extern int SteamAPI_ISteamFriends_GetFriendsGroupMembersCount(IntPtr instancePtr, char friendsGroupID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupMembersList")] +internal static extern void SteamAPI_ISteamFriends_GetFriendsGroupMembersList(IntPtr instancePtr, char friendsGroupID, [In, Out] CSteamID[] pOutSteamIDMembers, int nMembersCount); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_HasFriend")] +internal static extern bool SteamAPI_ISteamFriends_HasFriend(IntPtr instancePtr, ulong steamIDFriend, int iFriendFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanCount")] +internal static extern int SteamAPI_ISteamFriends_GetClanCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanByIndex")] +internal static extern ulong SteamAPI_ISteamFriends_GetClanByIndex(IntPtr instancePtr, int iClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanName")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetClanName(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanTag")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetClanTag(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanActivityCounts")] +internal static extern bool SteamAPI_ISteamFriends_GetClanActivityCounts(IntPtr instancePtr, ulong steamIDClan, ref int pnOnline, ref int pnInGame, ref int pnChatting); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_DownloadClanActivityCounts")] +internal static extern ulong SteamAPI_ISteamFriends_DownloadClanActivityCounts(IntPtr instancePtr, [In, Out] CSteamID[] psteamIDClans, int cClansToRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendCountFromSource")] +internal static extern int SteamAPI_ISteamFriends_GetFriendCountFromSource(IntPtr instancePtr, ulong steamIDSource); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendFromSourceByIndex")] +internal static extern ulong SteamAPI_ISteamFriends_GetFriendFromSourceByIndex(IntPtr instancePtr, ulong steamIDSource, int iFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_IsUserInSource")] +internal static extern bool SteamAPI_ISteamFriends_IsUserInSource(IntPtr instancePtr, ulong steamIDUser, ulong steamIDSource); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_SetInGameVoiceSpeaking")] +internal static extern void SteamAPI_ISteamFriends_SetInGameVoiceSpeaking(IntPtr instancePtr, ulong steamIDUser, bool bSpeaking); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlay")] +internal static extern void SteamAPI_ISteamFriends_ActivateGameOverlay(IntPtr instancePtr, string pchDialog); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayToUser")] +internal static extern void SteamAPI_ISteamFriends_ActivateGameOverlayToUser(IntPtr instancePtr, string pchDialog, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage")] +internal static extern void SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage(IntPtr instancePtr, string pchURL, uint eMode); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayToStore")] +internal static extern void SteamAPI_ISteamFriends_ActivateGameOverlayToStore(IntPtr instancePtr, uint nAppID, char eFlag); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_SetPlayedWith")] +internal static extern void SteamAPI_ISteamFriends_SetPlayedWith(IntPtr instancePtr, ulong steamIDUserPlayedWith); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog")] +internal static extern void SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetSmallFriendAvatar")] +internal static extern int SteamAPI_ISteamFriends_GetSmallFriendAvatar(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetMediumFriendAvatar")] +internal static extern int SteamAPI_ISteamFriends_GetMediumFriendAvatar(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetLargeFriendAvatar")] +internal static extern int SteamAPI_ISteamFriends_GetLargeFriendAvatar(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_RequestUserInformation")] +internal static extern bool SteamAPI_ISteamFriends_RequestUserInformation(IntPtr instancePtr, ulong steamIDUser, bool bRequireNameOnly); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_RequestClanOfficerList")] +internal static extern ulong SteamAPI_ISteamFriends_RequestClanOfficerList(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanOwner")] +internal static extern ulong SteamAPI_ISteamFriends_GetClanOwner(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanOfficerCount")] +internal static extern int SteamAPI_ISteamFriends_GetClanOfficerCount(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanOfficerByIndex")] +internal static extern ulong SteamAPI_ISteamFriends_GetClanOfficerByIndex(IntPtr instancePtr, ulong steamIDClan, int iOfficer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetUserRestrictions")] +internal static extern uint SteamAPI_ISteamFriends_GetUserRestrictions(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_SetRichPresence")] +internal static extern bool SteamAPI_ISteamFriends_SetRichPresence(IntPtr instancePtr, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ClearRichPresence")] +internal static extern void SteamAPI_ISteamFriends_ClearRichPresence(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendRichPresence")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetFriendRichPresence(IntPtr instancePtr, ulong steamIDFriend, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount")] +internal static extern int SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex")] +internal static extern IntPtr SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex(IntPtr instancePtr, ulong steamIDFriend, int iKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_RequestFriendRichPresence")] +internal static extern void SteamAPI_ISteamFriends_RequestFriendRichPresence(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_InviteUserToGame")] +internal static extern bool SteamAPI_ISteamFriends_InviteUserToGame(IntPtr instancePtr, ulong steamIDFriend, string pchConnectString); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetCoplayFriendCount")] +internal static extern int SteamAPI_ISteamFriends_GetCoplayFriendCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetCoplayFriend")] +internal static extern ulong SteamAPI_ISteamFriends_GetCoplayFriend(IntPtr instancePtr, int iCoplayFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendCoplayTime")] +internal static extern int SteamAPI_ISteamFriends_GetFriendCoplayTime(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendCoplayGame")] +internal static extern uint SteamAPI_ISteamFriends_GetFriendCoplayGame(IntPtr instancePtr, ulong steamIDFriend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_JoinClanChatRoom")] +internal static extern ulong SteamAPI_ISteamFriends_JoinClanChatRoom(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_LeaveClanChatRoom")] +internal static extern bool SteamAPI_ISteamFriends_LeaveClanChatRoom(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanChatMemberCount")] +internal static extern int SteamAPI_ISteamFriends_GetClanChatMemberCount(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetChatMemberByIndex")] +internal static extern ulong SteamAPI_ISteamFriends_GetChatMemberByIndex(IntPtr instancePtr, ulong steamIDClan, int iUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_SendClanChatMessage")] +internal static extern bool SteamAPI_ISteamFriends_SendClanChatMessage(IntPtr instancePtr, ulong steamIDClanChat, string pchText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetClanChatMessage")] +internal static extern int SteamAPI_ISteamFriends_GetClanChatMessage(IntPtr instancePtr, ulong steamIDClanChat, int iMessage, IntPtr prgchText, int cchTextMax, ref uint peChatEntryType, ref CSteamID psteamidChatter); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_IsClanChatAdmin")] +internal static extern bool SteamAPI_ISteamFriends_IsClanChatAdmin(IntPtr instancePtr, ulong steamIDClanChat, ulong steamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam")] +internal static extern bool SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam(IntPtr instancePtr, ulong steamIDClanChat); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_OpenClanChatWindowInSteam")] +internal static extern bool SteamAPI_ISteamFriends_OpenClanChatWindowInSteam(IntPtr instancePtr, ulong steamIDClanChat); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_CloseClanChatWindowInSteam")] +internal static extern bool SteamAPI_ISteamFriends_CloseClanChatWindowInSteam(IntPtr instancePtr, ulong steamIDClanChat); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_SetListenForFriendsMessages")] +internal static extern bool SteamAPI_ISteamFriends_SetListenForFriendsMessages(IntPtr instancePtr, bool bInterceptEnabled); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_ReplyToFriendMessage")] +internal static extern bool SteamAPI_ISteamFriends_ReplyToFriendMessage(IntPtr instancePtr, ulong steamIDFriend, string pchMsgToSend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFriendMessage")] +internal static extern int SteamAPI_ISteamFriends_GetFriendMessage(IntPtr instancePtr, ulong steamIDFriend, int iMessageID, IntPtr pvData, int cubData, ref uint peChatEntryType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetFollowerCount")] +internal static extern ulong SteamAPI_ISteamFriends_GetFollowerCount(IntPtr instancePtr, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_IsFollowing")] +internal static extern ulong SteamAPI_ISteamFriends_IsFollowing(IntPtr instancePtr, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_EnumerateFollowingList")] +internal static extern ulong SteamAPI_ISteamFriends_EnumerateFollowingList(IntPtr instancePtr, uint unStartIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_IsClanPublic")] +internal static extern bool SteamAPI_ISteamFriends_IsClanPublic(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_IsClanOfficialGameGroup")] +internal static extern bool SteamAPI_ISteamFriends_IsClanOfficialGameGroup(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages")] +internal static extern int SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetSecondsSinceAppActive")] +internal static extern uint SteamAPI_ISteamUtils_GetSecondsSinceAppActive(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetSecondsSinceComputerActive")] +internal static extern uint SteamAPI_ISteamUtils_GetSecondsSinceComputerActive(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetConnectedUniverse")] +internal static extern int SteamAPI_ISteamUtils_GetConnectedUniverse(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetServerRealTime")] +internal static extern uint SteamAPI_ISteamUtils_GetServerRealTime(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetIPCountry")] +internal static extern IntPtr SteamAPI_ISteamUtils_GetIPCountry(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetImageSize")] +internal static extern bool SteamAPI_ISteamUtils_GetImageSize(IntPtr instancePtr, int iImage, ref uint pnWidth, ref uint pnHeight); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetImageRGBA")] +internal static extern bool SteamAPI_ISteamUtils_GetImageRGBA(IntPtr instancePtr, int iImage, IntPtr pubDest, int nDestBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetCSERIPPort")] +internal static extern bool SteamAPI_ISteamUtils_GetCSERIPPort(IntPtr instancePtr, ref uint unIP, ref char usPort); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetCurrentBatteryPower")] +internal static extern byte SteamAPI_ISteamUtils_GetCurrentBatteryPower(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetAppID")] +internal static extern uint SteamAPI_ISteamUtils_GetAppID(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_SetOverlayNotificationPosition")] +internal static extern void SteamAPI_ISteamUtils_SetOverlayNotificationPosition(IntPtr instancePtr, uint eNotificationPosition); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_IsAPICallCompleted")] +internal static extern bool SteamAPI_ISteamUtils_IsAPICallCompleted(IntPtr instancePtr, ulong hSteamAPICall, ref bool pbFailed); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetAPICallFailureReason")] +internal static extern int SteamAPI_ISteamUtils_GetAPICallFailureReason(IntPtr instancePtr, ulong hSteamAPICall); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetAPICallResult")] +internal static extern bool SteamAPI_ISteamUtils_GetAPICallResult(IntPtr instancePtr, ulong hSteamAPICall, IntPtr pCallback, int cubCallback, int iCallbackExpected, ref bool pbFailed); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetIPCCallCount")] +internal static extern uint SteamAPI_ISteamUtils_GetIPCCallCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_SetWarningMessageHook")] +internal static extern void SteamAPI_ISteamUtils_SetWarningMessageHook(IntPtr instancePtr, IntPtr pFunction); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_IsOverlayEnabled")] +internal static extern bool SteamAPI_ISteamUtils_IsOverlayEnabled(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_BOverlayNeedsPresent")] +internal static extern bool SteamAPI_ISteamUtils_BOverlayNeedsPresent(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_CheckFileSignature")] +internal static extern ulong SteamAPI_ISteamUtils_CheckFileSignature(IntPtr instancePtr, string szFileName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_ShowGamepadTextInput")] +internal static extern bool SteamAPI_ISteamUtils_ShowGamepadTextInput(IntPtr instancePtr, int eInputMode, int eLineInputMode, string pchDescription, uint unCharMax, string pchExistingText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetEnteredGamepadTextLength")] +internal static extern uint SteamAPI_ISteamUtils_GetEnteredGamepadTextLength(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetEnteredGamepadTextInput")] +internal static extern bool SteamAPI_ISteamUtils_GetEnteredGamepadTextInput(IntPtr instancePtr, string pchText, uint cchText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_GetSteamUILanguage")] +internal static extern IntPtr SteamAPI_ISteamUtils_GetSteamUILanguage(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_IsSteamRunningInVR")] +internal static extern bool SteamAPI_ISteamUtils_IsSteamRunningInVR(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_SetOverlayNotificationInset")] +internal static extern void SteamAPI_ISteamUtils_SetOverlayNotificationInset(IntPtr instancePtr, int nHorizontalInset, int nVerticalInset); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_IsSteamInBigPictureMode")] +internal static extern bool SteamAPI_ISteamUtils_IsSteamInBigPictureMode(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_StartVRDashboard")] +internal static extern void SteamAPI_ISteamUtils_StartVRDashboard(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled")] +internal static extern bool SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled")] +internal static extern void SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled(IntPtr instancePtr, bool bEnabled); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_IsSteamChinaLauncher")] +internal static extern bool SteamAPI_ISteamUtils_IsSteamChinaLauncher(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_InitFilterText")] +internal static extern bool SteamAPI_ISteamUtils_InitFilterText(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUtils_FilterText")] +internal static extern int SteamAPI_ISteamUtils_FilterText(IntPtr instancePtr, string pchOutFilteredText, uint nByteSizeOutFilteredText, string pchInputMessage, bool bLegalOnly); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetFavoriteGameCount")] +internal static extern int SteamAPI_ISteamMatchmaking_GetFavoriteGameCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetFavoriteGame")] +internal static extern bool SteamAPI_ISteamMatchmaking_GetFavoriteGame(IntPtr instancePtr, int iGame, ref uint pnAppID, ref uint pnIP, ref char pnConnPort, ref char pnQueryPort, ref uint punFlags, ref uint pRTime32LastPlayedOnServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddFavoriteGame")] +internal static extern int SteamAPI_ISteamMatchmaking_AddFavoriteGame(IntPtr instancePtr, uint nAppID, uint nIP, char nConnPort, char nQueryPort, uint unFlags, uint rTime32LastPlayedOnServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_RemoveFavoriteGame")] +internal static extern bool SteamAPI_ISteamMatchmaking_RemoveFavoriteGame(IntPtr instancePtr, uint nAppID, uint nIP, char nConnPort, char nQueryPort, uint unFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_RequestLobbyList")] +internal static extern ulong SteamAPI_ISteamMatchmaking_RequestLobbyList(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter(IntPtr instancePtr, string pchKeyToMatch, string pchValueToMatch, uint eComparisonType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter(IntPtr instancePtr, string pchKeyToMatch, int nValueToMatch, uint eComparisonType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter(IntPtr instancePtr, string pchKeyToMatch, int nValueToBeCloseTo); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable(IntPtr instancePtr, int nSlotsAvailable); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter(IntPtr instancePtr, uint eLobbyDistanceFilter); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter(IntPtr instancePtr, int cMaxResults); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter")] +internal static extern void SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyByIndex")] +internal static extern ulong SteamAPI_ISteamMatchmaking_GetLobbyByIndex(IntPtr instancePtr, int iLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_CreateLobby")] +internal static extern ulong SteamAPI_ISteamMatchmaking_CreateLobby(IntPtr instancePtr, uint eLobbyType, int cMaxMembers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_JoinLobby")] +internal static extern ulong SteamAPI_ISteamMatchmaking_JoinLobby(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_LeaveLobby")] +internal static extern void SteamAPI_ISteamMatchmaking_LeaveLobby(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_InviteUserToLobby")] +internal static extern bool SteamAPI_ISteamMatchmaking_InviteUserToLobby(IntPtr instancePtr, ulong steamIDLobby, ulong steamIDInvitee); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetNumLobbyMembers")] +internal static extern int SteamAPI_ISteamMatchmaking_GetNumLobbyMembers(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex")] +internal static extern ulong SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex(IntPtr instancePtr, ulong steamIDLobby, int iMember); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyData")] +internal static extern IntPtr SteamAPI_ISteamMatchmaking_GetLobbyData(IntPtr instancePtr, ulong steamIDLobby, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyData")] +internal static extern bool SteamAPI_ISteamMatchmaking_SetLobbyData(IntPtr instancePtr, ulong steamIDLobby, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyDataCount")] +internal static extern int SteamAPI_ISteamMatchmaking_GetLobbyDataCount(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex")] +internal static extern bool SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex(IntPtr instancePtr, ulong steamIDLobby, int iLobbyData, string pchKey, int cchKeyBufferSize, string pchValue, int cchValueBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_DeleteLobbyData")] +internal static extern bool SteamAPI_ISteamMatchmaking_DeleteLobbyData(IntPtr instancePtr, ulong steamIDLobby, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyMemberData")] +internal static extern IntPtr SteamAPI_ISteamMatchmaking_GetLobbyMemberData(IntPtr instancePtr, ulong steamIDLobby, ulong steamIDUser, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyMemberData")] +internal static extern void SteamAPI_ISteamMatchmaking_SetLobbyMemberData(IntPtr instancePtr, ulong steamIDLobby, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SendLobbyChatMsg")] +internal static extern bool SteamAPI_ISteamMatchmaking_SendLobbyChatMsg(IntPtr instancePtr, ulong steamIDLobby, IntPtr pvMsgBody, int cubMsgBody); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyChatEntry")] +internal static extern int SteamAPI_ISteamMatchmaking_GetLobbyChatEntry(IntPtr instancePtr, ulong steamIDLobby, int iChatID, ref CSteamID pSteamIDUser, IntPtr pvData, int cubData, ref uint peChatEntryType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_RequestLobbyData")] +internal static extern bool SteamAPI_ISteamMatchmaking_RequestLobbyData(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyGameServer")] +internal static extern void SteamAPI_ISteamMatchmaking_SetLobbyGameServer(IntPtr instancePtr, ulong steamIDLobby, uint unGameServerIP, char unGameServerPort, ulong steamIDGameServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyGameServer")] +internal static extern bool SteamAPI_ISteamMatchmaking_GetLobbyGameServer(IntPtr instancePtr, ulong steamIDLobby, ref uint punGameServerIP, ref char punGameServerPort, ref CSteamID psteamIDGameServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit")] +internal static extern bool SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit(IntPtr instancePtr, ulong steamIDLobby, int cMaxMembers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit")] +internal static extern int SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyType")] +internal static extern bool SteamAPI_ISteamMatchmaking_SetLobbyType(IntPtr instancePtr, ulong steamIDLobby, uint eLobbyType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyJoinable")] +internal static extern bool SteamAPI_ISteamMatchmaking_SetLobbyJoinable(IntPtr instancePtr, ulong steamIDLobby, bool bLobbyJoinable); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_GetLobbyOwner")] +internal static extern ulong SteamAPI_ISteamMatchmaking_GetLobbyOwner(IntPtr instancePtr, ulong steamIDLobby); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLobbyOwner")] +internal static extern bool SteamAPI_ISteamMatchmaking_SetLobbyOwner(IntPtr instancePtr, ulong steamIDLobby, ulong steamIDNewOwner); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmaking_SetLinkedLobby")] +internal static extern bool SteamAPI_ISteamMatchmaking_SetLinkedLobby(IntPtr instancePtr, ulong steamIDLobby, ulong steamIDLobbyDependent); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded")] +internal static extern void SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded(IntPtr instancePtr, uint hRequest, int iServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond")] +internal static extern void SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond(IntPtr instancePtr, uint hRequest, int iServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete")] +internal static extern void SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete(IntPtr instancePtr, uint hRequest, uint response); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingPingResponse_ServerResponded")] +internal static extern void SteamAPI_ISteamMatchmakingPingResponse_ServerResponded(IntPtr instancePtr, IntPtr server); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond")] +internal static extern void SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList")] +internal static extern void SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList(IntPtr instancePtr, string pchName, int nScore, float flTimePlayed); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond")] +internal static extern void SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete")] +internal static extern void SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded")] +internal static extern void SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded(IntPtr instancePtr, string pchRule, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond")] +internal static extern void SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete")] +internal static extern void SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RequestInternetServerList")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_RequestInternetServerList(IntPtr instancePtr, uint iApp, [In, Out] IntPtr[] ppchFilters, uint nFilters, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RequestLANServerList")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_RequestLANServerList(IntPtr instancePtr, uint iApp, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList(IntPtr instancePtr, uint iApp, [In, Out] IntPtr[] ppchFilters, uint nFilters, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList(IntPtr instancePtr, uint iApp, [In, Out] IntPtr[] ppchFilters, uint nFilters, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList(IntPtr instancePtr, uint iApp, [In, Out] IntPtr[] ppchFilters, uint nFilters, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList(IntPtr instancePtr, uint iApp, [In, Out] IntPtr[] ppchFilters, uint nFilters, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_ReleaseRequest")] +internal static extern void SteamAPI_ISteamMatchmakingServers_ReleaseRequest(IntPtr instancePtr, uint hServerListRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_GetServerDetails")] +internal static extern IntPtr SteamAPI_ISteamMatchmakingServers_GetServerDetails(IntPtr instancePtr, uint hRequest, int iServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_CancelQuery")] +internal static extern void SteamAPI_ISteamMatchmakingServers_CancelQuery(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RefreshQuery")] +internal static extern void SteamAPI_ISteamMatchmakingServers_RefreshQuery(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_IsRefreshing")] +internal static extern bool SteamAPI_ISteamMatchmakingServers_IsRefreshing(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_GetServerCount")] +internal static extern int SteamAPI_ISteamMatchmakingServers_GetServerCount(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_RefreshServer")] +internal static extern void SteamAPI_ISteamMatchmakingServers_RefreshServer(IntPtr instancePtr, uint hRequest, int iServer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_PingServer")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_PingServer(IntPtr instancePtr, uint unIP, char usPort, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_PlayerDetails")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_PlayerDetails(IntPtr instancePtr, uint unIP, char usPort, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_ServerRules")] +internal static extern uint SteamAPI_ISteamMatchmakingServers_ServerRules(IntPtr instancePtr, uint unIP, char usPort, IntPtr pRequestServersResponse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMatchmakingServers_CancelServerQuery")] +internal static extern void SteamAPI_ISteamMatchmakingServers_CancelServerQuery(IntPtr instancePtr, uint hServerQuery); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_AddGameSearchParams")] +internal static extern uint SteamAPI_ISteamGameSearch_AddGameSearchParams(IntPtr instancePtr, string pchKeyToFind, string pchValuesToFind); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_SearchForGameWithLobby")] +internal static extern uint SteamAPI_ISteamGameSearch_SearchForGameWithLobby(IntPtr instancePtr, ulong steamIDLobby, int nPlayerMin, int nPlayerMax); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_SearchForGameSolo")] +internal static extern uint SteamAPI_ISteamGameSearch_SearchForGameSolo(IntPtr instancePtr, int nPlayerMin, int nPlayerMax); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_AcceptGame")] +internal static extern uint SteamAPI_ISteamGameSearch_AcceptGame(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_DeclineGame")] +internal static extern uint SteamAPI_ISteamGameSearch_DeclineGame(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_RetrieveConnectionDetails")] +internal static extern uint SteamAPI_ISteamGameSearch_RetrieveConnectionDetails(IntPtr instancePtr, ulong steamIDHost, string pchConnectionDetails, int cubConnectionDetails); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_EndGameSearch")] +internal static extern uint SteamAPI_ISteamGameSearch_EndGameSearch(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_SetGameHostParams")] +internal static extern uint SteamAPI_ISteamGameSearch_SetGameHostParams(IntPtr instancePtr, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_SetConnectionDetails")] +internal static extern uint SteamAPI_ISteamGameSearch_SetConnectionDetails(IntPtr instancePtr, string pchConnectionDetails, int cubConnectionDetails); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_RequestPlayersForGame")] +internal static extern uint SteamAPI_ISteamGameSearch_RequestPlayersForGame(IntPtr instancePtr, int nPlayerMin, int nPlayerMax, int nMaxTeamSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_HostConfirmGameStart")] +internal static extern uint SteamAPI_ISteamGameSearch_HostConfirmGameStart(IntPtr instancePtr, ulong ullUniqueGameID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame")] +internal static extern uint SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_SubmitPlayerResult")] +internal static extern uint SteamAPI_ISteamGameSearch_SubmitPlayerResult(IntPtr instancePtr, ulong ullUniqueGameID, ulong steamIDPlayer, uint EPlayerResult); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameSearch_EndGame")] +internal static extern uint SteamAPI_ISteamGameSearch_EndGame(IntPtr instancePtr, ulong ullUniqueGameID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_GetNumActiveBeacons")] +internal static extern uint SteamAPI_ISteamParties_GetNumActiveBeacons(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_GetBeaconByIndex")] +internal static extern ulong SteamAPI_ISteamParties_GetBeaconByIndex(IntPtr instancePtr, uint unIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_GetBeaconDetails")] +internal static extern bool SteamAPI_ISteamParties_GetBeaconDetails(IntPtr instancePtr, ulong ulBeaconID, ref CSteamID pSteamIDBeaconOwner, ref SteamPartyBeaconLocation_t pLocation, System.Text.StringBuilder pchMetadata, int cchMetadata); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_JoinParty")] +internal static extern ulong SteamAPI_ISteamParties_JoinParty(IntPtr instancePtr, ulong ulBeaconID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_GetNumAvailableBeaconLocations")] +internal static extern bool SteamAPI_ISteamParties_GetNumAvailableBeaconLocations(IntPtr instancePtr, ref uint puNumLocations); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_GetAvailableBeaconLocations")] +internal static extern bool SteamAPI_ISteamParties_GetAvailableBeaconLocations(IntPtr instancePtr, ref SteamPartyBeaconLocation_t pLocationList, uint uMaxNumLocations); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_CreateBeacon")] +internal static extern ulong SteamAPI_ISteamParties_CreateBeacon(IntPtr instancePtr, uint unOpenSlots, ref SteamPartyBeaconLocation_t pBeaconLocation, string pchConnectString, string pchMetadata); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_OnReservationCompleted")] +internal static extern void SteamAPI_ISteamParties_OnReservationCompleted(IntPtr instancePtr, ulong ulBeacon, ulong steamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_CancelReservation")] +internal static extern void SteamAPI_ISteamParties_CancelReservation(IntPtr instancePtr, ulong ulBeacon, ulong steamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_ChangeNumOpenSlots")] +internal static extern ulong SteamAPI_ISteamParties_ChangeNumOpenSlots(IntPtr instancePtr, ulong ulBeacon, uint unOpenSlots); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_DestroyBeacon")] +internal static extern bool SteamAPI_ISteamParties_DestroyBeacon(IntPtr instancePtr, ulong ulBeacon); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParties_GetBeaconLocationData")] +internal static extern bool SteamAPI_ISteamParties_GetBeaconLocationData(IntPtr instancePtr, SteamPartyBeaconLocation_t BeaconLocation, uint eData, System.Text.StringBuilder pchDataStringOut, int cchDataStringOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileWrite")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileWrite(IntPtr instancePtr, string pchFile, IntPtr pvData, int cubData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileRead")] +internal static extern int SteamAPI_ISteamRemoteStorage_FileRead(IntPtr instancePtr, string pchFile, IntPtr pvData, int cubDataToRead); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileWriteAsync")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_FileWriteAsync(IntPtr instancePtr, string pchFile, IntPtr pvData, uint cubData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileReadAsync")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_FileReadAsync(IntPtr instancePtr, string pchFile, uint nOffset, uint cubToRead); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete(IntPtr instancePtr, ulong hReadCall, IntPtr pvBuffer, uint cubToRead); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileForget")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileForget(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileDelete")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileDelete(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileShare")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_FileShare(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_SetSyncPlatforms")] +internal static extern bool SteamAPI_ISteamRemoteStorage_SetSyncPlatforms(IntPtr instancePtr, string pchFile, uint eRemoteStoragePlatform); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk(IntPtr instancePtr, ulong writeHandle, IntPtr pvData, int cubData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileWriteStreamClose")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileWriteStreamClose(IntPtr instancePtr, ulong writeHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel(IntPtr instancePtr, ulong writeHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FileExists")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FileExists(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_FilePersisted")] +internal static extern bool SteamAPI_ISteamRemoteStorage_FilePersisted(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetFileSize")] +internal static extern int SteamAPI_ISteamRemoteStorage_GetFileSize(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetFileTimestamp")] +internal static extern long SteamAPI_ISteamRemoteStorage_GetFileTimestamp(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetSyncPlatforms")] +internal static extern uint SteamAPI_ISteamRemoteStorage_GetSyncPlatforms(IntPtr instancePtr, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetFileCount")] +internal static extern int SteamAPI_ISteamRemoteStorage_GetFileCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetFileNameAndSize")] +internal static extern IntPtr SteamAPI_ISteamRemoteStorage_GetFileNameAndSize(IntPtr instancePtr, int iFile, ref int pnFileSizeInBytes); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetQuota")] +internal static extern bool SteamAPI_ISteamRemoteStorage_GetQuota(IntPtr instancePtr, ref ulong pnTotalBytes, ref ulong puAvailableBytes); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount")] +internal static extern bool SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp")] +internal static extern bool SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp")] +internal static extern void SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp(IntPtr instancePtr, bool bEnabled); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UGCDownload")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_UGCDownload(IntPtr instancePtr, ulong hContent, uint unPriority); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress")] +internal static extern bool SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress(IntPtr instancePtr, ulong hContent, ref int pnBytesDownloaded, ref int pnBytesExpected); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetUGCDetails")] +internal static extern bool SteamAPI_ISteamRemoteStorage_GetUGCDetails(IntPtr instancePtr, ulong hContent, ref uint pnAppID, System.Text.StringBuilder ppchName, ref int pnFileSizeInBytes, ref CSteamID pSteamIDOwner); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UGCRead")] +internal static extern int SteamAPI_ISteamRemoteStorage_UGCRead(IntPtr instancePtr, ulong hContent, IntPtr pvData, int cubDataToRead, uint cOffset, uint eAction); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetCachedUGCCount")] +internal static extern int SteamAPI_ISteamRemoteStorage_GetCachedUGCCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle(IntPtr instancePtr, int iCachedContent); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_PublishWorkshopFile")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_PublishWorkshopFile(IntPtr instancePtr, string pchFile, string pchPreviewFile, uint nConsumerAppId, string pchTitle, string pchDescription, uint eVisibility, ref SteamParamStringArray_t pTags, uint eWorkshopFileType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest(IntPtr instancePtr, ulong unPublishedFileId); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile(IntPtr instancePtr, ulong updateHandle, string pchFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile(IntPtr instancePtr, ulong updateHandle, string pchPreviewFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle(IntPtr instancePtr, ulong updateHandle, string pchTitle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription(IntPtr instancePtr, ulong updateHandle, string pchDescription); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility(IntPtr instancePtr, ulong updateHandle, uint eVisibility); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags(IntPtr instancePtr, ulong updateHandle, ref SteamParamStringArray_t pTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate(IntPtr instancePtr, ulong updateHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails(IntPtr instancePtr, ulong unPublishedFileId, uint unMaxSecondsOld); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_DeletePublishedFile")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_DeletePublishedFile(IntPtr instancePtr, ulong unPublishedFileId); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles(IntPtr instancePtr, uint unStartIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_SubscribePublishedFile")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_SubscribePublishedFile(IntPtr instancePtr, ulong unPublishedFileId); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles(IntPtr instancePtr, uint unStartIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile(IntPtr instancePtr, ulong unPublishedFileId); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription")] +internal static extern bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription(IntPtr instancePtr, ulong updateHandle, string pchChangeDescription); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails(IntPtr instancePtr, ulong unPublishedFileId); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote(IntPtr instancePtr, ulong unPublishedFileId, bool bVoteUp); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails(IntPtr instancePtr, ulong unPublishedFileId); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles(IntPtr instancePtr, ulong steamId, uint unStartIndex, ref SteamParamStringArray_t pRequiredTags, ref SteamParamStringArray_t pExcludedTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_PublishVideo")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_PublishVideo(IntPtr instancePtr, uint eVideoProvider, string pchVideoAccount, string pchVideoIdentifier, string pchPreviewFile, uint nConsumerAppId, string pchTitle, string pchDescription, uint eVisibility, ref SteamParamStringArray_t pTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction(IntPtr instancePtr, ulong unPublishedFileId, uint eAction); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction(IntPtr instancePtr, uint eAction, uint unStartIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles(IntPtr instancePtr, uint eEnumerationType, uint unStartIndex, uint unCount, uint unDays, ref SteamParamStringArray_t pTags, ref SteamParamStringArray_t pUserTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation")] +internal static extern ulong SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation(IntPtr instancePtr, ulong hContent, string pchLocation, uint unPriority); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_RequestCurrentStats")] +internal static extern bool SteamAPI_ISteamUserStats_RequestCurrentStats(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetStat")] +internal static extern bool SteamAPI_ISteamUserStats_GetStat(IntPtr instancePtr, string pchName, ref int pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetStat0")] +internal static extern bool SteamAPI_ISteamUserStats_GetStat0(IntPtr instancePtr, string pchName, ref float pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_SetStat")] +internal static extern bool SteamAPI_ISteamUserStats_SetStat(IntPtr instancePtr, string pchName, int nData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_SetStat0")] +internal static extern bool SteamAPI_ISteamUserStats_SetStat0(IntPtr instancePtr, string pchName, float fData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_UpdateAvgRateStat")] +internal static extern bool SteamAPI_ISteamUserStats_UpdateAvgRateStat(IntPtr instancePtr, string pchName, float flCountThisSession, double dSessionLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetAchievement")] +internal static extern bool SteamAPI_ISteamUserStats_GetAchievement(IntPtr instancePtr, string pchName, ref bool pbAchieved); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_SetAchievement")] +internal static extern bool SteamAPI_ISteamUserStats_SetAchievement(IntPtr instancePtr, string pchName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_ClearAchievement")] +internal static extern bool SteamAPI_ISteamUserStats_ClearAchievement(IntPtr instancePtr, string pchName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime")] +internal static extern bool SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime(IntPtr instancePtr, string pchName, ref bool pbAchieved, ref uint punUnlockTime); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_StoreStats")] +internal static extern bool SteamAPI_ISteamUserStats_StoreStats(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetAchievementIcon")] +internal static extern int SteamAPI_ISteamUserStats_GetAchievementIcon(IntPtr instancePtr, string pchName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute")] +internal static extern IntPtr SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute(IntPtr instancePtr, string pchName, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_IndicateAchievementProgress")] +internal static extern bool SteamAPI_ISteamUserStats_IndicateAchievementProgress(IntPtr instancePtr, string pchName, uint nCurProgress, uint nMaxProgress); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetNumAchievements")] +internal static extern uint SteamAPI_ISteamUserStats_GetNumAchievements(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetAchievementName")] +internal static extern IntPtr SteamAPI_ISteamUserStats_GetAchievementName(IntPtr instancePtr, uint iAchievement); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_RequestUserStats")] +internal static extern ulong SteamAPI_ISteamUserStats_RequestUserStats(IntPtr instancePtr, ulong steamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetUserStat")] +internal static extern bool SteamAPI_ISteamUserStats_GetUserStat(IntPtr instancePtr, ulong steamIDUser, string pchName, ref int pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetUserStat0")] +internal static extern bool SteamAPI_ISteamUserStats_GetUserStat0(IntPtr instancePtr, ulong steamIDUser, string pchName, ref float pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetUserAchievement")] +internal static extern bool SteamAPI_ISteamUserStats_GetUserAchievement(IntPtr instancePtr, ulong steamIDUser, string pchName, ref bool pbAchieved); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime")] +internal static extern bool SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime(IntPtr instancePtr, ulong steamIDUser, string pchName, ref bool pbAchieved, ref uint punUnlockTime); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_ResetAllStats")] +internal static extern bool SteamAPI_ISteamUserStats_ResetAllStats(IntPtr instancePtr, bool bAchievementsToo); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_FindOrCreateLeaderboard")] +internal static extern ulong SteamAPI_ISteamUserStats_FindOrCreateLeaderboard(IntPtr instancePtr, string pchLeaderboardName, uint eLeaderboardSortMethod, uint eLeaderboardDisplayType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_FindLeaderboard")] +internal static extern ulong SteamAPI_ISteamUserStats_FindLeaderboard(IntPtr instancePtr, string pchLeaderboardName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetLeaderboardName")] +internal static extern IntPtr SteamAPI_ISteamUserStats_GetLeaderboardName(IntPtr instancePtr, ulong hSteamLeaderboard); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetLeaderboardEntryCount")] +internal static extern int SteamAPI_ISteamUserStats_GetLeaderboardEntryCount(IntPtr instancePtr, ulong hSteamLeaderboard); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetLeaderboardSortMethod")] +internal static extern uint SteamAPI_ISteamUserStats_GetLeaderboardSortMethod(IntPtr instancePtr, ulong hSteamLeaderboard); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetLeaderboardDisplayType")] +internal static extern uint SteamAPI_ISteamUserStats_GetLeaderboardDisplayType(IntPtr instancePtr, ulong hSteamLeaderboard); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_DownloadLeaderboardEntries")] +internal static extern ulong SteamAPI_ISteamUserStats_DownloadLeaderboardEntries(IntPtr instancePtr, ulong hSteamLeaderboard, uint eLeaderboardDataRequest, int nRangeStart, int nRangeEnd); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers")] +internal static extern ulong SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers(IntPtr instancePtr, ulong hSteamLeaderboard, [In, Out] CSteamID[] prgUsers, int cUsers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry")] +internal static extern bool SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry(IntPtr instancePtr, ulong hSteamLeaderboardEntries, int index, ref LeaderboardEntry_t pLeaderboardEntry, ref int pDetails, int cDetailsMax); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_UploadLeaderboardScore")] +internal static extern ulong SteamAPI_ISteamUserStats_UploadLeaderboardScore(IntPtr instancePtr, ulong hSteamLeaderboard, uint eLeaderboardUploadScoreMethod, int nScore, ref int pScoreDetails, int cScoreDetailsCount); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_AttachLeaderboardUGC")] +internal static extern ulong SteamAPI_ISteamUserStats_AttachLeaderboardUGC(IntPtr instancePtr, ulong hSteamLeaderboard, ulong hUGC); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers")] +internal static extern ulong SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages")] +internal static extern ulong SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo")] +internal static extern int SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo(IntPtr instancePtr, string pchName, uint unNameBufLen, ref float pflPercent, ref bool pbAchieved); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo")] +internal static extern int SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo(IntPtr instancePtr, int iIteratorPrevious, string pchName, uint unNameBufLen, ref float pflPercent, ref bool pbAchieved); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetAchievementAchievedPercent")] +internal static extern bool SteamAPI_ISteamUserStats_GetAchievementAchievedPercent(IntPtr instancePtr, string pchName, ref float pflPercent); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_RequestGlobalStats")] +internal static extern ulong SteamAPI_ISteamUserStats_RequestGlobalStats(IntPtr instancePtr, int nHistoryDays); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetGlobalStat")] +internal static extern bool SteamAPI_ISteamUserStats_GetGlobalStat(IntPtr instancePtr, string pchStatName, ref long pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetGlobalStat0")] +internal static extern bool SteamAPI_ISteamUserStats_GetGlobalStat0(IntPtr instancePtr, string pchStatName, ref double pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetGlobalStatHistory")] +internal static extern int SteamAPI_ISteamUserStats_GetGlobalStatHistory(IntPtr instancePtr, string pchStatName, [In, Out] long[] pData, uint cubData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUserStats_GetGlobalStatHistory0")] +internal static extern int SteamAPI_ISteamUserStats_GetGlobalStatHistory0(IntPtr instancePtr, string pchStatName, [In, Out] double[] pData, uint cubData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsSubscribed")] +internal static extern bool SteamAPI_ISteamApps_BIsSubscribed(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsLowViolence")] +internal static extern bool SteamAPI_ISteamApps_BIsLowViolence(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsCybercafe")] +internal static extern bool SteamAPI_ISteamApps_BIsCybercafe(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsVACBanned")] +internal static extern bool SteamAPI_ISteamApps_BIsVACBanned(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetCurrentGameLanguage")] +internal static extern IntPtr SteamAPI_ISteamApps_GetCurrentGameLanguage(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetAvailableGameLanguages")] +internal static extern IntPtr SteamAPI_ISteamApps_GetAvailableGameLanguages(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsSubscribedApp")] +internal static extern bool SteamAPI_ISteamApps_BIsSubscribedApp(IntPtr instancePtr, uint appID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsDlcInstalled")] +internal static extern bool SteamAPI_ISteamApps_BIsDlcInstalled(IntPtr instancePtr, uint appID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime")] +internal static extern uint SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend")] +internal static extern bool SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetDLCCount")] +internal static extern int SteamAPI_ISteamApps_GetDLCCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BGetDLCDataByIndex")] +internal static extern bool SteamAPI_ISteamApps_BGetDLCDataByIndex(IntPtr instancePtr, int iDLC, ref uint pAppID, ref bool pbAvailable, string pchName, int cchNameBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_InstallDLC")] +internal static extern void SteamAPI_ISteamApps_InstallDLC(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_UninstallDLC")] +internal static extern void SteamAPI_ISteamApps_UninstallDLC(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey")] +internal static extern void SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetCurrentBetaName")] +internal static extern bool SteamAPI_ISteamApps_GetCurrentBetaName(IntPtr instancePtr, string pchName, int cchNameBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_MarkContentCorrupt")] +internal static extern bool SteamAPI_ISteamApps_MarkContentCorrupt(IntPtr instancePtr, bool bMissingFilesOnly); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetInstalledDepots")] +internal static extern uint SteamAPI_ISteamApps_GetInstalledDepots(IntPtr instancePtr, uint appID, ref uint pvecDepots, uint cMaxDepots); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetAppInstallDir")] +internal static extern uint SteamAPI_ISteamApps_GetAppInstallDir(IntPtr instancePtr, uint appID, string pchFolder, uint cchFolderBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsAppInstalled")] +internal static extern bool SteamAPI_ISteamApps_BIsAppInstalled(IntPtr instancePtr, uint appID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetAppOwner")] +internal static extern ulong SteamAPI_ISteamApps_GetAppOwner(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetLaunchQueryParam")] +internal static extern IntPtr SteamAPI_ISteamApps_GetLaunchQueryParam(IntPtr instancePtr, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetDlcDownloadProgress")] +internal static extern bool SteamAPI_ISteamApps_GetDlcDownloadProgress(IntPtr instancePtr, uint nAppID, ref ulong punBytesDownloaded, ref ulong punBytesTotal); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetAppBuildId")] +internal static extern int SteamAPI_ISteamApps_GetAppBuildId(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys")] +internal static extern void SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetFileDetails")] +internal static extern ulong SteamAPI_ISteamApps_GetFileDetails(IntPtr instancePtr, string pszFileName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_GetLaunchCommandLine")] +internal static extern int SteamAPI_ISteamApps_GetLaunchCommandLine(IntPtr instancePtr, string pszCommandLine, int cubCommandLine); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing")] +internal static extern bool SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_SendP2PPacket")] +internal static extern bool SteamAPI_ISteamNetworking_SendP2PPacket(IntPtr instancePtr, ulong steamIDRemote, IntPtr pubData, uint cubData, uint eP2PSendType, int nChannel); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_IsP2PPacketAvailable")] +internal static extern bool SteamAPI_ISteamNetworking_IsP2PPacketAvailable(IntPtr instancePtr, ref uint pcubMsgSize, int nChannel); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_ReadP2PPacket")] +internal static extern bool SteamAPI_ISteamNetworking_ReadP2PPacket(IntPtr instancePtr, IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref CSteamID psteamIDRemote, int nChannel); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser")] +internal static extern bool SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser(IntPtr instancePtr, ulong steamIDRemote); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_CloseP2PSessionWithUser")] +internal static extern bool SteamAPI_ISteamNetworking_CloseP2PSessionWithUser(IntPtr instancePtr, ulong steamIDRemote); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_CloseP2PChannelWithUser")] +internal static extern bool SteamAPI_ISteamNetworking_CloseP2PChannelWithUser(IntPtr instancePtr, ulong steamIDRemote, int nChannel); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_GetP2PSessionState")] +internal static extern bool SteamAPI_ISteamNetworking_GetP2PSessionState(IntPtr instancePtr, ulong steamIDRemote, ref P2PSessionState_t pConnectionState); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_AllowP2PPacketRelay")] +internal static extern bool SteamAPI_ISteamNetworking_AllowP2PPacketRelay(IntPtr instancePtr, bool bAllow); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_CreateListenSocket")] +internal static extern uint SteamAPI_ISteamNetworking_CreateListenSocket(IntPtr instancePtr, int nVirtualP2PPort, uint nIP, char nPort, bool bAllowUseOfPacketRelay); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_CreateP2PConnectionSocket")] +internal static extern uint SteamAPI_ISteamNetworking_CreateP2PConnectionSocket(IntPtr instancePtr, ulong steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_CreateConnectionSocket")] +internal static extern uint SteamAPI_ISteamNetworking_CreateConnectionSocket(IntPtr instancePtr, uint nIP, char nPort, int nTimeoutSec); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_DestroySocket")] +internal static extern bool SteamAPI_ISteamNetworking_DestroySocket(IntPtr instancePtr, uint hSocket, bool bNotifyRemoteEnd); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_DestroyListenSocket")] +internal static extern bool SteamAPI_ISteamNetworking_DestroyListenSocket(IntPtr instancePtr, uint hSocket, bool bNotifyRemoteEnd); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_SendDataOnSocket")] +internal static extern bool SteamAPI_ISteamNetworking_SendDataOnSocket(IntPtr instancePtr, uint hSocket, IntPtr pubData, uint cubData, bool bReliable); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_IsDataAvailableOnSocket")] +internal static extern bool SteamAPI_ISteamNetworking_IsDataAvailableOnSocket(IntPtr instancePtr, uint hSocket, ref uint pcubMsgSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_RetrieveDataFromSocket")] +internal static extern bool SteamAPI_ISteamNetworking_RetrieveDataFromSocket(IntPtr instancePtr, uint hSocket, IntPtr pubDest, uint cubDest, ref uint pcubMsgSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_IsDataAvailable")] +internal static extern bool SteamAPI_ISteamNetworking_IsDataAvailable(IntPtr instancePtr, uint hListenSocket, ref uint pcubMsgSize, ref uint phSocket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_RetrieveData")] +internal static extern bool SteamAPI_ISteamNetworking_RetrieveData(IntPtr instancePtr, uint hListenSocket, IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref uint phSocket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_GetSocketInfo")] +internal static extern bool SteamAPI_ISteamNetworking_GetSocketInfo(IntPtr instancePtr, uint hSocket, ref CSteamID pSteamIDRemote, ref int peSocketStatus, ref uint punIPRemote, ref char punPortRemote); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_GetListenSocketInfo")] +internal static extern bool SteamAPI_ISteamNetworking_GetListenSocketInfo(IntPtr instancePtr, uint hListenSocket, ref uint pnIP, ref char pnPort); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_GetSocketConnectionType")] +internal static extern uint SteamAPI_ISteamNetworking_GetSocketConnectionType(IntPtr instancePtr, uint hSocket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamNetworking_GetMaxPacketSize")] +internal static extern int SteamAPI_ISteamNetworking_GetMaxPacketSize(IntPtr instancePtr, uint hSocket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_WriteScreenshot")] +internal static extern uint SteamAPI_ISteamScreenshots_WriteScreenshot(IntPtr instancePtr, IntPtr pubRGB, uint cubRGB, int nWidth, int nHeight); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_AddScreenshotToLibrary")] +internal static extern uint SteamAPI_ISteamScreenshots_AddScreenshotToLibrary(IntPtr instancePtr, string pchFilename, string pchThumbnailFilename, int nWidth, int nHeight); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_TriggerScreenshot")] +internal static extern void SteamAPI_ISteamScreenshots_TriggerScreenshot(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_HookScreenshots")] +internal static extern void SteamAPI_ISteamScreenshots_HookScreenshots(IntPtr instancePtr, bool bHook); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_SetLocation")] +internal static extern bool SteamAPI_ISteamScreenshots_SetLocation(IntPtr instancePtr, uint hScreenshot, string pchLocation); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_TagUser")] +internal static extern bool SteamAPI_ISteamScreenshots_TagUser(IntPtr instancePtr, uint hScreenshot, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_TagPublishedFile")] +internal static extern bool SteamAPI_ISteamScreenshots_TagPublishedFile(IntPtr instancePtr, uint hScreenshot, ulong unPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_IsScreenshotsHooked")] +internal static extern bool SteamAPI_ISteamScreenshots_IsScreenshotsHooked(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary")] +internal static extern uint SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary(IntPtr instancePtr, uint eType, string pchFilename, string pchVRFilename); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_BIsEnabled")] +internal static extern bool SteamAPI_ISteamMusic_BIsEnabled(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_BIsPlaying")] +internal static extern bool SteamAPI_ISteamMusic_BIsPlaying(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_GetPlaybackStatus")] +internal static extern int SteamAPI_ISteamMusic_GetPlaybackStatus(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_Play")] +internal static extern void SteamAPI_ISteamMusic_Play(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_Pause")] +internal static extern void SteamAPI_ISteamMusic_Pause(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_PlayPrevious")] +internal static extern void SteamAPI_ISteamMusic_PlayPrevious(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_PlayNext")] +internal static extern void SteamAPI_ISteamMusic_PlayNext(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_SetVolume")] +internal static extern void SteamAPI_ISteamMusic_SetVolume(IntPtr instancePtr, float flVolume); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusic_GetVolume")] +internal static extern float SteamAPI_ISteamMusic_GetVolume(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote")] +internal static extern bool SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote(IntPtr instancePtr, string pchName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote")] +internal static extern bool SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote")] +internal static extern bool SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_BActivationSuccess")] +internal static extern bool SteamAPI_ISteamMusicRemote_BActivationSuccess(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_SetDisplayName")] +internal static extern bool SteamAPI_ISteamMusicRemote_SetDisplayName(IntPtr instancePtr, string pchDisplayName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64")] +internal static extern bool SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64(IntPtr instancePtr, IntPtr pvBuffer, uint cbBufferLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_EnablePlayPrevious")] +internal static extern bool SteamAPI_ISteamMusicRemote_EnablePlayPrevious(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_EnablePlayNext")] +internal static extern bool SteamAPI_ISteamMusicRemote_EnablePlayNext(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_EnableShuffled")] +internal static extern bool SteamAPI_ISteamMusicRemote_EnableShuffled(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_EnableLooped")] +internal static extern bool SteamAPI_ISteamMusicRemote_EnableLooped(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_EnableQueue")] +internal static extern bool SteamAPI_ISteamMusicRemote_EnableQueue(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_EnablePlaylists")] +internal static extern bool SteamAPI_ISteamMusicRemote_EnablePlaylists(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus(IntPtr instancePtr, int nStatus); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdateShuffled")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdateShuffled(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdateLooped")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdateLooped(IntPtr instancePtr, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdateVolume")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdateVolume(IntPtr instancePtr, float flValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_CurrentEntryWillChange")] +internal static extern bool SteamAPI_ISteamMusicRemote_CurrentEntryWillChange(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable")] +internal static extern bool SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable(IntPtr instancePtr, bool bAvailable); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText(IntPtr instancePtr, string pchText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds(IntPtr instancePtr, int nValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt")] +internal static extern bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt(IntPtr instancePtr, IntPtr pvBuffer, uint cbBufferLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_CurrentEntryDidChange")] +internal static extern bool SteamAPI_ISteamMusicRemote_CurrentEntryDidChange(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_QueueWillChange")] +internal static extern bool SteamAPI_ISteamMusicRemote_QueueWillChange(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_ResetQueueEntries")] +internal static extern bool SteamAPI_ISteamMusicRemote_ResetQueueEntries(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_SetQueueEntry")] +internal static extern bool SteamAPI_ISteamMusicRemote_SetQueueEntry(IntPtr instancePtr, int nID, int nPosition, string pchEntryText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry")] +internal static extern bool SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry(IntPtr instancePtr, int nID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_QueueDidChange")] +internal static extern bool SteamAPI_ISteamMusicRemote_QueueDidChange(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_PlaylistWillChange")] +internal static extern bool SteamAPI_ISteamMusicRemote_PlaylistWillChange(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_ResetPlaylistEntries")] +internal static extern bool SteamAPI_ISteamMusicRemote_ResetPlaylistEntries(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_SetPlaylistEntry")] +internal static extern bool SteamAPI_ISteamMusicRemote_SetPlaylistEntry(IntPtr instancePtr, int nID, int nPosition, string pchEntryText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry")] +internal static extern bool SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry(IntPtr instancePtr, int nID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamMusicRemote_PlaylistDidChange")] +internal static extern bool SteamAPI_ISteamMusicRemote_PlaylistDidChange(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_CreateHTTPRequest")] +internal static extern uint SteamAPI_ISteamHTTP_CreateHTTPRequest(IntPtr instancePtr, uint eHTTPRequestMethod, string pchAbsoluteURL); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestContextValue")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestContextValue(IntPtr instancePtr, uint hRequest, ulong ulContextValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout(IntPtr instancePtr, uint hRequest, uint unTimeoutSeconds); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue(IntPtr instancePtr, uint hRequest, string pchHeaderName, string pchHeaderValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter(IntPtr instancePtr, uint hRequest, string pchParamName, string pchParamValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SendHTTPRequest")] +internal static extern bool SteamAPI_ISteamHTTP_SendHTTPRequest(IntPtr instancePtr, uint hRequest, ref ulong pCallHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse")] +internal static extern bool SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse(IntPtr instancePtr, uint hRequest, ref ulong pCallHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_DeferHTTPRequest")] +internal static extern bool SteamAPI_ISteamHTTP_DeferHTTPRequest(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_PrioritizeHTTPRequest")] +internal static extern bool SteamAPI_ISteamHTTP_PrioritizeHTTPRequest(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize(IntPtr instancePtr, uint hRequest, string pchHeaderName, ref uint unResponseHeaderSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue(IntPtr instancePtr, uint hRequest, string pchHeaderName, IntPtr pHeaderValueBuffer, uint unBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPResponseBodySize")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPResponseBodySize(IntPtr instancePtr, uint hRequest, ref uint unBodySize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPResponseBodyData")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPResponseBodyData(IntPtr instancePtr, uint hRequest, IntPtr pBodyDataBuffer, uint unBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData(IntPtr instancePtr, uint hRequest, uint cOffset, IntPtr pBodyDataBuffer, uint unBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_ReleaseHTTPRequest")] +internal static extern bool SteamAPI_ISteamHTTP_ReleaseHTTPRequest(IntPtr instancePtr, uint hRequest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct(IntPtr instancePtr, uint hRequest, ref float pflPercentOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody(IntPtr instancePtr, uint hRequest, string pchContentType, IntPtr pubBody, uint unBodyLen); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_CreateCookieContainer")] +internal static extern uint SteamAPI_ISteamHTTP_CreateCookieContainer(IntPtr instancePtr, bool bAllowResponsesToModify); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_ReleaseCookieContainer")] +internal static extern bool SteamAPI_ISteamHTTP_ReleaseCookieContainer(IntPtr instancePtr, uint hCookieContainer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetCookie")] +internal static extern bool SteamAPI_ISteamHTTP_SetCookie(IntPtr instancePtr, uint hCookieContainer, string pchHost, string pchUrl, string pchCookie); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer(IntPtr instancePtr, uint hRequest, uint hCookieContainer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo(IntPtr instancePtr, uint hRequest, string pchUserAgentInfo); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate(IntPtr instancePtr, uint hRequest, bool bRequireVerifiedCertificate); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS")] +internal static extern bool SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS(IntPtr instancePtr, uint hRequest, uint unMilliseconds); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut")] +internal static extern bool SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut(IntPtr instancePtr, uint hRequest, ref bool pbWasTimedOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_Init")] +internal static extern bool SteamAPI_ISteamInput_Init(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_Shutdown")] +internal static extern bool SteamAPI_ISteamInput_Shutdown(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_RunFrame")] +internal static extern void SteamAPI_ISteamInput_RunFrame(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetConnectedControllers")] +internal static extern int SteamAPI_ISteamInput_GetConnectedControllers(IntPtr instancePtr, [In, Out] ulong[] handlesOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetActionSetHandle")] +internal static extern ulong SteamAPI_ISteamInput_GetActionSetHandle(IntPtr instancePtr, string pszActionSetName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_ActivateActionSet")] +internal static extern void SteamAPI_ISteamInput_ActivateActionSet(IntPtr instancePtr, ulong inputHandle, ulong actionSetHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetCurrentActionSet")] +internal static extern ulong SteamAPI_ISteamInput_GetCurrentActionSet(IntPtr instancePtr, ulong inputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_ActivateActionSetLayer")] +internal static extern void SteamAPI_ISteamInput_ActivateActionSetLayer(IntPtr instancePtr, ulong inputHandle, ulong actionSetLayerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_DeactivateActionSetLayer")] +internal static extern void SteamAPI_ISteamInput_DeactivateActionSetLayer(IntPtr instancePtr, ulong inputHandle, ulong actionSetLayerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_DeactivateAllActionSetLayers")] +internal static extern void SteamAPI_ISteamInput_DeactivateAllActionSetLayers(IntPtr instancePtr, ulong inputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetActiveActionSetLayers")] +internal static extern int SteamAPI_ISteamInput_GetActiveActionSetLayers(IntPtr instancePtr, ulong inputHandle, [In, Out] ulong[] handlesOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetDigitalActionHandle")] +internal static extern ulong SteamAPI_ISteamInput_GetDigitalActionHandle(IntPtr instancePtr, string pszActionName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetDigitalActionData")] +internal static extern InputDigitalActionData_t SteamAPI_ISteamInput_GetDigitalActionData(IntPtr instancePtr, ulong inputHandle, ulong digitalActionHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetDigitalActionOrigins")] +internal static extern int SteamAPI_ISteamInput_GetDigitalActionOrigins(IntPtr instancePtr, ulong inputHandle, ulong actionSetHandle, ulong digitalActionHandle, [In, Out] uint[] originsOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetAnalogActionHandle")] +internal static extern ulong SteamAPI_ISteamInput_GetAnalogActionHandle(IntPtr instancePtr, string pszActionName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetAnalogActionData")] +internal static extern InputAnalogActionData_t SteamAPI_ISteamInput_GetAnalogActionData(IntPtr instancePtr, ulong inputHandle, ulong analogActionHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetAnalogActionOrigins")] +internal static extern int SteamAPI_ISteamInput_GetAnalogActionOrigins(IntPtr instancePtr, ulong inputHandle, ulong actionSetHandle, ulong analogActionHandle, [In, Out] uint[] originsOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetGlyphForActionOrigin")] +internal static extern IntPtr SteamAPI_ISteamInput_GetGlyphForActionOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetStringForActionOrigin")] +internal static extern IntPtr SteamAPI_ISteamInput_GetStringForActionOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_StopAnalogActionMomentum")] +internal static extern void SteamAPI_ISteamInput_StopAnalogActionMomentum(IntPtr instancePtr, ulong inputHandle, ulong eAction); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetMotionData")] +internal static extern InputMotionData_t SteamAPI_ISteamInput_GetMotionData(IntPtr instancePtr, ulong inputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_TriggerVibration")] +internal static extern void SteamAPI_ISteamInput_TriggerVibration(IntPtr instancePtr, ulong inputHandle, char usLeftSpeed, char usRightSpeed); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_SetLEDColor")] +internal static extern void SteamAPI_ISteamInput_SetLEDColor(IntPtr instancePtr, ulong inputHandle, byte nColorR, byte nColorG, byte nColorB, uint nFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_TriggerHapticPulse")] +internal static extern void SteamAPI_ISteamInput_TriggerHapticPulse(IntPtr instancePtr, ulong inputHandle, uint eTargetPad, char usDurationMicroSec); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_TriggerRepeatedHapticPulse")] +internal static extern void SteamAPI_ISteamInput_TriggerRepeatedHapticPulse(IntPtr instancePtr, ulong inputHandle, uint eTargetPad, char usDurationMicroSec, char usOffMicroSec, char unRepeat, uint nFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_ShowBindingPanel")] +internal static extern bool SteamAPI_ISteamInput_ShowBindingPanel(IntPtr instancePtr, ulong inputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetInputTypeForHandle")] +internal static extern uint SteamAPI_ISteamInput_GetInputTypeForHandle(IntPtr instancePtr, ulong inputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetControllerForGamepadIndex")] +internal static extern ulong SteamAPI_ISteamInput_GetControllerForGamepadIndex(IntPtr instancePtr, int nIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetGamepadIndexForController")] +internal static extern int SteamAPI_ISteamInput_GetGamepadIndexForController(IntPtr instancePtr, ulong ulinputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetStringForXboxOrigin")] +internal static extern IntPtr SteamAPI_ISteamInput_GetStringForXboxOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetGlyphForXboxOrigin")] +internal static extern IntPtr SteamAPI_ISteamInput_GetGlyphForXboxOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin")] +internal static extern uint SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin(IntPtr instancePtr, ulong inputHandle, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_TranslateActionOrigin")] +internal static extern uint SteamAPI_ISteamInput_TranslateActionOrigin(IntPtr instancePtr, uint eDestinationInputType, uint eSourceOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetDeviceBindingRevision")] +internal static extern bool SteamAPI_ISteamInput_GetDeviceBindingRevision(IntPtr instancePtr, ulong inputHandle, ref int pMajor, ref int pMinor); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInput_GetRemotePlaySessionID")] +internal static extern uint SteamAPI_ISteamInput_GetRemotePlaySessionID(IntPtr instancePtr, ulong inputHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_Init")] +internal static extern bool SteamAPI_ISteamController_Init(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_Shutdown")] +internal static extern bool SteamAPI_ISteamController_Shutdown(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_RunFrame")] +internal static extern void SteamAPI_ISteamController_RunFrame(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetConnectedControllers")] +internal static extern int SteamAPI_ISteamController_GetConnectedControllers(IntPtr instancePtr, [In, Out] ulong[] handlesOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetActionSetHandle")] +internal static extern ulong SteamAPI_ISteamController_GetActionSetHandle(IntPtr instancePtr, string pszActionSetName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_ActivateActionSet")] +internal static extern void SteamAPI_ISteamController_ActivateActionSet(IntPtr instancePtr, ulong controllerHandle, ulong actionSetHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetCurrentActionSet")] +internal static extern ulong SteamAPI_ISteamController_GetCurrentActionSet(IntPtr instancePtr, ulong controllerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_ActivateActionSetLayer")] +internal static extern void SteamAPI_ISteamController_ActivateActionSetLayer(IntPtr instancePtr, ulong controllerHandle, ulong actionSetLayerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_DeactivateActionSetLayer")] +internal static extern void SteamAPI_ISteamController_DeactivateActionSetLayer(IntPtr instancePtr, ulong controllerHandle, ulong actionSetLayerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_DeactivateAllActionSetLayers")] +internal static extern void SteamAPI_ISteamController_DeactivateAllActionSetLayers(IntPtr instancePtr, ulong controllerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetActiveActionSetLayers")] +internal static extern int SteamAPI_ISteamController_GetActiveActionSetLayers(IntPtr instancePtr, ulong controllerHandle, [In, Out] ulong[] handlesOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetDigitalActionHandle")] +internal static extern ulong SteamAPI_ISteamController_GetDigitalActionHandle(IntPtr instancePtr, string pszActionName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetDigitalActionData")] +internal static extern InputDigitalActionData_t SteamAPI_ISteamController_GetDigitalActionData(IntPtr instancePtr, ulong controllerHandle, ulong digitalActionHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetDigitalActionOrigins")] +internal static extern int SteamAPI_ISteamController_GetDigitalActionOrigins(IntPtr instancePtr, ulong controllerHandle, ulong actionSetHandle, ulong digitalActionHandle, [In, Out] uint[] originsOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetAnalogActionHandle")] +internal static extern ulong SteamAPI_ISteamController_GetAnalogActionHandle(IntPtr instancePtr, string pszActionName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetAnalogActionData")] +internal static extern InputAnalogActionData_t SteamAPI_ISteamController_GetAnalogActionData(IntPtr instancePtr, ulong controllerHandle, ulong analogActionHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetAnalogActionOrigins")] +internal static extern int SteamAPI_ISteamController_GetAnalogActionOrigins(IntPtr instancePtr, ulong controllerHandle, ulong actionSetHandle, ulong analogActionHandle, [In, Out] uint[] originsOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetGlyphForActionOrigin")] +internal static extern IntPtr SteamAPI_ISteamController_GetGlyphForActionOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetStringForActionOrigin")] +internal static extern IntPtr SteamAPI_ISteamController_GetStringForActionOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_StopAnalogActionMomentum")] +internal static extern void SteamAPI_ISteamController_StopAnalogActionMomentum(IntPtr instancePtr, ulong controllerHandle, ulong eAction); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetMotionData")] +internal static extern InputMotionData_t SteamAPI_ISteamController_GetMotionData(IntPtr instancePtr, ulong controllerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_TriggerHapticPulse")] +internal static extern void SteamAPI_ISteamController_TriggerHapticPulse(IntPtr instancePtr, ulong controllerHandle, uint eTargetPad, char usDurationMicroSec); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_TriggerRepeatedHapticPulse")] +internal static extern void SteamAPI_ISteamController_TriggerRepeatedHapticPulse(IntPtr instancePtr, ulong controllerHandle, uint eTargetPad, char usDurationMicroSec, char usOffMicroSec, char unRepeat, uint nFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_TriggerVibration")] +internal static extern void SteamAPI_ISteamController_TriggerVibration(IntPtr instancePtr, ulong controllerHandle, char usLeftSpeed, char usRightSpeed); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_SetLEDColor")] +internal static extern void SteamAPI_ISteamController_SetLEDColor(IntPtr instancePtr, ulong controllerHandle, byte nColorR, byte nColorG, byte nColorB, uint nFlags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_ShowBindingPanel")] +internal static extern bool SteamAPI_ISteamController_ShowBindingPanel(IntPtr instancePtr, ulong controllerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetInputTypeForHandle")] +internal static extern uint SteamAPI_ISteamController_GetInputTypeForHandle(IntPtr instancePtr, ulong controllerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetControllerForGamepadIndex")] +internal static extern ulong SteamAPI_ISteamController_GetControllerForGamepadIndex(IntPtr instancePtr, int nIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetGamepadIndexForController")] +internal static extern int SteamAPI_ISteamController_GetGamepadIndexForController(IntPtr instancePtr, ulong ulControllerHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetStringForXboxOrigin")] +internal static extern IntPtr SteamAPI_ISteamController_GetStringForXboxOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetGlyphForXboxOrigin")] +internal static extern IntPtr SteamAPI_ISteamController_GetGlyphForXboxOrigin(IntPtr instancePtr, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetActionOriginFromXboxOrigin")] +internal static extern uint SteamAPI_ISteamController_GetActionOriginFromXboxOrigin(IntPtr instancePtr, ulong controllerHandle, uint eOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_TranslateActionOrigin")] +internal static extern uint SteamAPI_ISteamController_TranslateActionOrigin(IntPtr instancePtr, uint eDestinationInputType, uint eSourceOrigin); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamController_GetControllerBindingRevision")] +internal static extern bool SteamAPI_ISteamController_GetControllerBindingRevision(IntPtr instancePtr, ulong controllerHandle, ref int pMajor, ref int pMinor); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_CreateQueryUserUGCRequest")] +internal static extern ulong SteamAPI_ISteamUGC_CreateQueryUserUGCRequest(IntPtr instancePtr, uint unAccountID, uint eListType, uint eMatchingUGCType, uint eSortOrder, uint nCreatorAppID, uint nConsumerAppID, uint unPage); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_CreateQueryAllUGCRequest")] +internal static extern ulong SteamAPI_ISteamUGC_CreateQueryAllUGCRequest(IntPtr instancePtr, uint eQueryType, uint eMatchingeMatchingUGCTypeFileType, uint nCreatorAppID, uint nConsumerAppID, uint unPage); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_CreateQueryAllUGCRequest0")] +internal static extern ulong SteamAPI_ISteamUGC_CreateQueryAllUGCRequest0(IntPtr instancePtr, uint eQueryType, uint eMatchingeMatchingUGCTypeFileType, uint nCreatorAppID, uint nConsumerAppID, string pchCursor); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest")] +internal static extern ulong SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest(IntPtr instancePtr, ref ulong pvecPublishedFileID, uint unNumPublishedFileIDs); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SendQueryUGCRequest")] +internal static extern ulong SteamAPI_ISteamUGC_SendQueryUGCRequest(IntPtr instancePtr, ulong handle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCResult")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCResult(IntPtr instancePtr, ulong handle, uint index, ref SteamUGCDetails_t pDetails); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCPreviewURL")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCPreviewURL(IntPtr instancePtr, ulong handle, uint index, System.Text.StringBuilder pchURL, uint cchURLSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCMetadata")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCMetadata(IntPtr instancePtr, ulong handle, uint index, System.Text.StringBuilder pchMetadata, uint cchMetadatasize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCChildren")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCChildren(IntPtr instancePtr, ulong handle, uint index, ref ulong pvecPublishedFileID, uint cMaxEntries); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCStatistic")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCStatistic(IntPtr instancePtr, ulong handle, uint index, uint eStatType, ref ulong pStatValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews")] +internal static extern uint SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews(IntPtr instancePtr, ulong handle, uint index); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview(IntPtr instancePtr, ulong handle, uint index, uint previewIndex, System.Text.StringBuilder pchURLOrVideoID, uint cchURLSize, System.Text.StringBuilder pchOriginalFileName, uint cchOriginalFileNameSize, ref uint pPreviewType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags")] +internal static extern uint SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags(IntPtr instancePtr, ulong handle, uint index); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag(IntPtr instancePtr, ulong handle, uint index, uint keyValueTagIndex, System.Text.StringBuilder pchKey, uint cchKeySize, System.Text.StringBuilder pchValue, uint cchValueSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag0")] +internal static extern bool SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag0(IntPtr instancePtr, ulong handle, uint index, string pchKey, System.Text.StringBuilder pchValue, uint cchValueSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_ReleaseQueryUGCRequest")] +internal static extern bool SteamAPI_ISteamUGC_ReleaseQueryUGCRequest(IntPtr instancePtr, ulong handle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddRequiredTag")] +internal static extern bool SteamAPI_ISteamUGC_AddRequiredTag(IntPtr instancePtr, ulong handle, string pTagName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddExcludedTag")] +internal static extern bool SteamAPI_ISteamUGC_AddExcludedTag(IntPtr instancePtr, ulong handle, string pTagName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnOnlyIDs")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnOnlyIDs(IntPtr instancePtr, ulong handle, bool bReturnOnlyIDs); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnKeyValueTags")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnKeyValueTags(IntPtr instancePtr, ulong handle, bool bReturnKeyValueTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnLongDescription")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnLongDescription(IntPtr instancePtr, ulong handle, bool bReturnLongDescription); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnMetadata")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnMetadata(IntPtr instancePtr, ulong handle, bool bReturnMetadata); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnChildren")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnChildren(IntPtr instancePtr, ulong handle, bool bReturnChildren); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnAdditionalPreviews")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnAdditionalPreviews(IntPtr instancePtr, ulong handle, bool bReturnAdditionalPreviews); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnTotalOnly")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnTotalOnly(IntPtr instancePtr, ulong handle, bool bReturnTotalOnly); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetReturnPlaytimeStats")] +internal static extern bool SteamAPI_ISteamUGC_SetReturnPlaytimeStats(IntPtr instancePtr, ulong handle, uint unDays); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetLanguage")] +internal static extern bool SteamAPI_ISteamUGC_SetLanguage(IntPtr instancePtr, ulong handle, string pchLanguage); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetAllowCachedResponse")] +internal static extern bool SteamAPI_ISteamUGC_SetAllowCachedResponse(IntPtr instancePtr, ulong handle, uint unMaxAgeSeconds); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetCloudFileNameFilter")] +internal static extern bool SteamAPI_ISteamUGC_SetCloudFileNameFilter(IntPtr instancePtr, ulong handle, string pMatchCloudFileName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetMatchAnyTag")] +internal static extern bool SteamAPI_ISteamUGC_SetMatchAnyTag(IntPtr instancePtr, ulong handle, bool bMatchAnyTag); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetSearchText")] +internal static extern bool SteamAPI_ISteamUGC_SetSearchText(IntPtr instancePtr, ulong handle, string pSearchText); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetRankedByTrendDays")] +internal static extern bool SteamAPI_ISteamUGC_SetRankedByTrendDays(IntPtr instancePtr, ulong handle, uint unDays); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddRequiredKeyValueTag")] +internal static extern bool SteamAPI_ISteamUGC_AddRequiredKeyValueTag(IntPtr instancePtr, ulong handle, string pKey, string pValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RequestUGCDetails")] +internal static extern ulong SteamAPI_ISteamUGC_RequestUGCDetails(IntPtr instancePtr, ulong nPublishedFileID, uint unMaxAgeSeconds); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_CreateItem")] +internal static extern ulong SteamAPI_ISteamUGC_CreateItem(IntPtr instancePtr, uint nConsumerAppId, uint eFileType); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_StartItemUpdate")] +internal static extern ulong SteamAPI_ISteamUGC_StartItemUpdate(IntPtr instancePtr, uint nConsumerAppId, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemTitle")] +internal static extern bool SteamAPI_ISteamUGC_SetItemTitle(IntPtr instancePtr, ulong handle, string pchTitle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemDescription")] +internal static extern bool SteamAPI_ISteamUGC_SetItemDescription(IntPtr instancePtr, ulong handle, string pchDescription); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemUpdateLanguage")] +internal static extern bool SteamAPI_ISteamUGC_SetItemUpdateLanguage(IntPtr instancePtr, ulong handle, string pchLanguage); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemMetadata")] +internal static extern bool SteamAPI_ISteamUGC_SetItemMetadata(IntPtr instancePtr, ulong handle, string pchMetaData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemVisibility")] +internal static extern bool SteamAPI_ISteamUGC_SetItemVisibility(IntPtr instancePtr, ulong handle, uint eVisibility); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemTags")] +internal static extern bool SteamAPI_ISteamUGC_SetItemTags(IntPtr instancePtr, ulong updateHandle, ref SteamParamStringArray_t pTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemContent")] +internal static extern bool SteamAPI_ISteamUGC_SetItemContent(IntPtr instancePtr, ulong handle, string pszContentFolder); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetItemPreview")] +internal static extern bool SteamAPI_ISteamUGC_SetItemPreview(IntPtr instancePtr, ulong handle, string pszPreviewFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetAllowLegacyUpload")] +internal static extern bool SteamAPI_ISteamUGC_SetAllowLegacyUpload(IntPtr instancePtr, ulong handle, bool bAllowLegacyUpload); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags")] +internal static extern bool SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags(IntPtr instancePtr, ulong handle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RemoveItemKeyValueTags")] +internal static extern bool SteamAPI_ISteamUGC_RemoveItemKeyValueTags(IntPtr instancePtr, ulong handle, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddItemKeyValueTag")] +internal static extern bool SteamAPI_ISteamUGC_AddItemKeyValueTag(IntPtr instancePtr, ulong handle, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddItemPreviewFile")] +internal static extern bool SteamAPI_ISteamUGC_AddItemPreviewFile(IntPtr instancePtr, ulong handle, string pszPreviewFile, uint type); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddItemPreviewVideo")] +internal static extern bool SteamAPI_ISteamUGC_AddItemPreviewVideo(IntPtr instancePtr, ulong handle, string pszVideoID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_UpdateItemPreviewFile")] +internal static extern bool SteamAPI_ISteamUGC_UpdateItemPreviewFile(IntPtr instancePtr, ulong handle, uint index, string pszPreviewFile); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_UpdateItemPreviewVideo")] +internal static extern bool SteamAPI_ISteamUGC_UpdateItemPreviewVideo(IntPtr instancePtr, ulong handle, uint index, string pszVideoID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RemoveItemPreview")] +internal static extern bool SteamAPI_ISteamUGC_RemoveItemPreview(IntPtr instancePtr, ulong handle, uint index); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SubmitItemUpdate")] +internal static extern ulong SteamAPI_ISteamUGC_SubmitItemUpdate(IntPtr instancePtr, ulong handle, string pchChangeNote); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetItemUpdateProgress")] +internal static extern uint SteamAPI_ISteamUGC_GetItemUpdateProgress(IntPtr instancePtr, ulong handle, ref ulong punBytesProcessed, ref ulong punBytesTotal); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SetUserItemVote")] +internal static extern ulong SteamAPI_ISteamUGC_SetUserItemVote(IntPtr instancePtr, ulong nPublishedFileID, bool bVoteUp); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetUserItemVote")] +internal static extern ulong SteamAPI_ISteamUGC_GetUserItemVote(IntPtr instancePtr, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddItemToFavorites")] +internal static extern ulong SteamAPI_ISteamUGC_AddItemToFavorites(IntPtr instancePtr, uint nAppId, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RemoveItemFromFavorites")] +internal static extern ulong SteamAPI_ISteamUGC_RemoveItemFromFavorites(IntPtr instancePtr, uint nAppId, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SubscribeItem")] +internal static extern ulong SteamAPI_ISteamUGC_SubscribeItem(IntPtr instancePtr, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_UnsubscribeItem")] +internal static extern ulong SteamAPI_ISteamUGC_UnsubscribeItem(IntPtr instancePtr, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetNumSubscribedItems")] +internal static extern uint SteamAPI_ISteamUGC_GetNumSubscribedItems(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetSubscribedItems")] +internal static extern uint SteamAPI_ISteamUGC_GetSubscribedItems(IntPtr instancePtr, ref ulong pvecPublishedFileID, uint cMaxEntries); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetItemState")] +internal static extern uint SteamAPI_ISteamUGC_GetItemState(IntPtr instancePtr, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetItemInstallInfo")] +internal static extern bool SteamAPI_ISteamUGC_GetItemInstallInfo(IntPtr instancePtr, ulong nPublishedFileID, ref ulong punSizeOnDisk, System.Text.StringBuilder pchFolder, uint cchFolderSize, ref uint punTimeStamp); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetItemDownloadInfo")] +internal static extern bool SteamAPI_ISteamUGC_GetItemDownloadInfo(IntPtr instancePtr, ulong nPublishedFileID, ref ulong punBytesDownloaded, ref ulong punBytesTotal); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_DownloadItem")] +internal static extern bool SteamAPI_ISteamUGC_DownloadItem(IntPtr instancePtr, ulong nPublishedFileID, bool bHighPriority); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_BInitWorkshopForGameServer")] +internal static extern bool SteamAPI_ISteamUGC_BInitWorkshopForGameServer(IntPtr instancePtr, uint unWorkshopDepotID, string pszFolder); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_SuspendDownloads")] +internal static extern void SteamAPI_ISteamUGC_SuspendDownloads(IntPtr instancePtr, bool bSuspend); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_StartPlaytimeTracking")] +internal static extern ulong SteamAPI_ISteamUGC_StartPlaytimeTracking(IntPtr instancePtr, ref ulong pvecPublishedFileID, uint unNumPublishedFileIDs); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_StopPlaytimeTracking")] +internal static extern ulong SteamAPI_ISteamUGC_StopPlaytimeTracking(IntPtr instancePtr, ref ulong pvecPublishedFileID, uint unNumPublishedFileIDs); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems")] +internal static extern ulong SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddDependency")] +internal static extern ulong SteamAPI_ISteamUGC_AddDependency(IntPtr instancePtr, ulong nParentPublishedFileID, ulong nChildPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RemoveDependency")] +internal static extern ulong SteamAPI_ISteamUGC_RemoveDependency(IntPtr instancePtr, ulong nParentPublishedFileID, ulong nChildPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_AddAppDependency")] +internal static extern ulong SteamAPI_ISteamUGC_AddAppDependency(IntPtr instancePtr, ulong nPublishedFileID, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_RemoveAppDependency")] +internal static extern ulong SteamAPI_ISteamUGC_RemoveAppDependency(IntPtr instancePtr, ulong nPublishedFileID, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_GetAppDependencies")] +internal static extern ulong SteamAPI_ISteamUGC_GetAppDependencies(IntPtr instancePtr, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamUGC_DeleteItem")] +internal static extern ulong SteamAPI_ISteamUGC_DeleteItem(IntPtr instancePtr, ulong nPublishedFileID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamAppList_GetNumInstalledApps")] +internal static extern uint SteamAPI_ISteamAppList_GetNumInstalledApps(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamAppList_GetInstalledApps")] +internal static extern uint SteamAPI_ISteamAppList_GetInstalledApps(IntPtr instancePtr, ref uint pvecAppID, uint unMaxAppIDs); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamAppList_GetAppName")] +internal static extern int SteamAPI_ISteamAppList_GetAppName(IntPtr instancePtr, uint nAppID, System.Text.StringBuilder pchName, int cchNameMax); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamAppList_GetAppInstallDir")] +internal static extern int SteamAPI_ISteamAppList_GetAppInstallDir(IntPtr instancePtr, uint nAppID, string pchDirectory, int cchNameMax); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamAppList_GetAppBuildId")] +internal static extern int SteamAPI_ISteamAppList_GetAppBuildId(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_DestructISteamHTMLSurface")] +internal static extern void SteamAPI_ISteamHTMLSurface_DestructISteamHTMLSurface(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_Init")] +internal static extern bool SteamAPI_ISteamHTMLSurface_Init(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_Shutdown")] +internal static extern bool SteamAPI_ISteamHTMLSurface_Shutdown(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_CreateBrowser")] +internal static extern ulong SteamAPI_ISteamHTMLSurface_CreateBrowser(IntPtr instancePtr, string pchUserAgent, string pchUserCSS); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_RemoveBrowser")] +internal static extern void SteamAPI_ISteamHTMLSurface_RemoveBrowser(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_LoadURL")] +internal static extern void SteamAPI_ISteamHTMLSurface_LoadURL(IntPtr instancePtr, uint unBrowserHandle, string pchURL, string pchPostData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetSize")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetSize(IntPtr instancePtr, uint unBrowserHandle, uint unWidth, uint unHeight); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_StopLoad")] +internal static extern void SteamAPI_ISteamHTMLSurface_StopLoad(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_Reload")] +internal static extern void SteamAPI_ISteamHTMLSurface_Reload(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_GoBack")] +internal static extern void SteamAPI_ISteamHTMLSurface_GoBack(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_GoForward")] +internal static extern void SteamAPI_ISteamHTMLSurface_GoForward(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_AddHeader")] +internal static extern void SteamAPI_ISteamHTMLSurface_AddHeader(IntPtr instancePtr, uint unBrowserHandle, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_ExecuteJavascript")] +internal static extern void SteamAPI_ISteamHTMLSurface_ExecuteJavascript(IntPtr instancePtr, uint unBrowserHandle, string pchScript); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_MouseUp")] +internal static extern void SteamAPI_ISteamHTMLSurface_MouseUp(IntPtr instancePtr, uint unBrowserHandle, uint eMouseButton); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_MouseDown")] +internal static extern void SteamAPI_ISteamHTMLSurface_MouseDown(IntPtr instancePtr, uint unBrowserHandle, uint eMouseButton); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_MouseDoubleClick")] +internal static extern void SteamAPI_ISteamHTMLSurface_MouseDoubleClick(IntPtr instancePtr, uint unBrowserHandle, uint eMouseButton); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_MouseMove")] +internal static extern void SteamAPI_ISteamHTMLSurface_MouseMove(IntPtr instancePtr, uint unBrowserHandle, int x, int y); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_MouseWheel")] +internal static extern void SteamAPI_ISteamHTMLSurface_MouseWheel(IntPtr instancePtr, uint unBrowserHandle, int nDelta); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_KeyDown")] +internal static extern void SteamAPI_ISteamHTMLSurface_KeyDown(IntPtr instancePtr, uint unBrowserHandle, uint nNativeKeyCode, uint eHTMLKeyModifiers, bool bIsSystemKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_KeyUp")] +internal static extern void SteamAPI_ISteamHTMLSurface_KeyUp(IntPtr instancePtr, uint unBrowserHandle, uint nNativeKeyCode, uint eHTMLKeyModifiers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_KeyChar")] +internal static extern void SteamAPI_ISteamHTMLSurface_KeyChar(IntPtr instancePtr, uint unBrowserHandle, uint cUnicodeChar, uint eHTMLKeyModifiers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetHorizontalScroll")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetHorizontalScroll(IntPtr instancePtr, uint unBrowserHandle, uint nAbsolutePixelScroll); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetVerticalScroll")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetVerticalScroll(IntPtr instancePtr, uint unBrowserHandle, uint nAbsolutePixelScroll); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetKeyFocus")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetKeyFocus(IntPtr instancePtr, uint unBrowserHandle, bool bHasKeyFocus); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_ViewSource")] +internal static extern void SteamAPI_ISteamHTMLSurface_ViewSource(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_CopyToClipboard")] +internal static extern void SteamAPI_ISteamHTMLSurface_CopyToClipboard(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_PasteFromClipboard")] +internal static extern void SteamAPI_ISteamHTMLSurface_PasteFromClipboard(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_Find")] +internal static extern void SteamAPI_ISteamHTMLSurface_Find(IntPtr instancePtr, uint unBrowserHandle, string pchSearchStr, bool bCurrentlyInFind, bool bReverse); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_StopFind")] +internal static extern void SteamAPI_ISteamHTMLSurface_StopFind(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_GetLinkAtPosition")] +internal static extern void SteamAPI_ISteamHTMLSurface_GetLinkAtPosition(IntPtr instancePtr, uint unBrowserHandle, int x, int y); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetCookie")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetCookie(IntPtr instancePtr, string pchHostname, string pchKey, string pchValue, string pchPath, ulong nExpires, bool bSecure, bool bHTTPOnly); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetPageScaleFactor")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetPageScaleFactor(IntPtr instancePtr, uint unBrowserHandle, float flZoom, int nPointX, int nPointY); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetBackgroundMode")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetBackgroundMode(IntPtr instancePtr, uint unBrowserHandle, bool bBackgroundMode); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor")] +internal static extern void SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor(IntPtr instancePtr, uint unBrowserHandle, float flDPIScaling); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_OpenDeveloperTools")] +internal static extern void SteamAPI_ISteamHTMLSurface_OpenDeveloperTools(IntPtr instancePtr, uint unBrowserHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_AllowStartRequest")] +internal static extern void SteamAPI_ISteamHTMLSurface_AllowStartRequest(IntPtr instancePtr, uint unBrowserHandle, bool bAllowed); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamHTMLSurface_JSDialogResponse")] +internal static extern void SteamAPI_ISteamHTMLSurface_JSDialogResponse(IntPtr instancePtr, uint unBrowserHandle, bool bResult); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetResultStatus")] +internal static extern uint SteamAPI_ISteamInventory_GetResultStatus(IntPtr instancePtr, int resultHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetResultItems")] +internal static extern bool SteamAPI_ISteamInventory_GetResultItems(IntPtr instancePtr, int resultHandle, [In, Out] SteamItemDetails_t[] pOutItemsArray, ref uint punOutItemsArraySize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetResultItemProperty")] +internal static extern bool SteamAPI_ISteamInventory_GetResultItemProperty(IntPtr instancePtr, int resultHandle, uint unItemIndex, string pchPropertyName, System.Text.StringBuilder pchValueBuffer, ref uint punValueBufferSizeOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetResultTimestamp")] +internal static extern uint SteamAPI_ISteamInventory_GetResultTimestamp(IntPtr instancePtr, int resultHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_CheckResultSteamID")] +internal static extern bool SteamAPI_ISteamInventory_CheckResultSteamID(IntPtr instancePtr, int resultHandle, ulong steamIDExpected); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_DestroyResult")] +internal static extern void SteamAPI_ISteamInventory_DestroyResult(IntPtr instancePtr, int resultHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetAllItems")] +internal static extern bool SteamAPI_ISteamInventory_GetAllItems(IntPtr instancePtr, ref int pResultHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetItemsByID")] +internal static extern bool SteamAPI_ISteamInventory_GetItemsByID(IntPtr instancePtr, ref int pResultHandle, [In, Out] ulong[] pInstanceIDs, uint unCountInstanceIDs); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SerializeResult")] +internal static extern bool SteamAPI_ISteamInventory_SerializeResult(IntPtr instancePtr, int resultHandle, IntPtr pOutBuffer, ref uint punOutBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_DeserializeResult")] +internal static extern bool SteamAPI_ISteamInventory_DeserializeResult(IntPtr instancePtr, ref int pOutResultHandle, IntPtr pBuffer, uint unBufferSize, bool bRESERVED_MUST_BE_FALSE); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GenerateItems")] +internal static extern bool SteamAPI_ISteamInventory_GenerateItems(IntPtr instancePtr, ref int pResultHandle, [In, Out] int[] pArrayItemDefs, [In, Out] uint[] punArrayQuantity, uint unArrayLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GrantPromoItems")] +internal static extern bool SteamAPI_ISteamInventory_GrantPromoItems(IntPtr instancePtr, ref int pResultHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_AddPromoItem")] +internal static extern bool SteamAPI_ISteamInventory_AddPromoItem(IntPtr instancePtr, ref int pResultHandle, int itemDef); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_AddPromoItems")] +internal static extern bool SteamAPI_ISteamInventory_AddPromoItems(IntPtr instancePtr, ref int pResultHandle, [In, Out] int[] pArrayItemDefs, uint unArrayLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_ConsumeItem")] +internal static extern bool SteamAPI_ISteamInventory_ConsumeItem(IntPtr instancePtr, ref int pResultHandle, ulong itemConsume, uint unQuantity); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_ExchangeItems")] +internal static extern bool SteamAPI_ISteamInventory_ExchangeItems(IntPtr instancePtr, ref int pResultHandle, [In, Out] int[] pArrayGenerate, [In, Out] uint[] punArrayGenerateQuantity, uint unArrayGenerateLength, [In, Out] ulong[] pArrayDestroy, [In, Out] uint[] punArrayDestroyQuantity, uint unArrayDestroyLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_TransferItemQuantity")] +internal static extern bool SteamAPI_ISteamInventory_TransferItemQuantity(IntPtr instancePtr, ref int pResultHandle, ulong itemIdSource, uint unQuantity, ulong itemIdDest); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SendItemDropHeartbeat")] +internal static extern void SteamAPI_ISteamInventory_SendItemDropHeartbeat(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_TriggerItemDrop")] +internal static extern bool SteamAPI_ISteamInventory_TriggerItemDrop(IntPtr instancePtr, ref int pResultHandle, int dropListDefinition); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_TradeItems")] +internal static extern bool SteamAPI_ISteamInventory_TradeItems(IntPtr instancePtr, ref int pResultHandle, ulong steamIDTradePartner, [In, Out] ulong[] pArrayGive, [In, Out] uint[] pArrayGiveQuantity, uint nArrayGiveLength, [In, Out] ulong[] pArrayGet, [In, Out] uint[] pArrayGetQuantity, uint nArrayGetLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_LoadItemDefinitions")] +internal static extern bool SteamAPI_ISteamInventory_LoadItemDefinitions(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetItemDefinitionIDs")] +internal static extern bool SteamAPI_ISteamInventory_GetItemDefinitionIDs(IntPtr instancePtr, [In, Out] int[] pItemDefIDs, ref uint punItemDefIDsArraySize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetItemDefinitionProperty")] +internal static extern bool SteamAPI_ISteamInventory_GetItemDefinitionProperty(IntPtr instancePtr, int iDefinition, string pchPropertyName, System.Text.StringBuilder pchValueBuffer, ref uint punValueBufferSizeOut); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs")] +internal static extern ulong SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs(IntPtr instancePtr, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs")] +internal static extern bool SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs(IntPtr instancePtr, ulong steamID, [In, Out] int[] pItemDefIDs, ref uint punItemDefIDsArraySize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_StartPurchase")] +internal static extern ulong SteamAPI_ISteamInventory_StartPurchase(IntPtr instancePtr, [In, Out] int[] pArrayItemDefs, [In, Out] uint[] punArrayQuantity, uint unArrayLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_RequestPrices")] +internal static extern ulong SteamAPI_ISteamInventory_RequestPrices(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetNumItemsWithPrices")] +internal static extern uint SteamAPI_ISteamInventory_GetNumItemsWithPrices(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetItemsWithPrices")] +internal static extern bool SteamAPI_ISteamInventory_GetItemsWithPrices(IntPtr instancePtr, [In, Out] int[] pArrayItemDefs, [In, Out] ulong[] pCurrentPrices, [In, Out] ulong[] pBasePrices, uint unArrayLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_GetItemPrice")] +internal static extern bool SteamAPI_ISteamInventory_GetItemPrice(IntPtr instancePtr, int iDefinition, ref ulong pCurrentPrice, ref ulong pBasePrice); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_StartUpdateProperties")] +internal static extern ulong SteamAPI_ISteamInventory_StartUpdateProperties(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_RemoveProperty")] +internal static extern bool SteamAPI_ISteamInventory_RemoveProperty(IntPtr instancePtr, ulong handle, ulong nItemID, string pchPropertyName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SetProperty")] +internal static extern bool SteamAPI_ISteamInventory_SetProperty(IntPtr instancePtr, ulong handle, ulong nItemID, string pchPropertyName, string pchPropertyValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SetProperty0")] +internal static extern bool SteamAPI_ISteamInventory_SetProperty0(IntPtr instancePtr, ulong handle, ulong nItemID, string pchPropertyName, bool bValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SetProperty1")] +internal static extern bool SteamAPI_ISteamInventory_SetProperty1(IntPtr instancePtr, ulong handle, ulong nItemID, string pchPropertyName, long nValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SetProperty2")] +internal static extern bool SteamAPI_ISteamInventory_SetProperty2(IntPtr instancePtr, ulong handle, ulong nItemID, string pchPropertyName, float flValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamInventory_SubmitUpdateProperties")] +internal static extern bool SteamAPI_ISteamInventory_SubmitUpdateProperties(IntPtr instancePtr, ulong handle, ref int pResultHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamVideo_GetVideoURL")] +internal static extern void SteamAPI_ISteamVideo_GetVideoURL(IntPtr instancePtr, uint unVideoAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamVideo_IsBroadcasting")] +internal static extern bool SteamAPI_ISteamVideo_IsBroadcasting(IntPtr instancePtr, ref int pnNumViewers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamVideo_GetOPFSettings")] +internal static extern void SteamAPI_ISteamVideo_GetOPFSettings(IntPtr instancePtr, uint unVideoAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamVideo_GetOPFStringForApp")] +internal static extern bool SteamAPI_ISteamVideo_GetOPFStringForApp(IntPtr instancePtr, uint unVideoAppID, string pchBuffer, ref int pnBufferSize); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_IsBroadcasting")] +internal static extern bool SteamAPI_ISteamTV_IsBroadcasting(IntPtr instancePtr, ref int pnNumViewers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_AddBroadcastGameData")] +internal static extern void SteamAPI_ISteamTV_AddBroadcastGameData(IntPtr instancePtr, string pchKey, string pchValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_RemoveBroadcastGameData")] +internal static extern void SteamAPI_ISteamTV_RemoveBroadcastGameData(IntPtr instancePtr, string pchKey); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_AddTimelineMarker")] +internal static extern void SteamAPI_ISteamTV_AddTimelineMarker(IntPtr instancePtr, string pchTemplateName, bool bPersistent, byte nColorR, byte nColorG, byte nColorB); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_RemoveTimelineMarker")] +internal static extern void SteamAPI_ISteamTV_RemoveTimelineMarker(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_AddRegion")] +internal static extern uint SteamAPI_ISteamTV_AddRegion(IntPtr instancePtr, string pchElementName, string pchTimelineDataSection, ref SteamTVRegion_t pSteamTVRegion, uint eSteamTVRegionBehavior); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamTV_RemoveRegion")] +internal static extern void SteamAPI_ISteamTV_RemoveRegion(IntPtr instancePtr, uint unRegionHandle); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled")] +internal static extern bool SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParentalSettings_BIsParentalLockLocked")] +internal static extern bool SteamAPI_ISteamParentalSettings_BIsParentalLockLocked(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParentalSettings_BIsAppBlocked")] +internal static extern bool SteamAPI_ISteamParentalSettings_BIsAppBlocked(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParentalSettings_BIsAppInBlockList")] +internal static extern bool SteamAPI_ISteamParentalSettings_BIsAppInBlockList(IntPtr instancePtr, uint nAppID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParentalSettings_BIsFeatureBlocked")] +internal static extern bool SteamAPI_ISteamParentalSettings_BIsFeatureBlocked(IntPtr instancePtr, uint eFeature); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList")] +internal static extern bool SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList(IntPtr instancePtr, uint eFeature); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemotePlay_GetSessionCount")] +internal static extern uint SteamAPI_ISteamRemotePlay_GetSessionCount(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemotePlay_GetSessionID")] +internal static extern uint SteamAPI_ISteamRemotePlay_GetSessionID(IntPtr instancePtr, int iSessionIndex); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemotePlay_GetSessionSteamID")] +internal static extern ulong SteamAPI_ISteamRemotePlay_GetSessionSteamID(IntPtr instancePtr, uint unSessionID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemotePlay_GetSessionClientName")] +internal static extern IntPtr SteamAPI_ISteamRemotePlay_GetSessionClientName(IntPtr instancePtr, uint unSessionID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor")] +internal static extern uint SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor(IntPtr instancePtr, uint unSessionID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamRemotePlay_BGetSessionClientResolution")] +internal static extern bool SteamAPI_ISteamRemotePlay_BGetSessionClientResolution(IntPtr instancePtr, uint unSessionID, ref int pnResolutionX, ref int pnResolutionY); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_InitGameServer")] +internal static extern bool SteamAPI_ISteamGameServer_InitGameServer(IntPtr instancePtr, uint unIP, char usGamePort, char usQueryPort, uint unFlags, uint nGameAppId, string pchVersionString); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetProduct")] +internal static extern void SteamAPI_ISteamGameServer_SetProduct(IntPtr instancePtr, string pszProduct); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetGameDescription")] +internal static extern void SteamAPI_ISteamGameServer_SetGameDescription(IntPtr instancePtr, string pszGameDescription); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetModDir")] +internal static extern void SteamAPI_ISteamGameServer_SetModDir(IntPtr instancePtr, string pszModDir); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetDedicatedServer")] +internal static extern void SteamAPI_ISteamGameServer_SetDedicatedServer(IntPtr instancePtr, bool bDedicated); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_LogOn")] +internal static extern void SteamAPI_ISteamGameServer_LogOn(IntPtr instancePtr, string pszToken); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_LogOnAnonymous")] +internal static extern void SteamAPI_ISteamGameServer_LogOnAnonymous(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_LogOff")] +internal static extern void SteamAPI_ISteamGameServer_LogOff(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_BLoggedOn")] +internal static extern bool SteamAPI_ISteamGameServer_BLoggedOn(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_BSecure")] +internal static extern bool SteamAPI_ISteamGameServer_BSecure(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_GetSteamID")] +internal static extern ulong SteamAPI_ISteamGameServer_GetSteamID(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_WasRestartRequested")] +internal static extern bool SteamAPI_ISteamGameServer_WasRestartRequested(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetMaxPlayerCount")] +internal static extern void SteamAPI_ISteamGameServer_SetMaxPlayerCount(IntPtr instancePtr, int cPlayersMax); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetBotPlayerCount")] +internal static extern void SteamAPI_ISteamGameServer_SetBotPlayerCount(IntPtr instancePtr, int cBotplayers); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetServerName")] +internal static extern void SteamAPI_ISteamGameServer_SetServerName(IntPtr instancePtr, string pszServerName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetMapName")] +internal static extern void SteamAPI_ISteamGameServer_SetMapName(IntPtr instancePtr, string pszMapName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetPasswordProtected")] +internal static extern void SteamAPI_ISteamGameServer_SetPasswordProtected(IntPtr instancePtr, bool bPasswordProtected); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetSpectatorPort")] +internal static extern void SteamAPI_ISteamGameServer_SetSpectatorPort(IntPtr instancePtr, char unSpectatorPort); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetSpectatorServerName")] +internal static extern void SteamAPI_ISteamGameServer_SetSpectatorServerName(IntPtr instancePtr, string pszSpectatorServerName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_ClearAllKeyValues")] +internal static extern void SteamAPI_ISteamGameServer_ClearAllKeyValues(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetKeyValue")] +internal static extern void SteamAPI_ISteamGameServer_SetKeyValue(IntPtr instancePtr, string pKey, string pValue); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetGameTags")] +internal static extern void SteamAPI_ISteamGameServer_SetGameTags(IntPtr instancePtr, string pchGameTags); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetGameData")] +internal static extern void SteamAPI_ISteamGameServer_SetGameData(IntPtr instancePtr, string pchGameData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetRegion")] +internal static extern void SteamAPI_ISteamGameServer_SetRegion(IntPtr instancePtr, string pszRegion); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate")] +internal static extern bool SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate(IntPtr instancePtr, uint unIPClient, IntPtr pvAuthBlob, uint cubAuthBlobSize, ref CSteamID pSteamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection")] +internal static extern ulong SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SendUserDisconnect")] +internal static extern void SteamAPI_ISteamGameServer_SendUserDisconnect(IntPtr instancePtr, ulong steamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_BUpdateUserData")] +internal static extern bool SteamAPI_ISteamGameServer_BUpdateUserData(IntPtr instancePtr, ulong steamIDUser, string pchPlayerName, uint uScore); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_GetAuthSessionTicket")] +internal static extern uint SteamAPI_ISteamGameServer_GetAuthSessionTicket(IntPtr instancePtr, IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_BeginAuthSession")] +internal static extern uint SteamAPI_ISteamGameServer_BeginAuthSession(IntPtr instancePtr, IntPtr pAuthTicket, int cbAuthTicket, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_EndAuthSession")] +internal static extern void SteamAPI_ISteamGameServer_EndAuthSession(IntPtr instancePtr, ulong steamID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_CancelAuthTicket")] +internal static extern void SteamAPI_ISteamGameServer_CancelAuthTicket(IntPtr instancePtr, uint hAuthTicket); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_UserHasLicenseForApp")] +internal static extern uint SteamAPI_ISteamGameServer_UserHasLicenseForApp(IntPtr instancePtr, ulong steamID, uint appID); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_RequestUserGroupStatus")] +internal static extern bool SteamAPI_ISteamGameServer_RequestUserGroupStatus(IntPtr instancePtr, ulong steamIDUser, ulong steamIDGroup); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_GetGameplayStats")] +internal static extern void SteamAPI_ISteamGameServer_GetGameplayStats(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_GetServerReputation")] +internal static extern ulong SteamAPI_ISteamGameServer_GetServerReputation(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_GetPublicIP")] +internal static extern uint SteamAPI_ISteamGameServer_GetPublicIP(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_HandleIncomingPacket")] +internal static extern bool SteamAPI_ISteamGameServer_HandleIncomingPacket(IntPtr instancePtr, IntPtr pData, int cbData, uint srcIP, char srcPort); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_GetNextOutgoingPacket")] +internal static extern int SteamAPI_ISteamGameServer_GetNextOutgoingPacket(IntPtr instancePtr, IntPtr pOut, int cbMaxOut, ref uint pNetAdr, ref char pPort); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_EnableHeartbeats")] +internal static extern void SteamAPI_ISteamGameServer_EnableHeartbeats(IntPtr instancePtr, bool bActive); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_SetHeartbeatInterval")] +internal static extern void SteamAPI_ISteamGameServer_SetHeartbeatInterval(IntPtr instancePtr, int iHeartbeatInterval); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_ForceHeartbeat")] +internal static extern void SteamAPI_ISteamGameServer_ForceHeartbeat(IntPtr instancePtr); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_AssociateWithClan")] +internal static extern ulong SteamAPI_ISteamGameServer_AssociateWithClan(IntPtr instancePtr, ulong steamIDClan); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility")] +internal static extern ulong SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility(IntPtr instancePtr, ulong steamIDNewPlayer); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_RequestUserStats")] +internal static extern ulong SteamAPI_ISteamGameServerStats_RequestUserStats(IntPtr instancePtr, ulong steamIDUser); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_GetUserStat")] +internal static extern bool SteamAPI_ISteamGameServerStats_GetUserStat(IntPtr instancePtr, ulong steamIDUser, string pchName, ref int pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_GetUserStat0")] +internal static extern bool SteamAPI_ISteamGameServerStats_GetUserStat0(IntPtr instancePtr, ulong steamIDUser, string pchName, ref float pData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_GetUserAchievement")] +internal static extern bool SteamAPI_ISteamGameServerStats_GetUserAchievement(IntPtr instancePtr, ulong steamIDUser, string pchName, ref bool pbAchieved); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_SetUserStat")] +internal static extern bool SteamAPI_ISteamGameServerStats_SetUserStat(IntPtr instancePtr, ulong steamIDUser, string pchName, int nData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_SetUserStat0")] +internal static extern bool SteamAPI_ISteamGameServerStats_SetUserStat0(IntPtr instancePtr, ulong steamIDUser, string pchName, float fData); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat")] +internal static extern bool SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat(IntPtr instancePtr, ulong steamIDUser, string pchName, float flCountThisSession, double dSessionLength); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_SetUserAchievement")] +internal static extern bool SteamAPI_ISteamGameServerStats_SetUserAchievement(IntPtr instancePtr, ulong steamIDUser, string pchName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_ClearUserAchievement")] +internal static extern bool SteamAPI_ISteamGameServerStats_ClearUserAchievement(IntPtr instancePtr, ulong steamIDUser, string pchName); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_ISteamGameServerStats_StoreUserStats")] +internal static extern ulong SteamAPI_ISteamGameServerStats_StoreUserStats(IntPtr instancePtr, ulong steamIDUser); +public delegate void SteamAPI_UserStatsReceived_t_Callback(UserStatsReceived_t pUserStatsReceived_t); +[DllImportAttribute("Steam_api", EntryPoint = "CUserStatsReceived_t_SetCallback")] +public static extern ulong CUserStatsReceived_t_SetCallback(SteamAPI_UserStatsReceived_t_Callback func); +[DllImportAttribute("Steam_api", EntryPoint = "CUserStatsReceived_t_RemoveCallback")] +public static extern ulong CUserStatsReceived_t_RemoveCallback(ulong handle); +public delegate void SteamAPI_GetOPFSettingsResult_t_Callback(GetOPFSettingsResult_t pGetOPFSettingsResult_t); +[DllImportAttribute("Steam_api", EntryPoint = "CGetOPFSettingsResult_t_SetCallback")] +public static extern ulong CGetOPFSettingsResult_t_SetCallback(SteamAPI_GetOPFSettingsResult_t_Callback func); +[DllImportAttribute("Steam_api", EntryPoint = "CGetOPFSettingsResult_t_RemoveCallback")] +public static extern ulong CGetOPFSettingsResult_t_RemoveCallback(ulong handle); +public delegate void SteamAPI_SteamInventoryStartPurchaseResult_t_CallResult(SteamInventoryStartPurchaseResult_t pSteamInventoryStartPurchaseResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamInventoryStartPurchaseResult_t_SetCallResult")] +public static extern ulong CSteamInventoryStartPurchaseResult_t_SetCallResult(ulong hAPICall, SteamAPI_SteamInventoryStartPurchaseResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamInventoryStartPurchaseResult_t_RemoveCallResult")] +public static extern ulong CSteamInventoryStartPurchaseResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageFileReadAsyncComplete_t_CallResult(RemoteStorageFileReadAsyncComplete_t pRemoteStorageFileReadAsyncComplete_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageFileReadAsyncComplete_t_SetCallResult")] +public static extern ulong CRemoteStorageFileReadAsyncComplete_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageFileReadAsyncComplete_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageFileReadAsyncComplete_t_RemoveCallResult")] +public static extern ulong CRemoteStorageFileReadAsyncComplete_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageGetPublishedItemVoteDetailsResult_t_CallResult(RemoteStorageGetPublishedItemVoteDetailsResult_t pRemoteStorageGetPublishedItemVoteDetailsResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageGetPublishedItemVoteDetailsResult_t_SetCallResult")] +public static extern ulong CRemoteStorageGetPublishedItemVoteDetailsResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageGetPublishedItemVoteDetailsResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageGetPublishedItemVoteDetailsResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageGetPublishedItemVoteDetailsResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_FileDetailsResult_t_CallResult(FileDetailsResult_t pFileDetailsResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CFileDetailsResult_t_SetCallResult")] +public static extern ulong CFileDetailsResult_t_SetCallResult(ulong hAPICall, SteamAPI_FileDetailsResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CFileDetailsResult_t_RemoveCallResult")] +public static extern ulong CFileDetailsResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GSStatsStored_t_CallResult(GSStatsStored_t pGSStatsStored_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGSStatsStored_t_SetCallResult")] +public static extern ulong CGSStatsStored_t_SetCallResult(ulong hAPICall, SteamAPI_GSStatsStored_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGSStatsStored_t_RemoveCallResult")] +public static extern ulong CGSStatsStored_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_StartPlaytimeTrackingResult_t_CallResult(StartPlaytimeTrackingResult_t pStartPlaytimeTrackingResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CStartPlaytimeTrackingResult_t_SetCallResult")] +public static extern ulong CStartPlaytimeTrackingResult_t_SetCallResult(ulong hAPICall, SteamAPI_StartPlaytimeTrackingResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CStartPlaytimeTrackingResult_t_RemoveCallResult")] +public static extern ulong CStartPlaytimeTrackingResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_FriendsGetFollowerCount_t_CallResult(FriendsGetFollowerCount_t pFriendsGetFollowerCount_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CFriendsGetFollowerCount_t_SetCallResult")] +public static extern ulong CFriendsGetFollowerCount_t_SetCallResult(ulong hAPICall, SteamAPI_FriendsGetFollowerCount_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CFriendsGetFollowerCount_t_RemoveCallResult")] +public static extern ulong CFriendsGetFollowerCount_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_FriendsIsFollowing_t_CallResult(FriendsIsFollowing_t pFriendsIsFollowing_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CFriendsIsFollowing_t_SetCallResult")] +public static extern ulong CFriendsIsFollowing_t_SetCallResult(ulong hAPICall, SteamAPI_FriendsIsFollowing_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CFriendsIsFollowing_t_RemoveCallResult")] +public static extern ulong CFriendsIsFollowing_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LobbyMatchList_t_CallResult(LobbyMatchList_t pLobbyMatchList_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLobbyMatchList_t_SetCallResult")] +public static extern ulong CLobbyMatchList_t_SetCallResult(ulong hAPICall, SteamAPI_LobbyMatchList_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLobbyMatchList_t_RemoveCallResult")] +public static extern ulong CLobbyMatchList_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageUpdatePublishedFileResult_t_CallResult(RemoteStorageUpdatePublishedFileResult_t pRemoteStorageUpdatePublishedFileResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageUpdatePublishedFileResult_t_SetCallResult")] +public static extern ulong CRemoteStorageUpdatePublishedFileResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageUpdatePublishedFileResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageUpdatePublishedFileResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageUpdatePublishedFileResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_StoreAuthURLResponse_t_CallResult(StoreAuthURLResponse_t pStoreAuthURLResponse_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CStoreAuthURLResponse_t_SetCallResult")] +public static extern ulong CStoreAuthURLResponse_t_SetCallResult(ulong hAPICall, SteamAPI_StoreAuthURLResponse_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CStoreAuthURLResponse_t_RemoveCallResult")] +public static extern ulong CStoreAuthURLResponse_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LobbyCreated_t_CallResult(LobbyCreated_t pLobbyCreated_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLobbyCreated_t_SetCallResult")] +public static extern ulong CLobbyCreated_t_SetCallResult(ulong hAPICall, SteamAPI_LobbyCreated_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLobbyCreated_t_RemoveCallResult")] +public static extern ulong CLobbyCreated_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageFileWriteAsyncComplete_t_CallResult(RemoteStorageFileWriteAsyncComplete_t pRemoteStorageFileWriteAsyncComplete_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageFileWriteAsyncComplete_t_SetCallResult")] +public static extern ulong CRemoteStorageFileWriteAsyncComplete_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageFileWriteAsyncComplete_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageFileWriteAsyncComplete_t_RemoveCallResult")] +public static extern ulong CRemoteStorageFileWriteAsyncComplete_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageDeletePublishedFileResult_t_CallResult(RemoteStorageDeletePublishedFileResult_t pRemoteStorageDeletePublishedFileResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageDeletePublishedFileResult_t_SetCallResult")] +public static extern ulong CRemoteStorageDeletePublishedFileResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageDeletePublishedFileResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageDeletePublishedFileResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageDeletePublishedFileResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageGetPublishedFileDetailsResult_t_CallResult(RemoteStorageGetPublishedFileDetailsResult_t pRemoteStorageGetPublishedFileDetailsResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageGetPublishedFileDetailsResult_t_SetCallResult")] +public static extern ulong CRemoteStorageGetPublishedFileDetailsResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageGetPublishedFileDetailsResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageGetPublishedFileDetailsResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageGetPublishedFileDetailsResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_AddUGCDependencyResult_t_CallResult(AddUGCDependencyResult_t pAddUGCDependencyResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CAddUGCDependencyResult_t_SetCallResult")] +public static extern ulong CAddUGCDependencyResult_t_SetCallResult(ulong hAPICall, SteamAPI_AddUGCDependencyResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CAddUGCDependencyResult_t_RemoveCallResult")] +public static extern ulong CAddUGCDependencyResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageDownloadUGCResult_t_CallResult(RemoteStorageDownloadUGCResult_t pRemoteStorageDownloadUGCResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageDownloadUGCResult_t_SetCallResult")] +public static extern ulong CRemoteStorageDownloadUGCResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageDownloadUGCResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageDownloadUGCResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageDownloadUGCResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_SteamUGCQueryCompleted_t_CallResult(SteamUGCQueryCompleted_t pSteamUGCQueryCompleted_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamUGCQueryCompleted_t_SetCallResult")] +public static extern ulong CSteamUGCQueryCompleted_t_SetCallResult(ulong hAPICall, SteamAPI_SteamUGCQueryCompleted_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamUGCQueryCompleted_t_RemoveCallResult")] +public static extern ulong CSteamUGCQueryCompleted_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageFileShareResult_t_CallResult(RemoteStorageFileShareResult_t pRemoteStorageFileShareResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageFileShareResult_t_SetCallResult")] +public static extern ulong CRemoteStorageFileShareResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageFileShareResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageFileShareResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageFileShareResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LobbyEnter_t_CallResult(LobbyEnter_t pLobbyEnter_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLobbyEnter_t_SetCallResult")] +public static extern ulong CLobbyEnter_t_SetCallResult(ulong hAPICall, SteamAPI_LobbyEnter_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLobbyEnter_t_RemoveCallResult")] +public static extern ulong CLobbyEnter_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_SubmitItemUpdateResult_t_CallResult(SubmitItemUpdateResult_t pSubmitItemUpdateResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSubmitItemUpdateResult_t_SetCallResult")] +public static extern ulong CSubmitItemUpdateResult_t_SetCallResult(ulong hAPICall, SteamAPI_SubmitItemUpdateResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSubmitItemUpdateResult_t_RemoveCallResult")] +public static extern ulong CSubmitItemUpdateResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_NumberOfCurrentPlayers_t_CallResult(NumberOfCurrentPlayers_t pNumberOfCurrentPlayers_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CNumberOfCurrentPlayers_t_SetCallResult")] +public static extern ulong CNumberOfCurrentPlayers_t_SetCallResult(ulong hAPICall, SteamAPI_NumberOfCurrentPlayers_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CNumberOfCurrentPlayers_t_RemoveCallResult")] +public static extern ulong CNumberOfCurrentPlayers_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GSStatsReceived_t_CallResult(GSStatsReceived_t pGSStatsReceived_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGSStatsReceived_t_SetCallResult")] +public static extern ulong CGSStatsReceived_t_SetCallResult(ulong hAPICall, SteamAPI_GSStatsReceived_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGSStatsReceived_t_RemoveCallResult")] +public static extern ulong CGSStatsReceived_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_HTML_BrowserReady_t_CallResult(HTML_BrowserReady_t pHTML_BrowserReady_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CHTML_BrowserReady_t_SetCallResult")] +public static extern ulong CHTML_BrowserReady_t_SetCallResult(ulong hAPICall, SteamAPI_HTML_BrowserReady_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CHTML_BrowserReady_t_RemoveCallResult")] +public static extern ulong CHTML_BrowserReady_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_MarketEligibilityResponse_t_CallResult(MarketEligibilityResponse_t pMarketEligibilityResponse_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CMarketEligibilityResponse_t_SetCallResult")] +public static extern ulong CMarketEligibilityResponse_t_SetCallResult(ulong hAPICall, SteamAPI_MarketEligibilityResponse_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CMarketEligibilityResponse_t_RemoveCallResult")] +public static extern ulong CMarketEligibilityResponse_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LeaderboardScoresDownloaded_t_CallResult(LeaderboardScoresDownloaded_t pLeaderboardScoresDownloaded_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardScoresDownloaded_t_SetCallResult")] +public static extern ulong CLeaderboardScoresDownloaded_t_SetCallResult(ulong hAPICall, SteamAPI_LeaderboardScoresDownloaded_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardScoresDownloaded_t_RemoveCallResult")] +public static extern ulong CLeaderboardScoresDownloaded_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageUpdateUserPublishedItemVoteResult_t_CallResult(RemoteStorageUpdateUserPublishedItemVoteResult_t pRemoteStorageUpdateUserPublishedItemVoteResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageUpdateUserPublishedItemVoteResult_t_SetCallResult")] +public static extern ulong CRemoteStorageUpdateUserPublishedItemVoteResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageUpdateUserPublishedItemVoteResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageUpdateUserPublishedItemVoteResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageUpdateUserPublishedItemVoteResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_CreateBeaconCallback_t_CallResult(CreateBeaconCallback_t pCreateBeaconCallback_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CCreateBeaconCallback_t_SetCallResult")] +public static extern ulong CCreateBeaconCallback_t_SetCallResult(ulong hAPICall, SteamAPI_CreateBeaconCallback_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CCreateBeaconCallback_t_RemoveCallResult")] +public static extern ulong CCreateBeaconCallback_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_CreateItemResult_t_CallResult(CreateItemResult_t pCreateItemResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CCreateItemResult_t_SetCallResult")] +public static extern ulong CCreateItemResult_t_SetCallResult(ulong hAPICall, SteamAPI_CreateItemResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CCreateItemResult_t_RemoveCallResult")] +public static extern ulong CCreateItemResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_DeleteItemResult_t_CallResult(DeleteItemResult_t pDeleteItemResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CDeleteItemResult_t_SetCallResult")] +public static extern ulong CDeleteItemResult_t_SetCallResult(ulong hAPICall, SteamAPI_DeleteItemResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CDeleteItemResult_t_RemoveCallResult")] +public static extern ulong CDeleteItemResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_SetUserItemVoteResult_t_CallResult(SetUserItemVoteResult_t pSetUserItemVoteResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSetUserItemVoteResult_t_SetCallResult")] +public static extern ulong CSetUserItemVoteResult_t_SetCallResult(ulong hAPICall, SteamAPI_SetUserItemVoteResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSetUserItemVoteResult_t_RemoveCallResult")] +public static extern ulong CSetUserItemVoteResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_SteamInventoryRequestPricesResult_t_CallResult(SteamInventoryRequestPricesResult_t pSteamInventoryRequestPricesResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamInventoryRequestPricesResult_t_SetCallResult")] +public static extern ulong CSteamInventoryRequestPricesResult_t_SetCallResult(ulong hAPICall, SteamAPI_SteamInventoryRequestPricesResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamInventoryRequestPricesResult_t_RemoveCallResult")] +public static extern ulong CSteamInventoryRequestPricesResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_ComputeNewPlayerCompatibilityResult_t_CallResult(ComputeNewPlayerCompatibilityResult_t pComputeNewPlayerCompatibilityResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CComputeNewPlayerCompatibilityResult_t_SetCallResult")] +public static extern ulong CComputeNewPlayerCompatibilityResult_t_SetCallResult(ulong hAPICall, SteamAPI_ComputeNewPlayerCompatibilityResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CComputeNewPlayerCompatibilityResult_t_RemoveCallResult")] +public static extern ulong CComputeNewPlayerCompatibilityResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LeaderboardScoreUploaded_t_CallResult(LeaderboardScoreUploaded_t pLeaderboardScoreUploaded_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardScoreUploaded_t_SetCallResult")] +public static extern ulong CLeaderboardScoreUploaded_t_SetCallResult(ulong hAPICall, SteamAPI_LeaderboardScoreUploaded_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardScoreUploaded_t_RemoveCallResult")] +public static extern ulong CLeaderboardScoreUploaded_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_JoinPartyCallback_t_CallResult(JoinPartyCallback_t pJoinPartyCallback_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CJoinPartyCallback_t_SetCallResult")] +public static extern ulong CJoinPartyCallback_t_SetCallResult(ulong hAPICall, SteamAPI_JoinPartyCallback_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CJoinPartyCallback_t_RemoveCallResult")] +public static extern ulong CJoinPartyCallback_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageEnumerateUserSubscribedFilesResult_t_CallResult(RemoteStorageEnumerateUserSubscribedFilesResult_t pRemoteStorageEnumerateUserSubscribedFilesResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumerateUserSubscribedFilesResult_t_SetCallResult")] +public static extern ulong CRemoteStorageEnumerateUserSubscribedFilesResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageEnumerateUserSubscribedFilesResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumerateUserSubscribedFilesResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageEnumerateUserSubscribedFilesResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GlobalStatsReceived_t_CallResult(GlobalStatsReceived_t pGlobalStatsReceived_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGlobalStatsReceived_t_SetCallResult")] +public static extern ulong CGlobalStatsReceived_t_SetCallResult(ulong hAPICall, SteamAPI_GlobalStatsReceived_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGlobalStatsReceived_t_RemoveCallResult")] +public static extern ulong CGlobalStatsReceived_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageEnumeratePublishedFilesByUserActionResult_t_CallResult(RemoteStorageEnumeratePublishedFilesByUserActionResult_t pRemoteStorageEnumeratePublishedFilesByUserActionResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_SetCallResult")] +public static extern ulong CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageEnumeratePublishedFilesByUserActionResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_ClanOfficerListResponse_t_CallResult(ClanOfficerListResponse_t pClanOfficerListResponse_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CClanOfficerListResponse_t_SetCallResult")] +public static extern ulong CClanOfficerListResponse_t_SetCallResult(ulong hAPICall, SteamAPI_ClanOfficerListResponse_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CClanOfficerListResponse_t_RemoveCallResult")] +public static extern ulong CClanOfficerListResponse_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStoragePublishFileProgress_t_CallResult(RemoteStoragePublishFileProgress_t pRemoteStoragePublishFileProgress_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStoragePublishFileProgress_t_SetCallResult")] +public static extern ulong CRemoteStoragePublishFileProgress_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStoragePublishFileProgress_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStoragePublishFileProgress_t_RemoveCallResult")] +public static extern ulong CRemoteStoragePublishFileProgress_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageEnumerateWorkshopFilesResult_t_CallResult(RemoteStorageEnumerateWorkshopFilesResult_t pRemoteStorageEnumerateWorkshopFilesResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumerateWorkshopFilesResult_t_SetCallResult")] +public static extern ulong CRemoteStorageEnumerateWorkshopFilesResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageEnumerateWorkshopFilesResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumerateWorkshopFilesResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageEnumerateWorkshopFilesResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_DurationControl_t_CallResult(DurationControl_t pDurationControl_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CDurationControl_t_SetCallResult")] +public static extern ulong CDurationControl_t_SetCallResult(ulong hAPICall, SteamAPI_DurationControl_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CDurationControl_t_RemoveCallResult")] +public static extern ulong CDurationControl_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GSReputation_t_CallResult(GSReputation_t pGSReputation_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGSReputation_t_SetCallResult")] +public static extern ulong CGSReputation_t_SetCallResult(ulong hAPICall, SteamAPI_GSReputation_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGSReputation_t_RemoveCallResult")] +public static extern ulong CGSReputation_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GlobalAchievementPercentagesReady_t_CallResult(GlobalAchievementPercentagesReady_t pGlobalAchievementPercentagesReady_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGlobalAchievementPercentagesReady_t_SetCallResult")] +public static extern ulong CGlobalAchievementPercentagesReady_t_SetCallResult(ulong hAPICall, SteamAPI_GlobalAchievementPercentagesReady_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGlobalAchievementPercentagesReady_t_RemoveCallResult")] +public static extern ulong CGlobalAchievementPercentagesReady_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_UserFavoriteItemsListChanged_t_CallResult(UserFavoriteItemsListChanged_t pUserFavoriteItemsListChanged_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CUserFavoriteItemsListChanged_t_SetCallResult")] +public static extern ulong CUserFavoriteItemsListChanged_t_SetCallResult(ulong hAPICall, SteamAPI_UserFavoriteItemsListChanged_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CUserFavoriteItemsListChanged_t_RemoveCallResult")] +public static extern ulong CUserFavoriteItemsListChanged_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_AddAppDependencyResult_t_CallResult(AddAppDependencyResult_t pAddAppDependencyResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CAddAppDependencyResult_t_SetCallResult")] +public static extern ulong CAddAppDependencyResult_t_SetCallResult(ulong hAPICall, SteamAPI_AddAppDependencyResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CAddAppDependencyResult_t_RemoveCallResult")] +public static extern ulong CAddAppDependencyResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_EncryptedAppTicketResponse_t_CallResult(EncryptedAppTicketResponse_t pEncryptedAppTicketResponse_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CEncryptedAppTicketResponse_t_SetCallResult")] +public static extern ulong CEncryptedAppTicketResponse_t_SetCallResult(ulong hAPICall, SteamAPI_EncryptedAppTicketResponse_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CEncryptedAppTicketResponse_t_RemoveCallResult")] +public static extern ulong CEncryptedAppTicketResponse_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageSetUserPublishedFileActionResult_t_CallResult(RemoteStorageSetUserPublishedFileActionResult_t pRemoteStorageSetUserPublishedFileActionResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageSetUserPublishedFileActionResult_t_SetCallResult")] +public static extern ulong CRemoteStorageSetUserPublishedFileActionResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageSetUserPublishedFileActionResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageSetUserPublishedFileActionResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageSetUserPublishedFileActionResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_StopPlaytimeTrackingResult_t_CallResult(StopPlaytimeTrackingResult_t pStopPlaytimeTrackingResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CStopPlaytimeTrackingResult_t_SetCallResult")] +public static extern ulong CStopPlaytimeTrackingResult_t_SetCallResult(ulong hAPICall, SteamAPI_StopPlaytimeTrackingResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CStopPlaytimeTrackingResult_t_RemoveCallResult")] +public static extern ulong CStopPlaytimeTrackingResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageEnumerateUserPublishedFilesResult_t_CallResult(RemoteStorageEnumerateUserPublishedFilesResult_t pRemoteStorageEnumerateUserPublishedFilesResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumerateUserPublishedFilesResult_t_SetCallResult")] +public static extern ulong CRemoteStorageEnumerateUserPublishedFilesResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageEnumerateUserPublishedFilesResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageEnumerateUserPublishedFilesResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageEnumerateUserPublishedFilesResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_FriendsEnumerateFollowingList_t_CallResult(FriendsEnumerateFollowingList_t pFriendsEnumerateFollowingList_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CFriendsEnumerateFollowingList_t_SetCallResult")] +public static extern ulong CFriendsEnumerateFollowingList_t_SetCallResult(ulong hAPICall, SteamAPI_FriendsEnumerateFollowingList_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CFriendsEnumerateFollowingList_t_RemoveCallResult")] +public static extern ulong CFriendsEnumerateFollowingList_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_ChangeNumOpenSlotsCallback_t_CallResult(ChangeNumOpenSlotsCallback_t pChangeNumOpenSlotsCallback_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CChangeNumOpenSlotsCallback_t_SetCallResult")] +public static extern ulong CChangeNumOpenSlotsCallback_t_SetCallResult(ulong hAPICall, SteamAPI_ChangeNumOpenSlotsCallback_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CChangeNumOpenSlotsCallback_t_RemoveCallResult")] +public static extern ulong CChangeNumOpenSlotsCallback_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageSubscribePublishedFileResult_t_CallResult(RemoteStorageSubscribePublishedFileResult_t pRemoteStorageSubscribePublishedFileResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageSubscribePublishedFileResult_t_SetCallResult")] +public static extern ulong CRemoteStorageSubscribePublishedFileResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageSubscribePublishedFileResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageSubscribePublishedFileResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageSubscribePublishedFileResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GetUserItemVoteResult_t_CallResult(GetUserItemVoteResult_t pGetUserItemVoteResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGetUserItemVoteResult_t_SetCallResult")] +public static extern ulong CGetUserItemVoteResult_t_SetCallResult(ulong hAPICall, SteamAPI_GetUserItemVoteResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGetUserItemVoteResult_t_RemoveCallResult")] +public static extern ulong CGetUserItemVoteResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_AssociateWithClanResult_t_CallResult(AssociateWithClanResult_t pAssociateWithClanResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CAssociateWithClanResult_t_SetCallResult")] +public static extern ulong CAssociateWithClanResult_t_SetCallResult(ulong hAPICall, SteamAPI_AssociateWithClanResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CAssociateWithClanResult_t_RemoveCallResult")] +public static extern ulong CAssociateWithClanResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LeaderboardUGCSet_t_CallResult(LeaderboardUGCSet_t pLeaderboardUGCSet_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardUGCSet_t_SetCallResult")] +public static extern ulong CLeaderboardUGCSet_t_SetCallResult(ulong hAPICall, SteamAPI_LeaderboardUGCSet_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardUGCSet_t_RemoveCallResult")] +public static extern ulong CLeaderboardUGCSet_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_CheckFileSignature_t_CallResult(CheckFileSignature_t pCheckFileSignature_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CCheckFileSignature_t_SetCallResult")] +public static extern ulong CCheckFileSignature_t_SetCallResult(ulong hAPICall, SteamAPI_CheckFileSignature_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CCheckFileSignature_t_RemoveCallResult")] +public static extern ulong CCheckFileSignature_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_GetAppDependenciesResult_t_CallResult(GetAppDependenciesResult_t pGetAppDependenciesResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CGetAppDependenciesResult_t_SetCallResult")] +public static extern ulong CGetAppDependenciesResult_t_SetCallResult(ulong hAPICall, SteamAPI_GetAppDependenciesResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CGetAppDependenciesResult_t_RemoveCallResult")] +public static extern ulong CGetAppDependenciesResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoteStorageUnsubscribePublishedFileResult_t_CallResult(RemoteStorageUnsubscribePublishedFileResult_t pRemoteStorageUnsubscribePublishedFileResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageUnsubscribePublishedFileResult_t_SetCallResult")] +public static extern ulong CRemoteStorageUnsubscribePublishedFileResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoteStorageUnsubscribePublishedFileResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoteStorageUnsubscribePublishedFileResult_t_RemoveCallResult")] +public static extern ulong CRemoteStorageUnsubscribePublishedFileResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_SetPersonaNameResponse_t_CallResult(SetPersonaNameResponse_t pSetPersonaNameResponse_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSetPersonaNameResponse_t_SetCallResult")] +public static extern ulong CSetPersonaNameResponse_t_SetCallResult(ulong hAPICall, SteamAPI_SetPersonaNameResponse_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSetPersonaNameResponse_t_RemoveCallResult")] +public static extern ulong CSetPersonaNameResponse_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoveAppDependencyResult_t_CallResult(RemoveAppDependencyResult_t pRemoveAppDependencyResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoveAppDependencyResult_t_SetCallResult")] +public static extern ulong CRemoveAppDependencyResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoveAppDependencyResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoveAppDependencyResult_t_RemoveCallResult")] +public static extern ulong CRemoveAppDependencyResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_UserStatsReceived_t_CallResult(UserStatsReceived_t pUserStatsReceived_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CUserStatsReceived_t_SetCallResult")] +public static extern ulong CUserStatsReceived_t_SetCallResult(ulong hAPICall, SteamAPI_UserStatsReceived_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CUserStatsReceived_t_RemoveCallResult")] +public static extern ulong CUserStatsReceived_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_SteamInventoryEligiblePromoItemDefIDs_t_CallResult(SteamInventoryEligiblePromoItemDefIDs_t pSteamInventoryEligiblePromoItemDefIDs_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamInventoryEligiblePromoItemDefIDs_t_SetCallResult")] +public static extern ulong CSteamInventoryEligiblePromoItemDefIDs_t_SetCallResult(ulong hAPICall, SteamAPI_SteamInventoryEligiblePromoItemDefIDs_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CSteamInventoryEligiblePromoItemDefIDs_t_RemoveCallResult")] +public static extern ulong CSteamInventoryEligiblePromoItemDefIDs_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_RemoveUGCDependencyResult_t_CallResult(RemoveUGCDependencyResult_t pRemoveUGCDependencyResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoveUGCDependencyResult_t_SetCallResult")] +public static extern ulong CRemoveUGCDependencyResult_t_SetCallResult(ulong hAPICall, SteamAPI_RemoveUGCDependencyResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CRemoveUGCDependencyResult_t_RemoveCallResult")] +public static extern ulong CRemoveUGCDependencyResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_JoinClanChatRoomCompletionResult_t_CallResult(JoinClanChatRoomCompletionResult_t pJoinClanChatRoomCompletionResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CJoinClanChatRoomCompletionResult_t_SetCallResult")] +public static extern ulong CJoinClanChatRoomCompletionResult_t_SetCallResult(ulong hAPICall, SteamAPI_JoinClanChatRoomCompletionResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CJoinClanChatRoomCompletionResult_t_RemoveCallResult")] +public static extern ulong CJoinClanChatRoomCompletionResult_t_RemoveCallResult(ulong handle); +public delegate void SteamAPI_LeaderboardFindResult_t_CallResult(LeaderboardFindResult_t pLeaderboardFindResult_t, bool bIOFailure); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardFindResult_t_SetCallResult")] +public static extern ulong CLeaderboardFindResult_t_SetCallResult(ulong hAPICall, SteamAPI_LeaderboardFindResult_t_CallResult func); +[DllImportAttribute("Steam_api", EntryPoint = "CLeaderboardFindResult_t_RemoveCallResult")] +public static extern ulong CLeaderboardFindResult_t_RemoveCallResult(ulong handle); + +} + +} + +namespace Valve.Steamworks +{ + + public abstract class ISteamClient + { + public abstract IntPtr GetIntPtr(); + public abstract uint CreateSteamPipe(); + public abstract bool BReleaseSteamPipe(uint hSteamPipe); + public abstract uint ConnectToGlobalUser(uint hSteamPipe); + public abstract uint CreateLocalUser(ref uint phSteamPipe,uint eAccountType); + public abstract void ReleaseUser(uint hSteamPipe,uint hUser); + public abstract ISteamUser GetISteamUser(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamGameServer GetISteamGameServer(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract void SetLocalIPBinding(uint unIP,char usPort); + public abstract ISteamFriends GetISteamFriends(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamUtils GetISteamUtils(uint hSteamPipe,string pchVersion); + public abstract ISteamMatchmaking GetISteamMatchmaking(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamMatchmakingServers GetISteamMatchmakingServers(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract IntPtr GetISteamGenericInterface(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamUserStats GetISteamUserStats(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamGameServerStats GetISteamGameServerStats(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamApps GetISteamApps(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamNetworking GetISteamNetworking(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamRemoteStorage GetISteamRemoteStorage(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamScreenshots GetISteamScreenshots(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamGameSearch GetISteamGameSearch(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract uint GetIPCCallCount(); + public abstract void SetWarningMessageHook(IntPtr pFunction); + public abstract bool BShutdownIfAllPipesClosed(); + public abstract ISteamHTTP GetISteamHTTP(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamController GetISteamController(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamUGC GetISteamUGC(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamAppList GetISteamAppList(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamMusic GetISteamMusic(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamMusicRemote GetISteamMusicRemote(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamHTMLSurface GetISteamHTMLSurface(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamInventory GetISteamInventory(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamVideo GetISteamVideo(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamParentalSettings GetISteamParentalSettings(uint hSteamuser,uint hSteamPipe,string pchVersion); + public abstract ISteamInput GetISteamInput(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamParties GetISteamParties(uint hSteamUser,uint hSteamPipe,string pchVersion); + public abstract ISteamRemotePlay GetISteamRemotePlay(uint hSteamUser,uint hSteamPipe,string pchVersion); + } + + + public abstract class ISteamUser + { + public abstract IntPtr GetIntPtr(); + public abstract uint GetHSteamUser(); + public abstract bool BLoggedOn(); + public abstract ulong GetSteamID(); + public abstract int InitiateGameConnection(IntPtr pAuthBlob,int cbMaxAuthBlob,ulong steamIDGameServer,uint unIPServer,char usPortServer,bool bSecure); + public abstract void TerminateGameConnection(uint unIPServer,char usPortServer); + public abstract void TrackAppUsageEvent(ulong gameID,int eAppUsageEvent,string pchExtraInfo); + public abstract bool GetUserDataFolder(string pchBuffer,int cubBuffer); + public abstract void StartVoiceRecording(); + public abstract void StopVoiceRecording(); + public abstract uint GetAvailableVoice(ref uint pcbCompressed,ref uint pcbUncompressed_Deprecated,uint nUncompressedVoiceDesiredSampleRate_Deprecated); + public abstract uint GetVoice(bool bWantCompressed,IntPtr pDestBuffer,uint cbDestBufferSize,ref uint nBytesWritten,bool bWantUncompressed_Deprecated,IntPtr pUncompressedDestBuffer_Deprecated,uint cbUncompressedDestBufferSize_Deprecated,ref uint nUncompressBytesWritten_Deprecated,uint nUncompressedVoiceDesiredSampleRate_Deprecated); + public abstract uint DecompressVoice(IntPtr pCompressed,uint cbCompressed,IntPtr pDestBuffer,uint cbDestBufferSize,ref uint nBytesWritten,uint nDesiredSampleRate); + public abstract uint GetVoiceOptimalSampleRate(); + public abstract uint GetAuthSessionTicket(IntPtr pTicket,int cbMaxTicket,ref uint pcbTicket); + public abstract uint BeginAuthSession(IntPtr pAuthTicket,int cbAuthTicket,ulong steamID); + public abstract void EndAuthSession(ulong steamID); + public abstract void CancelAuthTicket(uint hAuthTicket); + public abstract uint UserHasLicenseForApp(ulong steamID,uint appID); + public abstract bool BIsBehindNAT(); + public abstract void AdvertiseGame(ulong steamIDGameServer,uint unIPServer,char usPortServer); + public abstract ulong RequestEncryptedAppTicket(IntPtr pDataToInclude,int cbDataToInclude); + public abstract bool GetEncryptedAppTicket(IntPtr pTicket,int cbMaxTicket,ref uint pcbTicket); + public abstract int GetGameBadgeLevel(int nSeries,bool bFoil); + public abstract int GetPlayerSteamLevel(); + public abstract ulong RequestStoreAuthURL(string pchRedirectURL); + public abstract bool BIsPhoneVerified(); + public abstract bool BIsTwoFactorEnabled(); + public abstract bool BIsPhoneIdentifying(); + public abstract bool BIsPhoneRequiringVerification(); + public abstract ulong GetMarketEligibility(); + public abstract ulong GetDurationControl(); + } + + + public abstract class ISteamFriends + { + public abstract IntPtr GetIntPtr(); + public abstract string GetPersonaName(); + public abstract ulong SetPersonaName(string pchPersonaName); + public abstract uint GetPersonaState(); + public abstract int GetFriendCount(int iFriendFlags); + public abstract ulong GetFriendByIndex(int iFriend,int iFriendFlags); + public abstract uint GetFriendRelationship(ulong steamIDFriend); + public abstract uint GetFriendPersonaState(ulong steamIDFriend); + public abstract string GetFriendPersonaName(ulong steamIDFriend); + public abstract bool GetFriendGamePlayed(ulong steamIDFriend,out FriendGameInfo_t pFriendGameInfo); + public abstract string GetFriendPersonaNameHistory(ulong steamIDFriend,int iPersonaName); + public abstract int GetFriendSteamLevel(ulong steamIDFriend); + public abstract string GetPlayerNickname(ulong steamIDPlayer); + public abstract int GetFriendsGroupCount(); + public abstract char GetFriendsGroupIDByIndex(int iFG); + public abstract string GetFriendsGroupName(char friendsGroupID); + public abstract int GetFriendsGroupMembersCount(char friendsGroupID); + public abstract void GetFriendsGroupMembersList(char friendsGroupID,out CSteamID [] pOutSteamIDMembers); + public abstract bool HasFriend(ulong steamIDFriend,int iFriendFlags); + public abstract int GetClanCount(); + public abstract ulong GetClanByIndex(int iClan); + public abstract string GetClanName(ulong steamIDClan); + public abstract string GetClanTag(ulong steamIDClan); + public abstract bool GetClanActivityCounts(ulong steamIDClan,ref int pnOnline,ref int pnInGame,ref int pnChatting); + public abstract ulong DownloadClanActivityCounts(CSteamID [] psteamIDClans); + public abstract int GetFriendCountFromSource(ulong steamIDSource); + public abstract ulong GetFriendFromSourceByIndex(ulong steamIDSource,int iFriend); + public abstract bool IsUserInSource(ulong steamIDUser,ulong steamIDSource); + public abstract void SetInGameVoiceSpeaking(ulong steamIDUser,bool bSpeaking); + public abstract void ActivateGameOverlay(string pchDialog); + public abstract void ActivateGameOverlayToUser(string pchDialog,ulong steamID); + public abstract void ActivateGameOverlayToWebPage(string pchURL,uint eMode); + public abstract void ActivateGameOverlayToStore(uint nAppID,char eFlag); + public abstract void SetPlayedWith(ulong steamIDUserPlayedWith); + public abstract void ActivateGameOverlayInviteDialog(ulong steamIDLobby); + public abstract int GetSmallFriendAvatar(ulong steamIDFriend); + public abstract int GetMediumFriendAvatar(ulong steamIDFriend); + public abstract int GetLargeFriendAvatar(ulong steamIDFriend); + public abstract bool RequestUserInformation(ulong steamIDUser,bool bRequireNameOnly); + public abstract ulong RequestClanOfficerList(ulong steamIDClan); + public abstract ulong GetClanOwner(ulong steamIDClan); + public abstract int GetClanOfficerCount(ulong steamIDClan); + public abstract ulong GetClanOfficerByIndex(ulong steamIDClan,int iOfficer); + public abstract uint GetUserRestrictions(); + public abstract bool SetRichPresence(string pchKey,string pchValue); + public abstract void ClearRichPresence(); + public abstract string GetFriendRichPresence(ulong steamIDFriend,string pchKey); + public abstract int GetFriendRichPresenceKeyCount(ulong steamIDFriend); + public abstract string GetFriendRichPresenceKeyByIndex(ulong steamIDFriend,int iKey); + public abstract void RequestFriendRichPresence(ulong steamIDFriend); + public abstract bool InviteUserToGame(ulong steamIDFriend,string pchConnectString); + public abstract int GetCoplayFriendCount(); + public abstract ulong GetCoplayFriend(int iCoplayFriend); + public abstract int GetFriendCoplayTime(ulong steamIDFriend); + public abstract uint GetFriendCoplayGame(ulong steamIDFriend); + public abstract ulong JoinClanChatRoom(ulong steamIDClan); + public abstract bool LeaveClanChatRoom(ulong steamIDClan); + public abstract int GetClanChatMemberCount(ulong steamIDClan); + public abstract ulong GetChatMemberByIndex(ulong steamIDClan,int iUser); + public abstract bool SendClanChatMessage(ulong steamIDClanChat,string pchText); + public abstract int GetClanChatMessage(ulong steamIDClanChat,int iMessage,IntPtr prgchText,int cchTextMax,ref uint peChatEntryType,out CSteamID psteamidChatter); + public abstract bool IsClanChatAdmin(ulong steamIDClanChat,ulong steamIDUser); + public abstract bool IsClanChatWindowOpenInSteam(ulong steamIDClanChat); + public abstract bool OpenClanChatWindowInSteam(ulong steamIDClanChat); + public abstract bool CloseClanChatWindowInSteam(ulong steamIDClanChat); + public abstract bool SetListenForFriendsMessages(bool bInterceptEnabled); + public abstract bool ReplyToFriendMessage(ulong steamIDFriend,string pchMsgToSend); + public abstract int GetFriendMessage(ulong steamIDFriend,int iMessageID,IntPtr pvData,int cubData,ref uint peChatEntryType); + public abstract ulong GetFollowerCount(ulong steamID); + public abstract ulong IsFollowing(ulong steamID); + public abstract ulong EnumerateFollowingList(uint unStartIndex); + public abstract bool IsClanPublic(ulong steamIDClan); + public abstract bool IsClanOfficialGameGroup(ulong steamIDClan); + public abstract int GetNumChatsWithUnreadPriorityMessages(); + } + + + public abstract class ISteamUtils + { + public abstract IntPtr GetIntPtr(); + public abstract uint GetSecondsSinceAppActive(); + public abstract uint GetSecondsSinceComputerActive(); + public abstract int GetConnectedUniverse(); + public abstract uint GetServerRealTime(); + public abstract string GetIPCountry(); + public abstract bool GetImageSize(int iImage,ref uint pnWidth,ref uint pnHeight); + public abstract bool GetImageRGBA(int iImage,IntPtr pubDest,int nDestBufferSize); + public abstract bool GetCSERIPPort(ref uint unIP,ref char usPort); + public abstract byte GetCurrentBatteryPower(); + public abstract uint GetAppID(); + public abstract void SetOverlayNotificationPosition(uint eNotificationPosition); + public abstract bool IsAPICallCompleted(ulong hSteamAPICall,ref bool pbFailed); + public abstract int GetAPICallFailureReason(ulong hSteamAPICall); + public abstract bool GetAPICallResult(ulong hSteamAPICall,IntPtr pCallback,int cubCallback,int iCallbackExpected,ref bool pbFailed); + public abstract uint GetIPCCallCount(); + public abstract void SetWarningMessageHook(IntPtr pFunction); + public abstract bool IsOverlayEnabled(); + public abstract bool BOverlayNeedsPresent(); + public abstract ulong CheckFileSignature(string szFileName); + public abstract bool ShowGamepadTextInput(int eInputMode,int eLineInputMode,string pchDescription,uint unCharMax,string pchExistingText); + public abstract uint GetEnteredGamepadTextLength(); + public abstract bool GetEnteredGamepadTextInput(string pchText,uint cchText); + public abstract string GetSteamUILanguage(); + public abstract bool IsSteamRunningInVR(); + public abstract void SetOverlayNotificationInset(int nHorizontalInset,int nVerticalInset); + public abstract bool IsSteamInBigPictureMode(); + public abstract void StartVRDashboard(); + public abstract bool IsVRHeadsetStreamingEnabled(); + public abstract void SetVRHeadsetStreamingEnabled(bool bEnabled); + public abstract bool IsSteamChinaLauncher(); + public abstract bool InitFilterText(); + public abstract int FilterText(string pchOutFilteredText,uint nByteSizeOutFilteredText,string pchInputMessage,bool bLegalOnly); + } + + + public abstract class ISteamMatchmaking + { + public abstract IntPtr GetIntPtr(); + public abstract int GetFavoriteGameCount(); + public abstract bool GetFavoriteGame(int iGame,ref uint pnAppID,ref uint pnIP,ref char pnConnPort,ref char pnQueryPort,ref uint punFlags,ref uint pRTime32LastPlayedOnServer); + public abstract int AddFavoriteGame(uint nAppID,uint nIP,char nConnPort,char nQueryPort,uint unFlags,uint rTime32LastPlayedOnServer); + public abstract bool RemoveFavoriteGame(uint nAppID,uint nIP,char nConnPort,char nQueryPort,uint unFlags); + public abstract ulong RequestLobbyList(); + public abstract void AddRequestLobbyListStringFilter(string pchKeyToMatch,string pchValueToMatch,uint eComparisonType); + public abstract void AddRequestLobbyListNumericalFilter(string pchKeyToMatch,int nValueToMatch,uint eComparisonType); + public abstract void AddRequestLobbyListNearValueFilter(string pchKeyToMatch,int nValueToBeCloseTo); + public abstract void AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable); + public abstract void AddRequestLobbyListDistanceFilter(uint eLobbyDistanceFilter); + public abstract void AddRequestLobbyListResultCountFilter(int cMaxResults); + public abstract void AddRequestLobbyListCompatibleMembersFilter(ulong steamIDLobby); + public abstract ulong GetLobbyByIndex(int iLobby); + public abstract ulong CreateLobby(uint eLobbyType,int cMaxMembers); + public abstract ulong JoinLobby(ulong steamIDLobby); + public abstract void LeaveLobby(ulong steamIDLobby); + public abstract bool InviteUserToLobby(ulong steamIDLobby,ulong steamIDInvitee); + public abstract int GetNumLobbyMembers(ulong steamIDLobby); + public abstract ulong GetLobbyMemberByIndex(ulong steamIDLobby,int iMember); + public abstract string GetLobbyData(ulong steamIDLobby,string pchKey); + public abstract bool SetLobbyData(ulong steamIDLobby,string pchKey,string pchValue); + public abstract int GetLobbyDataCount(ulong steamIDLobby); + public abstract bool GetLobbyDataByIndex(ulong steamIDLobby,int iLobbyData,string pchKey,int cchKeyBufferSize,string pchValue,int cchValueBufferSize); + public abstract bool DeleteLobbyData(ulong steamIDLobby,string pchKey); + public abstract string GetLobbyMemberData(ulong steamIDLobby,ulong steamIDUser,string pchKey); + public abstract void SetLobbyMemberData(ulong steamIDLobby,string pchKey,string pchValue); + public abstract bool SendLobbyChatMsg(ulong steamIDLobby,IntPtr pvMsgBody,int cubMsgBody); + public abstract int GetLobbyChatEntry(ulong steamIDLobby,int iChatID,out CSteamID pSteamIDUser,IntPtr pvData,int cubData,ref uint peChatEntryType); + public abstract bool RequestLobbyData(ulong steamIDLobby); + public abstract void SetLobbyGameServer(ulong steamIDLobby,uint unGameServerIP,char unGameServerPort,ulong steamIDGameServer); + public abstract bool GetLobbyGameServer(ulong steamIDLobby,ref uint punGameServerIP,ref char punGameServerPort,out CSteamID psteamIDGameServer); + public abstract bool SetLobbyMemberLimit(ulong steamIDLobby,int cMaxMembers); + public abstract int GetLobbyMemberLimit(ulong steamIDLobby); + public abstract bool SetLobbyType(ulong steamIDLobby,uint eLobbyType); + public abstract bool SetLobbyJoinable(ulong steamIDLobby,bool bLobbyJoinable); + public abstract ulong GetLobbyOwner(ulong steamIDLobby); + public abstract bool SetLobbyOwner(ulong steamIDLobby,ulong steamIDNewOwner); + public abstract bool SetLinkedLobby(ulong steamIDLobby,ulong steamIDLobbyDependent); + } + + + public abstract class ISteamMatchmakingServerListResponse + { + public abstract IntPtr GetIntPtr(); + public abstract void ServerResponded(uint hRequest,int iServer); + public abstract void ServerFailedToRespond(uint hRequest,int iServer); + public abstract void RefreshComplete(uint hRequest,uint response); + } + + + public abstract class ISteamMatchmakingPingResponse + { + public abstract IntPtr GetIntPtr(); + public abstract void ServerResponded(IntPtr server); + public abstract void ServerFailedToRespond(); + } + + + public abstract class ISteamMatchmakingPlayersResponse + { + public abstract IntPtr GetIntPtr(); + public abstract void AddPlayerToList(string pchName,int nScore,float flTimePlayed); + public abstract void PlayersFailedToRespond(); + public abstract void PlayersRefreshComplete(); + } + + + public abstract class ISteamMatchmakingRulesResponse + { + public abstract IntPtr GetIntPtr(); + public abstract void RulesResponded(string pchRule,string pchValue); + public abstract void RulesFailedToRespond(); + public abstract void RulesRefreshComplete(); + } + + + public abstract class ISteamMatchmakingServers + { + public abstract IntPtr GetIntPtr(); + public abstract uint RequestInternetServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse); + public abstract uint RequestLANServerList(uint iApp,ISteamMatchmakingServerListResponse pRequestServersResponse); + public abstract uint RequestFriendsServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse); + public abstract uint RequestFavoritesServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse); + public abstract uint RequestHistoryServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse); + public abstract uint RequestSpectatorServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse); + public abstract void ReleaseRequest(uint hServerListRequest); + public abstract gameserveritem_t GetServerDetails(uint hRequest,int iServer); + public abstract void CancelQuery(uint hRequest); + public abstract void RefreshQuery(uint hRequest); + public abstract bool IsRefreshing(uint hRequest); + public abstract int GetServerCount(uint hRequest); + public abstract void RefreshServer(uint hRequest,int iServer); + public abstract uint PingServer(uint unIP,char usPort,ISteamMatchmakingPingResponse pRequestServersResponse); + public abstract uint PlayerDetails(uint unIP,char usPort,ISteamMatchmakingPlayersResponse pRequestServersResponse); + public abstract uint ServerRules(uint unIP,char usPort,ISteamMatchmakingRulesResponse pRequestServersResponse); + public abstract void CancelServerQuery(uint hServerQuery); + } + + + public abstract class ISteamGameSearch + { + public abstract IntPtr GetIntPtr(); + public abstract uint AddGameSearchParams(string pchKeyToFind,string pchValuesToFind); + public abstract uint SearchForGameWithLobby(ulong steamIDLobby,int nPlayerMin,int nPlayerMax); + public abstract uint SearchForGameSolo(int nPlayerMin,int nPlayerMax); + public abstract uint AcceptGame(); + public abstract uint DeclineGame(); + public abstract uint RetrieveConnectionDetails(ulong steamIDHost,string pchConnectionDetails,int cubConnectionDetails); + public abstract uint EndGameSearch(); + public abstract uint SetGameHostParams(string pchKey,string pchValue); + public abstract uint SetConnectionDetails(string pchConnectionDetails,int cubConnectionDetails); + public abstract uint RequestPlayersForGame(int nPlayerMin,int nPlayerMax,int nMaxTeamSize); + public abstract uint HostConfirmGameStart(ulong ullUniqueGameID); + public abstract uint CancelRequestPlayersForGame(); + public abstract uint SubmitPlayerResult(ulong ullUniqueGameID,ulong steamIDPlayer,uint EPlayerResult); + public abstract uint EndGame(ulong ullUniqueGameID); + } + + + public abstract class ISteamParties + { + public abstract IntPtr GetIntPtr(); + public abstract uint GetNumActiveBeacons(); + public abstract ulong GetBeaconByIndex(uint unIndex); + public abstract bool GetBeaconDetails(ulong ulBeaconID,ref CSteamID pSteamIDBeaconOwner,out SteamPartyBeaconLocation_t pLocation,out string pchMetadata); + public abstract ulong JoinParty(ulong ulBeaconID); + public abstract bool GetNumAvailableBeaconLocations(ref uint puNumLocations); + public abstract bool GetAvailableBeaconLocations(ref SteamPartyBeaconLocation_t pLocationList,uint uMaxNumLocations); + public abstract ulong CreateBeacon(uint unOpenSlots,ref SteamPartyBeaconLocation_t pBeaconLocation,string pchConnectString,string pchMetadata); + public abstract void OnReservationCompleted(ulong ulBeacon,ulong steamIDUser); + public abstract void CancelReservation(ulong ulBeacon,ulong steamIDUser); + public abstract ulong ChangeNumOpenSlots(ulong ulBeacon,uint unOpenSlots); + public abstract bool DestroyBeacon(ulong ulBeacon); + public abstract bool GetBeaconLocationData(SteamPartyBeaconLocation_t BeaconLocation,uint eData,out string pchDataStringOut); + } + + + public abstract class ISteamRemoteStorage + { + public abstract IntPtr GetIntPtr(); + public abstract bool FileWrite(string pchFile,IntPtr pvData,int cubData); + public abstract int FileRead(string pchFile,IntPtr pvData,int cubDataToRead); + public abstract ulong FileWriteAsync(string pchFile,IntPtr pvData,uint cubData); + public abstract ulong FileReadAsync(string pchFile,uint nOffset,uint cubToRead); + public abstract bool FileReadAsyncComplete(ulong hReadCall,IntPtr pvBuffer,uint cubToRead); + public abstract bool FileForget(string pchFile); + public abstract bool FileDelete(string pchFile); + public abstract ulong FileShare(string pchFile); + public abstract bool SetSyncPlatforms(string pchFile,uint eRemoteStoragePlatform); + public abstract ulong FileWriteStreamOpen(string pchFile); + public abstract bool FileWriteStreamWriteChunk(ulong writeHandle,IntPtr pvData,int cubData); + public abstract bool FileWriteStreamClose(ulong writeHandle); + public abstract bool FileWriteStreamCancel(ulong writeHandle); + public abstract bool FileExists(string pchFile); + public abstract bool FilePersisted(string pchFile); + public abstract int GetFileSize(string pchFile); + public abstract long GetFileTimestamp(string pchFile); + public abstract uint GetSyncPlatforms(string pchFile); + public abstract int GetFileCount(); + public abstract string GetFileNameAndSize(int iFile,ref int pnFileSizeInBytes); + public abstract bool GetQuota(ref ulong pnTotalBytes,ref ulong puAvailableBytes); + public abstract bool IsCloudEnabledForAccount(); + public abstract bool IsCloudEnabledForApp(); + public abstract void SetCloudEnabledForApp(bool bEnabled); + public abstract ulong UGCDownload(ulong hContent,uint unPriority); + public abstract bool GetUGCDownloadProgress(ulong hContent,ref int pnBytesDownloaded,ref int pnBytesExpected); + public abstract bool GetUGCDetails(ulong hContent,ref uint pnAppID,System.Text.StringBuilder ppchName,ref int pnFileSizeInBytes,out CSteamID pSteamIDOwner); + public abstract int UGCRead(ulong hContent,IntPtr pvData,int cubDataToRead,uint cOffset,uint eAction); + public abstract int GetCachedUGCCount(); + public abstract ulong GetCachedUGCHandle(int iCachedContent); + public abstract ulong PublishWorkshopFile(string pchFile,string pchPreviewFile,uint nConsumerAppId,string pchTitle,string pchDescription,uint eVisibility,ref SteamParamStringArray_t pTags,uint eWorkshopFileType); + public abstract ulong CreatePublishedFileUpdateRequest(ulong unPublishedFileId); + public abstract bool UpdatePublishedFileFile(ulong updateHandle,string pchFile); + public abstract bool UpdatePublishedFilePreviewFile(ulong updateHandle,string pchPreviewFile); + public abstract bool UpdatePublishedFileTitle(ulong updateHandle,string pchTitle); + public abstract bool UpdatePublishedFileDescription(ulong updateHandle,string pchDescription); + public abstract bool UpdatePublishedFileVisibility(ulong updateHandle,uint eVisibility); + public abstract bool UpdatePublishedFileTags(ulong updateHandle,ref SteamParamStringArray_t pTags); + public abstract ulong CommitPublishedFileUpdate(ulong updateHandle); + public abstract ulong GetPublishedFileDetails(ulong unPublishedFileId,uint unMaxSecondsOld); + public abstract ulong DeletePublishedFile(ulong unPublishedFileId); + public abstract ulong EnumerateUserPublishedFiles(uint unStartIndex); + public abstract ulong SubscribePublishedFile(ulong unPublishedFileId); + public abstract ulong EnumerateUserSubscribedFiles(uint unStartIndex); + public abstract ulong UnsubscribePublishedFile(ulong unPublishedFileId); + public abstract bool UpdatePublishedFileSetChangeDescription(ulong updateHandle,string pchChangeDescription); + public abstract ulong GetPublishedItemVoteDetails(ulong unPublishedFileId); + public abstract ulong UpdateUserPublishedItemVote(ulong unPublishedFileId,bool bVoteUp); + public abstract ulong GetUserPublishedItemVoteDetails(ulong unPublishedFileId); + public abstract ulong EnumerateUserSharedWorkshopFiles(ulong steamId,uint unStartIndex,ref SteamParamStringArray_t pRequiredTags,ref SteamParamStringArray_t pExcludedTags); + public abstract ulong PublishVideo(uint eVideoProvider,string pchVideoAccount,string pchVideoIdentifier,string pchPreviewFile,uint nConsumerAppId,string pchTitle,string pchDescription,uint eVisibility,ref SteamParamStringArray_t pTags); + public abstract ulong SetUserPublishedFileAction(ulong unPublishedFileId,uint eAction); + public abstract ulong EnumeratePublishedFilesByUserAction(uint eAction,uint unStartIndex); + public abstract ulong EnumeratePublishedWorkshopFiles(uint eEnumerationType,uint unStartIndex,uint unCount,uint unDays,ref SteamParamStringArray_t pTags,ref SteamParamStringArray_t pUserTags); + public abstract ulong UGCDownloadToLocation(ulong hContent,string pchLocation,uint unPriority); + } + + + public abstract class ISteamUserStats + { + public abstract IntPtr GetIntPtr(); + public abstract bool RequestCurrentStats(); + public abstract bool GetStat(string pchName,ref int pData); + public abstract bool GetStat0(string pchName,ref float pData); + public abstract bool SetStat(string pchName,int nData); + public abstract bool SetStat0(string pchName,float fData); + public abstract bool UpdateAvgRateStat(string pchName,float flCountThisSession,double dSessionLength); + public abstract bool GetAchievement(string pchName,ref bool pbAchieved); + public abstract bool SetAchievement(string pchName); + public abstract bool ClearAchievement(string pchName); + public abstract bool GetAchievementAndUnlockTime(string pchName,ref bool pbAchieved,ref uint punUnlockTime); + public abstract bool StoreStats(); + public abstract int GetAchievementIcon(string pchName); + public abstract string GetAchievementDisplayAttribute(string pchName,string pchKey); + public abstract bool IndicateAchievementProgress(string pchName,uint nCurProgress,uint nMaxProgress); + public abstract uint GetNumAchievements(); + public abstract string GetAchievementName(uint iAchievement); + public abstract ulong RequestUserStats(ulong steamIDUser); + public abstract bool GetUserStat(ulong steamIDUser,string pchName,ref int pData); + public abstract bool GetUserStat0(ulong steamIDUser,string pchName,ref float pData); + public abstract bool GetUserAchievement(ulong steamIDUser,string pchName,ref bool pbAchieved); + public abstract bool GetUserAchievementAndUnlockTime(ulong steamIDUser,string pchName,ref bool pbAchieved,ref uint punUnlockTime); + public abstract bool ResetAllStats(bool bAchievementsToo); + public abstract ulong FindOrCreateLeaderboard(string pchLeaderboardName,uint eLeaderboardSortMethod,uint eLeaderboardDisplayType); + public abstract ulong FindLeaderboard(string pchLeaderboardName); + public abstract string GetLeaderboardName(ulong hSteamLeaderboard); + public abstract int GetLeaderboardEntryCount(ulong hSteamLeaderboard); + public abstract uint GetLeaderboardSortMethod(ulong hSteamLeaderboard); + public abstract uint GetLeaderboardDisplayType(ulong hSteamLeaderboard); + public abstract ulong DownloadLeaderboardEntries(ulong hSteamLeaderboard,uint eLeaderboardDataRequest,int nRangeStart,int nRangeEnd); + public abstract ulong DownloadLeaderboardEntriesForUsers(ulong hSteamLeaderboard,CSteamID [] prgUsers); + public abstract bool GetDownloadedLeaderboardEntry(ulong hSteamLeaderboardEntries,int index,ref LeaderboardEntry_t pLeaderboardEntry,ref int pDetails,int cDetailsMax); + public abstract ulong UploadLeaderboardScore(ulong hSteamLeaderboard,uint eLeaderboardUploadScoreMethod,int nScore,ref int pScoreDetails,int cScoreDetailsCount); + public abstract ulong AttachLeaderboardUGC(ulong hSteamLeaderboard,ulong hUGC); + public abstract ulong GetNumberOfCurrentPlayers(); + public abstract ulong RequestGlobalAchievementPercentages(); + public abstract int GetMostAchievedAchievementInfo(string pchName,uint unNameBufLen,ref float pflPercent,ref bool pbAchieved); + public abstract int GetNextMostAchievedAchievementInfo(int iIteratorPrevious,string pchName,uint unNameBufLen,ref float pflPercent,ref bool pbAchieved); + public abstract bool GetAchievementAchievedPercent(string pchName,ref float pflPercent); + public abstract ulong RequestGlobalStats(int nHistoryDays); + public abstract bool GetGlobalStat(string pchStatName,ref long pData); + public abstract bool GetGlobalStat0(string pchStatName,ref double pData); + public abstract int GetGlobalStatHistory(string pchStatName,long [] pData); + public abstract int GetGlobalStatHistory0(string pchStatName,double [] pData); + } + + + public abstract class ISteamApps + { + public abstract IntPtr GetIntPtr(); + public abstract bool BIsSubscribed(); + public abstract bool BIsLowViolence(); + public abstract bool BIsCybercafe(); + public abstract bool BIsVACBanned(); + public abstract string GetCurrentGameLanguage(); + public abstract string GetAvailableGameLanguages(); + public abstract bool BIsSubscribedApp(uint appID); + public abstract bool BIsDlcInstalled(uint appID); + public abstract uint GetEarliestPurchaseUnixTime(uint nAppID); + public abstract bool BIsSubscribedFromFreeWeekend(); + public abstract int GetDLCCount(); + public abstract bool BGetDLCDataByIndex(int iDLC,ref uint pAppID,ref bool pbAvailable,string pchName,int cchNameBufferSize); + public abstract void InstallDLC(uint nAppID); + public abstract void UninstallDLC(uint nAppID); + public abstract void RequestAppProofOfPurchaseKey(uint nAppID); + public abstract bool GetCurrentBetaName(string pchName,int cchNameBufferSize); + public abstract bool MarkContentCorrupt(bool bMissingFilesOnly); + public abstract uint GetInstalledDepots(uint appID,ref uint pvecDepots,uint cMaxDepots); + public abstract uint GetAppInstallDir(uint appID,string pchFolder,uint cchFolderBufferSize); + public abstract bool BIsAppInstalled(uint appID); + public abstract ulong GetAppOwner(); + public abstract string GetLaunchQueryParam(string pchKey); + public abstract bool GetDlcDownloadProgress(uint nAppID,ref ulong punBytesDownloaded,ref ulong punBytesTotal); + public abstract int GetAppBuildId(); + public abstract void RequestAllProofOfPurchaseKeys(); + public abstract ulong GetFileDetails(string pszFileName); + public abstract int GetLaunchCommandLine(string pszCommandLine,int cubCommandLine); + public abstract bool BIsSubscribedFromFamilySharing(); + } + + + public abstract class ISteamNetworking + { + public abstract IntPtr GetIntPtr(); + public abstract bool SendP2PPacket(ulong steamIDRemote,IntPtr pubData,uint cubData,uint eP2PSendType,int nChannel); + public abstract bool IsP2PPacketAvailable(ref uint pcubMsgSize,int nChannel); + public abstract bool ReadP2PPacket(IntPtr pubDest,uint cubDest,ref uint pcubMsgSize,ref CSteamID psteamIDRemote,int nChannel); + public abstract bool AcceptP2PSessionWithUser(ulong steamIDRemote); + public abstract bool CloseP2PSessionWithUser(ulong steamIDRemote); + public abstract bool CloseP2PChannelWithUser(ulong steamIDRemote,int nChannel); + public abstract bool GetP2PSessionState(ulong steamIDRemote,ref P2PSessionState_t pConnectionState); + public abstract bool AllowP2PPacketRelay(bool bAllow); + public abstract uint CreateListenSocket(int nVirtualP2PPort,uint nIP,char nPort,bool bAllowUseOfPacketRelay); + public abstract uint CreateP2PConnectionSocket(ulong steamIDTarget,int nVirtualPort,int nTimeoutSec,bool bAllowUseOfPacketRelay); + public abstract uint CreateConnectionSocket(uint nIP,char nPort,int nTimeoutSec); + public abstract bool DestroySocket(uint hSocket,bool bNotifyRemoteEnd); + public abstract bool DestroyListenSocket(uint hSocket,bool bNotifyRemoteEnd); + public abstract bool SendDataOnSocket(uint hSocket,IntPtr pubData,uint cubData,bool bReliable); + public abstract bool IsDataAvailableOnSocket(uint hSocket,ref uint pcubMsgSize); + public abstract bool RetrieveDataFromSocket(uint hSocket,IntPtr pubDest,uint cubDest,ref uint pcubMsgSize); + public abstract bool IsDataAvailable(uint hListenSocket,ref uint pcubMsgSize,ref uint phSocket); + public abstract bool RetrieveData(uint hListenSocket,IntPtr pubDest,uint cubDest,ref uint pcubMsgSize,ref uint phSocket); + public abstract bool GetSocketInfo(uint hSocket,ref CSteamID pSteamIDRemote,ref int peSocketStatus,ref uint punIPRemote,ref char punPortRemote); + public abstract bool GetListenSocketInfo(uint hListenSocket,ref uint pnIP,ref char pnPort); + public abstract uint GetSocketConnectionType(uint hSocket); + public abstract int GetMaxPacketSize(uint hSocket); + } + + + public abstract class ISteamScreenshots + { + public abstract IntPtr GetIntPtr(); + public abstract uint WriteScreenshot(IntPtr pubRGB,uint cubRGB,int nWidth,int nHeight); + public abstract uint AddScreenshotToLibrary(string pchFilename,string pchThumbnailFilename,int nWidth,int nHeight); + public abstract void TriggerScreenshot(); + public abstract void HookScreenshots(bool bHook); + public abstract bool SetLocation(uint hScreenshot,string pchLocation); + public abstract bool TagUser(uint hScreenshot,ulong steamID); + public abstract bool TagPublishedFile(uint hScreenshot,ulong unPublishedFileID); + public abstract bool IsScreenshotsHooked(); + public abstract uint AddVRScreenshotToLibrary(uint eType,string pchFilename,string pchVRFilename); + } + + + public abstract class ISteamMusic + { + public abstract IntPtr GetIntPtr(); + public abstract bool BIsEnabled(); + public abstract bool BIsPlaying(); + public abstract int GetPlaybackStatus(); + public abstract void Play(); + public abstract void Pause(); + public abstract void PlayPrevious(); + public abstract void PlayNext(); + public abstract void SetVolume(float flVolume); + public abstract float GetVolume(); + } + + + public abstract class ISteamMusicRemote + { + public abstract IntPtr GetIntPtr(); + public abstract bool RegisterSteamMusicRemote(string pchName); + public abstract bool DeregisterSteamMusicRemote(); + public abstract bool BIsCurrentMusicRemote(); + public abstract bool BActivationSuccess(bool bValue); + public abstract bool SetDisplayName(string pchDisplayName); + public abstract bool SetPNGIcon_64x64(IntPtr pvBuffer,uint cbBufferLength); + public abstract bool EnablePlayPrevious(bool bValue); + public abstract bool EnablePlayNext(bool bValue); + public abstract bool EnableShuffled(bool bValue); + public abstract bool EnableLooped(bool bValue); + public abstract bool EnableQueue(bool bValue); + public abstract bool EnablePlaylists(bool bValue); + public abstract bool UpdatePlaybackStatus(int nStatus); + public abstract bool UpdateShuffled(bool bValue); + public abstract bool UpdateLooped(bool bValue); + public abstract bool UpdateVolume(float flValue); + public abstract bool CurrentEntryWillChange(); + public abstract bool CurrentEntryIsAvailable(bool bAvailable); + public abstract bool UpdateCurrentEntryText(string pchText); + public abstract bool UpdateCurrentEntryElapsedSeconds(int nValue); + public abstract bool UpdateCurrentEntryCoverArt(IntPtr pvBuffer,uint cbBufferLength); + public abstract bool CurrentEntryDidChange(); + public abstract bool QueueWillChange(); + public abstract bool ResetQueueEntries(); + public abstract bool SetQueueEntry(int nID,int nPosition,string pchEntryText); + public abstract bool SetCurrentQueueEntry(int nID); + public abstract bool QueueDidChange(); + public abstract bool PlaylistWillChange(); + public abstract bool ResetPlaylistEntries(); + public abstract bool SetPlaylistEntry(int nID,int nPosition,string pchEntryText); + public abstract bool SetCurrentPlaylistEntry(int nID); + public abstract bool PlaylistDidChange(); + } + + + public abstract class ISteamHTTP + { + public abstract IntPtr GetIntPtr(); + public abstract uint CreateHTTPRequest(uint eHTTPRequestMethod,string pchAbsoluteURL); + public abstract bool SetHTTPRequestContextValue(uint hRequest,ulong ulContextValue); + public abstract bool SetHTTPRequestNetworkActivityTimeout(uint hRequest,uint unTimeoutSeconds); + public abstract bool SetHTTPRequestHeaderValue(uint hRequest,string pchHeaderName,string pchHeaderValue); + public abstract bool SetHTTPRequestGetOrPostParameter(uint hRequest,string pchParamName,string pchParamValue); + public abstract bool SendHTTPRequest(uint hRequest,ref ulong pCallHandle); + public abstract bool SendHTTPRequestAndStreamResponse(uint hRequest,ref ulong pCallHandle); + public abstract bool DeferHTTPRequest(uint hRequest); + public abstract bool PrioritizeHTTPRequest(uint hRequest); + public abstract bool GetHTTPResponseHeaderSize(uint hRequest,string pchHeaderName,ref uint unResponseHeaderSize); + public abstract bool GetHTTPResponseHeaderValue(uint hRequest,string pchHeaderName,IntPtr pHeaderValueBuffer,uint unBufferSize); + public abstract bool GetHTTPResponseBodySize(uint hRequest,ref uint unBodySize); + public abstract bool GetHTTPResponseBodyData(uint hRequest,IntPtr pBodyDataBuffer,uint unBufferSize); + public abstract bool GetHTTPStreamingResponseBodyData(uint hRequest,uint cOffset,IntPtr pBodyDataBuffer,uint unBufferSize); + public abstract bool ReleaseHTTPRequest(uint hRequest); + public abstract bool GetHTTPDownloadProgressPct(uint hRequest,ref float pflPercentOut); + public abstract bool SetHTTPRequestRawPostBody(uint hRequest,string pchContentType,IntPtr pubBody,uint unBodyLen); + public abstract uint CreateCookieContainer(bool bAllowResponsesToModify); + public abstract bool ReleaseCookieContainer(uint hCookieContainer); + public abstract bool SetCookie(uint hCookieContainer,string pchHost,string pchUrl,string pchCookie); + public abstract bool SetHTTPRequestCookieContainer(uint hRequest,uint hCookieContainer); + public abstract bool SetHTTPRequestUserAgentInfo(uint hRequest,string pchUserAgentInfo); + public abstract bool SetHTTPRequestRequiresVerifiedCertificate(uint hRequest,bool bRequireVerifiedCertificate); + public abstract bool SetHTTPRequestAbsoluteTimeoutMS(uint hRequest,uint unMilliseconds); + public abstract bool GetHTTPRequestWasTimedOut(uint hRequest,ref bool pbWasTimedOut); + } + + + public abstract class ISteamInput + { + public abstract IntPtr GetIntPtr(); + public abstract bool Init(); + public abstract bool Shutdown(); + public abstract void RunFrame(); + public abstract int GetConnectedControllers(out ulong [] handlesOut); + public abstract ulong GetActionSetHandle(string pszActionSetName); + public abstract void ActivateActionSet(ulong inputHandle,ulong actionSetHandle); + public abstract ulong GetCurrentActionSet(ulong inputHandle); + public abstract void ActivateActionSetLayer(ulong inputHandle,ulong actionSetLayerHandle); + public abstract void DeactivateActionSetLayer(ulong inputHandle,ulong actionSetLayerHandle); + public abstract void DeactivateAllActionSetLayers(ulong inputHandle); + public abstract int GetActiveActionSetLayers(ulong inputHandle,out ulong [] handlesOut); + public abstract ulong GetDigitalActionHandle(string pszActionName); + public abstract InputDigitalActionData_t GetDigitalActionData(ulong inputHandle,ulong digitalActionHandle); + public abstract int GetDigitalActionOrigins(ulong inputHandle,ulong actionSetHandle,ulong digitalActionHandle,out uint [] originsOut); + public abstract ulong GetAnalogActionHandle(string pszActionName); + public abstract InputAnalogActionData_t GetAnalogActionData(ulong inputHandle,ulong analogActionHandle); + public abstract int GetAnalogActionOrigins(ulong inputHandle,ulong actionSetHandle,ulong analogActionHandle,out uint [] originsOut); + public abstract string GetGlyphForActionOrigin(uint eOrigin); + public abstract string GetStringForActionOrigin(uint eOrigin); + public abstract void StopAnalogActionMomentum(ulong inputHandle,ulong eAction); + public abstract InputMotionData_t GetMotionData(ulong inputHandle); + public abstract void TriggerVibration(ulong inputHandle,char usLeftSpeed,char usRightSpeed); + public abstract void SetLEDColor(ulong inputHandle,byte nColorR,byte nColorG,byte nColorB,uint nFlags); + public abstract void TriggerHapticPulse(ulong inputHandle,uint eTargetPad,char usDurationMicroSec); + public abstract void TriggerRepeatedHapticPulse(ulong inputHandle,uint eTargetPad,char usDurationMicroSec,char usOffMicroSec,char unRepeat,uint nFlags); + public abstract bool ShowBindingPanel(ulong inputHandle); + public abstract uint GetInputTypeForHandle(ulong inputHandle); + public abstract ulong GetControllerForGamepadIndex(int nIndex); + public abstract int GetGamepadIndexForController(ulong ulinputHandle); + public abstract string GetStringForXboxOrigin(uint eOrigin); + public abstract string GetGlyphForXboxOrigin(uint eOrigin); + public abstract uint GetActionOriginFromXboxOrigin(ulong inputHandle,uint eOrigin); + public abstract uint TranslateActionOrigin(uint eDestinationInputType,uint eSourceOrigin); + public abstract bool GetDeviceBindingRevision(ulong inputHandle,ref int pMajor,ref int pMinor); + public abstract uint GetRemotePlaySessionID(ulong inputHandle); + } + + + public abstract class ISteamController + { + public abstract IntPtr GetIntPtr(); + public abstract bool Init(); + public abstract bool Shutdown(); + public abstract void RunFrame(); + public abstract int GetConnectedControllers(out ulong [] handlesOut); + public abstract ulong GetActionSetHandle(string pszActionSetName); + public abstract void ActivateActionSet(ulong controllerHandle,ulong actionSetHandle); + public abstract ulong GetCurrentActionSet(ulong controllerHandle); + public abstract void ActivateActionSetLayer(ulong controllerHandle,ulong actionSetLayerHandle); + public abstract void DeactivateActionSetLayer(ulong controllerHandle,ulong actionSetLayerHandle); + public abstract void DeactivateAllActionSetLayers(ulong controllerHandle); + public abstract int GetActiveActionSetLayers(ulong controllerHandle,out ulong [] handlesOut); + public abstract ulong GetDigitalActionHandle(string pszActionName); + public abstract InputDigitalActionData_t GetDigitalActionData(ulong controllerHandle,ulong digitalActionHandle); + public abstract int GetDigitalActionOrigins(ulong controllerHandle,ulong actionSetHandle,ulong digitalActionHandle,out uint [] originsOut); + public abstract ulong GetAnalogActionHandle(string pszActionName); + public abstract InputAnalogActionData_t GetAnalogActionData(ulong controllerHandle,ulong analogActionHandle); + public abstract int GetAnalogActionOrigins(ulong controllerHandle,ulong actionSetHandle,ulong analogActionHandle,out uint [] originsOut); + public abstract string GetGlyphForActionOrigin(uint eOrigin); + public abstract string GetStringForActionOrigin(uint eOrigin); + public abstract void StopAnalogActionMomentum(ulong controllerHandle,ulong eAction); + public abstract InputMotionData_t GetMotionData(ulong controllerHandle); + public abstract void TriggerHapticPulse(ulong controllerHandle,uint eTargetPad,char usDurationMicroSec); + public abstract void TriggerRepeatedHapticPulse(ulong controllerHandle,uint eTargetPad,char usDurationMicroSec,char usOffMicroSec,char unRepeat,uint nFlags); + public abstract void TriggerVibration(ulong controllerHandle,char usLeftSpeed,char usRightSpeed); + public abstract void SetLEDColor(ulong controllerHandle,byte nColorR,byte nColorG,byte nColorB,uint nFlags); + public abstract bool ShowBindingPanel(ulong controllerHandle); + public abstract uint GetInputTypeForHandle(ulong controllerHandle); + public abstract ulong GetControllerForGamepadIndex(int nIndex); + public abstract int GetGamepadIndexForController(ulong ulControllerHandle); + public abstract string GetStringForXboxOrigin(uint eOrigin); + public abstract string GetGlyphForXboxOrigin(uint eOrigin); + public abstract uint GetActionOriginFromXboxOrigin(ulong controllerHandle,uint eOrigin); + public abstract uint TranslateActionOrigin(uint eDestinationInputType,uint eSourceOrigin); + public abstract bool GetControllerBindingRevision(ulong controllerHandle,ref int pMajor,ref int pMinor); + } + + + public abstract class ISteamUGC + { + public abstract IntPtr GetIntPtr(); + public abstract ulong CreateQueryUserUGCRequest(uint unAccountID,uint eListType,uint eMatchingUGCType,uint eSortOrder,uint nCreatorAppID,uint nConsumerAppID,uint unPage); + public abstract ulong CreateQueryAllUGCRequest(uint eQueryType,uint eMatchingeMatchingUGCTypeFileType,uint nCreatorAppID,uint nConsumerAppID,uint unPage); + public abstract ulong CreateQueryAllUGCRequest0(uint eQueryType,uint eMatchingeMatchingUGCTypeFileType,uint nCreatorAppID,uint nConsumerAppID,string pchCursor); + public abstract ulong CreateQueryUGCDetailsRequest(ref ulong pvecPublishedFileID,uint unNumPublishedFileIDs); + public abstract ulong SendQueryUGCRequest(ulong handle); + public abstract bool GetQueryUGCResult(ulong handle,uint index,ref SteamUGCDetails_t pDetails); + public abstract bool GetQueryUGCPreviewURL(ulong handle,uint index,out string pchURL); + public abstract bool GetQueryUGCMetadata(ulong handle,uint index,out string pchMetadata); + public abstract bool GetQueryUGCChildren(ulong handle,uint index,ref ulong pvecPublishedFileID,uint cMaxEntries); + public abstract bool GetQueryUGCStatistic(ulong handle,uint index,uint eStatType,ref ulong pStatValue); + public abstract uint GetQueryUGCNumAdditionalPreviews(ulong handle,uint index); + public abstract bool GetQueryUGCAdditionalPreview(ulong handle,uint index,uint previewIndex,out string pchURLOrVideoID,out string pchOriginalFileName,uint cchOriginalFileNameSize,ref uint pPreviewType); + public abstract uint GetQueryUGCNumKeyValueTags(ulong handle,uint index); + public abstract bool GetQueryUGCKeyValueTag(ulong handle,uint index,uint keyValueTagIndex,out string pchKey,out string pchValue); + public abstract bool GetQueryUGCKeyValueTag0(ulong handle,uint index,string pchKey,out string pchValue); + public abstract bool ReleaseQueryUGCRequest(ulong handle); + public abstract bool AddRequiredTag(ulong handle,string pTagName); + public abstract bool AddExcludedTag(ulong handle,string pTagName); + public abstract bool SetReturnOnlyIDs(ulong handle,bool bReturnOnlyIDs); + public abstract bool SetReturnKeyValueTags(ulong handle,bool bReturnKeyValueTags); + public abstract bool SetReturnLongDescription(ulong handle,bool bReturnLongDescription); + public abstract bool SetReturnMetadata(ulong handle,bool bReturnMetadata); + public abstract bool SetReturnChildren(ulong handle,bool bReturnChildren); + public abstract bool SetReturnAdditionalPreviews(ulong handle,bool bReturnAdditionalPreviews); + public abstract bool SetReturnTotalOnly(ulong handle,bool bReturnTotalOnly); + public abstract bool SetReturnPlaytimeStats(ulong handle,uint unDays); + public abstract bool SetLanguage(ulong handle,string pchLanguage); + public abstract bool SetAllowCachedResponse(ulong handle,uint unMaxAgeSeconds); + public abstract bool SetCloudFileNameFilter(ulong handle,string pMatchCloudFileName); + public abstract bool SetMatchAnyTag(ulong handle,bool bMatchAnyTag); + public abstract bool SetSearchText(ulong handle,string pSearchText); + public abstract bool SetRankedByTrendDays(ulong handle,uint unDays); + public abstract bool AddRequiredKeyValueTag(ulong handle,string pKey,string pValue); + public abstract ulong RequestUGCDetails(ulong nPublishedFileID,uint unMaxAgeSeconds); + public abstract ulong CreateItem(uint nConsumerAppId,uint eFileType); + public abstract ulong StartItemUpdate(uint nConsumerAppId,ulong nPublishedFileID); + public abstract bool SetItemTitle(ulong handle,string pchTitle); + public abstract bool SetItemDescription(ulong handle,string pchDescription); + public abstract bool SetItemUpdateLanguage(ulong handle,string pchLanguage); + public abstract bool SetItemMetadata(ulong handle,string pchMetaData); + public abstract bool SetItemVisibility(ulong handle,uint eVisibility); + public abstract bool SetItemTags(ulong updateHandle,ref SteamParamStringArray_t pTags); + public abstract bool SetItemContent(ulong handle,string pszContentFolder); + public abstract bool SetItemPreview(ulong handle,string pszPreviewFile); + public abstract bool SetAllowLegacyUpload(ulong handle,bool bAllowLegacyUpload); + public abstract bool RemoveAllItemKeyValueTags(ulong handle); + public abstract bool RemoveItemKeyValueTags(ulong handle,string pchKey); + public abstract bool AddItemKeyValueTag(ulong handle,string pchKey,string pchValue); + public abstract bool AddItemPreviewFile(ulong handle,string pszPreviewFile,uint type); + public abstract bool AddItemPreviewVideo(ulong handle,string pszVideoID); + public abstract bool UpdateItemPreviewFile(ulong handle,uint index,string pszPreviewFile); + public abstract bool UpdateItemPreviewVideo(ulong handle,uint index,string pszVideoID); + public abstract bool RemoveItemPreview(ulong handle,uint index); + public abstract ulong SubmitItemUpdate(ulong handle,string pchChangeNote); + public abstract uint GetItemUpdateProgress(ulong handle,ref ulong punBytesProcessed,ref ulong punBytesTotal); + public abstract ulong SetUserItemVote(ulong nPublishedFileID,bool bVoteUp); + public abstract ulong GetUserItemVote(ulong nPublishedFileID); + public abstract ulong AddItemToFavorites(uint nAppId,ulong nPublishedFileID); + public abstract ulong RemoveItemFromFavorites(uint nAppId,ulong nPublishedFileID); + public abstract ulong SubscribeItem(ulong nPublishedFileID); + public abstract ulong UnsubscribeItem(ulong nPublishedFileID); + public abstract uint GetNumSubscribedItems(); + public abstract uint GetSubscribedItems(ref ulong pvecPublishedFileID,uint cMaxEntries); + public abstract uint GetItemState(ulong nPublishedFileID); + public abstract bool GetItemInstallInfo(ulong nPublishedFileID,ref ulong punSizeOnDisk,out string pchFolder,ref uint punTimeStamp); + public abstract bool GetItemDownloadInfo(ulong nPublishedFileID,ref ulong punBytesDownloaded,ref ulong punBytesTotal); + public abstract bool DownloadItem(ulong nPublishedFileID,bool bHighPriority); + public abstract bool BInitWorkshopForGameServer(uint unWorkshopDepotID,string pszFolder); + public abstract void SuspendDownloads(bool bSuspend); + public abstract ulong StartPlaytimeTracking(ref ulong pvecPublishedFileID,uint unNumPublishedFileIDs); + public abstract ulong StopPlaytimeTracking(ref ulong pvecPublishedFileID,uint unNumPublishedFileIDs); + public abstract ulong StopPlaytimeTrackingForAllItems(); + public abstract ulong AddDependency(ulong nParentPublishedFileID,ulong nChildPublishedFileID); + public abstract ulong RemoveDependency(ulong nParentPublishedFileID,ulong nChildPublishedFileID); + public abstract ulong AddAppDependency(ulong nPublishedFileID,uint nAppID); + public abstract ulong RemoveAppDependency(ulong nPublishedFileID,uint nAppID); + public abstract ulong GetAppDependencies(ulong nPublishedFileID); + public abstract ulong DeleteItem(ulong nPublishedFileID); + } + + + public abstract class ISteamAppList + { + public abstract IntPtr GetIntPtr(); + public abstract uint GetNumInstalledApps(); + public abstract uint GetInstalledApps(ref uint pvecAppID,uint unMaxAppIDs); + public abstract int GetAppName(uint nAppID,System.Text.StringBuilder pchName,int cchNameMax); + public abstract int GetAppInstallDir(uint nAppID,string pchDirectory,int cchNameMax); + public abstract int GetAppBuildId(uint nAppID); + } + + + public abstract class ISteamHTMLSurface + { + public abstract IntPtr GetIntPtr(); + public abstract void DestructISteamHTMLSurface(); + public abstract bool Init(); + public abstract bool Shutdown(); + public abstract ulong CreateBrowser(string pchUserAgent,string pchUserCSS); + public abstract void RemoveBrowser(uint unBrowserHandle); + public abstract void LoadURL(uint unBrowserHandle,string pchURL,string pchPostData); + public abstract void SetSize(uint unBrowserHandle,uint unWidth,uint unHeight); + public abstract void StopLoad(uint unBrowserHandle); + public abstract void Reload(uint unBrowserHandle); + public abstract void GoBack(uint unBrowserHandle); + public abstract void GoForward(uint unBrowserHandle); + public abstract void AddHeader(uint unBrowserHandle,string pchKey,string pchValue); + public abstract void ExecuteJavascript(uint unBrowserHandle,string pchScript); + public abstract void MouseUp(uint unBrowserHandle,uint eMouseButton); + public abstract void MouseDown(uint unBrowserHandle,uint eMouseButton); + public abstract void MouseDoubleClick(uint unBrowserHandle,uint eMouseButton); + public abstract void MouseMove(uint unBrowserHandle,int x,int y); + public abstract void MouseWheel(uint unBrowserHandle,int nDelta); + public abstract void KeyDown(uint unBrowserHandle,uint nNativeKeyCode,uint eHTMLKeyModifiers,bool bIsSystemKey); + public abstract void KeyUp(uint unBrowserHandle,uint nNativeKeyCode,uint eHTMLKeyModifiers); + public abstract void KeyChar(uint unBrowserHandle,uint cUnicodeChar,uint eHTMLKeyModifiers); + public abstract void SetHorizontalScroll(uint unBrowserHandle,uint nAbsolutePixelScroll); + public abstract void SetVerticalScroll(uint unBrowserHandle,uint nAbsolutePixelScroll); + public abstract void SetKeyFocus(uint unBrowserHandle,bool bHasKeyFocus); + public abstract void ViewSource(uint unBrowserHandle); + public abstract void CopyToClipboard(uint unBrowserHandle); + public abstract void PasteFromClipboard(uint unBrowserHandle); + public abstract void Find(uint unBrowserHandle,string pchSearchStr,bool bCurrentlyInFind,bool bReverse); + public abstract void StopFind(uint unBrowserHandle); + public abstract void GetLinkAtPosition(uint unBrowserHandle,int x,int y); + public abstract void SetCookie(string pchHostname,string pchKey,string pchValue,string pchPath,ulong nExpires,bool bSecure,bool bHTTPOnly); + public abstract void SetPageScaleFactor(uint unBrowserHandle,float flZoom,int nPointX,int nPointY); + public abstract void SetBackgroundMode(uint unBrowserHandle,bool bBackgroundMode); + public abstract void SetDPIScalingFactor(uint unBrowserHandle,float flDPIScaling); + public abstract void OpenDeveloperTools(uint unBrowserHandle); + public abstract void AllowStartRequest(uint unBrowserHandle,bool bAllowed); + public abstract void JSDialogResponse(uint unBrowserHandle,bool bResult); + } + + + public abstract class ISteamInventory + { + public abstract IntPtr GetIntPtr(); + public abstract uint GetResultStatus(int resultHandle); + public abstract bool GetResultItems(int resultHandle,out SteamItemDetails_t [] pOutItemsArray); + public abstract bool GetResultItemProperty(int resultHandle,uint unItemIndex,string pchPropertyName,out string pchValueBuffer); + public abstract uint GetResultTimestamp(int resultHandle); + public abstract bool CheckResultSteamID(int resultHandle,ulong steamIDExpected); + public abstract void DestroyResult(int resultHandle); + public abstract bool GetAllItems(ref int pResultHandle); + public abstract bool GetItemsByID(ref int pResultHandle,ulong [] pInstanceIDs); + public abstract bool SerializeResult(int resultHandle,IntPtr pOutBuffer,ref uint punOutBufferSize); + public abstract bool DeserializeResult(ref int pOutResultHandle,IntPtr pBuffer,uint unBufferSize,bool bRESERVED_MUST_BE_FALSE); + public abstract bool GenerateItems(ref int pResultHandle,int [] pArrayItemDefs,uint [] punArrayQuantity); + public abstract bool GrantPromoItems(ref int pResultHandle); + public abstract bool AddPromoItem(ref int pResultHandle,int itemDef); + public abstract bool AddPromoItems(ref int pResultHandle,int [] pArrayItemDefs); + public abstract bool ConsumeItem(ref int pResultHandle,ulong itemConsume,uint unQuantity); + public abstract bool ExchangeItems(ref int pResultHandle,int [] pArrayGenerate,uint [] punArrayGenerateQuantity,ulong [] pArrayDestroy,uint [] punArrayDestroyQuantity); + public abstract bool TransferItemQuantity(ref int pResultHandle,ulong itemIdSource,uint unQuantity,ulong itemIdDest); + public abstract void SendItemDropHeartbeat(); + public abstract bool TriggerItemDrop(ref int pResultHandle,int dropListDefinition); + public abstract bool TradeItems(ref int pResultHandle,ulong steamIDTradePartner,ulong [] pArrayGive,uint [] pArrayGiveQuantity,ulong [] pArrayGet,uint [] pArrayGetQuantity); + public abstract bool LoadItemDefinitions(); + public abstract bool GetItemDefinitionIDs(out int [] pItemDefIDs); + public abstract bool GetItemDefinitionProperty(int iDefinition,string pchPropertyName,out string pchValueBuffer); + public abstract ulong RequestEligiblePromoItemDefinitionsIDs(ulong steamID); + public abstract bool GetEligiblePromoItemDefinitionIDs(ulong steamID,out int [] pItemDefIDs); + public abstract ulong StartPurchase(int [] pArrayItemDefs,uint [] punArrayQuantity); + public abstract ulong RequestPrices(); + public abstract uint GetNumItemsWithPrices(); + public abstract bool GetItemsWithPrices(out int [] pArrayItemDefs,out ulong [] pCurrentPrices,out ulong [] pBasePrices,uint unArrayLength); + public abstract bool GetItemPrice(int iDefinition,ref ulong pCurrentPrice,ref ulong pBasePrice); + public abstract ulong StartUpdateProperties(); + public abstract bool RemoveProperty(ulong handle,ulong nItemID,string pchPropertyName); + public abstract bool SetProperty(ulong handle,ulong nItemID,string pchPropertyName,string pchPropertyValue); + public abstract bool SetProperty0(ulong handle,ulong nItemID,string pchPropertyName,bool bValue); + public abstract bool SetProperty1(ulong handle,ulong nItemID,string pchPropertyName,long nValue); + public abstract bool SetProperty2(ulong handle,ulong nItemID,string pchPropertyName,float flValue); + public abstract bool SubmitUpdateProperties(ulong handle,ref int pResultHandle); + } + + + public abstract class ISteamVideo + { + public abstract IntPtr GetIntPtr(); + public abstract void GetVideoURL(uint unVideoAppID); + public abstract bool IsBroadcasting(ref int pnNumViewers); + public abstract void GetOPFSettings(uint unVideoAppID); + public abstract bool GetOPFStringForApp(uint unVideoAppID,string pchBuffer,ref int pnBufferSize); + } + + + public abstract class ISteamTV + { + public abstract IntPtr GetIntPtr(); + public abstract bool IsBroadcasting(ref int pnNumViewers); + public abstract void AddBroadcastGameData(string pchKey,string pchValue); + public abstract void RemoveBroadcastGameData(string pchKey); + public abstract void AddTimelineMarker(string pchTemplateName,bool bPersistent,byte nColorR,byte nColorG,byte nColorB); + public abstract void RemoveTimelineMarker(); + public abstract uint AddRegion(string pchElementName,string pchTimelineDataSection,ref SteamTVRegion_t pSteamTVRegion,uint eSteamTVRegionBehavior); + public abstract void RemoveRegion(uint unRegionHandle); + } + + + public abstract class ISteamParentalSettings + { + public abstract IntPtr GetIntPtr(); + public abstract bool BIsParentalLockEnabled(); + public abstract bool BIsParentalLockLocked(); + public abstract bool BIsAppBlocked(uint nAppID); + public abstract bool BIsAppInBlockList(uint nAppID); + public abstract bool BIsFeatureBlocked(uint eFeature); + public abstract bool BIsFeatureInBlockList(uint eFeature); + } + + + public abstract class ISteamRemotePlay + { + public abstract IntPtr GetIntPtr(); + public abstract uint GetSessionCount(); + public abstract uint GetSessionID(int iSessionIndex); + public abstract ulong GetSessionSteamID(uint unSessionID); + public abstract string GetSessionClientName(uint unSessionID); + public abstract uint GetSessionClientFormFactor(uint unSessionID); + public abstract bool BGetSessionClientResolution(uint unSessionID,ref int pnResolutionX,ref int pnResolutionY); + } + + + public abstract class ISteamGameServer + { + public abstract IntPtr GetIntPtr(); + public abstract bool InitGameServer(uint unIP,char usGamePort,char usQueryPort,uint unFlags,uint nGameAppId,string pchVersionString); + public abstract void SetProduct(string pszProduct); + public abstract void SetGameDescription(string pszGameDescription); + public abstract void SetModDir(string pszModDir); + public abstract void SetDedicatedServer(bool bDedicated); + public abstract void LogOn(string pszToken); + public abstract void LogOnAnonymous(); + public abstract void LogOff(); + public abstract bool BLoggedOn(); + public abstract bool BSecure(); + public abstract ulong GetSteamID(); + public abstract bool WasRestartRequested(); + public abstract void SetMaxPlayerCount(int cPlayersMax); + public abstract void SetBotPlayerCount(int cBotplayers); + public abstract void SetServerName(string pszServerName); + public abstract void SetMapName(string pszMapName); + public abstract void SetPasswordProtected(bool bPasswordProtected); + public abstract void SetSpectatorPort(char unSpectatorPort); + public abstract void SetSpectatorServerName(string pszSpectatorServerName); + public abstract void ClearAllKeyValues(); + public abstract void SetKeyValue(string pKey,string pValue); + public abstract void SetGameTags(string pchGameTags); + public abstract void SetGameData(string pchGameData); + public abstract void SetRegion(string pszRegion); + public abstract bool SendUserConnectAndAuthenticate(uint unIPClient,IntPtr pvAuthBlob,uint cubAuthBlobSize,ref CSteamID pSteamIDUser); + public abstract ulong CreateUnauthenticatedUserConnection(); + public abstract void SendUserDisconnect(ulong steamIDUser); + public abstract bool BUpdateUserData(ulong steamIDUser,string pchPlayerName,uint uScore); + public abstract uint GetAuthSessionTicket(IntPtr pTicket,int cbMaxTicket,ref uint pcbTicket); + public abstract uint BeginAuthSession(IntPtr pAuthTicket,int cbAuthTicket,ulong steamID); + public abstract void EndAuthSession(ulong steamID); + public abstract void CancelAuthTicket(uint hAuthTicket); + public abstract uint UserHasLicenseForApp(ulong steamID,uint appID); + public abstract bool RequestUserGroupStatus(ulong steamIDUser,ulong steamIDGroup); + public abstract void GetGameplayStats(); + public abstract ulong GetServerReputation(); + public abstract uint GetPublicIP(); + public abstract bool HandleIncomingPacket(IntPtr pData,int cbData,uint srcIP,char srcPort); + public abstract int GetNextOutgoingPacket(IntPtr pOut,int cbMaxOut,ref uint pNetAdr,ref char pPort); + public abstract void EnableHeartbeats(bool bActive); + public abstract void SetHeartbeatInterval(int iHeartbeatInterval); + public abstract void ForceHeartbeat(); + public abstract ulong AssociateWithClan(ulong steamIDClan); + public abstract ulong ComputeNewPlayerCompatibility(ulong steamIDNewPlayer); + } + + + public abstract class ISteamGameServerStats + { + public abstract IntPtr GetIntPtr(); + public abstract ulong RequestUserStats(ulong steamIDUser); + public abstract bool GetUserStat(ulong steamIDUser,string pchName,ref int pData); + public abstract bool GetUserStat0(ulong steamIDUser,string pchName,ref float pData); + public abstract bool GetUserAchievement(ulong steamIDUser,string pchName,ref bool pbAchieved); + public abstract bool SetUserStat(ulong steamIDUser,string pchName,int nData); + public abstract bool SetUserStat0(ulong steamIDUser,string pchName,float fData); + public abstract bool UpdateUserAvgRateStat(ulong steamIDUser,string pchName,float flCountThisSession,double dSessionLength); + public abstract bool SetUserAchievement(ulong steamIDUser,string pchName); + public abstract bool ClearUserAchievement(ulong steamIDUser,string pchName); + public abstract ulong StoreUserStats(ulong steamIDUser); + } + + +public class CSteamClient : ISteamClient +{ +public CSteamClient(IntPtr SteamClient) +{ + m_pSteamClient = SteamClient; +} +IntPtr m_pSteamClient; + +public override IntPtr GetIntPtr() { return m_pSteamClient; } + +private void CheckIfUsable() +{ + if (m_pSteamClient == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint CreateSteamPipe() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamClient_CreateSteamPipe(m_pSteamClient); + return result; +} +public override bool BReleaseSteamPipe(uint hSteamPipe) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamClient_BReleaseSteamPipe(m_pSteamClient,hSteamPipe); + return result; +} +public override uint ConnectToGlobalUser(uint hSteamPipe) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamClient_ConnectToGlobalUser(m_pSteamClient,hSteamPipe); + return result; +} +public override uint CreateLocalUser(ref uint phSteamPipe,uint eAccountType) +{ + CheckIfUsable(); + phSteamPipe = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamClient_CreateLocalUser(m_pSteamClient,ref phSteamPipe,eAccountType); + return result; +} +public override void ReleaseUser(uint hSteamPipe,uint hUser) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamClient_ReleaseUser(m_pSteamClient,hSteamPipe,hUser); +} +public override ISteamUser GetISteamUser(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamUser(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamUser) Marshal.PtrToStructure(result, typeof(ISteamUser)); +} +public override ISteamGameServer GetISteamGameServer(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamGameServer(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamGameServer) Marshal.PtrToStructure(result, typeof(ISteamGameServer)); +} +public override void SetLocalIPBinding(uint unIP,char usPort) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamClient_SetLocalIPBinding(m_pSteamClient,unIP,usPort); +} +public override ISteamFriends GetISteamFriends(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamFriends(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamFriends) Marshal.PtrToStructure(result, typeof(ISteamFriends)); +} +public override ISteamUtils GetISteamUtils(uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamUtils(m_pSteamClient,hSteamPipe,pchVersion); + return (ISteamUtils) Marshal.PtrToStructure(result, typeof(ISteamUtils)); +} +public override ISteamMatchmaking GetISteamMatchmaking(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamMatchmaking(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamMatchmaking) Marshal.PtrToStructure(result, typeof(ISteamMatchmaking)); +} +public override ISteamMatchmakingServers GetISteamMatchmakingServers(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamMatchmakingServers(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamMatchmakingServers) Marshal.PtrToStructure(result, typeof(ISteamMatchmakingServers)); +} +public override IntPtr GetISteamGenericInterface(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamGenericInterface(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (IntPtr) Marshal.PtrToStructure(result, typeof(IntPtr)); +} +public override ISteamUserStats GetISteamUserStats(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamUserStats(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamUserStats) Marshal.PtrToStructure(result, typeof(ISteamUserStats)); +} +public override ISteamGameServerStats GetISteamGameServerStats(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamGameServerStats(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamGameServerStats) Marshal.PtrToStructure(result, typeof(ISteamGameServerStats)); +} +public override ISteamApps GetISteamApps(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamApps(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamApps) Marshal.PtrToStructure(result, typeof(ISteamApps)); +} +public override ISteamNetworking GetISteamNetworking(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamNetworking(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamNetworking) Marshal.PtrToStructure(result, typeof(ISteamNetworking)); +} +public override ISteamRemoteStorage GetISteamRemoteStorage(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamRemoteStorage(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamRemoteStorage) Marshal.PtrToStructure(result, typeof(ISteamRemoteStorage)); +} +public override ISteamScreenshots GetISteamScreenshots(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamScreenshots(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamScreenshots) Marshal.PtrToStructure(result, typeof(ISteamScreenshots)); +} +public override ISteamGameSearch GetISteamGameSearch(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamGameSearch(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamGameSearch) Marshal.PtrToStructure(result, typeof(ISteamGameSearch)); +} +public override uint GetIPCCallCount() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamClient_GetIPCCallCount(m_pSteamClient); + return result; +} +public override void SetWarningMessageHook(IntPtr pFunction) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamClient_SetWarningMessageHook(m_pSteamClient,pFunction); +} +public override bool BShutdownIfAllPipesClosed() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamClient_BShutdownIfAllPipesClosed(m_pSteamClient); + return result; +} +public override ISteamHTTP GetISteamHTTP(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamHTTP(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamHTTP) Marshal.PtrToStructure(result, typeof(ISteamHTTP)); +} +public override ISteamController GetISteamController(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamController(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamController) Marshal.PtrToStructure(result, typeof(ISteamController)); +} +public override ISteamUGC GetISteamUGC(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamUGC(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamUGC) Marshal.PtrToStructure(result, typeof(ISteamUGC)); +} +public override ISteamAppList GetISteamAppList(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamAppList(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamAppList) Marshal.PtrToStructure(result, typeof(ISteamAppList)); +} +public override ISteamMusic GetISteamMusic(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamMusic(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamMusic) Marshal.PtrToStructure(result, typeof(ISteamMusic)); +} +public override ISteamMusicRemote GetISteamMusicRemote(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamMusicRemote(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamMusicRemote) Marshal.PtrToStructure(result, typeof(ISteamMusicRemote)); +} +public override ISteamHTMLSurface GetISteamHTMLSurface(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamHTMLSurface(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamHTMLSurface) Marshal.PtrToStructure(result, typeof(ISteamHTMLSurface)); +} +public override ISteamInventory GetISteamInventory(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamInventory(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamInventory) Marshal.PtrToStructure(result, typeof(ISteamInventory)); +} +public override ISteamVideo GetISteamVideo(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamVideo(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamVideo) Marshal.PtrToStructure(result, typeof(ISteamVideo)); +} +public override ISteamParentalSettings GetISteamParentalSettings(uint hSteamuser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamParentalSettings(m_pSteamClient,hSteamuser,hSteamPipe,pchVersion); + return (ISteamParentalSettings) Marshal.PtrToStructure(result, typeof(ISteamParentalSettings)); +} +public override ISteamInput GetISteamInput(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamInput(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamInput) Marshal.PtrToStructure(result, typeof(ISteamInput)); +} +public override ISteamParties GetISteamParties(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamParties(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamParties) Marshal.PtrToStructure(result, typeof(ISteamParties)); +} +public override ISteamRemotePlay GetISteamRemotePlay(uint hSteamUser,uint hSteamPipe,string pchVersion) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamRemotePlay(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion); + return (ISteamRemotePlay) Marshal.PtrToStructure(result, typeof(ISteamRemotePlay)); +} +} + + +public class CSteamUser : ISteamUser +{ +public CSteamUser(IntPtr SteamUser) +{ + m_pSteamUser = SteamUser; +} +IntPtr m_pSteamUser; + +public override IntPtr GetIntPtr() { return m_pSteamUser; } + +private void CheckIfUsable() +{ + if (m_pSteamUser == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint GetHSteamUser() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUser_GetHSteamUser(m_pSteamUser); + return result; +} +public override bool BLoggedOn() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_BLoggedOn(m_pSteamUser); + return result; +} +public override ulong GetSteamID() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUser_GetSteamID(m_pSteamUser); + return result; +} +public override int InitiateGameConnection(IntPtr pAuthBlob,int cbMaxAuthBlob,ulong steamIDGameServer,uint unIPServer,char usPortServer,bool bSecure) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUser_InitiateGameConnection(m_pSteamUser,pAuthBlob,cbMaxAuthBlob,steamIDGameServer,unIPServer,usPortServer,bSecure); + return result; +} +public override void TerminateGameConnection(uint unIPServer,char usPortServer) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_TerminateGameConnection(m_pSteamUser,unIPServer,usPortServer); +} +public override void TrackAppUsageEvent(ulong gameID,int eAppUsageEvent,string pchExtraInfo) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_TrackAppUsageEvent(m_pSteamUser,gameID,eAppUsageEvent,pchExtraInfo); +} +public override bool GetUserDataFolder(string pchBuffer,int cubBuffer) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_GetUserDataFolder(m_pSteamUser,pchBuffer,cubBuffer); + return result; +} +public override void StartVoiceRecording() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_StartVoiceRecording(m_pSteamUser); +} +public override void StopVoiceRecording() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_StopVoiceRecording(m_pSteamUser); +} +public override uint GetAvailableVoice(ref uint pcbCompressed,ref uint pcbUncompressed_Deprecated,uint nUncompressedVoiceDesiredSampleRate_Deprecated) +{ + CheckIfUsable(); + pcbCompressed = 0; + pcbUncompressed_Deprecated = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamUser_GetAvailableVoice(m_pSteamUser,ref pcbCompressed,ref pcbUncompressed_Deprecated,nUncompressedVoiceDesiredSampleRate_Deprecated); + return result; +} +public override uint GetVoice(bool bWantCompressed,IntPtr pDestBuffer,uint cbDestBufferSize,ref uint nBytesWritten,bool bWantUncompressed_Deprecated,IntPtr pUncompressedDestBuffer_Deprecated,uint cbUncompressedDestBufferSize_Deprecated,ref uint nUncompressBytesWritten_Deprecated,uint nUncompressedVoiceDesiredSampleRate_Deprecated) +{ + CheckIfUsable(); + nBytesWritten = 0; + nUncompressBytesWritten_Deprecated = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamUser_GetVoice(m_pSteamUser,bWantCompressed,pDestBuffer,cbDestBufferSize,ref nBytesWritten,bWantUncompressed_Deprecated,pUncompressedDestBuffer_Deprecated,cbUncompressedDestBufferSize_Deprecated,ref nUncompressBytesWritten_Deprecated,nUncompressedVoiceDesiredSampleRate_Deprecated); + return result; +} +public override uint DecompressVoice(IntPtr pCompressed,uint cbCompressed,IntPtr pDestBuffer,uint cbDestBufferSize,ref uint nBytesWritten,uint nDesiredSampleRate) +{ + CheckIfUsable(); + nBytesWritten = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamUser_DecompressVoice(m_pSteamUser,pCompressed,cbCompressed,pDestBuffer,cbDestBufferSize,ref nBytesWritten,nDesiredSampleRate); + return result; +} +public override uint GetVoiceOptimalSampleRate() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUser_GetVoiceOptimalSampleRate(m_pSteamUser); + return result; +} +public override uint GetAuthSessionTicket(IntPtr pTicket,int cbMaxTicket,ref uint pcbTicket) +{ + CheckIfUsable(); + pcbTicket = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamUser_GetAuthSessionTicket(m_pSteamUser,pTicket,cbMaxTicket,ref pcbTicket); + return result; +} +public override uint BeginAuthSession(IntPtr pAuthTicket,int cbAuthTicket,ulong steamID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUser_BeginAuthSession(m_pSteamUser,pAuthTicket,cbAuthTicket,steamID); + return result; +} +public override void EndAuthSession(ulong steamID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_EndAuthSession(m_pSteamUser,steamID); +} +public override void CancelAuthTicket(uint hAuthTicket) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_CancelAuthTicket(m_pSteamUser,hAuthTicket); +} +public override uint UserHasLicenseForApp(ulong steamID,uint appID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUser_UserHasLicenseForApp(m_pSteamUser,steamID,appID); + return result; +} +public override bool BIsBehindNAT() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_BIsBehindNAT(m_pSteamUser); + return result; +} +public override void AdvertiseGame(ulong steamIDGameServer,uint unIPServer,char usPortServer) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUser_AdvertiseGame(m_pSteamUser,steamIDGameServer,unIPServer,usPortServer); +} +public override ulong RequestEncryptedAppTicket(IntPtr pDataToInclude,int cbDataToInclude) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUser_RequestEncryptedAppTicket(m_pSteamUser,pDataToInclude,cbDataToInclude); + return result; +} +public override bool GetEncryptedAppTicket(IntPtr pTicket,int cbMaxTicket,ref uint pcbTicket) +{ + CheckIfUsable(); + pcbTicket = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUser_GetEncryptedAppTicket(m_pSteamUser,pTicket,cbMaxTicket,ref pcbTicket); + return result; +} +public override int GetGameBadgeLevel(int nSeries,bool bFoil) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUser_GetGameBadgeLevel(m_pSteamUser,nSeries,bFoil); + return result; +} +public override int GetPlayerSteamLevel() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUser_GetPlayerSteamLevel(m_pSteamUser); + return result; +} +public override ulong RequestStoreAuthURL(string pchRedirectURL) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUser_RequestStoreAuthURL(m_pSteamUser,pchRedirectURL); + return result; +} +public override bool BIsPhoneVerified() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_BIsPhoneVerified(m_pSteamUser); + return result; +} +public override bool BIsTwoFactorEnabled() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_BIsTwoFactorEnabled(m_pSteamUser); + return result; +} +public override bool BIsPhoneIdentifying() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_BIsPhoneIdentifying(m_pSteamUser); + return result; +} +public override bool BIsPhoneRequiringVerification() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUser_BIsPhoneRequiringVerification(m_pSteamUser); + return result; +} +public override ulong GetMarketEligibility() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUser_GetMarketEligibility(m_pSteamUser); + return result; +} +public override ulong GetDurationControl() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUser_GetDurationControl(m_pSteamUser); + return result; +} +} + + +public class CSteamFriends : ISteamFriends +{ +public CSteamFriends(IntPtr SteamFriends) +{ + m_pSteamFriends = SteamFriends; +} +IntPtr m_pSteamFriends; + +public override IntPtr GetIntPtr() { return m_pSteamFriends; } + +private void CheckIfUsable() +{ + if (m_pSteamFriends == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override string GetPersonaName() +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetPersonaName(m_pSteamFriends); + return Marshal.PtrToStringAnsi(result); +} +public override ulong SetPersonaName(string pchPersonaName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_SetPersonaName(m_pSteamFriends,pchPersonaName); + return result; +} +public override uint GetPersonaState() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamFriends_GetPersonaState(m_pSteamFriends); + return result; +} +public override int GetFriendCount(int iFriendFlags) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendCount(m_pSteamFriends,iFriendFlags); + return result; +} +public override ulong GetFriendByIndex(int iFriend,int iFriendFlags) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendByIndex(m_pSteamFriends,iFriend,iFriendFlags); + return result; +} +public override uint GetFriendRelationship(ulong steamIDFriend) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendRelationship(m_pSteamFriends,steamIDFriend); + return result; +} +public override uint GetFriendPersonaState(ulong steamIDFriend) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendPersonaState(m_pSteamFriends,steamIDFriend); + return result; +} +public override string GetFriendPersonaName(ulong steamIDFriend) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendPersonaName(m_pSteamFriends,steamIDFriend); + return Marshal.PtrToStringAnsi(result); +} +public override bool GetFriendGamePlayed(ulong steamIDFriend,out FriendGameInfo_t pFriendGameInfo) +{ + CheckIfUsable(); + pFriendGameInfo = new FriendGameInfo_t(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendGamePlayed(m_pSteamFriends,steamIDFriend,ref pFriendGameInfo); + return result; +} +public override string GetFriendPersonaNameHistory(ulong steamIDFriend,int iPersonaName) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendPersonaNameHistory(m_pSteamFriends,steamIDFriend,iPersonaName); + return Marshal.PtrToStringAnsi(result); +} +public override int GetFriendSteamLevel(ulong steamIDFriend) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendSteamLevel(m_pSteamFriends,steamIDFriend); + return result; +} +public override string GetPlayerNickname(ulong steamIDPlayer) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetPlayerNickname(m_pSteamFriends,steamIDPlayer); + return Marshal.PtrToStringAnsi(result); +} +public override int GetFriendsGroupCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendsGroupCount(m_pSteamFriends); + return result; +} +public override char GetFriendsGroupIDByIndex(int iFG) +{ + CheckIfUsable(); + char result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex(m_pSteamFriends,iFG); + return result; +} +public override string GetFriendsGroupName(char friendsGroupID) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendsGroupName(m_pSteamFriends,friendsGroupID); + return Marshal.PtrToStringAnsi(result); +} +public override int GetFriendsGroupMembersCount(char friendsGroupID) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendsGroupMembersCount(m_pSteamFriends,friendsGroupID); + return result; +} +public override void GetFriendsGroupMembersList(char friendsGroupID,out CSteamID [] pOutSteamIDMembers) +{ + CheckIfUsable(); + int nMembersCount = GetFriendsGroupMembersCount (friendsGroupID); + pOutSteamIDMembers = new CSteamID[nMembersCount]; + NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendsGroupMembersList(m_pSteamFriends,friendsGroupID,pOutSteamIDMembers,nMembersCount); +} +public override bool HasFriend(ulong steamIDFriend,int iFriendFlags) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_HasFriend(m_pSteamFriends,steamIDFriend,iFriendFlags); + return result; +} +public override int GetClanCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanCount(m_pSteamFriends); + return result; +} +public override ulong GetClanByIndex(int iClan) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanByIndex(m_pSteamFriends,iClan); + return result; +} +public override string GetClanName(ulong steamIDClan) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanName(m_pSteamFriends,steamIDClan); + return Marshal.PtrToStringAnsi(result); +} +public override string GetClanTag(ulong steamIDClan) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanTag(m_pSteamFriends,steamIDClan); + return Marshal.PtrToStringAnsi(result); +} +public override bool GetClanActivityCounts(ulong steamIDClan,ref int pnOnline,ref int pnInGame,ref int pnChatting) +{ + CheckIfUsable(); + pnOnline = 0; + pnInGame = 0; + pnChatting = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanActivityCounts(m_pSteamFriends,steamIDClan,ref pnOnline,ref pnInGame,ref pnChatting); + return result; +} +public override ulong DownloadClanActivityCounts(CSteamID [] psteamIDClans) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_DownloadClanActivityCounts(m_pSteamFriends,psteamIDClans,(int) psteamIDClans.Length); + return result; +} +public override int GetFriendCountFromSource(ulong steamIDSource) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendCountFromSource(m_pSteamFriends,steamIDSource); + return result; +} +public override ulong GetFriendFromSourceByIndex(ulong steamIDSource,int iFriend) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendFromSourceByIndex(m_pSteamFriends,steamIDSource,iFriend); + return result; +} +public override bool IsUserInSource(ulong steamIDUser,ulong steamIDSource) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_IsUserInSource(m_pSteamFriends,steamIDUser,steamIDSource); + return result; +} +public override void SetInGameVoiceSpeaking(ulong steamIDUser,bool bSpeaking) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_SetInGameVoiceSpeaking(m_pSteamFriends,steamIDUser,bSpeaking); +} +public override void ActivateGameOverlay(string pchDialog) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_ActivateGameOverlay(m_pSteamFriends,pchDialog); +} +public override void ActivateGameOverlayToUser(string pchDialog,ulong steamID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_ActivateGameOverlayToUser(m_pSteamFriends,pchDialog,steamID); +} +public override void ActivateGameOverlayToWebPage(string pchURL,uint eMode) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage(m_pSteamFriends,pchURL,eMode); +} +public override void ActivateGameOverlayToStore(uint nAppID,char eFlag) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_ActivateGameOverlayToStore(m_pSteamFriends,nAppID,eFlag); +} +public override void SetPlayedWith(ulong steamIDUserPlayedWith) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_SetPlayedWith(m_pSteamFriends,steamIDUserPlayedWith); +} +public override void ActivateGameOverlayInviteDialog(ulong steamIDLobby) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog(m_pSteamFriends,steamIDLobby); +} +public override int GetSmallFriendAvatar(ulong steamIDFriend) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetSmallFriendAvatar(m_pSteamFriends,steamIDFriend); + return result; +} +public override int GetMediumFriendAvatar(ulong steamIDFriend) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetMediumFriendAvatar(m_pSteamFriends,steamIDFriend); + return result; +} +public override int GetLargeFriendAvatar(ulong steamIDFriend) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetLargeFriendAvatar(m_pSteamFriends,steamIDFriend); + return result; +} +public override bool RequestUserInformation(ulong steamIDUser,bool bRequireNameOnly) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_RequestUserInformation(m_pSteamFriends,steamIDUser,bRequireNameOnly); + return result; +} +public override ulong RequestClanOfficerList(ulong steamIDClan) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_RequestClanOfficerList(m_pSteamFriends,steamIDClan); + return result; +} +public override ulong GetClanOwner(ulong steamIDClan) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanOwner(m_pSteamFriends,steamIDClan); + return result; +} +public override int GetClanOfficerCount(ulong steamIDClan) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanOfficerCount(m_pSteamFriends,steamIDClan); + return result; +} +public override ulong GetClanOfficerByIndex(ulong steamIDClan,int iOfficer) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanOfficerByIndex(m_pSteamFriends,steamIDClan,iOfficer); + return result; +} +public override uint GetUserRestrictions() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamFriends_GetUserRestrictions(m_pSteamFriends); + return result; +} +public override bool SetRichPresence(string pchKey,string pchValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_SetRichPresence(m_pSteamFriends,pchKey,pchValue); + return result; +} +public override void ClearRichPresence() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_ClearRichPresence(m_pSteamFriends); +} +public override string GetFriendRichPresence(ulong steamIDFriend,string pchKey) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendRichPresence(m_pSteamFriends,steamIDFriend,pchKey); + return Marshal.PtrToStringAnsi(result); +} +public override int GetFriendRichPresenceKeyCount(ulong steamIDFriend) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount(m_pSteamFriends,steamIDFriend); + return result; +} +public override string GetFriendRichPresenceKeyByIndex(ulong steamIDFriend,int iKey) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex(m_pSteamFriends,steamIDFriend,iKey); + return Marshal.PtrToStringAnsi(result); +} +public override void RequestFriendRichPresence(ulong steamIDFriend) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamFriends_RequestFriendRichPresence(m_pSteamFriends,steamIDFriend); +} +public override bool InviteUserToGame(ulong steamIDFriend,string pchConnectString) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_InviteUserToGame(m_pSteamFriends,steamIDFriend,pchConnectString); + return result; +} +public override int GetCoplayFriendCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetCoplayFriendCount(m_pSteamFriends); + return result; +} +public override ulong GetCoplayFriend(int iCoplayFriend) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetCoplayFriend(m_pSteamFriends,iCoplayFriend); + return result; +} +public override int GetFriendCoplayTime(ulong steamIDFriend) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendCoplayTime(m_pSteamFriends,steamIDFriend); + return result; +} +public override uint GetFriendCoplayGame(ulong steamIDFriend) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendCoplayGame(m_pSteamFriends,steamIDFriend); + return result; +} +public override ulong JoinClanChatRoom(ulong steamIDClan) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_JoinClanChatRoom(m_pSteamFriends,steamIDClan); + return result; +} +public override bool LeaveClanChatRoom(ulong steamIDClan) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_LeaveClanChatRoom(m_pSteamFriends,steamIDClan); + return result; +} +public override int GetClanChatMemberCount(ulong steamIDClan) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanChatMemberCount(m_pSteamFriends,steamIDClan); + return result; +} +public override ulong GetChatMemberByIndex(ulong steamIDClan,int iUser) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetChatMemberByIndex(m_pSteamFriends,steamIDClan,iUser); + return result; +} +public override bool SendClanChatMessage(ulong steamIDClanChat,string pchText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_SendClanChatMessage(m_pSteamFriends,steamIDClanChat,pchText); + return result; +} +public override int GetClanChatMessage(ulong steamIDClanChat,int iMessage,IntPtr prgchText,int cchTextMax,ref uint peChatEntryType,out CSteamID psteamidChatter) +{ + CheckIfUsable(); + peChatEntryType = 0; + psteamidChatter = new CSteamID(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetClanChatMessage(m_pSteamFriends,steamIDClanChat,iMessage,prgchText,cchTextMax,ref peChatEntryType,ref psteamidChatter); + return result; +} +public override bool IsClanChatAdmin(ulong steamIDClanChat,ulong steamIDUser) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_IsClanChatAdmin(m_pSteamFriends,steamIDClanChat,steamIDUser); + return result; +} +public override bool IsClanChatWindowOpenInSteam(ulong steamIDClanChat) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam(m_pSteamFriends,steamIDClanChat); + return result; +} +public override bool OpenClanChatWindowInSteam(ulong steamIDClanChat) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_OpenClanChatWindowInSteam(m_pSteamFriends,steamIDClanChat); + return result; +} +public override bool CloseClanChatWindowInSteam(ulong steamIDClanChat) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_CloseClanChatWindowInSteam(m_pSteamFriends,steamIDClanChat); + return result; +} +public override bool SetListenForFriendsMessages(bool bInterceptEnabled) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_SetListenForFriendsMessages(m_pSteamFriends,bInterceptEnabled); + return result; +} +public override bool ReplyToFriendMessage(ulong steamIDFriend,string pchMsgToSend) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_ReplyToFriendMessage(m_pSteamFriends,steamIDFriend,pchMsgToSend); + return result; +} +public override int GetFriendMessage(ulong steamIDFriend,int iMessageID,IntPtr pvData,int cubData,ref uint peChatEntryType) +{ + CheckIfUsable(); + peChatEntryType = 0; + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFriendMessage(m_pSteamFriends,steamIDFriend,iMessageID,pvData,cubData,ref peChatEntryType); + return result; +} +public override ulong GetFollowerCount(ulong steamID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_GetFollowerCount(m_pSteamFriends,steamID); + return result; +} +public override ulong IsFollowing(ulong steamID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_IsFollowing(m_pSteamFriends,steamID); + return result; +} +public override ulong EnumerateFollowingList(uint unStartIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamFriends_EnumerateFollowingList(m_pSteamFriends,unStartIndex); + return result; +} +public override bool IsClanPublic(ulong steamIDClan) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_IsClanPublic(m_pSteamFriends,steamIDClan); + return result; +} +public override bool IsClanOfficialGameGroup(ulong steamIDClan) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamFriends_IsClanOfficialGameGroup(m_pSteamFriends,steamIDClan); + return result; +} +public override int GetNumChatsWithUnreadPriorityMessages() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages(m_pSteamFriends); + return result; +} +} + + +public class CSteamUtils : ISteamUtils +{ +public CSteamUtils(IntPtr SteamUtils) +{ + m_pSteamUtils = SteamUtils; +} +IntPtr m_pSteamUtils; + +public override IntPtr GetIntPtr() { return m_pSteamUtils; } + +private void CheckIfUsable() +{ + if (m_pSteamUtils == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint GetSecondsSinceAppActive() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUtils_GetSecondsSinceAppActive(m_pSteamUtils); + return result; +} +public override uint GetSecondsSinceComputerActive() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUtils_GetSecondsSinceComputerActive(m_pSteamUtils); + return result; +} +public override int GetConnectedUniverse() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUtils_GetConnectedUniverse(m_pSteamUtils); + return result; +} +public override uint GetServerRealTime() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUtils_GetServerRealTime(m_pSteamUtils); + return result; +} +public override string GetIPCountry() +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamUtils_GetIPCountry(m_pSteamUtils); + return Marshal.PtrToStringAnsi(result); +} +public override bool GetImageSize(int iImage,ref uint pnWidth,ref uint pnHeight) +{ + CheckIfUsable(); + pnWidth = 0; + pnHeight = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_GetImageSize(m_pSteamUtils,iImage,ref pnWidth,ref pnHeight); + return result; +} +public override bool GetImageRGBA(int iImage,IntPtr pubDest,int nDestBufferSize) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_GetImageRGBA(m_pSteamUtils,iImage,pubDest,nDestBufferSize); + return result; +} +public override bool GetCSERIPPort(ref uint unIP,ref char usPort) +{ + CheckIfUsable(); + unIP = 0; + usPort = (char) 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_GetCSERIPPort(m_pSteamUtils,ref unIP,ref usPort); + return result; +} +public override byte GetCurrentBatteryPower() +{ + CheckIfUsable(); + byte result = NativeEntrypoints.SteamAPI_ISteamUtils_GetCurrentBatteryPower(m_pSteamUtils); + return result; +} +public override uint GetAppID() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUtils_GetAppID(m_pSteamUtils); + return result; +} +public override void SetOverlayNotificationPosition(uint eNotificationPosition) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUtils_SetOverlayNotificationPosition(m_pSteamUtils,eNotificationPosition); +} +public override bool IsAPICallCompleted(ulong hSteamAPICall,ref bool pbFailed) +{ + CheckIfUsable(); + pbFailed = false; + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_IsAPICallCompleted(m_pSteamUtils,hSteamAPICall,ref pbFailed); + return result; +} +public override int GetAPICallFailureReason(ulong hSteamAPICall) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUtils_GetAPICallFailureReason(m_pSteamUtils,hSteamAPICall); + return result; +} +public override bool GetAPICallResult(ulong hSteamAPICall,IntPtr pCallback,int cubCallback,int iCallbackExpected,ref bool pbFailed) +{ + CheckIfUsable(); + pbFailed = false; + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_GetAPICallResult(m_pSteamUtils,hSteamAPICall,pCallback,cubCallback,iCallbackExpected,ref pbFailed); + return result; +} +public override uint GetIPCCallCount() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUtils_GetIPCCallCount(m_pSteamUtils); + return result; +} +public override void SetWarningMessageHook(IntPtr pFunction) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUtils_SetWarningMessageHook(m_pSteamUtils,pFunction); +} +public override bool IsOverlayEnabled() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_IsOverlayEnabled(m_pSteamUtils); + return result; +} +public override bool BOverlayNeedsPresent() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_BOverlayNeedsPresent(m_pSteamUtils); + return result; +} +public override ulong CheckFileSignature(string szFileName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUtils_CheckFileSignature(m_pSteamUtils,szFileName); + return result; +} +public override bool ShowGamepadTextInput(int eInputMode,int eLineInputMode,string pchDescription,uint unCharMax,string pchExistingText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_ShowGamepadTextInput(m_pSteamUtils,eInputMode,eLineInputMode,pchDescription,unCharMax,pchExistingText); + return result; +} +public override uint GetEnteredGamepadTextLength() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUtils_GetEnteredGamepadTextLength(m_pSteamUtils); + return result; +} +public override bool GetEnteredGamepadTextInput(string pchText,uint cchText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_GetEnteredGamepadTextInput(m_pSteamUtils,pchText,cchText); + return result; +} +public override string GetSteamUILanguage() +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamUtils_GetSteamUILanguage(m_pSteamUtils); + return Marshal.PtrToStringAnsi(result); +} +public override bool IsSteamRunningInVR() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_IsSteamRunningInVR(m_pSteamUtils); + return result; +} +public override void SetOverlayNotificationInset(int nHorizontalInset,int nVerticalInset) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUtils_SetOverlayNotificationInset(m_pSteamUtils,nHorizontalInset,nVerticalInset); +} +public override bool IsSteamInBigPictureMode() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_IsSteamInBigPictureMode(m_pSteamUtils); + return result; +} +public override void StartVRDashboard() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUtils_StartVRDashboard(m_pSteamUtils); +} +public override bool IsVRHeadsetStreamingEnabled() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled(m_pSteamUtils); + return result; +} +public override void SetVRHeadsetStreamingEnabled(bool bEnabled) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled(m_pSteamUtils,bEnabled); +} +public override bool IsSteamChinaLauncher() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_IsSteamChinaLauncher(m_pSteamUtils); + return result; +} +public override bool InitFilterText() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUtils_InitFilterText(m_pSteamUtils); + return result; +} +public override int FilterText(string pchOutFilteredText,uint nByteSizeOutFilteredText,string pchInputMessage,bool bLegalOnly) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUtils_FilterText(m_pSteamUtils,pchOutFilteredText,nByteSizeOutFilteredText,pchInputMessage,bLegalOnly); + return result; +} +} + + +public class CSteamMatchmaking : ISteamMatchmaking +{ +public CSteamMatchmaking(IntPtr SteamMatchmaking) +{ + m_pSteamMatchmaking = SteamMatchmaking; +} +IntPtr m_pSteamMatchmaking; + +public override IntPtr GetIntPtr() { return m_pSteamMatchmaking; } + +private void CheckIfUsable() +{ + if (m_pSteamMatchmaking == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override int GetFavoriteGameCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetFavoriteGameCount(m_pSteamMatchmaking); + return result; +} +public override bool GetFavoriteGame(int iGame,ref uint pnAppID,ref uint pnIP,ref char pnConnPort,ref char pnQueryPort,ref uint punFlags,ref uint pRTime32LastPlayedOnServer) +{ + CheckIfUsable(); + pnAppID = 0; + pnIP = 0; + pnConnPort = (char) 0; + pnQueryPort = (char) 0; + punFlags = 0; + pRTime32LastPlayedOnServer = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetFavoriteGame(m_pSteamMatchmaking,iGame,ref pnAppID,ref pnIP,ref pnConnPort,ref pnQueryPort,ref punFlags,ref pRTime32LastPlayedOnServer); + return result; +} +public override int AddFavoriteGame(uint nAppID,uint nIP,char nConnPort,char nQueryPort,uint unFlags,uint rTime32LastPlayedOnServer) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddFavoriteGame(m_pSteamMatchmaking,nAppID,nIP,nConnPort,nQueryPort,unFlags,rTime32LastPlayedOnServer); + return result; +} +public override bool RemoveFavoriteGame(uint nAppID,uint nIP,char nConnPort,char nQueryPort,uint unFlags) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_RemoveFavoriteGame(m_pSteamMatchmaking,nAppID,nIP,nConnPort,nQueryPort,unFlags); + return result; +} +public override ulong RequestLobbyList() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_RequestLobbyList(m_pSteamMatchmaking); + return result; +} +public override void AddRequestLobbyListStringFilter(string pchKeyToMatch,string pchValueToMatch,uint eComparisonType) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter(m_pSteamMatchmaking,pchKeyToMatch,pchValueToMatch,eComparisonType); +} +public override void AddRequestLobbyListNumericalFilter(string pchKeyToMatch,int nValueToMatch,uint eComparisonType) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter(m_pSteamMatchmaking,pchKeyToMatch,nValueToMatch,eComparisonType); +} +public override void AddRequestLobbyListNearValueFilter(string pchKeyToMatch,int nValueToBeCloseTo) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter(m_pSteamMatchmaking,pchKeyToMatch,nValueToBeCloseTo); +} +public override void AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable(m_pSteamMatchmaking,nSlotsAvailable); +} +public override void AddRequestLobbyListDistanceFilter(uint eLobbyDistanceFilter) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter(m_pSteamMatchmaking,eLobbyDistanceFilter); +} +public override void AddRequestLobbyListResultCountFilter(int cMaxResults) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter(m_pSteamMatchmaking,cMaxResults); +} +public override void AddRequestLobbyListCompatibleMembersFilter(ulong steamIDLobby) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter(m_pSteamMatchmaking,steamIDLobby); +} +public override ulong GetLobbyByIndex(int iLobby) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyByIndex(m_pSteamMatchmaking,iLobby); + return result; +} +public override ulong CreateLobby(uint eLobbyType,int cMaxMembers) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_CreateLobby(m_pSteamMatchmaking,eLobbyType,cMaxMembers); + return result; +} +public override ulong JoinLobby(ulong steamIDLobby) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_JoinLobby(m_pSteamMatchmaking,steamIDLobby); + return result; +} +public override void LeaveLobby(ulong steamIDLobby) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_LeaveLobby(m_pSteamMatchmaking,steamIDLobby); +} +public override bool InviteUserToLobby(ulong steamIDLobby,ulong steamIDInvitee) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_InviteUserToLobby(m_pSteamMatchmaking,steamIDLobby,steamIDInvitee); + return result; +} +public override int GetNumLobbyMembers(ulong steamIDLobby) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetNumLobbyMembers(m_pSteamMatchmaking,steamIDLobby); + return result; +} +public override ulong GetLobbyMemberByIndex(ulong steamIDLobby,int iMember) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex(m_pSteamMatchmaking,steamIDLobby,iMember); + return result; +} +public override string GetLobbyData(ulong steamIDLobby,string pchKey) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyData(m_pSteamMatchmaking,steamIDLobby,pchKey); + return Marshal.PtrToStringAnsi(result); +} +public override bool SetLobbyData(ulong steamIDLobby,string pchKey,string pchValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyData(m_pSteamMatchmaking,steamIDLobby,pchKey,pchValue); + return result; +} +public override int GetLobbyDataCount(ulong steamIDLobby) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyDataCount(m_pSteamMatchmaking,steamIDLobby); + return result; +} +public override bool GetLobbyDataByIndex(ulong steamIDLobby,int iLobbyData,string pchKey,int cchKeyBufferSize,string pchValue,int cchValueBufferSize) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex(m_pSteamMatchmaking,steamIDLobby,iLobbyData,pchKey,cchKeyBufferSize,pchValue,cchValueBufferSize); + return result; +} +public override bool DeleteLobbyData(ulong steamIDLobby,string pchKey) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_DeleteLobbyData(m_pSteamMatchmaking,steamIDLobby,pchKey); + return result; +} +public override string GetLobbyMemberData(ulong steamIDLobby,ulong steamIDUser,string pchKey) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyMemberData(m_pSteamMatchmaking,steamIDLobby,steamIDUser,pchKey); + return Marshal.PtrToStringAnsi(result); +} +public override void SetLobbyMemberData(ulong steamIDLobby,string pchKey,string pchValue) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyMemberData(m_pSteamMatchmaking,steamIDLobby,pchKey,pchValue); +} +public override bool SendLobbyChatMsg(ulong steamIDLobby,IntPtr pvMsgBody,int cubMsgBody) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SendLobbyChatMsg(m_pSteamMatchmaking,steamIDLobby,pvMsgBody,cubMsgBody); + return result; +} +public override int GetLobbyChatEntry(ulong steamIDLobby,int iChatID,out CSteamID pSteamIDUser,IntPtr pvData,int cubData,ref uint peChatEntryType) +{ + CheckIfUsable(); + pSteamIDUser = new CSteamID(); + peChatEntryType = 0; + int result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyChatEntry(m_pSteamMatchmaking,steamIDLobby,iChatID,ref pSteamIDUser,pvData,cubData,ref peChatEntryType); + return result; +} +public override bool RequestLobbyData(ulong steamIDLobby) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_RequestLobbyData(m_pSteamMatchmaking,steamIDLobby); + return result; +} +public override void SetLobbyGameServer(ulong steamIDLobby,uint unGameServerIP,char unGameServerPort,ulong steamIDGameServer) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyGameServer(m_pSteamMatchmaking,steamIDLobby,unGameServerIP,unGameServerPort,steamIDGameServer); +} +public override bool GetLobbyGameServer(ulong steamIDLobby,ref uint punGameServerIP,ref char punGameServerPort,out CSteamID psteamIDGameServer) +{ + CheckIfUsable(); + punGameServerIP = 0; + punGameServerPort = (char) 0; + psteamIDGameServer = new CSteamID(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyGameServer(m_pSteamMatchmaking,steamIDLobby,ref punGameServerIP,ref punGameServerPort,ref psteamIDGameServer); + return result; +} +public override bool SetLobbyMemberLimit(ulong steamIDLobby,int cMaxMembers) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit(m_pSteamMatchmaking,steamIDLobby,cMaxMembers); + return result; +} +public override int GetLobbyMemberLimit(ulong steamIDLobby) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit(m_pSteamMatchmaking,steamIDLobby); + return result; +} +public override bool SetLobbyType(ulong steamIDLobby,uint eLobbyType) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyType(m_pSteamMatchmaking,steamIDLobby,eLobbyType); + return result; +} +public override bool SetLobbyJoinable(ulong steamIDLobby,bool bLobbyJoinable) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyJoinable(m_pSteamMatchmaking,steamIDLobby,bLobbyJoinable); + return result; +} +public override ulong GetLobbyOwner(ulong steamIDLobby) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_GetLobbyOwner(m_pSteamMatchmaking,steamIDLobby); + return result; +} +public override bool SetLobbyOwner(ulong steamIDLobby,ulong steamIDNewOwner) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLobbyOwner(m_pSteamMatchmaking,steamIDLobby,steamIDNewOwner); + return result; +} +public override bool SetLinkedLobby(ulong steamIDLobby,ulong steamIDLobbyDependent) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmaking_SetLinkedLobby(m_pSteamMatchmaking,steamIDLobby,steamIDLobbyDependent); + return result; +} +} + + +public class CSteamMatchmakingServerListResponse : ISteamMatchmakingServerListResponse +{ +public CSteamMatchmakingServerListResponse(IntPtr SteamMatchmakingServerListResponse) +{ + m_pSteamMatchmakingServerListResponse = SteamMatchmakingServerListResponse; +} +IntPtr m_pSteamMatchmakingServerListResponse; + +public override IntPtr GetIntPtr() { return m_pSteamMatchmakingServerListResponse; } + +private void CheckIfUsable() +{ + if (m_pSteamMatchmakingServerListResponse == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override void ServerResponded(uint hRequest,int iServer) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded(m_pSteamMatchmakingServerListResponse,hRequest,iServer); +} +public override void ServerFailedToRespond(uint hRequest,int iServer) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond(m_pSteamMatchmakingServerListResponse,hRequest,iServer); +} +public override void RefreshComplete(uint hRequest,uint response) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete(m_pSteamMatchmakingServerListResponse,hRequest,response); +} +} + + +public class CSteamMatchmakingPingResponse : ISteamMatchmakingPingResponse +{ +public CSteamMatchmakingPingResponse(IntPtr SteamMatchmakingPingResponse) +{ + m_pSteamMatchmakingPingResponse = SteamMatchmakingPingResponse; +} +IntPtr m_pSteamMatchmakingPingResponse; + +public override IntPtr GetIntPtr() { return m_pSteamMatchmakingPingResponse; } + +private void CheckIfUsable() +{ + if (m_pSteamMatchmakingPingResponse == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override void ServerResponded(IntPtr server) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingPingResponse_ServerResponded(m_pSteamMatchmakingPingResponse,server); +} +public override void ServerFailedToRespond() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond(m_pSteamMatchmakingPingResponse); +} +} + + +public class CSteamMatchmakingPlayersResponse : ISteamMatchmakingPlayersResponse +{ +public CSteamMatchmakingPlayersResponse(IntPtr SteamMatchmakingPlayersResponse) +{ + m_pSteamMatchmakingPlayersResponse = SteamMatchmakingPlayersResponse; +} +IntPtr m_pSteamMatchmakingPlayersResponse; + +public override IntPtr GetIntPtr() { return m_pSteamMatchmakingPlayersResponse; } + +private void CheckIfUsable() +{ + if (m_pSteamMatchmakingPlayersResponse == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override void AddPlayerToList(string pchName,int nScore,float flTimePlayed) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList(m_pSteamMatchmakingPlayersResponse,pchName,nScore,flTimePlayed); +} +public override void PlayersFailedToRespond() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond(m_pSteamMatchmakingPlayersResponse); +} +public override void PlayersRefreshComplete() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete(m_pSteamMatchmakingPlayersResponse); +} +} + + +public class CSteamMatchmakingRulesResponse : ISteamMatchmakingRulesResponse +{ +public CSteamMatchmakingRulesResponse(IntPtr SteamMatchmakingRulesResponse) +{ + m_pSteamMatchmakingRulesResponse = SteamMatchmakingRulesResponse; +} +IntPtr m_pSteamMatchmakingRulesResponse; + +public override IntPtr GetIntPtr() { return m_pSteamMatchmakingRulesResponse; } + +private void CheckIfUsable() +{ + if (m_pSteamMatchmakingRulesResponse == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override void RulesResponded(string pchRule,string pchValue) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded(m_pSteamMatchmakingRulesResponse,pchRule,pchValue); +} +public override void RulesFailedToRespond() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond(m_pSteamMatchmakingRulesResponse); +} +public override void RulesRefreshComplete() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete(m_pSteamMatchmakingRulesResponse); +} +} + + +public class CSteamMatchmakingServers : ISteamMatchmakingServers +{ +public CSteamMatchmakingServers(IntPtr SteamMatchmakingServers) +{ + m_pSteamMatchmakingServers = SteamMatchmakingServers; +} +IntPtr m_pSteamMatchmakingServers; + +public override IntPtr GetIntPtr() { return m_pSteamMatchmakingServers; } + +private void CheckIfUsable() +{ + if (m_pSteamMatchmakingServers == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint RequestInternetServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RequestInternetServerList(m_pSteamMatchmakingServers,iApp,ppchFilters,(uint) ppchFilters.Length,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint RequestLANServerList(uint iApp,ISteamMatchmakingServerListResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RequestLANServerList(m_pSteamMatchmakingServers,iApp,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint RequestFriendsServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList(m_pSteamMatchmakingServers,iApp,ppchFilters,(uint) ppchFilters.Length,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint RequestFavoritesServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList(m_pSteamMatchmakingServers,iApp,ppchFilters,(uint) ppchFilters.Length,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint RequestHistoryServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList(m_pSteamMatchmakingServers,iApp,ppchFilters,(uint) ppchFilters.Length,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint RequestSpectatorServerList(uint iApp,IntPtr [] ppchFilters,ISteamMatchmakingServerListResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList(m_pSteamMatchmakingServers,iApp,ppchFilters,(uint) ppchFilters.Length,pRequestServersResponse.GetIntPtr()); + return result; +} +public override void ReleaseRequest(uint hServerListRequest) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_ReleaseRequest(m_pSteamMatchmakingServers,hServerListRequest); +} +public override gameserveritem_t GetServerDetails(uint hRequest,int iServer) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_GetServerDetails(m_pSteamMatchmakingServers,hRequest,iServer); + return (gameserveritem_t) Marshal.PtrToStructure(result, typeof(gameserveritem_t)); +} +public override void CancelQuery(uint hRequest) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_CancelQuery(m_pSteamMatchmakingServers,hRequest); +} +public override void RefreshQuery(uint hRequest) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RefreshQuery(m_pSteamMatchmakingServers,hRequest); +} +public override bool IsRefreshing(uint hRequest) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_IsRefreshing(m_pSteamMatchmakingServers,hRequest); + return result; +} +public override int GetServerCount(uint hRequest) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_GetServerCount(m_pSteamMatchmakingServers,hRequest); + return result; +} +public override void RefreshServer(uint hRequest,int iServer) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_RefreshServer(m_pSteamMatchmakingServers,hRequest,iServer); +} +public override uint PingServer(uint unIP,char usPort,ISteamMatchmakingPingResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_PingServer(m_pSteamMatchmakingServers,unIP,usPort,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint PlayerDetails(uint unIP,char usPort,ISteamMatchmakingPlayersResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_PlayerDetails(m_pSteamMatchmakingServers,unIP,usPort,pRequestServersResponse.GetIntPtr()); + return result; +} +public override uint ServerRules(uint unIP,char usPort,ISteamMatchmakingRulesResponse pRequestServersResponse) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_ServerRules(m_pSteamMatchmakingServers,unIP,usPort,pRequestServersResponse.GetIntPtr()); + return result; +} +public override void CancelServerQuery(uint hServerQuery) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMatchmakingServers_CancelServerQuery(m_pSteamMatchmakingServers,hServerQuery); +} +} + + +public class CSteamGameSearch : ISteamGameSearch +{ +public CSteamGameSearch(IntPtr SteamGameSearch) +{ + m_pSteamGameSearch = SteamGameSearch; +} +IntPtr m_pSteamGameSearch; + +public override IntPtr GetIntPtr() { return m_pSteamGameSearch; } + +private void CheckIfUsable() +{ + if (m_pSteamGameSearch == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint AddGameSearchParams(string pchKeyToFind,string pchValuesToFind) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_AddGameSearchParams(m_pSteamGameSearch,pchKeyToFind,pchValuesToFind); + return result; +} +public override uint SearchForGameWithLobby(ulong steamIDLobby,int nPlayerMin,int nPlayerMax) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_SearchForGameWithLobby(m_pSteamGameSearch,steamIDLobby,nPlayerMin,nPlayerMax); + return result; +} +public override uint SearchForGameSolo(int nPlayerMin,int nPlayerMax) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_SearchForGameSolo(m_pSteamGameSearch,nPlayerMin,nPlayerMax); + return result; +} +public override uint AcceptGame() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_AcceptGame(m_pSteamGameSearch); + return result; +} +public override uint DeclineGame() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_DeclineGame(m_pSteamGameSearch); + return result; +} +public override uint RetrieveConnectionDetails(ulong steamIDHost,string pchConnectionDetails,int cubConnectionDetails) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_RetrieveConnectionDetails(m_pSteamGameSearch,steamIDHost,pchConnectionDetails,cubConnectionDetails); + return result; +} +public override uint EndGameSearch() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_EndGameSearch(m_pSteamGameSearch); + return result; +} +public override uint SetGameHostParams(string pchKey,string pchValue) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_SetGameHostParams(m_pSteamGameSearch,pchKey,pchValue); + return result; +} +public override uint SetConnectionDetails(string pchConnectionDetails,int cubConnectionDetails) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_SetConnectionDetails(m_pSteamGameSearch,pchConnectionDetails,cubConnectionDetails); + return result; +} +public override uint RequestPlayersForGame(int nPlayerMin,int nPlayerMax,int nMaxTeamSize) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_RequestPlayersForGame(m_pSteamGameSearch,nPlayerMin,nPlayerMax,nMaxTeamSize); + return result; +} +public override uint HostConfirmGameStart(ulong ullUniqueGameID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_HostConfirmGameStart(m_pSteamGameSearch,ullUniqueGameID); + return result; +} +public override uint CancelRequestPlayersForGame() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame(m_pSteamGameSearch); + return result; +} +public override uint SubmitPlayerResult(ulong ullUniqueGameID,ulong steamIDPlayer,uint EPlayerResult) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_SubmitPlayerResult(m_pSteamGameSearch,ullUniqueGameID,steamIDPlayer,EPlayerResult); + return result; +} +public override uint EndGame(ulong ullUniqueGameID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameSearch_EndGame(m_pSteamGameSearch,ullUniqueGameID); + return result; +} +} + + +public class CSteamParties : ISteamParties +{ +public CSteamParties(IntPtr SteamParties) +{ + m_pSteamParties = SteamParties; +} +IntPtr m_pSteamParties; + +public override IntPtr GetIntPtr() { return m_pSteamParties; } + +private void CheckIfUsable() +{ + if (m_pSteamParties == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint GetNumActiveBeacons() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamParties_GetNumActiveBeacons(m_pSteamParties); + return result; +} +public override ulong GetBeaconByIndex(uint unIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamParties_GetBeaconByIndex(m_pSteamParties,unIndex); + return result; +} +public override bool GetBeaconDetails(ulong ulBeaconID,ref CSteamID pSteamIDBeaconOwner,out SteamPartyBeaconLocation_t pLocation,out string pchMetadata) +{ + CheckIfUsable(); + pLocation = new SteamPartyBeaconLocation_t(); + int cchMetadata = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamParties_GetBeaconDetails(m_pSteamParties,ulBeaconID,ref pSteamIDBeaconOwner,ref pLocation,null,ref cchMetadata); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder((int)cchMetadata); + result = NativeEntrypoints.SteamAPI_ISteamParties_GetBeaconDetails(m_pSteamParties,ulBeaconID,ref pSteamIDBeaconOwner,ref pLocation,pStrBuffer1,ref cchMetadata); + pchMetadata = pStrBuffer1.ToString(); + return result; +} +public override ulong JoinParty(ulong ulBeaconID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamParties_JoinParty(m_pSteamParties,ulBeaconID); + return result; +} +public override bool GetNumAvailableBeaconLocations(ref uint puNumLocations) +{ + CheckIfUsable(); + puNumLocations = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamParties_GetNumAvailableBeaconLocations(m_pSteamParties,ref puNumLocations); + return result; +} +public override bool GetAvailableBeaconLocations(ref SteamPartyBeaconLocation_t pLocationList,uint uMaxNumLocations) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParties_GetAvailableBeaconLocations(m_pSteamParties,ref pLocationList,uMaxNumLocations); + return result; +} +public override ulong CreateBeacon(uint unOpenSlots,ref SteamPartyBeaconLocation_t pBeaconLocation,string pchConnectString,string pchMetadata) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamParties_CreateBeacon(m_pSteamParties,unOpenSlots,ref pBeaconLocation,pchConnectString,pchMetadata); + return result; +} +public override void OnReservationCompleted(ulong ulBeacon,ulong steamIDUser) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamParties_OnReservationCompleted(m_pSteamParties,ulBeacon,steamIDUser); +} +public override void CancelReservation(ulong ulBeacon,ulong steamIDUser) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamParties_CancelReservation(m_pSteamParties,ulBeacon,steamIDUser); +} +public override ulong ChangeNumOpenSlots(ulong ulBeacon,uint unOpenSlots) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamParties_ChangeNumOpenSlots(m_pSteamParties,ulBeacon,unOpenSlots); + return result; +} +public override bool DestroyBeacon(ulong ulBeacon) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParties_DestroyBeacon(m_pSteamParties,ulBeacon); + return result; +} +public override bool GetBeaconLocationData(SteamPartyBeaconLocation_t BeaconLocation,uint eData,out string pchDataStringOut) +{ + CheckIfUsable(); + int cchDataStringOut = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamParties_GetBeaconLocationData(m_pSteamParties,BeaconLocation,eData,null,ref cchDataStringOut); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder((int)cchDataStringOut); + result = NativeEntrypoints.SteamAPI_ISteamParties_GetBeaconLocationData(m_pSteamParties,BeaconLocation,eData,pStrBuffer1,ref cchDataStringOut); + pchDataStringOut = pStrBuffer1.ToString(); + return result; +} +} + + +public class CSteamRemoteStorage : ISteamRemoteStorage +{ +public CSteamRemoteStorage(IntPtr SteamRemoteStorage) +{ + m_pSteamRemoteStorage = SteamRemoteStorage; +} +IntPtr m_pSteamRemoteStorage; + +public override IntPtr GetIntPtr() { return m_pSteamRemoteStorage; } + +private void CheckIfUsable() +{ + if (m_pSteamRemoteStorage == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool FileWrite(string pchFile,IntPtr pvData,int cubData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileWrite(m_pSteamRemoteStorage,pchFile,pvData,cubData); + return result; +} +public override int FileRead(string pchFile,IntPtr pvData,int cubDataToRead) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileRead(m_pSteamRemoteStorage,pchFile,pvData,cubDataToRead); + return result; +} +public override ulong FileWriteAsync(string pchFile,IntPtr pvData,uint cubData) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileWriteAsync(m_pSteamRemoteStorage,pchFile,pvData,cubData); + return result; +} +public override ulong FileReadAsync(string pchFile,uint nOffset,uint cubToRead) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileReadAsync(m_pSteamRemoteStorage,pchFile,nOffset,cubToRead); + return result; +} +public override bool FileReadAsyncComplete(ulong hReadCall,IntPtr pvBuffer,uint cubToRead) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete(m_pSteamRemoteStorage,hReadCall,pvBuffer,cubToRead); + return result; +} +public override bool FileForget(string pchFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileForget(m_pSteamRemoteStorage,pchFile); + return result; +} +public override bool FileDelete(string pchFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileDelete(m_pSteamRemoteStorage,pchFile); + return result; +} +public override ulong FileShare(string pchFile) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileShare(m_pSteamRemoteStorage,pchFile); + return result; +} +public override bool SetSyncPlatforms(string pchFile,uint eRemoteStoragePlatform) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_SetSyncPlatforms(m_pSteamRemoteStorage,pchFile,eRemoteStoragePlatform); + return result; +} +public override ulong FileWriteStreamOpen(string pchFile) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen(m_pSteamRemoteStorage,pchFile); + return result; +} +public override bool FileWriteStreamWriteChunk(ulong writeHandle,IntPtr pvData,int cubData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk(m_pSteamRemoteStorage,writeHandle,pvData,cubData); + return result; +} +public override bool FileWriteStreamClose(ulong writeHandle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileWriteStreamClose(m_pSteamRemoteStorage,writeHandle); + return result; +} +public override bool FileWriteStreamCancel(ulong writeHandle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel(m_pSteamRemoteStorage,writeHandle); + return result; +} +public override bool FileExists(string pchFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FileExists(m_pSteamRemoteStorage,pchFile); + return result; +} +public override bool FilePersisted(string pchFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_FilePersisted(m_pSteamRemoteStorage,pchFile); + return result; +} +public override int GetFileSize(string pchFile) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetFileSize(m_pSteamRemoteStorage,pchFile); + return result; +} +public override long GetFileTimestamp(string pchFile) +{ + CheckIfUsable(); + long result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetFileTimestamp(m_pSteamRemoteStorage,pchFile); + return result; +} +public override uint GetSyncPlatforms(string pchFile) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetSyncPlatforms(m_pSteamRemoteStorage,pchFile); + return result; +} +public override int GetFileCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetFileCount(m_pSteamRemoteStorage); + return result; +} +public override string GetFileNameAndSize(int iFile,ref int pnFileSizeInBytes) +{ + CheckIfUsable(); + pnFileSizeInBytes = 0; + IntPtr result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetFileNameAndSize(m_pSteamRemoteStorage,iFile,ref pnFileSizeInBytes); + return Marshal.PtrToStringAnsi(result); +} +public override bool GetQuota(ref ulong pnTotalBytes,ref ulong puAvailableBytes) +{ + CheckIfUsable(); + pnTotalBytes = 0; + puAvailableBytes = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetQuota(m_pSteamRemoteStorage,ref pnTotalBytes,ref puAvailableBytes); + return result; +} +public override bool IsCloudEnabledForAccount() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount(m_pSteamRemoteStorage); + return result; +} +public override bool IsCloudEnabledForApp() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp(m_pSteamRemoteStorage); + return result; +} +public override void SetCloudEnabledForApp(bool bEnabled) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp(m_pSteamRemoteStorage,bEnabled); +} +public override ulong UGCDownload(ulong hContent,uint unPriority) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UGCDownload(m_pSteamRemoteStorage,hContent,unPriority); + return result; +} +public override bool GetUGCDownloadProgress(ulong hContent,ref int pnBytesDownloaded,ref int pnBytesExpected) +{ + CheckIfUsable(); + pnBytesDownloaded = 0; + pnBytesExpected = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress(m_pSteamRemoteStorage,hContent,ref pnBytesDownloaded,ref pnBytesExpected); + return result; +} +public override bool GetUGCDetails(ulong hContent,ref uint pnAppID,System.Text.StringBuilder ppchName,ref int pnFileSizeInBytes,out CSteamID pSteamIDOwner) +{ + CheckIfUsable(); + pnAppID = 0; + pnFileSizeInBytes = 0; + pSteamIDOwner = new CSteamID(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetUGCDetails(m_pSteamRemoteStorage,hContent,ref pnAppID,ppchName,ref pnFileSizeInBytes,ref pSteamIDOwner); + return result; +} +public override int UGCRead(ulong hContent,IntPtr pvData,int cubDataToRead,uint cOffset,uint eAction) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UGCRead(m_pSteamRemoteStorage,hContent,pvData,cubDataToRead,cOffset,eAction); + return result; +} +public override int GetCachedUGCCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetCachedUGCCount(m_pSteamRemoteStorage); + return result; +} +public override ulong GetCachedUGCHandle(int iCachedContent) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle(m_pSteamRemoteStorage,iCachedContent); + return result; +} +public override ulong PublishWorkshopFile(string pchFile,string pchPreviewFile,uint nConsumerAppId,string pchTitle,string pchDescription,uint eVisibility,ref SteamParamStringArray_t pTags,uint eWorkshopFileType) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_PublishWorkshopFile(m_pSteamRemoteStorage,pchFile,pchPreviewFile,nConsumerAppId,pchTitle,pchDescription,eVisibility,ref pTags,eWorkshopFileType); + return result; +} +public override ulong CreatePublishedFileUpdateRequest(ulong unPublishedFileId) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest(m_pSteamRemoteStorage,unPublishedFileId); + return result; +} +public override bool UpdatePublishedFileFile(ulong updateHandle,string pchFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile(m_pSteamRemoteStorage,updateHandle,pchFile); + return result; +} +public override bool UpdatePublishedFilePreviewFile(ulong updateHandle,string pchPreviewFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile(m_pSteamRemoteStorage,updateHandle,pchPreviewFile); + return result; +} +public override bool UpdatePublishedFileTitle(ulong updateHandle,string pchTitle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle(m_pSteamRemoteStorage,updateHandle,pchTitle); + return result; +} +public override bool UpdatePublishedFileDescription(ulong updateHandle,string pchDescription) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription(m_pSteamRemoteStorage,updateHandle,pchDescription); + return result; +} +public override bool UpdatePublishedFileVisibility(ulong updateHandle,uint eVisibility) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility(m_pSteamRemoteStorage,updateHandle,eVisibility); + return result; +} +public override bool UpdatePublishedFileTags(ulong updateHandle,ref SteamParamStringArray_t pTags) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags(m_pSteamRemoteStorage,updateHandle,ref pTags); + return result; +} +public override ulong CommitPublishedFileUpdate(ulong updateHandle) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate(m_pSteamRemoteStorage,updateHandle); + return result; +} +public override ulong GetPublishedFileDetails(ulong unPublishedFileId,uint unMaxSecondsOld) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails(m_pSteamRemoteStorage,unPublishedFileId,unMaxSecondsOld); + return result; +} +public override ulong DeletePublishedFile(ulong unPublishedFileId) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_DeletePublishedFile(m_pSteamRemoteStorage,unPublishedFileId); + return result; +} +public override ulong EnumerateUserPublishedFiles(uint unStartIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles(m_pSteamRemoteStorage,unStartIndex); + return result; +} +public override ulong SubscribePublishedFile(ulong unPublishedFileId) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_SubscribePublishedFile(m_pSteamRemoteStorage,unPublishedFileId); + return result; +} +public override ulong EnumerateUserSubscribedFiles(uint unStartIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles(m_pSteamRemoteStorage,unStartIndex); + return result; +} +public override ulong UnsubscribePublishedFile(ulong unPublishedFileId) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile(m_pSteamRemoteStorage,unPublishedFileId); + return result; +} +public override bool UpdatePublishedFileSetChangeDescription(ulong updateHandle,string pchChangeDescription) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription(m_pSteamRemoteStorage,updateHandle,pchChangeDescription); + return result; +} +public override ulong GetPublishedItemVoteDetails(ulong unPublishedFileId) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails(m_pSteamRemoteStorage,unPublishedFileId); + return result; +} +public override ulong UpdateUserPublishedItemVote(ulong unPublishedFileId,bool bVoteUp) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote(m_pSteamRemoteStorage,unPublishedFileId,bVoteUp); + return result; +} +public override ulong GetUserPublishedItemVoteDetails(ulong unPublishedFileId) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails(m_pSteamRemoteStorage,unPublishedFileId); + return result; +} +public override ulong EnumerateUserSharedWorkshopFiles(ulong steamId,uint unStartIndex,ref SteamParamStringArray_t pRequiredTags,ref SteamParamStringArray_t pExcludedTags) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles(m_pSteamRemoteStorage,steamId,unStartIndex,ref pRequiredTags,ref pExcludedTags); + return result; +} +public override ulong PublishVideo(uint eVideoProvider,string pchVideoAccount,string pchVideoIdentifier,string pchPreviewFile,uint nConsumerAppId,string pchTitle,string pchDescription,uint eVisibility,ref SteamParamStringArray_t pTags) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_PublishVideo(m_pSteamRemoteStorage,eVideoProvider,pchVideoAccount,pchVideoIdentifier,pchPreviewFile,nConsumerAppId,pchTitle,pchDescription,eVisibility,ref pTags); + return result; +} +public override ulong SetUserPublishedFileAction(ulong unPublishedFileId,uint eAction) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction(m_pSteamRemoteStorage,unPublishedFileId,eAction); + return result; +} +public override ulong EnumeratePublishedFilesByUserAction(uint eAction,uint unStartIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction(m_pSteamRemoteStorage,eAction,unStartIndex); + return result; +} +public override ulong EnumeratePublishedWorkshopFiles(uint eEnumerationType,uint unStartIndex,uint unCount,uint unDays,ref SteamParamStringArray_t pTags,ref SteamParamStringArray_t pUserTags) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles(m_pSteamRemoteStorage,eEnumerationType,unStartIndex,unCount,unDays,ref pTags,ref pUserTags); + return result; +} +public override ulong UGCDownloadToLocation(ulong hContent,string pchLocation,uint unPriority) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation(m_pSteamRemoteStorage,hContent,pchLocation,unPriority); + return result; +} +} + + +public class CSteamUserStats : ISteamUserStats +{ +public CSteamUserStats(IntPtr SteamUserStats) +{ + m_pSteamUserStats = SteamUserStats; +} +IntPtr m_pSteamUserStats; + +public override IntPtr GetIntPtr() { return m_pSteamUserStats; } + +private void CheckIfUsable() +{ + if (m_pSteamUserStats == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool RequestCurrentStats() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_RequestCurrentStats(m_pSteamUserStats); + return result; +} +public override bool GetStat(string pchName,ref int pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetStat(m_pSteamUserStats,pchName,ref pData); + return result; +} +public override bool GetStat0(string pchName,ref float pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetStat0(m_pSteamUserStats,pchName,ref pData); + return result; +} +public override bool SetStat(string pchName,int nData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_SetStat(m_pSteamUserStats,pchName,nData); + return result; +} +public override bool SetStat0(string pchName,float fData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_SetStat0(m_pSteamUserStats,pchName,fData); + return result; +} +public override bool UpdateAvgRateStat(string pchName,float flCountThisSession,double dSessionLength) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_UpdateAvgRateStat(m_pSteamUserStats,pchName,flCountThisSession,dSessionLength); + return result; +} +public override bool GetAchievement(string pchName,ref bool pbAchieved) +{ + CheckIfUsable(); + pbAchieved = false; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetAchievement(m_pSteamUserStats,pchName,ref pbAchieved); + return result; +} +public override bool SetAchievement(string pchName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_SetAchievement(m_pSteamUserStats,pchName); + return result; +} +public override bool ClearAchievement(string pchName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_ClearAchievement(m_pSteamUserStats,pchName); + return result; +} +public override bool GetAchievementAndUnlockTime(string pchName,ref bool pbAchieved,ref uint punUnlockTime) +{ + CheckIfUsable(); + pbAchieved = false; + punUnlockTime = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime(m_pSteamUserStats,pchName,ref pbAchieved,ref punUnlockTime); + return result; +} +public override bool StoreStats() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_StoreStats(m_pSteamUserStats); + return result; +} +public override int GetAchievementIcon(string pchName) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetAchievementIcon(m_pSteamUserStats,pchName); + return result; +} +public override string GetAchievementDisplayAttribute(string pchName,string pchKey) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute(m_pSteamUserStats,pchName,pchKey); + return Marshal.PtrToStringAnsi(result); +} +public override bool IndicateAchievementProgress(string pchName,uint nCurProgress,uint nMaxProgress) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_IndicateAchievementProgress(m_pSteamUserStats,pchName,nCurProgress,nMaxProgress); + return result; +} +public override uint GetNumAchievements() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetNumAchievements(m_pSteamUserStats); + return result; +} +public override string GetAchievementName(uint iAchievement) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetAchievementName(m_pSteamUserStats,iAchievement); + return Marshal.PtrToStringAnsi(result); +} +public override ulong RequestUserStats(ulong steamIDUser) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_RequestUserStats(m_pSteamUserStats,steamIDUser); + return result; +} +public override bool GetUserStat(ulong steamIDUser,string pchName,ref int pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetUserStat(m_pSteamUserStats,steamIDUser,pchName,ref pData); + return result; +} +public override bool GetUserStat0(ulong steamIDUser,string pchName,ref float pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetUserStat0(m_pSteamUserStats,steamIDUser,pchName,ref pData); + return result; +} +public override bool GetUserAchievement(ulong steamIDUser,string pchName,ref bool pbAchieved) +{ + CheckIfUsable(); + pbAchieved = false; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetUserAchievement(m_pSteamUserStats,steamIDUser,pchName,ref pbAchieved); + return result; +} +public override bool GetUserAchievementAndUnlockTime(ulong steamIDUser,string pchName,ref bool pbAchieved,ref uint punUnlockTime) +{ + CheckIfUsable(); + pbAchieved = false; + punUnlockTime = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime(m_pSteamUserStats,steamIDUser,pchName,ref pbAchieved,ref punUnlockTime); + return result; +} +public override bool ResetAllStats(bool bAchievementsToo) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_ResetAllStats(m_pSteamUserStats,bAchievementsToo); + return result; +} +public override ulong FindOrCreateLeaderboard(string pchLeaderboardName,uint eLeaderboardSortMethod,uint eLeaderboardDisplayType) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_FindOrCreateLeaderboard(m_pSteamUserStats,pchLeaderboardName,eLeaderboardSortMethod,eLeaderboardDisplayType); + return result; +} +public override ulong FindLeaderboard(string pchLeaderboardName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_FindLeaderboard(m_pSteamUserStats,pchLeaderboardName); + return result; +} +public override string GetLeaderboardName(ulong hSteamLeaderboard) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetLeaderboardName(m_pSteamUserStats,hSteamLeaderboard); + return Marshal.PtrToStringAnsi(result); +} +public override int GetLeaderboardEntryCount(ulong hSteamLeaderboard) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetLeaderboardEntryCount(m_pSteamUserStats,hSteamLeaderboard); + return result; +} +public override uint GetLeaderboardSortMethod(ulong hSteamLeaderboard) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetLeaderboardSortMethod(m_pSteamUserStats,hSteamLeaderboard); + return result; +} +public override uint GetLeaderboardDisplayType(ulong hSteamLeaderboard) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetLeaderboardDisplayType(m_pSteamUserStats,hSteamLeaderboard); + return result; +} +public override ulong DownloadLeaderboardEntries(ulong hSteamLeaderboard,uint eLeaderboardDataRequest,int nRangeStart,int nRangeEnd) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_DownloadLeaderboardEntries(m_pSteamUserStats,hSteamLeaderboard,eLeaderboardDataRequest,nRangeStart,nRangeEnd); + return result; +} +public override ulong DownloadLeaderboardEntriesForUsers(ulong hSteamLeaderboard,CSteamID [] prgUsers) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers(m_pSteamUserStats,hSteamLeaderboard,prgUsers,(int) prgUsers.Length); + return result; +} +public override bool GetDownloadedLeaderboardEntry(ulong hSteamLeaderboardEntries,int index,ref LeaderboardEntry_t pLeaderboardEntry,ref int pDetails,int cDetailsMax) +{ + CheckIfUsable(); + pDetails = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry(m_pSteamUserStats,hSteamLeaderboardEntries,index,ref pLeaderboardEntry,ref pDetails,cDetailsMax); + return result; +} +public override ulong UploadLeaderboardScore(ulong hSteamLeaderboard,uint eLeaderboardUploadScoreMethod,int nScore,ref int pScoreDetails,int cScoreDetailsCount) +{ + CheckIfUsable(); + pScoreDetails = 0; + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_UploadLeaderboardScore(m_pSteamUserStats,hSteamLeaderboard,eLeaderboardUploadScoreMethod,nScore,ref pScoreDetails,cScoreDetailsCount); + return result; +} +public override ulong AttachLeaderboardUGC(ulong hSteamLeaderboard,ulong hUGC) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_AttachLeaderboardUGC(m_pSteamUserStats,hSteamLeaderboard,hUGC); + return result; +} +public override ulong GetNumberOfCurrentPlayers() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers(m_pSteamUserStats); + return result; +} +public override ulong RequestGlobalAchievementPercentages() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages(m_pSteamUserStats); + return result; +} +public override int GetMostAchievedAchievementInfo(string pchName,uint unNameBufLen,ref float pflPercent,ref bool pbAchieved) +{ + CheckIfUsable(); + pflPercent = 0; + pbAchieved = false; + int result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo(m_pSteamUserStats,pchName,unNameBufLen,ref pflPercent,ref pbAchieved); + return result; +} +public override int GetNextMostAchievedAchievementInfo(int iIteratorPrevious,string pchName,uint unNameBufLen,ref float pflPercent,ref bool pbAchieved) +{ + CheckIfUsable(); + pflPercent = 0; + pbAchieved = false; + int result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo(m_pSteamUserStats,iIteratorPrevious,pchName,unNameBufLen,ref pflPercent,ref pbAchieved); + return result; +} +public override bool GetAchievementAchievedPercent(string pchName,ref float pflPercent) +{ + CheckIfUsable(); + pflPercent = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetAchievementAchievedPercent(m_pSteamUserStats,pchName,ref pflPercent); + return result; +} +public override ulong RequestGlobalStats(int nHistoryDays) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUserStats_RequestGlobalStats(m_pSteamUserStats,nHistoryDays); + return result; +} +public override bool GetGlobalStat(string pchStatName,ref long pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetGlobalStat(m_pSteamUserStats,pchStatName,ref pData); + return result; +} +public override bool GetGlobalStat0(string pchStatName,ref double pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetGlobalStat0(m_pSteamUserStats,pchStatName,ref pData); + return result; +} +public override int GetGlobalStatHistory(string pchStatName,long [] pData) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetGlobalStatHistory(m_pSteamUserStats,pchStatName,pData,(uint) pData.Length); + return result; +} +public override int GetGlobalStatHistory0(string pchStatName,double [] pData) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamUserStats_GetGlobalStatHistory0(m_pSteamUserStats,pchStatName,pData,(uint) pData.Length); + return result; +} +} + + +public class CSteamApps : ISteamApps +{ +public CSteamApps(IntPtr SteamApps) +{ + m_pSteamApps = SteamApps; +} +IntPtr m_pSteamApps; + +public override IntPtr GetIntPtr() { return m_pSteamApps; } + +private void CheckIfUsable() +{ + if (m_pSteamApps == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool BIsSubscribed() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsSubscribed(m_pSteamApps); + return result; +} +public override bool BIsLowViolence() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsLowViolence(m_pSteamApps); + return result; +} +public override bool BIsCybercafe() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsCybercafe(m_pSteamApps); + return result; +} +public override bool BIsVACBanned() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsVACBanned(m_pSteamApps); + return result; +} +public override string GetCurrentGameLanguage() +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamApps_GetCurrentGameLanguage(m_pSteamApps); + return Marshal.PtrToStringAnsi(result); +} +public override string GetAvailableGameLanguages() +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamApps_GetAvailableGameLanguages(m_pSteamApps); + return Marshal.PtrToStringAnsi(result); +} +public override bool BIsSubscribedApp(uint appID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsSubscribedApp(m_pSteamApps,appID); + return result; +} +public override bool BIsDlcInstalled(uint appID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsDlcInstalled(m_pSteamApps,appID); + return result; +} +public override uint GetEarliestPurchaseUnixTime(uint nAppID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime(m_pSteamApps,nAppID); + return result; +} +public override bool BIsSubscribedFromFreeWeekend() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend(m_pSteamApps); + return result; +} +public override int GetDLCCount() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamApps_GetDLCCount(m_pSteamApps); + return result; +} +public override bool BGetDLCDataByIndex(int iDLC,ref uint pAppID,ref bool pbAvailable,string pchName,int cchNameBufferSize) +{ + CheckIfUsable(); + pAppID = 0; + pbAvailable = false; + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BGetDLCDataByIndex(m_pSteamApps,iDLC,ref pAppID,ref pbAvailable,pchName,cchNameBufferSize); + return result; +} +public override void InstallDLC(uint nAppID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamApps_InstallDLC(m_pSteamApps,nAppID); +} +public override void UninstallDLC(uint nAppID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamApps_UninstallDLC(m_pSteamApps,nAppID); +} +public override void RequestAppProofOfPurchaseKey(uint nAppID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey(m_pSteamApps,nAppID); +} +public override bool GetCurrentBetaName(string pchName,int cchNameBufferSize) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_GetCurrentBetaName(m_pSteamApps,pchName,cchNameBufferSize); + return result; +} +public override bool MarkContentCorrupt(bool bMissingFilesOnly) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_MarkContentCorrupt(m_pSteamApps,bMissingFilesOnly); + return result; +} +public override uint GetInstalledDepots(uint appID,ref uint pvecDepots,uint cMaxDepots) +{ + CheckIfUsable(); + pvecDepots = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamApps_GetInstalledDepots(m_pSteamApps,appID,ref pvecDepots,cMaxDepots); + return result; +} +public override uint GetAppInstallDir(uint appID,string pchFolder,uint cchFolderBufferSize) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamApps_GetAppInstallDir(m_pSteamApps,appID,pchFolder,cchFolderBufferSize); + return result; +} +public override bool BIsAppInstalled(uint appID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsAppInstalled(m_pSteamApps,appID); + return result; +} +public override ulong GetAppOwner() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamApps_GetAppOwner(m_pSteamApps); + return result; +} +public override string GetLaunchQueryParam(string pchKey) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamApps_GetLaunchQueryParam(m_pSteamApps,pchKey); + return Marshal.PtrToStringAnsi(result); +} +public override bool GetDlcDownloadProgress(uint nAppID,ref ulong punBytesDownloaded,ref ulong punBytesTotal) +{ + CheckIfUsable(); + punBytesDownloaded = 0; + punBytesTotal = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamApps_GetDlcDownloadProgress(m_pSteamApps,nAppID,ref punBytesDownloaded,ref punBytesTotal); + return result; +} +public override int GetAppBuildId() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamApps_GetAppBuildId(m_pSteamApps); + return result; +} +public override void RequestAllProofOfPurchaseKeys() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys(m_pSteamApps); +} +public override ulong GetFileDetails(string pszFileName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamApps_GetFileDetails(m_pSteamApps,pszFileName); + return result; +} +public override int GetLaunchCommandLine(string pszCommandLine,int cubCommandLine) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamApps_GetLaunchCommandLine(m_pSteamApps,pszCommandLine,cubCommandLine); + return result; +} +public override bool BIsSubscribedFromFamilySharing() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing(m_pSteamApps); + return result; +} +} + + +public class CSteamNetworking : ISteamNetworking +{ +public CSteamNetworking(IntPtr SteamNetworking) +{ + m_pSteamNetworking = SteamNetworking; +} +IntPtr m_pSteamNetworking; + +public override IntPtr GetIntPtr() { return m_pSteamNetworking; } + +private void CheckIfUsable() +{ + if (m_pSteamNetworking == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool SendP2PPacket(ulong steamIDRemote,IntPtr pubData,uint cubData,uint eP2PSendType,int nChannel) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_SendP2PPacket(m_pSteamNetworking,steamIDRemote,pubData,cubData,eP2PSendType,nChannel); + return result; +} +public override bool IsP2PPacketAvailable(ref uint pcubMsgSize,int nChannel) +{ + CheckIfUsable(); + pcubMsgSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_IsP2PPacketAvailable(m_pSteamNetworking,ref pcubMsgSize,nChannel); + return result; +} +public override bool ReadP2PPacket(IntPtr pubDest,uint cubDest,ref uint pcubMsgSize,ref CSteamID psteamIDRemote,int nChannel) +{ + CheckIfUsable(); + pcubMsgSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_ReadP2PPacket(m_pSteamNetworking,pubDest,cubDest,ref pcubMsgSize,ref psteamIDRemote,nChannel); + return result; +} +public override bool AcceptP2PSessionWithUser(ulong steamIDRemote) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser(m_pSteamNetworking,steamIDRemote); + return result; +} +public override bool CloseP2PSessionWithUser(ulong steamIDRemote) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_CloseP2PSessionWithUser(m_pSteamNetworking,steamIDRemote); + return result; +} +public override bool CloseP2PChannelWithUser(ulong steamIDRemote,int nChannel) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_CloseP2PChannelWithUser(m_pSteamNetworking,steamIDRemote,nChannel); + return result; +} +public override bool GetP2PSessionState(ulong steamIDRemote,ref P2PSessionState_t pConnectionState) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_GetP2PSessionState(m_pSteamNetworking,steamIDRemote,ref pConnectionState); + return result; +} +public override bool AllowP2PPacketRelay(bool bAllow) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_AllowP2PPacketRelay(m_pSteamNetworking,bAllow); + return result; +} +public override uint CreateListenSocket(int nVirtualP2PPort,uint nIP,char nPort,bool bAllowUseOfPacketRelay) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamNetworking_CreateListenSocket(m_pSteamNetworking,nVirtualP2PPort,nIP,nPort,bAllowUseOfPacketRelay); + return result; +} +public override uint CreateP2PConnectionSocket(ulong steamIDTarget,int nVirtualPort,int nTimeoutSec,bool bAllowUseOfPacketRelay) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamNetworking_CreateP2PConnectionSocket(m_pSteamNetworking,steamIDTarget,nVirtualPort,nTimeoutSec,bAllowUseOfPacketRelay); + return result; +} +public override uint CreateConnectionSocket(uint nIP,char nPort,int nTimeoutSec) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamNetworking_CreateConnectionSocket(m_pSteamNetworking,nIP,nPort,nTimeoutSec); + return result; +} +public override bool DestroySocket(uint hSocket,bool bNotifyRemoteEnd) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_DestroySocket(m_pSteamNetworking,hSocket,bNotifyRemoteEnd); + return result; +} +public override bool DestroyListenSocket(uint hSocket,bool bNotifyRemoteEnd) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_DestroyListenSocket(m_pSteamNetworking,hSocket,bNotifyRemoteEnd); + return result; +} +public override bool SendDataOnSocket(uint hSocket,IntPtr pubData,uint cubData,bool bReliable) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_SendDataOnSocket(m_pSteamNetworking,hSocket,pubData,cubData,bReliable); + return result; +} +public override bool IsDataAvailableOnSocket(uint hSocket,ref uint pcubMsgSize) +{ + CheckIfUsable(); + pcubMsgSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_IsDataAvailableOnSocket(m_pSteamNetworking,hSocket,ref pcubMsgSize); + return result; +} +public override bool RetrieveDataFromSocket(uint hSocket,IntPtr pubDest,uint cubDest,ref uint pcubMsgSize) +{ + CheckIfUsable(); + pcubMsgSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_RetrieveDataFromSocket(m_pSteamNetworking,hSocket,pubDest,cubDest,ref pcubMsgSize); + return result; +} +public override bool IsDataAvailable(uint hListenSocket,ref uint pcubMsgSize,ref uint phSocket) +{ + CheckIfUsable(); + pcubMsgSize = 0; + phSocket = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_IsDataAvailable(m_pSteamNetworking,hListenSocket,ref pcubMsgSize,ref phSocket); + return result; +} +public override bool RetrieveData(uint hListenSocket,IntPtr pubDest,uint cubDest,ref uint pcubMsgSize,ref uint phSocket) +{ + CheckIfUsable(); + pcubMsgSize = 0; + phSocket = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_RetrieveData(m_pSteamNetworking,hListenSocket,pubDest,cubDest,ref pcubMsgSize,ref phSocket); + return result; +} +public override bool GetSocketInfo(uint hSocket,ref CSteamID pSteamIDRemote,ref int peSocketStatus,ref uint punIPRemote,ref char punPortRemote) +{ + CheckIfUsable(); + peSocketStatus = 0; + punIPRemote = 0; + punPortRemote = (char) 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_GetSocketInfo(m_pSteamNetworking,hSocket,ref pSteamIDRemote,ref peSocketStatus,ref punIPRemote,ref punPortRemote); + return result; +} +public override bool GetListenSocketInfo(uint hListenSocket,ref uint pnIP,ref char pnPort) +{ + CheckIfUsable(); + pnIP = 0; + pnPort = (char) 0; + bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_GetListenSocketInfo(m_pSteamNetworking,hListenSocket,ref pnIP,ref pnPort); + return result; +} +public override uint GetSocketConnectionType(uint hSocket) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamNetworking_GetSocketConnectionType(m_pSteamNetworking,hSocket); + return result; +} +public override int GetMaxPacketSize(uint hSocket) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamNetworking_GetMaxPacketSize(m_pSteamNetworking,hSocket); + return result; +} +} + + +public class CSteamScreenshots : ISteamScreenshots +{ +public CSteamScreenshots(IntPtr SteamScreenshots) +{ + m_pSteamScreenshots = SteamScreenshots; +} +IntPtr m_pSteamScreenshots; + +public override IntPtr GetIntPtr() { return m_pSteamScreenshots; } + +private void CheckIfUsable() +{ + if (m_pSteamScreenshots == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint WriteScreenshot(IntPtr pubRGB,uint cubRGB,int nWidth,int nHeight) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamScreenshots_WriteScreenshot(m_pSteamScreenshots,pubRGB,cubRGB,nWidth,nHeight); + return result; +} +public override uint AddScreenshotToLibrary(string pchFilename,string pchThumbnailFilename,int nWidth,int nHeight) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamScreenshots_AddScreenshotToLibrary(m_pSteamScreenshots,pchFilename,pchThumbnailFilename,nWidth,nHeight); + return result; +} +public override void TriggerScreenshot() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamScreenshots_TriggerScreenshot(m_pSteamScreenshots); +} +public override void HookScreenshots(bool bHook) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamScreenshots_HookScreenshots(m_pSteamScreenshots,bHook); +} +public override bool SetLocation(uint hScreenshot,string pchLocation) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamScreenshots_SetLocation(m_pSteamScreenshots,hScreenshot,pchLocation); + return result; +} +public override bool TagUser(uint hScreenshot,ulong steamID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamScreenshots_TagUser(m_pSteamScreenshots,hScreenshot,steamID); + return result; +} +public override bool TagPublishedFile(uint hScreenshot,ulong unPublishedFileID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamScreenshots_TagPublishedFile(m_pSteamScreenshots,hScreenshot,unPublishedFileID); + return result; +} +public override bool IsScreenshotsHooked() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamScreenshots_IsScreenshotsHooked(m_pSteamScreenshots); + return result; +} +public override uint AddVRScreenshotToLibrary(uint eType,string pchFilename,string pchVRFilename) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary(m_pSteamScreenshots,eType,pchFilename,pchVRFilename); + return result; +} +} + + +public class CSteamMusic : ISteamMusic +{ +public CSteamMusic(IntPtr SteamMusic) +{ + m_pSteamMusic = SteamMusic; +} +IntPtr m_pSteamMusic; + +public override IntPtr GetIntPtr() { return m_pSteamMusic; } + +private void CheckIfUsable() +{ + if (m_pSteamMusic == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool BIsEnabled() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusic_BIsEnabled(m_pSteamMusic); + return result; +} +public override bool BIsPlaying() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusic_BIsPlaying(m_pSteamMusic); + return result; +} +public override int GetPlaybackStatus() +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamMusic_GetPlaybackStatus(m_pSteamMusic); + return result; +} +public override void Play() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMusic_Play(m_pSteamMusic); +} +public override void Pause() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMusic_Pause(m_pSteamMusic); +} +public override void PlayPrevious() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMusic_PlayPrevious(m_pSteamMusic); +} +public override void PlayNext() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMusic_PlayNext(m_pSteamMusic); +} +public override void SetVolume(float flVolume) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamMusic_SetVolume(m_pSteamMusic,flVolume); +} +public override float GetVolume() +{ + CheckIfUsable(); + float result = NativeEntrypoints.SteamAPI_ISteamMusic_GetVolume(m_pSteamMusic); + return result; +} +} + + +public class CSteamMusicRemote : ISteamMusicRemote +{ +public CSteamMusicRemote(IntPtr SteamMusicRemote) +{ + m_pSteamMusicRemote = SteamMusicRemote; +} +IntPtr m_pSteamMusicRemote; + +public override IntPtr GetIntPtr() { return m_pSteamMusicRemote; } + +private void CheckIfUsable() +{ + if (m_pSteamMusicRemote == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool RegisterSteamMusicRemote(string pchName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote(m_pSteamMusicRemote,pchName); + return result; +} +public override bool DeregisterSteamMusicRemote() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote(m_pSteamMusicRemote); + return result; +} +public override bool BIsCurrentMusicRemote() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote(m_pSteamMusicRemote); + return result; +} +public override bool BActivationSuccess(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_BActivationSuccess(m_pSteamMusicRemote,bValue); + return result; +} +public override bool SetDisplayName(string pchDisplayName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_SetDisplayName(m_pSteamMusicRemote,pchDisplayName); + return result; +} +public override bool SetPNGIcon_64x64(IntPtr pvBuffer,uint cbBufferLength) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64(m_pSteamMusicRemote,pvBuffer,cbBufferLength); + return result; +} +public override bool EnablePlayPrevious(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_EnablePlayPrevious(m_pSteamMusicRemote,bValue); + return result; +} +public override bool EnablePlayNext(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_EnablePlayNext(m_pSteamMusicRemote,bValue); + return result; +} +public override bool EnableShuffled(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_EnableShuffled(m_pSteamMusicRemote,bValue); + return result; +} +public override bool EnableLooped(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_EnableLooped(m_pSteamMusicRemote,bValue); + return result; +} +public override bool EnableQueue(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_EnableQueue(m_pSteamMusicRemote,bValue); + return result; +} +public override bool EnablePlaylists(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_EnablePlaylists(m_pSteamMusicRemote,bValue); + return result; +} +public override bool UpdatePlaybackStatus(int nStatus) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus(m_pSteamMusicRemote,nStatus); + return result; +} +public override bool UpdateShuffled(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdateShuffled(m_pSteamMusicRemote,bValue); + return result; +} +public override bool UpdateLooped(bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdateLooped(m_pSteamMusicRemote,bValue); + return result; +} +public override bool UpdateVolume(float flValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdateVolume(m_pSteamMusicRemote,flValue); + return result; +} +public override bool CurrentEntryWillChange() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_CurrentEntryWillChange(m_pSteamMusicRemote); + return result; +} +public override bool CurrentEntryIsAvailable(bool bAvailable) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable(m_pSteamMusicRemote,bAvailable); + return result; +} +public override bool UpdateCurrentEntryText(string pchText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText(m_pSteamMusicRemote,pchText); + return result; +} +public override bool UpdateCurrentEntryElapsedSeconds(int nValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds(m_pSteamMusicRemote,nValue); + return result; +} +public override bool UpdateCurrentEntryCoverArt(IntPtr pvBuffer,uint cbBufferLength) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt(m_pSteamMusicRemote,pvBuffer,cbBufferLength); + return result; +} +public override bool CurrentEntryDidChange() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_CurrentEntryDidChange(m_pSteamMusicRemote); + return result; +} +public override bool QueueWillChange() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_QueueWillChange(m_pSteamMusicRemote); + return result; +} +public override bool ResetQueueEntries() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_ResetQueueEntries(m_pSteamMusicRemote); + return result; +} +public override bool SetQueueEntry(int nID,int nPosition,string pchEntryText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_SetQueueEntry(m_pSteamMusicRemote,nID,nPosition,pchEntryText); + return result; +} +public override bool SetCurrentQueueEntry(int nID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry(m_pSteamMusicRemote,nID); + return result; +} +public override bool QueueDidChange() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_QueueDidChange(m_pSteamMusicRemote); + return result; +} +public override bool PlaylistWillChange() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_PlaylistWillChange(m_pSteamMusicRemote); + return result; +} +public override bool ResetPlaylistEntries() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_ResetPlaylistEntries(m_pSteamMusicRemote); + return result; +} +public override bool SetPlaylistEntry(int nID,int nPosition,string pchEntryText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_SetPlaylistEntry(m_pSteamMusicRemote,nID,nPosition,pchEntryText); + return result; +} +public override bool SetCurrentPlaylistEntry(int nID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry(m_pSteamMusicRemote,nID); + return result; +} +public override bool PlaylistDidChange() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamMusicRemote_PlaylistDidChange(m_pSteamMusicRemote); + return result; +} +} + + +public class CSteamHTTP : ISteamHTTP +{ +public CSteamHTTP(IntPtr SteamHTTP) +{ + m_pSteamHTTP = SteamHTTP; +} +IntPtr m_pSteamHTTP; + +public override IntPtr GetIntPtr() { return m_pSteamHTTP; } + +private void CheckIfUsable() +{ + if (m_pSteamHTTP == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint CreateHTTPRequest(uint eHTTPRequestMethod,string pchAbsoluteURL) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamHTTP_CreateHTTPRequest(m_pSteamHTTP,eHTTPRequestMethod,pchAbsoluteURL); + return result; +} +public override bool SetHTTPRequestContextValue(uint hRequest,ulong ulContextValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestContextValue(m_pSteamHTTP,hRequest,ulContextValue); + return result; +} +public override bool SetHTTPRequestNetworkActivityTimeout(uint hRequest,uint unTimeoutSeconds) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout(m_pSteamHTTP,hRequest,unTimeoutSeconds); + return result; +} +public override bool SetHTTPRequestHeaderValue(uint hRequest,string pchHeaderName,string pchHeaderValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue(m_pSteamHTTP,hRequest,pchHeaderName,pchHeaderValue); + return result; +} +public override bool SetHTTPRequestGetOrPostParameter(uint hRequest,string pchParamName,string pchParamValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter(m_pSteamHTTP,hRequest,pchParamName,pchParamValue); + return result; +} +public override bool SendHTTPRequest(uint hRequest,ref ulong pCallHandle) +{ + CheckIfUsable(); + pCallHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SendHTTPRequest(m_pSteamHTTP,hRequest,ref pCallHandle); + return result; +} +public override bool SendHTTPRequestAndStreamResponse(uint hRequest,ref ulong pCallHandle) +{ + CheckIfUsable(); + pCallHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse(m_pSteamHTTP,hRequest,ref pCallHandle); + return result; +} +public override bool DeferHTTPRequest(uint hRequest) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_DeferHTTPRequest(m_pSteamHTTP,hRequest); + return result; +} +public override bool PrioritizeHTTPRequest(uint hRequest) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_PrioritizeHTTPRequest(m_pSteamHTTP,hRequest); + return result; +} +public override bool GetHTTPResponseHeaderSize(uint hRequest,string pchHeaderName,ref uint unResponseHeaderSize) +{ + CheckIfUsable(); + unResponseHeaderSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize(m_pSteamHTTP,hRequest,pchHeaderName,ref unResponseHeaderSize); + return result; +} +public override bool GetHTTPResponseHeaderValue(uint hRequest,string pchHeaderName,IntPtr pHeaderValueBuffer,uint unBufferSize) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue(m_pSteamHTTP,hRequest,pchHeaderName,pHeaderValueBuffer,unBufferSize); + return result; +} +public override bool GetHTTPResponseBodySize(uint hRequest,ref uint unBodySize) +{ + CheckIfUsable(); + unBodySize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPResponseBodySize(m_pSteamHTTP,hRequest,ref unBodySize); + return result; +} +public override bool GetHTTPResponseBodyData(uint hRequest,IntPtr pBodyDataBuffer,uint unBufferSize) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPResponseBodyData(m_pSteamHTTP,hRequest,pBodyDataBuffer,unBufferSize); + return result; +} +public override bool GetHTTPStreamingResponseBodyData(uint hRequest,uint cOffset,IntPtr pBodyDataBuffer,uint unBufferSize) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData(m_pSteamHTTP,hRequest,cOffset,pBodyDataBuffer,unBufferSize); + return result; +} +public override bool ReleaseHTTPRequest(uint hRequest) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_ReleaseHTTPRequest(m_pSteamHTTP,hRequest); + return result; +} +public override bool GetHTTPDownloadProgressPct(uint hRequest,ref float pflPercentOut) +{ + CheckIfUsable(); + pflPercentOut = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct(m_pSteamHTTP,hRequest,ref pflPercentOut); + return result; +} +public override bool SetHTTPRequestRawPostBody(uint hRequest,string pchContentType,IntPtr pubBody,uint unBodyLen) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody(m_pSteamHTTP,hRequest,pchContentType,pubBody,unBodyLen); + return result; +} +public override uint CreateCookieContainer(bool bAllowResponsesToModify) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamHTTP_CreateCookieContainer(m_pSteamHTTP,bAllowResponsesToModify); + return result; +} +public override bool ReleaseCookieContainer(uint hCookieContainer) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_ReleaseCookieContainer(m_pSteamHTTP,hCookieContainer); + return result; +} +public override bool SetCookie(uint hCookieContainer,string pchHost,string pchUrl,string pchCookie) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetCookie(m_pSteamHTTP,hCookieContainer,pchHost,pchUrl,pchCookie); + return result; +} +public override bool SetHTTPRequestCookieContainer(uint hRequest,uint hCookieContainer) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer(m_pSteamHTTP,hRequest,hCookieContainer); + return result; +} +public override bool SetHTTPRequestUserAgentInfo(uint hRequest,string pchUserAgentInfo) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo(m_pSteamHTTP,hRequest,pchUserAgentInfo); + return result; +} +public override bool SetHTTPRequestRequiresVerifiedCertificate(uint hRequest,bool bRequireVerifiedCertificate) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate(m_pSteamHTTP,hRequest,bRequireVerifiedCertificate); + return result; +} +public override bool SetHTTPRequestAbsoluteTimeoutMS(uint hRequest,uint unMilliseconds) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS(m_pSteamHTTP,hRequest,unMilliseconds); + return result; +} +public override bool GetHTTPRequestWasTimedOut(uint hRequest,ref bool pbWasTimedOut) +{ + CheckIfUsable(); + pbWasTimedOut = false; + bool result = NativeEntrypoints.SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut(m_pSteamHTTP,hRequest,ref pbWasTimedOut); + return result; +} +} + + +public class CSteamInput : ISteamInput +{ +public CSteamInput(IntPtr SteamInput) +{ + m_pSteamInput = SteamInput; +} +IntPtr m_pSteamInput; + +public override IntPtr GetIntPtr() { return m_pSteamInput; } + +private void CheckIfUsable() +{ + if (m_pSteamInput == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool Init() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInput_Init(m_pSteamInput); + return result; +} +public override bool Shutdown() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInput_Shutdown(m_pSteamInput); + return result; +} +public override void RunFrame() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_RunFrame(m_pSteamInput); +} +public override int GetConnectedControllers(out ulong [] handlesOut) +{ + CheckIfUsable(); + handlesOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamInput_GetConnectedControllers(m_pSteamInput,null); + handlesOut= new ulong[STEAM_INPUT_MAX_COUNT]; + result = NativeEntrypoints.SteamAPI_ISteamInput_GetConnectedControllers(m_pSteamInput,handlesOut); + return result; +} +public override ulong GetActionSetHandle(string pszActionSetName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInput_GetActionSetHandle(m_pSteamInput,pszActionSetName); + return result; +} +public override void ActivateActionSet(ulong inputHandle,ulong actionSetHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_ActivateActionSet(m_pSteamInput,inputHandle,actionSetHandle); +} +public override ulong GetCurrentActionSet(ulong inputHandle) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInput_GetCurrentActionSet(m_pSteamInput,inputHandle); + return result; +} +public override void ActivateActionSetLayer(ulong inputHandle,ulong actionSetLayerHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_ActivateActionSetLayer(m_pSteamInput,inputHandle,actionSetLayerHandle); +} +public override void DeactivateActionSetLayer(ulong inputHandle,ulong actionSetLayerHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_DeactivateActionSetLayer(m_pSteamInput,inputHandle,actionSetLayerHandle); +} +public override void DeactivateAllActionSetLayers(ulong inputHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_DeactivateAllActionSetLayers(m_pSteamInput,inputHandle); +} +public override int GetActiveActionSetLayers(ulong inputHandle,out ulong [] handlesOut) +{ + CheckIfUsable(); + handlesOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamInput_GetActiveActionSetLayers(m_pSteamInput,inputHandle,null); + handlesOut= new ulong[STEAM_INPUT_MAX_ACTIVE_LAYERS]; + result = NativeEntrypoints.SteamAPI_ISteamInput_GetActiveActionSetLayers(m_pSteamInput,inputHandle,handlesOut); + return result; +} +public override ulong GetDigitalActionHandle(string pszActionName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInput_GetDigitalActionHandle(m_pSteamInput,pszActionName); + return result; +} +public override InputDigitalActionData_t GetDigitalActionData(ulong inputHandle,ulong digitalActionHandle) +{ + CheckIfUsable(); + InputDigitalActionData_t result = NativeEntrypoints.SteamAPI_ISteamInput_GetDigitalActionData(m_pSteamInput,inputHandle,digitalActionHandle); + return result; +} +public override int GetDigitalActionOrigins(ulong inputHandle,ulong actionSetHandle,ulong digitalActionHandle,out uint [] originsOut) +{ + CheckIfUsable(); + originsOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamInput_GetDigitalActionOrigins(m_pSteamInput,inputHandle,actionSetHandle,digitalActionHandle,null); + originsOut= new uint[STEAM_INPUT_MAX_ORIGINS]; + result = NativeEntrypoints.SteamAPI_ISteamInput_GetDigitalActionOrigins(m_pSteamInput,inputHandle,actionSetHandle,digitalActionHandle,originsOut); + return result; +} +public override ulong GetAnalogActionHandle(string pszActionName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInput_GetAnalogActionHandle(m_pSteamInput,pszActionName); + return result; +} +public override InputAnalogActionData_t GetAnalogActionData(ulong inputHandle,ulong analogActionHandle) +{ + CheckIfUsable(); + InputAnalogActionData_t result = NativeEntrypoints.SteamAPI_ISteamInput_GetAnalogActionData(m_pSteamInput,inputHandle,analogActionHandle); + return result; +} +public override int GetAnalogActionOrigins(ulong inputHandle,ulong actionSetHandle,ulong analogActionHandle,out uint [] originsOut) +{ + CheckIfUsable(); + originsOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamInput_GetAnalogActionOrigins(m_pSteamInput,inputHandle,actionSetHandle,analogActionHandle,null); + originsOut= new uint[STEAM_INPUT_MAX_ORIGINS]; + result = NativeEntrypoints.SteamAPI_ISteamInput_GetAnalogActionOrigins(m_pSteamInput,inputHandle,actionSetHandle,analogActionHandle,originsOut); + return result; +} +public override string GetGlyphForActionOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamInput_GetGlyphForActionOrigin(m_pSteamInput,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override string GetStringForActionOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamInput_GetStringForActionOrigin(m_pSteamInput,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override void StopAnalogActionMomentum(ulong inputHandle,ulong eAction) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_StopAnalogActionMomentum(m_pSteamInput,inputHandle,eAction); +} +public override InputMotionData_t GetMotionData(ulong inputHandle) +{ + CheckIfUsable(); + InputMotionData_t result = NativeEntrypoints.SteamAPI_ISteamInput_GetMotionData(m_pSteamInput,inputHandle); + return result; +} +public override void TriggerVibration(ulong inputHandle,char usLeftSpeed,char usRightSpeed) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_TriggerVibration(m_pSteamInput,inputHandle,usLeftSpeed,usRightSpeed); +} +public override void SetLEDColor(ulong inputHandle,byte nColorR,byte nColorG,byte nColorB,uint nFlags) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_SetLEDColor(m_pSteamInput,inputHandle,nColorR,nColorG,nColorB,nFlags); +} +public override void TriggerHapticPulse(ulong inputHandle,uint eTargetPad,char usDurationMicroSec) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_TriggerHapticPulse(m_pSteamInput,inputHandle,eTargetPad,usDurationMicroSec); +} +public override void TriggerRepeatedHapticPulse(ulong inputHandle,uint eTargetPad,char usDurationMicroSec,char usOffMicroSec,char unRepeat,uint nFlags) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInput_TriggerRepeatedHapticPulse(m_pSteamInput,inputHandle,eTargetPad,usDurationMicroSec,usOffMicroSec,unRepeat,nFlags); +} +public override bool ShowBindingPanel(ulong inputHandle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInput_ShowBindingPanel(m_pSteamInput,inputHandle); + return result; +} +public override uint GetInputTypeForHandle(ulong inputHandle) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInput_GetInputTypeForHandle(m_pSteamInput,inputHandle); + return result; +} +public override ulong GetControllerForGamepadIndex(int nIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInput_GetControllerForGamepadIndex(m_pSteamInput,nIndex); + return result; +} +public override int GetGamepadIndexForController(ulong ulinputHandle) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamInput_GetGamepadIndexForController(m_pSteamInput,ulinputHandle); + return result; +} +public override string GetStringForXboxOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamInput_GetStringForXboxOrigin(m_pSteamInput,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override string GetGlyphForXboxOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamInput_GetGlyphForXboxOrigin(m_pSteamInput,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override uint GetActionOriginFromXboxOrigin(ulong inputHandle,uint eOrigin) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin(m_pSteamInput,inputHandle,eOrigin); + return result; +} +public override uint TranslateActionOrigin(uint eDestinationInputType,uint eSourceOrigin) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInput_TranslateActionOrigin(m_pSteamInput,eDestinationInputType,eSourceOrigin); + return result; +} +public override bool GetDeviceBindingRevision(ulong inputHandle,ref int pMajor,ref int pMinor) +{ + CheckIfUsable(); + pMajor = 0; + pMinor = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInput_GetDeviceBindingRevision(m_pSteamInput,inputHandle,ref pMajor,ref pMinor); + return result; +} +public override uint GetRemotePlaySessionID(ulong inputHandle) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInput_GetRemotePlaySessionID(m_pSteamInput,inputHandle); + return result; +} +} + + +public class CSteamController : ISteamController +{ +public CSteamController(IntPtr SteamController) +{ + m_pSteamController = SteamController; +} +IntPtr m_pSteamController; + +public override IntPtr GetIntPtr() { return m_pSteamController; } + +private void CheckIfUsable() +{ + if (m_pSteamController == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool Init() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamController_Init(m_pSteamController); + return result; +} +public override bool Shutdown() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamController_Shutdown(m_pSteamController); + return result; +} +public override void RunFrame() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_RunFrame(m_pSteamController); +} +public override int GetConnectedControllers(out ulong [] handlesOut) +{ + CheckIfUsable(); + handlesOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamController_GetConnectedControllers(m_pSteamController,null); + handlesOut= new ulong[STEAM_CONTROLLER_MAX_COUNT]; + result = NativeEntrypoints.SteamAPI_ISteamController_GetConnectedControllers(m_pSteamController,handlesOut); + return result; +} +public override ulong GetActionSetHandle(string pszActionSetName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamController_GetActionSetHandle(m_pSteamController,pszActionSetName); + return result; +} +public override void ActivateActionSet(ulong controllerHandle,ulong actionSetHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_ActivateActionSet(m_pSteamController,controllerHandle,actionSetHandle); +} +public override ulong GetCurrentActionSet(ulong controllerHandle) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamController_GetCurrentActionSet(m_pSteamController,controllerHandle); + return result; +} +public override void ActivateActionSetLayer(ulong controllerHandle,ulong actionSetLayerHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_ActivateActionSetLayer(m_pSteamController,controllerHandle,actionSetLayerHandle); +} +public override void DeactivateActionSetLayer(ulong controllerHandle,ulong actionSetLayerHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_DeactivateActionSetLayer(m_pSteamController,controllerHandle,actionSetLayerHandle); +} +public override void DeactivateAllActionSetLayers(ulong controllerHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_DeactivateAllActionSetLayers(m_pSteamController,controllerHandle); +} +public override int GetActiveActionSetLayers(ulong controllerHandle,out ulong [] handlesOut) +{ + CheckIfUsable(); + handlesOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamController_GetActiveActionSetLayers(m_pSteamController,controllerHandle,null); + handlesOut= new ulong[STEAM_CONTROLLER_MAX_ACTIVE_LAYERS]; + result = NativeEntrypoints.SteamAPI_ISteamController_GetActiveActionSetLayers(m_pSteamController,controllerHandle,handlesOut); + return result; +} +public override ulong GetDigitalActionHandle(string pszActionName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamController_GetDigitalActionHandle(m_pSteamController,pszActionName); + return result; +} +public override InputDigitalActionData_t GetDigitalActionData(ulong controllerHandle,ulong digitalActionHandle) +{ + CheckIfUsable(); + InputDigitalActionData_t result = NativeEntrypoints.SteamAPI_ISteamController_GetDigitalActionData(m_pSteamController,controllerHandle,digitalActionHandle); + return result; +} +public override int GetDigitalActionOrigins(ulong controllerHandle,ulong actionSetHandle,ulong digitalActionHandle,out uint [] originsOut) +{ + CheckIfUsable(); + originsOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamController_GetDigitalActionOrigins(m_pSteamController,controllerHandle,actionSetHandle,digitalActionHandle,null); + originsOut= new uint[STEAM_CONTROLLER_MAX_ORIGINS]; + result = NativeEntrypoints.SteamAPI_ISteamController_GetDigitalActionOrigins(m_pSteamController,controllerHandle,actionSetHandle,digitalActionHandle,originsOut); + return result; +} +public override ulong GetAnalogActionHandle(string pszActionName) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamController_GetAnalogActionHandle(m_pSteamController,pszActionName); + return result; +} +public override InputAnalogActionData_t GetAnalogActionData(ulong controllerHandle,ulong analogActionHandle) +{ + CheckIfUsable(); + InputAnalogActionData_t result = NativeEntrypoints.SteamAPI_ISteamController_GetAnalogActionData(m_pSteamController,controllerHandle,analogActionHandle); + return result; +} +public override int GetAnalogActionOrigins(ulong controllerHandle,ulong actionSetHandle,ulong analogActionHandle,out uint [] originsOut) +{ + CheckIfUsable(); + originsOut = 0; + int result = NativeEntrypoints.SteamAPI_ISteamController_GetAnalogActionOrigins(m_pSteamController,controllerHandle,actionSetHandle,analogActionHandle,null); + originsOut= new uint[STEAM_CONTROLLER_MAX_ORIGINS]; + result = NativeEntrypoints.SteamAPI_ISteamController_GetAnalogActionOrigins(m_pSteamController,controllerHandle,actionSetHandle,analogActionHandle,originsOut); + return result; +} +public override string GetGlyphForActionOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamController_GetGlyphForActionOrigin(m_pSteamController,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override string GetStringForActionOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamController_GetStringForActionOrigin(m_pSteamController,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override void StopAnalogActionMomentum(ulong controllerHandle,ulong eAction) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_StopAnalogActionMomentum(m_pSteamController,controllerHandle,eAction); +} +public override InputMotionData_t GetMotionData(ulong controllerHandle) +{ + CheckIfUsable(); + InputMotionData_t result = NativeEntrypoints.SteamAPI_ISteamController_GetMotionData(m_pSteamController,controllerHandle); + return result; +} +public override void TriggerHapticPulse(ulong controllerHandle,uint eTargetPad,char usDurationMicroSec) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_TriggerHapticPulse(m_pSteamController,controllerHandle,eTargetPad,usDurationMicroSec); +} +public override void TriggerRepeatedHapticPulse(ulong controllerHandle,uint eTargetPad,char usDurationMicroSec,char usOffMicroSec,char unRepeat,uint nFlags) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_TriggerRepeatedHapticPulse(m_pSteamController,controllerHandle,eTargetPad,usDurationMicroSec,usOffMicroSec,unRepeat,nFlags); +} +public override void TriggerVibration(ulong controllerHandle,char usLeftSpeed,char usRightSpeed) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_TriggerVibration(m_pSteamController,controllerHandle,usLeftSpeed,usRightSpeed); +} +public override void SetLEDColor(ulong controllerHandle,byte nColorR,byte nColorG,byte nColorB,uint nFlags) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamController_SetLEDColor(m_pSteamController,controllerHandle,nColorR,nColorG,nColorB,nFlags); +} +public override bool ShowBindingPanel(ulong controllerHandle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamController_ShowBindingPanel(m_pSteamController,controllerHandle); + return result; +} +public override uint GetInputTypeForHandle(ulong controllerHandle) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamController_GetInputTypeForHandle(m_pSteamController,controllerHandle); + return result; +} +public override ulong GetControllerForGamepadIndex(int nIndex) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamController_GetControllerForGamepadIndex(m_pSteamController,nIndex); + return result; +} +public override int GetGamepadIndexForController(ulong ulControllerHandle) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamController_GetGamepadIndexForController(m_pSteamController,ulControllerHandle); + return result; +} +public override string GetStringForXboxOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamController_GetStringForXboxOrigin(m_pSteamController,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override string GetGlyphForXboxOrigin(uint eOrigin) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamController_GetGlyphForXboxOrigin(m_pSteamController,eOrigin); + return Marshal.PtrToStringAnsi(result); +} +public override uint GetActionOriginFromXboxOrigin(ulong controllerHandle,uint eOrigin) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamController_GetActionOriginFromXboxOrigin(m_pSteamController,controllerHandle,eOrigin); + return result; +} +public override uint TranslateActionOrigin(uint eDestinationInputType,uint eSourceOrigin) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamController_TranslateActionOrigin(m_pSteamController,eDestinationInputType,eSourceOrigin); + return result; +} +public override bool GetControllerBindingRevision(ulong controllerHandle,ref int pMajor,ref int pMinor) +{ + CheckIfUsable(); + pMajor = 0; + pMinor = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamController_GetControllerBindingRevision(m_pSteamController,controllerHandle,ref pMajor,ref pMinor); + return result; +} +} + + +public class CSteamUGC : ISteamUGC +{ +public CSteamUGC(IntPtr SteamUGC) +{ + m_pSteamUGC = SteamUGC; +} +IntPtr m_pSteamUGC; + +public override IntPtr GetIntPtr() { return m_pSteamUGC; } + +private void CheckIfUsable() +{ + if (m_pSteamUGC == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override ulong CreateQueryUserUGCRequest(uint unAccountID,uint eListType,uint eMatchingUGCType,uint eSortOrder,uint nCreatorAppID,uint nConsumerAppID,uint unPage) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_CreateQueryUserUGCRequest(m_pSteamUGC,unAccountID,eListType,eMatchingUGCType,eSortOrder,nCreatorAppID,nConsumerAppID,unPage); + return result; +} +public override ulong CreateQueryAllUGCRequest(uint eQueryType,uint eMatchingeMatchingUGCTypeFileType,uint nCreatorAppID,uint nConsumerAppID,uint unPage) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_CreateQueryAllUGCRequest(m_pSteamUGC,eQueryType,eMatchingeMatchingUGCTypeFileType,nCreatorAppID,nConsumerAppID,unPage); + return result; +} +public override ulong CreateQueryAllUGCRequest0(uint eQueryType,uint eMatchingeMatchingUGCTypeFileType,uint nCreatorAppID,uint nConsumerAppID,string pchCursor) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_CreateQueryAllUGCRequest0(m_pSteamUGC,eQueryType,eMatchingeMatchingUGCTypeFileType,nCreatorAppID,nConsumerAppID,pchCursor); + return result; +} +public override ulong CreateQueryUGCDetailsRequest(ref ulong pvecPublishedFileID,uint unNumPublishedFileIDs) +{ + CheckIfUsable(); + pvecPublishedFileID = 0; + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest(m_pSteamUGC,ref pvecPublishedFileID,unNumPublishedFileIDs); + return result; +} +public override ulong SendQueryUGCRequest(ulong handle) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_SendQueryUGCRequest(m_pSteamUGC,handle); + return result; +} +public override bool GetQueryUGCResult(ulong handle,uint index,ref SteamUGCDetails_t pDetails) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCResult(m_pSteamUGC,handle,index,ref pDetails); + return result; +} +public override bool GetQueryUGCPreviewURL(ulong handle,uint index,out string pchURL) +{ + CheckIfUsable(); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder(2048); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCPreviewURL(m_pSteamUGC,handle,index,pStrBuffer1,2048); + pchURL = pStrBuffer1.ToString(); + return result; +} +public override bool GetQueryUGCMetadata(ulong handle,uint index,out string pchMetadata) +{ + CheckIfUsable(); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder(2048); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCMetadata(m_pSteamUGC,handle,index,pStrBuffer1,2048); + pchMetadata = pStrBuffer1.ToString(); + return result; +} +public override bool GetQueryUGCChildren(ulong handle,uint index,ref ulong pvecPublishedFileID,uint cMaxEntries) +{ + CheckIfUsable(); + pvecPublishedFileID = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCChildren(m_pSteamUGC,handle,index,ref pvecPublishedFileID,cMaxEntries); + return result; +} +public override bool GetQueryUGCStatistic(ulong handle,uint index,uint eStatType,ref ulong pStatValue) +{ + CheckIfUsable(); + pStatValue = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCStatistic(m_pSteamUGC,handle,index,eStatType,ref pStatValue); + return result; +} +public override uint GetQueryUGCNumAdditionalPreviews(ulong handle,uint index) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews(m_pSteamUGC,handle,index); + return result; +} +public override bool GetQueryUGCAdditionalPreview(ulong handle,uint index,uint previewIndex,out string pchURLOrVideoID,out string pchOriginalFileName,uint cchOriginalFileNameSize,ref uint pPreviewType) +{ + CheckIfUsable(); + pPreviewType = 0; + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder(2048); + System.Text.StringBuilder pStrBuffer2 = new System.Text.StringBuilder(2048); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview(m_pSteamUGC,handle,index,previewIndex,pStrBuffer1,2048,pStrBuffer2,cchOriginalFileNameSize,ref pPreviewType); + pchURLOrVideoID = pStrBuffer1.ToString(); + pchOriginalFileName = pStrBuffer2.ToString(); + return result; +} +public override uint GetQueryUGCNumKeyValueTags(ulong handle,uint index) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags(m_pSteamUGC,handle,index); + return result; +} +public override bool GetQueryUGCKeyValueTag(ulong handle,uint index,uint keyValueTagIndex,out string pchKey,out string pchValue) +{ + CheckIfUsable(); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder(2048); + System.Text.StringBuilder pStrBuffer2 = new System.Text.StringBuilder(2048); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag(m_pSteamUGC,handle,index,keyValueTagIndex,pStrBuffer1,2048,pStrBuffer2,2048); + pchKey = pStrBuffer1.ToString(); + pchValue = pStrBuffer2.ToString(); + return result; +} +public override bool GetQueryUGCKeyValueTag0(ulong handle,uint index,string pchKey,out string pchValue) +{ + CheckIfUsable(); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder(2048); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag0(m_pSteamUGC,handle,index,pchKey,pStrBuffer1,2048); + pchValue = pStrBuffer1.ToString(); + return result; +} +public override bool ReleaseQueryUGCRequest(ulong handle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_ReleaseQueryUGCRequest(m_pSteamUGC,handle); + return result; +} +public override bool AddRequiredTag(ulong handle,string pTagName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_AddRequiredTag(m_pSteamUGC,handle,pTagName); + return result; +} +public override bool AddExcludedTag(ulong handle,string pTagName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_AddExcludedTag(m_pSteamUGC,handle,pTagName); + return result; +} +public override bool SetReturnOnlyIDs(ulong handle,bool bReturnOnlyIDs) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnOnlyIDs(m_pSteamUGC,handle,bReturnOnlyIDs); + return result; +} +public override bool SetReturnKeyValueTags(ulong handle,bool bReturnKeyValueTags) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnKeyValueTags(m_pSteamUGC,handle,bReturnKeyValueTags); + return result; +} +public override bool SetReturnLongDescription(ulong handle,bool bReturnLongDescription) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnLongDescription(m_pSteamUGC,handle,bReturnLongDescription); + return result; +} +public override bool SetReturnMetadata(ulong handle,bool bReturnMetadata) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnMetadata(m_pSteamUGC,handle,bReturnMetadata); + return result; +} +public override bool SetReturnChildren(ulong handle,bool bReturnChildren) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnChildren(m_pSteamUGC,handle,bReturnChildren); + return result; +} +public override bool SetReturnAdditionalPreviews(ulong handle,bool bReturnAdditionalPreviews) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnAdditionalPreviews(m_pSteamUGC,handle,bReturnAdditionalPreviews); + return result; +} +public override bool SetReturnTotalOnly(ulong handle,bool bReturnTotalOnly) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnTotalOnly(m_pSteamUGC,handle,bReturnTotalOnly); + return result; +} +public override bool SetReturnPlaytimeStats(ulong handle,uint unDays) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetReturnPlaytimeStats(m_pSteamUGC,handle,unDays); + return result; +} +public override bool SetLanguage(ulong handle,string pchLanguage) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetLanguage(m_pSteamUGC,handle,pchLanguage); + return result; +} +public override bool SetAllowCachedResponse(ulong handle,uint unMaxAgeSeconds) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetAllowCachedResponse(m_pSteamUGC,handle,unMaxAgeSeconds); + return result; +} +public override bool SetCloudFileNameFilter(ulong handle,string pMatchCloudFileName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetCloudFileNameFilter(m_pSteamUGC,handle,pMatchCloudFileName); + return result; +} +public override bool SetMatchAnyTag(ulong handle,bool bMatchAnyTag) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetMatchAnyTag(m_pSteamUGC,handle,bMatchAnyTag); + return result; +} +public override bool SetSearchText(ulong handle,string pSearchText) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetSearchText(m_pSteamUGC,handle,pSearchText); + return result; +} +public override bool SetRankedByTrendDays(ulong handle,uint unDays) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetRankedByTrendDays(m_pSteamUGC,handle,unDays); + return result; +} +public override bool AddRequiredKeyValueTag(ulong handle,string pKey,string pValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_AddRequiredKeyValueTag(m_pSteamUGC,handle,pKey,pValue); + return result; +} +public override ulong RequestUGCDetails(ulong nPublishedFileID,uint unMaxAgeSeconds) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_RequestUGCDetails(m_pSteamUGC,nPublishedFileID,unMaxAgeSeconds); + return result; +} +public override ulong CreateItem(uint nConsumerAppId,uint eFileType) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_CreateItem(m_pSteamUGC,nConsumerAppId,eFileType); + return result; +} +public override ulong StartItemUpdate(uint nConsumerAppId,ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_StartItemUpdate(m_pSteamUGC,nConsumerAppId,nPublishedFileID); + return result; +} +public override bool SetItemTitle(ulong handle,string pchTitle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemTitle(m_pSteamUGC,handle,pchTitle); + return result; +} +public override bool SetItemDescription(ulong handle,string pchDescription) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemDescription(m_pSteamUGC,handle,pchDescription); + return result; +} +public override bool SetItemUpdateLanguage(ulong handle,string pchLanguage) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemUpdateLanguage(m_pSteamUGC,handle,pchLanguage); + return result; +} +public override bool SetItemMetadata(ulong handle,string pchMetaData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemMetadata(m_pSteamUGC,handle,pchMetaData); + return result; +} +public override bool SetItemVisibility(ulong handle,uint eVisibility) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemVisibility(m_pSteamUGC,handle,eVisibility); + return result; +} +public override bool SetItemTags(ulong updateHandle,ref SteamParamStringArray_t pTags) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemTags(m_pSteamUGC,updateHandle,ref pTags); + return result; +} +public override bool SetItemContent(ulong handle,string pszContentFolder) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemContent(m_pSteamUGC,handle,pszContentFolder); + return result; +} +public override bool SetItemPreview(ulong handle,string pszPreviewFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetItemPreview(m_pSteamUGC,handle,pszPreviewFile); + return result; +} +public override bool SetAllowLegacyUpload(ulong handle,bool bAllowLegacyUpload) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_SetAllowLegacyUpload(m_pSteamUGC,handle,bAllowLegacyUpload); + return result; +} +public override bool RemoveAllItemKeyValueTags(ulong handle) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags(m_pSteamUGC,handle); + return result; +} +public override bool RemoveItemKeyValueTags(ulong handle,string pchKey) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_RemoveItemKeyValueTags(m_pSteamUGC,handle,pchKey); + return result; +} +public override bool AddItemKeyValueTag(ulong handle,string pchKey,string pchValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_AddItemKeyValueTag(m_pSteamUGC,handle,pchKey,pchValue); + return result; +} +public override bool AddItemPreviewFile(ulong handle,string pszPreviewFile,uint type) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_AddItemPreviewFile(m_pSteamUGC,handle,pszPreviewFile,type); + return result; +} +public override bool AddItemPreviewVideo(ulong handle,string pszVideoID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_AddItemPreviewVideo(m_pSteamUGC,handle,pszVideoID); + return result; +} +public override bool UpdateItemPreviewFile(ulong handle,uint index,string pszPreviewFile) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_UpdateItemPreviewFile(m_pSteamUGC,handle,index,pszPreviewFile); + return result; +} +public override bool UpdateItemPreviewVideo(ulong handle,uint index,string pszVideoID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_UpdateItemPreviewVideo(m_pSteamUGC,handle,index,pszVideoID); + return result; +} +public override bool RemoveItemPreview(ulong handle,uint index) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_RemoveItemPreview(m_pSteamUGC,handle,index); + return result; +} +public override ulong SubmitItemUpdate(ulong handle,string pchChangeNote) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_SubmitItemUpdate(m_pSteamUGC,handle,pchChangeNote); + return result; +} +public override uint GetItemUpdateProgress(ulong handle,ref ulong punBytesProcessed,ref ulong punBytesTotal) +{ + CheckIfUsable(); + punBytesProcessed = 0; + punBytesTotal = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamUGC_GetItemUpdateProgress(m_pSteamUGC,handle,ref punBytesProcessed,ref punBytesTotal); + return result; +} +public override ulong SetUserItemVote(ulong nPublishedFileID,bool bVoteUp) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_SetUserItemVote(m_pSteamUGC,nPublishedFileID,bVoteUp); + return result; +} +public override ulong GetUserItemVote(ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_GetUserItemVote(m_pSteamUGC,nPublishedFileID); + return result; +} +public override ulong AddItemToFavorites(uint nAppId,ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_AddItemToFavorites(m_pSteamUGC,nAppId,nPublishedFileID); + return result; +} +public override ulong RemoveItemFromFavorites(uint nAppId,ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_RemoveItemFromFavorites(m_pSteamUGC,nAppId,nPublishedFileID); + return result; +} +public override ulong SubscribeItem(ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_SubscribeItem(m_pSteamUGC,nPublishedFileID); + return result; +} +public override ulong UnsubscribeItem(ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_UnsubscribeItem(m_pSteamUGC,nPublishedFileID); + return result; +} +public override uint GetNumSubscribedItems() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUGC_GetNumSubscribedItems(m_pSteamUGC); + return result; +} +public override uint GetSubscribedItems(ref ulong pvecPublishedFileID,uint cMaxEntries) +{ + CheckIfUsable(); + pvecPublishedFileID = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamUGC_GetSubscribedItems(m_pSteamUGC,ref pvecPublishedFileID,cMaxEntries); + return result; +} +public override uint GetItemState(ulong nPublishedFileID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamUGC_GetItemState(m_pSteamUGC,nPublishedFileID); + return result; +} +public override bool GetItemInstallInfo(ulong nPublishedFileID,ref ulong punSizeOnDisk,out string pchFolder,ref uint punTimeStamp) +{ + CheckIfUsable(); + punSizeOnDisk = 0; + punTimeStamp = 0; + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder(2048); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetItemInstallInfo(m_pSteamUGC,nPublishedFileID,ref punSizeOnDisk,pStrBuffer1,2048,ref punTimeStamp); + pchFolder = pStrBuffer1.ToString(); + return result; +} +public override bool GetItemDownloadInfo(ulong nPublishedFileID,ref ulong punBytesDownloaded,ref ulong punBytesTotal) +{ + CheckIfUsable(); + punBytesDownloaded = 0; + punBytesTotal = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_GetItemDownloadInfo(m_pSteamUGC,nPublishedFileID,ref punBytesDownloaded,ref punBytesTotal); + return result; +} +public override bool DownloadItem(ulong nPublishedFileID,bool bHighPriority) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_DownloadItem(m_pSteamUGC,nPublishedFileID,bHighPriority); + return result; +} +public override bool BInitWorkshopForGameServer(uint unWorkshopDepotID,string pszFolder) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamUGC_BInitWorkshopForGameServer(m_pSteamUGC,unWorkshopDepotID,pszFolder); + return result; +} +public override void SuspendDownloads(bool bSuspend) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamUGC_SuspendDownloads(m_pSteamUGC,bSuspend); +} +public override ulong StartPlaytimeTracking(ref ulong pvecPublishedFileID,uint unNumPublishedFileIDs) +{ + CheckIfUsable(); + pvecPublishedFileID = 0; + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_StartPlaytimeTracking(m_pSteamUGC,ref pvecPublishedFileID,unNumPublishedFileIDs); + return result; +} +public override ulong StopPlaytimeTracking(ref ulong pvecPublishedFileID,uint unNumPublishedFileIDs) +{ + CheckIfUsable(); + pvecPublishedFileID = 0; + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_StopPlaytimeTracking(m_pSteamUGC,ref pvecPublishedFileID,unNumPublishedFileIDs); + return result; +} +public override ulong StopPlaytimeTrackingForAllItems() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems(m_pSteamUGC); + return result; +} +public override ulong AddDependency(ulong nParentPublishedFileID,ulong nChildPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_AddDependency(m_pSteamUGC,nParentPublishedFileID,nChildPublishedFileID); + return result; +} +public override ulong RemoveDependency(ulong nParentPublishedFileID,ulong nChildPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_RemoveDependency(m_pSteamUGC,nParentPublishedFileID,nChildPublishedFileID); + return result; +} +public override ulong AddAppDependency(ulong nPublishedFileID,uint nAppID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_AddAppDependency(m_pSteamUGC,nPublishedFileID,nAppID); + return result; +} +public override ulong RemoveAppDependency(ulong nPublishedFileID,uint nAppID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_RemoveAppDependency(m_pSteamUGC,nPublishedFileID,nAppID); + return result; +} +public override ulong GetAppDependencies(ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_GetAppDependencies(m_pSteamUGC,nPublishedFileID); + return result; +} +public override ulong DeleteItem(ulong nPublishedFileID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamUGC_DeleteItem(m_pSteamUGC,nPublishedFileID); + return result; +} +} + + +public class CSteamAppList : ISteamAppList +{ +public CSteamAppList(IntPtr SteamAppList) +{ + m_pSteamAppList = SteamAppList; +} +IntPtr m_pSteamAppList; + +public override IntPtr GetIntPtr() { return m_pSteamAppList; } + +private void CheckIfUsable() +{ + if (m_pSteamAppList == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint GetNumInstalledApps() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamAppList_GetNumInstalledApps(m_pSteamAppList); + return result; +} +public override uint GetInstalledApps(ref uint pvecAppID,uint unMaxAppIDs) +{ + CheckIfUsable(); + pvecAppID = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamAppList_GetInstalledApps(m_pSteamAppList,ref pvecAppID,unMaxAppIDs); + return result; +} +public override int GetAppName(uint nAppID,System.Text.StringBuilder pchName,int cchNameMax) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamAppList_GetAppName(m_pSteamAppList,nAppID,pchName,cchNameMax); + return result; +} +public override int GetAppInstallDir(uint nAppID,string pchDirectory,int cchNameMax) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamAppList_GetAppInstallDir(m_pSteamAppList,nAppID,pchDirectory,cchNameMax); + return result; +} +public override int GetAppBuildId(uint nAppID) +{ + CheckIfUsable(); + int result = NativeEntrypoints.SteamAPI_ISteamAppList_GetAppBuildId(m_pSteamAppList,nAppID); + return result; +} +} + + +public class CSteamHTMLSurface : ISteamHTMLSurface +{ +public CSteamHTMLSurface(IntPtr SteamHTMLSurface) +{ + m_pSteamHTMLSurface = SteamHTMLSurface; +} +IntPtr m_pSteamHTMLSurface; + +public override IntPtr GetIntPtr() { return m_pSteamHTMLSurface; } + +private void CheckIfUsable() +{ + if (m_pSteamHTMLSurface == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override void DestructISteamHTMLSurface() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_DestructISteamHTMLSurface(m_pSteamHTMLSurface); +} +public override bool Init() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTMLSurface_Init(m_pSteamHTMLSurface); + return result; +} +public override bool Shutdown() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamHTMLSurface_Shutdown(m_pSteamHTMLSurface); + return result; +} +public override ulong CreateBrowser(string pchUserAgent,string pchUserCSS) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamHTMLSurface_CreateBrowser(m_pSteamHTMLSurface,pchUserAgent,pchUserCSS); + return result; +} +public override void RemoveBrowser(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_RemoveBrowser(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void LoadURL(uint unBrowserHandle,string pchURL,string pchPostData) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_LoadURL(m_pSteamHTMLSurface,unBrowserHandle,pchURL,pchPostData); +} +public override void SetSize(uint unBrowserHandle,uint unWidth,uint unHeight) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetSize(m_pSteamHTMLSurface,unBrowserHandle,unWidth,unHeight); +} +public override void StopLoad(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_StopLoad(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void Reload(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_Reload(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void GoBack(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_GoBack(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void GoForward(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_GoForward(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void AddHeader(uint unBrowserHandle,string pchKey,string pchValue) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_AddHeader(m_pSteamHTMLSurface,unBrowserHandle,pchKey,pchValue); +} +public override void ExecuteJavascript(uint unBrowserHandle,string pchScript) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_ExecuteJavascript(m_pSteamHTMLSurface,unBrowserHandle,pchScript); +} +public override void MouseUp(uint unBrowserHandle,uint eMouseButton) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_MouseUp(m_pSteamHTMLSurface,unBrowserHandle,eMouseButton); +} +public override void MouseDown(uint unBrowserHandle,uint eMouseButton) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_MouseDown(m_pSteamHTMLSurface,unBrowserHandle,eMouseButton); +} +public override void MouseDoubleClick(uint unBrowserHandle,uint eMouseButton) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_MouseDoubleClick(m_pSteamHTMLSurface,unBrowserHandle,eMouseButton); +} +public override void MouseMove(uint unBrowserHandle,int x,int y) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_MouseMove(m_pSteamHTMLSurface,unBrowserHandle,x,y); +} +public override void MouseWheel(uint unBrowserHandle,int nDelta) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_MouseWheel(m_pSteamHTMLSurface,unBrowserHandle,nDelta); +} +public override void KeyDown(uint unBrowserHandle,uint nNativeKeyCode,uint eHTMLKeyModifiers,bool bIsSystemKey) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_KeyDown(m_pSteamHTMLSurface,unBrowserHandle,nNativeKeyCode,eHTMLKeyModifiers,bIsSystemKey); +} +public override void KeyUp(uint unBrowserHandle,uint nNativeKeyCode,uint eHTMLKeyModifiers) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_KeyUp(m_pSteamHTMLSurface,unBrowserHandle,nNativeKeyCode,eHTMLKeyModifiers); +} +public override void KeyChar(uint unBrowserHandle,uint cUnicodeChar,uint eHTMLKeyModifiers) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_KeyChar(m_pSteamHTMLSurface,unBrowserHandle,cUnicodeChar,eHTMLKeyModifiers); +} +public override void SetHorizontalScroll(uint unBrowserHandle,uint nAbsolutePixelScroll) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetHorizontalScroll(m_pSteamHTMLSurface,unBrowserHandle,nAbsolutePixelScroll); +} +public override void SetVerticalScroll(uint unBrowserHandle,uint nAbsolutePixelScroll) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetVerticalScroll(m_pSteamHTMLSurface,unBrowserHandle,nAbsolutePixelScroll); +} +public override void SetKeyFocus(uint unBrowserHandle,bool bHasKeyFocus) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetKeyFocus(m_pSteamHTMLSurface,unBrowserHandle,bHasKeyFocus); +} +public override void ViewSource(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_ViewSource(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void CopyToClipboard(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_CopyToClipboard(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void PasteFromClipboard(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_PasteFromClipboard(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void Find(uint unBrowserHandle,string pchSearchStr,bool bCurrentlyInFind,bool bReverse) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_Find(m_pSteamHTMLSurface,unBrowserHandle,pchSearchStr,bCurrentlyInFind,bReverse); +} +public override void StopFind(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_StopFind(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void GetLinkAtPosition(uint unBrowserHandle,int x,int y) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_GetLinkAtPosition(m_pSteamHTMLSurface,unBrowserHandle,x,y); +} +public override void SetCookie(string pchHostname,string pchKey,string pchValue,string pchPath,ulong nExpires,bool bSecure,bool bHTTPOnly) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetCookie(m_pSteamHTMLSurface,pchHostname,pchKey,pchValue,pchPath,nExpires,bSecure,bHTTPOnly); +} +public override void SetPageScaleFactor(uint unBrowserHandle,float flZoom,int nPointX,int nPointY) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetPageScaleFactor(m_pSteamHTMLSurface,unBrowserHandle,flZoom,nPointX,nPointY); +} +public override void SetBackgroundMode(uint unBrowserHandle,bool bBackgroundMode) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetBackgroundMode(m_pSteamHTMLSurface,unBrowserHandle,bBackgroundMode); +} +public override void SetDPIScalingFactor(uint unBrowserHandle,float flDPIScaling) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor(m_pSteamHTMLSurface,unBrowserHandle,flDPIScaling); +} +public override void OpenDeveloperTools(uint unBrowserHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_OpenDeveloperTools(m_pSteamHTMLSurface,unBrowserHandle); +} +public override void AllowStartRequest(uint unBrowserHandle,bool bAllowed) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_AllowStartRequest(m_pSteamHTMLSurface,unBrowserHandle,bAllowed); +} +public override void JSDialogResponse(uint unBrowserHandle,bool bResult) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamHTMLSurface_JSDialogResponse(m_pSteamHTMLSurface,unBrowserHandle,bResult); +} +} + + +public class CSteamInventory : ISteamInventory +{ +public CSteamInventory(IntPtr SteamInventory) +{ + m_pSteamInventory = SteamInventory; +} +IntPtr m_pSteamInventory; + +public override IntPtr GetIntPtr() { return m_pSteamInventory; } + +private void CheckIfUsable() +{ + if (m_pSteamInventory == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint GetResultStatus(int resultHandle) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInventory_GetResultStatus(m_pSteamInventory,resultHandle); + return result; +} +public override bool GetResultItems(int resultHandle,out SteamItemDetails_t [] pOutItemsArray) +{ + CheckIfUsable(); + uint punOutItemsArraySize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetResultItems(m_pSteamInventory,resultHandle,null,ref punOutItemsArraySize); + pOutItemsArray= new SteamItemDetails_t[punOutItemsArraySize]; + result = NativeEntrypoints.SteamAPI_ISteamInventory_GetResultItems(m_pSteamInventory,resultHandle,pOutItemsArray,ref punOutItemsArraySize); + return result; +} +public override bool GetResultItemProperty(int resultHandle,uint unItemIndex,string pchPropertyName,out string pchValueBuffer) +{ + CheckIfUsable(); + uint punValueBufferSizeOut = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetResultItemProperty(m_pSteamInventory,resultHandle,unItemIndex,pchPropertyName,null,ref punValueBufferSizeOut); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder((int)punValueBufferSizeOut); + result = NativeEntrypoints.SteamAPI_ISteamInventory_GetResultItemProperty(m_pSteamInventory,resultHandle,unItemIndex,pchPropertyName,pStrBuffer1,ref punValueBufferSizeOut); + pchValueBuffer = pStrBuffer1.ToString(); + return result; +} +public override uint GetResultTimestamp(int resultHandle) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInventory_GetResultTimestamp(m_pSteamInventory,resultHandle); + return result; +} +public override bool CheckResultSteamID(int resultHandle,ulong steamIDExpected) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_CheckResultSteamID(m_pSteamInventory,resultHandle,steamIDExpected); + return result; +} +public override void DestroyResult(int resultHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInventory_DestroyResult(m_pSteamInventory,resultHandle); +} +public override bool GetAllItems(ref int pResultHandle) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetAllItems(m_pSteamInventory,ref pResultHandle); + return result; +} +public override bool GetItemsByID(ref int pResultHandle,ulong [] pInstanceIDs) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemsByID(m_pSteamInventory,ref pResultHandle,pInstanceIDs,(uint) pInstanceIDs.Length); + return result; +} +public override bool SerializeResult(int resultHandle,IntPtr pOutBuffer,ref uint punOutBufferSize) +{ + CheckIfUsable(); + punOutBufferSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_SerializeResult(m_pSteamInventory,resultHandle,pOutBuffer,ref punOutBufferSize); + return result; +} +public override bool DeserializeResult(ref int pOutResultHandle,IntPtr pBuffer,uint unBufferSize,bool bRESERVED_MUST_BE_FALSE) +{ + CheckIfUsable(); + pOutResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_DeserializeResult(m_pSteamInventory,ref pOutResultHandle,pBuffer,unBufferSize,bRESERVED_MUST_BE_FALSE); + return result; +} +public override bool GenerateItems(ref int pResultHandle,int [] pArrayItemDefs,uint [] punArrayQuantity) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GenerateItems(m_pSteamInventory,ref pResultHandle,pArrayItemDefs,punArrayQuantity,(uint) punArrayQuantity.Length); + return result; +} +public override bool GrantPromoItems(ref int pResultHandle) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GrantPromoItems(m_pSteamInventory,ref pResultHandle); + return result; +} +public override bool AddPromoItem(ref int pResultHandle,int itemDef) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_AddPromoItem(m_pSteamInventory,ref pResultHandle,itemDef); + return result; +} +public override bool AddPromoItems(ref int pResultHandle,int [] pArrayItemDefs) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_AddPromoItems(m_pSteamInventory,ref pResultHandle,pArrayItemDefs,(uint) pArrayItemDefs.Length); + return result; +} +public override bool ConsumeItem(ref int pResultHandle,ulong itemConsume,uint unQuantity) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_ConsumeItem(m_pSteamInventory,ref pResultHandle,itemConsume,unQuantity); + return result; +} +public override bool ExchangeItems(ref int pResultHandle,int [] pArrayGenerate,uint [] punArrayGenerateQuantity,ulong [] pArrayDestroy,uint [] punArrayDestroyQuantity) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_ExchangeItems(m_pSteamInventory,ref pResultHandle,pArrayGenerate,punArrayGenerateQuantity,(uint) punArrayGenerateQuantity.Length,pArrayDestroy,punArrayDestroyQuantity,(uint) punArrayDestroyQuantity.Length); + return result; +} +public override bool TransferItemQuantity(ref int pResultHandle,ulong itemIdSource,uint unQuantity,ulong itemIdDest) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_TransferItemQuantity(m_pSteamInventory,ref pResultHandle,itemIdSource,unQuantity,itemIdDest); + return result; +} +public override void SendItemDropHeartbeat() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamInventory_SendItemDropHeartbeat(m_pSteamInventory); +} +public override bool TriggerItemDrop(ref int pResultHandle,int dropListDefinition) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_TriggerItemDrop(m_pSteamInventory,ref pResultHandle,dropListDefinition); + return result; +} +public override bool TradeItems(ref int pResultHandle,ulong steamIDTradePartner,ulong [] pArrayGive,uint [] pArrayGiveQuantity,ulong [] pArrayGet,uint [] pArrayGetQuantity) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_TradeItems(m_pSteamInventory,ref pResultHandle,steamIDTradePartner,pArrayGive,pArrayGiveQuantity,(uint) pArrayGiveQuantity.Length,pArrayGet,pArrayGetQuantity,(uint) pArrayGetQuantity.Length); + return result; +} +public override bool LoadItemDefinitions() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_LoadItemDefinitions(m_pSteamInventory); + return result; +} +public override bool GetItemDefinitionIDs(out int [] pItemDefIDs) +{ + CheckIfUsable(); + uint punItemDefIDsArraySize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemDefinitionIDs(m_pSteamInventory,null,ref punItemDefIDsArraySize); + pItemDefIDs= new int[punItemDefIDsArraySize]; + result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemDefinitionIDs(m_pSteamInventory,pItemDefIDs,ref punItemDefIDsArraySize); + return result; +} +public override bool GetItemDefinitionProperty(int iDefinition,string pchPropertyName,out string pchValueBuffer) +{ + CheckIfUsable(); + uint punValueBufferSizeOut = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemDefinitionProperty(m_pSteamInventory,iDefinition,pchPropertyName,null,ref punValueBufferSizeOut); + System.Text.StringBuilder pStrBuffer1 = new System.Text.StringBuilder((int)punValueBufferSizeOut); + result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemDefinitionProperty(m_pSteamInventory,iDefinition,pchPropertyName,pStrBuffer1,ref punValueBufferSizeOut); + pchValueBuffer = pStrBuffer1.ToString(); + return result; +} +public override ulong RequestEligiblePromoItemDefinitionsIDs(ulong steamID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs(m_pSteamInventory,steamID); + return result; +} +public override bool GetEligiblePromoItemDefinitionIDs(ulong steamID,out int [] pItemDefIDs) +{ + CheckIfUsable(); + uint punItemDefIDsArraySize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs(m_pSteamInventory,steamID,null,ref punItemDefIDsArraySize); + pItemDefIDs= new int[punItemDefIDsArraySize]; + result = NativeEntrypoints.SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs(m_pSteamInventory,steamID,pItemDefIDs,ref punItemDefIDsArraySize); + return result; +} +public override ulong StartPurchase(int [] pArrayItemDefs,uint [] punArrayQuantity) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInventory_StartPurchase(m_pSteamInventory,pArrayItemDefs,punArrayQuantity,(uint) punArrayQuantity.Length); + return result; +} +public override ulong RequestPrices() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInventory_RequestPrices(m_pSteamInventory); + return result; +} +public override uint GetNumItemsWithPrices() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamInventory_GetNumItemsWithPrices(m_pSteamInventory); + return result; +} +public override bool GetItemsWithPrices(out int [] pArrayItemDefs,out ulong [] pCurrentPrices,out ulong [] pBasePrices,uint unArrayLength) +{ + CheckIfUsable(); + pArrayItemDefs = 0; + pPrices = 0; + pBasePrices = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemsWithPrices(m_pSteamInventory,pArrayItemDefs,pCurrentPrices,null,unArrayLength); + pArrayItemDefs= new int[pArrayItemDefs]; + pCurrentPrices= new ulong[pPrices]; + pBasePrices= new ulong[pPrices]; + result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemsWithPrices(m_pSteamInventory,pArrayItemDefs,pCurrentPrices,pBasePrices,unArrayLength); + return result; +} +public override bool GetItemPrice(int iDefinition,ref ulong pCurrentPrice,ref ulong pBasePrice) +{ + CheckIfUsable(); + pCurrentPrice = 0; + pBasePrice = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_GetItemPrice(m_pSteamInventory,iDefinition,ref pCurrentPrice,ref pBasePrice); + return result; +} +public override ulong StartUpdateProperties() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamInventory_StartUpdateProperties(m_pSteamInventory); + return result; +} +public override bool RemoveProperty(ulong handle,ulong nItemID,string pchPropertyName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_RemoveProperty(m_pSteamInventory,handle,nItemID,pchPropertyName); + return result; +} +public override bool SetProperty(ulong handle,ulong nItemID,string pchPropertyName,string pchPropertyValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_SetProperty(m_pSteamInventory,handle,nItemID,pchPropertyName,pchPropertyValue); + return result; +} +public override bool SetProperty0(ulong handle,ulong nItemID,string pchPropertyName,bool bValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_SetProperty0(m_pSteamInventory,handle,nItemID,pchPropertyName,bValue); + return result; +} +public override bool SetProperty1(ulong handle,ulong nItemID,string pchPropertyName,long nValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_SetProperty1(m_pSteamInventory,handle,nItemID,pchPropertyName,nValue); + return result; +} +public override bool SetProperty2(ulong handle,ulong nItemID,string pchPropertyName,float flValue) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_SetProperty2(m_pSteamInventory,handle,nItemID,pchPropertyName,flValue); + return result; +} +public override bool SubmitUpdateProperties(ulong handle,ref int pResultHandle) +{ + CheckIfUsable(); + pResultHandle = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamInventory_SubmitUpdateProperties(m_pSteamInventory,handle,ref pResultHandle); + return result; +} +} + + +public class CSteamVideo : ISteamVideo +{ +public CSteamVideo(IntPtr SteamVideo) +{ + m_pSteamVideo = SteamVideo; +} +IntPtr m_pSteamVideo; + +public override IntPtr GetIntPtr() { return m_pSteamVideo; } + +private void CheckIfUsable() +{ + if (m_pSteamVideo == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override void GetVideoURL(uint unVideoAppID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamVideo_GetVideoURL(m_pSteamVideo,unVideoAppID); +} +public override bool IsBroadcasting(ref int pnNumViewers) +{ + CheckIfUsable(); + pnNumViewers = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamVideo_IsBroadcasting(m_pSteamVideo,ref pnNumViewers); + return result; +} +public override void GetOPFSettings(uint unVideoAppID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamVideo_GetOPFSettings(m_pSteamVideo,unVideoAppID); +} +public override bool GetOPFStringForApp(uint unVideoAppID,string pchBuffer,ref int pnBufferSize) +{ + CheckIfUsable(); + pnBufferSize = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamVideo_GetOPFStringForApp(m_pSteamVideo,unVideoAppID,pchBuffer,ref pnBufferSize); + return result; +} +} + + +public class CSteamTV : ISteamTV +{ +public CSteamTV(IntPtr SteamTV) +{ + m_pSteamTV = SteamTV; +} +IntPtr m_pSteamTV; + +public override IntPtr GetIntPtr() { return m_pSteamTV; } + +private void CheckIfUsable() +{ + if (m_pSteamTV == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool IsBroadcasting(ref int pnNumViewers) +{ + CheckIfUsable(); + pnNumViewers = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamTV_IsBroadcasting(m_pSteamTV,ref pnNumViewers); + return result; +} +public override void AddBroadcastGameData(string pchKey,string pchValue) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamTV_AddBroadcastGameData(m_pSteamTV,pchKey,pchValue); +} +public override void RemoveBroadcastGameData(string pchKey) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamTV_RemoveBroadcastGameData(m_pSteamTV,pchKey); +} +public override void AddTimelineMarker(string pchTemplateName,bool bPersistent,byte nColorR,byte nColorG,byte nColorB) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamTV_AddTimelineMarker(m_pSteamTV,pchTemplateName,bPersistent,nColorR,nColorG,nColorB); +} +public override void RemoveTimelineMarker() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamTV_RemoveTimelineMarker(m_pSteamTV); +} +public override uint AddRegion(string pchElementName,string pchTimelineDataSection,ref SteamTVRegion_t pSteamTVRegion,uint eSteamTVRegionBehavior) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamTV_AddRegion(m_pSteamTV,pchElementName,pchTimelineDataSection,ref pSteamTVRegion,eSteamTVRegionBehavior); + return result; +} +public override void RemoveRegion(uint unRegionHandle) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamTV_RemoveRegion(m_pSteamTV,unRegionHandle); +} +} + + +public class CSteamParentalSettings : ISteamParentalSettings +{ +public CSteamParentalSettings(IntPtr SteamParentalSettings) +{ + m_pSteamParentalSettings = SteamParentalSettings; +} +IntPtr m_pSteamParentalSettings; + +public override IntPtr GetIntPtr() { return m_pSteamParentalSettings; } + +private void CheckIfUsable() +{ + if (m_pSteamParentalSettings == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool BIsParentalLockEnabled() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled(m_pSteamParentalSettings); + return result; +} +public override bool BIsParentalLockLocked() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParentalSettings_BIsParentalLockLocked(m_pSteamParentalSettings); + return result; +} +public override bool BIsAppBlocked(uint nAppID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParentalSettings_BIsAppBlocked(m_pSteamParentalSettings,nAppID); + return result; +} +public override bool BIsAppInBlockList(uint nAppID) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParentalSettings_BIsAppInBlockList(m_pSteamParentalSettings,nAppID); + return result; +} +public override bool BIsFeatureBlocked(uint eFeature) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParentalSettings_BIsFeatureBlocked(m_pSteamParentalSettings,eFeature); + return result; +} +public override bool BIsFeatureInBlockList(uint eFeature) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList(m_pSteamParentalSettings,eFeature); + return result; +} +} + + +public class CSteamRemotePlay : ISteamRemotePlay +{ +public CSteamRemotePlay(IntPtr SteamRemotePlay) +{ + m_pSteamRemotePlay = SteamRemotePlay; +} +IntPtr m_pSteamRemotePlay; + +public override IntPtr GetIntPtr() { return m_pSteamRemotePlay; } + +private void CheckIfUsable() +{ + if (m_pSteamRemotePlay == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override uint GetSessionCount() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamRemotePlay_GetSessionCount(m_pSteamRemotePlay); + return result; +} +public override uint GetSessionID(int iSessionIndex) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamRemotePlay_GetSessionID(m_pSteamRemotePlay,iSessionIndex); + return result; +} +public override ulong GetSessionSteamID(uint unSessionID) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamRemotePlay_GetSessionSteamID(m_pSteamRemotePlay,unSessionID); + return result; +} +public override string GetSessionClientName(uint unSessionID) +{ + CheckIfUsable(); + IntPtr result = NativeEntrypoints.SteamAPI_ISteamRemotePlay_GetSessionClientName(m_pSteamRemotePlay,unSessionID); + return Marshal.PtrToStringAnsi(result); +} +public override uint GetSessionClientFormFactor(uint unSessionID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor(m_pSteamRemotePlay,unSessionID); + return result; +} +public override bool BGetSessionClientResolution(uint unSessionID,ref int pnResolutionX,ref int pnResolutionY) +{ + CheckIfUsable(); + pnResolutionX = 0; + pnResolutionY = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamRemotePlay_BGetSessionClientResolution(m_pSteamRemotePlay,unSessionID,ref pnResolutionX,ref pnResolutionY); + return result; +} +} + + +public class CSteamGameServer : ISteamGameServer +{ +public CSteamGameServer(IntPtr SteamGameServer) +{ + m_pSteamGameServer = SteamGameServer; +} +IntPtr m_pSteamGameServer; + +public override IntPtr GetIntPtr() { return m_pSteamGameServer; } + +private void CheckIfUsable() +{ + if (m_pSteamGameServer == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override bool InitGameServer(uint unIP,char usGamePort,char usQueryPort,uint unFlags,uint nGameAppId,string pchVersionString) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_InitGameServer(m_pSteamGameServer,unIP,usGamePort,usQueryPort,unFlags,nGameAppId,pchVersionString); + return result; +} +public override void SetProduct(string pszProduct) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetProduct(m_pSteamGameServer,pszProduct); +} +public override void SetGameDescription(string pszGameDescription) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetGameDescription(m_pSteamGameServer,pszGameDescription); +} +public override void SetModDir(string pszModDir) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetModDir(m_pSteamGameServer,pszModDir); +} +public override void SetDedicatedServer(bool bDedicated) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetDedicatedServer(m_pSteamGameServer,bDedicated); +} +public override void LogOn(string pszToken) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_LogOn(m_pSteamGameServer,pszToken); +} +public override void LogOnAnonymous() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_LogOnAnonymous(m_pSteamGameServer); +} +public override void LogOff() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_LogOff(m_pSteamGameServer); +} +public override bool BLoggedOn() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_BLoggedOn(m_pSteamGameServer); + return result; +} +public override bool BSecure() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_BSecure(m_pSteamGameServer); + return result; +} +public override ulong GetSteamID() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServer_GetSteamID(m_pSteamGameServer); + return result; +} +public override bool WasRestartRequested() +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_WasRestartRequested(m_pSteamGameServer); + return result; +} +public override void SetMaxPlayerCount(int cPlayersMax) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetMaxPlayerCount(m_pSteamGameServer,cPlayersMax); +} +public override void SetBotPlayerCount(int cBotplayers) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetBotPlayerCount(m_pSteamGameServer,cBotplayers); +} +public override void SetServerName(string pszServerName) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetServerName(m_pSteamGameServer,pszServerName); +} +public override void SetMapName(string pszMapName) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetMapName(m_pSteamGameServer,pszMapName); +} +public override void SetPasswordProtected(bool bPasswordProtected) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetPasswordProtected(m_pSteamGameServer,bPasswordProtected); +} +public override void SetSpectatorPort(char unSpectatorPort) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetSpectatorPort(m_pSteamGameServer,unSpectatorPort); +} +public override void SetSpectatorServerName(string pszSpectatorServerName) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetSpectatorServerName(m_pSteamGameServer,pszSpectatorServerName); +} +public override void ClearAllKeyValues() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_ClearAllKeyValues(m_pSteamGameServer); +} +public override void SetKeyValue(string pKey,string pValue) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetKeyValue(m_pSteamGameServer,pKey,pValue); +} +public override void SetGameTags(string pchGameTags) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetGameTags(m_pSteamGameServer,pchGameTags); +} +public override void SetGameData(string pchGameData) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetGameData(m_pSteamGameServer,pchGameData); +} +public override void SetRegion(string pszRegion) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetRegion(m_pSteamGameServer,pszRegion); +} +public override bool SendUserConnectAndAuthenticate(uint unIPClient,IntPtr pvAuthBlob,uint cubAuthBlobSize,ref CSteamID pSteamIDUser) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate(m_pSteamGameServer,unIPClient,pvAuthBlob,cubAuthBlobSize,ref pSteamIDUser); + return result; +} +public override ulong CreateUnauthenticatedUserConnection() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection(m_pSteamGameServer); + return result; +} +public override void SendUserDisconnect(ulong steamIDUser) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SendUserDisconnect(m_pSteamGameServer,steamIDUser); +} +public override bool BUpdateUserData(ulong steamIDUser,string pchPlayerName,uint uScore) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_BUpdateUserData(m_pSteamGameServer,steamIDUser,pchPlayerName,uScore); + return result; +} +public override uint GetAuthSessionTicket(IntPtr pTicket,int cbMaxTicket,ref uint pcbTicket) +{ + CheckIfUsable(); + pcbTicket = 0; + uint result = NativeEntrypoints.SteamAPI_ISteamGameServer_GetAuthSessionTicket(m_pSteamGameServer,pTicket,cbMaxTicket,ref pcbTicket); + return result; +} +public override uint BeginAuthSession(IntPtr pAuthTicket,int cbAuthTicket,ulong steamID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameServer_BeginAuthSession(m_pSteamGameServer,pAuthTicket,cbAuthTicket,steamID); + return result; +} +public override void EndAuthSession(ulong steamID) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_EndAuthSession(m_pSteamGameServer,steamID); +} +public override void CancelAuthTicket(uint hAuthTicket) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_CancelAuthTicket(m_pSteamGameServer,hAuthTicket); +} +public override uint UserHasLicenseForApp(ulong steamID,uint appID) +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameServer_UserHasLicenseForApp(m_pSteamGameServer,steamID,appID); + return result; +} +public override bool RequestUserGroupStatus(ulong steamIDUser,ulong steamIDGroup) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_RequestUserGroupStatus(m_pSteamGameServer,steamIDUser,steamIDGroup); + return result; +} +public override void GetGameplayStats() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_GetGameplayStats(m_pSteamGameServer); +} +public override ulong GetServerReputation() +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServer_GetServerReputation(m_pSteamGameServer); + return result; +} +public override uint GetPublicIP() +{ + CheckIfUsable(); + uint result = NativeEntrypoints.SteamAPI_ISteamGameServer_GetPublicIP(m_pSteamGameServer); + return result; +} +public override bool HandleIncomingPacket(IntPtr pData,int cbData,uint srcIP,char srcPort) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServer_HandleIncomingPacket(m_pSteamGameServer,pData,cbData,srcIP,srcPort); + return result; +} +public override int GetNextOutgoingPacket(IntPtr pOut,int cbMaxOut,ref uint pNetAdr,ref char pPort) +{ + CheckIfUsable(); + pNetAdr = 0; + pPort = (char) 0; + int result = NativeEntrypoints.SteamAPI_ISteamGameServer_GetNextOutgoingPacket(m_pSteamGameServer,pOut,cbMaxOut,ref pNetAdr,ref pPort); + return result; +} +public override void EnableHeartbeats(bool bActive) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_EnableHeartbeats(m_pSteamGameServer,bActive); +} +public override void SetHeartbeatInterval(int iHeartbeatInterval) +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_SetHeartbeatInterval(m_pSteamGameServer,iHeartbeatInterval); +} +public override void ForceHeartbeat() +{ + CheckIfUsable(); + NativeEntrypoints.SteamAPI_ISteamGameServer_ForceHeartbeat(m_pSteamGameServer); +} +public override ulong AssociateWithClan(ulong steamIDClan) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServer_AssociateWithClan(m_pSteamGameServer,steamIDClan); + return result; +} +public override ulong ComputeNewPlayerCompatibility(ulong steamIDNewPlayer) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility(m_pSteamGameServer,steamIDNewPlayer); + return result; +} +} + + +public class CSteamGameServerStats : ISteamGameServerStats +{ +public CSteamGameServerStats(IntPtr SteamGameServerStats) +{ + m_pSteamGameServerStats = SteamGameServerStats; +} +IntPtr m_pSteamGameServerStats; + +public override IntPtr GetIntPtr() { return m_pSteamGameServerStats; } + +private void CheckIfUsable() +{ + if (m_pSteamGameServerStats == IntPtr.Zero) + { + throw new Exception("Steam Pointer not configured"); + } +} +public override ulong RequestUserStats(ulong steamIDUser) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_RequestUserStats(m_pSteamGameServerStats,steamIDUser); + return result; +} +public override bool GetUserStat(ulong steamIDUser,string pchName,ref int pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_GetUserStat(m_pSteamGameServerStats,steamIDUser,pchName,ref pData); + return result; +} +public override bool GetUserStat0(ulong steamIDUser,string pchName,ref float pData) +{ + CheckIfUsable(); + pData = 0; + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_GetUserStat0(m_pSteamGameServerStats,steamIDUser,pchName,ref pData); + return result; +} +public override bool GetUserAchievement(ulong steamIDUser,string pchName,ref bool pbAchieved) +{ + CheckIfUsable(); + pbAchieved = false; + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_GetUserAchievement(m_pSteamGameServerStats,steamIDUser,pchName,ref pbAchieved); + return result; +} +public override bool SetUserStat(ulong steamIDUser,string pchName,int nData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_SetUserStat(m_pSteamGameServerStats,steamIDUser,pchName,nData); + return result; +} +public override bool SetUserStat0(ulong steamIDUser,string pchName,float fData) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_SetUserStat0(m_pSteamGameServerStats,steamIDUser,pchName,fData); + return result; +} +public override bool UpdateUserAvgRateStat(ulong steamIDUser,string pchName,float flCountThisSession,double dSessionLength) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat(m_pSteamGameServerStats,steamIDUser,pchName,flCountThisSession,dSessionLength); + return result; +} +public override bool SetUserAchievement(ulong steamIDUser,string pchName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_SetUserAchievement(m_pSteamGameServerStats,steamIDUser,pchName); + return result; +} +public override bool ClearUserAchievement(ulong steamIDUser,string pchName) +{ + CheckIfUsable(); + bool result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_ClearUserAchievement(m_pSteamGameServerStats,steamIDUser,pchName); + return result; +} +public override ulong StoreUserStats(ulong steamIDUser) +{ + CheckIfUsable(); + ulong result = NativeEntrypoints.SteamAPI_ISteamGameServerStats_StoreUserStats(m_pSteamGameServerStats,steamIDUser); + return result; +} +} + + +public class CUserStatsReceived_t_Callback +{ + public CUserStatsReceived_t_Callback() { } + ~CUserStatsReceived_t_Callback() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CUserStatsReceived_t_RemoveCallback(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(Valve.Interop.NativeEntrypoints.SteamAPI_UserStatsReceived_t_Callback func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CUserStatsReceived_t_RemoveCallback(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CUserStatsReceived_t_SetCallback(func); + } +} +public class CGetOPFSettingsResult_t_Callback +{ + public CGetOPFSettingsResult_t_Callback() { } + ~CGetOPFSettingsResult_t_Callback() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGetOPFSettingsResult_t_RemoveCallback(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(Valve.Interop.NativeEntrypoints.SteamAPI_GetOPFSettingsResult_t_Callback func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGetOPFSettingsResult_t_RemoveCallback(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGetOPFSettingsResult_t_SetCallback(func); + } +} +public class CSteamInventoryStartPurchaseResult_t_CallResult +{ + public CSteamInventoryStartPurchaseResult_t_CallResult() { } + ~CSteamInventoryStartPurchaseResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamInventoryStartPurchaseResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SteamInventoryStartPurchaseResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamInventoryStartPurchaseResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSteamInventoryStartPurchaseResult_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageFileReadAsyncComplete_t_CallResult +{ + public CRemoteStorageFileReadAsyncComplete_t_CallResult() { } + ~CRemoteStorageFileReadAsyncComplete_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageFileReadAsyncComplete_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageFileReadAsyncComplete_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageFileReadAsyncComplete_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageFileReadAsyncComplete_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageGetPublishedItemVoteDetailsResult_t_CallResult +{ + public CRemoteStorageGetPublishedItemVoteDetailsResult_t_CallResult() { } + ~CRemoteStorageGetPublishedItemVoteDetailsResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageGetPublishedItemVoteDetailsResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageGetPublishedItemVoteDetailsResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageGetPublishedItemVoteDetailsResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageGetPublishedItemVoteDetailsResult_t_SetCallResult(hAPICall, func); + } +} +public class CFileDetailsResult_t_CallResult +{ + public CFileDetailsResult_t_CallResult() { } + ~CFileDetailsResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFileDetailsResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_FileDetailsResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFileDetailsResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CFileDetailsResult_t_SetCallResult(hAPICall, func); + } +} +public class CGSStatsStored_t_CallResult +{ + public CGSStatsStored_t_CallResult() { } + ~CGSStatsStored_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGSStatsStored_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GSStatsStored_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGSStatsStored_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGSStatsStored_t_SetCallResult(hAPICall, func); + } +} +public class CStartPlaytimeTrackingResult_t_CallResult +{ + public CStartPlaytimeTrackingResult_t_CallResult() { } + ~CStartPlaytimeTrackingResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CStartPlaytimeTrackingResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_StartPlaytimeTrackingResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CStartPlaytimeTrackingResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CStartPlaytimeTrackingResult_t_SetCallResult(hAPICall, func); + } +} +public class CFriendsGetFollowerCount_t_CallResult +{ + public CFriendsGetFollowerCount_t_CallResult() { } + ~CFriendsGetFollowerCount_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFriendsGetFollowerCount_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_FriendsGetFollowerCount_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFriendsGetFollowerCount_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CFriendsGetFollowerCount_t_SetCallResult(hAPICall, func); + } +} +public class CFriendsIsFollowing_t_CallResult +{ + public CFriendsIsFollowing_t_CallResult() { } + ~CFriendsIsFollowing_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFriendsIsFollowing_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_FriendsIsFollowing_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFriendsIsFollowing_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CFriendsIsFollowing_t_SetCallResult(hAPICall, func); + } +} +public class CLobbyMatchList_t_CallResult +{ + public CLobbyMatchList_t_CallResult() { } + ~CLobbyMatchList_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLobbyMatchList_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LobbyMatchList_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLobbyMatchList_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLobbyMatchList_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageUpdatePublishedFileResult_t_CallResult +{ + public CRemoteStorageUpdatePublishedFileResult_t_CallResult() { } + ~CRemoteStorageUpdatePublishedFileResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageUpdatePublishedFileResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageUpdatePublishedFileResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageUpdatePublishedFileResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageUpdatePublishedFileResult_t_SetCallResult(hAPICall, func); + } +} +public class CStoreAuthURLResponse_t_CallResult +{ + public CStoreAuthURLResponse_t_CallResult() { } + ~CStoreAuthURLResponse_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CStoreAuthURLResponse_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_StoreAuthURLResponse_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CStoreAuthURLResponse_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CStoreAuthURLResponse_t_SetCallResult(hAPICall, func); + } +} +public class CLobbyCreated_t_CallResult +{ + public CLobbyCreated_t_CallResult() { } + ~CLobbyCreated_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLobbyCreated_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LobbyCreated_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLobbyCreated_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLobbyCreated_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageFileWriteAsyncComplete_t_CallResult +{ + public CRemoteStorageFileWriteAsyncComplete_t_CallResult() { } + ~CRemoteStorageFileWriteAsyncComplete_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageFileWriteAsyncComplete_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageFileWriteAsyncComplete_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageFileWriteAsyncComplete_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageFileWriteAsyncComplete_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageDeletePublishedFileResult_t_CallResult +{ + public CRemoteStorageDeletePublishedFileResult_t_CallResult() { } + ~CRemoteStorageDeletePublishedFileResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageDeletePublishedFileResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageDeletePublishedFileResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageDeletePublishedFileResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageDeletePublishedFileResult_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageGetPublishedFileDetailsResult_t_CallResult +{ + public CRemoteStorageGetPublishedFileDetailsResult_t_CallResult() { } + ~CRemoteStorageGetPublishedFileDetailsResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageGetPublishedFileDetailsResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageGetPublishedFileDetailsResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageGetPublishedFileDetailsResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageGetPublishedFileDetailsResult_t_SetCallResult(hAPICall, func); + } +} +public class CAddUGCDependencyResult_t_CallResult +{ + public CAddUGCDependencyResult_t_CallResult() { } + ~CAddUGCDependencyResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CAddUGCDependencyResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_AddUGCDependencyResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CAddUGCDependencyResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CAddUGCDependencyResult_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageDownloadUGCResult_t_CallResult +{ + public CRemoteStorageDownloadUGCResult_t_CallResult() { } + ~CRemoteStorageDownloadUGCResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageDownloadUGCResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageDownloadUGCResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageDownloadUGCResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageDownloadUGCResult_t_SetCallResult(hAPICall, func); + } +} +public class CSteamUGCQueryCompleted_t_CallResult +{ + public CSteamUGCQueryCompleted_t_CallResult() { } + ~CSteamUGCQueryCompleted_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamUGCQueryCompleted_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SteamUGCQueryCompleted_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamUGCQueryCompleted_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSteamUGCQueryCompleted_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageFileShareResult_t_CallResult +{ + public CRemoteStorageFileShareResult_t_CallResult() { } + ~CRemoteStorageFileShareResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageFileShareResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageFileShareResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageFileShareResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageFileShareResult_t_SetCallResult(hAPICall, func); + } +} +public class CLobbyEnter_t_CallResult +{ + public CLobbyEnter_t_CallResult() { } + ~CLobbyEnter_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLobbyEnter_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LobbyEnter_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLobbyEnter_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLobbyEnter_t_SetCallResult(hAPICall, func); + } +} +public class CSubmitItemUpdateResult_t_CallResult +{ + public CSubmitItemUpdateResult_t_CallResult() { } + ~CSubmitItemUpdateResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSubmitItemUpdateResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SubmitItemUpdateResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSubmitItemUpdateResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSubmitItemUpdateResult_t_SetCallResult(hAPICall, func); + } +} +public class CNumberOfCurrentPlayers_t_CallResult +{ + public CNumberOfCurrentPlayers_t_CallResult() { } + ~CNumberOfCurrentPlayers_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CNumberOfCurrentPlayers_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_NumberOfCurrentPlayers_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CNumberOfCurrentPlayers_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CNumberOfCurrentPlayers_t_SetCallResult(hAPICall, func); + } +} +public class CGSStatsReceived_t_CallResult +{ + public CGSStatsReceived_t_CallResult() { } + ~CGSStatsReceived_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGSStatsReceived_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GSStatsReceived_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGSStatsReceived_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGSStatsReceived_t_SetCallResult(hAPICall, func); + } +} +public class CHTML_BrowserReady_t_CallResult +{ + public CHTML_BrowserReady_t_CallResult() { } + ~CHTML_BrowserReady_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CHTML_BrowserReady_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_HTML_BrowserReady_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CHTML_BrowserReady_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CHTML_BrowserReady_t_SetCallResult(hAPICall, func); + } +} +public class CMarketEligibilityResponse_t_CallResult +{ + public CMarketEligibilityResponse_t_CallResult() { } + ~CMarketEligibilityResponse_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CMarketEligibilityResponse_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_MarketEligibilityResponse_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CMarketEligibilityResponse_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CMarketEligibilityResponse_t_SetCallResult(hAPICall, func); + } +} +public class CLeaderboardScoresDownloaded_t_CallResult +{ + public CLeaderboardScoresDownloaded_t_CallResult() { } + ~CLeaderboardScoresDownloaded_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardScoresDownloaded_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LeaderboardScoresDownloaded_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardScoresDownloaded_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLeaderboardScoresDownloaded_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageUpdateUserPublishedItemVoteResult_t_CallResult +{ + public CRemoteStorageUpdateUserPublishedItemVoteResult_t_CallResult() { } + ~CRemoteStorageUpdateUserPublishedItemVoteResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageUpdateUserPublishedItemVoteResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageUpdateUserPublishedItemVoteResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageUpdateUserPublishedItemVoteResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageUpdateUserPublishedItemVoteResult_t_SetCallResult(hAPICall, func); + } +} +public class CCreateBeaconCallback_t_CallResult +{ + public CCreateBeaconCallback_t_CallResult() { } + ~CCreateBeaconCallback_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CCreateBeaconCallback_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_CreateBeaconCallback_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CCreateBeaconCallback_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CCreateBeaconCallback_t_SetCallResult(hAPICall, func); + } +} +public class CCreateItemResult_t_CallResult +{ + public CCreateItemResult_t_CallResult() { } + ~CCreateItemResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CCreateItemResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_CreateItemResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CCreateItemResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CCreateItemResult_t_SetCallResult(hAPICall, func); + } +} +public class CDeleteItemResult_t_CallResult +{ + public CDeleteItemResult_t_CallResult() { } + ~CDeleteItemResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CDeleteItemResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_DeleteItemResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CDeleteItemResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CDeleteItemResult_t_SetCallResult(hAPICall, func); + } +} +public class CSetUserItemVoteResult_t_CallResult +{ + public CSetUserItemVoteResult_t_CallResult() { } + ~CSetUserItemVoteResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSetUserItemVoteResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SetUserItemVoteResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSetUserItemVoteResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSetUserItemVoteResult_t_SetCallResult(hAPICall, func); + } +} +public class CSteamInventoryRequestPricesResult_t_CallResult +{ + public CSteamInventoryRequestPricesResult_t_CallResult() { } + ~CSteamInventoryRequestPricesResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamInventoryRequestPricesResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SteamInventoryRequestPricesResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamInventoryRequestPricesResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSteamInventoryRequestPricesResult_t_SetCallResult(hAPICall, func); + } +} +public class CComputeNewPlayerCompatibilityResult_t_CallResult +{ + public CComputeNewPlayerCompatibilityResult_t_CallResult() { } + ~CComputeNewPlayerCompatibilityResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CComputeNewPlayerCompatibilityResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_ComputeNewPlayerCompatibilityResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CComputeNewPlayerCompatibilityResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CComputeNewPlayerCompatibilityResult_t_SetCallResult(hAPICall, func); + } +} +public class CLeaderboardScoreUploaded_t_CallResult +{ + public CLeaderboardScoreUploaded_t_CallResult() { } + ~CLeaderboardScoreUploaded_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardScoreUploaded_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LeaderboardScoreUploaded_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardScoreUploaded_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLeaderboardScoreUploaded_t_SetCallResult(hAPICall, func); + } +} +public class CJoinPartyCallback_t_CallResult +{ + public CJoinPartyCallback_t_CallResult() { } + ~CJoinPartyCallback_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CJoinPartyCallback_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_JoinPartyCallback_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CJoinPartyCallback_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CJoinPartyCallback_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageEnumerateUserSubscribedFilesResult_t_CallResult +{ + public CRemoteStorageEnumerateUserSubscribedFilesResult_t_CallResult() { } + ~CRemoteStorageEnumerateUserSubscribedFilesResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateUserSubscribedFilesResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageEnumerateUserSubscribedFilesResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateUserSubscribedFilesResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateUserSubscribedFilesResult_t_SetCallResult(hAPICall, func); + } +} +public class CGlobalStatsReceived_t_CallResult +{ + public CGlobalStatsReceived_t_CallResult() { } + ~CGlobalStatsReceived_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGlobalStatsReceived_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GlobalStatsReceived_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGlobalStatsReceived_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGlobalStatsReceived_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_CallResult +{ + public CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_CallResult() { } + ~CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageEnumeratePublishedFilesByUserActionResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageEnumeratePublishedFilesByUserActionResult_t_SetCallResult(hAPICall, func); + } +} +public class CClanOfficerListResponse_t_CallResult +{ + public CClanOfficerListResponse_t_CallResult() { } + ~CClanOfficerListResponse_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CClanOfficerListResponse_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_ClanOfficerListResponse_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CClanOfficerListResponse_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CClanOfficerListResponse_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStoragePublishFileProgress_t_CallResult +{ + public CRemoteStoragePublishFileProgress_t_CallResult() { } + ~CRemoteStoragePublishFileProgress_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStoragePublishFileProgress_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStoragePublishFileProgress_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStoragePublishFileProgress_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStoragePublishFileProgress_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageEnumerateWorkshopFilesResult_t_CallResult +{ + public CRemoteStorageEnumerateWorkshopFilesResult_t_CallResult() { } + ~CRemoteStorageEnumerateWorkshopFilesResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateWorkshopFilesResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageEnumerateWorkshopFilesResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateWorkshopFilesResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateWorkshopFilesResult_t_SetCallResult(hAPICall, func); + } +} +public class CDurationControl_t_CallResult +{ + public CDurationControl_t_CallResult() { } + ~CDurationControl_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CDurationControl_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_DurationControl_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CDurationControl_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CDurationControl_t_SetCallResult(hAPICall, func); + } +} +public class CGSReputation_t_CallResult +{ + public CGSReputation_t_CallResult() { } + ~CGSReputation_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGSReputation_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GSReputation_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGSReputation_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGSReputation_t_SetCallResult(hAPICall, func); + } +} +public class CGlobalAchievementPercentagesReady_t_CallResult +{ + public CGlobalAchievementPercentagesReady_t_CallResult() { } + ~CGlobalAchievementPercentagesReady_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGlobalAchievementPercentagesReady_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GlobalAchievementPercentagesReady_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGlobalAchievementPercentagesReady_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGlobalAchievementPercentagesReady_t_SetCallResult(hAPICall, func); + } +} +public class CUserFavoriteItemsListChanged_t_CallResult +{ + public CUserFavoriteItemsListChanged_t_CallResult() { } + ~CUserFavoriteItemsListChanged_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CUserFavoriteItemsListChanged_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_UserFavoriteItemsListChanged_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CUserFavoriteItemsListChanged_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CUserFavoriteItemsListChanged_t_SetCallResult(hAPICall, func); + } +} +public class CAddAppDependencyResult_t_CallResult +{ + public CAddAppDependencyResult_t_CallResult() { } + ~CAddAppDependencyResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CAddAppDependencyResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_AddAppDependencyResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CAddAppDependencyResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CAddAppDependencyResult_t_SetCallResult(hAPICall, func); + } +} +public class CEncryptedAppTicketResponse_t_CallResult +{ + public CEncryptedAppTicketResponse_t_CallResult() { } + ~CEncryptedAppTicketResponse_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CEncryptedAppTicketResponse_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_EncryptedAppTicketResponse_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CEncryptedAppTicketResponse_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CEncryptedAppTicketResponse_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageSetUserPublishedFileActionResult_t_CallResult +{ + public CRemoteStorageSetUserPublishedFileActionResult_t_CallResult() { } + ~CRemoteStorageSetUserPublishedFileActionResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageSetUserPublishedFileActionResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageSetUserPublishedFileActionResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageSetUserPublishedFileActionResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageSetUserPublishedFileActionResult_t_SetCallResult(hAPICall, func); + } +} +public class CStopPlaytimeTrackingResult_t_CallResult +{ + public CStopPlaytimeTrackingResult_t_CallResult() { } + ~CStopPlaytimeTrackingResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CStopPlaytimeTrackingResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_StopPlaytimeTrackingResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CStopPlaytimeTrackingResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CStopPlaytimeTrackingResult_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageEnumerateUserPublishedFilesResult_t_CallResult +{ + public CRemoteStorageEnumerateUserPublishedFilesResult_t_CallResult() { } + ~CRemoteStorageEnumerateUserPublishedFilesResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateUserPublishedFilesResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageEnumerateUserPublishedFilesResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateUserPublishedFilesResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageEnumerateUserPublishedFilesResult_t_SetCallResult(hAPICall, func); + } +} +public class CFriendsEnumerateFollowingList_t_CallResult +{ + public CFriendsEnumerateFollowingList_t_CallResult() { } + ~CFriendsEnumerateFollowingList_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFriendsEnumerateFollowingList_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_FriendsEnumerateFollowingList_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CFriendsEnumerateFollowingList_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CFriendsEnumerateFollowingList_t_SetCallResult(hAPICall, func); + } +} +public class CChangeNumOpenSlotsCallback_t_CallResult +{ + public CChangeNumOpenSlotsCallback_t_CallResult() { } + ~CChangeNumOpenSlotsCallback_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CChangeNumOpenSlotsCallback_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_ChangeNumOpenSlotsCallback_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CChangeNumOpenSlotsCallback_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CChangeNumOpenSlotsCallback_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageSubscribePublishedFileResult_t_CallResult +{ + public CRemoteStorageSubscribePublishedFileResult_t_CallResult() { } + ~CRemoteStorageSubscribePublishedFileResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageSubscribePublishedFileResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageSubscribePublishedFileResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageSubscribePublishedFileResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageSubscribePublishedFileResult_t_SetCallResult(hAPICall, func); + } +} +public class CGetUserItemVoteResult_t_CallResult +{ + public CGetUserItemVoteResult_t_CallResult() { } + ~CGetUserItemVoteResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGetUserItemVoteResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GetUserItemVoteResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGetUserItemVoteResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGetUserItemVoteResult_t_SetCallResult(hAPICall, func); + } +} +public class CAssociateWithClanResult_t_CallResult +{ + public CAssociateWithClanResult_t_CallResult() { } + ~CAssociateWithClanResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CAssociateWithClanResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_AssociateWithClanResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CAssociateWithClanResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CAssociateWithClanResult_t_SetCallResult(hAPICall, func); + } +} +public class CLeaderboardUGCSet_t_CallResult +{ + public CLeaderboardUGCSet_t_CallResult() { } + ~CLeaderboardUGCSet_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardUGCSet_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LeaderboardUGCSet_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardUGCSet_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLeaderboardUGCSet_t_SetCallResult(hAPICall, func); + } +} +public class CCheckFileSignature_t_CallResult +{ + public CCheckFileSignature_t_CallResult() { } + ~CCheckFileSignature_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CCheckFileSignature_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_CheckFileSignature_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CCheckFileSignature_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CCheckFileSignature_t_SetCallResult(hAPICall, func); + } +} +public class CGetAppDependenciesResult_t_CallResult +{ + public CGetAppDependenciesResult_t_CallResult() { } + ~CGetAppDependenciesResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGetAppDependenciesResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_GetAppDependenciesResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CGetAppDependenciesResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CGetAppDependenciesResult_t_SetCallResult(hAPICall, func); + } +} +public class CRemoteStorageUnsubscribePublishedFileResult_t_CallResult +{ + public CRemoteStorageUnsubscribePublishedFileResult_t_CallResult() { } + ~CRemoteStorageUnsubscribePublishedFileResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageUnsubscribePublishedFileResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoteStorageUnsubscribePublishedFileResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoteStorageUnsubscribePublishedFileResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoteStorageUnsubscribePublishedFileResult_t_SetCallResult(hAPICall, func); + } +} +public class CSetPersonaNameResponse_t_CallResult +{ + public CSetPersonaNameResponse_t_CallResult() { } + ~CSetPersonaNameResponse_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSetPersonaNameResponse_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SetPersonaNameResponse_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSetPersonaNameResponse_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSetPersonaNameResponse_t_SetCallResult(hAPICall, func); + } +} +public class CRemoveAppDependencyResult_t_CallResult +{ + public CRemoveAppDependencyResult_t_CallResult() { } + ~CRemoveAppDependencyResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoveAppDependencyResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoveAppDependencyResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoveAppDependencyResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoveAppDependencyResult_t_SetCallResult(hAPICall, func); + } +} +public class CUserStatsReceived_t_CallResult +{ + public CUserStatsReceived_t_CallResult() { } + ~CUserStatsReceived_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CUserStatsReceived_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_UserStatsReceived_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CUserStatsReceived_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CUserStatsReceived_t_SetCallResult(hAPICall, func); + } +} +public class CSteamInventoryEligiblePromoItemDefIDs_t_CallResult +{ + public CSteamInventoryEligiblePromoItemDefIDs_t_CallResult() { } + ~CSteamInventoryEligiblePromoItemDefIDs_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamInventoryEligiblePromoItemDefIDs_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_SteamInventoryEligiblePromoItemDefIDs_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CSteamInventoryEligiblePromoItemDefIDs_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CSteamInventoryEligiblePromoItemDefIDs_t_SetCallResult(hAPICall, func); + } +} +public class CRemoveUGCDependencyResult_t_CallResult +{ + public CRemoveUGCDependencyResult_t_CallResult() { } + ~CRemoveUGCDependencyResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoveUGCDependencyResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_RemoveUGCDependencyResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CRemoveUGCDependencyResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CRemoveUGCDependencyResult_t_SetCallResult(hAPICall, func); + } +} +public class CJoinClanChatRoomCompletionResult_t_CallResult +{ + public CJoinClanChatRoomCompletionResult_t_CallResult() { } + ~CJoinClanChatRoomCompletionResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CJoinClanChatRoomCompletionResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_JoinClanChatRoomCompletionResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CJoinClanChatRoomCompletionResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CJoinClanChatRoomCompletionResult_t_SetCallResult(hAPICall, func); + } +} +public class CLeaderboardFindResult_t_CallResult +{ + public CLeaderboardFindResult_t_CallResult() { } + ~CLeaderboardFindResult_t_CallResult() + { + if(m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardFindResult_t_RemoveCallResult(m_Handle); + } + } + ulong m_Handle = 0; + public void Set(ulong hAPICall, Valve.Interop.NativeEntrypoints.SteamAPI_LeaderboardFindResult_t_CallResult func) + { + if (m_Handle != 0) + { + Valve.Interop.NativeEntrypoints.CLeaderboardFindResult_t_RemoveCallResult(m_Handle); + } + m_Handle = Valve.Interop.NativeEntrypoints.CLeaderboardFindResult_t_SetCallResult(hAPICall, func); + } +} +public class SteamAPIInterop +{ +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_RestartAppIfNecessary")] +internal static extern void SteamAPI_RestartAppIfNecessary(uint unOwnAppID ); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_Init")] +internal static extern void SteamAPI_Init(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_RunCallbacks")] +internal static extern void SteamAPI_RunCallbacks(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_RegisterCallback")] +internal static extern void SteamAPI_RegisterCallback(IntPtr pCallback, int iCallback); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAPI_UnregisterCallback")] +internal static extern void SteamAPI_UnregisterCallback(IntPtr pCallback); +[DllImportAttribute("Steam_api", EntryPoint = "SteamClient")] +internal static extern IntPtr SteamClient(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamUser")] +internal static extern IntPtr SteamUser(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamFriends")] +internal static extern IntPtr SteamFriends(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamUtils")] +internal static extern IntPtr SteamUtils(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMatchmaking")] +internal static extern IntPtr SteamMatchmaking(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMatchmakingServerListResponse")] +internal static extern IntPtr SteamMatchmakingServerListResponse(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMatchmakingPingResponse")] +internal static extern IntPtr SteamMatchmakingPingResponse(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMatchmakingPlayersResponse")] +internal static extern IntPtr SteamMatchmakingPlayersResponse(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMatchmakingRulesResponse")] +internal static extern IntPtr SteamMatchmakingRulesResponse(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMatchmakingServers")] +internal static extern IntPtr SteamMatchmakingServers(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamGameSearch")] +internal static extern IntPtr SteamGameSearch(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamParties")] +internal static extern IntPtr SteamParties(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamRemoteStorage")] +internal static extern IntPtr SteamRemoteStorage(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamUserStats")] +internal static extern IntPtr SteamUserStats(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamApps")] +internal static extern IntPtr SteamApps(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamNetworking")] +internal static extern IntPtr SteamNetworking(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamScreenshots")] +internal static extern IntPtr SteamScreenshots(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMusic")] +internal static extern IntPtr SteamMusic(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamMusicRemote")] +internal static extern IntPtr SteamMusicRemote(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamHTTP")] +internal static extern IntPtr SteamHTTP(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamInput")] +internal static extern IntPtr SteamInput(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamController")] +internal static extern IntPtr SteamController(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamUGC")] +internal static extern IntPtr SteamUGC(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamAppList")] +internal static extern IntPtr SteamAppList(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamHTMLSurface")] +internal static extern IntPtr SteamHTMLSurface(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamInventory")] +internal static extern IntPtr SteamInventory(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamVideo")] +internal static extern IntPtr SteamVideo(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamTV")] +internal static extern IntPtr SteamTV(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamParentalSettings")] +internal static extern IntPtr SteamParentalSettings(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamRemotePlay")] +internal static extern IntPtr SteamRemotePlay(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamGameServer")] +internal static extern IntPtr SteamGameServer(); +[DllImportAttribute("Steam_api", EntryPoint = "SteamGameServerStats")] +internal static extern IntPtr SteamGameServerStats(); +} + + +public enum EUniverse +{ + k_EUniverseInvalid = 0, + k_EUniversePublic = 1, + k_EUniverseBeta = 2, + k_EUniverseInternal = 3, + k_EUniverseDev = 4, + k_EUniverseMax = 5, +} +public enum EResult +{ + k_EResultOK = 1, + k_EResultFail = 2, + k_EResultNoConnection = 3, + k_EResultInvalidPassword = 5, + k_EResultLoggedInElsewhere = 6, + k_EResultInvalidProtocolVer = 7, + k_EResultInvalidParam = 8, + k_EResultFileNotFound = 9, + k_EResultBusy = 10, + k_EResultInvalidState = 11, + k_EResultInvalidName = 12, + k_EResultInvalidEmail = 13, + k_EResultDuplicateName = 14, + k_EResultAccessDenied = 15, + k_EResultTimeout = 16, + k_EResultBanned = 17, + k_EResultAccountNotFound = 18, + k_EResultInvalidSteamID = 19, + k_EResultServiceUnavailable = 20, + k_EResultNotLoggedOn = 21, + k_EResultPending = 22, + k_EResultEncryptionFailure = 23, + k_EResultInsufficientPrivilege = 24, + k_EResultLimitExceeded = 25, + k_EResultRevoked = 26, + k_EResultExpired = 27, + k_EResultAlreadyRedeemed = 28, + k_EResultDuplicateRequest = 29, + k_EResultAlreadyOwned = 30, + k_EResultIPNotFound = 31, + k_EResultPersistFailed = 32, + k_EResultLockingFailed = 33, + k_EResultLogonSessionReplaced = 34, + k_EResultConnectFailed = 35, + k_EResultHandshakeFailed = 36, + k_EResultIOFailure = 37, + k_EResultRemoteDisconnect = 38, + k_EResultShoppingCartNotFound = 39, + k_EResultBlocked = 40, + k_EResultIgnored = 41, + k_EResultNoMatch = 42, + k_EResultAccountDisabled = 43, + k_EResultServiceReadOnly = 44, + k_EResultAccountNotFeatured = 45, + k_EResultAdministratorOK = 46, + k_EResultContentVersion = 47, + k_EResultTryAnotherCM = 48, + k_EResultPasswordRequiredToKickSession = 49, + k_EResultAlreadyLoggedInElsewhere = 50, + k_EResultSuspended = 51, + k_EResultCancelled = 52, + k_EResultDataCorruption = 53, + k_EResultDiskFull = 54, + k_EResultRemoteCallFailed = 55, + k_EResultPasswordUnset = 56, + k_EResultExternalAccountUnlinked = 57, + k_EResultPSNTicketInvalid = 58, + k_EResultExternalAccountAlreadyLinked = 59, + k_EResultRemoteFileConflict = 60, + k_EResultIllegalPassword = 61, + k_EResultSameAsPreviousValue = 62, + k_EResultAccountLogonDenied = 63, + k_EResultCannotUseOldPassword = 64, + k_EResultInvalidLoginAuthCode = 65, + k_EResultAccountLogonDeniedNoMail = 66, + k_EResultHardwareNotCapableOfIPT = 67, + k_EResultIPTInitError = 68, + k_EResultParentalControlRestricted = 69, + k_EResultFacebookQueryError = 70, + k_EResultExpiredLoginAuthCode = 71, + k_EResultIPLoginRestrictionFailed = 72, + k_EResultAccountLockedDown = 73, + k_EResultAccountLogonDeniedVerifiedEmailRequired = 74, + k_EResultNoMatchingURL = 75, + k_EResultBadResponse = 76, + k_EResultRequirePasswordReEntry = 77, + k_EResultValueOutOfRange = 78, + k_EResultUnexpectedError = 79, + k_EResultDisabled = 80, + k_EResultInvalidCEGSubmission = 81, + k_EResultRestrictedDevice = 82, + k_EResultRegionLocked = 83, + k_EResultRateLimitExceeded = 84, + k_EResultAccountLoginDeniedNeedTwoFactor = 85, + k_EResultItemDeleted = 86, + k_EResultAccountLoginDeniedThrottle = 87, + k_EResultTwoFactorCodeMismatch = 88, + k_EResultTwoFactorActivationCodeMismatch = 89, + k_EResultAccountAssociatedToMultiplePartners = 90, + k_EResultNotModified = 91, + k_EResultNoMobileDevice = 92, + k_EResultTimeNotSynced = 93, + k_EResultSmsCodeFailed = 94, + k_EResultAccountLimitExceeded = 95, + k_EResultAccountActivityLimitExceeded = 96, + k_EResultPhoneActivityLimitExceeded = 97, + k_EResultRefundToWallet = 98, + k_EResultEmailSendFailure = 99, + k_EResultNotSettled = 100, + k_EResultNeedCaptcha = 101, + k_EResultGSLTDenied = 102, + k_EResultGSOwnerDenied = 103, + k_EResultInvalidItemType = 104, + k_EResultIPBanned = 105, + k_EResultGSLTExpired = 106, + k_EResultInsufficientFunds = 107, + k_EResultTooManyPending = 108, + k_EResultNoSiteLicensesFound = 109, + k_EResultWGNetworkSendExceeded = 110, + k_EResultAccountNotFriends = 111, + k_EResultLimitedUserAccount = 112, + k_EResultCantRemoveItem = 113, +} +public enum EVoiceResult +{ + k_EVoiceResultOK = 0, + k_EVoiceResultNotInitialized = 1, + k_EVoiceResultNotRecording = 2, + k_EVoiceResultNoData = 3, + k_EVoiceResultBufferTooSmall = 4, + k_EVoiceResultDataCorrupted = 5, + k_EVoiceResultRestricted = 6, + k_EVoiceResultUnsupportedCodec = 7, + k_EVoiceResultReceiverOutOfDate = 8, + k_EVoiceResultReceiverDidNotAnswer = 9, +} +public enum EDenyReason +{ + k_EDenyInvalid = 0, + k_EDenyInvalidVersion = 1, + k_EDenyGeneric = 2, + k_EDenyNotLoggedOn = 3, + k_EDenyNoLicense = 4, + k_EDenyCheater = 5, + k_EDenyLoggedInElseWhere = 6, + k_EDenyUnknownText = 7, + k_EDenyIncompatibleAnticheat = 8, + k_EDenyMemoryCorruption = 9, + k_EDenyIncompatibleSoftware = 10, + k_EDenySteamConnectionLost = 11, + k_EDenySteamConnectionError = 12, + k_EDenySteamResponseTimedOut = 13, + k_EDenySteamValidationStalled = 14, + k_EDenySteamOwnerLeftGuestUser = 15, +} +public enum EBeginAuthSessionResult +{ + k_EBeginAuthSessionResultOK = 0, + k_EBeginAuthSessionResultInvalidTicket = 1, + k_EBeginAuthSessionResultDuplicateRequest = 2, + k_EBeginAuthSessionResultInvalidVersion = 3, + k_EBeginAuthSessionResultGameMismatch = 4, + k_EBeginAuthSessionResultExpiredTicket = 5, +} +public enum EAuthSessionResponse +{ + k_EAuthSessionResponseOK = 0, + k_EAuthSessionResponseUserNotConnectedToSteam = 1, + k_EAuthSessionResponseNoLicenseOrExpired = 2, + k_EAuthSessionResponseVACBanned = 3, + k_EAuthSessionResponseLoggedInElseWhere = 4, + k_EAuthSessionResponseVACCheckTimedOut = 5, + k_EAuthSessionResponseAuthTicketCanceled = 6, + k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed = 7, + k_EAuthSessionResponseAuthTicketInvalid = 8, + k_EAuthSessionResponsePublisherIssuedBan = 9, +} +public enum EUserHasLicenseForAppResult +{ + k_EUserHasLicenseResultHasLicense = 0, + k_EUserHasLicenseResultDoesNotHaveLicense = 1, + k_EUserHasLicenseResultNoAuth = 2, +} +public enum EAccountType +{ + k_EAccountTypeInvalid = 0, + k_EAccountTypeIndividual = 1, + k_EAccountTypeMultiseat = 2, + k_EAccountTypeGameServer = 3, + k_EAccountTypeAnonGameServer = 4, + k_EAccountTypePending = 5, + k_EAccountTypeContentServer = 6, + k_EAccountTypeClan = 7, + k_EAccountTypeChat = 8, + k_EAccountTypeConsoleUser = 9, + k_EAccountTypeAnonUser = 10, + k_EAccountTypeMax = 11, +} +public enum EAppReleaseState +{ + k_EAppReleaseState_Unknown = 0, + k_EAppReleaseState_Unavailable = 1, + k_EAppReleaseState_Prerelease = 2, + k_EAppReleaseState_PreloadOnly = 3, + k_EAppReleaseState_Released = 4, +} +public enum EAppOwnershipFlags +{ + k_EAppOwnershipFlags_None = 0, + k_EAppOwnershipFlags_OwnsLicense = 1, + k_EAppOwnershipFlags_FreeLicense = 2, + k_EAppOwnershipFlags_RegionRestricted = 4, + k_EAppOwnershipFlags_LowViolence = 8, + k_EAppOwnershipFlags_InvalidPlatform = 16, + k_EAppOwnershipFlags_SharedLicense = 32, + k_EAppOwnershipFlags_FreeWeekend = 64, + k_EAppOwnershipFlags_RetailLicense = 128, + k_EAppOwnershipFlags_LicenseLocked = 256, + k_EAppOwnershipFlags_LicensePending = 512, + k_EAppOwnershipFlags_LicenseExpired = 1024, + k_EAppOwnershipFlags_LicensePermanent = 2048, + k_EAppOwnershipFlags_LicenseRecurring = 4096, + k_EAppOwnershipFlags_LicenseCanceled = 8192, + k_EAppOwnershipFlags_AutoGrant = 16384, + k_EAppOwnershipFlags_PendingGift = 32768, + k_EAppOwnershipFlags_RentalNotActivated = 65536, + k_EAppOwnershipFlags_Rental = 131072, + k_EAppOwnershipFlags_SiteLicense = 262144, +} +public enum EAppType +{ + k_EAppType_Invalid = 0, + k_EAppType_Game = 1, + k_EAppType_Application = 2, + k_EAppType_Tool = 4, + k_EAppType_Demo = 8, + k_EAppType_Media_DEPRECATED = 16, + k_EAppType_DLC = 32, + k_EAppType_Guide = 64, + k_EAppType_Driver = 128, + k_EAppType_Config = 256, + k_EAppType_Hardware = 512, + k_EAppType_Franchise = 1024, + k_EAppType_Video = 2048, + k_EAppType_Plugin = 4096, + k_EAppType_Music = 8192, + k_EAppType_Series = 16384, + k_EAppType_Comic = 32768, + k_EAppType_Beta = 65536, + k_EAppType_Shortcut = 1073741824, + k_EAppType_DepotOnly = -2147483648, +} +public enum ESteamUserStatType +{ + k_ESteamUserStatTypeINVALID = 0, + k_ESteamUserStatTypeINT = 1, + k_ESteamUserStatTypeFLOAT = 2, + k_ESteamUserStatTypeAVGRATE = 3, + k_ESteamUserStatTypeACHIEVEMENTS = 4, + k_ESteamUserStatTypeGROUPACHIEVEMENTS = 5, + k_ESteamUserStatTypeMAX = 6, +} +public enum EChatEntryType +{ + k_EChatEntryTypeInvalid = 0, + k_EChatEntryTypeChatMsg = 1, + k_EChatEntryTypeTyping = 2, + k_EChatEntryTypeInviteGame = 3, + k_EChatEntryTypeEmote = 4, + k_EChatEntryTypeLeftConversation = 6, + k_EChatEntryTypeEntered = 7, + k_EChatEntryTypeWasKicked = 8, + k_EChatEntryTypeWasBanned = 9, + k_EChatEntryTypeDisconnected = 10, + k_EChatEntryTypeHistoricalChat = 11, + k_EChatEntryTypeLinkBlocked = 14, +} +public enum EChatRoomEnterResponse +{ + k_EChatRoomEnterResponseSuccess = 1, + k_EChatRoomEnterResponseDoesntExist = 2, + k_EChatRoomEnterResponseNotAllowed = 3, + k_EChatRoomEnterResponseFull = 4, + k_EChatRoomEnterResponseError = 5, + k_EChatRoomEnterResponseBanned = 6, + k_EChatRoomEnterResponseLimited = 7, + k_EChatRoomEnterResponseClanDisabled = 8, + k_EChatRoomEnterResponseCommunityBan = 9, + k_EChatRoomEnterResponseMemberBlockedYou = 10, + k_EChatRoomEnterResponseYouBlockedMember = 11, + k_EChatRoomEnterResponseRatelimitExceeded = 15, +} +public enum EChatSteamIDInstanceFlags +{ + k_EChatAccountInstanceMask = 4095, + k_EChatInstanceFlagClan = 524288, + k_EChatInstanceFlagLobby = 262144, + k_EChatInstanceFlagMMSLobby = 131072, +} +public enum EMarketingMessageFlags +{ + k_EMarketingMessageFlagsNone = 0, + k_EMarketingMessageFlagsHighPriority = 1, + k_EMarketingMessageFlagsPlatformWindows = 2, + k_EMarketingMessageFlagsPlatformMac = 4, + k_EMarketingMessageFlagsPlatformLinux = 8, + k_EMarketingMessageFlagsPlatformRestrictions = 14, +} +public enum ENotificationPosition +{ + k_EPositionTopLeft = 0, + k_EPositionTopRight = 1, + k_EPositionBottomLeft = 2, + k_EPositionBottomRight = 3, +} +public enum EBroadcastUploadResult +{ + k_EBroadcastUploadResultNone = 0, + k_EBroadcastUploadResultOK = 1, + k_EBroadcastUploadResultInitFailed = 2, + k_EBroadcastUploadResultFrameFailed = 3, + k_EBroadcastUploadResultTimeout = 4, + k_EBroadcastUploadResultBandwidthExceeded = 5, + k_EBroadcastUploadResultLowFPS = 6, + k_EBroadcastUploadResultMissingKeyFrames = 7, + k_EBroadcastUploadResultNoConnection = 8, + k_EBroadcastUploadResultRelayFailed = 9, + k_EBroadcastUploadResultSettingsChanged = 10, + k_EBroadcastUploadResultMissingAudio = 11, + k_EBroadcastUploadResultTooFarBehind = 12, + k_EBroadcastUploadResultTranscodeBehind = 13, + k_EBroadcastUploadResultNotAllowedToPlay = 14, + k_EBroadcastUploadResultBusy = 15, + k_EBroadcastUploadResultBanned = 16, + k_EBroadcastUploadResultAlreadyActive = 17, + k_EBroadcastUploadResultForcedOff = 18, + k_EBroadcastUploadResultAudioBehind = 19, + k_EBroadcastUploadResultShutdown = 20, + k_EBroadcastUploadResultDisconnect = 21, + k_EBroadcastUploadResultVideoInitFailed = 22, + k_EBroadcastUploadResultAudioInitFailed = 23, +} +public enum ELaunchOptionType +{ + k_ELaunchOptionType_None = 0, + k_ELaunchOptionType_Default = 1, + k_ELaunchOptionType_SafeMode = 2, + k_ELaunchOptionType_Multiplayer = 3, + k_ELaunchOptionType_Config = 4, + k_ELaunchOptionType_OpenVR = 5, + k_ELaunchOptionType_Server = 6, + k_ELaunchOptionType_Editor = 7, + k_ELaunchOptionType_Manual = 8, + k_ELaunchOptionType_Benchmark = 9, + k_ELaunchOptionType_Option1 = 10, + k_ELaunchOptionType_Option2 = 11, + k_ELaunchOptionType_Option3 = 12, + k_ELaunchOptionType_OculusVR = 13, + k_ELaunchOptionType_OpenVROverlay = 14, + k_ELaunchOptionType_OSVR = 15, + k_ELaunchOptionType_Dialog = 1000, +} +public enum EVRHMDType +{ + k_eEVRHMDType_None = -1, + k_eEVRHMDType_Unknown = 0, + k_eEVRHMDType_HTC_Dev = 1, + k_eEVRHMDType_HTC_VivePre = 2, + k_eEVRHMDType_HTC_Vive = 3, + k_eEVRHMDType_HTC_VivePro = 4, + k_eEVRHMDType_HTC_ViveCosmos = 5, + k_eEVRHMDType_HTC_Unknown = 20, + k_eEVRHMDType_Oculus_DK1 = 21, + k_eEVRHMDType_Oculus_DK2 = 22, + k_eEVRHMDType_Oculus_Rift = 23, + k_eEVRHMDType_Oculus_RiftS = 24, + k_eEVRHMDType_Oculus_Unknown = 40, + k_eEVRHMDType_Acer_Unknown = 50, + k_eEVRHMDType_Acer_WindowsMR = 51, + k_eEVRHMDType_Dell_Unknown = 60, + k_eEVRHMDType_Dell_Visor = 61, + k_eEVRHMDType_Lenovo_Unknown = 70, + k_eEVRHMDType_Lenovo_Explorer = 71, + k_eEVRHMDType_HP_Unknown = 80, + k_eEVRHMDType_HP_WindowsMR = 81, + k_eEVRHMDType_Samsung_Unknown = 90, + k_eEVRHMDType_Samsung_Odyssey = 91, + k_eEVRHMDType_Unannounced_Unknown = 100, + k_eEVRHMDType_Unannounced_WindowsMR = 101, + k_eEVRHMDType_vridge = 110, + k_eEVRHMDType_Huawei_Unknown = 120, + k_eEVRHMDType_Huawei_VR2 = 121, + k_eEVRHMDType_Huawei_EndOfRange = 129, + k_eEVRHmdType_Valve_Unknown = 130, + k_eEVRHmdType_Valve_Index = 131, +} +public enum EMarketNotAllowedReasonFlags +{ + k_EMarketNotAllowedReason_None = 0, + k_EMarketNotAllowedReason_TemporaryFailure = 1, + k_EMarketNotAllowedReason_AccountDisabled = 2, + k_EMarketNotAllowedReason_AccountLockedDown = 4, + k_EMarketNotAllowedReason_AccountLimited = 8, + k_EMarketNotAllowedReason_TradeBanned = 16, + k_EMarketNotAllowedReason_AccountNotTrusted = 32, + k_EMarketNotAllowedReason_SteamGuardNotEnabled = 64, + k_EMarketNotAllowedReason_SteamGuardOnlyRecentlyEnabled = 128, + k_EMarketNotAllowedReason_RecentPasswordReset = 256, + k_EMarketNotAllowedReason_NewPaymentMethod = 512, + k_EMarketNotAllowedReason_InvalidCookie = 1024, + k_EMarketNotAllowedReason_UsingNewDevice = 2048, + k_EMarketNotAllowedReason_RecentSelfRefund = 4096, + k_EMarketNotAllowedReason_NewPaymentMethodCannotBeVerified = 8192, + k_EMarketNotAllowedReason_NoRecentPurchases = 16384, + k_EMarketNotAllowedReason_AcceptedWalletGift = 32768, +} +public enum EDurationControlProgress +{ + k_EDurationControlProgress_Full = 0, + k_EDurationControlProgress_Half = 1, + k_EDurationControlProgress_None = 2, +} +public enum EDurationControlNotification +{ + k_EDurationControlNotification_None = 0, + k_EDurationControlNotification_1Hour = 1, + k_EDurationControlNotification_3Hours = 2, + k_EDurationControlNotification_HalfProgress = 3, + k_EDurationControlNotification_NoProgress = 4, +} +public enum EGameSearchErrorCode_t +{ + k_EGameSearchErrorCode_OK = 1, + k_EGameSearchErrorCode_Failed_Search_Already_In_Progress = 2, + k_EGameSearchErrorCode_Failed_No_Search_In_Progress = 3, + k_EGameSearchErrorCode_Failed_Not_Lobby_Leader = 4, + k_EGameSearchErrorCode_Failed_No_Host_Available = 5, + k_EGameSearchErrorCode_Failed_Search_Params_Invalid = 6, + k_EGameSearchErrorCode_Failed_Offline = 7, + k_EGameSearchErrorCode_Failed_NotAuthorized = 8, + k_EGameSearchErrorCode_Failed_Unknown_Error = 9, +} +public enum EPlayerResult_t +{ + k_EPlayerResultFailedToConnect = 1, + k_EPlayerResultAbandoned = 2, + k_EPlayerResultKicked = 3, + k_EPlayerResultIncomplete = 4, + k_EPlayerResultCompleted = 5, +} +public enum EFailureType +{ + k_EFailureFlushedCallbackQueue = 0, + k_EFailurePipeFail = 1, +} +public enum EFriendRelationship +{ + k_EFriendRelationshipNone = 0, + k_EFriendRelationshipBlocked = 1, + k_EFriendRelationshipRequestRecipient = 2, + k_EFriendRelationshipFriend = 3, + k_EFriendRelationshipRequestInitiator = 4, + k_EFriendRelationshipIgnored = 5, + k_EFriendRelationshipIgnoredFriend = 6, + k_EFriendRelationshipSuggested_DEPRECATED = 7, + k_EFriendRelationshipMax = 8, +} +public enum EPersonaState +{ + k_EPersonaStateOffline = 0, + k_EPersonaStateOnline = 1, + k_EPersonaStateBusy = 2, + k_EPersonaStateAway = 3, + k_EPersonaStateSnooze = 4, + k_EPersonaStateLookingToTrade = 5, + k_EPersonaStateLookingToPlay = 6, + k_EPersonaStateInvisible = 7, + k_EPersonaStateMax = 8, +} +public enum EFriendFlags +{ + k_EFriendFlagNone = 0, + k_EFriendFlagBlocked = 1, + k_EFriendFlagFriendshipRequested = 2, + k_EFriendFlagImmediate = 4, + k_EFriendFlagClanMember = 8, + k_EFriendFlagOnGameServer = 16, + k_EFriendFlagRequestingFriendship = 128, + k_EFriendFlagRequestingInfo = 256, + k_EFriendFlagIgnored = 512, + k_EFriendFlagIgnoredFriend = 1024, + k_EFriendFlagChatMember = 4096, + k_EFriendFlagAll = 65535, +} +public enum EUserRestriction +{ + k_nUserRestrictionNone = 0, + k_nUserRestrictionUnknown = 1, + k_nUserRestrictionAnyChat = 2, + k_nUserRestrictionVoiceChat = 4, + k_nUserRestrictionGroupChat = 8, + k_nUserRestrictionRating = 16, + k_nUserRestrictionGameInvites = 32, + k_nUserRestrictionTrading = 64, +} +public enum EOverlayToStoreFlag +{ + k_EOverlayToStoreFlag_None = 0, + k_EOverlayToStoreFlag_AddToCart = 1, + k_EOverlayToStoreFlag_AddToCartAndShow = 2, +} +public enum EActivateGameOverlayToWebPageMode +{ + k_EActivateGameOverlayToWebPageMode_Default = 0, + k_EActivateGameOverlayToWebPageMode_Modal = 1, +} +public enum EPersonaChange +{ + k_EPersonaChangeName = 1, + k_EPersonaChangeStatus = 2, + k_EPersonaChangeComeOnline = 4, + k_EPersonaChangeGoneOffline = 8, + k_EPersonaChangeGamePlayed = 16, + k_EPersonaChangeGameServer = 32, + k_EPersonaChangeAvatar = 64, + k_EPersonaChangeJoinedSource = 128, + k_EPersonaChangeLeftSource = 256, + k_EPersonaChangeRelationshipChanged = 512, + k_EPersonaChangeNameFirstSet = 1024, + k_EPersonaChangeBroadcast = 2048, + k_EPersonaChangeNickname = 4096, + k_EPersonaChangeSteamLevel = 8192, + k_EPersonaChangeRichPresence = 16384, +} +public enum ESteamAPICallFailure +{ + k_ESteamAPICallFailureNone = -1, + k_ESteamAPICallFailureSteamGone = 0, + k_ESteamAPICallFailureNetworkFailure = 1, + k_ESteamAPICallFailureInvalidHandle = 2, + k_ESteamAPICallFailureMismatchedCallback = 3, +} +public enum EGamepadTextInputMode +{ + k_EGamepadTextInputModeNormal = 0, + k_EGamepadTextInputModePassword = 1, +} +public enum EGamepadTextInputLineMode +{ + k_EGamepadTextInputLineModeSingleLine = 0, + k_EGamepadTextInputLineModeMultipleLines = 1, +} +public enum ECheckFileSignature +{ + k_ECheckFileSignatureInvalidSignature = 0, + k_ECheckFileSignatureValidSignature = 1, + k_ECheckFileSignatureFileNotFound = 2, + k_ECheckFileSignatureNoSignaturesFoundForThisApp = 3, + k_ECheckFileSignatureNoSignaturesFoundForThisFile = 4, +} +public enum EMatchMakingServerResponse +{ + eServerResponded = 0, + eServerFailedToRespond = 1, + eNoServersListedOnMasterServer = 2, +} +public enum ELobbyType +{ + k_ELobbyTypePrivate = 0, + k_ELobbyTypeFriendsOnly = 1, + k_ELobbyTypePublic = 2, + k_ELobbyTypeInvisible = 3, + k_ELobbyTypePrivateUnique = 4, +} +public enum ELobbyComparison +{ + k_ELobbyComparisonEqualToOrLessThan = -2, + k_ELobbyComparisonLessThan = -1, + k_ELobbyComparisonEqual = 0, + k_ELobbyComparisonGreaterThan = 1, + k_ELobbyComparisonEqualToOrGreaterThan = 2, + k_ELobbyComparisonNotEqual = 3, +} +public enum ELobbyDistanceFilter +{ + k_ELobbyDistanceFilterClose = 0, + k_ELobbyDistanceFilterDefault = 1, + k_ELobbyDistanceFilterFar = 2, + k_ELobbyDistanceFilterWorldwide = 3, +} +public enum EChatMemberStateChange +{ + k_EChatMemberStateChangeEntered = 1, + k_EChatMemberStateChangeLeft = 2, + k_EChatMemberStateChangeDisconnected = 4, + k_EChatMemberStateChangeKicked = 8, + k_EChatMemberStateChangeBanned = 16, +} +public enum ESteamPartyBeaconLocationType +{ + k_ESteamPartyBeaconLocationType_Invalid = 0, + k_ESteamPartyBeaconLocationType_ChatGroup = 1, + k_ESteamPartyBeaconLocationType_Max = 2, +} +public enum ESteamPartyBeaconLocationData +{ + k_ESteamPartyBeaconLocationDataInvalid = 0, + k_ESteamPartyBeaconLocationDataName = 1, + k_ESteamPartyBeaconLocationDataIconURLSmall = 2, + k_ESteamPartyBeaconLocationDataIconURLMedium = 3, + k_ESteamPartyBeaconLocationDataIconURLLarge = 4, +} +public enum ERemoteStoragePlatform +{ + k_ERemoteStoragePlatformNone = 0, + k_ERemoteStoragePlatformWindows = 1, + k_ERemoteStoragePlatformOSX = 2, + k_ERemoteStoragePlatformPS3 = 4, + k_ERemoteStoragePlatformLinux = 8, + k_ERemoteStoragePlatformReserved2 = 16, + k_ERemoteStoragePlatformAndroid = 32, + k_ERemoteStoragePlatformIOS = 64, + k_ERemoteStoragePlatformAll = -1, +} +public enum ERemoteStoragePublishedFileVisibility +{ + k_ERemoteStoragePublishedFileVisibilityPublic = 0, + k_ERemoteStoragePublishedFileVisibilityFriendsOnly = 1, + k_ERemoteStoragePublishedFileVisibilityPrivate = 2, +} +public enum EWorkshopFileType +{ + k_EWorkshopFileTypeFirst = 0, + k_EWorkshopFileTypeCommunity = 0, + k_EWorkshopFileTypeMicrotransaction = 1, + k_EWorkshopFileTypeCollection = 2, + k_EWorkshopFileTypeArt = 3, + k_EWorkshopFileTypeVideo = 4, + k_EWorkshopFileTypeScreenshot = 5, + k_EWorkshopFileTypeGame = 6, + k_EWorkshopFileTypeSoftware = 7, + k_EWorkshopFileTypeConcept = 8, + k_EWorkshopFileTypeWebGuide = 9, + k_EWorkshopFileTypeIntegratedGuide = 10, + k_EWorkshopFileTypeMerch = 11, + k_EWorkshopFileTypeControllerBinding = 12, + k_EWorkshopFileTypeSteamworksAccessInvite = 13, + k_EWorkshopFileTypeSteamVideo = 14, + k_EWorkshopFileTypeGameManagedItem = 15, + k_EWorkshopFileTypeMax = 16, +} +public enum EWorkshopVote +{ + k_EWorkshopVoteUnvoted = 0, + k_EWorkshopVoteFor = 1, + k_EWorkshopVoteAgainst = 2, + k_EWorkshopVoteLater = 3, +} +public enum EWorkshopFileAction +{ + k_EWorkshopFileActionPlayed = 0, + k_EWorkshopFileActionCompleted = 1, +} +public enum EWorkshopEnumerationType +{ + k_EWorkshopEnumerationTypeRankedByVote = 0, + k_EWorkshopEnumerationTypeRecent = 1, + k_EWorkshopEnumerationTypeTrending = 2, + k_EWorkshopEnumerationTypeFavoritesOfFriends = 3, + k_EWorkshopEnumerationTypeVotedByFriends = 4, + k_EWorkshopEnumerationTypeContentByFriends = 5, + k_EWorkshopEnumerationTypeRecentFromFollowedUsers = 6, +} +public enum EWorkshopVideoProvider +{ + k_EWorkshopVideoProviderNone = 0, + k_EWorkshopVideoProviderYoutube = 1, +} +public enum EUGCReadAction +{ + k_EUGCRead_ContinueReadingUntilFinished = 0, + k_EUGCRead_ContinueReading = 1, + k_EUGCRead_Close = 2, +} +public enum ELeaderboardDataRequest +{ + k_ELeaderboardDataRequestGlobal = 0, + k_ELeaderboardDataRequestGlobalAroundUser = 1, + k_ELeaderboardDataRequestFriends = 2, + k_ELeaderboardDataRequestUsers = 3, +} +public enum ELeaderboardSortMethod +{ + k_ELeaderboardSortMethodNone = 0, + k_ELeaderboardSortMethodAscending = 1, + k_ELeaderboardSortMethodDescending = 2, +} +public enum ELeaderboardDisplayType +{ + k_ELeaderboardDisplayTypeNone = 0, + k_ELeaderboardDisplayTypeNumeric = 1, + k_ELeaderboardDisplayTypeTimeSeconds = 2, + k_ELeaderboardDisplayTypeTimeMilliSeconds = 3, +} +public enum ELeaderboardUploadScoreMethod +{ + k_ELeaderboardUploadScoreMethodNone = 0, + k_ELeaderboardUploadScoreMethodKeepBest = 1, + k_ELeaderboardUploadScoreMethodForceUpdate = 2, +} +public enum ERegisterActivationCodeResult +{ + k_ERegisterActivationCodeResultOK = 0, + k_ERegisterActivationCodeResultFail = 1, + k_ERegisterActivationCodeResultAlreadyRegistered = 2, + k_ERegisterActivationCodeResultTimeout = 3, + k_ERegisterActivationCodeAlreadyOwned = 4, +} +public enum EP2PSessionError +{ + k_EP2PSessionErrorNone = 0, + k_EP2PSessionErrorNotRunningApp = 1, + k_EP2PSessionErrorNoRightsToApp = 2, + k_EP2PSessionErrorDestinationNotLoggedIn = 3, + k_EP2PSessionErrorTimeout = 4, + k_EP2PSessionErrorMax = 5, +} +public enum EP2PSend +{ + k_EP2PSendUnreliable = 0, + k_EP2PSendUnreliableNoDelay = 1, + k_EP2PSendReliable = 2, + k_EP2PSendReliableWithBuffering = 3, +} +public enum ESNetSocketState +{ + k_ESNetSocketStateInvalid = 0, + k_ESNetSocketStateConnected = 1, + k_ESNetSocketStateInitiated = 10, + k_ESNetSocketStateLocalCandidatesFound = 11, + k_ESNetSocketStateReceivedRemoteCandidates = 12, + k_ESNetSocketStateChallengeHandshake = 15, + k_ESNetSocketStateDisconnecting = 21, + k_ESNetSocketStateLocalDisconnect = 22, + k_ESNetSocketStateTimeoutDuringConnect = 23, + k_ESNetSocketStateRemoteEndDisconnected = 24, + k_ESNetSocketStateConnectionBroken = 25, +} +public enum ESNetSocketConnectionType +{ + k_ESNetSocketConnectionTypeNotConnected = 0, + k_ESNetSocketConnectionTypeUDP = 1, + k_ESNetSocketConnectionTypeUDPRelay = 2, +} +public enum EVRScreenshotType +{ + k_EVRScreenshotType_None = 0, + k_EVRScreenshotType_Mono = 1, + k_EVRScreenshotType_Stereo = 2, + k_EVRScreenshotType_MonoCubemap = 3, + k_EVRScreenshotType_MonoPanorama = 4, + k_EVRScreenshotType_StereoPanorama = 5, +} +public enum AudioPlayback_Status +{ + AudioPlayback_Undefined = 0, + AudioPlayback_Playing = 1, + AudioPlayback_Paused = 2, + AudioPlayback_Idle = 3, +} +public enum EHTTPMethod +{ + k_EHTTPMethodInvalid = 0, + k_EHTTPMethodGET = 1, + k_EHTTPMethodHEAD = 2, + k_EHTTPMethodPOST = 3, + k_EHTTPMethodPUT = 4, + k_EHTTPMethodDELETE = 5, + k_EHTTPMethodOPTIONS = 6, + k_EHTTPMethodPATCH = 7, +} +public enum EHTTPStatusCode +{ + k_EHTTPStatusCodeInvalid = 0, + k_EHTTPStatusCode100Continue = 100, + k_EHTTPStatusCode101SwitchingProtocols = 101, + k_EHTTPStatusCode200OK = 200, + k_EHTTPStatusCode201Created = 201, + k_EHTTPStatusCode202Accepted = 202, + k_EHTTPStatusCode203NonAuthoritative = 203, + k_EHTTPStatusCode204NoContent = 204, + k_EHTTPStatusCode205ResetContent = 205, + k_EHTTPStatusCode206PartialContent = 206, + k_EHTTPStatusCode300MultipleChoices = 300, + k_EHTTPStatusCode301MovedPermanently = 301, + k_EHTTPStatusCode302Found = 302, + k_EHTTPStatusCode303SeeOther = 303, + k_EHTTPStatusCode304NotModified = 304, + k_EHTTPStatusCode305UseProxy = 305, + k_EHTTPStatusCode307TemporaryRedirect = 307, + k_EHTTPStatusCode400BadRequest = 400, + k_EHTTPStatusCode401Unauthorized = 401, + k_EHTTPStatusCode402PaymentRequired = 402, + k_EHTTPStatusCode403Forbidden = 403, + k_EHTTPStatusCode404NotFound = 404, + k_EHTTPStatusCode405MethodNotAllowed = 405, + k_EHTTPStatusCode406NotAcceptable = 406, + k_EHTTPStatusCode407ProxyAuthRequired = 407, + k_EHTTPStatusCode408RequestTimeout = 408, + k_EHTTPStatusCode409Conflict = 409, + k_EHTTPStatusCode410Gone = 410, + k_EHTTPStatusCode411LengthRequired = 411, + k_EHTTPStatusCode412PreconditionFailed = 412, + k_EHTTPStatusCode413RequestEntityTooLarge = 413, + k_EHTTPStatusCode414RequestURITooLong = 414, + k_EHTTPStatusCode415UnsupportedMediaType = 415, + k_EHTTPStatusCode416RequestedRangeNotSatisfiable = 416, + k_EHTTPStatusCode417ExpectationFailed = 417, + k_EHTTPStatusCode4xxUnknown = 418, + k_EHTTPStatusCode429TooManyRequests = 429, + k_EHTTPStatusCode500InternalServerError = 500, + k_EHTTPStatusCode501NotImplemented = 501, + k_EHTTPStatusCode502BadGateway = 502, + k_EHTTPStatusCode503ServiceUnavailable = 503, + k_EHTTPStatusCode504GatewayTimeout = 504, + k_EHTTPStatusCode505HTTPVersionNotSupported = 505, + k_EHTTPStatusCode5xxUnknown = 599, +} +public enum EInputSource +{ + k_EInputSource_None = 0, + k_EInputSource_LeftTrackpad = 1, + k_EInputSource_RightTrackpad = 2, + k_EInputSource_Joystick = 3, + k_EInputSource_ABXY = 4, + k_EInputSource_Switch = 5, + k_EInputSource_LeftTrigger = 6, + k_EInputSource_RightTrigger = 7, + k_EInputSource_LeftBumper = 8, + k_EInputSource_RightBumper = 9, + k_EInputSource_Gyro = 10, + k_EInputSource_CenterTrackpad = 11, + k_EInputSource_RightJoystick = 12, + k_EInputSource_DPad = 13, + k_EInputSource_Key = 14, + k_EInputSource_Mouse = 15, + k_EInputSource_LeftGyro = 16, + k_EInputSource_Count = 17, +} +public enum EInputSourceMode +{ + k_EInputSourceMode_None = 0, + k_EInputSourceMode_Dpad = 1, + k_EInputSourceMode_Buttons = 2, + k_EInputSourceMode_FourButtons = 3, + k_EInputSourceMode_AbsoluteMouse = 4, + k_EInputSourceMode_RelativeMouse = 5, + k_EInputSourceMode_JoystickMove = 6, + k_EInputSourceMode_JoystickMouse = 7, + k_EInputSourceMode_JoystickCamera = 8, + k_EInputSourceMode_ScrollWheel = 9, + k_EInputSourceMode_Trigger = 10, + k_EInputSourceMode_TouchMenu = 11, + k_EInputSourceMode_MouseJoystick = 12, + k_EInputSourceMode_MouseRegion = 13, + k_EInputSourceMode_RadialMenu = 14, + k_EInputSourceMode_SingleButton = 15, + k_EInputSourceMode_Switches = 16, +} +public enum EInputActionOrigin +{ + k_EInputActionOrigin_None = 0, + k_EInputActionOrigin_SteamController_A = 1, + k_EInputActionOrigin_SteamController_B = 2, + k_EInputActionOrigin_SteamController_X = 3, + k_EInputActionOrigin_SteamController_Y = 4, + k_EInputActionOrigin_SteamController_LeftBumper = 5, + k_EInputActionOrigin_SteamController_RightBumper = 6, + k_EInputActionOrigin_SteamController_LeftGrip = 7, + k_EInputActionOrigin_SteamController_RightGrip = 8, + k_EInputActionOrigin_SteamController_Start = 9, + k_EInputActionOrigin_SteamController_Back = 10, + k_EInputActionOrigin_SteamController_LeftPad_Touch = 11, + k_EInputActionOrigin_SteamController_LeftPad_Swipe = 12, + k_EInputActionOrigin_SteamController_LeftPad_Click = 13, + k_EInputActionOrigin_SteamController_LeftPad_DPadNorth = 14, + k_EInputActionOrigin_SteamController_LeftPad_DPadSouth = 15, + k_EInputActionOrigin_SteamController_LeftPad_DPadWest = 16, + k_EInputActionOrigin_SteamController_LeftPad_DPadEast = 17, + k_EInputActionOrigin_SteamController_RightPad_Touch = 18, + k_EInputActionOrigin_SteamController_RightPad_Swipe = 19, + k_EInputActionOrigin_SteamController_RightPad_Click = 20, + k_EInputActionOrigin_SteamController_RightPad_DPadNorth = 21, + k_EInputActionOrigin_SteamController_RightPad_DPadSouth = 22, + k_EInputActionOrigin_SteamController_RightPad_DPadWest = 23, + k_EInputActionOrigin_SteamController_RightPad_DPadEast = 24, + k_EInputActionOrigin_SteamController_LeftTrigger_Pull = 25, + k_EInputActionOrigin_SteamController_LeftTrigger_Click = 26, + k_EInputActionOrigin_SteamController_RightTrigger_Pull = 27, + k_EInputActionOrigin_SteamController_RightTrigger_Click = 28, + k_EInputActionOrigin_SteamController_LeftStick_Move = 29, + k_EInputActionOrigin_SteamController_LeftStick_Click = 30, + k_EInputActionOrigin_SteamController_LeftStick_DPadNorth = 31, + k_EInputActionOrigin_SteamController_LeftStick_DPadSouth = 32, + k_EInputActionOrigin_SteamController_LeftStick_DPadWest = 33, + k_EInputActionOrigin_SteamController_LeftStick_DPadEast = 34, + k_EInputActionOrigin_SteamController_Gyro_Move = 35, + k_EInputActionOrigin_SteamController_Gyro_Pitch = 36, + k_EInputActionOrigin_SteamController_Gyro_Yaw = 37, + k_EInputActionOrigin_SteamController_Gyro_Roll = 38, + k_EInputActionOrigin_SteamController_Reserved0 = 39, + k_EInputActionOrigin_SteamController_Reserved1 = 40, + k_EInputActionOrigin_SteamController_Reserved2 = 41, + k_EInputActionOrigin_SteamController_Reserved3 = 42, + k_EInputActionOrigin_SteamController_Reserved4 = 43, + k_EInputActionOrigin_SteamController_Reserved5 = 44, + k_EInputActionOrigin_SteamController_Reserved6 = 45, + k_EInputActionOrigin_SteamController_Reserved7 = 46, + k_EInputActionOrigin_SteamController_Reserved8 = 47, + k_EInputActionOrigin_SteamController_Reserved9 = 48, + k_EInputActionOrigin_SteamController_Reserved10 = 49, + k_EInputActionOrigin_PS4_X = 50, + k_EInputActionOrigin_PS4_Circle = 51, + k_EInputActionOrigin_PS4_Triangle = 52, + k_EInputActionOrigin_PS4_Square = 53, + k_EInputActionOrigin_PS4_LeftBumper = 54, + k_EInputActionOrigin_PS4_RightBumper = 55, + k_EInputActionOrigin_PS4_Options = 56, + k_EInputActionOrigin_PS4_Share = 57, + k_EInputActionOrigin_PS4_LeftPad_Touch = 58, + k_EInputActionOrigin_PS4_LeftPad_Swipe = 59, + k_EInputActionOrigin_PS4_LeftPad_Click = 60, + k_EInputActionOrigin_PS4_LeftPad_DPadNorth = 61, + k_EInputActionOrigin_PS4_LeftPad_DPadSouth = 62, + k_EInputActionOrigin_PS4_LeftPad_DPadWest = 63, + k_EInputActionOrigin_PS4_LeftPad_DPadEast = 64, + k_EInputActionOrigin_PS4_RightPad_Touch = 65, + k_EInputActionOrigin_PS4_RightPad_Swipe = 66, + k_EInputActionOrigin_PS4_RightPad_Click = 67, + k_EInputActionOrigin_PS4_RightPad_DPadNorth = 68, + k_EInputActionOrigin_PS4_RightPad_DPadSouth = 69, + k_EInputActionOrigin_PS4_RightPad_DPadWest = 70, + k_EInputActionOrigin_PS4_RightPad_DPadEast = 71, + k_EInputActionOrigin_PS4_CenterPad_Touch = 72, + k_EInputActionOrigin_PS4_CenterPad_Swipe = 73, + k_EInputActionOrigin_PS4_CenterPad_Click = 74, + k_EInputActionOrigin_PS4_CenterPad_DPadNorth = 75, + k_EInputActionOrigin_PS4_CenterPad_DPadSouth = 76, + k_EInputActionOrigin_PS4_CenterPad_DPadWest = 77, + k_EInputActionOrigin_PS4_CenterPad_DPadEast = 78, + k_EInputActionOrigin_PS4_LeftTrigger_Pull = 79, + k_EInputActionOrigin_PS4_LeftTrigger_Click = 80, + k_EInputActionOrigin_PS4_RightTrigger_Pull = 81, + k_EInputActionOrigin_PS4_RightTrigger_Click = 82, + k_EInputActionOrigin_PS4_LeftStick_Move = 83, + k_EInputActionOrigin_PS4_LeftStick_Click = 84, + k_EInputActionOrigin_PS4_LeftStick_DPadNorth = 85, + k_EInputActionOrigin_PS4_LeftStick_DPadSouth = 86, + k_EInputActionOrigin_PS4_LeftStick_DPadWest = 87, + k_EInputActionOrigin_PS4_LeftStick_DPadEast = 88, + k_EInputActionOrigin_PS4_RightStick_Move = 89, + k_EInputActionOrigin_PS4_RightStick_Click = 90, + k_EInputActionOrigin_PS4_RightStick_DPadNorth = 91, + k_EInputActionOrigin_PS4_RightStick_DPadSouth = 92, + k_EInputActionOrigin_PS4_RightStick_DPadWest = 93, + k_EInputActionOrigin_PS4_RightStick_DPadEast = 94, + k_EInputActionOrigin_PS4_DPad_North = 95, + k_EInputActionOrigin_PS4_DPad_South = 96, + k_EInputActionOrigin_PS4_DPad_West = 97, + k_EInputActionOrigin_PS4_DPad_East = 98, + k_EInputActionOrigin_PS4_Gyro_Move = 99, + k_EInputActionOrigin_PS4_Gyro_Pitch = 100, + k_EInputActionOrigin_PS4_Gyro_Yaw = 101, + k_EInputActionOrigin_PS4_Gyro_Roll = 102, + k_EInputActionOrigin_PS4_DPad_Move = 103, + k_EInputActionOrigin_PS4_Reserved1 = 104, + k_EInputActionOrigin_PS4_Reserved2 = 105, + k_EInputActionOrigin_PS4_Reserved3 = 106, + k_EInputActionOrigin_PS4_Reserved4 = 107, + k_EInputActionOrigin_PS4_Reserved5 = 108, + k_EInputActionOrigin_PS4_Reserved6 = 109, + k_EInputActionOrigin_PS4_Reserved7 = 110, + k_EInputActionOrigin_PS4_Reserved8 = 111, + k_EInputActionOrigin_PS4_Reserved9 = 112, + k_EInputActionOrigin_PS4_Reserved10 = 113, + k_EInputActionOrigin_XBoxOne_A = 114, + k_EInputActionOrigin_XBoxOne_B = 115, + k_EInputActionOrigin_XBoxOne_X = 116, + k_EInputActionOrigin_XBoxOne_Y = 117, + k_EInputActionOrigin_XBoxOne_LeftBumper = 118, + k_EInputActionOrigin_XBoxOne_RightBumper = 119, + k_EInputActionOrigin_XBoxOne_Menu = 120, + k_EInputActionOrigin_XBoxOne_View = 121, + k_EInputActionOrigin_XBoxOne_LeftTrigger_Pull = 122, + k_EInputActionOrigin_XBoxOne_LeftTrigger_Click = 123, + k_EInputActionOrigin_XBoxOne_RightTrigger_Pull = 124, + k_EInputActionOrigin_XBoxOne_RightTrigger_Click = 125, + k_EInputActionOrigin_XBoxOne_LeftStick_Move = 126, + k_EInputActionOrigin_XBoxOne_LeftStick_Click = 127, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadNorth = 128, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadSouth = 129, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadWest = 130, + k_EInputActionOrigin_XBoxOne_LeftStick_DPadEast = 131, + k_EInputActionOrigin_XBoxOne_RightStick_Move = 132, + k_EInputActionOrigin_XBoxOne_RightStick_Click = 133, + k_EInputActionOrigin_XBoxOne_RightStick_DPadNorth = 134, + k_EInputActionOrigin_XBoxOne_RightStick_DPadSouth = 135, + k_EInputActionOrigin_XBoxOne_RightStick_DPadWest = 136, + k_EInputActionOrigin_XBoxOne_RightStick_DPadEast = 137, + k_EInputActionOrigin_XBoxOne_DPad_North = 138, + k_EInputActionOrigin_XBoxOne_DPad_South = 139, + k_EInputActionOrigin_XBoxOne_DPad_West = 140, + k_EInputActionOrigin_XBoxOne_DPad_East = 141, + k_EInputActionOrigin_XBoxOne_DPad_Move = 142, + k_EInputActionOrigin_XBoxOne_Reserved1 = 143, + k_EInputActionOrigin_XBoxOne_Reserved2 = 144, + k_EInputActionOrigin_XBoxOne_Reserved3 = 145, + k_EInputActionOrigin_XBoxOne_Reserved4 = 146, + k_EInputActionOrigin_XBoxOne_Reserved5 = 147, + k_EInputActionOrigin_XBoxOne_Reserved6 = 148, + k_EInputActionOrigin_XBoxOne_Reserved7 = 149, + k_EInputActionOrigin_XBoxOne_Reserved8 = 150, + k_EInputActionOrigin_XBoxOne_Reserved9 = 151, + k_EInputActionOrigin_XBoxOne_Reserved10 = 152, + k_EInputActionOrigin_XBox360_A = 153, + k_EInputActionOrigin_XBox360_B = 154, + k_EInputActionOrigin_XBox360_X = 155, + k_EInputActionOrigin_XBox360_Y = 156, + k_EInputActionOrigin_XBox360_LeftBumper = 157, + k_EInputActionOrigin_XBox360_RightBumper = 158, + k_EInputActionOrigin_XBox360_Start = 159, + k_EInputActionOrigin_XBox360_Back = 160, + k_EInputActionOrigin_XBox360_LeftTrigger_Pull = 161, + k_EInputActionOrigin_XBox360_LeftTrigger_Click = 162, + k_EInputActionOrigin_XBox360_RightTrigger_Pull = 163, + k_EInputActionOrigin_XBox360_RightTrigger_Click = 164, + k_EInputActionOrigin_XBox360_LeftStick_Move = 165, + k_EInputActionOrigin_XBox360_LeftStick_Click = 166, + k_EInputActionOrigin_XBox360_LeftStick_DPadNorth = 167, + k_EInputActionOrigin_XBox360_LeftStick_DPadSouth = 168, + k_EInputActionOrigin_XBox360_LeftStick_DPadWest = 169, + k_EInputActionOrigin_XBox360_LeftStick_DPadEast = 170, + k_EInputActionOrigin_XBox360_RightStick_Move = 171, + k_EInputActionOrigin_XBox360_RightStick_Click = 172, + k_EInputActionOrigin_XBox360_RightStick_DPadNorth = 173, + k_EInputActionOrigin_XBox360_RightStick_DPadSouth = 174, + k_EInputActionOrigin_XBox360_RightStick_DPadWest = 175, + k_EInputActionOrigin_XBox360_RightStick_DPadEast = 176, + k_EInputActionOrigin_XBox360_DPad_North = 177, + k_EInputActionOrigin_XBox360_DPad_South = 178, + k_EInputActionOrigin_XBox360_DPad_West = 179, + k_EInputActionOrigin_XBox360_DPad_East = 180, + k_EInputActionOrigin_XBox360_DPad_Move = 181, + k_EInputActionOrigin_XBox360_Reserved1 = 182, + k_EInputActionOrigin_XBox360_Reserved2 = 183, + k_EInputActionOrigin_XBox360_Reserved3 = 184, + k_EInputActionOrigin_XBox360_Reserved4 = 185, + k_EInputActionOrigin_XBox360_Reserved5 = 186, + k_EInputActionOrigin_XBox360_Reserved6 = 187, + k_EInputActionOrigin_XBox360_Reserved7 = 188, + k_EInputActionOrigin_XBox360_Reserved8 = 189, + k_EInputActionOrigin_XBox360_Reserved9 = 190, + k_EInputActionOrigin_XBox360_Reserved10 = 191, + k_EInputActionOrigin_Switch_A = 192, + k_EInputActionOrigin_Switch_B = 193, + k_EInputActionOrigin_Switch_X = 194, + k_EInputActionOrigin_Switch_Y = 195, + k_EInputActionOrigin_Switch_LeftBumper = 196, + k_EInputActionOrigin_Switch_RightBumper = 197, + k_EInputActionOrigin_Switch_Plus = 198, + k_EInputActionOrigin_Switch_Minus = 199, + k_EInputActionOrigin_Switch_Capture = 200, + k_EInputActionOrigin_Switch_LeftTrigger_Pull = 201, + k_EInputActionOrigin_Switch_LeftTrigger_Click = 202, + k_EInputActionOrigin_Switch_RightTrigger_Pull = 203, + k_EInputActionOrigin_Switch_RightTrigger_Click = 204, + k_EInputActionOrigin_Switch_LeftStick_Move = 205, + k_EInputActionOrigin_Switch_LeftStick_Click = 206, + k_EInputActionOrigin_Switch_LeftStick_DPadNorth = 207, + k_EInputActionOrigin_Switch_LeftStick_DPadSouth = 208, + k_EInputActionOrigin_Switch_LeftStick_DPadWest = 209, + k_EInputActionOrigin_Switch_LeftStick_DPadEast = 210, + k_EInputActionOrigin_Switch_RightStick_Move = 211, + k_EInputActionOrigin_Switch_RightStick_Click = 212, + k_EInputActionOrigin_Switch_RightStick_DPadNorth = 213, + k_EInputActionOrigin_Switch_RightStick_DPadSouth = 214, + k_EInputActionOrigin_Switch_RightStick_DPadWest = 215, + k_EInputActionOrigin_Switch_RightStick_DPadEast = 216, + k_EInputActionOrigin_Switch_DPad_North = 217, + k_EInputActionOrigin_Switch_DPad_South = 218, + k_EInputActionOrigin_Switch_DPad_West = 219, + k_EInputActionOrigin_Switch_DPad_East = 220, + k_EInputActionOrigin_Switch_ProGyro_Move = 221, + k_EInputActionOrigin_Switch_ProGyro_Pitch = 222, + k_EInputActionOrigin_Switch_ProGyro_Yaw = 223, + k_EInputActionOrigin_Switch_ProGyro_Roll = 224, + k_EInputActionOrigin_Switch_DPad_Move = 225, + k_EInputActionOrigin_Switch_Reserved1 = 226, + k_EInputActionOrigin_Switch_Reserved2 = 227, + k_EInputActionOrigin_Switch_Reserved3 = 228, + k_EInputActionOrigin_Switch_Reserved4 = 229, + k_EInputActionOrigin_Switch_Reserved5 = 230, + k_EInputActionOrigin_Switch_Reserved6 = 231, + k_EInputActionOrigin_Switch_Reserved7 = 232, + k_EInputActionOrigin_Switch_Reserved8 = 233, + k_EInputActionOrigin_Switch_Reserved9 = 234, + k_EInputActionOrigin_Switch_Reserved10 = 235, + k_EInputActionOrigin_Switch_RightGyro_Move = 236, + k_EInputActionOrigin_Switch_RightGyro_Pitch = 237, + k_EInputActionOrigin_Switch_RightGyro_Yaw = 238, + k_EInputActionOrigin_Switch_RightGyro_Roll = 239, + k_EInputActionOrigin_Switch_LeftGyro_Move = 240, + k_EInputActionOrigin_Switch_LeftGyro_Pitch = 241, + k_EInputActionOrigin_Switch_LeftGyro_Yaw = 242, + k_EInputActionOrigin_Switch_LeftGyro_Roll = 243, + k_EInputActionOrigin_Switch_LeftGrip_Lower = 244, + k_EInputActionOrigin_Switch_LeftGrip_Upper = 245, + k_EInputActionOrigin_Switch_RightGrip_Lower = 246, + k_EInputActionOrigin_Switch_RightGrip_Upper = 247, + k_EInputActionOrigin_Switch_Reserved11 = 248, + k_EInputActionOrigin_Switch_Reserved12 = 249, + k_EInputActionOrigin_Switch_Reserved13 = 250, + k_EInputActionOrigin_Switch_Reserved14 = 251, + k_EInputActionOrigin_Switch_Reserved15 = 252, + k_EInputActionOrigin_Switch_Reserved16 = 253, + k_EInputActionOrigin_Switch_Reserved17 = 254, + k_EInputActionOrigin_Switch_Reserved18 = 255, + k_EInputActionOrigin_Switch_Reserved19 = 256, + k_EInputActionOrigin_Switch_Reserved20 = 257, + k_EInputActionOrigin_Count = 258, + k_EInputActionOrigin_MaximumPossibleValue = 32767, +} +public enum EXboxOrigin +{ + k_EXboxOrigin_A = 0, + k_EXboxOrigin_B = 1, + k_EXboxOrigin_X = 2, + k_EXboxOrigin_Y = 3, + k_EXboxOrigin_LeftBumper = 4, + k_EXboxOrigin_RightBumper = 5, + k_EXboxOrigin_Menu = 6, + k_EXboxOrigin_View = 7, + k_EXboxOrigin_LeftTrigger_Pull = 8, + k_EXboxOrigin_LeftTrigger_Click = 9, + k_EXboxOrigin_RightTrigger_Pull = 10, + k_EXboxOrigin_RightTrigger_Click = 11, + k_EXboxOrigin_LeftStick_Move = 12, + k_EXboxOrigin_LeftStick_Click = 13, + k_EXboxOrigin_LeftStick_DPadNorth = 14, + k_EXboxOrigin_LeftStick_DPadSouth = 15, + k_EXboxOrigin_LeftStick_DPadWest = 16, + k_EXboxOrigin_LeftStick_DPadEast = 17, + k_EXboxOrigin_RightStick_Move = 18, + k_EXboxOrigin_RightStick_Click = 19, + k_EXboxOrigin_RightStick_DPadNorth = 20, + k_EXboxOrigin_RightStick_DPadSouth = 21, + k_EXboxOrigin_RightStick_DPadWest = 22, + k_EXboxOrigin_RightStick_DPadEast = 23, + k_EXboxOrigin_DPad_North = 24, + k_EXboxOrigin_DPad_South = 25, + k_EXboxOrigin_DPad_West = 26, + k_EXboxOrigin_DPad_East = 27, + k_EXboxOrigin_Count = 28, +} +public enum ESteamControllerPad +{ + k_ESteamControllerPad_Left = 0, + k_ESteamControllerPad_Right = 1, +} +public enum ESteamInputType +{ + k_ESteamInputType_Unknown = 0, + k_ESteamInputType_SteamController = 1, + k_ESteamInputType_XBox360Controller = 2, + k_ESteamInputType_XBoxOneController = 3, + k_ESteamInputType_GenericGamepad = 4, + k_ESteamInputType_PS4Controller = 5, + k_ESteamInputType_AppleMFiController = 6, + k_ESteamInputType_AndroidController = 7, + k_ESteamInputType_SwitchJoyConPair = 8, + k_ESteamInputType_SwitchJoyConSingle = 9, + k_ESteamInputType_SwitchProController = 10, + k_ESteamInputType_MobileTouch = 11, + k_ESteamInputType_PS3Controller = 12, + k_ESteamInputType_Count = 13, + k_ESteamInputType_MaximumPossibleValue = 255, +} +public enum ESteamInputLEDFlag +{ + k_ESteamInputLEDFlag_SetColor = 0, + k_ESteamInputLEDFlag_RestoreUserDefault = 1, +} +public enum EControllerSource +{ + k_EControllerSource_None = 0, + k_EControllerSource_LeftTrackpad = 1, + k_EControllerSource_RightTrackpad = 2, + k_EControllerSource_Joystick = 3, + k_EControllerSource_ABXY = 4, + k_EControllerSource_Switch = 5, + k_EControllerSource_LeftTrigger = 6, + k_EControllerSource_RightTrigger = 7, + k_EControllerSource_LeftBumper = 8, + k_EControllerSource_RightBumper = 9, + k_EControllerSource_Gyro = 10, + k_EControllerSource_CenterTrackpad = 11, + k_EControllerSource_RightJoystick = 12, + k_EControllerSource_DPad = 13, + k_EControllerSource_Key = 14, + k_EControllerSource_Mouse = 15, + k_EControllerSource_LeftGyro = 16, + k_EControllerSource_Count = 17, +} +public enum EControllerSourceMode +{ + k_EControllerSourceMode_None = 0, + k_EControllerSourceMode_Dpad = 1, + k_EControllerSourceMode_Buttons = 2, + k_EControllerSourceMode_FourButtons = 3, + k_EControllerSourceMode_AbsoluteMouse = 4, + k_EControllerSourceMode_RelativeMouse = 5, + k_EControllerSourceMode_JoystickMove = 6, + k_EControllerSourceMode_JoystickMouse = 7, + k_EControllerSourceMode_JoystickCamera = 8, + k_EControllerSourceMode_ScrollWheel = 9, + k_EControllerSourceMode_Trigger = 10, + k_EControllerSourceMode_TouchMenu = 11, + k_EControllerSourceMode_MouseJoystick = 12, + k_EControllerSourceMode_MouseRegion = 13, + k_EControllerSourceMode_RadialMenu = 14, + k_EControllerSourceMode_SingleButton = 15, + k_EControllerSourceMode_Switches = 16, +} +public enum EControllerActionOrigin +{ + k_EControllerActionOrigin_None = 0, + k_EControllerActionOrigin_A = 1, + k_EControllerActionOrigin_B = 2, + k_EControllerActionOrigin_X = 3, + k_EControllerActionOrigin_Y = 4, + k_EControllerActionOrigin_LeftBumper = 5, + k_EControllerActionOrigin_RightBumper = 6, + k_EControllerActionOrigin_LeftGrip = 7, + k_EControllerActionOrigin_RightGrip = 8, + k_EControllerActionOrigin_Start = 9, + k_EControllerActionOrigin_Back = 10, + k_EControllerActionOrigin_LeftPad_Touch = 11, + k_EControllerActionOrigin_LeftPad_Swipe = 12, + k_EControllerActionOrigin_LeftPad_Click = 13, + k_EControllerActionOrigin_LeftPad_DPadNorth = 14, + k_EControllerActionOrigin_LeftPad_DPadSouth = 15, + k_EControllerActionOrigin_LeftPad_DPadWest = 16, + k_EControllerActionOrigin_LeftPad_DPadEast = 17, + k_EControllerActionOrigin_RightPad_Touch = 18, + k_EControllerActionOrigin_RightPad_Swipe = 19, + k_EControllerActionOrigin_RightPad_Click = 20, + k_EControllerActionOrigin_RightPad_DPadNorth = 21, + k_EControllerActionOrigin_RightPad_DPadSouth = 22, + k_EControllerActionOrigin_RightPad_DPadWest = 23, + k_EControllerActionOrigin_RightPad_DPadEast = 24, + k_EControllerActionOrigin_LeftTrigger_Pull = 25, + k_EControllerActionOrigin_LeftTrigger_Click = 26, + k_EControllerActionOrigin_RightTrigger_Pull = 27, + k_EControllerActionOrigin_RightTrigger_Click = 28, + k_EControllerActionOrigin_LeftStick_Move = 29, + k_EControllerActionOrigin_LeftStick_Click = 30, + k_EControllerActionOrigin_LeftStick_DPadNorth = 31, + k_EControllerActionOrigin_LeftStick_DPadSouth = 32, + k_EControllerActionOrigin_LeftStick_DPadWest = 33, + k_EControllerActionOrigin_LeftStick_DPadEast = 34, + k_EControllerActionOrigin_Gyro_Move = 35, + k_EControllerActionOrigin_Gyro_Pitch = 36, + k_EControllerActionOrigin_Gyro_Yaw = 37, + k_EControllerActionOrigin_Gyro_Roll = 38, + k_EControllerActionOrigin_PS4_X = 39, + k_EControllerActionOrigin_PS4_Circle = 40, + k_EControllerActionOrigin_PS4_Triangle = 41, + k_EControllerActionOrigin_PS4_Square = 42, + k_EControllerActionOrigin_PS4_LeftBumper = 43, + k_EControllerActionOrigin_PS4_RightBumper = 44, + k_EControllerActionOrigin_PS4_Options = 45, + k_EControllerActionOrigin_PS4_Share = 46, + k_EControllerActionOrigin_PS4_LeftPad_Touch = 47, + k_EControllerActionOrigin_PS4_LeftPad_Swipe = 48, + k_EControllerActionOrigin_PS4_LeftPad_Click = 49, + k_EControllerActionOrigin_PS4_LeftPad_DPadNorth = 50, + k_EControllerActionOrigin_PS4_LeftPad_DPadSouth = 51, + k_EControllerActionOrigin_PS4_LeftPad_DPadWest = 52, + k_EControllerActionOrigin_PS4_LeftPad_DPadEast = 53, + k_EControllerActionOrigin_PS4_RightPad_Touch = 54, + k_EControllerActionOrigin_PS4_RightPad_Swipe = 55, + k_EControllerActionOrigin_PS4_RightPad_Click = 56, + k_EControllerActionOrigin_PS4_RightPad_DPadNorth = 57, + k_EControllerActionOrigin_PS4_RightPad_DPadSouth = 58, + k_EControllerActionOrigin_PS4_RightPad_DPadWest = 59, + k_EControllerActionOrigin_PS4_RightPad_DPadEast = 60, + k_EControllerActionOrigin_PS4_CenterPad_Touch = 61, + k_EControllerActionOrigin_PS4_CenterPad_Swipe = 62, + k_EControllerActionOrigin_PS4_CenterPad_Click = 63, + k_EControllerActionOrigin_PS4_CenterPad_DPadNorth = 64, + k_EControllerActionOrigin_PS4_CenterPad_DPadSouth = 65, + k_EControllerActionOrigin_PS4_CenterPad_DPadWest = 66, + k_EControllerActionOrigin_PS4_CenterPad_DPadEast = 67, + k_EControllerActionOrigin_PS4_LeftTrigger_Pull = 68, + k_EControllerActionOrigin_PS4_LeftTrigger_Click = 69, + k_EControllerActionOrigin_PS4_RightTrigger_Pull = 70, + k_EControllerActionOrigin_PS4_RightTrigger_Click = 71, + k_EControllerActionOrigin_PS4_LeftStick_Move = 72, + k_EControllerActionOrigin_PS4_LeftStick_Click = 73, + k_EControllerActionOrigin_PS4_LeftStick_DPadNorth = 74, + k_EControllerActionOrigin_PS4_LeftStick_DPadSouth = 75, + k_EControllerActionOrigin_PS4_LeftStick_DPadWest = 76, + k_EControllerActionOrigin_PS4_LeftStick_DPadEast = 77, + k_EControllerActionOrigin_PS4_RightStick_Move = 78, + k_EControllerActionOrigin_PS4_RightStick_Click = 79, + k_EControllerActionOrigin_PS4_RightStick_DPadNorth = 80, + k_EControllerActionOrigin_PS4_RightStick_DPadSouth = 81, + k_EControllerActionOrigin_PS4_RightStick_DPadWest = 82, + k_EControllerActionOrigin_PS4_RightStick_DPadEast = 83, + k_EControllerActionOrigin_PS4_DPad_North = 84, + k_EControllerActionOrigin_PS4_DPad_South = 85, + k_EControllerActionOrigin_PS4_DPad_West = 86, + k_EControllerActionOrigin_PS4_DPad_East = 87, + k_EControllerActionOrigin_PS4_Gyro_Move = 88, + k_EControllerActionOrigin_PS4_Gyro_Pitch = 89, + k_EControllerActionOrigin_PS4_Gyro_Yaw = 90, + k_EControllerActionOrigin_PS4_Gyro_Roll = 91, + k_EControllerActionOrigin_XBoxOne_A = 92, + k_EControllerActionOrigin_XBoxOne_B = 93, + k_EControllerActionOrigin_XBoxOne_X = 94, + k_EControllerActionOrigin_XBoxOne_Y = 95, + k_EControllerActionOrigin_XBoxOne_LeftBumper = 96, + k_EControllerActionOrigin_XBoxOne_RightBumper = 97, + k_EControllerActionOrigin_XBoxOne_Menu = 98, + k_EControllerActionOrigin_XBoxOne_View = 99, + k_EControllerActionOrigin_XBoxOne_LeftTrigger_Pull = 100, + k_EControllerActionOrigin_XBoxOne_LeftTrigger_Click = 101, + k_EControllerActionOrigin_XBoxOne_RightTrigger_Pull = 102, + k_EControllerActionOrigin_XBoxOne_RightTrigger_Click = 103, + k_EControllerActionOrigin_XBoxOne_LeftStick_Move = 104, + k_EControllerActionOrigin_XBoxOne_LeftStick_Click = 105, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadNorth = 106, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadSouth = 107, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadWest = 108, + k_EControllerActionOrigin_XBoxOne_LeftStick_DPadEast = 109, + k_EControllerActionOrigin_XBoxOne_RightStick_Move = 110, + k_EControllerActionOrigin_XBoxOne_RightStick_Click = 111, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadNorth = 112, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadSouth = 113, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadWest = 114, + k_EControllerActionOrigin_XBoxOne_RightStick_DPadEast = 115, + k_EControllerActionOrigin_XBoxOne_DPad_North = 116, + k_EControllerActionOrigin_XBoxOne_DPad_South = 117, + k_EControllerActionOrigin_XBoxOne_DPad_West = 118, + k_EControllerActionOrigin_XBoxOne_DPad_East = 119, + k_EControllerActionOrigin_XBox360_A = 120, + k_EControllerActionOrigin_XBox360_B = 121, + k_EControllerActionOrigin_XBox360_X = 122, + k_EControllerActionOrigin_XBox360_Y = 123, + k_EControllerActionOrigin_XBox360_LeftBumper = 124, + k_EControllerActionOrigin_XBox360_RightBumper = 125, + k_EControllerActionOrigin_XBox360_Start = 126, + k_EControllerActionOrigin_XBox360_Back = 127, + k_EControllerActionOrigin_XBox360_LeftTrigger_Pull = 128, + k_EControllerActionOrigin_XBox360_LeftTrigger_Click = 129, + k_EControllerActionOrigin_XBox360_RightTrigger_Pull = 130, + k_EControllerActionOrigin_XBox360_RightTrigger_Click = 131, + k_EControllerActionOrigin_XBox360_LeftStick_Move = 132, + k_EControllerActionOrigin_XBox360_LeftStick_Click = 133, + k_EControllerActionOrigin_XBox360_LeftStick_DPadNorth = 134, + k_EControllerActionOrigin_XBox360_LeftStick_DPadSouth = 135, + k_EControllerActionOrigin_XBox360_LeftStick_DPadWest = 136, + k_EControllerActionOrigin_XBox360_LeftStick_DPadEast = 137, + k_EControllerActionOrigin_XBox360_RightStick_Move = 138, + k_EControllerActionOrigin_XBox360_RightStick_Click = 139, + k_EControllerActionOrigin_XBox360_RightStick_DPadNorth = 140, + k_EControllerActionOrigin_XBox360_RightStick_DPadSouth = 141, + k_EControllerActionOrigin_XBox360_RightStick_DPadWest = 142, + k_EControllerActionOrigin_XBox360_RightStick_DPadEast = 143, + k_EControllerActionOrigin_XBox360_DPad_North = 144, + k_EControllerActionOrigin_XBox360_DPad_South = 145, + k_EControllerActionOrigin_XBox360_DPad_West = 146, + k_EControllerActionOrigin_XBox360_DPad_East = 147, + k_EControllerActionOrigin_SteamV2_A = 148, + k_EControllerActionOrigin_SteamV2_B = 149, + k_EControllerActionOrigin_SteamV2_X = 150, + k_EControllerActionOrigin_SteamV2_Y = 151, + k_EControllerActionOrigin_SteamV2_LeftBumper = 152, + k_EControllerActionOrigin_SteamV2_RightBumper = 153, + k_EControllerActionOrigin_SteamV2_LeftGrip_Lower = 154, + k_EControllerActionOrigin_SteamV2_LeftGrip_Upper = 155, + k_EControllerActionOrigin_SteamV2_RightGrip_Lower = 156, + k_EControllerActionOrigin_SteamV2_RightGrip_Upper = 157, + k_EControllerActionOrigin_SteamV2_LeftBumper_Pressure = 158, + k_EControllerActionOrigin_SteamV2_RightBumper_Pressure = 159, + k_EControllerActionOrigin_SteamV2_LeftGrip_Pressure = 160, + k_EControllerActionOrigin_SteamV2_RightGrip_Pressure = 161, + k_EControllerActionOrigin_SteamV2_LeftGrip_Upper_Pressure = 162, + k_EControllerActionOrigin_SteamV2_RightGrip_Upper_Pressure = 163, + k_EControllerActionOrigin_SteamV2_Start = 164, + k_EControllerActionOrigin_SteamV2_Back = 165, + k_EControllerActionOrigin_SteamV2_LeftPad_Touch = 166, + k_EControllerActionOrigin_SteamV2_LeftPad_Swipe = 167, + k_EControllerActionOrigin_SteamV2_LeftPad_Click = 168, + k_EControllerActionOrigin_SteamV2_LeftPad_Pressure = 169, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadNorth = 170, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadSouth = 171, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadWest = 172, + k_EControllerActionOrigin_SteamV2_LeftPad_DPadEast = 173, + k_EControllerActionOrigin_SteamV2_RightPad_Touch = 174, + k_EControllerActionOrigin_SteamV2_RightPad_Swipe = 175, + k_EControllerActionOrigin_SteamV2_RightPad_Click = 176, + k_EControllerActionOrigin_SteamV2_RightPad_Pressure = 177, + k_EControllerActionOrigin_SteamV2_RightPad_DPadNorth = 178, + k_EControllerActionOrigin_SteamV2_RightPad_DPadSouth = 179, + k_EControllerActionOrigin_SteamV2_RightPad_DPadWest = 180, + k_EControllerActionOrigin_SteamV2_RightPad_DPadEast = 181, + k_EControllerActionOrigin_SteamV2_LeftTrigger_Pull = 182, + k_EControllerActionOrigin_SteamV2_LeftTrigger_Click = 183, + k_EControllerActionOrigin_SteamV2_RightTrigger_Pull = 184, + k_EControllerActionOrigin_SteamV2_RightTrigger_Click = 185, + k_EControllerActionOrigin_SteamV2_LeftStick_Move = 186, + k_EControllerActionOrigin_SteamV2_LeftStick_Click = 187, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadNorth = 188, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadSouth = 189, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadWest = 190, + k_EControllerActionOrigin_SteamV2_LeftStick_DPadEast = 191, + k_EControllerActionOrigin_SteamV2_Gyro_Move = 192, + k_EControllerActionOrigin_SteamV2_Gyro_Pitch = 193, + k_EControllerActionOrigin_SteamV2_Gyro_Yaw = 194, + k_EControllerActionOrigin_SteamV2_Gyro_Roll = 195, + k_EControllerActionOrigin_Switch_A = 196, + k_EControllerActionOrigin_Switch_B = 197, + k_EControllerActionOrigin_Switch_X = 198, + k_EControllerActionOrigin_Switch_Y = 199, + k_EControllerActionOrigin_Switch_LeftBumper = 200, + k_EControllerActionOrigin_Switch_RightBumper = 201, + k_EControllerActionOrigin_Switch_Plus = 202, + k_EControllerActionOrigin_Switch_Minus = 203, + k_EControllerActionOrigin_Switch_Capture = 204, + k_EControllerActionOrigin_Switch_LeftTrigger_Pull = 205, + k_EControllerActionOrigin_Switch_LeftTrigger_Click = 206, + k_EControllerActionOrigin_Switch_RightTrigger_Pull = 207, + k_EControllerActionOrigin_Switch_RightTrigger_Click = 208, + k_EControllerActionOrigin_Switch_LeftStick_Move = 209, + k_EControllerActionOrigin_Switch_LeftStick_Click = 210, + k_EControllerActionOrigin_Switch_LeftStick_DPadNorth = 211, + k_EControllerActionOrigin_Switch_LeftStick_DPadSouth = 212, + k_EControllerActionOrigin_Switch_LeftStick_DPadWest = 213, + k_EControllerActionOrigin_Switch_LeftStick_DPadEast = 214, + k_EControllerActionOrigin_Switch_RightStick_Move = 215, + k_EControllerActionOrigin_Switch_RightStick_Click = 216, + k_EControllerActionOrigin_Switch_RightStick_DPadNorth = 217, + k_EControllerActionOrigin_Switch_RightStick_DPadSouth = 218, + k_EControllerActionOrigin_Switch_RightStick_DPadWest = 219, + k_EControllerActionOrigin_Switch_RightStick_DPadEast = 220, + k_EControllerActionOrigin_Switch_DPad_North = 221, + k_EControllerActionOrigin_Switch_DPad_South = 222, + k_EControllerActionOrigin_Switch_DPad_West = 223, + k_EControllerActionOrigin_Switch_DPad_East = 224, + k_EControllerActionOrigin_Switch_ProGyro_Move = 225, + k_EControllerActionOrigin_Switch_ProGyro_Pitch = 226, + k_EControllerActionOrigin_Switch_ProGyro_Yaw = 227, + k_EControllerActionOrigin_Switch_ProGyro_Roll = 228, + k_EControllerActionOrigin_Switch_RightGyro_Move = 229, + k_EControllerActionOrigin_Switch_RightGyro_Pitch = 230, + k_EControllerActionOrigin_Switch_RightGyro_Yaw = 231, + k_EControllerActionOrigin_Switch_RightGyro_Roll = 232, + k_EControllerActionOrigin_Switch_LeftGyro_Move = 233, + k_EControllerActionOrigin_Switch_LeftGyro_Pitch = 234, + k_EControllerActionOrigin_Switch_LeftGyro_Yaw = 235, + k_EControllerActionOrigin_Switch_LeftGyro_Roll = 236, + k_EControllerActionOrigin_Switch_LeftGrip_Lower = 237, + k_EControllerActionOrigin_Switch_LeftGrip_Upper = 238, + k_EControllerActionOrigin_Switch_RightGrip_Lower = 239, + k_EControllerActionOrigin_Switch_RightGrip_Upper = 240, + k_EControllerActionOrigin_PS4_DPad_Move = 241, + k_EControllerActionOrigin_XBoxOne_DPad_Move = 242, + k_EControllerActionOrigin_XBox360_DPad_Move = 243, + k_EControllerActionOrigin_Switch_DPad_Move = 244, + k_EControllerActionOrigin_Count = 245, + k_EControllerActionOrigin_MaximumPossibleValue = 32767, +} +public enum ESteamControllerLEDFlag +{ + k_ESteamControllerLEDFlag_SetColor = 0, + k_ESteamControllerLEDFlag_RestoreUserDefault = 1, +} +public enum EUGCMatchingUGCType +{ + k_EUGCMatchingUGCType_Items = 0, + k_EUGCMatchingUGCType_Items_Mtx = 1, + k_EUGCMatchingUGCType_Items_ReadyToUse = 2, + k_EUGCMatchingUGCType_Collections = 3, + k_EUGCMatchingUGCType_Artwork = 4, + k_EUGCMatchingUGCType_Videos = 5, + k_EUGCMatchingUGCType_Screenshots = 6, + k_EUGCMatchingUGCType_AllGuides = 7, + k_EUGCMatchingUGCType_WebGuides = 8, + k_EUGCMatchingUGCType_IntegratedGuides = 9, + k_EUGCMatchingUGCType_UsableInGame = 10, + k_EUGCMatchingUGCType_ControllerBindings = 11, + k_EUGCMatchingUGCType_GameManagedItems = 12, + k_EUGCMatchingUGCType_All = -1, +} +public enum EUserUGCList +{ + k_EUserUGCList_Published = 0, + k_EUserUGCList_VotedOn = 1, + k_EUserUGCList_VotedUp = 2, + k_EUserUGCList_VotedDown = 3, + k_EUserUGCList_WillVoteLater = 4, + k_EUserUGCList_Favorited = 5, + k_EUserUGCList_Subscribed = 6, + k_EUserUGCList_UsedOrPlayed = 7, + k_EUserUGCList_Followed = 8, +} +public enum EUserUGCListSortOrder +{ + k_EUserUGCListSortOrder_CreationOrderDesc = 0, + k_EUserUGCListSortOrder_CreationOrderAsc = 1, + k_EUserUGCListSortOrder_TitleAsc = 2, + k_EUserUGCListSortOrder_LastUpdatedDesc = 3, + k_EUserUGCListSortOrder_SubscriptionDateDesc = 4, + k_EUserUGCListSortOrder_VoteScoreDesc = 5, + k_EUserUGCListSortOrder_ForModeration = 6, +} +public enum EUGCQuery +{ + k_EUGCQuery_RankedByVote = 0, + k_EUGCQuery_RankedByPublicationDate = 1, + k_EUGCQuery_AcceptedForGameRankedByAcceptanceDate = 2, + k_EUGCQuery_RankedByTrend = 3, + k_EUGCQuery_FavoritedByFriendsRankedByPublicationDate = 4, + k_EUGCQuery_CreatedByFriendsRankedByPublicationDate = 5, + k_EUGCQuery_RankedByNumTimesReported = 6, + k_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate = 7, + k_EUGCQuery_NotYetRated = 8, + k_EUGCQuery_RankedByTotalVotesAsc = 9, + k_EUGCQuery_RankedByVotesUp = 10, + k_EUGCQuery_RankedByTextSearch = 11, + k_EUGCQuery_RankedByTotalUniqueSubscriptions = 12, + k_EUGCQuery_RankedByPlaytimeTrend = 13, + k_EUGCQuery_RankedByTotalPlaytime = 14, + k_EUGCQuery_RankedByAveragePlaytimeTrend = 15, + k_EUGCQuery_RankedByLifetimeAveragePlaytime = 16, + k_EUGCQuery_RankedByPlaytimeSessionsTrend = 17, + k_EUGCQuery_RankedByLifetimePlaytimeSessions = 18, +} +public enum EItemUpdateStatus +{ + k_EItemUpdateStatusInvalid = 0, + k_EItemUpdateStatusPreparingConfig = 1, + k_EItemUpdateStatusPreparingContent = 2, + k_EItemUpdateStatusUploadingContent = 3, + k_EItemUpdateStatusUploadingPreviewFile = 4, + k_EItemUpdateStatusCommittingChanges = 5, +} +public enum EItemState +{ + k_EItemStateNone = 0, + k_EItemStateSubscribed = 1, + k_EItemStateLegacyItem = 2, + k_EItemStateInstalled = 4, + k_EItemStateNeedsUpdate = 8, + k_EItemStateDownloading = 16, + k_EItemStateDownloadPending = 32, +} +public enum EItemStatistic +{ + k_EItemStatistic_NumSubscriptions = 0, + k_EItemStatistic_NumFavorites = 1, + k_EItemStatistic_NumFollowers = 2, + k_EItemStatistic_NumUniqueSubscriptions = 3, + k_EItemStatistic_NumUniqueFavorites = 4, + k_EItemStatistic_NumUniqueFollowers = 5, + k_EItemStatistic_NumUniqueWebsiteViews = 6, + k_EItemStatistic_ReportScore = 7, + k_EItemStatistic_NumSecondsPlayed = 8, + k_EItemStatistic_NumPlaytimeSessions = 9, + k_EItemStatistic_NumComments = 10, + k_EItemStatistic_NumSecondsPlayedDuringTimePeriod = 11, + k_EItemStatistic_NumPlaytimeSessionsDuringTimePeriod = 12, +} +public enum EItemPreviewType +{ + k_EItemPreviewType_Image = 0, + k_EItemPreviewType_YouTubeVideo = 1, + k_EItemPreviewType_Sketchfab = 2, + k_EItemPreviewType_EnvironmentMap_HorizontalCross = 3, + k_EItemPreviewType_EnvironmentMap_LatLong = 4, + k_EItemPreviewType_ReservedMax = 255, +} +public enum EHTMLMouseButton +{ + eHTMLMouseButton_Left = 0, + eHTMLMouseButton_Right = 1, + eHTMLMouseButton_Middle = 2, +} +public enum EMouseCursor +{ + dc_user = 0, + dc_none = 1, + dc_arrow = 2, + dc_ibeam = 3, + dc_hourglass = 4, + dc_waitarrow = 5, + dc_crosshair = 6, + dc_up = 7, + dc_sizenw = 8, + dc_sizese = 9, + dc_sizene = 10, + dc_sizesw = 11, + dc_sizew = 12, + dc_sizee = 13, + dc_sizen = 14, + dc_sizes = 15, + dc_sizewe = 16, + dc_sizens = 17, + dc_sizeall = 18, + dc_no = 19, + dc_hand = 20, + dc_blank = 21, + dc_middle_pan = 22, + dc_north_pan = 23, + dc_north_east_pan = 24, + dc_east_pan = 25, + dc_south_east_pan = 26, + dc_south_pan = 27, + dc_south_west_pan = 28, + dc_west_pan = 29, + dc_north_west_pan = 30, + dc_alias = 31, + dc_cell = 32, + dc_colresize = 33, + dc_copycur = 34, + dc_verticaltext = 35, + dc_rowresize = 36, + dc_zoomin = 37, + dc_zoomout = 38, + dc_help = 39, + dc_custom = 40, + dc_last = 41, +} +public enum EHTMLKeyModifiers +{ + k_eHTMLKeyModifier_None = 0, + k_eHTMLKeyModifier_AltDown = 1, + k_eHTMLKeyModifier_CtrlDown = 2, + k_eHTMLKeyModifier_ShiftDown = 4, +} +public enum ESteamItemFlags +{ + k_ESteamItemNoTrade = 1, + k_ESteamItemRemoved = 256, + k_ESteamItemConsumed = 512, +} +public enum ESteamTVRegionBehavior +{ + k_ESteamVideoRegionBehaviorInvalid = -1, + k_ESteamVideoRegionBehaviorHover = 0, + k_ESteamVideoRegionBehaviorClickPopup = 1, + k_ESteamVideoRegionBehaviorClickSurroundingRegion = 2, +} +public enum EParentalFeature +{ + k_EFeatureInvalid = 0, + k_EFeatureStore = 1, + k_EFeatureCommunity = 2, + k_EFeatureProfile = 3, + k_EFeatureFriends = 4, + k_EFeatureNews = 5, + k_EFeatureTrading = 6, + k_EFeatureSettings = 7, + k_EFeatureConsole = 8, + k_EFeatureBrowser = 9, + k_EFeatureParentalSetup = 10, + k_EFeatureLibrary = 11, + k_EFeatureTest = 12, + k_EFeatureMax = 13, +} +public enum ESteamDeviceFormFactor +{ + k_ESteamDeviceFormFactorUnknown = 0, + k_ESteamDeviceFormFactorPhone = 1, + k_ESteamDeviceFormFactorTablet = 2, + k_ESteamDeviceFormFactorComputer = 3, + k_ESteamDeviceFormFactorTV = 4, +} +[StructLayout(LayoutKind.Sequential)] public struct CSteamID +{ + public SteamID_t m_steamid; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamID_t +{ + public SteamIDComponent_t m_comp; + public ulong m_unAll64Bits; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamIDComponent_t +{ + public uint m_unAccountID; + public uint m_unAccountInstance; + public uint m_EAccountType; + public EUniverse m_EUniverse; +} +[StructLayout(LayoutKind.Sequential)] public struct GameID_t +{ + public uint m_nAppID; + public uint m_nType; + public uint m_nModID; +} +[StructLayout(LayoutKind.Sequential)] public struct ValvePackingSentinel_t +{ + public uint m_u32; + public ulong m_u64; + public char m_u16; + public double m_d; +} +[StructLayout(LayoutKind.Sequential)] public struct CCallbackBase +{ + public byte m_nCallbackFlags; + public int m_iCallback; +} +[StructLayout(LayoutKind.Sequential)] public struct CCallResult +{ + public ulong m_hAPICall; + public IntPtr m_pObj; // T * + public IntPtr m_Func; +} +[StructLayout(LayoutKind.Sequential)] public struct CCallback +{ + public IntPtr m_pObj; // T * + public IntPtr m_Func; +} +[StructLayout(LayoutKind.Sequential)] public struct CSteamAPIContext +{ + public IntPtr m_pSteamClient; // class ISteamClient * + public IntPtr m_pSteamUser; // class ISteamUser * + public IntPtr m_pSteamFriends; // class ISteamFriends * + public IntPtr m_pSteamUtils; // class ISteamUtils * + public IntPtr m_pSteamMatchmaking; // class ISteamMatchmaking * + public IntPtr m_pSteamGameSearch; // class ISteamGameSearch * + public IntPtr m_pSteamUserStats; // class ISteamUserStats * + public IntPtr m_pSteamApps; // class ISteamApps * + public IntPtr m_pSteamMatchmakingServers; // class ISteamMatchmakingServers * + public IntPtr m_pSteamNetworking; // class ISteamNetworking * + public IntPtr m_pSteamRemoteStorage; // class ISteamRemoteStorage * + public IntPtr m_pSteamScreenshots; // class ISteamScreenshots * + public IntPtr m_pSteamHTTP; // class ISteamHTTP * + public IntPtr m_pController; // class ISteamController * + public IntPtr m_pSteamUGC; // class ISteamUGC * + public IntPtr m_pSteamAppList; // class ISteamAppList * + public IntPtr m_pSteamMusic; // class ISteamMusic * + public IntPtr m_pSteamMusicRemote; // class ISteamMusicRemote * + public IntPtr m_pSteamHTMLSurface; // class ISteamHTMLSurface * + public IntPtr m_pSteamInventory; // class ISteamInventory * + public IntPtr m_pSteamVideo; // class ISteamVideo * + public IntPtr m_pSteamTV; // class ISteamTV * + public IntPtr m_pSteamParentalSettings; // class ISteamParentalSettings * + public IntPtr m_pSteamInput; // class ISteamInput * +} +[StructLayout(LayoutKind.Sequential)] public struct CSteamGameServerAPIContext +{ + public IntPtr m_pSteamClient; // class ISteamClient * + public IntPtr m_pSteamGameServer; // class ISteamGameServer * + public IntPtr m_pSteamGameServerUtils; // class ISteamUtils * + public IntPtr m_pSteamGameServerNetworking; // class ISteamNetworking * + public IntPtr m_pSteamGameServerStats; // class ISteamGameServerStats * + public IntPtr m_pSteamHTTP; // class ISteamHTTP * + public IntPtr m_pSteamInventory; // class ISteamInventory * + public IntPtr m_pSteamUGC; // class ISteamUGC * + public IntPtr m_pSteamApps; // class ISteamApps * +} +[StructLayout(LayoutKind.Sequential)] public struct CallbackMsg_t +{ + public uint m_hSteamUser; + public int m_iCallback; + public IntPtr m_pubParam; // uint8 * + public int m_cubParam; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamServerConnectFailure_t +{ + public EResult m_eResult; + [MarshalAs(UnmanagedType.I1)] + public bool m_bStillRetrying; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamServersDisconnected_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct ClientGameServerDeny_t +{ + public uint m_uAppID; + public uint m_unGameServerIP; + public char m_usGameServerPort; + public char m_bSecure; + public uint m_uReason; +} +[StructLayout(LayoutKind.Sequential)] public struct ValidateAuthTicketResponse_t +{ + public ulong m_SteamID; + public EAuthSessionResponse m_eAuthSessionResponse; + public ulong m_OwnerSteamID; +} +[StructLayout(LayoutKind.Sequential)] public struct MicroTxnAuthorizationResponse_t +{ + public uint m_unAppID; + public ulong m_ulOrderID; + public byte m_bAuthorized; +} +[StructLayout(LayoutKind.Sequential)] public struct EncryptedAppTicketResponse_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct GetAuthSessionTicketResponse_t +{ + public uint m_hAuthTicket; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct GameWebCallback_t +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_szURL; //char[256] +} +[StructLayout(LayoutKind.Sequential)] public struct StoreAuthURLResponse_t +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public string m_szURL; //char[512] +} +[StructLayout(LayoutKind.Sequential)] public struct MarketEligibilityResponse_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bAllowed; + public EMarketNotAllowedReasonFlags m_eNotAllowedReason; + public ulong m_rtAllowedAtTime; + public int m_cdaySteamGuardRequiredDays; + public int m_cdayNewDeviceCooldown; +} +[StructLayout(LayoutKind.Sequential)] public struct DurationControl_t +{ + public EResult m_eResult; + public uint m_appid; + [MarshalAs(UnmanagedType.I1)] + public bool m_bApplicable; + public int m_csecsLast5h; + public EDurationControlProgress m_progress; + public EDurationControlNotification m_notification; +} +[StructLayout(LayoutKind.Sequential)] public struct FriendGameInfo_t +{ + public ulong m_gameID; + public uint m_unGameIP; + public char m_usGamePort; + public char m_usQueryPort; + public ulong m_steamIDLobby; +} +[StructLayout(LayoutKind.Sequential)] public struct FriendSessionStateInfo_t +{ + public uint m_uiOnlineSessionInstances; + public byte m_uiPublishedToFriendsSessionInstance; +} +[StructLayout(LayoutKind.Sequential)] public struct PersonaStateChange_t +{ + public ulong m_ulSteamID; + public int m_nChangeFlags; +} +[StructLayout(LayoutKind.Sequential)] public struct GameOverlayActivated_t +{ + public byte m_bActive; +} +[StructLayout(LayoutKind.Sequential)] public struct GameServerChangeRequested_t +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string m_rgchServer; //char[64] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string m_rgchPassword; //char[64] +} +[StructLayout(LayoutKind.Sequential)] public struct GameLobbyJoinRequested_t +{ + public ulong m_steamIDLobby; + public ulong m_steamIDFriend; +} +[StructLayout(LayoutKind.Sequential)] public struct AvatarImageLoaded_t +{ + public ulong m_steamID; + public int m_iImage; + public int m_iWide; + public int m_iTall; +} +[StructLayout(LayoutKind.Sequential)] public struct ClanOfficerListResponse_t +{ + public ulong m_steamIDClan; + public int m_cOfficers; + public byte m_bSuccess; +} +[StructLayout(LayoutKind.Sequential)] public struct FriendRichPresenceUpdate_t +{ + public ulong m_steamIDFriend; + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct GameRichPresenceJoinRequested_t +{ + public ulong m_steamIDFriend; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_rgchConnect; //char[256] +} +[StructLayout(LayoutKind.Sequential)] public struct GameConnectedClanChatMsg_t +{ + public ulong m_steamIDClanChat; + public ulong m_steamIDUser; + public int m_iMessageID; +} +[StructLayout(LayoutKind.Sequential)] public struct GameConnectedChatJoin_t +{ + public ulong m_steamIDClanChat; + public ulong m_steamIDUser; +} +[StructLayout(LayoutKind.Sequential)] public struct GameConnectedChatLeave_t +{ + public ulong m_steamIDClanChat; + public ulong m_steamIDUser; + [MarshalAs(UnmanagedType.I1)] + public bool m_bKicked; + [MarshalAs(UnmanagedType.I1)] + public bool m_bDropped; +} +[StructLayout(LayoutKind.Sequential)] public struct DownloadClanActivityCountsResult_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bSuccess; +} +[StructLayout(LayoutKind.Sequential)] public struct JoinClanChatRoomCompletionResult_t +{ + public ulong m_steamIDClanChat; + public EChatRoomEnterResponse m_eChatRoomEnterResponse; +} +[StructLayout(LayoutKind.Sequential)] public struct GameConnectedFriendChatMsg_t +{ + public ulong m_steamIDUser; + public int m_iMessageID; +} +[StructLayout(LayoutKind.Sequential)] public struct FriendsGetFollowerCount_t +{ + public EResult m_eResult; + public ulong m_steamID; + public int m_nCount; +} +[StructLayout(LayoutKind.Sequential)] public struct FriendsIsFollowing_t +{ + public EResult m_eResult; + public ulong m_steamID; + [MarshalAs(UnmanagedType.I1)] + public bool m_bIsFollowing; +} +[StructLayout(LayoutKind.Sequential)] public struct FriendsEnumerateFollowingList_t +{ + public EResult m_eResult; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U8)] + public CSteamID[] m_rgSteamID; //CSteamID[50] + public int m_nResultsReturned; + public int m_nTotalResultCount; +} +[StructLayout(LayoutKind.Sequential)] public struct SetPersonaNameResponse_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bSuccess; + [MarshalAs(UnmanagedType.I1)] + public bool m_bLocalSuccess; + public EResult m_result; +} +[StructLayout(LayoutKind.Sequential)] public struct LowBatteryPower_t +{ + public byte m_nMinutesBatteryLeft; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamAPICallCompleted_t +{ + public ulong m_hAsyncCall; + public int m_iCallback; + public uint m_cubParam; +} +[StructLayout(LayoutKind.Sequential)] public struct CheckFileSignature_t +{ + public ECheckFileSignature m_eCheckFileSignature; +} +[StructLayout(LayoutKind.Sequential)] public struct GamepadTextInputDismissed_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bSubmitted; + public uint m_unSubmittedText; +} +[StructLayout(LayoutKind.Sequential)] public struct MatchMakingKeyValuePair_t +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_szKey; //char[256] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_szValue; //char[256] +} +[StructLayout(LayoutKind.Sequential)] public struct servernetadr_t +{ + public char m_usConnectionPort; + public char m_usQueryPort; + public uint m_unIP; +} +[StructLayout(LayoutKind.Sequential)] public struct gameserveritem_t +{ + public servernetadr_t m_NetAdr; + public int m_nPing; + [MarshalAs(UnmanagedType.I1)] + public bool m_bHadSuccessfulResponse; + [MarshalAs(UnmanagedType.I1)] + public bool m_bDoNotRefresh; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string m_szGameDir; //char[32] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string m_szMap; //char[32] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string m_szGameDescription; //char[64] + public uint m_nAppID; + public int m_nPlayers; + public int m_nMaxPlayers; + public int m_nBotPlayers; + [MarshalAs(UnmanagedType.I1)] + public bool m_bPassword; + [MarshalAs(UnmanagedType.I1)] + public bool m_bSecure; + public uint m_ulTimeLastPlayed; + public int m_nServerVersion; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string m_szServerName; //char[64] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string m_szGameTags; //char[128] + public ulong m_steamID; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamPartyBeaconLocation_t +{ + public ESteamPartyBeaconLocationType m_eType; + public ulong m_ulLocationID; +} +[StructLayout(LayoutKind.Sequential)] public struct FavoritesListChanged_t +{ + public uint m_nIP; + public uint m_nQueryPort; + public uint m_nConnPort; + public uint m_nAppID; + public uint m_nFlags; + [MarshalAs(UnmanagedType.I1)] + public bool m_bAdd; + public uint m_unAccountId; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyInvite_t +{ + public ulong m_ulSteamIDUser; + public ulong m_ulSteamIDLobby; + public ulong m_ulGameID; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyEnter_t +{ + public ulong m_ulSteamIDLobby; + public uint m_rgfChatPermissions; + [MarshalAs(UnmanagedType.I1)] + public bool m_bLocked; + public uint m_EChatRoomEnterResponse; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyDataUpdate_t +{ + public ulong m_ulSteamIDLobby; + public ulong m_ulSteamIDMember; + public byte m_bSuccess; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyChatUpdate_t +{ + public ulong m_ulSteamIDLobby; + public ulong m_ulSteamIDUserChanged; + public ulong m_ulSteamIDMakingChange; + public uint m_rgfChatMemberStateChange; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyChatMsg_t +{ + public ulong m_ulSteamIDLobby; + public ulong m_ulSteamIDUser; + public byte m_eChatEntryType; + public uint m_iChatID; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyGameCreated_t +{ + public ulong m_ulSteamIDLobby; + public ulong m_ulSteamIDGameServer; + public uint m_unIP; + public char m_usPort; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyMatchList_t +{ + public uint m_nLobbiesMatching; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyKicked_t +{ + public ulong m_ulSteamIDLobby; + public ulong m_ulSteamIDAdmin; + public byte m_bKickedDueToDisconnect; +} +[StructLayout(LayoutKind.Sequential)] public struct LobbyCreated_t +{ + public EResult m_eResult; + public ulong m_ulSteamIDLobby; +} +[StructLayout(LayoutKind.Sequential)] public struct PSNGameBootInviteResult_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bGameBootInviteExists; + public ulong m_steamIDLobby; +} +[StructLayout(LayoutKind.Sequential)] public struct FavoritesListAccountsUpdated_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct SearchForGameProgressCallback_t +{ + public ulong m_ullSearchID; + public EResult m_eResult; + public ulong m_lobbyID; + public ulong m_steamIDEndedSearch; + public int m_nSecondsRemainingEstimate; + public int m_cPlayersSearching; +} +[StructLayout(LayoutKind.Sequential)] public struct SearchForGameResultCallback_t +{ + public ulong m_ullSearchID; + public EResult m_eResult; + public int m_nCountPlayersInGame; + public int m_nCountAcceptedGame; + public ulong m_steamIDHost; + [MarshalAs(UnmanagedType.I1)] + public bool m_bFinalCallback; +} +[StructLayout(LayoutKind.Sequential)] public struct RequestPlayersForGameProgressCallback_t +{ + public EResult m_eResult; + public ulong m_ullSearchID; +} +[StructLayout(LayoutKind.Sequential)] public struct RequestPlayersForGameResultCallback_t +{ + public EResult m_eResult; + public ulong m_ullSearchID; + public ulong m_SteamIDPlayerFound; + public ulong m_SteamIDLobby; + public PlayerAcceptState_t m_ePlayerAcceptState; + public int m_nPlayerIndex; + public int m_nTotalPlayersFound; + public int m_nTotalPlayersAcceptedGame; + public int m_nSuggestedTeamIndex; + public ulong m_ullUniqueGameID; +} +[StructLayout(LayoutKind.Sequential)] public struct RequestPlayersForGameFinalResultCallback_t +{ + public EResult m_eResult; + public ulong m_ullSearchID; + public ulong m_ullUniqueGameID; +} +[StructLayout(LayoutKind.Sequential)] public struct SubmitPlayerResultResultCallback_t +{ + public EResult m_eResult; + public ulong ullUniqueGameID; + public ulong steamIDPlayer; +} +[StructLayout(LayoutKind.Sequential)] public struct EndGameResultCallback_t +{ + public EResult m_eResult; + public ulong ullUniqueGameID; +} +[StructLayout(LayoutKind.Sequential)] public struct JoinPartyCallback_t +{ + public EResult m_eResult; + public ulong m_ulBeaconID; + public ulong m_SteamIDBeaconOwner; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_rgchConnectString; //char[256] +} +[StructLayout(LayoutKind.Sequential)] public struct CreateBeaconCallback_t +{ + public EResult m_eResult; + public ulong m_ulBeaconID; +} +[StructLayout(LayoutKind.Sequential)] public struct ReservationNotificationCallback_t +{ + public ulong m_ulBeaconID; + public ulong m_steamIDJoiner; +} +[StructLayout(LayoutKind.Sequential)] public struct ChangeNumOpenSlotsCallback_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamParamStringArray_t +{ + public IntPtr m_ppStrings; // const char ** + public int m_nNumStrings; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageAppSyncedClient_t +{ + public uint m_nAppID; + public EResult m_eResult; + public int m_unNumDownloads; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageAppSyncedServer_t +{ + public uint m_nAppID; + public EResult m_eResult; + public int m_unNumUploads; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageAppSyncProgress_t +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string m_rgchCurrentFile; //char[260] + public uint m_nAppID; + public uint m_uBytesTransferredThisChunk; + public double m_dAppPercentComplete; + [MarshalAs(UnmanagedType.I1)] + public bool m_bUploading; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageAppSyncStatusCheck_t +{ + public uint m_nAppID; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageFileShareResult_t +{ + public EResult m_eResult; + public ulong m_hFile; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string m_rgchFilename; //char[260] +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStoragePublishFileResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + [MarshalAs(UnmanagedType.I1)] + public bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageDeletePublishedFileResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageEnumerateUserPublishedFilesResult_t +{ + public EResult m_eResult; + public int m_nResultsReturned; + public int m_nTotalResultCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U8)] + public ulong[] m_rgPublishedFileId; //ulong[50] +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageSubscribePublishedFileResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageEnumerateUserSubscribedFilesResult_t +{ + public EResult m_eResult; + public int m_nResultsReturned; + public int m_nTotalResultCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U8)] + public ulong[] m_rgPublishedFileId; //ulong[50] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U4)] + public uint[] m_rgRTimeSubscribed; //uint[50] +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageUnsubscribePublishedFileResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageUpdatePublishedFileResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + [MarshalAs(UnmanagedType.I1)] + public bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageDownloadUGCResult_t +{ + public EResult m_eResult; + public ulong m_hFile; + public uint m_nAppID; + public int m_nSizeInBytes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string m_pchFileName; //char[260] + public ulong m_ulSteamIDOwner; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageGetPublishedFileDetailsResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public uint m_nCreatorAppID; + public uint m_nConsumerAppID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] + public string m_rgchTitle; //char[129] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8000)] + public string m_rgchDescription; //char[8000] + public ulong m_hFile; + public ulong m_hPreviewFile; + public ulong m_ulSteamIDOwner; + public uint m_rtimeCreated; + public uint m_rtimeUpdated; + public ERemoteStoragePublishedFileVisibility m_eVisibility; + [MarshalAs(UnmanagedType.I1)] + public bool m_bBanned; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1025)] + public string m_rgchTags; //char[1025] + [MarshalAs(UnmanagedType.I1)] + public bool m_bTagsTruncated; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string m_pchFileName; //char[260] + public int m_nFileSize; + public int m_nPreviewFileSize; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_rgchURL; //char[256] + public EWorkshopFileType m_eFileType; + [MarshalAs(UnmanagedType.I1)] + public bool m_bAcceptedForUse; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageEnumerateWorkshopFilesResult_t +{ + public EResult m_eResult; + public int m_nResultsReturned; + public int m_nTotalResultCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U8)] + public ulong[] m_rgPublishedFileId; //ulong[50] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.R4)] + public float[] m_rgScore; //float[50] + public uint m_nAppId; + public uint m_unStartIndex; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageGetPublishedItemVoteDetailsResult_t +{ + public EResult m_eResult; + public ulong m_unPublishedFileId; + public int m_nVotesFor; + public int m_nVotesAgainst; + public int m_nReports; + public float m_fScore; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStoragePublishedFileSubscribed_t +{ + public ulong m_nPublishedFileId; + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStoragePublishedFileUnsubscribed_t +{ + public ulong m_nPublishedFileId; + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStoragePublishedFileDeleted_t +{ + public ulong m_nPublishedFileId; + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageUpdateUserPublishedItemVoteResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageUserVoteDetails_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public EWorkshopVote m_eVote; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageEnumerateUserSharedWorkshopFilesResult_t +{ + public EResult m_eResult; + public int m_nResultsReturned; + public int m_nTotalResultCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U8)] + public ulong[] m_rgPublishedFileId; //ulong[50] +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageSetUserPublishedFileActionResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public EWorkshopFileAction m_eAction; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageEnumeratePublishedFilesByUserActionResult_t +{ + public EResult m_eResult; + public EWorkshopFileAction m_eAction; + public int m_nResultsReturned; + public int m_nTotalResultCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U8)] + public ulong[] m_rgPublishedFileId; //ulong[50] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50, ArraySubType = UnmanagedType.U4)] + public uint[] m_rgRTimeUpdated; //uint[50] +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStoragePublishFileProgress_t +{ + public double m_dPercentFile; + [MarshalAs(UnmanagedType.I1)] + public bool m_bPreview; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStoragePublishedFileUpdated_t +{ + public ulong m_nPublishedFileId; + public uint m_nAppID; + public ulong m_ulUnused; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageFileWriteAsyncComplete_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoteStorageFileReadAsyncComplete_t +{ + public ulong m_hFileReadAsync; + public EResult m_eResult; + public uint m_nOffset; + public uint m_cubRead; +} +[StructLayout(LayoutKind.Sequential)] public struct LeaderboardEntry_t +{ + public ulong m_steamIDUser; + public int m_nGlobalRank; + public int m_nScore; + public int m_cDetails; + public ulong m_hUGC; +} +[StructLayout(LayoutKind.Sequential)] public struct UserStatsReceived_t +{ + public ulong m_nGameID; + public EResult m_eResult; + public ulong m_steamIDUser; +} +[StructLayout(LayoutKind.Sequential)] public struct UserStatsStored_t +{ + public ulong m_nGameID; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct UserAchievementStored_t +{ + public ulong m_nGameID; + [MarshalAs(UnmanagedType.I1)] + public bool m_bGroupAchievement; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string m_rgchAchievementName; //char[128] + public uint m_nCurProgress; + public uint m_nMaxProgress; +} +[StructLayout(LayoutKind.Sequential)] public struct LeaderboardFindResult_t +{ + public ulong m_hSteamLeaderboard; + public byte m_bLeaderboardFound; +} +[StructLayout(LayoutKind.Sequential)] public struct LeaderboardScoresDownloaded_t +{ + public ulong m_hSteamLeaderboard; + public ulong m_hSteamLeaderboardEntries; + public int m_cEntryCount; +} +[StructLayout(LayoutKind.Sequential)] public struct LeaderboardScoreUploaded_t +{ + public byte m_bSuccess; + public ulong m_hSteamLeaderboard; + public int m_nScore; + public byte m_bScoreChanged; + public int m_nGlobalRankNew; + public int m_nGlobalRankPrevious; +} +[StructLayout(LayoutKind.Sequential)] public struct NumberOfCurrentPlayers_t +{ + public byte m_bSuccess; + public int m_cPlayers; +} +[StructLayout(LayoutKind.Sequential)] public struct UserStatsUnloaded_t +{ + public ulong m_steamIDUser; +} +[StructLayout(LayoutKind.Sequential)] public struct UserAchievementIconFetched_t +{ + public ulong m_nGameID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string m_rgchAchievementName; //char[128] + [MarshalAs(UnmanagedType.I1)] + public bool m_bAchieved; + public int m_nIconHandle; +} +[StructLayout(LayoutKind.Sequential)] public struct GlobalAchievementPercentagesReady_t +{ + public ulong m_nGameID; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct LeaderboardUGCSet_t +{ + public EResult m_eResult; + public ulong m_hSteamLeaderboard; +} +[StructLayout(LayoutKind.Sequential)] public struct PS3TrophiesInstalled_t +{ + public ulong m_nGameID; + public EResult m_eResult; + public ulong m_ulRequiredDiskSpace; +} +[StructLayout(LayoutKind.Sequential)] public struct GlobalStatsReceived_t +{ + public ulong m_nGameID; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct DlcInstalled_t +{ + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct RegisterActivationCodeResponse_t +{ + public ERegisterActivationCodeResult m_eResult; + public uint m_unPackageRegistered; +} +[StructLayout(LayoutKind.Sequential)] public struct AppProofOfPurchaseKeyResponse_t +{ + public EResult m_eResult; + public uint m_nAppID; + public uint m_cchKeyLength; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 240)] + public string m_rgchKey; //char[240] +} +[StructLayout(LayoutKind.Sequential)] public struct FileDetailsResult_t +{ + public EResult m_eResult; + public ulong m_ulFileSize; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20, ArraySubType = UnmanagedType.U1)] + public byte[] m_FileSHA; //byte[20] + public uint m_unFlags; +} +[StructLayout(LayoutKind.Sequential)] public struct P2PSessionState_t +{ + public byte m_bConnectionActive; + public byte m_bConnecting; + public byte m_eP2PSessionError; + public byte m_bUsingRelay; + public int m_nBytesQueuedForSend; + public int m_nPacketsQueuedForSend; + public uint m_nRemoteIP; + public char m_nRemotePort; +} +[StructLayout(LayoutKind.Sequential)] public struct P2PSessionRequest_t +{ + public ulong m_steamIDRemote; +} +[StructLayout(LayoutKind.Sequential)] public struct P2PSessionConnectFail_t +{ + public ulong m_steamIDRemote; + public byte m_eP2PSessionError; +} +[StructLayout(LayoutKind.Sequential)] public struct SocketStatusCallback_t +{ + public uint m_hSocket; + public uint m_hListenSocket; + public ulong m_steamIDRemote; + public int m_eSNetSocketState; +} +[StructLayout(LayoutKind.Sequential)] public struct ScreenshotReady_t +{ + public uint m_hLocal; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct VolumeHasChanged_t +{ + public float m_flNewVolume; +} +[StructLayout(LayoutKind.Sequential)] public struct MusicPlayerWantsShuffled_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bShuffled; +} +[StructLayout(LayoutKind.Sequential)] public struct MusicPlayerWantsLooped_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bLooped; +} +[StructLayout(LayoutKind.Sequential)] public struct MusicPlayerWantsVolume_t +{ + public float m_flNewVolume; +} +[StructLayout(LayoutKind.Sequential)] public struct MusicPlayerSelectsQueueEntry_t +{ + public int nID; +} +[StructLayout(LayoutKind.Sequential)] public struct MusicPlayerSelectsPlaylistEntry_t +{ + public int nID; +} +[StructLayout(LayoutKind.Sequential)] public struct MusicPlayerWantsPlayingRepeatStatus_t +{ + public int m_nPlayingRepeatStatus; +} +[StructLayout(LayoutKind.Sequential)] public struct HTTPRequestCompleted_t +{ + public uint m_hRequest; + public ulong m_ulContextValue; + [MarshalAs(UnmanagedType.I1)] + public bool m_bRequestSuccessful; + public EHTTPStatusCode m_eStatusCode; + public uint m_unBodySize; +} +[StructLayout(LayoutKind.Sequential)] public struct HTTPRequestHeadersReceived_t +{ + public uint m_hRequest; + public ulong m_ulContextValue; +} +[StructLayout(LayoutKind.Sequential)] public struct HTTPRequestDataReceived_t +{ + public uint m_hRequest; + public ulong m_ulContextValue; + public uint m_cOffset; + public uint m_cBytesReceived; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamUGCDetails_t +{ + public ulong m_nPublishedFileId; + public EResult m_eResult; + public EWorkshopFileType m_eFileType; + public uint m_nCreatorAppID; + public uint m_nConsumerAppID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] + public string m_rgchTitle; //char[129] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8000)] + public string m_rgchDescription; //char[8000] + public ulong m_ulSteamIDOwner; + public uint m_rtimeCreated; + public uint m_rtimeUpdated; + public uint m_rtimeAddedToUserList; + public ERemoteStoragePublishedFileVisibility m_eVisibility; + [MarshalAs(UnmanagedType.I1)] + public bool m_bBanned; + [MarshalAs(UnmanagedType.I1)] + public bool m_bAcceptedForUse; + [MarshalAs(UnmanagedType.I1)] + public bool m_bTagsTruncated; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1025)] + public string m_rgchTags; //char[1025] + public ulong m_hFile; + public ulong m_hPreviewFile; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string m_pchFileName; //char[260] + public int m_nFileSize; + public int m_nPreviewFileSize; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_rgchURL; //char[256] + public uint m_unVotesUp; + public uint m_unVotesDown; + public float m_flScore; + public uint m_unNumChildren; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamUGCQueryCompleted_t +{ + public ulong m_handle; + public EResult m_eResult; + public uint m_unNumResultsReturned; + public uint m_unTotalMatchingResults; + [MarshalAs(UnmanagedType.I1)] + public bool m_bCachedData; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_rgchNextCursor; //char[256] +} +[StructLayout(LayoutKind.Sequential)] public struct SteamUGCRequestUGCDetailsResult_t +{ + public SteamUGCDetails_t m_details; + [MarshalAs(UnmanagedType.I1)] + public bool m_bCachedData; +} +[StructLayout(LayoutKind.Sequential)] public struct CreateItemResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + [MarshalAs(UnmanagedType.I1)] + public bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +} +[StructLayout(LayoutKind.Sequential)] public struct SubmitItemUpdateResult_t +{ + public EResult m_eResult; + [MarshalAs(UnmanagedType.I1)] + public bool m_bUserNeedsToAcceptWorkshopLegalAgreement; + public ulong m_nPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct DownloadItemResult_t +{ + public uint m_unAppID; + public ulong m_nPublishedFileId; + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct UserFavoriteItemsListChanged_t +{ + public ulong m_nPublishedFileId; + public EResult m_eResult; + [MarshalAs(UnmanagedType.I1)] + public bool m_bWasAddRequest; +} +[StructLayout(LayoutKind.Sequential)] public struct SetUserItemVoteResult_t +{ + public ulong m_nPublishedFileId; + public EResult m_eResult; + [MarshalAs(UnmanagedType.I1)] + public bool m_bVoteUp; +} +[StructLayout(LayoutKind.Sequential)] public struct GetUserItemVoteResult_t +{ + public ulong m_nPublishedFileId; + public EResult m_eResult; + [MarshalAs(UnmanagedType.I1)] + public bool m_bVotedUp; + [MarshalAs(UnmanagedType.I1)] + public bool m_bVotedDown; + [MarshalAs(UnmanagedType.I1)] + public bool m_bVoteSkipped; +} +[StructLayout(LayoutKind.Sequential)] public struct StartPlaytimeTrackingResult_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct StopPlaytimeTrackingResult_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct AddUGCDependencyResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public ulong m_nChildPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoveUGCDependencyResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public ulong m_nChildPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct AddAppDependencyResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct RemoveAppDependencyResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct GetAppDependenciesResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.U4)] + public uint[] m_rgAppIDs; //uint[32] + public uint m_nNumAppDependencies; + public uint m_nTotalNumAppDependencies; +} +[StructLayout(LayoutKind.Sequential)] public struct DeleteItemResult_t +{ + public EResult m_eResult; + public ulong m_nPublishedFileId; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamAppInstalled_t +{ + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamAppUninstalled_t +{ + public uint m_nAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_BrowserReady_t +{ + public uint unBrowserHandle; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_NeedsPaint_t +{ + public uint unBrowserHandle; + public IntPtr pBGRA; // const char * + public uint unWide; + public uint unTall; + public uint unUpdateX; + public uint unUpdateY; + public uint unUpdateWide; + public uint unUpdateTall; + public uint unScrollX; + public uint unScrollY; + public float flPageScale; + public uint unPageSerial; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_StartRequest_t +{ + public uint unBrowserHandle; + public IntPtr pchURL; // const char * + public IntPtr pchTarget; // const char * + public IntPtr pchPostData; // const char * + [MarshalAs(UnmanagedType.I1)] + public bool bIsRedirect; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_CloseBrowser_t +{ + public uint unBrowserHandle; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_URLChanged_t +{ + public uint unBrowserHandle; + public IntPtr pchURL; // const char * + public IntPtr pchPostData; // const char * + [MarshalAs(UnmanagedType.I1)] + public bool bIsRedirect; + public IntPtr pchPageTitle; // const char * + [MarshalAs(UnmanagedType.I1)] + public bool bNewNavigation; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_FinishedRequest_t +{ + public uint unBrowserHandle; + public IntPtr pchURL; // const char * + public IntPtr pchPageTitle; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_OpenLinkInNewTab_t +{ + public uint unBrowserHandle; + public IntPtr pchURL; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_ChangedTitle_t +{ + public uint unBrowserHandle; + public IntPtr pchTitle; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_SearchResults_t +{ + public uint unBrowserHandle; + public uint unResults; + public uint unCurrentMatch; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_CanGoBackAndForward_t +{ + public uint unBrowserHandle; + [MarshalAs(UnmanagedType.I1)] + public bool bCanGoBack; + [MarshalAs(UnmanagedType.I1)] + public bool bCanGoForward; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_HorizontalScroll_t +{ + public uint unBrowserHandle; + public uint unScrollMax; + public uint unScrollCurrent; + public float flPageScale; + [MarshalAs(UnmanagedType.I1)] + public bool bVisible; + public uint unPageSize; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_VerticalScroll_t +{ + public uint unBrowserHandle; + public uint unScrollMax; + public uint unScrollCurrent; + public float flPageScale; + [MarshalAs(UnmanagedType.I1)] + public bool bVisible; + public uint unPageSize; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_LinkAtPosition_t +{ + public uint unBrowserHandle; + public uint x; + public uint y; + public IntPtr pchURL; // const char * + [MarshalAs(UnmanagedType.I1)] + public bool bInput; + [MarshalAs(UnmanagedType.I1)] + public bool bLiveLink; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_JSAlert_t +{ + public uint unBrowserHandle; + public IntPtr pchMessage; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_JSConfirm_t +{ + public uint unBrowserHandle; + public IntPtr pchMessage; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_FileOpenDialog_t +{ + public uint unBrowserHandle; + public IntPtr pchTitle; // const char * + public IntPtr pchInitialFile; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_NewWindow_t +{ + public uint unBrowserHandle; + public IntPtr pchURL; // const char * + public uint unX; + public uint unY; + public uint unWide; + public uint unTall; + public uint unNewWindow_BrowserHandle_IGNORE; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_SetCursor_t +{ + public uint unBrowserHandle; + public uint eMouseCursor; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_StatusText_t +{ + public uint unBrowserHandle; + public IntPtr pchMsg; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_ShowToolTip_t +{ + public uint unBrowserHandle; + public IntPtr pchMsg; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_UpdateToolTip_t +{ + public uint unBrowserHandle; + public IntPtr pchMsg; // const char * +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_HideToolTip_t +{ + public uint unBrowserHandle; +} +[StructLayout(LayoutKind.Sequential)] public struct HTML_BrowserRestarted_t +{ + public uint unBrowserHandle; + public uint unOldBrowserHandle; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamItemDetails_t +{ + public ulong m_itemId; + public int m_iDefinition; + public char m_unQuantity; + public char m_unFlags; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamInventoryResultReady_t +{ + public int m_handle; + public EResult m_result; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamInventoryFullUpdate_t +{ + public int m_handle; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamInventoryEligiblePromoItemDefIDs_t +{ + public EResult m_result; + public ulong m_steamID; + public int m_numEligiblePromoItemDefs; + [MarshalAs(UnmanagedType.I1)] + public bool m_bCachedData; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamInventoryStartPurchaseResult_t +{ + public EResult m_result; + public ulong m_ulOrderID; + public ulong m_ulTransID; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamInventoryRequestPricesResult_t +{ + public EResult m_result; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] + public string m_rgchCurrency; //char[4] +} +[StructLayout(LayoutKind.Sequential)] public struct GetVideoURLResult_t +{ + public EResult m_eResult; + public uint m_unVideoAppID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string m_rgchURL; //char[256] +} +[StructLayout(LayoutKind.Sequential)] public struct GetOPFSettingsResult_t +{ + public EResult m_eResult; + public uint m_unVideoAppID; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamTVRegion_t +{ + public uint unMinX; + public uint unMinY; + public uint unMaxX; + public uint unMaxY; +} +[StructLayout(LayoutKind.Sequential)] public struct BroadcastUploadStart_t +{ + [MarshalAs(UnmanagedType.I1)] + public bool m_bIsRTMP; +} +[StructLayout(LayoutKind.Sequential)] public struct BroadcastUploadStop_t +{ + public EBroadcastUploadResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamRemotePlaySessionConnected_t +{ + public uint m_unSessionID; +} +[StructLayout(LayoutKind.Sequential)] public struct SteamRemotePlaySessionDisconnected_t +{ + public uint m_unSessionID; +} +[StructLayout(LayoutKind.Sequential)] public struct GSClientApprove_t +{ + public ulong m_SteamID; + public ulong m_OwnerSteamID; +} +[StructLayout(LayoutKind.Sequential)] public struct GSClientDeny_t +{ + public ulong m_SteamID; + public EDenyReason m_eDenyReason; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string m_rgchOptionalText; //char[128] +} +[StructLayout(LayoutKind.Sequential)] public struct GSClientKick_t +{ + public ulong m_SteamID; + public EDenyReason m_eDenyReason; +} +[StructLayout(LayoutKind.Sequential)] public struct GSClientAchievementStatus_t +{ + public ulong m_SteamID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string m_pchAchievement; //char[128] + [MarshalAs(UnmanagedType.I1)] + public bool m_bUnlocked; +} +[StructLayout(LayoutKind.Sequential)] public struct GSPolicyResponse_t +{ + public byte m_bSecure; +} +[StructLayout(LayoutKind.Sequential)] public struct GSGameplayStats_t +{ + public EResult m_eResult; + public int m_nRank; + public uint m_unTotalConnects; + public uint m_unTotalMinutesPlayed; +} +[StructLayout(LayoutKind.Sequential)] public struct GSClientGroupStatus_t +{ + public ulong m_SteamIDUser; + public ulong m_SteamIDGroup; + [MarshalAs(UnmanagedType.I1)] + public bool m_bMember; + [MarshalAs(UnmanagedType.I1)] + public bool m_bOfficer; +} +[StructLayout(LayoutKind.Sequential)] public struct GSReputation_t +{ + public EResult m_eResult; + public uint m_unReputationScore; + [MarshalAs(UnmanagedType.I1)] + public bool m_bBanned; + public uint m_unBannedIP; + public char m_usBannedPort; + public ulong m_ulBannedGameID; + public uint m_unBanExpires; +} +[StructLayout(LayoutKind.Sequential)] public struct AssociateWithClanResult_t +{ + public EResult m_eResult; +} +[StructLayout(LayoutKind.Sequential)] public struct ComputeNewPlayerCompatibilityResult_t +{ + public EResult m_eResult; + public int m_cPlayersThatDontLikeCandidate; + public int m_cPlayersThatCandidateDoesntLike; + public int m_cClanPlayersThatDontLikeCandidate; + public ulong m_SteamIDCandidate; +} +[StructLayout(LayoutKind.Sequential)] public struct GSStatsReceived_t +{ + public EResult m_eResult; + public ulong m_steamIDUser; +} +[StructLayout(LayoutKind.Sequential)] public struct GSStatsStored_t +{ + public EResult m_eResult; + public ulong m_steamIDUser; +} +[StructLayout(LayoutKind.Sequential)] public struct GSStatsUnloaded_t +{ + public ulong m_steamIDUser; +} + +public class SteamAPI +{ +public static void Init(uint appId) +{ +SteamAPIInterop.SteamAPI_RestartAppIfNecessary (appId); +SteamAPIInterop.SteamAPI_Init (); +} + +public static void RunCallbacks() +{ +SteamAPIInterop.SteamAPI_RunCallbacks (); +} + +public static void RegisterCallback(IntPtr pCallback, int iCallback) +{ +SteamAPIInterop.SteamAPI_RegisterCallback (pCallback, iCallback); +} + +public static void UnregisterCallback(IntPtr pCallback) +{ +SteamAPIInterop.SteamAPI_UnregisterCallback (pCallback); +} + +public const int k_iSteamUserCallbacks = 100; +public const int k_iSteamGameServerCallbacks = 200; +public const int k_iSteamFriendsCallbacks = 300; +public const int k_iSteamBillingCallbacks = 400; +public const int k_iSteamMatchmakingCallbacks = 500; +public const int k_iSteamContentServerCallbacks = 600; +public const int k_iSteamUtilsCallbacks = 700; +public const int k_iClientFriendsCallbacks = 800; +public const int k_iClientUserCallbacks = 900; +public const int k_iSteamAppsCallbacks = 1000; +public const int k_iSteamUserStatsCallbacks = 1100; +public const int k_iSteamNetworkingCallbacks = 1200; +public const int k_iSteamNetworkingSocketsCallbacks = 1220; +public const int k_iSteamNetworkingMessagesCallbacks = 1250; +public const int k_iSteamNetworkingUtilsCallbacks = 1280; +public const int k_iClientRemoteStorageCallbacks = 1300; +public const int k_iClientDepotBuilderCallbacks = 1400; +public const int k_iSteamGameServerItemsCallbacks = 1500; +public const int k_iClientUtilsCallbacks = 1600; +public const int k_iSteamGameCoordinatorCallbacks = 1700; +public const int k_iSteamGameServerStatsCallbacks = 1800; +public const int k_iSteam2AsyncCallbacks = 1900; +public const int k_iSteamGameStatsCallbacks = 2000; +public const int k_iClientHTTPCallbacks = 2100; +public const int k_iClientScreenshotsCallbacks = 2200; +public const int k_iSteamScreenshotsCallbacks = 2300; +public const int k_iClientAudioCallbacks = 2400; +public const int k_iClientUnifiedMessagesCallbacks = 2500; +public const int k_iSteamStreamLauncherCallbacks = 2600; +public const int k_iClientControllerCallbacks = 2700; +public const int k_iSteamControllerCallbacks = 2800; +public const int k_iClientParentalSettingsCallbacks = 2900; +public const int k_iClientDeviceAuthCallbacks = 3000; +public const int k_iClientNetworkDeviceManagerCallbacks = 3100; +public const int k_iClientMusicCallbacks = 3200; +public const int k_iClientRemoteClientManagerCallbacks = 3300; +public const int k_iClientUGCCallbacks = 3400; +public const int k_iSteamStreamClientCallbacks = 3500; +public const int k_IClientProductBuilderCallbacks = 3600; +public const int k_iClientShortcutsCallbacks = 3700; +public const int k_iClientRemoteControlManagerCallbacks = 3800; +public const int k_iSteamAppListCallbacks = 3900; +public const int k_iSteamMusicCallbacks = 4000; +public const int k_iSteamMusicRemoteCallbacks = 4100; +public const int k_iClientVRCallbacks = 4200; +public const int k_iClientGameNotificationCallbacks = 4300; +public const int k_iSteamGameNotificationCallbacks = 4400; +public const int k_iSteamHTMLSurfaceCallbacks = 4500; +public const int k_iClientVideoCallbacks = 4600; +public const int k_iClientInventoryCallbacks = 4700; +public const int k_iClientBluetoothManagerCallbacks = 4800; +public const int k_iClientSharedConnectionCallbacks = 4900; +public const int k_ISteamParentalSettingsCallbacks = 5000; +public const int k_iClientShaderCallbacks = 5100; +public const int k_iSteamGameSearchCallbacks = 5200; +public const int k_iSteamPartiesCallbacks = 5300; +public const int k_iClientPartiesCallbacks = 5400; +public const int k_iSteamSTARCallbacks = 5500; +public const int k_iClientSTARCallbacks = 5600; +public const int k_iSteamRemotePlayCallbacks = 5700; +public const int k_cchPersonaNameMax = 128; +public const int k_cwchPersonaNameMax = 32; +public const int k_cchMaxRichPresenceKeys = 30; +public const int k_cchMaxRichPresenceKeyLength = 64; +public const int k_cchMaxRichPresenceValueLength = 256; +public const int k_cchStatNameMax = 128; +public const int k_cchLeaderboardNameMax = 128; +public const int k_cLeaderboardDetailsMax = 64; +public const ulong k_SteamItemInstanceIDInvalid = 0xffffffffffffffff; +public const int k_SteamInventoryResultInvalid = -1; +public const int k_cchBroadcastGameDataMax = 8192; +public static ISteamClient SteamClient() +{ +return new CSteamClient(SteamAPIInterop.SteamClient()); +} + +public static ISteamUser SteamUser() +{ +return new CSteamUser(SteamAPIInterop.SteamUser()); +} + +public static ISteamFriends SteamFriends() +{ +return new CSteamFriends(SteamAPIInterop.SteamFriends()); +} + +public static ISteamUtils SteamUtils() +{ +return new CSteamUtils(SteamAPIInterop.SteamUtils()); +} + +public static ISteamMatchmaking SteamMatchmaking() +{ +return new CSteamMatchmaking(SteamAPIInterop.SteamMatchmaking()); +} + +public static ISteamMatchmakingServerListResponse SteamMatchmakingServerListResponse() +{ +return new CSteamMatchmakingServerListResponse(SteamAPIInterop.SteamMatchmakingServerListResponse()); +} + +public static ISteamMatchmakingPingResponse SteamMatchmakingPingResponse() +{ +return new CSteamMatchmakingPingResponse(SteamAPIInterop.SteamMatchmakingPingResponse()); +} + +public static ISteamMatchmakingPlayersResponse SteamMatchmakingPlayersResponse() +{ +return new CSteamMatchmakingPlayersResponse(SteamAPIInterop.SteamMatchmakingPlayersResponse()); +} + +public static ISteamMatchmakingRulesResponse SteamMatchmakingRulesResponse() +{ +return new CSteamMatchmakingRulesResponse(SteamAPIInterop.SteamMatchmakingRulesResponse()); +} + +public static ISteamMatchmakingServers SteamMatchmakingServers() +{ +return new CSteamMatchmakingServers(SteamAPIInterop.SteamMatchmakingServers()); +} + +public static ISteamGameSearch SteamGameSearch() +{ +return new CSteamGameSearch(SteamAPIInterop.SteamGameSearch()); +} + +public static ISteamParties SteamParties() +{ +return new CSteamParties(SteamAPIInterop.SteamParties()); +} + +public static ISteamRemoteStorage SteamRemoteStorage() +{ +return new CSteamRemoteStorage(SteamAPIInterop.SteamRemoteStorage()); +} + +public static ISteamUserStats SteamUserStats() +{ +return new CSteamUserStats(SteamAPIInterop.SteamUserStats()); +} + +public static ISteamApps SteamApps() +{ +return new CSteamApps(SteamAPIInterop.SteamApps()); +} + +public static ISteamNetworking SteamNetworking() +{ +return new CSteamNetworking(SteamAPIInterop.SteamNetworking()); +} + +public static ISteamScreenshots SteamScreenshots() +{ +return new CSteamScreenshots(SteamAPIInterop.SteamScreenshots()); +} + +public static ISteamMusic SteamMusic() +{ +return new CSteamMusic(SteamAPIInterop.SteamMusic()); +} + +public static ISteamMusicRemote SteamMusicRemote() +{ +return new CSteamMusicRemote(SteamAPIInterop.SteamMusicRemote()); +} + +public static ISteamHTTP SteamHTTP() +{ +return new CSteamHTTP(SteamAPIInterop.SteamHTTP()); +} + +public static ISteamInput SteamInput() +{ +return new CSteamInput(SteamAPIInterop.SteamInput()); +} + +public static ISteamController SteamController() +{ +return new CSteamController(SteamAPIInterop.SteamController()); +} + +public static ISteamUGC SteamUGC() +{ +return new CSteamUGC(SteamAPIInterop.SteamUGC()); +} + +public static ISteamAppList SteamAppList() +{ +return new CSteamAppList(SteamAPIInterop.SteamAppList()); +} + +public static ISteamHTMLSurface SteamHTMLSurface() +{ +return new CSteamHTMLSurface(SteamAPIInterop.SteamHTMLSurface()); +} + +public static ISteamInventory SteamInventory() +{ +return new CSteamInventory(SteamAPIInterop.SteamInventory()); +} + +public static ISteamVideo SteamVideo() +{ +return new CSteamVideo(SteamAPIInterop.SteamVideo()); +} + +public static ISteamTV SteamTV() +{ +return new CSteamTV(SteamAPIInterop.SteamTV()); +} + +public static ISteamParentalSettings SteamParentalSettings() +{ +return new CSteamParentalSettings(SteamAPIInterop.SteamParentalSettings()); +} + +public static ISteamRemotePlay SteamRemotePlay() +{ +return new CSteamRemotePlay(SteamAPIInterop.SteamRemotePlay()); +} + +public static ISteamGameServer SteamGameServer() +{ +return new CSteamGameServer(SteamAPIInterop.SteamGameServer()); +} + +public static ISteamGameServerStats SteamGameServerStats() +{ +return new CSteamGameServerStats(SteamAPIInterop.SteamGameServerStats()); +} + +} + + + +} + diff --git a/public/steam/steam_gameserver.h b/public/steam/steam_gameserver.h new file mode 100644 index 0000000..bec600d --- /dev/null +++ b/public/steam/steam_gameserver.h @@ -0,0 +1,110 @@ +//====== Copyright 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef STEAM_GAMESERVER_H +#define STEAM_GAMESERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api.h" +#include "isteamgameserver.h" +#include "isteamgameserverstats.h" + +enum EServerMode +{ + eServerModeInvalid = 0, // DO NOT USE + eServerModeNoAuthentication = 1, // Don't authenticate user logins and don't list on the server list + eServerModeAuthentication = 2, // Authenticate users, list on the server list, don't run VAC on clients that connect + eServerModeAuthenticationAndSecure = 3, // Authenticate users, list on the server list and VAC protect clients +}; + +// Initialize SteamGameServer client and interface objects, and set server properties which may not be changed. +// +// After calling this function, you should set any additional server parameters, and then +// call ISteamGameServer::LogOnAnonymous() or ISteamGameServer::LogOn() +// +// - usSteamPort is the local port used to communicate with the steam servers. +// NOTE: unless you are using ver old Steam client binaries, this parameter is ignored, and +// you should pass 0. Gameservers now always use WebSockets to talk to Steam. +// This protocol is TCP-based and thus always uses an ephemeral local port. +// Older steam client binaries used UDP to talk to Steam, and this argument was useful. +// A future version of the SDK will remove this argument. +// - usGamePort is the port that clients will connect to for gameplay. +// - usQueryPort is the port that will manage server browser related duties and info +// pings from clients. If you pass MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE for usQueryPort, then it +// will use "GameSocketShare" mode, which means that the game is responsible for sending and receiving +// UDP packets for the master server updater. See references to GameSocketShare in isteamgameserver.h. +// - The version string is usually in the form x.x.x.x, and is used by the master server to detect when the +// server is out of date. (Only servers with the latest version will be listed.) +inline bool SteamGameServer_Init( uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); + +// Shutdown SteamGameSeverXxx interfaces, log out, and free resources. +S_API void SteamGameServer_Shutdown(); + +// Most Steam API functions allocate some amount of thread-local memory for +// parameter storage. Calling SteamGameServer_ReleaseCurrentThreadMemory() +// will free all API-related memory associated with the calling thread. +// This memory is released automatically by SteamGameServer_RunCallbacks(), +// so single-threaded servers do not need to explicitly call this function. +inline void SteamGameServer_ReleaseCurrentThreadMemory(); + +S_API bool SteamGameServer_BSecure(); +S_API uint64 SteamGameServer_GetSteamID(); + +// Older SDKs exported this global pointer, but it is no longer supported. +// You should use SteamGameServerClient() or CSteamGameServerAPIContext to +// safely access the ISteamClient APIs from your game server application. +//S_API ISteamClient *g_pSteamClientGameServer; + +// SteamGameServer_InitSafe has been replaced with SteamGameServer_Init and +// is no longer supported. Use SteamGameServer_Init instead. +//S_API void S_CALLTYPE SteamGameServer_InitSafe(); + +//============================================================================= +// +// Internal implementation details below +// +//============================================================================= + +#ifndef STEAM_API_EXPORTS +// This function must be declared inline in the header so the module using steam_api.dll gets the version names they want. +inline bool CSteamGameServerAPIContext::Init() +{ + m_pSteamClient = ::SteamGameServerClient(); + if ( !m_pSteamClient ) + return false; + + m_pSteamGameServer = ::SteamGameServer(); + m_pSteamGameServerUtils = ::SteamGameServerUtils(); + m_pSteamGameServerNetworking = ::SteamGameServerNetworking(); + m_pSteamGameServerStats = ::SteamGameServerStats(); + m_pSteamHTTP = ::SteamGameServerHTTP(); + m_pSteamInventory = ::SteamGameServerInventory(); + m_pSteamUGC = ::SteamGameServerUGC(); + m_pSteamApps = ::SteamGameServerApps(); + if ( !m_pSteamGameServer || !m_pSteamGameServerUtils || !m_pSteamGameServerNetworking || !m_pSteamGameServerStats + || !m_pSteamHTTP || !m_pSteamInventory || !m_pSteamUGC || !m_pSteamApps ) + return false; + + return true; +} +#endif + +S_API bool S_CALLTYPE SteamInternal_GameServer_Init( uint32 unIP, uint16 usPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); +inline bool SteamGameServer_Init( uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ) +{ + if ( !SteamInternal_GameServer_Init( unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString ) ) + return false; + + return true; +} +inline void SteamGameServer_ReleaseCurrentThreadMemory() +{ + SteamAPI_ReleaseCurrentThreadMemory(); +} + +#endif // STEAM_GAMESERVER_H diff --git a/public/steam/steamclientpublic.h b/public/steam/steamclientpublic.h new file mode 100644 index 0000000..7af8aa5 --- /dev/null +++ b/public/steam/steamclientpublic.h @@ -0,0 +1,1448 @@ +//========= Copyright � 1996-2008, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMCLIENTPUBLIC_H +#define STEAMCLIENTPUBLIC_H +#ifdef _WIN32 +#pragma once +#endif +//lint -save -e1931 -e1927 -e1924 -e613 -e726 + +// This header file defines the interface between the calling application and the code that +// knows how to communicate with the connection manager (CM) from the Steam service + +// This header file is intended to be portable; ideally this 1 header file plus a lib or dll +// is all you need to integrate the client library into some other tree. So please avoid +// including or requiring other header files if possible. This header should only describe the +// interface layer, no need to include anything about the implementation. + +#include "steamtypes.h" +#include "steamuniverse.h" + +// General result codes +enum EResult +{ + k_EResultOK = 1, // success + k_EResultFail = 2, // generic failure + k_EResultNoConnection = 3, // no/failed network connection +// k_EResultNoConnectionRetry = 4, // OBSOLETE - removed + k_EResultInvalidPassword = 5, // password/ticket is invalid + k_EResultLoggedInElsewhere = 6, // same user logged in elsewhere + k_EResultInvalidProtocolVer = 7, // protocol version is incorrect + k_EResultInvalidParam = 8, // a parameter is incorrect + k_EResultFileNotFound = 9, // file was not found + k_EResultBusy = 10, // called method busy - action not taken + k_EResultInvalidState = 11, // called object was in an invalid state + k_EResultInvalidName = 12, // name is invalid + k_EResultInvalidEmail = 13, // email is invalid + k_EResultDuplicateName = 14, // name is not unique + k_EResultAccessDenied = 15, // access is denied + k_EResultTimeout = 16, // operation timed out + k_EResultBanned = 17, // VAC2 banned + k_EResultAccountNotFound = 18, // account not found + k_EResultInvalidSteamID = 19, // steamID is invalid + k_EResultServiceUnavailable = 20, // The requested service is currently unavailable + k_EResultNotLoggedOn = 21, // The user is not logged on + k_EResultPending = 22, // Request is pending (may be in process, or waiting on third party) + k_EResultEncryptionFailure = 23, // Encryption or Decryption failed + k_EResultInsufficientPrivilege = 24, // Insufficient privilege + k_EResultLimitExceeded = 25, // Too much of a good thing + k_EResultRevoked = 26, // Access has been revoked (used for revoked guest passes) + k_EResultExpired = 27, // License/Guest pass the user is trying to access is expired + k_EResultAlreadyRedeemed = 28, // Guest pass has already been redeemed by account, cannot be acked again + k_EResultDuplicateRequest = 29, // The request is a duplicate and the action has already occurred in the past, ignored this time + k_EResultAlreadyOwned = 30, // All the games in this guest pass redemption request are already owned by the user + k_EResultIPNotFound = 31, // IP address not found + k_EResultPersistFailed = 32, // failed to write change to the data store + k_EResultLockingFailed = 33, // failed to acquire access lock for this operation + k_EResultLogonSessionReplaced = 34, + k_EResultConnectFailed = 35, + k_EResultHandshakeFailed = 36, + k_EResultIOFailure = 37, + k_EResultRemoteDisconnect = 38, + k_EResultShoppingCartNotFound = 39, // failed to find the shopping cart requested + k_EResultBlocked = 40, // a user didn't allow it + k_EResultIgnored = 41, // target is ignoring sender + k_EResultNoMatch = 42, // nothing matching the request found + k_EResultAccountDisabled = 43, + k_EResultServiceReadOnly = 44, // this service is not accepting content changes right now + k_EResultAccountNotFeatured = 45, // account doesn't have value, so this feature isn't available + k_EResultAdministratorOK = 46, // allowed to take this action, but only because requester is admin + k_EResultContentVersion = 47, // A Version mismatch in content transmitted within the Steam protocol. + k_EResultTryAnotherCM = 48, // The current CM can't service the user making a request, user should try another. + k_EResultPasswordRequiredToKickSession = 49,// You are already logged in elsewhere, this cached credential login has failed. + k_EResultAlreadyLoggedInElsewhere = 50, // You are already logged in elsewhere, you must wait + k_EResultSuspended = 51, // Long running operation (content download) suspended/paused + k_EResultCancelled = 52, // Operation canceled (typically by user: content download) + k_EResultDataCorruption = 53, // Operation canceled because data is ill formed or unrecoverable + k_EResultDiskFull = 54, // Operation canceled - not enough disk space. + k_EResultRemoteCallFailed = 55, // an remote call or IPC call failed + k_EResultPasswordUnset = 56, // Password could not be verified as it's unset server side + k_EResultExternalAccountUnlinked = 57, // External account (PSN, Facebook...) is not linked to a Steam account + k_EResultPSNTicketInvalid = 58, // PSN ticket was invalid + k_EResultExternalAccountAlreadyLinked = 59, // External account (PSN, Facebook...) is already linked to some other account, must explicitly request to replace/delete the link first + k_EResultRemoteFileConflict = 60, // The sync cannot resume due to a conflict between the local and remote files + k_EResultIllegalPassword = 61, // The requested new password is not legal + k_EResultSameAsPreviousValue = 62, // new value is the same as the old one ( secret question and answer ) + k_EResultAccountLogonDenied = 63, // account login denied due to 2nd factor authentication failure + k_EResultCannotUseOldPassword = 64, // The requested new password is not legal + k_EResultInvalidLoginAuthCode = 65, // account login denied due to auth code invalid + k_EResultAccountLogonDeniedNoMail = 66, // account login denied due to 2nd factor auth failure - and no mail has been sent + k_EResultHardwareNotCapableOfIPT = 67, // + k_EResultIPTInitError = 68, // + k_EResultParentalControlRestricted = 69, // operation failed due to parental control restrictions for current user + k_EResultFacebookQueryError = 70, // Facebook query returned an error + k_EResultExpiredLoginAuthCode = 71, // account login denied due to auth code expired + k_EResultIPLoginRestrictionFailed = 72, + k_EResultAccountLockedDown = 73, + k_EResultAccountLogonDeniedVerifiedEmailRequired = 74, + k_EResultNoMatchingURL = 75, + k_EResultBadResponse = 76, // parse failure, missing field, etc. + k_EResultRequirePasswordReEntry = 77, // The user cannot complete the action until they re-enter their password + k_EResultValueOutOfRange = 78, // the value entered is outside the acceptable range + k_EResultUnexpectedError = 79, // something happened that we didn't expect to ever happen + k_EResultDisabled = 80, // The requested service has been configured to be unavailable + k_EResultInvalidCEGSubmission = 81, // The set of files submitted to the CEG server are not valid ! + k_EResultRestrictedDevice = 82, // The device being used is not allowed to perform this action + k_EResultRegionLocked = 83, // The action could not be complete because it is region restricted + k_EResultRateLimitExceeded = 84, // Temporary rate limit exceeded, try again later, different from k_EResultLimitExceeded which may be permanent + k_EResultAccountLoginDeniedNeedTwoFactor = 85, // Need two-factor code to login + k_EResultItemDeleted = 86, // The thing we're trying to access has been deleted + k_EResultAccountLoginDeniedThrottle = 87, // login attempt failed, try to throttle response to possible attacker + k_EResultTwoFactorCodeMismatch = 88, // two factor code mismatch + k_EResultTwoFactorActivationCodeMismatch = 89, // activation code for two-factor didn't match + k_EResultAccountAssociatedToMultiplePartners = 90, // account has been associated with multiple partners + k_EResultNotModified = 91, // data not modified + k_EResultNoMobileDevice = 92, // the account does not have a mobile device associated with it + k_EResultTimeNotSynced = 93, // the time presented is out of range or tolerance + k_EResultSmsCodeFailed = 94, // SMS code failure (no match, none pending, etc.) + k_EResultAccountLimitExceeded = 95, // Too many accounts access this resource + k_EResultAccountActivityLimitExceeded = 96, // Too many changes to this account + k_EResultPhoneActivityLimitExceeded = 97, // Too many changes to this phone + k_EResultRefundToWallet = 98, // Cannot refund to payment method, must use wallet + k_EResultEmailSendFailure = 99, // Cannot send an email + k_EResultNotSettled = 100, // Can't perform operation till payment has settled + k_EResultNeedCaptcha = 101, // Needs to provide a valid captcha + k_EResultGSLTDenied = 102, // a game server login token owned by this token's owner has been banned + k_EResultGSOwnerDenied = 103, // game server owner is denied for other reason (account lock, community ban, vac ban, missing phone) + k_EResultInvalidItemType = 104, // the type of thing we were requested to act on is invalid + k_EResultIPBanned = 105, // the ip address has been banned from taking this action + k_EResultGSLTExpired = 106, // this token has expired from disuse; can be reset for use + k_EResultInsufficientFunds = 107, // user doesn't have enough wallet funds to complete the action + k_EResultTooManyPending = 108, // There are too many of this thing pending already + k_EResultNoSiteLicensesFound = 109, // No site licenses found + k_EResultWGNetworkSendExceeded = 110, // the WG couldn't send a response because we exceeded max network send size + k_EResultAccountNotFriends = 111, // the user is not mutually friends + k_EResultLimitedUserAccount = 112, // the user is limited + k_EResultCantRemoveItem = 113, // item can't be removed +}; + +// Error codes for use with the voice functions +enum EVoiceResult +{ + k_EVoiceResultOK = 0, + k_EVoiceResultNotInitialized = 1, + k_EVoiceResultNotRecording = 2, + k_EVoiceResultNoData = 3, + k_EVoiceResultBufferTooSmall = 4, + k_EVoiceResultDataCorrupted = 5, + k_EVoiceResultRestricted = 6, + k_EVoiceResultUnsupportedCodec = 7, + k_EVoiceResultReceiverOutOfDate = 8, + k_EVoiceResultReceiverDidNotAnswer = 9, + +}; + +// Result codes to GSHandleClientDeny/Kick +enum EDenyReason +{ + k_EDenyInvalid = 0, + k_EDenyInvalidVersion = 1, + k_EDenyGeneric = 2, + k_EDenyNotLoggedOn = 3, + k_EDenyNoLicense = 4, + k_EDenyCheater = 5, + k_EDenyLoggedInElseWhere = 6, + k_EDenyUnknownText = 7, + k_EDenyIncompatibleAnticheat = 8, + k_EDenyMemoryCorruption = 9, + k_EDenyIncompatibleSoftware = 10, + k_EDenySteamConnectionLost = 11, + k_EDenySteamConnectionError = 12, + k_EDenySteamResponseTimedOut = 13, + k_EDenySteamValidationStalled = 14, + k_EDenySteamOwnerLeftGuestUser = 15, +}; + +// return type of GetAuthSessionTicket +typedef uint32 HAuthTicket; +const HAuthTicket k_HAuthTicketInvalid = 0; + +// results from BeginAuthSession +enum EBeginAuthSessionResult +{ + k_EBeginAuthSessionResultOK = 0, // Ticket is valid for this game and this steamID. + k_EBeginAuthSessionResultInvalidTicket = 1, // Ticket is not valid. + k_EBeginAuthSessionResultDuplicateRequest = 2, // A ticket has already been submitted for this steamID + k_EBeginAuthSessionResultInvalidVersion = 3, // Ticket is from an incompatible interface version + k_EBeginAuthSessionResultGameMismatch = 4, // Ticket is not for this game + k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired +}; + +// Callback values for callback ValidateAuthTicketResponse_t which is a response to BeginAuthSession +enum EAuthSessionResponse +{ + k_EAuthSessionResponseOK = 0, // Steam has verified the user is online, the ticket is valid and ticket has not been reused. + k_EAuthSessionResponseUserNotConnectedToSteam = 1, // The user in question is not connected to steam + k_EAuthSessionResponseNoLicenseOrExpired = 2, // The license has expired. + k_EAuthSessionResponseVACBanned = 3, // The user is VAC banned for this game. + k_EAuthSessionResponseLoggedInElseWhere = 4, // The user account has logged in elsewhere and the session containing the game instance has been disconnected. + k_EAuthSessionResponseVACCheckTimedOut = 5, // VAC has been unable to perform anti-cheat checks on this user + k_EAuthSessionResponseAuthTicketCanceled = 6, // The ticket has been canceled by the issuer + k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed = 7, // This ticket has already been used, it is not valid. + k_EAuthSessionResponseAuthTicketInvalid = 8, // This ticket is not from a user instance currently connected to steam. + k_EAuthSessionResponsePublisherIssuedBan = 9, // The user is banned for this game. The ban came via the web api and not VAC +}; + +// results from UserHasLicenseForApp +enum EUserHasLicenseForAppResult +{ + k_EUserHasLicenseResultHasLicense = 0, // User has a license for specified app + k_EUserHasLicenseResultDoesNotHaveLicense = 1, // User does not have a license for the specified app + k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated +}; + + +// Steam account types +enum EAccountType +{ + k_EAccountTypeInvalid = 0, + k_EAccountTypeIndividual = 1, // single user account + k_EAccountTypeMultiseat = 2, // multiseat (e.g. cybercafe) account + k_EAccountTypeGameServer = 3, // game server account + k_EAccountTypeAnonGameServer = 4, // anonymous game server account + k_EAccountTypePending = 5, // pending + k_EAccountTypeContentServer = 6, // content server + k_EAccountTypeClan = 7, + k_EAccountTypeChat = 8, + k_EAccountTypeConsoleUser = 9, // Fake SteamID for local PSN account on PS3 or Live account on 360, etc. + k_EAccountTypeAnonUser = 10, + + // Max of 16 items in this field + k_EAccountTypeMax +}; + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum EAppReleaseState +{ + k_EAppReleaseState_Unknown = 0, // unknown, required appinfo or license info is missing + k_EAppReleaseState_Unavailable = 1, // even if user 'just' owns it, can see game at all + k_EAppReleaseState_Prerelease = 2, // can be purchased and is visible in games list, nothing else. Common appInfo section released + k_EAppReleaseState_PreloadOnly = 3, // owners can preload app, not play it. AppInfo fully released. + k_EAppReleaseState_Released = 4, // owners can download and play app. +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum EAppOwnershipFlags +{ + k_EAppOwnershipFlags_None = 0x0000, // unknown + k_EAppOwnershipFlags_OwnsLicense = 0x0001, // owns license for this game + k_EAppOwnershipFlags_FreeLicense = 0x0002, // not paid for game + k_EAppOwnershipFlags_RegionRestricted = 0x0004, // owns app, but not allowed to play in current region + k_EAppOwnershipFlags_LowViolence = 0x0008, // only low violence version + k_EAppOwnershipFlags_InvalidPlatform = 0x0010, // app not supported on current platform + k_EAppOwnershipFlags_SharedLicense = 0x0020, // license was granted by authorized local device + k_EAppOwnershipFlags_FreeWeekend = 0x0040, // owned by a free weekend licenses + k_EAppOwnershipFlags_RetailLicense = 0x0080, // has a retail license for game, (CD-Key etc) + k_EAppOwnershipFlags_LicenseLocked = 0x0100, // shared license is locked (in use) by other user + k_EAppOwnershipFlags_LicensePending = 0x0200, // owns app, but transaction is still pending. Can't install or play + k_EAppOwnershipFlags_LicenseExpired = 0x0400, // doesn't own app anymore since license expired + k_EAppOwnershipFlags_LicensePermanent = 0x0800, // permanent license, not borrowed, or guest or freeweekend etc + k_EAppOwnershipFlags_LicenseRecurring = 0x1000, // Recurring license, user is charged periodically + k_EAppOwnershipFlags_LicenseCanceled = 0x2000, // Mark as canceled, but might be still active if recurring + k_EAppOwnershipFlags_AutoGrant = 0x4000, // Ownership is based on any kind of autogrant license + k_EAppOwnershipFlags_PendingGift = 0x8000, // user has pending gift to redeem + k_EAppOwnershipFlags_RentalNotActivated = 0x10000, // Rental hasn't been activated yet + k_EAppOwnershipFlags_Rental = 0x20000, // Is a rental + k_EAppOwnershipFlags_SiteLicense = 0x40000, // Is from a site license +}; + + +//----------------------------------------------------------------------------- +// Purpose: designed as flags to allow filters masks +// NOTE: If you add to this, please update PackageAppType (SteamConfig) as well as populatePackageAppType +//----------------------------------------------------------------------------- +enum EAppType +{ + k_EAppType_Invalid = 0x000, // unknown / invalid + k_EAppType_Game = 0x001, // playable game, default type + k_EAppType_Application = 0x002, // software application + k_EAppType_Tool = 0x004, // SDKs, editors & dedicated servers + k_EAppType_Demo = 0x008, // game demo + k_EAppType_Media_DEPRECATED = 0x010, // legacy - was used for game trailers, which are now just videos on the web + k_EAppType_DLC = 0x020, // down loadable content + k_EAppType_Guide = 0x040, // game guide, PDF etc + k_EAppType_Driver = 0x080, // hardware driver updater (ATI, Razor etc) + k_EAppType_Config = 0x100, // hidden app used to config Steam features (backpack, sales, etc) + k_EAppType_Hardware = 0x200, // a hardware device (Steam Machine, Steam Controller, Steam Link, etc.) + k_EAppType_Franchise = 0x400, // A hub for collections of multiple apps, eg films, series, games + k_EAppType_Video = 0x800, // A video component of either a Film or TVSeries (may be the feature, an episode, preview, making-of, etc) + k_EAppType_Plugin = 0x1000, // Plug-in types for other Apps + k_EAppType_Music = 0x2000, // Music files + k_EAppType_Series = 0x4000, // Container app for video series + k_EAppType_Comic = 0x8000, // Comic Book + k_EAppType_Beta = 0x10000, // this is a beta version of a game + + k_EAppType_Shortcut = 0x40000000, // just a shortcut, client side only + k_EAppType_DepotOnly = 0x80000000, // placeholder since depots and apps share the same namespace +}; + + + +//----------------------------------------------------------------------------- +// types of user game stats fields +// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE +//----------------------------------------------------------------------------- +enum ESteamUserStatType +{ + k_ESteamUserStatTypeINVALID = 0, + k_ESteamUserStatTypeINT = 1, + k_ESteamUserStatTypeFLOAT = 2, + // Read as FLOAT, set with count / session length + k_ESteamUserStatTypeAVGRATE = 3, + k_ESteamUserStatTypeACHIEVEMENTS = 4, + k_ESteamUserStatTypeGROUPACHIEVEMENTS = 5, + + // max, for sanity checks + k_ESteamUserStatTypeMAX +}; + + +//----------------------------------------------------------------------------- +// Purpose: Chat Entry Types (previously was only friend-to-friend message types) +//----------------------------------------------------------------------------- +enum EChatEntryType +{ + k_EChatEntryTypeInvalid = 0, + k_EChatEntryTypeChatMsg = 1, // Normal text message from another user + k_EChatEntryTypeTyping = 2, // Another user is typing (not used in multi-user chat) + k_EChatEntryTypeInviteGame = 3, // Invite from other user into that users current game + k_EChatEntryTypeEmote = 4, // text emote message (deprecated, should be treated as ChatMsg) + //k_EChatEntryTypeLobbyGameStart = 5, // lobby game is starting (dead - listen for LobbyGameCreated_t callback instead) + k_EChatEntryTypeLeftConversation = 6, // user has left the conversation ( closed chat window ) + // Above are previous FriendMsgType entries, now merged into more generic chat entry types + k_EChatEntryTypeEntered = 7, // user has entered the conversation (used in multi-user chat and group chat) + k_EChatEntryTypeWasKicked = 8, // user was kicked (data: 64-bit steamid of actor performing the kick) + k_EChatEntryTypeWasBanned = 9, // user was banned (data: 64-bit steamid of actor performing the ban) + k_EChatEntryTypeDisconnected = 10, // user disconnected + k_EChatEntryTypeHistoricalChat = 11, // a chat message from user's chat history or offilne message + //k_EChatEntryTypeReserved1 = 12, // No longer used + //k_EChatEntryTypeReserved2 = 13, // No longer used + k_EChatEntryTypeLinkBlocked = 14, // a link was removed by the chat filter. +}; + + +//----------------------------------------------------------------------------- +// Purpose: Chat Room Enter Responses +//----------------------------------------------------------------------------- +enum EChatRoomEnterResponse +{ + k_EChatRoomEnterResponseSuccess = 1, // Success + k_EChatRoomEnterResponseDoesntExist = 2, // Chat doesn't exist (probably closed) + k_EChatRoomEnterResponseNotAllowed = 3, // General Denied - You don't have the permissions needed to join the chat + k_EChatRoomEnterResponseFull = 4, // Chat room has reached its maximum size + k_EChatRoomEnterResponseError = 5, // Unexpected Error + k_EChatRoomEnterResponseBanned = 6, // You are banned from this chat room and may not join + k_EChatRoomEnterResponseLimited = 7, // Joining this chat is not allowed because you are a limited user (no value on account) + k_EChatRoomEnterResponseClanDisabled = 8, // Attempt to join a clan chat when the clan is locked or disabled + k_EChatRoomEnterResponseCommunityBan = 9, // Attempt to join a chat when the user has a community lock on their account + k_EChatRoomEnterResponseMemberBlockedYou = 10, // Join failed - some member in the chat has blocked you from joining + k_EChatRoomEnterResponseYouBlockedMember = 11, // Join failed - you have blocked some member already in the chat + // k_EChatRoomEnterResponseNoRankingDataLobby = 12, // No longer used + // k_EChatRoomEnterResponseNoRankingDataUser = 13, // No longer used + // k_EChatRoomEnterResponseRankOutOfRange = 14, // No longer used + k_EChatRoomEnterResponseRatelimitExceeded = 15, // Join failed - to many join attempts in a very short period of time +}; + + +typedef void (*PFNLegacyKeyRegistration)( const char *pchCDKey, const char *pchInstallPath ); +typedef bool (*PFNLegacyKeyInstalled)(); + +const unsigned int k_unSteamAccountIDMask = 0xFFFFFFFF; +const unsigned int k_unSteamAccountInstanceMask = 0x000FFFFF; +// we allow 3 simultaneous user account instances right now, 1= desktop, 2 = console, 4 = web, 0 = all +const unsigned int k_unSteamUserDesktopInstance = 1; +const unsigned int k_unSteamUserConsoleInstance = 2; +const unsigned int k_unSteamUserWebInstance = 4; + +// Special flags for Chat accounts - they go in the top 8 bits +// of the steam ID's "instance", leaving 12 for the actual instances +enum EChatSteamIDInstanceFlags +{ + k_EChatAccountInstanceMask = 0x00000FFF, // top 8 bits are flags + + k_EChatInstanceFlagClan = ( k_unSteamAccountInstanceMask + 1 ) >> 1, // top bit + k_EChatInstanceFlagLobby = ( k_unSteamAccountInstanceMask + 1 ) >> 2, // next one down, etc + k_EChatInstanceFlagMMSLobby = ( k_unSteamAccountInstanceMask + 1 ) >> 3, // next one down, etc + + // Max of 8 flags +}; + + +//----------------------------------------------------------------------------- +// Purpose: Marketing message flags that change how a client should handle them +//----------------------------------------------------------------------------- +enum EMarketingMessageFlags +{ + k_EMarketingMessageFlagsNone = 0, + k_EMarketingMessageFlagsHighPriority = 1 << 0, + k_EMarketingMessageFlagsPlatformWindows = 1 << 1, + k_EMarketingMessageFlagsPlatformMac = 1 << 2, + k_EMarketingMessageFlagsPlatformLinux = 1 << 3, + + //aggregate flags + k_EMarketingMessageFlagsPlatformRestrictions = + k_EMarketingMessageFlagsPlatformWindows | + k_EMarketingMessageFlagsPlatformMac | + k_EMarketingMessageFlagsPlatformLinux, +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Possible positions to tell the overlay to show notifications in +//----------------------------------------------------------------------------- +enum ENotificationPosition +{ + k_EPositionTopLeft = 0, + k_EPositionTopRight = 1, + k_EPositionBottomLeft = 2, + k_EPositionBottomRight = 3, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Broadcast upload result details +//----------------------------------------------------------------------------- +enum EBroadcastUploadResult +{ + k_EBroadcastUploadResultNone = 0, // broadcast state unknown + k_EBroadcastUploadResultOK = 1, // broadcast was good, no problems + k_EBroadcastUploadResultInitFailed = 2, // broadcast init failed + k_EBroadcastUploadResultFrameFailed = 3, // broadcast frame upload failed + k_EBroadcastUploadResultTimeout = 4, // broadcast upload timed out + k_EBroadcastUploadResultBandwidthExceeded = 5, // broadcast send too much data + k_EBroadcastUploadResultLowFPS = 6, // broadcast FPS too low + k_EBroadcastUploadResultMissingKeyFrames = 7, // broadcast sending not enough key frames + k_EBroadcastUploadResultNoConnection = 8, // broadcast client failed to connect to relay + k_EBroadcastUploadResultRelayFailed = 9, // relay dropped the upload + k_EBroadcastUploadResultSettingsChanged = 10, // the client changed broadcast settings + k_EBroadcastUploadResultMissingAudio = 11, // client failed to send audio data + k_EBroadcastUploadResultTooFarBehind = 12, // clients was too slow uploading + k_EBroadcastUploadResultTranscodeBehind = 13, // server failed to keep up with transcode + k_EBroadcastUploadResultNotAllowedToPlay = 14, // Broadcast does not have permissions to play game + k_EBroadcastUploadResultBusy = 15, // RTMP host to busy to take new broadcast stream, choose another + k_EBroadcastUploadResultBanned = 16, // Account banned from community broadcast + k_EBroadcastUploadResultAlreadyActive = 17, // We already already have an stream running. + k_EBroadcastUploadResultForcedOff = 18, // We explicitly shutting down a broadcast + k_EBroadcastUploadResultAudioBehind = 19, // Audio stream was too far behind video + k_EBroadcastUploadResultShutdown = 20, // Broadcast Server was shut down + k_EBroadcastUploadResultDisconnect = 21, // broadcast uploader TCP disconnected + k_EBroadcastUploadResultVideoInitFailed = 22, // invalid video settings + k_EBroadcastUploadResultAudioInitFailed = 23, // invalid audio settings +}; + + +//----------------------------------------------------------------------------- +// Purpose: codes for well defined launch options +//----------------------------------------------------------------------------- +enum ELaunchOptionType +{ + k_ELaunchOptionType_None = 0, // unknown what launch option does + k_ELaunchOptionType_Default = 1, // runs the game, app, whatever in default mode + k_ELaunchOptionType_SafeMode = 2, // runs the game in safe mode + k_ELaunchOptionType_Multiplayer = 3, // runs the game in multiplayer mode + k_ELaunchOptionType_Config = 4, // runs config tool for this game + k_ELaunchOptionType_OpenVR = 5, // runs game in VR mode using OpenVR + k_ELaunchOptionType_Server = 6, // runs dedicated server for this game + k_ELaunchOptionType_Editor = 7, // runs game editor + k_ELaunchOptionType_Manual = 8, // shows game manual + k_ELaunchOptionType_Benchmark = 9, // runs game benchmark + k_ELaunchOptionType_Option1 = 10, // generic run option, uses description field for game name + k_ELaunchOptionType_Option2 = 11, // generic run option, uses description field for game name + k_ELaunchOptionType_Option3 = 12, // generic run option, uses description field for game name + k_ELaunchOptionType_OculusVR = 13, // runs game in VR mode using the Oculus SDK + k_ELaunchOptionType_OpenVROverlay = 14, // runs an OpenVR dashboard overlay + k_ELaunchOptionType_OSVR = 15, // runs game in VR mode using the OSVR SDK + + + k_ELaunchOptionType_Dialog = 1000, // show launch options dialog +}; + + +//----------------------------------------------------------------------------- +// Purpose: true if this launch option is any of the vr launching types +//----------------------------------------------------------------------------- +static inline bool BIsVRLaunchOptionType( const ELaunchOptionType eType ) +{ + return eType == k_ELaunchOptionType_OpenVR + || eType == k_ELaunchOptionType_OpenVROverlay + || eType == k_ELaunchOptionType_OculusVR + || eType == k_ELaunchOptionType_OSVR; +} + + +//----------------------------------------------------------------------------- +// Purpose: code points for VR HMD vendors and models +// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN A DATABASE +//----------------------------------------------------------------------------- +enum EVRHMDType +{ + k_eEVRHMDType_None = -1, // unknown vendor and model + + k_eEVRHMDType_Unknown = 0, // unknown vendor and model + + k_eEVRHMDType_HTC_Dev = 1, // original HTC dev kits + k_eEVRHMDType_HTC_VivePre = 2, // htc vive pre + k_eEVRHMDType_HTC_Vive = 3, // htc vive consumer release + k_eEVRHMDType_HTC_VivePro = 4, // htc vive pro release + k_eEVRHMDType_HTC_ViveCosmos = 5, // HTC Vive Cosmos + + k_eEVRHMDType_HTC_Unknown = 20, // unknown htc hmd + + k_eEVRHMDType_Oculus_DK1 = 21, // Oculus DK1 + k_eEVRHMDType_Oculus_DK2 = 22, // Oculus DK2 + k_eEVRHMDType_Oculus_Rift = 23, // Oculus Rift + k_eEVRHMDType_Oculus_RiftS = 24, // Oculus Rift S + + k_eEVRHMDType_Oculus_Unknown = 40, // // Oculus unknown HMD + + k_eEVRHMDType_Acer_Unknown = 50, // Acer unknown HMD + k_eEVRHMDType_Acer_WindowsMR = 51, // Acer QHMD Windows MR headset + + k_eEVRHMDType_Dell_Unknown = 60, // Dell unknown HMD + k_eEVRHMDType_Dell_Visor = 61, // Dell Visor Windows MR headset + + k_eEVRHMDType_Lenovo_Unknown = 70, // Lenovo unknown HMD + k_eEVRHMDType_Lenovo_Explorer = 71, // Lenovo Explorer Windows MR headset + + k_eEVRHMDType_HP_Unknown = 80, // HP unknown HMD + k_eEVRHMDType_HP_WindowsMR = 81, // HP Windows MR headset + + k_eEVRHMDType_Samsung_Unknown = 90, // Samsung unknown HMD + k_eEVRHMDType_Samsung_Odyssey = 91, // Samsung Odyssey Windows MR headset + + k_eEVRHMDType_Unannounced_Unknown = 100, // Unannounced unknown HMD + k_eEVRHMDType_Unannounced_WindowsMR = 101, // Unannounced Windows MR headset + + k_eEVRHMDType_vridge = 110, // VRIDGE tool + + k_eEVRHMDType_Huawei_Unknown = 120, // Huawei unknown HMD + k_eEVRHMDType_Huawei_VR2 = 121, // Huawei VR2 3DOF headset + k_eEVRHMDType_Huawei_EndOfRange = 129, // end of Huawei HMD range + + k_eEVRHmdType_Valve_Unknown = 130, // Valve Unknown HMD + k_eEVRHmdType_Valve_Index = 131, // Valve Index HMD + +}; + + +//----------------------------------------------------------------------------- +// Purpose: true if this is from an Oculus HMD +//----------------------------------------------------------------------------- +static inline bool BIsOculusHMD( EVRHMDType eType ) +{ + return eType == k_eEVRHMDType_Oculus_DK1 || eType == k_eEVRHMDType_Oculus_DK2 || eType == k_eEVRHMDType_Oculus_Rift || eType == k_eEVRHMDType_Oculus_RiftS || eType == k_eEVRHMDType_Oculus_Unknown; +} + + +//----------------------------------------------------------------------------- +// Purpose: true if this is from a Windows MR HMD +//----------------------------------------------------------------------------- +static inline bool BIsWindowsMRHeadset( EVRHMDType eType ) +{ + return eType >= k_eEVRHMDType_Acer_WindowsMR && eType <= k_eEVRHMDType_Unannounced_WindowsMR; +} + + +//----------------------------------------------------------------------------- +// Purpose: true if this is from a Hauwei HMD +//----------------------------------------------------------------------------- +static inline bool BIsHuaweiHeadset( EVRHMDType eType ) +{ + return eType >= k_eEVRHMDType_Huawei_Unknown && eType <= k_eEVRHMDType_Huawei_EndOfRange; +} + + +//----------------------------------------------------------------------------- +// Purpose: true if this is from an Vive HMD +//----------------------------------------------------------------------------- +static inline bool BIsViveHMD( EVRHMDType eType ) +{ + return eType == k_eEVRHMDType_HTC_Dev || eType == k_eEVRHMDType_HTC_VivePre || eType == k_eEVRHMDType_HTC_Vive || eType == k_eEVRHMDType_HTC_Unknown || eType == k_eEVRHMDType_HTC_VivePro; +} + + +//----------------------------------------------------------------------------- +// Purpose: Reasons a user may not use the Community Market. +// Used in MarketEligibilityResponse_t. +//----------------------------------------------------------------------------- +enum EMarketNotAllowedReasonFlags +{ + k_EMarketNotAllowedReason_None = 0, + + // A back-end call failed or something that might work again on retry + k_EMarketNotAllowedReason_TemporaryFailure = (1 << 0), + + // Disabled account + k_EMarketNotAllowedReason_AccountDisabled = (1 << 1), + + // Locked account + k_EMarketNotAllowedReason_AccountLockedDown = (1 << 2), + + // Limited account (no purchases) + k_EMarketNotAllowedReason_AccountLimited = (1 << 3), + + // The account is banned from trading items + k_EMarketNotAllowedReason_TradeBanned = (1 << 4), + + // Wallet funds aren't tradable because the user has had no purchase + // activity in the last year or has had no purchases prior to last month + k_EMarketNotAllowedReason_AccountNotTrusted = (1 << 5), + + // The user doesn't have Steam Guard enabled + k_EMarketNotAllowedReason_SteamGuardNotEnabled = (1 << 6), + + // The user has Steam Guard, but it hasn't been enabled for the required + // number of days + k_EMarketNotAllowedReason_SteamGuardOnlyRecentlyEnabled = (1 << 7), + + // The user has recently forgotten their password and reset it + k_EMarketNotAllowedReason_RecentPasswordReset = (1 << 8), + + // The user has recently funded his or her wallet with a new payment method + k_EMarketNotAllowedReason_NewPaymentMethod = (1 << 9), + + // An invalid cookie was sent by the user + k_EMarketNotAllowedReason_InvalidCookie = (1 << 10), + + // The user has Steam Guard, but is using a new computer or web browser + k_EMarketNotAllowedReason_UsingNewDevice = (1 << 11), + + // The user has recently refunded a store purchase by his or herself + k_EMarketNotAllowedReason_RecentSelfRefund = (1 << 12), + + // The user has recently funded his or her wallet with a new payment method that cannot be verified + k_EMarketNotAllowedReason_NewPaymentMethodCannotBeVerified = (1 << 13), + + // Not only is the account not trusted, but they have no recent purchases at all + k_EMarketNotAllowedReason_NoRecentPurchases = (1 << 14), + + // User accepted a wallet gift that was recently purchased + k_EMarketNotAllowedReason_AcceptedWalletGift = (1 << 15), +}; + + +// +// describes XP / progress restrictions to apply for games with duration control / +// anti-indulgence enabled for minor Steam China users. +// +enum EDurationControlProgress +{ + k_EDurationControlProgress_Full, // Full progress + k_EDurationControlProgress_Half, // XP or persistent rewards should be halved + k_EDurationControlProgress_None, // XP or persistent rewards should be stopped +}; + + +// +// describes which notification timer has expired, for steam china duration control feature +// +enum EDurationControlNotification +{ + k_EDurationControlNotification_None, // just informing you about progress, no notification to show + k_EDurationControlNotification_1Hour, // "you've been playing for an hour" + k_EDurationControlNotification_3Hours, // "you've been playing for 3 hours; take a break" + k_EDurationControlNotification_HalfProgress, // "your XP / progress is half normal" + k_EDurationControlNotification_NoProgress, // "your XP / progress is zero" +}; + + +#pragma pack( push, 1 ) + +#define CSTEAMID_DEFINED + +// Steam ID structure (64 bits total) +class CSteamID +{ +public: + + //----------------------------------------------------------------------------- + // Purpose: Constructor + //----------------------------------------------------------------------------- + CSteamID() + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeInvalid; + m_steamid.m_comp.m_EUniverse = k_EUniverseInvalid; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + + //----------------------------------------------------------------------------- + // Purpose: Constructor + // Input : unAccountID - 32-bit account ID + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + CSteamID( uint32 unAccountID, EUniverse eUniverse, EAccountType eAccountType ) + { + Set( unAccountID, eUniverse, eAccountType ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Constructor + // Input : unAccountID - 32-bit account ID + // unAccountInstance - instance + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + CSteamID( uint32 unAccountID, unsigned int unAccountInstance, EUniverse eUniverse, EAccountType eAccountType ) + { +#if defined(_SERVER) && defined(Assert) + Assert( ! ( ( k_EAccountTypeIndividual == eAccountType ) && ( unAccountInstance > k_unSteamUserWebInstance ) ) ); // enforce that for individual accounts, instance is always 1 +#endif // _SERVER + InstancedSet( unAccountID, unAccountInstance, eUniverse, eAccountType ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Constructor + // Input : ulSteamID - 64-bit representation of a Steam ID + // Note: Will not accept a uint32 or int32 as input, as that is a probable mistake. + // See the stubbed out overloads in the private: section for more info. + //----------------------------------------------------------------------------- + CSteamID( uint64 ulSteamID ) + { + SetFromUint64( ulSteamID ); + } +#ifdef INT64_DIFFERENT_FROM_INT64_T + CSteamID( uint64_t ulSteamID ) + { + SetFromUint64( (uint64)ulSteamID ); + } +#endif + + + //----------------------------------------------------------------------------- + // Purpose: Sets parameters for steam ID + // Input : unAccountID - 32-bit account ID + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + void Set( uint32 unAccountID, EUniverse eUniverse, EAccountType eAccountType ) + { + m_steamid.m_comp.m_unAccountID = unAccountID; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_EAccountType = eAccountType; + + if ( eAccountType == k_EAccountTypeClan || eAccountType == k_EAccountTypeGameServer ) + { + m_steamid.m_comp.m_unAccountInstance = 0; + } + else + { + // by default we pick the desktop instance + m_steamid.m_comp.m_unAccountInstance = k_unSteamUserDesktopInstance; + } + } + + + //----------------------------------------------------------------------------- + // Purpose: Sets parameters for steam ID + // Input : unAccountID - 32-bit account ID + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + void InstancedSet( uint32 unAccountID, uint32 unInstance, EUniverse eUniverse, EAccountType eAccountType ) + { + m_steamid.m_comp.m_unAccountID = unAccountID; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_EAccountType = eAccountType; + m_steamid.m_comp.m_unAccountInstance = unInstance; + } + + + //----------------------------------------------------------------------------- + // Purpose: Initializes a steam ID from its 52 bit parts and universe/type + // Input : ulIdentifier - 52 bits of goodness + //----------------------------------------------------------------------------- + void FullSet( uint64 ulIdentifier, EUniverse eUniverse, EAccountType eAccountType ) + { + m_steamid.m_comp.m_unAccountID = ( ulIdentifier & k_unSteamAccountIDMask ); // account ID is low 32 bits + m_steamid.m_comp.m_unAccountInstance = ( ( ulIdentifier >> 32 ) & k_unSteamAccountInstanceMask ); // account instance is next 20 bits + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_EAccountType = eAccountType; + } + + + //----------------------------------------------------------------------------- + // Purpose: Initializes a steam ID from its 64-bit representation + // Input : ulSteamID - 64-bit representation of a Steam ID + //----------------------------------------------------------------------------- + void SetFromUint64( uint64 ulSteamID ) + { + m_steamid.m_unAll64Bits = ulSteamID; + } + + + //----------------------------------------------------------------------------- + // Purpose: Clear all fields, leaving an invalid ID. + //----------------------------------------------------------------------------- + void Clear() + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeInvalid; + m_steamid.m_comp.m_EUniverse = k_EUniverseInvalid; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + +#if defined( INCLUDED_STEAM2_USERID_STRUCTS ) + //----------------------------------------------------------------------------- + // Purpose: Initializes a steam ID from a Steam2 ID structure + // Input: pTSteamGlobalUserID - Steam2 ID to convert + // eUniverse - universe this ID belongs to + //----------------------------------------------------------------------------- + void SetFromSteam2( TSteamGlobalUserID *pTSteamGlobalUserID, EUniverse eUniverse ) + { + m_steamid.m_comp.m_unAccountID = pTSteamGlobalUserID->m_SteamLocalUserID.Split.Low32bits * 2 + + pTSteamGlobalUserID->m_SteamLocalUserID.Split.High32bits; + m_steamid.m_comp.m_EUniverse = eUniverse; // set the universe + m_steamid.m_comp.m_EAccountType = k_EAccountTypeIndividual; // Steam 2 accounts always map to account type of individual + m_steamid.m_comp.m_unAccountInstance = k_unSteamUserDesktopInstance; // Steam2 only knew desktop instances + } + + //----------------------------------------------------------------------------- + // Purpose: Fills out a Steam2 ID structure + // Input: pTSteamGlobalUserID - Steam2 ID to write to + //----------------------------------------------------------------------------- + void ConvertToSteam2( TSteamGlobalUserID *pTSteamGlobalUserID ) const + { + // only individual accounts have any meaning in Steam 2, only they can be mapped + // Assert( m_steamid.m_comp.m_EAccountType == k_EAccountTypeIndividual ); + + pTSteamGlobalUserID->m_SteamInstanceID = 0; + pTSteamGlobalUserID->m_SteamLocalUserID.Split.High32bits = m_steamid.m_comp.m_unAccountID % 2; + pTSteamGlobalUserID->m_SteamLocalUserID.Split.Low32bits = m_steamid.m_comp.m_unAccountID / 2; + } +#endif // defined( INCLUDED_STEAM_COMMON_STEAMCOMMON_H ) + + //----------------------------------------------------------------------------- + // Purpose: Converts steam ID to its 64-bit representation + // Output : 64-bit representation of a Steam ID + //----------------------------------------------------------------------------- + uint64 ConvertToUint64() const + { + return m_steamid.m_unAll64Bits; + } + + + //----------------------------------------------------------------------------- + // Purpose: Converts the static parts of a steam ID to a 64-bit representation. + // For multiseat accounts, all instances of that account will have the + // same static account key, so they can be grouped together by the static + // account key. + // Output : 64-bit static account key + //----------------------------------------------------------------------------- + uint64 GetStaticAccountKey() const + { + // note we do NOT include the account instance (which is a dynamic property) in the static account key + return (uint64) ( ( ( (uint64) m_steamid.m_comp.m_EUniverse ) << 56 ) + ((uint64) m_steamid.m_comp.m_EAccountType << 52 ) + m_steamid.m_comp.m_unAccountID ); + } + + + //----------------------------------------------------------------------------- + // Purpose: create an anonymous game server login to be filled in by the AM + //----------------------------------------------------------------------------- + void CreateBlankAnonLogon( EUniverse eUniverse ) + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeAnonGameServer; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + + //----------------------------------------------------------------------------- + // Purpose: create an anonymous game server login to be filled in by the AM + //----------------------------------------------------------------------------- + void CreateBlankAnonUserLogon( EUniverse eUniverse ) + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeAnonUser; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous game server login that will be filled in? + //----------------------------------------------------------------------------- + bool BBlankAnonAccount() const + { + return m_steamid.m_comp.m_unAccountID == 0 && BAnonAccount() && m_steamid.m_comp.m_unAccountInstance == 0; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a game server account id? (Either persistent or anonymous) + //----------------------------------------------------------------------------- + bool BGameServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeGameServer || m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a persistent (not anonymous) game server account id? + //----------------------------------------------------------------------------- + bool BPersistentGameServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous game server account id? + //----------------------------------------------------------------------------- + bool BAnonGameServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a content server account id? + //----------------------------------------------------------------------------- + bool BContentServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeContentServer; + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this a clan account id? + //----------------------------------------------------------------------------- + bool BClanAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeClan; + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this a chat account id? + //----------------------------------------------------------------------------- + bool BChatAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeChat; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a chat account id? + //----------------------------------------------------------------------------- + bool IsLobby() const + { + return ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeChat ) + && ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagLobby ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this an individual user account id? + //----------------------------------------------------------------------------- + bool BIndividualAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeIndividual || m_steamid.m_comp.m_EAccountType == k_EAccountTypeConsoleUser; + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous account? + //----------------------------------------------------------------------------- + bool BAnonAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonUser || m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous user account? ( used to create an account or reset a password ) + //----------------------------------------------------------------------------- + bool BAnonUserAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonUser; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a faked up Steam ID for a PSN friend account? + //----------------------------------------------------------------------------- + bool BConsoleUserAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeConsoleUser; + } + + // simple accessors + void SetAccountID( uint32 unAccountID ) { m_steamid.m_comp.m_unAccountID = unAccountID; } + void SetAccountInstance( uint32 unInstance ){ m_steamid.m_comp.m_unAccountInstance = unInstance; } + void ClearIndividualInstance() { if ( BIndividualAccount() ) m_steamid.m_comp.m_unAccountInstance = 0; } + bool HasNoIndividualInstance() const { return BIndividualAccount() && (m_steamid.m_comp.m_unAccountInstance==0); } + AccountID_t GetAccountID() const { return m_steamid.m_comp.m_unAccountID; } + uint32 GetUnAccountInstance() const { return m_steamid.m_comp.m_unAccountInstance; } + EAccountType GetEAccountType() const { return ( EAccountType ) m_steamid.m_comp.m_EAccountType; } + EUniverse GetEUniverse() const { return m_steamid.m_comp.m_EUniverse; } + void SetEUniverse( EUniverse eUniverse ) { m_steamid.m_comp.m_EUniverse = eUniverse; } + bool IsValid() const; + + // this set of functions is hidden, will be moved out of class + explicit CSteamID( const char *pchSteamID, EUniverse eDefaultUniverse = k_EUniverseInvalid ); + const char * Render() const; // renders this steam ID to string + static const char * Render( uint64 ulSteamID ); // static method to render a uint64 representation of a steam ID to a string + + void SetFromString( const char *pchSteamID, EUniverse eDefaultUniverse ); + // SetFromString allows many partially-correct strings, constraining how + // we might be able to change things in the future. + // SetFromStringStrict requires the exact string forms that we support + // and is preferred when the caller knows it's safe to be strict. + // Returns whether the string parsed correctly. + bool SetFromStringStrict( const char *pchSteamID, EUniverse eDefaultUniverse ); + bool SetFromSteam2String( const char *pchSteam2ID, EUniverse eUniverse ); + + inline bool operator==( const CSteamID &val ) const { return m_steamid.m_unAll64Bits == val.m_steamid.m_unAll64Bits; } + inline bool operator!=( const CSteamID &val ) const { return !operator==( val ); } + inline bool operator<( const CSteamID &val ) const { return m_steamid.m_unAll64Bits < val.m_steamid.m_unAll64Bits; } + inline bool operator>( const CSteamID &val ) const { return m_steamid.m_unAll64Bits > val.m_steamid.m_unAll64Bits; } + + // DEBUG function + bool BValidExternalSteamID() const; + +private: + // These are defined here to prevent accidental implicit conversion of a u32AccountID to a CSteamID. + // If you get a compiler error about an ambiguous constructor/function then it may be because you're + // passing a 32-bit int to a function that takes a CSteamID. You should explicitly create the SteamID + // using the correct Universe and account Type/Instance values. + CSteamID( uint32 ); + CSteamID( int32 ); + + // 64 bits total + union SteamID_t + { + struct SteamIDComponent_t + { +#ifdef VALVE_BIG_ENDIAN + EUniverse m_EUniverse : 8; // universe this account belongs to + unsigned int m_EAccountType : 4; // type of account - can't show as EAccountType, due to signed / unsigned difference + unsigned int m_unAccountInstance : 20; // dynamic instance ID + uint32 m_unAccountID : 32; // unique account identifier +#else + uint32 m_unAccountID : 32; // unique account identifier + unsigned int m_unAccountInstance : 20; // dynamic instance ID + unsigned int m_EAccountType : 4; // type of account - can't show as EAccountType, due to signed / unsigned difference + EUniverse m_EUniverse : 8; // universe this account belongs to +#endif + } m_comp; + + uint64 m_unAll64Bits; + } m_steamid; +}; + +inline bool CSteamID::IsValid() const +{ + if ( m_steamid.m_comp.m_EAccountType <= k_EAccountTypeInvalid || m_steamid.m_comp.m_EAccountType >= k_EAccountTypeMax ) + return false; + + if ( m_steamid.m_comp.m_EUniverse <= k_EUniverseInvalid || m_steamid.m_comp.m_EUniverse >= k_EUniverseMax ) + return false; + + if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeIndividual ) + { + if ( m_steamid.m_comp.m_unAccountID == 0 || m_steamid.m_comp.m_unAccountInstance > k_unSteamUserWebInstance ) + return false; + } + + if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeClan ) + { + if ( m_steamid.m_comp.m_unAccountID == 0 || m_steamid.m_comp.m_unAccountInstance != 0 ) + return false; + } + + if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeGameServer ) + { + if ( m_steamid.m_comp.m_unAccountID == 0 ) + return false; + // Any limit on instances? We use them for local users and bots + } + return true; +} + +// generic invalid CSteamID +#define k_steamIDNil CSteamID() + +// This steamID comes from a user game connection to an out of date GS that hasnt implemented the protocol +// to provide its steamID +#define k_steamIDOutofDateGS CSteamID( 0, 0, k_EUniverseInvalid, k_EAccountTypeInvalid ) +// This steamID comes from a user game connection to an sv_lan GS +#define k_steamIDLanModeGS CSteamID( 0, 0, k_EUniversePublic, k_EAccountTypeInvalid ) +// This steamID can come from a user game connection to a GS that has just booted but hasnt yet even initialized +// its steam3 component and started logging on. +#define k_steamIDNotInitYetGS CSteamID( 1, 0, k_EUniverseInvalid, k_EAccountTypeInvalid ) +// This steamID can come from a user game connection to a GS that isn't using the steam authentication system but still +// wants to support the "Join Game" option in the friends list +#define k_steamIDNonSteamGS CSteamID( 2, 0, k_EUniverseInvalid, k_EAccountTypeInvalid ) + + +#ifdef STEAM +// Returns the matching chat steamID, with the default instance of 0 +// If the steamID passed in is already of type k_EAccountTypeChat it will be returned with the same instance +CSteamID ChatIDFromSteamID( const CSteamID &steamID ); +// Returns the matching clan steamID, with the default instance of 0 +// If the steamID passed in is already of type k_EAccountTypeClan it will be returned with the same instance +CSteamID ClanIDFromSteamID( const CSteamID &steamID ); +// Asserts steamID type before conversion +CSteamID ChatIDFromClanID( const CSteamID &steamIDClan ); +// Asserts steamID type before conversion +CSteamID ClanIDFromChatID( const CSteamID &steamIDChat ); + +#endif // _STEAM + + +//----------------------------------------------------------------------------- +// Purpose: encapsulates an appID/modID pair +//----------------------------------------------------------------------------- +class CGameID +{ +public: + + CGameID() + { + m_gameID.m_nType = k_EGameIDTypeApp; + m_gameID.m_nAppID = k_uAppIdInvalid; + m_gameID.m_nModID = 0; + } + + explicit CGameID( uint64 ulGameID ) + { + m_ulGameID = ulGameID; + } +#ifdef INT64_DIFFERENT_FROM_INT64_T + CGameID( uint64_t ulGameID ) + { + m_ulGameID = (uint64)ulGameID; + } +#endif + + explicit CGameID( int32 nAppID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + } + + explicit CGameID( uint32 nAppID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + } + + CGameID( uint32 nAppID, uint32 nModID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + m_gameID.m_nModID = nModID; + m_gameID.m_nType = k_EGameIDTypeGameMod; + } + + // Hidden functions used only by Steam + explicit CGameID( const char *pchGameID ); + const char *Render() const; // render this Game ID to string + static const char *Render( uint64 ulGameID ); // static method to render a uint64 representation of a Game ID to a string + + // must include checksum_crc.h first to get this functionality +#if defined( CHECKSUM_CRC_H ) + CGameID( uint32 nAppID, const char *pchModPath ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + m_gameID.m_nType = k_EGameIDTypeGameMod; + + char rgchModDir[MAX_PATH]; + V_FileBase( pchModPath, rgchModDir, sizeof( rgchModDir ) ); + CRC32_t crc32; + CRC32_Init( &crc32 ); + CRC32_ProcessBuffer( &crc32, rgchModDir, V_strlen( rgchModDir ) ); + CRC32_Final( &crc32 ); + + // set the high-bit on the mod-id + // reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique + // replacement for appID's + m_gameID.m_nModID = crc32 | (0x80000000); + } + + CGameID( const char *pchExePath, const char *pchAppName ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = k_uAppIdInvalid; + m_gameID.m_nType = k_EGameIDTypeShortcut; + + CRC32_t crc32; + CRC32_Init( &crc32 ); + if ( pchExePath ) + CRC32_ProcessBuffer( &crc32, pchExePath, V_strlen( pchExePath ) ); + if ( pchAppName ) + CRC32_ProcessBuffer( &crc32, pchAppName, V_strlen( pchAppName ) ); + CRC32_Final( &crc32 ); + + // set the high-bit on the mod-id + // reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique + // replacement for appID's + m_gameID.m_nModID = crc32 | (0x80000000); + } + +#if defined( VSTFILEID_H ) + + CGameID( VstFileID vstFileID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = k_uAppIdInvalid; + m_gameID.m_nType = k_EGameIDTypeP2P; + + CRC32_t crc32; + CRC32_Init( &crc32 ); + const char *pchFileId = vstFileID.Render(); + CRC32_ProcessBuffer( &crc32, pchFileId, V_strlen( pchFileId ) ); + CRC32_Final( &crc32 ); + + // set the high-bit on the mod-id + // reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique + // replacement for appID's + m_gameID.m_nModID = crc32 | (0x80000000); + } + +#endif /* VSTFILEID_H */ + +#endif /* CHECKSUM_CRC_H */ + + + uint64 ToUint64() const + { + return m_ulGameID; + } + + uint64 *GetUint64Ptr() + { + return &m_ulGameID; + } + + void Set( uint64 ulGameID ) + { + m_ulGameID = ulGameID; + } + + bool IsMod() const + { + return ( m_gameID.m_nType == k_EGameIDTypeGameMod ); + } + + bool IsShortcut() const + { + return ( m_gameID.m_nType == k_EGameIDTypeShortcut ); + } + + bool IsP2PFile() const + { + return ( m_gameID.m_nType == k_EGameIDTypeP2P ); + } + + bool IsSteamApp() const + { + return ( m_gameID.m_nType == k_EGameIDTypeApp ); + } + + uint32 ModID() const + { + return m_gameID.m_nModID; + } + + uint32 AppID() const + { + return m_gameID.m_nAppID; + } + + bool operator == ( const CGameID &rhs ) const + { + return m_ulGameID == rhs.m_ulGameID; + } + + bool operator != ( const CGameID &rhs ) const + { + return !(*this == rhs); + } + + bool operator < ( const CGameID &rhs ) const + { + return ( m_ulGameID < rhs.m_ulGameID ); + } + + bool IsValid() const + { + // each type has it's own invalid fixed point: + switch( m_gameID.m_nType ) + { + case k_EGameIDTypeApp: + return m_gameID.m_nAppID != k_uAppIdInvalid; + + case k_EGameIDTypeGameMod: + return m_gameID.m_nAppID != k_uAppIdInvalid && m_gameID.m_nModID & 0x80000000; + + case k_EGameIDTypeShortcut: + return (m_gameID.m_nModID & 0x80000000) != 0; + + case k_EGameIDTypeP2P: + return m_gameID.m_nAppID == k_uAppIdInvalid && m_gameID.m_nModID & 0x80000000; + + default: + return false; + } + + } + + void Reset() + { + m_ulGameID = 0; + } + + + +private: + + enum EGameIDType + { + k_EGameIDTypeApp = 0, + k_EGameIDTypeGameMod = 1, + k_EGameIDTypeShortcut = 2, + k_EGameIDTypeP2P = 3, + }; + + struct GameID_t + { +#ifdef VALVE_BIG_ENDIAN + unsigned int m_nModID : 32; + unsigned int m_nType : 8; + unsigned int m_nAppID : 24; +#else + unsigned int m_nAppID : 24; + unsigned int m_nType : 8; + unsigned int m_nModID : 32; +#endif + }; + + union + { + uint64 m_ulGameID; + GameID_t m_gameID; + }; +}; + +#pragma pack( pop ) + +const int k_cchGameExtraInfoMax = 64; + + +//----------------------------------------------------------------------------- +// Constants used for query ports. +//----------------------------------------------------------------------------- + +#define QUERY_PORT_NOT_INITIALIZED 0xFFFF // We haven't asked the GS for this query port's actual value yet. +#define QUERY_PORT_ERROR 0xFFFE // We were unable to get the query port for this server. + + +//----------------------------------------------------------------------------- +// Purpose: Passed as argument to SteamAPI_UseBreakpadCrashHandler to enable optional callback +// just before minidump file is captured after a crash has occurred. (Allows app to append additional comment data to the dump, etc.) +//----------------------------------------------------------------------------- +typedef void (*PFNPreMinidumpCallback)(void *context); + +//----------------------------------------------------------------------------- +// Purpose: Used by ICrashHandler interfaces to reference particular installed crash handlers +//----------------------------------------------------------------------------- +typedef void *BREAKPAD_HANDLE; +#define BREAKPAD_INVALID_HANDLE (BREAKPAD_HANDLE)0 + +enum EGameSearchErrorCode_t +{ + k_EGameSearchErrorCode_OK = 1, + k_EGameSearchErrorCode_Failed_Search_Already_In_Progress = 2, + k_EGameSearchErrorCode_Failed_No_Search_In_Progress = 3, + k_EGameSearchErrorCode_Failed_Not_Lobby_Leader = 4, // if not the lobby leader can not call SearchForGameWithLobby + k_EGameSearchErrorCode_Failed_No_Host_Available = 5, // no host is available that matches those search params + k_EGameSearchErrorCode_Failed_Search_Params_Invalid = 6, // search params are invalid + k_EGameSearchErrorCode_Failed_Offline = 7, // offline, could not communicate with server + k_EGameSearchErrorCode_Failed_NotAuthorized = 8, // either the user or the application does not have priveledges to do this + k_EGameSearchErrorCode_Failed_Unknown_Error = 9, // unknown error +}; + +enum EPlayerResult_t +{ + k_EPlayerResultFailedToConnect = 1, // failed to connect after confirming + k_EPlayerResultAbandoned = 2, // quit game without completing it + k_EPlayerResultKicked = 3, // kicked by other players/moderator/server rules + k_EPlayerResultIncomplete = 4, // player stayed to end but game did not conclude successfully ( nofault to player ) + k_EPlayerResultCompleted = 5, // player completed game +}; + +// Define compile time assert macros to let us validate the structure sizes. +#define VALVE_COMPILE_TIME_ASSERT( pred ) typedef char compile_time_assert_type[(pred) ? 1 : -1]; + +#if defined(__linux__) || defined(__APPLE__) +// The 32-bit version of gcc has the alignment requirement for uint64 and double set to +// 4 meaning that even with #pragma pack(8) these types will only be four-byte aligned. +// The 64-bit version of gcc has the alignment requirement for these types set to +// 8 meaning that unless we use #pragma pack(4) our structures will get bigger. +// The 64-bit structure packing has to match the 32-bit structure packing for each platform. +#define VALVE_CALLBACK_PACK_SMALL +#else +#define VALVE_CALLBACK_PACK_LARGE +#endif + +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error ??? +#endif + +typedef struct ValvePackingSentinel_t +{ + uint32 m_u32; + uint64 m_u64; + uint16 m_u16; + double m_d; +} ValvePackingSentinel_t; + +#pragma pack( pop ) + + +#if defined(VALVE_CALLBACK_PACK_SMALL) +VALVE_COMPILE_TIME_ASSERT( sizeof(ValvePackingSentinel_t) == 24 ) +#elif defined(VALVE_CALLBACK_PACK_LARGE) +VALVE_COMPILE_TIME_ASSERT( sizeof(ValvePackingSentinel_t) == 32 ) +#else +#error ??? +#endif + +#endif // STEAMCLIENTPUBLIC_H diff --git a/public/steam/steamdatagram_tickets.h b/public/steam/steamdatagram_tickets.h new file mode 100644 index 0000000..2c40f90 --- /dev/null +++ b/public/steam/steamdatagram_tickets.h @@ -0,0 +1,286 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Types and utilities for handling steam datagram tickets. These are +// useful for both the client and the backend ticket generating authority. +// +//============================================================================= + +#ifndef STEAMDATAGRAM_TICKETS_H +#define STEAMDATAGRAM_TICKETS_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef assert + #include +#endif + +#include +#include "steamnetworkingtypes.h" + +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error "Must define VALVE_CALLBACK_PACK_SMALL or VALVE_CALLBACK_PACK_LARGE" +#endif + +/// Max length of serialized auth ticket. This is important so that we +/// can ensure that we always fit into a single UDP datagram (along with +/// other certs and signatures) and keep the implementation simple. +const size_t k_cbSteamDatagramMaxSerializedTicket = 512; + +/// Network-routable identifier for a service. This is an intentionally +/// opaque byte blob. The relays know how to use this to forward it on +/// to the intended destination, but otherwise clients really should not +/// need to know what's inside. (Indeed, we don't really want them to +/// know, as it could reveal information useful to an attacker.) +struct SteamDatagramHostedAddress +{ + + // Size of data blob. + int m_cbSize; + + // Opaque data + char m_data[ 128 ]; + + // Reset to empty state + void Clear() { memset( this, 0, sizeof(*this) ); } + + // Parse the data center out of the blob. + SteamNetworkingPOPID GetPopID() const { return CalculateSteamNetworkingPOPIDFromString( m_data ); } + + /// Set a dummy routing blob with a hardcoded IP:port. You should only use + /// this in a dev environment, since the address is in plaintext! + /// In production this information should come from the server, + /// using ISteamNetworkingSockets::GetHostedDedicatedServerAddress + void SetDevAddress( uint32 nIP, uint16 nPort, SteamNetworkingPOPID popid = 0 ) + { + GetSteamNetworkingLocationPOPStringFromID( popid, m_data ); + m_cbSize = 4; + m_data[m_cbSize++] = 1; + m_data[m_cbSize++] = 1; + m_data[m_cbSize++] = char(nPort); + m_data[m_cbSize++] = char(nPort>>8); + m_data[m_cbSize++] = char(nIP); + m_data[m_cbSize++] = char(nIP>>8); + m_data[m_cbSize++] = char(nIP>>16); + m_data[m_cbSize++] = char(nIP>>24); + } + + /// Convert to/from std::string (or anything that acts like it). + /// Useful for interfacing with google protobuf. It's a template + /// mainly so that we don't have to include in the header. + /// Note: by "string", we don't mean that it's text. It's a binary + /// blob, and it might have zeros in it. (std::string can handle that.) + template bool SetFromStdString( const T &str ) + { + if ( str.length() >= sizeof(m_data) ) + { + m_cbSize = 0; + return false; + } + m_cbSize = (int)str.length(); + memcpy( m_data, str.c_str(), m_cbSize ); + return true; + } + template void GetAsStdString( T *str ) const + { + str->assign( m_data, m_cbSize ); + } +}; + +/// Ticket used to gain access to the relay network. +struct SteamDatagramRelayAuthTicket +{ + SteamDatagramRelayAuthTicket() { Clear(); } + + /// Reset all fields + void Clear() { memset( this, 0, sizeof(*this) ); m_nRestrictToVirtualPort = -1; } + + /// Identity of the gameserver we want to talk to. This is required. + SteamNetworkingIdentity m_identityGameserver; + + /// Identity of the person who was authorized. This is required. + SteamNetworkingIdentity m_identityAuthorizedClient; + + /// SteamID is authorized to send from a particular public IP. If this + /// is 0, then the sender is not restricted to a particular IP. + /// + /// Recommend to leave this set to zero. + uint32 m_unPublicIP; + + /// Time when the ticket expires. Recommended: take the current + /// time and add 6 hours, or maybe a bit longer if your gameplay + /// sessions are longer. + /// + /// NOTE: relays may reject tickets with expiry times excessively + /// far in the future, so contact us if you wish to use an expiry + /// longer than, say, 24 hours. + RTime32 m_rtimeTicketExpiry; + + /// Routing information where the gameserver is listening for + /// relayed traffic. You should fill this in when generating + /// a ticket. + /// + /// When generating tickets on your backend: + /// - In production: The gameserver knows the proper routing + /// information, so you need to call + /// ISteamNetworkingSockets::GetHostedDedicatedServerAddress + /// and send the info to your backend. + /// - In development, you will need to provide public IP + /// of the server using SteamDatagramServiceNetID::SetDevAddress. + /// Relays need to be able to send UDP + /// packets to this server. Since it's very likely that + /// your server is behind a firewall/NAT, make sure that + /// the address is the one that the outside world can use. + /// The traffic from the relays will be "unsolicited", so + /// stateful firewalls won't work -- you will probably have + /// to set up an explicit port forward. + /// On the client: + /// - this field will always be blank. + SteamDatagramHostedAddress m_routing; + + /// App ID this is for. This is required, and should be the + /// App ID the client is running. (Even if your gameserver + /// uses a different App ID.) + uint32 m_nAppID; + + /// Restrict this ticket to be used for a particular virtual port? + /// Set to -1 to allow any virtual port. + /// + /// This is useful as a security measure, and also so the client will + /// use the right ticket (which might have extra fields that are useful + /// for proper analytics), if the client happens to have more than one + /// appropriate ticket. + /// + /// Note: if a client has more that one acceptable ticket, they will + /// always use the one expiring the latest. + int m_nRestrictToVirtualPort; + + // + // Extra fields. + // + // These are collected for backend analytics. For example, you might + // send a MatchID so that all of the records for a particular match can + // be located. Or send a game mode field so that you can compare + // the network characteristics of different game modes. + // + // (At the time of this writing we don't have a way to expose the data + // we collect to partners, but we hope to in the future so that you can + // get visibility into network conditions.) + // + + struct ExtraField + { + enum EType + { + k_EType_String, + k_EType_Int, // For most small integral values. Uses google protobuf sint64, so it's small on the wire. WARNING: In some places this value may be transmitted in JSON, in which case precision may be lost in backend analytics. Don't use this for an "identifier", use it for a scalar quantity. + k_EType_Fixed64, // 64 arbitrary bits. This value is treated as an "identifier". In places where JSON format is used, it will be serialized as a string. No aggregation / analytics can be performed on this value. + }; + int /* EType */ m_eType; + char m_szName[28]; + + union { + char m_szStringValue[128]; + int64 m_nIntValue; + uint64 m_nFixed64Value; + }; + }; + enum { k_nMaxExtraFields = 16 }; + int m_nExtraFields; + ExtraField m_vecExtraFields[ k_nMaxExtraFields ]; + + /// Helper to add an extra field in a single call + void AddExtraField_Int( const char *pszName, int64 val ) + { + ExtraField *p = AddExtraField( pszName, ExtraField::k_EType_Int ); + if ( p ) + p->m_nIntValue = val; + } + void AddExtraField_Fixed64( const char *pszName, uint64 val ) + { + ExtraField *p = AddExtraField( pszName, ExtraField::k_EType_Fixed64 ); + if ( p ) + p->m_nFixed64Value = val; + } + void AddExtraField_String( const char *pszName, const char *val ) + { + ExtraField *p = AddExtraField( pszName, ExtraField::k_EType_String ); + if ( p ) + { + size_t l = strlen( val ); + if ( l > sizeof(p->m_szStringValue)-1 ) + l = sizeof(p->m_szStringValue)-1; + memcpy( p->m_szStringValue, val, l ); + p->m_szStringValue[l] = '\0'; + } + } + +private: + ExtraField *AddExtraField( const char *pszName, ExtraField::EType eType ) + { + if ( m_nExtraFields >= k_nMaxExtraFields ) + { + assert( false ); + return NULL; + } + ExtraField *p = &m_vecExtraFields[ m_nExtraFields++ ]; + p->m_eType = eType; + + size_t l = strlen( pszName ); + if ( l > sizeof(p->m_szName)-1 ) + l = sizeof(p->m_szName)-1; + memcpy( p->m_szName, pszName, l ); + p->m_szName[l] = '\0'; + return p; + } +}; + +#pragma pack(pop) + +/// Max size of user data blob +const size_t k_cbMaxSteamDatagramGameCoordinatorServerLoginAppData = 2048; + +/// Max size of serialized data blob +const size_t k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized = 4096; + +/// Structure that describes a gameserver attempting to authenticate +/// with your central server allocator / matchmaking service ("game coordinator"). +/// This is useful because the game coordinator needs to know: +/// +/// - What data center is the gameserver running in? +/// - The routing blob of the gameserver +/// - Is the gameserver actually trusted? +/// +/// Using this structure, you can securely communicate this information +/// to your server, and you can do this WITHOUT maintaining any +/// whitelists or tables of IP addresses. +/// +/// See ISteamNetworkingSockets::GetGameCoordinatorServerLogin +struct SteamDatagramGameCoordinatorServerLogin +{ + /// Server's identity + SteamNetworkingIdentity m_identity; + + /// Routing info. Note that this includes the POPID + SteamDatagramHostedAddress m_routing; + + /// AppID that the server thinks it is running + AppId_t m_nAppID; + + /// Unix timestamp when this was generated + RTime32 m_rtime; + + /// Size of application data + int m_cbAppData; + + /// Application data. This is any additional information + /// that you need to identify the server not contained above. + /// (E.g. perhaps a public IP as seen by the coordinator service.) + char m_appData[ k_cbMaxSteamDatagramGameCoordinatorServerLoginAppData ]; +}; + +#endif // STEAMDATAGRAM_TICKETS_H diff --git a/public/steam/steamencryptedappticket.h b/public/steam/steamencryptedappticket.h new file mode 100644 index 0000000..bedc07b --- /dev/null +++ b/public/steam/steamencryptedappticket.h @@ -0,0 +1,34 @@ +//========= Copyright 1996-2010, Valve LLC, All rights reserved. ============ +// +// Purpose: utilities to decode/decrypt a ticket from the +// ISteamUser::RequestEncryptedAppTicket, ISteamUser::GetEncryptedAppTicket API +// +// To use: declare CSteamEncryptedAppTicket, then call BDecryptTicket +// if BDecryptTicket returns true, other accessors are valid +// +//============================================================================= + +#include "steam_api.h" + +static const int k_nSteamEncryptedAppTicketSymmetricKeyLen = 32; + + +S_API bool SteamEncryptedAppTicket_BDecryptTicket( const uint8 *rgubTicketEncrypted, uint32 cubTicketEncrypted, + uint8 *rgubTicketDecrypted, uint32 *pcubTicketDecrypted, + const uint8 rgubKey[k_nSteamEncryptedAppTicketSymmetricKeyLen], int cubKey ); + +S_API bool SteamEncryptedAppTicket_BIsTicketForApp( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted, AppId_t nAppID ); + +S_API RTime32 SteamEncryptedAppTicket_GetTicketIssueTime( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted ); + +S_API void SteamEncryptedAppTicket_GetTicketSteamID( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted, CSteamID *psteamID ); + +S_API AppId_t SteamEncryptedAppTicket_GetTicketAppID( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted ); + +S_API bool SteamEncryptedAppTicket_BUserOwnsAppInTicket( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted, AppId_t nAppID ); + +S_API bool SteamEncryptedAppTicket_BUserIsVacBanned( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted ); + +S_API const uint8 *SteamEncryptedAppTicket_GetUserVariableData( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted, uint32 *pcubUserData ); + +S_API bool SteamEncryptedAppTicket_BIsTicketSigned( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted, const uint8 *pubRSAKey, uint32 cubRSAKey ); diff --git a/public/steam/steamhttpenums.h b/public/steam/steamhttpenums.h new file mode 100644 index 0000000..d95f195 --- /dev/null +++ b/public/steam/steamhttpenums.h @@ -0,0 +1,98 @@ +//====== Copyright 1996-2010, Valve Corporation, All rights reserved. ======= +// +// Purpose: HTTP related enums, stuff that is shared by both clients and servers, and our +// UI projects goes here. +// +//============================================================================= + +#ifndef STEAMHTTPENUMS_H +#define STEAMHTTPENUMS_H +#ifdef _WIN32 +#pragma once +#endif + +// HTTP related types + +// This enum is used in client API methods, do not re-number existing values. +enum EHTTPMethod +{ + k_EHTTPMethodInvalid = 0, + k_EHTTPMethodGET, + k_EHTTPMethodHEAD, + k_EHTTPMethodPOST, + k_EHTTPMethodPUT, + k_EHTTPMethodDELETE, + k_EHTTPMethodOPTIONS, + k_EHTTPMethodPATCH, + + // The remaining HTTP methods are not yet supported, per rfc2616 section 5.1.1 only GET and HEAD are required for + // a compliant general purpose server. We'll likely add more as we find uses for them. + + // k_EHTTPMethodTRACE, + // k_EHTTPMethodCONNECT +}; + + +// HTTP Status codes that the server can send in response to a request, see rfc2616 section 10.3 for descriptions +// of each of these. +enum EHTTPStatusCode +{ + // Invalid status code (this isn't defined in HTTP, used to indicate unset in our code) + k_EHTTPStatusCodeInvalid = 0, + + // Informational codes + k_EHTTPStatusCode100Continue = 100, + k_EHTTPStatusCode101SwitchingProtocols = 101, + + // Success codes + k_EHTTPStatusCode200OK = 200, + k_EHTTPStatusCode201Created = 201, + k_EHTTPStatusCode202Accepted = 202, + k_EHTTPStatusCode203NonAuthoritative = 203, + k_EHTTPStatusCode204NoContent = 204, + k_EHTTPStatusCode205ResetContent = 205, + k_EHTTPStatusCode206PartialContent = 206, + + // Redirection codes + k_EHTTPStatusCode300MultipleChoices = 300, + k_EHTTPStatusCode301MovedPermanently = 301, + k_EHTTPStatusCode302Found = 302, + k_EHTTPStatusCode303SeeOther = 303, + k_EHTTPStatusCode304NotModified = 304, + k_EHTTPStatusCode305UseProxy = 305, + //k_EHTTPStatusCode306Unused = 306, (used in old HTTP spec, now unused in 1.1) + k_EHTTPStatusCode307TemporaryRedirect = 307, + + // Error codes + k_EHTTPStatusCode400BadRequest = 400, + k_EHTTPStatusCode401Unauthorized = 401, // You probably want 403 or something else. 401 implies you're sending a WWW-Authenticate header and the client can sent an Authorization header in response. + k_EHTTPStatusCode402PaymentRequired = 402, // This is reserved for future HTTP specs, not really supported by clients + k_EHTTPStatusCode403Forbidden = 403, + k_EHTTPStatusCode404NotFound = 404, + k_EHTTPStatusCode405MethodNotAllowed = 405, + k_EHTTPStatusCode406NotAcceptable = 406, + k_EHTTPStatusCode407ProxyAuthRequired = 407, + k_EHTTPStatusCode408RequestTimeout = 408, + k_EHTTPStatusCode409Conflict = 409, + k_EHTTPStatusCode410Gone = 410, + k_EHTTPStatusCode411LengthRequired = 411, + k_EHTTPStatusCode412PreconditionFailed = 412, + k_EHTTPStatusCode413RequestEntityTooLarge = 413, + k_EHTTPStatusCode414RequestURITooLong = 414, + k_EHTTPStatusCode415UnsupportedMediaType = 415, + k_EHTTPStatusCode416RequestedRangeNotSatisfiable = 416, + k_EHTTPStatusCode417ExpectationFailed = 417, + k_EHTTPStatusCode4xxUnknown = 418, // 418 is reserved, so we'll use it to mean unknown + k_EHTTPStatusCode429TooManyRequests = 429, + + // Server error codes + k_EHTTPStatusCode500InternalServerError = 500, + k_EHTTPStatusCode501NotImplemented = 501, + k_EHTTPStatusCode502BadGateway = 502, + k_EHTTPStatusCode503ServiceUnavailable = 503, + k_EHTTPStatusCode504GatewayTimeout = 504, + k_EHTTPStatusCode505HTTPVersionNotSupported = 505, + k_EHTTPStatusCode5xxUnknown = 599, +}; + +#endif // STEAMHTTPENUMS_H \ No newline at end of file diff --git a/public/steam/steamnetworkingtypes.h b/public/steam/steamnetworkingtypes.h new file mode 100644 index 0000000..f41a857 --- /dev/null +++ b/public/steam/steamnetworkingtypes.h @@ -0,0 +1,1159 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Purpose: misc networking utilities +// +//============================================================================= + +#ifndef STEAMNETWORKINGTYPES +#define STEAMNETWORKINGTYPES +#ifdef _WIN32 +#pragma once +#endif + +#include + +//---------------------------------------- +// SteamNetworkingSockets library config +// Compiling in Steam public branch. +#define STEAMNETWORKINGSOCKETS_STEAM +#ifdef STEAMNETWORKINGSOCKETS_STATIC_LINK + #define STEAMNETWORKINGSOCKETS_INTERFACE extern +#endif +#define STEAMNETWORKINGSOCKETS_STEAMCLIENT +#define STEAMNETWORKINGSOCKETS_ENABLE_SDR +#define STEAMNETWORKINGSOCKETS_ENABLE_P2P +#include "steam_api_common.h" +// +//---------------------------------------- + + +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error "Must define VALVE_CALLBACK_PACK_SMALL or VALVE_CALLBACK_PACK_LARGE" +#endif + +struct SteamDatagramRelayAuthTicket; +struct SteamDatagramHostedAddress; +struct SteamDatagramGameCoordinatorServerLogin; +struct SteamNetConnectionStatusChangedCallback_t; +struct SteamNetAuthenticationStatus_t; +struct SteamRelayNetworkStatus_t; + +/// Handle used to identify a connection to a remote host. +typedef uint32 HSteamNetConnection; +const HSteamNetConnection k_HSteamNetConnection_Invalid = 0; + +/// Handle used to identify a "listen socket". +typedef uint32 HSteamListenSocket; +const HSteamListenSocket k_HSteamListenSocket_Invalid = 0; + +/// Max length of diagnostic error message +const int k_cchMaxSteamNetworkingErrMsg = 1024; + +/// Used to return English-language diagnostic error messages to caller. +/// (For debugging or spewing to a console, etc. Not intended for UI.) +typedef char SteamNetworkingErrMsg[ k_cchMaxSteamNetworkingErrMsg ]; + +/// Identifier used for a network location point of presence. (E.g. a Valve data center.) +/// Typically you won't need to directly manipulate these. +typedef uint32 SteamNetworkingPOPID; + +/// A local timestamp. You can subtract two timestamps to get the number of elapsed +/// microseconds. This is guaranteed to increase over time during the lifetime +/// of a process, but not globally across runs. You don't need to worry about +/// the value wrapping around. Note that the underlying clock might not actually have +/// microsecond *resolution*. +typedef int64 SteamNetworkingMicroseconds; + +/// Describe the status of a particular network resource +enum ESteamNetworkingAvailability +{ + // Negative values indicate a problem. + // + // In general, we will not automatically retry unless you take some action that + // depends on of requests this resource, such as querying the status, attempting + // to initiate a connection, receive a connection, etc. If you do not take any + // action at all, we do not automatically retry in the background. + k_ESteamNetworkingAvailability_CannotTry = -102, // A dependent resource is missing, so this service is unavailable. (E.g. we cannot talk to routers because Internet is down or we don't have the network config.) + k_ESteamNetworkingAvailability_Failed = -101, // We have tried for enough time that we would expect to have been successful by now. We have never been successful + k_ESteamNetworkingAvailability_Previously = -100, // We tried and were successful at one time, but now it looks like we have a problem + + k_ESteamNetworkingAvailability_Retrying = -10, // We previously failed and are currently retrying + + // Not a problem, but not ready either + k_ESteamNetworkingAvailability_NeverTried = 1, // We don't know because we haven't ever checked/tried + k_ESteamNetworkingAvailability_Waiting = 2, // We're waiting on a dependent resource to be acquired. (E.g. we cannot obtain a cert until we are logged into Steam. We cannot measure latency to relays until we have the network config.) + k_ESteamNetworkingAvailability_Attempting = 3, // We're actively trying now, but are not yet successful. + + k_ESteamNetworkingAvailability_Current = 100, // Resource is online/available + + + k_ESteamNetworkingAvailability_Unknown = 0, // Internal dummy/sentinel, or value is not applicable in this context + k_ESteamNetworkingAvailability__Force32bit = 0x7fffffff, +}; + +// +// Describing network hosts +// + +/// Different methods of describing the identity of a network host +enum ESteamNetworkingIdentityType +{ + // Dummy/empty/invalid. + // Plese note that if we parse a string that we don't recognize + // but that appears reasonable, we will NOT use this type. Instead + // we'll use k_ESteamNetworkingIdentityType_UnknownType. + k_ESteamNetworkingIdentityType_Invalid = 0, + + // + // Basic platform-specific identifiers. + // + k_ESteamNetworkingIdentityType_SteamID = 16, // 64-bit CSteamID + + // + // Special identifiers. + // + + // Use their IP address (and port) as their "identity". + // These types of identities are always unauthenticated. + // They are useful for porting plain sockets code, and other + // situations where you don't care about authentication. In this + // case, the local identity will be "localhost", + // and the remote address will be their network address. + // + // We use the same type for either IPv4 or IPv6, and + // the address is always store as IPv6. We use IPv4 + // mapped addresses to handle IPv4. + k_ESteamNetworkingIdentityType_IPAddress = 1, + + // Generic string/binary blobs. It's up to your app to interpret this. + // This library can tell you if the remote host presented a certificate + // signed by somebody you have chosen to trust, with this identity on it. + // It's up to you to ultimately decide what this identity means. + k_ESteamNetworkingIdentityType_GenericString = 2, + k_ESteamNetworkingIdentityType_GenericBytes = 3, + + // This identity type is used when we parse a string that looks like is a + // valid identity, just of a kind that we don't recognize. In this case, we + // can often still communicate with the peer! Allowing such identities + // for types we do not recognize useful is very useful for forward + // compatibility. + k_ESteamNetworkingIdentityType_UnknownType = 4, + + // Make sure this enum is stored in an int. + k_ESteamNetworkingIdentityType__Force32bit = 0x7fffffff, +}; + +#pragma pack(push,1) + +/// Store an IP and port. IPv6 is always used; IPv4 is represented using +/// "IPv4-mapped" addresses: IPv4 aa.bb.cc.dd => IPv6 ::ffff:aabb:ccdd +/// (RFC 4291 section 2.5.5.2.) +struct SteamNetworkingIPAddr +{ + void Clear(); // Set everything to zero. E.g. [::]:0 + bool IsIPv6AllZeros() const; // Return true if the IP is ::0. (Doesn't check port.) + void SetIPv6( const uint8 *ipv6, uint16 nPort ); // Set IPv6 address. IP is interpreted as bytes, so there are no endian issues. (Same as inaddr_in6.) The IP can be a mapped IPv4 address + void SetIPv4( uint32 nIP, uint16 nPort ); // Sets to IPv4 mapped address. IP and port are in host byte order. + bool IsIPv4() const; // Return true if IP is mapped IPv4 + uint32 GetIPv4() const; // Returns IP in host byte order (e.g. aa.bb.cc.dd as 0xaabbccdd). Returns 0 if IP is not mapped IPv4. + void SetIPv6LocalHost( uint16 nPort = 0); // Set to the IPv6 localhost address ::1, and the specified port. + bool IsLocalHost() const; // Return true if this identity is localhost. (Either IPv6 ::1, or IPv4 127.0.0.1) + + // Max length of the buffer needed to hold IP formatted using ToString, including '\0' + // ([0123:4567:89ab:cdef:0123:4567:89ab:cdef]:12345) + enum { k_cchMaxString = 48 }; + + /// Print to a string, with or without the port. Mapped IPv4 addresses are printed + /// as dotted decimal (12.34.56.78), otherwise this will print the canonical + /// form according to RFC5952. If you include the port, IPv6 will be surrounded by + /// brackets, e.g. [::1:2]:80. Your buffer should be at least k_cchMaxString bytes + /// to avoid truncation + inline void ToString( char *buf, size_t cbBuf, bool bWithPort ) const; + + /// Parse an IP address and optional port. If a port is not present, it is set to 0. + /// (This means that you cannot tell if a zero port was explicitly specified.) + inline bool ParseString( const char *pszStr ); + + union + { + uint8 m_ipv6[ 16 ]; + struct // IPv4 "mapped address" (rfc4038 section 4.2) + { + uint64 m_8zeros; + uint16 m_0000; + uint16 m_ffff; + uint8 m_ip[ 4 ]; // NOTE: As bytes, i.e. network byte order + } m_ipv4; + }; + uint16 m_port; // Host byte order + + /// See if two addresses are identical + bool operator==(const SteamNetworkingIPAddr &x ) const; +}; + +/// An abstract way to represent the identity of a network host +struct SteamNetworkingIdentity +{ + /// Type of identity. + ESteamNetworkingIdentityType m_eType; + + // + // Get/Set in various formats. + // + + void Clear(); + bool IsInvalid() const; // Return true if we are the invalid type. Does not make any other validity checks (e.g. is SteamID actually valid) + + void SetSteamID( CSteamID steamID ); + CSteamID GetSteamID() const; // Return black CSteamID (!IsValid()) if identity is not a SteamID + void SetSteamID64( uint64 steamID ); // Takes SteamID as raw 64-bit number + uint64 GetSteamID64() const; // Returns 0 if identity is not SteamID + + void SetIPAddr( const SteamNetworkingIPAddr &addr ); // Set to specified IP:port + const SteamNetworkingIPAddr *GetIPAddr() const; // returns null if we are not an IP address. + + // "localhost" is equivalent for many purposes to "anonymous." Our remote + // will identify us by the network address we use. + void SetLocalHost(); // Set to localhost. (We always use IPv6 ::1 for this, not 127.0.0.1) + bool IsLocalHost() const; // Return true if this identity is localhost. + + bool SetGenericString( const char *pszString ); // Returns false if invalid length + const char *GetGenericString() const; // Returns nullptr if not generic string type + + bool SetGenericBytes( const void *data, size_t cbLen ); // Returns false if invalid size. + const uint8 *GetGenericBytes( int &cbLen ) const; // Returns null if not generic bytes type + + /// See if two identities are identical + bool operator==(const SteamNetworkingIdentity &x ) const; + + /// Print to a human-readable string. This is suitable for debug messages + /// or any other time you need to encode the identity as a string. It has a + /// URL-like format (type:). Your buffer should be at least + /// k_cchMaxString bytes big to avoid truncation. + void ToString( char *buf, size_t cbBuf ) const; + + /// Parse back a string that was generated using ToString + bool ParseString( const char *pszStr ); + + // Max sizes + enum { + k_cchMaxString = 128, // Max length of the buffer needed to hold any identity, formatted in string format by ToString + k_cchMaxGenericString = 32, // Max length of the string for generic string identities. Including terminating '\0' + k_cbMaxGenericBytes = 32, + }; + + // + // Internal representation. Don't access this directly, use the accessors! + // + // Number of bytes that are relevant below. This MUST ALWAYS be + // set. (Use the accessors!) This is important to enable old code to work + // with new identity types. + int m_cbSize; + union { + uint64 m_steamID64; + char m_szGenericString[ k_cchMaxGenericString ]; + uint8 m_genericBytes[ k_cbMaxGenericBytes ]; + char m_szUnknownRawString[ k_cchMaxString ]; + SteamNetworkingIPAddr m_ip; + uint32 m_reserved[ 32 ]; // Pad structure to leave easy room for future expansion + }; +}; +#pragma pack(pop) + +// +// Connection status +// + +/// High level connection status +enum ESteamNetworkingConnectionState +{ + + /// Dummy value used to indicate an error condition in the API. + /// Specified connection doesn't exist or has already been closed. + k_ESteamNetworkingConnectionState_None = 0, + + /// We are trying to establish whether peers can talk to each other, + /// whether they WANT to talk to each other, perform basic auth, + /// and exchange crypt keys. + /// + /// - For connections on the "client" side (initiated locally): + /// We're in the process of trying to establish a connection. + /// Depending on the connection type, we might not know who they are. + /// Note that it is not possible to tell if we are waiting on the + /// network to complete handshake packets, or for the application layer + /// to accept the connection. + /// + /// - For connections on the "server" side (accepted through listen socket): + /// We have completed some basic handshake and the client has presented + /// some proof of identity. The connection is ready to be accepted + /// using AcceptConnection(). + /// + /// In either case, any unreliable packets sent now are almost certain + /// to be dropped. Attempts to receive packets are guaranteed to fail. + /// You may send messages if the send mode allows for them to be queued. + /// but if you close the connection before the connection is actually + /// established, any queued messages will be discarded immediately. + /// (We will not attempt to flush the queue and confirm delivery to the + /// remote host, which ordinarily happens when a connection is closed.) + k_ESteamNetworkingConnectionState_Connecting = 1, + + /// Some connection types use a back channel or trusted 3rd party + /// for earliest communication. If the server accepts the connection, + /// then these connections switch into the rendezvous state. During this + /// state, we still have not yet established an end-to-end route (through + /// the relay network), and so if you send any messages unreliable, they + /// are going to be discarded. + k_ESteamNetworkingConnectionState_FindingRoute = 2, + + /// We've received communications from our peer (and we know + /// who they are) and are all good. If you close the connection now, + /// we will make our best effort to flush out any reliable sent data that + /// has not been acknowledged by the peer. (But note that this happens + /// from within the application process, so unlike a TCP connection, you are + /// not totally handing it off to the operating system to deal with it.) + k_ESteamNetworkingConnectionState_Connected = 3, + + /// Connection has been closed by our peer, but not closed locally. + /// The connection still exists from an API perspective. You must close the + /// handle to free up resources. If there are any messages in the inbound queue, + /// you may retrieve them. Otherwise, nothing may be done with the connection + /// except to close it. + /// + /// This stats is similar to CLOSE_WAIT in the TCP state machine. + k_ESteamNetworkingConnectionState_ClosedByPeer = 4, + + /// A disruption in the connection has been detected locally. (E.g. timeout, + /// local internet connection disrupted, etc.) + /// + /// The connection still exists from an API perspective. You must close the + /// handle to free up resources. + /// + /// Attempts to send further messages will fail. Any remaining received messages + /// in the queue are available. + k_ESteamNetworkingConnectionState_ProblemDetectedLocally = 5, + +// +// The following values are used internally and will not be returned by any API. +// We document them here to provide a little insight into the state machine that is used +// under the hood. +// + + /// We've disconnected on our side, and from an API perspective the connection is closed. + /// No more data may be sent or received. All reliable data has been flushed, or else + /// we've given up and discarded it. We do not yet know for sure that the peer knows + /// the connection has been closed, however, so we're just hanging around so that if we do + /// get a packet from them, we can send them the appropriate packets so that they can + /// know why the connection was closed (and not have to rely on a timeout, which makes + /// it appear as if something is wrong). + k_ESteamNetworkingConnectionState_FinWait = -1, + + /// We've disconnected on our side, and from an API perspective the connection is closed. + /// No more data may be sent or received. From a network perspective, however, on the wire, + /// we have not yet given any indication to the peer that the connection is closed. + /// We are in the process of flushing out the last bit of reliable data. Once that is done, + /// we will inform the peer that the connection has been closed, and transition to the + /// FinWait state. + /// + /// Note that no indication is given to the remote host that we have closed the connection, + /// until the data has been flushed. If the remote host attempts to send us data, we will + /// do whatever is necessary to keep the connection alive until it can be closed properly. + /// But in fact the data will be discarded, since there is no way for the application to + /// read it back. Typically this is not a problem, as application protocols that utilize + /// the lingering functionality are designed for the remote host to wait for the response + /// before sending any more data. + k_ESteamNetworkingConnectionState_Linger = -2, + + /// Connection is completely inactive and ready to be destroyed + k_ESteamNetworkingConnectionState_Dead = -3, + + k_ESteamNetworkingConnectionState__Force32Bit = 0x7fffffff +}; + +/// Enumerate various causes of connection termination. These are designed to work similar +/// to HTTP error codes: the numeric range gives you a rough classification as to the source +/// of the problem. +enum ESteamNetConnectionEnd +{ + // Invalid/sentinel value + k_ESteamNetConnectionEnd_Invalid = 0, + + // + // Application codes. These are the values you will pass to + // ISteamNetworkingSockets::CloseConnection. You can use these codes if + // you want to plumb through application-specific reason codes. If you don't + // need this facility, feel free to always pass + // k_ESteamNetConnectionEnd_App_Generic. + // + // The distinction between "normal" and "exceptional" termination is + // one you may use if you find useful, but it's not necessary for you + // to do so. The only place where we distinguish between normal and + // exceptional is in connection analytics. If a significant + // proportion of connections terminates in an exceptional manner, + // this can trigger an alert. + // + + // 1xxx: Application ended the connection in a "usual" manner. + // E.g.: user intentionally disconnected from the server, + // gameplay ended normally, etc + k_ESteamNetConnectionEnd_App_Min = 1000, + k_ESteamNetConnectionEnd_App_Generic = k_ESteamNetConnectionEnd_App_Min, + // Use codes in this range for "normal" disconnection + k_ESteamNetConnectionEnd_App_Max = 1999, + + // 2xxx: Application ended the connection in some sort of exceptional + // or unusual manner that might indicate a bug or configuration + // issue. + // + k_ESteamNetConnectionEnd_AppException_Min = 2000, + k_ESteamNetConnectionEnd_AppException_Generic = k_ESteamNetConnectionEnd_AppException_Min, + // Use codes in this range for "unusual" disconnection + k_ESteamNetConnectionEnd_AppException_Max = 2999, + + // + // System codes. These will be returned by the system when + // the connection state is k_ESteamNetworkingConnectionState_ClosedByPeer + // or k_ESteamNetworkingConnectionState_ProblemDetectedLocally. It is + // illegal to pass a code in this range to ISteamNetworkingSockets::CloseConnection + // + + // 3xxx: Connection failed or ended because of problem with the + // local host or their connection to the Internet. + k_ESteamNetConnectionEnd_Local_Min = 3000, + + // You cannot do what you want to do because you're running in offline mode. + k_ESteamNetConnectionEnd_Local_OfflineMode = 3001, + + // We're having trouble contacting many (perhaps all) relays. + // Since it's unlikely that they all went offline at once, the best + // explanation is that we have a problem on our end. Note that we don't + // bother distinguishing between "many" and "all", because in practice, + // it takes time to detect a connection problem, and by the time + // the connection has timed out, we might not have been able to + // actively probe all of the relay clusters, even if we were able to + // contact them at one time. So this code just means that: + // + // * We don't have any recent successful communication with any relay. + // * We have evidence of recent failures to communicate with multiple relays. + k_ESteamNetConnectionEnd_Local_ManyRelayConnectivity = 3002, + + // A hosted server is having trouble talking to the relay + // that the client was using, so the problem is most likely + // on our end + k_ESteamNetConnectionEnd_Local_HostedServerPrimaryRelay = 3003, + + // We're not able to get the network config. This is + // *almost* always a local issue, since the network config + // comes from the CDN, which is pretty darn reliable. + k_ESteamNetConnectionEnd_Local_NetworkConfig = 3004, + + // Steam rejected our request because we don't have rights + // to do this. + k_ESteamNetConnectionEnd_Local_Rights = 3005, + + k_ESteamNetConnectionEnd_Local_Max = 3999, + + // 4xxx: Connection failed or ended, and it appears that the + // cause does NOT have to do with the local host or their + // connection to the Internet. It could be caused by the + // remote host, or it could be somewhere in between. + k_ESteamNetConnectionEnd_Remote_Min = 4000, + + // The connection was lost, and as far as we can tell our connection + // to relevant services (relays) has not been disrupted. This doesn't + // mean that the problem is "their fault", it just means that it doesn't + // appear that we are having network issues on our end. + k_ESteamNetConnectionEnd_Remote_Timeout = 4001, + + // Something was invalid with the cert or crypt handshake + // info you gave me, I don't understand or like your key types, + // etc. + k_ESteamNetConnectionEnd_Remote_BadCrypt = 4002, + + // You presented me with a cert that was I was able to parse + // and *technically* we could use encrypted communication. + // But there was a problem that prevents me from checking your identity + // or ensuring that somebody int he middle can't observe our communication. + // E.g.: - the CA key was missing (and I don't accept unsigned certs) + // - The CA key isn't one that I trust, + // - The cert doesn't was appropriately restricted by app, user, time, data center, etc. + // - The cert wasn't issued to you. + // - etc + k_ESteamNetConnectionEnd_Remote_BadCert = 4003, + + // We couldn't rendezvous with the remote host because + // they aren't logged into Steam + k_ESteamNetConnectionEnd_Remote_NotLoggedIn = 4004, + + // We couldn't rendezvous with the remote host because + // they aren't running the right application. + k_ESteamNetConnectionEnd_Remote_NotRunningApp = 4005, + + // Something wrong with the protocol version you are using. + // (Probably the code you are running is too old.) + k_ESteamNetConnectionEnd_Remote_BadProtocolVersion = 4006, + + k_ESteamNetConnectionEnd_Remote_Max = 4999, + + // 5xxx: Connection failed for some other reason. + k_ESteamNetConnectionEnd_Misc_Min = 5000, + + // A failure that isn't necessarily the result of a software bug, + // but that should happen rarely enough that it isn't worth specifically + // writing UI or making a localized message for. + // The debug string should contain further details. + k_ESteamNetConnectionEnd_Misc_Generic = 5001, + + // Generic failure that is most likely a software bug. + k_ESteamNetConnectionEnd_Misc_InternalError = 5002, + + // The connection to the remote host timed out, but we + // don't know if the problem is on our end, in the middle, + // or on their end. + k_ESteamNetConnectionEnd_Misc_Timeout = 5003, + + // We're having trouble talking to the relevant relay. + // We don't have enough information to say whether the + // problem is on our end or not. + k_ESteamNetConnectionEnd_Misc_RelayConnectivity = 5004, + + // There's some trouble talking to Steam. + k_ESteamNetConnectionEnd_Misc_SteamConnectivity = 5005, + + // A server in a dedicated hosting situation has no relay sessions + // active with which to talk back to a client. (It's the client's + // job to open and maintain those sessions.) + k_ESteamNetConnectionEnd_Misc_NoRelaySessionsToClient = 5006, + + k_ESteamNetConnectionEnd_Misc_Max = 5999, + + k_ESteamNetConnectionEnd__Force32Bit = 0x7fffffff +}; + +/// Max length, in bytes (including null terminator) of the reason string +/// when a connection is closed. +const int k_cchSteamNetworkingMaxConnectionCloseReason = 128; + +/// Max length, in bytes (include null terminator) of debug description +/// of a connection. +const int k_cchSteamNetworkingMaxConnectionDescription = 128; + +/// Describe the state of a connection. +struct SteamNetConnectionInfo_t +{ + + /// Who is on the other end? Depending on the connection type and phase of the connection, we might not know + SteamNetworkingIdentity m_identityRemote; + + /// Arbitrary user data set by the local application code + int64 m_nUserData; + + /// Handle to listen socket this was connected on, or k_HSteamListenSocket_Invalid if we initiated the connection + HSteamListenSocket m_hListenSocket; + + /// Remote address. Might be all 0's if we don't know it, or if this is N/A. + /// (E.g. Basically everything except direct UDP connection.) + SteamNetworkingIPAddr m_addrRemote; + uint16 m__pad1; + + /// What data center is the remote host in? (0 if we don't know.) + SteamNetworkingPOPID m_idPOPRemote; + + /// What relay are we using to communicate with the remote host? + /// (0 if not applicable.) + SteamNetworkingPOPID m_idPOPRelay; + + /// High level state of the connection + ESteamNetworkingConnectionState m_eState; + + /// Basic cause of the connection termination or problem. + /// See ESteamNetConnectionEnd for the values used + int m_eEndReason; + + /// Human-readable, but non-localized explanation for connection + /// termination or problem. This is intended for debugging / + /// diagnostic purposes only, not to display to users. It might + /// have some details specific to the issue. + char m_szEndDebug[ k_cchSteamNetworkingMaxConnectionCloseReason ]; + + /// Debug description. This includes the connection handle, + /// connection type (and peer information), and the app name. + /// This string is used in various internal logging messages + char m_szConnectionDescription[ k_cchSteamNetworkingMaxConnectionDescription ]; + + /// Internal stuff, room to change API easily + uint32 reserved[64]; +}; + +/// Quick connection state, pared down to something you could call +/// more frequently without it being too big of a perf hit. +struct SteamNetworkingQuickConnectionStatus +{ + + /// High level state of the connection + ESteamNetworkingConnectionState m_eState; + + /// Current ping (ms) + int m_nPing; + + /// Connection quality measured locally, 0...1. (Percentage of packets delivered + /// end-to-end in order). + float m_flConnectionQualityLocal; + + /// Packet delivery success rate as observed from remote host + float m_flConnectionQualityRemote; + + /// Current data rates from recent history. + float m_flOutPacketsPerSec; + float m_flOutBytesPerSec; + float m_flInPacketsPerSec; + float m_flInBytesPerSec; + + /// Estimate rate that we believe that we can send data to our peer. + /// Note that this could be significantly higher than m_flOutBytesPerSec, + /// meaning the capacity of the channel is higher than you are sending data. + /// (That's OK!) + int m_nSendRateBytesPerSecond; + + /// Number of bytes pending to be sent. This is data that you have recently + /// requested to be sent but has not yet actually been put on the wire. The + /// reliable number ALSO includes data that was previously placed on the wire, + /// but has now been scheduled for re-transmission. Thus, it's possible to + /// observe m_cbPendingReliable increasing between two checks, even if no + /// calls were made to send reliable data between the checks. Data that is + /// awaiting the nagle delay will appear in these numbers. + int m_cbPendingUnreliable; + int m_cbPendingReliable; + + /// Number of bytes of reliable data that has been placed the wire, but + /// for which we have not yet received an acknowledgment, and thus we may + /// have to re-transmit. + int m_cbSentUnackedReliable; + + /// If you asked us to send a message right now, how long would that message + /// sit in the queue before we actually started putting packets on the wire? + /// (And assuming Nagle does not cause any packets to be delayed.) + /// + /// In general, data that is sent by the application is limited by the + /// bandwidth of the channel. If you send data faster than this, it must + /// be queued and put on the wire at a metered rate. Even sending a small amount + /// of data (e.g. a few MTU, say ~3k) will require some of the data to be delayed + /// a bit. + /// + /// In general, the estimated delay will be approximately equal to + /// + /// ( m_cbPendingUnreliable+m_cbPendingReliable ) / m_nSendRateBytesPerSecond + /// + /// plus or minus one MTU. It depends on how much time has elapsed since the last + /// packet was put on the wire. For example, the queue might have *just* been emptied, + /// and the last packet placed on the wire, and we are exactly up against the send + /// rate limit. In that case we might need to wait for one packet's worth of time to + /// elapse before we can send again. On the other extreme, the queue might have data + /// in it waiting for Nagle. (This will always be less than one packet, because as soon + /// as we have a complete packet we would send it.) In that case, we might be ready + /// to send data now, and this value will be 0. + SteamNetworkingMicroseconds m_usecQueueTime; + + /// Internal stuff, room to change API easily + uint32 reserved[16]; +}; + +#pragma pack( pop ) + +// +// Network messages +// + +/// Max size of a single message that we can SEND. +/// Note: We might be wiling to receive larger messages, +/// and our peer might, too. +const int k_cbMaxSteamNetworkingSocketsMessageSizeSend = 512 * 1024; + +/// A message that has been received +struct SteamNetworkingMessage_t +{ + + /// Message payload + void *m_pData; + + /// Size of the payload. + uint32 m_cbSize; + + /// The connection this came from. (Not used when using the ISteamMessages interface) + HSteamNetConnection m_conn; + + /// Who sent this to us? + SteamNetworkingIdentity m_sender; + + /// The user data associated with the connection. + /// + /// This is *usually* the same as calling GetConnection() and then + /// fetching the user data associated with that connection, but for + /// the following subtle differences: + /// + /// - This user data will match the connection's user data at the time + /// is captured at the time the message is returned by the API. + /// If you subsequently change the userdata on the connection, + /// this won't be updated. + /// - This is an inline call, so it's *much* faster. + /// - You might have closed the connection, so fetching the user data + /// would not be possible. + int64 m_nConnUserData; + + /// Local timestamps when it was received + SteamNetworkingMicroseconds m_usecTimeReceived; + + /// Message number assigned by the sender + int64 m_nMessageNumber; + + /// Function used to free up m_pData. This mechanism exists so that + /// apps can create messages with buffers allocated from their own + /// heap, and pass them into the library. This function will + /// usually be something like: + /// + /// free( pMsg->m_pData ); + void (*m_pfnFreeData)( SteamNetworkingMessage_t *pMsg ); + + /// Function to used to decrement reference count and, if it's zero, release + /// the message. You should not normally need to access this directly. + /// (Use Release(), and don't set this.) + void (*m_pfnRelease)( SteamNetworkingMessage_t *pMsg ); + + /// The channel number the message was received on. + /// (Not used for messages received on "connections") + int m_nChannel; + + /// Pad to multiple of 8 bytes + int m___nPadDummy; + + #ifdef __cplusplus + + /// You MUST call this when you're done with the object, + /// to free up memory, etc. + inline void Release(); + + // For code compatibility, some accessors + inline uint32 GetSize() const { return m_cbSize; } + inline const void *GetData() const { return m_pData; } + inline int GetChannel() const { return m_nChannel; } + inline HSteamNetConnection GetConnection() const { return m_conn; } + inline int64 GetConnectionUserData() const { return m_nConnUserData; } + inline SteamNetworkingMicroseconds GetTimeReceived() const { return m_usecTimeReceived; } + inline int64 GetMessageNumber() const { return m_nMessageNumber; } + #endif +}; + +// +// Flags used to set options for message sending +// + +// Send the message unreliably. Can be lost. Messages *can* be larger than a +// single MTU (UDP packet), but there is no retransmission, so if any piece +// of the message is lost, the entire message will be dropped. +// +// The sending API does have some knowledge of the underlying connection, so +// if there is no NAT-traversal accomplished or there is a recognized adjustment +// happening on the connection, the packet will be batched until the connection +// is open again. +// +// Migration note: This is not exactly the same as k_EP2PSendUnreliable! You +// probably want k_ESteamNetworkingSendType_UnreliableNoNagle +const int k_nSteamNetworkingSend_Unreliable = 0; + +// Disable Nagle's algorithm. +// By default, Nagle's algorithm is applied to all outbound messages. This means +// that the message will NOT be sent immediately, in case further messages are +// sent soon after you send this, which can be grouped together. Any time there +// is enough buffered data to fill a packet, the packets will be pushed out immediately, +// but partially-full packets not be sent until the Nagle timer expires. See +// ISteamNetworkingSockets::FlushMessagesOnConnection, ISteamNetworkingMessages::FlushMessagesToUser +// +// NOTE: Don't just send every message without Nagle because you want packets to get there +// quicker. Make sure you understand the problem that Nagle is solving before disabling it. +// If you are sending small messages, often many at the same time, then it is very likely that +// it will be more efficient to leave Nagle enabled. A typical proper use of this flag is +// when you are sending what you know will be the last message sent for a while (e.g. the last +// in the server simulation tick to a particular client), and you use this flag to flush all +// messages. +const int k_nSteamNetworkingSend_NoNagle = 1; + +// Send a message unreliably, bypassing Nagle's algorithm for this message and any messages +// currently pending on the Nagle timer. This is equivalent to using k_ESteamNetworkingSend_Unreliable +// and then immediately flushing the messages using ISteamNetworkingSockets::FlushMessagesOnConnection +// or ISteamNetworkingMessages::FlushMessagesToUser. (But using this flag is more efficient since you +// only make one API call.) +const int k_nSteamNetworkingSend_UnreliableNoNagle = k_nSteamNetworkingSend_Unreliable|k_nSteamNetworkingSend_NoNagle; + +// If the message cannot be sent very soon (because the connection is still doing some initial +// handshaking, route negotiations, etc), then just drop it. This is only applicable for unreliable +// messages. Using this flag on reliable messages is invalid. +const int k_nSteamNetworkingSend_NoDelay = 4; + +// Send an unreliable message, but if it cannot be sent relatively quickly, just drop it instead of queuing it. +// This is useful for messages that are not useful if they are excessively delayed, such as voice data. +// NOTE: The Nagle algorithm is not used, and if the message is not dropped, any messages waiting on the +// Nagle timer are immediately flushed. +// +// A message will be dropped under the following circumstances: +// - the connection is not fully connected. (E.g. the "Connecting" or "FindingRoute" states) +// - there is a sufficiently large number of messages queued up already such that the current message +// will not be placed on the wire in the next ~200ms or so. +// +// if a message is dropped for these reasons, k_EResultIgnored will be returned. +const int k_nSteamNetworkingSend_UnreliableNoDelay = k_nSteamNetworkingSend_Unreliable|k_nSteamNetworkingSend_NoDelay|k_nSteamNetworkingSend_NoNagle; + +// Reliable message send. Can send up to k_cbMaxSteamNetworkingSocketsMessageSizeSend bytes in a single message. +// Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for +// efficient sends of large chunks of data. +// +// The Nagle algorithm is used. See notes on k_ESteamNetworkingSendType_Unreliable for more details. +// See k_ESteamNetworkingSendType_ReliableNoNagle, ISteamNetworkingSockets::FlushMessagesOnConnection, +// ISteamNetworkingMessages::FlushMessagesToUser +// +// Migration note: This is NOT the same as k_EP2PSendReliable, it's more like k_EP2PSendReliableWithBuffering +const int k_nSteamNetworkingSend_Reliable = 8; + +// Send a message reliably, but bypass Nagle's algorithm. +// +// Migration note: This is equivalent to k_EP2PSendReliable +const int k_nSteamNetworkingSend_ReliableNoNagle = k_nSteamNetworkingSend_Reliable|k_nSteamNetworkingSend_NoNagle; + +// +// Ping location / measurement +// + +/// Object that describes a "location" on the Internet with sufficient +/// detail that we can reasonably estimate an upper bound on the ping between +/// the two hosts, even if a direct route between the hosts is not possible, +/// and the connection must be routed through the Steam Datagram Relay network. +/// This does not contain any information that identifies the host. Indeed, +/// if two hosts are in the same building or otherwise have nearly identical +/// networking characteristics, then it's valid to use the same location +/// object for both of them. +/// +/// NOTE: This object should only be used in the same process! Do not serialize it, +/// send it over the wire, or persist it in a file or database! If you need +/// to do that, convert it to a string representation using the methods in +/// ISteamNetworkingUtils(). +struct SteamNetworkPingLocation_t +{ + uint8 m_data[ 512 ]; +}; + +/// Max possible length of a ping location, in string format. This is +/// an extremely conservative worst case value which leaves room for future +/// syntax enhancements. Most strings in practice are a lot shorter. +/// If you are storing many of these, you will very likely benefit from +/// using dynamic memory. +const int k_cchMaxSteamNetworkingPingLocationString = 1024; + +/// Special values that are returned by some functions that return a ping. +const int k_nSteamNetworkingPing_Failed = -1; +const int k_nSteamNetworkingPing_Unknown = -2; + +// +// Configuration values +// + +/// Configuration values can be applied to different types of objects. +enum ESteamNetworkingConfigScope +{ + + /// Get/set global option, or defaults. Even options that apply to more specific scopes + /// have global scope, and you may be able to just change the global defaults. If you + /// need different settings per connection (for example), then you will need to set those + /// options at the more specific scope. + k_ESteamNetworkingConfig_Global = 1, + + /// Some options are specific to a particular interface. Note that all connection + /// and listen socket settings can also be set at the interface level, and they will + /// apply to objects created through those interfaces. + k_ESteamNetworkingConfig_SocketsInterface = 2, + + /// Options for a listen socket. Listen socket options can be set at the interface layer, + /// if you have multiple listen sockets and they all use the same options. + /// You can also set connection options on a listen socket, and they set the defaults + /// for all connections accepted through this listen socket. (They will be used if you don't + /// set a connection option.) + k_ESteamNetworkingConfig_ListenSocket = 3, + + /// Options for a specific connection. + k_ESteamNetworkingConfig_Connection = 4, + + k_ESteamNetworkingConfigScope__Force32Bit = 0x7fffffff +}; + +// Different configuration values have different data types +enum ESteamNetworkingConfigDataType +{ + k_ESteamNetworkingConfig_Int32 = 1, + k_ESteamNetworkingConfig_Int64 = 2, + k_ESteamNetworkingConfig_Float = 3, + k_ESteamNetworkingConfig_String = 4, + k_ESteamNetworkingConfig_FunctionPtr = 5, // NOTE: When setting callbacks, you should put the pointer into a variable and pass a pointer to that variable. + + k_ESteamNetworkingConfigDataType__Force32Bit = 0x7fffffff +}; + +/// Configuration options +enum ESteamNetworkingConfigValue +{ + k_ESteamNetworkingConfig_Invalid = 0, + + /// [global float, 0--100] Randomly discard N pct of packets instead of sending/recv + /// This is a global option only, since it is applied at a low level + /// where we don't have much context + k_ESteamNetworkingConfig_FakePacketLoss_Send = 2, + k_ESteamNetworkingConfig_FakePacketLoss_Recv = 3, + + /// [global int32]. Delay all outbound/inbound packets by N ms + k_ESteamNetworkingConfig_FakePacketLag_Send = 4, + k_ESteamNetworkingConfig_FakePacketLag_Recv = 5, + + /// [global float] 0-100 Percentage of packets we will add additional delay + /// to (causing them to be reordered) + k_ESteamNetworkingConfig_FakePacketReorder_Send = 6, + k_ESteamNetworkingConfig_FakePacketReorder_Recv = 7, + + /// [global int32] Extra delay, in ms, to apply to reordered packets. + k_ESteamNetworkingConfig_FakePacketReorder_Time = 8, + + /// [global float 0--100] Globally duplicate some percentage of packets we send + k_ESteamNetworkingConfig_FakePacketDup_Send = 26, + k_ESteamNetworkingConfig_FakePacketDup_Recv = 27, + + /// [global int32] Amount of delay, in ms, to delay duplicated packets. + /// (We chose a random delay between 0 and this value) + k_ESteamNetworkingConfig_FakePacketDup_TimeMax = 28, + + /// [connection int32] Timeout value (in ms) to use when first connecting + k_ESteamNetworkingConfig_TimeoutInitial = 24, + + /// [connection int32] Timeout value (in ms) to use after connection is established + k_ESteamNetworkingConfig_TimeoutConnected = 25, + + /// [connection int32] Upper limit of buffered pending bytes to be sent, + /// if this is reached SendMessage will return k_EResultLimitExceeded + /// Default is 512k (524288 bytes) + k_ESteamNetworkingConfig_SendBufferSize = 9, + + /// [connection int32] Minimum/maximum send rate clamp, 0 is no limit. + /// This value will control the min/max allowed sending rate that + /// bandwidth estimation is allowed to reach. Default is 0 (no-limit) + k_ESteamNetworkingConfig_SendRateMin = 10, + k_ESteamNetworkingConfig_SendRateMax = 11, + + /// [connection int32] Nagle time, in microseconds. When SendMessage is called, if + /// the outgoing message is less than the size of the MTU, it will be + /// queued for a delay equal to the Nagle timer value. This is to ensure + /// that if the application sends several small messages rapidly, they are + /// coalesced into a single packet. + /// See historical RFC 896. Value is in microseconds. + /// Default is 5000us (5ms). + k_ESteamNetworkingConfig_NagleTime = 12, + + /// [connection int32] Don't automatically fail IP connections that don't have + /// strong auth. On clients, this means we will attempt the connection even if + /// we don't know our identity or can't get a cert. On the server, it means that + /// we won't automatically reject a connection due to a failure to authenticate. + /// (You can examine the incoming connection and decide whether to accept it.) + k_ESteamNetworkingConfig_IP_AllowWithoutAuth = 23, + + /// [connection int32] Do not send UDP packets with a payload of + /// larger than N bytes. If you set this, k_ESteamNetworkingConfig_MTU_DataSize + /// is automatically adjusted + k_ESteamNetworkingConfig_MTU_PacketSize = 32, + + /// [connection int32] (read only) Maximum message size you can send that + /// will not fragment, based on k_ESteamNetworkingConfig_MTU_PacketSize + k_ESteamNetworkingConfig_MTU_DataSize = 33, + + // + // Settings for SDR relayed connections + // + + /// [int32 global] If the first N pings to a port all fail, mark that port as unavailable for + /// a while, and try a different one. Some ISPs and routers may drop the first + /// packet, so setting this to 1 may greatly disrupt communications. + k_ESteamNetworkingConfig_SDRClient_ConsecutitivePingTimeoutsFailInitial = 19, + + /// [int32 global] If N consecutive pings to a port fail, after having received successful + /// communication, mark that port as unavailable for a while, and try a + /// different one. + k_ESteamNetworkingConfig_SDRClient_ConsecutitivePingTimeoutsFail = 20, + + /// [int32 global] Minimum number of lifetime pings we need to send, before we think our estimate + /// is solid. The first ping to each cluster is very often delayed because of NAT, + /// routers not having the best route, etc. Until we've sent a sufficient number + /// of pings, our estimate is often inaccurate. Keep pinging until we get this + /// many pings. + k_ESteamNetworkingConfig_SDRClient_MinPingsBeforePingAccurate = 21, + + /// [int32 global] Set all steam datagram traffic to originate from the same + /// local port. By default, we open up a new UDP socket (on a different local + /// port) for each relay. This is slightly less optimal, but it works around + /// some routers that don't implement NAT properly. If you have intermittent + /// problems talking to relays that might be NAT related, try toggling + /// this flag + k_ESteamNetworkingConfig_SDRClient_SingleSocket = 22, + + /// [global string] Code of relay cluster to force use. If not empty, we will + /// only use relays in that cluster. E.g. 'iad' + k_ESteamNetworkingConfig_SDRClient_ForceRelayCluster = 29, + + /// [connection string] For debugging, generate our own (unsigned) ticket, using + /// the specified gameserver address. Router must be configured to accept unsigned + /// tickets. + k_ESteamNetworkingConfig_SDRClient_DebugTicketAddress = 30, + + /// [global string] For debugging. Override list of relays from the config with + /// this set (maybe just one). Comma-separated list. + k_ESteamNetworkingConfig_SDRClient_ForceProxyAddr = 31, + + // + // Log levels for debuging information. A higher priority + // (lower numeric value) will cause more stuff to be printed. + // + k_ESteamNetworkingConfig_LogLevel_AckRTT = 13, // [connection int32] RTT calculations for inline pings and replies + k_ESteamNetworkingConfig_LogLevel_PacketDecode = 14, // [connection int32] log SNP packets send + k_ESteamNetworkingConfig_LogLevel_Message = 15, // [connection int32] log each message send/recv + k_ESteamNetworkingConfig_LogLevel_PacketGaps = 16, // [connection int32] dropped packets + k_ESteamNetworkingConfig_LogLevel_P2PRendezvous = 17, // [connection int32] P2P rendezvous messages + k_ESteamNetworkingConfig_LogLevel_SDRRelayPings = 18, // [global int32] Ping relays + + k_ESteamNetworkingConfigValue__Force32Bit = 0x7fffffff +}; + +/// Return value of ISteamNetworkintgUtils::GetConfigValue +enum ESteamNetworkingGetConfigValueResult +{ + k_ESteamNetworkingGetConfigValue_BadValue = -1, // No such configuration value + k_ESteamNetworkingGetConfigValue_BadScopeObj = -2, // Bad connection handle, etc + k_ESteamNetworkingGetConfigValue_BufferTooSmall = -3, // Couldn't fit the result in your buffer + k_ESteamNetworkingGetConfigValue_OK = 1, + k_ESteamNetworkingGetConfigValue_OKInherited = 2, // A value was not set at this level, but the effective (inherited) value was returned. + + k_ESteamNetworkingGetConfigValueResult__Force32Bit = 0x7fffffff +}; + +// +// Debug output +// + +/// Detail level for diagnostic output callback. +/// See ISteamNetworkingUtils::SetDebugOutputFunction +enum ESteamNetworkingSocketsDebugOutputType +{ + k_ESteamNetworkingSocketsDebugOutputType_None = 0, + k_ESteamNetworkingSocketsDebugOutputType_Bug = 1, // You used the API incorrectly, or an internal error happened + k_ESteamNetworkingSocketsDebugOutputType_Error = 2, // Run-time error condition that isn't the result of a bug. (E.g. we are offline, cannot bind a port, etc) + k_ESteamNetworkingSocketsDebugOutputType_Important = 3, // Nothing is wrong, but this is an important notification + k_ESteamNetworkingSocketsDebugOutputType_Warning = 4, + k_ESteamNetworkingSocketsDebugOutputType_Msg = 5, // Recommended amount + k_ESteamNetworkingSocketsDebugOutputType_Verbose = 6, // Quite a bit + k_ESteamNetworkingSocketsDebugOutputType_Debug = 7, // Practically everything + k_ESteamNetworkingSocketsDebugOutputType_Everything = 8, // Wall of text, detailed packet contents breakdown, etc + + k_ESteamNetworkingSocketsDebugOutputType__Force32Bit = 0x7fffffff +}; + +/// Setup callback for debug output, and the desired verbosity you want. +typedef void (*FSteamNetworkingSocketsDebugOutput)( ESteamNetworkingSocketsDebugOutputType nType, const char *pszMsg ); + +// +// Valve data centers +// + +/// Convert 3- or 4-character ID to 32-bit int. +inline SteamNetworkingPOPID CalculateSteamNetworkingPOPIDFromString( const char *pszCode ) +{ + // OK we made a bad decision when we decided how to pack 3-character codes into a uint32. We'd like to support + // 4-character codes, but we don't want to break compatibility. The migration path has some subtleties that make + // this nontrivial, and there are already some IDs stored in SQL. Ug, so the 4 character code "abcd" will + // be encoded with the digits like "0xddaabbcc". + // + // Also: we don't currently use 1- or 2-character codes, but if ever do in the future, let's make sure don't read + // past the end of the string and access uninitialized memory. (And if the string is empty, we always want + // to return 0 and not read bytes past the '\0'.) + // + // There is also extra paranoia to make sure the bytes are not treated as signed. + SteamNetworkingPOPID result = (uint32)(uint8)pszCode[0] << 16U; + if ( pszCode[1] ) + { + result |= ( (uint32)(uint8)pszCode[1] << 8U ); + if ( pszCode[2] ) + { + result |= (uint32)(uint8)pszCode[2] | ( (uint32)(uint8)pszCode[3] << 24U ); + } + } + return result; +} + +/// Unpack integer to string representation, including terminating '\0' +template +inline void GetSteamNetworkingLocationPOPStringFromID( SteamNetworkingPOPID id, char (&szCode)[N] ) +{ + static_assert( N >= 5, "Fixed-size buffer not big enough to hold SDR POP ID" ); + szCode[0] = char( id >> 16U ); + szCode[1] = char( id >> 8U ); + szCode[2] = char( id ); + szCode[3] = char( id >> 24U ); // See comment above about deep regret and sadness + szCode[4] = 0; +} + +/// The POPID "dev" is used in non-production environments for testing. +const SteamNetworkingPOPID k_SteamDatagramPOPID_dev = ( (uint32)'d' << 16U ) | ( (uint32)'e' << 8U ) | (uint32)'v'; + +/////////////////////////////////////////////////////////////////////////////// +// +// Internal stuff + +// For code compatibility +typedef SteamNetworkingMessage_t ISteamNetworkingMessage; +typedef SteamNetworkingErrMsg SteamDatagramErrMsg; + +inline void SteamNetworkingIPAddr::Clear() { memset( this, 0, sizeof(*this) ); } +inline bool SteamNetworkingIPAddr::IsIPv6AllZeros() const { const uint64 *q = (const uint64 *)m_ipv6; return q[0] == 0 && q[1] == 0; } +inline void SteamNetworkingIPAddr::SetIPv6( const uint8 *ipv6, uint16 nPort ) { memcpy( m_ipv6, ipv6, 16 ); m_port = nPort; } +inline void SteamNetworkingIPAddr::SetIPv4( uint32 nIP, uint16 nPort ) { m_ipv4.m_8zeros = 0; m_ipv4.m_0000 = 0; m_ipv4.m_ffff = 0xffff; m_ipv4.m_ip[0] = uint8(nIP>>24); m_ipv4.m_ip[1] = uint8(nIP>>16); m_ipv4.m_ip[2] = uint8(nIP>>8); m_ipv4.m_ip[3] = uint8(nIP); m_port = nPort; } +inline bool SteamNetworkingIPAddr::IsIPv4() const { return m_ipv4.m_8zeros == 0 && m_ipv4.m_0000 == 0 && m_ipv4.m_ffff == 0xffff; } +inline uint32 SteamNetworkingIPAddr::GetIPv4() const { return IsIPv4() ? ( (uint32(m_ipv4.m_ip[0])<<24) | (uint32(m_ipv4.m_ip[1])<<16) | (uint32(m_ipv4.m_ip[2])<<8) | uint32(m_ipv4.m_ip[3]) ) : 0; } +inline void SteamNetworkingIPAddr::SetIPv6LocalHost( uint16 nPort ) { m_ipv4.m_8zeros = 0; m_ipv4.m_0000 = 0; m_ipv4.m_ffff = 0; m_ipv6[12] = 0; m_ipv6[13] = 0; m_ipv6[14] = 0; m_ipv6[15] = 1; m_port = nPort; } +inline bool SteamNetworkingIPAddr::IsLocalHost() const { return ( m_ipv4.m_8zeros == 0 && m_ipv4.m_0000 == 0 && m_ipv4.m_ffff == 0 && m_ipv6[12] == 0 && m_ipv6[13] == 0 && m_ipv6[14] == 0 && m_ipv6[15] == 1 ) || ( GetIPv4() == 0x7f000001 ); } +inline bool SteamNetworkingIPAddr::operator==(const SteamNetworkingIPAddr &x ) const { return memcmp( this, &x, sizeof(SteamNetworkingIPAddr) ) == 0; } + +inline void SteamNetworkingIdentity::Clear() { memset( this, 0, sizeof(*this) ); } +inline bool SteamNetworkingIdentity::IsInvalid() const { return m_eType == k_ESteamNetworkingIdentityType_Invalid; } +inline void SteamNetworkingIdentity::SetSteamID( CSteamID steamID ) { SetSteamID64( steamID.ConvertToUint64() ); } +inline CSteamID SteamNetworkingIdentity::GetSteamID() const { return CSteamID( GetSteamID64() ); } +inline void SteamNetworkingIdentity::SetSteamID64( uint64 steamID ) { m_eType = k_ESteamNetworkingIdentityType_SteamID; m_cbSize = sizeof( m_steamID64 ); m_steamID64 = steamID; } +inline uint64 SteamNetworkingIdentity::GetSteamID64() const { return m_eType == k_ESteamNetworkingIdentityType_SteamID ? m_steamID64 : 0; } +inline void SteamNetworkingIdentity::SetIPAddr( const SteamNetworkingIPAddr &addr ) { m_eType = k_ESteamNetworkingIdentityType_IPAddress; m_cbSize = (int)sizeof(m_ip); m_ip = addr; } +inline const SteamNetworkingIPAddr *SteamNetworkingIdentity::GetIPAddr() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress ? &m_ip : NULL; } +inline void SteamNetworkingIdentity::SetLocalHost() { m_eType = k_ESteamNetworkingIdentityType_IPAddress; m_cbSize = (int)sizeof(m_ip); m_ip.SetIPv6LocalHost(); } +inline bool SteamNetworkingIdentity::IsLocalHost() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress && m_ip.IsLocalHost(); } +inline bool SteamNetworkingIdentity::SetGenericString( const char *pszString ) { size_t l = strlen( pszString ); if ( l >= sizeof(m_szGenericString) ) return false; + m_eType = k_ESteamNetworkingIdentityType_GenericString; m_cbSize = int(l+1); memcpy( m_szGenericString, pszString, m_cbSize ); return true; } +inline const char *SteamNetworkingIdentity::GetGenericString() const { return m_eType == k_ESteamNetworkingIdentityType_GenericString ? m_szGenericString : NULL; } +inline bool SteamNetworkingIdentity::SetGenericBytes( const void *data, size_t cbLen ) { if ( cbLen > sizeof(m_genericBytes) ) return false; + m_eType = k_ESteamNetworkingIdentityType_GenericBytes; m_cbSize = int(cbLen); memcpy( m_genericBytes, data, m_cbSize ); return true; } +inline const uint8 *SteamNetworkingIdentity::GetGenericBytes( int &cbLen ) const { if ( m_eType != k_ESteamNetworkingIdentityType_GenericBytes ) return NULL; + cbLen = m_cbSize; return m_genericBytes; } +inline bool SteamNetworkingIdentity::operator==(const SteamNetworkingIdentity &x ) const { return m_eType == x.m_eType && m_cbSize == x.m_cbSize && memcmp( m_genericBytes, x.m_genericBytes, m_cbSize ) == 0; } +inline void SteamNetworkingMessage_t::Release() { (*m_pfnRelease)( this ); } + +#if defined( STEAMNETWORKINGSOCKETS_STATIC_LINK ) || !defined( STEAMNETWORKINGSOCKETS_STEAMCLIENT ) +STEAMNETWORKINGSOCKETS_INTERFACE void SteamAPI_SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr *pAddr, char *buf, size_t cbBuf, bool bWithPort ); +STEAMNETWORKINGSOCKETS_INTERFACE bool SteamAPI_SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr ); +STEAMNETWORKINGSOCKETS_INTERFACE void SteamAPI_SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf ); +STEAMNETWORKINGSOCKETS_INTERFACE bool SteamAPI_SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, size_t sizeofIdentity, const char *pszStr ); +inline void SteamNetworkingIPAddr::ToString( char *buf, size_t cbBuf, bool bWithPort ) const { SteamAPI_SteamNetworkingIPAddr_ToString( this, buf, cbBuf, bWithPort ); } +inline bool SteamNetworkingIPAddr::ParseString( const char *pszStr ) { return SteamAPI_SteamNetworkingIPAddr_ParseString( this, pszStr ); } +inline void SteamNetworkingIdentity::ToString( char *buf, size_t cbBuf ) const { SteamAPI_SteamNetworkingIdentity_ToString( *this, buf, cbBuf ); } +inline bool SteamNetworkingIdentity::ParseString( const char *pszStr ) { return SteamAPI_SteamNetworkingIdentity_ParseString( this, sizeof(*this), pszStr ); } +#endif + +#endif // #ifndef STEAMNETWORKINGTYPES diff --git a/public/steam/steamps3params.h b/public/steam/steamps3params.h new file mode 100644 index 0000000..c0741b4 --- /dev/null +++ b/public/steam/steamps3params.h @@ -0,0 +1,112 @@ +//====== Copyright 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMPS3PARAMS_H +#define STEAMPS3PARAMS_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// PlayStation 3 initialization parameters +// +// The following structure must be passed to when loading steam_api_ps3.prx +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +#define STEAM_PS3_PATH_MAX 1055 +#define STEAM_PS3_SERVICE_ID_MAX 32 +#define STEAM_PS3_COMMUNICATION_ID_MAX 10 +#define STEAM_PS3_COMMUNICATION_SIG_MAX 160 +#define STEAM_PS3_LANGUAGE_MAX 64 +#define STEAM_PS3_REGION_CODE_MAX 16 +#define STEAM_PS3_CURRENT_PARAMS_VER 2 +struct SteamPS3Params_t +{ + uint32 m_unVersion; // set to STEAM_PS3_CURRENT_PARAMS_VER + + void *pReserved; + uint32 m_nAppId; // set to your game's appid + + char m_rgchInstallationPath[ STEAM_PS3_PATH_MAX ]; // directory containing latest steam prx's and sdata. Can be read only (BDVD) + char m_rgchSystemCache[ STEAM_PS3_PATH_MAX ]; // temp working cache, not persistent + char m_rgchGameData[ STEAM_PS3_PATH_MAX ]; // persistent game data path for storing user data + char m_rgchNpServiceID[ STEAM_PS3_SERVICE_ID_MAX ]; + char m_rgchNpCommunicationID[ STEAM_PS3_COMMUNICATION_ID_MAX ]; + char m_rgchNpCommunicationSig[ STEAM_PS3_COMMUNICATION_SIG_MAX ]; + + // Language should be one of the following. must be zero terminated + // danish + // dutch + // english + // finnish + // french + // german + // italian + // korean + // norwegian + // polish + // portuguese + // russian + // schinese + // spanish + // swedish + // tchinese + char m_rgchSteamLanguage[ STEAM_PS3_LANGUAGE_MAX ]; + + // region codes are "SCEA", "SCEE", "SCEJ". must be zero terminated + char m_rgchRegionCode[ STEAM_PS3_REGION_CODE_MAX ]; + + // Should be SYS_TTYP3 through SYS_TTYP10, if it's 0 then Steam won't spawn a + // thread to read console input at all. Using this let's you use Steam console commands + // like: profile_on, profile_off, profile_dump, mem_stats, mem_validate. + unsigned int m_cSteamInputTTY; + + struct Ps3netInit_t + { + bool m_bNeedInit; + void *m_pMemory; + int m_nMemorySize; + int m_flags; + } m_sysNetInitInfo; + + struct Ps3jpgInit_t + { + bool m_bNeedInit; + } m_sysJpgInitInfo; + + struct Ps3pngInit_t + { + bool m_bNeedInit; + } m_sysPngInitInfo; + + struct Ps3sysutilUserInfo_t + { + bool m_bNeedInit; + } m_sysSysUtilUserInfo; + + bool m_bIncludeNewsPage; +}; + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// PlayStation 3 memory structure +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +#define STEAMPS3_MALLOC_INUSE 0x53D04A51 +#define STEAMPS3_MALLOC_SYSTEM 0x0D102C48 +#define STEAMPS3_MALLOC_OK 0xFFD04A51 +struct SteamPS3Memory_t +{ + bool m_bSingleAllocation; // If true, Steam will request one 6MB allocation and use the returned memory for all future allocations + // If false, Steam will make call malloc for each allocation + + // required function pointers + void* (*m_pfMalloc)(size_t); + void* (*m_pfRealloc)(void *, size_t); + void (*m_pfFree)(void *); + size_t (*m_pUsable_size)(void*); +}; + + +#endif // STEAMPS3PARAMS_H diff --git a/public/steam/steamtypes.h b/public/steam/steamtypes.h new file mode 100644 index 0000000..0660f68 --- /dev/null +++ b/public/steam/steamtypes.h @@ -0,0 +1,186 @@ +//========= Copyright 1996-2008, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMTYPES_H +#define STEAMTYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#define S_CALLTYPE __cdecl + +// Steam-specific types. Defined here so this header file can be included in other code bases. +#ifndef WCHARTYPES_H +typedef unsigned char uint8; +#endif + +#if defined( __GNUC__ ) && !defined(POSIX) + #if __GNUC__ < 4 + #error "Steamworks requires GCC 4.X (4.2 or 4.4 have been tested)" + #endif + #define POSIX 1 +#endif + +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) +#define X64BITS +#endif + +// Make sure VALVE_BIG_ENDIAN gets set on PS3, may already be set previously in Valve internal code. +#if !defined(VALVE_BIG_ENDIAN) && defined(_PS3) +#define VALVE_BIG_ENDIAN +#endif + +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( _WIN32 ) + +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; + +typedef int64 lint64; +typedef uint64 ulint64; + +#ifdef X64BITS +typedef __int64 intp; // intp is an integer that can accomodate a pointer +typedef unsigned __int64 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) +#else +typedef __int32 intp; +typedef unsigned __int32 uintp; +#endif + +#else // _WIN32 + +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; + +// [u]int64 are actually defined as 'long long' and gcc 64-bit +// doesn't automatically consider them the same as 'long int'. +// Changing the types for [u]int64 is complicated by +// there being many definitions, so we just +// define a 'long int' here and use it in places that would +// otherwise confuse the compiler. +typedef long int lint64; +typedef unsigned long int ulint64; + +#ifdef X64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif + +#endif // else _WIN32 + +#ifdef API_GEN +# define STEAM_CLANG_ATTR(ATTR) __attribute__((annotate( ATTR ))) +#else +# define STEAM_CLANG_ATTR(ATTR) +#endif + +#define STEAM_METHOD_DESC(DESC) STEAM_CLANG_ATTR( "desc:" #DESC ";" ) +#define STEAM_IGNOREATTR() STEAM_CLANG_ATTR( "ignore" ) +#define STEAM_OUT_STRUCT() STEAM_CLANG_ATTR( "out_struct: ;" ) +#define STEAM_OUT_STRING() STEAM_CLANG_ATTR( "out_string: ;" ) +#define STEAM_OUT_ARRAY_CALL(COUNTER,FUNCTION,PARAMS) STEAM_CLANG_ATTR( "out_array_call:" #COUNTER "," #FUNCTION "," #PARAMS ";" ) +#define STEAM_OUT_ARRAY_COUNT(COUNTER, DESC) STEAM_CLANG_ATTR( "out_array_count:" #COUNTER ";desc:" #DESC ) +#define STEAM_ARRAY_COUNT(COUNTER) STEAM_CLANG_ATTR( "array_count:" #COUNTER ";" ) +#define STEAM_ARRAY_COUNT_D(COUNTER, DESC) STEAM_CLANG_ATTR( "array_count:" #COUNTER ";desc:" #DESC ) +#define STEAM_BUFFER_COUNT(COUNTER) STEAM_CLANG_ATTR( "buffer_count:" #COUNTER ";" ) +#define STEAM_OUT_BUFFER_COUNT(COUNTER) STEAM_CLANG_ATTR( "out_buffer_count:" #COUNTER ";" ) +#define STEAM_OUT_STRING_COUNT(COUNTER) STEAM_CLANG_ATTR( "out_string_count:" #COUNTER ";" ) +#define STEAM_DESC(DESC) STEAM_CLANG_ATTR("desc:" #DESC ";") +#define STEAM_CALL_RESULT(RESULT_TYPE) STEAM_CLANG_ATTR("callresult:" #RESULT_TYPE ";") +#define STEAM_CALL_BACK(RESULT_TYPE) STEAM_CLANG_ATTR("callback:" #RESULT_TYPE ";") + +const int k_cubSaltSize = 8; +typedef uint8 Salt_t[ k_cubSaltSize ]; + +//----------------------------------------------------------------------------- +// GID (GlobalID) stuff +// This is a globally unique identifier. It's guaranteed to be unique across all +// racks and servers for as long as a given universe persists. +//----------------------------------------------------------------------------- +// NOTE: for GID parsing/rendering and other utils, see gid.h +typedef uint64 GID_t; + +const GID_t k_GIDNil = 0xffffffffffffffffull; + +// For convenience, we define a number of types that are just new names for GIDs +typedef uint64 JobID_t; // Each Job has a unique ID +typedef GID_t TxnID_t; // Each financial transaction has a unique ID + +const GID_t k_TxnIDNil = k_GIDNil; +const GID_t k_TxnIDUnknown = 0; + +const JobID_t k_JobIDNil = 0xffffffffffffffffull; + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. +typedef uint32 PackageId_t; +const PackageId_t k_uPackageIdInvalid = 0xFFFFFFFF; + +typedef uint32 BundleId_t; +const BundleId_t k_uBundleIdInvalid = 0; + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. +typedef uint32 AppId_t; +const AppId_t k_uAppIdInvalid = 0x0; + +typedef uint64 AssetClassId_t; +const AssetClassId_t k_ulAssetClassIdInvalid = 0x0; + +typedef uint32 PhysicalItemId_t; +const PhysicalItemId_t k_uPhysicalItemIdInvalid = 0x0; + + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. AppIds and DepotIDs also presently +// share the same namespace, but since we'd like to change that in the future +// I've defined it seperately here. +typedef uint32 DepotId_t; +const DepotId_t k_uDepotIdInvalid = 0x0; + +// RTime32 +// We use this 32 bit time representing real world time. +// It offers 1 second resolution beginning on January 1, 1970 (Unix time) +typedef uint32 RTime32; + +typedef uint32 CellID_t; +const CellID_t k_uCellIDInvalid = 0xFFFFFFFF; + +// handle to a Steam API call +typedef uint64 SteamAPICall_t; +const SteamAPICall_t k_uAPICallInvalid = 0x0; + +typedef uint32 AccountID_t; + +typedef uint32 PartnerId_t; +const PartnerId_t k_uPartnerIdInvalid = 0; + +// ID for a depot content manifest +typedef uint64 ManifestId_t; +const ManifestId_t k_uManifestIdInvalid = 0; + +// ID for cafe sites +typedef uint64 SiteId_t; +const SiteId_t k_ulSiteIdInvalid = 0; + +// Party Beacon ID +typedef uint64 PartyBeaconID_t; +const PartyBeaconID_t k_ulPartyBeaconIdInvalid = 0; + +#endif // STEAMTYPES_H diff --git a/public/steam/steamuniverse.h b/public/steam/steamuniverse.h new file mode 100644 index 0000000..dd384dc --- /dev/null +++ b/public/steam/steamuniverse.h @@ -0,0 +1,27 @@ +//========= Copyright � 1996-2008, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMUNIVERSE_H +#define STEAMUNIVERSE_H +#ifdef _WIN32 +#pragma once +#endif + + +// Steam universes. Each universe is a self-contained Steam instance. +enum EUniverse +{ + k_EUniverseInvalid = 0, + k_EUniversePublic = 1, + k_EUniverseBeta = 2, + k_EUniverseInternal = 3, + k_EUniverseDev = 4, + // k_EUniverseRC = 5, // no such universe anymore + k_EUniverseMax +}; + + +#endif // STEAMUNIVERSE_H diff --git a/public/string_t.h b/public/string_t.h new file mode 100644 index 0000000..9fa1de6 --- /dev/null +++ b/public/string_t.h @@ -0,0 +1,115 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the more complete set of operations on the string_t defined +// These should be used instead of direct manipulation to allow more +// flexibility in future ports or optimization. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef STRING_T_H +#define STRING_T_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifndef NO_STRING_T + +#ifdef WEAK_STRING_T + +typedef int string_t; + +//----------------------------------------------------------------------------- +// Purpose: The correct way to specify the NULL string as a constant. +//----------------------------------------------------------------------------- + +#define NULL_STRING 0 + +//----------------------------------------------------------------------------- +// Purpose: Given a string_t, make a C string. By convention the result string +// pointer should be considered transient and should not be stored. +//----------------------------------------------------------------------------- + +#define STRING( offset ) ( ( offset ) ? reinterpret_cast( offset ) : "" ) + +//----------------------------------------------------------------------------- +// Purpose: Given a C string, obtain a string_t +//----------------------------------------------------------------------------- + +#define MAKE_STRING( str ) ( ( *str != 0 ) ? reinterpret_cast( str ) : 0 ) + +//----------------------------------------------------------------------------- + +#define IDENT_STRINGS( s1, s2 ) *((void **)&(s1)) == *((void **)&(s2)) + +//----------------------------------------------------------------------------- + +#else // Strong string_t + +//----------------------------------------------------------------------------- + +struct string_t +{ +public: + bool operator!() const { return ( pszValue == NULL ); } + bool operator==( const string_t &rhs ) const { return ( pszValue == rhs.pszValue ); } + bool operator!=( const string_t &rhs ) const { return ( pszValue != rhs.pszValue ); } + bool operator<( const string_t &rhs ) const { return ((void *)pszValue < (void *)rhs.pszValue ); } + + const char *ToCStr() const { return ( pszValue ) ? pszValue : ""; } + +protected: + const char *pszValue; +}; + +//----------------------------------------------------------------------------- + +struct castable_string_t : public string_t // string_t is used in unions, hence, no constructor allowed +{ + castable_string_t() { pszValue = NULL; } + castable_string_t( const char *pszFrom ) { pszValue = (pszFrom && *pszFrom) ? pszFrom : 0; } +}; + +//----------------------------------------------------------------------------- +// Purpose: The correct way to specify the NULL string as a constant. +//----------------------------------------------------------------------------- + +#define NULL_STRING castable_string_t() + +//----------------------------------------------------------------------------- +// Purpose: Given a string_t, make a C string. By convention the result string +// pointer should be considered transient and should not be stored. +//----------------------------------------------------------------------------- + +#define STRING( string_t_obj ) (string_t_obj).ToCStr() + +//----------------------------------------------------------------------------- +// Purpose: Given a C string, obtain a string_t +//----------------------------------------------------------------------------- + +#define MAKE_STRING( c_str ) castable_string_t( c_str ) + +//----------------------------------------------------------------------------- + +#define IDENT_STRINGS( s1, s2 ) *((void **)&(s1)) == *((void **)&(s2)) + +//----------------------------------------------------------------------------- + +inline void NetworkVarConstruct( string_t &x ) { x = NULL_STRING; } + +#endif + +#else // NO_STRING_T + +typedef const char *string_t; +#define NULL_STRING 0 +#define STRING( c_str ) ( c_str ) +#define MAKE_STRING( c_str ) ( c_str ) +#define IDENT_STRINGS( s1, s2 ) *((void **)&(s1)) == *((void **)&(s2)) + +#endif // NO_STRING_T + +//============================================================================= + +#endif // STRING_T_H diff --git a/public/stringregistry.cpp b/public/stringregistry.cpp new file mode 100644 index 0000000..896430b --- /dev/null +++ b/public/stringregistry.cpp @@ -0,0 +1,145 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A registry of strings and associated ints +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + + +#include +#include +#include "stringregistry.h" +#include "utldict.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if !defined(_STATIC_LINKED) || defined(CLIENT_DLL) + +//----------------------------------------------------------------------------- +// Purpose: This class wraps the containers that do the actual work +//----------------------------------------------------------------------------- +struct StringTable_t : public CUtlDict +{ +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Add null terminated string to the string registry +// Input : +// Output : +//----------------------------------------------------------------------------- +unsigned short CStringRegistry::AddString(const char *stringText, int stringID) +{ + return m_pStringList->Insert( stringText, stringID ); +} + +//----------------------------------------------------------------------------- +// Purpose: Given string text get the string ID +// Input : Text of string to find +// Output : Return string id or -1 if no such string exists +//----------------------------------------------------------------------------- +int CStringRegistry::GetStringID( const char *stringText ) +{ + unsigned short index = m_pStringList->Find( stringText ); + if ( m_pStringList->IsValidIndex( index ) ) + { + return (*m_pStringList)[index]; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: Given a string ID return the string text +// Input : ID of string to find +// Output : Return string text of NULL of no such ID exists +//----------------------------------------------------------------------------- +char const *CStringRegistry::GetStringText( int stringID ) +{ + for( unsigned short index = m_pStringList->First() ; index != m_pStringList->InvalidIndex(); index = m_pStringList->Next( index ) ) + { + if ( (*m_pStringList)[index] == stringID ) + { + return m_pStringList->GetElementName( index ); + } + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Given a key return the string text +//----------------------------------------------------------------------------- +char const *CStringRegistry::GetStringForKey( unsigned short key ) +{ + if ( !m_pStringList->IsValidIndex( key ) ) + return NULL; + + return m_pStringList->GetElementName( key ); +} + +//----------------------------------------------------------------------------- +// Purpose: Given a key return the string text +//----------------------------------------------------------------------------- +int CStringRegistry::GetIDForKey( unsigned short key ) +{ + if ( !m_pStringList->IsValidIndex( key ) ) + return 0; + + return (*m_pStringList)[key]; +} + +//----------------------------------------------------------------------------- +// Purpose: Clear all strings from the string registry +//----------------------------------------------------------------------------- +void CStringRegistry::ClearStrings(void) +{ + m_pStringList->RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor - delete the list of strings and maps +// Input : +// Output : +//----------------------------------------------------------------------------- +CStringRegistry::~CStringRegistry(void) +{ + delete m_pStringList; +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : +// Output : +//----------------------------------------------------------------------------- +CStringRegistry::CStringRegistry(void) +{ + m_pStringList = new StringTable_t; +} + + +unsigned short CStringRegistry::First() const +{ + return m_pStringList->First(); +} + +unsigned short CStringRegistry::Next( unsigned short key ) const +{ + return m_pStringList->Next( key ); +} + +unsigned short CStringRegistry::InvalidIndex() const +{ + return m_pStringList->InvalidIndex(); +} + +#endif // _STATIC_LINKED && CLIENT_DLL diff --git a/public/stringregistry.h b/public/stringregistry.h new file mode 100644 index 0000000..9e4ff82 --- /dev/null +++ b/public/stringregistry.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A registry of strings and associated ints +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef STRINGREGISTRY_H +#define STRINGREGISTRY_H +#pragma once + +struct StringTable_t; + +//----------------------------------------------------------------------------- +// Purpose: Just a convenience/legacy wrapper for CUtlDict<> . +//----------------------------------------------------------------------------- +class CStringRegistry +{ +private: + StringTable_t *m_pStringList; + +public: + // returns a key for a given string + unsigned short AddString(const char *stringText, int stringID); + + // This is optimized. It will do 2 O(logN) searches + // Only one of the searches needs to compare strings, the other compares symbols (ints) + // returns -1 if the string is not present in the registry. + int GetStringID(const char *stringText); + + // This is unoptimized. It will linearly search (but only compares ints, not strings) + const char *GetStringText(int stringID); + + // This is O(1). It will not search. key MUST be a value that was returned by AddString + const char *GetStringForKey(unsigned short key); + // This is O(1). It will not search. key MUST be a value that was returned by AddString + int GetIDForKey(unsigned short key); + + void ClearStrings(void); + + + // Iterate all the keys. + unsigned short First() const; + unsigned short Next( unsigned short key ) const; + unsigned short InvalidIndex() const; + + ~CStringRegistry(void); // Need to free allocated memory + CStringRegistry(void); +}; + +#endif // STRINGREGISTRY_H diff --git a/public/studio.cpp b/public/studio.cpp new file mode 100644 index 0000000..156b793 --- /dev/null +++ b/public/studio.cpp @@ -0,0 +1,1862 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "studio.h" +#include "datacache/idatacache.h" +#include "datacache/imdlcache.h" +#include "convar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +mstudioanimdesc_t &studiohdr_t::pAnimdesc( int i ) const +{ + if (numincludemodels == 0) + { + return *pLocalAnimdesc( i ); + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_anim[i].group ]; + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + Assert( pStudioHdr ); + + return *pStudioHdr->pLocalAnimdesc( pVModel->m_anim[i].index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +mstudioanim_t *mstudioanimdesc_t::pAnimBlock( int block, int index ) const +{ + if (block == -1) + { + return (mstudioanim_t *)NULL; + } + if (block == 0) + { + return (mstudioanim_t *)(((byte *)this) + index); + } + + byte *pAnimBlock = pStudiohdr()->GetAnimBlock( block ); + if ( pAnimBlock ) + { + return (mstudioanim_t *)(pAnimBlock + index); + } + + return (mstudioanim_t *)NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +static ConVar mod_load_showstall( "mod_load_showstall", "0", 0, "1 - show hitches , 2 - show stalls" ); +mstudioanim_t *mstudioanimdesc_t::pAnim( int *piFrame ) const +{ + float flStall; + return pAnim( piFrame, flStall ); +} + +mstudioanim_t *mstudioanimdesc_t::pAnim( int *piFrame, float &flStall ) const +{ + mstudioanim_t *panim = NULL; + + int block = animblock; + int index = animindex; + int section = 0; + + if (sectionframes != 0) + { + if (numframes > sectionframes && *piFrame == numframes - 1) + { + // last frame on long anims is stored separately + *piFrame = 0; + section = (numframes / sectionframes) + 1; + } + else + { + section = *piFrame / sectionframes; + *piFrame -= section * sectionframes; + } + + block = pSection( section )->animblock; + index = pSection( section )->animindex; + } + + if (block == -1) + { + // model needs to be recompiled + return NULL; + } + + panim = pAnimBlock( block, index ); + + // force a preload on the next block + if ( sectionframes != 0 ) + { + int count = ( numframes / sectionframes) + 2; + for ( int i = section + 1; i < count; i++ ) + { + if ( pSection( i )->animblock != block ) + { + pAnimBlock( pSection( i )->animblock, pSection( i )->animindex ); + break; + } + } + } + + if (panim == NULL) + { + if (section > 0 && mod_load_showstall.GetInt() > 0) + { + Msg("[%8.3f] hitch on %s:%s:%d:%d\n", Plat_FloatTime(), pStudiohdr()->pszName(), pszName(), section, block ); + } + // back up until a previously loaded block is found + while (--section >= 0) + { + block = pSection( section )->animblock; + index = pSection( section )->animindex; + panim = pAnimBlock( block, index ); + if (panim) + { + // set it to the last frame in the last valid section + *piFrame = sectionframes - 1; + break; + } + } + } + + // try to guess a valid stall time interval (tuned for the X360) + flStall = 0.0f; + if (panim == NULL && section <= 0) + { + zeroframestalltime = Plat_FloatTime(); + flStall = 1.0f; + } + else if (panim != NULL && zeroframestalltime != 0.0f) + { + float dt = Plat_FloatTime() - zeroframestalltime; + if (dt >= 0.0) + { + flStall = SimpleSpline( clamp( (0.200f - dt) * 5.0f, 0.0f, 1.0f ) ); + } + + if (flStall == 0.0f) + { + // disable stalltime + zeroframestalltime = 0.0f; + } + else if (mod_load_showstall.GetInt() > 1) + { + Msg("[%8.3f] stall blend %.2f on %s:%s:%d:%d\n", Plat_FloatTime(), flStall, pStudiohdr()->pszName(), pszName(), section, block ); + } + } + + if (panim == NULL && mod_load_showstall.GetInt() > 1) + { + Msg("[%8.3f] stall on %s:%s:%d:%d\n", Plat_FloatTime(), pStudiohdr()->pszName(), pszName(), section, block ); + } + + return panim; +} + +mstudioikrule_t *mstudioanimdesc_t::pIKRule( int i ) const +{ + if (ikruleindex) + { + return (mstudioikrule_t *)(((byte *)this) + ikruleindex) + i; + } + else if (animblockikruleindex) + { + if (animblock == 0) + { + return (mstudioikrule_t *)(((byte *)this) + animblockikruleindex) + i; + } + else + { + byte *pAnimBlocks = pStudiohdr()->GetAnimBlock( animblock ); + + if ( pAnimBlocks ) + { + return (mstudioikrule_t *)(pAnimBlocks + animblockikruleindex) + i; + } + } + } + + return NULL; +} + + +mstudiolocalhierarchy_t *mstudioanimdesc_t::pHierarchy( int i ) const +{ + if (localhierarchyindex) + { + if (animblock == 0) + { + return (mstudiolocalhierarchy_t *)(((byte *)this) + localhierarchyindex) + i; + } + else + { + byte *pAnimBlocks = pStudiohdr()->GetAnimBlock( animblock ); + + if ( pAnimBlocks ) + { + return (mstudiolocalhierarchy_t *)(pAnimBlocks + localhierarchyindex) + i; + } + } + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +bool studiohdr_t::SequencesAvailable() const +{ + if (numincludemodels == 0) + { + return true; + } + + return ( GetVirtualModel() != NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::GetNumSeq( void ) const +{ + if (numincludemodels == 0) + { + return numlocalseq; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + return pVModel->m_seq.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +mstudioseqdesc_t &studiohdr_t::pSeqdesc( int i ) const +{ + if (numincludemodels == 0) + { + return *pLocalSeqdesc( i ); + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + if ( !pVModel ) + { + return *pLocalSeqdesc( i ); + } + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[i].group ]; + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + Assert( pStudioHdr ); + + return *pStudioHdr->pLocalSeqdesc( pVModel->m_seq[i].index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::iRelativeAnim( int baseseq, int relanim ) const +{ + if (numincludemodels == 0) + { + return relanim; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[baseseq].group ]; + + return pGroup->masterAnim[ relanim ]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::iRelativeSeq( int baseseq, int relseq ) const +{ + if (numincludemodels == 0) + { + return relseq; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[baseseq].group ]; + + return pGroup->masterSeq[ relseq ]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::GetNumPoseParameters( void ) const +{ + if (numincludemodels == 0) + { + return numlocalposeparameters; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + return pVModel->m_pose.Count(); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +const mstudioposeparamdesc_t &studiohdr_t::pPoseParameter( int i ) +{ + if (numincludemodels == 0) + { + return *pLocalPoseParameter( i ); + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + if ( pVModel->m_pose[i].group == 0) + return *pLocalPoseParameter( pVModel->m_pose[i].index ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_pose[i].group ]; + + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + Assert( pStudioHdr ); + + return *pStudioHdr->pLocalPoseParameter( pVModel->m_pose[i].index ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::GetSharedPoseParameter( int iSequence, int iLocalPose ) const +{ + if (numincludemodels == 0) + { + return iLocalPose; + } + + if (iLocalPose == -1) + return iLocalPose; + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ]; + + return pGroup->masterPose[iLocalPose]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::EntryNode( int iSequence ) +{ + mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence ); + + if (numincludemodels == 0 || seqdesc.localentrynode == 0) + { + return seqdesc.localentrynode; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ]; + + return pGroup->masterNode[seqdesc.localentrynode-1]+1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +int studiohdr_t::ExitNode( int iSequence ) +{ + mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence ); + + if (numincludemodels == 0 || seqdesc.localexitnode == 0) + { + return seqdesc.localexitnode; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ]; + + return pGroup->masterNode[seqdesc.localexitnode-1]+1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::GetNumAttachments( void ) const +{ + if (numincludemodels == 0) + { + return numlocalattachments; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + return pVModel->m_attachment.Count(); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +const mstudioattachment_t &studiohdr_t::pAttachment( int i ) const +{ + if (numincludemodels == 0) + { + return *pLocalAttachment( i ); + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[i].group ]; + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + Assert( pStudioHdr ); + + return *pStudioHdr->pLocalAttachment( pVModel->m_attachment[i].index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::GetAttachmentBone( int i ) +{ + const mstudioattachment_t &attachment = pAttachment( i ); + + // remap bone + virtualmodel_t *pVModel = GetVirtualModel(); + if (pVModel) + { + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[i].group ]; + int iBone = pGroup->masterBone[attachment.localbone]; + if (iBone == -1) + return 0; + return iBone; + } + return attachment.localbone; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void studiohdr_t::SetAttachmentBone( int iAttachment, int iBone ) +{ + mstudioattachment_t &attachment = (mstudioattachment_t &)pAttachment( iAttachment ); + + // remap bone + virtualmodel_t *pVModel = GetVirtualModel(); + if (pVModel) + { + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[iAttachment].group ]; + iBone = pGroup->boneMap[iBone]; + } + attachment.localbone = iBone; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +char *studiohdr_t::pszNodeName( int iNode ) +{ + if (numincludemodels == 0) + { + return pszLocalNodeName( iNode ); + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + if ( pVModel->m_node.Count() <= iNode-1 ) + return "Invalid node"; + + return pVModel->m_group[ pVModel->m_node[iNode-1].group ].GetStudioHdr()->pszLocalNodeName( pVModel->m_node[iNode-1].index ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int studiohdr_t::GetTransition( int iFrom, int iTo ) const +{ + if (numincludemodels == 0) + { + return *pLocalTransition( (iFrom-1)*numlocalnodes + (iTo - 1) ); + } + + return iTo; + /* + FIXME: not connected + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + return pVModel->m_transition.Element( iFrom ).Element( iTo ); + */ +} + + +int studiohdr_t::GetActivityListVersion( void ) +{ + if (numincludemodels == 0) + { + return activitylistversion; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + int version = activitylistversion; + + int i; + for (i = 1; i < pVModel->m_group.Count(); i++) + { + virtualgroup_t *pGroup = &pVModel->m_group[ i ]; + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + + Assert( pStudioHdr ); + + version = vmin( version, pStudioHdr->activitylistversion ); + } + + return version; +} + +void studiohdr_t::SetActivityListVersion( int version ) const +{ + activitylistversion = version; + + if (numincludemodels == 0) + { + return; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + int i; + for (i = 1; i < pVModel->m_group.Count(); i++) + { + virtualgroup_t *pGroup = &pVModel->m_group[ i ]; + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + + Assert( pStudioHdr ); + + pStudioHdr->SetActivityListVersion( version ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +int studiohdr_t::GetNumIKAutoplayLocks( void ) const +{ + if (numincludemodels == 0) + { + return numlocalikautoplaylocks; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + return pVModel->m_iklock.Count(); +} + +const mstudioiklock_t &studiohdr_t::pIKAutoplayLock( int i ) +{ + if (numincludemodels == 0) + { + return *pLocalIKAutoplayLock( i ); + } + + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_iklock[i].group ]; + const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr(); + Assert( pStudioHdr ); + + return *pStudioHdr->pLocalIKAutoplayLock( pVModel->m_iklock[i].index ); +} + +int studiohdr_t::CountAutoplaySequences() const +{ + int count = 0; + for (int i = 0; i < GetNumSeq(); i++) + { + mstudioseqdesc_t &seqdesc = pSeqdesc( i ); + if (seqdesc.flags & STUDIO_AUTOPLAY) + { + count++; + } + } + return count; +} + +int studiohdr_t::CopyAutoplaySequences( unsigned short *pOut, int outCount ) const +{ + int outIndex = 0; + for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++) + { + mstudioseqdesc_t &seqdesc = pSeqdesc( i ); + if (seqdesc.flags & STUDIO_AUTOPLAY) + { + pOut[outIndex] = i; + outIndex++; + } + } + return outIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: maps local sequence bone to global bone +//----------------------------------------------------------------------------- + +int studiohdr_t::RemapSeqBone( int iSequence, int iLocalBone ) const +{ + // remap bone + virtualmodel_t *pVModel = GetVirtualModel(); + if (pVModel) + { + const virtualgroup_t *pSeqGroup = pVModel->pSeqGroup( iSequence ); + return pSeqGroup->masterBone[iLocalBone]; + } + return iLocalBone; +} + +int studiohdr_t::RemapAnimBone( int iAnim, int iLocalBone ) const +{ + // remap bone + virtualmodel_t *pVModel = GetVirtualModel(); + if (pVModel) + { + const virtualgroup_t *pAnimGroup = pVModel->pAnimGroup( iAnim ); + return pAnimGroup->masterBone[iLocalBone]; + } + return iLocalBone; +} + + + + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +CStudioHdr::CStudioHdr( void ) +{ + // set pointer to bogus value + m_nFrameUnlockCounter = 0; + m_pFrameUnlockCounter = &m_nFrameUnlockCounter; + Init( NULL ); +} + +CStudioHdr::CStudioHdr( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache ) +{ + // preset pointer to bogus value (it may be overwritten with legitimate data later) + m_nFrameUnlockCounter = 0; + m_pFrameUnlockCounter = &m_nFrameUnlockCounter; + Init( pStudioHdr, mdlcache ); +} + + +// extern IDataCache *g_pDataCache; + +void CStudioHdr::Init( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache ) +{ + m_pStudioHdr = pStudioHdr; + + m_pVModel = NULL; + m_pStudioHdrCache.RemoveAll(); + + if (m_pStudioHdr == NULL) + { + return; + } + + if ( mdlcache ) + { + m_pFrameUnlockCounter = mdlcache->GetFrameUnlockCounterPtr( MDLCACHE_STUDIOHDR ); + m_nFrameUnlockCounter = *m_pFrameUnlockCounter - 1; + } + + if (m_pStudioHdr->numincludemodels == 0) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE +#else + m_ActivityToSequence.Initialize(this); +#endif + } + else + { + ResetVModel( m_pStudioHdr->GetVirtualModel() ); +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE +#else + m_ActivityToSequence.Initialize(this); +#endif + } + + m_boneFlags.EnsureCount( numbones() ); + m_boneParent.EnsureCount( numbones() ); + for (int i = 0; i < numbones(); i++) + { + m_boneFlags[i] = pBone( i )->flags; + m_boneParent[i] = pBone( i )->parent; + } +} + +void CStudioHdr::Term() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +bool CStudioHdr::SequencesAvailable() const +{ + if (m_pStudioHdr->numincludemodels == 0) + { + return true; + } + + if (m_pVModel == NULL) + { + // repoll m_pVModel + return (ResetVModel( m_pStudioHdr->GetVirtualModel() ) != NULL); + } + else + return true; +} + + +const virtualmodel_t * CStudioHdr::ResetVModel( const virtualmodel_t *pVModel ) const +{ + if (pVModel != NULL) + { + m_pVModel = (virtualmodel_t *)pVModel; + Assert( !pVModel->m_Lock.GetOwnerId() ); + m_pStudioHdrCache.SetCount( m_pVModel->m_group.Count() ); + + int i; + for (i = 0; i < m_pStudioHdrCache.Count(); i++) + { + m_pStudioHdrCache[ i ] = NULL; + } + + return const_cast(pVModel); + } + else + { + m_pVModel = NULL; + return NULL; + } +} + +const studiohdr_t *CStudioHdr::GroupStudioHdr( int i ) +{ + if ( !this ) + { + ExecuteNTimes( 5, Warning( "Call to NULL CStudioHdr::GroupStudioHdr()\n" ) ); + } + + if ( m_nFrameUnlockCounter != *m_pFrameUnlockCounter ) + { + m_FrameUnlockCounterMutex.Lock(); + if ( *m_pFrameUnlockCounter != m_nFrameUnlockCounter ) // i.e., this thread got the mutex + { + memset( m_pStudioHdrCache.Base(), 0, m_pStudioHdrCache.Count() * sizeof(studiohdr_t *) ); + m_nFrameUnlockCounter = *m_pFrameUnlockCounter; + } + m_FrameUnlockCounterMutex.Unlock(); + } + + if ( !m_pStudioHdrCache.IsValidIndex( i ) ) + { + const char *pszName = ( m_pStudioHdr ) ? m_pStudioHdr->pszName() : "<>"; + ExecuteNTimes( 5, Warning( "Invalid index passed to CStudioHdr(%s)::GroupStudioHdr(): %d, but max is %d\n", pszName, i, m_pStudioHdrCache.Count() ) ); + DebuggerBreakIfDebugging(); + return m_pStudioHdr; // return something known to probably exist, certainly things will be messed up, but hopefully not crash before the warning is noticed + } + + const studiohdr_t *pStudioHdr = m_pStudioHdrCache[ i ]; + + if (pStudioHdr == NULL) + { + Assert( !m_pVModel->m_Lock.GetOwnerId() ); + virtualgroup_t *pGroup = &m_pVModel->m_group[ i ]; + pStudioHdr = pGroup->GetStudioHdr(); + m_pStudioHdrCache[ i ] = pStudioHdr; + } + + Assert( pStudioHdr ); + return pStudioHdr; +} + + +const studiohdr_t *CStudioHdr::pSeqStudioHdr( int sequence ) +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr; + } + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_seq[sequence].group ); + + return pStudioHdr; +} + + +const studiohdr_t *CStudioHdr::pAnimStudioHdr( int animation ) +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr; + } + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_anim[animation].group ); + + return pStudioHdr; +} + + + +mstudioanimdesc_t &CStudioHdr::pAnimdesc( int i ) +{ + if (m_pVModel == NULL) + { + return *m_pStudioHdr->pLocalAnimdesc( i ); + } + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_anim[i].group ); + + return *pStudioHdr->pLocalAnimdesc( m_pVModel->m_anim[i].index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetNumSeq( void ) const +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr->numlocalseq; + } + + return m_pVModel->m_seq.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +mstudioseqdesc_t &CStudioHdr::pSeqdesc( int i ) +{ + Assert( ( i >= 0 && i < GetNumSeq() ) || ( i == 1 && GetNumSeq() <= 1 ) ); + if ( i < 0 || i >= GetNumSeq() ) + { + if ( GetNumSeq() <= 0 ) + { + // Return a zero'd out struct reference if we've got nothing. + // C_BaseObject::StopAnimGeneratedSounds was crashing due to this function + // returning a reference to garbage. It should now see numevents is 0, + // and bail. + static mstudioseqdesc_t s_nil_seq; + return s_nil_seq; + } + + // Avoid reading random memory. + i = 0; + } + + if (m_pVModel == NULL) + { + return *m_pStudioHdr->pLocalSeqdesc( i ); + } + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_seq[i].group ); + + return *pStudioHdr->pLocalSeqdesc( m_pVModel->m_seq[i].index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::iRelativeAnim( int baseseq, int relanim ) const +{ + if (m_pVModel == NULL) + { + return relanim; + } + + virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[baseseq].group ]; + + return pGroup->masterAnim[ relanim ]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::iRelativeSeq( int baseseq, int relseq ) const +{ + if (m_pVModel == NULL) + { + return relseq; + } + + Assert( m_pVModel ); + + virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[baseseq].group ]; + + return pGroup->masterSeq[ relseq ]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetNumPoseParameters( void ) const +{ + if (m_pVModel == NULL) + { + if ( m_pStudioHdr ) + return m_pStudioHdr->numlocalposeparameters; + else + return 0; + } + + Assert( m_pVModel ); + + return m_pVModel->m_pose.Count(); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +const mstudioposeparamdesc_t &CStudioHdr::pPoseParameter( int i ) +{ + if (m_pVModel == NULL) + { + return *m_pStudioHdr->pLocalPoseParameter( i ); + } + + if ( m_pVModel->m_pose[i].group == 0) + return *m_pStudioHdr->pLocalPoseParameter( m_pVModel->m_pose[i].index ); + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_pose[i].group ); + + return *pStudioHdr->pLocalPoseParameter( m_pVModel->m_pose[i].index ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetSharedPoseParameter( int iSequence, int iLocalPose ) const +{ + if (m_pVModel == NULL) + { + return iLocalPose; + } + + if (iLocalPose == -1) + return iLocalPose; + + Assert( m_pVModel ); + + int group = m_pVModel->m_seq[iSequence].group; + virtualgroup_t *pGroup = m_pVModel->m_group.IsValidIndex( group ) ? &m_pVModel->m_group[ group ] : NULL; + + return pGroup ? pGroup->masterPose[iLocalPose] : iLocalPose; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::EntryNode( int iSequence ) +{ + mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence ); + + if (m_pVModel == NULL || seqdesc.localentrynode == 0) + { + return seqdesc.localentrynode; + } + + Assert( m_pVModel ); + + virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ]; + + return pGroup->masterNode[seqdesc.localentrynode-1]+1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +int CStudioHdr::ExitNode( int iSequence ) +{ + mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence ); + + if (m_pVModel == NULL || seqdesc.localexitnode == 0) + { + return seqdesc.localexitnode; + } + + Assert( m_pVModel ); + + virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ]; + + return pGroup->masterNode[seqdesc.localexitnode-1]+1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetNumAttachments( void ) const +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr->numlocalattachments; + } + + Assert( m_pVModel ); + + return m_pVModel->m_attachment.Count(); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +const mstudioattachment_t &CStudioHdr::pAttachment( int i ) +{ + if (m_pVModel == NULL) + { + return *m_pStudioHdr->pLocalAttachment( i ); + } + + Assert( m_pVModel ); + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_attachment[i].group ); + + return *pStudioHdr->pLocalAttachment( m_pVModel->m_attachment[i].index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetAttachmentBone( int i ) +{ + if (m_pVModel == 0) + { + return m_pStudioHdr->pLocalAttachment( i )->localbone; + } + + virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_attachment[i].group ]; + const mstudioattachment_t &attachment = pAttachment( i ); + int iBone = pGroup->masterBone[attachment.localbone]; + if (iBone == -1) + return 0; + return iBone; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void CStudioHdr::SetAttachmentBone( int iAttachment, int iBone ) +{ + mstudioattachment_t &attachment = (mstudioattachment_t &)m_pStudioHdr->pAttachment( iAttachment ); + + // remap bone + if (m_pVModel) + { + virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_attachment[iAttachment].group ]; + iBone = pGroup->boneMap[iBone]; + } + attachment.localbone = iBone; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +char *CStudioHdr::pszNodeName( int iNode ) +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr->pszLocalNodeName( iNode ); + } + + if ( m_pVModel->m_node.Count() <= iNode-1 ) + return "Invalid node"; + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_node[iNode-1].group ); + + return pStudioHdr->pszLocalNodeName( m_pVModel->m_node[iNode-1].index ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetTransition( int iFrom, int iTo ) const +{ + if (m_pVModel == NULL) + { + return *m_pStudioHdr->pLocalTransition( (iFrom-1)*m_pStudioHdr->numlocalnodes + (iTo - 1) ); + } + + return iTo; + /* + FIXME: not connected + virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); + Assert( pVModel ); + + return pVModel->m_transition.Element( iFrom ).Element( iTo ); + */ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetActivityListVersion( void ) +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr->activitylistversion; + } + + int version = m_pStudioHdr->activitylistversion; + + int i; + for (i = 1; i < m_pVModel->m_group.Count(); i++) + { + const studiohdr_t *pStudioHdr = GroupStudioHdr( i ); + Assert( pStudioHdr ); + version = vmin( version, pStudioHdr->activitylistversion ); + } + + return version; +} + +void CStudioHdr::SetActivityListVersion( int version ) +{ + m_pStudioHdr->activitylistversion = version; + + if (m_pVModel == NULL) + { + return; + } + + int i; + for (i = 1; i < m_pVModel->m_group.Count(); i++) + { + const studiohdr_t *pStudioHdr = GroupStudioHdr( i ); + Assert( pStudioHdr ); + pStudioHdr->SetActivityListVersion( version ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +int CStudioHdr::GetEventListVersion( void ) +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr->eventsindexed; + } + + int version = m_pStudioHdr->eventsindexed; + + int i; + for (i = 1; i < m_pVModel->m_group.Count(); i++) + { + const studiohdr_t *pStudioHdr = GroupStudioHdr( i ); + Assert( pStudioHdr ); + version = vmin( version, pStudioHdr->eventsindexed ); + } + + return version; +} + +void CStudioHdr::SetEventListVersion( int version ) +{ + m_pStudioHdr->eventsindexed = version; + + if (m_pVModel == NULL) + { + return; + } + + int i; + for (i = 1; i < m_pVModel->m_group.Count(); i++) + { + const studiohdr_t *pStudioHdr = GroupStudioHdr( i ); + Assert( pStudioHdr ); + pStudioHdr->eventsindexed = version; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +int CStudioHdr::GetNumIKAutoplayLocks( void ) const +{ + if (m_pVModel == NULL) + { + return m_pStudioHdr->numlocalikautoplaylocks; + } + + return m_pVModel->m_iklock.Count(); +} + +const mstudioiklock_t &CStudioHdr::pIKAutoplayLock( int i ) +{ + if (m_pVModel == NULL) + { + return *m_pStudioHdr->pLocalIKAutoplayLock( i ); + } + + const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_iklock[i].group ); + Assert( pStudioHdr ); + return *pStudioHdr->pLocalIKAutoplayLock( m_pVModel->m_iklock[i].index ); +} + +#if 0 +int CStudioHdr::CountAutoplaySequences() const +{ + int count = 0; + for (int i = 0; i < GetNumSeq(); i++) + { + mstudioseqdesc_t &seqdesc = pSeqdesc( i ); + if (seqdesc.flags & STUDIO_AUTOPLAY) + { + count++; + } + } + return count; +} + +int CStudioHdr::CopyAutoplaySequences( unsigned short *pOut, int outCount ) const +{ + int outIndex = 0; + for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++) + { + mstudioseqdesc_t &seqdesc = pSeqdesc( i ); + if (seqdesc.flags & STUDIO_AUTOPLAY) + { + pOut[outIndex] = i; + outIndex++; + } + } + return outIndex; +} + +#endif + +//----------------------------------------------------------------------------- +// Purpose: maps local sequence bone to global bone +//----------------------------------------------------------------------------- + +int CStudioHdr::RemapSeqBone( int iSequence, int iLocalBone ) const +{ + // remap bone + if (m_pVModel) + { + const virtualgroup_t *pSeqGroup = m_pVModel->pSeqGroup( iSequence ); + return pSeqGroup->masterBone[iLocalBone]; + } + return iLocalBone; +} + +int CStudioHdr::RemapAnimBone( int iAnim, int iLocalBone ) const +{ + // remap bone + if (m_pVModel) + { + const virtualgroup_t *pAnimGroup = m_pVModel->pAnimGroup( iAnim ); + return pAnimGroup->masterBone[iLocalBone]; + } + return iLocalBone; +} + +// JasonM hack +//ConVar flex_maxrule( "flex_maxrule", "0" ); + + +//----------------------------------------------------------------------------- +// Purpose: run the interpreted FAC's expressions, converting flex_controller +// values into FAC weights +//----------------------------------------------------------------------------- +void CStudioHdr::RunFlexRules( const float *src, float *dest ) +{ + int i, j; + + // FIXME: this shouldn't be needed, flex without rules should be stripped in studiomdl + for (i = 0; i < numflexdesc(); i++) + { + dest[i] = 0; + } + + for (i = 0; i < numflexrules(); i++) + { + float stack[32] = {}; + int k = 0; + mstudioflexrule_t *prule = pFlexRule( i ); + + mstudioflexop_t *pops = prule->iFlexOp( 0 ); +/* + // JasonM hack for flex perf testing... + int nFlexRulesToRun = 0; // 0 means run them all + const char *pszExpression = flex_maxrule.GetString(); + if ( pszExpression ) + { + nFlexRulesToRun = atoi(pszExpression); // 0 will be returned if not a numeric string + } + // end JasonM hack +//*/ + // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i + 1, 0, "%2d:%d\n", i, prule->flex ); + + for (j = 0; j < prule->numops; j++) + { + switch (pops->op) + { + case STUDIO_ADD: stack[k-2] = stack[k-2] + stack[k-1]; k--; break; + case STUDIO_SUB: stack[k-2] = stack[k-2] - stack[k-1]; k--; break; + case STUDIO_MUL: stack[k-2] = stack[k-2] * stack[k-1]; k--; break; + case STUDIO_DIV: + if (stack[k-1] > 0.0001) + { + stack[k-2] = stack[k-2] / stack[k-1]; + } + else + { + stack[k-2] = 0; + } + k--; + break; + case STUDIO_NEG: stack[k-1] = -stack[k-1]; break; + case STUDIO_MAX: stack[k-2] = vmax( stack[k-2], stack[k-1] ); k--; break; + case STUDIO_MIN: stack[k-2] = vmin( stack[k-2], stack[k-1] ); k--; break; + case STUDIO_CONST: stack[k] = pops->d.value; k++; break; + case STUDIO_FETCH1: + { + int m = pFlexcontroller( (LocalFlexController_t)pops->d.index)->localToGlobal; + stack[k] = src[m]; + k++; + break; + } + case STUDIO_FETCH2: + { + stack[k] = dest[pops->d.index]; k++; break; + } + case STUDIO_COMBO: + { + int m = pops->d.index; + int km = k - m; + for ( int i = km + 1; i < k; ++i ) + { + stack[ km ] *= stack[ i ]; + } + k = k - m + 1; + } + break; + case STUDIO_DOMINATE: + { + int m = pops->d.index; + int km = k - m; + float dv = stack[ km ]; + for ( int i = km + 1; i < k; ++i ) + { + dv *= stack[ i ]; + } + stack[ km - 1 ] *= 1.0f - dv; + k -= m; + } + break; + case STUDIO_2WAY_0: + { + int m = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal; + stack[ k ] = RemapValClamped( src[m], -1.0f, 0.0f, 1.0f, 0.0f ); + k++; + } + break; + case STUDIO_2WAY_1: + { + int m = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal; + stack[ k ] = RemapValClamped( src[m], 0.0f, 1.0f, 0.0f, 1.0f ); + k++; + } + break; + case STUDIO_NWAY: + { + LocalFlexController_t valueControllerIndex = static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ); + int m = pFlexcontroller( valueControllerIndex )->localToGlobal; + float flValue = src[ m ]; + int v = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal; + + const Vector4D filterRamp( stack[ k - 5 ], stack[ k - 4 ], stack[ k - 3 ], stack[ k - 2 ] ); + + // Apply multicontrol remapping + if ( flValue <= filterRamp.x || flValue >= filterRamp.w ) + { + flValue = 0.0f; + } + else if ( flValue < filterRamp.y ) + { + flValue = RemapValClamped( flValue, filterRamp.x, filterRamp.y, 0.0f, 1.0f ); + } + else if ( flValue > filterRamp.z ) + { + flValue = RemapValClamped( flValue, filterRamp.z, filterRamp.w, 1.0f, 0.0f ); + } + else + { + flValue = 1.0f; + } + + stack[ k - 5 ] = flValue * src[ v ]; + + k -= 4; + } + break; + case STUDIO_DME_LOWER_EYELID: + { + const mstudioflexcontroller_t *const pCloseLidV = pFlexcontroller( (LocalFlexController_t)pops->d.index ); + const float flCloseLidV = RemapValClamped( src[ pCloseLidV->localToGlobal ], pCloseLidV->min, pCloseLidV->max, 0.0f, 1.0f ); + + const mstudioflexcontroller_t *const pCloseLid = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ) ); + const float flCloseLid = RemapValClamped( src[ pCloseLid->localToGlobal ], pCloseLid->min, pCloseLid->max, 0.0f, 1.0f ); + + int nBlinkIndex = static_cast< int >( stack[ k - 2 ] ); + float flBlink = 0.0f; + if ( nBlinkIndex >= 0 ) + { + const mstudioflexcontroller_t *const pBlink = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 2 ] ) ); + flBlink = RemapValClamped( src[ pBlink->localToGlobal ], pBlink->min, pBlink->max, 0.0f, 1.0f ); + } + + int nEyeUpDownIndex = static_cast< int >( stack[ k - 3 ] ); + float flEyeUpDown = 0.0f; + if ( nEyeUpDownIndex >= 0 ) + { + const mstudioflexcontroller_t *const pEyeUpDown = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 3 ] ) ); + flEyeUpDown = RemapValClamped( src[ pEyeUpDown->localToGlobal ], pEyeUpDown->min, pEyeUpDown->max, -1.0f, 1.0f ); + } + + if ( flEyeUpDown > 0.0 ) + { + stack [ k - 3 ] = ( 1.0f - flEyeUpDown ) * ( 1.0f - flCloseLidV ) * flCloseLid; + } + else + { + stack [ k - 3 ] = ( 1.0f - flCloseLidV ) * flCloseLid; + } + k -= 2; + } + break; + case STUDIO_DME_UPPER_EYELID: + { + const mstudioflexcontroller_t *const pCloseLidV = pFlexcontroller( (LocalFlexController_t)pops->d.index ); + const float flCloseLidV = RemapValClamped( src[ pCloseLidV->localToGlobal ], pCloseLidV->min, pCloseLidV->max, 0.0f, 1.0f ); + + const mstudioflexcontroller_t *const pCloseLid = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ) ); + const float flCloseLid = RemapValClamped( src[ pCloseLid->localToGlobal ], pCloseLid->min, pCloseLid->max, 0.0f, 1.0f ); + + int nBlinkIndex = static_cast< int >( stack[ k - 2 ] ); + float flBlink = 0.0f; + if ( nBlinkIndex >= 0 ) + { + const mstudioflexcontroller_t *const pBlink = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 2 ] ) ); + flBlink = RemapValClamped( src[ pBlink->localToGlobal ], pBlink->min, pBlink->max, 0.0f, 1.0f ); + } + + int nEyeUpDownIndex = static_cast< int >( stack[ k - 3 ] ); + float flEyeUpDown = 0.0f; + if ( nEyeUpDownIndex >= 0 ) + { + const mstudioflexcontroller_t *const pEyeUpDown = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 3 ] ) ); + flEyeUpDown = RemapValClamped( src[ pEyeUpDown->localToGlobal ], pEyeUpDown->min, pEyeUpDown->max, -1.0f, 1.0f ); + } + + if ( flEyeUpDown < 0.0f ) + { + stack [ k - 3 ] = ( 1.0f + flEyeUpDown ) * flCloseLidV * flCloseLid; + } + else + { + stack [ k - 3 ] = flCloseLidV * flCloseLid; + } + k -= 2; + } + break; + } + + pops++; + } + + dest[prule->flex] = stack[0]; +/* + // JasonM hack + if ( nFlexRulesToRun == 0) // 0 means run all rules correctly + { + dest[prule->flex] = stack[0]; + } + else // run only up to nFlexRulesToRun correctly...zero out the rest + { + if ( j < nFlexRulesToRun ) + dest[prule->flex] = stack[0]; + else + dest[prule->flex] = 0.0f; + } + + dest[prule->flex] = 1.0f; +//*/ + // end JasonM hack + + } +} + + + +//----------------------------------------------------------------------------- +// CODE PERTAINING TO ACTIVITY->SEQUENCE MAPPING SUBCLASS +//----------------------------------------------------------------------------- +#define iabs(i) (( (i) >= 0 ) ? (i) : -(i) ) + +CUtlSymbolTable g_ActivityModifiersTable; + +extern void SetActivityForSequence( CStudioHdr *pstudiohdr, int i ); +void CStudioHdr::CActivityToSequenceMapping::Initialize( CStudioHdr * __restrict pstudiohdr ) +{ + // Algorithm: walk through every sequence in the model, determine to which activity + // it corresponds, and keep a count of sequences per activity. Once the total count + // is available, allocate an array large enough to contain them all, update the + // starting indices for every activity's section in the array, and go back through, + // populating the array with its data. + + AssertMsg1( m_pSequenceTuples == NULL, "Tried to double-initialize sequence mapping for %s", pstudiohdr->pszName() ); + if ( m_pSequenceTuples != NULL ) + return; // don't double initialize. + + SetValidationPair(pstudiohdr); + + if ( ! pstudiohdr->SequencesAvailable() ) + return; // nothing to do. + +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + m_bIsInitialized = true; +#endif + + // Some studio headers have no activities at all. In those + // cases we can avoid a lot of this effort. + bool bFoundOne = false; + + // for each sequence in the header... + const int NumSeq = pstudiohdr->GetNumSeq(); + for ( int i = 0 ; i < NumSeq ; ++i ) + { + const mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); +#if defined(SERVER_DLL) || defined(CLIENT_DLL) || defined(GAME_DLL) + if (!(seqdesc.flags & STUDIO_ACTIVITY)) + { + // AssertMsg2( false, "Sequence %d on studiohdr %s didn't have its activity initialized!", i, pstudiohdr->pszName() ); + SetActivityForSequence( pstudiohdr, i ); + } +#endif + + // is there an activity associated with this sequence? + if (seqdesc.activity >= 0) + { + bFoundOne = true; + + // look up if we already have an entry. First we need to make a speculative one -- + HashValueType entry(seqdesc.activity, 0, 1, iabs(seqdesc.actweight)); + UtlHashHandle_t handle = m_ActToSeqHash.Find(entry); + if ( m_ActToSeqHash.IsValidHandle(handle) ) + { + // we already have an entry and must update it by incrementing count + HashValueType * __restrict toUpdate = &m_ActToSeqHash.Element(handle); + toUpdate->count += 1; + toUpdate->totalWeight += iabs(seqdesc.actweight); + if ( !HushAsserts() ) + { + AssertMsg( toUpdate->totalWeight > 0, "toUpdate->totalWeight: %d", toUpdate->totalWeight ); + } + } + else + { + // we do not have an entry yet; create one. + m_ActToSeqHash.Insert(entry); + } + } + } + + // if we found nothing, don't bother with any other initialization! + if (!bFoundOne) + return; + + // Now, create starting indices for each activity. For an activity n, + // the starting index is of course the sum of counts [0..n-1]. + int sequenceCount = 0; + int topActivity = 0; // this will store the highest seen activity number (used later to make an ad hoc map on the stack) + for ( UtlHashHandle_t handle = m_ActToSeqHash.GetFirstHandle() ; + m_ActToSeqHash.IsValidHandle(handle) ; + handle = m_ActToSeqHash.GetNextHandle(handle) ) + { + HashValueType &element = m_ActToSeqHash[handle]; + element.startingIdx = sequenceCount; + sequenceCount += element.count; + topActivity = vmax(topActivity, element.activityIdx); + } + + + // Allocate the actual array of sequence information. Note the use of restrict; + // this is an important optimization, but means that you must never refer to this + // array through m_pSequenceTuples in the scope of this function. + SequenceTuple * __restrict tupleList = new SequenceTuple[sequenceCount]; + m_pSequenceTuples = tupleList; // save it off -- NEVER USE m_pSequenceTuples in this function! + m_iSequenceTuplesCount = sequenceCount; + + + + // Now we're going to actually populate that list with the relevant data. + // First, create an array on the stack to store how many sequences we've written + // so far for each activity. (This is basically a very simple way of doing a map.) + // This stack may potentially grow very large; so if you have problems with it, + // go to a utlmap or similar structure. + unsigned int allocsize = (topActivity + 1) * sizeof(int); +#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression + allocsize = ALIGN_VALUE(allocsize,16); + int * __restrict seqsPerAct = static_cast(stackalloc(allocsize)); + memset(seqsPerAct, 0, allocsize); + + // okay, walk through all the sequences again, and write the relevant data into + // our little table. + for ( int i = 0 ; i < NumSeq ; ++i ) + { + const mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if (seqdesc.activity >= 0) + { + const HashValueType &element = m_ActToSeqHash[m_ActToSeqHash.Find(HashValueType(seqdesc.activity, 0, 0, 0))]; + + // If this assert trips, we've written more sequences per activity than we allocated + // (therefore there must have been a miscount in the first for loop above). + int tupleOffset = seqsPerAct[seqdesc.activity]; + Assert( tupleOffset < element.count ); + + if ( seqdesc.numactivitymodifiers > 0 ) + { + // add entries for this model's activity modifiers + (tupleList + element.startingIdx + tupleOffset)->pActivityModifiers = new CUtlSymbol[ seqdesc.numactivitymodifiers ]; + (tupleList + element.startingIdx + tupleOffset)->iNumActivityModifiers = seqdesc.numactivitymodifiers; + + for ( int k = 0; k < seqdesc.numactivitymodifiers; k++ ) + { + (tupleList + element.startingIdx + tupleOffset)->pActivityModifiers[ k ] = g_ActivityModifiersTable.AddString( seqdesc.pActivityModifier( k )->pszName() ); + } + } + else + { + (tupleList + element.startingIdx + tupleOffset)->pActivityModifiers = NULL; + (tupleList + element.startingIdx + tupleOffset)->iNumActivityModifiers = 0; + } + + // You might be tempted to collapse this pointer math into a single pointer -- + // don't! the tuple list is marked __restrict above. + (tupleList + element.startingIdx + tupleOffset)->seqnum = i; // store sequence number + (tupleList + element.startingIdx + tupleOffset)->weight = iabs(seqdesc.actweight); + + // We can't have weights of 0 + // Assert( (tupleList + element.startingIdx + tupleOffset)->weight > 0 ); + if ( (tupleList + element.startingIdx + tupleOffset)->weight == 0 ) + { + (tupleList + element.startingIdx + tupleOffset)->weight = 1; + } + + seqsPerAct[seqdesc.activity] += 1; + } + } + +#ifdef DBGFLAG_ASSERT + // double check that we wrote exactly the right number of sequences. + unsigned int chkSequenceCount = 0; + for (int j = 0 ; j <= topActivity ; ++j) + { + chkSequenceCount += seqsPerAct[j]; + } + Assert(chkSequenceCount == m_iSequenceTuplesCount); +#endif + +} + +/// Force Initialize() to occur again, even if it has already occured. +void CStudioHdr::CActivityToSequenceMapping::Reinitialize( CStudioHdr *pstudiohdr ) +{ + m_bIsInitialized = false; + if (m_pSequenceTuples) + { + delete m_pSequenceTuples; + m_pSequenceTuples = NULL; + } + m_ActToSeqHash.RemoveAll(); + + Initialize(pstudiohdr); +} + +// Look up relevant data for an activity's sequences. This isn't terribly efficient, due to the +// load-hit-store on the output parameters, so the most common case -- SelectWeightedSequence -- +// is specially implemented. +const CStudioHdr::CActivityToSequenceMapping::SequenceTuple *CStudioHdr::CActivityToSequenceMapping::GetSequences( int forActivity, int * __restrict outSequenceCount, int * __restrict outTotalWeight ) +{ + // Construct a dummy entry so we can do a hash lookup (the UtlHash does not divorce keys from values) + + HashValueType entry(forActivity, 0, 0, 0); + UtlHashHandle_t handle = m_ActToSeqHash.Find(entry); + + if (m_ActToSeqHash.IsValidHandle(handle)) + { + const HashValueType &element = m_ActToSeqHash[handle]; + const SequenceTuple *retval = m_pSequenceTuples + element.startingIdx; + *outSequenceCount = element.count; + *outTotalWeight = element.totalWeight; + + return retval; + } + else + { + // invalid handle; return NULL. + // this is actually a legit use case, so no need to assert. + return NULL; + } +} + +int CStudioHdr::CActivityToSequenceMapping::NumSequencesForActivity( int forActivity ) +{ + // If this trips, you've called this function on something that doesn't + // have activities. + //Assert(m_pSequenceTuples != NULL); + if ( m_pSequenceTuples == NULL ) + return 0; + + HashValueType entry(forActivity, 0, 0, 0); + UtlHashHandle_t handle = m_ActToSeqHash.Find(entry); + if (m_ActToSeqHash.IsValidHandle(handle)) + { + return m_ActToSeqHash[handle].count; + } + else + { + return 0; + } +} + +// double-check that the data I point to hasn't changed +bool CStudioHdr::CActivityToSequenceMapping::ValidateAgainst( const CStudioHdr * RESTRICT pstudiohdr ) RESTRICT +{ + if (m_bIsInitialized) + { + return m_expectedPStudioHdr == pstudiohdr->GetRenderHdr() && + m_expectedVModel == pstudiohdr->GetVirtualModel(); + } + else + { + return true; // Allow an ordinary initialization to take place without printing a panicky assert. + } +} + +void CStudioHdr::CActivityToSequenceMapping::SetValidationPair( const CStudioHdr *RESTRICT pstudiohdr ) RESTRICT +{ + m_expectedPStudioHdr = pstudiohdr->GetRenderHdr(); + m_expectedVModel = pstudiohdr->GetVirtualModel(); +} \ No newline at end of file diff --git a/public/studio.h b/public/studio.h new file mode 100644 index 0000000..f978bfd --- /dev/null +++ b/public/studio.h @@ -0,0 +1,3230 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef STUDIO_H +#define STUDIO_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "mathlib/vector2d.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "mathlib/compressed_vector.h" +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "mathlib/mathlib.h" +#include "utlvector.h" +#include "utlhash.h" +#include "datamap.h" +#include "generichash.h" +#include "localflexcontroller.h" +#include "utlsymbol.h" + +#define STUDIO_ENABLE_PERF_COUNTERS + +#define STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW 0 +// If this is set to 1, then the activity->sequence mapping inside +// the CStudioHdr will not be initialized until the first call to +// SelectWeightedSequence() or HaveSequenceForActivity(). If set +// to zero, the mapping will be initialized from CStudioHdr::Init() +// (itself called from the constructor). +// As of June 4 2007, this was set to 1 because physics, among other +// systems, extemporaneously declares CStudioHdrs inside local function +// scopes without querying their activity/sequence mapping at all. +#define STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE 1 + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- + +class IMaterial; +class IMesh; +class IMorph; +struct virtualmodel_t; +struct vertexFileHeader_t; +struct thinModelVertices_t; + +namespace OptimizedModel +{ + struct StripHeader_t; +} + + +/* +============================================================================== + +STUDIO MODELS + +Studio models are position independent, so the cache manager can move them. +============================================================================== +*/ + +#define STUDIO_VERSION 48 + +#ifndef _XBOX +#define MAXSTUDIOTRIANGLES 65536 // TODO: tune this +#define MAXSTUDIOVERTS 65536 // TODO: tune this +#define MAXSTUDIOFLEXVERTS 10000 // max number of verts that can be flexed per mesh. TODO: tune this +#else +#define MAXSTUDIOTRIANGLES 25000 +#define MAXSTUDIOVERTS 10000 +#define MAXSTUDIOFLEXVERTS 1000 +#endif +#define MAXSTUDIOSKINS 32 // total textures +#define MAXSTUDIOBONES 128 // total bones actually used +#define MAXSTUDIOFLEXDESC 1024 // maximum number of low level flexes (actual morph targets) +#define MAXSTUDIOFLEXCTRL 96 // maximum number of flexcontrollers (input sliders) +#define MAXSTUDIOPOSEPARAM 24 +#define MAXSTUDIOBONECTRLS 4 +#define MAXSTUDIOANIMBLOCKS 256 + +#define MAXSTUDIOBONEBITS 7 // NOTE: MUST MATCH MAXSTUDIOBONES + +// NOTE!!! : Changing this number also changes the vtx file format!!!!! +#define MAX_NUM_BONES_PER_VERT 3 + +//Adrian - Remove this when we completely phase out the old event system. +#define NEW_EVENT_STYLE ( 1 << 10 ) + +struct mstudiodata_t +{ + int count; + int offset; +}; + +#define STUDIO_PROC_AXISINTERP 1 +#define STUDIO_PROC_QUATINTERP 2 +#define STUDIO_PROC_AIMATBONE 3 +#define STUDIO_PROC_AIMATATTACH 4 +#define STUDIO_PROC_JIGGLE 5 + +struct mstudioaxisinterpbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + int control;// local transformation of this bone used to calc 3 point blend + int axis; // axis to check + Vector pos[6]; // X+, X-, Y+, Y-, Z+, Z- + Quaternion quat[6];// X+, X-, Y+, Y-, Z+, Z- + + mstudioaxisinterpbone_t(){} +private: + // No copy constructors allowed + mstudioaxisinterpbone_t(const mstudioaxisinterpbone_t& vOther); +}; + + +struct mstudioquatinterpinfo_t +{ + DECLARE_BYTESWAP_DATADESC(); + float inv_tolerance; // 1 / radian angle of trigger influence + Quaternion trigger; // angle to match + Vector pos; // new position + Quaternion quat; // new angle + + mstudioquatinterpinfo_t(){} +private: + // No copy constructors allowed + mstudioquatinterpinfo_t(const mstudioquatinterpinfo_t& vOther); +}; + +struct mstudioquatinterpbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + int control;// local transformation to check + int numtriggers; + int triggerindex; + inline mstudioquatinterpinfo_t *pTrigger( int i ) const { return (mstudioquatinterpinfo_t *)(((byte *)this) + triggerindex) + i; }; + + mstudioquatinterpbone_t(){} +private: + // No copy constructors allowed + mstudioquatinterpbone_t(const mstudioquatinterpbone_t& vOther); +}; + + +#define JIGGLE_IS_FLEXIBLE 0x01 +#define JIGGLE_IS_RIGID 0x02 +#define JIGGLE_HAS_YAW_CONSTRAINT 0x04 +#define JIGGLE_HAS_PITCH_CONSTRAINT 0x08 +#define JIGGLE_HAS_ANGLE_CONSTRAINT 0x10 +#define JIGGLE_HAS_LENGTH_CONSTRAINT 0x20 +#define JIGGLE_HAS_BASE_SPRING 0x40 +#define JIGGLE_IS_BOING 0x80 // simple squash and stretch sinusoid "boing" + +struct mstudiojigglebone_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int flags; + + // general params + float length; // how from from bone base, along bone, is tip + float tipMass; + + // flexible params + float yawStiffness; + float yawDamping; + float pitchStiffness; + float pitchDamping; + float alongStiffness; + float alongDamping; + + // angle constraint + float angleLimit; // maximum deflection of tip in radians + + // yaw constraint + float minYaw; // in radians + float maxYaw; // in radians + float yawFriction; + float yawBounce; + + // pitch constraint + float minPitch; // in radians + float maxPitch; // in radians + float pitchFriction; + float pitchBounce; + + // base spring + float baseMass; + float baseStiffness; + float baseDamping; + float baseMinLeft; + float baseMaxLeft; + float baseLeftFriction; + float baseMinUp; + float baseMaxUp; + float baseUpFriction; + float baseMinForward; + float baseMaxForward; + float baseForwardFriction; + + // boing + float boingImpactSpeed; + float boingImpactAngle; + float boingDampingRate; + float boingFrequency; + float boingAmplitude; + +private: + // No copy constructors allowed + //mstudiojigglebone_t(const mstudiojigglebone_t& vOther); +}; + +struct mstudioaimatbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int parent; + int aim; // Might be bone or attach + Vector aimvector; + Vector upvector; + Vector basepos; + + mstudioaimatbone_t() {} +private: + // No copy constructors allowed + mstudioaimatbone_t(const mstudioaimatbone_t& vOther); +}; + +// bones +struct mstudiobone_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int parent; // parent bone + int bonecontroller[6]; // bone controller index, -1 == none + + // default values + Vector pos; + Quaternion quat; + RadianEuler rot; + // compression scale + Vector posscale; + Vector rotscale; + + matrix3x4_t poseToBone; + Quaternion qAlignment; + int flags; + int proctype; + int procindex; // procedural rule + mutable int physicsbone; // index into physically simulated bone + inline void *pProcedure( ) const { if (procindex == 0) return NULL; else return (void *)(((byte *)this) + procindex); }; + int surfacepropidx; // index into string tablefor property name + inline const char *pszSurfaceProp( void ) const { return ((char *)this) + surfacepropidx; } + int contents; // See BSPFlags.h for the contents flags + + int unused[8]; // remove as appropriate + + mstudiobone_t(){} +private: + // No copy constructors allowed + mstudiobone_t(const mstudiobone_t& vOther); +}; + +struct mstudiolinearbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int numbones; + + int flagsindex; + inline int flags( int i ) const { Assert( i >= 0 && i < numbones); return *((int *)(((byte *)this) + flagsindex) + i); }; + inline int *pflags( int i ) { Assert( i >= 0 && i < numbones); return ((int *)(((byte *)this) + flagsindex) + i); }; + + int parentindex; + inline int parent( int i ) const { Assert( i >= 0 && i < numbones); return *((int *)(((byte *)this) + parentindex) + i); }; + + int posindex; + inline Vector pos( int i ) const { Assert( i >= 0 && i < numbones); return *((Vector *)(((byte *)this) + posindex) + i); }; + + int quatindex; + inline Quaternion quat( int i ) const { Assert( i >= 0 && i < numbones); return *((Quaternion *)(((byte *)this) + quatindex) + i); }; + + int rotindex; + inline RadianEuler rot( int i ) const { Assert( i >= 0 && i < numbones); return *((RadianEuler *)(((byte *)this) + rotindex) + i); }; + + int posetoboneindex; + inline matrix3x4_t poseToBone( int i ) const { Assert( i >= 0 && i < numbones); return *((matrix3x4_t *)(((byte *)this) + posetoboneindex) + i); }; + + int posscaleindex; + inline Vector posscale( int i ) const { Assert( i >= 0 && i < numbones); return *((Vector *)(((byte *)this) + posscaleindex) + i); }; + + int rotscaleindex; + inline Vector rotscale( int i ) const { Assert( i >= 0 && i < numbones); return *((Vector *)(((byte *)this) + rotscaleindex) + i); }; + + int qalignmentindex; + inline Quaternion qalignment( int i ) const { Assert( i >= 0 && i < numbones); return *((Quaternion *)(((byte *)this) + qalignmentindex) + i); }; + + int unused[6]; + + mstudiolinearbone_t(){} +private: + // No copy constructors allowed + mstudiolinearbone_t(const mstudiolinearbone_t& vOther); +}; + + +//----------------------------------------------------------------------------- +// The component of the bone used by mstudioboneflexdriver_t +//----------------------------------------------------------------------------- +enum StudioBoneFlexComponent_t +{ + STUDIO_BONE_FLEX_INVALID = -1, // Invalid + STUDIO_BONE_FLEX_TX = 0, // Translate X + STUDIO_BONE_FLEX_TY = 1, // Translate Y + STUDIO_BONE_FLEX_TZ = 2 // Translate Z +}; + + +//----------------------------------------------------------------------------- +// Component is one of Translate X, Y or Z [0,2] (StudioBoneFlexComponent_t) +//----------------------------------------------------------------------------- +struct mstudioboneflexdrivercontrol_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int m_nBoneComponent; // Bone component that drives flex, StudioBoneFlexComponent_t + int m_nFlexControllerIndex; // Flex controller to drive + float m_flMin; // Min value of bone component mapped to 0 on flex controller + float m_flMax; // Max value of bone component mapped to 1 on flex controller + + mstudioboneflexdrivercontrol_t(){} +private: + // No copy constructors allowed + mstudioboneflexdrivercontrol_t( const mstudioboneflexdrivercontrol_t &vOther ); +}; + + +//----------------------------------------------------------------------------- +// Drive flex controllers from bone components +//----------------------------------------------------------------------------- +struct mstudioboneflexdriver_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int m_nBoneIndex; // Bone to drive flex controller + int m_nControlCount; // Number of flex controllers being driven + int m_nControlIndex; // Index into data where controllers are (relative to this) + + inline mstudioboneflexdrivercontrol_t *pBoneFlexDriverControl( int i ) const + { + Assert( i >= 0 && i < m_nControlCount ); + return (mstudioboneflexdrivercontrol_t *)(((byte *)this) + m_nControlIndex) + i; + } + + int unused[3]; + + mstudioboneflexdriver_t(){} +private: + // No copy constructors allowed + mstudioboneflexdriver_t( const mstudioboneflexdriver_t &vOther ); +}; + + +#define BONE_CALCULATE_MASK 0x1F +#define BONE_PHYSICALLY_SIMULATED 0x01 // bone is physically simulated when physics are active +#define BONE_PHYSICS_PROCEDURAL 0x02 // procedural when physics is active +#define BONE_ALWAYS_PROCEDURAL 0x04 // bone is always procedurally animated +#define BONE_SCREEN_ALIGN_SPHERE 0x08 // bone aligns to the screen, not constrained in motion. +#define BONE_SCREEN_ALIGN_CYLINDER 0x10 // bone aligns to the screen, constrained by it's own axis. + +#define BONE_USED_MASK 0x0007FF00 +#define BONE_USED_BY_ANYTHING 0x0007FF00 +#define BONE_USED_BY_HITBOX 0x00000100 // bone (or child) is used by a hit box +#define BONE_USED_BY_ATTACHMENT 0x00000200 // bone (or child) is used by an attachment point +#define BONE_USED_BY_VERTEX_MASK 0x0003FC00 +#define BONE_USED_BY_VERTEX_LOD0 0x00000400 // bone (or child) is used by the toplevel model via skinned vertex +#define BONE_USED_BY_VERTEX_LOD1 0x00000800 +#define BONE_USED_BY_VERTEX_LOD2 0x00001000 +#define BONE_USED_BY_VERTEX_LOD3 0x00002000 +#define BONE_USED_BY_VERTEX_LOD4 0x00004000 +#define BONE_USED_BY_VERTEX_LOD5 0x00008000 +#define BONE_USED_BY_VERTEX_LOD6 0x00010000 +#define BONE_USED_BY_VERTEX_LOD7 0x00020000 +#define BONE_USED_BY_BONE_MERGE 0x00040000 // bone is available for bone merge to occur against it + +#define BONE_USED_BY_VERTEX_AT_LOD(lod) ( BONE_USED_BY_VERTEX_LOD0 << (lod) ) +#define BONE_USED_BY_ANYTHING_AT_LOD(lod) ( ( BONE_USED_BY_ANYTHING & ~BONE_USED_BY_VERTEX_MASK ) | BONE_USED_BY_VERTEX_AT_LOD(lod) ) + +#define MAX_NUM_LODS 8 + +#define BONE_TYPE_MASK 0x00F00000 +#define BONE_FIXED_ALIGNMENT 0x00100000 // bone can't spin 360 degrees, all interpolation is normalized around a fixed orientation + +#define BONE_HAS_SAVEFRAME_POS 0x00200000 // Vector48 +#define BONE_HAS_SAVEFRAME_ROT 0x00400000 // Quaternion64 + +// bone controllers +struct mstudiobonecontroller_t +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; // -1 == 0 + int type; // X, Y, Z, XR, YR, ZR, M + float start; + float end; + int rest; // byte index value at rest + int inputfield; // 0-3 user set controller, 4 mouth + int unused[8]; +}; + +// intersection boxes +struct mstudiobbox_t +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + int group; // intersection group + Vector bbmin; // bounding box + Vector bbmax; + int szhitboxnameindex; // offset to the name of the hitbox. + int unused[8]; + + const char* pszHitboxName() + { + if( szhitboxnameindex == 0 ) + return ""; + + return ((const char*)this) + szhitboxnameindex; + } + + mstudiobbox_t() {} + +private: + // No copy constructors allowed + mstudiobbox_t(const mstudiobbox_t& vOther); +}; + +// demand loaded sequence groups +struct mstudiomodelgroup_t +{ + DECLARE_BYTESWAP_DATADESC(); + int szlabelindex; // textual name + inline const char *pszLabel( void ) const { return ((char *)this) + szlabelindex; } + int sznameindex; // file name + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } +}; + +struct mstudiomodelgrouplookup_t +{ + int modelgroup; + int indexwithingroup; +}; + +// events +struct mstudioevent_t +{ + DECLARE_BYTESWAP_DATADESC(); + float cycle; + int event; + int type; + inline const char *pszOptions( void ) const { return options; } + char options[64]; + + int szeventindex; + inline const char *pszEventName( void ) const { return ((char *)this) + szeventindex; } +}; + +#define ATTACHMENT_FLAG_WORLD_ALIGN 0x10000 + +// attachment +struct mstudioattachment_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + unsigned int flags; + int localbone; + matrix3x4_t local; // attachment point + int unused[8]; +}; + +#define IK_SELF 1 +#define IK_WORLD 2 +#define IK_GROUND 3 +#define IK_RELEASE 4 +#define IK_ATTACHMENT 5 +#define IK_UNLATCH 6 + +struct mstudioikerror_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector pos; + Quaternion q; + + mstudioikerror_t() {} + +private: + // No copy constructors allowed + mstudioikerror_t(const mstudioikerror_t& vOther); +}; + +union mstudioanimvalue_t; + +struct mstudiocompressedikerror_t +{ + DECLARE_BYTESWAP_DATADESC(); + float scale[6]; + short offset[6]; + inline mstudioanimvalue_t *pAnimvalue( int i ) const { if (offset[i] > 0) return (mstudioanimvalue_t *)(((byte *)this) + offset[i]); else return NULL; }; + mstudiocompressedikerror_t(){} + +private: + // No copy constructors allowed + mstudiocompressedikerror_t(const mstudiocompressedikerror_t& vOther); +}; + +struct mstudioikrule_t +{ + DECLARE_BYTESWAP_DATADESC(); + int index; + + int type; + int chain; + + int bone; + + int slot; // iktarget slot. Usually same as chain. + float height; + float radius; + float floor; + Vector pos; + Quaternion q; + + int compressedikerrorindex; + inline mstudiocompressedikerror_t *pCompressedError() const { return (mstudiocompressedikerror_t *)(((byte *)this) + compressedikerrorindex); }; + int unused2; + + int iStart; + int ikerrorindex; + inline mstudioikerror_t *pError( int i ) const { return (ikerrorindex) ? (mstudioikerror_t *)(((byte *)this) + ikerrorindex) + (i - iStart) : NULL; }; + + float start; // beginning of influence + float peak; // start of full influence + float tail; // end of full influence + float end; // end of all influence + + float unused3; // + float contact; // frame footstep makes ground concact + float drop; // how far down the foot should drop when reaching for IK + float top; // top of the foot box + + int unused6; + int unused7; + int unused8; + + int szattachmentindex; // name of world attachment + inline const char *pszAttachment( void ) const { return ((char *)this) + szattachmentindex; } + + int unused[7]; + + mstudioikrule_t() {} + +private: + // No copy constructors allowed + mstudioikrule_t(const mstudioikrule_t& vOther); +}; + + +struct mstudioiklock_t +{ + DECLARE_BYTESWAP_DATADESC(); + int chain; + float flPosWeight; + float flLocalQWeight; + int flags; + + int unused[4]; +}; + + +struct mstudiolocalhierarchy_t +{ + DECLARE_BYTESWAP_DATADESC(); + int iBone; // bone being adjusted + int iNewParent; // the bones new parent + + float start; // beginning of influence + float peak; // start of full influence + float tail; // end of full influence + float end; // end of all influence + + int iStart; // first frame + + int localanimindex; + inline mstudiocompressedikerror_t *pLocalAnim() const { return (mstudiocompressedikerror_t *)(((byte *)this) + localanimindex); }; + + int unused[4]; +}; + + + +// animation frames +union mstudioanimvalue_t +{ + struct + { + byte valid; + byte total; + } num; + short value; +}; + +struct mstudioanim_valueptr_t +{ + DECLARE_BYTESWAP_DATADESC(); + short offset[3]; + inline mstudioanimvalue_t *pAnimvalue( int i ) const { if (offset[i] > 0) return (mstudioanimvalue_t *)(((byte *)this) + offset[i]); else return NULL; }; +}; + +#define STUDIO_ANIM_RAWPOS 0x01 // Vector48 +#define STUDIO_ANIM_RAWROT 0x02 // Quaternion48 +#define STUDIO_ANIM_ANIMPOS 0x04 // mstudioanim_valueptr_t +#define STUDIO_ANIM_ANIMROT 0x08 // mstudioanim_valueptr_t +#define STUDIO_ANIM_DELTA 0x10 +#define STUDIO_ANIM_RAWROT2 0x20 // Quaternion64 + + +// per bone per animation DOF and weight pointers +struct mstudioanim_t +{ + DECLARE_BYTESWAP_DATADESC(); + byte bone; + byte flags; // weighing options + + // valid for animating data only + inline byte *pData( void ) const { return (((byte *)this) + sizeof( struct mstudioanim_t )); }; + inline mstudioanim_valueptr_t *pRotV( void ) const { return (mstudioanim_valueptr_t *)(pData()); }; + inline mstudioanim_valueptr_t *pPosV( void ) const { return (mstudioanim_valueptr_t *)(pData()) + ((flags & STUDIO_ANIM_ANIMROT) != 0); }; + + // valid if animation unvaring over timeline + inline Quaternion48 *pQuat48( void ) const { return (Quaternion48 *)(pData()); }; + inline Quaternion64 *pQuat64( void ) const { return (Quaternion64 *)(pData()); }; + inline Vector48 *pPos( void ) const { return (Vector48 *)(pData() + ((flags & STUDIO_ANIM_RAWROT) != 0) * sizeof( *pQuat48() ) + ((flags & STUDIO_ANIM_RAWROT2) != 0) * sizeof( *pQuat64() ) ); }; + + short nextoffset; + inline mstudioanim_t *pNext( void ) const { if (nextoffset != 0) return (mstudioanim_t *)(((byte *)this) + nextoffset); else return NULL; }; +}; + +struct mstudiomovement_t +{ + DECLARE_BYTESWAP_DATADESC(); + int endframe; + int motionflags; + float v0; // velocity at start of block + float v1; // velocity at end of block + float angle; // YAW rotation at end of this blocks movement + Vector vector; // movement vector relative to this blocks initial angle + Vector position; // relative to start of animation??? + + mstudiomovement_t(){} +private: + // No copy constructors allowed + mstudiomovement_t(const mstudiomovement_t& vOther); +}; + +struct studiohdr_t; + +// used for piecewise loading of animation data +struct mstudioanimblock_t +{ + DECLARE_BYTESWAP_DATADESC(); + int datastart; + int dataend; +}; + +struct mstudioanimsections_t +{ + DECLARE_BYTESWAP_DATADESC(); + int animblock; + int animindex; +}; + +struct mstudioanimdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int baseptr; + inline studiohdr_t *pStudiohdr( void ) const { return (studiohdr_t *)(((byte *)this) + baseptr); } + + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + + float fps; // frames per second + int flags; // looping/non-looping flags + + int numframes; + + // piecewise movement + int nummovements; + int movementindex; + inline const mstudiomovement_t *pMovement( int i ) const { return (mstudiomovement_t *)(((byte *)this) + movementindex) + i; }; + + int unused1[6]; // remove as appropriate (and zero if loading older versions) + + int animblock; + int animindex; // non-zero when anim data isn't in sections + mstudioanim_t *pAnimBlock( int block, int index ) const; // returns pointer to a specific anim block (local or external) + mstudioanim_t *pAnim( int *piFrame, float &flStall ) const; // returns pointer to data and new frame index + mstudioanim_t *pAnim( int *piFrame ) const; // returns pointer to data and new frame index + + int numikrules; + int ikruleindex; // non-zero when IK data is stored in the mdl + int animblockikruleindex; // non-zero when IK data is stored in animblock file + mstudioikrule_t *pIKRule( int i ) const; + + int numlocalhierarchy; + int localhierarchyindex; + mstudiolocalhierarchy_t *pHierarchy( int i ) const; + + int sectionindex; + int sectionframes; // number of frames used in each fast lookup section, zero if not used + inline const mstudioanimsections_t *pSection( int i ) const { return (mstudioanimsections_t *)(((byte *)this) + sectionindex) + i; } + + short zeroframespan; // frames per span + short zeroframecount; // number of spans + int zeroframeindex; + byte *pZeroFrameData( ) const { if (zeroframeindex) return (((byte *)this) + zeroframeindex); else return NULL; }; + mutable float zeroframestalltime; // saved during read stalls + + mstudioanimdesc_t(){} +private: + // No copy constructors allowed + mstudioanimdesc_t(const mstudioanimdesc_t& vOther); +}; + +struct mstudioikrule_t; + +struct mstudioautolayer_t +{ + DECLARE_BYTESWAP_DATADESC(); +//private: + short iSequence; + short iPose; +//public: + int flags; + float start; // beginning of influence + float peak; // start of full influence + float tail; // end of full influence + float end; // end of all influence +}; + +struct mstudioactivitymodifier_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int sznameindex; + inline char *pszName() { return (sznameindex) ? (char *)(((byte *)this) + sznameindex ) : NULL; } +}; + +// sequence descriptions +struct mstudioseqdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int baseptr; + inline studiohdr_t *pStudiohdr( void ) const { return (studiohdr_t *)(((byte *)this) + baseptr); } + + int szlabelindex; + inline const char *pszLabel( void ) const { return ((char *)this) + szlabelindex; } + + int szactivitynameindex; + inline const char *pszActivityName( void ) const { return ((char *)this) + szactivitynameindex; } + + int flags; // looping/non-looping flags + + int activity; // initialized at loadtime to game DLL values + int actweight; + + int numevents; + int eventindex; + inline mstudioevent_t *pEvent( int i ) const { Assert( i >= 0 && i < numevents); return (mstudioevent_t *)(((byte *)this) + eventindex) + i; }; + + Vector bbmin; // per sequence bounding box + Vector bbmax; + + int numblends; + + // Index into array of shorts which is groupsize[0] x groupsize[1] in length + int animindexindex; + + inline int anim( int x, int y ) const + { + if ( x >= groupsize[0] ) + { + x = groupsize[0] - 1; + } + + if ( y >= groupsize[1] ) + { + y = groupsize[ 1 ] - 1; + } + + int offset = y * groupsize[0] + x; + short *blends = (short *)(((byte *)this) + animindexindex); + int value = (int)blends[ offset ]; + return value; + } + + int movementindex; // [blend] float array for blended movement + int groupsize[2]; + int paramindex[2]; // X, Y, Z, XR, YR, ZR + float paramstart[2]; // local (0..1) starting value + float paramend[2]; // local (0..1) ending value + int paramparent; + + float fadeintime; // ideal cross fate in time (0.2 default) + float fadeouttime; // ideal cross fade out time (0.2 default) + + int localentrynode; // transition node at entry + int localexitnode; // transition node at exit + int nodeflags; // transition rules + + float entryphase; // used to match entry gait + float exitphase; // used to match exit gait + + float lastframe; // frame that should generation EndOfSequence + + int nextseq; // auto advancing sequences + int pose; // index of delta animation between end and nextseq + + int numikrules; + + int numautolayers; // + int autolayerindex; + inline mstudioautolayer_t *pAutolayer( int i ) const { Assert( i >= 0 && i < numautolayers); return (mstudioautolayer_t *)(((byte *)this) + autolayerindex) + i; }; + + int weightlistindex; + inline float *pBoneweight( int i ) const { return ((float *)(((byte *)this) + weightlistindex) + i); }; + inline float weight( int i ) const { return *(pBoneweight( i)); }; + + // FIXME: make this 2D instead of 2x1D arrays + int posekeyindex; + float *pPoseKey( int iParam, int iAnim ) const { return (float *)(((byte *)this) + posekeyindex) + iParam * groupsize[0] + iAnim; } + float poseKey( int iParam, int iAnim ) const { return *(pPoseKey( iParam, iAnim )); } + + int numiklocks; + int iklockindex; + inline mstudioiklock_t *pIKLock( int i ) const { Assert( i >= 0 && i < numiklocks); return (mstudioiklock_t *)(((byte *)this) + iklockindex) + i; }; + + // Key values + int keyvalueindex; + int keyvaluesize; + inline const char *KeyValueText( void ) const { return keyvaluesize != 0 ? ((char *)this) + keyvalueindex : NULL; } + + int cycleposeindex; // index of pose parameter to use as cycle index + + int activitymodifierindex; + int numactivitymodifiers; + inline mstudioactivitymodifier_t *pActivityModifier( int i ) const { Assert( i >= 0 && i < numactivitymodifiers); return activitymodifierindex != 0 ? (mstudioactivitymodifier_t *)(((byte *)this) + activitymodifierindex) + i : NULL; }; + + int unused[5]; // remove/add as appropriate (grow back to 8 ints on version change!) + + mstudioseqdesc_t(){} +private: + // No copy constructors allowed + mstudioseqdesc_t(const mstudioseqdesc_t& vOther); +}; + + +struct mstudioposeparamdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int flags; // ???? + float start; // starting value + float end; // ending value + float loop; // looping range, 0 for no looping, 360 for rotations, etc. +}; + +struct mstudioflexdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int szFACSindex; + inline const char *pszFACS( void ) const { return ((char *)this) + szFACSindex; } +}; + + + +struct mstudioflexcontroller_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sztypeindex; + inline const char *pszType( void ) const { return ((char *)this) + sztypeindex; } + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + mutable int localToGlobal; // remapped at load time to master list + float min; + float max; +}; + + +enum FlexControllerRemapType_t +{ + FLEXCONTROLLER_REMAP_PASSTHRU = 0, + FLEXCONTROLLER_REMAP_2WAY, // Control 0 -> ramps from 1-0 from 0->0.5. Control 1 -> ramps from 0-1 from 0.5->1 + FLEXCONTROLLER_REMAP_NWAY, // StepSize = 1 / (control count-1) Control n -> ramps from 0-1-0 from (n-1)*StepSize to n*StepSize to (n+1)*StepSize. A second control is needed to specify amount to use + FLEXCONTROLLER_REMAP_EYELID +}; + + +class CStudioHdr; +struct mstudioflexcontrollerui_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + + // These are used like a union to save space + // Here are the possible configurations for a UI controller + // + // SIMPLE NON-STEREO: 0: control 1: unused 2: unused + // STEREO: 0: left 1: right 2: unused + // NWAY NON-STEREO: 0: control 1: unused 2: value + // NWAY STEREO: 0: left 1: right 2: value + + int szindex0; + int szindex1; + int szindex2; + + inline const mstudioflexcontroller_t *pController( void ) const + { + return !stereo ? (mstudioflexcontroller_t *)( (char *)this + szindex0 ) : NULL; + } + inline const char *pszControllerName( void ) const { return !stereo ? pController()->pszName() : NULL; } + inline int controllerIndex( const CStudioHdr &cStudioHdr ) const; + + inline const mstudioflexcontroller_t *pLeftController( void ) const + { + return stereo ? (mstudioflexcontroller_t *)( (char *)this + szindex0 ) : NULL; + } + inline const char *pszLeftName( void ) const { return stereo ? pLeftController()->pszName() : NULL; } + inline int leftIndex( const CStudioHdr &cStudioHdr ) const; + + inline const mstudioflexcontroller_t *pRightController( void ) const + { + return stereo ? (mstudioflexcontroller_t *)( (char *)this + szindex1 ): NULL; + } + inline const char *pszRightName( void ) const { return stereo ? pRightController()->pszName() : NULL; } + inline int rightIndex( const CStudioHdr &cStudioHdr ) const; + + inline const mstudioflexcontroller_t *pNWayValueController( void ) const + { + return remaptype == FLEXCONTROLLER_REMAP_NWAY ? (mstudioflexcontroller_t *)( (char *)this + szindex2 ) : NULL; + } + inline const char *pszNWayValueName( void ) const { return remaptype == FLEXCONTROLLER_REMAP_NWAY ? pNWayValueController()->pszName() : NULL; } + inline int nWayValueIndex( const CStudioHdr &cStudioHdr ) const; + + // Number of controllers this ui description contains, 1, 2 or 3 + inline int Count() const { return ( stereo ? 2 : 1 ) + ( remaptype == FLEXCONTROLLER_REMAP_NWAY ? 1 : 0 ); } + inline const mstudioflexcontroller_t *pController( int index ) const; + + unsigned char remaptype; // See the FlexControllerRemapType_t enum + bool stereo; // Is this a stereo control? + byte unused[2]; +}; + + +// this is the memory image of vertex anims (16-bit fixed point) +struct mstudiovertanim_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short index; + byte speed; // 255/max_length_in_flex + byte side; // 255/left_right + +protected: + // JasonM changing this type a lot, to prefer fixed point 16 bit... + union + { + short delta[3]; + float16 flDelta[3]; + }; + + union + { + short ndelta[3]; + float16 flNDelta[3]; + }; + +public: + inline void ConvertToFixed( float flVertAnimFixedPointScale ) + { + delta[0] = flDelta[0].GetFloat() / flVertAnimFixedPointScale; + delta[1] = flDelta[1].GetFloat() / flVertAnimFixedPointScale; + delta[2] = flDelta[2].GetFloat() / flVertAnimFixedPointScale; + ndelta[0] = flNDelta[0].GetFloat() / flVertAnimFixedPointScale; + ndelta[1] = flNDelta[1].GetFloat() / flVertAnimFixedPointScale; + ndelta[2] = flNDelta[2].GetFloat() / flVertAnimFixedPointScale; + } + + inline Vector GetDeltaFixed( float flVertAnimFixedPointScale ) + { + return Vector( delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale ); + } + inline Vector GetNDeltaFixed( float flVertAnimFixedPointScale ) + { + return Vector( ndelta[0] * flVertAnimFixedPointScale, ndelta[1] * flVertAnimFixedPointScale, ndelta[2] * flVertAnimFixedPointScale ); + } + inline void GetDeltaFixed4DAligned( Vector4DAligned *vFillIn, float flVertAnimFixedPointScale ) + { + vFillIn->Set( delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale, 0.0f ); + } + inline void GetNDeltaFixed4DAligned( Vector4DAligned *vFillIn, float flVertAnimFixedPointScale ) + { + vFillIn->Set( ndelta[0] * flVertAnimFixedPointScale, ndelta[1] * flVertAnimFixedPointScale, ndelta[2] * flVertAnimFixedPointScale, 0.0f ); + } + inline Vector GetDeltaFloat() + { + return Vector (flDelta[0].GetFloat(), flDelta[1].GetFloat(), flDelta[2].GetFloat()); + } + inline Vector GetNDeltaFloat() + { + return Vector (flNDelta[0].GetFloat(), flNDelta[1].GetFloat(), flNDelta[2].GetFloat()); + } + inline void SetDeltaFixed( const Vector& vInput, float flVertAnimFixedPointScale ) + { + delta[0] = vInput.x / flVertAnimFixedPointScale; + delta[1] = vInput.y / flVertAnimFixedPointScale; + delta[2] = vInput.z / flVertAnimFixedPointScale; + } + inline void SetNDeltaFixed( const Vector& vInputNormal, float flVertAnimFixedPointScale ) + { + ndelta[0] = vInputNormal.x / flVertAnimFixedPointScale; + ndelta[1] = vInputNormal.y / flVertAnimFixedPointScale; + ndelta[2] = vInputNormal.z / flVertAnimFixedPointScale; + } + + // Ick...can also force fp16 data into this structure for writing to file in legacy format... + inline void SetDeltaFloat( const Vector& vInput ) + { + flDelta[0].SetFloat( vInput.x ); + flDelta[1].SetFloat( vInput.y ); + flDelta[2].SetFloat( vInput.z ); + } + inline void SetNDeltaFloat( const Vector& vInputNormal ) + { + flNDelta[0].SetFloat( vInputNormal.x ); + flNDelta[1].SetFloat( vInputNormal.y ); + flNDelta[2].SetFloat( vInputNormal.z ); + } + + class CSortByIndex + { + public: + bool operator()(const mstudiovertanim_t &left, const mstudiovertanim_t & right)const + { + return left.index < right.index; + } + }; + friend class CSortByIndex; + + mstudiovertanim_t(){} +//private: +// No copy constructors allowed, but it's needed for std::sort() +// mstudiovertanim_t(const mstudiovertanim_t& vOther); +}; + + +// this is the memory image of vertex anims (16-bit fixed point) +struct mstudiovertanim_wrinkle_t : public mstudiovertanim_t +{ + DECLARE_BYTESWAP_DATADESC(); + + short wrinkledelta; + + inline void SetWrinkleFixed( float flWrinkle, float flVertAnimFixedPointScale ) + { + int nWrinkleDeltaInt = flWrinkle / flVertAnimFixedPointScale; + wrinkledelta = clamp( nWrinkleDeltaInt, -32767, 32767 ); + } + + inline Vector4D GetDeltaFixed( float flVertAnimFixedPointScale ) + { + return Vector4D( delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale, wrinkledelta * flVertAnimFixedPointScale ); + } + + inline void GetDeltaFixed4DAligned( Vector4DAligned *vFillIn, float flVertAnimFixedPointScale ) + { + vFillIn->Set( delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale, wrinkledelta * flVertAnimFixedPointScale ); + } + + inline float GetWrinkleDeltaFixed( float flVertAnimFixedPointScale ) + { + return wrinkledelta * flVertAnimFixedPointScale; + } +}; + + +enum StudioVertAnimType_t +{ + STUDIO_VERT_ANIM_NORMAL = 0, + STUDIO_VERT_ANIM_WRINKLE, +}; + +struct mstudioflex_t +{ + DECLARE_BYTESWAP_DATADESC(); + int flexdesc; // input value + + float target0; // zero + float target1; // one + float target2; // one + float target3; // zero + + int numverts; + int vertindex; + + inline mstudiovertanim_t *pVertanim( int i ) const { Assert( vertanimtype == STUDIO_VERT_ANIM_NORMAL ); return (mstudiovertanim_t *)(((byte *)this) + vertindex) + i; }; + inline mstudiovertanim_wrinkle_t *pVertanimWrinkle( int i ) const { Assert( vertanimtype == STUDIO_VERT_ANIM_WRINKLE ); return (mstudiovertanim_wrinkle_t *)(((byte *)this) + vertindex) + i; }; + + inline byte *pBaseVertanim( ) const { return ((byte *)this) + vertindex; }; + inline int VertAnimSizeBytes() const { return ( vertanimtype == STUDIO_VERT_ANIM_NORMAL ) ? sizeof(mstudiovertanim_t) : sizeof(mstudiovertanim_wrinkle_t); } + + int flexpair; // second flex desc + unsigned char vertanimtype; // See StudioVertAnimType_t + unsigned char unusedchar[3]; + int unused[6]; +}; + + +struct mstudioflexop_t +{ + DECLARE_BYTESWAP_DATADESC(); + int op; + union + { + int index; + float value; + } d; +}; + +struct mstudioflexrule_t +{ + DECLARE_BYTESWAP_DATADESC(); + int flex; + int numops; + int opindex; + inline mstudioflexop_t *iFlexOp( int i ) const { return (mstudioflexop_t *)(((byte *)this) + opindex) + i; }; +}; + +// 16 bytes +struct mstudioboneweight_t +{ + DECLARE_BYTESWAP_DATADESC(); + float weight[MAX_NUM_BONES_PER_VERT]; + char bone[MAX_NUM_BONES_PER_VERT]; + byte numbones; + +// byte material; +// short firstref; +// short lastref; +}; + +// NOTE: This is exactly 48 bytes +struct mstudiovertex_t +{ + DECLARE_BYTESWAP_DATADESC(); + mstudioboneweight_t m_BoneWeights; + Vector m_vecPosition; + Vector m_vecNormal; + Vector2D m_vecTexCoord; + + mstudiovertex_t() {} + +private: + // No copy constructors allowed + mstudiovertex_t(const mstudiovertex_t& vOther); +}; + +// skin info +struct mstudiotexture_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int flags; + int used; + int unused1; + mutable IMaterial *material; // fixme: this needs to go away . .isn't used by the engine, but is used by studiomdl + mutable void *clientmaterial; // gary, replace with client material pointer if used + + int unused[10]; +}; + +// eyeball +struct mstudioeyeball_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int bone; + Vector org; + float zoffset; + float radius; + Vector up; + Vector forward; + int texture; + + int unused1; + float iris_scale; + int unused2; + + int upperflexdesc[3]; // index of raiser, neutral, and lowerer flexdesc that is set by flex controllers + int lowerflexdesc[3]; + float uppertarget[3]; // angle (radians) of raised, neutral, and lowered lid positions + float lowertarget[3]; + + int upperlidflexdesc; // index of flex desc that actual lid flexes look to + int lowerlidflexdesc; + int unused[4]; // These were used before, so not guaranteed to be 0 + bool m_bNonFACS; // Never used before version 44 + char unused3[3]; + int unused4[7]; + + mstudioeyeball_t(){} +private: + // No copy constructors allowed + mstudioeyeball_t(const mstudioeyeball_t& vOther); +}; + + +// ikinfo +struct mstudioiklink_t +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + Vector kneeDir; // ideal bending direction (per link, if applicable) + Vector unused0; // unused + + mstudioiklink_t(){} +private: + // No copy constructors allowed + mstudioiklink_t(const mstudioiklink_t& vOther); +}; + +struct mstudioikchain_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int linktype; + int numlinks; + int linkindex; + inline mstudioiklink_t *pLink( int i ) const { return (mstudioiklink_t *)(((byte *)this) + linkindex) + i; }; + // FIXME: add unused entries +}; + + +struct mstudioiface_t +{ + unsigned short a, b, c; // Indices to vertices +}; + + +struct mstudiomodel_t; + +struct mstudio_modelvertexdata_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector *Position( int i ) const; + Vector *Normal( int i ) const; + Vector4D *TangentS( int i ) const; + Vector2D *Texcoord( int i ) const; + mstudioboneweight_t *BoneWeights( int i ) const; + mstudiovertex_t *Vertex( int i ) const; + bool HasTangentData( void ) const; + int GetGlobalVertexIndex( int i ) const; + int GetGlobalTangentIndex( int i ) const; + + // base of external vertex data stores + const void *pVertexData; + const void *pTangentData; +}; + +struct mstudio_meshvertexdata_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector *Position( int i ) const; + Vector *Normal( int i ) const; + Vector4D *TangentS( int i ) const; + Vector2D *Texcoord( int i ) const; + mstudioboneweight_t *BoneWeights( int i ) const; + mstudiovertex_t *Vertex( int i ) const; + bool HasTangentData( void ) const; + int GetModelVertexIndex( int i ) const; + int GetGlobalVertexIndex( int i ) const; + + // indirection to this mesh's model's vertex data + const mstudio_modelvertexdata_t *modelvertexdata; + + // used for fixup calcs when culling top level lods + // expected number of mesh verts at desired lod + int numLODVertexes[MAX_NUM_LODS]; +}; + +struct mstudiomesh_t +{ + DECLARE_BYTESWAP_DATADESC(); + int material; + + int modelindex; + mstudiomodel_t *pModel() const; + + int numvertices; // number of unique vertices/normals/texcoords + int vertexoffset; // vertex mstudiovertex_t + + // Access thin/fat mesh vertex data (only one will return a non-NULL result) + const mstudio_meshvertexdata_t *GetVertexData( void *pModelData = NULL ); + const thinModelVertices_t *GetThinVertexData( void *pModelData = NULL ); + + int numflexes; // vertex animation + int flexindex; + inline mstudioflex_t *pFlex( int i ) const { return (mstudioflex_t *)(((byte *)this) + flexindex) + i; }; + + // special codes for material operations + int materialtype; + int materialparam; + + // a unique ordinal for this mesh + int meshid; + + Vector center; + + mstudio_meshvertexdata_t vertexdata; + + int unused[8]; // remove as appropriate + + mstudiomesh_t(){} +private: + // No copy constructors allowed + mstudiomesh_t(const mstudiomesh_t& vOther); +}; + +// studio models +struct mstudiomodel_t +{ + DECLARE_BYTESWAP_DATADESC(); + inline const char * pszName( void ) const { return name; } + char name[64]; + + int type; + + float boundingradius; + + int nummeshes; + int meshindex; + inline mstudiomesh_t *pMesh( int i ) const { return (mstudiomesh_t *)(((byte *)this) + meshindex) + i; }; + + // cache purposes + int numvertices; // number of unique vertices/normals/texcoords + int vertexindex; // vertex Vector + int tangentsindex; // tangents Vector + + // These functions are defined in application-specific code: + const vertexFileHeader_t *CacheVertexData( void *pModelData ); + + // Access thin/fat mesh vertex data (only one will return a non-NULL result) + const mstudio_modelvertexdata_t *GetVertexData( void *pModelData = NULL ); + const thinModelVertices_t *GetThinVertexData( void *pModelData = NULL ); + + int numattachments; + int attachmentindex; + + int numeyeballs; + int eyeballindex; + inline mstudioeyeball_t *pEyeball( int i ) { return (mstudioeyeball_t *)(((byte *)this) + eyeballindex) + i; }; + + mstudio_modelvertexdata_t vertexdata; + + int unused[8]; // remove as appropriate +}; + +inline bool mstudio_modelvertexdata_t::HasTangentData( void ) const +{ + return (pTangentData != NULL); +} + +inline int mstudio_modelvertexdata_t::GetGlobalVertexIndex( int i ) const +{ + mstudiomodel_t *modelptr = (mstudiomodel_t *)((byte *)this - offsetof(mstudiomodel_t, vertexdata)); + Assert( ( modelptr->vertexindex % sizeof( mstudiovertex_t ) ) == 0 ); + return ( i + ( modelptr->vertexindex / sizeof( mstudiovertex_t ) ) ); +} + +inline int mstudio_modelvertexdata_t::GetGlobalTangentIndex( int i ) const +{ + mstudiomodel_t *modelptr = (mstudiomodel_t *)((byte *)this - offsetof(mstudiomodel_t, vertexdata)); + Assert( ( modelptr->tangentsindex % sizeof( Vector4D ) ) == 0 ); + return ( i + ( modelptr->tangentsindex / sizeof( Vector4D ) ) ); +} + +inline mstudiovertex_t *mstudio_modelvertexdata_t::Vertex( int i ) const +{ + return (mstudiovertex_t *)pVertexData + GetGlobalVertexIndex( i ); +} + +inline Vector *mstudio_modelvertexdata_t::Position( int i ) const +{ + return &Vertex(i)->m_vecPosition; +} + +inline Vector *mstudio_modelvertexdata_t::Normal( int i ) const +{ + return &Vertex(i)->m_vecNormal; +} + +inline Vector4D *mstudio_modelvertexdata_t::TangentS( int i ) const +{ + // NOTE: The tangents vector is 16-bytes in a separate array + // because it only exists on the high end, and if I leave it out + // of the mstudiovertex_t, the vertex is 64-bytes (good for low end) + return (Vector4D *)pTangentData + GetGlobalTangentIndex( i ); +} + +inline Vector2D *mstudio_modelvertexdata_t::Texcoord( int i ) const +{ + return &Vertex(i)->m_vecTexCoord; +} + +inline mstudioboneweight_t *mstudio_modelvertexdata_t::BoneWeights( int i ) const +{ + return &Vertex(i)->m_BoneWeights; +} + +inline mstudiomodel_t *mstudiomesh_t::pModel() const +{ + return (mstudiomodel_t *)(((byte *)this) + modelindex); +} + +inline bool mstudio_meshvertexdata_t::HasTangentData( void ) const +{ + return modelvertexdata->HasTangentData(); +} + +inline const mstudio_meshvertexdata_t *mstudiomesh_t::GetVertexData( void *pModelData ) +{ + // get this mesh's model's vertex data (allow for mstudiomodel_t::GetVertexData + // returning NULL if the data has been converted to 'thin' vertices) + this->pModel()->GetVertexData( pModelData ); + vertexdata.modelvertexdata = &( this->pModel()->vertexdata ); + + if ( !vertexdata.modelvertexdata->pVertexData ) + return NULL; + + return &vertexdata; +} + +inline const thinModelVertices_t * mstudiomesh_t::GetThinVertexData( void *pModelData ) +{ + // get this mesh's model's thin vertex data + return this->pModel()->GetThinVertexData( pModelData ); +} + +inline int mstudio_meshvertexdata_t::GetModelVertexIndex( int i ) const +{ + mstudiomesh_t *meshptr = (mstudiomesh_t *)((byte *)this - offsetof(mstudiomesh_t,vertexdata)); + return meshptr->vertexoffset + i; +} + +inline int mstudio_meshvertexdata_t::GetGlobalVertexIndex( int i ) const +{ + return modelvertexdata->GetGlobalVertexIndex( GetModelVertexIndex( i ) ); +} + +inline Vector *mstudio_meshvertexdata_t::Position( int i ) const +{ + return modelvertexdata->Position( GetModelVertexIndex( i ) ); +}; + +inline Vector *mstudio_meshvertexdata_t::Normal( int i ) const +{ + return modelvertexdata->Normal( GetModelVertexIndex( i ) ); +}; + +inline Vector4D *mstudio_meshvertexdata_t::TangentS( int i ) const +{ + return modelvertexdata->TangentS( GetModelVertexIndex( i ) ); +} + +inline Vector2D *mstudio_meshvertexdata_t::Texcoord( int i ) const +{ + return modelvertexdata->Texcoord( GetModelVertexIndex( i ) ); +}; + +inline mstudioboneweight_t *mstudio_meshvertexdata_t::BoneWeights( int i ) const +{ + return modelvertexdata->BoneWeights( GetModelVertexIndex( i ) ); +}; + +inline mstudiovertex_t *mstudio_meshvertexdata_t::Vertex( int i ) const +{ + return modelvertexdata->Vertex( GetModelVertexIndex( i ) ); +} + +// a group of studio model data +enum studiomeshgroupflags_t +{ + MESHGROUP_IS_FLEXED = 0x1, + MESHGROUP_IS_HWSKINNED = 0x2, + MESHGROUP_IS_DELTA_FLEXED = 0x4 +}; + + +// ---------------------------------------------------------- +// runtime stuff +// ---------------------------------------------------------- + +struct studiomeshgroup_t +{ + IMesh *m_pMesh; + int m_NumStrips; + int m_Flags; // see studiomeshgroupflags_t + OptimizedModel::StripHeader_t *m_pStripData; + unsigned short *m_pGroupIndexToMeshIndex; + int m_NumVertices; + int *m_pUniqueTris; // for performance measurements + unsigned short *m_pIndices; + bool m_MeshNeedsRestore; + short m_ColorMeshID; + IMorph *m_pMorph; + + inline unsigned short MeshIndex( int i ) const { return m_pGroupIndexToMeshIndex[m_pIndices[i]]; } +}; + + +// studio model data +struct studiomeshdata_t +{ + int m_NumGroup; + studiomeshgroup_t* m_pMeshGroup; +}; + +struct studioloddata_t +{ + // not needed - this is really the same as studiohwdata_t.m_NumStudioMeshes + //int m_NumMeshes; + studiomeshdata_t *m_pMeshData; // there are studiohwdata_t.m_NumStudioMeshes of these. + float m_SwitchPoint; + // one of these for each lod since we can switch to simpler materials on lower lods. + int numMaterials; + IMaterial **ppMaterials; /* will have studiohdr_t.numtextures elements allocated */ + // hack - this needs to go away. + int *pMaterialFlags; /* will have studiohdr_t.numtextures elements allocated */ + + // For decals on hardware morphing, we must actually do hardware skinning + // For this to work, we have to hope that the total # of bones used by + // hw flexed verts is < than the max possible for the dx level we're running under + int *m_pHWMorphDecalBoneRemap; + int m_nDecalBoneCount; +}; + +struct studiohwdata_t +{ + int m_RootLOD; // calced and clamped, nonzero for lod culling + int m_NumLODs; + studioloddata_t *m_pLODs; + int m_NumStudioMeshes; + + inline float LODMetric( float unitSphereSize ) const { return ( unitSphereSize != 0.0f ) ? (100.0f / unitSphereSize) : 0.0f; } + inline int GetLODForMetric( float lodMetric ) const + { + if ( !m_NumLODs ) + return 0; + + // shadow lod is specified on the last lod with a negative switch + // never consider shadow lod as viable candidate + int numLODs = (m_pLODs[m_NumLODs-1].m_SwitchPoint < 0.0f) ? m_NumLODs-1 : m_NumLODs; + + for ( int i = m_RootLOD; i < numLODs-1; i++ ) + { + if ( m_pLODs[i+1].m_SwitchPoint > lodMetric ) + return i; + } + + return numLODs-1; + } +}; + +// ---------------------------------------------------------- +// ---------------------------------------------------------- + +// body part index +struct mstudiobodyparts_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int nummodels; + int base; + int modelindex; // index into models array + inline mstudiomodel_t *pModel( int i ) const { return (mstudiomodel_t *)(((byte *)this) + modelindex) + i; }; +}; + + +struct mstudiomouth_t +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + Vector forward; + int flexdesc; + + mstudiomouth_t(){} +private: + // No copy constructors allowed + mstudiomouth_t(const mstudiomouth_t& vOther); +}; + +struct mstudiohitboxset_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + int numhitboxes; + int hitboxindex; + inline mstudiobbox_t *pHitbox( int i ) const { return (mstudiobbox_t *)(((byte *)this) + hitboxindex) + i; }; +}; + + +//----------------------------------------------------------------------------- +// Src bone transforms are transformations that will convert .dmx or .smd-based animations into .mdl-based animations +// NOTE: The operation you should apply is: pretransform * bone transform * posttransform +//----------------------------------------------------------------------------- +struct mstudiosrcbonetransform_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int sznameindex; + inline const char *pszName( void ) const { return ((char *)this) + sznameindex; } + matrix3x4_t pretransform; + matrix3x4_t posttransform; +}; + + +// ---------------------------------------------------------- +// Purpose: Load time results on model compositing +// ---------------------------------------------------------- + +class virtualgroup_t +{ +public: + virtualgroup_t( void ) { cache = NULL; }; + // tool dependant. In engine this is a model_t, in tool it's a direct pointer + void *cache; + // converts cache entry into a usable studiohdr_t * + const studiohdr_t *GetStudioHdr( void ) const; + + CUtlVector< int > boneMap; // maps global bone to local bone + CUtlVector< int > masterBone; // maps local bone to global bone + CUtlVector< int > masterSeq; // maps local sequence to master sequence + CUtlVector< int > masterAnim; // maps local animation to master animation + CUtlVector< int > masterAttachment; // maps local attachment to global + CUtlVector< int > masterPose; // maps local pose parameter to global + CUtlVector< int > masterNode; // maps local transition nodes to global +}; + +struct virtualsequence_t +{ +#ifdef _XBOX + short flags; + short activity; + short group; + short index; +#else + int flags; + int activity; + int group; + int index; +#endif +}; + +struct virtualgeneric_t +{ +#ifdef _XBOX + short group; + short index; +#else + int group; + int index; +#endif +}; + + +struct virtualmodel_t +{ + void AppendSequences( int group, const studiohdr_t *pStudioHdr ); + void AppendAnimations( int group, const studiohdr_t *pStudioHdr ); + void AppendAttachments( int ground, const studiohdr_t *pStudioHdr ); + void AppendPoseParameters( int group, const studiohdr_t *pStudioHdr ); + void AppendBonemap( int group, const studiohdr_t *pStudioHdr ); + void AppendNodes( int group, const studiohdr_t *pStudioHdr ); + void AppendTransitions( int group, const studiohdr_t *pStudioHdr ); + void AppendIKLocks( int group, const studiohdr_t *pStudioHdr ); + void AppendModels( int group, const studiohdr_t *pStudioHdr ); + void UpdateAutoplaySequences( const studiohdr_t *pStudioHdr ); + + virtualgroup_t *pAnimGroup( int animation ) { return &m_group[ m_anim[ animation ].group ]; } // Note: user must manage mutex for this + virtualgroup_t *pSeqGroup( int sequence ) + { + // Check for out of range access that is causing crashes on some servers. + // Perhaps caused by sourcemod bugs. Typical sequence in these cases is ~292 + // when the count is 234. Using unsigned math allows for free range + // checking against zero. + if ( (unsigned)sequence >= (unsigned)m_seq.Count() ) + { + Assert( 0 ); + return 0; + } + return &m_group[ m_seq[ sequence ].group ]; + } // Note: user must manage mutex for this + + CThreadFastMutex m_Lock; + + CUtlVector< virtualsequence_t > m_seq; + CUtlVector< virtualgeneric_t > m_anim; + CUtlVector< virtualgeneric_t > m_attachment; + CUtlVector< virtualgeneric_t > m_pose; + CUtlVector< virtualgroup_t > m_group; + CUtlVector< virtualgeneric_t > m_node; + CUtlVector< virtualgeneric_t > m_iklock; + CUtlVector< unsigned short > m_autoplaySequences; +}; + +// 'thin' vertex data, used to do model decals (see Studio_CreateThinVertexes()) +struct thinModelVertices_t +{ + void Init( int numBoneInfluences, Vector *positions, unsigned short *normals, float *boneWeights, char *boneIndices ) + { + Assert( positions != NULL ); + Assert( normals != NULL ); + Assert( ( numBoneInfluences >= 0 ) && ( numBoneInfluences <= 3 ) ); + Assert( numBoneInfluences > 0 ? !!boneIndices : !boneIndices ); + Assert( numBoneInfluences > 1 ? !!boneWeights : !boneWeights ); + m_numBoneInfluences = numBoneInfluences; + m_vecPositions = positions; + m_vecNormals = normals; + m_boneWeights = boneWeights; + m_boneIndices = boneIndices; + } + + void SetPosition( int vertIndex, const Vector & position ) + { + Assert( m_vecPositions ); + m_vecPositions[ vertIndex ] = position; + } + + void SetNormal( int vertIndex, const Vector & normal ) + { + Assert( m_vecNormals ); + unsigned int packedNormal; + PackNormal_UBYTE4( normal.x, normal.y, normal.z, &packedNormal ); + m_vecNormals[ vertIndex ] = (unsigned short)( 0x0000FFFF & packedNormal ); + } + + void SetBoneWeights( int vertIndex, const mstudioboneweight_t & boneWeights ) + { + Assert( ( m_numBoneInfluences >= 1 ) && ( m_numBoneInfluences <= 3 ) ); + Assert( ( boneWeights.numbones >= 1 ) && ( boneWeights.numbones <= m_numBoneInfluences ) ); + int numStoredWeights = vmax( 0, ( m_numBoneInfluences - 1 ) ); + float *pBaseWeight = m_boneWeights + vertIndex*numStoredWeights; + char *pBaseIndex = m_boneIndices + vertIndex*m_numBoneInfluences; + for ( int i = 0; i < m_numBoneInfluences; i++ ) + { + pBaseIndex[i] = boneWeights.bone[i]; + } + for ( int i = 0; i < numStoredWeights; i++ ) + { + pBaseWeight[i] = boneWeights.weight[i]; + } + } + + void GetMeshPosition( mstudiomesh_t *pMesh, int meshIndex, Vector *pPosition ) const + { + Assert( pMesh ); + GetPosition( pMesh->vertexdata.GetGlobalVertexIndex( meshIndex ), pPosition ); + } + + void GetMeshNormal( mstudiomesh_t *pMesh, int meshIndex, Vector *pNormal ) const + { + Assert( pMesh ); + GetNormal( pMesh->vertexdata.GetGlobalVertexIndex( meshIndex ), pNormal ); + } + + void GetMeshBoneWeights( mstudiomesh_t *pMesh, int meshIndex, mstudioboneweight_t *pBoneWeights ) const + { + Assert( pMesh ); + GetBoneWeights( pMesh->vertexdata.GetGlobalVertexIndex( meshIndex ), pBoneWeights ); + } + + void GetModelPosition( mstudiomodel_t *pModel, int modelIndex, Vector *pPosition ) const + { + Assert( pModel ); + GetPosition( pModel->vertexdata.GetGlobalVertexIndex( modelIndex ), pPosition ); + } + + void GetModelNormal( mstudiomodel_t *pModel, int modelIndex, Vector *pNormal ) const + { + Assert( pModel ); + GetNormal( pModel->vertexdata.GetGlobalVertexIndex( modelIndex ), pNormal ); + } + + void GetModelBoneWeights( mstudiomodel_t *pModel, int modelIndex, mstudioboneweight_t *pBoneWeights ) const + { + Assert( pModel ); + GetBoneWeights( pModel->vertexdata.GetGlobalVertexIndex( modelIndex ), pBoneWeights ); + } + +private: + void GetPosition( int vertIndex, Vector *pPosition ) const + { + Assert( pPosition ); + Assert( m_vecPositions ); + *pPosition = m_vecPositions[ vertIndex ]; + } + + void GetNormal( int vertIndex, Vector *pNormal ) const + { + Assert( pNormal ); + Assert( m_vecNormals ); + unsigned int packedNormal = 0x0000FFFF & m_vecNormals[ vertIndex ]; + UnpackNormal_UBYTE4( &packedNormal, pNormal->Base() ); + } + + void GetBoneWeights( int vertIndex, mstudioboneweight_t *pBoneWeights ) const + { + Assert( pBoneWeights ); + Assert( ( m_numBoneInfluences <= 1 ) || ( m_boneWeights != NULL ) ); + Assert( ( m_numBoneInfluences <= 0 ) || ( m_boneIndices != NULL ) ); + int numStoredWeights = vmax( 0, ( m_numBoneInfluences - 1 ) ); + float *pBaseWeight = m_boneWeights + vertIndex*numStoredWeights; + char *pBaseIndex = m_boneIndices + vertIndex*m_numBoneInfluences; + float sum = 0.0f; + for (int i = 0;i < MAX_NUM_BONES_PER_VERT;i++) + { + if ( i < ( m_numBoneInfluences - 1 ) ) + pBoneWeights->weight[i] = pBaseWeight[i]; + else + pBoneWeights->weight[i] = 1.0f - sum; + sum += pBoneWeights->weight[i]; + + pBoneWeights->bone[i] = ( i < m_numBoneInfluences ) ? pBaseIndex[i] : 0; + } + + // Treat 'zero weights' as '100% binding to bone zero': + pBoneWeights->numbones = m_numBoneInfluences ? m_numBoneInfluences : 1; + } + + int m_numBoneInfluences;// Number of bone influences per vertex, N + float *m_boneWeights; // This array stores (N-1) weights per vertex (unless N is zero) + char *m_boneIndices; // This array stores N indices per vertex + Vector *m_vecPositions; + unsigned short *m_vecNormals; // Normals are compressed into 16 bits apiece (see PackNormal_UBYTE4() ) +}; + +// ---------------------------------------------------------- +// Studio Model Vertex Data File +// Position independent flat data for cache manager +// ---------------------------------------------------------- + +// little-endian "IDSV" +#define MODEL_VERTEX_FILE_ID (('V'<<24)+('S'<<16)+('D'<<8)+'I') +#define MODEL_VERTEX_FILE_VERSION 4 +// this id (IDCV) is used once the vertex data has been compressed (see CMDLCache::CreateThinVertexes) +#define MODEL_VERTEX_FILE_THIN_ID (('V'<<24)+('C'<<16)+('D'<<8)+'I') + +struct vertexFileHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int id; // MODEL_VERTEX_FILE_ID + int version; // MODEL_VERTEX_FILE_VERSION + int checksum; // same as studiohdr_t, ensures sync + int numLODs; // num of valid lods + int numLODVertexes[MAX_NUM_LODS]; // num verts for desired root lod + int numFixups; // num of vertexFileFixup_t + int fixupTableStart; // offset from base to fixup table + int vertexDataStart; // offset from base to vertex block + int tangentDataStart; // offset from base to tangent block + +public: + + // Accessor to fat vertex data + const mstudiovertex_t *GetVertexData() const + { + if ( ( id == MODEL_VERTEX_FILE_ID ) && ( vertexDataStart != 0 ) ) + return ( mstudiovertex_t * ) ( vertexDataStart + (byte *)this ); + else + return NULL; + } + // Accessor to (fat) tangent vertex data (tangents aren't stored in compressed data) + const Vector4D *GetTangentData() const + { + if ( ( id == MODEL_VERTEX_FILE_ID ) && ( tangentDataStart != 0 ) ) + return ( Vector4D * ) ( tangentDataStart + (byte *)this ); + else + return NULL; + } + // Accessor to thin vertex data + const thinModelVertices_t *GetThinVertexData() const + { + if ( ( id == MODEL_VERTEX_FILE_THIN_ID ) && ( vertexDataStart != 0 ) ) + return ( thinModelVertices_t * ) ( vertexDataStart + (byte *)this ); + else + return NULL; + } +}; + +// model vertex data accessor (defined here so vertexFileHeader_t can be used) +inline const mstudio_modelvertexdata_t * mstudiomodel_t::GetVertexData( void *pModelData ) +{ + const vertexFileHeader_t * pVertexHdr = CacheVertexData( pModelData ); + if ( !pVertexHdr ) + { + vertexdata.pVertexData = NULL; + vertexdata.pTangentData = NULL; + return NULL; + } + + vertexdata.pVertexData = pVertexHdr->GetVertexData(); + vertexdata.pTangentData = pVertexHdr->GetTangentData(); + + if ( !vertexdata.pVertexData ) + return NULL; + + return &vertexdata; +} + +// model thin vertex data accessor (defined here so vertexFileHeader_t can be used) +inline const thinModelVertices_t * mstudiomodel_t::GetThinVertexData( void *pModelData ) +{ + const vertexFileHeader_t * pVertexHdr = CacheVertexData( pModelData ); + if ( !pVertexHdr ) + return NULL; + + return pVertexHdr->GetThinVertexData(); +} + +// apply sequentially to lod sorted vertex and tangent pools to re-establish mesh order +struct vertexFileFixup_t +{ + DECLARE_BYTESWAP_DATADESC(); + int lod; // used to skip culled root lod + int sourceVertexID; // absolute index from start of vertex/tangent blocks + int numVertexes; +}; + +// This flag is set if no hitbox information was specified +#define STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX 0x00000001 + +// NOTE: This flag is set at loadtime, not mdl build time so that we don't have to rebuild +// models when we change materials. +#define STUDIOHDR_FLAGS_USES_ENV_CUBEMAP 0x00000002 + +// Use this when there are translucent parts to the model but we're not going to sort it +#define STUDIOHDR_FLAGS_FORCE_OPAQUE 0x00000004 + +// Use this when we want to render the opaque parts during the opaque pass +// and the translucent parts during the translucent pass +#define STUDIOHDR_FLAGS_TRANSLUCENT_TWOPASS 0x00000008 + +// This is set any time the .qc files has $staticprop in it +// Means there's no bones and no transforms +#define STUDIOHDR_FLAGS_STATIC_PROP 0x00000010 + +// NOTE: This flag is set at loadtime, not mdl build time so that we don't have to rebuild +// models when we change materials. +#define STUDIOHDR_FLAGS_USES_FB_TEXTURE 0x00000020 + +// This flag is set by studiomdl.exe if a separate "$shadowlod" entry was present +// for the .mdl (the shadow lod is the last entry in the lod list if present) +#define STUDIOHDR_FLAGS_HASSHADOWLOD 0x00000040 + +// NOTE: This flag is set at loadtime, not mdl build time so that we don't have to rebuild +// models when we change materials. +#define STUDIOHDR_FLAGS_USES_BUMPMAPPING 0x00000080 + +// NOTE: This flag is set when we should use the actual materials on the shadow LOD +// instead of overriding them with the default one (necessary for translucent shadows) +#define STUDIOHDR_FLAGS_USE_SHADOWLOD_MATERIALS 0x00000100 + +// NOTE: This flag is set when we should use the actual materials on the shadow LOD +// instead of overriding them with the default one (necessary for translucent shadows) +#define STUDIOHDR_FLAGS_OBSOLETE 0x00000200 + +#define STUDIOHDR_FLAGS_UNUSED 0x00000400 + +// NOTE: This flag is set at mdl build time +#define STUDIOHDR_FLAGS_NO_FORCED_FADE 0x00000800 + +// NOTE: The npc will lengthen the viseme check to always include two phonemes +#define STUDIOHDR_FLAGS_FORCE_PHONEME_CROSSFADE 0x00001000 + +// This flag is set when the .qc has $constantdirectionallight in it +// If set, we use constantdirectionallightdot to calculate light intensity +// rather than the normal directional dot product +// only valid if STUDIOHDR_FLAGS_STATIC_PROP is also set +#define STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT 0x00002000 + +// Flag to mark delta flexes as already converted from disk format to memory format +#define STUDIOHDR_FLAGS_FLEXES_CONVERTED 0x00004000 + +// Indicates the studiomdl was built in preview mode +#define STUDIOHDR_FLAGS_BUILT_IN_PREVIEW_MODE 0x00008000 + +// Ambient boost (runtime flag) +#define STUDIOHDR_FLAGS_AMBIENT_BOOST 0x00010000 + +// Don't cast shadows from this model (useful on first-person models) +#define STUDIOHDR_FLAGS_DO_NOT_CAST_SHADOWS 0x00020000 + +// alpha textures should cast shadows in vrad on this model (ONLY prop_static!) +#define STUDIOHDR_FLAGS_CAST_TEXTURE_SHADOWS 0x00040000 + + +// flagged on load to indicate no animation events on this model +#define STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE 0x00200000 + +// NOTE! Next time we up the .mdl file format, remove studiohdr2_t +// and insert all fields in this structure into studiohdr_t. +struct studiohdr2_t +{ + // NOTE: For forward compat, make sure any methods in this struct + // are also available in studiohdr_t so no leaf code ever directly references + // a studiohdr2_t structure + DECLARE_BYTESWAP_DATADESC(); + int numsrcbonetransform; + int srcbonetransformindex; + + int illumpositionattachmentindex; + inline int IllumPositionAttachmentIndex() const { return illumpositionattachmentindex; } + + float flMaxEyeDeflection; + inline float MaxEyeDeflection() const { return flMaxEyeDeflection != 0.0f ? flMaxEyeDeflection : 0.866f; } // default to cos(30) if not set + + int linearboneindex; + inline mstudiolinearbone_t *pLinearBones() const { return (linearboneindex) ? (mstudiolinearbone_t *)(((byte *)this) + linearboneindex) : NULL; } + + int sznameindex; + inline char *pszName() { return (sznameindex) ? (char *)(((byte *)this) + sznameindex ) : NULL; } + + int m_nBoneFlexDriverCount; + int m_nBoneFlexDriverIndex; + inline mstudioboneflexdriver_t *pBoneFlexDriver( int i ) const { Assert( i >= 0 && i < m_nBoneFlexDriverCount ); return (mstudioboneflexdriver_t *)(((byte *)this) + m_nBoneFlexDriverIndex) + i; } + + int reserved[56]; +}; + +struct studiohdr_t +{ + DECLARE_BYTESWAP_DATADESC(); + int id; + int version; + + int checksum; // this has to be the same in the phy and vtx files to load! + + inline const char * pszName( void ) const { if (studiohdr2index && pStudioHdr2()->pszName()) return pStudioHdr2()->pszName(); else return name; } + char name[64]; + int length; + + + Vector eyeposition; // ideal eye position + + Vector illumposition; // illumination center + + Vector hull_min; // ideal movement hull size + Vector hull_max; + + Vector view_bbmin; // clipping bounding box + Vector view_bbmax; + + int flags; + + int numbones; // bones + int boneindex; + inline mstudiobone_t *pBone( int i ) const { Assert( i >= 0 && i < numbones); return (mstudiobone_t *)(((byte *)this) + boneindex) + i; }; + int RemapSeqBone( int iSequence, int iLocalBone ) const; // maps local sequence bone to global bone + int RemapAnimBone( int iAnim, int iLocalBone ) const; // maps local animations bone to global bone + + int numbonecontrollers; // bone controllers + int bonecontrollerindex; + inline mstudiobonecontroller_t *pBonecontroller( int i ) const { Assert( i >= 0 && i < numbonecontrollers); return (mstudiobonecontroller_t *)(((byte *)this) + bonecontrollerindex) + i; }; + + int numhitboxsets; + int hitboxsetindex; + + // Look up hitbox set by index + mstudiohitboxset_t *pHitboxSet( int i ) const + { + Assert( i >= 0 && i < numhitboxsets); + return (mstudiohitboxset_t *)(((byte *)this) + hitboxsetindex ) + i; + }; + + // Calls through to hitbox to determine size of specified set + inline mstudiobbox_t *pHitbox( int i, int set ) const + { + mstudiohitboxset_t const *s = pHitboxSet( set ); + if ( !s ) + return NULL; + + return s->pHitbox( i ); + }; + + // Calls through to set to get hitbox count for set + inline int iHitboxCount( int set ) const + { + mstudiohitboxset_t const *s = pHitboxSet( set ); + if ( !s ) + return 0; + + return s->numhitboxes; + }; + + // file local animations? and sequences +//private: + int numlocalanim; // animations/poses + int localanimindex; // animation descriptions + inline mstudioanimdesc_t *pLocalAnimdesc( int i ) const { if (i < 0 || i >= numlocalanim) i = 0; return (mstudioanimdesc_t *)(((byte *)this) + localanimindex) + i; }; + + int numlocalseq; // sequences + int localseqindex; + inline mstudioseqdesc_t *pLocalSeqdesc( int i ) const { if (i < 0 || i >= numlocalseq) i = 0; return (mstudioseqdesc_t *)(((byte *)this) + localseqindex) + i; }; + +//public: + bool SequencesAvailable() const; + int GetNumSeq() const; + mstudioanimdesc_t &pAnimdesc( int i ) const; + mstudioseqdesc_t &pSeqdesc( int i ) const; + int iRelativeAnim( int baseseq, int relanim ) const; // maps seq local anim reference to global anim index + int iRelativeSeq( int baseseq, int relseq ) const; // maps seq local seq reference to global seq index + +//private: + mutable int activitylistversion; // initialization flag - have the sequences been indexed? + mutable int eventsindexed; +//public: + int GetSequenceActivity( int iSequence ); + void SetSequenceActivity( int iSequence, int iActivity ); + int GetActivityListVersion( void ); + void SetActivityListVersion( int version ) const; + int GetEventListVersion( void ); + void SetEventListVersion( int version ); + + // raw textures + int numtextures; + int textureindex; + inline mstudiotexture_t *pTexture( int i ) const { Assert( i >= 0 && i < numtextures ); return (mstudiotexture_t *)(((byte *)this) + textureindex) + i; }; + + + // raw textures search paths + int numcdtextures; + int cdtextureindex; + inline char *pCdtexture( int i ) const { return (((char *)this) + *((int *)(((byte *)this) + cdtextureindex) + i)); }; + + // replaceable textures tables + int numskinref; + int numskinfamilies; + int skinindex; + inline short *pSkinref( int i ) const { return (short *)(((byte *)this) + skinindex) + i; }; + + int numbodyparts; + int bodypartindex; + inline mstudiobodyparts_t *pBodypart( int i ) const { return (mstudiobodyparts_t *)(((byte *)this) + bodypartindex) + i; }; + + // queryable attachable points +//private: + int numlocalattachments; + int localattachmentindex; + inline mstudioattachment_t *pLocalAttachment( int i ) const { Assert( i >= 0 && i < numlocalattachments); return (mstudioattachment_t *)(((byte *)this) + localattachmentindex) + i; }; +//public: + int GetNumAttachments( void ) const; + const mstudioattachment_t &pAttachment( int i ) const; + int GetAttachmentBone( int i ); + // used on my tools in hlmv, not persistant + void SetAttachmentBone( int iAttachment, int iBone ); + + // animation node to animation node transition graph +//private: + int numlocalnodes; + int localnodeindex; + int localnodenameindex; + inline char *pszLocalNodeName( int iNode ) const { Assert( iNode >= 0 && iNode < numlocalnodes); return (((char *)this) + *((int *)(((byte *)this) + localnodenameindex) + iNode)); } + inline byte *pLocalTransition( int i ) const { Assert( i >= 0 && i < (numlocalnodes * numlocalnodes)); return (byte *)(((byte *)this) + localnodeindex) + i; }; + +//public: + int EntryNode( int iSequence ); + int ExitNode( int iSequence ); + char *pszNodeName( int iNode ); + int GetTransition( int iFrom, int iTo ) const; + + int numflexdesc; + int flexdescindex; + inline mstudioflexdesc_t *pFlexdesc( int i ) const { Assert( i >= 0 && i < numflexdesc); return (mstudioflexdesc_t *)(((byte *)this) + flexdescindex) + i; }; + + int numflexcontrollers; + int flexcontrollerindex; + inline mstudioflexcontroller_t *pFlexcontroller( LocalFlexController_t i ) const { Assert( numflexcontrollers == 0 || ( i >= 0 && i < numflexcontrollers ) ); return (mstudioflexcontroller_t *)(((byte *)this) + flexcontrollerindex) + i; }; + + int numflexrules; + int flexruleindex; + inline mstudioflexrule_t *pFlexRule( int i ) const { Assert( i >= 0 && i < numflexrules); return (mstudioflexrule_t *)(((byte *)this) + flexruleindex) + i; }; + + int numikchains; + int ikchainindex; + inline mstudioikchain_t *pIKChain( int i ) const { Assert( i >= 0 && i < numikchains); return (mstudioikchain_t *)(((byte *)this) + ikchainindex) + i; }; + + int nummouths; + int mouthindex; + inline mstudiomouth_t *pMouth( int i ) const { Assert( i >= 0 && i < nummouths); return (mstudiomouth_t *)(((byte *)this) + mouthindex) + i; }; + +//private: + int numlocalposeparameters; + int localposeparamindex; + inline mstudioposeparamdesc_t *pLocalPoseParameter( int i ) const { Assert( i >= 0 && i < numlocalposeparameters); return (mstudioposeparamdesc_t *)(((byte *)this) + localposeparamindex) + i; }; +//public: + int GetNumPoseParameters( void ) const; + const mstudioposeparamdesc_t &pPoseParameter( int i ); + int GetSharedPoseParameter( int iSequence, int iLocalPose ) const; + + int surfacepropindex; + inline const char *pszSurfaceProp( void ) const { return ((char *)this) + surfacepropindex; } + + // Key values + int keyvalueindex; + int keyvaluesize; + inline const char *KeyValueText( void ) const { return keyvaluesize != 0 ? ((char *)this) + keyvalueindex : NULL; } + + int numlocalikautoplaylocks; + int localikautoplaylockindex; + inline mstudioiklock_t *pLocalIKAutoplayLock( int i ) const { Assert( i >= 0 && i < numlocalikautoplaylocks); return (mstudioiklock_t *)(((byte *)this) + localikautoplaylockindex) + i; }; + + int GetNumIKAutoplayLocks( void ) const; + const mstudioiklock_t &pIKAutoplayLock( int i ); + int CountAutoplaySequences() const; + int CopyAutoplaySequences( unsigned short *pOut, int outCount ) const; + int GetAutoplayList( unsigned short **pOut ) const; + + // The collision model mass that jay wanted + float mass; + int contents; + + // external animations, models, etc. + int numincludemodels; + int includemodelindex; + inline mstudiomodelgroup_t *pModelGroup( int i ) const { Assert( i >= 0 && i < numincludemodels); return (mstudiomodelgroup_t *)(((byte *)this) + includemodelindex) + i; }; + // implementation specific call to get a named model + const studiohdr_t *FindModel( void **cache, char const *modelname ) const; + + // implementation specific back pointer to virtual data + mutable void *virtualModel; + virtualmodel_t *GetVirtualModel( void ) const; + + // for demand loaded animation blocks + int szanimblocknameindex; + inline const char *pszAnimBlockName( void ) const { return ((char *)this) + szanimblocknameindex; } + int numanimblocks; + int animblockindex; + inline mstudioanimblock_t *pAnimBlock( int i ) const { Assert( i > 0 && i < numanimblocks); return (mstudioanimblock_t *)(((byte *)this) + animblockindex) + i; }; + mutable void *animblockModel; + byte * GetAnimBlock( int i ) const; + + int bonetablebynameindex; + inline const byte *GetBoneTableSortedByName() const { return (byte *)this + bonetablebynameindex; } + + // used by tools only that don't cache, but persist mdl's peer data + // engine uses virtualModel to back link to cache pointers + void *pVertexBase; + void *pIndexBase; + + // if STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT is set, + // this value is used to calculate directional components of lighting + // on static props + byte constdirectionallightdot; + + // set during load of mdl data to track *desired* lod configuration (not actual) + // the *actual* clamped root lod is found in studiohwdata + // this is stored here as a global store to ensure the staged loading matches the rendering + byte rootLOD; + + // set in the mdl data to specify that lod configuration should only allow first numAllowRootLODs + // to be set as root LOD: + // numAllowedRootLODs = 0 means no restriction, any lod can be set as root lod. + // numAllowedRootLODs = N means that lod0 - lod(N-1) can be set as root lod, but not lodN or lower. + byte numAllowedRootLODs; + + byte unused[1]; + + int unused4; // zero out if version < 47 + + int numflexcontrollerui; + int flexcontrolleruiindex; + mstudioflexcontrollerui_t *pFlexControllerUI( int i ) const { Assert( i >= 0 && i < numflexcontrollerui); return (mstudioflexcontrollerui_t *)(((byte *)this) + flexcontrolleruiindex) + i; } + + float flVertAnimFixedPointScale; + inline float VertAnimFixedPointScale() const { return ( flags & STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE ) ? flVertAnimFixedPointScale : 1.0f / 4096.0f; } + + int unused3[1]; + + // FIXME: Remove when we up the model version. Move all fields of studiohdr2_t into studiohdr_t. + int studiohdr2index; + studiohdr2_t* pStudioHdr2() const { return (studiohdr2_t *)( ( (byte *)this ) + studiohdr2index ); } + + // Src bone transforms are transformations that will convert .dmx or .smd-based animations into .mdl-based animations + int NumSrcBoneTransforms() const { return studiohdr2index ? pStudioHdr2()->numsrcbonetransform : 0; } + const mstudiosrcbonetransform_t* SrcBoneTransform( int i ) const { Assert( i >= 0 && i < NumSrcBoneTransforms()); return (mstudiosrcbonetransform_t *)(((byte *)this) + pStudioHdr2()->srcbonetransformindex) + i; } + + inline int IllumPositionAttachmentIndex() const { return studiohdr2index ? pStudioHdr2()->IllumPositionAttachmentIndex() : 0; } + + inline float MaxEyeDeflection() const { return studiohdr2index ? pStudioHdr2()->MaxEyeDeflection() : 0.866f; } // default to cos(30) if not set + + inline mstudiolinearbone_t *pLinearBones() const { return studiohdr2index ? pStudioHdr2()->pLinearBones() : NULL; } + + inline int BoneFlexDriverCount() const { return studiohdr2index ? pStudioHdr2()->m_nBoneFlexDriverCount : 0; } + inline const mstudioboneflexdriver_t* BoneFlexDriver( int i ) const { Assert( i >= 0 && i < BoneFlexDriverCount() ); return studiohdr2index ? pStudioHdr2()->pBoneFlexDriver( i ) : NULL; } + + // NOTE: No room to add stuff? Up the .mdl file format version + // [and move all fields in studiohdr2_t into studiohdr_t and kill studiohdr2_t], + // or add your stuff to studiohdr2_t. See NumSrcBoneTransforms/SrcBoneTransform for the pattern to use. + int unused2[1]; + + studiohdr_t() {} + +private: + // No copy constructors allowed + studiohdr_t(const studiohdr_t& vOther); + + friend struct virtualmodel_t; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +class IDataCache; +class IMDLCache; + +class CStudioHdr +{ +public: + CStudioHdr( void ); + CStudioHdr( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache = NULL ); + ~CStudioHdr() { Term(); } + + void Init( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache = NULL ); + void Term(); + +public: + inline bool IsVirtual( void ) { return (m_pVModel != NULL); }; + inline bool IsValid( void ) { return (m_pStudioHdr != NULL); }; + inline bool IsReadyForAccess( void ) const { return (m_pStudioHdr != NULL); }; + inline virtualmodel_t *GetVirtualModel( void ) const { return m_pVModel; }; + inline const studiohdr_t *GetRenderHdr( void ) const { return m_pStudioHdr; }; + const studiohdr_t *pSeqStudioHdr( int sequence ); + const studiohdr_t *pAnimStudioHdr( int animation ); + +private: + mutable const studiohdr_t *m_pStudioHdr; + mutable virtualmodel_t *m_pVModel; + + const virtualmodel_t * ResetVModel( const virtualmodel_t *pVModel ) const; + const studiohdr_t *GroupStudioHdr( int group ); + mutable CUtlVector< const studiohdr_t * > m_pStudioHdrCache; + + mutable int m_nFrameUnlockCounter; + int * m_pFrameUnlockCounter; + CThreadFastMutex m_FrameUnlockCounterMutex; + +public: + inline int numbones( void ) const { return m_pStudioHdr->numbones; }; + inline mstudiobone_t *pBone( int i ) const { return m_pStudioHdr->pBone( i ); }; + int RemapAnimBone( int iAnim, int iLocalBone ) const; // maps local animations bone to global bone + int RemapSeqBone( int iSequence, int iLocalBone ) const; // maps local sequence bone to global bone + + bool SequencesAvailable() const; + int GetNumSeq( void ) const; + mstudioanimdesc_t &pAnimdesc( int i ); + mstudioseqdesc_t &pSeqdesc( int iSequence ); + int iRelativeAnim( int baseseq, int relanim ) const; // maps seq local anim reference to global anim index + int iRelativeSeq( int baseseq, int relseq ) const; // maps seq local seq reference to global seq index + + int GetSequenceActivity( int iSequence ); + void SetSequenceActivity( int iSequence, int iActivity ); + int GetActivityListVersion( void ); + void SetActivityListVersion( int version ); + int GetEventListVersion( void ); + void SetEventListVersion( int version ); + + int GetNumAttachments( void ) const; + const mstudioattachment_t &pAttachment( int i ); + int GetAttachmentBone( int i ); + // used on my tools in hlmv, not persistant + void SetAttachmentBone( int iAttachment, int iBone ); + + int EntryNode( int iSequence ); + int ExitNode( int iSequence ); + char *pszNodeName( int iNode ); + // FIXME: where should this one be? + int GetTransition( int iFrom, int iTo ) const; + + int GetNumPoseParameters( void ) const; + const mstudioposeparamdesc_t &pPoseParameter( int i ); + int GetSharedPoseParameter( int iSequence, int iLocalPose ) const; + + int GetNumIKAutoplayLocks( void ) const; + const mstudioiklock_t &pIKAutoplayLock( int i ); + + inline int CountAutoplaySequences() const { return m_pStudioHdr->CountAutoplaySequences(); }; + inline int CopyAutoplaySequences( unsigned short *pOut, int outCount ) const { return m_pStudioHdr->CopyAutoplaySequences( pOut, outCount ); }; + inline int GetAutoplayList( unsigned short **pOut ) const { return m_pStudioHdr->GetAutoplayList( pOut ); }; + + inline int GetNumBoneControllers( void ) const { return m_pStudioHdr->numbonecontrollers; }; + inline mstudiobonecontroller_t *pBonecontroller( int i ) const { return m_pStudioHdr->pBonecontroller( i ); }; + + inline int numikchains() const { return m_pStudioHdr->numikchains; }; + inline int GetNumIKChains( void ) const { return m_pStudioHdr->numikchains; }; + inline mstudioikchain_t *pIKChain( int i ) const { return m_pStudioHdr->pIKChain( i ); }; + + inline int numflexrules() const { return m_pStudioHdr->numflexrules; }; + inline mstudioflexrule_t *pFlexRule( int i ) const { return m_pStudioHdr->pFlexRule( i ); }; + + inline int numflexdesc() const{ return m_pStudioHdr->numflexdesc; }; + inline mstudioflexdesc_t *pFlexdesc( int i ) const { return m_pStudioHdr->pFlexdesc( i ); }; + + inline LocalFlexController_t numflexcontrollers() const{ return (LocalFlexController_t)m_pStudioHdr->numflexcontrollers; }; + inline mstudioflexcontroller_t *pFlexcontroller( LocalFlexController_t i ) const { return m_pStudioHdr->pFlexcontroller( i ); }; + + inline int numflexcontrollerui() const{ return m_pStudioHdr->numflexcontrollerui; }; + inline mstudioflexcontrollerui_t *pFlexcontrollerUI( int i ) const { return m_pStudioHdr->pFlexControllerUI( i ); }; + + //inline const char *name() const { return m_pStudioHdr->name; }; // deprecated -- remove after full xbox merge + inline const char *pszName() const { return m_pStudioHdr->pszName(); }; + + inline int numbonecontrollers() const { return m_pStudioHdr->numbonecontrollers; }; + + inline int numhitboxsets() const { return m_pStudioHdr->numhitboxsets; }; + inline mstudiohitboxset_t *pHitboxSet( int i ) const { return m_pStudioHdr->pHitboxSet( i ); }; + + inline mstudiobbox_t *pHitbox( int i, int set ) const { return m_pStudioHdr->pHitbox( i, set ); }; + inline int iHitboxCount( int set ) const { return m_pStudioHdr->iHitboxCount( set ); }; + + inline int numbodyparts() const { return m_pStudioHdr->numbodyparts; }; + inline mstudiobodyparts_t *pBodypart( int i ) const { return m_pStudioHdr->pBodypart( i ); }; + + inline int numskinfamilies() const { return m_pStudioHdr->numskinfamilies; } + + inline Vector eyeposition() const { return m_pStudioHdr->eyeposition; }; + + inline int flags() const { return m_pStudioHdr->flags; }; + + inline const char *pszSurfaceProp( void ) const { return m_pStudioHdr->pszSurfaceProp(); }; + + inline float mass() const { return m_pStudioHdr->mass; }; + inline int contents() const { return m_pStudioHdr->contents; } + + inline const byte *GetBoneTableSortedByName() const { return m_pStudioHdr->GetBoneTableSortedByName(); }; + + inline Vector illumposition() const { return m_pStudioHdr->illumposition; }; + + inline Vector hull_min() const { return m_pStudioHdr->hull_min; }; // ideal movement hull size + inline Vector hull_max() const { return m_pStudioHdr->hull_max; }; + + inline Vector view_bbmin() const { return m_pStudioHdr->view_bbmin; }; // clipping bounding box + inline Vector view_bbmax() const { return m_pStudioHdr->view_bbmax; }; + + inline int numtextures() const { return m_pStudioHdr->numtextures; }; + + inline int IllumPositionAttachmentIndex() const { return m_pStudioHdr->IllumPositionAttachmentIndex(); } + + inline float MaxEyeDeflection() const { return m_pStudioHdr->MaxEyeDeflection(); } + + inline mstudiolinearbone_t *pLinearBones() const { return m_pStudioHdr->pLinearBones(); } + + inline int BoneFlexDriverCount() const { return m_pStudioHdr->BoneFlexDriverCount(); } + inline const mstudioboneflexdriver_t *BoneFlexDriver( int i ) const { return m_pStudioHdr->BoneFlexDriver( i ); } + + inline float VertAnimFixedPointScale() const { return m_pStudioHdr->VertAnimFixedPointScale(); } + +public: + int IsSequenceLooping( int iSequence ); + float GetSequenceCycleRate( int iSequence ); + + void RunFlexRules( const float *src, float *dest ); + + +public: + inline int boneFlags( int iBone ) const { return m_boneFlags[ iBone ]; } + inline int boneParent( int iBone ) const { return m_boneParent[ iBone ]; } + +private: + CUtlVector< int > m_boneFlags; + CUtlVector< int > m_boneParent; + +public: + + // This class maps an activity to sequences allowed for that activity, accelerating the resolution + // of SelectWeightedSequence(), especially on PowerPC. Iterating through every sequence + // attached to a model turned out to be a very destructive cache access pattern on 360. + // + // I've encapsulated this behavior inside a nested class for organizational reasons; there is + // no particular programmatic or efficiency benefit to it. It just makes clearer what particular + // code in the otherwise very complicated StudioHdr class has to do with this particular + // optimization, and it lets you collapse the whole definition down to a single line in Visual + // Studio. + class CActivityToSequenceMapping /* final */ + { + public: + // A tuple of a sequence and its corresponding weight. Lists of these correspond to activities. + struct SequenceTuple + { + short seqnum; + short weight; // the absolute value of the weight from the sequence header + CUtlSymbol *pActivityModifiers; // list of activity modifier symbols + int iNumActivityModifiers; + }; + + // The type of the hash's stored data, a composite of both key and value + // (because that's how CUtlHash works): + // key: an int, the activity # + // values: an index into the m_pSequenceTuples array, a count of the + // total sequences present for an activity, and the sum of their + // weights. + // Note this struct is 128-bits wide, exactly coincident to a PowerPC + // cache line and VMX register. Please consider very carefully the + // performance implications before adding any additional fields to this. + // You could probably do away with totalWeight if you really had to. + struct HashValueType + { + // KEY (hashed) + int activityIdx; + + // VALUE (not hashed) + int startingIdx; + int count; + int totalWeight; + + HashValueType(int _actIdx, int _stIdx, int _ct, int _tW) : + activityIdx(_actIdx), startingIdx(_stIdx), count(_ct), totalWeight(_tW) {} + + // default constructor (ought not to be actually used) + HashValueType() : activityIdx(-1), startingIdx(-1), count(-1), totalWeight(-1) + { AssertMsg(false, "Don't use default HashValueType()!"); } + + + class HashFuncs + { + public: + // dummy constructor (gndn) + HashFuncs( int ) {} + + // COMPARE + // compare two entries for uniqueness. We should never have two different + // entries for the same activity, so we only compare the activity index; + // this allows us to use the utlhash as a dict by constructing dummy entries + // as hash lookup keys. + bool operator()( const HashValueType &lhs, const HashValueType &rhs ) const + { + return lhs.activityIdx == rhs.activityIdx; + } + + // HASH + // We only hash on the activity index; everything else is data. + unsigned int operator()( const HashValueType &item ) const + { + return HashInt( item.activityIdx ); + } + }; + }; + + typedef CUtlHash ActivityToValueIdxHash; + + // These must be here because IFM does not compile/link studio.cpp (?!?) + + // ctor + CActivityToSequenceMapping( void ) + : m_pSequenceTuples(NULL), m_iSequenceTuplesCount(0), +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + m_bIsInitialized(false), +#endif + m_ActToSeqHash(8,0,0), m_expectedPStudioHdr(NULL), m_expectedVModel(NULL) + {}; + + // dtor -- not virtual because this class has no inheritors + ~CActivityToSequenceMapping() + { + if ( m_pSequenceTuples != NULL ) + { + if ( m_pSequenceTuples->pActivityModifiers != NULL ) + { + delete[] m_pSequenceTuples->pActivityModifiers; + } + delete[] m_pSequenceTuples; + } + } + + /// Get the list of sequences for an activity. Returns the pointer to the + /// first sequence tuple. Output parameters are a count of sequences present, + /// and the total weight of all the sequences. (it would be more LHS-friendly + /// to return these on registers, if only C++ offered more than one return + /// value....) + const SequenceTuple *GetSequences( int forActivity, int *outSequenceCount, int *outTotalWeight ); + + /// The number of sequences available for an activity. + int NumSequencesForActivity( int forActivity ); + +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + inline bool IsInitialized( void ) { return m_bIsInitialized; } +#endif + + private: + + /// Allocate my internal array. (It is freed in the destructor.) Also, + /// build the hash of activities to sequences and populate m_pSequenceTuples. + void Initialize( CStudioHdr *pstudiohdr ); + + /// Force Initialize() to occur again, even if it has already occured. + void Reinitialize( CStudioHdr *pstudiohdr ); + + /// A more efficient version of the old SelectWeightedSequence() function in animation.cpp. + int SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence ); + + // selects the sequence with the most matching modifiers + int SelectWeightedSequenceFromModifiers( CStudioHdr *pstudiohdr, int activity, CUtlSymbol *pActivityModifiers, int iModifierCount ); + + // Actually a big array, into which the hash values index. + SequenceTuple *m_pSequenceTuples; + unsigned int m_iSequenceTuplesCount; // (size of the whole array) +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + bool m_bIsInitialized; +#endif + + // we don't store an outer pointer because we can't initialize it at construction time + // (warning c4355) -- there are ways around this but it's easier to just pass in a + // pointer to the CStudioHdr when we need it, since this class isn't supposed to + // export its interface outside the studio header anyway. + // CStudioHdr * const m_pOuter; + + ActivityToValueIdxHash m_ActToSeqHash; + + // we store these so we can know if the contents of the studiohdr have changed + // from underneath our feet (this is an emergency data integrity check) + const void *m_expectedPStudioHdr; + const void *m_expectedVModel; + + // double-check that the data I point to hasn't changed + bool ValidateAgainst( const CStudioHdr * RESTRICT pstudiohdr ); + void SetValidationPair( const CStudioHdr *RESTRICT pstudiohdr ); + + friend class CStudioHdr; + }; + + CActivityToSequenceMapping m_ActivityToSequence; + + /// A more efficient version of the old SelectWeightedSequence() function in animation.cpp. + /// Returns -1 on failure to find a sequence + inline int SelectWeightedSequence( int activity, int curSequence ) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + // We lazy-initialize the header on demand here, because CStudioHdr::Init() is + // called from the constructor, at which time the this pointer is illegitimate. + if ( !m_ActivityToSequence.IsInitialized() ) + { + m_ActivityToSequence.Initialize(this); + } +#endif + return m_ActivityToSequence.SelectWeightedSequence( this, activity, curSequence ); + } + + inline int SelectWeightedSequenceFromModifiers( int activity, CUtlSymbol *pActivityModifiers, int iModifierCount ) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + // We lazy-initialize the header on demand here, because CStudioHdr::Init() is + // called from the constructor, at which time the this pointer is illegitimate. + if ( !m_ActivityToSequence.IsInitialized() ) + { + m_ActivityToSequence.Initialize( this ); + } +#endif + return m_ActivityToSequence.SelectWeightedSequenceFromModifiers( this, activity, pActivityModifiers, iModifierCount ); + } + + /// True iff there is at least one sequence for the given activity. + inline bool HaveSequenceForActivity( int activity ) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + if ( !m_ActivityToSequence.IsInitialized() ) + { + m_ActivityToSequence.Initialize(this); + } +#endif + return (m_ActivityToSequence.NumSequencesForActivity( activity ) > 0); + } + + // Force this CStudioHdr's activity-to-sequence mapping to be reinitialized + inline void ReinitializeSequenceMapping(void) + { + m_ActivityToSequence.Reinitialize(this); + } + +#ifdef STUDIO_ENABLE_PERF_COUNTERS +public: + inline void ClearPerfCounters( void ) + { + m_nPerfAnimatedBones = 0; + m_nPerfUsedBones = 0; + m_nPerfAnimationLayers = 0; + }; + + // timing info + mutable int m_nPerfAnimatedBones; + mutable int m_nPerfUsedBones; + mutable int m_nPerfAnimationLayers; +#endif + + +}; + +/* +class CModelAccess +{ +public: + CModelAccess(CStudioHdr *pSemaphore) + : m_pStudioHdr(pSemaphore) + { + m_pStudioHdr->IncrementAccess(); + } + + ~CModelAccess() + { + m_pStudioHdr->DecrementAccess(); + } + +private: + CStudioHdr *m_pStudioHdr; +}; + +#define ENABLE_MODEL_ACCESS( a ) \ + CModelAccess ModelAccess##__LINE__( a->m_pStudioHdr ) +*/ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +struct flexweight_t +{ + DECLARE_BYTESWAP_DATADESC(); + int key; + float weight; + float influence; +}; + +struct flexsetting_t +{ + DECLARE_BYTESWAP_DATADESC(); + int nameindex; + + inline char *pszName( void ) const + { + return (char *)(((byte *)this) + nameindex); + } + + // Leaving this for legacy support + int obsolete1; + + // Number of flex settings + int numsettings; + int index; + + // OBSOLETE: + int obsolete2; + + // Index of start of contiguous array of flexweight_t structures + int settingindex; + + //----------------------------------------------------------------------------- + // Purpose: Retrieves a pointer to the flexweight_t, including resolving + // any markov chain hierarchy. Because of this possibility, we return + // the number of settings in the weights array returned. We'll generally + // call this function with i == 0 + // Input : *base - + // i - + // **weights - + // Output : int + //----------------------------------------------------------------------------- + inline int psetting( byte *base, int i, flexweight_t **weights ) const; +}; + + +struct flexsettinghdr_t +{ + DECLARE_BYTESWAP_DATADESC(); + int id; + int version; + + inline const char * pszName( void ) const { return name; } + char name[64]; + int length; + + int numflexsettings; + int flexsettingindex; + inline flexsetting_t *pSetting( int i ) const { return (flexsetting_t *)(((byte *)this) + flexsettingindex) + i; }; + int nameindex; + + // look up flex settings by "index" + int numindexes; + int indexindex; + + inline flexsetting_t *pIndexedSetting( int index ) const + { + if ( index < 0 || index >= numindexes ) + { + return NULL; + } + + int i = *((int *)(((byte *)this) + indexindex) + index); + + if (i == -1) + { + return NULL; + } + + return pSetting( i ); + } + + // index names of "flexcontrollers" + int numkeys; + int keynameindex; + inline char *pLocalName( int i ) const { return (char *)(((byte *)this) + *((int *)(((byte *)this) + keynameindex) + i)); }; + + int keymappingindex; + inline int *pLocalToGlobal( int i ) const { return (int *)(((byte *)this) + keymappingindex) + i; }; + inline int LocalToGlobal( int i ) const { return *pLocalToGlobal( i ); }; +}; + +//----------------------------------------------------------------------------- +// Purpose: Retrieves a pointer to the flexweight_t. +// Input : *base - flexsettinghdr_t * pointer +// i - index of flex setting to retrieve +// **weights - destination for weights array starting at index i. +// Output : int +//----------------------------------------------------------------------------- +inline int flexsetting_t::psetting( byte *base, int i, flexweight_t **weights ) const +{ + // Grab array pointer + *weights = (flexweight_t *)(((byte *)this) + settingindex) + i; + // Return true number of settings + return numsettings; +}; + + +//----------------------------------------------------------------------------- +// For a given flex controller ui struct, these return the index of the +// studiohdr_t flex controller that correspond to the the left and right +// flex controllers if the ui controller is a stereo control. +// nWayValueIndex returns the index of the flex controller that is the value +// flex controller for an NWAY combination +// If these functions are called and the ui controller isn't of the type +// specified then -1 is returned +//----------------------------------------------------------------------------- +inline int mstudioflexcontrollerui_t::controllerIndex( const CStudioHdr &cStudioHdr ) const +{ + return !stereo ? pController() - cStudioHdr.pFlexcontroller( (LocalFlexController_t)0 ) : -1; +} + + +inline int mstudioflexcontrollerui_t::rightIndex( const CStudioHdr &cStudioHdr ) const +{ + return stereo ? pRightController() - cStudioHdr.pFlexcontroller( (LocalFlexController_t)0 ) : -1; +} + + +inline int mstudioflexcontrollerui_t::leftIndex( const CStudioHdr &cStudioHdr ) const +{ + return stereo ? pLeftController() - cStudioHdr.pFlexcontroller((LocalFlexController_t) 0 ) : -1; +} + + +inline int mstudioflexcontrollerui_t::nWayValueIndex( const CStudioHdr &cStudioHdr ) const +{ + return remaptype == FLEXCONTROLLER_REMAP_NWAY ? pNWayValueController() - cStudioHdr.pFlexcontroller( (LocalFlexController_t)0 ) : -1; +} + + +inline const mstudioflexcontroller_t *mstudioflexcontrollerui_t::pController( int index ) const +{ + if ( index < 0 || index > Count() ) + return NULL; + + if ( remaptype == FLEXCONTROLLER_REMAP_NWAY ) + { + if ( stereo ) + return (mstudioflexcontroller_t *)( ( char * ) this ) + *( &szindex0 + index ); + + if ( index == 0 ) + return pController(); + + if ( index == 1 ) + return pNWayValueController(); + + return NULL; + } + + if ( index > 1 ) + return NULL; + + if ( stereo ) + return (mstudioflexcontroller_t *)( ( char * ) this ) + *( &szindex0 + index ); + + if ( index > 0 ) + return NULL; + + return pController(); +} + + +#define STUDIO_CONST 1 // get float +#define STUDIO_FETCH1 2 // get Flexcontroller value +#define STUDIO_FETCH2 3 // get flex weight +#define STUDIO_ADD 4 +#define STUDIO_SUB 5 +#define STUDIO_MUL 6 +#define STUDIO_DIV 7 +#define STUDIO_NEG 8 // not implemented +#define STUDIO_EXP 9 // not implemented +#define STUDIO_OPEN 10 // only used in token parsing +#define STUDIO_CLOSE 11 +#define STUDIO_COMMA 12 // only used in token parsing +#define STUDIO_MAX 13 +#define STUDIO_MIN 14 +#define STUDIO_2WAY_0 15 // Fetch a value from a 2 Way slider for the 1st value RemapVal( 0.0, 0.5, 0.0, 1.0 ) +#define STUDIO_2WAY_1 16 // Fetch a value from a 2 Way slider for the 2nd value RemapVal( 0.5, 1.0, 0.0, 1.0 ) +#define STUDIO_NWAY 17 // Fetch a value from a 2 Way slider for the 2nd value RemapVal( 0.5, 1.0, 0.0, 1.0 ) +#define STUDIO_COMBO 18 // Perform a combo operation (essentially multiply the last N values on the stack) +#define STUDIO_DOMINATE 19 // Performs a combination domination operation +#define STUDIO_DME_LOWER_EYELID 20 // +#define STUDIO_DME_UPPER_EYELID 21 // + +// motion flags +#define STUDIO_X 0x00000001 +#define STUDIO_Y 0x00000002 +#define STUDIO_Z 0x00000004 +#define STUDIO_XR 0x00000008 +#define STUDIO_YR 0x00000010 +#define STUDIO_ZR 0x00000020 + +#define STUDIO_LX 0x00000040 +#define STUDIO_LY 0x00000080 +#define STUDIO_LZ 0x00000100 +#define STUDIO_LXR 0x00000200 +#define STUDIO_LYR 0x00000400 +#define STUDIO_LZR 0x00000800 + +#define STUDIO_LINEAR 0x00001000 + +#define STUDIO_TYPES 0x0003FFFF +#define STUDIO_RLOOP 0x00040000 // controller that wraps shortest distance + +// sequence and autolayer flags +#define STUDIO_LOOPING 0x0001 // ending frame should be the same as the starting frame +#define STUDIO_SNAP 0x0002 // do not interpolate between previous animation and this one +#define STUDIO_DELTA 0x0004 // this sequence "adds" to the base sequences, not slerp blends +#define STUDIO_AUTOPLAY 0x0008 // temporary flag that forces the sequence to always play +#define STUDIO_POST 0x0010 // +#define STUDIO_ALLZEROS 0x0020 // this animation/sequence has no real animation data +// 0x0040 +#define STUDIO_CYCLEPOSE 0x0080 // cycle index is taken from a pose parameter index +#define STUDIO_REALTIME 0x0100 // cycle index is taken from a real-time clock, not the animations cycle index +#define STUDIO_LOCAL 0x0200 // sequence has a local context sequence +#define STUDIO_HIDDEN 0x0400 // don't show in default selection views +#define STUDIO_OVERRIDE 0x0800 // a forward declared sequence (empty) +#define STUDIO_ACTIVITY 0x1000 // Has been updated at runtime to activity index +#define STUDIO_EVENT 0x2000 // Has been updated at runtime to event index +#define STUDIO_WORLD 0x4000 // sequence blends in worldspace +// autolayer flags +// 0x0001 +// 0x0002 +// 0x0004 +// 0x0008 +#define STUDIO_AL_POST 0x0010 // +// 0x0020 +#define STUDIO_AL_SPLINE 0x0040 // convert layer ramp in/out curve is a spline instead of linear +#define STUDIO_AL_XFADE 0x0080 // pre-bias the ramp curve to compense for a non-1 weight, assuming a second layer is also going to accumulate +// 0x0100 +#define STUDIO_AL_NOBLEND 0x0200 // animation always blends at 1.0 (ignores weight) +// 0x0400 +// 0x0800 +#define STUDIO_AL_LOCAL 0x1000 // layer is a local context sequence +// 0x2000 +#define STUDIO_AL_POSE 0x4000 // layer blends using a pose parameter instead of parent cycle + + +// Insert this code anywhere that you need to allow for conversion from an old STUDIO_VERSION +// to a new one. +// If we only support the current version, this function should be empty. +inline bool Studio_ConvertStudioHdrToNewVersion( studiohdr_t *pStudioHdr ) +{ + COMPILE_TIME_ASSERT( STUDIO_VERSION == 48 ); // put this to make sure this code is updated upon changing version. + + int version = pStudioHdr->version; + if ( version == STUDIO_VERSION ) + return true; + + bool bResult = true; + if (version < 46) + { + // some of the anim index data is incompatible + for (int i = 0; i < pStudioHdr->numlocalanim; i++) + { + mstudioanimdesc_t *pAnim = (mstudioanimdesc_t *)pStudioHdr->pLocalAnimdesc( i ); + + // old ANI files that used sections (v45 only) are not compatible + if ( pAnim->sectionframes != 0 ) + { + // zero most everything out + memset( &(pAnim->numframes), 0, (byte *)(pAnim + 1) - (byte *)&(pAnim->numframes) ); + + pAnim->numframes = 1; + pAnim->animblock = -1; // disable animation fetching + bResult = false; + } + } + } + + if (version < 47) + { + // used to contain zeroframe cache data + if (pStudioHdr->unused4 != 0) + { + pStudioHdr->unused4 = 0; + bResult = false; + } + for (int i = 0; i < pStudioHdr->numlocalanim; i++) + { + mstudioanimdesc_t *pAnim = (mstudioanimdesc_t *)pStudioHdr->pLocalAnimdesc( i ); + pAnim->zeroframeindex = 0; + pAnim->zeroframespan = 0; + } + } + else if (version == 47) + { + for (int i = 0; i < pStudioHdr->numlocalanim; i++) + { + mstudioanimdesc_t *pAnim = (mstudioanimdesc_t *)pStudioHdr->pLocalAnimdesc( i ); + if (pAnim->zeroframeindex != 0) + { + pAnim->zeroframeindex = 0; + pAnim->zeroframespan = 0; + bResult = false; + } + } + } + + // for now, just slam the version number since they're compatible + pStudioHdr->version = STUDIO_VERSION; + + return bResult; +} + +// must be run to fixup with specified rootLOD +inline void Studio_SetRootLOD( studiohdr_t *pStudioHdr, int rootLOD ) +{ + // honor studiohdr restriction of root lod in case requested root lod exceeds restriction. + if ( pStudioHdr->numAllowedRootLODs > 0 && + rootLOD >= pStudioHdr->numAllowedRootLODs ) + { + rootLOD = pStudioHdr->numAllowedRootLODs - 1; + } + + Assert( rootLOD >= 0 && rootLOD < MAX_NUM_LODS ); + Clamp( rootLOD, 0, MAX_NUM_LODS - 1 ); + + // run the lod fixups that culls higher detail lods + // vertexes are external, fixups ensure relative offsets and counts are cognizant of shrinking data + // indexes are built in lodN..lod0 order so higher detail lod data can be truncated at load + // the fixup lookup arrays are filled (or replicated) to ensure all slots valid + int vertexindex = 0; + int tangentsindex = 0; + int bodyPartID; + for ( bodyPartID = 0; bodyPartID < pStudioHdr->numbodyparts; bodyPartID++ ) + { + mstudiobodyparts_t *pBodyPart = pStudioHdr->pBodypart( bodyPartID ); + int modelID; + for ( modelID = 0; modelID < pBodyPart->nummodels; modelID++ ) + { + mstudiomodel_t *pModel = pBodyPart->pModel( modelID ); + int totalMeshVertexes = 0; + int meshID; + for ( meshID = 0; meshID < pModel->nummeshes; meshID++ ) + { + mstudiomesh_t *pMesh = pModel->pMesh( meshID ); + + // get the fixup, vertexes are reduced + pMesh->numvertices = pMesh->vertexdata.numLODVertexes[rootLOD]; + pMesh->vertexoffset = totalMeshVertexes; + totalMeshVertexes += pMesh->numvertices; + } + + // stay in sync + pModel->numvertices = totalMeshVertexes; + pModel->vertexindex = vertexindex; + pModel->tangentsindex = tangentsindex; + + vertexindex += totalMeshVertexes*sizeof(mstudiovertex_t); + tangentsindex += totalMeshVertexes*sizeof(Vector4D); + } + } + + // track the set desired configuration + pStudioHdr->rootLOD = rootLOD; +} + +// Determines allocation requirements for vertexes +inline int Studio_VertexDataSize( const vertexFileHeader_t *pVvdHdr, int rootLOD, bool bNeedsTangentS ) +{ + // the quantity of vertexes necessary for root lod and all lower detail lods + // add one extra vertex to each section + // the extra vertex allows prefetch hints to read ahead 1 vertex without faulting + int numVertexes = pVvdHdr->numLODVertexes[rootLOD] + 1; + int dataLength = pVvdHdr->vertexDataStart + numVertexes*sizeof(mstudiovertex_t); + if (bNeedsTangentS) + { + dataLength += numVertexes*sizeof(Vector4D); + } + + // allocate this much + return dataLength; +} + +// Load the minimum quantity of verts and run fixups +inline int Studio_LoadVertexes( const vertexFileHeader_t *pTempVvdHdr, vertexFileHeader_t *pNewVvdHdr, int rootLOD, bool bNeedsTangentS ) +{ + int i; + int target; + int numVertexes; + vertexFileFixup_t *pFixupTable; + + numVertexes = pTempVvdHdr->numLODVertexes[rootLOD]; + + // copy all data up to start of vertexes + memcpy((void*)pNewVvdHdr, (void*)pTempVvdHdr, pTempVvdHdr->vertexDataStart); + + for ( i = 0; i < rootLOD; i++) + { + pNewVvdHdr->numLODVertexes[i] = pNewVvdHdr->numLODVertexes[rootLOD]; + } + + // fixup data starts + if (bNeedsTangentS) + { + // tangent data follows possibly reduced vertex data + pNewVvdHdr->tangentDataStart = pNewVvdHdr->vertexDataStart + numVertexes*sizeof(mstudiovertex_t); + } + else + { + // no tangent data will be available, mark for identification + pNewVvdHdr->tangentDataStart = 0; + } + + if (!pNewVvdHdr->numFixups) + { + // fixups not required + // transfer vertex data + memcpy( + (byte *)pNewVvdHdr+pNewVvdHdr->vertexDataStart, + (byte *)pTempVvdHdr+pTempVvdHdr->vertexDataStart, + numVertexes*sizeof(mstudiovertex_t) ); + + if (bNeedsTangentS) + { + // transfer tangent data to cache memory + memcpy( + (byte *)pNewVvdHdr+pNewVvdHdr->tangentDataStart, + (byte *)pTempVvdHdr+pTempVvdHdr->tangentDataStart, + numVertexes*sizeof(Vector4D) ); + } + + return numVertexes; + } + + // fixups required + // re-establish mesh ordered vertexes into cache memory, according to table + target = 0; + pFixupTable = (vertexFileFixup_t *)((byte *)pTempVvdHdr + pTempVvdHdr->fixupTableStart); + for (i=0; inumFixups; i++) + { + if (pFixupTable[i].lod < rootLOD) + { + // working bottom up, skip over copying higher detail lods + continue; + } + + // copy vertexes + memcpy( + (mstudiovertex_t *)((byte *)pNewVvdHdr+pNewVvdHdr->vertexDataStart) + target, + (mstudiovertex_t *)((byte *)pTempVvdHdr+pTempVvdHdr->vertexDataStart) + pFixupTable[i].sourceVertexID, + pFixupTable[i].numVertexes*sizeof(mstudiovertex_t) ); + + if (bNeedsTangentS) + { + // copy tangents + memcpy( + (Vector4D *)((byte *)pNewVvdHdr+pNewVvdHdr->tangentDataStart) + target, + (Vector4D *)((byte *)pTempVvdHdr+pTempVvdHdr->tangentDataStart) + pFixupTable[i].sourceVertexID, + pFixupTable[i].numVertexes*sizeof(Vector4D) ); + } + + // data is placed consecutively + target += pFixupTable[i].numVertexes; + } + + pNewVvdHdr->numFixups = 0; + + return target; +} + +#endif // STUDIO_H diff --git a/public/studio_generic_io.cpp b/public/studio_generic_io.cpp new file mode 100644 index 0000000..7345e9a --- /dev/null +++ b/public/studio_generic_io.cpp @@ -0,0 +1,156 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include + +#include "studio.h" +#include "utlrbtree.h" + +extern studiohdr_t *FindOrLoadGroupFile( char const *modelname ); + +virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const +{ + if (numincludemodels == 0) + { + return NULL; + } + + virtualmodel_t *pVModel = (virtualmodel_t *)virtualModel; + + if (pVModel == NULL) + { + pVModel = new virtualmodel_t; + + // !!! Set cache handle? Set pointer to local virtual model?? + virtualModel = (void *)pVModel; + + int group = pVModel->m_group.AddToTail( ); + pVModel->m_group[ group ].cache = (void *)this; + pVModel->AppendModels( 0, this ); + } + + return pVModel; +} + + +const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *modelname ) const +{ + studiohdr_t *hdr = (studiohdr_t *)(*cache); + + if (hdr) + { + return hdr; + } + + hdr = FindOrLoadGroupFile( modelname ); + + *cache = (void *)hdr; + + return hdr; +} + +const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const +{ + return (studiohdr_t *)cache; +} + + +byte *studiohdr_t::GetAnimBlock( int i ) const +{ + byte *hdr = (byte *)animblockModel; + + if (!hdr) + { + hdr = (byte *)FindOrLoadGroupFile( pszAnimBlockName() ); + animblockModel = hdr; + } + + return hdr + pAnimBlock( i )->datastart; +} + +//----------------------------------------------------------------------------- +// Purpose: Builds up a dictionary of autoplay indices by studiohdr_t * +// NOTE: This list never gets freed even if the model gets unloaded, but we're in a tool so we can probably live with that +//----------------------------------------------------------------------------- +struct AutoPlayGeneric_t +{ +public: + + AutoPlayGeneric_t() : + hdr( 0 ) + { + } + + // Implement copy constructor + AutoPlayGeneric_t( const AutoPlayGeneric_t& src ) + { + hdr = src.hdr; + autoplaylist.EnsureCount( src.autoplaylist.Count() ); + autoplaylist.CopyArray( src.autoplaylist.Base(), src.autoplaylist.Count() ); + } + + static bool AutoPlayGenericLessFunc( const AutoPlayGeneric_t& lhs, const AutoPlayGeneric_t& rhs ) + { + return lhs.hdr < rhs.hdr; + } + +public: + // Data + const studiohdr_t *hdr; + CUtlVector< unsigned short > autoplaylist; +}; + +// A global array to track this data +static CUtlRBTree< AutoPlayGeneric_t, int > g_AutoPlayGeneric( 0, 0, AutoPlayGeneric_t::AutoPlayGenericLessFunc ); + +int studiohdr_t::GetAutoplayList( unsigned short **pAutoplayList ) const +{ + virtualmodel_t *pVirtualModel = GetVirtualModel(); + if ( pVirtualModel ) + { + if ( pAutoplayList && pVirtualModel->m_autoplaySequences.Count() ) + { + *pAutoplayList = pVirtualModel->m_autoplaySequences.Base(); + } + return pVirtualModel->m_autoplaySequences.Count(); + } + + AutoPlayGeneric_t *pData = NULL; + + // Search for this studiohdr_t ptr in the global list + AutoPlayGeneric_t search; + search.hdr = this; + int index = g_AutoPlayGeneric.Find( search ); + if ( index == g_AutoPlayGeneric.InvalidIndex() ) + { + // Not there, so add it + index = g_AutoPlayGeneric.Insert( search ); + pData = &g_AutoPlayGeneric[ index ]; + // And compute the autoplay info this one time + int autoPlayCount = CountAutoplaySequences(); + pData->autoplaylist.EnsureCount( autoPlayCount ); + CopyAutoplaySequences( pData->autoplaylist.Base(), autoPlayCount ); + } + else + { + // Refer to existing data + pData = &g_AutoPlayGeneric[ index ]; + } + + // Oops!!! + if ( !pData ) + { + return 0; + } + + // Give back data if it's being requested + if ( pAutoplayList ) + { + *pAutoplayList = pData->autoplaylist.Base(); + } + return pData->autoplaylist.Count(); +} diff --git a/public/studio_virtualmodel.cpp b/public/studio_virtualmodel.cpp new file mode 100644 index 0000000..37939c9 --- /dev/null +++ b/public/studio_virtualmodel.cpp @@ -0,0 +1,594 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include +#include "studio.h" +#include "tier1/utlmap.h" +#include "tier1/utldict.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "tier0/icommandline.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern IFileSystem * g_pFileSystem; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +// a string table to speed up searching for sequences in the current virtual model +struct modellookup_t +{ + CUtlDict seqTable; + CUtlDict animTable; +}; + +static CUtlVector g_ModelLookup; +static int g_ModelLookupIndex = -1; + +inline bool HasLookupTable() +{ + return g_ModelLookupIndex >= 0 ? true : false; +} + +inline CUtlDict *GetSeqTable() +{ + return &g_ModelLookup[g_ModelLookupIndex].seqTable; +} + +inline CUtlDict *GetAnimTable() +{ + return &g_ModelLookup[g_ModelLookupIndex].animTable; +} + +class CModelLookupContext +{ +public: + CModelLookupContext(int group, const studiohdr_t *pStudioHdr); + ~CModelLookupContext(); + +private: + int m_lookupIndex; +}; + +CModelLookupContext::CModelLookupContext(int group, const studiohdr_t *pStudioHdr) +{ + m_lookupIndex = -1; + if ( group == 0 && pStudioHdr->numincludemodels ) + { + m_lookupIndex = g_ModelLookup.AddToTail(); + g_ModelLookupIndex = g_ModelLookup.Count()-1; + } +} + +CModelLookupContext::~CModelLookupContext() +{ + if ( m_lookupIndex >= 0 ) + { + Assert(m_lookupIndex == (g_ModelLookup.Count()-1)); + g_ModelLookup.FastRemove(m_lookupIndex); + g_ModelLookupIndex = g_ModelLookup.Count()-1; + } +} + +void virtualmodel_t::AppendModels( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + + // build a search table if necesary + CModelLookupContext ctx(group, pStudioHdr); + + AppendSequences( group, pStudioHdr ); + AppendAnimations( group, pStudioHdr ); + AppendBonemap( group, pStudioHdr ); + AppendAttachments( group, pStudioHdr ); + AppendPoseParameters( group, pStudioHdr ); + AppendNodes( group, pStudioHdr ); + AppendIKLocks( group, pStudioHdr ); + + struct HandleAndHeader_t + { + void *handle; + const studiohdr_t *pHdr; + }; + HandleAndHeader_t list[64]; + + // determine quantity of valid include models in one pass only + // temporarily cache results off, otherwise FindModel() causes ref counting problems + int j; + int nValidIncludes = 0; + for (j = 0; j < pStudioHdr->numincludemodels; j++) + { + // find model (increases ref count) + void *tmp = NULL; + const studiohdr_t *pTmpHdr = pStudioHdr->FindModel( &tmp, pStudioHdr->pModelGroup( j )->pszName() ); + if ( pTmpHdr ) + { + if ( nValidIncludes >= ARRAYSIZE( list ) ) + { + // would cause stack overflow + Assert( 0 ); + break; + } + + list[nValidIncludes].handle = tmp; + list[nValidIncludes].pHdr = pTmpHdr; + nValidIncludes++; + } + } + + if ( nValidIncludes ) + { + m_group.EnsureCapacity( m_group.Count() + nValidIncludes ); + for (j = 0; j < nValidIncludes; j++) + { + MEM_ALLOC_CREDIT(); + int group = m_group.AddToTail(); + m_group[group].cache = list[j].handle; + AppendModels( group, list[j].pHdr ); + } + } + + UpdateAutoplaySequences( pStudioHdr ); +} + +void virtualmodel_t::AppendSequences( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int numCheck = m_seq.Count(); + + int j, k; + + MEM_ALLOC_CREDIT(); + + CUtlVector< virtualsequence_t > seq; + + seq = m_seq; + + m_group[ group ].masterSeq.SetCount( pStudioHdr->numlocalseq ); + + for (j = 0; j < pStudioHdr->numlocalseq; j++) + { + const mstudioseqdesc_t *seqdesc = pStudioHdr->pLocalSeqdesc( j ); + char *s1 = seqdesc->pszLabel(); + + if ( HasLookupTable() ) + { + k = numCheck; + short index = GetSeqTable()->Find( s1 ); + if ( index != GetSeqTable()->InvalidIndex() ) + { + k = GetSeqTable()->Element(index); + } + } + else + { + for (k = 0; k < numCheck; k++) + { + const studiohdr_t *hdr = m_group[ seq[k].group ].GetStudioHdr(); + char *s2 = hdr->pLocalSeqdesc( seq[k].index )->pszLabel(); + if ( !stricmp( s1, s2 ) ) + { + break; + } + } + } + // no duplication + if (k == numCheck) + { + virtualsequence_t tmp; + tmp.group = group; + tmp.index = j; + tmp.flags = seqdesc->flags; + tmp.activity = seqdesc->activity; + k = seq.AddToTail( tmp ); + } + else if (m_group[ seq[k].group ].GetStudioHdr()->pLocalSeqdesc( seq[k].index )->flags & STUDIO_OVERRIDE) + { + // the one in memory is a forward declared sequence, override it + virtualsequence_t tmp; + tmp.group = group; + tmp.index = j; + tmp.flags = seqdesc->flags; + tmp.activity = seqdesc->activity; + seq[k] = tmp; + } + m_group[ group ].masterSeq[ j ] = k; + } + + if ( HasLookupTable() ) + { + for ( j = numCheck; j < seq.Count(); j++ ) + { + const studiohdr_t *hdr = m_group[ seq[j].group ].GetStudioHdr(); + const char *s1 = hdr->pLocalSeqdesc( seq[j].index )->pszLabel(); + GetSeqTable()->Insert( s1, j ); + } + } + + m_seq = seq; +} + + +void virtualmodel_t::UpdateAutoplaySequences( const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int autoplayCount = pStudioHdr->CountAutoplaySequences(); + m_autoplaySequences.SetCount( autoplayCount ); + pStudioHdr->CopyAutoplaySequences( m_autoplaySequences.Base(), autoplayCount ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void virtualmodel_t::AppendAnimations( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int numCheck = m_anim.Count(); + + CUtlVector< virtualgeneric_t > anim; + anim = m_anim; + + MEM_ALLOC_CREDIT(); + + int j, k; + + m_group[ group ].masterAnim.SetCount( pStudioHdr->numlocalanim ); + + for (j = 0; j < pStudioHdr->numlocalanim; j++) + { + char *s1 = pStudioHdr->pLocalAnimdesc( j )->pszName(); + if ( HasLookupTable() ) + { + k = numCheck; + short index = GetAnimTable()->Find( s1 ); + if ( index != GetAnimTable()->InvalidIndex() ) + { + k = GetAnimTable()->Element(index); + } + } + else + { + for (k = 0; k < numCheck; k++) + { + char *s2 = m_group[ anim[k].group ].GetStudioHdr()->pLocalAnimdesc( anim[k].index )->pszName(); + if (stricmp( s1, s2 ) == 0) + { + break; + } + } + } + // no duplication + if (k == numCheck) + { + virtualgeneric_t tmp; + tmp.group = group; + tmp.index = j; + k = anim.AddToTail( tmp ); + } + + m_group[ group ].masterAnim[ j ] = k; + } + + if ( HasLookupTable() ) + { + for ( j = numCheck; j < anim.Count(); j++ ) + { + const char *s1 = m_group[ anim[j].group ].GetStudioHdr()->pLocalAnimdesc( anim[j].index )->pszName(); + GetAnimTable()->Insert( s1, j ); + } + } + + m_anim = anim; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void virtualmodel_t::AppendBonemap( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + MEM_ALLOC_CREDIT(); + + const studiohdr_t *pBaseStudioHdr = m_group[ 0 ].GetStudioHdr( ); + + m_group[ group ].boneMap.SetCount( pBaseStudioHdr->numbones ); + m_group[ group ].masterBone.SetCount( pStudioHdr->numbones ); + + int j, k; + + if (group == 0) + { + for (j = 0; j < pStudioHdr->numbones; j++) + { + m_group[ group ].boneMap[ j ] = j; + m_group[ group ].masterBone[ j ] = j; + } + } + else + { + for (j = 0; j < pBaseStudioHdr->numbones; j++) + { + m_group[ group ].boneMap[ j ] = -1; + } + for (j = 0; j < pStudioHdr->numbones; j++) + { + // NOTE: studiohdr has a bone table - using the table is ~5% faster than this for alyx.mdl on a P4/3.2GHz + for (k = 0; k < pBaseStudioHdr->numbones; k++) + { + if (stricmp( pStudioHdr->pBone( j )->pszName(), pBaseStudioHdr->pBone( k )->pszName() ) == 0) + { + break; + } + } + if (k < pBaseStudioHdr->numbones) + { + m_group[ group ].masterBone[ j ] = k; + m_group[ group ].boneMap[ k ] = j; + + // FIXME: these runtime messages don't display in hlmv + if ((pStudioHdr->pBone( j )->parent == -1) || (pBaseStudioHdr->pBone( k )->parent == -1)) + { + if ((pStudioHdr->pBone( j )->parent != -1) || (pBaseStudioHdr->pBone( k )->parent != -1)) + { + Warning( "%s/%s : missmatched parent bones on \"%s\"\n", pBaseStudioHdr->pszName(), pStudioHdr->pszName(), pStudioHdr->pBone( j )->pszName() ); + } + } + else if (m_group[ group ].masterBone[ pStudioHdr->pBone( j )->parent ] != m_group[ 0 ].masterBone[ pBaseStudioHdr->pBone( k )->parent ]) + { + Warning( "%s/%s : missmatched parent bones on \"%s\"\n", pBaseStudioHdr->pszName(), pStudioHdr->pszName(), pStudioHdr->pBone( j )->pszName() ); + } + } + else + { + m_group[ group ].masterBone[ j ] = -1; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void virtualmodel_t::AppendAttachments( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int numCheck = m_attachment.Count(); + + CUtlVector< virtualgeneric_t > attachment; + attachment = m_attachment; + + MEM_ALLOC_CREDIT(); + + int j, k, n; + + m_group[ group ].masterAttachment.SetCount( pStudioHdr->numlocalattachments ); + + for (j = 0; j < pStudioHdr->numlocalattachments; j++) + { + + n = m_group[ group ].masterBone[ pStudioHdr->pLocalAttachment( j )->localbone ]; + + // skip if the attachments bone doesn't exist in the root model + if (n == -1) + { + continue; + } + + + char *s1 = pStudioHdr->pLocalAttachment( j )->pszName(); + for (k = 0; k < numCheck; k++) + { + char *s2 = m_group[ attachment[k].group ].GetStudioHdr()->pLocalAttachment( attachment[k].index )->pszName(); + + if (stricmp( s1, s2 ) == 0) + { + break; + } + } + // no duplication + if (k == numCheck) + { + virtualgeneric_t tmp; + tmp.group = group; + tmp.index = j; + k = attachment.AddToTail( tmp ); + + // make sure bone flags are set so attachment calculates + if ((m_group[ 0 ].GetStudioHdr()->pBone( n )->flags & BONE_USED_BY_ATTACHMENT) == 0) + { + while (n != -1) + { + m_group[ 0 ].GetStudioHdr()->pBone( n )->flags |= BONE_USED_BY_ATTACHMENT; + + if (m_group[ 0 ].GetStudioHdr()->pLinearBones()) + { + *m_group[ 0 ].GetStudioHdr()->pLinearBones()->pflags(n) |= BONE_USED_BY_ATTACHMENT; + } + + n = m_group[ 0 ].GetStudioHdr()->pBone( n )->parent; + } + continue; + } + } + + m_group[ group ].masterAttachment[ j ] = k; + } + + m_attachment = attachment; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void virtualmodel_t::AppendPoseParameters( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int numCheck = m_pose.Count(); + + CUtlVector< virtualgeneric_t > pose; + pose = m_pose; + + MEM_ALLOC_CREDIT(); + + int j, k; + + m_group[ group ].masterPose.SetCount( pStudioHdr->numlocalposeparameters ); + + for (j = 0; j < pStudioHdr->numlocalposeparameters; j++) + { + char *s1 = pStudioHdr->pLocalPoseParameter( j )->pszName(); + for (k = 0; k < numCheck; k++) + { + char *s2 = m_group[ pose[k].group ].GetStudioHdr()->pLocalPoseParameter( pose[k].index )->pszName(); + + if (stricmp( s1, s2 ) == 0) + { + break; + } + } + if (k == numCheck) + { + // no duplication + virtualgeneric_t tmp; + tmp.group = group; + tmp.index = j; + k = pose.AddToTail( tmp ); + } + else + { + // duplicate, reset start and end to fit full dynamic range + mstudioposeparamdesc_t *pPose1 = pStudioHdr->pLocalPoseParameter( j ); + mstudioposeparamdesc_t *pPose2 = m_group[ pose[k].group ].GetStudioHdr()->pLocalPoseParameter( pose[k].index ); + float start = vmin( pPose2->end, vmin( pPose1->end, vmin( pPose2->start, pPose1->start ) ) ); + float end = vmax( pPose2->end, vmax( pPose1->end, vmax( pPose2->start, pPose1->start ) ) ); + pPose2->start = start; + pPose2->end = end; + } + + m_group[ group ].masterPose[ j ] = k; + } + + m_pose = pose; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +void virtualmodel_t::AppendNodes( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int numCheck = m_node.Count(); + + CUtlVector< virtualgeneric_t > node; + node = m_node; + + MEM_ALLOC_CREDIT(); + + int j, k; + + m_group[ group ].masterNode.SetCount( pStudioHdr->numlocalnodes ); + + for (j = 0; j < pStudioHdr->numlocalnodes; j++) + { + char *s1 = pStudioHdr->pszLocalNodeName( j ); + for (k = 0; k < numCheck; k++) + { + char *s2 = m_group[ node[k].group ].GetStudioHdr()->pszLocalNodeName( node[k].index ); + + if (stricmp( s1, s2 ) == 0) + { + break; + } + } + // no duplication + if (k == numCheck) + { + virtualgeneric_t tmp; + tmp.group = group; + tmp.index = j; + k = node.AddToTail( tmp ); + } + + m_group[ group ].masterNode[ j ] = k; + } + + m_node = node; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + + +void virtualmodel_t::AppendIKLocks( int group, const studiohdr_t *pStudioHdr ) +{ + AUTO_LOCK_( CThreadTerminalMutex, m_Lock ); + int numCheck = m_iklock.Count(); + + CUtlVector< virtualgeneric_t > iklock; + iklock = m_iklock; + + int j, k; + + for (j = 0; j < pStudioHdr->numlocalikautoplaylocks; j++) + { + int chain1 = pStudioHdr->pLocalIKAutoplayLock( j )->chain; + for (k = 0; k < numCheck; k++) + { + int chain2 = m_group[ iklock[k].group ].GetStudioHdr()->pLocalIKAutoplayLock( iklock[k].index )->chain; + + if (chain1 == chain2) + { + break; + } + } + // no duplication + if (k == numCheck) + { + MEM_ALLOC_CREDIT(); + + virtualgeneric_t tmp; + tmp.group = group; + tmp.index = j; + k = iklock.AddToTail( tmp ); + } + } + + m_iklock = iklock; + + // copy knee directions for uninitialized knees + if ( group != 0 ) + { + studiohdr_t *pBaseHdr = (studiohdr_t *)m_group[ 0 ].GetStudioHdr(); + if ( pStudioHdr->numikchains == pBaseHdr->numikchains ) + { + for (j = 0; j < pStudioHdr->numikchains; j++) + { + if ( pBaseHdr->pIKChain( j )->pLink(0)->kneeDir.LengthSqr() == 0.0f ) + { + if ( pStudioHdr->pIKChain( j )->pLink(0)->kneeDir.LengthSqr() > 0.0f ) + { + pBaseHdr->pIKChain( j )->pLink(0)->kneeDir = pStudioHdr->pIKChain( j )->pLink(0)->kneeDir; + } + } + } + } + } +} diff --git a/public/surfinfo.h b/public/surfinfo.h new file mode 100644 index 0000000..a4d4dba --- /dev/null +++ b/public/surfinfo.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef SURFINFO_H +#define SURFINFO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vplane.h" + +//#include "mathlib/vector.h" +#define MAX_SURFINFO_VERTS 16 +class SurfInfo +{ +public: + // Shape of the surface. + Vector m_Verts[ MAX_SURFINFO_VERTS ]; + unsigned long m_nVerts; + + // Plane of the surface. + VPlane m_Plane; + + // For engine use only.. + void *m_pEngineData; +}; + +#endif // SURFINFO_H diff --git a/public/texture_group_names.h b/public/texture_group_names.h new file mode 100644 index 0000000..92b3127 --- /dev/null +++ b/public/texture_group_names.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef TEXTURE_GROUP_NAMES_H +#define TEXTURE_GROUP_NAMES_H +#ifdef _WIN32 +#pragma once +#endif + +// These are given to FindMaterial to reference the texture groups that show up on the +#define TEXTURE_GROUP_LIGHTMAP "Lightmaps" +#define TEXTURE_GROUP_WORLD "World textures" +#define TEXTURE_GROUP_MODEL "Model textures" +#define TEXTURE_GROUP_VGUI "VGUI textures" +#define TEXTURE_GROUP_PARTICLE "Particle textures" +#define TEXTURE_GROUP_DECAL "Decal textures" +#define TEXTURE_GROUP_SKYBOX "SkyBox textures" +#define TEXTURE_GROUP_CLIENT_EFFECTS "ClientEffect textures" +#define TEXTURE_GROUP_OTHER "Other textures" +#define TEXTURE_GROUP_PRECACHED "Precached" // TODO: assign texture groups to the precached materials +#define TEXTURE_GROUP_CUBE_MAP "CubeMap textures" +#define TEXTURE_GROUP_RENDER_TARGET "RenderTargets" +#define TEXTURE_GROUP_RUNTIME_COMPOSITE "Runtime Composite" +#define TEXTURE_GROUP_UNACCOUNTED "Unaccounted textures" // Textures that weren't assigned a texture group. +//#define TEXTURE_GROUP_STATIC_VERTEX_BUFFER "Static Vertex" +#define TEXTURE_GROUP_STATIC_INDEX_BUFFER "Static Indices" +#define TEXTURE_GROUP_STATIC_VERTEX_BUFFER_DISP "Displacement Verts" +#define TEXTURE_GROUP_STATIC_VERTEX_BUFFER_COLOR "Lighting Verts" +#define TEXTURE_GROUP_STATIC_VERTEX_BUFFER_WORLD "World Verts" +#define TEXTURE_GROUP_STATIC_VERTEX_BUFFER_MODELS "Model Verts" +#define TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER "Other Verts" +#define TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER "Dynamic Indices" +#define TEXTURE_GROUP_DYNAMIC_VERTEX_BUFFER "Dynamic Verts" +#define TEXTURE_GROUP_DEPTH_BUFFER "DepthBuffer" +#define TEXTURE_GROUP_VIEW_MODEL "ViewModel" +#define TEXTURE_GROUP_PIXEL_SHADERS "Pixel Shaders" +#define TEXTURE_GROUP_VERTEX_SHADERS "Vertex Shaders" +#define TEXTURE_GROUP_RENDER_TARGET_SURFACE "RenderTarget Surfaces" +#define TEXTURE_GROUP_MORPH_TARGETS "Morph Targets" + +#endif // TEXTURE_GROUP_NAMES_H diff --git a/public/tier0/EventMasks.h b/public/tier0/EventMasks.h new file mode 100644 index 0000000..0185567 --- /dev/null +++ b/public/tier0/EventMasks.h @@ -0,0 +1,480 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#pragma once + +typedef union EVENT_MASK(TC_deliver_mode) +{ + struct + { + uint16 DD:1; // both logical processors in deliver mode }, + uint16 DB:1; // logical processor 0 in deliver mode, 1 in build mode }, + uint16 DI:1; // logical processor 0 in deliver mode, 1 is inactive }, + uint16 BD:1; // logical processor 0 in build mode, 1 in deliver mode }, + uint16 BB:1; // both logical processors in build mode }, + uint16 BI:1; // logical processor 0 in build mode, 1 is inactive }, + uint16 ID:1; // logical processor 0 is inactive, 1 in deliver mode }, + uint16 IB:1; // logical processor 0 is inactive, 1 in build mode } + }; + uint16 flat; +} EVENT_MASK(TC_deliver_mode); + +typedef union EVENT_MASK(BPU_fetch_request) +{ + + struct + { + uint16 TCMISS:1; // Trace cache lookup miss }, + }; + uint16 flat; +} EVENT_MASK(BPU_fetch_request); + + +typedef union EVENT_MASK(ITLB_reference) +{ + struct + { + uint16 HIT : 1; //ITLB hit }, + uint16 MISS : 1;//ITLB miss }, + uint16 HIT_UC :1; // Uncacheable ITLB hit } + }; + uint16 flat; +} EVENT_MASK(ITLB_reference); + +typedef union EVENT_MASK(memory_cancel) +{ + struct + { + uint16 dummy : 2; + + uint16 ST_RB_FULL:1; //Replayed because no store request buffer is available }, + uint16 _64K_CONF:1; //Conflicts due to 64K aliasing } + }; + uint16 flat; +}EVENT_MASK(memory_cancel); + +typedef union EVENT_MASK(memory_complete) +{ + struct + { + uint16 LSC:1; // Load split completed, excluding UC/WC loads }, + uint16 SSC:1; //Any split stores completed } } + }; + uint16 flat; +} EVENT_MASK(memory_complete); + +typedef union EVENT_MASK(load_port_replay) +{ + struct + { + uint16 dummy:1; + uint16 SPLIT_LD:1; //Split load } } + }; + uint16 flat; +} EVENT_MASK(load_port_replay); + +typedef union EVENT_MASK(store_port_replay) +{ + struct + { + uint16 dummy0:1; + uint16 SPLIT_ST:1; //Split store } } + + }; + uint16 flat; +} EVENT_MASK(store_port_replay); + +typedef union EVENT_MASK(MOB_load_replay) +{ + struct + { + uint16 dummy0:1; + + uint16 NO_STA:1; //Replayed because of unknown store address }, + + uint16 dummy2:1; + + uint16 NO_STD:1; //Replayed because of unknown store data }, + uint16 PARTIAL_DATA:1; //Replayed because of partially overlapped data access between the load and store operations }, + uint16 UNALGN_ADDR:1; //Replayed because the lower 4 bits of the linear address do not match between the load and store operations } } + }; + uint16 flat; +}EVENT_MASK(MOB_load_replay); + +typedef union EVENT_MASK(page_walk_type) +{ + struct + { + uint16 DTMISS:1; // Page walk for a data TLB miss }, + uint16 ITMISS:1; // Page walk for an instruction TLB miss } } + }; + uint16 flat; +}EVENT_MASK(page_walk_type); + + +typedef union EVENT_MASK(BSQ_cache_reference) +{ + struct + { + uint16 RD_2ndL_HITS:1; // Read 2nd level cache hit Shared }, + uint16 RD_2ndL_HITE:1; // Read 2nd level cache hit Exclusive }, + uint16 RD_2ndL_HITM:1; // Read 2nd level cache hit Modified }, + uint16 RD_3rdL_HITS:1; // Read 3rd level cache hit Shared }, + uint16 RD_3rdL_HITE:1; // Read 3rd level cache hit Exclusive }, + uint16 RD_3rdL_HITM:1; // Read 3rd level cache hit Modified }, + uint16 dummy6:1; + uint16 dummy7:1; + uint16 RD_2ndL_MISS:1; // Read 2nd level cache miss }, + uint16 RD_3rdL_MISS:1; // Read 3rd level cache miss }, + uint16 WR_2ndL_MISS:1; // Writeback lookup from DAC misses the 2nd level cache } } + }; + uint16 flat; +} EVENT_MASK(BSQ_cache_reference) ; + +typedef union EVENT_MASK(IOQ) +{ + struct + { + uint16 bit0:1; // bus request type (use 00001 for invalid or default) + uint16 bit1:1; // + uint16 bit2:1; // + uint16 bit3:1; // + uint16 bit4:1; // + uint16 ALL_READ:1; // Count read entries }, + uint16 ALL_WRITE:1; // Count write entries }, + uint16 MEM_UC:1; // Count UC memory access entries }, + uint16 MEM_WC:1; // Count WC memory access entries }, + uint16 MEM_WT:1; // Count WT memory access entries }, + uint16 MEM_WP:1; // Count WP memory access entries }, + uint16 MEM_WB:1; // Count WB memory access entries }, + uint16 dummy12:1; + + uint16 OWN:1; // Count own store requests }, + uint16 OTHER:1; // Count other and DMA store requests }, + uint16 PREFETCH:1; // Include HW and SW prefetch requests } } + }; + uint16 flat; +} EVENT_MASK(IOQ) ; + +typedef union EVENT_MASK(FSB_data_activity) +{ + struct + { + /* DRDY_OWN is mutually exclusive with DRDY_OTHER */ + /* DBSY_OWN is mutually exclusive with DBSY_OTHER */ + uint16 DRDY_DRV:1; // Count when this processor drives data onto the bus }, + uint16 DRDY_OWN:1; // Count when this processor reads data from the bus }, + uint16 DRDY_OTHER:1; // Count when data is on the bus but not being sampled by the processor }, + uint16 DBSY_DRV:1; // Count when this processor reserves the bus for driving data }, + uint16 DBSY_OWN:1; // Count when this processor reserves the bus for sampling data }, + uint16 DBSY_OTHER:1; // Count when the bus is reserved for driving data this processor will not sample } } + }; + uint16 flat; +}EVENT_MASK(FSB_data_activity); + +typedef union EVENT_MASK(BSQ) +{ + struct + { + uint16 REQ_TYPE0:1; // Request type encoding bit 0 }, + uint16 REQ_TYPE1:1; // Request type encoding bit 1 }, + uint16 REQ_LEN0:1; // Request length encoding bit 0 }, + uint16 REQ_LEN1:1; // Request length encoding bit 1 }, + uint16 dummy4: 1; + uint16 REQ_IO_TYPE:1; // Request type is input or output }, + uint16 REQ_LOCK_TYPE:1; // Request type is bus lock }, + uint16 REQ_CACHE_TYPE:1; // Request type is cacheable }, + uint16 REQ_SPLIT_TYPE:1; // Request type is a bus 8-byte chunk split across 8-byte boundary }, + uint16 REQ_DEM_TYPE:1; // Request type is a demand (1) or prefetch (0) }, + uint16 REQ_ORD_TYPE:1; // Request is an ordered type }, + uint16 MEM_TYPE0:1; // Memory type encoding bit 0 }, + uint16 MEM_TYPE1:1; // Memory type encoding bit 1 }, + uint16 MEM_TYPE2:1; // Memory type encoding bit 2 } } + }; + uint16 flat; +} EVENT_MASK(BSQ); + +typedef union EVENT_MASK(firm_uop) +{ + struct + { + uint16 dummy15 : 15; + uint16 ALL:1; // count all uops of this type } } + }; + uint16 flat; +} EVENT_MASK(firm_uop); + + + +typedef union EVENT_MASK(TC_misc) +{ + struct + { + uint16 dymmy4 : 4; + uint16 FLUSH:1; // Number of flushes } } + }; + uint16 flat; +} EVENT_MASK(TC_misc); + +typedef union EVENT_MASK(global_power_events) +{ + struct + { + uint16 Running:1; // The processor is active } } + }; + uint16 flat; +} EVENT_MASK(global_power_events); + +typedef union EVENT_MASK(tc_ms_xfer) +{ + struct + { + uint16 CISC:1; // A TC to MS transfer ocurred } } + }; + uint16 flat; +}EVENT_MASK(tc_ms_xfer); + + + +typedef union EVENT_MASK(uop_queue_writes) +{ + struct + { + uint16 FROM_TC_BUILD:1; // uops written from TC build mode + uint16 FROM_TC_DELIVER:1; // uops written from TC deliver mode + uint16 FROM_ROM:1; // uops written from microcode ROM } } + }; + uint16 flat; +} EVENT_MASK(uop_queue_writes); + +typedef union EVENT_MASK(branch_type) +{ + struct + { + uint16 dummy : 1; + uint16 CONDITIONAL:1; // Conditional jumps + uint16 CALL:1; // Direct or indirect call + uint16 RETURN:1; // Return branches + uint16 INDIRECT:1; // Returns, indirect calls, or indirect jumps + }; + uint16 flat; +} EVENT_MASK(branch_type); + + + +typedef union EVENT_MASK(resource_stall) +{ + struct + { + uint16 dummy1 : 5; + uint16 SBFULL:1; // A Stall due to lack of store buffers } } + }; + uint16 flat; +} EVENT_MASK(resource_stall); + + + + +typedef union EVENT_MASK(WC_Buffer) +{ + struct + { + uint16 WCB_EVICTS : 1; // all causes }, + uint16 WCB_FULL_EVICT : 1; // no WC buffer is available }, + /* XXX: 245472-011 no longer lists bit 2, but that looks like + a table formatting error. Keeping it for now. */ + uint16 WCB_HITM_EVICT : 1; // store encountered a Hit Modified condition } } + }; + uint16 flat; +} EVENT_MASK(WC_Buffer); + + +typedef union EVENT_MASK(b2b_cycles) +{ + struct + { + uint16 dummy0 : 1; + uint16 bit1 : 1; // + uint16 bit2 : 1; // + uint16 bit3 : 1; // + uint16 bit4 : 1; // + uint16 bit5 : 1; // + uint16 bit6 : 1; // + + }; + uint16 flat; +} EVENT_MASK(b2b_cycles); + +typedef union EVENT_MASK(bnr) +{ + struct + { + uint16 bit0:1; // + uint16 bit1:1; // + uint16 bit2:1; // + }; + uint16 flat; +} EVENT_MASK(bnr); + + +typedef union EVENT_MASK(snoop) +{ + struct + { + uint16 dummy0 : 1; + uint16 dummy1 : 1; + + uint16 bit2:1; // + uint16 dummy3:1; // + uint16 dummy4:1; // + uint16 dummy5:1; // + uint16 bit6:1; // + uint16 bit7:1; // + }; + uint16 flat; +} EVENT_MASK(snoop); + + +typedef union EVENT_MASK(response) +{ + struct + { + uint16 dummy0:1; // + uint16 bit1:1; // + uint16 bit2:1; // + uint16 dummy3:1; // + uint16 dummy4:1; // + uint16 dummy5:1; // + uint16 dummy6:1; // + uint16 dummy7:1; // + uint16 bit8:1; // + uint16 bit9:1; // + }; + uint16 flat; +} EVENT_MASK(response); + + +typedef union EVENT_MASK(nbogus_bogus) +{ + struct + { + uint16 NBOGUS:1; // The marked uops are not bogus + uint16 BOGUS:1; // The marked uops are bogus + }; + uint16 flat; +} EVENT_MASK(nbogus_bogus); + + +typedef union EVENT_MASK(execution_event) +{ + struct + { + uint16 NBOGUS0:1; // non-bogus uops with tag bit 0 set }, + uint16 NBOGUS1:1; // non-bogus uops with tag bit 1 set }, + uint16 NBOGUS2:1; // non-bogus uops with tag bit 2 set }, + uint16 NBOGUS3:1; // non-bogus uops with tag bit 3 set }, + uint16 BOGUS0:1; // bogus uops with tag bit 0 set }, + uint16 BOGUS1:1; // bogus uops with tag bit 1 set }, + uint16 BOGUS2:1; // bogus uops with tag bit 2 set }, + uint16 BOGUS3:1; // bogus uops with tag bit 3 set } } + }; + uint16 flat; +}EVENT_MASK(execution_event); + +typedef union EVENT_MASK(instr_retired) +{ + struct + { + uint16 NBOGUSNTAG:1; // Non-bogus instructions that are not tagged }, + uint16 NBOGUSTAG:1; // Non-bogus instructions that are tagged }, + uint16 BOGUSNTAG:1; // Bogus instructions that are not tagged }, + uint16 BOGUSTAG:1; // Bogus instructions that are tagged } } + }; + uint16 flat; +} EVENT_MASK(instr_retired); + + +typedef union EVENT_MASK(uop_type) +{ + struct + { + uint16 dummy0 : 1; + uint16 TAGLOADS:1; // The uop is a load operation }, + uint16 TAGSTORES:1; // The uop is a store operation } } + }; + uint16 flat; +} EVENT_MASK(uop_type); + +typedef union EVENT_MASK(branch_retired) +{ + struct + { + uint16 MMNP:1; // Branch Not-taken Predicted + uint16 MMNM:1; // Branch Not-taken Mispredicted + uint16 MMTP:1; // Branch Taken Predicted + uint16 MMTM:1; // Branch Taken Mispredicted + }; + uint16 flat; +} EVENT_MASK(branch_retired); + +typedef union EVENT_MASK(mispred_branch_retired) +{ + struct + { + uint16 NBOGUS:1; // The retired branch is not bogus } } + }; + uint16 flat; +} EVENT_MASK(mispred_branch_retired); + + +typedef union EVENT_MASK(x87_assist) +{ + struct + { + uint16 FPSU:1; // FP stack underflow }, + uint16 FPSO:1; // FP stack overflow }, + uint16 POAO:1; // x87 output overflow }, + uint16 POAU:1; // x87 output underflow }, + uint16 PREA:1; // x87 input assist } } + }; + uint16 flat; +}EVENT_MASK(x87_assist); + +typedef union EVENT_MASK(machine_clear) +{ + struct + { + uint16 CLEAR:1; // Count a portion of the cycles when the machine is cleared }, + uint16 dummy1: 1; + uint16 MOCLEAR:1; // Count clears due to memory ordering issues }, + uint16 dummy3: 1; + uint16 dummy4: 1; + uint16 dummy5: 1; + + uint16 SMCLEAR:1;// Count clears due to self-modifying code issues } } + }; + uint16 flat; +} EVENT_MASK(machine_clear); + + +typedef union EVENT_MASK(x87_SIMD_moves_uop) +{ + struct + { + uint16 dummy3:3; + uint16 ALLP0:1; // Count all x87/SIMD store/move uops }, + uint16 ALLP2:1; // count all x87/SIMD load uops } } + }; + uint16 flat; +} EVENT_MASK(x87_SIMD_moves_uop); + + + + + + + diff --git a/public/tier0/EventModes.h b/public/tier0/EventModes.h new file mode 100644 index 0000000..b6b9756 --- /dev/null +++ b/public/tier0/EventModes.h @@ -0,0 +1,1787 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef EVENTMODES_H +#define EVENTMODES_H + + +#pragma once + +/* + + + + Event Modes to choose from: + + P4Event_TC_deliver_mode + + P4Event_BPU_fetch_request + + P4Event_ITLB_reference + + P4Event_memory_cancel + + P4Event_memory_complete + + P4Event_load_port_replay + + P4Event_store_port_replay + + P4Event_MOB_load_replay + + P4Event_page_walk_type + + P4Event_BSQ_cache_reference + + P4Event_IOQ_allocation + + P4Event_IOQ_active_entries + + P4Event_FSB_data_activity + + P4Event_BSQ_allocation + + P4Event_BSQ_active_entries + + P4Event_SSE_input_assist + + P4Event_packed_SP_uop + + P4Event_packed_DP_uop + + P4Event_scalar_SP_uop + + P4Event_scalar_DP_uop + + P4Event_64bit_MMX_uop + + P4Event_128bit_MMX_uop + + P4Event_x87_FP_uop + + P4Event_x87_SIMD_moves_uop + + P4Event_TC_misc + + P4Event_global_power_events + + P4Event_tc_ms_xfer + + P4Event_uop_queue_writes + + P4Event_retired_mispred_branch_type + + P4Event_retired_branch_type + + P4Event_resource_stall + + P4Event_WC_Buffer + + P4Event_b2b_cycles + + P4Event_bnr + + P4Event_snoop + + P4Event_response + + P4Event_front_end_event + + P4Event_execution_event + + P4Event_replay_event + + P4Event_instr_retired + + P4Event_uops_retired + + P4Event_uop_type + + P4Event_branch_retired + + P4Event_mispred_branch_retired + + P4Event_x87_assist + + P4Event_machine_clear + + +*/ + + + +class P4P4Event_TC_deliver_mode: public P4BaseEvent +{ +public: + EVENT_MASK(TC_deliver_mode) * eventMask; + + P4P4Event_TC_deliver_mode() + { + eventMask = (EVENT_MASK(TC_deliver_mode) *)&m_eventMask; + + escr.ESCREventSelect = 0x01; + cccr.CCCRSelect = 0x01; + //// eventType = EVENT_TYPE(TC_deliver_mode); + description = _T("TC_deliver_mode"); + UseCounter4(); + } + + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; + +class P4P4Event_BPU_fetch_request: public P4BaseEvent + +{ +public: + EVENT_MASK(BPU_fetch_request)* eventMask; + + P4P4Event_BPU_fetch_request() + { + eventMask = (EVENT_MASK(BPU_fetch_request) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x00; + // eventType = EVENT_TYPE(BPU_fetch_request); + description=_T("BPU_fetch_request"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } + +}; +class P4P4Event_ITLB_reference: public P4BaseEvent + +{ +public: + EVENT_MASK(ITLB_reference) * eventMask; + + P4P4Event_ITLB_reference() + { + eventMask = (EVENT_MASK(ITLB_reference) *)&m_eventMask; + + escr.ESCREventSelect= 0x18; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(ITLB_reference); + description=_T("ITLB_reference"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_memory_cancel: public P4BaseEvent + +{ +public: + EVENT_MASK(memory_cancel) * eventMask; + + P4Event_memory_cancel() + { + eventMask = (EVENT_MASK(memory_cancel) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(memory_cancel); + description=_T("memory_cancel"); + UseCounter8(); + } + + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_memory_complete: public P4BaseEvent + +{ +public: + EVENT_MASK(memory_complete) * eventMask; + + P4Event_memory_complete() + { + eventMask = (EVENT_MASK(memory_complete) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(memory_complete); + description=_T("memory_complete"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_load_port_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(load_port_replay) * eventMask; + + P4Event_load_port_replay() + { + eventMask = (EVENT_MASK(load_port_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(load_port_replay); + description=_T("load_port_replay"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_store_port_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(store_port_replay) * eventMask; + + P4Event_store_port_replay() + { + eventMask = (EVENT_MASK(store_port_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(store_port_replay); + description=_T("store_port_replay"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_MOB_load_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(MOB_load_replay) * eventMask; + + P4Event_MOB_load_replay() + { + eventMask = (EVENT_MASK(MOB_load_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(MOB_load_replay); + description=_T("MOB_load_replay"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_page_walk_type: public P4BaseEvent + +{ +public: + EVENT_MASK(page_walk_type) * eventMask; + + P4Event_page_walk_type() + { + eventMask = (EVENT_MASK(page_walk_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(page_walk_type); + description=_T("page_walk_type"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_BSQ_cache_reference: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ_cache_reference) * eventMask; + + P4Event_BSQ_cache_reference() + { + eventMask = (EVENT_MASK(BSQ_cache_reference) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ_cache_reference); + description=_T("BSQ_cache_reference"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_IOQ_allocation: public P4BaseEvent + +{ +public: + EVENT_MASK(IOQ) * eventMask; + + P4Event_IOQ_allocation() + { + eventMask = (EVENT_MASK(IOQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(IOQ); + description=_T("IOQ_allocation"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_IOQ_active_entries: public P4BaseEvent + +{ +public: + EVENT_MASK(IOQ) * eventMask; + + P4Event_IOQ_active_entries() + { + eventMask = (EVENT_MASK(IOQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x1A; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(IOQ); + description=_T("IOQ_active_entries"); + UseCounter2(); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_FSB_data_activity: public P4BaseEvent + +{ +public: + EVENT_MASK(FSB_data_activity) * eventMask; + + P4Event_FSB_data_activity() + { + eventMask = (EVENT_MASK(FSB_data_activity) *)&m_eventMask; + + escr.ESCREventSelect= 0x17; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(FSB_data_activity); + description=_T("FSB_data_activity"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_BSQ_allocation: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ) * eventMask; + + P4Event_BSQ_allocation() + { + eventMask = (EVENT_MASK(BSQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ); + description=_T("BSQ_allocation"); + UseCounter0(); + } + + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + + } +}; +class P4Event_BSQ_active_entries: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ) * eventMask; + + P4Event_BSQ_active_entries() + { + eventMask = (EVENT_MASK(BSQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ); + description=_T("bsq_active_entries"); + UseCounter2(); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_SSE_input_assist: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_SSE_input_assist() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x34; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("SSE_input_assist"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_packed_SP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_packed_SP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("packed_SP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_packed_DP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_packed_DP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("packed_DP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_scalar_SP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_scalar_SP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0A; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("scalar_SP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_scalar_DP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_scalar_DP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0E; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("scalar_DP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_64bit_MMX_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_64bit_MMX_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("64bit_MMX_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_128bit_MMX_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_128bit_MMX_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x1A; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("128bit_MMX_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_x87_FP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_x87_FP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("x87_FP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_x87_SIMD_moves_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(x87_SIMD_moves_uop) * eventMask; + + P4Event_x87_SIMD_moves_uop() + { + eventMask = (EVENT_MASK(x87_SIMD_moves_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x2E; + cccr.CCCRSelect= 0; + // eventType=EVENT_TYPE(x87_SIMD_moves_uop); + description=_T("x87_SIMD_moves_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_TC_misc: public P4BaseEvent + +{ +public: + EVENT_MASK(TC_misc) * eventMask; + + P4Event_TC_misc() + { + eventMask = (EVENT_MASK(TC_misc) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(TC_misc); + description=_T("TC_misc"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_global_power_events: public P4BaseEvent + +{ +public: + EVENT_MASK(global_power_events) * eventMask; + + P4Event_global_power_events() + { + eventMask = (EVENT_MASK(global_power_events) *)&m_eventMask; + + escr.ESCREventSelect= 0x13; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(global_power_events); + description=_T("global_power_events"); + UseCounter0(); + } + + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_tc_ms_xfer: public P4BaseEvent + +{ +public: + EVENT_MASK(tc_ms_xfer) * eventMask; + + P4Event_tc_ms_xfer() + { + eventMask = (EVENT_MASK(tc_ms_xfer) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x00; + // eventType=EVENT_TYPE(tc_ms_xfer); + description=_T("tc_ms_xfer"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_uop_queue_writes: public P4BaseEvent + +{ +public: + EVENT_MASK(uop_queue_writes) * eventMask; + + P4Event_uop_queue_writes() + { + eventMask = (EVENT_MASK(uop_queue_writes) *)&m_eventMask; + + escr.ESCREventSelect= 0x09; + cccr.CCCRSelect= 0x00; + // eventType=EVENT_TYPE(uop_queue_writes); + description=_T("uop_queue_writes"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_retired_mispred_branch_type: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_type) * eventMask; + + P4Event_retired_mispred_branch_type() + { + eventMask = (EVENT_MASK(branch_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(branch_type); + description=_T("retired_mispred_branch_type"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_retired_branch_type: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_type) * eventMask; + + P4Event_retired_branch_type() + { + eventMask = (EVENT_MASK(branch_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(branch_type); + description=_T("retired_branch_type"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_resource_stall: public P4BaseEvent + +{ +public: + EVENT_MASK(resource_stall) * eventMask; + + P4Event_resource_stall() + { + eventMask = (EVENT_MASK(resource_stall) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(resource_stall); + description=_T("resource_stall"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } + +}; +class P4Event_WC_Buffer: public P4BaseEvent + +{ +public: + EVENT_MASK(WC_Buffer) * eventMask; + + P4Event_WC_Buffer() + { + eventMask = (EVENT_MASK(WC_Buffer) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(WC_Buffer); + description=_T("WC_Buffer"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_b2b_cycles: public P4BaseEvent + +{ +public: + EVENT_MASK(b2b_cycles) * eventMask; + + P4Event_b2b_cycles() + { + eventMask = (EVENT_MASK(b2b_cycles) *)&m_eventMask; + + escr.ESCREventSelect= 0x16; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(b2b_cycles); + description=_T("b2b_cycles"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_bnr: public P4BaseEvent + +{ +public: + EVENT_MASK(bnr) * eventMask; + + P4Event_bnr() + { + eventMask = (EVENT_MASK(bnr) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(bnr); + description=_T("bnr"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_snoop: public P4BaseEvent + +{ +public: + EVENT_MASK(snoop) * eventMask; + + P4Event_snoop() + { + eventMask = (EVENT_MASK(snoop) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(snoop); + description=_T("snoop"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_response: public P4BaseEvent + +{ +public: + EVENT_MASK(response) * eventMask; + + P4Event_response() + { + eventMask = (EVENT_MASK(response) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(response); + description=_T("response"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_front_end_event: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_front_end_event() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("front_end_event"); + UseCounter12(); + } + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_execution_event: public P4BaseEvent + +{ +public: + EVENT_MASK(execution_event) * eventMask; + + P4Event_execution_event() + { + eventMask = (EVENT_MASK(execution_event) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(execution_event); + description=_T("execution_event"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_replay_event: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_replay_event() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x09; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("replay_event"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_instr_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(instr_retired) * eventMask; + + P4Event_instr_retired() + { + eventMask = (EVENT_MASK(instr_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(instr_retired); + description=_T("instr_retired"); + UseCounter12(); + } + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_uops_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_uops_retired() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("uops_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_uop_type: public P4BaseEvent + +{ +public: + EVENT_MASK(uop_type) * eventMask; + + P4Event_uop_type() + { + eventMask = (EVENT_MASK(uop_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(uop_type); + description=_T("uop_type"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_branch_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_retired) * eventMask; + + P4Event_branch_retired() + { + eventMask = (EVENT_MASK(branch_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(branch_retired); + description=_T("branch_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_mispred_branch_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(mispred_branch_retired) * eventMask; + + P4Event_mispred_branch_retired() + { + eventMask = (EVENT_MASK(mispred_branch_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(mispred_branch_retired); + description=_T("mispred_branch_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_x87_assist: public P4BaseEvent + +{ +public: + EVENT_MASK(x87_assist) * eventMask; + + P4Event_x87_assist() + { + eventMask = (EVENT_MASK(x87_assist) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(x87_assist); + description=_T("x87_assist"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_machine_clear: public P4BaseEvent + +{ +public: + EVENT_MASK(machine_clear) * eventMask; + + P4Event_machine_clear() + { + eventMask = (EVENT_MASK(machine_clear) *)&m_eventMask; + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(machine_clear); + description=_T("machine_clear"); + UseCounter12(); + } + + + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } + +}; + +#endif // EVENTMODES_H diff --git a/public/tier0/IOCTLCodes.h b/public/tier0/IOCTLCodes.h new file mode 100644 index 0000000..a8f50d0 --- /dev/null +++ b/public/tier0/IOCTLCodes.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef IOCTLCODES_H +#define IOCTLCODES_H +#pragma once + +// Define the IOCTL codes we will use. The IOCTL code contains a command +// identifier, plus other information about the device, the type of access +// with which the file must have been opened, and the type of buffering. + +// Device type -- in the "User Defined" range." +#define DEVICE_FILE_TYPE 40000 + + +// The IOCTL function codes from 0x800 to 0xFFF are for customer use. + +#define IOCTL_WRITE_MSR \ + CTL_CODE( DEVICE_FILE_TYPE, 0x900, METHOD_BUFFERED, FILE_READ_ACCESS ) + +#define IOCTL_READ_MSR \ + CTL_CODE( DEVICE_FILE_TYPE, 0x901, METHOD_BUFFERED, FILE_READ_ACCESS ) + + +#endif IOCTLCODES_H diff --git a/public/tier0/K8PerformanceCounters.h b/public/tier0/K8PerformanceCounters.h new file mode 100644 index 0000000..4367dff --- /dev/null +++ b/public/tier0/K8PerformanceCounters.h @@ -0,0 +1,2032 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef K8PERFORMANCECOUNTERS_H +#define K8PERFORMANCECOUNTERS_H + +/* + * AMD K8 events. + * + */ + + + +typedef union EVENT_MASK(NULL_MASK) +{ + // no tests defined + uint16 flat; +} EVENT_MASK(NULL_MASK); + + +#define MSR_K8_EVNTSEL0 0xC0010000 /* .. 0xC0010003 */ +#define MSR_K8_PERFCTR0 0xC0010004 /* .. 0xC0010007 */ + +# pragma pack(push, 1) + + + +// access to these bits is through the methods +typedef union PerfEvtSel +{ + struct + { + uint64 EventMask : 8; + + uint64 UnitMask : 8; + uint64 USR : 1; + uint64 OS : 1; + uint64 Edge : 1; + uint64 PC : 1; + uint64 INTAPIC : 1; + uint64 Reserved21 : 1; + uint64 Enable : 1; + uint64 Complement : 1; // aka INV + uint64 Threshold : 8; // aka CounterMask + uint64 Reserver32 : 32; + }; + uint64 flat; + +} PerfEvtSel; + + +enum UnitEncode +{ + FP, + LS, + DC, + BU, + IC, + UE_Unknown, + FR, + NB +}; + +# pragma pack(pop) + +// Turn off the no return value warning in ReadCounter. +#pragma warning( disable : 4035 ) +#define k8NUM_COUNTERS 4 +class k8BaseEvent +{ +public: + + PME * pme; + + PerfEvtSel eventSelect[k8NUM_COUNTERS]; + + unsigned short m_eventMask; + int event_id; + tchar * name; + tchar revRequired; + int eventSelectNum; + UnitEncode unitEncode; + + + void SetCounter(int n) + { + if (n < 0) + n = 0; + else if (n > 3) + n = 3; + eventSelectNum = n; + + } + k8BaseEvent() + { + pme = PME::Instance(); + + for(int i = 0; i< k8NUM_COUNTERS; i++) + { + eventSelect[i].flat = 0; + + } + eventSelectNum = 0; + + m_eventMask = 0; + event_id = 0; + name = 0; + revRequired = 'A'; + + + } + + void SetCaptureMode(PrivilegeCapture priv) + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + StopCounter(); + + switch (priv) + { + case OS_Only: + select.USR = 0; + select.OS = 1; + break; + + case USR_Only: + select.USR = 1; + select.OS = 0; + break; + + case OS_and_USR: + select.USR = 1; + select.OS = 1; + break; + } + + + select.UnitMask = m_eventMask; + select.EventMask = event_id; + + + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + pme->WriteMSR(selectPort, select.flat); + } + + + void SetFiltering(CompareState compareEnable, + CompareMethod compareMethod, + uint8 threshold, + EdgeState edgeEnable) + { + + PerfEvtSel & select = eventSelect[eventSelectNum]; + + StopCounter(); + + if (compareEnable == CompareDisable) + select.Threshold = 0; + else + select.Threshold = threshold; + + select.Complement = compareMethod; + + select.Edge = edgeEnable; + + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + pme->WriteMSR(selectPort, select.flat); + + + } + + + void StartCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + + select.Enable = 1; + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + + pme->WriteMSR(selectPort, select.flat); + + } + void StopCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + select.Enable = 0; + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + + pme->WriteMSR(selectPort, select.flat); + } + + + + void ClearCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + + int counterPort = MSR_K8_PERFCTR0 + eventSelectNum; + + pme->WriteMSR(counterPort, 0ui64 ); // clear + } + + void WriteCounter(int64 value) + { + + PerfEvtSel & select = eventSelect[eventSelectNum]; + + int counterPort = MSR_K8_PERFCTR0 + eventSelectNum; + pme->WriteMSR(counterPort, value); // clear + } + + int64 ReadCounter() + { + +#if PME_DEBUG + PerfEvtSel & select = eventSelect[eventSelectNum]; + + if (select.USR == 0 && select.OS == 0) + return -1; // no area to collect, use SetCaptureMode + + if (select.EventMask == 0) + return -2; // no event mask set + + if (eventSelectNum < 0 || eventSelectNum > 3) + return -3; // counter not legal + + // check revision + +#endif + + // ReadMSR should work here too, but RDPMC should be faster + //ReadMSR(counterPort, int64); + + // we need to copy this into a temp for some reason +#ifdef COMPILER_MSVC64 + return __readpmc((unsigned long) eventSelectNum); +#else + int temp = eventSelectNum; + _asm + { + mov ecx, temp + RDPMC + } +#endif + + } + + +}; +#pragma warning( default : 4035 ) + + + + +typedef union EVENT_MASK(k8_dispatched_fpu_ops) +{ + // event 0 + struct + { + uint16 AddPipeOps:1; // Add pipe ops excluding junk ops" }, + uint16 MulPipeOps:1; // Multiply pipe ops excluding junk ops" },, + uint16 StoreOps:1; // Store pipe ops excluding junk ops" }, + uint16 AndPipeOpsJunk:1; // Add pipe junk ops" },, + uint16 MulPipeOpsJunk:1; // Multiply pipe junk ops" }, + uint16 StoreOpsJunk:1; // Store pipe junk ops" } } + }; + uint16 flat; +} EVENT_MASK(k8_dispatched_fpu_ops); + +class k8Event_DISPATCHED_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_DISPATCHED_FPU_OPS() + { + eventMask = (EVENT_MASK(k8_dispatched_fpu_ops) *)&m_eventMask; + + event_id = 0x00; + unitEncode = FP; + name = _T("Dispatched FPU ops"); + revRequired = 'B'; + } + EVENT_MASK(k8_dispatched_fpu_ops) * eventMask; + +}; + +////////////////////////////////////////////////////////// + + + +class k8Event_NO_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_NO_FPU_OPS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x01; + unitEncode = FP; + + name = _T("Cycles with no FPU ops retired"); + revRequired = 'B'; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +////////////////////////////////////////////////////////// + +class k8Event_FAST_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_FAST_FPU_OPS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x02; + unitEncode = FP; + + name = _T("Dispatched FPU ops that use the fast flag interface"); + revRequired = 'B'; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +////////////////////////////////////////////////////////// + + +typedef union EVENT_MASK(k8_segment_register_load) +{ + + struct + { + uint16 ES:1; + uint16 CS:1; + uint16 SS:1; + uint16 DS:1; + uint16 FS:1; + uint16 GS:1; + uint16 HS:1; + }; + uint16 flat; +} EVENT_MASK(k8_segment_register_load); + + +class k8Event_SEG_REG_LOAD : public k8BaseEvent +{ +public: + + k8Event_SEG_REG_LOAD() + { + eventMask = (EVENT_MASK(k8_segment_register_load) *)&m_eventMask; + name = _T("Segment register load"); + event_id = 0x20; + unitEncode = LS; + + } + EVENT_MASK(k8_segment_register_load) * eventMask; + +}; + + +class k8Event_SELF_MODIFY_RESYNC : public k8BaseEvent +{ +public: + + k8Event_SELF_MODIFY_RESYNC() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural resync caused by self modifying code"); + event_id = 0x21; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; +class k8Event_LS_RESYNC_BY_SNOOP : public k8BaseEvent +{ +public: + + k8Event_LS_RESYNC_BY_SNOOP() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x22; + unitEncode = LS; + + name = _T("Microarchitectural resync caused by snoop"); + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; +class k8Event_LS_BUFFER_FULL : public k8BaseEvent +{ +public: + + k8Event_LS_BUFFER_FULL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("LS Buffer 2 Full"); + event_id = 0x23; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +typedef union EVENT_MASK(k8_locked_op) +{ + + + struct + { + uint16 NumLockInstr : 1; //Number of lock instructions executed + uint16 NumCyclesInRequestGrant : 1; //Number of cycles spent in the lock request/grant stage + + uint16 NumCyclesForLock:1; + /*Number of cycles a lock takes to complete once it is + non-speculative and is the oldest load/store operation + (non-speculative cycles in Ls2 entry 0)*/ + + + }; + uint16 flat; + + +} EVENT_MASK(k8_locked_op); + + + +class k8Event_LOCKED_OP : public k8BaseEvent +{ +public: + + EVENT_MASK(k8_locked_op) * eventMask; + + k8Event_LOCKED_OP() + { + eventMask = (EVENT_MASK(k8_locked_op) *)&m_eventMask; + name = _T("Locked operation"); + event_id = 0x24; + unitEncode = LS; + + revRequired = 'C'; + } + + +}; + +class k8Event_OP_LATE_CANCEL : public k8BaseEvent +{ +public: + + k8Event_OP_LATE_CANCEL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural late cancel of an operation"); + event_id = 0x25; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("OP_LATE_CANCEL"); + + +}; +class k8Event_CFLUSH_RETIRED : public k8BaseEvent +{ +public: + + k8Event_CFLUSH_RETIRED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired CFLUSH instructions"); + event_id = 0x26; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CFLUSH_RETIRED"); + + +}; +class k8Event_CPUID_RETIRED : public k8BaseEvent +{ +public: + + k8Event_CPUID_RETIRED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired CPUID instructions"); + event_id = 0x27; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CPUID_RETIRED"); + + +}; + +typedef union EVENT_MASK( k8_cache) +{ + + struct + { + uint16 Invalid:1; + uint16 Exclusive:1; + uint16 Shared:1; + uint16 Owner:1; + uint16 Modified:1; + }; + uint16 flat; + +}EVENT_MASK( k8_cache); + /* 0x40-0x47: from K7 official event set */ + + +class k8Event_DATA_CACHE_ACCESSES : public k8BaseEvent +{ + k8Event_DATA_CACHE_ACCESSES() + { + + event_id = 0x40; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //_T("DATA_CACHE_ACCESSES"), + name = _T("Data cache accesses"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +class k8Event_DATA_CACHE_MISSES : public k8BaseEvent +{ + k8Event_DATA_CACHE_MISSES() + { + + event_id = 0x41; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //_T("DATA_CACHE_MISSES"), + name = _T("Data cache misses"); + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_DATA_CACHE_REFILLS_FROM_L2 : public k8BaseEvent +{ + k8Event_DATA_CACHE_REFILLS_FROM_L2() + { + + event_id = 0x42; + unitEncode = DC; + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + + name = _T("Data cache refills from L2"); + } + EVENT_MASK(k8_cache) * eventMask; + +}; + +class k8Event_DATA_CACHE_REFILLS_FROM_SYSTEM : public k8BaseEvent +{ + k8Event_DATA_CACHE_REFILLS_FROM_SYSTEM() + { + + event_id = 0x43; + unitEncode = DC; + + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + //UM(k7_um_moesi), + //_T("DATA_CACHE_REFILLS_FROM_SYSTEM"), + name = _T("Data cache refills from system"); + } + EVENT_MASK(k8_cache) * eventMask; + +}; + +class k8Event_DATA_CACHE_WRITEBACKS : public k8BaseEvent +{ + k8Event_DATA_CACHE_WRITEBACKS() + { + + event_id = 0x44; + unitEncode = DC; + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + //UM(k7_um_moesi), + //_T("DATA_CACHE_WRITEBACKS"), + name = _T("Data cache writebacks"); + } + EVENT_MASK(k8_cache) * eventMask; + + +}; + +class k8Event_L1_DTLB_MISSES_AND_L2_DTLB_HITS : public k8BaseEvent +{ + k8Event_L1_DTLB_MISSES_AND_L2_DTLB_HITS() + { + + event_id = 0x45; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("L1 DTLB misses and L2 DTLB hits"); + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; + +class k8Event_L1_AND_L2_DTLB_MISSES : public k8BaseEvent +{ + k8Event_L1_AND_L2_DTLB_MISSES() + { + + event_id = 0x46; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("L1 and L2 DTLB misses") ; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +class k8Event_MISALIGNED_DATA_REFERENCES : public k8BaseEvent +{ + k8Event_MISALIGNED_DATA_REFERENCES() + { + + event_id = 0x47; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //NULL, _T("MISALIGNED_DATA_REFERENCES"), + name = _T("Misaligned data references"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + + +class k8Event_ACCESS_CANCEL_LATE : public k8BaseEvent +{ +public: + + k8Event_ACCESS_CANCEL_LATE() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural late cancel of an access"); + event_id = 0x48; + unitEncode = DC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("ACCESS_CANCEL_LATE"); + + +}; +class k8Event_ACCESS_CANCEL_EARLY : public k8BaseEvent +{ +public: + + k8Event_ACCESS_CANCEL_EARLY() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural early cancel of an access"); + event_id = 0x49; + unitEncode = DC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("ACCESS_CANCEL_EARLY"); + + +}; +typedef union EVENT_MASK( k8_ecc) +{ + struct + { + uint16 ScrubberError : 1; // Scrubber error" }, + uint16 PiggybackScrubberErrors : 1; // Piggyback scrubber errors" } } + }; + uint16 flat; + +}EVENT_MASK( k8_ecc); + + +class k8Event_ECC_BIT_ERR : public k8BaseEvent +{ +public: + + k8Event_ECC_BIT_ERR() + { + eventMask = (EVENT_MASK(k8_ecc) *)&m_eventMask; + name = _T("One bit ECC error recorded found by scrubber"); + event_id = 0x4A; + unitEncode = DC; + + } + EVENT_MASK(k8_ecc) * eventMask; + // name = _T("ECC_BIT_ERR"); + + +}; + +// 4B +typedef union EVENT_MASK( k8_distpatch_prefetch_instructions) +{ + struct + { + uint16 Load : 1; + uint16 Store : 1; + uint16 NTA : 1; + }; + uint16 flat; + + +}EVENT_MASK( k8_distpatch_prefetch_instructions); + +class k8Event_DISPATCHED_PRE_INSTRS : public k8BaseEvent +{ +public: + + k8Event_DISPATCHED_PRE_INSTRS() + { + eventMask = (EVENT_MASK(k8_distpatch_prefetch_instructions) *)&m_eventMask; + name = _T("Dispatched prefetch instructions"); + event_id = 0x4B; + unitEncode = DC; + + } + EVENT_MASK(k8_distpatch_prefetch_instructions) * eventMask; + // name = _T("DISPATCHED_PRE_INSTRS"); + + /* 0x4C: added in Revision C */ + +}; + + + +typedef union EVENT_MASK( k8_lock_accesses) +{ + struct + { + uint16 DcacheAccesses:1; // Number of dcache accesses by lock instructions" }, + uint16 DcacheMisses:1; // Number of dcache misses by lock instructions" } } + }; + uint16 flat; + +}EVENT_MASK( k8_lock_accesses); + + + +class k8Event_LOCK_ACCESSES : public k8BaseEvent +{ +public: + + k8Event_LOCK_ACCESSES() + { + eventMask = (EVENT_MASK(k8_lock_accesses) *)&m_eventMask; + name = _T("DCACHE accesses by locks") ; + event_id = 0x4C; + unitEncode = DC; + + revRequired = 'C'; + } + EVENT_MASK(k8_lock_accesses) * eventMask; + + +}; + + +class k8Event_CYCLES_PROCESSOR_IS_RUNNING : public k8BaseEvent +{ +public: + + k8Event_CYCLES_PROCESSOR_IS_RUNNING() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Cycles processor is running (not in HLT or STPCLK)"); + event_id = 0x76; + unitEncode = BU; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CYCLES_PROCESSOR_IS_RUNNING"); /* undocumented *; + + +}; + + +typedef union EVENT_MASK( k8_internal_L2_request) +{ + struct + { + uint16 ICFill:1; // IC fill" }, + uint16 DCFill:1; // DC fill" }, + uint16 TLBReload:1; // TLB reload" }, + uint16 TagSnoopRequest:1; // Tag snoop request" }, + uint16 CancelledRequest:1; // Cancelled request" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_internal_L2_request); + +class k8Event_BU_INT_L2_REQ : public k8BaseEvent +{ +public: + + k8Event_BU_INT_L2_REQ() + { + eventMask = (EVENT_MASK(k8_internal_L2_request) *)&m_eventMask; + name = _T("Internal L2 request"); + unitEncode = BU; + event_id = 0x7D; + } + + EVENT_MASK(k8_internal_L2_request) * eventMask; +} ; + + // name = _T("BU_INT_L2_REQ"); + + + +// 7E +typedef union EVENT_MASK( k8_fill_request_missed_L2) +{ + + struct + { + uint16 ICFill:1; // IC fill" }, + uint16 DCFill:1; // DC fill" }, + uint16 TLBReload:1; // TLB reload" }, + }; + uint16 flat; + +} EVENT_MASK( k8_fill_request_missed_L2); + + +class k8Event_BU_FILL_REQ : public k8BaseEvent +{ +public: + + k8Event_BU_FILL_REQ() + { + eventMask = (EVENT_MASK(k8_fill_request_missed_L2) *)&m_eventMask; + name = _T("Fill request that missed in L2"); + event_id = 0x7E; + unitEncode = BU; + + } + EVENT_MASK(k8_fill_request_missed_L2) * eventMask; + // name = _T("BU_FILL_REQ"); + + + +}; + + + + +// 7F +typedef union EVENT_MASK( k8_fill_into_L2) +{ + + struct + { + uint16 DirtyL2Victim:1; // Dirty L2 victim + uint16 VictimFromL2:1; // Victim from L2 + }; + uint16 flat; + +}EVENT_MASK( k8_fill_into_L2); + +class k8Event_BU_FILL_L2 : public k8BaseEvent +{ +public: + + k8Event_BU_FILL_L2() + { + eventMask = (EVENT_MASK(k8_fill_into_L2) *)&m_eventMask; + name = _T("Fill into L2"); + event_id = 0x7F; + unitEncode = BU; + + } + EVENT_MASK(k8_fill_into_L2) * eventMask; + // name = _T("BU_FILL_L2"); + + +}; + +class k8Event_INSTRUCTION_CACHE_FETCHES : public k8BaseEvent +{ +public: + k8Event_INSTRUCTION_CACHE_FETCHES() + { + event_id = 0x80; + unitEncode = IC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("Instruction cache fetches"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_INSTRUCTION_CACHE_MISSES : public k8BaseEvent +{ +public: + k8Event_INSTRUCTION_CACHE_MISSES() + { + event_id = 0x81; + unitEncode = IC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //0xF, NULL, _T("INSTRUCTION_CACHE_MISSES"), + name = _T("Instruction cache misses"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_IC_REFILL_FROM_L2 : public k8BaseEvent +{ +public: + + k8Event_IC_REFILL_FROM_L2() + { + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + name = _T("Refill from L2"); + event_id = 0x82; + unitEncode = IC; + + } + EVENT_MASK(k8_cache) * eventMask; + // name = _T("IC_REFILL_FROM_L2"); + + + +}; +class k8Event_IC_REFILL_FROM_SYS : public k8BaseEvent +{ +public: + + k8Event_IC_REFILL_FROM_SYS() + { + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + name = _T("Refill from system"); + event_id = 0x83; + unitEncode = IC; + + } + EVENT_MASK(k8_cache) * eventMask; + // name = _T("IC_REFILL_FROM_SYS"); + + + +}; +class k8Event_L1_ITLB_MISSES_AND_L2_ITLB_HITS : public k8BaseEvent +{ +public: + k8Event_L1_ITLB_MISSES_AND_L2_ITLB_HITS() + { + + event_id = 0x84; + unitEncode = IC; + + name = _T("L1 ITLB misses (and L2 ITLB hits)"); + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; + +class k8Event_L1_AND_L2_ITLB_MISSES : public k8BaseEvent +{ +public: + k8Event_L1_AND_L2_ITLB_MISSES() + { + event_id = 0x85; + unitEncode = IC; + + name = _T("(L1 and) L2 ITLB misses"); + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + + + +class k8Event_IC_RESYNC_BY_SNOOP : public k8BaseEvent +{ +public: + + k8Event_IC_RESYNC_BY_SNOOP() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x86; + unitEncode = IC; + + name = _T("Microarchitectural resync caused by snoop"); + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_RESYNC_BY_SNOOP"); + /* similar to 0x22; but IC unit instead of LS unit */ + + + +}; +class k8Event_IC_FETCH_STALL : public k8BaseEvent +{ +public: + + k8Event_IC_FETCH_STALL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Instruction fetch stall"); + event_id = 0x87; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_FETCH_STALL"); + + + +}; +class k8Event_IC_STACK_HIT : public k8BaseEvent +{ +public: + + k8Event_IC_STACK_HIT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Return stack hit"); + event_id = 0x88; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_STACK_HIT"); + + + +}; +class k8Event_IC_STACK_OVERFLOW : public k8BaseEvent +{ +public: + + k8Event_IC_STACK_OVERFLOW() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Return stack overflow"); + event_id = 0x89; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_STACK_OVERFLOW"); + + + + +}; + + /* 0xC0-0xC7: from K7 official event set */ +class k8Event_RETIRED_INSTRUCTIONS : public k8BaseEvent +{ +public: + k8Event_RETIRED_INSTRUCTIONS() + { + event_id = 0xC0; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //0xF, NULL, _T("RETIRED_INSTRUCTIONS"), + name = _T("Retired instructions (includes exceptions, interrupts, resyncs)"); + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_RETIRED_OPS : public k8BaseEvent +{ +public: + k8Event_RETIRED_OPS() + { + event_id = 0xC1; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_OPS"), + name = _T("Retired Ops") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_BRANCHES() + { + event_id = 0xC2; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_BRANCHES"), + name = _T("Retired branches (conditional, unconditional, exceptions, interrupts)") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_BRANCHES_MISPREDICTED : public k8BaseEvent +{ +public: + k8Event_RETIRED_BRANCHES_MISPREDICTED() + { + event_id = 0xC3; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_BRANCHES_MISPREDICTED"), + name = _T("Retired branches mispredicted") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_TAKEN_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_TAKEN_BRANCHES() + { + event_id = 0xC4; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_TAKEN_BRANCHES"), + name = _T("Retired taken branches") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_TAKEN_BRANCHES_MISPREDICTED : public k8BaseEvent +{ +public: + k8Event_RETIRED_TAKEN_BRANCHES_MISPREDICTED() + { + event_id = 0xC5; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_TAKEN_BRANCHES_MISPREDICTED"), + name = _T("Retired taken branches mispredicted") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_FAR_CONTROL_TRANSFERS : public k8BaseEvent +{ +public: + k8Event_RETIRED_FAR_CONTROL_TRANSFERS() + { + event_id = 0xC6; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_FAR_CONTROL_TRANSFERS"), + name = _T("Retired far control transfers") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_RESYNC_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_RESYNC_BRANCHES() + { + event_id = 0xC7; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_RESYNC_BRANCHES"), + name = _T("Retired resync branches (only non-control transfer branches counted)") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_RETIRED_NEAR_RETURNS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_NEAR_RETURNS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired near returns"); + event_id = 0xC8; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + + + +}; +class k8Event_RETIRED_RETURNS_MISPREDICT : public k8BaseEvent +{ +public: + + k8Event_RETIRED_RETURNS_MISPREDICT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired near returns mispredicted"); + event_id = 0xC9; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("RETIRED_RETURNS_MISPREDICT"); + + +}; +class k8Event_RETIRED_BRANCH_MISCOMPARE : public k8BaseEvent +{ +public: + + k8Event_RETIRED_BRANCH_MISCOMPARE() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired taken branches mispredicted due to address miscompare"); + event_id = 0xCA; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("RETIRED_BRANCH_MISCOMPARE"); + + +}; + + + /* Revision B and later */ + +typedef union EVENT_MASK( k8_retired_fpu_instr) +{ + struct + { + uint16 DirtyL2Victim:1; // x87 instructions + uint16 CombinedMMX_3DNow:1; // Combined MMX & 3DNow! instructions" }, + uint16 CombinedPackedSSE_SSE2:1; // Combined packed SSE and SSE2 instructions" }, + uint16 CombinedScalarSSE_SSE2:1; // Combined scalar SSE and SSE2 instructions" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_retired_fpu_instr); + + +class k8Event_RETIRED_FPU_INSTRS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_FPU_INSTRS() + { + eventMask = (EVENT_MASK(k8_retired_fpu_instr) *)&m_eventMask; + event_id = 0xCB; + unitEncode = FR; + + name = _T("Retired FPU instructions"); + revRequired = 'B'; + } + EVENT_MASK(k8_retired_fpu_instr) * eventMask; + /* Revision B and later */ + + + +}; + +// CC +typedef union EVENT_MASK( k8_retired_fastpath_double_op_instr ) +{ + + struct + { + uint16 LowOpPosition0:1; // With low op in position 0" }, + uint16 LowOpPosition1:1; // With low op in position 1" }, + uint16 LowOpPosition2:1; // With low op in position 2" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_retired_fastpath_double_op_instr); + +class k8Event_RETIRED_FASTPATH_INSTRS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_FASTPATH_INSTRS() + { + eventMask = (EVENT_MASK(k8_retired_fastpath_double_op_instr) *)&m_eventMask; + event_id = 0xCC; + unitEncode = FR; + + name = _T("Retired fastpath double op instructions"); + revRequired = 'B'; + + } + EVENT_MASK(k8_retired_fastpath_double_op_instr) * eventMask; + + +}; + +class k8Event_INTERRUPTS_MASKED_CYCLES : public k8BaseEvent +{ +public: + k8Event_INTERRUPTS_MASKED_CYCLES() + { + event_id = 0xCD; + unitEncode = FR; + + //0xF, NULL, _T("INTERRUPTS_MASKED_CYCLES"), + name = _T("Interrupts masked cycles (IF=0)") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; +class k8Event_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES : public k8BaseEvent +{ +public: + k8Event_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES() + { + event_id = 0xCE; + unitEncode = FR; + + //0xF, NULL, _T("INTERRUPTS_MASKED_WHILE_PENDING_CYCLES"), + name = _T("Interrupts masked while pending cycles (INTR while IF=0)") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; +class k8Event_NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS : public k8BaseEvent +{ +public: + k8Event_NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS() + { + event_id = 0xCF; + unitEncode = FR; + + //0xF, NULL, _T("NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS"), + name = _T("Number of taken hardware interrupts") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_DECODER_EMPTY : public k8BaseEvent +{ +public: + + k8Event_DECODER_EMPTY() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Nothing to dispatch (decoder empty)"); + event_id = 0xD0; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DECODER_EMPTY"); + + +}; +class k8Event_DISPATCH_STALLS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALLS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stalls (events 0xD2-0xDA combined)"); + event_id = 0xD1; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALLS"); + + + +}; +class k8Event_DISPATCH_STALL_FROM_BRANCH_ABORT : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_FROM_BRANCH_ABORT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall from branch abort to retire"); + event_id = 0xD2; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_FROM_BRANCH_ABORT"); + + + +}; +class k8Event_DISPATCH_STALL_SERIALIZATION : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_SERIALIZATION() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall for serialization"); + event_id = 0xD3; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_SERIALIZATION"); + + +}; +class k8Event_DISPATCH_STALL_SEG_LOAD : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_SEG_LOAD() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall for segment load"); + event_id = 0xD4; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_SEG_LOAD"); + + + +}; +class k8Event_DISPATCH_STALL_REORDER_BUFFER : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_REORDER_BUFFER() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when reorder buffer is full"); + event_id = 0xD5; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_REORDER_BUFFER"); + + +}; +class k8Event_DISPATCH_STALL_RESERVE_STATIONS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_RESERVE_STATIONS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when reservation stations are full"); + event_id = 0xD6; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_RESERVE_STATIONS"); + + +}; +class k8Event_DISPATCH_STALL_FPU : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_FPU() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when FPU is full"); + event_id = 0xD7; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_FPU"); + + +}; +class k8Event_DISPATCH_STALL_LS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_LS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when LS is full"); + event_id = 0xD8; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_LS"); + + +}; +class k8Event_DISPATCH_STALL_QUIET_WAIT : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_QUIET_WAIT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when waiting for all to be quiet"); + event_id = 0xD9; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_QUIET_WAIT"); + + + +}; +class k8Event_DISPATCH_STALL_PENDING : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_PENDING() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when far control transfer or resync branch is pending"); + event_id = 0xDA; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_PENDING"); + + + +}; + + +typedef union EVENT_MASK( k8_fpu_exceptions) +{ + + + + struct + { + uint16 x87ReclassMicrofaults:1; // x87 reclass microfaults" }, + uint16 SSERetypeMicrofaults:1; // SSE retype microfaults" }, + uint16 SSEReclassMicrofaults:1; // SSE reclass microfaults" }, + uint16 SSE_x87Microtraps:1; // SSE and x87 microtraps" } } + }; + uint16 flat; + + + +}EVENT_MASK( k8_fpu_exceptions); + +class k8Event_FPU_EXCEPTIONS : public k8BaseEvent +{ +public: + + k8Event_FPU_EXCEPTIONS() + { + eventMask = (EVENT_MASK(k8_fpu_exceptions) *)&m_eventMask; + event_id = 0xDB; + unitEncode = FR; + + name = _T("FPU exceptions"); + revRequired = 'B'; + + } + EVENT_MASK(k8_fpu_exceptions) * eventMask; + // name = _T("FPU_EXCEPTIONS"); + /* Revision B and later */ + + + +}; +class k8Event_DR0_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR0_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR0"); + event_id = 0xDC; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR0_BREAKPOINTS"); + + + +}; +class k8Event_DR1_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR1_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR1"); + event_id = 0xDD; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR1_BREAKPOINTS"); + + + +}; +class k8Event_DR2_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR2_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR2"); + event_id = 0xDE; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR2_BREAKPOINTS"); + + +}; +class k8Event_DR3_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR3_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR3"); + event_id = 0xDF; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR3_BREAKPOINTS"); + + +}; + + + +// E0 +typedef union EVENT_MASK( k8_page_access_event) +{ + struct + { + uint16 PageHit:1; // Page hit" }, + uint16 PageMiss:1; // Page miss" }, + uint16 PageConflict:1; // Page conflict" } } + }; + uint16 flat; + +}EVENT_MASK( k8_page_access_event); + +class k8Event_MEM_PAGE_ACCESS : public k8BaseEvent +{ +public: + + k8Event_MEM_PAGE_ACCESS() + { + eventMask = (EVENT_MASK(k8_page_access_event) *)&m_eventMask; + name = _T("Memory controller page access"); + event_id = 0xE0; + unitEncode = NB; + + } + EVENT_MASK(k8_page_access_event) * eventMask; + // name = _T("MEM_PAGE_ACCESS"); + + +}; +class k8Event_MEM_PAGE_TBL_OVERFLOW : public k8BaseEvent +{ +public: + + k8Event_MEM_PAGE_TBL_OVERFLOW() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Memory controller page table overflow"); + event_id = 0xE1; + unitEncode = NB; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("MEM_PAGE_TBL_OVERFLOW"); + + +}; +class k8Event_DRAM_SLOTS_MISSED : public k8BaseEvent +{ +public: + + k8Event_DRAM_SLOTS_MISSED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Memory controller DRAM command slots missed (in MemClks)"); + event_id = 0xE2; + unitEncode = NB; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DRAM_SLOTS_MISSED"); + + +}; + + +// e3 +typedef union EVENT_MASK( k8_turnaround) +{ + + struct + { + uint16 DIMMTurnaround:1; //DIMM turnaround" }, + uint16 ReadToWriteTurnaround:1; //Read to write turnaround" }, + uint16 WriteToReadTurnaround:1; //Write to read turnaround" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_turnaround); + +class k8Event_MEM_TURNAROUND : public k8BaseEvent +{ +public: + + k8Event_MEM_TURNAROUND() + { + eventMask = (EVENT_MASK(k8_turnaround) *)&m_eventMask; + name = _T("Memory controller turnaround"); + event_id = 0xE3; + unitEncode = NB; + + } + EVENT_MASK(k8_turnaround) * eventMask; + // name = _T("MEM_TURNAROUND"); + + +}; + + + + +// E4 +typedef union EVENT_MASK( k8_bypass_counter_saturation) +{ + struct + { + uint16 MEM_HighPriorityBypass:1; // Memory controller high priority bypass" }, + uint16 MEM_LowPriorityBypass:1; // Memory controller low priority bypass" }, + uint16 DRAM_InterfaceBypass:1; // DRAM controller interface bypass" }, + uint16 DRAM_QueueBypass:1; // DRAM controller queue bypass" } } + }; + uint16 flat; + +}EVENT_MASK( k8_bypass_counter_saturation); + +class k8Event_MEM_BYPASS_SAT : public k8BaseEvent +{ +public: + + k8Event_MEM_BYPASS_SAT() + { + eventMask = (EVENT_MASK(k8_bypass_counter_saturation) *)&m_eventMask; + name = _T("Memory controller bypass counter saturation"); + event_id = 0xE4; + unitEncode = NB; + + } + EVENT_MASK(k8_bypass_counter_saturation) * eventMask; + // name = _T("MEM_BYPASS_SAT"); + + +}; + + + +//EB +typedef union EVENT_MASK( k8_sized_commands) +{ + + struct + { + uint16 NonPostWrSzByte:1; // NonPostWrSzByte" }, + uint16 NonPostWrSzDword:1; // NonPostWrSzDword" }, + uint16 PostWrSzByte:1; // PostWrSzByte" }, + uint16 PostWrSzDword:1; // PostWrSzDword" }, + uint16 RdSzByte:1; // RdSzByte" }, + uint16 RdSzDword:1; // RdSzDword" }, + uint16 RdModWr:1; // RdModWr" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_sized_commands); + + +class k8Event_SIZED_COMMANDS : public k8BaseEvent +{ +public: + + k8Event_SIZED_COMMANDS() + { + eventMask = (EVENT_MASK(k8_sized_commands) *)&m_eventMask; + name = _T("Sized commands"); + event_id = 0xEB; + unitEncode = NB; + + } + EVENT_MASK(k8_sized_commands) * eventMask; + // name = _T("SIZED_COMMANDS"); + + +}; + +typedef union EVENT_MASK( k8_probe_result) +{ + struct + { + uint16 ProbeMiss:1; // Probe miss" }, + uint16 ProbeHit:1; // Probe hit" }, + uint16 ProbeHitDirtyWithoutMemoryCancel:1; // Probe hit dirty without memory cancel" }, + uint16 ProbeHitDirtyWithMemoryCancel:1; // Probe hit dirty with memory cancel" } } + uint16 UpstreamDisplayRefreshReads:1; // Rev D and later + uint16 UpstreamNonDisplayRefreshReads:1; // Rev D and later + uint16 UpstreamWrites:1; // Rev D and later + }; + uint16 flat; + + +}EVENT_MASK( k8_probe_result); + + +class k8Event_PROBE_RESULT : public k8BaseEvent +{ +public: + + k8Event_PROBE_RESULT() + { + eventMask = (EVENT_MASK(k8_probe_result) *)&m_eventMask; + name = _T("Probe result"); + event_id = 0xEC; + unitEncode = NB; + + } + EVENT_MASK(k8_probe_result) * eventMask; + // name = _T("PROBE_RESULT"); + + +}; + +typedef union EVENT_MASK( k8_ht) +{ + + struct + { + uint16 CommandSent:1; //Command sent" }, + uint16 DataSent:1; //Data sent" }, + uint16 BufferReleaseSent:1; //Buffer release sent" + uint16 NopSent:1; //Nop sent" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_ht); + + +class k8Event_HYPERTRANSPORT_BUS0_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS0_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 0 bandwidth"); + event_id = 0xF6; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS0_WIDTH"); + + +}; +class k8Event_HYPERTRANSPORT_BUS1_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS1_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 1 bandwidth"); + event_id = 0xF7; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS1_WIDTH"); + + +}; +class k8Event_HYPERTRANSPORT_BUS2_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS2_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 2 bandwidth"); + event_id = 0xF8; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS2_WIDTH"); + +}; + +// +//typedef union EVENT_MASK( perfctr_event_set k8_common_event_set) +//{ +// +// .cpu_type = PERFCTR_X86_AMD_K8, +// .event_prefix = _T("K8_"), +// .include = &k7_official_event_set, +// .nevents = ARRAY_SIZE(k8_common_events), +// .events = k8_common_events, +//}EVENT_MASK( perfctr_event_set k8_common_event_set); +// +//typedef union EVENT_MASK( perfctr_event k8_events[]) +//{ +// +// { 0x24, 0xF, UM(NULL), _T("LOCKED_OP"), /* unit mask changed in Rev. C */ +// _T("Locked operation") }, +//}EVENT_MASK( perfctr_event k8_events[]); + + + + +//const struct perfctr_event_set perfctr_k8_event_set) +//{ +// +// .cpu_type = PERFCTR_X86_AMD_K8, +// .event_prefix = _T("K8_"), +// .include = &k8_common_event_set, +// .nevents = ARRAY_SIZE(k8_events), +// .events = k8_events, +//}; +// +/* + * K8 Revision C. Starts at CPUID 0xF58 for Opteron/Athlon64FX and + * CPUID 0xF48 for Athlon64. (CPUID 0xF51 is Opteron Revision B3.) + */ + + + + + + + + +// +//typedef union EVENT_MASK( k8_lock_accesses) +//{ +// struct +// { +// uint16 DcacheAccesses:1; // Number of dcache accesses by lock instructions" }, +// uint16 DcacheMisses:1; // Number of dcache misses by lock instructions" } } +// }; +// uint16 flat; +// +//}EVENT_MASK( k8_lock_accesses); +// + +#endif // K8PERFORMANCECOUNTERS_H diff --git a/public/tier0/P4PerformanceCounters.h b/public/tier0/P4PerformanceCounters.h new file mode 100644 index 0000000..b52b691 --- /dev/null +++ b/public/tier0/P4PerformanceCounters.h @@ -0,0 +1,322 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef P4PERFORMANCECOUNTERS_H +#define P4PERFORMANCECOUNTERS_H + +#pragma once +// Pentium 4 support + +/* + http://developer.intel.com/design/Pentium4/documentation.htm + + IA-32 Intel Architecture Software Developer's Manual Volume 1: Basic Architecture + + IA-32 Intel Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M + + IA-32 Intel Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z + + IA-32 Intel Architecture Software Developer's Manual Volume 3: System Programming Guide + + + From Mikael Pettersson's perfctr: + + http://user.it.uu.se/~mikpe/linux/perfctr/ + + * Known quirks: + - OVF_PMI+FORCE_OVF counters must have an ireset value of -1. + This allows the regular overflow check to also handle FORCE_OVF + counters. Not having this restriction would lead to MAJOR + complications in the driver's "detect overflow counters" code. + There is no loss of functionality since the ireset value doesn't + affect the counter's PMI rate for FORCE_OVF counters. + + - In experiments with FORCE_OVF counters, and regular OVF_PMI + counters with small ireset values between -8 and -1, it appears + that the faulting instruction is subjected to a new PMI before + it can complete, ad infinitum. This occurs even though the driver + clears the CCCR (and in testing also the ESCR) and invokes a + user-space signal handler before restoring the CCCR and resuming + the instruction. +*/ + +#define NCOUNTERS 18 + +// The 18 counters +enum Counters +{ + MSR_BPU_COUNTER0, + MSR_BPU_COUNTER1, + MSR_BPU_COUNTER2, + MSR_BPU_COUNTER3, + MSR_MS_COUNTER0, + MSR_MS_COUNTER1, + MSR_MS_COUNTER2, + MSR_MS_COUNTER3, + MSR_FLAME_COUNTER0, + MSR_FLAME_COUNTER1, + MSR_FLAME_COUNTER2, + MSR_FLAME_COUNTER3, + MSR_IQ_COUNTER0, + MSR_IQ_COUNTER1, + MSR_IQ_COUNTER2, + MSR_IQ_COUNTER3, + MSR_IQ_COUNTER4, + MSR_IQ_COUNTER5 +}; + +// register base for counters +#define MSR_COUNTER_BASE 0x300 + +// register base for CCCR register +#define MSR_CCCR_BASE 0x360 + +#pragma pack(push, 1) +// access to these bits is through the methods +typedef union ESCR +{ + struct + { + uint64 Reserved0_1 : 2; // + uint64 USR : 1; // + uint64 OS : 1; // + uint64 TagEnable : 1; // + uint64 TagValue : 4; // + uint64 EventMask : 16; // from event select + uint64 ESCREventSelect : 6; // 31:25 class of event + uint64 Reserved31 : 1; // + + uint64 Reserved32_63 : 32; // + }; + uint64 flat; + +} ESCR; + +typedef union CCCR +{ + struct + { + uint64 Reserved0_11 : 12;// 0 -11 + uint64 Enable : 1; // 12 + uint64 CCCRSelect : 3; // 13-15 + uint64 Reserved16_17 : 2; // 16 17 + + uint64 Compare : 1; // 18 + uint64 Complement : 1; // 19 + uint64 Threshold : 4; // 20-23 + uint64 Edge : 1; // 24 + uint64 FORCE_OVF : 1; // 25 + uint64 OVF_PMI : 1; // 26 + uint64 Reserved27_29 : 3; // 27-29 + uint64 Cascade : 1; // 30 + uint64 OVF : 1; // 31 + + uint64 Reserved32_63 : 32; // + }; + uint64 flat; + +} CCCR; + +#pragma pack(pop) + +extern const unsigned short cccr_escr_map[NCOUNTERS][8]; + +enum P4TagState +{ + TagDisable, // + TagEnable, // +}; + +enum P4ForceOverflow +{ + ForceOverflowDisable, + ForceOverflowEnable, +}; + +enum P4OverflowInterrupt +{ + OverflowInterruptDisable, + OverflowInterruptEnable, +}; + +// Turn off the no return value warning in ReadCounter. +#pragma warning( disable : 4035 ) +class P4BaseEvent +{ + int m_counter; + +protected: + + void SetCounter(int counter) + { + m_counter = counter; + cccrPort = MSR_CCCR_BASE + m_counter; + counterPort = MSR_COUNTER_BASE + m_counter; + escrPort = cccr_escr_map[m_counter][cccr.CCCRSelect]; + } + +public: + + unsigned short m_eventMask; + const tchar *description; + PME *pme; + ESCR escr; + CCCR cccr; + int counterPort; + int cccrPort; + int escrPort; + + P4BaseEvent() + { + pme = PME::Instance(); + m_eventMask = 0; + description = _T(""); + escr.flat = 0; + cccr.flat = 0; + cccr.Reserved16_17 = 3; // must be set + escrPort = 0; + m_counter = -1; + } + + void StartCounter() + { + cccr.Enable = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void StopCounter() + { + cccr.Enable = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearCounter() + { + pme->WriteMSR( counterPort, 0ui64 ); // clear + } + + void WriteCounter( int64 value ) + { + pme->WriteMSR( counterPort, value ); // clear + } + + int64 ReadCounter() + { +#if PME_DEBUG + if ( escr.USR == 0 && escr.OS == 0 ) + return -1; // no area to collect, use SetCaptureMode + + if ( escr.EventMask == 0 ) + return -2; // no event mask set + + if ( m_counter == -1 ) + return -3; // counter not legal +#endif + + // ReadMSR should work here too, but RDPMC should be faster + int64 value = 0; + pme->ReadMSR( counterPort, &value ); + return value; +#if 0 + // we need to copy this into a temp for some reason + int temp = m_counter; + _asm + { + mov ecx, temp + RDPMC + } +#endif + } + + void SetCaptureMode( PrivilegeCapture priv ) + { + switch ( priv ) + { + case OS_Only: + { + escr.USR = 0; + escr.OS = 1; + break; + } + case USR_Only: + { + escr.USR = 1; + escr.OS = 0; + break; + } + case OS_and_USR: + { + escr.USR = 1; + escr.OS = 1; + break; + } + } + + escr.EventMask = m_eventMask; + pme->WriteMSR( escrPort, escr.flat ); + } + + void SetTagging( P4TagState tagEnable, uint8 tagValue ) + { + escr.TagEnable = tagEnable; + escr.TagValue = tagValue; + pme->WriteMSR( escrPort, escr.flat ); + } + + void SetFiltering( CompareState compareEnable, CompareMethod compareMethod, uint8 threshold, EdgeState edgeEnable ) + { + cccr.Compare = compareEnable; + cccr.Complement = compareMethod; + cccr.Threshold = threshold; + cccr.Edge = edgeEnable; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void SetOverflowEnables( P4ForceOverflow overflowEnable, P4OverflowInterrupt overflowInterruptEnable ) + { + cccr.FORCE_OVF = overflowEnable; + cccr.OVF_PMI = overflowInterruptEnable; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void SetOverflow() + { + cccr.OVF = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearOverflow() + { + cccr.OVF = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + bool isOverflow() + { + CCCR cccr_temp; + pme->ReadMSR( cccrPort, &cccr_temp.flat ); + return cccr_temp.OVF; + } + + void SetCascade() + { + cccr.Cascade = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearCascade() + { + cccr.Cascade = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } +}; +#pragma warning( default : 4035 ) + +#include "EventMasks.h" +#include "EventModes.h" + +#endif // P4PERFORMANCECOUNTERS_H diff --git a/public/tier0/P5P6PerformanceCounters.h b/public/tier0/P5P6PerformanceCounters.h new file mode 100644 index 0000000..a765756 --- /dev/null +++ b/public/tier0/P5P6PerformanceCounters.h @@ -0,0 +1,225 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef P5P6PERFORMANCECOUNTERS_H +#define P5P6PERFORMANCECOUNTERS_H + +// defined for < Pentium 4 + +//--------------------------------------------------------------------------- +// Format of the performance event IDs within this header file in case you +// wish to add any additional events that may not be present here. +// +// BITS 0-8 Unit Mask, Unsed on P5 processors +// BIT 9 Set if event can be set on counter 0 +// BIT 10 Set if event can be set on counter 1 +// BITS 11-15 Unused Set to zero +// BITS 16-23 Event Select ID, Only bits 16-21 used on P5 Family +// BITS 24-27 Unused set to zero +// BITS 28-32 Process family that the event belong to, as returned by +// the CPUID instruction. +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// PENTIUM PERFORMANCE COUNTERS. +//--------------------------------------------------------------------------- +#define P5_DTCRD 0x50000300 //Data Cache Reads +#define P5_DWRIT 0x50010300 //Data Cache Writes +#define P5_DTTLB 0x50020300 //Data TLB Miss +#define P5_DTRMS 0x50030300 //Data Read Misses +#define P5_DWRMS 0x50040300 //Data Write Miss +#define P5_WHLCL 0x50050300 //Write (Hit) to M- or E-state line +#define P5_DCLWB 0x50060300 //Data Cache Lines Written Back +#define P5_DCSNP 0x50070300 //External Snoops +#define P5_DCSHT 0x50080300 //Data Cache Snoop Hits +#define P5_MAIBP 0x50090300 //Memory Access in Both Pipes +#define P5_BANKS 0x500A0300 //Bank Conflicts +#define P5_MISAL 0x500B0300 //Misaligned Data Memory Reference +#define P5_COCRD 0x500C0300 //Code Cache Reads +#define P5_COTLB 0x500D0300 //Code TLB Misses +#define P5_COCMS 0x500E0300 //Code Cache Misses +#define P5_ANYSG 0x500F0300 //Any Segment Register Loaded +#define P5_BRANC 0x50120300 //Branches +#define P5_BTBHT 0x50130300 //BTB Hits +#define P5_TBRAN 0x50140300 //Taken Branch or BTB hit +#define P5_PFLSH 0x50150300 //Pipeline flushes +#define P5_INSTR 0x50160300 //Instructions Executed +#define P5_INSTV 0x50170300 //Instructions Executed in the V-Pipe (Pairing) +#define P5_CLOCL 0x50180300 //Bus active +#define P5_PSDWR 0x50190300 //Full write buffers +#define P5_PSWDR 0x501A0300 //Waiting for Data Memory Read +#define P5_NCLSW 0x501B0300 //Clocks stalled writing an E or M state line +#define P5_IORWC 0x501D0300 //I/O Read or Write Cycle +#define P5_NOCMR 0x501E0300 //Non-Cacheable Memory Reads +#define P5_PSLDA 0x501F0300 //Clocks stalled due to AGI +#define P5_FLOPS 0x50220300 //Floating Point Operations +#define P5_DBGR0 0x50230300 //Breakpoint match on DR0 +#define P5_DBGR1 0x50240300 //Breakpoint match on DR1 +#define P5_DBGR2 0x50250300 //Breakpoint match on DR2 +#define P5_DBGR3 0x50260300 //Breakpoint match on DR3 +#define P5_HWINT 0x50270300 //Hardware interrupts +#define P5_DTRWR 0x50280300 //Data reads or writes +#define P5_DTRWM 0x50290300 //Data read or write miss +#define P5_BOLAT 0x502A0100 //Bus ownership latency +#define P5_BOTFR 0x502A0200 //Bus ownership transfer +#define P5_MMXA1 0x502B0100 //MMX Instruction Executed in U-pipe +#define P5_MMXA2 0x502B0200 //MMX Instruction Executed in V-pipe +#define P5_MMXMS 0x502C0100 //Cache M state line sharing +#define P5_MMSLS 0x502C0200 //Cache line sharing +#define P5_MMXB1 0x502D0100 //EMMS Instructions Executed +#define P5_MMXB2 0x502D0200 //Transition from MMX to FP instructions +#define P5_NOCMW 0x502E0200 //Non-Cacheable Memory Writes +#define P5_MMXC1 0x502F0100 //Saturated MMX Instructions Executed +#define P5_MMXC2 0x502F0200 //Saturations Performed +#define P5_MMXHS 0x50300100 //Cycles Not in HALT State +#define P5_MMXD2 0x50310100 //MMX Data Read +#define P5_MMXFP 0x50320100 //Floating Point Stalls +#define P5_MMXTB 0x50320200 //Taken Branches +#define P5_MMXD0 0x50330100 //D1 Starvation and FIFO Empty +#define P5_MMXD1 0x50330200 //D1 Starvation and one instruction in FIFO +#define P5_MMXE1 0x50340100 //MMX Data Writes +#define P5_MMXE2 0x50340200 //MMX Data Write Misses +#define P5_MMXWB 0x50350100 //Pipeline flushes, wrong branch prediction +#define P5_MMXWJ 0x50350200 //Pipeline flushes, branch prediction WB-stage +#define P5_MMXF1 0x50360100 //Misaligned MMX Data Memory Reference +#define P5_MMXF2 0x50360200 //Pipeline Stalled Waiting for MMX data read +#define P5_MMXRI 0x50370100 //Returns Predicted Incorrectly +#define P5_MMXRP 0x50370200 //Returns Predicted +#define P5_MMXG1 0x50380100 //MMX Multiply Unit Interlock +#define P5_MMXG2 0x50380200 //MOVD/MOVQ store stall, previous operation +#define P5_MMXRT 0x50390100 //Returns +#define P5_MMXRO 0x50390200 //RSB Overflows +#define P5_MMXBF 0x503A0100 //BTB False entries +#define P5_MMXBM 0x503A0200 //BTB misprediction on a Not-Taken Branch +#define P5_PXDWR 0x503B0100 //stalled due MMX Full write buffers +#define P5_PXZWR 0x503B0200 //stalled on MMX write to E or M state line + +#define P5_CLOCK 0x503F0300 //Special value to count clocks on P5 + + +//--------------------------------------------------------------------------- +// PENTIUM PRO / PENTIUM II PERFORMANCE COUNTERS. +//--------------------------------------------------------------------------- +#define P6_STRBB 0x60030300 //Store Buffer Block +#define P6_STBDC 0x60040300 //Store Buffer Drain Cycles +#define P6_MISMM 0x60050300 //Misaligned Data Memory Reference +#define P6_SEGLD 0x60060300 //Segment register loads +#define P6_FPOPE 0x60100100 //FP Computational Op. (COUNTER 0 ONLY) +#define P6_FPEOA 0x60110200 //FP Microcode Exceptions (COUNTER 1 ONLY) +#define P6_FMULT 0x60120200 //Multiplies (COUNTER 1 ONLY) +#define P6_FPDIV 0x60130200 //Divides (COUNTER 1 ONLY) +#define P6_DBUSY 0x60140200 //Cycles Divider Busy (COUNTER 1 ONLY) +#define P6_L2STR 0x60210300 //L2 address strobes => address bus utilization +#define P6_L2BBS 0x60220300 //Cycles L2 Bus Busy +#define P6_L2BBT 0x60230300 //Cycles L2 Bus Busy transferring data to CPU +#define P6_L2ALO 0x60240300 //L2 Lines Allocated +#define P6_L2MAL 0x60250300 //L2 M-state Lines Allocated +#define P6_L2CEV 0x60260300 //L2 Lines Evicted +#define P6_L2MEV 0x60270300 //L2 M-state Lines Evicted +#define P6_L2MCF 0x60280301 //L2 Cache Instruction Fetch Misses +#define P6_L2FET 0x6028030F //L2 Cache Instruction Fetches +#define P6_L2DRM 0x60290301 //L2 Cache Read Misses +#define P6_L2DMR 0x6029030F //L2 Cache Reads +#define P6_L2DWM 0x602A0301 //L2 Cache Write Misses +#define P6_L2DMW 0x602A030F //L2 Cache Writes +#define P6_L2CMS 0x602E0301 //L2 Cache Request Misses +#define P6_L2DCR 0x602E030F //L2 Cache Requests +#define P6_DMREF 0x60430300 //Data Memory References +#define P6_DCALO 0x6045030F //L1 Lines Allocated +#define P6_DCMAL 0x60460300 //L1 M-state Data Cache Lines Allocated +#define P6_DCMEV 0x60470300 //L1 M-state Data Cache Lines Evicted +#define P6_DCOUT 0x60480300 //L1 Misses outstanding +#define P6_TSMCD 0x60520300 //Time Self-Modifiying Code Detected +#define P6_BRWRA 0x60600300 //External Bus Cycles While Receive Active +#define P6_BRDCD 0x60600300 //External Bus Request Outstanding +#define P6_BRBNR 0x60610300 //External Bus Cycles While BNR Asserted +#define P6_BUSBS 0x60620300 //External Bus Cycles-DRDY Asserted (busy) +#define P6_BLOCK 0x60630300 //External Bus Cycles-LOCK signal asserted +#define P6_BBRCV 0x60640300 //External Bus Cycles-Processor receiving data +#define P6_BURST 0x60650300 //External Bus Burst Read Operations +#define P6_BRINV 0x60660300 //External Bus Read for Ownership Transaction +#define P6_BMLEV 0x60670300 //External Bus Writeback M-state Evicted +#define P6_BBIFT 0x60680300 //External Bus Burst Instruction Fetches +#define P6_BINVL 0x60690300 //External Bus Invalidate Transactions +#define P6_BPRBT 0x606A0300 //External Bus Partial Read Transactions +#define P6_BPTMO 0x606B0300 //External Bus Partial Memory Transactions +#define P6_BUSIO 0x606C0300 //External Bus I/O Bus Transactions +#define P6_BUSDF 0x606D0300 //External Bus Deferred Transactions +#define P6_BUSTB 0x606E0300 //External Bus Burst Transactions +#define P6_BMALL 0x606F0300 //External Bus Memory Transactions +#define P6_BSALL 0x60700300 //External Bus Transactions +#define P6_CLOCK 0x60790300 //Clockticks +#define P6_BRHIT 0x607A0300 //External Bus Cycles While HIT Asserted +#define P6_BRHTM 0x607B0300 //External Bus Cycles While HITM Asserted +#define P6_BRSST 0x607E0300 //External Bus Cycles While Snoop Stalled +#define P6_CMREF 0x60800300 //Total Instruction Fetches +#define P6_TOIFM 0x60810300 //Total Instruction Fetch Misses +#define P6_INTLB 0x60850300 //Instructions TLB Misses +#define P6_CSFET 0x60860300 //Cycles Instruction Fetch Stalled +#define P6_FTSTL 0x60870300 //Cycles Instruction Fetch stalled +#define P6_RSTAL 0x60A20300 //Resource Related Stalls +#define P6_MMXIE 0x60B00300 //MMX Instructions Executed +#define P6_SAISE 0x60B10300 //Saturated Arithmetic Instructions Executed +#define P6_PORT0 0x60B20301 //MMX micro-ops executed on Port 0 +#define P6_PORT1 0x60B20302 //MMX micro-ops executed on Port 1 +#define P6_PORT2 0x60B20304 //MMX micro-ops executed on Port 2 +#define P6_PORT3 0x60B20308 //MMX micro-ops executed on Port 3 +#define P6_MMXPA 0x60B30300 //MMX Packed Arithmetic +#define P6_MMXPM 0x60B30301 //MMX Packed Multiply +#define P6_MMXPS 0x60B30302 //MMX Packed Shift +#define P6_MMXPO 0x60B30304 //MMX Packed Operations +#define P6_MMXUO 0x60B30308 //MMX Unpacked Operations +#define P6_MMXPL 0x60B30310 //MMX Packed Logical +#define P6_INSTR 0x60C00300 //Instructions Retired +#define P6_FPOPS 0x60C10100 //FP operations retired (COUNTER 0 ONLY) +#define P6_UOPSR 0x60C20300 //Micro-Ops Retired +#define P6_BRRET 0x60C40300 //Branch Instructions Retired +#define P6_BRMSR 0x60C50300 //Branch Mispredictions Retired +#define P6_MASKD 0x60C60300 //Clocks while interrupts masked +#define P6_MSKPN 0x60C70300 //Clocks while interrupt is pending +#define P6_HWINT 0x60C80300 //Hardware Interrupts Received +#define P6_BTAKR 0x60C90300 //Taken Branch Retired +#define P6_BTAKM 0x60CA0300 //Taken Branch Mispredictions +#define P6_FPMMX 0x60CC0301 //Transitions from Floating Point to MMX +#define P6_MMXFP 0x60CC0300 //Transitions from MMX to Floating Point +#define P6_SIMDA 0x60CD0300 //SIMD Assists (EMMS Instructions Executed) +#define P6_MMXIR 0x60CE0300 //MMX Instructions Retired +#define P6_SAISR 0x60CF0300 //Saturated Arithmetic Instructions Retired +#define P6_INSTD 0x60D00300 //Instructions Decoded +#define P6_NPRTL 0x60D20300 //Renaming Stalls +#define P6_SRSES 0x60D40301 //Segment Rename Stalls - ES +#define P6_SRSDS 0x60D40302 //Segment Rename Stalls - DS +#define P6_SRSFS 0x60D40304 //Segment Rename Stalls - FS +#define P6_SRSGS 0x60D40308 //Segment Rename Stalls - GS +#define P6_SRSXS 0x60D4030F //Segment Rename Stalls - ES DS FS GS +#define P6_SRNES 0x60D50301 //Segment Renames - ES +#define P6_SRNDS 0x60D50302 //Segment Renames - DS +#define P6_SRNFS 0x60D50304 //Segment Renames - FS +#define P6_SRNGS 0x60D50308 //Segment Renames - GS +#define P6_SRNXS 0x60D5030F //Segment Renames - ES DS FS GS +#define P6_BRDEC 0x60E00300 //Branch Instructions Decoded +#define P6_BTBMS 0x60E20301 //BTB Misses +#define P6_RETDC 0x60E40300 //Bogus Branches +#define P6_BACLR 0x60E60300 //BACLEARS Asserted (Testing) + + + + + + +// INTEL +#define PENTIUM_FAMILY 5 // define for pentium +#define PENTIUMPRO_FAMILY 6 // define for pentium pro +#define PENTIUM4_FAMILY 15 // define for pentium 4 + + +// AMD +#define K6_FAMILY 5 +#define K8_FAMILY 6 +#define EXTENDED_FAMILY 15 // AMD 64 and AMD Opteron + +#endif // P5P6PERFORMANCECOUNTERS_H diff --git a/public/tier0/PMELib.h b/public/tier0/PMELib.h new file mode 100644 index 0000000..5eeb63c --- /dev/null +++ b/public/tier0/PMELib.h @@ -0,0 +1,192 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef PMELIB_H +#define PMELIB_H + +#include "Windows.h" +#include "tier0/platform.h" + +// Get rid of a bunch of STL warnings! +#pragma warning( push, 3 ) +#pragma warning( disable : 4018 ) + +#define VERSION "1.0.2" + +// uncomment this list to add some runtime checks +//#define PME_DEBUG + +#include "tier0/valve_off.h" +#include +#include "tier0/valve_on.h" + +using namespace std; + +// RDTSC Instruction macro +#define RDTSC(var) var = __rdtsc() + +// RDPMC Instruction macro +#define RDPMC(counter, var) \ +_asm mov ecx, counter \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx + +// RDPMC Instruction macro, for performance counter 1 (ecx = 1) +#define RDPMC0(var) \ +_asm mov ecx, 0 \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx + +#define RDPMC1(var) \ +_asm mov ecx, 1 \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx + +#define EVENT_TYPE(mode) EventType##mode +#define EVENT_MASK(mode) EventMask##mode + +#include "ia32detect.h" + +enum ProcessPriority +{ + ProcessPriorityNormal, + ProcessPriorityHigh, +}; + +enum PrivilegeCapture +{ + OS_Only, // ring 0, kernel level + USR_Only, // app level + OS_and_USR, // all levels +}; + +enum CompareMethod +{ + CompareGreater, // + CompareLessEqual, // +}; + +enum EdgeState +{ + RisingEdgeDisabled, // + RisingEdgeEnabled, // +}; + +enum CompareState +{ + CompareDisable, // + CompareEnable, // +}; + +// Singletion Class +class PME : public ia32detect +{ +public: +//private: + + static PME* _singleton; + + HANDLE hFile; + bool bDriverOpen; + double m_CPUClockSpeed; + + //ia32detect detect; + HRESULT Init(); + HRESULT Close(); + +protected: + + PME() + { + hFile = NULL; + bDriverOpen = FALSE; + m_CPUClockSpeed = 0; + Init(); + } + +public: + + static PME* Instance(); // gives back a real object + + ~PME() + { + Close(); + } + + double GetCPUClockSpeedSlow( void ); + double GetCPUClockSpeedFast( void ); + + HRESULT SelectP5P6PerformanceEvent( uint32 dw_event, uint32 dw_counter, bool b_user, bool b_kernel ); + + HRESULT ReadMSR( uint32 dw_reg, int64 * pi64_value ); + HRESULT ReadMSR( uint32 dw_reg, uint64 * pi64_value ); + + HRESULT WriteMSR( uint32 dw_reg, const int64 & i64_value ); + HRESULT WriteMSR( uint32 dw_reg, const uint64 & i64_value ); + + void SetProcessPriority( ProcessPriority priority ) + { + switch( priority ) + { + case ProcessPriorityNormal: + { + SetPriorityClass (GetCurrentProcess(),NORMAL_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_NORMAL); + break; + } + case ProcessPriorityHigh: + { + SetPriorityClass (GetCurrentProcess(),REALTIME_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_HIGHEST); + break; + } + } + } + + //--------------------------------------------------------------------------- + // Return the family of the processor + //--------------------------------------------------------------------------- + CPUVendor GetVendor(void) + { + return vendor; + } + + int GetProcessorFamily(void) + { + return version.Family; + } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +}; + +#include "P5P6PerformanceCounters.h" +#include "P4PerformanceCounters.h" +#include "K8PerformanceCounters.h" + +enum PerfErrors +{ + E_UNKNOWN_CPU_VENDOR = -1, + E_BAD_COUNTER = -2, + E_UNKNOWN_CPU = -3, + E_CANT_OPEN_DRIVER = -4, + E_DRIVER_ALREADY_OPEN = -5, + E_DRIVER_NOT_OPEN = -6, + E_DISABLED = -7, + E_BAD_DATA = -8, + E_CANT_CLOSE = -9, + E_ILLEGAL_OPERATION = -10, +}; + +#pragma warning( pop ) + +#endif // PMELIB_H \ No newline at end of file diff --git a/public/tier0/afxmem_override.cpp b/public/tier0/afxmem_override.cpp new file mode 100644 index 0000000..f5794b2 --- /dev/null +++ b/public/tier0/afxmem_override.cpp @@ -0,0 +1,456 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// File extracted from MFC due to symbol conflicts + +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + +#include "stdafx.h" + +#ifdef AFX_CORE1_SEG +#pragma code_seg(AFX_CORE1_SEG) +#endif + + +///////////////////////////////////////////////////////////////////////////// +// Debug memory globals and implementation helpers + +#ifdef _DEBUG // most of this file is for debugging + +void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine); +#if _MSC_VER >= 1210 +void* __cdecl operator new[](size_t nSize, int nType, LPCSTR lpszFileName, int nLine); +#endif + +///////////////////////////////////////////////////////////////////////////// +// test allocation routines + +void* PASCAL CObject::operator new(size_t nSize) +{ +#ifdef _AFX_NO_DEBUG_CRT + return ::operator new(nSize); +#else + return ::operator new(nSize, _AFX_CLIENT_BLOCK, NULL, 0); +#endif // _AFX_NO_DEBUG_CRT +} + +void PASCAL CObject::operator delete(void* p) +{ +#ifdef _AFX_NO_DEBUG_CRT + free(p); +#else + _free_dbg(p, _AFX_CLIENT_BLOCK); +#endif +} + +#if _MSC_VER >= 1200 +void PASCAL CObject::operator delete(void* p, void*) +{ +#ifdef _AFX_NO_DEBUG_CRT + free(p); +#else + _free_dbg(p, _AFX_CLIENT_BLOCK); +#endif +} +#endif + +#ifndef _AFX_NO_DEBUG_CRT + +void* __cdecl operator new(size_t nSize, LPCSTR lpszFileName, int nLine) +{ + return ::operator new(nSize, _NORMAL_BLOCK, lpszFileName, nLine); +} + +#if _MSC_VER >= 1210 +void* __cdecl operator new[](size_t nSize, LPCSTR lpszFileName, int nLine) +{ + return ::operator new[](nSize, _NORMAL_BLOCK, lpszFileName, nLine); +} +#endif + +#if _MSC_VER >= 1200 +void __cdecl operator delete(void* pData, LPCSTR /* lpszFileName */, + int /* nLine */) +{ + ::operator delete(pData); +} +#endif + +#if _MSC_VER >= 1210 +void __cdecl operator delete[](void* pData, LPCSTR /* lpszFileName */, + int /* nLine */) +{ + ::operator delete(pData); +} +#endif + +void* PASCAL +CObject::operator new(size_t nSize, LPCSTR lpszFileName, int nLine) +{ + return ::operator new(nSize, _AFX_CLIENT_BLOCK, lpszFileName, nLine); +} + +#if _MSC_VER >= 1200 +void PASCAL +CObject::operator delete(void *pObject, LPCSTR /* lpszFileName */, + int /* nLine */) +{ +#ifdef _AFX_NO_DEBUG_CRT + free(pObject); +#else + _free_dbg(pObject, _AFX_CLIENT_BLOCK); +#endif +} +#endif + +void* AFXAPI AfxAllocMemoryDebug(size_t nSize, BOOL bIsObject, LPCSTR lpszFileName, int nLine) +{ + return _malloc_dbg(nSize, bIsObject ? _AFX_CLIENT_BLOCK : _NORMAL_BLOCK, + lpszFileName, nLine); +} + +void AFXAPI AfxFreeMemoryDebug(void* pbData, BOOL bIsObject) +{ + _free_dbg(pbData, bIsObject ? _AFX_CLIENT_BLOCK : _NORMAL_BLOCK); +} + +///////////////////////////////////////////////////////////////////////////// +// allocation failure hook, tracking turn on + +BOOL AFXAPI _AfxDefaultAllocHook(size_t, BOOL, LONG) + { return TRUE; } + +AFX_STATIC_DATA AFX_ALLOC_HOOK pfnAllocHook = _AfxDefaultAllocHook; + +AFX_STATIC_DATA _CRT_ALLOC_HOOK pfnCrtAllocHook = NULL; +#if _MSC_VER >= 1200 +int __cdecl _AfxAllocHookProxy(int nAllocType, void * pvData, size_t nSize, + int nBlockUse, long lRequest, const unsigned char * szFilename, int nLine) +#else +int __cdecl _AfxAllocHookProxy(int nAllocType, void * pvData, size_t nSize, + int nBlockUse, long lRequest, const char * szFilename, int nLine) +#endif +{ +#if _MSC_VER >= 1200 + if (nAllocType != _HOOK_ALLOC) + return (pfnCrtAllocHook)(nAllocType, pvData, nSize, + nBlockUse, lRequest, (const unsigned char*) szFilename, nLine); + if ((pfnAllocHook)(nSize, _BLOCK_TYPE(nBlockUse) == _AFX_CLIENT_BLOCK, lRequest)) + return (pfnCrtAllocHook)(nAllocType, pvData, nSize, + nBlockUse, lRequest, (const unsigned char*) szFilename, nLine); +#else + if (nAllocType != _HOOK_ALLOC) + return (pfnCrtAllocHook)(nAllocType, pvData, nSize, + nBlockUse, lRequest, szFilename, nLine); + if ((pfnAllocHook)(nSize, _BLOCK_TYPE(nBlockUse) == _AFX_CLIENT_BLOCK, lRequest)) + return (pfnCrtAllocHook)(nAllocType, pvData, nSize, + nBlockUse, lRequest, szFilename, nLine); +#endif + return FALSE; +} + +AFX_ALLOC_HOOK AFXAPI AfxSetAllocHook(AFX_ALLOC_HOOK pfnNewHook) +{ + if (pfnCrtAllocHook == NULL) + pfnCrtAllocHook = _CrtSetAllocHook(_AfxAllocHookProxy); + + AFX_ALLOC_HOOK pfnOldHook = pfnAllocHook; + pfnAllocHook = pfnNewHook; + return pfnOldHook; +} + +// This can be set to TRUE to override all AfxEnableMemoryTracking calls, +// allowing all allocations, even MFC internal allocations to be tracked. +BOOL _afxMemoryLeakOverride = FALSE; + +BOOL AFXAPI AfxEnableMemoryTracking(BOOL bTrack) +{ + if (_afxMemoryLeakOverride) + return TRUE; + + int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + if (bTrack) + _CrtSetDbgFlag(nOldState | _CRTDBG_ALLOC_MEM_DF); + else + _CrtSetDbgFlag(nOldState & ~_CRTDBG_ALLOC_MEM_DF); + return nOldState & _CRTDBG_ALLOC_MEM_DF; +} + +///////////////////////////////////////////////////////////////////////////// +// stop on a specific memory request + +// Obsolete API +void AFXAPI AfxSetAllocStop(LONG lRequestNumber) +{ + _CrtSetBreakAlloc(lRequestNumber); +} + +BOOL AFXAPI AfxCheckMemory() + // check all of memory (look for memory tromps) +{ + return _CrtCheckMemory(); +} + +// -- true if block of exact size, allocated on the heap +// -- set *plRequestNumber to request number (or 0) +BOOL AFXAPI AfxIsMemoryBlock(const void* pData, UINT nBytes, + LONG* plRequestNumber) +{ + return _CrtIsMemoryBlock(pData, nBytes, plRequestNumber, NULL, NULL); +} + +///////////////////////////////////////////////////////////////////////////// +// CMemoryState + +CMemoryState::CMemoryState() +{ + memset(this, 0, sizeof(*this)); +} + +void CMemoryState::UpdateData() +{ + for(int i = 0; i < nBlockUseMax; i++) + { + m_lCounts[i] = m_memState.lCounts[i]; + m_lSizes[i] = m_memState.lSizes[i]; + } + m_lHighWaterCount = m_memState.lHighWaterCount; + m_lTotalCount = m_memState.lTotalCount; +} + +// fills 'this' with the difference, returns TRUE if significant +BOOL CMemoryState::Difference(const CMemoryState& oldState, + const CMemoryState& newState) +{ + int nResult = _CrtMemDifference(&m_memState, &oldState.m_memState, &newState.m_memState); + UpdateData(); + return nResult != 0; +} + +void CMemoryState::DumpStatistics() const +{ + _CrtMemDumpStatistics(&m_memState); +} + +// -- fill with current memory state +void CMemoryState::Checkpoint() +{ + _CrtMemCheckpoint(&m_memState); + UpdateData(); +} + +// Dump objects created after this memory state was checkpointed +// Will dump all objects if this memory state wasn't checkpointed +// Dump all objects, report about non-objects also +// List request number in {} +void CMemoryState::DumpAllObjectsSince() const +{ + _CrtMemDumpAllObjectsSince(&m_memState); +} + +///////////////////////////////////////////////////////////////////////////// +// Enumerate all objects allocated in the diagnostic memory heap + +struct _AFX_ENUM_CONTEXT +{ + void (*m_pfn)(CObject*,void*); + void* m_pContext; +}; + +AFX_STATIC void _AfxDoForAllObjectsProxy(void* pObject, void* pContext) +{ + _AFX_ENUM_CONTEXT* p = (_AFX_ENUM_CONTEXT*)pContext; + (*p->m_pfn)((CObject*)pObject, p->m_pContext); +} + +void AFXAPI +AfxDoForAllObjects(void (AFX_CDECL *pfn)(CObject*, void*), void* pContext) +{ + if (pfn == NULL) + { + AfxThrowInvalidArgException(); + } + _AFX_ENUM_CONTEXT context; + context.m_pfn = pfn; + context.m_pContext = pContext; + _CrtDoForAllClientObjects(_AfxDoForAllObjectsProxy, &context); +} + +///////////////////////////////////////////////////////////////////////////// +// Automatic debug memory diagnostics + +BOOL AFXAPI AfxDumpMemoryLeaks() +{ + return _CrtDumpMemoryLeaks(); +} + +#endif // _AFX_NO_DEBUG_CRT +#endif // _DEBUG + +///////////////////////////////////////////////////////////////////////////// +// Non-diagnostic memory routines + +int AFX_CDECL AfxNewHandler(size_t /* nSize */) +{ + AfxThrowMemoryException(); +} + +#pragma warning(disable: 4273) + +#ifndef _AFXDLL +_PNH _afxNewHandler = &AfxNewHandler; +#endif + +_PNH AFXAPI AfxGetNewHandler(void) +{ +#ifdef _AFXDLL + AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); + return pState->m_pfnNewHandler; +#else + return _afxNewHandler; +#endif +} + +_PNH AFXAPI AfxSetNewHandler(_PNH pfnNewHandler) +{ +#ifdef _AFXDLL + AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); + _PNH pfnOldHandler = pState->m_pfnNewHandler; + pState->m_pfnNewHandler = pfnNewHandler; + return pfnOldHandler; +#else + _PNH pfnOldHandler = _afxNewHandler; + _afxNewHandler = pfnNewHandler; + return pfnOldHandler; +#endif +} + +AFX_STATIC_DATA const _PNH _pfnUninitialized = (_PNH)-1; + +void* __cdecl operator new(size_t nSize) +{ + void* pResult; +#ifdef _AFXDLL + _PNH pfnNewHandler = _pfnUninitialized; +#endif + for (;;) + { +#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG) + pResult = _malloc_dbg(nSize, _NORMAL_BLOCK, NULL, 0); +#else + pResult = malloc(nSize); +#endif + if (pResult != NULL) + return pResult; + +#ifdef _AFXDLL + if (pfnNewHandler == _pfnUninitialized) + { + AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); + pfnNewHandler = pState->m_pfnNewHandler; + } + if (pfnNewHandler == NULL || (*pfnNewHandler)(nSize) == 0) + break; +#else + if (_afxNewHandler == NULL || (*_afxNewHandler)(nSize) == 0) + break; +#endif + } + return pResult; +} + +void __cdecl operator delete(void* p) +{ +#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG) + _free_dbg(p, _NORMAL_BLOCK); +#else + free(p); +#endif +} + +#if _MSC_VER >= 1210 +void* __cdecl operator new[](size_t nSize) +{ + return ::operator new(nSize); +} + +void __cdecl operator delete[](void* p) +{ + ::operator delete(p); +} +#endif + +#ifdef _DEBUG + +void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine) +{ +#ifdef _AFX_NO_DEBUG_CRT + UNUSED_ALWAYS(nType); + UNUSED_ALWAYS(lpszFileName); + UNUSED_ALWAYS(nLine); + return ::operator new(nSize); +#else + void* pResult; +#ifdef _AFXDLL + _PNH pfnNewHandler = _pfnUninitialized; +#endif + for (;;) + { + pResult = _malloc_dbg(nSize, nType, lpszFileName, nLine); + if (pResult != NULL) + return pResult; + +#ifdef _AFXDLL + if (pfnNewHandler == _pfnUninitialized) + { + AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); + pfnNewHandler = pState->m_pfnNewHandler; + } + if (pfnNewHandler == NULL || (*pfnNewHandler)(nSize) == 0) + break; +#else + if (_afxNewHandler == NULL || (*_afxNewHandler)(nSize) == 0) + break; +#endif + } + return pResult; +#endif +} + +#if _MSC_VER >= 1700 +void __cdecl operator delete(void* p, int nType, LPCSTR /* lpszFileName */, int /* nLine */) +{ +#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG) + _free_dbg(p, nType); +#else + free(p); +#endif +} +#endif // _MSC_VER >= 1200 + +#if _MSC_VER >= 1700 +void* __cdecl operator new[](size_t nSize, int nType, LPCSTR lpszFileName, int nLine) +{ + return ::operator new(nSize, nType, lpszFileName, nLine); +} +void __cdecl operator delete[](void* p, int nType, LPCSTR lpszFileName, int nLine) +{ + ::operator delete(p, nType, lpszFileName, nLine); +} +#endif // _MSC_VER >= 1210 + +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// diff --git a/public/tier0/annotations.h b/public/tier0/annotations.h new file mode 100644 index 0000000..7e0f469 --- /dev/null +++ b/public/tier0/annotations.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef ANALYSIS_ANNOTATIONS_H +#define ANALYSIS_ANNOTATIONS_H + +#if _MSC_VER >= 1600 // VS 2010 and above. +//----------------------------------------------------------------------------- +// Upgrading important helpful warnings to errors +//----------------------------------------------------------------------------- +#pragma warning(error : 4789 ) // warning C4789: destination of memory copy is too small + +// Suppress some code analysis warnings +#ifdef _PREFAST_ +// Include the annotation header file. +#include + +// For temporarily suppressing warnings -- the warnings are suppressed for the next source line. +#define ANALYZE_SUPPRESS(wnum) __pragma(warning(suppress: wnum)) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) __pragma(warning(supress: wnum1 wnum2)) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) __pragma(warning(suppress: wnum1 wnum2 wnum3)) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) __pragma(warning(suppress: wnum1 wnum2 wnum3 wnum4)) + +// Tag all printf style format strings with this +#define PRINTF_FORMAT_STRING _Printf_format_string_ +#define SCANF_FORMAT_STRING _Scanf_format_string_impl_ +// Various macros for specifying the capacity of the buffer pointed +// to by a function parameter. Variations include in/out/inout, +// CAP (elements) versus BYTECAP (bytes), and null termination or +// not (_Z). +#define IN_Z _In_z_ +#define IN_CAP(x) _In_count_(x) +#define IN_BYTECAP(x) _In_bytecount_(x) +#define OUT_Z_CAP(x) _Out_z_cap_(x) +#define OUT_CAP(x) _Out_cap_(x) +#define OUT_CAP_C(x) _Out_cap_c_(x) // Output buffer with specified *constant* capacity in elements +#define OUT_BYTECAP(x) _Out_bytecap_(x) +#define OUT_Z_BYTECAP(x) _Out_z_bytecap_(x) +#define INOUT_BYTECAP(x) _Inout_bytecap_(x) +#define INOUT_Z_CAP(x) _Inout_z_cap_(x) +#define INOUT_Z_BYTECAP(x) _Inout_z_bytecap_(x) +// These macros are use for annotating array reference parameters, typically used in functions +// such as V_strcpy_safe. Because they are array references the capacity is already known. +#if _MSC_VER >= 1700 +#define IN_Z_ARRAY _Pre_z_ +#define OUT_Z_ARRAY _Post_z_ +#define INOUT_Z_ARRAY _Prepost_z_ +#else +#define IN_Z_ARRAY _Deref_pre_z_ +#define OUT_Z_ARRAY _Deref_post_z_ +#define INOUT_Z_ARRAY _Deref_prepost_z_ +#endif // _MSC_VER >= 1700 +// Used for annotating functions to describe their return types. +#define MUST_CHECK_RETURN _Check_return_ +// Use the macros above to annotate string functions that fill buffers as shown here, +// in order to give VS's /analyze more opportunities to find bugs. +// void V_wcsncpy( OUT_Z_BYTECAP(maxLenInBytes) wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes ); +// int V_snwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, ... ); + +#endif // _PREFAST_ +#endif // _MSC_VER >= 1600 // VS 2010 and above. + +#ifndef ANALYZE_SUPPRESS +#define ANALYZE_SUPPRESS(wnum) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) +#define PRINTF_FORMAT_STRING +#define SCANF_FORMAT_STRING +#define IN_Z +#define IN_CAP(x) +#define IN_BYTECAP(x) +#define OUT_Z_CAP(x) +#define OUT_CAP(x) +#define OUT_CAP_C(x) +#define OUT_BYTECAP(x) +#define OUT_Z_BYTECAP(x) +#define INOUT_BYTECAP(x) +#define INOUT_Z_CAP(x) +#define INOUT_Z_BYTECAP(x) +#define OUT_Z_ARRAY +#define INOUT_Z_ARRAY +#define MUST_CHECK_RETURN +#endif + +#endif // ANALYSIS_ANNOTATIONS_H diff --git a/public/tier0/basetypes.h b/public/tier0/basetypes.h new file mode 100644 index 0000000..9939845 --- /dev/null +++ b/public/tier0/basetypes.h @@ -0,0 +1,398 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASETYPES_H +#define BASETYPES_H + +#include "commonmacros.h" +#include "wchartypes.h" + +#include "tier0/valve_off.h" + +#ifdef _WIN32 +#pragma once +#endif + + +// This is a trick to get the DLL extension off the -D option on the command line. +#define DLLExtTokenPaste(x) #x +#define DLLExtTokenPaste2(x) DLLExtTokenPaste(x) +#define DLL_EXT_STRING DLLExtTokenPaste2( _DLL_EXT ) + + +#include "protected_things.h" + +// There's a different version of this file in the xbox codeline +// so the PC version built in the xbox branch includes things like +// tickrate changes. +#include "xbox_codeline_defines.h" + +#ifdef IN_XBOX_CODELINE +#define XBOX_CODELINE_ONLY() +#else +#define XBOX_CODELINE_ONLY() Error_Compiling_Code_Only_Valid_in_Xbox_Codeline +#endif + +// stdio.h +#ifndef NULL +#define NULL 0 +#endif + + +#ifdef POSIX +#include +#endif + +#define ExecuteNTimes( nTimes, x ) \ + { \ + static int __executeCount=0;\ + if ( __executeCount < nTimes )\ + { \ + x; \ + ++__executeCount; \ + } \ + } + + +#define ExecuteOnce( x ) ExecuteNTimes( 1, x ) + + +template +inline T AlignValue( T val, uintptr_t alignment ) +{ + return (T)( ( (uintptr_t)val + alignment - 1 ) & ~( alignment - 1 ) ); +} + + +// Pad a number so it lies on an N byte boundary. +// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +// In case this ever changes +#if !defined(M_PI) && !defined(HAVE_M_PI) +#define M_PI 3.14159265358979323846 +#endif + +#include "valve_minmax_on.h" + +// #define COMPILETIME_MAX and COMPILETIME_MIN for max/min in constant expressions +#define COMPILETIME_MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#define COMPILETIME_MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#ifndef MIN +#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifndef MAX +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifdef __cplusplus + +// This is the preferred clamp operator. Using the clamp macro can lead to +// unexpected side-effects or more expensive code. Even the clamp (all +// lower-case) function can generate more expensive code because of the +// mixed types involved. +template< class T > +T Clamp( T const &val, T const &minVal, T const &maxVal ) +{ + if( val < minVal ) + return minVal; + else if( val > maxVal ) + return maxVal; + else + return val; +} + +// This is the preferred Min operator. Using the MIN macro can lead to unexpected +// side-effects or more expensive code. +template< class T > +T Min( T const &val1, T const &val2 ) +{ + return val1 < val2 ? val1 : val2; +} + +// This is the preferred Max operator. Using the MAX macro can lead to unexpected +// side-effects or more expensive code. +template< class T > +T Max( T const &val1, T const &val2 ) +{ + return val1 > val2 ? val1 : val2; +} + +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + + +#ifndef DONT_DEFINE_BOOL // Needed for Cocoa stuff to compile. +typedef int BOOL; +#endif + +typedef int qboolean; +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned short word; +#ifdef _WIN32 +typedef wchar_t ucs2; // under windows wchar_t is ucs2 +#else +typedef unsigned short ucs2; +#endif + +enum ThreeState_t +{ + TRS_FALSE, + TRS_TRUE, + TRS_NONE, +}; + +typedef float vec_t; + +#if defined(__GNUC__) +#define fpmin __builtin_fminf +#define fpmax __builtin_fmaxf +#elif !defined(_X360) +#define fpmin vmin +#define fpmax vmax +#endif + + +//----------------------------------------------------------------------------- +// look for NANs, infinities, and underflows. +// This assumes the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- + +inline unsigned long& FloatBits( vec_t& f ) +{ + return *reinterpret_cast(&f); +} + +inline unsigned long const& FloatBits( vec_t const& f ) +{ + return *reinterpret_cast(&f); +} + +inline vec_t BitsToFloat( unsigned long i ) +{ + return *reinterpret_cast(&i); +} + +inline bool IsFinite( vec_t f ) +{ + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +} + +inline unsigned long FloatAbsBits( vec_t f ) +{ + return FloatBits(f) & 0x7FFFFFFF; +} + +// Given today's processors, I cannot think of any circumstance +// where bit tricks would be faster than fabs. henryg 8/16/2011 +#ifdef _MSC_VER +#ifndef _In_ +#define _In_ +#endif +extern "C" float fabsf(_In_ float); +#else +#include +#endif + +inline float FloatMakeNegative( vec_t f ) +{ + return -fabsf(f); +} + +inline float FloatMakePositive( vec_t f ) +{ + return fabsf(f); +} + +inline float FloatNegate( vec_t f ) +{ + return -f; +} + + +#define FLOAT32_NAN_BITS (unsigned long)0x7FC00000 // not a number! +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) + +#define VEC_T_NAN FLOAT32_NAN + + + +// FIXME: why are these here? Hardly anyone actually needs them. +struct color24 +{ + byte r, g, b; +}; + +typedef struct color32_s +{ + bool operator!=( const struct color32_s &other ) const; + + byte r, g, b, a; +} color32; + +inline bool color32::operator!=( const color32 &other ) const +{ + return r != other.r || g != other.g || b != other.b || a != other.a; +} + +struct colorVec +{ + unsigned r, g, b, a; +}; + + +#ifndef NOTE_UNUSED +#define NOTE_UNUSED(x) (void)(x) // for pesky compiler / lint warnings +#endif + +struct vrect_t +{ + int x,y,width,height; + vrect_t *pnext; +}; + + +//----------------------------------------------------------------------------- +// MaterialRect_t struct - used for DrawDebugText +//----------------------------------------------------------------------------- +struct Rect_t +{ + int x, y; + int width, height; +}; + + +//----------------------------------------------------------------------------- +// Interval, used by soundemittersystem + the game +//----------------------------------------------------------------------------- +struct interval_t +{ + float start; + float range; +}; + + +//----------------------------------------------------------------------------- +// Declares a type-safe handle type; you can't assign one handle to the next +//----------------------------------------------------------------------------- + +// 32-bit pointer handles. + +// Typesafe 8-bit and 16-bit handles. +template< class HandleType > +class CBaseIntHandle +{ +public: + + inline bool operator==( const CBaseIntHandle &other ) { return m_Handle == other.m_Handle; } + inline bool operator!=( const CBaseIntHandle &other ) { return m_Handle != other.m_Handle; } + + // Only the code that doles out these handles should use these functions. + // Everyone else should treat them as a transparent type. + inline HandleType GetHandleValue() { return m_Handle; } + inline void SetHandleValue( HandleType val ) { m_Handle = val; } + + typedef HandleType HANDLE_TYPE; + +protected: + + HandleType m_Handle; +}; + +template< class DummyType > +class CIntHandle16 : public CBaseIntHandle< unsigned short > +{ +public: + inline CIntHandle16() {} + + static inline CIntHandle16 MakeHandle( HANDLE_TYPE val ) + { + return CIntHandle16( val ); + } + +protected: + inline CIntHandle16( HANDLE_TYPE val ) + { + m_Handle = val; + } +}; + + +template< class DummyType > +class CIntHandle32 : public CBaseIntHandle< unsigned long > +{ +public: + inline CIntHandle32() {} + + static inline CIntHandle32 MakeHandle( HANDLE_TYPE val ) + { + return CIntHandle32( val ); + } + +protected: + inline CIntHandle32( HANDLE_TYPE val ) + { + m_Handle = val; + } +}; + + +// NOTE: This macro is the same as windows uses; so don't change the guts of it +#define DECLARE_HANDLE_16BIT(name) typedef CIntHandle16< struct name##__handle * > name; +#define DECLARE_HANDLE_32BIT(name) typedef CIntHandle32< struct name##__handle * > name; + +#define DECLARE_POINTER_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#define FORWARD_DECLARE_HANDLE(name) typedef struct name##__ *name + +// @TODO: Find a better home for this +#if !defined(_STATIC_LINKED) && !defined(PUBLISH_DLL_SUBSYSTEM) +// for platforms built with dynamic linking, the dll interface does not need spoofing +#define PUBLISH_DLL_SUBSYSTEM() +#endif + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define EXPAND_CONCAT(a,c) UID_CAT1(a,c) +#ifdef _MSC_VER +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__COUNTER__) +#else +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) +#endif + +// this allows enumerations to be used as flags, and still remain type-safe! +#define DEFINE_ENUM_BITWISE_OPERATORS( Type ) \ + inline Type operator| ( Type a, Type b ) { return Type( int( a ) | int( b ) ); } \ + inline Type operator& ( Type a, Type b ) { return Type( int( a ) & int( b ) ); } \ + inline Type operator^ ( Type a, Type b ) { return Type( int( a ) ^ int( b ) ); } \ + inline Type operator<< ( Type a, int b ) { return Type( int( a ) << b ); } \ + inline Type operator>> ( Type a, int b ) { return Type( int( a ) >> b ); } \ + inline Type &operator|= ( Type &a, Type b ) { return a = a | b; } \ + inline Type &operator&= ( Type &a, Type b ) { return a = a & b; } \ + inline Type &operator^= ( Type &a, Type b ) { return a = a ^ b; } \ + inline Type &operator<<=( Type &a, int b ) { return a = a << b; } \ + inline Type &operator>>=( Type &a, int b ) { return a = a >> b; } \ + inline Type operator~( Type a ) { return Type( ~int( a ) ); } + +// defines increment/decrement operators for enums for easy iteration +#define DEFINE_ENUM_INCREMENT_OPERATORS( Type ) \ + inline Type &operator++( Type &a ) { return a = Type( int( a ) + 1 ); } \ + inline Type &operator--( Type &a ) { return a = Type( int( a ) - 1 ); } \ + inline Type operator++( Type &a, int ) { Type t = a; ++a; return t; } \ + inline Type operator--( Type &a, int ) { Type t = a; --a; return t; } + +#include "tier0/valve_on.h" + +#endif // BASETYPES_H diff --git a/public/tier0/commonmacros.h b/public/tier0/commonmacros.h new file mode 100644 index 0000000..ffa934a --- /dev/null +++ b/public/tier0/commonmacros.h @@ -0,0 +1,173 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef COMMONMACROS_H +#define COMMONMACROS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// ------------------------------------------------------- +// +// commonmacros.h +// +// This should contain ONLY general purpose macros that are +// appropriate for use in engine/launcher/all tools +// +// ------------------------------------------------------- + +// Makes a 4-byte "packed ID" int out of 4 characters +#define MAKEID(d,c,b,a) ( ((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d)) ) + +// Compares a string with a 4-byte packed ID constant +#define STRING_MATCHES_ID( p, id ) ( (*((int *)(p)) == (id) ) ? true : false ) +#define ID_TO_STRING( id, p ) ( (p)[3] = (((id)>>24) & 0xFF), (p)[2] = (((id)>>16) & 0xFF), (p)[1] = (((id)>>8) & 0xFF), (p)[0] = (((id)>>0) & 0xFF) ) + +#define SETBITS(iBitVector, bits) ((iBitVector) |= (bits)) +#define CLEARBITS(iBitVector, bits) ((iBitVector) &= ~(bits)) +#define FBitSet(iBitVector, bits) ((iBitVector) & (bits)) + +template +inline bool IsPowerOfTwo( T value ) +{ + return (value & ( value - (T)1 )) == (T)0; +} + +#ifndef REFERENCE +#define REFERENCE(arg) ((void)arg) +#endif + +#define CONST_INTEGER_AS_STRING(x) #x //Wraps the integer in quotes, allowing us to form constant strings with it +#define __HACK_LINE_AS_STRING__(x) CONST_INTEGER_AS_STRING(x) //__LINE__ can only be converted to an actual number by going through this, otherwise the output is literally "__LINE__" +#define __LINE__AS_STRING __HACK_LINE_AS_STRING__(__LINE__) //Gives you the line number in constant string form + +// Using ARRAYSIZE implementation from winnt.h: +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif + +// Return the number of elements in a statically sized array. +// DWORD Buffer[100]; +// RTL_NUMBER_OF(Buffer) == 100 +// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc. +// +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) + +#if defined(__cplusplus) && \ + !defined(MIDL_PASS) && \ + !defined(RC_INVOKED) && \ + (_MSC_FULL_VER >= 13009466) && \ + !defined(SORTPP_PASS) + +// From crtdefs.h +#if !defined(UNALIGNED) +#if defined(_M_IA64) || defined(_M_AMD64) +#define UNALIGNED __unaligned +#else +#define UNALIGNED +#endif +#endif + +// RtlpNumberOf is a function that takes a reference to an array of N Ts. +// +// typedef T array_of_T[N]; +// typedef array_of_T &reference_to_array_of_T; +// +// RtlpNumberOf returns a pointer to an array of N chars. +// We could return a reference instead of a pointer but older compilers do not accept that. +// +// typedef char array_of_char[N]; +// typedef array_of_char *pointer_to_array_of_char; +// +// sizeof(array_of_char) == N +// sizeof(*pointer_to_array_of_char) == N +// +// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T); +// +// We never even call RtlpNumberOf, we just take the size of dereferencing its return type. +// We do not even implement RtlpNumberOf, we just decare it. +// +// Attempts to pass pointers instead of arrays to this macro result in compile time errors. +// That is the point. +extern "C++" // templates cannot be declared to have 'C' linkage +template +char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N]; + +#ifdef _PREFAST_ +// The +0 is so that we can go: +// size = ARRAYSIZE(array) * sizeof(array[0]) without triggering a /analyze +// warning about multiplying sizeof. +#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))+0) +#else +#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))) +#endif + +// This does not work with: +// +// void Foo() +// { +// struct { int x; } y[2]; +// RTL_NUMBER_OF_V2(y); // illegal use of anonymous local type in template instantiation +// } +// +// You must instead do: +// +// struct Foo1 { int x; }; +// +// void Foo() +// { +// Foo1 y[2]; +// RTL_NUMBER_OF_V2(y); // ok +// } +// +// OR +// +// void Foo() +// { +// struct { int x; } y[2]; +// RTL_NUMBER_OF_V1(y); // ok +// } +// +// OR +// +// void Foo() +// { +// struct { int x; } y[2]; +// _ARRAYSIZE(y); // ok +// } + +#else +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) +#endif + +// ARRAYSIZE is more readable version of RTL_NUMBER_OF_V2 +// _ARRAYSIZE is a version useful for anonymous types +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#define Q_ARRAYSIZE(p) ARRAYSIZE(p) + +template< typename IndexType, typename T, unsigned int N > +IndexType ClampedArrayIndex( const T (&buffer)[N], IndexType index ) +{ + NOTE_UNUSED( buffer ); + return clamp( index, 0, (IndexType)N - 1 ); +} + +template< typename T, unsigned int N > +T ClampedArrayElement( const T (&buffer)[N], unsigned int uIndex ) +{ + // Put index in an unsigned type to halve the clamping. + if ( uIndex >= N ) + uIndex = N - 1; + return buffer[ uIndex ]; +} + +#endif // COMMONMACROS_H diff --git a/public/tier0/cpumonitoring.h b/public/tier0/cpumonitoring.h new file mode 100644 index 0000000..e6d1c9c --- /dev/null +++ b/public/tier0/cpumonitoring.h @@ -0,0 +1,33 @@ +#ifndef CPU_MONITORING_H +#define CPU_MONITORING_H + +/* +This header defines functions and structures for controlling the measurement of CPU frequency +in order to detect thermal throttling. For details see the associated source file. +*/ + +struct CPUFrequencyResults +{ + double m_timeStamp; // Time (from Plat_FloatTime) when the measurements were made. + float m_GHz; + float m_percentage; + float m_lowestPercentage; +}; + +// Call this to get results. +// When CPU monitoring is 'disabled' it may still be running at a low frequency, +// for OGS purposes or for proactively warning users of problems. If fGetDisabledResults +// is true then results will be returned when disabled (if available). +PLATFORM_INTERFACE CPUFrequencyResults GetCPUFrequencyResults( bool fGetDisabledResults = false ); + +// Call this to set the monitoring frequency. Intervals of 2-5 seconds (2,000 to 5,000 ms) +// are recommended. An interval of zero will disable CPU monitoring. Short delays (below +// about 300 ms) will be rounded up. +PLATFORM_INTERFACE void SetCPUMonitoringInterval( unsigned nDelayMilliseconds ); + +// Warn with increasing strident colors when CPU percentages go below these levels. +// They are const int instead of float because const float in C++ is stupid. +const int kCPUMonitoringWarning1 = 80; +const int kCPUMonitoringWarning2 = 50; + +#endif diff --git a/public/tier0/dbg.h b/public/tier0/dbg.h new file mode 100644 index 0000000..8bc0d36 --- /dev/null +++ b/public/tier0/dbg.h @@ -0,0 +1,826 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "dbgflag.h" +#include "platform.h" +#include +#include +#include + +#ifdef POSIX +#define __cdecl +#endif + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- +#ifndef STATIC_TIER0 + +#ifdef TIER0_DLL_EXPORT +#define DBG_INTERFACE DLL_EXPORT +#define DBG_OVERLOAD DLL_GLOBAL_EXPORT +#define DBG_CLASS DLL_CLASS_EXPORT +#else +#define DBG_INTERFACE DLL_IMPORT +#define DBG_OVERLOAD DLL_GLOBAL_IMPORT +#define DBG_CLASS DLL_CLASS_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define DBG_INTERFACE extern +#define DBG_OVERLOAD +#define DBG_CLASS +#endif // BUILD_AS_DLL + + +class Color; + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Spew. +// +// Spew can be used in a static and a dynamic mode. The static +// mode allows us to display assertions and other messages either only +// in debug builds, or in non-release builds. The dynamic mode allows us to +// turn on and off certain spew messages while the application is running. +// +// Static Spew messages: +// +// Assertions are used to detect and warn about invalid states +// Spews are used to display a particular status/warning message. +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// To use a warning, use +// +// Warning("Oh I feel so %s all over\n", "yummy"); +// +// Warning will do its magic in only Debug builds. To perform spew in *all* +// builds, use RelWarning. +// +// Three other spew types, Msg, Log, and Error, are compiled into all builds. +// These error types do *not* need two sets of parenthesis. +// +// Msg( "Isn't this exciting %d?", 5 ); +// Error( "I'm just thrilled" ); +// +// Dynamic Spew messages +// +// It is possible to dynamically turn spew on and off. Dynamic spew is +// identified by a spew group and priority level. To turn spew on for a +// particular spew group, use SpewActivate( "group", level ). This will +// cause all spew in that particular group with priority levels <= the +// level specified in the SpewActivate function to be printed. Use DSpew +// to perform the spew: +// +// DWarning( "group", level, "Oh I feel even yummier!\n" ); +// +// Priority level 0 means that the spew will *always* be printed, and group +// '*' is the default spew group. If a DWarning is encountered using a group +// whose priority has not been set, it will use the priority of the default +// group. The priority of the default group is initially set to 0. +// +// Spew output +// +// The output of the spew system can be redirected to an externally-supplied +// function which is responsible for outputting the spew. By default, the +// spew is simply printed using printf. +// +// To redirect spew output, call SpewOutput. +// +// SpewOutputFunc( OutputFunc ); +// +// This will cause OutputFunc to be called every time a spew message is +// generated. OutputFunc will be passed a spew type and a message to print. +// It must return a value indicating whether the debugger should be invoked, +// whether the program should continue running, or whether the program +// should abort. +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +/* Various types of spew messages */ +// I'm sure you're asking yourself why SPEW_ instead of DBG_ ? +// It's because DBG_ is used all over the place in windows.h +// For example, DBG_CONTINUE is defined. Feh. +enum SpewType_t +{ + SPEW_MESSAGE = 0, + SPEW_WARNING, + SPEW_ASSERT, + SPEW_ERROR, + SPEW_LOG, + + SPEW_TYPE_COUNT +}; + +enum SpewRetval_t +{ + SPEW_DEBUGGER = 0, + SPEW_CONTINUE, + SPEW_ABORT +}; + +/* type of externally defined function used to display debug spew */ +typedef SpewRetval_t (*SpewOutputFunc_t)( SpewType_t spewType, const tchar *pMsg ); + +/* Used to redirect spew output */ +DBG_INTERFACE void SpewOutputFunc( SpewOutputFunc_t func ); + +/* Used to get the current spew output function */ +DBG_INTERFACE SpewOutputFunc_t GetSpewOutputFunc( void ); + +/* This is the default spew fun, which is used if you don't specify one */ +DBG_INTERFACE SpewRetval_t DefaultSpewFunc( SpewType_t type, const tchar *pMsg ); + +/* Same as the default spew func, but returns SPEW_ABORT for asserts */ +DBG_INTERFACE SpewRetval_t DefaultSpewFuncAbortOnAsserts( SpewType_t type, const tchar *pMsg ); + +/* Should be called only inside a SpewOutputFunc_t, returns groupname, level, color */ +DBG_INTERFACE const tchar* GetSpewOutputGroup( void ); +DBG_INTERFACE int GetSpewOutputLevel( void ); +DBG_INTERFACE const Color* GetSpewOutputColor( void ); + +/* Used to manage spew groups and subgroups */ +DBG_INTERFACE void SpewActivate( const tchar* pGroupName, int level ); +DBG_INTERFACE bool IsSpewActive( const tchar* pGroupName, int level ); + +/* Used to display messages, should never be called directly. */ +DBG_INTERFACE void _SpewInfo( SpewType_t type, const tchar* pFile, int line ); +DBG_INTERFACE SpewRetval_t _SpewMessage( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE SpewRetval_t _DSpewMessage( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 ); +DBG_INTERFACE SpewRetval_t ColorSpewMessage( SpewType_t type, const Color *pColor, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 ); +DBG_INTERFACE void _ExitOnFatalAssert( const tchar* pFile, int line ); +DBG_INTERFACE bool ShouldUseNewAssertDialog(); + +DBG_INTERFACE bool SetupWin32ConsoleIO(); + +// Returns true if they want to break in the debugger. +DBG_INTERFACE bool DoNewAssertDialog( const tchar *pFile, int line, const tchar *pExpression ); + +// Allows the assert dialogs to be turned off from code +DBG_INTERFACE bool AreAllAssertsDisabled(); +DBG_INTERFACE void SetAllAssertsDisabled( bool bAssertsEnabled ); + +// Provides a callback that is called on asserts regardless of spew levels +typedef void (*AssertFailedNotifyFunc_t)( const char *pchFile, int nLine, const char *pchMessage ); +DBG_INTERFACE void SetAssertFailedNotifyFunc( AssertFailedNotifyFunc_t func ); +DBG_INTERFACE void CallAssertFailedNotifyFunc( const char *pchFile, int nLine, const char *pchMessage ); + +/* True if -hushasserts was passed on command line. */ +DBG_INTERFACE bool HushAsserts(); + +#if defined( USE_SDL ) +DBG_INTERFACE void SetAssertDialogParent( struct SDL_Window *window ); +DBG_INTERFACE struct SDL_Window * GetAssertDialogParent(); +#endif + +/* Used to define macros, never use these directly. */ + +#ifdef _PREFAST_ + // When doing /analyze builds define _AssertMsg to be __analysis_assume. This tells + // the compiler to assume that the condition is true, which helps to suppress many + // warnings. This define is done in debug and release builds. + // The unfortunate !! is necessary because otherwise /analyze is incapable of evaluating + // all of the logical expressions that the regular compiler can handle. + // Include _msg in the macro so that format errors in it are detected. + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0) + #define _AssertMsgOnce( _exp, _msg, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0) + // Force asserts on for /analyze so that we get a __analysis_assume of all of the constraints. + #define DBGFLAG_ASSERT + #define DBGFLAG_ASSERTFATAL + #define DBGFLAG_ASSERTDEBUG +#else + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __TFILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("%s", static_cast( _msg )); \ + CallAssertFailedNotifyFunc( __TFILE__, __LINE__, _msg ); \ + _executeExp; \ + if ( ret == SPEW_DEBUGGER) \ + { \ + if ( !ShouldUseNewAssertDialog() || DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + { \ + DebuggerBreak(); \ + } \ + if ( _bFatal ) \ + { \ + _ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } \ + } while (0) + + #define _AssertMsgOnce( _exp, _msg, _bFatal ) \ + do { \ + static bool fAsserted; \ + if (!fAsserted ) \ + { \ + _AssertMsg( _exp, _msg, (fAsserted = true), _bFatal ); \ + } \ + } while (0) +#endif + +/* Spew macros... */ + +// AssertFatal macros +// AssertFatal is used to detect an unrecoverable error condition. +// If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned on or running under the debugger), +// and always terminates the application + +#ifdef DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true ) +#define AssertFatalOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), true ) +#define AssertFatalMsg( _exp, _msg, ... ) _AssertMsg( _exp, (const tchar *)CDbgFmtMsg( _msg, ##__VA_ARGS__ ), ((void)0), true ) +#define AssertFatalMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, true ) +#define AssertFatalFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true ) +#define AssertFatalEquals( _exp, _expectedValue ) AssertFatalMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) AssertFatalMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define VerifyFatal( _exp ) AssertFatal( _exp ) +#define VerifyEqualsFatal( _exp, _expectedValue ) AssertFatalEquals( _exp, _expectedValue ) + +#define AssertFatalMsg1( _exp, _msg, a1 ) AssertFatalMsg( _exp, _msg, a1 ) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) AssertFatalMsg( _exp, _msg, a1, a2 ) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) AssertFatalMsg( _exp, _msg, a1, a2, a3 ) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4 ) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5 ) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6 ) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) + +#else // DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) ((void)0) +#define AssertFatalOnce( _exp ) ((void)0) +#define AssertFatalMsg( _exp, _msg ) ((void)0) +#define AssertFatalMsgOnce( _exp, _msg ) ((void)0) +#define AssertFatalFunc( _exp, _f ) ((void)0) +#define AssertFatalEquals( _exp, _expectedValue ) ((void)0) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define VerifyFatal( _exp ) (_exp) +#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp) + +#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERTFATAL + +// Assert macros +// Assert is used to detect an important but survivable error. +// It's only turned on when DBGFLAG_ASSERT is true. + +#ifdef DBGFLAG_ASSERT + +#define Assert( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsg( _exp, _msg, ... ) _AssertMsg( _exp, (const tchar *)CDbgFmtMsg( _msg, ##__VA_ARGS__ ), ((void)0), false ) +#define AssertOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), false ) +#define AssertMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, false ) +#define AssertFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), _f, false ) +#define AssertEquals( _exp, _expectedValue ) AssertMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) AssertMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define Verify( _exp ) Assert( _exp ) +#define VerifyMsg1( _exp, _msg, a1 ) AssertMsg1( _exp, _msg, a1 ) +#define VerifyMsg2( _exp, _msg, a1, a2 ) AssertMsg2( _exp, _msg, a1, a2 ) +#define VerifyMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg3( _exp, _msg, a1, a2, a3 ) +#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue ) +#define DbgVerify( _exp ) Assert( _exp ) + +#define AssertMsg1( _exp, _msg, a1 ) AssertMsg( _exp, _msg, a1 ) +#define AssertMsg2( _exp, _msg, a1, a2 ) AssertMsg( _exp, _msg, a1, a2 ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg( _exp, _msg, a1, a2, a3 ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertMsg( _exp, _msg, a1, a2, a3, a4 ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5 ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6 ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) + +#else // DBGFLAG_ASSERT + +#define Assert( _exp ) ((void)0) +#define AssertOnce( _exp ) ((void)0) +#define AssertMsg( _exp, _msg, ... ) ((void)0) +#define AssertMsgOnce( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) +#define VerifyMsg1( _exp, _msg, a1 ) (_exp) +#define VerifyMsg2( _exp, _msg, a1, a2 ) (_exp) +#define VerifyMsg3( _exp, _msg, a1, a2, a3 ) (_exp) +#define VerifyEquals( _exp, _expectedValue ) (_exp) +#define DbgVerify( _exp ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERT + +// The Always version of the assert macros are defined even when DBGFLAG_ASSERT is not, +// so they will be available even in release. +#define AssertAlways( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsgAlways( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false ) + +// Stringify a number +#define V_STRINGIFY_INTERNAL(x) #x +// Extra level of indirection needed when passing in a macro to avoid getting the macro name instead of value +#define V_STRINGIFY(x) V_STRINGIFY_INTERNAL(x) + +// Macros to help decorate warnings or errors with the location in code +#define FILE_LINE_FUNCTION_STRING __FILE__ "(" V_STRINGIFY(__LINE__) "):" __FUNCTION__ ":" +#define FILE_LINE_STRING __FILE__ "(" V_STRINGIFY(__LINE__) "):" +#define FUNCTION_LINE_STRING __FUNCTION__ "(" V_STRINGIFY(__LINE__) "): " + +// Handy define for inserting clickable messages into the build output. +// Use like this: +// #pragma MESSAGE("Some message") +#define MESSAGE(msg) message(__FILE__ "(" V_STRINGIFY(__LINE__) "): " msg) + + +#if !defined( _X360 ) || !defined( _RETAIL ) + +/* These are always compiled in */ +DBG_INTERFACE void Msg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE void DMsg( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 3, 4 ); +DBG_INTERFACE void MsgV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ); + +DBG_INTERFACE void Warning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE void DWarning( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 3, 4 ); +DBG_INTERFACE void WarningV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ); + +DBG_INTERFACE void Log( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE void DLog( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 3, 4 ); +DBG_INTERFACE void LogV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ); + +#ifdef Error +// p4.cpp does a #define Error Warning and in that case the Error prototype needs to +// be consistent with the Warning prototype. +DBG_INTERFACE void Error( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +#else +DBG_INTERFACE void NORETURN Error( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE void NORETURN ErrorV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ); + +#endif + +#else + +inline void Msg( ... ) {} +inline void DMsg( ... ) {} +inline void MsgV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {} +inline void Warning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) {} +inline void WarningV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {} +inline void DWarning( ... ) {} +inline void Log( ... ) {} +inline void DLog( ... ) {} +inline void LogV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {} +inline void Error( ... ) {} +inline void ErrorV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {} + +#endif + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( condition ) \ + ; \ + else \ + { \ + Error msg; \ + } + +#if !defined( _X360 ) || !defined( _RETAIL ) + +/* A couple of super-common dynamic spew messages, here for convenience */ +/* These looked at the "developer" group */ +DBG_INTERFACE void DevMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void DevWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void DevLog( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +/* default level versions (level 1) */ +DBG_OVERLOAD void DevMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_OVERLOAD void DevWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_OVERLOAD void DevLog( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +/* These looked at the "console" group */ +DBG_INTERFACE void ConColorMsg( int level, const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 ); +DBG_INTERFACE void ConMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void ConWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void ConLog( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +/* default console version (level 1) */ +DBG_OVERLOAD void ConColorMsg( const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_OVERLOAD void ConMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_OVERLOAD void ConWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_OVERLOAD void ConLog( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +/* developer console version (level 2) */ +DBG_INTERFACE void ConDColorMsg( const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void ConDMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE void ConDWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +DBG_INTERFACE void ConDLog( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +/* These looked at the "network" group */ +DBG_INTERFACE void NetMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void NetWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); +DBG_INTERFACE void NetLog( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +void ValidateSpew( class CValidator &validator ); + +#else + +inline void DevMsg( ... ) {} +inline void DevWarning( ... ) {} +inline void DevLog( ... ) {} +inline void ConMsg( ... ) {} +inline void ConLog( ... ) {} +inline void NetMsg( ... ) {} +inline void NetWarning( ... ) {} +inline void NetLog( ... ) {} + +#endif + +DBG_INTERFACE void COM_TimestampedLog( PRINTF_FORMAT_STRING char const *fmt, ... ) FMTFUNCTION( 1, 2 ); + +/* Code macros, debugger interface */ + +#ifdef DBGFLAG_ASSERT + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_CODE_NOSCOPE( _code ) _code +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_CODE_NOSCOPE( _code ) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- + +#ifndef _RETAIL +class CScopeMsg +{ +public: + CScopeMsg( const char *pszScope ) + { + m_pszScope = pszScope; + Msg( "%s { ", pszScope ); + } + ~CScopeMsg() + { + Msg( "} %s", m_pszScope ); + } + const char *m_pszScope; +}; +#define SCOPE_MSG( msg ) CScopeMsg scopeMsg( msg ) +#else +#define SCOPE_MSG( msg ) +#endif + + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +// This implementation of compile time assert has zero cost (so it can safely be +// included in release builds) and can be used at file scope or function scope. +// We're using an ancient version of GCC that can't quite handle some +// of our complicated templates properly. Use some preprocessor trickery +// to workaround this +#ifdef __GNUC__ + #define COMPILE_TIME_ASSERT( pred ) typedef int UNIQUE_ID[ (pred) ? 1 : -1 ] +#else + #if _MSC_VER >= 1600 + // If available use static_assert instead of weird language tricks. This + // leads to much more readable messages when compile time assert constraints + // are violated. + #define COMPILE_TIME_ASSERT( pred ) static_assert( pred, "Compile time assert constraint is not true: " #pred ) + #else + // Due to gcc bugs this can in rare cases (some template functions) cause redeclaration + // errors when used multiple times in one scope. Fix by adding extra scoping. + #define COMPILE_TIME_ASSERT( pred ) typedef char compile_time_assert_type[(pred) ? 1 : -1]; + #endif +#endif +// ASSERT_INVARIANT used to be needed in order to allow COMPILE_TIME_ASSERTs at global +// scope. However the new COMPILE_TIME_ASSERT macro supports that by default. +#define ASSERT_INVARIANT( pred ) COMPILE_TIME_ASSERT( pred ) + + +#ifdef _DEBUG +template +inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) +{ + Assert( static_cast(pSource) == dynamic_cast(pSource) ); + return static_cast(pSource); +} +#else +#define assert_cast static_cast +#endif + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. + +DBG_INTERFACE void _AssertValidReadPtr( void* ptr, int count = 1 ); +DBG_INTERFACE void _AssertValidWritePtr( void* ptr, int count = 1 ); +DBG_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count = 1 ); +DBG_INTERFACE void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ); + +#ifdef DBGFLAG_ASSERT + +FORCEINLINE void AssertValidReadPtr( const void* ptr, int count = 1 ) { _AssertValidReadPtr( (void*)ptr, count ); } +FORCEINLINE void AssertValidWritePtr( const void* ptr, int count = 1 ) { _AssertValidWritePtr( (void*)ptr, count ); } +FORCEINLINE void AssertValidReadWritePtr( const void* ptr, int count = 1 ) { _AssertValidReadWritePtr( (void*)ptr, count ); } + +#else + +FORCEINLINE void AssertValidReadPtr( const void*, int = 1 ) { } +FORCEINLINE void AssertValidWritePtr( const void*, int = 1 ) { } +FORCEINLINE void AssertValidReadWritePtr( const void*, int = 1 ) { } +#define AssertValidStringPtr AssertValidReadPtr + +#endif + +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +#include "tier0/valve_off.h" +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(PRINTF_FORMAT_STRING const tchar *pszFormat, ...) FMTFUNCTION( 2, 3 ) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + _vsntprintf(m_szBuf, sizeof(m_szBuf)-1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf)-1] = 0; + } + + operator const tchar *() const + { + return m_szBuf; + } + +private: + tchar m_szBuf[256]; +}; +#include "tier0/valve_on.h" + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// +#if defined( _WIN32 ) && !defined( _X360 ) + + #ifdef _DEBUG + #pragma comment(compiler) + #endif + +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Wrap around a variable to create a simple place to put a breakpoint +// + +#ifdef _DEBUG + +template< class Type > +class CDataWatcher +{ +public: + const Type& operator=( const Type &val ) + { + return Set( val ); + } + + const Type& operator=( const CDataWatcher &val ) + { + return Set( val.m_Value ); + } + + const Type& Set( const Type &val ) + { + // Put your breakpoint here + m_Value = val; + return m_Value; + } + + Type& GetForModify() + { + return m_Value; + } + + const Type& operator+=( const Type &val ) + { + return Set( m_Value + val ); + } + + const Type& operator-=( const Type &val ) + { + return Set( m_Value - val ); + } + + const Type& operator/=( const Type &val ) + { + return Set( m_Value / val ); + } + + const Type& operator*=( const Type &val ) + { + return Set( m_Value * val ); + } + + const Type& operator^=( const Type &val ) + { + return Set( m_Value ^ val ); + } + + const Type& operator|=( const Type &val ) + { + return Set( m_Value | val ); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++( int ) // postfix version.. + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--( int ) // postfix version.. + { + Type val = m_Value; + (*this -= 1); + return val; + } + + // For some reason the compiler only generates type conversion warnings for this operator when used like + // CNetworkVarBase = 0x1 + // (it warns about converting from an int to an unsigned char). + template< class C > + const Type& operator&=( C val ) + { + return Set( m_Value & val ); + } + + operator const Type&() const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +}; + +#else + +template< class Type > +class CDataWatcher +{ +private: + CDataWatcher(); // refuse to compile in non-debug builds +}; + +#endif + +//----------------------------------------------------------------------------- + +#endif /* DBG_H */ diff --git a/public/tier0/dbgflag.h b/public/tier0/dbgflag.h new file mode 100644 index 0000000..05f84c9 --- /dev/null +++ b/public/tier0/dbgflag.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This file sets all of our debugging flags. It should be +// called before all other header files. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DBGFLAG_H +#define DBGFLAG_H +#ifdef _WIN32 +#pragma once +#endif + + +// Here are all the flags we support: +// DBGFLAG_MEMORY: Enables our memory debugging system, which overrides malloc & free +// DBGFLAG_MEMORY_NEWDEL: Enables new / delete tracking for memory debug system. Requires DBGFLAG_MEMORY to be enabled. +// DBGFLAG_VALIDATE: Enables our recursive validation system for checking integrity and memory leaks +// DBGFLAG_ASSERT: Turns Assert on or off (when off, it isn't compiled at all) +// DBGFLAG_ASSERTFATAL: Turns AssertFatal on or off (when off, it isn't compiled at all) +// DBGFLAG_ASSERTDLG: Turns assert dialogs on or off and debug breaks on or off when not under the debugger. +// (Dialogs will always be on when process is being debugged.) +// DBGFLAG_STRINGS: Turns on hardcore string validation (slow but safe) + +#undef DBGFLAG_MEMORY +#undef DBGFLAG_MEMORY_NEWDEL +#undef DBGFLAG_VALIDATE +#undef DBGFLAG_ASSERT +#undef DBGFLAG_ASSERTFATAL +#undef DBGFLAG_ASSERTDLG +#undef DBGFLAG_STRINGS + +//----------------------------------------------------------------------------- +// Default flags for debug builds +//----------------------------------------------------------------------------- +#if (defined( _DEBUG ) || defined( RELEASEASSERTS ) ) + +#define DBGFLAG_MEMORY +#ifdef _SERVER // only enable new & delete tracking for server; on client it conflicts with CRT mem leak tracking +#define DBGFLAG_MEMORY_NEWDEL +#endif +#ifdef STEAM +#define DBGFLAG_VALIDATE +#endif +#define DBGFLAG_ASSERT +#define DBGFLAG_ASSERTFATAL +#define DBGFLAG_ASSERTDLG +#define DBGFLAG_STRINGS + + +//----------------------------------------------------------------------------- +// Default flags for release builds +//----------------------------------------------------------------------------- +#else // _DEBUG + +#ifdef STEAM +#define DBGFLAG_ASSERT +#endif +#define DBGFLAG_ASSERTFATAL // note: fatal asserts are enabled in release builds +#define DBGFLAG_ASSERTDLG + +#endif // _DEBUG + +#endif // DBGFLAG_H diff --git a/public/tier0/dynfunction.h b/public/tier0/dynfunction.h new file mode 100644 index 0000000..bd976b7 --- /dev/null +++ b/public/tier0/dynfunction.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// This makes it easy to dynamically load a shared library and lookup a +// function in that library. +// +// Usage: +// CDynamicFunction MyPuts(libname, "puts"); +// if (MyPuts) +// MyPuts("Hello world!"); +// +// Please note that this interface does not distinguish between functions and +// data. If you look up a global variable in your shared library, or simply +// mess up the function signature, you'll get a valid pointer and a crash +// if you call it as a function. + +#ifndef DYNFUNCTION_H +#define DYNFUNCTION_H +#pragma once + +#include "tier0/platform.h" + +// The heavy lifting isn't template-specific, so we move it out of the header. +DLL_EXPORT void *VoidFnPtrLookup_Tier0(const char *libname, const char *fn, void *fallback); + +template < class FunctionType > +class CDynamicFunction +{ +public: + // Construct with a NULL function pointer. You must manually call + // Lookup() before you can call a dynamic function through this interface. + CDynamicFunction() : m_pFn(NULL) {} + + // Construct and do a lookup right away. You will need to make sure that + // the lookup actually succeeded, as (libname) might have failed to load + // or (fn) might not exist in it. + CDynamicFunction(const char *libname, const char *fn, FunctionType fallback=NULL) : m_pFn(NULL) + { + Lookup(libname, fn, fallback); + } + + // Construct and do a lookup right away. See comments in Lookup() about what (okay) does. + CDynamicFunction(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) : m_pFn(NULL) + { + Lookup(libname, fn, okay, fallback); + } + + // Load library if necessary, look up symbol. Returns true and sets + // m_pFn on successful lookup, returns false otherwise. If the + // function pointer is already looked up, this return true immediately. + // Use Reset() first if you want to look up the symbol again. + // This function will return false immediately unless (okay) is true. + // This allows you to chain lookups like this: + // bool okay = true; + // x.Lookup(lib, "x", okay); + // y.Lookup(lib, "y", okay); + // z.Lookup(lib, "z", okay); + // if (okay) { printf("All functions were loaded successfully!\n"); } + // If you supply a fallback, it'll be used if the lookup fails (and if + // non-NULL, means this will always return (okay)). + bool Lookup(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) + { + if (!okay) + return false; + else if (m_pFn == NULL) + m_pFn = (FunctionType) VoidFnPtrLookup_Tier0(libname, fn, (void *) fallback); + okay = m_pFn != NULL; + return okay; + } + + // Load library if necessary, look up symbol. Returns true and sets + // m_pFn on successful lookup, returns false otherwise. If the + // function pointer is already looked up, this return true immediately. + // Use Reset() first if you want to look up the symbol again. + // This function will return false immediately unless (okay) is true. + // If you supply a fallback, it'll be used if the lookup fails (and if + // non-NULL, means this will always return true). + bool Lookup(const char *libname, const char *fn, FunctionType fallback=NULL) + { + bool okay = true; + return Lookup(libname, fn, okay, fallback); + } + + // Invalidates the current lookup. Makes the function pointer NULL. You + // will need to call Lookup() before you can call a dynamic function + // through this interface again. + void Reset() { m_pFn = NULL; } + + // Force this to be a specific function pointer. + void Force(FunctionType ptr) { m_pFn = ptr; } + + // Retrieve the actual function pointer. + FunctionType Pointer() const { return m_pFn; } + operator FunctionType() const { return m_pFn; } + + // Can be used to verify that we have an actual function looked up and + // ready to call: if (!MyDynFunc) { printf("Function not found!\n"); } + operator bool () const { return m_pFn != NULL; } + bool operator !() const { return m_pFn == NULL; } + +protected: + FunctionType m_pFn; +}; + + +// This is the same as CDynamicFunction, but we made the default constructor +// private, forcing you to do loading/lookup during construction. +// The usage pattern is to have a list of dynamic functions that are +// constructed en masse as part of another class's constructor, with the +// possibility of human error removed (the compiler will complain if you +// forget to initialize one). +template < class FunctionType > +class CDynamicFunctionMustInit : public CDynamicFunction < FunctionType > +{ +private: // forbid default constructor. + CDynamicFunctionMustInit() {} + +public: + CDynamicFunctionMustInit(const char *libname, const char *fn, FunctionType fallback=NULL) + : CDynamicFunction< FunctionType >(libname, fn, fallback) + { + } + + CDynamicFunctionMustInit(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) + : CDynamicFunction< FunctionType >(libname, fn, okay, fallback) + { + } +}; + +#endif // DYNFUNCTION_H + diff --git a/public/tier0/etwprof.h b/public/tier0/etwprof.h new file mode 100644 index 0000000..c1d4282 --- /dev/null +++ b/public/tier0/etwprof.h @@ -0,0 +1,157 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// ETW (Event Tracing for Windows) profiling helpers. +// This allows easy insertion of Generic Event markers into ETW/xperf tracing +// which then aids in analyzing the traces and finding performance problems. +// The usage patterns are to use ETWBegin and ETWEnd (typically through the +// convenience class CETWScope) to bracket time-consuming operations. In addition +// ETWFrameMark marks the beginning of each frame, and ETWMark can be used to +// mark other notable events. More event types and providers can be added as needed. +// When recording xperf profiles add Valve-Main+Valve-FrameRate to the list of +// user-mode providers and be sure to register the providers with this sequence +// of commands: +// xcopy /y game\bin\tier0.dll %temp% +// wevtutil um src\tier0\ValveETWProvider.man +// wevtutil im src\tier0\ValveETWProvider.man +// +//=============================================================================== + +#ifndef ETWPROF_H +#define ETWPROF_H +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "tier0/platform.h" + +#ifdef IS_WINDOWS_PC +// ETW support should be compiled in for all Windows PC platforms. It isn't +// supported on Windows XP but that is determined at run-time. +#define ETW_MARKS_ENABLED +#endif + +#ifdef ETW_MARKS_ENABLED + +// Insert a single event to mark a point in an ETW trace. The return value is a 64-bit +// time stamp. +PLATFORM_INTERFACE int64 ETWMark( const char *pMessage ); +// Optionally do full printf formatting of the mark string. This will be more expensive, +// but only when tracing is enabled. +PLATFORM_INTERFACE void ETWMarkPrintf( PRINTF_FORMAT_STRING const char *pMessage, ... ) FMTFUNCTION( 1, 2 ); +// Optionally specify one to four floats. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1F( const char *pMessage, float data1 ); +PLATFORM_INTERFACE void ETWMark2F( const char *pMessage, float data1, float data2 ); +PLATFORM_INTERFACE void ETWMark3F( const char *pMessage, float data1, float data2, float data3 ); +PLATFORM_INTERFACE void ETWMark4F( const char *pMessage, float data1, float data2, float data3, float data4 ); +// Optionally specify one to four ints. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1I( const char *pMessage, int data1 ); +PLATFORM_INTERFACE void ETWMark2I( const char *pMessage, int data1, int data2 ); +PLATFORM_INTERFACE void ETWMark3I( const char *pMessage, int data1, int data2, int data3 ); +PLATFORM_INTERFACE void ETWMark4I( const char *pMessage, int data1, int data2, int data3, int data4 ); +// Optionally specify one to two strings. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1S( const char *pMessage, const char* data1 ); +PLATFORM_INTERFACE void ETWMark2S( const char *pMessage, const char* data1, const char* data2 ); + +// Insert a begin event to mark the start of some work. The return value is a 64-bit +// time stamp which should be passed to the corresponding ETWEnd function. +PLATFORM_INTERFACE int64 ETWBegin( const char *pMessage ); + +// Insert a paired end event to mark the end of some work. +PLATFORM_INTERFACE int64 ETWEnd( const char *pMessage, int64 nStartTime ); + +// Mark the start of the next render frame. bIsServerProcess must be passed +// in consistently for a particular process. +PLATFORM_INTERFACE void ETWRenderFrameMark( bool bIsServerProcess ); +// Mark the start of the next simulation frame. bIsServerProcess must be passed +// in consistently for a particular process. +PLATFORM_INTERFACE void ETWSimFrameMark( bool bIsServerProcess ); +// Return the frame number recorded in the ETW trace -- useful for synchronizing +// other profile information to the ETW trace. +PLATFORM_INTERFACE int ETWGetRenderFrameNumber(); + +PLATFORM_INTERFACE void ETWMouseDown( int nWhichButton, int nX, int nY ); +PLATFORM_INTERFACE void ETWMouseUp( int nWhichButton, int nX, int nY ); +PLATFORM_INTERFACE void ETWMouseMove( int nX, int nY ); +PLATFORM_INTERFACE void ETWMouseWheel( int nWheelDelta, int nX, int nY ); +PLATFORM_INTERFACE void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar ); + +PLATFORM_INTERFACE void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck ); +PLATFORM_INTERFACE void ETWThrottled(); +PLATFORM_INTERFACE void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck ); + +// This class calls the ETW Begin and End functions in order to insert a +// pair of events to bracket some work. +class CETWScope +{ +public: + CETWScope( const char *pMessage ) + : m_pMessage( pMessage ) + { + m_nStartTime = ETWBegin( pMessage ); + } + ~CETWScope() + { + ETWEnd( m_pMessage, m_nStartTime ); + } +private: + // Private and unimplemented to disable copying. + CETWScope( const CETWScope& rhs ); + CETWScope& operator=( const CETWScope& rhs ); + + const char* m_pMessage; + int64 m_nStartTime; +}; + +#else + +inline int64 ETWMark( const char* ) { return 0; } +inline void ETWMarkPrintf( const char *, ... ) { return; } +inline void ETWMark1F( const char *, float ) { } +inline void ETWMark2F( const char *, float , float ) { } +inline void ETWMark3F( const char *, float , float , float ) { } +inline void ETWMark4F( const char *, float , float , float , float ) { } +inline void ETWMark1I( const char *, int ) { } +inline void ETWMark2I( const char *, int , int ) { } +inline void ETWMark3I( const char *, int , int , int ) { } +inline void ETWMark4I( const char *, int , int , int , int ) { } +// Optionally specify one to two strings. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +inline void ETWMark1S( const char *, const char* ) { } +inline void ETWMark2S( const char *, const char* , const char* ) { } + +inline int64 ETWBegin( const char* ) { return 0; } +inline int64 ETWEnd( const char*, int64 ) { return 0; } +inline void ETWRenderFrameMark( bool ) {} +inline void ETWSimFrameMark( bool ) {} +inline int ETWGetRenderFrameNumber() { return 0; } + +inline void ETWMouseDown( int nWhichButton, int nX, int nY ) {} +inline void ETWMouseUp( int nWhichButton, int nX, int nY ) {} +inline void ETWMouseMove( int nX, int nY ) {} +inline void ETWMouseWheel( int nWheelDelta, int nX, int nY ) {} +inline void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar ) {} + +inline void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck ) {} +inline void ETWThrottled() {} +inline void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck ) {} + +// This class calls the ETW Begin and End functions in order to insert a +// pair of events to bracket some work. +class CETWScope +{ +public: + CETWScope( const char* ) + { + } +private: + // Private and unimplemented to disable copying. + CETWScope( const CETWScope& rhs ); + CETWScope& operator=( const CETWScope& rhs ); +}; + +#endif + +#endif // ETWPROF_H diff --git a/public/tier0/fasttimer.h b/public/tier0/fasttimer.h new file mode 100644 index 0000000..e9e634f --- /dev/null +++ b/public/tier0/fasttimer.h @@ -0,0 +1,569 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FASTTIMER_H +#define FASTTIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _WIN32 +#include +#endif + +#include +#include "tier0/platform.h" + +PLATFORM_INTERFACE uint64 g_ClockSpeed; +#if defined( _X360 ) && defined( _CERT ) +PLATFORM_INTERFACE unsigned long g_dwFakeFastCounter; +#endif + +PLATFORM_INTERFACE double g_ClockSpeedMicrosecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedMillisecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedSecondsMultiplier; + +class CCycleCount +{ +friend class CFastTimer; + +public: + CCycleCount(); + CCycleCount( uint64 cycles ); + + void Sample(); // Sample the clock. This takes about 34 clocks to execute (or 26,000 calls per millisecond on a P900). + + void Init(); // Set to zero. + void Init( float initTimeMsec ); + void Init( double initTimeMsec ) { Init( (float)initTimeMsec ); } + void Init( uint64 cycles ); + bool IsLessThan( CCycleCount const &other ) const; // Compare two counts. + + // Convert to other time representations. These functions are slow, so it's preferable to call them + // during display rather than inside a timing block. + unsigned long GetCycles() const; + uint64 GetLongCycles() const; + + unsigned long GetMicroseconds() const; + uint64 GetUlMicroseconds() const; + double GetMicrosecondsF() const; + void SetMicroseconds( unsigned long nMicroseconds ); + + unsigned long GetMilliseconds() const; + double GetMillisecondsF() const; + + double GetSeconds() const; + + CCycleCount& operator+=( CCycleCount const &other ); + + // dest = rSrc1 + rSrc2 + static void Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together. + + // dest = rSrc1 - rSrc2 + static void Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together. + + static uint64 GetTimestamp(); + + uint64 m_Int64; +}; + +class PLATFORM_CLASS CClockSpeedInit +{ +public: + CClockSpeedInit() + { + Init(); + } + + static void Init(); +}; + +class CFastTimer +{ +public: + // These functions are fast to call and should be called from your sampling code. + void Start(); + void End(); + + const CCycleCount & GetDuration() const; // Get the elapsed time between Start and End calls. + CCycleCount GetDurationInProgress() const; // Call without ending. Not that cheap. + + // Return number of cycles per second on this processor. + static inline int64 GetClockSpeed(); + +private: + CCycleCount m_Duration; +#ifdef DEBUG_FASTTIMER + bool m_bRunning; // Are we currently running? +#endif +}; + + +// This is a helper class that times whatever block of code it's in +class CTimeScope +{ +public: + CTimeScope( CFastTimer *pTimer ); + ~CTimeScope(); + +private: + CFastTimer *m_pTimer; +}; + +inline CTimeScope::CTimeScope( CFastTimer *pTotal ) +{ + m_pTimer = pTotal; + m_pTimer->Start(); +} + +inline CTimeScope::~CTimeScope() +{ + m_pTimer->End(); +} + +// This is a helper class that times whatever block of code it's in and +// adds the total (int microseconds) to a global counter. +class CTimeAdder +{ +public: + CTimeAdder( CCycleCount *pTotal ); + ~CTimeAdder(); + + void End(); + +private: + CCycleCount *m_pTotal; + CFastTimer m_Timer; +}; + +inline CTimeAdder::CTimeAdder( CCycleCount *pTotal ) +{ + m_pTotal = pTotal; + m_Timer.Start(); +} + +inline CTimeAdder::~CTimeAdder() +{ + End(); +} + +inline void CTimeAdder::End() +{ + if( m_pTotal ) + { + m_Timer.End(); + *m_pTotal += m_Timer.GetDuration(); + m_pTotal = 0; + } +} + + + +// -------------------------------------------------------------------------- // +// Simple tool to support timing a block of code, and reporting the results on +// program exit or at each iteration +// +// Macros used because dbg.h uses this header, thus Msg() is unavailable +// -------------------------------------------------------------------------- // + +#define PROFILE_SCOPE(name) \ + class C##name##ACC : public CAverageCycleCounter \ + { \ + public: \ + ~C##name##ACC() \ + { \ + Msg("%-48s: %6.3f avg (%8.1f total, %7.3f peak, %5d iters)\n", \ + #name, \ + GetAverageMilliseconds(), \ + GetTotalMilliseconds(), \ + GetPeakMilliseconds(), \ + GetIters() ); \ + } \ + }; \ + static C##name##ACC name##_ACC; \ + CAverageTimeMarker name##_ATM( &name##_ACC ) + +#define TIME_SCOPE(name) \ + class CTimeScopeMsg_##name \ + { \ + public: \ + CTimeScopeMsg_##name() { m_Timer.Start(); } \ + ~CTimeScopeMsg_##name() \ + { \ + m_Timer.End(); \ + Msg( #name "time: %.4fms\n", m_Timer.GetDuration().GetMillisecondsF() ); \ + } \ + private: \ + CFastTimer m_Timer; \ + } name##_TSM; + + +// -------------------------------------------------------------------------- // + +class CAverageCycleCounter +{ +public: + CAverageCycleCounter(); + + void Init(); + void MarkIter( const CCycleCount &duration ); + + unsigned GetIters() const; + + double GetAverageMilliseconds() const; + double GetTotalMilliseconds() const; + double GetPeakMilliseconds() const; + +private: + unsigned m_nIters; + CCycleCount m_Total; + CCycleCount m_Peak; +}; + +// -------------------------------------------------------------------------- // + +class CAverageTimeMarker +{ +public: + CAverageTimeMarker( CAverageCycleCounter *pCounter ); + ~CAverageTimeMarker(); + +private: + CAverageCycleCounter *m_pCounter; + CFastTimer m_Timer; +}; + + +// -------------------------------------------------------------------------- // +// CCycleCount inlines. +// -------------------------------------------------------------------------- // + +inline CCycleCount::CCycleCount() +{ + Init( (uint64)0 ); +} + +inline CCycleCount::CCycleCount( uint64 cycles ) +{ + Init( cycles ); +} + +inline void CCycleCount::Init() +{ + Init( (uint64)0 ); +} + +inline void CCycleCount::Init( float initTimeMsec ) +{ + if ( g_ClockSpeedMillisecondsMultiplier > 0 ) + Init( (uint64)(initTimeMsec / g_ClockSpeedMillisecondsMultiplier) ); + else + Init( (uint64)0 ); +} + +inline void CCycleCount::Init( uint64 cycles ) +{ + m_Int64 = cycles; +} + +inline void CCycleCount::Sample() +{ + m_Int64 = Plat_Rdtsc(); +} + +inline CCycleCount& CCycleCount::operator+=( CCycleCount const &other ) +{ + m_Int64 += other.m_Int64; + return *this; +} + + +inline void CCycleCount::Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ) +{ + dest.m_Int64 = rSrc1.m_Int64 + rSrc2.m_Int64; +} + +inline void CCycleCount::Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ) +{ + dest.m_Int64 = rSrc1.m_Int64 - rSrc2.m_Int64; +} + +inline uint64 CCycleCount::GetTimestamp() +{ + CCycleCount c; + c.Sample(); + return c.GetLongCycles(); +} + +inline bool CCycleCount::IsLessThan(CCycleCount const &other) const +{ + return m_Int64 < other.m_Int64; +} + + +inline unsigned long CCycleCount::GetCycles() const +{ + return (unsigned long)m_Int64; +} + +inline uint64 CCycleCount::GetLongCycles() const +{ + return m_Int64; +} + +inline unsigned long CCycleCount::GetMicroseconds() const +{ + return (unsigned long)((m_Int64 * 1000000) / g_ClockSpeed); +} + +inline uint64 CCycleCount::GetUlMicroseconds() const +{ + return ((m_Int64 * 1000000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMicrosecondsF() const +{ + return (double)( m_Int64 * g_ClockSpeedMicrosecondsMultiplier ); +} + + +inline void CCycleCount::SetMicroseconds( unsigned long nMicroseconds ) +{ + m_Int64 = ((uint64)nMicroseconds * g_ClockSpeed) / 1000000; +} + + +inline unsigned long CCycleCount::GetMilliseconds() const +{ + return (unsigned long)((m_Int64 * 1000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMillisecondsF() const +{ + return (double)( m_Int64 * g_ClockSpeedMillisecondsMultiplier ); +} + + +inline double CCycleCount::GetSeconds() const +{ + return (double)( m_Int64 * g_ClockSpeedSecondsMultiplier ); +} + + +// -------------------------------------------------------------------------- // +// CFastTimer inlines. +// -------------------------------------------------------------------------- // +inline void CFastTimer::Start() +{ + m_Duration.Sample(); +#ifdef DEBUG_FASTTIMER + m_bRunning = true; +#endif +} + + +inline void CFastTimer::End() +{ + CCycleCount cnt; + cnt.Sample(); + if ( IsX360() ) + { + // have to handle rollover, hires timer is only accurate to 32 bits + // more than one overflow should not have occurred, otherwise caller should use a slower timer + if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 ) + { + // rollover occurred + cnt.m_Int64 += 0x100000000LL; + } + } + + m_Duration.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + +#ifdef DEBUG_FASTTIMER + m_bRunning = false; +#endif +} + +inline CCycleCount CFastTimer::GetDurationInProgress() const +{ + CCycleCount cnt; + cnt.Sample(); + if ( IsX360() ) + { + // have to handle rollover, hires timer is only accurate to 32 bits + // more than one overflow should not have occurred, otherwise caller should use a slower timer + if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 ) + { + // rollover occurred + cnt.m_Int64 += 0x100000000LL; + } + } + + CCycleCount result; + result.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + + return result; +} + + +inline int64 CFastTimer::GetClockSpeed() +{ + return g_ClockSpeed; +} + + +inline CCycleCount const& CFastTimer::GetDuration() const +{ +#ifdef DEBUG_FASTTIMER + assert( !m_bRunning ); +#endif + return m_Duration; +} + + +// -------------------------------------------------------------------------- // +// CAverageCycleCounter inlines + +inline CAverageCycleCounter::CAverageCycleCounter() + : m_nIters( 0 ) +{ +} + +inline void CAverageCycleCounter::Init() +{ + m_Total.Init(); + m_Peak.Init(); + m_nIters = 0; +} + +inline void CAverageCycleCounter::MarkIter( const CCycleCount &duration ) +{ + ++m_nIters; + m_Total += duration; + if ( m_Peak.IsLessThan( duration ) ) + m_Peak = duration; +} + +inline unsigned CAverageCycleCounter::GetIters() const +{ + return m_nIters; +} + +inline double CAverageCycleCounter::GetAverageMilliseconds() const +{ + if ( m_nIters ) + return (m_Total.GetMillisecondsF() / (double)m_nIters); + else + return 0; +} + +inline double CAverageCycleCounter::GetTotalMilliseconds() const +{ + return m_Total.GetMillisecondsF(); +} + +inline double CAverageCycleCounter::GetPeakMilliseconds() const +{ + return m_Peak.GetMillisecondsF(); +} + +// -------------------------------------------------------------------------- // + +inline CAverageTimeMarker::CAverageTimeMarker( CAverageCycleCounter *pCounter ) +{ + m_pCounter = pCounter; + m_Timer.Start(); +} + +inline CAverageTimeMarker::~CAverageTimeMarker() +{ + m_Timer.End(); + m_pCounter->MarkIter( m_Timer.GetDuration() ); +} + + +// CLimitTimer +// Use this to time whether a desired interval of time has passed. It's extremely fast +// to check while running. NOTE: CMicroSecOverage() and CMicroSecLeft() are not as fast to check. +class CLimitTimer +{ +public: + CLimitTimer() {} + CLimitTimer( uint64 cMicroSecDuration ) { SetLimit( cMicroSecDuration ); } + void SetLimit( uint64 m_cMicroSecDuration ); + bool BLimitReached() const; + + int CMicroSecOverage() const; + uint64 CMicroSecLeft() const; + +private: + uint64 m_lCycleLimit; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Initializes the limit timer with a period of time to measure. +// Input : cMicroSecDuration - How long a time period to measure +//----------------------------------------------------------------------------- +inline void CLimitTimer::SetLimit( uint64 cMicroSecDuration ) +{ + uint64 dlCycles = ( ( uint64 ) cMicroSecDuration * g_ClockSpeed ) / ( uint64 ) 1000000L; + CCycleCount cycleCount; + cycleCount.Sample( ); + m_lCycleLimit = cycleCount.GetLongCycles( ) + dlCycles; +} + + +//----------------------------------------------------------------------------- +// Purpose: Determines whether our specified time period has passed +// Output: true if at least the specified time period has passed +//----------------------------------------------------------------------------- +inline bool CLimitTimer::BLimitReached() const +{ + CCycleCount cycleCount; + cycleCount.Sample( ); + return ( cycleCount.GetLongCycles( ) >= m_lCycleLimit ); +} + + +//----------------------------------------------------------------------------- +// Purpose: If we're over our specified time period, return the amount of the overage. +// Output: # of microseconds since we reached our specified time period. +//----------------------------------------------------------------------------- +inline int CLimitTimer::CMicroSecOverage() const +{ + CCycleCount cycleCount; + cycleCount.Sample(); + uint64 lcCycles = cycleCount.GetLongCycles(); + + if ( lcCycles < m_lCycleLimit ) + return 0; + + return( ( int ) ( ( lcCycles - m_lCycleLimit ) * ( uint64 ) 1000000L / g_ClockSpeed ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: If we're under our specified time period, return the amount under. +// Output: # of microseconds until we reached our specified time period, 0 if we've passed it +//----------------------------------------------------------------------------- +inline uint64 CLimitTimer::CMicroSecLeft() const +{ + CCycleCount cycleCount; + cycleCount.Sample(); + uint64 lcCycles = cycleCount.GetLongCycles(); + + if ( lcCycles >= m_lCycleLimit ) + return 0; + + return( ( uint64 ) ( ( m_lCycleLimit - lcCycles ) * ( uint64 ) 1000000L / g_ClockSpeed ) ); +} + + +#endif // FASTTIMER_H diff --git a/public/tier0/ia32detect.h b/public/tier0/ia32detect.h new file mode 100644 index 0000000..dd603d1 --- /dev/null +++ b/public/tier0/ia32detect.h @@ -0,0 +1,377 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef IA32DETECT_H +#define IA32DETECT_H + +#ifdef PLATFORM_WINDOWS_PC +#include +#endif + +/* + This section from http://iss.cs.cornell.edu/ia32.htm + + + */ +typedef unsigned bit; + +enum CPUVendor +{ + INTEL, + AMD, + UNKNOWN_VENDOR +}; +class ia32detect +{ +public: + + enum type_t + { + type_OEM, + type_OverDrive, + type_Dual, + type_reserved + }; + + enum brand_t + { + brand_na, + brand_Celeron, + brand_PentiumIII, + brand_PentiumIIIXeon, + brand_reserved1, + brand_reserved2, + brand_PentiumIIIMobile, + brand_reserved3, + brand_Pentium4, + brand_invalid + }; + +# pragma pack(push, 1) + + struct version_t + { + bit Stepping : 4; + bit Model : 4; + bit Family : 4; + bit Type : 2; + bit Reserved1 : 2; + bit XModel : 4; + bit XFamily : 8; + bit Reserved2 : 4; + }; + + struct misc_t + { + byte Brand; + byte CLFLUSH; + byte Reserved; + byte APICId; + }; + + struct feature_t + { + bit FPU : 1; // Floating Point Unit On-Chip + bit VME : 1; // Virtual 8086 Mode Enhancements + bit DE : 1; // Debugging Extensions + bit PSE : 1; // Page Size Extensions + bit TSC : 1; // Time Stamp Counter + bit MSR : 1; // Model Specific Registers + bit PAE : 1; // Physical Address Extension + bit MCE : 1; // Machine Check Exception + bit CX8 : 1; // CMPXCHG8 Instruction + bit APIC : 1; // APIC On-Chip + bit Reserved1 : 1; + bit SEP : 1; // SYSENTER and SYSEXIT instructions + bit MTRR : 1; // Memory Type Range Registers + bit PGE : 1; // PTE Global Bit + bit MCA : 1; // Machine Check Architecture + bit CMOV : 1; // Conditional Move Instructions + bit PAT : 1; // Page Attribute Table + bit PSE36 : 1; // 32-bit Page Size Extension + bit PSN : 1; // Processor Serial Number + bit CLFSH : 1; // CLFLUSH Instruction + bit Reserved2 : 1; + bit DS : 1; // Debug Store + bit ACPI : 1; // Thermal Monitor and Software Controlled Clock Facilities + bit MMX : 1; // Intel MMX Technology + bit FXSR : 1; // FXSAVE and FXRSTOR Instructions + bit SSE : 1; // Intel SSE Technology + bit SSE2 : 1; // Intel SSE2 Technology + bit SS : 1; // Self Snoop + bit HTT : 1; // Hyper Threading + bit TM : 1; // Thermal Monitor + bit Reserved3 : 1; + bit PBE : 1; // Pending Brk. EN. + }; + +# pragma pack(pop) + + tstring vendor_name; + CPUVendor vendor; + tstring brand; + version_t version; + misc_t misc; + feature_t feature; + byte *cache; + + ia32detect () + { + + cache = 0; + uint32 m = init0(); + + uint32 *d = new uint32[m * 4]; + + for (uint32 i = 1; i <= m; i++) + { +#ifdef COMPILER_MSVC64 + __cpuid((int *) (d + (i-1) * 4), i); + +#else + uint32 *t = d + (i - 1) * 4; + + __asm + { + mov eax, i; + mov esi, t; + + cpuid; + + mov dword ptr [esi + 0x0], eax; + mov dword ptr [esi + 0x4], ebx; + mov dword ptr [esi + 0x8], ecx; + mov dword ptr [esi + 0xC], edx; + } +#endif + } + + if (m >= 1) + init1(d); + + if (m >= 2) + init2(d[4] & 0xFF); + + delete [] d; + + init0x80000000(); + + + //----------------------------------------------------------------------- + // Get the vendor of the processor + //----------------------------------------------------------------------- + if (_tcscmp(vendor_name.c_str(), _T("GenuineIntel")) == 0) + { + vendor = INTEL; + + } + else if (_tcscmp(vendor_name.c_str(), _T("AuthenticAMD")) == 0) + { + vendor = AMD; + + } + else + { + vendor = UNKNOWN_VENDOR; + } + } + + const tstring version_text () const + { + tchar b[128]; + + _stprintf(b, _T("%d.%d.%d %s XVersion(%d.%d)"), + version.Family, version.Model, version.Stepping, type_text(), version.XFamily, version.XModel); + + return tstring(b); + } + +protected: + + const tchar * type_text () const + { + static const tchar *text[] = + { + _T("Intel OEM Processor"), + _T("Intel OverDrive(R) Processor"), + _T("Intel Dual Processor"), + _T("reserved") + }; + + return text[version.Type]; + } + + const tstring brand_text () const + { + static const tchar *text[] = + { + _T("n/a"), + _T("Celeron"), + _T("Pentium III"), + _T("Pentium III Xeon"), + _T("reserved (4)"), + _T("reserved (5)"), + _T("Pentium III Mobile"), + _T("reserved (7)"), + _T("Pentium 4") + }; + + if (misc.Brand < brand_invalid) + return tstring(text[misc.Brand]); + else + { + tchar b[32]; + + _stprintf(b, _T("Brand %d (Update)"), misc.Brand); + + return tstring(b); + } + } + +private: + + uint32 init0 () + { + uint32 m; + + int data[4 + 1]; + tchar * s1; + + s1 = (tchar *) &data[1]; + __cpuid(data, 0); + data[4] = 0; + // Returns something like this: + // data[0] = 0x0000000b + // data[1] = 0x756e6547 Genu + // data[2] = 0x6c65746e ntel + // data[3] = 0x49656e69 ineI + // data[4] = 0x00000000 + + m = data[0]; + int t = data[2]; + data[2] = data[3]; + data[3] = t; + vendor_name = s1; + return m; + } + + void init1 (uint32 *d) + { + version = *(version_t *)&d[0]; + misc = *(misc_t *)&d[1]; + feature = *(feature_t *)&d[3]; + } + + void process2 (uint32 d, bool c[]) + { + if ((d & 0x80000000) == 0) + for (int i = 0; i < 32; i += 8) + c[(d >> i) & 0xFF] = true; + } + + void init2 (byte count) + { + uint32 d[4]; + bool c[256]; + + for (int ci1 = 0; ci1 < 256; ci1++) + c[ci1] = false; + + for (int i = 0; i < count; i++) + { +#ifdef COMPILER_MSVC64 + __cpuid((int *) d, 2); +#else + __asm + { + mov eax, 2; + lea esi, d; + cpuid; + mov [esi + 0x0], eax; + mov [esi + 0x4], ebx; + mov [esi + 0x8], ecx; + mov [esi + 0xC], edx; + } +#endif + + if (i == 0) + d[0] &= 0xFFFFFF00; + + process2(d[0], c); + process2(d[1], c); + process2(d[2], c); + process2(d[3], c); + } + + int m = 0; + + for (int ci2 = 0; ci2 < 256; ci2++) + if (c[ci2]) + m++; + + cache = new byte[m]; + + m = 0; + + for (int ci3 = 1; ci3 < 256; ci3++) + if (c[ci3]) + cache[m++] = ci3; + + cache[m] = 0; + } + + void init0x80000000 () + { + uint32 m; + +#ifdef COMPILER_MSVC64 + int data[4]; + __cpuid(data, 0x80000000); + m = data[0]; +#else + __asm + { + mov eax, 0x80000000; + cpuid; + mov m, eax + } +#endif + + if ((m & 0x80000000) != 0) + { + uint32 *d = new uint32[(m - 0x80000000) * 4]; + + for (uint32 i = 0x80000001; i <= m; i++) + { + uint32 *t = d + (i - 0x80000001) * 4; + +#ifdef COMPILER_MSVC64 + __cpuid((int *) (d + (i - 0x80000001) * 4), i); +#else + __asm + { + mov eax, i; + mov esi, t; + cpuid; + mov dword ptr [esi + 0x0], eax; + mov dword ptr [esi + 0x4], ebx; + mov dword ptr [esi + 0x8], ecx; + mov dword ptr [esi + 0xC], edx; + } +#endif + } + + if (m >= 0x80000002) + brand = (tchar *)(d + 4); + + // note the assignment to brand above does a copy, we need to delete + delete[] d; + } + } +}; + +#endif // IA32DETECT_H diff --git a/public/tier0/icommandline.h b/public/tier0/icommandline.h new file mode 100644 index 0000000..9107d69 --- /dev/null +++ b/public/tier0/icommandline.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef TIER0_ICOMMANDLINE_H +#define TIER0_ICOMMANDLINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + + +//----------------------------------------------------------------------------- +// Purpose: Interface to engine command line +//----------------------------------------------------------------------------- +abstract_class ICommandLine +{ +public: + virtual void CreateCmdLine( const char *commandline ) = 0; + virtual void CreateCmdLine( int argc, char **argv ) = 0; + virtual const char *GetCmdLine( void ) const = 0; + + // Check whether a particular parameter exists + virtual const char *CheckParm( const char *psz, const char **ppszValue = 0 ) const = 0; + virtual void RemoveParm( const char *parm ) = 0; + virtual void AppendParm( const char *pszParm, const char *pszValues ) = 0; + + // Returns the argument after the one specified, or the default if not found + virtual const char *ParmValue( const char *psz, const char *pDefaultVal = 0 ) const = 0; + virtual int ParmValue( const char *psz, int nDefaultVal ) const = 0; + virtual float ParmValue( const char *psz, float flDefaultVal ) const = 0; + + // Gets at particular parameters + virtual int ParmCount() const = 0; + virtual int FindParm( const char *psz ) const = 0; // Returns 0 if not found. + virtual const char* GetParm( int nIndex ) const = 0; + + // copies the string passwed + virtual void SetParm( int nIndex, char const *pNewParm ) =0; + + virtual const char *ParmValueByIndex( int nIndex, const char *pDefaultVal = 0 ) const = 0; +}; + +//----------------------------------------------------------------------------- +// Gets a singleton to the commandline interface +// NOTE: The #define trickery here is necessary for backwards compat: +// this interface used to lie in the vstdlib library. +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE ICommandLine *CommandLine_Tier0(); + +#if !defined( VSTDLIB_BACKWARD_COMPAT ) +#define CommandLine CommandLine_Tier0 +#endif + +#endif // TIER0_ICOMMANDLINE_H + diff --git a/public/tier0/l2cache.h b/public/tier0/l2cache.h new file mode 100644 index 0000000..2ee8833 --- /dev/null +++ b/public/tier0/l2cache.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#ifndef CL2CACHE_H +#define CL2CACHE_H +#ifdef _WIN32 +#pragma once +#endif + +class P4Event_BSQ_cache_reference; + +class CL2Cache +{ +public: + + CL2Cache(); + ~CL2Cache(); + + void Start( void ); + void End( void ); + + //------------------------------------------------------------------------- + // GetL2CacheMisses + //------------------------------------------------------------------------- + int GetL2CacheMisses( void ) + { + return m_iL2CacheMissCount; + } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +private: + + int m_nID; + + P4Event_BSQ_cache_reference *m_pL2CacheEvent; + int64 m_i64Start; + int64 m_i64End; + int m_iL2CacheMissCount; +}; + +#endif // CL2CACHE_H diff --git a/public/tier0/mem.h b/public/tier0/mem.h new file mode 100644 index 0000000..fc8807a --- /dev/null +++ b/public/tier0/mem.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Memory allocation! +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_MEM_H +#define TIER0_MEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#ifdef LINUX +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#include "tier0/platform.h" + +#if !defined(STATIC_TIER0) && !defined(_STATIC_LINKED) + +#ifdef TIER0_DLL_EXPORT +# define MEM_INTERFACE DLL_EXPORT +#else +# define MEM_INTERFACE DLL_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define MEM_INTERFACE extern + +#endif // BUILD_AS_DLL + + + +//----------------------------------------------------------------------------- +// DLL-exported methods for particular kinds of memory +//----------------------------------------------------------------------------- +MEM_INTERFACE void *MemAllocScratch( int nMemSize ); +MEM_INTERFACE void MemFreeScratch(); + +#ifdef _LINUX +MEM_INTERFACE void ZeroMemory( void *mem, size_t length ); +#endif + + +#endif /* TIER0_MEM_H */ diff --git a/public/tier0/memalloc.h b/public/tier0/memalloc.h new file mode 100644 index 0000000..ef4df55 --- /dev/null +++ b/public/tier0/memalloc.h @@ -0,0 +1,654 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This header should never be used directly from leaf code!!! +// Instead, just add the file memoverride.cpp into your project and all this +// will automagically be used +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_MEMALLOC_H +#define TIER0_MEMALLOC_H + +#ifdef _WIN32 +#pragma once +#endif + +// These memory debugging switches aren't relevant under Linux builds since memoverride.cpp +// isn't built into Linux projects +#ifndef POSIX +// Define this in release to get memory tracking even in release builds +//#define USE_MEM_DEBUG 1 +#endif + +#if defined( _MEMTEST ) +#ifdef _WIN32 +#define USE_MEM_DEBUG 1 +#endif +#endif + +// Undefine this if using a compiler lacking threadsafe RTTI (like vc6) +#define MEM_DEBUG_CLASSNAME 1 + +#include +#if defined( OSX ) +#include +#endif + +#include "tier0/mem.h" + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +struct _CrtMemState; + +#define MEMALLOC_VERSION 1 + +typedef size_t (*MemAllocFailHandler_t)( size_t ); + +//----------------------------------------------------------------------------- +// NOTE! This should never be called directly from leaf code +// Just use new,delete,malloc,free etc. They will call into this eventually +//----------------------------------------------------------------------------- +abstract_class IMemAlloc +{ +public: + // Release versions + virtual void *Alloc( size_t nSize ) = 0; + virtual void *Realloc( void *pMem, size_t nSize ) = 0; + virtual void Free( void *pMem ) = 0; + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize ) = 0; + + // Debug versions + virtual void *Alloc( size_t nSize, const char *pFileName, int nLine ) = 0; + virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0; + virtual void Free( void *pMem, const char *pFileName, int nLine ) = 0; + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0; + + // Returns size of a particular allocation + virtual size_t GetSize( void *pMem ) = 0; + + // Force file + line information for an allocation + virtual void PushAllocDbgInfo( const char *pFileName, int nLine ) = 0; + virtual void PopAllocDbgInfo() = 0; + + // FIXME: Remove when we have our own allocator + // these methods of the Crt debug code is used in our codebase currently + virtual long CrtSetBreakAlloc( long lNewBreakAlloc ) = 0; + virtual int CrtSetReportMode( int nReportType, int nReportMode ) = 0; + virtual int CrtIsValidHeapPointer( const void *pMem ) = 0; + virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access ) = 0; + virtual int CrtCheckMemory( void ) = 0; + virtual int CrtSetDbgFlag( int nNewFlag ) = 0; + virtual void CrtMemCheckpoint( _CrtMemState *pState ) = 0; + + // FIXME: Make a better stats interface + virtual void DumpStats() = 0; + virtual void DumpStatsFileBase( char const *pchFileBase ) = 0; + + // FIXME: Remove when we have our own allocator + virtual void* CrtSetReportFile( int nRptType, void* hFile ) = 0; + virtual void* CrtSetReportHook( void* pfnNewHook ) = 0; + virtual int CrtDbgReport( int nRptType, const char * szFile, + int nLine, const char * szModule, const char * pMsg ) = 0; + + virtual int heapchk() = 0; + + virtual bool IsDebugHeap() = 0; + + virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) = 0; + virtual void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) = 0; + virtual void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) = 0; + + virtual int GetVersion() = 0; + + virtual void CompactHeap() = 0; + + // Function called when malloc fails or memory limits hit to attempt to free up memory (can come in any thread) + virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler ) = 0; + + virtual void DumpBlockStats( void * ) = 0; + +#if defined( _MEMTEST ) + virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment ) = 0; +#endif + + // Returns 0 if no failure, otherwise the size_t of the last requested chunk + // "I'm sure this is completely thread safe!" Brian Deen 7/19/2012. + virtual size_t MemoryAllocFailed() = 0; + + // handles storing allocation info for coroutines + virtual uint32 GetDebugInfoSize() = 0; + virtual void SaveDebugInfo( void *pvDebugInfo ) = 0; + virtual void RestoreDebugInfo( const void *pvDebugInfo ) = 0; + virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) = 0; + + // Replacement for ::GlobalMemoryStatus which accounts for unused memory in our system + virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory ) = 0; +}; + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +MEM_INTERFACE IMemAlloc *g_pMemAlloc; + +//----------------------------------------------------------------------------- + +#ifdef MEMALLOC_REGIONS +#ifndef MEMALLOC_REGION +#define MEMALLOC_REGION 0 +#endif +inline void *MemAlloc_Alloc( size_t nSize ) +{ + return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize ); +} + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize, pFileName, nLine ); +} +#else +#undef MEMALLOC_REGION +inline void *MemAlloc_Alloc( size_t nSize ) +{ + return g_pMemAlloc->Alloc( nSize ); +} + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->Alloc( nSize, pFileName, nLine ); +} +#endif +inline void MemAlloc_Free( void *ptr ) +{ + g_pMemAlloc->Free( ptr ); +} +inline void MemAlloc_Free( void *ptr, const char *pFileName, int nLine ) +{ + g_pMemAlloc->Free( ptr, pFileName, nLine ); +} + +//----------------------------------------------------------------------------- + +inline bool ValueIsPowerOfTwo( size_t value ) // don't clash with mathlib definition +{ + return (value & ( value - 1 )) == 0; +} + +inline void *MemAlloc_AllocAligned( size_t size, size_t align ) +{ + unsigned char *pAlloc, *pResult; + + if (!IsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)g_pMemAlloc->Alloc( sizeof(void *) + align + size ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; +} + +inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFile, int nLine ) +{ + unsigned char *pAlloc, *pResult; + + if (!IsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)g_pMemAlloc->Alloc( sizeof(void *) + align + size, pszFile, nLine ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; +} + +inline void *MemAlloc_AllocAlignedUnattributed( size_t size, size_t align ) +{ + unsigned char *pAlloc, *pResult; + + if (!ValueIsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; +} + +inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile, int nLine ) +{ + unsigned char *pAlloc, *pResult; + + if (!ValueIsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size, pszFile, nLine ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; +} + +inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align ) +{ + if ( !IsPowerOfTwo( align ) ) + return NULL; + + // Don't change alignment between allocation + reallocation. + if ( ( (size_t)ptr & ( align - 1 ) ) != 0 ) + return NULL; + + if ( !ptr ) + return MemAlloc_AllocAligned( size, align ); + + void *pAlloc, *pResult; + + // Figure out the actual allocation point + pAlloc = ptr; + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + pAlloc = *( (void **)pAlloc ); + + // See if we have enough space + size_t nOffset = (size_t)ptr - (size_t)pAlloc; + size_t nOldSize = g_pMemAlloc->GetSize( pAlloc ); + if ( nOldSize >= size + nOffset ) + return ptr; + + pResult = MemAlloc_AllocAligned( size, align ); + memcpy( pResult, ptr, nOldSize - nOffset ); + g_pMemAlloc->Free( pAlloc ); + return pResult; +} + +inline void MemAlloc_FreeAligned( void *pMemBlock ) +{ + void *pAlloc; + + if ( pMemBlock == NULL ) + return; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *( (void **)pAlloc ); + g_pMemAlloc->Free( pAlloc ); +} + +inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pFileName, int nLine ) +{ + void *pAlloc; + + if ( pMemBlock == NULL ) + return; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *( (void **)pAlloc ); + g_pMemAlloc->Free( pAlloc, pFileName, nLine ); +} + +inline size_t MemAlloc_GetSizeAligned( void *pMemBlock ) +{ + void *pAlloc; + + if ( pMemBlock == NULL ) + return 0; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *((void **)pAlloc ); + return g_pMemAlloc->GetSize( pAlloc ) - ( (byte *)pMemBlock - (byte *)pAlloc ); +} + +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ ) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo() +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#else +#define MEM_ALLOC_CREDIT_(tag) ((void)tag) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)pszFile, (void)line) +#define MemAlloc_PopAllocDbgInfo() ((void)0) +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)pFileName, (void)nLine, (void)nLogicalSize, (void)nActualSize, (void)nTime) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)pFileName, (void)nLine, (void)nLogicalSize, (void)nActualSize, (void)nTime) +#endif + +#define MemAlloc_DumpStats() g_pMemAlloc->DumpStats() +#define MemAlloc_CompactHeap() g_pMemAlloc->CompactHeap() +#define MemAlloc_OutOfMemory() g_pMemAlloc->OutOfMemory() +#define MemAlloc_CompactIncremental() g_pMemAlloc->CompactIncremental() +#define MemAlloc_DumpStatsFileBase( _filename ) g_pMemAlloc->DumpStatsFileBase( _filename ) +#define MemAlloc_CrtCheckMemory() g_pMemAlloc->CrtCheckMemory() +#define MemAlloc_GlobalMemoryStatus( _usedMemory, _freeMemory ) g_pMemAlloc->GlobalMemoryStatus( _usedMemory, _freeMemory ) +#define MemAlloc_MemoryAllocFailed() g_pMemAlloc->MemoryAllocFailed() + +#define MemAlloc_GetDebugInfoSize() g_pMemAlloc->GetDebugInfoSize() +#define MemAlloc_SaveDebugInfo( pvDebugInfo ) g_pMemAlloc->SaveDebugInfo( pvDebugInfo ) +#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) g_pMemAlloc->RestoreDebugInfo( pvDebugInfo ) +#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) g_pMemAlloc->InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) +#define MemAlloc_GetSize( x ) g_pMemAlloc->GetSize( x ); +//----------------------------------------------------------------------------- + +class CMemAllocAttributeAlloction +{ +public: + CMemAllocAttributeAlloction( const char *pszFile, int line ) + { + MemAlloc_PushAllocDbgInfo( pszFile, line ); + } + + ~CMemAllocAttributeAlloction() + { + MemAlloc_PopAllocDbgInfo(); + } +}; + +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) + +//----------------------------------------------------------------------------- + +#if defined(_WIN32) && ( defined(_DEBUG) || defined(USE_MEM_DEBUG) ) + + #pragma warning(disable:4290) + #pragma warning(push) + #include + + // MEM_DEBUG_CLASSNAME is opt-in. + // Note: typeid().name() is not threadsafe, so if the project needs to access it in multiple threads + // simultaneously, it'll need a mutex. + #if defined(_CPPRTTI) && defined(MEM_DEBUG_CLASSNAME) + #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( typeid(*this).name() ) + #define MEM_ALLOC_CLASSNAME(type) (typeid((type*)(0)).name()) + #else + #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( __FILE__ ) + #define MEM_ALLOC_CLASSNAME(type) (__FILE__) + #endif + + // MEM_ALLOC_CREDIT_FUNCTION is used when no this pointer is available ( inside 'new' overloads, for example ) + #ifdef _MSC_VER + #define MEM_ALLOC_CREDIT_FUNCTION() MEM_ALLOC_CREDIT_( __FUNCTION__ ) + #else + #define MEM_ALLOC_CREDIT_FUNCTION() (__FILE__) + #endif + + #pragma warning(pop) +#else + #define MEM_ALLOC_CREDIT_CLASS() + #define MEM_ALLOC_CLASSNAME(type) NULL + #define MEM_ALLOC_CREDIT_FUNCTION() +#endif + +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +struct MemAllocFileLine_t +{ + const char *pszFile; + int line; +}; + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \ + static CUtlMap g_##tag##Allocs( DefLessFunc( void *) ); \ + static const char *g_psz##tag##Alloc = strcpy( (char *)g_pMemAlloc->Alloc( strlen( #tag "Alloc" ) + 1, "intentional leak", 0 ), #tag "Alloc" ); + +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + g_pMemAlloc->GetActualDbgInfo( fileLine.pszFile, fileLine.line ); \ + if ( fileLine.pszFile != g_psz##tag##Alloc ) \ + { \ + g_##tag##Allocs.Insert( p, fileLine ); \ + } \ + \ + MemAlloc_RegisterAllocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + CUtlMap::IndexType_t iRecordedFileLine = g_##tag##Allocs.Find( p ); \ + if ( iRecordedFileLine != g_##tag##Allocs.InvalidIndex() ) \ + { \ + fileLine = g_##tag##Allocs[iRecordedFileLine]; \ + g_##tag##Allocs.RemoveAt( iRecordedFileLine ); \ + } \ + \ + MemAlloc_RegisterDeallocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#else + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +#endif + +//----------------------------------------------------------------------------- + +#elif defined( POSIX ) + +#if defined( OSX ) +// Mac always aligns allocs, don't need to call posix_memalign which doesn't exist in 10.5.8 which TF2 still needs to run on +//inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; posix_memalign(&pTmp, alignment, size); return pTmp;} +inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; pTmp = malloc(size); return pTmp;} +#endif + +inline void *_aligned_malloc( size_t nSize, size_t align ) { return memalign( align, nSize ); } +inline void _aligned_free( void *ptr ) { free( ptr ); } + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName = NULL, int nLine = 0 ) { return malloc( nSize ); } +inline void MemAlloc_Free( void *ptr, const char *pFileName = NULL, int nLine = 0 ) { free( ptr ); } + +inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFile = NULL, int nLine = 0 ) { return memalign( align, size ); } +inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile = NULL, int nLine = 0 ) { return memalign( align, size ); } +inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile = NULL, int nLine = 0 ) { free( pMemBlock ); } + +#if defined( OSX ) +inline size_t _msize( void *ptr ) { return malloc_size( ptr ); } +#else +inline size_t _msize( void *ptr ) { return malloc_usable_size( ptr ); } +#endif + +inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align ) +{ + void *ptr_new_aligned = memalign( align, size ); + + if( ptr_new_aligned ) + { + size_t old_size = _msize( ptr ); + size_t copy_size = ( size < old_size ) ? size : old_size; + + memcpy( ptr_new_aligned, ptr, copy_size ); + free( ptr ); + } + + return ptr_new_aligned; +} +#else +#define MemAlloc_GetDebugInfoSize() g_pMemAlloc->GetDebugInfoSize() +#define MemAlloc_SaveDebugInfo( pvDebugInfo ) g_pMemAlloc->SaveDebugInfo( pvDebugInfo ) +#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) g_pMemAlloc->RestoreDebugInfo( pvDebugInfo ) +#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) g_pMemAlloc->InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) + +#endif // !STEAM && !NO_MALLOC_OVERRIDE + +//----------------------------------------------------------------------------- + +#if !defined(STEAM) && defined(NO_MALLOC_OVERRIDE) + +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) +#define MEM_ALLOC_CREDIT_FUNCTION() +#define MEM_ALLOC_CREDIT_CLASS() +#define MEM_ALLOC_CLASSNAME(type) NULL + +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_DumpStats() ((void)0) +#define MemAlloc_CompactHeap() ((void)0) +#define MemAlloc_OutOfMemory() ((void)0) +#define MemAlloc_CompactIncremental() ((void)0) +#define MemAlloc_DumpStatsFileBase( _filename ) ((void)0) +inline bool MemAlloc_CrtCheckMemory() { return true; } +inline void MemAlloc_GlobalMemoryStatus( size_t *pusedMemory, size_t *pfreeMemory ) +{ + *pusedMemory = 0; + *pfreeMemory = 0; +} +#define MemAlloc_MemoryAllocFailed() 0 + +#define MemAlloc_GetDebugInfoSize() 0 +#define MemAlloc_SaveDebugInfo( pvDebugInfo ) ((void)0) +#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) ((void)0) +#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) ((void)0) + + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +#endif // !STEAM && NO_MALLOC_OVERRIDE + +//----------------------------------------------------------------------------- + + + +// linux memory tracking via hooks. +#if defined( POSIX ) && !defined( NO_HOOK_MALLOC ) +PLATFORM_INTERFACE void MemoryLogMessage( char const *s ); // throw a message into the memory log +PLATFORM_INTERFACE void EnableMemoryLogging( bool bOnOff ); +PLATFORM_INTERFACE void DumpMemoryLog( int nThresh ); +PLATFORM_INTERFACE void DumpMemorySummary( void ); +PLATFORM_INTERFACE void SetMemoryMark( void ); +PLATFORM_INTERFACE void DumpChangedMemory( int nThresh ); + +#else +FORCEINLINE void MemoryLogMessage( char const * ) +{ +} + +FORCEINLINE void EnableMemoryLogging( bool ) +{ +} +FORCEINLINE void DumpMemoryLog( int ) +{ +} +FORCEINLINE void DumpMemorySummary( void ) +{ +} +FORCEINLINE void SetMemoryMark( void ) +{ +} +FORCEINLINE void DumpChangedMemory( int ) +{ +} + +#endif + +#ifdef POSIX +// ApproximateProcessMemoryUsage returns the approximate memory footprint of this process. +PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage( void ); +#else +FORCEINLINE size_t ApproximateProcessMemoryUsage( void ) +{ + return 0; +} + +#endif + +struct aligned_tmp_t +{ + // empty base class +}; + +/* +This class used to be required if you wanted an object to be allocated with a specific +alignment. ALIGN16 and ALIGN16_POST are not actually sufficient for this because they +guarantee that the globals, statics, locals, and function parameters are appropriately +aligned they do not affect memory allocation alignment. +However this class is usually not needed because as of 2012 our policy is that our +allocator should take care of this automatically. Any object whose size is a multiple +of 16 will be 16-byte aligned. Existing uses of this class were not changed because +the cost/benefit did not justify it. +*/ +// template here to allow adding alignment at levels of hierarchy that aren't the base +template< int bytesAlignment = 16, class T = aligned_tmp_t > +class CAlignedNewDelete : public T +{ + +public: + /* + Note that this class does not overload operator new[] and delete[] which means that + classes that depend on this for alignment may end up misaligned if an array is + allocated. This problem is now mostly theoretical because this class is mostly + obsolete. + */ + void *operator new( size_t nSize ) + { + return MemAlloc_AllocAligned( nSize, bytesAlignment ); + } + + void* operator new( size_t nSize, int nBlockUse, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine( nSize, bytesAlignment, pFileName, nLine ); + } + + void operator delete(void *pData) + { + if ( pData ) + { + MemAlloc_FreeAligned( pData ); + } + } + + void operator delete( void* pData, int nBlockUse, const char *pFileName, int nLine ) + { + if ( pData ) + { + MemAlloc_FreeAligned( pData, pFileName, nLine ); + } + } +}; + + +#endif /* TIER0_MEMALLOC_H */ diff --git a/public/tier0/memdbgoff.h b/public/tier0/memdbgoff.h new file mode 100644 index 0000000..1cd09da --- /dev/null +++ b/public/tier0/memdbgoff.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This header, which must be the final line of a .h file, +// causes all crt methods to stop using debugging versions of the memory allocators. +// NOTE: Use memdbgon.h to re-enable memory debugging. +// +// $NoKeywords: $ +//=============================================================================// + +#ifdef MEM_OVERRIDE_ON + +#undef malloc +#undef realloc +#undef calloc +#undef free +#undef _expand +#undef _msize +#undef new +#undef _aligned_malloc +#undef _aligned_free +#undef _malloc_dbg + +#undef MEM_OVERRIDE_ON + +#endif diff --git a/public/tier0/memdbgon.h b/public/tier0/memdbgon.h new file mode 100644 index 0000000..3b31157 --- /dev/null +++ b/public/tier0/memdbgon.h @@ -0,0 +1,252 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This header, which must be the final include in a .cpp (or .h) file, +// causes all crt methods to use debugging versions of the memory allocators. +// NOTE: Use memdbgoff.h to disable memory debugging. +// +// $NoKeywords: $ +//=============================================================================// + +// SPECIAL NOTE! This file must *not* use include guards; we need to be able +// to include this potentially multiple times (since we can deactivate debugging +// by including memdbgoff.h) + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +// SPECIAL NOTE #2: This must be the final include in a .cpp or .h file!!! + +#if defined(_DEBUG) && !defined(USE_MEM_DEBUG) +#define USE_MEM_DEBUG 1 +#endif + +#if defined(NO_HOOK_MALLOC) +#undef USE_MEM_DEBUG +#endif + +// If debug build or ndebug and not already included MS custom alloc files, or already included this file +#if (defined(_DEBUG) || !defined(_INC_CRTDBG)) || defined(MEMDBGON_H) + +#include "basetypes.h" +#ifdef _WIN32 +#include +#else +#include +#endif +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include "commonmacros.h" +#include "memalloc.h" + +#if defined(USE_MEM_DEBUG) + #if defined( POSIX ) + + #define _NORMAL_BLOCK 1 + + #include + #include + #include + #include + #if !defined( DID_THE_OPERATOR_NEW ) + #define DID_THE_OPERATOR_NEW + // posix doesn't have a new of this form, so we impl our own + void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ); + void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ); + #endif + + #else // defined(POSIX) + + // Include crtdbg.h and make sure _DEBUG is set to 1. + #if !defined(_DEBUG) + #define _DEBUG 1 + #include + #undef _DEBUG + #else + #include + #endif // !defined(_DEBUG) + + #endif // defined(POSIX) +#endif + +#include "tier0/memdbgoff.h" + +// -------------------------------------------------------- +// Debug/non-debug agnostic elements + +#define MEM_OVERRIDE_ON 1 + +#undef malloc +#undef realloc +#undef calloc +#undef _expand +#undef free +#undef _msize +#undef _aligned_malloc +#undef _aligned_free + +#ifndef MEMDBGON_H +inline void *MemAlloc_InlineCallocMemset( void *pMem, size_t nCount, size_t nElementSize) +{ + memset(pMem, 0, nElementSize * nCount); + return pMem; +} +#endif + +#define calloc(c, s) MemAlloc_InlineCallocMemset(malloc(c*s), c, s) +#define free(p) g_pMemAlloc->Free( p ) +#define _msize(p) g_pMemAlloc->GetSize( p ) +#define _expand(p, s) _expand_NoLongerSupported(p, s) +#define _aligned_free( p ) MemAlloc_FreeAligned( p ) + +// -------------------------------------------------------- +// Debug path +#if defined(USE_MEM_DEBUG) + +#define malloc(s) g_pMemAlloc->Alloc( s, __FILE__, __LINE__) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s, __FILE__, __LINE__ ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAligned( s, a, __FILE__, __LINE__ ) + +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) + +#if !defined( LINUX ) +#if defined(__AFX_H__) && defined(DEBUG_NEW) + #define new DEBUG_NEW +#else + #undef new + #define MEMALL_DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) + #define new MEMALL_DEBUG_NEW +#endif +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define _wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) +#define wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) + +// Make sure we don't define strdup twice +#if !defined(MEMDBGON_H) + +inline char *MemAlloc_StrDup(const char *pString, const char *pFileName, unsigned nLine) +{ + char *pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char *)g_pMemAlloc->Alloc(len, pFileName, nLine)) != NULL) + { + return strcpy( pMemory, pString ); + } + + return NULL; +} + +inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString, const char *pFileName, unsigned nLine) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t *)g_pMemAlloc->Alloc(len * sizeof(wchar_t), pFileName, nLine)) != NULL) + { + return wcscpy( pMemory, pString ); + } + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#else +// -------------------------------------------------------- +// Release path + +#define malloc(s) g_pMemAlloc->Alloc( s ) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAligned( s, a ) + +#ifndef _malloc_dbg +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) +#endif + +#undef new + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s) +#define strdup(s) MemAlloc_StrDup(s) +#define _wcsdup(s) MemAlloc_WcStrDup(s) +#define wcsdup(s) MemAlloc_WcStrDup(s) + +// Make sure we don't define strdup twice +#if !defined(MEMDBGON_H) + +inline char *MemAlloc_StrDup(const char *pString) +{ + char *pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char *)g_pMemAlloc->Alloc(len)) != NULL) + { + return strcpy( pMemory, pString ); + } + + return NULL; +} + +inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t *)g_pMemAlloc->Alloc(len * sizeof(wchar_t))) != NULL) + { + return wcscpy( pMemory, pString ); + } + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#endif // USE_MEM_DEBUG + +#define MEMDBGON_H // Defined here so can be used above + +#else + +#if defined(USE_MEM_DEBUG) +#ifndef _STATIC_LINKED +#pragma message ("Note: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build") +#else +#error "Error: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build. Not recoverable in static build" +#endif +#endif +#endif // _INC_CRTDBG + +#else + +// Needed for MEM_ALLOC_CREDIT(), MemAlloc_Alloc(), etc. +#include "memalloc.h" + +#endif // !STEAM && !NO_MALLOC_OVERRIDE diff --git a/public/tier0/memoverride.cpp b/public/tier0/memoverride.cpp new file mode 100644 index 0000000..c2c198a --- /dev/null +++ b/public/tier0/memoverride.cpp @@ -0,0 +1,1724 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Insert this file into all projects using the memory system +// It will cause that project to use the shader memory allocator +// +// $NoKeywords: $ +//=============================================================================// + + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +#undef PROTECTED_THINGS_ENABLE // allow use of _vsnprintf + +#if defined( _WIN32 ) && !defined( _X360 ) +#define WIN_32_LEAN_AND_MEAN +#include +#endif + +#include "tier0/dbg.h" +#include "tier0/memalloc.h" +#include +#include +#include "memdbgoff.h" + +#ifdef _WIN32 +// ARG: crtdbg is necessary for certain definitions below, +// but it also redefines malloc as a macro in release. +// To disable this, we gotta define _DEBUG before including it.. BLEAH! +#define _DEBUG 1 +#include "crtdbg.h" +#ifdef NDEBUG +#undef _DEBUG +#endif + +// Turn this back off in release mode. +#ifdef NDEBUG +#undef _DEBUG +#endif +#elif POSIX +#define __cdecl +#endif + +#if defined( _WIN32 ) && !defined( _X360 ) +const char *MakeModuleFileName() +{ + if ( g_pMemAlloc->IsDebugHeap() ) + { + char *pszModuleName = (char *)HeapAlloc( GetProcessHeap(), 0, MAX_PATH ); // small leak, debug only + + MEMORY_BASIC_INFORMATION mbi; + static int dummy; + VirtualQuery( &dummy, &mbi, sizeof(mbi) ); + + GetModuleFileName( reinterpret_cast(mbi.AllocationBase), pszModuleName, MAX_PATH ); + char *pDot = strrchr( pszModuleName, '.' ); + if ( pDot ) + { + char *pSlash = strrchr( pszModuleName, '\\' ); + if ( pSlash ) + { + pszModuleName = pSlash + 1; + *pDot = 0; + } + } + + return pszModuleName; + } + return NULL; +} + +static void *AllocUnattributed( size_t nSize ) +{ + static const char *pszOwner = MakeModuleFileName(); + + if ( !pszOwner ) + return g_pMemAlloc->Alloc(nSize); + else + return g_pMemAlloc->Alloc(nSize, pszOwner, 0); +} + +static void *ReallocUnattributed( void *pMem, size_t nSize ) +{ + static const char *pszOwner = MakeModuleFileName(); + + if ( !pszOwner ) + return g_pMemAlloc->Realloc(pMem, nSize); + else + return g_pMemAlloc->Realloc(pMem, nSize, pszOwner, 0); +} + +#else +#define MakeModuleFileName() NULL +inline void *AllocUnattributed( size_t nSize ) +{ + return g_pMemAlloc->Alloc(nSize); +} + +inline void *ReallocUnattributed( void *pMem, size_t nSize ) +{ + return g_pMemAlloc->Realloc(pMem, nSize); +} +#endif + +//----------------------------------------------------------------------------- +// Standard functions in the CRT that we're going to override to call our allocator +//----------------------------------------------------------------------------- +#if defined(_WIN32) && !defined(_STATIC_LINKED) +// this magic only works under win32 +// under linux this malloc() overrides the libc malloc() and so we +// end up in a recursion (as g_pMemAlloc->Alloc() calls malloc) +#if _MSC_VER >= 1900 +#define ALLOC_CALL _CRTRESTRICT +#define FREE_CALL +#elif _MSC_VER >= 1400 +#define ALLOC_CALL _CRTNOALIAS _CRTRESTRICT +#define FREE_CALL _CRTNOALIAS +#else +#define ALLOC_CALL +#define FREE_CALL +#endif + +extern "C" +{ + +ALLOC_CALL void *malloc( size_t nSize ) +{ + return AllocUnattributed( nSize ); +} + +FREE_CALL void free( void *pMem ) +{ + g_pMemAlloc->Free(pMem); +} + +ALLOC_CALL void *realloc( void *pMem, size_t nSize ) +{ + return ReallocUnattributed( pMem, nSize ); +} + +ALLOC_CALL void *calloc( size_t nCount, size_t nElementSize ) +{ + void *pMem = AllocUnattributed( nElementSize * nCount ); + memset(pMem, 0, nElementSize * nCount); + return pMem; +} + +} // end extern "C" + +//----------------------------------------------------------------------------- +// Non-standard MSVC functions that we're going to override to call our allocator +//----------------------------------------------------------------------------- +extern "C" +{ + +// 64-bit +#ifdef _WIN64 +#if _MSC_VER >= 1900 +ALLOC_CALL void* __cdecl _malloc_base(size_t nSize) +{ + return AllocUnattributed(nSize); +} +#else +void* __cdecl _malloc_base(size_t nSize) +{ + return AllocUnattributed(nSize); +} +#endif +#else +#if _MSC_VER >= 1900 +ALLOC_CALL void *_malloc_base(size_t nSize) +{ + return AllocUnattributed(nSize); +} +#else +void *_malloc_base(size_t nSize) +{ + return AllocUnattributed(nSize); +} +#endif +#endif + +#if _MSC_VER >= 1900 +ALLOC_CALL void *_calloc_base(size_t nCount, size_t nSize) +{ + nSize *= nCount; + void *pMem = AllocUnattributed(nSize); + memset(pMem, 0, nSize); + return pMem; +} +#else +void *_calloc_base(size_t nSize) +{ + void *pMem = AllocUnattributed(nSize); + memset(pMem, 0, nSize); + return pMem; +} +#endif + +#if _MSC_VER >= 1900 +ALLOC_CALL void *_realloc_base(void *pMem, size_t nSize) +{ + return ReallocUnattributed(pMem, nSize); +} +#else +void *_realloc_base(void *pMem, size_t nSize) +{ + return ReallocUnattributed(pMem, nSize); +} +#endif + +void *_recalloc_base( void *pMem, size_t nSize ) +{ + void *pMemOut = ReallocUnattributed( pMem, nSize ); + memset(pMemOut, 0, nSize); + return pMemOut; +} + +void _free_base( void *pMem ) +{ + g_pMemAlloc->Free(pMem); +} + +void *__cdecl _expand_base( void *pMem, size_t nNewSize, int nBlockUse ) +{ + Assert( 0 ); + return NULL; +} + +// crt +void * __cdecl _malloc_crt(size_t size) +{ + return AllocUnattributed( size ); +} + +void * __cdecl _calloc_crt(size_t count, size_t size) +{ +#if _MSC_VER >= 1900 + return _calloc_base(count, size); +#else + return _calloc_base(count * size); +#endif +} + +void * __cdecl _realloc_crt(void *ptr, size_t size) +{ + return _realloc_base( ptr, size ); +} + +void * __cdecl _recalloc_crt(void *ptr, size_t count, size_t size) +{ + return _recalloc_base( ptr, size * count ); +} + +ALLOC_CALL void * __cdecl _recalloc ( void * memblock, size_t count, size_t size ) +{ + void *pMem = ReallocUnattributed( memblock, size * count ); + memset( pMem, 0, size * count ); + return pMem; +} + +size_t _msize_base( void *pMem ) +{ + return g_pMemAlloc->GetSize(pMem); +} + +size_t _msize( void *pMem ) +{ + return _msize_base(pMem); +} + +size_t msize( void *pMem ) +{ + return g_pMemAlloc->GetSize(pMem); +} + +void *__cdecl _heap_alloc( size_t nSize ) +{ + return AllocUnattributed( nSize ); +} + +void *__cdecl _nh_malloc( size_t nSize, int ) +{ + return AllocUnattributed( nSize ); +} + +void *__cdecl _expand( void *pMem, size_t nSize ) +{ + Assert( 0 ); + return NULL; +} + +unsigned int _amblksiz = 16; //BYTES_PER_PARA; + +#if _MSC_VER >= 1400 +HANDLE _crtheap = (HANDLE)1; // PatM Can't be 0 or CRT pukes +int __active_heap = 1; +#endif // _MSC_VER >= 1400 + +size_t __cdecl _get_sbh_threshold( void ) +{ + return 0; +} + +int __cdecl _set_sbh_threshold( size_t ) +{ + return 0; +} + +int _heapchk() +{ + return g_pMemAlloc->heapchk(); +} + +int _heapmin() +{ + return 1; +} + +int __cdecl _heapadd( void *, size_t ) +{ + return 0; +} + +int __cdecl _heapset( unsigned int ) +{ + return 0; +} + +size_t __cdecl _heapused( size_t *, size_t * ) +{ + return 0; +} + +#ifdef _WIN32 +int __cdecl _heapwalk( _HEAPINFO * ) +{ + return 0; +} +#endif + +} // end extern "C" + + +//----------------------------------------------------------------------------- +// Debugging functions that we're going to override to call our allocator +// NOTE: These have to be here for release + debug builds in case we +// link to a debug static lib!!! +//----------------------------------------------------------------------------- + +extern "C" +{ + +void *malloc_db( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->Alloc(nSize, pFileName, nLine); +} + +void free_db( void *pMem, const char *pFileName, int nLine ) +{ + g_pMemAlloc->Free(pMem, pFileName, nLine); +} + +void *realloc_db( void *pMem, size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->Realloc(pMem, nSize, pFileName, nLine); +} + +} // end extern "C" + +//----------------------------------------------------------------------------- +// These methods are standard MSVC heap initialization + shutdown methods +//----------------------------------------------------------------------------- +extern "C" +{ + +#if !defined( _X360 ) + int __cdecl _heap_init() + { + return g_pMemAlloc != NULL; + } + + void __cdecl _heap_term() + { + } +#endif + +} +#endif + + +//----------------------------------------------------------------------------- +// Prevents us from using an inappropriate new or delete method, +// ensures they are here even when linking against debug or release static libs +//----------------------------------------------------------------------------- +#ifndef NO_MEMOVERRIDE_NEW_DELETE +#ifdef OSX +void *__cdecl operator new( size_t nSize ) throw (std::bad_alloc) +#else +void *__cdecl operator new( size_t nSize ) +#endif +{ + return AllocUnattributed( nSize ); +} + +void *__cdecl operator new( size_t nSize, int nBlockUse, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->Alloc(nSize, pFileName, nLine); +} + +#ifdef OSX +void __cdecl operator delete( void *pMem ) throw() +#else +void __cdecl operator delete( void *pMem ) +#endif +{ + g_pMemAlloc->Free( pMem ); +} + +#ifdef OSX +void *__cdecl operator new[]( size_t nSize ) throw (std::bad_alloc) +#else +void *__cdecl operator new[]( size_t nSize ) +#endif +{ + return AllocUnattributed( nSize ); +} + +void *__cdecl operator new[] ( size_t nSize, int nBlockUse, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->Alloc(nSize, pFileName, nLine); +} + +#ifdef OSX +void __cdecl operator delete[]( void *pMem ) throw() +#else +void __cdecl operator delete[]( void *pMem ) +#endif +{ + g_pMemAlloc->Free( pMem ); +} +#endif + + +//----------------------------------------------------------------------------- +// Override some debugging allocation methods in MSVC +// NOTE: These have to be here for release + debug builds in case we +// link to a debug static lib!!! +//----------------------------------------------------------------------------- +#ifndef _STATIC_LINKED +#ifdef _WIN32 + +// This here just hides the internal file names, etc of allocations +// made in the c runtime library +#define CRT_INTERNAL_FILE_NAME "C-runtime internal" + +class CAttibCRT +{ +public: + CAttibCRT(int nBlockUse) : m_nBlockUse(nBlockUse) + { + if (m_nBlockUse == _CRT_BLOCK) + { + g_pMemAlloc->PushAllocDbgInfo(CRT_INTERNAL_FILE_NAME, 0); + } + } + + ~CAttibCRT() + { + if (m_nBlockUse == _CRT_BLOCK) + { + g_pMemAlloc->PopAllocDbgInfo(); + } + } + +private: + int m_nBlockUse; +}; + + +#define AttribIfCrt() CAttibCRT _attrib(nBlockUse) +#elif defined(POSIX) +#define AttribIfCrt() +#endif // _WIN32 + + +extern "C" +{ + +void *__cdecl _nh_malloc_dbg( size_t nSize, int nFlag, int nBlockUse, + const char *pFileName, int nLine ) +{ + AttribIfCrt(); + return g_pMemAlloc->Alloc(nSize, pFileName, nLine); +} + +void *__cdecl _malloc_dbg( size_t nSize, int nBlockUse, + const char *pFileName, int nLine ) +{ + AttribIfCrt(); + return g_pMemAlloc->Alloc(nSize, pFileName, nLine); +} + +#if defined( _X360 ) +void *__cdecl _calloc_dbg_impl( size_t nNum, size_t nSize, int nBlockUse, + const char * szFileName, int nLine, int * errno_tmp ) +{ + return _calloc_dbg( nNum, nSize, nBlockUse, szFileName, nLine ); +} +#endif + +void *__cdecl _calloc_dbg( size_t nNum, size_t nSize, int nBlockUse, + const char *pFileName, int nLine ) +{ + AttribIfCrt(); + void *pMem = g_pMemAlloc->Alloc(nSize * nNum, pFileName, nLine); + memset(pMem, 0, nSize * nNum); + return pMem; +} + +void *__cdecl _calloc_dbg_impl( size_t nNum, size_t nSize, int nBlockUse, + const char * szFileName, int nLine, int * errno_tmp ) +{ + return _calloc_dbg( nNum, nSize, nBlockUse, szFileName, nLine ); +} + +void *__cdecl _realloc_dbg( void *pMem, size_t nNewSize, int nBlockUse, + const char *pFileName, int nLine ) +{ + AttribIfCrt(); + return g_pMemAlloc->Realloc(pMem, nNewSize, pFileName, nLine); +} + +void *__cdecl _expand_dbg( void *pMem, size_t nNewSize, int nBlockUse, + const char *pFileName, int nLine ) +{ + Assert( 0 ); + return NULL; +} + +void __cdecl _free_dbg( void *pMem, int nBlockUse ) +{ + AttribIfCrt(); + g_pMemAlloc->Free(pMem); +} + +size_t __cdecl _msize_dbg( void *pMem, int nBlockUse ) +{ +#ifdef _WIN32 + return _msize(pMem); +#elif POSIX + Assert( "_msize_dbg unsupported" ); + return 0; +#endif +} + + +#ifdef _WIN32 + +#if defined(_DEBUG) && _MSC_VER >= 1300 +// X360TBD: aligned and offset allocations may be important on the 360 + +// aligned base +ALLOC_CALL void *__cdecl _aligned_malloc_base( size_t size, size_t align ) +{ + return MemAlloc_AllocAligned( size, align ); +} + +ALLOC_CALL void *__cdecl _aligned_realloc_base( void *ptr, size_t size, size_t align ) +{ + return MemAlloc_ReallocAligned( ptr, size, align ); +} + +ALLOC_CALL void *__cdecl _aligned_recalloc_base( void *ptr, size_t size, size_t align ) +{ + Error( "Unsupported function\n" ); + return NULL; +} + +FREE_CALL void __cdecl _aligned_free_base( void *ptr ) +{ + MemAlloc_FreeAligned( ptr ); +} + +// aligned +ALLOC_CALL void * __cdecl _aligned_malloc( size_t size, size_t align ) +{ + return _aligned_malloc_base(size, align); +} + +ALLOC_CALL void *__cdecl _aligned_realloc(void *memblock, size_t size, size_t align) +{ + return _aligned_realloc_base(memblock, size, align); +} + +ALLOC_CALL void * __cdecl _aligned_recalloc( void * memblock, size_t count, size_t size, size_t align ) +{ + return _aligned_recalloc_base(memblock, count * size, align); +} + +FREE_CALL void __cdecl _aligned_free( void *memblock ) +{ + _aligned_free_base(memblock); +} + +// aligned offset base +ALLOC_CALL void * __cdecl _aligned_offset_malloc_base( size_t size, size_t align, size_t offset ) +{ + Assert( IsPC() || 0 ); + return NULL; +} + +ALLOC_CALL void * __cdecl _aligned_offset_realloc_base( void * memblock, size_t size, size_t align, size_t offset) +{ + Assert( IsPC() || 0 ); + return NULL; +} + +ALLOC_CALL void * __cdecl _aligned_offset_recalloc_base( void * memblock, size_t size, size_t align, size_t offset) +{ + Assert( IsPC() || 0 ); + return NULL; +} + +// aligned offset +ALLOC_CALL void *__cdecl _aligned_offset_malloc(size_t size, size_t align, size_t offset) +{ + return _aligned_offset_malloc_base( size, align, offset ); +} + +ALLOC_CALL void *__cdecl _aligned_offset_realloc(void *memblock, size_t size, size_t align, size_t offset) +{ + return _aligned_offset_realloc_base( memblock, size, align, offset ); +} + +ALLOC_CALL void * __cdecl _aligned_offset_recalloc( void * memblock, size_t count, size_t size, size_t align, size_t offset ) +{ + return _aligned_offset_recalloc_base( memblock, count * size, align, offset ); +} + +#endif // _MSC_VER >= 1400 + +#endif + +} // end extern "C" + + +//----------------------------------------------------------------------------- +// Override some the _CRT debugging allocation methods in MSVC +//----------------------------------------------------------------------------- +#ifdef _WIN32 + +extern "C" +{ + +int _CrtDumpMemoryLeaks(void) +{ + return 0; +} + +_CRT_DUMP_CLIENT _CrtSetDumpClient( _CRT_DUMP_CLIENT dumpClient ) +{ + return NULL; +} + +int _CrtSetDbgFlag( int nNewFlag ) +{ + return g_pMemAlloc->CrtSetDbgFlag( nNewFlag ); +} + +// 64-bit port. +#define AFNAME(var) __p_ ## var +#define AFRET(var) &var + +#if _MSC_VER >= 1900 +#undef _crtDbgFlag +#undef _crtBreakAlloc +#endif + +int _crtDbgFlag = _CRTDBG_ALLOC_MEM_DF; +int* AFNAME(_crtDbgFlag)(void) +{ + return AFRET(_crtDbgFlag); +} + +long _crtBreakAlloc; /* Break on this allocation */ +long* AFNAME(_crtBreakAlloc) (void) +{ + return AFRET(_crtBreakAlloc); +} + +void __cdecl _CrtSetDbgBlockType( void *pMem, int nBlockUse ) +{ + DebuggerBreak(); +} + +_CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook( _CRT_ALLOC_HOOK pfnNewHook ) +{ + DebuggerBreak(); + return NULL; +} + +long __cdecl _CrtSetBreakAlloc( long lNewBreakAlloc ) +{ + return g_pMemAlloc->CrtSetBreakAlloc( lNewBreakAlloc ); +} + +int __cdecl _CrtIsValidHeapPointer( const void *pMem ) +{ + return g_pMemAlloc->CrtIsValidHeapPointer( pMem ); +} + +int __cdecl _CrtIsValidPointer( const void *pMem, unsigned int size, int access ) +{ + return g_pMemAlloc->CrtIsValidPointer( pMem, size, access ); +} + +int __cdecl _CrtCheckMemory( void ) +{ + // FIXME: Remove this when we re-implement the heap + return g_pMemAlloc->CrtCheckMemory( ); +} + +int __cdecl _CrtIsMemoryBlock( const void *pMem, unsigned int nSize, + long *plRequestNumber, char **ppFileName, int *pnLine ) +{ + DebuggerBreak(); + return 1; +} + +int __cdecl _CrtMemDifference( _CrtMemState *pState, const _CrtMemState * oldState, const _CrtMemState * newState ) +{ + DebuggerBreak(); + return FALSE; +} + +void __cdecl _CrtMemDumpStatistics( const _CrtMemState *pState ) +{ + DebuggerBreak(); +} + +void __cdecl _CrtMemCheckpoint( _CrtMemState *pState ) +{ + // FIXME: Remove this when we re-implement the heap + g_pMemAlloc->CrtMemCheckpoint( pState ); +} + +void __cdecl _CrtMemDumpAllObjectsSince( const _CrtMemState *pState ) +{ + DebuggerBreak(); +} + +void __cdecl _CrtDoForAllClientObjects( void (*pfn)(void *, void *), void * pContext ) +{ + DebuggerBreak(); +} + + +//----------------------------------------------------------------------------- +// Methods in dbgrpt.cpp +//----------------------------------------------------------------------------- +long _crtAssertBusy = -1; + +int __cdecl _CrtSetReportMode( int nReportType, int nReportMode ) +{ + return g_pMemAlloc->CrtSetReportMode( nReportType, nReportMode ); +} + +_HFILE __cdecl _CrtSetReportFile( int nRptType, _HFILE hFile ) +{ + return (_HFILE)g_pMemAlloc->CrtSetReportFile( nRptType, hFile ); +} + +_CRT_REPORT_HOOK __cdecl _CrtSetReportHook( _CRT_REPORT_HOOK pfnNewHook ) +{ + return (_CRT_REPORT_HOOK)g_pMemAlloc->CrtSetReportHook( pfnNewHook ); +} + +int __cdecl _CrtDbgReport( int nRptType, const char * szFile, + int nLine, const char * szModule, const char * szFormat, ... ) +{ + static char output[1024]; + va_list args; + if ( szFormat ) + { + va_start( args, szFormat ); + _vsnprintf( output, sizeof( output )-1, szFormat, args ); + va_end( args ); + } + else + { + output[0] = 0; + } + + return g_pMemAlloc->CrtDbgReport( nRptType, szFile, nLine, szModule, output ); +} + +#if _MSC_VER >= 1400 + +// Configure VS so that it will record crash dumps on pure-call violations +// and invalid parameter handlers. +// If you manage to call a pure-virtual function (easily done if you indirectly +// call a pure-virtual function from the base-class constructor or destructor) +// or if you invoke the invalid parameter handler (printf(NULL); is one way) +// then no crash dump will be created. +// This crash redirects the handlers for these two events so that crash dumps +// are created. +// +// The ErrorHandlerRegistrar object must be in memoverride.cpp so that it will +// be placed in every DLL and EXE. This is required because each DLL and EXE +// gets its own copy of the C run-time and these overrides are set on a per-CRT +// basis. + +/* +// This sample code will cause pure-call and invalid_parameter violations and +// was used for testing: +class Base +{ +public: + virtual void PureFunction() = 0; + + Base() + { + NonPureFunction(); + } + + void NonPureFunction() + { + PureFunction(); + } +}; + +class Derived : public Base +{ +public: + void PureFunction() OVERRIDE + { + } +}; + +void PureCallViolation() +{ + Derived derived; +} + +void InvalidParameterViolation() +{ + printf( NULL ); +} +*/ + +#include +#include "minidump.h" + +// Disable compiler optimizations. If we don't do this then VC++ generates code +// that confuses the Visual Studio debugger and causes it to display completely +// random call stacks. That makes the minidumps excruciatingly hard to understand. +#pragma optimize("", off) + +// Write a minidump file, unless running under the debugger in which case break +// into the debugger. +// The "int dummy" parameter is so that the callers can be unique so that the +// linker won't use its /opt:icf optimization to collapse them together. This +// makes reading the call stack easier. +void __cdecl WriteMiniDumpOrBreak( int dummy, const char *pchName ) +{ + if ( Plat_IsInDebugSession() ) + { + __debugbreak(); + // Continue at your peril... + } + else + { + WriteMiniDump( pchName ); + // Call Plat_ExitProcess so we don't continue in a bad state. + TerminateProcess(GetCurrentProcess(), 0); + } +} + +void __cdecl VPureCall() +{ + WriteMiniDumpOrBreak( 0, "PureClass" ); +} + +void VInvalidParameterHandler(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, + unsigned int line, + uintptr_t pReserved) +{ + WriteMiniDumpOrBreak( 1, "InvalidParameterHandler" ); +} + +// Restore compiler optimizations. +#pragma optimize("", on) + +// Helper class for registering error callbacks. See above for details. +class ErrorHandlerRegistrar +{ +public: + ErrorHandlerRegistrar(); +} s_ErrorHandlerRegistration; + +ErrorHandlerRegistrar::ErrorHandlerRegistrar() +{ + _set_purecall_handler( VPureCall ); + _set_invalid_parameter_handler( VInvalidParameterHandler ); +} + +#if defined( _DEBUG ) + +// wrapper which passes no debug info; not available in debug +#ifndef SUPPRESS_INVALID_PARAMETER_NO_INFO +void __cdecl _invalid_parameter_noinfo(void) +{ + Assert(0); +} +#endif + +#endif /* defined( _DEBUG ) */ + +#if defined( _DEBUG ) || defined( USE_MEM_DEBUG ) + +int __cdecl __crtMessageWindowW( int nRptType, const wchar_t * szFile, const wchar_t * szLine, + const wchar_t * szModule, const wchar_t * szUserMessage ) +{ + Assert(0); + return 0; +} + +int __cdecl _CrtDbgReportV( int nRptType, const wchar_t *szFile, int nLine, + const wchar_t *szModule, const wchar_t *szFormat, va_list arglist ) +{ + Assert(0); + return 0; +} + +int __cdecl _CrtDbgReportW( int nRptType, const wchar_t *szFile, int nLine, + const wchar_t *szModule, const wchar_t *szFormat, ...) +{ + Assert(0); + return 0; +} + +#if _MSC_VER >= 1900 +int __cdecl _VCrtDbgReportA( int nRptType, void *vRetAddr, const char * szFile, int nLine, + const char * szModule, const char * szFormat, va_list arglist ) +{ + Assert(0); + return 0; +} +#else +int __cdecl _VCrtDbgReportA( int nRptType, const wchar_t * szFile, int nLine, + const wchar_t * szModule, const wchar_t * szFormat, va_list arglist ) +{ + Assert(0); + return 0; +} +#endif + +int __cdecl _CrtSetReportHook2( int mode, _CRT_REPORT_HOOK pfnNewHook ) +{ + _CrtSetReportHook( pfnNewHook ); + return 0; +} + + +#endif /* defined( _DEBUG ) || defined( USE_MEM_DEBUG ) */ + +extern "C" int __crtDebugCheckCount = FALSE; + +extern "C" int __cdecl _CrtSetCheckCount( int fCheckCount ) +{ + int oldCheckCount = __crtDebugCheckCount; + return oldCheckCount; +} + +extern "C" int __cdecl _CrtGetCheckCount( void ) +{ + return __crtDebugCheckCount; +} + +// aligned offset debug +extern "C" void * __cdecl _aligned_offset_recalloc_dbg( void * memblock, size_t count, size_t size, size_t align, size_t offset, const char * f_name, int line_n ) +{ + Assert( IsPC() || 0 ); + void *pMem = ReallocUnattributed( memblock, size * count ); + memset( pMem, 0, size * count ); + return pMem; +} + +extern "C" void * __cdecl _aligned_recalloc_dbg( void *memblock, size_t count, size_t size, size_t align, const char * f_name, int line_n ) +{ + return _aligned_offset_recalloc_dbg(memblock, count, size, align, 0, f_name, line_n); +} + +extern "C" void * __cdecl _recalloc_dbg ( void * memblock, size_t count, size_t size, int nBlockUse, const char * szFileName, int nLine ) +{ + return _aligned_offset_recalloc_dbg(memblock, count, size, 0, 0, szFileName, nLine); +} + +_CRT_REPORT_HOOK __cdecl _CrtGetReportHook( void ) +{ + return NULL; +} + +#endif +int __cdecl _CrtReportBlockType(const void * pUserData) +{ + return 0; +} + + +} // end extern "C" +#endif // _WIN32 + +// Most files include this file, so when it's used it adds an extra .ValveDbg section, +// to help identify debug binaries. +#ifdef _WIN32 + #ifndef NDEBUG // _DEBUG + #pragma data_seg("ValveDBG") + volatile const char* DBG = "*** DEBUG STUB ***"; + #endif +#endif + +#endif + +// Extras added prevent dbgheap.obj from being included - DAL +#ifdef _WIN32 + +extern "C" +{ +size_t __crtDebugFillThreshold = 0; + +extern "C" void * __cdecl _heap_alloc_base (size_t size) { + assert(0); + return NULL; +} + + +void * __cdecl _heap_alloc_dbg( size_t nSize, int nBlockUse, const char * szFileName, int nLine) +{ + return _heap_alloc(nSize); +} + +// 64-bit +#ifdef _WIN64 +static void * __cdecl realloc_help( void * pUserData, size_t * pnNewSize, int nBlockUse,const char * szFileName, + int nLine, int fRealloc ) +{ + assert(0); // Shouldn't be needed + return NULL; +} +#else +static void * __cdecl realloc_help( void * pUserData, size_t nNewSize, int nBlockUse, const char * szFileName, + int nLine, int fRealloc) +{ + assert(0); // Shouldn't be needed + return NULL; +} +#endif + +void __cdecl _free_nolock( void * pUserData) +{ + // I don't think the second param is used in memoverride + _free_dbg(pUserData, 0); +} + +void __cdecl _free_dbg_nolock( void * pUserData, int nBlockUse) +{ + _free_dbg(pUserData, 0); +} + +_CRT_ALLOC_HOOK __cdecl _CrtGetAllocHook ( void) +{ + assert(0); + return NULL; +} + +static int __cdecl CheckBytes( unsigned char * pb, unsigned char bCheck, size_t nSize) +{ + int bOkay = TRUE; + return bOkay; +} + + +_CRT_DUMP_CLIENT __cdecl _CrtGetDumpClient ( void) +{ + assert(0); + return NULL; +} + +#if _MSC_VER >= 1400 +static void __cdecl _printMemBlockData( _locale_t plocinfo, _CrtMemBlockHeader * pHead) +{ +} + +static void __cdecl _CrtMemDumpAllObjectsSince_stat( const _CrtMemState * state, _locale_t plocinfo) +{ +} +#endif +void * __cdecl _aligned_malloc_dbg( size_t size, size_t align, const char * f_name, int line_n) +{ + return _aligned_malloc(size, align); +} + +void * __cdecl _aligned_realloc_dbg( void *memblock, size_t size, size_t align, + const char * f_name, int line_n) +{ + return _aligned_realloc(memblock, size, align); +} + +void * __cdecl _aligned_offset_malloc_dbg( size_t size, size_t align, size_t offset, + const char * f_name, int line_n) +{ + return _aligned_offset_malloc(size, align, offset); +} + +void * __cdecl _aligned_offset_realloc_dbg( void * memblock, size_t size, size_t align, + size_t offset, const char * f_name, int line_n) +{ + return _aligned_offset_realloc(memblock, size, align, offset); +} + +void __cdecl _aligned_free_dbg( void * memblock) +{ + _aligned_free(memblock); +} + +#if _MSC_VER < 1900 +size_t __cdecl _CrtSetDebugFillThreshold( size_t _NewDebugFillThreshold) +{ + assert(0); + return 0; +} +#endif + +//=========================================== +// NEW!!! 64-bit + +#if _MSC_VER < 1900 +char * __cdecl _strdup ( const char * string ) +{ + int nSize = (int)strlen(string) + 1; + // Check for integer underflow. + if ( nSize <= 0 ) + return NULL; + char *pCopy = (char*)AllocUnattributed( nSize ); + if ( pCopy ) + memcpy( pCopy, string, nSize ); + return pCopy; +} +#endif + +#if 0 +_TSCHAR * __cdecl _tfullpath_dbg ( _TSCHAR *UserBuf, const _TSCHAR *path, size_t maxlen, int nBlockUse, const char * szFileName, int nLine ) +{ + Assert(0); + return NULL; +} + +_TSCHAR * __cdecl _tfullpath ( _TSCHAR *UserBuf, const _TSCHAR *path, size_t maxlen ) +{ + Assert(0); + return NULL; +} + +_TSCHAR * __cdecl _tgetdcwd_lk_dbg ( int drive, _TSCHAR *pnbuf, int maxlen, int nBlockUse, const char * szFileName, int nLine ) +{ + Assert(0); + return NULL; +} + +_TSCHAR * __cdecl _tgetdcwd_nolock ( int drive, _TSCHAR *pnbuf, int maxlen ) +{ + Assert(0); + return NULL; +} + +errno_t __cdecl _tdupenv_s_helper ( _TSCHAR **pBuffer, size_t *pBufferSizeInTChars, const _TSCHAR *varname, int nBlockUse, const char * szFileName, int nLine ) +{ + Assert(0); + return 0; +} + +errno_t __cdecl _tdupenv_s_helper ( _TSCHAR **pBuffer, size_t *pBufferSizeInTChars, const _TSCHAR *varname ) +{ + Assert(0); + return 0; +} + +_TSCHAR * __cdecl _ttempnam_dbg ( const _TSCHAR *dir, const _TSCHAR *pfx, int nBlockUse, const char * szFileName, int nLine ) +{ + Assert(0); + return 0; +} + +_TSCHAR * __cdecl _ttempnam ( const _TSCHAR *dir, const _TSCHAR *pfx ) +{ + Assert(0); + return 0; +} + +wchar_t * __cdecl _wcsdup_dbg ( const wchar_t * string, int nBlockUse, const char * szFileName, int nLine ) +{ + Assert(0); + return 0; +} + +wchar_t * __cdecl _wcsdup ( const wchar_t * string ) +{ + Assert(0); + return 0; +} +#endif +} // end extern "C" + +#if _MSC_VER >= 1400 + +//----------------------------------------------------------------------------- +// XBox Memory Allocator Override +//----------------------------------------------------------------------------- +#if defined( _X360 ) +#if defined( _DEBUG ) || defined( USE_MEM_DEBUG ) +#include "utlmap.h" + +MEMALLOC_DEFINE_EXTERNAL_TRACKING( XMem ); + +CThreadFastMutex g_XMemAllocMutex; + +void XMemAlloc_RegisterAllocation( void *p, DWORD dwAllocAttributes ) +{ + if ( !g_pMemAlloc ) + { + // core xallocs cannot be journaled until system is ready + return; + } + + AUTO_LOCK_FM( g_XMemAllocMutex ); + int size = XMemSize( p, dwAllocAttributes ); + MemAlloc_RegisterExternalAllocation( XMem, p, size ); +} + +void XMemAlloc_RegisterDeallocation( void *p, DWORD dwAllocAttributes ) +{ + if ( !g_pMemAlloc ) + { + // core xallocs cannot be journaled until system is ready + return; + } + + AUTO_LOCK_FM( g_XMemAllocMutex ); + int size = XMemSize( p, dwAllocAttributes ); + MemAlloc_RegisterExternalDeallocation( XMem, p, size ); +} + +#else + +#define XMemAlloc_RegisterAllocation( p, a ) ((void)0) +#define XMemAlloc_RegisterDeallocation( p, a ) ((void)0) + +#endif + +//----------------------------------------------------------------------------- +// XMemAlloc +// +// XBox Memory Allocator Override +//----------------------------------------------------------------------------- +LPVOID WINAPI XMemAlloc( SIZE_T dwSize, DWORD dwAllocAttributes ) +{ + LPVOID ptr; + XALLOC_ATTRIBUTES *pAttribs = (XALLOC_ATTRIBUTES *)&dwAllocAttributes; + bool bPhysical = ( pAttribs->dwMemoryType == XALLOC_MEMTYPE_PHYSICAL ); + + if ( !bPhysical && !pAttribs->dwHeapTracksAttributes && pAttribs->dwAllocatorId != eXALLOCAllocatorId_XUI ) + { + MEM_ALLOC_CREDIT(); + switch ( pAttribs->dwAlignment ) + { + case XALLOC_ALIGNMENT_4: + ptr = g_pMemAlloc->Alloc( dwSize ); + break; + case XALLOC_ALIGNMENT_8: + ptr = MemAlloc_AllocAligned( dwSize, 8 ); + break; + case XALLOC_ALIGNMENT_DEFAULT: + case XALLOC_ALIGNMENT_16: + default: + ptr = MemAlloc_AllocAligned( dwSize, 16 ); + break; + } + if ( pAttribs->dwZeroInitialize != 0 ) + { + memset( ptr, 0, XMemSize( ptr, dwAllocAttributes ) ); + } + return ptr; + } + + ptr = XMemAllocDefault( dwSize, dwAllocAttributes ); + if ( ptr ) + { + XMemAlloc_RegisterAllocation( ptr, dwAllocAttributes ); + } + + return ptr; +} + +//----------------------------------------------------------------------------- +// XMemFree +// +// XBox Memory Allocator Override +//----------------------------------------------------------------------------- +VOID WINAPI XMemFree( PVOID pAddress, DWORD dwAllocAttributes ) +{ + if ( !pAddress ) + { + return; + } + + XALLOC_ATTRIBUTES *pAttribs = (XALLOC_ATTRIBUTES *)&dwAllocAttributes; + bool bPhysical = ( pAttribs->dwMemoryType == XALLOC_MEMTYPE_PHYSICAL ); + + if ( !bPhysical && !pAttribs->dwHeapTracksAttributes && pAttribs->dwAllocatorId != eXALLOCAllocatorId_XUI ) + { + switch ( pAttribs->dwAlignment ) + { + case XALLOC_ALIGNMENT_4: + return g_pMemAlloc->Free( pAddress ); + default: + return MemAlloc_FreeAligned( pAddress ); + } + return; + } + + XMemAlloc_RegisterDeallocation( pAddress, dwAllocAttributes ); + + XMemFreeDefault( pAddress, dwAllocAttributes ); +} + +//----------------------------------------------------------------------------- +// XMemSize +// +// XBox Memory Allocator Override +//----------------------------------------------------------------------------- +SIZE_T WINAPI XMemSize( PVOID pAddress, DWORD dwAllocAttributes ) +{ + XALLOC_ATTRIBUTES *pAttribs = (XALLOC_ATTRIBUTES *)&dwAllocAttributes; + bool bPhysical = ( pAttribs->dwMemoryType == XALLOC_MEMTYPE_PHYSICAL ); + + if ( !bPhysical && !pAttribs->dwHeapTracksAttributes && pAttribs->dwAllocatorId != eXALLOCAllocatorId_XUI ) + { + switch ( pAttribs->dwAlignment ) + { + case XALLOC_ALIGNMENT_4: + return g_pMemAlloc->GetSize( pAddress ); + default: + return MemAlloc_GetSizeAligned( pAddress ); + } + } + + return XMemSizeDefault( pAddress, dwAllocAttributes ); +} +#endif // _X360 + +#define MAX_LANG_LEN 64 /* max language name length */ +#define MAX_CTRY_LEN 64 /* max country name length */ +#define MAX_MODIFIER_LEN 0 /* max modifier name length - n/a */ +#define MAX_LC_LEN (MAX_LANG_LEN+MAX_CTRY_LEN+MAX_MODIFIER_LEN+3) + +#if _MSC_VER >= 1700 // VS 11 +// Copied from C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\crt\src\mtdll.h +#ifndef _SETLOC_STRUCT_DEFINED +struct _is_ctype_compatible { + unsigned long id; + int is_clike; +}; + +typedef struct setloc_struct { + /* getqloc static variables */ + wchar_t *pchLanguage; + wchar_t *pchCountry; + int iLocState; + int iPrimaryLen; + BOOL bAbbrevLanguage; + BOOL bAbbrevCountry; + UINT _cachecp; + wchar_t _cachein[MAX_LC_LEN]; + wchar_t _cacheout[MAX_LC_LEN]; + /* _setlocale_set_cat (LC_CTYPE) static variable */ + struct _is_ctype_compatible _Loc_c[5]; + wchar_t _cacheLocaleName[LOCALE_NAME_MAX_LENGTH]; +} _setloc_struct, *_psetloc_struct; +#define _SETLOC_STRUCT_DEFINED +#endif /* _SETLOC_STRUCT_DEFINED */ + +_CRTIMP extern unsigned long __cdecl __threadid(void); +#define _threadid (__threadid()) +_CRTIMP extern uintptr_t __cdecl __threadhandle(void); +#define _threadhandle (__threadhandle()) + +#if _MSC_VER >= 1900 +struct threadlocaleinfostruct; +struct threadmbcinfostruct; +typedef struct threadlocaleinfostruct * pthreadlocinfo; +typedef struct threadmbcinfostruct * pthreadmbcinfo; +#endif + +/* Structure for each thread's data */ + +struct _tiddata { + unsigned long _tid; /* thread ID */ + + + uintptr_t _thandle; /* thread handle */ + + int _terrno; /* errno value */ + unsigned long _tdoserrno; /* _doserrno value */ + unsigned int _fpds; /* Floating Point data segment */ + unsigned long _holdrand; /* rand() seed value */ + char * _token; /* ptr to strtok() token */ + wchar_t * _wtoken; /* ptr to wcstok() token */ + unsigned char * _mtoken; /* ptr to _mbstok() token */ + + /* following pointers get malloc'd at runtime */ + char * _errmsg; /* ptr to strerror()/_strerror() buff */ + wchar_t * _werrmsg; /* ptr to _wcserror()/__wcserror() buff */ + char * _namebuf0; /* ptr to tmpnam() buffer */ + wchar_t * _wnamebuf0; /* ptr to _wtmpnam() buffer */ + char * _namebuf1; /* ptr to tmpfile() buffer */ + wchar_t * _wnamebuf1; /* ptr to _wtmpfile() buffer */ + char * _asctimebuf; /* ptr to asctime() buffer */ + wchar_t * _wasctimebuf; /* ptr to _wasctime() buffer */ + void * _gmtimebuf; /* ptr to gmtime() structure */ + char * _cvtbuf; /* ptr to ecvt()/fcvt buffer */ + unsigned char _con_ch_buf[MB_LEN_MAX]; + /* ptr to putch() buffer */ + unsigned short _ch_buf_used; /* if the _con_ch_buf is used */ + + /* following fields are needed by _beginthread code */ + void * _initaddr; /* initial user thread address */ + void * _initarg; /* initial user thread argument */ + + /* following three fields are needed to support signal handling and + * runtime errors */ + void * _pxcptacttab; /* ptr to exception-action table */ + void * _tpxcptinfoptrs; /* ptr to exception info pointers */ + int _tfpecode; /* float point exception code */ + + /* pointer to the copy of the multibyte character information used by + * the thread */ + pthreadmbcinfo ptmbcinfo; + + /* pointer to the copy of the locale informaton used by the thead */ + pthreadlocinfo ptlocinfo; + int _ownlocale; /* if 1, this thread owns its own locale */ + + /* following field is needed by NLG routines */ + unsigned long _NLG_dwCode; + + /* + * Per-Thread data needed by C++ Exception Handling + */ + void * _terminate; /* terminate() routine */ + void * _unexpected; /* unexpected() routine */ + void * _translator; /* S.E. translator */ + void * _purecall; /* called when pure virtual happens */ + void * _curexception; /* current exception */ + void * _curcontext; /* current exception context */ + int _ProcessingThrow; /* for uncaught_exception */ + void * _curexcspec; /* for handling exceptions thrown from std::unexpected */ +#if defined (_M_X64) || defined (_M_ARM) + void * _pExitContext; + void * _pUnwindContext; + void * _pFrameInfoChain; +#if defined (_WIN64) + unsigned __int64 _ImageBase; + unsigned __int64 _ThrowImageBase; +#else /* defined (_WIN64) */ + unsigned __int32 _ImageBase; + unsigned __int32 _ThrowImageBase; +#endif /* defined (_WIN64) */ + void * _pForeignException; +#elif defined (_M_IX86) + void * _pFrameInfoChain; +#endif /* defined (_M_IX86) */ + _setloc_struct _setloc_data; + + void * _reserved1; /* nothing */ + void * _reserved2; /* nothing */ + void * _reserved3; /* nothing */ +#ifdef _M_IX86 + void * _reserved4; /* nothing */ + void * _reserved5; /* nothing */ +#endif /* _M_IX86 */ + + int _cxxReThrow; /* Set to True if it's a rethrown C++ Exception */ + + unsigned long __initDomain; /* initial domain used by _beginthread[ex] for managed function */ +}; +#else +struct _is_ctype_compatible { + unsigned long id; + int is_clike; +}; + +typedef struct setloc_struct { + /* getqloc static variables */ + char *pchLanguage; + char *pchCountry; + int iLcidState; + int iPrimaryLen; + BOOL bAbbrevLanguage; + BOOL bAbbrevCountry; + LCID lcidLanguage; + LCID lcidCountry; + /* expand_locale static variables */ + LC_ID _cacheid; + UINT _cachecp; + char _cachein[MAX_LC_LEN]; + char _cacheout[MAX_LC_LEN]; + /* _setlocale_set_cat (LC_CTYPE) static variable */ + struct _is_ctype_compatible _Lcid_c[5]; +} _setloc_struct, *_psetloc_struct; + +struct _tiddata { + unsigned long _tid; /* thread ID */ + + + uintptr_t _thandle; /* thread handle */ + + int _terrno; /* errno value */ + unsigned long _tdoserrno; /* _doserrno value */ + unsigned int _fpds; /* Floating Point data segment */ + unsigned long _holdrand; /* rand() seed value */ + char * _token; /* ptr to strtok() token */ + wchar_t * _wtoken; /* ptr to wcstok() token */ + unsigned char * _mtoken; /* ptr to _mbstok() token */ + + /* following pointers get malloc'd at runtime */ + char * _errmsg; /* ptr to strerror()/_strerror() buff */ + wchar_t * _werrmsg; /* ptr to _wcserror()/__wcserror() buff */ + char * _namebuf0; /* ptr to tmpnam() buffer */ + wchar_t * _wnamebuf0; /* ptr to _wtmpnam() buffer */ + char * _namebuf1; /* ptr to tmpfile() buffer */ + wchar_t * _wnamebuf1; /* ptr to _wtmpfile() buffer */ + char * _asctimebuf; /* ptr to asctime() buffer */ + wchar_t * _wasctimebuf; /* ptr to _wasctime() buffer */ + void * _gmtimebuf; /* ptr to gmtime() structure */ + char * _cvtbuf; /* ptr to ecvt()/fcvt buffer */ + unsigned char _con_ch_buf[MB_LEN_MAX]; + /* ptr to putch() buffer */ + unsigned short _ch_buf_used; /* if the _con_ch_buf is used */ + + /* following fields are needed by _beginthread code */ + void * _initaddr; /* initial user thread address */ + void * _initarg; /* initial user thread argument */ + + /* following three fields are needed to support signal handling and + * runtime errors */ + void * _pxcptacttab; /* ptr to exception-action table */ + void * _tpxcptinfoptrs; /* ptr to exception info pointers */ + int _tfpecode; /* float point exception code */ + + /* pointer to the copy of the multibyte character information used by + * the thread */ + pthreadmbcinfo ptmbcinfo; + + /* pointer to the copy of the locale informaton used by the thead */ + pthreadlocinfo ptlocinfo; + int _ownlocale; /* if 1, this thread owns its own locale */ + + /* following field is needed by NLG routines */ + unsigned long _NLG_dwCode; + + /* + * Per-Thread data needed by C++ Exception Handling + */ + void * _terminate; /* terminate() routine */ + void * _unexpected; /* unexpected() routine */ + void * _translator; /* S.E. translator */ + void * _purecall; /* called when pure virtual happens */ + void * _curexception; /* current exception */ + void * _curcontext; /* current exception context */ + int _ProcessingThrow; /* for uncaught_exception */ + void * _curexcspec; /* for handling exceptions thrown from std::unexpected */ +#if defined (_M_IA64) || defined (_M_AMD64) + void * _pExitContext; + void * _pUnwindContext; + void * _pFrameInfoChain; + unsigned __int64 _ImageBase; +#if defined (_M_IA64) + unsigned __int64 _TargetGp; +#endif /* defined (_M_IA64) */ + unsigned __int64 _ThrowImageBase; + void * _pForeignException; +#elif defined (_M_IX86) + void * _pFrameInfoChain; +#endif /* defined (_M_IX86) */ + _setloc_struct _setloc_data; + + void * _encode_ptr; /* EncodePointer() routine */ + void * _decode_ptr; /* DecodePointer() routine */ + + void * _reserved1; /* nothing */ + void * _reserved2; /* nothing */ + void * _reserved3; /* nothing */ + + int _cxxReThrow; /* Set to True if it's a rethrown C++ Exception */ + + unsigned long __initDomain; /* initial domain used by _beginthread[ex] for managed function */ +}; +#endif + +#if _MSC_VER >= 1900 +typedef __crt_locale_pointers _locale_tstruct; +#endif + +typedef struct _tiddata * _ptiddata; + +class _LocaleUpdate +{ + _locale_tstruct localeinfo; + _ptiddata ptd; + bool updated; + public: + _LocaleUpdate(_locale_t plocinfo) + : updated(false) + { + /* + if (plocinfo == NULL) + { + ptd = _getptd(); + localeinfo.locinfo = ptd->ptlocinfo; + localeinfo.mbcinfo = ptd->ptmbcinfo; + + __UPDATE_LOCALE(ptd, localeinfo.locinfo); + __UPDATE_MBCP(ptd, localeinfo.mbcinfo); + if (!(ptd->_ownlocale & _PER_THREAD_LOCALE_BIT)) + { + ptd->_ownlocale |= _PER_THREAD_LOCALE_BIT; + updated = true; + } + } + else + { + localeinfo=*plocinfo; + } + */ + } + ~_LocaleUpdate() + { +// if (updated) +// ptd->_ownlocale = ptd->_ownlocale & ~_PER_THREAD_LOCALE_BIT; + } + _locale_t GetLocaleT() + { + return &localeinfo; + } +}; + + +#pragma warning(push) +#pragma warning(disable: 4483) +#if _MSC_FULL_VER >= 140050415 +#define _NATIVE_STARTUP_NAMESPACE __identifier("") +#else /* _MSC_FULL_VER >= 140050415 */ +#define _NATIVE_STARTUP_NAMESPACE __CrtImplementationDetails +#endif /* _MSC_FULL_VER >= 140050415 */ + +namespace _NATIVE_STARTUP_NAMESPACE +{ + class NativeDll + { + private: + static const unsigned int ProcessDetach = 0; + static const unsigned int ProcessAttach = 1; + static const unsigned int ThreadAttach = 2; + static const unsigned int ThreadDetach = 3; + static const unsigned int ProcessVerifier = 4; + + public: + + inline static bool IsInDllMain() + { + return false; + } + + inline static bool IsInProcessAttach() + { + return false; + } + + inline static bool IsInProcessDetach() + { + return false; + } + + inline static bool IsInVcclrit() + { + return false; + } + + inline static bool IsSafeForManagedCode() + { + if (!IsInDllMain()) + { + return true; + } + + if (IsInVcclrit()) + { + return true; + } + + return !IsInProcessAttach() && !IsInProcessDetach(); + } + }; +} +#pragma warning(pop) + +#endif // _MSC_VER >= 1400 + +#endif // !STEAM && !NO_MALLOC_OVERRIDE + +#endif // _WIN32 diff --git a/public/tier0/minidump.h b/public/tier0/minidump.h new file mode 100644 index 0000000..e650725 --- /dev/null +++ b/public/tier0/minidump.h @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MINIDUMP_H +#define MINIDUMP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// Set prefix to use for minidump files. If you don't set one, it is defaulted for you, +// using the current module name +PLATFORM_INTERFACE void SetMinidumpFilenamePrefix( const char *pszPrefix ); + +// Set comment to put into minidump file upon next call of WriteMiniDump. (Most common use is the assert text.) +PLATFORM_INTERFACE void SetMinidumpComment( const char *pszComment ); + +// writes out a minidump of the current stack trace with a unique filename +PLATFORM_INTERFACE void WriteMiniDump( const char *pszFilenameSuffix = NULL ); + +typedef void (*FnWMain)( int , tchar *[] ); +typedef void (*FnVoidPtrFn)( void * ); + +#if defined(_WIN32) && !defined(_X360) + +// calls the passed in function pointer and catches any exceptions/crashes thrown by it, and writes a minidump +// use from wmain() to protect the whole program +typedef void (*FnWMain)( int , tchar *[] ); +typedef int (*FnWMainIntRet)( int , tchar *[] ); +typedef void (*FnVoidPtrFn)( void * ); + +enum ECatchAndWriteMinidumpAction +{ + k_ECatchAndWriteMiniDumpAbort = 0, + k_ECatchAndWriteMiniDumpReThrow = 1, + k_ECatchAndWriteMiniDumpIgnore = 2, +}; + +PLATFORM_INTERFACE void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ); // action = Abort +PLATFORM_INTERFACE void CatchAndWriteMiniDumpForVoidPtrFn( FnVoidPtrFn pfn, void *pv, bool bExitQuietly ); // action = abort if bExitQuietly, Rethrow otherwise + +PLATFORM_INTERFACE void CatchAndWriteMiniDumpEx( FnWMain pfn, int argc, tchar *argv[], ECatchAndWriteMinidumpAction eAction ); +PLATFORM_INTERFACE int CatchAndWriteMiniDumpExReturnsInt( FnWMainIntRet pfn, int argc, tchar *argv[], ECatchAndWriteMinidumpAction eAction ); +PLATFORM_INTERFACE void CatchAndWriteMiniDumpExForVoidPtrFn( FnVoidPtrFn pfn, void *pv, ECatchAndWriteMinidumpAction eAction ); + +// Let's not include this. We'll use forwards instead. +//#include +struct _EXCEPTION_POINTERS; + +// Replaces the current function pointer with the one passed in. +// Returns the previously-set function. +// The function is called internally by WriteMiniDump() and CatchAndWriteMiniDump() +// The default is the built-in function that uses DbgHlp.dll's MiniDumpWriteDump function +typedef void (*FnMiniDump)( unsigned int uStructuredExceptionCode, _EXCEPTION_POINTERS * pExceptionInfo, const char *pszFilenameSuffix ); +PLATFORM_INTERFACE FnMiniDump SetMiniDumpFunction( FnMiniDump pfn ); + +// Use this to write a minidump explicitly. +// Some of the tools choose to catch the minidump themselves instead of using CatchAndWriteMinidump +// so they can show their own dialog. +// +// ptchMinidumpFileNameBuffer if not-NULL should be a writable tchar buffer of length at +// least _MAX_PATH and on return will contain the name of the minidump file written. +// If ptchMinidumpFileNameBuffer is NULL the name of the minidump file written will not +// be available after the function returns. +// +PLATFORM_INTERFACE bool WriteMiniDumpUsingExceptionInfo( + unsigned int uStructuredExceptionCode, + _EXCEPTION_POINTERS * pExceptionInfo, + int /* MINIDUMP_TYPE */ minidumpType, + const char *pszFilenameSuffix = NULL, + tchar *ptchMinidumpFileNameBuffer = NULL + ); + +// Call this to enable a handler for unhandled exceptions. +PLATFORM_INTERFACE void MinidumpSetUnhandledExceptionFunction( FnMiniDump pfn ); + +// Call this to prevent crashes in kernel callbacks such as window procs from +// being silently swallowed. We should always call this at startup. +PLATFORM_INTERFACE void EnableCrashingOnCrashes(); + +#endif // defined(_WIN32) && !defined(_X360) + +// +// Minidump User Stream Info Comments. +// +// There currently is a single header string, and an array of 64 comment strings. +// MinidumpUserStreamInfoSetHeader() will set the single header string. +// MinidumpUserStreamInfoAppend() will round robin through and array and set the comment strings, overwriting old. +PLATFORM_INTERFACE void MinidumpUserStreamInfoSetHeader( const char *pFormat, ... ); +PLATFORM_INTERFACE void MinidumpUserStreamInfoAppend( const char *pFormat, ... ); + +// Retrieve the StreamInfo strings. +// Index 0: header string +// Index 1..: comment string +// Returns NULL when you've reached the end of the comment string array +// Empty strings ("\0") can be returned if comment hasn't been set +PLATFORM_INTERFACE const char *MinidumpUserStreamInfoGet( int Index ); + +#endif // MINIDUMP_H + diff --git a/public/tier0/platform.h b/public/tier0/platform.h new file mode 100644 index 0000000..900ddcb --- /dev/null +++ b/public/tier0/platform.h @@ -0,0 +1,1599 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef PLATFORM_H +#define PLATFORM_H + +#if defined(__x86_64__) || defined(_WIN64) +#define PLATFORM_64BITS 1 +#endif + +#if defined(__GCC__) || defined(__GNUC__) +#define COMPILER_GCC 1 +#endif + +#ifdef __clang__ +#define COMPILER_CLANG 1 +#endif + +#if defined( _X360 ) + #define NO_STEAM + #define NO_VOICE + // for the 360, the ppc platform and the rtos are tightly coupled + // setup the 360 environment here !once! for much less leaf module include wackiness + // these are critical order and purposely appear *before* anything else + #define _XBOX +#include + #include + #include +#include + #include + #include +#include + #undef _XBOX +#endif + +#include "wchartypes.h" +#include "basetypes.h" +#include "tier0/valve_off.h" + +#ifdef _DEBUG +#if !defined( PLAT_COMPILE_TIME_ASSERT ) +#define PLAT_COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#endif +#else +#if !defined( PLAT_COMPILE_TIME_ASSERT ) +#define PLAT_COMPILE_TIME_ASSERT( pred ) +#endif +#endif + +#ifdef _WIN32 +#pragma once +#endif + +// feature enables +#define NEW_SOFTWARE_LIGHTING + +#ifdef POSIX +// need this for _alloca +#include +#include +#include +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif +#include + +// need this for memset +#include + +#include "tier0/valve_minmax_on.h" // GCC 4.2.2 headers screw up our min/max defs. + +#ifdef _RETAIL +#define IsRetail() true +#else +#define IsRetail() false +#endif + +#ifdef _DEBUG +#define IsRelease() false +#define IsDebug() true +#else +#define IsRelease() true +#define IsDebug() false +#endif + +// Deprecating, infavor of IsX360() which will revert to IsXbox() +// after confidence of xbox 1 code flush +#define IsXbox() false + +#ifdef _WIN32 + #define IsLinux() false + #define IsOSX() false + #define IsPosix() false + #define PLATFORM_WINDOWS 1 // Windows PC or Xbox 360 + #ifndef _X360 + #define IsWindows() true + #define IsPC() true + #define IsConsole() false + #define IsX360() false + #define IsPS3() false + #define IS_WINDOWS_PC + #define PLATFORM_WINDOWS_PC 1 // Windows PC + #ifdef _WIN64 + #define IsPlatformWindowsPC64() true + #define IsPlatformWindowsPC32() false + #define PLATFORM_WINDOWS_PC64 1 + #else + #define IsPlatformWindowsPC64() false + #define IsPlatformWindowsPC32() true + #define PLATFORM_WINDOWS_PC32 1 + #endif + #else + #define PLATFORM_X360 1 + #ifndef _CONSOLE + #define _CONSOLE + #endif + #define IsWindows() false + #define IsPC() false + #define IsConsole() true + #define IsX360() true + #define IsPS3() false + #endif + // Adding IsPlatformOpenGL() to help fix a bunch of code that was using IsPosix() to infer if the DX->GL translation layer was being used. + #if defined( DX_TO_GL_ABSTRACTION ) + #define IsPlatformOpenGL() true + #else + #define IsPlatformOpenGL() false + #endif +#elif defined(POSIX) + #define IsPC() true + #define IsWindows() false + #define IsConsole() false + #define IsX360() false + #define IsPS3() false + #if defined( LINUX ) + #define IsLinux() true + #else + #define IsLinux() false + #endif + + #if defined( OSX ) + #define IsOSX() true + #else + #define IsOSX() false + #endif + + #define IsPosix() true + #define IsPlatformOpenGL() true +#else + #error +#endif + +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( _WIN32 ) + + typedef __int16 int16; + typedef unsigned __int16 uint16; + typedef __int32 int32; + typedef unsigned __int32 uint32; + typedef __int64 int64; + typedef unsigned __int64 uint64; + + #ifdef PLATFORM_64BITS + typedef __int64 intp; // intp is an integer that can accomodate a pointer + typedef unsigned __int64 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) + #else + typedef __int32 intp; + typedef unsigned __int32 uintp; + #endif + + #if defined( _X360 ) + #ifdef __m128 + #undef __m128 + #endif + #define __m128 __vector4 + #endif + + // Use this to specify that a function is an override of a virtual function. + // This lets the compiler catch cases where you meant to override a virtual + // function but you accidentally changed the function signature and created + // an overloaded function. Usage in function declarations is like this: + // int GetData() const OVERRIDE; + #define OVERRIDE override + +#else // _WIN32 + + typedef short int16; + typedef unsigned short uint16; + typedef int int32; + typedef unsigned int uint32; + typedef long long int64; + typedef unsigned long long uint64; + #ifdef PLATFORM_64BITS + typedef long long intp; + typedef unsigned long long uintp; + #else + typedef int intp; + typedef unsigned int uintp; + #endif + typedef void *HWND; + + // Avoid redefinition warnings if a previous header defines this. + #undef OVERRIDE + #if __cplusplus >= 201103L + #define OVERRIDE override + #if defined(__clang__) + // warning: 'override' keyword is a C++11 extension [-Wc++11-extensions] + // Disabling this warning is less intrusive than enabling C++11 extensions + #pragma GCC diagnostic ignored "-Wc++11-extensions" + #endif + #else + #define OVERRIDE + #endif + +#endif // else _WIN32 + +//----------------------------------------------------------------------------- +// Set up platform type defines. +//----------------------------------------------------------------------------- +#if defined( PLATFORM_X360 ) || defined( _PS3 ) + #if !defined( _GAMECONSOLE ) + #define _GAMECONSOLE + #endif + #define IsPC() false + #define IsGameConsole() true +#else + #define IsPC() true + #define IsGameConsole() false +#endif + +#ifdef PLATFORM_64BITS + #define IsPlatform64Bits() true +#else + #define IsPlatform64Bits() false +#endif + +// From steam/steamtypes.h +// RTime32 +// We use this 32 bit time representing real world time. +// It offers 1 second resolution beginning on January 1, 1970 (Unix time) +typedef uint32 RTime32; + +typedef float float32; +typedef double float64; + +// for when we don't care about how many bits we use +typedef unsigned int uint; + +#ifdef _MSC_VER +#pragma once +// Ensure that everybody has the right compiler version installed. The version +// number can be obtained by looking at the compiler output when you type 'cl' +// and removing the last two digits and the periods: 16.00.40219.01 becomes 160040219 +#if _MSC_FULL_VER > 180000000 + #if _MSC_FULL_VER < 180030723 + #error You must install VS 2013 Update 3 + #endif +#elif _MSC_FULL_VER > 160000000 + #if _MSC_FULL_VER < 160040219 + #error You must install VS 2010 SP1 + #endif +#else + #if _MSC_FULL_VER < 140050727 + #error You must install VS 2005 SP1 + #endif +#endif +#endif + +// This can be used to ensure the size of pointers to members when declaring +// a pointer type for a class that has only been forward declared +#ifdef _MSC_VER +#define SINGLE_INHERITANCE __single_inheritance +#define MULTIPLE_INHERITANCE __multiple_inheritance +#else +#define SINGLE_INHERITANCE +#define MULTIPLE_INHERITANCE +#endif + +#ifdef _MSC_VER +#define NO_VTABLE __declspec( novtable ) +#else +#define NO_VTABLE +#endif + +#ifdef _MSC_VER + // This indicates that a function never returns, which helps with + // generating accurate compiler warnings + #define NORETURN __declspec( noreturn ) +#else + #define NORETURN +#endif + +// This can be used to declare an abstract (interface only) class. +// Classes marked abstract should not be instantiated. If they are, and access violation will occur. +// +// Example of use: +// +// abstract_class CFoo +// { +// ... +// } +// +// MSDN __declspec(novtable) documentation: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_langref_novtable.asp +// +// Note: NJS: This is not enabled for regular PC, due to not knowing the implications of exporting a class with no no vtable. +// It's probable that this shouldn't be an issue, but an experiment should be done to verify this. +// +#ifndef _X360 +#define abstract_class class +#else +#define abstract_class class NO_VTABLE +#endif + + +// MSVC CRT uses 0x7fff while gcc uses MAX_INT, leading to mismatches between platforms +// As a result, we pick the least common denominator here. This should be used anywhere +// you might typically want to use RAND_MAX +#define VALVE_RAND_MAX 0x7fff + + + +/* +FIXME: Enable this when we no longer fear change =) + +// need these for the limits +#include +#include + +// Maximum and minimum representable values +#define INT8_MAX SCHAR_MAX +#define INT16_MAX SHRT_MAX +#define INT32_MAX LONG_MAX +#define INT64_MAX (((int64)~0) >> 1) + +#define INT8_MIN SCHAR_MIN +#define INT16_MIN SHRT_MIN +#define INT32_MIN LONG_MIN +#define INT64_MIN (((int64)1) << 63) + +#define UINT8_MAX ((uint8)~0) +#define UINT16_MAX ((uint16)~0) +#define UINT32_MAX ((uint32)~0) +#define UINT64_MAX ((uint64)~0) + +#define UINT8_MIN 0 +#define UINT16_MIN 0 +#define UINT32_MIN 0 +#define UINT64_MIN 0 + +#ifndef UINT_MIN +#define UINT_MIN UINT32_MIN +#endif + +#define FLOAT32_MAX FLT_MAX +#define FLOAT64_MAX DBL_MAX + +#define FLOAT32_MIN FLT_MIN +#define FLOAT64_MIN DBL_MIN +*/ + +// portability / compiler settings +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#elif POSIX +#if defined( OSX ) && defined( CARBON_WORKAROUND ) +#define DWORD unsigned int +#else +typedef unsigned int DWORD; +#endif +typedef unsigned short WORD; +typedef void * HINSTANCE; +#define _MAX_PATH PATH_MAX +#define __cdecl +#define __stdcall +#define __declspec + +#endif // defined(_WIN32) && !defined(WINDED) + + +// Defines MAX_PATH +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +#ifdef _WIN32 +#define MAX_UNICODE_PATH 32767 +#else +#define MAX_UNICODE_PATH MAX_PATH +#endif + +#define MAX_UNICODE_PATH_IN_UTF8 MAX_UNICODE_PATH*4 + +#ifdef GNUC +#undef offsetof +//#define offsetof( type, var ) __builtin_offsetof( type, var ) +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#else +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + + +#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression + +// Used to step into the debugger +#if defined( _WIN32 ) && !defined( _X360 ) +#define DebuggerBreak() __debugbreak() +#elif defined( _X360 ) +#define DebuggerBreak() DebugBreak() +#else + // On OSX, SIGTRAP doesn't really stop the thread cold when debugging. + // So if being debugged, use INT3 which is precise. +#ifdef OSX +#define DebuggerBreak() if ( Plat_IsInDebugSession() ) { __asm ( "int $3" ); } else { raise(SIGTRAP); } +#else +#define DebuggerBreak() raise(SIGTRAP) +#endif +#endif +#define DebuggerBreakIfDebugging() if ( !Plat_IsInDebugSession() ) ; else DebuggerBreak() + +#ifdef STAGING_ONLY +#define DebuggerBreakIfDebugging_StagingOnly() if ( !Plat_IsInDebugSession() ) ; else DebuggerBreak() +#else +#define DebuggerBreakIfDebugging_StagingOnly() +#endif + +// Allows you to specify code that should only execute if we are in a staging build. Otherwise the code noops. +#ifdef STAGING_ONLY +#define STAGING_ONLY_EXEC( _exec ) do { _exec; } while (0) +#else +#define STAGING_ONLY_EXEC( _exec ) do { } while (0) +#endif + +// C functions for external declarations that call the appropriate C++ methods +#ifndef EXPORT + #ifdef _WIN32 + #define EXPORT _declspec( dllexport ) + #else + #define EXPORT /* */ + #endif +#endif + +#if defined __i386__ && !defined __linux__ + #define id386 1 +#else + #define id386 0 +#endif // __i386__ + +// decls for aligning data +#ifdef _WIN32 + #define DECL_ALIGN(x) __declspec(align(x)) + +#elif GNUC + #define DECL_ALIGN(x) __attribute__((aligned(x))) +#else + #define DECL_ALIGN(x) /* */ +#endif + +#ifdef _MSC_VER +// MSVC has the align at the start of the struct +#define ALIGN4 DECL_ALIGN(4) +#define ALIGN8 DECL_ALIGN(8) +#define ALIGN16 DECL_ALIGN(16) +#define ALIGN32 DECL_ALIGN(32) +#define ALIGN128 DECL_ALIGN(128) + +#define ALIGN4_POST +#define ALIGN8_POST +#define ALIGN16_POST +#define ALIGN32_POST +#define ALIGN128_POST +#elif defined( GNUC ) +// gnuc has the align decoration at the end +#define ALIGN4 +#define ALIGN8 +#define ALIGN16 +#define ALIGN32 +#define ALIGN128 + +#define ALIGN4_POST DECL_ALIGN(4) +#define ALIGN8_POST DECL_ALIGN(8) +#define ALIGN16_POST DECL_ALIGN(16) +#define ALIGN32_POST DECL_ALIGN(32) +#define ALIGN128_POST DECL_ALIGN(128) +#else +#error +#endif + +// Pull in the /analyze code annotations. +#include "annotations.h" + +//----------------------------------------------------------------------------- +// Convert int<-->pointer, avoiding 32/64-bit compiler warnings: +//----------------------------------------------------------------------------- +#define INT_TO_POINTER( i ) (void *)( ( i ) + (char *)NULL ) +#define POINTER_TO_INT( p ) ( (int)(uintp)( p ) ) + + +//----------------------------------------------------------------------------- +// Stack-based allocation related helpers +//----------------------------------------------------------------------------- +#if defined( GNUC ) + #define stackalloc( _size ) alloca( ALIGN_VALUE( _size, 16 ) ) +#ifdef _LINUX + #define mallocsize( _p ) ( malloc_usable_size( _p ) ) +#elif defined(OSX) + #define mallocsize( _p ) ( malloc_size( _p ) ) +#else +#error +#endif +#elif defined ( _WIN32 ) + #define stackalloc( _size ) _alloca( ALIGN_VALUE( _size, 16 ) ) + #define mallocsize( _p ) ( _msize( _p ) ) +#endif + +#define stackfree( _p ) 0 + +// Linux had a few areas where it didn't construct objects in the same order that Windows does. +// So when CVProfile::CVProfile() would access g_pMemAlloc, it would crash because the allocator wasn't initalized yet. +#ifdef POSIX + #define CONSTRUCT_EARLY __attribute__((init_priority(101))) +#else + #define CONSTRUCT_EARLY + #endif + +#if defined(_MSC_VER) + #define SELECTANY __declspec(selectany) + #define RESTRICT __restrict + #define RESTRICT_FUNC __declspec(restrict) + #define FMTFUNCTION( a, b ) +#elif defined(GNUC) + #define SELECTANY __attribute__((weak)) + #if defined(LINUX) && !defined(DEDICATED) + #define RESTRICT + #else + #define RESTRICT __restrict + #endif + #define RESTRICT_FUNC + // squirrel.h does a #define printf DevMsg which leads to warnings when we try + // to use printf as the prototype format function. Using __printf__ instead. + #define FMTFUNCTION( fmtargnumber, firstvarargnumber ) __attribute__ (( format( __printf__, fmtargnumber, firstvarargnumber ))) +#else + #define SELECTANY static + #define RESTRICT + #define RESTRICT_FUNC + #define FMTFUNCTION( a, b ) +#endif + +#if defined( _WIN32 ) + + // Used for dll exporting and importing + #define DLL_EXPORT extern "C" __declspec( dllexport ) + #define DLL_IMPORT extern "C" __declspec( dllimport ) + + // Can't use extern "C" when DLL exporting a class + #define DLL_CLASS_EXPORT __declspec( dllexport ) + #define DLL_CLASS_IMPORT __declspec( dllimport ) + + // Can't use extern "C" when DLL exporting a global + #define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) + #define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) + + #define DLL_LOCAL + +#elif defined GNUC +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" __attribute__ ((visibility("default"))) +#define DLL_IMPORT extern "C" + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT __attribute__ ((visibility("default"))) +#define DLL_CLASS_IMPORT + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern __attribute ((visibility("default"))) +#define DLL_GLOBAL_IMPORT extern + +#define DLL_LOCAL __attribute__ ((visibility("hidden"))) + +#else +#error "Unsupported Platform." +#endif + +// Used for standard calling conventions +#if defined( _WIN32 ) && !defined( _X360 ) + #define STDCALL __stdcall + #define FASTCALL __fastcall + #define FORCEINLINE __forceinline + // GCC 3.4.1 has a bug in supporting forced inline of templated functions + // this macro lets us not force inlining in that case + #define FORCEINLINE_TEMPLATE __forceinline +#elif defined( _X360 ) + #define STDCALL __stdcall + #ifdef FORCEINLINE + #undef FORCEINLINE +#endif + #define FORCEINLINE __forceinline + #define FORCEINLINE_TEMPLATE __forceinline + #else + #define STDCALL + #define FASTCALL + #ifdef _LINUX_DEBUGGABLE + #define FORCEINLINE + #else + #define FORCEINLINE inline __attribute__ ((always_inline)) + #endif + // GCC 3.4.1 has a bug in supporting forced inline of templated functions + // this macro lets us not force inlining in that case + #define FORCEINLINE_TEMPLATE inline +// #define __stdcall __attribute__ ((__stdcall__)) +#endif + +// Force a function call site -not- to inlined. (useful for profiling) +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +// Pass hints to the compiler to prevent it from generating unnessecary / stupid code +// in certain situations. Several compilers other than MSVC also have an equivilent +// construct. +// +// Essentially the 'Hint' is that the condition specified is assumed to be true at +// that point in the compilation. If '0' is passed, then the compiler assumes that +// any subsequent code in the same 'basic block' is unreachable, and thus usually +// removed. +#ifdef _MSC_VER + #define HINT(THE_HINT) __assume((THE_HINT)) +#else + #define HINT(THE_HINT) 0 +#endif + +// Marks the codepath from here until the next branch entry point as unreachable, +// and asserts if any attempt is made to execute it. +#define UNREACHABLE() { Assert(0); HINT(0); } + +// In cases where no default is present or appropriate, this causes MSVC to generate +// as little code as possible, and throw an assertion in debug. +#define NO_DEFAULT default: UNREACHABLE(); + + +#if defined( LINUX ) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406 + // based on some Jonathan Wakely macros on the net... + #define GCC_DIAG_STR(s) #s + #define GCC_DIAG_JOINSTR(x,y) GCC_DIAG_STR(x ## y) + #define GCC_DIAG_DO_PRAGMA(x) _Pragma (#x) + #define GCC_DIAG_PRAGMA(x) GCC_DIAG_DO_PRAGMA(GCC diagnostic x) + + #define GCC_DIAG_PUSH_OFF(x) GCC_DIAG_PRAGMA(push) GCC_DIAG_PRAGMA(ignored GCC_DIAG_JOINSTR(-W,x)) + #define GCC_DIAG_POP() GCC_DIAG_PRAGMA(pop) +#else + #define GCC_DIAG_PUSH_OFF(x) + #define GCC_DIAG_POP() +#endif + +#ifdef LINUX +#pragma GCC diagnostic ignored "-Wconversion-null" // passing NULL to non-pointer argument 1 +#pragma GCC diagnostic ignored "-Wpointer-arith" // NULL used in arithmetic. Ie, vpanel == NULL where VPANEL is uint. +#pragma GCC diagnostic ignored "-Wswitch" // enumeration values not handled in switch +#endif + +#ifdef OSX +#pragma GCC diagnostic ignored "-Wconversion-null" // passing NULL to non-pointer argument 1 +#pragma GCC diagnostic ignored "-Wnull-arithmetic" // NULL used in arithmetic. Ie, vpanel == NULL where VPANEL is uint. +#pragma GCC diagnostic ignored "-Wswitch-enum" // enumeration values not handled in switch +#pragma GCC diagnostic ignored "-Wswitch" // enumeration values not handled in switch +#endif + + +#ifdef POSIX +#define _stricmp stricmp +#define strcmpi stricmp +#define stricmp strcasecmp +#define _vsnprintf vsnprintf +#define _alloca alloca +#ifdef _snprintf +#undef _snprintf +#endif +#define _snprintf snprintf +#define GetProcAddress dlsym +#define _chdir chdir +#define _strnicmp strnicmp +#define strnicmp strncasecmp +#define _getcwd getcwd +#define _snwprintf swprintf +#define swprintf_s swprintf +#define wcsicmp _wcsicmp +#define _wcsicmp wcscmp +#define _finite finite +#define _tempnam tempnam +#define _unlink unlink +#define _access access +#define _mkdir(dir) mkdir( dir, S_IRWXU | S_IRWXG | S_IRWXO ) +#define _wtoi(arg) wcstol(arg, NULL, 10) +#define _wtoi64(arg) wcstoll(arg, NULL, 10) + +typedef uint32 HMODULE; +typedef void *HANDLE; +#endif + +//----------------------------------------------------------------------------- +// fsel +//----------------------------------------------------------------------------- +#ifndef _X360 + +static FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} +static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} + +#else + +// __fsel(double fComparand, double fValGE, double fLT) == fComparand >= 0 ? fValGE : fLT +// this is much faster than if ( aFloat > 0 ) { x = .. } +#define fsel __fsel + +#endif + + +//----------------------------------------------------------------------------- +// FP exception handling +//----------------------------------------------------------------------------- +//#define CHECK_FLOAT_EXCEPTIONS 1 + +#if !defined( _X360 ) +#if defined( _MSC_VER ) + + #if defined( PLATFORM_WINDOWS_PC64 ) + inline void SetupFPUControlWord() + { + } + #else + inline void SetupFPUControlWordForceExceptions() + { + // use local to get and store control word + uint16 tmpCtrlW; + __asm + { + fnclex /* clear all current exceptions */ + fnstcw word ptr [tmpCtrlW] /* get current control word */ + and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */ + or [tmpCtrlW], 0230h /* set to 53-bit, mask only inexact, underflow */ + fldcw word ptr [tmpCtrlW] /* put new control word in FPU */ + } + } + + #ifdef CHECK_FLOAT_EXCEPTIONS + + inline void SetupFPUControlWord() + { + SetupFPUControlWordForceExceptions(); + } + + #else + + inline void SetupFPUControlWord() + { + // use local to get and store control word + uint16 tmpCtrlW; + __asm + { + fnstcw word ptr [tmpCtrlW] /* get current control word */ + and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */ + or [tmpCtrlW], 023Fh /* set to 53-bit, mask only inexact, underflow */ + fldcw word ptr [tmpCtrlW] /* put new control word in FPU */ + } + } + + #endif + #endif + +#else + + inline void SetupFPUControlWord() + { + __volatile unsigned short int __cw; + __asm __volatile ("fnstcw %0" : "=m" (__cw)); + __cw = __cw & 0x0FCC0; // keep infinity control, keep rounding mode + __cw = __cw | 0x023F; // set 53-bit, no exceptions + __asm __volatile ("fldcw %0" : : "m" (__cw)); + } + +#endif // _MSC_VER + +#else + + #ifdef _DEBUG + FORCEINLINE bool IsFPUControlWordSet() + { + float f = 0.996f; + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw( f ); + return ( pResult[1] == 1 ); + } + #endif + + inline void SetupFPUControlWord() + { + // Set round-to-nearest in FPSCR + // (cannot assemble, must use op-code form) + __emit( 0xFF80010C ); // mtfsfi 7,0 + + // Favour compatibility over speed (make sure the VPU set to Java-compliant mode) + // NOTE: the VPU *always* uses round-to-nearest + __vector4 a = { 0.0f, 0.0f, 0.0f, 0.0f }; + a; // Avoid compiler warning + __asm + { + mtvscr a; // Clear the Vector Status & Control Register to zero + } + } + +#endif // _X360 + +//----------------------------------------------------------------------------- +// Purpose: Standard functions for handling endian-ness +//----------------------------------------------------------------------------- + +//------------------------------------- +// Basic swaps +//------------------------------------- + +template +inline T WordSwapC( T w ) +{ + uint16 temp; + + temp = ((*((uint16 *)&w) & 0xff00) >> 8); + temp |= ((*((uint16 *)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template +inline T DWordSwapC( T dw ) +{ + uint32 temp; + + temp = *((uint32 *)&dw) >> 24; + temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +template +inline T QWordSwapC( T dw ) +{ + // Assert sizes passed to this are already correct, otherwise + // the cast to uint64 * below is unsafe and may have wrong results + // or even crash. + PLAT_COMPILE_TIME_ASSERT( sizeof( dw ) == sizeof(uint64) ); + + uint64 temp; + + temp = *((uint64 *)&dw) >> 56; + temp |= ((*((uint64 *)&dw) & 0x00FF000000000000ull) >> 40); + temp |= ((*((uint64 *)&dw) & 0x0000FF0000000000ull) >> 24); + temp |= ((*((uint64 *)&dw) & 0x000000FF00000000ull) >> 8); + temp |= ((*((uint64 *)&dw) & 0x00000000FF000000ull) << 8); + temp |= ((*((uint64 *)&dw) & 0x0000000000FF0000ull) << 24); + temp |= ((*((uint64 *)&dw) & 0x000000000000FF00ull) << 40); + temp |= ((*((uint64 *)&dw) & 0x00000000000000FFull) << 56); + + return *((T*)&temp); +} + +//------------------------------------- +// Fast swaps +//------------------------------------- + +#if defined( _X360 ) + + #define WordSwap WordSwap360Intr + #define DWordSwap DWordSwap360Intr + + template + inline T WordSwap360Intr( T w ) + { + T output; + __storeshortbytereverse( w, 0, &output ); + return output; + } + + template + inline T DWordSwap360Intr( T dw ) + { + T output; + __storewordbytereverse( dw, 0, &output ); + return output; + } + +#elif defined( _MSC_VER ) && !defined( PLATFORM_WINDOWS_PC64 ) + + #define WordSwap WordSwapAsm + #define DWordSwap DWordSwapAsm + + #pragma warning(push) + #pragma warning (disable:4035) // no return value + + template + inline T WordSwapAsm( T w ) + { + __asm + { + mov ax, w + xchg al, ah + } + } + + template + inline T DWordSwapAsm( T dw ) + { + __asm + { + mov eax, dw + bswap eax + } + } + + #pragma warning(pop) + +#else + + #define WordSwap WordSwapC + #define DWordSwap DWordSwapC + +#endif + +// No ASM implementation for this yet +#define QWordSwap QWordSwapC + +//------------------------------------- +// The typically used methods. +//------------------------------------- + +#if defined(__i386__) && !defined(VALVE_LITTLE_ENDIAN) +#define VALVE_LITTLE_ENDIAN 1 +#endif + +#if defined( _SGI_SOURCE ) || defined( _X360 ) +#define VALVE_BIG_ENDIAN 1 +#endif + +// If a swapped float passes through the fpu, the bytes may get changed. +// Prevent this by swapping floats as DWORDs. +#define SafeSwapFloat( pOut, pIn ) (*((uint*)pOut) = DWordSwap( *((uint*)pIn) )) + +#if defined(VALVE_LITTLE_ENDIAN) + +#define BigShort( val ) WordSwap( val ) +#define BigWord( val ) WordSwap( val ) +#define BigLong( val ) DWordSwap( val ) +#define BigDWord( val ) DWordSwap( val ) +#define LittleShort( val ) ( val ) +#define LittleWord( val ) ( val ) +#define LittleLong( val ) ( val ) +#define LittleDWord( val ) ( val ) +#define LittleQWord( val ) ( val ) +#define SwapShort( val ) BigShort( val ) +#define SwapWord( val ) BigWord( val ) +#define SwapLong( val ) BigLong( val ) +#define SwapDWord( val ) BigDWord( val ) + +// Pass floats by pointer for swapping to avoid truncation in the fpu +#define BigFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define LittleFloat( pOut, pIn ) ( *pOut = *pIn ) +#define SwapFloat( pOut, pIn ) BigFloat( pOut, pIn ) + +#elif defined(VALVE_BIG_ENDIAN) + +#define BigShort( val ) ( val ) +#define BigWord( val ) ( val ) +#define BigLong( val ) ( val ) +#define BigDWord( val ) ( val ) +#define LittleShort( val ) WordSwap( val ) +#define LittleWord( val ) WordSwap( val ) +#define LittleLong( val ) DWordSwap( val ) +#define LittleDWord( val ) DWordSwap( val ) +#define LittleQWord( val ) QWordSwap( val ) +#define SwapShort( val ) LittleShort( val ) +#define SwapWord( val ) LittleWord( val ) +#define SwapLong( val ) LittleLong( val ) +#define SwapDWord( val ) LittleDWord( val ) + +// Pass floats by pointer for swapping to avoid truncation in the fpu +#define BigFloat( pOut, pIn ) ( *pOut = *pIn ) +#define LittleFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define SwapFloat( pOut, pIn ) LittleFloat( pOut, pIn ) + +#else + +// @Note (toml 05-02-02): this technique expects the compiler to +// optimize the expression and eliminate the other path. On any new +// platform/compiler this should be tested. +inline short BigShort( short val ) { int test = 1; return ( *(char *)&test == 1 ) ? WordSwap( val ) : val; } +inline uint16 BigWord( uint16 val ) { int test = 1; return ( *(char *)&test == 1 ) ? WordSwap( val ) : val; } +inline long BigLong( long val ) { int test = 1; return ( *(char *)&test == 1 ) ? DWordSwap( val ) : val; } +inline uint32 BigDWord( uint32 val ) { int test = 1; return ( *(char *)&test == 1 ) ? DWordSwap( val ) : val; } +inline short LittleShort( short val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : WordSwap( val ); } +inline uint16 LittleWord( uint16 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : WordSwap( val ); } +inline long LittleLong( long val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : DWordSwap( val ); } +inline uint32 LittleDWord( uint32 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : DWordSwap( val ); } +inline uint64 LittleQWord( uint64 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : QWordSwap( val ); } +inline short SwapShort( short val ) { return WordSwap( val ); } +inline uint16 SwapWord( uint16 val ) { return WordSwap( val ); } +inline long SwapLong( long val ) { return DWordSwap( val ); } +inline uint32 SwapDWord( uint32 val ) { return DWordSwap( val ); } + +// Pass floats by pointer for swapping to avoid truncation in the fpu +inline void BigFloat( float *pOut, const float *pIn ) { int test = 1; ( *(char *)&test == 1 ) ? SafeSwapFloat( pOut, pIn ) : ( *pOut = *pIn ); } +inline void LittleFloat( float *pOut, const float *pIn ) { int test = 1; ( *(char *)&test == 1 ) ? ( *pOut = *pIn ) : SafeSwapFloat( pOut, pIn ); } +inline void SwapFloat( float *pOut, const float *pIn ) { SafeSwapFloat( pOut, pIn ); } + +#endif + +#if _X360 +FORCEINLINE unsigned long LoadLittleDWord( const unsigned long *base, unsigned int dwordIndex ) + { + return __loadwordbytereverse( dwordIndex<<2, base ); + } + +FORCEINLINE void StoreLittleDWord( unsigned long *base, unsigned int dwordIndex, unsigned long dword ) + { + __storewordbytereverse( dword, dwordIndex<<2, base ); + } +#else +FORCEINLINE unsigned long LoadLittleDWord( const unsigned long *base, unsigned int dwordIndex ) + { + return LittleDWord( base[dwordIndex] ); + } + +FORCEINLINE void StoreLittleDWord( unsigned long *base, unsigned int dwordIndex, unsigned long dword ) + { + base[dwordIndex] = LittleDWord(dword); + } +#endif + + +//----------------------------------------------------------------------------- +// DLL export for platform utilities +//----------------------------------------------------------------------------- +#ifndef STATIC_TIER0 + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#define PLATFORM_CLASS DLL_CLASS_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#define PLATFORM_CLASS DLL_CLASS_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define PLATFORM_INTERFACE extern +#define PLATFORM_OVERLOAD +#define PLATFORM_CLASS + +#endif // BUILD_AS_DLL + + +// When in benchmark mode, the timer returns a simple incremented value each time you call it. +// +// It should not be changed after startup unless you really know what you're doing. The only place +// that should do this is the benchmark code itself so it can output a legit duration. +PLATFORM_INTERFACE void Plat_SetBenchmarkMode( bool bBenchmarkMode ); +PLATFORM_INTERFACE bool Plat_IsInBenchmarkMode(); + + +PLATFORM_INTERFACE double Plat_FloatTime(); // Returns time in seconds since the module was loaded. +PLATFORM_INTERFACE unsigned int Plat_MSTime(); // Time in milliseconds. +PLATFORM_INTERFACE char * Plat_ctime( const time_t *timep, char *buf, size_t bufsize ); +PLATFORM_INTERFACE struct tm * Plat_gmtime( const time_t *timep, struct tm *result ); +PLATFORM_INTERFACE time_t Plat_timegm( struct tm *timeptr ); +PLATFORM_INTERFACE struct tm * Plat_localtime( const time_t *timep, struct tm *result ); + +#if defined( _WIN32 ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) + extern "C" unsigned __int64 __rdtsc(); + #pragma intrinsic(__rdtsc) +#endif + +inline uint64 Plat_Rdtsc() +{ +#if defined( _X360 ) + return ( uint64 )__mftb32(); +#elif defined( _WIN64 ) + return ( uint64 )__rdtsc(); +#elif defined( _WIN32 ) + #if defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) + return ( uint64 )__rdtsc(); + #else + __asm rdtsc; + __asm ret; + #endif +#elif defined( __i386__ ) + uint64 val; + __asm__ __volatile__ ( "rdtsc" : "=A" (val) ); + return val; +#elif defined( __x86_64__ ) + uint32 lo, hi; + __asm__ __volatile__ ( "rdtsc" : "=a" (lo), "=d" (hi)); + return ( ( ( uint64 )hi ) << 32 ) | lo; +#else + #error +#endif +} + +// b/w compatibility +#define Sys_FloatTime Plat_FloatTime + +// Protect against bad auto operator= +#define DISALLOW_OPERATOR_EQUAL( _classname ) \ + private: \ + _classname &operator=( const _classname & ); \ + public: + +// Define a reasonable operator= +#define IMPLEMENT_OPERATOR_EQUAL( _classname ) \ + public: \ + _classname &operator=( const _classname &src ) \ + { \ + memcpy( this, &src, sizeof(_classname) ); \ + return *this; \ + } + +// Processor Information: +struct CPUInformation +{ + int m_Size; // Size of this structure, for forward compatability. + + bool m_bRDTSC : 1, // Is RDTSC supported? + m_bCMOV : 1, // Is CMOV supported? + m_bFCMOV : 1, // Is FCMOV supported? + m_bSSE : 1, // Is SSE supported? + m_bSSE2 : 1, // Is SSE2 Supported? + m_b3DNow : 1, // Is 3DNow! Supported? + m_bMMX : 1, // Is MMX supported? + m_bHT : 1; // Is HyperThreading supported? + + uint8 m_nLogicalProcessors; // Number op logical processors. + uint8 m_nPhysicalProcessors; // Number of physical processors + + bool m_bSSE3 : 1, + m_bSSSE3 : 1, + m_bSSE4a : 1, + m_bSSE41 : 1, + m_bSSE42 : 1; + + int64 m_Speed; // In cycles per second. + + tchar* m_szProcessorID; // Processor vendor Identification. + + uint32 m_nModel; + uint32 m_nFeatures[3]; + + CPUInformation(): m_Size(0){} +}; + +// Have to return a pointer, not a reference, because references are not compatible with the +// extern "C" implied by PLATFORM_INTERFACE. +PLATFORM_INTERFACE const CPUInformation* GetCPUInformation(); + +PLATFORM_INTERFACE float GetCPUUsage(); + +PLATFORM_INTERFACE void GetCurrentDate( int *pDay, int *pMonth, int *pYear ); + +// ---------------------------------------------------------------------------------- // +// Performance Monitoring Events - L2 stats etc... +// ---------------------------------------------------------------------------------- // +PLATFORM_INTERFACE void InitPME(); +PLATFORM_INTERFACE void ShutdownPME(); + +//----------------------------------------------------------------------------- +// Thread related functions +//----------------------------------------------------------------------------- + +// Sets a hardware data breakpoint on the given address. Currently Win32-only. +// Specify 1, 2, or 4 bytes for nWatchBytes; pass 0 to unregister the address. +PLATFORM_INTERFACE void Plat_SetHardwareDataBreakpoint( const void *pAddress, int nWatchBytes, bool bBreakOnRead ); + +// Apply current hardware data breakpoints to a newly created thread. +PLATFORM_INTERFACE void Plat_ApplyHardwareDataBreakpointsToNewThread( unsigned long dwThreadID ); + +//----------------------------------------------------------------------------- +// Process related functions +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE const tchar *Plat_GetCommandLine(); +#ifndef _WIN32 +// helper function for OS's that don't have a ::GetCommandLine() call +PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine ); +#endif +PLATFORM_INTERFACE const char *Plat_GetCommandLineA(); + +//----------------------------------------------------------------------------- +// Security related functions +//----------------------------------------------------------------------------- +// Ensure that the hardware key's drivers have been installed. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +// Ok, so this isn't a very secure way to verify the hardware key for now. It +// is primarially depending on the fact that all the binaries have been wrapped +// with the secure wrapper provided by the hardware keys vendor. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +// The same as above, but notifies user with a message box when the key isn't in +// and gives him an opportunity to correct the situation. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +// Can be called in real time, doesn't perform the verify every frame. Mainly just +// here to allow the game to drop out quickly when the key is removed, rather than +// allowing the wrapper to pop up it's own blocking dialog, which the engine doesn't +// like much. +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + +//----------------------------------------------------------------------------- +// Just logs file and line to simple.log +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE void* Plat_SimpleLog( const tchar* file, int line ); + +#if _X360 +#define Plat_FastMemset XMemSet +#define Plat_FastMemcpy XMemCpy +#else +#define Plat_FastMemset memset +#define Plat_FastMemcpy memcpy +#endif + +//----------------------------------------------------------------------------- +// Returns true if debugger attached, false otherwise +//----------------------------------------------------------------------------- +#if defined(_WIN32) || defined(LINUX) || defined(OSX) +PLATFORM_INTERFACE bool Plat_IsInDebugSession(); +PLATFORM_INTERFACE void Plat_DebugString( const char * ); +#else +inline bool Plat_IsInDebugSession( bool bForceRecheck = false ) { return false; } +#define Plat_DebugString(s) ((void)0) +#endif + +//----------------------------------------------------------------------------- +// Returns true if running on a 64 bit (windows) OS +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE bool Is64BitOS(); + + +//----------------------------------------------------------------------------- +// XBOX Components valid in PC compilation space +//----------------------------------------------------------------------------- + +#define XBOX_DVD_SECTORSIZE 2048 +#define XBOX_DVD_ECC_SIZE 32768 // driver reads in quantum ECC blocks +#define XBOX_HDD_SECTORSIZE 512 + +// Custom windows messages for Xbox input +#define WM_XREMOTECOMMAND (WM_USER + 100) +#define WM_XCONTROLLER_KEY (WM_USER + 101) +#define WM_SYS_UI (WM_USER + 102) +#define WM_SYS_SIGNINCHANGED (WM_USER + 103) +#define WM_SYS_STORAGEDEVICESCHANGED (WM_USER + 104) +#define WM_SYS_PROFILESETTINGCHANGED (WM_USER + 105) +#define WM_SYS_MUTELISTCHANGED (WM_USER + 106) +#define WM_SYS_INPUTDEVICESCHANGED (WM_USER + 107) +#define WM_SYS_INPUTDEVICECONFIGCHANGED (WM_USER + 108) +#define WM_LIVE_CONNECTIONCHANGED (WM_USER + 109) +#define WM_LIVE_INVITE_ACCEPTED (WM_USER + 110) +#define WM_LIVE_LINK_STATE_CHANGED (WM_USER + 111) +#define WM_LIVE_CONTENT_INSTALLED (WM_USER + 112) +#define WM_LIVE_MEMBERSHIP_PURCHASED (WM_USER + 113) +#define WM_LIVE_VOICECHAT_AWAY (WM_USER + 114) +#define WM_LIVE_PRESENCE_CHANGED (WM_USER + 115) +#define WM_FRIENDS_PRESENCE_CHANGED (WM_USER + 116) +#define WM_FRIENDS_FRIEND_ADDED (WM_USER + 117) +#define WM_FRIENDS_FRIEND_REMOVED (WM_USER + 118) +#define WM_CUSTOM_GAMEBANNERPRESSED (WM_USER + 119) +#define WM_CUSTOM_ACTIONPRESSED (WM_USER + 120) +#define WM_XMP_STATECHANGED (WM_USER + 121) +#define WM_XMP_PLAYBACKBEHAVIORCHANGED (WM_USER + 122) +#define WM_XMP_PLAYBACKCONTROLLERCHANGED (WM_USER + 123) + +inline const char *GetPlatformExt( void ) +{ + return IsX360() ? ".360" : ""; +} + +// flat view, 6 hw threads +#define XBOX_PROCESSOR_0 ( 1<<0 ) +#define XBOX_PROCESSOR_1 ( 1<<1 ) +#define XBOX_PROCESSOR_2 ( 1<<2 ) +#define XBOX_PROCESSOR_3 ( 1<<3 ) +#define XBOX_PROCESSOR_4 ( 1<<4 ) +#define XBOX_PROCESSOR_5 ( 1<<5 ) + +// core view, 3 cores with 2 hw threads each +#define XBOX_CORE_0_HWTHREAD_0 XBOX_PROCESSOR_0 +#define XBOX_CORE_0_HWTHREAD_1 XBOX_PROCESSOR_1 +#define XBOX_CORE_1_HWTHREAD_0 XBOX_PROCESSOR_2 +#define XBOX_CORE_1_HWTHREAD_1 XBOX_PROCESSOR_3 +#define XBOX_CORE_2_HWTHREAD_0 XBOX_PROCESSOR_4 +#define XBOX_CORE_2_HWTHREAD_1 XBOX_PROCESSOR_5 + +//----------------------------------------------------------------------------- +// Include additional dependant header components. +//----------------------------------------------------------------------------- +#include "tier0/fasttimer.h" + +#if defined( _X360 ) +#include "xbox/xbox_core.h" +#endif + +//----------------------------------------------------------------------------- +// Methods to invoke the constructor, copy constructor, and destructor +//----------------------------------------------------------------------------- + +template +inline T* Construct( T* pMemory ) +{ + return ::new( pMemory ) T; +} + +template +inline T* Construct( T* pMemory, ARG1 a1 ) +{ + return ::new( pMemory ) T( a1 ); +} + +template +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2 ) +{ + return ::new( pMemory ) T( a1, a2 ); +} + +template +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3 ) +{ + return ::new( pMemory ) T( a1, a2, a3 ); +} + +template +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4 ) +{ + return ::new( pMemory ) T( a1, a2, a3, a4 ); +} + +template +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4, ARG5 a5 ) +{ + return ::new( pMemory ) T( a1, a2, a3, a4, a5 ); +} + +template +inline void ConstructOneArg( T* pMemory, P const& arg) +{ + ::new( pMemory ) T(arg); +} + +template +inline void ConstructTwoArg( T* pMemory, P1 const& arg1, P2 const& arg2) +{ + ::new( pMemory ) T(arg1, arg2); +} + +template +inline void ConstructThreeArg( T* pMemory, P1 const& arg1, P2 const& arg2, P3 const& arg3) +{ + ::new( pMemory ) T(arg1, arg2, arg3); +} + +template +inline T* CopyConstruct( T* pMemory, T const& src ) +{ + return ::new( pMemory ) T(src); +} + +template +inline void Destruct( T* pMemory ) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset( reinterpret_cast( pMemory ), 0xDD, sizeof(T) ); +#endif +} + + +// +// GET_OUTER() +// +// A platform-independent way for a contained class to get a pointer to its +// owner. If you know a class is exclusively used in the context of some +// "outer" class, this is a much more space efficient way to get at the outer +// class than having the inner class store a pointer to it. +// +// class COuter +// { +// class CInner // Note: this does not need to be a nested class to work +// { +// void PrintAddressOfOuter() +// { +// printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) ); +// } +// }; +// +// CInner m_Inner; +// friend class CInner; +// }; + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (uint8 *)this - offsetof( OuterType, OuterMember ) ) ) + + +/* TEMPLATE_FUNCTION_TABLE() + + (Note added to platform.h so platforms that correctly support templated + functions can handle portions as templated functions rather than wrapped + functions) + + Helps automate the process of creating an array of function + templates that are all specialized by a single integer. + This sort of thing is often useful in optimization work. + + For example, using TEMPLATE_FUNCTION_TABLE, this: + + TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10) + { + return argument * argument; + } + + is equivilent to the following: + + (NOTE: the function has to be wrapped in a class due to code + generation bugs involved with directly specializing a function + based on a constant.) + + template + class FunctionWrapper + { + public: + int Function( int blah, int blah ) + { + return argument*argument; + } + } + + typedef int (*FunctionType)( int blah, int blah ); + + class FunctionName + { + public: + enum { count = 10 }; + FunctionType functions[10]; + }; + + FunctionType FunctionName::functions[] = + { + FunctionWrapper<0>::Function, + FunctionWrapper<1>::Function, + FunctionWrapper<2>::Function, + FunctionWrapper<3>::Function, + FunctionWrapper<4>::Function, + FunctionWrapper<5>::Function, + FunctionWrapper<6>::Function, + FunctionWrapper<7>::Function, + FunctionWrapper<8>::Function, + FunctionWrapper<9>::Function + }; +*/ + +PLATFORM_INTERFACE bool vtune( bool resume ); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template \ +RETURN_TYPE FASTCALL __Function_##NAME::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + +//----------------------------------------------------------------------------- +// Dynamic libs support +//----------------------------------------------------------------------------- +#if 0 // defined( PLATFORM_WINDOWS_PC ) + +PLATFORM_INTERFACE void *Plat_GetProcAddress( const char *pszModule, const char *pszName ); + +template +class CDynamicFunction +{ +public: + CDynamicFunction( const char *pszModule, const char *pszName, FUNCPTR_TYPE pfnFallback = NULL ) + { + m_pfn = pfnFallback; + void *pAddr = Plat_GetProcAddress( pszModule, pszName ); + if ( pAddr ) + { + m_pfn = (FUNCPTR_TYPE)pAddr; + } + } + + operator bool() { return m_pfn != NULL; } + bool operator !() { return !m_pfn; } + operator FUNCPTR_TYPE() { return m_pfn; } + +private: + FUNCPTR_TYPE m_pfn; +}; +#endif + + +// Watchdog timer support. Call Plat_BeginWatchdogTimer( nn ) to kick the timer off. if you don't call +// Plat_EndWatchdogTimer within nn seconds, the program will kick off an exception. This is for making +// sure that hung dedicated servers abort (and restart) instead of staying hung. Calling +// Plat_EndWatchdogTimer more than once or when there is no active watchdog is fine. Only does anything +// under linux right now. It should be possible to implement this functionality in windows via a +// thread, if desired. +PLATFORM_INTERFACE void Plat_BeginWatchdogTimer( int nSecs ); +PLATFORM_INTERFACE void Plat_EndWatchdogTimer( void ); +PLATFORM_INTERFACE int Plat_GetWatchdogTime( void ); + +typedef void (*Plat_WatchDogHandlerFunction_t)(void); +PLATFORM_INTERFACE void Plat_SetWatchdogHandlerFunction( Plat_WatchDogHandlerFunction_t function ); + + +//----------------------------------------------------------------------------- + +#include "tier0/valve_on.h" + +#if defined(TIER0_DLL_EXPORT) +extern "C" int V_tier0_stricmp(const char *s1, const char *s2 ); +#undef stricmp +#undef strcmpi +#define stricmp(s1,s2) V_tier0_stricmp( s1, s2 ) +#define strcmpi(s1,s2) V_tier0_stricmp( s1, s2 ) +#endif + + +#endif /* PLATFORM_H */ diff --git a/public/tier0/pmc360.h b/public/tier0/pmc360.h new file mode 100644 index 0000000..ebae346 --- /dev/null +++ b/public/tier0/pmc360.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Analogous to l2cache.h, this class represents information gleaned +// from the 360's Performance Monitor Counters. In particular we +// are interested in l2 cache misses and load-hit-stores. +// +//=============================================================================// +#ifndef CPMCDATA_H +#define CPMCDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef _X360 +#error This file must only be compiled for XBOX360! +#endif + + +// Warning: +// As written, this class only supports profiling thread 0, processor 0. + +class CPMCData +{ +public: + + CPMCData(); + ~CPMCData() {}; + + void Start( void ); + void End( void ); + + /// This function should be called exactly once during the lifespan of the program; + /// it will set up the counters to record the information we are interested in. + /// This will stomp on whoever else might have set the performance counters elsewhere + /// in the game. + static void InitializeOnceProgramWide( void ); + static bool IsInitialized(); + + //------------------------------------------------------------------------- + // GetL2CacheMisses + //------------------------------------------------------------------------- + uint64 GetL2CacheMisses( void ) const + { + return m_Delta.L2CacheMiss; + } + + uint64 GetLHS( void ) const + { + return m_Delta.LHS; + } + +/* +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE +*/ + +private: + /// represents saved numbers from the counters we are interested in + struct PMCounters + { + uint64 L2CacheMiss; + uint64 LHS; ///< load hit store + + PMCounters(int64 _l2cm, int64 _lhs ) : L2CacheMiss(_l2cm), LHS(_lhs) {}; + PMCounters() : L2CacheMiss(0), LHS(0) {}; + }; + + PMCounters m_OnStart; ///< values when we began the timer + PMCounters m_Delta ; ///< computed total delta between start/stop +}; + +#endif // CPMCDATA_H \ No newline at end of file diff --git a/public/tier0/pointeroverride.asm b/public/tier0/pointeroverride.asm new file mode 100644 index 0000000..e75ed65 --- /dev/null +++ b/public/tier0/pointeroverride.asm @@ -0,0 +1,17 @@ +.model flat, C + +.data + __imp__EncodePointer@4 dd dummy + __imp__DecodePointer@4 dd dummy + + EXTERNDEF __imp__EncodePointer@4 : DWORD + EXTERNDEF __imp__DecodePointer@4 : DWORD + +.code + dummy proc + mov eax, [esp+4] + ret 4 + dummy endp + +end + \ No newline at end of file diff --git a/public/tier0/progressbar.h b/public/tier0/progressbar.h new file mode 100644 index 0000000..ce28afe --- /dev/null +++ b/public/tier0/progressbar.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Provide a shared place for library fucntions to report progress % for display +// +//=============================================================================// + +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H +#ifdef _WIN32 +#pragma once +#endif + + +PLATFORM_INTERFACE void ReportProgress(char const *job_name, int total_units_to_do, + int n_units_completed); + +typedef void (*ProgressReportHandler_t)( char const*, int, int ); + +// install your own handler. returns previous handler +PLATFORM_INTERFACE ProgressReportHandler_t InstallProgressReportHandler( ProgressReportHandler_t pfn); + + +#endif diff --git a/public/tier0/protected_things.h b/public/tier0/protected_things.h new file mode 100644 index 0000000..8cbfa92 --- /dev/null +++ b/public/tier0/protected_things.h @@ -0,0 +1,271 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROTECTED_THINGS_H +#define PROTECTED_THINGS_H +#ifdef _WIN32 +#pragma once +#endif + + +// This header tries to prevent people from using potentially dangerous functions +// (like the notorious non-null-terminating strncpy) and functions that will break +// VCR mode (like time, input, registry, etc). +// +// This header should be included by ALL of our source code. + +// Eventually, ALL of these should be protected, but one man can only accomplish so much in +// one day AND work on features too! +#if defined( PROTECTED_STRINGS_ENABLE ) && !defined(DISABLE_PROTECTED_STRINGS) + + #if defined( printf ) + #undef printf + #endif + #define printf printf__HEY_YOU__USE_VSTDLIB + + #if defined( wprintf ) + #undef wprintf + #endif + #define wprintf wprintf__HEY_YOU__USE_VSTDLIB + + #if defined( strcmp ) + #undef strcmp + #endif + #define strcmp strcmp__HEY_YOU__USE_VSTDLIB + + #if defined( wcscmp ) + #undef wcscmp + #endif + #define wcscmp wcscmp__HEY_YOU__USE_VSTDLIB + + #if defined( strncpy ) + #undef strncpy + #endif + #define strncpy strncpy__HEY_YOU__USE_VSTDLIB + + #if defined( wcsncpy ) + #undef wcsncpy + #endif + #define wcsncpy wcsncpy__HEY_YOU__USE_VSTDLIB + + #if defined( strlen ) + #undef strlen + #endif + #define strlen strlen__HEY_YOU__USE_VSTDLIB + + #if defined( wcslen ) + #undef wcslen + #endif + #define wcslen wcslen__HEY_YOU__USE_VSTDLIB + + #if defined( Q_strlen ) + #undef Q_strlen + #endif + #define Q_strlen Q_strlen__HEY_YOU__USE_VSTDLIB + + #if defined( _snprintf ) + #undef _snprintf + #endif + #define _snprintf snprintf__HEY_YOU__USE_VSTDLIB + + #if defined( _snwprintf ) + #undef _snwprintf + #endif + #define _snwprintf snwprintf__HEY_YOU__USE_VSTDLIB + + #if defined( sprintf ) + #undef sprintf + #endif + #define sprintf sprintf__HEY_YOU__USE_VSTDLIB + + #if defined( swprintf ) + #undef swprintf + #endif + #define swprintf swprintf__HEY_YOU__USE_VSTDLIB + + #if defined( vsprintf ) + #undef vsprintf + #endif + #define vsprintf vsprintf__HEY_YOU__USE_VSTDLIB + + #if defined( vswprintf ) + #undef vswprintf + #endif + #define vswprintf vswprintf__HEY_YOU__USE_VSTDLIB + + #if defined( _vsnprintf ) + #undef _vsnprintf + #endif + #define _vsnprintf vsnprintf__HEY_YOU__USE_VSTDLIB + + #if defined( _vsnwprintf ) + #undef _vsnwprintf + #endif + #define _vsnwprintf vsnwprintf__HEY_YOU__USE_VSTDLIB + + #if defined( strcat ) + #undef strcat + #endif + #define strcat strcat__HEY_YOU__USE_VSTDLIB + + #if defined( wcscat ) + #undef wcscat + #endif + #define wcscat wcscat__HEY_YOU__USE_VSTDLIB + + #if defined( strncat ) + #undef strncat + #endif + #define strncat strncat__HEY_YOU__USE_VSTDLIB + + #if defined( wcsncat ) + #undef wcsncat + #endif + #define wcsncat wcsncat__HEY_YOU__USE_VSTDLIB + +#endif + + +#if defined( PROTECTED_THINGS_ENABLE ) && !defined( _X360 ) && !defined(DISABLE_PROTECTED_THINGS) + + #if defined( GetTickCount ) + #undef GetTickCount + #endif + #define GetTickCount GetTickCount__USE_VCR_MODE + + + #if defined( timeGetTime ) + #undef timeGetTime + #endif + #define timeGetTime timeGetTime__USE_VCR_MODE + #if defined( clock ) + #undef clock + #endif + #define time time__USE_VCR_MODE + + + #if defined( recvfrom ) + #undef recvfrom + #endif + #define recvfrom recvfrom__USE_VCR_MODE + + + #if defined( GetCursorPos ) + #undef GetCursorPos + #endif + #define GetCursorPos GetCursorPos__USE_VCR_MODE + + + #if defined( ScreenToClient ) + #undef ScreenToClient + #endif + #define ScreenToClient ScreenToClient__USE_VCR_MODE + + + #if defined( GetCommandLine ) + #undef GetCommandLine + #endif + #define GetCommandLine GetCommandLine__USE_VCR_MODE + + + #if defined( RegOpenKeyEx ) + #undef RegOpenKeyEx + #endif + #define RegOpenKeyEx RegOpenKeyEx__USE_VCR_MODE + + + #if defined( RegOpenKey ) + #undef RegOpenKey + #endif + #define RegOpenKey RegOpenKey__USE_VCR_MODE + + + #if defined( RegSetValueEx ) + #undef RegSetValueEx + #endif + #define RegSetValueEx RegSetValueEx__USE_VCR_MODE + + + #if defined( RegSetValue ) + #undef RegSetValue + #endif + #define RegSetValue RegSetValue__USE_VCR_MODE + + + #if defined( RegQueryValueEx ) + #undef RegQueryValueEx + #endif + #define RegQueryValueEx RegQueryValueEx__USE_VCR_MODE + + + #if defined( RegQueryValue ) + #undef RegQueryValue + #endif + #define RegQueryValue RegQueryValue__USE_VCR_MODE + + + #if defined( RegCreateKeyEx ) + #undef RegCreateKeyEx + #endif + #define RegCreateKeyEx RegCreateKeyEx__USE_VCR_MODE + + + #if defined( RegCreateKey ) + #undef RegCreateKey + #endif + #define RegCreateKey RegCreateKey__USE_VCR_MODE + + + #if defined( RegCloseKey ) + #undef RegCloseKey + #endif + #define RegCloseKey RegCloseKey__USE_VCR_MODE + + + #if defined( GetNumberOfConsoleInputEvents ) + #undef GetNumberOfConsoleInputEvents + #endif + #define GetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents__USE_VCR_MODE + + + #if defined( ReadConsoleInput ) + #undef ReadConsoleInput + #endif + #define ReadConsoleInput ReadConsoleInput__USE_VCR_MODE + + + #if defined( GetAsyncKeyState ) + #undef GetAsyncKeyState + #endif + #define GetAsyncKeyState GetAsyncKeyState__USE_VCR_MODE + + + #if defined( GetKeyState ) + #undef GetKeyState + #endif + #define GetKeyState GetKeyState__USE_VCR_MODE + + + #if defined( CreateThread ) + #undef CreateThread + #endif + #define CreateThread CreateThread__USE_VCR_MODE + + #if defined( WaitForSingleObject ) + #undef WaitForSingleObject + #endif + #define WaitForSingleObject WaitForSingleObject__USE_VCR_MODE + + #if defined( EnterCriticalSection ) + #undef EnterCriticalSection + #endif + #define EnterCriticalSection EnterCriticalSection__USE_VCR_MODE + +#endif + + +#endif // PROTECTED_THINGS_H diff --git a/public/tier0/stacktools.h b/public/tier0/stacktools.h new file mode 100644 index 0000000..c356b8c --- /dev/null +++ b/public/tier0/stacktools.h @@ -0,0 +1,153 @@ +//========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Tools for grabbing/dumping the stack at runtime +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_STACKTOOLS_H +#define TIER0_STACKTOOLS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +#if (defined( PLATFORM_WINDOWS ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) && defined( TCHAR_IS_CHAR ) //designed for windows/x360, not built/tested with wide characters, not intended for release builds (but probably wouldn't damage anything) +# define ENABLE_RUNTIME_STACK_TRANSLATION //uncomment to enable runtime stack translation tools. All of which use on-demand loading of necessary dll's and pdb's +#endif + +#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) +//#define ENABLE_THREAD_PARENT_STACK_TRACING 1 //uncomment to actually enable tracking stack traces from threads and jobs to their parent thread. Must also define THREAD_PARENT_STACK_TRACE_SUPPORTED in threadtools.h +# if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) +# define THREAD_PARENT_STACK_TRACE_LENGTH 32 +# endif +#endif + + + + +PLATFORM_INTERFACE int GetCallStack( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +//ONLY WORKS IF THE CRAWLED PORTION OF THE STACK DISABLES FRAME POINTER OMISSION (/Oy-) "vpc /nofpo" +PLATFORM_INTERFACE int GetCallStack_Fast( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +typedef int (*FN_GetCallStack)( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +//where we'll find our PDB's for win32. +PLATFORM_INTERFACE void SetStackTranslationSymbolSearchPath( const char *szSemicolonSeparatedList = NULL ); +PLATFORM_INTERFACE void StackToolsNotify_LoadedLibrary( const char *szLibName ); + +//maximum output sample "tier0.dll!TranslateStackInfo - u:\Dev\L4D\src\tier0\stacktools.cpp(162) + 4 bytes" +enum TranslateStackInfo_StyleFlags_t +{ + TSISTYLEFLAG_NONE = 0, + TSISTYLEFLAG_MODULENAME = (1<<0), //start with module Sample: "tier0.dll!" + TSISTYLEFLAG_SYMBOLNAME = (1<<1), //include the symbol name Sample: "TranslateStackInfo" + TSISTYLEFLAG_FULLPATH = (1<<2), //include full path Sample: "u:\Dev\L4D\src\tier0\stacktools.cpp" + TSISTYLEFLAG_SHORTPATH = (1<<3), //only include 2 directories Sample: "\src\tier0\stacktools.cpp" + TSISTYLEFLAG_LINE = (1<<4), //file line number Sample: "(162)" + TSISTYLEFLAG_LINEANDOFFSET = (1<<5), //file line + offset Sample: "(162) + 4 bytes" + TSISTYLEFLAG_LAST = TSISTYLEFLAG_LINEANDOFFSET, + TSISTYLEFLAG_DEFAULT = (TSISTYLEFLAG_MODULENAME | TSISTYLEFLAG_SYMBOLNAME | TSISTYLEFLAG_FULLPATH | TSISTYLEFLAG_LINEANDOFFSET), //produces sample above +}; + +//Generates a formatted list of function information, returns number of translated entries +//On 360 this generates a string that can be decoded by VXConsole in print functions. Optimal path for translation because it's one way. Other paths require multiple transactions. +PLATFORM_INTERFACE int TranslateStackInfo( const void * const *pCallStack, int iCallStackCount, tchar *szOutput, int iOutBufferSize, const tchar *szEntrySeparator, TranslateStackInfo_StyleFlags_t style = TSISTYLEFLAG_DEFAULT ); + +PLATFORM_INTERFACE void PreloadStackInformation( void * const *pAddresses, int iAddressCount ); //caches data and reduces communication with VXConsole to speed up 360 decoding when using any of the Get***FromAddress() functions. Nop on PC. +PLATFORM_INTERFACE bool GetFileAndLineFromAddress( const void *pAddress, tchar *pFileNameOut, int iMaxFileNameLength, uint32 &iLineNumberOut, uint32 *pDisplacementOut = NULL ); +PLATFORM_INTERFACE bool GetSymbolNameFromAddress( const void *pAddress, tchar *pSymbolNameOut, int iMaxSymbolNameLength, uint64 *pDisplacementOut = NULL ); +PLATFORM_INTERFACE bool GetModuleNameFromAddress( const void *pAddress, tchar *pModuleNameOut, int iMaxModuleNameLength ); + + + +class PLATFORM_CLASS CCallStackStorage //a helper class to grab a stack trace as close to the leaf code surface as possible, then pass it on to deeper functions intact with less unpredictable inlining pollution +{ +public: + CCallStackStorage( FN_GetCallStack GetStackFunction = GetCallStack, uint32 iSkipCalls = 0 ); + CCallStackStorage( const CCallStackStorage ©From ) + { + iValidEntries = copyFrom.iValidEntries; + memcpy( pStack, copyFrom.pStack, sizeof( void * ) * copyFrom.iValidEntries ); + } + + void *pStack[128]; //probably too big, possibly too small for some applications. Don't want to spend the time figuring out how to generalize this without templatizing pollution or mallocs + uint32 iValidEntries; +}; + + +//Hold onto one of these to denote the top of a functional stack trace. Also allows us to string together threads to their parents +class PLATFORM_CLASS CStackTop_Base +{ +protected: +#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) + CStackTop_Base *m_pPrevTop; + void *m_pStackBase; + void *m_pReplaceAddress; + + void * const *m_pParentStackTrace; + int m_iParentStackTraceLength; +#endif +}; + +//makes a copy of the parent stack +class PLATFORM_CLASS CStackTop_CopyParentStack : public CStackTop_Base +{ +public: + CStackTop_CopyParentStack( void * const * pParentStackTrace, int iParentStackTraceLength ); + ~CStackTop_CopyParentStack( void ); +}; + +//just references the parent stack. Assuming that you'll keep that memory around as long as you're keeping this Stack Top marker. +class PLATFORM_CLASS CStackTop_ReferenceParentStack : public CStackTop_Base +{ +public: + CStackTop_ReferenceParentStack( void * const * pParentStackTrace = NULL, int iParentStackTraceLength = 0 ); + ~CStackTop_ReferenceParentStack( void ); + void ReleaseParentStackReferences( void ); //in case you need to delete the parent stack trace before this class goes out of scope +}; + + +//Encodes data so that every byte's most significant bit is a 1. Ensuring no null terminators. +//This puts the encoded data in the 128-255 value range. Leaving all standard ascii characters for control. +//Returns string length (not including the written null terminator as is standard). +//Or if the buffer is too small. Returns negative of necessary buffer size (including room needed for null terminator) +PLATFORM_INTERFACE int EncodeBinaryToString( const void *pToEncode, int iDataLength, char *pEncodeOut, int iEncodeBufferSize ); + +//Decodes a string produced by EncodeBinaryToString(). Safe to decode in place if you don't mind trashing your string, binary byte count always less than string byte count. +//Returns: +// >= 0 is the decoded data size +// INT_MIN (most negative value possible) indicates an improperly formatted string (not our data) +// all other negative values are the negative of how much dest buffer size is necessary. +PLATFORM_INTERFACE int DecodeBinaryFromString( const char *pString, void *pDestBuffer, int iDestBufferSize, char **ppParseFinishOut = NULL ); + + + + +// 360<->VXConsole specific communication definitions +#define XBX_CALLSTACKDECODEPREFIX ":CSDECODE[" + +enum StackTranslation_BinaryHandler_Command_t +{ + ST_BHC_LOADEDLIBARY, + ST_BHC_GETTRANSLATIONINFO, +}; + +#pragma pack(push) +#pragma pack(1) +struct FullStackInfo_t +{ + const void *pAddress; + char szModuleName[24]; + char szFileName[MAX_PATH/2]; + char szSymbol[64]; + uint32 iLine; + uint32 iSymbolOffset; + +}; +#pragma pack(pop) + +#endif //#ifndef TIER0_STACKTOOLS_H diff --git a/public/tier0/systeminformation.h b/public/tier0/systeminformation.h new file mode 100644 index 0000000..f9ba59e --- /dev/null +++ b/public/tier0/systeminformation.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef SYSTEMINFORMATION_H +#define SYSTEMINFORMATION_H + +#ifdef _WIN32 + #pragma once +#endif + +#ifndef PLATFORM_INTERFACE + #define PLATFORM_INTERFACE +#endif + +// +// Defines a possible outcome of a system call +// +enum SYSTEM_CALL_RESULT_t +{ + SYSCALL_SUCCESS = 0, // System call succeeded + SYSCALL_FAILED = 1, // System call failed + SYSCALL_NOPROC = 2, // Failed to find required system procedure + SYSCALL_NODLL = 3, // Failed to find or load required system module + SYSCALL_UNSUPPORTED = 4, // System call unsupported on the OS +}; + + +// +// Information about paged pool memory +// +struct PAGED_POOL_INFO_t +{ + unsigned long numPagesUsed; // Number of Paged Pool pages used + unsigned long numPagesFree; // Number of Paged Pool pages free +}; + +// +// Plat_GetMemPageSize +// Returns the size of a memory page in kilobytes. +// +PLATFORM_INTERFACE unsigned long Plat_GetMemPageSize(); + +// +// Plat_GetPagedPoolInfo +// Fills in the paged pool info structure if successful. +// +PLATFORM_INTERFACE SYSTEM_CALL_RESULT_t Plat_GetPagedPoolInfo( PAGED_POOL_INFO_t *pPPI ); + + + +#endif // #ifndef SYSTEMINFORMATION_H diff --git a/public/tier0/testthread.h b/public/tier0/testthread.h new file mode 100644 index 0000000..6ffda65 --- /dev/null +++ b/public/tier0/testthread.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: exposes testing thread functions +// +//============================================================================= + +#ifndef TESTTHREAD_H +#define TESTTHREAD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" + +// test callback +typedef void (STDCALL *TestFunc)(void *pv); + +// runs the test function +DBG_INTERFACE void Test_RunTest(TestFunc func, void *pvArg); + +// call to give the test thread a chance to run +// calling thread will block until the test thread yields +// doesn't do anything if no tests are running +DBG_INTERFACE void Test_RunFrame(); + +// true if any tests are running, or have ran +DBG_INTERFACE bool Test_IsActive(); + +// sets that the test has failed +DBG_INTERFACE void Test_SetFailed(); + +// true if any tests have failed, due to an assert, warning, or explicit fail +DBG_INTERFACE bool Test_HasFailed(); + +// true if any tests have completed +DBG_INTERFACE bool Test_HasFinished(); + +// terminates the test thread +DBG_INTERFACE void Test_TerminateThread(); + +// the following functions should only be called from the test thread + +// yields to the main thread for a single frame +// passing in is a count of the number of frames that have been yielded by this yield macro +// can be used to assert if a test thread is blocked foor +DBG_INTERFACE void TestThread_Yield(); + +// utility functions to pause the test frame until the selected condition is true +#define YIELD_UNTIL(x) { int iYieldCount = 0; while (!(x)) { TestThread_Yield(); iYieldCount++; if ( iYieldCount >= 100 ) { AssertMsg( false, #x ); break; } } } + +// use this like a while(1) loop, with break; to stop yielding +#define YIELD_UNTIL_BREAK() for (; true; TestThread_Yield()) + +// yields for a single frame +#define YIELD_FRAME() { TestThread_Yield(); } +#define YIELD_TWO_FRAMES() { TestThread_Yield(); TestThread_Yield(); } + + + +#endif // TESTTHREAD_H diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h new file mode 100644 index 0000000..fc52622 --- /dev/null +++ b/public/tier0/threadtools.h @@ -0,0 +1,1777 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A collection of utility classes to simplify thread handling, and +// as much as possible contain portability problems. Here avoiding +// including windows.h. +// +//============================================================================= + +#ifndef THREADTOOLS_H +#define THREADTOOLS_H + +#include + +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier0/vcrmode.h" + +#ifdef PLATFORM_WINDOWS_PC +#include +#endif + +#ifdef POSIX +#include +#include +#define WAIT_OBJECT_0 0 +#define WAIT_TIMEOUT 0x00000102 +#define WAIT_FAILED -1 +#define THREAD_PRIORITY_HIGHEST 2 +#endif + +#if defined( _WIN32 ) +#pragma once +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +// #define THREAD_PROFILER 1 + +#ifndef _RETAIL +#define THREAD_MUTEX_TRACING_SUPPORTED +#if defined(_WIN32) && defined(_DEBUG) +#define THREAD_MUTEX_TRACING_ENABLED +#endif +#endif + +#ifdef _WIN32 +typedef void *HANDLE; +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +const unsigned TT_INFINITE = 0xffffffff; + +#ifndef NO_THREAD_LOCAL + +#ifndef THREAD_LOCAL +#ifdef _WIN32 +#define THREAD_LOCAL __declspec(thread) +#elif POSIX +#define THREAD_LOCAL __thread +#endif +#endif + +#endif // NO_THREAD_LOCAL + +typedef unsigned long ThreadId_t; + +//----------------------------------------------------------------------------- +// +// Simple thread creation. Differs from VCR mode/CreateThread/_beginthreadex +// in that it accepts a standard C function rather than compiler specific one. +// +//----------------------------------------------------------------------------- +FORWARD_DECLARE_HANDLE( ThreadHandle_t ); +typedef unsigned (*ThreadFunc_t)( void *pParam ); + +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 ); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 ); +PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t ); + + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0); +PLATFORM_INTERFACE uint ThreadGetCurrentId(); +PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle(); +PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL ); +PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority ); +inline bool ThreadSetPriority( int priority ) { return ThreadSetPriority( NULL, priority ); } +PLATFORM_INTERFACE bool ThreadInMainThread(); +PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread(); + +// NOTE: ThreadedLoadLibraryFunc_t needs to return the sleep time in milliseconds or TT_INFINITE +typedef int (*ThreadedLoadLibraryFunc_t)(); +PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func ); +PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc(); + +#if defined( _WIN32 ) && !defined( _WIN64 ) && !defined( _X360 ) +extern "C" unsigned long __declspec(dllimport) __stdcall GetCurrentThreadId(); +#define ThreadGetCurrentId GetCurrentThreadId +#endif + +inline void ThreadPause() +{ +#if defined( PLATFORM_WINDOWS_PC ) + // Intrinsic for __asm pause; from + _mm_pause(); +#elif POSIX + __asm __volatile( "pause" ); +#elif defined( _X360 ) +#else +#error "implement me" +#endif +} + +PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE ); +// If you're not calling ThreadJoin, you need to call ThreadDetach so pthreads on Linux knows it can +// free the memory for this thread. Otherwise you wind up leaking threads until you run out and +// CreateSimpleThread() will fail. +PLATFORM_INTERFACE void ThreadDetach( ThreadHandle_t ); + +PLATFORM_INTERFACE void ThreadSetDebugName( ThreadId_t id, const char *pszName ); +inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( (ThreadId_t)-1, pszName ); } + +PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask ); + +//----------------------------------------------------------------------------- + +enum ThreadWaitResult_t +{ + TW_FAILED = 0xffffffff, // WAIT_FAILED + TW_TIMEOUT = 0x00000102, // WAIT_TIMEOUT +}; + +#ifdef _WIN32 +PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE ); +inline int ThreadWaitForObject( HANDLE handle, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( 1, &handle, bWaitAll, timeout ); } +#endif + +//----------------------------------------------------------------------------- +// +// Interlock methods. These perform very fast atomic thread +// safe operations. These are especially relevant in a multi-core setting. +// +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +#define NOINLINE +#elif POSIX +#define NOINLINE __attribute__ ((noinline)) +#endif + +// ThreadMemoryBarrier is a fence/barrier sufficient for most uses. It prevents reads +// from moving past reads, and writes moving past writes. It is sufficient for +// read-acquire and write-release barriers. It is not a full barrier and it does +// not prevent reads from moving past writes -- that would require a full __sync() +// on PPC and is significantly more expensive. +#if defined( _X360 ) || defined( _PS3 ) + #define ThreadMemoryBarrier() __lwsync() + +#elif defined(_MSC_VER) + // Prevent compiler reordering across this barrier. This is + // sufficient for most purposes on x86/x64. + + #if _MSC_VER < 1500 + // !KLUDGE! For VC 2005 + // http://connect.microsoft.com/VisualStudio/feedback/details/100051 + #pragma intrinsic(_ReadWriteBarrier) + #endif + #define ThreadMemoryBarrier() _ReadWriteBarrier() +#elif defined(GNUC) + // Prevent compiler reordering across this barrier. This is + // sufficient for most purposes on x86/x64. + // http://preshing.com/20120625/memory-ordering-at-compile-time + #define ThreadMemoryBarrier() asm volatile("" ::: "memory") +#else + #error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering +#endif + +#if defined(_WIN32) && !defined(_X360) + #if ( _MSC_VER >= 1310 ) + #define USE_INTRINSIC_INTERLOCKED + #endif +#endif + +#ifdef USE_INTRINSIC_INTERLOCKED +extern "C" +{ + long __cdecl _InterlockedIncrement(volatile long*); + long __cdecl _InterlockedDecrement(volatile long*); + long __cdecl _InterlockedExchange(volatile long*, long); + long __cdecl _InterlockedExchangeAdd(volatile long*, long); + long __cdecl _InterlockedCompareExchange(volatile long*, long, long); +} + +#pragma intrinsic( _InterlockedCompareExchange ) +#pragma intrinsic( _InterlockedDecrement ) +#pragma intrinsic( _InterlockedExchange ) +#pragma intrinsic( _InterlockedExchangeAdd ) +#pragma intrinsic( _InterlockedIncrement ) + +inline long ThreadInterlockedIncrement( long volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( p ); } +inline long ThreadInterlockedDecrement( long volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( p ); } +inline long ThreadInterlockedExchange( long volatile *p, long value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( p, value ); } +inline long ThreadInterlockedExchangeAdd( long volatile *p, long value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( p, value ); } +inline long ThreadInterlockedCompareExchange( long volatile *p, long value, long comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( long volatile *p, long value, long comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( p, value, comperand ) == comperand ); } +#else +PLATFORM_INTERFACE long ThreadInterlockedIncrement( long volatile * ); +PLATFORM_INTERFACE long ThreadInterlockedDecrement( long volatile * ); +PLATFORM_INTERFACE long ThreadInterlockedExchange( long volatile *, long value ); +PLATFORM_INTERFACE long ThreadInterlockedExchangeAdd( long volatile *, long value ); +PLATFORM_INTERFACE long ThreadInterlockedCompareExchange( long volatile *, long value, long comperand ); +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( long volatile *, long value, long comperand ); +#endif + +inline unsigned ThreadInterlockedExchangeSubtract( long volatile *p, long value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, -value ); } + +#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( _WIN64 ) +#define TIPTR() +inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)_InterlockedExchange( reinterpret_cast(p), reinterpret_cast(value) ); } +inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)_InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ); } +inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( _InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) == reinterpret_cast(comperand) ); } +#else +PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE; +PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE; +#endif + +inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); } +inline void const *ThreadInterlockedCompareExchangePointerToConst( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedCompareExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } +inline bool ThreadInterlockedAssignPointerToConstIf( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedAssignPointerIf( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } + +#if defined( PLATFORM_64BITS ) +#if defined (_WIN32) +typedef __m128i int128; +inline int128 int128_zero() { return _mm_setzero_si128(); } +#else +typedef __int128_t int128; +#define int128_zero() 0 +#endif + +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) NOINLINE; + +#endif + +PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE; + +inline unsigned ThreadInterlockedExchangeSubtract( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } +inline unsigned ThreadInterlockedIncrement( unsigned volatile *p ) { return ThreadInterlockedIncrement( (long volatile *)p ); } +inline unsigned ThreadInterlockedDecrement( unsigned volatile *p ) { return ThreadInterlockedDecrement( (long volatile *)p ); } +inline unsigned ThreadInterlockedExchange( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchange( (long volatile *)p, value ); } +inline unsigned ThreadInterlockedExchangeAdd( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } +inline unsigned ThreadInterlockedCompareExchange( unsigned volatile *p, unsigned value, unsigned comperand ) { return ThreadInterlockedCompareExchange( (long volatile *)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( unsigned volatile *p, unsigned value, unsigned comperand ) { return ThreadInterlockedAssignIf( (long volatile *)p, value, comperand ); } + +inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } +inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (long volatile *)p ); } +inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (long volatile *)p ); } +inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (long volatile *)p, value ); } +inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } +inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (long volatile *)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (long volatile *)p, value, comperand ); } + +//----------------------------------------------------------------------------- +// Access to VTune thread profiling +//----------------------------------------------------------------------------- +#if defined(_WIN32) && defined(THREAD_PROFILER) +PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncCancel(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p); +#else +#define ThreadNotifySyncPrepare(p) ((void)0) +#define ThreadNotifySyncCancel(p) ((void)0) +#define ThreadNotifySyncAcquired(p) ((void)0) +#define ThreadNotifySyncReleasing(p) ((void)0) +#endif + +//----------------------------------------------------------------------------- +// Encapsulation of a thread local datum (needed because THREAD_LOCAL doesn't +// work in a DLL loaded with LoadLibrary() +//----------------------------------------------------------------------------- + +#ifndef NO_THREAD_LOCAL + +#if defined(_LINUX) && !defined(OSX) +// linux totally supports compiler thread locals, even across dll's. +#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 +#define CTHREADLOCALINTEGER( typ ) __thread int +#define CTHREADLOCALINT __thread int +#define CTHREADLOCALPTR( typ ) __thread typ * +#define CTHREADLOCAL( typ ) __thread typ +#define GETLOCAL( x ) ( x ) +#endif // _LINUX && !OSX + +#if defined(WIN32) || defined(OSX) +#ifndef __AFXTLS_H__ // not compatible with some Windows headers +#define CTHREADLOCALINT CThreadLocalInt +#define CTHREADLOCALINTEGER( typ ) CThreadLocalInt +#define CTHREADLOCALPTR( typ ) CThreadLocalPtr +#define CTHREADLOCAL( typ ) CThreadLocal +#define GETLOCAL( x ) ( x.Get() ) +#endif +#endif // WIN32 || OSX + +#endif // NO_THREAD_LOCALS + +#ifndef __AFXTLS_H__ // not compatible with some Windows headers +#ifndef NO_THREAD_LOCAL + +class PLATFORM_CLASS CThreadLocalBase + { +public: + CThreadLocalBase(); + ~CThreadLocalBase(); + + void * Get() const; + void Set(void *); + +private: +#ifdef _WIN32 + uint32 m_index; +#elif POSIX + pthread_key_t m_index; +#endif + }; + + //--------------------------------------------------------- + +#ifndef __AFXTLS_H__ + + template + class CThreadLocal : public CThreadLocalBase + { + public: + CThreadLocal() + { + COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); + } + + T Get() const + { + return reinterpret_cast( CThreadLocalBase::Get() ); + } + + void Set(T val) + { + CThreadLocalBase::Set( reinterpret_cast(val) ); + } + }; + +#endif + + //--------------------------------------------------------- + +template + class CThreadLocalInt : public CThreadLocal + { + public: + CThreadLocalInt() + { + COMPILE_TIME_ASSERT( sizeof(T) >= sizeof(int) ); + } + + operator int() const { return (int)this->Get(); } + int operator=( int i ) { this->Set( (intp)i ); return i; } + + int operator++() { T i = this->Get(); this->Set( ++i ); return (int)i; } + int operator++(int) { T i = this->Get(); this->Set( i + 1 ); return (int)i; } + + int operator--() { T i = this->Get(); this->Set( --i ); return (int)i; } + int operator--(int) { T i = this->Get(); this->Set( i - 1 ); return (int)i; } + }; + + + //--------------------------------------------------------- + + template + class CThreadLocalPtr : private CThreadLocalBase + { + public: + CThreadLocalPtr() {} + + operator const void *() const { return (T *)Get(); } + operator void *() { return (T *)Get(); } + + operator const T *() const { return (T *)Get(); } + operator const T *() { return (T *)Get(); } + operator T *() { return (T *)Get(); } + + int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); Set( NULL ); return 0; } + T * operator=( T *p ) { Set( p ); return p; } + + bool operator !() const { return (!Get()); } + bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); } + bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); } + bool operator==( const void *p ) const { return (Get() == p); } + bool operator!=( const void *p ) const { return (Get() != p); } + bool operator==( const T *p ) const { return operator==((void*)p); } + bool operator!=( const T *p ) const { return operator!=((void*)p); } + + T * operator->() { return (T *)Get(); } + T & operator *() { return *((T *)Get()); } + + const T * operator->() const { return (T *)Get(); } + const T & operator *() const { return *((T *)Get()); } + + const T & operator[]( int i ) const { return *((T *)Get() + i); } + T & operator[]( int i ) { return *((T *)Get() + i); } + + private: + // Disallowed operations + CThreadLocalPtr( T *pFrom ); + CThreadLocalPtr( const CThreadLocalPtr &from ); + T **operator &(); + T * const *operator &() const; + void operator=( const CThreadLocalPtr &from ); + bool operator==( const CThreadLocalPtr &p ) const; + bool operator!=( const CThreadLocalPtr &p ) const; + }; + +#endif // NO_THREAD_LOCAL +#endif // !__AFXTLS_H__ + +//----------------------------------------------------------------------------- +// +// A super-fast thread-safe integer A simple class encapsulating the notion of an +// atomic integer used across threads that uses the built in and faster +// "interlocked" functionality rather than a full-blown mutex. Useful for simple +// things like reference counts, etc. +// +//----------------------------------------------------------------------------- + +template +class CInterlockedIntT +{ +public: + CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(long) ); } + CInterlockedIntT( T value ) : m_value( value ) {} + + T GetRaw() const { return m_value; } + + operator T() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T rhs ) const { return ( m_value == rhs ); } + bool operator!=( T rhs ) const { return ( m_value != rhs ); } + + T operator++() { return (T)ThreadInterlockedIncrement( (long *)&m_value ); } + T operator++(int) { return operator++() - 1; } + + T operator--() { return (T)ThreadInterlockedDecrement( (long *)&m_value ); } + T operator--(int) { return operator--() + 1; } + + bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (long *)&m_value, (long)newValue, (long)conditionValue ); } + + T operator=( T newValue ) { ThreadInterlockedExchange((long *)&m_value, newValue); return m_value; } + + void operator+=( T add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, (long)add ); } + void operator-=( T subtract ) { operator+=( -subtract ); } + void operator*=( T multiplier ) { + T original, result; + do + { + original = m_value; + result = original * multiplier; + } while ( !AssignIf( original, result ) ); + } + void operator/=( T divisor ) { + T original, result; + do + { + original = m_value; + result = original / divisor; + } while ( !AssignIf( original, result ) ); + } + + T operator+( T rhs ) const { return m_value + rhs; } + T operator-( T rhs ) const { return m_value - rhs; } + +private: + volatile T m_value; +}; + +typedef CInterlockedIntT CInterlockedInt; +typedef CInterlockedIntT CInterlockedUInt; + +//----------------------------------------------------------------------------- + +template +class CInterlockedPtr +{ +public: + CInterlockedPtr() : m_value( 0 ) {} + CInterlockedPtr( T *value ) : m_value( value ) {} + + operator T *() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T *rhs ) const { return ( m_value == rhs ); } + bool operator!=( T *rhs ) const { return ( m_value != rhs ); } + +#if defined( PLATFORM_64BITS ) + T *operator++() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) )) + 1; } + T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) ); } + + T *operator--() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, -sizeof(T) )) - 1; } + T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, -sizeof(T) ); } + + bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } + + T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } + + void operator+=( int add ) { ThreadInterlockedExchangeAdd64( (int64 *)&m_value, add * sizeof(T) ); } +#else + T *operator++() { return ((T *)ThreadInterlockedExchangeAdd( (long *)&m_value, sizeof(T) )) + 1; } + T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (long *)&m_value, sizeof(T) ); } + + T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (long *)&m_value, -sizeof(T) )) - 1; } + T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (long *)&m_value, -sizeof(T) ); } + + bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } + + T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } + + void operator+=( int add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, add * sizeof(T) ); } +#endif + + void operator-=( int subtract ) { operator+=( -subtract ); } + + T *operator+( int rhs ) const { return m_value + rhs; } + T *operator-( int rhs ) const { return m_value - rhs; } + T *operator+( unsigned rhs ) const { return m_value + rhs; } + T *operator-( unsigned rhs ) const { return m_value - rhs; } + size_t operator-( T *p ) const { return m_value - p; } + size_t operator-( const CInterlockedPtr &p ) const { return m_value - p.m_value; } + +private: + T * volatile m_value; +}; + +//----------------------------------------------------------------------------- +// +// Platform independent verification that multiple threads aren't getting into the same code at the same time. +// Note: This is intended for use to identify problems, it doesn't provide any sort of thread safety. +// +//----------------------------------------------------------------------------- +class ReentrancyVerifier +{ +public: + inline ReentrancyVerifier(CInterlockedInt* counter, int sleepTimeMS) + : mCounter(counter) + { + Assert(mCounter != NULL); + + if (++(*mCounter) != 1) { + DebuggerBreakIfDebugging_StagingOnly(); + } + + if (sleepTimeMS > 0) + { + ThreadSleep(sleepTimeMS); + } + } + + inline ~ReentrancyVerifier() + { + if (--(*mCounter) != 0) { + DebuggerBreakIfDebugging_StagingOnly(); + } + } + +private: + CInterlockedInt* mCounter; +}; + + +//----------------------------------------------------------------------------- +// +// Platform independent for critical sections management +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadMutex +{ +public: + CThreadMutex(); + ~CThreadMutex(); + + //------------------------------------------------------ + // Mutex acquisition/release. Const intentionally defeated. + //------------------------------------------------------ + void Lock(); + void Lock() const { (const_cast(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast(this))->TryLock(); } + + //------------------------------------------------------ + // Use this to make deadlocks easier to track by asserting + // when it is expected that the current thread owns the mutex + //------------------------------------------------------ + bool AssertOwnedByCurrentThread(); + + //------------------------------------------------------ + // Enable tracing to track deadlock problems + //------------------------------------------------------ + void SetTrace( bool ); + +private: + // Disallow copying + CThreadMutex( const CThreadMutex & ); + CThreadMutex &operator=( const CThreadMutex & ); + +#if defined( _WIN32 ) + // Efficient solution to breaking the windows.h dependency, invariant is tested. +#ifdef _WIN64 + #define TT_SIZEOF_CRITICALSECTION 40 +#else +#ifndef _X360 + #define TT_SIZEOF_CRITICALSECTION 24 +#else + #define TT_SIZEOF_CRITICALSECTION 28 +#endif // !_XBOX +#endif // _WIN64 + byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION]; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_mutexattr_t m_Attr; +#else +#error +#endif + +#ifdef THREAD_MUTEX_TRACING_SUPPORTED + // Debugging (always here to allow mixed debug/release builds w/o changing size) + uint m_currentOwnerID; + uint16 m_lockCount; + bool m_bTrace; +#endif +}; + +//----------------------------------------------------------------------------- +// +// An alternative mutex that is useful for cases when thread contention is +// rare, but a mutex is required. Instances should be declared volatile. +// Sleep of 0 may not be sufficient to keep high priority threads from starving +// lesser threads. This class is not a suitable replacement for a critical +// section if the resource contention is high. +// +//----------------------------------------------------------------------------- + +#if !defined(THREAD_PROFILER) + +class CThreadFastMutex +{ +public: + CThreadFastMutex() + : m_ownerID( 0 ), + m_depth( 0 ) + { + } + +private: + FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile + { + if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile long *)&m_ownerID, (long)threadId, 0 ) ) + return false; + + ThreadMemoryBarrier(); + ++m_depth; + return true; + } + + bool TryLock( const uint32 threadId ) volatile + { + return TryLockInline( threadId ); + } + + PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile; + +public: + bool TryLock() volatile + { +#ifdef _DEBUG + if ( m_depth == INT_MAX ) + DebuggerBreak(); + + if ( m_depth < 0 ) + DebuggerBreak(); +#endif + return TryLockInline( ThreadGetCurrentId() ); + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Lock( unsigned int nSpinSleepTime = 0 ) volatile + { + const uint32 threadId = ThreadGetCurrentId(); + + if ( !TryLockInline( threadId ) ) + { + ThreadPause(); + Lock( threadId, nSpinSleepTime ); + } +#ifdef _DEBUG + if ( m_ownerID != ThreadGetCurrentId() ) + DebuggerBreak(); + + if ( m_depth == INT_MAX ) + DebuggerBreak(); + + if ( m_depth < 0 ) + DebuggerBreak(); +#endif + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Unlock() volatile + { +#ifdef _DEBUG + if ( m_ownerID != ThreadGetCurrentId() ) + DebuggerBreak(); + + if ( m_depth <= 0 ) + DebuggerBreak(); +#endif + + --m_depth; + if ( !m_depth ) + { + ThreadMemoryBarrier(); + ThreadInterlockedExchange( &m_ownerID, 0 ); + } + } + +#ifdef WIN32 + bool TryLock() const volatile { return (const_cast(this))->TryLock(); } + void Lock(unsigned nSpinSleepTime = 1 ) const volatile { (const_cast(this))->Lock( nSpinSleepTime ); } + void Unlock() const volatile { (const_cast(this))->Unlock(); } +#endif + // To match regular CThreadMutex: + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace( bool ) {} + + uint32 GetOwnerId() const { return m_ownerID; } + int GetDepth() const { return m_depth; } +private: + volatile uint32 m_ownerID; + int m_depth; +}; + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); + } + +private: + uint8 pad[128-sizeof(CThreadFastMutex)]; +} ALIGN128_POST; + +#else +typedef CThreadMutex CThreadFastMutex; +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CThreadNullMutex +{ +public: + static void Lock() {} + static void Unlock() {} + + static bool TryLock() { return true; } + static bool AssertOwnedByCurrentThread() { return true; } + static void SetTrace( bool ) {} + + static uint32 GetOwnerId() { return 0; } + static int GetDepth() { return 0; } +}; + +//----------------------------------------------------------------------------- +// +// A mutex decorator class used to control the use of a mutex, to make it +// less expensive when not multithreading +// +//----------------------------------------------------------------------------- + +template +class CThreadConditionalMutex : public BaseClass +{ +public: + void Lock() { if ( *pCondition ) BaseClass::Lock(); } + void Lock() const { if ( *pCondition ) BaseClass::Lock(); } + void Unlock() { if ( *pCondition ) BaseClass::Unlock(); } + void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); } + + bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; } + bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; } + bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; } + void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); } +}; + +//----------------------------------------------------------------------------- +// Mutex decorator that blows up if another thread enters +//----------------------------------------------------------------------------- + +template +class CThreadTerminalMutex : public BaseClass +{ +public: + bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } + bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } + void Lock() { if ( !TryLock() ) BaseClass::Lock(); } + void Lock() const { if ( !TryLock() ) BaseClass::Lock(); } + +}; + +//----------------------------------------------------------------------------- +// +// Class to Lock a critical section, and unlock it automatically +// when the lock goes out of scope +// +//----------------------------------------------------------------------------- + +template +class CAutoLockT +{ +public: + FORCEINLINE CAutoLockT( MUTEX_TYPE &lock) + : m_lock(lock) + { + m_lock.Lock(); + } + + FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock) + : m_lock(const_cast(lock)) + { + m_lock.Lock(); + } + + FORCEINLINE ~CAutoLockT() + { + m_lock.Unlock(); + } + + +private: + MUTEX_TYPE &m_lock; + + // Disallow copying + CAutoLockT( const CAutoLockT & ); + CAutoLockT &operator=( const CAutoLockT & ); +}; + +typedef CAutoLockT CAutoLock; + +//--------------------------------------------------------- + +template struct CAutoLockTypeDeducer {}; +template <> struct CAutoLockTypeDeducer { typedef CThreadMutex Type_t; }; +template <> struct CAutoLockTypeDeducer { typedef CThreadNullMutex Type_t; }; +#if !defined(THREAD_PROFILER) +template <> struct CAutoLockTypeDeducer { typedef CThreadFastMutex Type_t; }; +template <> struct CAutoLockTypeDeducer { typedef CAlignedThreadFastMutex Type_t; }; +#endif + +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< type > UNIQUE_ID( static_cast( mutex ) ) + +#if defined(GNUC) + +template T strip_cv_quals_for_mutex(T&); +template T strip_cv_quals_for_mutex(const T&); +template T strip_cv_quals_for_mutex(volatile T&); +template T strip_cv_quals_for_mutex(const volatile T&); + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( typeof(::strip_cv_quals_for_mutex(mutex)), mutex ) + +#else // GNUC + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer::Type_t, mutex ) + +#endif + +#define AUTO_LOCK_FM( mutex ) \ + AUTO_LOCK_( CThreadFastMutex, mutex ) + +#define LOCAL_THREAD_LOCK_( tag ) \ + ; \ + static CThreadFastMutex autoMutex_##tag; \ + AUTO_LOCK( autoMutex_##tag ) + +#define LOCAL_THREAD_LOCK() \ + LOCAL_THREAD_LOCK_(_) + +//----------------------------------------------------------------------------- +// +// Base class for event, semaphore and mutex objects. +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadSyncObject +{ +public: + ~CThreadSyncObject(); + + //----------------------------------------------------- + // Query if object is useful + //----------------------------------------------------- + bool operator!() const; + + //----------------------------------------------------- + // Access handle + //----------------------------------------------------- +#ifdef _WIN32 + operator HANDLE() { return GetHandle(); } + const HANDLE GetHandle() const { return m_hSyncObject; } +#endif + //----------------------------------------------------- + // Wait for a signal from the object + //----------------------------------------------------- + bool Wait( uint32 dwTimeout = TT_INFINITE ); + +protected: + CThreadSyncObject(); + void AssertUseable(); + +#ifdef _WIN32 + HANDLE m_hSyncObject; + bool m_bCreatedHandle; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_cond_t m_Condition; + bool m_bInitalized; + int m_cSet; + bool m_bManualReset; + bool m_bWakeForEvent; +#else +#error "Implement me" +#endif + +private: + CThreadSyncObject( const CThreadSyncObject & ); + CThreadSyncObject &operator=( const CThreadSyncObject & ); +}; + + +//----------------------------------------------------------------------------- +// +// Wrapper for unnamed event objects +// +//----------------------------------------------------------------------------- + +#if defined( _WIN32 ) + +//----------------------------------------------------------------------------- +// +// CThreadSemaphore +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject +{ +public: + CThreadSemaphore(long initialValue, long maxValue); + + //----------------------------------------------------- + // Increases the count of the semaphore object by a specified + // amount. Wait() decreases the count by one on return. + //----------------------------------------------------- + bool Release(long releaseCount = 1, long * pPreviousCount = NULL ); + +private: + CThreadSemaphore(const CThreadSemaphore &); + CThreadSemaphore &operator=(const CThreadSemaphore &); +}; + + +//----------------------------------------------------------------------------- +// +// A mutex suitable for out-of-process, multi-processor usage +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject +{ +public: + CThreadFullMutex( bool bEstablishInitialOwnership = false, const char * pszName = NULL ); + + //----------------------------------------------------- + // Release ownership of the mutex + //----------------------------------------------------- + bool Release(); + + // To match regular CThreadMutex: + void Lock() { Wait(); } + void Lock( unsigned timeout ) { Wait( timeout ); } + void Unlock() { Release(); } + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace( bool ) {} + +private: + CThreadFullMutex( const CThreadFullMutex & ); + CThreadFullMutex &operator=( const CThreadFullMutex & ); +}; +#endif + + +class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject +{ +public: + CThreadEvent( bool fManualReset = false ); +#ifdef WIN32 + CThreadEvent( HANDLE hHandle ); +#endif + //----------------------------------------------------- + // Set the state to signaled + //----------------------------------------------------- + bool Set(); + + //----------------------------------------------------- + // Set the state to nonsignaled + //----------------------------------------------------- + bool Reset(); + + //----------------------------------------------------- + // Check if the event is signaled + //----------------------------------------------------- + bool Check(); + + bool Wait( uint32 dwTimeout = TT_INFINITE ); + +private: + CThreadEvent( const CThreadEvent & ); + CThreadEvent &operator=( const CThreadEvent & ); +}; + +// Hard-wired manual event for use in array declarations +class CThreadManualEvent : public CThreadEvent +{ +public: + CThreadManualEvent() + : CThreadEvent( true ) + { + } +}; + +inline int ThreadWaitForEvents( int nEvents, CThreadEvent * const *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) +{ +#ifdef POSIX + Assert( nEvents == 1); + if ( pEvents[0]->Wait( timeout ) ) + return WAIT_OBJECT_0; + else + return WAIT_TIMEOUT; +#else + HANDLE handles[64]; + for ( unsigned int i = 0; i < vmin( nEvents, ARRAYSIZE(handles) ); i++ ) + handles[i] = pEvents[i]->GetHandle(); + return ThreadWaitForObjects( nEvents, handles, bWaitAll, timeout ); +#endif +} + +//----------------------------------------------------------------------------- +// +// CThreadRWLock +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadRWLock +{ +public: + CThreadRWLock(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + void LockForRead() const { const_cast(this)->LockForRead(); } + void UnlockRead() const { const_cast(this)->UnlockRead(); } + void LockForWrite() const { const_cast(this)->LockForWrite(); } + void UnlockWrite() const { const_cast(this)->UnlockWrite(); } + +private: + void WaitForRead(); + +#ifdef WIN32 + CThreadFastMutex m_mutex; +#else + CThreadMutex m_mutex; +#endif + CThreadEvent m_CanWrite; + CThreadEvent m_CanRead; + + int m_nWriters; + int m_nActiveReaders; + int m_nPendingReaders; +}; + +//----------------------------------------------------------------------------- +// +// CThreadSpinRWLock +// +//----------------------------------------------------------------------------- + +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } + + bool TryLockForWrite(); + bool TryLockForRead(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + bool TryLockForWrite() const { return const_cast(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast(this)->TryLockForRead(); } + void LockForRead() const { const_cast(this)->LockForRead(); } + void UnlockRead() const { const_cast(this)->UnlockRead(); } + void LockForWrite() const { const_cast(this)->LockForWrite(); } + void UnlockWrite() const { const_cast(this)->UnlockWrite(); } + +private: + struct LockInfo_t + { + uint32 m_writerId; + int m_nReaders; + }; + + bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); + bool TryLockForWrite( const uint32 threadId ); + void SpinLockForWrite( const uint32 threadId ); + + volatile LockInfo_t m_lockInfo; + CInterlockedInt m_nWriters; + int __padding; +} ALIGN8_POST; + +//----------------------------------------------------------------------------- +// +// A thread wrapper similar to a Java thread. +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThread +{ +public: + CThread(); + virtual ~CThread(); + + //----------------------------------------------------- + + const char *GetName(); + void SetName( const char * ); + + size_t CalcStackDepth( void *pStackVariable ) { return ((byte *)m_pStackBase - (byte *)pStackVariable); } + + //----------------------------------------------------- + // Functions for the other threads + //----------------------------------------------------- + + // Start thread running - error if already running + virtual bool Start( unsigned nBytesStack = 0 ); + + // Returns true if thread has been created and hasn't yet exited + bool IsAlive(); + + // This method causes the current thread to wait until this thread + // is no longer alive. + bool Join( unsigned timeout = TT_INFINITE ); + +#ifdef _WIN32 + // Access the thread handle directly + HANDLE GetThreadHandle(); + uint GetThreadId(); +#elif defined( LINUX ) + uint GetThreadId(); +#endif + + //----------------------------------------------------- + + int GetResult(); + + //----------------------------------------------------- + // Functions for both this, and maybe, and other threads + //----------------------------------------------------- + + // Forcibly, abnormally, but relatively cleanly stop the thread + void Stop( int exitCode = 0 ); + + // Get the priority + int GetPriority() const; + + // Set the priority + bool SetPriority( int ); + + // Request a thread to suspend, this must ONLY be called from the thread itself, not the main thread + // This suspend variant causes the thread in question to suspend at a known point in its execution + // which means you don't risk the global deadlocks/hangs potentially caused by the raw Suspend() call + void SuspendCooperative(); + + // Resume a previously suspended thread from the Cooperative call + void ResumeCooperative(); + + // wait for a thread to execute its SuspendCooperative call + void BWaitForThreadSuspendCooperative(); + +#ifndef LINUX + // forcefully Suspend a thread + unsigned int Suspend(); + + // forcefully Resume a previously suspended thread + unsigned int Resume(); +#endif + + // Force hard-termination of thread. Used for critical failures. + bool Terminate( int exitCode = 0 ); + + //----------------------------------------------------- + // Global methods + //----------------------------------------------------- + + // Get the Thread object that represents the current thread, if any. + // Can return NULL if the current thread was not created using + // CThread + static CThread *GetCurrentCThread(); + + // Offer a context switch. Under Win32, equivalent to Sleep(0) +#ifdef Yield +#undef Yield +#endif + static void Yield(); + + // This method causes the current thread to yield and not to be + // scheduled for further execution until a certain amount of real + // time has elapsed, more or less. + static void Sleep( unsigned duration ); + +protected: + + // Optional pre-run call, with ability to fail-create. Note Init() + // is forced synchronous with Start() + virtual bool Init(); + + // Thread will run this function on startup, must be supplied by + // derived class, performs the intended action of the thread. + virtual int Run() = 0; + + // Called when the thread is about to exit, by the about-to-exit thread. + virtual void OnExit(); + + // Called after OnExit when a thread finishes or is killed. Not virtual because no inherited classes + // override it and we don't want to change the vtable from the published SDK version. + void Cleanup(); + + bool WaitForCreateComplete( CThreadEvent *pEvent ); + + // "Virtual static" facility + typedef unsigned (__stdcall *ThreadProc_t)( void * ); + virtual ThreadProc_t GetThreadProc(); + virtual bool IsThreadRunning(); + + CThreadMutex m_Lock; + +#ifdef WIN32 + ThreadHandle_t GetThreadID() const { return (ThreadHandle_t)m_hThread; } +#else + ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; } +#endif + +private: + enum Flags + { + SUPPORT_STOP_PROTOCOL = 1 << 0 + }; + + // Thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + struct ThreadInit_t + { + CThread * pThread; + CThreadEvent *pInitCompleteEvent; + bool * pfInitSuccess; + }; + + static unsigned __stdcall ThreadProc( void * pv ); + + // make copy constructor and assignment operator inaccessible + CThread( const CThread & ); + CThread &operator=( const CThread & ); + +#ifdef _WIN32 + HANDLE m_hThread; + ThreadId_t m_threadId; +#elif defined(POSIX) + pthread_t m_threadId; +#endif + CInterlockedInt m_nSuspendCount; + CThreadEvent m_SuspendEvent; + CThreadEvent m_SuspendEventSignal; + int m_result; + char m_szName[32]; + void * m_pStackBase; + unsigned m_flags; +}; + +//----------------------------------------------------------------------------- +// +// A helper class to let you sleep a thread for memory validation, you need to handle +// m_bSleepForValidate in your ::Run() call and set m_bSleepingForValidate when sleeping +// +//----------------------------------------------------------------------------- +class PLATFORM_CLASS CValidatableThread : public CThread +{ +public: + CValidatableThread() + { + m_bSleepForValidate = false; + m_bSleepingForValidate = false; + } + +#ifdef DBGFLAG_VALIDATE + virtual void SleepForValidate() { m_bSleepForValidate = true; } + bool BSleepingForValidate() { return m_bSleepingForValidate; } + virtual void WakeFromValidate() { m_bSleepForValidate = false; } +#endif +protected: + bool m_bSleepForValidate; + bool m_bSleepingForValidate; +}; + +//----------------------------------------------------------------------------- +// Simple thread class encompasses the notion of a worker thread, handing +// synchronized communication. +//----------------------------------------------------------------------------- + + +// These are internal reserved error results from a call attempt +enum WTCallResult_t +{ + WTCR_FAIL = -1, + WTCR_TIMEOUT = -2, + WTCR_THREAD_GONE = -3, +}; + +class CFunctor; +class PLATFORM_CLASS CWorkerThread : public CThread +{ +public: + CWorkerThread(); + + //----------------------------------------------------- + // + // Inter-thread communication + // + // Calls in either direction take place on the same "channel." + // Seperate functions are specified to make identities obvious + // + //----------------------------------------------------- + + // Master: Signal the thread, and block for a response + int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true, CFunctor *pParamFunctor = NULL ); + + // Worker: Signal the thread, and block for a response + int CallMaster( unsigned, unsigned timeout = TT_INFINITE ); + + // Wait for the next request + bool WaitForCall( unsigned dwTimeout, unsigned *pResult = NULL ); + bool WaitForCall( unsigned *pResult = NULL ); + + // Is there a request? + bool PeekCall( unsigned *pParam = NULL, CFunctor **ppParamFunctor = NULL ); + + // Reply to the request + void Reply( unsigned ); + + // Wait for a reply in the case when CallWorker() with timeout != TT_INFINITE + int WaitForReply( unsigned timeout = TT_INFINITE ); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + CThreadEvent &GetCallHandle(); + // Find out what the request was + unsigned GetCallParam( CFunctor **ppParamFunctor = NULL ) const; + + // Boost the worker thread to the master thread, if worker thread is lesser, return old priority + int BoostPriority(); + +protected: +#ifndef _WIN32 +#define __stdcall +#endif + typedef uint32 (__stdcall *WaitFunc_t)( int nEvents, CThreadEvent * const *pEvents, int bWaitAll, uint32 timeout ); + + int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL, CFunctor *pParamFunctor = NULL ); + int WaitForReply( unsigned timeout, WaitFunc_t ); + +private: + CWorkerThread( const CWorkerThread & ); + CWorkerThread &operator=( const CWorkerThread & ); + + CThreadEvent m_EventSend; + CThreadEvent m_EventComplete; + + unsigned m_Param; + CFunctor *m_pParamFunctor; + int m_ReturnVal; +}; + + +// a unidirectional message queue. A queue of type T. Not especially high speed since each message +// is malloced/freed. Note that if your message class has destructors/constructors, they MUST be +// thread safe! +template class CMessageQueue +{ + CThreadEvent SignalEvent; // signals presence of data + CThreadMutex QueueAccessMutex; + + // the parts protected by the mutex + struct MsgNode + { + MsgNode *Next; + T Data; + }; + + MsgNode *Head; + MsgNode *Tail; + +public: + CMessageQueue( void ) + { + Head = Tail = NULL; + } + + // check for a message. not 100% reliable - someone could grab the message first + bool MessageWaiting( void ) + { + return ( Head != NULL ); + } + + void WaitMessage( T *pMsg ) + { + for(;;) + { + while( ! MessageWaiting() ) + SignalEvent.Wait(); + QueueAccessMutex.Lock(); + if (! Head ) + { + // multiple readers could make this null + QueueAccessMutex.Unlock(); + continue; + } + *( pMsg ) = Head->Data; + MsgNode *remove_this = Head; + Head = Head->Next; + if (! Head) // if empty, fix tail ptr + Tail = NULL; + QueueAccessMutex.Unlock(); + delete remove_this; + break; + } + } + + void QueueMessage( T const &Msg) + { + MsgNode *new1=new MsgNode; + new1->Data=Msg; + new1->Next=NULL; + QueueAccessMutex.Lock(); + if ( Tail ) + { + Tail->Next=new1; + Tail = new1; + } + else + { + Head = new1; + Tail = new1; + } + SignalEvent.Set(); + QueueAccessMutex.Unlock(); + } +}; + + +//----------------------------------------------------------------------------- +// +// CThreadMutex. Inlining to reduce overhead and to allow client code +// to decide debug status (tracing) +// +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION; +typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + +#ifndef _X360 +extern "C" +{ + void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION *); +}; +#endif + +//--------------------------------------------------------- + +inline void CThreadMutex::Lock() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED + uint thisThreadID = ThreadGetCurrentId(); + if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) ) + Msg( "Thread %u about to wait for lock %p owned by %u\n", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + #endif + + VCRHook_EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + + #ifdef THREAD_MUTEX_TRACING_ENABLED + if (m_lockCount == 0) + { + // we now own it for the first time. Set owner information + m_currentOwnerID = thisThreadID; + if ( m_bTrace ) + Msg( "Thread %u now owns lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + } + m_lockCount++; + #endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Unlock() +{ + #ifdef THREAD_MUTEX_TRACING_ENABLED + AssertMsg( m_lockCount >= 1, "Invalid unlock of thread lock" ); + m_lockCount--; + if (m_lockCount == 0) + { + if ( m_bTrace ) + Msg( "Thread %u releasing lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + m_currentOwnerID = 0; + } + #endif + LeaveCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); +} + +//--------------------------------------------------------- + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED + if (ThreadGetCurrentId() == m_currentOwnerID) + return true; + AssertMsg3( 0, "Expected thread %u as owner of lock %p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + return false; +#else + return true; +#endif +} + +//--------------------------------------------------------- + +#ifdef THREAD_MUTEX_TRACING_ENABLED +inline void CThreadMutex::SetTrace( bool bTrace ) +{ + m_bTrace = bTrace; +#else +inline void CThreadMutex::SetTrace( bool ) +{ +#endif +} + +//--------------------------------------------------------- + +#elif defined(POSIX) + +inline CThreadMutex::CThreadMutex() +{ + // enable recursive locks as we need them + pthread_mutexattr_init( &m_Attr ); + pthread_mutexattr_settype( &m_Attr, PTHREAD_MUTEX_RECURSIVE ); + pthread_mutex_init( &m_Mutex, &m_Attr ); +} + +//--------------------------------------------------------- + +inline CThreadMutex::~CThreadMutex() +{ + pthread_mutex_destroy( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Lock() +{ + pthread_mutex_lock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Unlock() +{ + pthread_mutex_unlock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ + return true; +} + +//--------------------------------------------------------- + +inline void CThreadMutex::SetTrace(bool fTrace) +{ +} + +#endif // POSIX + +//----------------------------------------------------------------------------- +// +// CThreadRWLock inline functions +// +//----------------------------------------------------------------------------- + +inline CThreadRWLock::CThreadRWLock() +: m_CanRead( true ), + m_nWriters( 0 ), + m_nActiveReaders( 0 ), + m_nPendingReaders( 0 ) +{ +} + +inline void CThreadRWLock::LockForRead() +{ + m_mutex.Lock(); + if ( m_nWriters) + { + WaitForRead(); + } + m_nActiveReaders++; + m_mutex.Unlock(); +} + +inline void CThreadRWLock::UnlockRead() +{ + m_mutex.Lock(); + m_nActiveReaders--; + if ( m_nActiveReaders == 0 && m_nWriters != 0 ) + { + m_CanWrite.Set(); + } + m_mutex.Unlock(); +} + + +//----------------------------------------------------------------------------- +// +// CThreadSpinRWLock inline functions +// +//----------------------------------------------------------------------------- + +inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ) +{ + return ThreadInterlockedAssignIf64( (int64 *)&m_lockInfo, *((int64 *)&newValue), *((int64 *)&comperand) ); +} + +inline bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId ) +{ + // In order to grab a write lock, there can be no readers and no owners of the write lock + if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) ) + { + return false; + } + + static const LockInfo_t oldValue = { 0, 0 }; + LockInfo_t newValue = { threadId, 0 }; + const bool bSuccess = AssignIf( newValue, oldValue ); +#if defined(_X360) + if ( bSuccess ) + { + // X360TBD: Serious perf implications. Not Yet. __sync(); + } +#endif + return bSuccess; +} + +inline bool CThreadSpinRWLock::TryLockForWrite() +{ + m_nWriters++; + if ( !TryLockForWrite( ThreadGetCurrentId() ) ) + { + m_nWriters--; + return false; + } + return true; +} + +inline bool CThreadSpinRWLock::TryLockForRead() +{ + if ( m_nWriters != 0 ) + { + return false; + } + // In order to grab a write lock, the number of readers must not change and no thread can own the write + LockInfo_t oldValue; + LockInfo_t newValue; + + oldValue.m_nReaders = m_lockInfo.m_nReaders; + oldValue.m_writerId = 0; + newValue.m_nReaders = oldValue.m_nReaders + 1; + newValue.m_writerId = 0; + + const bool bSuccess = AssignIf( newValue, oldValue ); +#if defined(_X360) + if ( bSuccess ) + { + // X360TBD: Serious perf implications. Not Yet. __sync(); + } +#endif + return bSuccess; +} + +inline void CThreadSpinRWLock::LockForWrite() +{ + const uint32 threadId = ThreadGetCurrentId(); + + m_nWriters++; + + if ( !TryLockForWrite( threadId ) ) + { + ThreadPause(); + SpinLockForWrite( threadId ); + } +} + +// read data from a memory address +template FORCEINLINE T ReadVolatileMemory( T const *pPtr ) +{ + volatile const T * pVolatilePtr = ( volatile const T * ) pPtr; + return *pVolatilePtr; +} + +//----------------------------------------------------------------------------- + +#if defined( _WIN32 ) +#pragma warning(pop) +#endif + +#endif // THREADTOOLS_H diff --git a/public/tier0/tmapi_dummy.h b/public/tier0/tmapi_dummy.h new file mode 100644 index 0000000..8a6aebc --- /dev/null +++ b/public/tier0/tmapi_dummy.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// This is the null header file used to remove Telemetry calls. + +#define TMERR_DISABLED 1 +#define TMPRINTF_TOKEN_NONE 0 + +#define tmGetSessionName(...) +#define tmEndTryLock(...) +#define tmEndTryLockEx(...) +#define tmSetLockState(...) +#define tmSetLockStateEx(...) +#define tmSetLockStateMinTime(...) 0 +#define tmSetLockStateMinTimeEx(...) 0 +#define tmSignalLockCount(...) + +#define tmCheckVersion(...) 0 +#define tmGetCallStack(...) 0 +#define tmSendCallStack( ... ) TMPRINTF_TOKEN_NONE +#define tmGetCallStackR(...) 0 +#define tmSendCallStackR(...) TMPRINTF_TOKEN_NONE +#define tmSendCallStackWithSkipR(...) TMPRINTF_TOKEN_NONE + +#define tmGetVersion(...) 0 +#define tmStartup(...) TMERR_DISABLED +#define tmGetPlatformInformation(...) TMERR_DISABLED +#define tmInitializeContext(...) TMERR_DISABLED +#define tmShutdown(...) TMERR_DISABLED + +#define tmEnter(...) +#define tmEnterEx(...) +#define tmZone(...) +#define tmZoneFiltered(...) +#define tmLeave(...) +#define tmLeaveEx(...) + +#define tmBeginTimeSpan(...) +#define tmEndTimeSpan(...) + +#define tmBeginTimeSpanAt(...) +#define tmEndTimeSpanAt(...) + +#define tmDynamicString(...) "" + +#define tmEmitAccumulationZone(...) + +#define tmGetStati(...) 0 + +#define tmSetVariable(...) + +#define tmBlob(...) +#define tmDisjointBlob(...) +#define tmSetTimelineSectionName(...) +#define tmThreadName(...) +#define tmLockName(...) +#define tmMessage(...) +#define tmAlloc(...) +#define tmAllocEx(...) + +#define tmTryLock(...) +#define tmTryLockEx(...) + +#define tmPlot(...) +#define tmPlotF32(...) +#define tmPlotF64(...) +#define tmPlotI32(...) +#define tmPlotU32(...) +#define tmPlotS32(...) +#define tmPlotI64(...) +#define tmPlotU64(...) +#define tmPlotS64(...) + +#define tmPPUGetListener(...) TMERR_DISABLED +#define tmPPURegisterSPUProgram(...) TMERR_DISABLED +#define tmSPUBindContextToListener(...) +#define tmSPUUpdateTime(...) +#define tmSPUFlushImage(...) + +#define NTELEMETRY 1 + +#define TM_CONTEXT_LITE(val) ((char*)(val)) +#define TM_CONTEXT_FULL(val) ((char*)(val)) + +typedef char *HTELEMETRY; + diff --git a/public/tier0/tslist.h b/public/tier0/tslist.h new file mode 100644 index 0000000..d6610e0 --- /dev/null +++ b/public/tier0/tslist.h @@ -0,0 +1,1004 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// LIFO from disassembly of Windows API and http://perso.wanadoo.fr/gmem/evenements/jim2002/articles/L17_Fober.pdf +// FIFO from http://perso.wanadoo.fr/gmem/evenements/jim2002/articles/L17_Fober.pdf +// +//============================================================================= + +#ifndef TSLIST_H +#define TSLIST_H + +#if defined( _WIN32 ) +#pragma once +// Suppress this spurious warning: +// warning C4700: uninitialized local variable 'oldHead' used +#pragma warning( push ) +#pragma warning( disable : 4700 ) +#endif + +#if defined( USE_NATIVE_SLIST ) && !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "tier0/memalloc.h" +#include "tier0/memdbgoff.h" + +#if defined( _X360 ) +#define USE_NATIVE_SLIST +#endif + +//----------------------------------------------------------------------------- + +#if defined( PLATFORM_64BITS ) + +#define TSLIST_HEAD_ALIGNMENT 16 +#define TSLIST_NODE_ALIGNMENT 16 +inline bool ThreadInterlockedAssignIf64x128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) + { return ThreadInterlockedAssignIf128( pDest, value, comperand ); } +#else +#define TSLIST_HEAD_ALIGNMENT 8 +#define TSLIST_NODE_ALIGNMENT 8 +inline bool ThreadInterlockedAssignIf64x128( volatile int64 *pDest, const int64 value, const int64 comperand ) + { return ThreadInterlockedAssignIf64( pDest, value, comperand ); } +#endif + +#ifdef _MSC_VER +#define TSLIST_HEAD_ALIGN DECL_ALIGN(TSLIST_HEAD_ALIGNMENT) +#define TSLIST_NODE_ALIGN DECL_ALIGN(TSLIST_NODE_ALIGNMENT) +#define TSLIST_HEAD_ALIGN_POST +#define TSLIST_NODE_ALIGN_POST +#elif defined( GNUC ) +#define TSLIST_HEAD_ALIGN +#define TSLIST_NODE_ALIGN +#define TSLIST_HEAD_ALIGN_POST DECL_ALIGN(TSLIST_HEAD_ALIGNMENT) +#define TSLIST_NODE_ALIGN_POST DECL_ALIGN(TSLIST_NODE_ALIGNMENT) +#elif defined( _PS3 ) +#define TSLIST_HEAD_ALIGNMENT 8 +#define TSLIST_NODE_ALIGNMENT 8 + +#define TSLIST_HEAD_ALIGN ALIGN8 +#define TSLIST_NODE_ALIGN ALIGN8 +#define TSLIST_HEAD_ALIGN_POST ALIGN8_POST +#define TSLIST_NODE_ALIGN_POST ALIGN8_POST + +#else +#error +#endif + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE bool RunTSQueueTests( int nListSize = 10000, int nTests = 1 ); +PLATFORM_INTERFACE bool RunTSListTests( int nListSize = 10000, int nTests = 1 ); + +//----------------------------------------------------------------------------- +// Lock free list. +//----------------------------------------------------------------------------- +//#define USE_NATIVE_SLIST + +#ifdef USE_NATIVE_SLIST +typedef SLIST_ENTRY TSLNodeBase_t; +typedef SLIST_HEADER TSLHead_t; +#else +struct TSLIST_NODE_ALIGN TSLNodeBase_t +{ + TSLNodeBase_t *Next; // name to match Windows +} TSLIST_NODE_ALIGN_POST; + +union TSLIST_HEAD_ALIGN TSLHead_t +{ + struct Value_t + { + TSLNodeBase_t *Next; + // Depth must be in the least significant halfword when atomically loading into register, + // to avoid carrying digits from Sequence. Carrying digits from Depth to Sequence is ok, + // because Sequence can be pretty much random. We could operate on both of them separately, + // but it could perhaps (?) lead to problems with store forwarding. I don't know 'cause I didn't + // performance-test or design original code, I'm just making it work on PowerPC. + #ifdef VALVE_BIG_ENDIAN + int16 Sequence; + int16 Depth; + #else + int16 Depth; + int16 Sequence; + #endif +#ifdef PLATFORM_64BITS + int32 Padding; +#endif + } value; + + struct Value32_t + { + TSLNodeBase_t *Next_do_not_use_me; + int32 DepthAndSequence; + } value32; + +#ifdef PLATFORM_64BITS + int128 value64x128; +#else + int64 value64x128; +#endif +} TSLIST_HEAD_ALIGN_POST; + +#endif + +//------------------------------------- +class CTSListBase +{ +public: + + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size ) + { + CTSListBase *pNode = (CTSListBase *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + return pNode; + } + + static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + { + CTSListBase *pNode = (CTSListBase *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); + return pNode; + } + + static void operator delete( void *p) + { + MemAlloc_FreeAligned( p ); + } + + static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + { + MemAlloc_FreeAligned( p ); + } + +private: + // These ain't gonna work + static void * operator new[] ( size_t size ); + static void operator delete [] ( void *p); + +public: + + CTSListBase() + { + if ( ((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSListBase: Misaligned list\n" ); + DebuggerBreak(); + } + +#ifdef USE_NATIVE_SLIST + InitializeSListHead( &m_Head ); +#elif defined(PLATFORM_64BITS) + m_Head.value64x128 = int128_zero(); +#else + m_Head.value64x128 = (int64)0; +#endif + } + + ~CTSListBase() + { + Detach(); + } + + TSLNodeBase_t *Push( TSLNodeBase_t *pNode ) + { +#ifdef _DEBUG + if ( (size_t)pNode % TSLIST_NODE_ALIGNMENT != 0 ) + { + Error( "CTSListBase: Misaligned node\n" ); + DebuggerBreak(); + } +#endif + +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + // integrated write-release barrier + return (TSLNodeBase_t *)InterlockedPushEntrySListRelease( &m_Head, pNode ); +#else + return (TSLNodeBase_t *)InterlockedPushEntrySList( &m_Head, pNode ); +#endif +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // write-release barrier + #endif + +#ifdef PLATFORM_64BITS + newHead.value.Padding = 0; +#endif + for (;;) + { + oldHead.value64x128 = m_Head.value64x128; + pNode->Next = oldHead.value.Next; + newHead.value.Next = pNode; + + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence + 0x10001; + + + if ( ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ) + { + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLNodeBase_t *Pop() + { +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + // integrated read-acquire barrier + TSLNodeBase_t *pNode = (TSLNodeBase_t *)InterlockedPopEntrySListAcquire( &m_Head ); +#else + TSLNodeBase_t *pNode = (TSLNodeBase_t *)InterlockedPopEntrySList( &m_Head ); +#endif + return pNode; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + +#ifdef PLATFORM_64BITS + newHead.value.Padding = 0; +#endif + for (;;) + { + oldHead.value64x128 = m_Head.value64x128; + if ( !oldHead.value.Next ) + return NULL; + + newHead.value.Next = oldHead.value.Next->Next; + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1; + + + if ( ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ) + { + #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // read-acquire barrier + #endif + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLNodeBase_t *Detach() + { +#ifdef USE_NATIVE_SLIST + TSLNodeBase_t *pBase = (TSLNodeBase_t *)InterlockedFlushSList( &m_Head ); +#if defined( _X360 ) || defined( _PS3 ) + __lwsync(); // read-acquire barrier +#endif + return pBase; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + +#ifdef PLATFORM_64BITS + newHead.value.Padding = 0; +#endif + do + { + ThreadPause(); + + oldHead.value64x128 = m_Head.value64x128; + if ( !oldHead.value.Next ) + return NULL; + + newHead.value.Next = NULL; + // the reason for AND'ing it instead of poking a short into memory + // is probably to avoid store forward issues, but I'm not sure because + // I didn't construct this code. In any case, leaving it as is on big-endian + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence & 0xffff0000; + + } while( !ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ); + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLHead_t *AccessUnprotected() + { + return &m_Head; + } + + int Count() const + { +#ifdef USE_NATIVE_SLIST + return QueryDepthSList( const_cast( &m_Head ) ); +#else + return m_Head.value.Depth; +#endif + } + +private: + TSLHead_t m_Head; +} TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- + +template +class TSLIST_HEAD_ALIGN CTSSimpleList : public CTSListBase +{ +public: + void Push( T *pNode ) + { + Assert( sizeof(T) >= sizeof(TSLNodeBase_t) ); + CTSListBase::Push( (TSLNodeBase_t *)pNode ); + } + + T *Pop() + { + return (T *)CTSListBase::Pop(); + } +} TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- +// this is a replacement for CTSList<> and CObjectPool<> that does not +// have a per-item, per-alloc new/delete overhead +// similar to CTSSimpleList except that it allocates it's own pool objects +// and frees them on destruct. Also it does not overlay the TSNodeBase_t memory +// on T's memory +template< class T > +class TSLIST_HEAD_ALIGN CTSPool : public CTSListBase +{ + // packs the node and the item (T) into a single struct and pools those + struct TSLIST_NODE_ALIGN simpleTSPoolStruct_t : public TSLNodeBase_t + { + T elem; + } TSLIST_NODE_ALIGN_POST; + +public: + + ~CTSPool() + { + Purge(); + } + + void Purge() + { + simpleTSPoolStruct_t *pNode = NULL; + while ( 1 ) + { + pNode = (simpleTSPoolStruct_t *)CTSListBase::Pop(); + if ( !pNode ) + break; + delete pNode; + } + } + + void PutObject( T *pInfo ) + { + char *pElem = (char *)pInfo; + pElem -= offsetof(simpleTSPoolStruct_t,elem); + simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)pElem; + + CTSListBase::Push( pNode ); + } + + T *GetObject() + { + simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)CTSListBase::Pop(); + if ( !pNode ) + { + pNode = new simpleTSPoolStruct_t; + } + return &pNode->elem; + } + + // omg windows sdk - why do you #define GetObject()? + FORCEINLINE T *Get() + { + return GetObject(); + } +} TSLIST_HEAD_ALIGN_POST; +//------------------------------------- + +template +class TSLIST_HEAD_ALIGN CTSList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + T elem; + + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size ) + { + Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_NODE_ALIGNMENT, __FILE__, __LINE__ ); + return pNode; + } + + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + { + Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_NODE_ALIGNMENT, pFileName, nLine ); + return pNode; + } + + static void operator delete( void *p) + { + MemAlloc_FreeAligned( p ); + } + static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + { + MemAlloc_FreeAligned( p ); + } + + } TSLIST_NODE_ALIGN_POST; + + ~CTSList() + { + Purge(); + } + + void Purge() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Purge(); + } + + Node_t *Push( Node_t *pNode ) + { + return (Node_t *)CTSListBase::Push( pNode ); + } + + Node_t *Pop() + { + return (Node_t *)CTSListBase::Pop(); + } + + void PushItem( const T &init ) + { + Push( new Node_t( init ) ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + delete pNode; + return true; + } + + Node_t *Detach() + { + return (Node_t *)CTSListBase::Detach(); + } + +} TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- + +template +class TSLIST_HEAD_ALIGN CTSListWithFreeList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + T elem; + } TSLIST_NODE_ALIGN_POST; + + ~CTSListWithFreeList() + { + Purge(); + } + + void Purge() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + pCurrent = (Node_t *)m_FreeList.Detach(); + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + m_FreeList.Push( pCurrent ); + pCurrent = pNext; + } + } + + Node_t *Push( Node_t *pNode ) + { + return (Node_t *)CTSListBase::Push( pNode ); + } + + Node_t *Pop() + { + return (Node_t *)CTSListBase::Pop(); + } + + void PushItem( const T &init ) + { + Node_t *pNode = (Node_t *)m_FreeList.Pop(); + if ( !pNode ) + { + pNode = new Node_t; + } + pNode->elem = init; + Push( pNode ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + m_FreeList.Push( pNode ); + return true; + } + + Node_t *Detach() + { + return (Node_t *)CTSListBase::Detach(); + } + + void FreeNode( Node_t *pNode ) + { + m_FreeList.Push( pNode ); + } + +private: + CTSListBase m_FreeList; +} TSLIST_HEAD_ALIGN_POST; + +//----------------------------------------------------------------------------- +// Lock free queue +// +// A special consideration: the element type should be simple. This code +// actually dereferences freed nodes as part of pop, but later detects +// that. If the item in the queue is a complex type, only bad things can +// come of that. Also, therefore, if you're using Push/Pop instead of +// push item, be aware that the node memory cannot be freed until +// all threads that might have been popping have completed the pop. +// The PushItem()/PopItem() for handles this by keeping a persistent +// free list. Dont mix Push/PushItem. Note also nodes will be freed at the end, +// and are expected to have been allocated with operator new. +//----------------------------------------------------------------------------- + +template +class TSLIST_HEAD_ALIGN CTSQueue +{ +public: + + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size ) + { + CTSQueue *pNode = (CTSQueue *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + return pNode; + } + + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + { + CTSQueue *pNode = (CTSQueue *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); + return pNode; + } + + static void operator delete( void *p) + { + MemAlloc_FreeAligned( p ); + } + + static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + { + MemAlloc_FreeAligned( p ); + } + +private: + // These ain't gonna work + static void * operator new[] ( size_t size ) throw() + { + return NULL; + } + + static void operator delete [] ( void *p) + { + } + +public: + + struct TSLIST_NODE_ALIGN Node_t + { + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size ) + { + Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + return pNode; + } + + static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + { + Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); + return pNode; + } + + static void operator delete( void *p) + { + MemAlloc_FreeAligned( p ); + } + + static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + { + MemAlloc_FreeAligned( p ); + } + + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + Node_t *pNext; + T elem; + } TSLIST_NODE_ALIGN_POST; + + union TSLIST_HEAD_ALIGN NodeLink_t + { + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new( size_t size ) + { + NodeLink_t *pNode = (NodeLink_t *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + return pNode; + } + + static void operator delete( void *p) + { + MemAlloc_FreeAligned( p ); + } + + struct Value_t + { + Node_t *pNode; + intp sequence; + } value; + +#ifdef PLATFORM_64BITS + int128 value64x128; +#else + int64 value64x128; +#endif + } TSLIST_HEAD_ALIGN_POST; + + CTSQueue() + { + COMPILE_TIME_ASSERT( sizeof(Node_t) >= sizeof(TSLNodeBase_t) ); + if ( ((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSQueue: Misaligned queue\n" ); + DebuggerBreak(); + } + if ( ((size_t)&m_Tail) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSQueue: Misaligned queue\n" ); + DebuggerBreak(); + } + m_Count = 0; + m_Head.value.sequence = m_Tail.value.sequence = 0; + m_Head.value.pNode = m_Tail.value.pNode = new Node_t; // list always contains a dummy node + m_Head.value.pNode->pNext = End(); + } + + ~CTSQueue() + { + Purge(); + Assert( m_Count == 0 ); + Assert( m_Head.value.pNode == m_Tail.value.pNode ); + Assert( m_Head.value.pNode->pNext == End() ); + delete m_Head.value.pNode; + } + + // Note: Purge, RemoveAll, and Validate are *not* threadsafe + void Purge() + { + if ( IsDebug() ) + { + ValidateQueue(); + } + + Node_t *pNode; + while ( ( pNode = Pop() ) != NULL ) + { + delete pNode; + } + + while ( ( pNode = (Node_t *)m_FreeNodes.Pop() ) != NULL ) + { + delete pNode; + } + + Assert( m_Count == 0 ); + Assert( m_Head.value.pNode == m_Tail.value.pNode ); + Assert( m_Head.value.pNode->pNext == End() ); + + m_Head.value.sequence = m_Tail.value.sequence = 0; + } + + void RemoveAll() + { + if ( IsDebug() ) + { + ValidateQueue(); + } + + Node_t *pNode; + while ( ( pNode = Pop() ) != NULL ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + } + + bool ValidateQueue() + { + if ( IsDebug() ) + { + bool bResult = true; + int nNodes = 0; + if ( m_Tail.value.pNode->pNext != End() ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + + if ( m_Count == 0 ) + { + if ( m_Head.value.pNode != m_Tail.value.pNode ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + } + + Node_t *pNode = m_Head.value.pNode; + while ( pNode != End() ) + { + nNodes++; + pNode = pNode->pNext; + } + + nNodes--;// skip dummy node + + if ( nNodes != m_Count ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + + if ( !bResult ) + { + Msg( "Corrupt CTSQueueDetected" ); + } + + return bResult; + } + else + { + return true; + } + } + + void FinishPush( Node_t *pNode, const NodeLink_t &oldTail ) + { + NodeLink_t newTail; + + newTail.value.pNode = pNode; + newTail.value.sequence = oldTail.value.sequence + 1; + + ThreadMemoryBarrier(); + + InterlockedCompareExchangeNodeLink( &m_Tail, newTail, oldTail ); + } + + Node_t *Push( Node_t *pNode ) + { +#ifdef _DEBUG + if ( (size_t)pNode % TSLIST_NODE_ALIGNMENT != 0 ) + { + Error( "CTSListBase: Misaligned node\n" ); + DebuggerBreak(); + } +#endif + + NodeLink_t oldTail; + + pNode->pNext = End(); + + for (;;) + { + oldTail.value.sequence = m_Tail.value.sequence; + oldTail.value.pNode = m_Tail.value.pNode; + if ( InterlockedCompareExchangeNode( &(oldTail.value.pNode->pNext), pNode, End() ) == End() ) + { + break; + } + else + { + // Another thread is trying to push, help it along + FinishPush( oldTail.value.pNode->pNext, oldTail ); + } + } + + FinishPush( pNode, oldTail ); // This can fail if another thread pushed between the sequence and node grabs above. Later pushes or pops corrects + + m_Count++; + + return oldTail.value.pNode; + } + + Node_t *Pop() + { + #define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) ) + NodeLink_t * volatile pHead = &m_Head; + NodeLink_t * volatile pTail = &m_Tail; + Node_t * volatile * pHeadNode = &m_Head.value.pNode; + volatile intp * volatile pHeadSequence = &m_Head.value.sequence; + Node_t * volatile * pTailNode = &pTail->value.pNode; + + NodeLink_t head; + NodeLink_t newHead; + Node_t *pNext; + intp tailSequence; + T elem; + + for (;;) + { + head.value.sequence = *pHeadSequence; // must grab sequence first, which allows condition below to ensure pNext is valid + ThreadMemoryBarrier(); // need a barrier to prevent reordering of these assignments + head.value.pNode = *pHeadNode; + tailSequence = pTail->value.sequence; + pNext = head.value.pNode->pNext; + + // Checking pNext only to force optimizer to not reorder the assignment + // to pNext and the compare of the sequence + if ( !pNext || head.value.sequence != *pHeadSequence ) + continue; + + if ( bTestOptimizer ) + { + if ( pNext == TSQUEUE_BAD_NODE_LINK ) + { + Msg( "Bad node link detected\n" ); + continue; + } + } + + if ( head.value.pNode == *pTailNode ) + { + if ( pNext == End() ) + return NULL; + + // Another thread is trying to push, help it along + NodeLink_t &oldTail = head; // just reuse local memory for head to build old tail + oldTail.value.sequence = tailSequence; // reuse head pNode + FinishPush( pNext, oldTail ); + continue; + } + + if ( pNext != End() ) + { + elem = pNext->elem; // NOTE: next could be a freed node here, by design + newHead.value.pNode = pNext; + newHead.value.sequence = head.value.sequence + 1; + if ( InterlockedCompareExchangeNodeLink( pHead, newHead, head ) ) + { + ThreadMemoryBarrier(); + if ( bTestOptimizer ) + { + head.value.pNode->pNext = TSQUEUE_BAD_NODE_LINK; + } + break; + } + } + } + + m_Count--; + head.value.pNode->elem = elem; + return head.value.pNode; + } + + void FreeNode( Node_t *pNode ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + + void PushItem( const T &init ) + { + Node_t *pNode = (Node_t *)m_FreeNodes.Pop(); + if ( pNode ) + { + pNode->elem = init; + } + else + { + pNode = new Node_t( init ); + } + Push( pNode ); + } + + bool PopItem( T *pResult ) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + + *pResult = pNode->elem; + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + return true; + } + + int Count() const + { + return m_Count; + } + +private: + Node_t *End() { return (Node_t *)this; } // just need a unique signifier + + Node_t *InterlockedCompareExchangeNode( Node_t * volatile *ppNode, Node_t *value, Node_t *comperand ) + { + return (Node_t *)::ThreadInterlockedCompareExchangePointer( (void **)ppNode, value, comperand ); + } + + bool InterlockedCompareExchangeNodeLink( NodeLink_t volatile *pLink, const NodeLink_t &value, const NodeLink_t &comperand ) + { + return ThreadInterlockedAssignIf64x128( &pLink->value64x128, value.value64x128, comperand.value64x128 ); + } + + NodeLink_t m_Head; + NodeLink_t m_Tail; + + CInterlockedInt m_Count; + + CTSListBase m_FreeNodes; +} TSLIST_NODE_ALIGN_POST; + +#if defined( _WIN32 ) +// Suppress this spurious warning: +// warning C4700: uninitialized local variable 'oldHead' used +#pragma warning( pop ) +#endif + +#endif // TSLIST_H diff --git a/public/tier0/validator.h b/public/tier0/validator.h new file mode 100644 index 0000000..6af0f51 --- /dev/null +++ b/public/tier0/validator.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "valobject.h" + +#ifndef VALIDATOR_H +#define VALIDATOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef DBGFLAG_VALIDATE + + +class CValidator +{ +public: + // Constructors & destructors + CValidator( void ); + ~CValidator( void ); + + // Call this each time we enter a new Validate function + void Push( tchar *pchType, void *pvObj, tchar *pchName ); + + // Call this each time we exit a Validate function + void Pop( void ); + + // Claim ownership of a memory block + void ClaimMemory( void *pvMem ); + + // Finish performing a check and perform necessary computations + void Finalize( void ); + + // Render our results to the console + void RenderObjects( int cubThreshold ); // Render all reported objects + void RenderLeaks( void ); // Render all memory leaks + + // List manipulation functions: + CValObject *FindObject( void *pvObj ); // Returns CValObject containing pvObj, or NULL. + void DiffAgainst( CValidator *pOtherValidator ); // Removes any entries from this validator that are also present in the other. + + // Accessors + bool BMemLeaks( void ) { return m_bMemLeaks; }; + CValObject *PValObjectFirst( void ) { return m_pValObjectFirst; }; + + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures + + +private: + CValObject *m_pValObjectFirst; // Linked list of all ValObjects + CValObject *m_pValObjectLast; // Last ValObject on the linked list + + CValObject *m_pValObjectCur; // Object we're current processing + + int m_cpvOwned; // Total # of blocks owned + + int m_cpubLeaked; // # of leaked memory blocks + int m_cubLeaked; // Amount of leaked memory + bool m_bMemLeaks; // Has any memory leaked? +}; + + +#endif // DBGFLAG_VALIDATE + + +#endif // VALIDATOR_H diff --git a/public/tier0/valobject.h b/public/tier0/valobject.h new file mode 100644 index 0000000..c139e9e --- /dev/null +++ b/public/tier0/valobject.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: CValObject is used for tracking individual objects that report +// in to CValidator. Whenever a new object reports in (via CValidator::Push), +// we create a new CValObject to aggregate stats for it. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VALOBJECT_H +#define VALOBJECT_H +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef DBGFLAG_VALIDATE +class CValObject +{ +public: + // Constructors & destructors + CValObject( void ) { }; + ~CValObject( void ); + + void Init( tchar *pchType, void *pvObj, tchar *pchName, CValObject *pValObjectParent, + CValObject *pValObjectPrev ); + + // Our object has claimed ownership of a memory block + void ClaimMemoryBlock( void *pvMem ); + + // A child of ours has claimed ownership of a memory block + void ClaimChildMemoryBlock( int cubUser ); + + // Accessors + tchar *PchType( void ) { return m_rgchType; }; + void *PvObj( void ) { return m_pvObj; }; + tchar *PchName( void ) { return m_rgchName; }; + CValObject *PValObjectParent( void ) { return m_pValObjectParent; }; + int NLevel( void ) { return m_nLevel; }; + CValObject *PValObjectNext( void ) { return m_pValObjectNext; }; + int CpubMemSelf( void ) { return m_cpubMemSelf; }; + int CubMemSelf( void ) { return m_cubMemSelf; }; + int CpubMemTree( void ) { return m_cpubMemTree; }; + int CubMemTree( void ) { return m_cubMemTree; }; + int NUser( void ) { return m_nUser; }; + void SetNUser( int nUser ) { m_nUser = nUser; }; + void SetBNewSinceSnapshot( bool bNewSinceSnapshot ) { m_bNewSinceSnapshot = bNewSinceSnapshot; } + bool BNewSinceSnapshot( void ) { return m_bNewSinceSnapshot; } + +private: + bool m_bNewSinceSnapshot; // If this block is new since the snapshot. + tchar m_rgchType[64]; // Type of the object we represent + tchar m_rgchName[64]; // Name of this particular object + void *m_pvObj; // Pointer to the object we represent + + CValObject *m_pValObjectParent; // Our parent object in the tree. + int m_nLevel; // Our depth in the tree + + CValObject *m_pValObjectNext; // Next ValObject in the linked list + + int m_cpubMemSelf; // # of memory blocks we own directly + int m_cubMemSelf; // Total size of the memory blocks we own directly + + int m_cpubMemTree; // # of memory blocks owned by us and our children + int m_cubMemTree; // Total size of the memory blocks owned by us and our children + + int m_nUser; // Field provided for use by our users +}; +#endif // DBGFLAG_VALIDATE + + +#endif // VALOBJECT_H diff --git a/public/tier0/valve_minmax_off.h b/public/tier0/valve_minmax_off.h new file mode 100644 index 0000000..a6dd819 --- /dev/null +++ b/public/tier0/valve_minmax_off.h @@ -0,0 +1,7 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifdef vmin + #undef vmin +#endif +#ifdef vmax + #undef vmax +#endif diff --git a/public/tier0/valve_minmax_on.h b/public/tier0/valve_minmax_on.h new file mode 100644 index 0000000..fb98fdd --- /dev/null +++ b/public/tier0/valve_minmax_on.h @@ -0,0 +1,7 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef vmin + #define vmin(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef vmax + #define vmax(a,b) (((a) > (b)) ? (a) : (b)) +#endif diff --git a/public/tier0/valve_off.h b/public/tier0/valve_off.h new file mode 100644 index 0000000..796408e --- /dev/null +++ b/public/tier0/valve_off.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This turns off all Valve-specific #defines. Because we sometimes +// call external include files from inside .cpp files, we need to +// wrap those includes like this: +// #include "tier0/valve_off.h" +// #include +// #include "tier0/valve_on.h" +// +// $NoKeywords: $ +//=============================================================================// + + +#ifdef STEAM + +//----------------------------------------------------------------------------- +// Unicode-related #defines (see wchartypes.h) +//----------------------------------------------------------------------------- +#undef char + + +//----------------------------------------------------------------------------- +// Memory-related #defines +//----------------------------------------------------------------------------- +#undef malloc +#undef realloc +#undef _expand +#undef free + +#endif diff --git a/public/tier0/valve_on.h b/public/tier0/valve_on.h new file mode 100644 index 0000000..ffc9b89 --- /dev/null +++ b/public/tier0/valve_on.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This turns on all Valve-specific #defines. Because we sometimes +// call external include files from inside .cpp files, we need to +// wrap those includes like this: +// #include "tier0/valve_off.h" +// #include +// #include "tier0/valve_on.h" +// +// $NoKeywords: $ +//=============================================================================// + + +#ifdef STEAM +//----------------------------------------------------------------------------- +// Unicode-related #defines (see wchartypes.h) +//----------------------------------------------------------------------------- +#ifdef ENFORCE_WCHAR +#define char DontUseChar_SeeWcharOn.h +#endif + + +//----------------------------------------------------------------------------- +// Memory-related #defines +//----------------------------------------------------------------------------- +#define malloc( cub ) HEY_DONT_USE_MALLOC_USE_PVALLOC +#define realloc( pvOld, cub ) HEY_DONT_USE_REALLOC_USE_PVREALLOC +#define _expand( pvOld, cub ) HEY_DONT_USE_EXPAND_USE_PVEXPAND +#define free( pv ) HEY_DONT_USE_FREE_USE_FREEPV + +#endif diff --git a/public/tier0/vcr_shared.h b/public/tier0/vcr_shared.h new file mode 100644 index 0000000..d2d5ac7 --- /dev/null +++ b/public/tier0/vcr_shared.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VCR_SHARED_H +#define VCR_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +#define VCRFILE_VERSION 2 + + +// Identifiers for the things we record. When playing back, these things should +// be asked for in the exact same order (otherwise, the engine isn't making all +// the calls in the same order). +typedef enum +{ + VCREvent_Sys_FloatTime=0, + VCREvent_recvfrom, + VCREvent_SyncToken, + VCREvent_GetCursorPos, + VCREvent_SetCursorPos, + VCREvent_ScreenToClient, + VCREvent_Cmd_Exec, + VCREvent_CmdLine, + VCREvent_RegOpenKeyEx, + VCREvent_RegSetValueEx, + VCREvent_RegQueryValueEx, + VCREvent_RegCreateKeyEx, + VCREvent_RegCloseKey, + VCREvent_PeekMessage, + VCREvent_GameMsg, + VCREvent_GetNumberOfConsoleInputEvents, + VCREvent_ReadConsoleInput, + VCREvent_GetKeyState, + VCREvent_recv, + VCREvent_send, + VCREvent_Generic, + VCREvent_CreateThread, + VCREvent_WaitForSingleObject, + VCREvent_EnterCriticalSection, + VCREvent_Time, + VCREvent_LocalTime, + VCREvent_GenericString, + VCREvent_NUMEVENTS +} VCREvent; + + +#endif // VCR_SHARED_H diff --git a/public/tier0/vcrmode.h b/public/tier0/vcrmode.h new file mode 100644 index 0000000..2af8a60 --- /dev/null +++ b/public/tier0/vcrmode.h @@ -0,0 +1,306 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: VCR mode records a client's game and allows you to +// play it back and reproduce it exactly. When playing it back, nothing +// is simulated on the server, but all server packets are recorded. +// +// Most of the VCR mode functionality is accomplished through hooks +// called at various points in the engine. +// +// $NoKeywords: $ +//===========================================================================// +#ifndef VCRMODE_H +#define VCRMODE_H + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier0/vcr_shared.h" +#include "tier0/dbg.h" + +#ifdef POSIX +DBG_INTERFACE const char *BuildCmdLine( int argc, char **argv, bool fAddSteam = true ); +tchar *GetCommandLine(); +#endif + +#ifdef _X360 +#define NO_VCR 1 +#endif + + +// Enclose lines of code in this if you don't want anything in them written to or read from the VCR file. +#ifndef NO_VCR +#define NOVCR(x) \ +{\ + VCRSetEnabled(0);\ + x;\ + VCRSetEnabled(1);\ +} +#else +#define NOVCR(x) \ +{\ + x;\ +} +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct InputEvent_t; + + +//----------------------------------------------------------------------------- +// Definitions. +//----------------------------------------------------------------------------- +enum VCRMode_t +{ + VCR_Invalid=-1, + VCR_Disabled=0, + VCR_Record, + VCR_Playback +}; + + +//----------------------------------------------------------------------------- +// Functions. +//----------------------------------------------------------------------------- +abstract_class IVCRHelpers +{ +public: + virtual void ErrorMessage( const tchar *pMsg ) = 0; + virtual void* GetMainWindow() = 0; +}; + + +// Used by the vcrtrace program. +abstract_class IVCRTrace +{ +public: + virtual VCREvent ReadEvent() = 0; + virtual void Read( void *pDest, int size ) = 0; +}; + +typedef struct VCR_s +{ + // Start VCR record or play. + int (*Start)( tchar const *pFilename, bool bRecord, IVCRHelpers *pHelpers ); + void (*End)(); + + // Used by the VCR trace app. + IVCRTrace* (*GetVCRTraceInterface)(); + + // Get the current mode the VCR is in. + VCRMode_t (*GetMode)(); + + // This can be used to block out areas of code that are unpredictable (like things triggered by WM_TIMER messages). + // Note: this enables/disables VCR mode usage on a PER-THREAD basis. The assumption is that you're marking out + // specific sections of code that you don't want to use VCR mode inside of, but you're not intending to + // stop all the other threads from using VCR mode. + void (*SetEnabled)(int bEnabled); + + // This can be called any time to put in a debug check to make sure things are synchronized. + void (*SyncToken)(tchar const *pToken); + + // Hook for Sys_FloatTime(). + double (*Hook_Sys_FloatTime)(double time); + + // Note: this makes no guarantees about msg.hwnd being the same on playback. If it needs to be, then we need to add + // an ID system for Windows and store the ID like in Goldsrc. + int (*Hook_PeekMessage)( + struct tagMSG *msg, + void *hWnd, + unsigned int wMsgFilterMin, + unsigned int wMsgFilterMax, + unsigned int wRemoveMsg + ); + + // Call this to record game messages. + void (*Hook_RecordGameMsg)( const InputEvent_t &event ); + void (*Hook_RecordEndGameMsg)(); + + // Call this to playback game messages until it returns false. + bool (*Hook_PlaybackGameMsg)( InputEvent_t *pEvent ); + + // Hook for recvfrom() calls. This replaces the recvfrom() call. + int (*Hook_recvfrom)(int s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen); + + void (*Hook_GetCursorPos)(struct tagPOINT *pt); + void (*Hook_ScreenToClient)(void *hWnd, struct tagPOINT *pt); + + void (*Hook_Cmd_Exec)(tchar **f); + + tchar* (*Hook_GetCommandLine)(); + + // Registry hooks. + long (*Hook_RegOpenKeyEx)( void *hKey, const tchar *lpSubKey, unsigned long ulOptions, unsigned long samDesired, void *pHKey ); + long (*Hook_RegSetValueEx)(void *hKey, tchar const *lpValueName, unsigned long Reserved, unsigned long dwType, uint8 const *lpData, unsigned long cbData); + long (*Hook_RegQueryValueEx)(void *hKey, tchar const *lpValueName, unsigned long *lpReserved, unsigned long *lpType, uint8 *lpData, unsigned long *lpcbData); + long (*Hook_RegCreateKeyEx)(void *hKey, tchar const *lpSubKey, unsigned long Reserved, tchar *lpClass, unsigned long dwOptions, unsigned long samDesired, void *lpSecurityAttributes, void *phkResult, unsigned long *lpdwDisposition); + void (*Hook_RegCloseKey)(void *hKey); + + // hInput is a HANDLE. + int (*Hook_GetNumberOfConsoleInputEvents)( void *hInput, unsigned long *pNumEvents ); + + // hInput is a HANDLE. + // pRecs is an INPUT_RECORD pointer. + int (*Hook_ReadConsoleInput)( void *hInput, void *pRecs, int nMaxRecs, unsigned long *pNumRead ); + + + // This calls time() then gives you localtime()'s result. + void (*Hook_LocalTime)( struct tm *today ); + + short (*Hook_GetKeyState)( int nVirtKey ); + + // TCP calls. + int (*Hook_recv)( int s, char *buf, int len, int flags ); + int (*Hook_send)( int s, const char *buf, int len, int flags ); + + // These can be used to add events without having to modify VCR mode. + // pEventName is used for verification to make sure it's playing back correctly. + // If pEventName is null, then verification is not performed. + void (*GenericRecord)( const tchar *pEventName, const void *pData, int len ); + + + // Returns the number of bytes written in the generic event. + // If bForceLenSame is true, then it will error out unless the value in the VCR file is the same as maxLen. + int (*GenericPlayback)( const tchar *pEventName, void *pOutData, int maxLen, bool bForceLenSame ); + + // If you just want to record and playback a value and not worry about whether or not you're + // recording or playing back, use this. It also will do nothing if you're not recording or playing back. + // + // NOTE: also see GenericValueVerify, which allows you to have it VERIFY that pData's contents are the same upon playback + // (rather than just copying whatever is in the VCR file into pData). + void (*GenericValue)( const tchar *pEventName, void *pData, int maxLen ); + + // Get the current percent (0.0 - 1.0) that it's played back through the file (only valid in playback). + double (*GetPercentCompleted)(); + + // If you use this, then any VCR stuff the thread does will work with VCR mode. + // This mirrors the Windows API CreateThread function and returns a HANDLE the same way. + void* (*Hook_CreateThread)( + void *lpThreadAttributes, + unsigned long dwStackSize, + void *lpStartAddress, + void *lpParameter, + unsigned long dwCreationFlags, + unsigned long *lpThreadID ); + + unsigned long (*Hook_WaitForSingleObject)( + void *handle, + unsigned long dwMilliseconds ); + + void (*Hook_EnterCriticalSection)( void *pCS ); + + void (*Hook_Time)( long *pTime ); + + // String value. Playback just verifies that the incoming string is the same as it was when recording. + void (*GenericString)( const char *pEventName, const char *pString ); + + // Works like GenericValue, except upon playback it will verify that pData's contents are the same as it was during recording. + void (*GenericValueVerify)( const tchar *pEventName, const void *pData, int maxLen ); + + unsigned long (*Hook_WaitForMultipleObjects)( uint32 nHandles, const void **pHandles, int bWaitAll, uint32 timeout ); + +} VCR_t; + +#ifndef NO_VCR + +// In the launcher, this is created by vcrmode.c. +// In the engine, this is set when the launcher initializes its DLL. +PLATFORM_INTERFACE VCR_t *g_pVCR; + +#endif + + +#ifndef NO_VCR +#define VCRStart g_pVCR->Start +#define VCREnd g_pVCR->End +#define VCRGetVCRTraceInterface g_pVCR->GetVCRTraceInterface +#define VCRGetMode g_pVCR->GetMode +#define VCRSetEnabled g_pVCR->SetEnabled +#define VCRSyncToken g_pVCR->SyncToken +#define VCRGenericString g_pVCR->GenericString +#define VCRGenericValueVerify g_pVCR->GenericValueVerify +#define VCRHook_Sys_FloatTime g_pVCR->Hook_Sys_FloatTime +#define VCRHook_PeekMessage g_pVCR->Hook_PeekMessage +#define VCRHook_RecordGameMsg g_pVCR->Hook_RecordGameMsg +#define VCRHook_RecordEndGameMsg g_pVCR->Hook_RecordEndGameMsg +#define VCRHook_PlaybackGameMsg g_pVCR->Hook_PlaybackGameMsg +#define VCRHook_recvfrom g_pVCR->Hook_recvfrom +#define VCRHook_GetCursorPos g_pVCR->Hook_GetCursorPos +#define VCRHook_ScreenToClient g_pVCR->Hook_ScreenToClient +#define VCRHook_Cmd_Exec g_pVCR->Hook_Cmd_Exec +#define VCRHook_GetCommandLine g_pVCR->Hook_GetCommandLine +#define VCRHook_RegOpenKeyEx g_pVCR->Hook_RegOpenKeyEx +#define VCRHook_RegSetValueEx g_pVCR->Hook_RegSetValueEx +#define VCRHook_RegQueryValueEx g_pVCR->Hook_RegQueryValueEx +#define VCRHook_RegCreateKeyEx g_pVCR->Hook_RegCreateKeyEx +#define VCRHook_RegCloseKey g_pVCR->Hook_RegCloseKey +#define VCRHook_GetNumberOfConsoleInputEvents g_pVCR->Hook_GetNumberOfConsoleInputEvents +#define VCRHook_ReadConsoleInput g_pVCR->Hook_ReadConsoleInput +#define VCRHook_LocalTime g_pVCR->Hook_LocalTime +#define VCRHook_GetKeyState g_pVCR->Hook_GetKeyState +#define VCRHook_recv g_pVCR->Hook_recv +#define VCRHook_send g_pVCR->Hook_send +#define VCRGenericRecord g_pVCR->GenericRecord +#define VCRGenericPlayback g_pVCR->GenericPlayback +#define VCRGenericValue g_pVCR->GenericValue +#define VCRGetPercentCompleted g_pVCR->GetPercentCompleted +#define VCRHook_CreateThread g_pVCR->Hook_CreateThread +#define VCRHook_WaitForSingleObject g_pVCR->Hook_WaitForSingleObject +#define VCRHook_EnterCriticalSection g_pVCR->Hook_EnterCriticalSection +#define VCRHook_Time g_pVCR->Hook_Time +#define VCRHook_WaitForMultipleObjects( a, b, c, d) g_pVCR->Hook_WaitForMultipleObjects( a, (const void **)b, c, d) +#else +#define VCRStart( a, b, c ) (1) +#define VCREnd ((void)(0)) +#define VCRGetVCRTraceInterface (NULL) +#define VCRGetMode() (VCR_Disabled) +#define VCRSetEnabled( a ) ((void)(0)) +#define VCRSyncToken( a ) ((void)(0)) +#define VCRGenericRecord MUST_IFDEF_OUT_GenericRecord +#define VCRGenericPlayback MUST_IFDEF_OUT_GenericPlayback +#define VCRGenericValue MUST_IFDEF_OUT_GenericValue +#define VCRGenericString MUST_IFDEF_OUT_GenericString +#define VCRGenericValueVerify MUST_IFDEF_OUT_GenericValueVerify +#define VCRGetPercentCompleted() (0.0f) +#define VCRHook_Sys_FloatTime Sys_FloatTime +#define VCRHook_PeekMessage PeekMessage +#define VCRHook_RecordGameMsg RecordGameMsg +#define VCRHook_RecordEndGameMsg RecordEndGameMsg +#define VCRHook_PlaybackGameMsg PlaybackGameMsg +#define VCRHook_recvfrom recvfrom +#define VCRHook_GetCursorPos GetCursorPos +#define VCRHook_ScreenToClient ScreenToClient +#define VCRHook_Cmd_Exec( a ) ((void)(0)) +#define VCRHook_GetCommandLine GetCommandLine +#define VCRHook_RegOpenKeyEx RegOpenKeyEx +#define VCRHook_RegSetValueEx RegSetValueEx +#define VCRHook_RegQueryValueEx RegQueryValueEx +#define VCRHook_RegCreateKeyEx RegCreateKeyEx +#define VCRHook_RegCloseKey RegCloseKey +#define VCRHook_GetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents +#define VCRHook_ReadConsoleInput ReadConsoleInput +#define VCRHook_LocalTime( a ) memset(a, 0, sizeof(*a)); +#define VCRHook_GetKeyState GetKeyState +#define VCRHook_recv recv +#define VCRHook_send send +#if defined( _X360 ) +#define VCRHook_CreateThread CreateThread +#else +#define VCRHook_CreateThread (void*)_beginthreadex +#endif +#define VCRHook_WaitForSingleObject WaitForSingleObject +#define VCRHook_EnterCriticalSection EnterCriticalSection +#define VCRHook_WaitForMultipleObjects( a, b, c, d) WaitForMultipleObjects( a, (const HANDLE *)b, c, d) +#define VCRHook_Time Time +#endif + +#endif // VCRMODE_H diff --git a/public/tier0/vprof.h b/public/tier0/vprof.h new file mode 100644 index 0000000..1c7321b --- /dev/null +++ b/public/tier0/vprof.h @@ -0,0 +1,1440 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Real-Time Hierarchical Profiling +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPROF_H +#define VPROF_H + +#include "tier0/dbg.h" +#include "tier0/fasttimer.h" +#include "tier0/l2cache.h" +#include "tier0/threadtools.h" +#include "tier0/vprof_telemetry.h" + +// VProf is enabled by default in all configurations -except- X360 Retail. +#if !( defined( _X360 ) && defined( _CERT ) ) +#define VPROF_ENABLED +#endif + +#if defined(_X360) && defined(VPROF_ENABLED) +#include "tier0/pmc360.h" +#ifndef USE_PIX +#define VPROF_UNDO_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#define USE_PIX +#include +#undef USE_PIX +#else +#include +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +// enable this to get detailed nodes beneath budget +// #define VPROF_LEVEL 1 + +// enable this to use pix (360 only) +// #define VPROF_PIX 1 + +#if defined(VPROF_PIX) +#pragma comment( lib, "Xapilibi" ) +#endif + +//----------------------------------------------------------------------------- +// +// Profiling instrumentation macros +// + +#define MAXCOUNTERS 256 + + +#ifdef VPROF_ENABLED + +#define VPROF_VTUNE_GROUP + +#define VPROF( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0) +#define VPROF_ASSERT_ACCOUNTED( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, true, 0) +#define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail(name,group, bAssertAccounted, budgetFlags) + +#define VPROF_BUDGET( name, group ) VPROF_BUDGET_FLAGS(name, group, BUDGETFLAG_OTHER) +#define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF_(name, 0, group, false, flags) + +#define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +#define VPROF_SCOPE_END() } while (0) + +#define VPROF_ONLY( expression ) expression + +#define VPROF_ENTER_SCOPE( name ) g_VProfCurrentProfile.EnterScope( name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0 ) +#define VPROF_EXIT_SCOPE() g_VProfCurrentProfile.ExitScope() + +#define VPROF_BUDGET_GROUP_ID_UNACCOUNTED 0 + + +// Budgetgroup flags. These are used with VPROF_BUDGET_FLAGS. +// These control which budget panels the groups show up in. +// If a budget group uses VPROF_BUDGET, it gets the default +// which is BUDGETFLAG_OTHER. +#define BUDGETFLAG_CLIENT (1<<0) // Shows up in the client panel. +#define BUDGETFLAG_SERVER (1<<1) // Shows up in the server panel. +#define BUDGETFLAG_OTHER (1<<2) // Unclassified (the client shows these but the dedicated server doesn't). +#define BUDGETFLAG_HIDDEN (1<<15) +#define BUDGETFLAG_ALL 0xFFFF + + +// NOTE: You can use strings instead of these defines. . they are defined here and added +// in vprof.cpp so that they are always in the same order. +#define VPROF_BUDGETGROUP_OTHER_UNACCOUNTED _T("Unaccounted") +#define VPROF_BUDGETGROUP_WORLD_RENDERING _T("World Rendering") +#define VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING _T("Displacement_Rendering") +#define VPROF_BUDGETGROUP_GAME _T("Game") +#define VPROF_BUDGETGROUP_NPCS _T("NPCs") +#define VPROF_BUDGETGROUP_SERVER_ANIM _T("Server Animation") +#define VPROF_BUDGETGROUP_PHYSICS _T("Physics") +#define VPROF_BUDGETGROUP_STATICPROP_RENDERING _T("Static_Prop_Rendering") +#define VPROF_BUDGETGROUP_MODEL_RENDERING _T("Other_Model_Rendering") +#define VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING _T("Fast Path Model Rendering") +#define VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING _T("Brush_Model_Rendering") +#define VPROF_BUDGETGROUP_SHADOW_RENDERING _T("Shadow_Rendering") +#define VPROF_BUDGETGROUP_DETAILPROP_RENDERING _T("Detail_Prop_Rendering") +#define VPROF_BUDGETGROUP_PARTICLE_RENDERING _T("Particle/Effect_Rendering") +#define VPROF_BUDGETGROUP_ROPES _T("Ropes") +#define VPROF_BUDGETGROUP_DLIGHT_RENDERING _T("Dynamic_Light_Rendering") +#define VPROF_BUDGETGROUP_OTHER_NETWORKING _T("Networking") +#define VPROF_BUDGETGROUP_CLIENT_ANIMATION _T("Client_Animation") +#define VPROF_BUDGETGROUP_OTHER_SOUND _T("Sound") +#define VPROF_BUDGETGROUP_OTHER_VGUI _T("VGUI") +#define VPROF_BUDGETGROUP_OTHER_FILESYSTEM _T("FileSystem") +#define VPROF_BUDGETGROUP_PREDICTION _T("Prediction") +#define VPROF_BUDGETGROUP_INTERPOLATION _T("Interpolation") +#define VPROF_BUDGETGROUP_SWAP_BUFFERS _T("Swap_Buffers") +#define VPROF_BUDGETGROUP_PLAYER _T("Player") +#define VPROF_BUDGETGROUP_OCCLUSION _T("Occlusion") +#define VPROF_BUDGETGROUP_OVERLAYS _T("Overlays") +#define VPROF_BUDGETGROUP_TOOLS _T("Tools") +#define VPROF_BUDGETGROUP_LIGHTCACHE _T("Light_Cache") +#define VPROF_BUDGETGROUP_DISP_HULLTRACES _T("Displacement_Hull_Traces") +#define VPROF_BUDGETGROUP_TEXTURE_CACHE _T("Texture_Cache") +#define VPROF_BUDGETGROUP_REPLAY _T("Replay") +#define VPROF_BUDGETGROUP_PARTICLE_SIMULATION _T("Particle Simulation") +#define VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING _T("Flashlight Shadows") +#define VPROF_BUDGETGROUP_CLIENT_SIM _T("Client Simulation") // think functions, tempents, etc. +#define VPROF_BUDGETGROUP_STEAM _T("Steam") +#define VPROF_BUDGETGROUP_CVAR_FIND _T("Cvar_Find") +#define VPROF_BUDGETGROUP_CLIENTLEAFSYSTEM _T("ClientLeafSystem") +#define VPROF_BUDGETGROUP_JOBS_COROUTINES _T("Jobs/Coroutines") +#define VPROF_BUDGETGROUP_SLEEPING _T("Sleeping") +#define VPROF_BUDGETGROUP_THREADINGMAIN _T("ThreadingMain") +#define VPROF_BUDGETGROUP_HTMLSURFACE _T("HTMLSurface") +#define VPROF_BUDGETGROUP_VGUI VPROF_BUDGETGROUP_HTMLSURFACE +#define VPROF_BUDGETGROUP_TENFOOT VPROF_BUDGETGROUP_HTMLSURFACE +#define VPROF_BUDGETGROUP_STEAMUI VPROF_BUDGETGROUP_HTMLSURFACE +#define VPROF_BUDGETGROUP_ATTRIBUTES _T("Attributes") +#define VPROF_BUDGETGROUP_FINDATTRIBUTE _T("FindAttribute") +#define VPROF_BUDGETGROUP_FINDATTRIBUTEUNSAFE _T("FindAttributeUnsafe") + +#ifdef _X360 +// update flags +#define VPROF_UPDATE_BUDGET 0x01 // send budget data every frame +#define VPROF_UPDATE_TEXTURE_GLOBAL 0x02 // send global texture data every frame +#define VPROF_UPDATE_TEXTURE_PERFRAME 0x04 // send perframe texture data every frame +#endif + +//------------------------------------- + +#ifndef VPROF_LEVEL +#define VPROF_LEVEL 0 +#endif + +//these macros exist to create VProf_ variables. This is important because it avoids /analyze warnings about variable aliasing when VPROF's are nested within each other, and allows +//for multiple VPROF's to exist within the same scope. Three macros must be used to force the __LINE__ to be resolved prior to the token concatenation, but just ignore the _INTERNAL macros and use +//the VPROF_VAR_NAME +#define VPROF_VAR_NAME_INTERNAL_CAT(a, b) a##b +#define VPROF_VAR_NAME_INTERNAL( a, b ) VPROF_VAR_NAME_INTERNAL_CAT( a, b ) +#define VPROF_VAR_NAME( a ) VPROF_VAR_NAME_INTERNAL( a, __LINE__ ) + +#define VPROF_0(name,group,assertAccounted,budgetFlags) tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "(%s)%s", group, name ); CVProfScope VPROF_VAR_NAME( VProf_ )(name, 0, group, assertAccounted, budgetFlags); + +#if VPROF_LEVEL > 0 +#define VPROF_1(name,group,assertAccounted,budgetFlags) tmZone( TELEMETRY_LEVEL3, TMZF_NONE, "(%s)%s", group, name ); CVProfScope VPROF_VAR_NAME( VProf_ )(name, 1, group, assertAccounted, budgetFlags); +#else +#define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +#endif + +#if VPROF_LEVEL > 1 +#define VPROF_2(name,group,assertAccounted,budgetFlags) CVProfScope VPROF_VAR_NAME( VProf_ )(name, 2, group, assertAccounted, budgetFlags); +#else +#define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +#endif + +#if VPROF_LEVEL > 2 +#define VPROF_3(name,group,assertAccounted,budgetFlags) CVProfScope VPROF_VAR_NAME( VProf_ )(name, 3, group, assertAccounted, budgetFlags); +#else +#define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +#endif + +#if VPROF_LEVEL > 3 +#define VPROF_4(name,group,assertAccounted,budgetFlags) CVProfScope VPROF_VAR_NAME( VProf_ )(name, 4, group, assertAccounted, budgetFlags); +#else +#define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +#endif + +//------------------------------------- + +#ifdef _MSC_VER +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( __FUNCTION__ ": " #code ); \ + code; \ + } +#else +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( #code ); \ + code; \ + } +#endif + + +//------------------------------------- + +#define VPROF_INCREMENT_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Increment( amount ); } while( 0 ) + +#else + +#define VPROF( name ) ((void)0) +#define VPROF_ASSERT_ACCOUNTED( name ) ((void)0) +#define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) ((void)0) +#define VPROF_BUDGET( name, group ) ((void)0) +#define VPROF_BUDGET_FLAGS( name, group, flags ) ((void)0) + +#define VPROF_SCOPE_BEGIN( tag ) do { +#define VPROF_SCOPE_END() } while (0) + +#define VPROF_ONLY( expression ) ((void)0) + +#define VPROF_ENTER_SCOPE( name ) +#define VPROF_EXIT_SCOPE() + +#define VPROF_INCREMENT_COUNTER(name,amount) ((void)0) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) ((void)0) + +#define VPROF_TEST_SPIKE( msec ) ((void)0) + +#define VProfCode( code ) code + +#endif + +//----------------------------------------------------------------------------- + +#ifdef VPROF_ENABLED + +//----------------------------------------------------------------------------- +// +// A node in the call graph hierarchy +// + +class DBG_CLASS CVProfNode +{ +friend class CVProfRecorder; +friend class CVProfile; + +public: + CVProfNode( const tchar * pszName, int detailLevel, CVProfNode *pParent, const tchar *pBudgetGroupName, int budgetFlags ); + ~CVProfNode(); + + CVProfNode *GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, int budgetFlags ); + CVProfNode *GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName ); + CVProfNode *GetParent(); + CVProfNode *GetSibling(); + CVProfNode *GetPrevSibling(); + CVProfNode *GetChild(); + + void MarkFrame(); + void ResetPeak(); + + void Pause(); + void Resume(); + void Reset(); + + void EnterScope(); + bool ExitScope(); + + const tchar *GetName(); + + int GetBudgetGroupID() + { + return m_BudgetGroupID; + } + + // Only used by the record/playback stuff. + void SetBudgetGroupID( int id ) + { + m_BudgetGroupID = id; + } + + int GetCurCalls(); + double GetCurTime(); + int GetPrevCalls(); + double GetPrevTime(); + int GetTotalCalls(); + double GetTotalTime(); + double GetPeakTime(); + + double GetCurTimeLessChildren(); + double GetPrevTimeLessChildren(); + double GetTotalTimeLessChildren(); + + int GetPrevL2CacheMissLessChildren(); + int GetPrevLoadHitStoreLessChildren(); + + void ClearPrevTime(); + + int GetL2CacheMisses(); + + // Not used in the common case... + void SetCurFrameTime( unsigned long milliseconds ); + + void SetClientData( int iClientData ) { m_iClientData = iClientData; } + int GetClientData() const { return m_iClientData; } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + + +// Used by vprof record/playback. +private: + + void SetUniqueNodeID( int id ) + { + m_iUniqueNodeID = id; + } + + int GetUniqueNodeID() const + { + return m_iUniqueNodeID; + } + + static int s_iCurrentUniqueNodeID; + + +private: + const tchar *m_pszName; + CFastTimer m_Timer; + + // L2 Cache data. + int m_iPrevL2CacheMiss; + int m_iCurL2CacheMiss; + int m_iTotalL2CacheMiss; + +#ifndef _X360 + // L2 Cache data. + CL2Cache m_L2Cache; +#else // 360: + + unsigned int m_iBitFlags; // see enum below for settings + CPMCData m_PMCData; + int m_iPrevLoadHitStores; + int m_iCurLoadHitStores; + int m_iTotalLoadHitStores; + + public: + enum FlagBits + { + kRecordL2 = 0x01, + kCPUTrace = 0x02, ///< cause a PIX trace inside this node. + }; + // call w/ true to enable L2 and LHS recording; false to turn it off + inline void EnableL2andLHS(bool enable) + { + if (enable) + m_iBitFlags |= kRecordL2; + else + m_iBitFlags &= (~kRecordL2); + } + + inline bool IsL2andLHSEnabled( void ) + { + return (m_iBitFlags & kRecordL2) != 0; + } + + int GetLoadHitStores(); + + private: + +#endif + + int m_nRecursions; + + unsigned m_nCurFrameCalls; + CCycleCount m_CurFrameTime; + + unsigned m_nPrevFrameCalls; + CCycleCount m_PrevFrameTime; + + unsigned m_nTotalCalls; + CCycleCount m_TotalTime; + + CCycleCount m_PeakTime; + + CVProfNode *m_pParent; + CVProfNode *m_pChild; + CVProfNode *m_pSibling; + + int m_BudgetGroupID; + + int m_iClientData; + int m_iUniqueNodeID; +}; + +//----------------------------------------------------------------------------- +// +// Coordinator and root node of the profile hierarchy tree +// + +enum VProfReportType_t +{ + VPRT_SUMMARY = ( 1 << 0 ), + VPRT_HIERARCHY = ( 1 << 1 ), + VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY = ( 1 << 2 ), + VPRT_LIST_BY_TIME = ( 1 << 3 ), + VPRT_LIST_BY_TIME_LESS_CHILDREN = ( 1 << 4 ), + VPRT_LIST_BY_AVG_TIME = ( 1 << 5 ), + VPRT_LIST_BY_AVG_TIME_LESS_CHILDREN = ( 1 << 6 ), + VPRT_LIST_BY_PEAK_TIME = ( 1 << 7 ), + VPRT_LIST_BY_PEAK_OVER_AVERAGE = ( 1 << 8 ), + VPRT_LIST_TOP_ITEMS_ONLY = ( 1 << 9 ), + + VPRT_FULL = (0xffffffff & ~(VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY|VPRT_LIST_TOP_ITEMS_ONLY)), +}; + +enum CounterGroup_t +{ + COUNTER_GROUP_DEFAULT=0, + COUNTER_GROUP_NO_RESET, // The engine doesn't reset these counters. Usually, they are used + // like global variables that can be accessed across modules. + COUNTER_GROUP_TEXTURE_GLOBAL, // Global texture usage counters (totals for what is currently in memory). + COUNTER_GROUP_TEXTURE_PER_FRAME, // Per-frame texture usage counters. + + COUNTER_GROUP_TELEMETRY, +}; + +class DBG_CLASS CVProfile +{ +public: + CVProfile(); + ~CVProfile(); + + void Term(); + + // + // Runtime operations + // + + void Start(); + void Stop(); + + void SetTargetThreadId( unsigned id ) { m_TargetThreadId = id; } + unsigned GetTargetThreadId() { return m_TargetThreadId; } + bool InTargetThread() { return ( m_TargetThreadId == ThreadGetCurrentId() ); } + +#ifdef _X360 + enum VXConsoleReportMode_t + { + VXCONSOLE_REPORT_TIME = 0, + VXCONSOLE_REPORT_L2CACHE_MISSES, + VXCONSOLE_REPORT_LOAD_HIT_STORE, + VXCONSOLE_REPORT_COUNT, + }; + + void VXProfileStart(); + void VXProfileUpdate(); + void VXEnableUpdateMode( int event, bool bEnable ); + void VXSendNodes( void ); + + void PMCDisableAllNodes(CVProfNode *pStartNode = NULL); ///< turn off l2 and lhs recording for everywhere + bool PMCEnableL2Upon(const tchar *pszNodeName, bool bRecursive = false); ///< enable l2 and lhs recording for one given node + bool PMCDisableL2Upon(const tchar *pszNodeName, bool bRecursive = false); ///< enable l2 and lhs recording for one given node + + void DumpEnabledPMCNodes( void ); + + void VXConsoleReportMode( VXConsoleReportMode_t mode ); + void VXConsoleReportScale( VXConsoleReportMode_t mode, float flScale ); + + // the CPU trace mode is actually a small state machine; it can be off, primed for + // single capture, primed for everything-in-a-frame capture, or currently in everything-in-a-frame + // capture. + enum CPUTraceState + { + kDisabled, + kFirstHitNode, // record from the first time we hit the node until that node ends + kAllNodesInFrame_WaitingForMark, // we're going to record all the times a node is hit in a frame, but are waiting for the frame to start + kAllNodesInFrame_Recording, // we're recording all hits on a node this frame. + + // Same as above, but going to record for > 1 frame + kAllNodesInFrame_WaitingForMarkMultiFrame, // we're going to record all the times a node is hit in a frame, but are waiting for the frame to start + kAllNodesInFrame_RecordingMultiFrame, + }; + + // Global switch to turn CPU tracing on or off at all. The idea is you set up a node first, + // then trigger tracing by throwing this to true. It'll reset back to false after the trace + // happens. + inline CPUTraceState GetCPUTraceMode(); + inline void SetCPUTraceEnabled( CPUTraceState enabled, bool bTraceCompleteEvent = false, int nNumFrames = -1 ); + inline void IncrementMultiTraceIndex(); // tick up the counter that gets appended to the multi-per-frame traces + inline unsigned int GetMultiTraceIndex(); // return the counter + void CPUTraceDisableAllNodes( CVProfNode *pStartNode = NULL ); // disable the cpu trace flag wherever it may be + CVProfNode *CPUTraceEnableForNode( const tchar *pszNodeName ); // enable cpu trace on this node only, disabling it wherever else it may be on. + CVProfNode *CPUTraceGetEnabledNode( CVProfNode *pStartNode = NULL ); // return the node enabled for CPU tracing, or NULL. + const char *GetCPUTraceFilename(); // get the filename the trace should write into. + const char *SetCPUTraceFilename( const char *filename ); // set the filename the trace should write into. (don't specify the extension; I'll do that.) + inline bool TraceCompleteEvent( void ); + +#ifdef _X360 + void LatchMultiFrame( int64 cycles ); + void SpewWorstMultiFrame(); +#endif + +#endif + + void EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted ); + void EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ); + void ExitScope(); + + void MarkFrame(); + void ResetPeaks(); + + void Pause(); + void Resume(); + void Reset(); + + bool IsEnabled() const; + int GetDetailLevel() const; + + bool AtRoot() const; + + // + // Queries + // + +#ifdef VPROF_VTUNE_GROUP +# define MAX_GROUP_STACK_DEPTH 1024 + + void EnableVTuneGroup( const tchar *pGroupName ) + { + m_nVTuneGroupID = BudgetGroupNameToBudgetGroupID( pGroupName ); + m_bVTuneGroupEnabled = true; + } + void DisableVTuneGroup( void ) + { + m_bVTuneGroupEnabled = false; + } + + inline void PushGroup( int nGroupID ); + inline void PopGroup( void ); +#endif + + int NumFramesSampled() { return m_nFrames; } + double GetPeakFrameTime(); + double GetTotalTimeSampled(); + double GetTimeLastFrame(); + + CVProfNode *GetRoot(); + CVProfNode *FindNode( CVProfNode *pStartNode, const tchar *pszNode ); + CVProfNode *GetCurrentNode(); + + typedef void ( __cdecl *StreamOut_t )( const char* pszFormat, ... ); + // Set the output function used for all vprof reports. Call this with NULL + // to set it to the default output function. + void SetOutputStream( StreamOut_t outputStream ); + void OutputReport( int type = VPRT_FULL, const tchar *pszStartNode = NULL, int budgetGroupID = -1 ); + + const tchar *GetBudgetGroupName( int budgetGroupID ); + int GetBudgetGroupFlags( int budgetGroupID ) const; // Returns a combination of BUDGETFLAG_ defines. + int GetNumBudgetGroups( void ); + void GetBudgetGroupColor( int budgetGroupID, int &r, int &g, int &b, int &a ); + int BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName ); + int BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName, int budgetFlagsToORIn ); + void RegisterNumBudgetGroupsChangedCallBack( void (*pCallBack)(void) ); + + int BudgetGroupNameToBudgetGroupIDNoCreate( const tchar *pBudgetGroupName ) { return FindBudgetGroupName( pBudgetGroupName ); } + + void HideBudgetGroup( int budgetGroupID, bool bHide = true ); + void HideBudgetGroup( const char *pszName, bool bHide = true ) { HideBudgetGroup( BudgetGroupNameToBudgetGroupID( pszName), bHide ); } + + int *FindOrCreateCounter( const tchar *pName, CounterGroup_t eCounterGroup=COUNTER_GROUP_DEFAULT ); + void ResetCounters( CounterGroup_t eCounterGroup ); + + int GetNumCounters( void ) const; + + const tchar *GetCounterName( int index ) const; + int GetCounterValue( int index ) const; + const tchar *GetCounterNameAndValue( int index, int &val ) const; + CounterGroup_t GetCounterGroup( int index ) const; + + // Performance monitoring events. + void PMEInitialized( bool bInit ) { m_bPMEInit = bInit; } + void PMEEnable( bool bEnable ) { m_bPMEEnabled = bEnable; } + +#ifndef _X360 + bool UsePME( void ) { return ( m_bPMEInit && m_bPMEEnabled ); } +#else + bool UsePME( void ) { return ( CPMCData::IsInitialized() && m_bPMEEnabled ); } +#endif + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + + void FreeNodes_R( CVProfNode *pNode ); + +#ifdef VPROF_VTUNE_GROUP + bool VTuneGroupEnabled() + { + return m_bVTuneGroupEnabled; + } + int VTuneGroupID() + { + return m_nVTuneGroupID; + } +#endif + + void SumTimes( const tchar *pszStartNode, int budgetGroupID ); + void SumTimes( CVProfNode *pNode, int budgetGroupID ); + void DumpNodes( CVProfNode *pNode, int indent, bool bAverageAndCountOnly ); + int FindBudgetGroupName( const tchar *pBudgetGroupName ); + int AddBudgetGroupName( const tchar *pBudgetGroupName, int budgetFlags ); + +#ifdef VPROF_VTUNE_GROUP + bool m_bVTuneGroupEnabled; + int m_nVTuneGroupID; + int m_GroupIDStack[MAX_GROUP_STACK_DEPTH]; + int m_GroupIDStackDepth; +#endif + int m_enabled; + bool m_fAtRoot; // tracked for efficiency of the "not profiling" case + CVProfNode *m_pCurNode; + CVProfNode m_Root; + int m_nFrames; + int m_ProfileDetailLevel; + int m_pausedEnabledDepth; + + class CBudgetGroup + { + public: + tchar *m_pName; + int m_BudgetFlags; + }; + + CBudgetGroup *m_pBudgetGroups; + int m_nBudgetGroupNamesAllocated; + int m_nBudgetGroupNames; + void (*m_pNumBudgetGroupsChangedCallBack)(void); + + // Performance monitoring events. + bool m_bPMEInit; + bool m_bPMEEnabled; + + int m_Counters[MAXCOUNTERS]; + char m_CounterGroups[MAXCOUNTERS]; // (These are CounterGroup_t's). + tchar *m_CounterNames[MAXCOUNTERS]; + int m_NumCounters; + +#ifdef _X360 + int m_UpdateMode; + CPUTraceState m_iCPUTraceEnabled; + int m_nFramesRemaining; + int m_nFrameCount; + int64 m_WorstCycles; + char m_WorstTraceFilename[128]; + char m_CPUTraceFilename[128]; + unsigned int m_iSuccessiveTraceIndex; + VXConsoleReportMode_t m_ReportMode; + float m_pReportScale[VXCONSOLE_REPORT_COUNT]; + bool m_bTraceCompleteEvent; +#endif + + unsigned m_TargetThreadId; + + StreamOut_t m_pOutputStream; +}; + +//------------------------------------- + +DBG_INTERFACE CVProfile g_VProfCurrentProfile; + + +//----------------------------------------------------------------------------- + +DBG_INTERFACE bool g_VProfSignalSpike; + +class CVProfSpikeDetector +{ +public: + CVProfSpikeDetector( float spike ) : + m_timeLast( GetTimeLast() ) + { + m_spike = spike; + m_Timer.Start(); + } + + ~CVProfSpikeDetector() + { + m_Timer.End(); + if ( Plat_FloatTime() - m_timeLast > 2.0 ) + { + m_timeLast = Plat_FloatTime(); + if ( m_Timer.GetDuration().GetMillisecondsF() > m_spike ) + { + g_VProfSignalSpike = true; + } + } + } + +private: + static float &GetTimeLast() { static float timeLast = 0; return timeLast; } + CFastTimer m_Timer; + float m_spike; + float &m_timeLast; +}; + + +// Macro to signal a local spike. Meant as temporary instrumentation, do not leave in code +#define VPROF_TEST_SPIKE( msec ) CVProfSpikeDetector UNIQUE_ID( msec ) + +//----------------------------------------------------------------------------- + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PushGroup( int nGroupID ) +{ + // There is always at least one item on the stack since we force + // the first element to be VPROF_BUDGETGROUP_OTHER_UNACCOUNTED. + Assert( m_GroupIDStackDepth > 0 ); + Assert( m_GroupIDStackDepth < MAX_GROUP_STACK_DEPTH ); + m_GroupIDStack[m_GroupIDStackDepth] = nGroupID; + m_GroupIDStackDepth++; + if( m_GroupIDStack[m_GroupIDStackDepth-2] != nGroupID && + VTuneGroupEnabled() && + nGroupID == VTuneGroupID() ) + { + vtune( true ); + } +} +#endif // VPROF_VTUNE_GROUP + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PopGroup( void ) +{ + m_GroupIDStackDepth--; + // There is always at least one item on the stack since we force + // the first element to be VPROF_BUDGETGROUP_OTHER_UNACCOUNTED. + Assert( m_GroupIDStackDepth > 0 ); + if( m_GroupIDStack[m_GroupIDStackDepth] != m_GroupIDStack[m_GroupIDStackDepth+1] && + VTuneGroupEnabled() && + m_GroupIDStack[m_GroupIDStackDepth+1] == VTuneGroupID() ) + { + vtune( false ); + } +} +#endif // VPROF_VTUNE_GROUP + +//----------------------------------------------------------------------------- + +class CVProfScope +{ +public: + CVProfScope( const tchar * pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ); + ~CVProfScope(); + +private: + bool m_bEnabled; +}; + +//----------------------------------------------------------------------------- +// +// CVProfNode, inline methods +// + +inline CVProfNode::CVProfNode( const tchar * pszName, int detailLevel, CVProfNode *pParent, const tchar *pBudgetGroupName, int budgetFlags ) + : m_pszName( pszName ), + m_nCurFrameCalls( 0 ), + m_nPrevFrameCalls( 0 ), + m_nRecursions( 0 ), + m_pParent( pParent ), + m_pChild( NULL ), + m_pSibling( NULL ), + m_iClientData( -1 ) +#ifdef _X360 + , m_iBitFlags( 0 ) +#endif +{ + m_iUniqueNodeID = s_iCurrentUniqueNodeID++; + + if ( m_iUniqueNodeID > 0 ) + { + m_BudgetGroupID = g_VProfCurrentProfile.BudgetGroupNameToBudgetGroupID( pBudgetGroupName, budgetFlags ); + } + else + { + m_BudgetGroupID = 0; // "m_Root" can't call BudgetGroupNameToBudgetGroupID because g_VProfCurrentProfile not yet initialized + } + + Reset(); + + if( m_pParent && ( m_BudgetGroupID == VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) ) + { + m_BudgetGroupID = m_pParent->GetBudgetGroupID(); + } +} + + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetParent() +{ + Assert( m_pParent ); + return m_pParent; +} + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetSibling() +{ + return m_pSibling; +} + +//------------------------------------- +// Hacky way to the previous sibling, only used from vprof panel at the moment, +// so it didn't seem like it was worth the memory waste to add the reverse +// link per node. + +inline CVProfNode *CVProfNode::GetPrevSibling() +{ + CVProfNode* p = GetParent(); + + if(!p) + return NULL; + + CVProfNode* s; + for( s = p->GetChild(); + s && ( s->GetSibling() != this ); + s = s->GetSibling() ) + ; + + return s; +} + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetChild() +{ + return m_pChild; +} + +//------------------------------------- + +inline const tchar *CVProfNode::GetName() +{ + Assert( m_pszName ); + return m_pszName; +} + +//------------------------------------- + +inline int CVProfNode::GetTotalCalls() +{ + return m_nTotalCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetTotalTime() +{ + return m_TotalTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline int CVProfNode::GetCurCalls() +{ + return m_nCurFrameCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetCurTime() +{ + return m_CurFrameTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline int CVProfNode::GetPrevCalls() +{ + return m_nPrevFrameCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetPrevTime() +{ + return m_PrevFrameTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline double CVProfNode::GetPeakTime() +{ + return m_PeakTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline double CVProfNode::GetTotalTimeLessChildren() +{ + double result = GetTotalTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetTotalTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +//------------------------------------- + +inline double CVProfNode::GetCurTimeLessChildren() +{ + double result = GetCurTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetCurTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +inline double CVProfNode::GetPrevTimeLessChildren() +{ + double result = GetPrevTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetPrevTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetPrevL2CacheMissLessChildren() +{ + int result = m_iPrevL2CacheMiss; + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->m_iPrevL2CacheMiss; + pChild = pChild->GetSibling(); + } + return result; +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetPrevLoadHitStoreLessChildren() +{ +#ifndef _X360 + return 0; +#else + int result = m_iPrevLoadHitStores; + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->m_iPrevLoadHitStores; + pChild = pChild->GetSibling(); + } + return result; +#endif +} + + +//----------------------------------------------------------------------------- +inline void CVProfNode::ClearPrevTime() +{ + m_PrevFrameTime.Init(); +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetL2CacheMisses( void ) +{ +#ifndef _X360 + return m_L2Cache.GetL2CacheMisses(); +#else + return m_iTotalL2CacheMiss; +#endif +} + +#ifdef _X360 +inline int CVProfNode::GetLoadHitStores( void ) +{ + return m_iTotalLoadHitStores; +} +#endif + +//----------------------------------------------------------------------------- +// +// CVProfile, inline methods +// + +//------------------------------------- + +inline bool CVProfile::IsEnabled() const +{ + return ( m_enabled != 0 ); +} + +//------------------------------------- + +inline int CVProfile::GetDetailLevel() const +{ + return m_ProfileDetailLevel; +} + + +//------------------------------------- + +inline bool CVProfile::AtRoot() const +{ + return m_fAtRoot; +} + +//------------------------------------- + +inline void CVProfile::Start() +{ + if ( ++m_enabled == 1 ) + { + m_Root.EnterScope(); +#ifdef _X360 + VXProfileStart(); + CPMCData::InitializeOnceProgramWide(); +#endif + } +} + +//------------------------------------- + +inline void CVProfile::Stop() +{ + if ( --m_enabled == 0 ) + m_Root.ExitScope(); +} + +//------------------------------------- + +inline void CVProfile::EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ) +{ + if ( ( m_enabled != 0 || !m_fAtRoot ) && InTargetThread() ) // if became disabled, need to unwind back to root before stopping + { + // Only account for vprof stuff on the primary thread. + //if( !Plat_IsPrimaryThread() ) + // return; + + if ( pszName != m_pCurNode->GetName() ) + { + m_pCurNode = m_pCurNode->GetSubNode( pszName, detailLevel, pBudgetGroupName, budgetFlags ); + } + m_pBudgetGroups[m_pCurNode->GetBudgetGroupID()].m_BudgetFlags |= budgetFlags; + +#if defined( _DEBUG ) && !defined( _X360 ) + // 360 doesn't want this to allow tier0 debug/release .def files to match + if ( bAssertAccounted ) + { + // FIXME + AssertOnce( m_pCurNode->GetBudgetGroupID() != 0 ); + } +#endif + m_pCurNode->EnterScope(); + m_fAtRoot = false; + } +#if defined(_X360) && defined(VPROF_PIX) + if ( m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) + PIXBeginNamedEvent( 0, pszName ); +#endif +} + +inline void CVProfile::EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted ) +{ + EnterScope( pszName, detailLevel, pBudgetGroupName, bAssertAccounted, BUDGETFLAG_OTHER ); +} + +//------------------------------------- + +inline void CVProfile::ExitScope() +{ +#if defined(_X360) && defined(VPROF_PIX) +#ifdef PIXBeginNamedEvent +#error +#endif + if ( m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) + PIXEndNamedEvent(); +#endif + if ( ( !m_fAtRoot || m_enabled != 0 ) && InTargetThread() ) + { + // Only account for vprof stuff on the primary thread. + //if( !Plat_IsPrimaryThread() ) + // return; + + // ExitScope will indicate whether we should back up to our parent (we may + // be profiling a recursive function) + if (m_pCurNode->ExitScope()) + { + m_pCurNode = m_pCurNode->GetParent(); + } + m_fAtRoot = ( m_pCurNode == &m_Root ); + } +} + +//------------------------------------- + +inline void CVProfile::Pause() +{ + m_pausedEnabledDepth = m_enabled; + m_enabled = 0; + if ( !AtRoot() ) + m_Root.Pause(); +} + +//------------------------------------- + +inline void CVProfile::Resume() +{ + m_enabled = m_pausedEnabledDepth; + if ( !AtRoot() ) + m_Root.Resume(); +} + +//------------------------------------- + +inline void CVProfile::Reset() +{ + m_Root.Reset(); + m_nFrames = 0; +} + +//------------------------------------- + +inline void CVProfile::ResetPeaks() +{ + m_Root.ResetPeak(); +} + +//------------------------------------- + +inline void CVProfile::MarkFrame() +{ + if ( m_enabled ) + { + ++m_nFrames; + m_Root.ExitScope(); + m_Root.MarkFrame(); + m_Root.EnterScope(); + +#ifdef _X360 + // update the CPU trace state machine if enabled + switch ( GetCPUTraceMode() ) + { + case kAllNodesInFrame_WaitingForMark: + // mark! Start recording a zillion traces. + m_iCPUTraceEnabled = kAllNodesInFrame_Recording; + break; + case kAllNodesInFrame_WaitingForMarkMultiFrame: + m_iCPUTraceEnabled = kAllNodesInFrame_RecordingMultiFrame; + break; + case kAllNodesInFrame_Recording: + // end of frame. stop recording if no more frames needed + m_iCPUTraceEnabled = kDisabled; + Msg("Frame ended. Recording no more CPU traces\n"); + + break; + case kAllNodesInFrame_RecordingMultiFrame: + // end of frame. stop recording if no more frames needed + if ( --m_nFramesRemaining == 0 ) + { + m_iCPUTraceEnabled = kDisabled; + Msg("Frames ended. Recording no more CPU traces\n"); + + SpewWorstMultiFrame(); + } + + ++m_nFrameCount; + + break; + default: + // no default + break; + } +#endif + } +} + +//------------------------------------- + +inline double CVProfile::GetTotalTimeSampled() +{ + return m_Root.GetTotalTime(); +} + +//------------------------------------- + +inline double CVProfile::GetPeakFrameTime() +{ + return m_Root.GetPeakTime(); +} + +//------------------------------------- + +inline double CVProfile::GetTimeLastFrame() +{ + return m_Root.GetCurTime(); +} + +//------------------------------------- + +inline CVProfNode *CVProfile::GetRoot() +{ + return &m_Root; +} + +//------------------------------------- + +inline CVProfNode *CVProfile::GetCurrentNode() +{ + return m_pCurNode; +} + + +inline const tchar *CVProfile::GetBudgetGroupName( int budgetGroupID ) +{ + Assert( budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames ); + return m_pBudgetGroups[budgetGroupID].m_pName; +} + +inline int CVProfile::GetBudgetGroupFlags( int budgetGroupID ) const +{ + Assert( budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames ); + return m_pBudgetGroups[budgetGroupID].m_BudgetFlags; +} + +#ifdef _X360 + +inline CVProfile::CPUTraceState CVProfile::GetCPUTraceMode() +{ + return m_iCPUTraceEnabled; +} + +inline void CVProfile::SetCPUTraceEnabled( CPUTraceState enabled, bool bTraceCompleteEvent /*=true*/, int nNumFrames /*= -1*/ ) +{ + m_iCPUTraceEnabled = enabled; + m_bTraceCompleteEvent = bTraceCompleteEvent; + if ( nNumFrames != -1 ) + { + m_nFramesRemaining = nNumFrames; + m_nFrameCount = 0; + m_WorstCycles = 0; + m_WorstTraceFilename[ 0 ] = 0; + } +} + +inline void CVProfile::IncrementMultiTraceIndex() +{ + ++m_iSuccessiveTraceIndex; +} + +inline unsigned int CVProfile::GetMultiTraceIndex() +{ + return m_iSuccessiveTraceIndex; +} + +#endif + + +//----------------------------------------------------------------------------- + +inline CVProfScope::CVProfScope( const tchar * pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ) + : m_bEnabled( g_VProfCurrentProfile.IsEnabled() ) +{ + if ( m_bEnabled ) + { + g_VProfCurrentProfile.EnterScope( pszName, detailLevel, pBudgetGroupName, bAssertAccounted, budgetFlags ); + } +} + +//------------------------------------- + +inline CVProfScope::~CVProfScope() +{ + if ( m_bEnabled ) + { + g_VProfCurrentProfile.ExitScope(); + } +} + +class CVProfCounter +{ +public: + CVProfCounter( const tchar *pName, CounterGroup_t group=COUNTER_GROUP_DEFAULT ) + { + m_pCounter = g_VProfCurrentProfile.FindOrCreateCounter( pName, group ); + Assert( m_pCounter ); + } + ~CVProfCounter() + { + } + void Increment( int val ) + { + Assert( m_pCounter ); + *m_pCounter += val; + } +private: + int *m_pCounter; +}; + +#endif + +#ifdef _X360 + +#include "xbox/xbox_console.h" +#include "tracerecording.h" +#include "tier1/fmtstr.h" +#pragma comment( lib, "tracerecording.lib" ) +#pragma comment( lib, "xbdm.lib" ) + +class CPIXRecorder +{ +public: + CPIXRecorder() : m_bActive( false ) {} + ~CPIXRecorder() { Stop(); } + + void Start( const char *pszFilename = "capture" ) + { + if ( !m_bActive ) + { + if ( !XTraceStartRecording( CFmtStr( "e:\\%s.pix2", pszFilename ) ) ) + { + Msg( "XTraceStartRecording failed, error code %d\n", GetLastError() ); + } + else + { + m_bActive = true; + } + } + } + + void Stop() + { + if ( m_bActive ) + { + m_bActive = false; + if ( XTraceStopRecording() ) + { + Msg( "CPU trace finished.\n" ); + // signal VXConsole that trace is completed + XBX_rTraceComplete(); + } + } + } + +private: + bool m_bActive; +}; + +#define VPROF_BEGIN_PIX_BLOCK( convar ) \ + { \ + bool bRunPix = 0; \ + static CFastTimer PIXTimer; \ + extern ConVar convar; \ + ConVar &PIXConvar = convar; \ + CPIXRecorder PIXRecorder; \ + { \ + PIXLabel: \ + if ( bRunPix ) \ + { \ + PIXRecorder.Start(); \ + } \ + else \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.Start(); \ + } \ + } \ + { + + +#define VPROF_END_PIX_BLOCK() \ + } \ + \ + if ( !bRunPix ) \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.End(); \ + if ( PIXTimer.GetDuration().GetMillisecondsF() > PIXConvar.GetFloat() ) \ + { \ + PIXConvar.SetValue( 0 ); \ + bRunPix = true; \ + goto PIXLabel; \ + } \ + } \ + } \ + else \ + { \ + PIXRecorder.Stop(); \ + } \ + } \ + } +#else +#define VPROF_BEGIN_PIX_BLOCK( PIXConvar ) { +#define VPROF_END_PIX_BLOCK() } +#endif + + +#ifdef VPROF_UNDO_PIX +#undef USE_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#include +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif + +//============================================================================= diff --git a/public/tier0/vprof_telemetry.h b/public/tier0/vprof_telemetry.h new file mode 100644 index 0000000..c60bde5 --- /dev/null +++ b/public/tier0/vprof_telemetry.h @@ -0,0 +1,148 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Real-Time Hierarchical Telemetry Profiling +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPROF_TELEMETRY_H +#define VPROF_TELEMETRY_H + +#if !defined( MAKE_VPC ) + +#if !defined( RAD_TELEMETRY_DISABLED ) && ( defined( IS_WINDOWS_PC ) || defined( _LINUX ) ) +// Rad Telemetry profiling is enabled on Win32 and Win64. +#define RAD_TELEMETRY_ENABLED +#endif + +#endif // !MAKE_VPC + + +#if !defined( RAD_TELEMETRY_ENABLED ) + +// +// Kill all tmZone() macros, etc. +// +#include "tmapi_dummy.h" + +inline void TelemetryTick() {} +inline void TelemetrySetLevel( unsigned int Level ) {} +#define TelemetrySetLockName( _ctx, _location, _description ) + +class CTelemetryLock +{ +public: + CTelemetryLock(void *plocation, const char *description) {} + ~CTelemetryLock() {} + void Locked() {} + void Unlocked() {} +}; + +class CTelemetrySpikeDetector +{ +public: + CTelemetrySpikeDetector( const char *msg, uint32 threshold = 50 ) {} + ~CTelemetrySpikeDetector() { } +}; + +#else + +// +// Telemetry is enabled. Include the telemetry header. +// +#include "../../thirdparty/telemetry/include/telemetry.h" +// Different versions of radbase.h define RADCOPYRIGHT to different values. So undef that here. +#undef RADCOPYRIGHT + +struct TelemetryData +{ + HTELEMETRY tmContext[32]; + float flRDTSCToMilliSeconds; // Conversion from tmFastTime() (rdtsc) to milliseconds. + uint32 FrameCount; // Count of frames to capture before turning off. + char ServerAddress[128]; // Server name to connect to. + int playbacktick; // GetPlaybackTick() value from demo file (or 0 if not playing a demo). + uint32 DemoTickStart; // Start telemetry on demo tick # + uint32 DemoTickEnd; // End telemetry on demo tick # + uint32 Level; // Current Telemetry level (Use TelemetrySetLevel to modify) +}; +PLATFORM_INTERFACE TelemetryData g_Telemetry; + +PLATFORM_INTERFACE void TelemetryTick(); +PLATFORM_INTERFACE void TelemetrySetLevel( unsigned int Level ); + +#define TELEMETRY_LEVEL0 g_Telemetry.tmContext[0] // high level tmZone() +#define TELEMETRY_LEVEL1 g_Telemetry.tmContext[1] // lower level tmZone(), tmZoneFiltered() +#define TELEMETRY_LEVEL2 g_Telemetry.tmContext[2] // VPROF_0 +#define TELEMETRY_LEVEL3 g_Telemetry.tmContext[3] // VPROF_1 +#define TELEMETRY_LEVEL4 g_Telemetry.tmContext[4] // VPROF_2 +#define TELEMETRY_LEVEL5 g_Telemetry.tmContext[5] // VPROF_3 +#define TELEMETRY_LEVEL6 g_Telemetry.tmContext[6] // VPROF_4 + +#define TelemetrySetLockName( _ctx, _location, _description ) \ + do \ + { \ + static bool s_bNameSet = false; \ + if( _ctx && !s_bNameSet ) \ + { \ + tmLockName( _ctx, _location, _description ); \ + s_bNameSet = true; \ + } \ + } while( 0 ) + +class CTelemetryLock +{ +public: + CTelemetryLock(void *plocation, const char *description) + { + m_plocation = (const char *)plocation; + m_description = description; + TelemetrySetLockName( TELEMETRY_LEVEL1, m_plocation, m_description ); + tmTryLock( TELEMETRY_LEVEL1, m_plocation, "%s", m_description ); + } + ~CTelemetryLock() + { + Unlocked(); + } + void Locked() + { + tmEndTryLock( TELEMETRY_LEVEL1, m_plocation, TMLR_SUCCESS ); + tmSetLockState( TELEMETRY_LEVEL1, m_plocation, TMLS_LOCKED, "%s Locked", m_description ); + } + void Unlocked() + { + if( m_plocation ) + { + tmSetLockState( TELEMETRY_LEVEL1, m_plocation, TMLS_RELEASED, "%s Released", m_description ); + m_plocation = NULL; + } + } + +public: + const char *m_plocation; + const char *m_description; +}; + +class CTelemetrySpikeDetector +{ +public: + // Spews Telemetry message when threshold hit (in milliseconds.) + CTelemetrySpikeDetector( const char *msg, float threshold = 5 ) : + m_message( msg ), m_threshold( threshold ), time0( tmFastTime() ) {} + ~CTelemetrySpikeDetector() + { + float time = ( tmFastTime() - time0 ) * g_Telemetry.flRDTSCToMilliSeconds; + if( time >= m_threshold ) + { + tmMessage( TELEMETRY_LEVEL0, TMMF_ICON_NOTE | TMMF_SEVERITY_WARNING, "(source/spike)%s %.2fms %t", m_message, time, tmSendCallStack( TELEMETRY_LEVEL0, 0 ) ); + } + } + +private: + TmU64 time0; + float m_threshold; + const char *m_message; +}; + +#endif // RAD_TELEMETRY_ENABLED + +#endif // VPROF_TELEMETRY_H diff --git a/public/tier0/wchartypes.h b/public/tier0/wchartypes.h new file mode 100644 index 0000000..814470f --- /dev/null +++ b/public/tier0/wchartypes.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: All of our code is completely Unicode. Instead of char, you should +// use wchar, uint8, or char8, as explained below. +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef WCHARTYPES_H +#define WCHARTYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _INC_TCHAR +#error ("Must include tier0 type headers before tchar.h") +#endif + +// Temporarily turn off Valve defines +#include "tier0/valve_off.h" + +#if !defined(_WCHAR_T_DEFINED) && !defined(GNUC) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +// char8 +// char8 is equivalent to char, and should be used when you really need a char +// (for example, when calling an external function that's declared to take +// chars). +typedef char char8; + +// uint8 +// uint8 is equivalent to byte (but is preferred over byte for clarity). Use this +// whenever you mean a byte (for example, one byte of a network packet). +typedef unsigned char uint8; +typedef unsigned char BYTE; +typedef unsigned char byte; + +// wchar +// wchar is a single character of text (currently 16 bits, as all of our text is +// Unicode). Use this whenever you mean a piece of text (for example, in a string). +typedef wchar_t wchar; +//typedef char wchar; + +// __WFILE__ +// This is a Unicode version of __FILE__ +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) +#define __WFILE__ WIDEN(__FILE__) + +#ifdef STEAM +#ifndef _UNICODE +#define FORCED_UNICODE +#endif +#define _UNICODE +#endif + +#ifdef _WIN32 +#include +#else +#define _tcsstr strstr +#define _tcsicmp stricmp +#define _tcscmp strcmp +#define _tcscpy strcpy +#define _tcsncpy strncpy +#define _tcsrchr strrchr +#define _tcslen strlen +#define _tfopen fopen +#define _stprintf sprintf +#define _ftprintf fprintf +#define _vsntprintf _vsnprintf +#define _tprintf printf +#define _sntprintf _snprintf +#define _T(s) s +#endif + +#if defined(_UNICODE) +typedef wchar tchar; +#define tstring wstring +#define __TFILE__ __WFILE__ +#define TCHAR_IS_WCHAR +#else +typedef char tchar; +#define tstring string +#define __TFILE__ __FILE__ +#define TCHAR_IS_CHAR +#endif + +#if defined( _MSC_VER ) || defined( WIN32 ) +typedef wchar_t uchar16; +typedef unsigned int uchar32; +#else +typedef unsigned short uchar16; +typedef wchar_t uchar32; +#endif + +#ifdef FORCED_UNICODE +#undef _UNICODE +#endif + +// Turn valve defines back on +#include "tier0/valve_on.h" + + +#endif // WCHARTYPES + + diff --git a/public/tier0/xbox_codeline_defines.h b/public/tier0/xbox_codeline_defines.h new file mode 100644 index 0000000..2e3b2c5 --- /dev/null +++ b/public/tier0/xbox_codeline_defines.h @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef XBOX_CODELINE_DEFINES_H +#define XBOX_CODELINE_DEFINES_H + + +// In the regular src_main codeline, we leave this out. +//#define IN_XBOX_CODELINE + + +#endif // XBOX_CODELINE_DEFINES_H diff --git a/public/tier1/CommandBuffer.h b/public/tier1/CommandBuffer.h new file mode 100644 index 0000000..d9bfd7d --- /dev/null +++ b/public/tier1/CommandBuffer.h @@ -0,0 +1,167 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + + +#ifndef COMMANDBUFFER_H +#define COMMANDBUFFER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utllinkedlist.h" +#include "tier1/convar.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; + + +//----------------------------------------------------------------------------- +// Invalid command handle +//----------------------------------------------------------------------------- +typedef int CommandHandle_t; +enum +{ + COMMAND_BUFFER_INVALID_COMMAND_HANDLE = 0 +}; + + +//----------------------------------------------------------------------------- +// A command buffer class- a queue of argc/argv based commands associated +// with a particular time +//----------------------------------------------------------------------------- +class CCommandBuffer +{ +public: + // Constructor, destructor + CCommandBuffer( ); + ~CCommandBuffer(); + + // Inserts text into the command buffer + bool AddText( const char *pText, int nTickDelay = 0 ); + + // Used to iterate over all commands appropriate for the current time + void BeginProcessingCommands( int nDeltaTicks ); + bool DequeueNextCommand( ); + int DequeueNextCommand( const char **& ppArgv ); + int ArgC() const; + const char **ArgV() const; + const char *ArgS() const; // All args that occur after the 0th arg, in string form + const char *GetCommandString() const; // The entire command in string form, including the 0th arg + const CCommand& GetCommand() const; + void EndProcessingCommands(); + + // Are we in the middle of processing commands? + bool IsProcessingCommands(); + + // Delays all queued commands to execute at a later time + void DelayAllQueuedCommands( int nTickDelay ); + + // Indicates how long to delay when encoutering a 'wait' command + void SetWaitDelayTime( int nTickDelay ); + + // Returns a handle to the next command to process + // (useful when inserting commands into the buffer during processing + // of commands to force immediate execution of those commands, + // most relevantly, to implement a feature where you stream a file + // worth of commands into the buffer, where the file size is too large + // to entirely contain in the buffer). + CommandHandle_t GetNextCommandHandle(); + + // Specifies a max limit of the args buffer. For unittesting. Size == 0 means use default + void LimitArgumentBufferSize( int nSize ); + + void SetWaitEnabled( bool bEnable ) { m_bWaitEnabled = bEnable; } + bool IsWaitEnabled( void ) { return m_bWaitEnabled; } + + int GetArgumentBufferSize() { return m_nArgSBufferSize; } + int GetMaxArgumentBufferSize() { return m_nMaxArgSBufferLength; } + +private: + enum + { + ARGS_BUFFER_LENGTH = 8192, + }; + + struct Command_t + { + int m_nTick; + int m_nFirstArgS; + int m_nBufferSize; + }; + + // Insert a command into the command queue at the appropriate time + void InsertCommandAtAppropriateTime( int hCommand ); + + // Insert a command into the command queue + // Only happens if it's inserted while processing other commands + void InsertImmediateCommand( int hCommand ); + + // Insert a command into the command queue + bool InsertCommand( const char *pArgS, int nCommandSize, int nTick ); + + // Returns the length of the next command, as well as the offset to the next command + void GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset ); + + // Compacts the command buffer + void Compact(); + + // Parses argv0 out of the buffer + bool ParseArgV0( CUtlBuffer &buf, char *pArgv0, int nMaxLen, const char **pArgs ); + + char m_pArgSBuffer[ ARGS_BUFFER_LENGTH ]; + int m_nLastUsedArgSSize; + int m_nArgSBufferSize; + CUtlFixedLinkedList< Command_t > m_Commands; + int m_nCurrentTick; + int m_nLastTickToProcess; + int m_nWaitDelayTicks; + int m_hNextCommand; + int m_nMaxArgSBufferLength; + bool m_bIsProcessingCommands; + bool m_bWaitEnabled; + + // NOTE: This is here to avoid the pointers returned by DequeueNextCommand + // to become invalid by calling AddText. Is there a way we can avoid the memcpy? + CCommand m_CurrentCommand; +}; + + +//----------------------------------------------------------------------------- +// Returns the next command +//----------------------------------------------------------------------------- +inline int CCommandBuffer::ArgC() const +{ + return m_CurrentCommand.ArgC(); +} + +inline const char **CCommandBuffer::ArgV() const +{ + return m_CurrentCommand.ArgV(); +} + +inline const char *CCommandBuffer::ArgS() const +{ + return m_CurrentCommand.ArgS(); +} + +inline const char *CCommandBuffer::GetCommandString() const +{ + return m_CurrentCommand.GetCommandString(); +} + +inline const CCommand& CCommandBuffer::GetCommand() const +{ + return m_CurrentCommand; +} + +#endif // COMMANDBUFFER_H diff --git a/public/tier1/KeyValues.h b/public/tier1/KeyValues.h new file mode 100644 index 0000000..97ae69c --- /dev/null +++ b/public/tier1/KeyValues.h @@ -0,0 +1,485 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef KEYVALUES_H +#define KEYVALUES_H + +#ifdef _WIN32 +#pragma once +#endif + +// #include + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#include "utlvector.h" +#include "Color.h" + +#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() ) + +#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() ) + +#define FOR_EACH_VALUE( kvRoot, kvValue ) \ + for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() ) + +class IBaseFileSystem; +class CUtlBuffer; +class Color; +typedef void * FileHandle_t; +class CKeyValuesGrowableStringTable; + +//----------------------------------------------------------------------------- +// Purpose: Simple recursive data access class +// Used in vgui for message parameters and resource files +// Destructor deletes all child KeyValues nodes +// Data is stored in key (string names) - (string/int/float)value pairs called nodes. +// +// About KeyValues Text File Format: + +// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or +// not. The quote '"' character must not be used within name or values, only for +// quoting whole tokens. You may use escape sequences wile parsing and add within a +// quoted token a \" to add quotes within your name or token. When using Escape +// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ), +// which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'. +// So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens. +// An open bracket '{' after a key name indicates a list of subkeys which is finished +// with a closing bracket '}'. Subkeys use the same definitions recursively. +// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences +// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes +// (eg #include), don't use it as first character in key names. +//----------------------------------------------------------------------------- +class KeyValues +{ +public: + // By default, the KeyValues class uses a string table for the key names that is + // limited to 4MB. The game will exit in error if this space is exhausted. In + // general this is preferable for game code for performance and memory fragmentation + // reasons. + // + // If this is not acceptable, you can use this call to switch to a table that can grow + // arbitrarily. This call must be made before any KeyValues objects are allocated or it + // will result in undefined behavior. If you use the growable string table, you cannot + // share KeyValues pointers directly with any other module. You can serialize them across + // module boundaries. These limitations are acceptable in the Steam backend code + // this option was written for, but may not be in other situations. Make sure to + // understand the implications before using this. + static void SetUseGrowableStringTable( bool bUseGrowableTable ); + + KeyValues( const char *setName ); + + // + // AutoDelete class to automatically free the keyvalues. + // Simply construct it with the keyvalues you allocated and it will free them when falls out of scope. + // When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it. + // If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues). + // You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDelete + // instance: call_my_function( KeyValues::AutoDelete( new KeyValues( "test" ) ) ) + // + class AutoDelete + { + public: + explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {} + explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {} + inline ~AutoDelete( void ) { if( m_pKeyValues ) m_pKeyValues->deleteThis(); } + inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; } + KeyValues *operator->() { return m_pKeyValues; } + operator KeyValues *() { return m_pKeyValues; } + private: + AutoDelete( AutoDelete const &x ); // forbid + AutoDelete & operator= ( AutoDelete const &x ); // forbid + KeyValues *m_pKeyValues; + }; + + // Quick setup constructors + KeyValues( const char *setName, const char *firstKey, const char *firstValue ); + KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue ); + KeyValues( const char *setName, const char *firstKey, int firstValue ); + KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue ); + KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue ); + + // Section name + const char *GetName() const; + void SetName( const char *setName); + + // gets the name as a unique int + int GetNameSymbol() const { return m_iKeyName; } + + // File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t) + void UsesEscapeSequences(bool state); // default false + void UsesConditionals(bool state); // default true + bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool refreshCache = false ); + bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool sortKeys = false, bool bAllowEmptyString = false, bool bCacheResult = false ); + + // Read from a buffer... Note that the buffer must be null terminated + bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL ); + + // Read from a utlbuffer... + bool LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL ); + + // Find a keyValue, create it if it is not found. + // Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned) + KeyValues *FindKey(const char *keyName, bool bCreate = false); + KeyValues *FindKey(int keySymbol) const; + KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name + void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues + void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT + + // Key iteration. + // + // NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions + // below if you want to iterate over just the keys or just the values. + // + KeyValues *GetFirstSubKey() { return m_pSub; } // returns the first subkey in the list + KeyValues *GetNextKey() { return m_pPeer; } // returns the next subkey + const KeyValues *GetNextKey() const { return m_pPeer; } // returns the next subkey + + void SetNextKey( KeyValues * pDat); + KeyValues *FindLastSubKey(); // returns the LAST subkey in the list. This requires a linked list iteration to find the key. Returns NULL if we don't have any children + + // + // These functions can be used to treat it like a true key/values tree instead of + // confusing values with keys. + // + // So if you wanted to iterate all subkeys, then all values, it would look like this: + // for ( KeyValues *pKey = pRoot->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() ) + // { + // Msg( "Key name: %s\n", pKey->GetName() ); + // } + // for ( KeyValues *pValue = pRoot->GetFirstValue(); pKey; pKey = pKey->GetNextValue() ) + // { + // Msg( "Int value: %d\n", pValue->GetInt() ); // Assuming pValue->GetDataType() == TYPE_INT... + // } + KeyValues* GetFirstTrueSubKey(); + KeyValues* GetNextTrueSubKey(); + + KeyValues* GetFirstValue(); // When you get a value back, you can use GetX and pass in NULL to get the value. + KeyValues* GetNextValue(); + + + // Data access + int GetInt( const char *keyName = NULL, int defaultValue = 0 ); + uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 ); + float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f ); + const char *GetString( const char *keyName = NULL, const char *defaultValue = "" ); + const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" ); + void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 ); + bool GetBool( const char *keyName = NULL, bool defaultValue = false, bool* optGotDefault = NULL ); + Color GetColor( const char *keyName = NULL /* default value is all black */); + bool IsEmpty(const char *keyName = NULL); + + // Data access + int GetInt( int keySymbol, int defaultValue = 0 ); + float GetFloat( int keySymbol, float defaultValue = 0.0f ); + const char *GetString( int keySymbol, const char *defaultValue = "" ); + const wchar_t *GetWString( int keySymbol, const wchar_t *defaultValue = L"" ); + void *GetPtr( int keySymbol, void *defaultValue = (void*)0 ); + Color GetColor( int keySymbol /* default value is all black */); + bool IsEmpty( int keySymbol ); + + // Key writing + void SetWString( const char *keyName, const wchar_t *value ); + void SetString( const char *keyName, const char *value ); + void SetInt( const char *keyName, int value ); + void SetUint64( const char *keyName, uint64 value ); + void SetFloat( const char *keyName, float value ); + void SetPtr( const char *keyName, void *value ); + void SetColor( const char *keyName, Color value); + void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); } + + // Memory allocation (optimized) + void *operator new( size_t iAllocSize ); + void *operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine ); + void operator delete( void *pMem ); + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ); + + KeyValues& operator=( const KeyValues& src ); + + // Adds a chain... if we don't find stuff in this keyvalue, we'll look + // in the one we're chained to. + void ChainKeyValue( KeyValues* pChain ); + + void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel, bool sortKeys = false, bool bAllowEmptyString = false ); + + bool WriteAsBinary( CUtlBuffer &buffer ); + bool ReadAsBinary( CUtlBuffer &buffer, int nStackDepth = 0 ); + + // Allocate & create a new copy of the keys + KeyValues *MakeCopy( void ) const; + + // Allocate & create a new copy of the keys, including the next keys. This is useful for top level files + // that don't use the usual convention of a root key with lots of children (like soundscape files). + KeyValues *MakeCopy( bool copySiblings ) const; + + // Make a new copy of all subkeys, add them all to the passed-in keyvalues + void CopySubkeys( KeyValues *pParent ) const; + + // Clear out all subkeys, and the current value + void Clear( void ); + + // Data type + enum types_t + { + TYPE_NONE = 0, + TYPE_STRING, + TYPE_INT, + TYPE_FLOAT, + TYPE_PTR, + TYPE_WSTRING, + TYPE_COLOR, + TYPE_UINT64, + TYPE_NUMTYPES, + }; + types_t GetDataType(const char *keyName = NULL); + + // Virtual deletion function - ensures that KeyValues object is deleted from correct heap + void deleteThis(); + + void SetStringValue( char const *strValue ); + + // unpack a key values list into a structure + void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest, size_t DestSizeInBytes ); + + // Process conditional keys for widescreen support. + bool ProcessResolutionKeys( const char *pResString ); + + // Dump keyvalues recursively into a dump context + bool Dump( class IKeyValuesDumpContext *pDump, int nIndentLevel = 0 ); + + // Merge in another KeyValues, keeping "our" settings + void RecursiveMergeKeyValues( KeyValues *baseKV ); + +private: + KeyValues( KeyValues& ); // prevent copy constructor being used + + // prevent delete being called except through deleteThis() + ~KeyValues(); + + KeyValues* CreateKey( const char *keyName ); + + /// Create a child key, given that we know which child is currently the last child. + /// This avoids the O(N^2) behaviour when adding children in sequence to KV, + /// when CreateKey() wil have to re-locate the end of the list each time. This happens, + /// for example, every time we load any KV file whatsoever. + KeyValues* CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild ); + void AddSubkeyUsingKnownLastChild( KeyValues *pSubKey, KeyValues *pLastChild ); + + void CopyKeyValuesFromRecursive( const KeyValues& src ); + void CopyKeyValue( const KeyValues& src, size_t tmpBufferSizeB, char* tmpBuffer ); + + void RemoveEverything(); +// void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel ); +// void WriteConvertedString( CUtlBuffer &buffer, const char *pszString ); + + // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them. + // If filesystem is null, it'll ignore f. + void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString ); + void SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString ); + void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString ); + + void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf ); + + // For handling #include "filename" + void AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys ); + void ParseIncludedKeys( char const *resourceName, const char *filetoinclude, + IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys ); + + // For handling #base "filename" + void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys ); + + // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them. + // If filesystem is null, it'll ignore f. + void InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len ); + + void Init(); + const char * ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional ); + void WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel ); + + void FreeAllocatedValue(); + void AllocateValueBlock(int size); + + int m_iKeyName; // keyname is a symbol defined in KeyValuesSystem + + // These are needed out of the union because the API returns string pointers + char *m_sValue; + wchar_t *m_wsValue; + + // we don't delete these + union + { + int m_iValue; + float m_flValue; + void *m_pValue; + unsigned char m_Color[4]; + }; + + char m_iDataType; + char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false) + char m_bEvaluateConditionals; // true, if while parsing this KeyValue, conditionals blocks are evaluated (default true) + char unused[1]; + + KeyValues *m_pPeer; // pointer to next key in list + KeyValues *m_pSub; // pointer to Start of a new sub key list + KeyValues *m_pChain;// Search here if it's not in our list + +private: + // Statics to implement the optional growable string table + // Function pointers that will determine which mode we are in + static int (*s_pfGetSymbolForString)( const char *name, bool bCreate ); + static const char *(*s_pfGetStringForSymbol)( int symbol ); + static CKeyValuesGrowableStringTable *s_pGrowableStringTable; + +public: + // Functions that invoke the default behavior + static int GetSymbolForStringClassic( const char *name, bool bCreate = true ); + static const char *GetStringForSymbolClassic( int symbol ); + + // Functions that use the growable string table + static int GetSymbolForStringGrowable( const char *name, bool bCreate = true ); + static const char *GetStringForSymbolGrowable( int symbol ); + + // Functions to get external access to whichever of the above functions we're going to call. + static int CallGetSymbolForString( const char *name, bool bCreate = true ) { return s_pfGetSymbolForString( name, bCreate ); } + static const char *CallGetStringForSymbol( int symbol ) { return s_pfGetStringForSymbol( symbol ); } +}; + +typedef KeyValues::AutoDelete KeyValuesAD; + +enum KeyValuesUnpackDestinationTypes_t +{ + UNPACK_TYPE_FLOAT, // dest is a float + UNPACK_TYPE_VECTOR, // dest is a Vector + UNPACK_TYPE_VECTOR_COLOR, // dest is a vector, src is a color + UNPACK_TYPE_STRING, // dest is a char *. unpacker will allocate. + UNPACK_TYPE_INT, // dest is an int + UNPACK_TYPE_FOUR_FLOATS, // dest is an array of 4 floats. source is a string like "1 2 3 4" + UNPACK_TYPE_TWO_FLOATS, // dest is an array of 2 floats. source is a string like "1 2" +}; + +#define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 } +#define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz } +#define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 } + +struct KeyValuesUnpackStructure +{ + char const *m_pKeyName; // null to terminate tbl + char const *m_pKeyDefault; // null ok + KeyValuesUnpackDestinationTypes_t m_eDataType; // UNPACK_TYPE_INT, .. + size_t m_nFieldOffset; // use offsetof to set + size_t m_nFieldSize; // for strings or other variable length +}; + +//----------------------------------------------------------------------------- +// inline methods +//----------------------------------------------------------------------------- +inline int KeyValues::GetInt( int keySymbol, int defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline float KeyValues::GetFloat( int keySymbol, float defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetFloat( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline const char *KeyValues::GetString( int keySymbol, const char *defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetString( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline const wchar_t *KeyValues::GetWString( int keySymbol, const wchar_t *defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetWString( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline void *KeyValues::GetPtr( int keySymbol, void *defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetPtr( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline Color KeyValues::GetColor( int keySymbol ) +{ + Color defaultValue( 0, 0, 0, 0 ); + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetColor( ) : defaultValue; +} + +inline bool KeyValues::IsEmpty( int keySymbol ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->IsEmpty( ) : true; +} + +bool EvaluateConditional( const char *str ); + +class CUtlSortVectorKeyValuesByName +{ +public: + bool Less( const KeyValues* lhs, const KeyValues* rhs, void * ) + { + return Q_stricmp( lhs->GetName(), rhs->GetName() ) < 0; + } +}; + +// +// KeyValuesDumpContext and generic implementations +// + +class IKeyValuesDumpContext +{ +public: + virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0; + virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0; + virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0; +}; + +class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext +{ +public: + virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ); + virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ); + virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ); + +public: + virtual bool KvWriteIndent( int nIndentLevel ); + virtual bool KvWriteText( char const *szText ) = 0; +}; + +class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText +{ +public: + // Overrides developer level to dump in DevMsg, zero to dump as Msg + CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {} + +public: + virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ); + virtual bool KvWriteText( char const *szText ); + +protected: + int m_nDeveloperLevel; +}; + +inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 ) +{ + CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel ); + return pKeyValues->Dump( &ctx, nIndentLevel ); +} + +#endif // KEYVALUES_H diff --git a/public/tier1/UtlSortVector.h b/public/tier1/UtlSortVector.h new file mode 100644 index 0000000..02756f7 --- /dev/null +++ b/public/tier1/UtlSortVector.h @@ -0,0 +1,414 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// $Header: $ +// $NoKeywords: $ +// +// A growable array class that keeps all elements in order using binary search +//===========================================================================// + +#ifndef UTLSORTVECTOR_H +#define UTLSORTVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + + +//----------------------------------------------------------------------------- +// class CUtlSortVector: +// description: +// This in an sorted order-preserving vector. Items may be inserted or removed +// at any point in the vector. When an item is inserted, all elements are +// moved down by one element using memmove. When an item is removed, all +// elements are shifted back down. Items are searched for in the vector +// using a binary search technique. Clients must pass in a Less() function +// into the constructor of the vector to determine the sort order. +//----------------------------------------------------------------------------- + +#ifndef _WIN32 +// gcc has no qsort_s, so i need to use a static var to hold the sort context. this makes cutlsortvector _not_ thread sfae under linux +extern void *g_pUtlSortVectorQSortContext; +#endif + +template +class CUtlSortVectorDefaultLess +{ +public: + bool Less( const T& lhs, const T& rhs, void * ) + { + return lhs < rhs; + } +}; + +template , class BaseVector = CUtlVector > +class CUtlSortVector : public BaseVector +{ + typedef BaseVector BaseClass; +public: + /// constructor + CUtlSortVector( int nGrowSize = 0, int initSize = 0 ); + CUtlSortVector( T* pMemory, int numElements ); + + /// inserts (copy constructs) an element in sorted order into the list + int Insert( const T& src ); + + /// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list + int InsertIfNotFound( const T& src ); + + /// Finds an element within the list using a binary search. These are templatized based upon the key + /// in which case the less function must handle the Less function for key, T and T, key + template< typename TKey > + int Find( const TKey& search ) const; + template< typename TKey > + int FindLessOrEqual( const TKey& search ) const; + template< typename TKey > + int FindLess( const TKey& search ) const; + + /// Removes a particular element + void Remove( const T& search ); + void Remove( int i ); + + /// Allows methods to set a context to be used with the less function.. + void SetLessContext( void *pCtx ); + + /// A version of insertion that will produce an un-ordered list. + /// Note that you can only use this index until sorting is redone with RedoSort!!! + int InsertNoSort( const T& src ); + void RedoSort( bool bForceSort = false ); + + /// Use this to insert at a specific insertion point; using FindLessOrEqual + /// is required for use this this. This will test that what you've inserted + /// produces a correctly ordered list. + int InsertAfter( int nElemIndex, const T &src ); + + /// finds a particular element using a linear search. Useful when used + /// in between calls to InsertNoSort and RedoSort + template< typename TKey > + int FindUnsorted( const TKey &src ) const; + +protected: + // No copy constructor + CUtlSortVector( const CUtlSortVector & ); + + // never call these; illegal for this class + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + int InsertBefore( int elem, const T& src ); + int AddToHead( const T& src ); + int AddToTail( const T& src ); + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); + int InsertMultipleAfter( int elem, int num ); + int AddVectorToTail( CUtlVector const &src ); + + struct QSortContext_t + { + void *m_pLessContext; + LessFunc *m_pLessFunc; + }; + +#ifdef _WIN32 + static int CompareHelper( void *context, const T *lhs, const T *rhs ) + { + QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context ); + if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) ) + return -1; + if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) ) + return 1; + return 0; + } +#else + static int CompareHelper( const T *lhs, const T *rhs ) + { + QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext ); + if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) ) + return -1; + if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) ) + return 1; + return 0; + } +#endif + + void *m_pLessContext; + bool m_bNeedsSort; + +private: + template< typename TKey > + int FindLessOrEqual( const TKey& search, bool *pFound ) const; + + void QuickSort( LessFunc& less, int X, int I ); +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +template +CUtlSortVector::CUtlSortVector( int nGrowSize, int initSize ) : + m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false ) +{ +} + +template +CUtlSortVector::CUtlSortVector( T* pMemory, int numElements ) : + m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false ) +{ +} + +//----------------------------------------------------------------------------- +// Allows methods to set a context to be used with the less function.. +//----------------------------------------------------------------------------- +template +void CUtlSortVector::SetLessContext( void *pCtx ) +{ + m_pLessContext = pCtx; +} + +//----------------------------------------------------------------------------- +// grows the vector +//----------------------------------------------------------------------------- +template +int CUtlSortVector::Insert( const T& src ) +{ + AssertFatal( !m_bNeedsSort ); + + int pos = FindLessOrEqual( src ) + 1; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct( &this->Element(pos), src ); + return pos; +} + +template +int CUtlSortVector::InsertNoSort( const T& src ) +{ + m_bNeedsSort = true; + int lastElement = BaseVector::m_Size; + // Just stick the new element at the end of the vector, but don't do a sort + this->GrowVector(); + this->ShiftElementsRight(lastElement); + CopyConstruct( &this->Element(lastElement), src ); + return lastElement; +} + +/// inserts (copy constructs) an element in sorted order into the list if it isn't already in the list +template +int CUtlSortVector::InsertIfNotFound( const T& src ) +{ + AssertFatal( !m_bNeedsSort ); + bool bFound; + int pos = FindLessOrEqual( src, &bFound ); + if ( bFound ) + return pos; + + ++pos; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct( &this->Element(pos), src ); + return pos; +} + +template +int CUtlSortVector::InsertAfter( int nIndex, const T &src ) +{ + int nInsertedIndex = this->BaseClass::InsertAfter( nIndex, src ); + +#ifdef DEBUG + LessFunc less; + if ( nInsertedIndex > 0 ) + { + Assert( less.Less( this->Element(nInsertedIndex-1), src, m_pLessContext ) ); + } + if ( nInsertedIndex < BaseClass::Count()-1 ) + { + Assert( less.Less( src, this->Element(nInsertedIndex+1), m_pLessContext ) ); + } +#endif + return nInsertedIndex; +} + + +template +void CUtlSortVector::QuickSort( LessFunc& less, int nLower, int nUpper ) +{ +#ifdef _WIN32 + typedef int (__cdecl *QSortCompareFunc_t)(void *context, const void *, const void *); + if ( this->Count() > 1 ) + { + QSortContext_t ctx; + ctx.m_pLessContext = m_pLessContext; + ctx.m_pLessFunc = &less; + + qsort_s( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector::CompareHelper, &ctx ); + } +#else + typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *); + if ( this->Count() > 1 ) + { + QSortContext_t ctx; + ctx.m_pLessContext = m_pLessContext; + ctx.m_pLessFunc = &less; + g_pUtlSortVectorQSortContext = &ctx; + + qsort( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector::CompareHelper ); + } +#endif +} + +template +void CUtlSortVector::RedoSort( bool bForceSort /*= false */ ) +{ + if ( !m_bNeedsSort && !bForceSort ) + return; + + m_bNeedsSort = false; + LessFunc less; + QuickSort( less, 0, this->Count() - 1 ); +} + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template +template < typename TKey > +int CUtlSortVector::Find( const TKey& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else if ( less.Less( src, this->Element(mid), m_pLessContext ) ) + { + end = mid - 1; + } + else + { + return mid; + } + } + return -1; +} + + +//----------------------------------------------------------------------------- +// finds a particular element using a linear search. Useful when used +// in between calls to InsertNoSort and RedoSort +//----------------------------------------------------------------------------- +template< class T, class LessFunc, class BaseVector > +template < typename TKey > +int CUtlSortVector::FindUnsorted( const TKey &src ) const +{ + LessFunc less; + int nCount = this->Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( less.Less( this->Element(i), src, m_pLessContext ) ) + continue; + if ( less.Less( src, this->Element(i), m_pLessContext ) ) + continue; + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template +template < typename TKey > +int CUtlSortVector::FindLessOrEqual( const TKey& src, bool *pFound ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else if ( less.Less( src, this->Element(mid), m_pLessContext ) ) + { + end = mid - 1; + } + else + { + *pFound = true; + return mid; + } + } + + *pFound = false; + return end; +} + +template +template < typename TKey > +int CUtlSortVector::FindLessOrEqual( const TKey& src ) const +{ + bool bFound; + return FindLessOrEqual( src, &bFound ); +} + +template +template < typename TKey > +int CUtlSortVector::FindLess( const TKey& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else + { + end = mid - 1; + } + } + return end; +} + + +//----------------------------------------------------------------------------- +// Removes a particular element +//----------------------------------------------------------------------------- +template +void CUtlSortVector::Remove( const T& search ) +{ + AssertFatal( !m_bNeedsSort ); + + int pos = Find(search); + if (pos != -1) + { + BaseVector::Remove(pos); + } +} + +template +void CUtlSortVector::Remove( int i ) +{ + BaseVector::Remove( i ); +} + +#endif // UTLSORTVECTOR_H diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h new file mode 100644 index 0000000..59d5c23 --- /dev/null +++ b/public/tier1/UtlStringMap.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef UTLSTRINGMAP_H +#define UTLSTRINGMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlsymbol.h" + +template +class CUtlStringMap +{ +public: + CUtlStringMap( bool caseInsensitive = true ) : m_SymbolTable( 0, 32, caseInsensitive ) + { + } + + // Get data by the string itself: + T& operator[]( const char *pString ) + { + CUtlSymbol symbol = m_SymbolTable.AddString( pString ); + int index = ( int )( UtlSymId_t )symbol; + if( m_Vector.Count() <= index ) + { + m_Vector.EnsureCount( index + 1 ); + } + return m_Vector[index]; + } + + // Get data by the string's symbol table ID - only used to retrieve a pre-existing symbol, not create a new one! + T& operator[]( UtlSymId_t n ) + { + Assert( n >=0 && n <= m_Vector.Count() ); + return m_Vector[n]; + } + + const T& operator[]( UtlSymId_t n ) const + { + Assert( n >=0 && n <= m_Vector.Count() ); + return m_Vector[n]; + } + + bool Defined( const char *pString ) const + { + return m_SymbolTable.Find( pString ) != UTL_INVAL_SYMBOL; + } + + UtlSymId_t Find( const char *pString ) const + { + return m_SymbolTable.Find( pString ); + } + + static UtlSymId_t InvalidIndex() + { + return UTL_INVAL_SYMBOL; + } + + int GetNumStrings( void ) const + { + return m_SymbolTable.GetNumStrings(); + } + + const char *String( int n ) const + { + return m_SymbolTable.String( n ); + } + + // Clear all of the data from the map + void Clear() + { + m_Vector.RemoveAll(); + m_SymbolTable.RemoveAll(); + } + + void Purge() + { + m_Vector.Purge(); + m_SymbolTable.RemoveAll(); + } + + void PurgeAndDeleteElements() + { + m_Vector.PurgeAndDeleteElements(); + m_SymbolTable.RemoveAll(); + } + + + +private: + CUtlVector m_Vector; + CUtlSymbolTable m_SymbolTable; +}; + +#endif // UTLSTRINGMAP_H diff --git a/public/tier1/bitbuf.h b/public/tier1/bitbuf.h new file mode 100644 index 0000000..6ba3c1d --- /dev/null +++ b/public/tier1/bitbuf.h @@ -0,0 +1,812 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// NOTE: bf_read is guaranteed to return zeros if it overflows. + +#ifndef BITBUF_H +#define BITBUF_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/mathlib.h" +#include "mathlib/vector.h" +#include "basetypes.h" +#include "tier0/dbg.h" + + +#if _DEBUG +#define BITBUF_INLINE inline +#else +#define BITBUF_INLINE FORCEINLINE +#endif + +//----------------------------------------------------------------------------- +// Forward declarations. +//----------------------------------------------------------------------------- + +class Vector; +class QAngle; + +//----------------------------------------------------------------------------- +// You can define a handler function that will be called in case of +// out-of-range values and overruns here. +// +// NOTE: the handler is only called in debug mode. +// +// Call SetBitBufErrorHandler to install a handler. +//----------------------------------------------------------------------------- + +typedef enum +{ + BITBUFERROR_VALUE_OUT_OF_RANGE=0, // Tried to write a value with too few bits. + BITBUFERROR_BUFFER_OVERRUN, // Was about to overrun a buffer. + + BITBUFERROR_NUM_ERRORS +} BitBufErrorType; + + +typedef void (*BitBufErrorHandler)( BitBufErrorType errorType, const char *pDebugName ); + + +#if defined( _DEBUG ) + extern void InternalBitBufErrorHandler( BitBufErrorType errorType, const char *pDebugName ); + #define CallErrorHandler( errorType, pDebugName ) InternalBitBufErrorHandler( errorType, pDebugName ); +#else + #define CallErrorHandler( errorType, pDebugName ) +#endif + + +// Use this to install the error handler. Call with NULL to uninstall your error handler. +void SetBitBufErrorHandler( BitBufErrorHandler fn ); + + +//----------------------------------------------------------------------------- +// Helpers. +//----------------------------------------------------------------------------- + +inline int BitByte( int bits ) +{ + // return PAD_NUMBER( bits, 8 ) >> 3; + return (bits + 7) >> 3; +} + +//----------------------------------------------------------------------------- +// namespaced helpers +//----------------------------------------------------------------------------- +namespace bitbuf +{ + // ZigZag Transform: Encodes signed integers so that they can be + // effectively used with varint encoding. + // + // varint operates on unsigned integers, encoding smaller numbers into + // fewer bytes. If you try to use it on a signed integer, it will treat + // this number as a very large unsigned integer, which means that even + // small signed numbers like -1 will take the maximum number of bytes + // (10) to encode. ZigZagEncode() maps signed integers to unsigned + // in such a way that those with a small absolute value will have smaller + // encoded values, making them appropriate for encoding using varint. + // + // int32 -> uint32 + // ------------------------- + // 0 -> 0 + // -1 -> 1 + // 1 -> 2 + // -2 -> 3 + // ... -> ... + // 2147483647 -> 4294967294 + // -2147483648 -> 4294967295 + // + // >> encode >> + // << decode << + + inline uint32 ZigZagEncode32(int32 n) + { + // Note: the right-shift must be arithmetic + return(n << 1) ^ (n >> 31); + } + + inline int32 ZigZagDecode32(uint32 n) + { + return(n >> 1) ^ -static_cast(n & 1); + } + + inline uint64 ZigZagEncode64(int64 n) + { + // Note: the right-shift must be arithmetic + return(n << 1) ^ (n >> 63); + } + + inline int64 ZigZagDecode64(uint64 n) + { + return(n >> 1) ^ -static_cast(n & 1); + } + + const int kMaxVarintBytes = 10; + const int kMaxVarint32Bytes = 5; +} + +//----------------------------------------------------------------------------- +// Used for serialization +//----------------------------------------------------------------------------- + +class bf_write +{ +public: + bf_write(); + + // nMaxBits can be used as the number of bits in the buffer. + // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8. + bf_write( void *pData, int nBytes, int nMaxBits = -1 ); + bf_write( const char *pDebugName, void *pData, int nBytes, int nMaxBits = -1 ); + + // Start writing to the specified buffer. + // nMaxBits can be used as the number of bits in the buffer. + // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8. + void StartWriting( void *pData, int nBytes, int iStartBit = 0, int nMaxBits = -1 ); + + // Restart buffer writing. + void Reset(); + + // Get the base pointer. + unsigned char* GetBasePointer() { return (unsigned char*) m_pData; } + + // Enable or disable assertion on overflow. 99% of the time, it's a bug that we need to catch, + // but there may be the occasional buffer that is allowed to overflow gracefully. + void SetAssertOnOverflow( bool bAssert ); + + // This can be set to assign a name that gets output if the buffer overflows. + const char* GetDebugName(); + void SetDebugName( const char *pDebugName ); + + +// Seek to a specific position. +public: + + void SeekToBit( int bitPos ); + + +// Bit functions. +public: + + void WriteOneBit(int nValue); + void WriteOneBitNoCheck(int nValue); + void WriteOneBitAt( int iBit, int nValue ); + + // Write signed or unsigned. Range is only checked in debug. + void WriteUBitLong( unsigned int data, int numbits, bool bCheckRange=true ); + void WriteSBitLong( int data, int numbits ); + + // Tell it whether or not the data is unsigned. If it's signed, + // cast to unsigned before passing in (it will cast back inside). + void WriteBitLong(unsigned int data, int numbits, bool bSigned); + + // Write a list of bits in. + bool WriteBits(const void *pIn, int nBits); + + // writes an unsigned integer with variable bit length + void WriteUBitVar( unsigned int data ); + + // writes a varint encoded integer + void WriteVarInt32( uint32 data ); + void WriteVarInt64( uint64 data ); + void WriteSignedVarInt32( int32 data ); + void WriteSignedVarInt64( int64 data ); + int ByteSizeVarInt32( uint32 data ); + int ByteSizeVarInt64( uint64 data ); + int ByteSizeSignedVarInt32( int32 data ); + int ByteSizeSignedVarInt64( int64 data ); + + // Copy the bits straight out of pIn. This seeks pIn forward by nBits. + // Returns an error if this buffer or the read buffer overflows. + bool WriteBitsFromBuffer( class bf_read *pIn, int nBits ); + + void WriteBitAngle( float fAngle, int numbits ); + void WriteBitCoord (const float f); + void WriteBitCoordMP( const float f, bool bIntegral, bool bLowPrecision ); + void WriteBitFloat(float val); + void WriteBitVec3Coord( const Vector& fa ); + void WriteBitNormal( float f ); + void WriteBitVec3Normal( const Vector& fa ); + void WriteBitAngles( const QAngle& fa ); + + +// Byte functions. +public: + + void WriteChar(int val); + void WriteByte(int val); + void WriteShort(int val); + void WriteWord(int val); + void WriteLong(long val); + void WriteLongLong(int64 val); + void WriteFloat(float val); + bool WriteBytes( const void *pBuf, int nBytes ); + + // Returns false if it overflows the buffer. + bool WriteString(const char *pStr); + + +// Status. +public: + + // How many bytes are filled in? + int GetNumBytesWritten() const; + int GetNumBitsWritten() const; + int GetMaxNumBits(); + int GetNumBitsLeft(); + int GetNumBytesLeft(); + unsigned char* GetData(); + const unsigned char* GetData() const; + + // Has the buffer overflowed? + bool CheckForOverflow(int nBits); + inline bool IsOverflowed() const {return m_bOverflow;} + + void SetOverflowFlag(); + + +public: + // The current buffer. + unsigned long* RESTRICT m_pData; + int m_nDataBytes; + int m_nDataBits; + + // Where we are in the buffer. + int m_iCurBit; + +private: + + // Errors? + bool m_bOverflow; + + bool m_bAssertOnOverflow; + const char *m_pDebugName; +}; + + +//----------------------------------------------------------------------------- +// Inlined methods +//----------------------------------------------------------------------------- + +// How many bytes are filled in? +inline int bf_write::GetNumBytesWritten() const +{ + return BitByte(m_iCurBit); +} + +inline int bf_write::GetNumBitsWritten() const +{ + return m_iCurBit; +} + +inline int bf_write::GetMaxNumBits() +{ + return m_nDataBits; +} + +inline int bf_write::GetNumBitsLeft() +{ + return m_nDataBits - m_iCurBit; +} + +inline int bf_write::GetNumBytesLeft() +{ + return GetNumBitsLeft() >> 3; +} + +inline unsigned char* bf_write::GetData() +{ + return (unsigned char*) m_pData; +} + +inline const unsigned char* bf_write::GetData() const +{ + return (unsigned char*) m_pData; +} + +BITBUF_INLINE bool bf_write::CheckForOverflow(int nBits) +{ + if ( m_iCurBit + nBits > m_nDataBits ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + } + + return m_bOverflow; +} + +BITBUF_INLINE void bf_write::SetOverflowFlag() +{ +#ifdef DBGFLAG_ASSERT + if ( m_bAssertOnOverflow ) + { + Assert( false ); + } +#endif + m_bOverflow = true; +} + +BITBUF_INLINE void bf_write::WriteOneBitNoCheck(int nValue) +{ +#if __i386__ + if(nValue) + m_pData[m_iCurBit >> 5] |= 1u << (m_iCurBit & 31); + else + m_pData[m_iCurBit >> 5] &= ~(1u << (m_iCurBit & 31)); +#else + extern unsigned long g_LittleBits[32]; + if(nValue) + m_pData[m_iCurBit >> 5] |= g_LittleBits[m_iCurBit & 31]; + else + m_pData[m_iCurBit >> 5] &= ~g_LittleBits[m_iCurBit & 31]; +#endif + + ++m_iCurBit; +} + +inline void bf_write::WriteOneBit(int nValue) +{ + if( m_iCurBit >= m_nDataBits ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + return; + } + WriteOneBitNoCheck( nValue ); +} + + +inline void bf_write::WriteOneBitAt( int iBit, int nValue ) +{ + if( iBit >= m_nDataBits ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + return; + } + +#if __i386__ + if(nValue) + m_pData[iBit >> 5] |= 1u << (iBit & 31); + else + m_pData[iBit >> 5] &= ~(1u << (iBit & 31)); +#else + extern unsigned long g_LittleBits[32]; + if(nValue) + m_pData[iBit >> 5] |= g_LittleBits[iBit & 31]; + else + m_pData[iBit >> 5] &= ~g_LittleBits[iBit & 31]; +#endif +} + +#ifdef _DEBUG +BITBUF_INLINE void bf_write::WriteUBitLong( unsigned int curData, int numbits, bool bCheckRange ) RESTRICT +{ + // Make sure it doesn't overflow. + if ( bCheckRange && numbits < 32 ) + { + if ( curData >= (unsigned long)(1 << numbits) ) + { + CallErrorHandler( BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName() ); + } + } + Assert( numbits >= 0 && numbits <= 32 ); +#else +BITBUF_INLINE void bf_write::WriteUBitLong( unsigned int curData, int numbits, bool ) RESTRICT +{ +#endif + + if ( GetNumBitsLeft() < numbits ) + { + m_iCurBit = m_nDataBits; + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + return; + } + + int iCurBitMasked = m_iCurBit & 31; + int iDWord = m_iCurBit >> 5; + m_iCurBit += numbits; + + // Mask in a dword. + Assert( (iDWord*4 + sizeof(long)) <= (unsigned int)m_nDataBytes ); + unsigned long * RESTRICT pOut = &m_pData[iDWord]; + + // Rotate data into dword alignment + curData = (curData << iCurBitMasked) | (curData >> (32 - iCurBitMasked)); + + // Calculate bitmasks for first and second word + unsigned int temp = 1 << (numbits-1); + unsigned int mask1 = (temp*2-1) << iCurBitMasked; + unsigned int mask2 = (temp-1) >> (31 - iCurBitMasked); + + // Only look beyond current word if necessary (avoid access violation) + int i = mask2 & 1; + unsigned long dword1 = LoadLittleDWord( pOut, 0 ); + unsigned long dword2 = LoadLittleDWord( pOut, i ); + + // Drop bits into place + dword1 ^= ( mask1 & ( curData ^ dword1 ) ); + dword2 ^= ( mask2 & ( curData ^ dword2 ) ); + + // Note reversed order of writes so that dword1 wins if mask2 == 0 && i == 0 + StoreLittleDWord( pOut, i, dword2 ); + StoreLittleDWord( pOut, 0, dword1 ); +} + +// writes an unsigned integer with variable bit length +BITBUF_INLINE void bf_write::WriteUBitVar( unsigned int data ) +{ + /* Reference: + if ( data < 0x10u ) + WriteUBitLong( 0, 2 ), WriteUBitLong( data, 4 ); + else if ( data < 0x100u ) + WriteUBitLong( 1, 2 ), WriteUBitLong( data, 8 ); + else if ( data < 0x1000u ) + WriteUBitLong( 2, 2 ), WriteUBitLong( data, 12 ); + else + WriteUBitLong( 3, 2 ), WriteUBitLong( data, 32 ); + */ + // a < b ? -1 : 0 translates into a CMP, SBB instruction pair + // with no flow control. should also be branchless on consoles. + int n = (data < 0x10u ? -1 : 0) + (data < 0x100u ? -1 : 0) + (data < 0x1000u ? -1 : 0); + WriteUBitLong( data*4 + n + 3, 6 + n*4 + 12 ); + if ( data >= 0x1000u ) + { + WriteUBitLong( data >> 16, 16 ); + } +} + +// write raw IEEE float bits in little endian form +BITBUF_INLINE void bf_write::WriteBitFloat(float val) +{ + int intVal; + + //static_assert(sizeof(int) == sizeof(float)); + //static_assert(sizeof(float) == 4); + + intVal = *((int*)&val); + WriteUBitLong( intVal, 32 ); +} + +//----------------------------------------------------------------------------- +// This is useful if you just want a buffer to write into on the stack. +//----------------------------------------------------------------------------- + +template +class old_bf_write_static : public bf_write +{ +public: + inline old_bf_write_static() : bf_write(m_StaticData, SIZE) {} + + char m_StaticData[SIZE]; +}; + + + +//----------------------------------------------------------------------------- +// Used for unserialization +//----------------------------------------------------------------------------- + +class bf_read +{ +public: + bf_read(); + + // nMaxBits can be used as the number of bits in the buffer. + // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8. + bf_read( const void *pData, int nBytes, int nBits = -1 ); + bf_read( const char *pDebugName, const void *pData, int nBytes, int nBits = -1 ); + + // Start reading from the specified buffer. + // pData's start address must be dword-aligned. + // nMaxBits can be used as the number of bits in the buffer. + // It must be <= nBytes*8. If you leave it at -1, then it's set to nBytes * 8. + void StartReading( const void *pData, int nBytes, int iStartBit = 0, int nBits = -1 ); + + // Restart buffer reading. + void Reset(); + + // Enable or disable assertion on overflow. 99% of the time, it's a bug that we need to catch, + // but there may be the occasional buffer that is allowed to overflow gracefully. + void SetAssertOnOverflow( bool bAssert ); + + // This can be set to assign a name that gets output if the buffer overflows. + const char* GetDebugName() const { return m_pDebugName; } + void SetDebugName( const char *pName ); + + void ExciseBits( int startbit, int bitstoremove ); + + +// Bit functions. +public: + + // Returns 0 or 1. + int ReadOneBit(); + + +protected: + + unsigned int CheckReadUBitLong(int numbits); // For debugging. + int ReadOneBitNoCheck(); // Faster version, doesn't check bounds and is inlined. + bool CheckForOverflow(int nBits); + + +public: + + // Get the base pointer. + const unsigned char* GetBasePointer() { return m_pData; } + + BITBUF_INLINE int TotalBytesAvailable( void ) const + { + return m_nDataBytes; + } + + // Read a list of bits in. + void ReadBits(void *pOut, int nBits); + // Read a list of bits in, but don't overrun the destination buffer. + // Returns the number of bits read into the buffer. The remaining + // bits are skipped over. + int ReadBitsClamped_ptr(void *pOut, size_t outSizeBytes, size_t nBits); + // Helper 'safe' template function that infers the size of the destination + // array. This version of the function should be preferred. + // Usage: char databuffer[100]; + // ReadBitsClamped( dataBuffer, msg->m_nLength ); + template + int ReadBitsClamped( T (&pOut)[N], size_t nBits ) + { + return ReadBitsClamped_ptr( pOut, N * sizeof(T), nBits ); + } + + float ReadBitAngle( int numbits ); + + unsigned int ReadUBitLong( int numbits ) RESTRICT; + unsigned int ReadUBitLongNoInline( int numbits ) RESTRICT; + unsigned int PeekUBitLong( int numbits ); + int ReadSBitLong( int numbits ); + + // reads an unsigned integer with variable bit length + unsigned int ReadUBitVar(); + unsigned int ReadUBitVarInternal( int encodingType ); + + // reads a varint encoded integer + uint32 ReadVarInt32(); + uint64 ReadVarInt64(); + int32 ReadSignedVarInt32(); + int64 ReadSignedVarInt64(); + + // You can read signed or unsigned data with this, just cast to + // a signed int if necessary. + unsigned int ReadBitLong(int numbits, bool bSigned); + + float ReadBitCoord(); + float ReadBitCoordMP( bool bIntegral, bool bLowPrecision ); + float ReadBitFloat(); + float ReadBitNormal(); + void ReadBitVec3Coord( Vector& fa ); + void ReadBitVec3Normal( Vector& fa ); + void ReadBitAngles( QAngle& fa ); + + // Faster for comparisons but do not fully decode float values + unsigned int ReadBitCoordBits(); + unsigned int ReadBitCoordMPBits( bool bIntegral, bool bLowPrecision ); + +// Byte functions (these still read data in bit-by-bit). +public: + + BITBUF_INLINE int ReadChar() { return (char)ReadUBitLong(8); } + BITBUF_INLINE int ReadByte() { return ReadUBitLong(8); } + BITBUF_INLINE int ReadShort() { return (short)ReadUBitLong(16); } + BITBUF_INLINE int ReadWord() { return ReadUBitLong(16); } + BITBUF_INLINE long ReadLong() { return ReadUBitLong(32); } + int64 ReadLongLong(); + float ReadFloat(); + bool ReadBytes(void *pOut, int nBytes); + + // Returns false if bufLen isn't large enough to hold the + // string in the buffer. + // + // Always reads to the end of the string (so you can read the + // next piece of data waiting). + // + // If bLine is true, it stops when it reaches a '\n' or a null-terminator. + // + // pStr is always null-terminated (unless bufLen is 0). + // + // pOutNumChars is set to the number of characters left in pStr when the routine is + // complete (this will never exceed bufLen-1). + // + bool ReadString( char *pStr, int bufLen, bool bLine=false, int *pOutNumChars=NULL ); + + // Reads a string and allocates memory for it. If the string in the buffer + // is > 2048 bytes, then pOverflow is set to true (if it's not NULL). + char* ReadAndAllocateString( bool *pOverflow = 0 ); + + // Returns nonzero if any bits differ + int CompareBits( bf_read * RESTRICT other, int bits ) RESTRICT; + int CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffset, int bits ) RESTRICT; + +// Status. +public: + int GetNumBytesLeft(); + int GetNumBytesRead(); + int GetNumBitsLeft(); + int GetNumBitsRead() const; + + // Has the buffer overflowed? + inline bool IsOverflowed() const {return m_bOverflow;} + + inline bool Seek(int iBit); // Seek to a specific bit. + inline bool SeekRelative(int iBitDelta); // Seek to an offset from the current position. + + // Called when the buffer is overflowed. + void SetOverflowFlag(); + + +public: + + // The current buffer. + const unsigned char* RESTRICT m_pData; + int m_nDataBytes; + int m_nDataBits; + + // Where we are in the buffer. + int m_iCurBit; + + +private: + // Errors? + bool m_bOverflow; + + // For debugging.. + bool m_bAssertOnOverflow; + + const char *m_pDebugName; +}; + +//----------------------------------------------------------------------------- +// Inlines. +//----------------------------------------------------------------------------- + +inline int bf_read::GetNumBytesRead() +{ + return BitByte(m_iCurBit); +} + +inline int bf_read::GetNumBitsLeft() +{ + return m_nDataBits - m_iCurBit; +} + +inline int bf_read::GetNumBytesLeft() +{ + return GetNumBitsLeft() >> 3; +} + +inline int bf_read::GetNumBitsRead() const +{ + return m_iCurBit; +} + +inline bool bf_read::Seek(int iBit) +{ + if(iBit < 0 || iBit > m_nDataBits) + { + SetOverflowFlag(); + m_iCurBit = m_nDataBits; + return false; + } + else + { + m_iCurBit = iBit; + return true; + } +} + +// Seek to an offset from the current position. +inline bool bf_read::SeekRelative(int iBitDelta) +{ + return Seek(m_iCurBit+iBitDelta); +} + +inline bool bf_read::CheckForOverflow(int nBits) +{ + if( m_iCurBit + nBits > m_nDataBits ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + } + + return m_bOverflow; +} + +inline int bf_read::ReadOneBitNoCheck() +{ +#if VALVE_LITTLE_ENDIAN + unsigned int value = ((unsigned long * RESTRICT)m_pData)[m_iCurBit >> 5] >> (m_iCurBit & 31); +#else + unsigned char value = m_pData[m_iCurBit >> 3] >> (m_iCurBit & 7); +#endif + ++m_iCurBit; + return value & 1; +} + +inline int bf_read::ReadOneBit() +{ + if( GetNumBitsLeft() <= 0 ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + return 0; + } + return ReadOneBitNoCheck(); +} + +inline float bf_read::ReadBitFloat() +{ + union { uint32 u; float f; } c = { ReadUBitLong(32) }; + return c.f; +} + +BITBUF_INLINE unsigned int bf_read::ReadUBitVar() +{ + // six bits: low 2 bits for encoding + first 4 bits of value + unsigned int sixbits = ReadUBitLong(6); + unsigned int encoding = sixbits & 3; + if ( encoding ) + { + // this function will seek back four bits and read the full value + return ReadUBitVarInternal( encoding ); + } + return sixbits >> 2; +} + +BITBUF_INLINE unsigned int bf_read::ReadUBitLong( int numbits ) RESTRICT +{ + Assert( numbits > 0 && numbits <= 32 ); + + if ( GetNumBitsLeft() < numbits ) + { + m_iCurBit = m_nDataBits; + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + return 0; + } + + unsigned int iStartBit = m_iCurBit & 31u; + int iLastBit = m_iCurBit + numbits - 1; + unsigned int iWordOffset1 = m_iCurBit >> 5; + unsigned int iWordOffset2 = iLastBit >> 5; + m_iCurBit += numbits; + +#if __i386__ + unsigned int bitmask = (2 << (numbits-1)) - 1; +#else + extern unsigned long g_ExtraMasks[33]; + unsigned int bitmask = g_ExtraMasks[numbits]; +#endif + + unsigned int dw1 = LoadLittleDWord( (unsigned long* RESTRICT)m_pData, iWordOffset1 ) >> iStartBit; + unsigned int dw2 = LoadLittleDWord( (unsigned long* RESTRICT)m_pData, iWordOffset2 ) << (32 - iStartBit); + + return (dw1 | dw2) & bitmask; +} + +BITBUF_INLINE int bf_read::CompareBits( bf_read * RESTRICT other, int numbits ) RESTRICT +{ + return (ReadUBitLong(numbits) != other->ReadUBitLong(numbits)); +} + + +#endif + + + diff --git a/public/tier1/byteswap.h b/public/tier1/byteswap.h new file mode 100644 index 0000000..9b08254 --- /dev/null +++ b/public/tier1/byteswap.h @@ -0,0 +1,249 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Low level byte swapping routines. +// +// $NoKeywords: $ +//============================================================================= +#ifndef BYTESWAP_H +#define BYTESWAP_H +#if defined(_WIN32) +#pragma once +#endif + +#include "datamap.h" // Needed for typedescription_t. Note datamap.h is tier1 as well. + +class CByteswap +{ +public: + CByteswap() + { + // Default behavior sets the target endian to match the machine native endian (no swap). + SetTargetBigEndian( IsMachineBigEndian() ); + } + + //----------------------------------------------------------------------------- + // Write a single field. + //----------------------------------------------------------------------------- + void SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField ); + + //----------------------------------------------------------------------------- + // Write a block of fields. Works a bit like the saverestore code. + //----------------------------------------------------------------------------- + void SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap ); + + // Swaps fields for the templated type to the output buffer. + template inline void SwapFieldsToTargetEndian( T* pOutputBuffer, void *pBaseData, unsigned int objectCount = 1 ) + { + for ( unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer ) + { + SwapFieldsToTargetEndian( (void*)pOutputBuffer, pBaseData, &T::m_DataMap ); + pBaseData = (byte*)pBaseData + sizeof(T); + } + } + + // Swaps fields for the templated type in place. + template inline void SwapFieldsToTargetEndian( T* pOutputBuffer, unsigned int objectCount = 1 ) + { + SwapFieldsToTargetEndian( pOutputBuffer, (void*)pOutputBuffer, objectCount ); + } + + //----------------------------------------------------------------------------- + // True if the current machine is detected as big endian. + // (Endienness is effectively detected at compile time when optimizations are + // enabled) + //----------------------------------------------------------------------------- + static bool IsMachineBigEndian() + { + short nIsBigEndian = 1; + + // if we are big endian, the first byte will be a 0, if little endian, it will be a one. + return (bool)(0 == *(char *)&nIsBigEndian ); + } + + //----------------------------------------------------------------------------- + // Sets the target byte ordering we are swapping to or from. + // + // Braindead Endian Reference: + // x86 is LITTLE Endian + // PowerPC is BIG Endian + //----------------------------------------------------------------------------- + inline void SetTargetBigEndian( bool bigEndian ) + { + m_bBigEndian = bigEndian; + m_bSwapBytes = IsMachineBigEndian() != bigEndian; + } + + // Changes target endian + inline void FlipTargetEndian( void ) + { + m_bSwapBytes = !m_bSwapBytes; + m_bBigEndian = !m_bBigEndian; + } + + // Forces byte swapping state, regardless of endianess + inline void ActivateByteSwapping( bool bActivate ) + { + SetTargetBigEndian( IsMachineBigEndian() != bActivate ); + } + + //----------------------------------------------------------------------------- + // Returns true if the target machine is the same as this one in endianness. + // + // Used to determine when a byteswap needs to take place. + //----------------------------------------------------------------------------- + inline bool IsSwappingBytes( void ) // Are bytes being swapped? + { + return m_bSwapBytes; + } + + inline bool IsTargetBigEndian( void ) // What is the current target endian? + { + return m_bBigEndian; + } + + //----------------------------------------------------------------------------- + // IsByteSwapped() + // + // When supplied with a chunk of input data and a constant or magic number + // (in native format) determines the endienness of the current machine in + // relation to the given input data. + // + // Returns: + // 1 if input is the same as nativeConstant. + // 0 if input is byteswapped relative to nativeConstant. + // -1 if input is not the same as nativeConstant and not byteswapped either. + // + // ( This is useful for detecting byteswapping in magic numbers in structure + // headers for example. ) + //----------------------------------------------------------------------------- + template inline int SourceIsNativeEndian( T input, T nativeConstant ) + { + // If it's the same, it isn't byteswapped: + if( input == nativeConstant ) + return 1; + + int output; + LowLevelByteSwap( &output, &input ); + if( output == nativeConstant ) + return 0; + + assert( 0 ); // if we get here, input is neither a swapped nor unswapped version of nativeConstant. + return -1; + } + + //----------------------------------------------------------------------------- + // Swaps an input buffer full of type T into the given output buffer. + // + // Swaps [count] items from the inputBuffer to the outputBuffer. + // If inputBuffer is omitted or NULL, then it is assumed to be the same as + // outputBuffer - effectively swapping the contents of the buffer in place. + //----------------------------------------------------------------------------- + template inline void SwapBuffer( T* outputBuffer, T* inputBuffer = NULL, int count = 1 ) + { + assert( count >= 0 ); + assert( outputBuffer ); + + // Fail gracefully in release: + if( count <=0 || !outputBuffer ) + return; + + // Optimization for the case when we are swapping in place. + if( inputBuffer == NULL ) + { + inputBuffer = outputBuffer; + } + + // Swap everything in the buffer: + for( int i = 0; i < count; i++ ) + { + LowLevelByteSwap( &outputBuffer[i], &inputBuffer[i] ); + } + } + + //----------------------------------------------------------------------------- + // Swaps an input buffer full of type T into the given output buffer. + // + // Swaps [count] items from the inputBuffer to the outputBuffer. + // If inputBuffer is omitted or NULL, then it is assumed to be the same as + // outputBuffer - effectively swapping the contents of the buffer in place. + //----------------------------------------------------------------------------- + template inline void SwapBufferToTargetEndian( T* outputBuffer, T* inputBuffer = NULL, int count = 1 ) + { + assert( count >= 0 ); + assert( outputBuffer ); + + // Fail gracefully in release: + if( count <=0 || !outputBuffer ) + return; + + // Optimization for the case when we are swapping in place. + if( inputBuffer == NULL ) + { + inputBuffer = outputBuffer; + } + + // Are we already the correct endienness? ( or are we swapping 1 byte items? ) + if( !m_bSwapBytes || ( sizeof(T) == 1 ) ) + { + // If we were just going to swap in place then return. + if( !inputBuffer ) + return; + + // Otherwise copy the inputBuffer to the outputBuffer: + memcpy( outputBuffer, inputBuffer, count * sizeof( T ) ); + return; + + } + + // Swap everything in the buffer: + for( int i = 0; i < count; i++ ) + { + LowLevelByteSwap( &outputBuffer[i], &inputBuffer[i] ); + } + } + +private: + //----------------------------------------------------------------------------- + // The lowest level byte swapping workhorse of doom. output always contains the + // swapped version of input. ( Doesn't compare machine to target endianness ) + //----------------------------------------------------------------------------- + template static void LowLevelByteSwap( T *output, T *input ) + { + T temp = *output; +#if defined( _X360 ) + // Intrinsics need the source type to be fixed-point + DWORD* word = (DWORD*)input; + switch( sizeof(T) ) + { + case 8: + { + __storewordbytereverse( *word, 0, &temp ); + __storewordbytereverse( *(word+1), 4, &temp ); + } + break; + + case 4: + __storewordbytereverse( *word, 0, &temp ); + break; + + case 2: + __storeshortbytereverse( *input, 0, &temp ); + break; + + default: + Assert( "Invalid size in CByteswap::LowLevelByteSwap" && 0 ); + } +#else + for( int i = 0; i < sizeof(T); i++ ) + { + ((unsigned char* )&temp)[i] = ((unsigned char*)input)[sizeof(T)-(i+1)]; + } +#endif + Q_memcpy( output, &temp, sizeof(T) ); + } + + unsigned int m_bSwapBytes : 1; + unsigned int m_bBigEndian : 1; +}; + +#endif /* !BYTESWAP_H */ diff --git a/public/tier1/callqueue.h b/public/tier1/callqueue.h new file mode 100644 index 0000000..5e0e994 --- /dev/null +++ b/public/tier1/callqueue.h @@ -0,0 +1,203 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef CALLQUEUE_H +#define CALLQUEUE_H + +#include "tier0/tslist.h" +#include "functors.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------- +// Avert thy eyes! Imagine rather: +// +// void QueueCall( , [args1, [arg2,]...] +// void QueueCall( , , [args1, [arg2,]...] +// void QueueRefCall( , <, [args1, [arg2,]...] +//----------------------------------------------------- + +#define DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL(N) \ + template \ + void QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + QueueFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ + } + +//------------------------------------- + +#define DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL(N) \ + template \ + void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ + } + +//------------------------------------- + +#define DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL(N) \ + template \ + void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ + } + +//------------------------------------- + +#define DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \ + template \ + void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ + } + +//------------------------------------- + +#define DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \ + template \ + void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ + \ + } + +#define FUNC_GENERATE_QUEUE_METHODS() \ + FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL ); \ + FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL ); \ + FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL );\ + FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL ); \ + FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL ) + +//----------------------------------------------------- + +template > +class CCallQueueT +{ +public: + CCallQueueT() + : m_bNoQueue( false ) + { +#ifdef _DEBUG + m_nCurSerialNumber = 0; + m_nBreakSerialNumber = (unsigned)-1; +#endif + } + + void DisableQueue( bool bDisable ) + { + if ( m_bNoQueue == bDisable ) + { + return; + } + if ( !m_bNoQueue ) + CallQueued(); + + m_bNoQueue = bDisable; + } + + bool IsDisabled() const + { + return m_bNoQueue; + } + + int Count() + { + return m_queue.Count(); + } + + void CallQueued() + { + if ( !m_queue.Count() ) + { + return; + } + + m_queue.PushItem( NULL ); + + CFunctor *pFunctor; + + while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL ) + { +#ifdef _DEBUG + if ( pFunctor->m_nUserID == m_nBreakSerialNumber) + { + m_nBreakSerialNumber = (unsigned)-1; + } +#endif + (*pFunctor)(); + pFunctor->Release(); + } + + } + + void QueueFunctor( CFunctor *pFunctor ) + { + Assert( pFunctor ); + QueueFunctorInternal( RetAddRef( pFunctor ) ); + } + + void Flush() + { + m_queue.PushItem( NULL ); + + CFunctor *pFunctor; + + while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL ) + { + pFunctor->Release(); + } + } + + FUNC_GENERATE_QUEUE_METHODS(); + +private: + void QueueFunctorInternal( CFunctor *pFunctor ) + { + if ( !m_bNoQueue ) + { +#ifdef _DEBUG + pFunctor->m_nUserID = m_nCurSerialNumber++; +#endif + m_queue.PushItem( pFunctor ); + } + else + { + (*pFunctor)(); + pFunctor->Release(); + } + } + + QUEUE_TYPE m_queue; + bool m_bNoQueue; + unsigned m_nCurSerialNumber; + unsigned m_nBreakSerialNumber; +}; + +class CCallQueue : public CCallQueueT<> +{ +}; + +//----------------------------------------------------- +// Optional interface that can be bound to concrete CCallQueue +//----------------------------------------------------- + +class ICallQueue +{ +public: + void QueueFunctor( CFunctor *pFunctor ) + { + QueueFunctorInternal( RetAddRef( pFunctor ) ); + } + + FUNC_GENERATE_QUEUE_METHODS(); + +private: + virtual void QueueFunctorInternal( CFunctor *pFunctor ) = 0; +}; + +#endif // CALLQUEUE_H diff --git a/public/tier1/characterset.h b/public/tier1/characterset.h new file mode 100644 index 0000000..0c639e1 --- /dev/null +++ b/public/tier1/characterset.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared code for parsing / searching for characters in a string +// using lookup tables +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef CHARACTERSET_H +#define CHARACTERSET_H + +#ifdef _WIN32 +#pragma once +#endif + + +struct characterset_t +{ + char set[256]; +}; + + +// This is essentially a strpbrk() using a precalculated lookup table +//----------------------------------------------------------------------------- +// Purpose: builds a simple lookup table of a group of important characters +// Input : *pSetBuffer - pointer to the buffer for the group +// *pSetString - list of characters to flag +//----------------------------------------------------------------------------- +extern void CharacterSetBuild( characterset_t *pSetBuffer, const char *pSetString ); + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSetBuffer - pre-build group buffer +// character - character to lookup +// Output : int - 1 if the character was in the set +//----------------------------------------------------------------------------- +#define IN_CHARACTERSET( SetBuffer, character ) ((SetBuffer).set[ (unsigned char) (character) ]) + + +#endif // CHARACTERSET_H diff --git a/public/tier1/checksum_crc.h b/public/tier1/checksum_crc.h new file mode 100644 index 0000000..dbbc50a --- /dev/null +++ b/public/tier1/checksum_crc.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic CRC functions +// +// $NoKeywords: $ +//=============================================================================// +#ifndef CHECKSUM_CRC_H +#define CHECKSUM_CRC_H +#ifdef _WIN32 +#pragma once +#endif + +typedef unsigned int CRC32_t; + +void CRC32_Init( CRC32_t *pulCRC ); +void CRC32_ProcessBuffer( CRC32_t *pulCRC, const void *p, int len ); +void CRC32_Final( CRC32_t *pulCRC ); +CRC32_t CRC32_GetTableEntry( unsigned int slot ); + +inline CRC32_t CRC32_ProcessSingleBuffer( const void *p, int len ) +{ + CRC32_t crc; + + CRC32_Init( &crc ); + CRC32_ProcessBuffer( &crc, p, len ); + CRC32_Final( &crc ); + + return crc; +} + +#endif // CHECKSUM_CRC_H diff --git a/public/tier1/checksum_md5.h b/public/tier1/checksum_md5.h new file mode 100644 index 0000000..e7cf7ec --- /dev/null +++ b/public/tier1/checksum_md5.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic MD5 hashing algo +// +//=============================================================================// + +#ifndef CHECKSUM_MD5_H +#define CHECKSUM_MD5_H + +#ifdef _WIN32 +#pragma once +#endif + +// 16 bytes == 128 bit digest +#define MD5_DIGEST_LENGTH 16 +#define MD5_BIT_LENGTH ( MD5_DIGEST_LENGTH * sizeof(unsigned char) ) +struct MD5Value_t +{ + unsigned char bits[MD5_DIGEST_LENGTH]; + + void Zero(); + bool IsZero() const; + + bool operator==( const MD5Value_t &src ) const; + bool operator!=( const MD5Value_t &src ) const; + +}; + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + +void MD5Init( MD5Context_t *context ); +void MD5Update( MD5Context_t *context, unsigned char const *buf, unsigned int len ); +void MD5Final( unsigned char digest[ MD5_DIGEST_LENGTH ], MD5Context_t *context ); + +char *MD5_Print(unsigned char *digest, int hashlen ); + +/// Convenience wrapper to calculate the MD5 for a buffer, all in one step, without +/// bothering with the context object. +void MD5_ProcessSingleBuffer( const void *p, int len, MD5Value_t &md5Result ); + +unsigned int MD5_PseudoRandom(unsigned int nSeed); + +/// Returns true if the values match. +bool MD5_Compare( const MD5Value_t &data, const MD5Value_t &compare ); + +inline bool MD5Value_t::operator==( const MD5Value_t &src ) const +{ + return MD5_Compare( *this, src ); +} + +inline bool MD5Value_t::operator!=( const MD5Value_t &src ) const +{ + return !MD5_Compare( *this, src ); +} + +#endif // CHECKSUM_MD5_H diff --git a/public/tier1/checksum_sha1.h b/public/tier1/checksum_sha1.h new file mode 100644 index 0000000..7c87aa5 --- /dev/null +++ b/public/tier1/checksum_sha1.h @@ -0,0 +1,174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implementation of SHA-1 +// +//============================================================================= + +#ifndef CHECKSUM_SHA1_H +#define CHECKSUM_SHA1_H + +#if defined( _WIN32 ) +#pragma once +#endif + +/* + 100% free public domain implementation of the SHA-1 + algorithm by Dominik Reichl + + + === Test Vectors (from FIPS PUB 180-1) === + + SHA1("abc") = + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + + SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + + SHA1(A million repetitions of "a") = + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#if !defined(_MINIMUM_BUILD_) +#include // Needed for file access +#if defined( _PS3 ) +#include +#else +#include +#endif +#include // Needed for strcat and strcpy +#endif + +// If you're compiling big endian, just comment out the following line +#define SHA1_LITTLE_ENDIAN + +typedef union +{ + unsigned char c[64]; + unsigned long l[16]; +} SHA1_WORKSPACE_BLOCK; + +// SHA1 hash +const unsigned int k_cubHash = 20; +const unsigned int k_cchHash = 41; // k_cubHash * 2, plus 1 for terminator +#pragma pack( push, 1 ) +typedef unsigned char SHADigest_t[ k_cubHash ]; +#pragma pack( pop ) + +#if !defined(_MINIMUM_BUILD_) +class CSHA1 +#else +class Minimum_CSHA1 +#endif +{ +public: + // Two different formats for ReportHash(...) + enum + { + REPORT_HEX = 0, + REPORT_DIGIT = 1 + }; + + // Constructor and Destructor +#if !defined(_MINIMUM_BUILD_) + CSHA1(); + virtual ~CSHA1() ; +#else + Minimum_CSHA1() ; + ~Minimum_CSHA1() ; // no virtual destructor's in the minimal builds ! +#endif + + unsigned long m_state[5]; + unsigned long m_count[2]; + unsigned char m_buffer[64]; + unsigned char m_digest[k_cubHash]; + + void Reset(); + + // Update the hash value + void Update(unsigned char *data, unsigned int len); +#if !defined(_MINIMUM_BUILD_) + bool HashFile(char *szFileName); +#endif + + // Finalize hash and report + void Final(); +#if !defined(_MINIMUM_BUILD_) + void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX); +#endif + void GetHash(unsigned char *uDest); + +private: + // Private SHA-1 transformation + void Transform(unsigned long state[5], unsigned char buffer[64]); + + // Member variables + unsigned char m_workspace[64]; + SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above +}; + +#define GenerateHash( hash, pubData, cubData ) { CSHA1 sha1; sha1.Update( (byte *)pubData, cubData ); sha1.Final(); sha1.GetHash( hash ); } + +#if !defined(_MINIMUM_BUILD_) +// hash comparison function, for use with CUtlMap/CUtlRBTree +bool HashLessFunc( SHADigest_t const &lhs, SHADigest_t const &rhs ); + +// utility class for manipulating SHA1 hashes in their compact form +struct CSHA +{ +public: + SHADigest_t m_shaDigest; + + CSHA() + { + memset( m_shaDigest, 0, k_cubHash ); + } + + explicit CSHA( const SHADigest_t rhs ) + { + memcpy( m_shaDigest, rhs, k_cubHash ); + } + + SHADigest_t &SHADigest() + { + return m_shaDigest; + } + + bool operator<( const CSHA &rhs ) const + { + return memcmp( m_shaDigest, rhs.m_shaDigest, k_cubHash ) < 0; + } + + bool operator==( const CSHA &rhs ) const + { + return memcmp( m_shaDigest, rhs.m_shaDigest, k_cubHash ) == 0; + } + + bool operator!=( const CSHA &rhs ) const + { + return !(*this == rhs); + } + + bool operator==( const SHADigest_t &rhs ) const + { + return memcmp( m_shaDigest, rhs, k_cubHash ) == 0; + } + + bool operator!=( const SHADigest_t &rhs ) const + { + return !(*this == rhs); + } + + CSHA &operator=( const SHADigest_t rhs ) + { + memcpy( m_shaDigest, rhs, k_cubHash ); + return *this; + } + + void AssignTo( SHADigest_t rhs ) const + { + memcpy( rhs, m_shaDigest, k_cubHash ); + } +}; +#endif // _MINIMUM_BUILD_ + +#endif // CHECKSUM_SHA1_H diff --git a/public/tier1/convar.h b/public/tier1/convar.h new file mode 100644 index 0000000..3d52388 --- /dev/null +++ b/public/tier1/convar.h @@ -0,0 +1,676 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//===========================================================================// + +#ifndef CONVAR_H +#define CONVAR_H + +#if _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier1/iconvar.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" +#include "icvar.h" + +#ifdef _WIN32 +#define FORCEINLINE_CVAR FORCEINLINE +#elif POSIX +#define FORCEINLINE_CVAR inline +#else +#error "implement me" +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConVar; +class CCommand; +class ConCommand; +class ConCommandBase; +struct characterset_t; + + + +//----------------------------------------------------------------------------- +// Any executable that wants to use ConVars need to implement one of +// these to hook up access to console variables. +//----------------------------------------------------------------------------- +class IConCommandBaseAccessor +{ +public: + // Flags is a combination of FCVAR flags in cvar.h. + // hOut is filled in with a handle to the variable. + virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Helper method for console development +//----------------------------------------------------------------------------- +#if defined( _X360 ) && !defined( _RETAIL ) +void ConVar_PublishToVXConsole(); +#endif + + +//----------------------------------------------------------------------------- +// Called when a ConCommand needs to execute +//----------------------------------------------------------------------------- +typedef void ( *FnCommandCallbackVoid_t )( void ); +typedef void ( *FnCommandCallback_t )( const CCommand &command ); + +#define COMMAND_COMPLETION_MAXITEMS 64 +#define COMMAND_COMPLETION_ITEM_LENGTH 64 + +//----------------------------------------------------------------------------- +// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings +//----------------------------------------------------------------------------- +typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); + + +//----------------------------------------------------------------------------- +// Interface version +//----------------------------------------------------------------------------- +class ICommandCallback +{ +public: + virtual void CommandCallback( const CCommand &command ) = 0; +}; + +class ICommandCompletionCallback +{ +public: + virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +//----------------------------------------------------------------------------- +class ConCommandBase +{ + friend class CCvar; + friend class ConVar; + friend class ConCommand; + friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor ); + friend void ConVar_PublishToVXConsole(); + + // FIXME: Remove when ConVar changes are done + friend class CDefaultCvar; + +public: + ConCommandBase( void ); + ConCommandBase( const char *pName, const char *pHelpString = 0, + int flags = 0 ); + + virtual ~ConCommandBase( void ); + + virtual bool IsCommand( void ) const; + + // Check flag + virtual bool IsFlagSet( int flag ) const; + // Set flag + virtual void AddFlags( int flags ); + + // INTERFACE_UPDATE:23.02.2020 + virtual void stub_001(){} + virtual void stub_002(){} + + // Return name of cvar + virtual const char *GetName( void ) const; + + // Return help text for cvar + virtual const char *GetHelpText( void ) const; + + // Deal with next pointer + const ConCommandBase *GetNext( void ) const; + ConCommandBase *GetNext( void ); + + virtual bool IsRegistered( void ) const; + + // Returns the DLL identifier + virtual CVarDLLIdentifier_t GetDLLIdentifier() const; + +protected: + virtual void CreateBase( const char *pName, const char *pHelpString = 0, + int flags = 0 ); + + // Used internally by OneTimeInit to initialize/shutdown + virtual void Init(); + void Shutdown(); + + // Internal copy routine ( uses new operator from correct module ) + char *CopyString( const char *from ); + +private: + // Next ConVar in chain + // Prior to register, it points to the next convar in the DLL. + // Once registered, though, m_pNext is reset to point to the next + // convar in the global list + ConCommandBase *m_pNext; + + // Has the cvar been added to the global list? + bool m_bRegistered; + + // Static data + const char *m_pszName; + const char *m_pszHelpString; + + // ConVar flags + int m_nFlags; + +protected: + // ConVars add themselves to this list for the executable. + // Then ConVar_Register runs through all the console variables + // and registers them into a global list stored in vstdlib.dll + static ConCommandBase *s_pConCommandBases; + + // ConVars in this executable use this 'global' to access values. + static IConCommandBaseAccessor *s_pAccessor; +}; + + +//----------------------------------------------------------------------------- +// Command tokenizer +//----------------------------------------------------------------------------- +class CCommand +{ +public: + CCommand(); + CCommand( int nArgC, const char **ppArgV ); + bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL ); + void Reset(); + + int ArgC() const; + const char **ArgV() const; + const char *ArgS() const; // All args that occur after the 0th arg, in string form + const char *GetCommandString() const; // The entire command in string form, including the 0th arg + const char *operator[]( int nIndex ) const; // Gets at arguments + const char *Arg( int nIndex ) const; // Gets at arguments + + // Helper functions to parse arguments to commands. + const char* FindArg( const char *pName ) const; + int FindArgInt( const char *pName, int nDefaultVal ) const; + + static int MaxCommandLength(); + static characterset_t* DefaultBreakSet(); + +private: + enum + { + COMMAND_MAX_ARGC = 64, + COMMAND_MAX_LENGTH = 512, + }; + + int m_nArgc; + int m_nArgv0Size; + char m_pArgSBuffer[ COMMAND_MAX_LENGTH ]; + char m_pArgvBuffer[ COMMAND_MAX_LENGTH ]; + const char* m_ppArgv[ COMMAND_MAX_ARGC ]; +}; + +inline int CCommand::MaxCommandLength() +{ + return COMMAND_MAX_LENGTH - 1; +} + +inline int CCommand::ArgC() const +{ + return m_nArgc; +} + +inline const char **CCommand::ArgV() const +{ + return m_nArgc ? (const char**)m_ppArgv : NULL; +} + +inline const char *CCommand::ArgS() const +{ + return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; +} + +inline const char *CCommand::GetCommandString() const +{ + return m_nArgc ? m_pArgSBuffer : ""; +} + +inline const char *CCommand::Arg( int nIndex ) const +{ + // FIXME: Many command handlers appear to not be particularly careful + // about checking for valid argc range. For now, we're going to + // do the extra check and return an empty string if it's out of range + if ( nIndex < 0 || nIndex >= m_nArgc ) + return ""; + return m_ppArgv[nIndex]; +} + +inline const char *CCommand::operator[]( int nIndex ) const +{ + return Arg( nIndex ); +} + + +//----------------------------------------------------------------------------- +// Purpose: The console invoked command +//----------------------------------------------------------------------------- +class ConCommand : public ConCommandBase +{ +friend class CCvar; + +public: + typedef ConCommandBase BaseClass; + + ConCommand( const char *pName, FnCommandCallbackVoid_t callback, + const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); + ConCommand( const char *pName, FnCommandCallback_t callback, + const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); + ConCommand( const char *pName, ICommandCallback *pCallback, + const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 ); + + virtual ~ConCommand( void ); + + virtual bool IsCommand( void ) const; + + virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands ); + + virtual bool CanAutoComplete( void ); + + // Invoke the function + virtual void Dispatch( const CCommand &command ); + +private: + // NOTE: To maintain backward compat, we have to be very careful: + // All public virtual methods must appear in the same order always + // since engine code will be calling into this code, which *does not match* + // in the mod code; it's using slightly different, but compatible versions + // of this class. Also: Be very careful about adding new fields to this class. + // Those fields will not exist in the version of this class that is instanced + // in mod code. + + // Call this function when executing the command + union + { + FnCommandCallbackVoid_t m_fnCommandCallbackV1; + FnCommandCallback_t m_fnCommandCallback; + ICommandCallback *m_pCommandCallback; + }; + + union + { + FnCommandCompletionCallback m_fnCompletionCallback; + ICommandCompletionCallback *m_pCommandCompletionCallback; + }; + + bool m_bHasCompletionCallback : 1; + bool m_bUsingNewCommandCallback : 1; + bool m_bUsingCommandCallbackInterface : 1; +}; + + +//----------------------------------------------------------------------------- +// Purpose: A console variable +//----------------------------------------------------------------------------- +class ConVar : public ConCommandBase, public IConVar +{ +friend class CCvar; +friend class ConVarRef; + +public: + typedef ConCommandBase BaseClass; + + ConVar( const char *pName, const char *pDefaultValue, int flags = 0); + + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString ); + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax ); + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString, FnChangeCallback_t callback ); + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, + FnChangeCallback_t callback ); + + virtual ~ConVar( void ); + + virtual bool IsFlagSet( int flag ) const; + virtual const char* GetHelpText( void ) const; + virtual bool IsRegistered( void ) const; + virtual const char *GetName( void ) const; + virtual void AddFlags( int flags ); + virtual bool IsCommand( void ) const; + + // Install a change callback (there shouldn't already be one....) + void InstallChangeCallback( FnChangeCallback_t callback ); + + // Retrieve value + FORCEINLINE_CVAR float GetFloat( void ) const; + FORCEINLINE_CVAR int GetInt( void ) const; + FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); } + FORCEINLINE_CVAR char const *GetString( void ) const; + + // Any function that allocates/frees memory needs to be virtual or else you'll have crashes + // from alloc/free across dll/exe boundaries. + + // These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue). + virtual void SetValue( const char *value ); + virtual void SetValue( float value ); + virtual void SetValue( int value ); + + // Reset to default value + void Revert( void ); + + // True if it has a min/max setting + bool GetMin( float& minVal ) const; + bool GetMax( float& maxVal ) const; + const char *GetDefault( void ) const; + void SetDefault( const char *pszDefault ); + +private: + // Called by CCvar when the value of a var is changing. + virtual void InternalSetValue(const char *value); + // For CVARs marked FCVAR_NEVER_AS_STRING + virtual void InternalSetFloatValue( float fNewValue ); + virtual void InternalSetIntValue( int nValue ); + + virtual bool ClampValue( float& value ); + virtual void ChangeStringValue( const char *tempVal, float flOldValue ); + + virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0, + const char *pHelpString = 0, bool bMin = false, float fMin = 0.0, + bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 ); + + // Used internally by OneTimeInit to initialize. + virtual void Init(); + int GetFlags() { return m_pParent->m_nFlags; } +private: + + // This either points to "this" or it points to the original declaration of a ConVar. + // This allows ConVars to exist in separate modules, and they all use the first one to be declared. + // m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar). + ConVar *m_pParent; + + // Static data + const char *m_pszDefaultValue; + + // Value + // Dynamically allocated + char *m_pszString; + int m_StringLength; + + // Values + float m_fValue; + int m_nValue; + + // Min/Max values + bool m_bHasMin; + float m_fMinVal; + bool m_bHasMax; + float m_fMaxVal; + + // Call this function when ConVar changes + FnChangeCallback_t m_fnChangeCallback; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float +// Output : float +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR float ConVar::GetFloat( void ) const +{ + return m_pParent->m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +// Output : int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR int ConVar::GetInt( void ) const +{ + return m_pParent->m_nValue; +} + + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. +// Output : const char * +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR const char *ConVar::GetString( void ) const +{ + if ( m_nFlags & FCVAR_NEVER_AS_STRING ) + return "FCVAR_NEVER_AS_STRING"; + + return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : ""; +} + + +//----------------------------------------------------------------------------- +// Used to read/write convars that already exist (replaces the FindVar method) +//----------------------------------------------------------------------------- +class ConVarRef +{ +public: + ConVarRef( const char *pName ); + ConVarRef( const char *pName, bool bIgnoreMissing ); + ConVarRef( IConVar *pConVar ); + + void Init( const char *pName, bool bIgnoreMissing ); + bool IsValid() const; + bool IsFlagSet( int nFlags ) const; + IConVar *GetLinkedConVar(); + + // Get/Set value + float GetFloat( void ) const; + int GetInt( void ) const; + bool GetBool() const { return !!GetInt(); } + const char *GetString( void ) const; + + void SetValue( const char *pValue ); + void SetValue( float flValue ); + void SetValue( int nValue ); + void SetValue( bool bValue ); + + const char *GetName() const; + + const char *GetDefault() const; + +private: + // High-speed method to read convar data + IConVar *m_pConVar; + ConVar *m_pConVarState; +}; + + +//----------------------------------------------------------------------------- +// Did we find an existing convar of that name? +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const +{ + return ( m_pConVar->IsFlagSet( nFlags ) != 0 ); +} + +FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar() +{ + return m_pConVar; +} + +FORCEINLINE_CVAR const char *ConVarRef::GetName() const +{ + return m_pConVar->GetName(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const +{ + return m_pConVarState->m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const +{ + return m_pConVarState->m_nValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const +{ + Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) ); + return m_pConVarState->m_pszString; +} + + +FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue ) +{ + m_pConVar->SetValue( pValue ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue ) +{ + m_pConVar->SetValue( flValue ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue ) +{ + m_pConVar->SetValue( nValue ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue ) +{ + m_pConVar->SetValue( bValue ? 1 : 0 ); +} + +FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const +{ + return m_pConVarState->m_pszDefaultValue; +} + + +//----------------------------------------------------------------------------- +// Called by the framework to register ConCommands with the ICVar +//----------------------------------------------------------------------------- +void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL ); +void ConVar_Unregister( ); + + +//----------------------------------------------------------------------------- +// Utility methods +//----------------------------------------------------------------------------- +void ConVar_PrintFlags( const ConCommandBase *var ); +void ConVar_PrintDescription( const ConCommandBase *pVar ); + + +//----------------------------------------------------------------------------- +// Purpose: Utility class to quickly allow ConCommands to call member methods +//----------------------------------------------------------------------------- +#pragma warning (disable : 4355 ) + +template< class T > +class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback +{ + typedef ConCommand BaseClass; + typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command ); + typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands ); + +public: + CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0, + int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) : + BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL ) + { + m_pOwner = pOwner; + m_Func = callback; + m_CompletionFunc = completionFunc; + } + + ~CConCommandMemberAccessor() + { + Shutdown(); + } + + void SetOwner( T* pOwner ) + { + m_pOwner = pOwner; + } + + virtual void CommandCallback( const CCommand &command ) + { + Assert( m_pOwner && m_Func ); + (m_pOwner->*m_Func)( command ); + } + + virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) + { + Assert( m_pOwner && m_CompletionFunc ); + return (m_pOwner->*m_CompletionFunc)( pPartial, commands ); + } + +private: + T* m_pOwner; + FnMemberCommandCallback_t m_Func; + FnMemberCommandCompletionCallback_t m_CompletionFunc; +}; + +#pragma warning ( default : 4355 ) + + +//----------------------------------------------------------------------------- +// Purpose: Utility macros to quicky generate a simple console command +//----------------------------------------------------------------------------- +#define CON_COMMAND( name, description ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_F( name, description, flags ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description, flags ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description, flags, completion ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_EXTERN( name, _funcname, description ) \ + void _funcname( const CCommand &args ); \ + static ConCommand name##_command( #name, _funcname, description ); \ + void _funcname( const CCommand &args ) + +#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \ + void _funcname( const CCommand &args ); \ + static ConCommand name##_command( #name, _funcname, description, flags ); \ + void _funcname( const CCommand &args ) + +#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \ + void _funcname( const CCommand &args ); \ + friend class CCommandMemberInitializer_##_funcname; \ + class CCommandMemberInitializer_##_funcname \ + { \ + public: \ + CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \ + { \ + m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \ + } \ + private: \ + CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \ + }; \ + \ + CCommandMemberInitializer_##_funcname m_##_funcname##_register; \ + + +#endif // CONVAR_H diff --git a/public/tier1/convar_serverbounded.h b/public/tier1/convar_serverbounded.h new file mode 100644 index 0000000..3bdd1ab --- /dev/null +++ b/public/tier1/convar_serverbounded.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Helper class for cvars that have restrictions on their value. +// +//=============================================================================// + +#ifndef CONVAR_SERVERBOUNDED_H +#define CONVAR_SERVERBOUNDED_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class is used to virtualize a ConVar's value, so the client can restrict its +// value while connected to a server. When using this across modules, it's important +// to dynamic_cast it to a ConVar_ServerBounded or you won't get the restricted value. +// +// NOTE: FCVAR_USERINFO vars are not virtualized before they are sent to the server +// (we have no way to detect if the virtualized value would change), so +// if you want to use a bounded cvar's value on the server, you must rebound it +// the same way the client does. +class ConVar_ServerBounded : public ConVar +{ +public: + ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) + : ConVar( pName, pDefaultValue, flags, pHelpString ) + { + } + + ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, FnChangeCallback_t callback ) + : ConVar( pName, pDefaultValue, flags, pHelpString, callback ) + { + } + + ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) + : ConVar( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax ) {} + + // You must implement GetFloat. + virtual float GetFloat() const = 0; + + // You can optionally implement these. + virtual int GetInt() const { return (int)GetFloat(); } + virtual bool GetBool() const { return ( GetInt() != 0 ); } + + // Use this to get the underlying cvar's value. + float GetBaseFloatValue() const + { + return ConVar::GetFloat(); + } +}; + + +#endif // CONVAR_SERVERBOUNDED_H diff --git a/public/tier1/datamanager.h b/public/tier1/datamanager.h new file mode 100644 index 0000000..8803054 --- /dev/null +++ b/public/tier1/datamanager.h @@ -0,0 +1,277 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef RESOURCEMANAGER_H +#define RESOURCEMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/threadtools.h" +#include "utlmultilist.h" +#include "utlvector.h" + +FORWARD_DECLARE_HANDLE( memhandle_t ); + +#define INVALID_MEMHANDLE ((memhandle_t)0xffffffff) + +class CDataManagerBase +{ +public: + + // public API + // ----------------------------------------------------------------------------- + // memhandle_t CreateResource( params ) // implemented by derived class + void DestroyResource( memhandle_t handle ); + + // type-safe implementation in derived class + //void *LockResource( memhandle_t handle ); + int UnlockResource( memhandle_t handle ); + void TouchResource( memhandle_t handle ); + void MarkAsStale( memhandle_t handle ); // move to head of LRU + + int LockCount( memhandle_t handle ); + int BreakLock( memhandle_t handle ); + int BreakAllLocks(); + + // HACKHACK: For convenience - offers no lock protection + // type-safe implementation in derived class + //void *GetResource_NoLock( memhandle_t handle ); + + unsigned int TargetSize(); + unsigned int AvailableSize(); + unsigned int UsedSize(); + + void NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize ); + + void SetTargetSize( unsigned int targetSize ); + + // NOTE: flush is equivalent to Destroy + unsigned int FlushAllUnlocked(); + unsigned int FlushToTargetSize(); + unsigned int FlushAll(); + unsigned int Purge( unsigned int nBytesToPurge ); + unsigned int EnsureCapacity( unsigned int size ); + + // Thread lock + virtual void Lock() {} + virtual bool TryLock() { return true; } + virtual void Unlock() {} + + // Iteration + + // ----------------------------------------------------------------------------- + + // Debugging only!!!! + void GetLRUHandleList( CUtlVector< memhandle_t >& list ); + void GetLockHandleList( CUtlVector< memhandle_t >& list ); + + +protected: + // derived class must call these to implement public API + unsigned short CreateHandle( bool bCreateLocked ); + memhandle_t StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize ); + void *GetResource_NoLock( memhandle_t handle ); + void *GetResource_NoLockNoLRUTouch( memhandle_t handle ); + void *LockResource( memhandle_t handle ); + + // NOTE: you must call this from the destructor of the derived class! (will assert otherwise) + void FreeAllLists() { FlushAll(); m_listsAreFreed = true; } + + CDataManagerBase( unsigned int maxSize ); + virtual ~CDataManagerBase(); + + + inline unsigned int MemTotal_Inline() const { return m_targetMemorySize; } + inline unsigned int MemAvailable_Inline() const { return m_targetMemorySize - m_memUsed; } + inline unsigned int MemUsed_Inline() const { return m_memUsed; } + +// Implemented by derived class: + virtual void DestroyResourceStorage( void * ) = 0; + virtual unsigned int GetRealSize( void * ) = 0; + + memhandle_t ToHandle( unsigned short index ); + unsigned short FromHandle( memhandle_t handle ); + + void TouchByIndex( unsigned short memoryIndex ); + void * GetForFreeByIndex( unsigned short memoryIndex ); + + // One of these is stored per active allocation + struct resource_lru_element_t + { + resource_lru_element_t() + { + lockCount = 0; + serial = 1; + pStore = 0; + } + + unsigned short lockCount; + unsigned short serial; + void *pStore; + }; + + unsigned int m_targetMemorySize; + unsigned int m_memUsed; + + CUtlMultiList< resource_lru_element_t, unsigned short > m_memoryLists; + + unsigned short m_lruList; + unsigned short m_lockList; + unsigned short m_freeList; + unsigned short m_listsAreFreed : 1; + unsigned short m_unused : 15; + +}; + +template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE *, class MUTEX_TYPE = CThreadNullMutex> +class CDataManager : public CDataManagerBase +{ + typedef CDataManagerBase BaseClass; +public: + + CDataManager( unsigned int size = (unsigned)-1 ) : BaseClass(size) {} + + + ~CDataManager() + { + // NOTE: This must be called in all implementations of CDataManager + FreeAllLists(); + } + + // Use GetData() to translate pointer to LOCK_TYPE + LOCK_TYPE LockResource( memhandle_t hMem ) + { + void *pLock = BaseClass::LockResource( hMem ); + if ( pLock ) + { + return StoragePointer(pLock)->GetData(); + } + + return NULL; + } + + // Use GetData() to translate pointer to LOCK_TYPE + LOCK_TYPE GetResource_NoLock( memhandle_t hMem ) + { + void *pLock = const_cast(BaseClass::GetResource_NoLock( hMem )); + if ( pLock ) + { + return StoragePointer(pLock)->GetData(); + } + return NULL; + } + + // Use GetData() to translate pointer to LOCK_TYPE + // Doesn't touch the memory LRU + LOCK_TYPE GetResource_NoLockNoLRUTouch( memhandle_t hMem ) + { + void *pLock = const_cast(BaseClass::GetResource_NoLockNoLRUTouch( hMem )); + if ( pLock ) + { + return StoragePointer(pLock)->GetData(); + } + return NULL; + } + + // Wrapper to match implementation of allocation with typed storage & alloc params. + memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false ) + { + BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); + unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); + STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); + return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() ); + } + + // Iteration. Must lock first + memhandle_t GetFirstUnlocked() + { + unsigned node = m_memoryLists.Head(m_lruList); + if ( node == m_memoryLists.InvalidIndex() ) + { + return INVALID_MEMHANDLE; + } + return ToHandle( node ); + } + + memhandle_t GetFirstLocked() + { + unsigned node = m_memoryLists.Head(m_lockList); + if ( node == m_memoryLists.InvalidIndex() ) + { + return INVALID_MEMHANDLE; + } + return ToHandle( node ); + } + + memhandle_t GetNext( memhandle_t hPrev ) + { + if ( hPrev == INVALID_MEMHANDLE ) + { + return INVALID_MEMHANDLE; + } + + unsigned short iNext = m_memoryLists.Next( FromHandle( hPrev ) ); + if ( iNext == m_memoryLists.InvalidIndex() ) + { + return INVALID_MEMHANDLE; + } + + return ToHandle( iNext ); + } + + MUTEX_TYPE &AccessMutex() { return m_mutex; } + virtual void Lock() { m_mutex.Lock(); } + virtual bool TryLock() { return m_mutex.TryLock(); } + virtual void Unlock() { m_mutex.Unlock(); } + +private: + STORAGE_TYPE *StoragePointer( void *pMem ) + { + return static_cast(pMem); + } + + virtual void DestroyResourceStorage( void *pStore ) + { + StoragePointer(pStore)->DestroyResource(); + } + + virtual unsigned int GetRealSize( void *pStore ) + { + return StoragePointer(pStore)->Size(); + } + + MUTEX_TYPE m_mutex; +}; + +//----------------------------------------------------------------------------- + +inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle ) +{ + unsigned int fullWord = (unsigned int)handle; + unsigned short serial = fullWord>>16; + unsigned short index = fullWord & 0xFFFF; + index--; + if ( m_memoryLists.IsValidIndex(index) && m_memoryLists[index].serial == serial ) + return index; + return m_memoryLists.InvalidIndex(); +} + +inline int CDataManagerBase::LockCount( memhandle_t handle ) +{ + Lock(); + int result = 0; + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + result = m_memoryLists[memoryIndex].lockCount; + } + Unlock(); + return result; +} + + +#endif // RESOURCEMANAGER_H diff --git a/public/tier1/delegates.h b/public/tier1/delegates.h new file mode 100644 index 0000000..35a50cf --- /dev/null +++ b/public/tier1/delegates.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Simple macros to generate delegation code +// +//============================================================================= + +#ifndef DELEGATES_H +#define DELEGATES_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#define DELEGATE_TO_OBJECT_0( RetType, FuncName, pDelegated ) RetType FuncName() { return (pDelegated)->FuncName(); } +#define DELEGATE_TO_OBJECT_0V( FuncName, pDelegated ) void FuncName() { (pDelegated)->FuncName(); } +#define DELEGATE_TO_OBJECT_1( RetType, FuncName, ArgType1, pDelegated ) RetType FuncName( ArgType1 a1 ) { return (pDelegated)->FuncName( a1 ); } +#define DELEGATE_TO_OBJECT_1V( FuncName, ArgType1, pDelegated ) void FuncName( ArgType1 a1 ) { (pDelegated)->FuncName( a1 ); } +#define DELEGATE_TO_OBJECT_2( RetType, FuncName, ArgType1, ArgType2, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) { return (pDelegated)->FuncName( a1, a2 ); } +#define DELEGATE_TO_OBJECT_2V( FuncName, ArgType1, ArgType2, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2 ) { (pDelegated)->FuncName( a1, a2 ); } +#define DELEGATE_TO_OBJECT_3( RetType, FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { return (pDelegated)->FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_OBJECT_3V( FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { (pDelegated)->FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_OBJECT_4( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { return (pDelegated)->FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_OBJECT_4V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { (pDelegated)->FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_OBJECT_5( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_OBJECT_5V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_OBJECT_6( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_OBJECT_6V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_OBJECT_7( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_OBJECT_7V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_OBJECT_8( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_OBJECT_8V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_OBJECT_9( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } +#define DELEGATE_TO_OBJECT_9V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } +#define DELEGATE_TO_OBJECT_11V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, ArgType10, ArgType11, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9, ArgType10 a10, ArgType11 a11 ) { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 ); } + +#define DELEGATE_TO_OBJECT_0C( RetType, FuncName, pDelegated ) RetType FuncName() const { return (pDelegated)->FuncName(); } +#define DELEGATE_TO_OBJECT_0VC( FuncName, pDelegated ) void FuncName() const { (pDelegated)->FuncName(); } +#define DELEGATE_TO_OBJECT_1C( RetType, FuncName, ArgType1, pDelegated ) RetType FuncName( ArgType1 a1 ) const { return (pDelegated)->FuncName( a1 ); } +#define DELEGATE_TO_OBJECT_1VC( FuncName, ArgType1, pDelegated ) void FuncName( ArgType1 a1 ) const { (pDelegated)->FuncName( a1 ); } +#define DELEGATE_TO_OBJECT_2C( RetType, FuncName, ArgType1, ArgType2, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) const { return (pDelegated)->FuncName( a1, a2 ); } +#define DELEGATE_TO_OBJECT_2VC( FuncName, ArgType1, ArgType2, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2 ) const { (pDelegated)->FuncName( a1, a2 ); } +#define DELEGATE_TO_OBJECT_3C( RetType, FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { return (pDelegated)->FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_OBJECT_3VC( FuncName, ArgType1, ArgType2, ArgType3, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { (pDelegated)->FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_OBJECT_4C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_OBJECT_4VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { (pDelegated)->FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_OBJECT_5C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_OBJECT_5VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_OBJECT_6C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_OBJECT_6VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_OBJECT_7C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_OBJECT_7VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_OBJECT_8C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_OBJECT_8VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_OBJECT_9C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { return (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } +#define DELEGATE_TO_OBJECT_9VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, pDelegated ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { (pDelegated)->FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } + +#define DELEGATE_TO_BASE_0( RetType, FuncName, BaseClass ) RetType FuncName() { return BaseClass::FuncName(); } +#define DELEGATE_TO_BASE_0V( FuncName, BaseClass ) void FuncName() { BaseClass::FuncName(); } +#define DELEGATE_TO_BASE_1( RetType, FuncName, ArgType1, BaseClass ) RetType FuncName( ArgType1 a1 ) { return BaseClass::FuncName( a1 ); } +#define DELEGATE_TO_BASE_1V( FuncName, ArgType1, BaseClass ) void FuncName( ArgType1 a1 ) { BaseClass::FuncName( a1 ); } +#define DELEGATE_TO_BASE_2( RetType, FuncName, ArgType1, ArgType2, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) { return BaseClass::FuncName( a1, a2 ); } +#define DELEGATE_TO_BASE_2V( FuncName, ArgType1, ArgType2, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2 ) { BaseClass::FuncName( a1, a2 ); } +#define DELEGATE_TO_BASE_3( RetType, FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { return BaseClass::FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_BASE_3V( FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) { BaseClass::FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_BASE_4( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { return BaseClass::FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_BASE_4V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) { BaseClass::FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_BASE_5( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_BASE_5V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) { BaseClass::FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_BASE_6( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_BASE_6V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_BASE_7( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_BASE_7V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_BASE_8( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_BASE_8V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_BASE_9( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } +#define DELEGATE_TO_BASE_9V( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } + +#define DELEGATE_TO_BASE_0C( RetType, FuncName, BaseClass ) RetType FuncName() const { return BaseClass::FuncName(); } +#define DELEGATE_TO_BASE_0VC( FuncName, BaseClass ) void FuncName() const { BaseClass::FuncName(); } +#define DELEGATE_TO_BASE_1C( RetType, FuncName, ArgType1, BaseClass ) RetType FuncName( ArgType1 a1 ) const { return BaseClass::FuncName( a1 ); } +#define DELEGATE_TO_BASE_1VC( FuncName, ArgType1, BaseClass ) void FuncName( ArgType1 a1 ) const { BaseClass::FuncName( a1 ); } +#define DELEGATE_TO_BASE_2C( RetType, FuncName, ArgType1, ArgType2, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2 ) const { return BaseClass::FuncName( a1, a2 ); } +#define DELEGATE_TO_BASE_2VC( FuncName, ArgType1, ArgType2, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2 ) const { BaseClass::FuncName( a1, a2 ); } +#define DELEGATE_TO_BASE_3C( RetType, FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { return BaseClass::FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_BASE_3VC( FuncName, ArgType1, ArgType2, ArgType3, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3 ) const { BaseClass::FuncName( a1, a2, a3 ); } +#define DELEGATE_TO_BASE_4C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { return BaseClass::FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_BASE_4VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4 ) const { BaseClass::FuncName( a1, a2, a3, a4 ); } +#define DELEGATE_TO_BASE_5C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_BASE_5VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5 ); } +#define DELEGATE_TO_BASE_6C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_BASE_6VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6 ); } +#define DELEGATE_TO_BASE_7C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_BASE_7VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7 ); } +#define DELEGATE_TO_BASE_8C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_BASE_8VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8 ); } +#define DELEGATE_TO_BASE_9C( RetType, FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) RetType FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { return BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } +#define DELEGATE_TO_BASE_9VC( FuncName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, ArgType6, ArgType7, ArgType8, ArgType9, BaseClass ) void FuncName( ArgType1 a1, ArgType2 a2, ArgType3 a3, ArgType4 a4, ArgType5 a5, ArgType6 a6, ArgType7 a7, ArgType8 a8, ArgType9 a9 ) const { BaseClass::FuncName( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); } + +#endif // DELEGATES_H diff --git a/public/tier1/diff.h b/public/tier1/diff.h new file mode 100644 index 0000000..fc2fb75 --- /dev/null +++ b/public/tier1/diff.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//=============================================================================// + +#ifndef DIFF_H +#define DIFF_H +#pragma once + +int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock, + int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize); + +int FindDiffsForLargeFiles(uint8 const *NewBlock, uint8 const *OldBlock, + int NewSize, int OldSize, int &DiffListSize,uint8 *Output, + uint32 OutSize, + int hashsize=65536); + +void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList, + int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize); + +int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock, + int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize); + +#endif + diff --git a/public/tier1/fileio.h b/public/tier1/fileio.h new file mode 100644 index 0000000..52f9e08 --- /dev/null +++ b/public/tier1/fileio.h @@ -0,0 +1,101 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A collection of utility classes to simplify file I/O, and +// as much as possible contain portability problems. Here avoiding +// including windows.h. +// +//============================================================================= + +#ifndef FILEIO_H +#define FILEIO_H + +#if defined (_WIN32) +#else +#include +#include +#if !defined( _PS3 ) +#include +#endif // _PS3 +#endif + +#include "tier0/platform.h" +#include "tier1/utlstring.h" +#include "tier1/utllinkedlist.h" + +const int64 k_nMillion = 1000000; +const int64 k_nThousand = 1000; +const int64 k_nKiloByte = 1024; +const int64 k_nMegabyte = k_nKiloByte * k_nKiloByte; +const int64 k_nGigabyte = k_nMegabyte * k_nKiloByte; + +class CPathString +{ +public: + + // Constructors: Automatically fixes slashes and removes double slashes when the object is + // constructed, and then knows how to append magic \\?\ on Windows for unicode paths + CPathString( const char *pchUTF8Path ); + ~CPathString(); + + // Gets the path in UTF8 + const char *GetUTF8Path(); + + // Gets wchar_t based path, with \\?\ pre-pended (allowing long paths on Win32, should only be used with unicode aware filesystem calls) + const wchar_t *GetWCharPathPrePended(); + +private: + + void PopulateWCharPath(); + + char *m_pchUTF8Path; + wchar_t *m_pwchWideCharPathPrepended; + +}; + +#if !defined(_PS3) +//----------------------------------------------------------------------------- +// Purpose: Encapsulates watching a directory for file changes +//----------------------------------------------------------------------------- +class CDirWatcher +{ +public: + CDirWatcher(); + ~CDirWatcher(); + + // only one directory can be watched at a time + void SetDirToWatch( const char *pchDir ); + + // retrieve any changes + bool GetChangedFile( CUtlString *psFile ); + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, const char *pchName ); +#endif + +private: + CUtlLinkedList m_listChangedFiles; + void *m_hFile; + void *m_pOverlapped; + void *m_pFileInfo; +#ifdef OSX +public: + struct timespec m_modTime; + void AddFileToChangeList( const char *pchFile ); + CUtlString m_BaseDir; +private: + void *m_WatcherStream; +#endif + friend class CDirWatcherFriend; + +#ifdef LINUX + void AddFileToChangeList( const char *pchFile ); +#endif +#ifdef _WIN32 + // used by callback functions to push a file onto the list + void AddFileToChangeList( const char *pchFile ); + void PostDirWatch(); +#endif +}; +#endif // _PS3 + +#endif // FILEIO_H diff --git a/public/tier1/fmtstr.h b/public/tier1/fmtstr.h new file mode 100644 index 0000000..66ea88f --- /dev/null +++ b/public/tier1/fmtstr.h @@ -0,0 +1,366 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A simple class for performing safe and in-expression sprintf-style +// string formatting +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FMTSTR_H +#define FMTSTR_H + +#include +#include +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier1/strtools.h" + +#if defined( _WIN32 ) +#pragma once +#endif +#if defined(POSIX) +#pragma GCC visibility push(hidden) +#endif + +//============================================================================= + +// using macro to be compatable with GCC +#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \ + do \ + { \ + int result; \ + va_list arg_ptr; \ + bool bTruncated = false; \ + static int scAsserted = 0; \ + \ + va_start(arg_ptr, lastArg); \ + result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \ + va_end(arg_ptr); \ + \ + (szBuf)[(nBufSize)-1] = 0; \ + if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \ + { \ + Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \ + AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \ + scAsserted++; \ + } \ + m_nLength = nPrevLen + result; \ + } \ + while (0) + +// using macro to be compatable with GCC +#define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \ + do \ + { \ + int result; \ + va_list arg_ptr; \ + bool bTruncated = false; \ + static int scAsserted = 0; \ + \ + va_start(arg_ptr, lastArg); \ + result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \ + va_end(arg_ptr); \ + \ + (szBuf)[(nBufSize)-1] = 0; \ + if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \ + { \ + Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \ + AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \ + scAsserted++; \ + } \ + } \ + while (0) + +//----------------------------------------------------------------------------- +// +// Purpose: String formatter with specified size +// + +template +class CFmtStrN +{ +public: + CFmtStrN() + { + InitQuietTruncation(); + m_szBuf[0] = 0; + m_nLength = 0; + } + + // Standard C formatting + CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 ) + { + InitQuietTruncation(); + FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat ); + } + + // Use this for pass-through formatting + CFmtStrN(const char ** ppszFormat, ...) + { + InitQuietTruncation(); + FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat ); + } + + // Explicit reformat + const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 ) + { + InitQuietTruncation(); + FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat ); + return m_szBuf; + } + + // Use this for va_list formatting + const char *sprintf_argv(const char *pszFormat, va_list arg_ptr) + { + int result; + bool bTruncated = false; + static int s_nWarned = 0; + + InitQuietTruncation(); + result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated ); + m_szBuf[SIZE_BUF - 1] = 0; + if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) ) + { + Warning( "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF ); + AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" ); + s_nWarned++; + } + m_nLength = V_strlen( m_szBuf ); + return m_szBuf; + } + + // Use this for pass-through formatting + void VSprintf(const char **ppszFormat, ...) + { + InitQuietTruncation(); + FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat ); + } + + // Compatible API with CUtlString for converting to const char* + const char *Get( ) const { return m_szBuf; } + const char *String( ) const { return m_szBuf; } + // Use for access + operator const char *() const { return m_szBuf; } + char *Access() { return m_szBuf; } + + // Access template argument + static inline int GetMaxLength() { return SIZE_BUF-1; } + + CFmtStrN & operator=( const char *pchValue ) + { + V_strncpy( m_szBuf, pchValue, SIZE_BUF ); + m_nLength = V_strlen( m_szBuf ); + return *this; + } + + CFmtStrN & operator+=( const char *pchValue ) + { + Append( pchValue ); + return *this; + } + + int Length() const { return m_nLength; } + + void SetLength( int nLength ) + { + m_nLength = Min( nLength, SIZE_BUF - 1 ); + m_szBuf[m_nLength] = '\0'; + } + + void Clear() + { + m_szBuf[0] = 0; + m_nLength = 0; + } + + void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 ) + { + char *pchEnd = m_szBuf + m_nLength; + FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat ); + } + + void AppendFormatV( const char *pchFormat, va_list args ); + + void Append( const char *pchValue ) + { + // This function is close to the metal to cut down on the CPU cost + // of the previous incantation of Append which was implemented as + // AppendFormat( "%s", pchValue ). This implementation, though not + // as easy to read, instead does a strcpy from the existing end + // point of the CFmtStrN. This brings something like a 10-20x speedup + // in my rudimentary tests. It isn't using V_strncpy because that + // function doesn't return the number of characters copied, which + // we need to adjust m_nLength. Doing the V_strncpy with a V_strlen + // afterwards took twice as long as this implementations in tests, + // so V_strncpy's implementation was used to write this method. + char *pDest = m_szBuf + m_nLength; + const int maxLen = SIZE_BUF - m_nLength; + char *pLast = pDest + maxLen - 1; + while ( (pDest < pLast) && (*pchValue != 0) ) + { + *pDest = *pchValue; + ++pDest; ++pchValue; + } + *pDest = 0; + m_nLength = pDest - m_szBuf; + } + + //optimized version of append for just adding a single character + void Append( char ch ) + { + if( m_nLength < SIZE_BUF - 1 ) + { + m_szBuf[ m_nLength ] = ch; + m_nLength++; + m_szBuf[ m_nLength ] = '\0'; + } + } + + void AppendIndent( uint32 unCount, char chIndent = '\t' ); + + void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; } + +protected: + virtual void InitQuietTruncation() + { + m_bQuietTruncation = QUIET_TRUNCATION; + } + + bool m_bQuietTruncation; + +private: + char m_szBuf[SIZE_BUF]; + int m_nLength; +}; + + +// Version which will not assert if strings are truncated + +template < int SIZE_BUF > +class CFmtStrQuietTruncationN : public CFmtStrN +{ +}; + + +template< int SIZE_BUF, bool QUIET_TRUNCATION > +void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent ) +{ + Assert( Length() + unCount < SIZE_BUF ); + if( Length() + unCount >= SIZE_BUF ) + unCount = SIZE_BUF - (1+Length()); + for ( uint32 x = 0; x < unCount; x++ ) + { + m_szBuf[ m_nLength++ ] = chIndent; + } + m_szBuf[ m_nLength ] = '\0'; +} + +template< int SIZE_BUF, bool QUIET_TRUNCATION > +void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args ) +{ + int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args ); + m_nLength += cubPrinted; +} + + +#if defined(POSIX) +#pragma GCC visibility pop +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Default-sized string formatter +// + +#define FMTSTR_STD_LEN 256 + +typedef CFmtStrN CFmtStr; +typedef CFmtStrQuietTruncationN CFmtStrQuietTruncation; +typedef CFmtStrN<1024> CFmtStr1024; +typedef CFmtStrN<8192> CFmtStrMax; + + +//----------------------------------------------------------------------------- +// Purpose: Fast-path number-to-string helper (with optional quoting) +// Derived off of the Steam CNumStr but with a few tweaks, such as +// trimming off the in-our-cases-unnecessary strlen calls (by not +// storing the length in the class). +//----------------------------------------------------------------------------- + +class CNumStr +{ +public: + CNumStr() { m_szBuf[0] = 0; } + + explicit CNumStr( bool b ) { SetBool( b ); } + + explicit CNumStr( int8 n8 ) { SetInt8( n8 ); } + explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); } + explicit CNumStr( int16 n16 ) { SetInt16( n16 ); } + explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); } + explicit CNumStr( int32 n32 ) { SetInt32( n32 ); } + explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); } + explicit CNumStr( int64 n64 ) { SetInt64( n64 ); } + explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); } + +#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS) + explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); } + explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); } +#endif + + explicit CNumStr( double f ) { SetDouble( f ); } + explicit CNumStr( float f ) { SetFloat( f ); } + + inline void SetBool( bool b ) { Q_memcpy( m_szBuf, b ? "1" : "0", 2 ); } + +#ifdef _WIN32 + inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); } + inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); } + inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); } + inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); } + inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); } + inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); } + inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); } + inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); } +#else + inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); } + inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); } + inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); } + inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); } + inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); } + inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); } + inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); } + inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); } +#endif + + inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); } + inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); } + + inline void SetHexUint64( uint64 un64 ) { Q_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); } + + operator const char *() const { return m_szBuf; } + const char* String() const { return m_szBuf; } + + void AddQuotes() + { + Assert( m_szBuf[0] != '"' ); + const int nLength = Q_strlen( m_szBuf ); + Q_memmove( m_szBuf + 1, m_szBuf, nLength ); + m_szBuf[0] = '"'; + m_szBuf[nLength + 1] = '"'; + m_szBuf[nLength + 2] = 0; + } + +protected: + char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes + +}; + + +//============================================================================= + +bool BGetLocalFormattedDateAndTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime ); +bool BGetLocalFormattedDate( time_t timeVal, char *pchDate, int cubDate ); +bool BGetLocalFormattedTime( time_t timeVal, char *pchTime, int cubTime ); + +#endif // FMTSTR_H diff --git a/public/tier1/functors.h b/public/tier1/functors.h new file mode 100644 index 0000000..afc45d3 --- /dev/null +++ b/public/tier1/functors.h @@ -0,0 +1,637 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements a generic infrastucture for functors combining +// a number of techniques to provide transparent parameter type +// deduction and packaging. Supports both member and non-member functions. +// +// See also: http://en.wikipedia.org/wiki/Function_object +// +// Note that getting into the guts of this file is not for the +// feint of heart. The core concept here is that the compiler can +// figure out all the parameter types. +// +// E.g.: +// +// struct CMyClass +// { +// void foo( int i) {} +// }; +// +// int bar(int i) { return i; } +// +// CMyClass myInstance; +// +// CFunctor *pFunctor = CreateFunctor( &myInstance, CMyClass::foo, 8675 ); +// CFunctor *pFunctor2 = CreateFunctor( &bar, 309 ); +// +// void CallEm() +// { +// (*pFunctor)(); +// (*pFunctor2)(); +// } +// +//============================================================================= + +#ifndef FUNCTORS_H +#define FUNCTORS_H + +#include "tier0/platform.h" +#include "tier1/refcount.h" +#include "tier1/utlenvelope.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// +// Macros used as basis for template generation. Just ignore the man behind the +// curtain +// +//----------------------------------------------------------------------------- + +#define FUNC_TEMPLATE_ARG_PARAMS_0 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_0 +#define FUNC_ARG_MEMBERS_0 +#define FUNC_ARG_FORMAL_PARAMS_0 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_0 +#define FUNC_CALL_ARGS_INIT_0 +#define FUNC_CALL_MEMBER_ARGS_0 +#define FUNC_CALL_ARGS_0 +#define FUNC_FUNCTOR_CALL_ARGS_0 +#define FUNC_TEMPLATE_FUNC_PARAMS_0 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_0 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_0 + +#define FUNC_TEMPLATE_ARG_PARAMS_1 , typename ARG_TYPE_1 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_1 , ARG_TYPE_1 +#define FUNC_ARG_MEMBERS_1 ARG_TYPE_1 m_arg1 +#define FUNC_ARG_FORMAL_PARAMS_1 , const ARG_TYPE_1 &arg1 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_1 const ARG_TYPE_1 &arg1 +#define FUNC_CALL_ARGS_INIT_1 , m_arg1( arg1 ) +#define FUNC_CALL_MEMBER_ARGS_1 m_arg1 +#define FUNC_CALL_ARGS_1 arg1 +#define FUNC_FUNCTOR_CALL_ARGS_1 , arg1 +#define FUNC_TEMPLATE_FUNC_PARAMS_1 , typename FUNC_ARG_TYPE_1 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_1 FUNC_ARG_TYPE_1 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_1 , FUNC_ARG_TYPE_1 + +#define FUNC_TEMPLATE_ARG_PARAMS_2 , typename ARG_TYPE_1, typename ARG_TYPE_2 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_2 , ARG_TYPE_1, ARG_TYPE_2 +#define FUNC_ARG_MEMBERS_2 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2 +#define FUNC_ARG_FORMAL_PARAMS_2 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_2 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2 +#define FUNC_CALL_ARGS_INIT_2 , m_arg1( arg1 ), m_arg2( arg2 ) +#define FUNC_CALL_MEMBER_ARGS_2 m_arg1, m_arg2 +#define FUNC_CALL_ARGS_2 arg1, arg2 +#define FUNC_FUNCTOR_CALL_ARGS_2 , arg1, arg2 +#define FUNC_TEMPLATE_FUNC_PARAMS_2 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_2 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_2 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2 + +#define FUNC_TEMPLATE_ARG_PARAMS_3 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_3 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3 +#define FUNC_ARG_MEMBERS_3 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3 +#define FUNC_ARG_FORMAL_PARAMS_3 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_3 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3 +#define FUNC_CALL_ARGS_INIT_3 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ) +#define FUNC_CALL_MEMBER_ARGS_3 m_arg1, m_arg2, m_arg3 +#define FUNC_CALL_ARGS_3 arg1, arg2, arg3 +#define FUNC_FUNCTOR_CALL_ARGS_3 , arg1, arg2, arg3 +#define FUNC_TEMPLATE_FUNC_PARAMS_3 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_3 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_3 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3 + +#define FUNC_TEMPLATE_ARG_PARAMS_4 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_4 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4 +#define FUNC_ARG_MEMBERS_4 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4 +#define FUNC_ARG_FORMAL_PARAMS_4 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_4 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4 +#define FUNC_CALL_ARGS_INIT_4 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ) +#define FUNC_CALL_MEMBER_ARGS_4 m_arg1, m_arg2, m_arg3, m_arg4 +#define FUNC_CALL_ARGS_4 arg1, arg2, arg3, arg4 +#define FUNC_FUNCTOR_CALL_ARGS_4 , arg1, arg2, arg3, arg4 +#define FUNC_TEMPLATE_FUNC_PARAMS_4 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_4 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_4 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4 + +#define FUNC_TEMPLATE_ARG_PARAMS_5 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_5 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5 +#define FUNC_ARG_MEMBERS_5 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5 +#define FUNC_ARG_FORMAL_PARAMS_5 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_5 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5 +#define FUNC_CALL_ARGS_INIT_5 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ) +#define FUNC_CALL_MEMBER_ARGS_5 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5 +#define FUNC_CALL_ARGS_5 arg1, arg2, arg3, arg4, arg5 +#define FUNC_FUNCTOR_CALL_ARGS_5 , arg1, arg2, arg3, arg4, arg5 +#define FUNC_TEMPLATE_FUNC_PARAMS_5 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_5 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_5 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5 + +#define FUNC_TEMPLATE_ARG_PARAMS_6 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_6 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6 +#define FUNC_ARG_MEMBERS_6 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6 +#define FUNC_ARG_FORMAL_PARAMS_6 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_6 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6 +#define FUNC_CALL_ARGS_INIT_6 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ) +#define FUNC_CALL_MEMBER_ARGS_6 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6 +#define FUNC_CALL_ARGS_6 arg1, arg2, arg3, arg4, arg5, arg6 +#define FUNC_FUNCTOR_CALL_ARGS_6 , arg1, arg2, arg3, arg4, arg5, arg6 +#define FUNC_TEMPLATE_FUNC_PARAMS_6 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_6 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_6 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6 + +#define FUNC_TEMPLATE_ARG_PARAMS_7 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_7 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7 +#define FUNC_ARG_MEMBERS_7 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; +#define FUNC_ARG_FORMAL_PARAMS_7 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_7 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7 +#define FUNC_CALL_ARGS_INIT_7 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ) +#define FUNC_CALL_MEMBER_ARGS_7 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7 +#define FUNC_CALL_ARGS_7 arg1, arg2, arg3, arg4, arg5, arg6, arg7 +#define FUNC_FUNCTOR_CALL_ARGS_7 , arg1, arg2, arg3, arg4, arg5, arg6, arg7 +#define FUNC_TEMPLATE_FUNC_PARAMS_7 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_7 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_7 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7 + +#define FUNC_TEMPLATE_ARG_PARAMS_8 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_8 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8 +#define FUNC_ARG_MEMBERS_8 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; +#define FUNC_ARG_FORMAL_PARAMS_8 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_8 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8 +#define FUNC_CALL_ARGS_INIT_8 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ) +#define FUNC_CALL_MEMBER_ARGS_8 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8 +#define FUNC_CALL_ARGS_8 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 +#define FUNC_FUNCTOR_CALL_ARGS_8 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 +#define FUNC_TEMPLATE_FUNC_PARAMS_8 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_8 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_8 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8 + +#define FUNC_TEMPLATE_ARG_PARAMS_9 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_9 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9 +#define FUNC_ARG_MEMBERS_9 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; +#define FUNC_ARG_FORMAL_PARAMS_9 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_9 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9 +#define FUNC_CALL_ARGS_INIT_9 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ) +#define FUNC_CALL_MEMBER_ARGS_9 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9 +#define FUNC_CALL_ARGS_9 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 +#define FUNC_FUNCTOR_CALL_ARGS_9 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 +#define FUNC_TEMPLATE_FUNC_PARAMS_9 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_9 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_9 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9 + +#define FUNC_TEMPLATE_ARG_PARAMS_10 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_10 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10 +#define FUNC_ARG_MEMBERS_10 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; +#define FUNC_ARG_FORMAL_PARAMS_10 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_10 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10 +#define FUNC_CALL_ARGS_INIT_10 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ) +#define FUNC_CALL_MEMBER_ARGS_10 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10 +#define FUNC_CALL_ARGS_10 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +#define FUNC_FUNCTOR_CALL_ARGS_10 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +#define FUNC_TEMPLATE_FUNC_PARAMS_10 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_10 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_10 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10 + +#define FUNC_TEMPLATE_ARG_PARAMS_11 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_11 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11 +#define FUNC_ARG_MEMBERS_11 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11 +#define FUNC_ARG_FORMAL_PARAMS_11 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_11 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11 +#define FUNC_CALL_ARGS_INIT_11 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ) +#define FUNC_CALL_MEMBER_ARGS_11 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11 +#define FUNC_CALL_ARGS_11 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 +#define FUNC_FUNCTOR_CALL_ARGS_11 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 +#define FUNC_TEMPLATE_FUNC_PARAMS_11 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_11 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_11 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11 + +#define FUNC_TEMPLATE_ARG_PARAMS_12 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_12 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12 +#define FUNC_ARG_MEMBERS_12 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12 +#define FUNC_ARG_FORMAL_PARAMS_12 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_12 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12 +#define FUNC_CALL_ARGS_INIT_12 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ) +#define FUNC_CALL_MEMBER_ARGS_12 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12 +#define FUNC_CALL_ARGS_12 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 +#define FUNC_FUNCTOR_CALL_ARGS_12 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 +#define FUNC_TEMPLATE_FUNC_PARAMS_12 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_12 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_12 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12 + +#define FUNC_TEMPLATE_ARG_PARAMS_13 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_13 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13 +#define FUNC_ARG_MEMBERS_13 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13 +#define FUNC_ARG_FORMAL_PARAMS_13 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_13 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13 +#define FUNC_CALL_ARGS_INIT_13 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ) +#define FUNC_CALL_MEMBER_ARGS_13 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13 +#define FUNC_CALL_ARGS_13 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 +#define FUNC_FUNCTOR_CALL_ARGS_13 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 +#define FUNC_TEMPLATE_FUNC_PARAMS_13 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_13 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_13 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13 + +#define FUNC_TEMPLATE_ARG_PARAMS_14 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_14 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14 +#define FUNC_ARG_MEMBERS_14 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13; ARG_TYPE_14 m_arg14 +#define FUNC_ARG_FORMAL_PARAMS_14 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_14 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14 +#define FUNC_CALL_ARGS_INIT_14 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 ) +#define FUNC_CALL_MEMBER_ARGS_14 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14 +#define FUNC_CALL_ARGS_14 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 +#define FUNC_FUNCTOR_CALL_ARGS_14 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 +#define FUNC_TEMPLATE_FUNC_PARAMS_14 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13, typename FUNC_ARG_TYPE_14 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_14 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14 +#define FUNC_ADDL_TEMPLATE_FUNC_PARAMS_14 , FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14 + +#define FUNC_GENERATE_ALL( INNERMACRONAME ) \ + INNERMACRONAME(0); \ + INNERMACRONAME(1); \ + INNERMACRONAME(2); \ + INNERMACRONAME(3); \ + INNERMACRONAME(4); \ + INNERMACRONAME(5); \ + INNERMACRONAME(6); \ + INNERMACRONAME(7); \ + INNERMACRONAME(8); \ + INNERMACRONAME(9); \ + INNERMACRONAME(10);\ + INNERMACRONAME(11);\ + INNERMACRONAME(12);\ + INNERMACRONAME(13);\ + INNERMACRONAME(14) + +//----------------------------------------------------------------------------- +// +// Purpose: Base class of all function objects +// +//----------------------------------------------------------------------------- + +abstract_class CFunctor : public IRefCounted +{ +public: + CFunctor() + { +#ifdef DEBUG + m_nUserID = 0; +#endif + } + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~CFunctor() {} + + virtual void operator()() = 0; + + unsigned m_nUserID; // For debugging +}; + + +//----------------------------------------------------------------------------- +// When calling through a functor, care needs to be taken to not pass objects that might go away. +// Since this code determines the type to store in the functor based on the actual arguments, +// this is achieved by changing the point of call. +// +// See also CUtlEnvelope +//----------------------------------------------------------------------------- + +// convert a reference to a passable value +template +inline T RefToVal(const T &item) +{ + return item; +} + +//----------------------------------------------------------------------------- +// This class can be used to pass into a functor a proxy object for a pointer +// to be resolved later. For example, you can execute a "call" on a resource +// whose actual value is not known until a later time +//----------------------------------------------------------------------------- + +template +class CLateBoundPtr +{ +public: + CLateBoundPtr( T **ppObject ) + : m_ppObject( ppObject ) + { + } + + T *operator->() { return *m_ppObject; } + T &operator *() { return **m_ppObject; } + operator T *() const { return (T*)(*m_ppObject); } + operator void *() { return *m_ppObject; } + +private: + T **m_ppObject; +}; + +//----------------------------------------------------------------------------- +// +// Purpose: Classes to define memory management policies when operating +// on pointers to members +// +//----------------------------------------------------------------------------- + +class CFuncMemPolicyNone +{ +public: + static void OnAcquire(void *pObject) {} + static void OnRelease(void *pObject) {} +}; + +template +class CFuncMemPolicyRefCount +{ +public: + static void OnAcquire(OBJECT_TYPE_PTR pObject) { pObject->AddRef(); } + static void OnRelease(OBJECT_TYPE_PTR pObject) { pObject->Release(); } +}; + +//----------------------------------------------------------------------------- +// +// Purpose: Function proxy is a generic facility for holding a function +// pointer. Can be used on own, though primarily for use +// by this file +// +//----------------------------------------------------------------------------- + +template +class CMemberFuncProxyBase +{ +protected: + CMemberFuncProxyBase( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied ) + : m_pObject( pObject ), + m_pfnProxied( pfnProxied ) + { + MEM_POLICY::OnAcquire(m_pObject); + } + + ~CMemberFuncProxyBase() + { + MEM_POLICY::OnRelease(m_pObject); + } + + void Set( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied ) + { + m_pfnProxied = pfnProxied; + m_pObject = pObject; + } + + void OnCall() + { + Assert( (void *)m_pObject != NULL ); + } + + FUNCTION_TYPE m_pfnProxied; + OBJECT_TYPE_PTR m_pObject; +}; + + +#define DEFINE_MEMBER_FUNC_PROXY( N ) \ + template \ + class CMemberFuncProxy##N : public CMemberFuncProxyBase \ + { \ + public: \ + CMemberFuncProxy##N( OBJECT_TYPE_PTR pObject = NULL, FUNCTION_TYPE pfnProxied = NULL ) \ + : CMemberFuncProxyBase( pObject, pfnProxied ) \ + { \ + } \ + \ + void operator()( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \ + { \ + this->OnCall(); \ + ((*this->m_pObject).*this->m_pfnProxied)( FUNC_CALL_ARGS_##N ); \ + } \ + } + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_PROXY ); + + +//----------------------------------------------------------------------------- +// +// The actual functor implementation +// +//----------------------------------------------------------------------------- + +#include "tier0/memdbgon.h" + +typedef CRefCounted1 CFunctorBase; + +#define DEFINE_FUNCTOR_TEMPLATE(N) \ + template \ + class CFunctor##N : public CFunctorBase \ + { \ + public: \ + CFunctor##N( FUNC_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_pfnProxied( pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \ + void operator()() { m_pfnProxied(FUNC_CALL_MEMBER_ARGS_##N); } \ + \ + private: \ + FUNC_TYPE m_pfnProxied; \ + FUNC_ARG_MEMBERS_##N; \ + } + +FUNC_GENERATE_ALL( DEFINE_FUNCTOR_TEMPLATE ); + +#define DEFINE_MEMBER_FUNCTOR( N ) \ + template \ + class CMemberFunctor##N : public FUNCTOR_BASE \ + { \ + public: \ + CMemberFunctor##N( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_Proxy( pObject, pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \ + void operator()() { m_Proxy(FUNC_CALL_MEMBER_ARGS_##N); } \ + \ + private: \ + CMemberFuncProxy##N m_Proxy; \ + FUNC_ARG_MEMBERS_##N; \ + }; + + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR ); + +//----------------------------------------------------------------------------- +// +// The real magic, letting the compiler figure out all the right template parameters +// +//----------------------------------------------------------------------------- + +#define DEFINE_NONMEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateFunctor(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \ + return new CFunctor##N( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } + +FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_MEMBER_FUNCTOR_FACTORY(N) \ +template \ +inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + return new CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY ); + +//----------------------------------------------------------------------------- +// +// Templates to assist early-out direct call code +// +//----------------------------------------------------------------------------- + +#define DEFINE_NONMEMBER_FUNCTOR_DIRECT(N) \ + template \ + inline void FunctorDirectCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + (*pfnProxied)( FUNC_CALL_ARGS_##N ); \ +} + +FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_DIRECT ); + + +//------------------------------------- + +#define DEFINE_MEMBER_FUNCTOR_DIRECT(N) \ + template \ + inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_DIRECT ); + +//------------------------------------- + +#define DEFINE_CONST_MEMBER_FUNCTOR_DIRECT(N) \ + template \ + inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_DIRECT ); + +#include "tier0/memdbgoff.h" + +//----------------------------------------------------------------------------- +// Factory class useable as templated traits +//----------------------------------------------------------------------------- + +class CDefaultFunctorFactory +{ +public: + FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY ); +}; + +template +class CCustomizedFunctorFactory +{ +public: + void SetAllocator( CAllocator *pAllocator ) + { + m_pAllocator = pAllocator; + } + + #define DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateFunctor( FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \ + return new (m_pAllocator->Alloc( sizeof(CFunctor##N) )) CFunctor##N( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } + + FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N) )) CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N) )) CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N >) )) CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N >) )) CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + +private: + CAllocator *m_pAllocator; + +}; + +//----------------------------------------------------------------------------- + +#endif // FUNCTORS_H diff --git a/public/tier1/generichash.h b/public/tier1/generichash.h new file mode 100644 index 0000000..59b8b61 --- /dev/null +++ b/public/tier1/generichash.h @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Variant Pearson Hash general purpose hashing algorithm described +// by Cargill in C++ Report 1994. Generates a 16-bit result. +// +//============================================================================= + +#ifndef GENERICHASH_H +#define GENERICHASH_H + +#if defined(_WIN32) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +unsigned FASTCALL HashString( const char *pszKey ); +unsigned FASTCALL HashStringCaseless( const char *pszKey ); +unsigned FASTCALL HashStringCaselessConventional( const char *pszKey ); +unsigned FASTCALL Hash4( const void *pKey ); +unsigned FASTCALL Hash8( const void *pKey ); +unsigned FASTCALL Hash12( const void *pKey ); +unsigned FASTCALL Hash16( const void *pKey ); +unsigned FASTCALL HashBlock( const void *pKey, unsigned size ); + +unsigned FASTCALL HashInt( const int key ); + +// hash a uint32 into a uint32 +FORCEINLINE uint32 HashIntAlternate( uint32 n) +{ + n = ( n + 0x7ed55d16 ) + ( n << 12 ); + n = ( n ^ 0xc761c23c ) ^ ( n >> 19 ); + n = ( n + 0x165667b1 ) + ( n << 5 ); + n = ( n + 0xd3a2646c ) ^ ( n << 9 ); + n = ( n + 0xfd7046c5 ) + ( n << 3 ); + n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 ); + return n; +} + +inline unsigned HashIntConventional( const int n ) // faster but less effective +{ + // first byte + unsigned hash = 0xAAAAAAAA + (n & 0xFF); + // second byte + hash = ( hash << 5 ) + hash + ( (n >> 8) & 0xFF ); + // third byte + hash = ( hash << 5 ) + hash + ( (n >> 16) & 0xFF ); + // fourth byte + hash = ( hash << 5 ) + hash + ( (n >> 24) & 0xFF ); + + return hash; + + /* this is the old version, which would cause a load-hit-store on every + line on a PowerPC, and therefore took hundreds of clocks to execute! + + byte *p = (byte *)&n; + unsigned hash = 0xAAAAAAAA + *p++; + hash = ( ( hash << 5 ) + hash ) + *p++; + hash = ( ( hash << 5 ) + hash ) + *p++; + return ( ( hash << 5 ) + hash ) + *p; + */ +} + +//----------------------------------------------------------------------------- + +template +inline unsigned HashItem( const T &item ) +{ + // TODO: Confirm comiler optimizes out unused paths + if ( sizeof(item) == 4 ) + return Hash4( &item ); + else if ( sizeof(item) == 8 ) + return Hash8( &item ); + else if ( sizeof(item) == 12 ) + return Hash12( &item ); + else if ( sizeof(item) == 16 ) + return Hash16( &item ); + else + return HashBlock( &item, sizeof(item) ); +} + +template <> inline unsigned HashItem(const int &key ) +{ + return HashInt( key ); +} + +template <> inline unsigned HashItem(const unsigned &key ) +{ + return HashInt( (int)key ); +} + +template<> inline unsigned HashItem(const char * const &pszKey ) +{ + return HashString( pszKey ); +} + +template<> inline unsigned HashItem(char * const &pszKey ) +{ + return HashString( pszKey ); +} + +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Murmur hash +//----------------------------------------------------------------------------- +uint32 MurmurHash2( const void * key, int len, uint32 seed ); + +// return murmurhash2 of a downcased string +uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed ); + +uint64 MurmurHash64( const void * key, int len, uint32 seed ); + + +#endif /* !GENERICHASH_H */ diff --git a/public/tier1/iconvar.h b/public/tier1/iconvar.h new file mode 100644 index 0000000..1ea5f7a --- /dev/null +++ b/public/tier1/iconvar.h @@ -0,0 +1,118 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//===========================================================================// + +#ifndef ICONVAR_H +#define ICONVAR_H + +#if _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "tier1/strtools.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IConVar; +class CCommand; + + +//----------------------------------------------------------------------------- +// ConVar flags +//----------------------------------------------------------------------------- +// The default, no flags at all +#define FCVAR_NONE 0 + +// Command to ConVars and ConCommands +// ConVar Systems +#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc. +#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined. +#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL +#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL +#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or autocomplete. Like DEVELOPMENTONLY, but can't be compiled out. + +// ConVar only +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc +#define FCVAR_NOTIFY (1<<8) // notifies players when changed +#define FCVAR_USERINFO (1<<9) // changes the client's info string +#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats + +#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar + +// It's a ConVar that's shared between the client and the server. +// At signon, the values of all such ConVars are sent from the server to the client (skipped for local +// client, of course ) +// If a change is requested it must come from the console (i.e., no remote client changes) +// If a value is changed while a server is active, it's replicated to all connected clients +#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time +#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file +#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles +#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload +#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload + +#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server +#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread +#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox + +#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars + +#define FCVAR_SERVER_CAN_EXECUTE (1<<28)// the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd. +#define FCVAR_SERVER_CANNOT_QUERY (1<<29)// If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue). +#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command. + // Note: IVEngineClient::ClientCmd_Unrestricted can run any client command. + +// #define FCVAR_AVAILABLE (1<<15) +// #define FCVAR_AVAILABLE (1<<18) +// #define FCVAR_AVAILABLE (1<<19) +// #define FCVAR_AVAILABLE (1<<20) +// #define FCVAR_AVAILABLE (1<<21) +// #define FCVAR_AVAILABLE (1<<23) +// #define FCVAR_AVAILABLE (1<<26) +// #define FCVAR_AVAILABLE (1<<27) +// #define FCVAR_AVAILABLE (1<<31) + +#define FCVAR_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD ) + +//----------------------------------------------------------------------------- +// Called when a ConVar changes value +// NOTE: For FCVAR_NEVER_AS_STRING ConVars, pOldValue == NULL +//----------------------------------------------------------------------------- +typedef void ( *FnChangeCallback_t )( IConVar *var, const char *pOldValue, float flOldValue ); + + +//----------------------------------------------------------------------------- +// Abstract interface for ConVars +//----------------------------------------------------------------------------- +abstract_class IConVar +{ +public: + // Value set + virtual void SetValue( const char *pValue ) = 0; + virtual void SetValue( float flValue ) = 0; + virtual void SetValue( int nValue ) = 0; + + // Return name of command + virtual const char *GetName( void ) const = 0; + + // Accessors.. not as efficient as using GetState()/GetInfo() + // if you call these methods multiple times on the same IConVar + virtual bool IsFlagSet( int nFlag ) const = 0; +}; + + +#endif // ICONVAR_H diff --git a/public/tier1/ilocalize.h b/public/tier1/ilocalize.h new file mode 100644 index 0000000..cbdb8f6 --- /dev/null +++ b/public/tier1/ilocalize.h @@ -0,0 +1,453 @@ + +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef TIER1_ILOCALIZE_H +#define TIER1_ILOCALIZE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" +#include + +// unicode character type +// for more unicode manipulation functions #include +#if !defined(_WCHAR_T_DEFINED) && !defined(GNUC) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + + +// direct references to localized strings +typedef unsigned long StringIndex_t; +const unsigned long INVALID_LOCALIZE_STRING_INDEX = (StringIndex_t) -1; + +//----------------------------------------------------------------------------- +// Purpose: Handles localization of text +// looks up string names and returns the localized unicode text +//----------------------------------------------------------------------------- +abstract_class ILocalize +{ +public: + // adds the contents of a file to the localization table + virtual bool AddFile( const char *fileName, const char *pPathID = NULL, bool bIncludeFallbackSearchPaths = false ) = 0; + + // Remove all strings from the table + virtual void RemoveAll() = 0; + + // Finds the localized text for tokenName + virtual wchar_t *Find(char const *tokenName) = 0; + + // finds the index of a token by token name, INVALID_STRING_INDEX if not found + virtual StringIndex_t FindIndex(const char *tokenName) = 0; + + // gets the values by the string index + virtual const char *GetNameByIndex(StringIndex_t index) = 0; + virtual wchar_t *GetValueByIndex(StringIndex_t index) = 0; + + /////////////////////////////////////////////////////////////////// + // the following functions should only be used by localization editors + + // iteration functions + virtual StringIndex_t GetFirstStringIndex() = 0; + // returns the next index, or INVALID_STRING_INDEX if no more strings available + virtual StringIndex_t GetNextStringIndex(StringIndex_t index) = 0; + + // adds a single name/unicode string pair to the table + virtual void AddString( const char *tokenName, wchar_t *unicodeString, const char *fileName ) = 0; + + // changes the value of a string + virtual void SetValueByIndex(StringIndex_t index, wchar_t *newValue) = 0; + + // saves the entire contents of the token tree to the file + virtual bool SaveToFile( const char *fileName ) = 0; + + // iterates the filenames + virtual int GetLocalizationFileCount() = 0; + virtual const char *GetLocalizationFileName(int index) = 0; + + // returns the name of the file the specified localized string is stored in + virtual const char *GetFileNameByIndex(StringIndex_t index) = 0; + + // for development only, reloads localization files + virtual void ReloadLocalizationFiles( ) = 0; + + virtual const char *FindAsUTF8( const char *pchTokenName ) = 0; + + // need to replace the existing ConstructString with this + virtual void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const char *tokenName, KeyValues *localizationVariables) = 0; + virtual void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, StringIndex_t unlocalizedTextSymbol, KeyValues *localizationVariables) = 0; + + /////////////////////////////////////////////////////////////////// + // static interface + + // converts an english string to unicode + // returns the number of wchar_t in resulting string, including null terminator + static int ConvertANSIToUnicode(const char *ansi, OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicode, int unicodeBufferSizeInBytes); + + // converts an unicode string to an english string + // unrepresentable characters are converted to system default + // returns the number of characters in resulting string, including null terminator + static int ConvertUnicodeToANSI(const wchar_t *unicode, OUT_Z_BYTECAP(ansiBufferSize) char *ansi, int ansiBufferSize); + + // builds a localized formatted string + // uses the format strings first: %s1, %s2, ... unicode strings (wchar_t *) + template < typename T > + static void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T *unicodeOuput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, ...) + { + va_list argList; + va_start( argList, numFormatParameters ); + + ConstructStringVArgsInternal( unicodeOuput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList ); + + va_end( argList ); + } + + template < typename T > + static void ConstructStringVArgs(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T *unicodeOuput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, va_list argList) + { + ConstructStringVArgsInternal( unicodeOuput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList ); + } + + template < typename T > + static void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, KeyValues *localizationVariables) + { + ConstructStringKeyValuesInternal( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables ); + } + +private: + // internal "interface" + static void ConstructStringVArgsInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, int numFormatParameters, va_list argList); + static void ConstructStringVArgsInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, int numFormatParameters, va_list argList); + + static void ConstructStringKeyValuesInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, KeyValues *localizationVariables); + static void ConstructStringKeyValuesInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, KeyValues *localizationVariables); +}; + +#ifdef GC + + typedef char locchar_t; + + #define loc_snprintf Q_snprintf + #define loc_sprintf_safe V_sprintf_safe + #define loc_sncat Q_strncat + #define loc_scat_safe V_strcat_safe + #define loc_sncpy Q_strncpy + #define loc_scpy_safe V_strcpy_safe + #define loc_strlen Q_strlen + #define LOCCHAR( x ) x + +#else + + typedef wchar_t locchar_t; + + #define loc_snprintf V_snwprintf + #define loc_sprintf_safe V_swprintf_safe + #define loc_sncat V_wcsncat + #define loc_scat_safe V_wcscat_safe + #define loc_sncpy Q_wcsncpy + #define loc_scpy_safe V_wcscpy_safe + #define loc_strlen Q_wcslen + #define LOCCHAR(x) L ## x + +#endif + +// -------------------------------------------------------------------------- +// Purpose: +// -------------------------------------------------------------------------- + +template < typename T > +class TypedKeyValuesStringHelper +{ +public: + static const T *Read( KeyValues *pKeyValues, const char *pKeyName, const T *pDefaultValue ); + static void Write( KeyValues *pKeyValues, const char *pKeyName, const T *pValue ); +}; + +// -------------------------------------------------------------------------- + +template < > +class TypedKeyValuesStringHelper +{ +public: + static const char *Read( KeyValues *pKeyValues, const char *pKeyName, const char *pDefaultValue ) { return pKeyValues->GetString( pKeyName, pDefaultValue ); } + static void Write( KeyValues *pKeyValues, const char *pKeyName, const char *pValue ) { pKeyValues->SetString( pKeyName, pValue ); } +}; + +// -------------------------------------------------------------------------- + +template < > +class TypedKeyValuesStringHelper +{ +public: + static const wchar_t *Read( KeyValues *pKeyValues, const char *pKeyName, const wchar_t *pDefaultValue ) { return pKeyValues->GetWString( pKeyName, pDefaultValue ); } + static void Write( KeyValues *pKeyValues, const char *pKeyName, const wchar_t *pValue ) { pKeyValues->SetWString( pKeyName, pValue ); } +}; + +// -------------------------------------------------------------------------- +// Purpose: CLocalizedStringArg<> is a class that will take a variable of any +// arbitary type and convert it to a string of whatever character type +// we're using for localization (locchar_t). +// +// Independently it isn't very useful, though it can be used to sort-of- +// intelligently fill out the correct format string. It's designed to be +// used for the arguments of CConstructLocalizedString, which can be of +// arbitrary number and type. +// +// If you pass in a (non-specialized) pointer, the code will assume that +// you meant that pointer to be used as a localized string. This will +// still fail to compile if some non-string type is passed in, but will +// handle weird combinations of const/volatile/whatever automatically. +// -------------------------------------------------------------------------- + +// The base implementation doesn't do anything except fail to compile if you +// use it. Getting an "incomplete type" error here means that you tried to construct +// a localized string with a type that doesn't have a specialization. +template < typename T > +class CLocalizedStringArg; + +// -------------------------------------------------------------------------- + +template < typename T > +class CLocalizedStringArgStringImpl +{ +public: + enum { kIsValid = true }; + + CLocalizedStringArgStringImpl( const locchar_t *pStr ) : m_pStr( pStr ) { } + + const locchar_t *GetLocArg() const { Assert( m_pStr ); return m_pStr; } + +private: + const locchar_t *m_pStr; +}; + +// -------------------------------------------------------------------------- + +template < typename T > +class CLocalizedStringArg : public CLocalizedStringArgStringImpl +{ +public: + CLocalizedStringArg( const locchar_t *pStr ) : CLocalizedStringArgStringImpl( pStr ) { } +}; + +// -------------------------------------------------------------------------- + +template < typename T > +class CLocalizedStringArgPrintfImpl +{ +public: + enum { kIsValid = true }; + + CLocalizedStringArgPrintfImpl( T value, const locchar_t *loc_Format ) { loc_snprintf( m_cBuffer, kBufferSize, loc_Format, value ); } + + const locchar_t *GetLocArg() const { return m_cBuffer; } + +private: + enum { kBufferSize = 128, }; + locchar_t m_cBuffer[ kBufferSize ]; +}; + +// -------------------------------------------------------------------------- + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg( uint16 unValue ) : CLocalizedStringArgPrintfImpl( unValue, LOCCHAR("%u") ) { } +}; + +// -------------------------------------------------------------------------- + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg( uint32 unValue ) : CLocalizedStringArgPrintfImpl( unValue, LOCCHAR("%u") ) { } +}; + +// -------------------------------------------------------------------------- + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg( uint64 unValue ) : CLocalizedStringArgPrintfImpl( unValue, LOCCHAR("%llu") ) { } +}; + +// -------------------------------------------------------------------------- + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + // Display one decimal point if we've got a value less than one, and no point + // if we're greater than one or are effectively zero. + CLocalizedStringArg( float fValue ) + : CLocalizedStringArgPrintfImpl( fValue, + fabsf( fValue ) <= FLT_EPSILON || fabsf( fValue ) >= 1.0f ? LOCCHAR("%.0f") : LOCCHAR("%.1f") ) + { + // + } +}; + +// -------------------------------------------------------------------------- +// Purpose: +// -------------------------------------------------------------------------- +class CConstructLocalizedString +{ +public: + template < typename T > + CConstructLocalizedString( const locchar_t *loc_Format, T arg0 ) + { + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + + m_loc_Buffer[0] = '\0'; + + if ( loc_Format ) + { + ::ILocalize::ConstructString( m_loc_Buffer, sizeof( m_loc_Buffer ), loc_Format, 1, CLocalizedStringArg( arg0 ).GetLocArg() ); + } + } + + template < typename T, typename U > + CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1 ) + { + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + + m_loc_Buffer[0] = '\0'; + + if ( loc_Format ) + { + ::ILocalize::ConstructString( m_loc_Buffer, sizeof( m_loc_Buffer ), loc_Format, 2, CLocalizedStringArg( arg0 ).GetLocArg(), CLocalizedStringArg( arg1 ).GetLocArg() ); + } + } + + template < typename T, typename U, typename V > + CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2 ) + { + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + + m_loc_Buffer[0] = '\0'; + + if ( loc_Format ) + { + ::ILocalize::ConstructString( m_loc_Buffer, + sizeof( m_loc_Buffer ), + loc_Format, + 3, + CLocalizedStringArg( arg0 ).GetLocArg(), + CLocalizedStringArg( arg1 ).GetLocArg(), + CLocalizedStringArg( arg2 ).GetLocArg() ); + } + } + + template < typename T, typename U, typename V, typename W > + CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3 ) + { + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + + m_loc_Buffer[0] = '\0'; + + if ( loc_Format ) + { + ::ILocalize::ConstructString( m_loc_Buffer, + sizeof( m_loc_Buffer ), + loc_Format, + 4, + CLocalizedStringArg( arg0 ).GetLocArg(), + CLocalizedStringArg( arg1 ).GetLocArg(), + CLocalizedStringArg( arg2 ).GetLocArg(), + CLocalizedStringArg( arg3 ).GetLocArg() ); + } + } + + template < typename T, typename U, typename V, typename W, typename X, typename Y > + CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4, Y arg5 ) + { + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + + m_loc_Buffer[0] = '\0'; + + if ( loc_Format ) + { + ::ILocalize::ConstructString( m_loc_Buffer, + sizeof( m_loc_Buffer ), + loc_Format, + 6, + CLocalizedStringArg( arg0 ).GetLocArg(), + CLocalizedStringArg( arg1 ).GetLocArg(), + CLocalizedStringArg( arg2 ).GetLocArg(), + CLocalizedStringArg( arg3 ).GetLocArg(), + CLocalizedStringArg( arg4 ).GetLocArg(), + CLocalizedStringArg( arg5 ).GetLocArg() ); + } + } + + template < typename T, typename U, typename V, typename W, typename X, typename Y, typename Z > + CConstructLocalizedString( const locchar_t *loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4, Y arg5, Z arg6) + { + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + COMPILE_TIME_ASSERT( CLocalizedStringArg::kIsValid ); + + m_loc_Buffer[0] = '\0'; + + if ( loc_Format ) + { + ::ILocalize::ConstructString( m_loc_Buffer, + sizeof( m_loc_Buffer ), + loc_Format, + 7, + CLocalizedStringArg( arg0 ).GetLocArg(), + CLocalizedStringArg( arg1 ).GetLocArg(), + CLocalizedStringArg( arg2 ).GetLocArg(), + CLocalizedStringArg( arg3 ).GetLocArg(), + CLocalizedStringArg( arg4 ).GetLocArg(), + CLocalizedStringArg( arg5 ).GetLocArg(), + CLocalizedStringArg( arg6 ).GetLocArg() ); + } + } + + CConstructLocalizedString( const locchar_t *loc_Format, KeyValues *pKeyValues ) + { + m_loc_Buffer[0] = '\0'; + + if ( loc_Format && pKeyValues ) + { + ::ILocalize::ConstructString( m_loc_Buffer, sizeof( m_loc_Buffer ), loc_Format, pKeyValues ); + } + } + + operator const locchar_t *() const + { + return m_loc_Buffer; + } + +private: + enum { kBufferSize = 512, }; + locchar_t m_loc_Buffer[ kBufferSize ]; +}; + +#endif // TIER1_ILOCALIZE_H diff --git a/public/tier1/interface.h b/public/tier1/interface.h new file mode 100644 index 0000000..5453f67 --- /dev/null +++ b/public/tier1/interface.h @@ -0,0 +1,230 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// This header defines the interface convention used in the valve engine. +// To make an interface and expose it: +// 1. The interface must be ALL pure virtuals, and have no data members. +// 2. Define a name for it. +// 3. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. + +// Versioning +// There are two versioning cases that are handled by this: +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// expose it for the old interface. + +// Static Linking: +// Must mimic unique seperate class 'InterfaceReg' constructors per subsystem. +// Each subsystem can then import and export interfaces as expected. +// This is achieved through unique namespacing 'InterfaceReg' via symbol _SUBSYSTEM. +// Static Linking also needs to generate unique symbols per interface so as to +// provide a 'stitching' method whereby these interface symbols can be referenced +// via the lib's primary module (usually the lib's interface exposure) +// therby stitching all of that lib's code/data together for eventual final exe link inclusion. + +#ifndef INTERFACE_H +#define INTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _LINUX +#include // dlopen,dlclose, et al +#include + +#define GetProcAddress dlsym + +#ifdef _snprintf +#undef _snprintf +#endif +#define _snprintf snprintf +#endif + +// TODO: move interface.cpp into tier0 library. +#include "tier0/platform.h" + +// All interfaces derive from this. +class IBaseInterface +{ +public: + virtual ~IBaseInterface() {} +}; + +#if !defined( _X360 ) +#define CREATEINTERFACE_PROCNAME "CreateInterface" +#else +// x360 only allows ordinal exports, .def files export "CreateInterface" at 1 +#define CREATEINTERFACE_PROCNAME ((const char*)1) +#endif + +typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); +typedef void* (*InstantiateInterfaceFn)(); + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + +public: + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; + + InterfaceReg *m_pNext; // For the global list. + static InterfaceReg *s_pInterfaceRegs; +}; + +// Use this to expose an interface that can have multiple instances. +// e.g.: +// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// This will expose a class called CInterfaceImp that implements IInterface (a pure class) +// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// +// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") +// so that each component can use these names/vtables to communicate +// +// A single class can support multiple interfaces through multiple inheritance +// +// Use this if you want to write the factory function. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); +#else +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \ + } +#endif + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static void* __Create##className##_interface() {return static_cast( new className );} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); +#else +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##_interface() {return static_cast( new className );} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \ + } +#endif + +// Use this to expose a singleton interface with a global variable you've created. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \ + static void* __Create##className##interfaceName##_interface() {return static_cast( &globalVarName );} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); +#else +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##interfaceName##_interface() {return static_cast( &globalVarName );} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \ + } +#endif + +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, , interfaceName, versionName, globalVarName) + +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#else +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static className __g_##className##_singleton; \ + } \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#endif + +// load/unload components +class CSysModule; + +// interface return status +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + +//----------------------------------------------------------------------------- +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values (IFACE_OK, IFACE_FAILED) +// extend this for other error conditions/code +//----------------------------------------------------------------------------- +DLL_EXPORT void* CreateInterface(const char *pName, int *pReturnCode); + +#if defined( _X360 ) +DLL_EXPORT void *CreateInterfaceThunk( const char *pName, int *pReturnCode ); +#endif + +//----------------------------------------------------------------------------- +// UNDONE: This is obsolete, use the module load/unload/get instead!!! +//----------------------------------------------------------------------------- +extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ); +extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName ); +extern CreateInterfaceFn Sys_GetFactoryThis( void ); + +enum Sys_Flags +{ + SYS_NOFLAGS = 0x00, + SYS_NOLOAD = 0x01 // no loading, no ref-counting, only returns handle if lib is loaded. +}; + +//----------------------------------------------------------------------------- +// Load & Unload should be called in exactly one place for each module +// The factory for that module should be passed on to dependent components for +// proper versioning. +//----------------------------------------------------------------------------- +extern CSysModule *Sys_LoadModule( const char *pModuleName, Sys_Flags flags = SYS_NOFLAGS ); +extern void Sys_UnloadModule( CSysModule *pModule ); + +// This is a helper function to load a module, get its factory, and get a specific interface. +// You are expected to free all of these things. +// Returns false and cleans up if any of the steps fail. +bool Sys_LoadInterface( + const char *pModuleName, + const char *pInterfaceVersionName, + CSysModule **pOutModule, + void **pOutInterface ); + +bool Sys_IsDebuggerPresent(); + +//----------------------------------------------------------------------------- +// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name. +// +// When the singleton goes out of scope (.dll unload if at module scope), +// then it'll call Sys_UnloadModule on the module so that the refcount is decremented +// and the .dll actually can unload from memory. +//----------------------------------------------------------------------------- +class CDllDemandLoader +{ +public: + CDllDemandLoader( char const *pchModuleName ); + virtual ~CDllDemandLoader(); + CreateInterfaceFn GetFactory(); + void Unload(); + +private: + + char const *m_pchModuleName; + CSysModule *m_hModule; + bool m_bLoadAttempted; +}; + +#endif + + + diff --git a/public/tier1/kvpacker.h b/public/tier1/kvpacker.h new file mode 100644 index 0000000..7e47fa1 --- /dev/null +++ b/public/tier1/kvpacker.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef KVPACKER_H +#define KVPACKER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "KeyValues.h" + +//----------------------------------------------------------------------------- +// Purpose: Handles packing KeyValues binary packing and unpacking in a a +// consistent way across all branches, including Steam. If you change +// this packing format you need to do so in a backward compatible way +// so that the Steam servers and all the various GCs can still talk to +// each other. +//----------------------------------------------------------------------------- +class KVPacker +{ +public: + bool WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer ); + bool ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer ); + +private: + // These types are used for serialization of KeyValues nodes. + // Do not renumber them or you will break serialization across + // branches. + enum EPackType + { + PACKTYPE_NONE = 0, + PACKTYPE_STRING, + PACKTYPE_INT, + PACKTYPE_FLOAT, + PACKTYPE_PTR, + PACKTYPE_WSTRING, + PACKTYPE_COLOR, + PACKTYPE_UINT64, + PACKTYPE_NULLMARKER, // used to mark the end of a block in the binary format + }; +}; + + +#endif // KVPACKER_H diff --git a/public/tier1/lzmaDecoder.h b/public/tier1/lzmaDecoder.h new file mode 100644 index 0000000..6f4b87f --- /dev/null +++ b/public/tier1/lzmaDecoder.h @@ -0,0 +1,102 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// LZMA Codec interface for engine. +// +// LZMA SDK 9.38 beta +// 2015-01-03 : Igor Pavlov : Public domain +// http://www.7-zip.org/ +// +//========================================================================// + +#ifndef _LZMADECODER_H +#define _LZMADECODER_H +#pragma once + +// Thanks for the useful define namespacing, LZMA +#include "../../utils/lzma/C/7zVersion.h" +#define LZMA_SDK_VERSION_MAJOR MY_VER_MAJOR +#define LZMA_SDK_VERSION_MINOR MY_VER_MINOR + +#if !defined( _X360 ) +#define LZMA_ID (('A'<<24)|('M'<<16)|('Z'<<8)|('L')) +#else +#define LZMA_ID (('L'<<24)|('Z'<<16)|('M'<<8)|('A')) +#endif + +// bind the buffer for correct identification +#pragma pack(1) +struct lzma_header_t +{ + unsigned int id; + unsigned int actualSize; // always little endian + unsigned int lzmaSize; // always little endian + unsigned char properties[5]; +}; +#pragma pack() + +class CLZMAStream; + +class CLZMA +{ +public: + static unsigned int Uncompress( unsigned char *pInput, unsigned char *pOutput ); + static bool IsCompressed( unsigned char *pInput ); + static unsigned int GetActualSize( unsigned char *pInput ); +}; + +// For files besides the implementation, we forward declare a dummy struct. We can't unconditionally forward declare +// this because LzmaEnc.h typedefs this directly to an unnamed struct :-/ +#ifndef CLzmaDec_t +struct _CLzmaDec_t; +#define CLzmaDec_t struct _CLzmaDec_t +#endif + +class CLZMAStream +{ +public: + CLZMAStream(); + ~CLZMAStream(); + + // Initialize a stream to read data from a LZMA style zip file, passing the original size from the zip headers. + // Streams with a source-engine style header (lzma_header_t) do not need an init call. + void InitZIPHeader( unsigned int nCompressedSize, unsigned int nOriginalSize ); + + // Attempt to read up to nMaxInputBytes from the compressed stream, writing up to nMaxOutputBytes to pOutput. + // Makes progress until blocked on input or output. + // Returns false if read stops due to an error or if called at EOF (GetExpectedBytesRemaining == 0) + bool Read( unsigned char *pInput, unsigned int nMaxInputBytes, + unsigned char *pOutput, unsigned int nMaxOutputBytes, + /* out */ unsigned int &nCompressedBytesRead, /* out */ unsigned int &nOutputBytesWritten ); + + // Get the expected uncompressed bytes yet to be read from this stream. Returns false if not yet known, such as + // before being fed the header. + bool GetExpectedBytesRemaining( /* out */ unsigned int &nBytesRemaining ); + +private: + enum eHeaderParse + { + eHeaderParse_OK, + eHeaderParse_Fail, + eHeaderParse_NeedMoreBytes + }; + + eHeaderParse TryParseHeader( unsigned char *pInput, unsigned int nBytesAvailable, /* out */ unsigned int &nBytesConsumed ); + + void FreeDecoderState(); + bool CreateDecoderState( const unsigned char *pProperties ); + + // Init from a zip-embedded LZMA stream. Requires the original size be passed from zip headers. + CLzmaDec_t *m_pDecoderState; + + unsigned int m_nActualSize; + unsigned int m_nActualBytesRead; + unsigned int m_nCompressedSize; + unsigned int m_nCompressedBytesRead; + + // If we have read past the header + bool m_bParsedHeader : 1; + // If InitZIPHeader() was called. We're expecting a zip-style header and have size information. + bool m_bZIPStyleHeader : 1; +}; + +#endif diff --git a/public/tier1/lzss.h b/public/tier1/lzss.h new file mode 100644 index 0000000..8b3409a --- /dev/null +++ b/public/tier1/lzss.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// LZSS Codec. Designed for fast cheap gametime encoding/decoding. Compression results +// are not aggresive as other alogrithms, but gets 2:1 on most arbitrary uncompressed data. +// +//=====================================================================================// + +#ifndef _LZSS_H +#define _LZSS_H +#pragma once + +#define LZSS_ID uint32( BigLong( ('L'<<24)|('Z'<<16)|('S'<<8)|('S') ) ) +#define SNAPPY_ID uint32( BigLong( ('S'<<24)|('N'<<16)|('A'<<8)|('P') ) ) + +// bind the buffer for correct identification +struct lzss_header_t +{ + unsigned int id; + unsigned int actualSize; // always little endian +}; + +class CUtlBuffer; + +#define DEFAULT_LZSS_WINDOW_SIZE 4096 + +class CLZSS +{ +public: + unsigned char* Compress( const unsigned char *pInput, int inputlen, unsigned int *pOutputSize ); + unsigned char* CompressNoAlloc( const unsigned char *pInput, int inputlen, unsigned char *pOutput, unsigned int *pOutputSize ); + unsigned int Uncompress( const unsigned char *pInput, unsigned char *pOutput ); + //unsigned int Uncompress( unsigned char *pInput, CUtlBuffer &buf ); + unsigned int SafeUncompress( const unsigned char *pInput, unsigned char *pOutput, unsigned int unBufSize ); + + static bool IsCompressed( const unsigned char *pInput ); + static unsigned int GetActualSize( const unsigned char *pInput ); + + // windowsize must be a power of two. + FORCEINLINE CLZSS( int nWindowSize = DEFAULT_LZSS_WINDOW_SIZE ); + +private: + // expected to be sixteen bytes + struct lzss_node_t + { + const unsigned char *pData; + lzss_node_t *pPrev; + lzss_node_t *pNext; + char empty[4]; + }; + + struct lzss_list_t + { + lzss_node_t *pStart; + lzss_node_t *pEnd; + }; + + void BuildHash( const unsigned char *pData ); + lzss_list_t *m_pHashTable; + lzss_node_t *m_pHashTarget; + int m_nWindowSize; + +}; + +FORCEINLINE CLZSS::CLZSS( int nWindowSize ) +{ + m_nWindowSize = nWindowSize; +} +#endif + diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h new file mode 100644 index 0000000..01d3a33 --- /dev/null +++ b/public/tier1/mempool.h @@ -0,0 +1,559 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/memalloc.h" +#include "tier0/tslist.h" +#include "tier0/platform.h" +#include "tier1/utlvector.h" +#include "tier1/utlrbtree.h" + +//----------------------------------------------------------------------------- +// Purpose: Optimized pool memory allocator +//----------------------------------------------------------------------------- + +typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... ); + +// Ways a memory pool can grow when it needs to make a new blob: +enum MemoryPoolGrowType_t +{ + UTLMEMORYPOOL_GROW_NONE=0, // Don't allow new blobs. + UTLMEMORYPOOL_GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates + // get larger and larger each time it allocates one). + UTLMEMORYPOOL_GROW_SLOW=2 // New blob size is numElements. +}; + +class CUtlMemoryPool +{ +public: + // !KLUDGE! For legacy code support, import the global enum into this scope + enum MemoryPoolGrowType_t + { + GROW_NONE=UTLMEMORYPOOL_GROW_NONE, + GROW_FAST=UTLMEMORYPOOL_GROW_FAST, + GROW_SLOW=UTLMEMORYPOOL_GROW_SLOW + }; + + CUtlMemoryPool( int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); + ~CUtlMemoryPool(); + + void* Alloc(); // Allocate the element size you specified in the constructor. + void* Alloc( size_t amount ); + void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction + void* AllocZero( size_t amount ); + void Free(void *pMem); + + // Frees everything + void Clear(); + + // Error reporting... + static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); + + // returns number of allocated blocks + int Count() { return m_BlocksAllocated; } + int PeakCount() { return m_PeakAlloc; } + +protected: + class CBlob + { + public: + CBlob *m_pPrev, *m_pNext; + int m_NumBytes; // Number of bytes in this blob. + char m_Data[1]; + char m_Padding[3]; // to int align the struct + }; + + // Resets the pool + void Init(); + void AddNewBlob(); + void ReportLeaks(); + + int m_BlockSize; + int m_BlocksPerBlob; + + int m_GrowMode; // GROW_ enum. + + // Put m_BlocksAllocated in front of m_pHeadOfFreeList for better + // packing on 64-bit where pointers are 8-byte aligned. + int m_BlocksAllocated; + // FIXME: Change m_ppMemBlob into a growable array? + void *m_pHeadOfFreeList; + int m_PeakAlloc; + unsigned short m_nAlignment; + unsigned short m_NumBlobs; + const char * m_pszAllocOwner; + // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned + CBlob m_BlobHead; + + static MemoryPoolReportFunc_t g_ReportFunc; +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CMemoryPoolMT : public CUtlMemoryPool +{ +public: + CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner) {} + + + void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } + void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); } + void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); } + void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); } + void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); } + + // Frees everything + void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); } +private: + CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007) +}; + + +//----------------------------------------------------------------------------- +// Wrapper macro to make an allocator that returns particular typed allocations +// and construction and destruction of objects. +//----------------------------------------------------------------------------- +template< class T > +class CClassMemoryPool : public CUtlMemoryPool +{ +public: + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : + CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) { + #ifdef PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 ); + #else + COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 ); + #endif + } + + T* Alloc(); + T* AllocZero(); + void Free( T *pMem ); + + void Clear(); +}; + + +//----------------------------------------------------------------------------- +// Specialized pool for aligned data management (e.g., Xbox cubemaps) +//----------------------------------------------------------------------------- +template +class CAlignedMemPool +{ + enum + { + BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8 + }; + +public: + CAlignedMemPool(); + + void *Alloc(); + void Free( void *p ); + + static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); + void Compact(); + + int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } + int NumAllocated() { return NumTotal() - m_nFree; } + int NumFree() { return m_nFree; } + + int BytesTotal() { return NumTotal() * BLOCK_SIZE; } + int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; } + int BytesFree() { return NumFree() * BLOCK_SIZE; } + + int ItemSize() { return ITEM_SIZE; } + int BlockSize() { return BLOCK_SIZE; } + int ChunkSize() { return CHUNK_SIZE; } + +private: + struct FreeBlock_t + { + FreeBlock_t *pNext; + byte reserved[ BLOCK_SIZE - sizeof( FreeBlock_t *) ]; + }; + + CUtlVector m_Chunks; // Chunks are tracked outside blocks (unlike CUtlMemoryPool) to simplify alignment issues + FreeBlock_t * m_pFirstFree; + int m_nFree; + CAllocator m_Allocator; + float m_TimeLastCompact; +}; + +//----------------------------------------------------------------------------- +// Pool variant using standard allocation +//----------------------------------------------------------------------------- +template +class CObjectPool +{ +public: + CObjectPool() + { + int i = nInitialCount; + while ( i-- > 0 ) + { + m_AvailableObjects.PushItem( new T ); + } + } + + ~CObjectPool() + { + Purge(); + } + + int NumAvailable() + { + return m_AvailableObjects.Count(); + } + + void Purge() + { + T *p; + while ( m_AvailableObjects.PopItem( &p ) ) + { + delete p; + } + } + + T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) + { + T *p; + if ( !m_AvailableObjects.PopItem( &p ) ) + { + p = ( bCreateNewIfEmpty ) ? new T : NULL; + } + return p; + } + + void PutObject( T *p ) + { + m_AvailableObjects.PushItem( p ); + } + +private: + CTSList m_AvailableObjects; +}; + +//----------------------------------------------------------------------------- + + +template< class T > +inline T* CClassMemoryPool::Alloc() +{ + T *pRet; + + { + MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + pRet = (T*)CUtlMemoryPool::Alloc(); + } + + if ( pRet ) + { + Construct( pRet ); + } + return pRet; +} + +template< class T > +inline T* CClassMemoryPool::AllocZero() +{ + T *pRet; + + { + MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + pRet = (T*)CUtlMemoryPool::AllocZero(); + } + + if ( pRet ) + { + Construct( pRet ); + } + return pRet; +} + +template< class T > +inline void CClassMemoryPool::Free(T *pMem) +{ + if ( pMem ) + { + Destruct( pMem ); + } + + CUtlMemoryPool::Free( pMem ); +} + +template< class T > +inline void CClassMemoryPool::Clear() +{ + CUtlRBTree freeBlocks; + SetDefLessFunc( freeBlocks ); + + void *pCurFree = m_pHeadOfFreeList; + while ( pCurFree != NULL ) + { + freeBlocks.Insert( pCurFree ); + pCurFree = *((void**)pCurFree); + } + + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + T *p = (T *)pCur->m_Data; + T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); + while ( p < pLimit ) + { + if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) + { + Destruct( p ); + } + p++; + } + } + + CUtlMemoryPool::Clear(); +} + + +//----------------------------------------------------------------------------- +// Macros that make it simple to make a class use a fixed-size allocator +// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class, +// Put DEFINE_FIXEDSIZE_ALLOCATOR in the CPP file +//----------------------------------------------------------------------------- +#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CUtlMemoryPool s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment ) + +#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CMemoryPoolMT s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +//----------------------------------------------------------------------------- +// Macros that make it simple to make a class use a fixed-size allocator +// This version allows us to use a memory pool which is externally defined... +// Put DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the private section of a class, +// Put DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the CPP file +//----------------------------------------------------------------------------- + +#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void operator delete( void* p ) { s_pAllocator->Free(p); } \ + private: \ + static CUtlMemoryPool* s_pAllocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \ + CUtlMemoryPool* _class::s_pAllocator = _allocator + + +template +inline CAlignedMemPool::CAlignedMemPool() + : m_pFirstFree( 0 ), + m_nFree( 0 ), + m_TimeLastCompact( 0 ) +{ + COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); + COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); +} + +template +inline void *CAlignedMemPool::Alloc() +{ + if ( !m_pFirstFree ) + { + FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); + Assert( (unsigned)pNew % ALIGNMENT == 0 ); + m_Chunks.AddToTail( pNew ); + m_nFree = CHUNK_SIZE / BLOCK_SIZE; + m_pFirstFree = pNew; + for ( int i = 0; i < m_nFree - 1; i++ ) + { + pNew->pNext = pNew + 1; + pNew++; + } + pNew->pNext = NULL; + } + + void *p = m_pFirstFree; + m_pFirstFree = m_pFirstFree->pNext; + m_nFree--; + + return p; +} + +template +inline void CAlignedMemPool::Free( void *p ) +{ + // Insertion sort to encourage allocation clusters in chunks + FreeBlock_t *pFree = ((FreeBlock_t *)p); + FreeBlock_t *pCur = m_pFirstFree; + FreeBlock_t *pPrev = NULL; + + while ( pCur && pFree > pCur ) + { + pPrev = pCur; + pCur = pCur->pNext; + } + + pFree->pNext = pCur; + + if ( pPrev ) + { + pPrev->pNext = pFree; + } + else + { + m_pFirstFree = pFree; + } + m_nFree++; + + if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) + { + float time = Plat_FloatTime(); + float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; + if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() ) + { + Compact(); + m_TimeLastCompact = time; + } + } +} + +template +inline int __cdecl CAlignedMemPool::CompareChunk( void * const *ppLeft, void * const *ppRight ) +{ + return ((unsigned)*ppLeft) - ((unsigned)*ppRight); +} + +template +inline void CAlignedMemPool::Compact() +{ + FreeBlock_t *pCur = m_pFirstFree; + FreeBlock_t *pPrev = NULL; + + m_Chunks.Sort( CompareChunk ); + +#ifdef VALIDATE_ALIGNED_MEM_POOL + { + FreeBlock_t *p = m_pFirstFree; + while ( p ) + { + if ( p->pNext && p > p->pNext ) + { + __asm { int 3 } + } + p = p->pNext; + } + + for ( int i = 0; i < m_Chunks.Count(); i++ ) + { + if ( i + 1 < m_Chunks.Count() ) + { + if ( m_Chunks[i] > m_Chunks[i + 1] ) + { + __asm { int 3 } + } + } + } + } +#endif + + int i; + + for ( i = 0; i < m_Chunks.Count(); i++ ) + { + int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE; + FreeBlock_t *pChunkLimit = ((FreeBlock_t *)m_Chunks[i]) + nBlocksPerChunk; + int nFromChunk = 0; + if ( pCur == m_Chunks[i] ) + { + FreeBlock_t *pFirst = pCur; + while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit ) + { + pCur = pCur->pNext; + nFromChunk++; + } + pCur = pFirst; + + } + + while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit ) + { + if ( nFromChunk != nBlocksPerChunk ) + { + if ( pPrev ) + { + pPrev->pNext = pCur; + } + else + { + m_pFirstFree = pCur; + } + pPrev = pCur; + } + else if ( pPrev ) + { + pPrev->pNext = NULL; + } + else + { + m_pFirstFree = NULL; + } + + pCur = pCur->pNext; + } + + if ( nFromChunk == nBlocksPerChunk ) + { + m_Allocator.Free( m_Chunks[i] ); + m_nFree -= nBlocksPerChunk; + m_Chunks[i] = 0; + } + } + + for ( i = m_Chunks.Count() - 1; i >= 0 ; i-- ) + { + if ( !m_Chunks[i] ) + { + m_Chunks.FastRemove( i ); + } + } +} + +#endif // MEMPOOL_H diff --git a/public/tier1/memstack.h b/public/tier1/memstack.h new file mode 100644 index 0000000..e5f0885 --- /dev/null +++ b/public/tier1/memstack.h @@ -0,0 +1,207 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A fast stack memory allocator that uses virtual memory if available +// +//=============================================================================// + +#ifndef MEMSTACK_H +#define MEMSTACK_H + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +typedef unsigned MemoryStackMark_t; + +class CMemoryStack +{ +public: + CMemoryStack(); + ~CMemoryStack(); + + bool Init( unsigned maxSize = 0, unsigned commitSize = 0, unsigned initialCommit = 0, unsigned alignment = 16 ); +#ifdef _X360 + bool InitPhysical( unsigned size = 0, unsigned alignment = 16 ); +#endif + void Term(); + + int GetSize(); + int GetMaxSize(); + int GetUsed(); + + void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT; + + MemoryStackMark_t GetCurrentAllocPoint(); + void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true ); + void FreeAll( bool bDecommit = true ); + + void Access( void **ppRegion, unsigned *pBytes ); + + void PrintContents(); + + void *GetBase(); + const void *GetBase() const { return const_cast(this)->GetBase(); } + +private: + bool CommitTo( byte * ) RESTRICT; + + byte *m_pNextAlloc; + byte *m_pCommitLimit; + byte *m_pAllocLimit; + + byte *m_pBase; + + unsigned m_maxSize; + unsigned m_alignment; +#ifdef _WIN32 + unsigned m_commitSize; + unsigned m_minCommit; +#endif +#ifdef _X360 + bool m_bPhysical; +#endif +}; + +//------------------------------------- + +FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT +{ + Assert( m_pBase ); + + int alignment = m_alignment; + if ( bytes ) + { + bytes = AlignValue( bytes, alignment ); + } + else + { + bytes = alignment; + } + + + void *pResult = m_pNextAlloc; + byte *pNextAlloc = m_pNextAlloc + bytes; + + if ( pNextAlloc > m_pCommitLimit ) + { + if ( !CommitTo( pNextAlloc ) ) + { + return NULL; + } + } + + if ( bClear ) + { + memset( pResult, 0, bytes ); + } + + m_pNextAlloc = pNextAlloc; + + return pResult; +} + +//------------------------------------- + +inline int CMemoryStack::GetMaxSize() +{ + return m_maxSize; +} + +//------------------------------------- + +inline int CMemoryStack::GetUsed() +{ + return ( m_pNextAlloc - m_pBase ); +} + +//------------------------------------- + +inline void *CMemoryStack::GetBase() +{ + return m_pBase; +} + +//------------------------------------- + +inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint() +{ + return ( m_pNextAlloc - m_pBase ); +} + +//----------------------------------------------------------------------------- +// The CUtlMemoryStack class: +// A fixed memory class +//----------------------------------------------------------------------------- +template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 > +class CUtlMemoryStack +{ +public: + // constructor, destructor + CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); } + CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); } + + // Can we use this index? + bool IsIdxValid( I i ) const { return (i >= 0) && (i < m_nAllocated); } + + // Specify the invalid ('null') index that we'll only return on failure + static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT + static I InvalidIndex() { return INVALID_INDEX; } + + class Iterator_t + { + Iterator_t( I i ) : index( i ) {} + I index; + friend class CUtlMemoryStack; + public: + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return it.index >= 0 && it.index < m_nAllocated; } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // Gets the base address + T* Base() { return (T*)m_MemoryStack.GetBase(); } + const T* Base() const { return (const T*)m_MemoryStack.GetBase(); } + + // element access + T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } + + // Size + int NumAllocated() const { return m_nAllocated; } + int Count() const { return m_nAllocated; } + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); } + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); } + + // Memory deallocation + void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; } + + // is the memory externally allocated? + bool IsExternallyAllocated() const { return false; } + + // Set the size by which the memory grows + void SetGrowSize( int size ) {} + +private: + CMemoryStack m_MemoryStack; + int m_nAllocated; +}; + +//----------------------------------------------------------------------------- + +#endif // MEMSTACK_H diff --git a/public/tier1/netadr.h b/public/tier1/netadr.h new file mode 100644 index 0000000..6e8b5eb --- /dev/null +++ b/public/tier1/netadr.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// netadr.h +#ifndef NETADR_H +#define NETADR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "steam/steamclientpublic.h" +#undef SetPort + +typedef enum +{ + NA_NULL = 0, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_STEAM, +} netadrtype_t; + +typedef struct netadr_s +{ +public: + netadr_s() { SetIP( 0 ); SetPort( 0 ); SetType( NA_IP ); } + netadr_s( uint unIP, uint16 usPort ) { SetIP( unIP ); SetPort( usPort ); SetType( NA_IP ); } + netadr_s( const char *pch ) { SetFromString( pch ); } + void Clear(); // invalids Address + + void SetType( netadrtype_t type ); + void SetPort( unsigned short port ); + bool SetFromSockadr(const struct sockaddr *s); + void SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4); + void SetIP(uint unIP); // Sets IP. unIP is in host order (little-endian) + void SetIPAndPort( uint unIP, unsigned short usPort ) { SetIP( unIP ); SetPort( usPort ); } + void SetFromString(const char *pch, bool bUseDNS = false ); // if bUseDNS is true then do a DNS lookup if needed + + bool CompareAdr (const netadr_s &a, bool onlyBase = false) const; + bool CompareClassBAdr (const netadr_s &a) const; + bool CompareClassCAdr (const netadr_s &a) const; + + netadrtype_t GetType() const; + unsigned short GetPort() const; + const CSteamID &GetSteamID() const; + const char* ToString( bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp + void ToSockadr(struct sockaddr *s) const; + unsigned int GetIPHostByteOrder() const; + unsigned int GetIPNetworkByteOrder() const; + + bool IsLocalhost() const; // true, if this is the localhost IP + bool IsLoopback() const; // true if engine loopback buffers are used + bool IsReservedAdr() const; // true, if this is a private LAN IP + bool IsValid() const; // ip & port != 0 + void SetFromSocket( int hSocket ); + bool operator==(const netadr_s &netadr) const {return ( CompareAdr( netadr ) );} + bool operator<(const netadr_s &netadr) const; + +public: // members are public to avoid to much changes + + netadrtype_t type; + unsigned char ip[4]; + unsigned short port; + CSteamID m_SteamID; +} netadr_t; + +#endif // NETADR_H diff --git a/public/tier1/passwordhash.h b/public/tier1/passwordhash.h new file mode 100644 index 0000000..f557c7f --- /dev/null +++ b/public/tier1/passwordhash.h @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Cryptographic hash agility helper definitions +// +//============================================================================= + +#ifndef PASSWORDHASH_H +#define PASSWORDHASH_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +#include "checksum_sha1.h" + +typedef unsigned char BigPasswordHash_t[32]; +typedef unsigned char PBKDF2Hash_t[32]; + +// +// A union of all the possible password hash types. +// When adding to this, if the maximum size of the +// structure has changed then the Account table and +// the AccountSecurityHistory table need to be manually +// revised using something like the following SQL: +// +// ALTER TABLE Account ALTER COLUMN PasswordHash binary(32) +// ALTER TABLE AccountSecurityHistory ALTER COLUMN PasswordHashOld binary(32) +// ALTER TABLE AccountSecurityHistory ALTER COLUMN PasswordHashNew binary(32) +// +// Replace 32 with the new size of PasswordHash_t. +// +// If the width of those columns does not match sizeof(PasswordHash_t), many +// database operations will fail. +// +// Note that while this query was correct at the time this code was checked in, +// it may not be sufficient at the time you actually change the size of the +// type, so look around. +// +typedef union +{ + SHADigest_t sha; + BigPasswordHash_t bigpassword; + PBKDF2Hash_t pbkdf2; +} PasswordHash_t; + + +// +// Enum of all available password hash algorithms. These should +// be consecutive and ordinals should never be reused. +// +// k_EHashSHA1: A salted SHA-1 hash, width 20 bytes. +// k_EHashBigPassword: For testing purposes, a salted SHA-1 hash extended to 32 bytes, with 6 bytes of 0x1 on either side. +// k_EHashPBKDF2_1000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 1,000 iterations. +// The digest width is 32 bytes. +// k_EHashPBKDF2_5000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 5,000 iterations. +// k_EHashPBKDF2_10000: A PKCS#5 v2.0 Password-Based Key Derivation Function hash (PBKDF2-HMAC-SHA256) with 10,000 iterations. +// k_EHashSHA1WrappedWithPBKDF2_10000: A SHA-1 hash which is then further hashed with PBKDF2 at 10,000 rounds. Used for +// strengthening old hashes in the database that haven't been logged in in a long time. +// +// Make sure to update k_EHashMax when adding new hash types. Also add the length into the k_HashLengths array below. +enum EPasswordHashAlg +{ + k_EHashSHA1 = 0, + k_EHashBigPassword = 1, + k_EHashPBKDF2_1000 = 2, + k_EHashPBKDF2_5000 = 3, + k_EHashPBKDF2_10000 = 4, + k_EHashSHA1WrappedWithPBKDF2_10000 = 5, + k_EHashMax = 5, +}; + +// +// Hash sizes for the various available hash algorithms, +// indexed by EPasswordHashAlg. +const size_t k_HashLengths[] = { + sizeof(SHADigest_t), + sizeof(BigPasswordHash_t), + sizeof(PBKDF2Hash_t), + sizeof(PBKDF2Hash_t), + sizeof(PBKDF2Hash_t), + sizeof(PBKDF2Hash_t), +}; + +#if defined(C_ASSERT) +// +// If you're hitting this assert at compile time, it means that you've added a new +// hash type and properly updated k_EHashMax, but you forgot to add the length +// of the new hash type into k_HashLengths. So do that. +// +C_ASSERT( ( ( sizeof(k_HashLengths) / sizeof(size_t) ) == k_EHashMax + 1 ) ); +#endif + +#endif // PASSWORDHASH_H diff --git a/public/tier1/processor_detect.h b/public/tier1/processor_detect.h new file mode 100644 index 0000000..cb4cc37 --- /dev/null +++ b/public/tier1/processor_detect.h @@ -0,0 +1,12 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: functions to expose CPU capabilities +// +// $NoKeywords: $ +//=============================================================================// + +bool CheckMMXTechnology(void); +bool CheckSSETechnology(void); +bool CheckSSE2Technology(void); +bool Check3DNowTechnology(void); + diff --git a/public/tier1/rangecheckedvar.h b/public/tier1/rangecheckedvar.h new file mode 100644 index 0000000..52313f8 --- /dev/null +++ b/public/tier1/rangecheckedvar.h @@ -0,0 +1,118 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef RANGECHECKEDVAR_H +#define RANGECHECKEDVAR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "mathlib/vector.h" +#include + + +// Use this to disable range checks within a scope. +class CDisableRangeChecks +{ +public: + CDisableRangeChecks(); + ~CDisableRangeChecks(); +}; + + +template< class T > +inline void RangeCheck( const T &value, int minValue, int maxValue ) +{ +#ifdef _DEBUG + extern bool g_bDoRangeChecks; + if ( ThreadInMainThread() && g_bDoRangeChecks ) + { + // Ignore the min/max stuff for now.. just make sure it's not a NAN. + Assert( _finite( value ) ); + } +#endif +} + +inline void RangeCheck( const Vector &value, int minValue, int maxValue ) +{ +#ifdef _DEBUG + RangeCheck( value.x, minValue, maxValue ); + RangeCheck( value.y, minValue, maxValue ); + RangeCheck( value.z, minValue, maxValue ); +#endif +} + + +template< class T, int minValue, int maxValue, int startValue > +class CRangeCheckedVar +{ +public: + + inline CRangeCheckedVar() + { + m_Val = startValue; + } + + inline CRangeCheckedVar( const T &value ) + { + *this = value; + } + + T GetRaw() const + { + return m_Val; + } + + // Clamp the value to its limits. Interpolation code uses this after interpolating. + inline void Clamp() + { + if ( m_Val < minValue ) + m_Val = minValue; + else if ( m_Val > maxValue ) + m_Val = maxValue; + } + + inline operator const T&() const + { + return m_Val; + } + + inline CRangeCheckedVar& operator=( const T &value ) + { + RangeCheck( value, minValue, maxValue ); + m_Val = value; + return *this; + } + + inline CRangeCheckedVar& operator+=( const T &value ) + { + return (*this = m_Val + value); + } + + inline CRangeCheckedVar& operator-=( const T &value ) + { + return (*this = m_Val - value); + } + + inline CRangeCheckedVar& operator*=( const T &value ) + { + return (*this = m_Val * value); + } + + inline CRangeCheckedVar& operator/=( const T &value ) + { + return (*this = m_Val / value); + } + +private: + + T m_Val; +}; + +#endif // RANGECHECKEDVAR_H diff --git a/public/tier1/refcount.h b/public/tier1/refcount.h new file mode 100644 index 0000000..9c756b8 --- /dev/null +++ b/public/tier1/refcount.h @@ -0,0 +1,419 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Tools for correctly implementing & handling reference counted +// objects +// +//============================================================================= + +#ifndef REFCOUNT_H +#define REFCOUNT_H + +#include "tier0/threadtools.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +template +inline void SafeAssign(T** ppInoutDst, T* pInoutSrc ) +{ + Assert( ppInoutDst ); + + // Do addref before release + if ( pInoutSrc ) + ( pInoutSrc )->AddRef(); + + // Do addref before release + if ( *ppInoutDst ) + ( *ppInoutDst )->Release(); + + // Do the assignment + ( *ppInoutDst ) = pInoutSrc; +} + +template +inline void SafeAddRef( T* pObj ) +{ + if ( pObj ) + pObj->AddRef(); +} + +template +inline void SafeRelease( T** ppInoutPtr ) +{ + Assert( ppInoutPtr ); + if ( *ppInoutPtr ) + ( *ppInoutPtr )->Release(); + + ( *ppInoutPtr ) = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Implement a standard reference counted interface. Use of this +// is optional insofar as all the concrete tools only require +// at compile time that the function signatures match. +//----------------------------------------------------------------------------- + +class IRefCounted +{ +public: + virtual int AddRef() = 0; + virtual int Release() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Release a pointer and mark it NULL +//----------------------------------------------------------------------------- + +template +inline int SafeRelease( REFCOUNTED_ITEM_PTR &pRef ) +{ + // Use funny syntax so that this works on "auto pointers" + REFCOUNTED_ITEM_PTR *ppRef = &pRef; + if ( *ppRef ) + { + int result = (*ppRef)->Release(); + *ppRef = NULL; + return result; + } + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Maintain a reference across a scope +//----------------------------------------------------------------------------- + +template +class CAutoRef +{ +public: + CAutoRef( T *pRef ) + : m_pRef( pRef ) + { + if ( m_pRef ) + m_pRef->AddRef(); + } + + ~CAutoRef() + { + if (m_pRef) + m_pRef->Release(); + } + +private: + T *m_pRef; +}; + +//----------------------------------------------------------------------------- +// Purpose: Do a an inline AddRef then return the pointer, useful when +// returning an object from a function +//----------------------------------------------------------------------------- + +#define RetAddRef( p ) ( (p)->AddRef(), (p) ) +#define InlineAddRef( p ) ( (p)->AddRef(), (p) ) + + +//----------------------------------------------------------------------------- +// Purpose: A class to both hold a pointer to an object and its reference. +// Base exists to support other cleanup models +//----------------------------------------------------------------------------- + +template +class CBaseAutoPtr +{ +public: + CBaseAutoPtr() : m_pObject(0) {} + CBaseAutoPtr(T *pFrom) : m_pObject(pFrom) {} + + operator const void *() const { return m_pObject; } + operator void *() { return m_pObject; } + + operator const T *() const { return m_pObject; } + operator const T *() { return m_pObject; } + operator T *() { return m_pObject; } + + int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); m_pObject = 0; return 0; } + T * operator=( T *p ) { m_pObject = p; return p; } + + bool operator !() const { return ( !m_pObject ); } + bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (m_pObject != NULL); } + bool operator==( const void *p ) const { return ( m_pObject == p ); } + bool operator!=( const void *p ) const { return ( m_pObject != p ); } + bool operator==( T *p ) const { return operator==( (void *)p ); } + bool operator!=( T *p ) const { return operator!=( (void *)p ); } + bool operator==( const CBaseAutoPtr &p ) const { return operator==( (const void *)p ); } + bool operator!=( const CBaseAutoPtr &p ) const { return operator!=( (const void *)p ); } + + T * operator->() { return m_pObject; } + T & operator *() { return *m_pObject; } + T ** operator &() { return &m_pObject; } + + const T * operator->() const { return m_pObject; } + const T & operator *() const { return *m_pObject; } + T * const * operator &() const { return &m_pObject; } + +protected: + CBaseAutoPtr( const CBaseAutoPtr &from ) : m_pObject( from.m_pObject ) {} + void operator=( const CBaseAutoPtr &from ) { m_pObject = from.m_pObject; } + + T *m_pObject; +}; + +//--------------------------------------------------------- + +template +class CRefPtr : public CBaseAutoPtr +{ + typedef CBaseAutoPtr BaseClass; +public: + CRefPtr() {} + CRefPtr( T *pInit ) : BaseClass( pInit ) {} + CRefPtr( const CRefPtr &from ) : BaseClass( from ) {} + ~CRefPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); } + + void operator=( const CRefPtr &from ) { BaseClass::operator=( from ); } + + int operator=( int i ) { return BaseClass::operator=( i ); } + T *operator=( T *p ) { return BaseClass::operator=( p ); } + + operator bool() const { return !BaseClass::operator!(); } + operator bool() { return !BaseClass::operator!(); } + + void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); BaseClass::m_pObject = 0; } + void AssignAddRef( T *pFrom ) { SafeRelease(); if (pFrom) pFrom->AddRef(); BaseClass::m_pObject = pFrom; } + void AddRefAssignTo( T *&pTo ) { ::SafeRelease( pTo ); if ( BaseClass::m_pObject ) BaseClass::m_pObject->AddRef(); pTo = BaseClass::m_pObject; } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Traits classes defining reference count threading model +//----------------------------------------------------------------------------- + +class CRefMT +{ +public: + static int Increment( int *p) { return ThreadInterlockedIncrement( (long *)p ); } + static int Decrement( int *p) { return ThreadInterlockedDecrement( (long *)p ); } +}; + +class CRefST +{ +public: + static int Increment( int *p) { return ++(*p); } + static int Decrement( int *p) { return --(*p); } +}; + +//----------------------------------------------------------------------------- +// Purpose: Actual reference counting implementation. Pulled out to reduce +// code bloat. +//----------------------------------------------------------------------------- + +template +class NO_VTABLE CRefCountServiceBase +{ +protected: + CRefCountServiceBase() + : m_iRefs( 1 ) + { + } + + virtual ~CRefCountServiceBase() + { + } + + virtual bool OnFinalRelease() + { + return true; + } + + int GetRefCount() const + { + return m_iRefs; + } + + int DoAddRef() + { + return CRefThreading::Increment( &m_iRefs ); + } + + int DoRelease() + { + int result = CRefThreading::Decrement( &m_iRefs ); + if ( result ) + return result; + if ( OnFinalRelease() && bSelfDelete ) + delete this; + return 0; + } + +private: + int m_iRefs; +}; + +class CRefCountServiceNull +{ +protected: + static int DoAddRef() { return 1; } + static int DoRelease() { return 1; } +}; + +template +class NO_VTABLE CRefCountServiceDestruct +{ +protected: + CRefCountServiceDestruct() + : m_iRefs( 1 ) + { + } + + virtual ~CRefCountServiceDestruct() + { + } + + int GetRefCount() const + { + return m_iRefs; + } + + int DoAddRef() + { + return CRefThreading::Increment( &m_iRefs ); + } + + int DoRelease() + { + int result = CRefThreading::Decrement( &m_iRefs ); + if ( result ) + return result; + this->~CRefCountServiceDestruct(); + return 0; + } + +private: + int m_iRefs; +}; + + +typedef CRefCountServiceBase CRefCountServiceST; +typedef CRefCountServiceBase CRefCountServiceNoDeleteST; + +typedef CRefCountServiceBase CRefCountServiceMT; +typedef CRefCountServiceBase CRefCountServiceNoDeleteMT; + +// Default to threadsafe +typedef CRefCountServiceNoDeleteMT CRefCountServiceNoDelete; +typedef CRefCountServiceMT CRefCountService; + +//----------------------------------------------------------------------------- +// Purpose: Base classes to implement reference counting +//----------------------------------------------------------------------------- + +template < class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted : public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted1 : public BASE1, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted1() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted2 : public BASE1, public BASE2, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted2() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class BASE3, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted3 : public BASE1, public BASE2, public BASE3, + public REFCOUNT_SERVICE +{ + virtual ~CRefCounted3() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class BASE3, class BASE4, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted4 : public BASE1, public BASE2, public BASE3, public BASE4, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted4() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class BASE3, class BASE4, class BASE5, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted5 : public BASE1, public BASE2, public BASE3, public BASE4, public BASE5, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted5() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//----------------------------------------------------------------------------- +// Purpose: Class to throw around a reference counted item to debug +// referencing problems +//----------------------------------------------------------------------------- + +template +class CRefDebug : public BASE_REFCOUNTED +{ +public: +#ifdef _DEBUG + CRefDebug() + { + AssertMsg( this->GetRefCount() == 1, "Expected initial ref count of 1" ); + DevMsg( "%s:create 0x%x\n", ( pszName ) ? pszName : "", this ); + } + + virtual ~CRefDebug() + { + AssertDevMsg( this->GetRefCount() == FINAL_REFS, "Object still referenced on destroy?" ); + DevMsg( "%s:destroy 0x%x\n", ( pszName ) ? pszName : "", this ); + } + + int AddRef() + { + DevMsg( "%s:(0x%x)->AddRef() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() + 1 ); + return BASE_REFCOUNTED::AddRef(); + } + + int Release() + { + DevMsg( "%s:(0x%x)->Release() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() - 1 ); + Assert( this->GetRefCount() > 0 ); + return BASE_REFCOUNTED::Release(); + } +#endif +}; + +//----------------------------------------------------------------------------- + +#endif // REFCOUNT_H diff --git a/public/tier1/reliabletimer.h b/public/tier1/reliabletimer.h new file mode 100644 index 0000000..c830fbe --- /dev/null +++ b/public/tier1/reliabletimer.h @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef RELIABLETIMER_H +#define RELIABLETIMER_H + +#include "tier0/dbg.h" +//#include "constants.h" +#include "tier0/fasttimer.h" +#include "tier1/tier1.h" +#include "tier1/strtools.h" + +#define DbgAssert Assert +#define kMILLION (1000000) +#define kTHOUSAND (1000) + +// Timer class that uses QueryPerformanceCounter. This is heavier-weight than CFastTimer which uses rdtsc, +// but this is reliable on multi-core systems whereas CFastTimer is not. + +class CReliableTimer +{ +public: + CReliableTimer(); + void Start(); + void End(); + int64 GetMicroseconds(); + int64 GetMilliseconds(); + void SetLimit( uint64 m_cMicroSecDuration ); + bool BLimitReached(); + int64 CMicroSecOverage(); + int64 CMicroSecLeft(); + int64 CMilliSecLeft(); +private: + int64 GetPerformanceCountNow(); + + int64 m_nPerformanceCounterStart; + int64 m_nPerformanceCounterEnd; + int64 m_nPerformanceCounterLimit; + + static int64 sm_nPerformanceFrequency; + static bool sm_bUseQPC; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Records timer start time +//----------------------------------------------------------------------------- +inline void CReliableTimer::Start() +{ + m_nPerformanceCounterStart = GetPerformanceCountNow(); +} + +//----------------------------------------------------------------------------- +// Purpose: Records timer end time +//----------------------------------------------------------------------------- +inline void CReliableTimer::End() +{ + m_nPerformanceCounterEnd = GetPerformanceCountNow(); + + // enforce that we've advanced at least one cycle + if ( m_nPerformanceCounterEnd < m_nPerformanceCounterStart ) + { +#ifdef _SERVER + if ( m_nPerformanceCounterEnd+10000 < m_nPerformanceCounterStart ) + AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() ); +#endif + m_nPerformanceCounterEnd = m_nPerformanceCounterStart + 1; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets microseconds elapsed between start and end +//----------------------------------------------------------------------------- +inline int64 CReliableTimer::GetMicroseconds() +{ + DbgAssert( m_nPerformanceCounterStart ); // timer must have been started + DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended + DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency + return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kMILLION / sm_nPerformanceFrequency ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets microseconds elapsed between start and end +//----------------------------------------------------------------------------- +inline int64 CReliableTimer::GetMilliseconds() +{ + DbgAssert( m_nPerformanceCounterStart ); // timer must have been started + DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended + DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency + return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kTHOUSAND / sm_nPerformanceFrequency ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets a limit on this timer that can subsequently be checked against +//----------------------------------------------------------------------------- +inline void CReliableTimer::SetLimit( uint64 cMicroSecDuration ) +{ + DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency + m_nPerformanceCounterStart = GetPerformanceCountNow(); + m_nPerformanceCounterLimit = m_nPerformanceCounterStart + ( ( cMicroSecDuration * sm_nPerformanceFrequency ) / kMILLION ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns if previously set limit has been reached +//----------------------------------------------------------------------------- +inline bool CReliableTimer::BLimitReached() +{ + DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called + DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called + int64 nPerformanceCountNow = GetPerformanceCountNow(); + + // make sure time advances + if ( nPerformanceCountNow < m_nPerformanceCounterStart ) + { +#ifdef _SERVER + if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart ) + AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() ); +#endif + // reset the limit to be lower, to match our new clock + m_nPerformanceCounterLimit = nPerformanceCountNow + (m_nPerformanceCounterLimit - m_nPerformanceCounterStart); + } + + return ( nPerformanceCountNow >= m_nPerformanceCounterLimit ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns microseconds current time is past limit, or 0 if not past limit +//----------------------------------------------------------------------------- +inline int64 CReliableTimer::CMicroSecOverage() +{ + DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called + DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called + int64 nPerformanceCountNow = GetPerformanceCountNow(); +#ifdef _SERVER + if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart ) + AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() ); +#endif + int64 nPerformanceCountOver = ( nPerformanceCountNow > m_nPerformanceCounterLimit ? + nPerformanceCountNow - m_nPerformanceCounterLimit : 0 ); + + Assert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency + return ( nPerformanceCountOver * kMILLION / sm_nPerformanceFrequency ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns microseconds remaining until limit +//----------------------------------------------------------------------------- +inline int64 CReliableTimer::CMicroSecLeft() +{ + DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called + DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called + int64 nPerformanceCountNow = GetPerformanceCountNow(); +#ifdef _SERVER + if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart ) + AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() ); +#endif + int64 nPerformanceCountLeft = ( nPerformanceCountNow < m_nPerformanceCounterLimit ? + m_nPerformanceCounterLimit - nPerformanceCountNow : 0 ); + + DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency + return ( nPerformanceCountLeft * kMILLION / sm_nPerformanceFrequency ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns milliseconds remaining until limit +//----------------------------------------------------------------------------- +inline int64 CReliableTimer::CMilliSecLeft() +{ + return CMicroSecLeft() / 1000; +} + + +#endif // TICKLIMITTIMER_H diff --git a/public/tier1/smartptr.h b/public/tier1/smartptr.h new file mode 100644 index 0000000..466ca0b --- /dev/null +++ b/public/tier1/smartptr.h @@ -0,0 +1,279 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SMARTPTR_H +#define SMARTPTR_H +#ifdef _WIN32 +#pragma once +#endif + + +class CRefCountAccessor +{ +public: + template< class T > + static void AddRef( T *pObj ) + { + pObj->AddRef(); + } + + template< class T > + static void Release( T *pObj ) + { + pObj->Release(); + } +}; + +// This can be used if your objects use AddReference/ReleaseReference function names. +class CRefCountAccessorLongName +{ +public: + template< class T > + static void AddRef( T *pObj ) + { + pObj->AddReference(); + } + + template< class T > + static void Release( T *pObj ) + { + pObj->ReleaseReference(); + } +}; + + +// +// CPlainAutoPtr +// is a smart wrapper for a pointer on the stack that performs "delete" upon destruction. +// +// No reference counting is performed, copying is prohibited "s_p2.Attach( s_p1.Detach() )" should be used +// for readability and ease of maintenance. +// +// Auto pointer supports an "arrow" operator for invoking methods on the pointee and a "dereference" operator +// for getting a pointee reference. +// +// No automatic casting to bool/ptrtype is performed to avoid bugs and problems (read on "safe bool idiom" +// if casting to bool or pointer happens to be useful). +// +// Test for validity with "IsValid", get the pointer with "Get". +// +template < typename T > +class CPlainAutoPtr +{ +public: + explicit CPlainAutoPtr( T *p = NULL ) : m_p( p ) {} + ~CPlainAutoPtr( void ) { Delete(); } + +public: + void Delete( void ) { delete Detach(); } + +private: // Disallow copying, use Detach() instead to avoid ambiguity + CPlainAutoPtr( CPlainAutoPtr const &x ); + CPlainAutoPtr & operator = ( CPlainAutoPtr const &x ); + +public: + void Attach( T *p ) { m_p = p; } + T * Detach( void ) { T * p( m_p ); m_p = NULL; return p; } + +public: + bool IsValid( void ) const { return m_p != NULL; } + T * Get( void ) const { return m_p; } + T * operator -> ( void ) const { return Get(); } + T & operator * ( void ) const { return *Get(); } + +private: + T * m_p; +}; + +// +// CArrayAutoPtr +// is a smart wrapper for an array pointer on the stack that performs "delete []" upon destruction. +// +// No reference counting is performed, copying is prohibited "s_p2.Attach( s_p1.Detach() )" should be used +// for readability and ease of maintenance. +// +// Auto pointer supports an "indexing" operator for accessing array elements. +// +// No automatic casting to bool/ptrtype is performed to avoid bugs and problems (read on "safe bool idiom" +// if casting to bool or pointer happens to be useful). +// +// Test for validity with "IsValid", get the array pointer with "Get". +// +template < typename T > +class CArrayAutoPtr : public CPlainAutoPtr < T > // Warning: no polymorphic destructor (delete on base class will be a mistake) +{ +public: + explicit CArrayAutoPtr( T *p = NULL ) { this->Attach( p ); } + ~CArrayAutoPtr( void ) { this->Delete(); } + +public: + void Delete( void ) { delete [] CPlainAutoPtr < T >::Detach(); } + +public: + T & operator [] ( int k ) const { return CPlainAutoPtr < T >::Get()[ k ]; } +}; + + +// Smart pointers can be used to automatically free an object when nobody points +// at it anymore. Things contained in smart pointers must implement AddRef and Release +// functions. If those functions are private, then the class must make +// CRefCountAccessor a friend. +template +class CSmartPtr +{ +public: + CSmartPtr(); + CSmartPtr( T *pObj ); + CSmartPtr( const CSmartPtr &other ); + ~CSmartPtr(); + + T* operator=( T *pObj ); + void operator=( const CSmartPtr &other ); + const T* operator->() const; + T* operator->(); + bool operator!() const; + bool operator==( const T *pOther ) const; + bool IsValid() const; // Tells if the pointer is valid. + T* GetObject() const; // Get temporary object pointer, don't store it for later reuse! + void MarkDeleted(); + +private: + T *m_pObj; +}; + + +template< class T, class RefCountAccessor > +inline CSmartPtr::CSmartPtr() +{ + m_pObj = NULL; +} + +template< class T, class RefCountAccessor > +inline CSmartPtr::CSmartPtr( T *pObj ) +{ + m_pObj = NULL; + *this = pObj; +} + +template< class T, class RefCountAccessor > +inline CSmartPtr::CSmartPtr( const CSmartPtr &other ) +{ + m_pObj = NULL; + *this = other; +} + +template< class T, class RefCountAccessor > +inline CSmartPtr::~CSmartPtr() +{ + if ( m_pObj ) + { + RefCountAccessor::Release( m_pObj ); + } +} + +template< class T, class RefCountAccessor > +inline T* CSmartPtr::operator=( T *pObj ) +{ + if ( pObj == m_pObj ) + return pObj; + + if ( pObj ) + { + RefCountAccessor::AddRef( pObj ); + } + if ( m_pObj ) + { + RefCountAccessor::Release( m_pObj ); + } + m_pObj = pObj; + return pObj; +} + +template< class T, class RefCountAccessor > +inline void CSmartPtr::MarkDeleted() +{ + m_pObj = NULL; +} + +template< class T, class RefCountAccessor > +inline void CSmartPtr::operator=( const CSmartPtr &other ) +{ + *this = other.m_pObj; +} + +template< class T, class RefCountAccessor > +inline const T* CSmartPtr::operator->() const +{ + return m_pObj; +} + +template< class T, class RefCountAccessor > +inline T* CSmartPtr::operator->() +{ + return m_pObj; +} + +template< class T, class RefCountAccessor > +inline bool CSmartPtr::operator!() const +{ + return !m_pObj; +} + +template< class T, class RefCountAccessor > +inline bool CSmartPtr::operator==( const T *pOther ) const +{ + return m_pObj == pOther; +} + +template< class T, class RefCountAccessor > +inline bool CSmartPtr::IsValid() const +{ + return m_pObj != NULL; +} + +template< class T, class RefCountAccessor > +inline T* CSmartPtr::GetObject() const +{ + return m_pObj; +} + + +// +// CAutoPushPop +// allows you to set value of a variable upon construction and destruction. +// Constructors: +// CAutoPushPop x( myvar ) +// saves the value and restores upon destruction. +// CAutoPushPop x( myvar, newvalue ) +// saves the value, assigns new value upon construction, restores saved value upon destruction. +// CAutoPushPop x( myvar, newvalue, restorevalue ) +// assigns new value upon construction, assignes restorevalue upon destruction. +// +template < typename T > +class CAutoPushPop +{ +public: + explicit CAutoPushPop( T& var ) : m_rVar( var ), m_valPop( var ) {} + CAutoPushPop( T& var, T const &valPush ) : m_rVar( var ), m_valPop( var ) { m_rVar = valPush; } + CAutoPushPop( T& var, T const &valPush, T const &valPop ) : m_rVar( var ), m_valPop( var ) { m_rVar = valPush; } + + ~CAutoPushPop() { m_rVar = m_valPop; } + +private: // forbid copying + CAutoPushPop( CAutoPushPop const &x ); + CAutoPushPop & operator = ( CAutoPushPop const &x ); + +public: + T & Get() { return m_rVar; } + +private: + T &m_rVar; + T m_valPop; +}; + + +#endif // SMARTPTR_H diff --git a/public/tier1/snappy-sinksource.h b/public/tier1/snappy-sinksource.h new file mode 100644 index 0000000..faabfa1 --- /dev/null +++ b/public/tier1/snappy-sinksource.h @@ -0,0 +1,137 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ +#define UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ + +#include + + +namespace snappy { + +// A Sink is an interface that consumes a sequence of bytes. +class Sink { + public: + Sink() { } + virtual ~Sink(); + + // Append "bytes[0,n-1]" to this. + virtual void Append(const char* bytes, size_t n) = 0; + + // Returns a writable buffer of the specified length for appending. + // May return a pointer to the caller-owned scratch buffer which + // must have at least the indicated length. The returned buffer is + // only valid until the next operation on this Sink. + // + // After writing at most "length" bytes, call Append() with the + // pointer returned from this function and the number of bytes + // written. Many Append() implementations will avoid copying + // bytes if this function returned an internal buffer. + // + // If a non-scratch buffer is returned, the caller may only pass a + // prefix of it to Append(). That is, it is not correct to pass an + // interior pointer of the returned array to Append(). + // + // The default implementation always returns the scratch buffer. + virtual char* GetAppendBuffer(size_t length, char* scratch); + + + private: + // No copying + Sink(const Sink&); + void operator=(const Sink&); +}; + +// A Source is an interface that yields a sequence of bytes +class Source { + public: + Source() { } + virtual ~Source(); + + // Return the number of bytes left to read from the source + virtual size_t Available() const = 0; + + // Peek at the next flat region of the source. Does not reposition + // the source. The returned region is empty iff Available()==0. + // + // Returns a pointer to the beginning of the region and store its + // length in *len. + // + // The returned region is valid until the next call to Skip() or + // until this object is destroyed, whichever occurs first. + // + // The returned region may be larger than Available() (for example + // if this ByteSource is a view on a substring of a larger source). + // The caller is responsible for ensuring that it only reads the + // Available() bytes. + virtual const char* Peek(size_t* len) = 0; + + // Skip the next n bytes. Invalidates any buffer returned by + // a previous call to Peek(). + // REQUIRES: Available() >= n + virtual void Skip(size_t n) = 0; + + private: + // No copying + Source(const Source&); + void operator=(const Source&); +}; + +// A Source implementation that yields the contents of a flat array +class ByteArraySource : public Source { + public: + ByteArraySource(const char* p, size_t n) : ptr_(p), left_(n) { } + virtual ~ByteArraySource(); + virtual size_t Available() const; + virtual const char* Peek(size_t* len); + virtual void Skip(size_t n); + private: + const char* ptr_; + size_t left_; +}; + +// A Sink implementation that writes to a flat array without any bound checks. +class UncheckedByteArraySink : public Sink { + public: + explicit UncheckedByteArraySink(char* dest) : dest_(dest) { } + virtual ~UncheckedByteArraySink(); + virtual void Append(const char* data, size_t n); + virtual char* GetAppendBuffer(size_t len, char* scratch); + + // Return the current output pointer so that a caller can see how + // many bytes were produced. + // Note: this is not a Sink method. + char* CurrentDestination() const { return dest_; } + private: + char* dest_; +}; + + +} + +#endif // UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ diff --git a/public/tier1/snappy-stubs-public.h b/public/tier1/snappy-stubs-public.h new file mode 100644 index 0000000..6b41bbe --- /dev/null +++ b/public/tier1/snappy-stubs-public.h @@ -0,0 +1,98 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Author: sesse@google.com (Steinar H. Gunderson) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Various type stubs for the open-source version of Snappy. +// +// This file cannot include config.h, as it is included from snappy.h, +// which is a public header. Instead, snappy-stubs-public.h is generated by +// from snappy-stubs-public.h.in at configure time. + +#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ +#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ + +#if 1 +#include +#endif + +#if 1 +#include +#endif + +#if 0 +#include +#endif + +#define SNAPPY_MAJOR 1 +#define SNAPPY_MINOR 1 +#define SNAPPY_PATCHLEVEL 2 +#define SNAPPY_VERSION \ + ((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL) + +#include + +namespace snappy { + +#if 1 +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; +#else +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; +#endif + +typedef std::string string; + +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#if !0 +// Windows does not have an iovec type, yet the concept is universally useful. +// It is simple to define it ourselves, so we put it inside our own namespace. +struct iovec { + void* iov_base; + size_t iov_len; +}; +#endif + +} // namespace snappy + +#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ diff --git a/public/tier1/snappy.h b/public/tier1/snappy.h new file mode 100644 index 0000000..fbb1af7 --- /dev/null +++ b/public/tier1/snappy.h @@ -0,0 +1,191 @@ +// Copyright 2005 and onwards Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// A light-weight compression algorithm. It is designed for speed of +// compression and decompression, rather than for the utmost in space +// savings. +// +// For getting better compression ratios when you are compressing data +// with long repeated sequences or compressing data that is similar to +// other data, while still compressing fast, you might look at first +// using BMDiff and then compressing the output of BMDiff with +// Snappy. + +#ifndef UTIL_SNAPPY_SNAPPY_H__ +#define UTIL_SNAPPY_SNAPPY_H__ + +// fletcherd@valvesoftware.com: Added this kludge. We really need to stop #defining this in our code. +#undef min +#undef max + +#include +#ifdef _WIN32 +#pragma warning(disable:4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc +#endif //_WIN32 +#include + +#include "snappy-stubs-public.h" + +namespace snappy { + class Source; + class Sink; + + // ------------------------------------------------------------------------ + // Generic compression/decompression routines. + // ------------------------------------------------------------------------ + + // Compress the bytes read from "*source" and append to "*sink". Return the + // number of bytes written. + size_t Compress(Source* source, Sink* sink); + + // Find the uncompressed length of the given stream, as given by the header. + // Note that the true length could deviate from this; the stream could e.g. + // be truncated. + // + // Also note that this leaves "*source" in a state that is unsuitable for + // further operations, such as RawUncompress(). You will need to rewind + // or recreate the source yourself before attempting any further calls. + bool GetUncompressedLength(Source* source, uint32* result); + + // ------------------------------------------------------------------------ + // Higher-level string based routines (should be sufficient for most users) + // ------------------------------------------------------------------------ + + // Sets "*output" to the compressed version of "input[0,input_length-1]". + // Original contents of *output are lost. + // + // REQUIRES: "input[]" is not an alias of "*output". + size_t Compress(const char* input, size_t input_length, std::string* output); + + // Decompresses "compressed[0,compressed_length-1]" to "*uncompressed". + // Original contents of "*uncompressed" are lost. + // + // REQUIRES: "compressed[]" is not an alias of "*uncompressed". + // + // returns false if the message is corrupted and could not be decompressed + bool Uncompress(const char* compressed, size_t compressed_length, + std::string* uncompressed); + + + // ------------------------------------------------------------------------ + // Lower-level character array based routines. May be useful for + // efficiency reasons in certain circumstances. + // ------------------------------------------------------------------------ + + // REQUIRES: "compressed" must point to an area of memory that is at + // least "MaxCompressedLength(input_length)" bytes in length. + // + // Takes the data stored in "input[0..input_length]" and stores + // it in the array pointed to by "compressed". + // + // "*compressed_length" is set to the length of the compressed output. + // + // Example: + // char* output = new char[snappy::MaxCompressedLength(input_length)]; + // size_t output_length; + // RawCompress(input, input_length, output, &output_length); + // ... Process(output, output_length) ... + // delete [] output; + void RawCompress(const char* input, + size_t input_length, + char* compressed, + size_t* compressed_length); + + // Given data in "compressed[0..compressed_length-1]" generated by + // calling the Snappy::Compress routine, this routine + // stores the uncompressed data to + // uncompressed[0..GetUncompressedLength(compressed)-1] + // returns false if the message is corrupted and could not be decrypted + bool RawUncompress(const char* compressed, size_t compressed_length, + char* uncompressed); + + // Given data from the byte source 'compressed' generated by calling + // the Snappy::Compress routine, this routine stores the uncompressed + // data to + // uncompressed[0..GetUncompressedLength(compressed,compressed_length)-1] + // returns false if the message is corrupted and could not be decrypted + bool RawUncompress(Source* compressed, char* uncompressed); + + // Given data in "compressed[0..compressed_length-1]" generated by + // calling the Snappy::Compress routine, this routine + // stores the uncompressed data to the iovec "iov". The number of physical + // buffers in "iov" is given by iov_cnt and their cumulative size + // must be at least GetUncompressedLength(compressed). The individual buffers + // in "iov" must not overlap with each other. + // + // returns false if the message is corrupted and could not be decrypted + bool RawUncompressToIOVec(const char* compressed, size_t compressed_length, + const struct iovec* iov, size_t iov_cnt); + + // Given data from the byte source 'compressed' generated by calling + // the Snappy::Compress routine, this routine stores the uncompressed + // data to the iovec "iov". The number of physical + // buffers in "iov" is given by iov_cnt and their cumulative size + // must be at least GetUncompressedLength(compressed). The individual buffers + // in "iov" must not overlap with each other. + // + // returns false if the message is corrupted and could not be decrypted + bool RawUncompressToIOVec(Source* compressed, const struct iovec* iov, + size_t iov_cnt); + + // Returns the maximal size of the compressed representation of + // input data that is "source_bytes" bytes in length; + size_t MaxCompressedLength(size_t source_bytes); + + // REQUIRES: "compressed[]" was produced by RawCompress() or Compress() + // Returns true and stores the length of the uncompressed data in + // *result normally. Returns false on parsing error. + // This operation takes O(1) time. + bool GetUncompressedLength(const char* compressed, size_t compressed_length, + size_t* result); + + // Returns true iff the contents of "compressed[]" can be uncompressed + // successfully. Does not return the uncompressed data. Takes + // time proportional to compressed_length, but is usually at least + // a factor of four faster than actual decompression. + bool IsValidCompressedBuffer(const char* compressed, + size_t compressed_length); + + // The size of a compression block. Note that many parts of the compression + // code assumes that kBlockSize <= 65536; in particular, the hash table + // can only store 16-bit offsets, and EmitCopy() also assumes the offset + // is 65535 bytes or less. Note also that if you change this, it will + // affect the framing format (see framing_format.txt). + // + // Note that there might be older data around that is compressed with larger + // block sizes, so the decompression code should not rely on the + // non-existence of long backreferences. + static const int kBlockLog = 16; + static const size_t kBlockSize = 1 << kBlockLog; + + static const int kMaxHashTableBits = 14; + static const size_t kMaxHashTableSize = 1 << kMaxHashTableBits; +} // end namespace snappy + + +#endif // UTIL_SNAPPY_SNAPPY_H__ diff --git a/public/tier1/sparsematrix.h b/public/tier1/sparsematrix.h new file mode 100644 index 0000000..d882e5f --- /dev/null +++ b/public/tier1/sparsematrix.h @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// A class allowing storage of a sparse NxN matirx as an array of sparse rows +//===========================================================================// + +#ifndef SPARSEMATRIX_H +#define SPARSEMATRIX_H + +#include "tier1/utlvector.h" + +/// CSparseMatrix is a matrix which compresses each row individually, not storing the zeros. NOte, +/// that while you can randomly set any element in a CSparseMatrix, you really want to do it top to +/// bottom or you will have bad perf as data is moved around to insert new elements. +class CSparseMatrix +{ +public: + struct NonZeroValueDescriptor_t + { + int m_nColumnNumber; + float m_flValue; + }; + + struct RowDescriptor_t + { + int m_nNonZeroCount; // number of non-zero elements in the row + int m_nDataIndex; // index of NonZeroValueDescriptor_t for the first non-zero value + }; + + int m_nNumRows; + int m_nNumCols; + CUtlVector m_rowDescriptors; + CUtlVector m_entries; + int m_nHighestRowAppendedTo; + + void AdjustAllRowIndicesAfter( int nStartRow, int nDelta ); +public: + FORCEINLINE float Element( int nRow, int nCol ) const; + void SetElement( int nRow, int nCol, float flValue ); + void SetDimensions( int nNumRows, int nNumCols ); + void AppendElement( int nRow, int nCol, float flValue ); + void FinishedAppending( void ); + + FORCEINLINE int Height( void ) const { return m_nNumRows; } + FORCEINLINE int Width( void ) const { return m_nNumCols; } + +}; + + + +FORCEINLINE float CSparseMatrix::Element( int nRow, int nCol ) const +{ + Assert( nCol < m_nNumCols ); + int nCount = m_rowDescriptors[nRow].m_nNonZeroCount; + if ( nCount ) + { + NonZeroValueDescriptor_t const *pValue = &(m_entries[m_rowDescriptors[nRow].m_nDataIndex]); + do + { + int nIdx = pValue->m_nColumnNumber; + if ( nIdx == nCol ) + { + return pValue->m_flValue; + } + if ( nIdx > nCol ) + { + break; + } + pValue++; + } while( --nCount ); + } + return 0; +} + + + +// type-specific overrides of matrixmath template for special case sparse routines + +namespace MatrixMath +{ + /// sparse * dense matrix x matrix multiplication + template + void MatrixMultiply( CSparseMatrix const &matA, BTYPE const &matB, OUTTYPE *pMatrixOut ) + { + Assert( matA.Width() == matB.Height() ); + pMatrixOut->SetDimensions( matA.Height(), matB.Width() ); + for( int i = 0; i < matA.Height(); i++ ) + { + for( int j = 0; j < matB.Width(); j++ ) + { + // compute inner product efficiently because of sparsity + int nCnt = matA.m_rowDescriptors[i].m_nNonZeroCount; + int nDataIdx = matA.m_rowDescriptors[i].m_nDataIndex; + float flDot = 0.0; + for( int nIdx = 0; nIdx < nCnt; nIdx++ ) + { + float flAValue = matA.m_entries[nIdx + nDataIdx].m_flValue; + int nCol = matA.m_entries[nIdx + nDataIdx].m_nColumnNumber; + flDot += flAValue * matB.Element( nCol, j ); + } + pMatrixOut->SetElement( i, j, flDot ); + } + } + } + + FORCEINLINE void AppendElement( CSparseMatrix &matrix, int nRow, int nCol, float flValue ) + { + matrix.AppendElement( nRow, nCol, flValue ); // default implementation + } + + FORCEINLINE void FinishedAppending( CSparseMatrix &matrix ) + { + matrix.FinishedAppending(); + } + +}; + + + + + +#endif // SPARSEMATRIX_H diff --git a/public/tier1/stringpool.h b/public/tier1/stringpool.h new file mode 100644 index 0000000..6b1dfae --- /dev/null +++ b/public/tier1/stringpool.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef STRINGPOOL_H +#define STRINGPOOL_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "utlrbtree.h" +#include "utlvector.h" + +//----------------------------------------------------------------------------- +// Purpose: Allocates memory for strings, checking for duplicates first, +// reusing exising strings if duplicate found. +//----------------------------------------------------------------------------- + +class CStringPool +{ +public: + CStringPool(); + ~CStringPool(); + + unsigned int Count() const; + + const char * Allocate( const char *pszValue ); + void FreeAll(); + + // searches for a string already in the pool + const char * Find( const char *pszValue ); + +protected: + typedef CUtlRBTree CStrSet; + + CStrSet m_Strings; +}; + +//----------------------------------------------------------------------------- +// Purpose: A reference counted string pool. +// +// Elements are stored more efficiently than in the conventional string pool, +// quicker to look up, and storage is tracked via reference counts. +// +// At some point this should replace CStringPool +//----------------------------------------------------------------------------- +class CCountedStringPool +{ +public: // HACK, hash_item_t structure should not be public. + + struct hash_item_t + { + char* pString; + unsigned short nNextElement; + unsigned char nReferenceCount; + unsigned char pad; + }; + + enum + { + INVALID_ELEMENT = 0, + MAX_REFERENCE = 0xFF, + HASH_TABLE_SIZE = 1024 + }; + + CUtlVector m_HashTable; // Points to each element + CUtlVector m_Elements; + unsigned short m_FreeListStart; + +public: + CCountedStringPool(); + virtual ~CCountedStringPool(); + + void FreeAll(); + + char *FindString( const char* pIntrinsic ); + char *ReferenceString( const char* pIntrinsic ); + void DereferenceString( const char* pIntrinsic ); + + // These are only reliable if there are less than 64k strings in your string pool + unsigned short FindStringHandle( const char* pIntrinsic ); + unsigned short ReferenceStringHandle( const char* pIntrinsic ); + char *HandleToString( unsigned short handle ); + void SpewStrings(); +}; + +#endif // STRINGPOOL_H diff --git a/public/tier1/strtools.h b/public/tier1/strtools.h new file mode 100644 index 0000000..12e0a0c --- /dev/null +++ b/public/tier1/strtools.h @@ -0,0 +1,1091 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef TIER1_STRTOOLS_H +#define TIER1_STRTOOLS_H + +#include "tier0/platform.h" + +#include +#include +#ifdef _WIN32 +#pragma once +#elif POSIX +#include +#include +#include +#endif + +#include +#include + +#ifdef _WIN64 +#define str_size unsigned int +#else +#define str_size size_t +#endif + +template< class T, class I > class CUtlMemory; +template< class T, class A > class CUtlVector; + + +//----------------------------------------------------------------------------- +// Portable versions of standard string functions +//----------------------------------------------------------------------------- +void _V_memset ( const char* file, int line, void *dest, int fill, int count ); +void _V_memcpy ( const char* file, int line, void *dest, const void *src, int count ); +void _V_memmove ( const char* file, int line, void *dest, const void *src, int count ); +int _V_memcmp ( const char* file, int line, const void *m1, const void *m2, int count ); +int _V_strlen ( const char* file, int line, const char *str ); +void _V_strcpy ( const char* file, int line, char *dest, const char *src ); +char* _V_strrchr ( const char* file, int line, const char *s, char c ); +int _V_strcmp ( const char* file, int line, const char *s1, const char *s2 ); +int _V_wcscmp ( const char* file, int line, const wchar_t *s1, const wchar_t *s2 ); +char* _V_strstr ( const char* file, int line, const char *s1, const char *search ); +int _V_wcslen ( const char* file, int line, const wchar_t *pwch ); +wchar_t* _V_wcslower (const char* file, int line, wchar_t *start); +wchar_t* _V_wcsupr (const char* file, int line, wchar_t *start); + +// ASCII-optimized functions which fall back to CRT only when necessary +char *V_strupr( char *start ); +char *V_strlower( char *start ); +int V_stricmp( const char *s1, const char *s2 ); +int V_strncmp( const char *s1, const char *s2, int count ); +int V_strnicmp( const char *s1, const char *s2, int n ); + +#ifdef POSIX + +inline char *strupr( char *start ) +{ + return V_strupr( start ); +} + +inline char *strlwr( char *start ) +{ + return V_strlower( start ); +} + +inline wchar_t *_wcslwr( wchar_t *start ) +{ + wchar_t *str = start; + while( str && *str ) + { + *str = (wchar_t)towlower(static_cast(*str)); + str++; + } + return start; +}; + +inline wchar_t *_wcsupr( wchar_t *start ) +{ + wchar_t *str = start; + while( str && *str ) + { + *str = (wchar_t)towupper(static_cast(*str)); + str++; + } + return start; +}; + +#endif // POSIX + + +#ifdef _DEBUG + +#define V_memset(dest, fill, count) _V_memset (__FILE__, __LINE__, (dest), (fill), (count)) +#define V_memcpy(dest, src, count) _V_memcpy (__FILE__, __LINE__, (dest), (src), (count)) +#define V_memmove(dest, src, count) _V_memmove (__FILE__, __LINE__, (dest), (src), (count)) +#define V_memcmp(m1, m2, count) _V_memcmp (__FILE__, __LINE__, (m1), (m2), (count)) +#define V_strlen(str) _V_strlen (__FILE__, __LINE__, (str)) +#define V_strcpy(dest, src) _V_strcpy (__FILE__, __LINE__, (dest), (src)) +#define V_strrchr(s, c) _V_strrchr (__FILE__, __LINE__, (s), (c)) +#define V_strcmp(s1, s2) _V_strcmp (__FILE__, __LINE__, (s1), (s2)) +#define V_wcscmp(s1, s2) _V_wcscmp (__FILE__, __LINE__, (s1), (s2)) +#define V_strstr(s1, search ) _V_strstr (__FILE__, __LINE__, (s1), (search) ) +#define V_wcslen(pwch) _V_wcslen (__FILE__, __LINE__, (pwch)) +#define V_wcslower(start) _V_wcslower (__FILE__, __LINE__, (start)) +#define V_wcsupr(start) _V_wcsupr (__FILE__, __LINE__, (start)) + +#else + + +inline void V_memset (void *dest, int fill, int count) { memset( dest, fill, count ); } +inline void V_memcpy (void *dest, const void *src, int count) { memcpy( dest, src, count ); } +inline void V_memmove (void *dest, const void *src, int count) { memmove( dest, src, count ); } +inline int V_memcmp (const void *m1, const void *m2, int count){ return memcmp( m1, m2, count ); } +inline int V_strlen (const char *str) { return (int) strlen ( str ); } +inline void V_strcpy (char *dest, const char *src) { strcpy( dest, src ); } +inline int V_wcslen(const wchar_t *pwch) { return (int)wcslen(pwch); } +inline char* V_strrchr (const char *s, char c) { return (char*)strrchr( s, c ); } +inline int V_strcmp (const char *s1, const char *s2) { return strcmp( s1, s2 ); } +inline int V_wcscmp (const wchar_t *s1, const wchar_t *s2) { return wcscmp( s1, s2 ); } +inline char* V_strstr( const char *s1, const char *search ) { return (char*)strstr( s1, search ); } +inline wchar_t* V_wcslower (wchar_t *start) { return _wcslwr( start ); } +inline wchar_t* V_wcsupr (wchar_t *start) { return _wcsupr( start ); } + +#endif + +int V_atoi (const char *str); +int64 V_atoi64(const char *str); +uint64 V_atoui64(const char *str); +float V_atof (const char *str); +char* V_stristr( char* pStr, const char* pSearch ); +const char* V_stristr( const char* pStr, const char* pSearch ); +const char* V_strnistr( const char* pStr, const char* pSearch, int n ); +const char* V_strnchr( const char* pStr, char c, int n ); +inline int V_strcasecmp (const char *s1, const char *s2) { return V_stricmp(s1, s2); } +inline int V_strncasecmp (const char *s1, const char *s2, int n) { return V_strnicmp(s1, s2, n); } +void V_qsort_s( void *base, size_t num, size_t width, int ( __cdecl *compare )(void *, const void *, +const void *), void *context ); + + +// returns string immediately following prefix, (ie str+strlen(prefix)) or NULL if prefix not found +const char *StringAfterPrefix ( const char *str, const char *prefix ); +const char *StringAfterPrefixCaseSensitive( const char *str, const char *prefix ); +inline bool StringHasPrefix ( const char *str, const char *prefix ) { return StringAfterPrefix ( str, prefix ) != NULL; } +inline bool StringHasPrefixCaseSensitive( const char *str, const char *prefix ) { return StringAfterPrefixCaseSensitive( str, prefix ) != NULL; } + + +template< bool CASE_SENSITIVE > inline bool _V_strEndsWithInner( const char *pStr, const char *pSuffix ) +{ + int nSuffixLen = V_strlen( pSuffix ); + int nStringLen = V_strlen( pStr ); + if ( nSuffixLen == 0 ) + return true; // All strings end with the empty string (matches Java & .NET behaviour) + if ( nStringLen < nSuffixLen ) + return false; + pStr += nStringLen - nSuffixLen; + if ( CASE_SENSITIVE ) + return !V_strcmp( pStr, pSuffix ); + else + return !V_stricmp( pStr, pSuffix ); +} + +// Does 'pStr' end with 'pSuffix'? (case sensitive/insensitive variants) +inline bool V_strEndsWith( const char *pStr, const char *pSuffix ) { return _V_strEndsWithInner( pStr, pSuffix ); } +inline bool V_striEndsWith( const char *pStr, const char *pSuffix ) { return _V_strEndsWithInner( pStr, pSuffix ); } + + +// Normalizes a float string in place. +// (removes leading zeros, trailing zeros after the decimal point, and the decimal point itself where possible) +void V_normalizeFloatString( char* pFloat ); + +// this is locale-unaware and therefore faster version of standard isdigit() +// It also avoids sign-extension errors. +inline bool V_isdigit( char c ) +{ + return c >= '0' && c <= '9'; +} + +// The islower/isdigit/etc. functions all expect a parameter that is either +// 0-0xFF or EOF. It is easy to violate this constraint simply by passing +// 'char' to these functions instead of unsigned char. +// The V_ functions handle the char/unsigned char mismatch by taking a +// char parameter and casting it to unsigned char so that chars with the +// sign bit set will be zero extended instead of sign extended. +// Not that EOF cannot be passed to these functions. +// +// These functions could also be used for optimizations if locale +// considerations make some of the CRT functions slow. +//#undef isdigit // In case this is implemented as a macro +//#define isdigit use_V_isdigit_instead_of_isdigit +inline bool V_isalpha(char c) { return isalpha( (unsigned char)c ) != 0; } +//#undef isalpha +//#define isalpha use_V_isalpha_instead_of_isalpha +inline bool V_isalnum(char c) { return isalnum( (unsigned char)c ) != 0; } +//#undef isalnum +//#define isalnum use_V_isalnum_instead_of_isalnum +inline bool V_isprint(char c) { return isprint( (unsigned char)c ) != 0; } +//#undef isprint +//#define isprint use_V_isprint_instead_of_isprint +inline bool V_isxdigit(char c) { return isxdigit( (unsigned char)c ) != 0; } +//#undef isxdigit +//#define isxdigit use_V_isxdigit_instead_of_isxdigit +inline bool V_ispunct(char c) { return ispunct( (unsigned char)c ) != 0; } +//#undef ispunct +//#define ispunct use_V_ispunct_instead_of_ispunct +inline bool V_isgraph(char c) { return isgraph( (unsigned char)c ) != 0; } +//#undef isgraph +//#define isgraph use_V_isgraph_instead_of_isgraph +inline bool V_isupper(char c) { return isupper( (unsigned char)c ) != 0; } +//#undef isupper +//#define isupper use_V_isupper_instead_of_isupper +inline bool V_islower(char c) { return islower( (unsigned char)c ) != 0; } +//#undef islower +//#define islower use_V_islower_instead_of_islower +inline bool V_iscntrl(char c) { return iscntrl( (unsigned char)c ) != 0; } +//#undef iscntrl +//#define iscntrl use_V_iscntrl_instead_of_iscntrl +inline bool V_isspace(char c) { return isspace( (unsigned char)c ) != 0; } +//#undef isspace +//#define isspace use_V_isspace_instead_of_isspace + + +// These are versions of functions that guarantee NULL termination. +// +// maxLen is the maximum number of bytes in the destination string. +// pDest[maxLen-1] is always NULL terminated if pSrc's length is >= maxLen. +// +// This means the last parameter can usually be a sizeof() of a string. +void V_strncpy( OUT_Z_CAP(maxLenInChars) char *pDest, const char *pSrc, int maxLenInChars ); + +// Ultimate safe strcpy function, for arrays only -- buffer size is inferred by the compiler +template void V_strcpy_safe( OUT_Z_ARRAY char (&pDest)[maxLenInChars], const char *pSrc ) +{ + V_strncpy( pDest, pSrc, (int)maxLenInChars ); +} + +// A function which duplicates a string using new[] to allocate the new string. +inline char *V_strdup( const char *pSrc ) +{ + int nLen = V_strlen( pSrc ); + char *pResult = new char [ nLen+1 ]; + V_memcpy( pResult, pSrc, nLen+1 ); + return pResult; +} + +void V_wcsncpy( OUT_Z_BYTECAP(maxLenInBytes) wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes ); +template void V_wcscpy_safe( OUT_Z_ARRAY wchar_t (&pDest)[maxLenInChars], wchar_t const *pSrc ) +{ + V_wcsncpy( pDest, pSrc, maxLenInChars * sizeof(*pDest) ); +} + +#define COPY_ALL_CHARACTERS -1 +char *V_strncat( INOUT_Z_CAP(cchDest) char *pDest, const char *pSrc, size_t cchDest, int max_chars_to_copy=COPY_ALL_CHARACTERS ); +template char *V_strcat_safe( INOUT_Z_ARRAY char (&pDest)[cchDest], const char *pSrc, int nMaxCharsToCopy=COPY_ALL_CHARACTERS ) +{ + return V_strncat( pDest, pSrc, (int)cchDest, nMaxCharsToCopy ); +} + +wchar_t *V_wcsncat( INOUT_Z_CAP(cchDest) wchar_t *pDest, const wchar_t *pSrc, size_t cchDest, int nMaxCharsToCopy=COPY_ALL_CHARACTERS ); +template wchar_t *V_wcscat_safe( INOUT_Z_ARRAY wchar_t (&pDest)[cchDest], const wchar_t *pSrc, int nMaxCharsToCopy=COPY_ALL_CHARACTERS ) +{ + return V_wcsncat( pDest, pSrc, (int)cchDest, nMaxCharsToCopy ); +} + +char *V_strnlwr( INOUT_Z_CAP(cchBuf) char *pBuf, size_t cchBuf); +template char *V_strlwr_safe( INOUT_Z_ARRAY char (&pBuf)[cchDest] ) +{ + return _V_strnlwr( pBuf, (int)cchDest ); +} + +// Unicode string conversion policies - what to do if an illegal sequence is encountered +enum EStringConvertErrorPolicy +{ + _STRINGCONVERTFLAG_SKIP = 1, + _STRINGCONVERTFLAG_FAIL = 2, + _STRINGCONVERTFLAG_ASSERT = 4, + + STRINGCONVERT_REPLACE = 0, + STRINGCONVERT_SKIP = _STRINGCONVERTFLAG_SKIP, + STRINGCONVERT_FAIL = _STRINGCONVERTFLAG_FAIL, + + STRINGCONVERT_ASSERT_REPLACE = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_REPLACE, + STRINGCONVERT_ASSERT_SKIP = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_SKIP, + STRINGCONVERT_ASSERT_FAIL = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_FAIL, +}; + +// Unicode (UTF-8, UTF-16, UTF-32) fundamental conversion functions. +bool Q_IsValidUChar32( uchar32 uValue ); +int Q_UChar32ToUTF8Len( uchar32 uValue ); +int Q_UChar32ToUTF8( uchar32 uValue, char *pOut ); +int Q_UChar32ToUTF16Len( uchar32 uValue ); +int Q_UChar32ToUTF16( uchar32 uValue, uchar16 *pOut ); + +// Validate that a Unicode string is well-formed and contains only valid code points +bool Q_UnicodeValidate( const char *pUTF8 ); +bool Q_UnicodeValidate( const uchar16 *pUTF16 ); +bool Q_UnicodeValidate( const uchar32 *pUTF32 ); + +// Returns length of string in Unicode code points (printed glyphs or non-printing characters) +int Q_UnicodeLength( const char *pUTF8 ); +int Q_UnicodeLength( const uchar16 *pUTF16 ); +int Q_UnicodeLength( const uchar32 *pUTF32 ); + +// Returns length of string in elements, not characters! These are analogous to Q_strlen and Q_wcslen +inline int Q_strlen16( const uchar16 *puc16 ) { int nElems = 0; while ( puc16[nElems] ) ++nElems; return nElems; } +inline int Q_strlen32( const uchar32 *puc32 ) { int nElems = 0; while ( puc32[nElems] ) ++nElems; return nElems; } + + +// Repair invalid Unicode strings by dropping truncated characters and fixing improperly-double-encoded UTF-16 sequences. +// Unlike conversion functions which replace with '?' by default, a repair operation assumes that you know that something +// is wrong with the string (eg, mid-sequence truncation) and you just want to do the best possible job of cleaning it up. +// You can pass a REPLACE or FAIL policy if you would prefer to replace characters with '?' or clear the entire string. +// Returns nonzero on success, or 0 if the policy is FAIL and an invalid sequence was found. +int Q_UnicodeRepair( char *pUTF8, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP ); +int Q_UnicodeRepair( uchar16 *pUTF16, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP ); +int Q_UnicodeRepair( uchar32 *pUTF32, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP ); + +// Advance pointer forward by N Unicode code points (printed glyphs or non-printing characters), stopping at terminating null if encountered. +char *Q_UnicodeAdvance( char *pUTF8, int nCharacters ); +uchar16 *Q_UnicodeAdvance( uchar16 *pUTF16, int nCharactersnCharacters ); +uchar32 *Q_UnicodeAdvance( uchar32 *pUTF32, int nChars ); +inline const char *Q_UnicodeAdvance( const char *pUTF8, int nCharacters ) { return Q_UnicodeAdvance( (char*) pUTF8, nCharacters ); } +inline const uchar16 *Q_UnicodeAdvance( const uchar16 *pUTF16, int nCharacters ) { return Q_UnicodeAdvance( (uchar16*) pUTF16, nCharacters ); } +inline const uchar32 *Q_UnicodeAdvance( const uchar32 *pUTF32, int nCharacters ) { return Q_UnicodeAdvance( (uchar32*) pUTF32, nCharacters ); } + +// Truncate to maximum of N Unicode code points (printed glyphs or non-printing characters) +inline void Q_UnicodeTruncate( char *pUTF8, int nCharacters ) { *Q_UnicodeAdvance( pUTF8, nCharacters ) = 0; } +inline void Q_UnicodeTruncate( uchar16 *pUTF16, int nCharacters ) { *Q_UnicodeAdvance( pUTF16, nCharacters ) = 0; } +inline void Q_UnicodeTruncate( uchar32 *pUTF32, int nCharacters ) { *Q_UnicodeAdvance( pUTF32, nCharacters ) = 0; } + + +// Conversion between Unicode string types (UTF-8, UTF-16, UTF-32). Deals with bytes, not element counts, +// to minimize harm from the programmer mistakes which continue to plague our wide-character string code. +// Returns the number of bytes written to the output, or if output is NULL, the number of bytes required. +int Q_UTF8ToUTF16( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF8ToUTF32( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF16ToUTF8( const uchar16 *pUTF16, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF16ToUTF32( const uchar16 *pUTF16, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF32ToUTF8( const uchar32 *pUTF32, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF32ToUTF16( const uchar32 *pUTF32, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); + +// This is disgusting and exist only easily to facilitate having 16-bit and 32-bit wchar_t's on different platforms +int Q_UTF32ToUTF32( const uchar32 *pUTF32Source, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32Dest, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); + +// Conversion between count-limited UTF-n character arrays, including any potential NULL characters. +// Output has a terminating NULL for safety; strip the last character if you want an unterminated string. +// Returns the number of bytes written to the output, or if output is NULL, the number of bytes required. +int Q_UTF8CharsToUTF16( const char *pUTF8, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF8CharsToUTF32( const char *pUTF8, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF16CharsToUTF8( const uchar16 *pUTF16, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF16CharsToUTF32( const uchar16 *pUTF16, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF32CharsToUTF8( const uchar32 *pUTF32, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); +int Q_UTF32CharsToUTF16( const uchar32 *pUTF32, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE ); + +// Decode a single UTF-8 character to a uchar32, returns number of UTF-8 bytes parsed +int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut ); + +// Decode a single UTF-16 character to a uchar32, returns number of UTF-16 characters (NOT BYTES) consumed +int Q_UTF16ToUChar32( const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut ); + + +// NOTE: WString means either UTF32 or UTF16 depending on the platform and compiler settings. +#if defined( _MSC_VER ) || defined( _WIN32 ) +#define Q_UTF8ToWString Q_UTF8ToUTF16 +#define Q_UTF8CharsToWString Q_UTF8CharsToUTF16 +#define Q_UTF32ToWString Q_UTF32ToUTF16 +#define Q_WStringToUTF8 Q_UTF16ToUTF8 +#define Q_WStringCharsToUTF8 Q_UTF16CharsToUTF8 +#define Q_WStringToUTF32 Q_UTF16ToUTF32 +#else +#define Q_UTF8ToWString Q_UTF8ToUTF32 +#define Q_UTF8CharsToWString Q_UTF8CharsToUTF32 +#define Q_UTF32ToWString Q_UTF32ToUTF32 +#define Q_WStringToUTF8 Q_UTF32ToUTF8 +#define Q_WStringCharsToUTF8 Q_UTF32CharsToUTF8 +#define Q_WStringToUTF32 Q_UTF32ToUTF32 +#endif + +// These are legacy names which don't make a lot of sense but are used everywhere. Prefer the WString convention wherever possible +#define V_UTF8ToUnicode Q_UTF8ToWString +#define V_UnicodeToUTF8 Q_WStringToUTF8 + + +#ifdef WIN32 +// This function is ill-defined as it relies on the current ANSI code page. Currently Win32 only for tools. +int Q_LocaleSpecificANSIToUTF8( const char *pANSI, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes ); +#endif + +// Windows-1252 is mostly the same as ISO Latin-1, and probably what you want if you are +// saddled with an 8-bit ANSI string that originated on a Windows system. +int Q_Windows1252CharsToUTF8( const char *pchSrc, int cchSrc, OUT_Z_BYTECAP(cchDestUTF8) char *pchDestUTF8, int cchDestUTF8 ); + +// CP 437 is used for VGA console text and some old-school file formats such as ZIP. It +// is also known as the "IBM PC OEM code page" and various related names. You probably +// don't want to use this function unless you know for a fact that you're dealing with +// old-school OEM code pages. Otherwise try the Windows-1252 function above. +int Q_CP437CharsToUTF8( const char *pchSrc, int cchSrc, OUT_Z_BYTECAP(cchDestUTF8) char *pchDestUTF8, int cchDestUTF8 ); + +// replaces characters in a UTF8 string with their identical-looking equivalent (non-roundtrippable) +// +// older version of API uses a small homoglyph table; newer version uses a larger one +// +// strings using old version are baked into the database, so we won't toss it quite yet, +// but don't use it for new features. +int Q_NormalizeUTF8Old( const char *pchSrc, OUT_Z_CAP(cchDest) char *pchDest, int cchDest ); +int Q_NormalizeUTF8( const char *pchSrc, OUT_Z_CAP(cchDest) char *pchDest, int cchDest ); + +//----------------------------------------------------------------------------- +// Purpose: replaces characters in a UTF8 string with similar-looking equivalents. +// Only replaces with ASCII characters.. non-recognized characters will be replaced with ? +// This operation is destructive (i.e. you can't roundtrip through the normalized +// form). +//----------------------------------------------------------------------------- +template int Q_NormalizeUTF8ToASCII( OUT_Z_ARRAY char (&pchDest)[maxLenInChars], const char *pchSrc ) +{ + int nResult = Q_NormalizeUTF8( pchSrc, pchDest, maxLenInChars ); + + // replace non ASCII characters with ? + for ( int i = 0; i < nResult; i++ ) + { + if ( pchDest[i] > 127 || pchDest[i] < 0 ) + { + pchDest[i] = '?'; + } + } + + return nResult; +} + +// UNDONE: Find a non-compiler-specific way to do this +#ifdef _WIN32 +#ifndef _VA_LIST_DEFINED + +#ifdef _M_ALPHA + +struct va_list +{ + char *a0; /* pointer to first homed integer argument */ + int offset; /* byte offset of next parameter */ +}; + +#else // !_M_ALPHA + +typedef char * va_list; + +#endif // !_M_ALPHA + +#define _VA_LIST_DEFINED + +#endif // _VA_LIST_DEFINED + +#elif POSIX +#include +#endif + +#ifdef _WIN32 +#define CORRECT_PATH_SEPARATOR '\\' +#define CORRECT_PATH_SEPARATOR_S "\\" +#define INCORRECT_PATH_SEPARATOR '/' +#define INCORRECT_PATH_SEPARATOR_S "/" +#elif POSIX +#define CORRECT_PATH_SEPARATOR '/' +#define CORRECT_PATH_SEPARATOR_S "/" +#define INCORRECT_PATH_SEPARATOR '\\' +#define INCORRECT_PATH_SEPARATOR_S "\\" +#endif + +int V_vsnprintf( OUT_Z_CAP(maxLenInCharacters) char *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char *pFormat, va_list params ); +template int V_vsprintf_safe( OUT_Z_ARRAY char (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char *pFormat, va_list params ) { return V_vsnprintf( pDest, maxLenInCharacters, pFormat, params ); } + +int V_snprintf( OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars, PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 3, 4 ); +// gcc insists on only having format annotations on declarations, not definitions, which is why I have both. +template int V_sprintf_safe( OUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); +template int V_sprintf_safe( OUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ... ) +{ + va_list params; + va_start( params, pFormat ); + int result = V_vsnprintf( pDest, maxLenInChars, pFormat, params ); + va_end( params ); + return result; +} + +int V_vsnwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, va_list params ); +template int V_vswprintf_safe( OUT_Z_ARRAY wchar_t (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const wchar_t *pFormat, va_list params ) { return V_vsnwprintf( pDest, maxLenInCharacters, pFormat, params ); } +int V_vsnprintfRet( OUT_Z_CAP(maxLenInCharacters) char *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char *pFormat, va_list params, bool *pbTruncated ); +template int V_vsprintfRet_safe( OUT_Z_ARRAY char (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char *pFormat, va_list params, bool *pbTruncated ) { return V_vsnprintfRet( pDest, maxLenInCharacters, pFormat, params, pbTruncated ); } + +// FMTFUNCTION can only be used on ASCII functions, not wide-char functions. +int V_snwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, ... ); +template int V_swprintf_safe( OUT_Z_ARRAY wchar_t (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const wchar_t *pFormat, ... ) +{ + va_list params; + va_start( params, pFormat ); + int result = V_vsnwprintf( pDest, maxLenInChars, pFormat, params ); + va_end( params ); + return result; +} + +// Prints out a pretified memory counter string value ( e.g., 7,233.27 Mb, 1,298.003 Kb, 127 bytes ) +char *V_pretifymem( float value, int digitsafterdecimal = 2, bool usebinaryonek = false ); + +// Prints out a pretified integer with comma separators (eg, 7,233,270,000) +char *V_pretifynum( int64 value ); + +int _V_UCS2ToUnicode( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, int cubDestSizeInBytes ); +template< typename T > inline int V_UCS2ToUnicode( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, T cubDestSizeInBytes ) +{ + return _V_UCS2ToUnicode( pUCS2, pUnicode, static_cast(cubDestSizeInBytes) ); +} + +int _V_UCS2ToUTF8( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes ); +template< typename T > inline int V_UCS2ToUTF8( const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, T cubDestSizeInBytes ) +{ + return _V_UCS2ToUTF8( pUCS2, pUTF8, static_cast(cubDestSizeInBytes) ); +} + +int _V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, int cubDestSizeInBytes ); +template< typename T, typename U > inline int V_UnicodeToUCS2( const wchar_t *pUnicode, T cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, U cubDestSizeInBytes ) +{ + return _V_UnicodeToUCS2( pUnicode, static_cast(cubSrcInBytes), pUCS2, static_cast(cubDestSizeInBytes) ); +} + +int _V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, int cubDestSizeInBytes ); +template< typename T, typename U > inline int V_UTF8ToUCS2( const char *pUTF8, T cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, U cubDestSizeInBytes ) +{ + return _V_UTF8ToUCS2( pUTF8, static_cast(cubSrcInBytes), pUCS2, static_cast(cubDestSizeInBytes) ); +} + +// strips leading and trailing whitespace; returns true if any characters were removed. UTF-8 and UTF-16 versions. +bool Q_StripPrecedingAndTrailingWhitespace( char *pch ); +bool Q_StripPrecedingAndTrailingWhitespaceW( wchar_t *pwch ); + +// strips leading and trailing whitespace, also taking "aggressive" characters +// like punctuation spaces, non-breaking spaces, composing characters, and so on +bool Q_AggressiveStripPrecedingAndTrailingWhitespace( char *pch ); +bool Q_AggressiveStripPrecedingAndTrailingWhitespaceW( wchar_t *pwch ); +bool Q_RemoveAllEvilCharacters( char *pch ); + +// Functions for converting hexidecimal character strings back into binary data etc. +// +// e.g., +// int output; +// V_hextobinary( "ffffffff", 8, &output, sizeof( output ) ); +// would make output == 0xfffffff or -1 +// Similarly, +// char buffer[ 9 ]; +// V_binarytohex( &output, sizeof( output ), buffer, sizeof( buffer ) ); +// would put "ffffffff" into buffer (note null terminator!!!) +unsigned char V_nibble( char c ); +void V_hextobinary( char const *in, int numchars, byte *out, int maxoutputbytes ); +void V_binarytohex( const byte *in, int inputbytes, char *out, int outsize ); + +// Tools for working with filenames +// Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator) +void V_FileBase( const char *in, char *out,int maxlen ); +// Remove the final characters of ppath if it's '\' or '/'. +void V_StripTrailingSlash( char *ppath ); +// Remove any extension from in and return resulting string in out +void V_StripExtension( const char *in, char *out, int outLen ); +// Make path end with extension if it doesn't already have an extension +void V_DefaultExtension( char *path, const char *extension, int pathStringLength ); +// Strips any current extension from path and ensures that extension is the new extension +void V_SetExtension( char *path, const char *extension, int pathStringLength ); +// Removes any filename from path ( strips back to previous / or \ character ) +void V_StripFilename( char *path ); +// Remove the final directory from the path +bool V_StripLastDir( char *dirName, int maxlen ); +// Returns a pointer to the unqualified file name (no path) of a file name +const char * V_UnqualifiedFileName( const char * in ); +// Given a path and a filename, composes "path\filename", inserting the (OS correct) separator if necessary +void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize ); + +// Copy out the path except for the stuff after the final pathseparator +bool V_ExtractFilePath( const char *path, char *dest, int destSize ); +// Copy out the file extension into dest +void V_ExtractFileExtension( const char *path, char *dest, int destSize ); + +const char *V_GetFileExtension( const char * path ); + +// returns a pointer to just the filename part of the path +// (everything after the last path seperator) +const char *V_GetFileName( const char * path ); + +// This removes "./" and "../" from the pathname. pFilename should be a full pathname. +// Also incorporates the behavior of V_FixSlashes and optionally V_FixDoubleSlashes. +// Returns false if it tries to ".." past the root directory in the drive (in which case +// it is an invalid path). +bool V_RemoveDotSlashes( char *pFilename, char separator = CORRECT_PATH_SEPARATOR, bool bRemoveDoubleSlashes = true ); + +// If pPath is a relative path, this function makes it into an absolute path +// using the current working directory as the base, or pStartingDir if it's non-NULL. +// Returns false if it runs out of room in the string, or if pPath tries to ".." past the root directory. +void V_MakeAbsolutePath( char *pOut, int outLen, const char *pPath, const char *pStartingDir = NULL ); + +// Creates a relative path given two full paths +// The first is the full path of the file to make a relative path for. +// The second is the full path of the directory to make the first file relative to +// Returns false if they can't be made relative (on separate drives, for example) +bool V_MakeRelativePath( const char *pFullPath, const char *pDirectory, char *pRelativePath, int nBufLen ); + +// Fixes up a file name, removing dot slashes, fixing slashes, converting to lowercase, etc. +void V_FixupPathName( OUT_Z_CAP(nOutLen) char *pOut, size_t nOutLen, const char *pPath ); + +// Adds a path separator to the end of the string if there isn't one already. Returns false if it would run out of space. +void V_AppendSlash( INOUT_Z_CAP(strSize) char *pStr, int strSize ); + +// Returns true if the path is an absolute path. +bool V_IsAbsolutePath( IN_Z const char *pPath ); + +// Scans pIn and replaces all occurences of pMatch with pReplaceWith. +// Writes the result to pOut. +// Returns true if it completed successfully. +// If it would overflow pOut, it fills as much as it can and returns false. +bool V_StrSubst( IN_Z const char *pIn, IN_Z const char *pMatch, const char *pReplaceWith, + OUT_Z_CAP(outLen) char *pOut, int outLen, bool bCaseSensitive=false ); + +// Split the specified string on the specified separator. +// Returns a list of strings separated by pSeparator. +// You are responsible for freeing the contents of outStrings (call outStrings.PurgeAndDeleteElements). +void V_SplitString( IN_Z const char *pString, IN_Z const char *pSeparator, CUtlVector > &outStrings ); + +// Just like V_SplitString, but it can use multiple possible separators. +void V_SplitString2( IN_Z const char *pString, const char **pSeparators, int nSeparators, CUtlVector > &outStrings ); + +// Returns false if the buffer is not large enough to hold the working directory name. +bool V_GetCurrentDirectory( OUT_Z_CAP(maxLen) char *pOut, int maxLen ); + +// Set the working directory thus. +bool V_SetCurrentDirectory( const char *pDirName ); + + +// This function takes a slice out of pStr and stores it in pOut. +// It follows the Python slice convention: +// Negative numbers wrap around the string (-1 references the last character). +// Large numbers are clamped to the end of the string. +void V_StrSlice( const char *pStr, int firstChar, int lastCharNonInclusive, OUT_Z_CAP(outSize) char *pOut, int outSize ); + +// Chop off the left nChars of a string. +void V_StrLeft( const char *pStr, int nChars, OUT_Z_CAP(outSize) char *pOut, int outSize ); + +// Chop off the right nChars of a string. +void V_StrRight( const char *pStr, int nChars, OUT_Z_CAP(outSize) char *pOut, int outSize ); + +// change "special" characters to have their c-style backslash sequence. like \n, \r, \t, ", etc. +// returns a pointer to a newly allocated string, which you must delete[] when finished with. +char *V_AddBackSlashesToSpecialChars( char const *pSrc ); + +// Force slashes of either type to be = separator character +void V_FixSlashes( char *pname, char separator = CORRECT_PATH_SEPARATOR ); + +// This function fixes cases of filenames like materials\\blah.vmt or somepath\otherpath\\ and removes the extra double slash. +void V_FixDoubleSlashes( char *pStr ); + +// Convert multibyte to wchar + back +// Specify -1 for nInSize for null-terminated string +void V_strtowcs( const char *pString, int nInSize, OUT_Z_BYTECAP(nOutSizeInBytes) wchar_t *pWString, int nOutSizeInBytes ); +void V_wcstostr( const wchar_t *pWString, int nInSize, OUT_Z_CAP(nOutSizeInBytes) char *pString, int nOutSizeInBytes ); + +// buffer-safe strcat +inline void V_strcat( INOUT_Z_CAP(cchDest) char *dest, const char *src, int cchDest ) +{ + V_strncat( dest, src, cchDest, COPY_ALL_CHARACTERS ); +} + +// Buffer safe wcscat +inline void V_wcscat( INOUT_Z_CAP(cchDest) wchar_t *dest, const wchar_t *src, int cchDest ) +{ + V_wcsncat( dest, src, cchDest, COPY_ALL_CHARACTERS ); +} + +//----------------------------------------------------------------------------- +// generic unique name helper functions +//----------------------------------------------------------------------------- + +// returns startindex if none found, 2 if "prefix" found, and n+1 if "prefixn" found +template < class NameArray > +int V_GenerateUniqueNameIndex( const char *prefix, const NameArray &nameArray, int startindex = 0 ) +{ + if ( prefix == NULL ) + return 0; + + int freeindex = startindex; + + int nNames = nameArray.Count(); + for ( int i = 0; i < nNames; ++i ) + { + const char *pName = nameArray[ i ]; + if ( !pName ) + continue; + + const char *pIndexStr = StringAfterPrefix( pName, prefix ); + if ( pIndexStr ) + { + int index = *pIndexStr ? atoi( pIndexStr ) : 1; + if ( index >= freeindex ) + { + // TODO - check that there isn't more junk after the index in pElementName + freeindex = index + 1; + } + } + } + + return freeindex; +} + +template < class NameArray > +bool V_GenerateUniqueName( OUT_Z_CAP(memsize) char *name, int memsize, const char *prefix, const NameArray &nameArray ) +{ + if ( name == NULL || memsize == 0 ) + return false; + + if ( prefix == NULL ) + { + name[ 0 ] = '\0'; + return false; + } + + int prefixLength = V_strlen( prefix ); + if ( prefixLength + 1 > memsize ) + { + name[ 0 ] = '\0'; + return false; + } + + int i = V_GenerateUniqueNameIndex( prefix, nameArray ); + if ( i <= 0 ) + { + V_strncpy( name, prefix, memsize ); + return true; + } + + int newlen = prefixLength + ( int )log10( ( float )i ) + 1; + if ( newlen + 1 > memsize ) + { + V_strncpy( name, prefix, memsize ); + return false; + } + + V_snprintf( name, memsize, "%s%d", prefix, i ); + return true; +} + + +// +// This utility class is for performing UTF-8 <-> UTF-16 conversion. +// It is intended for use with function/method parameters. +// +// For example, you can call +// FunctionTakingUTF16( CStrAutoEncode( utf8_string ).ToWString() ) +// or +// FunctionTakingUTF8( CStrAutoEncode( utf16_string ).ToString() ) +// +// The converted string is allocated off the heap, and destroyed when +// the object goes out of scope. +// +// if the string cannot be converted, NULL is returned. +// +// This class doesn't have any conversion operators; the intention is +// to encourage the developer to get used to having to think about which +// encoding is desired. +// +class CStrAutoEncode +{ +public: + + // ctor + explicit CStrAutoEncode( const char *pch ) + { + m_pch = pch; + m_pwch = NULL; +#if !defined( WIN32 ) && !defined(_WIN32) + m_pucs2 = NULL; + m_bCreatedUCS2 = false; +#endif + m_bCreatedUTF16 = false; + } + + // ctor + explicit CStrAutoEncode( const wchar_t *pwch ) + { + m_pch = NULL; + m_pwch = pwch; +#if !defined( WIN32 ) && !defined(_WIN32) + m_pucs2 = NULL; + m_bCreatedUCS2 = false; +#endif + m_bCreatedUTF16 = true; + } + +#if !defined(WIN32) && !defined(_WINDOWS) && !defined(_WIN32) + explicit CStrAutoEncode( const ucs2 *pwch ) + { + m_pch = NULL; + m_pwch = NULL; + m_pucs2 = pwch; + m_bCreatedUCS2 = true; + m_bCreatedUTF16 = false; + } +#endif + + // returns the UTF-8 string, converting on the fly. + const char* ToString() + { + PopulateUTF8(); + return m_pch; + } + + // returns the UTF-8 string - a writable pointer. + // only use this if you don't want to call const_cast + // yourself. We need this for cases like CreateProcess. + char* ToStringWritable() + { + PopulateUTF8(); + return const_cast< char* >( m_pch ); + } + + // returns the UTF-16 string, converting on the fly. + const wchar_t* ToWString() + { + PopulateUTF16(); + return m_pwch; + } + +#if !defined( WIN32 ) && !defined(_WIN32) + // returns the UTF-16 string, converting on the fly. + const ucs2* ToUCS2String() + { + PopulateUCS2(); + return m_pucs2; + } +#endif + + // returns the UTF-16 string - a writable pointer. + // only use this if you don't want to call const_cast + // yourself. We need this for cases like CreateProcess. + wchar_t* ToWStringWritable() + { + PopulateUTF16(); + return const_cast< wchar_t* >( m_pwch ); + } + + // dtor + ~CStrAutoEncode() + { + // if we're "native unicode" then the UTF-8 string is something we allocated, + // and vice versa. + if ( m_bCreatedUTF16 ) + { + delete [] m_pch; + } + else + { + delete [] m_pwch; + } +#if !defined( WIN32 ) && !defined(_WIN32) + if ( !m_bCreatedUCS2 && m_pucs2 ) + delete [] m_pucs2; +#endif + } + +private: + // ensure we have done any conversion work required to farm out a + // UTF-8 encoded string. + // + // We perform two heap allocs here; the first one is the worst-case + // (four bytes per Unicode code point). This is usually quite pessimistic, + // so we perform a second allocation that's just the size we need. + void PopulateUTF8() + { + if ( !m_bCreatedUTF16 ) + return; // no work to do + if ( m_pwch == NULL ) + return; // don't have a UTF-16 string to convert + if ( m_pch != NULL ) + return; // already been converted to UTF-8; no work to do + + // each Unicode code point can expand to as many as four bytes in UTF-8; we + // also need to leave room for the terminating NUL. + uint32 cbMax = 4 * static_cast( V_wcslen( m_pwch ) ) + 1; + char *pchTemp = new char[ cbMax ]; + if ( V_UnicodeToUTF8( m_pwch, pchTemp, cbMax ) ) + { + uint32 cchAlloc = static_cast( V_strlen( pchTemp ) ) + 1; + char *pchHeap = new char[ cchAlloc ]; + V_strncpy( pchHeap, pchTemp, cchAlloc ); + delete [] pchTemp; + m_pch = pchHeap; + } + else + { + // do nothing, and leave the UTF-8 string NULL + delete [] pchTemp; + } + } + + // ensure we have done any conversion work required to farm out a + // UTF-16 encoded string. + // + // We perform two heap allocs here; the first one is the worst-case + // (one code point per UTF-8 byte). This is sometimes pessimistic, + // so we perform a second allocation that's just the size we need. + void PopulateUTF16() + { + if ( m_bCreatedUTF16 ) + return; // no work to do + if ( m_pch == NULL ) + return; // no UTF-8 string to convert + if ( m_pwch != NULL ) + return; // already been converted to UTF-16; no work to do + + uint32 cchMax = static_cast( V_strlen( m_pch ) ) + 1; + wchar_t *pwchTemp = new wchar_t[ cchMax ]; + if ( V_UTF8ToUnicode( m_pch, pwchTemp, cchMax * sizeof( wchar_t ) ) ) + { + uint32 cchAlloc = static_cast( V_wcslen( pwchTemp ) ) + 1; + wchar_t *pwchHeap = new wchar_t[ cchAlloc ]; + V_wcsncpy( pwchHeap, pwchTemp, cchAlloc * sizeof( wchar_t ) ); + delete [] pwchTemp; + m_pwch = pwchHeap; + } + else + { + // do nothing, and leave the UTF-16 string NULL + delete [] pwchTemp; + } + } + +#if !defined( WIN32 ) && !defined(_WIN32) + // ensure we have done any conversion work required to farm out a + // UTF-16 encoded string. + // + // We perform two heap allocs here; the first one is the worst-case + // (one code point per UTF-8 byte). This is sometimes pessimistic, + // so we perform a second allocation that's just the size we need. + void PopulateUCS2() + { + if ( m_bCreatedUCS2 ) + return; + if ( m_pch == NULL ) + return; // no UTF-8 string to convert + if ( m_pucs2 != NULL ) + return; // already been converted to UTF-16; no work to do + + uint32 cchMax = static_cast( V_strlen( m_pch ) ) + 1; + ucs2 *pwchTemp = new ucs2[ cchMax ]; + if ( V_UTF8ToUCS2( m_pch, cchMax, pwchTemp, cchMax * sizeof( ucs2 ) ) ) + { + uint32 cchAlloc = cchMax; + ucs2 *pwchHeap = new ucs2[ cchAlloc ]; + memcpy( pwchHeap, pwchTemp, cchAlloc * sizeof( ucs2 ) ); + delete [] pwchTemp; + m_pucs2 = pwchHeap; + } + else + { + // do nothing, and leave the UTF-16 string NULL + delete [] pwchTemp; + } + } +#endif + + // one of these pointers is an owned pointer; whichever + // one is the encoding OTHER than the one we were initialized + // with is the pointer we've allocated and must free. + const char *m_pch; + const wchar_t *m_pwch; +#if !defined( WIN32 ) && !defined(_WIN32) + const ucs2 *m_pucs2; + bool m_bCreatedUCS2; +#endif + // "created as UTF-16", means our owned string is the UTF-8 string not the UTF-16 one. + bool m_bCreatedUTF16; + +}; + +// Encodes a string (or binary data) in URL encoding format, see rfc1738 section 2.2. +// Dest buffer should be 3 times the size of source buffer to guarantee it has room to encode. +void Q_URLEncodeRaw( OUT_Z_CAP(nDestLen) char *pchDest, int nDestLen, const char *pchSource, int nSourceLen ); + +// Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. +// Dest buffer should be at least as large as source buffer to gurantee room for decode. +// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed. +// +// Returns the amount of space actually used in the output buffer. +size_t Q_URLDecodeRaw( OUT_CAP(nDecodeDestLen) char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen ); + +// Encodes a string (or binary data) in URL encoding format, this isn't the strict rfc1738 format, but instead uses + for spaces. +// This is for historical reasons and HTML spec foolishness that lead to + becoming a de facto standard for spaces when encoding form data. +// Dest buffer should be 3 times the size of source buffer to guarantee it has room to encode. +void Q_URLEncode( OUT_Z_CAP(nDestLen) char *pchDest, int nDestLen, const char *pchSource, int nSourceLen ); + +// Decodes a string (or binary data) in URL encoding format, this isn't the strict rfc1738 format, but instead uses + for spaces. +// This is for historical reasons and HTML spec foolishness that lead to + becoming a de facto standard for spaces when encoding form data. +// Dest buffer should be at least as large as source buffer to gurantee room for decode. +// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed. +// +// Returns the amount of space actually used in the output buffer. +size_t Q_URLDecode( OUT_CAP(nDecodeDestLen) char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen ); + + +// NOTE: This is for backward compatability! +// We need to DLL-export the Q methods in vstdlib but not link to them in other projects +#if !defined( VSTDLIB_BACKWARD_COMPAT ) + +#define Q_memset V_memset +#define Q_memcpy V_memcpy +#define Q_memmove V_memmove +#define Q_memcmp V_memcmp +#define Q_strlen V_strlen +#define Q_strcpy V_strcpy +#define Q_strrchr V_strrchr +#define Q_strcmp V_strcmp +#define Q_wcscmp V_wcscmp +#define Q_stricmp V_stricmp +#define Q_strstr V_strstr +#define Q_strupr V_strupr +#define Q_strlower V_strlower +#define Q_wcslen V_wcslen +#define Q_strncmp V_strncmp +#define Q_strcasecmp V_strcasecmp +#define Q_strncasecmp V_strncasecmp +#define Q_strnicmp V_strnicmp +#define Q_atoi V_atoi +#define Q_atoi64 V_atoi64 +#define Q_atoui64 V_atoui64 +#define Q_atof V_atof +#define Q_stristr V_stristr +#define Q_strnistr V_strnistr +#define Q_strnchr V_strnchr +#define Q_normalizeFloatString V_normalizeFloatString +#define Q_strncpy V_strncpy +#define Q_snprintf V_snprintf +#define Q_wcsncpy V_wcsncpy +#define Q_strncat V_strncat +#define Q_strnlwr V_strnlwr +#define Q_vsnprintf V_vsnprintf +#define Q_vsnprintfRet V_vsnprintfRet +#define Q_pretifymem V_pretifymem +#define Q_pretifynum V_pretifynum +#define Q_UTF8ToUnicode V_UTF8ToUnicode +#define Q_UnicodeToUTF8 V_UnicodeToUTF8 +#define Q_hextobinary V_hextobinary +#define Q_binarytohex V_binarytohex +#define Q_FileBase V_FileBase +#define Q_StripTrailingSlash V_StripTrailingSlash +#define Q_StripExtension V_StripExtension +#define Q_DefaultExtension V_DefaultExtension +#define Q_SetExtension V_SetExtension +#define Q_StripFilename V_StripFilename +#define Q_StripLastDir V_StripLastDir +#define Q_UnqualifiedFileName V_UnqualifiedFileName +#define Q_ComposeFileName V_ComposeFileName +#define Q_ExtractFilePath V_ExtractFilePath +#define Q_ExtractFileExtension V_ExtractFileExtension +#define Q_GetFileExtension V_GetFileExtension +#define Q_RemoveDotSlashes V_RemoveDotSlashes +#define Q_MakeAbsolutePath V_MakeAbsolutePath +#define Q_AppendSlash V_AppendSlash +#define Q_IsAbsolutePath V_IsAbsolutePath +#define Q_StrSubst V_StrSubst +#define Q_SplitString V_SplitString +#define Q_SplitString2 V_SplitString2 +#define Q_StrSlice V_StrSlice +#define Q_StrLeft V_StrLeft +#define Q_StrRight V_StrRight +#define Q_FixSlashes V_FixSlashes +#define Q_strtowcs V_strtowcs +#define Q_wcstostr V_wcstostr +#define Q_strcat V_strcat +#define Q_GenerateUniqueNameIndex V_GenerateUniqueNameIndex +#define Q_GenerateUniqueName V_GenerateUniqueName +#define Q_MakeRelativePath V_MakeRelativePath +#define Q_qsort_s V_qsort_s + +#endif // !defined( VSTDLIB_DLL_EXPORT ) + + +#ifdef POSIX +#define FMT_WS L"%ls" +#else +#define FMT_WS L"%s" +#endif + + +#endif // TIER1_STRTOOLS_H diff --git a/public/tier1/thash.h b/public/tier1/thash.h new file mode 100644 index 0000000..5102074 --- /dev/null +++ b/public/tier1/thash.h @@ -0,0 +1,698 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef THASH_H +#define THASH_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +//#define DBGFLAG_THASH // Perform extra sanity checks on the THash + + +// THash +// This is a heavyweight, templatized version of DHash. +// It differs from DHash in the following ways: +// - It's templetized, and automatically constructs and destructs its records as appropriate +// - It provides a scheduling service, which can be used to touch every record in the table +// at a specified interval. The scheduler is low-overhead, and provides a very smooth +// distribution of touches across frames. + +// Template arguments: +// Data: the class to be stored in the hash table +// I: the type of the primary key (uint32 by default) +template +class CTHash +{ +private: + // RecHdr + // We insert one of these at the beginning of every record. It's used for + // keeping the records in a linked list. + typedef struct RecHdr_t + { + RecHdr_t *m_pRecHdrNext; // Next item in our linked list + RecHdr_t *m_pRecHdrPrev; // Previous item in our linked list + I m_unKey; // Key of this item + int m_iBucket; // The bucket we're in + int m_nRunRatio; // We want to run 1 cycle out of every m_nRunRatio + // cycles (not at all if 0). +#ifdef DBGFLAG_THASH + uint m_iCycleLast; // Last cycle we were visited (whether or not we ran) +#endif + } RecHdr_t; + + // Bucket + // Each hash bucket is represented by a Bucket structure, which points to the + // first record with the bucket's hash. + typedef struct Bucket_t + { + RecHdr_t *m_pRecHdrFirst; // First record in our list + } Bucket_t; + + +public: + // Constructors & destructors + CTHash( int cFramesPerCycle ); + ~CTHash(); + + // Initializer + void Init( int cRecordInit, int cBuckets ); + + // Insert a record into the table + Data *PvRecordInsert( I unKey ); + // Insert a record into the table and set the allocated object's pointer as the hash key + Data *PvRecordInsertAutoKey(); + // Changes the key for a previously inserted item + void ChangeKey( Data * pvRecord, I unOldKey, I unNewKey ); + + // Remove a record + void Remove( I unKey ); + // Remove a record + void Remove( Data * pvRecord ); + // Remove all records + void RemoveAll(); + + // Find a record + Data *PvRecordFind( I unKey ) const; + + // How many records do we have + int Count() const { return m_cRecordInUse; } + + // Iterate through our members + Data *PvRecordFirst() const; + Data *PvRecordNext( Data *pvRecordCur ) const; + + // We provide a scheduling service. Call StartFrameSchedule when you want to start running + // records in a given frame, and repeatedly call PvRecordRun until it returns NULL (or you + // run our of time). + void SetRunRatio( Data *pvRecord, int nRunRatio ); + void SetMicroSecPerCycle( int cMicroSecPerCycle, int cMicroSecPerFrame ) { m_cFramesPerCycle = cMicroSecPerCycle / cMicroSecPerFrame; } + void StartFrameSchedule( bool bNewFrame ); + Data *PvRecordRun(); + + bool BCompletedPass(); + +#ifdef DBGFLAG_VALIDATE + virtual void Validate( CValidator &validator, const char *pchName ); +#endif // DBGFLAG_VALIDATE + + +private: + // Insert a record into the table + Data *PvRecordInsertInternal( RecHdr_t *pRecHdr, I unKey ); + + // Get the record associated with a THashHdr + Data *PvRecordFromPRecHdr( RecHdr_t *pRecHdr ) const { return ( Data * ) ( ( ( uint8 * ) pRecHdr + sizeof( RecHdr_t ) ) ); } + + // Get the RecHdr preceding a PvRecord + RecHdr_t *PRecHdrFromPvRecord( Data *pvRecord ) const { return ( ( ( RecHdr_t * ) pvRecord ) - 1 ); } + + // Get the hash bucket corresponding to a key + int IBucket( I unKey ) const; + + void InsertIntoHash( RecHdr_t *pRecHdr, I unKey ); + void RemoveFromHash( Data * pvRecord ); + + int m_cBucket; // # of hash buckets we have + Bucket_t *m_pBucket; // Big array of hash buckets + + CUtlMemoryPool *m_pMemoryPoolRecord; // All our data records + + int m_cRecordInUse; // # of records in use + RecHdr_t m_RecHdrHead; // Head of our linked list + RecHdr_t m_RecHdrTail; // Tail of our linked list + + int m_cFramesPerCycle; // Run each of our records once every m_cFramesPerCycle frames + RecHdr_t *m_pRecHdrRunNext; // Next record to run (be careful-- this is more complicated than it sounds) + int m_iBucketRunMax; // Stop running when we get to this bucket + uint m_iCycleCur; // Current cycle (ie, how many times we've made a complete scheduler pass) + uint m_iCycleLast; // Our previous cycle + uint m_iFrameCur; // Our current frame (incremented once each StartFrameSchedule) + uint m_iCycleLastReported; // Last cycle checked by BCompletedPass() +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input: cMicroSecRunInterval - How often we want the scheduler to run each of our records +//----------------------------------------------------------------------------- +template +CTHash::CTHash( int cFramesPerCycle ) +{ + m_cBucket = 0; + m_pBucket = NULL; + m_pMemoryPoolRecord = NULL; + m_cRecordInUse = 0; + + m_cFramesPerCycle = cFramesPerCycle; + m_pRecHdrRunNext = &m_RecHdrTail; // This will make us start at the beginning on our first frame + m_iBucketRunMax = 0; + m_iCycleCur = 0; + m_iCycleLast = 0; + m_iFrameCur = 0; + m_iCycleLastReported = 0; + + m_RecHdrHead.m_pRecHdrPrev = NULL; + m_RecHdrHead.m_pRecHdrNext = &m_RecHdrTail; + m_RecHdrHead.m_iBucket = -1; + + m_RecHdrTail.m_pRecHdrPrev = &m_RecHdrHead; + m_RecHdrTail.m_pRecHdrNext = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +template +CTHash::~CTHash() +{ + RemoveAll(); + + if ( NULL != m_pBucket ) + FreePv( m_pBucket ); + m_pBucket = NULL; + + if ( NULL != m_pMemoryPoolRecord ) + delete( m_pMemoryPoolRecord ); + m_pMemoryPoolRecord = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Initializer. Allocate our various arrays, and set up the free +// list. +// Input: cRecordInit - Initial # of data records we can contain +// cBucket - # of hash buckets we should use +//----------------------------------------------------------------------------- +template +void CTHash::Init( int cRecordInit, int cBucket ) +{ + Assert( cRecordInit > 0 ); // need to init with non-zero value or memory pool will never grow + + // Copy our parameters + m_cBucket = cBucket; + + // Alloc our arrays + m_pBucket = ( Bucket_t * ) PvAlloc( sizeof( Bucket_t ) * m_cBucket ); + m_pMemoryPoolRecord = new CUtlMemoryPool( sizeof( Data ) + sizeof( RecHdr_t ), cRecordInit, + CUtlMemoryPool::GROW_SLOW ); + + // Init the hash buckets + for ( int iBucket = 0; iBucket < m_cBucket; iBucket++ ) + m_pBucket[iBucket].m_pRecHdrFirst = NULL; + + // Make the tail have an illegally large bucket + m_RecHdrTail.m_iBucket = m_cBucket + 1; +} + + +//----------------------------------------------------------------------------- +// Purpose: Inserts a new record into the table +// Input: unKey - Primary key of the new record +// Output: Pointer to the new record +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordInsert( I unKey ) +{ + Assert( PvRecordFind( unKey ) == NULL ); // keys are unique; no record with this key may exist + + // Find a free record + RecHdr_t *pRecHdr = ( RecHdr_t * ) m_pMemoryPoolRecord->Alloc(); + + return PvRecordInsertInternal( pRecHdr, unKey ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Inserts a new record into the table and sets its key to the pointer +// value of the record +// Output: Pointer to the new record +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordInsertAutoKey() +{ + // Find a free record + RecHdr_t *pRecHdr = ( RecHdr_t * ) m_pMemoryPoolRecord->Alloc(); + + return PvRecordInsertInternal( pRecHdr, (I) PvRecordFromPRecHdr( pRecHdr ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Inserts an allocated record into the hash table with specified key +// and calls the constructor of the allocated object +// Input: pRecHdr - record to insert +// unKey - hash key to use for record +// Output: Pointer to the new record +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordInsertInternal( RecHdr_t *pRecHdr, I unKey ) +{ + InsertIntoHash( pRecHdr, unKey ); + + // assert that we don't have too many items per bucket + static bool s_bPerfWarning = false; + if ( !s_bPerfWarning && Count() >= ( 5 * m_cBucket ) ) + { + s_bPerfWarning = true; + AssertMsg( false, "Performance warning: too many items, not enough buckets" ); + Msg( "not enough buckets in thash class %s (%d records, %d buckets)\n", +#ifdef _WIN32 + typeid(*this).raw_name(), +#else + typeid(*this).name(), +#endif + Count(), m_cBucket ); + } + + // Construct ourselves + Data *pData = PvRecordFromPRecHdr( pRecHdr ); + Construct( pData ); + return pData; +} + +//----------------------------------------------------------------------------- +// Purpose: Changes key on previously inserted item +// Input: pvRecord - record to change key for +// unOldKey - old key (not strictly needed, but helpful consistency check) +// unNewKey - new key to use +//----------------------------------------------------------------------------- +template +void CTHash::ChangeKey( Data * pvRecord, I unOldKey, I unNewKey ) +{ + Data * pvRecordFound = PvRecordFind( unOldKey ); + Assert( pvRecordFound == pvRecord ); + if ( pvRecordFound == pvRecord ) + { + RemoveFromHash( pvRecord ); + InsertIntoHash( PRecHdrFromPvRecord( pvRecord), unNewKey ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Removes the entry with a specified key from the table +// Input: unKey - Key of the entry to remove +//----------------------------------------------------------------------------- +template +void CTHash::Remove( I unKey ) +{ + Data *pvRemove = ( Data * ) PvRecordFind( unKey ); + Assert( pvRemove ); + if ( !pvRemove ) + return; + Remove( pvRemove ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Removes the specified entry from the table +// Input: pvRemove - Pointer to the entry to remove +//----------------------------------------------------------------------------- +template +void CTHash::Remove( Data * pvRemove ) +{ + // Destruct the record we're removing + Destruct( pvRemove ); + + RemoveFromHash( pvRemove ); + m_pMemoryPoolRecord->Free( PRecHdrFromPvRecord( pvRemove ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Removes all entries from the table +//----------------------------------------------------------------------------- +template +void CTHash::RemoveAll() +{ + Data * pvRecord = PvRecordFirst(); + while ( pvRecord ) + { + Data *pvRecordNext = PvRecordNext( pvRecord ); + Remove( pvRecord ); + pvRecord = pvRecordNext; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Finds the entry with a specified key +// Input: unKey - Key to find +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordFind( I unKey ) const +{ + // Find our hash bucket + int iBucket = IBucket( unKey ); + + // Walk the bucket's list looking for an exact match + for ( RecHdr_t *pRecHdr = m_pBucket[iBucket].m_pRecHdrFirst; + NULL != pRecHdr && pRecHdr->m_iBucket == iBucket; + pRecHdr = pRecHdr->m_pRecHdrNext ) + { + if ( unKey == pRecHdr->m_unKey ) + return PvRecordFromPRecHdr( pRecHdr ); + } + + // Didn't find a match + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Finds our first record +// Output: Pointer to our first record +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordFirst() const +{ + if ( &m_RecHdrTail != m_RecHdrHead.m_pRecHdrNext ) + return PvRecordFromPRecHdr( m_RecHdrHead.m_pRecHdrNext ); + else + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Iterates to the record after a given record +// Input: Pointer to a current record +// Output: Pointer to the next record +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordNext( Data *pvRecordCur ) const +{ + RecHdr_t *pRecHdr = PRecHdrFromPvRecord( pvRecordCur ); + if ( &m_RecHdrTail == pRecHdr->m_pRecHdrNext ) + return NULL; + + return PvRecordFromPRecHdr( pRecHdr->m_pRecHdrNext ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the run ratio of a particular record in the hash table. +// The record will be run 1 cycle out of every nRunRatio cycles. +// Input: pvRecord - The record we're setting +// nRunRatio - The run ratio for this record +//----------------------------------------------------------------------------- +template +void CTHash::SetRunRatio( Data *pvRecord, int nRunRatio ) +{ + PRecHdrFromPvRecord( pvRecord )->m_nRunRatio = nRunRatio; +} + + +//----------------------------------------------------------------------------- +// Purpose: Prepares us to run all records that are due to be run this frame. +// Records are run at a particular time dependent on their hash bucket, +// regardless of when they were last run. +// Input: bNewFrame - True if this is a new frame. If false, we've run +// off the end of the list and are checking whether +// we need to keep going at the beginning. +//----------------------------------------------------------------------------- +template +void CTHash::StartFrameSchedule( bool bNewFrame ) +{ + // Calculate our current frame and cycle cycle + if ( bNewFrame ) + { + m_iCycleLast = m_iCycleCur; + m_iFrameCur++; + m_iCycleCur = m_iFrameCur / m_cFramesPerCycle; + } + + // Calculate the last bucket to run + int iFrameInCycle = m_iFrameCur % m_cFramesPerCycle; + m_iBucketRunMax = ( int ) ( ( ( int64 ) ( iFrameInCycle + 1 ) * ( int64 ) m_cBucket ) + / ( int64 ) m_cFramesPerCycle ); + AssertFatal( m_iBucketRunMax >= 0 && m_iBucketRunMax <= m_cBucket ); + + // Are we starting a new cycle? + if ( m_iCycleCur > m_iCycleLast ) + { +#ifdef DBGFLAG_THASH + Assert( m_iCycleCur == m_iCycleLast + 1 ); +#endif + + // Did we finish the last cycle? + if ( &m_RecHdrTail == m_pRecHdrRunNext ) + { + m_pRecHdrRunNext = m_RecHdrHead.m_pRecHdrNext; + } + // No-- finish it up before moving on + else + { + m_iBucketRunMax = m_cBucket + 1; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the next record to run, if any +// Output: Pointer to the next record that needs to run (NULL if we're done) +//----------------------------------------------------------------------------- +template +Data *CTHash::PvRecordRun() +{ + // Loop until we find a record to run, or until we pass m_iBucketRunMax + for ( ; ; ) + { + // Are we past our stopping point? + if ( m_pRecHdrRunNext->m_iBucket >= m_iBucketRunMax ) + { + // If this cycle ran to the very end, see if we need to start over + if ( m_iBucketRunMax > m_cBucket ) + { + StartFrameSchedule( false ); + continue; + } + + return NULL; + } + +#ifdef DBGFLAG_THASH + Assert( m_pRecHdrRunNext->m_iBucket >= m_iBucketRunFirst ); + if ( 0 != m_pRecHdrRunNext->m_iCycleLast ) + { + if ( m_pRecHdrRunNext->m_iCycleLast == m_iCycleCur ) + { + DMsg( SPEW_CONSOLE, 1, "Double cycle: hdr = 0x%x, last frame = %d, curFrame = %d, first = %d, last = %d, bucket = %d\n", + m_pRecHdrRunNext, m_pRecHdrRunNext->m_iFrameLast, m_iFrame, + m_iBucketRunFirst, m_iBucketRunMax, m_pRecHdrRunNext->m_iBucket ); + } + else if ( m_pRecHdrRunNext->m_iCycleLast != m_iCycleCur - 1 ) + { + DMsg( SPEW_CONSOLE, 1, "Skipped cycle: hdr = 0x%x, cycleLast = %u, cycleCur = %u (missed %u cycles)\n", + m_pRecHdrRunNext, m_pRecHdrRunNext->m_iCycleLast, m_iCycleCur, + m_iCycleCur - m_pRecHdrRunNext->m_iCycleLast ); + Assert( false ); + } + } + m_pRecHdrRunNext->m_iCycleLast = m_iCycleCur; + m_pRecHdrRunNext->m_iFrameLast = m_iFrame; +#endif + + // Set up the record to run next time + RecHdr_t *pRecHdrCur = m_pRecHdrRunNext; + m_pRecHdrRunNext = m_pRecHdrRunNext->m_pRecHdrNext; + + // Does this record need to run? + if ( 0 == pRecHdrCur->m_nRunRatio ) + continue; + + if ( 0 == m_iCycleCur % pRecHdrCur->m_nRunRatio ) + return PvRecordFromPRecHdr( pRecHdrCur ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Return true if we've completed a scheduler pass since last called +//----------------------------------------------------------------------------- +template +bool CTHash::BCompletedPass() +{ + if ( m_iCycleCur != m_iCycleLastReported ) + { + m_iCycleLastReported = m_iCycleCur; + return true; + } + return false; +} + + +extern const unsigned char g_CTHashRandomValues[256]; // definition lives in globals.cpp + +//----------------------------------------------------------------------------- +// Purpose: Returns the index of the hash bucket corresponding to a particular key +// Input: unKey - Key to find +// Output: Index of the hash bucket corresponding to unKey +//----------------------------------------------------------------------------- +template +int CTHash::IBucket( I unKey ) const +{ + AssertFatal( m_cBucket > 0 ); + + // This is a pearsons hash variant that returns a maximum of 32 bits + size_t size = sizeof(I); + const uint8 * k = (const uint8 *) &unKey; + uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n; + + while (size) + { + --size; + n = *k++; + byte_one = g_CTHashRandomValues[byte_one ^ n]; + + if (size) + { + --size; + n = *k++; + byte_two = g_CTHashRandomValues[byte_two ^ n]; + } + else + break; + + if (size) + { + --size; + n = *k++; + byte_three = g_CTHashRandomValues[byte_three ^ n]; + } + else + break; + + if (size) + { + --size; + n = *k++; + byte_four = g_CTHashRandomValues[byte_four ^ n]; + } + else + break; + } + + uint32 idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one; + idx = idx % m_cBucket; + return ( (int) idx ); +} + + +#ifdef DBGFLAG_VALIDATE +//----------------------------------------------------------------------------- +// Purpose: Run a global validation pass on all of our data structures and memory +// allocations. +// Input: validator - Our global validator object +// pchName - Our name (typically a member var in our container) +//----------------------------------------------------------------------------- +template +void CTHash::Validate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + + validator.ClaimMemory( m_pBucket ); + ValidatePtr( m_pMemoryPoolRecord ); + +#if defined( _DEBUG ) + // first verify m_cRecordInUse + Data * pvRecord = PvRecordFirst(); + int cItems = 0; + while ( pvRecord ) + { + Data *pvRecordNext = PvRecordNext( pvRecord ); + cItems++; + pvRecord = pvRecordNext; + } + Assert( m_cRecordInUse == cItems ); + // then ask the mempool to verify this + if ( m_pMemoryPoolRecord ) + m_pMemoryPoolRecord->LeakCheck( cItems ); +#endif // _DEBUG +} +#endif // DBGFLAG_VALIDATE + + +//----------------------------------------------------------------------------- +// Purpose: Inserts a new record into the table +// Input: unKey - Primary key of the new record +// Output: Pointer to the new record +//----------------------------------------------------------------------------- +template +void CTHash::InsertIntoHash( RecHdr_t *pRecHdr, I unKey ) +{ + m_cRecordInUse++; + + // Init the RecHdr + pRecHdr->m_unKey = unKey; + pRecHdr->m_nRunRatio = 1; + + // Find our hash bucket + int iBucket = IBucket( unKey ); + pRecHdr->m_iBucket = iBucket; +#ifdef DBGFLAG_THASH + pRecHdr->m_iCycleLast = 0; +#endif + + // Find where to insert ourselves in the linked list + RecHdr_t *pRecHdrInsertBefore = &m_RecHdrTail; + // Find the first bucket with anything in it that's at or after our bucket + for ( int iBucketT = iBucket; iBucketT < m_cBucket; iBucketT++ ) + { + if ( NULL != m_pBucket[iBucketT].m_pRecHdrFirst ) + { + pRecHdrInsertBefore = m_pBucket[iBucketT].m_pRecHdrFirst; + break; + } + } + + // Insert ourselves + pRecHdr->m_pRecHdrNext = pRecHdrInsertBefore; + pRecHdr->m_pRecHdrPrev = pRecHdrInsertBefore->m_pRecHdrPrev; + pRecHdrInsertBefore->m_pRecHdrPrev = pRecHdr; + pRecHdr->m_pRecHdrPrev->m_pRecHdrNext = pRecHdr; + + // Our bucket should point to us + m_pBucket[iBucket].m_pRecHdrFirst = pRecHdr; +} + + +//----------------------------------------------------------------------------- +// Purpose: Removes the specified entry from the table +// Input: pvRemove - Pointer to the entry to remove +//----------------------------------------------------------------------------- +template +void CTHash::RemoveFromHash( Data * pvRemove ) +{ + // Find our RecHdr + RecHdr_t *pRecHdr = PRecHdrFromPvRecord( pvRemove ); + + // If our bucket points to us, point it to the next record (or else NULL) + int iBucket = IBucket( pRecHdr->m_unKey ); + if ( pRecHdr == m_pBucket[iBucket].m_pRecHdrFirst ) + { + if ( pRecHdr->m_pRecHdrNext->m_iBucket == iBucket ) + m_pBucket[iBucket].m_pRecHdrFirst = pRecHdr->m_pRecHdrNext; + else + m_pBucket[iBucket].m_pRecHdrFirst = NULL; + } + + // Remove us from the linked list + pRecHdr->m_pRecHdrPrev->m_pRecHdrNext = pRecHdr->m_pRecHdrNext; + pRecHdr->m_pRecHdrNext->m_pRecHdrPrev = pRecHdr->m_pRecHdrPrev; + + // Are we the next record to run? + if ( pRecHdr == m_pRecHdrRunNext ) + m_pRecHdrRunNext = pRecHdr->m_pRecHdrNext; + + m_cRecordInUse--; +} + +#endif // THASH_H diff --git a/public/tier1/tier1.h b/public/tier1/tier1.h new file mode 100644 index 0000000..ac79067 --- /dev/null +++ b/public/tier1/tier1.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER1_H +#define TIER1_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "appframework/IAppSystem.h" +#include "tier1/convar.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ICvar; +class IProcessUtils; + + +//----------------------------------------------------------------------------- +// These tier1 libraries must be set by any users of this library. +// They can be set by calling ConnectTier1Libraries. +// It is hoped that setting this, and using this library will be the common mechanism for +// allowing link libraries to access tier1 library interfaces +//----------------------------------------------------------------------------- + +// These are marked DLL_EXPORT for Linux. +DLL_EXPORT ICvar *cvar; +extern ICvar *g_pCVar; +extern IProcessUtils *g_pProcessUtils; + + +//----------------------------------------------------------------------------- +// Call this to connect to/disconnect from all tier 1 libraries. +// It's up to the caller to check the globals it cares about to see if ones are missing +//----------------------------------------------------------------------------- +void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount ); +void DisconnectTier1Libraries(); + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier1AppSystem : public CTier0AppSystem< IInterface > +{ + typedef CTier0AppSystem< IInterface > BaseClass; + +public: + CTier1AppSystem( bool bIsPrimaryAppSystem = true ) : BaseClass( bIsPrimaryAppSystem ) + { + } + + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( BaseClass::IsPrimaryAppSystem() ) + { + ConnectTier1Libraries( &factory, 1 ); + } + return true; + } + + virtual void Disconnect() + { + if ( BaseClass::IsPrimaryAppSystem() ) + { + DisconnectTier1Libraries(); + } + BaseClass::Disconnect(); + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + if ( g_pCVar && BaseClass::IsPrimaryAppSystem() ) + { + ConVar_Register( ConVarFlag ); + } + return INIT_OK; + } + + virtual void Shutdown() + { + if ( g_pCVar && BaseClass::IsPrimaryAppSystem() ) + { + ConVar_Unregister( ); + } + BaseClass::Shutdown( ); + } +}; + + +#endif // TIER1_H + diff --git a/public/tier1/tokenreader.h b/public/tier1/tokenreader.h new file mode 100644 index 0000000..b174869 --- /dev/null +++ b/public/tier1/tokenreader.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TOKENREADER_H +#define TOKENREADER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/basetypes.h" + +#ifdef _WIN32 +#pragma warning(push, 1) +#pragma warning(disable:4701 4702 4530) +#endif + +#undef min +#undef max +#include +#include "valve_minmax_on.h" + +#ifdef _WIN32 +#pragma warning(pop) +#endif + +#include + + +typedef enum +{ + TOKENSTRINGTOOLONG = -4, + TOKENERROR = -3, + TOKENNONE = -2, + TOKENEOF = -1, + OPERATOR, + INTEGER, + STRING, + IDENT +} trtoken_t; + + +#define IsToken(s1, s2) !strcmpi(s1, s2) + +#define MAX_TOKEN 128 + 1 +#define MAX_IDENT 64 + 1 +#define MAX_STRING 128 + 1 + + +class TokenReader : private std::ifstream +{ +public: + + TokenReader(); + + bool Open(const char *pszFilename); + trtoken_t NextToken(char *pszStore, int nSize); + trtoken_t NextTokenDynamic(char **ppszStore); + void Close(); + + void IgnoreTill(trtoken_t ttype, const char *pszToken); + void Stuff(trtoken_t ttype, const char *pszToken); + bool Expecting(trtoken_t ttype, const char *pszToken); + const char *Error(char *error, ...); + trtoken_t PeekTokenType(char* = NULL, int maxlen = 0); + + inline int GetErrorCount(void); + +private: + // compiler can't generate an assignment operator since descended from std::ifstream + inline TokenReader(TokenReader const &); + inline int operator=(TokenReader const &); + + trtoken_t GetString(char *pszStore, int nSize); + bool SkipWhiteSpace(void); + + int m_nLine; + int m_nErrorCount; + + char m_szFilename[128]; + char m_szStuffed[128]; + bool m_bStuffed; + trtoken_t m_eStuffed; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Returns the total number of parsing errors since this file was opened. +//----------------------------------------------------------------------------- +int TokenReader::GetErrorCount(void) +{ + return(m_nErrorCount); +} + + +#endif // TOKENREADER_H diff --git a/public/tier1/uniqueid.h b/public/tier1/uniqueid.h new file mode 100644 index 0000000..fd3fe26 --- /dev/null +++ b/public/tier1/uniqueid.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Utilities for globally unique IDs +//=============================================================================// + +#ifndef UNIQUEID_H +#define UNIQUEID_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct UniqueId_t; +class CUtlBuffer; + + +//----------------------------------------------------------------------------- +// Defines a globally unique ID +//----------------------------------------------------------------------------- +struct UniqueId_t +{ + unsigned char m_Value[16]; +}; + + +//----------------------------------------------------------------------------- +// Methods related to unique ids +//----------------------------------------------------------------------------- +void CreateUniqueId( UniqueId_t *pDest ); +void InvalidateUniqueId( UniqueId_t *pDest ); +bool IsUniqueIdValid( const UniqueId_t &id ); +bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 ); +void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen ); +bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen = 0 ); +void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest ); +bool Serialize( CUtlBuffer &buf, const UniqueId_t &src ); +bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest ); + +inline bool operator ==( const UniqueId_t& lhs, const UniqueId_t& rhs ) +{ + return !Q_memcmp( (void *)&lhs.m_Value[ 0 ], (void *)&rhs.m_Value[ 0 ], sizeof( lhs.m_Value ) ); +} + + +#endif // UNIQUEID_H + diff --git a/public/tier1/utlallocation.h b/public/tier1/utlallocation.h new file mode 100644 index 0000000..65416bc --- /dev/null +++ b/public/tier1/utlallocation.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// The CUtlAllocation class: +// A single allocation in the style of CUtlMemory/CUtlString/CUtlBuffer +// as compact as possible, no virtuals or extraneous data +// to be used primarily to replace CUtlBuffer +//============================================================================= + +#ifndef UTLALLOCATION_H +#define UTLALLOCATION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlmemory.h" + +class CUtlAllocation +{ +public: + + // constructor, destructor + CUtlAllocation() + { + m_pMemory = NULL; + } + + CUtlAllocation( const void *pMemory, int cub ) + { + m_pMemory = NULL; + Copy( pMemory, cub ); + } + + CUtlAllocation( CUtlAllocation const &src ) + { + m_pMemory = NULL; + Copy( src ); + } + + ~CUtlAllocation() + { + Purge(); + } + + CUtlAllocation &operator=( CUtlAllocation const &src ) + { + Copy( src ); + return *this; + } + + bool operator==( CUtlAllocation const &src ) + { + if ( Count() != src.Count() ) + return false; + return Q_memcmp( Base(), src.Base(), Count() ) == 0; + } + + void Copy( const void *pMemory, int cub ) + { + if ( cub == 0 || pMemory == NULL ) + { + Purge(); + return; + } + if ( cub != Count() ) + { + Purge(); + m_pMemory = (ActualMemory_t *)malloc( cub + sizeof( int ) ); + m_pMemory->cub = cub; + } + Q_memcpy( Base(), pMemory, cub ); + } + + // Gets the base address + uint8* Base() + { + if ( m_pMemory == NULL ) + return NULL; + return m_pMemory->rgub; + } + + const uint8* Base() const + { + if ( m_pMemory == NULL ) + return NULL; + return m_pMemory->rgub; + } + + // Size + int Count() const + { + if ( m_pMemory == NULL ) + return 0; + return m_pMemory->cub; + } + + // Memory deallocation + void Purge() + { + if ( m_pMemory ) + free(m_pMemory); + m_pMemory = NULL; + } + + void Copy( const CUtlAllocation &alloc ) + { + Copy( alloc.Base(), alloc.Count() ); + } + + void Swap( CUtlAllocation &alloc ) + { + ActualMemory_t *pTemp = m_pMemory; + m_pMemory = alloc.m_pMemory; + alloc.m_pMemory = pTemp; + } + + void Alloc( int cub ) + { + Purge(); + m_pMemory = (ActualMemory_t *)malloc( cub + sizeof( int ) ); + m_pMemory->cub = cub; + } + +private: + struct ActualMemory_t + { + int cub; + uint8 rgub[4]; // i'd prefer to make this 0 but the compiler whines when i do + }; + + ActualMemory_t *m_pMemory; +}; + +#endif // UTLALLOCATION_H diff --git a/public/tier1/utlarray.h b/public/tier1/utlarray.h new file mode 100644 index 0000000..ce5ffe8 --- /dev/null +++ b/public/tier1/utlarray.h @@ -0,0 +1,332 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable array class that maintains a free list and keeps elements +// in the same location +//=============================================================================// + +#ifndef UTLARRAY_H +#define UTLARRAY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "vstdlib/random.h" + +#define FOR_EACH_ARRAY( vecName, iteratorName ) \ + for ( int iteratorName = 0; (vecName).IsUtlArray && iteratorName < (vecName).Count(); iteratorName++ ) +#define FOR_EACH_ARRAY_BACK( vecName, iteratorName ) \ + for ( int iteratorName = (vecName).Count()-1; (vecName).IsUtlArray && iteratorName >= 0; iteratorName-- ) + +// utlarray derives from this so we can do the type check above +struct base_array_t +{ +public: + static const bool IsUtlArray = true; // Used to match this at compiletime +}; + +#if defined( GNUC ) && defined( DEBUG ) +// gcc in debug doesn't optimize away the need for the storage of IsUtlArray so make one here +// as this is in a shared header use SELECTANY to make it throw away the dupe symbols +const bool base_array_t::IsUtlArray SELECTANY; +#endif + +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlArray : public base_array_t +{ +public: + typedef T ElemType_t; + typedef T* iterator; + typedef const T* const_iterator; + + CUtlArray(); + CUtlArray( T* pMemory, size_t count ); + ~CUtlArray(); + + CUtlArray& operator=( const CUtlArray &other ); + CUtlArray( CUtlArray const& vec ); + + // element access + T& operator[]( int i ); + const T& operator[]( int i ) const; + T& Element( int i ); + const T& Element( int i ) const; + T& Random(); + const T& Random() const; + + // STL compatible member functions. These allow easier use of std::sort + // and they are forward compatible with the C++ 11 range-based for loops. + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + T* Base(); + const T* Base() const; + + // Returns the number of elements in the array, NumAllocated() is included for consistency with UtlVector + int Count() const; + int NumAllocated() const; + + // Is element index valid? + bool IsValidIndex( int i ) const; + static int InvalidIndex(); + + void CopyArray( const T *pArray, size_t count ); + + void Swap( CUtlArray< T, MAX_SIZE > &vec ); + + // Finds an element (element needs operator== defined) + int Find( const T& src ) const; + void FillWithValue( const T& src ); + + bool HasElement( const T& src ) const; + + // calls delete on each element in it. + void DeleteElements(); + + void Sort( int (__cdecl *pfnCompare)(const T *, const T *) ); + +protected: + T m_Memory[ MAX_SIZE ]; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +inline CUtlArray::CUtlArray() +{ +} + +template< typename T, size_t MAX_SIZE > +inline CUtlArray::CUtlArray( T* pMemory, size_t count ) +{ + CopyArray( pMemory, count ); +} + +template< typename T, size_t MAX_SIZE > +inline CUtlArray::~CUtlArray() +{ +} + +template< typename T, size_t MAX_SIZE > +inline CUtlArray& CUtlArray::operator=( const CUtlArray &other ) +{ + if ( this != &other ) + { + for ( size_t n = 0; n < MAX_SIZE; ++n ) + { + m_Memory[n] = other.m_Memory[n]; + } + } + return *this; +} + +template< typename T, size_t MAX_SIZE > +inline CUtlArray::CUtlArray( CUtlArray const& vec ) +{ + for ( size_t n = 0; n < MAX_SIZE; ++n ) + { + m_Memory[n] = vec.m_Memory[n]; + } +} + +template< typename T, size_t MAX_SIZE > +typename CUtlArray::iterator CUtlArray::begin() +{ + return Base(); +} + +template< typename T, size_t MAX_SIZE > +typename CUtlArray::const_iterator CUtlArray::begin() const +{ + return Base(); +} + +template< typename T, size_t MAX_SIZE > +typename CUtlArray::iterator CUtlArray::end() +{ + return Base() + Count(); +} + +template< typename T, size_t MAX_SIZE > +typename CUtlArray::const_iterator CUtlArray::end() const +{ + return Base() + Count(); +} + +template< typename T, size_t MAX_SIZE > +inline T *CUtlArray::Base() +{ + return &m_Memory[0]; +} + +template< typename T, size_t MAX_SIZE > +inline const T *CUtlArray::Base() const +{ + return &m_Memory[0]; +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +inline T& CUtlArray::operator[]( int i ) +{ + Assert( IsValidIndex( i ) ); + return m_Memory[ i ]; +} + +template< typename T, size_t MAX_SIZE > +inline const T& CUtlArray::operator[]( int i ) const +{ + Assert( IsValidIndex( i ) ); + return m_Memory[ i ]; +} + +template< typename T, size_t MAX_SIZE > +inline T& CUtlArray::Element( int i ) +{ + Assert( IsValidIndex( i ) ); + return m_Memory[ i ]; +} + +template< typename T, size_t MAX_SIZE > +inline const T& CUtlArray::Element( int i ) const +{ + Assert( IsValidIndex( i ) ); + return m_Memory[ i ]; +} + +template< typename T, size_t MAX_SIZE > +inline T& CUtlArray::Random() +{ + Assert( MAX_SIZE > 0 ); + return m_Memory[ RandomInt( 0, MAX_SIZE - 1 ) ]; +} + +template< typename T, size_t MAX_SIZE > +inline const T& CUtlArray::Random() const +{ + Assert( MAX_SIZE > 0 ); + return m_Memory[ RandomInt( 0, MAX_SIZE - 1 ) ]; +} + + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +inline int CUtlArray::Count() const +{ + return (int)MAX_SIZE; +} + + +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +inline int CUtlArray::NumAllocated() const +{ + return (int)MAX_SIZE; +} + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +inline bool CUtlArray::IsValidIndex( int i ) const +{ + return (i >= 0) && (i < MAX_SIZE); +} + + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +inline int CUtlArray::InvalidIndex() +{ + return -1; +} + + +//----------------------------------------------------------------------------- +// Sorts the vector +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +void CUtlArray::Sort( int (__cdecl *pfnCompare)(const T *, const T *) ) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if ( Count() <= 1 ) + return; + + qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) ); +} + +template< typename T, size_t MAX_SIZE > +void CUtlArray::CopyArray( const T *pArray, size_t count ) +{ + Assert( count < MAX_SIZE ); + + for ( size_t n = 0; n < count; ++n ) + { + m_Memory[n] = pArray[n]; + } +} + +template< typename T, size_t MAX_SIZE > +void CUtlArray::Swap( CUtlArray< T, MAX_SIZE > &vec ) +{ + for ( size_t n = 0; n < MAX_SIZE; ++n ) + { + V_swap( m_Memory[n], vec.m_Memory[n] ); + } +} + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< typename T, size_t MAX_SIZE > +int CUtlArray::Find( const T& src ) const +{ + for ( int i = 0; i < Count(); ++i ) + { + if (Element(i) == src) + return i; + } + return -1; +} + +template< typename T, size_t MAX_SIZE > +void CUtlArray::FillWithValue( const T& src ) +{ + for ( int i = 0; i < Count(); i++ ) + { + Element(i) = src; + } +} + +template< typename T, size_t MAX_SIZE > +bool CUtlArray::HasElement( const T& src ) const +{ + return ( Find(src) >= 0 ); +} + +template< typename T, size_t MAX_SIZE > +inline void CUtlArray::DeleteElements() +{ + for( int i=0; i < MAX_SIZE; i++ ) + { + delete Element(i); + } +} + +#endif // UTLARRAY_H diff --git a/public/tier1/utlbidirectionalset.h b/public/tier1/utlbidirectionalset.h new file mode 100644 index 0000000..36aea62 --- /dev/null +++ b/public/tier1/utlbidirectionalset.h @@ -0,0 +1,394 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Bi-directional set. A Bucket knows about the elements that lie +// in it, and the elements know about the buckets they lie in. +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLBIDIRECTIONALSET_H +#define UTLBIDIRECTIONALSET_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "utllinkedlist.h" + +//----------------------------------------------------------------------------- +// Templatized helper class to deal with the kinds of things that spatial +// partition code always seems to have; buckets with lists of lots of elements +// and elements that live in lots of buckets. This makes it really quick to +// add and remove elements, and to iterate over all elements in a bucket. +// +// For this to work, you must initialize the set with two functions one that +// maps from bucket to the index of the first element in that bucket, and one +// that maps from element to the index of the first bucket that element lies in. +// The set will completely manage the index, it's just expected that those +// indices will be stored outside the set. +// +// S is the storage type of the index; it is the type that you may use to +// save indices into memory. I is the local iterator type, which you should +// use in any local scope (eg, inside a for() loop.) The reason for this is +// that you may wish to use unsigned shorts inside the structs you are +// saving with a CBidirectionalSet; but 16-bit arithmetic is catastrophically +// slow on a PowerPC -- during testing we saw CBidirectionalSet:: operations +// consume as much as 8% of the frame. +// +// For this reason, on the 360, the handles have been typedef'd to native +// register types (U32) which are accepted as parameters by the functions. +// The implicit assumption is that CBucketHandle and CElementHandle can +// be safely cast to ints! You can increase to U64 without performance +// penalty if necessary; the PowerPC is a 64-bit processor. +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I = S > +class CBidirectionalSet +{ +public: + // Install methods to get at the first bucket given a element + // and vice versa... + typedef S& (*FirstElementFunc_t)(CBucketHandle); + typedef S& (*FirstBucketFunc_t)(CElementHandle); + +#ifdef _X360 + typedef uint32 CBucketHandlePram; + typedef uint32 CElementHandlePram; +#else + typedef CBucketHandle CBucketHandlePram; + typedef CElementHandle CElementHandlePram; +#endif + + // Constructor + CBidirectionalSet(); + + // Call this before using the set + void Init( FirstElementFunc_t elemFunc, FirstBucketFunc_t bucketFunc ); + + // Add an element to a particular bucket + void AddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element ); + + // Prevalidate an add to a particular bucket + // NOTE: EXPENSIVE!!! + void ValidateAddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element ); + + // Test if an element is in a particular bucket. + // NOTE: EXPENSIVE!!! + bool IsElementInBucket( CBucketHandlePram bucket, CElementHandlePram element ); + + // Remove an element from a particular bucket + void RemoveElementFromBucket( CBucketHandlePram bucket, CElementHandlePram element ); + + // Remove an element from all buckets + void RemoveElement( CElementHandlePram element ); + void RemoveBucket( CBucketHandlePram element ); + + // Used to iterate elements in a bucket; I is the iterator + I FirstElement( CBucketHandlePram bucket ) const; + I NextElement( I idx ) const; + CElementHandle Element( I idx ) const; + + // Used to iterate buckets associated with an element; I is the iterator + I FirstBucket( CElementHandlePram bucket ) const; + I NextBucket( I idx ) const; + CBucketHandle Bucket( I idx ) const; + + static S InvalidIndex(); + + // Ensure capacity + void EnsureCapacity( int count ); + + // Deallocate.... + void Purge(); + + int NumAllocated( void ) const; + +private: + struct BucketListInfo_t + { + CElementHandle m_Element; + S m_BucketListIndex; // what's the m_BucketsUsedByElement index of the entry? + }; + + struct ElementListInfo_t + { + CBucketHandle m_Bucket; + S m_ElementListIndex; // what's the m_ElementsInBucket index of the entry? + }; + + // Maintains a list of all elements in a particular bucket + CUtlLinkedList< BucketListInfo_t, S, true, I > m_ElementsInBucket; + + // Maintains a list of all buckets a particular element lives in + CUtlLinkedList< ElementListInfo_t, S, true, I > m_BucketsUsedByElement; + + FirstBucketFunc_t m_FirstBucket; + FirstElementFunc_t m_FirstElement; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +CBidirectionalSet::CBidirectionalSet( ) +{ + m_FirstBucket = NULL; + m_FirstElement = NULL; +} + + +//----------------------------------------------------------------------------- +// Call this before using the set +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::Init( FirstElementFunc_t elemFunc, FirstBucketFunc_t bucketFunc ) +{ + m_FirstBucket = bucketFunc; + m_FirstElement = elemFunc; +} + + +//----------------------------------------------------------------------------- +// Adds an element to the bucket +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::ValidateAddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element ) +{ +#ifdef _DEBUG + // Make sure that this element doesn't already exist in the list of elements in the bucket + I elementInBucket = m_FirstElement( bucket ); + while( elementInBucket != m_ElementsInBucket.InvalidIndex() ) + { + // If you hit an Assert here, fix the calling code. It's too expensive to ensure + // that each item only shows up once here. Hopefully you can do something better + // outside of here. + Assert( m_ElementsInBucket[elementInBucket].m_Element != element ); + elementInBucket = m_ElementsInBucket.Next( elementInBucket ); + } + // Make sure that this bucket doesn't already exist in the element's list of buckets. + I bucketInElement = m_FirstBucket( element ); + while( bucketInElement != m_BucketsUsedByElement.InvalidIndex() ) + { + // If you hit an Assert here, fix the calling code. It's too expensive to ensure + // that each item only shows up once here. Hopefully you can do something better + // outside of here. + Assert( m_BucketsUsedByElement[bucketInElement].m_Bucket != bucket ); + bucketInElement = m_BucketsUsedByElement.Next( bucketInElement ); + } +#endif +} + + +//----------------------------------------------------------------------------- +// Adds an element to the bucket +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::AddElementToBucket( CBucketHandlePram bucket, CElementHandlePram element ) +{ + Assert( m_FirstBucket && m_FirstElement ); + + // Allocate new element + bucket entries + I idx = m_ElementsInBucket.Alloc(true); + I list = m_BucketsUsedByElement.Alloc( true ); + + // Store off the element data + m_ElementsInBucket[idx].m_Element = element; + m_ElementsInBucket[idx].m_BucketListIndex = list; + + // Here's the bucket data + m_BucketsUsedByElement[list].m_Bucket = bucket; + m_BucketsUsedByElement[list].m_ElementListIndex = idx; + + // Insert the element into the list of elements in the bucket + S& firstElementInBucket = m_FirstElement( bucket ); + if ( firstElementInBucket != m_ElementsInBucket.InvalidIndex() ) + m_ElementsInBucket.LinkBefore( firstElementInBucket, idx ); + firstElementInBucket = idx; + + // Insert the bucket into the element's list of buckets + S& firstBucketInElement = m_FirstBucket( element ); + if ( firstBucketInElement != m_BucketsUsedByElement.InvalidIndex() ) + m_BucketsUsedByElement.LinkBefore( firstBucketInElement, list ); + firstBucketInElement = list; +} + +//----------------------------------------------------------------------------- +// Test if an element is in a particular bucket. +// NOTE: EXPENSIVE!!! +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +bool CBidirectionalSet::IsElementInBucket( CBucketHandlePram bucket, CElementHandlePram element ) +{ + // Search through all elements in this bucket to see if element is in there. + I elementInBucket = m_FirstElement( bucket ); + while( elementInBucket != m_ElementsInBucket.InvalidIndex() ) + { + if( m_ElementsInBucket[elementInBucket].m_Element == element ) + { + return true; + } + elementInBucket = m_ElementsInBucket.Next( elementInBucket ); + } + return false; +} + + +//----------------------------------------------------------------------------- +// Remove an element from a particular bucket +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::RemoveElementFromBucket( CBucketHandlePram bucket, CElementHandlePram element ) +{ + // FIXME: Implement me! + Assert(0); +} + + +//----------------------------------------------------------------------------- +// Removes an element from all buckets +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::RemoveElement( CElementHandlePram element ) +{ + Assert( m_FirstBucket && m_FirstElement ); + + // Iterate over the list of all buckets the element is in + I i = m_FirstBucket( element ); + while (i != m_BucketsUsedByElement.InvalidIndex()) + { + CBucketHandlePram bucket = m_BucketsUsedByElement[i].m_Bucket; + I elementListIndex = m_BucketsUsedByElement[i].m_ElementListIndex; + + // Unhook the element from the bucket's list of elements + if (elementListIndex == m_FirstElement(bucket)) + m_FirstElement(bucket) = m_ElementsInBucket.Next(elementListIndex); + m_ElementsInBucket.Free(elementListIndex); + + I prevNode = i; + i = m_BucketsUsedByElement.Next(i); + m_BucketsUsedByElement.Free(prevNode); + } + + // Mark the list as empty + m_FirstBucket( element ) = m_BucketsUsedByElement.InvalidIndex(); +} + +//----------------------------------------------------------------------------- +// Removes a bucket from all elements +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::RemoveBucket( CBucketHandlePram bucket ) +{ + // Iterate over the list of all elements in the bucket + I i = m_FirstElement( bucket ); + while (i != m_ElementsInBucket.InvalidIndex()) + { + CElementHandlePram element = m_ElementsInBucket[i].m_Element; + I bucketListIndex = m_ElementsInBucket[i].m_BucketListIndex; + + // Unhook the bucket from the element's list of buckets + if (bucketListIndex == m_FirstBucket(element)) + m_FirstBucket(element) = m_BucketsUsedByElement.Next(bucketListIndex); + m_BucketsUsedByElement.Free(bucketListIndex); + + // Remove the list element + I prevNode = i; + i = m_ElementsInBucket.Next(i); + m_ElementsInBucket.Free(prevNode); + } + + // Mark the bucket list as empty + m_FirstElement( bucket ) = m_ElementsInBucket.InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Ensure capacity +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::EnsureCapacity( int count ) +{ + m_ElementsInBucket.EnsureCapacity( count ); + m_BucketsUsedByElement.EnsureCapacity( count ); +} + + +//----------------------------------------------------------------------------- +// Deallocate.... +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +void CBidirectionalSet::Purge() +{ + m_ElementsInBucket.Purge( ); + m_BucketsUsedByElement.Purge( ); +} + + +//----------------------------------------------------------------------------- +// Number of elements allocated in each linked list (should be the same) +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +int CBidirectionalSet::NumAllocated( void ) const +{ + Assert( m_ElementsInBucket.NumAllocated() == m_BucketsUsedByElement.NumAllocated() ); + return m_ElementsInBucket.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Invalid index for iteration.. +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +inline S CBidirectionalSet::InvalidIndex() +{ + return CUtlLinkedList< CElementHandle, I >::InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Used to iterate elements in a bucket; I is the iterator +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +inline I CBidirectionalSet::FirstElement( CBucketHandlePram bucket ) const +{ + Assert( m_FirstElement ); + return m_FirstElement(bucket); +} + +template< class CBucketHandle, class CElementHandle, class S, class I > +inline I CBidirectionalSet::NextElement( I idx ) const +{ + return m_ElementsInBucket.Next(idx); +} + +template< class CBucketHandle, class CElementHandle, class S, class I > +inline CElementHandle CBidirectionalSet::Element( I idx ) const +{ + return m_ElementsInBucket[idx].m_Element; +} + +//----------------------------------------------------------------------------- +// Used to iterate buckets an element lies in; I is the iterator +//----------------------------------------------------------------------------- +template< class CBucketHandle, class CElementHandle, class S, class I > +inline I CBidirectionalSet::FirstBucket( CElementHandlePram element ) const +{ + Assert( m_FirstBucket ); + return m_FirstBucket(element); +} + +template< class CBucketHandle, class CElementHandle, class S, class I > +inline I CBidirectionalSet::NextBucket( I idx ) const +{ + return m_BucketsUsedByElement.Next(idx); +} + +template< class CBucketHandle, class CElementHandle, class S, class I > +inline CBucketHandle CBidirectionalSet::Bucket( I idx ) const +{ + return m_BucketsUsedByElement[idx].m_Bucket; +} + +#endif // UTLBIDIRECTIONALSET_H diff --git a/public/tier1/utlbinaryblock.h b/public/tier1/utlbinaryblock.h new file mode 100644 index 0000000..93c6e68 --- /dev/null +++ b/public/tier1/utlbinaryblock.h @@ -0,0 +1,107 @@ +//====== Copyright 1996-2004, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef UTLBINARYBLOCK_H +#define UTLBINARYBLOCK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlmemory.h" +#include "tier1/strtools.h" +#include "limits.h" + +//----------------------------------------------------------------------------- +// Base class, containing simple memory management +//----------------------------------------------------------------------------- +class CUtlBinaryBlock +{ +public: + CUtlBinaryBlock( int growSize = 0, int initSize = 0 ); + + // NOTE: nInitialLength indicates how much of the buffer starts full + CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ); + CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ); + CUtlBinaryBlock( const CUtlBinaryBlock& src ); + + void Get( void *pValue, int nMaxLen ) const; + void Set( const void *pValue, int nLen ); + const void *Get( ) const; + void *Get( ); + + unsigned char& operator[]( int i ); + const unsigned char& operator[]( int i ) const; + + int Length() const; + void SetLength( int nLength ); // Undefined memory will result + bool IsEmpty() const; + void Clear(); + void Purge(); + + bool IsReadOnly() const; + + CUtlBinaryBlock &operator=( const CUtlBinaryBlock &src ); + + // Test for equality + bool operator==( const CUtlBinaryBlock &src ) const; + +private: + CUtlMemory m_Memory; + int m_nActualLength; +}; + + +//----------------------------------------------------------------------------- +// class inlines +//----------------------------------------------------------------------------- +inline const void *CUtlBinaryBlock::Get( ) const +{ + return m_Memory.Base(); +} + +inline void *CUtlBinaryBlock::Get( ) +{ + return m_Memory.Base(); +} + +inline int CUtlBinaryBlock::Length() const +{ + return m_nActualLength; +} + +inline unsigned char& CUtlBinaryBlock::operator[]( int i ) +{ + return m_Memory[i]; +} + +inline const unsigned char& CUtlBinaryBlock::operator[]( int i ) const +{ + return m_Memory[i]; +} + +inline bool CUtlBinaryBlock::IsReadOnly() const +{ + return m_Memory.IsReadOnly(); +} + +inline bool CUtlBinaryBlock::IsEmpty() const +{ + return Length() == 0; +} + +inline void CUtlBinaryBlock::Clear() +{ + SetLength( 0 ); +} + +inline void CUtlBinaryBlock::Purge() +{ + SetLength( 0 ); + m_Memory.Purge(); +} + +#endif // UTLBINARYBLOCK_H + diff --git a/public/tier1/utlblockmemory.h b/public/tier1/utlblockmemory.h new file mode 100644 index 0000000..63b1e87 --- /dev/null +++ b/public/tier1/utlblockmemory.h @@ -0,0 +1,352 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLBLOCKMEMORY_H +#define UTLBLOCKMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "mathlib/mathlib.h" + +#include + +#include "tier0/memalloc.h" +#include "tier0/memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +//----------------------------------------------------------------------------- + +#ifdef UTBLOCKLMEMORY_TRACK +#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0) +#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlBlockMemory class: +// A growable memory class that allocates non-sequential blocks, but is indexed sequentially +//----------------------------------------------------------------------------- +template< class T, class I > +class CUtlBlockMemory +{ +public: + // constructor, destructor + CUtlBlockMemory( int nGrowSize = 0, int nInitSize = 0 ); + ~CUtlBlockMemory(); + + // Set the size by which the memory grows - round up to the next power of 2 + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL + T* Base() { return NULL; } + const T* Base() const { return NULL; } + + class Iterator_t + { + public: + Iterator_t( I i ) : index( i ) {} + I index; + + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // element access + T& operator[]( I i ); + const T& operator[]( I i ) const; + T& Element( I i ); + const T& Element( I i ) const; + + // Can we use this index? + bool IsIdxValid( I i ) const; + static I InvalidIndex() { return ( I )-1; } + + void Swap( CUtlBlockMemory< T, I > &mem ); + + // Size + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + // Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements + void Purge( int numElements ); + +protected: + int Index( int major, int minor ) const { return ( major << m_nIndexShift ) | minor; } + int MajorIndex( int i ) const { return i >> m_nIndexShift; } + int MinorIndex( int i ) const { return i & m_nIndexMask; } + void ChangeSize( int nBlocks ); + int NumElementsInBlock() const { return m_nIndexMask + 1; } + + T** m_pMemory; + int m_nBlocks; + int m_nIndexMask : 27; + int m_nIndexShift : 5; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class I > +CUtlBlockMemory::CUtlBlockMemory( int nGrowSize, int nInitAllocationCount ) +: m_pMemory( 0 ), m_nBlocks( 0 ), m_nIndexMask( 0 ), m_nIndexShift( 0 ) +{ + Init( nGrowSize, nInitAllocationCount ); +} + +template< class T, class I > +CUtlBlockMemory::~CUtlBlockMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory::Swap( CUtlBlockMemory< T, I > &mem ) +{ + std::swap( m_pMemory, mem.m_pMemory ); + std::swap( m_nBlocks, mem.m_nBlocks ); + std::swap( m_nIndexMask, mem.m_nIndexMask ); + std::swap( m_nIndexShift, mem.m_nIndexShift ); +} + + +//----------------------------------------------------------------------------- +// Set the size by which the memory grows - round up to the next power of 2 +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ ) +{ + Purge(); + + if ( nGrowSize == 0) + { + // default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size + nGrowSize = ( 127 + sizeof( T ) ) / sizeof( T ); + } + nGrowSize = SmallestPowerOfTwoGreaterOrEqual( nGrowSize ); + m_nIndexMask = nGrowSize - 1; + + m_nIndexShift = 0; + while ( nGrowSize > 1 ) + { + nGrowSize >>= 1; + ++m_nIndexShift; + } + Assert( m_nIndexMask + 1 == ( 1 << m_nIndexShift ) ); + + Grow( nInitSize ); +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T, class I > +inline T& CUtlBlockMemory::operator[]( I i ) +{ + Assert( IsIdxValid(i) ); + T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory::operator[]( I i ) const +{ + Assert( IsIdxValid(i) ); + const T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline T& CUtlBlockMemory::Element( I i ) +{ + Assert( IsIdxValid(i) ); + T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory::Element( I i ) const +{ + Assert( IsIdxValid(i) ); + const T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T, class I > +inline int CUtlBlockMemory::NumAllocated() const +{ + return m_nBlocks * NumElementsInBlock(); +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T, class I > +inline bool CUtlBlockMemory::IsIdxValid( I i ) const +{ + return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks ); +} + +template< class T, class I > +void CUtlBlockMemory::Grow( int num ) +{ + if ( num <= 0 ) + return; + + int nBlockSize = NumElementsInBlock(); + int nBlocks = ( num + nBlockSize - 1 ) / nBlockSize; + + ChangeSize( m_nBlocks + nBlocks ); +} + +template< class T, class I > +void CUtlBlockMemory::ChangeSize( int nBlocks ) +{ + UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value + + int nBlocksOld = m_nBlocks; + m_nBlocks = nBlocks; + + UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value + + if ( m_pMemory ) + { + // free old blocks if shrinking + // Only possible if m_pMemory is non-NULL (and avoids PVS-Studio warning) + for ( int i = m_nBlocks; i < nBlocksOld; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)realloc( m_pMemory, m_nBlocks * sizeof(T*) ); + Assert( m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)malloc( m_nBlocks * sizeof(T*) ); + Assert( m_pMemory ); + } + + if ( !m_pMemory ) + { + Error( "CUtlBlockMemory overflow!\n" ); + } + + // allocate new blocks if growing + int nBlockSize = NumElementsInBlock(); + for ( int i = nBlocksOld; i < m_nBlocks; ++i ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory[ i ] = (T*)malloc( nBlockSize * sizeof( T ) ); + Assert( m_pMemory[ i ] ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, class I > +inline void CUtlBlockMemory::EnsureCapacity( int num ) +{ + Grow( num - NumAllocated() ); +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory::Purge() +{ + if ( !m_pMemory ) + return; + + for ( int i = 0; i < m_nBlocks; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + m_nBlocks = 0; + + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory ); + m_pMemory = 0; +} + +template< class T, class I > +void CUtlBlockMemory::Purge( int numElements ) +{ + Assert( numElements >= 0 ); + + int nAllocated = NumAllocated(); + if ( numElements > nAllocated ) + { + // Ensure this isn't a grow request in disguise. + Assert( numElements <= nAllocated ); + return; + } + + if ( numElements <= 0 ) + { + Purge(); + return; + } + + int nBlockSize = NumElementsInBlock(); + int nBlocksOld = m_nBlocks; + int nBlocks = ( numElements + nBlockSize - 1 ) / nBlockSize; + + // If the number of blocks is the same as the allocated number of blocks, we are done. + if ( nBlocks == m_nBlocks ) + return; + + ChangeSize( nBlocks ); +} + +#include "tier0/memdbgoff.h" + +#endif // UTLBLOCKMEMORY_H diff --git a/public/tier1/utlbuffer.h b/public/tier1/utlbuffer.h new file mode 100644 index 0000000..0de85fd --- /dev/null +++ b/public/tier1/utlbuffer.h @@ -0,0 +1,1094 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//=============================================================================// + +#ifndef UTLBUFFER_H +#define UTLBUFFER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlmemory.h" +#include "tier1/byteswap.h" +#include + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct characterset_t; + + +//----------------------------------------------------------------------------- +// Description of character conversions for string output +// Here's an example of how to use the macros to define a character conversion +// BEGIN_CHAR_CONVERSION( CStringConversion, '\\' ) +// { '\n', "n" }, +// { '\t', "t" } +// END_CHAR_CONVERSION( CStringConversion, '\\' ) +//----------------------------------------------------------------------------- +class CUtlCharConversion +{ +public: + struct ConversionArray_t + { + char m_nActualChar; + const char *m_pReplacementString; + }; + + CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ); + char GetEscapeChar() const; + const char *GetDelimiter() const; + int GetDelimiterLength() const; + + const char *GetConversionString( char c ) const; + int GetConversionLength( char c ) const; + int MaxConversionLength() const; + + // Finds a conversion for the passed-in string, returns length + virtual char FindConversion( const char *pString, int *pLength ); + +protected: + struct ConversionInfo_t + { + int m_nLength; + const char *m_pReplacementString; + }; + + char m_nEscapeChar; + const char *m_pDelimiter; + int m_nDelimiterLength; + int m_nCount; + int m_nMaxConversionLength; + char m_pList[256]; + ConversionInfo_t m_pReplacements[256]; +}; + +#define BEGIN_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \ + static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = { + +#define END_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \ + }; \ + CUtlCharConversion _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name ); + +#define BEGIN_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \ + static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = { + +#define END_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \ + }; \ + _className _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name ); + +//----------------------------------------------------------------------------- +// Character conversions for C strings +//----------------------------------------------------------------------------- +CUtlCharConversion *GetCStringCharConversion(); + +//----------------------------------------------------------------------------- +// Character conversions for quoted strings, with no escape sequences +//----------------------------------------------------------------------------- +CUtlCharConversion *GetNoEscCharConversion(); + + +//----------------------------------------------------------------------------- +// Macro to set overflow functions easily +//----------------------------------------------------------------------------- +#define SetUtlBufferOverflowFuncs( _get, _put ) \ + SetOverflowFuncs( static_cast ( _get ), static_cast ( _put ) ) + + +//----------------------------------------------------------------------------- +// Command parsing.. +//----------------------------------------------------------------------------- +class CUtlBuffer +{ +public: + enum SeekType_t + { + SEEK_HEAD = 0, + SEEK_CURRENT, + SEEK_TAIL + }; + + // flags + enum BufferFlags_t + { + TEXT_BUFFER = 0x1, // Describes how get + put work (as strings, or binary) + EXTERNAL_GROWABLE = 0x2, // This is used w/ external buffers and causes the utlbuf to switch to reallocatable memory if an overflow happens when Putting. + CONTAINS_CRLF = 0x4, // For text buffers only, does this contain \n or \n\r? + READ_ONLY = 0x8, // For external buffers; prevents null termination from happening. + AUTO_TABS_DISABLED = 0x10, // Used to disable/enable push/pop tabs + }; + + // Overflow functions when a get or put overflows + typedef bool (CUtlBuffer::*UtlBufferOverflowFunc_t)( int nSize ); + + // Constructors for growable + external buffers for serialization/unserialization + CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 ); + CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 ); + // This one isn't actually defined so that we catch contructors that are trying to pass a bool in as the third param. + CUtlBuffer( const void *pBuffer, int size, bool crap ); + + unsigned char GetFlags() const; + + // NOTE: This will assert if you attempt to recast it in a way that + // is not compatible. The only valid conversion is binary-> text w/CRLF + void SetBufferType( bool bIsText, bool bContainsCRLF ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Attaches the buffer to external memory.... + void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 ); + bool IsExternallyAllocated() const; + // Takes ownership of the passed memory, including freeing it when this buffer is destroyed. + void AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags = 0 ); + + // copies data from another buffer + void CopyBuffer( const CUtlBuffer &buffer ); + void CopyBuffer( const void *pubData, int cubData ); + + void Swap( CUtlBuffer &buf ); + void Swap( CUtlMemory &mem ); + + FORCEINLINE void ActivateByteSwappingIfBigEndian( void ) + { + if ( IsX360() ) + ActivateByteSwapping( true ); + } + + + // Controls endian-ness of binary utlbufs - default matches the current platform + void ActivateByteSwapping( bool bActivate ); + void SetBigEndian( bool bigEndian ); + bool IsBigEndian( void ); + + // Resets the buffer; but doesn't free memory + void Clear(); + + // Clears out the buffer; frees memory + void Purge(); + + // Read stuff out. + // Binary mode: it'll just read the bits directly in, and characters will be + // read for strings until a null character is reached. + // Text mode: it'll parse the file, turning text #s into real numbers. + // GetString will read a string until a space is reached + char GetChar( ); + unsigned char GetUnsignedChar( ); + short GetShort( ); + unsigned short GetUnsignedShort( ); + int GetInt( ); + int64 GetInt64( ); + int GetIntHex( ); + unsigned int GetUnsignedInt( ); + float GetFloat( ); + double GetDouble( ); + template void GetString( char( &pString )[maxLenInChars] ) + { + GetStringInternal( pString, maxLenInChars ); + } + + void GetStringManualCharCount( char *pString, size_t maxLenInChars ) + { + GetStringInternal( pString, maxLenInChars ); + } + + void Get( void* pMem, int size ); + void GetLine( char* pLine, int nMaxChars = 0 ); + + // Used for getting objects that have a byteswap datadesc defined + template void GetObjects( T *dest, int count = 1 ); + + // This will get at least 1 byte and up to nSize bytes. + // It will return the number of bytes actually read. + int GetUpTo( void *pMem, int nSize ); + + // This version of GetString converts \" to \\ and " to \, etc. + // It also reads a " at the beginning and end of the string + void GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars = 0 ); + char GetDelimitedChar( CUtlCharConversion *pConv ); + + // This will return the # of characters of the string about to be read out + // NOTE: The count will *include* the terminating 0!! + // In binary mode, it's the number of characters until the next 0 + // In text mode, it's the number of characters until the next space. + int PeekStringLength(); + + // This version of PeekStringLength converts \" to \\ and " to \, etc. + // It also reads a " at the beginning and end of the string + // NOTE: The count will *include* the terminating 0!! + // In binary mode, it's the number of characters until the next 0 + // In text mode, it's the number of characters between "s (checking for \") + // Specifying false for bActualSize will return the pre-translated number of characters + // including the delimiters and the escape characters. So, \n counts as 2 characters when bActualSize == false + // and only 1 character when bActualSize == true + int PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize = true ); + + // Just like scanf, but doesn't work in binary mode + int Scanf( SCANF_FORMAT_STRING const char* pFmt, ... ); + int VaScanf( const char* pFmt, va_list list ); + + // Eats white space, advances Get index + void EatWhiteSpace(); + + // Eats C++ style comments + bool EatCPPComment(); + + // (For text buffers only) + // Parse a token from the buffer: + // Grab all text that lies between a starting delimiter + ending delimiter + // (skipping whitespace that leads + trails both delimiters). + // If successful, the get index is advanced and the function returns true, + // otherwise the index is not advanced and the function returns false. + bool ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen ); + + // Advance the get index until after the particular string is found + // Do not eat whitespace before starting. Return false if it failed + // String test is case-insensitive. + bool GetToken( const char *pToken ); + + // Parses the next token, given a set of character breaks to stop at + // Returns the length of the token parsed in bytes (-1 if none parsed) + int ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments = true ); + + // Write stuff in + // Binary mode: it'll just write the bits directly in, and strings will be + // written with a null terminating character + // Text mode: it'll convert the numbers to text versions + // PutString will not write a terminating character + void PutChar( char c ); + void PutUnsignedChar( unsigned char uc ); + void PutUint64( uint64 ub ); + void PutInt16( int16 s16 ); + void PutShort( short s ); + void PutUnsignedShort( unsigned short us ); + void PutInt( int i ); + void PutInt64( int64 i ); + void PutUnsignedInt( unsigned int u ); + void PutFloat( float f ); + void PutDouble( double d ); + void PutString( const char* pString ); + void Put( const void* pMem, int size ); + + // Used for putting objects that have a byteswap datadesc defined + template void PutObjects( T *src, int count = 1 ); + + // This version of PutString converts \ to \\ and " to \", etc. + // It also places " at the beginning and end of the string + void PutDelimitedString( CUtlCharConversion *pConv, const char *pString ); + void PutDelimitedChar( CUtlCharConversion *pConv, char c ); + + // Just like printf, writes a terminating zero in binary mode + void Printf( PRINTF_FORMAT_STRING const char* pFmt, ... ) FMTFUNCTION( 2, 3 ); + void VaPrintf( const char* pFmt, va_list list ); + + // What am I writing (put)/reading (get)? + void* PeekPut( int offset = 0 ); + const void* PeekGet( int offset = 0 ) const; + const void* PeekGet( int nMaxSize, int nOffset ); + + // Where am I writing (put)/reading (get)? + int TellPut( ) const; + int TellGet( ) const; + + // What's the most I've ever written? + int TellMaxPut( ) const; + + // How many bytes remain to be read? + // NOTE: This is not accurate for streaming text files; it overshoots + int GetBytesRemaining() const; + + // Change where I'm writing (put)/reading (get) + void SeekPut( SeekType_t type, int offset ); + void SeekGet( SeekType_t type, int offset ); + + // Buffer base + const void* Base() const; + void* Base(); + // Returns the base as a const char*, only valid in text mode. + const char *String() const; + + // memory allocation size, does *not* reflect size written or read, + // use TellPut or TellGet for that + int Size() const; + + // Am I a text buffer? + bool IsText() const; + + // Can I grow if I'm externally allocated? + bool IsGrowable() const; + + // Am I valid? (overflow or underflow error), Once invalid it stays invalid + bool IsValid() const; + + // Do I contain carriage return/linefeeds? + bool ContainsCRLF() const; + + // Am I read-only + bool IsReadOnly() const; + + // Converts a buffer from a CRLF buffer to a CR buffer (and back) + // Returns false if no conversion was necessary (and outBuf is left untouched) + // If the conversion occurs, outBuf will be cleared. + bool ConvertCRLF( CUtlBuffer &outBuf ); + + // Push/pop pretty-printing tabs + void PushTab(); + void PopTab(); + + // Temporarily disables pretty print + void EnableTabs( bool bEnable ); + +protected: + // error flags + enum + { + PUT_OVERFLOW = 0x1, + GET_OVERFLOW = 0x2, + MAX_ERROR_FLAG = GET_OVERFLOW, + }; + + void SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc ); + + bool OnPutOverflow( int nSize ); + bool OnGetOverflow( int nSize ); + +protected: + // Checks if a get/put is ok + bool CheckPut( int size ); + bool CheckGet( int size ); + + void AddNullTermination( ); + + // Methods to help with pretty-printing + bool WasLastCharacterCR(); + void PutTabs(); + + // Help with delimited stuff + char GetDelimitedCharInternal( CUtlCharConversion *pConv ); + void PutDelimitedCharInternal( CUtlCharConversion *pConv, char c ); + + // Default overflow funcs + bool PutOverflow( int nSize ); + bool GetOverflow( int nSize ); + + // Does the next bytes of the buffer match a pattern? + bool PeekStringMatch( int nOffset, const char *pString, int nLen ); + + // Peek size of line to come, check memory bound + int PeekLineLength(); + + // How much whitespace should I skip? + int PeekWhiteSpace( int nOffset ); + + // Checks if a peek get is ok + bool CheckPeekGet( int nOffset, int nSize ); + + // Call this to peek arbitrarily long into memory. It doesn't fail unless + // it can't read *anything* new + bool CheckArbitraryPeekGet( int nOffset, int &nIncrement ); + void GetStringInternal( char *pString, size_t maxLenInChars ); + + template void GetType( T& dest, const char *pszFmt ); + template void GetTypeBin( T& dest ); + template void GetObject( T *src ); + + template void PutType( T src, const char *pszFmt ); + template void PutTypeBin( T src ); + template void PutObject( T *src ); + + CUtlMemory m_Memory; + int m_Get; + int m_Put; + + unsigned char m_Error; + unsigned char m_Flags; + unsigned char m_Reserved; +#if defined( _X360 ) + unsigned char pad; +#endif + + int m_nTab; + int m_nMaxPut; + int m_nOffset; + + UtlBufferOverflowFunc_t m_GetOverflowFunc; + UtlBufferOverflowFunc_t m_PutOverflowFunc; + + CByteswap m_Byteswap; +}; + + +// Stream style output operators for CUtlBuffer +inline CUtlBuffer &operator<<( CUtlBuffer &b, char v ) +{ + b.PutChar( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned char v ) +{ + b.PutUnsignedChar( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, short v ) +{ + b.PutShort( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned short v ) +{ + b.PutUnsignedShort( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, int v ) +{ + b.PutInt( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned int v ) +{ + b.PutUnsignedInt( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, float v ) +{ + b.PutFloat( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, double v ) +{ + b.PutDouble( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, const char *pv ) +{ + b.PutString( pv ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector &v ) +{ + b << v.x << " " << v.y << " " << v.z; + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector2D &v ) +{ + b << v.x << " " << v.y; + return b; +} + + +class CUtlInplaceBuffer : public CUtlBuffer +{ +public: + CUtlInplaceBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 ); + + // + // Routines returning buffer-inplace-pointers + // +public: + // + // Upon success, determines the line length, fills out the pointer to the + // beginning of the line and the line length, advances the "get" pointer + // offset by the line length and returns "true". + // + // If end of file is reached or upon error returns "false". + // + // Note: the returned length of the line is at least one character because the + // trailing newline characters are also included as part of the line. + // + // Note: the pointer returned points into the local memory of this buffer, in + // case the buffer gets relocated or destroyed the pointer becomes invalid. + // + // e.g.: ------------- + // + // char *pszLine; + // int nLineLen; + // while ( pUtlInplaceBuffer->InplaceGetLinePtr( &pszLine, &nLineLen ) ) + // { + // ... + // } + // + // ------------- + // + // @param ppszInBufferPtr on return points into this buffer at start of line + // @param pnLineLength on return holds num bytes accessible via (*ppszInBufferPtr) + // + // @returns true if line was successfully read + // false when EOF is reached or error occurs + // + bool InplaceGetLinePtr( /* out */ char **ppszInBufferPtr, /* out */ int *pnLineLength ); + + // + // Determines the line length, advances the "get" pointer offset by the line length, + // replaces the newline character with null-terminator and returns the initial pointer + // to now null-terminated line. + // + // If end of file is reached or upon error returns NULL. + // + // Note: the pointer returned points into the local memory of this buffer, in + // case the buffer gets relocated or destroyed the pointer becomes invalid. + // + // e.g.: ------------- + // + // while ( char *pszLine = pUtlInplaceBuffer->InplaceGetLinePtr() ) + // { + // ... + // } + // + // ------------- + // + // @returns ptr-to-zero-terminated-line if line was successfully read and buffer modified + // NULL when EOF is reached or error occurs + // + char * InplaceGetLinePtr( void ); +}; + + +//----------------------------------------------------------------------------- +// Where am I reading? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellGet( ) const +{ + return m_Get; +} + + +//----------------------------------------------------------------------------- +// How many bytes remain to be read? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::GetBytesRemaining() const +{ + return m_nMaxPut - TellGet(); +} + + +//----------------------------------------------------------------------------- +// What am I reading? +//----------------------------------------------------------------------------- +inline const void* CUtlBuffer::PeekGet( int offset ) const +{ + return &m_Memory[ m_Get + offset - m_nOffset ]; +} + + +//----------------------------------------------------------------------------- +// Unserialization +//----------------------------------------------------------------------------- + +template +inline void CUtlBuffer::GetObject( T *dest ) +{ + if ( CheckGet( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + *dest = *(T *)PeekGet(); + } + else + { + m_Byteswap.SwapFieldsToTargetEndian( dest, (T*)PeekGet() ); + } + m_Get += sizeof(T); + } + else + { + Q_memset( dest, 0, sizeof(T) ); + } +} + + +template +inline void CUtlBuffer::GetObjects( T *dest, int count ) +{ + for ( int i = 0; i < count; ++i, ++dest ) + { + GetObject( dest ); + } +} + + +template +inline void CUtlBuffer::GetTypeBin( T &dest ) +{ + if ( CheckGet( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + dest = *(T *)PeekGet(); + } + else + { + m_Byteswap.SwapBufferToTargetEndian( &dest, (T*)PeekGet() ); + } + m_Get += sizeof(T); + } + else + { + dest = 0; + } +} + +template <> +inline void CUtlBuffer::GetTypeBin< float >( float &dest ) +{ + if ( CheckGet( sizeof( float ) ) ) + { + uintptr_t pData = (uintptr_t)PeekGet(); + if ( IsX360() && ( pData & 0x03 ) ) + { + // handle unaligned read + ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; + ((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1]; + ((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2]; + ((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3]; + } + else + { + // aligned read + dest = *(float *)pData; + } + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian< float >( &dest, &dest ); + } + m_Get += sizeof( float ); + } + else + { + dest = 0; + } +} + +template +inline void CUtlBuffer::GetType( T &dest, const char *pszFmt ) +{ + if (!IsText()) + { + GetTypeBin( dest ); + } + else + { + dest = 0; + Scanf( pszFmt, &dest ); + } +} + +inline char CUtlBuffer::GetChar( ) +{ + char c; + GetType( c, "%c" ); + return c; +} + +inline unsigned char CUtlBuffer::GetUnsignedChar( ) +{ + unsigned char c; + GetType( c, "%u" ); + return c; +} + +inline short CUtlBuffer::GetShort( ) +{ + short s; + GetType( s, "%d" ); + return s; +} + +inline unsigned short CUtlBuffer::GetUnsignedShort( ) +{ + unsigned short s; + GetType( s, "%u" ); + return s; +} + +inline int CUtlBuffer::GetInt( ) +{ + int i; + GetType( i, "%d" ); + return i; +} + +inline int64 CUtlBuffer::GetInt64( ) +{ + int64 i; + GetType( i, "%lld" ); + return i; +} + +inline int CUtlBuffer::GetIntHex( ) +{ + int i; + GetType( i, "%x" ); + return i; +} + +inline unsigned int CUtlBuffer::GetUnsignedInt( ) +{ + unsigned int u; + GetType( u, "%u" ); + return u; +} + +inline float CUtlBuffer::GetFloat( ) +{ + float f; + GetType( f, "%f" ); + return f; +} + +inline double CUtlBuffer::GetDouble( ) +{ + double d; + GetType( d, "%f" ); + return d; +} + + +//----------------------------------------------------------------------------- +// Where am I writing? +//----------------------------------------------------------------------------- +inline unsigned char CUtlBuffer::GetFlags() const +{ + return m_Flags; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsExternallyAllocated() const +{ + return m_Memory.IsExternallyAllocated(); +} + + +//----------------------------------------------------------------------------- +// Where am I writing? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellPut( ) const +{ + return m_Put; +} + + +//----------------------------------------------------------------------------- +// What's the most I've ever written? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellMaxPut( ) const +{ + return m_nMaxPut; +} + + +//----------------------------------------------------------------------------- +// What am I reading? +//----------------------------------------------------------------------------- +inline void* CUtlBuffer::PeekPut( int offset ) +{ + return &m_Memory[m_Put + offset - m_nOffset]; +} + + +//----------------------------------------------------------------------------- +// Various put methods +//----------------------------------------------------------------------------- + +template +inline void CUtlBuffer::PutObject( T *src ) +{ + if ( CheckPut( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + *(T *)PeekPut() = *src; + } + else + { + m_Byteswap.SwapFieldsToTargetEndian( (T*)PeekPut(), src ); + } + m_Put += sizeof(T); + AddNullTermination(); + } +} + + +template +inline void CUtlBuffer::PutObjects( T *src, int count ) +{ + for ( int i = 0; i < count; ++i, ++src ) + { + PutObject( src ); + } +} + + +template +inline void CUtlBuffer::PutTypeBin( T src ) +{ + if ( CheckPut( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + *(T *)PeekPut() = src; + } + else + { + m_Byteswap.SwapBufferToTargetEndian( (T*)PeekPut(), &src ); + } + m_Put += sizeof(T); + AddNullTermination(); + } +} + +template +inline void CUtlBuffer::PutType( T src, const char *pszFmt ) +{ + if (!IsText()) + { + PutTypeBin( src ); + } + else + { + Printf( pszFmt, src ); + } +} + +//----------------------------------------------------------------------------- +// Methods to help with pretty-printing +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::WasLastCharacterCR() +{ + if ( !IsText() || (TellPut() == 0) ) + return false; + return ( *( const char * )PeekPut( -1 ) == '\n' ); +} + +inline void CUtlBuffer::PutTabs() +{ + int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab; + for (int i = nTabCount; --i >= 0; ) + { + PutTypeBin( '\t' ); + } +} + + +//----------------------------------------------------------------------------- +// Push/pop pretty-printing tabs +//----------------------------------------------------------------------------- +inline void CUtlBuffer::PushTab( ) +{ + ++m_nTab; +} + +inline void CUtlBuffer::PopTab() +{ + if ( --m_nTab < 0 ) + { + m_nTab = 0; + } +} + + +//----------------------------------------------------------------------------- +// Temporarily disables pretty print +//----------------------------------------------------------------------------- +inline void CUtlBuffer::EnableTabs( bool bEnable ) +{ + if ( bEnable ) + { + m_Flags &= ~AUTO_TABS_DISABLED; + } + else + { + m_Flags |= AUTO_TABS_DISABLED; + } +} + +inline void CUtlBuffer::PutChar( char c ) +{ + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + + PutTypeBin( c ); +} + +inline void CUtlBuffer::PutUnsignedChar( unsigned char c ) +{ + PutType( c, "%u" ); +} + +inline void CUtlBuffer::PutUint64( uint64 ub ) +{ + PutType( ub, "%llu" ); +} + +inline void CUtlBuffer::PutInt16( int16 s16 ) +{ + PutType( s16, "%d" ); +} + +inline void CUtlBuffer::PutShort( short s ) +{ + PutType( s, "%d" ); +} + +inline void CUtlBuffer::PutUnsignedShort( unsigned short s ) +{ + PutType( s, "%u" ); +} + +inline void CUtlBuffer::PutInt( int i ) +{ + PutType( i, "%d" ); +} + +inline void CUtlBuffer::PutInt64( int64 i ) +{ + PutType( i, "%llu" ); +} + +inline void CUtlBuffer::PutUnsignedInt( unsigned int u ) +{ + PutType( u, "%u" ); +} + +inline void CUtlBuffer::PutFloat( float f ) +{ + PutType( f, "%f" ); +} + +inline void CUtlBuffer::PutDouble( double d ) +{ + PutType( d, "%f" ); +} + + +//----------------------------------------------------------------------------- +// Am I a text buffer? +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsText() const +{ + return (m_Flags & TEXT_BUFFER) != 0; +} + + +//----------------------------------------------------------------------------- +// Can I grow if I'm externally allocated? +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsGrowable() const +{ + return (m_Flags & EXTERNAL_GROWABLE) != 0; +} + + +//----------------------------------------------------------------------------- +// Am I valid? (overflow or underflow error), Once invalid it stays invalid +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsValid() const +{ + return m_Error == 0; +} + + +//----------------------------------------------------------------------------- +// Do I contain carriage return/linefeeds? +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::ContainsCRLF() const +{ + return IsText() && ((m_Flags & CONTAINS_CRLF) != 0); +} + + +//----------------------------------------------------------------------------- +// Am I read-only +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsReadOnly() const +{ + return (m_Flags & READ_ONLY) != 0; +} + + +//----------------------------------------------------------------------------- +// Buffer base and size +//----------------------------------------------------------------------------- +inline const void* CUtlBuffer::Base() const +{ + return m_Memory.Base(); +} + +inline void* CUtlBuffer::Base() +{ + return m_Memory.Base(); +} + +// Returns the base as a const char*, only valid in text mode. +inline const char *CUtlBuffer::String() const +{ + Assert( IsText() ); + return reinterpret_cast( m_Memory.Base() ); +} + +inline int CUtlBuffer::Size() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Clears out the buffer; frees memory +//----------------------------------------------------------------------------- +inline void CUtlBuffer::Clear() +{ + m_Get = 0; + m_Put = 0; + m_Error = 0; + m_nOffset = 0; + m_nMaxPut = -1; + AddNullTermination(); +} + +inline void CUtlBuffer::Purge() +{ + m_Get = 0; + m_Put = 0; + m_nOffset = 0; + m_nMaxPut = 0; + m_Error = 0; + m_Memory.Purge(); +} + +inline void CUtlBuffer::CopyBuffer( const CUtlBuffer &buffer ) +{ + CopyBuffer( buffer.Base(), buffer.TellPut() ); +} + +inline void CUtlBuffer::CopyBuffer( const void *pubData, int cubData ) +{ + Clear(); + if ( cubData ) + { + Put( pubData, cubData ); + } +} + +#endif // UTLBUFFER_H + diff --git a/public/tier1/utlbufferutil.h b/public/tier1/utlbufferutil.h new file mode 100644 index 0000000..a52a528 --- /dev/null +++ b/public/tier1/utlbufferutil.h @@ -0,0 +1,192 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Utilities for serialization/unserialization buffer +//=============================================================================// + +#ifndef UTLBUFFERUTIL_H +#define UTLBUFFERUTIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include "tier1/utlbuffer.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class Vector2D; +class Vector; +class Vector4D; +class QAngle; +class Quaternion; +class VMatrix; +class Color; +class CUtlBinaryBlock; +class CUtlString; +class CUtlCharConversion; + + +//----------------------------------------------------------------------------- +// For string serialization, set the delimiter rules +//----------------------------------------------------------------------------- +void SetSerializationDelimiter( CUtlCharConversion *pConv ); +void SetSerializationArrayDelimiter( const char *pDelimiter ); + + +//----------------------------------------------------------------------------- +// Standard serialization methods for basic types +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const bool &src ); +bool Unserialize( CUtlBuffer &buf, bool &dest ); + +bool Serialize( CUtlBuffer &buf, const int &src ); +bool Unserialize( CUtlBuffer &buf, int &dest ); + +bool Serialize( CUtlBuffer &buf, const float &src ); +bool Unserialize( CUtlBuffer &buf, float &dest ); + +bool Serialize( CUtlBuffer &buf, const Vector2D &src ); +bool Unserialize( CUtlBuffer &buf, Vector2D &dest ); + +bool Serialize( CUtlBuffer &buf, const Vector &src ); +bool Unserialize( CUtlBuffer &buf, Vector &dest ); + +bool Serialize( CUtlBuffer &buf, const Vector4D &src ); +bool Unserialize( CUtlBuffer &buf, Vector4D &dest ); + +bool Serialize( CUtlBuffer &buf, const QAngle &src ); +bool Unserialize( CUtlBuffer &buf, QAngle &dest ); + +bool Serialize( CUtlBuffer &buf, const Quaternion &src ); +bool Unserialize( CUtlBuffer &buf, Quaternion &dest ); + +bool Serialize( CUtlBuffer &buf, const VMatrix &src ); +bool Unserialize( CUtlBuffer &buf, VMatrix &dest ); + +bool Serialize( CUtlBuffer &buf, const Color &src ); +bool Unserialize( CUtlBuffer &buf, Color &dest ); + +bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src ); +bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest ); + +bool Serialize( CUtlBuffer &buf, const CUtlString &src ); +bool Unserialize( CUtlBuffer &buf, CUtlString &dest ); + + +//----------------------------------------------------------------------------- +// You can use this to check if a type serializes on multiple lines +//----------------------------------------------------------------------------- +template< class T > +inline bool SerializesOnMultipleLines() +{ + return false; +} + +template< > +inline bool SerializesOnMultipleLines() +{ + return true; +} + +template< > +inline bool SerializesOnMultipleLines() +{ + return true; +} + + +//----------------------------------------------------------------------------- +// Vector serialization +//----------------------------------------------------------------------------- +template< class T > +bool Serialize( CUtlBuffer &buf, const CUtlVector &src ) +{ + extern const char *s_pUtlBufferUtilArrayDelim; + + int nCount = src.Count(); + + if ( !buf.IsText() ) + { + buf.PutInt( nCount ); + for ( int i = 0; i < nCount; ++i ) + { + ::Serialize( buf, src[i] ); + } + return buf.IsValid(); + } + + if ( !SerializesOnMultipleLines() ) + { + buf.PutChar('\n'); + for ( int i = 0; i < nCount; ++i ) + { + ::Serialize( buf, src[i] ); + if ( s_pUtlBufferUtilArrayDelim && (i != nCount-1) ) + { + buf.PutString( s_pUtlBufferUtilArrayDelim ); + } + buf.PutChar('\n'); + } + } + else + { + for ( int i = 0; i < nCount; ++i ) + { + ::Serialize( buf, src[i] ); + if ( s_pUtlBufferUtilArrayDelim && (i != nCount-1) ) + { + buf.PutString( s_pUtlBufferUtilArrayDelim ); + } + buf.PutChar(' '); + } + } + + return buf.IsValid(); +} + +template< class T > +bool Unserialize( CUtlBuffer &buf, CUtlVector &dest ) +{ + dest.RemoveAll(); + + MEM_ALLOC_CREDIT_FUNCTION(); + + if ( !buf.IsText() ) + { + int nCount = buf.GetInt(); + if ( nCount ) + { + dest.EnsureCapacity( nCount ); + for ( int i = 0; i < nCount; ++i ) + { + VerifyEquals( dest.AddToTail(), i ); + if ( !::Unserialize( buf, dest[i] ) ) + return false; + } + } + return buf.IsValid(); + } + + while ( true ) + { + buf.EatWhiteSpace(); + if ( !buf.IsValid() ) + break; + + int i = dest.AddToTail( ); + if ( ! ::Unserialize( buf, dest[i] ) ) + return false; + } + return true; +} + + +#endif // UTLBUFFERUTIL_H + diff --git a/public/tier1/utlcommon.h b/public/tier1/utlcommon.h new file mode 100644 index 0000000..d44dc2d --- /dev/null +++ b/public/tier1/utlcommon.h @@ -0,0 +1,345 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: common helpers for reuse among various Utl containers +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef UTLCOMMON_H +#define UTLCOMMON_H +#pragma once + +//----------------------------------------------------------------------------- +// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit. +//----------------------------------------------------------------------------- + +// empty_t is the canonical "no-value" type which is fully defined but empty. +struct empty_t {}; + +// undefined_t is the canonical "undefined" type, used mostly for typedefs; +// parameters of type undefined_t will not compile, which is actually useful +// behavior when it comes to template programming. Google "SFINAE" for info. +struct undefined_t; + +// CTypeSelect::type is a typedef of A if sel is nonzero, else B +template +struct CTypeSelect { typedef A type; }; + +template +struct CTypeSelect<0, A, B> { typedef B type; }; + +// CTypeEquals::value is nonzero if A and B are the same type +template +struct CTypeEquals { enum { value = 0 }; }; + +template +struct CTypeEquals { enum { value = 1 }; }; + +template +struct CTypeEquals : CTypeEquals< const volatile A&, const volatile B& > {}; + +template +struct CTypeEquals : CTypeEquals< const volatile A, const volatile B > {}; + +template +struct CTypeEquals : CTypeEquals< A&, B& > {}; + +// CUtlKeyValuePair is intended for use with key-lookup containers. +// Because it is specialized for "empty_t" values, one container can +// function as either a set of keys OR a key-value dictionary while +// avoiding storage waste or padding for the empty_t value objects. +template +class CUtlKeyValuePair +{ +public: + typedef V ValueReturn_t; + K m_key; + V m_value; + + CUtlKeyValuePair() {} + + template < typename KInit > + explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {} + + template < typename KInit, typename VInit > + CUtlKeyValuePair( const KInit &k, const VInit &v ) : m_key( k ), m_value( v ) {} + + V &GetValue() { return m_value; } + const V &GetValue() const { return m_value; } +}; + +template +class CUtlKeyValuePair +{ +public: + typedef const K ValueReturn_t; + K m_key; + + CUtlKeyValuePair() {} + + template < typename KInit > + explicit CUtlKeyValuePair( const KInit &k ) : m_key( k ) {} + + template < typename KInit > + CUtlKeyValuePair( const KInit &k, empty_t ) : m_key( k ) {} + + CUtlKeyValuePair( const K &k, const empty_t& ) : m_key( k ) {} + const K &GetValue() const { return m_key; } +}; + + +// Default functors. You can specialize these if your type does +// not implement operator== or operator< in an efficient way for +// some odd reason. +template struct DefaultLessFunctor; +template struct DefaultEqualFunctor; + +// Hashing functor used by hash tables. You can either specialize +// for types which are widely used, or plug a custom functor directly +// into the hash table. If you do roll your own, please read up on +// bit-mixing and the avalanche property; be sure that your values +// are reasonably well-distributed across the entire 32-bit range. +// http://en.wikipedia.org/wiki/Avalanche_effect +// http://home.comcast.net/~bretm/hash/5.html +// +template struct DefaultHashFunctor; + +// Argument type information. Struct currently contains one or two typedefs: +// typename Arg_t = primary argument type. Usually const T&, sometimes T. +// typename Alt_t = optional alternate type. Usually *undefined*. +// +// Any specializations should be implemented via simple inheritance +// from ArgumentTypeInfoImpl< BestArgType, [optional] AlternateArgType > +// +template struct ArgumentTypeInfo; + + +// Some fundamental building-block functors... +struct StringLessFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcmp( a, b ) < 0; } }; +struct StringEqualFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcmp( a, b ) == 0; } }; +struct CaselessStringLessFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcasecmp( a, b ) < 0; } }; +struct CaselessStringEqualFunctor { bool operator()( const char *a, const char *b ) const { return Q_strcasecmp( a, b ) == 0; } }; + +struct Mix32HashFunctor { unsigned int operator()( uint32 s ) const; }; +struct StringHashFunctor { unsigned int operator()( const char* s ) const; }; +struct CaselessStringHashFunctor { unsigned int operator()( const char* s ) const; }; + +struct PointerLessFunctor { bool operator()( const void *a, const void *b ) const { return a < b; } }; +struct PointerEqualFunctor { bool operator()( const void *a, const void *b ) const { return a == b; } }; +struct PointerHashFunctor { unsigned int operator()( const void* s ) const { return Mix32HashFunctor()((uint32)POINTER_TO_INT(s)); } }; + + +// Generic implementation of Less and Equal functors +template < typename T > +struct DefaultLessFunctor +{ + bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; } + bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a < b; } + bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a < b; } +}; + +template < typename T > +struct DefaultEqualFunctor +{ + bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; } + bool operator()( typename ArgumentTypeInfo< T >::Alt_t a, typename ArgumentTypeInfo< T >::Arg_t b ) const { return a == b; } + bool operator()( typename ArgumentTypeInfo< T >::Arg_t a, typename ArgumentTypeInfo< T >::Alt_t b ) const { return a == b; } +}; + +// Hashes for basic types +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +template <> struct DefaultHashFunctor : PointerHashFunctor { }; +template <> struct DefaultHashFunctor : PointerHashFunctor { }; +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +template <> struct DefaultHashFunctor : Mix32HashFunctor { }; +#endif + +// String specializations. If you want to operate on raw values, use +// PointerLessFunctor and friends from the "building-block" section above +template <> struct DefaultLessFunctor : StringLessFunctor { }; +template <> struct DefaultLessFunctor : StringLessFunctor { }; +template <> struct DefaultEqualFunctor : StringEqualFunctor { }; +template <> struct DefaultEqualFunctor : StringEqualFunctor { }; +template <> struct DefaultHashFunctor : StringHashFunctor { }; +template <> struct DefaultHashFunctor : StringHashFunctor { }; + +// CUtlString/CUtlConstString are specialized here and not in utlstring.h +// because I consider string datatypes to be fundamental, and don't feel +// comfortable making that header file dependent on this one. (henryg) +class CUtlString; +template < typename T > class CUtlConstStringBase; + +template <> struct DefaultLessFunctor : StringLessFunctor { }; +template <> struct DefaultHashFunctor : StringHashFunctor { }; +template < typename T > struct DefaultLessFunctor< CUtlConstStringBase > : StringLessFunctor { }; +template < typename T > struct DefaultHashFunctor< CUtlConstStringBase > : StringHashFunctor { }; + + +// Helpers to deduce if a type defines a public AltArgumentType_t typedef: +template < typename T > +struct HasClassAltArgumentType +{ + template < typename X > static long Test( typename X::AltArgumentType_t* ); + template < typename X > static char Test( ... ); + enum { value = ( sizeof( Test< T >( NULL ) ) != sizeof( char ) ) }; +}; + +template < typename T, bool = HasClassAltArgumentType< T >::value > +struct GetClassAltArgumentType { typedef typename T::AltArgumentType_t Result_t; }; + +template < typename T > +struct GetClassAltArgumentType< T, false > { typedef undefined_t Result_t; }; + +// Unwrap references; reference types don't have member typedefs. +template < typename T > +struct GetClassAltArgumentType< T&, false > : GetClassAltArgumentType< T > { }; + +// ArgumentTypeInfoImpl is the base for all ArgumentTypeInfo specializations. +template < typename ArgT, typename AltT = typename GetClassAltArgumentType::Result_t > +struct ArgumentTypeInfoImpl +{ + enum { has_alt = 1 }; + typedef ArgT Arg_t; + typedef AltT Alt_t; +}; + +// Handle cases where AltArgumentType_t is typedef'd to undefined_t +template < typename ArgT > +struct ArgumentTypeInfoImpl< ArgT, undefined_t > +{ + enum { has_alt = 0 }; + typedef ArgT Arg_t; + typedef undefined_t Alt_t; +}; + +// Handle cases where AltArgumentType_t is typedef'd to the primary type +template < typename ArgT > +struct ArgumentTypeInfoImpl< ArgT, ArgT > +{ + enum { has_alt = 0 }; + typedef ArgT Arg_t; + typedef undefined_t Alt_t; +}; + + +// By default, everything is passed via const ref and doesn't define an alternate type. +template struct ArgumentTypeInfo : ArgumentTypeInfoImpl< const T& > { }; + +// Small native types are most efficiently passed by value. +template <> struct ArgumentTypeInfo< bool > : ArgumentTypeInfoImpl< bool > { }; +template <> struct ArgumentTypeInfo< char > : ArgumentTypeInfoImpl< char > { }; +template <> struct ArgumentTypeInfo< signed char > : ArgumentTypeInfoImpl< signed char > { }; +template <> struct ArgumentTypeInfo< unsigned char > : ArgumentTypeInfoImpl< unsigned char > { }; +template <> struct ArgumentTypeInfo< signed short > : ArgumentTypeInfoImpl< signed short > { }; +template <> struct ArgumentTypeInfo< unsigned short > : ArgumentTypeInfoImpl< unsigned short > { }; +template <> struct ArgumentTypeInfo< signed int > : ArgumentTypeInfoImpl< signed int > { }; +template <> struct ArgumentTypeInfo< unsigned int > : ArgumentTypeInfoImpl< unsigned int > { }; +template <> struct ArgumentTypeInfo< signed long > : ArgumentTypeInfoImpl< signed long > { }; +template <> struct ArgumentTypeInfo< unsigned long > : ArgumentTypeInfoImpl< unsigned long > { }; +template <> struct ArgumentTypeInfo< signed long long > : ArgumentTypeInfoImpl< signed long long > { }; +template <> struct ArgumentTypeInfo< unsigned long long > : ArgumentTypeInfoImpl< unsigned long long > { }; +template <> struct ArgumentTypeInfo< float > : ArgumentTypeInfoImpl< float > { }; +template <> struct ArgumentTypeInfo< double > : ArgumentTypeInfoImpl< double > { }; +template <> struct ArgumentTypeInfo< long double > : ArgumentTypeInfoImpl< long double > { }; +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +template <> struct ArgumentTypeInfo< wchar_t > : ArgumentTypeInfoImpl< wchar_t > { }; +#endif + +// Pointers are also most efficiently passed by value. +template < typename T > struct ArgumentTypeInfo< T* > : ArgumentTypeInfoImpl< T* > { }; + + +// Specializations to unwrap const-decorated types and references +template struct ArgumentTypeInfo : ArgumentTypeInfo { }; +template struct ArgumentTypeInfo : ArgumentTypeInfo { }; +template struct ArgumentTypeInfo : ArgumentTypeInfo { }; +template struct ArgumentTypeInfo : ArgumentTypeInfo { }; + +template struct DefaultLessFunctor : DefaultLessFunctor { }; +template struct DefaultLessFunctor : DefaultLessFunctor { }; +template struct DefaultLessFunctor : DefaultLessFunctor { }; +template struct DefaultLessFunctor : DefaultLessFunctor { }; + +template struct DefaultEqualFunctor : DefaultEqualFunctor { }; +template struct DefaultEqualFunctor : DefaultEqualFunctor { }; +template struct DefaultEqualFunctor : DefaultEqualFunctor { }; +template struct DefaultEqualFunctor : DefaultEqualFunctor { }; + +template struct DefaultHashFunctor : DefaultHashFunctor { }; +template struct DefaultHashFunctor : DefaultHashFunctor { }; +template struct DefaultHashFunctor : DefaultHashFunctor { }; +template struct DefaultHashFunctor : DefaultHashFunctor { }; + + +// Hash all pointer types as raw pointers by default +template struct DefaultHashFunctor< T * > : PointerHashFunctor { }; + + +// Here follow the useful implementations. + +// Bob Jenkins's 32-bit mix function. +inline unsigned int Mix32HashFunctor::operator()( uint32 n ) const +{ + // Perform a mixture of the bits in n, where each bit + // of the input value has an equal chance to affect each + // bit of the output. This turns tightly clustered input + // values into a smooth distribution. + // + // This takes 16-20 cycles on modern x86 architectures; + // that's roughly the same cost as a mispredicted branch. + // It's also reasonably efficient on PPC-based consoles. + // + // If you're still thinking, "too many instructions!", + // do keep in mind that reading one byte of uncached RAM + // is about 30x slower than executing this code. It pays + // to have a good hash function which minimizes collisions + // (and therefore long lookup chains). + n = ( n + 0x7ed55d16 ) + ( n << 12 ); + n = ( n ^ 0xc761c23c ) ^ ( n >> 19 ); + n = ( n + 0x165667b1 ) + ( n << 5 ); + n = ( n + 0xd3a2646c ) ^ ( n << 9 ); + n = ( n + 0xfd7046c5 ) + ( n << 3 ); + n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 ); + return n; +} + +// Based on the widely-used FNV-1A string hash with a final +// mixing step to improve dispersion for very small and very +// large hash table sizes. +inline unsigned int StringHashFunctor::operator()( const char* s ) const +{ + uint32 h = 2166136261u; + for ( ; *s; ++s ) + { + uint32 c = (unsigned char) *s; + h = (h ^ c) * 16777619; + } + return (h ^ (h << 17)) + (h >> 21); +} + +// Equivalent to StringHashFunctor on lower-case strings. +inline unsigned int CaselessStringHashFunctor::operator()( const char* s ) const +{ + uint32 h = 2166136261u; + for ( ; *s; ++s ) + { + uint32 c = (unsigned char) *s; + // Brutally fast branchless ASCII tolower(): + // if ((c >= 'A') && (c <= 'Z')) c += ('a' - 'A'); + c += (((('A'-1) - c) & (c - ('Z'+1))) >> 26) & 32; + h = (h ^ c) * 16777619; + } + return (h ^ (h << 17)) + (h >> 21); +} + + +#endif // UTLCOMMON_H diff --git a/public/tier1/utldelegate.h b/public/tier1/utldelegate.h new file mode 100644 index 0000000..04c5dad --- /dev/null +++ b/public/tier1/utldelegate.h @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A header describing use of the delegate system. It's hiding +// the highly complex implementation details of the delegate system +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef UTLDELEGATE_H +#define UTLDELEGATE_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// The delegate system: A method of invoking methods, whether they are +// member methods of classes, static methods of classes, or free functions, +// dealing with all the nastiness in differences between how the calls have +// to happen yet works in a highly optimal fashion. For details, see +// +// http://www.codeproject.com/cpp/FastDelegate.asp +// +// The delegate design pattern is described here +// +// http://en.wikipedia.org/wiki/Delegation_(programming) +//----------------------------------------------------------------------------- + +#ifdef UTLDELEGATE_USAGE_DEMONSTRATION + +//----------------------------------------------------------------------------- +// Here, we show how to use this system (the ifdef UTLDELEGATE_USAGE_DEMONSTRATION is used to get syntax coloring). +//----------------------------------------------------------------------------- + +// First, define the functions you wish to call. +int Test1( char *pString, float x ); +class CTestClass +{ +public: + void Test2(); + static float Test3( int x ); +}; + +void Test() +{ + CTestClass testClass; + + // CUtlDelegate is a class that can be used to invoke methods of classes + // or static functions in a highly efficient manner. + + // There are a couple ways to hook up a delegate. One is in a constructor + // Note that the template parameter of CUtlFastDelegate looks like the + // function type: first, you have the return type, then ( parameter list ) + CUtlDelegate< int ( char *, float ) > delegate1( &Test1 ); + + // Another way is to use the UtlMakeDelegate method, allowing you to + // define the delegate later. Note that UtlMakeDelegate does *not* do a heap allocation + CUtlDelegate< void () > delegate2; + delegate2 = UtlMakeDelegate( &testClass, &CTestClass::Test2 ); + + // A third method is to use the Bind() method of CUtlFastDelegate + // Note that you do not pass in the class pointer for static functions + CUtlDelegate< float ( int ) > delegate3; + delegate3.Bind( &CTestClass::Test3 ); + + // Use the () operator to invoke the function calls. + int x = delegate1( "hello", 1.0f ); + delegate2(); + float y = delegate3( 5 ); + + // Use the Clear() method to unbind a delegate. + delegate1.Clear(); + + // You can use operator! or IsEmpty() to see if a delegate is bound + if ( !delegate1.IsEmpty() ) + { + delegate1( "hello2" ); + } + + // Delegates maintain an internal non-templatized representation of the + // functions they are bound to called CUtlAbstractDelegate. These are + // useful when keeping a list of untyped delegates or when passing + // delegates across interface boundaries. + const CUtlAbstractDelegate &abstractDelegate3 = delegate3.GetAbstractDelegate(); + CUtlDelegate< float ( int ) > delegate4; + delegate4.SetAbstractDelegate( abstractDelegate3 ); + delegate4( 10 ); +} + +#endif // UTLDELEGATE_USAGE_DEMONSTRATION + +// Looking in this file may cause blindness. +#include "tier1/utldelegateimpl.h" + +#endif // UTLDELEGATE_H diff --git a/public/tier1/utldelegateimpl.h b/public/tier1/utldelegateimpl.h new file mode 100644 index 0000000..cf9809d --- /dev/null +++ b/public/tier1/utldelegateimpl.h @@ -0,0 +1,2656 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// FastDelegate.h +// Efficient delegates in C++ that generate only two lines of asm code! +// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp +// +// - Don Clugston, Mar 2004. +// Major contributions were made by Jody Hagins. +// History: +// 24-Apr-04 1.0 * Submitted to CodeProject. +// 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack. +// * Improved syntax for horrible_cast (thanks Paul Bludov). +// * Tested on Metrowerks MWCC and Intel ICL (IA32) +// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL. +// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 +// * Now works on /clr "managed C++" code on VC7, VC7.1 +// * Comeau C++ now compiles without warnings. +// * Prevent the virtual inheritance case from being used on +// VC6 and earlier, which generate incorrect code. +// * Improved warning and error messages. Non-standard hacks +// now have compile-time checks to make them safer. +// * implicit_cast used instead of static_cast in many cases. +// * If calling a const member function, a const class pointer can be used. +// * UtlMakeDelegate() global helper function added to simplify pass-by-value. +// * Added fastdelegate.Clear() +// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates) +// 30-Oct-04 1.3 * Support for (non-void) return values. +// * No more workarounds in client code! +// MSVC and Intel now use a clever hack invented by John Dlugosz: +// - The FASTDELEGATEDECLARE workaround is no longer necessary. +// - No more warning messages for VC6 +// * Less use of macros. Error messages should be more comprehensible. +// * Added include guards +// * Added FastDelegate::IsEmpty() to test if invocation is safe (Thanks Neville Franks). +// * Now tested on VS 2005 Express Beta, PGI C++ +// 24-Dec-04 1.4 * Added CUtlAbstractDelegate, to allow collections of disparate delegates. +// * <,>,<=,>= comparison operators to allow storage in ordered containers. +// * Substantial reduction of code size, especially the 'Closure' class. +// * Standardised all the compiler-specific workarounds. +// * MFP conversion now works for CodePlay (but not yet supported in the full code). +// * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1 +// * New syntax: FastDelegate< int (char *, double) >. +// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .Clear(), ==0 as equivalent to .IsEmpty(). (Thanks elfric). +// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium. +// 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.IsEmpty())" +// * Fully supported by CodePlay VectorC +// * Bugfix for Metrowerks: IsEmpty() was buggy because a valid MFP can be 0 on MWCC! +// * More optimal assignment,== and != operators for static function pointers. +// 22-Jul-10 xxx * Reformatted + renamed to match valve coding standards +// * Added UtlMakeDelegate for static functions + +#ifndef UTLDELEGATEIMPL_H +#define UTLDELEGATEIMPL_H +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include // to allow <,> comparisons + +//////////////////////////////////////////////////////////////////////////////// +// Configuration options +// +//////////////////////////////////////////////////////////////////////////////// + +// Uncomment the following #define for optimally-sized delegates. +// In this case, the generated asm code is almost identical to the code you'd get +// if the compiler had native support for delegates. +// It will not work on systems where sizeof(dataptr) < sizeof(codeptr). +// Thus, it will not work for DOS compilers using the medium model. +// It will also probably fail on some DSP systems. +#define FASTDELEGATE_USESTATICFUNCTIONHACK + +// Uncomment the next line to allow function declarator syntax. +// It is automatically enabled for those compilers where it is known to work. +//#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX + +//////////////////////////////////////////////////////////////////////////////// +// Compiler identification for workarounds +// +//////////////////////////////////////////////////////////////////////////////// + +// Compiler identification. It's not easy to identify Visual C++ because +// many vendors fraudulently define Microsoft's identifiers. +#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__) +#define FASTDLGT_ISMSVC + +#if (_MSC_VER <1300) // Many workarounds are required for VC6. +#define FASTDLGT_VC6 +#pragma warning(disable:4786) // disable this ridiculous warning +#endif + +#endif + +// Does the compiler uses Microsoft's member function pointer structure? +// If so, it needs special treatment. +// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's +// identifier, _MSC_VER. We need to filter Metrowerks out. +#if defined(_MSC_VER) && !defined(__MWERKS__) +#define FASTDLGT_MICROSOFT_MFP + +#if !defined(__VECTOR_C) +// CodePlay doesn't have the __single/multi/virtual_inheritance keywords +#define FASTDLGT_HASINHERITANCE_KEYWORDS +#endif +#endif + +// Does it allow function declarator syntax? The following compilers are known to work: +#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1 +#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX +#endif + +// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use. +#if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__) +#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX +#endif + +// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too. +#if defined (__MWERKS__) +#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX +#endif + +#ifdef __GNUC__ // Workaround GCC bug #8271 + // At present, GCC doesn't recognize constness of MFPs in templates +#define FASTDELEGATE_GCC_BUG_8271 +#endif + + + +//////////////////////////////////////////////////////////////////////////////// +// General tricks used in this code +// +// (a) Error messages are generated by typdefing an array of negative size to +// generate compile-time errors. +// (b) Warning messages on MSVC are generated by declaring unused variables, and +// enabling the "variable XXX is never used" warning. +// (c) Unions are used in a few compiler-specific cases to perform illegal casts. +// (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to +// (char *) first to ensure that the correct number of *bytes* are added. +// +//////////////////////////////////////////////////////////////////////////////// +// Helper templates +// +//////////////////////////////////////////////////////////////////////////////// + + +namespace detail // we'll hide the implementation details in a nested namespace. +{ + +// implicit_cast< > +// I believe this was originally going to be in the C++ standard but +// was left out by accident. It's even milder than static_cast. +// I use it instead of static_cast<> to emphasize that I'm not doing +// anything nasty. +// Usage is identical to static_cast<> +template +inline OutputClass implicit_cast(InputClass input) +{ + return input; +} + +// horrible_cast< > +// This is truly evil. It completely subverts C++'s type system, allowing you +// to cast from any class to any other class. Technically, using a union +// to perform the cast is undefined behaviour (even in C). But we can see if +// it is OK by checking that the union is the same size as each of its members. +// horrible_cast<> should only be used for compiler-specific workarounds. +// Usage is identical to reinterpret_cast<>. + +// This union is declared outside the horrible_cast because BCC 5.5.1 +// can't inline a function with a nested class, and gives a warning. +template +union horrible_union +{ + OutputClass out; + InputClass in; +}; + +template +inline OutputClass horrible_cast(const InputClass input) +{ + horrible_union u; + // Cause a compile-time error if in, out and u are not the same size. + // If the compile fails here, it means the compiler has peculiar + // unions which would prevent the cast from working. + typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u) + && sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1]; + u.in = input; + return u.out; +} + +//////////////////////////////////////////////////////////////////////////////// +// Workarounds +// +//////////////////////////////////////////////////////////////////////////////// + +// Backwards compatibility: This macro used to be necessary in the virtual inheritance +// case for Intel and Microsoft. Now it just forward-declares the class. +#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME; + +// Prevent use of the static function hack with the DOS medium model. +#ifdef __MEDIUM__ +#undef FASTDELEGATE_USESTATICFUNCTIONHACK +#endif + +// DefaultVoid - a workaround for 'void' templates in VC6. +// +// (1) VC6 and earlier do not allow 'void' as a default template argument. +// (2) They also doesn't allow you to return 'void' from a function. +// +// Workaround for (1): Declare a dummy type 'DefaultVoid' which we use +// when we'd like to use 'void'. We convert it into 'void' and back +// using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>. +// Workaround for (2): On VC6, the code for calling a void function is +// identical to the code for calling a non-void function in which the +// return value is never used, provided the return value is returned +// in the EAX register, rather than on the stack. +// This is true for most fundamental types such as int, enum, void *. +// Const void * is the safest option since it doesn't participate +// in any automatic conversions. But on a 16-bit compiler it might +// cause extra code to be generated, so we disable it for all compilers +// except for VC6 (and VC5). +#ifdef FASTDLGT_VC6 +// VC6 workaround +typedef const void * DefaultVoid; +#else +// On any other compiler, just use a normal void. +typedef void DefaultVoid; +#endif + +// Translate from 'DefaultVoid' to 'void'. +// Everything else is unchanged +template +struct DefaultVoidToVoid { typedef T type; }; + +template <> +struct DefaultVoidToVoid { typedef void type; }; + +// Translate from 'void' into 'DefaultVoid' +// Everything else is unchanged +template +struct VoidToDefaultVoid { typedef T type; }; + +template <> +struct VoidToDefaultVoid { typedef DefaultVoid type; }; + + + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 1: +// +// Conversion of member function pointer to a standard form +// +//////////////////////////////////////////////////////////////////////////////// + +// GenericClass is a fake class, ONLY used to provide a type. +// It is vitally important that it is never defined, so that the compiler doesn't +// think it can optimize the invocation. For example, Borland generates simpler +// code if it knows the class only uses single inheritance. + +// Compilers using Microsoft's structure need to be treated as a special case. +#ifdef FASTDLGT_MICROSOFT_MFP + +#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS + // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP + // (4 bytes), even when the /vmg option is used. Declaring an empty class + // would give 16 byte pointers in this case.... + class __single_inheritance GenericClass; +#endif + // ...but for Codeplay, an empty class *always* gives 4 byte pointers. + // If compiled with the /clr option ("managed C++"), the JIT compiler thinks + // it needs to load GenericClass before it can call any of its functions, + // (compiles OK but crashes at runtime!), so we need to declare an + // empty class to make it happy. + // Codeplay and VC4 can't cope with the unknown_inheritance case either. + class GenericClass {}; +#else + class GenericClass; +#endif + +// The size of a single inheritance member function pointer. +const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)()); + +// SimplifyMemFunc< >::Convert() +// +// A template function that converts an arbitrary member function pointer into the +// simplest possible form of member function pointer, using a supplied 'this' pointer. +// According to the standard, this can be done legally with reinterpret_cast<>. +// For (non-standard) compilers which use member function pointers which vary in size +// depending on the class, we need to use knowledge of the internal structure of a +// member function pointer, as used by the compiler. Template specialization is used +// to distinguish between the sizes. Because some compilers don't support partial +// template specialisation, I use full specialisation of a wrapper struct. + +// general case -- don't know how to convert it. Force a compile failure +template +struct SimplifyMemFunc +{ + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) + { + // Unsupported member function type -- force a compile failure. + // (it's illegal to have a array with negative size). + typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100]; + return 0; + } +}; + +// For compilers where all member func ptrs are the same size, everything goes here. +// For non-standard compilers, only single_inheritance classes go here. +template <> +struct SimplifyMemFunc +{ + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) + { +#if defined __DMC__ + // Digital Mars doesn't allow you to cast between abitrary PMF's, + // even though the standard says you can. The 32-bit compiler lets you + // static_cast through an int, but the DOS compiler doesn't. + bound_func = horrible_cast(function_to_bind); +#else + bound_func = reinterpret_cast(function_to_bind); +#endif + return reinterpret_cast(pthis); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 1b: +// +// Workarounds for Microsoft and Intel +// +//////////////////////////////////////////////////////////////////////////////// + + +// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay), +// need to be treated as a special case. +#ifdef FASTDLGT_MICROSOFT_MFP + +// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1) +// at the start of each function for extra safety, but VC6 seems to ICE +// intermittently if you do this inside a template. + +// __multiple_inheritance classes go here +// Nasty hack for Microsoft and Intel (IA32 and Itanium) +template<> +struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > +{ + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) + { + // We need to use a horrible_cast to do this conversion. + // In MSVC, a multiple inheritance member pointer is internally defined as: + union + { + XFuncType func; + struct + { + GenericMemFuncType funcaddress; // points to the actual member function + int delta; // #BYTES to be added to the 'this' pointer + }s; + } u; + // Check that the horrible_cast will work + typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1]; + u.func = function_to_bind; + bound_func = u.s.funcaddress; + return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta); + } +}; + +// virtual inheritance is a real nuisance. It's inefficient and complicated. +// On MSVC and Intel, there isn't enough information in the pointer itself to +// enable conversion to a closure pointer. Earlier versions of this code didn't +// work for all cases, and generated a compile-time error instead. +// But a very clever hack invented by John M. Dlugosz solves this problem. +// My code is somewhat different to his: I have no asm code, and I make no +// assumptions about the calling convention that is used. + +// In VC++ and ICL, a virtual_inheritance member pointer +// is internally defined as: +struct MicrosoftVirtualMFP +{ + void (GenericClass::*codeptr)(); // points to the actual member function + int delta; // #bytes to be added to the 'this' pointer + int vtable_index; // or 0 if no virtual inheritance +}; +// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the +// m_codeptr member is *always* called, regardless of the values of the other +// members. (This is *not* true for other compilers, eg GCC, which obtain the +// function address from the vtable if a virtual function is being called). +// Dlugosz's trick is to make the codeptr point to a probe function which +// returns the 'this' pointer that was used. + +// Define a generic class that uses virtual inheritance. +// It has a trival member function that returns the value of the 'this' pointer. +struct GenericVirtualClass : virtual public GenericClass +{ + typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)(); + GenericVirtualClass * GetThis() { return this; } +}; + +// __virtual_inheritance classes go here +#ifdef _MSC_VER +#pragma warning( disable : 4121 ) +#endif + +template <> +struct SimplifyMemFunc +{ + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) + { + union + { + XFuncType func; + GenericClass* (X::*ProbeFunc)(); + MicrosoftVirtualMFP s; + } u; + u.func = function_to_bind; + bound_func = reinterpret_cast(u.s.codeptr); + union + { + GenericVirtualClass::ProbePtrType virtfunc; + MicrosoftVirtualMFP s; + } u2; + // Check that the horrible_cast<>s will work + typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s) + && sizeof(function_to_bind)==sizeof(u.ProbeFunc) + && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1]; + // Unfortunately, taking the address of a MF prevents it from being inlined, so + // this next line can't be completely optimised away by the compiler. + u2.virtfunc = &GenericVirtualClass::GetThis; + u.s.codeptr = u2.s.codeptr; + return (pthis->*u.ProbeFunc)(); + } +}; +#ifdef _MSC_VER +#pragma warning( default : 4121 ) +#endif + +#if (_MSC_VER <1300) + +// Nasty hack for Microsoft Visual C++ 6.0 +// unknown_inheritance classes go here +// There is a compiler bug in MSVC6 which generates incorrect code in this case!! +template <> +struct SimplifyMemFunc +{ + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) + { + // There is an apalling but obscure compiler bug in MSVC6 and earlier: + // vtable_index and 'vtordisp' are always set to 0 in the + // unknown_inheritance case! + // This means that an incorrect function could be called!!! + // Compiling with the /vmg option leads to potentially incorrect code. + // This is probably the reason that the IDE has a user interface for specifying + // the /vmg option, but it is disabled - you can only specify /vmg on + // the command line. In VC1.5 and earlier, the compiler would ICE if it ever + // encountered this situation. + // It is OK to use the /vmg option if /vmm or /vms is specified. + + // Fortunately, the wrong function is only called in very obscure cases. + // It only occurs when a derived class overrides a virtual function declared + // in a virtual base class, and the member function + // points to the *Derived* version of that function. The problem can be + // completely averted in 100% of cases by using the *Base class* for the + // member fpointer. Ie, if you use the base class as an interface, you'll + // stay out of trouble. + // Occasionally, you might want to point directly to a derived class function + // that isn't an override of a base class. In this case, both vtable_index + // and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated. + // We can generate correct code in this case. To prevent an incorrect call from + // ever being made, on MSVC6 we generate a warning, and call a function to + // make the program crash instantly. + typedef char ERROR_VC6CompilerBug[-100]; + return 0; + } +}; + + +#else + +// Nasty hack for Microsoft and Intel (IA32 and Itanium) +// unknown_inheritance classes go here +// This is probably the ugliest bit of code I've ever written. Look at the casts! +// There is a compiler bug in MSVC6 which prevents it from using this code. +template <> +struct SimplifyMemFunc +{ + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) + { + // The member function pointer is 16 bytes long. We can't use a normal cast, but + // we can use a union to do the conversion. + union + { + XFuncType func; + // In VC++ and ICL, an unknown_inheritance member pointer + // is internally defined as: + struct + { + GenericMemFuncType funcaddress; // points to the actual member function + int delta; // #bytes to be added to the 'this' pointer + int vtordisp; // #bytes to add to 'this' to find the vtable + int vtable_index; // or 0 if no virtual inheritance + } s; + } u; + // Check that the horrible_cast will work + typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1]; + u.func = function_to_bind; + bound_func = u.s.funcaddress; + int virtual_delta = 0; + if (u.s.vtable_index) + { // Virtual inheritance is used + // First, get to the vtable. + // It is 'vtordisp' bytes from the start of the class. + const int * vtable = *reinterpret_cast( + reinterpret_cast(pthis) + u.s.vtordisp ); + + // 'vtable_index' tells us where in the table we should be looking. + virtual_delta = u.s.vtordisp + *reinterpret_cast( + reinterpret_cast(vtable) + u.s.vtable_index); + } + // The int at 'virtual_delta' gives us the amount to add to 'this'. + // Finally we can add the three components together. Phew! + return reinterpret_cast( + reinterpret_cast(pthis) + u.s.delta + virtual_delta); + }; +}; +#endif // MSVC 7 and greater + +#endif // MS/Intel hacks + +} // namespace detail + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 2: +// +// Define the delegate storage, and cope with static functions +// +//////////////////////////////////////////////////////////////////////////////// + +// CUtlAbstractDelegate -- an opaque structure which can hold an arbitary delegate. +// It knows nothing about the calling convention or number of arguments used by +// the function pointed to. +// It supplies comparison operators so that it can be stored in STL collections. +// It cannot be set to anything other than null, nor invoked directly: +// it must be converted to a specific delegate. + +// Implementation: +// There are two possible implementations: the Safe method and the Evil method. +// CUtlAbstractDelegate - Safe version +// +// This implementation is standard-compliant, but a bit tricky. +// A static function pointer is stored inside the class. +// Here are the valid values: +// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ +// | 0 | 0 | 0 | Empty | +// | !=0 |(dontcare)| Invoker | Static function| +// | 0 | !=0 | !=0* | Method call | +// +--------------------+----------+------------+----------------+ +// * For Metrowerks, this can be 0. (first virtual function in a +// single_inheritance class). +// When stored stored inside a specific delegate, the 'dontcare' entries are replaced +// with a reference to the delegate itself. This complicates the = and == operators +// for the delegate class. + +// CUtlAbstractDelegate - Evil version +// +// For compilers where data pointers are at least as big as code pointers, it is +// possible to store the function pointer in the this pointer, using another +// horrible_cast. In this case the CUtlAbstractDelegate implementation is simple: +// +--pThis --+-- pMemFunc-+-- Meaning---------------------+ +// | 0 | 0 | Empty | +// | !=0 | !=0* | Static function or method call| +// +----------+------------+-------------------------------+ +// * For Metrowerks, this can be 0. (first virtual function in a +// single_inheritance class). +// Note that the Sun C++ and MSVC documentation explicitly state that they +// support static_cast between void * and function pointers. + +class CUtlAbstractDelegate +{ +protected: + // the data is protected, not private, because many + // compilers have problems with template friends. + typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. + detail::GenericClass *m_pthis; + GenericMemFuncType m_pFunction; + +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + typedef void (*GenericFuncPtr)(); // arbitrary code pointer + GenericFuncPtr m_pStaticFunction; +#endif + +public: +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + CUtlAbstractDelegate() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {}; + void Clear() + { + m_pthis=0; m_pFunction=0; m_pStaticFunction=0; + } +#else + CUtlAbstractDelegate() : m_pthis(0), m_pFunction(0) {}; + void Clear() { m_pthis=0; m_pFunction=0; } +#endif +public: +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + inline bool IsEqual (const CUtlAbstractDelegate &x) const + { + // We have to cope with the static function pointers as a special case + if (m_pFunction!=x.m_pFunction) + return false; + // the static function ptrs must either both be equal, or both be 0. + if (m_pStaticFunction!=x.m_pStaticFunction) + return false; + if (m_pStaticFunction!=0) + return m_pthis==x.m_pthis; + else + return true; + } +#else // Evil Method + inline bool IsEqual (const CUtlAbstractDelegate &x) const + { + return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction; + } +#endif + // Provide a strict weak ordering for DelegateMementos. + inline bool IsLess(const CUtlAbstractDelegate &right) const + { + // deal with static function pointers first +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) + return m_pStaticFunction < right.m_pStaticFunction; +#endif + if (m_pthis !=right.m_pthis) + return m_pthis < right.m_pthis; + // There are no ordering operators for member function pointers, + // but we can fake one by comparing each byte. The resulting ordering is + // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers. + return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; + + } + // BUGFIX (Mar 2005): + // We can't just compare m_pFunction because on Metrowerks, + // m_pFunction can be zero even if the delegate is not empty! + inline bool operator ! () const // Is it bound to anything? + { + return m_pthis==0 && m_pFunction==0; + } + inline bool IsEmpty() const // Is it bound to anything? + { + return m_pthis==0 && m_pFunction==0; + } +public: + CUtlAbstractDelegate & operator = (const CUtlAbstractDelegate &right) + { + SetMementoFrom(right); + return *this; + } + inline bool operator <(const CUtlAbstractDelegate &right) + { + return IsLess(right); + } + inline bool operator >(const CUtlAbstractDelegate &right) + { + return right.IsLess(*this); + } + CUtlAbstractDelegate (const CUtlAbstractDelegate &right) : + m_pFunction(right.m_pFunction), m_pthis(right.m_pthis) +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + , m_pStaticFunction (right.m_pStaticFunction) +#endif + {} + + // Only use this if you really know what you're doing. + // It's used in cases where I've cached off a delegate previously + void UnsafeThisPointerSlam( void *pThis ) + { + m_pthis = (detail::GenericClass*)( pThis ); + } + + void *UnsafeGetThisPtr() + { + return m_pthis; + } + +protected: + void SetMementoFrom(const CUtlAbstractDelegate &right) + { + m_pFunction = right.m_pFunction; + m_pthis = right.m_pthis; +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + m_pStaticFunction = right.m_pStaticFunction; +#endif + } +}; + + +// ClosurePtr<> +// +// A private wrapper class that adds function signatures to CUtlAbstractDelegate. +// It's the class that does most of the actual work. +// The signatures are specified by: +// GenericMemFunc: must be a type of GenericClass member function pointer. +// StaticFuncPtr: must be a type of function pointer with the same signature +// as GenericMemFunc. +// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 +// where it never returns void (returns DefaultVoid instead). + +// An outer class, FastDelegateN<>, handles the invoking and creates the +// necessary typedefs. +// This class does everything else. + +namespace detail +{ + +template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr> +class ClosurePtr : public CUtlAbstractDelegate +{ +public: + // These functions are for setting the delegate to a member function. + + // Here's the clever bit: we convert an arbitrary member function into a + // standard form. XMemFunc should be a member function of class X, but I can't + // enforce that here. It needs to be enforced by the wrapper class. + template < class X, class XMemFunc > + inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) + { + m_pthis = SimplifyMemFunc< sizeof(function_to_bind) > + ::Convert(pthis, function_to_bind, m_pFunction); +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + m_pStaticFunction = 0; +#endif + } + // For const member functions, we only need a const class pointer. + // Since we know that the member function is const, it's safe to + // remove the const qualifier from the 'this' pointer with a const_cast. + // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name. + template < class X, class XMemFunc> + inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) + { + m_pthis= SimplifyMemFunc< sizeof(function_to_bind) > + ::Convert(const_cast(pthis), function_to_bind, m_pFunction); +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + m_pStaticFunction = 0; +#endif + } +#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates + template < class X, class XMemFunc> + inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) + { + bindconstmemfunc(pthis, function_to_bind); +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + m_pStaticFunction = 0; +#endif + } +#endif + // These functions are required for invoking the stored function + inline GenericClass *GetClosureThis() const { return m_pthis; } + inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast(m_pFunction); } + +// There are a few ways of dealing with static function pointers. +// There's a standard-compliant, but tricky method. +// There's also a straightforward hack, that won't work on DOS compilers using the +// medium memory model. It's so evil that I can't recommend it, but I've +// implemented it anyway because it produces very nice asm code. + +#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + +// ClosurePtr<> - Safe version +// +// This implementation is standard-compliant, but a bit tricky. +// I store the function pointer inside the class, and the delegate then +// points to itself. Whenever the delegate is copied, these self-references +// must be transformed, and this complicates the = and == operators. +public: + // The next two functions are for operator ==, =, and the copy constructor. + // We may need to convert the m_pthis pointers, so that + // they remain as self-references. + template< class DerivedClass > + inline void CopyFrom (DerivedClass *pParent, const CUtlAbstractDelegate &x) + { + SetMementoFrom(x); + if (m_pStaticFunction!=0) + { + // transform self references... + m_pthis=reinterpret_cast(pParent); + } + } + // For static functions, the 'static_function_invoker' class in the parent + // will be called. The parent then needs to call GetStaticFunction() to find out + // the actual function to invoke. + template < class DerivedClass, class ParentInvokerSig > + inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, + StaticFuncPtr function_to_bind ) + { + if (function_to_bind==0) + { // cope with assignment to 0 + m_pFunction=0; + } + else + { + bindmemfunc(pParent, static_function_invoker); + } + m_pStaticFunction=reinterpret_cast(function_to_bind); + } + inline UnvoidStaticFuncPtr GetStaticFunction() const + { + return reinterpret_cast(m_pStaticFunction); + } +#else + +// ClosurePtr<> - Evil version +// +// For compilers where data pointers are at least as big as code pointers, it is +// possible to store the function pointer in the this pointer, using another +// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and +// speeds up comparison and assignment. If C++ provided direct language support +// for delegates, they would produce asm code that was almost identical to this. +// Note that the Sun C++ and MSVC documentation explicitly state that they +// support static_cast between void * and function pointers. + + template< class DerivedClass > + inline void CopyFrom (DerivedClass *pParent, const CUtlAbstractDelegate &right) + { + pParent; + SetMementoFrom(right); + } + // For static functions, the 'static_function_invoker' class in the parent + // will be called. The parent then needs to call GetStaticFunction() to find out + // the actual function to invoke. + // ******** EVIL, EVIL CODE! ******* + template < class DerivedClass, class ParentInvokerSig> + inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, + StaticFuncPtr function_to_bind) + { + if (function_to_bind==0) + { // cope with assignment to 0 + m_pFunction=0; + } + else + { + // We'll be ignoring the 'this' pointer, but we need to make sure we pass + // a valid value to bindmemfunc(). + bindmemfunc(pParent, static_function_invoker); + } + + // WARNING! Evil hack. We store the function in the 'this' pointer! + // Ensure that there's a compilation failure if function pointers + // and data pointers have different sizes. + // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. + typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1]; + m_pthis = horrible_cast(function_to_bind); + // MSVC, SunC++ and DMC accept the following (non-standard) code: +// m_pthis = static_cast(static_cast(function_to_bind)); + // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long +// m_pthis = reinterpret_cast(reinterpret_cast(function_to_bind)); + } + // ******** EVIL, EVIL CODE! ******* + // This function will be called with an invalid 'this' pointer!! + // We're just returning the 'this' pointer, converted into + // a function pointer! + inline UnvoidStaticFuncPtr GetStaticFunction() const + { + // Ensure that there's a compilation failure if function pointers + // and data pointers have different sizes. + // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. + typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1]; + return horrible_cast(this); + } +#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) + + // Does the closure contain this static function? + inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr) + { + if (funcptr==0) return IsEmpty(); + // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary + // value that is not equal to any valid function pointer. + else return funcptr==reinterpret_cast(GetStaticFunction()); + } +}; + + +} // namespace detail + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 3: +// +// Wrapper classes to ensure type safety +// +//////////////////////////////////////////////////////////////////////////////// + + +// Once we have the member function conversion templates, it's easy to make the +// wrapper classes. So that they will work with as many compilers as possible, +// the classes are of the form +// FastDelegate3 +// They can cope with any combination of parameters. The max number of parameters +// allowed is 8, but it is trivial to increase this limit. +// Note that we need to treat const member functions seperately. +// All this class does is to enforce type safety, and invoke the delegate with +// the correct list of parameters. + +// Because of the weird rule about the class of derived member function pointers, +// you sometimes need to apply a downcast to the 'this' pointer. +// This is the reason for the use of "implicit_cast(pthis)" in the code below. +// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction, +// without this trick you'd need to write: +// MyDelegate(static_cast(&d), &CDerivedClass::SimpleVirtualFunction); +// but with the trick you can write +// MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction); + +// RetType is the type the compiler uses in compiling the template. For VC6, +// it cannot be void. DesiredRetType is the real type which is returned from +// all of the functions. It can be void. + +// Implicit conversion to "bool" is achieved using the safe_bool idiom, +// using member data pointers (MDP). This allows "if (dg)..." syntax +// Because some compilers (eg codeplay) don't have a unique value for a zero +// MDP, an extra padding member is added to the SafeBool struct. +// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so +// in that case the static function constructor is not made explicit; this +// allows "if (dg==0) ..." to compile. + +//N=0 +template +class FastDelegate0 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(); + typedef RetType (*UnvoidStaticFunctionPtr)(); + typedef RetType (detail::GenericClass::*GenericMemFn)(); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate0 type; + + // Construction and comparison functions + FastDelegate0() { Clear(); } + FastDelegate0(const FastDelegate0 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate0 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate0 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate0 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate0 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate0 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate0(Y *pthis, DesiredRetType (X::* function_to_bind)() ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)()) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate0(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate0(DesiredRetType (*function_to_bind)() ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)() ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)()) + { + m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() () const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction() const + { + return (*(m_Closure.GetStaticFunction()))(); + } +}; + +//N=1 +template +class FastDelegate1 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate1 type; + + // Construction and comparison functions + FastDelegate1() { Clear(); } + FastDelegate1(const FastDelegate1 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate1 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate1 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate1 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate1 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate1 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate1(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate1(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1)) + { + m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1) const + { + return (*(m_Closure.GetStaticFunction()))(p1); + } +}; + +//N=2 +template +class FastDelegate2 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate2 type; + + // Construction and comparison functions + FastDelegate2() { Clear(); } + FastDelegate2(const FastDelegate2 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate2 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate2 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate2 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate2 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate2 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate2(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate2(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) + { + m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2); + } +}; + +//N=3 +template +class FastDelegate3 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate3 type; + + // Construction and comparison functions + FastDelegate3() { Clear(); } + FastDelegate3(const FastDelegate3 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate3 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate3 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate3 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate3 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate3 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate3(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate3(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) + { + m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2, Param3 p3) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2, p3); + } +}; + +//N=4 +template +class FastDelegate4 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate4 type; + + // Construction and comparison functions + FastDelegate4() { Clear(); } + FastDelegate4(const FastDelegate4 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate4 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate4 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate4 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate4 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate4 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate4(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate4(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) + { + m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4); + } +}; + +//N=5 +template +class FastDelegate5 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate5 type; + + // Construction and comparison functions + FastDelegate5() { Clear(); } + FastDelegate5(const FastDelegate5 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate5 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate5 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate5 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate5 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate5 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate5(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate5(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) + { + m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5); + } +}; + +//N=6 +template +class FastDelegate6 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate6 type; + + // Construction and comparison functions + FastDelegate6() { Clear(); } + FastDelegate6(const FastDelegate6 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate6 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate6 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate6 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate6 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate6 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate6(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate6(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) + { + m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6); + } +}; + +//N=7 +template +class FastDelegate7 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate7 type; + + // Construction and comparison functions + FastDelegate7() { Clear(); } + FastDelegate7(const FastDelegate7 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate7 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate7 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate7 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate7 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate7 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate7(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate7(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) + { + m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7); + } +}; + +//N=8 +template +class FastDelegate8 +{ +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); + typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); + typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegate8 type; + + // Construction and comparison functions + FastDelegate8() { Clear(); } + FastDelegate8(const FastDelegate8 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + void operator = (const FastDelegate8 &x) + { + m_Closure.CopyFrom(this, x.m_Closure); + } + bool operator ==(const FastDelegate8 &x) const + { + return m_Closure.IsEqual(x.m_Closure); + } + bool operator !=(const FastDelegate8 &x) const + { + return !m_Closure.IsEqual(x.m_Closure); + } + bool operator <(const FastDelegate8 &x) const + { + return m_Closure.IsLess(x.m_Closure); + } + bool operator >(const FastDelegate8 &x) const + { + return x.m_Closure.IsLess(m_Closure); + } + // Binding to non-const member functions + template < class X, class Y > + FastDelegate8(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) + { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Binding to const member functions. + template < class X, class Y > + FastDelegate8(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + template < class X, class Y > + inline void Bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) + { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); + } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) + { + Bind(function_to_bind); + } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) + { + Bind(function_to_bind); + } + inline void Bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) + { + m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction, + function_to_bind); + } + // Invoke the delegate + RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const + { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7, p8); + } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct + { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const + { + return IsEmpty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) + { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator!=(StaticFunctionPtr funcptr) + { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); + } + inline bool operator ! () const + { // Is it bound to anything? + return !m_Closure; + } + inline bool IsEmpty() const + { + return !m_Closure; + } + void Clear() { m_Closure.Clear();} + // Conversion to and from the CUtlAbstractDelegate storage class + const CUtlAbstractDelegate & GetAbstractDelegate() { return m_Closure; } + void SetAbstractDelegate(const CUtlAbstractDelegate &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const + { + return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8); + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 4: +// +// CUtlDelegate<> class (Original author: Jody Hagins) +// Allows boost::function style syntax like: +// CUtlDelegate< double (int, long) > +// instead of: +// FastDelegate2< int, long, double > +// +//////////////////////////////////////////////////////////////////////////////// + +#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX + +// Declare CUtlDelegate as a class template. It will be specialized +// later for all number of arguments. +template +class CUtlDelegate; + +//N=0 +// Specialization to allow use of +// CUtlDelegate< R ( ) > +// instead of +// FastDelegate0 < R > +template +class CUtlDelegate< R ( ) > + // Inherit from FastDelegate0 so that it can be treated just like a FastDelegate0 + : public FastDelegate0 < R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate0 < R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=1 +// Specialization to allow use of +// CUtlDelegate< R ( Param1 ) > +// instead of +// FastDelegate1 < Param1, R > +template +class CUtlDelegate< R ( Param1 ) > + // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1 + : public FastDelegate1 < Param1, R > +{ + public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate1 < Param1, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=2 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2 ) > +// instead of +// FastDelegate2 < Param1, Param2, R > +template +class CUtlDelegate< R ( Param1, Param2 ) > + // Inherit from FastDelegate2 so that it can be treated just like a FastDelegate2 + : public FastDelegate2 < Param1, Param2, R > +{ + public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate2 < Param1, Param2, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=3 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2, Param3 ) > +// instead of +// FastDelegate3 < Param1, Param2, Param3, R > +template +class CUtlDelegate< R ( Param1, Param2, Param3 ) > + // Inherit from FastDelegate3 so that it can be treated just like a FastDelegate3 + : public FastDelegate3 < Param1, Param2, Param3, R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate3 < Param1, Param2, Param3, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=4 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2, Param3, Param4 ) > +// instead of +// FastDelegate4 < Param1, Param2, Param3, Param4, R > +template +class CUtlDelegate< R ( Param1, Param2, Param3, Param4 ) > + // Inherit from FastDelegate4 so that it can be treated just like a FastDelegate4 + : public FastDelegate4 < Param1, Param2, Param3, Param4, R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate4 < Param1, Param2, Param3, Param4, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=5 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) > +// instead of +// FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > +template +class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) > + // Inherit from FastDelegate5 so that it can be treated just like a FastDelegate5 + : public FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=6 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) > +// instead of +// FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > +template +class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) > + // Inherit from FastDelegate6 so that it can be treated just like a FastDelegate6 + : public FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=7 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > +// instead of +// FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > +template +class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > + // Inherit from FastDelegate7 so that it can be treated just like a FastDelegate7 + : public FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + +//N=8 +// Specialization to allow use of +// CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > +// instead of +// FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > +template +class CUtlDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > + // Inherit from FastDelegate8 so that it can be treated just like a FastDelegate8 + : public FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > BaseType; + + // Allow users access to the specific type of this delegate. + typedef CUtlDelegate SelfType; + + // Mimic the base class constructors. + CUtlDelegate() : BaseType() { } + + template < class X, class Y > + CUtlDelegate(Y * pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 )) + : BaseType(pthis, function_to_bind) + { } + + template < class X, class Y > + CUtlDelegate(const Y *pthis, R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const) + : BaseType(pthis, function_to_bind) + { } + + CUtlDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 )) + : BaseType(function_to_bind) + { } + + void operator = (const BaseType &x) + { + *static_cast(this) = x; + } +}; + + +#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 5: +// +// UtlMakeDelegate() helper function +// +// UtlMakeDelegate(&x, &X::func) returns a fastdelegate of the type +// necessary for calling x.func() with the correct number of arguments. +// This makes it possible to eliminate many typedefs from user code. +// +//////////////////////////////////////////////////////////////////////////////// + +// Also declare overloads of a UtlMakeDelegate() global function to +// reduce the need for typedefs. +// We need seperate overloads for const and non-const member functions. +// Also, because of the weird rule about the class of derived member function pointers, +// implicit downcasts may need to be applied later to the 'this' pointer. +// That's why two classes (X and Y) appear in the definitions. Y must be implicitly +// castable to X. + +// Workaround for VC6. VC6 needs void return types converted into DefaultVoid. +// GCC 3.2 and later won't compile this unless it's preceded by 'typename', +// but VC6 doesn't allow 'typename' in this context. +// So, I have to use a macro. + +#ifdef FASTDLGT_VC6 +#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid::type +#else +#define FASTDLGT_RETTYPE RetType +#endif + + +//N=0 +template +CUtlDelegate< FASTDLGT_RETTYPE ( ) > UtlMakeDelegate(Y* x, RetType (X::*func)()) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( ) > UtlMakeDelegate(Y* x, RetType (X::*func)() const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( ) >(x, func); +} + +template < class RetType > +CUtlDelegate< FASTDLGT_RETTYPE ( ) > UtlMakeDelegate( RetType (*func)()) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( ) >( func ); +} + +//N=1 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) >(x, func); +} + +template < class Param1, class RetType > +CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) > UtlMakeDelegate( RetType (*func)(Param1 p1)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1 ) >( func ); +} + + +//N=2 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) > UtlMakeDelegate( RetType (*func)(Param1 p1, Param2 p2)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2 ) >(func); +} + +//N=3 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) > UtlMakeDelegate( RetType (*func)(Param1 p1, Param2 p2, Param3 p3)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3 ) >(func); +} + +//N=4 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4 ) >(func); +} + +//N=5 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5 ) >(func); +} + +//N=6 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6 ) >(func); +} + +//N=7 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >(func); +} + +//N=8 +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > UtlMakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >(x, func); +} + +template +CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > UtlMakeDelegate(RetType (*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) +{ + return CUtlDelegate< FASTDLGT_RETTYPE ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >(func); +} + + +// clean up after ourselves... +#undef FASTDLGT_RETTYPE + +#endif // !defined(UTLDELEGATEIMPL_H) + diff --git a/public/tier1/utldict.h b/public/tier1/utldict.h new file mode 100644 index 0000000..cb0455a --- /dev/null +++ b/public/tier1/utldict.h @@ -0,0 +1,358 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A dictionary mapping from symbol to structure +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLDICT_H +#define UTLDICT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier1/utlmap.h" + +// Include this because tons of code was implicitly getting utlsymbol or utlvector via utldict.h +#include "tier1/utlsymbol.h" + +#include "tier0/memdbgon.h" + +enum EDictCompareType +{ + k_eDictCompareTypeCaseSensitive=0, + k_eDictCompareTypeCaseInsensitive=1, + k_eDictCompareTypeFilenames // Slashes and backslashes count as the same character.. +}; + +//----------------------------------------------------------------------------- +// A dictionary mapping from symbol to structure +//----------------------------------------------------------------------------- +#define FOR_EACH_DICT( dictName, iteratorName ) \ + for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) ) + +// faster iteration, but in an unspecified order +#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else + +//----------------------------------------------------------------------------- +// A dictionary mapping from symbol to structure +//----------------------------------------------------------------------------- +template +class CUtlDict +{ +public: + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + CUtlDict( int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0 ); + ~CUtlDict( ); + + void EnsureCapacity( int ); + + // gets particular elements + T& Element( I i ); + const T& Element( I i ) const; + T& operator[]( I i ); + const T& operator[]( I i ) const; + + // gets element names + char *GetElementName( I i ); + char const *GetElementName( I i ) const; + + void SetElementName( I i, char const *pName ); + + // Number of elements + unsigned int Count() const; + + // Number of allocated slots + I MaxElement() const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( I i ) const; + + // Invalid index + static I InvalidIndex(); + + // Insert method (inserts in order) + I Insert( const char *pName, const T &element ); + I Insert( const char *pName ); + + // Find method + I Find( const char *pName ) const; + bool HasElement( const char *pName ) const; + + // Remove methods + void RemoveAt( I i ); + void Remove( const char *pName ); + void RemoveAll( ); + + // Purge memory + void Purge(); + void PurgeAndDeleteElements(); // Call delete on each element. + + // Iteration methods + I First() const; + I Next( I i ) const; + + // Nested typedefs, for code that might need + // to fish out the index type from a given dict + typedef I IndexType_t; + +protected: + typedef CUtlMap DictElementMap_t; + DictElementMap_t m_Elements; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template +CUtlDict::CUtlDict( int compareType, int growSize, int initSize ) : m_Elements( growSize, initSize ) +{ + if ( compareType == k_eDictCompareTypeFilenames ) + { + m_Elements.SetLessFunc( CaselessStringLessThanIgnoreSlashes ); + } + else if ( compareType == k_eDictCompareTypeCaseInsensitive ) + { + m_Elements.SetLessFunc( CaselessStringLessThan ); + } + else + { + m_Elements.SetLessFunc( StringLessThan ); + } +} + +template +CUtlDict::~CUtlDict() +{ + Purge(); +} + +template +inline void CUtlDict::EnsureCapacity( int num ) +{ + return m_Elements.EnsureCapacity( num ); +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- +template +inline T& CUtlDict::Element( I i ) +{ + return m_Elements[i]; +} + +template +inline const T& CUtlDict::Element( I i ) const +{ + return m_Elements[i]; +} + +//----------------------------------------------------------------------------- +// gets element names +//----------------------------------------------------------------------------- +template +inline char *CUtlDict::GetElementName( I i ) +{ + return (char *)m_Elements.Key( i ); +} + +template +inline char const *CUtlDict::GetElementName( I i ) const +{ + return m_Elements.Key( i ); +} + +template +inline T& CUtlDict::operator[]( I i ) +{ + return Element(i); +} + +template +inline const T & CUtlDict::operator[]( I i ) const +{ + return Element(i); +} + +template +inline void CUtlDict::SetElementName( I i, char const *pName ) +{ + MEM_ALLOC_CREDIT_CLASS(); + // TODO: This makes a copy of the old element + // TODO: This relies on the rb tree putting the most recently + // removed element at the head of the insert list + free( (void *)m_Elements.Key( i ) ); + m_Elements.Reinsert( strdup( pName ), i ); +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- +template +inline unsigned int CUtlDict::Count() const +{ + return m_Elements.Count(); +} + +//----------------------------------------------------------------------------- +// Number of allocated slots +//----------------------------------------------------------------------------- +template +inline I CUtlDict::MaxElement() const +{ + return m_Elements.MaxElement(); +} + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- +template +inline bool CUtlDict::IsValidIndex( I i ) const +{ + return m_Elements.IsValidIndex(i); +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- +template +inline I CUtlDict::InvalidIndex() +{ + return DictElementMap_t::InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- +template +void CUtlDict::RemoveAt(I elem) +{ + free( (void *)m_Elements.Key( elem ) ); + m_Elements.RemoveAt(elem); +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- +template void CUtlDict::Remove( const char *search ) +{ + I node = Find( search ); + if (node != InvalidIndex()) + { + RemoveAt(node); + } +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- +template +void CUtlDict::RemoveAll() +{ + typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder(); + while ( index != m_Elements.InvalidIndex() ) + { + free( (void *)m_Elements.Key( index ) ); + index = m_Elements.NextInorder( index ); + } + + m_Elements.RemoveAll(); +} + +template +void CUtlDict::Purge() +{ + RemoveAll(); +} + + +template +void CUtlDict::PurgeAndDeleteElements() +{ + // Delete all the elements. + I index = m_Elements.FirstInorder(); + while ( index != m_Elements.InvalidIndex() ) + { + free( (void *)m_Elements.Key( index ) ); + delete m_Elements[index]; + index = m_Elements.NextInorder( index ); + } + + m_Elements.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- +template +I CUtlDict::Insert( const char *pName, const T &element ) +{ + MEM_ALLOC_CREDIT_CLASS(); + return m_Elements.Insert( strdup( pName ), element ); +} + +template +I CUtlDict::Insert( const char *pName ) +{ + MEM_ALLOC_CREDIT_CLASS(); + return m_Elements.Insert( strdup( pName ) ); +} + + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- +template +I CUtlDict::Find( const char *pName ) const +{ + MEM_ALLOC_CREDIT_CLASS(); + if ( pName ) + return m_Elements.Find( pName ); + else + return InvalidIndex(); +} + +//----------------------------------------------------------------------------- +// returns true if we already have this node +//----------------------------------------------------------------------------- +template +bool CUtlDict::HasElement( const char *pName ) const +{ + if ( pName ) + return m_Elements.IsValidIndex( m_Elements.Find( pName ) ); + else + return false; +} + + +//----------------------------------------------------------------------------- +// Iteration methods +//----------------------------------------------------------------------------- +template +I CUtlDict::First() const +{ + return m_Elements.FirstInorder(); +} + +template +I CUtlDict::Next( I i ) const +{ + return m_Elements.NextInorder(i); +} + +#include "tier0/memdbgoff.h" + +#endif // UTLDICT_H diff --git a/public/tier1/utlenvelope.h b/public/tier1/utlenvelope.h new file mode 100644 index 0000000..3de254a --- /dev/null +++ b/public/tier1/utlenvelope.h @@ -0,0 +1,241 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A class to wrap data for transport over a boundary like a thread +// or window. +// +//============================================================================= + +#include "tier1/utlstring.h" +#include "tier0/basetypes.h" + +#ifndef UTLENVELOPE_H +#define UTLENVELOPE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +class CUtlDataEnvelope +{ +public: + CUtlDataEnvelope( const void *pData, int nBytes ); + CUtlDataEnvelope( const CUtlDataEnvelope &from ); + ~CUtlDataEnvelope(); + + CUtlDataEnvelope &operator=( const CUtlDataEnvelope &from ); + + operator void *(); + operator void *() const; + +private: + void Assign( const void *pData, int nBytes ); + void Assign( const CUtlDataEnvelope &from ); + void Purge(); + + // TODO: switch to a reference counted array? + union + { + byte *m_pData; + byte m_data[4]; + }; + int m_nBytes; +}; + + +//----------------------------------------------------------------------------- + +template +class CUtlEnvelope : protected CUtlDataEnvelope +{ +public: + CUtlEnvelope( const T *pData, int nElems = 1 ); + CUtlEnvelope( const CUtlEnvelope &from ); + + CUtlEnvelope &operator=( const CUtlEnvelope &from ); + + operator T *(); + operator T *() const; + + operator void *(); + operator void *() const; +}; + +//----------------------------------------------------------------------------- + +template <> +class CUtlEnvelope +{ +public: + CUtlEnvelope( const char *pData ) + { + m_string = pData; + } + + CUtlEnvelope( const CUtlEnvelope &from ) + { + m_string = from.m_string; + } + + CUtlEnvelope &operator=( const CUtlEnvelope &from ) + { + m_string = from.m_string; + return *this; + } + + operator char *() + { + return (char *) m_string.Get(); + } + + operator char *() const + { + return (char *) m_string.Get(); + } + + operator void *() + { + return (void *) m_string.Get(); + } + + operator void *() const + { + return (void *) m_string.Get(); + } + +private: + CUtlString m_string; +}; + +//----------------------------------------------------------------------------- + +#include "tier0/memdbgon.h" + +inline void CUtlDataEnvelope::Assign( const void *pData, int nBytes ) +{ + if ( pData ) + { + m_nBytes = nBytes; + if ( m_nBytes > 4 ) + { + m_pData = new byte[nBytes]; + memcpy( m_pData, pData, nBytes ); + } + else + { + memcpy( m_data, pData, nBytes ); + } + } + else + { + m_pData = NULL; + m_nBytes = 0; + } +} + +inline void CUtlDataEnvelope::Assign( const CUtlDataEnvelope &from ) +{ + Assign( from.operator void *(), from.m_nBytes ); +} + +inline void CUtlDataEnvelope::Purge() +{ + if (m_nBytes > 4) + delete [] m_pData; + m_nBytes = 0; +} + +inline CUtlDataEnvelope::CUtlDataEnvelope( const void *pData, int nBytes ) +{ + Assign( pData, nBytes ); +} + +inline CUtlDataEnvelope::CUtlDataEnvelope( const CUtlDataEnvelope &from ) +{ + Assign( from ); +} + +inline CUtlDataEnvelope::~CUtlDataEnvelope() +{ + Purge(); +} + +inline CUtlDataEnvelope &CUtlDataEnvelope::operator=( const CUtlDataEnvelope &from ) +{ + Purge(); + Assign( from ); + return *this; +} + +inline CUtlDataEnvelope::operator void *() +{ + if ( !m_nBytes ) + { + return NULL; + } + + return ( m_nBytes > 4) ? m_pData : m_data; +} + +inline CUtlDataEnvelope::operator void *() const +{ + if ( !m_nBytes ) + { + return NULL; + } + + return ( m_nBytes > 4) ? (void *)m_pData : (void *)m_data; +} + +//----------------------------------------------------------------------------- + +template +inline CUtlEnvelope::CUtlEnvelope( const T *pData, int nElems ) + : CUtlDataEnvelope( pData, sizeof(T) * nElems ) +{ +} + +template +inline CUtlEnvelope::CUtlEnvelope( const CUtlEnvelope &from ) + : CUtlDataEnvelope( from ) +{ + +} + +template +inline CUtlEnvelope &CUtlEnvelope::operator=( const CUtlEnvelope &from ) +{ + CUtlDataEnvelope::operator=( from ); + return *this; +} + +template +inline CUtlEnvelope::operator T *() +{ + return (T *)CUtlDataEnvelope::operator void *(); +} + +template +inline CUtlEnvelope::operator T *() const +{ + return (T *)( (const_cast *>(this))->operator T *() ); +} + +template +inline CUtlEnvelope::operator void *() +{ + return CUtlDataEnvelope::operator void *(); +} + +template +inline CUtlEnvelope::operator void *() const +{ + return ( (const_cast *>(this))->operator void *() ); +} + +//----------------------------------------------------------------------------- + +#include "tier0/memdbgoff.h" + +#endif // UTLENVELOPE_H diff --git a/public/tier1/utlfixedmemory.h b/public/tier1/utlfixedmemory.h new file mode 100644 index 0000000..6ff8c19 --- /dev/null +++ b/public/tier1/utlfixedmemory.h @@ -0,0 +1,354 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLFIXEDMEMORY_H +#define UTLFIXEDMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" + +#include "tier0/memalloc.h" +#include "tier0/memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +//----------------------------------------------------------------------------- + +#ifdef UTLFIXEDMEMORY_TRACK +#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0) +#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlFixedMemory class: +// A growable memory class that allocates non-sequential blocks, but is indexed sequentially +//----------------------------------------------------------------------------- +template< class T > +class CUtlFixedMemory +{ +public: + // constructor, destructor + CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 ); + ~CUtlFixedMemory(); + + // Set the size by which the memory grows + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL + T* Base() { return NULL; } + const T* Base() const { return NULL; } + +protected: + struct BlockHeader_t; + +public: + class Iterator_t + { + public: + Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {} + BlockHeader_t *m_pBlockHeader; + intp m_nIndex; + + bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; } + bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; } + }; + Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); } + Iterator_t Next( const Iterator_t &it ) const + { + Assert( IsValidIterator( it ) ); + if ( !IsValidIterator( it ) ) + return InvalidIterator(); + + BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader; + if ( it.m_nIndex + 1 < pHeader->m_nBlockSize ) + return Iterator_t( pHeader, it.m_nIndex + 1 ); + + return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator(); + } + intp GetIndex( const Iterator_t &it ) const + { + Assert( IsValidIterator( it ) ); + if ( !IsValidIterator( it ) ) + return InvalidIndex(); + + return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex ); + } + bool IsIdxAfter( intp i, const Iterator_t &it ) const + { + Assert( IsValidIterator( it ) ); + if ( !IsValidIterator( it ) ) + return false; + + if ( IsInBlock( i, it.m_pBlockHeader ) ) + return i > GetIndex( it ); + + for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext ) + { + if ( IsInBlock( i, pbh ) ) + return true; + } + return false; + } + bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; } + Iterator_t InvalidIterator() const { return Iterator_t( NULL, INVALID_INDEX ); } + + // element access + T& operator[]( intp i ); + const T& operator[]( intp i ) const; + T& Element( intp i ); + const T& Element( intp i ) const; + + // Can we use this index? + bool IsIdxValid( intp i ) const; + + // Specify the invalid ('null') index that we'll only return on failure + static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT + static intp InvalidIndex() { return INVALID_INDEX; } + + // Size + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + // Grows memory by max(num,growsize), and returns the allocation index/ptr + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + +protected: + // Fast swap - WARNING: Swap invalidates all ptr-based indices!!! + void Swap( CUtlFixedMemory< T > &mem ); + + bool IsInBlock( intp i, BlockHeader_t *pBlockHeader ) const + { + T *p = ( T* )i; + const T *p0 = HeaderToBlock( pBlockHeader ); + return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize; + } + + struct BlockHeader_t + { + BlockHeader_t *m_pNext; + intp m_nBlockSize; + }; + + const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); } + const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; } + + BlockHeader_t* m_pBlocks; + int m_nAllocationCount; + int m_nGrowSize; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T > +CUtlFixedMemory::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount ) +: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 ) +{ + Init( nGrowSize, nInitAllocationCount ); +} + +template< class T > +CUtlFixedMemory::~CUtlFixedMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Fast swap - WARNING: Swap invalidates all ptr-based indices!!! +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory::Swap( CUtlFixedMemory< T > &mem ) +{ + V_swap( m_pBlocks, mem.m_pBlocks ); + V_swap( m_nAllocationCount, mem.m_nAllocationCount ); + V_swap( m_nGrowSize, mem.m_nGrowSize ); +} + + +//----------------------------------------------------------------------------- +// Set the size by which the memory grows - round up to the next power of 2 +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + + Grow( nInitSize ); +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T > +inline T& CUtlFixedMemory::operator[]( intp i ) +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + +template< class T > +inline const T& CUtlFixedMemory::operator[]( intp i ) const +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + +template< class T > +inline T& CUtlFixedMemory::Element( intp i ) +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + +template< class T > +inline const T& CUtlFixedMemory::Element( intp i ) const +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlFixedMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T > +inline bool CUtlFixedMemory::IsIdxValid( intp i ) const +{ +#ifdef _DEBUG + for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext ) + { + if ( IsInBlock( i, pbh ) ) + return true; + } + return false; +#else + return i != InvalidIndex(); +#endif +} + +template< class T > +void CUtlFixedMemory::Grow( int num ) +{ + if ( num <= 0 ) + return; + + int nBlockSize = m_nGrowSize; + if ( nBlockSize == 0 ) + { + if ( m_nAllocationCount ) + { + nBlockSize = m_nAllocationCount; + } + else + { + // Compute an allocation which is at least as big as a cache line... + nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T ); + Assert( nBlockSize ); + } + } + if ( nBlockSize < num ) + { + int n = ( num + nBlockSize -1 ) / nBlockSize; + Assert( n * nBlockSize >= num ); + Assert( ( n - 1 ) * nBlockSize < num ); + nBlockSize *= n; + } + m_nAllocationCount += nBlockSize; + + MEM_ALLOC_CREDIT_CLASS(); + BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) ); + if ( !pBlockHeader ) + { + Error( "CUtlFixedMemory overflow!\n" ); + } + pBlockHeader->m_pNext = NULL; + pBlockHeader->m_nBlockSize = nBlockSize; + + if ( !m_pBlocks ) + { + m_pBlocks = pBlockHeader; + } + else + { +#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end + BlockHeader_t * RESTRICT pbh = m_pBlocks; + while ( pbh->m_pNext ) + { + pbh = pbh->m_pNext; + } + pbh->m_pNext = pBlockHeader; +#else + pBlockHeader = m_pBlocks; + pBlockHeader->m_pNext = m_pBlocks; +#endif + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T > +inline void CUtlFixedMemory::EnsureCapacity( int num ) +{ + Grow( num - NumAllocated() ); +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory::Purge() +{ + if ( !m_pBlocks ) + return; + + for ( BlockHeader_t *pbh = m_pBlocks; pbh; ) + { + BlockHeader_t *pFree = pbh; + pbh = pbh->m_pNext; + free( pFree ); + } + m_pBlocks = NULL; + m_nAllocationCount = 0; +} + +#include "tier0/memdbgoff.h" + +#endif // UTLFIXEDMEMORY_H diff --git a/public/tier1/utlflags.h b/public/tier1/utlflags.h new file mode 100644 index 0000000..e225b43 --- /dev/null +++ b/public/tier1/utlflags.h @@ -0,0 +1,124 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Simple class to make it easier to deal with flags +// +//============================================================================= + +#ifndef UTLFLAGS_H +#define UTLFLAGS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" + + +//----------------------------------------------------------------------------- +// Simple class to make it easier to deal with flags +//----------------------------------------------------------------------------- +template< class T > +class CUtlFlags +{ +public: + CUtlFlags( int nInitialFlags = 0 ); + + // Flag setting + void SetFlag( int nFlagMask ); + void SetFlag( int nFlagMask, bool bEnable ); + + // Flag clearing + void ClearFlag( int nFlagMask ); + void ClearAllFlags(); + bool IsFlagSet( int nFlagMask ) const; + + // Is any flag set? + bool IsAnyFlagSet() const; + +private: + T m_nFlags; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +template< class T > +CUtlFlags::CUtlFlags( int nInitialFlags ) +{ + // Makes sure we didn't truncate + Assert( nInitialFlags == (T)nInitialFlags ); + + m_nFlags = (T)nInitialFlags; +} + + +//----------------------------------------------------------------------------- +// Set flags +//----------------------------------------------------------------------------- +template< class T > +void CUtlFlags::SetFlag( int nFlagMask ) +{ + // Makes sure we didn't truncate + Assert( nFlagMask == (T)nFlagMask ); + + m_nFlags |= (T)nFlagMask; +} + +template< class T > +void CUtlFlags::SetFlag( int nFlagMask, bool bEnable ) +{ + // Makes sure we didn't truncate + Assert( nFlagMask == (T)nFlagMask ); + + if ( bEnable ) + { + m_nFlags |= (T)nFlagMask; + } + else + { + m_nFlags &= ~((T)nFlagMask); + } +} + + +//----------------------------------------------------------------------------- +// Clear flags +//----------------------------------------------------------------------------- +template< class T > +void CUtlFlags::ClearFlag( int nFlagMask ) +{ + // Makes sure we didn't truncate + Assert( nFlagMask == (T)nFlagMask ); + m_nFlags &= ~((T)nFlagMask); +} + +template< class T > +void CUtlFlags::ClearAllFlags() +{ + m_nFlags = 0; +} + + +//----------------------------------------------------------------------------- +// Is a flag set? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlFlags::IsFlagSet( int nFlagMask ) const +{ + // Makes sure we didn't truncate + Assert( nFlagMask == (T)nFlagMask ); + return ( m_nFlags & nFlagMask ) != 0; +} + + +//----------------------------------------------------------------------------- +// Is any flag set? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlFlags::IsAnyFlagSet() const +{ + return m_nFlags != 0; +} + + +#endif // UTLFLAGS_H diff --git a/public/tier1/utlhandletable.h b/public/tier1/utlhandletable.h new file mode 100644 index 0000000..22f5435 --- /dev/null +++ b/public/tier1/utlhandletable.h @@ -0,0 +1,586 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef UTLHANDLETABLE_H +#define UTLHANDLETABLE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/utlvector.h" +#include "tier1/utlqueue.h" + + +//----------------------------------------------------------------------------- +// Handles are 32 bits. Invalid handles are all 1s +//----------------------------------------------------------------------------- +typedef unsigned int UtlHandle_t; +#define UTLHANDLE_INVALID ((UtlHandle_t)~0) + + +//----------------------------------------------------------------------------- +// Purpose: This is a table used to allocate handles +// HandleBits specifies the max # of simultaneously allocated handles. +// An extra bit is used for the validity state +// The rest of the 32 bits are used for a serial number +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +class CUtlHandleTable +{ +public: + CUtlHandleTable(); + + // Allocate, deallocate handles + UtlHandle_t AddHandle(); + void RemoveHandle( UtlHandle_t h ); + + // Set/get handle values + void SetHandle( UtlHandle_t h, T *pData ); + T *GetHandle( UtlHandle_t h ) const; + T *GetHandle( UtlHandle_t h, bool checkValidity ) const; + + // Is a handle valid? + bool IsHandleValid( UtlHandle_t h ) const; + + // Iterate over handles; they may not be valid + unsigned int GetValidHandleCount() const; + unsigned int GetHandleCount() const; + UtlHandle_t GetHandleFromIndex( int i ) const; + int GetIndexFromHandle( UtlHandle_t h ) const; + + void MarkHandleInvalid( UtlHandle_t h ); + void MarkHandleValid( UtlHandle_t h ); + +private: + struct HandleType_t + { + HandleType_t( unsigned int i, unsigned int s ) : nIndex( i ), nSerial( s ) + { + Assert( i < ( 1 << HandleBits ) ); + Assert( s < ( 1 << ( 31 - HandleBits ) ) ); + } + unsigned int nIndex : HandleBits; + unsigned int nSerial : 31 - HandleBits; + }; + + struct EntryType_t + { + EntryType_t() : m_nSerial( 0 ), nInvalid( 0 ), m_pData( 0 ) {} + unsigned int m_nSerial : 31; + unsigned int nInvalid : 1; + T *m_pData; + }; + + static unsigned int GetSerialNumber( UtlHandle_t handle ); + static unsigned int GetListIndex( UtlHandle_t handle ); + static UtlHandle_t CreateHandle( unsigned int nSerial, unsigned int nIndex ); + const EntryType_t *GetEntry( UtlHandle_t handle, bool checkValidity ) const; + + unsigned int m_nValidHandles; + CUtlVector< EntryType_t > m_list; + CUtlQueue< int > m_unused; +}; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +CUtlHandleTable::CUtlHandleTable() : m_nValidHandles( 0 ) +{ +} + + +//----------------------------------------------------------------------------- +// Allocate, deallocate handles +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable::AddHandle() +{ + unsigned int nIndex = ( m_unused.Count() > 0 ) ? m_unused.RemoveAtHead() : m_list.AddToTail(); + + EntryType_t &entry = m_list[ nIndex ]; + entry.nInvalid = 0; + entry.m_pData = NULL; + + ++m_nValidHandles; + + return CreateHandle( entry.m_nSerial, nIndex ); +} + +template< class T, int HandleBits > +void CUtlHandleTable::RemoveHandle( UtlHandle_t handle ) +{ + unsigned int nIndex = GetListIndex( handle ); + Assert( nIndex < ( unsigned int )m_list.Count() ); + if ( nIndex >= ( unsigned int )m_list.Count() ) + return; + + EntryType_t &entry = m_list[ nIndex ]; + ++entry.m_nSerial; // mark old serial# invalid + if ( !entry.nInvalid ) + { + entry.nInvalid = 1; + --m_nValidHandles; + } + entry.m_pData = NULL; + + + // If a handle has been used this many times, then we need to take it out of service, otherwise if the + // serial # wraps around we'll possibly revalidate old handles and they'll start to point at the wrong objects. Unlikely, but possible. + bool bStopUsing = ( entry.m_nSerial >= ( (1 << ( 31 - HandleBits ) ) - 1 ) ); + if ( !bStopUsing ) + { + m_unused.Insert( nIndex ); + } +} + + +//----------------------------------------------------------------------------- +// Set/get handle values +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +void CUtlHandleTable::SetHandle( UtlHandle_t handle, T *pData ) +{ + EntryType_t *entry = const_cast< EntryType_t* >( GetEntry( handle, false ) ); + Assert( entry ); + if ( entry == NULL ) + return; + + // Validate the handle + if ( entry->nInvalid ) + { + ++m_nValidHandles; + entry->nInvalid = 0; + } + entry->m_pData = pData; +} + +template< class T, int HandleBits > +T *CUtlHandleTable::GetHandle( UtlHandle_t handle ) const +{ + const EntryType_t *entry = GetEntry( handle, true ); + return entry ? entry->m_pData : NULL; +} + +template< class T, int HandleBits > +T *CUtlHandleTable::GetHandle( UtlHandle_t handle, bool checkValidity ) const +{ + const EntryType_t *entry = GetEntry( handle, checkValidity ); + return entry ? entry->m_pData : NULL; +} + + +//----------------------------------------------------------------------------- +// Is a handle valid? +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +bool CUtlHandleTable::IsHandleValid( UtlHandle_t handle ) const +{ + if ( handle == UTLHANDLE_INVALID ) + return false; + + unsigned int nIndex = GetListIndex( handle ); + AssertOnce( nIndex < ( unsigned int )m_list.Count() ); + if ( nIndex >= ( unsigned int )m_list.Count() ) + return false; + + const EntryType_t &entry = m_list[ nIndex ]; + if ( entry.m_nSerial != GetSerialNumber( handle ) ) + return false; + + if ( 1 == entry.nInvalid ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Current max handle +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetValidHandleCount() const +{ + return m_nValidHandles; +} + +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetHandleCount() const +{ + return m_list.Count(); +} + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable::GetHandleFromIndex( int i ) const +{ + if ( m_list[i].m_pData ) + return CreateHandle( m_list[i].m_nSerial, i ); + return UTLHANDLE_INVALID; +} + +template< class T, int HandleBits > +int CUtlHandleTable::GetIndexFromHandle( UtlHandle_t h ) const +{ + if ( h == UTLHANDLE_INVALID ) + return -1; + + return GetListIndex( h ); +} + + + +//----------------------------------------------------------------------------- +// Cracking handles into indices + serial numbers +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetSerialNumber( UtlHandle_t handle ) +{ + return ( ( HandleType_t* )&handle )->nSerial; +} + +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetListIndex( UtlHandle_t handle ) +{ + return ( ( HandleType_t* )&handle )->nIndex; +} + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable::CreateHandle( unsigned int nSerial, unsigned int nIndex ) +{ + HandleType_t h( nIndex, nSerial ); + return *( UtlHandle_t* )&h; +} + + +//----------------------------------------------------------------------------- +// Looks up a entry by handle +//----------------------------------------------------------------------------- +template< class T, int HandleBits > +const typename CUtlHandleTable::EntryType_t *CUtlHandleTable::GetEntry( UtlHandle_t handle, bool checkValidity ) const +{ + if ( handle == UTLHANDLE_INVALID ) + return NULL; + + unsigned int nIndex = GetListIndex( handle ); + Assert( nIndex < ( unsigned int )m_list.Count() ); + if ( nIndex >= ( unsigned int )m_list.Count() ) + return NULL; + + const EntryType_t &entry = m_list[ nIndex ]; + if ( entry.m_nSerial != GetSerialNumber( handle ) ) + return NULL; + + if ( checkValidity && + ( 1 == entry.nInvalid ) ) + return NULL; + + return &entry; +} + +template< class T, int HandleBits > +void CUtlHandleTable::MarkHandleInvalid( UtlHandle_t handle ) +{ + if ( handle == UTLHANDLE_INVALID ) + return; + + unsigned int nIndex = GetListIndex( handle ); + Assert( nIndex < ( unsigned int )m_list.Count() ); + if ( nIndex >= ( unsigned int )m_list.Count() ) + return; + + EntryType_t &entry = m_list[ nIndex ]; + if ( entry.m_nSerial != GetSerialNumber( handle ) ) + return; + + if ( !entry.nInvalid ) + { + --m_nValidHandles; + entry.nInvalid = 1; + } +} + +template< class T, int HandleBits > +void CUtlHandleTable::MarkHandleValid( UtlHandle_t handle ) +{ + if ( handle == UTLHANDLE_INVALID ) + return; + + unsigned int nIndex = GetListIndex( handle ); + Assert( nIndex < ( unsigned int )m_list.Count() ); + if ( nIndex >= ( unsigned int )m_list.Count() ) + return; + + EntryType_t &entry = m_list[ nIndex ]; + if ( entry.m_nSerial != GetSerialNumber( handle ) ) + return; + + if ( entry.nInvalid ) + { + ++m_nValidHandles; + entry.nInvalid = 0; + } +} + + +//----------------------------------------------------------------------------- +// Handle wrapper. Assumes 2 things +// 1) That class T has a non-static method called GetHandle which returns a UtlHandle_t +// 2) That class T has a static method called GetPtrFromHandle which returns a T* given a UtlHandle_t +// 3) That class T has a static method called IsHandleValid which accepts a UtlHandle_t +//----------------------------------------------------------------------------- +template< class T > +class CUtlHandle +{ +public: + // Constructors + CUtlHandle(); + explicit CUtlHandle( T *pObject ); + CUtlHandle( UtlHandle_t h ); + CUtlHandle( const CUtlHandle &h ); + + // Assignment + void Set( T *pObject ); + void Set( UtlHandle_t h ); + const CUtlHandle &operator=( UtlHandle_t h ); + const CUtlHandle &operator=( T *pObject ); + + // Retrieval + T *Get(); + const T* Get() const; + + // Is the handle valid? + bool IsValid() const; + + // Casting + operator T*(); + operator UtlHandle_t(); + operator bool(); + T* operator->(); + const T* operator->() const; + + // Equality + bool operator==( CUtlHandle h ) const; + bool operator==( T *pObject ) const; + bool operator==( UtlHandle_t h ) const; + bool operator!=( CUtlHandle h ) const; + bool operator!=( T *pObject ) const; + bool operator!=( UtlHandle_t h ) const; + +private: + UtlHandle_t m_handle; +}; + + +//----------------------------------------------------------------------------- +// Constructors +//----------------------------------------------------------------------------- +template< class T > +CUtlHandle::CUtlHandle() : m_handle( UTLHANDLE_INVALID ) +{ +} + +template< class T > +CUtlHandle::CUtlHandle( T *pObject ) +{ + Set( pObject ); +} + +template< class T > +CUtlHandle::CUtlHandle( UtlHandle_t h ) +{ + m_handle = h; +} + +template< class T > +CUtlHandle::CUtlHandle( const CUtlHandle &h ) +{ + m_handle = h.m_handle; +} + + +//----------------------------------------------------------------------------- +// Assignment +//----------------------------------------------------------------------------- +template< class T > +void CUtlHandle::Set( T *pObject ) +{ + // Assumes T has a member function GetHandle + m_handle = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; +} + +template< class T > +void CUtlHandle::Set( UtlHandle_t h ) +{ + m_handle = h; +} + +template< class T > +const CUtlHandle &CUtlHandle::operator=( UtlHandle_t h ) +{ + Set( h ); + return *this; +} + +template< class T > +const CUtlHandle &CUtlHandle::operator=( T *pObject ) +{ + Set( pObject ); + return *this; +} + + +//----------------------------------------------------------------------------- +// Is the handle valid? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlHandle::IsValid() const +{ + // Assumes T has a static member function IsHandleValid + return T::IsHandleValid( m_handle ); +} + + +//----------------------------------------------------------------------------- +// Retrieval +//----------------------------------------------------------------------------- +template< class T > +T *CUtlHandle::Get() +{ + // Assumes T has a static member function GetPtrFromHandle + return T::GetPtrFromHandle( m_handle ); +} + +template< class T > +const T* CUtlHandle::Get() const +{ + // Assumes T has a static member function GetPtrFromHandle + return T::GetPtrFromHandle( m_handle ); +} + + +//----------------------------------------------------------------------------- +// Casting +//----------------------------------------------------------------------------- +template< class T > +CUtlHandle::operator T*() +{ + return Get(); +} + +template< class T > +CUtlHandle::operator UtlHandle_t() +{ + return m_handle; +} + +template< class T > +T* CUtlHandle::operator->() +{ + return Get(); +} + +template< class T > +const T* CUtlHandle::operator->() const +{ + return Get(); +} + +template< class T > +CUtlHandle::operator bool() +{ + return m_handle != UTLHANDLE_INVALID; +} + + +//----------------------------------------------------------------------------- +// Equality +//----------------------------------------------------------------------------- +template< class T > +bool CUtlHandle::operator==( CUtlHandle h ) const +{ + return m_handle == h.m_handle; +} + +template< class T > +bool CUtlHandle::operator==( T *pObject ) const +{ + UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; + return m_handle == h; +} + +template< class T > +bool CUtlHandle::operator==( UtlHandle_t h ) const +{ + return m_handle == h; +} + +template< class T > +bool CUtlHandle::operator!=( CUtlHandle h ) const +{ + return m_handle != h.m_handle; +} + +template< class T > +bool CUtlHandle::operator!=( T *pObject ) const +{ + UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; + return m_handle != h; +} + +template< class T > +bool CUtlHandle::operator!=( UtlHandle_t h ) const +{ + return m_handle != h; +} + + +//----------------------------------------------------------------------------- +// Add this macro to a class definition to hook in handles for it! +//----------------------------------------------------------------------------- +#define DECLARE_HANDLES( _className, _handleBitCount ) \ + public: \ + UtlHandle_t GetHandle() \ + { \ + return m_Handle; \ + } \ + static _className* GetPtrFromHandle( UtlHandle_t h ) \ + { \ + return m_HandleTable.GetHandle( h ); \ + } \ + static bool IsHandleValid( UtlHandle_t h ) \ + { \ + return m_HandleTable.IsHandleValid( h ); \ + } \ + private: \ + UtlHandle_t m_Handle; \ + static CUtlHandleTable< _className, _handleBitCount > m_HandleTable + + +//----------------------------------------------------------------------------- +// Add this macro to a .cpp file to hook in handles for it! +//----------------------------------------------------------------------------- +#define IMPLEMENT_HANDLES( _className, _handleBitCount ) \ + CUtlHandleTable< _className, _handleBitCount > _className::m_HandleTable; + + +//----------------------------------------------------------------------------- +// Add these macro to the class constructor + destructor +//----------------------------------------------------------------------------- +#define CONSTRUCT_HANDLE( ) \ + m_Handle = m_HandleTable.AddHandle(); \ + m_HandleTable.SetHandle( m_Handle, this ) + +#define DESTRUCT_HANDLE() \ + m_HandleTable.RemoveHandle( m_Handle ); \ + m_Handle = UTLHANDLE_INVALID + + + +#endif // UTLHANDLETABLE_H + diff --git a/public/tier1/utlhash.h b/public/tier1/utlhash.h new file mode 100644 index 0000000..7207b59 --- /dev/null +++ b/public/tier1/utlhash.h @@ -0,0 +1,936 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//=============================================================================// + +#ifndef UTLHASH_H +#define UTLHASH_H +#pragma once + +#include +#include +#include "utlmemory.h" +#include "utlvector.h" +#include "utllinkedlist.h" +#include "utllinkedlist.h" +#include "commonmacros.h" +#include "generichash.h" + +typedef unsigned int UtlHashHandle_t; + +template +class CUtlHash +{ +public: + // compare and key functions - implemented by the + typedef C CompareFunc_t; + typedef K KeyFunc_t; + + // constructor/deconstructor + CUtlHash( int bucketCount = 0, int growCount = 0, int initCount = 0, + CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0 ); + ~CUtlHash(); + + // invalid handle + static UtlHashHandle_t InvalidHandle( void ) { return ( UtlHashHandle_t )~0; } + bool IsValidHandle( UtlHashHandle_t handle ) const; + + // size + int Count( void ) const; + + // memory + void Purge( void ); + + // insertion methods + UtlHashHandle_t Insert( Data const &src ); + UtlHashHandle_t Insert( Data const &src, bool *pDidInsert ); + UtlHashHandle_t AllocEntryFromKey( Data const &src ); + + // removal methods + void Remove( UtlHashHandle_t handle ); + void RemoveAll(); + + // retrieval methods + UtlHashHandle_t Find( Data const &src ) const; + + Data &Element( UtlHashHandle_t handle ); + Data const &Element( UtlHashHandle_t handle ) const; + Data &operator[]( UtlHashHandle_t handle ); + Data const &operator[]( UtlHashHandle_t handle ) const; + + UtlHashHandle_t GetFirstHandle() const; + UtlHashHandle_t GetNextHandle( UtlHashHandle_t h ) const; + + // debugging!! + void Log( const char *filename ); + +protected: + + int GetBucketIndex( UtlHashHandle_t handle ) const; + int GetKeyDataIndex( UtlHashHandle_t handle ) const; + UtlHashHandle_t BuildHandle( int ndxBucket, int ndxKeyData ) const; + + bool DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const; + +protected: + + // handle upper 16 bits = bucket index (bucket heads) + // handle lower 16 bits = key index (bucket list) + typedef CUtlVector HashBucketList_t; + CUtlVector m_Buckets; + + CompareFunc_t m_CompareFunc; // function used to handle unique compares on data + KeyFunc_t m_KeyFunc; // function used to generate the key value + + bool m_bPowerOfTwo; // if the bucket value is a power of two, + unsigned int m_ModMask; // use the mod mask to "mod" +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +CUtlHash::CUtlHash( int bucketCount, int growCount, int initCount, + CompareFunc_t compareFunc, KeyFunc_t keyFunc ) : + m_CompareFunc( compareFunc ), + m_KeyFunc( keyFunc ) +{ + m_Buckets.SetSize( bucketCount ); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + m_Buckets[ndxBucket].SetSize( initCount ); + m_Buckets[ndxBucket].SetGrowSize( growCount ); + } + + // check to see if the bucket count is a power of 2 and set up + // optimizations appropriately + m_bPowerOfTwo = IsPowerOfTwo( bucketCount ); + m_ModMask = m_bPowerOfTwo ? (bucketCount-1) : 0; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +CUtlHash::~CUtlHash() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CUtlHash::IsValidHandle( UtlHashHandle_t handle ) const +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + // ndxBucket and ndxKeyData can't possibly be less than zero -- take a + // look at the definition of the Get..Index functions for why. However, + // if you override those functions, you will need to override this one + // as well. + if( /*( ndxBucket >= 0 ) && */ ( ndxBucket < m_Buckets.Count() ) ) + { + if( /*( ndxKeyData >= 0 ) && */ ( ndxKeyData < m_Buckets[ndxBucket].Count() ) ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline int CUtlHash::Count( void ) const +{ + int count = 0; + + int bucketCount = m_Buckets.Count(); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + count += m_Buckets[ndxBucket].Count(); + } + + return count; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline int CUtlHash::GetBucketIndex( UtlHashHandle_t handle ) const +{ + return ( ( ( handle >> 16 ) & 0x0000ffff ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline int CUtlHash::GetKeyDataIndex( UtlHashHandle_t handle ) const +{ + return ( handle & 0x0000ffff ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline UtlHashHandle_t CUtlHash::BuildHandle( int ndxBucket, int ndxKeyData ) const +{ + assert( ( ndxBucket >= 0 ) && ( ndxBucket < 65536 ) ); + assert( ( ndxKeyData >= 0 ) && ( ndxKeyData < 65536 ) ); + + UtlHashHandle_t handle = ndxKeyData; + handle |= ( ndxBucket << 16 ); + + return handle; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CUtlHash::Purge( void ) +{ + int bucketCount = m_Buckets.Count(); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + m_Buckets[ndxBucket].Purge(); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CUtlHash::DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const +{ + // generate the data "key" + unsigned int key = m_KeyFunc( src ); + + // hash the "key" - get the correct hash table "bucket" + unsigned int ndxBucket; + if( m_bPowerOfTwo ) + { + *pBucket = ndxBucket = ( key & m_ModMask ); + } + else + { + int bucketCount = m_Buckets.Count(); + *pBucket = ndxBucket = key % bucketCount; + } + + int ndxKeyData; + const CUtlVector &bucket = m_Buckets[ndxBucket]; + int keyDataCount = bucket.Count(); + for( ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++ ) + { + if( m_CompareFunc( bucket.Element( ndxKeyData ), src ) ) + break; + } + + if( ndxKeyData == keyDataCount ) + return false; + + *pIndex = ndxKeyData; + return true; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline UtlHashHandle_t CUtlHash::Find( Data const &src ) const +{ + unsigned int ndxBucket; + int ndxKeyData; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + return ( InvalidHandle() ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline UtlHashHandle_t CUtlHash::Insert( Data const &src ) +{ + unsigned int ndxBucket; + int ndxKeyData; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + + ndxKeyData = m_Buckets[ndxBucket].AddToTail( src ); + + return ( BuildHandle( ndxBucket, ndxKeyData ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline UtlHashHandle_t CUtlHash::Insert( Data const &src, bool *pDidInsert ) +{ + unsigned int ndxBucket; + int ndxKeyData; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + *pDidInsert = false; + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + + *pDidInsert = true; + ndxKeyData = m_Buckets[ndxBucket].AddToTail( src ); + + return ( BuildHandle( ndxBucket, ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline UtlHashHandle_t CUtlHash::AllocEntryFromKey( Data const &src ) +{ + unsigned int ndxBucket; + int ndxKeyData; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + + ndxKeyData = m_Buckets[ndxBucket].AddToTail(); + + return ( BuildHandle( ndxBucket, ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CUtlHash::Remove( UtlHashHandle_t handle ) +{ + assert( IsValidHandle( handle ) ); + + // check to see if the bucket exists + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + if( m_Buckets[ndxBucket].IsValidIndex( ndxKeyData ) ) + { + m_Buckets[ndxBucket].FastRemove( ndxKeyData ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CUtlHash::RemoveAll() +{ + int bucketCount = m_Buckets.Count(); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + m_Buckets[ndxBucket].RemoveAll(); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline Data &CUtlHash::Element( UtlHashHandle_t handle ) +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline Data const &CUtlHash::Element( UtlHashHandle_t handle ) const +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline Data &CUtlHash::operator[]( UtlHashHandle_t handle ) +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline Data const &CUtlHash::operator[]( UtlHashHandle_t handle ) const +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline UtlHashHandle_t CUtlHash::GetFirstHandle() const +{ + return GetNextHandle( ( UtlHashHandle_t )-1 ); +} + +template +inline UtlHashHandle_t CUtlHash::GetNextHandle( UtlHashHandle_t handle ) const +{ + ++handle; // start at the first possible handle after the one given + + int bi = GetBucketIndex( handle ); + int ki = GetKeyDataIndex( handle ); + + int nBuckets = m_Buckets.Count(); + for ( ; bi < nBuckets; ++bi ) + { + if ( ki < m_Buckets[ bi ].Count() ) + return BuildHandle( bi, ki ); + + ki = 0; + } + + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CUtlHash::Log( const char *filename ) +{ + FILE *pDebugFp; + pDebugFp = fopen( filename, "w" ); + if( !pDebugFp ) + return; + + int maxBucketSize = 0; + int numBucketsEmpty = 0; + + int bucketCount = m_Buckets.Count(); + fprintf( pDebugFp, "\n%d Buckets\n", bucketCount ); + + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + int count = m_Buckets[ndxBucket].Count(); + + if( count > maxBucketSize ) { maxBucketSize = count; } + if( count == 0 ) + numBucketsEmpty++; + + fprintf( pDebugFp, "Bucket %d: %d\n", ndxBucket, count ); + } + + fprintf( pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty ); + fprintf( pDebugFp, "Max Bucket Size: %d\n", maxBucketSize ); + + fclose( pDebugFp ); +} + +//============================================================================= +// +// Fast Hash +// +// Number of buckets must be a power of 2. +// Key must be 32-bits (unsigned int). +// +typedef int UtlHashFastHandle_t; + +#define UTLHASH_POOL_SCALAR 2 + +class CUtlHashFastNoHash +{ +public: + static int Hash( int key, int bucketMask ) + { + return ( key & bucketMask ); + } +}; + +class CUtlHashFastGenericHash +{ +public: + static int Hash( int key, int bucketMask ) + { + return ( HashIntConventional( key ) & bucketMask ); + } +}; + +template +class CUtlHashFast +{ +public: + + // Constructor/Deconstructor. + CUtlHashFast(); + ~CUtlHashFast(); + + // Memory. + void Purge( void ); + + // Invalid handle. + static UtlHashFastHandle_t InvalidHandle( void ) { return ( UtlHashFastHandle_t )~0; } + + // Initialize. + bool Init( int nBucketCount ); + + // Size. + int Count( void ); + + // Insertion. + UtlHashFastHandle_t Insert( unsigned int uiKey, const Data &data ); + UtlHashFastHandle_t FastInsert( unsigned int uiKey, const Data &data ); + + // Removal. + void Remove( UtlHashFastHandle_t hHash ); + void RemoveAll( void ); + + // Retrieval. + UtlHashFastHandle_t Find( unsigned int uiKey ); + + Data &Element( UtlHashFastHandle_t hHash ); + Data const &Element( UtlHashFastHandle_t hHash ) const; + Data &operator[]( UtlHashFastHandle_t hHash ); + Data const &operator[]( UtlHashFastHandle_t hHash ) const; + +//protected: + + // Templatized for memory tracking purposes + template + struct HashFastData_t_ + { + unsigned int m_uiKey; + HashData m_Data; + }; + + typedef HashFastData_t_ HashFastData_t; + + unsigned int m_uiBucketMask; + CUtlVector m_aBuckets; + CUtlFixedLinkedList m_aDataPool; +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +template CUtlHashFast::CUtlHashFast() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Deconstructor +//----------------------------------------------------------------------------- +template CUtlHashFast::~CUtlHashFast() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy dynamically allocated hash data. +//----------------------------------------------------------------------------- +template inline void CUtlHashFast::Purge( void ) +{ + m_aBuckets.Purge(); + m_aDataPool.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize the hash - set bucket count and hash grow amount. +//----------------------------------------------------------------------------- +template bool CUtlHashFast::Init( int nBucketCount ) +{ + // Verify the bucket count is power of 2. + if ( !IsPowerOfTwo( nBucketCount ) ) + return false; + + // Set the bucket size. + m_aBuckets.SetSize( nBucketCount ); + for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket ) + { + m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); + } + + // Set the mod mask. + m_uiBucketMask = nBucketCount - 1; + + // Calculate the grow size. + int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount; + m_aDataPool.SetGrowSize( nGrowSize ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Return the number of elements in the hash. +//----------------------------------------------------------------------------- +template inline int CUtlHashFast::Count( void ) +{ + return m_aDataPool.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), with +// a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template inline UtlHashFastHandle_t CUtlHashFast::Insert( unsigned int uiKey, const Data &data ) +{ + // Check to see if that key already exists in the buckets (should be unique). + UtlHashFastHandle_t hHash = Find( uiKey ); + if( hHash != InvalidHandle() ) + return hHash; + + return FastInsert( uiKey, data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// without a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template inline UtlHashFastHandle_t CUtlHashFast::FastInsert( unsigned int uiKey, const Data &data ) +{ + // Get a new element from the pool. + int iHashData = m_aDataPool.Alloc( true ); + HashFastData_t *pHashData = &m_aDataPool[iHashData]; + if ( !pHashData ) + return InvalidHandle(); + + // Add data to new element. + pHashData->m_uiKey = uiKey; + pHashData->m_Data = data; + + // Link element. + int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask ); + m_aDataPool.LinkBefore( m_aBuckets[iBucket], iHashData ); + m_aBuckets[iBucket] = iHashData; + + return iHashData; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a given element from the hash. +//----------------------------------------------------------------------------- +template inline void CUtlHashFast::Remove( UtlHashFastHandle_t hHash ) +{ + int iBucket = HashFuncs::Hash( m_aDataPool[hHash].m_uiKey, m_uiBucketMask ); + if ( m_aBuckets[iBucket] == hHash ) + { + // It is a bucket head. + m_aBuckets[iBucket] = m_aDataPool.Next( hHash ); + } + else + { + // Not a bucket head. + m_aDataPool.Unlink( hHash ); + } + + // Remove the element. + m_aDataPool.Remove( hHash ); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +template inline void CUtlHashFast::RemoveAll( void ) +{ + m_aBuckets.RemoveAll(); + m_aDataPool.RemoveAll(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template inline UtlHashFastHandle_t CUtlHashFast::Find( unsigned int uiKey ) +{ + // hash the "key" - get the correct hash table "bucket" + int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask ); + + for ( int iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) ) + { + if ( m_aDataPool[iElement].m_uiKey == uiKey ) + return iElement; + } + + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data &CUtlHashFast::Element( UtlHashFastHandle_t hHash ) +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data const &CUtlHashFast::Element( UtlHashFastHandle_t hHash ) const +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data &CUtlHashFast::operator[]( UtlHashFastHandle_t hHash ) +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data const &CUtlHashFast::operator[]( UtlHashFastHandle_t hHash ) const +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//============================================================================= +// +// Fixed Hash +// +// Number of buckets must be a power of 2. +// Key must be 32-bits (unsigned int). +// +typedef int UtlHashFixedHandle_t; + +template +class CUtlHashFixedGenericHash +{ +public: + static int Hash( int key, int bucketMask ) + { + int hash = HashIntConventional( key ); + if ( NUM_BUCKETS <= USHRT_MAX ) + { + hash ^= ( hash >> 16 ); + } + if ( NUM_BUCKETS <= UCHAR_MAX ) + { + hash ^= ( hash >> 8 ); + } + return ( hash & bucketMask ); + } +}; + +template +class CUtlHashFixed +{ +public: + + // Constructor/Deconstructor. + CUtlHashFixed(); + ~CUtlHashFixed(); + + // Memory. + void Purge( void ); + + // Invalid handle. + static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )~0; } + + // Size. + int Count( void ); + + // Insertion. + UtlHashFixedHandle_t Insert( unsigned int uiKey, const Data &data ); + UtlHashFixedHandle_t FastInsert( unsigned int uiKey, const Data &data ); + + // Removal. + void Remove( UtlHashFixedHandle_t hHash ); + void RemoveAll( void ); + + // Retrieval. + UtlHashFixedHandle_t Find( unsigned int uiKey ); + + Data &Element( UtlHashFixedHandle_t hHash ); + Data const &Element( UtlHashFixedHandle_t hHash ) const; + Data &operator[]( UtlHashFixedHandle_t hHash ); + Data const &operator[]( UtlHashFixedHandle_t hHash ) const; + + //protected: + + // Templatized for memory tracking purposes + template + struct HashFixedData_t_ + { + unsigned int m_uiKey; + Data_t m_Data; + }; + + typedef HashFixedData_t_ HashFixedData_t; + + enum + { + BUCKET_MASK = NUM_BUCKETS - 1 + }; + CUtlPtrLinkedList m_aBuckets[NUM_BUCKETS]; + int m_nElements; +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +template CUtlHashFixed::CUtlHashFixed() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Deconstructor +//----------------------------------------------------------------------------- +template CUtlHashFixed::~CUtlHashFixed() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy dynamically allocated hash data. +//----------------------------------------------------------------------------- +template inline void CUtlHashFixed::Purge( void ) +{ + RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return the number of elements in the hash. +//----------------------------------------------------------------------------- +template inline int CUtlHashFixed::Count( void ) +{ + return m_nElements; +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), with +// a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template inline UtlHashFixedHandle_t CUtlHashFixed::Insert( unsigned int uiKey, const Data &data ) +{ + // Check to see if that key already exists in the buckets (should be unique). + UtlHashFixedHandle_t hHash = Find( uiKey ); + if( hHash != InvalidHandle() ) + return hHash; + + return FastInsert( uiKey, data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// without a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template inline UtlHashFixedHandle_t CUtlHashFixed::FastInsert( unsigned int uiKey, const Data &data ) +{ + int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 ); + UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead(); + + HashFixedData_t *pHashData = &m_aBuckets[iBucket][iElem]; + + Assert( (UtlPtrLinkedListIndex_t)pHashData == iElem ); + + // Add data to new element. + pHashData->m_uiKey = uiKey; + pHashData->m_Data = data; + + m_nElements++; + return (UtlHashFixedHandle_t)pHashData; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a given element from the hash. +//----------------------------------------------------------------------------- +template inline void CUtlHashFixed::Remove( UtlHashFixedHandle_t hHash ) +{ + HashFixedData_t *pHashData = (HashFixedData_t *)hHash; + Assert( Find(pHashData->m_uiKey) != InvalidHandle() ); + int iBucket = HashFuncs::Hash( pHashData->m_uiKey, NUM_BUCKETS - 1 ); + m_aBuckets[iBucket].Remove( (UtlPtrLinkedListIndex_t)pHashData ); + m_nElements--; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +template inline void CUtlHashFixed::RemoveAll( void ) +{ + for ( int i = 0; i < NUM_BUCKETS; i++ ) + { + m_aBuckets[i].RemoveAll(); + } + m_nElements = 0; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template inline UtlHashFixedHandle_t CUtlHashFixed::Find( unsigned int uiKey ) +{ + int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 ); + CUtlPtrLinkedList &bucket = m_aBuckets[iBucket]; + + for ( UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next( iElement ) ) + { + if ( bucket[iElement].m_uiKey == uiKey ) + return (UtlHashFixedHandle_t)iElement; + } + + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data &CUtlHashFixed::Element( UtlHashFixedHandle_t hHash ) +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data const &CUtlHashFixed::Element( UtlHashFixedHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data &CUtlHashFixed::operator[]( UtlHashFixedHandle_t hHash ) +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template inline Data const &CUtlHashFixed::operator[]( UtlHashFixedHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +#endif // UTLHASH_H diff --git a/public/tier1/utlhashdict.h b/public/tier1/utlhashdict.h new file mode 100644 index 0000000..109bb75 --- /dev/null +++ b/public/tier1/utlhashdict.h @@ -0,0 +1,342 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef UTLHASHDICT_H +#define UTLHASHDICT_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1/utlhash.h" +#include "tier1/generichash.h" +#include "mathlib/mathlib.h" + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +template +class CUtlHashDict +{ +public: + // constructor, destructor + CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 ); + ~CUtlHashDict( ); + + // gets particular elements + T& Element( unsigned i ); + const T& Element( unsigned i ) const; + T& operator[]( unsigned i ); + const T& operator[]( unsigned i ) const; + + // gets element names + char const *GetElementName( unsigned i ) const; + + // Number of elements + int Count() const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( unsigned i ) const; + + // Invalid index + static unsigned InvalidHandle(); + + // Insert method (inserts in order) + unsigned Insert( const char *pName, const T &element ); + unsigned Insert( const char *pName ); + + // Find method + unsigned Find( const char *pName ) const; + + // Remove methods + void RemoveAt( unsigned i ); + void Remove( const char *pName ); + void RemoveAll( ); + + // Purge memory + void Purge(); + void PurgeAndDeleteElements(); // Call delete on each element. + + // Iteration methods + unsigned First() const; + unsigned Next( unsigned i ) const; + +protected: + struct Entry_t + { + const char *pszSymbol; + T value; + }; + + template + class CCompare + { + public: + CCompare( int ignored ) {} + + bool operator()( const Entry_t &entry1, const Entry_t &entry2 ) const + { + return !( ( bCaseInsensitive ) ? stricmp( entry1.pszSymbol, entry2.pszSymbol ) : strcmp( entry1.pszSymbol, entry2.pszSymbol ) ); + } + }; + + template + class CHash + { + public: + CHash( int ignored ) {} + + unsigned operator()( const Entry_t &entry ) const + { + return !( ( bCaseInsensitive ) ? HashStringCaseless( entry.pszSymbol ) : HashString( entry.pszSymbol ) ); + } + }; + + typedef CUtlHash, CHash > CHashTable; + CHashTable m_Elements; + int m_nCount; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template +CUtlHashDict::CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 ) : + m_Elements( SmallestPowerOfTwoGreaterOrEqual(bucketCount), growCount, initCount ) +{ + Assert( SmallestPowerOfTwoGreaterOrEqual(bucketCount) <= 0xffff ); +} + +template +CUtlHashDict::~CUtlHashDict() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- +template +inline T& CUtlHashDict::Element( unsigned i ) +{ + return m_Elements[i].value; +} + +template +inline const T& CUtlHashDict::Element( unsigned i ) const +{ + return m_Elements[i].value; +} + +//----------------------------------------------------------------------------- +// gets element names +//----------------------------------------------------------------------------- +template +inline char const *CUtlHashDict::GetElementName( unsigned i ) const +{ + return m_Elements[i].pszSymbol; +} + +template +inline T& CUtlHashDict::operator[]( unsigned i ) +{ + return m_Elements[i].value; +} + +template +inline const T & CUtlHashDict::operator[]( unsigned i ) const +{ + return m_Elements[i].value; +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- +template +inline int CUtlHashDict::Count() const +{ + Assert( m_nCount == m_Elements.Count() ); + return m_nCount; +} + + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- +template +inline bool CUtlHashDict::IsValidIndex( unsigned i ) const +{ + return m_Elements.IsValidHandle(i); +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- +template +inline unsigned CUtlHashDict::InvalidHandle() +{ + return CHashTable::InvalidHandle(); +} + + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- +template +void CUtlHashDict::RemoveAt(unsigned elem) +{ + if ( bDupeStrings ) + { + free( (void *)m_Elements[elem].pszSymbol ); + } + m_Elements.Remove(elem); + m_nCount--; +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- +template void CUtlHashDict::Remove( const char *search ) +{ + unsigned node = Find( search ); + if (node != InvalidHandle()) + { + RemoveAt(node); + } +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- +template +void CUtlHashDict::RemoveAll() +{ + if ( bDupeStrings ) + { + typename UtlHashHandle_t index = m_Elements.GetFirstHandle(); + while ( index != m_Elements.InvalidHandle() ) + { + free( (void *)m_Elements[index].pszSymbol ); + index = m_Elements.GetNextHandle( index ); + } + } + + m_Elements.RemoveAll(); + m_nCount = 0; +} + +template +void CUtlHashDict::Purge() +{ + if ( bDupeStrings ) + { + typename UtlHashHandle_t index = m_Elements.GetFirstHandle(); + while ( index != m_Elements.InvalidHandle() ) + { + free( (void *)m_Elements[index].pszSymbol ); + index = m_Elements.GetNextHandle( index ); + } + } + + m_Elements.Purge(); + m_nCount = 0; +} + + +template +void CUtlHashDict::PurgeAndDeleteElements() +{ + // Delete all the elements. + unsigned index = m_Elements.GetFirstHandle(); + while ( index != m_Elements.InvalidHandle() ) + { + if ( bDupeStrings ) + { + free( (void *)m_Elements[index].pszSymbol ); + } + delete m_Elements[index].value; + index = m_Elements.GetNextHandle( index ); + } + + m_Elements.RemoveAll(); + m_nCount = 0; +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- +template +unsigned CUtlHashDict::Insert( const char *pName, const T &element ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_nCount++; + Entry_t entry = + { + (bDupeStrings) ? strdup( pName ) : pName, + element + }; + bool bInserted; + unsigned result = m_Elements.Insert( entry, &bInserted ); + if ( bDupeStrings && !bInserted ) + { + free( (void *)entry.pszSymbol ); + } + return result; +} + +template +unsigned CUtlHashDict::Insert( const char *pName ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_nCount++; + Entry_t entry = + { + (bDupeStrings) ? strdup( pName ) : pName + }; + bool bInserted; + unsigned result = m_Elements.Insert( entry, &bInserted ); + if ( bDupeStrings && !bInserted ) + { + free( (void *)entry.pszSymbol ); + } + return result; +} + + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- +template +unsigned CUtlHashDict::Find( const char *pName ) const +{ + MEM_ALLOC_CREDIT_CLASS(); + if ( pName ) + return m_Elements.Find( *((Entry_t *)&pName) ); + else + return InvalidHandle(); +} + + +//----------------------------------------------------------------------------- +// Iteration methods +//----------------------------------------------------------------------------- +template +unsigned CUtlHashDict::First() const +{ + return m_Elements.GetFirstHandle(); +} + +template +unsigned CUtlHashDict::Next( unsigned i ) const +{ + return m_Elements.GetNextHandle(i); +} + +#endif // UTLHASHDICT_H diff --git a/public/tier1/utlhashtable.h b/public/tier1/utlhashtable.h new file mode 100644 index 0000000..c780040 --- /dev/null +++ b/public/tier1/utlhashtable.h @@ -0,0 +1,944 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: a fast growable hashtable with stored hashes, L2-friendly behavior. +// Useful as a string dictionary or a low-overhead set/map for small POD types. +// +// Usage notes: +// - handles are NOT STABLE across element removal! use RemoveAndAdvance() +// if you are removing elements while iterating through the hashtable. +// Use CUtlStableHashtable if you need stable handles (less efficient). +// - Insert() first searches for an existing match and returns it if found +// - a value type of "empty_t" can be used to eliminate value storage and +// switch Element() to return const Key references instead of values +// - an extra user flag bit is accessible via Get/SetUserFlag() +// - hash function pointer / functor is exposed via GetHashRef() +// - comparison function pointer / functor is exposed via GetEqualRef() +// - if your value type cannot be copy-constructed, use key-only Insert() +// to default-initialize the value and then manipulate it afterwards. +// +// Implementation notes: +// - overall hash table load is kept between .25 and .75 +// - items which would map to the same ideal slot are chained together +// - chained items are stored sequentially in adjacent free spaces +// - "root" entries are prioritized over chained entries; if a +// slot is not occupied by an item in its root position, the table +// is guaranteed to contain no keys which would hash to that slot. +// - new items go at the head of the chain (ie, in their root slot) +// and evict / "bump" any chained entries which occupy that slot +// - chain-following skips over unused holes and continues examining +// table entries until a chain entry with FLAG_LAST is encountered +// +// CUtlHashtable< uint32 > setOfIntegers; +// CUtlHashtable< const char* > setOfStringPointers; +// CUtlHashtable< int, CUtlVector > mapFromIntsToArrays; +// +// $NoKeywords: $ +// +// A closed-form (open addressing) hashtable with linear sequential probing. +//=============================================================================// + +#ifndef UTLHASHTABLE_H +#define UTLHASHTABLE_H +#pragma once + +#include "utlcommon.h" +#include "utlmemory.h" +#include "mathlib/mathlib.h" +#include "utllinkedlist.h" + +//----------------------------------------------------------------------------- +// Henry Goffin (henryg) was here. Questions? Bugs? Go slap him around a bit. +//----------------------------------------------------------------------------- + +typedef unsigned int UtlHashHandle_t; + +#define FOR_EACH_HASHTABLE( table, iter ) \ + for ( UtlHashHandle_t iter = (table).FirstHandle(); iter != (table).InvalidHandle(); iter = (table).NextHandle( iter ) ) + +// CUtlHashtableEntry selects between 16 and 32 bit storage backing +// for flags_and_hash depending on the size of the stored types. +template < typename KeyT, typename ValueT = empty_t > +class CUtlHashtableEntry +{ +public: + typedef CUtlKeyValuePair< KeyT, ValueT > KVPair; + + enum { INT16_STORAGE = ( sizeof( KVPair ) <= 2 ) }; + typedef typename CTypeSelect< INT16_STORAGE, int16, int32 >::type storage_t; + + enum + { + FLAG_FREE = INT16_STORAGE ? 0x8000 : 0x80000000, // must be high bit for IsValid and IdealIndex to work + FLAG_LAST = INT16_STORAGE ? 0x4000 : 0x40000000, + MASK_HASH = INT16_STORAGE ? 0x3FFF : 0x3FFFFFFF + }; + + storage_t flags_and_hash; + storage_t data[ ( sizeof(KVPair) + sizeof(storage_t) - 1 ) / sizeof(storage_t) ]; + + bool IsValid() const { return flags_and_hash >= 0; } + void MarkInvalid() { int32 flag = FLAG_FREE; flags_and_hash = (storage_t)flag; } + const KVPair *Raw() const { return reinterpret_cast< const KVPair * >( &data[0] ); } + const KVPair *operator->() const { Assert( IsValid() ); return reinterpret_cast< const KVPair * >( &data[0] ); } + KVPair *Raw() { return reinterpret_cast< KVPair * >( &data[0] ); } + KVPair *operator->() { Assert( IsValid() ); return reinterpret_cast< KVPair * >( &data[0] ); } + + // Returns the ideal index of the data in this slot, or all bits set if invalid + uint32 FORCEINLINE IdealIndex( uint32 slotmask ) const { return IdealIndex( flags_and_hash, slotmask ) | ( (int32)flags_and_hash >> 31 ); } + + // Use template tricks to fully define only one function that takes either 16 or 32 bits + // and performs different logic without using "if ( INT16_STORAGE )", because GCC and MSVC + // sometimes have trouble removing the constant branch, which is dumb... but whatever. + // 16-bit hashes are simply too narrow for large hashtables; more mask bits than hash bits! + // So we duplicate the hash bits. (Note: h *= MASK_HASH+2 is the same as h += h<::type uint32_if16BitStorage; + typedef typename CTypeSelect< INT16_STORAGE, undefined_t, int32 >::type uint32_if32BitStorage; + static FORCEINLINE uint32 IdealIndex( uint32_if16BitStorage h, uint32 m ) { h &= MASK_HASH; h *= MASK_HASH + 2; return h & m; } + static FORCEINLINE uint32 IdealIndex( uint32_if32BitStorage h, uint32 m ) { return h & m; } + + // More efficient than memcpy for the small types that are stored in a hashtable + void MoveDataFrom( CUtlHashtableEntry &src ) + { + storage_t * RESTRICT srcData = &src.data[0]; + for ( int i = 0; i < ARRAYSIZE( data ); ++i ) { data[i] = srcData[i]; } + } +}; + +template , typename KeyIsEqualT = DefaultEqualFunctor, typename AlternateKeyT = typename ArgumentTypeInfo::Alt_t > +class CUtlHashtable +{ +public: + typedef UtlHashHandle_t handle_t; + +protected: + typedef CUtlKeyValuePair KVPair; + typedef typename ArgumentTypeInfo::Arg_t KeyArg_t; + typedef typename ArgumentTypeInfo::Arg_t ValueArg_t; + typedef typename ArgumentTypeInfo::Arg_t KeyAlt_t; + typedef CUtlHashtableEntry< KeyT, ValueT > entry_t; + + enum { FLAG_FREE = entry_t::FLAG_FREE }; + enum { FLAG_LAST = entry_t::FLAG_LAST }; + enum { MASK_HASH = entry_t::MASK_HASH }; + + CUtlMemory< entry_t > m_table; + int m_nUsed; + int m_nMinSize; + bool m_bSizeLocked; + KeyIsEqualT m_eq; + KeyHashT m_hash; + + // Allocate an empty table and then re-insert all existing entries. + void DoRealloc( int size ); + + // Move an existing entry to a free slot, leaving a hole behind + void BumpEntry( unsigned int idx ); + + // Insert an unconstructed KVPair at the primary slot + int DoInsertUnconstructed( unsigned int h, bool allowGrow ); + + // Implementation for Insert functions, constructs a KVPair + // with either a default-construted or copy-constructed value + template handle_t DoInsert( KeyParamT k, unsigned int h ); + template handle_t DoInsert( KeyParamT k, typename ArgumentTypeInfo::Arg_t v, unsigned int h, bool* pDidInsert ); + template handle_t DoInsertNoCheck( KeyParamT k, typename ArgumentTypeInfo::Arg_t v, unsigned int h ); + + // Key lookup. Can also return previous-in-chain if result is chained. + template handle_t DoLookup( KeyParamT x, unsigned int h, handle_t *pPreviousInChain ) const; + + // Remove single element by key + hash. Returns the index of the new hole + // that was created. Returns InvalidHandle() if element was not found. + template int DoRemove( KeyParamT x, unsigned int h ); + + // Friend CUtlStableHashtable so that it can call our Do* functions directly + template < typename K, typename V, typename S, typename H, typename E, typename A > friend class CUtlStableHashtable; + +public: + explicit CUtlHashtable( int minimumSize = 32 ) + : m_nUsed(0), m_nMinSize(MAX(8, minimumSize)), m_bSizeLocked(false), m_eq(), m_hash() { } + + CUtlHashtable( int minimumSize, const KeyHashT &hash, KeyIsEqualT const &eq = KeyIsEqualT() ) + : m_nUsed(0), m_nMinSize(MAX(8, minimumSize)), m_bSizeLocked(false), m_eq(eq), m_hash(hash) { } + + CUtlHashtable( entry_t* pMemory, unsigned int nCount, const KeyHashT &hash = KeyHashT(), KeyIsEqualT const &eq = KeyIsEqualT() ) + : m_nUsed(0), m_nMinSize(8), m_bSizeLocked(false), m_eq(eq), m_hash(hash) { SetExternalBuffer( pMemory, nCount ); } + + ~CUtlHashtable() { RemoveAll(); } + + CUtlHashtable &operator=( CUtlHashtable const &src ); + + // Set external memory + void SetExternalBuffer( byte* pRawBuffer, unsigned int nBytes, bool bAssumeOwnership = false, bool bGrowable = false ); + void SetExternalBuffer( entry_t* pBuffer, unsigned int nSize, bool bAssumeOwnership = false, bool bGrowable = false ); + + // Functor/function-pointer access + KeyHashT& GetHashRef() { return m_hash; } + KeyIsEqualT& GetEqualRef() { return m_eq; } + KeyHashT const &GetHashRef() const { return m_hash; } + KeyIsEqualT const &GetEqualRef() const { return m_eq; } + + // Handle validation + bool IsValidHandle( handle_t idx ) const { return (unsigned)idx < (unsigned)m_table.Count() && m_table[idx].IsValid(); } + static handle_t InvalidHandle() { return (handle_t) -1; } + + // Iteration functions + handle_t FirstHandle() const { return NextHandle( (handle_t) -1 ); } + handle_t NextHandle( handle_t start ) const; + + // Returns the number of unique keys in the table + int Count() const { return m_nUsed; } + + + // Key lookup, returns InvalidHandle() if not found + handle_t Find( KeyArg_t k ) const { return DoLookup( k, m_hash(k), NULL ); } + handle_t Find( KeyArg_t k, unsigned int hash) const { Assert( hash == m_hash(k) ); return DoLookup( k, hash, NULL ); } + // Alternate-type key lookup, returns InvalidHandle() if not found + handle_t Find( KeyAlt_t k ) const { return DoLookup( k, m_hash(k), NULL ); } + handle_t Find( KeyAlt_t k, unsigned int hash) const { Assert( hash == m_hash(k) ); return DoLookup( k, hash, NULL ); } + + // True if the key is in the table + bool HasElement( KeyArg_t k ) const { return InvalidHandle() != Find( k ); } + bool HasElement( KeyAlt_t k ) const { return InvalidHandle() != Find( k ); } + + // Key insertion or lookup, always returns a valid handle + handle_t Insert( KeyArg_t k ) { return DoInsert( k, m_hash(k) ); } + handle_t Insert( KeyArg_t k, ValueArg_t v, bool *pDidInsert = NULL ) { return DoInsert( k, v, m_hash(k), pDidInsert ); } + handle_t Insert( KeyArg_t k, ValueArg_t v, unsigned int hash, bool *pDidInsert = NULL ) { Assert( hash == m_hash(k) ); return DoInsert( k, v, hash, pDidInsert ); } + // Alternate-type key insertion or lookup, always returns a valid handle + handle_t Insert( KeyAlt_t k ) { return DoInsert( k, m_hash(k) ); } + handle_t Insert( KeyAlt_t k, ValueArg_t v, bool *pDidInsert = NULL ) { return DoInsert( k, v, m_hash(k), pDidInsert ); } + handle_t Insert( KeyAlt_t k, ValueArg_t v, unsigned int hash, bool *pDidInsert = NULL ) { Assert( hash == m_hash(k) ); return DoInsert( k, v, hash, pDidInsert ); } + + // Key removal, returns false if not found + bool Remove( KeyArg_t k ) { return DoRemove( k, m_hash(k) ) >= 0; } + bool Remove( KeyArg_t k, unsigned int hash ) { Assert( hash == m_hash(k) ); return DoRemove( k, hash ) >= 0; } + // Alternate-type key removal, returns false if not found + bool Remove( KeyAlt_t k ) { return DoRemove( k, m_hash(k) ) >= 0; } + bool Remove( KeyAlt_t k, unsigned int hash ) { Assert( hash == m_hash(k) ); return DoRemove( k, hash ) >= 0; } + + // Remove while iterating, returns the next handle for forward iteration + // Note: aside from this, ALL handles are invalid if an element is removed + handle_t RemoveAndAdvance( handle_t idx ); + + // Nuke contents + void RemoveAll(); + + // Nuke and release memory. + void Purge() { RemoveAll(); m_table.Purge(); } + + // Reserve table capacity up front to avoid reallocation during insertions + void Reserve( int expected ) { if ( expected > m_nUsed ) DoRealloc( expected * 4 / 3 ); } + + // Shrink to best-fit size, re-insert keys for optimal lookup + void Compact( bool bMinimal ) { DoRealloc( bMinimal ? m_nUsed : ( m_nUsed * 4 / 3 ) ); } + + // Access functions. Note: if ValueT is empty_t, all functions return const keys. + typedef typename KVPair::ValueReturn_t Element_t; + KeyT const &Key( handle_t idx ) const { return m_table[idx]->m_key; } + Element_t const &Element( handle_t idx ) const { return m_table[idx]->GetValue(); } + Element_t &Element(handle_t idx) { return m_table[idx]->GetValue(); } + Element_t const &operator[]( handle_t idx ) const { return m_table[idx]->GetValue(); } + Element_t &operator[]( handle_t idx ) { return m_table[idx]->GetValue(); } + + void ReplaceKey( handle_t idx, KeyArg_t k ) { Assert( m_eq( m_table[idx]->m_key, k ) && m_hash( k ) == m_hash( m_table[idx]->m_key ) ); m_table[idx]->m_key = k; } + void ReplaceKey( handle_t idx, KeyAlt_t k ) { Assert( m_eq( m_table[idx]->m_key, k ) && m_hash( k ) == m_hash( m_table[idx]->m_key ) ); m_table[idx]->m_key = k; } + + Element_t const &Get( KeyArg_t k, Element_t const &defaultValue ) const { handle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; } + Element_t const &Get( KeyAlt_t k, Element_t const &defaultValue ) const { handle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; } + + Element_t const *GetPtr( KeyArg_t k ) const { handle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + Element_t const *GetPtr( KeyAlt_t k ) const { handle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + Element_t *GetPtr( KeyArg_t k ) { handle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + Element_t *GetPtr( KeyAlt_t k ) { handle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + + // Swap memory and contents with another identical hashtable + // (NOTE: if using function pointers or functors with state, + // it is up to the caller to ensure that they are compatible!) + void Swap( CUtlHashtable &other ) { m_table.Swap(other.m_table); ::V_swap(m_nUsed, other.m_nUsed); } + +#if _DEBUG + // Validate the integrity of the hashtable + void DbgCheckIntegrity() const; +#endif + +private: + CUtlHashtable(const CUtlHashtable& copyConstructorIsNotImplemented); +}; + + +// Set external memory (raw byte buffer, best-fit) +template +void CUtlHashtable::SetExternalBuffer( byte* pRawBuffer, unsigned int nBytes, bool bAssumeOwnership, bool bGrowable ) +{ + Assert( ((uintptr_t)pRawBuffer % __alignof(int)) == 0 ); + uint32 bestSize = LargestPowerOfTwoLessThanOrEqual( nBytes / sizeof(entry_t) ); + Assert( bestSize != 0 && bestSize*sizeof(entry_t) <= nBytes ); + + return SetExternalBuffer( (entry_t*) pRawBuffer, bestSize, bAssumeOwnership, bGrowable ); +} + +// Set external memory (typechecked, must be power of two) +template +void CUtlHashtable::SetExternalBuffer( entry_t* pBuffer, unsigned int nSize, bool bAssumeOwnership, bool bGrowable ) +{ + Assert( IsPowerOfTwo(nSize) ); + Assert( m_nUsed == 0 ); + for ( uint i = 0; i < nSize; ++i ) + pBuffer[i].MarkInvalid(); + if ( bAssumeOwnership ) + m_table.AssumeMemory( pBuffer, nSize ); + else + m_table.SetExternalBuffer( pBuffer, nSize ); + m_bSizeLocked = !bGrowable; +} + +// Allocate an empty table and then re-insert all existing entries. +template +void CUtlHashtable::DoRealloc( int size ) +{ + Assert( !m_bSizeLocked ); + + size = SmallestPowerOfTwoGreaterOrEqual( MAX( m_nMinSize, size ) ); + Assert( size > 0 && (uint)size <= entry_t::IdealIndex( ~0, 0x1FFFFFFF ) ); // reasonable power of 2 + Assert( size > m_nUsed ); + + CUtlMemory oldTable; + oldTable.Swap( m_table ); + entry_t * RESTRICT const pOldBase = oldTable.Base(); + + m_table.EnsureCapacity( size ); + entry_t * const pNewBase = m_table.Base(); + for ( int i = 0; i < size; ++i ) + pNewBase[i].MarkInvalid(); + + int nLeftToMove = m_nUsed; + m_nUsed = 0; + for ( int i = oldTable.Count() - 1; i >= 0; --i ) + { + if ( pOldBase[i].IsValid() ) + { + int newIdx = DoInsertUnconstructed( pOldBase[i].flags_and_hash, false ); + pNewBase[newIdx].MoveDataFrom( pOldBase[i] ); + if ( --nLeftToMove == 0 ) + break; + } + } + Assert( nLeftToMove == 0 ); +} + + +// Move an existing entry to a free slot, leaving a hole behind +template +void CUtlHashtable::BumpEntry( unsigned int idx ) +{ + Assert( m_table[idx].IsValid() ); + Assert( m_nUsed < m_table.Count() ); + + entry_t* table = m_table.Base(); + unsigned int slotmask = m_table.Count()-1; + unsigned int new_flags_and_hash = table[idx].flags_and_hash & (FLAG_LAST | MASK_HASH); + + unsigned int chainid = entry_t::IdealIndex( new_flags_and_hash, slotmask ); + + // Look for empty slots scanning forward, stripping FLAG_LAST as we go. + // Note: this potentially strips FLAG_LAST from table[idx] if we pass it + int newIdx = chainid; // start at ideal slot + for ( ; ; newIdx = (newIdx + 1) & slotmask ) + { + if ( table[newIdx].IdealIndex( slotmask ) == chainid ) + { + if ( table[newIdx].flags_and_hash & FLAG_LAST ) + { + table[newIdx].flags_and_hash &= ~FLAG_LAST; + new_flags_and_hash |= FLAG_LAST; + } + continue; + } + if ( table[newIdx].IsValid() ) + { + continue; + } + break; + } + + // Did we pick something closer to the ideal slot, leaving behind a + // FLAG_LAST bit on the current slot because we didn't scan past it? + if ( table[idx].flags_and_hash & FLAG_LAST ) + { +#ifdef _DEBUG + Assert( new_flags_and_hash & FLAG_LAST ); + // Verify logic: we must have moved to an earlier slot, right? + uint offset = ((uint)idx - chainid + slotmask + 1) & slotmask; + uint newOffset = ((uint)newIdx - chainid + slotmask + 1) & slotmask; + Assert( newOffset < offset ); +#endif + // Scan backwards from old to new location, depositing FLAG_LAST on + // the first match we find. (+slotmask) is the same as (-1) without + // having to make anyone think about two's complement shenanigans. + int scan = (idx + slotmask) & slotmask; + while ( scan != newIdx ) + { + if ( table[scan].IdealIndex( slotmask ) == chainid ) + { + table[scan].flags_and_hash |= FLAG_LAST; + new_flags_and_hash &= ~FLAG_LAST; + break; + } + scan = (scan + slotmask) & slotmask; + } + } + + // Move entry to the free slot we found, leaving a hole at idx + table[newIdx].flags_and_hash = new_flags_and_hash; + table[newIdx].MoveDataFrom( table[idx] ); + table[idx].MarkInvalid(); +} + + +// Insert a value at the root position for that value's hash chain. +template +int CUtlHashtable::DoInsertUnconstructed( unsigned int h, bool allowGrow ) +{ + if ( allowGrow && !m_bSizeLocked ) + { + // Keep the load factor between .25 and .75 + int newSize = m_nUsed + 1; + if ( ( newSize*4 < m_table.Count() && m_table.Count() > m_nMinSize*2 ) || newSize*4 > m_table.Count()*3 ) + { + DoRealloc( newSize * 4 / 3 ); + } + } + Assert( m_nUsed < m_table.Count() ); + ++m_nUsed; + + entry_t* table = m_table.Base(); + unsigned int slotmask = m_table.Count()-1; + unsigned int new_flags_and_hash = FLAG_LAST | (h & MASK_HASH); + unsigned int idx = entry_t::IdealIndex( h, slotmask ); + if ( table[idx].IdealIndex( slotmask ) == idx ) + { + // There is already an entry in this chain. + new_flags_and_hash &= ~FLAG_LAST; + BumpEntry(idx); + } + else if ( table[idx].IsValid() ) + { + // Somebody else is living in our ideal index but does not belong + // to our entry chain; move it out of the way, start a new chain. + BumpEntry(idx); + } + table[idx].flags_and_hash = new_flags_and_hash; + return idx; +} + + +// Key lookup. Can also return previous-in-chain if result is a chained slot. +template +template +UtlHashHandle_t CUtlHashtable::DoLookup( KeyParamT x, unsigned int h, handle_t *pPreviousInChain ) const +{ + if ( m_nUsed == 0 ) + { + // Empty table. + return (handle_t) -1; + } + + const entry_t* table = m_table.Base(); + unsigned int slotmask = m_table.Count()-1; + Assert( m_table.Count() > 0 && (slotmask & m_table.Count()) == 0 ); + unsigned int chainid = entry_t::IdealIndex( h, slotmask ); + + unsigned int idx = chainid; + if ( table[idx].IdealIndex( slotmask ) != chainid ) + { + // Nothing in root position? No match. + return (handle_t) -1; + } + + // Linear scan until found or end of chain + handle_t lastIdx = (handle_t) -1; + while (1) + { + // Only examine this slot if it is valid and belongs to our hash chain + if ( table[idx].IdealIndex( slotmask ) == chainid ) + { + // Test the full-width hash to avoid unnecessary calls to m_eq() + if ( ((table[idx].flags_and_hash ^ h) & MASK_HASH) == 0 && m_eq( table[idx]->m_key, x ) ) + { + // Found match! + if (pPreviousInChain) + *pPreviousInChain = lastIdx; + + return (handle_t) idx; + } + + if ( table[idx].flags_and_hash & FLAG_LAST ) + { + // End of chain. No match. + return (handle_t) -1; + } + + lastIdx = (handle_t) idx; + } + idx = (idx + 1) & slotmask; + } +} + + +// Key insertion, or return index of existing key if found +template +template +UtlHashHandle_t CUtlHashtable::DoInsert( KeyParamT k, unsigned int h ) +{ + handle_t idx = DoLookup( k, h, NULL ); + if ( idx == (handle_t) -1 ) + { + idx = (handle_t) DoInsertUnconstructed( h, true ); + ConstructOneArg( m_table[ idx ].Raw(), k ); + } + return idx; +} + +// Key insertion, or return index of existing key if found +template +template +UtlHashHandle_t CUtlHashtable::DoInsert( KeyParamT k, typename ArgumentTypeInfo::Arg_t v, unsigned int h, bool *pDidInsert ) +{ + handle_t idx = DoLookup( k, h, NULL ); + if ( idx == (handle_t) -1 ) + { + idx = (handle_t) DoInsertUnconstructed( h, true ); + ConstructTwoArg( m_table[ idx ].Raw(), k, v ); + if ( pDidInsert ) *pDidInsert = true; + } + else + { + if ( pDidInsert ) *pDidInsert = false; + } + return idx; +} + +// Key insertion +template +template +UtlHashHandle_t CUtlHashtable::DoInsertNoCheck( KeyParamT k, typename ArgumentTypeInfo::Arg_t v, unsigned int h ) +{ + Assert( DoLookup( k, h, NULL ) == (handle_t) -1 ); + handle_t idx = (handle_t) DoInsertUnconstructed( h, true ); + ConstructTwoArg( m_table[ idx ].Raw(), k, v ); + return idx; +} + + +// Remove single element by key + hash. Returns the location of the new empty hole. +template +template +int CUtlHashtable::DoRemove( KeyParamT x, unsigned int h ) +{ + unsigned int slotmask = m_table.Count()-1; + handle_t previous = (handle_t) -1; + int idx = (int) DoLookup( x, h, &previous ); + if (idx == -1) + { + return -1; + } + + enum { FAKEFLAG_ROOT = 1 }; + int nLastAndRootFlags = m_table[idx].flags_and_hash & FLAG_LAST; + nLastAndRootFlags |= ( (uint)idx == m_table[idx].IdealIndex( slotmask ) ); + + // Remove from table + m_table[idx].MarkInvalid(); + Destruct( m_table[idx].Raw() ); + --m_nUsed; + + if ( nLastAndRootFlags == FLAG_LAST ) // last only, not root + { + // This was the end of the chain - mark previous as last. + // (This isn't the root, so there must be a previous.) + Assert( previous != (handle_t) -1 ); + m_table[previous].flags_and_hash |= FLAG_LAST; + } + + if ( nLastAndRootFlags == FAKEFLAG_ROOT ) // root only, not last + { + // If we are removing the root and there is more to the chain, + // scan to find the next chain entry and move it to the root. + unsigned int chainid = entry_t::IdealIndex( h, slotmask ); + unsigned int nextIdx = idx; + while (1) + { + nextIdx = (nextIdx + 1) & slotmask; + if ( m_table[nextIdx].IdealIndex( slotmask ) == chainid ) + { + break; + } + } + Assert( !(m_table[nextIdx].flags_and_hash & FLAG_FREE) ); + + // Leave a hole where the next entry in the chain was. + m_table[idx].flags_and_hash = m_table[nextIdx].flags_and_hash; + m_table[idx].MoveDataFrom( m_table[nextIdx] ); + m_table[nextIdx].MarkInvalid(); + return nextIdx; + } + + // The hole is still where the element used to be. + return idx; +} + + +// Assignment operator. It's up to the user to make sure that the hash and equality functors match. +template +CUtlHashtable &CUtlHashtable::operator=( CUtlHashtable const &src ) +{ + if ( &src != this ) + { + Assert( !m_bSizeLocked || m_table.Count() >= src.m_nUsed ); + if ( !m_bSizeLocked ) + { + Purge(); + Reserve(src.m_nUsed); + } + else + { + RemoveAll(); + } + + const entry_t * srcTable = src.m_table.Base(); + for ( int i = src.m_table.Count() - 1; i >= 0; --i ) + { + if ( srcTable[i].IsValid() ) + { + // If this assert trips, double-check that both hashtables + // have the same hash function pointers or hash functor state! + Assert( m_hash(srcTable[i]->m_key) == src.m_hash(srcTable[i]->m_key) ); + int newIdx = DoInsertUnconstructed( srcTable[i].flags_and_hash , false ); + CopyConstruct( m_table[newIdx].Raw(), *srcTable[i].Raw() ); // copy construct KVPair + } + } + } + return *this; +} + +// Remove and return the next valid iterator for a forward iteration. +template +UtlHashHandle_t CUtlHashtable::RemoveAndAdvance( UtlHashHandle_t idx ) +{ + Assert( IsValidHandle( idx ) ); + + // TODO optimize, implement DoRemoveAt that does not need to re-evaluate equality in DoLookup + int hole = DoRemove< KeyArg_t >( m_table[idx]->m_key, m_table[idx].flags_and_hash & MASK_HASH ); + // DoRemove returns the index of the element that it moved to fill the hole, if any. + if ( hole <= (int) idx ) + { + // Didn't fill, or filled from a previously seen element. + return NextHandle( idx ); + } + else + { + // Do not advance; slot has a new un-iterated value. + Assert( IsValidHandle(idx) ); + return idx; + } +} + +// Burn it with fire. +template +void CUtlHashtable::RemoveAll() +{ + int used = m_nUsed; + if ( used != 0 ) + { + entry_t* table = m_table.Base(); + for ( int i = m_table.Count() - 1; i >= 0; --i ) + { + if ( table[i].IsValid() ) + { + table[i].MarkInvalid(); + Destruct( table[i].Raw() ); + if ( --used == 0 ) + break; + } + } + m_nUsed = 0; + } +} + +template +UtlHashHandle_t CUtlHashtable::NextHandle( handle_t start ) const +{ + const entry_t *table = m_table.Base(); + for ( int i = (int)start + 1; i < m_table.Count(); ++i ) + { + if ( table[i].IsValid() ) + return (handle_t) i; + } + return (handle_t) -1; +} + + +#if _DEBUG +template +void CUtlHashtable::DbgCheckIntegrity() const +{ + // Stress test the hash table as a test of both container functionality + // and also the validity of the user's Hash and Equal function objects. + // NOTE: will fail if function objects require any sort of state! + CUtlHashtable clone; + unsigned int bytes = sizeof(entry_t)*vmax(16,m_table.Count()); + byte* tempbuf = (byte*) malloc(bytes); + clone.SetExternalBuffer( tempbuf, bytes, false, false ); + clone = *this; + + int count = 0, roots = 0, ends = 0; + int slotmask = m_table.Count() - 1; + for (int i = 0; i < m_table.Count(); ++i) + { + if (!(m_table[i].flags_and_hash & FLAG_FREE)) ++count; + if (m_table[i].IdealIndex(slotmask) == (uint)i) ++roots; + if (m_table[i].flags_and_hash & FLAG_LAST) ++ends; + if (m_table[i].IsValid()) + { + Assert( Find(m_table[i]->m_key) == (handle_t)i ); + Verify( clone.Remove(m_table[i]->m_key) ); + } + else + { + Assert( m_table[i].flags_and_hash == FLAG_FREE ); + } + } + Assert( count == Count() && count >= roots && roots == ends ); + Assert( clone.Count() == 0 ); + clone.Purge(); + free(tempbuf); +} +#endif + +//----------------------------------------------------------------------- +// CUtlStableHashtable +//----------------------------------------------------------------------- + +// Stable hashtables are less memory and cache efficient, but can be +// iterated quickly and their element handles are completely stable. +// Implemented as a hashtable which only stores indices, and a separate +// CUtlLinkedList data table which contains key-value pairs; this may +// change to a more efficient structure in the future if space becomes +// critical. I have some ideas about that but not the time to implement +// at the moment. -henryg + +// Note: RemoveAndAdvance is slower than in CUtlHashtable because the +// key needs to be re-hashed under the current implementation. + +template , typename KeyIsEqualT = DefaultEqualFunctor, typename IndexStorageT = uint16, typename AlternateKeyT = typename ArgumentTypeInfo::Alt_t > +class CUtlStableHashtable +{ +public: + typedef typename ArgumentTypeInfo::Arg_t KeyArg_t; + typedef typename ArgumentTypeInfo::Arg_t ValueArg_t; + typedef typename ArgumentTypeInfo::Arg_t KeyAlt_t; + typedef typename CTypeSelect< sizeof( IndexStorageT ) == 2, uint16, uint32 >::type IndexStorage_t; + +protected: + COMPILE_TIME_ASSERT( sizeof( IndexStorage_t ) == sizeof( IndexStorageT ) ); + + typedef CUtlKeyValuePair< KeyT, ValueT > KVPair; + struct HashProxy; + struct EqualProxy; + struct IndirectIndex; + + typedef CUtlHashtable< IndirectIndex, empty_t, HashProxy, EqualProxy, AlternateKeyT > Hashtable_t; + typedef CUtlLinkedList< KVPair, IndexStorage_t > LinkedList_t; + + template bool DoRemove( KeyArgumentT k ); + template UtlHashHandle_t DoFind( KeyArgumentT k ) const; + template UtlHashHandle_t DoInsert( KeyArgumentT k ); + template UtlHashHandle_t DoInsert( KeyArgumentT k, ValueArgumentT v ); + +public: + + KeyHashT &GetHashRef() { return m_table.GetHashRef().m_hash; } + KeyIsEqualT &GetEqualRef() { return m_table.GetEqualRef().m_eq; } + KeyHashT const &GetHashRef() const { return m_table.GetHashRef().m_hash; } + KeyIsEqualT const &GetEqualRef() const { return m_table.GetEqualRef().m_eq; } + + UtlHashHandle_t Insert( KeyArg_t k ) { return DoInsert( k ); } + UtlHashHandle_t Insert( KeyAlt_t k ) { return DoInsert( k ); } + UtlHashHandle_t Insert( KeyArg_t k, ValueArg_t v ) { return DoInsert( k, v ); } + UtlHashHandle_t Insert( KeyAlt_t k, ValueArg_t v ) { return DoInsert( k, v ); } + UtlHashHandle_t Find( KeyArg_t k ) const { return DoFind( k ); } + UtlHashHandle_t Find( KeyAlt_t k ) const { return DoFind( k ); } + bool Remove( KeyArg_t k ) { return DoRemove( k ); } + bool Remove( KeyAlt_t k ) { return DoRemove( k ); } + + void RemoveAll() { m_table.RemoveAll(); m_data.RemoveAll(); } + void Purge() { m_table.Purge(); m_data.Purge(); } + int Count() const { return m_table.Count(); } + + typedef typename KVPair::ValueReturn_t Element_t; + KeyT const &Key( UtlHashHandle_t idx ) const { return m_data[idx].m_key; } + Element_t const &Element( UtlHashHandle_t idx ) const { return m_data[idx].GetValue(); } + Element_t &Element( UtlHashHandle_t idx ) { return m_data[idx].GetValue(); } + Element_t const &operator[]( UtlHashHandle_t idx ) const { return m_data[idx].GetValue(); } + Element_t &operator[]( UtlHashHandle_t idx ) { return m_data[idx].GetValue(); } + + void ReplaceKey( UtlHashHandle_t idx, KeyArg_t k ) { Assert( GetEqualRef()( m_data[idx].m_key, k ) && GetHashRef()( k ) == GetHashRef()( m_data[idx].m_key ) ); m_data[idx].m_key = k; } + void ReplaceKey( UtlHashHandle_t idx, KeyAlt_t k ) { Assert( GetEqualRef()( m_data[idx].m_key, k ) && GetHashRef()( k ) == GetHashRef()( m_data[idx].m_key ) ); m_data[idx].m_key = k; } + + Element_t const &Get( KeyArg_t k, Element_t const &defaultValue ) const { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; } + Element_t const &Get( KeyAlt_t k, Element_t const &defaultValue ) const { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return Element( h ); return defaultValue; } + + Element_t const *GetPtr( KeyArg_t k ) const { UtlHashHandle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + Element_t const *GetPtr( KeyAlt_t k ) const { UtlHashHandle_t h = Find(k); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + Element_t *GetPtr( KeyArg_t k ) { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + Element_t *GetPtr( KeyAlt_t k ) { UtlHashHandle_t h = Find( k ); if ( h != InvalidHandle() ) return &Element( h ); return NULL; } + + UtlHashHandle_t FirstHandle() const { return ExtendInvalidHandle( m_data.Head() ); } + UtlHashHandle_t NextHandle( UtlHashHandle_t h ) const { return ExtendInvalidHandle( m_data.Next( h ) ); } + bool IsValidHandle( UtlHashHandle_t h ) const { return m_data.IsValidIndex( h ); } + UtlHashHandle_t InvalidHandle() const { return (UtlHashHandle_t)-1; } + + UtlHashHandle_t RemoveAndAdvance( UtlHashHandle_t h ) + { + Assert( m_data.IsValidIndex( h ) ); + m_table.Remove( IndirectIndex( h ) ); + IndexStorage_t next = m_data.Next( h ); + m_data.Remove( h ); + return ExtendInvalidHandle(next); + } + + void Compact( bool bMinimal ) { m_table.Compact( bMinimal ); /*m_data.Compact();*/ } + + void Swap( CUtlStableHashtable &other ) + { + m_table.Swap(other.m_table); + // XXX swapping CUtlLinkedList by block memory swap, ugh + char buf[ sizeof(m_data) ]; + memcpy( buf, &m_data, sizeof(m_data) ); + memcpy( &m_data, &other.m_data, sizeof(m_data) ); + memcpy( &other.m_data, buf, sizeof(m_data) ); + } + + +protected: + // Perform extension of 0xFFFF to 0xFFFFFFFF if necessary. Note: ( a < CONSTANT ) ? 0 : -1 is usually branchless + static UtlHashHandle_t ExtendInvalidHandle( uint32 x ) { return x; } + static UtlHashHandle_t ExtendInvalidHandle( uint16 x ) { uint32 a = x; return a | ( ( a < 0xFFFFu ) ? 0 : -1 ); } + + struct IndirectIndex + { + explicit IndirectIndex(IndexStorage_t i) : m_index(i) { } + IndexStorage_t m_index; + }; + + struct HashProxy + { + KeyHashT m_hash; + unsigned int operator()( IndirectIndex idx ) const + { + const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetHashRef()) - 1024; + const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset; + CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset); + return m_hash( pOwner->m_data[ idx.m_index ].m_key ); + } + unsigned int operator()( KeyArg_t k ) const { return m_hash( k ); } + unsigned int operator()( KeyAlt_t k ) const { return m_hash( k ); } + }; + + struct EqualProxy + { + KeyIsEqualT m_eq; + unsigned int operator()( IndirectIndex lhs, IndirectIndex rhs ) const + { + return lhs.m_index == rhs.m_index; + } + unsigned int operator()( IndirectIndex lhs, KeyArg_t rhs ) const + { + const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024; + const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset; + CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset); + return m_eq( pOwner->m_data[ lhs.m_index ].m_key, rhs ); + } + unsigned int operator()( IndirectIndex lhs, KeyAlt_t rhs ) const + { + const ptrdiff_t tableoffset = (uintptr_t)(&((Hashtable_t*)1024)->GetEqualRef()) - 1024; + const ptrdiff_t owneroffset = offsetof(CUtlStableHashtable, m_table) + tableoffset; + CUtlStableHashtable* pOwner = (CUtlStableHashtable*)((uintptr_t)this - owneroffset); + return m_eq( pOwner->m_data[ lhs.m_index ].m_key, rhs ); + } + }; + + class CCustomLinkedList : public LinkedList_t + { + public: + int AddToTailUnconstructed() + { + IndexStorage_t newNode = this->AllocInternal(); + if ( newNode != this->InvalidIndex() ) + this->LinkToTail( newNode ); + return newNode; + } + }; + + Hashtable_t m_table; + CCustomLinkedList m_data; +}; + +template +template +inline bool CUtlStableHashtable::DoRemove( KeyArgumentT k ) +{ + unsigned int hash = m_table.GetHashRef()( k ); + UtlHashHandle_t h = m_table.template DoLookup( k, hash, NULL ); + if ( h == m_table.InvalidHandle() ) + return false; + + int idx = m_table[ h ].m_index; + m_table.template DoRemove( IndirectIndex( idx ), hash ); + m_data.Remove( idx ); + return true; +} + +template +template +inline UtlHashHandle_t CUtlStableHashtable::DoFind( KeyArgumentT k ) const +{ + unsigned int hash = m_table.GetHashRef()( k ); + UtlHashHandle_t h = m_table.template DoLookup( k, hash, NULL ); + if ( h != m_table.InvalidHandle() ) + return m_table[ h ].m_index; + + return (UtlHashHandle_t) -1; +} + +template +template +inline UtlHashHandle_t CUtlStableHashtable::DoInsert( KeyArgumentT k ) +{ + unsigned int hash = m_table.GetHashRef()( k ); + UtlHashHandle_t h = m_table.template DoLookup( k, hash, NULL ); + if ( h != m_table.InvalidHandle() ) + return m_table[ h ].m_index; + + int idx = m_data.AddToTailUnconstructed(); + ConstructOneArg( &m_data[idx], k ); + m_table.template DoInsertNoCheck( IndirectIndex( idx ), empty_t(), hash ); + return idx; +} + +template +template +inline UtlHashHandle_t CUtlStableHashtable::DoInsert( KeyArgumentT k, ValueArgumentT v ) +{ + unsigned int hash = m_table.GetHashRef()( k ); + UtlHashHandle_t h = m_table.template DoLookup( k, hash, NULL ); + if ( h != m_table.InvalidHandle() ) + return m_table[ h ].m_index; + + int idx = m_data.AddToTailUnconstructed(); + ConstructTwoArg( &m_data[idx], k, v ); + m_table.template DoInsertNoCheck( IndirectIndex( idx ), empty_t(), hash ); + return idx; +} + +#endif // UTLHASHTABLE_H diff --git a/public/tier1/utlintrusivelist.h b/public/tier1/utlintrusivelist.h new file mode 100644 index 0000000..04a39bd --- /dev/null +++ b/public/tier1/utlintrusivelist.h @@ -0,0 +1,888 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Intrusive linked list templates, both for singly and doubly linked lists +// +// $Revision: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef UTILINTRUSIVELIST_H +#define UTILINTRUSIVELIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/basetypes.h" +#include "utlmemory.h" +#include "tier0/dbg.h" + + +// +// These templates are used for intrusive linked list classes. Intrusive linked list templates +// force the structs and classes contained within them to have their own m_pNext, (optionally), +// m_pPrev, and other fields contained within. All memory management is up to the caller and their +// classes. No data will ever be copied. Nodes can only exist on one list at a time, because of +// only having on m_Next field, and manipulating the list while walking it requires that care on +// the part of the caller. All accessing and searching functions work by passing and returning +// pointers. +// +// +// +// naming and field conventions: +// functions referring to a DList are for doubly linked lists. nodes must have m_pHead and +// m_pPrev pointer fields. +// Functions using Priority require an m_Priority field, which must be comparable. +// +// Some functions are mean for use with lists which maintain both a head and tail pointer +// in order to support fast adding to the end. + + +/// validates that the doubly linked list has the proper structure, pointer-wise + +namespace IntrusiveList +{ +#ifdef SUPERSLOW_DEBUG_VERSION + template inline void ValidateDList(T *head) + { + if (head) + { + Assert(head->m_pPrev==0); + } + while(head) + { + if (head->m_pNext) + { + Assert(head->m_pNext->m_pPrev==head); + } + if (head->m_pPrev) + { + Assert(head->m_pPrev->m_pNext==head); + } + head=head->m_pNext; + } + } +#else + template inline void ValidateDList(T * /*head*/) + { + } +#endif + + + +// move a node in a doubly linked list backwards one step. + template inline void MoveDNodeBackwards( T *which, T * &head) + { + if (which->m_pPrev) + { + T *p=which->m_pPrev; + T *pp=p->m_pPrev; + T *n=which->m_pNext; + Assert(p->m_pNext == which); + if (n) + { + Assert(n->m_pPrev==which); + n->m_pPrev=p; + } + if (pp) + { + Assert(pp->m_pNext==p); + pp->m_pNext=which; + } + else + { + head=which; // this node is the new root! + } + which->m_pNext=p; + which->m_pPrev=pp; + p->m_pNext=n; + p->m_pPrev=which; + } + ValidateDList(head); + } + + + + // removes node 'which' from doubly linked list with 'head' + template inline void RemoveFromDList(T * &head, T *which) + { + if (which->m_pPrev) + { + Assert(which->m_pPrev->m_pNext==which); + which->m_pPrev->m_pNext=which->m_pNext; + if (which->m_pNext) + { + Assert(which->m_pNext->m_pPrev==which); + which->m_pNext->m_pPrev=which->m_pPrev; + } + } + else + { + if (head==which) + { + head=which->m_pNext; + if (head) + { + Assert(head->m_pPrev==which); + head->m_pPrev=0; + } + } + } + which->m_pNext=which->m_pPrev=0; + ValidateDList(head); + + } + + //checks to see if node is in doubly linked list + template bool OnDList(T const *head, T const *which) + { + return (head==which) || (which->m_pNext !=0) || (which->m_pPrev !=0); + } + + // add a node to the end of a singly linked list + template void AddToDTail(T * & head, T * node) + { + node->m_pNext=0; + if (! head) + { + head=node; + } + else + { + T *ptr=head; + while(ptr->m_pNext) + { + ptr=ptr->m_pNext; + } + ptr->m_pNext=node; + node->m_pPrev=ptr; // + } + } + + // add a node to end of doubly linked list. + template inline void AddToDHead(T * &head, T *which) + { + which->m_pNext=head; + if (head) + { + head->m_pPrev=which; + } + which->m_pPrev=0; + head=which; + ValidateDList(head); + } + + // add a node to front of doubly linked list which maintains a tail ptr + template inline void AddToDHeadWithTailPtr(T * &head, T *which, T * &tailptr) + { + which->m_pNext=head; + if (head) + { + head->m_pPrev=which; + } + else + { + tailptr=which; + } + which->m_pPrev=0; + head=which; + ValidateDList(head); + } + + // add a node to end of doubly linked list which maintains a tail ptr + template inline void AddToDTailWithTailPtr(T * &head, T *which, T * & tailptr) + { + if (! tailptr) + { + Assert(! head); + which->m_pPrev=which->m_pNext=0; + tailptr=head=which; + } + else + { + which->m_pNext=0; + which->m_pPrev=tailptr; + tailptr->m_pNext=which; + tailptr=which; + } + ValidateDList( head ); + } + + // Remove a node from a dlist , maintaining the tail ptr. node is not 'delete' d + template inline void RemoveFromDListWithTailPtr(T * &head, T *which, T * & tailptr) + { + if (which==tailptr) + { + tailptr=which->m_pPrev; + } + if (which->m_pPrev) + { + Assert(which->m_pPrev->m_pNext==which); + which->m_pPrev->m_pNext=which->m_pNext; + if (which->m_pNext) + { + Assert(which->m_pNext->m_pPrev==which); + which->m_pNext->m_pPrev=which->m_pPrev; + } + } + else + { + if (head==which) + { + head=which->m_pNext; + if (head) + { + Assert(head->m_pPrev==which); + head->m_pPrev=0; + } + } + } + which->m_pNext=which->m_pPrev=0; + ValidateDList(head); + + } + + // this function removes a node, and delete's the node + template inline void DeleteFromDListWithTailPtr(T * &head, T *which, T * & tailptr) + { + T *tmp=which; + if (which==tailptr) + { + tailptr=which->m_pPrev; + } + if (which->m_pPrev) + { + Assert(which->m_pPrev->m_pNext==which); + which->m_pPrev->m_pNext=which->m_pNext; + if (which->m_pNext) + { + Assert(which->m_pNext->m_pPrev==which); + which->m_pNext->m_pPrev=which->m_pPrev; + } + } + else + { + if (head==which) + { + head=which->m_pNext; + if (head) + { + Assert(head->m_pPrev==which); + head->m_pPrev=0; + } + } + } + which->m_pNext=which->m_pPrev=0; + delete tmp; + ValidateDList(head); + } + + // Add a node to a d-list, keeping the highest priority nodes first. This is a simple + // linear search to insert, NOT a O(logn) heap. + template inline void AddToDPriority(T * &head, T *which) + { + T* prevnode=0; + for(T *curnode=head;curnode;curnode=curnode->m_pNext) + { + if (which->m_Priority>=curnode->m_Priority) + break; + prevnode=curnode; + } + // now, we have either run out of list, or we have found an + // element to add this one before + if (! prevnode) + { + AddToDHead(head,which); + } + else + { + which->m_pNext=prevnode->m_pNext; + prevnode->m_pNext=which; + which->m_pPrev=prevnode; + if (which->m_pNext) + which->m_pNext->m_pPrev=which; + } + } + + // same as AddToDPriority, except with reverse order + template inline void AddToDPriorityLowestFirst(T * &head, T *which) + { + T* prevnode=0; + for(T *curnode=head;curnode;curnode=curnode->m_pNext) + { + if (which->m_Priority<=curnode->m_Priority) + break; + prevnode=curnode; + } + // now, we have either run out of list, or we have found an + // element to add this one before + if (! prevnode) + { + AddToDHead(head,which); + } + else + { + which->m_pNext=prevnode->m_pNext; + prevnode->m_pNext=which; + which->m_pPrev=prevnode; + if (which->m_pNext) + which->m_pNext->m_pPrev=which; + } + } + + + // return a pointer to the last node in a singly-linked (or doubly) list + template T * LastNode(T * head) + { + if (head) + { + while(head->m_pNext) + { + head=head->m_pNext; + } + } + return head; + } + + + // Remove from a singly linked list. no delete called. + template void RemoveFromList(T * & head, V *which) + { + if (head==which) + { + head=which->m_pNext; + } + else + { + for(T * i=head; i; i=i->m_pNext) + { + if (i->m_pNext==which) + { + i->m_pNext=which->m_pNext; + return; + } + } + } + } + + // same as RemoveFromList, but 'delete' is called. + template void DeleteFromList(T * & head, V *which) + { + T *tmp; + if (head==which) + { + tmp=which->m_pNext; + delete(head); + head=tmp; + } + else + { + for(T * i=head; i; i=i->m_pNext) + { + if (i->m_pNext==which) + { + tmp=which->m_pNext; + delete(which); + i->m_pNext=tmp; + return; + } + } + } + } + + // find the position in a list of a node. -1 if not found. Linear search. + // nodes must have comparison functions + template int PositionInList(T *head, V *node) + { + int pos=0; + while(head) + { + if (head==node) return pos; + head=head->m_pNext; + pos++; + } + return -1; + } + + // find the Nth node in a list. null if index too high. + template T *NthNode(T * head, int idx) + { + while(idx && head) + { + idx--; + head=head->m_pNext; + } + return head; + } + + //Add a node to the head of a singly-linked + // Note that the head var passed to this will be modified. + template static inline void AddToHead(T * & head, V * node) + { + node->m_pNext=head; + head=node; + } + + //Add a node to the tail of a singly-linked. Not fast + // Note that the head var passed to this will be modified. + template static inline void AddToTail(T * & head, V * node) + { + node->m_pNext = NULL; + if ( ! head ) + head = node; + else + { + T *pLastNode = head; + while( pLastNode->m_pNext ) + pLastNode = pLastNode->m_pNext; + pLastNode->m_pNext = node; + } + } + + //Add a node to the head of a singly-linked list, maintaining a tail pointer + template static inline void AddToHead(T * & head, T * &tail,V * node) + { + if (! head) + { + tail=node; + } + node->m_pNext=head; + head=node; + } + + + + // return the node in head before in a singly linked list. returns null if head is empty, n is + // null, or if n is the first node. not fast. + template static inline T * PrevNode(T *head, T *node) + { + T *i; + for(i=head;i;i=i->m_pNext) + { + if (i->m_pNext == node) + break; + } + return i; + } + + + // add a node to the end of a singly linked list. Not fast. + template void AddToEnd(T * & head, V * node) + { + node->m_pNext=0; + if (! head) + { + head=node; + } + else + { + T *ptr=head; + while(ptr->m_pNext) + { + ptr=ptr->m_pNext; + } + ptr->m_pNext=node; + } + } + + // add a node to the end of a singly linked list, maintaining a tail pointer. + // the head and tail pointer can be modified by this routine. + template void AddToEndWithTail(T * & head, T * & tail,V * node) + { + Assert((head && tail) || ((!head) && (!tail))); + node->m_pNext=0; + if (! head) + { + head=tail=node; + } + else + { + tail->m_pNext=node; + tail=node; + } + } + + // Add a node to a singly linked list, sorting by the m_Name field + template void AddSortedByName(T * & head, T * node) + { + if ( (! head) || // empty list? + (stricmp(node->m_Name,head->m_Name)==-1)) // or we should be first? + { + node->m_pNext=head; // make us head + head=node; + } + else + { + T *t; + for(t=head;t->m_pNext;t=t->m_pNext) // find the node we should be before + if (stricmp(t->m_pNext->m_Name,node->m_Name)>=0) + break; + node->m_pNext=t->m_pNext; + t->m_pNext=node; + } + } + + // count # of elements in list + template int ListLength(T *head) + { + int len=0; + while(head) + { + len++; + head=head->m_pNext; + } + return len; + } + + // this will kill a list if the list is of objects which automatically + // remove themselves from the list when delete is called + template void KillList(T * & head) + { + while(head) + { + delete head; + } + } + + + // this will kill all elements in a list if + // the elements are of a type which does NOT remove itself from + // the list when the destructor is called. + template void DeleteList(T * & head) + { + while (head) + { + T* tmp=head->m_pNext; + delete head; + head=tmp; + } + } + + // find a named node in any list which has both a Next field and a Name field. + template static inline T * FindNamedNode(T * head, char const *name) + { + for(;head && stricmp(head->m_Name,name); head=head->m_pNext) + { + } + return head; + } + + template static inline T * FindNamedNodeCaseSensitive(T * head, char const *name) + { + for(;head && strcmp(head->m_Name,name); head=head->m_pNext) + { + } + return head; + } + + // find data in a singly linked list, using equality match on any field + // usage: FindNodeByField(listptr,data,&list::fieldname) + template static inline T * FindNodeByField(T * head, U data, U V::*field) + { + while(head) + { + if (data==(*head).*field) + return head; + head=head->m_pNext; + } + return 0; + } + + // find a node and its predecessor, matching on equality of a given field. + // usage: FindNodeByFieldWithPrev(listptr,data,&list::fieldname, prevptr) + template static inline T * FindNodeByFieldWithPrev(T * head, U data, U V::*field, T * & prev) + { + prev=0; + for(T *i=head; i; i=i->m_pNext) + { + if(data==(*i).*field) + return i; + prev=i; + } + prev=0; + return 0; + } + + + /// sort a list. comparefn should return 0 if the items are equal, 1 if A goes first, and -1 if A goes last. + // NOT fast. + template void SortList(T * &head, int (*comparefn)(T * a, T * b)) + { + int didswap=1; + while(didswap) + { + didswap=0; + T *prev=0; + for(T *i=head;i && i->m_pNext; i=i->m_pNext) + { + /// compare i and i+1 + int rslt=(*comparefn)(i,i->m_pNext); + if (rslt==-1) + { + /// need to swap + didswap=1; + T *newfirst=i->m_pNext; + if (prev) + { + prev->m_pNext=newfirst; + i->m_pNext=newfirst->m_pNext; + newfirst->m_pNext=i; + } + else + { + head=i->m_pNext; + i->m_pNext=newfirst->m_pNext; + newfirst->m_pNext=i; + } + i=newfirst; + } + prev=i; + } + } + } + + // sort a doubly linked list. NOt fast. + template void SortDList(T * & head, int (*comparefn)(T * a, T * b)) + { + SortList(head,comparefn); + /// now, regen prev ptrs + T *prev=0; + for(T *i=head;i;i=i->m_pNext) + { + i->m_pPrev=prev; + prev=i; + } + } + + // reverse a singly linked list. not recommended for anything other than valve programming + // interview :-) + template T *ReversedList( T * head ) + { + T * pNewHead=NULL; + while( head ) + { + T *pNext=head->m_pNext; +#ifdef INTERVIEW_QUESTION + head->m_pNext=pNewHead; + pNewHead = head; +#else + AddToHead( pNewHead, head ); +#endif + head = pNext; + } + return pNewHead; + } +}; + +// singly linked list +template class CUtlIntrusiveList +{ +public: + T *m_pHead; + + FORCEINLINE T *Head( void ) const + { + return m_pHead; + } + + FORCEINLINE CUtlIntrusiveList(void) + { + m_pHead = NULL; + } + + + FORCEINLINE void RemoveAll( void ) + { + // empty list. doesn't touch nodes at all + m_pHead = NULL; + } + FORCEINLINE void AddToHead( T * node ) + { + IntrusiveList::AddToHead( m_pHead, node ); + } + + FORCEINLINE void AddToTail( T * node ) + { + IntrusiveList::AddToTail( m_pHead, node ); + } + + void RemoveNode(T *which) + { + IntrusiveList::RemoveFromList( m_pHead, which ); + } + + // this will kill a list if the list is of objects which automatically + // remove themselves from the list when delete is called + void KillList( void ) + { + while(m_pHead) + { + delete m_pHead; + } + } + + + // return the node in head before in a singly linked list. returns null if head is empty, n is + // null, or if n is the first node. not fast. Fast for dlists + T * PrevNode(T *node) + { + return IntrusiveList::PrevNode( m_pHead, node ); + } + + int NthNode( int n ) + { + return NthNode( m_pHead, n ); + } + + // this will kill all elements in a list if + // the elements are of a type which does NOT remove itself from + // the list when the destructor is called. + void Purge( void ) + { + while (m_pHead) + { + T* tmp=m_pHead->m_pNext; + delete m_pHead; + m_pHead=tmp; + } + } + + int Count( void ) const + { + return IntrusiveList::ListLength( m_pHead ); + } + + FORCEINLINE T * FindNamedNodeCaseSensitive( char const *pName ) const + { + return IntrusiveList::FindNamedNodeCaseSensitive( m_pHead, pName ); + + } + + T *RemoveHead( void ) + { + if ( m_pHead ) + { + T *pRet = m_pHead; + m_pHead = pRet->m_pNext; + return pRet; + } + else + return NULL; + } +}; + +// doubly linked list +template class CUtlIntrusiveDList : public CUtlIntrusiveList +{ +public: + + FORCEINLINE void AddToHead( T * node ) + { + IntrusiveList::AddToDHead( CUtlIntrusiveList::m_pHead, node ); + } + FORCEINLINE void AddToTail( T * node ) + { + IntrusiveList::AddToDTail( CUtlIntrusiveList::m_pHead, node ); + } + + void RemoveNode(T *which) + { + IntrusiveList::RemoveFromDList( CUtlIntrusiveList::m_pHead, which ); + } + + T *RemoveHead( void ) + { + if ( CUtlIntrusiveList::m_pHead ) + { + T *pRet = CUtlIntrusiveList::m_pHead; + CUtlIntrusiveList::m_pHead = CUtlIntrusiveList::m_pHead->m_pNext; + if ( CUtlIntrusiveList::m_pHead ) + CUtlIntrusiveList::m_pHead->m_pPrev = NULL; + return pRet; + } + else + return NULL; + } + + T * PrevNode(T *node) + { + return ( node )?node->m_Prev:NULL; + } + +}; + +template class CUtlIntrusiveDListWithTailPtr : public CUtlIntrusiveDList +{ +public: + + T *m_pTailPtr; + + FORCEINLINE CUtlIntrusiveDListWithTailPtr( void ) : CUtlIntrusiveDList() + { + m_pTailPtr = NULL; + } + + FORCEINLINE void AddToHead( T * node ) + { + IntrusiveList::AddToDHeadWithTailPtr( CUtlIntrusiveList::m_pHead, node, m_pTailPtr ); + } + FORCEINLINE void AddToTail( T * node ) + { + IntrusiveList::AddToDTailWithTailPtr( CUtlIntrusiveList::m_pHead, node, m_pTailPtr ); + } + + void RemoveNode( T *pWhich ) + { + IntrusiveList::RemoveFromDListWithTailPtr( CUtlIntrusiveList::m_pHead, pWhich, m_pTailPtr ); + } + + void Purge( void ) + { + CUtlIntrusiveList::Purge(); + m_pTailPtr = NULL; + } + + void Kill( void ) + { + CUtlIntrusiveList::Purge(); + m_pTailPtr = NULL; + } + + T *RemoveHead( void ) + { + if ( CUtlIntrusiveDList::m_pHead ) + { + T *pRet = CUtlIntrusiveDList::m_pHead; + CUtlIntrusiveDList::m_pHead = CUtlIntrusiveDList::m_pHead->m_pNext; + if ( CUtlIntrusiveDList::m_pHead ) + CUtlIntrusiveDList::m_pHead->m_pPrev = NULL; + if (! CUtlIntrusiveDList::m_pHead ) + m_pTailPtr = NULL; + ValidateDList( CUtlIntrusiveDList::m_pHead ); + return pRet; + } + else + return NULL; + } + + T * PrevNode(T *node) + { + return ( node )?node->m_Prev:NULL; + } + +}; + +template void PrependDListWithTailToDList( CUtlIntrusiveDListWithTailPtr &src, + CUtlIntrusiveDList &dest ) +{ + if ( src.m_pHead ) + { + src.m_pTailPtr->m_pNext = dest.m_pHead; + if ( dest.m_pHead ) + dest.m_pHead->m_pPrev = src.m_pTailPtr; + dest.m_pHead = src.m_pHead; + IntrusiveList::ValidateDList( dest.m_pHead ); + } +} + +#endif diff --git a/public/tier1/utllinkedlist.h b/public/tier1/utllinkedlist.h new file mode 100644 index 0000000..46ac4a6 --- /dev/null +++ b/public/tier1/utllinkedlist.h @@ -0,0 +1,1288 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Linked list container class +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLLINKEDLIST_H +#define UTLLINKEDLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/basetypes.h" +#include "utlmemory.h" +#include "utlfixedmemory.h" +#include "utlblockmemory.h" +#include "tier0/dbg.h" + +// define to enable asserts griping about things you shouldn't be doing with multilists +// #define MULTILIST_PEDANTIC_ASSERTS 1 + +// This is a useful macro to iterate from head to tail in a linked list. +#define FOR_EACH_LL( listName, iteratorName ) \ + for( int iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) ) + +//----------------------------------------------------------------------------- +// class CUtlLinkedList: +// description: +// A lovely index-based linked list! T is the class type, I is the index +// type, which usually should be an unsigned short or smaller. However, +// you must avoid using 16- or 8-bit arithmetic on PowerPC architectures; +// therefore you should not use UtlLinkedListElem_t::I as the type of +// a local variable... ever. PowerPC integer arithmetic must be 32- or +// 64-bit only; otherwise performance plummets. +//----------------------------------------------------------------------------- + +template +struct UtlLinkedListElem_t +{ + T m_Element; + I m_Previous; + I m_Next; + +private: + // No copy constructor for these... + UtlLinkedListElem_t( const UtlLinkedListElem_t& ); +}; + + +// Class S is the storage type; the type you can use to save off indices in +// persistent memory. Class I is the iterator type, which is what should be used +// in local scopes. I defaults to be S, but be aware that on the 360, 16-bit +// arithmetic is catastrophically slow. Therefore you should try to save shorts +// in memory, but always operate on 32's or 64's in local scope. +// The ideal parameter order would be TSMI (you are more likely to override M than I) +// but since M depends on I we can't have the defaults in that order, alas. +template , I > > +class CUtlLinkedList +{ +public: + typedef T ElemType_t; + typedef S IndexType_t; // should really be called IndexStorageType_t, but that would be a huge change + typedef I IndexLocalType_t; + typedef M MemoryAllocator_t; + static const bool IsUtlLinkedList = true; // Used to match this at compiletime + + // constructor, destructor + CUtlLinkedList( int growSize = 0, int initSize = 0 ); + ~CUtlLinkedList(); + + // gets particular elements + T& Element( I i ); + T const& Element( I i ) const; + T& operator[]( I i ); + T const& operator[]( I i ) const; + + // Make sure we have a particular amount of memory + void EnsureCapacity( int num ); + + void SetGrowSize( int growSize ); + + // Memory deallocation + void Purge(); + + // Delete all the elements then call Purge. + void PurgeAndDeleteElements(); + + // Insertion methods.... + I InsertBefore( I before ); + I InsertAfter( I after ); + I AddToHead( ); + I AddToTail( ); + + I InsertBefore( I before, T const& src ); + I InsertAfter( I after, T const& src ); + I AddToHead( T const& src ); + I AddToTail( T const& src ); + + // Find an element and return its index or InvalidIndex() if it couldn't be found. + I Find( const T &src ) const; + + // Look for the element. If it exists, remove it and return true. Otherwise, return false. + bool FindAndRemove( const T &src ); + + // Removal methods + void Remove( I elem ); + void RemoveAll(); + + // Allocation/deallocation methods + // If multilist == true, then list list may contain many + // non-connected lists, and IsInList and Head + Tail are meaningless... + I Alloc( bool multilist = false ); + void Free( I elem ); + + // list modification + void LinkBefore( I before, I elem ); + void LinkAfter( I after, I elem ); + void Unlink( I elem ); + void LinkToHead( I elem ); + void LinkToTail( I elem ); + + // invalid index (M will never allocate an element at this index) + inline static S InvalidIndex() { return ( S )M::InvalidIndex(); } + + // Is a given index valid to use? (representible by S and not the invalid index) + static bool IndexInRange( I index ); + + inline static size_t ElementSize() { return sizeof( ListElem_t ); } + + // list statistics + int Count() const; + I MaxElementIndex() const; + I NumAllocated( void ) const { return m_NumAlloced; } + + // Traversing the list + I Head() const; + I Tail() const; + I Previous( I i ) const; + I Next( I i ) const; + + // STL compatible const_iterator class + template < typename List_t > + class _CUtlLinkedList_constiterator_t + { + public: + typedef typename List_t::ElemType_t ElemType_t; + typedef typename List_t::IndexType_t IndexType_t; + + // Default constructor -- gives a currently unusable iterator. + _CUtlLinkedList_constiterator_t() + : m_list( 0 ) + , m_index( List_t::InvalidIndex() ) + { + } + // Normal constructor. + _CUtlLinkedList_constiterator_t( const List_t& list, IndexType_t index ) + : m_list( &list ) + , m_index( index ) + { + } + + // Pre-increment operator++. This is the most efficient increment + // operator so it should always be used. + _CUtlLinkedList_constiterator_t& operator++() + { + m_index = m_list->Next( m_index ); + return *this; + } + // Post-increment operator++. This is less efficient than pre-increment. + _CUtlLinkedList_constiterator_t operator++(int) + { + // Copy ourselves. + _CUtlLinkedList_constiterator_t temp = *this; + // Increment ourselves. + ++*this; + // Return the copy. + return temp; + } + + // Pre-decrement operator--. This is the most efficient decrement + // operator so it should always be used. + _CUtlLinkedList_constiterator_t& operator--() + { + Assert( m_index != m_list->Head() ); + if ( m_index == m_list->InvalidIndex() ) + { + m_index = m_list->Tail(); + } + else + { + m_index = m_list->Previous( m_index ); + } + return *this; + } + // Post-decrement operator--. This is less efficient than post-decrement. + _CUtlLinkedList_constiterator_t operator--(int) + { + // Copy ourselves. + _CUtlLinkedList_constiterator_t temp = *this; + // Decrement ourselves. + --*this; + // Return the copy. + return temp; + } + + bool operator==( const _CUtlLinkedList_constiterator_t& other) const + { + Assert( m_list == other.m_list ); + return m_index == other.m_index; + } + + bool operator!=( const _CUtlLinkedList_constiterator_t& other) const + { + Assert( m_list == other.m_list ); + return m_index != other.m_index; + } + + const ElemType_t& operator*() const + { + return m_list->Element( m_index ); + } + + const ElemType_t* operator->() const + { + return (&**this); + } + + protected: + // Use a pointer rather than a reference so that we can support + // assignment of iterators. + const List_t* m_list; + IndexType_t m_index; + }; + + // STL compatible iterator class, using derivation so that a non-const + // list can return a const_iterator. + template < typename List_t > + class _CUtlLinkedList_iterator_t : public _CUtlLinkedList_constiterator_t< List_t > + { + public: + typedef typename List_t::ElemType_t ElemType_t; + typedef typename List_t::IndexType_t IndexType_t; + typedef _CUtlLinkedList_constiterator_t< List_t > Base; + + // Default constructor -- gives a currently unusable iterator. + _CUtlLinkedList_iterator_t() + { + } + // Normal constructor. + _CUtlLinkedList_iterator_t( const List_t& list, IndexType_t index ) + : _CUtlLinkedList_constiterator_t< List_t >( list, index ) + { + } + + // Pre-increment operator++. This is the most efficient increment + // operator so it should always be used. + _CUtlLinkedList_iterator_t& operator++() + { + Base::m_index = Base::m_list->Next( Base::m_index ); + return *this; + } + // Post-increment operator++. This is less efficient than pre-increment. + _CUtlLinkedList_iterator_t operator++(int) + { + // Copy ourselves. + _CUtlLinkedList_iterator_t temp = *this; + // Increment ourselves. + ++*this; + // Return the copy. + return temp; + } + + // Pre-decrement operator--. This is the most efficient decrement + // operator so it should always be used. + _CUtlLinkedList_iterator_t& operator--() + { + Assert( Base::m_index != Base::m_list->Head() ); + if ( Base::m_index == Base::m_list->InvalidIndex() ) + { + Base::m_index = Base::m_list->Tail(); + } + else + { + Base::m_index = Base::m_list->Previous( Base::m_index ); + } + return *this; + } + // Post-decrement operator--. This is less efficient than post-decrement. + _CUtlLinkedList_iterator_t operator--(int) + { + // Copy ourselves. + _CUtlLinkedList_iterator_t temp = *this; + // Decrement ourselves. + --*this; + // Return the copy. + return temp; + } + + ElemType_t& operator*() const + { + // Const_cast to allow sharing the implementation with the + // base class. + List_t* pMutableList = const_cast( Base::m_list ); + return pMutableList->Element( Base::m_index ); + } + + ElemType_t* operator->() const + { + return (&**this); + } + }; + + typedef _CUtlLinkedList_constiterator_t > const_iterator; + typedef _CUtlLinkedList_iterator_t > iterator; + const_iterator begin() const + { + return const_iterator( *this, Head() ); + } + iterator begin() + { + return iterator( *this, Head() ); + } + + const_iterator end() const + { + return const_iterator( *this, InvalidIndex() ); + } + iterator end() + { + return iterator( *this, InvalidIndex() ); + } + + // Are nodes in the list or valid? + bool IsValidIndex( I i ) const; + bool IsInList( I i ) const; + +protected: + + // What the linked list element looks like + typedef UtlLinkedListElem_t ListElem_t; + + // constructs the class + I AllocInternal( bool multilist = false ); + void ConstructList(); + + // Gets at the list element.... + ListElem_t& InternalElement( I i ) { return m_Memory[i]; } + ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; } + + // copy constructors not allowed + CUtlLinkedList( CUtlLinkedList const& list ) { Assert(0); } + + M m_Memory; + I m_Head; + I m_Tail; + I m_FirstFree; + I m_ElementCount; // The number actually in the list + I m_NumAlloced; // The number of allocated elements + typename M::Iterator_t m_LastAlloc; // the last index allocated + + // For debugging purposes; + // it's in release builds so this can be used in libraries correctly + ListElem_t *m_pElements; + + FORCEINLINE M const &Memory( void ) const + { + return m_Memory; + } + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + } + +private: + // Faster version of Next that can only be used from tested code internal + // to this class, such as Find(). It avoids the cost of checking the index + // validity, which is a big win on debug builds. + I PrivateNext( I i ) const; +}; + + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T > +class CUtlFixedLinkedList : public CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > +{ +public: + CUtlFixedLinkedList( int growSize = 0, int initSize = 0 ) + : CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >( growSize, initSize ) {} + + typedef CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > BaseClass; + bool IsValidIndex( int i ) const + { + if ( !BaseClass::Memory().IsIdxValid( i ) ) + return false; + +#ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex + if ( BaseClass::Memory().IsIdxAfter( i, this->m_LastAlloc ) ) + { + Assert( 0 ); + return false; // don't read values that have been allocated, but not constructed + } +#endif + + return ( BaseClass::Memory()[ i ].m_Previous != i ) || ( BaseClass::Memory()[ i ].m_Next == i ); + } + +private: + int MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1 + void ResetDbgInfo() {} +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = unsigned short > +class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > > +{ +public: + CUtlBlockLinkedList( int growSize = 0, int initSize = 0 ) + : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >( growSize, initSize ) {} +protected: + void ResetDbgInfo() {} +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template +CUtlLinkedList::CUtlLinkedList( int growSize, int initSize ) : + m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() ) +{ + // Prevent signed non-int datatypes + COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) ); + ConstructList(); + ResetDbgInfo(); +} + +template +CUtlLinkedList::~CUtlLinkedList( ) +{ + RemoveAll(); +} + +template +void CUtlLinkedList::ConstructList() +{ + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_FirstFree = InvalidIndex(); + m_ElementCount = 0; + m_NumAlloced = 0; +} + + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template +inline T& CUtlLinkedList::Element( I i ) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlLinkedList::Element( I i ) const +{ + return m_Memory[i].m_Element; +} + +template +inline T& CUtlLinkedList::operator[]( I i ) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlLinkedList::operator[]( I i ) const +{ + return m_Memory[i].m_Element; +} + +//----------------------------------------------------------------------------- +// list statistics +//----------------------------------------------------------------------------- + +template +inline int CUtlLinkedList::Count() const +{ +#ifdef MULTILIST_PEDANTIC_ASSERTS + AssertMsg( !ML, "CUtlLinkedList::Count() is meaningless for linked lists." ); +#endif + return m_ElementCount; +} + +template +inline I CUtlLinkedList::MaxElementIndex() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Traversing the list +//----------------------------------------------------------------------------- + +template +inline I CUtlLinkedList::Head() const +{ + return m_Head; +} + +template +inline I CUtlLinkedList::Tail() const +{ + return m_Tail; +} + +template +inline I CUtlLinkedList::Previous( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Previous; +} + +template +inline I CUtlLinkedList::Next( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Next; +} + +template +inline I CUtlLinkedList::PrivateNext( I i ) const +{ + return InternalElement(i).m_Next; +} + + +//----------------------------------------------------------------------------- +// Are nodes in the list or valid? +//----------------------------------------------------------------------------- + +#pragma warning(push) +#pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below +template +inline bool CUtlLinkedList::IndexInRange( I index ) // Static method +{ + // Since S is not necessarily the type returned by M, we need to check that M returns indices + // which are representable by S. A common case is 'S === unsigned short', 'I == int', in which + // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in S), and will + // happily return elements at index 65535 and above. + + // Do some static checks here: + // 'I' needs to be able to store 'S' + COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) ); + // 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges) + COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) ); + // M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536) + COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) ); + + return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) ); +} +#pragma warning(pop) + +template +inline bool CUtlLinkedList::IsValidIndex( I i ) const +{ + if ( !m_Memory.IsIdxValid( i ) ) + return false; + + if ( m_Memory.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return ( m_Memory[ i ].m_Previous != i ) || ( m_Memory[ i ].m_Next == i ); +} + +template +inline bool CUtlLinkedList::IsInList( I i ) const +{ + if ( !m_Memory.IsIdxValid( i ) || m_Memory.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return Previous( i ) != i; +} + +/* +template +inline bool CUtlFixedLinkedList::IsInList( int i ) const +{ + return m_Memory.IsIdxValid( i ) && (Previous( i ) != i); +} +*/ + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList::SetGrowSize( int growSize ) +{ + RemoveAll(); + m_Memory.Init( growSize ); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Deallocate memory +//----------------------------------------------------------------------------- + +template +void CUtlLinkedList::Purge() +{ + RemoveAll(); + + m_Memory.Purge(); + m_FirstFree = InvalidIndex(); + m_NumAlloced = 0; + + //Routing "m_LastAlloc = m_Memory.InvalidIterator();" through a local const to sidestep an internal compiler error on 360 builds + const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator(); + m_LastAlloc = scInvalidIterator; + ResetDbgInfo(); +} + + +template +void CUtlLinkedList::PurgeAndDeleteElements() +{ + I iNext; + for( I i=Head(); i != InvalidIndex(); i=iNext ) + { + iNext = Next(i); + delete Element(i); + } + + Purge(); +} + + +//----------------------------------------------------------------------------- +// Node allocation/deallocation +//----------------------------------------------------------------------------- +template +I CUtlLinkedList::AllocInternal( bool multilist ) +{ + Assert( !multilist || ML ); +#ifdef MULTILIST_PEDANTIC_ASSERTS + Assert( multilist == ML ); +#endif + I elem; + if ( m_FirstFree == InvalidIndex() ) + { + Assert( m_Memory.IsValidIterator( m_LastAlloc ) || m_ElementCount == 0 ); + + typename M::Iterator_t it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First(); + + if ( !m_Memory.IsValidIterator( it ) ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow(); + ResetDbgInfo(); + + it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First(); + + Assert( m_Memory.IsValidIterator( it ) ); + if ( !m_Memory.IsValidIterator( it ) ) + { + // We rarely if ever handle alloc failure. Continuing leads to corruption. + Error( "CUtlLinkedList overflow! (exhausted memory allocator)\n" ); + return InvalidIndex(); + } + } + + // We can overflow before the utlmemory overflows, since S != I + if ( !IndexInRange( m_Memory.GetIndex( it ) ) ) + { + // We rarely if ever handle alloc failure. Continuing leads to corruption. + Error( "CUtlLinkedList overflow! (exhausted index range)\n" ); + return InvalidIndex(); + } + + m_LastAlloc = it; + elem = m_Memory.GetIndex( m_LastAlloc ); + m_NumAlloced++; + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalElement( m_FirstFree ).m_Next; + } + + if ( !multilist ) + { + InternalElement( elem ).m_Next = elem; + InternalElement( elem ).m_Previous = elem; + } + else + { + InternalElement( elem ).m_Next = InvalidIndex(); + InternalElement( elem ).m_Previous = InvalidIndex(); + } + + return elem; +} + +template +I CUtlLinkedList::Alloc( bool multilist ) +{ + I elem = AllocInternal( multilist ); + if ( elem == InvalidIndex() ) + return elem; + + Construct( &Element(elem) ); + + return elem; +} + +template +void CUtlLinkedList::Free( I elem ) +{ + Assert( IsValidIndex(elem) && IndexInRange( elem ) ); + Unlink(elem); + + ListElem_t &internalElem = InternalElement(elem); + Destruct( &internalElem.m_Element ); + internalElem.m_Next = m_FirstFree; + m_FirstFree = elem; +} + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses default constructor) +//----------------------------------------------------------------------------- + +template +I CUtlLinkedList::InsertBefore( I before ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( before, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template +I CUtlLinkedList::InsertAfter( I after ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( after, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template +inline I CUtlLinkedList::AddToHead( ) +{ + return InsertAfter( InvalidIndex() ); +} + +template +inline I CUtlLinkedList::AddToTail( ) +{ + return InsertBefore( InvalidIndex() ); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses copy constructor) +//----------------------------------------------------------------------------- + +template +I CUtlLinkedList::InsertBefore( I before, T const& src ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( before, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template +I CUtlLinkedList::InsertAfter( I after, T const& src ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( after, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template +inline I CUtlLinkedList::AddToHead( T const& src ) +{ + return InsertAfter( InvalidIndex(), src ); +} + +template +inline I CUtlLinkedList::AddToTail( T const& src ) +{ + return InsertBefore( InvalidIndex(), src ); +} + + +//----------------------------------------------------------------------------- +// Removal methods +//----------------------------------------------------------------------------- + +template +I CUtlLinkedList::Find( const T &src ) const +{ + // Cache the invalidIndex to avoid two levels of function calls on each iteration. + I invalidIndex = InvalidIndex(); + for ( I i=Head(); i != invalidIndex; i = PrivateNext( i ) ) + { + if ( Element( i ) == src ) + return i; + } + return InvalidIndex(); +} + + +template +bool CUtlLinkedList::FindAndRemove( const T &src ) +{ + I i = Find( src ); + if ( i == InvalidIndex() ) + { + return false; + } + else + { + Remove( i ); + return true; + } +} + + +template +void CUtlLinkedList::Remove( I elem ) +{ + Free( elem ); +} + +template +void CUtlLinkedList::RemoveAll() +{ + // Have to do some convoluted stuff to invoke the destructor on all + // valid elements for the multilist case (since we don't have all elements + // connected to each other in a list). + + if ( m_LastAlloc == m_Memory.InvalidIterator() ) + { + Assert( m_Head == InvalidIndex() ); + Assert( m_Tail == InvalidIndex() ); + Assert( m_FirstFree == InvalidIndex() ); + Assert( m_ElementCount == 0 ); + return; + } + + if ( ML ) + { + for ( typename M::Iterator_t it = m_Memory.First(); it != m_Memory.InvalidIterator(); it = m_Memory.Next( it ) ) + { + I i = m_Memory.GetIndex( it ); + if ( IsValidIndex( i ) ) // skip elements already in the free list + { + ListElem_t &internalElem = InternalElement( i ); + Destruct( &internalElem.m_Element ); + internalElem.m_Previous = i; + internalElem.m_Next = m_FirstFree; + m_FirstFree = i; + } + + if ( it == m_LastAlloc ) + break; // don't destruct elements that haven't ever been constructed + } + } + else + { + I i = Head(); + I next; + while ( i != InvalidIndex() ) + { + next = Next( i ); + ListElem_t &internalElem = InternalElement( i ); + Destruct( &internalElem.m_Element ); + internalElem.m_Previous = i; + internalElem.m_Next = next == InvalidIndex() ? m_FirstFree : next; + i = next; + } + if ( Head() != InvalidIndex() ) + { + m_FirstFree = Head(); + } + } + + // Clear everything else out + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_ElementCount = 0; +} + + +//----------------------------------------------------------------------------- +// list modification +//----------------------------------------------------------------------------- + +template +void CUtlLinkedList::LinkBefore( I before, I elem ) +{ + Assert( IsValidIndex(elem) ); + + // Unlink it if it's in the list at the moment + Unlink(elem); + + ListElem_t * RESTRICT pNewElem = &InternalElement(elem); + + // The element *after* our newly linked one is the one we linked before. + pNewElem->m_Next = before; + + S newElem_mPrevious; // we need to hang on to this for the compairson against InvalidIndex() + // below; otherwise we get a a load-hit-store on pNewElem->m_Previous, even + // with RESTRICT + if (before == InvalidIndex()) + { + // In this case, we're linking to the end of the list, so reset the tail + newElem_mPrevious = m_Tail; + pNewElem->m_Previous = m_Tail; + m_Tail = elem; + } + else + { + // Here, we're not linking to the end. Set the prev pointer to point to + // the element we're linking. + Assert( IsInList(before) ); + ListElem_t * RESTRICT beforeElem = &InternalElement(before); + pNewElem->m_Previous = newElem_mPrevious = beforeElem->m_Previous; + beforeElem->m_Previous = elem; + } + + // Reset the head if we linked to the head of the list + if (newElem_mPrevious == InvalidIndex()) + m_Head = elem; + else + InternalElement(newElem_mPrevious).m_Next = elem; + + // one more element baby + ++m_ElementCount; +} + +template +void CUtlLinkedList::LinkAfter( I after, I elem ) +{ + Assert( IsValidIndex(elem) ); + + // Unlink it if it's in the list at the moment + if ( IsInList(elem) ) + Unlink(elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *before* our newly linked one is the one we linked after + newElem.m_Previous = after; + if (after == InvalidIndex()) + { + // In this case, we're linking to the head of the list, reset the head + newElem.m_Next = m_Head; + m_Head = elem; + } + else + { + // Here, we're not linking to the end. Set the next pointer to point to + // the element we're linking. + Assert( IsInList(after) ); + ListElem_t& afterElem = InternalElement(after); + newElem.m_Next = afterElem.m_Next; + afterElem.m_Next = elem; + } + + // Reset the tail if we linked to the tail of the list + if (newElem.m_Next == InvalidIndex()) + m_Tail = elem; + else + InternalElement(newElem.m_Next).m_Previous = elem; + + // one more element baby + ++m_ElementCount; +} + +template +void CUtlLinkedList::Unlink( I elem ) +{ + Assert( IsValidIndex(elem) ); + if (IsInList(elem)) + { + ListElem_t * RESTRICT pOldElem = &m_Memory[ elem ]; + + // If we're the first guy, reset the head + // otherwise, make our previous node's next pointer = our next + if ( pOldElem->m_Previous != InvalidIndex() ) + { + m_Memory[ pOldElem->m_Previous ].m_Next = pOldElem->m_Next; + } + else + { + m_Head = pOldElem->m_Next; + } + + // If we're the last guy, reset the tail + // otherwise, make our next node's prev pointer = our prev + if ( pOldElem->m_Next != InvalidIndex() ) + { + m_Memory[ pOldElem->m_Next ].m_Previous = pOldElem->m_Previous; + } + else + { + m_Tail = pOldElem->m_Previous; + } + + // This marks this node as not in the list, + // but not in the free list either + pOldElem->m_Previous = pOldElem->m_Next = elem; + + // One less puppy + --m_ElementCount; + } +} + +template +inline void CUtlLinkedList::LinkToHead( I elem ) +{ + LinkAfter( InvalidIndex(), elem ); +} + +template +inline void CUtlLinkedList::LinkToTail( I elem ) +{ + LinkBefore( InvalidIndex(), elem ); +} + + +//----------------------------------------------------------------------------- +// Class to drop in to replace a CUtlLinkedList that needs to be more memory agressive +//----------------------------------------------------------------------------- + +DECLARE_POINTER_HANDLE( UtlPtrLinkedListIndex_t ); // to enforce correct usage + +template < typename T > +class CUtlPtrLinkedList +{ +public: + CUtlPtrLinkedList() + : m_pFirst( NULL ), + m_nElems( 0 ) + { + COMPILE_TIME_ASSERT( sizeof(IndexType_t) == sizeof(Node_t *) ); + } + + ~CUtlPtrLinkedList() + { + RemoveAll(); + } + + typedef UtlPtrLinkedListIndex_t IndexType_t; + + T &operator[]( IndexType_t i ) + { + return (( Node_t * )i)->elem; + } + + const T &operator[]( IndexType_t i ) const + { + return (( Node_t * )i)->elem; + } + + IndexType_t AddToTail() + { + return DoInsertBefore( (IndexType_t)m_pFirst, NULL ); + } + + IndexType_t AddToTail( T const& src ) + { + return DoInsertBefore( (IndexType_t)m_pFirst, &src ); + } + + IndexType_t AddToHead() + { + IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, NULL ); + m_pFirst = ((Node_t *)result); + return result; + } + + IndexType_t AddToHead( T const& src ) + { + IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, &src ); + m_pFirst = ((Node_t *)result); + return result; + } + + IndexType_t InsertBefore( IndexType_t before ) + { + return DoInsertBefore( before, NULL ); + } + + IndexType_t InsertAfter( IndexType_t after ) + { + Node_t *pBefore = ((Node_t *)after)->next; + return DoInsertBefore( pBefore, NULL ); + } + + IndexType_t InsertBefore( IndexType_t before, T const& src ) + { + return DoInsertBefore( before, &src ); + } + + IndexType_t InsertAfter( IndexType_t after, T const& src ) + { + Node_t *pBefore = ((Node_t *)after)->next; + return DoInsertBefore( pBefore, &src ); + } + + void Remove( IndexType_t elem ) + { + Node_t *p = (Node_t *)elem; + + if ( p->pNext == p ) + { + m_pFirst = NULL; + } + else + { + if ( m_pFirst == p ) + { + m_pFirst = p->pNext; + } + p->pNext->pPrev = p->pPrev; + p->pPrev->pNext = p->pNext; + } + + delete p; + m_nElems--; + } + + void RemoveAll() + { + Node_t *p = m_pFirst; + if ( p ) + { + do + { + Node_t *pNext = p->pNext; + delete p; + p = pNext; + } while( p != m_pFirst ); + } + + m_pFirst = NULL; + m_nElems = 0; + } + + int Count() const + { + return m_nElems; + } + + IndexType_t Head() const + { + return (IndexType_t)m_pFirst; + } + + IndexType_t Next( IndexType_t i ) const + { + Node_t *p = ((Node_t *)i)->pNext; + if ( p != m_pFirst ) + { + return (IndexType_t)p; + } + return NULL; + } + + bool IsValidIndex( IndexType_t i ) const + { + Node_t *p = ((Node_t *)i); + return ( p && p->pNext && p->pPrev ); + } + + inline static IndexType_t InvalidIndex() + { + return NULL; + } +private: + + struct Node_t + { + Node_t() {} + Node_t( const T &_elem ) : elem( _elem ) {} + + T elem; + Node_t *pPrev, *pNext; + }; + + Node_t *AllocNode( const T *pCopyFrom ) + { + MEM_ALLOC_CREDIT_CLASS(); + Node_t *p; + + if ( !pCopyFrom ) + { + p = new Node_t; + } + else + { + p = new Node_t( *pCopyFrom ); + } + + return p; + } + + IndexType_t DoInsertBefore( IndexType_t before, const T *pCopyFrom ) + { + Node_t *p = AllocNode( pCopyFrom ); + Node_t *pBefore = (Node_t *)before; + if ( pBefore ) + { + p->pNext = pBefore; + p->pPrev = pBefore->pPrev; + pBefore->pPrev = p; + p->pPrev->pNext = p; + } + else + { + Assert( !m_pFirst ); + m_pFirst = p->pNext = p->pPrev = p; + } + + m_nElems++; + return (IndexType_t)p; + } + + Node_t *m_pFirst; + unsigned m_nElems; +}; + +//----------------------------------------------------------------------------- + +#endif // UTLLINKEDLIST_H diff --git a/public/tier1/utlmap.h b/public/tier1/utlmap.h new file mode 100644 index 0000000..9c08bc0 --- /dev/null +++ b/public/tier1/utlmap.h @@ -0,0 +1,252 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLMAP_H +#define UTLMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "utlrbtree.h" + +//----------------------------------------------------------------------------- +// +// Purpose: An associative container. Pretty much identical to std::map. +// +//----------------------------------------------------------------------------- + +// This is a useful macro to iterate from start to end in order in a map +#define FOR_EACH_MAP( mapName, iteratorName ) \ + for ( int iteratorName = (mapName).FirstInorder(); (mapName).IsUtlMap && iteratorName != (mapName).InvalidIndex(); iteratorName = (mapName).NextInorder( iteratorName ) ) + +// faster iteration, but in an unspecified order +#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \ + for ( int iteratorName = 0; (mapName).IsUtlMap && iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else + +struct base_utlmap_t +{ +public: + // This enum exists so that FOR_EACH_MAP and FOR_EACH_MAP_FAST cannot accidentally + // be used on a type that is not a CUtlMap. If the code compiles then all is well. + // The check for IsUtlMap being true should be free. + // Using an enum rather than a static const bool ensures that this trick works even + // with optimizations disabled on gcc. + enum CompileTimeCheck + { + IsUtlMap = 1 + }; +}; + +template +class CUtlMap : public base_utlmap_t +{ +public: + typedef K KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef bool (*LessFunc_t)( const KeyType_t &, const KeyType_t & ); + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlMap( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 ) + : m_Tree( growSize, initSize, CKeyLess( lessfunc ) ) + { + } + + CUtlMap( LessFunc_t lessfunc ) + : m_Tree( CKeyLess( lessfunc ) ) + { + } + + void EnsureCapacity( int num ) { m_Tree.EnsureCapacity( num ); } + + // gets particular elements + ElemType_t & Element( IndexType_t i ) { return m_Tree.Element( i ).elem; } + const ElemType_t & Element( IndexType_t i ) const { return m_Tree.Element( i ).elem; } + ElemType_t & operator[]( IndexType_t i ) { return m_Tree.Element( i ).elem; } + const ElemType_t & operator[]( IndexType_t i ) const { return m_Tree.Element( i ).elem; } + KeyType_t & Key( IndexType_t i ) { return m_Tree.Element( i ).key; } + const KeyType_t & Key( IndexType_t i ) const { return m_Tree.Element( i ).key; } + + + // Num elements + unsigned int Count() const { return m_Tree.Count(); } + + // Max "size" of the vector + IndexType_t MaxElement() const { return m_Tree.MaxElement(); } + + // Checks if a node is valid and in the map + bool IsValidIndex( IndexType_t i ) const { return m_Tree.IsValidIndex( i ); } + + // Checks if the map as a whole is valid + bool IsValid() const { return m_Tree.IsValid(); } + + // Invalid index + static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); } + + // Sets the less func + void SetLessFunc( LessFunc_t func ) + { + m_Tree.SetLessFunc( CKeyLess( func ) ); + } + + // Insert method (inserts in order) + IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) + { + Node_t node; + node.key = key; + node.elem = insert; + return m_Tree.Insert( node ); + } + + IndexType_t Insert( const KeyType_t &key ) + { + Node_t node; + node.key = key; + return m_Tree.Insert( node ); + } + + // Find method + IndexType_t Find( const KeyType_t &key ) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Find( dummyNode ); + } + + // Remove methods + void RemoveAt( IndexType_t i ) { m_Tree.RemoveAt( i ); } + bool Remove( const KeyType_t &key ) + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Remove( dummyNode ); + } + + void RemoveAll( ) { m_Tree.RemoveAll(); } + void Purge( ) { m_Tree.Purge(); } + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Iteration + IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); } + IndexType_t NextInorder( IndexType_t i ) const { return m_Tree.NextInorder( i ); } + IndexType_t PrevInorder( IndexType_t i ) const { return m_Tree.PrevInorder( i ); } + IndexType_t LastInorder() const { return m_Tree.LastInorder(); } + + // If you change the search key, this can be used to reinsert the + // element into the map. + void Reinsert( const KeyType_t &key, IndexType_t i ) + { + m_Tree[i].key = key; + m_Tree.Reinsert(i); + } + + IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert ) + { + IndexType_t i = Find( key ); + if ( i != InvalidIndex() ) + { + Element( i ) = insert; + return i; + } + + return Insert( key, insert ); + } + + void Swap( CUtlMap< K, T, I > &that ) + { + m_Tree.Swap( that.m_Tree ); + } + + + struct Node_t + { + Node_t() + { + } + + Node_t( const Node_t &from ) + : key( from.key ), + elem( from.elem ) + { + } + + KeyType_t key; + ElemType_t elem; + }; + + class CKeyLess + { + public: + CKeyLess( LessFunc_t lessFunc ) : m_LessFunc(lessFunc) {} + + bool operator!() const + { + return !m_LessFunc; + } + + bool operator()( const Node_t &left, const Node_t &right ) const + { + return m_LessFunc( left.key, right.key ); + } + + LessFunc_t m_LessFunc; + }; + + typedef CUtlRBTree CTree; + + CTree *AccessTree() { return &m_Tree; } + +protected: + CTree m_Tree; +}; + +//----------------------------------------------------------------------------- + +// Purges the list and calls delete on each element in it. +template< typename K, typename T, typename I > +inline void CUtlMap::PurgeAndDeleteElements() +{ + for ( I i = 0; i < MaxElement(); ++i ) + { + if ( !IsValidIndex( i ) ) + continue; + + delete Element( i ); + } + + Purge(); +} + +//----------------------------------------------------------------------------- + +// This is horrible and slow and meant to be used only when you're dealing with really +// non-time/memory-critical code and desperately want to copy a whole map element-by-element +// for whatever reason. +template < typename K, typename T, typename I > +void DeepCopyMap( const CUtlMap& pmapIn, CUtlMap *out_pmapOut ) +{ + Assert( out_pmapOut ); + + out_pmapOut->Purge(); + FOR_EACH_MAP_FAST( pmapIn, i ) + { + out_pmapOut->Insert( pmapIn.Key( i ), pmapIn.Element( i ) ); + } +} + +#endif // UTLMAP_H diff --git a/public/tier1/utlmemory.h b/public/tier1/utlmemory.h new file mode 100644 index 0000000..927aaee --- /dev/null +++ b/public/tier1/utlmemory.h @@ -0,0 +1,1077 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLMEMORY_H +#define UTLMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include +#include "tier0/platform.h" +#include "mathlib/mathlib.h" + +#include "tier0/memalloc.h" +#include "tier0/memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + + +//----------------------------------------------------------------------------- + + +#ifdef UTLMEMORY_TRACK +#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlMemory", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlMemory", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#else +#define UTLMEMORY_TRACK_ALLOC() ((void)0) +#define UTLMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, class I = int > +class CUtlMemory +{ +public: + // constructor, destructor + CUtlMemory( int nGrowSize = 0, int nInitSize = 0 ); + CUtlMemory( T* pMemory, int numElements ); + CUtlMemory( const T* pMemory, int numElements ); + ~CUtlMemory(); + + // Set the size by which the memory grows + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + class Iterator_t + { + public: + Iterator_t( I i ) : index( i ) {} + I index; + + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // element access + T& operator[]( I i ); + const T& operator[]( I i ) const; + T& Element( I i ); + const T& Element( I i ) const; + + // Can we use this index? + bool IsIdxValid( I i ) const; + + // Specify the invalid ('null') index that we'll only return on failure + static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT + static I InvalidIndex() { return INVALID_INDEX; } + + // Gets the base address (can change when adding elements!) + T* Base(); + const T* Base() const; + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ); + void SetExternalBuffer( const T* pMemory, int numElements ); + // Takes ownership of the passed memory, including freeing it when this buffer is destroyed. + void AssumeMemory( T *pMemory, int nSize ); + + // Fast swap + void Swap( CUtlMemory< T, I > &mem ); + + // Switches the buffer from an external memory buffer to a reallocatable buffer + // Will copy the current contents of the external buffer to the reallocatable buffer + void ConvertToGrowableMemory( int nGrowSize ); + + // Size + int NumAllocated() const; + int Count() const; + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements + void Purge( int numElements ); + + // is the memory externally allocated? + bool IsExternallyAllocated() const; + + // is the memory read only? + bool IsReadOnly() const; + + // Set the size by which the memory grows + void SetGrowSize( int size ); + +protected: + void ValidateGrowSize() + { +#ifdef _X360 + if ( m_nGrowSize && m_nGrowSize != EXTERNAL_BUFFER_MARKER ) + { + // Max grow size at 128 bytes on XBOX + const int MAX_GROW = 128; + if ( m_nGrowSize * sizeof(T) > MAX_GROW ) + { + m_nGrowSize = vmax( 1, MAX_GROW / sizeof(T) ); + } + } +#endif + } + + enum + { + EXTERNAL_BUFFER_MARKER = -1, + EXTERNAL_CONST_BUFFER_MARKER = -2, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, size_t SIZE, class I = int > +class CUtlMemoryFixedGrowable : public CUtlMemory< T, I > +{ + typedef CUtlMemory< T, I > BaseClass; + +public: + CUtlMemoryFixedGrowable( int nGrowSize = 0, int nInitSize = SIZE ) : BaseClass( m_pFixedMemory, SIZE ) + { + Assert( nInitSize == 0 || nInitSize == SIZE ); + m_nMallocGrowSize = nGrowSize; + } + + void Grow( int nCount = 1 ) + { + if ( this->IsExternallyAllocated() ) + { + this->ConvertToGrowableMemory( m_nMallocGrowSize ); + } + BaseClass::Grow( nCount ); + } + + void EnsureCapacity( int num ) + { + if ( CUtlMemory::m_nAllocationCount >= num ) + return; + + if ( this->IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + this->ConvertToGrowableMemory( m_nMallocGrowSize ); + } + + BaseClass::EnsureCapacity( num ); + } + +private: + int m_nMallocGrowSize; + T m_pFixedMemory[ SIZE ]; +}; + +//----------------------------------------------------------------------------- +// The CUtlMemoryFixed class: +// A fixed memory class +//----------------------------------------------------------------------------- +template< typename T, size_t SIZE, int nAlignment = 0 > +class CUtlMemoryFixed +{ +public: + // constructor, destructor + CUtlMemoryFixed( int nGrowSize = 0, int nInitSize = 0 ) { Assert( nInitSize == 0 || nInitSize == SIZE ); } + CUtlMemoryFixed( T* pMemory, int numElements ) { Assert( 0 ); } + + // Can we use this index? + // Use unsigned math to improve performance + bool IsIdxValid( int i ) const { return (size_t)i < SIZE; } + + // Specify the invalid ('null') index that we'll only return on failure + static const int INVALID_INDEX = -1; // For use with COMPILE_TIME_ASSERT + static int InvalidIndex() { return INVALID_INDEX; } + + // Gets the base address + T* Base() { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } + const T* Base() const { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } + + // element access + // Use unsigned math and inlined checks to improve performance. + T& operator[]( int i ) { Assert( (size_t)i < SIZE ); return Base()[i]; } + const T& operator[]( int i ) const { Assert( (size_t)i < SIZE ); return Base()[i]; } + T& Element( int i ) { Assert( (size_t)i < SIZE ); return Base()[i]; } + const T& Element( int i ) const { Assert( (size_t)i < SIZE ); return Base()[i]; } + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } + + // Size + int NumAllocated() const { return SIZE; } + int Count() const { return SIZE; } + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ) { Assert( 0 ); } + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ) { Assert( num <= SIZE ); } + + // Memory deallocation + void Purge() {} + + // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryFixed) + void Purge( int numElements ) { Assert( 0 ); } + + // is the memory externally allocated? + bool IsExternallyAllocated() const { return false; } + + // Set the size by which the memory grows + void SetGrowSize( int size ) {} + + class Iterator_t + { + public: + Iterator_t( int i ) : index( i ) {} + int index; + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + int GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + +private: + char m_Memory[ SIZE*sizeof(T) + nAlignment ]; +}; + +#if defined(POSIX) +// From Chris Green: Memory is a little fuzzy but I believe this class did +// something fishy with respect to msize and alignment that was OK under our +// allocator, the glibc allocator, etc but not the valgrind one (which has no +// padding because it detects all forms of head/tail overwrite, including +// writing 1 byte past a 1 byte allocation). +#define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1 +#endif + +//----------------------------------------------------------------------------- +// The CUtlMemoryConservative class: +// A dynamic memory class that tries to minimize overhead (itself small, no custom grow factor) +//----------------------------------------------------------------------------- +template< typename T > +class CUtlMemoryConservative +{ + +public: + // constructor, destructor + CUtlMemoryConservative( int nGrowSize = 0, int nInitSize = 0 ) : m_pMemory( NULL ) + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + m_nCurAllocSize = 0; +#endif + + } + CUtlMemoryConservative( T* pMemory, int numElements ) { Assert( 0 ); } + ~CUtlMemoryConservative() { if ( m_pMemory ) free( m_pMemory ); } + + // Can we use this index? + bool IsIdxValid( int i ) const { return ( IsDebug() ) ? ( i >= 0 && i < NumAllocated() ) : ( i >= 0 ); } + static int InvalidIndex() { return -1; } + + // Gets the base address + T* Base() { return m_pMemory; } + const T* Base() const { return m_pMemory; } + + // element access + T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } + + // Size + FORCEINLINE void RememberAllocSize( size_t sz ) + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + m_nCurAllocSize = sz; +#endif + } + + size_t AllocSize( void ) const + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + return m_nCurAllocSize; +#else + return ( m_pMemory ) ? g_pMemAlloc->GetSize( m_pMemory ) : 0; +#endif + } + + int NumAllocated() const + { + return AllocSize() / sizeof( T ); + } + int Count() const + { + return NumAllocated(); + } + + FORCEINLINE void ReAlloc( size_t sz ) + { + m_pMemory = (T*)realloc( m_pMemory, sz ); + RememberAllocSize( sz ); + } + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ) + { + int nCurN = NumAllocated(); + ReAlloc( ( nCurN + num ) * sizeof( T ) ); + } + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ) + { + size_t nSize = sizeof( T ) * MAX( num, Count() ); + ReAlloc( nSize ); + } + + // Memory deallocation + void Purge() + { + free( m_pMemory ); + RememberAllocSize( 0 ); + m_pMemory = NULL; + } + + // Purge all but the given number of elements + void Purge( int numElements ) { ReAlloc( numElements * sizeof(T) ); } + + // is the memory externally allocated? + bool IsExternallyAllocated() const { return false; } + + // Set the size by which the memory grows + void SetGrowSize( int size ) {} + + class Iterator_t + { + public: + Iterator_t( int i, int _limit ) : index( i ), limit( _limit ) {} + int index; + int limit; + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { int limit = NumAllocated(); return Iterator_t( limit ? 0 : InvalidIndex(), limit ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( ( it.index + 1 < it.limit ) ? it.index + 1 : InvalidIndex(), it.limit ); } + int GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ) && ( it.index < it.limit ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex(), 0 ); } + +private: + T *m_pMemory; +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + size_t m_nCurAllocSize; +#endif + +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class I > +CUtlMemory::CUtlMemory( int nGrowSize, int nInitAllocationCount ) : m_pMemory(0), + m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize ) +{ + ValidateGrowSize(); + Assert( nGrowSize >= 0 ); + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + } +} + +template< class T, class I > +CUtlMemory::CUtlMemory( T* pMemory, int numElements ) : m_pMemory(pMemory), + m_nAllocationCount( numElements ) +{ + // Special marker indicating externally supplied modifyable memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory::CUtlMemory( const T* pMemory, int numElements ) : m_pMemory( (T*)pMemory ), + m_nAllocationCount( numElements ) +{ + // Special marker indicating externally supplied modifyable memory + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory::~CUtlMemory() +{ + Purge(); +} + +template< class T, class I > +void CUtlMemory::Init( int nGrowSize /*= 0*/, int nInitSize /*= 0*/ ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + m_nAllocationCount = nInitSize; + ValidateGrowSize(); + Assert( nGrowSize >= 0 ); + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + } +} + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::Swap( CUtlMemory &mem ) +{ + V_swap( m_nGrowSize, mem.m_nGrowSize ); + V_swap( m_pMemory, mem.m_pMemory ); + V_swap( m_nAllocationCount, mem.m_nAllocationCount ); +} + + +//----------------------------------------------------------------------------- +// Switches the buffer from an external memory buffer to a reallocatable buffer +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::ConvertToGrowableMemory( int nGrowSize ) +{ + if ( !IsExternallyAllocated() ) + return; + + m_nGrowSize = nGrowSize; + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + + int nNumBytes = m_nAllocationCount * sizeof(T); + T *pMemory = (T*)malloc( nNumBytes ); + memcpy( (void*)pMemory, (void*)m_pMemory, nNumBytes ); + m_pMemory = pMemory; + } + else + { + m_pMemory = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::SetExternalBuffer( T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory::SetExternalBuffer( const T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = const_cast( pMemory ); + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory::AssumeMemory( T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + // Simply take the pointer but don't mark us as external + m_pMemory = pMemory; + m_nAllocationCount = numElements; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T, class I > +inline T& CUtlMemory::operator[]( I i ) +{ + // Avoid function calls in the asserts to improve debug build performance + Assert( m_nGrowSize != EXTERNAL_CONST_BUFFER_MARKER ); //Assert( !IsReadOnly() ); + Assert( (uint32)i < (uint32)m_nAllocationCount ); + return m_pMemory[(uint32)i]; +} + +template< class T, class I > +inline const T& CUtlMemory::operator[]( I i ) const +{ + // Avoid function calls in the asserts to improve debug build performance + Assert( (uint32)i < (uint32)m_nAllocationCount ); + return m_pMemory[(uint32)i]; +} + +template< class T, class I > +inline T& CUtlMemory::Element( I i ) +{ + // Avoid function calls in the asserts to improve debug build performance + Assert( m_nGrowSize != EXTERNAL_CONST_BUFFER_MARKER ); //Assert( !IsReadOnly() ); + Assert( (uint32)i < (uint32)m_nAllocationCount ); + return m_pMemory[(uint32)i]; +} + +template< class T, class I > +inline const T& CUtlMemory::Element( I i ) const +{ + // Avoid function calls in the asserts to improve debug build performance + Assert( (uint32)i < (uint32)m_nAllocationCount ); + return m_pMemory[(uint32)i]; +} + + +//----------------------------------------------------------------------------- +// is the memory externally allocated? +//----------------------------------------------------------------------------- +template< class T, class I > +bool CUtlMemory::IsExternallyAllocated() const +{ + return (m_nGrowSize < 0); +} + + +//----------------------------------------------------------------------------- +// is the memory read only? +//----------------------------------------------------------------------------- +template< class T, class I > +bool CUtlMemory::IsReadOnly() const +{ + return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER); +} + + +template< class T, class I > +void CUtlMemory::SetGrowSize( int nSize ) +{ + Assert( !IsExternallyAllocated() ); + Assert( nSize >= 0 ); + m_nGrowSize = nSize; + ValidateGrowSize(); +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- +template< class T, class I > +inline T* CUtlMemory::Base() +{ + Assert( !IsReadOnly() ); + return m_pMemory; +} + +template< class T, class I > +inline const T *CUtlMemory::Base() const +{ + return m_pMemory; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T, class I > +inline int CUtlMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + +template< class T, class I > +inline int CUtlMemory::Count() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T, class I > +inline bool CUtlMemory::IsIdxValid( I i ) const +{ + // If we always cast 'i' and 'm_nAllocationCount' to unsigned then we can + // do our range checking with a single comparison instead of two. This gives + // a modest speedup in debug builds. + return (uint32)i < (uint32)m_nAllocationCount; +} + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem ) +{ + if ( nGrowSize ) + { + nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize); + } + else + { + if ( !nAllocationCount ) + { + // Compute an allocation which is at least as big as a cache line... + nAllocationCount = (31 + nBytesItem) / nBytesItem; + } + + while (nAllocationCount < nNewSize) + { +#ifndef _X360 + nAllocationCount *= 2; +#else + int nNewAllocationCount = ( nAllocationCount * 9) / 8; // 12.5 % + if ( nNewAllocationCount > nAllocationCount ) + nAllocationCount = nNewAllocationCount; + else + nAllocationCount *= 2; +#endif + } + } + + return nAllocationCount; +} + +template< class T, class I > +void CUtlMemory::Grow( int num ) +{ + Assert( num > 0 ); + + if ( IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = m_nAllocationCount + num; + + UTLMEMORY_TRACK_FREE(); + + int nNewAllocationCount = UtlMemory_CalcNewAllocationCount( m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T) ); + + // if m_nAllocationRequested wraps index type I, recalculate + if ( ( int )( I )nNewAllocationCount < nAllocationRequested ) + { + if ( ( int )( I )nNewAllocationCount == 0 && ( int )( I )( nNewAllocationCount - 1 ) >= nAllocationRequested ) + { + --nNewAllocationCount; // deal w/ the common case of m_nAllocationCount == MAX_USHORT + 1 + } + else + { + if ( ( int )( I )nAllocationRequested != nAllocationRequested ) + { + // we've been asked to grow memory to a size s.t. the index type can't address the requested amount of memory + Assert( 0 ); + return; + } + while ( ( int )( I )nNewAllocationCount < nAllocationRequested ) + { + nNewAllocationCount = ( nNewAllocationCount + nAllocationRequested ) / 2; + } + } + } + + m_nAllocationCount = nNewAllocationCount; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); + Assert( m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + Assert( m_pMemory ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, class I > +inline void CUtlMemory::EnsureCapacity( int num ) +{ + if (m_nAllocationCount >= num) + return; + + if ( IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::Purge() +{ + if ( !IsExternallyAllocated() ) + { + if (m_pMemory) + { + UTLMEMORY_TRACK_FREE(); + free( (void*)m_pMemory ); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + +template< class T, class I > +void CUtlMemory::Purge( int numElements ) +{ + Assert( numElements >= 0 ); + + if( numElements > m_nAllocationCount ) + { + // Ensure this isn't a grow request in disguise. + Assert( numElements <= m_nAllocationCount ); + return; + } + + // If we have zero elements, simply do a purge: + if( numElements == 0 ) + { + Purge(); + return; + } + + if ( IsExternallyAllocated() ) + { + // Can't shrink a buffer whose memory was externally allocated, fail silently like purge + return; + } + + // If the number of elements is the same as the allocation count, we are done. + if( numElements == m_nAllocationCount ) + { + return; + } + + + if( !m_pMemory ) + { + // Allocation count is non zero, but memory is null. + Assert( m_pMemory ); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = numElements; + + UTLMEMORY_TRACK_ALLOC(); + + // Allocation count > 0, shrink it down. + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); +} + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +class CUtlMemoryAligned : public CUtlMemory +{ +public: + // constructor, destructor + CUtlMemoryAligned( int nGrowSize = 0, int nInitSize = 0 ); + CUtlMemoryAligned( T* pMemory, int numElements ); + CUtlMemoryAligned( const T* pMemory, int numElements ); + ~CUtlMemoryAligned(); + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ); + void SetExternalBuffer( const T* pMemory, int numElements ); + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryAligned) + void Purge( int numElements ) { Assert( 0 ); } + +private: + void *Align( const void *pAddr ); +}; + + +//----------------------------------------------------------------------------- +// Aligns a pointer +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void *CUtlMemoryAligned::Align( const void *pAddr ) +{ + size_t nAlignmentMask = nAlignment - 1; + return (void*)( ((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask) ); +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned( int nGrowSize, int nInitAllocationCount ) +{ + CUtlMemory::m_pMemory = 0; + CUtlMemory::m_nAllocationCount = nInitAllocationCount; + CUtlMemory::m_nGrowSize = nGrowSize; + this->ValidateGrowSize(); + + // Alignment must be a power of two + COMPILE_TIME_ASSERT( (nAlignment & (nAlignment-1)) == 0 ); + Assert( (nGrowSize >= 0) && (nGrowSize != CUtlMemory::EXTERNAL_BUFFER_MARKER) ); + if ( CUtlMemory::m_nAllocationCount ) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)_aligned_malloc( nInitAllocationCount * sizeof(T), nAlignment ); + } +} + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned( T* pMemory, int numElements ) +{ + // Special marker indicating externally supplied memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; + + CUtlMemory::m_pMemory = (T*)Align( pMemory ); + CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned( const T* pMemory, int numElements ) +{ + // Special marker indicating externally supplied memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; + + CUtlMemory::m_pMemory = (T*)Align( pMemory ); + CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned::~CUtlMemoryAligned() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned::SetExternalBuffer( T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + CUtlMemory::m_pMemory = (T*)Align( pMemory ); + CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); + + // Indicate that we don't own the memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; +} + +template< class T, int nAlignment > +void CUtlMemoryAligned::SetExternalBuffer( const T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + CUtlMemory::m_pMemory = (T*)Align( pMemory ); + CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); + + // Indicate that we don't own the memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; +} + + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned::Grow( int num ) +{ + Assert( num > 0 ); + + if ( this->IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = CUtlMemory::m_nAllocationCount + num; + + CUtlMemory::m_nAllocationCount = UtlMemory_CalcNewAllocationCount( CUtlMemory::m_nAllocationCount, CUtlMemory::m_nGrowSize, nAllocationRequested, sizeof(T) ); + + UTLMEMORY_TRACK_ALLOC(); + + if ( CUtlMemory::m_pMemory ) + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); + Assert( CUtlMemory::m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); + Assert( CUtlMemory::m_pMemory ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +inline void CUtlMemoryAligned::EnsureCapacity( int num ) +{ + if ( CUtlMemory::m_nAllocationCount >= num ) + return; + + if ( this->IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + CUtlMemory::m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if ( CUtlMemory::m_pMemory ) + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned::Purge() +{ + if ( !this->IsExternallyAllocated() ) + { + if ( CUtlMemory::m_pMemory ) + { + UTLMEMORY_TRACK_FREE(); + MemAlloc_FreeAligned( CUtlMemory::m_pMemory ); + CUtlMemory::m_pMemory = 0; + } + CUtlMemory::m_nAllocationCount = 0; + } +} + +#include "tier0/memdbgoff.h" + +#endif // UTLMEMORY_H diff --git a/public/tier1/utlmovingaverage.h b/public/tier1/utlmovingaverage.h new file mode 100644 index 0000000..b91ccb6 --- /dev/null +++ b/public/tier1/utlmovingaverage.h @@ -0,0 +1,103 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Simple moving average class +// +// $NoKeywords: $ +// +// +//=============================================================================// +#ifndef MOVING_AVERAGE_H +#define MOVING_AVERAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier0/basetypes.h" + +template class CUtlMovingAverage +{ +public: + CUtlMovingAverage() : + m_nValuesPushed( 0 ), + m_flTotal( 0.0f ) + { + } + + void Reset() + { + m_nValuesPushed = 0; + m_flTotal = 0.0f; + } + + uint32 GetTotalValuesPushed() const + { + return m_nValuesPushed; + } + + float GetAverage( ) + { + uint n = MIN( TBufferSize, m_nValuesPushed ); + return n ? ( m_flTotal / static_cast( n ) ) : 0.0f; + } + + void GetAverageAndAbsRange( float *pflOutAverage, float *pflOutAbsRange, float *pflMinTime, float *pflMaxTime ) + { + if ( m_nValuesPushed == 0 ) + { + *pflOutAverage = 0; + *pflOutAbsRange = 0; + *pflMinTime = 0; + *pflMaxTime = 0; + return; + } + + *pflOutAverage = GetAverage(); + + const int nNumValues = MIN( m_nValuesPushed, TBufferSize ); + + float flAbsRange = 0; + float flMinTime = 9e+9; + float flMaxTime = 0; + + for ( int i = 0; i < nNumValues; ++i ) + { + float flDif = ( m_Buffer[i] - *pflOutAverage ); + flAbsRange = MAX( flAbsRange, abs( flDif ) ); + flMinTime = MIN( flMinTime, m_Buffer[i] ); + flMaxTime = MAX( flMaxTime, m_Buffer[i] ); + } + + *pflOutAbsRange = flAbsRange; + *pflMinTime = flMinTime; + *pflMaxTime = flMaxTime; + } + + void PushValue( float v ) + { + uint nIndex = m_nValuesPushed % TBufferSize; + + if ( m_nValuesPushed >= TBufferSize ) + { + m_flTotal = MAX( m_flTotal - m_Buffer[nIndex], 0.0f ); + } + m_flTotal += v; + + m_Buffer[nIndex] = v; + m_nValuesPushed++; + + if ( UINT_MAX == m_nValuesPushed ) + { + Reset(); + } + } + +private: + float m_Buffer[TBufferSize]; + uint32 m_nValuesPushed; + + double m_flTotal; +}; + +#endif // MOVING_AVERAGE_H diff --git a/public/tier1/utlmultilist.h b/public/tier1/utlmultilist.h new file mode 100644 index 0000000..72a970f --- /dev/null +++ b/public/tier1/utlmultilist.h @@ -0,0 +1,771 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Multiple linked list container class +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLMULTILIST_H +#define UTLMULTILIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utllinkedlist.h" + +// memdbgon must be the last include file in a .h file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// class CUtlMultiList: +// description: +// A lovely index-based linked list! T is the class type, I is the index +// type, which usually should be an unsigned short or smaller. +// This list can contain multiple lists +//----------------------------------------------------------------------------- +template +class CUtlMultiList +{ +protected: + // What the linked list element looks like + struct ListElem_t + { + T m_Element; + I m_Previous; + I m_Next; + }; + + struct List_t + { + I m_Head; + I m_Tail; + I m_Count; + }; + + typedef CUtlMemory M; // Keep naming similar to CUtlLinkedList +public: + typedef I ListHandle_t; + + // constructor, destructor + CUtlMultiList( int growSize = 0, int initSize = 0 ); + CUtlMultiList( void *pMemory, int memsize ); + ~CUtlMultiList( ); + + // gets particular elements + T& Element( I i ); + T const& Element( I i ) const; + T& operator[]( I i ); + T const& operator[]( I i ) const; + + // Make sure we have a particular amount of memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // List Creation/deletion + ListHandle_t CreateList(); + void DestroyList( ListHandle_t list ); + bool IsValidList( ListHandle_t list ) const; + + // Insertion methods (call default constructor).... + I InsertBefore( ListHandle_t list, I before ); + I InsertAfter( ListHandle_t list, I after ); + I AddToHead( ListHandle_t list ); + I AddToTail( ListHandle_t list ); + + // Insertion methods (call copy constructor).... + I InsertBefore( ListHandle_t list, I before, T const& src ); + I InsertAfter( ListHandle_t list, I after, T const& src ); + I AddToHead( ListHandle_t list, T const& src ); + I AddToTail( ListHandle_t list, T const& src ); + + // Removal methods + void Remove( ListHandle_t list, I elem ); + + // Removes all items in a single list + void RemoveAll( ListHandle_t list ); + + // Removes all items in all lists + void RemoveAll(); + + // Allocation/deallocation methods + // NOTE: To free, it must *not* be in a list! + I Alloc( ); + void Free( I elem ); + + // list modification + void LinkBefore( ListHandle_t list, I before, I elem ); + void LinkAfter( ListHandle_t list, I after, I elem ); + void Unlink( ListHandle_t list, I elem ); + void LinkToHead( ListHandle_t list, I elem ); + void LinkToTail( ListHandle_t list, I elem ); + + // invalid index + static I InvalidIndex() { return (I)~0; } + static bool IndexInRange( int index ); + static size_t ElementSize() { return sizeof(ListElem_t); } + + // list statistics + int Count( ListHandle_t list ) const; + int TotalCount( ) const; + I MaxElementIndex() const; + + // Traversing the list + I Head( ListHandle_t list ) const; + I Tail( ListHandle_t list ) const; + I Previous( I element ) const; + I Next( I element ) const; + + // Are nodes in a list or valid? + bool IsValidIndex( I i ) const; + bool IsInList( I i ) const; + +protected: + // constructs the class + void ConstructList( ); + + // Gets at the list element.... + ListElem_t& InternalElement( I i ) { return m_Memory[i]; } + ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; } + + // A test for debug mode only... + bool IsElementInList( ListHandle_t list, I elem ) const; + + // copy constructors not allowed + CUtlMultiList( CUtlMultiList const& list ) { Assert(0); } + + M m_Memory; + CUtlLinkedList m_List; + I* m_pElementList; + + I m_FirstFree; + I m_TotalElements; + int m_MaxElementIndex; // The number allocated (use int so we can catch overflow) + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + +#ifdef _DEBUG + // Allocate space for the element list (which list is each element in) + if (m_Memory.NumAllocated() > 0) + { + if (!m_pElementList) + { + m_pElementList = (I*)malloc( m_Memory.NumAllocated() * sizeof(I) ); + } + else + { + m_pElementList = (I*)realloc( m_pElementList, m_Memory.NumAllocated() * sizeof(I) ); + } + } +#endif + } + + // For debugging purposes; + // it's in release builds so this can be used in libraries correctly + ListElem_t *m_pElements; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template +CUtlMultiList::CUtlMultiList( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_pElementList(0) +{ + ConstructList(); +} + +template +CUtlMultiList::CUtlMultiList( void* pMemory, int memsize ) : + m_Memory((ListElem_t *)pMemory, memsize/sizeof(ListElem_t)), m_pElementList(0) +{ + ConstructList(); +} + +template +CUtlMultiList::~CUtlMultiList( ) +{ + RemoveAll(); + if (m_pElementList) + free(m_pElementList); +} + +template +void CUtlMultiList::ConstructList( ) +{ + m_FirstFree = InvalidIndex(); + m_TotalElements = 0; + m_MaxElementIndex = 0; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- +template +inline T& CUtlMultiList::Element( I i ) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlMultiList::Element( I i ) const +{ + return m_Memory[i].m_Element; +} + +template +inline T& CUtlMultiList::operator[]( I i ) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlMultiList::operator[]( I i ) const +{ + return m_Memory[i].m_Element; +} + + +//----------------------------------------------------------------------------- +// list creation/destruction +//----------------------------------------------------------------------------- +template +typename CUtlMultiList::ListHandle_t CUtlMultiList::CreateList() +{ + ListHandle_t l = m_List.AddToTail(); + m_List[l].m_Head = m_List[l].m_Tail = InvalidIndex(); + m_List[l].m_Count = 0; + return l; +} + +template +void CUtlMultiList::DestroyList( ListHandle_t list ) +{ + Assert( IsValidList(list) ); + RemoveAll( list ); + m_List.Remove(list); +} + +template +bool CUtlMultiList::IsValidList( ListHandle_t list ) const +{ + return m_List.IsValidIndex(list); +} + + +//----------------------------------------------------------------------------- +// list statistics +//----------------------------------------------------------------------------- +template +inline int CUtlMultiList::TotalCount() const +{ + return m_TotalElements; +} + +template +inline int CUtlMultiList::Count( ListHandle_t list ) const +{ + Assert( IsValidList(list) ); + return m_List[list].m_Count; +} + +template +inline I CUtlMultiList::MaxElementIndex() const +{ + return m_MaxElementIndex; +} + + +//----------------------------------------------------------------------------- +// Traversing the list +//----------------------------------------------------------------------------- +template +inline I CUtlMultiList::Head(ListHandle_t list) const +{ + Assert( IsValidList(list) ); + return m_List[list].m_Head; +} + +template +inline I CUtlMultiList::Tail(ListHandle_t list) const +{ + Assert( IsValidList(list) ); + return m_List[list].m_Tail; +} + +template +inline I CUtlMultiList::Previous( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Previous; +} + +template +inline I CUtlMultiList::Next( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Next; +} + + +//----------------------------------------------------------------------------- +// Are nodes in the list or valid? +//----------------------------------------------------------------------------- + +template +inline bool CUtlMultiList::IndexInRange( int index ) // Static method +{ + // Since I is not necessarily the type returned by M (int), we need to check that M returns + // indices which are representable by I. A common case is 'I === unsigned short', in which case + // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in I), and will + // happily return elements at index 65535 and above. + + // Do a couple of static checks here: the invalid index should be (I)~0 given how we use m_MaxElementIndex, + // and 'I' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges). + COMPILE_TIME_ASSERT( (I)M::INVALID_INDEX == (I)~0 ); + COMPILE_TIME_ASSERT( ( sizeof(I) > 2 ) || ( ( (I)-1 ) > 0 ) ); + + return ( ( (I)index == index ) && ( (I)index != InvalidIndex() ) ); +} + +template +inline bool CUtlMultiList::IsValidIndex( I i ) const +{ + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + + return (i < m_MaxElementIndex) && (x >= 0) && + ((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i)); +} + +template +inline bool CUtlMultiList::IsInList( I i ) const +{ + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + return (i < m_MaxElementIndex) && (x >= 0) && (Previous(i) != i); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMultiList::EnsureCapacity( int num ) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Deallocate memory +//----------------------------------------------------------------------------- +template +void CUtlMultiList::Purge() +{ + RemoveAll(); + m_List.Purge(); + m_Memory.Purge( ); + m_List.Purge(); + m_FirstFree = InvalidIndex(); + m_TotalElements = 0; + m_MaxElementIndex = 0; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Node allocation/deallocation +//----------------------------------------------------------------------------- +template +I CUtlMultiList::Alloc( ) +{ + I elem; + if (m_FirstFree == InvalidIndex()) + { + // We can overflow before the utlmemory overflows, since we have have I != int + if ( !IndexInRange( m_MaxElementIndex ) ) + { + // We rarely if ever handle alloc failure. Continuing leads to corruption. + Error( "CUtlMultiList overflow! (exhausted index range)\n" ); + return InvalidIndex(); + } + + // Nothing in the free list; add. + // Since nothing is in the free list, m_TotalElements == total # of elements + // the list knows about. + if (m_MaxElementIndex == m_Memory.NumAllocated()) + { + m_Memory.Grow(); + ResetDbgInfo(); + + if ( m_MaxElementIndex >= m_Memory.NumAllocated() ) + { + // We rarely if ever handle alloc failure. Continuing leads to corruption. + Error( "CUtlMultiList overflow! (exhausted memory allocator)\n" ); + return InvalidIndex(); + } + } + + elem = (I)m_MaxElementIndex; + ++m_MaxElementIndex; + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalElement(m_FirstFree).m_Next; + } + + // Mark the element as not being in a list + InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem; + + ++m_TotalElements; + + Construct( &Element(elem) ); + + return elem; +} + +template +void CUtlMultiList::Free( I elem ) +{ + Assert( IsValidIndex(elem) && !IsInList(elem) ); + Destruct( &Element(elem) ); + InternalElement(elem).m_Next = m_FirstFree; + m_FirstFree = elem; + --m_TotalElements; +} + + +//----------------------------------------------------------------------------- +// A test for debug mode only... +//----------------------------------------------------------------------------- +template +inline bool CUtlMultiList::IsElementInList( ListHandle_t list, I elem ) const +{ + if (!m_pElementList) + return true; + + return m_pElementList[elem] == list; +} + + +//----------------------------------------------------------------------------- +// list modification +//----------------------------------------------------------------------------- +template +void CUtlMultiList::LinkBefore( ListHandle_t list, I before, I elem ) +{ + Assert( IsValidIndex(elem) && IsValidList(list) ); + + // Unlink it if it's in the list at the moment + Unlink(list, elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *after* our newly linked one is the one we linked before. + newElem.m_Next = before; + + if (before == InvalidIndex()) + { + // In this case, we're linking to the end of the list, so reset the tail + newElem.m_Previous = m_List[list].m_Tail; + m_List[list].m_Tail = elem; + } + else + { + // Here, we're not linking to the end. Set the prev pointer to point to + // the element we're linking. + Assert( IsInList(before) ); + ListElem_t& beforeElem = InternalElement(before); + newElem.m_Previous = beforeElem.m_Previous; + beforeElem.m_Previous = elem; + } + + // Reset the head if we linked to the head of the list + if (newElem.m_Previous == InvalidIndex()) + m_List[list].m_Head = elem; + else + InternalElement(newElem.m_Previous).m_Next = elem; + + // one more element baby + ++m_List[list].m_Count; + + // Store the element into the list + if (m_pElementList) + m_pElementList[elem] = list; +} + +template +void CUtlMultiList::LinkAfter( ListHandle_t list, I after, I elem ) +{ + Assert( IsValidIndex(elem) ); + + // Unlink it if it's in the list at the moment + Unlink(list, elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *before* our newly linked one is the one we linked after + newElem.m_Previous = after; + if (after == InvalidIndex()) + { + // In this case, we're linking to the head of the list, reset the head + newElem.m_Next = m_List[list].m_Head; + m_List[list].m_Head = elem; + } + else + { + // Here, we're not linking to the end. Set the next pointer to point to + // the element we're linking. + Assert( IsInList(after) ); + ListElem_t& afterElem = InternalElement(after); + newElem.m_Next = afterElem.m_Next; + afterElem.m_Next = elem; + } + + // Reset the tail if we linked to the tail of the list + if (newElem.m_Next == InvalidIndex()) + m_List[list].m_Tail = elem; + else + InternalElement(newElem.m_Next).m_Previous = elem; + + // one more element baby + ++m_List[list].m_Count; + + // Store the element into the list + if (m_pElementList) + m_pElementList[elem] = list; +} + +template +void CUtlMultiList::Unlink( ListHandle_t list, I elem ) +{ + Assert( IsValidIndex(elem) && IsValidList(list) ); + + if (IsInList(elem)) + { + // Make sure the element is in the right list + Assert( IsElementInList( list, elem ) ); + ListElem_t& oldElem = InternalElement(elem); + + // If we're the first guy, reset the head + // otherwise, make our previous node's next pointer = our next + if (oldElem.m_Previous != InvalidIndex()) + InternalElement(oldElem.m_Previous).m_Next = oldElem.m_Next; + else + m_List[list].m_Head = oldElem.m_Next; + + // If we're the last guy, reset the tail + // otherwise, make our next node's prev pointer = our prev + if (oldElem.m_Next != InvalidIndex()) + InternalElement(oldElem.m_Next).m_Previous = oldElem.m_Previous; + else + m_List[list].m_Tail = oldElem.m_Previous; + + // This marks this node as not in the list, + // but not in the free list either + oldElem.m_Previous = oldElem.m_Next = elem; + + // One less puppy + --m_List[list].m_Count; + + // Store the element into the list + if (m_pElementList) + m_pElementList[elem] = m_List.InvalidIndex(); + } +} + +template +inline void CUtlMultiList::LinkToHead( ListHandle_t list, I elem ) +{ + LinkAfter( list, InvalidIndex(), elem ); +} + +template +inline void CUtlMultiList::LinkToTail( ListHandle_t list, I elem ) +{ + LinkBefore( list, InvalidIndex(), elem ); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses default constructor) +//----------------------------------------------------------------------------- +template +I CUtlMultiList::InsertBefore( ListHandle_t list, I before ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( list, before, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template +I CUtlMultiList::InsertAfter( ListHandle_t list, I after ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( list, after, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template +inline I CUtlMultiList::AddToHead( ListHandle_t list ) +{ + return InsertAfter( list, InvalidIndex() ); +} + +template +inline I CUtlMultiList::AddToTail( ListHandle_t list ) +{ + return InsertBefore( list, InvalidIndex() ); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses copy constructor) +//----------------------------------------------------------------------------- +template +I CUtlMultiList::InsertBefore( ListHandle_t list, I before, T const& src ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( list, before, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template +I CUtlMultiList::InsertAfter( ListHandle_t list, I after, T const& src ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( list, after, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template +inline I CUtlMultiList::AddToHead( ListHandle_t list, T const& src ) +{ + return InsertAfter( list, InvalidIndex(), src ); +} + +template +inline I CUtlMultiList::AddToTail( ListHandle_t list, T const& src ) +{ + return InsertBefore( list, InvalidIndex(), src ); +} + + +//----------------------------------------------------------------------------- +// Removal methods +//----------------------------------------------------------------------------- +template +void CUtlMultiList::Remove( ListHandle_t list, I elem ) +{ + if (IsInList(elem)) + Unlink(list, elem); + Free( elem ); +} + +// Removes all items in a single list +template +void CUtlMultiList::RemoveAll( ListHandle_t list ) +{ + Assert( IsValidList(list) ); + I i = Head(list); + I next; + while( i != InvalidIndex() ) + { + next = Next(i); + Remove(list, i); + i = next; + } +} + + +template +void CUtlMultiList::RemoveAll() +{ + if (m_MaxElementIndex == 0) + return; + + // Put everything into the free list + I prev = InvalidIndex(); + for (int i = (int)m_MaxElementIndex; --i >= 0; ) + { + // Invoke the destructor + if (IsValidIndex((I)i)) + Destruct( &Element((I)i) ); + + // next points to the next free list item + InternalElement((I)i).m_Next = prev; + + // Indicates it's in the free list + InternalElement((I)i).m_Previous = (I)i; + prev = (I)i; + } + + // First free points to the first element + m_FirstFree = 0; + + // Clear everything else out + for (I list = m_List.Head(); list != m_List.InvalidIndex(); list = m_List.Next(list) ) + { + m_List[list].m_Head = InvalidIndex(); + m_List[list].m_Tail = InvalidIndex(); + m_List[list].m_Count = 0; + } + + m_TotalElements = 0; +} + + +#include "tier0/memdbgoff.h" + +#endif // UTLMULTILIST_H diff --git a/public/tier1/utlntree.h b/public/tier1/utlntree.h new file mode 100644 index 0000000..463b5e1 --- /dev/null +++ b/public/tier1/utlntree.h @@ -0,0 +1,624 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: N-way tree container class +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLNTREE_H +#define UTLNTREE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "utlmemory.h" +#include "tier0/dbg.h" + + +#define INVALID_NTREE_IDX ((I)~0) + +//----------------------------------------------------------------------------- +// class CUtlNTree: +// description: +// A lovely index-based linked list! T is the class type, I is the index +// type, which usually should be an unsigned short or smaller. +//----------------------------------------------------------------------------- +template +class CUtlNTree +{ +public: + typedef T ElemType_t; + typedef I IndexType_t; + + // constructor, destructor + CUtlNTree( int growSize = 0, int initSize = 0 ); + CUtlNTree( void *pMemory, int memsize ); + ~CUtlNTree( ); + + // gets particular elements + T& Element( I i ); + const T& Element( I i ) const; + T& operator[]( I i ); + const T& operator[]( I i ) const; + + // Make sure we have a particular amount of memory + void EnsureCapacity( int num ); + + // Clears the tree, doesn't deallocate memory + void RemoveAll(); + + // Memory deallocation + void Purge(); + + // Allocation/deallocation methods + I Alloc( ); + void Free( I elem ); + void FreeSubTree( I elem ); + + // list modification + void SetRoot( I root ); + void LinkChildBefore( I parent, I before, I elem ); + void LinkChildAfter( I parent, I after, I elem ); + void Unlink( I elem ); + + // Alloc + link combined + I InsertChildBefore( I parent, I before ); + I InsertChildAfter( I parent, I after ); + I InsertChildBefore( I parent, I before, const T &elem ); + I InsertChildAfter( I parent, I after, const T &elem ); + + // Unlink + free combined + void Remove( I elem ); + void RemoveSubTree( I elem ); + + // invalid index + inline static I InvalidIndex() { return INVALID_NTREE_IDX; } + inline static size_t ElementSize() { return sizeof(Node_t); } + + // list statistics + int Count() const; + I MaxElementIndex() const; + + // Traversing the list + I Root() const; + I FirstChild( I i ) const; + I PrevSibling( I i ) const; + I NextSibling( I i ) const; + I Parent( I i ) const; + + // Are nodes in the list or valid? + bool IsValidIndex( I i ) const; + bool IsInTree( I i ) const; + +protected: + // What the linked list element looks like + struct Node_t + { + T m_Element; + I m_Parent; + I m_FirstChild; + I m_PrevSibling; + I m_NextSibling; + + private: + // No copy constructor for these... + Node_t( const Node_t& ); + }; + + // constructs the class + void ConstructList(); + + // Allocates the element, doesn't call the constructor + I AllocInternal(); + + // Gets at the node element.... + Node_t& InternalNode( I i ) { return m_Memory[i]; } + const Node_t& InternalNode( I i ) const { return m_Memory[i]; } + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + } + + // copy constructors not allowed + CUtlNTree( CUtlNTree const& tree ) { Assert(0); } + + CUtlMemory m_Memory; + I m_Root; + I m_FirstFree; + I m_ElementCount; // The number actually in the tree + I m_MaxElementIndex; // The max index we've ever assigned + + // For debugging purposes; + // it's in release builds so this can be used in libraries correctly + Node_t *m_pElements; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template +CUtlNTree::CUtlNTree( int growSize, int initSize ) : + m_Memory(growSize, initSize) +{ + ConstructList(); + ResetDbgInfo(); +} + +template +CUtlNTree::CUtlNTree( void* pMemory, int memsize ) : + m_Memory(pMemory, memsize/sizeof(T)) +{ + ConstructList(); + ResetDbgInfo(); +} + +template +CUtlNTree::~CUtlNTree( ) +{ + RemoveAll(); +} + +template +void CUtlNTree::ConstructList() +{ + m_Root = InvalidIndex(); + m_FirstFree = InvalidIndex(); + m_ElementCount = m_MaxElementIndex = 0; +} + + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- +template +inline T& CUtlNTree::Element( I i ) +{ + return m_Memory[i].m_Element; +} + +template +inline const T& CUtlNTree::Element( I i ) const +{ + return m_Memory[i].m_Element; +} + +template +inline T& CUtlNTree::operator[]( I i ) +{ + return m_Memory[i].m_Element; +} + +template +inline const T& CUtlNTree::operator[]( I i ) const +{ + return m_Memory[i].m_Element; +} + + +//----------------------------------------------------------------------------- +// list statistics +//----------------------------------------------------------------------------- +template +inline int CUtlNTree::Count() const +{ + return m_ElementCount; +} + +template +inline I CUtlNTree::MaxElementIndex() const +{ + return m_MaxElementIndex; +} + + +//----------------------------------------------------------------------------- +// Traversing the list +//----------------------------------------------------------------------------- +template +inline I CUtlNTree::Root() const +{ + return m_Root; +} + +template +inline I CUtlNTree::FirstChild( I i ) const +{ + Assert( IsInTree(i) ); + return InternalNode(i).m_FirstChild; +} + +template +inline I CUtlNTree::PrevSibling( I i ) const +{ + Assert( IsInTree(i) ); + return InternalNode(i).m_PrevSibling; +} + +template +inline I CUtlNTree::NextSibling( I i ) const +{ + Assert( IsInTree(i) ); + return InternalNode(i).m_NextSibling; +} + +template +inline I CUtlNTree::Parent( I i ) const +{ + Assert( IsInTree(i) ); + return InternalNode(i).m_Parent; +} + + +//----------------------------------------------------------------------------- +// Are nodes in the list or valid? +//----------------------------------------------------------------------------- +template +inline bool CUtlNTree::IsValidIndex( I i ) const +{ + return (i < m_MaxElementIndex) && (i >= 0); +} + +template +inline bool CUtlNTree::IsInTree( I i ) const +{ + return (i < m_MaxElementIndex) && (i >= 0) && (InternalNode(i).m_PrevSibling != i); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlNTree::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Deallocate memory +//----------------------------------------------------------------------------- +template +void CUtlNTree::Purge() +{ + RemoveAll(); + m_Memory.Purge( ); + m_FirstFree = InvalidIndex(); + m_MaxElementIndex = 0; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Node allocation/deallocation +//----------------------------------------------------------------------------- +template +I CUtlNTree::AllocInternal( ) +{ + I elem; + if ( m_FirstFree == INVALID_NTREE_IDX ) + { + // Nothing in the free list; add. + // Since nothing is in the free list, m_MaxElementIndex == total # of elements + // the list knows about. + if ((int)m_MaxElementIndex == m_Memory.NumAllocated()) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow(); + } + + Assert( m_MaxElementIndex != INVALID_NTREE_IDX ); + + elem = (I)m_MaxElementIndex; + ++m_MaxElementIndex; + + if ( elem == InvalidIndex() ) + { + Error("CUtlNTree overflow!\n"); + } + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalNode( m_FirstFree ).m_NextSibling; + } + + Node_t &node = InternalNode( elem ); + node.m_NextSibling = node.m_PrevSibling = node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX; + ResetDbgInfo(); + + // one more element baby + ++m_ElementCount; + + return elem; +} + +template +I CUtlNTree::Alloc( ) +{ + I elem = AllocInternal(); + Construct( &Element(elem) ); + return elem; +} + +template +void CUtlNTree::Free( I elem ) +{ + Assert( IsInTree( elem ) ); + Unlink( elem ); + + // If there's children, this will result in leaks. Use FreeSubTree instead. + Assert( FirstChild( elem ) == INVALID_NTREE_IDX ); + + Node_t &node = InternalNode( elem ); + Destruct( &node.m_Element ); + node.m_NextSibling = m_FirstFree; + node.m_PrevSibling = elem; // Marks it as being in the free list + node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX; + m_FirstFree = elem; + + // one less element baby + --m_ElementCount; +} + +template +void CUtlNTree::FreeSubTree( I elem ) +{ + Assert( IsValidIndex( elem ) ); + + I child = FirstChild( elem ); + while ( child != INVALID_NTREE_IDX ) + { + I next = NextSibling( child ); + FreeSubTree( child ); + child = next; + } + + Free( elem ); +} + + +//----------------------------------------------------------------------------- +// Clears the tree +//----------------------------------------------------------------------------- +template +void CUtlNTree::RemoveAll() +{ + if ( m_MaxElementIndex == 0 ) + return; + + // Put everything into the free list (even unlinked things ) + I prev = InvalidIndex(); + for (int i = (int)m_MaxElementIndex; --i >= 0; prev = (I)i ) + { + Node_t &node = InternalNode( i ); + if ( IsInTree( i ) ) + { + Destruct( &node.m_Element ); + } + + node.m_NextSibling = prev; + node.m_PrevSibling = (I)i; // Marks it as being in the free list + node.m_Parent = node.m_FirstChild = INVALID_NTREE_IDX; + } + + // First free points to the first element + m_FirstFree = 0; + + // Clear everything else out + m_Root = INVALID_NTREE_IDX; + m_ElementCount = 0; +} + + +//----------------------------------------------------------------------------- +// list modification +//----------------------------------------------------------------------------- +template +void CUtlNTree::SetRoot( I root ) +{ + // Resetting the root while it's got stuff in it is bad... + Assert( m_Root == InvalidIndex() ); + m_Root = root; +} + + +//----------------------------------------------------------------------------- +// Links a node after a particular node +//----------------------------------------------------------------------------- +template +void CUtlNTree::LinkChildAfter( I parent, I after, I elem ) +{ + Assert( IsInTree(elem) ); + + // Unlink it if it's in the list at the moment + Unlink(elem); + + Node_t& newElem = InternalNode(elem); + newElem.m_Parent = parent; + newElem.m_PrevSibling = after; + if ( after != INVALID_NTREE_IDX ) + { + Node_t& prevSiblingNode = InternalNode( after ); + newElem.m_NextSibling = prevSiblingNode.m_NextSibling; + prevSiblingNode.m_NextSibling = elem; + } + else + { + if ( parent != INVALID_NTREE_IDX ) + { + Node_t& parentNode = InternalNode( parent ); + newElem.m_NextSibling = parentNode.m_FirstChild; + parentNode.m_FirstChild = elem; + } + else + { + newElem.m_NextSibling = m_Root; + if ( m_Root != INVALID_NTREE_IDX ) + { + Node_t& rootNode = InternalNode( m_Root ); + rootNode.m_PrevSibling = elem; + } + m_Root = elem; + } + } + + if ( newElem.m_NextSibling != INVALID_NTREE_IDX ) + { + Node_t& nextSiblingNode = InternalNode( newElem.m_NextSibling ); + nextSiblingNode.m_PrevSibling = elem; + } +} + + +//----------------------------------------------------------------------------- +// Links a node before a particular node +//----------------------------------------------------------------------------- +template +void CUtlNTree::LinkChildBefore( I parent, I before, I elem ) +{ + Assert( IsValidIndex(elem) ); + + if ( before != INVALID_NTREE_IDX ) + { + LinkChildAfter( parent, InternalNode( before ).m_PrevSibling, elem ); + return; + } + + // NOTE: I made the choice to do an O(n) operation here + // instead of store more data per node (LastChild). + // This might not be the right choice. Revisit if we get perf problems. + I after; + if ( parent != INVALID_NTREE_IDX ) + { + after = InternalNode( parent ).m_FirstChild; + } + else + { + after = m_Root; + } + + if ( after == INVALID_NTREE_IDX ) + { + LinkChildAfter( parent, after, elem ); + return; + } + + I next = InternalNode( after ).m_NextSibling; + while ( next != InvalidIndex() ) + { + after = next; + next = InternalNode( next ).m_NextSibling; + } + + LinkChildAfter( parent, after, elem ); +} + + +//----------------------------------------------------------------------------- +// Unlinks a node from the tree +//----------------------------------------------------------------------------- +template +void CUtlNTree::Unlink( I elem ) +{ + Assert( IsInTree(elem) ); + + Node_t *pOldNode = &InternalNode( elem ); + + // If we're the first guy, reset the head + // otherwise, make our previous node's next pointer = our next + if ( pOldNode->m_PrevSibling != INVALID_NTREE_IDX ) + { + InternalNode( pOldNode->m_PrevSibling ).m_NextSibling = pOldNode->m_NextSibling; + } + else + { + if ( pOldNode->m_Parent != INVALID_NTREE_IDX ) + { + InternalNode( pOldNode->m_Parent ).m_FirstChild = pOldNode->m_NextSibling; + } + else if ( m_Root == elem ) + { + m_Root = pOldNode->m_NextSibling; + } + } + + // If we're the last guy, reset the tail + // otherwise, make our next node's prev pointer = our prev + if ( pOldNode->m_NextSibling != INVALID_NTREE_IDX ) + { + InternalNode( pOldNode->m_NextSibling ).m_PrevSibling = pOldNode->m_PrevSibling; + } + + // Unlink everything except children + pOldNode->m_Parent = pOldNode->m_PrevSibling = pOldNode->m_NextSibling = INVALID_NTREE_IDX; +} + + +//----------------------------------------------------------------------------- +// Alloc + link combined +//----------------------------------------------------------------------------- +template +I CUtlNTree::InsertChildBefore( I parent, I before ) +{ + I elem = AllocInternal(); + Construct( &Element( elem ) ); + LinkChildBefore( parent, before, elem ); + return elem; +} + +template +I CUtlNTree::InsertChildAfter( I parent, I after ) +{ + I elem = AllocInternal(); + Construct( &Element( elem ) ); + LinkChildAfter( parent, after, elem ); + return elem; +} + +template +I CUtlNTree::InsertChildBefore( I parent, I before, const T &data ) +{ + I elem = AllocInternal(); + CopyConstruct( &Element( elem ), data ); + LinkChildBefore( parent, before, elem ); + return elem; +} + +template +I CUtlNTree::InsertChildAfter( I parent, I after, const T &data ) +{ + I elem = AllocInternal(); + CopyConstruct( &Element( elem ), data ); + LinkChildAfter( parent, after, elem ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Unlink + free combined +//----------------------------------------------------------------------------- +template +void CUtlNTree::Remove( I elem ) +{ + Unlink( elem ); + Free( elem ); +} + +template +void CUtlNTree::RemoveSubTree( I elem ) +{ + UnlinkSubTree( elem ); + Free( elem ); +} + + +#endif // UTLNTREE_H diff --git a/public/tier1/utlobjectreference.h b/public/tier1/utlobjectreference.h new file mode 100644 index 0000000..da9d303 --- /dev/null +++ b/public/tier1/utlobjectreference.h @@ -0,0 +1,165 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// $Revision: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef UTLOBJECTREFERENCE_H +#define UTLOBJECTREFERENCE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlintrusivelist.h" +#include "mathlib/mathlib.h" + + +// Purpose: class for keeping track of all the references that exist to an object. When the object +// being referenced is freed, all of the references pointing at it will become null. +// +// To Use: +// Add a DECLARE_REFERENCED_CLASS to the class that you want to use CutlReferences with. +// Replace pointers to that class with CUtlReferences. +// Check these references for null in appropriate places. +// +// NOTE : You can still happily use pointers instead of references where you want to - these +// pointers will not magically become null like references would, but if you know no one is going +// to delete the underlying object during a partcular section of code, it doesn't +// matter. Basically, CUtlReferences don't rely on every use of an object using one. + + + + +template class CUtlReference +{ +public: + FORCEINLINE CUtlReference(void) + { + m_pNext = m_pPrev = NULL; + m_pObject = NULL; + } + + FORCEINLINE CUtlReference(T *pObj) + { + m_pNext = m_pPrev = NULL; + AddRef( pObj ); + } + + FORCEINLINE ~CUtlReference(void) + { + KillRef(); + } + + FORCEINLINE void Set(T *pObj) + { + if ( m_pObject != pObj ) + { + KillRef(); + AddRef( pObj ); + } + } + + FORCEINLINE T * operator()(void) const + { + return m_pObject; + } + + FORCEINLINE operator T*() + { + return m_pObject; + } + + FORCEINLINE operator const T*() const + { + return m_pObject; + } + + FORCEINLINE T* operator->() + { + return m_pObject; + } + + FORCEINLINE const T* operator->() const + { + return m_pObject; + } + + FORCEINLINE CUtlReference &operator=( const CUtlReference& otherRef ) + { + Set( otherRef.m_pObject ); + return *this; + } + + FORCEINLINE CUtlReference &operator=( T *pObj ) + { + Set( pObj ); + return *this; + } + + + FORCEINLINE bool operator==( const CUtlReference& o ) const + { + return ( o.m_pObject == m_pObject ); + } + +public: + CUtlReference *m_pNext; + CUtlReference *m_pPrev; + + T *m_pObject; + + FORCEINLINE void AddRef( T *pObj ) + { + m_pObject = pObj; + if ( pObj ) + { + pObj->m_References.AddToHead( this ); + } + } + + FORCEINLINE void KillRef(void) + { + if ( m_pObject ) + { + m_pObject->m_References.RemoveNode( this ); + m_pObject = NULL; + } + } + +}; + +template class CUtlReferenceList : public CUtlIntrusiveDList< CUtlReference > +{ +public: + ~CUtlReferenceList( void ) + { + CUtlReference *i = CUtlIntrusiveDList >::m_pHead; + while( i ) + { + CUtlReference *n = i->m_pNext; + i->m_pNext = NULL; + i->m_pPrev = NULL; + i->m_pObject = NULL; + i = n; + } + CUtlIntrusiveDList >::m_pHead = NULL; + } +}; + + +//----------------------------------------------------------------------------- +// Put this macro in classes that are referenced by CUtlReference +//----------------------------------------------------------------------------- +#define DECLARE_REFERENCED_CLASS( _className ) \ + private: \ + CUtlReferenceList< _className > m_References; \ + template friend class CUtlReference; + + +#endif + + + + + diff --git a/public/tier1/utlpair.h b/public/tier1/utlpair.h new file mode 100644 index 0000000..d306f32 --- /dev/null +++ b/public/tier1/utlpair.h @@ -0,0 +1,52 @@ +//========= Copyright, Valve Corporation, All rights reserved. ================// +// +// std::pair style container; exists to work easily in our CUtlMap/CUtlHashMap classes +// +//=============================================================================// + +#ifndef UTLPAIR_H +#define UTLPAIR_H + +#ifdef _WIN32 +#pragma once +#endif + + +// std::pair style container; exists to work easily in our CUtlMap/CUtlHashMap classes +template +class CUtlPair +{ +public: + CUtlPair() {} + CUtlPair( T1 t1, T2 t2 ) : first( t1 ), second( t2 ) {} + + bool operator<( const CUtlPair &rhs ) const { + if ( first != rhs.first ) + return first < rhs.first; + return second < rhs.second; + } + + bool operator==( const CUtlPair &rhs ) const { + return first == rhs.first && second == rhs.second; + } + + T1 first; + T2 second; +}; + +// utility to make a CUtlPair without having to specify template parameters +template +inline CUtlPair MakeUtlPair( T1 t1, T2 t2 ) +{ + return CUtlPair(t1, t2); +} + +//// HashItem() overload that works automatically with our hash containers +//template +//inline uint32 HashItem( const CUtlPair &item ) +//{ +// return HashItem( (uint64)HashItem( item.first ) + ((uint64)HashItem( item.second ) << 32) ); +//} + + +#endif // UTLPAIR_H diff --git a/public/tier1/utlpriorityqueue.h b/public/tier1/utlpriorityqueue.h new file mode 100644 index 0000000..8d3f457 --- /dev/null +++ b/public/tier1/utlpriorityqueue.h @@ -0,0 +1,198 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLPRIORITYQUEUE_H +#define UTLPRIORITYQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +// T is the type stored in the queue, it must include the priority +// The head of the list contains the element with GREATEST priority +// configure the LessFunc_t to get the desired queue order +template< class T > +class CUtlPriorityQueue +{ +public: + // Less func typedef + // Returns true if the first parameter is "less priority" than the second + // Items that are "less priority" sort toward the tail of the queue + typedef bool (*LessFunc_t)( T const&, T const& ); + + typedef T ElemType_t; + + // constructor: lessfunc is required, but may be set after the constructor with + // SetLessFunc + CUtlPriorityQueue( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 ); + CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc = 0 ); + + // gets particular elements + inline T const& ElementAtHead() const { return m_heap.Element(0); } + + inline bool IsValidIndex(int index) { return m_heap.IsValidIndex(index); } + + // O(lgn) to rebalance the heap + void RemoveAtHead(); + void RemoveAt( int index ); + + // O(lgn) to rebalance heap + void Insert( T const &element ); + // Sets the less func + void SetLessFunc( LessFunc_t func ); + + // Returns the count of elements in the queue + inline int Count() const { return m_heap.Count(); } + + // doesn't deallocate memory + void RemoveAll() { m_heap.RemoveAll(); } + + // Memory deallocation + void Purge() { m_heap.Purge(); } + + inline const T & Element( int index ) const { return m_heap.Element(index); } + +protected: + CUtlVector m_heap; + + void Swap( int index1, int index2 ); + + // Used for sorting. + LessFunc_t m_LessFunc; +}; + +template< class T > +inline CUtlPriorityQueue::CUtlPriorityQueue( int growSize, int initSize, LessFunc_t lessfunc ) : + m_heap(growSize, initSize), m_LessFunc(lessfunc) +{ +} + +template< class T > +inline CUtlPriorityQueue::CUtlPriorityQueue( T *pMemory, int numElements, LessFunc_t lessfunc ) : + m_heap(pMemory, numElements), m_LessFunc(lessfunc) +{ +} + +template +void CUtlPriorityQueue::RemoveAtHead() +{ + m_heap.FastRemove( 0 ); + int index = 0; + + int count = Count(); + if ( !count ) + return; + + int half = count/2; + int larger = index; + while ( index < half ) + { + int child = ((index+1) * 2) - 1; // if we wasted an element, this math would be more compact (1 based array) + if ( child < count ) + { + // Item has been filtered down to its proper place, terminate. + if ( m_LessFunc( m_heap[index], m_heap[child] ) ) + { + // mark the potential swap and check the other child + larger = child; + } + } + // go to sibling + child++; + if ( child < count ) + { + // If this child is larger, swap it instead + if ( m_LessFunc( m_heap[larger], m_heap[child] ) ) + larger = child; + } + + if ( larger == index ) + break; + + // swap with the larger child + Swap( index, larger ); + index = larger; + } +} + + +template +void CUtlPriorityQueue::RemoveAt( int index ) +{ + Assert(m_heap.IsValidIndex(index)); + m_heap.FastRemove( index ); + + int count = Count(); + if ( !count ) + return; + + int half = count/2; + int larger = index; + while ( index < half ) + { + int child = ((index+1) * 2) - 1; // if we wasted an element, this math would be more compact (1 based array) + if ( child < count ) + { + // Item has been filtered down to its proper place, terminate. + if ( m_LessFunc( m_heap[index], m_heap[child] ) ) + { + // mark the potential swap and check the other child + larger = child; + } + } + // go to sibling + child++; + if ( child < count ) + { + // If this child is larger, swap it instead + if ( m_LessFunc( m_heap[larger], m_heap[child] ) ) + larger = child; + } + + if ( larger == index ) + break; + + // swap with the larger child + Swap( index, larger ); + index = larger; + } +} + +template +void CUtlPriorityQueue::Insert( T const &element ) +{ + int index = m_heap.AddToTail(); + m_heap[index] = element; + + while ( index != 0 ) + { + int parent = ((index+1) / 2) - 1; + if ( m_LessFunc( m_heap[index], m_heap[parent] ) ) + break; + + // swap with parent and repeat + Swap( parent, index ); + index = parent; + } +} + +template +void CUtlPriorityQueue::Swap( int index1, int index2 ) +{ + T tmp = m_heap[index1]; + m_heap[index1] = m_heap[index2]; + m_heap[index2] = tmp; +} + +template +void CUtlPriorityQueue::SetLessFunc( LessFunc_t lessfunc ) +{ + m_LessFunc = lessfunc; +} + +#endif // UTLPRIORITYQUEUE_H diff --git a/public/tier1/utlqueue.h b/public/tier1/utlqueue.h new file mode 100644 index 0000000..05c89ee --- /dev/null +++ b/public/tier1/utlqueue.h @@ -0,0 +1,551 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLQUEUE_H +#define UTLQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmemory.h" + +//#define TEST_UTLQUEUE + +enum QueueIter_t { QUEUE_ITERATOR_INVALID = 0xffffffff }; + +// T is the type stored in the queue +template< class T, class M = CUtlMemory< T > > +class CUtlQueue +{ +public: + + CUtlQueue( int growSize = 0, int initSize = 0 ); + CUtlQueue( T *pMemory, int numElements ); + + // return the item from the front of the queue and delete it + T RemoveAtHead(); + bool RemoveAtHead( T &removedElement ); + + // return the item from the end of the queue and delete it + T RemoveAtTail(); + bool RemoveAtTail( T &removedElement ); + + // return item at the front of the queue + T const& Head() const; + // return item at the end of the queue + T const& Tail() const; + + // Add a new item to the end of the queue + void Insert( T const &element ); + + // checks if an element of this value already exists on the stack, returns true if it does + bool Check( T const element ) const; + + // iterators may be invalidated by Insert() + QueueIter_t First() const; + QueueIter_t Next( QueueIter_t it ) const; + QueueIter_t Last() const; + QueueIter_t Previous( QueueIter_t it ) const; + bool IsValid( QueueIter_t it ) const; + T const& Element( QueueIter_t it ) const; + + // Returns the count of elements in the queue + int Count() const; + + // Return whether the queue is empty or not, faster than Count(). + bool IsEmpty() const; + + // doesn't deallocate memory + void RemoveAll(); + + // Memory deallocation + void Purge(); + +protected: + QueueIter_t Next_Unchecked( QueueIter_t it ) const; + QueueIter_t Previous_Unchecked( QueueIter_t it ) const; + + M m_memory; + + // if m_head == m_tail == QUEUE_ITERATOR_INVALID, then the queue is empty + QueueIter_t m_head; + QueueIter_t m_tail; + +#ifdef TEST_UTLQUEUE + friend void CUtlQueue_Test(); +#endif +}; + +//----------------------------------------------------------------------------- +// The CUtlQueueFixed class: +// A queue class with a fixed allocation scheme +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlQueueFixed : public CUtlQueue< T, CUtlMemoryFixed > +{ + typedef CUtlQueue< T, CUtlMemoryFixed > BaseClass; +public: + + // constructor, destructor + CUtlQueueFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + CUtlQueueFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + +template< class T, class M > +inline CUtlQueue::CUtlQueue( int growSize, int initSize ) : + m_memory( growSize, initSize ), m_head( QUEUE_ITERATOR_INVALID ), m_tail( QUEUE_ITERATOR_INVALID ) +{ +} + +template< class T, class M > +inline CUtlQueue::CUtlQueue( T *pMemory, int numElements ) : + m_memory( pMemory, numElements ), m_head( QUEUE_ITERATOR_INVALID ), m_tail( QUEUE_ITERATOR_INVALID ) +{ +} + +template +inline T CUtlQueue::RemoveAtHead() +{ + T temp; + RemoveAtHead( temp ); + return temp; +} + +template +inline bool CUtlQueue::RemoveAtHead( T &removedElement ) +{ + Assert( m_head != QUEUE_ITERATOR_INVALID ); + if ( m_head == QUEUE_ITERATOR_INVALID ) + { + Construct( &removedElement ); + return false; + } + + QueueIter_t it = m_head; + removedElement = m_memory[ it ]; + Destruct( &m_memory[ it ] ); + if ( m_head == m_tail ) + { + m_head = m_tail = QUEUE_ITERATOR_INVALID; + } + else + { + m_head = Next_Unchecked( m_head ); + } + return true; +} + +template +inline T CUtlQueue::RemoveAtTail() +{ + T temp; + RemoveAtTail( temp ); + return temp; +} + +template +inline bool CUtlQueue::RemoveAtTail( T &removedElement ) +{ + Assert( m_tail != QUEUE_ITERATOR_INVALID ); + if ( m_tail == QUEUE_ITERATOR_INVALID ) + { + Construct( &removedElement ); + return false; + } + + removedElement = m_memory[ m_tail ]; + Destruct( &m_memory[ m_tail ] ); + if ( m_head == m_tail ) + { + m_head = m_tail = QUEUE_ITERATOR_INVALID; + } + else + { + m_tail = Previous_Unchecked( m_tail ); + } + return true; +} + +template +inline T const& CUtlQueue::Head() const +{ + Assert( m_head != QUEUE_ITERATOR_INVALID ); + if ( m_head == QUEUE_ITERATOR_INVALID ) + { + static T dummy; + return dummy; + } + + return m_memory[ m_head ]; +} + +template +inline T const& CUtlQueue::Tail() const +{ + Assert( m_tail != QUEUE_ITERATOR_INVALID ); + if ( m_tail == QUEUE_ITERATOR_INVALID ) + { + static T dummy; + return dummy; + } + + return m_memory[ m_tail ]; +} + +template +void CUtlQueue::Insert( T const &element ) +{ + if ( m_tail == QUEUE_ITERATOR_INVALID ) + { + // empty + m_memory.EnsureCapacity( 1 ); + m_head = m_tail = QueueIter_t( 0 ); + } + else + { + // non-empty + QueueIter_t nextTail = Next_Unchecked( m_tail ); + if ( nextTail == m_head ) // if non-empty, and growing by 1 appears to make the queue of length 1, then we were already full before the Insert + { + int nOldAllocCount = m_memory.NumAllocated(); + m_memory.Grow(); + int nNewAllocCount = m_memory.NumAllocated(); + int nGrowAmount = nNewAllocCount - nOldAllocCount; + + nextTail = Next_Unchecked( m_tail ); // if nextTail was 0, then it now should be nOldAllocCount + + if ( m_head != QueueIter_t( 0 ) ) + { + // if the queue wraps around the end of m_memory, move the part at the end of memory to the new end of memory + Q_memmove( &m_memory[ m_head + nGrowAmount ], &m_memory[ m_head ], ( nOldAllocCount - m_head ) * sizeof( T ) ); +#ifdef _DEBUG + Q_memset( &m_memory[ m_head ], 0xdd, nGrowAmount * sizeof( T ) ); +#endif + m_head = QueueIter_t( m_head + nGrowAmount ); + } + } + m_tail = nextTail; + } + + CopyConstruct( &m_memory[ m_tail ], element ); +} + +template +bool CUtlQueue::Check( T const element ) const +{ + for ( QueueIter_t it = First(); it != QUEUE_ITERATOR_INVALID; it = Next( it ) ) + { + if ( m_memory[ it ] == element ) + return true; + } + return false; +} + +template +QueueIter_t CUtlQueue::First() const +{ + return m_head; +} + +template +QueueIter_t CUtlQueue::Next( QueueIter_t it ) const +{ + if ( it == QUEUE_ITERATOR_INVALID ) + return QUEUE_ITERATOR_INVALID; + + if ( it == m_tail ) + return QUEUE_ITERATOR_INVALID; + + Assert( IsValid( it ) ); + if ( !IsValid( it ) ) + return QUEUE_ITERATOR_INVALID; + + return Next_Unchecked( it ); +} + +template +QueueIter_t CUtlQueue::Last() const +{ + return m_tail; +} + +template +QueueIter_t CUtlQueue::Previous( QueueIter_t it ) const +{ + if ( it == QUEUE_ITERATOR_INVALID ) + return QUEUE_ITERATOR_INVALID; + + if ( it == m_head ) + return QUEUE_ITERATOR_INVALID; + + Assert( IsValid( it ) ); + if ( !IsValid( it ) ) + return QUEUE_ITERATOR_INVALID; + + return Previous_Unchecked( it ); +} + +template +QueueIter_t CUtlQueue::Next_Unchecked( QueueIter_t it ) const +{ + return it == m_memory.Count() - 1 ? QueueIter_t( 0 ) : QueueIter_t( it + 1 ); +} + +template +QueueIter_t CUtlQueue::Previous_Unchecked( QueueIter_t it ) const +{ + return it == 0 ? QueueIter_t( m_memory.Count() - 1 ) : QueueIter_t( it - 1 ); +} + +template +bool CUtlQueue::IsValid( QueueIter_t it ) const +{ + if ( it == QUEUE_ITERATOR_INVALID ) + return false; + + if ( m_head == QUEUE_ITERATOR_INVALID ) + return false; + + if ( m_head <= m_tail ) + return it >= m_head && it <= m_tail; + + return ( it >= m_head && it < m_memory.Count() ) || ( it >= 0 && it <= m_tail ); +} + +template +T const& CUtlQueue::Element( QueueIter_t it ) const +{ + Assert( it != QUEUE_ITERATOR_INVALID ); + if ( it == QUEUE_ITERATOR_INVALID ) + { + static T dummy; + return dummy; + } + + Assert( IsValid( it ) ); + return m_memory[ it ]; +} + +template +int CUtlQueue::Count() const +{ + if ( m_head == QUEUE_ITERATOR_INVALID ) + { + Assert( m_tail == QUEUE_ITERATOR_INVALID ); + return 0; + } + Assert( m_tail != QUEUE_ITERATOR_INVALID ); + + if ( m_head <= m_tail ) + return m_tail + 1 - m_head; + + return m_tail + 1 - m_head + m_memory.Count(); +} + +template +bool CUtlQueue::IsEmpty() const +{ + Assert( ( m_head == QUEUE_ITERATOR_INVALID ) == ( m_tail == QUEUE_ITERATOR_INVALID ) ); + return ( m_head == QUEUE_ITERATOR_INVALID ); +} + +template +void CUtlQueue::RemoveAll() +{ + m_head = m_tail = QUEUE_ITERATOR_INVALID; +} + +template +void CUtlQueue::Purge() +{ + m_head = m_tail = QUEUE_ITERATOR_INVALID; + m_memory.Purge(); +} + + +#ifdef TEST_UTLQUEUE + +#include + +struct Data_t +{ + Data_t( int i = 0xffffffff ) : m_id( i ) {} + Data_t( const Data_t &that ) : m_id( that.m_id ) {} + ~Data_t() { m_id = 0xdddddddd; } + Data_t &operator=( const Data_t &that ) { m_id = that.m_id; return *this; } + + int m_id; +}; + +inline void CUtlQueue_Test() +{ + CUtlQueue< Data_t > queue; + + for ( int n = 1; n < 100; ++n ) + { + Assert( queue.Count() == 0 ); + Assert( queue.m_head == QUEUE_ITERATOR_INVALID ); + Assert( queue.m_tail == QUEUE_ITERATOR_INVALID ); + + int w = rand() % n; + for ( int i = 0; i < w; ++i ) + { + queue.Insert( Data_t( i ) ); + } + + if ( w > 0 ) + { + Assert( queue.Head().m_id == queue.First() ); + Assert( queue.Tail().m_id == queue.Last() ); + Assert( queue.Head().m_id == 0 ); + Assert( queue.Tail().m_id == w - 1 ); + } + Assert( queue.Count() == w ); + + for ( int j = 0; j < n; ++j ) + { + queue.Insert( Data_t( w + j ) ); + + if ( j == 0 ) + { + Assert( queue.Count() == w + j + 1 ); + + for ( int i = 0; i < w; ++i ) + { + queue.RemoveAtHead(); + } + } + + Assert( queue.Count() == j + 1 ); + + Assert( queue.m_head != QUEUE_ITERATOR_INVALID ); + Assert( queue.m_tail != QUEUE_ITERATOR_INVALID ); + + int id = queue.Head().m_id % queue.m_memory.Count(); + for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) ) + { + Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id ); + id = ( id + 1 ) % queue.m_memory.Count(); + } + + id = queue.Tail().m_id % queue.m_memory.Count(); + for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) ) + { + Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id ); + id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count(); + } + + for ( int i = 0; i < j; ++i ) + { + int id = queue.m_memory[ i ].m_id; + if ( queue.IsValid( QueueIter_t( i ) ) ) + { + Assert( ( id & 0xff000000 ) == 0 ); + } + else + { + Assert( id == 0xdddddddd ); + } + } + } + + Assert( queue.Count() == n ); +#if 0 + for ( int j = 0; j < n; ++j ) + { + Assert( queue.m_head != QUEUE_ITERATOR_INVALID ); + Assert( queue.m_tail != QUEUE_ITERATOR_INVALID ); + + Assert( queue.Count() == n - j ); + + Data_t data = queue.RemoveAtHead(); + + Assert( queue.Count() == n - j - 1 ); + + if ( queue.Count() > 0 ) + { + int id = queue.Head().m_id % queue.m_memory.Count(); + for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) ) + { + Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id ); + id = ( id + 1 ) % queue.m_memory.Count(); + } + + id = queue.Tail().m_id % queue.m_memory.Count(); + for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) ) + { + Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id ); + id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count(); + } + } + + for ( int i = 0; i < j; ++i ) + { + int id = queue.m_memory[ i ].m_id; + if ( queue.IsValid( QueueIter_t( i ) ) ) + { + Assert( ( id & 0xff000000 ) == 0 ); + } + else + { + Assert( id == 0xdddddddd ); + } + } + } +#else + for ( int j = n - 1; j >= 0; --j ) + { + Assert( queue.m_head != QUEUE_ITERATOR_INVALID ); + Assert( queue.m_tail != QUEUE_ITERATOR_INVALID ); + + Assert( queue.Count() == j + 1 ); + + Data_t data = queue.RemoveAtTail(); + + Assert( queue.Count() == j ); + + if ( queue.Count() > 0 ) + { + int id = queue.Head().m_id % queue.m_memory.Count(); + for ( QueueIter_t it = queue.First(); it != QUEUE_ITERATOR_INVALID; it = queue.Next( it ) ) + { + Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id ); + id = ( id + 1 ) % queue.m_memory.Count(); + } + + id = queue.Tail().m_id % queue.m_memory.Count(); + for ( QueueIter_t it = queue.Last(); it != QUEUE_ITERATOR_INVALID; it = queue.Previous( it ) ) + { + Assert( queue.Element( it ).m_id % queue.m_memory.Count() == id ); + id = ( id + queue.m_memory.Count() - 1 ) % queue.m_memory.Count(); + } + } + + for ( int i = 0; i < j; ++i ) + { + int id = queue.m_memory[ i ].m_id; + if ( queue.IsValid( QueueIter_t( i ) ) ) + { + Assert( ( id & 0xff000000 ) == 0 ); + } + else + { + Assert( id == 0xdddddddd ); + } + } + } +#endif + + Assert( queue.Count() == 0 ); + Assert( queue.m_head == QUEUE_ITERATOR_INVALID ); + Assert( queue.m_tail == QUEUE_ITERATOR_INVALID ); + } +} + +#endif // TEST_UTLQUEUE + +#endif // UTLQUEUE_H diff --git a/public/tier1/utlrbtree.h b/public/tier1/utlrbtree.h new file mode 100644 index 0000000..7c9d8e4 --- /dev/null +++ b/public/tier1/utlrbtree.h @@ -0,0 +1,1593 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLRBTREE_H +#define UTLRBTREE_H + +#include "tier1/utlmemory.h" +#include "tier1/utlfixedmemory.h" +#include "tier1/utlblockmemory.h" +#include "tier1/strtools.h" + +//----------------------------------------------------------------------------- +// Tool to generate a default compare function for any type that implements +// operator<, including all simple types +//----------------------------------------------------------------------------- + +template +class CDefOps +{ +public: + static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); } +}; + +#define DefLessFunc( type ) CDefOps< type >::LessFunc + +template +class CDefLess +{ +public: + CDefLess() {} + CDefLess( int i ) {} + inline bool operator()( const T &lhs, const T &rhs ) const { return ( lhs < rhs ); } + inline bool operator!() const { return false; } +}; + +//------------------------------------- + +inline bool StringLessThan( const char * const &lhs, const char * const &rhs) { + if ( !lhs ) return false; + if ( !rhs ) return true; + return ( V_strcmp( lhs, rhs) < 0 ); +} + +inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) { + if ( !lhs ) return false; + if ( !rhs ) return true; + return ( V_stricmp( lhs, rhs) < 0 ); +} + + +// Same as CaselessStringLessThan, but it ignores differences in / and \. +inline bool CaselessStringLessThanIgnoreSlashes( const char * const &lhs, const char * const &rhs ) +{ + const char *pa = lhs; + const char *pb = rhs; + while ( *pa && *pb ) + { + char a = *pa; + char b = *pb; + + // Check for dir slashes. + if ( a == '/' || a == '\\' ) + { + if ( b != '/' && b != '\\' ) + return ('/' < b); + } + else + { + if ( a >= 'a' && a <= 'z' ) + a = 'A' + (a - 'a'); + + if ( b >= 'a' && b <= 'z' ) + b = 'A' + (b - 'a'); + + if ( a > b ) + return false; + else if ( a < b ) + return true; + } + ++pa; + ++pb; + } + + // Filenames also must be the same length. + if ( *pa != *pb ) + { + // If pa shorter than pb then it's "less" + return ( !*pa ); + } + + return false; +} + +//------------------------------------- +// inline these two templates to stop multiple definitions of the same code +template <> inline bool CDefOps::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); } +template <> inline bool CDefOps::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); } + +//------------------------------------- + +template +void SetDefLessFunc( RBTREE_T &RBTree ) +{ + RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) ); +} + +//----------------------------------------------------------------------------- +// A red-black binary search tree +//----------------------------------------------------------------------------- + +template < class I > +struct UtlRBTreeLinks_t +{ + I m_Left; + I m_Right; + I m_Parent; + I m_Tag; +}; + +template < class T, class I > +struct UtlRBTreeNode_t : public UtlRBTreeLinks_t< I > +{ + T m_Data; +}; + +template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ), class M = CUtlMemory< UtlRBTreeNode_t< T, I >, I > > +class CUtlRBTree +{ +public: + + typedef T KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef L LessFunc_t; + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ); + CUtlRBTree( const LessFunc_t &lessfunc ); + ~CUtlRBTree( ); + + void EnsureCapacity( int num ); + + void CopyFrom( const CUtlRBTree &other ); + + // gets particular elements + T& Element( I i ); + T const &Element( I i ) const; + T& operator[]( I i ); + T const &operator[]( I i ) const; + + // Gets the root + I Root() const; + + // Num elements + unsigned int Count() const; + + // Max "size" of the vector + // it's not generally safe to iterate from index 0 to MaxElement()-1 + // it IS safe to do so when using CUtlMemory as the allocator, + // but we should really remove patterns using this anyways, for safety and generality + I MaxElement() const; + + // Gets the children + I Parent( I i ) const; + I LeftChild( I i ) const; + I RightChild( I i ) const; + + // Tests if a node is a left or right child + bool IsLeftChild( I i ) const; + bool IsRightChild( I i ) const; + + // Tests if root or leaf + bool IsRoot( I i ) const; + bool IsLeaf( I i ) const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( I i ) const; + + // Checks if the tree as a whole is valid + bool IsValid() const; + + // Invalid index + static I InvalidIndex(); + + // returns the tree depth (not a very fast operation) + int Depth( I node ) const; + int Depth() const; + + // Sets the less func + void SetLessFunc( const LessFunc_t &func ); + + // Allocation method + I NewNode(); + + // Insert method (inserts in order) + I Insert( T const &insert ); + void Insert( const T *pArray, int nItems ); + I InsertIfNotFound( T const &insert ); + + // Find method + I Find( T const &search ) const; + + // Remove methods + void RemoveAt( I i ); + bool Remove( T const &remove ); + void RemoveAll( ); + void Purge(); + + bool HasElement( T const &search ) const { return Find( search ) != InvalidIndex(); } + + // Allocation, deletion + void FreeNode( I i ); + + // Iteration + I FirstInorder() const; + I NextInorder( I i ) const; + I PrevInorder( I i ) const; + I LastInorder() const; + + I FirstPreorder() const; + I NextPreorder( I i ) const; + I PrevPreorder( I i ) const; + I LastPreorder( ) const; + + I FirstPostorder() const; + I NextPostorder( I i ) const; + + // If you change the search key, this can be used to reinsert the + // element into the tree. + void Reinsert( I elem ); + + // swap in place + void Swap( CUtlRBTree< T, I, L > &that ); + +private: + // Can't copy the tree this way! + CUtlRBTree& operator=( const CUtlRBTree &other ); + +protected: + enum NodeColor_t + { + RED = 0, + BLACK + }; + + typedef UtlRBTreeNode_t< T, I > Node_t; + typedef UtlRBTreeLinks_t< I > Links_t; + + // Sets the children + void SetParent( I i, I parent ); + void SetLeftChild( I i, I child ); + void SetRightChild( I i, I child ); + void LinkToParent( I i, I parent, bool isLeft ); + + // Gets at the links + Links_t const &Links( I i ) const; + Links_t &Links( I i ); + + // Checks if a link is red or black + bool IsRed( I i ) const; + bool IsBlack( I i ) const; + + // Sets/gets node color + NodeColor_t Color( I i ) const; + void SetColor( I i, NodeColor_t c ); + + // operations required to preserve tree balance + void RotateLeft(I i); + void RotateRight(I i); + void InsertRebalance(I i); + void RemoveRebalance(I i); + + // Insertion, removal + I InsertAt( I parent, bool leftchild ); + + // copy constructors not allowed + CUtlRBTree( CUtlRBTree const &tree ); + + // Inserts a node into the tree, doesn't copy the data in. + void FindInsertionPosition( T const &insert, I &parent, bool &leftchild ); + + // Remove and add back an element in the tree. + void Unlink( I elem ); + void Link( I elem ); + + // Used for sorting. + LessFunc_t m_LessFunc; + + M m_Elements; + I m_Root; + I m_NumElements; + I m_FirstFree; + typename M::Iterator_t m_LastAlloc; // the last index allocated + + Node_t* m_pElements; + + FORCEINLINE M const &Elements( void ) const + { + return m_Elements; + } + + + void ResetDbgInfo() + { + m_pElements = (Node_t*)m_Elements.Base(); + } +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = int, typename L = bool (*)( const T &, const T & ) > +class CUtlFixedRBTree : public CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > +{ +public: + + typedef L LessFunc_t; + + CUtlFixedRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( growSize, initSize, lessfunc ) {} + CUtlFixedRBTree( const LessFunc_t &lessfunc ) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( lessfunc ) {} + + typedef CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > BaseClass; + bool IsValidIndex( I i ) const + { + if ( !BaseClass::Elements().IsIdxValid( i ) ) + return false; + +#ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElement() + if ( BaseClass::Elements().IsIdxAfter( i, this->m_LastAlloc ) ) + { + Assert( 0 ); + return false; // don't read values that have been allocated, but not constructed + } +#endif + + return LeftChild(i) != i; + } + +protected: + void ResetDbgInfo() {} + +private: + // this doesn't make sense for fixed rbtrees, since there's no useful max pointer, and the index space isn't contiguous anyways + I MaxElement() const; +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ) > +class CUtlBlockRBTree : public CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > > +{ +public: + typedef L LessFunc_t; + CUtlBlockRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( growSize, initSize, lessfunc ) {} + CUtlBlockRBTree( const LessFunc_t &lessfunc ) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( lessfunc ) {} +protected: + void ResetDbgInfo() {} +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline CUtlRBTree::CUtlRBTree( int growSize, int initSize, const LessFunc_t &lessfunc ) : +m_LessFunc( lessfunc ), +m_Elements( growSize, initSize ), +m_Root( InvalidIndex() ), +m_NumElements( 0 ), +m_FirstFree( InvalidIndex() ), +m_LastAlloc( m_Elements.InvalidIterator() ) +{ + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree::CUtlRBTree( const LessFunc_t &lessfunc ) : +m_LessFunc( lessfunc ), +m_Elements( 0, 0 ), +m_Root( InvalidIndex() ), +m_NumElements( 0 ), +m_FirstFree( InvalidIndex() ), +m_LastAlloc( m_Elements.InvalidIterator() ) +{ + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree::~CUtlRBTree() +{ + Purge(); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::EnsureCapacity( int num ) +{ + m_Elements.EnsureCapacity( num ); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::CopyFrom( const CUtlRBTree &other ) +{ + Purge(); + m_Elements.EnsureCapacity( other.m_Elements.Count() ); + memcpy( m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof( T ) ); + m_LessFunc = other.m_LessFunc; + m_Root = other.m_Root; + m_NumElements = other.m_NumElements; + m_FirstFree = other.m_FirstFree; + m_LastAlloc = other.m_LastAlloc; + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline T &CUtlRBTree::Element( I i ) +{ + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T const &CUtlRBTree::Element( I i ) const +{ + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T &CUtlRBTree::operator[]( I i ) +{ + return Element(i); +} + +template < class T, class I, typename L, class M > +inline T const &CUtlRBTree::operator[]( I i ) const +{ + return Element(i); +} + +//----------------------------------------------------------------------------- +// +// various accessors +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Gets the root +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::Root() const +{ + return m_Root; +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline unsigned int CUtlRBTree::Count() const +{ + return (unsigned int)m_NumElements; +} + +//----------------------------------------------------------------------------- +// Max "size" of the vector +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::MaxElement() const +{ + return ( I )m_Elements.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Gets the children +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::Parent( I i ) const +{ + return Links(i).m_Parent; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::LeftChild( I i ) const +{ + return Links(i).m_Left; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::RightChild( I i ) const +{ + return Links(i).m_Right; +} + +//----------------------------------------------------------------------------- +// Tests if a node is a left or right child +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsLeftChild( I i ) const +{ + return LeftChild(Parent(i)) == i; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRightChild( I i ) const +{ + return RightChild(Parent(i)) == i; +} + + +//----------------------------------------------------------------------------- +// Tests if root or leaf +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRoot( I i ) const +{ + return i == m_Root; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsLeaf( I i ) const +{ + return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex()); +} + + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsValidIndex( I i ) const +{ + if ( !m_Elements.IsIdxValid( i ) ) + return false; + + if ( m_Elements.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return LeftChild(i) != i; +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::InvalidIndex() +{ + return ( I )M::InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline int CUtlRBTree::Depth() const +{ + return Depth(Root()); +} + +//----------------------------------------------------------------------------- +// Sets the children +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetParent( I i, I parent ) +{ + Links(i).m_Parent = parent; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetLeftChild( I i, I child ) +{ + Links(i).m_Left = child; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetRightChild( I i, I child ) +{ + Links(i).m_Right = child; +} + +//----------------------------------------------------------------------------- +// Gets at the links +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::Links_t const &CUtlRBTree::Links( I i ) const +{ + // Sentinel node, makes life easier + static Links_t s_Sentinel = + { + InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree::BLACK + }; + + return (i != InvalidIndex()) ? *(Links_t*)&m_Elements[i] : *(Links_t*)&s_Sentinel; +} + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::Links_t &CUtlRBTree::Links( I i ) +{ + Assert(i != InvalidIndex()); + return *(Links_t *)&m_Elements[i]; +} + +//----------------------------------------------------------------------------- +// Checks if a link is red or black +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRed( I i ) const +{ + return (Links(i).m_Tag == RED); +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsBlack( I i ) const +{ + return (Links(i).m_Tag == BLACK); +} + + +//----------------------------------------------------------------------------- +// Sets/gets node color +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color( I i ) const +{ + return (NodeColor_t)Links(i).m_Tag; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetColor( I i, typename CUtlRBTree::NodeColor_t c ) +{ + Links(i).m_Tag = (I)c; +} + +//----------------------------------------------------------------------------- +// Allocates/ deallocates nodes +//----------------------------------------------------------------------------- +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +template < class T, class I, typename L, class M > +I CUtlRBTree::NewNode() +{ + I elem; + + // Nothing in the free list; add. + if ( m_FirstFree == InvalidIndex() ) + { + Assert( m_Elements.IsValidIterator( m_LastAlloc ) || m_NumElements == 0 ); + typename M::Iterator_t it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); + if ( !m_Elements.IsValidIterator( it ) ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Elements.Grow(); + + it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); + + Assert( m_Elements.IsValidIterator( it ) ); + if ( !m_Elements.IsValidIterator( it ) ) + { + Error( "CUtlRBTree overflow!\n" ); + } + } + m_LastAlloc = it; + elem = m_Elements.GetIndex( m_LastAlloc ); + Assert( m_Elements.IsValidIterator( m_LastAlloc ) ); + } + else + { + elem = m_FirstFree; + m_FirstFree = Links( m_FirstFree ).m_Right; + } + +#ifdef _DEBUG + // reset links to invalid.... + Links_t &node = Links( elem ); + node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); +#endif + + Construct( &Element( elem ) ); + ResetDbgInfo(); + + return elem; +} +#pragma warning(pop) + +template < class T, class I, typename L, class M > +void CUtlRBTree::FreeNode( I i ) +{ + Assert( IsValidIndex(i) && (i != InvalidIndex()) ); + Destruct( &Element(i) ); + SetLeftChild( i, i ); // indicates it's in not in the tree + SetRightChild( i, m_FirstFree ); + m_FirstFree = i; +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the left +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RotateLeft(I elem) +{ + I rightchild = RightChild(elem); + SetRightChild( elem, LeftChild(rightchild) ); + if (LeftChild(rightchild) != InvalidIndex()) + SetParent( LeftChild(rightchild), elem ); + + if (rightchild != InvalidIndex()) + SetParent( rightchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), rightchild ); + else + SetRightChild( Parent(elem), rightchild ); + } + else + m_Root = rightchild; + + SetLeftChild( rightchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, rightchild ); +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the right +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RotateRight(I elem) +{ + I leftchild = LeftChild(elem); + SetLeftChild( elem, RightChild(leftchild) ); + if (RightChild(leftchild) != InvalidIndex()) + SetParent( RightChild(leftchild), elem ); + + if (leftchild != InvalidIndex()) + SetParent( leftchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsRightChild(elem)) + SetRightChild( Parent(elem), leftchild ); + else + SetLeftChild( Parent(elem), leftchild ); + } + else + m_Root = leftchild; + + SetRightChild( leftchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, leftchild ); +} + + +//----------------------------------------------------------------------------- +// Rebalances the tree after an insertion +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::InsertRebalance(I elem) +{ + while ( !IsRoot(elem) && (Color(Parent(elem)) == RED) ) + { + I parent = Parent(elem); + I grandparent = Parent(parent); + + /* we have a violation */ + if (IsLeftChild(parent)) + { + I uncle = RightChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsRightChild(elem)) + { + /* make x a left child, will change parent and grandparent */ + elem = parent; + RotateLeft(elem); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateRight(grandparent); + } + } + else + { + /* mirror image of above code */ + I uncle = LeftChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsLeftChild(elem)) + { + /* make x a right child, will change parent and grandparent */ + elem = parent; + RotateRight(parent); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateLeft(grandparent); + } + } + } + SetColor( m_Root, BLACK ); +} + + +//----------------------------------------------------------------------------- +// Insert a node into the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +I CUtlRBTree::InsertAt( I parent, bool leftchild ) +{ + I i = NewNode(); + LinkToParent( i, parent, leftchild ); + ++m_NumElements; + + Assert(IsValid()); + + return i; +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::LinkToParent( I i, I parent, bool isLeft ) +{ + Links_t &elem = Links(i); + elem.m_Parent = parent; + elem.m_Left = elem.m_Right = InvalidIndex(); + elem.m_Tag = RED; + + /* insert node in tree */ + if (parent != InvalidIndex()) + { + if (isLeft) + Links(parent).m_Left = i; + else + Links(parent).m_Right = i; + } + else + { + m_Root = i; + } + + InsertRebalance(i); +} + +//----------------------------------------------------------------------------- +// Rebalance the tree after a deletion +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveRebalance(I elem) +{ + while (elem != m_Root && IsBlack(elem)) + { + I parent = Parent(elem); + + // If elem is the left child of the parent + if (elem == LeftChild(parent)) + { + // Get our sibling + I sibling = RightChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateLeft(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = RightChild(parent); + } + if ( (IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor(sibling, RED); + elem = parent; + } + else + { + if (IsBlack(RightChild(sibling))) + { + SetColor(LeftChild(sibling), BLACK); + SetColor(sibling, RED); + RotateRight(sibling); + + // rotation may have changed this + parent = Parent(elem); + sibling = RightChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( RightChild(sibling), BLACK ); + RotateLeft( parent ); + elem = m_Root; + } + } + else + { + // Elem is the right child of the parent + I sibling = LeftChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateRight(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = LeftChild(parent); + } + if ( (IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor( sibling, RED ); + elem = parent; + } + else + { + if (IsBlack(LeftChild(sibling))) + { + SetColor( RightChild(sibling), BLACK ); + SetColor( sibling, RED ); + RotateLeft( sibling ); + + // rotation may have changed this + parent = Parent(elem); + sibling = LeftChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( LeftChild(sibling), BLACK ); + RotateRight( parent ); + elem = m_Root; + } + } + } + SetColor( elem, BLACK ); +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Unlink( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I x, y; + + if ((LeftChild(elem) == InvalidIndex()) || + (RightChild(elem) == InvalidIndex())) + { + /* y has a NIL node as a child */ + y = elem; + } + else + { + /* find tree successor with a NIL node as a child */ + y = RightChild(elem); + while (LeftChild(y) != InvalidIndex()) + y = LeftChild(y); + } + + /* x is y's only child */ + if (LeftChild(y) != InvalidIndex()) + x = LeftChild(y); + else + x = RightChild(y); + + /* remove y from the parent chain */ + if (x != InvalidIndex()) + SetParent( x, Parent(y) ); + if (!IsRoot(y)) + { + if (IsLeftChild(y)) + SetLeftChild( Parent(y), x ); + else + SetRightChild( Parent(y), x ); + } + else + m_Root = x; + + // need to store this off now, we'll be resetting y's color + NodeColor_t ycolor = Color(y); + if (y != elem) + { + // Standard implementations copy the data around, we cannot here. + // Hook in y to link to the same stuff elem used to. + SetParent( y, Parent(elem) ); + SetRightChild( y, RightChild(elem) ); + SetLeftChild( y, LeftChild(elem) ); + + if (!IsRoot(elem)) + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), y ); + else + SetRightChild( Parent(elem), y ); + else + m_Root = y; + + if (LeftChild(y) != InvalidIndex()) + SetParent( LeftChild(y), y ); + if (RightChild(y) != InvalidIndex()) + SetParent( RightChild(y), y ); + + SetColor( y, Color(elem) ); + } + + if ((x != InvalidIndex()) && (ycolor == BLACK)) + RemoveRebalance(x); + } +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Link( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I parent; + bool leftchild; + + FindInsertionPosition( Element( elem ), parent, leftchild ); + + LinkToParent( elem, parent, leftchild ); + + Assert(IsValid()); + } +} + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveAt(I elem) +{ + if ( elem != InvalidIndex() ) + { + Unlink( elem ); + + FreeNode(elem); + --m_NumElements; + + Assert(IsValid()); + } +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > bool CUtlRBTree::Remove( T const &search ) +{ + I node = Find( search ); + if (node != InvalidIndex()) + { + RemoveAt(node); + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveAll() +{ + // Have to do some convoluted stuff to invoke the destructor on all + // valid elements for the multilist case (since we don't have all elements + // connected to each other in a list). + + if ( m_LastAlloc == m_Elements.InvalidIterator() ) + { + Assert( m_Root == InvalidIndex() ); + Assert( m_FirstFree == InvalidIndex() ); + Assert( m_NumElements == 0 ); + return; + } + + for ( typename M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) + { + I i = m_Elements.GetIndex( it ); + if ( IsValidIndex( i ) ) // skip elements in the free list + { + Destruct( &Element( i ) ); + SetRightChild( i, m_FirstFree ); + SetLeftChild( i, i ); + m_FirstFree = i; + } + + if ( it == m_LastAlloc ) + break; // don't destruct elements that haven't ever been constucted + } + + // Clear everything else out + m_Root = InvalidIndex(); + // Technically, this iterator could become invalid. It will not, because it's + // always the same iterator. If we don't clear this here, the state of this + // container will be invalid after we start inserting elements again. + m_LastAlloc = m_Elements.InvalidIterator(); + m_FirstFree = InvalidIndex(); + m_NumElements = 0; + + Assert( IsValid() ); +} + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree and purges memory +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::Purge() +{ + RemoveAll(); + m_Elements.Purge(); +} + + +//----------------------------------------------------------------------------- +// iteration +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstInorder() const +{ + I i = m_Root; + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextInorder( I i ) const +{ + // Don't go into an infinite loop if it's a bad index + Assert(IsValidIndex(i)); + if ( !IsValidIndex(i) ) + return InvalidIndex(); + + if (RightChild(i) != InvalidIndex()) + { + i = RightChild(i); + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; + } + + I parent = Parent(i); + while (IsRightChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::PrevInorder( I i ) const +{ + // Don't go into an infinite loop if it's a bad index + Assert(IsValidIndex(i)); + if ( !IsValidIndex(i) ) + return InvalidIndex(); + + if (LeftChild(i) != InvalidIndex()) + { + i = LeftChild(i); + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; + } + + I parent = Parent(i); + while (IsLeftChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::LastInorder() const +{ + I i = m_Root; + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstPreorder() const +{ + return m_Root; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextPreorder( I i ) const +{ + if (LeftChild(i) != InvalidIndex()) + return LeftChild(i); + + if (RightChild(i) != InvalidIndex()) + return RightChild(i); + + I parent = Parent(i); + while( parent != InvalidIndex()) + { + if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex())) + return RightChild(parent); + i = parent; + parent = Parent(parent); + } + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::PrevPreorder( I i ) const +{ + Assert(0); // not implemented yet + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::LastPreorder() const +{ + I i = m_Root; + while (1) + { + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + + if (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + else + break; + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstPostorder() const +{ + I i = m_Root; + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextPostorder( I i ) const +{ + I parent = Parent(i); + if (parent == InvalidIndex()) + return InvalidIndex(); + + if (IsRightChild(i)) + return parent; + + if (RightChild(parent) == InvalidIndex()) + return parent; + + i = RightChild(parent); + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Reinsert( I elem ) +{ + Unlink( elem ); + Link( elem ); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +int CUtlRBTree::Depth( I node ) const +{ + if (node == InvalidIndex()) + return 0; + + int depthright = Depth( RightChild(node) ); + int depthleft = Depth( LeftChild(node) ); + return Max(depthright, depthleft) + 1; +} + + +//#define UTLTREE_PARANOID + +//----------------------------------------------------------------------------- +// Makes sure the tree is valid after every operation +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +bool CUtlRBTree::IsValid() const +{ + if ( !Count() ) + return true; + + if ( m_LastAlloc == m_Elements.InvalidIterator() ) + return false; + + if ( !m_Elements.IsIdxValid( Root() ) ) + return false; + + if ( Parent( Root() ) != InvalidIndex() ) + return false; + +#ifdef UTLTREE_PARANOID + + // First check to see that mNumEntries matches reality. + // count items on the free list + int numFree = 0; + for ( int i = m_FirstFree; i != InvalidIndex(); i = RightChild( i ) ) + { + ++numFree; + if ( !m_Elements.IsIdxValid( i ) ) + return false; + } + + // iterate over all elements, looking for validity + // based on the self pointers + int nElements = 0; + int numFree2 = 0; + for ( M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) + { + I i = m_Elements.GetIndex( it ); + if ( !IsValidIndex( i ) ) + { + ++numFree2; + } + else + { + ++nElements; + + int right = RightChild( i ); + int left = LeftChild( i ); + if ( ( right == left ) && ( right != InvalidIndex() ) ) + return false; + + if ( right != InvalidIndex() ) + { + if ( !IsValidIndex( right ) ) + return false; + if ( Parent( right ) != i ) + return false; + if ( IsRed( i ) && IsRed( right ) ) + return false; + } + + if ( left != InvalidIndex() ) + { + if ( !IsValidIndex( left ) ) + return false; + if ( Parent( left ) != i ) + return false; + if ( IsRed( i ) && IsRed( left ) ) + return false; + } + } + + if ( it == m_LastAlloc ) + break; + } + if ( numFree2 != numFree ) + return false; + + if ( nElements != m_NumElements ) + return false; + +#endif // UTLTREE_PARANOID + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets the less func +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::SetLessFunc( const typename CUtlRBTree::LessFunc_t &func ) +{ + if (!m_LessFunc) + { + m_LessFunc = func; + } + else if ( Count() > 0 ) + { + // need to re-sort the tree here.... + Assert(0); + } +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- + +// Inserts a node into the tree, doesn't copy the data in. +template < class T, class I, typename L, class M > +void CUtlRBTree::FindInsertionPosition( T const &insert, I &parent, bool &leftchild ) +{ + Assert( m_LessFunc ); + + /* find where node belongs */ + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else + { + leftchild = false; current = RightChild(current); + } + } +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::Insert( T const &insert ) +{ + // use copy constructor to copy it in + I parent; + bool leftchild; + FindInsertionPosition( insert, parent, leftchild ); + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Insert( const T *pArray, int nItems ) +{ + while ( nItems-- ) + { + Insert( *pArray++ ); + } +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree::InsertIfNotFound( T const &insert ) +{ + // use copy constructor to copy it in + I parent; + bool leftchild; + + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else if (m_LessFunc( Element(current), insert )) + { + leftchild = false; current = RightChild(current); + } + else + // Match found, no insertion + return InvalidIndex(); + } + + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- +template < class T, class I, typename L, class M > +I CUtlRBTree::Find( T const &search ) const +{ + Assert( m_LessFunc ); + + I current = m_Root; + while (current != InvalidIndex()) + { + if (m_LessFunc( search, Element(current) )) + current = LeftChild(current); + else if (m_LessFunc( Element(current), search )) + current = RightChild(current); + else + break; + } + return current; +} + + +//----------------------------------------------------------------------------- +// swap in place +//----------------------------------------------------------------------------- +template < class T, class I, typename L, class M > +void CUtlRBTree::Swap( CUtlRBTree< T, I, L > &that ) +{ + m_Elements.Swap( that.m_Elements ); + V_swap( m_LessFunc, that.m_LessFunc ); + V_swap( m_Root, that.m_Root ); + V_swap( m_NumElements, that.m_NumElements ); + V_swap( m_FirstFree, that.m_FirstFree ); + V_swap( m_pElements, that.m_pElements ); + V_swap( m_LastAlloc, that.m_LastAlloc ); + Assert( IsValid() ); + Assert( m_Elements.IsValidIterator( m_LastAlloc ) || ( m_NumElements == 0 && m_FirstFree == InvalidIndex() ) ); +} + + +#endif // UTLRBTREE_H diff --git a/public/tier1/utlsoacontainer.h b/public/tier1/utlsoacontainer.h new file mode 100644 index 0000000..b9440c5 --- /dev/null +++ b/public/tier1/utlsoacontainer.h @@ -0,0 +1,334 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A Fixed-allocation class for maintaining a 1d or 2d or 3d array of data in a structure-of-arrays +// (SOA) sse-friendly manner. +// =============================================================================// + +#ifndef UTLSOACONTAINER_H +#define UTLSOACONTAINER_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "tier1/utlmemory.h" +#include "tier1/utlblockmemory.h" +#include "mathlib/ssemath.h" + + +// strided pointers. gives you a class that acts like a pointer, but the ++ and += operators do the +// right thing +template class CStridedPtr +{ +protected: + T *m_pData; + size_t m_nStride; + +public: + FORCEINLINE CStridedPtr( void *pData, size_t nByteStride ) + { + m_pData = reinterpret_cast( pData ); + m_nStride = nByteStride / sizeof( T ); + } + + FORCEINLINE CStridedPtr( void ) {} + T *operator->(void) const + { + return m_pData; + } + + T & operator*(void) const + { + return *m_pData; + } + + FORCEINLINE operator T *(void) + { + return m_pData; + } + + FORCEINLINE CStridedPtr & operator++(void) + { + m_pData += m_nStride; + return *this; + } + + FORCEINLINE void operator+=( size_t nNumElements ) + { + m_pData += nNumElements * m_nStride; + } + +}; + +template class CStridedConstPtr +{ +protected: + const T *m_pData; + size_t m_nStride; + +public: + FORCEINLINE CStridedConstPtr( void const *pData, size_t nByteStride ) + { + m_pData = reinterpret_cast( pData ); + m_nStride = nByteStride / sizeof( T ); + } + + FORCEINLINE CStridedConstPtr( void ) {} + + const T *operator->(void) const + { + return m_pData; + } + + const T & operator*(void) const + { + return *m_pData; + } + + FORCEINLINE operator const T *(void) const + { + return m_pData; + } + + FORCEINLINE CStridedConstPtr &operator++(void) + { + m_pData += m_nStride; + return *this; + } + FORCEINLINE void operator+=( size_t nNumElements ) + { + m_pData += nNumElements*m_nStride; + } +}; + +// allowed field data types. if you change these values, you need to change the tables in the .cpp file +enum EAttributeDataType +{ + ATTRDATATYPE_FLOAT = 0, // a float attribute + ATTRDATATYPE_4V = 1, // vector data type, stored as class FourVectors + ATTRDATATYPE_INT = 2, // integer. not especially sse-able on + // all architectures. + ATTRDATATYPE_POINTER = 3, // a pointer. + ATTRDATATYPE_NONE = -1, // pad and varargs ender +}; + +#define MAX_SOA_FIELDS 32 + +class CSOAContainer +{ + +protected: + int m_nColumns; // # of rows and columns created with + int m_nRows; + int m_nSlices; + + int m_nPaddedColumns; // # of columns rounded up for sse + int m_nNumQuadsPerRow; // # of groups of 4 elements per row + + uint8 *m_pDataMemory; // the actual data memory + uint8 *m_pAttributePtrs[MAX_SOA_FIELDS]; + + EAttributeDataType m_nDataType[MAX_SOA_FIELDS]; + + size_t m_nStrideInBytes[MAX_SOA_FIELDS]; // stride from one field datum to another + size_t m_nRowStrideInBytes[MAX_SOA_FIELDS]; // stride from one row datum to another per field + size_t m_nSliceStrideInBytes[MAX_SOA_FIELDS]; // stride from one slice datum to another per field + + + + uint32 m_nFieldPresentMask; + + FORCEINLINE void Init( void ) + { + memset( m_nDataType, 0xff, sizeof( m_nDataType ) ); + m_pDataMemory = 0; + m_nColumns = m_nPaddedColumns = m_nRows = m_nSlices = 0; + m_nFieldPresentMask = 0; + } +public: + + + CSOAContainer( void ) // an empoty one with no attributes + { + Init(); + } + + void Purge( void ); // set back to un-initted state, freeing memory + + ~CSOAContainer( void ); + + // easy constructor for 2d using varargs. call like + // #define ATTR_RED 0 + // #define ATTR_GREEN 1 + // #define ATTR_BLUE 2 + // CSOAContainer myimage( 256, 256, ATTR_RED, ATTRDATATYPE_FLOAT, ATTR_GREEN, ATTRDATATYPE_FLOAT, + // ATTR_BLUE, ATTRDATATYPE_FLOAT, -1 ); + + CSOAContainer( int nCols, int nRows, ... ); + + size_t ElementSize( void ) const; // total bytes per element. not super fast. + + // set the data type for an attribute. If you set the data type, but tell it not to allocate, + // the data type will be set but writes will assert, and reads will give you back zeros. + FORCEINLINE void SetAttributeType( int nAttrIdx, EAttributeDataType nDataType, bool bAllocateMemory = true ) + { + Assert( !m_pDataMemory ); // can't change after memory allocated + Assert( nAttrIdx < MAX_SOA_FIELDS ); + m_nDataType[nAttrIdx] = nDataType; + if ( ( m_nDataType[nAttrIdx] != ATTRDATATYPE_NONE ) && bAllocateMemory ) + m_nFieldPresentMask |= ( 1 << nAttrIdx ); + else + m_nFieldPresentMask &= ~( 1 << nAttrIdx ); + } + + FORCEINLINE int NumRows( void ) const + { + return m_nRows; + } + + FORCEINLINE int NumCols( void ) const + { + return m_nColumns; + } + FORCEINLINE int NumSlices( void ) const + { + return m_nSlices; + } + + + FORCEINLINE void AssertDataType( int nAttrIdx, EAttributeDataType nDataType ) const + { + Assert( nAttrIdx >= 0 ); + Assert( nAttrIdx < MAX_SOA_FIELDS ); + Assert( m_nStrideInBytes[nAttrIdx] ); + } + + + // # of groups of 4 elements per row + FORCEINLINE int NumQuadsPerRow( void ) const + { + return m_nNumQuadsPerRow; + } + + FORCEINLINE int Count( void ) const // for 1d data + { + return NumCols(); + } + + FORCEINLINE int NumElements( void ) const + { + return NumCols() * NumRows() * NumSlices(); + } + + + // how much to step to go from the end of one row to the start of the next one. Basically, how + // many bytes to add at the end of a row when iterating over the whole 2d array with ++ + FORCEINLINE size_t RowToRowStep( int nAttrIdx ) const + { + return 0; + } + + FORCEINLINE void *RowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const + { + Assert( nRowNumber < m_nRows ); + Assert( nAttributeIdx < MAX_SOA_FIELDS ); + Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE ); + Assert( m_nFieldPresentMask & ( 1 << nAttributeIdx ) ); + return m_pAttributePtrs[nAttributeIdx] + + + nRowNumber * m_nRowStrideInBytes[nAttributeIdx] + + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx]; + } + + FORCEINLINE void const *ConstRowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const + { + Assert( nRowNumber < m_nRows ); + Assert( nAttributeIdx < MAX_SOA_FIELDS ); + Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE ); + return m_pAttributePtrs[nAttributeIdx] + + nRowNumber * m_nRowStrideInBytes[nAttributeIdx] + + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx]; + } + + + template FORCEINLINE T *ElementPointer( int nAttributeIdx, + int nX = 0, int nY = 0, int nZ = 0 ) const + { + Assert( nAttributeIdx < MAX_SOA_FIELDS ); + Assert( nX < m_nColumns ); + Assert( nY < m_nRows ); + Assert( nZ < m_nSlices ); + Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE ); + Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_4V ); + return reinterpret_cast( m_pAttributePtrs[nAttributeIdx] + + nX * sizeof( float ) + + nY * m_nRowStrideInBytes[nAttributeIdx] + + nZ * m_nSliceStrideInBytes[nAttributeIdx] + ); + } + + FORCEINLINE size_t ItemByteStride( int nAttributeIdx ) const + { + Assert( nAttributeIdx < MAX_SOA_FIELDS ); + Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE ); + return m_nStrideInBytes[ nAttributeIdx ]; + } + + // copy the attribute data from another soacontainer. must be compatible geometry + void CopyAttrFrom( CSOAContainer const &other, int nAttributeIdx ); + + // copy the attribute data from another attribute. must be compatible data format + void CopyAttrToAttr( int nSrcAttributeIndex, int nDestAttributeIndex); + + // move all the data from one csoacontainer to another, leaving the source empty. + // this is just a pointer copy. + FORCEINLINE void MoveDataFrom( CSOAContainer other ) + { + (*this) = other; + other.Init(); + } + + + + void AllocateData( int nNCols, int nNRows, int nSlices = 1 ); // actually allocate the memory and set the pointers up + + // arithmetic and data filling functions. All SIMD and hopefully fast + + // set all elements of a float attribute to random #s + void RandomizeAttribute( int nAttr, float flMin, float flMax ) const ; + + // fill 2d a rectangle with values interpolated from 4 corner values. + void FillAttrWithInterpolatedValues( int nAttr, float flValue00, float flValue10, float flValue01, float flValue11 ) const; + void FillAttrWithInterpolatedValues( int nAttr, Vector flValue00, Vector flValue10, + Vector const &flValue01, Vector const &flValue11 ) const; + +}; + +class CFltX4AttributeIterator : public CStridedConstPtr +{ + FORCEINLINE CFltX4AttributeIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 ) + : CStridedConstPtr( pContainer->ConstRowPtr( nAttribute, nRowNumber), + pContainer->ItemByteStride( nAttribute ) ) + { + } +}; + +class CFltX4AttributeWriteIterator : public CStridedPtr +{ + FORCEINLINE CFltX4AttributeWriteIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 ) + : CStridedPtr( pContainer->RowPtr( nAttribute, nRowNumber), + pContainer->ItemByteStride( nAttribute ) ) + { + } + +}; + + +#endif diff --git a/public/tier1/utlstack.h b/public/tier1/utlstack.h new file mode 100644 index 0000000..a46beb2 --- /dev/null +++ b/public/tier1/utlstack.h @@ -0,0 +1,331 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A stack based on a growable array +//=============================================================================// + +#ifndef UTLSTACK_H +#define UTLSTACK_H + +#include +#include +#include "utlmemory.h" + + +//----------------------------------------------------------------------------- +// The CUtlStack class: +// A growable stack class which doubles in size by default. +// It will always keep all elements consecutive in memory, and may move the +// elements around in memory (via a realloc) when elements are pushed or +// popped. Clients should therefore refer to the elements of the stack +// by index (they should *never* maintain pointers to elements in the stack). +//----------------------------------------------------------------------------- + +template< class T, class M = CUtlMemory< T > > +class CUtlStack +{ +public: + // constructor, destructor + CUtlStack( int growSize = 0, int initSize = 0 ); + ~CUtlStack(); + + void CopyFrom( const CUtlStack &from ); + + // element access + T& operator[]( int i ); + T const& operator[]( int i ) const; + T& Element( int i ); + T const& Element( int i ) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Looks at the stack top + T& Top(); + T const& Top() const; + + // Size + int Count() const; + + // Is element index valid? + bool IsIdxValid( int i ) const; + + // Adds an element, uses default constructor + int Push(); + + // Adds an element, uses copy constructor + int Push( T const& src ); + + // Pops the stack + void Pop(); + void Pop( T& oldTop ); + void PopMultiple( int num ); + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Clears the stack, no deallocation + void Clear(); + + // Memory deallocation + void Purge(); + +private: + // Grows the stack allocation + void GrowStack(); + + // For easier access to the elements through the debugger + void ResetDbgInfo(); + + M m_Memory; + int m_Size; + + // For easier access to the elements through the debugger + T* m_pElements; +}; + + +//----------------------------------------------------------------------------- +// For easier access to the elements through the debugger +//----------------------------------------------------------------------------- + +template< class T, class M > +inline void CUtlStack::ResetDbgInfo() +{ + m_pElements = m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class M > +CUtlStack::CUtlStack( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T, class M > +CUtlStack::~CUtlStack() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// copy into +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack::CopyFrom( const CUtlStack &from ) +{ + Purge(); + EnsureCapacity( from.Count() ); + for ( int i = 0; i < from.Count(); i++ ) + { + Push( from[i] ); + } +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T& CUtlStack::operator[]( int i ) +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + +template< class T, class M > +inline T const& CUtlStack::operator[]( int i ) const +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + +template< class T, class M > +inline T& CUtlStack::Element( int i ) +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + +template< class T, class M > +inline T const& CUtlStack::Element( int i ) const +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T* CUtlStack::Base() +{ + return m_Memory.Base(); +} + +template< class T, class M > +inline T const* CUtlStack::Base() const +{ + return m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// Returns the top of the stack +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T& CUtlStack::Top() +{ + assert( m_Size > 0 ); + return Element(m_Size-1); +} + +template< class T, class M > +inline T const& CUtlStack::Top() const +{ + assert( m_Size > 0 ); + return Element(m_Size-1); +} + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- + +template< class T, class M > +inline int CUtlStack::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- + +template< class T, class M > +inline bool CUtlStack::IsIdxValid( int i ) const +{ + return (i >= 0) && (i < m_Size); +} + +//----------------------------------------------------------------------------- +// Grows the stack +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack::GrowStack() +{ + if (m_Size >= m_Memory.NumAllocated()) + m_Memory.Grow(); + + ++m_Size; + + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack::EnsureCapacity( int num ) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- + +template< class T, class M > +int CUtlStack::Push() +{ + GrowStack(); + Construct( &Element(m_Size-1) ); + return m_Size - 1; +} + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- + +template< class T, class M > +int CUtlStack::Push( T const& src ) +{ + GrowStack(); + CopyConstruct( &Element(m_Size-1), src ); + return m_Size - 1; +} + + +//----------------------------------------------------------------------------- +// Pops the stack +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack::Pop() +{ + assert( m_Size > 0 ); + Destruct( &Element(m_Size-1) ); + --m_Size; +} + +template< class T, class M > +void CUtlStack::Pop( T& oldTop ) +{ + assert( m_Size > 0 ); + oldTop = Top(); + Pop(); +} + +template< class T, class M > +void CUtlStack::PopMultiple( int num ) +{ + assert( m_Size >= num ); + for ( int i = 0; i < num; ++i ) + Destruct( &Element( m_Size - i - 1 ) ); + m_Size -= num; +} + + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack::Clear() +{ + for (int i = m_Size; --i >= 0; ) + Destruct(&Element(i)); + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack::Purge() +{ + Clear(); + m_Memory.Purge( ); + ResetDbgInfo(); +} + +#endif // UTLSTACK_H \ No newline at end of file diff --git a/public/tier1/utlstring.h b/public/tier1/utlstring.h new file mode 100644 index 0000000..3ff74dc --- /dev/null +++ b/public/tier1/utlstring.h @@ -0,0 +1,435 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef UTLSTRING_H +#define UTLSTRING_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/utlmemory.h" +#include "tier1/strtools.h" +#include "limits.h" + +//----------------------------------------------------------------------------- +// Simple string class. +// NOTE: This is *not* optimal! Use in tools, but not runtime code +//----------------------------------------------------------------------------- +class CUtlString +{ +public: + typedef enum + { + PATTERN_NONE = 0x00000000, + PATTERN_DIRECTORY = 0x00000001 + } TUtlStringPattern; + +public: + CUtlString(); + CUtlString( const char *pString ); + CUtlString( const char *pString, int length ); + CUtlString( const CUtlString& string ); + +#ifdef MOVE_CONSTRUCTOR_SUPPORT + // Support moving of CUtlString objects. Long live C++11 + // This move constructor will get called when appropriate, such as when + // returning objects from functions, or otherwise copying from temporaries + // which are about to be destroyed. It can also be explicitly invoked with + // std::move(). + // Move constructor: + CUtlString( CUtlString&& rhs ) + { + // Move the string pointer from the source to this -- be sure to + // zero out the source to avoid double frees. + m_pString = rhs.m_pString; + rhs.m_pString = 0; + } + // Move assignment operator: + CUtlString& operator=( CUtlString&& rhs ) + { + // Move the string pointer from the source to this -- be sure to + // zero out the source to avoid double frees. + m_pString = rhs.m_pString; + rhs.m_pString = 0; + return *this; + } +#endif + + ~CUtlString(); + + const char *Get( ) const; + void Set( const char *pValue ); + operator const char*() const; + + // Set directly and don't look for a null terminator in pValue. + // nChars does not include the nul and this will only copy + // at most nChars (even if pValue is longer). If nChars + // is >strlen(pValue) it will copy past the end, don't do it + // Does nothing if pValue == String() + void SetDirect( const char *pValue, int nChars ); + + // for compatibility switching items from UtlSymbol + const char *String() const { return Get(); } + + // Returns strlen + int Length() const; + // IsEmpty() is more efficient than Length() == 0 + bool IsEmpty() const; + + // Sets the length (used to serialize into the buffer ) + // Note: If nLen != 0, then this adds an extra byte for a null-terminator. + void SetLength( int nLen ); + char *GetForModify(); + void Clear(); + void Purge(); + + // Case Change + void ToLower(); + void ToUpper(); + void Append( const char *pAddition, int nChars ); + + void Append( const char *pchAddition ); + void Append( const char chAddition ) { char temp[2] = { chAddition, 0 }; Append( temp ); } + // Strips the trailing slash + void StripTrailingSlash(); + void FixSlashes( char cSeparator = CORRECT_PATH_SEPARATOR ); + + // Trim whitespace + void TrimLeft( char cTarget ); + void TrimLeft( const char *szTargets = "\t\r\n " ); + void TrimRight( char cTarget ); + void TrimRight( const char *szTargets = "\t\r\n " ); + void Trim( char cTarget ); + void Trim( const char *szTargets = "\t\r\n " ); + + bool IsEqual_CaseSensitive( const char *src ) const; + bool IsEqual_CaseInsensitive( const char *src ) const; + + CUtlString &operator=( const CUtlString &src ); + CUtlString &operator=( const char *src ); + + // Test for equality + bool operator==( const CUtlString &src ) const; + bool operator!=( const CUtlString &src ) const { return !operator==( src ); } + + CUtlString &operator+=( const CUtlString &rhs ); + CUtlString &operator+=( const char *rhs ); + CUtlString &operator+=( char c ); + CUtlString &operator+=( int rhs ); + CUtlString &operator+=( double rhs ); + + CUtlString operator+( const char *pOther ) const; + CUtlString operator+( const CUtlString &other ) const; + CUtlString operator+( int rhs ) const; + + bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ) const; // case SENSITIVE, use * for wildcard in pattern string + + char operator[]( int i ) const; + +#if ! defined(SWIG) + // Don't let SWIG see the PRINTF_FORMAT_STRING attribute or it will complain. + int Format( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); + int FormatV( PRINTF_FORMAT_STRING const char *pFormat, va_list marker ); +#else + int Format( const char *pFormat, ... ); + int FormatV( const char *pFormat, va_list marker ); +#endif + + // Defining AltArgumentType_t hints that associative container classes should + // also implement Find/Insert/Remove functions that take const char* params. + typedef const char *AltArgumentType_t; + + // Get a copy of part of the string. + // If you only specify nStart, it'll go from nStart to the end. + // You can use negative numbers and it'll wrap around to the start. + CUtlString Slice( int32 nStart=0, int32 nEnd=INT_MAX ) const; + + // Get a substring starting from the left or the right side. + CUtlString Left( int32 nChars ) const; + CUtlString Right( int32 nChars ) const; + + // Get a string with all instances of one character replaced with another. + CUtlString Replace( char cFrom, char cTo ) const; + + // Replace all instances of specified string with another. + CUtlString Replace( const char *pszFrom, const char *pszTo ) const; + + // Get this string as an absolute path (calls right through to V_MakeAbsolutePath). + CUtlString AbsPath( const char *pStartingDir=NULL ) const; + + // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt). + CUtlString UnqualifiedFilename() const; + + // Gets a string with one directory removed. Uses V_StripLastDir but strips the last slash also! + CUtlString DirName() const; + + // Get a string with the extension removed (with V_StripExtension). + CUtlString StripExtension() const; + + // Get a string with the filename removed (uses V_UnqualifiedFileName and also strips the last slash) + CUtlString StripFilename() const; + + // Get a string with the base filename (with V_FileBase). + CUtlString GetBaseFilename() const; + + // Get a string with the file extension (with V_FileBase). + CUtlString GetExtension() const; + + // Works like V_ComposeFileName. + static CUtlString PathJoin( const char *pStr1, const char *pStr2 ); + + // These can be used for utlvector sorts. + static int __cdecl SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 ); + static int __cdecl SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 ); + + // Empty string for those times when you need to return an empty string and + // either don't want to pay the construction cost, or are returning a + // const CUtlString& and cannot just return "". + static const CUtlString &GetEmptyString(); + +private: + // INTERNALS + // AllocMemory allocates enough space for length characters plus a terminating zero. + // Previous characters are preserved, the buffer is null-terminated, but new characters + // are not touched. + void *AllocMemory( uint32 length ); + + // If m_pString is not NULL, it points to the start of the string, and the memory allocation. + char *m_pString; +}; + +// // If these are not defined, CUtlConstString as rhs will auto-convert +// // to const char* and do logical operations on the raw pointers. Ugh. +// inline friend bool operator<( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) > 0; } +// inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; } +// inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; } + +inline bool operator==( const char *pString, const CUtlString &utlString ) +{ + return utlString.IsEqual_CaseSensitive( pString ); +} + +inline bool operator!=( const char *pString, const CUtlString &utlString ) +{ + return !utlString.IsEqual_CaseSensitive( pString ); +} + +inline bool operator==( const CUtlString &utlString, const char *pString ) +{ + return utlString.IsEqual_CaseSensitive( pString ); +} + +inline bool operator!=( const CUtlString &utlString, const char *pString ) +{ + return !utlString.IsEqual_CaseSensitive( pString ); +} + + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline CUtlString::CUtlString() +: m_pString( NULL ) +{ +} + +inline CUtlString::CUtlString( const char *pString ) +: m_pString( NULL ) +{ + Set( pString ); +} + +inline CUtlString::CUtlString( const char *pString, int length ) +: m_pString( NULL ) +{ + SetDirect( pString, length ); +} + +inline CUtlString::CUtlString( const CUtlString& string ) +: m_pString( NULL ) +{ + Set( string.Get() ); +} + +inline CUtlString::~CUtlString() +{ + Purge(); +} + +inline int CUtlString::Length() const +{ + if (m_pString) + { + return V_strlen( m_pString ); + } + return 0; +} + +inline bool CUtlString::IsEmpty() const +{ + return !m_pString || m_pString[0] == 0; +} + +inline int __cdecl CUtlString::SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 ) +{ + return V_stricmp( pString1->String(), pString2->String() ); +} + +inline int __cdecl CUtlString::SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 ) +{ + return V_strcmp( pString1->String(), pString2->String() ); +} + +// Converts to c-strings +inline CUtlString::operator const char*() const +{ + return Get(); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Implementation of low-level string functionality for character types. +//----------------------------------------------------------------------------- + +template < typename T > +class StringFuncs +{ +public: + static T *Duplicate( const T *pValue ); + // Note that this function takes a character count, and does not guarantee null-termination. + static void Copy( T *out_pOut, const T *pIn, int iLengthInChars ); + static int Compare( const T *pLhs, const T *pRhs ); + static int CaselessCompare( const T *pLhs, const T *pRhs ); + static int Length( const T *pValue ); + static const T *FindChar( const T *pStr, const T cSearch ); + static const T *EmptyString(); + static const T *NullDebugString(); +}; + +template < > +class StringFuncs +{ +public: + static char *Duplicate( const char *pValue ) { return strdup( pValue ); } + // Note that this function takes a character count, and does not guarantee null-termination. + static void Copy( OUT_CAP(iLengthInChars) char *out_pOut, const char *pIn, int iLengthInChars ) { strncpy( out_pOut, pIn, iLengthInChars ); } + static int Compare( const char *pLhs, const char *pRhs ) { return strcmp( pLhs, pRhs ); } + static int CaselessCompare( const char *pLhs, const char *pRhs ) { return Q_strcasecmp( pLhs, pRhs ); } + static int Length( const char *pValue ) { return (int)strlen( pValue ); } + static const char *FindChar( const char *pStr, const char cSearch ) { return strchr( pStr, cSearch ); } + static const char *EmptyString() { return ""; } + static const char *NullDebugString() { return "(null)"; } +}; + +template < > +class StringFuncs +{ +public: + static wchar_t *Duplicate( const wchar_t *pValue ) { return wcsdup( pValue ); } + // Note that this function takes a character count, and does not guarantee null-termination. + static void Copy( OUT_CAP(iLengthInChars) wchar_t *out_pOut, const wchar_t *pIn, int iLengthInChars ) { wcsncpy( out_pOut, pIn, iLengthInChars ); } + static int Compare( const wchar_t *pLhs, const wchar_t *pRhs ) { return wcscmp( pLhs, pRhs ); } + static int CaselessCompare( const wchar_t *pLhs, const wchar_t *pRhs ); // no implementation? + static int Length( const wchar_t *pValue ) { return (int)wcslen( pValue ); } + static const wchar_t *FindChar( const wchar_t *pStr, const wchar_t cSearch ) { return wcschr( pStr, cSearch ); } + static const wchar_t *EmptyString() { return L""; } + static const wchar_t *NullDebugString() { return L"(null)"; } +}; + +//----------------------------------------------------------------------------- +// Dirt-basic auto-release string class. Not intended for manipulation, +// can be stored in a container or forwarded as a functor parameter. +// Note the benefit over CUtlString: sizeof(CUtlConstString) == sizeof(char*). +// Also note: null char* pointers are treated identically to empty strings. +//----------------------------------------------------------------------------- + +template < typename T = char > +class CUtlConstStringBase +{ +public: + CUtlConstStringBase() : m_pString( NULL ) {} + explicit CUtlConstStringBase( const T *pString ) : m_pString( NULL ) { Set( pString ); } + CUtlConstStringBase( const CUtlConstStringBase& src ) : m_pString( NULL ) { Set( src.m_pString ); } + ~CUtlConstStringBase() { Set( NULL ); } + + void Set( const T *pValue ); + void Clear() { Set( NULL ); } + + const T *Get() const { return m_pString ? m_pString : StringFuncs::EmptyString(); } + operator const T*() const { return m_pString ? m_pString : StringFuncs::EmptyString(); } + + bool IsEmpty() const { return m_pString == NULL; } // Note: empty strings are never stored by Set + + int Compare( const T *rhs ) const; + + // Logical ops + bool operator<( const T *rhs ) const { return Compare( rhs ) < 0; } + bool operator==( const T *rhs ) const { return Compare( rhs ) == 0; } + bool operator!=( const T *rhs ) const { return Compare( rhs ) != 0; } + bool operator<( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) < 0; } + bool operator==( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) == 0; } + bool operator!=( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) != 0; } + + // If these are not defined, CUtlConstString as rhs will auto-convert + // to const char* and do logical operations on the raw pointers. Ugh. + inline friend bool operator<( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) > 0; } + inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; } + inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; } + + CUtlConstStringBase &operator=( const T *src ) { Set( src ); return *this; } + CUtlConstStringBase &operator=( const CUtlConstStringBase &src ) { Set( src.m_pString ); return *this; } + + // Defining AltArgumentType_t is a hint to containers that they should + // implement Find/Insert/Remove functions that take const char* params. + typedef const T *AltArgumentType_t; + +protected: + const T *m_pString; +}; + +template < typename T > +void CUtlConstStringBase::Set( const T *pValue ) +{ + if ( pValue != m_pString ) + { + free( ( void* ) m_pString ); + m_pString = pValue && pValue[0] ? StringFuncs::Duplicate( pValue ) : NULL; + } +} + +template < typename T > +int CUtlConstStringBase::Compare( const T *rhs ) const +{ + // Empty or null RHS? + if ( !rhs || !rhs[0] ) + return m_pString ? 1 : 0; + + // Empty *this, non-empty RHS? + if ( !m_pString ) + return -1; + + // Neither empty + return StringFuncs::Compare( m_pString, rhs ); +} + +typedef CUtlConstStringBase CUtlConstString; +typedef CUtlConstStringBase CUtlConstWideString; + +//----------------------------------------------------------------------------- +// Helper functor objects. +//----------------------------------------------------------------------------- + +template < typename T > struct UTLConstStringCaselessStringLessFunctor { bool operator()( const CUtlConstStringBase& a, const char *b ) const { return StringFuncs::CaselessCompare( a.Get(), b ) < 0; } }; +template < typename T > struct UTLConstStringCaselessStringEqualFunctor { bool operator()( const CUtlConstStringBase& a, const char *b ) const { return StringFuncs::CaselessCompare( a.Get(), b ) == 0; } }; + +// Helper function for CUtlMaps with a CUtlString key +inline bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs ) { return V_strcmp( lhs.Get(), rhs.Get() ) < 0; } +inline bool UtlStringCaseInsensitiveLessFunc( const CUtlString &lhs, const CUtlString &rhs ) { return V_stricmp( lhs.Get(), rhs.Get() ) < 0; } + +#endif // UTLSTRING_H diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h new file mode 100644 index 0000000..f7e94f9 --- /dev/null +++ b/public/tier1/utlsymbol.h @@ -0,0 +1,272 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines a symbol table +// +// $Header: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef UTLSYMBOL_H +#define UTLSYMBOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/threadtools.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlvector.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class CUtlSymbolTable; +class CUtlSymbolTableMT; + + +//----------------------------------------------------------------------------- +// This is a symbol, which is a easier way of dealing with strings. +//----------------------------------------------------------------------------- +typedef unsigned short UtlSymId_t; + +#define UTL_INVAL_SYMBOL ((UtlSymId_t)~0) + +class CUtlSymbol +{ +public: + // constructor, destructor + CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {} + CUtlSymbol( UtlSymId_t id ) : m_Id(id) {} + CUtlSymbol( const char* pStr ); + CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {} + + // operator= + CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; } + + // operator== + bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; } + bool operator==( const char* pStr ) const; + + // Is valid? + bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; } + + // Gets at the symbol + operator UtlSymId_t() const { return m_Id; } + + // Gets the string associated with the symbol + const char* String( ) const; + + // Modules can choose to disable the static symbol table so to prevent accidental use of them. + static void DisableStaticSymbolTable(); + +protected: + UtlSymId_t m_Id; + + // Initializes the symbol table + static void Initialize(); + + // returns the current symbol table + static CUtlSymbolTableMT* CurrTable(); + + // The standard global symbol table + static CUtlSymbolTableMT* s_pSymbolTable; + + static bool s_bAllowStaticSymbolTable; + + friend class CCleanupUtlSymbolTable; +}; + + +//----------------------------------------------------------------------------- +// CUtlSymbolTable: +// description: +// This class defines a symbol table, which allows us to perform mappings +// of strings to symbols and back. The symbol class itself contains +// a static version of this class for creating global strings, but this +// class can also be instanced to create local symbol tables. +//----------------------------------------------------------------------------- + +class CUtlSymbolTable +{ +public: + // constructor, destructor + CUtlSymbolTable( int growSize = 0, int initSize = 32, bool caseInsensitive = false ); + ~CUtlSymbolTable(); + + // Finds and/or creates a symbol based on the string + CUtlSymbol AddString( const char* pString ); + + // Finds the symbol for pString + CUtlSymbol Find( const char* pString ) const; + + // Look up the string associated with a particular symbol + const char* String( CUtlSymbol id ) const; + + // Remove all symbols in the table. + void RemoveAll(); + + int GetNumStrings( void ) const + { + return m_Lookup.Count(); + } + +protected: + class CStringPoolIndex + { + public: + inline CStringPoolIndex() + { + } + + inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset ) + { + m_iPool = iPool; + m_iOffset = iOffset; + } + + inline bool operator==( const CStringPoolIndex &other ) const + { + return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset; + } + + unsigned short m_iPool; // Index into m_StringPools. + unsigned short m_iOffset; // Index into the string pool. + }; + + class CLess + { + public: + CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree + bool operator!() const { return false; } + bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const; + }; + + // Stores the symbol lookup + class CTree : public CUtlRBTree + { + public: + CTree( int growSize, int initSize ) : CUtlRBTree( growSize, initSize ) {} + friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table + }; + + struct StringPool_t + { + int m_TotalLen; // How large is + int m_SpaceUsed; + char m_Data[1]; + }; + + CTree m_Lookup; + bool m_bInsensitive; + mutable const char* m_pUserSearchString; + + // stores the string data + CUtlVector m_StringPools; + +private: + int FindPoolWithSpace( int len ) const; + const char* StringFromIndex( const CStringPoolIndex &index ) const; + + friend class CLess; +}; + +class CUtlSymbolTableMT : private CUtlSymbolTable +{ +public: + CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false ) + : CUtlSymbolTable( growSize, initSize, caseInsensitive ) + { + } + + CUtlSymbol AddString( const char* pString ) + { + m_lock.LockForWrite(); + CUtlSymbol result = CUtlSymbolTable::AddString( pString ); + m_lock.UnlockWrite(); + return result; + } + + CUtlSymbol Find( const char* pString ) const + { + m_lock.LockForRead(); + CUtlSymbol result = CUtlSymbolTable::Find( pString ); + m_lock.UnlockRead(); + return result; + } + + const char* String( CUtlSymbol id ) const + { + m_lock.LockForRead(); + const char *pszResult = CUtlSymbolTable::String( id ); + m_lock.UnlockRead(); + return pszResult; + } + +private: +#if defined(WIN32) || defined(_WIN32) + mutable CThreadSpinRWLock m_lock; +#else + mutable CThreadRWLock m_lock; +#endif +}; + + + +//----------------------------------------------------------------------------- +// CUtlFilenameSymbolTable: +// description: +// This class defines a symbol table of individual filenames, stored more +// efficiently than a standard symbol table. Internally filenames are broken +// up into file and path entries, and a file handle class allows convenient +// access to these. +//----------------------------------------------------------------------------- + +// The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor +// copies them into a static char buffer for return. +typedef void* FileNameHandle_t; +#define FILENAMEHANDLE_INVALID 0 + +// Symbol table for more efficiently storing filenames by breaking paths and filenames apart. +// Refactored from BaseFileSystem.h +class CUtlFilenameSymbolTable +{ + // Internal representation of a FileHandle_t + // If we get more than 64K filenames, we'll have to revisit... + // Right now CUtlSymbol is a short, so this packs into an int/void * pointer size... + struct FileNameHandleInternal_t + { + FileNameHandleInternal_t() + { + path = 0; + file = 0; + } + + // Part before the final '/' character + unsigned short path; + // Part after the final '/', including extension + unsigned short file; + }; + + class HashTable; + +public: + CUtlFilenameSymbolTable(); + ~CUtlFilenameSymbolTable(); + FileNameHandle_t FindOrAddFileName( const char *pFileName ); + FileNameHandle_t FindFileName( const char *pFileName ); + int PathIndex(const FileNameHandle_t &handle) { return (( const FileNameHandleInternal_t * )&handle)->path; } + bool String( const FileNameHandle_t& handle, char *buf, int buflen ); + void RemoveAll(); + +private: + //CCountedStringPool m_StringPool; + HashTable* m_Strings; +#if defined(_M_IX86) || defined(___i386__) || defined(__i386) || defined(__X86__) || defined(_X86_) || defined(__I86__) + int __padding; +#endif + mutable CThreadSpinRWLock m_lock; +}; + + +#endif // UTLSYMBOL_H diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h new file mode 100644 index 0000000..4384540 --- /dev/null +++ b/public/tier1/utlsymbollarge.h @@ -0,0 +1,499 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines a large symbol table (intp sized handles, can store more than 64k strings) +// +// $Header: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef UTLSYMBOLLARGE_H +#define UTLSYMBOLLARGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/threadtools.h" +#include "tier1/utltshash.h" +#include "tier1/stringpool.h" +#include "tier0/vprof.h" +#include "tier1/utltshash.h" + +//----------------------------------------------------------------------------- +// CUtlSymbolTableLarge: +// description: +// This class defines a symbol table, which allows us to perform mappings +// of strings to symbols and back. +// +// This class stores the strings in a series of string pools. The returned CUtlSymbolLarge is just a pointer +// to the string data, the hash precedes it in memory and is used to speed up searching, etc. +//----------------------------------------------------------------------------- + +typedef intp UtlSymLargeId_t; + +#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0) + +class CUtlSymbolLarge +{ +public: + // constructor, destructor + CUtlSymbolLarge() + { + u.m_Id = UTL_INVAL_SYMBOL_LARGE; + } + + CUtlSymbolLarge( UtlSymLargeId_t id ) + { + u.m_Id = id; + } + CUtlSymbolLarge( CUtlSymbolLarge const& sym ) + { + u.m_Id = sym.u.m_Id; + } + + // operator= + CUtlSymbolLarge& operator=( CUtlSymbolLarge const& src ) + { + u.m_Id = src.u.m_Id; + return *this; + } + + // operator== + bool operator==( CUtlSymbolLarge const& src ) const + { + return u.m_Id == src.u.m_Id; + } + + // operator== + bool operator==( UtlSymLargeId_t const& src ) const + { + return u.m_Id == src; + } + + // operator== + bool operator!=( CUtlSymbolLarge const& src ) const + { + return u.m_Id != src.u.m_Id; + } + + // operator== + bool operator!=( UtlSymLargeId_t const& src ) const + { + return u.m_Id != src; + } + + // Gets at the symbol + operator UtlSymLargeId_t const() const + { + return u.m_Id; + } + + // Gets the string associated with the symbol + inline const char* String( ) const + { + if ( u.m_Id == UTL_INVAL_SYMBOL_LARGE ) + return ""; + return u.m_pAsString; + } + + inline bool IsValid() const + { + return u.m_Id != UTL_INVAL_SYMBOL_LARGE ? true : false; + } + +private: + // Disallowed + CUtlSymbolLarge( const char* pStr ); // they need to go through the table to assign the ptr + bool operator==( const char* pStr ) const; // disallow since we don't know if the table this is from was case sensitive or not... maybe we don't care + + union + { + UtlSymLargeId_t m_Id; + char const *m_pAsString; + } u; +}; + +#define MIN_STRING_POOL_SIZE 2048 + +inline uint32 CUtlSymbolLarge_Hash( bool CASEINSENSITIVE, const char *pString, int len ) +{ + return ( CASEINSENSITIVE ? HashStringCaseless( pString ) : HashString( pString ) ); +} + +typedef uint32 LargeSymbolTableHashDecoration_t; + +// The structure consists of the hash immediately followed by the string data +struct CUtlSymbolTableLargeBaseTreeEntry_t +{ + LargeSymbolTableHashDecoration_t m_Hash; + // Variable length string data + char m_String[1]; + + bool IsEmpty() const + { + return ( ( m_Hash == 0 ) && ( 0 == m_String[0] ) ); + } + + char const *String() const + { + return (const char *)&m_String[ 0 ]; + } + + CUtlSymbolLarge ToSymbol() const + { + return reinterpret_cast< UtlSymLargeId_t >( String() ); + } + + LargeSymbolTableHashDecoration_t HashValue() const + { + return m_Hash; + } +}; + +template< class TreeType, bool CASEINSENSITIVE > +class CTreeEntryLess +{ +public: + CTreeEntryLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree + bool operator!() const { return false; } + bool operator()( CUtlSymbolTableLargeBaseTreeEntry_t * const &left, CUtlSymbolTableLargeBaseTreeEntry_t * const &right ) const + { + // compare the hashes + if ( left->m_Hash == right->m_Hash ) + { + // if the hashes match compare the strings + if ( !CASEINSENSITIVE ) + return strcmp( left->String(), right->String() ) < 0; + else + return V_stricmp( left->String(), right->String() ) < 0; + } + else + { + return left->m_Hash < right->m_Hash; + } + } +}; + +// For non-threaded versions, simply index into CUtlRBTree +template< bool CASEINSENSITIVE > +class CNonThreadsafeTree : public CUtlRBTree, CASEINSENSITIVE > > +{ +public: + typedef CUtlRBTree > CNonThreadsafeTreeType; + + CNonThreadsafeTree() : + CNonThreadsafeTreeType( 0, 16 ) + { + } + inline void Commit() + { + // Nothing, only matters for thread-safe tables + } + inline int Insert( CUtlSymbolTableLargeBaseTreeEntry_t *entry ) + { + return CNonThreadsafeTreeType::Insert( entry ); + } + inline int Find( CUtlSymbolTableLargeBaseTreeEntry_t *entry ) const + { + return CNonThreadsafeTreeType::Find( entry ); + } + inline int InvalidIndex() const + { + return CNonThreadsafeTreeType::InvalidIndex(); + } + inline int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const + { + CUtlVector< CUtlSymbolTableLargeBaseTreeEntry_t * > list; + list.EnsureCount( nCount ); + for ( int i = 0; i < nCount; ++i ) + { + pElements[ i ] = CNonThreadsafeTreeType::Element( i )->ToSymbol(); + } + + return nCount; + } +}; + +// Since CUtlSymbolTableLargeBaseTreeEntry_t already has the hash +// contained inside of it, don't need to recompute a hash here +template < int BUCKET_COUNT, class KEYTYPE, bool CASEINSENSITIVE > +class CCThreadsafeTreeHashMethod +{ +public: + static int Hash( const KEYTYPE &key, int nBucketMask ) + { + uint32 nHash = key->HashValue(); + return ( nHash & nBucketMask ); + } + + static bool Compare( CUtlSymbolTableLargeBaseTreeEntry_t * const &lhs, CUtlSymbolTableLargeBaseTreeEntry_t * const &rhs ) + { + if ( lhs->m_Hash != rhs->m_Hash ) + return false; + if ( !CASEINSENSITIVE ) + { + return ( !Q_strcmp( lhs->String(), rhs->String() ) ? true : false ); + } + + return ( !Q_stricmp( lhs->String(), rhs->String() ) ? true : false ); + } +}; + +/* + NOTE: So the only crappy thing about using a CUtlTSHash here is that the KEYTYPE is a CUtlSymbolTableLargeBaseTreeEntry_t ptr which has both the + hash and the string since with strings there is a good chance of hash collision after you have a fair number of strings so we have to implement + a Compare method (above) which falls back to strcmp/stricmp if the hashes are equal. This means that all of the data is in the KEYTYPE of the hash and the + payload doesn't matter. So I made the payload also be a pointer to a CUtlSymbolTableLargeBaseTreeEntry_t since that makes using the API more convenient + + TODO: If we have a CUtlTSHash that was all about the existence of the KEYTYPE and didn't require a payload (or template on 'void') then we could eliminate + 50% of the pointer overhead used for this data structure. +*/ + +// Thread safe version is based on the +template < bool CASEINSENSITIVE > +class CThreadsafeTree : public CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t *, 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CASEINSENSITIVE > > +{ +public: + typedef CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t *, 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t *, CASEINSENSITIVE > > CThreadsafeTreeType; + + CThreadsafeTree() : + CThreadsafeTreeType( 32 ) + { + } + inline void Commit() + { + CThreadsafeTreeType::Commit(); + } + inline int Insert( CUtlSymbolTableLargeBaseTreeEntry_t *entry ) + { + return CThreadsafeTreeType::Insert( entry, entry ); + } + inline int Find( CUtlSymbolTableLargeBaseTreeEntry_t *entry ) + { + return CThreadsafeTreeType::Find( entry ); + } + inline int InvalidIndex() const + { + return CThreadsafeTreeType::InvalidHandle(); + } + inline int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const + { + CUtlVector< UtlTSHashHandle_t > list; + list.EnsureCount( nCount ); + int c = CThreadsafeTreeType::GetElements( nFirstElement, nCount, list.Base() ); + for ( int i = 0; i < c; ++i ) + { + pElements[ i ] = CThreadsafeTreeType::Element( list[ i ] )->ToSymbol(); + } + + return c; + } +}; + +// Base Class for threaded and non-threaded types +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE = MIN_STRING_POOL_SIZE > +class CUtlSymbolTableLargeBase +{ +public: + // constructor, destructor + CUtlSymbolTableLargeBase(); + ~CUtlSymbolTableLargeBase(); + + // Finds and/or creates a symbol based on the string + CUtlSymbolLarge AddString( const char* pString ); + + // Finds the symbol for pString + CUtlSymbolLarge Find( const char* pString ) const; + + // Remove all symbols in the table. + void RemoveAll(); + + int GetNumStrings( void ) const + { + return m_Lookup.Count(); + } + + void Commit() + { + m_Lookup.Commit(); + } + + // Returns elements in the table + int GetElements( int nFirstElement, int nCount, CUtlSymbolLarge *pElements ) const + { + return m_Lookup.GetElements( nFirstElement, nCount, pElements ); + } + + uint64 GetMemoryUsage() const + { + uint64 unBytesUsed = 0u; + + for ( int i=0; i < m_StringPools.Count(); i++ ) + { + StringPool_t *pPool = m_StringPools[i]; + + unBytesUsed += (uint64)pPool->m_TotalLen; + } + return unBytesUsed; + } + + +protected: + + struct StringPool_t + { + int m_TotalLen; // How large is + int m_SpaceUsed; + char m_Data[1]; + }; + + TreeType m_Lookup; + + // stores the string data + CUtlVector< StringPool_t * > m_StringPools; + +private: + int FindPoolWithSpace( int len ) const; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolTableLargeBase::CUtlSymbolTableLargeBase() : + m_StringPools( 8 ) +{ +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolTableLargeBase::~CUtlSymbolTableLargeBase() +{ + // Release the stringpool string data + RemoveAll(); +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolLarge CUtlSymbolTableLargeBase::Find( const char* pString ) const +{ + VPROF( "CUtlSymbolLarge::Find" ); + if (!pString) + return CUtlSymbolLarge(); + + // Passing this special invalid symbol makes the comparison function + // use the string passed in the context + int len = Q_strlen( pString ) + 1; + + CUtlSymbolTableLargeBaseTreeEntry_t *search = (CUtlSymbolTableLargeBaseTreeEntry_t *)_alloca( len + sizeof( LargeSymbolTableHashDecoration_t ) ); + search->m_Hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, len ); + Q_memcpy( (char *)&search->m_String[ 0 ], pString, len ); + + int idx = const_cast< TreeType & >(m_Lookup).Find( search ); + + if ( idx == m_Lookup.InvalidIndex() ) + return UTL_INVAL_SYMBOL_LARGE; + + const CUtlSymbolTableLargeBaseTreeEntry_t *entry = m_Lookup[ idx ]; + return entry->ToSymbol(); +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline int CUtlSymbolTableLargeBase::FindPoolWithSpace( int len ) const +{ + for ( int i=0; i < m_StringPools.Count(); i++ ) + { + StringPool_t *pPool = m_StringPools[i]; + + if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len ) + { + return i; + } + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Finds and/or creates a symbol based on the string +//----------------------------------------------------------------------------- +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolLarge CUtlSymbolTableLargeBase::AddString( const char* pString ) +{ + VPROF("CUtlSymbolLarge::AddString"); + if (!pString) + return UTL_INVAL_SYMBOL_LARGE; + + CUtlSymbolLarge id = Find( pString ); + if ( id != UTL_INVAL_SYMBOL_LARGE ) + return id; + + int lenString = Q_strlen(pString) + 1; // length of just the string + int lenDecorated = lenString + sizeof(LargeSymbolTableHashDecoration_t); // and with its hash decoration + // make sure that all strings are aligned on 2-byte boundaries so the hashes will read correctly + // This assert seems to be invalid because LargeSymbolTableHashDecoration_t is always + // a uint32, by design. + //COMPILE_TIME_ASSERT(sizeof(LargeSymbolTableHashDecoration_t) == sizeof(intp)); + lenDecorated = ALIGN_VALUE(lenDecorated, sizeof( intp ) ); + + // Find a pool with space for this string, or allocate a new one. + int iPool = FindPoolWithSpace( lenDecorated ); + if ( iPool == -1 ) + { + // Add a new pool. + int newPoolSize = MAX( lenDecorated + sizeof( StringPool_t ), POOL_SIZE ); + StringPool_t *pPool = (StringPool_t*)malloc( newPoolSize ); + + pPool->m_TotalLen = newPoolSize - sizeof( StringPool_t ); + pPool->m_SpaceUsed = 0; + iPool = m_StringPools.AddToTail( pPool ); + } + + // Compute a hash + LargeSymbolTableHashDecoration_t hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, lenString ); + + // Copy the string in. + StringPool_t *pPool = m_StringPools[iPool]; + // Assert( pPool->m_SpaceUsed < 0xFFFF ); // Pool could be bigger than 2k + // This should never happen, because if we had a string > 64k, it + // would have been given its entire own pool. + + CUtlSymbolTableLargeBaseTreeEntry_t *entry = ( CUtlSymbolTableLargeBaseTreeEntry_t * )&pPool->m_Data[ pPool->m_SpaceUsed ]; + + pPool->m_SpaceUsed += lenDecorated; + + entry->m_Hash = hash; + char *pText = (char *)&entry->m_String [ 0 ]; + Q_memcpy( pText, pString, lenString ); + + // insert the string into the database + MEM_ALLOC_CREDIT(); + int idx = m_Lookup.Insert( entry ); + return m_Lookup.Element( idx )->ToSymbol(); +} + +//----------------------------------------------------------------------------- +// Remove all symbols in the table. +//----------------------------------------------------------------------------- +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline void CUtlSymbolTableLargeBase::RemoveAll() +{ + m_Lookup.Purge(); + + for ( int i=0; i < m_StringPools.Count(); i++ ) + { + StringPool_t * pString = m_StringPools[i]; + free( pString ); + } + + m_StringPools.RemoveAll(); +} + +// Case-sensitive +typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< false >, false > CUtlSymbolTableLarge; +// Case-insensitive +typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< true >, true > CUtlSymbolTableLarge_CI; +// Multi-threaded case-sensitive +typedef CUtlSymbolTableLargeBase< CThreadsafeTree< false >, false > CUtlSymbolTableLargeMT; +// Multi-threaded case-insensitive +typedef CUtlSymbolTableLargeBase< CThreadsafeTree< true >, true > CUtlSymbolTableLargeMT_CI; + +#endif // UTLSYMBOLLARGE_H diff --git a/public/tier1/utltshash.h b/public/tier1/utltshash.h new file mode 100644 index 0000000..9ff4e83 --- /dev/null +++ b/public/tier1/utltshash.h @@ -0,0 +1,625 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Thread-safe hash class +//===========================================================================// + +#ifndef UTLTSHASH_H +#define UTLTSHASH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier0/threadtools.h" +#include "tier1/mempool.h" +#include "generichash.h" + + +//============================================================================= +// +// Threadsafe Hash +// +// Number of buckets must be a power of 2. +// Key must be intp sized (32-bits on x32, 64-bits on x64) +// Designed for a usage pattern where the data is semi-static, and there +// is a well-defined point where we are guaranteed no queries are occurring. +// +// Insertions are added into a thread-safe list, and when Commit() is called, +// the insertions are moved into a lock-free list +// +// Elements are never individually removed; clears must occur at a time +// where we and guaranteed no queries are occurring +// +typedef intp UtlTSHashHandle_t; + +template < class T > +abstract_class ITSHashConstructor +{ +public: + virtual void Construct( T* pElement ) = 0; +}; + +template < class T > +class CDefaultTSHashConstructor : public ITSHashConstructor< T > +{ +public: + virtual void Construct( T* pElement ) + { + ::Construct( pElement ); + } +}; + +template < int BUCKET_COUNT, class KEYTYPE = intp > +class CUtlTSHashGenericHash +{ +public: + static int Hash( const KEYTYPE &key, int nBucketMask ) + { + int nHash = HashIntConventional( (intp)key ); + if ( BUCKET_COUNT <= USHRT_MAX ) + { + nHash ^= ( nHash >> 16 ); + } + if ( BUCKET_COUNT <= UCHAR_MAX ) + { + nHash ^= ( nHash >> 8 ); + } + return ( nHash & nBucketMask ); + } + + static bool Compare( const KEYTYPE &lhs, const KEYTYPE &rhs ) + { + return lhs == rhs; + } +}; + +template < int BUCKET_COUNT, class KEYTYPE > +class CUtlTSHashUseKeyHashMethod +{ +public: + static int Hash( const KEYTYPE &key, int nBucketMask ) + { + uint32 nHash = key.HashValue(); + return ( nHash & nBucketMask ); + } + + static bool Compare( const KEYTYPE &lhs, const KEYTYPE &rhs ) + { + return lhs == rhs; + } +}; + +template< class T, int BUCKET_COUNT, class KEYTYPE = intp, class HashFuncs = CUtlTSHashGenericHash< BUCKET_COUNT, KEYTYPE >, int nAlignment = 0 > +class CUtlTSHash +{ +public: + // Constructor/Deconstructor. + CUtlTSHash( int nAllocationCount ); + ~CUtlTSHash(); + + // Invalid handle. + static UtlTSHashHandle_t InvalidHandle( void ) { return ( UtlTSHashHandle_t )0; } + + // Retrieval. Super fast, is thread-safe + UtlTSHashHandle_t Find( KEYTYPE uiKey ); + + // Insertion ( find or add ). + UtlTSHashHandle_t Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert = NULL ); + UtlTSHashHandle_t Insert( KEYTYPE uiKey, ITSHashConstructor *pConstructor, bool *pDidInsert = NULL ); + + // This insertion method assumes the element is not in the hash table, skips + UtlTSHashHandle_t FastInsert( KEYTYPE uiKey, const T &data ); + UtlTSHashHandle_t FastInsert( KEYTYPE uiKey, ITSHashConstructor *pConstructor ); + + // Commit recent insertions, making finding them faster. + // Only call when you're certain no threads are accessing the hash table + void Commit( ); + + // Removal. Only call when you're certain no threads are accessing the hash table + void FindAndRemove( KEYTYPE uiKey ); + void Remove( UtlTSHashHandle_t hHash ) { FindAndRemove( GetID( hHash ) ); } + void RemoveAll( void ); + void Purge( void ); + + // Returns the number of elements in the hash table + int Count() const; + + // Returns elements in the table + int GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const; + + // Element access + T &Element( UtlTSHashHandle_t hHash ); + T const &Element( UtlTSHashHandle_t hHash ) const; + T &operator[]( UtlTSHashHandle_t hHash ); + T const &operator[]( UtlTSHashHandle_t hHash ) const; + KEYTYPE GetID( UtlTSHashHandle_t hHash ) const; + + // Convert element * to hashHandle + UtlTSHashHandle_t ElementPtrToHandle( T* pElement ) const; + +private: + // Templatized for memory tracking purposes + template < typename Data_t > + struct HashFixedDataInternal_t + { + KEYTYPE m_uiKey; + HashFixedDataInternal_t< Data_t >* m_pNext; + Data_t m_Data; + }; + + typedef HashFixedDataInternal_t HashFixedData_t; + + enum + { + BUCKET_MASK = BUCKET_COUNT - 1 + }; + + struct HashBucket_t + { + HashFixedData_t *m_pFirst; + HashFixedData_t *m_pFirstUncommitted; + CThreadSpinRWLock m_AddLock; + }; + + UtlTSHashHandle_t Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement ); + UtlTSHashHandle_t InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket ); + CMemoryPoolMT m_EntryMemory; + HashBucket_t m_aBuckets[BUCKET_COUNT]; + bool m_bNeedsCommit; + +#ifdef _DEBUG + CInterlockedInt m_ContentionCheck; +#endif +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +template +CUtlTSHash::CUtlTSHash( int nAllocationCount ) : + m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ), nAlignment ) +{ +#ifdef _DEBUG + m_ContentionCheck = 0; +#endif + m_bNeedsCommit = false; + for ( int i = 0; i < BUCKET_COUNT; i++ ) + { + HashBucket_t &bucket = m_aBuckets[ i ]; + bucket.m_pFirst = NULL; + bucket.m_pFirstUncommitted = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Deconstructor +//----------------------------------------------------------------------------- +template +CUtlTSHash::~CUtlTSHash() +{ +#ifdef _DEBUG + if ( m_ContentionCheck != 0 ) + { + DebuggerBreak(); + } +#endif + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy dynamically allocated hash data. +//----------------------------------------------------------------------------- +template +inline void CUtlTSHash::Purge( void ) +{ + RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Returns the number of elements in the hash table +//----------------------------------------------------------------------------- +template +inline int CUtlTSHash::Count() const +{ + return m_EntryMemory.Count(); +} + + +//----------------------------------------------------------------------------- +// Returns elements in the table +//----------------------------------------------------------------------------- +template +int CUtlTSHash::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const +{ + int nIndex = 0; + for ( int i = 0; i < BUCKET_COUNT; i++ ) + { + const HashBucket_t &bucket = m_aBuckets[ i ]; + bucket.m_AddLock.LockForRead( ); + for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext ) + { + if ( --nFirstElement >= 0 ) + continue; + + pHandles[ nIndex++ ] = (UtlTSHashHandle_t)pElement; + if ( nIndex >= nCount ) + { + bucket.m_AddLock.UnlockRead( ); + return nIndex; + } + } + bucket.m_AddLock.UnlockRead( ); + } + return nIndex; +} + + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (KEYTYPE), +// without a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template +inline UtlTSHashHandle_t CUtlTSHash::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket ) +{ + m_bNeedsCommit = true; + HashFixedData_t *pNewElement = static_cast< HashFixedData_t * >( m_EntryMemory.Alloc() ); + pNewElement->m_pNext = bucket.m_pFirstUncommitted; + bucket.m_pFirstUncommitted = pNewElement; + pNewElement->m_uiKey = uiKey; + return (UtlTSHashHandle_t)pNewElement; +} + + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key, with +// a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template +inline UtlTSHashHandle_t CUtlTSHash::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert ) +{ +#ifdef _DEBUG + if ( m_ContentionCheck != 0 ) + { + DebuggerBreak(); + } +#endif + + if ( pDidInsert ) + { + *pDidInsert = false; + } + + int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); + HashBucket_t &bucket = m_aBuckets[ iBucket ]; + + // First try lock-free + UtlTSHashHandle_t h = Find( uiKey ); + if ( h != InvalidHandle() ) + return h; + + // Now, try again, but only look in uncommitted elements + bucket.m_AddLock.LockForWrite( ); + + h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst ); + if ( h == InvalidHandle() ) + { + h = InsertUncommitted( uiKey, bucket ); + CopyConstruct( &Element(h), data ); + if ( pDidInsert ) + { + *pDidInsert = true; + } + } + + bucket.m_AddLock.UnlockWrite( ); + return h; +} + +template +inline UtlTSHashHandle_t CUtlTSHash::Insert( KEYTYPE uiKey, ITSHashConstructor *pConstructor, bool *pDidInsert ) +{ +#ifdef _DEBUG + if ( m_ContentionCheck != 0 ) + { + DebuggerBreak(); + } +#endif + + if ( pDidInsert ) + { + *pDidInsert = false; + } + + // First try lock-free + UtlTSHashHandle_t h = Find( uiKey ); + if ( h != InvalidHandle() ) + return h; + + // Now, try again, but only look in uncommitted elements + int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); + HashBucket_t &bucket = m_aBuckets[ iBucket ]; + bucket.m_AddLock.LockForWrite( ); + + h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst ); + if ( h == InvalidHandle() ) + { + // Useful if non-trivial work needs to happen to make data; don't want to + // do it and then have to undo it if it turns out we don't need to add it + h = InsertUncommitted( uiKey, bucket ); + pConstructor->Construct( &Element(h) ); + if ( pDidInsert ) + { + *pDidInsert = true; + } + } + + bucket.m_AddLock.UnlockWrite( ); + return h; +} + + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key +// without a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template +inline UtlTSHashHandle_t CUtlTSHash::FastInsert( KEYTYPE uiKey, const T &data ) +{ +#ifdef _DEBUG + if ( m_ContentionCheck != 0 ) + { + DebuggerBreak(); + } +#endif + int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); + HashBucket_t &bucket = m_aBuckets[ iBucket ]; + bucket.m_AddLock.LockForWrite( ); + UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket ); + CopyConstruct( &Element(h), data ); + bucket.m_AddLock.UnlockWrite( ); + return h; +} + +template +inline UtlTSHashHandle_t CUtlTSHash::FastInsert( KEYTYPE uiKey, ITSHashConstructor *pConstructor ) +{ +#ifdef _DEBUG + if ( m_ContentionCheck != 0 ) + { + DebuggerBreak(); + } +#endif + int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); + HashBucket_t &bucket = m_aBuckets[ iBucket ]; + bucket.m_AddLock.LockForWrite( ); + UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket ); + pConstructor->Construct( &Element(h) ); + bucket.m_AddLock.UnlockWrite( ); + return h; +} + + +//----------------------------------------------------------------------------- +// Purpose: Commits all uncommitted insertions +//----------------------------------------------------------------------------- +template +inline void CUtlTSHash::Commit( ) +{ + // FIXME: Is this legal? Want this to be lock-free + if ( !m_bNeedsCommit ) + return; + + // This must occur when no queries are occurring +#ifdef _DEBUG + m_ContentionCheck++; +#endif + + for ( int i = 0; i < BUCKET_COUNT; i++ ) + { + HashBucket_t &bucket = m_aBuckets[ i ]; + bucket.m_AddLock.LockForRead( ); + bucket.m_pFirst = bucket.m_pFirstUncommitted; + bucket.m_AddLock.UnlockRead( ); + } + + m_bNeedsCommit = false; + +#ifdef _DEBUG + m_ContentionCheck--; +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: Remove a single element from the hash +//----------------------------------------------------------------------------- +template +inline void CUtlTSHash::FindAndRemove( KEYTYPE uiKey ) +{ + if ( m_EntryMemory.Count() == 0 ) + return; + + // This must occur when no queries are occurring +#ifdef _DEBUG + m_ContentionCheck++; +#endif + + int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); + HashBucket_t &bucket = m_aBuckets[ iBucket ]; + bucket.m_AddLock.LockForWrite( ); + + HashFixedData_t *pPrev = NULL; + for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext ) + { + if ( !HashFuncs::Compare( pElement->m_uiKey, uiKey ) ) + continue; + + if ( pPrev ) + { + pPrev->m_pNext = pElement->m_pNext; + } + else + { + bucket.m_pFirstUncommitted = pElement->m_pNext; + } + + if ( bucket.m_pFirst == pElement ) + { + bucket.m_pFirst = bucket.m_pFirst->m_pNext; + } + + Destruct( &pElement->m_Data ); + +#ifdef _DEBUG + memset( pElement, 0xDD, sizeof(HashFixedData_t) ); +#endif + + m_EntryMemory.Free( pElement ); + + break; + } + + bucket.m_AddLock.UnlockWrite( ); + +#ifdef _DEBUG + m_ContentionCheck--; +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +template +inline void CUtlTSHash::RemoveAll( void ) +{ + m_bNeedsCommit = false; + if ( m_EntryMemory.Count() == 0 ) + return; + + // This must occur when no queries are occurring +#ifdef _DEBUG + m_ContentionCheck++; +#endif + + for ( int i = 0; i < BUCKET_COUNT; i++ ) + { + HashBucket_t &bucket = m_aBuckets[ i ]; + + bucket.m_AddLock.LockForWrite( ); + + for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext ) + { + Destruct( &pElement->m_Data ); + } + + bucket.m_pFirst = NULL; + bucket.m_pFirstUncommitted = NULL; + bucket.m_AddLock.UnlockWrite( ); + } + + m_EntryMemory.Clear(); + +#ifdef _DEBUG + m_ContentionCheck--; +#endif +} + +//----------------------------------------------------------------------------- +// Finds an element, but only in the committed elements +//----------------------------------------------------------------------------- +template +inline UtlTSHashHandle_t CUtlTSHash::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement ) +{ +#ifdef _DEBUG + if ( m_ContentionCheck != 0 ) + { + DebuggerBreak(); + } +#endif + + for ( HashFixedData_t *pElement = pFirstElement; pElement != pLastElement; pElement = pElement->m_pNext ) + { + if ( HashFuncs::Compare( pElement->m_uiKey, uiKey ) ) + return (UtlTSHashHandle_t)pElement; + } + return InvalidHandle(); +} + + +//----------------------------------------------------------------------------- +// Finds an element, but only in the committed elements +//----------------------------------------------------------------------------- +template +inline UtlTSHashHandle_t CUtlTSHash::Find( KEYTYPE uiKey ) +{ + int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); + const HashBucket_t &bucket = m_aBuckets[iBucket]; + UtlTSHashHandle_t h = Find( uiKey, bucket.m_pFirst, NULL ); + if ( h != InvalidHandle() ) + return h; + + // Didn't find it in the fast ( committed ) list. Let's try the slow ( uncommitted ) one + bucket.m_AddLock.LockForRead( ); + h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst ); + bucket.m_AddLock.UnlockRead( ); + + return h; +} + + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template +inline T &CUtlTSHash::Element( UtlTSHashHandle_t hHash ) +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +template +inline T const &CUtlTSHash::Element( UtlTSHashHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +template +inline T &CUtlTSHash::operator[]( UtlTSHashHandle_t hHash ) +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +template +inline T const &CUtlTSHash::operator[]( UtlTSHashHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + + +template +inline KEYTYPE CUtlTSHash::GetID( UtlTSHashHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_uiKey; +} + + +// Convert element * to hashHandle +template +inline UtlTSHashHandle_t CUtlTSHash::ElementPtrToHandle( T* pElement ) const +{ + Assert( pElement ); + HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) ); + Assert( m_EntryMemory.IsAllocationWithinPool( pFixedData ) ); + return (UtlTSHashHandle_t)pFixedData; +} + + +#endif // UTLTSHASH_H diff --git a/public/tier1/utlvector.h b/public/tier1/utlvector.h new file mode 100644 index 0000000..7313bc9 --- /dev/null +++ b/public/tier1/utlvector.h @@ -0,0 +1,1273 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable array class that maintains a free list and keeps elements +// in the same location +//=============================================================================// + +#ifndef UTLVECTOR_H +#define UTLVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "tier1/utlmemory.h" +#include "tier1/utlblockmemory.h" +#include "tier1/strtools.h" +#include "vstdlib/random.h" + +#define FOR_EACH_VEC( vecName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ ) +#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \ + for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- ) + +//----------------------------------------------------------------------------- +// The CUtlVector class: +// A growable array class which doubles in size by default. +// It will always keep all elements consecutive in memory, and may move the +// elements around in memory (via a PvRealloc) when elements are inserted or +// removed. Clients should therefore refer to the elements of the vector +// by index (they should *never* maintain pointers to elements in the vector). +//----------------------------------------------------------------------------- +template< class T, class A = CUtlMemory > +class CUtlVector +{ + typedef A CAllocator; +public: + typedef T ElemType_t; + typedef T* iterator; + typedef const T* const_iterator; + + // constructor, destructor + explicit CUtlVector( int growSize = 0, int initSize = 0 ); + explicit CUtlVector( T* pMemory, int allocationCount, int numElements = 0 ); + ~CUtlVector(); + + // Copy the array. + CUtlVector& operator=( const CUtlVector &other ); + + // element access + T& operator[]( int i ); + const T& operator[]( int i ) const; + T& Element( int i ); + const T& Element( int i ) const; + T& Head(); + const T& Head() const; + T& Tail(); + const T& Tail() const; + T& Random(); + const T& Random() const; + + // STL compatible member functions. These allow easier use of std::sort + // and they are forward compatible with the C++ 11 range-based for loops. + iterator begin() { return Base(); } + const_iterator begin() const { return Base(); } + iterator end() { return Base() + Count(); } + const_iterator end() const { return Base() + Count(); } + + // Gets the base address (can change when adding elements!) + T* Base() { return m_Memory.Base(); } + const T* Base() const { return m_Memory.Base(); } + + // Returns the number of elements in the vector + // SIZE IS DEPRECATED! + int Count() const; + int Size() const; // don't use me! + + /// are there no elements? For compatibility with lists. + inline bool IsEmpty( void ) const + { + return ( Count() == 0 ); + } + + // Is element index valid? + bool IsValidIndex( int i ) const; + static int InvalidIndex(); + + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + + // Adds an element, uses copy constructor + int AddToHead( const T& src ); + int AddToTail( const T& src ); + int InsertBefore( int elem, const T& src ); + int InsertAfter( int elem, const T& src ); + + // Adds multiple elements, uses default constructor + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and + int InsertMultipleAfter( int elem, int num ); + + // Calls RemoveAll() then AddMultipleToTail. + void SetSize( int size ); + void SetCount( int count ); + void SetCountNonDestructively( int count ); //sets count by adding or removing elements to tail TODO: This should probably be the default behavior for SetCount + + // Calls SetSize and copies each element. + void CopyArray( const T *pArray, int size ); + + // Fast swap + void Swap( CUtlVector< T, A > &vec ); + + // Add the specified array to the tail. + int AddVectorToTail( CUtlVector const &src ); + + // Finds an element (element needs operator== defined) + int Find( const T& src ) const; + + bool HasElement( const T& src ) const; + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Makes sure we have at least this many elements + void EnsureCount( int num ); + + // Element removal + void FastRemove( int elem ); // doesn't preserve order + void Remove( int elem ); // preserves order, shifts elements + bool FindAndRemove( const T& src ); // removes first occurrence of src, preserves order, shifts elements + bool FindAndFastRemove( const T& src ); // removes first occurrence of src, doesn't preserve order + void RemoveMultiple( int elem, int num ); // preserves order, shifts elements + void RemoveMultipleFromHead(int num); // removes num elements from tail + void RemoveMultipleFromTail(int num); // removes num elements from tail + void RemoveAll(); // doesn't deallocate memory + + // Memory deallocation + void Purge(); + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Compacts the vector to the number of elements actually in use + void Compact(); + + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize( int size ) { m_Memory.SetGrowSize( size ); } + + int NumAllocated() const; // Only use this if you really know what you're doing! + + void Sort( int (__cdecl *pfnCompare)(const T *, const T *) ); + + void Shuffle( IUniformRandomStream* pSteam = NULL ); + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, char *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + // Grows the vector + void GrowVector( int num = 1 ); + + // Shifts elements.... + void ShiftElementsRight( int elem, int num = 1 ); + void ShiftElementsLeft( int elem, int num = 1 ); + + CAllocator m_Memory; + int m_Size; + +#ifndef _X360 + // For easier access to the elements through the debugger + // it's in release builds so this can be used in libraries correctly + T *m_pElements; + + inline void ResetDbgInfo() + { + m_pElements = Base(); + } +#else + inline void ResetDbgInfo() {} +#endif + +private: + // Can't copy this unless we explicitly do it! + // Use CCopyableUtlVector to get this functionality + CUtlVector( CUtlVector const& vec ); +}; + + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T > +class CUtlBlockVector : public CUtlVector< T, CUtlBlockMemory< T, int > > +{ +public: + explicit CUtlBlockVector( int growSize = 0, int initSize = 0 ) + : CUtlVector< T, CUtlBlockMemory< T, int > >( growSize, initSize ) {} + +private: + // Private and unimplemented because iterator semantics are not currently supported + // on CUtlBlockVector, due to its non-contiguous allocations. + // typename is require to disambiguate iterator as a type versus other possibilities. + typedef CUtlVector< T, CUtlBlockMemory< T, int > > Base; + typename Base::iterator begin(); + typename Base::const_iterator begin() const; + typename Base::iterator end(); + typename Base::const_iterator end() const; +}; + +//----------------------------------------------------------------------------- +// The CUtlVectorFixed class: +// A array class with a fixed allocation scheme +//----------------------------------------------------------------------------- + +template< class BASE_UTLVECTOR, class MUTEX_TYPE = CThreadFastMutex > +class CUtlVectorMT : public BASE_UTLVECTOR, public MUTEX_TYPE +{ + typedef BASE_UTLVECTOR BaseClass; +public: + MUTEX_TYPE Mutex_t; + + // constructor, destructor + explicit CUtlVectorMT( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CUtlVectorMT( typename BaseClass::ElemType_t* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorFixed class: +// A array class with a fixed allocation scheme +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlVectorFixed : public CUtlVector< T, CUtlMemoryFixed > +{ + typedef CUtlVector< T, CUtlMemoryFixed > BaseClass; +public: + + // constructor, destructor + explicit CUtlVectorFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CUtlVectorFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorFixedGrowable class: +// A array class with a fixed allocation scheme backed by a dynamic one +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable > +{ + typedef CUtlVector< T, CUtlMemoryFixedGrowable > BaseClass; + +public: + // constructor, destructor + explicit CUtlVectorFixedGrowable( int growSize = 0 ) : BaseClass( growSize, MAX_SIZE ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorConservative class: +// A array class with a conservative allocation scheme +//----------------------------------------------------------------------------- +template< class T > +class CUtlVectorConservative : public CUtlVector< T, CUtlMemoryConservative > +{ + typedef CUtlVector< T, CUtlMemoryConservative > BaseClass; +public: + + // constructor, destructor + explicit CUtlVectorConservative( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CUtlVectorConservative( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorUltra Conservative class: +// A array class with a very conservative allocation scheme, with customizable allocator +// Especialy useful if you have a lot of vectors that are sparse, or if you're +// carefully packing holders of vectors +//----------------------------------------------------------------------------- +#pragma warning(push) +#pragma warning(disable : 4200) // warning C4200: nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable : 4815 ) // warning C4815: 'staticData' : zero-sized array in stack object will have no elements + +class CUtlVectorUltraConservativeAllocator +{ +public: + static void *Alloc( size_t nSize ) + { + return malloc( nSize ); + } + + static void *Realloc( void *pMem, size_t nSize ) + { + return realloc( pMem, nSize ); + } + + static void Free( void *pMem ) + { + free( pMem ); + } + + static size_t GetSize( void *pMem ) + { + return mallocsize( pMem ); + } + +}; + +template +class CUtlVectorUltraConservative : private A +{ +public: + CUtlVectorUltraConservative() + { + m_pData = StaticData(); + } + + ~CUtlVectorUltraConservative() + { + RemoveAll(); + } + + int Count() const + { + return m_pData->m_Size; + } + + static int InvalidIndex() + { + return -1; + } + + inline bool IsValidIndex( int i ) const + { + return (i >= 0) && (i < Count()); + } + + T& operator[]( int i ) + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + const T& operator[]( int i ) const + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + T& Element( int i ) + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + const T& Element( int i ) const + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + void EnsureCapacity( int num ) + { + int nCurCount = Count(); + if ( num <= nCurCount ) + { + return; + } + if ( m_pData == StaticData() ) + { + m_pData = (Data_t *)A::Alloc( sizeof(int) + ( num * sizeof(T) ) ); + m_pData->m_Size = 0; + } + else + { + int nNeeded = sizeof(int) + ( num * sizeof(T) ); + int nHave = A::GetSize( m_pData ); + if ( nNeeded > nHave ) + { + m_pData = (Data_t *)A::Realloc( m_pData, nNeeded ); + } + } + } + + int AddToTail( const T& src ) + { + int iNew = Count(); + EnsureCapacity( Count() + 1 ); + m_pData->m_Elements[iNew] = src; + m_pData->m_Size++; + return iNew; + } + + void RemoveAll() + { + if ( Count() ) + { + for (int i = m_pData->m_Size; --i >= 0; ) + { + Destruct(&m_pData->m_Elements[i]); + } + } + if ( m_pData != StaticData() ) + { + A::Free( m_pData ); + m_pData = StaticData(); + + } + } + + void PurgeAndDeleteElements() + { + if ( m_pData != StaticData() ) + { + for( int i=0; i < m_pData->m_Size; i++ ) + { + delete Element(i); + } + RemoveAll(); + } + } + + void FastRemove( int elem ) + { + Assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (Count() > 0) + { + if ( elem != m_pData->m_Size -1 ) + memcpy( &Element(elem), &Element(m_pData->m_Size-1), sizeof(T) ); + --m_pData->m_Size; + } + if ( !m_pData->m_Size ) + { + A::Free( m_pData ); + m_pData = StaticData(); + } + } + + void Remove( int elem ) + { + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_pData->m_Size; + if ( !m_pData->m_Size ) + { + A::Free( m_pData ); + m_pData = StaticData(); + } + } + + int Find( const T& src ) const + { + int nCount = Count(); + for ( int i = 0; i < nCount; ++i ) + { + if (Element(i) == src) + return i; + } + return -1; + } + + bool FindAndRemove( const T& src ) + { + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + return true; + } + return false; + } + + + bool FindAndFastRemove( const T& src ) + { + int elem = Find( src ); + if ( elem != -1 ) + { + FastRemove( elem ); + return true; + } + return false; + } + + struct Data_t + { + int m_Size; + T m_Elements[0]; + }; + + Data_t *m_pData; +private: + void ShiftElementsLeft( int elem, int num = 1 ) + { + int Size = Count(); + Assert( IsValidIndex(elem) || ( Size == 0 ) || ( num == 0 )); + int numToMove = Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + Q_memset( &Element(Size-num), 0xDD, num * sizeof(T) ); +#endif + } + } + + + + static Data_t *StaticData() + { + static Data_t staticData; + Assert( staticData.m_Size == 0 ); + return &staticData; + } +}; + +#pragma warning(pop) + + +//----------------------------------------------------------------------------- +// The CCopyableUtlVector class: +// A array class that allows copy construction (so you can nest a CUtlVector inside of another one of our containers) +// WARNING - this class lets you copy construct which can be an expensive operation if you don't carefully control when it happens +// Only use this when nesting a CUtlVector() inside of another one of our container classes (i.e a CUtlMap) +//----------------------------------------------------------------------------- +template< typename T, typename A = CUtlMemory > +class CCopyableUtlVector : public CUtlVector< T, A > +{ + typedef CUtlVector< T, A > BaseClass; +public: + explicit CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} + virtual ~CCopyableUtlVector() {} + CCopyableUtlVector( CCopyableUtlVector const& vec ) { this->CopyArray( vec.Base(), vec.Count() ); } +}; + +// TODO (Ilya): It seems like all the functions in CUtlVector are simple enough that they should be inlined. + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline CUtlVector::CUtlVector( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector::CUtlVector( T* pMemory, int allocationCount, int numElements ) : + m_Memory(pMemory, allocationCount), m_Size(numElements) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector::~CUtlVector() +{ + Purge(); +} + +template< typename T, class A > +inline CUtlVector& CUtlVector::operator=( const CUtlVector &other ) +{ + int nCount = other.Count(); + SetSize( nCount ); + for ( int i = 0; i < nCount; i++ ) + { + (*this)[ i ] = other[ i ]; + } + return *this; +} + +#ifdef STAGING_ONLY +inline void StagingUtlVectorBoundsCheck( int i, int size ) +{ + if ( (unsigned)i >= (unsigned)size ) + { + Msg( "Array access error: %d / %d\n", i, size ); + DebuggerBreak(); + } +} + +#else +#define StagingUtlVectorBoundsCheck( _i, _size ) +#endif + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< typename T, class A > +inline T& CUtlVector::operator[]( int i ) +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + StagingUtlVectorBoundsCheck( i, m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline const T& CUtlVector::operator[]( int i ) const +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + StagingUtlVectorBoundsCheck( i, m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector::Element( int i ) +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + StagingUtlVectorBoundsCheck( i, m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline const T& CUtlVector::Element( int i ) const +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + StagingUtlVectorBoundsCheck( i, m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector::Head() +{ + Assert( m_Size > 0 ); + StagingUtlVectorBoundsCheck( 0, m_Size ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline const T& CUtlVector::Head() const +{ + Assert( m_Size > 0 ); + StagingUtlVectorBoundsCheck( 0, m_Size ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline T& CUtlVector::Tail() +{ + Assert( m_Size > 0 ); + StagingUtlVectorBoundsCheck( 0, m_Size ); + return m_Memory[ m_Size - 1 ]; +} + +template< typename T, class A > +inline const T& CUtlVector::Tail() const +{ + Assert( m_Size > 0 ); + StagingUtlVectorBoundsCheck( 0, m_Size ); + return m_Memory[ m_Size - 1 ]; +} + + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::Size() const +{ + return m_Size; +} + +template< typename T, class A > +inline T& CUtlVector::Random() +{ + Assert( m_Size > 0 ); + return m_Memory[ RandomInt( 0, m_Size - 1 ) ]; +} + +template< typename T, class A > +inline const T& CUtlVector::Random() const +{ + Assert( m_Size > 0 ); + return m_Memory[ RandomInt( 0, m_Size - 1 ) ]; +} + + +//----------------------------------------------------------------------------- +// Shuffle - Knuth/Fisher-Yates +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::Shuffle( IUniformRandomStream* pSteam ) +{ + for ( int i = 0; i < m_Size; i++ ) + { + int j = pSteam ? pSteam->RandomInt( i, m_Size - 1 ) : RandomInt( i, m_Size - 1 ); + if ( i != j ) + { + V_swap( m_Memory[ i ], m_Memory[ j ] ); + } + } +} + +template< typename T, class A > +inline int CUtlVector::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< typename T, class A > +inline bool CUtlVector::IsValidIndex( int i ) const +{ + return (i >= 0) && (i < m_Size); +} + + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::InvalidIndex() +{ + return -1; +} + + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::GrowVector( int num ) +{ + if (m_Size + num > m_Memory.NumAllocated()) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() ); + } + + m_Size += num; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Sorts the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::Sort( int (__cdecl *pfnCompare)(const T *, const T *) ) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if ( Count() <= 1 ) + return; + + if ( Base() ) + { + qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) ); + } + else + { + Assert( 0 ); + // this path is untested + // if you want to sort vectors that use a non-sequential memory allocator, + // you'll probably want to patch in a quicksort algorithm here + // I just threw in this bubble sort to have something just in case... + + for ( int i = m_Size - 1; i >= 0; --i ) + { + for ( int j = 1; j <= i; ++j ) + { + if ( pfnCompare( &Element( j - 1 ), &Element( j ) ) < 0 ) + { + V_swap( Element( j - 1 ), Element( j ) ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::EnsureCount( int num ) +{ + if (Count() < num) + AddMultipleToTail( num - Count() ); +} + + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::ShiftElementsRight( int elem, int num ) +{ + Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + Q_memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) ); +} + +template< typename T, class A > +void CUtlVector::ShiftElementsLeft( int elem, int num ) +{ + Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + Q_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) ); +#endif + } +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::AddToHead() +{ + return InsertBefore(0); +} + +template< typename T, class A > +inline int CUtlVector::AddToTail() +{ + return InsertBefore( m_Size ); +} + +template< typename T, class A > +inline int CUtlVector::InsertAfter( int elem ) +{ + return InsertBefore( elem + 1 ); +} + +template< typename T, class A > +int CUtlVector::InsertBefore( int elem ) +{ + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + Construct( &Element(elem) ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::AddToHead( const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( 0, src ); +} + +template< typename T, class A > +inline int CUtlVector::AddToTail( const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( m_Size, src ); +} + +template< typename T, class A > +inline int CUtlVector::InsertAfter( int elem, const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( elem + 1, src ); +} + +template< typename T, class A > +int CUtlVector::InsertBefore( int elem, const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct( &Element(elem), src ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds multiple elements, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::AddMultipleToHead( int num ) +{ + return InsertMultipleBefore( 0, num ); +} + +template< typename T, class A > +inline int CUtlVector::AddMultipleToTail( int num, const T *pToCopy ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || !pToCopy || (pToCopy + num < Base()) || (pToCopy >= (Base() + Count()) ) ); + + return InsertMultipleBefore( m_Size, num, pToCopy ); +} + +template< typename T, class A > +int CUtlVector::InsertMultipleAfter( int elem, int num ) +{ + return InsertMultipleBefore( elem + 1, num ); +} + + +template< typename T, class A > +void CUtlVector::SetCount( int count ) +{ + RemoveAll(); + AddMultipleToTail( count ); +} + +template< typename T, class A > +inline void CUtlVector::SetSize( int size ) +{ + SetCount( size ); +} + +template< typename T, class A > +void CUtlVector::SetCountNonDestructively( int count ) +{ + int delta = count - m_Size; + if(delta > 0) AddMultipleToTail( delta ); + else if(delta < 0) RemoveMultipleFromTail( -delta ); +} + +template< typename T, class A > +void CUtlVector::CopyArray( const T *pArray, int size ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()) ) ); + + SetSize( size ); + for( int i=0; i < size; i++ ) + { + (*this)[i] = pArray[i]; + } +} + +template< typename T, class A > +void CUtlVector::Swap( CUtlVector< T, A > &vec ) +{ + m_Memory.Swap( vec.m_Memory ); + V_swap( m_Size, vec.m_Size ); + +#ifndef _X360 + V_swap( m_pElements, vec.m_pElements ); +#endif +} + +template< typename T, class A > +int CUtlVector::AddVectorToTail( CUtlVector const &src ) +{ + Assert( &src != this ); + + int base = Count(); + + // Make space. + AddMultipleToTail( src.Count() ); + + // Copy the elements. + for ( int i=0; i < src.Count(); i++ ) + { + (*this)[base + i] = src[i]; + } + + return base; +} + +template< typename T, class A > +inline int CUtlVector::InsertMultipleBefore( int elem, int num, const T *pToInsert ) +{ + if( num == 0 ) + return elem; + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(num); + ShiftElementsRight( elem, num ); + + // Invoke default constructors + for (int i = 0; i < num; ++i ) + Construct( &Element( elem+i ) ); + + // Copy stuff in? + if ( pToInsert ) + { + for ( int i=0; i < num; i++ ) + { + Element( elem+i ) = pToInsert[i]; + } + } + + return elem; +} + + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< typename T, class A > +int CUtlVector::Find( const T& src ) const +{ + for ( int i = 0; i < Count(); ++i ) + { + if (Element(i) == src) + return i; + } + return -1; +} + +template< typename T, class A > +bool CUtlVector::HasElement( const T& src ) const +{ + return ( Find(src) >= 0 ); +} + + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::FastRemove( int elem ) +{ + Assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (m_Size > 0) + { + if ( elem != m_Size -1 ) + memcpy( reinterpret_cast( &Element(elem) ), reinterpret_cast( &Element(m_Size-1) ), sizeof(T) ); + --m_Size; + } +} + +template< typename T, class A > +void CUtlVector::Remove( int elem ) +{ + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_Size; +} + +template< typename T, class A > +bool CUtlVector::FindAndRemove( const T& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + return true; + } + return false; +} + +template< typename T, class A > +bool CUtlVector::FindAndFastRemove( const T& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + FastRemove( elem ); + return true; + } + return false; +} + +template< typename T, class A > +void CUtlVector::RemoveMultiple( int elem, int num ) +{ + Assert( elem >= 0 ); + Assert( elem + num <= Count() ); + + for (int i = elem + num; --i >= elem; ) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveMultipleFromHead( int num ) +{ + Assert( num <= Count() ); + + for (int i = num; --i >= 0; ) + Destruct(&Element(i)); + + ShiftElementsLeft(0, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveMultipleFromTail( int num ) +{ + Assert( num <= Count() ); + + for (int i = m_Size-num; i < m_Size; i++) + Destruct(&Element(i)); + + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveAll() +{ + for (int i = m_Size; --i >= 0; ) + { + Destruct(&Element(i)); + } + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< typename T, class A > +inline void CUtlVector::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + + +template< typename T, class A > +inline void CUtlVector::PurgeAndDeleteElements() +{ + for( int i=0; i < m_Size; i++ ) + { + delete Element(i); + } + Purge(); +} + +template< typename T, class A > +inline void CUtlVector::Compact() +{ + m_Memory.Purge(m_Size); +} + +template< typename T, class A > +inline int CUtlVector::NumAllocated() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Data and memory validation +//----------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +template< typename T, class A > +void CUtlVector::Validate( CValidator &validator, char *pchName ) +{ + validator.Push( typeid(*this).name(), this, pchName ); + + m_Memory.Validate( validator, "m_Memory" ); + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE + +// A vector class for storing pointers, so that the elements pointed to by the pointers are deleted +// on exit. +template class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> > +{ +public: + ~CUtlVectorAutoPurge( void ) + { + this->PurgeAndDeleteElements(); + } + +}; + +// easy string list class with dynamically allocated strings. For use with V_SplitString, etc. +// Frees the dynamic strings in destructor. +class CUtlStringList : public CUtlVectorAutoPurge< char *> +{ +public: + void CopyAndAddToTail( char const *pString ) // clone the string and add to the end + { + char *pNewStr = new char[1 + strlen( pString )]; + V_strcpy( pNewStr, pString ); + AddToTail( pNewStr ); + } + + static int __cdecl SortFunc( char * const * sz1, char * const * sz2 ) + { + return strcmp( *sz1, *sz2 ); + } + + inline void PurgeAndDeleteElements() + { + for( int i=0; i < m_Size; i++ ) + { + delete [] Element(i); + } + Purge(); + } + + ~CUtlStringList( void ) + { + this->PurgeAndDeleteElements(); + } +}; + + + +// placing it here a few days before Cert to minimize disruption to the rest of codebase +class CSplitString: public CUtlVector > +{ +public: + CSplitString(const char *pString, const char *pSeparator); + CSplitString(const char *pString, const char **pSeparators, int nSeparators); + ~CSplitString(); + // + // NOTE: If you want to make Construct() public and implement Purge() here, you'll have to free m_szBuffer there + // +private: + void Construct(const char *pString, const char **pSeparators, int nSeparators); + void PurgeAndDeleteElements(); +private: + char *m_szBuffer; // a copy of original string, with '\0' instead of separators +}; + + +#endif // CCVECTOR_H diff --git a/public/tier2/beamsegdraw.h b/public/tier2/beamsegdraw.h new file mode 100644 index 0000000..7a11f9c --- /dev/null +++ b/public/tier2/beamsegdraw.h @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#if !defined( BEAMSEGDRAW_H ) +#define BEAMSEGDRAW_H +#ifdef _WIN32 +#pragma once +#endif + +#define NOISE_DIVISIONS 128 + + +#include "mathlib/vector.h" +#include "materialsystem/imesh.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct BeamTrail_t; +class IMaterial; + + +//----------------------------------------------------------------------------- +// CBeamSegDraw is a simple interface to beam rendering. +//----------------------------------------------------------------------------- +struct BeamSeg_t +{ + Vector m_vPos; + Vector m_vColor; + float m_flTexCoord; // Y texture coordinate + float m_flWidth; + float m_flAlpha; +}; + +class CBeamSegDraw +{ +public: + CBeamSegDraw() : m_pRenderContext( NULL ) {} + // Pass null for pMaterial if you have already set the material you want. + void Start( IMatRenderContext *pRenderContext, int nSegs, IMaterial *pMaterial=0, CMeshBuilder *pMeshBuilder = NULL, int nMeshVertCount = 0 ); + virtual void NextSeg( BeamSeg_t *pSeg ); + void End(); + +protected: + void SpecifySeg( const Vector &vecCameraPos, const Vector &vNextPos ); + void ComputeNormal( const Vector &vecCameraPos, const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal ); + + CMeshBuilder *m_pMeshBuilder; + int m_nMeshVertCount; + + CMeshBuilder m_Mesh; + BeamSeg_t m_Seg; + + int m_nTotalSegs; + int m_nSegsDrawn; + + Vector m_vNormalLast; + IMatRenderContext *m_pRenderContext; +}; + +class CBeamSegDrawArbitrary : public CBeamSegDraw +{ +public: + void SetNormal( const Vector &normal ); + void NextSeg( BeamSeg_t *pSeg ); + +protected: + void SpecifySeg( const Vector &vNextPos ); + + BeamSeg_t m_PrevSeg; +}; + +#if 0 +int ScreenTransform( const Vector& point, Vector& screen ); + +void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, const Vector& delta, + float startWidth, float endWidth, float scale, float freq, float speed, int segments, + int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f ); +void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, const Vector& delta, + float startWidth, float endWidth, float scale, float freq, float speed, int segments, + int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f ); +void DrawSplineSegs( int noise_divisions, float *prgNoise, + const model_t* beammodel, const model_t* halomodel, float flHaloScale, + float frame, int rendermode, int numAttachments, Vector* attachment, + float startWidth, float endWidth, float scale, float freq, float speed, int segments, + int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f ); +void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale = 1.0f ); +void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode, const Vector& source, + float scale, float* color, float flHDRColorScale = 1.0f ); +void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, const Vector& delta, + float width, float scale, float freq, float speed, + int segments, float* color, float flHDRColorScale = 1.0f ); +void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel, + float frame, int rendermode, const Vector& source, + const Vector& delta, float width, float scale, float freq, + float speed, int segments, float* color, float flHDRColorScale = 1.0f ); +void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ), + const model_t* spritemodel, float frame, int rendermode, + const Vector& source, const Vector& delta, float width, float amplitude, + float freq, float speed, int segments, float* color, float flHDRColorScale = 1.0f ); +void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode, Vector& delta, + Vector& screen, Vector& screenLast, float die, const Vector& source, + int flags, float width, float amplitude, float freq, float* color, float flHDRColorScale = 1.0f ); + +void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale = 1.0f ); +#endif + +//----------------------------------------------------------------------------- +// Assumes the material has already been bound +//----------------------------------------------------------------------------- +void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ); + +#endif // BEAMDRAW_H diff --git a/public/tier2/camerautils.h b/public/tier2/camerautils.h new file mode 100644 index 0000000..dcaf423 --- /dev/null +++ b/public/tier2/camerautils.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A set of utilities to deal with camera transforms +// +//===========================================================================// + +#ifndef CAMERAUTILS_H +#define CAMERAUTILS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier2/tier2.h" +#include "Color.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class Vector; +class QAngle; +class IMaterial; +struct matrix3x4_t; +class VMatrix; + + +//----------------------------------------------------------------------------- +// Camera state +// TODO: Maybe this should be a base class of CViewSetup? +//----------------------------------------------------------------------------- +struct Camera_t +{ + Vector m_origin; + QAngle m_angles; + float m_flFOV; + float m_flZNear; + float m_flZFar; +}; + + +//----------------------------------------------------------------------------- +// accessors for generated matrices +//----------------------------------------------------------------------------- +void ComputeViewMatrix( VMatrix *pWorldToCamera, const Camera_t& camera ); +void ComputeViewMatrix( matrix3x4_t *pWorldToCamera, const Camera_t& camera ); +void ComputeProjectionMatrix( VMatrix *pCameraToProjection, const Camera_t& camera, int width, int height ); + + +//----------------------------------------------------------------------------- +// Computes the screen space position given a screen size +//----------------------------------------------------------------------------- +void ComputeScreenSpacePosition( Vector2D *pScreenPosition, const Vector &vecWorldPosition, + const Camera_t &camera, int width, int height ); + + +#endif // CAMERAUTILS_H + diff --git a/public/tier2/fileutils.h b/public/tier2/fileutils.h new file mode 100644 index 0000000..d349836 --- /dev/null +++ b/public/tier2/fileutils.h @@ -0,0 +1,317 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef FILEUTILS_H +#define FILEUTILS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifndef TIER2_H +#include "tier2/tier2.h" +#endif + +#ifndef FILESYSTEM_H +#include "filesystem.h" +#endif + +#include "tier0/platform.h" + +// Builds a directory which is a subdirectory of the current mod +void GetModSubdirectory( const char *pSubDir, char *pBuf, int nBufLen ); + +// Builds a directory which is a subdirectory of the current mod's *content* +void GetModContentSubdirectory( const char *pSubDir, char *pBuf, int nBufLen ); + +// Generates a filename under the 'game' subdirectory given a subdirectory of 'content' +void ComputeModFilename( const char *pContentFileName, char *pBuf, size_t nBufLen ); + +// Generates a filename under the 'content' subdirectory given a subdirectory of 'game' +void ComputeModContentFilename( const char *pGameFileName, char *pBuf, size_t nBufLen ); + +// Builds a list of all files under a directory with a particular extension +void AddFilesToList( CUtlVector< CUtlString > &list, const char *pDirectory, const char *pPath, const char *pExtension ); + +// Returns the search path as a list of paths +void GetSearchPath( CUtlVector< CUtlString > &path, const char *pPathID ); + +// Given file name generate a full path using the following rules. +// 1. if its full path already return +// 2. if its a relative path try to find it under the path id +// 3. if find fails treat relative path as relative to the current dir +bool GenerateFullPath( const char *pFileName, char const *pPathID, char *pBuf, int nBufLen ); + + +// Generates a .360 file if it doesn't exist or is out of sync with the pc source file +#define UOC_FAIL -1 +#define UOC_NOT_CREATED 0 +#define UOC_CREATED 1 +typedef bool ( *CreateCallback_t )( const char *pSourceName, const char *pTargetName, const char *pPathID, void *pExtraData ); +int UpdateOrCreate( const char *pSourceName, char *pTargetName, int targetLen, const char *pPathID, CreateCallback_t pfnCreate, bool bForce = false, void *pExtraData = NULL ); + +char *CreateX360Filename( const char *pSourceName, char *pTargetName, int targetLen ); + +FORCEINLINE const char *AdjustFileExtensionForPlatform( const char *pSourceName, char *pTargetName, int targetLen ) +{ +#ifdef PLATFORM_X360 + return CreateX360Filename( pSourceName, pTargetName, targetLen ); +#else + return pSourceName; +#endif +} + +// simple file classes. File I/O mode (text/binary, read/write) is based upon the subclass chosen. +// classes with the word Required on them abort with a message if the file can't be opened. +// destructores close the file handle, or it can be explicitly closed with the Close() method. + +class CBaseFile +{ +public: + FileHandle_t m_FileHandle; + + CBaseFile(void) + { + m_FileHandle = FILESYSTEM_INVALID_HANDLE; + } + + ~CBaseFile( void ) + { + Close(); + } + + FileHandle_t Handle( void ) const + { + return m_FileHandle; + } + + void Close( void ) + { + if ( m_FileHandle != FILESYSTEM_INVALID_HANDLE ) + g_pFullFileSystem->Close( m_FileHandle ); + m_FileHandle = FILESYSTEM_INVALID_HANDLE; + } + + void Open( char const *fname, char const *modes ) + { + Close(); + m_FileHandle = g_pFullFileSystem->Open( fname, modes ); + } + + char *ReadLine( char *pOutput, int maxChars ) + { + return g_pFullFileSystem->ReadLine( pOutput, maxChars, m_FileHandle ); + } + + // read every line of the file into a vector of strings + void ReadLines( CUtlStringList &sList, int nMaxLineLength = 2048 ); + + int Read( void* pOutput, int size ) + { + return g_pFullFileSystem->Read( pOutput, size, m_FileHandle ); + } + + void MustRead( void* pOutput, int size ) + { + int ret=Read( pOutput, size ); + if (ret != size ) + Error("failed to read %d bytes\n", size ); + } + + int Write( void const* pInput, int size) + { + return g_pFullFileSystem->Write( pInput, size, m_FileHandle ); + } + + + // {Get|Put}{Int|Float} read and write ints and floats from a file in x86 order, swapping on + // input for big-endian systems. + void PutInt( int n ) + { + int n1=LittleDWord( n ); + Write(&n1, sizeof( n1 ) ); + } + + int GetInt( void ) + { + int ret; + MustRead( &ret, sizeof( ret )); + return LittleDWord( ret ); + } + + float GetFloat( void ) + { + float ret; + MustRead( &ret, sizeof( ret )); + LittleFloat( &ret, &ret ); + return ret; + } + void PutFloat( float f ) + { + LittleFloat( &f, &f ); + Write( &f, sizeof( f ) ); + } + + bool IsOk( void ) + { + return ( m_FileHandle != FILESYSTEM_INVALID_HANDLE) && + ( g_pFullFileSystem->IsOk( m_FileHandle ) ); + } + + void Seek( int pos, FileSystemSeek_t nSeekType = FILESYSTEM_SEEK_HEAD ) + { + g_pFullFileSystem->Seek( m_FileHandle, pos, nSeekType ); + } + + unsigned int Tell() + { + return g_pFullFileSystem->Tell( m_FileHandle ); + } + + unsigned int Size( void ) + { + Assert( IsOk() ); + return g_pFullFileSystem->Size( m_FileHandle ); + } + + void ReadFile( CUtlBuffer &dataBuf ); +}; + +class COutputFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "wb" ); + } + + COutputFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + + COutputFile( void ) : CBaseFile() + { + } +}; + +class COutputTextFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "w" ); + } + + COutputTextFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + + COutputTextFile( void ) : CBaseFile() + { + } +}; + +class CAppendTextFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "a+" ); + } + + CAppendTextFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + + CAppendTextFile( void ) : CBaseFile() + { + } +}; + +class CInputFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "rb" ); + } + + CInputFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + CInputFile( void ) : CBaseFile() + { + } +}; + +class CInputTextFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "r" ); + } + + CInputTextFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + CInputTextFile( void ) : CBaseFile() + { + } + + +}; + +class CRequiredInputTextFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "r" ); + if ( ! IsOk() ) + { + Error("error opening required file %s\n", pFname ); + } + } + + CRequiredInputTextFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + CRequiredInputTextFile( void ) : CBaseFile() + { + } +}; + +class CRequiredInputFile : public CBaseFile +{ +public: + void Open( char const *pFname ) + { + CBaseFile::Open( pFname, "rb" ); + if ( ! IsOk() ) + { + Error("error opening required file %s\n", pFname ); + } + } + + CRequiredInputFile( char const *pFname ) : CBaseFile() + { + Open( pFname ); + } + CRequiredInputFile( void ) : CBaseFile() + { + } +}; + +#endif // FILEUTILS_H + diff --git a/public/tier2/keybindings.h b/public/tier2/keybindings.h new file mode 100644 index 0000000..050219e --- /dev/null +++ b/public/tier2/keybindings.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef KEYBINDINGS_H +#define KEYBINDINGS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlstring.h" +#include "inputsystem/ButtonCode.h" + +class CUtlBuffer; + + +class CKeyBindings +{ +public: + void SetBinding( ButtonCode_t code, const char *pBinding ); + void SetBinding( const char *pButtonName, const char *pBinding ); + + void Unbind( ButtonCode_t code ); + void Unbind( const char *pButtonName ); + void UnbindAll(); + + int GetBindingCount() const; + void WriteBindings( CUtlBuffer &buf ); + const char *ButtonNameForBinding( const char *pBinding ); + const char *GetBindingForButton( ButtonCode_t code ); + +private: + CUtlString m_KeyInfo[ BUTTON_CODE_LAST ]; +}; + + +#endif // KEYBINDINGS_H diff --git a/public/tier2/meshutils.h b/public/tier2/meshutils.h new file mode 100644 index 0000000..1a995fc --- /dev/null +++ b/public/tier2/meshutils.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A set of utilities to help with generating meshes +// +//===========================================================================// + +#ifndef MESHUTILS_H +#define MESHUTILS_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Helper methods to create various standard index buffer types +//----------------------------------------------------------------------------- +void GenerateSequentialIndexBuffer( unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex ); +void GenerateQuadIndexBuffer( unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex ); +void GeneratePolygonIndexBuffer( unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex ); +void GenerateLineStripIndexBuffer( unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex ); +void GenerateLineLoopIndexBuffer( unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex ); + + +#endif // MESHUTILS_H + diff --git a/public/tier2/p4helpers.h b/public/tier2/p4helpers.h new file mode 100644 index 0000000..61c70c8 --- /dev/null +++ b/public/tier2/p4helpers.h @@ -0,0 +1,179 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef P4HELPERS_H +#define P4HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/utlstring.h" +#include "tier1/smartptr.h" + + +// +// Class representing file operations +// +class CP4File +{ +public: + explicit CP4File( char const *szFilename ); + virtual ~CP4File(); + +public: + // Opens the file for edit + virtual bool Edit( void ); + + // Opens the file for add + virtual bool Add( void ); + + // Reverts the file + virtual bool Revert( void ); + + // Is the file in perforce? + virtual bool IsFileInPerforce(); + + // Changes the file to the specified filetype. + virtual bool SetFileType( const CUtlString& desiredFileType ); + +protected: + // The filename that this class instance represents + CUtlString m_sFilename; +}; + +// +// An override of CP4File performing no Perforce interaction +// +class CP4File_Dummy : public CP4File +{ +public: + explicit CP4File_Dummy( char const *szFilename ) : CP4File( szFilename ) {} + +public: + virtual bool Edit( void ) { return true; } + virtual bool Add( void ) { return true; } + virtual bool IsFileInPerforce() { return false; } + virtual bool SetFileType(const CUtlString& desiredFileType) { return true; } +}; + + +// +// Class representing a factory for creating other helper objects +// +class CP4Factory +{ +public: + CP4Factory(); + ~CP4Factory(); + +public: + // Sets whether dummy objects are created by the factory. + // Returns the old state of the dummy mode. + bool SetDummyMode( bool bDummyMode ); + +public: + // Sets the name of the changelist to open files under, + // NULL for "Default" changelist. + void SetOpenFileChangeList( const char *szChangeListName ); + +public: + // Creates a file access object for the given filename. + CP4File *AccessFile( char const *szFilename ) const; + +protected: + // Whether the factory is in the "dummy mode" and is creating dummy objects + bool m_bDummyMode; +}; + +// Default p4 factory +extern CP4Factory *g_p4factory; + + +// +// CP4AutoEditFile - edits the file upon construction +// +class CP4AutoEditFile +{ +public: + explicit CP4AutoEditFile( char const *szFilename ) : m_spImpl( g_p4factory->AccessFile( szFilename ) ) { m_spImpl->Edit(); } + + CP4File * File() const { return m_spImpl.Get(); } + +protected: + CPlainAutoPtr< CP4File > m_spImpl; +}; + +// +// CP4AutoAddFile - adds the file upon construction +// +class CP4AutoAddFile +{ +public: + explicit CP4AutoAddFile( char const *szFilename ) : m_spImpl( g_p4factory->AccessFile( szFilename ) ) { m_spImpl->Add(); } + + CP4File * File() const { return m_spImpl.Get(); } + +protected: + CPlainAutoPtr< CP4File > m_spImpl; +}; + +// +// CP4AutoEditAddFile - edits the file upon construction / adds upon destruction +// +class CP4AutoEditAddFile +{ +public: + explicit CP4AutoEditAddFile( char const *szFilename ) + : m_spImpl( g_p4factory->AccessFile( szFilename ) ) + , m_bHasDesiredFileType( false ) + { + m_spImpl->Edit(); + } + + explicit CP4AutoEditAddFile( char const *szFilename, const char *szFiletype ) + : m_spImpl( g_p4factory->AccessFile( szFilename ) ) + , m_sFileType(szFiletype) + , m_bHasDesiredFileType( true ) + { + m_spImpl->Edit(); + m_spImpl->SetFileType( m_sFileType ); + } + + ~CP4AutoEditAddFile( void ) + { + m_spImpl->Add(); + if ( m_bHasDesiredFileType ) + m_spImpl->SetFileType( m_sFileType ); + } + + CP4File * File() const { return m_spImpl.Get(); } + +protected: + CPlainAutoPtr< CP4File > m_spImpl; + CUtlString m_sFileType; + bool m_bHasDesiredFileType; +}; + + +// +// CP4AutoRevert - reverts the file upon construction +// +class CP4AutoRevertFile +{ +public: + explicit CP4AutoRevertFile( char const *szFilename ) : m_spImpl( g_p4factory->AccessFile( szFilename ) ) { m_spImpl->Revert(); } + + CP4File * File() const { return m_spImpl.Get(); } + +protected: + CPlainAutoPtr< CP4File > m_spImpl; +}; + + +#endif // #ifndef P4HELPERS_H diff --git a/public/tier2/renderutils.h b/public/tier2/renderutils.h new file mode 100644 index 0000000..fe3d87c --- /dev/null +++ b/public/tier2/renderutils.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A set of utilities to render standard shapes +// +//===========================================================================// + +#ifndef RENDERUTILS_H +#define RENDERUTILS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier2/tier2.h" +#include "Color.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class Vector; +class QAngle; +class IMaterial; +struct matrix3x4_t; + + +// Renders a wireframe sphere +void RenderWireframeSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer ); + +// Renders a sphere +void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer ); +void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi, Color c, IMaterial *pMaterial ); + +// Renders a wireframe box relative to an origin +void RenderWireframeBox( const Vector &vOrigin, const QAngle& angles, const Vector &vMins, const Vector &vMaxs, Color c, bool bZBuffer ); + +// Renders a swept wireframe box +void RenderWireframeSweptBox( const Vector &vStart, const Vector &vEnd, const QAngle &angles, const Vector &vMins, const Vector &vMaxs, Color c, bool bZBuffer ); + +// Renders a solid box +void RenderBox( const Vector& origin, const QAngle& angles, const Vector& mins, const Vector& maxs, Color c, bool bZBuffer, bool bInsideOut = false ); +void RenderBox( const Vector& origin, const QAngle& angles, const Vector& mins, const Vector& maxs, Color c, IMaterial *pMaterial, bool bInsideOut = false ); + +// Renders axes, red->x, green->y, blue->z (axis aligned) +void RenderAxes( const Vector &vOrigin, float flScale, bool bZBuffer ); +void RenderAxes( const matrix3x4_t &transform, float flScale, bool bZBuffer ); + +// Render a line +void RenderLine( const Vector& v1, const Vector& v2, Color c, bool bZBuffer ); + +// Draws a triangle +void RenderTriangle( const Vector& p1, const Vector& p2, const Vector& p3, Color c, bool bZBuffer ); +void RenderTriangle( const Vector& p1, const Vector& p2, const Vector& p3, Color c, IMaterial *pMaterial ); + +// Draws a axis-aligned quad +void RenderQuad( IMaterial *pMaterial, float x, float y, float w, float h, float z, float s0, float t0, float s1, float t1, const Color& clr ); + +// Renders a screen space quad +void DrawScreenSpaceRectangle( IMaterial *pMaterial, + int nDestX, int nDestY, int nWidth, int nHeight, // Rect to draw into in screen space + float flSrcTextureX0, float flSrcTextureY0, // which texel you want to appear at destx/y + float flSrcTextureX1, float flSrcTextureY1, // which texel you want to appear at destx+width-1, desty+height-1 + int nSrcTextureWidth, int nSrcTextureHeight, // needed for fixup + void *pClientRenderable = NULL, // Used to pass to the bind proxies + int nXDice = 1, + int nYDice = 1, + float fDepth = 0.0 ); // what Z value to put in the verts + +#endif // RENDERUTILS_H + diff --git a/public/tier2/riff.h b/public/tier2/riff.h new file mode 100644 index 0000000..e24b090 --- /dev/null +++ b/public/tier2/riff.h @@ -0,0 +1,202 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RIFF_H +#define RIFF_H +#pragma once + +#include "commonmacros.h" + + +//----------------------------------------------------------------------------- +// Purpose: This is a simple abstraction that the RIFF classes use to read from +// files/memory +//----------------------------------------------------------------------------- +class IFileReadBinary +{ +public: + virtual int open( const char *pFileName ) = 0; + virtual int read( void *pOutput, int size, int file ) = 0; + virtual void close( int file ) = 0; + virtual void seek( int file, int pos ) = 0; + virtual unsigned int tell( int file ) = 0; + virtual unsigned int size( int file ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Used to read/parse a RIFF format file +//----------------------------------------------------------------------------- +class InFileRIFF +{ +public: + InFileRIFF( const char *pFileName, IFileReadBinary &io ); + ~InFileRIFF( void ); + + unsigned int RIFFName( void ) { return m_riffName; } + unsigned int RIFFSize( void ) { return m_riffSize; } + + int ReadInt( void ); + int ReadData( void *pOutput, int dataSize ); + int PositionGet( void ); + void PositionSet( int position ); + bool IsValid( void ) { return m_file != 0; } + +private: + const InFileRIFF & operator=( const InFileRIFF & ); + + IFileReadBinary &m_io; + int m_file; + unsigned int m_riffName; + unsigned int m_riffSize; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Used to iterate over an InFileRIFF +//----------------------------------------------------------------------------- +class IterateRIFF +{ +public: + IterateRIFF( InFileRIFF &riff, int size ); + IterateRIFF( IterateRIFF &parent ); + + bool ChunkAvailable( void ); + bool ChunkNext( void ); + + unsigned int ChunkName( void ); + unsigned int ChunkSize( void ); + int ChunkRead( void *pOutput ); + int ChunkReadPartial( void *pOutput, int dataSize ); + int ChunkReadInt( void ); + int ChunkFilePosition( void ) { return m_chunkPosition; } + +private: + const IterateRIFF & operator=( const IterateRIFF & ); + + void ChunkSetup( void ); + void ChunkClear( void ); + + InFileRIFF &m_riff; + int m_start; + int m_size; + + unsigned int m_chunkName; + int m_chunkSize; + int m_chunkPosition; +}; + +class IFileWriteBinary +{ +public: + virtual int create( const char *pFileName ) = 0; + virtual int write( void *pData, int size, int file ) = 0; + virtual void close( int file ) = 0; + virtual void seek( int file, int pos ) = 0; + virtual unsigned int tell( int file ) = 0; +}; +//----------------------------------------------------------------------------- +// Purpose: Used to write a RIFF format file +//----------------------------------------------------------------------------- +class OutFileRIFF +{ +public: + OutFileRIFF( const char *pFileName, IFileWriteBinary &io ); + ~OutFileRIFF( void ); + + bool WriteInt( int number ); + bool WriteData( void *pOutput, int dataSize ); + int PositionGet( void ); + void PositionSet( int position ); + bool IsValid( void ) { return m_file != 0; } + + void HasLISETData( int position ); + +private: + const OutFileRIFF & operator=( const OutFileRIFF & ); + + IFileWriteBinary &m_io; + int m_file; + unsigned int m_riffName; + unsigned int m_riffSize; + unsigned int m_nNamePos; + + // hack to make liset work correctly + bool m_bUseIncorrectLISETLength; + int m_nLISETSize; + + +}; + +//----------------------------------------------------------------------------- +// Purpose: Used to iterate over an InFileRIFF +//----------------------------------------------------------------------------- +class IterateOutputRIFF +{ +public: + IterateOutputRIFF( OutFileRIFF &riff ); + IterateOutputRIFF( IterateOutputRIFF &parent ); + + void ChunkStart( unsigned int chunkname ); + void ChunkFinish( void ); + + void ChunkWrite( unsigned int chunkname, void *pOutput, int size ); + void ChunkWriteInt( int number ); + void ChunkWriteData( void *pOutput, int size ); + + int ChunkFilePosition( void ) { return m_chunkPosition; } + + unsigned int ChunkGetPosition( void ); + void ChunkSetPosition( int position ); + + void CopyChunkData( IterateRIFF& input ); + + void SetLISETData( int position ); + +private: + + const IterateOutputRIFF & operator=( const IterateOutputRIFF & ); + + OutFileRIFF &m_riff; + int m_start; + int m_size; + + unsigned int m_chunkName; + int m_chunkSize; + int m_chunkPosition; + int m_chunkStart; +}; + +#define RIFF_ID MAKEID('R','I','F','F') +#define RIFF_WAVE MAKEID('W','A','V','E') +#define WAVE_FMT MAKEID('f','m','t',' ') +#define WAVE_DATA MAKEID('d','a','t','a') +#define WAVE_FACT MAKEID('f','a','c','t') +#define WAVE_CUE MAKEID('c','u','e',' ') +#define WAVE_SAMPLER MAKEID('s','m','p','l') +#define WAVE_VALVEDATA MAKEID('V','D','A','T') +#define WAVE_PADD MAKEID('P','A','D','D') +#define WAVE_LIST MAKEID('L','I','S','T') + +#ifndef WAVE_FORMAT_PCM +#define WAVE_FORMAT_PCM 0x0001 +#endif +#ifndef WAVE_FORMAT_ADPCM +#define WAVE_FORMAT_ADPCM 0x0002 +#endif +#define WAVE_FORMAT_XBOX_ADPCM 0x0069 +#ifndef WAVE_FORMAT_XMA +#define WAVE_FORMAT_XMA 0x0165 +#endif + +#endif // RIFF_H diff --git a/public/tier2/soundutils.h b/public/tier2/soundutils.h new file mode 100644 index 0000000..eca1337 --- /dev/null +++ b/public/tier2/soundutils.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Helper methods + classes for sound +// +//===========================================================================// + +#ifndef SOUNDUTILS_H +#define SOUNDUTILS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier2/riff.h" + + +//----------------------------------------------------------------------------- +// RIFF reader/writers that use the file system +//----------------------------------------------------------------------------- +extern IFileReadBinary *g_pFSIOReadBinary; +extern IFileWriteBinary *g_pFSIOWriteBinary; + + +//----------------------------------------------------------------------------- +// Returns the duration of a wav file +//----------------------------------------------------------------------------- +float GetWavSoundDuration( const char *pWavFile ); + + +#endif // SOUNDUTILS_H + diff --git a/public/tier2/tier2.h b/public/tier2/tier2.h new file mode 100644 index 0000000..68bb6bb --- /dev/null +++ b/public/tier2/tier2.h @@ -0,0 +1,128 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER2_H +#define TIER2_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1/tier1.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IFileSystem; +class IMaterialSystem; +class IColorCorrectionSystem; +class IMaterialSystemHardwareConfig; +class IDebugTextureInfo; +class IVBAllocTracker; +class IInputSystem; +class INetworkSystem; +class IP4; +class IMdlLib; +class IQueuedLoader; + + +//----------------------------------------------------------------------------- +// These tier2 libraries must be set by any users of this library. +// They can be set by calling ConnectTier2Libraries or InitDefaultFileSystem. +// It is hoped that setting this, and using this library will be the common mechanism for +// allowing link libraries to access tier2 library interfaces +//----------------------------------------------------------------------------- +extern IFileSystem *g_pFullFileSystem; +extern IMaterialSystem *materials; +extern IMaterialSystem *g_pMaterialSystem; +extern IInputSystem *g_pInputSystem; +extern INetworkSystem *g_pNetworkSystem; +extern IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig; +extern IDebugTextureInfo *g_pMaterialSystemDebugTextureInfo; +extern IVBAllocTracker *g_VBAllocTracker; +extern IColorCorrectionSystem *colorcorrection; +extern IP4 *p4; +extern IMdlLib *mdllib; +extern IQueuedLoader *g_pQueuedLoader; + + +//----------------------------------------------------------------------------- +// Call this to connect to/disconnect from all tier 2 libraries. +// It's up to the caller to check the globals it cares about to see if ones are missing +//----------------------------------------------------------------------------- +void ConnectTier2Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount ); +void DisconnectTier2Libraries(); + + +//----------------------------------------------------------------------------- +// Call this to get the file system set up to stdio for utilities, etc: +//----------------------------------------------------------------------------- +void InitDefaultFileSystem(void); +void ShutdownDefaultFileSystem(void); + + +//----------------------------------------------------------------------------- +// for simple utilities using valve libraries, call the entry point below in main(). It will +// init a filesystem for you, init mathlib, and create the command line. +//----------------------------------------------------------------------------- +void InitCommandLineProgram( int argc, char **argv ); + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier2AppSystem : public CTier1AppSystem< IInterface, ConVarFlag > +{ + typedef CTier1AppSystem< IInterface, ConVarFlag > BaseClass; + +public: + CTier2AppSystem( bool bIsPrimaryAppSystem = true ) : BaseClass( bIsPrimaryAppSystem ) + { + } + + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( BaseClass::IsPrimaryAppSystem() ) + { + ConnectTier2Libraries( &factory, 1 ); + } + + return true; + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + return INIT_OK; + } + + virtual void Shutdown() + { + BaseClass::Shutdown(); + } + + virtual void Disconnect() + { + if ( BaseClass::IsPrimaryAppSystem() ) + { + DisconnectTier2Libraries(); + } + BaseClass::Disconnect(); + } +}; + + +#endif // TIER2_H + diff --git a/public/tier2/tier2dm.h b/public/tier2/tier2dm.h new file mode 100644 index 0000000..40ce58b --- /dev/null +++ b/public/tier2/tier2dm.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER2DM_H +#define TIER2DM_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier2/tier2.h" + +//----------------------------------------------------------------------------- +// Set up methods related to datamodel interfaces +//----------------------------------------------------------------------------- +bool ConnectDataModel( CreateInterfaceFn factory ); +InitReturnVal_t InitDataModel(); +void ShutdownDataModel(); +void DisconnectDataModel(); + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier2DmAppSystem : public CTier2AppSystem< IInterface, ConVarFlag > +{ + typedef CTier2AppSystem< IInterface, ConVarFlag > BaseClass; + +public: + CTier2DmAppSystem( bool bIsPrimaryAppSystem = true ) : BaseClass( bIsPrimaryAppSystem ) + { + } + + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + ConnectDataModel( factory ); + + return true; + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + nRetVal = InitDataModel(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + return INIT_OK; + } + + virtual void Shutdown() + { + ShutdownDataModel(); + BaseClass::Shutdown(); + } + + virtual void Disconnect() + { + DisconnectDataModel(); + BaseClass::Disconnect(); + } +}; + + +#endif // TIER2DM_H + diff --git a/public/tier2/utlstreambuffer.h b/public/tier2/utlstreambuffer.h new file mode 100644 index 0000000..d1d9c11 --- /dev/null +++ b/public/tier2/utlstreambuffer.h @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//=============================================================================// + +#ifndef UTLSTREAMBUFFER_H +#define UTLSTREAMBUFFER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlbuffer.h" +#include "filesystem.h" + + +//----------------------------------------------------------------------------- +// Command parsing.. +//----------------------------------------------------------------------------- +class CUtlStreamBuffer : public CUtlBuffer +{ + typedef CUtlBuffer BaseClass; + +public: + // See CUtlBuffer::BufferFlags_t for flags + CUtlStreamBuffer( ); + CUtlStreamBuffer( const char *pFileName, const char *pPath, int nFlags = 0, bool bDelayOpen = false ); + ~CUtlStreamBuffer(); + + // Open the file. normally done in constructor + void Open( const char *pFileName, const char *pPath, int nFlags ); + + // close the file. normally done in destructor + void Close(); + + // Is the file open? + bool IsOpen() const; + +private: + // error flags + enum + { + FILE_OPEN_ERROR = MAX_ERROR_FLAG << 1, + FILE_WRITE_ERROR = MAX_ERROR_FLAG << 2, + }; + + // Overflow functions + bool StreamPutOverflow( int nSize ); + bool StreamGetOverflow( int nSize ); + + // Grow allocation size to fit requested size + void GrowAllocatedSize( int nSize ); + + // Reads bytes from the file; fixes up maxput if necessary and null terminates + int ReadBytesFromFile( int nBytesToRead, int nReadOffset ); + + FileHandle_t OpenFile( const char *pFileName, const char *pPath ); + + FileHandle_t m_hFileHandle; + + char *m_pFileName; + char *m_pPath; +}; + + +#endif // UTLSTREAMBUFFER_H + diff --git a/public/tier2/vconfig.h b/public/tier2/vconfig.h new file mode 100644 index 0000000..2ccf9d1 --- /dev/null +++ b/public/tier2/vconfig.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Utilities for setting vproject settings +// +//===========================================================================// + +#ifndef _VCONFIG_H +#define _VCONFIG_H + +#ifdef _WIN32 +#pragma once +#endif + + +// The registry keys that vconfig uses to store the current vproject directory. +//#define VPROJECT_REG_KEY "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment" +// Moved to simply 'Environment' - we need to set in HKEY_CURRENT_USER and not local machine, to avoid security issues in vista! +#define VPROJECT_REG_KEY "Environment" + +// For accessing the environment variables we store the current vproject in. +void SetVConfigRegistrySetting( const char *pName, const char *pValue, bool bNotify = true ); +bool GetVConfigRegistrySetting( const char *pName, char *pReturn, int size ); +#ifdef _WIN32 +bool RemoveObsoleteVConfigRegistrySetting( const char *pValueName, char *pOldValue = NULL , int size = 0 ); +#endif +bool ConvertObsoleteVConfigRegistrySetting( const char *pValueName ); + + +#endif // _VCONFIG_H \ No newline at end of file diff --git a/public/tier3/choreoutils.h b/public/tier3/choreoutils.h new file mode 100644 index 0000000..b531737 --- /dev/null +++ b/public/tier3/choreoutils.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Helper methods + classes for choreo +// +//===========================================================================// + +#ifndef CHOREOUTILS_H +#define CHOREOUTILS_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CChoreoScene; +class CChoreoEvent; +class CStudioHdr; + + +//----------------------------------------------------------------------------- +// Finds sound files associated with events +//----------------------------------------------------------------------------- +const char *GetSoundForEvent( CChoreoEvent *pEvent, CStudioHdr *pStudioHdr ); + + +//----------------------------------------------------------------------------- +// Fixes up the duration of a choreo scene based on wav files + animations +// Returns true if a change needed to be made +//----------------------------------------------------------------------------- +bool AutoAddGestureKeys( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly ); +bool UpdateGestureLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly ); +bool UpdateSequenceLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly, bool bVerbose ); + + +#endif // CHOREOUTILS_H + diff --git a/public/tier3/mdlutils.h b/public/tier3/mdlutils.h new file mode 100644 index 0000000..1e04abd --- /dev/null +++ b/public/tier3/mdlutils.h @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef MDLUTILS_H +#define MDLUTILS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "datacache/imdlcache.h" +#include "mathlib/vector.h" +#include "Color.h" +#include "studio.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct matrix3x4_t; + +struct MDLSquenceLayer_t +{ + int m_nSequenceIndex; + float m_flWeight; + bool m_bNoLoop; + float m_flCycleBeganAt; +}; + +//----------------------------------------------------------------------------- +// Class containing simplistic MDL state for use in rendering +//----------------------------------------------------------------------------- +class CMDL +{ +public: + CMDL(); + ~CMDL(); + + void SetMDL( MDLHandle_t h ); + MDLHandle_t GetMDL() const; + + // Simple version of drawing; sets up bones for you + void Draw( const matrix3x4_t& rootToWorld ); + + // NOTE: This version of draw assumes you've filled in the bone to world + // matrix yourself by calling IStudioRender::LockBoneMatrices. The pointer + // returned by that method needs to be passed into here + void Draw( const matrix3x4_t& rootToWorld, const matrix3x4_t *pBoneToWorld ); + + + void SetUpBones( const matrix3x4_t& shapeToWorld, int nMaxBoneCount, matrix3x4_t *pOutputMatrices, const float *pPoseParameters = NULL, MDLSquenceLayer_t *pSequenceLayers = NULL, int nNumSequenceLayers = 0 ); + void SetupBonesWithBoneMerge( const CStudioHdr *pMergeHdr, matrix3x4_t *pMergeBoneToWorld, + const CStudioHdr *pFollow, const matrix3x4_t *pFollowBoneToWorld, const matrix3x4_t &matModelToWorld ); + + studiohdr_t *GetStudioHdr(); + +private: + void UnreferenceMDL(); + +public: + MDLHandle_t m_MDLHandle; + Color m_Color; + int m_nSkin; + int m_nBody; + int m_nSequence; + int m_nLOD; + float m_flPlaybackRate; + float m_flTime; + float m_pFlexControls[ MAXSTUDIOFLEXCTRL * 4 ]; + Vector m_vecViewTarget; + bool m_bWorldSpaceViewTarget; + void *m_pProxyData; +}; + + +//----------------------------------------------------------------------------- +// Returns the bounding box for the model +//----------------------------------------------------------------------------- +void GetMDLBoundingBox( Vector *pMins, Vector *pMaxs, MDLHandle_t h, int nSequence ); + +//----------------------------------------------------------------------------- +// Returns the radius of the model as measured from the origin +//----------------------------------------------------------------------------- +float GetMDLRadius( MDLHandle_t h, int nSequence ); + +//----------------------------------------------------------------------------- +// Returns a more accurate bounding sphere +//----------------------------------------------------------------------------- +void GetMDLBoundingSphere( Vector *pVecCenter, float *pRadius, MDLHandle_t h, int nSequence ); + + +#endif // MDLUTILS_H + diff --git a/public/tier3/scenetokenprocessor.h b/public/tier3/scenetokenprocessor.h new file mode 100644 index 0000000..d614b75 --- /dev/null +++ b/public/tier3/scenetokenprocessor.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SCENETOKENPROCESSOR_H +#define SCENETOKENPROCESSOR_H +#ifdef _WIN32 +#pragma once +#endif + +class ISceneTokenProcessor; + +ISceneTokenProcessor *GetTokenProcessor(); +void SetTokenProcessorBuffer( const char *buf ); + +#endif // SCENETOKENPROCESSOR_H diff --git a/public/tier3/tier3.h b/public/tier3/tier3.h new file mode 100644 index 0000000..7f53353 --- /dev/null +++ b/public/tier3/tier3.h @@ -0,0 +1,114 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER3_H +#define TIER3_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier2/tier2.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IStudioRender; +class IMatSystemSurface; +class IDataCache; +class IMDLCache; +class IVideoServices; +class IDmeMakefileUtils; +class IPhysicsCollision; +class ISoundEmitterSystemBase; +class IVTex; + +namespace vgui +{ + class ISurface; + class IVGui; + class IInput; + class IPanel; + class ILocalize; + class ISchemeManager; + class ISystem; +} + + +//----------------------------------------------------------------------------- +// These tier3 libraries must be set by any users of this library. +// They can be set by calling ConnectTier3Libraries. +// It is hoped that setting this, and using this library will be the common mechanism for +// allowing link libraries to access tier3 library interfaces +//----------------------------------------------------------------------------- +extern IStudioRender *g_pStudioRender; +extern IStudioRender *studiorender; +extern IMatSystemSurface *g_pMatSystemSurface; +extern vgui::ISurface *g_pVGuiSurface; +extern vgui::IInput *g_pVGuiInput; +extern vgui::IVGui *g_pVGui; +extern vgui::IPanel *g_pVGuiPanel; +extern vgui::ILocalize *g_pVGuiLocalize; +extern vgui::ISchemeManager *g_pVGuiSchemeManager; +extern vgui::ISystem *g_pVGuiSystem; +extern IDataCache *g_pDataCache; // FIXME: Should IDataCache be in tier2? +extern IMDLCache *g_pMDLCache; +extern IMDLCache *mdlcache; +extern IVideoServices *g_pVideo; +extern IDmeMakefileUtils *g_pDmeMakefileUtils; +extern IPhysicsCollision *g_pPhysicsCollision; +extern ISoundEmitterSystemBase *g_pSoundEmitterSystem; +extern IVTex *g_pVTex; + + +//----------------------------------------------------------------------------- +// Call this to connect to/disconnect from all tier 3 libraries. +// It's up to the caller to check the globals it cares about to see if ones are missing +//----------------------------------------------------------------------------- +void ConnectTier3Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount ); +void DisconnectTier3Libraries(); + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier3AppSystem : public CTier2AppSystem< IInterface, ConVarFlag > +{ + typedef CTier2AppSystem< IInterface, ConVarFlag > BaseClass; + +public: + CTier3AppSystem( bool bIsPrimaryAppSystem = true ) : BaseClass( bIsPrimaryAppSystem ) + { + } + + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( BaseClass::IsPrimaryAppSystem() ) + { + ConnectTier3Libraries( &factory, 1 ); + } + return true; + } + + virtual void Disconnect() + { + if ( BaseClass::IsPrimaryAppSystem() ) + { + DisconnectTier3Libraries(); + } + BaseClass::Disconnect(); + } +}; + + +#endif // TIER3_H + diff --git a/public/tier3/tier3dm.h b/public/tier3/tier3dm.h new file mode 100644 index 0000000..5ac6028 --- /dev/null +++ b/public/tier3/tier3dm.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER3DM_H +#define TIER3DM_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier3/tier3.h" +#include "tier2/tier2dm.h" + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier3DmAppSystem : public CTier2DmAppSystem< IInterface, ConVarFlag > +{ + typedef CTier2DmAppSystem< IInterface, ConVarFlag > BaseClass; + +public: + CTier3DmAppSystem( bool bIsPrimaryAppSystem = true ) : BaseClass( bIsPrimaryAppSystem ) + { + } + + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( IsPrimaryAppSystem() ) + { + ConnectTier3Libraries( &factory, 1 ); + } + return true; + } + + virtual void Disconnect() + { + if ( IsPrimaryAppSystem() ) + { + DisconnectTier3Libraries(); + } + BaseClass::Disconnect(); + } +}; + + +#endif // TIER3DM_H + diff --git a/public/togl/glfuncs.inl b/public/togl/glfuncs.inl new file mode 100644 index 0000000..1f6b3b4 --- /dev/null +++ b/public/togl/glfuncs.inl @@ -0,0 +1,2 @@ +#include "togl/linuxwin/glfuncs.h" + diff --git a/public/togl/linuxwin/cglmbuffer.h b/public/togl/linuxwin/cglmbuffer.h new file mode 100644 index 0000000..1078224 --- /dev/null +++ b/public/togl/linuxwin/cglmbuffer.h @@ -0,0 +1,262 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// cglmprogram.h +// GLMgr buffers (index / vertex) +// ... maybe add PBO later as well +//=============================================================================== + +#ifndef CGLMBUFFER_H +#define CGLMBUFFER_H + +#pragma once + +//=============================================================================== + +extern bool g_bUsePseudoBufs; + +// forward declarations + +class GLMContext; + +enum EGLMBufferType +{ + kGLMVertexBuffer, + kGLMIndexBuffer, + kGLMUniformBuffer, // for bindable uniform + kGLMPixelBuffer, // for PBO + + kGLMNumBufferTypes +}; + +// pass this in "options" to constructor to make a dynamic buffer +#define GLMBufferOptionDynamic 0x00000001 + +struct GLMBuffLockParams +{ + uint m_nOffset; + uint m_nSize; + bool m_bNoOverwrite; + bool m_bDiscard; +}; + +#define GL_STATIC_BUFFER_SIZE ( 2048 * 1024 ) +#define GL_MAX_STATIC_BUFFERS 2 + +extern void glBufferSubDataMaxSize( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data, uint nMaxSizePerCall = 128 * 1024 ); + +//===========================================================================// + +// Creates an immutable storage for a buffer object +// https://www.opengl.org/registry/specs/ARB/buffer_storage.txt +class CPersistentBuffer +{ +public: + + CPersistentBuffer(); + ~CPersistentBuffer(); + + void Init( EGLMBufferType type,uint nSize ); + void Deinit(); + + void InsertFence(); + void BlockUntilNotBusy(); + + void Append( uint nSize ); + + inline uint GetBytesRemaining() const { return m_nSize - m_nOffset; } + inline uint GetOffset() const { return m_nOffset; } + inline void *GetPtr() const { return m_pImmutablePersistentBuf; } + inline GLuint GetHandle() const { return m_nHandle; } + +private: + + CPersistentBuffer( const CPersistentBuffer & ); + CPersistentBuffer & operator= (const CPersistentBuffer &); + + uint m_nSize; + + EGLMBufferType m_type; + GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB + GLuint m_nHandle; // handle of this program in the GL context + + // Holds a pointer to the persistently mapped buffer + void* m_pImmutablePersistentBuf; + + uint m_nOffset; + +#ifdef HAVE_GL_ARB_SYNC + GLsync m_nSyncObj; +#endif +}; + +//=============================================================================== + +#if GL_ENABLE_INDEX_VERIFICATION + +struct GLDynamicBuf_t +{ + GLenum m_nGLType; + uint m_nHandle; + uint m_nActualBufSize; + uint m_nSize; + + uint m_nLockOffset; + uint m_nLockSize; +}; + +class CGLMBufferSpanManager +{ + CGLMBufferSpanManager( const CGLMBufferSpanManager& ); + CGLMBufferSpanManager& operator= ( const CGLMBufferSpanManager& ); + +public: + CGLMBufferSpanManager(); + ~CGLMBufferSpanManager(); + + void Init( GLMContext *pContext, EGLMBufferType nBufType, uint nInitialCapacity, uint nBufSize, bool bDynamic ); + void Deinit(); + + inline GLMContext *GetContext() const { return m_pCtx; } + + inline GLenum GetGLBufType() const { return ( m_nBufType == kGLMVertexBuffer ) ? GL_ARRAY_BUFFER_ARB : GL_ELEMENT_ARRAY_BUFFER_ARB; } + + struct ActiveSpan_t + { + uint m_nStart; + uint m_nEnd; + + GLDynamicBuf_t m_buf; + bool m_bOriginalAlloc; + + inline ActiveSpan_t() { } + inline ActiveSpan_t( uint nStart, uint nEnd, GLDynamicBuf_t &buf, bool bOriginalAlloc ) : m_nStart( nStart ), m_nEnd( nEnd ), m_buf( buf ), m_bOriginalAlloc( bOriginalAlloc ) { Assert( nStart <= nEnd ); } + }; + + ActiveSpan_t *AddSpan( uint nOffset, uint nMaxSize, uint nActualSize, bool bDiscard, bool bNoOverwrite ); + + void DiscardAllSpans(); + + bool IsValid( uint nOffset, uint nSize ) const; + +private: + bool AllocDynamicBuf( uint nSize, GLDynamicBuf_t &buf ); + void ReleaseDynamicBuf( GLDynamicBuf_t &buf ); + + GLMContext *m_pCtx; + + EGLMBufferType m_nBufType; + + uint m_nBufSize; + bool m_bDynamic; + + CUtlVector m_ActiveSpans; + CUtlVector m_DeletedSpans; + + int m_nSpanEndMax; + + int m_nNumAllocatedBufs; + int m_nTotalBytesAllocated; +}; + +#endif // GL_ENABLE_INDEX_VERIFICATION + +class CGLMBuffer +{ +public: + void Lock( GLMBuffLockParams *pParams, char **pAddressOut ); + void Unlock( int nActualSize = -1, const void *pActualData = NULL ); + + GLuint GetHandle() const; + + friend class GLMContext; // only GLMContext can make CGLMBuffer objects + friend class GLMTester; + friend struct IDirect3D9; + friend struct IDirect3DDevice9; + + CGLMBuffer( GLMContext *pCtx, EGLMBufferType type, uint size, uint options ); + ~CGLMBuffer(); + + void SetModes( bool bAsyncMap, bool bExplicitFlush, bool bForce = false ); + void FlushRange( uint offset, uint size ); + +#if GL_ENABLE_INDEX_VERIFICATION + bool IsSpanValid( uint nOffset, uint nSize ) const; +#endif + + GLMContext *m_pCtx; // link back to parent context + EGLMBufferType m_type; + uint m_nSize; + uint m_nActualSize; + + bool m_bDynamic; + + GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB + GLuint m_nHandle; // name of this program in the context + + uint m_nRevision; // bump anytime the size changes or buffer is orphaned + + bool m_bEnableAsyncMap; // mirror of the buffer state + bool m_bEnableExplicitFlush; // mirror of the buffer state + + bool m_bMapped; // is it currently mapped + + uint m_dirtyMinOffset; // when equal, range is empty + uint m_dirtyMaxOffset; + + float *m_pLastMappedAddress; + + int m_nPinnedMemoryOfs; + + uint m_nPersistentBufferStartOffset; + bool m_bUsingPersistentBuffer; + + bool m_bPseudo; // true if the m_name is 0, and the backing is plain RAM + + // in pseudo mode, there is just one RAM buffer that acts as the backing. + // expectation is that this mode would only be used for dynamic indices. + // since indices have to be consumed (copied to command stream) prior to return from a drawing call, + // there's no need to do any fencing or multibuffering. orphaning in particular becomes a no-op. + + char *m_pActualPseudoBuf; // storage for pseudo buffer + char *m_pPseudoBuf; // storage for pseudo buffer + char *m_pStaticBuffer; + + GLMBuffLockParams m_LockParams; + + static char ALIGN16 m_StaticBuffers[ GL_MAX_STATIC_BUFFERS ][ GL_STATIC_BUFFER_SIZE ] ALIGN16_POST; + static bool m_bStaticBufferUsed[ GL_MAX_STATIC_BUFFERS ]; + +#if GL_ENABLE_INDEX_VERIFICATION + CGLMBufferSpanManager m_BufferSpanManager; +#endif + +#if GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION + uint m_nDirtyRangeStart; + uint m_nDirtyRangeEnd; +#endif +}; + +#endif // CGLMBUFFER_H + diff --git a/public/togl/linuxwin/cglmfbo.h b/public/togl/linuxwin/cglmfbo.h new file mode 100644 index 0000000..93ebb11 --- /dev/null +++ b/public/togl/linuxwin/cglmfbo.h @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// cglmfbo.h +// GLMgr FBO's (render targets) +// +//=============================================================================== + +#ifndef CGLMFBO_H +#define CGLMFBO_H + +#pragma once + +// good FBO references / recaps +// http://www.songho.ca/opengl/gl_fbo.html +// http://www.gamedev.net/reference/articles/article2331.asp + +// ext links + +// http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt +// http://www.opengl.org/registry/specs/EXT/framebuffer_multisample.txt + +//=============================================================================== + +// tokens not in the SDK headers + +#ifndef GL_DEPTH_STENCIL_ATTACHMENT_EXT + #define GL_DEPTH_STENCIL_ATTACHMENT_EXT 0x84F9 +#endif + +//=============================================================================== + +// forward declarations + +class GLMContext; + +enum EGLMFBOAttachment +{ + kAttColor0, kAttColor1, kAttColor2, kAttColor3, + kAttDepth, kAttStencil, kAttDepthStencil, + kAttCount +}; + +struct GLMFBOTexAttachParams +{ + CGLMTex *m_tex; + int m_face; // keep zero if not cube map + int m_mip; // keep zero if notmip mapped + int m_zslice; // keep zero if not a 3D tex +}; + +class CGLMFBO +{ + friend class GLMContext; + friend class GLMTester; + friend class CGLMTex; + + friend struct IDirect3D9; + friend struct IDirect3DDevice9; + +public: + CGLMFBO( GLMContext *ctx ); + ~CGLMFBO( ); + +protected: + void TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint = GL_FRAMEBUFFER_EXT ); + void TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint = GL_FRAMEBUFFER_EXT ); + // you can also pass GL_READ_FRAMEBUFFER_EXT or GL_DRAW_FRAMEBUFFER_EXT to selectively bind the receiving FBO to one or the other. + + void TexScrub( CGLMTex *tex ); + // search and destroy any attachment for the named texture + + bool IsReady( void ); // aka FBO completeness check - ready to draw + + GLMContext *m_ctx; // link back to parent context + + GLuint m_name; // name of this FBO in the context + + GLMFBOTexAttachParams m_attach[ kAttCount ]; // indexed by EGLMFBOAttachment +}; + + +#endif \ No newline at end of file diff --git a/public/togl/linuxwin/cglmprogram.h b/public/togl/linuxwin/cglmprogram.h new file mode 100644 index 0000000..e3f4f60 --- /dev/null +++ b/public/togl/linuxwin/cglmprogram.h @@ -0,0 +1,458 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// cglmprogram.h +// GLMgr programs (ARBVP/ARBfp) +// +//=============================================================================== + +#ifndef CGLMPROGRAM_H +#define CGLMPROGRAM_H + +#include + +#pragma once + +// good ARB program references +// http://petewarden.com/notes/archives/2005/05/fragment_progra_2.html +// http://petewarden.com/notes/archives/2005/06/fragment_progra_3.html + +// ext links + +// http://www.opengl.org/registry/specs/ARB/vertex_program.txt +// http://www.opengl.org/registry/specs/ARB/fragment_program.txt +// http://www.opengl.org/registry/specs/EXT/gpu_program_parameters.txt + + +//=============================================================================== + +// tokens not in the SDK headers + +//#ifndef GL_DEPTH_STENCIL_ATTACHMENT_EXT +// #define GL_DEPTH_STENCIL_ATTACHMENT_EXT 0x84F9 +//#endif + +//=============================================================================== + +// forward declarations + +class GLMContext; +class CGLMShaderPair; +class CGLMShaderPairCache; + +// CGLMProgram can contain two flavors of the same program, one in assembler, one in GLSL. +// these flavors are pretty different in terms of the API's that are used to activate them - +// for example, assembler programs can just get bound to the context, whereas GLSL programs +// have to be linked. To some extent we try to hide that detail inside GLM. + +// for now, make CGLMProgram a container, it does not set policy or hold a preference as to which +// flavor you want to use. GLMContext has to handle that. + +enum EGLMProgramType +{ + kGLMVertexProgram, + kGLMFragmentProgram, + + kGLMNumProgramTypes +}; + +enum EGLMProgramLang +{ + kGLMARB, + kGLMGLSL, + + kGLMNumProgramLangs +}; + +struct GLMShaderDesc +{ + union + { + GLuint arb; // ARB program object name + GLhandleARB glsl; // GLSL shader object handle (void*) + } m_object; + + // these can change if shader text is edited + bool m_textPresent; // is this flavor(lang) of text present in the buffer? + int m_textOffset; // where is it + int m_textLength; // how big + + bool m_compiled; // has this text been through a compile attempt + bool m_valid; // and if so, was the compile successful + + int m_slowMark; // has it been flagged during a non native draw batch before. increment every time it's slow. + + int m_highWater; // count of vec4's in the major uniform array ("vc" on vs, "pc" on ps) + // written by dxabstract.... gross! + int m_VSHighWaterBone; // count of vec4's in the bone-specific uniform array (only valid for vertex shaders) +}; + +GLenum GLMProgTypeToARBEnum( EGLMProgramType type ); // map vert/frag to ARB asm bind target +GLenum GLMProgTypeToGLSLEnum( EGLMProgramType type ); // map vert/frag to ARB asm bind target + +#define GL_SHADER_PAIR_CACHE_STATS 0 + +class CGLMProgram +{ +public: + friend class CGLMShaderPairCache; + friend class CGLMShaderPair; + friend class GLMContext; // only GLMContext can make CGLMProgram objects + friend class GLMTester; + friend struct IDirect3D9; + friend struct IDirect3DDevice9; + + //=============================== + + // constructor is very light, it just makes one empty program object per flavor. + CGLMProgram( GLMContext *ctx, EGLMProgramType type ); + ~CGLMProgram( ); + + void SetProgramText ( char *text ); // import text to GLM object - invalidate any prev compiled program + void SetShaderName ( const char *name ); // only used for debugging/telemetry markup + + void CompileActiveSources ( void ); // compile only the flavors that were provided. + void Compile ( EGLMProgramLang lang ); + bool CheckValidity ( EGLMProgramLang lang ); + + void LogSlow ( EGLMProgramLang lang ); // detailed spew when called for first time; one liner or perhaps silence after that + + void GetLabelIndexCombo ( char *labelOut, int labelOutMaxChars, int *indexOut, int *comboOut ); + void GetComboIndexNameString ( char *stringOut, int stringOutMaxChars ); // mmmmmmmm-nnnnnnnn-filename + +#if GLMDEBUG + bool PollForChanges( void ); // check mirror for changes. + void ReloadStringFromEditable( void ); // populate m_string from editable item (react to change) + bool SyncWithEditable( void ); +#endif + + //=============================== + + // common stuff + + GLMContext *m_ctx; // link back to parent context + + EGLMProgramType m_type; // vertex or pixel + + uint m_nHashTag; // serial number for hashing + + char *m_text; // copy of text passed into constructor. Can change if editable shaders is enabled. + // note - it can contain multiple flavors, so use CGLMTextSectioner to scan it and locate them +#if GLMDEBUG + CGLMEditableTextItem *m_editable; // editable text item for debugging +#endif + + GLMShaderDesc m_descs[ kGLMNumProgramLangs ]; + + uint m_samplerMask; // (1<> 16 ); + // Apply half pixel offset to output vertices to account for the pixel center difference between D3D9 and OpenGL. + // We output vertices in clip space, which ranges from [-1,1], so 1.0/width in clip space transforms into .5/width in screenspace, see: "Viewports and Clipping (Direct3D 9)" in the DXSDK + float v[4] = { 1.0f / fWidth, 1.0f / fHeight, fWidth, fHeight }; + if ( m_locVertexScreenParams >= 0 ) + gGL->glUniform4fv( m_locVertexScreenParams, 1, v ); + } + + //=============================== + + // common stuff + + GLMContext *m_ctx; // link back to parent context + + CGLMProgram *m_vertexProg; + CGLMProgram *m_fragmentProg; + + GLhandleARB m_program; // linked program object + + // need meta data for attribs / samplers / params + // actually we only need it for samplers and params. + // attributes are hardwired. + + // vertex stage uniforms + GLint m_locVertexParams; // "vc" per dx9asmtogl2 convention + GLint m_locVertexBoneParams; // "vcbones" + GLint m_locVertexInteger0; // "i0" + + enum { cMaxVertexShaderBoolUniforms = 4, cMaxFragmentShaderBoolUniforms = 1 }; + + GLint m_locVertexBool[cMaxVertexShaderBoolUniforms]; // "b0", etc. + GLint m_locFragmentBool[cMaxFragmentShaderBoolUniforms]; // "fb0", etc. + bool m_bHasBoolOrIntUniforms; + + // fragment stage uniforms + GLint m_locFragmentParams; // "pc" per dx9asmtogl2 convention + + int m_NumUniformBufferParams[kGLMNumProgramTypes]; + GLint m_UniformBufferParams[kGLMNumProgramTypes][256]; + + GLint m_locFragmentFakeSRGBEnable; // "flSRGBWrite" - set to 1.0 to effect sRGB encoding on output + float m_fakeSRGBEnableValue; // shadow to avoid redundant sets of the m_locFragmentFakeSRGBEnable uniform + // init it to -1.0 at link or relink, so it will trip on any legit incoming value (0.0 or 1.0) + + GLint m_locSamplers[ GLM_SAMPLER_COUNT ]; // "sampler0 ... sampler1..." + + // other stuff + bool m_valid; // true on successful link + bool m_bCheckLinkStatus; + uint m_revision; // if this pair is relinked, bump this number. + + GLint m_locVertexScreenParams; // vcscreen + uint m_nScreenWidthHeight; + +}; + +//=============================================================================== + +// N-row, M-way associative cache with LRU per row. +// still needs some metric dump ability and some parameter tuning. +// extra credit would be to make an auto-tuner. + +struct CGLMPairCacheEntry +{ + long long m_lastMark; // a mark of zero means an empty entry + CGLMProgram *m_vertexProg; + CGLMProgram *m_fragmentProg; + uint m_extraKeyBits; + CGLMShaderPair *m_pair; +}; + +class CGLMShaderPairCache // cache for linked GLSL shader pairs +{ + +public: + +protected: + friend class CGLMShaderPair; + friend class CGLMProgram; + friend class GLMContext; + + //=============================== + + CGLMShaderPairCache( GLMContext *ctx ); + ~CGLMShaderPairCache( ); + + FORCEINLINE CGLMShaderPair *SelectShaderPair ( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits ); + void QueryShaderPair ( int index, GLMShaderPairInfo *infoOut ); + + // shoot down linked pairs that use the program in the arg + // return true if any had to be skipped due to conflict with currently bound pair + bool PurgePairsWithShader( CGLMProgram *prog ); + + // purge everything (when would GLM know how to do this ? at context destroy time, but any other times?) + // return true if any had to be skipped due to conflict with currently bound pair + bool Purge ( void ); + + // stats + void DumpStats ( void ); + + //=============================== + + FORCEINLINE uint HashRowIndex( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits ) const; + FORCEINLINE CGLMPairCacheEntry* HashRowPtr( uint hashRowIndex ) const; + + FORCEINLINE void HashRowProbe( CGLMPairCacheEntry *row, CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int &hitway, int &emptyway, int &oldestway ); + + CGLMShaderPair *SelectShaderPairInternal( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int rowIndex ); + //=============================== + + // common stuff + + GLMContext *m_ctx; // link back to parent context + + long long m_mark; + + uint m_rowsLg2; + uint m_rows; + uint m_rowsMask; + + uint m_waysLg2; + uint m_ways; + + uint m_entryCount; + + CGLMPairCacheEntry *m_entries; // array[ m_rows ][ m_ways ] + + uint *m_evictions; // array[ m_rows ]; + +#if GL_SHADER_PAIR_CACHE_STATS + uint *m_hits; // array[ m_rows ]; +#endif +}; + +FORCEINLINE uint CGLMShaderPairCache::HashRowIndex( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits ) const +{ + return ( vp->m_nHashTag + fp->m_nHashTag + extraKeyBits * 7 ) & m_rowsMask; +} + +FORCEINLINE CGLMPairCacheEntry* CGLMShaderPairCache::HashRowPtr( uint hashRowIndex ) const +{ + return &m_entries[ hashRowIndex * m_ways ]; +} + +FORCEINLINE void CGLMShaderPairCache::HashRowProbe( CGLMPairCacheEntry *row, CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int& hitway, int& emptyway, int& oldestway ) +{ + hitway = -1; + emptyway = -1; + oldestway = -1; + + // scan this row to see if the desired pair is present + CGLMPairCacheEntry *cursor = row; + long long oldestmark = 0xFFFFFFFFFFFFFFFFLL; + + for( uint way = 0; way < m_ways; ++way ) + { + if ( cursor->m_lastMark != 0 ) // occupied slot + { + // check if this is the oldest one on the row - only occupied slots are checked + if ( cursor->m_lastMark < oldestmark ) + { + oldestway = way; + oldestmark = cursor->m_lastMark; + } + + if ( ( cursor->m_vertexProg == vp ) && ( cursor->m_fragmentProg == fp ) && ( cursor->m_extraKeyBits == extraKeyBits ) ) // match? + { + // found it + hitway = way; + break; + } + } + else + { + // empty way, log it if first one seen + if (emptyway<0) + { + emptyway = way; + } + } + cursor++; + } +} + +FORCEINLINE CGLMShaderPair *CGLMShaderPairCache::SelectShaderPair( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits ) +{ + // select row where pair would be found if it exists + uint rowIndex = HashRowIndex( vp, fp, extraKeyBits ); + + CGLMPairCacheEntry *pCursor = HashRowPtr( rowIndex ); + + if ( ( pCursor->m_fragmentProg != fp ) || ( pCursor->m_vertexProg != vp ) || ( pCursor->m_extraKeyBits != extraKeyBits ) ) + { + CGLMPairCacheEntry *pLastCursor = pCursor + m_ways; + + ++pCursor; + + while ( pCursor != pLastCursor ) + { + if ( ( pCursor->m_fragmentProg == fp ) && ( pCursor->m_vertexProg == vp ) && ( pCursor->m_extraKeyBits == extraKeyBits ) ) // match? + break; + ++pCursor; + }; + + if ( pCursor == pLastCursor ) + return SelectShaderPairInternal( vp, fp, extraKeyBits, rowIndex ); + } + + // found it. mark it and return + pCursor->m_lastMark = m_mark++; + +#if GL_SHADER_PAIR_CACHE_STATS + // count the hit + m_hits[ rowIndex ] ++; +#endif + + return pCursor->m_pair; +} + +#endif diff --git a/public/togl/linuxwin/cglmquery.h b/public/togl/linuxwin/cglmquery.h new file mode 100644 index 0000000..168e3f7 --- /dev/null +++ b/public/togl/linuxwin/cglmquery.h @@ -0,0 +1,108 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// cglmquery.h +// GLMgr queries +// +//=============================================================================== + +#ifndef CGLMQUERY_H +#define CGLMQUERY_H + +#pragma once + +//=============================================================================== + +// forward declarations + +class GLMContext; +class CGLMQuery; + +//=============================================================================== + +enum EGLMQueryType +{ + EOcclusion, + EFence, + EGLMQueryCount +}; + +struct GLMQueryParams +{ + EGLMQueryType m_type; +}; + +class CGLMQuery +{ + // leave everything public til it's running +public: + friend class GLMContext; // only GLMContext can make CGLMTex objects + friend struct IDirect3DDevice9; + friend struct IDirect3DQuery9; + + GLMContext *m_ctx; // link back to parent context + GLMQueryParams m_params; // params created with + + GLuint m_name; // name of the query object per se - could be fence, could be query object ... NOT USED WITH GL_ARB_sync! +#ifdef HAVE_GL_ARB_SYNC + GLsync m_syncobj; // GL_ARB_sync object. NOT USED WITH GL_NV_fence or GL_APPLE_fence! +#else + GLuint m_syncobj; +#endif + + bool m_started; + bool m_stopped; + bool m_done; + + bool m_nullQuery; // was gl_nullqueries true at Start time - if so, continue to act like a null query through Stop/IsDone/Complete time + // restated - only Start should examine the convar. + static uint s_nTotalOcclusionQueryCreatesOrDeletes; + + CGLMQuery( GLMContext *ctx, GLMQueryParams *params ); + ~CGLMQuery( ); + + // for an occlusion query: + // Start = BeginQuery query-start goes into stream + // Stop = EndQuery query-end goes into stream - a fence is also set so we can probe for completion + // IsDone = TestFence use the added fence to ask if query-end has passed (i.e. will Complete block?) + // Complete = GetQueryObjectuivARB(uint id, enum pname, uint *params) - extract the sample count + + // for a fence query: + // Start = SetFence fence goes into command stream + // Stop = NOP fences are self finishing - no need to call Stop on a fence + // IsDone = TestFence ask if fence passed + // Complete = FinishFence + + void Start ( void ); + void Stop ( void ); + bool IsDone ( void ); + void Complete ( uint *result ); + + // accessors for the started/stopped state + bool IsStarted ( void ); + bool IsStopped ( void ); +}; + + +#endif diff --git a/public/togl/linuxwin/cglmtex.h b/public/togl/linuxwin/cglmtex.h new file mode 100644 index 0000000..90870a7 --- /dev/null +++ b/public/togl/linuxwin/cglmtex.h @@ -0,0 +1,536 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// cglmtex.h +// GLMgr textures +// +//=============================================================================== + +#ifndef CGLMTEX_H +#define CGLMTEX_H + +#pragma once + +#ifdef OSX +#include "glmgrbasics.h" +#endif +#include "tier1/utlhash.h" +#include "tier1/utlmap.h" + +//=============================================================================== + +// forward declarations + +class GLMContext; +class GLMTester; +class CGLMTexLayoutTable; +class CGLMTex; +class CGLMFBO; + +struct IDirect3DSurface9; + +#if GLMDEBUG +extern CGLMTex *g_pFirstCGMLTex; +#endif + +// For GL_EXT_texture_sRGB_decode +#ifndef GL_TEXTURE_SRGB_DECODE_EXT +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#endif + +#ifndef GL_DECODE_EXT +#define GL_DECODE_EXT 0x8A49 +#endif + +#ifndef GL_SKIP_DECODE_EXT +#define GL_SKIP_DECODE_EXT 0x8A4A +#endif + +//=============================================================================== + +struct GLMTexFormatDesc +{ + const char *m_formatSummary; // for debug visibility + + D3DFORMAT m_d3dFormat; // what D3D knows it as; see public/bitmap/imageformat.h + + GLenum m_glIntFormat; // GL internal format + GLenum m_glIntFormatSRGB; // internal format if SRGB flavor + GLenum m_glDataFormat; // GL data format + GLenum m_glDataType; // GL data type + + int m_chunkSize; // 1 or 4 - 4 is used for compressed textures + int m_bytesPerSquareChunk; // how many bytes for the smallest quantum (m_chunkSize x m_chunkSize) + // this description lets us calculate size cleanly without conditional logic for compression +}; +const GLMTexFormatDesc *GetFormatDesc( D3DFORMAT format ); + +//=============================================================================== + +// utility function for generating slabs of texels. mostly for test. +typedef struct +{ + // in + D3DFORMAT m_format; + void *m_dest; // dest address + int m_chunkCount; // square chunk count (single texels or compressed blocks) + int m_byteCountLimit; // caller expectation of max number of bytes to write out + float r,g,b,a; // color desired + + // out + int m_bytesWritten; +} GLMGenTexelParams; + +// return true if successful +bool GLMGenTexels( GLMGenTexelParams *params ); + + +//=============================================================================== + +struct GLMTexLayoutSlice +{ + int m_xSize,m_ySize,m_zSize; //texel dimensions of this slice + int m_storageOffset; //where in the storage slab does this slice live + int m_storageSize; //how much storage does this slice occupy +}; + +enum EGLMTexFlags +{ + kGLMTexMipped = 0x01, + kGLMTexMippedAuto = 0x02, + kGLMTexRenderable = 0x04, + kGLMTexIsStencil = 0x08, + kGLMTexIsDepth = 0x10, + kGLMTexSRGB = 0x20, + kGLMTexMultisampled = 0x40, // has an RBO backing it. Cannot combine with Mipped, MippedAuto. One slice maximum, only targeting GL_TEXTURE_2D. + // actually not 100% positive on the mipmapping, the RBO itself can't be mipped, but the resulting texture could + // have mipmaps generated. +}; + +//=============================================================================== + +struct GLMTexLayoutKey +{ + // input values: held const, these are the hash key for the form map + GLenum m_texGLTarget; // flavor of texture: GL_TEXTURE_2D, GL_TEXTURE_3D, GLTEXTURE_CUBE_MAP + D3DFORMAT m_texFormat; // D3D texel format + unsigned long m_texFlags; // mipped, autogen mips, render target, ... ? + unsigned long m_texSamples; // zero for a plain tex, 2/4/6/8 for "MSAA tex" (RBO backed) + int m_xSize,m_ySize,m_zSize; // size of base mip +}; + +bool LessFunc_GLMTexLayoutKey( const GLMTexLayoutKey &a, const GLMTexLayoutKey &b ); + +#define GLM_TEX_MAX_MIPS 14 +#define GLM_TEX_MAX_FACES 6 +#define GLM_TEX_MAX_SLICES (GLM_TEX_MAX_MIPS * GLM_TEX_MAX_FACES) + +#pragma warning( push ) +#pragma warning( disable : 4200 ) + +struct GLMTexLayout +{ + char *m_layoutSummary; // for debug visibility + + // const inputs used for hashing + GLMTexLayoutKey m_key; + + // refcount + int m_refCount; + + // derived values: + GLMTexFormatDesc *m_format; // format specific info + int m_mipCount; // derived by starying at base size and working down towards 1x1 + int m_faceCount; // 1 for 2d/3d, 6 for cubemap + int m_sliceCount; // product of faces and mips + int m_storageTotalSize; // size of storage slab required + + // slice array + GLMTexLayoutSlice m_slices[0]; // dynamically allocated 2-d array [faces][mips] +}; + +#pragma warning( pop ) + +class CGLMTexLayoutTable +{ +public: + CGLMTexLayoutTable(); + + GLMTexLayout *NewLayoutRef( GLMTexLayoutKey *pDesiredKey ); // pass in a pointer to layout key - receive ptr to completed layout + void DelLayoutRef( GLMTexLayout *layout ); // pass in pointer to completed layout. refcount is dropped. + + void DumpStats( void ); +protected: + CUtlMap< GLMTexLayoutKey, GLMTexLayout* > m_layoutMap; +}; + +//=============================================================================== + +// a sampler specifies desired state for drawing on a given sampler index +// this is the combination of a texture choice and a set of sampler parameters +// see http://msdn.microsoft.com/en-us/library/bb172602(VS.85).aspx + +struct GLMTexLockParams +{ + // input params which identify the slice of interest + CGLMTex *m_tex; + int m_face; + int m_mip; + + // identifies the region of the slice + GLMRegion m_region; + + // tells GLM to force re-read of the texels back from GL + // i.e. "I know I stepped on those texels with a draw or blit - the GLM copy is stale" + bool m_readback; +}; + +struct GLMTexLockDesc +{ + GLMTexLockParams m_req; // form of the lock request + + bool m_active; // set true at lock time. cleared at unlock time. + + int m_sliceIndex; // which slice in the layout + int m_sliceBaseOffset; // where is that in the texture data + int m_sliceRegionOffset; // offset to the start (lowest address corner) of the region requested +}; + +//=============================================================================== + +#define GLM_SAMPLER_COUNT 16 + +#define GLM_MAX_PIXEL_TEX_SAMPLERS 16 +#define GLM_MAX_VERTEX_TEX_SAMPLERS 0 +typedef CBitVec CTexBindMask; + +enum EGLMTexSliceFlag +{ + kSliceValid = 0x01, // slice has been teximage'd in whole at least once - set to 0 initially + kSliceStorageValid = 0x02, // if backing store is available, this slice's data is a valid copy - set to 0 initially + kSliceLocked = 0x04, // are one or more locks outstanding on this slice + kSliceFullyDirty = 0x08, // does the slice need to be fully downloaded at unlock time (disregard dirty rects) +}; + +//=============================================================================== + +#define GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS (2) +#define GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS (2) +#define GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS (2) +#define GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS (2) +#define GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS (4) +#define GLM_PACKED_SAMPLER_PARAMS_MAX_ANISO_BITS (5) +#define GLM_PACKED_SAMPLER_PARAMS_COMPARE_MODE_BITS (1) +#define GLM_PACKED_SAMPLER_PARAMS_SRGB_BITS (1) + +struct GLMTexPackedSamplingParams +{ + uint32 m_addressU : GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS; + uint32 m_addressV : GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS; + uint32 m_addressW : GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS; + + uint32 m_minFilter : GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS; + uint32 m_magFilter : GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS; + uint32 m_mipFilter : GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS; + + uint32 m_minLOD : GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS; + uint32 m_maxAniso : GLM_PACKED_SAMPLER_PARAMS_MAX_ANISO_BITS; + uint32 m_compareMode : GLM_PACKED_SAMPLER_PARAMS_COMPARE_MODE_BITS; + uint32 m_srgb : GLM_PACKED_SAMPLER_PARAMS_SRGB_BITS; + uint32 m_isValid : 1; +}; + +struct GLMTexSamplingParams +{ + union + { + GLMTexPackedSamplingParams m_packed; + uint32 m_bits; + }; + + uint32 m_borderColor; + + FORCEINLINE bool operator== (const GLMTexSamplingParams& rhs ) const + { + return ( m_bits == rhs.m_bits ) && ( m_borderColor == rhs.m_borderColor ); + } + + FORCEINLINE void SetToDefaults() + { + m_bits = 0; + m_borderColor = 0; + m_packed.m_addressU = D3DTADDRESS_WRAP; + m_packed.m_addressV = D3DTADDRESS_WRAP; + m_packed.m_addressW = D3DTADDRESS_WRAP; + m_packed.m_minFilter = D3DTEXF_POINT; + m_packed.m_magFilter = D3DTEXF_POINT; + m_packed.m_mipFilter = D3DTEXF_NONE; + m_packed.m_maxAniso = 1; + m_packed.m_compareMode = 0; + m_packed.m_isValid = true; + } + +#ifndef OSX + FORCEINLINE void SetToSamplerObject( GLuint nSamplerObject ) const + { + static const GLenum dxtogl_addressMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, (GLenum)-1 }; + static const GLenum dxtogl_magFilter[4] = { GL_NEAREST, GL_NEAREST, GL_LINEAR, GL_LINEAR }; + static const GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter]. + { + /* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT + /* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, + /* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, + /* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling + }; + + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_WRAP_S, dxtogl_addressMode[m_packed.m_addressU] ); + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_WRAP_T, dxtogl_addressMode[m_packed.m_addressV] ); + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_WRAP_R, dxtogl_addressMode[m_packed.m_addressW] ); + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MIN_FILTER, dxtogl_minFilter[m_packed.m_minFilter][m_packed.m_mipFilter] ); + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MAG_FILTER, dxtogl_magFilter[m_packed.m_magFilter] ); + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_packed.m_maxAniso ); + + float flBorderColor[4] = { 0, 0, 0, 0 }; + if ( m_borderColor ) + { + flBorderColor[0] = ((m_borderColor >> 16) & 0xFF) * (1.0f/255.0f); //R + flBorderColor[1] = ((m_borderColor >> 8) & 0xFF) * (1.0f/255.0f); //G + flBorderColor[2] = ((m_borderColor ) & 0xFF) * (1.0f/255.0f); //B + flBorderColor[3] = ((m_borderColor >> 24) & 0xFF) * (1.0f/255.0f); //A + } + gGL->glSamplerParameterfv( nSamplerObject, GL_TEXTURE_BORDER_COLOR, flBorderColor ); // <-- this crashes ATI's driver, remark it out + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MIN_LOD, m_packed.m_minLOD ); + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_COMPARE_MODE_ARB, m_packed.m_compareMode ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE ); + if ( m_packed.m_compareMode ) + { + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL ); + } + if ( gGL->m_bHave_GL_EXT_texture_sRGB_decode ) + { + gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_SRGB_DECODE_EXT, m_packed.m_srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT ); + } + } +#endif // !OSX + + inline void DeltaSetToTarget( GLenum target, const GLMTexSamplingParams &curState ) + { + static const GLenum dxtogl_addressMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, (GLenum)-1 }; + static const GLenum dxtogl_magFilter[4] = { GL_NEAREST, GL_NEAREST, GL_LINEAR, GL_LINEAR }; + static const GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter]. + { + /* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT + /* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, + /* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, + /* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling + }; + + if ( m_packed.m_addressU != curState.m_packed.m_addressU ) + { + gGL->glTexParameteri( target, GL_TEXTURE_WRAP_S, dxtogl_addressMode[m_packed.m_addressU] ); + } + + if ( m_packed.m_addressV != curState.m_packed.m_addressV ) + { + gGL->glTexParameteri( target, GL_TEXTURE_WRAP_T, dxtogl_addressMode[m_packed.m_addressV] ); + } + + if ( m_packed.m_addressW != curState.m_packed.m_addressW ) + { + gGL->glTexParameteri( target, GL_TEXTURE_WRAP_R, dxtogl_addressMode[m_packed.m_addressW] ); + } + + if ( ( m_packed.m_minFilter != curState.m_packed.m_minFilter ) || + ( m_packed.m_magFilter != curState.m_packed.m_magFilter ) || + ( m_packed.m_mipFilter != curState.m_packed.m_mipFilter ) || + ( m_packed.m_maxAniso != curState.m_packed.m_maxAniso ) ) + { + gGL->glTexParameteri( target, GL_TEXTURE_MIN_FILTER, dxtogl_minFilter[m_packed.m_minFilter][m_packed.m_mipFilter] ); + gGL->glTexParameteri( target, GL_TEXTURE_MAG_FILTER, dxtogl_magFilter[m_packed.m_magFilter] ); + gGL->glTexParameteri( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_packed.m_maxAniso ); + } + + if ( m_borderColor != curState.m_borderColor ) + { + float flBorderColor[4] = { 0, 0, 0, 0 }; + if ( m_borderColor ) + { + flBorderColor[0] = ((m_borderColor >> 16) & 0xFF) * (1.0f/255.0f); //R + flBorderColor[1] = ((m_borderColor >> 8) & 0xFF) * (1.0f/255.0f); //G + flBorderColor[2] = ((m_borderColor ) & 0xFF) * (1.0f/255.0f); //B + flBorderColor[3] = ((m_borderColor >> 24) & 0xFF) * (1.0f/255.0f); //A + } + + gGL->glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, flBorderColor ); // <-- this crashes ATI's driver, remark it out + } + + if ( m_packed.m_minLOD != curState.m_packed.m_minLOD ) + { + gGL->glTexParameteri( target, GL_TEXTURE_MIN_LOD, m_packed.m_minLOD ); + } + + if ( m_packed.m_compareMode != curState.m_packed.m_compareMode ) + { + gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_MODE_ARB, m_packed.m_compareMode ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE ); + if ( m_packed.m_compareMode ) + { + gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL ); + } + } + + if ( ( gGL->m_bHave_GL_EXT_texture_sRGB_decode ) && ( m_packed.m_srgb != curState.m_packed.m_srgb ) ) + { + gGL->glTexParameteri( target, GL_TEXTURE_SRGB_DECODE_EXT, m_packed.m_srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT ); + } + } + + inline void SetToTarget( GLenum target ) + { + static const GLenum dxtogl_addressMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, (GLenum)-1 }; + static const GLenum dxtogl_magFilter[4] = { GL_NEAREST, GL_NEAREST, GL_LINEAR, GL_LINEAR }; + static const GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter]. + { + /* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT + /* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, + /* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, + /* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling + }; + + gGL->glTexParameteri( target, GL_TEXTURE_WRAP_S, dxtogl_addressMode[m_packed.m_addressU] ); + gGL->glTexParameteri( target, GL_TEXTURE_WRAP_T, dxtogl_addressMode[m_packed.m_addressV] ); + gGL->glTexParameteri( target, GL_TEXTURE_WRAP_R, dxtogl_addressMode[m_packed.m_addressW] ); + gGL->glTexParameteri( target, GL_TEXTURE_MIN_FILTER, dxtogl_minFilter[m_packed.m_minFilter][m_packed.m_mipFilter] ); + gGL->glTexParameteri( target, GL_TEXTURE_MAG_FILTER, dxtogl_magFilter[m_packed.m_magFilter] ); + gGL->glTexParameteri( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_packed.m_maxAniso ); + + float flBorderColor[4] = { 0, 0, 0, 0 }; + if ( m_borderColor ) + { + flBorderColor[0] = ((m_borderColor >> 16) & 0xFF) * (1.0f/255.0f); //R + flBorderColor[1] = ((m_borderColor >> 8) & 0xFF) * (1.0f/255.0f); //G + flBorderColor[2] = ((m_borderColor ) & 0xFF) * (1.0f/255.0f); //B + flBorderColor[3] = ((m_borderColor >> 24) & 0xFF) * (1.0f/255.0f); //A + } + gGL->glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, flBorderColor ); // <-- this crashes ATI's driver, remark it out + gGL->glTexParameteri( target, GL_TEXTURE_MIN_LOD, m_packed.m_minLOD ); + gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_MODE_ARB, m_packed.m_compareMode ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE ); + if ( m_packed.m_compareMode ) + { + gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL ); + } + if ( gGL->m_bHave_GL_EXT_texture_sRGB_decode ) + { + gGL->glTexParameteri( target, GL_TEXTURE_SRGB_DECODE_EXT, m_packed.m_srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT ); + } + } +}; + +//=============================================================================== + +class CGLMTex +{ + +public: + + void Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut, int *zStrideOut ); + void Unlock( GLMTexLockParams *params ); + GLuint GetTexName() { return m_texName; } + +protected: + friend class GLMContext; // only GLMContext can make CGLMTex objects + friend class GLMTester; + friend class CGLMFBO; + + friend struct IDirect3DDevice9; + friend struct IDirect3DBaseTexture9; + friend struct IDirect3DTexture9; + friend struct IDirect3DSurface9; + friend struct IDirect3DCubeTexture9; + friend struct IDirect3DVolumeTexture9; + + CGLMTex( GLMContext *ctx, GLMTexLayout *layout, uint levels, const char *debugLabel = NULL ); + ~CGLMTex( ); + + int CalcSliceIndex( int face, int mip ); + void CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut ); + + void ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice=true ); + void WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice=true, bool noDataWrite=false ); + // last param lets us send NULL data ptr (only legal with uncompressed formats, beware) + // this helps out ResetSRGB. + +#if defined( OSX ) + void HandleSRGBMismatch( bool srgb, int &srgbFlipCount ); + void ResetSRGB( bool srgb, bool noDataWrite ); + // re-specify texture format to match desired sRGB form + // noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's +#endif + + bool IsRBODirty() const; + void ForceRBONonDirty(); + void ForceRBODirty(); + + // re-specify texture format to match desired sRGB form + // noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's + + GLuint m_texName; // name of this texture in the context + GLenum m_texGLTarget; + uint m_nSamplerType; // SAMPLER_2D, etc. + + GLMTexSamplingParams m_SamplingParams; + + GLMTexLayout *m_layout; // layout of texture (shared across all tex with same layout) + + uint m_nLastResolvedBatchCounter; + + int m_minActiveMip;//index of lowest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL. + int m_maxActiveMip;//index of highest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL. + + GLMContext *m_ctx; // link back to parent context + + + CGLMFBO *m_pBlitSrcFBO; + CGLMFBO *m_pBlitDstFBO; + GLuint m_rboName; // name of MSAA RBO backing the tex if MSAA enabled (or zero) + + int m_rtAttachCount; // how many RT's have this texture attached somewhere + + char *m_backing; // backing storage if available + + int m_lockCount; // lock reqs are stored in the GLMContext for tracking + + CUtlVector m_sliceFlags; + + char *m_debugLabel; // strdup() of debugLabel passed in, or NULL + + bool m_texClientStorage; // was CS selected for texture + bool m_texPreloaded; // has it been kicked into VRAM with GLMContext::PreloadTex yet + + int m_srgbFlipCount; +#if GLMDEBUG + CGLMTex *m_pPrevTex; + CGLMTex *m_pNextTex; +#endif +}; + +#endif diff --git a/public/togl/linuxwin/dxabstract.h b/public/togl/linuxwin/dxabstract.h new file mode 100644 index 0000000..b601e78 --- /dev/null +++ b/public/togl/linuxwin/dxabstract.h @@ -0,0 +1,1443 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// dxabstract.h +// +//================================================================================================== +#ifndef DXABSTRACT_H +#define DXABSTRACT_H + +#ifdef DX_TO_GL_ABSTRACTION + +#include "togl/rendermechanism.h" + +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier1/utlmap.h" + +// turn this on to get refcount logging from IUnknown +#define IUNKNOWN_ALLOC_SPEW 0 +#define IUNKNOWN_ALLOC_SPEW_MARK_ALL 0 + + +TOGL_INTERFACE void toglGetClientRect( VD3DHWND hWnd, RECT *destRect ); + + +struct TOGL_CLASS IUnknown +{ + int m_refcount[2]; + bool m_mark; + + IUnknown() + { + m_refcount[0] = 1; + m_refcount[1] = 0; + m_mark = (IUNKNOWN_ALLOC_SPEW_MARK_ALL != 0); // either all are marked, or only the ones that have SetMark(true) called on them + + #if IUNKNOWN_ALLOC_SPEW + if (m_mark) + { + GLMPRINTF(("-A- IUnew (%08x) refc -> (%d,%d) ",this,m_refcount[0],m_refcount[1])); + } + #endif + }; + + virtual ~IUnknown() + { + #if IUNKNOWN_ALLOC_SPEW + if (m_mark) + { + GLMPRINTF(("-A- IUdel (%08x) ",this )); + } + #endif + }; + + void AddRef( int which=0, char *comment = NULL ) + { + Assert( which >= 0 ); + Assert( which < 2 ); + m_refcount[which]++; + + #if IUNKNOWN_ALLOC_SPEW + if (m_mark) + { + GLMPRINTF(("-A- IUAddRef (%08x,%d) refc -> (%d,%d) [%s]",this,which,m_refcount[0],m_refcount[1],comment?comment:"...")) ; + if (!comment) + { + GLMPRINTF(("")) ; // place to hang a breakpoint + } + } + #endif + }; + + ULONG __stdcall Release( int which=0, char *comment = NULL ) + { + Assert( which >= 0 ); + Assert( which < 2 ); + + //int oldrefcs[2] = { m_refcount[0], m_refcount[1] }; + bool deleting = false; + + m_refcount[which]--; + if ( (!m_refcount[0]) && (!m_refcount[1]) ) + { + deleting = true; + } + + #if IUNKNOWN_ALLOC_SPEW + if (m_mark) + { + GLMPRINTF(("-A- IURelease (%08x,%d) refc -> (%d,%d) [%s] %s",this,which,m_refcount[0],m_refcount[1],comment?comment:"...",deleting?"->DELETING":"")); + if (!comment) + { + GLMPRINTF(("")) ; // place to hang a breakpoint + } + } + #endif + + if (deleting) + { + if (m_mark) + { + GLMPRINTF(("")) ; // place to hang a breakpoint + } + delete this; + return 0; + } + else + { + return m_refcount[0]; + } + }; + + void SetMark( bool markValue, char *comment=NULL ) + { + #if IUNKNOWN_ALLOC_SPEW + if (!m_mark && markValue) // leading edge detect + { + // print the same thing that the constructor would have printed if it had been marked from the beginning + // i.e. it's anticipated that callers asking for marking will do so right at create time + GLMPRINTF(("-A- IUSetMark (%08x) refc -> (%d,%d) (%s) ",this,m_refcount[0],m_refcount[1],comment?comment:"...")); + } + #endif + + m_mark = markValue; + } +}; + +// ------------------------------------------------------------------------------------------------------------------------------ // +// INTERFACES +// ------------------------------------------------------------------------------------------------------------------------------ // + +struct TOGL_CLASS IDirect3DResource9 : public IUnknown +{ + IDirect3DDevice9 *m_device; // parent device + D3DRESOURCETYPE m_restype; + + DWORD SetPriority(DWORD PriorityNew); +}; + +struct TOGL_CLASS IDirect3DBaseTexture9 : public IDirect3DResource9 // "A Texture.." +{ + D3DSURFACE_DESC m_descZero; // desc of top level. + CGLMTex *m_tex; // a CGLMTex can represent all forms of tex + + virtual ~IDirect3DBaseTexture9(); + D3DRESOURCETYPE TOGLMETHODCALLTYPE GetType(); + DWORD TOGLMETHODCALLTYPE GetLevelCount(); + HRESULT TOGLMETHODCALLTYPE GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc); +}; + +struct TOGL_CLASS IDirect3DTexture9 : public IDirect3DBaseTexture9 // "Texture 2D" +{ + IDirect3DSurface9 *m_surfZero; // surf of top level. + virtual ~IDirect3DTexture9(); + HRESULT TOGLMETHODCALLTYPE LockRect(UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags); + HRESULT TOGLMETHODCALLTYPE UnlockRect(UINT Level); + HRESULT TOGLMETHODCALLTYPE GetSurfaceLevel(UINT Level,IDirect3DSurface9** ppSurfaceLevel); +}; + +struct TOGL_CLASS IDirect3DCubeTexture9 : public IDirect3DBaseTexture9 // "Texture Cube Map" +{ + IDirect3DSurface9 *m_surfZero[6]; // surfs of top level. + virtual ~IDirect3DCubeTexture9(); + HRESULT TOGLMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface); + HRESULT TOGLMETHODCALLTYPE GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc); +}; + +struct TOGL_CLASS IDirect3DVolumeTexture9 : public IDirect3DBaseTexture9 // "Texture 3D" +{ + IDirect3DSurface9 *m_surfZero; // surf of top level. + D3DVOLUME_DESC m_volDescZero; // volume desc top level + virtual ~IDirect3DVolumeTexture9(); + HRESULT TOGLMETHODCALLTYPE LockBox(UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags); + HRESULT TOGLMETHODCALLTYPE UnlockBox(UINT Level); + HRESULT TOGLMETHODCALLTYPE GetLevelDesc( UINT level, D3DVOLUME_DESC *pDesc ); +}; + + +// for the moment, a "D3D surface" is modeled as a GLM tex, a face, and a mip. +// no Create method, these are filled in by the various create surface methods. + +struct TOGL_CLASS IDirect3DSurface9 : public IDirect3DResource9 +{ + virtual ~IDirect3DSurface9(); + HRESULT TOGLMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags); + HRESULT TOGLMETHODCALLTYPE UnlockRect(); + HRESULT TOGLMETHODCALLTYPE GetDesc(D3DSURFACE_DESC *pDesc); + + D3DSURFACE_DESC m_desc; + CGLMTex *m_tex; + int m_face; + int m_mip; +}; + +struct TOGL_CLASS IDirect3D9 : public IUnknown +{ + virtual ~IDirect3D9(); + + UINT TOGLMETHODCALLTYPE GetAdapterCount(); + + HRESULT TOGLMETHODCALLTYPE GetDeviceCaps (UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps); + HRESULT TOGLMETHODCALLTYPE GetAdapterIdentifier (UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier); + HRESULT TOGLMETHODCALLTYPE CheckDeviceFormat (UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat); + UINT TOGLMETHODCALLTYPE GetAdapterModeCount (UINT Adapter,D3DFORMAT Format); + HRESULT TOGLMETHODCALLTYPE EnumAdapterModes (UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode); + HRESULT TOGLMETHODCALLTYPE CheckDeviceType (UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed); + HRESULT TOGLMETHODCALLTYPE GetAdapterDisplayMode (UINT Adapter,D3DDISPLAYMODE* pMode); + HRESULT TOGLMETHODCALLTYPE CheckDepthStencilMatch (UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat); + HRESULT TOGLMETHODCALLTYPE CheckDeviceMultiSampleType (UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels); + + HRESULT TOGLMETHODCALLTYPE CreateDevice (UINT Adapter,D3DDEVTYPE DeviceType,VD3DHWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface); +}; + +struct TOGL_CLASS IDirect3DVertexDeclaration9 : public IUnknown +{ + IDirect3DDevice9 *m_device; + uint m_elemCount; + D3DVERTEXELEMENT9_GL m_elements[ MAX_D3DVERTEXELEMENTS ]; + + uint8 m_VertexAttribDescToStreamIndex[256]; + + virtual ~IDirect3DVertexDeclaration9(); +}; + +struct TOGL_CLASS IDirect3DQuery9 : public IDirect3DResource9 //was IUnknown +{ + D3DQUERYTYPE m_type; // D3DQUERYTYPE_OCCLUSION or D3DQUERYTYPE_EVENT + GLMContext *m_ctx; + CGLMQuery *m_query; + + uint m_nIssueStartThreadID, m_nIssueEndThreadID; + uint m_nIssueStartDrawCallIndex, m_nIssueEndDrawCallIndex; + uint m_nIssueStartFrameIndex, m_nIssueEndFrameIndex; + uint m_nIssueStartQueryCreationCounter, m_nIssueEndQueryCreationCounter; + + virtual ~IDirect3DQuery9(); + + HRESULT Issue(DWORD dwIssueFlags); + HRESULT GetData(void* pData,DWORD dwSize,DWORD dwGetDataFlags); +}; + +struct TOGL_CLASS IDirect3DVertexBuffer9 : public IDirect3DResource9 //was IUnknown +{ + GLMContext *m_ctx; + CGLMBuffer *m_vtxBuffer; + D3DVERTEXBUFFER_DESC m_vtxDesc; // to satisfy GetDesc + + virtual ~IDirect3DVertexBuffer9(); + HRESULT Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags); + HRESULT Unlock(); + void UnlockActualSize( uint nActualSize, const void *pActualData = NULL ); +}; + +struct TOGL_CLASS IDirect3DIndexBuffer9 : public IDirect3DResource9 //was IUnknown +{ + GLMContext *m_ctx; + CGLMBuffer *m_idxBuffer; + D3DINDEXBUFFER_DESC m_idxDesc; // to satisfy GetDesc + + virtual ~IDirect3DIndexBuffer9(); + + HRESULT Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags); + HRESULT Unlock(); + void UnlockActualSize( uint nActualSize, const void *pActualData = NULL ); + + HRESULT GetDesc(D3DINDEXBUFFER_DESC *pDesc); +}; + +struct TOGL_CLASS IDirect3DPixelShader9 : public IDirect3DResource9 //was IUnknown +{ + CGLMProgram *m_pixProgram; + uint m_pixHighWater; // count of active constant slots referenced by shader. + uint m_pixSamplerMask; // (1< CD3DMATRIXAllocator; + typedef class TOGL_CLASS CUtlVector CD3DMATRIXStack; +#else + typedef class CUtlMemory CD3DMATRIXAllocator; + typedef class CUtlVector CD3DMATRIXStack; +#endif + +struct TOGL_CLASS ID3DXMatrixStack //: public IUnknown +{ + int m_refcount[2]; + bool m_mark; + CD3DMATRIXStack m_stack; + int m_stackTop; // top of stack is at the highest index, this is that index. push increases, pop decreases. + + ID3DXMatrixStack(); + void AddRef( int which=0, char *comment = NULL ); + ULONG Release( int which=0, char *comment = NULL ); + + HRESULT Create( void ); + + D3DXMATRIX* GetTop(); + void Push(); + void Pop(); + void LoadIdentity(); + void LoadMatrix( const D3DXMATRIX *pMat ); + void MultMatrix( const D3DXMATRIX *pMat ); + void MultMatrixLocal( const D3DXMATRIX *pMat ); + HRESULT ScaleLocal(FLOAT x, FLOAT y, FLOAT z); + + // Left multiply the current matrix with the computed rotation + // matrix, counterclockwise about the given axis with the given angle. + // (rotation is about the local origin of the object) + HRESULT RotateAxisLocal(CONST D3DXVECTOR3* pV, FLOAT Angle); + + // Left multiply the current matrix with the computed translation + // matrix. (transformation is about the local origin of the object) + HRESULT TranslateLocal(FLOAT x, FLOAT y, FLOAT z); +}; + +typedef ID3DXMatrixStack* LPD3DXMATRIXSTACK; + +struct RenderTargetState_t +{ + void clear() { V_memset( this, 0, sizeof( *this ) ); } + + CGLMTex *m_pRenderTargets[4]; + CGLMTex *m_pDepthStencil; + + inline bool RefersTo( CGLMTex * pSurf ) const + { + for ( uint i = 0; i < 4; i++ ) + if ( m_pRenderTargets[i] == pSurf ) + return true; + + if ( m_pDepthStencil == pSurf ) + return true; + + return false; + } + + static inline bool LessFunc( const RenderTargetState_t &lhs, const RenderTargetState_t &rhs ) + { + COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uint32 ) ); + uint64 lhs0 = reinterpret_cast(lhs.m_pRenderTargets)[0]; + uint64 rhs0 = reinterpret_cast(rhs.m_pRenderTargets)[0]; + if ( lhs0 < rhs0 ) + return true; + else if ( lhs0 == rhs0 ) + { + uint64 lhs1 = reinterpret_cast(lhs.m_pRenderTargets)[1]; + uint64 rhs1 = reinterpret_cast(rhs.m_pRenderTargets)[1]; + if ( lhs1 < rhs1 ) + return true; + else if ( lhs1 == rhs1 ) + { + return lhs.m_pDepthStencil < rhs.m_pDepthStencil; + } + } + return false; + } + + inline bool operator < ( const RenderTargetState_t &rhs ) const + { + return LessFunc( *this, rhs ); + } +}; + +typedef CUtlMap< RenderTargetState_t, CGLMFBO *> CGLMFBOMap; + +class simple_bitmap; + +struct TOGL_CLASS IDirect3DDevice9 : public IUnknown +{ + friend class GLMContext; + friend struct IDirect3DBaseTexture9; + friend struct IDirect3DTexture9; + friend struct IDirect3DCubeTexture9; + friend struct IDirect3DVolumeTexture9; + friend struct IDirect3DSurface9; + friend struct IDirect3DVertexBuffer9; + friend struct IDirect3DIndexBuffer9; + friend struct IDirect3DPixelShader9; + friend struct IDirect3DVertexShader9; + friend struct IDirect3DQuery9; + friend struct IDirect3DVertexDeclaration9; + + IDirect3DDevice9(); + virtual ~IDirect3DDevice9(); + + // Create call invoked from IDirect3D9 + HRESULT TOGLMETHODCALLTYPE Create( IDirect3DDevice9Params *params ); + + // + // Basics + // + HRESULT TOGLMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS* pPresentationParameters); + HRESULT TOGLMETHODCALLTYPE SetViewport(CONST D3DVIEWPORT9* pViewport); + HRESULT TOGLMETHODCALLTYPE GetViewport(D3DVIEWPORT9* pViewport); + HRESULT TOGLMETHODCALLTYPE BeginScene(); + HRESULT TOGLMETHODCALLTYPE Clear(DWORD Count,CONST D3DRECT* pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil); + HRESULT TOGLMETHODCALLTYPE EndScene(); + HRESULT TOGLMETHODCALLTYPE Present(CONST RECT* pSourceRect,CONST RECT* pDestRect,VD3DHWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion); + + // textures + HRESULT TOGLMETHODCALLTYPE CreateTexture(UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DTexture9** ppTexture,VD3DHANDLE* pSharedHandle, char *debugLabel=NULL); + HRESULT TOGLMETHODCALLTYPE CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,VD3DHANDLE* pSharedHandle, char *debugLabel=NULL); + HRESULT TOGLMETHODCALLTYPE CreateVolumeTexture(UINT Width,UINT Height,UINT Depth,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DVolumeTexture9** ppVolumeTexture,VD3DHANDLE* pSharedHandle, char *debugLabel=NULL); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetTexture(DWORD Stage,IDirect3DBaseTexture9* pTexture); + HRESULT TOGLMETHODCALLTYPE SetTextureNonInline(DWORD Stage,IDirect3DBaseTexture9* pTexture); + + HRESULT TOGLMETHODCALLTYPE GetTexture(DWORD Stage,IDirect3DBaseTexture9** ppTexture); + + // render targets, color and depthstencil, surfaces, blit + HRESULT TOGLMETHODCALLTYPE CreateRenderTarget(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Lockable,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle, char *debugLabel=NULL); + HRESULT TOGLMETHODCALLTYPE SetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9* pRenderTarget); + HRESULT TOGLMETHODCALLTYPE GetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9** ppRenderTarget); + + HRESULT TOGLMETHODCALLTYPE CreateOffscreenPlainSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DPOOL Pool,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle); + + HRESULT TOGLMETHODCALLTYPE CreateDepthStencilSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Discard,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle); + HRESULT TOGLMETHODCALLTYPE SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil); + HRESULT TOGLMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface); + + HRESULT TOGLMETHODCALLTYPE GetRenderTargetData(IDirect3DSurface9* pRenderTarget,IDirect3DSurface9* pDestSurface); // ? is anyone using this ? + HRESULT TOGLMETHODCALLTYPE GetFrontBufferData(UINT iSwapChain,IDirect3DSurface9* pDestSurface); + HRESULT TOGLMETHODCALLTYPE StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect,IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect,D3DTEXTUREFILTERTYPE Filter); + + // pixel shaders + HRESULT TOGLMETHODCALLTYPE CreatePixelShader(CONST DWORD* pFunction,IDirect3DPixelShader9** ppShader, const char *pShaderName, char *debugLabel = NULL, const uint32 *pCentroidMask = NULL ); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetPixelShader(IDirect3DPixelShader9* pShader); + HRESULT TOGLMETHODCALLTYPE SetPixelShaderNonInline(IDirect3DPixelShader9* pShader); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount); + HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantFNonInline(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount); + + HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount); + HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount); + + // vertex shaders + HRESULT TOGLMETHODCALLTYPE CreateVertexShader(CONST DWORD* pFunction,IDirect3DVertexShader9** ppShader, const char *pShaderName, char *debugLabel = NULL); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShader(IDirect3DVertexShader9* pShader); + HRESULT TOGLMETHODCALLTYPE SetVertexShaderNonInline(IDirect3DVertexShader9* pShader); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount); + HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantFNonInline(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount); + HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantBNonInline(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount); + HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantINonInline(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount); + + // POSIX only - preheating for a specific vertex/pixel shader pair - trigger GLSL link inside GLM + HRESULT TOGLMETHODCALLTYPE LinkShaderPair( IDirect3DVertexShader9* vs, IDirect3DPixelShader9* ps ); + HRESULT TOGLMETHODCALLTYPE ValidateShaderPair( IDirect3DVertexShader9* vs, IDirect3DPixelShader9* ps ); + HRESULT TOGLMETHODCALLTYPE QueryShaderPair( int index, GLMShaderPairInfo *infoOut ); + + // vertex buffers + HRESULT TOGLMETHODCALLTYPE CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements,IDirect3DVertexDeclaration9** ppDecl); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl); + HRESULT TOGLMETHODCALLTYPE SetVertexDeclarationNonInline(IDirect3DVertexDeclaration9* pDecl); + + HRESULT TOGLMETHODCALLTYPE SetFVF(DWORD FVF); // we might not be using these ? + HRESULT TOGLMETHODCALLTYPE GetFVF(DWORD* pFVF); + + HRESULT CreateVertexBuffer(UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer9** ppVertexBuffer,VD3DHANDLE* pSharedHandle); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride); + HRESULT SetStreamSourceNonInline(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride); + + // index buffers + HRESULT TOGLMETHODCALLTYPE CreateIndexBuffer(UINT Length,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer9** ppIndexBuffer,VD3DHANDLE* pSharedHandle); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer9* pIndexData); + HRESULT TOGLMETHODCALLTYPE SetIndicesNonInline(IDirect3DIndexBuffer9* pIndexData); + + // State management. + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetRenderStateInline(D3DRENDERSTATETYPE State,DWORD Value); + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetRenderStateConstInline(D3DRENDERSTATETYPE State,DWORD Value); + HRESULT TOGLMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State,DWORD Value); + + FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetSamplerState(DWORD Sampler,D3DSAMPLERSTATETYPE Type,DWORD Value); + HRESULT TOGLMETHODCALLTYPE SetSamplerStateNonInline(DWORD Sampler,D3DSAMPLERSTATETYPE Type,DWORD Value); + + FORCEINLINE void TOGLMETHODCALLTYPE SetSamplerStates(DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW, DWORD MinFilter, DWORD MagFilter, DWORD MipFilter ); + void TOGLMETHODCALLTYPE SetSamplerStatesNonInline(DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW, DWORD MinFilter, DWORD MagFilter, DWORD MipFilter ); + +#ifdef OSX + // required for 10.6 support + HRESULT TOGLMETHODCALLTYPE FlushIndexBindings(void); // push index buffer (set index ptr) + HRESULT TOGLMETHODCALLTYPE FlushVertexBindings(uint baseVertexIndex); // push vertex streams (set attrib ptrs) +#endif + + // Draw. + HRESULT TOGLMETHODCALLTYPE DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount); + HRESULT TOGLMETHODCALLTYPE DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType,INT BaseVertexIndex,UINT MinVertexIndex,UINT NumVertices,UINT startIndex,UINT primCount); + HRESULT TOGLMETHODCALLTYPE DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertices,UINT PrimitiveCount,CONST void* pIndexData,D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride); + + // misc + BOOL TOGLMETHODCALLTYPE ShowCursor(BOOL bShow); + HRESULT TOGLMETHODCALLTYPE ValidateDevice(DWORD* pNumPasses); + HRESULT TOGLMETHODCALLTYPE SetMaterial(CONST D3DMATERIAL9* pMaterial); + HRESULT TOGLMETHODCALLTYPE LightEnable(DWORD Index,BOOL Enable); + HRESULT TOGLMETHODCALLTYPE SetScissorRect(CONST RECT* pRect); + HRESULT TOGLMETHODCALLTYPE CreateQuery(D3DQUERYTYPE Type,IDirect3DQuery9** ppQuery); + HRESULT TOGLMETHODCALLTYPE GetDeviceCaps(D3DCAPS9* pCaps); + HRESULT TOGLMETHODCALLTYPE TestCooperativeLevel(); + HRESULT TOGLMETHODCALLTYPE EvictManagedResources(); + HRESULT TOGLMETHODCALLTYPE SetLight(DWORD Index,CONST D3DLIGHT9*); + void TOGLMETHODCALLTYPE SetGammaRamp(UINT iSwapChain,DWORD Flags,CONST D3DGAMMARAMP* pRamp); + + + void TOGLMETHODCALLTYPE SaveGLState(); + void TOGLMETHODCALLTYPE RestoreGLState(); + + // Talk to JasonM about this one. It's tricky in GL. + HRESULT TOGLMETHODCALLTYPE SetClipPlane(DWORD Index,CONST float* pPlane); + + // + // + // **** FIXED FUNCTION STUFF - None of this stuff needs support in GL. + // + // + HRESULT TOGLMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix); + HRESULT TOGLMETHODCALLTYPE SetTextureStageState(DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value); + + void TOGLMETHODCALLTYPE AcquireThreadOwnership( ); + void TOGLMETHODCALLTYPE ReleaseThreadOwnership( ); + inline DWORD TOGLMETHODCALLTYPE GetCurrentOwnerThreadId() const { return m_ctx->m_nCurOwnerThreadId; } + + FORCEINLINE void TOGLMETHODCALLTYPE SetMaxUsedVertexShaderConstantsHint( uint nMaxReg ); + void TOGLMETHODCALLTYPE SetMaxUsedVertexShaderConstantsHintNonInline( uint nMaxReg ); + + void DumpStatsToConsole( const CCommand *pArgs ); + +#if GLMDEBUG + void DumpTextures( const CCommand *pArgs ); +#endif + +private: + IDirect3DDevice9( const IDirect3DDevice9& ); + IDirect3DDevice9& operator= ( const IDirect3DDevice9& ); + // Flushing changes to GL + void FlushClipPlaneEquation(); + void InitStates(); + void FullFlushStates(); + void UpdateBoundFBO(); + void ResetFBOMap(); + void ScrubFBOMap( CGLMTex *pTex ); + + // response to retired objects (when refcount goes to zero and they self-delete..) + void ReleasedVertexDeclaration( IDirect3DVertexDeclaration9 *pDecl ); + void ReleasedTexture( IDirect3DBaseTexture9 *baseTex ); // called from texture destructor - need to scrub samplers + void ReleasedCGLMTex( CGLMTex *pTex ); + void ReleasedSurface( IDirect3DSurface9 *surface ); // called from any surface destructor - need to scrub RT table if an RT + void ReleasedPixelShader( IDirect3DPixelShader9 *pixelShader ); // called from IDirect3DPixelShader9 destructor + void ReleasedVertexShader( IDirect3DVertexShader9 *vertexShader ); // called from IDirect3DVertexShader9 destructor + void ReleasedVertexBuffer( IDirect3DVertexBuffer9 *vertexBuffer ); // called from IDirect3DVertexBuffer9 destructor + void ReleasedIndexBuffer( IDirect3DIndexBuffer9 *indexBuffer ); // called from IDirect3DIndexBuffer9 destructor + void ReleasedQuery( IDirect3DQuery9 *query ); // called from IDirect3DQuery9 destructor + + // Member variables + + DWORD m_nValidMarker; +public: + IDirect3DDevice9Params m_params; // mirror of the creation inputs +private: + + // D3D flavor stuff + IDirect3DSurface9 *m_pRenderTargets[4]; + IDirect3DSurface9 *m_pDepthStencil; + + IDirect3DSurface9 *m_pDefaultColorSurface; // default color surface. + IDirect3DSurface9 *m_pDefaultDepthStencilSurface; // queried by GetDepthStencilSurface. + + IDirect3DVertexDeclaration9 *m_pVertDecl; // Set by SetVertexDeclaration... + D3DStreamDesc m_streams[ D3D_MAX_STREAMS ]; // Set by SetStreamSource.. + CGLMBuffer *m_vtx_buffers[ D3D_MAX_STREAMS ]; + CGLMBuffer *m_pDummy_vtx_buffer; + D3DIndexDesc m_indices; // Set by SetIndices.. + + IDirect3DVertexShader9 *m_vertexShader; // Set by SetVertexShader... + IDirect3DPixelShader9 *m_pixelShader; // Set by SetPixelShader... + + IDirect3DBaseTexture9 *m_textures[GLM_SAMPLER_COUNT]; // set by SetTexture... NULL if stage inactive + + // GLM flavor stuff + GLMContext *m_ctx; + CGLMFBOMap *m_pFBOs; + bool m_bFBODirty; + + struct ObjectStats_t + { + int m_nTotalFBOs; + int m_nTotalVertexShaders; + int m_nTotalPixelShaders; + int m_nTotalVertexDecls; + int m_nTotalIndexBuffers; + int m_nTotalVertexBuffers; + int m_nTotalRenderTargets; + int m_nTotalTextures; + int m_nTotalSurfaces; + int m_nTotalQueries; + + void clear() { V_memset( this, 0, sizeof(* this ) ); } + + ObjectStats_t &operator -= ( const ObjectStats_t &rhs ) + { + m_nTotalFBOs -= rhs.m_nTotalFBOs; + m_nTotalVertexShaders -= rhs.m_nTotalVertexShaders; + m_nTotalPixelShaders -= rhs.m_nTotalPixelShaders; + m_nTotalVertexDecls -= rhs.m_nTotalVertexDecls; + m_nTotalIndexBuffers -= rhs.m_nTotalIndexBuffers; + m_nTotalVertexBuffers -= rhs.m_nTotalVertexBuffers; + m_nTotalRenderTargets -= rhs.m_nTotalRenderTargets; + m_nTotalTextures -= rhs.m_nTotalTextures; + m_nTotalSurfaces -= rhs.m_nTotalSurfaces; + m_nTotalQueries -= m_nTotalQueries; + return *this; + } + }; + ObjectStats_t m_ObjectStats; + ObjectStats_t m_PrevObjectStats; + void PrintObjectStats( const ObjectStats_t &stats ); + + // GL state + struct + { + // render state buckets + GLAlphaTestEnable_t m_AlphaTestEnable; + GLAlphaTestFunc_t m_AlphaTestFunc; + + GLAlphaToCoverageEnable_t m_AlphaToCoverageEnable; + + GLDepthTestEnable_t m_DepthTestEnable; + GLDepthMask_t m_DepthMask; + GLDepthFunc_t m_DepthFunc; + + GLClipPlaneEnable_t m_ClipPlaneEnable[kGLMUserClipPlanes]; + GLClipPlaneEquation_t m_ClipPlaneEquation[kGLMUserClipPlanes]; + + GLColorMaskSingle_t m_ColorMaskSingle; + GLColorMaskMultiple_t m_ColorMaskMultiple; + + GLCullFaceEnable_t m_CullFaceEnable; + GLCullFrontFace_t m_CullFrontFace; + GLPolygonMode_t m_PolygonMode; + GLDepthBias_t m_DepthBias; + GLScissorEnable_t m_ScissorEnable; + GLScissorBox_t m_ScissorBox; + GLViewportBox_t m_ViewportBox; + GLViewportDepthRange_t m_ViewportDepthRange; + + GLBlendEnable_t m_BlendEnable; + GLBlendFactor_t m_BlendFactor; + GLBlendEquation_t m_BlendEquation; + GLBlendColor_t m_BlendColor; + GLBlendEnableSRGB_t m_BlendEnableSRGB; + + GLStencilTestEnable_t m_StencilTestEnable; + GLStencilFunc_t m_StencilFunc; + GLStencilOp_t m_StencilOp; + GLStencilWriteMask_t m_StencilWriteMask; + + GLClearColor_t m_ClearColor; + GLClearDepth_t m_ClearDepth; + GLClearStencil_t m_ClearStencil; + + bool m_FogEnable; // not really pushed to GL, just latched here + + // samplers + //GLMTexSamplingParams m_samplers[GLM_SAMPLER_COUNT]; + } gl; + +#if GL_BATCH_PERF_ANALYSIS + simple_bitmap *m_pBatch_vis_bitmap; + uint m_nBatchVisY; + uint m_nBatchVisFrameIndex, m_nBatchVisFileIdx; + uint m_nNumProgramChanges; + + uint m_nTotalD3DCalls; + double m_flTotalD3DTime; + uint m_nTotalGLCalls; + double m_flTotalGLTime; + uint m_nTotalPrims; + + uint m_nOverallProgramChanges; + uint m_nOverallDraws; + uint m_nOverallPrims; + uint m_nOverallD3DCalls; + double m_flOverallD3DTime; + uint m_nOverallGLCalls; + double m_flOverallGLTime; + + double m_flOverallPresentTime; + double m_flOverallPresentTimeSquared; + double m_flOverallSwapWindowTime; + double m_flOverallSwapWindowTimeSquared; + uint m_nOverallPresents; +#endif +}; + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetSamplerState( DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value ) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetSamplerStateNonInline( Sampler, Type, Value ); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + Assert( Sampler < GLM_SAMPLER_COUNT ); + + m_ctx->SetSamplerDirty( Sampler ); + + switch( Type ) + { + case D3DSAMP_ADDRESSU: + m_ctx->SetSamplerAddressU( Sampler, Value ); + break; + case D3DSAMP_ADDRESSV: + m_ctx->SetSamplerAddressV( Sampler, Value ); + break; + case D3DSAMP_ADDRESSW: + m_ctx->SetSamplerAddressW( Sampler, Value ); + break; + case D3DSAMP_BORDERCOLOR: + m_ctx->SetSamplerBorderColor( Sampler, Value ); + break; + case D3DSAMP_MAGFILTER: + m_ctx->SetSamplerMagFilter( Sampler, Value ); + break; + case D3DSAMP_MIPFILTER: + m_ctx->SetSamplerMipFilter( Sampler, Value ); + break; + case D3DSAMP_MINFILTER: + m_ctx->SetSamplerMinFilter( Sampler, Value ); + break; + case D3DSAMP_MIPMAPLODBIAS: + m_ctx->SetSamplerMipMapLODBias( Sampler, Value ); + break; + case D3DSAMP_MAXMIPLEVEL: + m_ctx->SetSamplerMaxMipLevel( Sampler, Value); + break; + case D3DSAMP_MAXANISOTROPY: + m_ctx->SetSamplerMaxAnisotropy( Sampler, Value); + break; + case D3DSAMP_SRGBTEXTURE: + //m_samplers[ Sampler ].m_srgb = Value; + m_ctx->SetSamplerSRGBTexture(Sampler, Value); + break; + case D3DSAMP_SHADOWFILTER: + m_ctx->SetShadowFilter(Sampler, Value); + break; + + default: DXABSTRACT_BREAK_ON_ERROR(); break; + } + return S_OK; +#endif +} + +FORCEINLINE void TOGLMETHODCALLTYPE IDirect3DDevice9::SetSamplerStates( + DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW, + DWORD MinFilter, DWORD MagFilter, DWORD MipFilter ) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + SetSamplerStatesNonInline( Sampler, AddressU, AddressV, AddressW, MinFilter, MagFilter, MipFilter ); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + Assert( Sampler < GLM_SAMPLER_COUNT); + + m_ctx->SetSamplerDirty( Sampler ); + + m_ctx->SetSamplerStates( Sampler, AddressU, AddressV, AddressW, MinFilter, MagFilter, MipFilter ); +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetTexture(DWORD Stage,IDirect3DBaseTexture9* pTexture) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetTextureNonInline( Stage, pTexture ); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + Assert( Stage < GLM_SAMPLER_COUNT ); + m_textures[Stage] = pTexture; + m_ctx->SetSamplerTex( Stage, pTexture ? pTexture->m_tex : NULL ); + return S_OK; +#endif +} + +inline GLenum D3DCompareFuncToGL( DWORD function ) +{ + switch ( function ) + { + case D3DCMP_NEVER : return GL_NEVER; // Always fail the test. + case D3DCMP_LESS : return GL_LESS; // Accept the new pixel if its value is less than the value of the current pixel. + case D3DCMP_EQUAL : return GL_EQUAL; // Accept the new pixel if its value equals the value of the current pixel. + case D3DCMP_LESSEQUAL : return GL_LEQUAL; // Accept the new pixel if its value is less than or equal to the value of the current pixel. ** + case D3DCMP_GREATER : return GL_GREATER; // Accept the new pixel if its value is greater than the value of the current pixel. + case D3DCMP_NOTEQUAL : return GL_NOTEQUAL; // Accept the new pixel if its value does not equal the value of the current pixel. + case D3DCMP_GREATEREQUAL: return GL_GEQUAL; // Accept the new pixel if its value is greater than or equal to the value of the current pixel. + case D3DCMP_ALWAYS : return GL_ALWAYS; // Always pass the test. + default : DXABSTRACT_BREAK_ON_ERROR(); return 0xFFFFFFFF; + } +} + +FORCEINLINE GLenum D3DBlendOperationToGL( DWORD operation ) +{ + switch (operation) + { + case D3DBLENDOP_ADD : return GL_FUNC_ADD; // The result is the destination added to the source. Result = Source + Destination + case D3DBLENDOP_SUBTRACT : return GL_FUNC_SUBTRACT; // The result is the destination subtracted from to the source. Result = Source - Destination + case D3DBLENDOP_REVSUBTRACT : return GL_FUNC_REVERSE_SUBTRACT; // The result is the source subtracted from the destination. Result = Destination - Source + case D3DBLENDOP_MIN : return GL_MIN; // The result is the minimum of the source and destination. Result = MIN(Source, Destination) + case D3DBLENDOP_MAX : return GL_MAX; // The result is the maximum of the source and destination. Result = MAX(Source, Destination) + default: + DXABSTRACT_BREAK_ON_ERROR(); + return 0xFFFFFFFF; + break; + } +} + +FORCEINLINE GLenum D3DBlendFactorToGL( DWORD equation ) +{ + switch (equation) + { + case D3DBLEND_ZERO : return GL_ZERO; // Blend factor is (0, 0, 0, 0). + case D3DBLEND_ONE : return GL_ONE; // Blend factor is (1, 1, 1, 1). + case D3DBLEND_SRCCOLOR : return GL_SRC_COLOR; // Blend factor is (Rs, Gs, Bs, As). + case D3DBLEND_INVSRCCOLOR : return GL_ONE_MINUS_SRC_COLOR; // Blend factor is (1 - Rs, 1 - Gs, 1 - Bs, 1 - As). + case D3DBLEND_SRCALPHA : return GL_SRC_ALPHA; // Blend factor is (As, As, As, As). + case D3DBLEND_INVSRCALPHA : return GL_ONE_MINUS_SRC_ALPHA; // Blend factor is ( 1 - As, 1 - As, 1 - As, 1 - As). + case D3DBLEND_DESTALPHA : return GL_DST_ALPHA; // Blend factor is (Ad Ad Ad Ad). + case D3DBLEND_INVDESTALPHA : return GL_ONE_MINUS_DST_ALPHA; // Blend factor is (1 - Ad 1 - Ad 1 - Ad 1 - Ad). + case D3DBLEND_DESTCOLOR : return GL_DST_COLOR; // Blend factor is (Rd, Gd, Bd, Ad). + case D3DBLEND_INVDESTCOLOR : return GL_ONE_MINUS_DST_COLOR; // Blend factor is (1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad). + case D3DBLEND_SRCALPHASAT : return GL_SRC_ALPHA_SATURATE; // Blend factor is (f, f, f, 1); where f = min(As, 1 - Ad). + + /* + // these are weird.... break if we hit them + case D3DBLEND_BOTHSRCALPHA : Assert(0); return GL_ZERO; // Obsolete. Starting with DirectX 6, you can achieve the same effect by setting the source and destination blend factors to D3DBLEND_SRCALPHA and D3DBLEND_INVSRCALPHA in separate calls. + case D3DBLEND_BOTHINVSRCALPHA: Assert(0); return GL_ZERO; // Source blend factor is (1 - As, 1 - As, 1 - As, 1 - As), and destination blend factor is (As, As, As, As); the destination blend selection is overridden. This blend mode is supported only for the D3DRS_SRCBLEND render state. + case D3DBLEND_BLENDFACTOR : Assert(0); return GL_ZERO; // Constant color blending factor used by the frame-buffer blender. This blend mode is supported only if D3DPBLENDCAPS_BLENDFACTOR is set in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9. + + dxabstract.h has not heard of these, so let them hit the debugger if they come through + case D3DBLEND_INVBLENDFACTOR: //Inverted constant color-blending factor used by the frame-buffer blender. This blend mode is supported only if the D3DPBLENDCAPS_BLENDFACTOR bit is set in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9. + case D3DBLEND_SRCCOLOR2: // Blend factor is (PSOutColor[1]r, PSOutColor[1]g, PSOutColor[1]b, not used). This flag is available in Direct3D 9Ex only. + case D3DBLEND_INVSRCCOLOR2: // Blend factor is (1 - PSOutColor[1]r, 1 - PSOutColor[1]g, 1 - PSOutColor[1]b, not used)). This flag is available in Direct3D 9Ex only. + */ + default: + DXABSTRACT_BREAK_ON_ERROR(); + return 0xFFFFFFFF; + break; + } +} + + +FORCEINLINE GLenum D3DStencilOpToGL( DWORD operation ) +{ + switch( operation ) + { + case D3DSTENCILOP_KEEP : return GL_KEEP; + case D3DSTENCILOP_ZERO : return GL_ZERO; + case D3DSTENCILOP_REPLACE : return GL_REPLACE; + case D3DSTENCILOP_INCRSAT : return GL_INCR; + case D3DSTENCILOP_DECRSAT : return GL_DECR; + case D3DSTENCILOP_INVERT : return GL_INVERT; + case D3DSTENCILOP_INCR : return GL_INCR_WRAP_EXT; + case D3DSTENCILOP_DECR : return GL_DECR_WRAP_EXT; + default : DXABSTRACT_BREAK_ON_ERROR(); return 0xFFFFFFFF; + } +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetRenderStateInline( D3DRENDERSTATETYPE State, DWORD Value ) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetRenderState( State, Value ); +#else + TOGL_NULL_DEVICE_CHECK; + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + + switch (State) + { + case D3DRS_ZENABLE: // kGLDepthTestEnable + { + gl.m_DepthTestEnable.enable = Value; + m_ctx->WriteDepthTestEnable( &gl.m_DepthTestEnable ); + break; + } + case D3DRS_ZWRITEENABLE: // kGLDepthMask + { + gl.m_DepthMask.mask = Value; + m_ctx->WriteDepthMask( &gl.m_DepthMask ); + break; + } + case D3DRS_ZFUNC: + { + // kGLDepthFunc + GLenum func = D3DCompareFuncToGL( Value ); + gl.m_DepthFunc.func = func; + m_ctx->WriteDepthFunc( &gl.m_DepthFunc ); + break; + } + case D3DRS_COLORWRITEENABLE: // kGLColorMaskSingle + { + gl.m_ColorMaskSingle.r = ((Value & D3DCOLORWRITEENABLE_RED) != 0) ? 0xFF : 0x00; + gl.m_ColorMaskSingle.g = ((Value & D3DCOLORWRITEENABLE_GREEN)!= 0) ? 0xFF : 0x00; + gl.m_ColorMaskSingle.b = ((Value & D3DCOLORWRITEENABLE_BLUE) != 0) ? 0xFF : 0x00; + gl.m_ColorMaskSingle.a = ((Value & D3DCOLORWRITEENABLE_ALPHA)!= 0) ? 0xFF : 0x00; + m_ctx->WriteColorMaskSingle( &gl.m_ColorMaskSingle ); + break; + } + case D3DRS_CULLMODE: // kGLCullFaceEnable / kGLCullFrontFace + { + switch (Value) + { + case D3DCULL_NONE: + { + gl.m_CullFaceEnable.enable = false; + gl.m_CullFrontFace.value = GL_CCW; //doesn't matter + + m_ctx->WriteCullFaceEnable( &gl.m_CullFaceEnable ); + m_ctx->WriteCullFrontFace( &gl.m_CullFrontFace ); + break; + } + + case D3DCULL_CW: + { + gl.m_CullFaceEnable.enable = true; + gl.m_CullFrontFace.value = GL_CW; //origGL_CCW; + + m_ctx->WriteCullFaceEnable( &gl.m_CullFaceEnable ); + m_ctx->WriteCullFrontFace( &gl.m_CullFrontFace ); + break; + } + case D3DCULL_CCW: + { + gl.m_CullFaceEnable.enable = true; + gl.m_CullFrontFace.value = GL_CCW; //origGL_CW; + + m_ctx->WriteCullFaceEnable( &gl.m_CullFaceEnable ); + m_ctx->WriteCullFrontFace( &gl.m_CullFrontFace ); + break; + } + default: + { + DXABSTRACT_BREAK_ON_ERROR(); + break; + } + } + break; + } + //-------------------------------------------------------------------------------------------- alphablend stuff + case D3DRS_ALPHABLENDENABLE: // kGLBlendEnable + { + gl.m_BlendEnable.enable = Value; + m_ctx->WriteBlendEnable( &gl.m_BlendEnable ); + break; + } + case D3DRS_BLENDOP: // kGLBlendEquation // D3D blend-op ==> GL blend equation + { + GLenum equation = D3DBlendOperationToGL( Value ); + gl.m_BlendEquation.equation = equation; + m_ctx->WriteBlendEquation( &gl.m_BlendEquation ); + break; + } + case D3DRS_SRCBLEND: // kGLBlendFactor // D3D blend-factor ==> GL blend factor + case D3DRS_DESTBLEND: // kGLBlendFactor + { + GLenum factor = D3DBlendFactorToGL( Value ); + + if (State==D3DRS_SRCBLEND) + { + gl.m_BlendFactor.srcfactor = factor; + } + else + { + gl.m_BlendFactor.dstfactor = factor; + } + m_ctx->WriteBlendFactor( &gl.m_BlendFactor ); + break; + } + case D3DRS_SRGBWRITEENABLE: // kGLBlendEnableSRGB + { + gl.m_BlendEnableSRGB.enable = Value; + m_ctx->WriteBlendEnableSRGB( &gl.m_BlendEnableSRGB ); + break; + } + //-------------------------------------------------------------------------------------------- alphatest stuff + case D3DRS_ALPHATESTENABLE: + { + gl.m_AlphaTestEnable.enable = Value; + m_ctx->WriteAlphaTestEnable( &gl.m_AlphaTestEnable ); + break; + } + case D3DRS_ALPHAREF: + { + gl.m_AlphaTestFunc.ref = Value / 255.0f; + m_ctx->WriteAlphaTestFunc( &gl.m_AlphaTestFunc ); + break; + } + case D3DRS_ALPHAFUNC: + { + GLenum func = D3DCompareFuncToGL( Value );; + gl.m_AlphaTestFunc.func = func; + m_ctx->WriteAlphaTestFunc( &gl.m_AlphaTestFunc ); + break; + } + //-------------------------------------------------------------------------------------------- stencil stuff + case D3DRS_STENCILENABLE: // GLStencilTestEnable_t + { + gl.m_StencilTestEnable.enable = Value; + m_ctx->WriteStencilTestEnable( &gl.m_StencilTestEnable ); + break; + } + case D3DRS_STENCILFAIL: // GLStencilOp_t "what do you do if stencil test fails" + { + GLenum stencilop = D3DStencilOpToGL( Value ); + gl.m_StencilOp.sfail = stencilop; + + m_ctx->WriteStencilOp( &gl.m_StencilOp,0 ); + m_ctx->WriteStencilOp( &gl.m_StencilOp,1 ); // ********* need to recheck this + break; + } + case D3DRS_STENCILZFAIL: // GLStencilOp_t "what do you do if stencil test passes *but* depth test fails, if depth test happened" + { + GLenum stencilop = D3DStencilOpToGL( Value ); + gl.m_StencilOp.dpfail = stencilop; + + m_ctx->WriteStencilOp( &gl.m_StencilOp,0 ); + m_ctx->WriteStencilOp( &gl.m_StencilOp,1 ); // ********* need to recheck this + break; + } + case D3DRS_STENCILPASS: // GLStencilOp_t "what do you do if stencil test and depth test both pass" + { + GLenum stencilop = D3DStencilOpToGL( Value ); + gl.m_StencilOp.dppass = stencilop; + + m_ctx->WriteStencilOp( &gl.m_StencilOp,0 ); + m_ctx->WriteStencilOp( &gl.m_StencilOp,1 ); // ********* need to recheck this + break; + } + case D3DRS_STENCILFUNC: // GLStencilFunc_t + { + GLenum stencilfunc = D3DCompareFuncToGL( Value ); + gl.m_StencilFunc.frontfunc = gl.m_StencilFunc.backfunc = stencilfunc; + + m_ctx->WriteStencilFunc( &gl.m_StencilFunc ); + break; + } + case D3DRS_STENCILREF: // GLStencilFunc_t + { + gl.m_StencilFunc.ref = Value; + m_ctx->WriteStencilFunc( &gl.m_StencilFunc ); + break; + } + case D3DRS_STENCILMASK: // GLStencilFunc_t + { + gl.m_StencilFunc.mask = Value; + m_ctx->WriteStencilFunc( &gl.m_StencilFunc ); + break; + } + case D3DRS_STENCILWRITEMASK: // GLStencilWriteMask_t + { + gl.m_StencilWriteMask.mask = Value; + m_ctx->WriteStencilWriteMask( &gl.m_StencilWriteMask ); + break; + } + case D3DRS_FOGENABLE: // none of these are implemented yet... erk + { + gl.m_FogEnable = (Value != 0); + GLMPRINTF(("-D- fogenable = %d",Value )); + break; + } + case D3DRS_SCISSORTESTENABLE: // kGLScissorEnable + { + gl.m_ScissorEnable.enable = Value; + m_ctx->WriteScissorEnable( &gl.m_ScissorEnable ); + break; + } + case D3DRS_DEPTHBIAS: // kGLDepthBias + { + // the value in the dword is actually a float + float fvalue = *(float*)&Value; + gl.m_DepthBias.units = fvalue; + + m_ctx->WriteDepthBias( &gl.m_DepthBias ); + break; + } + // good ref on these: http://aras-p.info/blog/2008/06/12/depth-bias-and-the-power-of-deceiving-yourself/ + case D3DRS_SLOPESCALEDEPTHBIAS: + { + // the value in the dword is actually a float + float fvalue = *(float*)&Value; + gl.m_DepthBias.factor = fvalue; + + m_ctx->WriteDepthBias( &gl.m_DepthBias ); + break; + } + // Alpha to coverage + case D3DRS_ADAPTIVETESS_Y: + { + gl.m_AlphaToCoverageEnable.enable = Value; + m_ctx->WriteAlphaToCoverageEnable( &gl.m_AlphaToCoverageEnable ); + break; + } + case D3DRS_CLIPPLANEENABLE: // kGLClipPlaneEnable + { + // d3d packs all the enables into one word. + // we break that out so we don't do N glEnable calls to sync - + // GLM is tracking one unique enable per plane. + for( int i=0; iWriteClipPlaneEnable( &gl.m_ClipPlaneEnable[x], x ); + break; + } + //-------------------------------------------------------------------------------------------- polygon/fill mode + case D3DRS_FILLMODE: + { + GLuint mode = 0; + switch(Value) + { + case D3DFILL_POINT: mode = GL_POINT; break; + case D3DFILL_WIREFRAME: mode = GL_LINE; break; + case D3DFILL_SOLID: mode = GL_FILL; break; + default: DXABSTRACT_BREAK_ON_ERROR(); break; + } + gl.m_PolygonMode.values[0] = gl.m_PolygonMode.values[1] = mode; + m_ctx->WritePolygonMode( &gl.m_PolygonMode ); + break; + } + } + + return S_OK; +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetRenderStateConstInline( D3DRENDERSTATETYPE State, DWORD Value ) +{ + // State is a compile time constant - luckily no need to do anything special to get the compiler to optimize this case. + return SetRenderStateInline( State, Value ); +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9* pIndexData) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetIndicesNonInline( pIndexData ); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + // just latch it. + m_indices.m_idxBuffer = pIndexData; + return S_OK; +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetStreamSourceNonInline( StreamNumber, pStreamData, OffsetInBytes, Stride ); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + Assert( StreamNumber < D3D_MAX_STREAMS ); + Assert( ( Stride & 3 ) == 0 ); // we support non-DWORD aligned strides, but on some drivers (like AMD's) perf goes off a cliff + + // perfectly legal to see a vertex buffer of NULL get passed in here. + // so we need an array to track these. + // OK, we are being given the stride, we don't need to calc it.. + + GLMPRINTF(("-X- IDirect3DDevice9::SetStreamSource setting stream #%d to D3D buf %p (GL name %d); offset %d, stride %d", StreamNumber, pStreamData, (pStreamData) ? pStreamData->m_vtxBuffer->m_name: -1, OffsetInBytes, Stride)); + + if ( !pStreamData ) + { + OffsetInBytes = 0; + Stride = 0; + + m_vtx_buffers[ StreamNumber ] = m_pDummy_vtx_buffer; + } + else + { + // We do not support strides of 0 + Assert( Stride > 0 ); + m_vtx_buffers[ StreamNumber ] = pStreamData->m_vtxBuffer; + } + + m_streams[ StreamNumber ].m_vtxBuffer = pStreamData; + m_streams[ StreamNumber ].m_offset = OffsetInBytes; + m_streams[ StreamNumber ].m_stride = Stride; + + return S_OK; +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount) // groups of 4 floats! +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetVertexShaderConstantFNonInline( StartRegister, pConstantData, Vector4fCount ); +#else + TOGL_NULL_DEVICE_CHECK; + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetProgramParametersF( kGLMVertexProgram, StartRegister, (float *)pConstantData, Vector4fCount ); + return S_OK; +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetVertexShaderConstantBNonInline( StartRegister, pConstantData, BoolCount ); +#else + TOGL_NULL_DEVICE_CHECK; + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetProgramParametersB( kGLMVertexProgram, StartRegister, (int *)pConstantData, BoolCount ); + return S_OK; +#endif +} + +FORCEINLINE HRESULT IDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount) // groups of 4 ints! +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetVertexShaderConstantINonInline( StartRegister, pConstantData, Vector4iCount ); +#else + TOGL_NULL_DEVICE_CHECK; + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetProgramParametersI( kGLMVertexProgram, StartRegister, (int *)pConstantData, Vector4iCount ); + return S_OK; +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetPixelShaderConstantFNonInline(StartRegister, pConstantData, Vector4fCount); +#else + TOGL_NULL_DEVICE_CHECK; + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetProgramParametersF( kGLMFragmentProgram, StartRegister, (float *)pConstantData, Vector4fCount ); + return S_OK; +#endif +} + +HRESULT IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9* pShader) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetVertexShaderNonInline(pShader); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetVertexProgram( pShader ? pShader->m_vtxProgram : NULL ); + m_vertexShader = pShader; + return S_OK; +#endif +} + +FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9* pShader) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetPixelShaderNonInline(pShader); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetFragmentProgram( pShader ? pShader->m_pixProgram : NULL ); + m_pixelShader = pShader; + return S_OK; +#endif +} + +FORCEINLINE HRESULT IDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetVertexDeclarationNonInline(pDecl); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_pVertDecl = pDecl; + return S_OK; +#endif +} + +FORCEINLINE void IDirect3DDevice9::SetMaxUsedVertexShaderConstantsHint( uint nMaxReg ) +{ +#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS + return SetMaxUsedVertexShaderConstantsHintNonInline( nMaxReg ); +#else + Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() ); + m_ctx->SetMaxUsedVertexShaderConstantsHint( nMaxReg ); +#endif +} + +// ------------------------------------------------------------------------------------------------------------------------------ // +// D3DX +// ------------------------------------------------------------------------------------------------------------------------------ // +struct ID3DXInclude +{ + virtual HRESULT Open(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes); + virtual HRESULT Close(LPCVOID pData); +}; +typedef ID3DXInclude* LPD3DXINCLUDE; + + +struct TOGL_CLASS ID3DXBuffer : public IUnknown +{ + void* GetBufferPointer(); + DWORD GetBufferSize(); +}; + +typedef ID3DXBuffer* LPD3DXBUFFER; + +class ID3DXConstantTable : public IUnknown +{ +}; +typedef ID3DXConstantTable* LPD3DXCONSTANTTABLE; + +TOGL_INTERFACE const char* D3DXGetPixelShaderProfile( IDirect3DDevice9 *pDevice ); + +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixMultiply( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2 ); +TOGL_INTERFACE D3DXVECTOR3* D3DXVec3TransformCoord( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DXMATRIX *pM ); + +TOGL_INTERFACE HRESULT D3DXCreateMatrixStack( DWORD Flags, LPD3DXMATRIXSTACK* ppStack); +TOGL_INTERFACE void D3DXMatrixIdentity( D3DXMATRIX * ); + +TOGL_INTERFACE D3DXINLINE D3DXVECTOR3* D3DXVec3Subtract( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ + pOut->x = pV1->x - pV2->x; + pOut->y = pV1->y - pV2->y; + pOut->z = pV1->z - pV2->z; + return pOut; +} + +TOGL_INTERFACE D3DXINLINE D3DXVECTOR3* D3DXVec3Cross( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ + D3DXVECTOR3 v; + + v.x = pV1->y * pV2->z - pV1->z * pV2->y; + v.y = pV1->z * pV2->x - pV1->x * pV2->z; + v.z = pV1->x * pV2->y - pV1->y * pV2->x; + + *pOut = v; + return pOut; +} + +TOGL_INTERFACE D3DXINLINE FLOAT D3DXVec3Dot( CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ + return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z; +} + +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixInverse( D3DXMATRIX *pOut, FLOAT *pDeterminant, CONST D3DXMATRIX *pM ); + +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixTranspose( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM ); + +TOGL_INTERFACE D3DXPLANE* D3DXPlaneNormalize( D3DXPLANE *pOut, CONST D3DXPLANE *pP); + +TOGL_INTERFACE D3DXVECTOR4* D3DXVec4Transform( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, CONST D3DXMATRIX *pM ); + + +TOGL_INTERFACE D3DXVECTOR4* D3DXVec4Normalize( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV ); + +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z ); + +// Build an ortho projection matrix. (right-handed) +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixOrthoOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn,FLOAT zf ); + +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixPerspectiveRH( D3DXMATRIX *pOut, FLOAT w, FLOAT h, FLOAT zn, FLOAT zf ); + +TOGL_INTERFACE D3DXMATRIX* D3DXMatrixPerspectiveOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn, FLOAT zf ); + +// Transform a plane by a matrix. The vector (a,b,c) must be normal. +// M should be the inverse transpose of the transformation desired. +TOGL_INTERFACE D3DXPLANE* D3DXPlaneTransform( D3DXPLANE *pOut, CONST D3DXPLANE *pP, CONST D3DXMATRIX *pM ); + +TOGL_INTERFACE IDirect3D9 *Direct3DCreate9(UINT SDKVersion); + +TOGL_INTERFACE void D3DPERF_SetOptions( DWORD dwOptions ); + +TOGL_INTERFACE HRESULT D3DXCompileShader( + LPCSTR pSrcData, + UINT SrcDataLen, + CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, + LPCSTR pFunctionName, + LPCSTR pProfile, + DWORD Flags, + LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs, + LPD3DXCONSTANTTABLE* ppConstantTable); + +// fake D3D usage constant for SRGB tex creation +#define D3DUSAGE_TEXTURE_SRGB (0x80000000L) + +#else + + //USE_ACTUAL_DX + #ifndef WIN32 + #error sorry man + #endif + + #ifdef _X360 + #include "d3d9.h" + #include "d3dx9.h" + #else + #include + #include "../../dx9sdk/include/d3d9.h" + #include "../../dx9sdk/include/d3dx9.h" + #endif + typedef HWND VD3DHWND; + +#endif // DX_TO_GL_ABSTRACTION + +#endif // DXABSTRACT_H diff --git a/public/togl/linuxwin/dxabstract_types.h b/public/togl/linuxwin/dxabstract_types.h new file mode 100644 index 0000000..9713ec7 --- /dev/null +++ b/public/togl/linuxwin/dxabstract_types.h @@ -0,0 +1,1748 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// dxabstract_types.h +// +//================================================================================================== +#ifndef DXABSTRACT_TYPES_H +#define DXABSTRACT_TYPES_H + +#pragma once + +#if GL_BATCH_PERF_ANALYSIS + class simple_bitmap; +#endif + +struct IUnknown; +struct IDirect3D9; +struct IDirect3DDevice9; +struct IDirect3DResource9; +struct IDirect3DBaseTexture9; +struct IDirect3DTexture9; +struct IDirect3DCubeTexture9; +struct IDirect3DVolumeTexture9; +struct IDirect3DSurface9; +struct IDirect3DVertexDeclaration9; +struct IDirect3DQuery9; +struct IDirect3DVertexBuffer9; +struct IDirect3DIndexBuffer9; +struct IDirect3DPixelShader9; +struct IDirect3DVertexShader9; +struct IDirect3DDevice9Params; + +class GLMContext; +struct GLMRect; +struct GLMShaderPairInfo; +class CGLMBuffer; +class CGLMQuery; +class CGLMTex; +class CGLMProgram; +class CGLMFBO; + +#ifdef TOGL_DLL_EXPORT + #define TOGL_INTERFACE DLL_EXPORT + #define TOGL_OVERLOAD DLL_GLOBAL_EXPORT + #define TOGL_CLASS DLL_CLASS_EXPORT + #define TOGL_GLOBAL DLL_GLOBAL_EXPORT +#else + #define TOGL_INTERFACE DLL_IMPORT + #define TOGL_OVERLOAD DLL_GLOBAL_IMPORT + #define TOGL_CLASS DLL_CLASS_IMPORT + #define TOGL_GLOBAL DLL_GLOBAL_IMPORT +#endif + +#define TOGLMETHODCALLTYPE __stdcall +//#define TOGLMETHODCALLTYPE + +#define DXABSTRACT_BREAK_ON_ERROR() DebuggerBreak() + +typedef void* VD3DHWND; +typedef void* VD3DHANDLE; + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) + +// +// +// Stuff that would be in windows.h +// +// +#if !defined(_WINNT_) + + typedef int INT; + typedef unsigned long ULONG; + typedef long LONG; + typedef float FLOAT; + typedef unsigned int DWORD; + typedef unsigned short WORD; + typedef long long LONGLONG; + typedef unsigned int UINT; + typedef long HRESULT; + typedef unsigned char BYTE; + #define CONST const + + #if defined(POSIX) + typedef size_t ULONG_PTR; + #else + typedef unsigned long ULONG_PTR; + #endif + + typedef ULONG_PTR SIZE_T; + + typedef const char* LPCSTR; + typedef char* LPSTR; + typedef DWORD* LPDWORD; + + #define ZeroMemory RtlZeroMemory + #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + + typedef union _LARGE_INTEGER + { + struct + { + DWORD LowPart; + LONG HighPart; + }; + struct + { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; + } LARGE_INTEGER; + + typedef struct _GUID + { + bool operator==( const struct _GUID &other ) const; + + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[ 8 ]; + } GUID; + + typedef struct _RECT + { + int left; + int top; + int right; + int bottom; + } RECT; + + typedef struct tagPOINT + { + LONG x; + LONG y; + } POINT, *PPOINT, *LPPOINT; + + typedef struct _MEMORYSTATUS + { + DWORD dwLength; + SIZE_T dwTotalPhys; + } MEMORYSTATUS, *LPMEMORYSTATUS; + + typedef DWORD COLORREF; + #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) + + #define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + + #define S_FALSE ((HRESULT)0x00000001L) + #define S_OK 0 + #define E_FAIL ((HRESULT)0x80004005L) + #define E_OUTOFMEMORY ((HRESULT)0x8007000EL) + + #define FAILED(hr) ((HRESULT)(hr) < 0) + #define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) + + struct RGNDATA + { + }; + + typedef const void* LPCVOID; +#endif + +//----------------------------------------------------------------------------- + +typedef enum _D3DFORMAT D3DFORMAT; + +#define D3DSI_OPCODE_MASK 0x0000FFFF +#define D3DSP_TEXTURETYPE_MASK 0x78000000 + +#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L +#define D3DSP_DCL_USAGE_MASK 0x0000000f + +#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000 +#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16 + +// Comparison for dynamic conditional instruction opcodes (i.e. if, breakc) +typedef enum _D3DSHADER_COMPARISON +{ + // < = > + D3DSPC_RESERVED0= 0, // 0 0 0 + D3DSPC_GT = 1, // 0 0 1 + D3DSPC_EQ = 2, // 0 1 0 + D3DSPC_GE = 3, // 0 1 1 + D3DSPC_LT = 4, // 1 0 0 + D3DSPC_NE = 5, // 1 0 1 + D3DSPC_LE = 6, // 1 1 0 + D3DSPC_RESERVED1= 7 // 1 1 1 +} D3DSHADER_COMPARISON; + + +// Comparison is part of instruction opcode token: +#define D3DSHADER_COMPARISON_SHIFT D3DSP_OPCODESPECIFICCONTROL_SHIFT +#define D3DSHADER_COMPARISON_MASK (0x7<>8)&0xFF) +#define D3DSHADER_VERSION_MINOR(_Version) (((_Version)>>0)&0xFF) + +#define D3DSHADER_ADDRESSMODE_SHIFT 13 +#define D3DSHADER_ADDRESSMODE_MASK (1 << D3DSHADER_ADDRESSMODE_SHIFT) + +#define D3DPS_END() 0x0000FFFF + +// ps_2_0 texld controls +#define D3DSI_TEXLD_PROJECT (0x01 << D3DSP_OPCODESPECIFICCONTROL_SHIFT) +#define D3DSI_TEXLD_BIAS (0x02 << D3DSP_OPCODESPECIFICCONTROL_SHIFT) + + +// destination parameter write mask +#define D3DSP_WRITEMASK_0 0x00010000 // Component 0 (X;Red) +#define D3DSP_WRITEMASK_1 0x00020000 // Component 1 (Y;Green) +#define D3DSP_WRITEMASK_2 0x00040000 // Component 2 (Z;Blue) +#define D3DSP_WRITEMASK_3 0x00080000 // Component 3 (W;Alpha) +#define D3DSP_WRITEMASK_ALL 0x000F0000 // All Components + +#define D3DVS_SWIZZLE_SHIFT 16 +#define D3DVS_SWIZZLE_MASK 0x00FF0000 + +// The following bits define where to take component X from: + +#define D3DVS_X_X (0 << D3DVS_SWIZZLE_SHIFT) +#define D3DVS_X_Y (1 << D3DVS_SWIZZLE_SHIFT) +#define D3DVS_X_Z (2 << D3DVS_SWIZZLE_SHIFT) +#define D3DVS_X_W (3 << D3DVS_SWIZZLE_SHIFT) + +// The following bits define where to take component Y from: + +#define D3DVS_Y_X (0 << (D3DVS_SWIZZLE_SHIFT + 2)) +#define D3DVS_Y_Y (1 << (D3DVS_SWIZZLE_SHIFT + 2)) +#define D3DVS_Y_Z (2 << (D3DVS_SWIZZLE_SHIFT + 2)) +#define D3DVS_Y_W (3 << (D3DVS_SWIZZLE_SHIFT + 2)) + +// The following bits define where to take component Z from: + +#define D3DVS_Z_X (0 << (D3DVS_SWIZZLE_SHIFT + 4)) +#define D3DVS_Z_Y (1 << (D3DVS_SWIZZLE_SHIFT + 4)) +#define D3DVS_Z_Z (2 << (D3DVS_SWIZZLE_SHIFT + 4)) +#define D3DVS_Z_W (3 << (D3DVS_SWIZZLE_SHIFT + 4)) + +// The following bits define where to take component W from: + +#define D3DVS_W_X (0 << (D3DVS_SWIZZLE_SHIFT + 6)) +#define D3DVS_W_Y (1 << (D3DVS_SWIZZLE_SHIFT + 6)) +#define D3DVS_W_Z (2 << (D3DVS_SWIZZLE_SHIFT + 6)) +#define D3DVS_W_W (3 << (D3DVS_SWIZZLE_SHIFT + 6)) + +// source parameter modifiers +#define D3DSP_SRCMOD_SHIFT 24 +#define D3DSP_SRCMOD_MASK 0x0F000000 + +// ------------------------------------------------------------------------------------------------------------------------------ // +// ENUMS +// ------------------------------------------------------------------------------------------------------------------------------ // + +typedef enum _D3DSHADER_PARAM_SRCMOD_TYPE +{ + D3DSPSM_NONE = 0<= 2.0 + + + D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0 + D3DDECLTYPE_SHORT2N = 9, // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1) + D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0) + D3DDECLTYPE_USHORT2N = 11, // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1) + D3DDECLTYPE_USHORT4N = 12, // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0) + D3DDECLTYPE_UDEC3 = 13, // 3D unsigned 10 10 10 format expanded to (value, value, value, 1) + D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1) + D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1) + D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values + D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused. +} D3DDECLTYPE; + +typedef enum _D3DDECLMETHOD +{ + D3DDECLMETHOD_DEFAULT = 0, + D3DDECLMETHOD_PARTIALU, + D3DDECLMETHOD_PARTIALV, + D3DDECLMETHOD_CROSSUV, // Normal + D3DDECLMETHOD_UV, + D3DDECLMETHOD_LOOKUP, // Lookup a displacement map + D3DDECLMETHOD_LOOKUPPRESAMPLED, // Lookup a pre-sampled displacement map +} D3DDECLMETHOD; + +typedef enum _D3DDECLUSAGE +{ + D3DDECLUSAGE_POSITION = 0, + D3DDECLUSAGE_BLENDWEIGHT = 1, + D3DDECLUSAGE_BLENDINDICES = 2, + D3DDECLUSAGE_NORMAL = 3, + D3DDECLUSAGE_PSIZE = 4, + D3DDECLUSAGE_TEXCOORD = 5, + D3DDECLUSAGE_TANGENT = 6, + D3DDECLUSAGE_BINORMAL = 7, + D3DDECLUSAGE_TESSFACTOR = 8, + D3DDECLUSAGE_PLUGH = 9, // mystery value + D3DDECLUSAGE_COLOR = 10, + D3DDECLUSAGE_FOG = 11, + D3DDECLUSAGE_DEPTH = 12, + D3DDECLUSAGE_SAMPLE = 13, +} D3DDECLUSAGE; + +typedef enum _D3DPRIMITIVETYPE +{ + D3DPT_POINTLIST = 1, + D3DPT_LINELIST = 2, + D3DPT_TRIANGLELIST = 4, + D3DPT_TRIANGLESTRIP = 5, + D3DPT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DPRIMITIVETYPE; + +// ------------------------------------------------------------------------------------------------------------------------------ // +// STRUCTURES +// ------------------------------------------------------------------------------------------------------------------------------ // + +typedef struct TOGL_CLASS D3DXPLANE +{ + float& operator[]( int i ); + bool operator==( const D3DXPLANE &o ); + bool operator!=( const D3DXPLANE &o ); + operator float*(); + operator const float*() const; + + float a, b, c, d; +} D3DXPLANE; + +typedef enum _D3DVERTEXBLENDFLAGS +{ + D3DVBF_DISABLE = 0, // Disable vertex blending + D3DVBF_1WEIGHTS = 1, // 2 matrix blending + D3DVBF_2WEIGHTS = 2, // 3 matrix blending + D3DVBF_3WEIGHTS = 3, // 4 matrix blending + D3DVBF_TWEENING = 255, // blending using D3DRS_TWEENFACTOR + D3DVBF_0WEIGHTS = 256, // one matrix is used with weight 1.0 + D3DVBF_FORCE_DWORD = 0x7fffffff, // force 32-bit size enum +} D3DVERTEXBLENDFLAGS; + +typedef struct _D3DINDEXBUFFER_DESC +{ + D3DFORMAT Format; + D3DRESOURCETYPE Type; + DWORD Usage; + D3DPOOL Pool; + UINT Size; +} D3DINDEXBUFFER_DESC; + +typedef struct _D3DVERTEXELEMENT9 +{ + WORD Stream; // Stream index + WORD Offset; // Offset in the stream in bytes + BYTE Type; // Data type + BYTE Method; // Processing method + BYTE Usage; // Semantics + BYTE UsageIndex; // Semantic index +} D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9; + + +#define MAX_DEVICE_IDENTIFIER_STRING 512 +typedef struct _D3DADAPTER_IDENTIFIER9 +{ + char Driver[MAX_DEVICE_IDENTIFIER_STRING]; + char Description[MAX_DEVICE_IDENTIFIER_STRING]; + char DeviceName[32]; /* Device name for GDI (ex. \\.\DISPLAY1) */ + + LARGE_INTEGER DriverVersion; /* Defined for 32 bit components */ + + DWORD VendorId; + DWORD DeviceId; + DWORD SubSysId; + DWORD Revision; + DWORD VideoMemory; + +} D3DADAPTER_IDENTIFIER9; + +typedef struct _D3DCOLORVALUE +{ + float r; + float g; + float b; + float a; +} D3DCOLORVALUE; + +typedef struct _D3DMATERIAL9 +{ + D3DCOLORVALUE Diffuse; /* Diffuse color RGBA */ + D3DCOLORVALUE Ambient; /* Ambient color RGB */ + D3DCOLORVALUE Specular; /* Specular 'shininess' */ + D3DCOLORVALUE Emissive; /* Emissive color RGB */ + float Power; /* Sharpness if specular highlight */ +} D3DMATERIAL9; + +typedef struct _D3DVOLUME_DESC +{ + D3DFORMAT Format; + D3DRESOURCETYPE Type; + DWORD Usage; + D3DPOOL Pool; + + UINT Width; + UINT Height; + UINT Depth; +} D3DVOLUME_DESC; + +typedef struct _D3DVIEWPORT9 +{ + DWORD X; + DWORD Y; /* Viewport Top left */ + DWORD Width; + DWORD Height; /* Viewport Dimensions */ + float MinZ; /* Min/max of clip Volume */ + float MaxZ; +} D3DVIEWPORT9; + +typedef struct _D3DPSHADERCAPS2_0 +{ + DWORD Caps; + INT DynamicFlowControlDepth; + INT NumTemps; + INT StaticFlowControlDepth; + INT NumInstructionSlots; +} D3DPSHADERCAPS2_0; + +typedef struct _D3DCAPS9 +{ + /* Device Info */ + D3DDEVTYPE DeviceType; + + /* Caps from DX7 Draw */ + DWORD Caps; + DWORD Caps2; + + /* Cursor Caps */ + DWORD CursorCaps; + + /* 3D Device Caps */ + DWORD DevCaps; + + DWORD PrimitiveMiscCaps; + DWORD RasterCaps; + DWORD TextureCaps; + DWORD TextureFilterCaps; // D3DPTFILTERCAPS for IDirect3DTexture9's + + DWORD MaxTextureWidth, MaxTextureHeight; + DWORD MaxVolumeExtent; + + DWORD MaxTextureAspectRatio; + DWORD MaxAnisotropy; + + DWORD TextureOpCaps; + DWORD MaxTextureBlendStages; + DWORD MaxSimultaneousTextures; + + DWORD VertexProcessingCaps; + DWORD MaxActiveLights; + DWORD MaxUserClipPlanes; + DWORD MaxVertexBlendMatrices; + DWORD MaxVertexBlendMatrixIndex; + + DWORD MaxPrimitiveCount; // max number of primitives per DrawPrimitive call + DWORD MaxStreams; + + DWORD VertexShaderVersion; + DWORD MaxVertexShaderConst; // number of vertex shader constant registers + + DWORD PixelShaderVersion; + + // Here are the DX9 specific ones + DWORD DevCaps2; + D3DPSHADERCAPS2_0 PS20Caps; + + DWORD NumSimultaneousRTs; // Will be at least 1 + DWORD MaxVertexShader30InstructionSlots; + DWORD MaxPixelShader30InstructionSlots; + + // only on Posix/GL + DWORD FakeSRGBWrite; // 1 for parts which can't support SRGB writes due to driver issues - 0 for others + DWORD MixedSizeTargets; // 1 for parts which can mix attachment sizes (RT's color vs depth) + DWORD CanDoSRGBReadFromRTs; // 0 when we're on Leopard, 1 when on Snow Leopard +} D3DCAPS9; + +typedef struct _D3DDISPLAYMODE +{ + UINT Width; + UINT Height; + UINT RefreshRate; + D3DFORMAT Format; +} D3DDISPLAYMODE; + +typedef struct _D3DGAMMARAMP +{ + WORD red [256]; + WORD green[256]; + WORD blue [256]; +} D3DGAMMARAMP; + + +/* Resize Optional Parameters */ +typedef struct _D3DPRESENT_PARAMETERS_ +{ + UINT BackBufferWidth; + UINT BackBufferHeight; + D3DFORMAT BackBufferFormat; + UINT BackBufferCount; + + D3DMULTISAMPLE_TYPE MultiSampleType; + DWORD MultiSampleQuality; + + D3DSWAPEFFECT SwapEffect; + VD3DHWND hDeviceWindow; + BOOL Windowed; + BOOL EnableAutoDepthStencil; + D3DFORMAT AutoDepthStencilFormat; + DWORD Flags; + + /* FullScreen_RefreshRateInHz must be zero for Windowed mode */ + UINT FullScreen_RefreshRateInHz; + UINT PresentationInterval; +} D3DPRESENT_PARAMETERS; + +typedef struct _D3DDEVICE_CREATION_PARAMETERS +{ + UINT AdapterOrdinal; + D3DDEVTYPE DeviceType; + VD3DHWND hFocusWindow; + DWORD BehaviorFlags; +} D3DDEVICE_CREATION_PARAMETERS; + +/* Structures for LockBox */ +typedef struct _D3DBOX +{ + UINT Left; + UINT Top; + UINT Right; + UINT Bottom; + UINT Front; + UINT Back; +} D3DBOX; + +typedef struct _D3DLOCKED_BOX +{ + INT RowPitch; + INT SlicePitch; + void* pBits; +} D3DLOCKED_BOX; + +typedef struct _D3DSURFACE_DESC +{ + D3DFORMAT Format; + D3DRESOURCETYPE Type; + DWORD Usage; + D3DPOOL Pool; + + D3DMULTISAMPLE_TYPE MultiSampleType; + DWORD MultiSampleQuality; + UINT Width; + UINT Height; +} D3DSURFACE_DESC; + + +typedef struct _D3DLOCKED_RECT +{ + INT Pitch; + void* pBits; +} D3DLOCKED_RECT; + + +typedef struct _D3DRASTER_STATUS +{ + BOOL InVBlank; + UINT ScanLine; +} D3DRASTER_STATUS; + +typedef enum _D3DLIGHTTYPE +{ + D3DLIGHT_POINT = 1, + D3DLIGHT_SPOT = 2, + D3DLIGHT_DIRECTIONAL = 3, + D3DLIGHT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DLIGHTTYPE; + +typedef struct TOGL_CLASS _D3DVECTOR +{ + float x; + float y; + float z; +} D3DVECTOR; + +class TOGL_CLASS D3DXVECTOR2 +{ +public: + operator FLOAT* (); + operator CONST FLOAT* () const; + + float x,y; +}; + +class TOGL_CLASS D3DXVECTOR3 : public D3DVECTOR +{ +public: + D3DXVECTOR3() {} + D3DXVECTOR3( float a, float b, float c ); + operator FLOAT* (); + operator CONST FLOAT* () const; +}; + +typedef enum _D3DXINCLUDE_TYPE +{ + D3DXINC_LOCAL, + + // force 32-bit size enum + D3DXINC_FORCE_DWORD = 0x7fffffff + +} D3DXINCLUDE_TYPE; + +typedef struct _D3DLIGHT9 +{ + D3DLIGHTTYPE Type; /* Type of light source */ + D3DCOLORVALUE Diffuse; /* Diffuse color of light */ + D3DCOLORVALUE Specular; /* Specular color of light */ + D3DCOLORVALUE Ambient; /* Ambient color of light */ + D3DVECTOR Position; /* Position in world space */ + D3DVECTOR Direction; /* Direction in world space */ + float Range; /* Cutoff range */ + float Falloff; /* Falloff */ + float Attenuation0; /* Constant attenuation */ + float Attenuation1; /* Linear attenuation */ + float Attenuation2; /* Quadratic attenuation */ + float Theta; /* Inner angle of spotlight cone */ + float Phi; /* Outer angle of spotlight cone */ +} D3DLIGHT9; + +class TOGL_CLASS D3DXVECTOR4 +{ +public: + D3DXVECTOR4() {} + D3DXVECTOR4( float a, float b, float c, float d ); + + float x,y,z,w; +}; + +//---------------------------------------------------------------------------- +// D3DXMACRO: +// ---------- +// Preprocessor macro definition. The application pass in a NULL-terminated +// array of this structure to various D3DX APIs. This enables the application +// to #define tokens at runtime, before the file is parsed. +//---------------------------------------------------------------------------- + +typedef struct _D3DXMACRO +{ + LPCSTR Name; + LPCSTR Definition; + +} D3DXMACRO, *LPD3DXMACRO; + +// ------------------------------------------------------------------------------------------------------------------------------ // +// ------------------------------------------------------------------------------------------------------------------------------ // +// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL. +// +// Also look for any functions marked with "**** FIXED FUNCTION STUFF" +// +// It's only laying around here so we don't have to chop up the shader system a lot to strip out the fixed function code paths. +// ------------------------------------------------------------------------------------------------------------------------------ // +// ------------------------------------------------------------------------------------------------------------------------------ // + +// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL. +typedef enum _D3DTRANSFORMSTATETYPE +{ + D3DTS_VIEW = 2, + D3DTS_PROJECTION = 3, + D3DTS_TEXTURE0 = 16, + D3DTS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTRANSFORMSTATETYPE; + +// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL. +typedef enum _D3DTEXTUREOP +{ + // Control + D3DTOP_DISABLE = 1, // disables stage + D3DTOP_SELECTARG1 = 2, // the default + D3DTOP_SELECTARG2 = 3, + + // Modulate + D3DTOP_MODULATE = 4, // multiply args together + D3DTOP_MODULATE2X = 5, // multiply and 1 bit + D3DTOP_MODULATE4X = 6, // multiply and 2 bits + + // Add + D3DTOP_ADD = 7, // add arguments together + D3DTOP_ADDSIGNED = 8, // add with -0.5 bias + D3DTOP_ADDSIGNED2X = 9, // as above but left 1 bit + D3DTOP_SUBTRACT = 10, // Arg1 - Arg2, with no saturation + D3DTOP_ADDSMOOTH = 11, // add 2 args, subtract product + // Arg1 + Arg2 - Arg1*Arg2 + // = Arg1 + (1-Arg1)*Arg2 + + // Linear alpha blend: Arg1*(Alpha) + Arg2*(1-Alpha) + D3DTOP_BLENDDIFFUSEALPHA = 12, // iterated alpha + D3DTOP_BLENDTEXTUREALPHA = 13, // texture alpha + D3DTOP_BLENDFACTORALPHA = 14, // alpha from D3DRS_TEXTUREFACTOR + + // Linear alpha blend with pre-multiplied arg1 input: Arg1 + Arg2*(1-Alpha) + D3DTOP_BLENDTEXTUREALPHAPM = 15, // texture alpha + D3DTOP_BLENDCURRENTALPHA = 16, // by alpha of current color + + // Specular mapping + D3DTOP_PREMODULATE = 17, // modulate with next texture before use + D3DTOP_MODULATEALPHA_ADDCOLOR = 18, // Arg1.RGB + Arg1.A*Arg2.RGB + // COLOROP only + D3DTOP_MODULATECOLOR_ADDALPHA = 19, // Arg1.RGB*Arg2.RGB + Arg1.A + // COLOROP only + D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20, // (1-Arg1.A)*Arg2.RGB + Arg1.RGB + // COLOROP only + D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21, // (1-Arg1.RGB)*Arg2.RGB + Arg1.A + // COLOROP only + + // Bump mapping + D3DTOP_BUMPENVMAP = 22, // per pixel env map perturbation + D3DTOP_BUMPENVMAPLUMINANCE = 23, // with luminance channel + + // This can do either diffuse or specular bump mapping with correct input. + // Performs the function (Arg1.R*Arg2.R + Arg1.G*Arg2.G + Arg1.B*Arg2.B) + // where each component has been scaled and offset to make it signed. + // The result is replicated into all four (including alpha) channels. + // This is a valid COLOROP only. + D3DTOP_DOTPRODUCT3 = 24, + + // Triadic ops + D3DTOP_MULTIPLYADD = 25, // Arg0 + Arg1*Arg2 + D3DTOP_LERP = 26, // (Arg0)*Arg1 + (1-Arg0)*Arg2 + + D3DTOP_FORCE_DWORD = 0x7fffffff, +} D3DTEXTUREOP; + +// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL. +typedef enum _D3DTEXTURESTAGESTATETYPE +{ + D3DTSS_COLOROP = 1, /* D3DTEXTUREOP - per-stage blending controls for color channels */ + D3DTSS_COLORARG1 = 2, /* D3DTA_* (texture arg) */ + D3DTSS_COLORARG2 = 3, /* D3DTA_* (texture arg) */ + D3DTSS_ALPHAOP = 4, /* D3DTEXTUREOP - per-stage blending controls for alpha channel */ + D3DTSS_ALPHAARG1 = 5, /* D3DTA_* (texture arg) */ + D3DTSS_ALPHAARG2 = 6, /* D3DTA_* (texture arg) */ + D3DTSS_BUMPENVMAT00 = 7, /* float (bump mapping matrix) */ + D3DTSS_BUMPENVMAT01 = 8, /* float (bump mapping matrix) */ + D3DTSS_BUMPENVMAT10 = 9, /* float (bump mapping matrix) */ + D3DTSS_BUMPENVMAT11 = 10, /* float (bump mapping matrix) */ + D3DTSS_TEXCOORDINDEX = 11, /* identifies which set of texture coordinates index this texture */ + D3DTSS_BUMPENVLOFFSET = 23, /* float offset for bump map luminance */ + D3DTSS_TEXTURETRANSFORMFLAGS = 24, /* D3DTEXTURETRANSFORMFLAGS controls texture transform */ + D3DTSS_COLORARG0 = 26, /* D3DTA_* third arg for triadic ops */ + D3DTSS_RESULTARG = 28, /* D3DTA_* arg for result (CURRENT or TEMP) */ + + + D3DTSS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTEXTURESTAGESTATETYPE; + +//===========================================================================// + +enum GLMVertexAttributeIndex +{ + kGLMGenericAttr00 = 0, + kGLMGenericAttr01, + kGLMGenericAttr02, + kGLMGenericAttr03, + kGLMGenericAttr04, + kGLMGenericAttr05, + kGLMGenericAttr06, + kGLMGenericAttr07, + kGLMGenericAttr08, + kGLMGenericAttr09, + kGLMGenericAttr10, + kGLMGenericAttr11, + kGLMGenericAttr12, + kGLMGenericAttr13, + kGLMGenericAttr14, + kGLMGenericAttr15, + + kGLMVertexAttributeIndexMax // ideally < 32 +}; + +struct GLMVertexAttributeDesc // all the info you need to do vertex setup for one attribute +{ + CGLMBuffer *m_pBuffer; // NULL allowed in which case m_offset is the full 32-bit pointer.. so you can draw from plain RAM if desired + GLuint m_nCompCount; // comp count of the attribute (1-4) + GLenum m_datatype; // data type of the attribute (GL_FLOAT, GL_UNSIGNED_BYTE, etc) + GLuint m_stride; + GLuint m_offset; // net offset to attribute 'zero' within the buffer. + GLuint m_streamOffset; // net offset to attribute 'zero' within the buffer. + GLboolean m_normalized; // apply to any fixed point data that needs normalizing, esp color bytes + + inline uint GetDataTypeSizeInBytes() const + { + switch ( m_datatype ) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return 1; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_HALF_FLOAT: + return 2; + case GL_INT: + case GL_FLOAT: + return 4; + default: + Assert( 0 ); + break; + } + return 0; + } + + inline uint GetTotalAttributeSizeInBytes() const { Assert( m_nCompCount ); return m_nCompCount * GetDataTypeSizeInBytes(); } + + // may need a seed value at some point to be able to disambiguate re-lifed buffers holding same pointer + // simpler alternative is to do shoot-down inside the vertex/index buffer free calls. + // I'd rather not have to have each attribute fiddling a ref count on the buffer to which it refers.. + +//#define EQ(fff) ( (src.fff) == (fff) ) + // test in decreasing order of likelihood of difference, but do not include the buffer revision as caller is not supplying it.. + //inline bool operator== ( const GLMVertexAttributeDesc& src ) const { return EQ( m_pBuffer ) && EQ( m_offset ) && EQ( m_stride ) && EQ( m_datatype ) && EQ( m_normalized ) && EQ( m_nCompCount ); } +//#undef EQ + + uint m_bufferRevision; // only set in GLM context's copy, to disambiguate references that are same offset / same buffer but cross an orphan event +}; + +#define MAX_D3DVERTEXELEMENTS 16 + +struct D3DVERTEXELEMENT9_GL +{ + // fields right out of the original decl element (copied) + D3DVERTEXELEMENT9 m_dxdecl; // d3d info + // WORD Stream; // Stream index + // WORD Offset; // Offset in the stream in bytes + // BYTE Type; // Data type + // BYTE Method; // Processing method + // BYTE Usage; // Semantics + // BYTE UsageIndex; // Semantic index + + GLMVertexAttributeDesc m_gldecl; + // CGLMBuffer *m_buffer; // late-dropped from selected stream desc (left NULL, will replace with stream source buffer at sync time) + // GLuint m_datasize; // component count (1,2,3,4) of the attrib + // GLenum m_datatype; // data type of the attribute (GL_FLOAT et al) + // GLuint m_stride; // late-dropped from stream desc + // GLuint m_offset; // net offset to attribute 'zero' within the stream data. Add the stream offset before passing to GL. + // GLuint m_normalized; // net offset to attribute 'zero' within the stream data. Add the stream offset before passing to GL. +}; + +struct IDirect3DDevice9Params +{ + UINT m_adapter; + D3DDEVTYPE m_deviceType; + VD3DHWND m_focusWindow; + DWORD m_behaviorFlags; + D3DPRESENT_PARAMETERS m_presentationParameters; +}; + +#define D3D_MAX_STREAMS 5 //9 +struct D3DStreamDesc +{ + IDirect3DVertexBuffer9 *m_vtxBuffer; + uint m_offset; + uint m_stride; +}; + +struct D3DIndexDesc +{ + IDirect3DIndexBuffer9 *m_idxBuffer; +}; + +// we latch sampler values until draw time and then convert them all to GL form +// note these are similar in name to the fields of a GLMTexSamplingParams but contents are not +// particularly in the texture filtering area + +struct D3DSamplerDesc +{ + DWORD m_srgb; // D3DSAMP_SRGBTEXTURE 0 = no SRGB sampling +}; + +// Tracking and naming sampler dimensions +#define SAMPLER_TYPE_2D 0 +#define SAMPLER_TYPE_CUBE 1 +#define SAMPLER_TYPE_3D 2 +#define SAMPLER_TYPE_UNUSED 3 + +#endif // DXABSTRACT_TYPES_H diff --git a/public/togl/linuxwin/glbase.h b/public/togl/linuxwin/glbase.h new file mode 100644 index 0000000..9c830e6 --- /dev/null +++ b/public/togl/linuxwin/glbase.h @@ -0,0 +1,117 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// glbase.h +// +//=============================================================================== + +#ifndef GLBASE_H +#define GLBASE_H + +#ifdef DX_TO_GL_ABSTRACTION + +#undef HAVE_GL_ARB_SYNC + +#ifndef OSX +#define HAVE_GL_ARB_SYNC 1 +#endif + +#ifdef USE_SDL +#include "SDL_opengl.h" +#endif + +#ifdef OSX +#include +#include +#endif + +#ifdef DX_TO_GL_ABSTRACTION + #ifndef WIN32 + #define Debugger DebuggerBreak + #endif + #undef CurrentTime + + #if defined( USE_SDL ) + #include "SDL.h" + #endif +#endif + +//=============================================================================== +// glue to call out to Obj-C land (these are in glmgrcocoa.mm) +#ifdef OSX + typedef void _PseudoNSGLContext; // aka NSOpenGLContext + typedef _PseudoNSGLContext *PseudoNSGLContextPtr; + + CGLContextObj GetCGLContextFromNSGL( PseudoNSGLContextPtr nsglCtx ); +#endif + +// Set TOGL_SUPPORT_NULL_DEVICE to 1 to support the NULL ref device +#define TOGL_SUPPORT_NULL_DEVICE 0 + +#if TOGL_SUPPORT_NULL_DEVICE + #define TOGL_NULL_DEVICE_CHECK if( m_params.m_deviceType == D3DDEVTYPE_NULLREF ) return S_OK; + #define TOGL_NULL_DEVICE_CHECK_RET_VOID if( m_params.m_deviceType == D3DDEVTYPE_NULLREF ) return; +#else + #define TOGL_NULL_DEVICE_CHECK + #define TOGL_NULL_DEVICE_CHECK_RET_VOID +#endif + +// GL_ENABLE_INDEX_VERIFICATION enables index range verification on all dynamic IB/VB's (obviously slow) +#define GL_ENABLE_INDEX_VERIFICATION 0 + +// GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION (currently win32 only) - If 1, VirtualAlloc/VirtualProtect is used to detect cases where the app locks a buffer, copies the ptr away, unlocks, then tries to later write to the buffer. +#define GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION 0 + +#define GL_BATCH_TELEMETRY_ZONES 0 + +// GL_BATCH_PERF_ANALYSIS - Enables gl_batch_vis, and various per-batch telemetry statistics messages. +#define GL_BATCH_PERF_ANALYSIS 0 +#define GL_BATCH_PERF_ANALYSIS_WRITE_PNGS 0 + +// GL_TELEMETRY_ZONES - Causes every single OpenGL call to generate a telemetry event +#define GL_TELEMETRY_ZONES 0 + +// GL_DUMP_ALL_API_CALLS - Causes a debug message to be printed for every API call if s_bDumpCalls bool is set to 1 +#define GL_DUMP_ALL_API_CALLS 0 + +// Must also enable PIX_ENABLE to use GL_TELEMETRY_GPU_ZONES. +#define GL_TELEMETRY_GPU_ZONES 0 + +// Records global # of OpenGL calls/total cycles spent inside GL +#define GL_TRACK_API_TIME GL_BATCH_PERF_ANALYSIS + +#define GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS ( GL_TELEMETRY_ZONES || GL_TRACK_API_TIME || GL_DUMP_ALL_API_CALLS ) + +#if GL_BATCH_PERF_ANALYSIS + #define GL_BATCH_PERF(...) __VA_ARGS__ +#else + #define GL_BATCH_PERF(...) +#endif + +#define kGLMUserClipPlanes 2 +#define kGLMScratchFBOCount 4 + +#endif // DX_TO_GL_ABSTRACTION + +#endif // GLBASE_H diff --git a/public/togl/linuxwin/glentrypoints.h b/public/togl/linuxwin/glentrypoints.h new file mode 100644 index 0000000..9b55c00 --- /dev/null +++ b/public/togl/linuxwin/glentrypoints.h @@ -0,0 +1,403 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// glentrypoints.h +// +//=============================================================================== + +#ifndef GLENTRYPOINTS_H +#define GLENTRYPOINTS_H + +#pragma once + +#ifdef DX_TO_GL_ABSTRACTION + +#include "tier0/platform.h" +#include "tier0/vprof_telemetry.h" +#include "interface.h" +#include "togl/rendermechanism.h" + +void *VoidFnPtrLookup_GlMgr(const char *fn, bool &okay, const bool bRequired, void *fallback=NULL); + +#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS +class CGLExecuteHelperBase +{ +public: + inline void StartCall(const char *pName); + inline void StopCall(const char *pName); +#if GL_TRACK_API_TIME + TmU64 m_nStartTime; +#endif +}; + +template < class FunctionType, typename Result > +class CGLExecuteHelper : public CGLExecuteHelperBase +{ +public: + inline CGLExecuteHelper(FunctionType pFn, const char *pName ) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g, h); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g, h, i); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g, h, i, j); StopCall(pName); } + + inline operator Result() const { return m_Result; } + inline operator char*() const { return (char*)m_Result; } + + FunctionType m_pFn; + + Result m_Result; +}; + +template < class FunctionType> +class CGLExecuteHelper : public CGLExecuteHelperBase +{ +public: + inline CGLExecuteHelper(FunctionType pFn, const char *pName ) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g, h); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g, h, i); StopCall(pName); } + template inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g, h, i, j); StopCall(pName); } + + FunctionType m_pFn; +}; +#endif + +template < class FunctionType, typename Result > +class CDynamicFunctionOpenGLBase +{ +public: + // Construct with a NULL function pointer. You must manually call + // Lookup() before you can call a dynamic function through this interface. + CDynamicFunctionOpenGLBase() : m_pFn(NULL) {} + + // Construct and do a lookup right away. You will need to make sure that + // the lookup actually succeeded, as the gl library might have failed to load + // or (fn) might not exist in it. + CDynamicFunctionOpenGLBase(const char *fn, FunctionType fallback=NULL) : m_pFn(NULL) + { + Lookup(fn, fallback); + } + + // Construct and do a lookup right away. See comments in Lookup() about what (okay) does. + CDynamicFunctionOpenGLBase(const char *fn, bool &okay, FunctionType fallback=NULL) : m_pFn(NULL) + { + Lookup(fn, okay, fallback); + } + + // Load library if necessary, look up symbol. Returns true and sets + // m_pFn on successful lookup, returns false otherwise. If the + // function pointer is already looked up, this return true immediately. + // Use Reset() first if you want to look up the symbol again. + // This function will return false immediately unless (okay) is true. + // This allows you to chain lookups like this: + // bool okay = true; + // x.Lookup(lib, "x", okay); + // y.Lookup(lib, "y", okay); + // z.Lookup(lib, "z", okay); + // if (okay) { printf("All functions were loaded successfully!\n"); } + // If you supply a fallback, it'll be used if the lookup fails (and if + // non-NULL, means this will always return (okay)). + bool Lookup(const char *fn, bool &okay, FunctionType fallback=NULL) + { + if (!okay) + return false; + else if (this->m_pFn == NULL) + { + this->m_pFn = (FunctionType) VoidFnPtrLookup_GlMgr(fn, okay, false, (void *) fallback); + this->SetFuncName( fn ); + } + okay = m_pFn != NULL; + return okay; + } + + // Load library if necessary, look up symbol. Returns true and sets + // m_pFn on successful lookup, returns false otherwise. If the + // function pointer is already looked up, this return true immediately. + // Use Reset() first if you want to look up the symbol again. + // This function will return false immediately unless (okay) is true. + // If you supply a fallback, it'll be used if the lookup fails (and if + // non-NULL, means this will always return true). + bool Lookup(const char *fn, FunctionType fallback=NULL) + { + bool okay = true; + return Lookup(fn, okay, fallback); + } + + // Invalidates the current lookup. Makes the function pointer NULL. You + // will need to call Lookup() before you can call a dynamic function + // through this interface again. + void Reset() { m_pFn = NULL; } + + // Force this to be a specific function pointer. + void Force(FunctionType ptr) { m_pFn = ptr; } + + // Retrieve the actual function pointer. + FunctionType Pointer() const { return m_pFn; } + +#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS + #if GL_TELEMETRY_ZONES || GL_DUMP_ALL_API_CALLS + #define GL_FUNC_NAME m_szName + #else + #define GL_FUNC_NAME "" + #endif + + inline CGLExecuteHelper operator() () const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME ); } + + template + inline CGLExecuteHelper operator() (T a) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a); } + + template + inline CGLExecuteHelper operator() (T a, U b) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c ) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d, X e) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d, e); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d, X e, Y f) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d, X e, Y f, Z g) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d, X e, Y f, Z g, A h) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g, h); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d, X e, Y f, Z g, A h, B i) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g, h, i); } + + template + inline CGLExecuteHelper operator() (T a, U b, V c, W d, X e, Y f, Z g, A h, B i, C j) const { return CGLExecuteHelper(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g, h, i, j); } +#else + operator FunctionType() const { return m_pFn; } +#endif + + // Can be used to verify that we have an actual function looked up and + // ready to call: if (!MyDynFunc) { printf("Function not found!\n"); } + operator bool () const { return m_pFn != NULL; } + bool operator !() const { return m_pFn == NULL; } + +protected: + FunctionType m_pFn; + +#if GL_TELEMETRY_ZONES || GL_DUMP_ALL_API_CALLS + char m_szName[32]; + inline void SetFuncName(const char *pFn) { V_strncpy( m_szName, pFn, sizeof( m_szName ) ); } +#else + inline void SetFuncName(const char *pFn) { (void)pFn; } +#endif +}; + +// This works a lot like CDynamicFunctionMustInit, but we use SDL_GL_GetProcAddress(). +template < const bool bRequired, class FunctionType, typename Result > +class CDynamicFunctionOpenGL : public CDynamicFunctionOpenGLBase< FunctionType, Result > +{ +private: // forbid default constructor. + CDynamicFunctionOpenGL() {} + +public: + CDynamicFunctionOpenGL(const char *fn, FunctionType fallback=NULL) + { + bool okay = true; + Lookup(fn, okay, fallback); + this->SetFuncName( fn ); + } + + CDynamicFunctionOpenGL(const char *fn, bool &okay, FunctionType fallback=NULL) + { + Lookup(fn, okay, fallback); + this->SetFuncName( fn ); + } + + // Please note this is not virtual. + // !!! FIXME: we might want to fall back and try "EXT" or "ARB" versions in some case. + bool Lookup(const char *fn, bool &okay, FunctionType fallback=NULL) + { + if (this->m_pFn == NULL) + { + this->m_pFn = (FunctionType) VoidFnPtrLookup_GlMgr(fn, okay, bRequired, (void *) fallback); + this->SetFuncName( fn ); + } + return okay; + } +}; + +enum GLDriverStrings_t +{ + cGLVendorString, + cGLRendererString, + cGLVersionString, + cGLExtensionsString, + + cGLTotalDriverStrings +}; + +enum GLDriverProvider_t +{ + cGLDriverProviderUnknown, + cGLDriverProviderNVIDIA, + cGLDriverProviderAMD, + cGLDriverProviderIntel, + cGLDriverProviderIntelOpenSource, + cGLDriverProviderApple, + + cGLTotalDriverProviders +}; + +// This provides all the entry points for a given OpenGL context. +// ENTRY POINTS ARE ONLY VALID FOR THE CONTEXT THAT WAS CURRENT WHEN +// YOU LOOKED THEM UP. 99% of the time, this is not a problem, but +// that 1% is really hard to track down. Always access the GL +// through this class! +class COpenGLEntryPoints +{ + COpenGLEntryPoints( const COpenGLEntryPoints & ); + COpenGLEntryPoints &operator= ( const COpenGLEntryPoints & ); + +public: + // The GL context you are looking up entry points for must be current when you construct this object! + COpenGLEntryPoints(); + ~COpenGLEntryPoints(); + + void ClearEntryPoints(); + uint64 m_nTotalGLCycles, m_nTotalGLCalls; + + int m_nOpenGLVersionMajor; // if GL_VERSION is 2.1.0, this will be set to 2. + int m_nOpenGLVersionMinor; // if GL_VERSION is 2.1.0, this will be set to 1. + int m_nOpenGLVersionPatch; // if GL_VERSION is 2.1.0, this will be set to 0. + bool m_bHave_OpenGL; + + char *m_pGLDriverStrings[cGLTotalDriverStrings]; + GLDriverProvider_t m_nDriverProvider; + +#ifdef OSX +#define GL_EXT(x,glmajor,glminor) bool m_bHave_##x; +#define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (*) arg, ret > fn; +#define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (*) arg, void > fn; +#else +#define GL_EXT(x,glmajor,glminor) bool m_bHave_##x; +#define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (APIENTRY *) arg, ret > fn; +#define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (APIENTRY *) arg, void > fn; +#endif + #include "togl/glfuncs.inl" + #undef GL_FUNC_VOID + #undef GL_FUNC + #undef GL_EXT + + bool HasSwapTearExtension() const + { +#ifdef _WIN32 + return m_bHave_WGL_EXT_swap_control_tear; +#else + return m_bHave_GLX_EXT_swap_control_tear; +#endif + } +}; + +// This will be set to the current OpenGL context's entry points. +extern COpenGLEntryPoints *gGL; +typedef void * (*GL_GetProcAddressCallbackFunc_t)(const char *, bool &, const bool, void *); + +#ifdef TOGL_DLL_EXPORT + DLL_EXPORT COpenGLEntryPoints *ToGLConnectLibraries( CreateInterfaceFn factory ); + DLL_EXPORT void ToGLDisconnectLibraries(); + DLL_EXPORT COpenGLEntryPoints *GetOpenGLEntryPoints(GL_GetProcAddressCallbackFunc_t callback); + DLL_EXPORT void ClearOpenGLEntryPoints(); +#else + DLL_IMPORT COpenGLEntryPoints *ToGLConnectLibraries( CreateInterfaceFn factory ); + DLL_IMPORT void ToGLDisconnectLibraries(); + DLL_IMPORT COpenGLEntryPoints *GetOpenGLEntryPoints(GL_GetProcAddressCallbackFunc_t callback); + DLL_IMPORT void ClearOpenGLEntryPoints(); +#endif + +#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS +inline void CGLExecuteHelperBase::StartCall(const char *pName) +{ + (void)pName; + +#if GL_TELEMETRY_ZONES + tmEnter( TELEMETRY_LEVEL3, TMZF_NONE, pName ); +#endif + +#if GL_TRACK_API_TIME + m_nStartTime = tmFastTime(); +#endif + +#if GL_DUMP_ALL_API_CALLS + static bool s_bDumpCalls; + if ( s_bDumpCalls ) + { + char buf[128]; + buf[0] = 'G'; + buf[1] = 'L'; + buf[2] = ':'; + size_t l = strlen( pName ); + memcpy( buf + 3, pName, l ); + buf[3 + l] = '\n'; + buf[4 + l] = '\0'; + Plat_DebugString( buf ); + } +#endif +} + +inline void CGLExecuteHelperBase::StopCall(const char *pName) +{ +#if GL_TRACK_API_TIME + uint64 nTotalCycles = tmFastTime() - m_nStartTime; +#endif + +#if GL_TELEMETRY_ZONES + tmLeave( TELEMETRY_LEVEL3 ); +#endif + +#if GL_TRACK_API_TIME + //double flMilliseconds = g_Telemetry.flRDTSCToMilliSeconds * nTotalCycles; + if (gGL) + { + gGL->m_nTotalGLCycles += nTotalCycles; + gGL->m_nTotalGLCalls++; + } +#endif +} +#endif + +#endif // DX_TO_GL_ABSTRACTION + +#endif // GLENTRYPOINTS_H diff --git a/public/togl/linuxwin/glfuncs.h b/public/togl/linuxwin/glfuncs.h new file mode 100644 index 0000000..f543b4a --- /dev/null +++ b/public/togl/linuxwin/glfuncs.h @@ -0,0 +1,277 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// !!! FIXME: Some of these aren't base OpenGL...pick out the extensions. +// !!! FIXME: Also, look up these -1, -1 versions numbers. +GL_FUNC(OpenGL,true,GLenum,glGetError,(void),()) +GL_FUNC_VOID(OpenGL,true,glActiveTexture,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glAlphaFunc,(GLenum a,GLclampf b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glAttachObjectARB,(GLhandleARB a,GLhandleARB b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glBegin,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glBindAttribLocationARB,(GLhandleARB a,GLuint b,const GLcharARB *c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glBindBufferARB,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glBindProgramARB,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glBindTexture,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glBlendColor,(GLclampf a,GLclampf b,GLclampf c,GLclampf d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glBlendEquation,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glBlendFunc,(GLenum a,GLenum b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glBufferDataARB,(GLenum a,GLsizeiptrARB b,const GLvoid *c,GLenum d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glClear,(GLbitfield a),(a)) +GL_FUNC_VOID(OpenGL,true,glClearColor,(GLclampf a,GLclampf b,GLclampf c,GLclampf d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glClearDepth,(GLclampd a),(a)) +GL_FUNC_VOID(OpenGL,true,glClearStencil,(GLint a),(a)) +GL_FUNC_VOID(OpenGL,true,glClipPlane,(GLenum a,const GLdouble *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glColorMask,(GLboolean a,GLboolean b,GLboolean c,GLboolean d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glCompileShaderARB,(GLhandleARB a),(a)) +GL_FUNC_VOID(OpenGL,true,glCompressedTexImage2D,(GLenum a,GLint b,GLenum c,GLsizei d,GLsizei e,GLint f,GLsizei g,const GLvoid *h),(a,b,c,d,e,f,g,h)) +GL_FUNC_VOID(OpenGL,true,glCompressedTexImage3D,(GLenum a,GLint b,GLenum c,GLsizei d,GLsizei e,GLsizei f,GLint g,GLsizei h,const GLvoid *i),(a,b,c,d,e,f,g,h,i)) +GL_FUNC(OpenGL,true,GLhandleARB,glCreateProgramObjectARB,(void),()) +GL_FUNC(OpenGL,true,GLhandleARB,glCreateShaderObjectARB,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glDeleteBuffersARB,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDeleteObjectARB,(GLhandleARB a),(a)) +GL_FUNC_VOID(OpenGL,true,glDeleteProgramsARB,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDeleteQueriesARB,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDeleteShader,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glDeleteTextures,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDepthFunc,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glDepthMask,(GLboolean a),(a)) +GL_FUNC_VOID(OpenGL,true,glDepthRange,(GLclampd a,GLclampd b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDetachObjectARB,(GLhandleARB a,GLhandleARB b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDisable,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glDisableVertexAttribArray,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glDrawArrays,(GLenum a,GLint b,GLsizei c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glDrawBuffer,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glDrawBuffers,(GLsizei a,const GLenum *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glDrawRangeElements,(GLenum a,GLuint b,GLuint c,GLsizei d,GLenum e,const GLvoid *f),(a,b,c,d,e,f)) +#ifndef OSX // 10.6/GL 2.1 compatability +GL_FUNC_VOID(OpenGL,true,glDrawRangeElementsBaseVertex,(GLenum a,GLuint b,GLuint c,GLsizei d,GLenum e,const GLvoid *f, GLenum g),(a,b,c,d,e,f,g)) +#endif +GL_FUNC_VOID(OpenGL,true,glEnable,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glEnableVertexAttribArray,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glEnd,(void),()) +GL_FUNC_VOID(OpenGL,true,glFinish,(void),()) +GL_FUNC_VOID(OpenGL,true,glFlush,(void),()) +GL_FUNC_VOID(OpenGL,true,glFrontFace,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glGenBuffersARB,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGenProgramsARB,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGenQueriesARB,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGenTextures,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGetBooleanv,(GLenum a,GLboolean *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGetCompressedTexImage,(GLenum a,GLint b,GLvoid *c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glGetDoublev,(GLenum a,GLdouble *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGetFloatv,(GLenum a,GLfloat *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGetInfoLogARB,(GLhandleARB a,GLsizei b,GLsizei *c,GLcharARB *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glGetIntegerv,(GLenum a,GLint *b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glGetObjectParameterivARB,(GLhandleARB a,GLenum b,GLint *c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glGetProgramivARB,(GLenum a,GLenum b,GLint *c),(a,b,c)) +GL_FUNC(OpenGL,true,const GLubyte *,glGetString,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glGetTexImage,(GLenum a,GLint b,GLenum c,GLenum d,GLvoid *e),(a,b,c,d,e)) +GL_FUNC(OpenGL,true,GLint,glGetUniformLocationARB,(GLhandleARB a,const GLcharARB *b),(a,b)) +GL_FUNC(OpenGL,true,GLboolean,glIsEnabled,(GLenum a),(a)) +GL_FUNC(OpenGL,true,GLboolean,glIsTexture,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glLinkProgramARB,(GLhandleARB a),(a)) +GL_FUNC(OpenGL,true,GLvoid*,glMapBufferARB,(GLenum a,GLenum b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glOrtho,(GLdouble a,GLdouble b,GLdouble c,GLdouble d,GLdouble e,GLdouble f),(a,b,c,d,e,f)) +GL_FUNC_VOID(OpenGL,true,glPixelStorei,(GLenum a,GLint b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glPolygonMode,(GLenum a,GLenum b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glPolygonOffset,(GLfloat a,GLfloat b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glPopAttrib,(void),()) +GL_FUNC_VOID(OpenGL,true,glProgramStringARB,(GLenum a,GLenum b,GLsizei c,const GLvoid *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glPushAttrib,(GLbitfield a),(a)) +GL_FUNC_VOID(OpenGL,true,glReadBuffer,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glScissor,(GLint a,GLint b,GLsizei c,GLsizei d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glShaderSourceARB,(GLhandleARB a,GLsizei b,const GLcharARB **c,const GLint *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glStencilFunc,(GLenum a,GLint b,GLuint c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glStencilMask,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glStencilOp,(GLenum a,GLenum b,GLenum c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glTexCoord2f,(GLfloat a,GLfloat b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glTexImage2D,(GLenum a,GLint b,GLint c,GLsizei d,GLsizei e,GLint f,GLenum g,GLenum h,const GLvoid *i),(a,b,c,d,e,f,g,h,i)) +GL_FUNC_VOID(OpenGL,true,glTexImage3D,(GLenum a,GLint b,GLint c,GLsizei d,GLsizei e,GLsizei f,GLint g,GLenum h,GLenum i,const GLvoid *j),(a,b,c,d,e,f,g,h,i,j)) +GL_FUNC_VOID(OpenGL,true,glTexParameterfv,(GLenum a,GLenum b,const GLfloat *c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glTexParameteri,(GLenum a,GLenum b,GLint c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glTexSubImage2D,(GLenum a,GLint b,GLint c,GLint d,GLsizei e,GLsizei f,GLenum g,GLenum h,const GLvoid *i),(a,b,c,d,e,f,g,h,i)) +GL_FUNC_VOID(OpenGL,true,glUniform1f,(GLint a,GLfloat b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glUniform1i,(GLint a,GLint b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glUniform1iARB,(GLint a,GLint b),(a,b)) +GL_FUNC_VOID(OpenGL,true,glUniform4fv,(GLint a,GLsizei b,const GLfloat *c),(a,b,c)) +GL_FUNC(OpenGL,true,GLboolean,glUnmapBuffer,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glUseProgram,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glVertex3f,(GLfloat a,GLfloat b,GLfloat c),(a,b,c)) +GL_FUNC_VOID(OpenGL,true,glVertexAttribPointer,(GLuint a,GLint b,GLenum c,GLboolean d,GLsizei e,const GLvoid *f),(a,b,c,d,e,f)) +GL_FUNC_VOID(OpenGL,true,glViewport,(GLint a,GLint b,GLsizei c,GLsizei d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glEnableClientState,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glDisableClientState,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glClientActiveTexture,(GLenum a),(a)) +GL_FUNC_VOID(OpenGL,true,glVertexPointer,(GLint a,GLenum b,GLsizei c,const GLvoid *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glTexCoordPointer,(GLint a,GLenum b,GLsizei c,const GLvoid *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glProgramEnvParameters4fvEXT,(GLenum a,GLuint b,GLsizei c,const GLfloat *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glColor4sv,(const GLshort *a),(a)) +GL_FUNC_VOID(OpenGL,true,glStencilOpSeparate,(GLenum a,GLenum b,GLenum c,GLenum d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glStencilFuncSeparate,(GLenum a,GLenum b,GLint c,GLuint d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glGetTexLevelParameteriv,(GLenum a,GLint b,GLenum c,GLint *d),(a,b,c,d)) +GL_FUNC_VOID(OpenGL,true,glColor4f,(GLfloat a,GLfloat b,GLfloat c,GLfloat d),(a,b,c,d)) +GL_EXT(GL_EXT_framebuffer_object,-1,-1) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glBindFramebufferEXT,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glBindRenderbufferEXT,(GLenum a,GLuint b),(a,b)) +GL_FUNC(GL_EXT_framebuffer_object,false,GLenum,glCheckFramebufferStatusEXT,(GLenum a),(a)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glDeleteRenderbuffersEXT,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glFramebufferRenderbufferEXT,(GLenum a,GLenum b,GLenum c,GLuint d),(a,b,c,d)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glFramebufferTexture2DEXT,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e),(a,b,c,d,e)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glFramebufferTexture3DEXT,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e,GLint f),(a,b,c,d,e,f)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glGenFramebuffersEXT,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glGenRenderbuffersEXT,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glDeleteFramebuffersEXT,(GLsizei a,const GLuint *b),(a,b)) +GL_EXT(GL_EXT_framebuffer_blit,-1,-1) +GL_FUNC_VOID(GL_EXT_framebuffer_blit,false,glBlitFramebufferEXT,(GLint a,GLint b,GLint c,GLint d,GLint e,GLint f,GLint g,GLint h,GLbitfield i,GLenum j),(a,b,c,d,e,f,g,h,i,j)) +GL_EXT(GL_EXT_framebuffer_multisample,-1,-1) +GL_FUNC_VOID(GL_EXT_framebuffer_multisample,false,glRenderbufferStorageMultisampleEXT,(GLenum a,GLsizei b,GLenum c,GLsizei d,GLsizei e),(a,b,c,d,e)) +GL_EXT(GL_APPLE_fence,-1,-1) +GL_FUNC(GL_APPLE_fence,false,GLboolean,glTestFenceAPPLE,(GLuint a),(a)) +GL_FUNC_VOID(GL_APPLE_fence,false,glSetFenceAPPLE,(GLuint a),(a)) +GL_FUNC_VOID(GL_APPLE_fence,false,glFinishFenceAPPLE,(GLuint a),(a)) +GL_FUNC_VOID(GL_APPLE_fence,false,glDeleteFencesAPPLE,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(GL_APPLE_fence,false,glGenFencesAPPLE,(GLsizei a,GLuint *b),(a,b)) +GL_EXT(GL_NV_fence,-1,-1) +GL_FUNC(GL_NV_fence,false,GLboolean,glTestFenceNV,(GLuint a),(a)) +GL_FUNC_VOID(GL_NV_fence,false,glSetFenceNV,(GLuint a,GLenum b),(a,b)) +GL_FUNC_VOID(GL_NV_fence,false,glFinishFenceNV,(GLuint a),(a)) +GL_FUNC_VOID(GL_NV_fence,false,glDeleteFencesNV,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(GL_NV_fence,false,glGenFencesNV,(GLsizei a,GLuint *b),(a,b)) +GL_EXT(GL_ARB_sync,3,2) +#ifdef HAVE_GL_ARB_SYNC +GL_FUNC_VOID(GL_ARB_sync,false,glGetSynciv,(GLsync a, GLenum b, GLsizei c, GLsizei *d, GLint *e),(a,b,c,d,e)) +GL_FUNC(GL_ARB_sync,false,GLenum,glClientWaitSync,(GLsync a, GLbitfield b, GLuint64 c),(a,b,c)) +GL_FUNC_VOID(GL_ARB_sync,false,glWaitSync,(GLsync a, GLbitfield b, GLuint64 c),(a,b,c)) +GL_FUNC_VOID(GL_ARB_sync,false,glDeleteSync,(GLsync a),(a)) +GL_FUNC(GL_ARB_sync,false,GLsync,glFenceSync,(GLenum a, GLbitfield b),(a,b)) +#endif +GL_EXT(GL_EXT_draw_buffers2,-1,-1) +GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glColorMaskIndexedEXT,(GLuint a,GLboolean b,GLboolean c,GLboolean d,GLboolean e),(a,b,c,d,e)) +GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glEnableIndexedEXT,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glDisableIndexedEXT,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glGetBooleanIndexedvEXT,(GLenum a,GLuint b,GLboolean *c),(a,b,c)) +GL_EXT(GL_EXT_bindable_uniform,-1,-1) +GL_FUNC_VOID(GL_EXT_bindable_uniform,false,glUniformBufferEXT,(GLuint a,GLint b,GLuint c),(a,b,c)) +GL_FUNC(GL_EXT_bindable_uniform,false,int,glGetUniformBufferSizeEXT,(GLenum a, GLenum b),(a,b)) +GL_FUNC(GL_EXT_bindable_uniform,false,GLintptr,glGetUniformOffsetEXT,(GLenum a, GLenum b),(a,b)) +GL_EXT(GL_APPLE_flush_buffer_range,-1,-1) +GL_FUNC_VOID(GL_APPLE_flush_buffer_range,false,glBufferParameteriAPPLE,(GLenum a,GLenum b,GLint c),(a,b,c)) +GL_FUNC_VOID(GL_APPLE_flush_buffer_range,false,glFlushMappedBufferRangeAPPLE,(GLenum a,GLintptr b,GLsizeiptr c),(a,b,c)) +GL_EXT(GL_ARB_map_buffer_range,-1,-1) +GL_FUNC(GL_ARB_map_buffer_range,false,void*,glMapBufferRange,(GLenum a,GLintptr b,GLsizeiptr c,GLbitfield d),(a,b,c,d)) +GL_FUNC_VOID(GL_ARB_map_buffer_range,false,glFlushMappedBufferRange,(GLenum a,GLintptr b,GLsizeiptr c),(a,b,c)) +GL_EXT(GL_ARB_vertex_buffer_object,-1,-1) +GL_FUNC_VOID(GL_ARB_vertex_buffer_object,true,glBufferSubData,(GLenum a,GLintptr b,GLsizeiptr c,const GLvoid *d),(a,b,c,d)) +GL_EXT(GL_ARB_occlusion_query,-1,-1) +GL_FUNC_VOID(GL_ARB_occlusion_query,false,glBeginQueryARB,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(GL_ARB_occlusion_query,false,glEndQueryARB,(GLenum a),(a)) +GL_FUNC_VOID(GL_ARB_occlusion_query,false,glGetQueryObjectivARB,(GLuint a,GLenum b,GLint *c),(a,b,c)) +GL_FUNC_VOID(GL_ARB_occlusion_query,false,glGetQueryObjectuivARB,(GLuint a,GLenum b,GLuint *c),(a,b,c)) +GL_EXT(GL_APPLE_texture_range,-1,-1) +GL_FUNC_VOID(GL_APPLE_texture_range,false,glTextureRangeAPPLE,(GLenum a,GLsizei b,void *c),(a,b,c)) +GL_FUNC_VOID(GL_APPLE_texture_range,false,glGetTexParameterPointervAPPLE,(GLenum a,GLenum b,void* *c),(a,b,c)) +GL_EXT(GL_APPLE_client_storage,-1,-1) +GL_EXT(GL_ARB_uniform_buffer,-1,-1) +GL_EXT(GL_ARB_vertex_array_bgra,-1,-1) +GL_EXT(GL_EXT_vertex_array_bgra,-1,-1) +GL_EXT(GL_ARB_framebuffer_object,3,0) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glBindFramebuffer,(GLenum a,GLuint b),(a,b)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glBindRenderbuffer,(GLenum a,GLuint b),(a,b)) +GL_FUNC(GL_ARB_framebuffer_object,false,GLenum,glCheckFramebufferStatus,(GLenum a),(a)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glDeleteRenderbuffers,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glFramebufferRenderbuffer,(GLenum a,GLenum b,GLenum c,GLuint d),(a,b,c,d)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glFramebufferTexture2D,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e),(a,b,c,d,e)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glFramebufferTexture3D,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e,GLint f),(a,b,c,d,e,f)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glGenFramebuffers,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glGenRenderbuffers,(GLsizei a,GLuint *b),(a,b)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glDeleteFramebuffers,(GLsizei a,const GLuint *b),(a,b)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glBlitFramebuffer,(GLint a,GLint b,GLint c,GLint d,GLint e,GLint f,GLint g,GLint h,GLbitfield i,GLenum j),(a,b,c,d,e,f,g,h,i,j)) +GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glRenderbufferStorageMultisample,(GLenum a,GLsizei b,GLenum c,GLsizei d,GLsizei e),(a,b,c,d,e)) +GL_EXT(GL_GREMEDY_string_marker,-1,-1) +GL_FUNC_VOID(GL_GREMEDY_string_marker,false,glStringMarkerGREMEDY,(GLsizei a,const void *b),(a,b)) +GL_EXT(GL_ARB_debug_output,-1,-1) +#ifdef OSX +GL_FUNC_VOID(GL_ARB_debug_output,false,glDebugMessageCallbackARB,(void ( *a)(GLenum, GLenum , GLuint , GLenum , GLsizei , const GLchar* , GLvoid*) ,void* b),(a,b)) +#else +GL_FUNC_VOID(GL_ARB_debug_output,false,glDebugMessageCallbackARB,(void (APIENTRY *a)(GLenum, GLenum , GLuint , GLenum , GLsizei , const GLchar* , GLvoid*) ,void* b),(a,b)) +#endif +GL_FUNC_VOID(GL_ARB_debug_output,false,glDebugMessageControlARB,(GLenum a, GLenum b, GLenum c, GLsizei d, const GLuint* e, GLboolean f),(a,b,c,d,e,f)) + +GL_EXT(GL_EXT_direct_state_access,-1,-1) +GL_FUNC_VOID(GL_EXT_direct_state_access,false,glBindMultiTextureEXT,(GLenum a,GLuint b, GLuint c),(a,b,c)) +GL_EXT(GL_NV_bindless_texture,-1,-1) + +#ifndef OSX +GL_FUNC_VOID(OpenGL, true, glGenSamplers, (GLuint a, GLuint *b), (a, b)) +GL_FUNC_VOID(OpenGL, true, glDeleteSamplers, (GLsizei a, const GLuint *b), (a, b)) +GL_FUNC_VOID(OpenGL, true, glBindSampler, (GLuint a, GLuint b), (a, b)) +GL_FUNC_VOID(OpenGL, true, glSamplerParameteri, (GLuint a, GLenum b, GLint c), (a, b, c)) +GL_FUNC_VOID(OpenGL, true, glSamplerParameterf, (GLuint a, GLenum b, GLfloat c), (a, b, c)) +GL_FUNC_VOID(OpenGL, true, glSamplerParameterfv, (GLuint a, GLenum b, const GLfloat *c), (a, b, c)) +GL_FUNC(GL_NV_bindless_texture, false, GLuint64, glGetTextureHandleNV, (GLuint texture), (texture)) +GL_FUNC(GL_NV_bindless_texture, false, GLuint64, glGetTextureSamplerHandleNV, (GLuint texture, GLuint sampler), (texture, sampler)) +GL_FUNC_VOID(GL_NV_bindless_texture, false, glMakeTextureHandleResidentNV, (GLuint64 handle), (handle)) +GL_FUNC_VOID(GL_NV_bindless_texture, false, glMakeTextureHandleNonResidentNV, (GLuint64 handle), (handle)) +GL_FUNC_VOID(GL_NV_bindless_texture, false, glUniformHandleui64NV, (GLint location, GLuint64 value), (location, value)) +GL_FUNC_VOID(GL_NV_bindless_texture, false, glUniformHandleui64vNV, (int location, GLsizei count, const GLuint64 *value), (location count, value)) +GL_FUNC_VOID(GL_NV_bindless_texture, false, glProgramUniformHandleui64NV, (GLuint program, GLint location, GLuint64 value), (program, location, value)) +GL_FUNC_VOID(GL_NV_bindless_texture, false, glProgramUniformHandleui64vNV, (GLuint program, GLint location, GLsizei count, const GLuint64 *values), (program, location, count, values)) +GL_FUNC(GL_NV_bindless_texture, false, GLboolean, glIsTextureHandleResidentNV, (GLuint64 handle), (handle)) +GL_FUNC_VOID(OpenGL,true,glGenQueries,(GLsizei n, GLuint *ids), (n, ids)) +GL_FUNC_VOID(OpenGL,true,glDeleteQueries,(GLsizei n, const GLuint *ids),(n, ids)) +GL_FUNC_VOID(OpenGL,true,glBeginQuery,(GLenum target, GLuint id), (target, id)) +GL_FUNC_VOID(OpenGL,true,glEndQuery,(GLenum target), (target)) +GL_FUNC_VOID(OpenGL,true,glQueryCounter,(GLuint id, GLenum target), (id, target)) +GL_FUNC_VOID(OpenGL,true,glGetQueryObjectiv,(GLuint id, GLenum pname, GLint *params), (id, pname, params)) +GL_FUNC_VOID(OpenGL,true,glGetQueryObjectui64v,(GLuint id, GLenum pname, GLuint64 *params), (id, pname, params)) +GL_FUNC_VOID(OpenGL,true,glCopyBufferSubData,(GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size),(readtarget, writetarget, readoffset, writeoffset, size)) +#endif // !OSX + +GL_EXT(GL_AMD_pinned_memory,-1,-1) +GL_EXT(GL_EXT_framebuffer_multisample_blit_scaled,-1,-1) + +#ifndef OSX +GL_FUNC_VOID(OpenGL,true,glGenVertexArrays,(GLsizei n, GLuint *arrays),(n, arrays)) +GL_FUNC_VOID(OpenGL,true,glDeleteVertexArrays,(GLsizei n, GLuint *arrays),(n, arrays)) +GL_FUNC_VOID(OpenGL,true,glBindVertexArray,(GLuint a),(a)) +#endif // !OSX + +GL_EXT(GL_EXT_texture_sRGB_decode,-1,-1) +GL_FUNC_VOID(OpenGL,true,glPushClientAttrib,(GLbitfield a),(a)) +GL_FUNC_VOID(OpenGL,true,glPopClientAttrib,(void),()) +GL_EXT(GL_NVX_gpu_memory_info,-1,-1) +GL_EXT(GL_ATI_meminfo,-1,-1) +GL_EXT(GL_EXT_texture_compression_s3tc,-1,-1) +GL_EXT(GL_EXT_texture_compression_dxt1,-1,-1) +GL_EXT(GL_ANGLE_texture_compression_dxt3,-1,-1) +GL_EXT(GL_ANGLE_texture_compression_dxt5,-1,-1) + +GL_EXT( GL_ARB_buffer_storage, 4, 4 ) +GL_FUNC_VOID( GL_ARB_buffer_storage, false, glBufferStorage, (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags), (target, size, data, flags) ) + +// This one is an OS extension. We'll add a little helper function to look for it. +#ifdef _WIN32 + GL_EXT(WGL_EXT_swap_control_tear,-1,-1) +#else + GL_EXT(GLX_EXT_swap_control_tear,-1,-1) +#endif diff --git a/public/togl/linuxwin/glmdebug.h b/public/togl/linuxwin/glmdebug.h new file mode 100644 index 0000000..08cb6f9 --- /dev/null +++ b/public/togl/linuxwin/glmdebug.h @@ -0,0 +1,181 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#ifndef GLMDEBUG_H +#define GLMDEBUG_H + +#include "tier0/platform.h" +#if defined( OSX ) +#include +#endif + +// include this anywhere you need to be able to compile-out code related specifically to GLM debugging. + +// we expect DEBUG to be driven by the build system so you can include this header anywhere. +// when we come out, GLMDEBUG will be defined to a value - 0, 1, or 2 +// 0 means no GLM debugging is possible +// 1 means it's possible and resulted from being a debug build +// 2 means it's possible and resulted from being manually forced on for a release build + +#ifdef POSIX + #ifndef GLMDEBUG + #ifdef DEBUG + #define GLMDEBUG 1 // normally 1 here, testing + #else + // #define GLMDEBUG 2 // don't check this in enabled.. + #endif + + #ifndef GLMDEBUG + #define GLMDEBUG 0 + #endif + #endif +#else + #ifndef GLMDEBUG + #define GLMDEBUG 0 + #endif +#endif + + +//=============================================================================== +// debug channels + +enum EGLMDebugChannel +{ + ePrintf, + eDebugger, + eGLProfiler +}; + +#if GLMDEBUG + // make all these prototypes disappear in non GLMDEBUG + void GLMDebugInitialize( bool forceReinit=false ); + + bool GLMDetectOGLP( void ); + bool GLMDetectGDB( void ); + uint GLMDetectAvailableChannels( void ); + + uint GLMDebugChannelMask( uint *newValue = NULL ); + // note that GDB and OGLP can both come and go during run - forceCheck will allow that to be detected. + // mask returned is in form of 1< < + eComment, // 3 one off messages --- + eMatrixData, // 4 matrix data -M- + eShaderData, // 5 shader data (params) -S- + eFrameBufData, // 6 FBO data (attachments) -F- + eDXStuff, // 7 dxabstract spew -X- + eAllocations, // 8 tracking allocs and frees -A- + eSlowness, // 9 slow things happening (srgb flips..) -Z- + eDefaultFlavor, // not specified (no marker) + eFlavorCount +}; +uint GLMDebugFlavorMask( uint *newValue = NULL ); + +// make all these prototypes disappear in non GLMDEBUG +#if GLMDEBUG + // these are unconditional outputs, they don't interrogate the string + void GLMStringOut( const char *string ); + void GLMStringOutIndented( const char *string, int indentColumns ); + + #ifdef TOGL_DLL_EXPORT + // these will look at the string to guess its flavor: <, >, ---, -M-, -S- + DLL_EXPORT void GLMPrintfVA( const char *fmt, va_list vargs ); + DLL_EXPORT void GLMPrintf( const char *fmt, ... ); + #else + DLL_IMPORT void GLMPrintfVA( const char *fmt, va_list vargs ); + DLL_IMPORT void GLMPrintf( const char *fmt, ... ); + #endif + + // these take an explicit flavor with a default value + void GLMPrintStr( const char *str, EGLMDebugFlavor flavor = eDefaultFlavor ); + + #define GLMPRINTTEXT_NUMBEREDLINES 0x80000000 + void GLMPrintText( const char *str, EGLMDebugFlavor flavor = eDefaultFlavor, uint options=0 ); // indent each newline + + int GLMIncIndent( int indentDelta ); + int GLMGetIndent( void ); + void GLMSetIndent( int indent ); + +#endif + +// helpful macro if you are in a position to call GLM functions directly (i.e. you live in materialsystem / shaderapidx9) +#if GLMDEBUG + #define GLMPRINTF(args) GLMPrintf args + #define GLMPRINTSTR(args) GLMPrintStr args + #define GLMPRINTTEXT(args) GLMPrintText args +#else + #define GLMPRINTF(args) + #define GLMPRINTSTR(args) + #define GLMPRINTTEXT(args) +#endif + + +//=============================================================================== +// knob twiddling +#ifdef TOGL_DLL_EXPORT + DLL_EXPORT float GLMKnob( char *knobname, float *setvalue ); // Pass NULL to not-set the knob value + DLL_EXPORT float GLMKnobToggle( char *knobname ); +#else + DLL_IMPORT float GLMKnob( char *knobname, float *setvalue ); // Pass NULL to not-set the knob value + DLL_IMPORT float GLMKnobToggle( char *knobname ); +#endif + +//=============================================================================== +// other stuff + +#if GLMDEBUG +void GLMTriggerDebuggerBreak(); +inline void GLMDebugger( void ) +{ + if (GLMDebugChannelMask() & (1< +#include +#include +#include +#include +#endif + +#ifdef MAC_OS_X_VERSION_10_9 +typedef uint32_t CGDirectDisplayID; +typedef uint32_t CGOpenGLDisplayMask; +typedef double CGRefreshRate; +#endif + +typedef void _PseudoNSGLContext; // aka NSOpenGLContext +typedef _PseudoNSGLContext *PseudoNSGLContextPtr; + +struct GLMDisplayModeInfoFields +{ + uint m_modePixelWidth; + uint m_modePixelHeight; + uint m_modeRefreshHz; + // are we even going to talk about bit depth... not yet +}; + +struct GLMDisplayInfoFields +{ +#ifdef OSX + CGDirectDisplayID m_cgDisplayID; + CGOpenGLDisplayMask m_glDisplayMask; // result of CGDisplayIDToOpenGLDisplayMask on the cg_displayID. +#endif + uint m_displayPixelWidth; + uint m_displayPixelHeight; +}; + +struct GLMRendererInfoFields +{ + /*properties of interest and their desired values. + + kCGLRPFullScreen = 54, true + kCGLRPAccelerated = 73, true + kCGLRPWindow = 80, true + + kCGLRPRendererID = 70, informational + kCGLRPDisplayMask = 84, informational + kCGLRPBufferModes = 100, informational + kCGLRPColorModes = 103, informational + kCGLRPAccumModes = 104, informational + kCGLRPDepthModes = 105, informational + kCGLRPStencilModes = 106, informational + kCGLRPMaxAuxBuffers = 107, informational + kCGLRPMaxSampleBuffers = 108, informational + kCGLRPMaxSamples = 109, informational + kCGLRPSampleModes = 110, informational + kCGLRPSampleAlpha = 111, informational + kCGLRPVideoMemory = 120, informational + kCGLRPTextureMemory = 121, informational + kCGLRPRendererCount = 128 number of renderers in the CGLRendererInfoObj under examination + + kCGLRPOffScreen = 53, D/C + kCGLRPRobust = 75, FALSE or D/C - aka we're asking for no-fallback + kCGLRPBackingStore = 76, D/C + kCGLRPMPSafe = 78, D/C + kCGLRPMultiScreen = 81, D/C + kCGLRPCompliant = 83, D/C + */ + + + //--------------------------- info we have from CGL renderer queries, IOKit, Gestalt + //--------------------------- these are set up in the displayDB by CocoaMgr + GLint m_fullscreen; + GLint m_accelerated; + GLint m_windowed; + + GLint m_rendererID; + GLint m_displayMask; + GLint m_bufferModes; + GLint m_colorModes; + GLint m_accumModes; + GLint m_depthModes; + GLint m_stencilModes; + + GLint m_maxAuxBuffers; + GLint m_maxSampleBuffers; + GLint m_maxSamples; + GLint m_sampleModes; + GLint m_sampleAlpha; + + GLint m_vidMemory; + GLint m_texMemory; + + uint m_pciVendorID; + uint m_pciDeviceID; + char m_pciModelString[64]; + char m_driverInfoString[64]; + + //--------------------------- OS version related - set up by CocoaMgr + + // OS version found + uint m_osComboVersion; // 0x00XXYYZZ : XX major, YY minor, ZZ minor minor : 10.6.3 --> 0x000A0603. 10.5.8 --> 0x000A0508. + + //--------------------------- shorthands - also set up by CocoaMgr - driven by vendorid / deviceid + + bool m_ati; + bool m_atiR5xx; + bool m_atiR6xx; + bool m_atiR7xx; + bool m_atiR8xx; + bool m_atiNewer; + + bool m_intel; + bool m_intel95x; + bool m_intel3100; + bool m_intelHD4000; + + bool m_nv; + bool m_nvG7x; + bool m_nvG8x; + bool m_nvNewer; + + //--------------------------- context query results - left blank in the display DB - but valid in a GLMContext (call ctx->Caps() to get a const ref) + + // booleans + bool m_hasGammaWrites; // aka glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT) / glEnable(GL_FRAMEBUFFER_SRGB_EXT) + bool m_hasMixedAttachmentSizes; // aka ARB_fbo in 10.6.3 - test for min OS vers, then exported ext string + bool m_hasBGRA; // aka GL_BGRA vertex attribs in 10.6.3 - - test for min OS vers, then exported ext string + bool m_hasNewFullscreenMode; // aka 10.6.x "big window" fullscreen mode + bool m_hasNativeClipVertexMode; // aka GLSL gl_ClipVertex does not fall back to SW- OS version and folklore-based + bool m_hasOcclusionQuery; // occlusion query: do you speak it ?! + bool m_hasFramebufferBlit; // framebuffer blit: know what I'm sayin?! + bool m_hasPerfPackage1; // means new MTGL, fast OQ, fast uniform upload, NV can resolve flipped (late summer 2010 post 10.6.4 update) + + // counts + int m_maxAniso; // aniso limit - context query + + // other exts + bool m_hasBindableUniforms; + int m_maxVertexBindableUniforms; + int m_maxFragmentBindableUniforms; + int m_maxBindableUniformSize; + + bool m_hasUniformBuffers; + + // runtime options that aren't negotiable once set + bool m_hasDualShaders; // must supply CLI arg "-glmdualshaders" or we go GLSL only + + //--------------------------- " can'ts " - specific problems that need to be worked around + + bool m_cantBlitReliably; // Intel chipsets have problems blitting sRGB sometimes + bool m_cantAttachSRGB; // NV G8x on 10.5.8 can't have srgb tex on FBO color - separate issue from hasGammaWrites + bool m_cantResolveFlipped; // happens on NV in 10.6.4 and prior - console variable "gl_can_resolve_flipped" can overrule + bool m_cantResolveScaled; // happens everywhere per GL spec but may be relaxed some day - console variable "gl_can_resolve_scaled" can overrule + bool m_costlyGammaFlips; // this means that sRGB sampling state affects shader code gen, resulting in state-dependent code regen + + + //--------------------------- " bads " - known bad drivers + bool m_badDriver1064NV; // this is the bad NVIDIA driver on 10.6.4 - stutter, tex corruption, black screen issues + bool m_badDriver108Intel; // this is the bad Intel HD4000 driver on 10.8 - intermittent crash on GLSL compilation. +}; + + + +#endif diff --git a/public/togl/linuxwin/glmdisplaydb.h b/public/togl/linuxwin/glmdisplaydb.h new file mode 100644 index 0000000..686c792 --- /dev/null +++ b/public/togl/linuxwin/glmdisplaydb.h @@ -0,0 +1,157 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#ifndef GLMDISPLAYDB_H +#define GLMDISPLAYDB_H + +#include "tier1/utlvector.h" + +//=============================================================================== +// modes, displays, and renderers +//=============================================================================== + +// GLMDisplayModeInfoFields is in glmdisplay.h + +class GLMDisplayMode +{ +public: + GLMDisplayModeInfoFields m_info; + + GLMDisplayMode( uint width, uint height, uint refreshHz ); + GLMDisplayMode() { }; + ~GLMDisplayMode( void ); + + void Init( uint width, uint height, uint refreshHz ); + void Dump( int which ); +}; + +//=============================================================================== + +// GLMDisplayInfoFields is in glmdisplay.h + +class GLMDisplayInfo +{ +public: + GLMDisplayInfoFields m_info; + CUtlVector< GLMDisplayMode* > *m_modes; // starts out NULL, set by PopulateModes + GLMDisplayMode m_DesktopMode; + +#ifdef OSX + GLMDisplayInfo( CGDirectDisplayID displayID, CGOpenGLDisplayMask displayMask ); +#else + GLMDisplayInfo( void ); +#endif + + ~GLMDisplayInfo( void ); + + void PopulateModes( void ); + + void Dump( int which ); + +#ifdef OSX +private: + int m_display; +#endif +}; + +//=============================================================================== + +// GLMRendererInfoFields is in glmdisplay.h + +class GLMRendererInfo +{ +public: + GLMRendererInfoFields m_info; +#ifdef OSX + CUtlVector< GLMDisplayInfo* > *m_displays; // starts out NULL, set by PopulateDisplays +#else + GLMDisplayInfo *m_display; +#endif + +#ifdef OSX + GLMRendererInfo ( GLMRendererInfoFields *info ); +#else + GLMRendererInfo (); +#endif + ~GLMRendererInfo ( void ); + +#ifndef OSX + void Init( GLMRendererInfoFields *info ); +#endif + void PopulateDisplays(); + void Dump( int which ); +}; + +//=============================================================================== + +#ifdef OSX +// this is just a tuple describing fake adapters which are really renderer/display pairings. +// dxabstract bridges the gap between the d3d adapter-centric world and the GL renderer+display world. +// this makes it straightforward to handle cases like two video cards with two displays on one, and one on the other - +// you get three fake adapters which represent each useful screen. + +// the constraint that dxa will have to follow though, is that if the user wants to change their +// display selection for full screen, they would only be able to pick on that has the same underlying renderer. +// can't change fakeAdapter from one to another with different GL renderer under it. Screen hop but no card hop. + +struct GLMFakeAdapter +{ + int m_rendererIndex; + int m_displayIndex; +}; +#endif + +class GLMDisplayDB +{ +public: +#ifdef OSX + CUtlVector< GLMRendererInfo* > *m_renderers; // starts out NULL, set by PopulateRenderers + CUtlVector< GLMFakeAdapter > m_fakeAdapters; +#else + GLMRendererInfo m_renderer; +#endif + + GLMDisplayDB ( void ); + ~GLMDisplayDB ( void ); + + virtual void PopulateRenderers( void ); + virtual void PopulateFakeAdapters( uint realRendererIndex ); // fake adapters = one real adapter times however many displays are on it + virtual void Populate( void ); + + // The info-get functions return false on success. + virtual int GetFakeAdapterCount( void ); + virtual bool GetFakeAdapterInfo( int fakeAdapterIndex, int *rendererOut, int *displayOut, GLMRendererInfoFields *rendererInfoOut, GLMDisplayInfoFields *displayInfoOut ); + + virtual int GetRendererCount( void ); + virtual bool GetRendererInfo( int rendererIndex, GLMRendererInfoFields *infoOut ); + + virtual int GetDisplayCount( int rendererIndex ); + virtual bool GetDisplayInfo( int rendererIndex, int displayIndex, GLMDisplayInfoFields *infoOut ); + + virtual int GetModeCount( int rendererIndex, int displayIndex ); + virtual bool GetModeInfo( int rendererIndex, int displayIndex, int modeIndex, GLMDisplayModeInfoFields *infoOut ); + + virtual void Dump( void ); +}; + +#endif // GLMDISPLAYDB_H diff --git a/public/togl/linuxwin/glmgr.h b/public/togl/linuxwin/glmgr.h new file mode 100644 index 0000000..aabcd70 --- /dev/null +++ b/public/togl/linuxwin/glmgr.h @@ -0,0 +1,2419 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// glmgr.h +// singleton class, common basis for managing GL contexts +// responsible for tracking adapters and contexts +// +//=============================================================================== + +#ifndef GLMGR_H +#define GLMGR_H + +#pragma once + +#undef HAVE_GL_ARB_SYNC +#ifndef OSX +#define HAVE_GL_ARB_SYNC 1 +#endif + +#include "glbase.h" +#include "glentrypoints.h" +#include "glmdebug.h" +#include "glmdisplay.h" +#include "glmgrext.h" +#include "glmgrbasics.h" +#include "cglmtex.h" +#include "cglmfbo.h" +#include "cglmprogram.h" +#include "cglmbuffer.h" +#include "cglmquery.h" + +#include "tier0/vprof_telemetry.h" +#include "materialsystem/IShader.h" +#include "dxabstract_types.h" +#include "tier0/icommandline.h" + +#undef FORCEINLINE +#define FORCEINLINE inline + +//=============================================================================== + +#define GLM_OPENGL_VENDOR_ID 1 +#define GLM_OPENGL_DEFAULT_DEVICE_ID 1 +#define GLM_OPENGL_LOW_PERF_DEVICE_ID 2 + +extern void GLMDebugPrintf( const char *pMsg, ... ); + +extern uint g_nTotalDrawsOrClears, g_nTotalVBLockBytes, g_nTotalIBLockBytes; + +#if GL_TELEMETRY_GPU_ZONES +struct TelemetryGPUStats_t +{ + uint m_nTotalBufferLocksAndUnlocks; + uint m_nTotalTexLocksAndUnlocks; + uint m_nTotalBlit2; + uint m_nTotalResolveTex; + uint m_nTotalPresent; + + inline void Clear() { memset( this, 0, sizeof( *this ) ); } + inline uint GetTotal() const { return m_nTotalBufferLocksAndUnlocks + m_nTotalTexLocksAndUnlocks + m_nTotalBlit2 + m_nTotalResolveTex + m_nTotalPresent; } +}; +extern TelemetryGPUStats_t g_TelemetryGPUStats; +#endif + +struct GLMRect; +typedef void *PseudoGLContextPtr; + +// parrot the D3D present parameters, more or less... "adapter" translates into "active display index" per the m_activeDisplayCount below. +class GLMDisplayParams +{ + public: + + // presumption, these indices are in sync with the current display DB that GLMgr has handy + //int m_rendererIndex; // index of renderer (-1 if root context) + //int m_displayIndex; // index of display in renderer - for FS + //int m_modeIndex; // index of mode in display - for FS + + void *m_focusWindow; // (VD3DHWND aka WindowRef) - what window does this context display into + + bool m_fsEnable; // fullscreen on or not + bool m_vsyncEnable; // vsync on or not + + // height and width have to match the display mode info if full screen. + + uint m_backBufferWidth; // pixel width (aka screen h-resolution if full screen) + uint m_backBufferHeight; // pixel height (aka screen v-resolution if full screen) + D3DFORMAT m_backBufferFormat; // pixel format + uint m_multiSampleCount; // 0 means no MSAA, 2 means 2x MSAA, etc + // uint m_multiSampleQuality; // no MSAA quality control yet + + bool m_enableAutoDepthStencil; // generally set to 'TRUE' per CShaderDeviceDx8::SetPresentParameters + D3DFORMAT m_autoDepthStencilFormat; + + uint m_fsRefreshHz; // if full screen, this refresh rate (likely 0 for LCD's) + + //uint m_rootRendererID; // only used if m_rendererIndex is -1. + //uint m_rootDisplayMask; // only used if m_rendererIndex is -1. + + bool m_mtgl; // enable multi threaded GL driver +}; + +//=============================================================================== + +class GLMgr +{ +public: + + //=========================================================================== + // class methods - singleton + static void NewGLMgr( void ); // instantiate singleton.. + static GLMgr *aGLMgr( void ); // return singleton.. + static void DelGLMgr( void ); // tear down singleton.. + + //=========================================================================== + // plain methods + + #if 0 // turned all these off while new approach is coded + void RefreshDisplayDB( void ); // blow away old display DB, make a new one + GLMDisplayDB *GetDisplayDB( void ); // get a ptr to the one GLMgr keeps. only valid til next refresh. + + // eligible renderers will be ranked by desirability starting at index 0 within the db + // within each renderer, eligible displays will be ranked some kind of desirability (area? dist from menu bar?) + // within each display, eligible modes will be ranked by descending areas + + // calls supplying indices are implicitly making reference to the current DB + bool CaptureDisplay( int rendIndex, int displayIndex, bool captureAll ); // capture one display or all displays + void ReleaseDisplays( void ); // release all captures + + int GetDisplayMode( int rendIndex, int displayIndex ); // retrieve current display res (returns modeIndex) + void SetDisplayMode( GLMDisplayParams *params ); // set the display res (only useful for FS) + #endif + + GLMContext *NewContext( IDirect3DDevice9 *pDevice, GLMDisplayParams *params ); // this will have to change + void DelContext( GLMContext *context ); + + // with usage of CGLMacro.h we could dispense with the "current context" thing + // and just declare a member variable of GLMContext, allowing each glXXX call to be routed directly + // to the correct context + void SetCurrentContext( GLMContext *context ); // make current in calling thread only + GLMContext *GetCurrentContext( void ); + +protected: + friend class GLMContext; + + GLMgr(); + ~GLMgr(); +}; + + +//===========================================================================// + +// helper function to do enable or disable in one step +FORCEINLINE void glSetEnable( GLenum which, bool enable ) +{ + if (enable) + gGL->glEnable(which); + else + gGL->glDisable(which); +} + +// helper function for int vs enum clarity +FORCEINLINE void glGetEnumv( GLenum which, GLenum *dst ) +{ + gGL->glGetIntegerv( which, (int*)dst ); +} + +//===========================================================================// +// +// types to support the GLMContext +// +//===========================================================================// + +// Each state set/get path we are providing caching for, needs its own struct and a comparison operator. +// we also provide an enum of how many such types there are, handy for building dirty masks etc. + +// shorthand macros +#define EQ(fff) ( (src.fff) == (fff) ) + +//rasterizer +struct GLAlphaTestEnable_t { GLint enable; inline bool operator==(const GLAlphaTestEnable_t& src) const { return EQ(enable); } }; +struct GLAlphaTestFunc_t { GLenum func; GLclampf ref; inline bool operator==(const GLAlphaTestFunc_t& src) const { return EQ(func) && EQ(ref); } }; +struct GLCullFaceEnable_t { GLint enable; inline bool operator==(const GLCullFaceEnable_t& src) const { return EQ(enable); } }; +struct GLCullFrontFace_t { GLenum value; inline bool operator==(const GLCullFrontFace_t& src) const { return EQ(value); } }; +struct GLPolygonMode_t { GLenum values[2]; inline bool operator==(const GLPolygonMode_t& src) const { return EQ(values[0]) && EQ(values[1]); } }; +struct GLDepthBias_t { GLfloat factor; GLfloat units; inline bool operator==(const GLDepthBias_t& src) const { return EQ(factor) && EQ(units); } }; +struct GLScissorEnable_t { GLint enable; inline bool operator==(const GLScissorEnable_t& src) const { return EQ(enable); } }; +struct GLScissorBox_t { GLint x,y; GLsizei width, height; inline bool operator==(const GLScissorBox_t& src) const { return EQ(x) && EQ(y) && EQ(width) && EQ(height); } }; +struct GLAlphaToCoverageEnable_t{ GLint enable; inline bool operator==(const GLAlphaToCoverageEnable_t& src) const { return EQ(enable); } }; +struct GLViewportBox_t { GLint x,y; GLsizei width, height; uint widthheight; inline bool operator==(const GLViewportBox_t& src) const { return EQ(x) && EQ(y) && EQ(width) && EQ(height); } }; +struct GLViewportDepthRange_t { GLdouble flNear,flFar; inline bool operator==(const GLViewportDepthRange_t& src) const { return EQ(flNear) && EQ(flFar); } }; +struct GLClipPlaneEnable_t { GLint enable; inline bool operator==(const GLClipPlaneEnable_t& src) const { return EQ(enable); } }; +struct GLClipPlaneEquation_t { GLfloat x,y,z,w; inline bool operator==(const GLClipPlaneEquation_t& src) const { return EQ(x) && EQ(y) && EQ(z) && EQ(w); } }; + +//blend +struct GLColorMaskSingle_t { char r,g,b,a; inline bool operator==(const GLColorMaskSingle_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } }; +struct GLColorMaskMultiple_t { char r,g,b,a; inline bool operator==(const GLColorMaskMultiple_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } }; +struct GLBlendEnable_t { GLint enable; inline bool operator==(const GLBlendEnable_t& src) const { return EQ(enable); } }; +struct GLBlendFactor_t { GLenum srcfactor,dstfactor; inline bool operator==(const GLBlendFactor_t& src) const { return EQ(srcfactor) && EQ(dstfactor); } }; +struct GLBlendEquation_t { GLenum equation; inline bool operator==(const GLBlendEquation_t& src) const { return EQ(equation); } }; +struct GLBlendColor_t { GLfloat r,g,b,a; inline bool operator==(const GLBlendColor_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } }; +struct GLBlendEnableSRGB_t { GLint enable; inline bool operator==(const GLBlendEnableSRGB_t& src) const { return EQ(enable); } }; + +//depth +struct GLDepthTestEnable_t { GLint enable; inline bool operator==(const GLDepthTestEnable_t& src) const { return EQ(enable); } }; +struct GLDepthFunc_t { GLenum func; inline bool operator==(const GLDepthFunc_t& src) const { return EQ(func); } }; +struct GLDepthMask_t { char mask; inline bool operator==(const GLDepthMask_t& src) const { return EQ(mask); } }; + +//stencil +struct GLStencilTestEnable_t { GLint enable; inline bool operator==(const GLStencilTestEnable_t& src) const { return EQ(enable); } }; +struct GLStencilFunc_t { GLenum frontfunc, backfunc; GLint ref; GLuint mask; inline bool operator==(const GLStencilFunc_t& src) const { return EQ(frontfunc) && EQ(backfunc) && EQ(ref) && EQ(mask); } }; +struct GLStencilOp_t { GLenum sfail; GLenum dpfail; GLenum dppass; inline bool operator==(const GLStencilOp_t& src) const { return EQ(sfail) && EQ(dpfail) && EQ(dppass); } }; +struct GLStencilWriteMask_t { GLint mask; inline bool operator==(const GLStencilWriteMask_t& src) const { return EQ(mask); } }; + +//clearing +struct GLClearColor_t { GLfloat r,g,b,a; inline bool operator==(const GLClearColor_t& src) const { return EQ(r) && EQ(g) && EQ(b) && EQ(a); } }; +struct GLClearDepth_t { GLdouble d; inline bool operator==(const GLClearDepth_t& src) const { return EQ(d); } }; +struct GLClearStencil_t { GLint s; inline bool operator==(const GLClearStencil_t& src) const { return EQ(s); } }; + +#undef EQ + +enum EGLMStateBlockType +{ + kGLAlphaTestEnable, + kGLAlphaTestFunc, + + kGLCullFaceEnable, + kGLCullFrontFace, + + kGLPolygonMode, + + kGLDepthBias, + + kGLScissorEnable, + kGLScissorBox, + + kGLViewportBox, + kGLViewportDepthRange, + + kGLClipPlaneEnable, + kGLClipPlaneEquation, + + kGLColorMaskSingle, + kGLColorMaskMultiple, + + kGLBlendEnable, + kGLBlendFactor, + kGLBlendEquation, + kGLBlendColor, + kGLBlendEnableSRGB, + + kGLDepthTestEnable, + kGLDepthFunc, + kGLDepthMask, + + kGLStencilTestEnable, + kGLStencilFunc, + kGLStencilOp, + kGLStencilWriteMask, + + kGLClearColor, + kGLClearDepth, + kGLClearStencil, + + kGLAlphaToCoverageEnable, + + kGLMStateBlockLimit +}; + +//===========================================================================// + +// templated functions representing GL R/W bottlenecks +// one set of set/get/getdefault is instantiated for each of the GL*** types above. + +// use these from the non array state objects +template void GLContextSet( T *src ); +template void GLContextGet( T *dst ); +template void GLContextGetDefault( T *dst ); + +// use these from the array state objects +template void GLContextSetIndexed( T *src, int index ); +template void GLContextGetIndexed( T *dst, int index ); +template void GLContextGetDefaultIndexed( T *dst, int index ); + +//=============================================================================== +// template specializations for each type of state + +// --- GLAlphaTestEnable --- +FORCEINLINE void GLContextSet( GLAlphaTestEnable_t *src ) +{ + glSetEnable( GL_ALPHA_TEST, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLAlphaTestEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_ALPHA_TEST ); +} + +FORCEINLINE void GLContextGetDefault( GLAlphaTestEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + +// --- GLAlphaTestFunc --- +FORCEINLINE void GLContextSet( GLAlphaTestFunc_t *src ) +{ + gGL->glAlphaFunc( src->func, src->ref ); +} + +FORCEINLINE void GLContextGet( GLAlphaTestFunc_t *dst ) +{ + glGetEnumv( GL_ALPHA_TEST_FUNC, &dst->func ); + gGL->glGetFloatv( GL_ALPHA_TEST_REF, &dst->ref ); +} + +FORCEINLINE void GLContextGetDefault( GLAlphaTestFunc_t *dst ) +{ + dst->func = GL_ALWAYS; + dst->ref = 0.0f; +} + +// --- GLAlphaToCoverageEnable --- +FORCEINLINE void GLContextSet( GLAlphaToCoverageEnable_t *src ) +{ + glSetEnable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLAlphaToCoverageEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB ); +} + +FORCEINLINE void GLContextGetDefault( GLAlphaToCoverageEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + +// --- GLCullFaceEnable --- +FORCEINLINE void GLContextSet( GLCullFaceEnable_t *src ) +{ + glSetEnable( GL_CULL_FACE, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLCullFaceEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_CULL_FACE ); +} + +FORCEINLINE void GLContextGetDefault( GLCullFaceEnable_t *dst ) +{ + dst->enable = GL_TRUE; +} + + +// --- GLCullFrontFace --- +FORCEINLINE void GLContextSet( GLCullFrontFace_t *src ) +{ + gGL->glFrontFace( src->value ); // legal values are GL_CW or GL_CCW +} + +FORCEINLINE void GLContextGet( GLCullFrontFace_t *dst ) +{ + glGetEnumv( GL_FRONT_FACE, &dst->value ); +} + +FORCEINLINE void GLContextGetDefault( GLCullFrontFace_t *dst ) +{ + dst->value = GL_CCW; +} + + +// --- GLPolygonMode --- +FORCEINLINE void GLContextSet( GLPolygonMode_t *src ) +{ + gGL->glPolygonMode( GL_FRONT, src->values[0] ); + gGL->glPolygonMode( GL_BACK, src->values[1] ); +} + +FORCEINLINE void GLContextGet( GLPolygonMode_t *dst ) +{ + glGetEnumv( GL_POLYGON_MODE, &dst->values[0] ); + +} + +FORCEINLINE void GLContextGetDefault( GLPolygonMode_t *dst ) +{ + dst->values[0] = dst->values[1] = GL_FILL; +} + + +// --- GLDepthBias --- +// note the implicit enable / disable. +// if you set non zero values, it is enabled, otherwise not. +FORCEINLINE void GLContextSet( GLDepthBias_t *src ) +{ + bool enable = (src->factor != 0.0f) || (src->units != 0.0f); + + glSetEnable( GL_POLYGON_OFFSET_FILL, enable ); + gGL->glPolygonOffset( src->factor, src->units ); +} + +FORCEINLINE void GLContextGet( GLDepthBias_t *dst ) +{ + gGL->glGetFloatv ( GL_POLYGON_OFFSET_FACTOR, &dst->factor ); + gGL->glGetFloatv ( GL_POLYGON_OFFSET_UNITS, &dst->units ); +} + +FORCEINLINE void GLContextGetDefault( GLDepthBias_t *dst ) +{ + dst->factor = 0.0; + dst->units = 0.0; +} + + +// --- GLScissorEnable --- +FORCEINLINE void GLContextSet( GLScissorEnable_t *src ) +{ + glSetEnable( GL_SCISSOR_TEST, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLScissorEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_SCISSOR_TEST ); +} + +FORCEINLINE void GLContextGetDefault( GLScissorEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + + +// --- GLScissorBox --- +FORCEINLINE void GLContextSet( GLScissorBox_t *src ) +{ + gGL->glScissor ( src->x, src->y, src->width, src->height ); +} + +FORCEINLINE void GLContextGet( GLScissorBox_t *dst ) +{ + gGL->glGetIntegerv ( GL_SCISSOR_BOX, &dst->x ); +} + +FORCEINLINE void GLContextGetDefault( GLScissorBox_t *dst ) +{ + // hmmmm, good question? we can't really know a good answer so we pick a silly one + // and the client better come back with a better answer later. + dst->x = dst->y = 0; + dst->width = dst->height = 16; +} + + +// --- GLViewportBox --- + +FORCEINLINE void GLContextSet( GLViewportBox_t *src ) +{ + Assert( src->width == (int)( src->widthheight & 0xFFFF ) ); + Assert( src->height == (int)( src->widthheight >> 16 ) ); + gGL->glViewport (src->x, src->y, src->width, src->height ); +} + +FORCEINLINE void GLContextGet( GLViewportBox_t *dst ) +{ + gGL->glGetIntegerv ( GL_VIEWPORT, &dst->x ); + dst->widthheight = dst->width | ( dst->height << 16 ); +} + +FORCEINLINE void GLContextGetDefault( GLViewportBox_t *dst ) +{ + // as with the scissor box, we don't know yet, so pick a silly one and change it later + dst->x = dst->y = 0; + dst->width = dst->height = 16; + dst->widthheight = dst->width | ( dst->height << 16 ); +} + + +// --- GLViewportDepthRange --- +FORCEINLINE void GLContextSet( GLViewportDepthRange_t *src ) +{ + gGL->glDepthRange ( src->flNear, src->flFar ); +} + +FORCEINLINE void GLContextGet( GLViewportDepthRange_t *dst ) +{ + gGL->glGetDoublev ( GL_DEPTH_RANGE, &dst->flNear ); +} + +FORCEINLINE void GLContextGetDefault( GLViewportDepthRange_t *dst ) +{ + dst->flNear = 0.0; + dst->flFar = 1.0; +} + +// --- GLClipPlaneEnable --- +FORCEINLINE void GLContextSetIndexed( GLClipPlaneEnable_t *src, int index ) +{ +#if GLMDEBUG + if (CommandLine()->FindParm("-caps_noclipplanes")) + { + if (GLMKnob("caps-key",NULL) > 0.0) + { + // caps ON means NO clipping + src->enable = false; + } + } +#endif + glSetEnable( GL_CLIP_PLANE0 + index, src->enable != 0 ); +} + +FORCEINLINE void GLContextGetIndexed( GLClipPlaneEnable_t *dst, int index ) +{ + dst->enable = gGL->glIsEnabled( GL_CLIP_PLANE0 + index ); +} + +FORCEINLINE void GLContextGetDefaultIndexed( GLClipPlaneEnable_t *dst, int index ) +{ + dst->enable = 0; +} + + + +// --- GLClipPlaneEquation --- +FORCEINLINE void GLContextSetIndexed( GLClipPlaneEquation_t *src, int index ) +{ + // shove into glGlipPlane + GLdouble coeffs[4] = { src->x, src->y, src->z, src->w }; + + gGL->glClipPlane( GL_CLIP_PLANE0 + index, coeffs ); +} + +FORCEINLINE void GLContextGetIndexed( GLClipPlaneEquation_t *dst, int index ) +{ + DebuggerBreak(); // do this later + // glClipPlane( GL_CLIP_PLANE0 + index, coeffs ); + // GLdouble coeffs[4] = { src->x, src->y, src->z, src->w }; +} + +FORCEINLINE void GLContextGetDefaultIndexed( GLClipPlaneEquation_t *dst, int index ) +{ + dst->x = 1.0; + dst->y = 0.0; + dst->z = 0.0; + dst->w = 0.0; +} + + +// --- GLColorMaskSingle --- +FORCEINLINE void GLContextSet( GLColorMaskSingle_t *src ) +{ + gGL->glColorMask( src->r, src->g, src->b, src->a ); +} + +FORCEINLINE void GLContextGet( GLColorMaskSingle_t *dst ) +{ + gGL->glGetBooleanv( GL_COLOR_WRITEMASK, (GLboolean*)&dst->r); +} + +FORCEINLINE void GLContextGetDefault( GLColorMaskSingle_t *dst ) +{ + dst->r = dst->g = dst->b = dst->a = 1; +} + + +// --- GLColorMaskMultiple --- +FORCEINLINE void GLContextSetIndexed( GLColorMaskMultiple_t *src, int index ) +{ + gGL->glColorMaskIndexedEXT ( index, src->r, src->g, src->b, src->a ); +} + +FORCEINLINE void GLContextGetIndexed( GLColorMaskMultiple_t *dst, int index ) +{ + gGL->glGetBooleanIndexedvEXT ( GL_COLOR_WRITEMASK, index, (GLboolean*)&dst->r ); +} + +FORCEINLINE void GLContextGetDefaultIndexed( GLColorMaskMultiple_t *dst, int index ) +{ + dst->r = dst->g = dst->b = dst->a = 1; +} + + +// --- GLBlendEnable --- +FORCEINLINE void GLContextSet( GLBlendEnable_t *src ) +{ + glSetEnable( GL_BLEND, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLBlendEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_BLEND ); +} + +FORCEINLINE void GLContextGetDefault( GLBlendEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + + +// --- GLBlendFactor --- +FORCEINLINE void GLContextSet( GLBlendFactor_t *src ) +{ + gGL->glBlendFunc ( src->srcfactor, src->dstfactor ); +} + +FORCEINLINE void GLContextGet( GLBlendFactor_t *dst ) +{ + glGetEnumv ( GL_BLEND_SRC, &dst->srcfactor ); + glGetEnumv ( GL_BLEND_DST, &dst->dstfactor ); +} + +FORCEINLINE void GLContextGetDefault( GLBlendFactor_t *dst ) +{ + dst->srcfactor = GL_ONE; + dst->dstfactor = GL_ZERO; +} + + +// --- GLBlendEquation --- +FORCEINLINE void GLContextSet( GLBlendEquation_t *src ) +{ + gGL->glBlendEquation ( src->equation ); +} + +FORCEINLINE void GLContextGet( GLBlendEquation_t *dst ) +{ + glGetEnumv ( GL_BLEND_EQUATION, &dst->equation ); +} + +FORCEINLINE void GLContextGetDefault( GLBlendEquation_t *dst ) +{ + dst->equation = GL_FUNC_ADD; +} + + +// --- GLBlendColor --- +FORCEINLINE void GLContextSet( GLBlendColor_t *src ) +{ + gGL->glBlendColor ( src->r, src->g, src->b, src->a ); +} + +FORCEINLINE void GLContextGet( GLBlendColor_t *dst ) +{ + gGL->glGetFloatv ( GL_BLEND_COLOR, &dst->r ); +} + +FORCEINLINE void GLContextGetDefault( GLBlendColor_t *dst ) +{ + //solid white + dst->r = dst->g = dst->b = dst->a = 1.0; +} + + +// --- GLBlendEnableSRGB --- + +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_COLOR_ATTACHMENT0 0x8CE0 + +FORCEINLINE void GLContextSet( GLBlendEnableSRGB_t *src ) +{ +#if GLMDEBUG + // just check in debug... this is too expensive to look at on MTGL + if (src->enable) + { + GLboolean srgb_capable = false; + gGL->glGetBooleanv( GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgb_capable); + + if (src->enable && !srgb_capable) + { + GLMPRINTF(("-Z- srgb-state-set FBO conflict: attempt to enable SRGB on non SRGB capable FBO config")); + } + } +#endif + // this query is not useful unless you have the ARB_framebuffer_srgb ext. + //GLint encoding = 0; + //pfnglGetFramebufferAttachmentParameteriv( GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding ); + + glSetEnable( GL_FRAMEBUFFER_SRGB_EXT, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLBlendEnableSRGB_t *dst ) +{ + //dst->enable = glIsEnabled( GL_FRAMEBUFFER_SRGB_EXT ); + dst->enable = true; // wtf ? +} + +FORCEINLINE void GLContextGetDefault( GLBlendEnableSRGB_t *dst ) +{ + dst->enable = GL_FALSE; +} + + +// --- GLDepthTestEnable --- +FORCEINLINE void GLContextSet( GLDepthTestEnable_t *src ) +{ + glSetEnable( GL_DEPTH_TEST, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLDepthTestEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_DEPTH_TEST ); +} + +FORCEINLINE void GLContextGetDefault( GLDepthTestEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + + +// --- GLDepthFunc --- +FORCEINLINE void GLContextSet( GLDepthFunc_t *src ) +{ + gGL->glDepthFunc ( src->func ); +} + +FORCEINLINE void GLContextGet( GLDepthFunc_t *dst ) +{ + glGetEnumv ( GL_DEPTH_FUNC, &dst->func ); +} + +FORCEINLINE void GLContextGetDefault( GLDepthFunc_t *dst ) +{ + dst->func = GL_GEQUAL; +} + + +// --- GLDepthMask --- +FORCEINLINE void GLContextSet( GLDepthMask_t *src ) +{ + gGL->glDepthMask ( src->mask ); +} + +FORCEINLINE void GLContextGet( GLDepthMask_t *dst ) +{ + gGL->glGetBooleanv ( GL_DEPTH_WRITEMASK, (GLboolean*)&dst->mask ); +} + +FORCEINLINE void GLContextGetDefault( GLDepthMask_t *dst ) +{ + dst->mask = GL_TRUE; +} + + +// --- GLStencilTestEnable --- +FORCEINLINE void GLContextSet( GLStencilTestEnable_t *src ) +{ + glSetEnable( GL_STENCIL_TEST, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLStencilTestEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_STENCIL_TEST ); +} + +FORCEINLINE void GLContextGetDefault( GLStencilTestEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + + +// --- GLStencilFunc --- +FORCEINLINE void GLContextSet( GLStencilFunc_t *src ) +{ + if (src->frontfunc == src->backfunc) + gGL->glStencilFuncSeparate( GL_FRONT_AND_BACK, src->frontfunc, src->ref, src->mask); + else + { + gGL->glStencilFuncSeparate( GL_FRONT, src->frontfunc, src->ref, src->mask); + gGL->glStencilFuncSeparate( GL_BACK, src->backfunc, src->ref, src->mask); + } +} + +FORCEINLINE void GLContextGet( GLStencilFunc_t *dst ) +{ + glGetEnumv ( GL_STENCIL_FUNC, &dst->frontfunc ); + glGetEnumv ( GL_STENCIL_BACK_FUNC, &dst->backfunc ); + gGL->glGetIntegerv ( GL_STENCIL_REF, &dst->ref ); + gGL->glGetIntegerv ( GL_STENCIL_VALUE_MASK, (GLint*)&dst->mask ); +} + +FORCEINLINE void GLContextGetDefault( GLStencilFunc_t *dst ) +{ + dst->frontfunc = GL_ALWAYS; + dst->backfunc = GL_ALWAYS; + dst->ref = 0; + dst->mask = 0xFFFFFFFF; +} + + +// --- GLStencilOp --- indexed 0=front, 1=back + +FORCEINLINE void GLContextSetIndexed( GLStencilOp_t *src, int index ) +{ + GLenum face = (index==0) ? GL_FRONT : GL_BACK; + gGL->glStencilOpSeparate( face, src->sfail, src->dpfail, src->dppass ); +} + +FORCEINLINE void GLContextGetIndexed( GLStencilOp_t *dst, int index ) +{ + glGetEnumv ( (index==0) ? GL_STENCIL_FAIL : GL_STENCIL_BACK_FAIL, &dst->sfail ); + glGetEnumv ( (index==0) ? GL_STENCIL_PASS_DEPTH_FAIL : GL_STENCIL_BACK_PASS_DEPTH_FAIL, &dst->dpfail ); + glGetEnumv ( (index==0) ? GL_STENCIL_PASS_DEPTH_PASS : GL_STENCIL_BACK_PASS_DEPTH_PASS, &dst->dppass ); +} + +FORCEINLINE void GLContextGetDefaultIndexed( GLStencilOp_t *dst, int index ) +{ + dst->sfail = dst->dpfail = dst->dppass = GL_KEEP; +} + + +// --- GLStencilWriteMask --- +FORCEINLINE void GLContextSet( GLStencilWriteMask_t *src ) +{ + gGL->glStencilMask( src->mask ); +} + +FORCEINLINE void GLContextGet( GLStencilWriteMask_t *dst ) +{ + gGL->glGetIntegerv ( GL_STENCIL_WRITEMASK, &dst->mask ); +} + +FORCEINLINE void GLContextGetDefault( GLStencilWriteMask_t *dst ) +{ + dst->mask = 0xFFFFFFFF; +} + + +// --- GLClearColor --- +FORCEINLINE void GLContextSet( GLClearColor_t *src ) +{ + gGL->glClearColor( src->r, src->g, src->b, src->a ); +} + +FORCEINLINE void GLContextGet( GLClearColor_t *dst ) +{ + gGL->glGetFloatv ( GL_COLOR_CLEAR_VALUE, &dst->r ); +} + +FORCEINLINE void GLContextGetDefault( GLClearColor_t *dst ) +{ + dst->r = dst->g = dst->b = 0.5; + dst->a = 1.0; +} + + +// --- GLClearDepth --- +FORCEINLINE void GLContextSet( GLClearDepth_t *src ) +{ + gGL->glClearDepth ( src->d ); +} + +FORCEINLINE void GLContextGet( GLClearDepth_t *dst ) +{ + gGL->glGetDoublev ( GL_DEPTH_CLEAR_VALUE, &dst->d ); +} + +FORCEINLINE void GLContextGetDefault( GLClearDepth_t *dst ) +{ + dst->d = 1.0; +} + + +// --- GLClearStencil --- +FORCEINLINE void GLContextSet( GLClearStencil_t *src ) +{ + gGL->glClearStencil( src->s ); +} + +FORCEINLINE void GLContextGet( GLClearStencil_t *dst ) +{ + gGL->glGetIntegerv ( GL_STENCIL_CLEAR_VALUE, &dst->s ); +} + +FORCEINLINE void GLContextGetDefault( GLClearStencil_t *dst ) +{ + dst->s = 0; +} + +//===========================================================================// + +// caching state object template. One of these is instantiated in the context per unique struct type above +template class GLState +{ + public: + inline GLState() + { + memset( &data, 0, sizeof(data) ); + Default(); + } + + FORCEINLINE void Flush() + { + // immediately blast out the state - it makes no sense to delta it or do anything fancy because shaderapi, dxabstract, and OpenGL itself does this for us (and OpenGL calls with multithreaded drivers are very cheap) + GLContextSet( &data ); + } + + // write: client src into cache + // common case is both false. dirty is calculated, context write is deferred. + FORCEINLINE void Write( const T *src ) + { + data = *src; + Flush(); + } + + // default: write default value to cache, optionally write through + inline void Default( bool noDefer=false ) + { + GLContextGetDefault( &data ); // read default values directly to our cache copy + Flush(); + } + + // read: sel = 0 for cache, 1 for context + inline void Read( T *dst, int sel ) + { + if (sel==0) + *dst = data; + else + GLContextGet( dst ); + } + + // check: verify that context equals cache, return true if mismatched or if illegal values seen + inline bool Check ( void ) + { + T temp; + bool result; + + GLContextGet( &temp ); + result = !(temp == data); + return result; + } + + FORCEINLINE const T &GetData() const { return data; } + + protected: + T data; +}; + +// caching state object template - with multiple values behind it that are indexed +template class GLStateArray +{ + public: + inline GLStateArray() + { + memset( &data, 0, sizeof(data) ); + Default(); + } + + // write cache->context if dirty or forced. + FORCEINLINE void FlushIndex( int index ) + { + // immediately blast out the state - it makes no sense to delta it or do anything fancy because shaderapi, dxabstract, and OpenGL itself does this for us (and OpenGL calls with multithreaded drivers are very cheap) + GLContextSetIndexed( &data[index], index ); + }; + + // write: client src into cache + // common case is both false. dirty is calculated, context write is deferred. + FORCEINLINE void WriteIndex( T *src, int index ) + { + data[index] = *src; + FlushIndex( index ); // dirty becomes false + }; + + // write all slots in the array + FORCEINLINE void Flush() + { + for( int i=0; i < COUNT; i++) + { + FlushIndex( i ); + } + } + + // default: write default value to cache, optionally write through + inline void DefaultIndex( int index ) + { + GLContextGetDefaultIndexed( &data[index], index ); // read default values directly to our cache copy + Flush(); + }; + + inline void Default( void ) + { + for( int i=0; i((reinterpret_cast(m_pRawBuf) + 65535) & (~65535)); + m_nSize = nSize; + m_nOfs = 0; + + gGL->glGenBuffersARB( 1, &m_nBufferObj ); + gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nBufferObj ); + + gGL->glBufferDataARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nSize, m_pBuf, GL_STREAM_COPY ); + + return true; + } + + void Deinit() + { + if ( !m_pRawBuf ) + return; + + BlockUntilNotBusy(); + + gGL->glBindBufferARB(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nBufferObj ); + + gGL->glBufferDataARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0, (void*)NULL, GL_STREAM_COPY ); + + gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0 ); + + gGL->glDeleteBuffersARB( 1, &m_nBufferObj ); + m_nBufferObj = 0; + + free( m_pRawBuf ); + m_pRawBuf = NULL; + m_pBuf = NULL; + + m_nSize = 0; + m_nOfs = 0; + } + + inline uint GetSize() const { return m_nSize; } + inline uint GetOfs() const { return m_nOfs; } + inline uint GetBytesRemaining() const { return m_nSize - m_nOfs; } + inline void *GetPtr() const { return m_pBuf; } + inline GLuint GetHandle() const { return m_nBufferObj; } + + void InsertFence() + { +#ifdef HAVE_GL_ARB_SYNC + if ( m_nSyncObj ) + { + gGL->glDeleteSync( m_nSyncObj ); + } + + m_nSyncObj = gGL->glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); +#endif + } + + void BlockUntilNotBusy() + { +#ifdef HAVE_GL_ARB_SYNC + if ( m_nSyncObj ) + { + gGL->glClientWaitSync( m_nSyncObj, GL_SYNC_FLUSH_COMMANDS_BIT, 3000000000000ULL ); + + gGL->glDeleteSync( m_nSyncObj ); + + m_nSyncObj = 0; + } +#endif + m_nOfs = 0; + } + + void Append( uint nSize ) + { + m_nOfs += nSize; + Assert( m_nOfs <= m_nSize ); + } + +private: + void *m_pRawBuf; + void *m_pBuf; + uint m_nSize; + uint m_nOfs; + + GLuint m_nBufferObj; +#ifdef HAVE_GL_ARB_SYNC + GLsync m_nSyncObj; +#endif +}; +#endif // !OSX + +//===========================================================================// + +class GLMContext +{ + public: + // set/check current context (perq for many other calls) + void MakeCurrent( bool bRenderThread = false ); + void ReleaseCurrent( bool bRenderThread = false ); + + // CheckCurrent has been removed (it no longer compiled on Linux). To minimize churn I'm leaving + // the inline NOP version. + // DO NOT change this to non-inlined. It's called all over the place from very hot codepaths. + FORCEINLINE void CheckCurrent( void ) { } + + void PopulateCaps( void ); // fill out later portions of renderer info record which need context queries + void DumpCaps( void ); // printf all the caps info (you can call this in release too) + const GLMRendererInfoFields& Caps( void ); // peek at the caps record + + // state cache/mirror + void SetDefaultStates( void ); + void ForceFlushStates(); + + void VerifyStates( void ); + + // textures + // Lock and Unlock reqs go directly to the tex object + CGLMTex *NewTex( GLMTexLayoutKey *key, uint levels=1, const char *debugLabel=NULL ); + void DelTex( CGLMTex *tex ); + + // options for Blit (replacement for ResolveTex and BlitTex) + // pass NULL for dstTex if you want to target GL_BACK with the blit. You get y-flip with that, don't change the dstrect yourself. + void Blit2( CGLMTex *srcTex, GLMRect *srcRect, int srcFace, int srcMip, CGLMTex *dstTex, GLMRect *dstRect, int dstFace, int dstMip, uint filter ); + + // tex blit (via FBO blit) + void BlitTex( CGLMTex *srcTex, GLMRect *srcRect, int srcFace, int srcMip, CGLMTex *dstTex, GLMRect *dstRect, int dstFace, int dstMip, uint filter, bool useBlitFB = true ); + + // MSAA resolve - we do this in GLMContext because it has to do a bunch of FBO/blit gymnastics + void ResolveTex( CGLMTex *tex, bool forceDirty=false ); + + // texture pre-load (residency forcing) - normally done one-time but you can force it + void PreloadTex( CGLMTex *tex, bool force=false ); + + // samplers + FORCEINLINE void SetSamplerTex( int sampler, CGLMTex *tex ); + + FORCEINLINE void SetSamplerDirty( int sampler ); + FORCEINLINE void SetSamplerMinFilter( int sampler, GLenum Value ); + FORCEINLINE void SetSamplerMagFilter( int sampler, GLenum Value ); + FORCEINLINE void SetSamplerMipFilter( int sampler, GLenum Value ); + FORCEINLINE void SetSamplerAddressU( int sampler, GLenum Value ); + FORCEINLINE void SetSamplerAddressV( int sampler, GLenum Value ); + FORCEINLINE void SetSamplerAddressW( int sampler, GLenum Value ); + FORCEINLINE void SetSamplerStates( int sampler, GLenum AddressU, GLenum AddressV, GLenum AddressW, GLenum minFilter, GLenum magFilter, GLenum mipFilter ); + FORCEINLINE void SetSamplerBorderColor( int sampler, DWORD Value ); + FORCEINLINE void SetSamplerMipMapLODBias( int sampler, DWORD Value ); + FORCEINLINE void SetSamplerMaxMipLevel( int sampler, DWORD Value ); + FORCEINLINE void SetSamplerMaxAnisotropy( int sampler, DWORD Value ); + FORCEINLINE void SetSamplerSRGBTexture( int sampler, DWORD Value ); + FORCEINLINE void SetShadowFilter( int sampler, DWORD Value ); + + // render targets (FBO's) + CGLMFBO *NewFBO( void ); + void DelFBO( CGLMFBO *fbo ); + + // programs + CGLMProgram *NewProgram( EGLMProgramType type, char *progString, const char *pShaderName ); + void DelProgram( CGLMProgram *pProg ); + void NullProgram( void ); // de-ac all shader state + + FORCEINLINE void SetVertexProgram( CGLMProgram *pProg ); + FORCEINLINE void SetFragmentProgram( CGLMProgram *pProg ); + FORCEINLINE void SetProgram( EGLMProgramType nProgType, CGLMProgram *pProg ) { m_drawingProgram[nProgType] = pProg; m_bDirtyPrograms = true; } + + void SetDrawingLang( EGLMProgramLang lang, bool immediate=false ); // choose ARB or GLSL. immediate=false defers lang change to top of frame + + void LinkShaderPair( CGLMProgram *vp, CGLMProgram *fp ); // ensure this combo has been linked and is in the GLSL pair cache + void ValidateShaderPair( CGLMProgram *vp, CGLMProgram *fp ); + void ClearShaderPairCache( void ); // call this to shoot down all the linked pairs + void QueryShaderPair( int index, GLMShaderPairInfo *infoOut ); // this lets you query the shader pair cache for saving its state + + // buffers + // Lock and Unlock reqs go directly to the buffer object + CGLMBuffer *NewBuffer( EGLMBufferType type, uint size, uint options ); + void DelBuffer( CGLMBuffer *buff ); + + FORCEINLINE void SetIndexBuffer( CGLMBuffer *buff ) { BindIndexBufferToCtx( buff ); } + + // FIXME: Remove this, it's no longer used + FORCEINLINE void SetVertexAttributes( GLMVertexSetup *setup ) + { + // we now just latch the vert setup and then execute on it at flushdrawstatestime if shaders are enabled. + if ( setup ) + { + m_drawVertexSetup = *setup; + } + else + { + memset( &m_drawVertexSetup, 0, sizeof( m_drawVertexSetup ) ); + } + } + + // note, no API is exposed for setting a single attribute source. + // come prepared with a complete block of attributes to use. + + // Queries + CGLMQuery *NewQuery( GLMQueryParams *params ); + void DelQuery( CGLMQuery *query ); + + // "slot" means a vec4-sized thing + // these write into .env parameter space + FORCEINLINE void SetProgramParametersF( EGLMProgramType type, uint baseSlot, float *slotData, uint slotCount ); + FORCEINLINE void SetProgramParametersB( EGLMProgramType type, uint baseSlot, int *slotData, uint boolCount ); // take "BOOL" aka int + FORCEINLINE void SetProgramParametersI( EGLMProgramType type, uint baseSlot, int *slotData, uint slotCount ); // take int4s + + // state sync + // If lazyUnbinding is true, unbound samplers will not actually be unbound to the GL device. + FORCEINLINE void FlushDrawStates( uint nStartIndex, uint nEndIndex, uint nBaseVertex ); // pushes all drawing state - samplers, tex, programs, etc. + void FlushDrawStatesNoShaders(); + + // drawing +#ifndef OSX + FORCEINLINE void DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, uint baseVertex, CGLMBuffer *pIndexBuf ); + void DrawRangeElementsNonInline( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, uint baseVertex, CGLMBuffer *pIndexBuf ); +#else + void DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, CGLMBuffer *pIndexBuf ); +#endif + + void CheckNative( void ); + + // clearing + void Clear( bool color, unsigned long colorValue, bool depth, float depthValue, bool stencil, unsigned int stencilValue, GLScissorBox_t *rect = NULL ); + + // display + //void SetVSyncEnable( bool vsyncOn ); + //void SetFullScreen( bool fsOn, int screenIndex ); // will be latched for next BeginFrame + //void ActivateFullScreen( bool fsOn, int screenIndex ); // will be called by BeginFrame + bool SetDisplayParams( GLMDisplayParams *params ); // either the first time setup, or a change to new setup + + void Present( CGLMTex *tex ); // somewhat hardwired for the time being + + // Called when IDirect3DDevice9::Reset() is called. + void Reset(); + + // writers for the state block inputs + + FORCEINLINE void WriteAlphaTestEnable( GLAlphaTestEnable_t *src ) { m_AlphaTestEnable.Write( src ); } + FORCEINLINE void WriteAlphaTestFunc( GLAlphaTestFunc_t *src ) { m_AlphaTestFunc.Write( src ); } + FORCEINLINE void WriteAlphaToCoverageEnable( GLAlphaToCoverageEnable_t *src ) { m_AlphaToCoverageEnable.Write( src ); } + FORCEINLINE void WriteCullFaceEnable( GLCullFaceEnable_t *src ) { m_CullFaceEnable.Write( src ); } + FORCEINLINE void WriteCullFrontFace( GLCullFrontFace_t *src ) { m_CullFrontFace.Write( src ); } + FORCEINLINE void WritePolygonMode( GLPolygonMode_t *src ) { m_PolygonMode.Write( src ); } + FORCEINLINE void WriteDepthBias( GLDepthBias_t *src ) { m_DepthBias.Write( src ); } + FORCEINLINE void WriteClipPlaneEnable( GLClipPlaneEnable_t *src, int which ) { m_ClipPlaneEnable.WriteIndex( src, which ); } + FORCEINLINE void WriteClipPlaneEquation( GLClipPlaneEquation_t *src, int which ) { m_ClipPlaneEquation.WriteIndex( src, which ); } + FORCEINLINE void WriteScissorEnable( GLScissorEnable_t *src ) { m_ScissorEnable.Write( src ); } + FORCEINLINE void WriteScissorBox( GLScissorBox_t *src ) { m_ScissorBox.Write( src ); } + FORCEINLINE void WriteViewportBox( GLViewportBox_t *src ) { m_ViewportBox.Write( src ); } + FORCEINLINE void WriteViewportDepthRange( GLViewportDepthRange_t *src ) { m_ViewportDepthRange.Write( src ); } + FORCEINLINE void WriteColorMaskSingle( GLColorMaskSingle_t *src ) { m_ColorMaskSingle.Write( src ); } + FORCEINLINE void WriteColorMaskMultiple( GLColorMaskMultiple_t *src, int which ) { m_ColorMaskMultiple.WriteIndex( src, which ); } + FORCEINLINE void WriteBlendEnable( GLBlendEnable_t *src ) { m_BlendEnable.Write( src ); } + FORCEINLINE void WriteBlendFactor( GLBlendFactor_t *src ) { m_BlendFactor.Write( src ); } + FORCEINLINE void WriteBlendEquation( GLBlendEquation_t *src ) { m_BlendEquation.Write( src ); } + FORCEINLINE void WriteBlendColor( GLBlendColor_t *src ) { m_BlendColor.Write( src ); } + + FORCEINLINE void WriteBlendEnableSRGB( GLBlendEnableSRGB_t *src ) + { + if (m_caps.m_hasGammaWrites) // only if caps allow do we actually push it through to the extension + { + m_BlendEnableSRGB.Write( src ); + } + else + { + m_FakeBlendEnableSRGB = src->enable != 0; + } + // note however that we're still tracking what this mode should be, so FlushDrawStates can look at it and adjust the pixel shader + // if fake SRGB mode is in place (m_caps.m_hasGammaWrites is false) + } + + FORCEINLINE void WriteDepthTestEnable( GLDepthTestEnable_t *src ) { m_DepthTestEnable.Write( src ); } + FORCEINLINE void WriteDepthFunc( GLDepthFunc_t *src ) { m_DepthFunc.Write( src ); } + FORCEINLINE void WriteDepthMask( GLDepthMask_t *src ) { m_DepthMask.Write( src ); } + FORCEINLINE void WriteStencilTestEnable( GLStencilTestEnable_t *src ) { m_StencilTestEnable.Write( src ); } + FORCEINLINE void WriteStencilFunc( GLStencilFunc_t *src ) { m_StencilFunc.Write( src ); } + FORCEINLINE void WriteStencilOp( GLStencilOp_t *src, int which ) { m_StencilOp.WriteIndex( src, which ); } + FORCEINLINE void WriteStencilWriteMask( GLStencilWriteMask_t *src ) { m_StencilWriteMask.Write( src ); } + FORCEINLINE void WriteClearColor( GLClearColor_t *src ) { m_ClearColor.Write( src ); } + FORCEINLINE void WriteClearDepth( GLClearDepth_t *src ) { m_ClearDepth.Write( src ); } + FORCEINLINE void WriteClearStencil( GLClearStencil_t *src ) { m_ClearStencil.Write( src ); } + + // debug stuff + void BeginFrame( void ); + void EndFrame( void ); + + // new interactive debug stuff +#if GLMDEBUG + void DebugDump( GLMDebugHookInfo *info, uint options, uint vertDumpMode ); + void DebugHook( GLMDebugHookInfo *info ); + void DebugPresent( void ); + void DebugClear( void ); +#endif + + FORCEINLINE void SetMaxUsedVertexShaderConstantsHint( uint nMaxConstants ); + FORCEINLINE DWORD GetCurrentOwnerThreadId() const { return m_nCurOwnerThreadId; } + + protected: + friend class GLMgr; // only GLMgr can make GLMContext objects + friend class GLMRendererInfo; // only GLMgr can make GLMContext objects + friend class CGLMTex; // tex needs to be able to do binds + friend class CGLMFBO; // fbo needs to be able to do binds + friend class CGLMProgram; + friend class CGLMShaderPair; + friend class CGLMShaderPairCache; + friend class CGLMBuffer; + friend class CGLMBufferSpanManager; + friend class GLMTester; // tester class needs access back into GLMContext + + friend struct IDirect3D9; + friend struct IDirect3DDevice9; + friend struct IDirect3DQuery9; + + // methods------------------------------------------ + + // old GLMContext( GLint displayMask, GLint rendererID, PseudoNSGLContextPtr nsglShareCtx ); + GLMContext( IDirect3DDevice9 *pDevice, GLMDisplayParams *params ); + ~GLMContext(); + +#ifndef OSX + FORCEINLINE GLuint FindSamplerObject( const GLMTexSamplingParams &desiredParams ); +#endif + + FORCEINLINE void SetBufAndVertexAttribPointer( uint nIndex, GLuint nGLName, GLuint stride, GLuint datatype, GLboolean normalized, GLuint nCompCount, const void *pBuf, uint nRevision ) + { + VertexAttribs_t &curAttribs = m_boundVertexAttribs[nIndex]; + if ( nGLName != m_nBoundGLBuffer[kGLMVertexBuffer] ) + { + m_nBoundGLBuffer[kGLMVertexBuffer] = nGLName; + gGL->glBindBufferARB( GL_ARRAY_BUFFER_ARB, nGLName ); + } + else if ( ( curAttribs.m_pPtr == pBuf ) && + ( curAttribs.m_revision == nRevision ) && + ( curAttribs.m_stride == stride ) && + ( curAttribs.m_datatype == datatype ) && + ( curAttribs.m_normalized == normalized ) && + ( curAttribs.m_nCompCount == nCompCount ) ) + { + return; + } + + curAttribs.m_nCompCount = nCompCount; + curAttribs.m_datatype = datatype; + curAttribs.m_normalized = normalized; + curAttribs.m_stride = stride; + curAttribs.m_pPtr = pBuf; + curAttribs.m_revision = nRevision; + + gGL->glVertexAttribPointer( nIndex, nCompCount, datatype, normalized, stride, pBuf ); + } + + struct CurAttribs_t + { + uint m_nTotalBufferRevision; + IDirect3DVertexDeclaration9 *m_pVertDecl; + D3DStreamDesc m_streams[ D3D_MAX_STREAMS ]; + uint64 m_vtxAttribMap[2]; + }; + + CurAttribs_t m_CurAttribs; + + FORCEINLINE void ClearCurAttribs() + { + m_CurAttribs.m_nTotalBufferRevision = 0; + m_CurAttribs.m_pVertDecl = NULL; + memset( m_CurAttribs.m_streams, 0, sizeof( m_CurAttribs.m_streams ) ); + m_CurAttribs.m_vtxAttribMap[0] = 0xBBBBBBBBBBBBBBBBULL; + m_CurAttribs.m_vtxAttribMap[1] = 0xBBBBBBBBBBBBBBBBULL; + } + + FORCEINLINE void ReleasedShader() { NullProgram(); } + + // textures + FORCEINLINE void SelectTMU( int tmu ) + { + if ( tmu != m_activeTexture ) + { + gGL->glActiveTexture( GL_TEXTURE0 + tmu ); + m_activeTexture = tmu; + } + } + + void BindTexToTMU( CGLMTex *tex, int tmu ); + + // render targets / FBO's + void BindFBOToCtx( CGLMFBO *fbo, GLenum bindPoint = GL_FRAMEBUFFER_EXT ); // you can also choose GL_READ_FRAMEBUFFER_EXT / GL_DRAW_FRAMEBUFFER_EXT + + // buffers + FORCEINLINE void BindGLBufferToCtx( GLenum nGLBufType, GLuint nGLName, bool bForce = false ) + { + Assert( ( nGLBufType == GL_ARRAY_BUFFER_ARB ) || ( nGLBufType == GL_ELEMENT_ARRAY_BUFFER_ARB ) ); + + const uint nIndex = ( nGLBufType == GL_ARRAY_BUFFER_ARB ) ? kGLMVertexBuffer : kGLMIndexBuffer; + if ( ( bForce ) || ( m_nBoundGLBuffer[nIndex] != nGLName ) ) + { + m_nBoundGLBuffer[nIndex] = nGLName; + gGL->glBindBufferARB( nGLBufType, nGLName ); + } + } + + void BindBufferToCtx( EGLMBufferType type, CGLMBuffer *buff, bool force = false ); // does not twiddle any enables. + + FORCEINLINE void BindIndexBufferToCtx( CGLMBuffer *buff ); + FORCEINLINE void BindVertexBufferToCtx( CGLMBuffer *buff ); + + GLuint CreateTex( GLenum texBind, GLenum internalFormat ); + void CleanupTex( GLenum texBind, GLMTexLayout* pLayout, GLuint tex ); + void DestroyTex( GLenum texBind, GLMTexLayout* pLayout, GLuint tex ); + GLuint FillTexCache( bool holdOne, int newTextures ); + void PurgeTexCache( ); + + // debug font + void GenDebugFontTex( void ); + void DrawDebugText( float x, float y, float z, float drawCharWidth, float drawCharHeight, char *string ); + +#ifndef OSX + CPinnedMemoryBuffer *GetCurPinnedMemoryBuffer( ) { return &m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer]; } +#endif + + CPersistentBuffer* GetCurPersistentBuffer( EGLMBufferType type ) { return &( m_persistentBuffer[m_nCurPersistentBuffer][type] ); } + + // members------------------------------------------ + + // context + DWORD m_nCurOwnerThreadId; + uint m_nThreadOwnershipReleaseCounter; + + bool m_bUseSamplerObjects; + bool m_bTexClientStorage; + + IDirect3DDevice9 *m_pDevice; + GLMRendererInfoFields m_caps; + + bool m_displayParamsValid; // is there a param block copied in yet + GLMDisplayParams m_displayParams; // last known display config, either via constructor, or by SetDisplayParams... + +#if defined( USE_SDL ) + int m_pixelFormatAttribs[100]; // more than enough + PseudoNSGLContextPtr m_nsctx; + void * m_ctx; +#endif + bool m_bUseBoneUniformBuffers; // if true, we use two uniform buffers for vertex shader constants vs. one + + // texture form table + CGLMTexLayoutTable *m_texLayoutTable; + + // context state mirrors + + GLState m_AlphaTestEnable; + + GLState m_AlphaTestFunc; + + GLState m_CullFaceEnable; + GLState m_CullFrontFace; + GLState m_PolygonMode; + + GLState m_DepthBias; + + GLStateArray m_ClipPlaneEnable; + GLStateArray m_ClipPlaneEquation; // dxabstract puts them directly into param slot 253(0) and 254(1) + + GLState m_ScissorEnable; + GLState m_ScissorBox; + + GLState m_AlphaToCoverageEnable; + + GLState m_ViewportBox; + GLState m_ViewportDepthRange; + + GLState m_ColorMaskSingle; + GLStateArray m_ColorMaskMultiple; // need an official constant for the color buffers limit + + GLState m_BlendEnable; + GLState m_BlendFactor; + GLState m_BlendEquation; + GLState m_BlendColor; + GLState m_BlendEnableSRGB; // write to this one to transmit intent to write SRGB encoded pixels to drawing FB + bool m_FakeBlendEnableSRGB; // writes to above will be shunted here if fake SRGB is in effect. + + GLState m_DepthTestEnable; + GLState m_DepthFunc; + GLState m_DepthMask; + + GLState m_StencilTestEnable; // global stencil test enable + GLState m_StencilFunc; // holds front and back stencil funcs + GLStateArray m_StencilOp; // indexed: 0=front 1=back + GLState m_StencilWriteMask; + + GLState m_ClearColor; + GLState m_ClearDepth; + GLState m_ClearStencil; + + // texture bindings and sampler setup + int m_activeTexture; // mirror for glActiveTexture + GLMTexSampler m_samplers[GLM_SAMPLER_COUNT]; + + uint8 m_nDirtySamplerFlags[GLM_SAMPLER_COUNT]; // 0 if the sampler is dirty, 1 if not + uint32 m_nNumDirtySamplers; // # of unique dirty sampler indices in m_nDirtySamplers + uint8 m_nDirtySamplers[GLM_SAMPLER_COUNT + 1]; // dirty sampler indices + + void MarkAllSamplersDirty(); + + struct SamplerHashEntry + { + GLuint m_samplerObject; + GLMTexSamplingParams m_params; + }; + + enum + { + cSamplerObjectHashBits = 9, cSamplerObjectHashSize = 1 << cSamplerObjectHashBits + }; + SamplerHashEntry m_samplerObjectHash[cSamplerObjectHashSize]; + uint m_nSamplerObjectHashNumEntries; + + // texture lock tracking - CGLMTex objects share usage of this + CUtlVector< GLMTexLockDesc > m_texLocks; + + // render target binding - check before draw + // similar to tex sampler mechanism, we track "bound" from "chosen for drawing" separately, + // so binding for creation/setup need not disrupt any notion of what will be used at draw time + + CGLMFBO *m_boundDrawFBO; // FBO on GL_DRAW_FRAMEBUFFER bind point + CGLMFBO *m_boundReadFBO; // FBO on GL_READ_FRAMEBUFFER bind point + // ^ both are set if you bind to GL_FRAMEBUFFER_EXT + + CGLMFBO *m_drawingFBO; // what FBO should be bound at draw time (to both read/draw bp's). + + CGLMFBO *m_blitReadFBO; + CGLMFBO *m_blitDrawFBO; // scratch FBO's for framebuffer blit + + CGLMFBO *m_scratchFBO[ kGLMScratchFBOCount ]; // general purpose FBO's for internal use + + CUtlVector< CGLMFBO* > m_fboTable; // each live FBO goes in the table + + uint m_fragDataMask; + + // program bindings + EGLMProgramLang m_drawingLangAtFrameStart; // selector for start of frame (spills into m_drawingLang) + EGLMProgramLang m_drawingLang; // selector for which language we desire to draw with on the next batch + CGLMProgram *m_drawingProgram[ kGLMNumProgramTypes ]; + bool m_bDirtyPrograms; + + GLMProgramParamsF m_programParamsF[ kGLMNumProgramTypes ]; + GLMProgramParamsB m_programParamsB[ kGLMNumProgramTypes ]; + GLMProgramParamsI m_programParamsI[ kGLMNumProgramTypes ]; // two banks, but only the vertex one is used + EGLMParamWriteMode m_paramWriteMode; + + CGLMProgram *m_pNullFragmentProgram; // write opaque black. Activate when caller asks for null FP + + CGLMProgram *m_preloadTexVertexProgram; // programs to help preload textures (dummies) + CGLMProgram *m_preload2DTexFragmentProgram; + CGLMProgram *m_preload3DTexFragmentProgram; + CGLMProgram *m_preloadCubeTexFragmentProgram; + +#if defined( OSX ) && defined( GLMDEBUG ) + CGLMProgram *m_boundProgram[ kGLMNumProgramTypes ]; +#endif + + CGLMShaderPairCache *m_pairCache; // GLSL only + CGLMShaderPair *m_pBoundPair; // GLSL only + + FORCEINLINE void NewLinkedProgram() { ClearCurAttribs(); } + + //uint m_boundPairRevision; // GLSL only + //GLhandleARB m_boundPairProgram; // GLSL only + + // buffer bindings + GLuint m_nBoundGLBuffer[kGLMNumBufferTypes]; + + struct VertexAttribs_t + { + GLuint m_nCompCount; + GLenum m_datatype; + GLboolean m_normalized; + GLuint m_stride; + const void *m_pPtr; + uint m_revision; + }; + + VertexAttribs_t m_boundVertexAttribs[ kGLMVertexAttributeIndexMax ]; // tracked per attrib for dupe-set-absorb + uint m_lastKnownVertexAttribMask; // tracked for dupe-enable-absorb + int m_nNumSetVertexAttributes; + + // FIXME: Remove this, it's no longer used + GLMVertexSetup m_drawVertexSetup; + + EGLMAttribWriteMode m_attribWriteMode; + + bool m_slowCheckEnable; // turn this on or no native checking is done ("-glmassertslow" or "-glmsspewslow") + bool m_slowAssertEnable; // turn this on to assert on a non-native batch "-glmassertslow" + bool m_slowSpewEnable; // turn this on to log non-native batches to stdout "-glmspewslow" + bool m_checkglErrorsAfterEveryBatch; // turn this on to check for GL errors after each batch (slow) ("-glcheckerrors") + + // debug font texture + CGLMTex *m_debugFontTex; // might be NULL unless you call GenDebugFontTex + CGLMBuffer *m_debugFontIndices; // up to 1024 indices (256 chars times 4) + CGLMBuffer *m_debugFontVertices; // up to 1024 verts + + // batch/frame debugging support + int m_debugFrameIndex; // init to -1. Increment at BeginFrame + + int m_nMaxUsedVertexProgramConstantsHint; + + uint32 m_dwRenderThreadId; + volatile bool m_bIsThreading; + + uint m_nCurFrame; + uint m_nBatchCounter; + + struct TextureEntry_t + { + GLenum m_nTexBind; + GLenum m_nInternalFormat; + GLuint m_nTexName; + }; + + GLuint m_destroyPBO; + CUtlVector< TextureEntry_t > m_availableTextures; + +#ifndef OSX + enum { cNumPinnedMemoryBuffers = 4 }; + CPinnedMemoryBuffer m_PinnedMemoryBuffers[cNumPinnedMemoryBuffers]; + uint m_nCurPinnedMemoryBuffer; +#endif + + enum { cNumPersistentBuffers = 3 }; + CPersistentBuffer m_persistentBuffer[cNumPersistentBuffers][kGLMNumBufferTypes]; + uint m_nCurPersistentBuffer; + + void SaveColorMaskAndSetToDefault(); + void RestoreSavedColorMask(); + GLColorMaskSingle_t m_SavedColorMask; + +#if GLMDEBUG + // interactive (DebugHook) debug support + + // using these you can implement frame advance, batch single step, and batch rewind (let it run til next frame and hold on prev batch #) + int m_holdFrameBegin; // -1 if no hold req'd, otherwise # of frame to hold at (at beginframe time) + int m_holdFrameEnd; // -1 if no hold req'd, otherwise # of frame to hold at (at endframe time) + + int m_holdBatch,m_holdBatchFrame; // -1 if no hold, else # of batch&frame to hold at (both must be set) + // these can be expired/cleared to -1 if the frame passes without a hit + // may be desirable to re-pause in that event, as user was expecting a hold to occur + + bool m_debugDelayEnable; // allow sleep delay + uint m_debugDelay; // sleep time per hook call in microseconds (for usleep()) + + // pre-draw global toggles / options + bool m_autoClearColor,m_autoClearDepth,m_autoClearStencil; + float m_autoClearColorValues[4]; + + // debug knobs + int m_selKnobIndex; + float m_selKnobMinValue,m_selKnobMaxValue,m_selKnobIncrement; +#endif + +#if GL_BATCH_PERF_ANALYSIS + uint m_nTotalVSUniformCalls; + uint m_nTotalVSUniformBoneCalls; + uint m_nTotalVSUniformsSet; + uint m_nTotalVSUniformsBoneSet; + uint m_nTotalPSUniformCalls; + uint m_nTotalPSUniformsSet; + + CFlushDrawStatesStats m_FlushStats; +#endif +}; + +#ifndef OSX + +FORCEINLINE void GLMContext::DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, uint baseVertex, CGLMBuffer *pIndexBuf ) +{ +#if GL_ENABLE_INDEX_VERIFICATION + DrawRangeElementsNonInline( mode, start, end, count, type, indices, baseVertex, pIndexBuf ); +#else + +#if GLMDEBUG + GLM_FUNC; +#else + //tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %d-%d count:%d mode:%d type:%d", __FUNCTION__, start, end, count, mode, type ); +#endif + + ++m_nBatchCounter; + + SetIndexBuffer( pIndexBuf ); + + void *indicesActual = (void*)indices; + + if ( pIndexBuf->m_bPseudo ) + { + // you have to pass actual address, not offset + indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + } + if (pIndexBuf->m_bUsingPersistentBuffer) + { + indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + } + +//#if GLMDEBUG +#if 0 + bool hasVP = m_drawingProgram[ kGLMVertexProgram ] != NULL; + bool hasFP = m_drawingProgram[ kGLMFragmentProgram ] != NULL; + + // init debug hook information + GLMDebugHookInfo info; + memset( &info, 0, sizeof(info) ); + info.m_caller = eDrawElements; + + // relay parameters we're operating under + info.m_drawMode = mode; + info.m_drawStart = start; + info.m_drawEnd = end; + info.m_drawCount = count; + info.m_drawType = type; + info.m_drawIndices = indices; + + do + { + // obey global options re pre-draw clear + if ( m_autoClearColor || m_autoClearDepth || m_autoClearStencil ) + { + GLMPRINTF(("-- DrawRangeElements auto clear" )); + this->DebugClear(); + } + + // always sync with editable shader text prior to draw +#if GLMDEBUG + //FIXME disengage this path if context is in GLSL mode.. + // it will need fixes to get the shader pair re-linked etc if edits happen anyway. + + if (m_drawingProgram[ kGLMVertexProgram ]) + { + m_drawingProgram[ kGLMVertexProgram ]->SyncWithEditable(); + } + else + { + AssertOnce(!"drawing with no vertex program bound"); + } + + + if (m_drawingProgram[ kGLMFragmentProgram ]) + { + m_drawingProgram[ kGLMFragmentProgram ]->SyncWithEditable(); + } + else + { + AssertOnce(!"drawing with no fragment program bound"); + } +#endif + // do the drawing + if (hasVP && hasFP) + { + gGL->glDrawRangeElementsBaseVertex( mode, start, end, count, type, indicesActual, baseVertex ); + + if ( m_slowCheckEnable ) + { + CheckNative(); + } + } + this->DebugHook( &info ); + + } while ( info.m_loop ); +#else + Assert( m_drawingLang == kGLMGLSL ); + + if ( m_pBoundPair ) + { + gGL->glDrawRangeElementsBaseVertex( mode, start, end, count, type, indicesActual, baseVertex ); + +#if GLMDEBUG + if ( m_slowCheckEnable ) + { + CheckNative(); + } +#endif + } +#endif + +#endif // GL_ENABLE_INDEX_VERIFICATION +} + +#endif // #ifndef OSX + +FORCEINLINE void GLMContext::SetVertexProgram( CGLMProgram *pProg ) +{ + m_drawingProgram[kGLMVertexProgram] = pProg; + m_bDirtyPrograms = true; +} + +FORCEINLINE void GLMContext::SetFragmentProgram( CGLMProgram *pProg ) +{ + m_drawingProgram[kGLMFragmentProgram] = pProg ? pProg : m_pNullFragmentProgram; + m_bDirtyPrograms = true; +} + +// "slot" means a vec4-sized thing +// these write into .env parameter space +FORCEINLINE void GLMContext::SetProgramParametersF( EGLMProgramType type, uint baseSlot, float *slotData, uint slotCount ) +{ +#if GLMDEBUG + GLM_FUNC; +#endif + + Assert( baseSlot < kGLMProgramParamFloat4Limit ); + Assert( baseSlot+slotCount <= kGLMProgramParamFloat4Limit ); + +#if GLMDEBUG + GLMPRINTF(("-S-GLMContext::SetProgramParametersF %s slots %d - %d: ", (type==kGLMVertexProgram) ? "VS" : "FS", baseSlot, baseSlot + slotCount - 1 )); + for( uint i=0; i DXABSTRACT_VS_LAST_BONE_SLOT ) + { + m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, firstDirty - maxBoneSlots ); + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, highWater - maxBoneSlots ); + } + else if ( firstDirty >= DXABSTRACT_VS_FIRST_BONE_SLOT ) + { + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone = DXABSTRACT_VS_LAST_BONE_SLOT + 1; + + m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, DXABSTRACT_VS_FIRST_BONE_SLOT ); + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, highWater - maxBoneSlots ); + } + else + { + int nNumActualBones = ( DXABSTRACT_VS_LAST_BONE_SLOT + 1 ) - DXABSTRACT_VS_FIRST_BONE_SLOT; + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone, nNumActualBones ); + + m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, firstDirty ); + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, highWater - maxBoneSlots ); + } + } + } + else + { + m_programParamsF[type].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[type].m_dirtySlotHighWaterNonBone, (int)(baseSlot + slotCount) ); + m_programParamsF[type].m_firstDirtySlotNonBone = MIN( m_programParamsF[type].m_firstDirtySlotNonBone, (int)baseSlot ); + } +} + +FORCEINLINE void GLMContext::SetProgramParametersB( EGLMProgramType type, uint baseSlot, int *slotData, uint boolCount ) +{ +#if GLMDEBUG + GLM_FUNC; +#endif + + Assert( m_drawingLang == kGLMGLSL ); + Assert( type==kGLMVertexProgram || type==kGLMFragmentProgram ); + + Assert( baseSlot < kGLMProgramParamBoolLimit ); + Assert( baseSlot+boolCount <= kGLMProgramParamBoolLimit ); + +#if GLMDEBUG + GLMPRINTF(("-S-GLMContext::SetProgramParametersB %s bools %d - %d: ", (type==kGLMVertexProgram) ? "VS" : "FS", baseSlot, baseSlot + boolCount - 1 )); + for( uint i=0; i m_programParamsB[type].m_dirtySlotCount) + m_programParamsB[type].m_dirtySlotCount = baseSlot+boolCount; +} + +FORCEINLINE void GLMContext::SetProgramParametersI( EGLMProgramType type, uint baseSlot, int *slotData, uint slotCount ) // groups of 4 ints... +{ +#if GLMDEBUG + GLM_FUNC; +#endif + + Assert( m_drawingLang == kGLMGLSL ); + Assert( type==kGLMVertexProgram ); + + Assert( baseSlot < kGLMProgramParamInt4Limit ); + Assert( baseSlot+slotCount <= kGLMProgramParamInt4Limit ); + +#if GLMDEBUG + GLMPRINTF(("-S-GLMContext::SetProgramParametersI %s slots %d - %d: ", (type==kGLMVertexProgram) ? "VS" : "FS", baseSlot, baseSlot + slotCount - 1 )); + for( uint i=0; i m_programParamsI[type].m_dirtySlotCount) + { + m_programParamsI[type].m_dirtySlotCount = baseSlot + slotCount; + } +} + +FORCEINLINE void GLMContext::SetSamplerDirty( int sampler ) +{ + Assert( sampler < GLM_SAMPLER_COUNT ); + m_nDirtySamplers[m_nNumDirtySamplers] = sampler; + m_nNumDirtySamplers += m_nDirtySamplerFlags[sampler]; + m_nDirtySamplerFlags[sampler] = 0; +} + +FORCEINLINE void GLMContext::SetSamplerTex( int sampler, CGLMTex *tex ) +{ + Assert( sampler < GLM_SAMPLER_COUNT ); + m_samplers[sampler].m_pBoundTex = tex; + if ( tex ) + { + if ( !gGL->m_bHave_GL_EXT_direct_state_access ) + { + if ( sampler != m_activeTexture ) + { + gGL->glActiveTexture( GL_TEXTURE0 + sampler ); + m_activeTexture = sampler; + } + + gGL->glBindTexture( tex->m_texGLTarget, tex->m_texName ); + } + else + { + gGL->glBindMultiTextureEXT( GL_TEXTURE0 + sampler, tex->m_texGLTarget, tex->m_texName ); + } + } + + if ( !m_bUseSamplerObjects ) + { + SetSamplerDirty( sampler ); + } +} + +FORCEINLINE void GLMContext::SetSamplerMinFilter( int sampler, GLenum Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_minFilter = Value; +} + +FORCEINLINE void GLMContext::SetSamplerMagFilter( int sampler, GLenum Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_magFilter = Value; +} + +FORCEINLINE void GLMContext::SetSamplerMipFilter( int sampler, GLenum Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_mipFilter = Value; +} + +FORCEINLINE void GLMContext::SetSamplerAddressU( int sampler, GLenum Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS) ); + m_samplers[sampler].m_samp.m_packed.m_addressU = Value; +} + +FORCEINLINE void GLMContext::SetSamplerAddressV( int sampler, GLenum Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS) ); + m_samplers[sampler].m_samp.m_packed.m_addressV = Value; +} + +FORCEINLINE void GLMContext::SetSamplerAddressW( int sampler, GLenum Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS) ); + m_samplers[sampler].m_samp.m_packed.m_addressW = Value; +} + +FORCEINLINE void GLMContext::SetSamplerStates( int sampler, GLenum AddressU, GLenum AddressV, GLenum AddressW, GLenum minFilter, GLenum magFilter, GLenum mipFilter ) +{ + Assert( AddressU < ( 1 << GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS) ); + Assert( AddressV < ( 1 << GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS) ); + Assert( AddressW < ( 1 << GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS) ); + Assert( minFilter < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS ) ); + Assert( magFilter < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS ) ); + Assert( mipFilter < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS ) ); + + GLMTexSamplingParams ¶ms = m_samplers[sampler].m_samp; + params.m_packed.m_addressU = AddressU; + params.m_packed.m_addressV = AddressV; + params.m_packed.m_addressW = AddressW; + params.m_packed.m_minFilter = minFilter; + params.m_packed.m_magFilter = magFilter; + params.m_packed.m_mipFilter = mipFilter; +} + +FORCEINLINE void GLMContext::SetSamplerBorderColor( int sampler, DWORD Value ) +{ + m_samplers[sampler].m_samp.m_borderColor = Value; +} + +FORCEINLINE void GLMContext::SetSamplerMipMapLODBias( int sampler, DWORD Value ) +{ + // not currently supported +} + +FORCEINLINE void GLMContext::SetSamplerMaxMipLevel( int sampler, DWORD Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_minLOD = Value; +} + +FORCEINLINE void GLMContext::SetSamplerMaxAnisotropy( int sampler, DWORD Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_MAX_ANISO_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_maxAniso = Value; +} + +FORCEINLINE void GLMContext::SetSamplerSRGBTexture( int sampler, DWORD Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_SRGB_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_srgb = Value; +} + +FORCEINLINE void GLMContext::SetShadowFilter( int sampler, DWORD Value ) +{ + Assert( Value < ( 1 << GLM_PACKED_SAMPLER_PARAMS_COMPARE_MODE_BITS ) ); + m_samplers[sampler].m_samp.m_packed.m_compareMode = Value; +} + +FORCEINLINE void GLMContext::BindIndexBufferToCtx( CGLMBuffer *buff ) +{ + GLMPRINTF(( "--- GLMContext::BindIndexBufferToCtx buff %p, GL name %d", buff, (buff) ? buff->m_nHandle : -1 )); + + Assert( !buff || ( buff->m_buffGLTarget == GL_ELEMENT_ARRAY_BUFFER_ARB ) ); + + GLuint nGLName = buff ? buff->GetHandle() : 0; + + if ( m_nBoundGLBuffer[ kGLMIndexBuffer] == nGLName ) + return; + + m_nBoundGLBuffer[ kGLMIndexBuffer] = nGLName; + gGL->glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, nGLName ); +} + +FORCEINLINE void GLMContext::BindVertexBufferToCtx( CGLMBuffer *buff ) +{ + GLMPRINTF(( "--- GLMContext::BindVertexBufferToCtx buff %p, GL name %d", buff, (buff) ? buff->m_nHandle : -1 )); + + Assert( !buff || ( buff->m_buffGLTarget == GL_ARRAY_BUFFER_ARB ) ); + + GLuint nGLName = buff ? buff->GetHandle() : 0; + + if ( m_nBoundGLBuffer[ kGLMVertexBuffer] == nGLName ) + return; + + m_nBoundGLBuffer[ kGLMVertexBuffer] = nGLName; + gGL->glBindBufferARB( GL_ARRAY_BUFFER_ARB, nGLName ); +} + +FORCEINLINE void GLMContext::SetMaxUsedVertexShaderConstantsHint( uint nMaxConstants ) +{ + static bool bUseMaxVertexShadeConstantHints = !CommandLine()->CheckParm("-disablemaxvertexshaderconstanthints"); + if ( bUseMaxVertexShadeConstantHints ) + { + m_nMaxUsedVertexProgramConstantsHint = nMaxConstants; + } +} + +struct GLMTestParams +{ + GLMContext *m_ctx; + int *m_testList; // -1 termed + + bool m_glErrToDebugger; + bool m_glErrToConsole; + + bool m_intlErrToDebugger; + bool m_intlErrToConsole; + + int m_frameCount; // how many frames to test. +}; + +class GLMTester +{ + public: + + GLMTester(GLMTestParams *params); + ~GLMTester(); + + + // optionally callable by test routines to get basic drawables wired up + void StdSetup( void ); + void StdCleanup( void ); + + // callable by test routines to clear the frame or present it + void Clear( void ); + void Present( int seed ); + + // error reporting + void CheckGLError( const char *comment ); // obey m_params setting for console / debugger response + void InternalError( int errcode, char *comment ); // if errcode!=0, obey m_params setting for console / debugger response + + void RunTests(); + + void RunOneTest( int testindex ); + + // test routines themselves + void Test0(); + void Test1(); + void Test2(); + void Test3(); + + GLMTestParams m_params; // copy of caller's params, do not mutate... + + // std-setup stuff + int m_drawWidth, m_drawHeight; + CGLMFBO *m_drawFBO; + CGLMTex *m_drawColorTex; + CGLMTex *m_drawDepthTex; +}; + +class CShowPixelsParams +{ +public: + GLuint m_srcTexName; + int m_width,m_height; + bool m_vsyncEnable; + bool m_fsEnable; // want receiving view to be full screen. for now, just target the main screen. extend later. + bool m_useBlit; // use FBO blit - sending context says it is available. + bool m_noBlit; // the back buffer has already been populated by the caller (perhaps via direct MSAA resolve from multisampled RT tex) + bool m_onlySyncView; // react to full/windowed state change only, do not present bits +}; + +#define kMaxCrawlFrames 100 +#define kMaxCrawlText (kMaxCrawlFrames * 256) +class CStackCrawlParams +{ + public: + uint m_frameLimit; // input: max frames to retrieve + uint m_frameCount; // output: frames found + void *m_crawl[kMaxCrawlFrames]; // call site addresses + char *m_crawlNames[kMaxCrawlFrames]; // pointers into text following, one per decoded name + char m_crawlText[kMaxCrawlText]; +}; + +#endif // GLMGR_H diff --git a/public/togl/linuxwin/glmgrbasics.h b/public/togl/linuxwin/glmgrbasics.h new file mode 100644 index 0000000..a32938a --- /dev/null +++ b/public/togl/linuxwin/glmgrbasics.h @@ -0,0 +1,332 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// glmgrbasics.h +// types, common headers, forward declarations, utilities +// +//=============================================================================== + +#ifndef GLMBASICS_H +#define GLMBASICS_H + +#pragma once + +#ifdef USE_SDL +#include "SDL_opengl.h" +#endif + +#ifdef OSX + #include + #include + #include + #include + +#ifndef MAC_OS_X_VERSION_10_9 + #include + #include +#endif +#endif + +#include "tier0/platform.h" + +#include "bitmap/imageformat.h" +#include "bitvec.h" +#include "tier1/checksum_md5.h" +#include "tier1/utlvector.h" +#include "tier1/convar.h" + +#include + +#include "dxabstract_types.h" + +struct GLMRect; +typedef void *PseudoGLContextPtr; + +// types + + // 3-d integer box (used for texture lock/unlock etc) +struct GLMRegion +{ + int xmin,xmax; + int ymin,ymax; + int zmin,zmax; +}; + +struct GLMRect // follows GL convention - if coming from the D3D rect you will need to fiddle the Y's +{ + int xmin; // left + int ymin; // bottom + int xmax; // right + int ymax; // top +}; + +// macros + +//#define GLMassert(x) assert(x) + +// forward decls +class GLMgr; // singleton +class GLMContext; // GL context +class CGLMContextTester; // testing class +class CGLMTex; +class CGLMFBO; +class CGLMProgram; +class CGLMBuffer; + + +// utilities + +typedef enum +{ + // D3D codes + eD3D_DEVTYPE, + eD3D_FORMAT, + eD3D_RTYPE, + eD3D_USAGE, + eD3D_RSTATE, // render state + eD3D_SIO, // D3D shader bytecode + eD3D_VTXDECLUSAGE, + + // CGL codes + eCGL_RENDID, + + // OpenGL error codes + eGL_ERROR, + + // OpenGL enums + eGL_ENUM, + eGL_RENDERER + +} GLMThing_t; + +// these will look at the string to guess its flavor: <, >, ---, -M-, -S- +#ifdef TOGL_DLL_EXPORT + DLL_EXPORT const char* GLMDecode( GLMThing_t type, unsigned long value ); // decode a numeric const +#else + DLL_IMPORT const char* GLMDecode( GLMThing_t type, unsigned long value ); // decode a numeric const +#endif + +const char* GLMDecodeMask( GLMThing_t type, unsigned long value ); // decode a bitmask + +FORCEINLINE void GLMStop( void ) { DXABSTRACT_BREAK_ON_ERROR(); } + +void GLMEnableTrace( bool on ); + +//=============================================================================== +// output functions + +// expose these in release now +// Mimic PIX events so we can decorate debug spew +DLL_EXPORT void GLMBeginPIXEvent( const char *str ); +DLL_EXPORT void GLMEndPIXEvent( void ); + +class CScopedGLMPIXEvent +{ + CScopedGLMPIXEvent( const CScopedGLMPIXEvent & ); + CScopedGLMPIXEvent& operator= ( const CScopedGLMPIXEvent & ); +public: + inline CScopedGLMPIXEvent( const char *pName ) { GLMBeginPIXEvent( pName ); } + inline ~CScopedGLMPIXEvent() { GLMEndPIXEvent( ); } +}; + +#if GLMDEBUG + + +//=============================================================================== +// classes + +// helper class making function tracking easier to wire up + +class GLMFuncLogger +{ + public: + + // simple function log + GLMFuncLogger( const char *funcName ) + { + m_funcName = funcName; + m_earlyOut = false; + + GLMPrintf( ">%s", m_funcName ); + }; + + // more advanced version lets you pass args (i.e. called parameters or anything else of interest) + // no macro for this one, since no easy way to pass through the args as well as the funcname + GLMFuncLogger( const char *funcName, char *fmt, ... ) + { + m_funcName = funcName; + m_earlyOut = false; + + // this acts like GLMPrintf here + // all the indent policy is down in GLMPrintfVA + // which means we need to inject a ">" at the front of the format string to make this work... sigh. + + char modifiedFmt[2000]; + modifiedFmt[0] = '>'; + strcpy( modifiedFmt+1, fmt ); + + va_list vargs; + va_start(vargs, fmt); + GLMPrintfVA( modifiedFmt, vargs ); + va_end( vargs ); + } + + ~GLMFuncLogger( ) + { + if (m_earlyOut) + { + GLMPrintf( "<%s (early out)", m_funcName ); + } + else + { + GLMPrintf( "<%s", m_funcName ); + } + }; + + void EarlyOut( void ) + { + m_earlyOut = true; + }; + + const char *m_funcName; // set at construction time + bool m_earlyOut; +}; + +// handy macro to go with the function tracking class +#define GLM_FUNC GLMFuncLogger _logger_ ( __FUNCTION__ ) +#else +#define GLM_FUNC tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ ) +#endif + + +// class to keep an in-memory mirror of a file which may be getting edited during run +class CGLMFileMirror +{ +public: + CGLMFileMirror( char *fullpath ); // just associates mirror with file. if file exists it will be read. + //if non existent it will be created with size zero + ~CGLMFileMirror( ); + + bool HasData( void ); // see if data avail + void GetData( char **dataPtr, uint *dataSizePtr ); // read it out + void SetData( char *data, uint dataSize ); // put data in (and write it to disk) + bool PollForChanges( void ); // check disk copy. If different, read it back in and return true. + + void UpdateStatInfo( void ); // make sure stat info is current for our file + void ReadFile( void ); + void WriteFile( void ); + + void OpenInEditor( bool foreground=false ); // pass TRUE if you would like the editor to pop to foreground + + /// how about a "wait for change" method.. + + char *m_path; // fullpath to file + bool m_exists; + struct stat m_stat; // stat results for the file (last time checked) + + char *m_data; // content of file + uint m_size; // length of content + +}; + +// class based on the file mirror, that makes it easy to edit them outside the app. + +// it receives an initial block of text from the engine, and hashes it. ("orig") +// it munges it by duplicating all the text after the "!!" line, and appending it in commented form. ("munged") +// a mirror file is activated, using a filename based on the hash from the orig text. +// if there is already content on disk matching that filename, use that content *unless* the 'blitz' parameter is set. +// (i.e. engine is instructing this subsystem to wipe out any old/modified variants of the text) + + +class CGLMEditableTextItem +{ +public: + CGLMEditableTextItem( char *text, uint size, bool forceOverwrite, char *prefix, char *suffix = NULL ); // create a text blob from text source, optional filename suffix + ~CGLMEditableTextItem( ); + + bool HasData( void ); + bool PollForChanges( void ); // return true if stale i.e. you need to get a new edition + void GetCurrentText( char **textOut, uint *sizeOut ); // query for read access to the active blob (could be the original, could be external edited copy) + void OpenInEditor( bool foreground=false ); // call user attention to this text + + // internal methods + void GenHashOfOrigText( void ); + void GenBaseNameAndFullPath( char *prefix, char *suffix ); + void GenMungedText( bool fromMirror ); + + // members + // orig + uint m_origSize; + char *m_origText; // what was submitted + unsigned char m_origDigest[MD5_DIGEST_LENGTH]; // digest of what was submitted + + // munged + uint m_mungedSize; + char *m_mungedText; // re-processed edition, initial content submission to the file mirror + + // mirror + char *m_mirrorBaseName; // generated from the hash of the orig text, plus the label / prefix + char *m_mirrorFullPath; // base name + CGLMFileMirror *m_mirror; // file mirror itself. holds "official" copy for GetCurrentText to return. +}; + + +// debug font +extern unsigned char g_glmDebugFontMap[16384]; + +// class for cracking multi-part text blobs +// sections are demarcated by beginning-of-line markers submitted in a table by the caller + +struct GLMTextSection +{ + int m_markerIndex; // based on table of markers passed in to constructor + uint m_textOffset; // where is the text - offset + int m_textLength; // how big is the section +}; + +class CGLMTextSectioner +{ +public: + CGLMTextSectioner( char *text, int textSize, const char **markers ); // constructor finds all the sections + ~CGLMTextSectioner( ); + + int Count( void ); // how many sections found + void GetSection( int index, uint *offsetOut, uint *lengthOut, int *markerIndexOut ); + // find section, size, what marker + // note that more than one section can be marked similarly. + // so policy isn't made here, you walk the sections and decide what to do if there are dupes. + + //members + + //section table + CUtlVector< GLMTextSection > m_sectionTable; +}; + +#ifndef OSX +void GLMGPUTimestampManagerInit(); +void GLMGPUTimestampManagerDeinit(); +void GLMGPUTimestampManagerTick(); +#endif + +#endif // GLMBASICS_H diff --git a/public/togl/linuxwin/glmgrext.h b/public/togl/linuxwin/glmgrext.h new file mode 100644 index 0000000..393942a --- /dev/null +++ b/public/togl/linuxwin/glmgrext.h @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// glmgrext.h +// helper file for extension testing and runtime importing of entry points +// +//=============================================================================== + +#pragma once + +#ifdef OSX +#include +#include +#elif defined(DX_TO_GL_ABSTRACTION) +#include +#include +#else +#error +#endif + +#ifndef GL_EXT_framebuffer_sRGB + #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 + #define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#endif + +#ifndef ARB_texture_rg + #define GL_COMPRESSED_RED 0x8225 + #define GL_COMPRESSED_RG 0x8226 + #define GL_RG 0x8227 + #define GL_RG_INTEGER 0x8228 + #define GL_R8 0x8229 + #define GL_R16 0x822A + #define GL_RG8 0x822B + #define GL_RG16 0x822C + #define GL_R16F 0x822D + #define GL_R32F 0x822E + #define GL_RG16F 0x822F + #define GL_RG32F 0x8230 + #define GL_R8I 0x8231 + #define GL_R8UI 0x8232 + #define GL_R16I 0x8233 + #define GL_R16UI 0x8234 + #define GL_R32I 0x8235 + #define GL_R32UI 0x8236 + #define GL_RG8I 0x8237 + #define GL_RG8UI 0x8238 + #define GL_RG16I 0x8239 + #define GL_RG16UI 0x823A + #define GL_RG32I 0x823B + #define GL_RG32UI 0x823C +#endif + +#ifndef GL_EXT_bindable_uniform + #define GL_UNIFORM_BUFFER_EXT 0x8DEE +#endif + +// unpublished extension enums (thus the "X") + +// from EXT_framebuffer_multisample_blit_scaled.. +#define XGL_SCALED_RESOLVE_FASTEST_EXT 0x90BA +#define XGL_SCALED_RESOLVE_NICEST_EXT 0x90BB + +#ifndef GL_TEXTURE_MINIMIZE_STORAGE_APPLE +#define GL_TEXTURE_MINIMIZE_STORAGE_APPLE 0x85B6 +#endif + +#ifndef GL_ALL_COMPLETED_NV +#define GL_ALL_COMPLETED_NV 0x84F2 +#endif + +#ifndef GL_MAP_READ_BIT +#define GL_MAP_READ_BIT 0x0001 +#endif + +#ifndef GL_MAP_WRITE_BIT +#define GL_MAP_WRITE_BIT 0x0002 +#endif + +#ifndef GL_MAP_INVALIDATE_RANGE_BIT +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#endif + +#ifndef GL_MAP_INVALIDATE_BUFFER_BIT +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#endif + +#ifndef GL_MAP_FLUSH_EXPLICIT_BIT +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#endif + +#ifndef GL_MAP_UNSYNCHRONIZED_BIT +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#endif + +#ifndef GL_MAP_PERSISTENT_BIT +#define GL_MAP_PERSISTENT_BIT 0x0040 +#endif + +#ifndef GL_MAP_COHERENT_BIT +#define GL_MAP_COHERENT_BIT 0x0080 +#endif + diff --git a/public/togl/rendermechanism.h b/public/togl/rendermechanism.h new file mode 100644 index 0000000..47be332 --- /dev/null +++ b/public/togl/rendermechanism.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// TOGL CODE LICENSE +// +// Copyright 2011-2014 Valve Corporation +// All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#ifndef RENDERMECHANISM_H +#define RENDERMECHANISM_H + +#if defined(DX_TO_GL_ABSTRACTION) + +#undef PROTECTED_THINGS_ENABLE + +#include +#include + +#include "tier0/basetypes.h" +#include "tier0/platform.h" + +#include "togl/linuxwin/glmdebug.h" +#include "togl/linuxwin/glbase.h" +#include "togl/linuxwin/glentrypoints.h" +#include "togl/linuxwin/glmdisplay.h" +#include "togl/linuxwin/glmdisplaydb.h" +#include "togl/linuxwin/glmgrbasics.h" +#include "togl/linuxwin/glmgrext.h" +#include "togl/linuxwin/cglmbuffer.h" +#include "togl/linuxwin/cglmtex.h" +#include "togl/linuxwin/cglmfbo.h" +#include "togl/linuxwin/cglmprogram.h" +#include "togl/linuxwin/cglmquery.h" +#include "togl/linuxwin/glmgr.h" +#include "togl/linuxwin/dxabstract_types.h" +#include "togl/linuxwin/dxabstract.h" + +#else + //USE_ACTUAL_DX + #ifdef WIN32 + #ifdef _X360 + #include "d3d9.h" + #include "d3dx9.h" + #else + #include + #include "../../dx9sdk/include/d3d9.h" + #include "../../dx9sdk/include/d3dx9.h" + #endif + typedef HWND VD3DHWND; + #endif + + #define GLMPRINTF(args) + #define GLMPRINTSTR(args) + #define GLMPRINTTEXT(args) +#endif // defined(DX_TO_GL_ABSTRACTION) + +#endif // RENDERMECHANISM_H diff --git a/public/toolframework/iclientenginetools.h b/public/toolframework/iclientenginetools.h new file mode 100644 index 0000000..32c460a --- /dev/null +++ b/public/toolframework/iclientenginetools.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ICLIENTENGINETOOLS_H +#define ICLIENTENGINETOOLS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "toolframework/itoolentity.h" // HTOOLHANDLE + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class KeyValues; +struct AudioState_t; + + +//----------------------------------------------------------------------------- +// Purpose: Exported from engine to client .dll to marshall tool framework calls +// into IToolSystems +//----------------------------------------------------------------------------- +class IClientEngineTools : public IBaseInterface +{ +public: + // Level init, shutdown + virtual void LevelInitPreEntityAllTools() = 0; + // entities are created / spawned / precached here + virtual void LevelInitPostEntityAllTools() = 0; + + virtual void LevelShutdownPreEntityAllTools() = 0; + // Entities are deleted / released here... + virtual void LevelShutdownPostEntityAllTools() = 0; + + virtual void PreRenderAllTools() = 0; + virtual void PostRenderAllTools() = 0; + + virtual void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ) = 0; + + virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ) = 0; + virtual bool SetupEngineView( Vector &origin, QAngle &angles, float &fov ) = 0; + virtual bool SetupAudioState( AudioState_t &audioState ) = 0; + + // Paintmode is an enum declared in ienginevgui.h + virtual void VGui_PreRenderAllTools( int paintMode ) = 0; + virtual void VGui_PostRenderAllTools( int paintMode ) = 0; + + virtual bool IsThirdPersonCamera( ) = 0; + + virtual bool InToolMode() = 0; +}; + +#define VCLIENTENGINETOOLS_INTERFACE_VERSION "VCLIENTENGINETOOLS001" + +#endif // ICLIENTENGINETOOLS_H diff --git a/public/toolframework/ienginetool.h b/public/toolframework/ienginetool.h new file mode 100644 index 0000000..cf4bf89 --- /dev/null +++ b/public/toolframework/ienginetool.h @@ -0,0 +1,233 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef IENGINETOOL_H +#define IENGINETOOL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "soundflags.h" +#include "video/ivideoservices.h" +#include "ispatialpartition.h" + +class CViewSetup; +class IToolSystem; +class KeyValues; +class ITraceFilter; +class CBaseTrace; +struct dlight_t; +struct Ray_t; +struct AudioState_t; + + +typedef bool (*FnQuitHandler)( void *pvUserData ); + +#ifndef MAX_DLIGHTS +#define MAX_DLIGHTS 32 +#endif + +// Exposed from engine to all tools, simplest interface +class IEngineToolFramework : public IBaseInterface +{ +public: + // Input system overrides TBD + // Something like this + //virtual void AddMessageHandler( int wm_message, bool (*pfnCallback)( int wm_message, int wParam, int lParam ) ) = 0; + //virtual void RemoveMessageHanlder( int wm_message, bool (*pfnCallbackToRemove)( int wm_message, int wParam, int lParam ) ) = 0; + + // Helpers for implementing a tool switching UI + virtual int GetToolCount() const = 0; + virtual char const *GetToolName( int index ) const = 0; + virtual void SwitchToTool( int index ) = 0; + + virtual bool IsTopmostTool( const IToolSystem *sys ) const = 0; + + virtual const IToolSystem *GetToolSystem( int index ) const = 0; + virtual IToolSystem *GetTopmostTool() = 0; + + // Take over input + virtual void ShowCursor( bool show ) = 0; + virtual bool IsCursorVisible() const = 0; +}; + +#define VENGINETOOLFRAMEWORK_INTERFACE_VERSION "VENGINETOOLFRAMEWORK003" + +struct model_t; +struct studiohdr_t; + +#include "toolframework/itoolentity.h" + +// Exposed from engine to tools via, more involved version of above +class IEngineTool : public IEngineToolFramework +{ +public: + virtual void GetServerFactory( CreateInterfaceFn& factory ) = 0; + virtual void GetClientFactory( CreateInterfaceFn& factory ) = 0; + + virtual float GetSoundDuration( const char *pszName ) = 0; + virtual bool IsSoundStillPlaying( int guid ) = 0; + // Returns the guid of the sound + virtual int StartSound( + int iUserData, + bool staticsound, + int iEntIndex, + int iChannel, + const char *pSample, + float flVolume, + soundlevel_t iSoundlevel, + const Vector& origin, + const Vector& direction, + int iFlags = 0, + int iPitch = PITCH_NORM, + bool bUpdatePositions = true, + float delay = 0.0f, + int speakerentity = -1 ) = 0; + + virtual void StopSoundByGuid( int guid ) = 0; + + // Returns how long the sound is + virtual float GetSoundDuration( int guid ) = 0; + + // Returns if the sound is looping + virtual bool IsLoopingSound( int guid ) = 0; + virtual void ReloadSound( const char *pSample ) = 0; + virtual void StopAllSounds( ) = 0; + virtual float GetMono16Samples( const char *pszName, CUtlVector< short >& sampleList ) = 0; + virtual void SetAudioState( const AudioState_t &audioState ) = 0; + + // Issue a console command + virtual void Command( char const *cmd ) = 0; + // Flush console command buffer right away + virtual void Execute() = 0; + + virtual char const *GetCurrentMap() = 0; + virtual void ChangeToMap( char const *mapname ) = 0; + virtual bool IsMapValid( char const *mapname ) = 0; + + // Method for causing engine to call client to render scene with no view model or overlays + // See cdll_int.h for enum RenderViewInfo_t for specifying whatToRender + virtual void RenderView( CViewSetup &view, int nFlags, int whatToRender ) = 0; + + // Returns true if the player is fully connected and active in game (i.e, not still loading) + virtual bool IsInGame() = 0; + // Returns true if the player is connected, but not necessarily active in game (could still be loading) + virtual bool IsConnected() = 0; + + virtual int GetMaxClients() = 0; // Tools might want to ensure single player, e.g. + + virtual bool IsGamePaused() = 0; + virtual void SetGamePaused( bool paused ) = 0; + + virtual float GetTimescale() = 0; // Could do this via ConVar system, too + virtual void SetTimescale( float scale ) = 0; + + // Real time is unscaled, but is updated once per frame + virtual float GetRealTime() = 0; + virtual float GetRealFrameTime() = 0; // unscaled + + // Get high precision timer (for profiling?) + virtual float Time() = 0; + + // Host time is scaled + virtual float HostFrameTime() = 0; // host_frametime + virtual float HostTime() = 0; // host_time + virtual int HostTick() = 0; // host_tickcount + virtual int HostFrameCount() = 0; // total famecount + + virtual float ServerTime() = 0; // gpGlobals->curtime on server + virtual float ServerFrameTime() = 0; // gpGlobals->frametime on server + virtual int ServerTick() = 0; // gpGlobals->tickcount on server + virtual float ServerTickInterval() = 0; // tick interval on server + + virtual float ClientTime() = 0; // gpGlobals->curtime on client + virtual float ClientFrameTime() = 0; // gpGlobals->frametime on client + virtual int ClientTick() = 0; // gpGlobals->tickcount on client + + virtual void SetClientFrameTime( float frametime ) = 0; // gpGlobals->frametime on client + + // Currently the engine doesn't like to do networking when it's paused, but if a tool changes entity state, it can be useful to force + // a network update to get that state over to the client + virtual void ForceUpdateDuringPause() = 0; + + // Maybe through modelcache??? + virtual model_t *GetModel( HTOOLHANDLE hEntity ) = 0; + // Get the .mdl file used by entity (if it's a cbaseanimating) + virtual studiohdr_t *GetStudioModel( HTOOLHANDLE hEntity ) = 0; + + // SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this) + // Prints the formatted string to the notification area of the screen ( down the right hand edge + // numbered lines starting at position 0 + virtual void Con_NPrintf( int pos, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + // SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this) + // Similar to Con_NPrintf, but allows specifying custom text color and duration information + virtual void Con_NXPrintf( const struct con_nprint_s *info, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // Get the current game directory (hl2, tf2, hl1, cstrike, etc.) + virtual void GetGameDir( char *szGetGameDir, int maxlength ) = 0; + +// Do we need separate rects for the 3d "viewport" vs. the tools surface??? and can we control viewports from + virtual void GetScreenSize( int& width, int &height ) = 0; + + // GetRootPanel(VPANEL) + + // Sets the location of the main view + virtual void SetMainView( const Vector &vecOrigin, const QAngle &angles ) = 0; + + // Gets the player view + virtual bool GetPlayerView( CViewSetup &playerView, int x, int y, int w, int h ) = 0; + + // From a location on the screen, figure out the vector into the world + virtual void CreatePickingRay( const CViewSetup &viewSetup, int x, int y, Vector& org, Vector& forward ) = 0; + + // precache methods + virtual bool PrecacheSound( const char *pName, bool bPreload = false ) = 0; + virtual bool PrecacheModel( const char *pName, bool bPreload = false ) = 0; + + virtual void InstallQuitHandler( void *pvUserData, FnQuitHandler func ) = 0; + virtual void TakeTGAScreenShot( char const *filename, int width, int height ) = 0; + // Even if game is paused, force networking to update to get new server state down to client + virtual void ForceSend() = 0; + + virtual bool IsRecordingMovie() = 0; + + // NOTE: Params can contain file name, frame rate, output avi, output raw, and duration + virtual void StartMovieRecording( KeyValues *pMovieParams ) = 0; + virtual void EndMovieRecording() = 0; + virtual void CancelMovieRecording() = 0; + virtual IVideoRecorder *GetActiveVideoRecorder() = 0; + + virtual void StartRecordingVoiceToFile( char const *filename, char const *pPathID = 0 ) = 0; + virtual void StopRecordingVoiceToFile() = 0; + virtual bool IsVoiceRecording() = 0; + + // A version that simply accepts a ray (can work as a traceline or tracehull) + virtual void TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace ) = 0; // client version + virtual void TraceRayServer( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace ) = 0; + + virtual bool IsConsoleVisible() = 0; + + virtual int GetPointContents( const Vector &vecPosition ) = 0; + + virtual int GetActiveDLights( dlight_t *pList[MAX_DLIGHTS] ) = 0; + virtual int GetLightingConditions( const Vector &vecPosition, Vector *pColors, int nMaxLocalLights, LightDesc_t *pLocalLights ) = 0; + + virtual void GetWorldToScreenMatrixForView( const CViewSetup &view, VMatrix *pVMatrix ) = 0; + + // Collision support + virtual SpatialPartitionHandle_t CreatePartitionHandle( IHandleEntity *pEntity, + SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs ) = 0; + virtual void DestroyPartitionHandle( SpatialPartitionHandle_t hPartition ) = 0; + virtual void InstallPartitionQueryCallback( IPartitionQueryCallback *pQuery ) = 0; + virtual void RemovePartitionQueryCallback( IPartitionQueryCallback *pQuery ) = 0; + virtual void ElementMoved( SpatialPartitionHandle_t handle, + const Vector& mins, const Vector& maxs ) = 0; +}; + +#define VENGINETOOL_INTERFACE_VERSION "VENGINETOOL003" + +#endif // IENGINETOOL_H diff --git a/public/toolframework/iserverenginetools.h b/public/toolframework/iserverenginetools.h new file mode 100644 index 0000000..437a97d --- /dev/null +++ b/public/toolframework/iserverenginetools.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ISERVERENGINETOOLS_H +#define ISERVERENGINETOOLS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: exposed from engine to game .dll +//----------------------------------------------------------------------------- +class IServerEngineTools : public IBaseInterface +{ +public: + // Level init, shutdown + virtual void LevelInitPreEntityAllTools() = 0; + // entities are created / spawned / precached here + virtual void LevelInitPostEntityAllTools() = 0; + + virtual void LevelShutdownPreEntityAllTools() = 0; + // Entities are deleted / released here... + virtual void LevelShutdownPostEntityAllTools() = 0; + // end of level shutdown + + // Called each frame before entities think + virtual void FrameUpdatePreEntityThinkAllTools() = 0; + // called after entities think + virtual void FrameUpdatePostEntityThinkAllTools() = 0; + + virtual void PreClientUpdateAllTools() = 0; + // FIXME: PostClientUpdateAllTools()??? + + // The server uses this to call into the tools to get the actual + // entities to spawn on startup + virtual const char* GetEntityData( const char *pActualEntityData ) = 0; + + virtual void PreSetupVisibilityAllTools() = 0; + + virtual bool InToolMode() = 0; +}; + +#define VSERVERENGINETOOLS_INTERFACE_VERSION "VSERVERENGINETOOLS001" + +#endif // ISERVERENGINETOOLS_H diff --git a/public/toolframework/itooldictionary.h b/public/toolframework/itooldictionary.h new file mode 100644 index 0000000..96465f1 --- /dev/null +++ b/public/toolframework/itooldictionary.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ITOOLDICTIONARY_H +#define ITOOLDICTIONARY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" + +//----------------------------------------------------------------------------- +// Forward declaration +//----------------------------------------------------------------------------- +class IToolSystem; + + +//----------------------------------------------------------------------------- +// Purpose: Every tool dll sitting in bin\tools must expose this interface +// The engine will load the .dll, get this interface, and then ask for all +// tools in the .dll +// The engine will call CreateTools just before querying for the tools, so you +// can instance any dynamically instanced tools during that call +//----------------------------------------------------------------------------- +class IToolDictionary : public IAppSystem +{ +public: + virtual void CreateTools() = 0; + virtual int GetToolCount() const = 0; + virtual IToolSystem *GetTool( int index ) = 0; +}; + +#define VTOOLDICTIONARY_INTERFACE_VERSION "VTOOLDICTIONARY002" + +#endif // ITOOLDICTIONARY_H diff --git a/public/toolframework/itoolentity.h b/public/toolframework/itoolentity.h new file mode 100644 index 0000000..38790ef --- /dev/null +++ b/public/toolframework/itoolentity.h @@ -0,0 +1,273 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ITOOLENTITY_H +#define ITOOLENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "tier1/utlvector.h" +#include "Color.h" +#include "basehandle.h" +#include "iclientrenderable.h" +#include "engine/ishadowmgr.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IServerEntity; +class IClientEntity; +class IToolSystem; +class IClientRenderable; +class Vector; +class QAngle; +class CBaseEntity; +class CBaseAnimating; +class CTakeDamageInfo; +class ITempEntsSystem; +class IEntityFactoryDictionary; +class CBaseTempEntity; +class CGlobalEntityList; +class IEntityFindFilter; + + +//----------------------------------------------------------------------------- +// Safe accessor to an entity +//----------------------------------------------------------------------------- +typedef unsigned int HTOOLHANDLE; +enum +{ + HTOOLHANDLE_INVALID = 0 +}; + + +//----------------------------------------------------------------------------- +// If you change this, change the flags in IClientShadowMgr.h also +//----------------------------------------------------------------------------- +enum ClientShadowFlags_t +{ + SHADOW_FLAGS_USE_RENDER_TO_TEXTURE = (SHADOW_FLAGS_LAST_FLAG<<1), + SHADOW_FLAGS_ANIMATING_SOURCE = (SHADOW_FLAGS_LAST_FLAG<<2), + SHADOW_FLAGS_USE_DEPTH_TEXTURE = (SHADOW_FLAGS_LAST_FLAG<<3), + // Update this if you add flags + CLIENT_SHADOW_FLAGS_LAST_FLAG = SHADOW_FLAGS_USE_DEPTH_TEXTURE +}; + + +//----------------------------------------------------------------------------- +// Opaque pointer returned from Find* methods, don't store this, you need to +// Attach it to a tool entity or discard after searching +//----------------------------------------------------------------------------- +typedef void *EntitySearchResult; + + +//----------------------------------------------------------------------------- +// Purpose: Client side tool interace (right now just handles IClientRenderables). +// In theory could support hooking into client side entities directly +//----------------------------------------------------------------------------- +class IClientTools : public IBaseInterface +{ +public: + // Allocates or returns the handle to an entity previously found using the Find* APIs below + virtual HTOOLHANDLE AttachToEntity( EntitySearchResult entityToAttach ) = 0; + virtual void DetachFromEntity( EntitySearchResult entityToDetach ) = 0; + + // Checks whether a handle is still valid. + virtual bool IsValidHandle( HTOOLHANDLE handle ) = 0; + + // Iterates the list of entities which have been associated with tools + virtual int GetNumRecordables() = 0; + virtual HTOOLHANDLE GetRecordable( int index ) = 0; + + // Iterates through ALL entities (separate list for client vs. server) + virtual EntitySearchResult NextEntity( EntitySearchResult currentEnt ) = 0; + EntitySearchResult FirstEntity() { return NextEntity( NULL ); } + + // Use this to turn on/off the presence of an underlying game entity + virtual void SetEnabled( HTOOLHANDLE handle, bool enabled ) = 0; + // Use this to tell an entity to post "state" to all listening tools + virtual void SetRecording( HTOOLHANDLE handle, bool recording ) = 0; + // Some entities are marked with ShouldRecordInTools false, such as ui entities, etc. + virtual bool ShouldRecord( HTOOLHANDLE handle ) = 0; + + virtual HTOOLHANDLE GetToolHandleForEntityByIndex( int entindex ) = 0; + + virtual int GetModelIndex( HTOOLHANDLE handle ) = 0; + virtual const char* GetModelName ( HTOOLHANDLE handle ) = 0; + virtual const char* GetClassname ( HTOOLHANDLE handle ) = 0; + + virtual void AddClientRenderable( IClientRenderable *pRenderable, int renderGroup ) = 0; + virtual void RemoveClientRenderable( IClientRenderable *pRenderable ) = 0; + virtual void SetRenderGroup( IClientRenderable *pRenderable, int renderGroup ) = 0; + virtual void MarkClientRenderableDirty( IClientRenderable *pRenderable ) = 0; + virtual void UpdateProjectedTexture( ClientShadowHandle_t h, bool bForce ) = 0; + + virtual bool DrawSprite( IClientRenderable *pRenderable, float scale, float frame, int rendermode, int renderfx, const Color &color, float flProxyRadius, int *pVisHandle ) = 0; + + virtual EntitySearchResult GetLocalPlayer() = 0; + virtual bool GetLocalPlayerEyePosition( Vector& org, QAngle& ang, float &fov ) = 0; + + // See ClientShadowFlags_t above + virtual ClientShadowHandle_t CreateShadow( CBaseHandle handle, int nFlags ) = 0; + virtual void DestroyShadow( ClientShadowHandle_t h ) = 0; + + virtual ClientShadowHandle_t CreateFlashlight( const FlashlightState_t &lightState ) = 0; + virtual void DestroyFlashlight( ClientShadowHandle_t h ) = 0; + virtual void UpdateFlashlightState( ClientShadowHandle_t h, const FlashlightState_t &lightState ) = 0; + + virtual void AddToDirtyShadowList( ClientShadowHandle_t h, bool force = false ) = 0; + virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t h ) = 0; + + // Global toggle for recording + virtual void EnableRecordingMode( bool bEnable ) = 0; + virtual bool IsInRecordingMode() const = 0; + + // Trigger a temp entity + virtual void TriggerTempEntity( KeyValues *pKeyValues ) = 0; + + // get owning weapon (for viewmodels) + virtual int GetOwningWeaponEntIndex( int entindex ) = 0; + virtual int GetEntIndex( EntitySearchResult entityToAttach ) = 0; + + virtual int FindGlobalFlexcontroller( char const *name ) = 0; + virtual char const *GetGlobalFlexControllerName( int idx ) = 0; + + // helper for traversing ownership hierarchy + virtual EntitySearchResult GetOwnerEntity( EntitySearchResult currentEnt ) = 0; + + // common and useful types to query for hierarchically + virtual bool IsPlayer ( EntitySearchResult currentEnt ) = 0; + virtual bool IsBaseCombatCharacter( EntitySearchResult currentEnt ) = 0; + virtual bool IsNPC ( EntitySearchResult currentEnt ) = 0; + + virtual Vector GetAbsOrigin( HTOOLHANDLE handle ) = 0; + virtual QAngle GetAbsAngles( HTOOLHANDLE handle ) = 0; + + // This reloads a portion or all of a particle definition file. + // It's up to the client to decide if it cares about this file + // Use a UtlBuffer to crack the data + virtual void ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen ) = 0; + + // Sends a mesage from the tool to the client + virtual void PostToolMessage( KeyValues *pKeyValues ) = 0; + + // Indicates whether the client should render particle systems + virtual void EnableParticleSystems( bool bEnable ) = 0; + + // Is the game rendering in 3rd person mode? + virtual bool IsRenderingThirdPerson() const = 0; +}; + +#define VCLIENTTOOLS_INTERFACE_VERSION "VCLIENTTOOLS001" + + +//----------------------------------------------------------------------------- +// Purpose: Interface from engine to tools for manipulating entities +//----------------------------------------------------------------------------- +class IServerTools : public IBaseInterface +{ +public: + virtual IServerEntity *GetIServerEntity( IClientEntity *pClientEntity ) = 0; + virtual bool SnapPlayerToPosition( const Vector &org, const QAngle &ang, IClientEntity *pClientPlayer = NULL ) = 0; + virtual bool GetPlayerPosition( Vector &org, QAngle &ang, IClientEntity *pClientPlayer = NULL ) = 0; + virtual bool SetPlayerFOV( int fov, IClientEntity *pClientPlayer = NULL ) = 0; + virtual int GetPlayerFOV( IClientEntity *pClientPlayer = NULL ) = 0; + virtual bool IsInNoClipMode( IClientEntity *pClientPlayer = NULL ) = 0; + + // entity searching + virtual CBaseEntity *FirstEntity( void ) = 0; + virtual CBaseEntity *NextEntity( CBaseEntity *pEntity ) = 0; + virtual CBaseEntity *FindEntityByHammerID( int iHammerID ) = 0; + + // entity query + virtual bool GetKeyValue( CBaseEntity *pEntity, const char *szField, char *szValue, int iMaxLen ) = 0; + virtual bool SetKeyValue( CBaseEntity *pEntity, const char *szField, const char *szValue ) = 0; + virtual bool SetKeyValue( CBaseEntity *pEntity, const char *szField, float flValue ) = 0; + virtual bool SetKeyValue( CBaseEntity *pEntity, const char *szField, const Vector &vecValue ) = 0; + + // entity spawning + virtual CBaseEntity *CreateEntityByName( const char *szClassName ) = 0; + virtual void DispatchSpawn( CBaseEntity *pEntity ) = 0; + + // This reloads a portion or all of a particle definition file. + // It's up to the server to decide if it cares about this file + // Use a UtlBuffer to crack the data + virtual void ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen ) = 0; + + virtual void AddOriginToPVS( const Vector &org ) = 0; + virtual void MoveEngineViewTo( const Vector &vPos, const QAngle &vAngles ) = 0; + + virtual bool DestroyEntityByHammerId( int iHammerID ) = 0; + virtual CBaseEntity *GetBaseEntityByEntIndex( int iEntIndex ) = 0; + virtual void RemoveEntity( CBaseEntity *pEntity ) = 0; + virtual void RemoveEntityImmediate( CBaseEntity *pEntity ) = 0; + virtual IEntityFactoryDictionary *GetEntityFactoryDictionary( void ) = 0; + + virtual void SetMoveType( CBaseEntity *pEntity, int val ) = 0; + virtual void SetMoveType( CBaseEntity *pEntity, int val, int moveCollide ) = 0; + virtual void ResetSequence( CBaseAnimating *pEntity, int nSequence ) = 0; + virtual void ResetSequenceInfo( CBaseAnimating *pEntity ) = 0; + + virtual void ClearMultiDamage( void ) = 0; + virtual void ApplyMultiDamage( void ) = 0; + virtual void AddMultiDamage( const CTakeDamageInfo &pTakeDamageInfo, CBaseEntity *pEntity ) = 0; + virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) = 0; + + virtual ITempEntsSystem *GetTempEntsSystem( void ) = 0; + virtual CBaseTempEntity *GetTempEntList( void ) = 0; + + virtual CGlobalEntityList *GetEntityList( void ) = 0; + virtual bool IsEntityPtr( void *pTest ) = 0; + virtual CBaseEntity *FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ) = 0; + virtual CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL ) = 0; + virtual CBaseEntity *FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) = 0; + virtual CBaseEntity *FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName ) = 0; + virtual CBaseEntity *FindEntityByModel( CBaseEntity *pStartEntity, const char *szModelName ) = 0; + virtual CBaseEntity *FindEntityByNameNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ) = 0; + virtual CBaseEntity *FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ) = 0; + virtual CBaseEntity *FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius ) = 0; + virtual CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius ) = 0; + virtual CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecMins, const Vector &vecMaxs ) = 0; + virtual CBaseEntity *FindEntityGeneric( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ) = 0; + virtual CBaseEntity *FindEntityGenericWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ) = 0; + virtual CBaseEntity *FindEntityGenericNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ) = 0; + virtual CBaseEntity *FindEntityNearestFacing( const Vector &origin, const Vector &facing, float threshold ) = 0; + virtual CBaseEntity *FindEntityClassNearestFacing( const Vector &origin, const Vector &facing, float threshold, char *classname ) = 0; + virtual CBaseEntity *FindEntityProcedural( const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ) = 0; +}; + +typedef IServerTools IServerTools001; +typedef IServerTools IServerTools002; + +#define VSERVERTOOLS_INTERFACE_VERSION_1 "VSERVERTOOLS001" +#define VSERVERTOOLS_INTERFACE_VERSION_2 "VSERVERTOOLS002" +#define VSERVERTOOLS_INTERFACE_VERSION "VSERVERTOOLS003" +#define VSERVERTOOLS_INTERFACE_VERSION_INT 3 + +//----------------------------------------------------------------------------- +// Purpose: Client side tool interace (right now just handles IClientRenderables). +// In theory could support hooking into client side entities directly +//----------------------------------------------------------------------------- +class IServerChoreoTools : public IBaseInterface +{ +public: + + // Iterates through ALL entities (separate list for client vs. server) + virtual EntitySearchResult NextChoreoEntity( EntitySearchResult currentEnt ) = 0; + EntitySearchResult FirstChoreoEntity() { return NextChoreoEntity( NULL ); } + virtual const char *GetSceneFile( EntitySearchResult sr ) = 0; + + // For interactive editing + virtual int GetEntIndex( EntitySearchResult sr ) = 0; + virtual void ReloadSceneFromDisk( int entindex ) = 0; +}; + +#define VSERVERCHOREOTOOLS_INTERFACE_VERSION "VSERVERCHOREOTOOLS001" + +#endif // ITOOLENTITY_H diff --git a/public/toolframework/itoolframework.h b/public/toolframework/itoolframework.h new file mode 100644 index 0000000..5be2190 --- /dev/null +++ b/public/toolframework/itoolframework.h @@ -0,0 +1,265 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ITOOLFRAMEWORK_H +#define ITOOLFRAMEWORK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/IAppSystem.h" +#include "materialsystem/imaterialproxy.h" +#include "toolframework/itoolentity.h" +#include "mathlib/vector.h" +#include "Color.h" +#include "toolframework/itoolentity.h" // HTOOLHANDLE defn + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IToolSystem; +struct SpatializationInfo_t; +class KeyValues; +class CBoneList; + + +//----------------------------------------------------------------------------- +// Standard messages +//----------------------------------------------------------------------------- +struct BaseEntityRecordingState_t +{ + BaseEntityRecordingState_t() : + m_flTime( 0.0f ), + m_pModelName( 0 ), + m_nOwner( -1 ), + m_nEffects( 0 ), + m_bVisible( false ), + m_bRecordFinalVisibleSample( false ) + { + m_vecRenderOrigin.Init(); + m_vecRenderAngles.Init(); + } + + float m_flTime; + const char *m_pModelName; + int m_nOwner; + int m_nEffects; + bool m_bVisible : 1; + bool m_bRecordFinalVisibleSample : 1; + Vector m_vecRenderOrigin; + QAngle m_vecRenderAngles; +}; + +struct SpriteRecordingState_t +{ + float m_flRenderScale; + float m_flFrame; + int m_nRenderMode; + bool m_nRenderFX; + Color m_Color; + float m_flProxyRadius; +}; + +struct BaseAnimatingRecordingState_t +{ + int m_nSkin; + int m_nBody; + int m_nSequence; + CBoneList *m_pBoneList; +}; + +struct BaseFlexRecordingState_t +{ + int m_nFlexCount; + float *m_pDestWeight; + Vector m_vecViewTarget; +}; + +struct CameraRecordingState_t +{ + bool m_bThirdPerson; + float m_flFOV; + Vector m_vecEyePosition; + QAngle m_vecEyeAngles; +}; + +struct MonitorRecordingState_t +{ + bool m_bActive; + float m_flFOV; + bool m_bFogEnabled; + float m_flFogStart; + float m_flFogEnd; + Color m_FogColor; +}; + +struct EntityTeleportedRecordingState_t +{ + Vector m_vecTo; + QAngle m_qaTo; + bool m_bTeleported; + bool m_bViewOverride; + matrix3x4_t m_teleportMatrix; +}; + +struct PortalRecordingState_t +{ + int m_nPortalId; + int m_nLinkedPortalId; + float m_fStaticAmount; + float m_fSecondaryStaticAmount; + float m_fOpenAmount; + bool m_bIsPortal2; //for any set of portals, one must be portal 1, and the other portal 2. Uses different render targets +}; + +struct ParticleSystemCreatedState_t +{ + int m_nParticleSystemId; + const char * m_pName; + float m_flTime; + int m_nOwner; +}; + +struct ParticleSystemDestroyedState_t +{ + int m_nParticleSystemId; + float m_flTime; +}; + +struct ParticleSystemStopEmissionState_t +{ + int m_nParticleSystemId; + float m_flTime; + bool m_bInfiniteOnly; +}; + +struct ParticleSystemSetControlPointObjectState_t +{ + int m_nParticleSystemId; + float m_flTime; + int m_nControlPoint; + int m_nObject; +}; + +struct ParticleSystemSetControlPointPositionState_t +{ + int m_nParticleSystemId; + float m_flTime; + int m_nControlPoint; + Vector m_vecPosition; +}; + +struct ParticleSystemSetControlPointOrientationState_t +{ + int m_nParticleSystemId; + float m_flTime; + int m_nControlPoint; + Quaternion m_qOrientation; +}; + + +//----------------------------------------------------------------------------- +// Purpose: This interface lives in the engine and handles loading up/unloading all +// available tools +//----------------------------------------------------------------------------- +class IToolFrameworkInternal : public IAppSystem +{ +public: // Client Hooks + virtual bool ClientInit( CreateInterfaceFn clientFactory ) = 0; + virtual void ClientShutdown() = 0; + + // Level init, shutdown + virtual void ClientLevelInitPreEntityAllTools() = 0; + // entities are created / spawned / precached here + virtual void ClientLevelInitPostEntityAllTools() = 0; + + virtual void ClientLevelShutdownPreEntityAllTools() = 0; + // Entities are deleted / released here... + virtual void ClientLevelShutdownPostEntityAllTools() = 0; + + virtual void ClientPreRenderAllTools() = 0; + virtual void ClientPostRenderAllTools() = 0; + + // Should we render with a thirdperson camera? + virtual bool IsThirdPersonCamera() = 0; + + // is the current tool recording? + virtual bool IsToolRecording() = 0; + +public: // Server Hooks + // Level init, shutdown + virtual bool ServerInit( CreateInterfaceFn serverFactory ) = 0; + virtual void ServerShutdown() = 0; + + virtual void ServerLevelInitPreEntityAllTools() = 0; + // entities are created / spawned / precached here + virtual void ServerLevelInitPostEntityAllTools() = 0; + + virtual void ServerLevelShutdownPreEntityAllTools() = 0; + // Entities are deleted / released here... + virtual void ServerLevelShutdownPostEntityAllTools() = 0; + // end of level shutdown + + // Called each frame before entities think + virtual void ServerFrameUpdatePreEntityThinkAllTools() = 0; + // called after entities think + virtual void ServerFrameUpdatePostEntityThinkAllTools() = 0; + virtual void ServerPreClientUpdateAllTools() = 0; + + virtual void ServerPreSetupVisibilityAllTools() = 0; + +public: // Other Hooks + // If any tool returns false, the engine will not actually quit + // FIXME: Not implemented yet + virtual bool CanQuit() = 0; + + // Called at end of Host_Init + virtual bool PostInit() = 0; + + virtual void Think( bool finalTick ) = 0; + + virtual void PostMessage( KeyValues *msg ) = 0; + + virtual bool GetSoundSpatialization( int iUserData, int guid, SpatializationInfo_t& info ) = 0; + + virtual void HostRunFrameBegin() = 0; + virtual void HostRunFrameEnd() = 0; + + virtual void RenderFrameBegin() = 0; + virtual void RenderFrameEnd() = 0; + + // Paintmode is an enum declared in enginevgui.h + virtual void VGui_PreRenderAllTools( int paintMode ) = 0; + virtual void VGui_PostRenderAllTools( int paintMode ) = 0; + + virtual void VGui_PreSimulateAllTools() = 0; + virtual void VGui_PostSimulateAllTools() = 0; + + // Are we using tools? + virtual bool InToolMode() = 0; + + // Should the game be allowed to render the world? + virtual bool ShouldGameRenderView() = 0; + + virtual IMaterialProxy *LookupProxy( const char *proxyName ) = 0; + +public: // general framework hooks + virtual int GetToolCount() = 0; + virtual char const *GetToolName( int index ) = 0; + virtual void SwitchToTool( int index ) = 0; + virtual IToolSystem *SwitchToTool( const char *pToolName ) = 0; + virtual bool IsTopmostTool( const IToolSystem *sys ) = 0; + virtual const IToolSystem *GetToolSystem( int index ) const = 0; + virtual IToolSystem *GetTopmostTool() = 0; +}; + +// Expose to rest of engine as a singleton +extern IToolFrameworkInternal *toolframework; + +// Exposed to launcher to automatically add AppSystemGroup hooks +#define VTOOLFRAMEWORK_INTERFACE_VERSION "VTOOLFRAMEWORKVERSION002" + +#endif // ITOOLFRAMEWORK_H diff --git a/public/toolframework/itoolsystem.h b/public/toolframework/itoolsystem.h new file mode 100644 index 0000000..84c91db --- /dev/null +++ b/public/toolframework/itoolsystem.h @@ -0,0 +1,146 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef ITOOLSYSTEM_H +#define ITOOLSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "itoolentity.h" +#include "interface.h" +#include "materialsystem/imaterialproxy.h" +#include "inputsystem/iinputsystem.h" + +class KeyValues; +struct SpatializationInfo_t; +struct AudioState_t; + +//----------------------------------------------------------------------------- +// Purpose: All tools expose this interface, which includes both client and server +// related hooks +//----------------------------------------------------------------------------- +class IToolSystem +{ +public: + // Name describing the tool + virtual char const *GetToolName() = 0; + + // Called at the end of engine startup (after client .dll and server .dll have been loaded) + virtual bool Init() = 0; + + // Called during RemoveTool or when engine is shutting down + virtual void Shutdown() = 0; + + // Called after server.dll is loaded + virtual bool ServerInit( CreateInterfaceFn serverFactory ) = 0; + // Called after client.dll is loaded + virtual bool ClientInit( CreateInterfaceFn clientFactory ) = 0; + + virtual void ServerShutdown() = 0; + virtual void ClientShutdown() = 0; + + // Allow tool to override quitting, called before Shutdown(), return no to abort quitting + virtual bool CanQuit() = 0; + + // Called when another system wiches to post a message to the tool and/or a specific entity + // FIXME: Are KeyValues too inefficient here? + virtual void PostMessage( HTOOLHANDLE hEntity, KeyValues *message ) = 0; + + // Called oncer per frame even when no level is loaded... (call ProcessMessages()) + virtual void Think( bool finalTick ) = 0; + +// Server calls: + + // Level init, shutdown + virtual void ServerLevelInitPreEntity() = 0; + // entities are created / spawned / precached here + virtual void ServerLevelInitPostEntity() = 0; + + virtual void ServerLevelShutdownPreEntity() = 0; + // Entities are deleted / released here... + virtual void ServerLevelShutdownPostEntity() = 0; + // end of level shutdown + + // Called each frame before entities think + virtual void ServerFrameUpdatePreEntityThink() = 0; + // called after entities think + virtual void ServerFrameUpdatePostEntityThink() = 0; + virtual void ServerPreClientUpdate() = 0; + virtual void ServerPreSetupVisibility() = 0; + + // Used to allow the tool to spawn different entities when it's active + virtual const char* GetEntityData( const char *pActualEntityData ) = 0; + +// Client calls: + // Level init, shutdown + virtual void ClientLevelInitPreEntity() = 0; + // entities are created / spawned / precached here + virtual void ClientLevelInitPostEntity() = 0; + + virtual void ClientLevelShutdownPreEntity() = 0; + // Entities are deleted / released here... + virtual void ClientLevelShutdownPostEntity() = 0; + // end of level shutdown + // Called before rendering + virtual void ClientPreRender() = 0; + virtual void ClientPostRender() = 0; + + // Let tool override viewport for engine + virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ) = 0; + + // let tool override view/camera + virtual bool SetupEngineView( Vector &origin, QAngle &angles, float &fov ) = 0; + + // let tool override microphone + virtual bool SetupAudioState( AudioState_t &audioState ) = 0; + + // Should the client be allowed to render the view normally? + virtual bool ShouldGameRenderView() = 0; + virtual bool IsThirdPersonCamera() = 0; + + // is the current tool recording? + virtual bool IsToolRecording() = 0; + + virtual IMaterialProxy *LookupProxy( const char *proxyName ) = 0; + + // Possible hooks for rendering + // virtual void Think( float curtime, float frametime ) = 0; + // virtual void Prerender() = 0; + // virtual void Render3D() = 0; + // virtual void Render2D() = 0; +// Tool activation/deactivation + + // This tool is being activated + virtual void OnToolActivate() = 0; + // Another tool is being activated + virtual void OnToolDeactivate() = 0; + + virtual bool TrapKey( ButtonCode_t key, bool down ) = 0; + + virtual bool GetSoundSpatialization( int iUserData, int guid, SpatializationInfo_t& info ) = 0; + + // Unlike the client .dll pre/post render stuff, these get called no matter whether a map is loaded and they only get called once per frame!!! + virtual void RenderFrameBegin() = 0; + virtual void RenderFrameEnd() = 0; + + // wraps the entire frame - surrounding all other begin/end and pre/post calls + virtual void HostRunFrameBegin() = 0; + virtual void HostRunFrameEnd() = 0; + + // See enginevgui.h for paintmode_t enum definitions + virtual void VGui_PreRender( int paintMode ) = 0; + virtual void VGui_PostRender( int paintMode ) = 0; + + virtual void VGui_PreSimulate() = 0; + virtual void VGui_PostSimulate() = 0; +}; + +// Pointer to a member method of IGameSystem +typedef void (IToolSystem::*ToolSystemFunc_t)(); +typedef void (IToolSystem::*ToolSystemFunc_Int_t)( int arg ); + +#endif // ITOOLSYSTEM_H diff --git a/public/toolframework/toolframework.cpp b/public/toolframework/toolframework.cpp new file mode 100644 index 0000000..8d0db6e --- /dev/null +++ b/public/toolframework/toolframework.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "toolframework/itooldictionary.h" +#include "utlvector.h" + +class CToolDictionary : public IToolDictionary +{ +public: + virtual int GetToolCount() const + { + return m_Tools.Count(); + } + + virtual IToolSystem *GetTool( int index ) + { + if ( index < 0 || index >= m_Tools.Count() ) + { + return NULL; + } + return m_Tools[ index ]; + } + +public: + + void RegisterTool( IToolSystem *tool ) + { + m_Tools.AddToTail( tool ); + } +private: + + CUtlVector< IToolSystem * > m_Tools; +}; + +static CToolDictionary g_ToolDictionary; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( IToolDictionary, CToolDictionary, VTOOLDICTIONARY_INTERFACE_VERSION, g_ToolDictionary ); + +void RegisterTool( IToolSystem *tool ) +{ + g_ToolDictionary.RegisterTool( tool ); +} + diff --git a/public/tools/bonelist.cpp b/public/tools/bonelist.cpp new file mode 100644 index 0000000..be772a9 --- /dev/null +++ b/public/tools/bonelist.cpp @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "bonelist.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CBoneList::CBoneList() +{ + m_bShouldDelete = false; + m_nBones = 0; + Q_memset( m_vecPos, 0, sizeof( m_vecPos ) ); + Q_memset( m_quatRot, 0, sizeof( m_quatRot ) ); +} + +void CBoneList::Release() +{ + if (m_bShouldDelete ) + { + delete this; + } + else + { + Warning( "Called Release() on CBoneList not allocated via Alloc() method\n" ); + } +} + +CBoneList *CBoneList::Alloc() +{ + CBoneList *newList = new CBoneList; + Assert( newList ); + if ( newList ) + { + newList->m_bShouldDelete = true; + } + return newList; +} + +CFlexList::CFlexList() +{ + m_bShouldDelete = false; + m_nNumFlexes = 0; + Q_memset( m_flexWeights, 0, sizeof( m_flexWeights ) ); +} + +void CFlexList::Release() +{ + if (m_bShouldDelete ) + { + delete this; + } + else + { + Warning( "Called Release() on CFlexList not allocated via Alloc() method\n" ); + } +} + +CFlexList *CFlexList::Alloc() +{ + CFlexList *newList = new CFlexList; + Assert( newList ); + if ( newList ) + { + newList->m_bShouldDelete = true; + } + return newList; +} \ No newline at end of file diff --git a/public/tools/bonelist.h b/public/tools/bonelist.h new file mode 100644 index 0000000..dbb3972 --- /dev/null +++ b/public/tools/bonelist.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef BONELIST_H +#define BONELIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "studio.h" + +class CBoneList +{ +public: + + CBoneList(); + + void Release(); + + static CBoneList *Alloc(); + +public: + + int m_nBones; + Vector m_vecPos[ MAXSTUDIOBONES ]; + Quaternion m_quatRot[ MAXSTUDIOBONES ]; + +private: + bool m_bShouldDelete; +}; + +class CFlexList +{ +public: + + CFlexList(); + + void Release(); + + static CFlexList *Alloc(); + +public: + + int m_nNumFlexes; + float m_flexWeights[ MAXSTUDIOFLEXCTRL ]; + +private: + bool m_bShouldDelete; +}; + +#endif // BONELIST_H diff --git a/public/trace.h b/public/trace.h new file mode 100644 index 0000000..765acd5 --- /dev/null +++ b/public/trace.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TRACE_H +#define TRACE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib/mathlib.h" + +// Note: These flags need to match the bspfile.h DISPTRI_TAG_* flags. +#define DISPSURF_FLAG_SURFACE (1<<0) +#define DISPSURF_FLAG_WALKABLE (1<<1) +#define DISPSURF_FLAG_BUILDABLE (1<<2) +#define DISPSURF_FLAG_SURFPROP1 (1<<3) +#define DISPSURF_FLAG_SURFPROP2 (1<<4) + +//============================================================================= +// Base Trace Structure +// - shared between engine/game dlls and tools (vrad) +//============================================================================= + +class CBaseTrace +{ +public: + + // Displacement flags tests. + bool IsDispSurface( void ) { return ( ( dispFlags & DISPSURF_FLAG_SURFACE ) != 0 ); } + bool IsDispSurfaceWalkable( void ) { return ( ( dispFlags & DISPSURF_FLAG_WALKABLE ) != 0 ); } + bool IsDispSurfaceBuildable( void ) { return ( ( dispFlags & DISPSURF_FLAG_BUILDABLE ) != 0 ); } + bool IsDispSurfaceProp1( void ) { return ( ( dispFlags & DISPSURF_FLAG_SURFPROP1 ) != 0 ); } + bool IsDispSurfaceProp2( void ) { return ( ( dispFlags & DISPSURF_FLAG_SURFPROP2 ) != 0 ); } + +public: + + // these members are aligned!! + Vector startpos; // start position + Vector endpos; // final position + cplane_t plane; // surface normal at impact + + float fraction; // time completed, 1.0 = didn't hit anything + + int contents; // contents on other side of surface hit + unsigned short dispFlags; // displacement flags for marking surfaces with data + + bool allsolid; // if true, plane is not valid + bool startsolid; // if true, the initial point was in a solid area + + CBaseTrace() {} + +private: + // No copy constructors allowed + CBaseTrace(const CBaseTrace& vOther); +}; + +#endif // TRACE_H diff --git a/public/unicode/unicode.h b/public/unicode/unicode.h new file mode 100644 index 0000000..7c3522e --- /dev/null +++ b/public/unicode/unicode.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef UNICODE_H +#define UNICODE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#if !defined( _X360 ) +#include +#endif +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +class IUnicodeWindows : public IBaseInterface +{ +public: + virtual LRESULT DefWindowProcW + ( + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam + ) = 0; + + virtual HWND CreateWindowExW + ( + DWORD dwExStyle, + LPCWSTR lpClassName, + LPCWSTR lpWindowName, + DWORD dwStyle, + int x, + int y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam + ) = 0; + + virtual ATOM RegisterClassW + ( + CONST WNDCLASSW *lpWndClass + ) = 0; + + virtual BOOL UnregisterClassW + ( + LPCWSTR lpClassName, + HINSTANCE hInstance + ) = 0; +}; + +#define VENGINE_UNICODEINTERFACE_VERSION "VENGINEUNICODE001" + + +#endif // UNICODE_H diff --git a/public/unitlib/unitlib.h b/public/unitlib/unitlib.h new file mode 100644 index 0000000..c27817d --- /dev/null +++ b/public/unitlib/unitlib.h @@ -0,0 +1,270 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef UNITLIB_H +#define UNITLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/interface.h" +#include "appframework/IAppSystem.h" + + +//----------------------------------------------------------------------------- +// Usage model for the UnitTest library +// +// The general methodology here is that clients are expected to create unit +// test DLLs that statically link to the unit test DLL and which implement +// tests of various libraries. The unit test application will dynamically +// load all DLLs in a directory, which causes them to install their test cases +// into the unit test system. The application then runs through all tests and +// executes them all, displaying the results. +// +// *** NOTE: The test suites are compiled in both debug and release builds, +// even though it's expected to only be useful in debug builds. This is because +// I couldn't come up with a good way of disabling the code in release builds. +// (The only options I could come up with would still compile in the functions, +// just not install them into the unit test library, or would make it so that +// you couldn't step through the unit test code). +// +// Even though this is the case, there's no reason not to add test cases +// directly into your shipping DLLs, as long as you surround the code with +// #ifdef _DEBUG. To error check a project to make sure it's not compiling +// in unit tests in Release build, just don't link in unitlib.lib in Release. +// You can of course also put your test suites into separate DLLs. +// +// All tests inherit from the ITestCase interface. There are two major kinds +// of tests; the first is a single test case meant to run a piece of +// code and check its results match expected values using the Assert macros. +// The second kind is a test suite which is simply a list of other tests. +// +// The following classes and macros are used to easily create unit test cases +// and suites: +// +// Use DEFINE_TESTSUITE to define a particular test suite, and DEFINE_TESTCASE +// to add as many test cases as you like to that test suite, as follows: +// +// DEFINE_TESTSUITE( VectorTestSuite ) +// +// DEFINE_TESTCASE( VectorAdditionTest, VectorTestSuite ) +// { +// .. test code here .. +// } +// +// Note that the definition of the test suite can occur in a different file +// as the test case. A link error will occur if the test suite to which a +// test case is added has not been defined. +// +// To create a test case that is not part of a suite, use... +// +// DEFINE_TESTCASE_NOSUITE( VectorAdditionTest ) +// { +// .. test code here .. +// } +// +// You can also create a suite which is a child of another suite using +// +// DEFINE_SUBSUITE( VectorTestSuite, MathTestSuite ) +// +//----------------------------------------------------------------------------- + + + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +#ifdef UNITLIB_DLL_EXPORT +#define UNITLIB_INTERFACE DLL_EXPORT +#define UNITLIB_CLASS_INTERFACE DLL_CLASS_EXPORT +#define UNITLIB_GLOBAL_INTERFACE DLL_GLOBAL_EXPORT +#else +#define UNITLIB_INTERFACE DLL_IMPORT +#define UNITLIB_CLASS_INTERFACE DLL_CLASS_IMPORT +#define UNITLIB_GLOBAL_INTERFACE DLL_GLOBAL_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// All unit test libraries can be asked for a unit test +// AppSystem to perform connection +//----------------------------------------------------------------------------- +#define UNITTEST_INTERFACE_VERSION "UnitTestV001" + + +//----------------------------------------------------------------------------- +// +// NOTE: All classes and interfaces below you shouldn't use directly. +// Use the DEFINE_TESTSUITE and DEFINE_TESTCASE macros instead. +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Test case + suite interface +//----------------------------------------------------------------------------- +class ITestCase +{ +public: + // This returns the test name + virtual char const* GetName() = 0; + + // This runs the test + virtual void RunTest() = 0; +}; + +class ITestSuite : public ITestCase +{ +public: + // Add a test to the suite... + virtual void AddTest( ITestCase* pTest ) = 0; +}; + + + +//----------------------------------------------------------------------------- +// This is the main function exported by the unit test library used by +// unit test DLLs to install their test cases into a list to be run +//----------------------------------------------------------------------------- +UNITLIB_INTERFACE void UnitTestInstallTestCase( ITestCase* pTest ); + + +//----------------------------------------------------------------------------- +// These are the methods used by the unit test running program to run all tests +//----------------------------------------------------------------------------- +UNITLIB_INTERFACE int UnitTestCount(); +UNITLIB_INTERFACE ITestCase* GetUnitTest( int i ); + + +//----------------------------------------------------------------------------- +// Helper for unit test DLLs to expose IAppSystems +//----------------------------------------------------------------------------- +#define USE_UNITTEST_APPSYSTEM( _className ) \ + static _className s_UnitTest ## _className; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR( _className, IAppSystem, UNITTEST_INTERFACE_VERSION, s_UnitTest ## _className ); + + +//----------------------------------------------------------------------------- +// Base class for test cases +//----------------------------------------------------------------------------- +class UNITLIB_CLASS_INTERFACE CTestCase : public ITestCase +{ +public: + CTestCase( char const* pName, ITestSuite* pParent = 0 ); + ~CTestCase(); + + // Returns the test name + char const* GetName(); + +private: + char* m_pName; +}; + + +//----------------------------------------------------------------------------- +// Test suite class +//----------------------------------------------------------------------------- +class UNITLIB_CLASS_INTERFACE CTestSuite : public ITestSuite +{ +public: + CTestSuite( char const* pName, ITestSuite* pParent = 0 ); + ~CTestSuite(); + + // This runs the test + void RunTest(); + + // Add a test to the suite... + void AddTest( ITestCase* pTest ); + + // Returns the test name + char const* GetName(); + +protected: + int m_TestCount; + ITestCase** m_ppTestCases; + char* m_pName; +}; + +#define TESTSUITE_CLASS( _suite ) \ + class CTS ## _suite : public CTestSuite \ + { \ + public: \ + CTS ## _suite(); \ + }; + +#define TESTSUITE_ACCESSOR( _suite ) \ + CTS ## _suite* GetTS ## _suite() \ + { \ + static CTS ## _suite s_TS ## _suite; \ + return &s_TS ## _suite; \ + } + +#define FWD_DECLARE_TESTSUITE( _suite ) \ + class CTS ## _suite; \ + CTS ## _suite* GetTS ## _suite(); + +#define DEFINE_TESTSUITE( _suite ) \ + TESTSUITE_CLASS( _suite ) \ + TESTSUITE_ACCESSOR( _suite ) \ + CTS ## _suite::CTS ## _suite() : CTestSuite( #_suite ) {} + +#define DEFINE_SUBSUITE( _suite, _parent ) \ + TESTSUITE_CLASS( _suite ) \ + TESTSUITE_ACCESSOR( _suite ) \ + FWD_DECLARE_TESTSUITE( _parent ) \ + CTS ## _suite::CTS ## _suite() : CTestSuite( #_suite, GetTS ## _parent() ) {} + +#define TESTCASE_CLASS( _case ) \ + class CTC ## _case : public CTestCase \ + { \ + public: \ + CTC ## _case (); \ + void RunTest(); \ + }; + +#define DEFINE_TESTCASE_NOSUITE( _case ) \ + TESTCASE_CLASS( _case ) \ + CTC ## _case::CTC ## _case () : CTestCase( #_case ) {} \ + \ + CTC ## _case s_TC ## _case; \ + \ + void CTC ## _case ::RunTest() + +#define DEFINE_TESTCASE( _case, _suite ) \ + TESTCASE_CLASS( _case ) \ + FWD_DECLARE_TESTSUITE( _suite ) \ + CTC ## _case::CTC ## _case () : CTestCase( #_case, GetTS ## _suite() ) {} \ + \ + CTC ## _case s_TC ## _case; \ + \ + void CTC ## _case ::RunTest() + + +#define _Shipping_AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __TFILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage(_msg); \ + _executeExp; \ + if ( ret == SPEW_DEBUGGER) \ + { \ + if ( !ShouldUseNewAssertDialog() || DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + if ( _bFatal ) \ + _ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + +#define Shipping_Assert( _exp ) _Shipping_AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) + + +#endif // UNITLIB_H diff --git a/public/vallocator.cpp b/public/vallocator.cpp new file mode 100644 index 0000000..be71703 --- /dev/null +++ b/public/vallocator.cpp @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) + +#include +#include "vallocator.h" +#include "basetypes.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +VStdAllocator g_StdAllocator; + +void* VStdAllocator::Alloc(unsigned long size) +{ + if(size) + { + void *ret = malloc(size); + return ret; + } + else + return 0; +} + +void VStdAllocator::Free(void *ptr) +{ + free(ptr); +} + +#endif // !_STATIC_LINKED || _SHARED_LIB diff --git a/public/vallocator.h b/public/vallocator.h new file mode 100644 index 0000000..ea26dbe --- /dev/null +++ b/public/vallocator.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// These classes let you write your own allocators to be used with new and delete. +// If you have an allocator: VAllocator *pAlloc, you can call new and delete like this: +// +// ptr = VNew(pAlloc) ClassName; +// VDelete(pAlloc, ptr); +// +// Note: allocating and freeing arrays of objects will not work using VAllocators. + + + +#ifndef VALLOCATOR_H +#define VALLOCATOR_H + + +class VAllocator +{ +public: + virtual void* Alloc(unsigned long size)=0; + virtual void Free(void *ptr)=0; +}; + + +// This allocator just uses malloc and free. +class VStdAllocator : public VAllocator +{ +public: + virtual void* Alloc(unsigned long size); + virtual void Free(void *ptr); +}; +extern VStdAllocator g_StdAllocator; + + + +// Use these to allocate classes through VAllocator. +// Allocating arrays of classes is not supported. +#define VNew(pAlloc) new +#define VDelete(pAlloc, ptr) delete ptr + +// Used internally.. just makes sure we call the right operator new. +class DummyAllocatorHelper +{ +public: + int x; +}; + +inline void* operator new(size_t size, void *ptr, DummyAllocatorHelper *asdf) +{ + (void)asdf; // Suppress unused-variable compiler warnings. + (void)size; + return ptr; +} + +inline void operator delete(void *ptrToDelete, void *ptr, DummyAllocatorHelper *asdf) +{ + (void)asdf; // Suppress unused-variable compiler warnings. + (void)ptr; + (void)ptrToDelete; +} + +// Use these to manually construct and destruct lists of objects. +template +inline void VAllocator_CallConstructors(T *pObjects, int count=1) +{ + for(int i=0; i < count; i++) + new(&pObjects[i], (DummyAllocatorHelper*)0) T; +} + +template +inline void VAllocator_CallDestructors(T *pObjects, int count) +{ + for(int i=0; i < count; i++) + pObjects[i].~T(); +} + +#endif + diff --git a/public/vaudio/ivaudio.h b/public/vaudio/ivaudio.h new file mode 100644 index 0000000..8b23e1d --- /dev/null +++ b/public/vaudio/ivaudio.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVAUDIO_H +#define IVAUDIO_H +#ifdef _WIN32 +#pragma once +#endif + +class IAudioStreamEvent +{ +public: + // called by the stream to request more data + // seek the source to position "offset" + // -1 indicates previous position + // copy the data to pBuffer and return the number of bytes copied + // you may return less than bytesRequested if the end of the stream + // is encountered. + virtual int StreamRequestData( void *pBuffer, int bytesRequested, int offset ) = 0; +}; + + +class IAudioStream +{ +public: + virtual ~IAudioStream() {} + + // Decode another bufferSize output bytes from the stream + // returns number of bytes decoded + virtual int Decode( void *pBuffer, unsigned int bufferSize ) = 0; + + // output sampling bits (8/16) + virtual int GetOutputBits() = 0; + // output sampling rate in Hz + virtual int GetOutputRate() = 0; + // output channels (1=mono,2=stereo) + virtual int GetOutputChannels() = 0; + + // seek + virtual unsigned int GetPosition() = 0; + + // NOTE: BUGBUG: Only supports seeking forward currently! + virtual void SetPosition( unsigned int position ) = 0; + + // reset? +}; + + +#define VAUDIO_INTERFACE_VERSION "VAudio002" +class IVAudio +{ +public: + virtual ~IVAudio() {} + + virtual IAudioStream *CreateMP3StreamDecoder( IAudioStreamEvent *pEventHandler ) = 0; + virtual void DestroyMP3StreamDecoder( IAudioStream *pDecoder ) = 0; +}; + + +#endif // IVAUDIO_H diff --git a/public/vcollide.h b/public/vcollide.h new file mode 100644 index 0000000..f4ebf62 --- /dev/null +++ b/public/vcollide.h @@ -0,0 +1,26 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VCOLLIDE_H +#define VCOLLIDE_H +#ifdef _WIN32 +#pragma once +#endif + +class CPhysCollide; + +struct vcollide_t +{ + unsigned short solidCount : 15; + unsigned short isPacked : 1; + unsigned short descSize; + // VPhysicsSolids + CPhysCollide **solids; + char *pKeyValues; +}; + +#endif // VCOLLIDE_H diff --git a/public/vcollide_parse.h b/public/vcollide_parse.h new file mode 100644 index 0000000..675c456 --- /dev/null +++ b/public/vcollide_parse.h @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VCOLLIDE_PARSE_H +#define VCOLLIDE_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vphysics_interface.h" + +struct solid_t +{ + int index; + char name[512]; + char parent[512]; + char surfaceprop[512]; + Vector massCenterOverride; + objectparams_t params; +}; + +struct fluid_t +{ + int index; + char surfaceprop[512]; + + fluidparams_t params; + + fluid_t() {} + fluid_t( fluid_t const& src ) : params(src.params) + { + index = src.index; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Pass this into the parser to handle the keys that vphysics does not +// parse. +//----------------------------------------------------------------------------- +class IVPhysicsKeyHandler +{ +public: + virtual void ParseKeyValue( void *pData, const char *pKey, const char *pValue ) = 0; + virtual void SetDefaults( void *pData ) = 0; +}; + + +class IVPhysicsKeyParser +{ +public: + virtual ~IVPhysicsKeyParser() {} + + virtual const char *GetCurrentBlockName( void ) = 0; + virtual bool Finished( void ) = 0; + virtual void ParseSolid( solid_t *pSolid, IVPhysicsKeyHandler *unknownKeyHandler ) = 0; + virtual void ParseFluid( fluid_t *pFluid, IVPhysicsKeyHandler *unknownKeyHandler ) = 0; + virtual void ParseRagdollConstraint( constraint_ragdollparams_t *pConstraint, IVPhysicsKeyHandler *unknownKeyHandler ) = 0; + virtual void ParseSurfaceTable( int *table, IVPhysicsKeyHandler *unknownKeyHandler ) = 0; + virtual void ParseCustom( void *pCustom, IVPhysicsKeyHandler *unknownKeyHandler ) = 0; + virtual void ParseVehicle( vehicleparams_t *pVehicle, IVPhysicsKeyHandler *unknownKeyHandler ) = 0; + virtual void SkipBlock( void ) = 0; +}; + +#endif // VCOLLIDE_PARSE_H diff --git a/public/vgui/Cursor.h b/public/vgui/Cursor.h new file mode 100644 index 0000000..be9ca78 --- /dev/null +++ b/public/vgui/Cursor.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Holds the enumerated list of default cursors +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CURSOR_H +#define CURSOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +enum CursorCode +{ + dc_user, + dc_none, + dc_arrow, + dc_ibeam, + dc_hourglass, + dc_waitarrow, + dc_crosshair, + dc_up, + dc_sizenwse, + dc_sizenesw, + dc_sizewe, + dc_sizens, + dc_sizeall, + dc_no, + dc_hand, + dc_blank, // don't show any custom vgui cursor, just let windows do it stuff (for HTML widget) + dc_last, + dc_alwaysvisible_push, + dc_alwaysvisible_pop, +}; + +typedef unsigned long HCursor; + +} + +#endif // CURSOR_H diff --git a/public/vgui/Dar.h b/public/vgui/Dar.h new file mode 100644 index 0000000..ee72008 --- /dev/null +++ b/public/vgui/Dar.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Holds the enumerated list of default cursors +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DAR_H +#define DAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include "tier1/utlvector.h" + +#include "tier0/memdbgon.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Simple lightweight dynamic array implementation +//----------------------------------------------------------------------------- +template class Dar : public CUtlVector< ELEMTYPE > +{ + typedef CUtlVector< ELEMTYPE > BaseClass; + +public: + Dar() + { + } + Dar(int initialCapacity) : + BaseClass( 0, initialCapacity ) + { + } + +public: + void SetCount(int count) + { + this->EnsureCount( count ); + } + int GetCount() + { + return this->Count(); + } + int AddElement(ELEMTYPE elem) + { + return this->AddToTail( elem ); + } + void MoveElementToEnd( ELEMTYPE elem ) + { + if ( this->Count() == 0 ) + return; + + // quick check to see if it's already at the end + if ( this->Element( this->Count() - 1 ) == elem ) + return; + + int idx = this->Find( elem ); + if ( idx == this->InvalidIndex() ) + return; + + this->Remove( idx ); + this->AddToTail( elem ); + } + // returns the index of the element in the array, -1 if not found + int FindElement(ELEMTYPE elem) + { + return this->Find( elem ); + } + bool HasElement(ELEMTYPE elem) + { + if ( this->FindElement(elem) != this->InvalidIndex() ) + { + return true; + } + return false; + } + int PutElement(ELEMTYPE elem) + { + int index = this->FindElement(elem); + if (index >= 0) + { + return index; + } + return this->AddElement(elem); + } + // insert element at index and move all the others down 1 + void InsertElementAt(ELEMTYPE elem,int index) + { + this->InsertBefore( index, elem ); + } + void SetElementAt(ELEMTYPE elem,int index) + { + this->EnsureCount( index + 1 ); + this->Element( index ) = elem; + } + void RemoveElementAt(int index) + { + this->Remove( index ); + } + + void RemoveElementsBefore(int index) + { + if ( index <= 0 ) + return; + this->RemoveMultiple( 0, index - 1 ); + } + + void RemoveElement(ELEMTYPE elem) + { + this->FindAndRemove( elem ); + } + + void *GetBaseData() + { + return this->Base(); + } + + void CopyFrom(Dar &dar) + { + this->CopyArray( dar.Base(), dar.Count() ); + } +}; + +} + +#include "tier0/memdbgoff.h" + +#endif // DAR_H diff --git a/public/vgui/IBorder.h b/public/vgui/IBorder.h new file mode 100644 index 0000000..e1237eb --- /dev/null +++ b/public/vgui/IBorder.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IBORDER_H +#define IBORDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +class KeyValues; + +namespace vgui +{ + +class IScheme; + +//----------------------------------------------------------------------------- +// Purpose: Interface to panel borders +// Borders have a close relationship with panels +// They are the edges of the panel. +//----------------------------------------------------------------------------- +class IBorder +{ +public: + IBorder() {} + virtual ~IBorder() {} + + virtual void Paint(VPANEL panel) = 0; + virtual void Paint(int x0, int y0, int x1, int y1) = 0; + virtual void Paint(int x0, int y0, int x1, int y1, int breakSide, int breakStart, int breakStop) = 0; + virtual void SetInset(int left, int top, int right, int bottom) = 0; + virtual void GetInset(int &left, int &top, int &right, int &bottom) = 0; + virtual void ApplySchemeSettings(IScheme *pScheme, KeyValues *inResourceData) = 0; + virtual const char *GetName() = 0; + virtual void SetName(const char *name) = 0; + + enum backgroundtype_e + { + BACKGROUND_FILLED, + BACKGROUND_TEXTURED, + BACKGROUND_ROUNDEDCORNERS, + }; + virtual backgroundtype_e GetBackgroundType() = 0; + + enum sides_e + { + SIDE_LEFT = 0, + SIDE_TOP = 1, + SIDE_RIGHT = 2, + SIDE_BOTTOM = 3 + }; + + virtual bool PaintFirst( void ) = 0; +}; + +} // namespace vgui + + +#endif // IBORDER_H diff --git a/public/vgui/IClientPanel.h b/public/vgui/IClientPanel.h new file mode 100644 index 0000000..ff96497 --- /dev/null +++ b/public/vgui/IClientPanel.h @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICLIENTPANEL_H +#define ICLIENTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +#ifdef GetClassName +#undef GetClassName +#endif + +class KeyValues; + +namespace vgui +{ + +class Panel; +class SurfaceBase; + +enum EInterfaceID +{ + ICLIENTPANEL_STANDARD_INTERFACE = 0, +}; + +//----------------------------------------------------------------------------- +// Purpose: Interface from vgui panels -> Client panels +// This interface cannot be changed without rebuilding all vgui projects +// Primarily this interface handles dispatching messages from core vgui to controls +// The additional functions are all their for debugging or optimization reasons +// To add to this later, use QueryInterface() to see if they support new interfaces +//----------------------------------------------------------------------------- +class IClientPanel +{ +public: + virtual VPANEL GetVPanel() = 0; + + // straight interface to Panel functions + virtual void Think() = 0; + virtual void PerformApplySchemeSettings() = 0; + virtual void PaintTraverse(bool forceRepaint, bool allowForce) = 0; + virtual void Repaint() = 0; + virtual VPANEL IsWithinTraverse(int x, int y, bool traversePopups) = 0; + virtual void GetInset(int &top, int &left, int &right, int &bottom) = 0; + virtual void GetClipRect(int &x0, int &y0, int &x1, int &y1) = 0; + virtual void OnChildAdded(VPANEL child) = 0; + virtual void OnSizeChanged(int newWide, int newTall) = 0; + + virtual void InternalFocusChanged(bool lost) = 0; + virtual bool RequestInfo(KeyValues *outputData) = 0; + virtual void RequestFocus(int direction) = 0; + virtual bool RequestFocusPrev(VPANEL existingPanel) = 0; + virtual bool RequestFocusNext(VPANEL existingPanel) = 0; + virtual void OnMessage(const KeyValues *params, VPANEL ifromPanel) = 0; + virtual VPANEL GetCurrentKeyFocus() = 0; + virtual int GetTabPosition() = 0; + + // for debugging purposes + virtual const char *GetName() = 0; + virtual const char *GetClassName() = 0; + + // get scheme handles from panels + virtual HScheme GetScheme() = 0; + // gets whether or not this panel should scale with screen resolution + virtual bool IsProportional() = 0; + // auto-deletion + virtual bool IsAutoDeleteSet() = 0; + // deletes this + virtual void DeletePanel() = 0; + + // interfaces + virtual void *QueryInterface(EInterfaceID id) = 0; + + // returns a pointer to the vgui controls baseclass Panel * + virtual Panel *GetPanel() = 0; + + // returns the name of the module this panel is part of + virtual const char *GetModuleName() = 0; + + virtual void OnTick() = 0; +}; + +} // namespace vgui + + +#endif // ICLIENTPANEL_H diff --git a/public/vgui/IHTML.h b/public/vgui/IHTML.h new file mode 100644 index 0000000..e296a0c --- /dev/null +++ b/public/vgui/IHTML.h @@ -0,0 +1,201 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IHTML_H +#define IHTML_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include + +namespace vgui +{ + + //----------------------------------------------------------------------------- + // Purpose: basic interface for a HTML window + //----------------------------------------------------------------------------- + class IHTML + { + public: + // open a new page + virtual void OpenURL(const char *)=0; + + // stops the existing page from loading + virtual bool StopLoading()=0; + + // refreshes the current page + virtual bool Refresh()=0; + + // display the control -- deprecated !! Use SetVisible() instead! + virtual bool Show(bool shown)=0; + + // return the currently opened page + virtual const char *GetOpenedPage()=0; + + // called when the browser needs to be resized + virtual void Obsolete_OnSize(int x,int y, int w,int h)=0; + + // returns the width and height (in pixels) of the HTML full page (not just the displayed region) + virtual void GetHTMLSize(int &wide,int &tall) = 0; + + + // clear the text in an existing control + virtual void Clear()=0; + + // add text to the browser control (as a HTML formated string) + virtual void AddText(const char *text)=0; + + enum MOUSE_STATE { UP,DOWN,MOVE,DBLCLICK }; + // unused functions we keep around so the vtable layout is binary compatible + virtual void Obsolete_OnMouse(MouseCode code,MOUSE_STATE s,int x,int y)=0; + virtual void Obsolete_OnChar(wchar_t unichar)=0; + virtual void Obsolete_OnKeyDown(KeyCode code)=0; + + virtual vgui::IImage *GetBitmap()=0; + virtual void SetVisible( bool state ) = 0; + + + virtual void SetSize( int wide,int tall )=0; + + virtual void OnMouse(MouseCode code,MOUSE_STATE s,int x,int y, bool bPopupMenuMenu )=0; + virtual void OnChar(wchar_t unichar, bool bPopupMenu)=0; + virtual void OnKeyDown(KeyCode code, bool bPopupMenu)=0; + + virtual void ScrollV( int nPixels ) = 0; + virtual void ScrollH( int nPixels ) = 0; + virtual void OnMouseWheeled( int delta, bool bPopupMenu )= 0; + + // called when the browser needs to be resized + virtual void OnKeyUp(KeyCode code, bool bPopupMenu)=0; + + + // open a URL with the provided POST data (which can be much larger than the max URL of 512 chars) + // NOTE - You CANNOT have get params (i.e a "?" ) in pchURL if pchPostData is set (due to an IE bug) + virtual void PostURL( const char *pchURL, const char *pchPostData ) = 0; + + // Run javascript within the browser control + virtual void RunJavascript( const char *pchScript ) = 0; + + virtual void SetMousePosition( int x, int y, bool bPopupMenu ) = 0; + + virtual void SetUserAgentInfo( const wchar_t *pwchUserAgent ) = 0; + + // can't add custom headers to IE + virtual void AddHeader( const char *pchHeader, const char *pchValue ) = 0; + + virtual void SetFileDialogChoice( const char *pchFileName ) = 0; + + // we are hiding the popup, so make sure webkit knows + virtual void HidePopup() = 0; + virtual void SetHTMLFocus() = 0; + virtual void KillHTMLFocus() = 0; + // ask webkit about the size of any scrollbars it wants to render + virtual void HorizontalScrollBarSize( int &x, int &y, int &wide, int &tall) = 0; + virtual void VerticalScrollBarSize( int &x, int &y, int &wide, int &tall) = 0; + virtual int HorizontalScroll() = 0; + virtual int VerticalScroll() = 0; + virtual int HorizontalScrollMax() =0; + virtual int VerticalScrollMax() =0; + virtual bool IsHorizontalScrollBarVisible() =0; + virtual bool IsVeritcalScrollBarVisible() =0; + virtual void SetHorizontalScroll( int scroll ) =0; + virtual void SetVerticalScroll( int scroll ) =0; + virtual void ViewSource() = 0; + virtual void Copy() = 0; + virtual void Paste() = 0; + + // IE specific calls + virtual bool IsIERender() = 0; + virtual void GetIDispatchPtr( void **pIDispatch ) = 0; + virtual void GetHTMLScroll( int &top, int &left ) = 0; + }; + + + //----------------------------------------------------------------------------- + // Purpose: possible load errors when you open a url in the web browser + //----------------------------------------------------------------------------- + enum EWebPageLoadError + { + eLoadErrorNone = 0, + eMimeTypeNotSupported, // probably trying to download an exe or something + eCacheMiss, // Usually caused by navigating to a page with POST data via back or forward buttons + eBadURL, // bad url passed in (invalid hostname, malformed) + eConnectionProblem, // network connectivity problem, server offline or user not on internet + eProxyConnectionProblem, // User is configured to use proxy, but we can't use it + + eLoadErrorUnknown, // not a load type we classify right now, check out cef_handler_errorcode_t for the full list we could translate + }; + + + //----------------------------------------------------------------------------- + // Purpose: basic callback interface for a HTML window + //----------------------------------------------------------------------------- + class IHTMLEvents + { + public: + // unused functions we keep around so the vtable layout is binary compatible + virtual bool Obsolete_OnStartURL(const char *url, const char *target, bool first)=0; + virtual void Obsolete_OnFinishURL(const char *url)=0; + virtual void Obsolete_OnProgressURL(long current, long maximum)=0; + virtual void Obsolete_OnSetStatusText(const char *text) =0; + virtual void Obsolete_OnUpdate() =0; + virtual void Obsolete_OnLink()=0; + virtual void Obsolete_OffLink()=0; + + // call backs for events + // when the top level browser is changing the page they are looking at (not sub iframes or the like loading) + virtual void OnURLChanged( const char *url, const char *pchPostData, bool bIsRedirect ) = 0; + // the control has finished loading a request, could be a sub request in the page + virtual void OnFinishRequest( const char *url, const char *pageTitle ) = 0; + + // the lower html control wants to load a url, do we allow it? + virtual bool OnStartRequestInternal( const char *url, const char *target, const char *pchPostData, bool bIsRedirect ) = 0; + + // show a popup menu for this html control + virtual void ShowPopup( int x, int y, int wide, int tall ) = 0; + // hide any popup menu you are showing + virtual void HidePopup() = 0; + // show an external html window at this position and side + virtual bool OnPopupHTMLWindow( const char *pchURL, int x, int y, int wide, int tall ) = 0; + // the browser is telling us the title it would like us to show + virtual void SetHTMLTitle( const char *pchTitle ) = 0; + // the browser is loading a sub url for a page, usually an image or css + virtual void OnLoadingResource( const char *pchURL ) = 0; + // the browser is telling us the user is hovering a url or the like + virtual void OnSetStatusText(const char *text) =0; + // the browser wants the cursor changed please + virtual void OnSetCursor( vgui::CursorCode cursor ) = 0; + // the browser wants to ask the user to select a local file and tell it about it + virtual void OnFileLoadDialog( const char *pchTitle, const char *pchInitialFile ) = 0; + // show and hide tooltip text + virtual void OnShowToolTip( const char *pchText ) = 0; + virtual void OnUpdateToolTip( const char *pchText ) = 0; + virtual void OnHideToolTip() = 0; + + + // IE only code + virtual bool BOnCreateNewWindow( void **ppDispatch ) = 0; + virtual void OnLink()=0; + virtual void OffLink()=0; + virtual void OnCloseWindow() = 0; + virtual void OnUpdate() =0; + virtual void OnProgressRequest(long current, long maximum)=0; + + // new Chrome calls + virtual bool OnOpenNewTab( const char *pchURL, bool bForeground ) = 0; + }; + + +} + +#endif // IHTML_H diff --git a/public/vgui/IImage.h b/public/vgui/IImage.h new file mode 100644 index 0000000..eadc964 --- /dev/null +++ b/public/vgui/IImage.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IIMAGE_H +#define IIMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +class Color; + +namespace vgui +{ + +typedef unsigned long HTexture; + +enum iimage_rotation_t +{ + ROTATED_UNROTATED = 0, + ROTATED_CLOCKWISE_90, + ROTATED_ANTICLOCKWISE_90, + ROTATED_FLIPPED, +}; + +//----------------------------------------------------------------------------- +// Purpose: Interface to drawing an image +//----------------------------------------------------------------------------- +class IImage +{ +public: + // Call to Paint the image + // Image will draw within the current panel context at the specified position + virtual void Paint() = 0; + + // Set the position of the image + virtual void SetPos(int x, int y) = 0; + + // Gets the size of the content + virtual void GetContentSize(int &wide, int &tall) = 0; + + // Get the size the image will actually draw in (usually defaults to the content size) + virtual void GetSize(int &wide, int &tall) = 0; + + // Sets the size of the image + virtual void SetSize(int wide, int tall) = 0; + + // Set the draw color + virtual void SetColor(Color col) = 0; + + // virtual destructor + virtual ~IImage() {} + + // not for general purpose use + // evicts the underlying image from memory if refcounts permit, otherwise ignored + // returns true if eviction occurred, otherwise false + virtual bool Evict() = 0; + + virtual int GetNumFrames() = 0; + virtual void SetFrame( int nFrame ) = 0; + virtual HTexture GetID() = 0; + + virtual void SetRotation( int iRotation ) = 0; +}; + +} // namespace vgui + + +#endif // IIMAGE_H diff --git a/public/vgui/IInput.h b/public/vgui/IInput.h new file mode 100644 index 0000000..26077e4 --- /dev/null +++ b/public/vgui/IInput.h @@ -0,0 +1,193 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef VGUI_IINPUT_H +#define VGUI_IINPUT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier1/interface.h" +#include "vgui/MouseCode.h" +#include "vgui/KeyCode.h" + +namespace vgui +{ + +class Cursor; +typedef unsigned long HCursor; + +#define VGUI_GCS_COMPREADSTR 0x0001 +#define VGUI_GCS_COMPREADATTR 0x0002 +#define VGUI_GCS_COMPREADCLAUSE 0x0004 +#define VGUI_GCS_COMPSTR 0x0008 +#define VGUI_GCS_COMPATTR 0x0010 +#define VGUI_GCS_COMPCLAUSE 0x0020 +#define VGUI_GCS_CURSORPOS 0x0080 +#define VGUI_GCS_DELTASTART 0x0100 +#define VGUI_GCS_RESULTREADSTR 0x0200 +#define VGUI_GCS_RESULTREADCLAUSE 0x0400 +#define VGUI_GCS_RESULTSTR 0x0800 +#define VGUI_GCS_RESULTCLAUSE 0x1000 +// style bit flags for WM_IME_COMPOSITION +#define VGUI_CS_INSERTCHAR 0x2000 +#define VGUI_CS_NOMOVECARET 0x4000 + +#define MESSAGE_CURSOR_POS -1 +#define MESSAGE_CURRENT_KEYFOCUS -2 + + +class IInput : public IBaseInterface +{ +public: + virtual void SetMouseFocus(VPANEL newMouseFocus) = 0; + virtual void SetMouseCapture(VPANEL panel) = 0; + + // returns the string name of a scan code + virtual void GetKeyCodeText(KeyCode code, OUT_Z_BYTECAP(buflen) char *buf, int buflen) = 0; + + // focus + virtual VPANEL GetFocus() = 0; + virtual VPANEL GetCalculatedFocus() = 0;// to handle cases where the focus changes inside a frame. + virtual VPANEL GetMouseOver() = 0; // returns the panel the mouse is currently over, ignoring mouse capture + + // mouse state + virtual void SetCursorPos(int x, int y) = 0; + virtual void GetCursorPos(int &x, int &y) = 0; + virtual bool WasMousePressed(MouseCode code) = 0; + virtual bool WasMouseDoublePressed(MouseCode code) = 0; + virtual bool IsMouseDown(MouseCode code) = 0; + + // cursor override + virtual void SetCursorOveride(HCursor cursor) = 0; + virtual HCursor GetCursorOveride() = 0; + + // key state + virtual bool WasMouseReleased(MouseCode code) = 0; + virtual bool WasKeyPressed(KeyCode code) = 0; + virtual bool IsKeyDown(KeyCode code) = 0; + virtual bool WasKeyTyped(KeyCode code) = 0; + virtual bool WasKeyReleased(KeyCode code) = 0; + + virtual VPANEL GetAppModalSurface() = 0; + // set the modal dialog panel. + // all events will go only to this panel and its children. + virtual void SetAppModalSurface(VPANEL panel) = 0; + // release the modal dialog panel + // do this when your modal dialog finishes. + virtual void ReleaseAppModalSurface() = 0; + + virtual void GetCursorPosition( int &x, int &y ) = 0; + + virtual void SetIMEWindow( void *hwnd ) = 0; + virtual void *GetIMEWindow() = 0; + + virtual void OnChangeIME( bool forward ) = 0; + virtual int GetCurrentIMEHandle() = 0; + virtual int GetEnglishIMEHandle() = 0; + + // Returns the Language Bar label (Chinese, Korean, Japanese, Russion, Thai, etc.) + virtual void GetIMELanguageName( OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *buf, int unicodeBufferSizeInBytes ) = 0; + // Returns the short code for the language (EN, CH, KO, JP, RU, TH, etc. ). + virtual void GetIMELanguageShortCode( OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t *buf, int unicodeBufferSizeInBytes ) = 0; + + struct LanguageItem + { + wchar_t shortname[ 4 ]; + wchar_t menuname[ 128 ]; + int handleValue; + bool active; // true if this is the active language + }; + + struct ConversionModeItem + { + wchar_t menuname[ 128 ]; + int handleValue; + bool active; // true if this is the active conversion mode + }; + + struct SentenceModeItem + { + wchar_t menuname[ 128 ]; + int handleValue; + bool active; // true if this is the active sentence mode + }; + + // Call with NULL dest to get item count + virtual int GetIMELanguageList( LanguageItem *dest, int destcount ) = 0; + virtual int GetIMEConversionModes( ConversionModeItem *dest, int destcount ) = 0; + virtual int GetIMESentenceModes( SentenceModeItem *dest, int destcount ) = 0; + + virtual void OnChangeIMEByHandle( int handleValue ) = 0; + virtual void OnChangeIMEConversionModeByHandle( int handleValue ) = 0; + virtual void OnChangeIMESentenceModeByHandle( int handleValue ) = 0; + + virtual void OnInputLanguageChanged() = 0; + virtual void OnIMEStartComposition() = 0; + virtual void OnIMEComposition( int flags ) = 0; + virtual void OnIMEEndComposition() = 0; + + virtual void OnIMEShowCandidates() = 0; + virtual void OnIMEChangeCandidates() = 0; + virtual void OnIMECloseCandidates() = 0; + virtual void OnIMERecomputeModes() = 0; + + virtual int GetCandidateListCount() = 0; + virtual void GetCandidate( int num, OUT_Z_BYTECAP(destSizeBytes) wchar_t *dest, int destSizeBytes ) = 0; + virtual int GetCandidateListSelectedItem() = 0; + virtual int GetCandidateListPageSize() = 0; + virtual int GetCandidateListPageStart() = 0; + + //NOTE: We render our own candidate lists most of the time... + virtual void SetCandidateWindowPos( int x, int y ) = 0; + + virtual bool GetShouldInvertCompositionString() = 0; + virtual bool CandidateListStartsAtOne() = 0; + + virtual void SetCandidateListPageStart( int start ) = 0; + + // Passes in a keycode which allows hitting other mouse buttons w/o cancelling capture mode + virtual void SetMouseCaptureEx(VPANEL panel, MouseCode captureStartMouseCode ) = 0; + + // Because OnKeyCodeTyped uses CallParentFunction and is therefore message based, there's no way + // to know if handler actually swallowed the specified keycode. To get around this, I set a global before calling the + // kb focus OnKeyCodeTyped function and if we ever get to a Panel::OnKeyCodeTypes we know that nobody handled the message + // and in that case we can post a message to any "unhandled keycode" listeners + // This will generate an MESSAGE_FUNC_INT( "KeyCodeUnhandled" "code" code ) message to each such listener + virtual void RegisterKeyCodeUnhandledListener( VPANEL panel ) = 0; + virtual void UnregisterKeyCodeUnhandledListener( VPANEL panel ) = 0; + + // Posts unhandled message to all interested panels + virtual void OnKeyCodeUnhandled( int keyCode ) = 0; + + // Assumes subTree is a child panel of the root panel for the vgui contect + // if restrictMessagesToSubTree is true, then mouse and kb messages are only routed to the subTree and it's children and mouse/kb focus + // can only be on one of the subTree children, if a mouse click occurs outside of the subtree, and "UnhandledMouseClick" message is sent to unhandledMouseClickListener panel + // if it's set + // if restrictMessagesToSubTree is false, then mouse and kb messages are routed as normal except that they are not routed down into the subtree + // however, if a mouse click occurs outside of the subtree, and "UnhandleMouseClick" message is sent to unhandledMouseClickListener panel + // if it's set + virtual void SetModalSubTree( VPANEL subTree, VPANEL unhandledMouseClickListener, bool restrictMessagesToSubTree = true ) = 0; + virtual void ReleaseModalSubTree() = 0; + virtual VPANEL GetModalSubTree() = 0; + + // These toggle whether the modal subtree is exclusively receiving messages or conversely whether it's being excluded from receiving messages + // Sends a "ModalSubTree", state message + virtual void SetModalSubTreeReceiveMessages( bool state ) = 0; + virtual bool ShouldModalSubTreeReceiveMessages() const = 0; + + virtual VPANEL GetMouseCapture() = 0; +}; + +#define VGUI_INPUT_INTERFACE_VERSION "VGUI_Input005" + +} // namespace vgui + + +#endif // VGUI_IINPUT_H diff --git a/public/vgui/IInputInternal.h b/public/vgui/IInputInternal.h new file mode 100644 index 0000000..a72eaa8 --- /dev/null +++ b/public/vgui/IInputInternal.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef IINPUTINTERNAL_H +#define IINPUTINTERNAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +enum MouseCodeState_t +{ + BUTTON_RELEASED = 0, + BUTTON_PRESSED, + BUTTON_DOUBLECLICKED, +}; + +typedef int HInputContext; + +#define DEFAULT_INPUT_CONTEXT ((vgui::HInputContext)~0) + +class IInputInternal : public IInput +{ +public: + // processes input for a frame + virtual void RunFrame() = 0; + + virtual void UpdateMouseFocus(int x, int y) = 0; + + // called when a panel becomes invalid + virtual void PanelDeleted(VPANEL panel) = 0; + + // inputs into vgui input handling + virtual bool InternalCursorMoved(int x,int y) = 0; //expects input in surface space + virtual bool InternalMousePressed(MouseCode code) = 0; + virtual bool InternalMouseDoublePressed(MouseCode code) = 0; + virtual bool InternalMouseReleased(MouseCode code) = 0; + virtual bool InternalMouseWheeled(int delta) = 0; + virtual bool InternalKeyCodePressed(KeyCode code) = 0; + virtual void InternalKeyCodeTyped(KeyCode code) = 0; + virtual void InternalKeyTyped(wchar_t unichar) = 0; + virtual bool InternalKeyCodeReleased(KeyCode code) = 0; + + // Creates/ destroys "input" contexts, which contains information + // about which controls have mouse + key focus, for example. + virtual HInputContext CreateInputContext() = 0; + virtual void DestroyInputContext( HInputContext context ) = 0; + + // Associates a particular panel with an input context + // Associating NULL is valid; it disconnects the panel from the context + virtual void AssociatePanelWithInputContext( HInputContext context, VPANEL pRoot ) = 0; + + // Activates a particular input context, use DEFAULT_INPUT_CONTEXT + // to get the one normally used by VGUI + virtual void ActivateInputContext( HInputContext context ) = 0; + + // This method is called to post a cursor message to the current input context + virtual void PostCursorMessage() = 0; + + // Cursor position; this is the current position read from the input queue. + // We need to set it because client code may read this during Mouse Pressed + // events, etc. + virtual void UpdateCursorPosInternal( int x, int y ) = 0; + + // Called to handle explicit calls to CursorSetPos after input processing is complete + virtual void HandleExplicitSetCursor( ) = 0; + + // Updates the internal key/mouse state associated with the current input context without sending messages + virtual void SetKeyCodeState( KeyCode code, bool bPressed ) = 0; + virtual void SetMouseCodeState( MouseCode code, MouseCodeState_t state ) = 0; + virtual void UpdateButtonState( const InputEvent_t &event ) = 0; +}; + +} // namespace vgui + +#define VGUI_INPUTINTERNAL_INTERFACE_VERSION "VGUI_InputInternal001" + +#endif // IINPUTINTERNAL_H diff --git a/public/vgui/ILocalize.h b/public/vgui/ILocalize.h new file mode 100644 index 0000000..808acb4 --- /dev/null +++ b/public/vgui/ILocalize.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ILOCALIZE_H +#define ILOCALIZE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/ilocalize.h" + +namespace vgui +{ + class ILocalize : public ::ILocalize { }; // backwards compatability with vgui::ILocalize declarations +} + +#define VGUI_LOCALIZE_INTERFACE_VERSION "VGUI_Localize005" + +#endif // ILOCALIZE_H diff --git a/public/vgui/IPanel.h b/public/vgui/IPanel.h new file mode 100644 index 0000000..a0313e0 --- /dev/null +++ b/public/vgui/IPanel.h @@ -0,0 +1,139 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IPANEL_H +#define IPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier1/interface.h" +#include "tier1/utlvector.h" + +#ifdef SendMessage +#undef SendMessage +#endif + +class KeyValues; + +namespace vgui +{ + +class SurfacePlat; +class IClientPanel; + +//!! must be removed +class Panel; + +//----------------------------------------------------------------------------- +// Purpose: interface from Client panels -> vgui panels +//----------------------------------------------------------------------------- +class IPanel : public IBaseInterface +{ +public: + virtual void Init(VPANEL vguiPanel, IClientPanel *panel) = 0; + + // methods + virtual void SetPos(VPANEL vguiPanel, int x, int y) = 0; + virtual void GetPos(VPANEL vguiPanel, int &x, int &y) = 0; + virtual void SetSize(VPANEL vguiPanel, int wide,int tall) = 0; + virtual void GetSize(VPANEL vguiPanel, int &wide, int &tall) = 0; + virtual void SetMinimumSize(VPANEL vguiPanel, int wide, int tall) = 0; + virtual void GetMinimumSize(VPANEL vguiPanel, int &wide, int &tall) = 0; + virtual void SetZPos(VPANEL vguiPanel, int z) = 0; + virtual int GetZPos(VPANEL vguiPanel) = 0; + + virtual void GetAbsPos(VPANEL vguiPanel, int &x, int &y) = 0; + virtual void GetClipRect(VPANEL vguiPanel, int &x0, int &y0, int &x1, int &y1) = 0; + virtual void SetInset(VPANEL vguiPanel, int left, int top, int right, int bottom) = 0; + virtual void GetInset(VPANEL vguiPanel, int &left, int &top, int &right, int &bottom) = 0; + + virtual void SetVisible(VPANEL vguiPanel, bool state) = 0; + virtual bool IsVisible(VPANEL vguiPanel) = 0; + virtual void SetParent(VPANEL vguiPanel, VPANEL newParent) = 0; + virtual int GetChildCount(VPANEL vguiPanel) = 0; + virtual VPANEL GetChild(VPANEL vguiPanel, int index) = 0; + virtual CUtlVector< VPANEL > &GetChildren( VPANEL vguiPanel ) = 0; + virtual VPANEL GetParent(VPANEL vguiPanel) = 0; + virtual void MoveToFront(VPANEL vguiPanel) = 0; + virtual void MoveToBack(VPANEL vguiPanel) = 0; + virtual bool HasParent(VPANEL vguiPanel, VPANEL potentialParent) = 0; + virtual bool IsPopup(VPANEL vguiPanel) = 0; + virtual void SetPopup(VPANEL vguiPanel, bool state) = 0; + virtual bool IsFullyVisible( VPANEL vguiPanel ) = 0; + + // gets the scheme this panel uses + virtual HScheme GetScheme(VPANEL vguiPanel) = 0; + // gets whether or not this panel should scale with screen resolution + virtual bool IsProportional(VPANEL vguiPanel) = 0; + // returns true if auto-deletion flag is set + virtual bool IsAutoDeleteSet(VPANEL vguiPanel) = 0; + // deletes the Panel * associated with the vpanel + virtual void DeletePanel(VPANEL vguiPanel) = 0; + + // input interest + virtual void SetKeyBoardInputEnabled(VPANEL vguiPanel, bool state) = 0; + virtual void SetMouseInputEnabled(VPANEL vguiPanel, bool state) = 0; + virtual bool IsKeyBoardInputEnabled(VPANEL vguiPanel) = 0; + virtual bool IsMouseInputEnabled(VPANEL vguiPanel) = 0; + + // calculates the panels current position within the hierarchy + virtual void Solve(VPANEL vguiPanel) = 0; + + // gets names of the object (for debugging purposes) + virtual const char *GetName(VPANEL vguiPanel) = 0; + virtual const char *GetClassName(VPANEL vguiPanel) = 0; + + // delivers a message to the panel + virtual void SendMessage(VPANEL vguiPanel, KeyValues *params, VPANEL ifromPanel) = 0; + + // these pass through to the IClientPanel + virtual void Think(VPANEL vguiPanel) = 0; + virtual void PerformApplySchemeSettings(VPANEL vguiPanel) = 0; + virtual void PaintTraverse(VPANEL vguiPanel, bool forceRepaint, bool allowForce = true) = 0; + virtual void Repaint(VPANEL vguiPanel) = 0; + virtual VPANEL IsWithinTraverse(VPANEL vguiPanel, int x, int y, bool traversePopups) = 0; + virtual void OnChildAdded(VPANEL vguiPanel, VPANEL child) = 0; + virtual void OnSizeChanged(VPANEL vguiPanel, int newWide, int newTall) = 0; + + virtual void InternalFocusChanged(VPANEL vguiPanel, bool lost) = 0; + virtual bool RequestInfo(VPANEL vguiPanel, KeyValues *outputData) = 0; + virtual void RequestFocus(VPANEL vguiPanel, int direction = 0) = 0; + virtual bool RequestFocusPrev(VPANEL vguiPanel, VPANEL existingPanel) = 0; + virtual bool RequestFocusNext(VPANEL vguiPanel, VPANEL existingPanel) = 0; + virtual VPANEL GetCurrentKeyFocus(VPANEL vguiPanel) = 0; + virtual int GetTabPosition(VPANEL vguiPanel) = 0; + + // used by ISurface to store platform-specific data + virtual SurfacePlat *Plat(VPANEL vguiPanel) = 0; + virtual void SetPlat(VPANEL vguiPanel, SurfacePlat *Plat) = 0; + + // returns a pointer to the vgui controls baseclass Panel * + // destinationModule needs to be passed in to verify that the returned Panel * is from the same module + // it must be from the same module since Panel * vtbl may be different in each module + virtual Panel *GetPanel(VPANEL vguiPanel, const char *destinationModule) = 0; + + virtual bool IsEnabled(VPANEL vguiPanel) = 0; + virtual void SetEnabled(VPANEL vguiPanel, bool state) = 0; + + // Used by the drag/drop manager to always draw on top + virtual bool IsTopmostPopup( VPANEL vguiPanel) = 0; + virtual void SetTopmostPopup( VPANEL vguiPanel, bool state ) = 0; + + // sibling pins + virtual void SetSiblingPin(VPANEL vguiPanel, VPANEL newSibling, byte iMyCornerToPin = 0, byte iSiblingCornerToPinTo = 0 ) = 0; + +}; + +#define VGUI_PANEL_INTERFACE_VERSION "VGUI_Panel009" + +} // namespace vgui + + +#endif // IPANEL_H diff --git a/public/vgui/IScheme.h b/public/vgui/IScheme.h new file mode 100644 index 0000000..25b221e --- /dev/null +++ b/public/vgui/IScheme.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISCHEME_H +#define ISCHEME_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier1/interface.h" + +class Color; +class KeyValues; + +namespace vgui +{ + +typedef unsigned long HScheme; +typedef unsigned long HTexture; + +class IBorder; +class IImage; + +//----------------------------------------------------------------------------- +// Purpose: Holds all panel rendering data +// This functionality is all wrapped in the Panel::GetScheme*() functions +//----------------------------------------------------------------------------- +class IScheme : public IBaseInterface +{ +public: + // gets a string from the default settings section + virtual const char *GetResourceString(const char *stringName) = 0; + + // returns a pointer to an existing border + virtual IBorder *GetBorder(const char *borderName) = 0; + + // returns a pointer to an existing font + virtual HFont GetFont(const char *fontName, bool proportional = false) = 0; + + // inverse font lookup + virtual char const *GetFontName( const HFont& font ) = 0; + + // colors + virtual Color GetColor(const char *colorName, Color defaultColor) = 0; + + // Get the number of borders + virtual int GetBorderCount() const = 0; + + // Get the border at the given index + virtual IBorder *GetBorderAtIndex( int iIndex ) = 0; + + // Get the number of fonts + virtual int GetFontCount() const = 0; + + // Get the font at the given index + virtual HFont GetFontAtIndex( int iIndex ) = 0; + + // Get color data + virtual const KeyValues *GetColorData() const = 0; +}; + + + +class ISchemeManager: public IBaseInterface +{ +public: + // loads a scheme from a file + // first scheme loaded becomes the default scheme, and all subsequent loaded scheme are derivitives of that + virtual HScheme LoadSchemeFromFile(const char *fileName, const char *tag) = 0; + + // reloads the scheme from the file - should only be used during development + virtual void ReloadSchemes() = 0; + + // reloads scheme fonts + virtual void ReloadFonts() = 0; + + // returns a handle to the default (first loaded) scheme + virtual HScheme GetDefaultScheme() = 0; + + // returns a handle to the scheme identified by "tag" + virtual HScheme GetScheme(const char *tag) = 0; + + // returns a pointer to an image + virtual IImage *GetImage(const char *imageName, bool hardwareFiltered) = 0; + virtual HTexture GetImageID(const char *imageName, bool hardwareFiltered) = 0; + + // This can only be called at certain times, like during paint() + // It will assert-fail if you call it at the wrong time... + + // FIXME: This interface should go away!!! It's an icky back-door + // If you're using this interface, try instead to cache off the information + // in ApplySchemeSettings + virtual IScheme *GetIScheme( HScheme scheme ) = 0; + + // unload all schemes + virtual void Shutdown( bool full = true ) = 0; + + // gets the proportional coordinates for doing screen-size independant panel layouts + // use these for font, image and panel size scaling (they all use the pixel height of the display for scaling) + virtual int GetProportionalScaledValue( int normalizedValue) = 0; + virtual int GetProportionalNormalizedValue(int scaledValue) = 0; + + // loads a scheme from a file + // first scheme loaded becomes the default scheme, and all subsequent loaded scheme are derivitives of that + virtual HScheme LoadSchemeFromFileEx( VPANEL sizingPanel, const char *fileName, const char *tag) = 0; + // gets the proportional coordinates for doing screen-size independant panel layouts + // use these for font, image and panel size scaling (they all use the pixel height of the display for scaling) + virtual int GetProportionalScaledValueEx( HScheme scheme, int normalizedValue ) = 0; + virtual int GetProportionalNormalizedValueEx( HScheme scheme, int scaledValue ) = 0; + + // Returns true if image evicted, false otherwise + virtual bool DeleteImage( const char *pImageName ) = 0; +}; + +#define VGUI_SCHEME_INTERFACE_VERSION "VGUI_Scheme010" + + +} // namespace vgui + + +#endif // ISCHEME_H diff --git a/public/vgui/ISurface.h b/public/vgui/ISurface.h new file mode 100644 index 0000000..4ec5899 --- /dev/null +++ b/public/vgui/ISurface.h @@ -0,0 +1,409 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ISURFACE_H +#define ISURFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include // CreateHTML, PaintHTML +#include "tier1/interface.h" +#include "bitmap/imageformat.h" + +#include "appframework/IAppSystem.h" +#include "mathlib/vector2d.h" // must be before the namespace line + +#include "IVguiMatInfo.h" + +#ifdef CreateFont +#undef CreateFont +#endif + +#ifdef PlaySound +#undef PlaySound +#endif + +class Color; +class ITexture; + +namespace vgui +{ + +class IImage; +class Image; +class Point; + +// handles +typedef unsigned long HCursor; +typedef unsigned long HTexture; +typedef unsigned long HFont; + + +//SRC only defines + + +struct Vertex_t +{ + Vertex_t() {} + Vertex_t( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) + { + m_Position = pos; + m_TexCoord = coord; + } + void Init( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) + { + m_Position = pos; + m_TexCoord = coord; + } + + Vector2D m_Position; + Vector2D m_TexCoord; +}; + + +enum FontDrawType_t +{ + // Use the "additive" value from the scheme file + FONT_DRAW_DEFAULT = 0, + + // Overrides + FONT_DRAW_NONADDITIVE, + FONT_DRAW_ADDITIVE, + + FONT_DRAW_TYPE_COUNT = 2, +}; + + +// Refactor these two +struct CharRenderInfo +{ + // Text pos + int x, y; + // Top left and bottom right + // This is now a pointer to an array maintained by the surface, to avoid copying the data on the 360 + Vertex_t *verts; + int textureId; + int abcA; + int abcB; + int abcC; + int fontTall; + HFont currentFont; + // In: + FontDrawType_t drawType; + wchar_t ch; + + // Out + bool valid; + // In/Out (true by default) + bool shouldclip; +}; + + +struct IntRect +{ + int x0; + int y0; + int x1; + int y1; +}; + +//----------------------------------------------------------------------------- +// Purpose: Wraps contextless windows system functions +//----------------------------------------------------------------------------- +class ISurface : public IAppSystem +{ +public: + // call to Shutdown surface; surface can no longer be used after this is called + virtual void Shutdown() = 0; + + // frame + virtual void RunFrame() = 0; + + // hierarchy root + virtual VPANEL GetEmbeddedPanel() = 0; + virtual void SetEmbeddedPanel( VPANEL pPanel ) = 0; + + // drawing context + virtual void PushMakeCurrent(VPANEL panel, bool useInsets) = 0; + virtual void PopMakeCurrent(VPANEL panel) = 0; + + // rendering functions + virtual void DrawSetColor(int r, int g, int b, int a) = 0; + virtual void DrawSetColor(Color col) = 0; + + virtual void DrawFilledRect(int x0, int y0, int x1, int y1) = 0; + virtual void DrawFilledRectArray( IntRect *pRects, int numRects ) = 0; + virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1) = 0; + + virtual void DrawLine(int x0, int y0, int x1, int y1) = 0; + virtual void DrawPolyLine(int *px, int *py, int numPoints) = 0; + + virtual void DrawSetTextFont(HFont font) = 0; + virtual void DrawSetTextColor(int r, int g, int b, int a) = 0; + virtual void DrawSetTextColor(Color col) = 0; + virtual void DrawSetTextPos(int x, int y) = 0; + virtual void DrawGetTextPos(int& x,int& y) = 0; + virtual void DrawPrintText(const wchar_t *text, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + + virtual void DrawFlushText() = 0; // flushes any buffered text (for rendering optimizations) + virtual IHTML *CreateHTMLWindow(vgui::IHTMLEvents *events,VPANEL context)=0; + virtual void PaintHTMLWindow(vgui::IHTML *htmlwin) =0; + virtual void DeleteHTMLWindow(IHTML *htmlwin)=0; + + enum ETextureFormat + { + eTextureFormat_RGBA, + eTextureFormat_BGRA, + eTextureFormat_BGRA_Opaque, // bgra format but alpha is always 255, CEF does this, we can use this fact for better perf on win32 gdi + }; + + virtual int DrawGetTextureId( char const *filename ) = 0; + virtual bool DrawGetTextureFile(int id, char *filename, int maxlen ) = 0; + virtual void DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload) = 0; + virtual void DrawSetTextureRGBA(int id, const unsigned char *rgba, int wide, int tall, int hardwareFilter, bool forceReload)=0; + virtual void DrawSetTexture(int id) = 0; + virtual void DrawGetTextureSize(int id, int &wide, int &tall) = 0; + virtual void DrawTexturedRect(int x0, int y0, int x1, int y1) = 0; + virtual bool IsTextureIDValid(int id) = 0; + virtual bool DeleteTextureByID(int id) = 0; + + virtual int CreateNewTextureID( bool procedural = false ) = 0; + + virtual void GetScreenSize(int &wide, int &tall) = 0; + virtual void SetAsTopMost(VPANEL panel, bool state) = 0; + virtual void BringToFront(VPANEL panel) = 0; + virtual void SetForegroundWindow (VPANEL panel) = 0; + virtual void SetPanelVisible(VPANEL panel, bool state) = 0; + virtual void SetMinimized(VPANEL panel, bool state) = 0; + virtual bool IsMinimized(VPANEL panel) = 0; + virtual void FlashWindow(VPANEL panel, bool state) = 0; + virtual void SetTitle(VPANEL panel, const wchar_t *title) = 0; + virtual void SetAsToolBar(VPANEL panel, bool state) = 0; // removes the window's task bar entry (for context menu's, etc.) + + // windows stuff + virtual void CreatePopup(VPANEL panel, bool minimised, bool showTaskbarIcon = true, bool disabled = false, bool mouseInput = true , bool kbInput = true) = 0; + virtual void SwapBuffers(VPANEL panel) = 0; + virtual void Invalidate(VPANEL panel) = 0; + virtual void SetCursor(HCursor cursor) = 0; + virtual void SetCursorAlwaysVisible( bool visible ) = 0; + virtual bool IsCursorVisible() = 0; + virtual void ApplyChanges() = 0; + virtual bool IsWithin(int x, int y) = 0; + virtual bool HasFocus() = 0; + + // returns true if the surface supports minimize & maximize capabilities + enum SurfaceFeature_e + { + ANTIALIASED_FONTS = 1, + DROPSHADOW_FONTS = 2, + ESCAPE_KEY = 3, + OPENING_NEW_HTML_WINDOWS = 4, + FRAME_MINIMIZE_MAXIMIZE = 5, + OUTLINE_FONTS = 6, + DIRECT_HWND_RENDER = 7, + }; + virtual bool SupportsFeature(SurfaceFeature_e feature) = 0; + + // restricts what gets drawn to one panel and it's children + // currently only works in the game + virtual void RestrictPaintToSinglePanel(VPANEL panel) = 0; + + // these two functions obselete, use IInput::SetAppModalSurface() instead + virtual void SetModalPanel(VPANEL ) = 0; + virtual VPANEL GetModalPanel() = 0; + + virtual void UnlockCursor() = 0; + virtual void LockCursor() = 0; + virtual void SetTranslateExtendedKeys(bool state) = 0; + virtual VPANEL GetTopmostPopup() = 0; + + // engine-only focus handling (replacing WM_FOCUS windows handling) + virtual void SetTopLevelFocus(VPANEL panel) = 0; + + // fonts + // creates an empty handle to a vgui font. windows fonts can be add to this via SetFontGlyphSet(). + virtual HFont CreateFont() = 0; + + // adds to the font + enum EFontFlags + { + FONTFLAG_NONE, + FONTFLAG_ITALIC = 0x001, + FONTFLAG_UNDERLINE = 0x002, + FONTFLAG_STRIKEOUT = 0x004, + FONTFLAG_SYMBOL = 0x008, + FONTFLAG_ANTIALIAS = 0x010, + FONTFLAG_GAUSSIANBLUR = 0x020, + FONTFLAG_ROTARY = 0x040, + FONTFLAG_DROPSHADOW = 0x080, + FONTFLAG_ADDITIVE = 0x100, + FONTFLAG_OUTLINE = 0x200, + FONTFLAG_CUSTOM = 0x400, // custom generated font - never fall back to asian compatibility mode + FONTFLAG_BITMAP = 0x800, // compiled bitmap font - no fallbacks + }; + + virtual bool SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin = 0, int nRangeMax = 0) = 0; + + // adds a custom font file (only supports true type font files (.ttf) for now) + virtual bool AddCustomFontFile(const char *fontName, const char *fontFileName) = 0; + + // returns the details about the font + virtual int GetFontTall(HFont font) = 0; + virtual int GetFontTallRequested(HFont font) = 0; + virtual int GetFontAscent(HFont font, wchar_t wch) = 0; + virtual bool IsFontAdditive(HFont font) = 0; + virtual void GetCharABCwide(HFont font, int ch, int &a, int &b, int &c) = 0; + virtual int GetCharacterWidth(HFont font, int ch) = 0; + virtual void GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall) = 0; + + // notify icons?!? + virtual VPANEL GetNotifyPanel() = 0; + virtual void SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char *text) = 0; + + // plays a sound + virtual void PlaySound(const char *fileName) = 0; + + //!! these functions should not be accessed directly, but only through other vgui items + //!! need to move these to seperate interface + virtual int GetPopupCount() = 0; + virtual VPANEL GetPopup(int index) = 0; + virtual bool ShouldPaintChildPanel(VPANEL childPanel) = 0; + virtual bool RecreateContext(VPANEL panel) = 0; + virtual void AddPanel(VPANEL panel) = 0; + virtual void ReleasePanel(VPANEL panel) = 0; + virtual void MovePopupToFront(VPANEL panel) = 0; + virtual void MovePopupToBack(VPANEL panel) = 0; + + virtual void SolveTraverse(VPANEL panel, bool forceApplySchemeSettings = false) = 0; + virtual void PaintTraverse(VPANEL panel) = 0; + + virtual void EnableMouseCapture(VPANEL panel, bool state) = 0; + + // returns the size of the workspace + virtual void GetWorkspaceBounds(int &x, int &y, int &wide, int &tall) = 0; + + // gets the absolute coordinates of the screen (in windows space) + virtual void GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall) = 0; + + // gets the base resolution used in proportional mode + virtual void GetProportionalBase( int &width, int &height ) = 0; + + virtual void CalculateMouseVisible() = 0; + virtual bool NeedKBInput() = 0; + + virtual bool HasCursorPosFunctions() = 0; + virtual void SurfaceGetCursorPos(int &x, int &y) = 0; + virtual void SurfaceSetCursorPos(int x, int y) = 0; + + // SRC only functions!!! + virtual void DrawTexturedLine( const Vertex_t &a, const Vertex_t &b ) = 0; + virtual void DrawOutlinedCircle(int x, int y, int radius, int segments) = 0; + virtual void DrawTexturedPolyLine( const Vertex_t *p,int n ) = 0; // (Note: this connects the first and last points). + virtual void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ) = 0; + virtual void DrawTexturedPolygon(int n, Vertex_t *pVertice, bool bClipVertices = true ) = 0; + virtual const wchar_t *GetTitle(VPANEL panel) = 0; + virtual bool IsCursorLocked( void ) const = 0; + virtual void SetWorkspaceInsets( int left, int top, int right, int bottom ) = 0; + + // Lower level char drawing code, call DrawGet then pass in info to DrawRender + virtual bool DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info ) = 0; + virtual void DrawRenderCharFromInfo( const CharRenderInfo& info ) = 0; + + // global alpha setting functions + // affect all subsequent draw calls - shouldn't normally be used directly, only in Panel::PaintTraverse() + virtual void DrawSetAlphaMultiplier( float alpha /* [0..1] */ ) = 0; + virtual float DrawGetAlphaMultiplier() = 0; + + // web browser + virtual void SetAllowHTMLJavaScript( bool state ) = 0; + + // video mode changing + virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight ) = 0; + + virtual vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID = 0 ) = 0; + + // create IVguiMatInfo object ( IMaterial wrapper in VguiMatSurface, NULL in CWin32Surface ) + virtual IVguiMatInfo *DrawGetTextureMatInfoFactory( int id ) = 0; + + virtual void PaintTraverseEx(VPANEL panel, bool paintPopups = false ) = 0; + + virtual float GetZPos() const = 0; + + // From the Xbox + virtual void SetPanelForInput( VPANEL vpanel ) = 0; + virtual void DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; + virtual void DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; + virtual void DrawSetTextureRGBAEx(int id, const unsigned char *rgba, int wide, int tall, ImageFormat imageFormat ) = 0; + virtual void DrawSetTextScale(float sx, float sy) = 0; + virtual bool SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags) = 0; + // adds a bitmap font file + virtual bool AddBitmapFontFile(const char *fontFileName) = 0; + // sets a symbol for the bitmap font + virtual void SetBitmapFontName( const char *pName, const char *pFontFilename ) = 0; + // gets the bitmap font filename + virtual const char *GetBitmapFontName( const char *pName ) = 0; + virtual void ClearTemporaryFontCache( void ) = 0; + + virtual IImage *GetIconImageForFullPath( char const *pFullPath ) = 0; + virtual void DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + virtual void PrecacheFontCharacters(HFont font, const wchar_t *pCharacters) = 0; + // Console-only. Get the string to use for the current video mode for layout files. + virtual const char *GetResolutionKey( void ) const = 0; + + virtual const char *GetFontName( HFont font ) = 0; + virtual const char *GetFontFamilyName( HFont font ) = 0; + virtual void GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA ) = 0; + + virtual bool ForceScreenSizeOverride( bool bState, int wide, int tall ) = 0; + // LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position + virtual bool ForceScreenPosOffset( bool bState, int x, int y ) = 0; + virtual void OffsetAbsPos( int &x, int &y ) = 0; + + + // Causes fonts to get reloaded, etc. + virtual void ResetFontCaches() = 0; + + virtual int GetTextureNumFrames( int id ) = 0; + virtual void DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache ) = 0; + virtual bool IsScreenSizeOverrideActive( void ) = 0; + virtual bool IsScreenPosOverrideActive( void ) = 0; + + virtual void DestroyTextureID( int id ) = 0; + + virtual void DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat ) = 0; + virtual bool BHTMLWindowNeedsPaint(IHTML *htmlwin) = 0 ; + + virtual const char *GetWebkitHTMLUserAgentString() = 0; + + virtual void *Deprecated_AccessChromeHTMLController() = 0; + + // the origin of the viewport on the framebuffer (Which might not be 0,0 for stereo) + virtual void SetFullscreenViewport( int x, int y, int w, int h ) = 0; // this uses NULL for the render target. + virtual void GetFullscreenViewport( int & x, int & y, int & w, int & h ) = 0; + virtual void PushFullscreenViewport() = 0; + virtual void PopFullscreenViewport() = 0; + + // handles support for software cursors + virtual void SetSoftwareCursor( bool bUseSoftwareCursor ) = 0; + virtual void PaintSoftwareCursor() = 0; + + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !! WARNING! YOU MUST NOT ADD YOUR NEW METHOD HERE OR YOU WILL BREAK MODS !! + // !! Add your new stuff to the bottom of IMatSystemSurface instead. !! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +}; + +} + +#define VGUI_SURFACE_INTERFACE_VERSION "VGUI_Surface030" + +#endif // ISURFACE_H diff --git a/public/vgui/ISurfaceV30.h b/public/vgui/ISurfaceV30.h new file mode 100644 index 0000000..420fb1a --- /dev/null +++ b/public/vgui/ISurfaceV30.h @@ -0,0 +1,375 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef ISURFACE_V30_H +#define ISURFACE_V30_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include // CreateHTML, PaintHTML +#include "interface.h" +#include "IVguiMatInfo.h" + +#include "appframework/IAppSystem.h" +#include "bitmap/ImageFormat.h" +#include "Vector2D.h" // must be before the namespace line + +#ifdef CreateFont +#undef CreateFont +#endif + +#ifdef PlaySound +#undef PlaySound +#endif + +class Color; + +namespace vgui +{ + + class Image; + class Point; + + // handles + typedef unsigned long HCursor; + typedef unsigned long HTexture; + typedef unsigned long HFont; +} + + + +namespace SurfaceV30 +{ + + //SRC only defines + + + struct Vertex_t + { + Vertex_t() {} + Vertex_t( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) + { + m_Position = pos; + m_TexCoord = coord; + } + void Init( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) + { + m_Position = pos; + m_TexCoord = coord; + } + + Vector2D m_Position; + Vector2D m_TexCoord; + }; + + + enum FontDrawType_t + { + // Use the "additive" value from the scheme file + FONT_DRAW_DEFAULT = 0, + + // Overrides + FONT_DRAW_NONADDITIVE, + FONT_DRAW_ADDITIVE, + + FONT_DRAW_TYPE_COUNT = 2, + }; + + + // Refactor these two + struct CharRenderInfo + { + // In: + FontDrawType_t drawType; + wchar_t ch; + + // Out + bool valid; + + // In/Out (true by default) + bool shouldclip; + // Text pos + int x, y; + // Top left and bottom right + Vertex_t verts[ 2 ]; + int textureId; + int abcA; + int abcB; + int abcC; + int fontTall; + vgui::HFont currentFont; + }; + + + struct IntRect + { + int x0; + int y0; + int x1; + int y1; + }; + + + //----------------------------------------------------------------------------- + // Purpose: Wraps contextless windows system functions + //----------------------------------------------------------------------------- + class ISurface : public IAppSystem + { + public: + // call to Shutdown surface; surface can no longer be used after this is called + virtual void Shutdown() = 0; + + // frame + virtual void RunFrame() = 0; + + // hierarchy root + virtual vgui::VPANEL GetEmbeddedPanel() = 0; + virtual void SetEmbeddedPanel( vgui::VPANEL pPanel ) = 0; + + // drawing context + virtual void PushMakeCurrent(vgui::VPANEL panel, bool useInsets) = 0; + virtual void PopMakeCurrent(vgui::VPANEL panel) = 0; + + // rendering functions + virtual void DrawSetColor(int r, int g, int b, int a) = 0; + virtual void DrawSetColor(Color col) = 0; + + virtual void DrawFilledRect(int x0, int y0, int x1, int y1) = 0; + virtual void DrawFilledRectArray( IntRect *pRects, int numRects ) = 0; + virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1) = 0; + + virtual void DrawLine(int x0, int y0, int x1, int y1) = 0; + virtual void DrawPolyLine(int *px, int *py, int numPoints) = 0; + + virtual void DrawSetTextFont(vgui::HFont font) = 0; + virtual void DrawSetTextColor(int r, int g, int b, int a) = 0; + virtual void DrawSetTextColor(Color col) = 0; + virtual void DrawSetTextPos(int x, int y) = 0; + virtual void DrawGetTextPos(int& x,int& y) = 0; + virtual void DrawPrintText(const wchar_t *text, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + + virtual void DrawFlushText() = 0; // flushes any buffered text (for rendering optimizations) + virtual vgui::IHTML *CreateHTMLWindow(vgui::IHTMLEvents *events,vgui::VPANEL context)=0; + virtual void PaintHTMLWindow(vgui::IHTML *htmlwin) =0; + virtual void DeleteHTMLWindow(vgui::IHTML *htmlwin)=0; + + virtual int DrawGetTextureId( char const *filename ) = 0; + virtual bool DrawGetTextureFile(int id, char *filename, int maxlen ) = 0; + virtual void DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload) = 0; + virtual void DrawSetTextureRGBA(int id, const unsigned char *rgba, int wide, int tall, int hardwareFilter, bool forceReload)=0; + virtual void DrawSetTexture(int id) = 0; + virtual void DrawGetTextureSize(int id, int &wide, int &tall) = 0; + virtual void DrawTexturedRect(int x0, int y0, int x1, int y1) = 0; + virtual bool IsTextureIDValid(int id) = 0; + + virtual int CreateNewTextureID( bool procedural = false ) = 0; +#ifdef _XBOX + virtual void DestroyTextureID( int id ) = 0; + virtual bool IsCachedForRendering( int id, bool bSyncWait ) = 0; + virtual void CopyFrontBufferToBackBuffer() = 0; + virtual void UncacheUnusedMaterials() = 0; +#endif + + virtual void GetScreenSize(int &wide, int &tall) = 0; + virtual void SetAsTopMost(vgui::VPANEL panel, bool state) = 0; + virtual void BringToFront(vgui::VPANEL panel) = 0; + virtual void SetForegroundWindow (vgui::VPANEL panel) = 0; + virtual void SetPanelVisible(vgui::VPANEL panel, bool state) = 0; + virtual void SetMinimized(vgui::VPANEL panel, bool state) = 0; + virtual bool IsMinimized(vgui::VPANEL panel) = 0; + virtual void FlashWindow(vgui::VPANEL panel, bool state) = 0; + virtual void SetTitle(vgui::VPANEL panel, const wchar_t *title) = 0; + virtual void SetAsToolBar(vgui::VPANEL panel, bool state) = 0; // removes the window's task bar entry (for context menu's, etc.) + + // windows stuff + virtual void CreatePopup(vgui::VPANEL panel, bool minimised, bool showTaskbarIcon = true, bool disabled = false, bool mouseInput = true , bool kbInput = true) = 0; + virtual void SwapBuffers(vgui::VPANEL panel) = 0; + virtual void Invalidate(vgui::VPANEL panel) = 0; + virtual void SetCursor(vgui::HCursor cursor) = 0; + virtual bool IsCursorVisible() = 0; + virtual void ApplyChanges() = 0; + virtual bool IsWithin(int x, int y) = 0; + virtual bool HasFocus() = 0; + + // returns true if the surface supports minimize & maximize capabilities + enum SurfaceFeature_e + { + ANTIALIASED_FONTS = 1, + DROPSHADOW_FONTS = 2, + ESCAPE_KEY = 3, + OPENING_NEW_HTML_WINDOWS = 4, + FRAME_MINIMIZE_MAXIMIZE = 5, + OUTLINE_FONTS = 6, + DIRECT_HWND_RENDER = 7, + }; + virtual bool SupportsFeature(SurfaceFeature_e feature) = 0; + + // restricts what gets drawn to one panel and it's children + // currently only works in the game + virtual void RestrictPaintToSinglePanel(vgui::VPANEL panel) = 0; + + // these two functions obselete, use IInput::SetAppModalSurface() instead + virtual void SetModalPanel(vgui::VPANEL ) = 0; + virtual vgui::VPANEL GetModalPanel() = 0; + + virtual void UnlockCursor() = 0; + virtual void LockCursor() = 0; + virtual void SetTranslateExtendedKeys(bool state) = 0; + virtual vgui::VPANEL GetTopmostPopup() = 0; + + // engine-only focus handling (replacing WM_FOCUS windows handling) + virtual void SetTopLevelFocus(vgui::VPANEL panel) = 0; + + // fonts + // creates an empty handle to a vgui font. windows fonts can be add to this via SetFontGlyphSet(). + virtual vgui::HFont CreateFont() = 0; + + // adds to the font + enum EFontFlags + { + FONTFLAG_NONE, + FONTFLAG_ITALIC = 0x001, + FONTFLAG_UNDERLINE = 0x002, + FONTFLAG_STRIKEOUT = 0x004, + FONTFLAG_SYMBOL = 0x008, + FONTFLAG_ANTIALIAS = 0x010, + FONTFLAG_GAUSSIANBLUR = 0x020, + FONTFLAG_ROTARY = 0x040, + FONTFLAG_DROPSHADOW = 0x080, + FONTFLAG_ADDITIVE = 0x100, + FONTFLAG_OUTLINE = 0x200, + FONTFLAG_CUSTOM = 0x400, // custom generated font - never fall back to asian compatibility mode + FONTFLAG_BITMAP = 0x800, // compiled bitmap font - no fallbacks + }; + + virtual bool SetFontGlyphSet(vgui::HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags) = 0; + + // adds a custom font file (only supports true type font files (.ttf) for now) + virtual bool AddCustomFontFile(const char *fontName, const char *fontFileName) = 0; + + // returns the details about the font + virtual int GetFontTall(vgui::HFont font) = 0; + virtual int GetFontAscent(vgui::HFont font, wchar_t wch) = 0; + virtual bool IsFontAdditive(vgui::HFont font) = 0; + virtual void GetCharABCwide(vgui::HFont font, int ch, int &a, int &b, int &c) = 0; + virtual int GetCharacterWidth(vgui::HFont font, int ch) = 0; + virtual void GetTextSize(vgui::HFont font, const wchar_t *text, int &wide, int &tall) = 0; + + // notify icons?!? + virtual vgui::VPANEL GetNotifyPanel() = 0; + virtual void SetNotifyIcon(vgui::VPANEL context, vgui::HTexture icon, vgui::VPANEL panelToReceiveMessages, const char *text) = 0; + + // plays a sound + virtual void PlaySound(const char *fileName) = 0; + + //!! these functions should not be accessed directly, but only through other vgui items + //!! need to move these to seperate interface + virtual int GetPopupCount() = 0; + virtual vgui::VPANEL GetPopup(int index) = 0; + virtual bool ShouldPaintChildPanel(vgui::VPANEL childPanel) = 0; + virtual bool RecreateContext(vgui::VPANEL panel) = 0; + virtual void AddPanel(vgui::VPANEL panel) = 0; + virtual void ReleasePanel(vgui::VPANEL panel) = 0; + virtual void MovePopupToFront(vgui::VPANEL panel) = 0; + virtual void MovePopupToBack(vgui::VPANEL panel) = 0; + + virtual void SolveTraverse(vgui::VPANEL panel, bool forceApplySchemeSettings = false) = 0; + virtual void PaintTraverse(vgui::VPANEL panel) = 0; + + virtual void EnableMouseCapture(vgui::VPANEL panel, bool state) = 0; + + // returns the size of the workspace + virtual void GetWorkspaceBounds(int &x, int &y, int &wide, int &tall) = 0; + + // gets the absolute coordinates of the screen (in windows space) + virtual void GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall) = 0; + + // gets the base resolution used in proportional mode + virtual void GetProportionalBase( int &width, int &height ) = 0; + + virtual void CalculateMouseVisible() = 0; + virtual bool NeedKBInput() = 0; + + virtual bool HasCursorPosFunctions() = 0; + virtual void SurfaceGetCursorPos(int &x, int &y) = 0; + virtual void SurfaceSetCursorPos(int x, int y) = 0; + + + // SRC only functions!!! + virtual void DrawTexturedLine( const Vertex_t &a, const Vertex_t &b ) = 0; + virtual void DrawOutlinedCircle(int x, int y, int radius, int segments) = 0; + virtual void DrawTexturedPolyLine( const Vertex_t *p,int n ) = 0; // (Note: this connects the first and last points). + virtual void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ) = 0; + virtual void DrawTexturedPolygon(int n, Vertex_t *pVertices) = 0; + virtual const wchar_t *GetTitle(vgui::VPANEL panel) = 0; + virtual bool IsCursorLocked( void ) const = 0; + virtual void SetWorkspaceInsets( int left, int top, int right, int bottom ) = 0; + + // Lower level char drawing code, call DrawGet then pass in info to DrawRender + virtual bool DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info ) = 0; + virtual void DrawRenderCharFromInfo( const CharRenderInfo& info ) = 0; + + // global alpha setting functions + // affect all subsequent draw calls - shouldn't normally be used directly, only in Panel::PaintTraverse() + virtual void DrawSetAlphaMultiplier( float alpha /* [0..1] */ ) = 0; + virtual float DrawGetAlphaMultiplier() = 0; + + // web browser + virtual void SetAllowHTMLJavaScript( bool state ) = 0; + + // video mode changing + virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight ) = 0; +#if !defined( _XBOX ) + virtual vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID = 0 ) = 0; +#endif + // create IVguiMatInfo object ( IMaterial wrapper in VguiMatSurface, NULL in CWin32Surface ) + virtual IVguiMatInfo *DrawGetTextureMatInfoFactory( int id ) = 0; + + virtual void PaintTraverseEx(vgui::VPANEL panel, bool paintPopups = false ) = 0; + + virtual float GetZPos() const = 0; + + // From the Xbox + virtual void SetPanelForInput( vgui::VPANEL vpanel ) = 0; + virtual void DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; + virtual void DrawSetTextureRGBAEx(int id, const unsigned char *rgba, int wide, int tall, ImageFormat imageFormat ) = 0; + virtual void DrawSetTextScale(float sx, float sy) = 0; + virtual bool SetBitmapFontGlyphSet(vgui::HFont font, const char *windowsFontName, float scalex, float scaley, int flags) = 0; + // adds a bitmap font file + virtual bool AddBitmapFontFile(const char *fontFileName) = 0; + // sets a symbol for the bitmap font + virtual void SetBitmapFontName( const char *pName, const char *pFontFilename ) = 0; + // gets the bitmap font filename + virtual const char *GetBitmapFontName( const char *pName ) = 0; + + virtual vgui::IImage *GetIconImageForFullPath( char const *pFullPath ) = 0; + virtual void DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + }; + +} // end namespace + +//----------------------------------------------------------------------------- +// FIXME: This works around using scoped interfaces w/ EXPOSE_SINGLE_INTERFACE +//----------------------------------------------------------------------------- +class ISurfaceV30 : public SurfaceV30::ISurface +{ +public: +}; + + +#define VGUI_SURFACE_INTERFACE_VERSION_30 "VGUI_Surface030" + +#endif // ISURFACE_V30_H diff --git a/public/vgui/ISystem.h b/public/vgui/ISystem.h new file mode 100644 index 0000000..1ae15ec --- /dev/null +++ b/public/vgui/ISystem.h @@ -0,0 +1,134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ISYSTEM_H +#define ISYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include +#include + +#ifdef PlaySound +#undef PlaySound +#endif + +class KeyValues; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Wraps contextless windows system functions +//----------------------------------------------------------------------------- +class ISystem : public IBaseInterface +{ +public: + // call when done with ISystem to clean up any memory allocation + virtual void Shutdown() = 0; + + // called every frame + virtual void RunFrame() = 0; + + // use this with the "open" command to launch web browsers/explorer windows, eg. ShellExecute("open", "www.valvesoftware.com") + virtual void ShellExecute(const char *command, const char *file) = 0; + + // returns the time at the start of the frame, in seconds + virtual double GetFrameTime() = 0; + + // returns the current time, in seconds + virtual double GetCurrentTime() = 0; + + // returns the current time, in milliseconds + virtual long GetTimeMillis() = 0; + + // clipboard access + virtual int GetClipboardTextCount() = 0; + virtual void SetClipboardText(const char *text, int textLen) = 0; + virtual void SetClipboardText(const wchar_t *text, int textLen) = 0; + virtual int GetClipboardText(int offset, char *buf, int bufLen) = 0; + virtual int GetClipboardText(int offset, wchar_t *buf, int bufLen) = 0; + + // windows registry + virtual bool SetRegistryString(const char *key, const char *value) = 0; + virtual bool GetRegistryString(const char *key, char *value, int valueLen) = 0; + virtual bool SetRegistryInteger(const char *key, int value) = 0; + virtual bool GetRegistryInteger(const char *key, int &value) = 0; + + // user config + virtual KeyValues *GetUserConfigFileData(const char *dialogName, int dialogID) = 0; + // sets the name of the config file to save/restore from. Settings are loaded immediately. + virtual void SetUserConfigFile(const char *fileName, const char *pathName) = 0; + // saves all the current settings to the user config file + virtual void SaveUserConfigFile() = 0; + + // sets the watch on global computer use + // returns true if supported + virtual bool SetWatchForComputerUse(bool state) = 0; + // returns the time, in seconds, since the last computer use. + virtual double GetTimeSinceLastUse() = 0; + + // Get a string containing the available drives + // If the function succeeds, the return value is the length, in characters, + // of the strings copied to the buffer, + // not including the terminating null character. + virtual int GetAvailableDrives(char *buf, int bufLen) = 0; + + // exe command line options accessors + // returns whether or not the parameter was on the command line + virtual bool CommandLineParamExists(const char *paramName) = 0; + + // returns the full command line, including the exe name + virtual const char *GetFullCommandLine() = 0; + + // Convert a windows virtual key code to a VGUI key code. + virtual KeyCode KeyCode_VirtualKeyToVGUI( int keyCode ) = 0; + + // returns the current local time and date + // fills in every field that a pointer is given to it for + virtual bool GetCurrentTimeAndDate(int *year, int *month, int *dayOfWeek, int *day, int *hour, int *minute, int *second) = 0; + + // returns the amount of available disk space, in bytes, on the drive + // path can be any path, drive letter is stripped out + virtual double GetFreeDiskSpace(const char *path) = 0; + + // shortcut (.lnk) modification functions + virtual bool CreateShortcut(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory, const char *iconFile) = 0; + virtual bool GetShortcutTarget(const char *linkFileName, char *targetPath, char *arguments, int destBufferSizes) = 0; + virtual bool ModifyShortcutTarget(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory) = 0; + + // gets the string following a command line param + //!! move this function up on changing interface version number + virtual bool GetCommandLineParamValue(const char *paramName, char *value, int valueBufferSize) = 0; + + // recursively deletes a registry key and all it's subkeys + //!! move this function next to other registry function on changing interface version number + virtual bool DeleteRegistryKey(const char *keyName) = 0; + + virtual const char *GetDesktopFolderPath() = 0; + + // use this with the "open" command to launch web browsers/explorer windows, eg. ShellExecute("open", "www.valvesoftware.com") + virtual void ShellExecuteEx( const char *command, const char *file, const char *pParams ) = 0; + + // Copy a portion of the application client area to the clipboard + // (x1,y1) specifies the top-left corner of the client rect to copy + // (x2,y2) specifies the bottom-right corner of the client rect to copy + // Requires: x2 > x1 && y2 > y1 + // Dimensions of the copied rectangle are (x2 - x1) x (y2 - y1) + // Pixel at (x1,y1) is copied, pixels at column x2 and row y2 are *not* copied + virtual void SetClipboardImage( void *pWnd, int x1, int y1, int x2, int y2 ) = 0; +}; + +} + +#define VGUI_SYSTEM_INTERFACE_VERSION "VGUI_System010" + + +#endif // ISYSTEM_H diff --git a/public/vgui/IVGui.h b/public/vgui/IVGui.h new file mode 100644 index 0000000..6a4c437 --- /dev/null +++ b/public/vgui/IVGui.h @@ -0,0 +1,112 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef IVGUI_H +#define IVGUI_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include + +#include "appframework/IAppSystem.h" + +class KeyValues; + +namespace vgui +{ + +// safe handle to a panel - can be converted to and from a VPANEL +typedef unsigned long HPanel; +typedef int HContext; + +enum +{ + DEFAULT_VGUI_CONTEXT = ((vgui::HContext)~0) +}; + +// safe handle to a panel - can be converted to and from a VPANEL +typedef unsigned long HPanel; + +//----------------------------------------------------------------------------- +// Purpose: Interface to core vgui components +//----------------------------------------------------------------------------- +class IVGui : public IAppSystem +{ +public: + // activates vgui message pump + virtual void Start() = 0; + + // signals vgui to Stop running + virtual void Stop() = 0; + + // returns true if vgui is current active + virtual bool IsRunning() = 0; + + // runs a single frame of vgui + virtual void RunFrame() = 0; + + // broadcasts "ShutdownRequest" "id" message to all top-level panels in the app + virtual void ShutdownMessage(unsigned int shutdownID) = 0; + + // panel allocation + virtual VPANEL AllocPanel() = 0; + virtual void FreePanel(VPANEL panel) = 0; + + // debugging prints + virtual void DPrintf(PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void DPrintf2(PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void SpewAllActivePanelNames() = 0; + + // safe-pointer handle methods + virtual HPanel PanelToHandle(VPANEL panel) = 0; + virtual VPANEL HandleToPanel(HPanel index) = 0; + virtual void MarkPanelForDeletion(VPANEL panel) = 0; + + // makes panel receive a 'Tick' message every frame (~50ms, depending on sleep times/framerate) + // panel is automatically removed from tick signal list when it's deleted + virtual void AddTickSignal(VPANEL panel, int intervalMilliseconds = 0 ) = 0; + virtual void RemoveTickSignal(VPANEL panel) = 0; + + // message sending + virtual void PostMessage(VPANEL target, KeyValues *params, VPANEL from, float delaySeconds = 0.0f) = 0; + + // Creates/ destroys vgui contexts, which contains information + // about which controls have mouse + key focus, for example. + virtual HContext CreateContext() = 0; + virtual void DestroyContext( HContext context ) = 0; + + // Associates a particular panel with a vgui context + // Associating NULL is valid; it disconnects the panel from the context + virtual void AssociatePanelWithContext( HContext context, VPANEL pRoot ) = 0; + + // Activates a particular context, use DEFAULT_VGUI_CONTEXT + // to get the one normally used by VGUI + virtual void ActivateContext( HContext context ) = 0; + + // whether to sleep each frame or not, true = sleep + virtual void SetSleep( bool state) = 0; + + // data accessor for above + virtual bool GetShouldVGuiControlSleep() = 0; + + // enables VR mode + virtual void SetVRMode( bool bVRMode ) = 0; + virtual bool GetVRMode() = 0; + + // add a tick signal like above, but to the head of the list of tick signals + virtual void AddTickSignalToHead( VPANEL panel, int intervalMilliseconds = 0 ) = 0; +}; + +#define VGUI_IVGUI_INTERFACE_VERSION "VGUI_ivgui008" + +}; + + +#endif // IVGUI_H diff --git a/public/vgui/IVguiMatInfo.h b/public/vgui/IVguiMatInfo.h new file mode 100644 index 0000000..2bfbe2d --- /dev/null +++ b/public/vgui/IVguiMatInfo.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVGUIMATINFO_H +#define IVGUIMATINFO_H + +#include "IVguiMatInfoVar.h" + +// wrapper for IMaterial +class IVguiMatInfo +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IVguiMatInfo() {} + + // make sure to delete the returned object after use! + virtual IVguiMatInfoVar* FindVarFactory ( const char *varName, bool *found ) = 0; + + virtual int GetNumAnimationFrames ( ) = 0; + + // todo: if you need to add more IMaterial functions add them here +}; + +#endif //IVGUIMATINFO_H diff --git a/public/vgui/IVguiMatInfoVar.h b/public/vgui/IVguiMatInfoVar.h new file mode 100644 index 0000000..319d39d --- /dev/null +++ b/public/vgui/IVguiMatInfoVar.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IVGUIMATINFOVAR_H +#define IVGUIMATINFOVAR_H + + +// wrapper for IMaterialVar +class IVguiMatInfoVar +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IVguiMatInfoVar() {} + + virtual int GetIntValue ( void ) const = 0; + virtual void SetIntValue ( int val ) = 0; + + // todo: if you need to add more IMaterialVar functions add them here +}; + +#endif //IVGUIMATINFOVAR_H diff --git a/public/vgui/KeyCode.h b/public/vgui/KeyCode.h new file mode 100644 index 0000000..0e58a5c --- /dev/null +++ b/public/vgui/KeyCode.h @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: this is a map for virtual key codes +// virtual key codes may exist outside this range for other languages +// NOTE: Button codes also contain mouse codes, but we won't worry about that +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef KEYCODE_H +#define KEYCODE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "inputsystem/ButtonCode.h" + +namespace vgui +{ +typedef ButtonCode_t KeyCode; +} + +#endif // KEYCODE_H diff --git a/public/vgui/MouseCode.h b/public/vgui/MouseCode.h new file mode 100644 index 0000000..7ba1621 --- /dev/null +++ b/public/vgui/MouseCode.h @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: names mouse button inputs +// NOTE: Button codes also contain key codes, but we won't worry about that +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MOUSECODE_H +#define MOUSECODE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "inputsystem/ButtonCode.h" + +namespace vgui +{ +typedef ButtonCode_t MouseCode; +} + +#endif // MOUSECODE_H diff --git a/public/vgui/Point.h b/public/vgui/Point.h new file mode 100644 index 0000000..96cd64d --- /dev/null +++ b/public/vgui/Point.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef POINT_H +#define POINT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Basic handler for a Points in 2 dimensions +// This class is fully inline +//----------------------------------------------------------------------------- +class Point +{ +public: + // constructors + Point() + { + SetPoint(0, 0); + } + Point(int x,int y) + { + SetPoint(x,y); + } + + void SetPoint(int x1, int y1) + { + x=x1; + y=y1; + } + + void GetPoint(int &x1, int &y1) const + { + x1 = x; + y1 = y; + + } + + bool operator == (Point &rhs) const + { + return (x == rhs.x && y == rhs.y); + } + +private: + int x, y; +}; + +} // namespace vgui + +#endif // POINT_H diff --git a/public/vgui/VGUI.h b/public/vgui/VGUI.h new file mode 100644 index 0000000..34fddfe --- /dev/null +++ b/public/vgui/VGUI.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Basic header for using vgui +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_H +#define VGUI_H + +#ifdef _WIN32 +#pragma once +#endif + +#define null 0L + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#pragma warning( disable: 4800 ) // disables 'performance warning converting int to bool' +#pragma warning( disable: 4786 ) // disables 'identifier truncated in browser information' warning +#pragma warning( disable: 4355 ) // disables 'this' : used in base member initializer list +#pragma warning( disable: 4097 ) // warning C4097: typedef-name 'BaseClass' used as synonym for class-name +#pragma warning( disable: 4514 ) // warning C4514: 'Color::Color' : unreferenced inline function has been removed +#pragma warning( disable: 4100 ) // warning C4100: 'code' : unreferenced formal parameter +#pragma warning( disable: 4127 ) // warning C4127: conditional expression is constant + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifndef _WCHAR_T_DEFINED +// DAL - wchar_t is a built in define in gcc 3.2 with a size of 4 bytes +#if !defined( __x86_64__ ) && !defined( __WCHAR_TYPE__ ) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif +#endif + +// do this in GOLDSRC only!!! +//#define Assert assert + +namespace vgui +{ +// handle to an internal vgui panel +// this is the only handle to a panel that is valid across dll boundaries +typedef unsigned int VPANEL; + +// handles to vgui objects +// NULL values signify an invalid value +typedef unsigned long HScheme; +// Both -1 and 0 are used for invalid textures. Be careful. +typedef unsigned long HTexture; +typedef unsigned long HCursor; +typedef unsigned long HPanel; +const HPanel INVALID_PANEL = 0xffffffff; +typedef unsigned long HFont; +const HFont INVALID_FONT = 0; // the value of an invalid font handle +} + +#include "tier1/strtools.h" + +#if 0 // defined( OSX ) // || defined( LINUX ) +// Disabled all platforms. Did a major cleanup of osxfont.cpp, and having this +// turned off renders much closer to Windows and Linux and also uses the same +// code paths (which is good). +#define USE_GETKERNEDCHARWIDTH 1 +#else +#define USE_GETKERNEDCHARWIDTH 0 +#endif + + +#endif // VGUI_H diff --git a/public/vgui/ipainthtml.h b/public/vgui/ipainthtml.h new file mode 100644 index 0000000..f30892e --- /dev/null +++ b/public/vgui/ipainthtml.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef IPAINTHTML_H +#define IPAINTHTML_H + +class IPaintHTML +{ +public: + enum EPaintTarget + { + ePaintBrowser, + ePaintPopup, + ePaintMAX + }; + // returns the texture id used, pass in -1 to create a new texture + virtual int DrawSubTextureRGBA( EPaintTarget eTarget, int textureID, int x, int y, const unsigned char *pRGBA, int wide, int tall ) = 0; + virtual void DeleteTexture( EPaintTarget eTarget, int textureID ) = 0; +}; + +class IInputEventHTML +{ +public: + enum EMouseButton + { + eButtonLeft, + eButtonMiddle, + eButtonRight + }; + + virtual bool ChromeHandleMouseClick( EMouseButton eButton, bool bUp, int nClickCount ) = 0; + virtual bool ChromeHandleMouseMove( int x, int y ) = 0; + virtual bool ChromeHandleMouseWheel( int delta ) = 0; + + enum EKeyType + { + KeyDown, + KeyUp, + Char + }; + enum EKeyModifier + { + AltDown = 1, + CrtlDown = 2, + ShiftDown = 4, + }; + + virtual bool ChromeHandleKeyEvent( EKeyType type, int key, int modifiers, bool bKeyUp ) = 0; +}; + +#endif // IPAINTHTML_H \ No newline at end of file diff --git a/public/vgui/keyrepeat.h b/public/vgui/keyrepeat.h new file mode 100644 index 0000000..874cc03 --- /dev/null +++ b/public/vgui/keyrepeat.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef KEYREPEAT_H +#define KEYREPEAT_H +#ifdef _WIN32 +#pragma once +#endif + +namespace vgui +{ + +enum KEYREPEAT_ALIASES +{ + KR_ALIAS_UP, + KR_ALIAS_DOWN, + KR_ALIAS_LEFT, + KR_ALIAS_RIGHT, + + FM_NUM_KEYREPEAT_ALIASES, +}; + +class CKeyRepeatHandler +{ +public: + CKeyRepeatHandler(); + + void Reset(); + void KeyDown( vgui::KeyCode code ); + void KeyUp( vgui::KeyCode code ); + vgui::KeyCode KeyRepeated(); + void SetKeyRepeatTime( vgui::KeyCode code, float flRepeat ); + +private: + bool m_bAliasDown[MAX_JOYSTICKS][FM_NUM_KEYREPEAT_ALIASES]; + float m_flRepeatTimes[FM_NUM_KEYREPEAT_ALIASES]; + float m_flNextKeyRepeat[MAX_JOYSTICKS]; + bool m_bHaveKeyDown; +}; + + +} // namespace vgui + +#endif // KEYREPEAT_H diff --git a/public/vgui_controls/AnalogBar.h b/public/vgui_controls/AnalogBar.h new file mode 100644 index 0000000..d6d696e --- /dev/null +++ b/public/vgui_controls/AnalogBar.h @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ANALOGBAR_H +#define ANALOGBAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Status bar that visually displays discrete analogValue in the form +// of a segmented strip +//----------------------------------------------------------------------------- +class AnalogBar : public Panel +{ + DECLARE_CLASS_SIMPLE( AnalogBar, Panel ); + +public: + AnalogBar(Panel *parent, const char *panelName); + ~AnalogBar(); + + // 'analogValue' is in the range [0.0f, 1.0f] + MESSAGE_FUNC_FLOAT( SetAnalogValue, "SetAnalogValue", analogValue ); + float GetAnalogValue(); + virtual void SetSegmentInfo( int gap, int width ); + + // utility function for calculating a time remaining string + static bool ConstructTimeRemainingString(OUT_Z_BYTECAP(outputBufferSizeInBytes) wchar_t *output, int outputBufferSizeInBytes, float startTime, float currentTime, float currentAnalogValue, float lastAnalogValueUpdateTime, bool addRemainingSuffix); + + void SetBarInset( int pixels ); + int GetBarInset( void ); + + virtual void ApplySettings(KeyValues *inResourceData); + virtual void GetSettings(KeyValues *outResourceData); + virtual const char *GetDescription(); + + // returns the number of segment blocks drawn + int GetDrawnSegmentCount(); + int GetTotalSegmentCount(); + + enum AnalogValueDir_e + { + PROGRESS_EAST, + PROGRESS_WEST, + PROGRESS_NORTH, + PROGRESS_SOUTH + }; + + int GetAnalogValueDirection() const { return m_iAnalogValueDirection; } + void SetAnalogValueDirection( int val ) { m_iAnalogValueDirection = val; } + + void SetHomeValue( float val ) { m_fHomeValue = val; } + + const Color& GetHomeColor( void ) { return m_HomeColor; } + void SetHomeColor( const Color &color ) { m_HomeColor = color; } + +protected: + virtual void Paint(); + void PaintSegment( int &x, int &y, int tall, int wide, Color color, bool bHome ); + virtual void PaintBackground(); + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_PARAMS( OnDialogVariablesChanged, "DialogVariables", dialogVariables ); + /* CUSTOM MESSAGE HANDLING + "SetAnalogValue" + input: "analogValue" - float value of the analogValue to set + */ + +protected: + int m_iAnalogValueDirection; + float _analogValue; + +private: + int _segmentCount; + int _segmentGap; + int _segmentWide; + int m_iBarInset; + char *m_pszDialogVar; + + float m_fHomeValue; + Color m_HomeColor; +}; + +//----------------------------------------------------------------------------- +// Purpose: Non-segmented analogValue bar +//----------------------------------------------------------------------------- +class ContinuousAnalogBar : public AnalogBar +{ + DECLARE_CLASS_SIMPLE( ContinuousAnalogBar, AnalogBar ); + +public: + ContinuousAnalogBar(Panel *parent, const char *panelName); + + virtual void Paint(); +}; + +} // namespace vgui + +#endif // ANALOGBAR_H diff --git a/public/vgui_controls/AnimatingImagePanel.h b/public/vgui_controls/AnimatingImagePanel.h new file mode 100644 index 0000000..a65a5dc --- /dev/null +++ b/public/vgui_controls/AnimatingImagePanel.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ANIMATINGIMAGEPANEL_H +#define ANIMATINGIMAGEPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Animating image +//----------------------------------------------------------------------------- +class AnimatingImagePanel : public Panel +{ + DECLARE_CLASS_SIMPLE( AnimatingImagePanel, Panel ); + +public: + AnimatingImagePanel(Panel *parent, const char *name); + + // Add an image to the end of the list of animations + // image - pointer to the image to add to the end of the list + virtual void AddImage(IImage *image); + + // Load a set of animations by name. + // baseName - The name of the animations without their frame number or file extension, (e.g. c1.tga becomes just c.) + // framecount: number of frames in the animation + virtual void LoadAnimation(const char *baseName, int frameCount); + + virtual void StartAnimation(); + virtual void StopAnimation(); + virtual void ResetAnimation(int frame = 0); + +protected: + virtual void OnTick(); + virtual void PerformLayout(); + virtual void PaintBackground(); + + virtual void GetSettings(KeyValues *outResourceData); + virtual void ApplySettings(KeyValues *inResourceData); + virtual const char *GetDescription(); + +private: + int m_iCurrentImage; + int m_iNextFrameTime; + int m_iFrameTimeMillis; + CUtlVector m_Frames; + char *m_pImageName; + bool m_bAnimating; + bool m_bFiltered; + bool m_bScaleImage; +}; + +}; // namespace vgui + +#endif // ANIMATINGIMAGEPANEL_H diff --git a/public/vgui_controls/AnimationController.h b/public/vgui_controls/AnimationController.h new file mode 100644 index 0000000..93ae709 --- /dev/null +++ b/public/vgui_controls/AnimationController.h @@ -0,0 +1,277 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ANIMATIONCONTROLLER_H +#define ANIMATIONCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +#include "tier1/utlsymbol.h" +#include "tier1/utlvector.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Handles controlling panel animation +// It is never visible, but needs to be a panel so that can receive messages +//----------------------------------------------------------------------------- +class AnimationController : public Panel +{ + DECLARE_CLASS_SIMPLE( AnimationController, Panel ); + +public: + AnimationController(Panel *parent); + ~AnimationController(); + + // sets which script file to use + bool SetScriptFile( VPANEL sizingPanel, const char *fileName, bool wipeAll = false ); + + // reloads the currently set script file + void ReloadScriptFile(); + + // runs a frame of animation (time is passed in so slow motion, etc. works) + void UpdateAnimations( float curtime ); + + int GetNumActiveAnimations( void ) { return m_ActiveAnimations.Count(); } + + // plays all animations to completion instantly + void RunAllAnimationsToCompletion(); + + // stops all animations + void CancelAllAnimations(); + + // starts an animation sequence script + bool StartAnimationSequence(const char *sequenceName); + bool StartAnimationSequence(Panel *pWithinParent, const char *sequenceName); + + bool StopAnimationSequence( Panel *pWithinParent, const char *sequenceName ); + void CancelAnimationsForPanel( Panel *pWithinParent ); + + // gets the length of an animation sequence, in seconds + float GetAnimationSequenceLength(const char *sequenceName); + + // sets that the script file should be reloaded each time a script is ran + // used for development + void SetAutoReloadScript(bool state); + + enum Interpolators_e + { + INTERPOLATOR_LINEAR, + INTERPOLATOR_ACCEL, + INTERPOLATOR_DEACCEL, + INTERPOLATOR_PULSE, + INTERPOLATOR_FLICKER, + INTERPOLATOR_SIMPLESPLINE, // ease in / out + INTERPOLATOR_BOUNCE, // gravitational bounce + }; + + // runs the specific animation command (doesn't use script file at all) + void RunAnimationCommand(vgui::Panel *panel, const char *variable, float targetValue, float startDelaySeconds, float durationSeconds, Interpolators_e interpolator, float animParameter = 0 ); + void RunAnimationCommand(vgui::Panel *panel, const char *variable, Color targetValue, float startDelaySeconds, float durationSeconds, Interpolators_e interpolator, float animParameter = 0 ); + +private: + bool UpdateScreenSize(); + + bool LoadScriptFile(const char *fileName); + bool ParseScriptFile(char *pMem, int length); + + void UpdatePostedMessages(bool bRunToCompletion); + void UpdateActiveAnimations(bool bRunToCompletion); + + bool m_bAutoReloadScript; + float m_flCurrentTime; + + enum AnimCommandType_e + { + CMD_ANIMATE, + CMD_RUNEVENT, + CMD_STOPEVENT, + CMD_STOPANIMATION, + CMD_STOPPANELANIMATIONS, + CMD_SETFONT, + CMD_SETTEXTURE, + CMD_SETSTRING, + CMD_RUNEVENTCHILD, + CMD_FIRECOMMAND, + CMD_SETVISIBLE, + }; + + enum RelativeAlignment + { + a_northwest = 0, + a_north, + a_northeast, + a_west, + a_center, + a_east, + a_southwest, + a_south, + a_southeast, + }; + + struct RelativeAlignmentLookup + { + RelativeAlignment align; + char const *name; + }; + + // a single animatable value + // some var types use 1, 2, 3 or all 4 of the values + struct Value_t + { + float a, b, c, d; + }; + + struct AnimAlign_t + { + // For Position, Xpos, YPos + bool relativePosition; + UtlSymId_t alignPanel; + RelativeAlignment alignment; + }; + + // info for the animate command + struct AnimCmdAnimate_t + { + UtlSymId_t panel; + UtlSymId_t variable; + Value_t target; + int interpolationFunction; + float interpolationParameter; + float startTime; + float duration; + + AnimAlign_t align; + + }; + + // info for the run event command + struct AnimCmdEvent_t + { + UtlSymId_t event; + UtlSymId_t variable; + UtlSymId_t variable2; + float timeDelay; + }; + + // holds a single command from an animation sequence + struct AnimCommand_t + { + AnimCommandType_e commandType; + union + { + AnimCmdAnimate_t animate; + AnimCmdEvent_t runEvent; + } cmdData; + }; + + // holds a full sequence + struct AnimSequence_t + { + UtlSymId_t name; + float duration; + CUtlVector cmdList; + }; + + // holds the list of sequences + CUtlVector m_Sequences; + + // list of active animations + struct ActiveAnimation_t + { + PHandle panel; + UtlSymId_t seqName; // the sequence this belongs to + UtlSymId_t variable; + bool started; + Value_t startValue; + Value_t endValue; + int interpolator; + float interpolatorParam; + float startTime; + float endTime; + + AnimAlign_t align; + }; + CUtlVector m_ActiveAnimations; + + // posted messages + struct PostedMessage_t + { + AnimCommandType_e commandType; + UtlSymId_t seqName; + UtlSymId_t event; + UtlSymId_t variable; + UtlSymId_t variable2; + float startTime; + PHandle parent; + }; + CUtlVector m_PostedMessages; + + struct RanEvent_t + { + UtlSymId_t event; + Panel *pParent; + + bool operator==( const RanEvent_t &other ) const + { + return ( event == other.event && pParent == other.pParent ); + } + }; + + // variable names + UtlSymId_t m_sPosition, m_sSize, m_sFgColor, m_sBgColor; + UtlSymId_t m_sXPos, m_sYPos, m_sWide, m_sTall; + UtlSymId_t m_sModelPos; + + // file name + CUtlVector m_ScriptFileNames; + + // runs a single line of the script + void ExecAnimationCommand(UtlSymId_t seqName, AnimCommand_t &animCommand, Panel *pWithinParent); + // removes all commands belonging to a script + void RemoveQueuedAnimationCommands(UtlSymId_t seqName, vgui::Panel *panel = NULL); + // removes an existing instance of a command + void RemoveQueuedAnimationByType(vgui::Panel *panel, UtlSymId_t variable, UtlSymId_t sequenceToIgnore); + + // handlers + void StartCmd_Animate(UtlSymId_t seqName, AnimCmdAnimate_t &cmd, Panel *pWithinParent); + void StartCmd_Animate(Panel *panel, UtlSymId_t seqName, AnimCmdAnimate_t &cmd); + void RunCmd_RunEvent(PostedMessage_t &msg); + void RunCmd_StopEvent(PostedMessage_t &msg); + void RunCmd_StopPanelAnimations(PostedMessage_t &msg); + void RunCmd_StopAnimation(PostedMessage_t &msg); + void RunCmd_SetFont(PostedMessage_t &msg); + void RunCmd_SetTexture(PostedMessage_t &msg); + void RunCmd_SetString(PostedMessage_t &msg); + + // value access + Value_t GetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var); + void SetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var, Value_t &value); + + // interpolation + Value_t GetInterpolatedValue(int interpolator, float interpolatorParam, float currentTime, float startTime, float endTime, Value_t &startValue, Value_t &endValue); + + void SetupPosition( AnimCmdAnimate_t& cmd, float *output, char const *psz, int screendimension ); + static RelativeAlignment LookupAlignment( char const *token ); + static RelativeAlignmentLookup g_AlignmentLookup[]; + + int GetRelativeOffset( AnimAlign_t& cmd, bool xcoord ); + + VPANEL m_hSizePanel; + int m_nScreenBounds[ 4 ]; +}; + +// singleton accessor for use only by other vgui_controls +extern AnimationController *GetAnimationController(); + +} // namespace vgui + +#endif // ANIMATIONCONTROLLER_H diff --git a/public/vgui_controls/BitmapImagePanel.h b/public/vgui_controls/BitmapImagePanel.h new file mode 100644 index 0000000..639ffb6 --- /dev/null +++ b/public/vgui_controls/BitmapImagePanel.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BITMAPIMAGEPANEL_H +#define BITMAPIMAGEPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui { + +class CBitmapImagePanel : public vgui::Panel +{ +public: + CBitmapImagePanel( vgui::Panel *parent, char const *panelName, char const *filename = NULL ); + ~CBitmapImagePanel(); + + virtual void PaintBackground(); + + virtual void setTexture( char const *filename, bool hardwareFiltered = true ); + + void setImageColor( Color color ) { m_bgColor = color; } + + // Set how the image aligns itself within the panel + virtual void SetContentAlignment(Label::Alignment alignment); + +protected: + virtual void GetSettings(KeyValues *outResourceData); + virtual void ApplySettings(KeyValues *inResourceData); + virtual const char *GetDescription(); + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PaintBorder(); + +private: + typedef vgui::Panel BaseClass; + + virtual void ComputeImagePosition(int &x, int &y, int &w, int &h); + Label::Alignment m_contentAlignment; + + bool m_preserveAspectRatio; + bool m_hardwareFiltered; + + IImage *m_pImage; + Color m_bgColor; + char *m_pszImageName; + char *m_pszColorName; +}; + +}; + +#endif // BITMAPIMAGEPANEL_H diff --git a/public/vgui_controls/BuildGroup.h b/public/vgui_controls/BuildGroup.h new file mode 100644 index 0000000..e95bca6 --- /dev/null +++ b/public/vgui_controls/BuildGroup.h @@ -0,0 +1,184 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_BUILDGROUP_H +#define VGUI_BUILDGROUP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include "tier1/utlsymbol.h" +#include +#include +#include +#include +#include +#include +#include "tier1/utlhandletable.h" + +class KeyValues; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: a BuildGroup is a list of panels contained in a window (the contextPanel) +// Members of this group are viewable and editable in Build Mode, via the BuildModeDialog wizard +//----------------------------------------------------------------------------- +class BuildGroup +{ + DECLARE_HANDLES( BuildGroup, 20 ); + +public: + BuildGroup(Panel *parentPanel, Panel *contextPanel); + ~BuildGroup(); + + // Toggle build mode on/off + virtual void SetEnabled(bool state); + + // Check if buildgroup is enabled + virtual bool IsEnabled(); + + // Return the currently selected panel + virtual Panel *GetCurrentPanel(); + + // Load the control settings from file + virtual void LoadControlSettings(const char *controlResourceName, const char *pathID = NULL, KeyValues *pPreloadedKeyValues = NULL, KeyValues *pConditions = NULL); + + // Reload the control settings from file + void ReloadControlSettings(); + + // changes which control settings are currently loaded + void ChangeControlSettingsFile(const char *controlResourceName); + + // Save control settings from file, using the same resource + // name as what LoadControlSettings() was called with + virtual bool SaveControlSettings(); + + // Serialize settings from a resource data container + virtual void ApplySettings(KeyValues *resourceData); + + // Serialize settings to a resource data container + virtual void GetSettings(KeyValues *resourceData); + + // Remove all objects in the current control group + virtual void RemoveSettings(); + + // Get a new unique fieldname for a new control + void GetNewFieldName(char *newFieldName, int newFieldNameSize, Panel *newPanel); + + // Check if a control name is already taken + Panel *FieldNameTaken(const char *fieldName); + + // Add a new control (via the BuildModeDialog) + Panel *NewControl( KeyValues *controlKeys, int x=0, int y=0); + Panel *NewControl( const char *name, int x=0, int y=0); + + // Set the panel from which the build group gets all it's object creation information + virtual void SetContextPanel(Panel *contextPanel); + + //Get the panel that build group is pointed at. + virtual Panel *GetContextPanel(); + + // Get the list of panels in the buildgroup + CUtlVector *GetPanelList(); + + // Get the resource file name used + virtual const char *GetResourceName(void) { return m_pResourceName; } + + virtual void PanelAdded(Panel* panel); + + virtual bool MousePressed(MouseCode code,Panel* panel); + virtual bool MouseReleased(MouseCode code,Panel* panel); + + // Get the list of panels that are currently selected + virtual CUtlVector *GetControlGroup(); + + // Toggle ruler display on/off + virtual void ToggleRulerDisplay(); + + // Toggle visibility of ruler number labels + virtual void SetRulerLabelsVisible(bool state); + + // Check if ruler display is activated + virtual bool HasRulersOn(); + + // Draw Rulers on screen + virtual void DrawRulers(); + + // registers that a control settings file may be loaded + // use when the dialog may have multiple states and the editor will need to be able to switch between them + void RegisterControlSettingsFile(const char *controlResourceName, const char *pathID = NULL); + + // iterator for registered files + int GetRegisteredControlSettingsFileCount(); + const char *GetRegisteredControlSettingsFileByIndex(int index); + + // dialog variables + KeyValues *GetDialogVariables(); + + // conditional keys for selectively reading keyvalues + void ProcessConditionalKeys( KeyValues *pDat, KeyValues *pConditions ); + +protected: + virtual bool CursorMoved(int x, int y, Panel *panel); + virtual bool MouseDoublePressed(MouseCode code, Panel *panel); + virtual bool KeyCodeTyped(KeyCode code, Panel *panel); + virtual bool KeyCodeReleased(KeyCode code, Panel *panel ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual bool KeyTyped( wchar_t unichar, Panel *panel ); + + virtual HCursor GetCursor(Panel *panel); + +private: + void ApplySnap(Panel* panel); + Panel *CreateBuildDialog(); + void ActivateBuildDialog(); + void DeleteAllControlsCreatedByControlSettingsFile(); + + bool _enabled; + int _snapX; + int _snapY; + HCursor _cursor_sizenwse; + HCursor _cursor_sizenesw; + HCursor _cursor_sizewe; + HCursor _cursor_sizens; + HCursor _cursor_sizeall; + bool _dragging; + MouseCode _dragMouseCode; + int _dragStartPanelPos[2]; + int _dragStartCursorPos[2]; + int _dragStartPanelSize[ 2 ]; + Panel * _currentPanel; + CUtlVector _panelDar; + char *m_pResourceName; + char *m_pResourcePathID; + PHandle m_hBuildDialog; + Panel *m_pBuildContext; // the panel from which the build dialog gets all the information it needs + Panel *m_pParentPanel; // panel to create new controls in + CUtlVector _controlGroup; // grouped panels + CUtlVector _groupDeltaX; // x offsets of panels in group from the selected panel + CUtlVector _groupDeltaY; // y offsets of panels in group from the selected panel + Label *_rulerNumber[4]; // 4 numbers to label rulers with + bool _showRulers; // toggles ruler display + CUtlVector m_RegisteredControlSettingsFiles; + + friend class Panel; +}; + + +//----------------------------------------------------------------------------- +// Handle to a build group +//----------------------------------------------------------------------------- +typedef CUtlHandle HBuildGroup; + + +} // namespace vgui + +#endif // VGUI_BUILDGROUP_H diff --git a/public/vgui_controls/BuildModeDialog.h b/public/vgui_controls/BuildModeDialog.h new file mode 100644 index 0000000..25c6185 --- /dev/null +++ b/public/vgui_controls/BuildModeDialog.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BUILDMODEDIALOG_H +#define BUILDMODEDIALOG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +struct PanelItem_t; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Dialog for use in build mode editing +//----------------------------------------------------------------------------- +class BuildModeDialog : public Frame +{ + DECLARE_CLASS_SIMPLE( BuildModeDialog, Frame ); + +public: + BuildModeDialog( BuildGroup *buildGroup ); + ~BuildModeDialog(); + + // Set the current control to edit + MESSAGE_FUNC_PTR( SetActiveControl, "SetActiveControl", panelPtr ); + + // Update the current control with the current resource settings. + MESSAGE_FUNC_PTR( UpdateControlData, "UpdateControlData", panel ); + + // Store the current settings of all panels in the build group. + virtual KeyValues *StoreSettings(); + + // Store the current settings of the current panel + MESSAGE_FUNC( StoreUndoSettings, "StoreUndo" ); + + /* CUSTOM MESSAGE HANDLING + "SetActiveControl" + input: "PanelPtr" - panel to set active control to edit to + */ + + MESSAGE_FUNC( OnShowNewControlMenu, "ShowNewControlMenu" ); + +protected: + virtual void PerformLayout(); + virtual void OnClose(); + virtual void OnCommand( const char *command ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual bool IsBuildGroupEnabled(); + +private: + void CreateControls(); + + void OnKeyCodeTyped(KeyCode code); + MESSAGE_FUNC( ApplyDataToControls, "ApplyDataToControls" ); + MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel ); + MESSAGE_FUNC( OnDeletePanel, "DeletePanel" ); + void ExitBuildMode(); + Panel *OnNewControl(const char *name, int x = 0, int y = 0); + MESSAGE_FUNC( DoUndo, "Undo" ); + MESSAGE_FUNC( DoCopy, "Copy" ); + MESSAGE_FUNC( DoPaste, "Paste" ); + MESSAGE_FUNC( EnableSaveButton, "EnableSaveButton" ); + void RevertToSaved(); + void ShowHelp(); + MESSAGE_FUNC( ShutdownBuildMode, "Close" ); + MESSAGE_FUNC( OnPanelMoved, "PanelMoved" ); + MESSAGE_FUNC( OnTextKillFocus, "TextKillFocus" ); + MESSAGE_FUNC( OnReloadLocalization, "ReloadLocalization" ); + MESSAGE_FUNC_CHARPTR( OnCreateNewControl, "CreateNewControl", text ); + + MESSAGE_FUNC_CHARPTR( OnSetClipboardText, "SetClipboardText", text ); + + MESSAGE_FUNC_INT( OnChangeChild, "OnChangeChild", direction ); + + Panel *m_pCurrentPanel; + BuildGroup *m_pBuildGroup; + Label *m_pStatusLabel; + ComboBox *m_pFileSelectionCombo; + Divider *m_pDivider; + + class PanelList; + PanelList *m_pPanelList; + + Button *m_pSaveButton; + Button *m_pApplyButton; + Button *m_pExitButton; + Button *m_pDeleteButton; + Button *m_pReloadLocalization; + MenuButton *m_pVarsButton; + + bool _autoUpdate; + + ComboBox *m_pAddNewControlCombo; // combo box for adding new controls + KeyValues *_undoSettings; // settings for the Undo command + KeyValues *_copySettings; // settings for the Copy/Paste command + char _copyClassName[255]; + int m_nClick[ 2 ]; + + void RemoveAllControls( void ); + void UpdateEditControl(PanelItem_t &panelItem, const char *datstring); + + enum { + TYPE_STRING, + TYPE_INTEGER, + TYPE_COLOR, + TYPE_ALIGNMENT, + TYPE_AUTORESIZE, + TYPE_CORNER, + TYPE_LOCALIZEDSTRING, + }; + + vgui::DHANDLE< Menu > m_hContextMenu; + + ComboBox *m_pEditableParents; + ComboBox *m_pEditableChildren; + + Button *m_pNextChild; + Button *m_pPrevChild; + + friend class PanelList; +}; + +} // namespace vgui + + +#endif // BUILDMODEDIALOG_H + diff --git a/public/vgui_controls/Button.h b/public/vgui_controls/Button.h new file mode 100644 index 0000000..50b68da --- /dev/null +++ b/public/vgui_controls/Button.h @@ -0,0 +1,238 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef BUTTON_H +#define BUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include "vgui/MouseCode.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class Button : public Label +{ + DECLARE_CLASS_SIMPLE( Button, Label ); + +public: + // You can optionally pass in the panel to send the click message to and the name of the command to send to that panel. + Button(Panel *parent, const char *panelName, const char *text, Panel *pActionSignalTarget=NULL, const char *pCmd=NULL); + Button(Panel *parent, const char *panelName, const wchar_t *text, Panel *pActionSignalTarget=NULL, const char *pCmd=NULL); + ~Button(); +private: + void Init(); +public: + // Set armed state. + virtual void SetArmed(bool state); + // Check armed state + virtual bool IsArmed( void ); + + // Check depressed state + virtual bool IsDepressed(); + // Set button force depressed state. + virtual void ForceDepressed(bool state); + // Set button depressed state with respect to the force depressed state. + virtual void RecalculateDepressedState( void ); + + // Set button selected state. + virtual void SetSelected(bool state); + // Check selected state + virtual bool IsSelected( void ); + + virtual void SetBlink(bool state); + virtual bool IsBlinking( void ); + + //Set whether or not the button captures all mouse input when depressed. + virtual void SetUseCaptureMouse( bool state ); + // Check if mouse capture is enabled. + virtual bool IsUseCaptureMouseEnabled( void ); + + // Activate a button click. + MESSAGE_FUNC( DoClick, "PressButton" ); + MESSAGE_FUNC( OnHotkey, "Hotkey" ) + { + DoClick(); + } + + // Set button to be mouse clickable or not. + virtual void SetMouseClickEnabled( MouseCode code, bool state ); + // Check if button is mouse clickable + virtual bool IsMouseClickEnabled( MouseCode code ); + // sets the how this button activates + enum ActivationType_t + { + ACTIVATE_ONPRESSEDANDRELEASED, // normal button behaviour + ACTIVATE_ONPRESSED, // menu buttons, toggle buttons + ACTIVATE_ONRELEASED, // menu items + }; + virtual void SetButtonActivationType(ActivationType_t activationType); + + // Message targets that the button has been pressed + virtual void FireActionSignal( void ); + // Perform graphical layout of button + virtual void PerformLayout(); + + virtual bool RequestInfo(KeyValues *data); + + virtual bool CanBeDefaultButton(void); + + // Set this button to be the button that is accessed by default when the user hits ENTER or SPACE + MESSAGE_FUNC_INT( SetAsDefaultButton, "SetAsDefaultButton", state ); + // Set this button to be the button that is currently accessed by default when the user hits ENTER or SPACE + MESSAGE_FUNC_INT( SetAsCurrentDefaultButton, "SetAsCurrentDefaultButton", state ); + + // Respond when key focus is received + virtual void OnSetFocus(); + // Respond when focus is killed + virtual void OnKillFocus(); + + // Set button border attribute enabled, controls display of button. + virtual void SetButtonBorderEnabled( bool state ); + + // Set default button colors. + virtual void SetDefaultColor(Color fgColor, Color bgColor); + // Set armed button colors + virtual void SetArmedColor(Color fgColor, Color bgColor); + // Set selected button colors + virtual void SetSelectedColor(Color fgColor, Color bgColor); + // Set depressed button colors + virtual void SetDepressedColor(Color fgColor, Color bgColor); + // Set blink button color + virtual void SetBlinkColor(Color fgColor); + + // Get button foreground color + virtual Color GetButtonFgColor(); + // Get button background color + virtual Color GetButtonBgColor(); + + Color GetButtonDefaultFgColor() { return _defaultFgColor; } + Color GetButtonDefaultBgColor() { return _defaultBgColor; } + + Color GetButtonArmedFgColor() { return _armedFgColor; } + Color GetButtonArmedBgColor() { return _armedBgColor; } + + Color GetButtonSelectedFgColor() { return _selectedFgColor; } + Color GetButtonSelectedBgColor() { return _selectedBgColor; } + + Color GetButtonDepressedFgColor() { return _depressedFgColor; } + Color GetButtonDepressedBgColor() { return _depressedBgColor; } + + // Set default button border attributes. + virtual void SetDefaultBorder(IBorder *border); + // Set depressed button border attributes. + virtual void SetDepressedBorder(IBorder *border); + // Set key focused button border attributes. + virtual void SetKeyFocusBorder(IBorder *border); + + // Set the command to send when the button is pressed + // Set the panel to send the command to with AddActionSignalTarget() + virtual void SetCommand( const char *command ); + // Set the message to send when the button is pressed + virtual void SetCommand( KeyValues *message ); + + // sound handling + void SetArmedSound(const char *sound); + void SetDepressedSound(const char *sound); + void SetReleasedSound(const char *sound); + + /* CUSTOM MESSAGE HANDLING + "PressButton" - makes the button act as if it had just been pressed by the user (just like DoClick()) + input: none + */ + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + virtual void SizeToContents(); + + virtual KeyValues *GetCommand(); + + bool IsDrawingFocusBox(); + void DrawFocusBox( bool bEnable ); + + bool ShouldPaint(){ return _paint; } + void SetShouldPaint( bool paint ){ _paint = paint; } + + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void NavigateTo(); + virtual void NavigateFrom(); + +protected: + virtual void DrawFocusBorder(int tx0, int ty0, int tx1, int ty1); + + // Paint button on screen + virtual void Paint(void); + // Get button border attributes. + virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_INT( OnSetState, "SetState", state ); + + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + virtual void OnKeyCodePressed(KeyCode code); + virtual void OnKeyCodeReleased(KeyCode code); + + // Get control settings for editing + virtual void GetSettings( KeyValues *outResourceData ); + virtual const char *GetDescription( void ); + + KeyValues *GetActionMessage(); + void PlayButtonReleasedSound(); + +protected: + enum ButtonFlags_t + { + ARMED = 0x0001, + DEPRESSED = 0x0002, + FORCE_DEPRESSED = 0x0004, + BUTTON_BORDER_ENABLED = 0x0008, + USE_CAPTURE_MOUSE = 0x0010, + BUTTON_KEY_DOWN = 0x0020, + DEFAULT_BUTTON = 0x0040, + SELECTED = 0x0080, + DRAW_FOCUS_BOX = 0x0100, + BLINK = 0x0200, + ALL_FLAGS = 0xFFFF, + }; + + CUtlFlags< unsigned short > _buttonFlags; // see ButtonFlags_t + int _mouseClickMask; + KeyValues *_actionMessage; + ActivationType_t _activationType; + + IBorder *_defaultBorder; + IBorder *_depressedBorder; + IBorder *_keyFocusBorder; + + Color _defaultFgColor, _defaultBgColor; + Color _armedFgColor, _armedBgColor; + Color _selectedFgColor, _selectedBgColor; + Color _depressedFgColor, _depressedBgColor; + Color _keyboardFocusColor; + Color _blinkFgColor; + + bool _paint; + + unsigned short m_sArmedSoundName, m_sDepressedSoundName, m_sReleasedSoundName; + bool m_bSelectionStateSaved; + bool m_bStaySelectedOnClick; +}; + +} // namespace vgui + +#endif // BUTTON_H diff --git a/public/vgui_controls/CheckButton.h b/public/vgui_controls/CheckButton.h new file mode 100644 index 0000000..a7e25ac --- /dev/null +++ b/public/vgui_controls/CheckButton.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CHECKBUTTON_H +#define CHECKBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class TextImage; + +//----------------------------------------------------------------------------- +// Purpose: Check box image +//----------------------------------------------------------------------------- +class CheckImage : public TextImage +{ +public: + CheckImage(CheckButton *CheckButton) : TextImage( "g" ) + { + _CheckButton = CheckButton; + + SetSize(20, 13); + } + + virtual void Paint(); + + virtual void SetColor(Color color) + { + _borderColor1 = color; + _borderColor2 = color; + _checkColor = color; + } + + Color _borderColor1; + Color _borderColor2; + Color _checkColor; + + Color _bgColor; + +private: + CheckButton *_CheckButton; +}; + +//----------------------------------------------------------------------------- +// Purpose: Tick-box button +//----------------------------------------------------------------------------- +class CheckButton : public ToggleButton +{ + DECLARE_CLASS_SIMPLE( CheckButton, ToggleButton ); + +public: + CheckButton(Panel *parent, const char *panelName, const char *text); + ~CheckButton(); + + // Check the button + virtual void SetSelected(bool state ); + + // sets whether or not the state of the check can be changed + // if this is set to false, then no input in the code or by the user can change it's state + virtual void SetCheckButtonCheckable(bool state); + virtual bool IsCheckButtonCheckable() const { return m_bCheckButtonCheckable; } + + Color GetDisabledFgColor() { return _disabledFgColor; } + Color GetDisabledBgColor() { return _disabledBgColor; } + + CheckImage *GetCheckImage() { return _checkBoxImage; } + + virtual void SetHighlightColor(Color fgColor); + +protected: + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel ); + virtual Color GetButtonFgColor(); + + virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + /* MESSAGES SENT + "CheckButtonChecked" - sent when the check button state is changed + "state" - button state: 1 is checked, 0 is unchecked + */ + + +private: + enum { CHECK_INSET = 6 }; + bool m_bCheckButtonCheckable; + CheckImage *_checkBoxImage; + Color _disabledFgColor; + Color _disabledBgColor; + Color _highlightFgColor; +}; + +} // namespace vgui + +#endif // CHECKBUTTON_H diff --git a/public/vgui_controls/CheckButtonList.h b/public/vgui_controls/CheckButtonList.h new file mode 100644 index 0000000..6bb95d9 --- /dev/null +++ b/public/vgui_controls/CheckButtonList.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CHECKBUTTONLIST_H +#define CHECKBUTTONLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "utlvector.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Contains a list of check boxes, displaying scrollbars if necessary +//----------------------------------------------------------------------------- +class CheckButtonList : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CheckButtonList, EditablePanel ); + +public: + CheckButtonList(Panel *parent, const char *name); + ~CheckButtonList(); + + // adds a check button to the list + int AddItem(const char *itemText, bool startsSelected, KeyValues *userData); + + // clears the list + void RemoveAll(); + + // number of items in list that are checked + int GetCheckedItemCount(); + + // item iteration + bool IsItemIDValid(int itemID); + int GetHighestItemID(); + int GetItemCount(); + + // item info + KeyValues *GetItemData(int itemID); + bool IsItemChecked(int itemID); + void SetItemCheckable(int itemID, bool state); + + /* MESSAGES SENT + "CheckButtonChecked" - sent when one of the check buttons state has changed + + */ + +protected: + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnMouseWheeled(int delta); + +private: + MESSAGE_FUNC_PARAMS( OnCheckButtonChecked, "CheckButtonChecked", pParams ); + MESSAGE_FUNC( OnScrollBarSliderMoved, "ScrollBarSliderMoved" ); + + struct CheckItem_t + { + vgui::CheckButton *checkButton; + KeyValues *userData; + }; + CUtlVector m_CheckItems; + vgui::ScrollBar *m_pScrollBar; +}; + +} + +#endif // CHECKBUTTONLIST_H diff --git a/public/vgui_controls/CircularProgressBar.h b/public/vgui_controls/CircularProgressBar.h new file mode 100644 index 0000000..2a31f50 --- /dev/null +++ b/public/vgui_controls/CircularProgressBar.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CIRCULARPROGRESSBAR_H +#define CIRCULARPROGRESSBAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +enum progress_textures_t +{ + PROGRESS_TEXTURE_FG, + PROGRESS_TEXTURE_BG, + + NUM_PROGRESS_TEXTURES, +}; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Progress Bar in the shape of a pie graph +//----------------------------------------------------------------------------- +class CircularProgressBar : public ProgressBar +{ + DECLARE_CLASS_SIMPLE( CircularProgressBar, ProgressBar ); + +public: + CircularProgressBar(Panel *parent, const char *panelName); + ~CircularProgressBar(); + + virtual void ApplySettings(KeyValues *inResourceData); + virtual void ApplySchemeSettings(IScheme *pScheme); + + void SetFgImage(const char *imageName) { SetImage( imageName, PROGRESS_TEXTURE_FG ); } + void SetBgImage(const char *imageName) { SetImage( imageName, PROGRESS_TEXTURE_BG ); } + + enum CircularProgressDir_e + { + PROGRESS_CW, + PROGRESS_CCW + }; + int GetProgressDirection() const { return m_iProgressDirection; } + void SetProgressDirection( int val ) { m_iProgressDirection = val; } + void SetStartSegment( int val ) { m_iStartSegment = val; } + +protected: + virtual void Paint(); + virtual void PaintBackground(); + + void DrawCircleSegment( Color c, float flEndDegrees, bool clockwise /* = true */ ); + void SetImage(const char *imageName, progress_textures_t iPos); + +private: + int m_iProgressDirection; + int m_iStartSegment; + + int m_nTextureId[NUM_PROGRESS_TEXTURES]; + char *m_pszImageName[NUM_PROGRESS_TEXTURES]; + int m_lenImageName[NUM_PROGRESS_TEXTURES]; +}; + +} // namespace vgui + +#endif // CIRCULARPROGRESSBAR_H \ No newline at end of file diff --git a/public/vgui_controls/ComboBox.h b/public/vgui_controls/ComboBox.h new file mode 100644 index 0000000..266f4dc --- /dev/null +++ b/public/vgui_controls/ComboBox.h @@ -0,0 +1,186 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMBOBOX_H +#define COMBOBOX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ +//----------------------------------------------------------------------------- +// Purpose: Scroll bar button +//----------------------------------------------------------------------------- +class ComboBoxButton : public vgui::Button +{ +public: + ComboBoxButton(ComboBox *parent, const char *panelName, const char *text); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + virtual void OnCursorExited(); + + virtual Color GetButtonBgColor() + { + if (IsEnabled()) + return Button::GetButtonBgColor(); + + return m_DisabledBgColor; + } + +private: + Color m_DisabledBgColor; +}; + +//----------------------------------------------------------------------------- +// Purpose: Text entry with drop down options list +//----------------------------------------------------------------------------- +class ComboBox : public TextEntry +{ + DECLARE_CLASS_SIMPLE( ComboBox, TextEntry ); + +public: + ComboBox(Panel *parent, const char *panelName, int numLines, bool allowEdit); + ~ComboBox(); + + // functions designed to be overriden + virtual void OnShowMenu(Menu *menu) {} + virtual void OnHideMenu(Menu *menu) {} + + // Set the number of items in the drop down menu. + virtual void SetNumberOfEditLines( int numLines ); + + // Add an item to the drop down + virtual int AddItem(const char *itemText, const KeyValues *userData); + virtual int AddItem(const wchar_t *itemText, const KeyValues *userData); + + virtual int GetItemCount() const; + int GetItemIDFromRow( int row ); + + // update the item + virtual bool UpdateItem(int itemID, const char *itemText,const KeyValues *userData); + virtual bool UpdateItem(int itemID, const wchar_t *itemText, const KeyValues *userData); + virtual bool IsItemIDValid(int itemID); + + // set the enabled state of an item + virtual void SetItemEnabled(const char *itemText, bool state); + virtual void SetItemEnabled(int itemID, bool state); + + // Removes a single item + void DeleteItem( int itemID ); + + // Remove all items from the drop down menu + void RemoveAll(); + // deprecated, use above + void DeleteAllItems() { RemoveAll(); } + + // Sorts the items in the list - FIXME does nothing + virtual void SortItems(); + + // Set the visiblity of the drop down menu button. + virtual void SetDropdownButtonVisible(bool state); + + // Return true if the combobox current has the dropdown menu open + virtual bool IsDropdownVisible(); + + // Activate the item in the menu list,as if that + // menu item had been selected by the user + MESSAGE_FUNC_INT( ActivateItem, "ActivateItem", itemID ); + void ActivateItemByRow(int row); + + void SilentActivateItem(int itemID); // Sets the menu to the appropriate row without sending a TextChanged message + void SilentActivateItemByRow(int row); // Sets the menu to the appropriate row without sending a TextChanged message + + int GetActiveItem(); + KeyValues *GetActiveItemUserData(); + KeyValues *GetItemUserData(int itemID); + void GetItemText( int itemID, OUT_Z_BYTECAP(bufLenInBytes) wchar_t *text, int bufLenInBytes ); + void GetItemText( int itemID, OUT_Z_BYTECAP(bufLenInBytes) char *text, int bufLenInBytes ); + + // sets a custom menu to use for the dropdown + virtual void SetMenu( Menu *menu ); + virtual Menu *GetMenu() { return m_pDropDown; } + + // Layout the format of the combo box for drawing on screen + virtual void PerformLayout(); + + /* action signals + "TextChanged" - signals that the text has changed in the combo box + + */ + + virtual void ShowMenu(); + virtual void HideMenu(); + virtual void OnKillFocus(); + MESSAGE_FUNC( OnMenuClose, "MenuClose" ); + virtual void DoClick(); + virtual void OnSizeChanged(int wide, int tall); + + virtual void SetOpenDirection(Menu::MenuDirection_e direction); + + virtual void SetFont( HFont font ); + + virtual void SetUseFallbackFont( bool bState, HFont hFallback ); + + ComboBoxButton *GetComboButton( void ) { return m_pButton; } + +protected: + // overrides + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + MESSAGE_FUNC( OnMenuItemSelected, "MenuItemSelected" ); + virtual void OnCommand( const char *command ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void ApplySettings( KeyValues *pInResourceData ); + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + + // custom message handlers + MESSAGE_FUNC_WCHARPTR( OnSetText, "SetText", text ); + virtual void OnSetFocus(); // called after the panel receives the keyboard focus +#ifdef _X360 + virtual void OnKeyCodePressed(KeyCode code); +#endif + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + + void SelectMenuItem(int itemToSelect); + void MoveAlongMenuItemList(int direction); + void MoveToFirstMenuItem(); + void MoveToLastMenuItem(); +private: + void DoMenuLayout(); + + Menu *m_pDropDown; + ComboBoxButton *m_pButton; + bool m_bPreventTextChangeMessage; + +//============================================================================= +// HPE_BEGIN: +// [pfreese] This member variable is never initialized and not used correctly +//============================================================================= + +// bool m_bAllowEdit; + +//============================================================================= +// HPE_END +//============================================================================= + bool m_bHighlight; + Menu::MenuDirection_e m_iDirection; + int m_iOpenOffsetY; + + char m_szBorderOverride[64]; +}; + +} // namespace vgui + +#endif // COMBOBOX_H diff --git a/public/vgui_controls/ControllerMap.h b/public/vgui_controls/ControllerMap.h new file mode 100644 index 0000000..7ccbdc6 --- /dev/null +++ b/public/vgui_controls/ControllerMap.h @@ -0,0 +1,48 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CONTROLLERMAP_H +#define CONTROLLERMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "Panel.h" +#include "utlmap.h" +#include "utlsymbol.h" + +class CControllerMap : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CControllerMap, vgui::Panel ) + + virtual void OnKeyCodeTyped( vgui::KeyCode code ); + +public: + CControllerMap( vgui::Panel *parent, const char *name ); + + virtual void ApplySettings( KeyValues *inResourceData ); + + int NumButtons( void ) + { + return m_buttonMap.Count(); + } + + const char *GetBindingText( int idx ); + const char *GetBindingIcon( int idx ); + +private: + + struct button_t + { + CUtlSymbol cmd; + CUtlSymbol text; + CUtlSymbol icon; + }; + CUtlMap< int, button_t > m_buttonMap; +}; + +#endif // CONTROLLERMAP_H \ No newline at end of file diff --git a/public/vgui_controls/Controls.h b/public/vgui_controls/Controls.h new file mode 100644 index 0000000..0afb8de --- /dev/null +++ b/public/vgui_controls/Controls.h @@ -0,0 +1,161 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef CONTROLS_H +#define CONTROLS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +#include "tier1/interface.h" +#include "vgui/MouseCode.h" +#include "vgui/KeyCode.h" +#include "tier3/tier3.h" + + +namespace vgui +{ + +// handles the initialization of the vgui interfaces +// interfaces (listed below) are first attempted to be loaded from primaryProvider, then secondaryProvider +// moduleName should be the name of the module that this instance of the vgui_controls has been compiled into +bool VGui_InitInterfacesList( const char *moduleName, CreateInterfaceFn *factoryList, int numFactories ); + +// returns the name of the module as specified above +const char *GetControlsModuleName(); + +class IPanel; +class IInput; +class ISchemeManager; +class ISurface; +class ISystem; +class IVGui; + +//----------------------------------------------------------------------------- +// Backward compat interfaces, use the interfaces grabbed in tier3 +// set of accessor functions to vgui interfaces +// the appropriate header file for each is listed above the item +//----------------------------------------------------------------------------- + +// #include +inline vgui::IInput *input() +{ + return g_pVGuiInput; +} + +// #include +inline vgui::ISchemeManager *scheme() +{ + return g_pVGuiSchemeManager; +} + +// #include +inline vgui::ISurface *surface() +{ + return g_pVGuiSurface; +} + +// #include +inline vgui::ISystem *system() +{ + return g_pVGuiSystem; +} + +// #include +inline vgui::IVGui *ivgui() +{ + return g_pVGui; +} + +// #include +inline vgui::IPanel *ipanel() +{ + return g_pVGuiPanel; +} + +// predeclare all the vgui control class names +class AnalogBar; +class AnimatingImagePanel; +class AnimationController; +class BuildModeDialog; +class Button; +class CheckButton; +class CheckButtonList; +class CircularProgressBar; +template< class T >class CvarToggleCheckButton; +class ComboBox; +class DirectorySelectDialog; +class Divider; +class EditablePanel; +class FileOpenDialog; +class Frame; +class GraphPanel; +class HTML; +class ImagePanel; +class Label; +class ListPanel; +class ListViewPanel; +class Menu; +class MenuBar; +class MenuButton; +class MenuItem; +class MessageBox; +class Panel; +class PanelListPanel; +class ProgressBar; +class ProgressBox; +class PropertyDialog; +class PropertyPage; +class PropertySheet; +class QueryBox; +class RadioButton; +class RichText; +class ScalableImagePanel; +class ScrollBar; +class ScrollBarSlider; +class SectionedListPanel; +class Slider; +class Splitter; +class TextEntry; +class ToggleButton; +class BaseTooltip; +class TextTooltip; +class TreeView; +class CTreeViewListControl; +class URLLabel; +class WizardPanel; +class WizardSubPanel; + +// vgui controls helper classes +class BuildGroup; +class FocusNavGroup; +class IBorder; +class IImage; +class Image; +class ImageList; +class TextImage; + +} // namespace vgui + +// hotkeys disabled until we work out exactly how we want to do them +#define VGUI_HOTKEYS_ENABLED +//#define VGUI_DRAW_HOTKEYS_ENABLED + +#define USING_BUILD_FACTORY( className ) \ + extern className *g_##className##LinkerHack; \ + className *g_##className##PullInModule = g_##className##LinkerHack; + +#define USING_BUILD_FACTORY_ALIAS( className, factoryName ) \ + extern className *g_##factoryName##LinkerHack; \ + className *g_##factoryName##PullInModule = g_##factoryName##LinkerHack; + +#endif // CONTROLS_H diff --git a/public/vgui_controls/DialogManager.h b/public/vgui_controls/DialogManager.h new file mode 100644 index 0000000..5c37616 --- /dev/null +++ b/public/vgui_controls/DialogManager.h @@ -0,0 +1,196 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DIALOGMANAGER_H +#define DIALOGMANAGER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: utility class, maps a set of ID's to dialogs +// used to manage sets of similar dialogs (object property dialogs, etc.) +//----------------------------------------------------------------------------- +template +class DialogManager +{ +public: + // new dialog factory function + typedef TDialog *(*CreateNewDialogFunc_t)(I dialogID); + + // constructor + DialogManager(CreateNewDialogFunc_t createDialogFunc); + + // finds the dialog by the specified ID + TDialog *FindDialog(I dialogID, bool bCreate); + + // opens the dialog; creating it if specified + TDialog *ActivateDialog(I dialogID, bool bCreate); + + // closes all the dialogs + void CloseAll(); + + // closes and deletes all the dialogs + void CloseAndDeleteAll(); + + // returns number of active dialogs + int Count(); + + // sets parent to use + void SetParent( vgui::VPANEL parent ); + +private: + // checks if an index in the dialog list is valid; if it has been deleted, removes the entry + bool ValidateIndex(int index); + + struct DialogItem_t + { + I id; + DHANDLE dlg; + }; + + CUtlLinkedList m_Dialogs; + CreateNewDialogFunc_t m_CreateFunc; + vgui::VPANEL m_pVGUIParentPanel; +}; + + +// constructor +template +inline DialogManager::DialogManager(CreateNewDialogFunc_t createDialogFunc) +{ + m_CreateFunc = createDialogFunc; + m_pVGUIParentPanel = NULL; +} + +// finds the dialog; creating it if necessary +template +inline TDialog *DialogManager::FindDialog(I dialogID, bool bCreate) +{ + for (int i = 0; i < m_Dialogs.MaxElementIndex(); i++) + { + if (ValidateIndex(i) && m_Dialogs[i].id == dialogID) + { + return m_Dialogs[i].dlg; + } + } + + if (bCreate) + { + int newIndex = m_Dialogs.AddToTail(); + if (m_CreateFunc) + { + m_Dialogs[newIndex].dlg = m_CreateFunc(dialogID); + } + else + { + m_Dialogs[newIndex].dlg = new TDialog(NULL, dialogID); + } + Assert(m_pVGUIParentPanel); + m_Dialogs[newIndex].dlg->SetParent( m_pVGUIParentPanel ); + + m_Dialogs[newIndex].id = dialogID; + return m_Dialogs[newIndex].dlg; + } + + // dlg not found, not created + return NULL; +} + +// opens the dialog; creating it if necessary +template +inline TDialog *DialogManager::ActivateDialog(I dialogID, bool bCreate) +{ + TDialog *dlg = FindDialog(dialogID, bCreate); + if (dlg) + { + dlg->Activate(); + } + return dlg; +} + +// count +template +inline int DialogManager::Count() +{ + // validate all the indexes first + for (int i = 0; i < m_Dialogs.MaxElementIndex(); i++) + { + if (ValidateIndex(i)) + { + } + } + + // return the (remaining) count + return m_Dialogs.Count(); +} + +// closes all the dialogs +template +inline void DialogManager::CloseAll() +{ + for (int i = 0; i < m_Dialogs.MaxElementIndex(); i++) + { + if (ValidateIndex(i)) + { + m_Dialogs[i].dlg->PostMessage(m_Dialogs[i].dlg, new KeyValues("Close")); + } + } +} + +// closes and deletes all the dialogs +template +inline void DialogManager::CloseAndDeleteAll() +{ + CloseAll(); + for (int i = 0; i < m_Dialogs.MaxElementIndex(); i++) + { + if (ValidateIndex(i)) + { + m_Dialogs[i].dlg->MarkForDeletion(); + } + } + m_Dialogs.RemoveAll(); +} + +// checks if a dialog is valid; if it has been deleted, removes the entry +template +inline bool DialogManager::ValidateIndex(int index) +{ + if (m_Dialogs.IsValidIndex(index)) + { + if (m_Dialogs[index].dlg.Get()) + { + return true; + } + else + { + // entry has been deleted; removed + m_Dialogs.Remove(index); + } + } + return false; +} + +template +inline void DialogManager::SetParent( vgui::VPANEL parent ) +{ + m_pVGUIParentPanel = parent; +} + + +} // namespace vgui + +#endif // DIALOGMANAGER_H diff --git a/public/vgui_controls/DirectorySelectDialog.h b/public/vgui_controls/DirectorySelectDialog.h new file mode 100644 index 0000000..f024d32 --- /dev/null +++ b/public/vgui_controls/DirectorySelectDialog.h @@ -0,0 +1,96 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef DIRECTORYSELECTDIALOG_H +#define DIRECTORYSELECTDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Used to handle dynamically populating the tree view +//----------------------------------------------------------------------------- +class DirectoryTreeView : public TreeView +{ +public: + DirectoryTreeView(DirectorySelectDialog *parent, const char *name); + virtual void GenerateChildrenOfNode(int itemIndex); + +private: + DirectorySelectDialog *m_pParent; +}; + +//----------------------------------------------------------------------------- +// Purpose: Utility dialog, used to let user select a directory (like during install) +//----------------------------------------------------------------------------- +class DirectorySelectDialog : public Frame +{ + DECLARE_CLASS_SIMPLE( DirectorySelectDialog, Frame ); + +public: + DirectorySelectDialog(vgui::Panel *parent, const char *title); + + // sets where it should start searching + void SetStartDirectory(const char *path); + + // sets what name should show up by default in the create directory dialog + void SetDefaultCreateDirectoryName(const char *defaultCreateDirName); + + // opens the dialog + void DoModal(); + + /* action signals + + "DirectorySelected" + "dir" - the directory that was selected + + */ + + // Expand the tree nodes to match a supplied path, optionally selecting the final directory + void ExpandTreeToPath( const char *lpszPath, bool bSelectFinalDirectory = true ); + +protected: + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnClose(); + + // command buttons + virtual void OnCommand(const char *command); + +private: + MESSAGE_FUNC( OnTextChanged, "TextChanged" ); + MESSAGE_FUNC( OnTreeViewItemSelected, "TreeViewItemSelected" ); + MESSAGE_FUNC_CHARPTR( OnCreateDirectory, "CreateDirectory", dir ); + void BuildDirTree(); + void BuildDriveChoices(); + void ExpandTreeNode(const char *path, int parentNodeIndex); + void GenerateChildrenOfDirectoryNode(int nodeIndex); + void GenerateFullPathForNode(int nodeIndex, char *path, int pathBufferSize); + bool DoesDirectoryHaveSubdirectories(const char *path, const char *dir); + + char m_szCurrentDir[512]; + char m_szDefaultCreateDirName[64]; + char m_szCurrentDrive[16]; + vgui::TreeView *m_pDirTree; + vgui::ComboBox *m_pDriveCombo; + vgui::Button *m_pCancelButton; + vgui::Button *m_pSelectButton; + vgui::Button *m_pCreateButton; + + friend class DirectoryTreeView; +}; + +} // namespace vgui + + +#endif // DIRECTORYSELECTDIALOG_H diff --git a/public/vgui_controls/Divider.h b/public/vgui_controls/Divider.h new file mode 100644 index 0000000..1c6e7b0 --- /dev/null +++ b/public/vgui_controls/Divider.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DIVIDER_H +#define DIVIDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Thin line used to divide sections in dialogs +//----------------------------------------------------------------------------- +class Divider : public Panel +{ + DECLARE_CLASS_SIMPLE( Divider, Panel ); + +public: + Divider(Panel *parent, const char *name); + ~Divider(); + + virtual void ApplySchemeSettings(IScheme *pScheme); +}; + + +} // namespace vgui + + +#endif // DIVIDER_H diff --git a/public/vgui_controls/EditablePanel.h b/public/vgui_controls/EditablePanel.h new file mode 100644 index 0000000..11b8e76 --- /dev/null +++ b/public/vgui_controls/EditablePanel.h @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef EDITABLEPANEL_H +#define EDITABLEPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Panel that supports editing via the build dialog +//----------------------------------------------------------------------------- +class EditablePanel : public Panel +{ + DECLARE_CLASS_SIMPLE( EditablePanel, Panel ); + +public: + EditablePanel(Panel *parent, const char *panelName); + EditablePanel(Panel *parent, const char *panelName, HScheme hScheme); + + virtual ~EditablePanel(); + + // Load the control settings - should be done after all the children are added + // If you pass in pPreloadedKeyValues, it won't actually load the file. That way, you can cache + // the keyvalues outside of here if you want to prevent file accesses in the middle of the game. + virtual void LoadControlSettings(const char *dialogResourceName, const char *pathID = NULL, KeyValues *pPreloadedKeyValues = NULL, KeyValues *pConditions = NULL); + virtual void ApplySettings(KeyValues *inResourceData); + + // sets the name of this dialog so it can be saved in the user config area + // use dialogID to differentiate multiple instances of the same dialog + virtual void LoadUserConfig(const char *configName, int dialogID = 0); + virtual void SaveUserConfig(); + + // combines both of the above, LoadControlSettings & LoadUserConfig + virtual void LoadControlSettingsAndUserConfig(const char *dialogResourceName, int dialogID = 0); + + // Override to change how build mode is activated + virtual void ActivateBuildMode(); + + // Return the buildgroup that this panel is part of. + virtual BuildGroup *GetBuildGroup(); + + // Virtual factory for control creation + // controlName is a string which is the same as the class name + virtual Panel *CreateControlByName(const char *controlName); + + // Shortcut function to set data in child controls + virtual void SetControlString(const char *controlName, const char *string); + // Shortcut function to set data in child controls + virtual void SetControlString(const char *controlName, const wchar_t *string); + // Shortcut function to set data in child controls + virtual void SetControlInt(const char *controlName, int state); + // Shortcut function to get data in child controls + virtual int GetControlInt(const char *controlName, int defaultState); + // Shortcut function to get data in child controls + // Returns a maximum of 511 characters in the string + virtual const char *GetControlString(const char *controlName, const char *defaultString = ""); + // as above, but copies the result into the specified buffer instead of a static buffer + virtual void GetControlString(const char *controlName, char *buf, int bufSize, const char *defaultString = ""); + // sets the enabled state of a control + virtual void SetControlEnabled(const char *controlName, bool enabled); + virtual void SetControlVisible(const char *controlName, bool visible); + + // localization variables (used in constructing UI strings) + // after the variable is set, causes all the necessary sub-panels to update + virtual void SetDialogVariable(const char *varName, const char *value); + virtual void SetDialogVariable(const char *varName, const wchar_t *value); + virtual void SetDialogVariable(const char *varName, int value); + virtual void SetDialogVariable(const char *varName, float value); + + // Focus handling + // Delegate focus to a sub panel + virtual void RequestFocus(int direction = 0); + virtual bool RequestFocusNext(VPANEL panel); + virtual bool RequestFocusPrev(VPANEL panel); + // Pass the focus down onto the last used panel + virtual void OnSetFocus(); + // Update focus info for navigation + virtual void OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel); + // Get the panel that currently has keyfocus + virtual VPANEL GetCurrentKeyFocus(); + // Get the panel with the specified hotkey + virtual Panel *HasHotkey(wchar_t key); + + virtual void OnKeyCodePressed( KeyCode code ); + + // Handle information requests + virtual bool RequestInfo(KeyValues *data); + /* INFO HANDLING + "BuildDialog" + input: + "BuildGroupPtr" - pointer to the panel/dialog to edit + returns: + "PanelPtr" - pointer to a new BuildModeDialog() + + "ControlFactory" + input: + "ControlName" - class name of the control to create + returns: + "PanelPtr" - pointer to the newly created panel, or NULL if no such class exists + */ + // registers a file in the list of control settings, so the vgui dialog can choose between them to edit + virtual void RegisterControlSettingsFile(const char *dialogResourceName, const char *pathID = NULL); + + // localization variables - only use this if you need to iterate the variables, use the SetLoc*() to set them + KeyValues *GetDialogVariables(); + +protected: + virtual void PaintBackground(); + + // nav group access + virtual FocusNavGroup &GetFocusNavGroup(); + + // called when default button has been set + MESSAGE_FUNC_HANDLE( OnDefaultButtonSet, "DefaultButtonSet", button ); + // called when the current default button has been set + MESSAGE_FUNC_HANDLE( OnCurrentDefaultButtonSet, "CurrentDefaultButtonSet", button ); + MESSAGE_FUNC( OnFindDefaultButton, "FindDefaultButton" ); + + // overrides + virtual void OnChildAdded(VPANEL child); + virtual void OnSizeChanged(int wide, int tall); + virtual void OnClose(); + + // user configuration settings + // this is used for any control details the user wants saved between sessions + // eg. dialog positions, last directory opened, list column width + virtual void ApplyUserConfigSettings(KeyValues *userConfig); + + // returns user config settings for this control + virtual void GetUserConfigSettings(KeyValues *userConfig); + + // optimization for text rendering, returns true if text should be rendered immediately after Paint() + // disabled for now + // virtual bool ShouldFlushText(); + +private: + void ForceSubPanelsToUpdateWithNewDialogVariables(); + + BuildGroup *_buildGroup; + FocusNavGroup m_NavGroup; + KeyValues *m_pDialogVariables; + + // the wide and tall to which all controls are locked - used for autolayout deltas + char *m_pszConfigName; + int m_iConfigID; + bool m_bShouldSkipAutoResize; +}; + +} // namespace vgui + +#endif // EDITABLEPANEL_H diff --git a/public/vgui_controls/ExpandButton.h b/public/vgui_controls/ExpandButton.h new file mode 100644 index 0000000..2dbf849 --- /dev/null +++ b/public/vgui_controls/ExpandButton.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A button with no borders that shows a left-pointing or down-pointing triangle +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef EXPANDBUTTON_H +#define EXPANDBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: A button with no borders that shows a left-pointing or down-pointing arrow +//----------------------------------------------------------------------------- +class ExpandButton : public ToggleButton +{ + DECLARE_CLASS_SIMPLE( ExpandButton, ToggleButton ); + +public: + ExpandButton( Panel *parent, const char *panelName ); + ~ExpandButton(); + + // Expand the button (selected == expanded) + virtual void SetSelected( bool bExpand ); + + // sets whether or not the state of the check can be changed + // if this is set to false, then no input in the code or by the user can change it's state + void SetExpandable(bool state); + + virtual void Paint(); + +protected: + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_PTR( OnExpanded, "Expanded", panel ); + + virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + /* MESSAGES SENT + "Expanded" - sent when the expand button state is changed + "state" - button state: 1 is expanded, 0 is unexpanded + */ + +private: + bool m_bExpandable; + HFont m_hFont; + Color m_Color; +}; + +} // namespace vgui + +#endif // EXPANDBUTTON_H diff --git a/public/vgui_controls/FileOpenDialog.h b/public/vgui_controls/FileOpenDialog.h new file mode 100644 index 0000000..bcaccf0 --- /dev/null +++ b/public/vgui_controls/FileOpenDialog.h @@ -0,0 +1,160 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Declaration of FileOpenDialog class, a generic open/save as file dialog +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FILEOPENDIALOG_H +#define FILEOPENDIALOG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Frame.h" + +namespace vgui +{ + +class FileCompletionEdit; // local +class InputDialog; + +//----------------------------------------------------------------------------- +// Purpose: generic open/save as file dialog +//----------------------------------------------------------------------------- +enum FileOpenDialogType_t +{ + FOD_SAVE = 0, + FOD_OPEN, + FOD_SELECT_DIRECTORY, +}; + + +class FileOpenDialog : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( FileOpenDialog, Frame ); + +public: + // NOTE: Backward compat constructor + FileOpenDialog( Panel *parent, const char *title, bool bOpenFile, KeyValues *pContextKeyValues = 0 ); + + // The context keyvalues are added to all messages sent by this dialog if they are specified + FileOpenDialog( Panel *parent, const char *title, FileOpenDialogType_t type, KeyValues *pContextKeyValues = 0 ); + ~FileOpenDialog(); + + // Set the directory the file search starts in + void SetStartDirectory(const char *dir); + + // Sets the start directory context (and resets the start directory in the process) + // NOTE: If you specify a startdir context, then if you've already opened + // a file with that same start dir context before, it will start in the + // same directory it ended up in. + void SetStartDirectoryContext( const char *pContext, const char *pDefaultDir ); + + // Add filters for the drop down combo box + // The filter info, if specified, gets sent back to the app in the FileSelected message + void AddFilter( const char *filter, const char *filterName, bool bActive, const char *pFilterInfo = NULL ); + + // Activate the dialog + // NOTE: The argument is there for backward compat + void DoModal( bool bUnused = false ); + + // Get the directory this is currently in + void GetCurrentDirectory( char *buf, int bufSize ); + + // Get the last selected file name + void GetSelectedFileName( char *buf, int bufSize ); + + /* + messages sent: + "FileSelected" + "fullpath" // specifies the fullpath of the file + "filterinfo" // Returns the filter info associated with the active filter + "FileSelectionCancelled" + */ + +protected: + virtual void OnCommand( const char *command ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnClose(); + virtual void OnKeyCodeTyped(KeyCode code); + + // handles the open button being pressed + // checks on what has changed and acts accordingly + MESSAGE_FUNC( OnOpen, "OnOpen" ); + MESSAGE_FUNC( OnSelectFolder, "SelectFolder" ); + MESSAGE_FUNC( OnFolderUp, "OnFolderUp" ); + MESSAGE_FUNC( OnNewFolder, "OnNewFolder" ); + MESSAGE_FUNC( OnOpenInExplorer, "OpenInExplorer" ); + + MESSAGE_FUNC( PopulateFileList, "PopulateFileList" ); + MESSAGE_FUNC( PopulateDriveList, "PopulateDriveList" ); + MESSAGE_FUNC( PopulateFileNameCompletion, "PopulateFileNameCompletion" ); + + // moves the directory structure up + virtual void MoveUpFolder(); + + // validates that the current path is valid + virtual void ValidatePath(); + + // handles an item in the list being selected + MESSAGE_FUNC( OnItemSelected, "ItemSelected" ); + MESSAGE_FUNC( OnListItemSelected, "ListItemSelected" ) + { + OnItemSelected(); + } + + // changes directories in response to selecting drives from the combo box + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv ); + + MESSAGE_FUNC( OnInputCanceled, "InputCanceled" ); + MESSAGE_FUNC_PARAMS( OnInputCompleted, "InputCompleted", data ); + +private: + // Necessary because we have 2 constructors + void Init( const char *title, KeyValues *pContextKeyValues ); + + // Does the specified extension match something in the filter list? + bool ExtensionMatchesFilter( const char *pExt ); + + // Choose the first non *.* filter in the filter list + void ChooseExtension( char *pExt, int nBufLen ); + + // Saves the file to the start dir context + void SaveFileToStartDirContext( const char *pFullPath ); + + // Posts a file selected message + void PostFileSelectedMessage( const char *pFileName ); + + // Creates a new folder + void NewFolder( char const *folderName ); + + vgui::ComboBox *m_pFullPathEdit; + vgui::ListPanel *m_pFileList; + + FileCompletionEdit *m_pFileNameEdit; + + vgui::ComboBox *m_pFileTypeCombo; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + vgui::Button *m_pFolderUpButton; + vgui::Button *m_pNewFolderButton; + vgui::Button *m_pOpenInExplorerButton; + vgui::ImagePanel *m_pFolderIcon; + vgui::Label *m_pFileTypeLabel; + + KeyValues *m_pContextKeyValues; + + char m_szLastPath[1024]; + unsigned short m_nStartDirContext; + FileOpenDialogType_t m_DialogType; + bool m_bFileSelected : 1; + + VPANEL m_SaveModal; + vgui::DHANDLE< vgui::InputDialog > m_hInputDialog; +}; + +} // namespace vgui + +#endif // FILEOPENDIALOG_H diff --git a/public/vgui_controls/FileOpenStateMachine.h b/public/vgui_controls/FileOpenStateMachine.h new file mode 100644 index 0000000..4fb327c --- /dev/null +++ b/public/vgui_controls/FileOpenStateMachine.h @@ -0,0 +1,172 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// This is a helper class designed to help with the chains of modal dialogs +// encountered when trying to open or save a particular file +// +//============================================================================= + +#ifndef FILEOPENSTATEMACHINE_H +#define FILEOPENSTATEMACHINE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Panel.h" +#include "tier1/utlstring.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Interface for things using the file open state machine +//----------------------------------------------------------------------------- +abstract_class IFileOpenStateMachineClient +{ +public: + // Called by to allow clients to set up the save dialog + virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues ) = 0; + + // Called by to allow clients to actually read the file in + virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues ) = 0; + + // Called by to allow clients to actually write the file out + virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues ) = 0; +}; + + +//----------------------------------------------------------------------------- +// This is a helper class designed to help with chains of modal dialogs +//----------------------------------------------------------------------------- +enum FileOpenStateMachineFlags_t +{ + FOSM_SHOW_PERFORCE_DIALOGS = 0x1, + FOSM_SHOW_SAVE_QUERY = 0x2, +}; + +class FileOpenStateMachine : public Panel +{ + DECLARE_CLASS_SIMPLE( FileOpenStateMachine, Panel ); + +public: + enum CompletionState_t + { + IN_PROGRESS = 0, // Still not finished, not successful or error + SUCCESSFUL, // Operation finished successfully + FILE_SAVE_CANCELLED, // The user chose 'cancel' in the dialog asking if he wanted to save + FILE_SAVE_NAME_NOT_SPECIFIED, // User hit cancel in the SaveAs dialog + FILE_NOT_OVERWRITTEN, // Operation aborted; existed file and user chose to not write over it + FILE_NOT_CHECKED_OUT, // Operation aborted; file wasn't checked out so couldn't be written over + ERROR_WRITING_FILE, // Error occurred writing the file out + ERROR_MAKING_FILE_WRITEABLE, // Error occurred when making the file writeable + FILE_NOT_MADE_WRITEABLE, // User chose to not make the file be writeable + FILE_OPEN_NAME_NOT_SPECIFIED, // User hit cancel in the Open dialog + ERROR_READING_FILE, // Error occurred reading the file in + }; + + FileOpenStateMachine( vgui::Panel *pParent, IFileOpenStateMachineClient *pClient ); + virtual ~FileOpenStateMachine(); + + // Opens a file, saves an existing one if necessary + void OpenFile( const char *pOpenFileType, KeyValues *pContextKeyValues, const char *pSaveFileName = NULL, const char *pSaveFileType = NULL, int nFlags = 0 ); + + // Version of OpenFile that skips browsing for a particular file to open + void OpenFile( const char *pOpenFileName, const char *pOpenFileType, KeyValues *pContextKeyValues, const char *pSaveFileName = NULL, const char *pSaveFileType = NULL, int nFlags = 0 ); + + // Used to save a specified file, and deal with all the lovely dialogs + // Pass in NULL to get a dialog to choose a filename to save + void SaveFile( KeyValues *pContextKeyValues, const char *pFileName, const char *pFileType, int nFlags = FOSM_SHOW_PERFORCE_DIALOGS ); + + // Returns the state machine completion state + CompletionState_t GetCompletionState(); + + /* MESSAGES SENT + "FileStateMachineFinished" - Called when we exit the state machine for any reason + "completionState" - See the CompletionState_t enum above + "wroteFile" - Indicates whether a file was written or not + "fullPath" - Indicates the full path of the file read for OpenFile or written for SaveFile + "fileType" - Indicates the file type of the file read for OpenFile or written for SaveFile + Use GetFirstTrueSubKey() to get the context passed into the OpenFile/SaveFile methods + */ + +private: + enum FOSMState_t + { + STATE_NONE = -1, + STATE_SHOWING_SAVE_DIRTY_FILE_DIALOG = 0, + STATE_SHOWING_SAVE_DIALOG, + STATE_SHOWING_OVERWRITE_DIALOG, + STATE_SHOWING_CHECK_OUT_DIALOG, + STATE_SHOWING_MAKE_FILE_WRITEABLE_DIALOG, + STATE_WRITING_FILE, + STATE_SHOWING_PERFORCE_ADD_DIALOG, + STATE_SHOWING_OPEN_DIALOG, + STATE_READING_FILE, + }; + + MESSAGE_FUNC_PARAMS( OnFileSelected, "FileSelected", pKeyValues ); + MESSAGE_FUNC( OnFileSelectionCancelled, "FileSelectionCancelled" ); + MESSAGE_FUNC_PARAMS( OnPerforceQueryCompleted, "PerforceQueryCompleted", pKeyValues ); + MESSAGE_FUNC( OnMakeFileWriteable, "MakeFileWriteable" ); + MESSAGE_FUNC( OnCancelMakeFileWriteable, "CancelMakeFileWriteable" ); + + // These messages are related to the dialog in OverwriteFileDialog + MESSAGE_FUNC( OnOverwriteFile, "OverwriteFile" ); + MESSAGE_FUNC( OnCancelOverwriteFile, "CancelOverwriteFile" ); + + // These messages come from the savedocumentquery dialog + MESSAGE_FUNC( OnSaveFile, "OnSaveFile" ); + MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" ); + MESSAGE_FUNC( OnCancelSaveDocument, "OnCancelSaveDocument" ); + + // Cleans up keyvalues + void CleanUpContextKeyValues(); + + // Utility to set the completion state + void SetCompletionState( CompletionState_t state ); + + // Show the save document query dialog + void ShowSaveQuery( ); + + // Shows the overwrite existing file dialog + void OverwriteFileDialog( ); + + // Shows the open file for edit dialog + void CheckOutDialog( ); + + // Shows the make file writeable dialog + void MakeFileWriteableDialog( ); + + // Writes the file out + void WriteFile(); + + // Shows the open file dialog + void OpenFileDialog( ); + + // Reads the file in + void ReadFile(); + + IFileOpenStateMachineClient *m_pClient; + KeyValues *m_pContextKeyValues; + FOSMState_t m_CurrentState; + CompletionState_t m_CompletionState; + CUtlString m_FileName; + CUtlString m_SaveFileType; + CUtlString m_OpenFileType; + CUtlString m_OpenFileName; + bool m_bShowPerforceDialogs : 1; + bool m_bShowSaveQuery : 1; + bool m_bIsOpeningFile : 1; + bool m_bWroteFile : 1; +}; + +} // end namespace vgui + + + +#endif // FILEOPENSTATEMACHINE_H diff --git a/public/vgui_controls/FocusNavGroup.h b/public/vgui_controls/FocusNavGroup.h new file mode 100644 index 0000000..2d74351 --- /dev/null +++ b/public/vgui_controls/FocusNavGroup.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FOCUSNAVGROUP_H +#define FOCUSNAVGROUP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class Panel; + +//----------------------------------------------------------------------------- +// Purpose: Handles navigation through a set of panels, with tab order & hotkeys +//----------------------------------------------------------------------------- +class FocusNavGroup +{ +public: + FocusNavGroup(Panel *panel); + ~FocusNavGroup(); + virtual Panel *GetDefaultPanel(); // returns a pointer to the panel with the default focus + + virtual void SetDefaultButton(Panel *panel); // sets which panel should receive input when ENTER is hit + virtual VPANEL GetDefaultButton(); // panel which receives default input when ENTER is hit, if current focused item cannot accept ENTER + virtual VPANEL GetCurrentDefaultButton(); // panel which receives input when ENTER is hit + virtual Panel *FindPanelByHotkey(wchar_t key); // finds the panel which is activated by the specified key + virtual bool RequestFocusPrev(VPANEL panel = NULL); // if panel is NULL, then the tab increment is based last known panel that had key focus + virtual bool RequestFocusNext(VPANEL panel = NULL); + + virtual Panel *GetCurrentFocus(); + virtual VPANEL SetCurrentFocus(VPANEL panel, VPANEL defaultPanel); // returns the Default panel + + // sets the panel that owns this FocusNavGroup to be the root in the focus traversal heirarchy + // focus change via KEY_TAB will only travel to children of this main panel + virtual void SetFocusTopLevel(bool state); + + virtual void SetCurrentDefaultButton(VPANEL panel, bool sendCurrentDefaultButtonMessage = true); +private: + bool CanButtonBeDefault(VPANEL panel); + + VPanelHandle _defaultButton; + VPanelHandle _currentDefaultButton; + VPanelHandle _currentFocus; + + Panel *_mainPanel; + bool _topLevelFocus; +}; + +} // namespace vgui + +#endif // FOCUSNAVGROUP_H diff --git a/public/vgui_controls/Frame.h b/public/vgui_controls/Frame.h new file mode 100644 index 0000000..0485a37 --- /dev/null +++ b/public/vgui_controls/Frame.h @@ -0,0 +1,260 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUI_FRAME_H +#define VGUI_FRAME_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include + +namespace vgui +{ + +class FrameButton; +class FrameSystemButton; + +//----------------------------------------------------------------------------- +// Purpose: Windowed frame +//----------------------------------------------------------------------------- +class Frame : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( Frame, EditablePanel ); + +public: + Frame(Panel *parent, const char *panelName, bool showTaskbarIcon = true, bool bPopup = true ); + virtual ~Frame(); + + // Set the text in the title bar. Set surfaceTitle=true if you want this to be the taskbar text as well. + virtual void SetTitle(const char *title, bool surfaceTitle); + virtual void SetTitle(const wchar_t *title, bool surfaceTitle); + + // Bring the frame to the front and requests focus, ensures it's not minimized + virtual void Activate(); + + // activates the dialog; if dialog is not currently visible it starts it minimized and flashing in the taskbar + virtual void ActivateMinimized(); + + // closes the dialog + MESSAGE_FUNC( Close, "Close" ); + MESSAGE_FUNC( CloseModal, "CloseModal" ); + + // sets the dialog to delete self on close + virtual void SetDeleteSelfOnClose( bool state ); + + // Move the dialog to the center of the screen + virtual void MoveToCenterOfScreen(); + + // Set the movability of the panel + virtual void SetMoveable(bool state); + // Check the movability of the panel + virtual bool IsMoveable(); + + // Set the resizability of the panel + virtual void SetSizeable(bool state); + // Check the resizability of the panel + virtual bool IsSizeable(); + // Toggle visibility of the system menu button + virtual void SetMenuButtonVisible(bool state); + void SetMenuButtonResponsive(bool state); + + // Toggle visibility of the minimize button + virtual void SetMinimizeButtonVisible(bool state); + // Toggle visibility of the maximize button + virtual void SetMaximizeButtonVisible(bool state); + // Toggles visibility of the minimize-to-systray icon (defaults to false) + virtual void SetMinimizeToSysTrayButtonVisible(bool state); + + // Toggle visibility of the close button + virtual void SetCloseButtonVisible(bool state); + + // returns true if the dialog is currently minimized + virtual bool IsMinimized(); + // Flash the window system tray button until the frame gets focus + virtual void FlashWindow(); + // Stops any window flashing + virtual void FlashWindowStop(); + // command handling + virtual void OnCommand(const char *command); + + // Get the system menu + virtual Menu *GetSysMenu(); + // Set the system menu + virtual void SetSysMenu(Menu *menu); + + // Set the system menu images + void SetImages( const char *pEnabledImage, const char *pDisabledImage = NULL ); + + // set whether the title bar should be rendered + virtual void SetTitleBarVisible( bool state ); + + // When moving via caption, don't let any part of window go outside parent's bounds + virtual void SetClipToParent( bool state ); + virtual bool GetClipToParent() const; + + // Set to true to make the caption height small + virtual void SetSmallCaption( bool state ); + virtual bool IsSmallCaption() const; + + virtual int GetDraggerSize(); + virtual int GetCornerSize(); + virtual int GetBottomRightSize(); + virtual int GetCaptionHeight(); + + /* CUSTOM MESSAGE HANDLING + "SetTitle" + input: "text" - string to set the title to be + */ + + // Load the control settings + virtual void LoadControlSettings( const char *dialogResourceName, const char *pathID = NULL, KeyValues *pPreloadedKeyValues = NULL, KeyValues *pConditions = NULL ); + + void SetChainKeysToParent( bool state ); + bool CanChainKeysToParent() const; + + // Shows the dialog in a modal fashion + virtual void DoModal(); + + void PlaceUnderCursor( ); + + // Disables the fade-in/out-effect even if configured in the scheme settings + void DisableFadeEffect( void ); + + // Temporarily enables or disables the fade effect rather than zeroing the fade times as done in DisableFadeEffect + void SetFadeEffectDisableOverride( bool disabled ); + +protected: + // Respond to mouse presses + virtual void OnMousePressed(MouseCode code); + // Respond to Key typing + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + // Respond to Key releases + virtual void OnKeyCodeReleased(KeyCode code); + // Respond to Key focus ticks + virtual void OnKeyFocusTicked(); + virtual void ApplySchemeSettings(IScheme *pScheme); + // Recalculate the position of all items + virtual void PerformLayout(); + // Respond when a close message is recieved. Can be called directly to close a frame. + virtual void OnClose(); + // Respond to a window finishing its closure. i.e. when a fading window has fully finished its fadeout. + virtual void OnFinishedClose(); + // Minimize the window on the taskbar. + MESSAGE_FUNC( OnMinimize, "Minimize" ); + // Called when minimize-to-systray button is pressed (does nothing by default) + virtual void OnMinimizeToSysTray(); + // the frame close button was pressed + MESSAGE_FUNC( OnCloseFrameButtonPressed, "CloseFrameButtonPressed" ); + // Add the child to the focus nav group + virtual void OnChildAdded(VPANEL child); + // settings + virtual void ApplySettings(KeyValues *inResourceData); + // records the settings into the resource data + virtual void GetSettings(KeyValues *outResourceData); + virtual const char *GetDescription( void ); + + // gets the default position and size on the screen to appear the first time (defaults to centered) + virtual bool GetDefaultScreenPosition(int &x, int &y, int &wide, int &tall); + + // painting + virtual void PaintBackground(); + + // per-frame thinking, used for transition effects + virtual void OnThink(); + + // screen size + virtual void OnScreenSizeChanged(int iOldWide, int iOldTall); + + // Get the size of the panel inside the frame edges. + virtual void GetClientArea(int &x, int &y, int &wide, int &tall); + + // user configuration settings + // this is used for any control details the user wants saved between sessions + // eg. dialog positions, last directory opened, list column width + virtual void ApplyUserConfigSettings(KeyValues *userConfig); + + // returns user config settings for this control + virtual void GetUserConfigSettings(KeyValues *userConfig); + + // optimization, return true if this control has any user config settings + virtual bool HasUserConfigSettings(); + +private: + MESSAGE_FUNC_CHARPTR( InternalSetTitle, "SetTitle", text ); + MESSAGE_FUNC( InternalFlashWindow, "FlashWindow" ); + MESSAGE_FUNC_PARAMS( OnDialogVariablesChanged, "DialogVariables", dialogVariables ); + + void SetupResizeCursors(); + void LayoutProportional( FrameButton *bt); + void FinishClose(); + void OnFrameFocusChanged(bool bHasFocus); + + Color _titleBarBgColor; + Color _titleBarDisabledBgColor; + Color _titleBarFgColor; + Color _titleBarDisabledFgColor; + Color m_InFocusBgColor; + Color m_OutOfFocusBgColor; + TextImage *_title; + +#if !defined( _X360 ) + Panel *_topGrip; + Panel *_bottomGrip; + Panel *_leftGrip; + Panel *_rightGrip; + Panel *_topLeftGrip; + Panel *_topRightGrip; + Panel *_bottomLeftGrip; + Panel *_bottomRightGrip; + Panel *_captionGrip; + FrameButton *_minimizeButton; + FrameButton *_maximizeButton; + FrameButton *_minimizeToSysTrayButton; + FrameButton *_closeButton; + FrameSystemButton *_menuButton; + Menu *_sysMenu; +#endif + + float m_flTransitionEffectTime; + float m_flFocusTransitionEffectTime; + int m_iClientInsetX; + int m_iClientInsetY; + int m_iTitleTextInsetX; + int m_nGripperWidth; + VPANEL m_hPreviousModal; + HFont m_hCustomTitleFont; + + bool _sizeable : 1; + bool _moveable : 1; + bool m_bHasFocus : 1; + bool _flashWindow : 1; + bool _nextFlashState : 1; + bool _drawTitleBar : 1; + bool m_bPreviouslyVisible : 1; + bool m_bFadingOut : 1; + bool m_bDeleteSelfOnClose : 1; + bool m_bDisableFadeEffect : 1; + bool m_bClipToParent : 1; + bool m_bSmallCaption : 1; + bool m_bChainKeysToParent : 1; + bool m_bPrimed : 1; + bool m_iClientInsetXOverridden : 1; + + CPanelAnimationVarAliasType( int, m_iTitleTextInsetXOverride, "titletextinsetX", "0", "proportional_int" ); + CPanelAnimationVar( int, m_iTitleTextInsetYOverride, "titletextinsetY", "0" ); +}; + +} // namespace vgui + +#endif // VGUI_FRAME_H diff --git a/public/vgui_controls/GraphPanel.h b/public/vgui_controls/GraphPanel.h new file mode 100644 index 0000000..e2c2bfe --- /dev/null +++ b/public/vgui_controls/GraphPanel.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GRAPHPANEL_H +#define GRAPHPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "utllinkedlist.h" +#include "utlvector.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Holds and displays a chart +//----------------------------------------------------------------------------- +class GraphPanel : public Panel +{ + DECLARE_CLASS_SIMPLE( GraphPanel, Panel ); + +public: + GraphPanel(Panel *parent, const char *name); + + // domain settings (x-axis settings) + // sets the window of samples to display + void SetDisplayDomainSize(float size); + // sets the range of samples the graph should keep + // should be set to the max you would set the display domain size + void SetMaxDomainSize(float size); + // sets the minimum domain that will be displayed; used to collapse samples + void SetMinDomainSize(float size); + + // range settings (y-axis settings) + void SetUseFixedRange(float lowRange, float highRange); + void SetUseDynamicRange(float *rangeList, int numRanges); + void GetDisplayedRange(float &lowRange, float &highRange); + + // adds an item to the end of the list + // sampleEnd is assumed to be the trailing edge of the sample + // assumes that the samples are fairly evenly spaced (not much more work to do to fix this though) + void AddItem(float sampleEnd, float sampleValue); + +protected: + virtual void Paint(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + +private: + int GetVisibleItemCount(); + + struct Sample_t + { + float sampleEnd; + float value; + }; + CUtlLinkedList m_Samples; + + // the window to show + float m_flDomainSize; + float m_flMaxDomainSize, m_flMinDomainSize; + bool m_bMaxDomainSizeSet; + + // range + float m_flLowRange, m_flHighRange; + bool m_bUseDynamicRange; + CUtlVector m_RangeList; + + // rendering + int m_iGraphBarWidth; + int m_iGraphBarGapWidth; +}; + +} // namespace vgui + +#endif // GRAPHPANEL_H diff --git a/public/vgui_controls/HTML.h b/public/vgui_controls/HTML.h new file mode 100644 index 0000000..ad786d2 --- /dev/null +++ b/public/vgui_controls/HTML.h @@ -0,0 +1,323 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Creates a HTML control +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HTML_H +#define HTML_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifndef VERSION_SAFE_STEAM_API_INTERFACES +#define VERSION_SAFE_STEAM_API_INTERFACES +#endif +#include "steam/steam_api.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Control to display HTML content +// This control utilises a hidden IE window to render a HTML page for you. +// It can load any valid URL (i.e local files or web pages), you cannot dynamically change the +// content however (internally to the control that is). +//----------------------------------------------------------------------------- +class HTML: public Panel +{ + DECLARE_CLASS_SIMPLE( HTML, Panel ); + // TODO::STYLE + //DECLARE_STYLE_BASE( "HTML" ); +public: + + HTML(Panel *parent,const char *name, bool allowJavaScript = false, bool bPopupWindow = false); + ~HTML(); + + // IHTML pass through functions + virtual void OpenURL( const char *URL, const char *pchPostData, bool bForce = false ); + virtual bool StopLoading(); + virtual bool Refresh(); + virtual void OnMove(); + virtual void RunJavascript( const char *pchScript ); + virtual void GoBack(); + virtual void GoForward(); + virtual bool BCanGoBack(); + virtual bool BCanGoFoward(); + + // event functions you can override and specialize behavior of + virtual bool OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect ); + virtual void OnFinishRequest(const char *url, const char *pageTitle, const CUtlMap < CUtlString, CUtlString > &headers ) {} + virtual void OnSetHTMLTitle( const char *pchTitle ) {} + virtual void OnLinkAtPosition( const char *pchURL ) {} + virtual void OnURLChanged( const char *url, const char *pchPostData, bool bIsRedirect ) {} + + virtual bool OnOpenNewTab( const char *pchURL, bool bForeground ) { return false; } + + // configuration + virtual void SetScrollbarsEnabled(bool state); + virtual void SetContextMenuEnabled(bool state); + virtual void SetViewSourceEnabled( bool state ); + virtual void NewWindowsOnly( bool state ); + + bool IsScrolledToBottom(); + bool IsScrollbarVisible(); + + // url handlers, lets you have web page links fire vgui events + // use to have custom web page links, eg. "steam://open/subscriptionpage" + // message contains "CustomURL", "url" + virtual void AddCustomURLHandler(const char *customProtocolName, vgui::Panel *target); + + // overridden to paint our special web browser texture + virtual void Paint(); + + // pass messages to the texture component to tell it about resizes + virtual void OnSizeChanged(int wide,int tall); + + // pass mouse clicks through + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + virtual void OnCursorMoved(int x,int y); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnKeyTyped(wchar_t unichar); + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyCodeReleased(KeyCode code); + virtual void PerformLayout(); + virtual void OnMouseWheeled(int delta); + virtual void PostChildPaint(); + + /* message posting: + + "HTMLSliderMoved" - indicates the scrollbar has moved + + "OnURLChanged" - indicates a new URL is being loaded + "url" + "postdata" + + "OnFinishRequest" - indicates all url loaded has completed + + "HTMLBackRequested" - mouse4 has been pressed on the dialog + "HTMLForwardRequested" - mouse5 has been pressed on the dialog + + "SecurityStatus" - indicates the SSL status of the page (disabled,good,bad) + "url" + "secure" - true if an ssl page + "certerror" - true if there is a cert error loading the page + "isevcert" - true if this is an EV style cert + "certname" - name of the entity this cert is issued to + */ + + MESSAGE_FUNC_INT( OnSetCursorVGUI, "SetCursor", cursor ); + + virtual void OnCommand( const char *pchCommand ); + + void AddHeader( const char *pchHeader, const char *pchValue ); + void OnKillFocus(); + void OnSetFocus(); + + void Find( const char *pchSubStr ); + void StopFind(); + void FindNext(); + void FindPrevious(); + void ShowFindDialog(); + void HideFindDialog(); + bool FindDialogVisible(); + int HorizontalScrollMax() { return m_scrollHorizontal.m_nMax; } + int VerticalScrollMax() { return m_scrollVertical.m_nMax; } + + void GetLinkAtPosition( int x, int y ); + + void HidePopup(); + +#ifdef DBGFLAG_VALIDATE + virtual void Validate( CValidator &validator, const char *pchName ) + { + ValidateObj( m_CustomURLHandlers ); + BaseClass::Validate( validator, pchName ); + } +#endif // DBGFLAG_VALIDATE + + ISteamHTMLSurface *SteamHTMLSurface() { return m_SteamAPIContext.SteamHTMLSurface(); } + + void OnHTMLMouseMoved( int x, int y ) + { + if ( m_SteamAPIContext.SteamHTMLSurface() ) + m_SteamAPIContext.SteamHTMLSurface()->MouseMove( m_unBrowserHandle, x, y ); + } + +protected: + virtual void ApplySchemeSettings( IScheme *pScheme ); + + vgui::Menu *m_pContextMenu; + +private: + STEAM_CALLBACK( HTML, BrowserNeedsPaint, HTML_NeedsPaint_t, m_NeedsPaint ); + STEAM_CALLBACK( HTML, BrowserStartRequest, HTML_StartRequest_t, m_StartRequest ); + STEAM_CALLBACK( HTML, BrowserURLChanged, HTML_URLChanged_t, m_URLChanged ); + STEAM_CALLBACK( HTML, BrowserFinishedRequest, HTML_FinishedRequest_t, m_FinishedRequest ); + STEAM_CALLBACK( HTML, BrowserOpenNewTab, HTML_OpenLinkInNewTab_t, m_LinkInNewTab ); + STEAM_CALLBACK( HTML, BrowserSetHTMLTitle, HTML_ChangedTitle_t, m_ChangeTitle ); + STEAM_CALLBACK( HTML, BrowserPopupHTMLWindow, HTML_NewWindow_t, m_NewWindow ); + STEAM_CALLBACK( HTML, BrowserFileLoadDialog, HTML_FileOpenDialog_t, m_FileLoadDialog ); + STEAM_CALLBACK( HTML, BrowserSearchResults, HTML_SearchResults_t, m_SearchResults ); + STEAM_CALLBACK( HTML, BrowserClose, HTML_CloseBrowser_t, m_CloseBrowser ); + STEAM_CALLBACK( HTML, BrowserHorizontalScrollBarSizeResponse, HTML_HorizontalScroll_t, m_HorizScroll ); + STEAM_CALLBACK( HTML, BrowserVerticalScrollBarSizeResponse, HTML_VerticalScroll_t, m_VertScroll ); + STEAM_CALLBACK( HTML, BrowserLinkAtPositionResponse, HTML_LinkAtPosition_t, m_LinkAtPosResp ); + STEAM_CALLBACK( HTML, BrowserJSAlert, HTML_JSAlert_t, m_JSAlert ); + STEAM_CALLBACK( HTML, BrowserJSConfirm, HTML_JSConfirm_t, m_JSConfirm ); + STEAM_CALLBACK( HTML, BrowserCanGoBackandForward, HTML_CanGoBackAndForward_t, m_CanGoBackForward ); + STEAM_CALLBACK( HTML, BrowserSetCursor, HTML_SetCursor_t, m_SetCursor ); + STEAM_CALLBACK( HTML, BrowserStatusText, HTML_StatusText_t, m_StatusText ); + STEAM_CALLBACK( HTML, BrowserShowToolTip, HTML_ShowToolTip_t, m_ShowTooltip ); + STEAM_CALLBACK( HTML, BrowserUpdateToolTip, HTML_UpdateToolTip_t, m_UpdateTooltip ); + STEAM_CALLBACK( HTML, BrowserHideToolTip, HTML_HideToolTip_t, m_HideTooltip ); + + void OnBrowserReady( HTML_BrowserReady_t *pBrowserReady, bool bIOFailure ); + + void PostURL(const char *URL, const char *pchPostData, bool force); + virtual void BrowserResize(); + void UpdateSizeAndScrollBars(); + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); + MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); + MESSAGE_FUNC( OnFileSelectionCancelled, "FileSelectionCancelled" ); + MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel ); + MESSAGE_FUNC_PTR( OnEditNewLine, "TextNewLine", panel ); + MESSAGE_FUNC_INT( DismissJSDialog, "DismissJSDialog", result ); + + vgui::Panel *m_pInteriorPanel; + vgui::ScrollBar *_hbar,*_vbar; + vgui::DHANDLE m_hFileOpenDialog; + class CHTMLFindBar : public vgui::EditablePanel + { + DECLARE_CLASS_SIMPLE( CHTMLFindBar, EditablePanel ); + public: + CHTMLFindBar( HTML *parent ); + void SetText( const char *pchText ) { m_pFindBar->SetText( pchText ); } + void GetText( char *pText, int ccText ) { m_pFindBar->GetText( pText, ccText ); } + void OnCommand( const char *pchCmd ); + void ShowCountLabel() { m_pFindCountLabel->SetVisible( true ); } + void HideCountLabel() { m_pFindCountLabel->SetVisible( false ); } + void SetHidden( bool bState ) { m_bHidden = bState; } + bool BIsHidden() { return m_bHidden; } + + private: + vgui::TextEntry *m_pFindBar; + vgui::HTML *m_pParent; + vgui::Label *m_pFindCountLabel; + bool m_bHidden; + }; + + CHTMLFindBar *m_pFindBar; + + int m_iMouseX,m_iMouseY; // where the mouse is on the control + + int m_iScrollBorderX,m_iScrollBorderY; + int m_iWideLastHTMLSize, m_iTalLastHTMLSize; + int m_iCopyLinkMenuItemID; + + bool m_bScrollBarEnabled; + bool m_bContextMenuEnabled; + int m_iScrollbarSize; + bool m_bNewWindowsOnly; + int m_nViewSourceAllowedIndex; + CUtlString m_sDragURL; + int m_iDragStartX, m_iDragStartY; + + struct CustomURLHandler_t + { + PHandle hPanel; + char url[32]; + }; + CUtlVector m_CustomURLHandlers; + + int m_iHTMLTextureID; // vgui texture id + // Track the texture width and height requested so we can tell + // when the size has changed and reallocate the texture. + int m_allocedTextureWidth; + int m_allocedTextureHeight; + bool m_bNeedsFullTextureUpload; + CUtlString m_sCurrentURL; // the url of our current page + // find in page state + bool m_bInFind; + CUtlString m_sLastSearchString; + + bool m_bCanGoBack; // cache of forward and back state + bool m_bCanGoForward; + + struct LinkAtPos_t + { + LinkAtPos_t() { m_nX = m_nY = 0; } + uint32 m_nX; + uint32 m_nY; + CUtlString m_sURL; + }; + LinkAtPos_t m_LinkAtPos; // cache for link at pos requests, because the request is async + bool m_bRequestingDragURL; // true if we need a response for a drag url loc + bool m_bRequestingCopyLink; // true if we wanted to copy the link under the cursor + + struct ScrollData_t + { + ScrollData_t() + { + m_bVisible = false; + m_nMax = m_nScroll = 0; + } + + bool operator==( ScrollData_t const &src ) const + { + return m_bVisible == src.m_bVisible && + m_nMax == src.m_nMax && + m_nScroll == src.m_nScroll; + } + + bool operator!=( ScrollData_t const &src ) const + { + return !operator==(src); + } + + + bool m_bVisible; // is the scroll bar visible + int m_nMax; // most amount of pixels we can scroll + int m_nScroll; // currently scrolled amount of pixels + float m_flZoom; // zoom level this scroll bar is for + }; + + ScrollData_t m_scrollHorizontal; // details of horizontal scroll bar + ScrollData_t m_scrollVertical; // details of vertical scroll bar + float m_flZoom; // current page zoom level + + CUtlString m_sPendingURLLoad; // cache of url to load if we get a PostURL before the cef object is mage + CUtlString m_sPendingPostData; // cache of the post data for above + + struct CustomCursorCache_t + { + CustomCursorCache_t() {} + CustomCursorCache_t( const void *pchData ) { m_pchData = pchData; } + float m_CacheTime; // the time we cached the cursor + CursorCode m_Cursor; // the vgui handle to it + const void *m_pchData; // the pointer to the cursor char data so we can detect the same cursor being used + bool operator==(const CustomCursorCache_t& rhs) const + { + return m_pchData == rhs.m_pchData ; + } + }; + CUtlVector m_vecHCursor; + + CSteamAPIContext m_SteamAPIContext; + HHTMLBrowser m_unBrowserHandle; + CCallResult< HTML, HTML_BrowserReady_t > m_SteamCallResultBrowserReady; +}; + +} // namespace vgui + +#endif // HTML_H diff --git a/public/vgui_controls/Image.h b/public/vgui_controls/Image.h new file mode 100644 index 0000000..9ed128e --- /dev/null +++ b/public/vgui_controls/Image.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMAGE_H +#define IMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class Panel; + +//----------------------------------------------------------------------------- +// Purpose: Basic image control +//----------------------------------------------------------------------------- +class Image : public IImage +{ +public: + Image(); + virtual ~Image(); + + // Set the position of the image + virtual void SetPos( int x, int y ); + // Get the position of the image + virtual void GetPos( int &x, int &y ); + // Get the size of the image + virtual void GetSize( int &wide, int &tall ); + virtual void GetContentSize( int &wide, int &tall ); + // Set the draw color + virtual void SetColor( Color color ); + // set the background color + virtual void SetBkColor( Color color ) { DrawSetColor( color ); } + // Get the draw color + virtual Color GetColor(); + virtual bool Evict(); + virtual int GetNumFrames(); + virtual void SetFrame( int nFrame ); + virtual HTexture GetID(); + virtual void SetRotation( int iRotation ) { return; }; + +protected: + virtual void SetSize(int wide, int tall); + virtual void DrawSetColor(Color color); + virtual void DrawSetColor(int r, int g, int b, int a); + virtual void DrawFilledRect(int x0, int y0, int x1, int y1); + virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1); + virtual void DrawLine(int x0,int y0,int x1,int y1); + virtual void DrawPolyLine(int *px, int *py, int numPoints); + virtual void DrawSetTextFont(HFont font); + virtual void DrawSetTextColor(Color color); + virtual void DrawSetTextColor(int r, int g, int b, int a); + virtual void DrawSetTextPos(int x,int y); + virtual void DrawPrintText(const wchar_t *str, int strlen); + virtual void DrawPrintText(int x, int y, const wchar_t *str, int strlen); + virtual void DrawPrintChar(wchar_t ch); + virtual void DrawPrintChar(int x, int y, wchar_t ch); + virtual void DrawSetTexture(int id); + virtual void DrawTexturedRect(int x0, int y0, int x1, int y1); + virtual void Paint() = 0; + +private: + int _pos[2]; + int _size[2]; + Color _color; +}; + +} // namespace vgui + +#endif // IMAGE_H diff --git a/public/vgui_controls/ImageList.h b/public/vgui_controls/ImageList.h new file mode 100644 index 0000000..db9ec63 --- /dev/null +++ b/public/vgui_controls/ImageList.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMAGELIST_H +#define IMAGELIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: holds a collection of images +// used by controls so that images can be refered to by indices +//----------------------------------------------------------------------------- +class ImageList +{ +public: + ImageList(bool deleteImagesWhenDone); + ~ImageList(); + + // adds a new image to the list, returning the index it was placed at + int AddImage(vgui::IImage *image); + + // returns the number of images + int GetImageCount(); + + // returns true if an index is valid + bool IsValidIndex(int imageIndex); + + // sets an image at a specified index, growing and adding NULL images if necessary + void SetImageAtIndex(int index, vgui::IImage *image); + + // gets an image, imageIndex is of range [0, GetImageCount) + // image index 0 is always the blank image + vgui::IImage *GetImage(int imageIndex); + +private: + CUtlVector m_Images; + bool m_bDeleteImagesWhenDone; +}; + + +} // namespace vgui + +#endif // IMAGELIST_H diff --git a/public/vgui_controls/ImagePanel.h b/public/vgui_controls/ImagePanel.h new file mode 100644 index 0000000..bba8f88 --- /dev/null +++ b/public/vgui_controls/ImagePanel.h @@ -0,0 +1,92 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMAGEPANEL_H +#define IMAGEPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class IImage; + +//----------------------------------------------------------------------------- +// Purpose: Panel that holds a single image +//----------------------------------------------------------------------------- +class ImagePanel : public Panel +{ + DECLARE_CLASS_SIMPLE( ImagePanel, Panel ); +public: + ImagePanel(Panel *parent, const char *name); + ~ImagePanel(); + + virtual void SetImage(IImage *image); + virtual void SetImage(const char *imageName); + virtual IImage *GetImage(); + char *GetImageName(); + + void SetShouldCenterImage( bool state ) { m_bCenterImage = state; } + bool GetShouldCenterImage() const { return m_bCenterImage; } + + // sets whether or not the image should scale to fit the size of the ImagePanel (defaults to false) + void SetShouldScaleImage( bool state ); + bool GetShouldScaleImage(); + void SetScaleAmount( float scale ); + float GetScaleAmount( void ); + + void SetTileImage( bool bTile ) { m_bTileImage = bTile; } + + // set the color to fill with, if no image is specified + void SetFillColor( Color col ); + Color GetFillColor(); + + virtual Color GetDrawColor( void ); + virtual void SetDrawColor( Color drawColor ); + + virtual void ApplySettings(KeyValues *inResourceData); + + // unhooks and evicts image if possible, caller must re-establish + bool EvictImage(); + + int GetNumFrames(); + void SetFrame( int nFrame ); + + void SetRotation( int iRotation ) { m_iRotation = iRotation; } + +protected: + virtual void PaintBackground(); + virtual void GetSettings(KeyValues *outResourceData); + virtual const char *GetDescription(); + virtual void OnSizeChanged(int newWide, int newTall); + virtual void ApplySchemeSettings( IScheme *pScheme ); + +private: + IImage *m_pImage; + char *m_pszImageName; + char *m_pszFillColorName; + char *m_pszDrawColorName; + bool m_bPositionImage; + bool m_bCenterImage; + bool m_bScaleImage; + bool m_bTileImage; + bool m_bTileHorizontally; + bool m_bTileVertically; + float m_fScaleAmount; + Color m_FillColor; + Color m_DrawColor; + int m_iRotation; +}; + +} // namespace vgui + +#endif // IMAGEPANEL_H diff --git a/public/vgui_controls/InputDialog.h b/public/vgui_controls/InputDialog.h new file mode 100644 index 0000000..00b8d6f --- /dev/null +++ b/public/vgui_controls/InputDialog.h @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef INPUTDIALOG_H +#define INPUTDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class Label; +class Button; +class TextEntry; + + +//----------------------------------------------------------------------------- +// Purpose: Utility dialog base class - just has context kv and ok/cancel buttons +//----------------------------------------------------------------------------- +class BaseInputDialog : public Frame +{ + DECLARE_CLASS_SIMPLE( BaseInputDialog, Frame ); + +public: + BaseInputDialog( vgui::Panel *parent, const char *title ); + ~BaseInputDialog(); + + void DoModal( KeyValues *pContextKeyValues = NULL ); + +protected: + virtual void PerformLayout(); + virtual void PerformLayout( int x, int y, int w, int h ) {} + + // command buttons + virtual void OnCommand( const char *command ); + + void CleanUpContextKeyValues(); + KeyValues *m_pContextKeyValues; + +private: + vgui::Button *m_pCancelButton; + vgui::Button *m_pOKButton; +}; + +//----------------------------------------------------------------------------- +// Purpose: Utility dialog, used to ask yes/no questions of the user +//----------------------------------------------------------------------------- +class InputMessageBox : public BaseInputDialog +{ + DECLARE_CLASS_SIMPLE( InputMessageBox, BaseInputDialog ); + +public: + InputMessageBox( vgui::Panel *parent, const char *title, char const *prompt ); + ~InputMessageBox(); + +protected: + virtual void PerformLayout( int x, int y, int w, int h ); + +private: + vgui::Label *m_pPrompt; +}; + +//----------------------------------------------------------------------------- +// Purpose: Utility dialog, used to let user type in some text +//----------------------------------------------------------------------------- +class InputDialog : public BaseInputDialog +{ + DECLARE_CLASS_SIMPLE( InputDialog, BaseInputDialog ); + +public: + InputDialog( vgui::Panel *parent, const char *title, char const *prompt, char const *defaultValue = "" ); + ~InputDialog(); + + void SetMultiline( bool state ); + + /* action signals + + "InputCompleted" + "text" - the text entered + + "InputCanceled" + */ + void AllowNumericInputOnly( bool bOnlyNumeric ); + +protected: + virtual void PerformLayout( int x, int y, int w, int h ); + + // command buttons + virtual void OnCommand(const char *command); + +private: + vgui::Label *m_pPrompt; + vgui::TextEntry *m_pInput; +}; + +} // namespace vgui + + +#endif // INPUTDIALOG_H diff --git a/public/vgui_controls/KeyBindingHelpDialog.h b/public/vgui_controls/KeyBindingHelpDialog.h new file mode 100644 index 0000000..3e4d0ed --- /dev/null +++ b/public/vgui_controls/KeyBindingHelpDialog.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef KEYBINDINGHELPDIALOG_H +#define KEYBINDINGHELPDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Frame.h" +#include "vgui/KeyCode.h" + +namespace vgui +{ + +class ListPanel; +class CKeyBoardEditorDialog; + +//----------------------------------------------------------------------------- +// Purpose: Dialog for use in editing keybindings +//----------------------------------------------------------------------------- +class CKeyBindingHelpDialog : public Frame +{ + DECLARE_CLASS_SIMPLE( CKeyBindingHelpDialog, Frame ); + +public: + CKeyBindingHelpDialog( Panel *parent, Panel *panelToView, KeyBindingContextHandle_t handle, KeyCode code, int modifiers ); + ~CKeyBindingHelpDialog(); + + virtual void OnCommand( char const *cmd ); + virtual void OnKeyCodeTyped(vgui::KeyCode code); + + // The key originally bound to help was pressed + void HelpKeyPressed(); +private: + + virtual void OnTick(); + + bool IsHelpKeyStillBeingHeld(); + + void PopulateList(); + void GetMappingList( Panel *panel, CUtlVector< PanelKeyBindingMap * >& maps ); + + void AnsiText( char const *token, char *out, size_t buflen ); + + vgui::PHandle m_hPanel; + KeyBindingContextHandle_t m_Handle; + KeyCode m_KeyCode; + int m_Modifiers; + + ListPanel *m_pList; + double m_flShowTime; + bool m_bPermanent; + + DHANDLE< CKeyBoardEditorDialog > m_hKeyBindingsEditor; +}; + +} + +#endif // KEYBINDINGHELPDIALOG_H diff --git a/public/vgui_controls/KeyBindingMap.h b/public/vgui_controls/KeyBindingMap.h new file mode 100644 index 0000000..16641c7 --- /dev/null +++ b/public/vgui_controls/KeyBindingMap.h @@ -0,0 +1,225 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef KEYBINDINGMAP_H +#define KEYBINDINGMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" + +// more flexible than default pointers to members code required for casting member function pointers +//#pragma pointers_to_members( full_generality, virtual_inheritance ) + +namespace vgui +{ + +class Panel; + +enum +{ + MODIFIER_SHIFT = ( 1 << 0 ), + MODIFIER_CONTROL = ( 1 << 1 ), + MODIFIER_ALT = ( 1 << 2 ), +}; + +//----------------------------------------------------------------------------- +// Purpose: An actual keybinding, where bindingname references a bindingmap mentioned below +//----------------------------------------------------------------------------- +struct BoundKey_t +{ + BoundKey_t(); + BoundKey_t( const BoundKey_t& src ); + ~BoundKey_t(); + BoundKey_t& operator =( const BoundKey_t& src ); + + bool isbuiltin; // whether this was by the #DECLARE macros or via code/parsing a config file + char const *bindingname; // what it's bound to + int keycode; // vgui keycode + int modifiers; // which modifiers +}; + +//----------------------------------------------------------------------------- +// Purpose: Single item in a message map +// Contains the information to map a string message name with parameters +// to a function call +//----------------------------------------------------------------------------- +struct KeyBindingMap_t +{ + KeyBindingMap_t(); + KeyBindingMap_t( const KeyBindingMap_t& src ); + ~KeyBindingMap_t(); + + char const *bindingname; // for the script file + ALIGN16 MessageFunc_t func; + char const *helpstring; // e.g., #KeybindingPasteHelp + char const *docstring; // e.g., #KeybindingPasteHelp + bool passive; // dispatch command, but still chain +}; + +#define DECLARE_KEYBINDINGMAP( className ) \ + static void KB_AddToMap \ + ( \ + char const *bindingname, \ + vgui::KeyCode defaultcode, \ + int default_modifiers, \ + vgui::MessageFunc_t function, \ + char const *helpstring, \ + char const *docstring, \ + bool passive \ + ) \ + { \ + vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + \ + vgui::KeyBindingMap_t entry; \ + entry.bindingname = bindingname; \ + \ + entry.func = function; \ + \ + entry.helpstring = helpstring; \ + entry.docstring = docstring; \ + \ + entry.passive = passive; \ + \ + map->entries.AddToTail( entry ); \ + \ + vgui::BoundKey_t kb; \ + kb.isbuiltin = true; \ + kb.bindingname = bindingname; \ + kb.keycode = defaultcode; \ + kb.modifiers = default_modifiers; \ + map->defaultkeys.AddToTail( kb ); \ + map->boundkeys.AddToTail( kb ); \ + } \ + \ + static void KB_ChainToMap( void ) \ + { \ + static bool chained = false; \ + if ( chained ) \ + return; \ + chained = true; \ + vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + map->pfnClassName = &GetPanelClassName; \ + if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] ) \ + { \ + map->baseMap = vgui::FindOrAddPanelKeyBindingMap( GetPanelBaseClassName() ); \ + } \ + } \ + \ + static void KB_AddBoundKey \ + ( \ + char const *bindingname, \ + int keycode, \ + int modifiers \ + ) \ + { \ + vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + vgui::BoundKey_t kb; \ + kb.isbuiltin = true; \ + kb.bindingname = bindingname; \ + kb.keycode = keycode; \ + kb.modifiers = modifiers; \ + map->defaultkeys.AddToTail( kb ); \ + map->boundkeys.AddToTail( kb ); \ + } \ + \ + class className##_RegisterKBMap; \ + friend class className##_RegisterKBMap; \ + class className##_RegisterKBMap \ + { \ + public: \ + className##_RegisterKBMap() \ + { \ + className::KB_ChainToMap(); \ + } \ + }; \ + className##_RegisterKBMap m_RegisterClassKB; \ + \ + virtual vgui::PanelKeyBindingMap *GetKBMap() \ + { \ + static vgui::PanelKeyBindingMap *s_pMap = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + return s_pMap; \ + } + +#define _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, passive ) \ + class PanelKBMapFunc_##name; \ + friend class PanelKBMapFunc_##name; \ + class PanelKBMapFunc_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + KB_AddToMap( #name, keycode, modifiers, (vgui::MessageFunc_t)&ThisClass::function, help, doc, passive ); \ + } \ + } \ + PanelKBMapFunc_##name() \ + { \ + PanelKBMapFunc_##name::InitVar(); \ + } \ + }; \ + PanelKBMapFunc_##name m_##name##_register; + +#define _KBBindKeyCommon( name, keycode, modifiers, _classname ) \ + class PanelKBBindFunc_##_classname; \ + friend class PanelKBBindFunc_##_classname; \ + class PanelKBBindFunc_##_classname \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + KB_AddBoundKey( #name, keycode, modifiers ); \ + } \ + } \ + PanelKBBindFunc_##_classname() \ + { \ + PanelKBBindFunc_##_classname::InitVar(); \ + } \ + }; \ + PanelKBBindFunc_##_classname m_##_classname##_bindkey_register; + +#define KEYBINDING_FUNC( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, false ); virtual void function() +#define KEYBINDING_FUNC_NODECLARE( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, false ); +#define KEYBINDING_FUNC_PASSIVE( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, true ); virtual void function() +#define KEYBINDING_FUNC_PASSIVE_NODECLARE( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, true ); + +// For definding additional (non-default) keybindings +#define KEYBINDING_ADDBINDING( name, keycode, modifiers ) _KBBindKeyCommon( name, keycode, modifiers, name ); +#define KEYBINDING_ADDBINDING_MULTIPLE( name, keycode, modifiers, _classname ) _KBBindKeyCommon( name, keycode, modifiers, _classname ); + +// mapping, one per class +struct PanelKeyBindingMap +{ + PanelKeyBindingMap() + { + baseMap = NULL; + pfnClassName = NULL; + processed = false; + } + + CUtlVector< KeyBindingMap_t > entries; + bool processed; + PanelKeyBindingMap *baseMap; + CUtlVector< BoundKey_t > defaultkeys; + CUtlVector< BoundKey_t > boundkeys; + char const *(*pfnClassName)( void ); +}; + +PanelKeyBindingMap *FindPanelKeyBindingMap( char const *className ); +PanelKeyBindingMap *FindOrAddPanelKeyBindingMap( char const *className ); + +} // namespace vgui + + +#endif // KEYBINDINGMAP_H diff --git a/public/vgui_controls/KeyBoardEditorDialog.h b/public/vgui_controls/KeyBoardEditorDialog.h new file mode 100644 index 0000000..209c86f --- /dev/null +++ b/public/vgui_controls/KeyBoardEditorDialog.h @@ -0,0 +1,138 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef KEYBOARDEDITORDIALOG_H +#define KEYBOARDEDITORDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Frame.h" +#include "vgui_controls/PropertySheet.h" +#include "vgui_controls/PropertyPage.h" + +class VControlsListPanel; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Dialog for use in editing keybindings +//----------------------------------------------------------------------------- +class CKeyBoardEditorPage : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CKeyBoardEditorPage, EditablePanel ); + +public: + CKeyBoardEditorPage( Panel *parent, Panel *panelToEdit, KeyBindingContextHandle_t handle ); + ~CKeyBoardEditorPage(); + + void SetKeybindingsSaveFile( char const *filename, char const *pathID = 0 ); + + virtual void OnKeyCodeTyped(vgui::KeyCode code); + + virtual void ApplySchemeSettings( IScheme *scheme ); + + void OnSaveChanges(); + void OnRevert(); + void OnUseDefaults(); + +protected: + + virtual void OnPageHide(); + + virtual void OnCommand( char const *cmd ); + + void PopulateList(); + + void GetMappingList( Panel *panel, CUtlVector< PanelKeyBindingMap * >& maps ); + int GetMappingCount( Panel *panel ); + + void BindKey( vgui::KeyCode code ); + + // Trap row selection message + MESSAGE_FUNC( ItemSelected, "ItemSelected" ); + MESSAGE_FUNC_INT( OnClearBinding, "ClearBinding", item ); + + void SaveMappings(); + void UpdateCurrentMappings(); + void RestoreMappings(); + void ApplyMappings(); + +protected: + void AnsiText( char const *token, char *out, size_t buflen ); + + Panel *m_pPanel; + KeyBindingContextHandle_t m_Handle; + + VControlsListPanel *m_pList; + + struct SaveMapping_t + { + SaveMapping_t(); + SaveMapping_t( const SaveMapping_t& src ); + + PanelKeyBindingMap *map; + CUtlVector< BoundKey_t > current; + CUtlVector< BoundKey_t > original; + }; + + CUtlVector< SaveMapping_t * > m_Save; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Dialog for use in editing keybindings +//----------------------------------------------------------------------------- +class CKeyBoardEditorSheet : public PropertySheet +{ + DECLARE_CLASS_SIMPLE( CKeyBoardEditorSheet, PropertySheet ); + +public: + CKeyBoardEditorSheet( Panel *parent, Panel *panelToEdit, KeyBindingContextHandle_t handle ); + + void SetKeybindingsSaveFile( char const *filename, char const *pathID = 0 ); + + void OnSaveChanges(); + void OnRevert(); + void OnUseDefaults(); + +protected: + + vgui::PHandle m_hPanel; + KeyBindingContextHandle_t m_Handle; + bool m_bSaveToExternalFile; + CUtlSymbol m_SaveFileName; + CUtlSymbol m_SaveFilePathID; + Color m_clrAlteredItem; +}; + +//----------------------------------------------------------------------------- +// Purpose: Dialog for use in editing keybindings +//----------------------------------------------------------------------------- +class CKeyBoardEditorDialog : public Frame +{ + DECLARE_CLASS_SIMPLE( CKeyBoardEditorDialog, Frame ); + +public: + CKeyBoardEditorDialog( Panel *parent, Panel *panelToEdit, KeyBindingContextHandle_t handle ); + + void SetKeybindingsSaveFile( char const *filename, char const *pathID = 0 ); + + virtual void OnCommand( char const *cmd ); + +private: + CKeyBoardEditorSheet *m_pKBEditor; + + Button *m_pSave; + Button *m_pCancel; + Button *m_pRevert; + Button *m_pUseDefaults; +}; + +} + +#endif // KEYBOARDEDITORDIALOG_H diff --git a/public/vgui_controls/KeyRepeat.h b/public/vgui_controls/KeyRepeat.h new file mode 100644 index 0000000..83d30a3 --- /dev/null +++ b/public/vgui_controls/KeyRepeat.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef KEYREPEAT_H +#define KEYREPEAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +enum KEYREPEAT_ALIASES +{ + KR_ALIAS_UP, + KR_ALIAS_DOWN, + KR_ALIAS_LEFT, + KR_ALIAS_RIGHT, + + FM_NUM_KEYREPEAT_ALIASES, +}; + +class CKeyRepeatHandler +{ +public: + CKeyRepeatHandler() + { + Reset(); + for ( int i = 0; i < FM_NUM_KEYREPEAT_ALIASES; i++ ) + { + m_flRepeatTimes[i] = 0.16; + } + } + + void Reset( void ) { memset( m_bAliasDown, 0, sizeof(bool) * FM_NUM_KEYREPEAT_ALIASES ); m_bHaveKeyDown = false; } + void KeyDown( vgui::KeyCode code ); + void KeyUp( vgui::KeyCode code ); + vgui::KeyCode KeyRepeated( void ); + void SetKeyRepeatTime( vgui::KeyCode code, float flRepeat ); + +private: + int GetIndexForCode( vgui::KeyCode code ) + { + switch ( code ) + { + case KEY_XBUTTON_DOWN: + case KEY_XSTICK1_DOWN: + return KR_ALIAS_DOWN; break; + case KEY_XBUTTON_UP: + case KEY_XSTICK1_UP: + return KR_ALIAS_UP; break; + case KEY_XBUTTON_LEFT: + case KEY_XSTICK1_LEFT: + return KR_ALIAS_LEFT; break; + case KEY_XBUTTON_RIGHT: + case KEY_XSTICK1_RIGHT: + return KR_ALIAS_RIGHT; break; + default: + break; + } + return -1; + } + +private: + bool m_bAliasDown[FM_NUM_KEYREPEAT_ALIASES]; + float m_flRepeatTimes[FM_NUM_KEYREPEAT_ALIASES]; + float m_flNextKeyRepeat; + bool m_bHaveKeyDown; +}; + + +} // namespace vgui + +#endif // KEYREPEAT_H diff --git a/public/vgui_controls/Label.h b/public/vgui_controls/Label.h new file mode 100644 index 0000000..53422f7 --- /dev/null +++ b/public/vgui_controls/Label.h @@ -0,0 +1,225 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef LABEL_H +#define LABEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "vgui/VGUI.h" +#include "vgui_controls/Panel.h" +#include "vgui_controls/PHandle.h" + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Contains and displays a set of images +// By default starts with one TextImage +//----------------------------------------------------------------------------- +class Label : public Panel +{ + DECLARE_CLASS_SIMPLE( Label, Panel ); + +public: + // Constructors + Label(Panel *parent, const char *panelName, const char *text); + Label(Panel *parent, const char *panelName, const wchar_t *wszText); + ~Label(); + +public: + // Take the string and looks it up in the localization file to convert it to unicode + virtual void SetText(const char *tokenName); + + // Set unicode text directly + virtual void SetText(const wchar_t *unicodeString, bool bClearUnlocalizedSymbol = false ); + + // Get the current text + virtual void GetText(OUT_Z_BYTECAP(bufferLen) char *textOut, int bufferLen); + virtual void GetText(OUT_Z_BYTECAP(bufLenInBytes) wchar_t *textOut, int bufLenInBytes); + + // Content alignment + // Get the size of the content within the label + virtual void GetContentSize(int &wide, int &tall); + + // Set how the content aligns itself within the label + // alignment code, used to determine how the images are layed out within the Label + enum Alignment + { + a_northwest = 0, + a_north, + a_northeast, + a_west, + a_center, + a_east, + a_southwest, + a_south, + a_southeast, + }; + + virtual void SetContentAlignment(Alignment alignment); + virtual void SetEnabled(bool state); + // Additional offset at the Start of the text (from whichever sides it is aligned) + virtual void SetTextInset(int xInset, int yInset); + virtual void GetTextInset(int *xInset, int *yInset ); + + // Text colors + virtual void SetFgColor(Color color); + virtual Color GetFgColor(); + + // colors to use when the label is disabled + virtual void SetDisabledFgColor1(Color color); + virtual void SetDisabledFgColor2(Color color); + virtual Color GetDisabledFgColor1(); + virtual Color GetDisabledFgColor2(); + + // Set whether the text is displayed bright or dull + enum EColorState + { + CS_NORMAL, + CS_DULL, + CS_BRIGHT, + }; + virtual void SetTextColorState(EColorState state); + + // Font + virtual void SetFont(HFont font); + virtual HFont GetFont(); + + // Hotkey + virtual Panel *HasHotkey(wchar_t key); + virtual void SetHotkey(wchar_t key); + virtual wchar_t GetHotKey(); + + // Labels can be associated with controls, and alter behaviour based on the associates behaviour + // If the associate is disabled, so are we + // If the associate has focus, we may alter how we draw + // If we get a hotkey press or focus message, we forward the focus to the associate + virtual void SetAssociatedControl(Panel *control); + + // Multiple image handling + // Images are drawn from left to right across the label, ordered by index + // By default there is a TextImage in position 0 (see GetTextImage()/SetTextImageIndex()) + virtual int AddImage(IImage *image, int preOffset); // Return the index the image was placed in + virtual void SetImageAtIndex(int index, IImage *image, int preOffset); + virtual void SetImagePreOffset(int index, int preOffset); // Set the offset in pixels before the image + virtual IImage *GetImageAtIndex(int index); + virtual int GetImageCount(); + virtual void ClearImages(); + virtual void ResetToSimpleTextImage(); + // fixes the layout bounds of the image within the label + virtual void SetImageBounds(int index, int x, int width); + + // Teturns a pointer to the default text image + virtual TextImage *GetTextImage(); + + // Moves where the default text image is within the image array (it starts in position 0) + // Setting it to -1 removes it from the image list + // Returns the index the default text image was previously in + virtual int SetTextImageIndex(int newIndex); + + // Message handling + // outputData - keyName is the name of the attribute requested. + // for Labels "text" is an option that returns the default text image text + // returns true on success in finding the requested value. false on failure. + virtual bool RequestInfo(KeyValues *outputData); + /* INFO HANDLING + "GetText" + returns: + "text" - text contained in the label + */ + + /* CUSTOM MESSAGE HANDLING + "SetText" + input: "text" - label text is set to be this string + */ + + virtual void SizeToContents(); + + // the +8 is padding to the content size + // the code which uses it should really set that itself; + // however a lot of existing code relies on this + enum Padding + { + Content = 8, + }; + + void SetWrap( bool bWrap ); + void SetCenterWrap( bool bWrap ); + + void SetAllCaps( bool bAllCaps ); + +protected: + virtual void PerformLayout(); + virtual wchar_t CalculateHotkey(const char *text); + virtual wchar_t CalculateHotkey(const wchar_t *text); + virtual void ComputeAlignment(int &tx0, int &ty0, int &tx1, int &ty1); + virtual void Paint(); + MESSAGE_FUNC_PARAMS( OnSetText, "SetText", params ); + virtual void DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen); + virtual void OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel); + MESSAGE_FUNC( OnHotkeyPressed, "Hotkey" ); + virtual void OnMousePressed(MouseCode code); + virtual void OnSizeChanged(int wide, int tall); + + // makes sure that the maxIndex will be a valid index + virtual void EnsureImageCapacity(int maxIndex); + + // editing + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void GetSettings( KeyValues *outResourceData ); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual const char *GetDescription( void ); + + MESSAGE_FUNC_PARAMS( OnDialogVariablesChanged, "DialogVariables", dialogVariables ); + + void HandleAutoSizing( void ); + +private: + void Init(); + + Alignment _contentAlignment; + TextImage *_textImage; // this is the textImage, if the full text will not + // fit we put as much as we can and add an elipsis (...) + struct TImageInfo + { + IImage *image; + short offset; + short xpos; + short width; + }; + CUtlVector _imageDar; + + int _textInset[2]; + Color _disabledFgColor1; + Color _disabledFgColor2; + Color _associateColor; + int _textImageIndex; // index in the image array that the default _textimage resides + EColorState _textColorState; + + PHandle _associate; + char *_associateName; + + char *_fontOverrideName; + + wchar_t _hotkey; // the hotkey contained in the text + + bool m_bWrap; + bool m_bCenterWrap; + bool m_bAllCaps; + bool m_bAutoWideToContents; + bool m_bAutoWideDirty; + bool m_bUseProportionalInsets; + +}; + +} // namespace vgui + +#endif // LABEL_H diff --git a/public/vgui_controls/ListPanel.h b/public/vgui_controls/ListPanel.h new file mode 100644 index 0000000..9248856 --- /dev/null +++ b/public/vgui_controls/ListPanel.h @@ -0,0 +1,371 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef LISTPANEL_H +#define LISTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include + +class KeyValues; + +namespace vgui +{ + +class ScrollBar; +class TextImage; +class ImagePanel; +class Label; +class Button; +class IDraggerEvent; +class FastSortListPanelItem; + +//----------------------------------------------------------------------------- +// Purpose: Generic class for ListPanel items +//----------------------------------------------------------------------------- +class ListPanelItem +{ +public: + ListPanelItem() : + kv( 0 ), + userData( 0 ), + m_pDragData( 0 ), + m_bImage( false ), + m_nImageIndex( -1 ), + m_nImageIndexSelected( -1 ), + m_pIcon( 0 ) + { + } + + KeyValues *kv; + unsigned int userData; + KeyValues *m_pDragData; + bool m_bImage; + int m_nImageIndex; + int m_nImageIndexSelected; + IImage *m_pIcon; +}; + +typedef int __cdecl SortFunc( + ListPanel *pPanel, + const ListPanelItem &item1, + const ListPanelItem &item2 ); + +//----------------------------------------------------------------------------- +// Purpose: A spread-sheet type data view, similar to MFC's +//----------------------------------------------------------------------------- +class ListPanel : public Panel +{ + DECLARE_CLASS_SIMPLE( ListPanel, Panel ); + +public: + ListPanel(Panel *parent, const char *panelName); + ~ListPanel(); + + // COLUMN HANDLING + // all indices are 0 based, limit of 255 columns + // columns are resizable by default + enum ColumnFlags_e + { + COLUMN_FIXEDSIZE = 0x01, // set to have the column be a fixed size + COLUMN_RESIZEWITHWINDOW = 0x02, // set to have the column grow with the parent dialog growing + COLUMN_IMAGE = 0x04, // set if the column data is not text, but instead the index of the image to display + COLUMN_HIDDEN = 0x08, // column is hidden by default + COLUMN_UNHIDABLE = 0x10, // column is unhidable + }; + + // adds a column header + virtual void AddColumnHeader(int index, const char *columnName, const char *columnText, int startingWidth, int minWidth, int maxWidth, int columnFlags = 0); + virtual void AddColumnHeader(int index, const char *columnName, const char *columnText, int width, int columnFlags = 0); + + virtual void RemoveColumn(int column); // removes a column + virtual int FindColumn(const char *columnName); + virtual void SetColumnHeaderHeight( int height ); + virtual void SetColumnHeaderText(int column, const char *text); + virtual void SetColumnHeaderText(int column, wchar_t *text); + virtual void SetColumnHeaderImage(int column, int imageListIndex); + virtual void SetColumnHeaderTooltip(int column, const char *tooltipText); + virtual void SetColumnTextAlignment( int column, int align ); + + // Get information about the column headers. + virtual int GetNumColumnHeaders() const; + virtual bool GetColumnHeaderText( int index, char *pOut, int maxLen ); + + virtual void SetSortFunc(int column, SortFunc *func); + virtual void SetSortColumn(int column); + virtual void SortList( void ); + virtual void SetColumnSortable(int column, bool sortable); + virtual void SetColumnVisible(int column, bool visible); + int GetSortColumn() const; + + // sets whether the user can add/remove columns (defaults to off) + virtual void SetAllowUserModificationOfColumns(bool allowed); + + // DATA HANDLING + // data->GetName() is used to uniquely identify an item + // data sub items are matched against column header name to be used in the table + virtual int AddItem(const KeyValues *data, unsigned int userData, bool bScrollToItem, bool bSortOnAdd); // Takes a copy of the data for use in the table. Returns the index the item is at. + void SetItemDragData( int itemID, const KeyValues *data ); // Makes a copy of the keyvalues to store in the table. Used when dragging from the table. Only used if the caller enables drag support + virtual int GetItemCount( void ); // returns the number of VISIBLE items + virtual int GetItem(const char *itemName); // gets the row index of an item by name (data->GetName()) + virtual KeyValues *GetItem(int itemID); // returns pointer to data the row holds + virtual int GetItemCurrentRow(int itemID); // returns -1 if invalid index or item not visible + virtual int GetItemIDFromRow(int currentRow); // returns -1 if invalid row + virtual unsigned int GetItemUserData(int itemID); + virtual ListPanelItem *GetItemData(int itemID); + virtual void SetUserData( int itemID, unsigned int userData ); + virtual int GetItemIDFromUserData( unsigned int userData ); + virtual void ApplyItemChanges(int itemID); // applies any changes to the data, performed by modifying the return of GetItem() above + virtual void RemoveItem(int itemID); // removes an item from the table (changing the indices of all following items) + virtual void RereadAllItems(); // updates the view with the new data + + virtual void RemoveAll(); // clears and deletes all the memory used by the data items + virtual void DeleteAllItems(); // obselete, use RemoveAll(); + + virtual void GetCellText(int itemID, int column, OUT_Z_BYTECAP(bufferSizeInBytes) wchar_t *buffer, int bufferSizeInBytes); // returns the data held by a specific cell + virtual IImage *GetCellImage(int itemID, int column); //, ImagePanel *&buffer); // returns the image held by a specific cell + + // Use these until they return InvalidItemID to iterate all the items. + virtual int FirstItem() const; + virtual int NextItem( int iItem ) const; + + virtual int InvalidItemID() const; + virtual bool IsValidItemID(int itemID); + + // sets whether the dataitem is visible or not + // it is removed from the row list when it becomes invisible, but stays in the indexes + // this is much faster than a normal remove + virtual void SetItemVisible(int itemID, bool state); + virtual void SetItemDisabled(int itemID, bool state ); + bool IsItemVisible( int itemID ); + + virtual void SetFont(HFont font); + + // image handling + virtual void SetImageList(ImageList *imageList, bool deleteImageListWhenDone); + + // SELECTION + + // returns the count of selected items + virtual int GetSelectedItemsCount(); + + // returns the selected item by selection index, valid in range [0, GetNumSelectedRows) + virtual int GetSelectedItem(int selectionIndex); + + // sets no item as selected + virtual void ClearSelectedItems(); + + virtual bool IsItemSelected( int itemID ); + + // adds a item to the select list + virtual void AddSelectedItem( int itemID ); + + // sets this single item as the only selected item + virtual void SetSingleSelectedItem( int itemID ); + + // returns the selected column, -1 for particular column selected + virtual int GetSelectedColumn(); + + // whether or not to select specific cells (off by default) + virtual void SetSelectIndividualCells(bool state); + + // whether or not multiple cells/rows can be selected + void SetMultiselectEnabled( bool bState ); + bool IsMultiselectEnabled() const; + + // sets a single cell - all other previous rows are cleared + virtual void SetSelectedCell(int row, int column); + + virtual bool GetCellAtPos(int x, int y, int &row, int &column); // returns true if any found, row and column are filled out. x, y are in screen space + virtual bool GetCellBounds( int row, int column, int& x, int& y, int& wide, int& tall ); + + // sets the text which is displayed when the list is empty + virtual void SetEmptyListText(const char *text); + virtual void SetEmptyListText(const wchar_t *text); + + // relayout the scroll bar in response to changing the items in the list panel + // do this if you RemoveAll() + void ResetScrollBar(); + + // Attaches drag data to a particular item + virtual void OnCreateDragData( KeyValues *msg ); + + void SetIgnoreDoubleClick( bool state ); + + // set up a field for editing + virtual void EnterEditMode(int itemID, int column, vgui::Panel *editPanel); + + // leaves editing mode + virtual void LeaveEditMode(); + + // returns true if we are currently in inline editing mode + virtual bool IsInEditMode(); + + MESSAGE_FUNC_INT( ResizeColumnToContents, "ResizeColumnToContents", column ); + +#ifdef _X360 + virtual void NavigateTo(); +#endif + /// Version number for file format of user config. This defaults to 1, + /// and if you rearrange columns you can increment it to cause any old + /// user configs (which will be screwed up) to be discarded. + int m_nUserConfigFileVersion; + +protected: + // PAINTING + virtual Panel *GetCellRenderer(int row, int column); + + // overrides + virtual void OnMouseWheeled(int delta); + virtual void OnSizeChanged(int wide, int tall); + virtual void PerformLayout(); + virtual void Paint(); + virtual void PaintBackground(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnMousePressed( MouseCode code ); + virtual void OnMouseDoublePressed( MouseCode code ); +#ifdef _X360 + virtual void OnKeyCodePressed(KeyCode code); +#else + virtual void OnKeyCodePressed( KeyCode code ); +#endif + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); + MESSAGE_FUNC_INT_INT( OnColumnResized, "ColumnResized", column, delta ); + MESSAGE_FUNC_INT( OnSetSortColumn, "SetSortColumn", column ); + MESSAGE_FUNC( OpenColumnChoiceMenu, "OpenColumnChoiceMenu" ); + MESSAGE_FUNC_INT( OnToggleColumnVisible, "ToggleColumnVisible", col ); + virtual float GetRowsPerPage(); + virtual int GetStartItem(); + + // user configuration + virtual void ApplyUserConfigSettings(KeyValues *userConfig); + virtual void GetUserConfigSettings(KeyValues *userConfig); + virtual bool HasUserConfigSettings(); + + /* MESSAGES SENT + "ItemSelected" - query which items are selected + "ItemDeselected" - query which items are selected + */ + +public: + virtual void SetSortColumnEx( int iPrimarySortColumn, int iSecondarySortColumn, bool bSortAscending ); + void GetSortColumnEx( int &iPrimarySortColumn, int &iSecondarySortColumn, bool &bSortAscending ) const; + +private: + // Cleans up allocations associated with a particular item + void CleanupItem( FastSortListPanelItem *data ); + + // adds the item into the column indexes + void IndexItem(int itemID); + + // Purpose: + void UpdateSelection( vgui::MouseCode code, int x, int y, int row, int column ); + + // Handles multiselect + void HandleMultiSelection( int itemID, int row, int column ); + + // Handles addselect + void HandleAddSelection( int itemID, int row, int column ); + + // pre-sorted columns + struct IndexItem_t + { + ListPanelItem *dataItem; + int duplicateIndex; + }; + typedef CUtlRBTree IndexRBTree_t; + + struct column_t + { + Button *m_pHeader; + int m_iMinWidth; + int m_iMaxWidth; + bool m_bResizesWithWindow; + Panel *m_pResizer; + SortFunc *m_pSortFunc; + bool m_bTypeIsText; + bool m_bHidden; + bool m_bUnhidable; + IndexRBTree_t m_SortedTree; + int m_nContentAlignment; + }; + + // list of the column headers + CUtlLinkedList m_ColumnsData; + + // persistent list of all columns ever created, indexes into m_ColumnsData - used for matching up DATAITEM m_SortedTreeIndexes + CUtlVector m_ColumnsHistory; + + // current list of columns, indexes into m_ColumnsData + CUtlVector m_CurrentColumns; + + int m_iColumnDraggerMoved; // which column dragger was moved->which header to resize + int m_lastBarWidth; + + CUtlLinkedList m_DataItems; + CUtlVector m_VisibleItems; + + // set to true if the table needs to be sorted before it's drawn next + int m_iSortColumn; + int m_iSortColumnSecondary; + + void ResortColumnRBTree(int col); + static bool RBTreeLessFunc(vgui::ListPanel::IndexItem_t &item1, vgui::ListPanel::IndexItem_t &item2); + + TextImage *m_pTextImage; // used in rendering + ImagePanel *m_pImagePanel; // used in rendering + Label *m_pLabel; // used in rendering + ScrollBar *m_hbar; + ScrollBar *m_vbar; + + int m_iSelectedColumn; + + bool m_bNeedsSort : 1; + bool m_bSortAscending : 1; + bool m_bSortAscendingSecondary : 1; + bool m_bCanSelectIndividualCells : 1; + bool m_bShiftHeldDown : 1; + bool m_bMultiselectEnabled : 1; + bool m_bAllowUserAddDeleteColumns : 1; + bool m_bDeleteImageListWhenDone : 1; + bool m_bIgnoreDoubleClick : 1; + + int m_iHeaderHeight; + int m_iRowHeight; + + // selection data + CUtlVector m_SelectedItems; // array of selected rows + int m_LastItemSelected; // remember the last row selected for future shift clicks + + int m_iTableStartX; + int m_iTableStartY; + + Color m_LabelFgColor; + Color m_DisabledColor; + Color m_SelectionFgColor; + Color m_DisabledSelectionFgColor; + + ImageList *m_pImageList; + TextImage *m_pEmptyListText; + + PHandle m_hEditModePanel; + int m_iEditModeItemID; + int m_iEditModeColumn; + + void ResetColumnHeaderCommands(); +}; + +} + +#endif // LISTPANEL_H diff --git a/public/vgui_controls/ListViewPanel.h b/public/vgui_controls/ListViewPanel.h new file mode 100644 index 0000000..39f1bec --- /dev/null +++ b/public/vgui_controls/ListViewPanel.h @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef LISTVIEWPANEL_H +#define LISTVIEWPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class ListViewPanel; +typedef bool (*ListViewSortFunc_t)(KeyValues *kv1, KeyValues *kv2); + +class ListViewItem; + +//----------------------------------------------------------------------------- +// Purpose: List Ctrl Panel with each item having an icon and text after it +//----------------------------------------------------------------------------- +class ListViewPanel : public Panel +{ + DECLARE_CLASS_SIMPLE( ListViewPanel, Panel ); + +public: + ListViewPanel(Panel *parent, const char *panelName); + ~ListViewPanel(); + + virtual int AddItem(const KeyValues *data, bool bScrollToItem, bool bSortOnAdd); + virtual int GetItemCount(); + virtual KeyValues *GetItem(int itemID); + virtual void ApplyItemChanges(int itemID); + virtual void RemoveItem(int itemID); + virtual void DeleteAllItems(); + virtual int GetItemIDFromPos(int iPos); // valid from [0, GetItemCount) + + virtual int InvalidItemID(); + virtual bool IsValidItemID(int itemID); + + virtual void ScrollToItem(int itemID); + + virtual void SetSortFunc(ListViewSortFunc_t func); + virtual void SortList(); + + // image handling + virtual void SetImageList(ImageList *imageList, bool deleteImageListWhenDone); + + virtual void SetFont(HFont font); + + // returns the count of selected items + virtual int GetSelectedItemsCount(); + + // returns the selected item by selection index, valid in range [0, GetNumSelectedRows) + virtual int GetSelectedItem(int selectionIndex); + + // sets no item as selected + virtual void ClearSelectedItems(); + + // adds a item to the select list + virtual void AddSelectedItem(int itemID); + + // sets this single item as the only selected item + virtual void SetSingleSelectedItem(int itemID); + +protected: + // overrides + virtual void OnMouseWheeled(int delta); + virtual void OnSizeChanged(int wide, int tall); + virtual void PerformLayout(); + virtual void Paint(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnMousePressed( MouseCode code); + virtual void OnMouseDoublePressed( MouseCode code); + virtual void OnKeyCodeTyped( KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); + virtual int GetItemsPerColumn(); + +private: + ScrollBar *m_hbar; + + friend class ListViewItem; + void OnItemMousePressed(ListViewItem* pItem, MouseCode code); + void OnItemMouseDoublePressed(ListViewItem* pItem, MouseCode code); + int GetItemsMaxWidth(); + int GetItemIndex(int itemID); + void OnShiftSelect(int itemID); + void FinishKeyPress(int itemID); + + CUtlLinkedList m_DataItems; + CUtlVector m_SortedItems; + ListViewSortFunc_t m_pSortFunc; + + int m_iRowHeight; + HFont m_hFont; + + Color m_LabelFgColor; + Color m_SelectionFgColor; + + // selection data + CUtlVector m_SelectedItems; + int m_LastSelectedItemID; + int m_ShiftStartItemID; + + bool m_bNeedsSort; + bool m_bDeleteImageListWhenDone; + ImageList *m_pImageList; +}; + + +} + +#endif // LISTVIEWPANEL_H diff --git a/public/vgui_controls/Menu.h b/public/vgui_controls/Menu.h new file mode 100644 index 0000000..7793733 --- /dev/null +++ b/public/vgui_controls/Menu.h @@ -0,0 +1,379 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MENU_H +#define MENU_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include + +namespace vgui +{ + +class MenuItem; +class ScrollBar; +class MenuSeparator; + +//----------------------------------------------------------------------------- +// Purpose: A menu is a list of items that can be selected with one click, navigated +// with arrow keys and/or hot keys, and have a lit behavior when mouse over. +// It is NOT the button which opens the menu, but only the menu itself. +// +// Behaviour spec: +// Menu navigation can be done in 2 modes, via keyboard keys and via mouse. +// Clicking on menu button opens menu. +// Only one item in a menu is highlighted at a time. +// Only one submenu in a menu is open at a time. +// Disabled menuitems get highlighted via mouse and keys but will not activate. +// +// Mouse: +// Moving mouse into a menuitem highlights it. +// If the menuitem has a cascading menu, the menu opens when the mouse enters +// the menuitem. The cascading menuitem stays highlighted while its menu is open. +// No submenu items are highlighted by default. +// Moving the mouse into another menuitem closes any previously open submenus in the list. +// Clicking once in the menu item activates the menu item and closes all menus. +// Moving the mouse off a menuitem unhighlights it. +// The scroll bar arrows can be used to move up/down the menu one item at a time. +// The clicking and dragging on the scroll bar nob also scrolls the menu items. +// If a highlighed menuitem scrolls off, and the user then begins navigating via keys, +// the menu will snap the scroll bar so the highlighted item is visible. +// If user has been navigating via keys, moving the mouse over a menu item +// highlights it. +// Mousewheel: +// You must have the mouse inside the menu/scroll bar to use the wheel. +// The mouse wheel moves the highlighted menuitem up or down the list. +// If the list has no scroll bar the wheel will cycle from the bottom of the list +// to the top of the list and vice versa. +// If the list has a scrollbar the mouse wheel will stop at the top or bottom +// of the list. +// If the mouse is over the scroll bar no items are highlighted. +// Keyboard: +// When a menu is opened, no items are highlighted. +// If a menuitem has a cascading menu it does not open when the item is highlighted. +// The down arrow selects the next item in the list. +// (first item if none are highlighted and there is a scrollbar). +// The up arrow selects the previous item in the list +// (first item if none are highlighted and there is a scrollbar, last item if none are +// highlighted and there is no scrollbar). +// Selecting a new menuitem closes any previously open submenus in the list. +// The enter key activates the selected item and closes all menus. +// If the selected item has a cascading menu, activating it opens its submenu. +// These may also be activated by pressing the right arrow. +// Pressing the left arrow closes the submenu. +// When the submenu is opened the cascading menuitem stays highlighted. +// No items in the submenu are highlighted when it is opened. +// +// Note: Cascading menuitems in menus with a scrollbar is not supported. +// Its a clunky UI and if we want this we should design a better solution, +// perhaps along the lines of how explorer's bookmarks does it. +// It currently functions, but there are some arm/disarm bugs. +// +// +//----------------------------------------------------------------------------- +class Menu : public Panel +{ + DECLARE_CLASS_SIMPLE( Menu, Panel ); + friend class MenuItem; +public: + enum MenuDirection_e + { + LEFT, + RIGHT, + UP, + DOWN, + CURSOR, // make the menu appear under the mouse cursor + ALIGN_WITH_PARENT, // make the menu appear under the parent + }; + + Menu(Panel *parent, const char *panelName); + ~Menu(); + + static void PlaceContextMenu( Panel *parent, Menu *menu ); + static void OnInternalMousePressed( Panel *other, MouseCode code ); + + virtual void PositionRelativeToPanel( Panel *reference, MenuDirection_e direction, int nAdditionalYOffset = 0, bool showMenu = false ); + + // the menu. For combo boxes, it's the edit/field, etc. etc. + + // Add a simple text item to the menu + virtual int AddMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, const KeyValues *userData = NULL ); + virtual int AddMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, const KeyValues *userData = NULL ); + + virtual int AddMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target , const KeyValues *userData = NULL); + virtual int AddMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target , const KeyValues *userData = NULL); + + virtual int AddMenuItem( const char *itemText, const char *command, Panel *target , const KeyValues *userData = NULL); + virtual int AddMenuItem( const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); + virtual int AddMenuItem( const char *itemText, Panel *target, const KeyValues *userData = NULL ); + + // Add a checkable item to the menu + virtual int AddCheckableMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, const KeyValues *userData = NULL ); + virtual int AddCheckableMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, const KeyValues *userData = NULL ); + + virtual int AddCheckableMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); + virtual int AddCheckableMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); + + virtual int AddCheckableMenuItem( const char *itemText, const char *command, Panel *target , const KeyValues *userData = NULL); + virtual int AddCheckableMenuItem( const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); + virtual int AddCheckableMenuItem( const char *itemText, Panel *target, const KeyValues *userData = NULL ); + + // Add a cascading menu item to the menu + virtual int AddCascadingMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + virtual int AddCascadingMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + + virtual int AddCascadingMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + virtual int AddCascadingMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + + virtual int AddCascadingMenuItem( const char *itemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + virtual int AddCascadingMenuItem( const char *itemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + virtual int AddCascadingMenuItem( const char *itemText, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); + + // Add a custom panel to the menu + virtual int AddMenuItem( MenuItem *panel ); + + virtual void AddSeparator(); + virtual void AddSeparatorAfterItem( int itemID ); + + // Sets the values of a menu item at the specified index + virtual void UpdateMenuItem(int itemID, const char *itemText,KeyValues *message, const KeyValues *userData = NULL); + virtual void UpdateMenuItem(int itemID, const wchar_t *wszItemText,KeyValues *message, const KeyValues *userData = NULL); + + virtual void MoveMenuItem( int itemID, int moveBeforeThisItemID ); + + virtual bool IsValidMenuID(int itemID); + virtual int GetInvalidMenuID(); + + KeyValues *GetItemUserData(int itemID); + void GetItemText(int itemID, wchar_t *text, int bufLenInBytes); + void GetItemText(int itemID, char *text, int bufLenInBytes); + + virtual void SetItemEnabled(const char *itemName, bool state); + virtual void SetItemEnabled(int itemID, bool state); + virtual void SetItemVisible(const char *itemName, bool visible); + virtual void SetItemVisible(int itemID, bool visible); + + // Remove a single item + void DeleteItem( int itemID ); + + // Clear the menu, deleting all the menu items within + void DeleteAllItems(); + + // Override the auto-width setting with a single fixed width + virtual void SetFixedWidth( int width ); + + // Sets the content alignment of all items in the menu + void SetContentAlignment( Label::Alignment alignment ); + + // sets the height of each menu item + virtual void SetMenuItemHeight(int itemHeight); + virtual int GetMenuItemHeight() const; + + // Set the max number of items visible (scrollbar appears with more) + virtual void SetNumberOfVisibleItems( int numItems ); + + // Add the menu to the menu manager (see Menu::SetVisible())? + void EnableUseMenuManager( bool bUseMenuManager ); + + // Set up the menu items layout + virtual void PerformLayout( void ); + + virtual void SetBorder(class IBorder *border); + virtual void ApplySchemeSettings(IScheme *pScheme); + + // Set type ahead behaviour + enum MenuTypeAheadMode + { + COMPAT_MODE = 0, + HOT_KEY_MODE, + TYPE_AHEAD_MODE, + }; + virtual void SetTypeAheadMode(MenuTypeAheadMode mode); + virtual int GetTypeAheadMode(); + + // Hotkey handling + virtual void OnKeyTyped(wchar_t unichar); + // Menu nagivation etc. + virtual void OnKeyCodeTyped( KeyCode code ); + + // Visibility + virtual void SetVisible(bool state); + + // Activates item in the menu list, as if that menu item had been selected by the user + virtual void ActivateItem(int itemID); + virtual void SilentActivateItem(int itemID); // activate item, but don't fire the action signal + virtual void ActivateItemByRow(int row); + virtual int GetActiveItem(); // returns the itemID (not the row) of the active item + + // Return the number of items currently in the menu list + virtual int GetItemCount() const; + + // return the menuID of the n'th item in the menu list, valid from [0, GetItemCount) + virtual int GetMenuID(int index); + + // Return the number of items currently visible in the menu list + int GetCurrentlyVisibleItemsCount(); + + MenuItem *GetMenuItem(int itemID); + void CloseOtherMenus(MenuItem *item); + virtual void OnKillFocus(); + + int GetMenuMode(); + enum MenuMode + { + MOUSE = 0, + KEYBOARD, + }; + + void SetCurrentlyHighlightedItem(int itemID); + int GetCurrentlyHighlightedItem(); + void ClearCurrentlyHighlightedItem(); + + // Set the checked state of a checkable menuItem + void SetMenuItemChecked(int itemID, bool state); + bool IsChecked(int index); // check if item is checked. + + + void SetMinimumWidth(int width); + int GetMinimumWidth(); + + // baseclass overrides to chain colors through to cascade menus + virtual void SetFgColor( Color newColor ); + virtual void SetBgColor( Color newColor ); + + virtual void SetFont( HFont font ); + + // Pass in NULL hotkey to remove hotkey + void SetCurrentKeyBinding( int itemID, char const *hotkey ); + + void ForceCalculateWidth(); + + void SetUseFallbackFont( bool bState, HFont hFallback ); + +protected: + // helper functions + int AddMenuItemCharCommand(MenuItem *item, const char *command, Panel *target, const KeyValues *userData); + int AddMenuItemKeyValuesCommand(MenuItem *item, KeyValues *message, Panel *target, const KeyValues *userData); + + // vgui result reporting + virtual void OnCommand( const char *command ); + MESSAGE_FUNC_PTR( OnMenuItemSelected, "MenuItemSelected", panel ); + virtual void AddScrollBar(); + virtual void RemoveScrollBar(); + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); + virtual void Paint(); + virtual void LayoutMenuBorder(); + virtual void MakeItemsVisibleInScrollRange( int maxVisibleItems, int nNumPixelsAvailable ); + virtual void OnMouseWheeled(int delta); + // Alternate OnKeyTyped behaviors + virtual void OnHotKey(wchar_t unichar); + virtual void OnTypeAhead(wchar_t unichar); + + int CountVisibleItems(); + void ComputeWorkspaceSize( int& workWide, int& workTall ); + int ComputeFullMenuHeightWithInsets(); + + void CalculateWidth(); + + void LayoutScrollBar(); + void PositionCascadingMenu(); + void SizeMenuItems(); + void OnCursorMoved(int x, int y); + void OnKeyCodePressed(KeyCode code); + void OnMenuClose(); + MESSAGE_FUNC( OnKeyModeSet, "KeyModeSet" ); + + void SetCurrentlySelectedItem(MenuItem *item); + void SetCurrentlySelectedItem(int itemID); + MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel); + MESSAGE_FUNC_INT( OnCursorExitedMenuItem, "CursorExitedMenuItem", VPanel); + + void MoveAlongMenuItemList(int direction, int loopCount); + + enum + { + DEFAULT_MENU_ITEM_HEIGHT = 22, // height of items in the menu + MENU_UP = -1, // used for moving up/down list of menu items in the menu + MENU_DOWN = 1 + }; + +#ifdef DBGFLAG_VALIDATE + virtual void Validate( CValidator &validator, char *pchName ); +#endif // DBGFLAG_VALIDATE + +private: + MenuItem *GetParentMenuItem(); + + int m_iMenuItemHeight; + int m_iFixedWidth; + int m_iMinimumWidth; // a minimum width the menu has to be if it is not fixed width + int m_iNumVisibleLines; // number of items in menu before scroll bar adds on + ScrollBar *m_pScroller; + + CUtlLinkedList m_MenuItems; + + CUtlVector m_VisibleSortedItems; + CUtlVector m_SortedItems; // used for visual + CUtlVector m_Separators; // menu item ids after which separators should be shown + CUtlVector m_SeparatorPanels; + + bool _sizedForScrollBar: 1 ; // whether menu has been sized for a scrollbar + bool m_bUseFallbackFont : 1; + bool _recalculateWidth : 1; + bool m_bUseMenuManager : 1; + + int _menuWide; + int m_iCurrentlySelectedItemID; + int m_iInputMode; + int m_iCheckImageWidth; // the size of the check box spot on a checkable menu. + int m_iProportionalScrollBarSize; + Label::Alignment m_Alignment; + Color _borderDark; + int m_iActivatedItem; + HFont m_hItemFont; + HFont m_hFallbackItemFont; + + // for managing type ahead + #define TYPEAHEAD_BUFSIZE 256 + MenuTypeAheadMode m_eTypeAheadMode; + wchar_t m_szTypeAheadBuf[TYPEAHEAD_BUFSIZE]; + int m_iNumTypeAheadChars; + double m_fLastTypeAheadTime; +}; + + +//----------------------------------------------------------------------------- +// Helper class to create menu +//----------------------------------------------------------------------------- +class MenuBuilder +{ +public: + + MenuBuilder( Menu *pMenu, Panel *pActionTarget ); + + MenuItem* AddMenuItem( const char *pszButtonText, const char *pszCommand, const char *pszCategoryName ); + + MenuItem* AddCascadingMenuItem( const char *pszButtonText, Menu *pSubMenu, const char *pszCategoryName ); + +private: + + void AddSepratorIfNeeded( const char *pszCategoryName ); + + Menu *m_pMenu; + Panel *m_pActionTarget; + const char *m_pszLastCategory; +}; + +} // namespace vgui + +#endif // MENU_H diff --git a/public/vgui_controls/MenuBar.h b/public/vgui_controls/MenuBar.h new file mode 100644 index 0000000..01ccc06 --- /dev/null +++ b/public/vgui_controls/MenuBar.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MENUBAR_H +#define MENUBAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class MenuBar : public Panel +{ + DECLARE_CLASS_SIMPLE( MenuBar, Panel ); + +public: + MenuBar(Panel *parent, const char *panelName); + ~MenuBar(); + + virtual void AddButton(MenuButton *button); // add button to end of menu list + virtual void AddMenu( const char *pButtonName, Menu *pMenu ); + + virtual void GetContentSize( int& w, int&h ); + +protected: + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void PerformLayout(); + virtual void Paint(); + MESSAGE_FUNC( OnMenuClose, "MenuClose" ); + MESSAGE_FUNC_INT( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel); + +private: + CUtlVector m_pMenuButtons; + int m_nRightEdge; +}; + +} // namespace vgui + +#endif // MENUBAR_H + diff --git a/public/vgui_controls/MenuButton.h b/public/vgui_controls/MenuButton.h new file mode 100644 index 0000000..a90fb23 --- /dev/null +++ b/public/vgui_controls/MenuButton.h @@ -0,0 +1,82 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MENUBUTTON_H +#define MENUBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "vgui_controls/Menu.h" + +namespace vgui +{ + +class Menu; +class TextImage; + +//----------------------------------------------------------------------------- +// Purpose: Button that displays a menu when pressed +//----------------------------------------------------------------------------- +class MenuButton : public Button +{ + DECLARE_CLASS_SIMPLE( MenuButton, Button ); + +public: + MenuButton(Panel *parent, const char *panelName, const char *text); + ~MenuButton(); + + // functions designed to be overriden + virtual void OnShowMenu(Menu *menu) {} + virtual void OnHideMenu(Menu *menu) {} + virtual int OnCheckMenuItemCount() { return 0; } + + virtual void SetMenu(Menu *menu); + virtual void HideMenu(void); + virtual void DrawFocusBorder(int tx0, int ty0, int tx1, int ty1); + MESSAGE_FUNC( OnMenuClose, "MenuClose" ); + MESSAGE_FUNC_PARAMS( OnKillFocus, "KillFocus", kv ); // called after the panel loses the keyboard focus + virtual void DoClick(); + virtual void SetOpenOffsetY(int yOffset); + + virtual bool CanBeDefaultButton(void); + + // sets the direction in which the menu opens from the button, defaults to down + virtual void SetOpenDirection(Menu::MenuDirection_e direction); + + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnCursorEntered(); + + virtual void Paint(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void OnCursorMoved( int x, int y ); + + // This style is like the IE "back" button where the left side acts like a regular button, the the right side has a little + // combo box dropdown indicator and presents and submenu + void SetDropMenuButtonStyle( bool state ); + bool IsDropMenuButtonStyle() const; + + Menu *GetMenu(); + +private: + + Menu *m_pMenu; + Menu::MenuDirection_e m_iDirection; + + int _openOffsetY; // vertical offset of menu from the menu button + + bool m_bDropMenuButtonStyle : 1; + TextImage *m_pDropMenuImage; + int m_nImageIndex; +}; + +}; // namespace vgui + +#endif // MENUBUTTON_H diff --git a/public/vgui_controls/MenuItem.h b/public/vgui_controls/MenuItem.h new file mode 100644 index 0000000..6baa512 --- /dev/null +++ b/public/vgui_controls/MenuItem.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MENUITEM_H +#define MENUITEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class IBorder; +class TextImage; +class Menu; +class Image; + +//----------------------------------------------------------------------------- +// Purpose: The items in a menu +// MenuItems MUST have the Menu class as parents. +//----------------------------------------------------------------------------- +class MenuItem : public Button +{ + DECLARE_CLASS_SIMPLE( MenuItem, Button ); + +public: + MenuItem(Menu *parent, const char *panelName, const char *text, Menu *cascadeMenu = NULL, bool checkable = false); + MenuItem(Menu *parent, const char *panelName, const wchar_t *wszText, Menu *cascadeMenu = NULL, bool checkable = false); + ~MenuItem(); + + virtual void Paint(); + + // Activate the menu item as if it had been selected by the user + virtual void FireActionSignal(); + + virtual bool CanBeDefaultButton(void); + + // Handle mouse cursor entering a MenuItem. + void OnCursorEntered(); + // Handle mouse cursor exiting a MenuItem. + void OnCursorExited(); + + // Close the cascading menu if we have one. + void CloseCascadeMenu(); + + // Pass kill focus events up to parent on loss of focus + MESSAGE_FUNC( OnKillFocus, "MenuClose" ); + + // Return true if this item triggers a cascading menu + bool HasMenu(); + + // Set the size of the text portion of the label. + void SetTextImageSize(int wide, int tall); + + //Return the size of the text portion of the label. + void GetTextImageSize(int &wide, int &tall); + + // Return the size of the arrow portion of the label. + void GetArrowImageSize(int &wide, int &tall); + + // Return the size of the check portion of the label. + void GetCheckImageSize(int &wide, int &tall); + + // Return the menu that this menuItem contains + Menu *GetMenu(); + + virtual void PerformLayout(); + + // Respond to cursor movement + void OnCursorMoved(int x, int y); + + // Highlight item + MESSAGE_FUNC( ArmItem, "ArmItem" ); + // Unhighlight item. + MESSAGE_FUNC( DisarmItem, "DisarmItem" ); + + // is the item highlighted? + bool IsItemArmed(); + + // Open cascading menu if there is one. + void OpenCascadeMenu(); + + bool IsCheckable(); + bool IsChecked(); + + // Set a checkable menuItem checked or unchecked. + void SetChecked(bool state); + + KeyValues *GetUserData(); + void SetUserData(const KeyValues *kv); + + int GetActiveItem() { if ( m_pCascadeMenu ) { return m_pCascadeMenu->GetActiveItem(); } else { return 0; }} + + Menu *GetParentMenu(); + + void SetCurrentKeyBinding( char const *keyName ); + + virtual void GetContentSize( int& cw, int &ch ); + +protected: + void OnKeyCodeReleased(KeyCode code); + void OnMenuClose(); + MESSAGE_FUNC( OnKeyModeSet, "KeyModeSet" ); + + // vgui overrides + virtual void Init( void ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + +private: + enum { CHECK_INSET = 6 }; + Menu *m_pCascadeMenu; // menu triggered to open upon selecting this menu item + bool m_bCheckable; // can this menu item have a little check to the left of it when you select it? + bool m_bChecked; // whether item is checked or not. + TextImage *m_pCascadeArrow; // little arrow that appears to the right of menuitems that open a menu + Image *m_pCheck; // the check that appears to the left of checked menu items + TextImage *m_pBlankCheck; // a blank image same size as the check for when items are not checked. + + TextImage *m_pCurrentKeyBinding; // An optional indicator for the key currently bound to this menu item + + KeyValues *m_pUserData; + +}; + +} // namespace vgui + +#endif // MENUITEM_H diff --git a/public/vgui_controls/MessageBox.h b/public/vgui_controls/MessageBox.h new file mode 100644 index 0000000..4791822 --- /dev/null +++ b/public/vgui_controls/MessageBox.h @@ -0,0 +1,98 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MESSAGEBOX_H +#define MESSAGEBOX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +// prevent windows macros from messing with the class +#ifdef MessageBox +#undef MessageBox +#endif + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Popup discardable message box +//----------------------------------------------------------------------------- +class MessageBox : public Frame +{ + DECLARE_CLASS_SIMPLE( MessageBox, Frame ); + +public: + // title - Text to be displayed in the title bar of the window + // text - Text message in the message box + // startMinimized - wether message box starts minimized. Starts invisible by default + // parent - parent panel of the message box, by default it has no parent. This will keep the box visible until the OK button is pressed. + MessageBox(const char *title, const char *text, Panel *parent = NULL); + MessageBox(const wchar_t *wszTitle, const wchar_t *wszText, Panel *parent = NULL); + ~MessageBox(); + + // Put the message box into a modal state + virtual void DoModal(Frame *pFrameOver = NULL); + + // make the message box appear and in a modeless state + virtual void ShowWindow(Frame *pFrameOver = NULL); + + // Set a string command to be sent when the OK button is pressed + // Use AddActionSignalTarget() to mark yourself as a recipient of the command + virtual void SetCommand(const char *command); + virtual void SetCommand(KeyValues *command); + + // Set the visibility of the OK button. + virtual void SetOKButtonVisible(bool state); + + // Set the text on the OK button + virtual void SetOKButtonText(const char *buttonText); + virtual void SetOKButtonText(const wchar_t *wszButtonText); + + // Cancel button (off by default) + void SetCancelButtonVisible(bool state); + void SetCancelButtonText(const char *buttonText); + void SetCancelButtonText(const wchar_t *wszButtonText); + void SetCancelCommand( KeyValues *command ); + + // Toggles visibility of the close box. + virtual void DisableCloseButton(bool state); + + virtual void OnCommand( const char *pCommand ); + + // Shows the message box over the cursor + void ShowMessageBoxOverCursor( bool bEnable ); + +protected: + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + +protected: + Button *m_pOkButton; + Button *m_pCancelButton; + Label *m_pMessageLabel; + +private: + MESSAGE_FUNC( OnShutdownRequest, "ShutdownRequest" ); + + void Init(); + + KeyValues *m_OkCommand; + KeyValues *m_CancelCommand; + vgui::Frame *m_pFrameOver; + bool m_bNoAutoClose : 1; + bool m_bShowMessageBoxOverCursor : 1; +}; + +} // namespace vgui + + +#endif // MESSAGEBOX_H diff --git a/public/vgui_controls/MessageDialog.h b/public/vgui_controls/MessageDialog.h new file mode 100644 index 0000000..191bb2b --- /dev/null +++ b/public/vgui_controls/MessageDialog.h @@ -0,0 +1,154 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains the CMessageDialog declaration +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MESSAGEDIALOG_H +#define MESSAGEDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +// styles +#define MD_WARNING 0x0001 +#define MD_ERROR 0x0002 + +// button configurations +#define MD_OK 0x0004 // 1 button - OK +#define MD_CANCEL 0x0008 // 1 button - CANCEL +#define MD_OKCANCEL 0x0010 // 2 buttons - OK and CANCEL +#define MD_YESNO 0x0020 // 2 buttons - YES and NO + +// behavior +#define MD_SIMPLEFRAME 0x0100 // legacy corners +#define MD_COMMANDAFTERCLOSE 0x0200 // send command at dialog termination (i.e. after fade) +#define MD_RESTRICTPAINT 0x0400 // only paint this dialog (hide any other ui elements) +#define MD_COMMANDONFORCECLOSE 0x0800 // send command when the dialog is closed assuming A input + +// dialog type +enum EDialogType +{ + MD_SAVE_BEFORE_QUIT, + MD_QUIT_CONFIRMATION, + MD_QUIT_CONFIRMATION_TF, + MD_KICK_CONFIRMATION, + MD_CLIENT_KICKED, + MD_LOST_HOST, + MD_LOST_SERVER, + MD_SEARCHING_FOR_GAMES, + MD_CREATING_GAME, + MD_MODIFYING_SESSION, + MD_SESSION_SEARCH_FAILED, + MD_SESSION_CREATE_FAILED, + MD_SESSION_CONNECTING, + MD_SESSION_CONNECT_NOTAVAILABLE, + MD_SESSION_CONNECT_SESSIONFULL, + MD_SESSION_CONNECT_FAILED, + MD_EXIT_SESSION_CONFIRMATION, + MD_STORAGE_DEVICES_NEEDED, + MD_STORAGE_DEVICES_CHANGED, + MD_STORAGE_DEVICES_TOO_FULL, + MD_NOT_ONLINE_ENABLED, + MD_NOT_ONLINE_SIGNEDIN, + MD_DEFAULT_CONTROLS_CONFIRM, + MD_AUTOSAVE_EXPLANATION, + MD_COMMENTARY_EXPLANATION, + MD_COMMENTARY_EXPLANATION_MULTI, + MD_COMMENTARY_CHAPTER_UNLOCK_EXPLANATION, + MD_SAVE_BEFORE_LANGUAGE_CHANGE, + MD_SAVE_BEFORE_NEW_GAME, + MD_SAVE_BEFORE_LOAD, + MD_DELETE_SAVE_CONFIRM, + MD_SAVE_OVERWRITE, + MD_SAVING_WARNING, + MD_SAVE_COMPLETE, + MD_STANDARD_SAMPLE, + MD_WARNING_SAMPLE, + MD_ERROR_SAMPLE, + MD_PROMPT_SIGNIN, + MD_PROMPT_SIGNIN_REQUIRED, + MD_PROMPT_STORAGE_DEVICE, + MD_PROMPT_STORAGE_DEVICE_REQUIRED, + MD_DISCONNECT_CONFIRMATION, + MD_DISCONNECT_CONFIRMATION_HOST, + MD_LOAD_FAILED_WARNING, + MD_OPTION_CHANGE_FROM_X360_DASHBOARD, + MD_STORAGE_DEVICES_CORRUPT, + MD_CHECKING_STORAGE_DEVICE +}; + +#include "vgui_controls/Frame.h" +#include "vgui_controls/Label.h" +#include "vgui_controls/AnimatingImagePanel.h" +#include "vgui_controls/ImagePanel.h" + +//----------------------------------------------------------------------------- +// Purpose: Simple modal dialog box for Xbox 360 warnings and messages +//----------------------------------------------------------------------------- +class CMessageDialog : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CMessageDialog, vgui::Frame ); + +public: + CMessageDialog( vgui::Panel *parent, const uint nType, const char *pTitle, const char *pMsg, const char *pCmdA, const char *pCmdB, vgui::Panel *pParent, bool bShowActivity ); + ~CMessageDialog(); + + enum + { + BTN_INVALID = -1, + BTN_B, + BTN_A, + MAX_BUTTONS, + }; + + struct ButtonLabel_s + { + vgui::Label *pIcon; + vgui::Label *pText; + int nWide; + bool bCreated; + }; + + virtual void OnKeyCodePressed( vgui::KeyCode code ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void PaintBackground(); + uint GetType( void ); + void SetControlSettingsKeys( KeyValues *pKeys ); + +private: + void CreateButtonLabel( ButtonLabel_s *pButton, const char *pIcon, const char *pText ); + void DoCommand( int button ); + + vgui::Panel *m_pCreator; + + vgui::Label *m_pTitle; + vgui::Label *m_pMsg; + vgui::ImagePanel *m_pBackground; + + vgui::AnimatingImagePanel *m_pAnimatingPanel; + + vgui::HFont m_hButtonFont; + vgui::HFont m_hTextFont; + uint m_nType; + Color m_ButtonTextColor; + int m_ButtonPressed; + KeyValues *m_pControlSettings; + + int m_FooterTall; + int m_ButtonMargin; + Color m_clrNotSimpleBG; + Color m_clrNotSimpleBGBlack; + int m_ButtonIconLabelSpace; + + int m_ActivityIndent; + + bool m_bShowActivity; // should we show an animating image panel? + + ButtonLabel_s m_Buttons[MAX_BUTTONS]; + char *m_pCommands[MAX_BUTTONS]; +}; + +#endif // MESSAGEDIALOG_H diff --git a/public/vgui_controls/MessageMap.h b/public/vgui_controls/MessageMap.h new file mode 100644 index 0000000..226c0ad --- /dev/null +++ b/public/vgui_controls/MessageMap.h @@ -0,0 +1,381 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MESSAGEMAP_H +#define MESSAGEMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" + +// more flexible than default pointers to members code required for casting member function pointers +//#pragma pointers_to_members( full_generality, virtual_inheritance ) + +namespace vgui +{ + +////////////// MESSAGEMAP DEFINITIONS ////////////// + + +//----------------------------------------------------------------------------- +// Purpose: parameter data type enumeration +// used internal but the shortcut macros require this to be exposed +//----------------------------------------------------------------------------- +enum DataType_t +{ + DATATYPE_VOID, + DATATYPE_CONSTCHARPTR, + DATATYPE_INT, + DATATYPE_FLOAT, + DATATYPE_PTR, + DATATYPE_BOOL, + DATATYPE_KEYVALUES, + DATATYPE_CONSTWCHARPTR, + DATATYPE_UINT64, + DATATYPE_HANDLE, // It's an int, really +}; + +#ifdef WIN32 +class __virtual_inheritance Panel; +#else +class Panel; +#endif +typedef unsigned int VPANEL; + +typedef void (Panel::*MessageFunc_t)(void); + +//----------------------------------------------------------------------------- +// Purpose: Single item in a message map +// Contains the information to map a string message name with parameters +// to a function call +//----------------------------------------------------------------------------- +#pragma warning(disable:4121) +struct MessageMapItem_t +{ + const char *name; + // VC6 aligns this to 16-bytes. Since some of the code has been compiled with VC6, + // we need to enforce the alignment on later compilers to remain compatible. + ALIGN16 MessageFunc_t func; + + int numParams; + + DataType_t firstParamType; + const char *firstParamName; + + DataType_t secondParamType; + const char *secondParamName; + + int nameSymbol; + int firstParamSymbol; + int secondParamSymbol; +}; + +#define DECLARE_PANELMESSAGEMAP( className ) \ + static void AddToMap( char const *scriptname, vgui::MessageFunc_t function, int paramCount, int p1type, const char *p1name, int p2type, const char *p2name ) \ + { \ + vgui::PanelMessageMap *map = vgui::FindOrAddPanelMessageMap( GetPanelClassName() ); \ + \ + vgui::MessageMapItem_t entry; \ + entry.name = scriptname; \ + entry.func = function; \ + entry.numParams = paramCount; \ + entry.firstParamType = (vgui::DataType_t)p1type; \ + entry.firstParamName = p1name; \ + entry.secondParamType = (vgui::DataType_t)p2type; \ + entry.secondParamName = p2name; \ + entry.nameSymbol = 0; \ + entry.firstParamSymbol = 0; \ + entry.secondParamSymbol = 0; \ + \ + map->entries.AddToTail( entry ); \ + } \ + \ + static void ChainToMap( void ) \ + { \ + static bool chained = false; \ + if ( chained ) \ + return; \ + chained = true; \ + vgui::PanelMessageMap *map = vgui::FindOrAddPanelMessageMap( GetPanelClassName() ); \ + map->pfnClassName = &GetPanelClassName; \ + if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] ) \ + { \ + map->baseMap = vgui::FindOrAddPanelMessageMap( GetPanelBaseClassName() ); \ + } \ + } \ + \ + class className##_RegisterMap; \ + friend class className##_RegisterMap; \ + class className##_RegisterMap \ + { \ + public: \ + className##_RegisterMap() \ + { \ + className::ChainToMap(); \ + } \ + }; \ + className##_RegisterMap m_RegisterClass; \ + \ + virtual vgui::PanelMessageMap *GetMessageMap() \ + { \ + static vgui::PanelMessageMap *s_pMap = vgui::FindOrAddPanelMessageMap( GetPanelClassName() ); \ + return s_pMap; \ + } + +#if !defined( _XBOX ) +#define VGUI_USEKEYBINDINGMAPS 1 +#endif + +#if defined( VGUI_USEKEYBINDINGMAPS ) + +#define DECLARE_CLASS_SIMPLE( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + DECLARE_KEYBINDINGMAP( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return #baseClassName; } + +#define DECLARE_CLASS_SIMPLE_NOBASE( className ) \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + DECLARE_KEYBINDINGMAP( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return NULL; } + +#else // no keybinding maps + +#define DECLARE_CLASS_SIMPLE( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return #baseClassName; } + +#define DECLARE_CLASS_SIMPLE_NOBASE( className ) \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return NULL; } + +#endif // !VGUI_USEKEYBINDINGMAPS + +#define _MessageFuncCommon( name, scriptname, paramCount, p1type, p1name, p2type, p2name ) \ + class PanelMessageFunc_##name; \ + friend class PanelMessageFunc_##name; \ + class PanelMessageFunc_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + AddToMap( scriptname, (vgui::MessageFunc_t)&ThisClass::name, paramCount, p1type, p1name, p2type, p2name ); \ + } \ + } \ + PanelMessageFunc_##name() \ + { \ + PanelMessageFunc_##name::InitVar(); \ + } \ + }; \ + PanelMessageFunc_##name m_##name##_register; \ + +// Use this macro to define a message mapped function +// must end with a semicolon ';', or with a function +// no parameter +#define MESSAGE_FUNC( name, scriptname ) _MessageFuncCommon( name, scriptname, 0, 0, 0, 0, 0 ); virtual void name( void ) + +// one parameter +#define MESSAGE_FUNC_INT( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 ); virtual void name( int p1 ) +#define MESSAGE_FUNC_UINT64( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_UINT64, #p1, 0, 0 ); virtual void name( uint64 p1 ) +#define MESSAGE_FUNC_PTR( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_PTR, #p1, 0, 0 ); virtual void name( vgui::Panel *p1 ) +#define MESSAGE_FUNC_HANDLE( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_HANDLE, #p1, 0, 0 ); virtual void name( vgui::VPANEL p1 ) +#define MESSAGE_FUNC_ENUM( name, scriptname, t1, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 ); virtual void name( t1 p1 ) +#define MESSAGE_FUNC_FLOAT( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_FLOAT, #p1, 0, 0 ); virtual void name( float p1 ) +#define MESSAGE_FUNC_CHARPTR( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_CONSTCHARPTR, #p1, 0, 0 ); virtual void name( const char *p1 ) +#define MESSAGE_FUNC_WCHARPTR( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_CONSTWCHARPTR, #p1, 0, 0 ); virtual void name( const wchar_t *p1 ) + +// two parameters +#define MESSAGE_FUNC_INT_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( int p1, int p2 ) +#define MESSAGE_FUNC_PTR_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( vgui::Panel *p1, int p2 ) +#define MESSAGE_FUNC_HANDLE_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( vgui::VPANEL p1, int p2 ) +#define MESSAGE_FUNC_ENUM_ENUM( name, scriptname, t1, p1, t2, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( t1 p1, t2 p2 ) +#define MESSAGE_FUNC_INT_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( int p1, const char *p2 ) +#define MESSAGE_FUNC_PTR_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( vgui::Panel *p1, const char *p2 ) +#define MESSAGE_FUNC_HANDLE_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( vgui::VPANEL p1, const char *p2 ) +#define MESSAGE_FUNC_PTR_WCHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 ); virtual void name( vgui::Panel *p1, const wchar_t *p2 ) +#define MESSAGE_FUNC_HANDLE_WCHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 ); virtual void name( vgui::VPANEL p1, const wchar_t *p2 ) +#define MESSAGE_FUNC_CHARPTR_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_CONSTCHARPTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( const char *p1, const char *p2 ) + +// unlimited parameters (passed in the whole KeyValues) +#define MESSAGE_FUNC_PARAMS( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_KEYVALUES, NULL, 0, 0 ); virtual void name( KeyValues *p1 ) + +// no-virtual function version +#define MESSAGE_FUNC_NV( name, scriptname ) _MessageFuncCommon( name, scriptname, 0, 0, 0, 0, 0 ); void name( void ) +#define MESSAGE_FUNC_NV_INT( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 ); void name( int p1 ) +#define MESSAGE_FUNC_NV_INT_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 ); void name( int p1, int p2 ) + + +// mapping, one per class +struct PanelMessageMap +{ + PanelMessageMap() + { + baseMap = NULL; + pfnClassName = NULL; + processed = false; + } + + CUtlVector< MessageMapItem_t > entries; + bool processed; + PanelMessageMap *baseMap; + char const *(*pfnClassName)( void ); +}; + +PanelMessageMap *FindPanelMessageMap( char const *className ); +PanelMessageMap *FindOrAddPanelMessageMap( char const *className ); + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// OBSELETE MAPPING FUNCTIONS, USE ABOVE +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// no parameters +#define MAP_MESSAGE( type, name, func ) { name, (vgui::MessageFunc_t)(&type::func), 0 } + +// implicit single parameter (params is the data store) +#define MAP_MESSAGE_PARAMS( type, name, func ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_KEYVALUES, NULL } + +// single parameter +#define MAP_MESSAGE_PTR( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_PTR, param1 } +#define MAP_MESSAGE_INT( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_INT, param1 } +#define MAP_MESSAGE_BOOL( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_BOOL, param1 } +#define MAP_MESSAGE_FLOAT( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_FLOAT, param1 } +#define MAP_MESSAGE_PTR( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_PTR, param1 } +#define MAP_MESSAGE_CONSTCHARPTR( type, name, func, param1) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_CONSTCHARPTR, param1 } +#define MAP_MESSAGE_CONSTWCHARPTR( type, name, func, param1) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_CONSTWCHARPTR, param1 } + +// two parameters +#define MAP_MESSAGE_INT_INT( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_INT, param1, vgui::DATATYPE_INT, param2 } +#define MAP_MESSAGE_PTR_INT( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_INT, param2 } +#define MAP_MESSAGE_INT_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_INT, param1, vgui::DATATYPE_CONSTCHARPTR, param2 } +#define MAP_MESSAGE_PTR_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_CONSTCHARPTR, param2 } +#define MAP_MESSAGE_PTR_CONSTWCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_CONSTWCHARPTR, param2 } +#define MAP_MESSAGE_CONSTCHARPTR_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_CONSTCHARPTR, param1, vgui::DATATYPE_CONSTCHARPTR, param2 } + +// if more parameters are needed, just use MAP_MESSAGE_PARAMS() and pass the keyvalue set into the function + +//----------------------------------------------------------------------------- +// Purpose: stores the list of objects in the hierarchy +// used to iterate through an object's message maps +//----------------------------------------------------------------------------- +struct PanelMap_t +{ + MessageMapItem_t *dataDesc; + int dataNumFields; + const char *dataClassName; + PanelMap_t *baseMap; + int processed; +}; + +// for use in class declarations +// declares the static variables and functions needed for the data description iteration +#define DECLARE_PANELMAP() \ + static vgui::PanelMap_t m_PanelMap; \ + static vgui::MessageMapItem_t m_MessageMap[]; \ + virtual vgui::PanelMap_t *GetPanelMap( void ); + +// could embed typeid() into here as well? +#define IMPLEMENT_PANELMAP( derivedClass, baseClass ) \ + vgui::PanelMap_t derivedClass::m_PanelMap = { derivedClass::m_MessageMap, ARRAYSIZE(derivedClass::m_MessageMap), #derivedClass, &baseClass::m_PanelMap }; \ + vgui::PanelMap_t *derivedClass::GetPanelMap( void ) { return &m_PanelMap; } + +typedef vgui::Panel *( *PANELCREATEFUNC )( void ); + +//----------------------------------------------------------------------------- +// Purpose: Used by DECLARE_BUILD_FACTORY macro to create a linked list of +// instancing functions +//----------------------------------------------------------------------------- +class CBuildFactoryHelper +{ +public: + // Static list of helpers + static CBuildFactoryHelper *m_sHelpers; + +public: + // Construction + CBuildFactoryHelper( char const *className, PANELCREATEFUNC func ); + + // Accessors + CBuildFactoryHelper *GetNext( void ); + + char const *GetClassName() const; + + vgui::Panel *CreatePanel(); + + static vgui::Panel *InstancePanel( char const *className ); + static void GetFactoryNames( CUtlVector< char const * >& list ); +private: + + static bool HasFactory( char const *className ); + + // Next factory in list + CBuildFactoryHelper *m_pNext; + + int m_Type; + PANELCREATEFUNC m_CreateFunc; + char const *m_pClassName; +}; + +// This is the macro which implements creation of each type of panel +// It creates a function which instances an object of the specified type +// It them hooks that function up to the helper list so that the CHud objects can create +// the elements by name, with no header file dependency, etc. +#define DECLARE_BUILD_FACTORY( className ) \ + static vgui::Panel *Create_##className( void ) \ + { \ + return new className( NULL, NULL ); \ + }; \ + static vgui::CBuildFactoryHelper g_##className##_Helper( #className, Create_##className );\ + className *g_##className##LinkerHack = NULL; + +#define DECLARE_BUILD_FACTORY_DEFAULT_TEXT( className, defaultText ) \ + static vgui::Panel *Create_##className( void ) \ + { \ + return new className( NULL, NULL, #defaultText ); \ + }; \ + static vgui::CBuildFactoryHelper g_##className##_Helper( #className, Create_##className );\ + className *g_##className##LinkerHack = NULL; + +// This one allows passing in a special function with calls new panel( xxx ) with arbitrary default parameters +#define DECLARE_BUILD_FACTORY_CUSTOM( className, createFunc ) \ + static vgui::CBuildFactoryHelper g_##className##_Helper( #className, createFunc );\ + className *g_##className##LinkerHack = NULL; + +#define DECLARE_BUILD_FACTORY_CUSTOM_ALIAS( className, factoryName, createFunc ) \ + static vgui::CBuildFactoryHelper g_##factoryName##_Helper( #factoryName, createFunc );\ + className *g_##factoryName##LinkerHack = NULL; + +} // namespace vgui + + +#endif // MESSAGEMAP_H diff --git a/public/vgui_controls/PHandle.h b/public/vgui_controls/PHandle.h new file mode 100644 index 0000000..959ee4a --- /dev/null +++ b/public/vgui_controls/PHandle.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PHANDLE_H +#define PHANDLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +class Panel; + +//----------------------------------------------------------------------------- +// Purpose: Safe pointer class for handling Panel or derived panel classes +//----------------------------------------------------------------------------- +class PHandle +{ +public: + PHandle() : m_iPanelID(INVALID_PANEL) {} //m_iSerialNumber(0), m_pListEntry(0) {} + + Panel *Get(); + Panel *Set( Panel *pPanel ); + Panel *Set( HPanel hPanel ); + + operator Panel *() { return Get(); } + Panel * operator ->() { return Get(); } + Panel * operator = (Panel *pPanel) { return Set(pPanel); } + + bool operator == (Panel *pPanel) { return (Get() == pPanel); } + operator bool () { return Get() != 0; } + +private: + HPanel m_iPanelID; +}; + +//----------------------------------------------------------------------------- +// Purpose: Safe pointer class to just convert between VPANEL's and PHandle +//----------------------------------------------------------------------------- +class VPanelHandle +{ +public: + VPanelHandle() : m_iPanelID(INVALID_PANEL) {} + + VPANEL Get(); + VPANEL Set( VPANEL pPanel ); + + operator VPANEL () { return Get(); } + VPANEL operator = (VPANEL pPanel) { return Set(pPanel); } + + bool operator == (VPANEL pPanel) { return (Get() == pPanel); } + operator bool () { return Get() != 0; } + +private: + HPanel m_iPanelID; +}; + +//----------------------------------------------------------------------------- +// Purpose: DHANDLE is a templated version of PHandle +//----------------------------------------------------------------------------- +template< class PanelType > +class DHANDLE : public PHandle +{ +public: + PanelType *Get() { return (PanelType *)PHandle::Get(); } + PanelType *Set( PanelType *pPanel ) { return (PanelType *)PHandle::Set(pPanel); } + PanelType *Set( HPanel hPanel ) { return (PanelType *)PHandle::Set(hPanel); } + + operator PanelType *() { return (PanelType *)PHandle::Get(); } + PanelType * operator ->() { return (PanelType *)PHandle::Get(); } + PanelType * operator = (PanelType *pPanel) { return (PanelType *)PHandle::Set(pPanel); } + bool operator == (Panel *pPanel) { return (PHandle::Get() == pPanel); } + operator bool () { return PHandle::Get() != NULL; } +}; + +}; + +#endif // PHANDLE_H diff --git a/public/vgui_controls/Panel.h b/public/vgui_controls/Panel.h new file mode 100644 index 0000000..174dea4 --- /dev/null +++ b/public/vgui_controls/Panel.h @@ -0,0 +1,1030 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PANEL_H +#define PANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlflags.h" +#include "vgui/VGUI.h" +#include "vgui/Dar.h" +#include "vgui_controls/MessageMap.h" +#if defined( VGUI_USEKEYBINDINGMAPS ) +#include "vgui_controls/KeyBindingMap.h" +#endif +#include "vgui/IClientPanel.h" +#include "vgui/IScheme.h" +#include "vgui_controls/Controls.h" +#include "vgui_controls/PHandle.h" +#include "vgui_controls/PanelAnimationVar.h" +#include "Color.h" +#include "vstdlib/IKeyValuesSystem.h" +#include "tier1/utlsymbol.h" +#include "vgui_controls/BuildGroup.h" + +// undefine windows function macros that overlap +#ifdef PostMessage +#undef PostMessage +#endif + +#ifdef SetCursor +#undef SetCursor +#endif + +class CUtlBuffer; + +namespace vgui +{ + +#if !defined( _X360 ) +#define VGUI_USEDRAGDROP 1 +#endif + +#if defined( VGUI_USEKEYBINDINGMAPS ) +struct PanelKeyBindingMap; +#endif +//----------------------------------------------------------------------------- +// Purpose: Helper functions to construct vgui panels +// +// SETUP_PANEL - will make a panel ready for use right now (i.e setup its colors, borders, fonts, etc) +// +template< class T > +inline T *SETUP_PANEL(T *panel) +{ + panel->MakeReadyForUse(); + return panel; +} + +// +// CREATE_PANEL - creates a panel that is ready to use right now +// +// example of use = to set the FG Color of a panel inside of a constructor (i.e before ApplySchemeSettings() has been run on the child) +// +#define CREATE_PANEL(type, parent, name) (SETUP_PANEL(new type(parent, name))) + +//----------------------------------------------------------------------------- +// Purpose: Drag/drop support context info (could defined within Panel...) +//----------------------------------------------------------------------------- +#if defined( VGUI_USEDRAGDROP ) +struct DragDrop_t; +class Menu; +#endif + +//----------------------------------------------------------------------------- +// Purpose: Macro to handle Colors that can be overridden in .res files +//----------------------------------------------------------------------------- +struct OverridableColorEntry +{ + char const *name() { return m_pszScriptName; } + + char const *m_pszScriptName; + Color *m_pColor; + Color m_colFromScript; + bool m_bOverridden; +}; + +#define REGISTER_COLOR_AS_OVERRIDABLE( name, scriptname ) \ + AddToOverridableColors( &name, scriptname ); + + + +//----------------------------------------------------------------------------- +// Purpose: For hudanimations.txt scripting of vars +//----------------------------------------------------------------------------- +class IPanelAnimationPropertyConverter +{ +public: + virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) = 0; + virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) = 0; + virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) = 0; +}; + +#if defined( VGUI_USEKEYBINDINGMAPS ) +enum KeyBindingContextHandle_t +{ + INVALID_KEYBINDINGCONTEXT_HANDLE = 0xffffffff, +}; +#endif + +class IForceVirtualInheritancePanel +{ + // We need Panel to use virtual inheritance so that + // pointers to its members are max size. + // This is due to a limitation in C++ with ahead + // declarations of points to members as used in MessageMap. +}; + +//============================================================================= +// HPE_BEGIN: +// [tj] bitwise defines for rounded corners +//============================================================================= +#define PANEL_ROUND_CORNER_TOP_LEFT (1 << 0) +#define PANEL_ROUND_CORNER_TOP_RIGHT (1 << 1) +#define PANEL_ROUND_CORNER_BOTTOM_LEFT (1 << 2) +#define PANEL_ROUND_CORNER_BOTTOM_RIGHT (1 << 3) +#define PANEL_ROUND_CORNER_ALL PANEL_ROUND_CORNER_TOP_LEFT | PANEL_ROUND_CORNER_TOP_RIGHT | PANEL_ROUND_CORNER_BOTTOM_LEFT | PANEL_ROUND_CORNER_BOTTOM_RIGHT +//============================================================================= +// HPE_END +//=============================================================================//----------------------------------------------------------------------------- +// Purpose: Base interface to all vgui windows +// All vgui controls that receive message and/or have a physical presence +// on screen are be derived from Panel. +// This is designed as an easy-access to the vgui-functionality; for more +// low-level access to vgui functions use the IPanel/IClientPanel interfaces directly +//----------------------------------------------------------------------------- +class Panel : public IClientPanel, virtual IForceVirtualInheritancePanel +{ + DECLARE_CLASS_SIMPLE_NOBASE( Panel ); + +public: + // For property mapping + static void InitPropertyConverters( void ); + static void AddPropertyConverter( char const *typeName, IPanelAnimationPropertyConverter *converter ); + + //----------------------------------------------------------------------------- + // CONSTRUCTORS + // these functions deal with the creation of the Panel + // the Panel automatically gets a handle to a vgui-internal panel, the ipanel(), upon construction + // vgui interfaces deal only with ipanel(), not Panel directly + Panel(); + Panel(Panel *parent); + Panel(Panel *parent, const char *panelName); + Panel(Panel *parent, const char *panelName, HScheme scheme); + + virtual ~Panel(); + + // returns pointer to Panel's vgui VPanel interface handle + virtual VPANEL GetVPanel() { return _vpanel; } + HPanel ToHandle() const; + + virtual void Init( int x, int y, int wide, int tall ); + + //----------------------------------------------------------------------------- + // PANEL METHODS + // these functions all manipulate panels + // they cannot be derived from + void SetName(const char *panelName); // sets the name of the panel - used as an identifier + const char *GetName(); // returns the name of this panel... never NULL + const char *GetClassName(); // returns the class name of the panel (eg. Panel, Label, Button, etc.) + + void MakeReadyForUse(); // fully construct this panel so its ready for use right now (i.e fonts loaded, colors set, default label text set, ...) + + // panel position & size + // all units are in pixels + void SetPos(int x,int y); // sets position of panel, in local space (ie. relative to parent's position) + void GetPos(int &x,int &y); // gets local position of panel + int GetXPos(); + int GetYPos(); + void SetSize(int wide,int tall); // sets size of panel + void GetSize(int &wide, int &tall); // gets size of panel + void SetBounds(int x, int y, int wide, int tall); // combination of SetPos/SetSize + void GetBounds(int &x, int &y, int &wide, int &tall); // combination of GetPos/GetSize + int GetWide(); // returns width of panel + void SetWide(int wide); // sets width of panel + int GetTall(); // returns height of panel + void SetTall(int tall); // sets height of panel + void SetMinimumSize(int wide,int tall); // sets the minimum size the panel can go + void GetMinimumSize(int& wide,int& tall); // gets the minimum size + bool IsBuildModeEditable(); // editable in the buildModeDialog? + void SetBuildModeEditable(bool state); // set buildModeDialog editable + bool IsBuildModeDeletable(); // deletable in the buildModeDialog? + void SetBuildModeDeletable(bool state); // set buildModeDialog deletable + bool IsBuildModeActive(); // true if we're currently in edit mode + void SetZPos(int z); // sets Z ordering - lower numbers are always behind higher z's + int GetZPos( void ); + void SetAlpha(int alpha); // sets alpha modifier for panel and all child panels [0..255] + int GetAlpha(); // returns the current alpha + + // panel visibility + // invisible panels and their children do not drawn, updated, or receive input messages + virtual void SetVisible(bool state); + virtual bool IsVisible(); + + // painting + virtual VPANEL IsWithinTraverse(int x, int y, bool traversePopups); // recursive; returns a pointer to the panel at those coordinates + MESSAGE_FUNC( Repaint, "Repaint" ); // marks the panel as needing to be repainted + virtual void PostMessage(VPANEL target, KeyValues *message, float delaySeconds = 0.0f); + + bool IsWithin(int x, int y); //in screen space + void LocalToScreen(int &x, int &y); + void ScreenToLocal(int &x, int &y); + void ParentLocalToScreen(int &x, int &y); + void MakePopup(bool showTaskbarIcon = true,bool disabled = false); // turns the panel into a popup window (ie. can draw outside of it's parents space) + virtual void OnMove(); + + // panel hierarchy + virtual Panel *GetParent(); + virtual VPANEL GetVParent(); + virtual void SetParent(Panel *newParent); + virtual void SetParent(VPANEL newParent); + virtual bool HasParent(VPANEL potentialParent); + + int GetChildCount(); + Panel *GetChild(int index); + virtual CUtlVector< VPANEL > &GetChildren(); + int FindChildIndexByName( const char *childName ); + Panel *FindChildByName(const char *childName, bool recurseDown = false); + Panel *FindSiblingByName(const char *siblingName); + void CallParentFunction(KeyValues *message); + + template < class T > + T *FindControl( const char *pszName, bool recurseDown = false ) { return dynamic_cast( FindChildByName( pszName, recurseDown ) ); } + + virtual void SetAutoDelete(bool state); // if set to true, panel automatically frees itself when parent is deleted + virtual bool IsAutoDeleteSet(); + virtual void DeletePanel(); // simply does a { delete this; } + + // messaging + virtual void AddActionSignalTarget(Panel *messageTarget); + virtual void AddActionSignalTarget(VPANEL messageTarget); + virtual void RemoveActionSignalTarget(Panel *oldTarget); + virtual void PostActionSignal(KeyValues *message); // sends a message to the current actionSignalTarget(s) + virtual bool RequestInfoFromChild(const char *childName, KeyValues *outputData); + virtual void PostMessageToChild(const char *childName, KeyValues *messsage); + virtual void PostMessage(Panel *target, KeyValues *message, float delaySeconds = 0.0f); + virtual bool RequestInfo(KeyValues *outputData); // returns true if output is successfully written. You should always chain back to the base class if info request is not handled + virtual bool SetInfo(KeyValues *inputData); // sets a specified value in the control - inverse of the above + virtual void SetSilentMode( bool bSilent ); //change the panel's silent mode; if silent, the panel will not post any action signals + + // install a mouse handler + virtual void InstallMouseHandler( Panel *pHandler ); // mouse events will be send to handler panel instead of this panel + + // drawing state + virtual void SetEnabled(bool state); + virtual bool IsEnabled(); + virtual bool IsPopup(); // has a parent, but is in it's own space + virtual void GetClipRect(int &x0, int &y0, int &x1, int &y1); + virtual void MoveToFront(); + + // pin positions for auto-layout + enum PinCorner_e + { + PIN_TOPLEFT = 0, + PIN_TOPRIGHT, + PIN_BOTTOMLEFT, + PIN_BOTTOMRIGHT, + + // For sibling pinning + PIN_CENTER_TOP, + PIN_CENTER_RIGHT, + PIN_CENTER_BOTTOM, + PIN_CENTER_LEFT, + + PIN_LAST + }; + + // specifies the auto-resize directions for the panel + enum AutoResize_e + { + AUTORESIZE_NO = 0, + AUTORESIZE_RIGHT, + AUTORESIZE_DOWN, + AUTORESIZE_DOWNANDRIGHT, + }; + + // Sets the pin corner for non-resizing panels + void SetPinCorner( PinCorner_e pinCorner, int nOffsetX, int nOffsetY ); + + // Sets the pin corner + resize mode for resizing panels + void SetAutoResize( PinCorner_e pinCorner, AutoResize_e resizeDir, int nPinOffsetX, int nPinOffsetY, int nUnpinnedCornerOffsetX, int nUnpinnedCornerOffsetY ); + + AutoResize_e GetAutoResize(); + PinCorner_e GetPinCorner(); + + // Gets the relative offset of the control from the pinned + non-pinned corner (for resizing) + void GetPinOffset( int &dx, int &dy ); + void GetResizeOffset( int &dx, int &dy ); + + void PinToSibling( const char *pszSibling, PinCorner_e pinOurCorner, PinCorner_e pinSibling ); + void UpdateSiblingPin( void ); + + // colors + virtual void SetBgColor(Color color); + virtual void SetFgColor(Color color); + virtual Color GetBgColor(); + virtual Color GetFgColor(); + + virtual void SetCursor(HCursor cursor); + virtual HCursor GetCursor(); + virtual void SetCursorAlwaysVisible( bool visible ); + virtual void RequestFocus(int direction = 0); + virtual bool HasFocus(); + virtual void InvalidateLayout(bool layoutNow = false, bool reloadScheme = false); + virtual bool RequestFocusPrev(VPANEL panel = NULL); + virtual bool RequestFocusNext(VPANEL panel = NULL); + // tab positioning + virtual void SetTabPosition(int position); + virtual int GetTabPosition(); + // border + virtual void SetBorder(IBorder *border); + virtual IBorder *GetBorder(); + virtual void SetPaintBorderEnabled(bool state); + virtual void SetPaintBackgroundEnabled(bool state); + virtual void SetPaintEnabled(bool state); + virtual void SetPostChildPaintEnabled(bool state); + virtual void SetPaintBackgroundType(int type); // 0 for normal(opaque), 1 for single texture from Texture1, and 2 for rounded box w/ four corner textures + virtual void GetInset(int &left, int &top, int &right, int &bottom); + virtual void GetPaintSize(int &wide, int &tall); + virtual void SetBuildGroup(BuildGroup *buildGroup); + virtual bool IsBuildGroupEnabled(); + virtual bool IsCursorNone(); + virtual bool IsCursorOver(); // returns true if the cursor is currently over the panel + virtual void MarkForDeletion(); // object will free it's memory next tick + virtual bool IsLayoutInvalid(); // does this object require a perform layout? + virtual Panel *HasHotkey(wchar_t key); // returns the panel that has this hotkey + virtual bool IsOpaque(); + bool IsRightAligned(); // returns true if the settings are aligned to the right of the screen + bool IsBottomAligned(); // returns true if the settings are aligned to the bottom of the screen + + // scheme access functions + virtual HScheme GetScheme(); + virtual void SetScheme(const char *tag); + virtual void SetScheme(HScheme scheme); + virtual Color GetSchemeColor(const char *keyName,IScheme *pScheme); + virtual Color GetSchemeColor(const char *keyName, Color defaultColor,IScheme *pScheme); + + // called when scheme settings need to be applied; called the first time before the panel is painted + virtual void ApplySchemeSettings(IScheme *pScheme); + + // interface to build settings + // takes a group of settings and applies them to the control + virtual void ApplySettings(KeyValues *inResourceData); + + // records the settings into the resource data + virtual void GetSettings(KeyValues *outResourceData); + + // gets a description of the resource for use in the UI + // format: ... + // unknown types as just displayed as strings in the UI (for future UI expansion) + virtual const char *GetDescription(); + + // returns the name of the module that this instance of panel was compiled into + virtual const char *GetModuleName(); + + // user configuration settings + // this is used for any control details the user wants saved between sessions + // eg. dialog positions, last directory opened, list column width + virtual void ApplyUserConfigSettings(KeyValues *userConfig); + + // returns user config settings for this control + virtual void GetUserConfigSettings(KeyValues *userConfig); + + // optimization, return true if this control has any user config settings + virtual bool HasUserConfigSettings(); + + // message handlers + // override to get access to the message + // override to get access to the message + virtual void OnMessage(const KeyValues *params, VPANEL fromPanel); // called when panel receives message; must chain back + MESSAGE_FUNC_CHARPTR( OnCommand, "Command", command ); // called when a panel receives a command + MESSAGE_FUNC( OnMouseCaptureLost, "MouseCaptureLost" ); // called after the panel loses mouse capture + MESSAGE_FUNC( OnSetFocus, "SetFocus" ); // called after the panel receives the keyboard focus + MESSAGE_FUNC( OnKillFocus, "KillFocus" ); // called after the panel loses the keyboard focus + MESSAGE_FUNC( OnDelete, "Delete" ); // called to delete the panel; Panel::OnDelete() does simply { delete this; } + virtual void OnThink(); // called every frame before painting, but only if panel is visible + virtual void OnChildAdded(VPANEL child); // called when a child has been added to this panel + virtual void OnSizeChanged(int newWide, int newTall); // called after the size of a panel has been changed + + // called every frame if ivgui()->AddTickSignal() is called + virtual void OnTick(); + + // input messages + MESSAGE_FUNC_INT_INT( OnCursorMoved, "OnCursorMoved", x, y ); + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + virtual void OnMouseMismatchedRelease( MouseCode code, Panel* pPressedPanel ); + virtual void OnMouseWheeled(int delta); + + // Trip pressing (e.g., select all text in a TextEntry) requires this to be enabled + virtual void SetTriplePressAllowed( bool state ); + virtual bool IsTriplePressAllowed() const; + virtual void OnMouseTriplePressed( MouseCode code ); + + static char const *KeyCodeToString( KeyCode code ); + static wchar_t const *KeyCodeToDisplayString( KeyCode code ); + static wchar_t const *KeyCodeModifiersToDisplayString( KeyCode code, int modifiers ); // L"Ctrl+Alt+Shift+Backspace" + + static KeyCode StringToKeyCode( char const *str ); +#if defined( VGUI_USEKEYBINDINGMAPS ) + static KeyBindingContextHandle_t CreateKeyBindingsContext( char const *filename, char const *pathID = 0 ); + virtual void SetKeyBindingsContext( KeyBindingContextHandle_t handle ); + virtual KeyBindingContextHandle_t GetKeyBindingsContext() const; + virtual bool IsValidKeyBindingsContext() const; + + static int GetPanelsWithKeyBindingsCount( KeyBindingContextHandle_t handle ); + static Panel *GetPanelWithKeyBindings( KeyBindingContextHandle_t handle, int index ); + + static void RevertKeyBindings( KeyBindingContextHandle_t handle ); + + static void ReloadKeyBindings( KeyBindingContextHandle_t handle ); + static void SaveKeyBindings( KeyBindingContextHandle_t handle ); + static void SaveKeyBindingsToFile( KeyBindingContextHandle_t handle, char const *filename, char const *pathID = 0 ); + static void LoadKeyBindings( KeyBindingContextHandle_t handle ); + static void LoadKeyBindingsForOnePanel( KeyBindingContextHandle_t handle, Panel *panelOfInterest ); + + // OnKeyCodeTyped hooks into here for action + virtual bool IsKeyRebound( KeyCode code, int modifiers ); + // If a panel implements this and returns true, then the IsKeyRebound check will fail and OnKeyCodeTyped messages will pass through.. + // sort of like setting the SetAllowKeyBindingChainToParent flag to false for specific keys + virtual bool IsKeyOverridden( KeyCode code, int modifiers ); + + virtual void AddKeyBinding( char const *bindingName, int keycode, int modifiers ); + + KeyBindingMap_t *LookupBinding( char const *bindingName ); + KeyBindingMap_t *LookupBindingByKeyCode( KeyCode code, int modifiers ); + void LookupBoundKeys( char const *bindingName, CUtlVector< BoundKey_t * >& list ); + BoundKey_t *LookupDefaultKey( char const *bindingName ); + PanelKeyBindingMap *LookupMapForBinding( char const *bindingName ); + + // Returns the number of keybindings + int GetKeyMappingCount( ); + + void RevertKeyBindingsToDefault(); + void RemoveAllKeyBindings(); + void ReloadKeyBindings(); + virtual void EditKeyBindings(); + + // calls RevertKeyBindingsToDefault() and then LoadKeyBindingsForOnePanel( GetKeyBindingsContext(), this ); + void SaveKeyBindingsToBuffer( int level, CUtlBuffer& buf ); + bool ParseKeyBindings( KeyValues *kv ); + + virtual char const *GetKeyBindingsFile() const; + virtual char const *GetKeyBindingsFilePathID() const; + + // Set this to false to disallow IsKeyRebound chaining to GetParent() Panels... + void SetAllowKeyBindingChainToParent( bool state ); + bool IsKeyBindingChainToParentAllowed() const; +#endif // VGUI_USEKEYBINDINGMAPS + + // base implementation forwards Key messages to the Panel's parent + // - override to 'swallow' the input + virtual void OnKeyCodePressed(KeyCode code); + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + virtual void OnKeyCodeReleased(KeyCode code); + virtual void OnKeyFocusTicked(); // every window gets key ticked events + + // forwards mouse messages to the panel's parent + MESSAGE_FUNC( OnMouseFocusTicked, "OnMouseFocusTicked" ); + + // message handlers that don't go through the message pump + virtual void PaintBackground(); + virtual void Paint(); + virtual void PaintBorder(); + virtual void PaintBuildOverlay(); // the extra drawing for when in build mode + virtual void PostChildPaint(); + virtual void PerformLayout(); + + // this enables message mapping for this class - requires matching IMPLEMENT_PANELDESC() in the .cpp file + DECLARE_PANELMAP(); + + virtual VPANEL GetCurrentKeyFocus(); + + // returns a pointer to the tooltip object associated with the panel + // creates a new one if none yet exists + BaseTooltip *GetTooltip(); + void SetTooltip( BaseTooltip *pToolTip, const char *pszText ); + + /// Returns the effective tooltip text to use, whether stored + /// locally in this panel, or in the tooltip object. Returns + /// an empty string if no tooltip text + const char *GetEffectiveTooltipText() const; + + // proportional mode settings + virtual bool IsProportional() { return _flags.IsFlagSet( IS_PROPORTIONAL ); } + virtual void SetProportional(bool state); + + // input interest + virtual void SetMouseInputEnabled( bool state ); + virtual void SetKeyBoardInputEnabled( bool state ); + virtual bool IsMouseInputEnabled(); + virtual bool IsKeyBoardInputEnabled(); + + virtual void DrawTexturedBox( int x, int y, int wide, int tall, Color color, float normalizedAlpha ); + virtual void DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, bool hollow = false ); + virtual void DrawBoxFade(int x, int y, int wide, int tall, Color color, float normalizedAlpha, unsigned int alpha0, unsigned int alpha1, bool bHorizontal, bool hollow = false ); + virtual void DrawHollowBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha ); + //============================================================================= + // HPE_BEGIN: + //============================================================================= + + // [menglish] Draws a hollow box similar to the already existing draw hollow box function, but takes the indents as params + virtual void DrawHollowBox( int x, int y, int wide, int tall, Color color, float normalizedAlpha, int cornerWide, int cornerTall ); + + // [tj] Simple getters and setters to decide which corners to draw rounded + unsigned char GetRoundedCorners() { return m_roundedCorners; } + void SetRoundedCorners (unsigned char cornerFlags) { m_roundedCorners = cornerFlags; } + bool ShouldDrawTopLeftCornerRounded() { return ( m_roundedCorners & PANEL_ROUND_CORNER_TOP_LEFT ) != 0; } + bool ShouldDrawTopRightCornerRounded() { return ( m_roundedCorners & PANEL_ROUND_CORNER_TOP_RIGHT ) != 0; } + bool ShouldDrawBottomLeftCornerRounded() { return ( m_roundedCorners & PANEL_ROUND_CORNER_BOTTOM_LEFT ) != 0; } + bool ShouldDrawBottomRightCornerRounded() { return ( m_roundedCorners & PANEL_ROUND_CORNER_BOTTOM_RIGHT ) != 0; } + + //============================================================================= + // HPE_END + //============================================================================= + +// Drag Drop Public interface + + virtual void SetDragEnabled( bool enabled ); + virtual bool IsDragEnabled() const; + + virtual void SetShowDragHelper( bool enabled ); + + // Called if drag drop is started but not dropped on top of droppable panel... + virtual void OnDragFailed( CUtlVector< KeyValues * >& msglist ); + + // Use this to prevent chaining up from a parent which can mess with mouse functionality if you don't want to chain up from a child panel to the best + // draggable parent. + virtual void SetBlockDragChaining( bool block ); + virtual bool IsBlockingDragChaining() const; + + virtual int GetDragStartTolerance() const; + virtual void SetDragSTartTolerance( int nTolerance ); + + // If hover context time is non-zero, then after the drop cursor is hovering over the panel for that amount of time + // the Show hover context menu function will be invoked + virtual void SetDropEnabled( bool enabled, float m_flHoverContextTime = 0.0f ); + virtual bool IsDropEnabled() const; + + // Called if m_flHoverContextTime was non-zero, allows droppee to preview the drop data and show an appropriate menu + // Return false if not using context menu + virtual bool GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist ); + virtual void OnDropContextHoverShow( CUtlVector< KeyValues * >& msglist ); + virtual void OnDropContextHoverHide( CUtlVector< KeyValues * >& msglist ); + +#if defined( VGUI_USEDRAGDROP ) + virtual DragDrop_t *GetDragDropInfo(); +#endif + // For handling multiple selections... + virtual void OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles ); + + virtual void OnCreateDragData( KeyValues *msg ); + // Called to see if a drop enabled panel can accept the specified data blob + virtual bool IsDroppable( CUtlVector< KeyValues * >& msglist ); + + // Mouse is on draggable panel and has started moving, but is not over a droppable panel yet + virtual void OnDraggablePanelPaint(); + // Mouse is now over a droppable panel + virtual void OnDroppablePanelPaint( CUtlVector< KeyValues * >& msglist, CUtlVector< Panel * >& dragPanels ); + + virtual void OnPanelDropped( CUtlVector< KeyValues * >& msglist ); + + // called on droptarget when draggable panel entered/exited droptarget + virtual void OnPanelEnteredDroppablePanel( CUtlVector< KeyValues * >& msglist ); + virtual void OnPanelExitedDroppablePanel ( CUtlVector< KeyValues * >& msglist ); + + // Chains up to any parent marked DropEnabled + virtual Panel *GetDropTarget( CUtlVector< KeyValues * >& msglist ); + // Chains up to first parent marked DragEnabled + virtual Panel *GetDragPanel(); + virtual bool IsBeingDragged(); + virtual HCursor GetDropCursor( CUtlVector< KeyValues * >& msglist ); + + Color GetDropFrameColor(); + Color GetDragFrameColor(); + + // Can override to require custom behavior to start the drag state + virtual bool CanStartDragging( int startx, int starty, int mx, int my ); + + // Draws a filled rect of specified bounds, but omits the bounds of the skip panel from those bounds + virtual void FillRectSkippingPanel( const Color &clr, int x, int y, int w, int h, Panel *skipPanel ); + + virtual int GetPaintBackgroundType(); + virtual void GetCornerTextureSize( int& w, int& h ); + + bool IsChildOfModalSubTree(); + bool IsChildOfSurfaceModalPanel(); + + bool ShouldHandleInputMessage(); + + virtual void SetSkipChildDuringPainting( Panel *child ); + + // If this is set, then the drag drop won't occur until the mouse leaves the drag panels current rectangle + void SetStartDragWhenMouseExitsPanel( bool state ); + bool IsStartDragWhenMouseExitsPanel() const; + + void DisableMouseInputForThisPanel( bool bDisable ); + bool IsMouseInputDisabledForThisPanel() const; + + bool GetForceStereoRenderToFrameBuffer() const { return m_bForceStereoRenderToFrameBuffer; } + void SetForceStereoRenderToFrameBuffer( bool bForce ) { m_bForceStereoRenderToFrameBuffer = bForce; } + + void PostMessageToAllSiblings( KeyValues *msg, float delaySeconds = 0.0f ); + template< class S > + void PostMessageToAllSiblingsOfType( KeyValues *msg, float delaySeconds = 0.0f ); + + void SetConsoleStylePanel( bool bConsoleStyle ); + bool IsConsoleStylePanel() const; + + void SetParentNeedsCursorMoveEvents( bool bNeedsEvents ) { m_bParentNeedsCursorMoveEvents = bNeedsEvents; } + bool ParentNeedsCursorMoveEvents() const { return m_bParentNeedsCursorMoveEvents; } + + int ComputePos( const char *pszInput, int &nPos, const int& nSize, const int& nParentSize, const bool& bX ); + + // For 360: support directional navigation between UI controls via dpad + enum NAV_DIRECTION { ND_UP, ND_DOWN, ND_LEFT, ND_RIGHT, ND_BACK, ND_NONE }; + virtual Panel* NavigateUp(); + virtual Panel* NavigateDown(); + virtual Panel* NavigateLeft(); + virtual Panel* NavigateRight(); + virtual Panel* NavigateActivate(); + virtual Panel* NavigateBack(); + virtual void NavigateTo(); + virtual void NavigateFrom(); + virtual void NavigateToChild( Panel *pNavigateTo ); //mouse support + // if set, Panel gets PerformLayout called after the camera and the renderer's m_matrixWorldToScreen has been setup, so panels can be correctly attached to entities in the world + inline void SetWorldPositionCurrentFrame( bool bWorldPositionCurrentFrame ) { m_bWorldPositionCurrentFrame = bWorldPositionCurrentFrame; } + inline bool GetWorldPositionCurrentFrame() { return m_bWorldPositionCurrentFrame; } + + Panel* SetNavUp( Panel* navUp ); + Panel* SetNavDown( Panel* navDown ); + Panel* SetNavLeft( Panel* navLeft ); + Panel* SetNavRight( Panel* navRight ); + Panel* SetNavToRelay( Panel* navToRelay ); + Panel* SetNavActivate( Panel* navActivate ); + Panel* SetNavBack( Panel* navBack ); + NAV_DIRECTION GetLastNavDirection(); + MESSAGE_FUNC_CHARPTR( OnNavigateTo, "OnNavigateTo", panelName ); + MESSAGE_FUNC_CHARPTR( OnNavigateFrom, "OnNavigateFrom", panelName ); + +// Drag Drop protected/internal interface +protected: + + virtual void OnStartDragging(); + virtual void OnContinueDragging(); + virtual void OnFinishDragging( bool mousereleased, MouseCode code, bool aborted = false ); + + virtual void DragDropStartDragging(); + + virtual void GetDragData( CUtlVector< KeyValues * >& list ); + virtual void CreateDragData(); + + virtual void PaintTraverse(bool Repaint, bool allowForce = true); + +protected: + virtual void OnChildSettingsApplied( KeyValues *pInResourceData, Panel *pChild ); + + MESSAGE_FUNC_ENUM_ENUM( OnRequestFocus, "OnRequestFocus", VPANEL, subFocus, VPANEL, defaultPanel); + MESSAGE_FUNC_INT_INT( OnScreenSizeChanged, "OnScreenSizeChanged", oldwide, oldtall ); + virtual void *QueryInterface(EInterfaceID id); + + void AddToOverridableColors( Color *pColor, char const *scriptname ) + { + int iIdx = m_OverridableColorEntries.AddToTail(); + m_OverridableColorEntries[iIdx].m_pszScriptName = scriptname; + m_OverridableColorEntries[iIdx].m_pColor = pColor; + m_OverridableColorEntries[iIdx].m_bOverridden = false; + } + + void ApplyOverridableColors( void ); + void SetOverridableColor( Color *pColor, const Color &newColor ); + +public: + void SetNavUp( const char* controlName ); + void SetNavDown( const char* controlName ); + void SetNavLeft( const char* controlName ); + void SetNavRight( const char* controlName ); + void SetNavToRelay( const char* controlName ); + void SetNavActivate( const char* controlName ); + void SetNavBack( const char* controlName ); + + /* + Will recursively look for the next visible panel in the navigation chain, parameters are for internal use. + It will stop looking if first == nextpanel (to prevent infinite looping). + */ + Panel* GetNavUp( Panel *first = NULL ); + Panel* GetNavDown( Panel *first = NULL ); + Panel* GetNavLeft( Panel *first = NULL ); + Panel* GetNavRight( Panel *first = NULL ); + Panel* GetNavToRelay( Panel *first = NULL ); + Panel* GetNavActivate( Panel *first = NULL ); + Panel* GetNavBack( Panel *first = NULL ); + + const char* GetNavUpName( void ) const { return m_sNavUpName.String(); } + const char* GetNavDownName( void ) const { return m_sNavDownName.String(); } + const char* GetNavLeftName( void ) const { return m_sNavLeftName.String(); } + const char* GetNavRightName( void ) const { return m_sNavRightName.String(); } + const char* GetNavToRelayName( void ) const { return m_sNavToRelayName.String(); } + const char* GetNavActivateName( void ) const { return m_sNavActivateName.String(); } + const char* GetNavBackName( void ) const { return m_sNavBackName.String(); } + +protected: + //this will return m_NavDown and will not look for the next visible panel + Panel* GetNavUpPanel(); + Panel* GetNavDownPanel(); + Panel* GetNavLeftPanel(); + Panel* GetNavRightPanel(); + Panel* GetNavToRelayPanel(); + Panel* GetNavActivatePanel(); + Panel* GetNavBackPanel(); + + bool m_PassUnhandledInput; + NAV_DIRECTION m_LastNavDirection; + +private: + enum BuildModeFlags_t + { + BUILDMODE_EDITABLE = 1 << 0, + BUILDMODE_DELETABLE = 1 << 1, + BUILDMODE_SAVE_XPOS_RIGHTALIGNED = 1 << 2, + BUILDMODE_SAVE_XPOS_CENTERALIGNED = 1 << 3, + BUILDMODE_SAVE_YPOS_BOTTOMALIGNED = 1 << 4, + BUILDMODE_SAVE_YPOS_CENTERALIGNED = 1 << 5, + BUILDMODE_SAVE_WIDE_FULL = 1 << 6, + BUILDMODE_SAVE_TALL_FULL = 1 << 7, + BUILDMODE_SAVE_PROPORTIONAL_TO_PARENT = 1 << 8, + BUILDMODE_SAVE_WIDE_PROPORTIONAL = 1 << 9, + BUILDMODE_SAVE_TALL_PROPORTIONAL = 1 << 10, + BUILDMODE_SAVE_XPOS_PROPORTIONAL_SELF = 1 << 11, + BUILDMODE_SAVE_YPOS_PROPORTIONAL_SELF = 1 << 12, + BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL = 1 << 13, + BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE = 1 << 14, + BUILDMODE_SAVE_XPOS_PROPORTIONAL_PARENT = 1 << 15, + BUILDMODE_SAVE_YPOS_PROPORTIONAL_PARENT = 1 << 16 + }; + + enum PanelFlags_t + { + MARKED_FOR_DELETION = 0x0001, + NEEDS_REPAINT = 0x0002, + PAINT_BORDER_ENABLED = 0x0004, + PAINT_BACKGROUND_ENABLED = 0x0008, + PAINT_ENABLED = 0x0010, + POST_CHILD_PAINT_ENABLED = 0x0020, + AUTODELETE_ENABLED = 0x0040, + NEEDS_LAYOUT = 0x0080, + NEEDS_SCHEME_UPDATE = 0x0100, + NEEDS_DEFAULT_SETTINGS_APPLIED = 0x0200, +#if defined( VGUI_USEKEYBINDINGMAPS ) + ALLOW_CHAIN_KEYBINDING_TO_PARENT = 0x0400, +#endif + IN_PERFORM_LAYOUT = 0x0800, + IS_PROPORTIONAL = 0x1000, + TRIPLE_PRESS_ALLOWED = 0x2000, + DRAG_REQUIRES_PANEL_EXIT = 0x4000, + IS_MOUSE_DISABLED_FOR_THIS_PANEL_ONLY = 0x8000, + ALL_FLAGS = 0xFFFF, + }; + + int ComputeWide( KeyValues *inResourceData, int nParentWide, int nParentTall, bool bComputingForTall ); + int ComputeTall( KeyValues *inResourceData, int nParentWide, int nParentTall, bool bComputingForWide ); + + // used to get the Panel * for users with only IClientPanel + virtual Panel *GetPanel() { return this; } + + // private methods + void Think(); + void PerformApplySchemeSettings(); + + void InternalPerformLayout(); + void InternalSetCursor(); + + MESSAGE_FUNC_INT_INT( InternalCursorMoved, "CursorMoved", xpos, ypos ); + MESSAGE_FUNC( InternalCursorEntered, "CursorEntered" ); + MESSAGE_FUNC( InternalCursorExited, "CursorExited" ); + + MESSAGE_FUNC_INT( InternalMousePressed, "MousePressed", code ); + MESSAGE_FUNC_INT( InternalMouseDoublePressed, "MouseDoublePressed", code ); + // Triple presses are synthesized + MESSAGE_FUNC_INT( InternalMouseTriplePressed, "MouseTriplePressed", code ); + MESSAGE_FUNC_INT( InternalMouseReleased, "MouseReleased", code ); + MESSAGE_FUNC_INT( InternalMouseWheeled, "MouseWheeled", delta ); + MESSAGE_FUNC_INT( InternalKeyCodePressed, "KeyCodePressed", code ); + MESSAGE_FUNC_INT( InternalKeyCodeTyped, "KeyCodeTyped", code ); + MESSAGE_FUNC_INT( InternalKeyTyped, "KeyTyped", unichar ); + MESSAGE_FUNC_INT( InternalKeyCodeReleased, "KeyCodeReleased", code ); + + MESSAGE_FUNC( InternalKeyFocusTicked, "KeyFocusTicked" ); + MESSAGE_FUNC( InternalMouseFocusTicked, "MouseFocusTicked" ); + + MESSAGE_FUNC( InternalInvalidateLayout, "Invalidate" ); + + MESSAGE_FUNC( InternalMove, "Move" ); + virtual void InternalFocusChanged(bool lost); // called when the focus gets changed + + void PreparePanelMap( PanelMap_t *panelMap ); + + bool InternalRequestInfo( PanelAnimationMap *map, KeyValues *outputData ); + bool InternalSetInfo( PanelAnimationMap *map, KeyValues *inputData ); + + PanelAnimationMapEntry *FindPanelAnimationEntry( char const *scriptname, PanelAnimationMap *map ); + + // Recursively invoke settings for PanelAnimationVars + void InternalApplySettings( PanelAnimationMap *map, KeyValues *inResourceData); + void InternalInitDefaultValues( PanelAnimationMap *map ); + + // Purpose: Loads panel details related to autoresize from the resource info + void ApplyAutoResizeSettings(KeyValues *inResourceData); + + void FindDropTargetPanel_R( CUtlVector< VPANEL >& panelList, int x, int y, VPANEL check ); + Panel *FindDropTargetPanel(); + + int GetProportionalScaledValue( int rootTall, int normalizedValue ); + +#if defined( VGUI_USEDRAGDROP ) + DragDrop_t *m_pDragDrop; + Color m_clrDragFrame; + Color m_clrDropFrame; +#endif + + BaseTooltip *m_pTooltips; + bool m_bToolTipOverridden; + + PHandle m_SkipChild; + long m_lLastDoublePressTime; + HFont m_infoFont; + +#if defined( VGUI_USEKEYBINDINGMAPS ) + KeyBindingContextHandle_t m_hKeyBindingsContext; +#endif + + // data + VPANEL _vpanel; // handle to a vgui panel + char *_panelName; // string name of the panel - only unique within the current context + IBorder *_border; + + CUtlFlags< unsigned short > _flags; // see PanelFlags_t + Dar _actionSignalTargetDar; // the panel to direct notify messages to ("Command", "TextChanged", etc.) + + CUtlVector m_OverridableColorEntries; + + Color _fgColor; // foreground color + Color _bgColor; // background color + + HBuildGroup _buildGroup; + + short m_nPinDeltaX; // Relative position of the pinned corner to the edge + short m_nPinDeltaY; + short m_nResizeDeltaX; // Relative position of the non-pinned corner to the edge + short m_nResizeDeltaY; + + HCursor _cursor; + unsigned short _buildModeFlags; // flags that control how the build mode dialog handles this panel + + byte _pinCorner : 4; // the corner of the dialog this panel is pinned to + byte _autoResizeDirection : 4; // the directions in which the panel will auto-resize to + + unsigned char _tabPosition; // the panel's place in the tab ordering + HScheme m_iScheme; // handle to the scheme to use + + bool m_bIsDMXSerialized : 1; // Is this a DMX panel? + bool m_bUseSchemeColors : 1; // Should we use colors from the scheme? + bool m_bIsSilent : 1; // should this panel PostActionSignals? + bool m_bIsConsoleStylePanel : 1; + bool m_bParentNeedsCursorMoveEvents : 1; + + // Sibling pinning + char *_pinToSibling; // string name of the sibling panel we're pinned to + byte _pinToSiblingCorner; // the corner of the sibling panel we're pinned to + byte _pinCornerToSibling; // the corner of our panel that we're pinning to our sibling + PHandle m_pinSibling; + + CUtlString m_sNavUpName; + PHandle m_NavUp; + + CUtlString m_sNavDownName; + PHandle m_NavDown; + + CUtlString m_sNavLeftName; + PHandle m_NavLeft; + + CUtlString m_sNavRightName; + PHandle m_NavRight; + + CUtlString m_sNavToRelayName; + PHandle m_NavToRelay; + + CUtlString m_sNavActivateName; + PHandle m_NavActivate; + + CUtlString m_sNavBackName; + PHandle m_NavBack; + +private: + + char *_tooltipText; // Tool tip text for panels that share tooltip panels with other panels + + PHandle m_hMouseEventHandler; + + bool m_bWorldPositionCurrentFrame; // if set, Panel gets PerformLayout called after the camera and the renderer's m_matrixWorldToScreen has been setup, so panels can be correctly attached to entities in the world + + bool m_bForceStereoRenderToFrameBuffer; + + static Panel* m_sMousePressedPanels[ ( MOUSE_MIDDLE - MOUSE_LEFT ) + 1 ]; + + CPanelAnimationVar( float, m_flAlpha, "alpha", "255" ); + + // 1 == Textured (TextureId1 only) + // 2 == Rounded Corner Box + CPanelAnimationVar( int, m_nPaintBackgroundType, "PaintBackgroundType", "0" ); + CPanelAnimationVarAliasType( int, m_nBgTextureId1, "Texture1", "vgui/hud/800corner1", "textureid" ); + CPanelAnimationVarAliasType( int, m_nBgTextureId2, "Texture2", "vgui/hud/800corner2", "textureid" ); + CPanelAnimationVarAliasType( int, m_nBgTextureId3, "Texture3", "vgui/hud/800corner3", "textureid" ); + CPanelAnimationVarAliasType( int, m_nBgTextureId4, "Texture4", "vgui/hud/800corner4", "textureid" ); + + //============================================================================= + // HPE_BEGIN: + // [tj] A bitset of flags to determine which corners should be rounded + //============================================================================= + unsigned char m_roundedCorners; + //============================================================================= + // HPE_END + //============================================================================= + friend class BuildGroup; + friend class BuildModeDialog; + friend class PHandle; + + // obselete, remove soon + void OnOldMessage(KeyValues *params, VPANEL ifromPanel); +}; + +inline void Panel::DisableMouseInputForThisPanel( bool bDisable ) +{ + _flags.SetFlag( IS_MOUSE_DISABLED_FOR_THIS_PANEL_ONLY, bDisable ); +} + +inline bool Panel::IsMouseInputDisabledForThisPanel() const +{ + return _flags.IsFlagSet( IS_MOUSE_DISABLED_FOR_THIS_PANEL_ONLY ); +} + +#if 0 +// This function cannot be defined here because it requires on a full definition of +// KeyValues (to call KeyValues::MakeCopy()) whereas the rest of this header file +// assumes a forward declared definition of KeyValues. +template< class S > +inline void Panel::PostMessageToAllSiblingsOfType( KeyValues *msg, float delaySeconds /*= 0.0f*/ ) +{ + Panel *parent = GetParent(); + if ( parent ) + { + int nChildCount = parent->GetChildCount(); + for ( int i = 0; i < nChildCount; ++i ) + { + Panel *sibling = parent->GetChild( i ); + if ( sibling == this ) + continue; + if ( dynamic_cast< S * >( sibling ) ) + { + PostMessage( sibling->GetVPanel(), msg->MakeCopy(), delaySeconds ); + } + } + } + + msg->deleteThis(); +} +#endif + +class Button; + +struct SortedPanel_t +{ + SortedPanel_t( Panel *panel ); + + Panel *pPanel; + Button *pButton; +}; + +class CSortedPanelYLess +{ +public: + bool Less( const SortedPanel_t &src1, const SortedPanel_t &src2, void *pCtx ) + { + int nX1, nY1, nX2, nY2; + src1.pPanel->GetPos( nX1, nY1 ); + src2.pPanel->GetPos( nX2, nY2 ); + + if ( nY1 == nY2 ) + { + return ( nX1 < nX2 ); + } + + if ( nY1 < nY2 ) + { + return true; + } + + return false; + } +}; + + +void VguiPanelGetSortedChildPanelList( Panel *pParentPanel, void *pSortedPanels ); +void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, char *pchFilter = NULL, int nFilterType = 0 ); +int VguiPanelNavigateSortedChildButtonList( void *pSortedPanels, int nDir ); + + +} // namespace vgui + + +#endif // PANEL_H diff --git a/public/vgui_controls/PanelAnimationVar.h b/public/vgui_controls/PanelAnimationVar.h new file mode 100644 index 0000000..24c41c8 --- /dev/null +++ b/public/vgui_controls/PanelAnimationVar.h @@ -0,0 +1,161 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PANELANIMATIONVAR_H +#define PANELANIMATIONVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlvector.h" +#include + +#define DECLARE_PANELANIMATION( className ) \ + static void AddToAnimationMap( char const *scriptname, char const *type, char const *var, \ + char const *defaultvalue, bool array, PANELLOOKUPFUNC func ) \ + { \ + PanelAnimationMap *map = FindOrAddPanelAnimationMap( GetPanelClassName() ); \ + \ + PanelAnimationMapEntry entry; \ + entry.m_pszScriptName = scriptname; \ + entry.m_pszVariable = var; \ + entry.m_pszType = type; \ + entry.m_pszDefaultValue = defaultvalue; \ + entry.m_pfnLookup = func; \ + entry.m_bArray = array; \ + \ + map->entries.AddToTail( entry ); \ + } \ + \ + static void ChainToAnimationMap( void ) \ + { \ + static bool chained = false; \ + if ( chained ) \ + return; \ + chained = true; \ + PanelAnimationMap *map = FindOrAddPanelAnimationMap( GetPanelClassName() ); \ + map->pfnClassName = GetPanelClassName; \ + if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] ) \ + { \ + map->baseMap = FindOrAddPanelAnimationMap( GetPanelBaseClassName() ); \ + } \ + } \ + \ + class className##_Register; \ + friend class className##_Register; \ + class className##_Register \ + { \ + public: \ + className##_Register() \ + { \ + className::ChainToAnimationMap(); \ + } \ + }; \ + className##_Register m_RegisterAnimationClass; \ + \ + virtual PanelAnimationMap *GetAnimMap() \ + { \ + return FindOrAddPanelAnimationMap( GetPanelClassName() ); \ + } + +typedef void *( *PANELLOOKUPFUNC )( vgui::Panel *panel ); + +// Use this macro to define a variable which hudanimations.txt and hudlayout.res scripts can access +#define CPanelAnimationVarAliasType( type, name, scriptname, defaultvalue, typealias ) \ + class PanelAnimationVar_##name; \ + friend class PanelAnimationVar_##name; \ + static void *GetVar_##name( vgui::Panel *panel ) \ + { \ + return &(( ThisClass *)panel)->name; \ + } \ + class PanelAnimationVar_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + AddToAnimationMap( scriptname, typealias, #name, defaultvalue, false, ThisClass::GetVar_##name ); \ + } \ + } \ + PanelAnimationVar_##name() \ + { \ + PanelAnimationVar_##name::InitVar(); \ + } \ + }; \ + PanelAnimationVar_##name m_##name##_register; \ + type name; + +#define CPanelAnimationVar( type, name, scriptname, defaultvalue ) \ + CPanelAnimationVarAliasType( type, name, scriptname, defaultvalue, #type ) + +// Use this macro to define a variable which hudanimations.txt and hudlayout.res scripts can access +#define CPanelAnimationStringVarAliasType( count, name, scriptname, defaultvalue, typealias ) \ + class PanelAnimationVar_##name; \ + friend class PanelAnimationVar_##name; \ + static void *GetVar_##name( vgui::Panel *panel ) \ + { \ + return &(( ThisClass *)panel)->name; \ + } \ + class PanelAnimationVar_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + AddToAnimationMap( scriptname, typealias, #name, defaultvalue, true, ThisClass::GetVar_##name ); \ + } \ + } \ + PanelAnimationVar_##name() \ + { \ + PanelAnimationVar_##name::InitVar(); \ + } \ + }; \ + PanelAnimationVar_##name m_##name##_register; \ + char name[ count ]; + +#define CPanelAnimationStringVar( count, name, scriptname, defaultvalue ) \ + CPanelAnimationStringVarAliasType( count, name, scriptname, defaultvalue, "string" ) + +struct PanelAnimationMapEntry +{ + char const *name() { return m_pszScriptName; } + char const *type() { return m_pszType; } + char const *defaultvalue() { return m_pszDefaultValue; } + bool isarray() { return m_bArray; } + + char const *m_pszScriptName; + char const *m_pszVariable; + char const *m_pszType; + char const *m_pszDefaultValue; + bool m_bArray; + + PANELLOOKUPFUNC m_pfnLookup; +}; + +struct PanelAnimationMap +{ + PanelAnimationMap() + { + baseMap = NULL; + pfnClassName = NULL; + } + + CUtlVector< PanelAnimationMapEntry > entries; + PanelAnimationMap *baseMap; + char const *(*pfnClassName)( void ); +}; + +PanelAnimationMap *FindPanelAnimationMap( char const *className ); +PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className ); +void PanelAnimationDumpVars( char const *className ); + +#endif // PANELANIMATIONVAR_H diff --git a/public/vgui_controls/PanelListPanel.h b/public/vgui_controls/PanelListPanel.h new file mode 100644 index 0000000..c4a647e --- /dev/null +++ b/public/vgui_controls/PanelListPanel.h @@ -0,0 +1,126 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PANELLISTPANEL_H +#define PANELLISTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include + +class KeyValues; + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: A list of variable height child panels +// each list item consists of a label-panel pair. Height of the item is +// determined from the label. +//----------------------------------------------------------------------------- +class PanelListPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( PanelListPanel, Panel ); + +public: + PanelListPanel( vgui::Panel *parent, char const *panelName ); + ~PanelListPanel(); + + // DATA & ROW HANDLING + // The list now owns the panel + virtual int AddItem( Panel *labelPanel, Panel *panel ); + int GetItemCount() const; + int GetItemIDFromRow( int nRow ) const; + + // Iteration. Use these until they return InvalidItemID to iterate all the items. + int FirstItem() const; + int NextItem( int nItemID ) const; + int InvalidItemID() const; + + virtual Panel *GetItemLabel(int itemID); + virtual Panel *GetItemPanel(int itemID); + + ScrollBar* GetScrollbar() { return m_vbar; } + + virtual void RemoveItem(int itemID); // removes an item from the table (changing the indices of all following items) + virtual void DeleteAllItems(); // clears and deletes all the memory used by the data items + void RemoveAll(); + + // painting + virtual vgui::Panel *GetCellRenderer( int row ); + + // layout + void SetFirstColumnWidth( int width ); + int GetFirstColumnWidth(); + void SetNumColumns( int iNumColumns ); + int GetNumColumns( void ); + void MoveScrollBarToTop(); + + // selection + void SetSelectedPanel( Panel *panel ); + Panel *GetSelectedPanel(); + /* + On a panel being selected, a message gets sent to it + "PanelSelected" int "state" + where state is 1 on selection, 0 on deselection + */ + + void SetVerticalBufferPixels( int buffer ); + + void ScrollToItem( int itemNumber ); + + CUtlVector< int > *GetSortedVector( void ) + { + return &m_SortedItems; + } + + int ComputeVPixelsNeeded(); + +protected: + // overrides + virtual void OnSizeChanged(int wide, int tall); + MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position ); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void OnMouseWheeled(int delta); + +private: + + + enum { DEFAULT_HEIGHT = 24, PANELBUFFER = 5 }; + + typedef struct dataitem_s + { + // Always store a panel pointer + Panel *panel; + Panel *labelPanel; + } DATAITEM; + + // list of the column headers + + CUtlLinkedList m_DataItems; + CUtlVector m_SortedItems; + + ScrollBar *m_vbar; + Panel *m_pPanelEmbedded; + + PHandle m_hSelectedItem; + int m_iFirstColumnWidth; + int m_iNumColumns; + int m_iDefaultHeight; + int m_iPanelBuffer; + + CPanelAnimationVar( bool, m_bAutoHideScrollbar, "autohide_scrollbar", "0" ); +}; + +} +#endif // PANELLISTPANEL_H diff --git a/public/vgui_controls/PerforceFileExplorer.h b/public/vgui_controls/PerforceFileExplorer.h new file mode 100644 index 0000000..4d3dd87 --- /dev/null +++ b/public/vgui_controls/PerforceFileExplorer.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Allows you to browse a directory structure, showing perforce files +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PERFORCEFILEEXPLORER_H +#define PERFORCEFILEEXPLORER_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/utlstring.h" +#include "vgui_controls/Frame.h" + + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class PerforceFileList; +class ComboBox; +class Button; + + +//----------------------------------------------------------------------------- +// Contains a list of files, determines their perforce status +//----------------------------------------------------------------------------- +class PerforceFileExplorer : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( PerforceFileExplorer, Frame ); + +public: + // The context keyvalues are added to all messages sent by this dialog if they are specified + PerforceFileExplorer( Panel *parent, const char *pPanelName ); + ~PerforceFileExplorer(); + + // Inherited from Frame + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void PerformLayout(); + +protected: + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv ); + MESSAGE_FUNC( OnItemDoubleClicked, "ItemDoubleClicked" ); + MESSAGE_FUNC( OnFolderUp, "FolderUp" ); + + void PopulateFileList(); + void PopulateDriveList(); + + // Returns the current directory + void SetCurrentDirectory( const char *pCurrentDirectory ); + + Button *m_pFolderUpButton; + ComboBox *m_pFullPathCombo; + PerforceFileList *m_pFileList; + CUtlString m_CurrentDirectory; +}; + + +} // namespace vgui + +#endif // PERFORCEFILEEXPLORER_H diff --git a/public/vgui_controls/PerforceFileList.h b/public/vgui_controls/PerforceFileList.h new file mode 100644 index 0000000..148b005 --- /dev/null +++ b/public/vgui_controls/PerforceFileList.h @@ -0,0 +1,114 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains a list of files, determines their perforce status +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef PERFORCEFILELIST_H +#define PERFORCEFILELIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlstring.h" +#include "tier1/UtlStringMap.h" +#include "vgui_controls/ListPanel.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct P4File_t; + +namespace vgui +{ + class ListPanel; +} + + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Contains a list of files, determines their perforce status +//----------------------------------------------------------------------------- +class PerforceFileList : public vgui::ListPanel +{ + DECLARE_CLASS_SIMPLE( PerforceFileList, ListPanel ); + +public: + // The context keyvalues are added to all messages sent by this dialog if they are specified + PerforceFileList( Panel *parent, const char *pPanelName ); + ~PerforceFileList(); + + // Add a file to the file list. Note that this file may exist on disk or not + // and it may exist in perforce or not. It's specified as a full path on disk though. + // In the case where a file doesn't exist on disk, but it does exist in perforce + // specify where that file would appear on disk. + // This function returns the itemID of the added file + // If you already know the file exists or is a directory (or not), specify that in the call. + // -1 means autodetect whether the file exists or is a directory + int AddFile( const char *pFullPath, int nFileExists = -1, int nIsDirectory = -1 ); + + // Is a file already in the list? + bool IsFileInList( const char *pFullPath ); + + // Find the item ID associated with a particular file + int FindFile( const char *pFullPath ); + + // Remove all files from the list + void RemoveAllFiles(); + + // Refresh perforce information + void Refresh(); + + // Refresh perforce information manually + void RefreshPerforceState( int nItemID, bool bFileExists, P4File_t *pFileInfo ); + + // Is a particular list item a directory? + bool IsDirectoryItem( int nItemID ); + + // Returns the file associated with a particular item ID + const char *GetFile( int nItemID ); + + // Toggle showing deleted files or not + void ShowDeletedFiles( bool bShowDeletedFiles ); + + // Inherited from vgui::EditablePanel + virtual void ApplySchemeSettings( IScheme *pScheme ); + virtual void OnMouseDoublePressed( MouseCode code ); + + /* + messages sent: + "ItemDoubleClicked" // Called when an item is double-clicked + */ + +protected: + struct DirectoryInfo_t + { + CUtlString m_ClientSpec; + CUtlVector< int > m_ItemIDs; + }; + + // Add a file to the file list. + int AddFileToFileList( const char *pFullPath, bool bExistsOnDisk ); + + // Add a directory to the file list. + int AddDirectoryToFileList( const char *pFullPath, bool bExistsOnDisk ); + + // Add a directory to the directory list, returns client spec + void AddItemToDirectoryList( const char *pFullPath, int nItemID, bool bIsDirectory ); + + // Used to look up directories -> client specs + CUtlStringMap< DirectoryInfo_t > m_Directories; + + // Show deleted files? + bool m_bShowDeletedFiles; +}; + + +} // namespace vgui + +#endif // PERFORCEFILELIST_H diff --git a/public/vgui_controls/ProgressBar.h b/public/vgui_controls/ProgressBar.h new file mode 100644 index 0000000..a91269b --- /dev/null +++ b/public/vgui_controls/ProgressBar.h @@ -0,0 +1,103 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Status bar that visually displays discrete progress in the form +// of a segmented strip +//----------------------------------------------------------------------------- +class ProgressBar : public Panel +{ + DECLARE_CLASS_SIMPLE( ProgressBar, Panel ); + +public: + ProgressBar(Panel *parent, const char *panelName); + ~ProgressBar(); + + // 'progress' is in the range [0.0f, 1.0f] + MESSAGE_FUNC_FLOAT( SetProgress, "SetProgress", progress ); + float GetProgress(); + virtual void SetSegmentInfo( int gap, int width ); + + // utility function for calculating a time remaining string + static bool ConstructTimeRemainingString(OUT_Z_BYTECAP(outputBufferSizeInBytes) wchar_t *output, int outputBufferSizeInBytes, float startTime, float currentTime, float currentProgress, float lastProgressUpdateTime, bool addRemainingSuffix); + + void SetBarInset( int pixels ); + int GetBarInset( void ); + void SetMargin( int pixels ); + int GetMargin(); + + virtual void ApplySettings(KeyValues *inResourceData); + virtual void GetSettings(KeyValues *outResourceData); + virtual const char *GetDescription(); + + // returns the number of segment blocks drawn + int GetDrawnSegmentCount(); + + enum ProgressDir_e + { + PROGRESS_EAST, + PROGRESS_WEST, + PROGRESS_NORTH, + PROGRESS_SOUTH + }; + + int GetProgressDirection() const { return m_iProgressDirection; } + void SetProgressDirection( int val ) { m_iProgressDirection = val; } + +protected: + virtual void Paint(); + void PaintSegment( int &x, int &y, int tall, int wide ); + virtual void PaintBackground(); + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_PARAMS( OnDialogVariablesChanged, "DialogVariables", dialogVariables ); + /* CUSTOM MESSAGE HANDLING + "SetProgress" + input: "progress" - float value of the progress to set + */ + +protected: + int m_iProgressDirection; + float _progress; + +private: + int _segmentCount; + int _segmentGap; + int _segmentWide; + int m_iBarInset; + int m_iBarMargin; + char *m_pszDialogVar; +}; + +//----------------------------------------------------------------------------- +// Purpose: Non-segmented progress bar +//----------------------------------------------------------------------------- +class ContinuousProgressBar : public ProgressBar +{ + DECLARE_CLASS_SIMPLE( ContinuousProgressBar, ProgressBar ); + +public: + ContinuousProgressBar(Panel *parent, const char *panelName); + + virtual void Paint(); +}; + +} // namespace vgui + +#endif // PROGRESSBAR_H diff --git a/public/vgui_controls/ProgressBox.h b/public/vgui_controls/ProgressBox.h new file mode 100644 index 0000000..d5c321a --- /dev/null +++ b/public/vgui_controls/ProgressBox.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROGRESSBOX_H +#define PROGRESSBOX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +// prevent windows macros from messing with the class +#ifdef ProgressBox +#undef ProgressBox +#endif + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Popup discardable message box +//----------------------------------------------------------------------------- +class ProgressBox : public Frame +{ + DECLARE_CLASS_SIMPLE( ProgressBox, Frame ); + +public: + // title - Text to be displayed in the title bar of the window + // text - Text message in the message box + // parent - parent panel of the message box, by default it has no parent. + ProgressBox(const char *title, const char *text, const char *pszUnknownTimeString, Panel *parent = NULL); + ProgressBox(const wchar_t *wszTitle, const wchar_t *wszText, const wchar_t *wszUnknownTimeString, Panel *parent = NULL); + ~ProgressBox(); + + // Put the message box into a modal state + virtual void DoModal(Frame *pFrameOver = NULL); + + // make the message box appear and in a modeless state + virtual void ShowWindow(Frame *pFrameOver = NULL); + + // updates progress bar, range [0, 1] + virtual void SetProgress(float progress); + + // sets the info text + virtual void SetText(const char *text); + + // toggles visibility of the close box. + virtual void SetCancelButtonVisible(bool state); + + // toggles the enabled state of the cancel button (for if it needs to be disabled part way through a process) + virtual void SetCancelButtonEnabled(bool state); + + /* custom messages: + + "ProgressBoxCancelled" + sent if the user pressed the cancel button (must be enabled & visible for this to happen) + + */ + +protected: + virtual void PerformLayout(); + virtual void OnClose(); + virtual void OnCloseFrameButtonPressed(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnThink(); + virtual void OnCommand(const char *command); + virtual void OnTick(); + + // called when the update has been cancelled + virtual void OnCancel(); + +private: + MESSAGE_FUNC( OnShutdownRequest, "ShutdownRequest" ); + void Init(); + void UpdateTitle(); + + Label *m_pMessageLabel; + ProgressBar *m_pProgressBar; + Button *m_pCancelButton; + + wchar_t m_wszTitleString[128]; + wchar_t m_wcsInfoString[128]; + wchar_t m_wszUnknownTimeString[128]; + + float m_flFirstProgressUpdate; + float m_flLastProgressUpdate; + float m_flCurrentProgress; +}; + +} // namespace vgui + + +#endif // PROGRESSBOX_H diff --git a/public/vgui_controls/PropertyDialog.h b/public/vgui_controls/PropertyDialog.h new file mode 100644 index 0000000..32747f0 --- /dev/null +++ b/public/vgui_controls/PropertyDialog.h @@ -0,0 +1,84 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROPERTYDIALOG_H +#define PROPERTYDIALOG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Simple frame that holds a property sheet +//----------------------------------------------------------------------------- +class PropertyDialog : public Frame +{ + DECLARE_CLASS_SIMPLE( PropertyDialog, Frame ); + +public: + PropertyDialog(Panel *parent, const char *panelName); + ~PropertyDialog(); + + // returns a pointer to the PropertySheet this dialog encapsulates + virtual PropertySheet *GetPropertySheet(); + + // wrapper for PropertySheet interface + virtual void AddPage(Panel *page, const char *title); + virtual Panel *GetActivePage(); + virtual void ResetAllData(); + virtual void ApplyChanges(); + + // sets the text on the OK/Cancel buttons, overriding the default + void SetOKButtonText(const char *text); + void SetCancelButtonText(const char *text); + void SetApplyButtonText(const char *text); + + // changes the visibility of the buttons + void SetOKButtonVisible(bool state); + void SetCancelButtonVisible(bool state); + void SetApplyButtonVisible(bool state); + + /* MESSAGES SENT + "ResetData" - sent when page is loaded. Data should be reloaded from document into controls. + "ApplyChanges" - sent when the OK / Apply button is pressed. Changed data should be written into document. + */ + +protected: + // Called when the OK button is pressed. Simply closes the dialog. + virtual bool OnOK(bool applyOnly); + + // called when the Cancel button is pressed + virtual void OnCancel(); + + // vgui overrides + virtual void PerformLayout(); + virtual void OnCommand(const char *command); + virtual void ActivateBuildMode(); + virtual void OnKeyCodeTyped(KeyCode code); + virtual void RequestFocus(int direction = 0); + + MESSAGE_FUNC( OnApplyButtonEnable, "ApplyButtonEnable" ); + void EnableApplyButton(bool bEnable); + +private: + PropertySheet *_propertySheet; + Button *_okButton; + Button *_cancelButton; + Button *_applyButton; + + CPanelAnimationVar( int, m_iSheetInsetBottom, "sheetinset_bottom", "32" ); +}; + +}; // vgui + +#endif // PROPERTYDIALOG_H diff --git a/public/vgui_controls/PropertyPage.h b/public/vgui_controls/PropertyPage.h new file mode 100644 index 0000000..8120ed0 --- /dev/null +++ b/public/vgui_controls/PropertyPage.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROPERTYPAGE_H +#define PROPERTYPAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Property page, as held by a set of property sheets +//----------------------------------------------------------------------------- +class PropertyPage : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( PropertyPage, EditablePanel ); + +public: + PropertyPage(Panel *parent, const char *panelName); + ~PropertyPage(); + + // Called when page is loaded. Data should be reloaded from document into controls. + MESSAGE_FUNC( OnResetData, "ResetData" ); + + // Called when the OK / Apply button is pressed. Changed data should be written into document. + MESSAGE_FUNC( OnApplyChanges, "ApplyChanges" ); + + // called when the page is shown/hidden + MESSAGE_FUNC( OnPageShow, "PageShow" ); + MESSAGE_FUNC( OnPageHide, "PageHide" ); + + virtual void OnKeyCodeTyped(KeyCode code); + virtual bool HasUserConfigSettings() { return true; } + + virtual void SetVisible(bool state); + +protected: + // called to be notified of the tab button used to Activate this page + // if overridden this must be chained back to + MESSAGE_FUNC_PTR( OnPageTabActivated, "PageTabActivated", panel ); + +private: + PHandle _pageTab; +}; + +} // namespace vgui + +#endif // PROPERTYPAGE_H diff --git a/public/vgui_controls/PropertySheet.h b/public/vgui_controls/PropertySheet.h new file mode 100644 index 0000000..d6fdf88 --- /dev/null +++ b/public/vgui_controls/PropertySheet.h @@ -0,0 +1,209 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PROPERTYSHEET_H +#define PROPERTYSHEET_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui/VGUI.h" +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/PHandle.h" +#include "utlvector.h" + +namespace vgui +{ + +class PageTab; +class ImagePanel; + +//----------------------------------------------------------------------------- +// Purpose: Tabbed property sheet. Holds and displays a set of Panel's +//----------------------------------------------------------------------------- +class PropertySheet : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( PropertySheet, EditablePanel ); + +public: + PropertySheet(Panel *parent, const char *panelName, bool draggableTabs = false ); + PropertySheet(Panel *parent, const char *panelName,ComboBox *combo); + ~PropertySheet(); + + virtual bool IsDraggableTab() const; + void SetDraggableTabs( bool state ); + + // Adds a page to the sheet. The first page added becomes the active sheet. + virtual void AddPage(Panel *page, const char *title, char const *imageName = NULL, bool showContextMenu = false ); + + // sets the current page + virtual void SetActivePage(Panel *page); + + // sets the width, in pixels, of the page tab buttons. + virtual void SetTabWidth(int pixels); + + // Gets a pointer to the currently active page. + virtual Panel *GetActivePage(); + + // Removes (but doesn't delete) all pages + virtual void RemoveAllPages(); + + // Removes all the pages and marks all the pages for deletion. + virtual void DeleteAllPages(); + + // reloads the data in all the property page + virtual void ResetAllData(); + + // writes out any changed data to the doc + virtual void ApplyChanges(); + + // focus handling - passed on to current active page + virtual void RequestFocus(int direction = 0); + virtual bool RequestFocusPrev(VPANEL panel = NULL); + virtual bool RequestFocusNext(VPANEL panel = NULL); + + // returns the ith panel + virtual Panel *GetPage(int i); + + // deletes this panel from the sheet + virtual void DeletePage(Panel *panel); + // removes this panel from the sheet, sets its parent to NULL, but does not delete it + virtual void RemovePage(Panel *panel); + + // returns the current activated tab + virtual Panel *GetActiveTab(); + + // returns the title text of the tab + virtual void GetActiveTabTitle( char *textOut, int bufferLen ); + + // returns the title of tab "i" + virtual bool GetTabTitle( int i, char *textOut, int bufferLen ); + + // sets the title of tab "i" + virtual bool SetTabTitle( int i, char *pchTitle ); + + // returns the index of the active page + virtual int GetActivePageNum(); + + // returns the number of pages in the sheet + virtual int GetNumPages(); + + // disable the page with title "title" + virtual void DisablePage(const char *title); + + // enable the page with title "title" + virtual void EnablePage(const char *title); + + virtual void SetSmallTabs( bool state ); + virtual bool IsSmallTabs() const; + + /* MESSAGES SENT TO PAGES + "PageShow" - sent when a page is shown + "PageHide" - sent when a page is hidden + "ResetData" - sent when the data should be reloaded from doc + "ApplyChanges" - sent when data should be written to doc + */ + + virtual void OnPanelDropped( CUtlVector< KeyValues * >& msglist ); + virtual bool IsDroppable( CUtlVector< KeyValues * >& msglist ); + // Mouse is now over a droppable panel + virtual void OnDroppablePanelPaint( CUtlVector< KeyValues * >& msglist, CUtlVector< Panel * >& dragPanels ); + + void ShowContextButtons( bool state ); + bool ShouldShowContextButtons() const; + + int FindPage( Panel *page ) const; + + bool PageHasContextMenu( Panel *page ) const; + + void SetKBNavigationEnabled( bool state ); + bool IsKBNavigationEnabled() const; + + virtual bool HasUserConfigSettings() { return true; } + +protected: + virtual void PaintBorder(); + virtual void PerformLayout(); + virtual Panel *HasHotkey(wchar_t key); + virtual void ChangeActiveTab(int index); + virtual void OnKeyCodePressed(KeyCode code); + virtual void OnCommand(const char *command); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void ApplySettings(KeyValues *inResourceData); + + // internal message handlers + MESSAGE_FUNC_PTR( OnTabPressed, "TabPressed", panel ); + MESSAGE_FUNC_PTR_WCHARPTR( OnTextChanged, "TextChanged", panel, text ); + MESSAGE_FUNC_PARAMS( OnOpenContextMenu, "OpenContextMenu", params ); + MESSAGE_FUNC( OnApplyButtonEnable, "ApplyButtonEnable" ); + // called when default button has been set + MESSAGE_FUNC_HANDLE( OnDefaultButtonSet, "DefaultButtonSet", button ); + // called when the current default button has been set + MESSAGE_FUNC_HANDLE( OnCurrentDefaultButtonSet, "CurrentDefaultButtonSet", button); + MESSAGE_FUNC( OnFindDefaultButton, "FindDefaultButton" ); + +private: + + // enable/disable the page with title "title" + virtual void SetPageEnabled(const char *title,bool state); + + struct Page_t + { + Page_t() : + page( 0 ), + contextMenu( false ) + { + } + + Panel *page; + bool contextMenu; + }; + + CUtlVector m_Pages; + CUtlVector m_PageTabs; + Panel *_activePage; + PageTab *_activeTab; + int _tabWidth; + int _activeTabIndex; + ComboBox *_combo; + bool _showTabs; + bool _tabFocus; + + PHandle m_hPreviouslyActivePage; + float m_flPageTransitionEffectTime; + bool m_bSmallTabs; + HFont m_tabFont; + bool m_bDraggableTabs; + bool m_bContextButton; + bool m_bKBNavigationEnabled; + + CPanelAnimationVarAliasType( int, m_iTabXIndent, "tabxindent", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTabXDelta, "tabxdelta", "0", "proportional_int" ); + CPanelAnimationVarAliasType( bool, m_bTabFitText, "tabxfittotext", "1", "bool" ); + + //============================================================================= + // HPE_BEGIN: + // [tj] These variables have been split into the initially specified size + // and the currently set size. This is so we can always recalculate the + // new value for resolution changes. + //============================================================================= + CPanelAnimationVarAliasType( int, m_iSpecifiedTabHeight, "tabheight", "28", "int" ); + CPanelAnimationVarAliasType( int, m_iSpecifiedTabHeightSmall, "tabheight_small", "14", "int" ); + + int m_iTabHeight; + int m_iTabHeightSmall; + //============================================================================= + // HPE_END + //============================================================================= + + KeyValues *m_pTabKV; +}; + +}; // namespace vgui + +#endif // PROPERTYSHEET_H diff --git a/public/vgui_controls/QueryBox.h b/public/vgui_controls/QueryBox.h new file mode 100644 index 0000000..40e6e46 --- /dev/null +++ b/public/vgui_controls/QueryBox.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Creates a Message box with a question in it and yes/no buttons +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef QUERYBOX_H +#define QUERYBOX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Creates A Message box with a question in it and yes/no buttons +//----------------------------------------------------------------------------- +class QueryBox : public MessageBox +{ + DECLARE_CLASS_SIMPLE( QueryBox, MessageBox ); + +public: + QueryBox(const char *title, const char *queryText,vgui::Panel *parent = NULL ); + QueryBox(const wchar_t *wszTitle, const wchar_t *wszQueryText,vgui::Panel *parent = NULL); + ~QueryBox(); + + // Layout the window for drawing + virtual void PerformLayout(); + + // Set the keyvalues to send when ok button is hit + void SetOKCommand(KeyValues *keyValues); + + // Set the keyvalues to send when the cancel button is hit + void SetCancelCommand(KeyValues *keyValues); + + // Set the text on the Cancel button + void SetCancelButtonText(const char *buttonText); + void SetCancelButtonText(const wchar_t *wszButtonText); + + // Set a value of the ok command + void SetOKCommandValue(const char *keyName, int value); + +protected: + virtual void OnKeyCodeTyped( KeyCode code ); + virtual void OnKeyCodePressed( KeyCode code ); + virtual void OnCommand(const char *command); + Button *m_pCancelButton; + +private: + KeyValues *m_pCancelCommand; + KeyValues *m_pOkCommand; +}; + +} +#endif // QUERYBOX_H diff --git a/public/vgui_controls/RadioButton.h b/public/vgui_controls/RadioButton.h new file mode 100644 index 0000000..c21abba --- /dev/null +++ b/public/vgui_controls/RadioButton.h @@ -0,0 +1,112 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RADIOBUTTON_H +#define RADIOBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Radio buton image +//----------------------------------------------------------------------------- +class RadioImage : public TextImage +{ +public: + RadioImage(RadioButton *radioButton) : TextImage( "n" ) + { + _radioButton = radioButton; + + SetSize(20, 13); + } + + virtual void Paint(); + + virtual void SetColor(Color color) + { + _borderColor1 = color; + _borderColor2 = color; + _checkColor = color; + } + + Color _borderColor1; + Color _borderColor2; + Color _checkColor; + + Color _bgColor; + +private: + RadioButton *_radioButton; +}; + +//----------------------------------------------------------------------------- +// Purpose: Radio buttons are automatically selected into groups by who their +// parent is. At most one radio button is active at any time. +//----------------------------------------------------------------------------- +class RadioButton : public ToggleButton +{ + DECLARE_CLASS_SIMPLE( RadioButton, ToggleButton ); + +public: + RadioButton(Panel *parent, const char *panelName, const char *text); + ~RadioButton(); + + // Set the radio button checked. When a radio button is checked, a + // message is sent to all other radio buttons in the same group so + // they will become unchecked. + virtual void SetSelected(bool state); + + // Get the tab position of the radio button with the set of radio buttons + // A group of RadioButtons must have the same TabPosition, with [1, n] subtabpositions + virtual int GetSubTabPosition(); + virtual void SetSubTabPosition(int position); + + // Return the RadioButton's real tab position (its Panel one changes) + virtual int GetRadioTabPosition(); + + // Set the selection state of the radio button, but don't fire + // any action signals or messages to other radio buttons + virtual void SilentSetSelected(bool state); + +protected: + virtual void DoClick(); + + virtual void Paint(); + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_INT( OnRadioButtonChecked, "RadioButtonChecked", tabposition); + virtual void OnKeyCodeTyped(KeyCode code); + + virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + virtual void ApplySettings(KeyValues *inResourceData); + virtual void GetSettings(KeyValues *outResourceData); + virtual const char *GetDescription(); + virtual void PerformLayout(); + + RadioButton *FindBestRadioButton(int direction); + +private: + RadioImage *_radioBoxImage; + int _oldTabPosition; + Color _selectedFgColor; + + int _subTabPosition; // tab position with the radio button list + + void InternalSetSelected(bool state, bool bFireEvents); +}; + +}; // namespace vgui + +#endif // RADIOBUTTON_H diff --git a/public/vgui_controls/RichText.h b/public/vgui_controls/RichText.h new file mode 100644 index 0000000..704ef08 --- /dev/null +++ b/public/vgui_controls/RichText.h @@ -0,0 +1,297 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RICHTEXT_H +#define RICHTEXT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class ClickPanel; + +//----------------------------------------------------------------------------- +// Purpose: Non-editable display of a rich text control +//----------------------------------------------------------------------------- +class RichText : public Panel +{ + DECLARE_CLASS_SIMPLE( RichText, Panel ); + +public: + RichText(Panel *parent, const char *panelName); + ~RichText(); + + // text manipulation + virtual void SetText(const char *text); + virtual void SetText(const wchar_t *text); + void GetText(int offset, OUT_Z_BYTECAP(bufLenInBytes) wchar_t *buf, int bufLenInBytes); + void GetText(int offset, OUT_Z_BYTECAP(bufLenInBytes) char *pch, int bufLenInBytes); + + // configuration + void SetFont(HFont font); + + // inserts characters at the end of the stream + void InsertChar(wchar_t ch); + void InsertString(const char *text); + void InsertString(const wchar_t *wszText); + + // selection + void SelectNone(); + void SelectAllText(); + void SelectNoText(); + MESSAGE_FUNC( CutSelected, "DoCutSelected" ); + MESSAGE_FUNC( CopySelected, "DoCopySelected" ); + + // sets the RichText control interactive or not (meaning you can select/copy text in the window) + void SetPanelInteractive( bool bInteractive ){ m_bInteractive = bInteractive; } + + // sets the RichText scrollbar invisible if it's not going to be used + void SetUnusedScrollbarInvisible( bool bInvis ){ m_bUnusedScrollbarInvis = bInvis; } + + // cursor movement + void GotoTextStart(); // go to start of text buffer + void GotoTextEnd(); // go to end of text buffer + + // configuration + // sets visibility of scrollbar + void SetVerticalScrollbar(bool state); + // sets limit of number of characters insertable into field; set to -1 to remove maximum + // only works with if rich-edit is NOT enabled + void SetMaximumCharCount(int maxChars); + + // rich edit commands + void InsertColorChange(Color col); + // IndentChange doesn't take effect until the next newline character + void InsertIndentChange(int pixelsIndent); + // clickable text + // notification that text was clicked is through "TextClicked" message + void InsertClickableTextStart( const char *pchClickAction = NULL ); + void InsertClickableTextEnd(); + // inserts a string that needs to be scanned for urls/mailto commands to be made clickable + void InsertPossibleURLString(const char *text, Color URLTextColor, Color normalTextColor); + + void InsertFade( float flSustain, float flLength ); + + void ResetAllFades( bool bHold, bool bOnlyExpired = false, float flNewSustain = -1.0f ); + + // sets the height of the window so all text is visible. + // used by tooltips + void SetToFullHeight(); + int GetNumLines(); + + /* CUSTOM MESSAGE HANDLING + "SetText" + input: "text" - text is set to be this string + */ + + /* MESSAGE SENDING (to action signal targets) + "TextChanged" - sent when the text is edited by the user + + + "TextClicked" - sent when clickable text has been clicked on + "text" - the text that was clicked on + */ + + virtual bool RequestInfo(KeyValues *outputData); + /* INFO HANDLING + "GetText" + returns: + "text" - text contained in the text box + */ + virtual void SetFgColor( Color color ); + virtual void SetDrawOffsets( int ofsx, int ofsy ); + bool IsScrollbarVisible(); + + // sets how URL's are handled + // if set, a "URLClicked" "url" "" message will be sent to that panel + void SetURLClickedHandler( Panel *pPanelToHandleClickMsg ); + + void SetUnderlineFont( HFont font ); + + bool IsAllTextAlphaZero() const; + bool HasText() const; + + void SetDrawTextOnly(); + +protected: + virtual void OnThink(); + virtual void PerformLayout(); // layout the text in the window + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void Paint(); + + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void GetSettings( KeyValues *outResourceData ); + virtual const char *GetDescription( void ); + MESSAGE_FUNC_WCHARPTR( OnSetText, "SetText", text ); + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); // respond to scroll bar events + virtual void OnKillFocus(); + virtual void OnMouseWheeled(int delta); // respond to mouse wheel events + virtual void OnKeyCodeTyped(KeyCode code); //respond to keyboard events + + MESSAGE_FUNC_INT( OnClickPanel, "ClickPanel", index); + + virtual void OnCursorMoved(int x, int y); // respond to moving the cursor with mouse button down + virtual void OnMousePressed(MouseCode code); // respond to mouse down events + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); // respond to mouse up events + + virtual void OnMouseFocusTicked(); // do while window has mouse focus + virtual void OnCursorEntered(); // handle cursor entering window + virtual void OnCursorExited(); // handle cursor exiting window + + virtual void OnMouseCaptureLost(); + virtual void OnSizeChanged(int newWide, int newTall); + virtual void OnSetFocus(); + + // clickable url handling + int ParseTextStringForUrls(const char *text, int startPos, char *pchURLText, int cchURLText, char *pchURL, int cchURL, bool &clickable); + virtual void OnTextClicked(const wchar_t *text); + +#ifdef DBGFLAG_VALIDATE + virtual void Validate( CValidator &validator, char *pchName ); +#endif // DBGFLAG_VALIDATE + +protected: + ScrollBar *_vertScrollBar; // the scroll bar used in the window + +private: + int GetLineHeight(); + HFont GetDefaultFont(); + + const wchar_t *ResolveLocalizedTextAndVariables( char const *pchLookup, OUT_Z_BYTECAP(outbufsizeinbytes) wchar_t *outbuf, size_t outbufsizeinbytes ); + void CheckRecalcLineBreaks(); + + void GotoWordRight(); // move cursor to start of next word + void GotoWordLeft(); // move cursor to start of prev word + + void TruncateTextStream(); + bool GetSelectedRange(int& cx0,int& cx1); + void CursorToPixelSpace(int cursorPos, int &cx, int &cy); + int PixelToCursorSpace(int cx, int cy); + void AddAnotherLine(int &cx, int &cy); + void RecalculateDefaultState(int startIndex); + + void LayoutVerticalScrollBarSlider(); + void OpenEditMenu(); + void FinishingURL(int x, int y); + // Returns the character index the drawing should Start at + int GetStartDrawIndex(int &lineBreakIndexIndex); + int GetCursorLine(); + int GetClickableTextIndexStart(int startIndex); + void CreateEditMenu(); // create copy/cut/paste menu + + MESSAGE_FUNC_INT( MoveScrollBar, "MoveScrollBar", delta ); + MESSAGE_FUNC_INT( MoveScrollBarDirect, "MoveScrollBarDirect", delta ); + + // linebreak stream functions + void InvalidateLineBreakStream(); + void RecalculateLineBreaks(); + + struct TFade + { + float flFadeStartTime; + float flFadeLength; + float flFadeSustain; + int iOriginalAlpha; + }; + + // format stream - describes changes in formatting for the text stream + struct TFormatStream + { + // render state + Color color; + int pixelsIndent; + bool textClickable; + CUtlSymbol m_sClickableTextAction; + + TFade fade; + + // position in TextStream that these changes take effect + int textStreamIndex; + }; + + bool m_bResetFades; + bool m_bInteractive; + bool m_bUnusedScrollbarInvis; + bool m_bAllTextAlphaIsZero; + + // data + CUtlVector m_TextStream; // the text in the text window is stored in this buffer + CUtlVector m_LineBreaks; // an array that holds the index in the buffer to wrap lines at + CUtlVector m_FormatStream; // list of format changes + + bool m_bRecalcLineBreaks; + + int _recalculateBreaksIndex; // tells next linebreakindex index to Start recalculating line breaks + bool _invalidateVerticalScrollbarSlider; + int _cursorPos; // the position in the text buffer of the blinking cursor + bool _mouseSelection; // whether we are highlighting text or not (selecting text) + bool _mouseDragSelection; // tells weather mouse is outside window and button is down so we select text + int _select[2]; // select[1] is the offset in the text to where the cursor is currently + // select[0] is the offset to where the cursor was dragged to. or -1 if no drag. + int _pixelsIndent; + int _maxCharCount; // max number of chars that can be in the text buffer + HFont _font; // font of chars in the text buffer + HFont m_hFontUnderline; + Color _selectionColor; + Color _selectionTextColor; // color of the highlighted text + bool _currentTextClickable; + CUtlVector _clickableTextPanels; + int _clickableTextIndex; + Color _defaultTextColor; + int _drawOffsetX; + int _drawOffsetY; + + Panel *m_pInterior; + PHandle m_hPanelToHandleClickingURLs; + + + // sub-controls + Menu *m_pEditMenu; // cut/copy/paste popup + + char *m_pszInitialText; // initial text + + // saved state + bool _recalcSavedRenderState; + + struct TRenderState + { + // rendering positions + int x, y; + + // basic state + Color textColor; + int pixelsIndent; + bool textClickable; + + // index into our current position in the formatting stream + int formatStreamIndex; + }; + TRenderState m_CachedRenderState; // cached render state for the beginning of painting + + // updates a render state based on the formatting and color streams + // returns true if any state changed + bool UpdateRenderState(int textStreamPos, TRenderState &renderState); + void CalculateFade( TRenderState &renderState ); + + void GenerateRenderStateForTextStreamIndex(int textStreamIndex, TRenderState &renderState); + int FindFormatStreamIndexForTextStreamPos(int textStreamIndex); + + // draws a string of characters with the same formatting using the current render state + int DrawString(int iFirst, int iLast, TRenderState &renderState, HFont font); +}; + +} // namespace vgui + + +#endif // RICHTEXT_H diff --git a/public/vgui_controls/RotatingProgressBar.h b/public/vgui_controls/RotatingProgressBar.h new file mode 100644 index 0000000..400838c --- /dev/null +++ b/public/vgui_controls/RotatingProgressBar.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ROTATINGPROGRESSBAR_H +#define ROTATINGPROGRESSBAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + + //----------------------------------------------------------------------------- + // Purpose: Progress Bar that rotates an image around its center + //----------------------------------------------------------------------------- + class RotatingProgressBar : public ProgressBar + { + DECLARE_CLASS_SIMPLE( RotatingProgressBar, ProgressBar ); + + public: + RotatingProgressBar(Panel *parent, const char *panelName); + ~RotatingProgressBar(); + + virtual void ApplySettings(KeyValues *inResourceData); + virtual void ApplySchemeSettings(IScheme *pScheme); + + void SetImage( const char *imageName ); + + protected: + virtual void Paint(); + virtual void PaintBackground(); + virtual void OnTick(); + + private: + int m_nTextureId; + char *m_pszImageName; + + float m_flStartRadians; + float m_flEndRadians; + + float m_flLastAngle; + + float m_flTickDelay; + float m_flApproachSpeed; + + float m_flRotOriginX; + float m_flRotOriginY; + + float m_flRotatingX; + float m_flRotatingY; + float m_flRotatingWide; + float m_flRotatingTall; + + }; + +} // namespace vgui + +#endif // ROTATINGPROGRESSBAR_H \ No newline at end of file diff --git a/public/vgui_controls/ScalableImagePanel.h b/public/vgui_controls/ScalableImagePanel.h new file mode 100644 index 0000000..7c4f1b7 --- /dev/null +++ b/public/vgui_controls/ScalableImagePanel.h @@ -0,0 +1,59 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SCALABLEIMAGEPANEL_H +#define SCALABLEIMAGEPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + //----------------------------------------------------------------------------- + // Purpose: 9-way Segmented background + //----------------------------------------------------------------------------- + class ScalableImagePanel : public Panel + { + DECLARE_CLASS_SIMPLE( ScalableImagePanel, Panel ); + public: + ScalableImagePanel(Panel *parent, const char *name); + ~ScalableImagePanel(); + + virtual void SetImage(const char *imageName); + void SetDrawColor( Color color ) { m_DrawColor = color; } + + protected: + virtual void PaintBackground(); + virtual void GetSettings(KeyValues *outResourceData); + virtual void ApplySettings(KeyValues *inResourceData); + virtual void PerformLayout( void ); + virtual const char *GetDescription(); + + private: + int m_iSrcCornerHeight; // in pixels, how tall is the corner inside the image + int m_iSrcCornerWidth; // same for width + int m_iCornerHeight; // output size of the corner height in pixels + int m_iCornerWidth; // same for width + + int m_iTextureID; + + float m_flCornerWidthPercent; // corner width as percentage of image width + float m_flCornerHeightPercent; // same for height + + char *m_pszImageName; + + char *m_pszDrawColorName; + Color m_DrawColor; + }; + +} // namespace vgui + +#endif // SCALABLEIMAGEPANEL_H diff --git a/public/vgui_controls/ScrollBar.h b/public/vgui_controls/ScrollBar.h new file mode 100644 index 0000000..c22e3a5 --- /dev/null +++ b/public/vgui_controls/ScrollBar.h @@ -0,0 +1,133 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SCROLLBAR_H +#define SCROLLBAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class Button; +class ScrollBarSlider; + +//----------------------------------------------------------------------------- +// Purpose: Generic scrollbar +// Uses Buttons & SliderBars for the main functionality +//----------------------------------------------------------------------------- +class ScrollBar : public Panel +{ + DECLARE_CLASS_SIMPLE( ScrollBar, Panel ); + +public: + ScrollBar(Panel *parent, const char *panelName, bool vertical); + + // Set the value of the scroll bar slider. + virtual void SetValue(int value); + + // Get the value of the scroll bar slider. + virtual int GetValue(); + + // Set the rangeof numbers the slider can scroll through + virtual void SetRange(int min,int max); + + virtual void GetRange(int &min, int &max); + + // Set how many lines are displayed at one time + // in the window the scroll bar is attached to. + virtual void SetRangeWindow(int rangeWindow); + + // Get how many lines are displayed at one time + // in the window the scroll bar is attached to. + virtual int GetRangeWindow(); + + // Check if the scrollbar is vertical or horizontal + virtual bool IsVertical(); + + // Purpose: Check if the slider can move through one or more pixels per + // unit of its range. + virtual bool HasFullRange(); + + // Setup the indexed scroll bar button with the input params. + virtual void SetButton(Button* button,int index); + // Return the indexed scroll bar button + virtual Button *GetButton(int index); + // Set up the slider. + virtual void SetSlider(ScrollBarSlider* slider); + // Return a pointer to the slider. + virtual ScrollBarSlider *GetSlider(); + // Set how far the scroll bar slider moves + // when a scroll bar button is pressed + virtual void SetButtonPressedScrollValue(int value); + + virtual void Validate(); + + // Update and look for clicks when mouse is in the scroll bar window. + virtual void OnMouseFocusTicked(); + + // Set the slider's Paint border enabled. + virtual void SetPaintBorderEnabled(bool state); + // Set the slider's Paint background enabled. + virtual void SetPaintBackgroundEnabled(bool state); + // Set the slider's Paint enabled. + virtual void SetPaintEnabled(bool state); + + // Sets the scrollbar buttons visible or not + virtual void SetScrollbarButtonsVisible(bool visible); + + void SetAutohideButtons( bool bAutohide ) { m_bAutoHideButtons = bAutohide; } + + void UseImages( const char *pszUpArrow, const char *pszDownArrow, const char *pszLine, const char *pszBox ); + + /* MESSAGES SENT: + "ScrollBarSliderMoved" + "position" - new value of the slider + */ + + void SetOverriddenButtons( Button *pB1, Button *pB2 ) { m_pOverriddenButtons[0] = pB1; m_pOverriddenButtons[1] = pB2; } + + virtual void ApplySettings( KeyValues *pInResourceData ); + +protected: + + virtual void PerformLayout(); + virtual void SendSliderMoveMessage(int value); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnSizeChanged(int wide, int tall); + + MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position ); + virtual void RespondToScrollArrow(int const direction); + + virtual void UpdateButtonsForImages( void ); + virtual void UpdateSliderImages( void ); + Button *GetDepressedButton( int iIndex ); + +private: + Button* _button[2]; + ScrollBarSlider* _slider; + int _buttonPressedScrollValue; + int _scrollDelay; // used to control delays in scrolling + bool _respond; + bool m_bNoButtons; + CPanelAnimationVar( bool, m_bAutoHideButtons, "autohide_buttons", "0" ); + + vgui::ImagePanel *m_pUpArrow; + vgui::ImagePanel *m_pLine; + vgui::ImagePanel *m_pDownArrow; + vgui::ImagePanel *m_pBox; + Button *m_pOverriddenButtons[2]; +}; + +} + +#endif // SCROLLBAR_H diff --git a/public/vgui_controls/ScrollBarSlider.h b/public/vgui_controls/ScrollBarSlider.h new file mode 100644 index 0000000..8769222 --- /dev/null +++ b/public/vgui_controls/ScrollBarSlider.h @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef SCROLLBARSLIDER_H +#define SCROLLBARSLIDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class IBorder; + +//----------------------------------------------------------------------------- +// Purpose: ScrollBarSlider bar, as used in ScrollBar's +//----------------------------------------------------------------------------- +class ScrollBarSlider : public Panel +{ + DECLARE_CLASS_SIMPLE( ScrollBarSlider, Panel ); + +public: + ScrollBarSlider(Panel *parent, const char *panelName, bool vertical); + + // Set the ScrollBarSlider value of the nob. + virtual void SetValue(int value); + virtual int GetValue(); + + // Check whether the scroll bar is vertical or not + virtual bool IsVertical(); + + // Set max and min range of lines to display + virtual void SetRange(int min, int max); + + virtual void GetRange(int &min, int &max); + + // Set number of rows that can be displayed in window + virtual void SetRangeWindow(int rangeWindow); + + // Get number of rows that can be displayed in window + virtual int GetRangeWindow(); + + // Set the size of the ScrollBarSlider nob + virtual void SetSize(int wide, int tall); + + // Get current ScrollBarSlider bounds + virtual void GetNobPos(int &min, int &max); + + virtual bool HasFullRange(); + virtual void SetButtonOffset(int buttonOffset); + virtual void OnCursorMoved(int x, int y); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + + // Return true if this slider is actually drawing itself + virtual bool IsSliderVisible( void ); + + virtual void ApplySettings( KeyValues *pInResourceData ); + +protected: + virtual void Paint(); + virtual void PaintBackground(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + +private: + virtual void RecomputeNobPosFromValue(); + virtual void RecomputeValueFromNobPos(); + virtual void SendScrollBarSliderMovedMessage(); + + bool _vertical; + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + int _range[2]; + int _value; // the position of the ScrollBarSlider, in coordinates as specified by SetRange/SetRangeWindow + int _rangeWindow; + int _buttonOffset; + IBorder *_ScrollBarSliderBorder; +}; + +} // namespace vgui + +#endif // SCROLLBARSLIDER_H diff --git a/public/vgui_controls/ScrollableEditablePanel.h b/public/vgui_controls/ScrollableEditablePanel.h new file mode 100644 index 0000000..6796405 --- /dev/null +++ b/public/vgui_controls/ScrollableEditablePanel.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SCROLLABLEEDITABLEPANEL_H +#define SCROLLABLEEDITABLEPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/EditablePanel.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +namespace vgui +{ + class ScrollBar; +} + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// An editable panel that has a scrollbar +//----------------------------------------------------------------------------- +class ScrollableEditablePanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( ScrollableEditablePanel, vgui::EditablePanel ); + +public: + ScrollableEditablePanel( vgui::Panel *pParent, vgui::EditablePanel *pChild, const char *pName ); + virtual ~ScrollableEditablePanel() {} + + virtual void ApplySettings( KeyValues *pInResourceData ); + virtual void PerformLayout(); + + vgui::ScrollBar *GetScrollbar( void ) { return m_pScrollBar; } + + MESSAGE_FUNC( OnScrollBarSliderMoved, "ScrollBarSliderMoved" ); + virtual void OnMouseWheeled(int delta); // respond to mouse wheel events + +private: + vgui::ScrollBar *m_pScrollBar; + vgui::EditablePanel *m_pChild; +}; + + +} // end namespace vgui + +#endif // SCROLLABLEEDITABLEPANEL_H \ No newline at end of file diff --git a/public/vgui_controls/SectionedListPanel.h b/public/vgui_controls/SectionedListPanel.h new file mode 100644 index 0000000..6fafedd --- /dev/null +++ b/public/vgui_controls/SectionedListPanel.h @@ -0,0 +1,319 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SECTIONEDLISTPANEL_H +#define SECTIONEDLISTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +namespace vgui +{ + +class SectionedListPanel; +class SectionedListPanelHeader; +class CItemButton; + +// sorting function, should return true if itemID1 should be displayed before itemID2 +typedef bool (*SectionSortFunc_t)(SectionedListPanel *list, int itemID1, int itemID2); + +//----------------------------------------------------------------------------- +// Purpose: List panel control that is divided up into discrete sections +//----------------------------------------------------------------------------- +class SectionedListPanel : public Panel +{ + DECLARE_CLASS_SIMPLE( SectionedListPanel, Panel ); + +public: + SectionedListPanel(vgui::Panel *parent, const char *name); + ~SectionedListPanel(); + + // adds a new section; returns false if section already exists + virtual void AddSection(int sectionID, const char *name, SectionSortFunc_t sortFunc = NULL); + virtual void AddSection(int sectionID, const wchar_t *name, SectionSortFunc_t sortFunc = NULL); + virtual void AddSection(int sectionID, SectionedListPanelHeader *pHeader, SectionSortFunc_t sortFunc = NULL); + + // clears all the sections - leaves the items in place + virtual void RemoveAllSections(); + + // modifies section info + virtual void SetSectionFgColor(int sectionID, Color color); + virtual void SetSectionDividerColor( int sectionID, Color color); + // forces a section to always be visible + virtual void SetSectionAlwaysVisible(int sectionID, bool visible = true); + virtual void SetSectionMinimumHeight(int sectionID, int iMinimumHeight); + + // adds a new column to a section + enum ColumnFlags_e + { + HEADER_IMAGE = 0x01, // set if the header for the column is an image instead of text + COLUMN_IMAGE = 0x02, // set if the column contains an image instead of text (images are looked up by index from the ImageList) (see SetImageList below) + COLUMN_BRIGHT = 0x04, // set if the column text should be the bright color + COLUMN_CENTER = 0x08, // set to center the text/image in the column + COLUMN_RIGHT = 0x10, // set to right-align the text in the column + }; + virtual bool AddColumnToSection(int sectionID, const char *columnName, const char *columnText, int columnFlags, int width, HFont fallbackFont = INVALID_FONT ); + virtual bool AddColumnToSection(int sectionID, const char *columnName, const wchar_t *columnText, int columnFlags, int width, HFont fallbackFont = INVALID_FONT ); + + // modifies the text in an existing column + virtual bool ModifyColumn(int sectionID, const char *columnName, const wchar_t *columnText); + + // adds an item to the list; returns the itemID of the new item + virtual int AddItem(int sectionID, const KeyValues *data); + + // modifies an existing item; returns false if the item does not exist + virtual bool ModifyItem(int itemID, int sectionID, const KeyValues *data); + + // removes an item from the list; returns false if the item does not exist or is already removed + virtual bool RemoveItem(int itemID); + + // clears the list + virtual void RemoveAll() { DeleteAllItems(); } + // DeleteAllItems() is deprecated, use RemoveAll(); + virtual void DeleteAllItems(); + + // set the text color of an item + virtual void SetItemFgColor(int itemID, Color color); + //============================================================================= + // HPE_BEGIN: + // [menglish] Getters and setters for several item and section objects + //============================================================================= + virtual void SetItemBgColor( int itemID, Color color ); + virtual int GetColumnIndexByName(int sectionID, char* name); + virtual int GetLineSpacing() { return m_iLineSpacing; } + //============================================================================= + // HPE_END + //============================================================================= + virtual void SetItemFont( int itemID, HFont font ); + virtual void SetItemEnabled( int itemID, bool bEnabled ); + + /* MESSAGES SENT: + "RowSelected" + "itemID" - the selected item id, -1 if nothing selected + + // when an item has been clicked on + "RowContextMenu" "itemID" + "RowLeftClick" "itemID" + "RowDoubleLeftClick" "itemID" + */ + + // returns the number of columns in a section + virtual int GetColumnCountBySection(int sectionID); + + // returns the name of a column by section and column index; returns NULL if there are no more columns + // valid range of columnIndex is [0, GetColumnCountBySection) + virtual const char *GetColumnNameBySection(int sectionID, int columnIndex); + virtual const wchar_t *GetColumnTextBySection(int sectionID, int columnIndex); + virtual int GetColumnFlagsBySection(int sectionID, int columnIndex); + virtual int GetColumnWidthBySection(int sectionID, int columnIndex); + virtual HFont GetColumnFallbackFontBySection( int sectionID, int columnIndex ); + + // returns the id of the currently selected item, -1 if nothing is selected + virtual int GetSelectedItem(); + + // sets which item is currently selected + virtual void SetSelectedItem(int itemID); + + // remove selection + virtual void ClearSelection( void ); + + // returns the data of a selected item + // InvalidateItem(itemID) needs to be called if the KeyValues are modified + virtual KeyValues *GetItemData(int itemID); + + // returns what section an item is in + virtual int GetItemSection(int itemID); + + // forces an item to redraw (use when keyvalues have been modified) + virtual void InvalidateItem(int itemID); + + // returns true if the itemID is valid for use + virtual bool IsItemIDValid(int itemID); + virtual int GetHighestItemID(); + + // returns the number of items (ignoring section dividers) + virtual int GetItemCount(); + + // returns the item ID from the row, again ignoring section dividers - valid from [0, GetItemCount ) + virtual int GetItemIDFromRow(int row); + + // returns the row that this itemID occupies. -1 if the itemID is invalid + virtual int GetRowFromItemID(int itemID); + + // gets the local coordinates of a cell + virtual bool GetCellBounds(int itemID, int column, int &x, int &y, int &wide, int &tall); + + // Gets the coordinates of a section header + virtual bool GetSectionHeaderBounds(int sectionID, int &x, int &y, int &wide, int &tall); + + //============================================================================= + // HPE_BEGIN: + // [menglish] Get the bounds of an item or column. + //============================================================================= + + // gets the local coordinates of a cell using the max width for every column + virtual bool GetMaxCellBounds(int itemID, int column, int &x, int &y, int &wide, int &tall); + + // gets the local coordinates of an item + virtual bool GetItemBounds(int itemID, int &x, int &y, int &wide, int &tall); + + // [tj] Accessors for clickability + void SetClickable(bool clickable) { m_clickable = clickable; } + bool IsClickable() { return m_clickable; } + + // [tj] Accessors for header drawing + void SetDrawHeaders(bool drawHeaders) { m_bDrawSectionHeaders = drawHeaders; } + bool GetDrawHeaders() { return m_bDrawSectionHeaders; } + + //============================================================================= + // HPE_END + //============================================================================= + + // set up a field for editing + virtual void EnterEditMode(int itemID, int column, vgui::Panel *editPanel); + + // leaves editing mode + virtual void LeaveEditMode(); + + // returns true if we are currently in inline editing mode + virtual bool IsInEditMode(); + + // sets whether or not the vertical scrollbar should ever be displayed + virtual void SetVerticalScrollbar(bool state); + + // returns the size required to fully draw the contents of the panel + virtual void GetContentSize(int &wide, int &tall); + + // image handling + virtual void SetImageList(ImageList *imageList, bool deleteImageListWhenDone); + + virtual void ScrollToItem(int iItem); + + virtual void SetProportional(bool state); + + HFont GetHeaderFont( void ) const; + void SetHeaderFont( HFont hFont ); + HFont GetRowFont( void ) const; + void SetRowFont( HFont hFont ); + void MoveSelectionDown( void ); + void MoveSelectionUp( void ); + + ScrollBar *GetScrollBar( void ) { return m_pScrollBar; } + +protected: + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void ApplySettings(KeyValues *inResourceData); + virtual void OnSizeChanged(int wide, int tall); + virtual void OnMouseWheeled(int delta); + virtual void OnMousePressed( MouseCode code); + virtual void NavigateTo( void ); + virtual void OnKeyCodePressed( KeyCode code ); + virtual void OnSetFocus(); // called after the panel receives the keyboard focus + +public: + virtual void SetFontSection(int sectionID, HFont font); +private: + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); + + int GetSectionTall(); + void LayoutPanels(int &contentTall); + + // Returns the index of a new item button, reusing an existing item button if possible + int GetNewItemButton(); + + friend class CItemButton; + void SetSelectedItem(CItemButton *item); + DHANDLE m_hSelectedItem; + + struct column_t + { + char m_szColumnName[32]; + wchar_t m_szColumnText[64]; + int m_iColumnFlags; + int m_iWidth; + HFont m_hFallbackFont; + }; + struct section_t + { + int m_iID; + bool m_bAlwaysVisible; + SectionedListPanelHeader *m_pHeader; + CUtlVector m_Columns; + SectionSortFunc_t m_pSortFunc; + int m_iMinimumHeight; + }; + + CUtlVector m_Sections; + CUtlLinkedList m_Items; + CUtlLinkedList m_FreeItems; + CUtlVector m_SortedItems; + + PHandle m_hEditModePanel; + int m_iEditModeItemID; + int m_iEditModeColumn; + int m_iContentHeight; + int m_iLineSpacing; + int m_iSectionGap; + + int FindSectionIndexByID(int sectionID); + void ReSortList(); + + ScrollBar *m_pScrollBar; + ImageList *m_pImageList; + bool m_bDeleteImageListWhenDone; + bool m_bSortNeeded; + bool m_bVerticalScrollbarEnabled; + + HFont m_hHeaderFont; + HFont m_hRowFont; + //============================================================================= + // HPE_BEGIN: + //============================================================================= + // [tj] Whether or not this list should respond to the mouse + bool m_clickable; + // [tj] Whether or not this list should draw the headers for the sections + bool m_bDrawSectionHeaders; + //============================================================================= + // HPE_END + //============================================================================= + + CPanelAnimationVar( bool, m_bShowColumns, "show_columns", "false" ); +}; + +class SectionedListPanelHeader : public Label +{ + DECLARE_CLASS_SIMPLE( SectionedListPanelHeader, Label ); + +public: + SectionedListPanelHeader(SectionedListPanel *parent, const char *name, int sectionID); + SectionedListPanelHeader(SectionedListPanel *parent, const wchar_t *name, int sectionID); + + virtual void ApplySchemeSettings(IScheme *pScheme) OVERRIDE; + virtual void Paint() OVERRIDE; + virtual void PerformLayout() OVERRIDE; + + void SetColor(Color col); + void SetDividerColor(Color col ); + +protected: + int m_iSectionID; + Color m_SectionDividerColor; + SectionedListPanel *m_pListPanel; +}; + +} // namespace vgui + +#endif // SECTIONEDLISTPANEL_H diff --git a/public/vgui_controls/Slider.h b/public/vgui_controls/Slider.h new file mode 100644 index 0000000..ce75aef --- /dev/null +++ b/public/vgui_controls/Slider.h @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SLIDER_H +#define SLIDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Labeled horizontal slider +//----------------------------------------------------------------------------- +class Slider : public Panel +{ + DECLARE_CLASS_SIMPLE( Slider, Panel ); +public: + Slider(Panel *parent, const char *panelName); + + // interface + virtual void SetValue(int value, bool bTriggerChangeMessage = true); + virtual int GetValue(); + virtual void SetRange(int min, int max); // set to max and min range of rows to display + virtual void GetRange(int &min, int &max); + virtual void GetNobPos(int &min, int &max); // get current Slider position + virtual void SetButtonOffset(int buttonOffset); + virtual void OnCursorMoved(int x, int y); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + virtual void SetTickCaptions(const wchar_t *left, const wchar_t *right); + virtual void SetTickCaptions(const char *left, const char *right); + virtual void SetNumTicks(int ticks); + virtual void SetThumbWidth( int width ); + virtual int EstimateValueAtPos( int localMouseX, int localMouseY ); + virtual void SetInverted( bool bInverted ); + + // If you click on the slider outside of the nob, the nob jumps + // to the click position, and if this setting is enabled, the nob + // is then draggable from the new position until the mouse is released + virtual void SetDragOnRepositionNob( bool state ); + virtual bool IsDragOnRepositionNob() const; + + // Get if the slider nob is being dragged by user, usually the application + // should refuse from forcefully setting slider value if it is being dragged + // by user since the next frame the nob will pop back to mouse position + virtual bool IsDragged( void ) const; + + // This allows the slider to behave like it's larger than what's actually being drawn + virtual void SetSliderThumbSubRange( bool bEnable, int nMin = 0, int nMax = 100 ); + +protected: + virtual void OnSizeChanged(int wide, int tall); + virtual void Paint(); + virtual void PaintBackground(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void GetSettings(KeyValues *outResourceData); + virtual void ApplySettings(KeyValues *inResourceData); + virtual const char *GetDescription(); +#ifdef _X360 + virtual void OnKeyCodePressed(KeyCode code); +#endif + virtual void OnKeyCodeTyped(KeyCode code); + + virtual void DrawNob(); + virtual void DrawTicks(); + virtual void DrawTickLabels(); + + virtual void GetTrackRect( int &x, int &y, int &w, int &h ); + +protected: + virtual void RecomputeNobPosFromValue(); + virtual void RecomputeValueFromNobPos(); + + virtual void SendSliderMovedMessage(); + virtual void SendSliderDragStartMessage(); + virtual void SendSliderDragEndMessage(); + + void ClampRange(); + + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + int _range[2]; + int _subrange[ 2 ]; + int _value; // the position of the Slider, in coordinates as specified by SetRange/SetRangeWindow + int _buttonOffset; + IBorder *_sliderBorder; + IBorder *_insetBorder; + float _nobSize; + + TextImage *_leftCaption; + TextImage *_rightCaption; + + Color m_TickColor; + Color m_TrackColor; + Color m_DisabledTextColor1; + Color m_DisabledTextColor2; +#ifdef _X360 + Color m_DepressedBgColor; +#endif + + int m_nNumTicks; + bool m_bIsDragOnRepositionNob : 1; + bool m_bUseSubRange : 1; + bool m_bInverted : 1; +}; + +} + +#endif // SLIDER_H diff --git a/public/vgui_controls/Splitter.h b/public/vgui_controls/Splitter.h new file mode 100644 index 0000000..f788ebc --- /dev/null +++ b/public/vgui_controls/Splitter.h @@ -0,0 +1,98 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef SPLITTER_H +#define SPLITTER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +enum SplitterMode_t +{ + SPLITTER_MODE_HORIZONTAL = 0, + SPLITTER_MODE_VERTICAL +}; + + +class SplitterHandle; +class SplitterChildPanel; + +//----------------------------------------------------------------------------- +// Purpose: Thin line used to divide sections, can be moved dragged! +//----------------------------------------------------------------------------- +class Splitter : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( Splitter, EditablePanel ); + +public: + // nCount is the number of splitters to create. + // NOTE: The constructor here will create (nCount+1) EditablePanel children + // and name them child0...childN for .res file purposes. + Splitter( Panel *parent, const char *name, SplitterMode_t mode, int nCount ); + ~Splitter(); + + // Evenly respace all splitters + void EvenlyRespaceSplitters(); + + // respace splitters using given fractions (must sum to 1) + void RespaceSplitters( float *flFractions ); + + // Inherited from Panel + virtual void ApplySettings(KeyValues *inResourceData); + virtual void GetSettings( KeyValues *outResourceData ); + virtual void PerformLayout(); + virtual void OnSizeChanged(int newWide, int newTall); + virtual void ApplyUserConfigSettings(KeyValues *userConfig); + virtual void GetUserConfigSettings(KeyValues *userConfig); + virtual bool HasUserConfigSettings() { return true; } + + // Sets the splitter color + void SetSplitterColor( Color c ); + + // Enables borders on the splitters + void EnableBorders( bool bEnable ); + + // Locks the size of a particular child in pixels. + void LockChildSize( int nChildIndex, int nSize ); + void UnlockChildSize( int nChildIndex ); + +private: + void RecreateSplitters( int nCount ); + + struct SplitterInfo_t + { + SplitterChildPanel *m_pPanel; // This panel is to the left or above the handle + SplitterHandle *m_pHandle; + float m_flPos; + bool m_bLocked; + int m_nLockedSize; + }; + + int GetPosRange(); + int GetSplitterCount() const; + int GetSplitterPosition( int nIndex ); + void SetSplitterPosition( int nIndex, int nPos ); + int GetSubPanelCount() const; + int ComputeLockedSize( int nStartingIndex ); + + CUtlVector< SplitterInfo_t > m_Splitters; + SplitterMode_t m_Mode; + + friend class SplitterHandle; +}; + + +} // namespace vgui + + +#endif // SPLITTER_H diff --git a/public/vgui_controls/TextEntry.h b/public/vgui_controls/TextEntry.h new file mode 100644 index 0000000..7231acc --- /dev/null +++ b/public/vgui_controls/TextEntry.h @@ -0,0 +1,390 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A Class to create a window that you can type and edit text in. +// Window can hold single line or multiline text. +// If it is single it can scroll horizontally in response to +// key input and mouse selection. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEXTENTRY_H +#define TEXTENTRY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Text-input handler +// Behaviour Specs: +// This class handles input from mouse and keyboard. +// TextEntry classes support several box styles, horizontal scrolling with no scrollbar +// vertical scrolling with or without a scrollbar, single line, multiline, +// editable and noneditable. +// +// Shared behaviour: +// URL's are a different text color and are clickable. Clicking them brings up a web browser. +// For vertical scroll bars, up and down arrows scroll one line at a time. +// Clicking and dragging the nob scrolls through text lines. +// Mouse wheel also moves the nob. +// User can select and highlight text in the window. +// Double clicking on a word selects it. +// +// Non editable: +// No blinking cursor in non editable windows. +// Right clicking mouse opens copy menu. Menu's top left corner is where mouse is. +// Ctrl-c will also copy the text. +// Editable: +// Blinking cursor is positioned where text will be inserted. +// Text keys type chars in the window. +// ctrl-c copy highlighted text +// ctrl-v paste highlighted text +// ctrl-x cut highlighted text +// ctrl-right arrow move cursor to the start of the next word +// ctrl-left arrow move cursor to the start of the prev word +// ctrl-enter delete the selected text (and inserts a newline if _catchEnterKey is true) +// insert delete selected text and pastes text from the clipboard +// delete delete the selected text +// ctrl-home move cursor to the start of the text +// ctrl-end move cursor to the end of the text. +// left arrow move cursor before prev char +// ctrl-shift left/right arrow selects text a word at a time +// right arrow move cursor before next char +// up arrow move cursor up one line. +// down arrow move cursor down one line. +// home move cursor to start of current line +// end move cursor to end of current line +// backspace delete prev char or selected text. +// Trying to move to the prev/next char/line/word when there is none moves the cursor to the +// start/end of the text. +// Horizontal scrolling: +// Trying to move to the prev/next char/line/word when there is none scrolls the text +// horizontally in the window so the new text displays at the correct side. +// When moving to prev chars scrolling is staggered. To next chars it is one char at a time. +// Cut/Copy/Paste Menu: +// Right clicking mouse brings up cut/copy/paste menu. +// If no text is highlighted the cut/copy options are dimmed. Cut is dimmed in non editable panels +// If there is no text in the clipboard or panel is not editable the paste option is dimmed. +// If the mouse is right clicked over selected text, the text stays selected. +// If the mouse is right clicked over unselected text, any selected text is deselected. +// +// +//----------------------------------------------------------------------------- +class TextEntry : public Panel +{ + DECLARE_CLASS_SIMPLE( TextEntry, Panel ); + +public: + TextEntry(Panel *parent, const char *panelName); + virtual ~TextEntry(); + + virtual void SetText(const wchar_t *wszText); + virtual void SetText(const char *text); + virtual void GetText(OUT_Z_BYTECAP(bufLenInBytes) char *buf, int bufLenInBytes); + virtual void GetText(OUT_Z_BYTECAP(bufLenInBytes) wchar_t *buf, int bufLenInBytes); + virtual int GetTextLength() const; + virtual bool IsTextFullySelected() const; + + // editing + virtual void GotoLeft(); // move cursor one char left + virtual void GotoRight(); // move cursor one char right + virtual void GotoUp(); // move cursor one line up + virtual void GotoDown(); // move cursor one line down + virtual void GotoWordRight(); // move cursor to Start of next word + virtual void GotoWordLeft(); // move cursor to Start of prev word + virtual void GotoFirstOfLine(); // go to Start of the current line + virtual void GotoEndOfLine(); // go to end of the current line + virtual void GotoTextStart(); // go to Start of text buffer + virtual void GotoTextEnd(); // go to end of text buffer + + virtual void InsertChar(wchar_t ch); + virtual void InsertString(const char *text); + virtual void InsertString(const wchar_t *wszText); + virtual void Backspace(); + virtual void Delete(); + virtual void SelectNone(); + virtual void OpenEditMenu(); + MESSAGE_FUNC( CutSelected, "DoCutSelected" ); + MESSAGE_FUNC( CopySelected, "DoCopySelected" ); + MESSAGE_FUNC( Paste, "DoPaste" ); + + MESSAGE_FUNC_INT( LanguageChanged, "DoLanguageChanged", handle ); + MESSAGE_FUNC_INT( ConversionModeChanged, "DoConversionModeChanged", handle ); + MESSAGE_FUNC_INT( SentenceModeChanged, "DoSentenceModeChanged", handle ); + + MESSAGE_FUNC_WCHARPTR( CompositionString, "DoCompositionString", string ); + + MESSAGE_FUNC( ShowIMECandidates, "DoShowIMECandidates" ); + MESSAGE_FUNC( HideIMECandidates, "DoHideIMECandidates" ); + MESSAGE_FUNC( UpdateIMECandidates, "DoUpdateIMECandidates" ); + + virtual void DeleteSelected(); + virtual void Undo(); + virtual void SaveUndoState(); + virtual void SetFont(HFont font); + virtual void SetTextHidden(bool bHideText); + virtual void SetEditable(bool state); + virtual bool IsEditable(); + virtual void SetEnabled(bool state); + // move the cursor to line 'line', given how many pixels are in a line + virtual void MoveCursor(int line, int pixelsAcross); + + // sets the color of the background when the control is disabled + virtual void SetDisabledBgColor(Color col); + + // set whether the box handles more than one line of entry + virtual void SetMultiline(bool state); + virtual bool IsMultiline(); + + // sets visibility of scrollbar + virtual void SetVerticalScrollbar(bool state); + + // sets whether or not the edit catches and stores ENTER key presses + virtual void SetCatchEnterKey(bool state); + + // sets whether or not to send "TextNewLine" msgs when ENTER key is pressed + virtual void SendNewLine(bool send); + + // sets limit of number of characters insertable into field; set to -1 to remove maximum + // only works with if rich-edit is NOT enabled + virtual void SetMaximumCharCount(int maxChars); + virtual int GetMaximumCharCount(); + virtual void SetAutoProgressOnHittingCharLimit(bool state); + + // sets whether to wrap text once maxChars is reached (on a line by line basis) + virtual void SetWrap(bool wrap); + + virtual void RecalculateLineBreaks(); + virtual void LayoutVerticalScrollBarSlider(); + + virtual bool RequestInfo(KeyValues *outputData); + + // sets the height of the window so all text is visible. + // used by tooltips + void SetToFullHeight(); + + // sets the width of the window so all text is visible. (will create one line) + // used by tooltips + void SetToFullWidth(); + + int GetNumLines(); + + /* INFO HANDLING + "GetText" + returns: + "text" - text contained in the text box + */ + + /* CUSTOM MESSAGE HANDLING + "SetText" + input: "text" - text is set to be this string + */ + + /* MESSAGE SENDING (to action signal targets) + "TextChanged" - sent when the text is edited by the user + + "TextNewLine" - sent when the end key is pressed in the text entry AND _sendNewLines is true + + "TextKillFocus" - sent when focus leaves textentry field + */ + + // Selects all the text in the text entry. + void SelectAllText(bool bResetCursorPos); + void SelectNoText(); + void SelectAllOnFirstFocus( bool status ); + void SetDrawWidth(int width); // width from right side of window we have to draw in + int GetDrawWidth(); + void SetHorizontalScrolling(bool status); // turn horizontal scrolling on or off. + + // sets whether non-asci characters (unicode chars > 127) are allowed in the control - defaults to OFF + void SetAllowNonAsciiCharacters(bool state); + + // sets whether or not number input only is allowed + void SetAllowNumericInputOnly(bool state); + + // By default, we draw the language shortname on the right hand side of the control + void SetDrawLanguageIDAtLeft( bool state ); + + virtual bool GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& data ); + virtual bool IsDroppable( CUtlVector< KeyValues * >& data ); + virtual void OnPanelDropped( CUtlVector< KeyValues * >& data ); + virtual Panel *GetDragPanel(); + virtual void OnCreateDragData( KeyValues *msg ); + + void SelectAllOnFocusAlways( bool status ); + void SetSelectionTextColor( const Color& clr ); + void SetSelectionBgColor( const Color& clr ); + void SetSelectionUnfocusedBgColor( const Color& clr ); + + void SetUseFallbackFont( bool bState, HFont hFallback ); + +protected: + virtual void ResetCursorBlink(); + virtual void PerformLayout(); // layout the text in the window + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void PaintBackground(); + virtual int DrawChar(wchar_t ch, HFont font, int index, int x, int y); + virtual bool DrawCursor(int x, int y); + + virtual void SetCharAt(wchar_t ch, int index); // set the value of a char in the text buffer + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void GetSettings( KeyValues *outResourceData ); + virtual const char *GetDescription( void ); + virtual void FireActionSignal(); + virtual bool GetSelectedRange(int& cx0,int& cx1); + virtual void CursorToPixelSpace(int cursorPos, int &cx, int &cy); + virtual int PixelToCursorSpace(int cx, int cy); + virtual void AddAnotherLine(int &cx, int &cy); + virtual int GetYStart(); // works out ypixel position drawing started at + + virtual bool SelectCheck( bool fromMouse = false ); // check if we are in text selection mode + MESSAGE_FUNC_WCHARPTR( OnSetText, "SetText", text ); + MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); // respond to scroll bar events + virtual void OnKillFocus(); + virtual void OnMouseWheeled(int delta); // respond to mouse wheel events + virtual void OnKeyCodePressed(KeyCode code); //respond to keyboard events + virtual void OnKeyCodeTyped(KeyCode code); //respond to keyboard events + virtual void OnKeyTyped(wchar_t unichar); //respond to keyboard events + + virtual void OnCursorMoved(int x, int y); // respond to moving the cursor with mouse button down + virtual void OnMousePressed(MouseCode code); // respond to mouse down events + virtual void OnMouseDoublePressed( MouseCode code ); + virtual void OnMouseTriplePressed( MouseCode code ); + virtual void OnMouseReleased( MouseCode code ); // respond to mouse up events + + virtual void OnKeyFocusTicked(); // do while window has keyboard focus + virtual void OnMouseFocusTicked(); // do while window has mouse focus + virtual void OnCursorEntered(); // handle cursor entering window + virtual void OnCursorExited(); // handle cursor exiting window + + virtual void OnMouseCaptureLost(); + virtual void OnSizeChanged(int newWide, int newTall); + + // Returns the character index the drawing should Start at + virtual int GetStartDrawIndex(int &lineBreakIndexIndex); + +public: + // helper accessors for common gets + virtual float GetValueAsFloat(); + virtual int GetValueAsInt(); + +protected: + void ScrollRight(); // scroll to right until cursor is visible + void ScrollLeft(); // scroll to left + bool IsCursorOffRightSideOfWindow(int cursorPos); // check if cursor is off right side of window + bool IsCursorOffLeftSideOfWindow(int cursorPos); // check if cursor is off left side of window + void ScrollLeftForResize(); + + void OnSetFocus(); + // Change keyboard layout type + void OnChangeIME( bool forward ); + + bool NeedsEllipses( HFont font, int *pIndex ); + +private: + MESSAGE_FUNC_INT( OnSetState, "SetState", state ); + // get index in buffer of the Start of the current line we are on + int GetCurrentLineStart(); + // get index in buffer of the end of the current line we are on + int GetCurrentLineEnd(); + bool IsLineBreak(int index); + int GetCursorLine(); + void MoveScrollBar(int delta); + void CalcBreakIndex(); // calculate _recalculateLineBreaksIndex + void CreateEditMenu(); // create copy/cut/paste menu + +public: + Menu *GetEditMenu(); // retrieve copy/cut/paste menu + +private: + void FlipToLastIME(); + +public: + virtual void GetTextRange( wchar_t *buf, int from, int numchars ); // copy a portion of the text to the buffer and add zero-termination + virtual void GetTextRange( char *buf, int from, int numchars ); // copy a portion of the text to the buffer and add zero-termination + +private: + + CUtlVector m_TextStream; // the text in the text window is stored in this buffer + CUtlVector m_UndoTextStream; // a copy of the text buffer to revert changes + CUtlVector m_LineBreaks; // an array that holds the index in the buffer to wrap lines at + + int _cursorPos; // the position in the text buffer of the blinking cursor + bool _cursorIsAtEnd; + bool _putCursorAtEnd; + int _undoCursorPos; // a copy of the cursor position to revert changes + bool _cursorBlink; // whether cursor is blinking or not + bool _hideText; // whether text is visible on screen or not + bool _editable; // whether text is editable or not + bool _mouseSelection; // whether we are highlighting text or not (selecting text) + bool _mouseDragSelection; // tells weather mouse is outside window and button is down so we select text + int _mouseSelectCursorStart; // where mouse button was pressed down in text window + long _cursorNextBlinkTime; // time of next cursor blink + int _cursorBlinkRate; // speed of cursor blinking + int _select[2]; // select[1] is the offset in the text to where the cursor is currently + // select[0] is the offset to where the cursor was dragged to. or -1 if no drag. + int _pixelsIndent; + int _charCount; + int _maxCharCount; // max number of chars that can be in the text buffer + HFont _font; // font of chars in the text buffer + HFont _smallfont; + bool _dataChanged; // whether anything in the window has changed. + bool _multiline; // whether buffer is multiline or just a single line + bool _verticalScrollbar; // whether window has a vertical scroll bar + ScrollBar *_vertScrollBar; // the scroll bar used in the window + Color _cursorColor; // color of the text cursor + Color _disabledFgColor; + Color _disabledBgColor; + Color _selectionColor; + Color _selectionTextColor; // color of the highlighted text + Color _defaultSelectionBG2Color; + int _currentStartLine; // use for checking vertical text scrolling (multiline) + int _currentStartIndex; // use for horizontal text scrolling (!multiline) + bool _horizScrollingAllowed; // use to disable horizontal text scrolling period. + Color _focusEdgeColor; + bool _catchEnterKey; + bool _wrap; + bool _sendNewLines; + int _drawWidth; + + // selection data + Menu *m_pEditMenu; ///cut/copy/paste popup + + int _recalculateBreaksIndex; // tells next linebreakindex index to Start recalculating line breaks + bool _selectAllOnFirstFocus : 1; // highlights all text in window when focus is gained. + bool _selectAllOnFocusAlways : 1; + bool _firstFocusStatus; // keep track if we've had that first focus or not + bool m_bAllowNumericInputOnly; + bool m_bAllowNonAsciiCharacters; + bool m_bAutoProgressOnHittingCharLimit; + + enum + { + MAX_COMPOSITION_STRING = 256, + }; + + wchar_t m_szComposition[ MAX_COMPOSITION_STRING ]; + Menu *m_pIMECandidates; + int m_hPreviousIME; + bool m_bDrawLanguageIDAtLeft; + int m_nLangInset; + + bool m_bUseFallbackFont : 1; + HFont m_hFallbackFont; +}; + +} + +#endif // TEXTENTRY_H diff --git a/public/vgui_controls/TextImage.h b/public/vgui_controls/TextImage.h new file mode 100644 index 0000000..20446e7 --- /dev/null +++ b/public/vgui_controls/TextImage.h @@ -0,0 +1,146 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEXTIMAGE_H +#define TEXTIMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +#include +#include + +class KeyValues; + +namespace vgui +{ + +struct label_colorchange_t +{ + Color color; + int textStreamIndex; +}; + +// Used to sort the color changes into sequential order. +class CColorChangeListLess +{ +public: + bool Less( const label_colorchange_t &src1, const label_colorchange_t &src2, void *pCtx ) + { + if ( src1.textStreamIndex < src2.textStreamIndex ) + return true; + + return false; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Image that handles drawing of a text string +//----------------------------------------------------------------------------- +class TextImage : public Image +{ +public: + TextImage(const char *text); + TextImage(const wchar_t *wszText); + ~TextImage(); + +public: + // takes the string and looks it up in the localization file to convert it to unicode + virtual void SetText(const char *text); + // sets unicode text directly + virtual void SetText(const wchar_t *text, bool bClearUnlocalizedSymbol = false); + // get the full text in the image + virtual void GetText(char *buffer, int bufferSize); + virtual void GetText(wchar_t *buffer, int bufferLength); + // get the text in it's unlocalized form + virtual void GetUnlocalizedText(char *buffer, int bufferSize); + virtual StringIndex_t GetUnlocalizedTextSymbol(); + + // set the font of the text + virtual void SetFont(vgui::HFont font); + // get the font of the text + virtual vgui::HFont GetFont(); + + // set the width of the text to be drawn + // use this function if the textImage is in another window to cause + // the text to be truncated to the width of the window (elipsis added) + void SetDrawWidth(int width); + // get the width of the text to be drawn + void GetDrawWidth(int &width); + + void ResizeImageToContent(); + void ResizeImageToContentMaxWidth( int nMaxWidth ); + + // set the size of the image + virtual void SetSize(int wide,int tall); + + // get the full size of a text string + virtual void GetContentSize(int &wide, int &tall); + + // draws the text + virtual void Paint(); + + void SetWrap( bool bWrap ); + void RecalculateNewLinePositions(); + + void SetUseFallbackFont( bool bState, HFont hFallback ); + + void SetAllCaps( bool bAllCaps ); + + void SetCenterWrap( bool bWrap ); + void RecalculateCenterWrapIndents(); + + const wchar_t *GetUText( void ) { return _utext; } + + void AddColorChange( Color col, int iTextStreamIndex ); + void SetColorChangeStream( CUtlSortVector *pUtlVecStream ); + void ClearColorChangeStream( void ) { m_ColorChangeStream.Purge(); } + + const wchar_t *GetEllipsesPosition( void ) const { return m_pwszEllipsesPosition; } + bool IsWrapping() const { return m_LineBreaks.Count() != 0; } + +protected: + // truncate the _text string to fit into the draw width + void SizeText(wchar_t *tempText, int stringLength); + // gets the size of a specified piece of text + virtual void GetTextSize(int &wide, int &tall); + +private: + void RecalculateEllipsesPosition(); + + wchar_t *_utext; // unicode version of the text + short _textBufferLen; // size of the text buffer + short _textLen; // length of the text string + vgui::HFont _font; // font of the text string + vgui::HFont _fallbackFont; + int _drawWidth; // this is the width of the window we are drawing into. + // if there is not enough room truncate the txt and add an elipsis + + StringIndex_t _unlocalizedTextSymbol; // store off the unlocalized text index for build mode + wchar_t *m_pwszEllipsesPosition; + + bool m_bRecalculateTruncation : 1; + bool m_bWrap : 1; + bool m_bUseFallbackFont : 1; + bool m_bRenderUsingFallbackFont : 1; + bool m_bAllCaps : 1; + CUtlVector m_LineBreaks; // an array that holds the index in the buffer to wrap lines at + + bool m_bWrapCenter; // Separate from m_bWrap to ensure it doesn't break legacy code. + CUtlVector m_LineXIndent; // For centered word wrap. The X indent for each line. + + CUtlSortVector m_ColorChangeStream; +}; + +} // namespace vgui + +#endif // TEXTIMAGE_H diff --git a/public/vgui_controls/ToggleButton.h b/public/vgui_controls/ToggleButton.h new file mode 100644 index 0000000..355e51a --- /dev/null +++ b/public/vgui_controls/ToggleButton.h @@ -0,0 +1,54 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef TOGGLEBUTTON_H +#define TOGGLEBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Type of button that when pressed stays selected & depressed until pressed again +//----------------------------------------------------------------------------- +class ToggleButton : public Button +{ + DECLARE_CLASS_SIMPLE( ToggleButton, Button ); + +public: + ToggleButton(Panel *parent, const char *panelName, const char *text); + + virtual void DoClick(); + + /* messages sent (get via AddActionSignalTarget()): + "ButtonToggled" + int "state" + */ + +protected: + // overrides + virtual void OnMouseDoublePressed(MouseCode code); + + virtual Color GetButtonFgColor(); + virtual void ApplySchemeSettings(IScheme *pScheme); + + virtual bool CanBeDefaultButton(void); + virtual void OnKeyCodePressed(KeyCode code); + +private: + Color _selectedColor; +}; + +} // namespace vgui + +#endif // TOGGLEBUTTON_H diff --git a/public/vgui_controls/ToolWindow.h b/public/vgui_controls/ToolWindow.h new file mode 100644 index 0000000..870f533 --- /dev/null +++ b/public/vgui_controls/ToolWindow.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef TOOLWINDOW_H +#define TOOLWINDOW_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class ToolWindow; + +// So that an app can have a "custom" tool window class created during window drag/drop operations on the property sheet +class IToolWindowFactory +{ +public: + virtual ToolWindow *InstanceToolWindow( Panel *parent, bool contextLabel, Panel *firstPage, char const *title, bool contextMenu ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Simple frame that holds a property sheet +//----------------------------------------------------------------------------- +class ToolWindow : public Frame +{ + DECLARE_CLASS_SIMPLE( ToolWindow, Frame ); + +public: + ToolWindow(Panel *parent, bool contextLabel, IToolWindowFactory *factory = 0, Panel *page = NULL, char const *title = NULL, bool contextMenu = false, bool inGlobalList = true ); + + ~ToolWindow(); + + virtual bool IsDraggableTabContainer() const; + + // returns a pointer to the PropertySheet this dialog encapsulates + PropertySheet *GetPropertySheet(); + + // wrapper for PropertySheet interface + void AddPage(Panel *page, const char *title, bool contextMenu ); + void RemovePage( Panel *page ); + Panel *GetActivePage(); + void SetActivePage( Panel *page ); + + void SetToolWindowFactory( IToolWindowFactory *factory ); + IToolWindowFactory *GetToolWindowFactory(); + + static int GetToolWindowCount(); + static ToolWindow *GetToolWindow( int index ); + + static CUtlVector< ToolWindow * > s_ToolWindows; + + virtual void Grow( int edge = 0, int from_x = -1, int from_y = -1 ); + virtual void GrowFromClick(); + +protected: + // vgui overrides + virtual void PerformLayout(); + virtual void ActivateBuildMode(); + virtual void RequestFocus(int direction = 0); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + +private: + PropertySheet *m_pPropertySheet; + IToolWindowFactory *m_pFactory; +}; + +}; // vgui + + +#endif // TOOLWINDOW_H diff --git a/public/vgui_controls/Tooltip.h b/public/vgui_controls/Tooltip.h new file mode 100644 index 0000000..2c7ec98 --- /dev/null +++ b/public/vgui_controls/Tooltip.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Creates a Message box with a question in it and yes/no buttons +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TOOLTIP_H +#define TOOLTIP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Tooltip for a panel - shows text when cursor hovers over a panel +//----------------------------------------------------------------------------- +class BaseTooltip +{ +public: + BaseTooltip(Panel *parent, const char *text = NULL); + + virtual void SetText(const char *text); + virtual const char *GetText(); + + virtual void ShowTooltip(Panel *currentPanel); + virtual void HideTooltip(); + + bool ShouldLayout( void ); + virtual void PerformLayout() { return; } + virtual void PositionWindow( Panel *pTipPanel ); + + void ResetDelay(); + void SetTooltipFormatToSingleLine(); + void SetTooltipFormatToMultiLine(); + void SetTooltipDelay(int tooltipDelayMilliseconds); + int GetTooltipDelay(); + void SetEnabled( bool bState ); + +private: + Panel *m_pParent; + virtual void ApplySchemeSettings(IScheme *pScheme) {}; +protected: + CUtlVector m_Text; + int _delay; // delay that counts down + int _tooltipDelay; // delay before tooltip comes up. + bool _makeVisible : 1; + bool _displayOnOneLine : 1; + bool _isDirty : 1; + bool _enabled : 1; +}; + +class TextTooltip : public BaseTooltip +{ +public: + TextTooltip(Panel *parent, const char *text = NULL); + ~TextTooltip(); + + virtual void SetText(const char *text); + virtual void ShowTooltip(Panel *currentPanel); + virtual void HideTooltip(); + virtual void SizeTextWindow(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); +}; + +}; + +#endif // TOOLTIP_H diff --git a/public/vgui_controls/TreeView.h b/public/vgui_controls/TreeView.h new file mode 100644 index 0000000..521d169 --- /dev/null +++ b/public/vgui_controls/TreeView.h @@ -0,0 +1,203 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TREEVIEW_H +#define TREEVIEW_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include + +class KeyValues; + +namespace vgui +{ + +class ExpandButton; +class TreeNode; +class TreeViewSubPanel; + +// sorting function, should return true if node1 should be displayed before node2 +typedef bool (*TreeViewSortFunc_t)(KeyValues *node1, KeyValues *node2); + +class TreeView : public Panel +{ + DECLARE_CLASS_SIMPLE( TreeView, Panel ); + +public: + TreeView(Panel *parent, const char *panelName); + ~TreeView(); + + void SetSortFunc(TreeViewSortFunc_t pSortFunc); + + virtual int AddItem(KeyValues *data, int parentItemIndex); + + virtual int GetRootItemIndex(); + virtual int GetNumChildren( int itemIndex ); + virtual int GetChild( int iParentItemIndex, int iChild ); // between 0 and GetNumChildren( iParentItemIndex ). + + virtual int GetItemCount(void); + virtual KeyValues *GetItemData(int itemIndex); + virtual void RemoveItem(int itemIndex, bool bPromoteChildren, bool bRecursivelyRemove = false ); + virtual void RemoveAll(); + virtual bool ModifyItem(int itemIndex, KeyValues *data); + virtual int GetItemParent(int itemIndex); + + virtual void SetFont(HFont font); + + virtual void SetImageList(ImageList *imageList, bool deleteImageListWhenDone); + + void SetAllowMultipleSelections( bool state ); + bool IsMultipleSelectionAllowed() const; + + virtual void ClearSelection(); + virtual void AddSelectedItem( int itemIndex, bool clearCurrentSelection, bool requestFocus = true, bool bMakeItemVisible = true ); + virtual void RemoveSelectedItem( int itemIndex ); + virtual void SelectAll(); + + virtual bool IsItemSelected( int itemIndex ); + virtual void RangeSelectItems( int clickedItem ); + virtual void FindNodesInRange( int startItem, int endItem, CUtlVector< int >& itemIndices ); + + // returns the id of the currently selected item, -1 if nothing is selected + virtual int GetSelectedItemCount() const; + virtual int GetFirstSelectedItem() const; + virtual void GetSelectedItems( CUtlVector< int >& list ); + virtual void GetSelectedItemData( CUtlVector< KeyValues * >& list ); + + // set colors for individual elments + virtual void SetItemFgColor(int itemIndex, const Color& color); + virtual void SetItemBgColor(int itemIndex, const Color& color); + virtual void SetItemSelectionTextColor( int itemIndex, const Color& clr ); + virtual void SetItemSelectionBgColor( int itemIndex, const Color& clr ); + virtual void SetItemSelectionUnfocusedBgColor( int itemIndex, const Color& clr ); + + // returns true if the itemID is valid for use + virtual bool IsItemIDValid(int itemIndex); + + // item iterators + // iterate from [0..GetHighestItemID()], + // and check each with IsItemIDValid() before using + virtual int GetHighestItemID(); + + virtual void ExpandItem(int itemIndex, bool bExpand); + virtual bool IsItemExpanded( int itemIndex ); + + virtual void MakeItemVisible(int itemIndex); + + // This tells which of the visible items is the top one. + virtual void GetVBarInfo( int &top, int &nItemsVisible, bool& hbarVisible ); + + virtual HFont GetFont(); + + virtual void GenerateDragDataForItem( int itemIndex, KeyValues *msg ); + virtual void SetDragEnabledItems( bool state ); + + virtual void OnLabelChanged( int itemIndex, char const *oldString, char const *newString ); + virtual bool IsLabelEditingAllowed() const; + virtual bool IsLabelBeingEdited() const; + virtual void SetAllowLabelEditing( bool state ); + + /* message sent + + "TreeViewItemSelected" int "itemIndex" + called when the selected item changes + "TreeViewItemDeselected" int "itemIndex" + called when item is deselected + */ + int GetRowHeight(); + int GetVisibleMaxWidth(); + virtual void OnMousePressed(MouseCode code); + + // By default, the tree view expands nodes on left-click. This enables/disables that feature + void EnableExpandTreeOnLeftClick( bool bEnable ); + + virtual void SetLabelEditingAllowed( int itemIndex, bool state ); + virtual void StartEditingLabel( int itemIndex ); + + virtual bool IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist ); + virtual void OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist ); + virtual bool GetItemDropContextMenu( int itemIndex, Menu *menu, CUtlVector< KeyValues * >& msglist ); + virtual HCursor GetItemDropCursor( int itemIndex, CUtlVector< KeyValues * >& msglist ); + + virtual int GetPrevChildItemIndex( int itemIndex ); + virtual int GetNextChildItemIndex( int itemIndex ); + + virtual void PerformLayout(); + + // Makes the scrollbar parented to some other panel... + ScrollBar *SetScrollBarExternal( bool vertical, Panel *newParent ); + void GetScrollBarSize( bool vertical, int& w, int& h ); + + void SetMultipleItemDragEnabled( bool state ); // if this is set, then clicking on one row and dragging will select a run or items, etc. + bool IsMultipleItemDragEnabled() const; + + int FindItemUnderMouse( int mx, int my ); + +protected: + // functions to override + // called when a node, marked as "Expand", needs to generate it's child nodes when expanded + virtual void GenerateChildrenOfNode(int itemIndex) {} + + // override to open a custom context menu on a node being selected and right-clicked + virtual void GenerateContextMenu( int itemIndex, int x, int y ) {} + + // overrides + virtual void OnMouseWheeled(int delta); + virtual void OnSizeChanged(int wide, int tall); + virtual void ApplySchemeSettings(IScheme *pScheme); + MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position ); + virtual void SetBgColor( Color color ); + +private: + friend class TreeNode; + friend class TreeNodeText; + + TreeNode* GetItem( int itemIndex ); + virtual void RemoveChildrenOfNode( int itemIndex ); + void SetLabelBeingEdited( bool state ); + + // Clean up the image list + void CleanUpImageList( ); + + // to be accessed by TreeNodes + IImage* GetImage(int index); + + // bools + bool m_bAllowLabelEditing : 1; + bool m_bDragEnabledItems : 1; + bool m_bDeleteImageListWhenDone : 1; + bool m_bLeftClickExpandsTree : 1; + bool m_bLabelBeingEdited : 1; + bool m_bMultipleItemDragging : 1; + bool m_bAllowMultipleSelections : 1; + + // cross reference - no hierarchy ordering in this list + CUtlLinkedList m_NodeList; + ScrollBar *m_pHorzScrollBar, *m_pVertScrollBar; + int m_nRowHeight; + + ImageList *m_pImageList; + TreeNode *m_pRootNode; + TreeViewSortFunc_t m_pSortFunc; + HFont m_Font; + + CUtlVector< TreeNode * > m_SelectedItems; + TreeViewSubPanel *m_pSubPanel; + + int m_nMostRecentlySelectedItem; + bool m_bScrollbarExternal[ 2 ]; // 0 = vert, 1 = horz +}; + +} + +#endif // TREEVIEW_H diff --git a/public/vgui_controls/TreeViewListControl.h b/public/vgui_controls/TreeViewListControl.h new file mode 100644 index 0000000..8a03470 --- /dev/null +++ b/public/vgui_controls/TreeViewListControl.h @@ -0,0 +1,130 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef TREEVIEWLISTCONTROL_H +#define TREEVIEWLISTCONTROL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include +#include +#include +#include "utlsymbol.h" + + +namespace vgui +{ + +// --------------------------------------------------------------------------------- // +// CTreeViewListControl +// +// This control has N columns, with a tree view in the leftmost column. +// --------------------------------------------------------------------------------- // + +class CTreeViewListControl : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CTreeViewListControl, Panel ); + +public: + + CTreeViewListControl( vgui::Panel *pParent, const char *pName ); + + // Set the tree view to be displayed on the left. If this isn't set, then nothing displays in here. + virtual void SetTreeView( vgui::TreeView *pTree ); + + // Set the height of the title bar. + virtual void SetTitleBarInfo( vgui::HFont hFont, int titleBarHeight ); + + // Set the color to draw the border lines in. + virtual void SetBorderColor( Color clr ); + + // Initialize the column headers.. This info includes the tree view on the left, so this + virtual void SetNumColumns( int nColumns ); + virtual int GetNumColumns() const; + // ciFlags is a combination of CI_ flags. + virtual void SetColumnInfo( int iColumn, const char *pTitle, int width, int ciFlags=0 ); + + // Use this to render your stuff. Iterate over the rows in the tree view and + virtual int GetNumRows(); + virtual int GetTreeItemAtRow( int iRow ); // You can use m_pTree->GetItemData to get at the data for the row. + + // Use this to find out the client area to render in for each grid element. + // The returned box is inclusive. + // The rule is that the the top and left pixels in each grid element are reserved for lines. + virtual void GetGridElementBounds( int iColumn, int iRow, int &left, int &top, int &right, int &bottom ); + + virtual vgui::TreeView *GetTree(); + + virtual int GetTitleBarHeight(); + + virtual int GetScrollBarSize(); + +// Overrides. +public: + + // This is where it recalculates the row infos. + virtual void PerformLayout(); + + // Usually, you'll want to override paint. After calling the base, use GetNumRows() to + // iterate over the data in the tree control and fill in the other columns. + virtual void Paint(); + virtual void PostChildPaint(); + + // You can override this to change the way the title bars are drawn. + virtual void DrawTitleBars(); + + +public: + + enum + { + // By default, column header text is centered. + CI_HEADER_LEFTALIGN =0x0001 + }; + + +protected: + + void RecalculateRows(); + void RecalculateRows_R( int index ); + void RecalculateColumns(); + +private: + + vgui::TreeView *m_pTree; + + class CColumnInfo + { + public: + CColumnInfo() + { + m_Width = m_Left = m_Right = m_ciFlags = 0; + } + + CUtlSymbol m_Title; + int m_Width; + int m_Left; + int m_Right; + int m_ciFlags; // Combination of CI_ flags. + }; + CUtlVector m_Columns; + + vgui::HFont m_TitleBarFont; + int m_TitleBarHeight; + + // These are indices into the tree view. + CUtlVector m_Rows; + + Color m_BorderColor; +}; + +} // namespace + + +#endif // TREEVIEWLISTCONTROL_H diff --git a/public/vgui_controls/URLLabel.h b/public/vgui_controls/URLLabel.h new file mode 100644 index 0000000..6611251 --- /dev/null +++ b/public/vgui_controls/URLLabel.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef URLLABEL_H +#define URLLABEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +namespace vgui +{ + +class URLLabel : public Label +{ + DECLARE_CLASS_SIMPLE( URLLabel, Label ); + +public: + URLLabel(Panel *parent, const char *panelName, const char *text, const char *pszURL); + URLLabel(Panel *parent, const char *panelName, const wchar_t *wszText, const char *pszURL); + ~URLLabel(); + + void SetURL(const char *pszURL); + +protected: + virtual void OnMousePressed(MouseCode code); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void GetSettings( KeyValues *outResourceData ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual const char *GetDescription( void ); + + const char *GetURL( void ) { return m_pszURL; } + +private: + char *m_pszURL; + int m_iURLSize; + bool m_bUnderline; +}; + +} + +#endif // URLLABEL_H diff --git a/public/vgui_controls/WizardPanel.h b/public/vgui_controls/WizardPanel.h new file mode 100644 index 0000000..c6e014e --- /dev/null +++ b/public/vgui_controls/WizardPanel.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WIZARDPANEL_H +#define WIZARDPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +class WizardSubPanel; + +//----------------------------------------------------------------------------- +// Purpose: Type of dialog that supports moving back and forth through a series +// of sub-dialogs, WizardSubPanels +//----------------------------------------------------------------------------- +class WizardPanel : public Frame +{ + DECLARE_CLASS_SIMPLE( WizardPanel, Frame ); + +public: + WizardPanel(Panel *parent, const char *panelName); + ~WizardPanel(); + + // Start the wizard, starting with the startPanel + virtual void Run(WizardSubPanel *startPanel); + + // Called when the buttons are pressed + // WizardSubPanels can also call these functions to simulate a button being pressed + MESSAGE_FUNC( OnNextButton, "NextButton" ); + MESSAGE_FUNC( OnPrevButton, "PrevButton" ); + MESSAGE_FUNC( OnFinishButton, "FinishButton" ); + MESSAGE_FUNC( OnCancelButton, "CancelButton" ); + + // sets whether or not a button is enabled + // this state is managed, and will be reset whenever going to a new page + virtual void SetNextButtonEnabled(bool state); + virtual void SetPrevButtonEnabled(bool state); + virtual void SetFinishButtonEnabled(bool state); + virtual void SetCancelButtonEnabled(bool state); + + // sets whether or not a button is visible + // this state is unmanaged, the user needs to ensure that the buttons state + // is correct when going both back and prev through the wizard + virtual void SetNextButtonVisible(bool state); + virtual void SetPrevButtonVisible(bool state); + virtual void SetFinishButtonVisible(bool state); + virtual void SetCancelButtonVisible(bool state); + + // sets the text for a button + // setting the text to be NULL resets the text to it's default state + // this state is unmanaged, the user needs to ensure that the buttons state + // is correct when going both back and prev through the wizard + virtual void SetNextButtonText(const char *text); + virtual void SetPrevButtonText(const char *text); + virtual void SetFinishButtonText(const char *text); + virtual void SetCancelButtonText(const char *text); + + // general wizard state for all the subpanels to access + virtual KeyValues *GetWizardData(); + + // recalculates where the key focus should be in the wizard + virtual void ResetKeyFocus(); + virtual void ResetDefaultButton(); + + // resets the sub panel history for the control + virtual void ResetHistory(); + + // returns a page by name + virtual WizardSubPanel *GetSubPanelByName(const char *pageName); + + virtual void ShowButtons(bool state); + virtual void GetClientArea(int &x, int &y, int &wide, int &tall); + +protected: + MESSAGE_FUNC_PTR( InternalActivateNextSubPanel, "ActivateNextSubPanel", panel ) + { + ActivateNextSubPanel( (WizardSubPanel *)panel ); + } + + virtual void ActivateNextSubPanel(WizardSubPanel *subPanel); + virtual void ActivatePrevSubPanel(); + virtual void CreateButtons(); + virtual void RecalculateTabOrdering(); + virtual vgui::WizardSubPanel *GetCurrentSubPanel() { return _currentSubPanel; } + + // overrides + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme *pScheme); + + // reroute build messages to the currently active sub panel + virtual void ActivateBuildMode(); + + // close maps to the cancel button + virtual void OnClose(); + virtual void OnCommand(const char *command); + virtual void OnCloseFrameButtonPressed(); + +private: + WizardSubPanel *FindNextValidSubPanel(WizardSubPanel *currentPanel); + + Button *_prevButton; + Button *_nextButton; + Button *_cancelButton; + Button *_finishButton; + + WizardSubPanel *_currentSubPanel; + KeyValues *_currentData; + + Dar _subPanelStack; // contains a list of all the subpanels (not including the current one) + + bool _showButtons; +}; + +} // namespace vgui + + +#endif // WIZARDPANEL_H diff --git a/public/vgui_controls/WizardSubPanel.h b/public/vgui_controls/WizardSubPanel.h new file mode 100644 index 0000000..a7d71fb --- /dev/null +++ b/public/vgui_controls/WizardSubPanel.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WIZARDSUBPANEL_H +#define WIZARDSUBPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +namespace vgui +{ + +//----------------------------------------------------------------------------- +// Purpose: Base panel for use in Wizards and in property sheets +//----------------------------------------------------------------------------- +class WizardSubPanel : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( WizardSubPanel, EditablePanel ); + +public: + // constructor + WizardSubPanel(Panel *parent, const char *panelName); + ~WizardSubPanel(); + + // called when the subpanel is displayed + // All controls & data should be reinitialized at this time + virtual void OnDisplayAsNext() {} + + // called anytime the panel is first displayed, whether the user is moving forward or back + // called immediately after OnDisplayAsNext/OnDisplayAsPrev + virtual void OnDisplay() {} + + // called when displayed as previous + virtual void OnDisplayAsPrev() {} + + // called when one of the wizard buttons are pressed + // returns true if the wizard should advance, false otherwise + virtual bool OnNextButton() { return true; } + virtual bool OnPrevButton() { return true; } + virtual bool OnFinishButton() { return true; } + virtual bool OnCancelButton() { return true; } + + // returns true if this panel should be displayed, or if we should just skip over it + virtual bool ShouldDisplayPanel() { return true; } + + // return true if this subpanel doesn't need the next/prev/finish/cancel buttons or will do it itself + virtual bool isNonWizardPanel() { return false; } + + // returns a pointer to the next subpanel that should be displayed + virtual WizardSubPanel *GetNextSubPanel() = 0; + + // returns a pointer to the panel to return to + // it must be a panel that is already in the wizards panel history + // returning NULL tells it to use the immediate previous panel in the history + virtual WizardSubPanel *GetPrevSubPanel() { return NULL; } + + virtual WizardPanel *GetWizardPanel() { return _wizardPanel; } + virtual void SetWizardPanel(WizardPanel *wizardPanel) { _wizardPanel = wizardPanel; } + + // returns a pointer to the wizard's doc + virtual KeyValues *GetWizardData(); + + // returns a pointer + virtual WizardSubPanel *GetSiblingSubPanelByName(const char *pageName); + + // gets the size this subpanel would like the wizard to be + // returns true if it has a desired size + virtual bool GetDesiredSize(int &wide, int &tall); + +protected: + virtual void ApplySettings(KeyValues *inResourceData); + virtual void GetSettings( KeyValues *outResourceData ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual const char *GetDescription(); + +private: + WizardPanel *_wizardPanel; + int m_iDesiredWide, m_iDesiredTall; +}; + +} // namespace vgui + + +#endif // WIZARDSUBPANEL_H diff --git a/public/vgui_controls/consoledialog.h b/public/vgui_controls/consoledialog.h new file mode 100644 index 0000000..1a354a0 --- /dev/null +++ b/public/vgui_controls/consoledialog.h @@ -0,0 +1,171 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef CONSOLEDIALOG_H +#define CONSOLEDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "tier1/utlvector.h" +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/Frame.h" +#include "icvar.h" + +class ConCommandBase; + + +namespace vgui +{ + +// Things the user typed in and hit submit/return with +class CHistoryItem +{ +public: + CHistoryItem( void ); + CHistoryItem( const char *text, const char *extra = NULL ); + CHistoryItem( const CHistoryItem& src ); + ~CHistoryItem( void ); + + const char *GetText() const; + const char *GetExtra() const; + void SetText( const char *text, const char *extra ); + bool HasExtra() { return m_bHasExtra; } + +private: + char *m_text; + char *m_extraText; + bool m_bHasExtra; +}; + +//----------------------------------------------------------------------------- +// Purpose: Game/dev console dialog +//----------------------------------------------------------------------------- +class CConsolePanel : public vgui::EditablePanel, public IConsoleDisplayFunc +{ + DECLARE_CLASS_SIMPLE( CConsolePanel, vgui::EditablePanel ); + +public: + CConsolePanel( Panel *pParent, const char *pName, bool bStatusVersion ); + ~CConsolePanel(); + + // Inherited from IConsoleDisplayFunc + virtual void ColorPrint( const Color& clr, const char *pMessage ); + virtual void Print( const char *pMessage ); + virtual void DPrint( const char *pMessage ); + virtual void GetConsoleText( char *pchText, size_t bufSize ) const; + + // clears the console + void Clear(); + + // writes console to a file + void DumpConsoleTextToFile(); + + // Hides the console + void Hide(); + + bool TextEntryHasFocus() const; + void TextEntryRequestFocus(); + + + +private: + enum + { + MAX_HISTORY_ITEMS = 100, + }; + + class CompletionItem + { + public: + CompletionItem( void ); + CompletionItem( const CompletionItem& src ); + CompletionItem& operator =( const CompletionItem& src ); + ~CompletionItem( void ); + const char *GetItemText( void ); + const char *GetCommand( void ) const; + const char *GetName() const; + + bool m_bIsCommand; + ConCommandBase *m_pCommand; + CHistoryItem *m_pText; + }; + +protected: + // methods + void OnAutoComplete(bool reverse); + MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel ); + void RebuildCompletionList(const char *partialText); + void UpdateCompletionListPosition(); + MESSAGE_FUNC( CloseCompletionList, "CloseCompletionList" ); + MESSAGE_FUNC_CHARPTR( OnMenuItemSelected, "CompletionCommand", command ); + void ClearCompletionList(); + void AddToHistory( const char *commandText, const char *extraText ); + + // vgui overrides + virtual void PerformLayout(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void OnCommand(const char *command); + virtual void OnKeyCodeTyped(vgui::KeyCode code); + virtual void OnThink(); + + vgui::RichText *m_pHistory; + vgui::TextEntry *m_pEntry; + vgui::Button *m_pSubmit; + vgui::Menu *m_pCompletionList; + Color m_PrintColor; + Color m_DPrintColor; + + int m_iNextCompletion; // the completion that we'll next go to + char m_szPartialText[256]; + char m_szPreviousPartialText[256]; + bool m_bAutoCompleteMode; // true if the user is currently tabbing through completion options + bool m_bWasBackspacing; + bool m_bStatusVersion; + + CUtlVector< CompletionItem * > m_CompletionList; + CUtlVector< CHistoryItem > m_CommandHistory; + + friend class CConsoleDialog; +}; + + +class CConsoleDialog : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CConsoleDialog, vgui::Frame ); + +public: + CConsoleDialog( vgui::Panel *pParent, const char *pName, bool bStatusVersion ); + + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); + virtual void Close(); + virtual void PerformLayout(); + + // brings dialog to the fore + MESSAGE_FUNC( Activate, "Activate" ); + MESSAGE_FUNC_CHARPTR( OnCommandSubmitted, "CommandSubmitted", command ); + + // hides the console + void Hide(); + + // Chain to the page + void Print( const char *msg ); + void DPrint( const char *msg ); + void ColorPrint( const Color& clr, const char *msg ); + void Clear(); + void DumpConsoleTextToFile(); + + virtual void OnKeyCodePressed( vgui::KeyCode code ); + +protected: + CConsolePanel *m_pConsolePanel; +}; + +} // end namespace vgui + +#endif // CONSOLEDIALOG_H diff --git a/public/vgui_controls/cvartogglecheckbutton.h b/public/vgui_controls/cvartogglecheckbutton.h new file mode 100644 index 0000000..5d9a9ba --- /dev/null +++ b/public/vgui_controls/cvartogglecheckbutton.h @@ -0,0 +1,191 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CVARTOGGLECHECKBUTTON_H +#define CVARTOGGLECHECKBUTTON_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui/VGUI.h" +#include "vgui_controls/CheckButton.h" +#include "tier1/utlstring.h" +#include "tier1/KeyValues.h" +namespace vgui +{ + +template< class T > +class CvarToggleCheckButton : public CheckButton +{ + DECLARE_CLASS_SIMPLE( CvarToggleCheckButton, CheckButton ); + +public: + CvarToggleCheckButton( Panel *parent, const char *panelName, const char *text = "", + char const *cvarname = NULL, bool ignoreMissingCvar = false ); + ~CvarToggleCheckButton(); + + virtual void SetSelected( bool state ); + + virtual void Paint(); + + void Reset(); + void ApplyChanges(); + bool HasBeenModified(); + virtual void ApplySettings( KeyValues *inResourceData ); + +private: + // Called when the OK / Apply button is pressed. Changed data should be written into cvar. + MESSAGE_FUNC( OnApplyChanges, "ApplyChanges" ); + MESSAGE_FUNC( OnButtonChecked, "CheckButtonChecked" ); + + T m_cvar; + bool m_bStartValue; + bool m_bIgnoreMissingCvar; +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +template< class T > +CvarToggleCheckButton::CvarToggleCheckButton( Panel *parent, const char *panelName, const char *text, char const *cvarname, bool ignoreMissingCvar ) + : CheckButton( parent, panelName, text ), m_cvar( (cvarname)?cvarname:"", (cvarname)?ignoreMissingCvar:true ) +{ + m_bIgnoreMissingCvar = ignoreMissingCvar; + + if (m_cvar.IsValid()) + { + Reset(); + } + AddActionSignalTarget( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +template< class T > +CvarToggleCheckButton::~CvarToggleCheckButton() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::Paint() +{ + if ( !m_cvar.IsValid() ) + { + BaseClass::Paint(); + return; + } + + bool value = m_cvar.GetBool(); + + if ( value != m_bStartValue ) + { + SetSelected( value ); + m_bStartValue = value; + } + BaseClass::Paint(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called when the OK / Apply button is pressed. Changed data should be written into cvar. +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::OnApplyChanges() +{ + ApplyChanges(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::ApplyChanges() +{ + if ( !m_cvar.IsValid() ) + return; + + m_bStartValue = IsSelected(); + m_cvar.SetValue( m_bStartValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::Reset() +{ + if ( !m_cvar.IsValid() ) + return; + + m_bStartValue = m_cvar.GetBool(); + SetSelected(m_bStartValue); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template< class T > +bool CvarToggleCheckButton::HasBeenModified() +{ + return IsSelected() != m_bStartValue; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *panel - +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::SetSelected( bool state ) +{ + BaseClass::SetSelected( state ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::OnButtonChecked() +{ + if (HasBeenModified()) + { + PostActionSignal(new KeyValues("ControlModified")); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +template< class T > +void CvarToggleCheckButton::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + const char *cvarName = inResourceData->GetString("cvar_name", ""); + const char *cvarValue = inResourceData->GetString("cvar_value", ""); + + if( Q_stricmp( cvarName, "") == 0 ) + return;// Doesn't have cvar set up in res file, must have been constructed with it. + + if( Q_stricmp( cvarValue, "1") == 0 ) + m_bStartValue = true; + else + m_bStartValue = false; + + m_cvar.Init( cvarName, m_bIgnoreMissingCvar ); + if ( m_cvar.IsValid() ) + { + SetSelected( m_cvar.GetBool() ); + } +} + +} // namespace vgui + +#endif // CVARTOGGLECHECKBUTTON_H diff --git a/public/vgui_controls/pch_vgui_controls.h b/public/vgui_controls/pch_vgui_controls.h new file mode 100644 index 0000000..7b09eb5 --- /dev/null +++ b/public/vgui_controls/pch_vgui_controls.h @@ -0,0 +1,115 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef PCH_VGUI_CONTROLS_H +#define PCH_VGUI_CONTROLS_H + +#ifdef _WIN32 +#pragma once +#endif + +// general includes +#include +#include +#include "tier0/dbg.h" +#include "tier0/valve_off.h" +#include "tier1/KeyValues.h" + +#include "tier0/valve_on.h" +#include "tier0/memdbgon.h" + +#include "filesystem.h" +#include "tier0/validator.h" + +// vgui includes +#include "vgui/IBorder.h" +#include "vgui/IInput.h" +#include "vgui/ILocalize.h" +#include "vgui/IPanel.h" +#include "vgui/IScheme.h" +#include "vgui/ISurface.h" +#include "vgui/ISystem.h" +#include "vgui/IVGui.h" +#include "vgui/KeyCode.h" +#include "vgui/Cursor.h" +#include "vgui/MouseCode.h" + +// vgui controls includes +#include "vgui_controls/Controls.h" + +#include "vgui_controls/AnimatingImagePanel.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/BitmapImagePanel.h" +#include "vgui_controls/BuildGroup.h" +#include "vgui_controls/BuildModeDialog.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/CheckButton.h" +#include "vgui_controls/CheckButtonList.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/Controls.h" +#include "vgui_controls/DialogManager.h" +#include "vgui_controls/DirectorySelectDialog.h" +#include "vgui_controls/Divider.h" +#include "vgui_controls/EditablePanel.h" +#include "vgui_controls/FileOpenDialog.h" +#include "vgui_controls/FocusNavGroup.h" +#include "vgui_controls/Frame.h" +#include "vgui_controls/GraphPanel.h" +#include "vgui_controls/HTML.h" +#include "vgui_controls/Image.h" +#include "vgui_controls/ImageList.h" +#include "vgui_controls/ImagePanel.h" +#include "vgui_controls/Label.h" +#include "vgui_controls/ListPanel.h" +#include "vgui_controls/ListViewPanel.h" +#include "vgui_controls/Menu.h" +#include "vgui_controls/MenuBar.h" +#include "vgui_controls/MenuButton.h" +#include "vgui_controls/MenuItem.h" +#include "vgui_controls/MessageBox.h" +#include "vgui_controls/Panel.h" +#ifndef HL1 +#include "vgui_controls/PanelAnimationVar.h" +#endif +#include "vgui_controls/PanelListPanel.h" +#include "vgui_controls/PHandle.h" +#include "vgui_controls/ProgressBar.h" +#include "vgui_controls/ProgressBox.h" +#include "vgui_controls/PropertyDialog.h" +#include "vgui_controls/PropertyPage.h" +#include "vgui_controls/PropertySheet.h" +#include "vgui_controls/QueryBox.h" +#include "vgui_controls/RadioButton.h" +#include "vgui_controls/RichText.h" +#include "vgui_controls/ScrollBar.h" +#include "vgui_controls/ScrollBarSlider.h" +#include "vgui_controls/SectionedListPanel.h" +#include "vgui_controls/Slider.h" +#ifndef HL1 +#include "vgui_controls/Splitter.h" +#endif +#include "vgui_controls/TextEntry.h" +#include "vgui_controls/TextImage.h" +#include "vgui_controls/ToggleButton.h" +#include "vgui_controls/Tooltip.h" +#ifndef HL1 +#include "vgui_controls/ToolWindow.h" +#endif +#include "vgui_controls/TreeView.h" +#ifndef HL1 +#include "vgui_controls/TreeViewListControl.h" +#endif +#include "vgui_controls/URLLabel.h" +#include "vgui_controls/WizardPanel.h" +#include "vgui_controls/WizardSubPanel.h" + +#ifndef HL1 +#include "vgui_controls/KeyBoardEditorDialog.h" +#include "vgui_controls/InputDialog.h" +#endif + +#endif // PCH_VGUI_CONTROLS_H \ No newline at end of file diff --git a/public/vgui_controls/perforcefilelistframe.h b/public/vgui_controls/perforcefilelistframe.h new file mode 100644 index 0000000..7744bf2 --- /dev/null +++ b/public/vgui_controls/perforcefilelistframe.h @@ -0,0 +1,151 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// List of perforce files and operations +// +//============================================================================= + +#ifndef PERFORCEFILELISTFRAME_H +#define PERFORCEFILELISTFRAME_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Frame.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" +#include "p4lib/ip4.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Enumeration of operation dialog ids +//----------------------------------------------------------------------------- +enum +{ + OPERATION_DIALOG_ID_PERFORCE = 0, + + OPERATION_DIALOG_STANDARD_ID_COUNT, + OPERATION_DIALOG_STANDARD_ID_MAX = OPERATION_DIALOG_STANDARD_ID_COUNT - 1, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for a list of files + an operation to perform +//----------------------------------------------------------------------------- +class COperationFileListFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( COperationFileListFrame, vgui::Frame ); + +public: + // NOTE: The dialog ID is used to allow dialogs to have different configurations saved + COperationFileListFrame( vgui::Panel *pParent, const char *pTitle, const char *pColumnHeader, bool bShowDescription, bool bShowOkOnly = false, int nDialogID = 1 ); + virtual ~COperationFileListFrame(); + + // Command handler + virtual void OnCommand( const char *pCommand ); + virtual void PerformLayout(); + + // Adds files to the frame + void ClearAllOperations(); + void AddOperation( const char *pOperation, const char *pFileName ); + void AddOperation( const char *pOperation, const char *pFileName, const Color& clr ); + + // Resizes the operation column to fit the operation text + void ResizeOperationColumnToContents(); + + // Sets the column header for the 'operation' column + void SetOperationColumnHeaderText( const char *pText ); + + // Shows the panel + void DoModal( KeyValues *pContextKeyValues = NULL, const char *pMessage = NULL ); + + // Retrieves the number of files, the file names, and operations + int GetOperationCount(); + const char *GetFileName( int i ); + const char *GetOperation( int i ); + + // Retreives the description (only if it was shown) + const char *GetDescription(); + +private: + virtual bool PerformOperation() { return true; } + const char *CompletionMessage(); + void CleanUpMessage(); + + vgui::ListPanel *m_pFileBrowser; + vgui::Splitter *m_pSplitter; + vgui::TextEntry *m_pDescription; + vgui::Button *m_pYesButton; + vgui::Button *m_pNoButton; + KeyValues *m_pContextKeyValues; + CUtlString m_MessageName; + char *m_pText; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for picker +//----------------------------------------------------------------------------- +enum PerforceAction_t +{ + PERFORCE_ACTION_NONE = -1, + PERFORCE_ACTION_FILE_ADD = 0, + PERFORCE_ACTION_FILE_EDIT, + PERFORCE_ACTION_FILE_DELETE, + PERFORCE_ACTION_FILE_REVERT, + PERFORCE_ACTION_FILE_SUBMIT, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Modal dialog for picker +//----------------------------------------------------------------------------- +class CPerforceFileListFrame : public COperationFileListFrame +{ + DECLARE_CLASS_SIMPLE( CPerforceFileListFrame, COperationFileListFrame ); + +public: + CPerforceFileListFrame( vgui::Panel *pParent, const char *pTitle, const char *pColumnHeader, PerforceAction_t action ); + virtual ~CPerforceFileListFrame(); + + // Adds files to the frame + void ClearAllFiles(); + void AddFile( const char *pFullPath ); + void AddFile( const char *pRelativePath, const char *pPathId ); + + void DoModal( KeyValues *pContextKeys = NULL, const char *pMessage = NULL ); + +private: + virtual bool PerformOperation(); + + // Adds files for open, submit + void AddFileForOpen( const char *pFullPath ); + void AddFileForSubmit( const char *pFullPath, P4FileState_t state ); + + // Does the perforce operation + void PerformPerforceAction( ); + + PerforceAction_t m_Action; + CUtlVector< P4File_t > m_OpenedFiles; + CUtlString m_LastOpenedFilePathId; +}; + + +//----------------------------------------------------------------------------- +// Show the perforce query dialog +// The specified keyvalues message will be sent either +// 1) If you open the file for add/edit +// 2) If you indicate to not add a file for add but don't hit cancel +// If a specific perforce action is specified, then the dialog will only +// be displayed if that action is appropriate +//----------------------------------------------------------------------------- +void ShowPerforceQuery( vgui::Panel *pParent, const char *pFileName, vgui::Panel *pActionSignalTarget, KeyValues *pKeyValues, PerforceAction_t actionFilter = PERFORCE_ACTION_NONE ); + + +#endif // PERFORCEFILELISTFRAME_H + diff --git a/public/vgui_controls/savedocumentquery.h b/public/vgui_controls/savedocumentquery.h new file mode 100644 index 0000000..fd738f4 --- /dev/null +++ b/public/vgui_controls/savedocumentquery.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// This dialog asks if you want to save your work +// +//============================================================================= + +#ifndef SAVEDOCUMENTQUERY_H +#define SAVEDOCUMENTQUERY_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class KeyValues; +namespace vgui +{ +class Panel; +} + + +//----------------------------------------------------------------------------- +// Show the save document query dialog +// NOTE: The following commands will be posted to the action signal target: +// "OnExit" - when we want to quit +// "OnSave" - when we want to save the file +// "OnCloseNoSave" - when we want to close the file without saving it +// "commandname" - additional command send after saving (SAVEDOC_POSTCOMMAND_AFTER_SAVE) +// "OnMarkNotDirty" - when we want to mark the file not dirty +//----------------------------------------------------------------------------- +void ShowSaveDocumentQuery( vgui::Panel *pParent, const char *pFileName, const char *pFileType, int nContext, vgui::Panel *pActionSignalTarget, KeyValues *pPostSaveCommand ); + + +#endif // SAVEDOCUMENTQUERY_H diff --git a/public/vgui_controls/subrectimage.h b/public/vgui_controls/subrectimage.h new file mode 100644 index 0000000..b7738c4 --- /dev/null +++ b/public/vgui_controls/subrectimage.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SUBRECTIMAGE_H +#define SUBRECTIMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/Image.h" +#include "vgui/VGUI.h" + + +//----------------------------------------------------------------------------- +// Purpose: Check box image +//----------------------------------------------------------------------------- +class CSubRectImage : public vgui::Image +{ +public: + CSubRectImage( const char *filename, bool hardwareFiltered, int subx, int suby, int subw, int subh ); + virtual ~CSubRectImage(); + + void GetSize( int &wide, int &tall ); + void GetContentSize( int &wide, int &tall ); + void SetSize( int x, int y ); + void SetPos( int x, int y ); + void SetColor( Color col ); + const char *GetName(); + void Paint(); + void ForceUpload(); + vgui::HTexture GetID(); + bool IsValid(); + +private: + vgui::HTexture _id; + int sub[ 4 ]; + char *_filename; + int _pos[2]; + int _wide,_tall; + Color _color; + bool _uploaded; + bool _valid; + bool _filtered; +}; + + +#endif // SUBRECTIMAGE_H \ No newline at end of file diff --git a/public/vgui_controls/vgui_controls.cpp b/public/vgui_controls/vgui_controls.cpp new file mode 100644 index 0000000..261ff98 --- /dev/null +++ b/public/vgui_controls/vgui_controls.cpp @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "vgui/IVGui.h" +#include "vgui_controls/Controls.h" + +#include "vgui_controls/AnimatingImagePanel.h" +#include "vgui_controls/BitmapImagePanel.h" +#include "vgui_controls/ExpandButton.h" +#include "vgui_controls/TreeViewListControl.h" +#include "vgui_controls/HTML.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +using namespace vgui; + +USING_BUILD_FACTORY( Button ); +USING_BUILD_FACTORY( EditablePanel ); +USING_BUILD_FACTORY( ImagePanel ); +USING_BUILD_FACTORY( Label ); +USING_BUILD_FACTORY( Panel ); +USING_BUILD_FACTORY( ToggleButton ); +USING_BUILD_FACTORY( AnimatingImagePanel ); +USING_BUILD_FACTORY( CBitmapImagePanel ); +USING_BUILD_FACTORY( CheckButton ); +USING_BUILD_FACTORY( ComboBox ); +USING_BUILD_FACTORY_ALIAS( CvarToggleCheckButton, CvarToggleCheckButton ); +USING_BUILD_FACTORY( Divider ); +USING_BUILD_FACTORY( ExpandButton ); +USING_BUILD_FACTORY( GraphPanel ); +//USING_BUILD_FACTORY_ALIAS( HTML, HTML_NoJavascript ); +//USING_BUILD_FACTORY_ALIAS( HTML, HTML_Javascript ); +USING_BUILD_FACTORY( ListPanel ); +USING_BUILD_FACTORY( ListViewPanel ); +USING_BUILD_FACTORY( Menu ); +USING_BUILD_FACTORY( MenuBar ); +USING_BUILD_FACTORY( MenuButton ); +USING_BUILD_FACTORY( MenuItem ); +USING_BUILD_FACTORY( MessageBox ); +USING_BUILD_FACTORY( ProgressBar ); +USING_BUILD_FACTORY( CircularProgressBar ); +USING_BUILD_FACTORY( RadioButton ); +USING_BUILD_FACTORY( RichText ); +USING_BUILD_FACTORY( ScalableImagePanel ); +USING_BUILD_FACTORY_ALIAS( ScrollBar, ScrollBar_Vertical ); +USING_BUILD_FACTORY_ALIAS( ScrollBar, ScrollBar_Horizontal ); +USING_BUILD_FACTORY( ScrollBar ); +USING_BUILD_FACTORY( Slider ); +USING_BUILD_FACTORY( TextEntry ); +USING_BUILD_FACTORY( TreeView ); +USING_BUILD_FACTORY( CTreeViewListControl ); +USING_BUILD_FACTORY( URLLabel ); + +int g_nYou_Must_Add_Public_Vgui_Controls_Vgui_ControlsCpp_To_Your_Project = 0; diff --git a/public/video/ivideoservices.h b/public/video/ivideoservices.h new file mode 100644 index 0000000..8a2d231 --- /dev/null +++ b/public/video/ivideoservices.h @@ -0,0 +1,549 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +//============================================================================= + +#ifndef IVIDEOSERVICES_H +#define IVIDEOSERVICES_H + +#if defined ( WIN32 ) + #pragma once +#endif + +#include +#include "appframework/IAppSystem.h" +#include "tier0/platform.h" + +#include +#ifndef _STDINT_H +#define _STDINT_H +#endif +#ifndef _STDINT +#define _STDINT +#endif + + +#ifndef nullptr + #define nullptr ( 0 ) +#endif +#ifndef INT32_MAX +#define INT32_MAX (0x7FFFFFFF) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (0xFFFFFFFFu) +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterial; + + +//----------------------------------------------------------------------------- +// Types used when dealing with video services +//----------------------------------------------------------------------------- + +#define FILE_EXTENSION_ANY_MATCHING_VIDEO ".vid" + +//#define ENABLE_EXTERNAL_ENCODER_LOGGING + + +//----------------------------------------------------------------------------- +// enums used when dealing with video services +//----------------------------------------------------------------------------- + + // ============================================== + // various general video system enumerations + + +namespace VideoResult +{ + enum EVideoResult_t + { + SUCCESS = 0, + + SYSTEM_NOT_AVAILABLE, + CODEC_NOT_AVAILABLE, + FEATURE_NOT_AVAILABLE, + + UNKNOWN_OPERATION, + ILLEGAL_OPERATION, + OPERATION_NOT_SUPPORTED, + + BAD_INPUT_PARAMETERS, + OPERATION_ALREADY_PERFORMED, + OPERATION_OUT_OF_SEQUENCE, + + VIDEO_ERROR_OCCURED, + FILE_ERROR_OCCURED, + AUDIO_ERROR_OCCURED, + SYSTEM_ERROR_OCCURED, + INITIALIZATION_ERROR_OCCURED, + SHUTDOWN_ERROR_OCCURED, + + MATERIAL_NOT_FOUND, + RECORDER_NOT_FOUND, + VIDEO_FILE_NOT_FOUND, + VIDEO_SYSTEM_NOT_FOUND, + }; +}; +typedef VideoResult::EVideoResult_t VideoResult_t; + +namespace VideoSystem +{ + enum EVideoSystem_t + { + ALL_VIDEO_SYSTEMS = -2, + DETERMINE_FROM_FILE_EXTENSION = -1, + NONE = 0, + + BINK, + AVI, + WMV, + QUICKTIME, + WEBM, + + VIDEO_SYSTEM_COUNT, + VIDEO_SYSTEM_FIRST = 1, + }; +}; +typedef VideoSystem::EVideoSystem_t VideoSystem_t; + + +namespace VideoSystemStatus +{ + enum EVideoSystemStatus_t + { + OK = 0, + NOT_INSTALLED, + NOT_CURRENT_VERSION, + NOT_INITIALIZED, + INITIALIZATION_ERROR, + }; +}; +typedef VideoSystemStatus::EVideoSystemStatus_t VideoSystemStatus_t; + + +namespace VideoSystemFeature +{ + enum EVideoSystemFeature_t + { + NO_FEATURES = 0x00000000, + PLAY_VIDEO_FILE_FULL_SCREEN = 0x00000001, + PLAY_VIDEO_FILE_IN_MATERIAL = 0x00000002, + ENCODE_VIDEO_TO_FILE = 0x00000004, + ENCODE_AUDIO_TO_FILE = 0x00000008, + + + FULL_PLAYBACK = PLAY_VIDEO_FILE_FULL_SCREEN | PLAY_VIDEO_FILE_IN_MATERIAL, + FULL_ENCODE = ENCODE_VIDEO_TO_FILE | ENCODE_AUDIO_TO_FILE, + ALL_VALID_FEATURES = FULL_PLAYBACK | FULL_ENCODE, + + ESF_FORCE_UINT32 = UINT32_MAX, + }; + + DEFINE_ENUM_BITWISE_OPERATORS( EVideoSystemFeature_t ); +}; +typedef VideoSystemFeature::EVideoSystemFeature_t VideoSystemFeature_t; + + +namespace VideoSoundDeviceOperation +{ + enum EVideoSoundDeviceOperation_t + { + SET_DIRECT_SOUND_DEVICE = 0, // Windows option + SET_MILES_SOUND_DEVICE, // Supported by RAD + HOOK_X_AUDIO, // Xbox Option + SET_SOUND_MANAGER_DEVICE, // OSX Option + SET_LIB_AUDIO_DEVICE, // PS3 Option + SET_SDL_SOUND_DEVICE, // SDL Audio + SET_SDL_PARAMS, // SDL Audio params + SDLMIXER_CALLBACK, // SDLMixer callback + + OPERATION_COUNT + }; +}; +typedef VideoSoundDeviceOperation::EVideoSoundDeviceOperation_t VideoSoundDeviceOperation_t; + + + // ============================================== + // Video Encoding related settings + +namespace VideoEncodeCodec +{ + // + // NOTE: NEW CODECS SHOULD BE ADDED TO THE END OF THIS LIST. + // + enum EVideoEncodeCodec_t + { + MPEG2_CODEC, + MPEG4_CODEC, + H261_CODEC, + H263_CODEC, + H264_CODEC, + MJPEG_A_CODEC, + MJPEG_B_CODEC, + SORENSON3_CODEC, + CINEPACK_CODEC, + WEBM_CODEC, + + // + // NOTE: ADD NEW CODECS HERE. + // + + CODEC_COUNT, + + DEFAULT_CODEC = H264_CODEC, + }; +}; +typedef VideoEncodeCodec::EVideoEncodeCodec_t VideoEncodeCodec_t; + + +namespace VideoEncodeQuality +{ + enum EVideoEncodeQuality_t + { + MIN_QUALITY = 0, + MAX_QUALITY = 100 + }; +}; +typedef VideoEncodeQuality::EVideoEncodeQuality_t VideoEncodeQuality_t; + + +namespace VideoEncodeSourceFormat +{ + enum EVideoEncodeSourceFormat_t // Image source format for frames to encoded + { + BGRA_32BIT = 0, + BGR_24BIT, + RGB_24BIT, + RGBA_32BIT, + + VIDEO_FORMAT_COUNT, + VIDEO_FORMAT_FIRST = 0 + }; +}; +typedef VideoEncodeSourceFormat::EVideoEncodeSourceFormat_t VideoEncodeSourceFormat_t; + + +namespace VideoEncodeGamma +{ + enum EVideoEncodeGamma_t + { + NO_GAMMA_ADJUST = 0, + PLATFORM_STANDARD_GAMMA, + GAMMA_1_8, + GAMMA_2_2, + GAMMA_2_5, + + GAMMA_COUNT + }; +}; +typedef VideoEncodeGamma::EVideoEncodeGamma_t VideoEncodeGamma_t; + + +namespace VideoPlaybackGamma +{ + enum EVideoPlaybackGamma_t + { + USE_GAMMA_CONVAR = -1, + NO_GAMMA_ADJUST = 0, + PLATFORM_DEFAULT_GAMMMA, + GAMMA_1_8, + GAMMA_2_2, + GAMMA_2_5, + + GAMMA_COUNT + }; +}; +typedef VideoPlaybackGamma::EVideoPlaybackGamma_t VideoPlaybackGamma_t; + + + // ============================================== + // Video Playback related settings + +namespace VideoPlaybackFlags +{ + enum EVideoPlaybackFlags_t // Options when playing a video file + { + NO_PLAYBACK_OPTIONS = 0x00000000, + + // Full Screen Playback Options + FILL_WINDOW = 0x00000001, // force video fill entire window + LOCK_ASPECT_RATIO = 0x00000002, // preserve aspect ratio when scaling + INTEGRAL_SCALE = 0x00000004, // scale video only by integral amounts + CENTER_VIDEO_IN_WINDOW = 0x00000008, // center output video in window + + FORCE_MIN_PLAY_TIME = 0x00000010, // play for a minimum amount of time before allowing skip or abort + + ABORT_ON_SPACE = 0x00000100, // Keys to abort fullscreen playback on + ABORT_ON_ESC = 0x00000200, + ABORT_ON_RETURN = 0x00000400, + ABORT_ON_ANY_KEY = 0x00000700, + + PAUSE_ON_SPACE = 0x00001000, // Keys to pause fullscreen playback on + PAUSE_ON_ESC = 0x00002000, + PAUSE_ON_RETURN = 0x00004000, + PAUSE_ON_ANY_KEY = 0x00007000, + + LOOP_VIDEO = 0x00010000, // Full Screen and Video material + NO_AUDIO = 0x00020000, + PRELOAD_VIDEO = 0x00040000, + + DONT_AUTO_START_VIDEO = 0x00100000, // Don't begin playing until told to do so. + TEXTURES_ACTUAL_SIZE = 0x00200000, // Try and use textures the same size as the video frame + + VALID_FULLSCREEN_FLAGS = 0x0007771F, // Playback Flags that are valid for playing videos fullscreen + VALID_MATERIAL_FLAGS = 0x00370000, // Playback Flags that are valid for playing videos in a material + + DEFAULT_MATERIAL_OPTIONS = NO_PLAYBACK_OPTIONS, + DEFAULT_FULLSCREEN_OPTIONS = CENTER_VIDEO_IN_WINDOW | LOCK_ASPECT_RATIO | ABORT_ON_ANY_KEY, + + EVPF_FORCE_UINT32 = UINT32_MAX, + }; + + DEFINE_ENUM_BITWISE_OPERATORS( EVideoPlaybackFlags_t ); +} +typedef VideoPlaybackFlags::EVideoPlaybackFlags_t VideoPlaybackFlags_t; + + +namespace AudioEncodeSourceFormat +{ + enum EAudioEncodeSourceFormat_t // Audio source format to encode + { + AUDIO_NONE = 0, + AUDIO_16BIT_PCMStereo, + + AUDIO_FORMAT_COUNT + }; +}; +typedef AudioEncodeSourceFormat::EAudioEncodeSourceFormat_t AudioEncodeSourceFormat_t; + + +namespace AudioEncodeOptions +{ + enum EAudioEncodeOptions_t // Options to control audio encoding + { + NO_AUDIO_OPTIONS = 0x00000000, + + USE_AUDIO_ENCODE_GROUP_SIZE = 0x00000001, // When adding to the video media, use fixed size sample groups + GROUP_SIZE_IS_VIDEO_FRAME = 0x00000002, // use a group size equal to one video frame in duration + LIMIT_AUDIO_TRACK_TO_VIDEO_DURATION = 0x00000004, // Don't let the Audio Track exceed the video track in duration + PAD_AUDIO_WITH_SILENCE = 0x00000008, // If Audio track duration is less than video track's, pad with silence + + AEO_FORCE_UINT32 = UINT32_MAX, + }; + DEFINE_ENUM_BITWISE_OPERATORS( EAudioEncodeOptions_t ); +} +typedef AudioEncodeOptions::EAudioEncodeOptions_t AudioEncodeOptions_t; + + +//----------------------------------------------------------------------------- +// Frame Rate Class +//----------------------------------------------------------------------------- +class VideoFrameRate_t +{ + public: + inline VideoFrameRate_t() : m_TimeUnitsPerSecond( 0 ), m_TimeUnitsPerFrame( 1000 ) {}; + + inline VideoFrameRate_t( int FPS, bool NTSC ) { SetFPS( FPS, NTSC); } + inline explicit VideoFrameRate_t( float FPS ) { SetFPS( FPS); }; + + inline VideoFrameRate_t& operator=( const VideoFrameRate_t& rhs ) { m_TimeUnitsPerSecond = rhs.m_TimeUnitsPerSecond; m_TimeUnitsPerFrame = rhs.m_TimeUnitsPerFrame; return *this; } + inline VideoFrameRate_t( const VideoFrameRate_t &rhs ) { *this = rhs; }; + + inline void SetRaw( int timeUnitsPerSecond, int TimeUnitsPerFrame ) { m_TimeUnitsPerSecond = timeUnitsPerSecond; m_TimeUnitsPerFrame = TimeUnitsPerFrame; } + + inline float GetFPS() const { return (float) m_TimeUnitsPerSecond / (float) m_TimeUnitsPerFrame; } + inline int GetIntFPS() const { return (int) ( (float) m_TimeUnitsPerSecond / (float) m_TimeUnitsPerFrame + 0.5f ); } + inline bool IsNTSCRate() const { return ( m_TimeUnitsPerFrame == 1001 ); } + inline int GetUnitsPerSecond() const { return m_TimeUnitsPerSecond; } + inline int GetUnitsPerFrame() const { return m_TimeUnitsPerFrame; } + + inline void SetFPS( int FPS, bool NTSC ) { m_TimeUnitsPerSecond = FPS * 1000; m_TimeUnitsPerFrame = 1000 + (uint) NTSC; } + inline void SetFPS( float FPS ) { m_TimeUnitsPerSecond = (uint) ( FPS * 1000.0f ); m_TimeUnitsPerFrame = 1000; } + + static inline bool IsNTSC( float FPS ) { float diff = ceil(FPS) - FPS; return ( diff > 0.02f && diff < 0.05f); } + + inline void Clear() { m_TimeUnitsPerSecond = 0; m_TimeUnitsPerFrame = 1000; } + inline bool IsValid() { return ( m_TimeUnitsPerSecond != 0); } + + private: + uint32 m_TimeUnitsPerSecond; + uint32 m_TimeUnitsPerFrame; +}; + + + +//----------------------------------------------------------------------------- +// specific interfaces returned and managed by video services +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Video Material interface - manages the playing back of a video to a +// a material / texture combo +//----------------------------------------------------------------------------- +class IVideoMaterial : public IBaseInterface +{ + public: + // Video information functions + virtual const char *GetVideoFileName() = 0; // Gets the file name of the video this material is playing + virtual VideoResult_t GetLastResult() = 0; // Gets detailed info on the last operation + + virtual VideoFrameRate_t &GetVideoFrameRate() = 0; // Returns the frame rate of the associated video in FPS + + // Audio Functions + virtual bool HasAudio() = 0; // Query if the video has an audio track + + virtual bool SetVolume( float fVolume ) = 0; // Adjust the playback volume + virtual float GetVolume() = 0; // Query the current volume + + virtual void SetMuted( bool bMuteState ) = 0; // Mute/UnMutes the audio playback + virtual bool IsMuted() = 0; // Query muted status + + virtual VideoResult_t SoundDeviceCommand( VideoSoundDeviceOperation_t operation, void *pDevice = nullptr, void *pData = nullptr ) = 0; // Assign Sound Device for this Video Material + + // Video playback state functions + virtual bool IsVideoReadyToPlay() = 0; // Queries if the video material was initialized successfully and is ready for playback, but not playing or finished + virtual bool IsVideoPlaying() = 0; // Is the video currently playing (and needs update calls, etc), or paused while playing? + virtual bool IsNewFrameReady() = 0; // Do we have a new frame to get & display? + virtual bool IsFinishedPlaying() = 0; // Have we reached the end of the movie + + virtual bool StartVideo() = 0; // Starts the video playing + virtual bool StopVideo() = 0; // Terminates the video playing + + virtual void SetLooping( bool bLoopVideo ) = 0; // Sets the video to loop (or not) + virtual bool IsLooping() = 0; // Queries if the video is looping + + virtual void SetPaused( bool bPauseState ) = 0; // Pauses or Unpauses video playback + virtual bool IsPaused() = 0; // Queries if the video is paused + + // Position in playback functions + virtual float GetVideoDuration() = 0; // Returns the duration of the associated video in seconds + virtual int GetFrameCount() = 0; // Returns the total number of (unique) frames in the video + + virtual bool SetFrame( int FrameNum ) = 0; // Sets the current frame # in the video to play next + virtual int GetCurrentFrame() = 0; // Gets the current frame # for the video playback, 0 based + + virtual bool SetTime( float flTime ) = 0; // Sets the video playback to specified time (in seconds) + virtual float GetCurrentVideoTime() = 0; // Gets the current time in the video playback + + // Update function + virtual bool Update() = 0; // Updates the video frame to reflect the time passed, true = new frame available + + // Material / Texture Info functions + virtual IMaterial *GetMaterial() = 0; // Gets the IMaterial associated with an video material + + virtual void GetVideoTexCoordRange( float *pMaxU, float *pMaxV ) = 0; // Returns the max texture coordinate of the video portion of the material surface ( 0.0, 0.0 to U, V ) + virtual void GetVideoImageSize( int *pWidth, int *pHeight ) = 0; // Returns the frame size of the Video Image Frame in pixels ( the stored in a subrect of the material itself) + +}; + + +//----------------------------------------------------------------------------- +// Video Recorder interface - manages the creation of a new video file +//----------------------------------------------------------------------------- +class IVideoRecorder : public IBaseInterface +{ + public: + virtual bool EstimateMovieFileSize( size_t *pEstSize, int movieWidth, int movieHeight, VideoFrameRate_t movieFps, float movieDuration, VideoEncodeCodec_t theCodec, int videoQuality, AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0 ) = 0; + + virtual bool CreateNewMovieFile( const char *pFilename, bool hasAudioTrack = false ) = 0; + + virtual bool SetMovieVideoParameters( VideoEncodeCodec_t theCodec, int videoQuality, int movieFrameWidth, int movieFrameHeight, VideoFrameRate_t movieFPS, VideoEncodeGamma_t gamma = VideoEncodeGamma::NO_GAMMA_ADJUST ) = 0; + virtual bool SetMovieSourceImageParameters( VideoEncodeSourceFormat_t srcImageFormat, int imgWidth, int imgHeight ) = 0; + virtual bool SetMovieSourceAudioParameters( AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0, AudioEncodeOptions_t audioOptions = AudioEncodeOptions::NO_AUDIO_OPTIONS, int audioSampleGroupSize = 0) = 0; + + virtual bool IsReadyToRecord() = 0; + virtual VideoResult_t GetLastResult() = 0; + + virtual bool AppendVideoFrame( void *pFrameBuffer, int nStrideAdjustBytes = 0 ) = 0; + virtual bool AppendAudioSamples( void *pSampleBuffer, size_t sampleSize ) = 0; + + virtual int GetFrameCount() = 0; + virtual int GetSampleCount() = 0; + + virtual VideoFrameRate_t GetFPS() = 0; + virtual int GetSampleRate() = 0; + + virtual bool AbortMovie() = 0; + virtual bool FinishMovie( bool SaveMovieToDisk = true ) = 0; + +#ifdef ENABLE_EXTERNAL_ENCODER_LOGGING + virtual bool LogMessage( const char *msg ) = 0; +#endif + +}; + + + + +//----------------------------------------------------------------------------- +// Main VIDEO_SERVICES interface +//----------------------------------------------------------------------------- +#define VIDEO_SERVICES_INTERFACE_VERSION "IVideoServices002" + + +class IVideoServices : public IAppSystem +{ + public: + // Query the available video systems + virtual int GetAvailableVideoSystemCount() = 0; + virtual VideoSystem_t GetAvailableVideoSystem( int n ) = 0; + + virtual bool IsVideoSystemAvailable( VideoSystem_t videoSystem ) = 0; + virtual VideoSystemStatus_t GetVideoSystemStatus( VideoSystem_t videoSystem ) = 0; + virtual VideoSystemFeature_t GetVideoSystemFeatures( VideoSystem_t videoSystem ) = 0; + virtual const char *GetVideoSystemName( VideoSystem_t videoSystem ) = 0; + + virtual VideoSystem_t FindNextSystemWithFeature( VideoSystemFeature_t features, VideoSystem_t startAfter = VideoSystem::NONE ) = 0; + + virtual VideoResult_t GetLastResult() = 0; + + // deal with video file extensions and video system mappings + virtual int GetSupportedFileExtensionCount( VideoSystem_t videoSystem ) = 0; + virtual const char *GetSupportedFileExtension( VideoSystem_t videoSystem, int extNum = 0 ) = 0; + virtual VideoSystemFeature_t GetSupportedFileExtensionFeatures( VideoSystem_t videoSystem, int extNum = 0 ) = 0; + + virtual VideoSystem_t LocateVideoSystemForPlayingFile( const char *pFileName, VideoSystemFeature_t playMode = VideoSystemFeature::PLAY_VIDEO_FILE_IN_MATERIAL ) = 0; + virtual VideoResult_t LocatePlayableVideoFile( const char *pSearchFileName, const char *pPathID, VideoSystem_t *pPlaybackSystem, char *pPlaybackFileName, int fileNameMaxLen, VideoSystemFeature_t playMode = VideoSystemFeature::FULL_PLAYBACK ) = 0; + + // Create/destroy a video material + virtual IVideoMaterial *CreateVideoMaterial( const char *pMaterialName, const char *pVideoFileName, const char *pPathID = nullptr, + VideoPlaybackFlags_t playbackFlags = VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS, + VideoSystem_t videoSystem = VideoSystem::DETERMINE_FROM_FILE_EXTENSION, bool PlayAlternateIfNotAvailable = true ) = 0; + + virtual VideoResult_t DestroyVideoMaterial( IVideoMaterial* pVideoMaterial ) = 0; + virtual int GetUniqueMaterialID() = 0; + + // Create/destroy a video encoder + virtual VideoResult_t IsRecordCodecAvailable( VideoSystem_t videoSystem, VideoEncodeCodec_t codec ) = 0; + + virtual IVideoRecorder *CreateVideoRecorder( VideoSystem_t videoSystem ) = 0; + virtual VideoResult_t DestroyVideoRecorder( IVideoRecorder *pVideoRecorder ) = 0; + + // Plays a given video file until it completes or the user presses ESC, SPACE, or ENTER + virtual VideoResult_t PlayVideoFileFullScreen( const char *pFileName, const char *pPathID, void *mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime, + VideoPlaybackFlags_t playbackFlags = VideoPlaybackFlags::DEFAULT_FULLSCREEN_OPTIONS, + VideoSystem_t videoSystem = VideoSystem::DETERMINE_FROM_FILE_EXTENSION, bool PlayAlternateIfNotAvailable = true ) = 0; + + // Sets the sound devices that the video will decode to + virtual VideoResult_t SoundDeviceCommand( VideoSoundDeviceOperation_t operation, void *pDevice = nullptr, void *pData = nullptr, VideoSystem_t videoSystem = VideoSystem::ALL_VIDEO_SYSTEMS ) = 0; + + // Get the (localized) name of a codec as a string + virtual const wchar_t *GetCodecName( VideoEncodeCodec_t nCodec ) = 0; + +}; + + + + + + + + +#endif // IVIDEOSERVICES_H diff --git a/public/view_shared.h b/public/view_shared.h new file mode 100644 index 0000000..a5af4d3 --- /dev/null +++ b/public/view_shared.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VIEW_SHARED_H +#define VIEW_SHARED_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "mathlib/vector.h" +#include "materialsystem/MaterialSystemUtil.h" + + +//----------------------------------------------------------------------------- +// Flags passed in with view setup +//----------------------------------------------------------------------------- +enum ClearFlags_t +{ + VIEW_CLEAR_COLOR = 0x1, + VIEW_CLEAR_DEPTH = 0x2, + VIEW_CLEAR_FULL_TARGET = 0x4, + VIEW_NO_DRAW = 0x8, + VIEW_CLEAR_OBEY_STENCIL = 0x10, // Draws a quad allowing stencil test to clear through portals + VIEW_CLEAR_STENCIL = 0x20, +}; + +enum StereoEye_t +{ + STEREO_EYE_MONO = 0, + STEREO_EYE_LEFT = 1, + STEREO_EYE_RIGHT = 2, + STEREO_EYE_MAX = 3, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Renderer setup data. +//----------------------------------------------------------------------------- +class CViewSetup +{ +public: + CViewSetup() + { + m_flAspectRatio = 0.0f; + m_bRenderToSubrectOfLargerScreen = false; + m_bDoBloomAndToneMapping = true; + m_bOrtho = false; + m_bOffCenter = false; + m_bCacheFullSceneState = false; +// m_bUseExplicitViewVector = false; + m_bViewToProjectionOverride = false; + m_eStereoEye = STEREO_EYE_MONO; + } + +// shared by 2D & 3D views + + // left side of view window + int x; + int m_nUnscaledX; + // top side of view window + int y; + int m_nUnscaledY; + // width of view window + int width; + int m_nUnscaledWidth; + // height of view window + int height; + // which eye are we rendering? + StereoEye_t m_eStereoEye; + int m_nUnscaledHeight; + +// the rest are only used by 3D views + + // Orthographic projection? + bool m_bOrtho; + // View-space rectangle for ortho projection. + float m_OrthoLeft; + float m_OrthoTop; + float m_OrthoRight; + float m_OrthoBottom; + + // horizontal FOV in degrees + float fov; + // horizontal FOV in degrees for in-view model + float fovViewmodel; + + // 3D origin of camera + Vector origin; + + // heading of camera (pitch, yaw, roll) + QAngle angles; + // local Z coordinate of near plane of camera + float zNear; + // local Z coordinate of far plane of camera + float zFar; + + // local Z coordinate of near plane of camera ( when rendering view model ) + float zNearViewmodel; + // local Z coordinate of far plane of camera ( when rendering view model ) + float zFarViewmodel; + + // set to true if this is to draw into a subrect of the larger screen + // this really is a hack, but no more than the rest of the way this class is used + bool m_bRenderToSubrectOfLargerScreen; + + // The aspect ratio to use for computing the perspective projection matrix + // (0.0f means use the viewport) + float m_flAspectRatio; + + // Controls for off-center projection (needed for poster rendering) + bool m_bOffCenter; + float m_flOffCenterTop; + float m_flOffCenterBottom; + float m_flOffCenterLeft; + float m_flOffCenterRight; + + // Control that the SFM needs to tell the engine not to do certain post-processing steps + bool m_bDoBloomAndToneMapping; + + // Cached mode for certain full-scene per-frame varying state such as sun entity coverage + bool m_bCacheFullSceneState; + + // If using VR, the headset calibration will feed you a projection matrix per-eye. + // This does NOT override the Z range - that will be set up as normal (i.e. the values in this matrix will be ignored). + bool m_bViewToProjectionOverride; + VMatrix m_ViewToProjection; +}; + + + +#endif // VIEW_SHARED_H diff --git a/public/vphysics/collision_set.h b/public/vphysics/collision_set.h new file mode 100644 index 0000000..66aaeb8 --- /dev/null +++ b/public/vphysics/collision_set.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// A set of collision rules +// NOTE: Defaults to all indices disabled +class IPhysicsCollisionSet +{ +public: + ~IPhysicsCollisionSet() {} + + virtual void EnableCollisions( int index0, int index1 ) = 0; + virtual void DisableCollisions( int index0, int index1 ) = 0; + + virtual bool ShouldCollide( int index0, int index1 ) = 0; +}; \ No newline at end of file diff --git a/public/vphysics/constraints.h b/public/vphysics/constraints.h new file mode 100644 index 0000000..afea760 --- /dev/null +++ b/public/vphysics/constraints.h @@ -0,0 +1,345 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CONSTRAINTS_H +#define CONSTRAINTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vphysics_interface.h" +#include "mathlib/mathlib.h" + +// constraint groups +struct constraint_groupparams_t +{ + int additionalIterations; // additional solver iterations make the constraint system more stable + int minErrorTicks; // minimum number of ticks with an error before it's reported + float errorTolerance; // error tolerance in HL units + + inline void Defaults() + { + additionalIterations = 0; + minErrorTicks = 15; + errorTolerance = 3.0f; + } +}; + +// Breakable constraints; +// +// forceLimit - kg * in / s limit (N * conversion(in/m)) +// torqueLimit - kg * in^2 / s (Nm * conversion(in^2/m^2)) + +// +// strength 0 - 1 +struct constraint_breakableparams_t +{ + float strength; // strength of the constraint 0.0 - 1.0 + float forceLimit; // constraint force limit to break (0 means never break) + float torqueLimit; // constraint torque limit to break (0 means never break) + float bodyMassScale[2]; // scale applied to mass of reference/attached object before solving constriant + bool isActive; + + inline void Defaults() + { + forceLimit = 0.0f; + torqueLimit = 0.0f; + strength = 1.0f; + bodyMassScale[0] = 1.0f; + bodyMassScale[1] = 1.0f; + isActive = true; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: constraint limit on a single rotation axis +//----------------------------------------------------------------------------- +struct constraint_axislimit_t +{ + float minRotation; + float maxRotation; + float angularVelocity; // desired angular velocity around hinge + float torque; // torque to achieve angular velocity (use 0, torque for "friction") + + inline void SetAxisFriction( float rmin, float rmax, float friction ) + { + minRotation = rmin; + maxRotation = rmax; + angularVelocity = 0; + torque = friction; + } + inline void Defaults() + { + SetAxisFriction(0,0,0); + } +}; + +// Builds a transform which maps points in the input object's local space +// to the output object's local space +inline void BuildObjectRelativeXform( IPhysicsObject *pOutputSpace, IPhysicsObject *pInputSpace, matrix3x4_t &xformInToOut ) +{ + matrix3x4_t outInv, tmp, input; + pOutputSpace->GetPositionMatrix( &tmp ); + MatrixInvert( tmp, outInv ); + pInputSpace->GetPositionMatrix( &input ); + ConcatTransforms( outInv, input, xformInToOut ); +} + + +//----------------------------------------------------------------------------- +// Purpose: special limited ballsocket constraint for ragdolls. +// Has axis limits for all 3 axes. +//----------------------------------------------------------------------------- +struct constraint_ragdollparams_t +{ + constraint_breakableparams_t constraint; + matrix3x4_t constraintToReference;// xform constraint space to refobject space + matrix3x4_t constraintToAttached; // xform constraint space to attached object space + int parentIndex; // NOTE: only used for parsing. NEED NOT BE SET for create + int childIndex; // NOTE: only used for parsing. NEED NOT BE SET for create + + constraint_axislimit_t axes[3]; + bool onlyAngularLimits; // only angular limits (not translation as well?) + bool isActive; + bool useClockwiseRotations; // HACKHACK: Did this wrong in version one. Fix in the future. + + inline void Defaults() + { + constraint.Defaults(); + isActive = true; + SetIdentityMatrix( constraintToReference ); + SetIdentityMatrix( constraintToAttached ); + parentIndex = -1; + childIndex = -1; + axes[0].Defaults(); + axes[1].Defaults(); + axes[2].Defaults(); + onlyAngularLimits = false; + useClockwiseRotations = false; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Used to init a hinge restricting the relative position and orientation +// of two objects to rotation around a single axis +//----------------------------------------------------------------------------- +struct constraint_hingeparams_t +{ + Vector worldPosition; // position in world space on the hinge axis + Vector worldAxisDirection; // unit direction vector of the hinge axis in world space + constraint_axislimit_t hingeAxis; + constraint_breakableparams_t constraint; + + inline void Defaults() + { + worldPosition.Init(); + worldAxisDirection.Init(); + hingeAxis.Defaults(); + constraint.Defaults(); + } +}; + +struct constraint_limitedhingeparams_t : public constraint_hingeparams_t +{ + Vector referencePerpAxisDirection; // unit direction vector vector perpendicular to the hinge axis in world space + Vector attachedPerpAxisDirection; // unit direction vector vector perpendicular to the hinge axis in world space + + constraint_limitedhingeparams_t() {} + constraint_limitedhingeparams_t( const constraint_hingeparams_t &hinge ) + { + static_cast(*this) = hinge; + referencePerpAxisDirection.Init(); + attachedPerpAxisDirection.Init(); + } + + inline void Defaults() + { + this->constraint_hingeparams_t::Defaults(); + referencePerpAxisDirection.Init(); + attachedPerpAxisDirection.Init(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Used to init a constraint that fixes the position and orientation +// of two objects relative to each other (like glue) +//----------------------------------------------------------------------------- +struct constraint_fixedparams_t +{ + matrix3x4_t attachedRefXform; // xform attached object space to ref object space + constraint_breakableparams_t constraint; + + inline void InitWithCurrentObjectState( IPhysicsObject *pRef, IPhysicsObject *pAttached ) + { + BuildObjectRelativeXform( pRef, pAttached, attachedRefXform ); + } + + inline void Defaults() + { + SetIdentityMatrix( attachedRefXform ); + constraint.Defaults(); + } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Same parameters as fixed constraint, but torqueLimit has no effect +//----------------------------------------------------------------------------- +struct constraint_ballsocketparams_t +{ + Vector constraintPosition[2]; // position of the constraint in each object's space + constraint_breakableparams_t constraint; + inline void Defaults() + { + constraint.Defaults(); + constraintPosition[0].Init(); + constraintPosition[1].Init(); + } + + void InitWithCurrentObjectState( IPhysicsObject *pRef, IPhysicsObject *pAttached, const Vector &ballsocketOrigin ) + { + pRef->WorldToLocal( &constraintPosition[0], ballsocketOrigin ); + pAttached->WorldToLocal( &constraintPosition[1], ballsocketOrigin ); + } +}; + +struct constraint_slidingparams_t +{ + matrix3x4_t attachedRefXform; // xform attached object space to ref object space + Vector slideAxisRef; // unit direction vector of the slide axis in ref object space + constraint_breakableparams_t constraint; + // NOTE: if limitMin == limitMax there is NO limit set! + float limitMin; // minimum limit coordinate refAxisDirection space + float limitMax; // maximum limit coordinate refAxisDirection space + float friction; // friction on sliding + float velocity; // desired velocity + + inline void Defaults() + { + SetIdentityMatrix( attachedRefXform ); + slideAxisRef.Init(); + limitMin = limitMax = 0; + friction = 0; + velocity = 0; + constraint.Defaults(); + } + + inline void SetFriction( float inputFriction ) + { + friction = inputFriction; + velocity = 0; + } + + inline void SetLinearMotor( float inputVelocity, float maxForce ) + { + friction = maxForce; + velocity = inputVelocity; + } + + inline void InitWithCurrentObjectState( IPhysicsObject *pRef, IPhysicsObject *pAttached, const Vector &slideDirWorldspace ) + { + BuildObjectRelativeXform( pRef, pAttached, attachedRefXform ); + matrix3x4_t tmp; + pRef->GetPositionMatrix( &tmp ); + VectorIRotate( slideDirWorldspace, tmp, slideAxisRef ); + } +}; + +struct constraint_pulleyparams_t +{ + constraint_breakableparams_t constraint; + Vector pulleyPosition[2]; // These are the pulley positions for the reference and attached objects in world space + Vector objectPosition[2]; // local positions of attachments to the ref,att objects + float totalLength; // total rope length (include gearing!) + float gearRatio; // gearing affects attached object ALWAYS + bool isRigid; + + inline void Defaults() + { + constraint.Defaults(); + totalLength = 1.0; + gearRatio = 1.0; + pulleyPosition[0].Init(); + pulleyPosition[1].Init(); + objectPosition[0].Init(); + objectPosition[1].Init(); + isRigid = false; + } +}; + + +struct constraint_lengthparams_t +{ + constraint_breakableparams_t constraint; + Vector objectPosition[2]; // These are the positions for the reference and attached objects in local space + float totalLength; // Length of rope/spring/constraint. Distance to maintain + float minLength; // if rigid, objects are not allowed to move closer than totalLength either + + void InitWorldspace( IPhysicsObject *pRef, IPhysicsObject *pAttached, const Vector &refPosition, const Vector &attachedPosition, bool rigid = false ) + { + pRef->WorldToLocal( &objectPosition[0], refPosition ); + pAttached->WorldToLocal( &objectPosition[1], attachedPosition ); + totalLength = (refPosition - attachedPosition).Length(); + minLength = rigid ? totalLength : 0; + } + + inline void Defaults() + { + constraint.Defaults(); + objectPosition[0].Init(); + objectPosition[1].Init(); + totalLength = 1; + minLength = 0; + } +}; + +class IPhysicsConstraint +{ +public: + virtual ~IPhysicsConstraint( void ) {} + + // NOTE: Constraints are active when created. You can temporarily enable/disable them with these functions + virtual void Activate( void ) = 0; + virtual void Deactivate( void ) = 0; + + // set a pointer to the game object + virtual void SetGameData( void *gameData ) = 0; + + // get a pointer to the game object + virtual void *GetGameData( void ) const = 0; + + // Get the parent/referenced object + virtual IPhysicsObject *GetReferenceObject( void ) const = 0; + + // Get the attached object + virtual IPhysicsObject *GetAttachedObject( void ) const = 0; + + virtual void SetLinearMotor( float speed, float maxLinearImpulse ) = 0; + virtual void SetAngularMotor( float rotSpeed, float maxAngularImpulse ) = 0; + + virtual void UpdateRagdollTransforms( const matrix3x4_t &constraintToReference, const matrix3x4_t &constraintToAttached ) = 0; + virtual bool GetConstraintTransform( matrix3x4_t *pConstraintToReference, matrix3x4_t *pConstraintToAttached ) const = 0; + virtual bool GetConstraintParams( constraint_breakableparams_t *pParams ) const = 0; + + virtual void OutputDebugInfo() = 0; +}; + + +class IPhysicsConstraintGroup +{ +public: + virtual ~IPhysicsConstraintGroup( void ) {} + virtual void Activate() = 0; + virtual bool IsInErrorState() = 0; + virtual void ClearErrorState() = 0; + virtual void GetErrorParams( constraint_groupparams_t *pParams ) = 0; + virtual void SetErrorParams( const constraint_groupparams_t ¶ms ) = 0; + virtual void SolvePenetration( IPhysicsObject *pObj0, IPhysicsObject *pObj1 ) = 0; +}; + + +#endif // CONSTRAINTS_H diff --git a/public/vphysics/friction.h b/public/vphysics/friction.h new file mode 100644 index 0000000..f8d6bd6 --- /dev/null +++ b/public/vphysics/friction.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FRICTION_H +#define FRICTION_H +#ifdef _WIN32 +#pragma once +#endif + +// NOTE: This is an iterator for the contact points on an object +// NOTE: This should only be used temporarily. Holding one of these +// NOTE: across collision callbacks or calls into simulation will cause errors! +// NOTE: VPHYSICS may choose to make the data contained within this object invalid +// NOTE: any time simulation is run. +class IPhysicsFrictionSnapshot +{ +public: + virtual ~IPhysicsFrictionSnapshot() {} + + virtual bool IsValid() = 0; + + // Object 0 is this object, Object 1 is the other object + virtual IPhysicsObject *GetObject( int index ) = 0; + virtual int GetMaterial( int index ) = 0; + + virtual void GetContactPoint( Vector &out ) = 0; + + // points away from source object + virtual void GetSurfaceNormal( Vector &out ) = 0; + virtual float GetNormalForce() = 0; + virtual float GetEnergyAbsorbed() = 0; + + // recompute friction (useful if dynamically altering materials/mass) + virtual void RecomputeFriction() = 0; + // clear all friction force at this contact point + virtual void ClearFrictionForce() = 0; + + virtual void MarkContactForDelete() = 0; + virtual void DeleteAllMarkedContacts( bool wakeObjects ) = 0; + + // Move to the next friction data for this object + virtual void NextFrictionData() = 0; + virtual float GetFrictionCoefficient() = 0; +}; + + + +#endif // FRICTION_H diff --git a/public/vphysics/object_hash.h b/public/vphysics/object_hash.h new file mode 100644 index 0000000..bfdef84 --- /dev/null +++ b/public/vphysics/object_hash.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef OBJECT_HASH_H +#define OBJECT_HASH_H +#ifdef _WIN32 +#pragma once +#endif + +class IPhysicsObjectPairHash +{ +public: + virtual ~IPhysicsObjectPairHash() {} + virtual void AddObjectPair( void *pObject0, void *pObject1 ) = 0; + virtual void RemoveObjectPair( void *pObject0, void *pObject1 ) = 0; + virtual bool IsObjectPairInHash( void *pObject0, void *pObject1 ) = 0; + virtual void RemoveAllPairsForObject( void *pObject0 ) = 0; + virtual bool IsObjectInHash( void *pObject0 ) = 0; + + // Used to iterate over all pairs an object is part of + virtual int GetPairCountForObject( void *pObject0 ) = 0; + virtual int GetPairListForObject( void *pObject0, int nMaxCount, void **ppObjectList ) = 0; +}; + + +#endif // OBJECT_HASH_H diff --git a/public/vphysics/performance.h b/public/vphysics/performance.h new file mode 100644 index 0000000..fa1cf47 --- /dev/null +++ b/public/vphysics/performance.h @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PERFORMANCE_H +#define PERFORMANCE_H +#ifdef _WIN32 +#pragma once +#endif + +// Don't ever change these values, or face all kinds of subtle gameplay changes +const float k_flMaxVelocity = 2000.0f; +const float k_flMaxAngularVelocity = 360.0f * 10.0f; + +const float DEFAULT_MIN_FRICTION_MASS = 10.0f; +const float DEFAULT_MAX_FRICTION_MASS = 2500.0f; +struct physics_performanceparams_t +{ + int maxCollisionsPerObjectPerTimestep; // object will be frozen after this many collisions (visual hitching vs. CPU cost) + int maxCollisionChecksPerTimestep; // objects may penetrate after this many collision checks (can be extended in AdditionalCollisionChecksThisTick) + float maxVelocity; // limit world space linear velocity to this (in / s) + float maxAngularVelocity; // limit world space angular velocity to this (degrees / s) + float lookAheadTimeObjectsVsWorld; // predict collisions this far (seconds) into the future + float lookAheadTimeObjectsVsObject; // predict collisions this far (seconds) into the future + float minFrictionMass; // min mass for friction solves (constrains dynamic range of mass to improve stability) + float maxFrictionMass; // mas mass for friction solves + + void Defaults() + { + maxCollisionsPerObjectPerTimestep = 6; + maxCollisionChecksPerTimestep = 250; + maxVelocity = k_flMaxVelocity; + maxAngularVelocity = k_flMaxAngularVelocity; + lookAheadTimeObjectsVsWorld = 1.0f; + lookAheadTimeObjectsVsObject = 0.5f; + minFrictionMass = DEFAULT_MIN_FRICTION_MASS; + maxFrictionMass = DEFAULT_MAX_FRICTION_MASS; + } +}; + + +#endif // PERFORMANCE_H diff --git a/public/vphysics/player_controller.h b/public/vphysics/player_controller.h new file mode 100644 index 0000000..6fbe1b0 --- /dev/null +++ b/public/vphysics/player_controller.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef PLAYER_CONTROLLER_H +#define PLAYER_CONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +class IPhysicsPlayerControllerEvent +{ +public: + virtual int ShouldMoveTo( IPhysicsObject *pObject, const Vector &position ) = 0; +}; + +class IPhysicsPlayerController +{ +public: + virtual ~IPhysicsPlayerController( void ) {} + + virtual void Update( const Vector &position, const Vector &velocity, float secondsToArrival, bool onground, IPhysicsObject *ground ) = 0; + virtual void SetEventHandler( IPhysicsPlayerControllerEvent *handler ) = 0; + virtual bool IsInContact( void ) = 0; + virtual void MaxSpeed( const Vector &maxVelocity ) = 0; + + // allows game code to change collision models + virtual void SetObject( IPhysicsObject *pObject ) = 0; + // UNDONE: Refactor this and shadow controllers into a single class/interface through IPhysicsObject + virtual int GetShadowPosition( Vector *position, QAngle *angles ) = 0; + virtual void StepUp( float height ) = 0; + virtual void Jump() = 0; + virtual void GetShadowVelocity( Vector *velocity ) = 0; + virtual IPhysicsObject *GetObject() = 0; + virtual void GetLastImpulse( Vector *pOut ) = 0; + + virtual void SetPushMassLimit( float maxPushMass ) = 0; + virtual void SetPushSpeedLimit( float maxPushSpeed ) = 0; + + virtual float GetPushMassLimit() = 0; + virtual float GetPushSpeedLimit() = 0; + virtual bool WasFrozen() = 0; +}; + +#endif // PLAYER_CONTROLLER_H diff --git a/public/vphysics/stats.h b/public/vphysics/stats.h new file mode 100644 index 0000000..21d8119 --- /dev/null +++ b/public/vphysics/stats.h @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef STATS_H +#define STATS_H +#ifdef _WIN32 +#pragma once +#endif + +// internal counters to measure cost of physics simulation +struct physics_stats_t +{ + float maxRescueSpeed; + float maxSpeedGain; + + int impactSysNum; + int impactCounter; + int impactSumSys; + int impactHardRescueCount; + int impactRescueAfterCount; + int impactDelayedCount; + int impactCollisionChecks; + int impactStaticCount; + + double totalEnergyDestroyed; + int collisionPairsTotal; + int collisionPairsCreated; + int collisionPairsDestroyed; + + int potentialCollisionsObjectVsObject; + int potentialCollisionsObjectVsWorld; + + int frictionEventsProcessed; +}; + + +#endif // STATS_H diff --git a/public/vphysics/vehicles.h b/public/vphysics/vehicles.h new file mode 100644 index 0000000..0125aa9 --- /dev/null +++ b/public/vphysics/vehicles.h @@ -0,0 +1,250 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VEHICLES_H +#define VEHICLES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamap.h" + + +#define VEHICLE_TYPE_CAR_WHEELS (1<<0) +#define VEHICLE_TYPE_CAR_RAYCAST (1<<1) +#define VEHICLE_TYPE_JETSKI_RAYCAST (1<<2) +#define VEHICLE_TYPE_AIRBOAT_RAYCAST (1<<3) + +#define VEHICLE_MAX_AXLE_COUNT 4 +#define VEHICLE_MAX_GEAR_COUNT 6 +#define VEHICLE_MAX_WHEEL_COUNT (2*VEHICLE_MAX_AXLE_COUNT) + +#define VEHICLE_TIRE_NORMAL 0 +#define VEHICLE_TIRE_BRAKING 1 +#define VEHICLE_TIRE_POWERSLIDE 2 + +struct vehicle_controlparams_t +{ + float throttle; + float steering; + float brake; + float boost; + bool handbrake; + bool handbrakeLeft; + bool handbrakeRight; + bool brakepedal; + bool bHasBrakePedal; + bool bAnalogSteering; +}; + +struct vehicle_operatingparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + float speed; + float engineRPM; + int gear; + float boostDelay; + int boostTimeLeft; + float skidSpeed; + int skidMaterial; + float steeringAngle; + int wheelsNotInContact; + int wheelsInContact; + bool isTorqueBoosting; +}; + +// Debug! +#define VEHICLE_DEBUGRENDERDATA_MAX_WHEELS 10 +#define VEHICLE_DEBUGRENDERDATA_MAX_AXLES 3 + +struct vehicle_debugcarsystem_t +{ + Vector vecAxlePos[VEHICLE_DEBUGRENDERDATA_MAX_AXLES]; + + Vector vecWheelPos[VEHICLE_DEBUGRENDERDATA_MAX_WHEELS]; + Vector vecWheelRaycasts[VEHICLE_DEBUGRENDERDATA_MAX_WHEELS][2]; + Vector vecWheelRaycastImpacts[VEHICLE_DEBUGRENDERDATA_MAX_WHEELS]; +}; + +struct vehicleparams_t; + +class IPhysicsVehicleController +{ +public: + virtual ~IPhysicsVehicleController() {} + // call this from the game code with the control parameters + virtual void Update( float dt, vehicle_controlparams_t &controls ) = 0; + virtual const vehicle_operatingparams_t &GetOperatingParams() = 0; + virtual const vehicleparams_t &GetVehicleParams() = 0; + virtual vehicleparams_t &GetVehicleParamsForChange() = 0; + virtual float UpdateBooster(float dt) = 0; + virtual int GetWheelCount(void) = 0; + virtual IPhysicsObject *GetWheel(int index) = 0; + virtual bool GetWheelContactPoint( int index, Vector *pContactPoint, int *pSurfaceProps ) = 0; + virtual void SetSpringLength(int wheelIndex, float length) = 0; + virtual void SetWheelFriction(int wheelIndex, float friction) = 0; + + virtual void OnVehicleEnter( void ) = 0; + virtual void OnVehicleExit( void ) = 0; + + virtual void SetEngineDisabled( bool bDisable ) = 0; + virtual bool IsEngineDisabled( void ) = 0; + + // Debug + virtual void GetCarSystemDebugData( vehicle_debugcarsystem_t &debugCarSystem ) = 0; + virtual void VehicleDataReload() = 0; +}; + + +// parameters for the body object control of the vehicle +struct vehicle_bodyparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + Vector massCenterOverride; // leave at vec3_origin for no override + float massOverride; // leave at 0 for no override + float addGravity; // keeps car down + float tiltForce; // keeps car down when not on flat ground + float tiltForceHeight; // where the tilt force pulls relative to center of mass + float counterTorqueFactor; + float keepUprightTorque; + float maxAngularVelocity; // clamp the car angular velocity separately from other objects to keep stable +}; + +// wheel objects are created by vphysics, these are the parameters for those objects +// NOTE: They are paired, so only one set of parameters is necessary per axle +struct vehicle_wheelparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + float radius; + float mass; + float inertia; + float damping; // usually 0 + float rotdamping; // usually 0 + float frictionScale; // 1.5 front, 1.8 rear + int materialIndex; + int brakeMaterialIndex; + int skidMaterialIndex; + float springAdditionalLength; // 0 means the spring is at it's rest length +}; + +struct vehicle_suspensionparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + float springConstant; + float springDamping; + float stabilizerConstant; + float springDampingCompression; + float maxBodyForce; +}; + +// NOTE: both raytrace and wheel data here because jetski uses both. +struct vehicle_axleparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + Vector offset; // center of this axle in vehicle object space + Vector wheelOffset; // offset to wheel (assume other wheel is symmetric at -wheelOffset) from axle center + Vector raytraceCenterOffset; // offset to center of axle for the raytrace data. + Vector raytraceOffset; // offset to raytrace for non-wheel (some wheeled) vehicles + vehicle_wheelparams_t wheels; + vehicle_suspensionparams_t suspension; + float torqueFactor; // normalized to 1 across all axles + // e.g. 0,1 for rear wheel drive - 0.5,0.5 for 4 wheel drive + float brakeFactor; // normalized to 1 across all axles +}; + +struct vehicle_steeringparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + float degreesSlow; // angle in degrees of steering at slow speed + float degreesFast; // angle in degrees of steering at fast speed + float degreesBoost; // angle in degrees of steering at fast speed + float steeringRateSlow; // this is the speed the wheels are steered when the vehicle is slow + float steeringRateFast; // this is the speed the wheels are steered when the vehicle is "fast" + float steeringRestRateSlow; // this is the speed at which the wheels move toward their resting state (straight ahead) at slow speed + float steeringRestRateFast; // this is the speed at which the wheels move toward their resting state (straight ahead) at fast speed + float speedSlow; // this is the max speed of "slow" + float speedFast; // this is the min speed of "fast" + float turnThrottleReduceSlow; // this is the amount of throttle reduction to apply at the maximum steering angle + float turnThrottleReduceFast; // this is the amount of throttle reduction to apply at the maximum steering angle + float brakeSteeringRateFactor; // this scales the steering rate when the brake/handbrake is down + float throttleSteeringRestRateFactor; // this scales the steering rest rate when the throttle is down + float powerSlideAccel; // scale of speed to acceleration + float boostSteeringRestRateFactor; // this scales the steering rest rate when boosting + float boostSteeringRateFactor; // this scales the steering rest rate when boosting + float steeringExponent; // this makes the steering response non-linear. The steering function is linear, then raised to this power + + bool isSkidAllowed; // true/false skid flag + bool dustCloud; // flag for creating a dustcloud behind vehicle +}; + +struct vehicle_engineparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + float horsepower; + float maxSpeed; + float maxRevSpeed; + float maxRPM; // redline RPM limit + float axleRatio; // ratio of engine rev to axle rev + float throttleTime; // time to reach full throttle in seconds + + // transmission + int gearCount; // gear count - max 10 + float gearRatio[VEHICLE_MAX_GEAR_COUNT]; // ratio for each gear + + // automatic transmission (simple auto-shifter - switches at fixed RPM limits) + float shiftUpRPM; // max RPMs to switch to a higher gear + float shiftDownRPM; // min RPMs to switch to a lower gear + float boostForce; + float boostDuration; + float boostDelay; + float boostMaxSpeed; + float autobrakeSpeedGain; + float autobrakeSpeedFactor; + bool torqueBoost; + bool isAutoTransmission; // true for auto, false for manual +}; + +struct vehicleparams_t +{ + DECLARE_SIMPLE_DATADESC(); + + int axleCount; + int wheelsPerAxle; + vehicle_bodyparams_t body; + vehicle_axleparams_t axles[VEHICLE_MAX_AXLE_COUNT]; + vehicle_engineparams_t engine; + vehicle_steeringparams_t steering; +}; + +// Iterator for queries +class CPassengerSeatTransition; +typedef CUtlVector< CPassengerSeatTransition> PassengerSeatAnims_t; + +// Seat query types +enum VehicleSeatQuery_e +{ + VEHICLE_SEAT_ANY, // Any available seat for our role + VEHICLE_SEAT_NEAREST, // Seat closest to our starting point +}; + +// Seat anim types for return +enum PassengerSeatAnimType_t +{ + PASSENGER_SEAT_ENTRY, + PASSENGER_SEAT_EXIT +}; + +#define VEHICLE_SEAT_INVALID -1 // An invalid seat + +#endif // VEHICLES_H diff --git a/public/vphysics/virtualmesh.h b/public/vphysics/virtualmesh.h new file mode 100644 index 0000000..41da4ea --- /dev/null +++ b/public/vphysics/virtualmesh.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef VIRTUALMESH_H +#define VIRTUALMESH_H +#ifdef _WIN32 +#pragma once +#endif + +// NOTE: These are fixed length to make it easy to fill these out without memory allocation or storage +const int MAX_VIRTUAL_TRIANGLES = 1024; +struct virtualmeshlist_t +{ + Vector *pVerts; + int indexCount; + int triangleCount; + int vertexCount; + int surfacePropsIndex; + byte *pHull; + unsigned short indices[MAX_VIRTUAL_TRIANGLES*3]; +}; + +struct virtualmeshtrianglelist_t +{ + int triangleCount; + unsigned short triangleIndices[MAX_VIRTUAL_TRIANGLES*3]; +}; + +class IVirtualMeshEvent +{ +public: + virtual void GetVirtualMesh( void *userData, virtualmeshlist_t *pList ) = 0; + virtual void GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs ) = 0; + virtual void GetTrianglesInSphere( void *userData, const Vector ¢er, float radius, virtualmeshtrianglelist_t *pList ) = 0; +}; +struct virtualmeshparams_t +{ + IVirtualMeshEvent *pMeshEventHandler; + void *userData; + bool buildOuterHull; +}; + +#endif // VIRTUALMESH_H diff --git a/public/vphysics_interface.h b/public/vphysics_interface.h new file mode 100644 index 0000000..1852ab8 --- /dev/null +++ b/public/vphysics_interface.h @@ -0,0 +1,1152 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Public interfaces to vphysics DLL +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPHYSICS_INTERFACE_H +#define VPHYSICS_INTERFACE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/interface.h" +#include "appframework/IAppSystem.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "vcollide.h" + + +// ------------------------------------------------------------------------------------ +// UNITS: +// ------------------------------------------------------------------------------------ +// NOTE: Coordinates are in HL units. 1 unit == 1 inch. X is east (forward), Y is north (left), Z is up (up) +// QAngle are pitch (around y), Yaw (around Z), Roll (around X) +// AngularImpulse are exponetial maps (an axis in HL units scaled by a "twist" angle in degrees) +// They can be transformed like normals/covectors and added linearly +// mass is kg, volume is in^3, acceleration is in/s^2, velocity is in/s + +// density is kg/m^3 (water ~= 998 at room temperature) +// preferably, these would be in kg/in^3, but the range of those numbers makes them not very human readable +// having water be about 1000 is really convenient for data entry. +// Since volume is in in^3 and density is in kg/m^3: +// density = (mass / volume) * CUBIC_METERS_PER_CUBIC_INCH +// Force is applied using impulses (kg*in/s) +// Torque is applied using impulses (kg*degrees/s) +// ------------------------------------------------------------------------------------ + +#define METERS_PER_INCH (0.0254f) +#define CUBIC_METERS_PER_CUBIC_INCH (METERS_PER_INCH*METERS_PER_INCH*METERS_PER_INCH) +// 2.2 lbs / kg +#define POUNDS_PER_KG (2.2f) +#define KG_PER_POUND (1.0f/POUNDS_PER_KG) + +// convert from pounds to kg +#define lbs2kg(x) ((x)*KG_PER_POUND) +#define kg2lbs(x) ((x)*POUNDS_PER_KG) + +const float VPHYSICS_MIN_MASS = 0.1f; +const float VPHYSICS_MAX_MASS = 5e4f; + +class IPhysicsObject; +class IPhysicsEnvironment; +class IPhysicsSurfaceProps; +class IPhysicsConstraint; +class IPhysicsConstraintGroup; +class IPhysicsFluidController; +class IPhysicsSpring; +class IPhysicsVehicleController; +class IConvexInfo; +class IPhysicsObjectPairHash; +class IPhysicsCollisionSet; +class IPhysicsPlayerController; +class IPhysicsFrictionSnapshot; + +struct Ray_t; +struct constraint_ragdollparams_t; +struct constraint_hingeparams_t; +struct constraint_fixedparams_t; +struct constraint_ballsocketparams_t; +struct constraint_slidingparams_t; +struct constraint_pulleyparams_t; +struct constraint_lengthparams_t; +struct constraint_groupparams_t; + +struct vehicleparams_t; +struct matrix3x4_t; + +struct fluidparams_t; +struct springparams_t; +struct objectparams_t; +struct debugcollide_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct physics_stats_t; +struct physics_performanceparams_t; +struct virtualmeshparams_t; + +//enum PhysInterfaceId_t; +struct physsaveparams_t; +struct physrestoreparams_t; +struct physprerestoreparams_t; + +enum PhysInterfaceId_t +{ + PIID_UNKNOWN, + PIID_IPHYSICSOBJECT, + PIID_IPHYSICSFLUIDCONTROLLER, + PIID_IPHYSICSSPRING, + PIID_IPHYSICSCONSTRAINTGROUP, + PIID_IPHYSICSCONSTRAINT, + PIID_IPHYSICSSHADOWCONTROLLER, + PIID_IPHYSICSPLAYERCONTROLLER, + PIID_IPHYSICSMOTIONCONTROLLER, + PIID_IPHYSICSVEHICLECONTROLLER, + PIID_IPHYSICSGAMETRACE, + + PIID_NUM_TYPES +}; + + +class ISave; +class IRestore; + + +#define VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION "VPhysicsDebugOverlay001" + +abstract_class IVPhysicsDebugOverlay +{ +public: + virtual void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, int r, int g, int b, int a, float duration) = 0; + virtual void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector& p3, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b,bool noDepthTest, float duration) = 0; + virtual void AddTextOverlay(const Vector& origin, float duration, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddTextOverlay(const Vector& origin, int line_offset, float duration, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char *text) = 0; + virtual void AddSweptBoxOverlay(const Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle & angles, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, PRINTF_FORMAT_STRING const char *format, ...) = 0; +}; + +#define VPHYSICS_INTERFACE_VERSION "VPhysics031" + +abstract_class IPhysics : public IAppSystem +{ +public: + virtual IPhysicsEnvironment *CreateEnvironment( void ) = 0; + virtual void DestroyEnvironment( IPhysicsEnvironment * ) = 0; + virtual IPhysicsEnvironment *GetActiveEnvironmentByIndex( int index ) = 0; + + // Creates a fast hash of pairs of objects + // Useful for maintaining a table of object relationships like pairs that do not collide. + virtual IPhysicsObjectPairHash *CreateObjectPairHash() = 0; + virtual void DestroyObjectPairHash( IPhysicsObjectPairHash *pHash ) = 0; + + // holds a cache of these by id. So you can get by id to search for the previously created set + // UNDONE: Sets are currently limited to 32 elements. More elements will return NULL in create. + // NOTE: id is not allowed to be zero. + virtual IPhysicsCollisionSet *FindOrCreateCollisionSet( unsigned int id, int maxElementCount ) = 0; + virtual IPhysicsCollisionSet *FindCollisionSet( unsigned int id ) = 0; + virtual void DestroyAllCollisionSets() = 0; +}; + + +// CPhysConvex is a single convex solid +class CPhysConvex; +// CPhysPolysoup is an abstract triangle soup mesh +class CPhysPolysoup; +class ICollisionQuery; +class IVPhysicsKeyParser; +struct convertconvexparams_t; +class CPackedPhysicsDescription; + +class CPolyhedron; + +// UNDONE: Find a better place for this? Should be in collisionutils, but it's needs VPHYSICS' solver. +struct truncatedcone_t +{ + Vector origin; + Vector normal; + float h; // height of the cone (hl units) + float theta; // cone angle (degrees) +}; + + +#define VPHYSICS_COLLISION_INTERFACE_VERSION "VPhysicsCollision007" + +abstract_class IPhysicsCollision +{ +public: + virtual ~IPhysicsCollision( void ) {} + + // produce a convex element from verts (convex hull around verts) + virtual CPhysConvex *ConvexFromVerts( Vector **pVerts, int vertCount ) = 0; + // produce a convex element from planes (csg of planes) + virtual CPhysConvex *ConvexFromPlanes( float *pPlanes, int planeCount, float mergeDistance ) = 0; + // calculate volume of a convex element + virtual float ConvexVolume( CPhysConvex *pConvex ) = 0; + + virtual float ConvexSurfaceArea( CPhysConvex *pConvex ) = 0; + // store game-specific data in a convex solid + virtual void SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData ) = 0; + // If not converted, free the convex elements with this call + virtual void ConvexFree( CPhysConvex *pConvex ) = 0; + virtual CPhysConvex *BBoxToConvex( const Vector &mins, const Vector &maxs ) = 0; + // produce a convex element from a convex polyhedron + virtual CPhysConvex *ConvexFromConvexPolyhedron( const CPolyhedron &ConvexPolyhedron ) = 0; + // produce a set of convex triangles from a convex polygon, normal is assumed to be on the side with forward point ordering, which should be clockwise, output will need to be able to hold exactly (iPointCount-2) convexes + virtual void ConvexesFromConvexPolygon( const Vector &vPolyNormal, const Vector *pPoints, int iPointCount, CPhysConvex **pOutput ) = 0; + + // concave objects + // create a triangle soup + virtual CPhysPolysoup *PolysoupCreate( void ) = 0; + // destroy the container and memory + virtual void PolysoupDestroy( CPhysPolysoup *pSoup ) = 0; + // add a triangle to the soup + virtual void PolysoupAddTriangle( CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits ) = 0; + // convert the convex into a compiled collision model + virtual CPhysCollide *ConvertPolysoupToCollide( CPhysPolysoup *pSoup, bool useMOPP ) = 0; + + // Convert an array of convex elements to a compiled collision model (this deletes the convex elements) + virtual CPhysCollide *ConvertConvexToCollide( CPhysConvex **pConvex, int convexCount ) = 0; + virtual CPhysCollide *ConvertConvexToCollideParams( CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams ) = 0; + // Free a collide that was created with ConvertConvexToCollide() + virtual void DestroyCollide( CPhysCollide *pCollide ) = 0; + + // Get the memory size in bytes of the collision model for serialization + virtual int CollideSize( CPhysCollide *pCollide ) = 0; + // serialize the collide to a block of memory + virtual int CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap = false ) = 0; + // unserialize the collide from a block of memory + virtual CPhysCollide *UnserializeCollide( char *pBuffer, int size, int index ) = 0; + + // compute the volume of a collide + virtual float CollideVolume( CPhysCollide *pCollide ) = 0; + // compute surface area for tools + virtual float CollideSurfaceArea( CPhysCollide *pCollide ) = 0; + + // Get the support map for a collide in the given direction + virtual Vector CollideGetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction ) = 0; + + // Get an AABB for an oriented collision model + virtual void CollideGetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles ) = 0; + + virtual void CollideGetMassCenter( CPhysCollide *pCollide, Vector *pOutMassCenter ) = 0; + virtual void CollideSetMassCenter( CPhysCollide *pCollide, const Vector &massCenter ) = 0; + // get the approximate cross-sectional area projected orthographically on the bbox of the collide + // NOTE: These are fractional areas - unitless. Basically this is the fraction of the OBB on each axis that + // would be visible if the object were rendered orthographically. + // NOTE: This has been precomputed when the collide was built or this function will return 1,1,1 + virtual Vector CollideGetOrthographicAreas( const CPhysCollide *pCollide ) = 0; + virtual void CollideSetOrthographicAreas( CPhysCollide *pCollide, const Vector &areas ) = 0; + + // query the vcollide index in the physics model for the instance + virtual int CollideIndex( const CPhysCollide *pCollide ) = 0; + + // Convert a bbox to a collide + virtual CPhysCollide *BBoxToCollide( const Vector &mins, const Vector &maxs ) = 0; + virtual int GetConvexesUsedInCollideable( const CPhysCollide *pCollideable, CPhysConvex **pOutputArray, int iOutputArrayLimit ) = 0; + + + // Trace an AABB against a collide + virtual void TraceBox( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + virtual void TraceBox( const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + virtual void TraceBox( const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + + // Trace one collide against another + virtual void TraceCollide( const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + + // relatively slow test for box vs. truncated cone + virtual bool IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone ) = 0; + + // loads a set of solids into a vcollide_t + virtual void VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap = false ) = 0; + // destroyts the set of solids created by VCollideLoad + virtual void VCollideUnload( vcollide_t *pVCollide ) = 0; + + // begins parsing a vcollide. NOTE: This keeps pointers to the text + // If you free the text and call members of IVPhysicsKeyParser, it will crash + virtual IVPhysicsKeyParser *VPhysicsKeyParserCreate( const char *pKeyData ) = 0; + // Free the parser created by VPhysicsKeyParserCreate + virtual void VPhysicsKeyParserDestroy( IVPhysicsKeyParser *pParser ) = 0; + + // creates a list of verts from a collision mesh + virtual int CreateDebugMesh( CPhysCollide const *pCollisionModel, Vector **outVerts ) = 0; + // destroy the list of verts created by CreateDebugMesh + virtual void DestroyDebugMesh( int vertCount, Vector *outVerts ) = 0; + + // create a queryable version of the collision model + virtual ICollisionQuery *CreateQueryModel( CPhysCollide *pCollide ) = 0; + // destroy the queryable version + virtual void DestroyQueryModel( ICollisionQuery *pQuery ) = 0; + + virtual IPhysicsCollision *ThreadContextCreate( void ) = 0; + virtual void ThreadContextDestroy( IPhysicsCollision *pThreadContex ) = 0; + + virtual CPhysCollide *CreateVirtualMesh( const virtualmeshparams_t ¶ms ) = 0; + virtual bool SupportsVirtualMesh() = 0; + + + virtual bool GetBBoxCacheSize( int *pCachedSize, int *pCachedCount ) = 0; + + + // extracts a polyhedron that defines a CPhysConvex's shape + virtual CPolyhedron *PolyhedronFromConvex( CPhysConvex * const pConvex, bool bUseTempPolyhedron ) = 0; + + // dumps info about the collide to Msg() + virtual void OutputDebugInfo( const CPhysCollide *pCollide ) = 0; + virtual unsigned int ReadStat( int statID ) = 0; +}; + +// this can be used to post-process a collision model +abstract_class ICollisionQuery +{ +public: + virtual ~ICollisionQuery() {} + // number of convex pieces in the whole solid + virtual int ConvexCount( void ) = 0; + // triangle count for this convex piece + virtual int TriangleCount( int convexIndex ) = 0; + // get the stored game data + virtual unsigned int GetGameData( int convexIndex ) = 0; + // Gets the triangle's verts to an array + virtual void GetTriangleVerts( int convexIndex, int triangleIndex, Vector *verts ) = 0; + + // UNDONE: This doesn't work!!! + virtual void SetTriangleVerts( int convexIndex, int triangleIndex, const Vector *verts ) = 0; + + // returns the 7-bit material index + virtual int GetTriangleMaterialIndex( int convexIndex, int triangleIndex ) = 0; + // sets a 7-bit material index for this triangle + virtual void SetTriangleMaterialIndex( int convexIndex, int triangleIndex, int index7bits ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Ray traces from game engine. +//----------------------------------------------------------------------------- +abstract_class IPhysicsGameTrace +{ +public: + virtual void VehicleTraceRay( const Ray_t &ray, void *pVehicle, trace_t *pTrace ) = 0; + virtual void VehicleTraceRayWithWater( const Ray_t &ray, void *pVehicle, trace_t *pTrace ) = 0; + virtual bool VehiclePointInWater( const Vector &vecPoint ) = 0; +}; + +// The caller should implement this to return contents masks per convex on a collide +abstract_class IConvexInfo +{ +public: + virtual unsigned int GetContents( int convexGameData ) = 0; +}; + +class CPhysicsEventHandler; +abstract_class IPhysicsCollisionData +{ +public: + virtual void GetSurfaceNormal( Vector &out ) = 0; // normal points toward second object (object index 1) + virtual void GetContactPoint( Vector &out ) = 0; // contact point of collision (in world space) + virtual void GetContactSpeed( Vector &out ) = 0; // speed of surface 1 relative to surface 0 (in world space) +}; + + +struct vcollisionevent_t +{ + IPhysicsObject *pObjects[2]; + int surfaceProps[2]; + bool isCollision; + bool isShadowCollision; + float deltaCollisionTime; + + float collisionSpeed; // only valid at postCollision + IPhysicsCollisionData *pInternalData; // may change pre/post collision +}; + +abstract_class IPhysicsCollisionEvent +{ +public: + // returns the two objects that collided, time between last collision of these objects + // and an opaque data block of collision information + // NOTE: PreCollision/PostCollision ALWAYS come in matched pairs!!! + virtual void PreCollision( vcollisionevent_t *pEvent ) = 0; + virtual void PostCollision( vcollisionevent_t *pEvent ) = 0; + + // This is a scrape event. The object has scraped across another object consuming the indicated energy + virtual void Friction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit, IPhysicsCollisionData *pData ) = 0; + + virtual void StartTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ) = 0; + virtual void EndTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ) = 0; + + virtual void FluidStartTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ) = 0; + virtual void FluidEndTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ) = 0; + + virtual void PostSimulationFrame() = 0; + + virtual void ObjectEnterTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ) {} + virtual void ObjectLeaveTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ) {} +}; + + +abstract_class IPhysicsObjectEvent +{ +public: + // these can be used to optimize out queries on sleeping objects + // Called when an object is woken after sleeping + virtual void ObjectWake( IPhysicsObject *pObject ) = 0; + // called when an object goes to sleep (no longer simulating) + virtual void ObjectSleep( IPhysicsObject *pObject ) = 0; +}; + +abstract_class IPhysicsConstraintEvent +{ +public: + // the constraint is now inactive, the game code is required to delete it or re-activate it. + virtual void ConstraintBroken( IPhysicsConstraint * ) = 0; +}; + +struct hlshadowcontrol_params_t +{ + Vector targetPosition; + QAngle targetRotation; + float maxAngular; + float maxDampAngular; + float maxSpeed; + float maxDampSpeed; + float dampFactor; + float teleportDistance; +}; + +// UNDONE: At some point allow this to be parameterized using hlshadowcontrol_params_t. +// All of the infrastructure is in place to do that. +abstract_class IPhysicsShadowController +{ +public: + virtual ~IPhysicsShadowController( void ) {} + + virtual void Update( const Vector &position, const QAngle &angles, float timeOffset ) = 0; + virtual void MaxSpeed( float maxSpeed, float maxAngularSpeed ) = 0; + virtual void StepUp( float height ) = 0; + + // If the teleport distance is non-zero, the object will be teleported to + // the target location when the error exceeds this quantity. + virtual void SetTeleportDistance( float teleportDistance ) = 0; + virtual bool AllowsTranslation() = 0; + virtual bool AllowsRotation() = 0; + + // There are two classes of shadow objects: + // 1) Game physics controlled, shadow follows game physics (this is the default) + // 2) Physically controlled - shadow position is a target, but the game hasn't guaranteed that the space can be occupied by this object + virtual void SetPhysicallyControlled( bool isPhysicallyControlled ) = 0; + virtual bool IsPhysicallyControlled() = 0; + virtual void GetLastImpulse( Vector *pOut ) = 0; + virtual void UseShadowMaterial( bool bUseShadowMaterial ) = 0; + virtual void ObjectMaterialChanged( int materialIndex ) = 0; + + + //Basically get the last inputs to IPhysicsShadowController::Update(), returns last input to timeOffset in Update() + virtual float GetTargetPosition( Vector *pPositionOut, QAngle *pAnglesOut ) = 0; + + virtual float GetTeleportDistance( void ) = 0; + virtual void GetMaxSpeed( float *pMaxSpeedOut, float *pMaxAngularSpeedOut ) = 0; +}; + +class CPhysicsSimObject; +class IPhysicsMotionController; + +// Callback for simulation +class IMotionEvent +{ +public: + // These constants instruct the simulator as to how to apply the values copied to linear & angular + // GLOBAL/LOCAL refer to the coordinate system of the values, whereas acceleration/force determine whether or not + // mass is divided out (forces must be divided by mass to compute acceleration) + enum simresult_e { SIM_NOTHING = 0, SIM_LOCAL_ACCELERATION, SIM_LOCAL_FORCE, SIM_GLOBAL_ACCELERATION, SIM_GLOBAL_FORCE }; + virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) = 0; +}; + + + +abstract_class IPhysicsMotionController +{ +public: + virtual ~IPhysicsMotionController( void ) {} + virtual void SetEventHandler( IMotionEvent *handler ) = 0; + virtual void AttachObject( IPhysicsObject *pObject, bool checkIfAlreadyAttached ) = 0; + virtual void DetachObject( IPhysicsObject *pObject ) = 0; + + // returns the number of objects currently attached to the controller + virtual int CountObjects( void ) = 0; + // NOTE: pObjectList is an array with at least CountObjects() allocated + virtual void GetObjects( IPhysicsObject **pObjectList ) = 0; + // detaches all attached objects + virtual void ClearObjects( void ) = 0; + // wakes up all attached objects + virtual void WakeObjects( void ) = 0; + + enum priority_t + { + LOW_PRIORITY = 0, + MEDIUM_PRIORITY = 1, + HIGH_PRIORITY = 2, + }; + virtual void SetPriority( priority_t priority ) = 0; +}; + +// ------------------- +// Collision filter function. Return 0 if objects should not be tested for collisions, nonzero otherwise +// Install with IPhysicsEnvironment::SetCollisionFilter() +// ------------------- +abstract_class IPhysicsCollisionSolver +{ +public: + virtual int ShouldCollide( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1 ) = 0; + virtual int ShouldSolvePenetration( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1, float dt ) = 0; + + // pObject has already done the max number of collisions this tick, should we freeze it to save CPU? + virtual bool ShouldFreezeObject( IPhysicsObject *pObject ) = 0; + + // The system has already done too many collision checks, performance will suffer. + // How many more should it do? + virtual int AdditionalCollisionChecksThisTick( int currentChecksDone ) = 0; + + // This list of objects is in a connected contact graph that is too large to solve quickly + // return true to freeze the system, false to solve it + virtual bool ShouldFreezeContacts( IPhysicsObject **pObjectList, int objectCount ) = 0; +}; + +enum PhysicsTraceType_t +{ + VPHYSICS_TRACE_EVERYTHING = 0, + VPHYSICS_TRACE_STATIC_ONLY, + VPHYSICS_TRACE_MOVING_ONLY, + VPHYSICS_TRACE_TRIGGERS_ONLY, + VPHYSICS_TRACE_STATIC_AND_MOVING, +}; + +abstract_class IPhysicsTraceFilter +{ +public: + virtual bool ShouldHitObject( IPhysicsObject *pObject, int contentsMask ) = 0; + virtual PhysicsTraceType_t GetTraceType() const = 0; +}; + +abstract_class IPhysicsEnvironment +{ +public: + virtual ~IPhysicsEnvironment( void ) {} + + virtual void SetDebugOverlay( CreateInterfaceFn debugOverlayFactory ) = 0; + virtual IVPhysicsDebugOverlay *GetDebugOverlay( void ) = 0; + + // gravity is a 3-vector in in/s^2 + virtual void SetGravity( const Vector &gravityVector ) = 0; + virtual void GetGravity( Vector *pGravityVector ) const = 0; + + // air density is in kg / m^3 (water is 1000) + // This controls drag, air that is more dense has more drag. + virtual void SetAirDensity( float density ) = 0; + virtual float GetAirDensity( void ) const = 0; + + // object creation + // create a polygonal object. pCollisionModel was created by the physics builder DLL in a pre-process. + virtual IPhysicsObject *CreatePolyObject( const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams ) = 0; + // same as above, but this one cannot move or rotate (infinite mass/inertia) + virtual IPhysicsObject *CreatePolyObjectStatic( const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams ) = 0; + // Create a perfectly spherical object + virtual IPhysicsObject *CreateSphereObject( float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic ) = 0; + // destroy an object created with CreatePolyObject() or CreatePolyObjectStatic() + virtual void DestroyObject( IPhysicsObject * ) = 0; + + // Create a polygonal fluid body out of the specified collision model + // This object will affect any other objects that collide with the collision model + virtual IPhysicsFluidController *CreateFluidController( IPhysicsObject *pFluidObject, fluidparams_t *pParams ) = 0; + // Destroy an object created with CreateFluidController() + virtual void DestroyFluidController( IPhysicsFluidController * ) = 0; + + // Create a simulated spring that connects 2 objects + virtual IPhysicsSpring *CreateSpring( IPhysicsObject *pObjectStart, IPhysicsObject *pObjectEnd, springparams_t *pParams ) = 0; + virtual void DestroySpring( IPhysicsSpring * ) = 0; + + // Create a constraint in the space of pReferenceObject which is attached by the constraint to pAttachedObject + virtual IPhysicsConstraint *CreateRagdollConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll ) = 0; + virtual IPhysicsConstraint *CreateHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_hingeparams_t &hinge ) = 0; + virtual IPhysicsConstraint *CreateFixedConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed ) = 0; + virtual IPhysicsConstraint *CreateSlidingConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &sliding ) = 0; + virtual IPhysicsConstraint *CreateBallsocketConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket ) = 0; + virtual IPhysicsConstraint *CreatePulleyConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley ) = 0; + virtual IPhysicsConstraint *CreateLengthConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length ) = 0; + + virtual void DestroyConstraint( IPhysicsConstraint * ) = 0; + + virtual IPhysicsConstraintGroup *CreateConstraintGroup( const constraint_groupparams_t &groupParams ) = 0; + virtual void DestroyConstraintGroup( IPhysicsConstraintGroup *pGroup ) = 0; + + virtual IPhysicsShadowController *CreateShadowController( IPhysicsObject *pObject, bool allowTranslation, bool allowRotation ) = 0; + virtual void DestroyShadowController( IPhysicsShadowController * ) = 0; + + virtual IPhysicsPlayerController *CreatePlayerController( IPhysicsObject *pObject ) = 0; + virtual void DestroyPlayerController( IPhysicsPlayerController * ) = 0; + + virtual IPhysicsMotionController *CreateMotionController( IMotionEvent *pHandler ) = 0; + virtual void DestroyMotionController( IPhysicsMotionController *pController ) = 0; + + virtual IPhysicsVehicleController *CreateVehicleController( IPhysicsObject *pVehicleBodyObject, const vehicleparams_t ¶ms, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace ) = 0; + virtual void DestroyVehicleController( IPhysicsVehicleController * ) = 0; + + // install a function to filter collisions/penentration + virtual void SetCollisionSolver( IPhysicsCollisionSolver *pSolver ) = 0; + + // run the simulator for deltaTime seconds + virtual void Simulate( float deltaTime ) = 0; + // true if currently running the simulator (i.e. in a callback during physenv->Simulate()) + virtual bool IsInSimulation() const = 0; + + // Manage the timestep (period) of the simulator. The main functions are all integrated with + // this period as dt. + virtual float GetSimulationTimestep() const = 0; + virtual void SetSimulationTimestep( float timestep ) = 0; + + // returns the current simulation clock's value. This is an absolute time. + virtual float GetSimulationTime() const = 0; + virtual void ResetSimulationClock() = 0; + // returns the current simulation clock's value at the next frame. This is an absolute time. + virtual float GetNextFrameTime( void ) const = 0; + + // Collision callbacks (game code collision response) + virtual void SetCollisionEventHandler( IPhysicsCollisionEvent *pCollisionEvents ) = 0; + virtual void SetObjectEventHandler( IPhysicsObjectEvent *pObjectEvents ) = 0; + virtual void SetConstraintEventHandler( IPhysicsConstraintEvent *pConstraintEvents ) = 0; + + virtual void SetQuickDelete( bool bQuick ) = 0; + + virtual int GetActiveObjectCount() const = 0; + virtual void GetActiveObjects( IPhysicsObject **pOutputObjectList ) const = 0; + virtual const IPhysicsObject **GetObjectList( int *pOutputObjectCount ) const = 0; + virtual bool TransferObject( IPhysicsObject *pObject, IPhysicsEnvironment *pDestinationEnvironment ) = 0; + + virtual void CleanupDeleteList( void ) = 0; + virtual void EnableDeleteQueue( bool enable ) = 0; + + // Save/Restore methods + virtual bool Save( const physsaveparams_t ¶ms ) = 0; + virtual void PreRestore( const physprerestoreparams_t ¶ms ) = 0; + virtual bool Restore( const physrestoreparams_t ¶ms ) = 0; + virtual void PostRestore() = 0; + + // Debugging: + virtual bool IsCollisionModelUsed( CPhysCollide *pCollide ) const = 0; + + // Physics world version of the enginetrace API: + virtual void TraceRay( const Ray_t &ray, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + virtual void SweepCollideable( const CPhysCollide *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd, + const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + + // performance tuning + virtual void GetPerformanceSettings( physics_performanceparams_t *pOutput ) const = 0; + virtual void SetPerformanceSettings( const physics_performanceparams_t *pSettings ) = 0; + + // perf/cost statistics + virtual void ReadStats( physics_stats_t *pOutput ) = 0; + virtual void ClearStats() = 0; + + virtual unsigned int GetObjectSerializeSize( IPhysicsObject *pObject ) const = 0; + virtual void SerializeObjectToBuffer( IPhysicsObject *pObject, unsigned char *pBuffer, unsigned int bufferSize ) = 0; + virtual IPhysicsObject *UnserializeObjectFromBuffer( void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions ) = 0; + + + virtual void EnableConstraintNotify( bool bEnable ) = 0; + virtual void DebugCheckContacts(void) = 0; +}; + +enum callbackflags +{ + CALLBACK_GLOBAL_COLLISION = 0x0001, + CALLBACK_GLOBAL_FRICTION = 0x0002, + CALLBACK_GLOBAL_TOUCH = 0x0004, + CALLBACK_GLOBAL_TOUCH_STATIC = 0x0008, + CALLBACK_SHADOW_COLLISION = 0x0010, + CALLBACK_GLOBAL_COLLIDE_STATIC = 0x0020, + CALLBACK_IS_VEHICLE_WHEEL = 0x0040, + CALLBACK_FLUID_TOUCH = 0x0100, + CALLBACK_NEVER_DELETED = 0x0200, // HACKHACK: This means this object will never be deleted (set on the world) + CALLBACK_MARKED_FOR_DELETE = 0x0400, // This allows vphysics to skip some work for this object since it will be + // deleted later this frame. (Set automatically by destroy calls) + CALLBACK_ENABLING_COLLISION = 0x0800, // This is active during the time an object is enabling collisions + // allows us to skip collisions between "new" objects and objects marked for delete + CALLBACK_DO_FLUID_SIMULATION = 0x1000, // remove this to opt out of fluid simulations + CALLBACK_IS_PLAYER_CONTROLLER= 0x2000, // HACKHACK: Set this on players until player cotrollers are unified with shadow controllers + CALLBACK_CHECK_COLLISION_DISABLE = 0x4000, + CALLBACK_MARKED_FOR_TEST = 0x8000, // debug -- marked object is being debugged +}; + +abstract_class IPhysicsObject +{ +public: + virtual ~IPhysicsObject( void ) {} + + // returns true if this object is static/unmoveable + // NOTE: returns false for objects that are not created static, but set EnableMotion(false); + // Call IsMoveable() to find if the object is static OR has motion disabled + virtual bool IsStatic() const = 0; + virtual bool IsAsleep() const = 0; + virtual bool IsTrigger() const = 0; + virtual bool IsFluid() const = 0; // fluids are special triggers with fluid controllers attached, they return true to IsTrigger() as well! + virtual bool IsHinged() const = 0; + virtual bool IsCollisionEnabled() const = 0; + virtual bool IsGravityEnabled() const = 0; + virtual bool IsDragEnabled() const = 0; + virtual bool IsMotionEnabled() const = 0; + virtual bool IsMoveable() const = 0; // legacy: IsMotionEnabled() && !IsStatic() + virtual bool IsAttachedToConstraint(bool bExternalOnly) const = 0; + + // Enable / disable collisions for this object + virtual void EnableCollisions( bool enable ) = 0; + // Enable / disable gravity for this object + virtual void EnableGravity( bool enable ) = 0; + // Enable / disable air friction / drag for this object + virtual void EnableDrag( bool enable ) = 0; + // Enable / disable motion (pin / unpin the object) + virtual void EnableMotion( bool enable ) = 0; + + // Game can store data in each object (link back to game object) + virtual void SetGameData( void *pGameData ) = 0; + virtual void *GetGameData( void ) const = 0; + // This flags word can be defined by the game as well + virtual void SetGameFlags( unsigned short userFlags ) = 0; + virtual unsigned short GetGameFlags( void ) const = 0; + virtual void SetGameIndex( unsigned short gameIndex ) = 0; + virtual unsigned short GetGameIndex( void ) const = 0; + + // setup various callbacks for this object + virtual void SetCallbackFlags( unsigned short callbackflags ) = 0; + // get the current callback state for this object + virtual unsigned short GetCallbackFlags( void ) const = 0; + + // "wakes up" an object + // NOTE: ALL OBJECTS ARE "Asleep" WHEN CREATED + virtual void Wake( void ) = 0; + virtual void Sleep( void ) = 0; + // call this when the collision filter conditions change due to this + // object's state (e.g. changing solid type or collision group) + virtual void RecheckCollisionFilter() = 0; + // NOTE: Contact points aren't updated when collision rules change, call this to force an update + // UNDONE: Force this in RecheckCollisionFilter() ? + virtual void RecheckContactPoints() = 0; + + // mass accessors + virtual void SetMass( float mass ) = 0; + virtual float GetMass( void ) const = 0; + // get 1/mass (it's cached) + virtual float GetInvMass( void ) const = 0; + virtual Vector GetInertia( void ) const = 0; + virtual Vector GetInvInertia( void ) const = 0; + virtual void SetInertia( const Vector &inertia ) = 0; + + virtual void SetDamping( const float *speed, const float *rot ) = 0; + virtual void GetDamping( float *speed, float *rot ) const = 0; + + // coefficients are optional, pass either + virtual void SetDragCoefficient( float *pDrag, float *pAngularDrag ) = 0; + virtual void SetBuoyancyRatio( float ratio ) = 0; // Override bouyancy + + // material index + virtual int GetMaterialIndex() const = 0; + virtual void SetMaterialIndex( int materialIndex ) = 0; + + // contents bits + virtual unsigned int GetContents() const = 0; + virtual void SetContents( unsigned int contents ) = 0; + + // Get the radius if this is a sphere object (zero if this is a polygonal mesh) + virtual float GetSphereRadius() const = 0; + virtual float GetEnergy() const = 0; + virtual Vector GetMassCenterLocalSpace() const = 0; + + // NOTE: This will teleport the object + virtual void SetPosition( const Vector &worldPosition, const QAngle &angles, bool isTeleport ) = 0; + virtual void SetPositionMatrix( const matrix3x4_t&matrix, bool isTeleport ) = 0; + + virtual void GetPosition( Vector *worldPosition, QAngle *angles ) const = 0; + virtual void GetPositionMatrix( matrix3x4_t *positionMatrix ) const = 0; + // force the velocity to a new value + // NOTE: velocity is in worldspace, angularVelocity is relative to the object's + // local axes (just like pev->velocity, pev->avelocity) + virtual void SetVelocity( const Vector *velocity, const AngularImpulse *angularVelocity ) = 0; + + // like the above, but force the change into the simulator immediately + virtual void SetVelocityInstantaneous( const Vector *velocity, const AngularImpulse *angularVelocity ) = 0; + + // NOTE: velocity is in worldspace, angularVelocity is relative to the object's + // local axes (just like pev->velocity, pev->avelocity) + virtual void GetVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const = 0; + + // NOTE: These are velocities, not forces. i.e. They will have the same effect regardless of + // the object's mass or inertia + virtual void AddVelocity( const Vector *velocity, const AngularImpulse *angularVelocity ) = 0; + // gets a velocity in the object's local frame of reference at a specific point + virtual void GetVelocityAtPoint( const Vector &worldPosition, Vector *pVelocity ) const = 0; + // gets the velocity actually moved by the object in the last simulation update + virtual void GetImplicitVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const = 0; + // NOTE: These are here for convenience, but you can do them yourself by using the matrix + // returned from GetPositionMatrix() + // convenient coordinate system transformations (params - dest, src) + virtual void LocalToWorld( Vector *worldPosition, const Vector &localPosition ) const = 0; + virtual void WorldToLocal( Vector *localPosition, const Vector &worldPosition ) const = 0; + + // transforms a vector (no translation) from object-local to world space + virtual void LocalToWorldVector( Vector *worldVector, const Vector &localVector ) const = 0; + // transforms a vector (no translation) from world to object-local space + virtual void WorldToLocalVector( Vector *localVector, const Vector &worldVector ) const = 0; + + // push on an object + // force vector is direction & magnitude of impulse kg in / s + virtual void ApplyForceCenter( const Vector &forceVector ) = 0; + virtual void ApplyForceOffset( const Vector &forceVector, const Vector &worldPosition ) = 0; + // apply torque impulse. This will change the angular velocity on the object. + // HL Axes, kg degrees / s + virtual void ApplyTorqueCenter( const AngularImpulse &torque ) = 0; + + // Calculates the force/torque on the center of mass for an offset force impulse (pass output to ApplyForceCenter / ApplyTorqueCenter) + virtual void CalculateForceOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque ) const = 0; + // Calculates the linear/angular velocities on the center of mass for an offset force impulse (pass output to AddVelocity) + virtual void CalculateVelocityOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity ) const = 0; + // calculate drag scale + virtual float CalculateLinearDrag( const Vector &unitDirection ) const = 0; + virtual float CalculateAngularDrag( const Vector &objectSpaceRotationAxis ) const = 0; + + // returns true if the object is in contact with another object + // if true, puts a point on the contact surface in contactPoint, and + // a pointer to the object in contactObject + // NOTE: You can pass NULL for either to avoid computations + // BUGBUG: Use CreateFrictionSnapshot instead of this - this is a simple hack + virtual bool GetContactPoint( Vector *contactPoint, IPhysicsObject **contactObject ) const = 0; + + // refactor this a bit - move some of this to IPhysicsShadowController + virtual void SetShadow( float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation ) = 0; + virtual void UpdateShadow( const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset ) = 0; + + // returns number of ticks since last Update() call + virtual int GetShadowPosition( Vector *position, QAngle *angles ) const = 0; + virtual IPhysicsShadowController *GetShadowController( void ) const = 0; + virtual void RemoveShadowController() = 0; + // applies the math of the shadow controller to this object. + // for use in your own controllers + // returns the new value of secondsToArrival with dt time elapsed + virtual float ComputeShadowControl( const hlshadowcontrol_params_t ¶ms, float secondsToArrival, float dt ) = 0; + + + virtual const CPhysCollide *GetCollide( void ) const = 0; + virtual const char *GetName() const = 0; + + virtual void BecomeTrigger() = 0; + virtual void RemoveTrigger() = 0; + + // sets the object to be hinged. Fixed it place, but able to rotate around one axis. + virtual void BecomeHinged( int localAxis ) = 0; + // resets the object to original state + virtual void RemoveHinged() = 0; + + // used to iterate the contact points of an object + virtual IPhysicsFrictionSnapshot *CreateFrictionSnapshot() = 0; + virtual void DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot ) = 0; + + // dumps info about the object to Msg() + virtual void OutputDebugInfo() const = 0; + +}; + + +abstract_class IPhysicsSpring +{ +public: + virtual ~IPhysicsSpring( void ) {} + virtual void GetEndpoints( Vector *worldPositionStart, Vector *worldPositionEnd ) = 0; + virtual void SetSpringConstant( float flSpringContant) = 0; + virtual void SetSpringDamping( float flSpringDamping) = 0; + virtual void SetSpringLength( float flSpringLenght) = 0; + + // Get the starting object + virtual IPhysicsObject *GetStartObject( void ) = 0; + + // Get the end object + virtual IPhysicsObject *GetEndObject( void ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: These properties are defined per-material. This is accessible at +// each triangle in a collision mesh +//----------------------------------------------------------------------------- +struct surfacephysicsparams_t +{ +// vphysics physical properties + float friction; + float elasticity; // collision elasticity - used to compute coefficient of restitution + float density; // physical density (in kg / m^3) + float thickness; // material thickness if not solid (sheet materials) in inches + float dampening; +}; + +struct surfaceaudioparams_t +{ +// sounds / audio data + float reflectivity; // like elasticity, but how much sound should be reflected by this surface + float hardnessFactor; // like elasticity, but only affects impact sound choices + float roughnessFactor; // like friction, but only affects scrape sound choices + +// audio thresholds + float roughThreshold; // surface roughness > this causes "rough" scrapes, < this causes "smooth" scrapes + float hardThreshold; // surface hardness > this causes "hard" impacts, < this causes "soft" impacts + float hardVelocityThreshold; // collision velocity > this causes "hard" impacts, < this causes "soft" impacts + // NOTE: Hard impacts must meet both hardnessFactor AND velocity thresholds +}; + +struct surfacesoundnames_t +{ + unsigned short stepleft; + unsigned short stepright; + + unsigned short impactSoft; + unsigned short impactHard; + + unsigned short scrapeSmooth; + unsigned short scrapeRough; + + unsigned short bulletImpact; + unsigned short rolling; + + unsigned short breakSound; + unsigned short strainSound; +}; + +struct surfacesoundhandles_t +{ + short stepleft; + short stepright; + + short impactSoft; + short impactHard; + + short scrapeSmooth; + short scrapeRough; + + short bulletImpact; + short rolling; + + short breakSound; + short strainSound; +}; + +struct surfacegameprops_t +{ +// game movement data + float maxSpeedFactor; // Modulates player max speed when walking on this surface + float jumpFactor; // Indicates how much higher the player should jump when on the surface +// Game-specific data + unsigned short material; + // Indicates whether or not the player is on a ladder. + unsigned char climbable; + unsigned char pad; +}; + +//----------------------------------------------------------------------------- +// Purpose: Each different material has an entry like this +//----------------------------------------------------------------------------- +struct surfacedata_t +{ + surfacephysicsparams_t physics; // physics parameters + surfaceaudioparams_t audio; // audio parameters + surfacesoundnames_t sounds; // names of linked sounds + surfacegameprops_t game; // Game data / properties + + surfacesoundhandles_t soundhandles; +}; + +#define VPHYSICS_SURFACEPROPS_INTERFACE_VERSION "VPhysicsSurfaceProps001" +abstract_class IPhysicsSurfaceProps +{ +public: + virtual ~IPhysicsSurfaceProps( void ) {} + + // parses a text file containing surface prop keys + virtual int ParseSurfaceData( const char *pFilename, const char *pTextfile ) = 0; + // current number of entries in the database + virtual int SurfacePropCount( void ) const = 0; + + virtual int GetSurfaceIndex( const char *pSurfacePropName ) const = 0; + virtual void GetPhysicsProperties( int surfaceDataIndex, float *density, float *thickness, float *friction, float *elasticity ) const = 0; + + virtual surfacedata_t *GetSurfaceData( int surfaceDataIndex ) = 0; + virtual const char *GetString( unsigned short stringTableIndex ) const = 0; + + + virtual const char *GetPropName( int surfaceDataIndex ) const = 0; + + // sets the global index table for world materials + // UNDONE: Make this per-CPhysCollide + virtual void SetWorldMaterialIndexTable( int *pMapArray, int mapSize ) = 0; + + // NOTE: Same as GetPhysicsProperties, but maybe more convenient + virtual void GetPhysicsParameters( int surfaceDataIndex, surfacephysicsparams_t *pParamsOut ) const = 0; +}; + +abstract_class IPhysicsFluidController +{ +public: + virtual ~IPhysicsFluidController( void ) {} + + virtual void SetGameData( void *pGameData ) = 0; + virtual void *GetGameData( void ) const = 0; + + virtual void GetSurfacePlane( Vector *pNormal, float *pDist ) const = 0; + virtual float GetDensity() const = 0; + virtual void WakeAllSleepingObjects() = 0; + virtual int GetContents() const = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: parameter block for creating fluid dynamic motion +// UNDONE: Expose additional fluid model paramters? +//----------------------------------------------------------------------------- +struct fluidparams_t +{ + Vector4D surfacePlane; // x,y,z normal, dist (plane constant) fluid surface + Vector currentVelocity; // velocity of the current in inches/second + float damping; // damping factor for buoyancy (tweak) + float torqueFactor; + float viscosityFactor; + void *pGameData; + bool useAerodynamics;// true if this controller should calculate surface pressure + int contents; + + fluidparams_t() {} + fluidparams_t( fluidparams_t const& src ) + { + Vector4DCopy( src.surfacePlane, surfacePlane ); + VectorCopy( src.currentVelocity, currentVelocity ); + damping = src.damping; + torqueFactor = src.torqueFactor; + viscosityFactor = src.viscosityFactor; + contents = src.contents; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: parameter block for creating linear springs +// UNDONE: Expose additional spring model paramters? +//----------------------------------------------------------------------------- +struct springparams_t +{ + springparams_t() + { + memset( this, 0, sizeof(*this) ); + } + float constant; // spring constant + float naturalLength;// relaxed length + float damping; // damping factor + float relativeDamping; // relative damping (damping proportional to the change in the relative position of the objects) + Vector startPosition; + Vector endPosition; + bool useLocalPositions; // start & end Position are in local space to start and end objects if this is true + bool onlyStretch; // only apply forces when the length is greater than the natural length +}; + +//----------------------------------------------------------------------------- +// Purpose: parameter block for creating polygonal objects +//----------------------------------------------------------------------------- +struct objectparams_t +{ + Vector *massCenterOverride; + float mass; + float inertia; + float damping; + float rotdamping; + float rotInertiaLimit; + const char *pName; // used only for debugging + void *pGameData; + float volume; + float dragCoefficient; + bool enableCollisions; +}; + +struct convertconvexparams_t +{ + bool buildOuterConvexHull; + bool buildDragAxisAreas; + bool buildOptimizedTraceTables; + float dragAreaEpsilon; + CPhysConvex *pForcedOuterHull; + + void Defaults() + { + dragAreaEpsilon = 0.25f; // 0.5in x 0.5in square + buildOuterConvexHull = false; + buildDragAxisAreas = false; + buildOptimizedTraceTables = false; + pForcedOuterHull = NULL; + } +}; + +//----------------------------------------------------------------------------- +// Physics interface IDs +// +// Note that right now the order of the enum also defines the order of save/load + + +//----------------------------------------------------------------------------- +// Purpose: parameter blocks for save and load operations +//----------------------------------------------------------------------------- +struct physsaveparams_t +{ + ISave *pSave; + void *pObject; + PhysInterfaceId_t type; +}; + +struct physrestoreparams_t +{ + IRestore *pRestore; + void **ppObject; + PhysInterfaceId_t type; + void *pGameData; + const char *pName; // used only for debugging + const CPhysCollide *pCollisionModel; + IPhysicsEnvironment *pEnvironment; + IPhysicsGameTrace *pGameTrace; +}; + +struct physrecreateparams_t +{ + void *pOldObject; + void *pNewObject; +}; + +struct physprerestoreparams_t +{ + int recreatedObjectCount; + physrecreateparams_t recreatedObjectList[1]; +}; + +//------------------------------------- + +#define DEFINE_PIID( type, enumval ) \ + template <> inline PhysInterfaceId_t GetPhysIID( type ** ) { return enumval; } + +template inline PhysInterfaceId_t GetPhysIID(PHYSPTR **); // will get link error if no match + +DEFINE_PIID( IPhysicsObject, PIID_IPHYSICSOBJECT ); +DEFINE_PIID( IPhysicsFluidController, PIID_IPHYSICSFLUIDCONTROLLER ); +DEFINE_PIID( IPhysicsSpring, PIID_IPHYSICSSPRING ); +DEFINE_PIID( IPhysicsConstraintGroup, PIID_IPHYSICSCONSTRAINTGROUP ); +DEFINE_PIID( IPhysicsConstraint, PIID_IPHYSICSCONSTRAINT ); +DEFINE_PIID( IPhysicsShadowController, PIID_IPHYSICSSHADOWCONTROLLER ); +DEFINE_PIID( IPhysicsPlayerController, PIID_IPHYSICSPLAYERCONTROLLER ); +DEFINE_PIID( IPhysicsMotionController, PIID_IPHYSICSMOTIONCONTROLLER ); +DEFINE_PIID( IPhysicsVehicleController, PIID_IPHYSICSVEHICLECONTROLLER ); +DEFINE_PIID( IPhysicsGameTrace, PIID_IPHYSICSGAMETRACE ); + +//----------------------------------------------------------------------------- + +#endif // VPHYSICS_INTERFACE_H diff --git a/public/vphysics_interfaceV30.h b/public/vphysics_interfaceV30.h new file mode 100644 index 0000000..a431aeb --- /dev/null +++ b/public/vphysics_interfaceV30.h @@ -0,0 +1,1064 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Public interfaces to vphysics DLL +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VPHYSICS_INTERFACE_V30_H +#define VPHYSICS_INTERFACE_V30_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "vcollide.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IPhysicsObjectPairHash; +class IPhysicsConstraint; +class IPhysicsConstraintGroup; +class IPhysicsFluidController; +class IPhysicsSpring; +class IPhysicsVehicleController; +class IPhysicsCollisionSet; +class IPhysicsPlayerController; +class IPhysicsFrictionSnapshot; +struct Ray_t; +struct constraint_ragdollparams_t; +struct constraint_hingeparams_t; +struct constraint_fixedparams_t; +struct constraint_ballsocketparams_t; +struct constraint_slidingparams_t; +struct constraint_pulleyparams_t; +struct constraint_lengthparams_t; +struct constraint_groupparams_t; +struct vehicleparams_t; +struct matrix3x4_t; +struct fluidparams_t; +struct springparams_t; +struct objectparams_t; +struct debugcollide_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct physics_stats_t; +struct physics_performanceparams_t; +struct physsaveparams_t; +struct physrestoreparams_t; +struct physprerestoreparams_t; + +namespace VPhysicsInterfaceV30 +{ + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IPhysicsObject; +class IPhysicsEnvironment; +class IPhysicsSurfaceProps; +class IConvexInfo; + +enum PhysInterfaceId_t +{ + PIID_UNKNOWN, + PIID_IPHYSICSOBJECT, + PIID_IPHYSICSFLUIDCONTROLLER, + PIID_IPHYSICSSPRING, + PIID_IPHYSICSCONSTRAINTGROUP, + PIID_IPHYSICSCONSTRAINT, + PIID_IPHYSICSSHADOWCONTROLLER, + PIID_IPHYSICSPLAYERCONTROLLER, + PIID_IPHYSICSMOTIONCONTROLLER, + PIID_IPHYSICSVEHICLECONTROLLER, + PIID_IPHYSICSGAMETRACE, + + PIID_NUM_TYPES +}; + + +class ISave; +class IRestore; + + +#define VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION_1 "VPhysicsDebugOverlay001" + +abstract_class IVPhysicsDebugOverlay +{ +public: + virtual void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, int r, int g, int b, int a, float duration) = 0; + virtual void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector& p3, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b,bool noDepthTest, float duration) = 0; + virtual void AddTextOverlay(const Vector& origin, float duration, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddTextOverlay(const Vector& origin, int line_offset, float duration, PRINTF_FORMAT_STRING const char *format, ...) = 0; + virtual void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char *text) = 0; + virtual void AddSweptBoxOverlay(const Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle & angles, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, PRINTF_FORMAT_STRING const char *format, ...) = 0; +}; + +#define VPHYSICS_INTERFACE_VERSION_30 "VPhysics030" + +abstract_class IPhysics +{ +public: + virtual IPhysicsEnvironment *CreateEnvironment( void ) = 0; + virtual void DestroyEnvironment( IPhysicsEnvironment * ) = 0; + virtual IPhysicsEnvironment *GetActiveEnvironmentByIndex( int index ) = 0; + + // Creates a fast hash of pairs of objects + // Useful for maintaining a table of object relationships like pairs that do not collide. + virtual IPhysicsObjectPairHash *CreateObjectPairHash() = 0; + virtual void DestroyObjectPairHash( IPhysicsObjectPairHash *pHash ) = 0; + + // holds a cache of these by id. So you can get by id to search for the previously created set + // UNDONE: Sets are currently limited to 32 elements. More elements will return NULL in create. + // NOTE: id is not allowed to be zero. + virtual IPhysicsCollisionSet *FindOrCreateCollisionSet( unsigned int id, int maxElementCount ) = 0; + virtual IPhysicsCollisionSet *FindCollisionSet( unsigned int id ) = 0; + virtual void DestroyAllCollisionSets() = 0; +}; + + +// CPhysConvex is a single convex solid +class CPhysConvex; +// CPhysPolysoup is an abstract triangle soup mesh +class CPhysPolysoup; +class ICollisionQuery; +class IVPhysicsKeyParser; +struct convertconvexparams_t; + +// UNDONE: Find a better place for this? Should be in collisionutils, but it's needs VPHYSICS' solver. +struct truncatedcone_t +{ + Vector origin; + Vector normal; + float h; // height of the cone (hl units) + float theta; // cone angle (degrees) +}; + + +#define VPHYSICS_COLLISION_INTERFACE_VERSION_7 "VPhysicsCollision007" + +abstract_class IPhysicsCollision +{ +public: + virtual ~IPhysicsCollision( void ) {} + + // produce a convex element from verts (convex hull around verts) + virtual CPhysConvex *ConvexFromVerts( Vector **pVerts, int vertCount ) = 0; + // produce a convex element from planes (csg of planes) + virtual CPhysConvex *ConvexFromPlanes( float *pPlanes, int planeCount, float mergeDistance ) = 0; + // calculate volume of a convex element + virtual float ConvexVolume( CPhysConvex *pConvex ) = 0; + + // Convert an array of convex elements to a compiled collision model (this deletes the convex elements) + virtual CPhysCollide *ConvertConvexToCollide( CPhysConvex **pConvex, int convexCount ) = 0; + + virtual float ConvexSurfaceArea( CPhysConvex *pConvex ) = 0; + // store game-specific data in a convex solid + virtual void SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData ) = 0; + // If not converted, free the convex elements with this call + virtual void ConvexFree( CPhysConvex *pConvex ) = 0; + + // concave objects + // create a triangle soup + virtual CPhysPolysoup *PolysoupCreate( void ) = 0; + // destroy the container and memory + virtual void PolysoupDestroy( CPhysPolysoup *pSoup ) = 0; + // add a triangle to the soup + virtual void PolysoupAddTriangle( CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits ) = 0; + // convert the convex into a compiled collision model + virtual CPhysCollide *ConvertPolysoupToCollide( CPhysPolysoup *pSoup, bool useMOPP ) = 0; + + // Get the memory size in bytes of the collision model for serialization + virtual int CollideSize( CPhysCollide *pCollide ) = 0; + // serialize the collide to a block of memory + virtual int CollideWrite( char *pDest, CPhysCollide *pCollide ) = 0; + + // Free a collide that was created with ConvertConvexToCollide() + // UNDONE: Move this up near the other Collide routines when the version is changed + virtual void DestroyCollide( CPhysCollide *pCollide ) = 0; + // compute the volume of a collide + virtual float CollideVolume( CPhysCollide *pCollide ) = 0; + // compute surface area for tools + virtual float CollideSurfaceArea( CPhysCollide *pCollide ) = 0; + + // Get the support map for a collide in the given direction + virtual Vector CollideGetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction ) = 0; + + // Get an AABB for an oriented collision model + virtual void CollideGetAABB( Vector &mins, Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles ) = 0; + + // Convert a bbox to a collide + virtual CPhysCollide *BBoxToCollide( const Vector &mins, const Vector &maxs ) = 0; + + + // Trace an AABB against a collide + virtual void TraceBox( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + virtual void TraceBox( const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + + // Trace one collide against another + virtual void TraceCollide( const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + + // loads a set of solids into a vcollide_t + virtual void VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size ) = 0; + // destroyts the set of solids created by VCollideLoad + virtual void VCollideUnload( vcollide_t *pVCollide ) = 0; + + // begins parsing a vcollide. NOTE: This keeps pointers to the text + // If you free the text and call members of IVPhysicsKeyParser, it will crash + virtual IVPhysicsKeyParser *VPhysicsKeyParserCreate( const char *pKeyData ) = 0; + // Free the parser created by VPhysicsKeyParserCreate + virtual void VPhysicsKeyParserDestroy( IVPhysicsKeyParser *pParser ) = 0; + + // creates a list of verts from a collision mesh + virtual int CreateDebugMesh( CPhysCollide const *pCollisionModel, Vector **outVerts ) = 0; + // destroy the list of verts created by CreateDebugMesh + virtual void DestroyDebugMesh( int vertCount, Vector *outVerts ) = 0; + + // create a queryable version of the collision model + virtual ICollisionQuery *CreateQueryModel( CPhysCollide *pCollide ) = 0; + // destroy the queryable version + virtual void DestroyQueryModel( ICollisionQuery *pQuery ) = 0; + + virtual IPhysicsCollision *ThreadContextCreate( void ) = 0; + virtual void ThreadContextDestroy( IPhysicsCollision *pThreadContex ) = 0; + + virtual unsigned int ReadStat( int statID ) = 0; + + // UNDONE: Move this up when changing the interface version + virtual void TraceBox( const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) = 0; + virtual void CollideGetMassCenter( CPhysCollide *pCollide, Vector *pOutMassCenter ) = 0; + virtual void CollideSetMassCenter( CPhysCollide *pCollide, const Vector &massCenter ) = 0; + + // query the collide index in the physics model for the instance + virtual int CollideIndex( const CPhysCollide *pCollide ) = 0; + + virtual CPhysCollide *ConvertConvexToCollideParams( CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams ) = 0; + virtual CPhysConvex *BBoxToConvex( const Vector &mins, const Vector &maxs ) = 0; + + // get the approximate cross-sectional area projected orthographically on the bbox of the collide + // NOTE: These are fractional areas - unitless. Basically this is the fraction of the OBB on each axis that + // would be visible if the object were rendered orthographically. + // NOTE: This has been precomputed when the collide was built or this function will return 1,1,1 + virtual Vector CollideGetOrthographicAreas( const CPhysCollide *pCollide ) = 0; + + // dumps info about the collide to Msg() + virtual void OutputDebugInfo( const CPhysCollide *pCollide ) = 0; + + // relatively slow test for box vs. truncated cone + virtual bool IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone ) = 0; +}; + +// this can be used to post-process a collision model +abstract_class ICollisionQuery +{ +public: + virtual ~ICollisionQuery() {} + // number of convex pieces in the whole solid + virtual int ConvexCount( void ) = 0; + // triangle count for this convex piece + virtual int TriangleCount( int convexIndex ) = 0; + // get the stored game data + virtual unsigned int GetGameData( int convexIndex ) = 0; + // Gets the triangle's verts to an array + virtual void GetTriangleVerts( int convexIndex, int triangleIndex, Vector *verts ) = 0; + + // UNDONE: This doesn't work!!! + virtual void SetTriangleVerts( int convexIndex, int triangleIndex, const Vector *verts ) = 0; + + // returns the 7-bit material index + virtual int GetTriangleMaterialIndex( int convexIndex, int triangleIndex ) = 0; + // sets a 7-bit material index for this triangle + virtual void SetTriangleMaterialIndex( int convexIndex, int triangleIndex, int index7bits ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Ray traces from game engine. +//----------------------------------------------------------------------------- +abstract_class IPhysicsGameTrace +{ +public: + virtual void VehicleTraceRay( const Ray_t &ray, void *pVehicle, trace_t *pTrace ) = 0; + virtual void VehicleTraceRayWithWater( const Ray_t &ray, void *pVehicle, trace_t *pTrace ) = 0; + virtual bool VehiclePointInWater( const Vector &vecPoint ) = 0; +}; + +// The caller should implement this to return contents masks per convex on a collide +abstract_class IConvexInfo +{ +public: + virtual unsigned int GetContents( int convexGameData ) = 0; +}; + +class CPhysicsEventHandler; +abstract_class IPhysicsCollisionData +{ +public: + virtual void GetSurfaceNormal( Vector &out ) = 0; // normal points toward second object (object index 1) + virtual void GetContactPoint( Vector &out ) = 0; // contact point of collision (in world space) + virtual void GetContactSpeed( Vector &out ) = 0; // speed of surface 1 relative to surface 0 (in world space) +}; + + +struct vcollisionevent_t +{ + IPhysicsObject *pObjects[2]; + int surfaceProps[2]; + bool isCollision; + bool isShadowCollision; + float deltaCollisionTime; + + float collisionSpeed; // only valid at postCollision + IPhysicsCollisionData *pInternalData; // may change pre/post collision +}; + +abstract_class IPhysicsCollisionEvent +{ +public: + // returns the two objects that collided, time between last collision of these objects + // and an opaque data block of collision information + // NOTE: PreCollision/PostCollision ALWAYS come in matched pairs!!! + virtual void PreCollision( vcollisionevent_t *pEvent ) = 0; + virtual void PostCollision( vcollisionevent_t *pEvent ) = 0; + + // This is a scrape event. The object has scraped across another object consuming the indicated energy + virtual void Friction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit, IPhysicsCollisionData *pData ) = 0; + + virtual void StartTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ) = 0; + virtual void EndTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ) = 0; + + virtual void FluidStartTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ) = 0; + virtual void FluidEndTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ) = 0; + + virtual void PostSimulationFrame() = 0; + + virtual void ObjectEnterTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ) {} + virtual void ObjectLeaveTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ) {} +}; + + +abstract_class IPhysicsObjectEvent +{ +public: + // these can be used to optimize out queries on sleeping objects + // Called when an object is woken after sleeping + virtual void ObjectWake( IPhysicsObject *pObject ) = 0; + // called when an object goes to sleep (no longer simulating) + virtual void ObjectSleep( IPhysicsObject *pObject ) = 0; +}; + +class IPhysicsConstraintEvent +{ +public: + // the constraint is now inactive, the game code is required to delete it or re-activate it. + virtual void ConstraintBroken( IPhysicsConstraint * ) = 0; +}; + +struct hlshadowcontrol_params_t +{ + Vector targetPosition; + QAngle targetRotation; + float maxAngular; + float maxDampAngular; + float maxSpeed; + float maxDampSpeed; + float dampFactor; + float teleportDistance; +}; + +// UNDONE: At some point allow this to be parameterized using hlshadowcontrol_params_t. +// All of the infrastructure is in place to do that. +abstract_class IPhysicsShadowController +{ +public: + virtual ~IPhysicsShadowController( void ) {} + + virtual void Update( const Vector &position, const QAngle &angles, float timeOffset ) = 0; + virtual void MaxSpeed( float maxSpeed, float maxAngularSpeed ) = 0; + virtual void StepUp( float height ) = 0; + + // If the teleport distance is non-zero, the object will be teleported to + // the target location when the error exceeds this quantity. + virtual void SetTeleportDistance( float teleportDistance ) = 0; + virtual bool AllowsTranslation() = 0; + virtual bool AllowsRotation() = 0; + + // There are two classes of shadow objects: + // 1) Game physics controlled, shadow follows game physics (this is the default) + // 2) Physically controlled - shadow position is a target, but the game hasn't guaranteed that the space can be occupied by this object + virtual void SetPhysicallyControlled( bool isPhysicallyControlled ) = 0; + virtual bool IsPhysicallyControlled() = 0; + virtual void GetLastImpulse( Vector *pOut ) = 0; + virtual void UseShadowMaterial( bool bUseShadowMaterial ) = 0; + virtual void ObjectMaterialChanged( int materialIndex ) = 0; +}; + +class CPhysicsSimObject; +class IPhysicsMotionController; + +// Callback for simulation +class IMotionEvent +{ +public: + // These constants instruct the simulator as to how to apply the values copied to linear & angular + // GLOBAL/LOCAL refer to the coordinate system of the values, whereas acceleration/force determine whether or not + // mass is divided out (forces must be divided by mass to compute acceleration) + enum simresult_e { SIM_NOTHING = 0, SIM_LOCAL_ACCELERATION, SIM_LOCAL_FORCE, SIM_GLOBAL_ACCELERATION, SIM_GLOBAL_FORCE }; + virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) = 0; +}; + + + +abstract_class IPhysicsMotionController +{ +public: + virtual ~IPhysicsMotionController( void ) {} + virtual void SetEventHandler( IMotionEvent *handler ) = 0; + virtual void AttachObject( IPhysicsObject *pObject, bool checkIfAlreadyAttached ) = 0; + virtual void DetachObject( IPhysicsObject *pObject ) = 0; + + // returns the number of objects currently attached to the controller + virtual int CountObjects( void ) = 0; + // NOTE: pObjectList is an array with at least CountObjects() allocated + virtual void GetObjects( IPhysicsObject **pObjectList ) = 0; + // detaches all attached objects + virtual void ClearObjects( void ) = 0; + + // wakes up all attached objects + virtual void WakeObjects( void ) = 0; + enum priority_t + { + LOW_PRIORITY = 0, + MEDIUM_PRIORITY = 1, + HIGH_PRIORITY = 2, + }; + virtual void SetPriority( priority_t priority ) = 0; +}; + +// ------------------- +// Collision filter function. Return 0 if objects should not be tested for collisions, nonzero otherwise +// Install with IPhysicsEnvironment::SetCollisionFilter() +// ------------------- +abstract_class IPhysicsCollisionSolver +{ +public: + virtual int ShouldCollide( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1 ) = 0; + virtual int ShouldSolvePenetration( IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1, float dt ) = 0; + + // pObject has already done the max number of collisions this tick, should we freeze it to save CPU? + virtual bool ShouldFreezeObject( IPhysicsObject *pObject ) = 0; + + // The system has already done too many collision checks, performance will suffer. + // How many more should it do? + virtual int AdditionalCollisionChecksThisTick( int currentChecksDone ) = 0; +}; + +enum PhysicsTraceType_t +{ + VPHYSICS_TRACE_EVERYTHING = 0, + VPHYSICS_TRACE_STATIC_ONLY, + VPHYSICS_TRACE_MOVING_ONLY, + VPHYSICS_TRACE_TRIGGERS_ONLY, + VPHYSICS_TRACE_STATIC_AND_MOVING, +}; + +abstract_class IPhysicsTraceFilter +{ +public: + virtual bool ShouldHitObject( IPhysicsObject *pObject, int contentsMask ) = 0; + virtual PhysicsTraceType_t GetTraceType() const = 0; +}; + +abstract_class IPhysicsEnvironment +{ +public: + virtual ~IPhysicsEnvironment( void ) {} + + virtual void SetDebugOverlay( CreateInterfaceFn debugOverlayFactory ) = 0; + virtual IVPhysicsDebugOverlay *GetDebugOverlay( void ) = 0; + + // gravity is a 3-vector in in/s^2 + virtual void SetGravity( const Vector &gravityVector ) = 0; + virtual void GetGravity( Vector &gravityVector ) = 0; + + // air density is in kg / m^3 (water is 1000) + // This controls drag, air that is more dense has more drag. + virtual void SetAirDensity( float density ) = 0; + virtual float GetAirDensity( void ) = 0; + + // object creation + // create a polygonal object. pCollisionModel was created by the physics builder DLL in a pre-process. + virtual IPhysicsObject *CreatePolyObject( const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams ) = 0; + // same as above, but this one cannot move or rotate (infinite mass/inertia) + virtual IPhysicsObject *CreatePolyObjectStatic( const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams ) = 0; + // Create a perfectly spherical object + virtual IPhysicsObject *CreateSphereObject( float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic ) = 0; + // Create a polygonal fluid body out of the specified collision model + // This object will affect any other objects that collide with the collision model + virtual IPhysicsFluidController *CreateFluidController( IPhysicsObject *pFluidObject, fluidparams_t *pParams ) = 0; + + // Create a simulated spring that connects 2 objects + virtual IPhysicsSpring *CreateSpring( IPhysicsObject *pObjectStart, IPhysicsObject *pObjectEnd, springparams_t *pParams ) = 0; + + // Create a constraint in the space of pReferenceObject which is attached by the constraint to pAttachedObject + virtual IPhysicsConstraint *CreateRagdollConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll ) = 0; + virtual IPhysicsConstraint *CreateHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_hingeparams_t &hinge ) = 0; + virtual IPhysicsConstraint *CreateFixedConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed ) = 0; + virtual IPhysicsConstraint *CreateSlidingConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &sliding ) = 0; + virtual IPhysicsConstraint *CreateBallsocketConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket ) = 0; + virtual IPhysicsConstraint *CreatePulleyConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley ) = 0; + virtual IPhysicsConstraint *CreateLengthConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length ) = 0; + + virtual IPhysicsConstraintGroup *CreateConstraintGroup( const constraint_groupparams_t &groupParams ) = 0; + + // destroy an object created with CreatePolyObject() or CreatePolyObjectStatic() + virtual void DestroyObject( IPhysicsObject * ) = 0; + virtual void DestroySpring( IPhysicsSpring * ) = 0; + // Destroy an object created with CreateFluidController() + virtual void DestroyFluidController( IPhysicsFluidController * ) = 0; + virtual void DestroyConstraint( IPhysicsConstraint * ) = 0; + virtual void DestroyConstraintGroup( IPhysicsConstraintGroup *pGroup ) = 0; + + // install a function to filter collisions/penentration + virtual void SetCollisionSolver( IPhysicsCollisionSolver *pSolver ) = 0; + + // run the simulator for deltaTime seconds + virtual void Simulate( float deltaTime ) = 0; + // true if currently running the simulator (i.e. in a callback during physenv->Simulate()) + virtual bool IsInSimulation( void ) const = 0; + + // Manage the timestep (period) of the simulator. The main functions are all integrated with + // this period as dt. + virtual float GetSimulationTimestep( void ) = 0; + virtual void SetSimulationTimestep( float timestep ) = 0; + + // returns the current simulation clock's value. This is an absolute time. + virtual float GetSimulationTime( void ) = 0; + virtual void ResetSimulationClock( void ) = 0; + + // Collision callbacks (game code collision response) + virtual void SetCollisionEventHandler( IPhysicsCollisionEvent *pCollisionEvents ) = 0; + virtual void SetObjectEventHandler( IPhysicsObjectEvent *pObjectEvents ) = 0; + virtual void SetConstraintEventHandler( IPhysicsConstraintEvent *pConstraintEvents ) = 0; + + virtual IPhysicsShadowController *CreateShadowController( IPhysicsObject *pObject, bool allowTranslation, bool allowRotation ) = 0; + virtual void DestroyShadowController( IPhysicsShadowController * ) = 0; + + virtual IPhysicsPlayerController *CreatePlayerController( IPhysicsObject *pObject ) = 0; + virtual void DestroyPlayerController( IPhysicsPlayerController * ) = 0; + + virtual IPhysicsMotionController *CreateMotionController( IMotionEvent *pHandler ) = 0; + virtual void DestroyMotionController( IPhysicsMotionController *pController ) = 0; + + virtual IPhysicsVehicleController *CreateVehicleController( IPhysicsObject *pVehicleBodyObject, const vehicleparams_t ¶ms, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace ) = 0; + virtual void DestroyVehicleController( IPhysicsVehicleController * ) = 0; + + virtual void SetQuickDelete( bool bQuick ) = 0; + + virtual int GetActiveObjectCount( void ) = 0; + virtual void GetActiveObjects( IPhysicsObject **pOutputObjectList ) = 0; + + virtual void CleanupDeleteList( void ) = 0; + virtual void EnableDeleteQueue( bool enable ) = 0; + + // Save/Restore methods + virtual bool Save( const physsaveparams_t ¶ms ) = 0; + virtual void PreRestore( const physprerestoreparams_t ¶ms ) = 0; + virtual bool Restore( const physrestoreparams_t ¶ms ) = 0; + virtual void PostRestore() = 0; + + // Debugging: + virtual bool IsCollisionModelUsed( CPhysCollide *pCollide ) = 0; + + // Physics world version of the enginetrace API: + virtual void TraceRay( const Ray_t &ray, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + virtual void SweepCollideable( const CPhysCollide *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd, + const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace ) = 0; + + // performance tuning + virtual void GetPerformanceSettings( physics_performanceparams_t *pOutput ) = 0; + virtual void SetPerformanceSettings( const physics_performanceparams_t *pSettings ) = 0; + + // perf/cost statistics + virtual void ReadStats( physics_stats_t *pOutput ) = 0; + virtual void ClearStats() = 0; +}; + +enum callbackflags +{ + CALLBACK_GLOBAL_COLLISION = 0x0001, + CALLBACK_GLOBAL_FRICTION = 0x0002, + CALLBACK_GLOBAL_TOUCH = 0x0004, + CALLBACK_GLOBAL_TOUCH_STATIC = 0x0008, + CALLBACK_SHADOW_COLLISION = 0x0010, + CALLBACK_GLOBAL_COLLIDE_STATIC = 0x0020, + CALLBACK_IS_VEHICLE_WHEEL = 0x0040, + CALLBACK_FLUID_TOUCH = 0x0100, + CALLBACK_NEVER_DELETED = 0x0200, // HACKHACK: This means this object will never be deleted (set on the world) + CALLBACK_MARKED_FOR_DELETE = 0x0400, // This allows vphysics to skip some work for this object since it will be + // deleted later this frame. (Set automatically by destroy calls) + CALLBACK_ENABLING_COLLISION = 0x0800, // This is active during the time an object is enabling collisions + // allows us to skip collisions between "new" objects and objects marked for delete + CALLBACK_DO_FLUID_SIMULATION = 0x1000, // remove this to opt out of fluid simulations + CALLBACK_IS_PLAYER_CONTROLLER= 0x2000, // HACKHACK: Set this on players until player cotrollers are unified with shadow controllers + CALLBACK_CHECK_COLLISION_DISABLE = 0x4000, + CALLBACK_MARKED_FOR_TEST = 0x8000, // debug -- marked object is being debugged +}; + +abstract_class IPhysicsObject +{ +public: + virtual ~IPhysicsObject( void ) {} + + // returns true if this object is static/unmoveable + // NOTE: returns false for objects that are not created static, but set EnableMotion(false); + // Call IsMoveable() to find if the object is static OR has motion disabled + virtual bool IsStatic( void ) = 0; + + // "wakes up" an object + // NOTE: ALL OBJECTS ARE "Asleep" WHEN CREATED + virtual void Wake( void ) = 0; + virtual void Sleep( void ) = 0; + virtual bool IsAsleep( void ) = 0; + + // Game can store data in each object (link back to game object) + virtual void SetGameData( void *pGameData ) = 0; + virtual void *GetGameData( void ) const = 0; + // This flags word can be defined by the game as well + virtual void SetGameFlags( unsigned short userFlags ) = 0; + virtual unsigned short GetGameFlags( void ) const = 0; + virtual void SetGameIndex( unsigned short gameIndex ) = 0; + virtual unsigned short GetGameIndex( void ) const = 0; + + // setup various callbacks for this object + virtual void SetCallbackFlags( unsigned short callbackflags ) = 0; + // get the current callback state for this object + virtual unsigned short GetCallbackFlags( void ) = 0; + + // mass accessors + virtual void SetMass( float mass ) = 0; + virtual float GetMass( void ) const = 0; + // get 1/mass (it's cached) + virtual float GetInvMass( void ) const = 0; + virtual Vector GetInertia( void ) const = 0; + virtual Vector GetInvInertia( void ) const = 0; + virtual void SetInertia( const Vector &inertia ) = 0; + + virtual void SetDamping( const float *speed, const float *rot ) = 0; + virtual void GetDamping( float *speed, float *rot ) = 0; + + // material index + virtual int GetMaterialIndex() const = 0; + virtual void SetMaterialIndex( int materialIndex ) = 0; + + // Enable / disable collisions for this object + virtual void EnableCollisions( bool enable ) = 0; + // Enable / disable gravity for this object + virtual void EnableGravity( bool enable ) = 0; + // Enable / disable air friction / drag for this object + virtual void EnableDrag( bool enable ) = 0; + // Enable / disable motion (pin / unpin the object) + virtual void EnableMotion( bool enable ) = 0; + + // call this when the collision filter conditions change due to this + // object's state (e.g. changing solid type or collision group) + virtual void RecheckCollisionFilter() = 0; + + // NOTE: These are here for convenience, but you can do them yourself by using the matrix + // returned from GetPositionMatrix() + // convenient coordinate system transformations (params - dest, src) + virtual void LocalToWorld( Vector *worldPosition, const Vector &localPosition ) = 0; + virtual void WorldToLocal( Vector *localPosition, const Vector &worldPosition ) = 0; + + // transforms a vector (no translation) from object-local to world space + virtual void LocalToWorldVector( Vector *worldVector, const Vector &localVector ) = 0; + // transforms a vector (no translation) from world to object-local space + virtual void WorldToLocalVector( Vector *localVector, const Vector &worldVector ) = 0; + + // push on an object + // force vector is direction & magnitude of impulse kg in / s + virtual void ApplyForceCenter( const Vector &forceVector ) = 0; + virtual void ApplyForceOffset( const Vector &forceVector, const Vector &worldPosition ) = 0; + + // Calculates the force/torque on the center of mass for an offset force impulse (pass output to ApplyForceCenter / ApplyTorqueCenter) + virtual void CalculateForceOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque ) = 0; + // Calculates the linear/angular velocities on the center of mass for an offset force impulse (pass output to AddVelocity) + virtual void CalculateVelocityOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity ) = 0; + + // apply torque impulse. This will change the angular velocity on the object. + // HL Axes, kg degrees / s + virtual void ApplyTorqueCenter( const AngularImpulse &torque ) = 0; + + // NOTE: This will teleport the object + virtual void SetPosition( const Vector &worldPosition, const QAngle &angles, bool isTeleport ) = 0; + virtual void SetPositionMatrix( const matrix3x4_t&matrix, bool isTeleport ) = 0; + + virtual void GetPosition( Vector *worldPosition, QAngle *angles ) = 0; + virtual void GetPositionMatrix( matrix3x4_t *positionMatrix ) = 0; + // force the velocity to a new value + // NOTE: velocity is in worldspace, angularVelocity is relative to the object's + // local axes (just like pev->velocity, pev->avelocity) + virtual void SetVelocity( const Vector *velocity, const AngularImpulse *angularVelocity ) = 0; + + // like the above, but force the change into the simulator immediately + virtual void SetVelocityInstantaneous( const Vector *velocity, const AngularImpulse *angularVelocity ) = 0; + + // NOTE: velocity is in worldspace, angularVelocity is relative to the object's + // local axes (just like pev->velocity, pev->avelocity) + virtual void GetVelocity( Vector *velocity, AngularImpulse *angularVelocity ) = 0; + + // NOTE: These are velocities, not forces. i.e. They will have the same effect regardless of + // the object's mass or inertia + virtual void AddVelocity( const Vector *velocity, const AngularImpulse *angularVelocity ) = 0; + virtual void GetVelocityAtPoint( const Vector &worldPosition, Vector &velocity ) = 0; + + virtual float GetEnergy() = 0; + + // returns true if the object is in contact with another object + // if true, puts a point on the contact surface in contactPoint, and + // a pointer to the object in contactObject + // NOTE: You can pass NULL for either to avoid computations + // JAY: This is still an experiment + virtual bool GetContactPoint( Vector *contactPoint, IPhysicsObject **contactObject ) = 0; + + // refactor this a bit - move some of this to IPhysicsShadowController + virtual void SetShadow( float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation ) = 0; + virtual void UpdateShadow( const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset ) = 0; + + // returns number of ticks since last Update() call + virtual int GetShadowPosition( Vector *position, QAngle *angles ) = 0; + virtual IPhysicsShadowController *GetShadowController( void ) const = 0; + + + virtual const CPhysCollide *GetCollide( void ) const = 0; + virtual const char *GetName() = 0; + virtual void RemoveShadowController() = 0; + virtual bool IsMoveable() = 0; + + // applies the math of the shadow controller to this object. + // for use in your own controllers + // returns the new value of secondsToArrival with dt time elapsed + virtual float ComputeShadowControl( const hlshadowcontrol_params_t ¶ms, float secondsToArrival, float dt ) = 0; + + // coefficients are optional, pass either + virtual void SetDragCoefficient( float *pDrag, float *pAngularDrag ) = 0; + + // Get the radius if this is a sphere object (zero if this is a polygonal mesh) + virtual float GetSphereRadius() = 0; + + virtual float CalculateLinearDrag( const Vector &unitDirection ) const = 0; + virtual float CalculateAngularDrag( const Vector &objectSpaceRotationAxis ) const = 0; + virtual void SetBuoyancyRatio( float ratio ) = 0; // Override bouyancy + + virtual void BecomeTrigger() = 0; + virtual void RemoveTrigger() = 0; + virtual bool IsTrigger() = 0; + virtual bool IsFluid() = 0; // fluids are special triggers with fluid controllers attached, they return true to IsTrigger() as well! + + // sets the object to be hinged. Fixed it place, but able to rotate around one axis. + virtual void BecomeHinged( int localAxis ) = 0; + // resets the object to original state + virtual void RemoveHinged() = 0; + virtual bool IsHinged() = 0; + + virtual unsigned int GetContents() = 0; + virtual void SetContents( unsigned int contents ) = 0; + virtual Vector GetMassCenterLocalSpace() = 0; + + // used to iterate the contact points of an object + virtual IPhysicsFrictionSnapshot *CreateFrictionSnapshot() = 0; + virtual void DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot ) = 0; + + // dumps info about the object to Msg() + virtual void OutputDebugInfo() = 0; + virtual void GetImplicitVelocity( Vector *velocity, AngularImpulse *angularVelocity ) = 0; + // this is a hack to recheck current contacts + // some of them may not be valid if the object's collision rules have recently changed + // UNDONE: Force this in RecheckCollisionFilter() ? + virtual void RecheckContactPoints() = 0; +}; + + +abstract_class IPhysicsSpring +{ +public: + virtual ~IPhysicsSpring( void ) {} + virtual void GetEndpoints( Vector *worldPositionStart, Vector *worldPositionEnd ) = 0; + virtual void SetSpringConstant( float flSpringContant) = 0; + virtual void SetSpringDamping( float flSpringDamping) = 0; + virtual void SetSpringLength( float flSpringLenght) = 0; + + // Get the starting object + virtual IPhysicsObject *GetStartObject( void ) = 0; + + // Get the end object + virtual IPhysicsObject *GetEndObject( void ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: These properties are defined per-material. This is accessible at +// each triangle in a collision mesh +//----------------------------------------------------------------------------- +struct surfacephysicsparams_t +{ +// vphysics physical properties + float friction; + float elasticity; // collision elasticity - used to compute coefficient of restitution + float density; // physical density (in kg / m^3) + float thickness; // material thickness if not solid (sheet materials) in inches + float dampening; +}; + +struct surfaceaudioparams_t +{ +// sounds / audio data + float reflectivity; // like elasticity, but how much sound should be reflected by this surface + float hardnessFactor; // like elasticity, but only affects impact sound choices + float roughnessFactor; // like friction, but only affects scrape sound choices + +// audio thresholds + float roughThreshold; // surface roughness > this causes "rough" scrapes, < this causes "smooth" scrapes + float hardThreshold; // surface hardness > this causes "hard" impacts, < this causes "soft" impacts + float hardVelocityThreshold; // collision velocity > this causes "hard" impacts, < this causes "soft" impacts + // NOTE: Hard impacts must meet both hardnessFactor AND velocity thresholds +}; + +struct surfacesoundnames_t +{ + unsigned short stepleft; + unsigned short stepright; + + unsigned short impactSoft; + unsigned short impactHard; + + unsigned short scrapeSmooth; + unsigned short scrapeRough; + + unsigned short bulletImpact; + unsigned short rolling; + + unsigned short breakSound; + unsigned short strainSound; +}; + +struct surfacegameprops_t +{ +// game movement data + float maxSpeedFactor; // Modulates player max speed when walking on this surface + float jumpFactor; // Indicates how much higher the player should jump when on the surface +// Game-specific data + unsigned short material; + // Indicates whether or not the player is on a ladder. + unsigned char climbable; + unsigned char pad; +}; + +//----------------------------------------------------------------------------- +// Purpose: Each different material has an entry like this +//----------------------------------------------------------------------------- +struct surfacedata_t +{ + surfacephysicsparams_t physics; // physics parameters + surfaceaudioparams_t audio; // audio parameters + surfacesoundnames_t sounds; // names of linked sounds + surfacegameprops_t game; // Game data / properties + + +}; + +#define VPHYSICS_SURFACEPROPS_INTERFACE_VERSION_1 "VPhysicsSurfaceProps001" +abstract_class IPhysicsSurfaceProps +{ +public: + virtual ~IPhysicsSurfaceProps( void ) {} + + // parses a text file containing surface prop keys + virtual int ParseSurfaceData( const char *pFilename, const char *pTextfile ) = 0; + // current number of entries in the database + virtual int SurfacePropCount( void ) = 0; + + virtual int GetSurfaceIndex( const char *pSurfacePropName ) = 0; + virtual void GetPhysicsProperties( int surfaceDataIndex, float *density, float *thickness, float *friction, float *elasticity ) = 0; + + virtual surfacedata_t *GetSurfaceData( int surfaceDataIndex ) = 0; + virtual const char *GetString( unsigned short stringTableIndex ) = 0; + + + virtual const char *GetPropName( int surfaceDataIndex ) = 0; + + // sets the global index table for world materials + virtual void SetWorldMaterialIndexTable( int *pMapArray, int mapSize ) = 0; + + // NOTE: Same as GetPhysicsProperties, but maybe more convenient + virtual void GetPhysicsParameters( int surfaceDataIndex, surfacephysicsparams_t *pParamsOut ) = 0; +}; + +abstract_class IPhysicsFluidController +{ +public: + virtual ~IPhysicsFluidController( void ) {} + + virtual void SetGameData( void *pGameData ) = 0; + virtual void *GetGameData( void ) const = 0; + + virtual void GetSurfacePlane( Vector *pNormal, float *pDist ) = 0; + virtual float GetDensity() = 0; + virtual void WakeAllSleepingObjects() = 0; + virtual int GetContents() const = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: parameter block for creating fluid dynamic motion +// UNDONE: Expose additional fluid model paramters? +//----------------------------------------------------------------------------- +struct fluidparams_t +{ + Vector4D surfacePlane; // x,y,z normal, dist (plane constant) fluid surface + Vector currentVelocity; // velocity of the current in inches/second + float damping; // damping factor for buoyancy (tweak) + float torqueFactor; + float viscosityFactor; + void *pGameData; + bool useAerodynamics;// true if this controller should calculate surface pressure + int contents; + + fluidparams_t() {} + fluidparams_t( fluidparams_t const& src ) + { + Vector4DCopy( src.surfacePlane, surfacePlane ); + VectorCopy( src.currentVelocity, currentVelocity ); + damping = src.damping; + torqueFactor = src.torqueFactor; + viscosityFactor = src.viscosityFactor; + contents = src.contents; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: parameter block for creating linear springs +// UNDONE: Expose additional spring model paramters? +//----------------------------------------------------------------------------- +struct springparams_t +{ + springparams_t() + { + memset( this, 0, sizeof(*this) ); + } + float constant; // spring constant + float naturalLength;// relaxed length + float damping; // damping factor + float relativeDamping; // relative damping (damping proportional to the change in the relative position of the objects) + Vector startPosition; + Vector endPosition; + bool useLocalPositions; // start & end Position are in local space to start and end objects if this is true + bool onlyStretch; // only apply forces when the length is greater than the natural length +}; + +//----------------------------------------------------------------------------- +// Purpose: parameter block for creating polygonal objects +//----------------------------------------------------------------------------- +struct objectparams_t +{ + Vector *massCenterOverride; + float mass; + float inertia; + float damping; + float rotdamping; + float rotInertiaLimit; + const char *pName; // used only for debugging + void *pGameData; + float volume; + float dragCoefficient; + bool enableCollisions; +}; + +struct convertconvexparams_t +{ + bool buildOuterConvexHull; + bool buildDragAxisAreas; + bool buildOptimizedTraceTables; + float dragAreaEpsilon; + CPhysConvex *pForcedOuterHull; + + void Defaults() + { + dragAreaEpsilon = 0.25f; // 0.5in x 0.5in square + buildOuterConvexHull = false; + buildDragAxisAreas = false; + buildOptimizedTraceTables = false; + pForcedOuterHull = NULL; + } +}; + +//----------------------------------------------------------------------------- +// Physics interface IDs +// +// Note that right now the order of the enum also defines the order of save/load + + +//----------------------------------------------------------------------------- +// Purpose: parameter blocks for save and load operations +//----------------------------------------------------------------------------- +struct physsaveparams_t +{ + ISave *pSave; + void *pObject; + PhysInterfaceId_t type; +}; + +struct physrestoreparams_t +{ + IRestore *pRestore; + void **ppObject; + PhysInterfaceId_t type; + void *pGameData; + const char *pName; // used only for debugging + const CPhysCollide *pCollisionModel; + IPhysicsEnvironment *pEnvironment; + IPhysicsGameTrace *pGameTrace; +}; + +struct physrecreateparams_t +{ + void *pOldObject; + void *pNewObject; +}; + +struct physprerestoreparams_t +{ + int recreatedObjectCount; + physrecreateparams_t recreatedObjectList[1]; +}; + + +//------------------------------------- + +#define DEFINE_PIID( type, enumval ) \ + template <> inline PhysInterfaceId_t GetPhysIID( type ** ) { return enumval; } + +template inline PhysInterfaceId_t GetPhysIID(PHYSPTR **); // will get link error if no match + +DEFINE_PIID( IPhysicsObject, PIID_IPHYSICSOBJECT ); +DEFINE_PIID( IPhysicsFluidController, PIID_IPHYSICSFLUIDCONTROLLER ); +DEFINE_PIID( IPhysicsSpring, PIID_IPHYSICSSPRING ); +DEFINE_PIID( IPhysicsConstraintGroup, PIID_IPHYSICSCONSTRAINTGROUP ); +DEFINE_PIID( IPhysicsConstraint, PIID_IPHYSICSCONSTRAINT ); +DEFINE_PIID( IPhysicsShadowController, PIID_IPHYSICSSHADOWCONTROLLER ); +DEFINE_PIID( IPhysicsPlayerController, PIID_IPHYSICSPLAYERCONTROLLER ); +DEFINE_PIID( IPhysicsMotionController, PIID_IPHYSICSMOTIONCONTROLLER ); +DEFINE_PIID( IPhysicsVehicleController, PIID_IPHYSICSVEHICLECONTROLLER ); +DEFINE_PIID( IPhysicsGameTrace, PIID_IPHYSICSGAMETRACE ); + +//----------------------------------------------------------------------------- + +} // end namespace VPhysicsInterfaceV30 + +#endif // VPHYSICS_INTERFACE_V30_H diff --git a/public/vstdlib/IKeyValuesSystem.h b/public/vstdlib/IKeyValuesSystem.h new file mode 100644 index 0000000..e999dd8 --- /dev/null +++ b/public/vstdlib/IKeyValuesSystem.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef VSTDLIB_IKEYVALUESSYSTEM_H +#define VSTDLIB_IKEYVALUESSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vstdlib/vstdlib.h" + +// handle to a KeyValues key name symbol +typedef int HKeySymbol; +#define INVALID_KEY_SYMBOL (-1) + +class IBaseFileSystem; +class KeyValues; + +//----------------------------------------------------------------------------- +// Purpose: Interface to shared data repository for KeyValues (included in vgui_controls.lib) +// allows for central data storage point of KeyValues symbol table +//----------------------------------------------------------------------------- +class IKeyValuesSystem +{ +public: + // registers the size of the KeyValues in the specified instance + // so it can build a properly sized memory pool for the KeyValues objects + // the sizes will usually never differ but this is for versioning safety + virtual void RegisterSizeofKeyValues(int size) = 0; + + // allocates/frees a KeyValues object from the shared mempool + virtual void *AllocKeyValuesMemory(int size) = 0; + virtual void FreeKeyValuesMemory(void *pMem) = 0; + + // symbol table access (used for key names) + virtual HKeySymbol GetSymbolForString( const char *name, bool bCreate = true ) = 0; + virtual const char *GetStringForSymbol(HKeySymbol symbol) = 0; + + // for debugging, adds KeyValues record into global list so we can track memory leaks + virtual void AddKeyValuesToMemoryLeakList(void *pMem, HKeySymbol name) = 0; + virtual void RemoveKeyValuesFromMemoryLeakList(void *pMem) = 0; + + // maintain a cache of KeyValues we load from disk. This saves us quite a lot of time on app startup. + virtual void AddFileKeyValuesToCache( const KeyValues* _kv, const char *resourceName, const char *pathID ) = 0; + virtual bool LoadFileKeyValuesFromCache( KeyValues* _outKv, const char *resourceName, const char *pathID, IBaseFileSystem *filesystem ) const = 0; + virtual void InvalidateCache( ) = 0; + virtual void InvalidateCacheForFile( const char *resourceName, const char *pathID ) = 0; +}; + +VSTDLIB_INTERFACE IKeyValuesSystem *KeyValuesSystem(); + +// #define KEYVALUESSYSTEM_INTERFACE_VERSION "KeyValuesSystem002" + +#endif // VSTDLIB_IKEYVALUESSYSTEM_H diff --git a/public/vstdlib/coroutine.h b/public/vstdlib/coroutine.h new file mode 100644 index 0000000..797324d --- /dev/null +++ b/public/vstdlib/coroutine.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: setjmp/longjmp based cooperative multitasking system +// +//============================================================================= + +#ifndef COROUTINE_H +#define COROUTINE_H +#pragma once + +#include "vstdlib/vstdlib.h" + +// enable this to do coroutine tracing +// this will tell coroutine API users to set coroutine names +// #define COROUTINE_TRACE + +//----------------------------------------------------------------------------- +// Purpose: handles running coroutines +// setjmp/longjmp based cooperative multitasking system +//----------------------------------------------------------------------------- + +// coroutine callback +typedef void (__cdecl *CoroutineFunc_t )(void *); + +// handle to a coroutine +typedef int32 HCoroutine; + +// creates a new coroutine +// no coroutine code is executed until Coroutine_Continue() is called +VSTDLIB_INTERFACE HCoroutine Coroutine_Create( CoroutineFunc_t pFunc, void *pvParam ); + +// continues the specified coroutine +// returns true if the coroutine is still running, false otherwise +VSTDLIB_INTERFACE bool Coroutine_Continue( HCoroutine hCoroutine, const char *pchName = NULL ); + +// cancels a currently running coroutine +VSTDLIB_INTERFACE void Coroutine_Cancel( HCoroutine hCoroutine ); + +// 'load' a coroutine only to debug it - immediately breaks into debugger +// when continued, pops back to the prior coroutine +VSTDLIB_INTERFACE void Coroutine_DebugBreak( HCoroutine hCoroutine ); + +// Load a coroutine and generate an assert. Used to get a minidump of a job +VSTDLIB_INTERFACE void Coroutine_DebugAssert( HCoroutine hCoroutine, const char *pchMsg ); + +// called from the coroutine to return control to the main thread +VSTDLIB_INTERFACE void Coroutine_YieldToMain(); + +// returns true if the code is currently running inside of a coroutine +VSTDLIB_INTERFACE bool Coroutine_IsActive(); + +// returns a handle the currently active coroutine +VSTDLIB_INTERFACE HCoroutine Coroutine_GetCurrentlyActive(); + +// call when a thread is quiting to release any per-thread memory +VSTDLIB_INTERFACE void Coroutine_ReleaseThreadMemory(); + +// runs a self-test of the coroutine system +VSTDLIB_INTERFACE bool Coroutine_Test(); + +// memory validation +VSTDLIB_INTERFACE void Coroutine_ValidateGlobals( class CValidator &validator ); + +// for debugging purposes - returns stack depth of current coroutine +VSTDLIB_INTERFACE size_t Coroutine_GetStackDepth(); + + + +#endif // COROUTINE_H diff --git a/public/vstdlib/cvar.h b/public/vstdlib/cvar.h new file mode 100644 index 0000000..6373441 --- /dev/null +++ b/public/vstdlib/cvar.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined( CVAR_H ) +#define CVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vstdlib/vstdlib.h" +#include "icvar.h" + + +//----------------------------------------------------------------------------- +// Returns a CVar dictionary for tool usage +//----------------------------------------------------------------------------- +VSTDLIB_INTERFACE CreateInterfaceFn VStdLib_GetICVarFactory(); + + +#endif // CVAR_H diff --git a/public/vstdlib/iprocessutils.h b/public/vstdlib/iprocessutils.h new file mode 100644 index 0000000..8e4d37f --- /dev/null +++ b/public/vstdlib/iprocessutils.h @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef IPROCESSUTILS_H +#define IPROCESSUTILS_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "appframework/IAppSystem.h" + + +//----------------------------------------------------------------------------- +// Handle to a process +//----------------------------------------------------------------------------- +typedef int ProcessHandle_t; +enum +{ + PROCESS_HANDLE_INVALID = 0, +}; + + +//----------------------------------------------------------------------------- +// Interface version +//----------------------------------------------------------------------------- +#define PROCESS_UTILS_INTERFACE_VERSION "VProcessUtils001" + + +//----------------------------------------------------------------------------- +// Interface for makefiles to build differently depending on where they are run from +//----------------------------------------------------------------------------- +abstract_class IProcessUtils : public IAppSystem +{ +public: + // Starts, stops a process + virtual ProcessHandle_t StartProcess( const char *pCommandLine, bool bConnectStdPipes ) = 0; + virtual ProcessHandle_t StartProcess( int argc, const char **argv, bool bConnectStdPipes ) = 0; + virtual void CloseProcess( ProcessHandle_t hProcess ) = 0; + virtual void AbortProcess( ProcessHandle_t hProcess ) = 0; + + // Returns true if a process is complete + virtual bool IsProcessComplete( ProcessHandle_t hProcess ) = 0; + + // Waits until a process is complete + virtual void WaitUntilProcessCompletes( ProcessHandle_t hProcess ) = 0; + + // Methods used to write input into a process + virtual int SendProcessInput( ProcessHandle_t hProcess, char *pBuf, int nBufLen ) = 0; + + // Methods used to read output back from a process + virtual int GetProcessOutputSize( ProcessHandle_t hProcess ) = 0; + virtual int GetProcessOutput( ProcessHandle_t hProcess, char *pBuf, int nBufLen ) = 0; + + // Returns the exit code for the process. Doesn't work unless the process is complete + virtual int GetProcessExitCode( ProcessHandle_t hProcess ) = 0; +}; + + +#endif // IPROCESSUTILS_H diff --git a/public/vstdlib/jobthread.h b/public/vstdlib/jobthread.h new file mode 100644 index 0000000..dcf2c74 --- /dev/null +++ b/public/vstdlib/jobthread.h @@ -0,0 +1,1344 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A utility for a discrete job-oriented worker thread. +// +// The class CThreadPool is both the job queue, and the +// worker thread. Except when the main thread attempts to +// synchronously execute a job, most of the inter-thread locking +// on the queue. +// +// The queue threading model uses a manual reset event for optimal +// throughput. Adding to the queue is guarded by a semaphore that +// will block the inserting thread if the queue has overflown. +// This prevents the worker thread from being starved out even if +// not running at a higher priority than the master thread. +// +// The thread function waits for jobs, services jobs, and manages +// communication between the worker and master threads. The nature +// of the work is opaque to the Executer. +// +// CJob instances actually do the work. The base class +// calls virtual methods for job primitives, so derivations don't +// need to worry about threading models. All of the variants of +// job and OS can be expressed in this hierarchy. Instances of +// CJob are the items placed in the queue, and by +// overriding the job primitives they are the manner by which +// users of the Executer control the state of the job. +// +//============================================================================= + +#include +#include "tier0/threadtools.h" +#include "tier1/refcount.h" +#include "tier1/utllinkedlist.h" +#include "tier1/utlvector.h" +#include "tier1/functors.h" +#include "tier0/vprof_telemetry.h" + +#include "vstdlib/vstdlib.h" + +#ifndef JOBTHREAD_H +#define JOBTHREAD_H + +#ifdef AddJob // windows.h print function collisions +#undef AddJob +#undef GetJob +#endif + +#ifdef VSTDLIB_DLL_EXPORT +#define JOB_INTERFACE DLL_EXPORT +#define JOB_OVERLOAD DLL_GLOBAL_EXPORT +#define JOB_CLASS DLL_CLASS_EXPORT +#else +#define JOB_INTERFACE DLL_IMPORT +#define JOB_OVERLOAD DLL_GLOBAL_IMPORT +#define JOB_CLASS DLL_CLASS_IMPORT +#endif + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CJob; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +enum JobStatusEnum_t +{ + // Use negative for errors + JOB_OK, // operation is successful + JOB_STATUS_PENDING, // file is properly queued, waiting for service + JOB_STATUS_INPROGRESS, // file is being accessed + JOB_STATUS_ABORTED, // file was aborted by caller + JOB_STATUS_UNSERVICED, // file is not yet queued +}; + +typedef int JobStatus_t; + +enum JobFlags_t +{ + JF_IO = ( 1 << 0 ), // The job primarily blocks on IO or hardware + JF_BOOST_THREAD = ( 1 << 1 ), // Up the thread priority to max allowed while processing task + JF_SERIAL = ( 1 << 2 ), // Job cannot be executed out of order relative to other "strict" jobs + JF_QUEUE = ( 1 << 3 ), // Queue it, even if not an IO job +}; + +enum JobPriority_t +{ + JP_LOW, + JP_NORMAL, + JP_HIGH +}; + +#define TP_MAX_POOL_THREADS 64 +struct ThreadPoolStartParams_t +{ + ThreadPoolStartParams_t( bool bIOThreads = false, unsigned nThreads = -1, int *pAffinities = NULL, ThreeState_t fDistribute = TRS_NONE, unsigned nStackSize = -1, int iThreadPriority = SHRT_MIN ) + : bIOThreads( bIOThreads ), nThreads( nThreads ), fDistribute( fDistribute ), nStackSize( nStackSize ), iThreadPriority( iThreadPriority ), nThreadsMax( -1 ) + { + bExecOnThreadPoolThreadsOnly = false; + + bUseAffinityTable = ( pAffinities != NULL ) && ( fDistribute == TRS_TRUE ) && ( nThreads != -1 ); + if ( bUseAffinityTable ) + { + // user supplied an optional 1:1 affinity mapping to override normal distribute behavior + nThreads = MIN( TP_MAX_POOL_THREADS, nThreads ); + for ( unsigned int i = 0; i < nThreads; i++ ) + { + iAffinityTable[i] = pAffinities[i]; + } + } + } + + int nThreads; + int nThreadsMax; + ThreeState_t fDistribute; + int nStackSize; + int iThreadPriority; + int iAffinityTable[TP_MAX_POOL_THREADS]; + + bool bIOThreads : 1; + bool bUseAffinityTable : 1; + bool bExecOnThreadPoolThreadsOnly : 1; +}; + +//----------------------------------------------------------------------------- +// +// IThreadPool +// +//----------------------------------------------------------------------------- + +typedef bool (*JobFilter_t)( CJob * ); + +//--------------------------------------------------------- +// Messages supported through the CallWorker() method +//--------------------------------------------------------- +enum ThreadPoolMessages_t +{ + TPM_EXIT, // Exit the thread + TPM_SUSPEND, // Suspend after next operation + TPM_RUNFUNCTOR, // Run functor, reply when done. +}; + +//--------------------------------------------------------- + +abstract_class IThreadPool : public IRefCounted +{ +public: + virtual ~IThreadPool() {}; + + //----------------------------------------------------- + // Thread functions + //----------------------------------------------------- + virtual bool Start( const ThreadPoolStartParams_t &startParams = ThreadPoolStartParams_t() ) = 0; + virtual bool Stop( int timeout = TT_INFINITE ) = 0; + + //----------------------------------------------------- + // Functions for any thread + //----------------------------------------------------- + virtual unsigned GetJobCount() = 0; + virtual int NumThreads() = 0; + virtual int NumIdleThreads() = 0; + + //----------------------------------------------------- + // Pause/resume processing jobs + //----------------------------------------------------- + virtual int SuspendExecution() = 0; + virtual int ResumeExecution() = 0; + + //----------------------------------------------------- + // Offer the current thread to the pool + //----------------------------------------------------- + virtual int YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) = 0; + virtual int YieldWait( CJob **, int nJobs, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) = 0; + virtual void Yield( unsigned timeout ) = 0; + + bool YieldWait( CThreadEvent &event, unsigned timeout = TT_INFINITE ); + bool YieldWait( CJob *, unsigned timeout = TT_INFINITE ); + + //----------------------------------------------------- + // Add a native job to the queue (master thread) + //----------------------------------------------------- + virtual void AddJob( CJob * ) = 0; + + //----------------------------------------------------- + // All threads execute pFunctor asap. Thread will either wake up + // and execute or execute pFunctor right after completing current job and + // before looking for another job. + //----------------------------------------------------- + virtual void ExecuteHighPriorityFunctor( CFunctor *pFunctor ) = 0; + + //----------------------------------------------------- + // Add an function object to the queue (master thread) + //----------------------------------------------------- + virtual void AddFunctor( CFunctor *pFunctor, CJob **ppJob = NULL, const char *pszDescription = NULL, unsigned flags = 0 ) { AddFunctorInternal( RetAddRef( pFunctor ), ppJob, pszDescription, flags ); } + + //----------------------------------------------------- + // Change the priority of an active job + //----------------------------------------------------- + virtual void ChangePriority( CJob *p, JobPriority_t priority ) = 0; + + //----------------------------------------------------- + // Bulk job manipulation (blocking) + //----------------------------------------------------- + int ExecuteAll( JobFilter_t pfnFilter = NULL ) { return ExecuteToPriority( JP_LOW, pfnFilter ); } + virtual int ExecuteToPriority( JobPriority_t toPriority, JobFilter_t pfnFilter = NULL ) = 0; + virtual int AbortAll() = 0; + + //----------------------------------------------------- + virtual void Reserved1() = 0; + + //----------------------------------------------------- + // Add an arbitrary call to the queue (master thread) + // + // Avert thy eyes! Imagine rather: + // + // CJob *AddCall( , [args1, [arg2,]...] + // CJob *AddCall( , , [args1, [arg2,]...] + // CJob *AddRefCall( , , [args1, [arg2,]...] + // CJob *QueueCall( , [args1, [arg2,]...] + // CJob *QueueCall( , , [args1, [arg2,]...] + //----------------------------------------------------- + + #define DEFINE_NONMEMBER_ADD_CALL(N) \ + template \ + CJob *AddCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_CONST_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_REF_COUNTING_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + //----------------------------------------------------------------------------- + + #define DEFINE_NONMEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_CONST_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + //------------------------------------- + + #define DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + \ + return pJob; \ + } + + FUNC_GENERATE_ALL( DEFINE_NONMEMBER_ADD_CALL ); + FUNC_GENERATE_ALL( DEFINE_MEMBER_ADD_CALL ); + FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_ADD_CALL ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_ADD_CALL ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL ); + FUNC_GENERATE_ALL( DEFINE_NONMEMBER_QUEUE_CALL ); + FUNC_GENERATE_ALL( DEFINE_MEMBER_QUEUE_CALL ); + FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_QUEUE_CALL ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL ); + + #undef DEFINE_NONMEMBER_ADD_CALL + #undef DEFINE_MEMBER_ADD_CALL + #undef DEFINE_CONST_MEMBER_ADD_CALL + #undef DEFINE_REF_COUNTING_MEMBER_ADD_CALL + #undef DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL + #undef DEFINE_NONMEMBER_QUEUE_CALL + #undef DEFINE_MEMBER_QUEUE_CALL + #undef DEFINE_CONST_MEMBER_QUEUE_CALL + #undef DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL + #undef DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL + +private: + virtual void AddFunctorInternal( CFunctor *, CJob ** = NULL, const char *pszDescription = NULL, unsigned flags = 0 ) = 0; + + //----------------------------------------------------- + // Services for internal use by job instances + //----------------------------------------------------- + friend class CJob; + + virtual CJob *GetDummyJob() = 0; + +public: + virtual void Distribute( bool bDistribute = true, int *pAffinityTable = NULL ) = 0; + + virtual bool Start( const ThreadPoolStartParams_t &startParams, const char *pszNameOverride ) = 0; +}; + +//----------------------------------------------------------------------------- + +JOB_INTERFACE IThreadPool *V_CreateThreadPool(); +JOB_INTERFACE void V_DestroyThreadPool( IThreadPool *pPool ); + +//------------------------------------- + +JOB_INTERFACE void RunThreadPoolTests(); + +//----------------------------------------------------------------------------- + +JOB_INTERFACE IThreadPool *g_pThreadPool; + +//----------------------------------------------------------------------------- +// Class to combine the metadata for an operation and the ability to perform +// the operation. Meant for inheritance. All functions inline, defers to executor +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE( ThreadPoolData_t ); +#define JOB_NO_DATA ((ThreadPoolData_t)-1) + +class CJob : public CRefCounted1 +{ +public: + CJob( JobPriority_t priority = JP_NORMAL ) + : m_status( JOB_STATUS_UNSERVICED ), + m_ThreadPoolData( JOB_NO_DATA ), + m_priority( priority ), + m_flags( 0 ), + m_pThreadPool( NULL ), + m_CompleteEvent( true ), + m_iServicingThread( -1 ) + { + m_szDescription[ 0 ] = 0; + } + + //----------------------------------------------------- + // Priority (not thread safe) + //----------------------------------------------------- + void SetPriority( JobPriority_t priority ) { m_priority = priority; } + JobPriority_t GetPriority() const { return m_priority; } + + //----------------------------------------------------- + + void SetFlags( unsigned flags ) { m_flags = flags; } + unsigned GetFlags() const { return m_flags; } + + //----------------------------------------------------- + + void SetServiceThread( int iServicingThread ) { m_iServicingThread = (char)iServicingThread; } + int GetServiceThread() const { return m_iServicingThread; } + void ClearServiceThread() { m_iServicingThread = -1; } + + //----------------------------------------------------- + // Fast queries + //----------------------------------------------------- + bool Executed() const { return ( m_status == JOB_OK ); } + bool CanExecute() const { return ( m_status == JOB_STATUS_PENDING || m_status == JOB_STATUS_UNSERVICED ); } + bool IsFinished() const { return ( m_status != JOB_STATUS_PENDING && m_status != JOB_STATUS_INPROGRESS && m_status != JOB_STATUS_UNSERVICED ); } + JobStatus_t GetStatus() const { return m_status; } + + /// Slam the status to a particular value. This is named "slam" instead of "set," + /// to warn you that it should only be used in unusual situations. Otherwise, the + /// job manager really should manage the status for you, and you should not manhandle it. + void SlamStatus(JobStatus_t s) { m_status = s; } + + //----------------------------------------------------- + // Try to acquire ownership (to satisfy). If you take the lock, you must either execute or abort. + //----------------------------------------------------- + bool TryLock() { return m_mutex.TryLock(); } + void Lock() { m_mutex.Lock(); } + void Unlock() { m_mutex.Unlock(); } + + //----------------------------------------------------- + // Thread event support (safe for NULL this to simplify code ) + //----------------------------------------------------- + bool WaitForFinish( uint32 dwTimeout = TT_INFINITE ) { if (!this) return true; return ( !IsFinished() ) ? g_pThreadPool->YieldWait( this, dwTimeout ) : true; } + bool WaitForFinishAndRelease( uint32 dwTimeout = TT_INFINITE ) { if (!this) return true; bool bResult = WaitForFinish( dwTimeout); Release(); return bResult; } + CThreadEvent *AccessEvent() { return &m_CompleteEvent; } + + //----------------------------------------------------- + // Perform the job + //----------------------------------------------------- + JobStatus_t Execute(); + JobStatus_t TryExecute(); + JobStatus_t ExecuteAndRelease() { JobStatus_t status = Execute(); Release(); return status; } + JobStatus_t TryExecuteAndRelease() { JobStatus_t status = TryExecute(); Release(); return status; } + + //----------------------------------------------------- + // Terminate the job, discard if partially or wholly fulfilled + //----------------------------------------------------- + JobStatus_t Abort( bool bDiscard = true ); + + virtual char const *Describe() { return m_szDescription[ 0 ] ? m_szDescription : "Job"; } + virtual void SetDescription( const char *pszDescription ) + { + if( pszDescription ) + { + Q_strncpy( m_szDescription, pszDescription, sizeof( m_szDescription ) ); + } + else + { + m_szDescription[ 0 ] = 0; + } + } + +private: + //----------------------------------------------------- + friend class CThreadPool; + + JobStatus_t m_status; + JobPriority_t m_priority; + CThreadMutex m_mutex; + unsigned char m_flags; + char m_iServicingThread; + short m_reserved; + ThreadPoolData_t m_ThreadPoolData; + IThreadPool * m_pThreadPool; + CThreadEvent m_CompleteEvent; + char m_szDescription[ 32 ]; + +private: + //----------------------------------------------------- + CJob( const CJob &fromRequest ); + void operator=(const CJob &fromRequest ); + + virtual JobStatus_t DoExecute() = 0; + virtual JobStatus_t DoAbort( bool bDiscard ) { return JOB_STATUS_ABORTED; } + virtual void DoCleanup() {} +}; + +//----------------------------------------------------------------------------- + +class CFunctorJob : public CJob +{ +public: + CFunctorJob( CFunctor *pFunctor, const char *pszDescription = NULL ) + : m_pFunctor( pFunctor ) + { + if ( pszDescription ) + { + Q_strncpy( m_szDescription, pszDescription, sizeof(m_szDescription) ); + } + else + { + m_szDescription[0] = 0; + } + } + + virtual JobStatus_t DoExecute() + { + (*m_pFunctor)(); + return JOB_OK; + } + + const char *Describe() + { + return m_szDescription; + } + +private: + CRefPtr m_pFunctor; + char m_szDescription[16]; +}; + +//----------------------------------------------------------------------------- +// Utility for managing multiple jobs +//----------------------------------------------------------------------------- + +class CJobSet +{ +public: + CJobSet( CJob *pJob = NULL ) + { + if ( pJob ) + { + m_jobs.AddToTail( pJob ); + } + } + + CJobSet( CJob **ppJobs, int nJobs ) + { + if ( ppJobs ) + { + m_jobs.AddMultipleToTail( nJobs, ppJobs ); + } + } + + ~CJobSet() + { + for ( int i = 0; i < m_jobs.Count(); i++ ) + { + m_jobs[i]->Release(); + } + } + + void operator+=( CJob *pJob ) + { + m_jobs.AddToTail( pJob ); + } + + void operator-=( CJob *pJob ) + { + m_jobs.FindAndRemove( pJob ); + } + + void Execute( bool bRelease = true ) + { + for ( int i = 0; i < m_jobs.Count(); i++ ) + { + m_jobs[i]->Execute(); + if ( bRelease ) + { + m_jobs[i]->Release(); + } + } + + if ( bRelease ) + { + m_jobs.RemoveAll(); + } + } + + void Abort( bool bRelease = true ) + { + for ( int i = 0; i < m_jobs.Count(); i++ ) + { + m_jobs[i]->Abort(); + if ( bRelease ) + { + m_jobs[i]->Release(); + } + } + + if ( bRelease ) + { + m_jobs.RemoveAll(); + } + } + + void WaitForFinish( bool bRelease = true ) + { + for ( int i = 0; i < m_jobs.Count(); i++ ) + { + m_jobs[i]->WaitForFinish(); + if ( bRelease ) + { + m_jobs[i]->Release(); + } + } + + if ( bRelease ) + { + m_jobs.RemoveAll(); + } + } + + void WaitForFinish( IThreadPool *pPool, bool bRelease = true ) + { + pPool->YieldWait( m_jobs.Base(), m_jobs.Count() ); + + if ( bRelease ) + { + for ( int i = 0; i < m_jobs.Count(); i++ ) + { + m_jobs[i]->Release(); + } + + m_jobs.RemoveAll(); + } + } + +private: + CUtlVectorFixed m_jobs; +}; + +//----------------------------------------------------------------------------- +// Job helpers +//----------------------------------------------------------------------------- + +#define ThreadExecute g_pThreadPool->QueueCall +#define ThreadExecuteRef g_pThreadPool->QueueRefCall + +#define BeginExecuteParallel() do { CJobSet jobSet +#define EndExecuteParallel() jobSet.WaitForFinish( g_pThreadPool ); } while (0) + +#define ExecuteParallel jobSet += g_pThreadPool->QueueCall +#define ExecuteRefParallel jobSet += g_pThreadPool->QueueCallRef + + +//----------------------------------------------------------------------------- +// Work splitting: array split, best when cost per item is roughly equal +//----------------------------------------------------------------------------- + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) +#pragma warning(disable:4018) +#pragma warning(disable:4701) +#endif + +#define DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL(N) \ + template \ + void IterRangeParallel(FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_ADDL_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + const int MAX_THREADS = 16; \ + int nIdle = g_pThreadPool->NumIdleThreads(); \ + ITERTYPE1 range = to - from; \ + int nThreads = MIN( nIdle + 1, range ); \ + if ( nThreads > MAX_THREADS ) \ + { \ + nThreads = MAX_THREADS; \ + } \ + if ( nThreads < 2 ) \ + { \ + FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + ITERTYPE1 nIncrement = range / nThreads; \ + \ + CJobSet jobSet; \ + while ( --nThreads ) \ + { \ + ITERTYPE2 thisTo = from + nIncrement; \ + jobSet += g_pThreadPool->AddCall( pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \ + from = thisTo; \ + } \ + FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + jobSet.WaitForFinish( g_pThreadPool ); \ + } \ + \ + } + +FUNC_GENERATE_ALL( DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL ); + +#define DEFINE_MEMBER_ITER_RANGE_PARALLEL(N) \ + template \ + void IterRangeParallel(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_ADDL_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + const int MAX_THREADS = 16; \ + int nIdle = g_pThreadPool->NumIdleThreads(); \ + ITERTYPE1 range = to - from; \ + int nThreads = MIN( nIdle + 1, range ); \ + if ( nThreads > MAX_THREADS ) \ + { \ + nThreads = MAX_THREADS; \ + } \ + if ( nThreads < 2 ) \ + { \ + FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + ITERTYPE1 nIncrement = range / nThreads; \ + \ + CJobSet jobSet; \ + while ( --nThreads ) \ + { \ + ITERTYPE2 thisTo = from + nIncrement; \ + jobSet += g_pThreadPool->AddCall( pObject, pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \ + from = thisTo; \ + } \ + FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + jobSet.WaitForFinish( g_pThreadPool ); \ + } \ + \ + } + +FUNC_GENERATE_ALL( DEFINE_MEMBER_ITER_RANGE_PARALLEL ); + +//----------------------------------------------------------------------------- +// Work splitting: competitive, best when cost per item varies a lot +//----------------------------------------------------------------------------- + +template +class CJobItemProcessor +{ +public: + typedef T ItemType_t; + void Begin() {} + // void Process( ItemType_t & ) {} + void End() {} +}; + +template +class CFuncJobItemProcessor : public CJobItemProcessor +{ +public: + void Init(void (*pfnProcess)( T & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL ) + { + m_pfnProcess = pfnProcess; + m_pfnBegin = pfnBegin; + m_pfnEnd = pfnEnd; + } + + //CFuncJobItemProcessor(OBJECT_TYPE_PTR pObject, void (FUNCTION_CLASS::*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL ); + void Begin() { if ( m_pfnBegin ) (*m_pfnBegin)(); } + void Process( T &item ) { (*m_pfnProcess)( item ); } + void End() { if ( m_pfnEnd ) (*m_pfnEnd)(); } + +protected: + void (*m_pfnProcess)( T & ); + void (*m_pfnBegin)(); + void (*m_pfnEnd)(); +}; + +template +class CMemberFuncJobItemProcessor : public CJobItemProcessor +{ +public: + void Init( OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( T & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL ) + { + m_pObject = pObject; + m_pfnProcess = pfnProcess; + m_pfnBegin = pfnBegin; + m_pfnEnd = pfnEnd; + } + + void Begin() { if ( m_pfnBegin ) ((*m_pObject).*m_pfnBegin)(); } + void Process( T &item ) { ((*m_pObject).*m_pfnProcess)( item ); } + void End() { if ( m_pfnEnd ) ((*m_pObject).*m_pfnEnd)(); } + +protected: + OBJECT_TYPE *m_pObject; + void (FUNCTION_CLASS::*m_pfnProcess)( T & ); + void (FUNCTION_CLASS::*m_pfnBegin)(); + void (FUNCTION_CLASS::*m_pfnEnd)(); +}; + +template +class CParallelProcessor +{ +public: + CParallelProcessor( const char *pszDescription ) + { + m_pItems = m_pLimit= 0; + m_szDescription = pszDescription; + } + + void Run( ITEM_TYPE *pItems, unsigned nItems, int nMaxParallel = INT_MAX, IThreadPool *pThreadPool = NULL ) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "Run %s %d", m_szDescription, nItems ); + + if ( nItems == 0 ) + return; + + if ( !pThreadPool ) + { + pThreadPool = g_pThreadPool; + } + + m_pItems = pItems; + m_pLimit = pItems + nItems; + + int nJobs = nItems - 1; + + if ( nJobs > nMaxParallel ) + { + nJobs = nMaxParallel; + } + + if (! pThreadPool ) // only possible on linux + { + DoExecute( ); + return; + } + + int nThreads = pThreadPool->NumThreads(); + if ( nJobs > nThreads ) + { + nJobs = nThreads; + } + + if ( nJobs > 1 ) + { + CJob **jobs = (CJob **)stackalloc( nJobs * sizeof(CJob **) ); + int i = nJobs; + + while( i-- ) + { + jobs[i] = pThreadPool->QueueCall( this, &CParallelProcessor::DoExecute ); + jobs[i]->SetDescription( m_szDescription ); + } + + DoExecute(); + + for ( i = 0; i < nJobs; i++ ) + { + jobs[i]->Abort(); // will either abort ones that never got a thread, or noop on ones that did + jobs[i]->Release(); + } + } + else + { + DoExecute(); + } + } + + ITEM_PROCESSOR_TYPE m_ItemProcessor; + +private: + void DoExecute() + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription ); + + if ( m_pItems < m_pLimit ) + { + m_ItemProcessor.Begin(); + + ITEM_TYPE *pLimit = m_pLimit; + + for (;;) + { + ITEM_TYPE *pCurrent = m_pItems++; + if ( pCurrent < pLimit ) + { + m_ItemProcessor.Process( *pCurrent ); + } + else + { + break; + } + } + + m_ItemProcessor.End(); + } + } + CInterlockedPtr m_pItems; + ITEM_TYPE * m_pLimit; + const char * m_szDescription; +}; + +template +inline void ParallelProcess( const char *pszDescription, ITEM_TYPE *pItems, unsigned nItems, void (*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX ) +{ + CParallelProcessor > processor( pszDescription ); + processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd ); + processor.Run( pItems, nItems, nMaxParallel ); + +} + +template +inline void ParallelProcess( const char *pszDescription, ITEM_TYPE *pItems, unsigned nItems, OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( ITEM_TYPE & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL, int nMaxParallel = INT_MAX ) +{ + CParallelProcessor > processor( pszDescription ); + processor.m_ItemProcessor.Init( pObject, pfnProcess, pfnBegin, pfnEnd ); + processor.Run( pItems, nItems, nMaxParallel ); +} + +// Parallel Process that lets you specify threadpool +template +inline void ParallelProcess( const char *pszDescription, IThreadPool *pPool, ITEM_TYPE *pItems, unsigned nItems, void (*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX ) +{ + CParallelProcessor > processor( pszDescription ); + processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd ); + processor.Run( pItems, nItems, nMaxParallel, pPool ); +} + + +template +class CParallelLoopProcessor +{ +public: + CParallelLoopProcessor( const char *pszDescription ) + { + m_lIndex = m_lLimit= 0; + m_nActive = 0; + m_szDescription = pszDescription; + } + + void Run( long lBegin, long nItems, int nMaxParallel = INT_MAX ) + { + if ( nItems ) + { + m_lIndex = lBegin; + m_lLimit = lBegin + nItems; + int i = g_pThreadPool->NumIdleThreads(); + + if ( nMaxParallel < i) + { + i = nMaxParallel; + } + + while( i-- ) + { + ++m_nActive; + ThreadExecute( this, &CParallelLoopProcessor::DoExecute )->Release(); + } + + ++m_nActive; + DoExecute(); + + while ( m_nActive ) + { + ThreadPause(); + } + } + } + + ITEM_PROCESSOR_TYPE m_ItemProcessor; + +private: + void DoExecute() + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription ); + + m_ItemProcessor.Begin(); + + long lLimit = m_lLimit; + + for (;;) + { + long lIndex = m_lIndex ++; + if ( lIndex < lLimit ) + { + m_ItemProcessor.Process( lIndex ); + } + else + { + break; + } + } + + m_ItemProcessor.End(); + + --m_nActive; + } + CInterlockedInt m_lIndex; + long m_lLimit; + CInterlockedInt m_nActive; + const char * m_szDescription; +}; + +inline void ParallelLoopProcess( const char *szDescription, long lBegin, unsigned nItems, void (*pfnProcess)( long const & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX ) +{ + CParallelLoopProcessor< CFuncJobItemProcessor< long const > > processor( szDescription ); + processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd ); + processor.Run( lBegin, nItems, nMaxParallel ); + +} + +template < typename OBJECT_TYPE, typename FUNCTION_CLASS > +inline void ParallelLoopProcess( const char *szDescription, long lBegin, unsigned nItems, OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( long const & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL, int nMaxParallel = INT_MAX ) +{ + CParallelLoopProcessor< CMemberFuncJobItemProcessor > processor( szDescription ); + processor.m_ItemProcessor.Init( pObject, pfnProcess, pfnBegin, pfnEnd ); + processor.Run( lBegin, nItems, nMaxParallel ); +} + + +template +class CParallelProcessorBase +{ +protected: + typedef CParallelProcessorBase ThisParallelProcessorBase_t; + typedef Derived ThisParallelProcessorDerived_t; + +public: + CParallelProcessorBase() + { + m_nActive = 0; + m_szDescription = NULL; + } + void SetDescription( const char *pszDescription ) + { + m_szDescription = pszDescription; + } + +protected: + void Run( int nMaxParallel = INT_MAX, int threadOverride = -1 ) + { + int i = g_pThreadPool->NumIdleThreads(); + + if ( nMaxParallel < i) + { + i = nMaxParallel; + } + + while( i -- > 0 ) + { + if ( threadOverride == -1 || i == threadOverride - 1 ) + { + ++ m_nActive; + ThreadExecute( this, &ThisParallelProcessorBase_t::DoExecute )->Release(); + } + } + + if ( threadOverride == -1 || threadOverride == 0 ) + { + ++ m_nActive; + DoExecute(); + } + + while ( m_nActive ) + { + ThreadPause(); + } + } + +protected: + void OnBegin() {} + bool OnProcess() { return false; } + void OnEnd() {} + +private: + void DoExecute() + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription ); + + static_cast( this )->OnBegin(); + + while ( static_cast( this )->OnProcess() ) + continue; + + static_cast(this)->OnEnd(); + + -- m_nActive; + } + + CInterlockedInt m_nActive; + const char * m_szDescription; +}; + + + + +//----------------------------------------------------------------------------- +// Raw thread launching +//----------------------------------------------------------------------------- + +inline unsigned FunctorExecuteThread( void *pParam ) +{ + CFunctor *pFunctor = (CFunctor *)pParam; + (*pFunctor)(); + pFunctor->Release(); + return 0; +} + +inline ThreadHandle_t ThreadExecuteSoloImpl( CFunctor *pFunctor, const char *pszName = NULL ) +{ + ThreadHandle_t hThread; + ThreadId_t threadId; + hThread = CreateSimpleThread( FunctorExecuteThread, pFunctor, &threadId ); + if ( pszName ) + { + ThreadSetDebugName( threadId, pszName ); + } + return hThread; +} + +inline ThreadHandle_t ThreadExecuteSolo( CJob *pJob ) { return ThreadExecuteSoloImpl( CreateFunctor( pJob, &CJob::Execute ), pJob->Describe() ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6, a7 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6, a7, a8 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7 ), pszName ); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7, a8 ), pszName ); } + +//----------------------------------------------------------------------------- + +inline bool IThreadPool::YieldWait( CThreadEvent &event, unsigned timeout ) +{ + CThreadEvent *pEvent = &event; + return ( YieldWait( &pEvent, 1, true, timeout ) != TW_TIMEOUT ); +} + +inline bool IThreadPool::YieldWait( CJob *pJob, unsigned timeout ) +{ + return ( YieldWait( &pJob, 1, true, timeout ) != TW_TIMEOUT ); +} + +//----------------------------------------------------------------------------- + +inline JobStatus_t CJob::Execute() +{ + if ( IsFinished() ) + { + return m_status; + } + + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status ); + + AUTO_LOCK( m_mutex ); + AddRef(); + + JobStatus_t result; + + switch ( m_status ) + { + case JOB_STATUS_UNSERVICED: + case JOB_STATUS_PENDING: + { + // Service it + m_status = JOB_STATUS_INPROGRESS; + result = m_status = DoExecute(); + DoCleanup(); + m_CompleteEvent.Set(); + break; + } + + case JOB_STATUS_INPROGRESS: + AssertMsg(0, "Mutex Should have protected use while processing"); + // fall through... + + case JOB_OK: + case JOB_STATUS_ABORTED: + result = m_status; + break; + + default: + AssertMsg( m_status < JOB_OK, "Unknown job state"); + result = m_status; + } + + Release(); + + return result; +} + + +//--------------------------------------------------------- + +inline JobStatus_t CJob::TryExecute() +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status ); + + // TryLock() would only fail if another thread has entered + // Execute() or Abort() + if ( !IsFinished() && TryLock() ) + { + // ...service the request + Execute(); + Unlock(); + } + return m_status; +} + +//--------------------------------------------------------- + +inline JobStatus_t CJob::Abort( bool bDiscard ) +{ + if ( IsFinished() ) + { + return m_status; + } + + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status ); + + AUTO_LOCK( m_mutex ); + AddRef(); + + JobStatus_t result; + + switch ( m_status ) + { + case JOB_STATUS_UNSERVICED: + case JOB_STATUS_PENDING: + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CJob::DoAbort" ); + + result = m_status = DoAbort( bDiscard ); + if ( bDiscard ) + DoCleanup(); + m_CompleteEvent.Set(); + } + break; + + case JOB_STATUS_ABORTED: + case JOB_STATUS_INPROGRESS: + case JOB_OK: + result = m_status; + break; + + default: + AssertMsg( m_status < JOB_OK, "Unknown job state"); + result = m_status; + } + + Release(); + + return result; +} + +//----------------------------------------------------------------------------- + +#endif // JOBTHREAD_H diff --git a/public/vstdlib/osversion.h b/public/vstdlib/osversion.h new file mode 100644 index 0000000..ecc68ae --- /dev/null +++ b/public/vstdlib/osversion.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef OSVERSION_H +#define OSVERSION_H +#pragma once + +#include "vstdlib/vstdlib.h" + +// OS types we know about +// Must be in ascending capability order, we use this for min OS requirements +enum EOSType +{ + k_eOSUnknown = -1, + k_eMacOSUnknown = -102, + k_eMacOS104 = -101, + k_eMacOS105 = -100, + k_eMacOS1058 = -99, + k_eMacOS106 = -95, + k_eMacOS1063 = -94, + k_eMacOS107 = -90, + // k_eMacOSMax = -1 + k_eLinuxUnknown = -203, + k_eLinux22 = -202, + k_eLinux24 = -201, + k_eLinux26 = -200, + // k_eLinuxMax = -103 + k_eWinUnknown = 0, + k_eWin311 = 1, + k_eWin95, + k_eWin98, + k_eWinME, + k_eWinNT, + k_eWin2000, + k_eWinXP, + k_eWin2003, + k_eWinVista, + k_eWindows7, + k_eWin2008, + k_eWinMAX, + k_eOSTypeMax = k_eWinMAX + 11 // win types + other ifdef'd types +}; + +VSTDLIB_INTERFACE const char *GetNameFromOSType( EOSType eOSType ); +VSTDLIB_INTERFACE const char *GetOSDetailString( char *pchOutBuf, int cchOutBuf ); +VSTDLIB_INTERFACE EOSType GetOSType(); +VSTDLIB_INTERFACE bool OSTypesAreCompatible( EOSType eOSTypeDetected, EOSType eOSTypeRequired ); +VSTDLIB_INTERFACE const char *GetPlatformName( bool *pbIs64Bit ); + +#endif // OSVERSION_H diff --git a/public/vstdlib/pch_vstdlib.h b/public/vstdlib/pch_vstdlib.h new file mode 100644 index 0000000..57242c4 --- /dev/null +++ b/public/vstdlib/pch_vstdlib.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//============================================================================= + + +#pragma warning(disable: 4514) + +// First include standard libraries +#include +#include +#include +#include +#include +#include + +// Next, include public +#include "tier0/basetypes.h" +#include "tier0/dbg.h" +#include "tier0/valobject.h" + +// Next, include vstdlib +#include "vstdlib/vstdlib.h" +#include "tier1/strtools.h" +#include "vstdlib/random.h" +#include "tier1/KeyValues.h" +#include "tier1/utlmemory.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlvector.h" +#include "tier1/utllinkedlist.h" +#include "tier1/utlmultilist.h" +#include "tier1/utlsymbol.h" +#include "tier0/icommandline.h" +#include "tier1/netadr.h" +#include "tier1/mempool.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlstring.h" +#include "tier1/utlmap.h" + +#include "tier0/memdbgon.h" + + + diff --git a/public/vstdlib/random.h b/public/vstdlib/random.h new file mode 100644 index 0000000..fdfd09c --- /dev/null +++ b/public/vstdlib/random.h @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Random number generator +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef VSTDLIB_RANDOM_H +#define VSTDLIB_RANDOM_H + +#include "vstdlib/vstdlib.h" +#include "tier0/basetypes.h" +#include "tier0/threadtools.h" +#include "tier1/interface.h" + +#define NTAB 32 + +#pragma warning(push) +#pragma warning( disable:4251 ) + +//----------------------------------------------------------------------------- +// A generator of uniformly distributed random numbers +//----------------------------------------------------------------------------- +class VSTDLIB_CLASS IUniformRandomStream +{ +public: + //virtual ~IUniformRandomStream() { } + + // Sets the seed of the random number generator + virtual void SetSeed( int iSeed ) = 0; + + // Generates random numbers + virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ) = 0; + virtual int RandomInt( int iMinVal, int iMaxVal ) = 0; + virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ) = 0; +}; + + +//----------------------------------------------------------------------------- +// The standard generator of uniformly distributed random numbers +//----------------------------------------------------------------------------- +class VSTDLIB_CLASS CUniformRandomStream : public IUniformRandomStream +{ +public: + CUniformRandomStream(); + + // Sets the seed of the random number generator + virtual void SetSeed( int iSeed ); + + // Generates random numbers + virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ); + virtual int RandomInt( int iMinVal, int iMaxVal ); + virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ); + +private: + int GenerateRandomNumber(); + + int m_idum; + int m_iy; + int m_iv[NTAB]; + + CThreadFastMutex m_mutex; +}; + + +//----------------------------------------------------------------------------- +// A generator of gaussian distributed random numbers +//----------------------------------------------------------------------------- +class VSTDLIB_CLASS CGaussianRandomStream +{ +public: + // Passing in NULL will cause the gaussian stream to use the + // installed global random number generator + CGaussianRandomStream( IUniformRandomStream *pUniformStream = NULL ); + + // Attaches to a random uniform stream + void AttachToStream( IUniformRandomStream *pUniformStream = NULL ); + + // Generates random numbers + float RandomFloat( float flMean = 0.0f, float flStdDev = 1.0f ); + +private: + IUniformRandomStream *m_pUniformStream; + bool m_bHaveValue; + float m_flRandomValue; + + CThreadFastMutex m_mutex; +}; + +//----------------------------------------------------------------------------- +// A couple of convenience functions to access the library's global uniform stream +//----------------------------------------------------------------------------- +VSTDLIB_INTERFACE void RandomSeed( int iSeed ); +VSTDLIB_INTERFACE float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ); +VSTDLIB_INTERFACE float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ); +VSTDLIB_INTERFACE int RandomInt( int iMinVal, int iMaxVal ); +VSTDLIB_INTERFACE float RandomGaussianFloat( float flMean = 0.0f, float flStdDev = 1.0f ); + +//----------------------------------------------------------------------------- +// IUniformRandomStream interface for free functions +//----------------------------------------------------------------------------- +class VSTDLIB_CLASS CDefaultUniformRandomStream : public IUniformRandomStream +{ +public: + virtual void SetSeed( int iSeed ) OVERRIDE { RandomSeed( iSeed ); } + virtual float RandomFloat( float flMinVal, float flMaxVal ) OVERRIDE { return ::RandomFloat( flMinVal, flMaxVal ); } + virtual int RandomInt( int iMinVal, int iMaxVal ) OVERRIDE { return ::RandomInt( iMinVal, iMaxVal ); } + virtual float RandomFloatExp( float flMinVal, float flMaxVal, float flExponent ) OVERRIDE { return ::RandomFloatExp( flMinVal, flMaxVal, flExponent ); } +}; + +//----------------------------------------------------------------------------- +// Installs a global random number generator, which will affect the Random functions above +//----------------------------------------------------------------------------- +VSTDLIB_INTERFACE void InstallUniformRandomStream( IUniformRandomStream *pStream ); + + +#pragma warning(pop) + +#endif // VSTDLIB_RANDOM_H + + + diff --git a/public/vstdlib/vcover.h b/public/vstdlib/vcover.h new file mode 100644 index 0000000..156534c --- /dev/null +++ b/public/vstdlib/vcover.h @@ -0,0 +1,125 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A simple tool for coverage tests +// +//============================================================================= + +#ifndef VCOVER_H +#define VCOVER_H + +#include "tier1/utlrbtree.h" +#include "vstdlib.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class CVCoverage +{ +public: + CVCoverage() : + m_bActive( false ), + m_depth( 0 ), + m_token( 1 ) + { + } + + bool IsActive() const + { + return m_bActive; + } + + void SetActive( bool bActive ) + { + Assert( bActive != m_bActive ); + m_bActive = bActive; + if ( bActive ) + ++m_token; + } + + void Begin() + { + ++m_depth; + } + + void End() + { + --m_depth; + } + + void Reset() + { + m_locations.RemoveAll(); + } + + bool ShouldCover( unsigned token ) const + { + return ( m_bActive && m_depth > 0 && token != m_token ); + } + + unsigned Cover( const char *pszFile, int line ) + { + Location_t location = { pszFile, line }; + + m_locations.Insert( location ); + + return m_token; + } + + void Report() + { + for ( int i = m_locations.FirstInorder(); i != m_locations.InvalidIndex(); i = m_locations.NextInorder( i ) ) + { + Msg( "%s(%d) :\n", m_locations[i].pszFile, m_locations[i].line ); + } + } + +private: + struct Location_t + { + const char *pszFile; + int line; + + }; + + class CLocationLess + { + public: + CLocationLess( int ignored ) {} + bool operator!() { return false; } + + bool operator()( const Location_t &lhs, const Location_t &rhs ) const + { + if ( lhs.line < rhs.line ) + { + return true; + } + + return CaselessStringLessThan( lhs.pszFile, rhs.pszFile ); + } + }; + + bool m_bActive; + int m_depth; + unsigned m_token; + + CUtlRBTree< Location_t, unsigned short, CLocationLess > m_locations; +}; + +VSTDLIB_INTERFACE CVCoverage g_VCoverage; + +#ifdef VCOVER_ENABLED +#define VCOVER() \ + do \ + { \ + static token; \ + if ( g_VCoverage.ShouldCover( token ) ) \ + { \ + token = g_VCoverage.Cover( __FILE__, __LINE__ ); \ + } \ + } while( 0 ) +#else +#define VCOVER() ((void)0) +#endif + +#endif // VCOVER_H diff --git a/public/vstdlib/vstdlib.h b/public/vstdlib/vstdlib.h new file mode 100644 index 0000000..4e3a7f8 --- /dev/null +++ b/public/vstdlib/vstdlib.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VSTDLIB_H +#define VSTDLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- +#ifdef VSTDLIB_DLL_EXPORT +#define VSTDLIB_INTERFACE DLL_EXPORT +#define VSTDLIB_OVERLOAD DLL_GLOBAL_EXPORT +#define VSTDLIB_CLASS DLL_CLASS_EXPORT +#define VSTDLIB_GLOBAL DLL_GLOBAL_EXPORT +#else +#define VSTDLIB_INTERFACE DLL_IMPORT +#define VSTDLIB_OVERLOAD DLL_GLOBAL_IMPORT +#define VSTDLIB_CLASS DLL_CLASS_IMPORT +#define VSTDLIB_GLOBAL DLL_GLOBAL_IMPORT +#endif + +#endif // VSTDLIB_H diff --git a/public/vtf/vtf.h b/public/vtf/vtf.h new file mode 100644 index 0000000..a77e7fb --- /dev/null +++ b/public/vtf/vtf.h @@ -0,0 +1,608 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef VTF_H +#define VTF_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" +#include "tier0/platform.h" + +// #define VTF_FILE_FORMAT_ONLY to just include the vtf header and none of the code declaration +#ifndef VTF_FILE_FORMAT_ONLY + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; +class Vector; +struct Rect_t; +class IFileSystem; + +//----------------------------------------------------------------------------- +// Texture flags +//----------------------------------------------------------------------------- +enum CompiledVtfFlags +{ + // flags from the *.txt config file + TEXTUREFLAGS_POINTSAMPLE = 0x00000001, + TEXTUREFLAGS_TRILINEAR = 0x00000002, + TEXTUREFLAGS_CLAMPS = 0x00000004, + TEXTUREFLAGS_CLAMPT = 0x00000008, + TEXTUREFLAGS_ANISOTROPIC = 0x00000010, + TEXTUREFLAGS_HINT_DXT5 = 0x00000020, + TEXTUREFLAGS_SRGB = 0x00000040, + TEXTUREFLAGS_NORMAL = 0x00000080, + TEXTUREFLAGS_NOMIP = 0x00000100, + TEXTUREFLAGS_NOLOD = 0x00000200, + TEXTUREFLAGS_ALL_MIPS = 0x00000400, + TEXTUREFLAGS_PROCEDURAL = 0x00000800, + + // These are automatically generated by vtex from the texture data. + TEXTUREFLAGS_ONEBITALPHA = 0x00001000, + TEXTUREFLAGS_EIGHTBITALPHA = 0x00002000, + + // newer flags from the *.txt config file + TEXTUREFLAGS_ENVMAP = 0x00004000, + TEXTUREFLAGS_RENDERTARGET = 0x00008000, + TEXTUREFLAGS_DEPTHRENDERTARGET = 0x00010000, + TEXTUREFLAGS_NODEBUGOVERRIDE = 0x00020000, + TEXTUREFLAGS_SINGLECOPY = 0x00040000, + + TEXTUREFLAGS_STAGING_MEMORY = 0x00080000, + TEXTUREFLAGS_IMMEDIATE_CLEANUP = 0x00100000, + TEXTUREFLAGS_IGNORE_PICMIP = 0x00200000, + TEXTUREFLAGS_UNUSED_00400000 = 0x00400000, + + TEXTUREFLAGS_NODEPTHBUFFER = 0x00800000, + + TEXTUREFLAGS_UNUSED_01000000 = 0x01000000, + + TEXTUREFLAGS_CLAMPU = 0x02000000, + + TEXTUREFLAGS_VERTEXTEXTURE = 0x04000000, // Useable as a vertex texture + + TEXTUREFLAGS_SSBUMP = 0x08000000, + + TEXTUREFLAGS_UNUSED_10000000 = 0x10000000, + + // Clamp to border color on all texture coordinates + TEXTUREFLAGS_BORDER = 0x20000000, + + TEXTUREFLAGS_UNUSED_40000000 = 0x40000000, + TEXTUREFLAGS_UNUSED_80000000 = 0x80000000, +}; + +enum VersionedVtfFlags +{ + VERSIONED_VTF_FLAGS_MASK_7_3 = ~0xD1780400, // For a ver 7.3 or earlier only these flags are valid +}; + + +struct VtfProcessingOptions +{ + uint32 cbSize; // Set to sizeof( VtfProcessingOptions ) + + // + // Flags0 + // + enum Flags0 + { + // Have a channel decaying to a given decay goal for the given last number of mips + OPT_DECAY_R = 0x00000001, // Red decays + OPT_DECAY_G = 0x00000002, // Green decays + OPT_DECAY_B = 0x00000004, // Blue decays + OPT_DECAY_A = 0x00000008, // Alpha decays + + OPT_DECAY_EXP_R = 0x00000010, // Channel R decays exponentially (otherwise linearly) + OPT_DECAY_EXP_G = 0x00000020, // Channel G decays exponentially (otherwise linearly) + OPT_DECAY_EXP_B = 0x00000040, // Channel B decays exponentially (otherwise linearly) + OPT_DECAY_EXP_A = 0x00000080, // Channel A decays exponentially (otherwise linearly) + + OPT_NOCOMPRESS = 0x00000100, // Use uncompressed image format + OPT_NORMAL_DUDV = 0x00000200, // dU dV normal map + OPT_FILTER_NICE = 0x00000400, // Use nice filtering + + OPT_SET_ALPHA_ONEOVERMIP = 0x00001000, // Alpha = 1/miplevel + OPT_PREMULT_COLOR_ONEOVERMIP = 0x00002000, // Color *= 1/miplevel + OPT_MIP_ALPHATEST = 0x00004000, // Alpha-tested mip generation + }; + + uint32 flags0; // A combination of "Flags0" + + // + // Decay settings + // + uint8 clrDecayGoal[4]; // Goal colors for R G B A + uint8 numNotDecayMips[4]; // Number of first mips unaffected by decay (0 means all below mip0) + float fDecayExponentBase[4]; // For exponential decay the base number (e.g. 0.75) +}; + + +//----------------------------------------------------------------------------- +// Cubemap face indices +//----------------------------------------------------------------------------- +enum CubeMapFaceIndex_t +{ + CUBEMAP_FACE_RIGHT = 0, + CUBEMAP_FACE_LEFT, + CUBEMAP_FACE_BACK, // NOTE: This face is in the +y direction?!?!? + CUBEMAP_FACE_FRONT, // NOTE: This face is in the -y direction!?!? + CUBEMAP_FACE_UP, + CUBEMAP_FACE_DOWN, + + // This is the fallback for low-end + CUBEMAP_FACE_SPHEREMAP, + + // NOTE: Cubemaps have *7* faces; the 7th is the fallback spheremap + CUBEMAP_FACE_COUNT +}; + + +//----------------------------------------------------------------------------- +// Enumeration used for spheremap generation +//----------------------------------------------------------------------------- +enum LookDir_t +{ + LOOK_DOWN_X = 0, + LOOK_DOWN_NEGX, + LOOK_DOWN_Y, + LOOK_DOWN_NEGY, + LOOK_DOWN_Z, + LOOK_DOWN_NEGZ, +}; + + +//----------------------------------------------------------------------------- +// Use this image format if you want to perform tool operations on the texture +//----------------------------------------------------------------------------- +#define IMAGE_FORMAT_DEFAULT ((ImageFormat)-2) + +//----------------------------------------------------------------------------- +// Interface to get at various bits of a VTF texture +//----------------------------------------------------------------------------- +class IVTFTexture +{ +public: + virtual ~IVTFTexture() {} + + // Initializes the texture and allocates space for the bits + // In most cases, you shouldn't force the mip count. + virtual bool Init( int nWidth, int nHeight, int nDepth, ImageFormat fmt, int nFlags, int iFrameCount, int nForceMipCount = -1 ) = 0; + + // Methods to set other texture fields + virtual void SetBumpScale( float flScale ) = 0; + virtual void SetReflectivity( const Vector &vecReflectivity ) = 0; + + // Methods to initialize the low-res image + virtual void InitLowResImage( int nWidth, int nHeight, ImageFormat fmt ) = 0; + + // set the resource data (for writers). pass size=0 to delete data. if pdata is not null, + // the resource data will be copied from *pData + virtual void *SetResourceData( uint32 eType, void const *pData, size_t nDataSize ) = 0; + + // find the resource data and return a pointer to it. The data pointed to by this pointer will + // go away when the ivtftexture does. retruns null if resource not present + virtual void *GetResourceData( uint32 eType, size_t *pDataSize ) const = 0; + + // Locates the resource entry info if it's present, easier than crawling array types + virtual bool HasResourceEntry( uint32 eType ) const = 0; + + // Retrieve available resource types of this IVTFTextures + // arrTypesBuffer buffer to be filled with resource types available. + // numTypesBufferElems how many resource types the buffer can accomodate. + // Returns: + // number of resource types available (can be greater than "numTypesBufferElems" + // in which case only first "numTypesBufferElems" are copied to "arrTypesBuffer") + virtual unsigned int GetResourceTypes( uint32 *arrTypesBuffer, int numTypesBufferElems ) const = 0; + + // When unserializing, we can skip a certain number of mip levels, + // and we also can just load everything but the image data + // NOTE: If you load only the buffer header, you'll need to use the + // VTFBufferHeaderSize() method below to only read that much from the file + // NOTE: If you skip mip levels, the height + width of the texture will + // change to reflect the size of the largest read in mip level + virtual bool Unserialize( CUtlBuffer &buf, bool bHeaderOnly = false, int nSkipMipLevels = 0 ) = 0; + virtual bool Serialize( CUtlBuffer &buf ) = 0; + + // These are methods to help with optimization: + // Once the header is read in, they indicate where to start reading + // other data (measured from file start), and how many bytes to read.... + virtual void LowResFileInfo( int *pStartLocation, int *pSizeInBytes) const = 0; + virtual void ImageFileInfo( int nFrame, int nFace, int nMip, int *pStartLocation, int *pSizeInBytes) const = 0; + virtual int FileSize( int nMipSkipCount = 0 ) const = 0; + + // Attributes... + virtual int Width() const = 0; + virtual int Height() const = 0; + virtual int Depth() const = 0; + virtual int MipCount() const = 0; + + // returns the size of one row of a particular mip level + virtual int RowSizeInBytes( int nMipLevel ) const = 0; + + // returns the size of one face of a particular mip level + virtual int FaceSizeInBytes( int nMipLevel ) const = 0; + + virtual ImageFormat Format() const = 0; + virtual int FaceCount() const = 0; + virtual int FrameCount() const = 0; + virtual int Flags() const = 0; + + virtual float BumpScale() const = 0; + + virtual int LowResWidth() const = 0; + virtual int LowResHeight() const = 0; + virtual ImageFormat LowResFormat() const = 0; + + // NOTE: reflectivity[0] = blue, [1] = greem, [2] = red + virtual const Vector &Reflectivity() const = 0; + + virtual bool IsCubeMap() const = 0; + virtual bool IsNormalMap() const = 0; + virtual bool IsVolumeTexture() const = 0; + + // Computes the dimensions of a particular mip level + virtual void ComputeMipLevelDimensions( int iMipLevel, int *pMipWidth, int *pMipHeight, int *pMipDepth ) const = 0; + + // Computes the size (in bytes) of a single mipmap of a single face of a single frame + virtual int ComputeMipSize( int iMipLevel ) const = 0; + + // Computes the size of a subrect (specified at the top mip level) at a particular lower mip level + virtual void ComputeMipLevelSubRect( Rect_t* pSrcRect, int nMipLevel, Rect_t *pSubRect ) const = 0; + + // Computes the size (in bytes) of a single face of a single frame + // All mip levels starting at the specified mip level are included + virtual int ComputeFaceSize( int iStartingMipLevel = 0 ) const = 0; + + // Computes the total size (in bytes) of all faces, all frames + virtual int ComputeTotalSize() const = 0; + + // Returns the base address of the image data + virtual unsigned char *ImageData() = 0; + + // Returns a pointer to the data associated with a particular frame, face, and mip level + virtual unsigned char *ImageData( int iFrame, int iFace, int iMipLevel ) = 0; + + // Returns a pointer to the data associated with a particular frame, face, mip level, and offset + virtual unsigned char *ImageData( int iFrame, int iFace, int iMipLevel, int x, int y, int z = 0 ) = 0; + + // Returns the base address of the low-res image data + virtual unsigned char *LowResImageData() = 0; + + // Converts the textures image format. Use IMAGE_FORMAT_DEFAULT + // if you want to be able to use various tool functions below + virtual void ConvertImageFormat( ImageFormat fmt, bool bNormalToDUDV ) = 0; + + // NOTE: The following methods only work on textures using the + // IMAGE_FORMAT_DEFAULT! + + // Generate spheremap based on the current cube faces (only works for cubemaps) + // The look dir indicates the direction of the center of the sphere + // NOTE: Only call this *after* cube faces have been correctly + // oriented (using FixCubemapFaceOrientation) + virtual void GenerateSpheremap( LookDir_t lookDir = LOOK_DOWN_Z ) = 0; + + // Generate spheremap based on the current cube faces (only works for cubemaps) + // The look dir indicates the direction of the center of the sphere + // NOTE: Only call this *after* cube faces have been correctly + // oriented (using FixCubemapFaceOrientation) + virtual void GenerateHemisphereMap( unsigned char *pSphereMapBitsRGBA, int targetWidth, + int targetHeight, LookDir_t lookDir, int iFrame ) = 0; + + // Fixes the cubemap faces orientation from our standard to the + // standard the material system needs. + virtual void FixCubemapFaceOrientation( ) = 0; + + // Generates mipmaps from the base mip levels + virtual void GenerateMipmaps() = 0; + + // Put 1/miplevel (1..n) into alpha. + virtual void PutOneOverMipLevelInAlpha() = 0; + + // Computes the reflectivity + virtual void ComputeReflectivity( ) = 0; + + // Computes the alpha flags + virtual void ComputeAlphaFlags() = 0; + + // Generate the low-res image bits + virtual bool ConstructLowResImage() = 0; + + // Gets the texture all internally consistent assuming you've loaded + // mip 0 of all faces of all frames + virtual void PostProcess(bool bGenerateSpheremap, LookDir_t lookDir = LOOK_DOWN_Z, bool bAllowFixCubemapOrientation = true) = 0; + + // Blends adjacent pixels on cubemap borders, since the card doesn't do it. If the texture + // is S3TC compressed, then it has to do it AFTER the texture has been compressed to prevent + // artifacts along the edges. + // + // If bSkybox is true, it assumes the faces are oriented in the way the engine draws the skybox + // (which happens to be different from the way cubemaps have their faces). + virtual void MatchCubeMapBorders( int iStage, ImageFormat finalFormat, bool bSkybox ) = 0; + + // Sets threshhold values for alphatest mipmapping + virtual void SetAlphaTestThreshholds( float flBase, float flHighFreq ) = 0; + +#if defined( _X360 ) + virtual int UpdateOrCreate( const char *pFilename, const char *pPathID = NULL, bool bForce = false ) = 0; + virtual bool UnserializeFromBuffer( CUtlBuffer &buf, bool bBufferIsVolatile, bool bHeaderOnly, bool bPreloadOnly, int nMipSkipCount ) = 0; + virtual int FileSize( bool bPreloadOnly, int nMipSkipCount ) const = 0; + virtual int MappingWidth() const = 0; + virtual int MappingHeight() const = 0; + virtual int MappingDepth() const = 0; + virtual int MipSkipCount() const = 0; + virtual bool IsPreTiled() const = 0; + virtual unsigned char *LowResImageSample() = 0; + virtual void ReleaseImageMemory() = 0; +#endif + + // Sets post-processing flags (settings are copied, pointer passed to distinguish between structure versions) + virtual void SetPostProcessingSettings( VtfProcessingOptions const *pOptions ) = 0; +}; + +//----------------------------------------------------------------------------- +// Class factory +//----------------------------------------------------------------------------- +IVTFTexture *CreateVTFTexture(); +void DestroyVTFTexture( IVTFTexture *pTexture ); + +//----------------------------------------------------------------------------- +// Allows us to only load in the first little bit of the VTF file to get info +// Clients should read this much into a UtlBuffer and then pass it in to +// Unserialize +//----------------------------------------------------------------------------- +int VTFFileHeaderSize( int nMajorVersion = -1, int nMinorVersion = -1 ); + +//----------------------------------------------------------------------------- +// 360 Conversion +//----------------------------------------------------------------------------- +typedef bool (*CompressFunc_t)( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer ); +bool ConvertVTFTo360Format( const char *pDebugName, CUtlBuffer &sourceBuf, CUtlBuffer &targetBuf, CompressFunc_t pCompressFunc ); + +//----------------------------------------------------------------------------- +// 360 Preload +//----------------------------------------------------------------------------- +bool GetVTFPreload360Data( const char *pDebugName, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); + +#include "mathlib/vector.h" + +#endif // VTF_FILE_FORMAT_ONLY + +//----------------------------------------------------------------------------- +// Disk format for VTF files ver. 7.2 and earlier +// +// NOTE: After the header is the low-res image data +// Then follows image data, which is sorted in the following manner +// +// for each mip level (starting with 1x1, and getting larger) +// for each animation frame +// for each face +// store the image data for the face +// +// NOTE: In memory, we store the data in the following manner: +// for each animation frame +// for each face +// for each mip level (starting with the largest, and getting smaller) +// store the image data for the face +// +// This is done because the various image manipulation function we have +// expect this format +//----------------------------------------------------------------------------- +// Disk format for VTF files ver. 7.3 +// +// NOTE: After the header is the array of ResourceEntryInfo structures, +// number of elements in the array is defined by "numResources". +// there are entries for: +// eRsrcLowResImage = low-res image data +// eRsrcSheet = sheet data +// eRsrcImage = image data +// { +// for each mip level (starting with 1x1, and getting larger) +// for each animation frame +// for each face +// store the image data for the face +// +// NOTE: In memory, we store the data in the following manner: +// for each animation frame +// for each face +// for each mip level (starting with the largest, and getting smaller) +// store the image data for the face +// } +// +//----------------------------------------------------------------------------- + + +#include "datamap.h" + +#pragma pack(1) + +// version number for the disk texture cache +#define VTF_MAJOR_VERSION 7 +#define VTF_MINOR_VERSION 4 + +//----------------------------------------------------------------------------- +// !!!!CRITICAL!!!! BEFORE YOU CHANGE THE FORMAT +// +// The structure sizes ARE NOT what they appear, regardless of Pack(1). +// The "VectorAligned" causes invisible padding in the FINAL derived structure. +// +// Each VTF format has been silently plagued by this. +// +// LOOK AT A 7.3 FILE. The 7.3 structure ends at 0x48 as you would expect by +// counting structure bytes. But, the "Infos" start at 0x50! because the PC +// compiler pads, the 360 compiler does NOT. +//----------------------------------------------------------------------------- + +struct VTFFileBaseHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + char fileTypeString[4]; // "VTF" Valve texture file + int version[2]; // version[0].version[1] + int headerSize; +}; + +struct VTFFileHeaderV7_1_t : public VTFFileBaseHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short width; + unsigned short height; + unsigned int flags; + unsigned short numFrames; + unsigned short startFrame; +#if !defined( POSIX ) && !defined( _X360 ) + VectorAligned reflectivity; +#else + // must manually align in order to maintain pack(1) expected layout with existing binaries + char pad1[4]; + Vector reflectivity; + char pad2[4]; +#endif + float bumpScale; + ImageFormat imageFormat; + unsigned char numMipLevels; + ImageFormat lowResImageFormat; + unsigned char lowResImageWidth; + unsigned char lowResImageHeight; +}; + +struct VTFFileHeaderV7_2_t : public VTFFileHeaderV7_1_t +{ + DECLARE_BYTESWAP_DATADESC(); + + unsigned short depth; +}; + +#define BYTE_POS( byteVal, shft ) uint32( uint32(uint8(byteVal)) << uint8(shft * 8) ) +#if !defined( _X360 ) +#define MK_VTF_RSRC_ID(a, b, c) uint32( BYTE_POS(a, 0) | BYTE_POS(b, 1) | BYTE_POS(c, 2) ) +#define MK_VTF_RSRCF(d) BYTE_POS(d, 3) +#else +#define MK_VTF_RSRC_ID(a, b, c) uint32( BYTE_POS(a, 3) | BYTE_POS(b, 2) | BYTE_POS(c, 1) ) +#define MK_VTF_RSRCF(d) BYTE_POS(d, 0) +#endif + +// Special section for stock resources types +enum ResourceEntryType +{ + // Legacy stock resources, readin/writing are handled differently (i.e. they do not have the length tag word!) + VTF_LEGACY_RSRC_LOW_RES_IMAGE = MK_VTF_RSRC_ID( 0x01, 0, 0 ), // Low-res image data + VTF_LEGACY_RSRC_IMAGE = MK_VTF_RSRC_ID( 0x30, 0, 0 ), // Image data + + // New extended resource + VTF_RSRC_SHEET = MK_VTF_RSRC_ID( 0x10, 0, 0 ), // Sheet data +}; + +// Bytes with special meaning when set in a resource type +enum ResourceEntryTypeFlag +{ + RSRCF_HAS_NO_DATA_CHUNK = MK_VTF_RSRCF( 0x02 ), // Resource doesn't have a corresponding data chunk + RSRCF_MASK = MK_VTF_RSRCF( 0xFF ) // Mask for all the flags +}; + +// Header details constants +enum HeaderDetails +{ + MAX_RSRC_DICTIONARY_ENTRIES = 32, // Max number of resources in dictionary + MAX_X360_RSRC_DICTIONARY_ENTRIES = 4, // 360 needs this to be slim, otherwise preload size suffers +}; + +struct ResourceEntryInfo +{ + union + { + unsigned int eType; // Use MK_VTF_??? macros to be endian compliant with the type + unsigned char chTypeBytes[4]; + }; + unsigned int resData; // Resource data or offset from the beginning of the file +}; + +struct VTFFileHeaderV7_3_t : public VTFFileHeaderV7_2_t +{ + DECLARE_BYTESWAP_DATADESC(); + + char pad4[3]; + unsigned int numResources; + +#if defined( _X360 ) || defined( POSIX ) + // must manually align in order to maintain pack(1) expected layout with existing binaries + char pad5[8]; +#endif + + // AFTER THE IMPLICIT PADDING CAUSED BY THE COMPILER.... + // *** followed by *** ResourceEntryInfo resources[0]; + // Array of resource entry infos sorted ascending by type +}; + +struct VTFFileHeader_t : public VTFFileHeaderV7_3_t +{ + DECLARE_BYTESWAP_DATADESC(); +}; + +#define VTF_X360_MAJOR_VERSION 0x0360 +#define VTF_X360_MINOR_VERSION 8 +struct VTFFileHeaderX360_t : public VTFFileBaseHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int flags; + unsigned short width; // actual width of data in file + unsigned short height; // actual height of data in file + unsigned short depth; // actual depth of data in file + unsigned short numFrames; + unsigned short preloadDataSize; // exact size of preload data (may extend into image!) + unsigned char mipSkipCount; // used to resconstruct mapping dimensions + unsigned char numResources; + Vector reflectivity; // Resides on 16 byte boundary! + float bumpScale; + ImageFormat imageFormat; + unsigned char lowResImageSample[4]; + unsigned int compressedSize; + + // *** followed by *** ResourceEntryInfo resources[0]; +}; + +/////////////////////////// +// Resource Extensions // +/////////////////////////// + +// extended texture lod control: +#define VTF_RSRC_TEXTURE_LOD_SETTINGS ( MK_VTF_RSRC_ID( 'L','O','D' ) ) +struct TextureLODControlSettings_t +{ + // What to clamp the dimenstions to, mip-map wise, when at picmip 0. keeps texture from + // exceeding (1< +#pragma warning(pop) +#endif +#undef PostMessage + +#pragma warning( disable: 4800 ) // forcing value to bool 'true' or 'false' (performance warning) + +#endif // WIN32 +#endif // WINLITE_H diff --git a/public/worldsize.h b/public/worldsize.h new file mode 100644 index 0000000..957e17f --- /dev/null +++ b/public/worldsize.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// worldsize.h -- extent of world and resolution/size of coordinate messages used in engine + +#ifndef WORLDSIZE_H +#define WORLDSIZE_H +#pragma once + + +// These definitions must match the coordinate message sizes in coordsize.h + +// Following values should be +16384, -16384, +15/16, -15/16 +// NOTE THAT IF THIS GOES ANY BIGGER THEN DISK NODES/LEAVES CANNOT USE SHORTS TO STORE THE BOUNDS +#define MAX_COORD_INTEGER (16384) +#define MIN_COORD_INTEGER (-MAX_COORD_INTEGER) +#define MAX_COORD_FRACTION (1.0-(1.0/16.0)) +#define MIN_COORD_FRACTION (-1.0+(1.0/16.0)) + +#define MAX_COORD_FLOAT (16384.0f) +#define MIN_COORD_FLOAT (-MAX_COORD_FLOAT) + +// Width of the coord system, which is TOO BIG to send as a client/server coordinate value +#define COORD_EXTENT (2*MAX_COORD_INTEGER) + +// Maximum traceable distance ( assumes cubic world and trace from one corner to opposite ) +// COORD_EXTENT * sqrt(3) +#define MAX_TRACE_LENGTH ( 1.732050807569 * COORD_EXTENT ) + +// This value is the LONGEST possible range (limited by max valid coordinate number, not 2x) +#define MAX_COORD_RANGE (MAX_COORD_INTEGER) + +#define ASSERT_COORD( v ) Assert( (v.x>=MIN_COORD_INTEGER*2) && (v.x<=MAX_COORD_INTEGER*2) && \ + (v.y>=MIN_COORD_INTEGER*2) && (v.y<=MAX_COORD_INTEGER*2) && \ + (v.z>=MIN_COORD_INTEGER*2) && (v.z<=MAX_COORD_INTEGER*2) ); \ + + +#endif // WORLDSIZE_H diff --git a/public/xwvfile.h b/public/xwvfile.h new file mode 100644 index 0000000..c27bad0 --- /dev/null +++ b/public/xwvfile.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef XWVFILE_H +#define XWVFILE_H +#ifdef _WIN32 +#pragma once +#endif + +#pragma pack(1) + +#define XWV_ID (('X'<<24)|('W'<<16)|('V'<<8)|(' '<<0)) +#define XWV_VERSION 4 + +enum xwvSampleRate_t +{ + XWV_RATE_11025 = 0, + XWV_RATE_22050 = 1, + XWV_RATE_44100 = 2, +}; + +enum xwvFormat_t +{ + XWV_FORMAT_PCM = 0, + XWV_FORMAT_XMA = 1, + XWV_FORMAT_ADPCM = 2, +}; + +// generated in big-endian +struct xwvHeader_t +{ + unsigned int id; + unsigned int version; + unsigned int headerSize; // header only + unsigned int staticDataSize; // follows header + unsigned int dataOffset; // start of samples, possibly sector aligned + unsigned int dataSize; // length of samples in bytes + unsigned int numDecodedSamples; // for duration calcs + int loopStart; // -1 = no loop, offset of loop in samples + unsigned short loopBlock; // the xma block where the loop starts + unsigned short numLeadingSamples; // number of leading samples in the loop block to discard + unsigned short numTrailingSamples; // number of trailing samples at the final block to discard + unsigned short vdatSize; // follows seek table + byte format; + byte bitsPerSample; + byte sampleRate; + byte channels; + byte quality; + byte bHasSeekTable; // indicates presence, follows header + byte padding[2]; // created as 0 + + inline unsigned int GetPreloadSize() { return headerSize + staticDataSize; } + + inline int GetBitsPerSample() const { return bitsPerSample; } + + int GetSampleRate() const + { + int rates[] = {11025, 22050, 44100}; + int rate = sampleRate; + return rates[rate]; + } + + inline int GetChannels() const { return channels; } + + void SetSampleRate( int sampleRateIn ) + { + byte rate = ( sampleRateIn == 11025 ) ? XWV_RATE_11025 : ( sampleRateIn==22050 )? XWV_RATE_22050 : XWV_RATE_44100; + sampleRate = rate; + } + + inline void SetChannels( int channelsIn ) { channels = channelsIn; } + + inline int GetSeekTableSize() + { + // seek table is indexed by packets + return bHasSeekTable ? ( dataSize / 2048 ) * sizeof( int ) : 0; + } +}; + +#pragma pack() + +#endif // XWVFILE_H diff --git a/public/xzp.cpp b/public/xzp.cpp new file mode 100644 index 0000000..5ffdeec --- /dev/null +++ b/public/xzp.cpp @@ -0,0 +1,1323 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#endif +#include +#include +#include +#include +#include "tier1/utlbuffer.h" +#include "tier1/strtools.h" +#include "tier2/riff.h" + +#if defined( _WIN32 ) && !defined( _X360 ) +#include +#endif + +#ifdef MAKE_GAMEDATA_TOOL + #include "../public/materialsystem/shader_vcs_version.h" + #include "../public/materialsystem/imaterial.h" + #include "../public/materialsystem/hardwareverts.h" + #include "../public/vtf/vtf.h" +#else + #include "materialsystem/shader_vcs_version.h" + #include "materialsystem/imaterial.h" + #include "materialsystem/hardwareverts.h" +#endif + +#include "xwvfile.h" +#include "xzp.h" + +CByteswap g_xzpSwap; +extern IFileReadBinary *g_pSndIO; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Datadesc blocks for byteswapping: +//----------------------------------------------------------------------------- +BEGIN_BYTESWAP_DATADESC( xZipHeader_t ) + DEFINE_FIELD( Magic, FIELD_INTEGER ), + DEFINE_FIELD( Version, FIELD_INTEGER ), + DEFINE_FIELD( PreloadDirectoryEntries, FIELD_INTEGER ), + DEFINE_FIELD( DirectoryEntries, FIELD_INTEGER ), + DEFINE_FIELD( PreloadBytes, FIELD_INTEGER ), + DEFINE_FIELD( HeaderLength, FIELD_INTEGER ), + DEFINE_FIELD( FilenameEntries, FIELD_INTEGER ), + DEFINE_FIELD( FilenameStringsOffset, FIELD_INTEGER ), + DEFINE_FIELD( FilenameStringsLength, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( xZipDirectoryEntry_t ) + DEFINE_FIELD( FilenameCRC, FIELD_INTEGER ), + DEFINE_FIELD( Length, FIELD_INTEGER ), + DEFINE_FIELD( StoredOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( xZipFilenameEntry_t ) + DEFINE_FIELD( FilenameCRC, FIELD_INTEGER ), + DEFINE_FIELD( FilenameOffset, FIELD_INTEGER ), + DEFINE_FIELD( TimeStamp, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( xZipFooter_t ) + DEFINE_FIELD( Size, FIELD_INTEGER ), + DEFINE_FIELD( Magic, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +CXZip::CXZip() +{ + // Ensure that the header doesn't contain a valid magic yet. + m_Header.Magic = 0; + m_pPreloadedData = NULL; + m_nPreloadStart = 0; + m_pDirectory = NULL; + m_pPreloadDirectory = NULL; + m_nRegular2PreloadEntryMapping = NULL; + + m_bByteSwapped = false; + + m_pFilenames = NULL; + m_hZip = NULL; + + m_pRead = NULL; + m_hUser = 0; + m_nMonitorLevel = 0; +} + +CXZip::CXZip( const char* filename ) +{ + // Ensure that the header doesn't contain a valid magic yet. + m_Header.Magic = 0; + m_nPreloadStart = 0; + m_pPreloadedData = NULL; + m_pDirectory = NULL; + m_pPreloadDirectory = NULL; + m_nRegular2PreloadEntryMapping = NULL; + + m_bByteSwapped = false; + + m_pFilenames = NULL; + m_hZip = NULL; + + m_pRead = NULL; + m_hUser = 0; + m_nMonitorLevel = 0; + + Load( filename ); +} + +CXZip::CXZip( FILE* handle, int offset, int size ) // file handle and offset of the zip file +{ + m_pRead = NULL; + m_hUser = 0; + m_nPreloadStart = 0; + m_pDirectory = NULL; + m_pPreloadDirectory = NULL; + m_nRegular2PreloadEntryMapping = NULL; + + m_bByteSwapped = false; + + m_pFilenames = NULL; + m_pPreloadedData = NULL; + m_nMonitorLevel = 0; + + Load( handle, offset, size ); +} + +CXZip::~CXZip() +{ + Unload(); +} + +bool CXZip::InstallAlternateIO( int (*read)( void* buffer, int offset, int length, int nDestLength, int hUser), int hUser ) +{ + m_pRead = read; + m_hUser = hUser; + return true; +} + + +// Loads an xZip file into memory: +bool CXZip::Load( const char* filename, bool bPreload ) +{ + FILE* hZip = fopen( filename, "rb" ); + fseek(hZip,0,SEEK_END); + int nSize = ftell( hZip ); + return Load( hZip, 0, nSize, bPreload ); +} + +bool CXZip::Load( FILE* handle, int nOffset, int nSize, bool bPreload ) // Load a pack file into this instance. Returns true on success. +{ + Unload(); + + m_bByteSwapped = false; + + m_hZip = handle; + m_nOffset = nOffset; + m_nSize = nSize; + + // Hacky, clean up: + if( m_hZip && !m_pRead ) + { + InstallAlternateIO( defaultRead, (int)m_hZip ); + } + + if( m_hZip == NULL && m_pRead == NULL ) + { + return false; + } + + // Read the header: + m_pRead( &m_Header, 0, -1, sizeof(m_Header), m_hUser ); + + // Validate the Magic number and at the same time determine if I am reading a regular or swappped xZip file: + switch( m_Swap.SourceIsNativeEndian( m_Header.Magic, xZipHeader_t::MAGIC ) ) + { + // Does the magic match exactly? + case 1: + m_Swap.ActivateByteSwapping( false ); + m_bByteSwapped = false; + break; + + // Does the magic match, but is swapped? + case 0: + m_bByteSwapped = true; + m_Swap.ActivateByteSwapping( true ); // We must be reading the opposite endianness. + m_Swap.SwapFieldsToTargetEndian( &m_Header ); + break; + + default: + assert( 0 ); + // Fail gently in release: + + // The magic doesn't match in any respect: + case -1: + { + printf("Invalid xZip file\n"); + + if( m_hZip ) + { + fclose( m_hZip ); + m_hZip = NULL; + } + return false; + } + } + + // Validate the archive version: + if( m_Header.Version != xZipHeader_t::VERSION ) + { + // Backward compatable support for version 1 + Msg("Incorrect xZip version found %u - expected %u\n", m_Header.Version, xZipHeader_t::VERSION ); + if( m_hZip ) + { + fclose( m_hZip ); + m_hZip = NULL; + } + + m_Header.Magic = xZipHeader_t::FREE; + return false; + } + + // Read the directory: + { + MEM_ALLOC_CREDIT(); + + m_pDirectory = (xZipDirectoryEntry_t*)malloc( sizeof(xZipDirectoryEntry_t) * m_Header.DirectoryEntries ); + m_pRead( m_pDirectory, m_Header.HeaderLength, -1, sizeof( xZipDirectoryEntry_t ) * m_Header.DirectoryEntries, m_hUser ); + + // Swap the directory entries if nessecary + if( m_bByteSwapped ) + { + for( unsigned nDirectoryEntry = 0; nDirectoryEntry < m_Header.DirectoryEntries; nDirectoryEntry++ ) + { + m_Swap.SwapFieldsToTargetEndian( &( m_pDirectory[nDirectoryEntry] ) ); + } + } + + + m_nPreloadStart = m_Header.HeaderLength + ( sizeof( xZipDirectoryEntry_t ) * m_Header.DirectoryEntries ); + } + + // Preload the preload chunk if desired: + if( bPreload ) + { + PreloadData(); + } + + return true; +} + +void CXZip::Unload() +{ + DiscardPreloadedData(); + + // Dump the directory: + if( m_pDirectory ) + { + free( m_pDirectory ); + m_pDirectory = NULL; + } + + if( m_pFilenames ) + { + free( m_pFilenames ); + m_pFilenames = NULL; + } + + // Invalidate the header: + m_Header.Magic = 0; + + if( m_hZip ) + { + fclose( m_hZip ); + m_hZip = NULL; + } + +} + +//----------------------------------------------------------------------------- +// CXZip::PreloadData +// +// Loads the preloaded data if it isn't already. +//----------------------------------------------------------------------------- + +void CXZip::PreloadData() +{ + Assert( IsValid() ); + + // Ensure it isn't already preloaded + if( m_pPreloadedData ) + return; + + // If I don't have a preloaded section, ignore the request. + if( !m_Header.PreloadBytes || !m_Header.PreloadDirectoryEntries ) + return; + + // Allocate and read the data block in: +#ifndef _X360 + MEM_ALLOC_CREDIT_( "xZip" ); + m_pPreloadedData = malloc( m_Header.PreloadBytes ); + + // Just drop out if allocation fails; + if ( !m_pPreloadedData ) + return; + + m_pRead( m_pPreloadedData, m_nPreloadStart, -1, m_Header.PreloadBytes, m_hUser ); +#else + int nAlignedStart = AlignValue( ( m_nPreloadStart - XBOX_HDD_SECTORSIZE ) + 1, XBOX_HDD_SECTORSIZE ); + int nBytesToRead = AlignValue( ( m_nPreloadStart - nAlignedStart ) + m_Header.PreloadBytes, XBOX_HDD_SECTORSIZE ); + int nBytesBuffer = AlignValue( nBytesToRead, XBOX_HDD_SECTORSIZE ); + byte *pReadData = (byte *)malloc( nBytesBuffer ); + + // Just drop out if allocation fails; + if ( !pReadData ) + return; + + MEM_ALLOC_CREDIT_( "xZip" ); + m_pRead( pReadData, nAlignedStart, nBytesBuffer,nBytesToRead, m_hUser ); + m_pPreloadedData = pReadData + ( m_nPreloadStart - nAlignedStart ); +#endif + + // Set up the preload directory: + m_pPreloadDirectory = (xZipDirectoryEntry_t*)m_pPreloadedData; + + // Swap the preload directory: + if ( m_bByteSwapped ) + { + for ( unsigned nDirectoryEntry = 0; nDirectoryEntry < m_Header.PreloadDirectoryEntries; nDirectoryEntry++ ) + { + m_Swap.SwapFieldsToTargetEndian( &( m_pPreloadDirectory[nDirectoryEntry] ) ); + } + } + + // Set up the regular 2 preload mapping section: + m_nRegular2PreloadEntryMapping = (unsigned short*)(((unsigned char*)m_pPreloadDirectory) + ( sizeof(xZipDirectoryEntry_t) * m_Header.PreloadDirectoryEntries )); + + // Swap the regular to preload mapping + if ( m_bByteSwapped ) + { + m_Swap.SwapBufferToTargetEndian( (short *)m_nRegular2PreloadEntryMapping, (short *)m_nRegular2PreloadEntryMapping, m_Header.DirectoryEntries ); + } + +} + +//----------------------------------------------------------------------------- +// CXZip::DiscardPreloadedData +// +// frees the preloaded data cache if it's present. +//----------------------------------------------------------------------------- + +void CXZip::DiscardPreloadedData() +{ + if ( m_pPreloadedData ) + { +#ifndef _X360 + free( m_pPreloadedData ); +#else + int nAlignedStart = AlignValue( ( m_nPreloadStart - XBOX_HDD_SECTORSIZE ) + 1, XBOX_HDD_SECTORSIZE ); + byte *pReadData = (byte *)m_pPreloadedData - ( m_nPreloadStart - nAlignedStart ); + free( pReadData ); +#endif + m_pPreloadedData = NULL; + m_pPreloadDirectory = NULL; + m_nRegular2PreloadEntryMapping = NULL; + } +} + +int CXZip::defaultRead( void* buffer, int offset, int destLength, int length, int hUser) +{ + fseek( (FILE*)hUser, offset, SEEK_SET ); + return fread( buffer, 1, length, (FILE*)hUser ); +} + +char* CXZip::GetEntryFileName( unsigned CRC, char* pDefault ) +{ + Assert( IsValid() ); + + if( IsRetail() ) + { + return pDefault; + } + else + { + + // Make sure I have a filename section: + if( m_Header.FilenameStringsOffset == 0 || m_Header.FilenameEntries == 0 || CRC == 0 ) + { + return pDefault; + } + + // If the filename chunk isn't here, load it up: + if( !m_pFilenames ) + { + MEM_ALLOC_CREDIT_("xZip"); + m_pFilenames = (xZipFilenameEntry_t*)malloc( m_Header.FilenameStringsLength ); + m_pRead( m_pFilenames, m_Header.FilenameStringsOffset, -1, m_Header.FilenameStringsLength, m_hUser ); + + // TODO: Swap! + for( unsigned int i=0; i< m_Header.FilenameEntries;i++ ) + { + m_Swap.SwapFieldsToTargetEndian(&m_pFilenames[i]); + } + } + + // Find this entry in the preload directory + xZipFilenameEntry_t entry; + entry.FilenameCRC = CRC; + + xZipFilenameEntry_t* found = (xZipFilenameEntry_t*)bsearch( &entry, m_pFilenames, m_Header.FilenameEntries, sizeof(xZipFilenameEntry_t), xZipFilenameEntry_t::xZipFilenameEntryCompare ); + + if( !found ) + return pDefault; + + return (((char*)m_pFilenames) + found->FilenameOffset) - m_Header.FilenameStringsOffset; + } +} + +// Sanity checks that the zip file is ready and readable: +bool CXZip::IsValid() +{ + if( m_Header.Magic != xZipHeader_t::MAGIC ) + return false; + + if( m_Header.Version > xZipHeader_t::VERSION ) + return false; + + if( !m_pDirectory ) + return false; + + return true; +} + +void CXZip::WarningDir() +{ + Assert( IsValid()); + + for( unsigned i = 0; i< m_Header.DirectoryEntries; i++ ) + { + Msg( GetEntryFileName( m_pDirectory[i].FilenameCRC ) ); + } +} + + +int CXZip::ReadIndex( int nEntryIndex, int nFileOffset, int nDestBytes, int nLength, void* pBuffer ) +{ + Assert( IsValid() ); + + if( nLength <=0 || nEntryIndex < 0 ) + return 0; + + // HACK HACK HACK - convert the pack file index to a local file index (ie, assuming the full file index is being passed in) + nFileOffset -= m_pDirectory[nEntryIndex].StoredOffset; + // HACK HACK HACK + + // If I've got my preload section loaded, first check there: + xZipDirectoryEntry_t* pPreloadEntry = GetPreloadEntry(nEntryIndex); + + if( pPreloadEntry ) + { + Assert( pPreloadEntry->FilenameCRC == m_pDirectory[nEntryIndex].FilenameCRC ); + + if( nFileOffset + nLength <= (int)pPreloadEntry->Length ) + { + if( m_nMonitorLevel >= 2 ) + { + char* filename = GetEntryFileName( m_pDirectory[nEntryIndex].FilenameCRC, "(!!! unknown !!!)" ); + + Msg("PACK(preload) %s: length:%i offset:%i",filename,nLength, nFileOffset); + + } + + memcpy( pBuffer, (char*)m_pPreloadedData + pPreloadEntry->StoredOffset + nFileOffset - m_nPreloadStart, nLength ); + return nLength; + } + } + + // Offset int the zip to start the read: + int ZipOffset = m_pDirectory[nEntryIndex].StoredOffset + nFileOffset; + int nBytesRead = m_pRead( pBuffer, ZipOffset, nDestBytes, nLength, m_hUser); + + if( m_nMonitorLevel ) + { + char* filename = GetEntryFileName( m_pDirectory[nEntryIndex].FilenameCRC, "(!!! unknown !!!)" ); + + unsigned preload = 0; + if( m_pPreloadedData && m_nRegular2PreloadEntryMapping[nEntryIndex] != 0xFFFF ) + { + // Find this entry in the preload directory + xZipDirectoryEntry_t* entry = &(m_pPreloadDirectory[m_nRegular2PreloadEntryMapping[nEntryIndex]]); + Assert(entry->FilenameCRC == m_pDirectory[nEntryIndex].FilenameCRC); + + preload = entry->Length; + } + + Msg("PACK %s: length:%i offset:%i (preload bytes:%i)",filename,nLength, nFileOffset, preload); + } + + return nBytesRead; +} + +bool CXZip::GetSimpleFileOffsetLength( const char* FileName, int& nBaseIndex, int &nFileOffset, int &nLength ) +{ + Assert( IsValid() ); + + xZipDirectoryEntry_t entry; + entry.FilenameCRC = xZipCRCFilename( FileName ); + + xZipDirectoryEntry_t* found = (xZipDirectoryEntry_t*)bsearch( &entry, m_pDirectory, m_Header.DirectoryEntries, sizeof(xZipDirectoryEntry_t), xZipDirectoryEntry_t::xZipDirectoryEntryFindCompare ); + + if( found == NULL ) + return false; + + nFileOffset = found[0].StoredOffset; + nLength = found[0].Length; + nBaseIndex = (((int)((char*)found - (char*)m_pDirectory))/sizeof(xZipDirectoryEntry_t)); + + return true; +} + +bool CXZip::ExtractFile( const char* FileName ) +{ + return false; +} + +// Compares to xZipDirectoryEntries. +// +// Sorts in the following order: +// FilenameCRC +// FileOffset +// Length +// StoredOffset +// +// The sort function may look overly complex, but it is actually useful for locating different pieces of +// the same file in a meaningful order. +// +int __cdecl xZipDirectoryEntry_t::xZipDirectoryEntrySortCompare( const void* left, const void* right ) +{ + xZipDirectoryEntry_t *l = (xZipDirectoryEntry_t*)left, + *r = (xZipDirectoryEntry_t*)right; + + if( l->FilenameCRC < r->FilenameCRC ) + { + return -1; + } + + else if( l->FilenameCRC > r->FilenameCRC ) + { + return 1; + } + + // else l->FileOffset == r->FileOffset + if( l->Length < r->Length ) + { + return -1; + } + else if( l->Length > r->Length ) + { + return 1; + } + + // else l->Length == r->Length + if( l->StoredOffset < r->StoredOffset ) + { + return -1; + } + else if( l->StoredOffset > r->StoredOffset ) + { + return 1; + } + + // else everything is identical: + return 0; + +} + +// Find an entry with matching CRC only +int __cdecl xZipDirectoryEntry_t::xZipDirectoryEntryFindCompare( const void* left, const void* right ) +{ + xZipDirectoryEntry_t *l = (xZipDirectoryEntry_t*)left, + *r = (xZipDirectoryEntry_t*)right; + + if( l->FilenameCRC < r->FilenameCRC ) + { + return -1; + } + + else if( l->FilenameCRC > r->FilenameCRC ) + { + return 1; + } + + return 0; + +} + +int __cdecl xZipFilenameEntry_t::xZipFilenameEntryCompare( const void* left, const void* right ) +{ + xZipFilenameEntry_t *l = (xZipFilenameEntry_t*)left, + *r = (xZipFilenameEntry_t*)right; + + if( l->FilenameCRC < r->FilenameCRC ) + { + return -1; + } + + else if( l->FilenameCRC > r->FilenameCRC ) + { + return 1; + } + + return 0; + +} + + +// CRC's an individual xZip filename: +unsigned xZipCRCFilename( const char* filename ) +{ + unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's + + for( ; *filename ; filename++ ) + { + char c = *filename; + + // Fix slashes + if( c == '/' ) + c = '\\'; + else + c = (char)tolower(c); + + hash = hash * 33 + c; + } + + return hash; +} + +#if defined( MAKE_GAMEDATA_TOOL ) + +// ------------ +xZipHeader_t Header; +xZipDirectoryEntry_t *pDirectoryEntries = NULL; +xZipDirectoryEntry_t *pPreloadDirectoryEntries = NULL; +xZipFilenameEntry_t *pFilenameEntries = NULL; +char *pFilenameData = NULL; +unsigned nFilenameDataLength = 0; + +unsigned InputFileBytes = 0; + +char* CleanFilename( char* filename ) +{ + // Trim leading white space: + while( isspace(*filename) ) + filename++; + + // Trim trailing white space: + while( isspace( filename[strlen(filename)-1] ) ) + { + filename[strlen(filename)-1] = '\0'; + } + + return filename; +} + + +bool CopyFileBytes( FILE* hDestination, FILE* hSource, unsigned nBytes ) +{ + char buffer[16384]; + + while( nBytes > 0 ) + { + int nBytesRead = fread( buffer, 1, nBytes > sizeof(buffer) ? sizeof(buffer) : nBytes, hSource ); + fwrite(buffer, 1, nBytesRead, hDestination ); + nBytes -= nBytesRead; + } + + return true; +} + +bool WriteFileBytes( FILE* hDestination, CUtlBuffer &source, unsigned nBytes ) +{ + unsigned int nBytesWritten = fwrite(source.Base(), 1, nBytes, hDestination ); + return (nBytesWritten == nBytes); +} + +void PadFileBytes(FILE* hFile, int nPreloadPadding ) +{ + if( nPreloadPadding < 0 || nPreloadPadding >= 512) + { + puts("Invalid padding"); + return; + } + + char padding[512]; + memset(padding,0,nPreloadPadding); + fwrite(padding,1,nPreloadPadding,hFile); +} + +void AddFilename( const char* filename ) +{ + unsigned CRCfilename = xZipCRCFilename( filename ); + + // If we already have this filename don't add it again: + for( int i = 0; i < (int)Header.FilenameEntries; i++ ) + { + if( pFilenameEntries[i].FilenameCRC == CRCfilename ) + { + return; + } + } + + Header.FilenameEntries++; + + // Add the file to the file string table: + pFilenameEntries = (xZipFilenameEntry_t*)realloc( pFilenameEntries, sizeof(xZipFilenameEntry_t) * Header.FilenameEntries ); + + int filenameLength = (int)strlen(filename) + 1; + pFilenameEntries[Header.FilenameEntries-1].FilenameCRC = CRCfilename; + pFilenameEntries[Header.FilenameEntries-1].FilenameOffset = nFilenameDataLength; + + // Grab the timestamp for the file: + struct stat buf; + if( stat( filename, &buf ) != -1 ) + { + pFilenameEntries[Header.FilenameEntries - 1].TimeStamp = buf.st_mtime; + } + else + { + pFilenameEntries[Header.FilenameEntries - 1].TimeStamp = 0; + } + + nFilenameDataLength += filenameLength; + pFilenameData = (char*)realloc(pFilenameData, nFilenameDataLength); + memcpy(pFilenameData + nFilenameDataLength - filenameLength, filename, filenameLength); +} + +FILE* hTempFilePreload; +FILE* hTempFileData; +FILE* hOutputFile; + +bool xZipAddFile( const char* filename, CUtlBuffer &fileBuff, bool bPrecacheEntireFile, bool bProcessPrecacheHeader, bool bProcessPrecacheHeaderOnly ) +{ + unsigned int fileSize = fileBuff.TellMaxPut(); + + // Track total input bytes for stats reasons + InputFileBytes += fileSize; + + unsigned customPreloadSize = 0; + + if( bPrecacheEntireFile ) + { + customPreloadSize = fileSize; + } + else if( bProcessPrecacheHeader ) + { + customPreloadSize = xZipComputeCustomPreloads( filename ); + } + else if( bProcessPrecacheHeaderOnly ) + { + customPreloadSize = xZipComputeCustomPreloads( filename ); + fileSize = vmin( fileSize, customPreloadSize ); + } + + unsigned CRC = xZipCRCFilename( filename ); + + // Does this file have a split header? + if( customPreloadSize > 0 ) + { + // Initialize the entry header: + xZipDirectoryEntry_t entry; + memset( &entry, 0, sizeof( entry ) ); + + entry.FilenameCRC = CRC; + entry.Length = customPreloadSize; + entry.StoredOffset = ftell(hTempFilePreload); + + // Add the directory entry to the preload table: + Header.PreloadDirectoryEntries++; + pPreloadDirectoryEntries = (xZipDirectoryEntry_t*)realloc( pPreloadDirectoryEntries, sizeof( xZipDirectoryEntry_t ) * Header.PreloadDirectoryEntries ); + memcpy( pPreloadDirectoryEntries + Header.PreloadDirectoryEntries - 1, &entry, sizeof( entry ) ); + + // Concatenate the data in the preload file: + fileBuff.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + WriteFileBytes( hTempFilePreload, fileBuff, entry.Length ); + fileBuff.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + + + // Add the filename entry: + AddFilename( filename ); + + // Spew it: + printf("+Preload: \"%s\": Length:%u\n", filename, entry.Length ); + } + + // Copy the file to the regular data region: + xZipDirectoryEntry_t entry; + memset(&entry,0,sizeof(entry)); + entry.FilenameCRC = CRC; + entry.Length = fileSize; + entry.StoredOffset = ftell(hTempFileData); + + // Add the directory entry to the table: + Header.DirectoryEntries++; + pDirectoryEntries = (xZipDirectoryEntry_t*)realloc( pDirectoryEntries, sizeof( xZipDirectoryEntry_t ) * Header.DirectoryEntries ); + memcpy( pDirectoryEntries + Header.DirectoryEntries - 1, &entry, sizeof( entry ) ); + + WriteFileBytes( hTempFileData, fileBuff, entry.Length ); + + // Align the data region to a 512 byte boundry: (has to be on last entry as well to ensure enough space to perform the final read, + // and initial alignment is taken careof by assembexzip) + int nPadding = ( XBOX_HDD_SECTORSIZE - ( ftell( hTempFileData ) % XBOX_HDD_SECTORSIZE) ) % XBOX_HDD_SECTORSIZE; + + PadFileBytes( hTempFileData, nPadding ); + + // Add the file to the file string table: + AddFilename( filename ); + + // Print a summary + printf("+File: \"%s\": Length:%u Padding:%i\n", filename, entry.Length, nPadding ); + + return true; +} + +bool xZipAddFile( const char* zipname, bool bPrecacheEntireFile, bool bProcessPrecacheHeader, bool bProcessPrecacheHeaderOnly ) +{ + // Clean up the filename: + char buffer[MAX_PATH]; + strcpy(buffer, zipname); + + // Fix slashes and convert it to lower case: + char *filename; + for( filename = buffer; *filename; filename++ ) + { + if( *filename == '/' ) + *filename = '\\'; + else + { + *filename = (char)tolower(*filename); + } + } + + // Skip leading white space: + for( filename = buffer; isspace(*filename); filename++ ) + ; + + // Obliterate trailing white space: + for(;;) + { + int len = (int)strlen( filename ); + if( len <= 0 ) + { + printf("!!!! BAD FILENAME: \"%s\"\n", filename ); + return false; + } + + if( isspace( filename[len-1] ) ) + filename[len-1]='\0'; + else + break; + } + + // Ensure we don't already have this file: + unsigned CRC = xZipCRCFilename( filename ); + + for( unsigned i=0; i < Header.DirectoryEntries; i++ ) + { + if( pDirectoryEntries[i].FilenameCRC == CRC ) + { + printf("!!!! NOT ADDING DUPLICATE FILENAME: \"%s\"\n", filename ); + return false; + } + } + + // Attempt to open the file: + FILE* hFile = fopen( filename, "rb" ); + if( !hFile ) + { + printf("!!!! FAILED TO OPEN FILE: \"%s\"\n", filename ); + return false; + } + + // Get the length of the file: + fseek(hFile,0,SEEK_END); + unsigned fileSize = ftell(hFile); + fseek(hFile,0,SEEK_SET); + + CUtlBuffer fileBuff; + fileBuff.EnsureCapacity( fileSize ); + fread( fileBuff.Base(), fileSize, 1, hFile ); + fclose( hFile ); + + fileBuff.SeekPut( CUtlBuffer::SEEK_HEAD, fileSize ); + + return xZipAddFile( zipname, fileBuff, bPrecacheEntireFile, bProcessPrecacheHeader, bProcessPrecacheHeaderOnly ); +} + +int xZipBegin( const char* fileNameXzip ) +{ + // Create and initialize the header: + memset( &Header, 0, sizeof(Header) ); // Zero out the header: + Header.Magic = xZipHeader_t::MAGIC; + Header.Version = xZipHeader_t::VERSION; + Header.HeaderLength = sizeof(Header); + + // Open the output file: + hOutputFile = fopen(fileNameXzip,"wb+"); + if( !hOutputFile ) + { + printf("Failed to open \"%s\" for writing.\n", fileNameXzip); + exit( EXIT_FAILURE); + } + + // Create a temporary file for storing the preloaded data: + hTempFilePreload = tmpfile(); + if( !hTempFilePreload ) + { + printf( "Error: failed to create temporary file\n" ); + return EXIT_FAILURE; + } + + // Create a temporary file for storing the non preloaded data + hTempFileData = tmpfile(); + if( !hTempFileData ) + { + printf( "Error: failed to create temporary file\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +bool xZipEnd() +{ + int nPreloadDirectorySize = sizeof(xZipDirectoryEntry_t)*Header.PreloadDirectoryEntries; + int nRegular2PreloadSize = sizeof(unsigned short) * Header.DirectoryEntries; + + // Compute the size of the preloaded section: + if( Header.PreloadDirectoryEntries ) + { + fseek( hTempFilePreload, 0, SEEK_END ); + Header.PreloadBytes = ftell(hTempFilePreload) + nPreloadDirectorySize + nRegular2PreloadSize; // Raw# of bytes to preload + fseek( hTempFilePreload, 0, SEEK_SET ); + } + else + { + Header.PreloadBytes = 0; + } + + // Number of bytes preceeding the preloaded section: + int nPreloadOffset = sizeof( Header ) + ( sizeof( xZipDirectoryEntry_t ) * Header.DirectoryEntries ); + + // Number of bytes to pad between the end of the preload section and the start of the data section: + int nPadding = ( 512 - ( ( nPreloadOffset + Header.PreloadBytes ) % 512) ) %512; // Number of alignment bytes after the preload section + + // Offset past the preload section: + int nDataOffset = nPreloadOffset + Header.PreloadBytes + nPadding; + + // Write out the header: (will need to be rewritten at the end as well) - note: not even bothering to byteswap at this point + fwrite(&Header,sizeof(Header),1,hOutputFile); + + + // Fixup each of the directory entries to make them relative to the beginning of the file. + for( unsigned i=0; i< Header.DirectoryEntries;i++ ) + { + xZipDirectoryEntry_t* pDir = &(pDirectoryEntries[i]); + + // Adjust files in the regular data area: + pDir->StoredOffset = nDataOffset + pDir->StoredOffset; + } + + // Sort and write the directory: + printf("Sorting and writing %i directory entries...\n",Header.DirectoryEntries); + qsort(pDirectoryEntries,Header.DirectoryEntries,sizeof(xZipDirectoryEntry_t),&xZipDirectoryEntry_t::xZipDirectoryEntrySortCompare); + + // Swap the directory entries: + for( unsigned i=0; i < Header.DirectoryEntries; i++ ) + { + g_xzpSwap.SwapFieldsToTargetEndian(&pDirectoryEntries[i]); + } + + fwrite(pDirectoryEntries,Header.DirectoryEntries*sizeof(xZipDirectoryEntry_t),1, hOutputFile); + + // Swap the directory back for later use: + for( unsigned i=0; i < Header.DirectoryEntries; i++ ) + { + g_xzpSwap.SwapFieldsToTargetEndian(&pDirectoryEntries[i]); + } + + // Copy the preload section: + if( Header.PreloadBytes > 0 ) + { + printf("Generating the preload section...(%u)\n", Header.PreloadBytes); + + + // Fixup each of the directory entries to make them relative to the beginning of the file. + for( unsigned i=0; i< Header.PreloadDirectoryEntries;i++ ) + { + xZipDirectoryEntry_t* pDir = &(pPreloadDirectoryEntries[i]); + + // Shift preload data down by preload bytes (and skipping over the directory): + pDir->StoredOffset += nPreloadOffset + nPreloadDirectorySize + nRegular2PreloadSize; + } + + printf("Sorting %u preload directory entries...\n",Header.PreloadDirectoryEntries); + qsort(pPreloadDirectoryEntries,Header.PreloadDirectoryEntries,sizeof(xZipDirectoryEntry_t),&xZipDirectoryEntry_t::xZipDirectoryEntrySortCompare); + + printf("Building regular to preload mapping table for %u entries...\n", Header.DirectoryEntries ); + unsigned short* Regular2Preload = (unsigned short*)malloc( nRegular2PreloadSize ); + for( unsigned i = 0; i < Header.DirectoryEntries; i++ ) + { + unsigned short j; + for( j = 0; j < Header.PreloadDirectoryEntries; j++ ) + { + if( pDirectoryEntries[i].FilenameCRC == pPreloadDirectoryEntries[j].FilenameCRC ) + break; + } + + // If I couldn't find it mark it as non-existant: + if( j == Header.PreloadDirectoryEntries ) + j = 0xFFFF; + + Regular2Preload[i] = j; + } + + printf("Writing preloaded directory entreis...\n" ); + + // Swap the preload directory entries: + for( unsigned i=0; i < Header.PreloadDirectoryEntries; i++ ) + { + g_xzpSwap.SwapFieldsToTargetEndian(&pPreloadDirectoryEntries[i]); + } + + fwrite( pPreloadDirectoryEntries, Header.PreloadDirectoryEntries*sizeof(xZipDirectoryEntry_t),1, hOutputFile ); + + // Swap them back: + for( unsigned i=0; i < Header.PreloadDirectoryEntries; i++ ) + { + g_xzpSwap.SwapFieldsToTargetEndian(&pPreloadDirectoryEntries[i]); + } + + printf("Writing regular to preload mapping (%u bytes)...\n", sizeof(unsigned short)*Header.DirectoryEntries ); + + // Swap regular to preload mapping: + g_xzpSwap.SwapBufferToTargetEndian((short*)Regular2Preload, (short*)Regular2Preload, nRegular2PreloadSize / sizeof(short) ); + + fwrite( Regular2Preload, nRegular2PreloadSize,1,hOutputFile ); + + // Swap it back + g_xzpSwap.SwapBufferToTargetEndian((short*)Regular2Preload, (short*)Regular2Preload, nRegular2PreloadSize / sizeof(short) ); + + printf("Copying %u Preloadable Bytes...\n", Header.PreloadBytes - nPreloadDirectorySize - nRegular2PreloadSize ); + fseek(hTempFilePreload,0,SEEK_SET); + CopyFileBytes(hOutputFile, hTempFilePreload, Header.PreloadBytes - nPreloadDirectorySize - nRegular2PreloadSize ); + } + + // Align the data section following the preload section: + if( nPadding ) + { + printf("Aligning Data Section Start by %u bytes...\n", nPadding ); + PadFileBytes(hOutputFile, nPadding ); + } + + // Copy the data section: + fseek(hTempFileData, 0, SEEK_END ); + unsigned length = ftell( hTempFileData ); + fseek(hTempFileData, 0, SEEK_SET ); + printf("Copying %u Bytes...\n",length); + + CopyFileBytes(hOutputFile, hTempFileData, length); + + // Write out the filename data if present: + if( nFilenameDataLength && Header.FilenameEntries ) + { + Header.FilenameStringsOffset = ftell(hOutputFile); + Header.FilenameStringsLength = (Header.FilenameEntries*sizeof(xZipFilenameEntry_t)) + nFilenameDataLength; + + // Adjust the offset in each of the filename offsets to absolute position in the file. + for( unsigned i=0;i(&pFilenameEntries[i]); + } + + fwrite(pFilenameEntries,1,Header.FilenameEntries*sizeof(xZipFilenameEntry_t),hOutputFile); + + // Swap them back: + for( unsigned int i = 0; i < Header.FilenameEntries; i++ ) + { + g_xzpSwap.SwapFieldsToTargetEndian(&pFilenameEntries[i]); + } + + printf("Writing %u bytes of filename data...\n",nFilenameDataLength); + fwrite(pFilenameData,1,nFilenameDataLength,hOutputFile); + } + + // Compute the total file size, including the size of the footer: + unsigned OutputFileBytes = ftell(hOutputFile) + sizeof(xZipFooter_t); + + // Write the footer: (block used to keep possibly swapped footer from being used later) + { + xZipFooter_t footer; + footer.Magic = xZipFooter_t::MAGIC; + footer.Size = OutputFileBytes; + + g_xzpSwap.SwapFieldsToTargetEndian( &footer ); // Swap the footer + fwrite( &footer, 1, sizeof(footer), hOutputFile ); + } + + // Seek back and rewrite the header (filename data changes it for example) + fseek(hOutputFile,0,SEEK_SET); + g_xzpSwap.SwapFieldsToTargetEndian( &Header ); // Swap it to write out: + fwrite(&Header,1,sizeof(Header),hOutputFile); + g_xzpSwap.SwapFieldsToTargetEndian( &Header ); // But then swap it back so we can use it in memory + + // Shut down + fclose(hOutputFile); + + // Print the summary + printf("\n\nSummary: Input:%u, XZip:%u, Directory Entries:%u (%u preloaded), Preloaded Bytes:%u\n\n",InputFileBytes,OutputFileBytes,Header.DirectoryEntries, Header.PreloadDirectoryEntries, Header.PreloadBytes); + + // Shut down: + fclose(hTempFileData); + fclose(hTempFilePreload); + + return true; +} + +#define PADD_ID MAKEID('P','A','D','D') + +//----------------------------------------------------------------------------- +// xZipComputeWAVPreload +// +// Returns the number of bytes from a xbox compliant WAV file that should go into +// the preload section: +//----------------------------------------------------------------------------- +unsigned xZipComputeWAVPreload( char *pFileName ) +{ + InFileRIFF riff( pFileName, *g_pSndIO ); + if ( riff.RIFFName() != RIFF_WAVE ) + { + return 0; + } + + IterateRIFF walk( riff, riff.RIFFSize() ); + + while ( walk.ChunkAvailable() ) + { + // xbox compliant wavs have a single PADD chunk + if ( walk.ChunkName() == PADD_ID ) + { + // want to preload data up through PADD chunk header + // and not the actual pad bytes + return walk.ChunkFilePosition() + 2*sizeof( int ); + } + walk.ChunkNext(); + } + + return 0; +} + + +//----------------------------------------------------------------------------- +// xZipComputeXWVPreload +// +// Returns the number of bytes from a XWV file that should go into the preload +// section: +//----------------------------------------------------------------------------- +unsigned xZipComputeXWVPreload( const char* filename ) +{ + FILE* hFile = fopen( filename, "rb" ); + if ( !hFile ) + { + printf( "Failed to open xwv file: %s\n", filename ); + return 0; + } + + // Read and validate the XWV header: + xwvHeader_t header; + memset( &header, 0, sizeof(header) ); + fread( &header, 1, sizeof(header), hFile ); + fclose( hFile ); + + if ( header.id != XWV_ID || header.headerSize != sizeof(header) ) + return 0; + + return header.GetPreloadSize(); +} + +unsigned xZipComputeXTFPreload( const char* filename ) +{ +#if 0 // X360TBD: Not using XTF anymore + FILE* hFile = fopen( filename, "rb" ); + if ( !hFile ) + { + printf("Failed to open file: %s\n", filename); + return 0; + } + + XTFFileHeader_t header; + memset( &header,0, sizeof( header ) ); + fread( &header,1,sizeof(header),hFile); + + fclose(hFile); + + if ( !strncmp( header.fileTypeString, "XTF", 4 ) ) + return header.preloadDataSize; +#endif + return 0; +} + +// TODO: ONLY store them in the preload section: +unsigned xZipComputeVMTPreload( const char* filename ) +{ + // Store VMT's entirely + if ( !strstr(filename,".vmt") ) + return 0; + + FILE* hFile = fopen( filename, "rb" ); + if ( !hFile ) + { + printf("Failed to open file: %s\n", filename); + return 0; + } + + fseek( hFile, 0, SEEK_END ); + unsigned offset = ftell( hFile ); + fclose( hFile ); + return offset; +} + +// TODO: ONLY store them in the preload section: +unsigned xZipComputeVHVPreload( const char* filename ) +{ + // Store VMT's entirely + if ( !strstr(filename,".vhv") ) + return 0; + + FILE* hFile = fopen( filename, "rb" ); + if ( !hFile ) + { + printf("Failed to open file: %s\n", filename); + return 0; + } + + fclose( hFile ); + + // Just load the header: + return sizeof(HardwareVerts::FileHeader_t); +} + +unsigned xZipComputeXCSPreload( const char* filename ) +{ + if( !strstr(filename,".vcs") ) + return 0; + + FILE* hFile = fopen( filename, "rb" ); + if ( !hFile ) + { + printf("Failed to open file: %s\n", filename); + return 0; + } + + XShaderHeader_t header; + fread(&header,1,sizeof(XShaderHeader_t), hFile); + fseek(hFile,0,SEEK_END); + fclose(hFile); + + if (!header.IsValid()) + return 0; + + return header.BytesToPreload(); +} + +unsigned xZipComputeCustomPreloads( const char* filename ) +{ + // X360TBD: These all need to act on a utlbuffer + Assert( 0 ); + return 0; + +// strlwr(filename); + + unsigned offset = xZipComputeXWVPreload( filename ); + if ( offset ) + return offset; + + offset = xZipComputeVMTPreload( filename ); + if ( offset ) + return offset; + + offset = xZipComputeXCSPreload( filename ); + if ( offset ) + return offset; + + offset = xZipComputeVHVPreload( filename ); + if ( offset ) + return offset; + + return xZipComputeXTFPreload( filename ); +} + +#endif // MAKE_GAMEDATA_TOOL diff --git a/public/zip/XUnzip.h b/public/zip/XUnzip.h new file mode 100644 index 0000000..1e66db2 --- /dev/null +++ b/public/zip/XUnzip.h @@ -0,0 +1,424 @@ +// XUnzip.h Version 1.1 +// +// Authors: Mark Adler et al. (see below) +// +// Modified by: Lucian Wischik +// lu@wischik.com +// +// Version 1.0 - Turned C files into just a single CPP file +// - Made them compile cleanly as C++ files +// - Gave them simpler APIs +// - Added the ability to zip/unzip directly in memory without +// any intermediate files +// +// Modified by: Hans Dietrich +// hdietrich2@hotmail.com +// +// Version 1.1: - Added Unicode support to CreateZip() and ZipAdd() +// - Changed file names to avoid conflicts with Lucian's files +// +/////////////////////////////////////////////////////////////////////////////// +// +// Lucian Wischik's comments: +// -------------------------- +// THIS FILE is almost entirely based upon code by info-zip. +// It has been modified by Lucian Wischik. +// The original code may be found at http://www.info-zip.org +// The original copyright text follows. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Original authors' comments: +// --------------------------- +// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The +// definitive version of this document should be available at +// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. +// +// Copyright (c) 1990-2002 Info-ZIP. All rights reserved. +// +// For the purposes of this copyright and license, "Info-ZIP" is defined as +// the following set of individuals: +// +// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, +// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, +// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, +// David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, +// Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, +// Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler, +// Antoine Verheijen, Paul von Behren, Rich Wales, Mike White +// +// This software is provided "as is", without warranty of any kind, express +// or implied. In no event shall Info-ZIP or its contributors be held liable +// for any direct, indirect, incidental, special or consequential damages +// arising out of the use of or inability to use this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. Redistributions of source code must retain the above copyright notice, +// definition, disclaimer, and this list of conditions. +// +// 2. Redistributions in binary form (compiled executables) must reproduce +// the above copyright notice, definition, disclaimer, and this list of +// conditions in documentation and/or other materials provided with the +// distribution. The sole exception to this condition is redistribution +// of a standard UnZipSFX binary as part of a self-extracting archive; +// that is permitted without inclusion of this license, as long as the +// normal UnZipSFX banner has not been removed from the binary or disabled. +// +// 3. Altered versions--including, but not limited to, ports to new +// operating systems, existing ports with new graphical interfaces, and +// dynamic, shared, or static library versions--must be plainly marked +// as such and must not be misrepresented as being the original source. +// Such altered versions also must not be misrepresented as being +// Info-ZIP releases--including, but not limited to, labeling of the +// altered versions with the names "Info-ZIP" (or any variation thereof, +// including, but not limited to, different capitalizations), +// "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of +// Info-ZIP. Such altered versions are further prohibited from +// misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or +// of the Info-ZIP URL(s). +// +// 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip", +// "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its +// own source and binary releases. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef XUNZIP_H +#define XUNZIP_H + +#if !defined( DWORD ) +#ifdef _WIN32 +typedef unsigned long DWORD; +#else +typedef unsigned int DWORD; +#endif +#endif + +#if !defined( TCHAR ) +typedef char TCHAR; +#endif + +#if defined(POSIX) && !defined(MAX_PATH) +#include +#define MAX_PATH PATH_MAX +typedef bool BOOL; +#endif + +#ifndef XZIP_H +#if !defined(DECLARE_HANDLE) +#if !defined(HANDLE) +typedef void *HANDLE; +#endif +#define DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name +#endif +DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that is being created +#endif + +#if defined(_WIN32) && !defined(_WINBASE_) && !defined(_FILETIME_) +#define _FILETIME_ +typedef struct _FILETIME +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, * LPFILETIME, *PFILETIME; +#endif + +#if defined(POSIX) +typedef time_t FILETIME; +#endif + +typedef DWORD ZRESULT; +// return codes from any of the zip functions. Listed later. + +#define ZIP_HANDLE 1 +#define ZIP_FILENAME 2 +#define ZIP_MEMORY 3 + +typedef struct +{ int index; // index of this file within the zip + char name[MAX_PATH]; // filename within the zip + DWORD attr; // attributes, as in GetFileAttributes. + FILETIME atime,ctime,mtime;// access, create, modify filetimes + long comp_size; // sizes of item, compressed and uncompressed. These + long unc_size; // may be -1 if not yet known (e.g. being streamed in) +} ZIPENTRY; + +typedef struct +{ int index; // index of this file within the zip + TCHAR name[MAX_PATH]; // filename within the zip + DWORD attr; // attributes, as in GetFileAttributes. + FILETIME atime,ctime,mtime;// access, create, modify filetimes + long comp_size; // sizes of item, compressed and uncompressed. These + long unc_size; // may be -1 if not yet known (e.g. being streamed in) +} ZIPENTRYW; + + +/////////////////////////////////////////////////////////////////////////////// +// +// OpenZip() +// +// Purpose: Open an existing zip archive file +// +// Parameters: z - archive file name if flags is ZIP_FILENAME; for other +// uses see below +// len - for memory (ZIP_MEMORY) should be the buffer size; +// for other uses, should be 0 +// flags - indicates usage, see below; for files, this will be +// ZIP_FILENAME +// +// Returns: HZIP - non-zero if zip archive opened ok, otherwise 0 +// +HZIP OpenZip(void *z, unsigned int len, DWORD flags); +// OpenZip - opens a zip file and returns a handle with which you can +// subsequently examine its contents. You can open a zip file from: +// from a pipe: OpenZip(hpipe_read,0, ZIP_HANDLE); +// from a file (by handle): OpenZip(hfile,0, ZIP_HANDLE); +// from a file (by name): OpenZip("c:\\test.zip",0, ZIP_FILENAME); +// from a memory block: OpenZip(bufstart, buflen, ZIP_MEMORY); +// If the file is opened through a pipe, then items may only be +// accessed in increasing order, and an item may only be unzipped once, +// although GetZipItem can be called immediately before and after unzipping +// it. If it's opened i n any other way, then full random access is possible. +// Note: pipe input is not yet implemented. + + +/////////////////////////////////////////////////////////////////////////////// +// +// GetZipItem() +// +// Purpose: Get information about an item in an open zip archive +// +// Parameters: hz - handle of open zip archive +// index - index number (0 based) of item in zip +// ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct +// (if Unicode) +// +// Returns: ZRESULT - ZR_OK if success, otherwise some other value +// + +#ifdef _UNICODE +#define GetZipItem GetZipItemW +#else +#define GetZipItem GetZipItemA +#endif + +ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze); +ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze); +// GetZipItem - call this to get information about an item in the zip. +// If index is -1 and the file wasn't opened through a pipe, +// then it returns information about the whole zipfile +// (and in particular ze.index returns the number of index items). +// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) +// See below for notes on what happens when you unzip such an item. +// Note: if you are opening the zip through a pipe, then random access +// is not possible and GetZipItem(-1) fails and you can't discover the number +// of items except by calling GetZipItem on each one of them in turn, +// starting at 0, until eventually the call fails. Also, in the event that +// you are opening through a pipe and the zip was itself created into a pipe, +// then then comp_size and sometimes unc_size as well may not be known until +// after the item has been unzipped. + + +/////////////////////////////////////////////////////////////////////////////// +// +// FindZipItem() +// +// Purpose: Find item by name and return information about it +// +// Parameters: hz - handle of open zip archive +// name - name of file to look for inside zip archive +// ic - TRUE = case insensitive +// index - pointer to index number returned, or -1 +// ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct +// (if Unicode) +// +// Returns: ZRESULT - ZR_OK if success, otherwise some other value +// + +#ifdef _UNICODE +#define FindZipItem FindZipItemW +#else +#define FindZipItem FindZipItemA +#endif + +ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); +ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze); +// FindZipItem - finds an item by name. ic means 'insensitive to case'. +// It returns the index of the item, and returns information about it. +// If nothing was found, then index is set to -1 and the function returns +// an error code. + + +/////////////////////////////////////////////////////////////////////////////// +// +// UnzipItem() +// +// Purpose: Find item by index and unzip it +// +// Parameters: hz - handle of open zip archive +// index - index number of file to unzip +// dst - target file name of unzipped file +// len - for memory (ZIP_MEMORY. length of buffer; +// otherwise 0 +// flags - indicates usage, see below; for files, this will be +// ZIP_FILENAME +// +// Returns: ZRESULT - ZR_OK if success, otherwise some other value +// + +ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags); +// UnzipItem - given an index to an item, unzips it. You can unzip to: +// to a pipe: UnzipItem(hz,i, hpipe_write,0,ZIP_HANDLE); +// to a file (by handle): UnzipItem(hz,i, hfile,0,ZIP_HANDLE); +// to a file (by name): UnzipItem(hz,i, ze.name,0,ZIP_FILENAME); +// to a memory block: UnzipItem(hz,i, buf,buflen,ZIP_MEMORY); +// In the final case, if the buffer isn't large enough to hold it all, +// then the return code indicates that more is yet to come. If it was +// large enough, and you want to know precisely how big, GetZipItem. +// Note: zip files are normally stored with relative pathnames. If you +// unzip with ZIP_FILENAME a relative pathname then the item gets created +// relative to the current directory - it first ensures that all necessary +// subdirectories have been created. Also, the item may itself be a directory. +// If you unzip a directory with ZIP_FILENAME, then the directory gets created. +// If you unzip it to a handle or a memory block, then nothing gets created +// and it emits 0 bytes. + + +/////////////////////////////////////////////////////////////////////////////// +// +// CloseZip() +// +// Purpose: Close an open zip archive +// +// Parameters: hz - handle to an open zip archive +// +// Returns: ZRESULT - ZR_OK if success, otherwise some other value +// +ZRESULT CloseZip(HZIP hz); +// CloseZip - the zip handle must be closed with this function. + +unsigned int FormatZipMessage(ZRESULT code, char *buf,unsigned int len); +// FormatZipMessage - given an error code, formats it as a string. +// It returns the length of the error message. If buf/len points +// to a real buffer, then it also writes as much as possible into there. + + +// These are the result codes: +#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, +#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. +// The following come from general system stuff (e.g. files not openable) +#define ZR_GENMASK 0x0000FF00 +#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle +#define ZR_NOFILE 0x00000200 // couldn't create/open the file +#define ZR_NOALLOC 0x00000300 // failed to allocate some resource +#define ZR_WRITE 0x00000400 // a general error writing to the file +#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip +#define ZR_MORE 0x00000600 // there's still more data to be unzipped +#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile +#define ZR_READ 0x00000800 // a general error reading the file +// The following come from mistakes on the part of the caller +#define ZR_CALLERMASK 0x00FF0000 +#define ZR_ARGS 0x00010000 // general mistake with the arguments +#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't +#define ZR_MEMSIZE 0x00030000 // the memory size is too small +#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function +#define ZR_ENDED 0x00050000 // the zip creation has already been closed +#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken +#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped +#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip +// The following come from bugs within the zip library itself +#define ZR_BUGMASK 0xFF000000 +#define ZR_NOTINITED 0x01000000 // initialisation didn't work +#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file +#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed +#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code + + + + + +// e.g. +// +// SetCurrentDirectory("c:\\docs\\stuff"); +// HZIP hz = OpenZip("c:\\stuff.zip",0,ZIP_FILENAME); +// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; +// for (int i=0; i +#ifdef IS_WINDOWS_PC +#include +#else +#define INVALID_HANDLE_VALUE (void *)0 +#define FILE_BEGIN SEEK_SET +#define FILE_END SEEK_END +#endif +#include "utlbuffer.h" +#include "utllinkedlist.h" +#include "zip_utils.h" +#include "zip_uncompressed.h" +#include "checksum_crc.h" +#include "byteswap.h" +#include "utlstring.h" + +#include "tier1/lzmaDecoder.h" + +// Not every user of zip utils wants to link LZMA encoder +#ifdef ZIP_SUPPORT_LZMA_ENCODE +#include "lzma/lzma.h" +#endif + +// Data descriptions for byte swapping - only needed +// for structures that are written to file for use by the game. +BEGIN_BYTESWAP_DATADESC( ZIP_EndOfCentralDirRecord ) + DEFINE_FIELD( signature, FIELD_INTEGER ), + DEFINE_FIELD( numberOfThisDisk, FIELD_SHORT ), + DEFINE_FIELD( numberOfTheDiskWithStartOfCentralDirectory, FIELD_SHORT ), + DEFINE_FIELD( nCentralDirectoryEntries_ThisDisk, FIELD_SHORT ), + DEFINE_FIELD( nCentralDirectoryEntries_Total, FIELD_SHORT ), + DEFINE_FIELD( centralDirectorySize, FIELD_INTEGER ), + DEFINE_FIELD( startOfCentralDirOffset, FIELD_INTEGER ), + DEFINE_FIELD( commentLength, FIELD_SHORT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( ZIP_FileHeader ) + DEFINE_FIELD( signature, FIELD_INTEGER ), + DEFINE_FIELD( versionMadeBy, FIELD_SHORT ), + DEFINE_FIELD( versionNeededToExtract, FIELD_SHORT ), + DEFINE_FIELD( flags, FIELD_SHORT ), + DEFINE_FIELD( compressionMethod, FIELD_SHORT ), + DEFINE_FIELD( lastModifiedTime, FIELD_SHORT ), + DEFINE_FIELD( lastModifiedDate, FIELD_SHORT ), + DEFINE_FIELD( crc32, FIELD_INTEGER ), + DEFINE_FIELD( compressedSize, FIELD_INTEGER ), + DEFINE_FIELD( uncompressedSize, FIELD_INTEGER ), + DEFINE_FIELD( fileNameLength, FIELD_SHORT ), + DEFINE_FIELD( extraFieldLength, FIELD_SHORT ), + DEFINE_FIELD( fileCommentLength, FIELD_SHORT ), + DEFINE_FIELD( diskNumberStart, FIELD_SHORT ), + DEFINE_FIELD( internalFileAttribs, FIELD_SHORT ), + DEFINE_FIELD( externalFileAttribs, FIELD_INTEGER ), + DEFINE_FIELD( relativeOffsetOfLocalHeader, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( ZIP_LocalFileHeader ) + DEFINE_FIELD( signature, FIELD_INTEGER ), + DEFINE_FIELD( versionNeededToExtract, FIELD_SHORT ), + DEFINE_FIELD( flags, FIELD_SHORT ), + DEFINE_FIELD( compressionMethod, FIELD_SHORT ), + DEFINE_FIELD( lastModifiedTime, FIELD_SHORT ), + DEFINE_FIELD( lastModifiedDate, FIELD_SHORT ), + DEFINE_FIELD( crc32, FIELD_INTEGER ), + DEFINE_FIELD( compressedSize, FIELD_INTEGER ), + DEFINE_FIELD( uncompressedSize, FIELD_INTEGER ), + DEFINE_FIELD( fileNameLength, FIELD_SHORT ), + DEFINE_FIELD( extraFieldLength, FIELD_SHORT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( ZIP_PreloadHeader ) + DEFINE_FIELD( Version, FIELD_INTEGER ), + DEFINE_FIELD( DirectoryEntries, FIELD_INTEGER ), + DEFINE_FIELD( PreloadDirectoryEntries, FIELD_INTEGER ), + DEFINE_FIELD( Alignment, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( ZIP_PreloadDirectoryEntry ) + DEFINE_FIELD( Length, FIELD_INTEGER ), + DEFINE_FIELD( DataOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +#ifdef WIN32 +//----------------------------------------------------------------------------- +// For >2 GB File Support +//----------------------------------------------------------------------------- +class CWin32File +{ +public: + static HANDLE CreateTempFile( CUtlString &WritePath, CUtlString &FileName ) + { + char tempFileName[MAX_PATH]; + if ( WritePath.IsEmpty() ) + { + // use a safe name in the cwd + char *pBuffer = tmpnam( NULL ); + if ( !pBuffer ) + { + return INVALID_HANDLE_VALUE; + } + if ( pBuffer[0] == '\\' ) + { + pBuffer++; + } + if ( pBuffer[strlen( pBuffer )-1] == '.' ) + { + pBuffer[strlen( pBuffer )-1] = '\0'; + } + V_snprintf( tempFileName, sizeof( tempFileName ), "_%s.tmp", pBuffer ); + } + else + { + // generate safe name at the desired prefix + char uniqueFilename[MAX_PATH]; + SYSTEMTIME sysTime; \ + GetLocalTime( &sysTime ); + sprintf( uniqueFilename, "%d_%d_%d_%d_%d.tmp", sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds ); \ + V_ComposeFileName( WritePath.String(), uniqueFilename, tempFileName, sizeof( tempFileName ) ); + } + + FileName = tempFileName; + HANDLE hFile = CreateFile( tempFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + + return hFile; + } + + static unsigned int FileSeek( HANDLE hFile, unsigned int distance, DWORD MoveMethod ) + { + LARGE_INTEGER li; + + li.QuadPart = distance; + li.LowPart = SetFilePointer( hFile, li.LowPart, &li.HighPart, MoveMethod); + if ( li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) + { + li.QuadPart = -1; + } + + return ( unsigned int )li.QuadPart; + } + + static unsigned int FileTell( HANDLE hFile ) + { + return FileSeek( hFile, 0, FILE_CURRENT ); + } + + static bool FileRead( HANDLE hFile, void *pBuffer, unsigned int size ) + { + DWORD numBytesRead; + BOOL bSuccess = ::ReadFile( hFile, pBuffer, size, &numBytesRead, NULL ); + return bSuccess && ( numBytesRead == size ); + } + + static bool FileWrite( HANDLE hFile, void *pBuffer, unsigned int size ) + { + DWORD numBytesWritten; + BOOL bSuccess = WriteFile( hFile, pBuffer, size, &numBytesWritten, NULL ); + return bSuccess && ( numBytesWritten == size ); + } +}; +#else +class CWin32File +{ +public: + static HANDLE CreateTempFile( CUtlString &WritePath, CUtlString &FileName ) + { + char tempFileName[MAX_PATH]; + if ( WritePath.IsEmpty() ) + { + // use a safe name in the cwd + char *pBuffer = tmpnam( NULL ); + if ( !pBuffer ) + { + return INVALID_HANDLE_VALUE; + } + if ( pBuffer[0] == '\\' ) + { + pBuffer++; + } + if ( pBuffer[strlen( pBuffer )-1] == '.' ) + { + pBuffer[strlen( pBuffer )-1] = '\0'; + } + V_snprintf( tempFileName, sizeof( tempFileName ), "_%s.tmp", pBuffer ); + } + else + { + char uniqueFilename[MAX_PATH]; + static int counter = 0; + time_t now = time( NULL ); + struct tm *tm = localtime( &now ); + sprintf( uniqueFilename, "%d_%d_%d_%d_%d.tmp", tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec, ++counter ); \ + V_ComposeFileName( WritePath.String(), uniqueFilename, tempFileName, sizeof( tempFileName ) ); + } + + FileName = tempFileName; + FILE *hFile = fopen( tempFileName, "rw+" ); + + return (HANDLE)hFile; + } + + static unsigned int FileSeek( HANDLE hFile, unsigned int distance, DWORD MoveMethod ) + { + if ( fseeko( (FILE *)hFile, distance, MoveMethod ) == 0 ) + { + return FileTell( hFile ); + } + return 0; + } + + static unsigned int FileTell( HANDLE hFile ) + { + return ftello( (FILE *)hFile ); + } + + static bool FileRead( HANDLE hFile, void *pBuffer, unsigned int size ) + { + size_t bytesRead = fread( pBuffer, 1, size, (FILE *)hFile ); + return bytesRead == size; + } + + static bool FileWrite( HANDLE hFile, void *pBuffer, unsigned int size ) + { + size_t bytesWrtitten = fwrite( pBuffer, 1, size, (FILE *)hFile ); + return bytesWrtitten == size; + } +}; +#endif + +//----------------------------------------------------------------------------- +// Purpose: Interface to allow abstraction of zip file output methods, and +// avoid duplication of code. Files may be written to a CUtlBuffer or a filestream +//----------------------------------------------------------------------------- +abstract_class IWriteStream +{ +public: + virtual void Put( const void* pMem, int size ) = 0; + virtual unsigned int Tell( void ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Wrapper for CUtlBuffer methods +//----------------------------------------------------------------------------- +class CBufferStream : public IWriteStream +{ +public: + CBufferStream( CUtlBuffer& buff ) : IWriteStream(), m_buff( &buff ) {} + + // Implementing IWriteStream method + virtual void Put( const void* pMem, int size ) {m_buff->Put( pMem, size );} + + // Implementing IWriteStream method + virtual unsigned int Tell( void ) { return m_buff->TellPut(); } + +private: + CUtlBuffer *m_buff; +}; + +//----------------------------------------------------------------------------- +// Purpose: Wrapper for file I/O methods +//----------------------------------------------------------------------------- +class CFileStream : public IWriteStream +{ +public: + CFileStream( FILE *fout ) : IWriteStream(), m_file( fout ), m_hFile( INVALID_HANDLE_VALUE ) {} + CFileStream( HANDLE hOutFile ) : IWriteStream(), m_file( NULL ), m_hFile( hOutFile ) {} + + // Implementing IWriteStream method + virtual void Put( const void* pMem, int size ) + { + if ( m_file ) + { + fwrite( pMem, size, 1, m_file ); + } +#ifdef WIN32 + else + { + DWORD numBytesWritten; + WriteFile( m_hFile, pMem, size, &numBytesWritten, NULL ); + } +#endif + } + + // Implementing IWriteStream method + virtual unsigned int Tell( void ) + { + if ( m_file ) + { + return ftell( m_file ); + } + else + { +#ifdef WIN32 + return CWin32File::FileTell( m_hFile ); +#else + return 0; +#endif + } + } + +private: + FILE *m_file; + HANDLE m_hFile; +}; + +//----------------------------------------------------------------------------- +// Purpose: Container for modifiable pak file which is embedded inside the .bsp file +// itself. It's used to allow one-off files to be stored local to the map and it is +// hooked into the file system as an override for searching for named files. +//----------------------------------------------------------------------------- +class CZipFile +{ +public: + // Construction + CZipFile( const char *pDiskCacheWritePath, bool bSortByName ); + ~CZipFile( void ); + + // Public API + // Clear all existing data + void Reset( void ); + + // Add file to zip under relative name + void AddFileToZip( const char *relativename, const char *fullpath, IZip::eCompressionType compressionType ); + + // Delete file from zip + void RemoveFileFromZip( const char *relativename ); + + // Add buffer to zip as a file with given name + void AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType ); + + // Check if a file already exists in the zip. + bool FileExistsInZip( const char *relativename ); + + // Reads a file from a zip file + bool ReadFileFromZip( const char *relativename, bool bTextMode, CUtlBuffer &buf ); + bool ReadFileFromZip( HANDLE hZipFile, const char *relativename, bool bTextMode, CUtlBuffer &buf ); + + // Initialize the zip file from a buffer + void ParseFromBuffer( void *buffer, int bufferlength ); + HANDLE ParseFromDisk( const char *pFilename ); + + // Estimate the size of the zip file (including header, padding, etc.) + unsigned int EstimateSize(); + + // Print out a directory of files in the zip. + void PrintDirectory( void ); + + // Use to iterate directory, pass 0 for first element + // returns nonzero element id with filled buffer, or -1 at list conclusion + int GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ); + + // Write the zip to a buffer + void SaveToBuffer( CUtlBuffer& buffer ); + // Write the zip to a filestream + void SaveToDisk( FILE *fout ); + void SaveToDisk( HANDLE hOutFile ); + + unsigned int CalculateSize( void ); + + void ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize ); + + unsigned int GetAlignment(); + + void SetBigEndian( bool bigEndian ); + void ActivateByteSwapping( bool bActivate ); + +private: + enum + { + MAX_FILES_IN_ZIP = 32768, + }; + + typedef struct + { + CUtlSymbol m_Name; + unsigned int filepos; + int filelen; + int uncompressedLen; + CRC32_t crc32; + IZip::eCompressionType compressionType; + } TmpFileInfo_t; + + CByteswap m_Swap; + unsigned int m_AlignmentSize; + bool m_bForceAlignment; + bool m_bCompatibleFormat; + + unsigned short CalculatePadding( unsigned int filenameLen, unsigned int pos ); + void SaveDirectory( IWriteStream& stream ); + int MakeXZipCommentString( char *pComment ); + void ParseXZipCommentString( const char *pComment ); + + // Internal entry for faster searching, etc. + class CZipEntry + { + public: + CZipEntry( void ); + ~CZipEntry( void ); + + CZipEntry( const CZipEntry& src ); + + // RB tree compare function + static bool ZipFileLessFunc( CZipEntry const& src1, CZipEntry const& src2 ); + static bool ZipFileLessFunc_CaselessSort( CZipEntry const& src1, CZipEntry const& src2 ); + + // Name of entry + CUtlSymbol m_Name; + + // Lenth of data element + int m_nCompressedSize; + + // Original, uncompressed size + int m_nUncompressedSize; + + // Raw data, could be null and data may be in disk write cache + void *m_pData; + + // Offset in Zip ( set and valid during final write ) + unsigned int m_ZipOffset; + // CRC of blob + CRC32_t m_ZipCRC; + + // Location of data in disk cache + unsigned int m_DiskCacheOffset; + unsigned int m_SourceDiskOffset; + + // The compression used on the data if any + IZip::eCompressionType m_eCompressionType; + }; + + // For fast name lookup and sorting + CUtlRBTree< CZipEntry, int > m_Files; + + // Used to buffer zip data, instead of ram + bool m_bUseDiskCacheForWrites; + HANDLE m_hDiskCacheWriteFile; + CUtlString m_DiskCacheName; + CUtlString m_DiskCacheWritePath; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CZipFile::CZipEntry::CZipEntry( void ) +{ + m_Name = ""; + m_nCompressedSize = 0; + m_nUncompressedSize = 0; + m_pData = NULL; + m_ZipOffset = 0; + m_ZipCRC = 0; + m_DiskCacheOffset = 0; + m_SourceDiskOffset = 0; + m_eCompressionType = IZip::eCompressionType_None; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : src - +//----------------------------------------------------------------------------- +CZipFile::CZipEntry::CZipEntry( const CZipFile::CZipEntry& src ) +{ + m_Name = src.m_Name; + m_nCompressedSize = src.m_nCompressedSize; + m_nUncompressedSize = src.m_nUncompressedSize; + m_eCompressionType = src.m_eCompressionType; + + if ( src.m_nCompressedSize > 0 && src.m_pData ) + { + m_pData = malloc( src.m_nCompressedSize ); + memcpy( m_pData, src.m_pData, src.m_nCompressedSize ); + } + else + { + m_pData = NULL; + } + + m_ZipOffset = src.m_ZipOffset; + m_ZipCRC = src.m_ZipCRC; + m_DiskCacheOffset = src.m_DiskCacheOffset; + m_SourceDiskOffset = src.m_SourceDiskOffset; +} + +//----------------------------------------------------------------------------- +// Purpose: Clear any leftover data +//----------------------------------------------------------------------------- +CZipFile::CZipEntry::~CZipEntry( void ) +{ + if ( m_pData ) + { + free( m_pData ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Construction +//----------------------------------------------------------------------------- +CZipFile::CZipFile( const char *pDiskCacheWritePath, bool bSortByName ) +: m_Files( 0, 32 ) +{ + m_AlignmentSize = 0; + m_bForceAlignment = false; + m_bCompatibleFormat = true; + + m_bUseDiskCacheForWrites = ( pDiskCacheWritePath != NULL ); + m_DiskCacheWritePath = pDiskCacheWritePath; + m_hDiskCacheWriteFile = INVALID_HANDLE_VALUE; + + if ( bSortByName ) + { + m_Files.SetLessFunc( CZipEntry::ZipFileLessFunc_CaselessSort ); + } + else + { + m_Files.SetLessFunc( CZipEntry::ZipFileLessFunc ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy zip data +//----------------------------------------------------------------------------- +CZipFile::~CZipFile( void ) +{ + m_bUseDiskCacheForWrites = false; + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: Delete all current data +//----------------------------------------------------------------------------- +void CZipFile::Reset( void ) +{ + m_Files.RemoveAll(); + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { +#ifdef WIN32 + CloseHandle( m_hDiskCacheWriteFile ); + DeleteFile( m_DiskCacheName.String() ); +#else + fclose( (FILE *)m_hDiskCacheWriteFile ); + unlink( m_DiskCacheName.String() ); +#endif + m_hDiskCacheWriteFile = INVALID_HANDLE_VALUE; + } + + if ( m_bUseDiskCacheForWrites ) + { + m_hDiskCacheWriteFile = CWin32File::CreateTempFile( m_DiskCacheWritePath, m_DiskCacheName ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Comparison for sorting entries +// Input : src1 - +// src2 - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CZipFile::CZipEntry::ZipFileLessFunc( CZipEntry const& src1, CZipEntry const& src2 ) +{ + return ( src1.m_Name < src2.m_Name ); +} + +bool CZipFile::CZipEntry::ZipFileLessFunc_CaselessSort( CZipEntry const& src1, CZipEntry const& src2 ) +{ + return ( V_stricmp( src1.m_Name.String(), src2.m_Name.String() ) < 0 ); +} + +void CZipFile::ForceAlignment( bool bAligned, bool bCompatibleFormat, unsigned int alignment ) +{ + m_bForceAlignment = bAligned; + m_AlignmentSize = alignment; + m_bCompatibleFormat = bCompatibleFormat; + + if ( !bAligned ) + { + m_AlignmentSize = 0; + } + else if ( !IsPowerOfTwo( m_AlignmentSize ) ) + { + m_AlignmentSize = 0; + } +} + +unsigned int CZipFile::GetAlignment() +{ + if ( !m_bForceAlignment || !m_AlignmentSize ) + { + return 0; + } + + return m_AlignmentSize; +} + +void CZipFile::SetBigEndian( bool bigEndian ) +{ + m_Swap.SetTargetBigEndian( bigEndian ); +} + +void CZipFile::ActivateByteSwapping( bool bActivate ) +{ + m_Swap.ActivateByteSwapping( bActivate ); +} + +//----------------------------------------------------------------------------- +// Purpose: Load pak file from raw buffer +// Input : *buffer - +// bufferlength - +//----------------------------------------------------------------------------- +void CZipFile::ParseFromBuffer( void *buffer, int bufferlength ) +{ + // Throw away old data + Reset(); + + // Initialize a buffer + CUtlBuffer buf( 0, bufferlength +1 ); // +1 for null termination + + // need to swap bytes, so set the buffer opposite the machine's endian + buf.ActivateByteSwapping( m_Swap.IsSwappingBytes() ); + + buf.Put( buffer, bufferlength ); + + buf.SeekGet( CUtlBuffer::SEEK_TAIL, 0 ); + unsigned int fileLen = buf.TellGet(); + + // Start from beginning + buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + + ZIP_EndOfCentralDirRecord rec = { 0 }; + +#ifdef DBGFLAG_ASSERT + bool bFoundEndOfCentralDirRecord = false; +#endif + unsigned int offset = fileLen - sizeof( ZIP_EndOfCentralDirRecord ); + // If offset is ever greater than startOffset then it means that it has + // wrapped. This used to be a tautological >= 0 test. + ANALYZE_SUPPRESS( 6293 ); // warning C6293: Ill-defined for-loop: counts down from minimum + for ( unsigned int startOffset = offset; offset <= startOffset; offset-- ) + { + buf.SeekGet( CUtlBuffer::SEEK_HEAD, offset ); + buf.GetObjects( &rec ); + if ( rec.signature == PKID( 5, 6 ) ) + { +#ifdef DBGFLAG_ASSERT + bFoundEndOfCentralDirRecord = true; +#endif + + // Set any xzip configuration + if ( rec.commentLength ) + { + char commentString[128]; + int commentLength = vmin( rec.commentLength, sizeof( commentString ) ); + buf.Get( commentString, commentLength ); + if ( commentLength == sizeof( commentString ) ) + --commentLength; + commentString[commentLength] = '\0'; + ParseXZipCommentString( commentString ); + } + break; + } + else + { + // wrong record + rec.nCentralDirectoryEntries_Total = 0; + } + } + Assert( bFoundEndOfCentralDirRecord ); + + // Make sure there are some files to parse + int numzipfiles = rec.nCentralDirectoryEntries_Total; + if ( numzipfiles <= 0 ) + { + // No files + return; + } + + buf.SeekGet( CUtlBuffer::SEEK_HEAD, rec.startOfCentralDirOffset ); + + // Allocate space for directory + TmpFileInfo_t *newfiles = new TmpFileInfo_t[numzipfiles]; + Assert( newfiles ); + + // build directory + int i; + for ( i = 0; i < rec.nCentralDirectoryEntries_Total; i++ ) + { + ZIP_FileHeader zipFileHeader; + buf.GetObjects( &zipFileHeader ); + Assert( zipFileHeader.signature == PKID( 1, 2 ) ); + if ( zipFileHeader.compressionMethod != IZip::eCompressionType_None && + zipFileHeader.compressionMethod != IZip::eCompressionType_LZMA ) + { + Assert( false ); + Warning( "Opening ZIP file with unsupported compression type\n"); + } + + char tmpString[1024] = { 0 }; + buf.Get( tmpString, Min( (unsigned int)zipFileHeader.fileNameLength, (unsigned int)sizeof( tmpString ) ) ); + Q_strlower( tmpString ); + + // can determine actual filepos, assuming a well formed zip + newfiles[i].m_Name = tmpString; + newfiles[i].filelen = zipFileHeader.compressedSize; + newfiles[i].uncompressedLen = zipFileHeader.uncompressedSize; + newfiles[i].crc32 = zipFileHeader.crc32; + newfiles[i].filepos = zipFileHeader.relativeOffsetOfLocalHeader + + sizeof( ZIP_LocalFileHeader ) + + zipFileHeader.fileNameLength + + zipFileHeader.extraFieldLength; + newfiles[i].compressionType = (IZip::eCompressionType)zipFileHeader.compressionMethod; + + int nextOffset; + if ( m_bCompatibleFormat ) + { + nextOffset = zipFileHeader.extraFieldLength + zipFileHeader.fileCommentLength; + } + else + { + nextOffset = 0; + } + buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nextOffset ); + } + + // Insert current data into rb tree + for ( i=0; i 0 ) + { + e.m_pData = malloc( e.m_nCompressedSize ); + + // Copy in data + buf.SeekGet( CUtlBuffer::SEEK_HEAD, newfiles[i].filepos ); + buf.Get( e.m_pData, e.m_nCompressedSize ); + } + else + { + e.m_pData = NULL; + } + + // Add to tree + m_Files.Insert( e ); + } + + // Through away directory + delete[] newfiles; +} + +//----------------------------------------------------------------------------- +// Purpose: Mount pak file from disk +//----------------------------------------------------------------------------- +HANDLE CZipFile::ParseFromDisk( const char *pFilename ) +{ +#ifdef WIN32 + HANDLE hFile = CreateFile( pFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile == INVALID_HANDLE_VALUE ) + { + // not found + return NULL; + } +#else + HANDLE hFile = fopen( pFilename, "rw+" ); + if ( !hFile ) + { + // not found + return NULL; + } +#endif + + unsigned int fileLen = CWin32File::FileSeek( hFile, 0, FILE_END ); + CWin32File::FileSeek( hFile, 0, FILE_BEGIN ); + if ( fileLen < sizeof( ZIP_EndOfCentralDirRecord ) ) + { + // bad format +#ifdef WIN32 + CloseHandle( hFile ); +#else + fclose( (FILE *)hFile ); +#endif + return NULL; + } + + // need to get the central dir + ZIP_EndOfCentralDirRecord rec = { 0 }; + unsigned int offset = fileLen - sizeof( ZIP_EndOfCentralDirRecord ); + // If offset is ever greater than startOffset then it means that it has + // wrapped. This used to be a tautological >= 0 test. + ANALYZE_SUPPRESS( 6293 ); // warning C6293: Ill-defined for-loop: counts down from minimum + for ( unsigned int startOffset = offset; offset <= startOffset; offset-- ) + { + CWin32File::FileSeek( hFile, offset, FILE_BEGIN ); + + CWin32File::FileRead( hFile, &rec, sizeof( rec ) ); + m_Swap.SwapFieldsToTargetEndian( &rec ); + + if ( rec.signature == PKID( 5, 6 ) ) + { + // Set any xzip configuration + if ( rec.commentLength ) + { + char commentString[128]; + int commentLength = vmin( rec.commentLength, sizeof( commentString ) ); + CWin32File::FileRead( hFile, commentString, commentLength ); + if ( commentLength == sizeof( commentString ) ) + --commentLength; + commentString[commentLength] = '\0'; + ParseXZipCommentString( commentString ); + } + break; + } + else + { + // wrong record + rec.nCentralDirectoryEntries_Total = 0; + } + } + + // Make sure there are some files to parse + int numZipFiles = rec.nCentralDirectoryEntries_Total; + if ( numZipFiles <= 0 ) + { + // No files +#ifdef WIN32 + CloseHandle( hFile ); +#else + fclose( (FILE *)hFile ); +#endif + return NULL; + } + + CWin32File::FileSeek( hFile, rec.startOfCentralDirOffset, FILE_BEGIN ); + + // read entire central dir into memory + CUtlBuffer zipDirBuff( 0, rec.centralDirectorySize, 0 ); + zipDirBuff.ActivateByteSwapping( m_Swap.IsSwappingBytes() ); + CWin32File::FileRead( hFile, zipDirBuff.Base(), rec.centralDirectorySize ); + zipDirBuff.SeekPut( CUtlBuffer::SEEK_HEAD, rec.centralDirectorySize ); + + // build directory + for ( int i = 0; i < numZipFiles; i++ ) + { + ZIP_FileHeader zipFileHeader; + zipDirBuff.GetObjects( &zipFileHeader ); + + if ( zipFileHeader.signature != PKID( 1, 2 ) + || ( zipFileHeader.compressionMethod != IZip::eCompressionType_None + && zipFileHeader.compressionMethod != IZip::eCompressionType_LZMA ) ) + { + // bad contents +#ifdef WIN32 + CloseHandle( hFile ); +#else + fclose( (FILE *)hFile ); +#endif + return NULL; + } + + char fileName[1024]; + zipDirBuff.Get( fileName, zipFileHeader.fileNameLength ); + fileName[zipFileHeader.fileNameLength] = '\0'; + Q_strlower( fileName ); + + // can determine actual filepos, assuming a well formed zip + CZipEntry e; + e.m_Name = fileName; + e.m_nCompressedSize = zipFileHeader.compressedSize; + e.m_nUncompressedSize = zipFileHeader.uncompressedSize; + e.m_ZipCRC = zipFileHeader.crc32; + e.m_SourceDiskOffset = zipFileHeader.relativeOffsetOfLocalHeader + + sizeof( ZIP_LocalFileHeader ) + + zipFileHeader.fileNameLength + + zipFileHeader.extraFieldLength; + e.m_eCompressionType = (IZip::eCompressionType)zipFileHeader.compressionMethod; + + // Add to tree + m_Files.Insert( e ); + + int nextOffset; + if ( m_bCompatibleFormat ) + { + nextOffset = zipFileHeader.extraFieldLength + zipFileHeader.fileCommentLength; + } + else + { + nextOffset = 0; + } + + zipDirBuff.SeekGet( CUtlBuffer::SEEK_CURRENT, nextOffset ); + } + + return hFile; +} + +static int GetLengthOfBinStringAsText( const char *pSrc, int srcSize ) +{ + const char *pSrcScan = pSrc; + const char *pSrcEnd = pSrc + srcSize; + int numChars = 0; + for( ; pSrcScan < pSrcEnd; pSrcScan++ ) + { + if( *pSrcScan == '\n' ) + { + numChars += 2; + } + else + { + numChars++; + } + } + return numChars; +} + + +//----------------------------------------------------------------------------- +// Copies text data from a form appropriate for disk to a normal string +//----------------------------------------------------------------------------- +static void ReadTextData( const char *pSrc, int nSrcSize, CUtlBuffer &buf ) +{ + buf.EnsureCapacity( nSrcSize + 1 ); + const char *pSrcEnd = pSrc + nSrcSize; + for ( const char *pSrcScan = pSrc; pSrcScan < pSrcEnd; ++pSrcScan ) + { + if ( *pSrcScan == '\r' ) + { + if ( pSrcScan[1] == '\n' ) + { + buf.PutChar( '\n' ); + ++pSrcScan; + continue; + } + } + + buf.PutChar( *pSrcScan ); + } + + // Null terminate + buf.PutChar( '\0' ); +} + + +//----------------------------------------------------------------------------- +// Copies text data into a form appropriate for disk +//----------------------------------------------------------------------------- +static void CopyTextData( char *pDst, const char *pSrc, int dstSize, int srcSize ) +{ + const char *pSrcScan = pSrc; + const char *pSrcEnd = pSrc + srcSize; + char *pDstScan = pDst; + +#ifdef DBGFLAG_ASSERT + char *pDstEnd = pDst + dstSize; +#endif + + for ( ; pSrcScan < pSrcEnd; pSrcScan++ ) + { + if ( *pSrcScan == '\n' ) + { + *pDstScan = '\r'; + pDstScan++; + *pDstScan = '\n'; + pDstScan++; + } + else + { + *pDstScan = *pSrcScan; + pDstScan++; + } + } + Assert( pSrcScan == pSrcEnd ); + Assert( pDstScan == pDstEnd ); +} + +//----------------------------------------------------------------------------- +// Purpose: Adds a new lump, or overwrites existing one +// Input : *relativename - +// *data - +// length - +//----------------------------------------------------------------------------- +void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType ) +{ + // Lower case only + char name[512]; + Q_strcpy( name, relativename ); + Q_strlower( name ); + + int outLength = length; + int uncompressedLength = length; + void *outData = data; + CUtlBuffer textTransform; + CUtlBuffer compressionTransform; + + if ( bTextMode ) + { + int textLen = GetLengthOfBinStringAsText( ( const char * )outData, outLength ); + textTransform.EnsureCapacity( textLen ); + CopyTextData( (char *)textTransform.Base(), (char *)outData, textLen, outLength ); + + outData = (void *)textTransform.Base(); + outLength = textLen; + uncompressedLength = textLen; + } + + // uncompressed data final at this point (CRC is before compression) + CRC32_t zipCRC; + CRC32_Init( &zipCRC ); + CRC32_ProcessBuffer( &zipCRC, outData, outLength ); + CRC32_Final( &zipCRC ); + +#ifdef ZIP_SUPPORT_LZMA_ENCODE + if ( compressionType == IZip::eCompressionType_LZMA ) + { + unsigned int compressedSize = 0; + unsigned char *pCompressedOutput = LZMA_Compress( (unsigned char *)outData, outLength, &compressedSize ); + if ( !pCompressedOutput || compressedSize < sizeof( lzma_header_t ) ) + { + Warning( "ZipFile: LZMA compression failed\n" ); + return; + } + + // Fixup LZMA header for ZIP payload usage + // The output of LZMA_Compress uses lzma_header_t, defined alongside it. + // + // ZIP payload format, see ZIP spec 5.8.8: + // LZMA Version Information 2 bytes + // LZMA Properties Size 2 bytes + // LZMA Properties Data variable, defined by "LZMA Properties Size" + unsigned int nZIPHeader = 2 + 2 + sizeof( lzma_header_t().properties ); + unsigned int finalCompressedSize = compressedSize - sizeof( lzma_header_t ) + nZIPHeader; + compressionTransform.EnsureCapacity( finalCompressedSize ); + + // LZMA version + compressionTransform.PutUnsignedChar( LZMA_SDK_VERSION_MAJOR ); + compressionTransform.PutUnsignedChar( LZMA_SDK_VERSION_MINOR ); + // properties size + uint16 nSwappedPropertiesSize = LittleWord( sizeof( lzma_header_t().properties ) ); + compressionTransform.Put( &nSwappedPropertiesSize, sizeof( nSwappedPropertiesSize ) ); + // properties + compressionTransform.Put( &(((lzma_header_t *)pCompressedOutput)->properties), sizeof( lzma_header_t().properties ) ); + // payload + compressionTransform.Put( pCompressedOutput + sizeof( lzma_header_t ), compressedSize - sizeof( lzma_header_t ) ); + + // Free original + free( pCompressedOutput ); + pCompressedOutput = NULL; + + outData = (void *)compressionTransform.Base(); + outLength = finalCompressedSize; + // (Not updating uncompressedLength) + } + else +#endif + /* else from ifdef */ if ( compressionType != IZip::eCompressionType_None ) + { + Error( "Calling AddBufferToZip with unknown compression type\n" ); + return; + } + + // See if entry is in list already + CZipEntry e; + e.m_Name = name; + int index = m_Files.Find( e ); + + // If already existing, throw away old data and update data and length + if ( index != m_Files.InvalidIndex() ) + { + CZipEntry *update = &m_Files[ index ]; + if ( update->m_pData ) + { + free( update->m_pData ); + } + + update->m_eCompressionType = compressionType; + update->m_pData = malloc( outLength ); + memcpy( update->m_pData, outData, outLength ); + update->m_nCompressedSize = outLength; + update->m_nUncompressedSize = uncompressedLength; + update->m_ZipCRC = zipCRC; + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { + update->m_DiskCacheOffset = CWin32File::FileTell( m_hDiskCacheWriteFile ); + CWin32File::FileWrite( m_hDiskCacheWriteFile, update->m_pData, update->m_nCompressedSize ); + free( update->m_pData ); + update->m_pData = NULL; + } + } + else + { + // Create a new entry + e.m_nCompressedSize = outLength; + e.m_nUncompressedSize = uncompressedLength; + e.m_eCompressionType = compressionType; + e.m_ZipCRC = zipCRC; + if ( outLength > 0 ) + { + e.m_pData = malloc( outLength ); + memcpy( e.m_pData, outData, outLength ); + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { + e.m_DiskCacheOffset = CWin32File::FileTell( m_hDiskCacheWriteFile ); + CWin32File::FileWrite( m_hDiskCacheWriteFile, e.m_pData, e.m_nCompressedSize ); + free( e.m_pData ); + e.m_pData = NULL; + } + } + else + { + e.m_pData = NULL; + } + + m_Files.Insert( e ); + } +} + + +//----------------------------------------------------------------------------- +// Reads a file from the zip +//----------------------------------------------------------------------------- +bool CZipFile::ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) +{ + return ReadFileFromZip( 0, pRelativeName, bTextMode, buf ); +} + +//----------------------------------------------------------------------------- +// Reads a file from the zip. Requires the zip file handle if this zip was loaded via ParseFromDisk +//----------------------------------------------------------------------------- +bool CZipFile::ReadFileFromZip( HANDLE hZipFile, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) +{ + // Lower case only + char pName[512]; + Q_strncpy( pName, pRelativeName, 512 ); + Q_strlower( pName ); + + // See if entry is in list already + CZipEntry e; + e.m_Name = pName; + int nIndex = m_Files.Find( e ); + if ( nIndex == m_Files.InvalidIndex() ) + { + // not found + return false; + } + + CZipEntry *pEntry = &m_Files[nIndex]; + + void *pData = pEntry->m_pData; + CUtlBuffer readBuffer; + if ( !pData && hZipFile ) + { + readBuffer.EnsureCapacity( pEntry->m_nCompressedSize ); + CWin32File::FileSeek( hZipFile, pEntry->m_SourceDiskOffset, FILE_BEGIN ); + if ( !CWin32File::FileRead( hZipFile, readBuffer.Base(), pEntry->m_nCompressedSize ) ) + { + return false; + } + + pData = readBuffer.Base(); + } + + CUtlBuffer decompressTransform; + if ( pEntry->m_eCompressionType != IZip::eCompressionType_None ) + { + if ( pEntry->m_eCompressionType == IZip::eCompressionType_LZMA ) + { + decompressTransform.EnsureCapacity( pEntry->m_nUncompressedSize ); + + CLZMAStream decompressStream; + decompressStream.InitZIPHeader( pEntry->m_nCompressedSize, pEntry->m_nUncompressedSize ); + + unsigned int nCompressedBytesRead = 0; + unsigned int nOutputBytesWritten = 0; + bool bSuccess = decompressStream.Read( (unsigned char *)pData, pEntry->m_nCompressedSize, + (unsigned char *)decompressTransform.Base(), decompressTransform.Size(), + nCompressedBytesRead, nOutputBytesWritten ); + if ( !bSuccess || + (int)nCompressedBytesRead != pEntry->m_nCompressedSize || + (int)nOutputBytesWritten != pEntry->m_nUncompressedSize ) + { + Error( "Zip: Failed decompressing LZMA data\n" ); + return false; + } + + pData = decompressTransform.Base(); + } + else + { + Error( "Unsupported compression type in Zip file: %u\n", pEntry->m_eCompressionType ); + return false; + } + } + + if ( bTextMode ) + { + buf.SetBufferType( true, false ); + ReadTextData( (const char *)pData, pEntry->m_nUncompressedSize, buf ); + } + else + { + buf.SetBufferType( false, false ); + buf.Put( pData, pEntry->m_nUncompressedSize ); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Check if a file already exists in the zip. +// Input : *relativename - +//----------------------------------------------------------------------------- +bool CZipFile::FileExistsInZip( const char *pRelativeName ) +{ + // Lower case only + char pName[512]; + Q_strncpy( pName, pRelativeName, 512 ); + Q_strlower( pName ); + + // See if entry is in list already + CZipEntry e; + e.m_Name = pName; + int nIndex = m_Files.Find( e ); + + // If it is, then it exists in the pack! + return nIndex != m_Files.InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Adds a new file to the zip. +//----------------------------------------------------------------------------- +void CZipFile::AddFileToZip( const char *relativename, const char *fullpath, IZip::eCompressionType compressionType ) +{ + FILE *temp = fopen( fullpath, "rb" ); + if ( !temp ) + return; + + // Determine length + fseek( temp, 0, SEEK_END ); + int size = ftell( temp ); + fseek( temp, 0, SEEK_SET ); + byte *buf = (byte *)malloc( size + 1 ); + + // Read data + fread( buf, size, 1, temp ); + fclose( temp ); + + // Now add as a buffer + AddBufferToZip( relativename, buf, size, false, compressionType ); + + free( buf ); +} + +//----------------------------------------------------------------------------- +// Purpose: Removes a file from the zip. +//----------------------------------------------------------------------------- +void CZipFile::RemoveFileFromZip( const char *relativename ) +{ + CZipEntry e; + e.m_Name = relativename; + int index = m_Files.Find( e ); + + if ( index != m_Files.InvalidIndex() ) + { + CZipEntry update = m_Files[index]; + m_Files.Remove( update ); + } +} + +//--------------------------------------------------------------- +// Purpose: Calculates how many bytes should be added to the extra field +// to push the start of the file data to the next aligned boundary +// Output: Required padding size +//--------------------------------------------------------------- +unsigned short CZipFile::CalculatePadding( unsigned int filenameLen, unsigned int pos ) +{ + if ( m_AlignmentSize == 0 ) + { + return 0; + } + + unsigned int headerSize = sizeof( ZIP_LocalFileHeader ) + filenameLen; + return (unsigned short)( m_AlignmentSize - ( ( pos + headerSize ) % m_AlignmentSize ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Create the XZIP identifying comment string +// Output : Length +//----------------------------------------------------------------------------- +int CZipFile::MakeXZipCommentString( char *pCommentString ) +{ + char tempString[XZIP_COMMENT_LENGTH]; + + memset( tempString, 0, sizeof( tempString ) ); + V_snprintf( tempString, sizeof( tempString ), "XZP%c %d", m_bCompatibleFormat ? '1' : '2', m_AlignmentSize ); + if ( pCommentString ) + { + memcpy( pCommentString, tempString, sizeof( tempString ) ); + } + + // expected fixed length + return XZIP_COMMENT_LENGTH; +} + +//----------------------------------------------------------------------------- +// Purpose: An XZIP has its configuration in the ascii comment +//----------------------------------------------------------------------------- +void CZipFile::ParseXZipCommentString( const char *pCommentString ) +{ + if ( !V_strnicmp( pCommentString, "XZP", 3 ) ) + { + m_bCompatibleFormat = true; + if ( pCommentString[3] == '2' ) + { + m_bCompatibleFormat = false; + } + + // parse out the alignement configuration + if ( !m_bForceAlignment ) + { + m_AlignmentSize = 0; + sscanf( pCommentString + 4, "%d", &m_AlignmentSize ); + if ( !IsPowerOfTwo( m_AlignmentSize ) ) + { + m_AlignmentSize = 0; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Calculate the exact size of zip file, with headers and padding +// Output : int +//----------------------------------------------------------------------------- +unsigned int CZipFile::CalculateSize( void ) +{ + unsigned int size = 0; + unsigned int dirHeaders = 0; + for ( int i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) ) + { + CZipEntry *e = &m_Files[ i ]; + + if ( e->m_nCompressedSize == 0 ) + continue; + + // local file header + size += sizeof( ZIP_LocalFileHeader ); + size += strlen( e->m_Name.String() ); + + // every file has a directory header that duplicates the filename + dirHeaders += sizeof( ZIP_FileHeader ) + strlen( e->m_Name.String() ); + + // calculate padding + if ( m_AlignmentSize != 0 ) + { + // round up to next boundary + unsigned int nextBoundary = ( size + m_AlignmentSize ) & ~( m_AlignmentSize - 1 ); + + // the directory header also duplicates the padding + dirHeaders += nextBoundary - size; + + size = nextBoundary; + } + + // data size + size += e->m_nCompressedSize; + } + + size += dirHeaders; + + // All processed zip files will have a comment string + size += sizeof( ZIP_EndOfCentralDirRecord ) + MakeXZipCommentString( NULL ); + + return size; +} + +//----------------------------------------------------------------------------- +// Purpose: Print a directory of files in the zip +//----------------------------------------------------------------------------- +void CZipFile::PrintDirectory( void ) +{ + for ( int i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) ) + { + CZipEntry *e = &m_Files[ i ]; + + Msg( "%s\n", e->m_Name.String() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Iterate through directory +//----------------------------------------------------------------------------- +int CZipFile::GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ) +{ + if ( id == -1 ) + { + id = m_Files.FirstInorder(); + } + else + { + id = m_Files.NextInorder( id ); + } + if ( id == m_Files.InvalidIndex() ) + { + // list is empty + return -1; + } + + CZipEntry *e = &m_Files[id]; + + Q_strncpy( pBuffer, e->m_Name.String(), bufferSize ); + fileSize = e->m_nUncompressedSize; + + return id; +} + +//----------------------------------------------------------------------------- +// Purpose: Store data out to disk +//----------------------------------------------------------------------------- +void CZipFile::SaveToDisk( FILE *fout ) +{ + CFileStream stream( fout ); + SaveDirectory( stream ); +} + +void CZipFile::SaveToDisk( HANDLE hOutFile ) +{ + CFileStream stream( hOutFile ); + SaveDirectory( stream ); +} + +//----------------------------------------------------------------------------- +// Purpose: Store data out to a CUtlBuffer +//----------------------------------------------------------------------------- +void CZipFile::SaveToBuffer( CUtlBuffer& buf ) +{ + CBufferStream stream( buf ); + SaveDirectory( stream ); +} + +//----------------------------------------------------------------------------- +// Purpose: Store data back out to a stream (could be CUtlBuffer or filestream) +//----------------------------------------------------------------------------- +void CZipFile::SaveDirectory( IWriteStream& stream ) +{ + void *pPaddingBuffer = NULL; + if ( m_AlignmentSize ) + { + // get a temp buffer for all padding work + pPaddingBuffer = malloc( m_AlignmentSize ); + memset( pPaddingBuffer, 0x00, m_AlignmentSize ); + } + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { +#ifdef WIN32 + FlushFileBuffers( m_hDiskCacheWriteFile ); +#else + fflush( (FILE *)m_hDiskCacheWriteFile ); +#endif + } + + // Might be writing a zip into a larger stream + unsigned int zipOffsetInStream = stream.Tell(); + + int i; + for ( i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) ) + { + CZipEntry *e = &m_Files[i]; + Assert( e ); + + // Fix up the offset + e->m_ZipOffset = stream.Tell() - zipOffsetInStream; + + if ( e->m_nCompressedSize > 0 && ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) ) + { + // get the data back from the write cache + e->m_pData = malloc( e->m_nCompressedSize ); + if ( e->m_pData ) + { + CWin32File::FileSeek( m_hDiskCacheWriteFile, e->m_DiskCacheOffset, FILE_BEGIN ); + CWin32File::FileRead( m_hDiskCacheWriteFile, e->m_pData, e->m_nCompressedSize ); + } + } + + if ( e->m_nCompressedSize > 0 && e->m_pData != NULL ) + { + ZIP_LocalFileHeader hdr = { 0 }; + hdr.signature = PKID( 3, 4 ); + hdr.versionNeededToExtract = 10; // No special features or even compression here, set to 1.0 +#ifdef ZIP_SUPPORT_LZMA_ENCODE + if ( e->m_eCompressionType == IZip::eCompressionType_LZMA ) + { + // Per ZIP spec 5.8.8 + hdr.versionNeededToExtract = 63; + } +#endif + hdr.flags = 0; + hdr.compressionMethod = e->m_eCompressionType; + hdr.lastModifiedTime = 0; + hdr.lastModifiedDate = 0; + hdr.crc32 = e->m_ZipCRC; + + const char *pFilename = e->m_Name.String(); + hdr.compressedSize = e->m_nCompressedSize; + hdr.uncompressedSize = e->m_nUncompressedSize; + hdr.fileNameLength = strlen( pFilename ); + hdr.extraFieldLength = CalculatePadding( hdr.fileNameLength, e->m_ZipOffset ); + int extraFieldLength = hdr.extraFieldLength; + + // Swap header in place + m_Swap.SwapFieldsToTargetEndian( &hdr ); + stream.Put( &hdr, sizeof( hdr ) ); + stream.Put( pFilename, strlen( pFilename ) ); + stream.Put( pPaddingBuffer, extraFieldLength ); + stream.Put( e->m_pData, e->m_nCompressedSize ); + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { + free( e->m_pData ); + + // temp hackery for the logic below to succeed + e->m_pData = (void*)0xFFFFFFFF; + } + } + } + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { + CWin32File::FileSeek( m_hDiskCacheWriteFile, 0, FILE_END ); + } + + unsigned int centralDirStart = stream.Tell() - zipOffsetInStream; + if ( m_AlignmentSize ) + { + // align the central directory starting position + unsigned int newDirStart = AlignValue( centralDirStart, m_AlignmentSize ); + int padLength = newDirStart - centralDirStart; + if ( padLength ) + { + stream.Put( pPaddingBuffer, padLength ); + centralDirStart = newDirStart; + } + } + + int realNumFiles = 0; + for ( i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) ) + { + CZipEntry *e = &m_Files[i]; + Assert( e ); + + if ( e->m_nCompressedSize > 0 && e->m_pData != NULL ) + { + ZIP_FileHeader hdr = { 0 }; + hdr.signature = PKID( 1, 2 ); + hdr.versionMadeBy = 20; // This is the version that the winzip that I have writes. + hdr.versionNeededToExtract = 10; // No special features or even compression here, set to 1.0 +#ifdef ZIP_SUPPORT_LZMA_ENCODE + if ( e->m_eCompressionType == IZip::eCompressionType_LZMA ) + { + // Per ZIP spec 5.8.8 + hdr.versionNeededToExtract = 63; + } +#endif + hdr.flags = 0; + hdr.compressionMethod = e->m_eCompressionType; + hdr.lastModifiedTime = 0; + hdr.lastModifiedDate = 0; + hdr.crc32 = e->m_ZipCRC; + + hdr.compressedSize = e->m_nCompressedSize; + hdr.uncompressedSize = e->m_nUncompressedSize; + hdr.fileNameLength = strlen( e->m_Name.String() ); + hdr.extraFieldLength = CalculatePadding( hdr.fileNameLength, e->m_ZipOffset ); + hdr.fileCommentLength = 0; + hdr.diskNumberStart = 0; + hdr.internalFileAttribs = 0; + hdr.externalFileAttribs = 0; // This is usually something, but zero is OK as if the input came from stdin + hdr.relativeOffsetOfLocalHeader = e->m_ZipOffset; + int extraFieldLength = hdr.extraFieldLength; + + // Swap the header in place + m_Swap.SwapFieldsToTargetEndian( &hdr ); + stream.Put( &hdr, sizeof( hdr ) ); + stream.Put( e->m_Name.String(), strlen( e->m_Name.String() ) ); + if ( m_bCompatibleFormat ) + { + stream.Put( pPaddingBuffer, extraFieldLength ); + } + + realNumFiles++; + + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) + { + // clear out temp hackery + e->m_pData = NULL; + } + } + } + + unsigned int centralDirEnd = stream.Tell() - zipOffsetInStream; + if ( m_AlignmentSize ) + { + // align the central directory starting position + unsigned int newDirEnd = AlignValue( centralDirEnd, m_AlignmentSize ); + int padLength = newDirEnd - centralDirEnd; + if ( padLength ) + { + stream.Put( pPaddingBuffer, padLength ); + centralDirEnd = newDirEnd; + } + } + + ZIP_EndOfCentralDirRecord rec = { 0 }; + rec.signature = PKID( 5, 6 ); + rec.numberOfThisDisk = 0; + rec.numberOfTheDiskWithStartOfCentralDirectory = 0; + rec.nCentralDirectoryEntries_ThisDisk = realNumFiles; + rec.nCentralDirectoryEntries_Total = realNumFiles; + rec.centralDirectorySize = centralDirEnd - centralDirStart; + rec.startOfCentralDirOffset = centralDirStart; + + char commentString[128]; + int commentLength = MakeXZipCommentString( commentString ); + rec.commentLength = commentLength; + + // Swap the header in place + m_Swap.SwapFieldsToTargetEndian( &rec ); + stream.Put( &rec, sizeof( rec ) ); + stream.Put( commentString, commentLength ); + + if ( pPaddingBuffer ) + { + free( pPaddingBuffer ); + } +} + +class CZip : public IZip +{ +public: + CZip( const char *pDiskCacheWritePath, bool bSortByName ); + virtual ~CZip(); + + virtual void Reset() OVERRIDE; + + // Add a single file to a zip - maintains the zip's previous alignment state + virtual void AddFileToZip( const char *relativename, const char *fullpath, eCompressionType compressionType ) OVERRIDE; + + // Whether a file is contained in a zip - maintains alignment + virtual bool FileExistsInZip( const char *pRelativeName ) OVERRIDE; + + // Reads a file from the zip - maintains alignement + virtual bool ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) OVERRIDE; + virtual bool ReadFileFromZip( HANDLE hZipFile, const char *relativename, bool bTextMode, CUtlBuffer &buf ) OVERRIDE; + + // Removes a single file from the zip - maintains alignment + virtual void RemoveFileFromZip( const char *relativename ) OVERRIDE; + + // Gets next filename in zip, for walking the directory - maintains alignment + virtual int GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ) OVERRIDE; + + // Prints the zip's contents - maintains alignment + virtual void PrintDirectory( void ) OVERRIDE; + + // Estimate the size of the Zip (including header, padding, etc.) + virtual unsigned int EstimateSize( void ) OVERRIDE; + + // Add buffer to zip as a file with given name - uses current alignment size, default 0 (no alignment) + virtual void AddBufferToZip( const char *relativename, void *data, int length, + bool bTextMode, eCompressionType compressionType ) OVERRIDE; + + // Writes out zip file to a buffer - uses current alignment size + // (set by file's previous alignment, or a call to ForceAlignment) + virtual void SaveToBuffer( CUtlBuffer& outbuf ) OVERRIDE; + + // Writes out zip file to a filestream - uses current alignment size + // (set by file's previous alignment, or a call to ForceAlignment) + virtual void SaveToDisk( FILE *fout ) OVERRIDE; + virtual void SaveToDisk( HANDLE hOutFile ) OVERRIDE; + + // Reads a zip file from a buffer into memory - sets current alignment size to + // the file's alignment size, unless overridden by a ForceAlignment call) + virtual void ParseFromBuffer( void *buffer, int bufferlength ) OVERRIDE; + virtual HANDLE ParseFromDisk( const char *pFilename ) OVERRIDE; + + // Forces a specific alignment size for all subsequent file operations, overriding files' previous alignment size. + // Return to using files' individual alignment sizes by passing FALSE. + virtual void ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize ) OVERRIDE; + + // Sets the endianess of the zip + virtual void SetBigEndian( bool bigEndian ) OVERRIDE; + virtual void ActivateByteSwapping( bool bActivate ) OVERRIDE; + + virtual unsigned int GetAlignment() OVERRIDE; + +private: + CZipFile m_ZipFile; +}; + +static CUtlLinkedList< CZip* > g_ZipUtils; + +IZip *IZip::CreateZip( const char *pDiskCacheWritePath, bool bSortByName ) +{ + CZip *pZip = new CZip( pDiskCacheWritePath, bSortByName ); + g_ZipUtils.AddToTail( pZip ); + + return pZip; +} + +void IZip::ReleaseZip( IZip *pZip ) +{ + g_ZipUtils.FindAndRemove( (CZip *)pZip ); + + delete ((CZip *)pZip); +} + +CZip::CZip( const char *pDiskCacheWritePath, bool bSortByName ) : m_ZipFile( pDiskCacheWritePath, bSortByName ) +{ + m_ZipFile.Reset(); +} + +CZip::~CZip() +{ +} + +void CZip::SetBigEndian( bool bigEndian ) +{ + m_ZipFile.SetBigEndian( bigEndian ); +} + +void CZip::ActivateByteSwapping( bool bActivate ) +{ + m_ZipFile.ActivateByteSwapping( bActivate ); +} + +void CZip::AddFileToZip( const char *relativename, const char *fullpath, eCompressionType compressionType ) +{ + m_ZipFile.AddFileToZip( relativename, fullpath, compressionType ); +} + +bool CZip::FileExistsInZip( const char *pRelativeName ) +{ + return m_ZipFile.FileExistsInZip( pRelativeName ); +} + +bool CZip::ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) +{ + return m_ZipFile.ReadFileFromZip( pRelativeName, bTextMode, buf ); +} + +bool CZip::ReadFileFromZip( HANDLE hZipFile, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) +{ + return m_ZipFile.ReadFileFromZip( hZipFile, pRelativeName, bTextMode, buf ); +} + +void CZip::RemoveFileFromZip( const char *relativename ) +{ + m_ZipFile.RemoveFileFromZip( relativename ); +} + +int CZip::GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ) +{ + return m_ZipFile.GetNextFilename( id, pBuffer, bufferSize, fileSize ); +} + +void CZip::PrintDirectory( void ) +{ + m_ZipFile.PrintDirectory(); +} + +void CZip::Reset() +{ + m_ZipFile.Reset(); +} + +unsigned int CZip::EstimateSize( void ) +{ + return m_ZipFile.CalculateSize(); +} + +// Add buffer to zip as a file with given name +void CZip::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, eCompressionType compressionType ) +{ + m_ZipFile.AddBufferToZip( relativename, data, length, bTextMode, compressionType ); +} + +void CZip::SaveToBuffer( CUtlBuffer& outbuf ) +{ + m_ZipFile.SaveToBuffer( outbuf ); +} + +void CZip::SaveToDisk( FILE *fout ) +{ + m_ZipFile.SaveToDisk( fout ); +} + +void CZip::SaveToDisk( HANDLE hOutFile ) +{ + m_ZipFile.SaveToDisk( hOutFile ); +} + +void CZip::ParseFromBuffer( void *buffer, int bufferlength ) +{ + m_ZipFile.Reset(); + m_ZipFile.ParseFromBuffer( buffer, bufferlength ); +} + +HANDLE CZip::ParseFromDisk( const char *pFilename ) +{ + m_ZipFile.Reset(); + return m_ZipFile.ParseFromDisk( pFilename ); +} + +void CZip::ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize ) +{ + m_ZipFile.ForceAlignment( aligned, bCompatibleFormat, alignmentSize ); +} + +unsigned int CZip::GetAlignment() +{ + return m_ZipFile.GetAlignment(); +} + diff --git a/public/zip_utils.h b/public/zip_utils.h new file mode 100644 index 0000000..2ac2005 --- /dev/null +++ b/public/zip_utils.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ZIP_UTILS_H +#define ZIP_UTILS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlsymbol.h" + +class CUtlBuffer; +#include "tier0/dbg.h" + +abstract_class IZip +{ +public: + enum eCompressionType + { + // Type of compression used for this file in the zip + eCompressionType_Unknown = -1, + eCompressionType_None = 0, + eCompressionType_LZMA = 14 + }; + virtual void Reset() = 0; + + // Add a single file to a zip - maintains the zip's previous alignment state. + virtual void AddFileToZip ( const char *relativename, const char *fullpath, eCompressionType compressionType = eCompressionType_None ) = 0; + + // Whether a file is contained in a zip - maintains alignment + virtual bool FileExistsInZip ( const char *pRelativeName ) = 0; + + // Reads a file from the zip - maintains alignement. + virtual bool ReadFileFromZip ( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) = 0; + virtual bool ReadFileFromZip ( HANDLE hFile, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) = 0; + + // Removes a single file from the zip - maintains alignment + virtual void RemoveFileFromZip ( const char *relativename ) = 0; + + // Gets next filename in zip, for walking the directory - maintains alignment + virtual int GetNextFilename ( int id, char *pBuffer, int bufferSize, int &fileSize ) = 0; + + // Prints the zip's contents - maintains alignment + virtual void PrintDirectory ( void ) = 0; + + // Estimate the size of the Zip (including header, padding, etc.) + virtual unsigned int EstimateSize ( void ) = 0; + + // Add buffer to zip as a file with given name - uses current alignment size, default 0 (no alignment) + virtual void AddBufferToZip ( const char *relativename, void *data, int length, bool bTextMode, eCompressionType compressionType = eCompressionType_None ) = 0; + + // Writes out zip file to a buffer - uses current alignment size + // (set by file's previous alignment, or a call to ForceAlignment) + virtual void SaveToBuffer ( CUtlBuffer& outbuf ) = 0; + + // Writes out zip file to a filestream - uses current alignment size + // (set by file's previous alignment, or a call to ForceAlignment) + virtual void SaveToDisk ( FILE *fout ) = 0; + virtual void SaveToDisk ( HANDLE hFileOut ) = 0; + + // Reads a zip file from a buffer into memory - sets current alignment size to + // the file's alignment size, unless overridden by a ForceAlignment call) + virtual void ParseFromBuffer ( void *buffer, int bufferlength ) = 0; + + // Mounts a zip file from the disk + // Only ReadFileFromZip() is supported because the zip file could be >2GB + virtual HANDLE ParseFromDisk ( const char *pFilename ) = 0; + + // Forces a specific alignment size for all subsequent file operations, overriding files' previous alignment size. + // Return to using files' individual alignment sizes by passing FALSE. + virtual void ForceAlignment ( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize=0 ) = 0; + + virtual unsigned int GetAlignment() = 0; + + // Sets the endianess of the zip + virtual void SetBigEndian( bool bigEndian ) = 0; + virtual void ActivateByteSwapping( bool bActivate ) = 0; + + // Create/Release additional instances + // Disk Caching is necessary for large zips + static IZip *CreateZip( const char *pDiskCacheWritePath = NULL, bool bSortByName = false ); + static void ReleaseZip( IZip *zip ); +}; + +#endif // ZIP_UTILS_H diff --git a/raytrace/raytrace.cpp b/raytrace/raytrace.cpp new file mode 100644 index 0000000..45aa500 --- /dev/null +++ b/raytrace/raytrace.cpp @@ -0,0 +1,901 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// $Id$ + +#include "raytrace.h" +#include +#include +#include + +static bool SameSign(float a, float b) +{ + int32 aa=*((int *) &a); + int32 bb=*((int *) &b); + return ((aa^bb)&0x80000000)==0; +} + +int FourRays::CalculateDirectionSignMask(void) const +{ + // this code treats the floats as integers since all it cares about is the sign bit and + // floating point compares suck. + + int ret; + int ormask; + int andmask; + int32 const *treat_as_int=((int32 const *) (&direction)); + + ormask=andmask=*(treat_as_int++); + ormask|=*treat_as_int; + andmask&=*(treat_as_int++); + ormask|=*(treat_as_int); + andmask&=*(treat_as_int++); + ormask|=*(treat_as_int); + andmask&=*(treat_as_int++); + if (ormask>=0) + ret=0; + else + { + if (andmask<0) + ret=1; + else return -1; + } + ormask=andmask=*(treat_as_int++); + ormask|=*treat_as_int; + andmask&=*(treat_as_int++); + ormask|=*(treat_as_int); + andmask&=*(treat_as_int++); + ormask|=*(treat_as_int); + andmask&=*(treat_as_int++); + if (ormask<0) + { + if (andmask<0) + ret|=2; + else return -1; + } + ormask=andmask=*(treat_as_int++); + ormask|=*treat_as_int; + andmask&=*(treat_as_int++); + ormask|=*(treat_as_int); + andmask&=*(treat_as_int++); + ormask|=*(treat_as_int); + andmask&=*(treat_as_int++); + if (ormask<0) + { + if (andmask<0) + ret|=4; + else return -1; + } + return ret; +} + + + + +void RayTracingEnvironment::MakeRoomForTriangles( int ntris ) +{ + //OptimizedTriangleList.EnsureCapacity( ntris ); + if (! (Flags & RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS)) + TriangleColors.EnsureCapacity( ntris ); +} + + +void RayTracingEnvironment::AddTriangle(int32 id, const Vector &v1, + const Vector &v2, const Vector &v3, + const Vector &color) +{ + AddTriangle( id, v1, v2, v3, color, 0, 0 ); +} + +void RayTracingEnvironment::AddTriangle(int32 id, const Vector &v1, + const Vector &v2, const Vector &v3, + const Vector &color, uint16 flags, int32 materialIndex) +{ + CacheOptimizedTriangle tmptri; + tmptri.m_Data.m_GeometryData.m_nTriangleID = id; + tmptri.Vertex( 0 ) = v1; + tmptri.Vertex( 1 ) = v2; + tmptri.Vertex( 2 ) = v3; + tmptri.m_Data.m_GeometryData.m_nFlags = flags; + OptimizedTriangleList.AddToTail(tmptri); + if (! ( Flags & RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS) ) + TriangleColors.AddToTail(color); + if ( !( Flags & RTE_FLAGS_DONT_STORE_TRIANGLE_MATERIALS) ) + TriangleMaterials.AddToTail(materialIndex); +// printf("add triange from (%f %f %f),(%f %f %f),(%f %f %f) id %d\n", +// XYZ(v1),XYZ(v2),XYZ(v3),id); +} + +void RayTracingEnvironment::AddQuad( + int32 id, const Vector &v1, const Vector &v2, const Vector &v3, + const Vector &v4, // specify vertices in cw or ccw order + const Vector &color) +{ + AddTriangle(id,v1,v2,v3,color); + AddTriangle(id+1,v1,v3,v4,color); +} + + +void RayTracingEnvironment::AddAxisAlignedRectangularSolid(int id,Vector minc, Vector maxc, + const Vector &color) +{ + + // "far" face + AddQuad(id, + Vector(minc.x,maxc.y,maxc.z), + Vector(maxc.x,maxc.y,maxc.z),Vector(maxc.x,minc.y,maxc.z), + Vector(minc.x,minc.y,maxc.z),color); + // "near" face + AddQuad(id, + Vector(minc.x,maxc.y,minc.z), + Vector(maxc.x,maxc.y,minc.z),Vector(maxc.x,minc.y,minc.z), + Vector(minc.x,minc.y,minc.z),color); + + // "left" face + AddQuad(id, + Vector(minc.x,maxc.y,maxc.z), + Vector(minc.x,maxc.y,minc.z), + Vector(minc.x,minc.y,minc.z), + Vector(minc.x,minc.y,maxc.z),color); + // "right" face + AddQuad(id, + Vector(maxc.x,maxc.y,maxc.z), + Vector(maxc.x,maxc.y,minc.z), + Vector(maxc.x,minc.y,minc.z), + Vector(maxc.x,minc.y,maxc.z),color); + + // "top" face + AddQuad(id, + Vector(minc.x,maxc.y,maxc.z), + Vector(maxc.x,maxc.y,maxc.z), + Vector(maxc.x,maxc.y,minc.z), + Vector(minc.x,maxc.y,minc.z),color); + // "bot" face + AddQuad(id, + Vector(minc.x,minc.y,maxc.z), + Vector(maxc.x,minc.y,maxc.z), + Vector(maxc.x,minc.y,minc.z), + Vector(minc.x,minc.y,minc.z),color); +} + + + +static Vector GetEdgeEquation(Vector p1, Vector p2, int c1, int c2, Vector InsidePoint) +{ + float nx=p1[c2]-p2[c2]; + float ny=p2[c1]-p1[c1]; + float d=-(nx*p1[c1]+ny*p1[c2]); +// assert(fabs(nx*p1[c1]+ny*p1[c2]+d)<0.01); +// assert(fabs(nx*p2[c1]+ny*p2[c2]+d)<0.01); + + // use the convention that negative is "outside" + float trial_dist=InsidePoint[c1]*nx+InsidePoint[c2]*ny+d; + if (trial_dist<0) + { + nx = -nx; + ny = -ny; + d = -d; + trial_dist = -trial_dist; + } + nx /= trial_dist; // scale so that it will be =1.0 at the oppositve vertex + ny /= trial_dist; + d /= trial_dist; + + return Vector(nx,ny,d); +} + +void CacheOptimizedTriangle::ChangeIntoIntersectionFormat(void) +{ + // lose the vertices and use edge equations instead + + // grab the whole original triangle to we don't overwrite it + TriGeometryData_t srcTri = m_Data.m_GeometryData; + + m_Data.m_IntersectData.m_nFlags = srcTri.m_nFlags; + m_Data.m_IntersectData.m_nTriangleID = srcTri.m_nTriangleID; + + Vector p1 = srcTri.Vertex( 0 ); + Vector p2 = srcTri.Vertex( 1 ); + Vector p3 = srcTri.Vertex( 2 ); + + Vector e1 = p2 - p1; + Vector e2 = p3 - p1; + + Vector N = e1.Cross( e2 ); + N.NormalizeInPlace(); + // now, determine which axis to drop + int drop_axis = 0; + for(int c=1 ; c<3 ; c++) + if ( fabs(N[c]) > fabs( N[drop_axis] ) ) + drop_axis = c; + + m_Data.m_IntersectData.m_flD = N.Dot( p1 ); + m_Data.m_IntersectData.m_flNx = N.x; + m_Data.m_IntersectData.m_flNy = N.y; + m_Data.m_IntersectData.m_flNz = N.z; + + // decide which axes to keep + int nCoordSelect0 = ( drop_axis + 1 ) % 3; + int nCoordSelect1 = ( drop_axis + 2 ) % 3; + + m_Data.m_IntersectData.m_nCoordSelect0 = nCoordSelect0; + m_Data.m_IntersectData.m_nCoordSelect1 = nCoordSelect1; + + + Vector edge1 = GetEdgeEquation( p1, p2, nCoordSelect0, nCoordSelect1, p3 ); + m_Data.m_IntersectData.m_ProjectedEdgeEquations[0] = edge1.x; + m_Data.m_IntersectData.m_ProjectedEdgeEquations[1] = edge1.y; + m_Data.m_IntersectData.m_ProjectedEdgeEquations[2] = edge1.z; + + Vector edge2 = GetEdgeEquation( p2, p3, nCoordSelect0, nCoordSelect1, p1 ); + m_Data.m_IntersectData.m_ProjectedEdgeEquations[3] = edge2.x; + m_Data.m_IntersectData.m_ProjectedEdgeEquations[4] = edge2.y; + m_Data.m_IntersectData.m_ProjectedEdgeEquations[5] = edge2.z; + + +} + +int n_intersection_calculations=0; + +int CacheOptimizedTriangle::ClassifyAgainstAxisSplit(int split_plane, float split_value) +{ + // classify a triangle against an axis-aligned plane + float minc=Vertex(0)[split_plane]; + float maxc=minc; + for(int v=1;v<3;v++) + { + minc=vmin(minc,Vertex(v)[split_plane]); + maxc=vmax(maxc,Vertex(v)[split_plane]); + } + + if (minc>=split_value) + return PLANECHECK_POSITIVE; + if (maxc<=split_value) + return PLANECHECK_NEGATIVE; + if (minc==maxc) + return PLANECHECK_POSITIVE; + return PLANECHECK_STRADDLING; +} + +#define MAILBOX_HASH_SIZE 256 +#define MAX_TREE_DEPTH 21 +#define MAX_NODE_STACK_LEN (40*MAX_TREE_DEPTH) + +struct NodeToVisit { + CacheOptimizedKDNode const *node; + fltx4 TMin; + fltx4 TMax; +}; + + +static fltx4 FourEpsilons={1.0e-10,1.0e-10,1.0e-10,1.0e-10}; +static fltx4 FourZeros={1.0e-10,1.0e-10,1.0e-10,1.0e-10}; +static fltx4 FourNegativeEpsilons={-1.0e-10,-1.0e-10,-1.0e-10,-1.0e-10}; + +static float BoxSurfaceArea(Vector const &boxmin, Vector const &boxmax) +{ + Vector boxdim=boxmax-boxmin; + return 2.0*((boxdim[0]*boxdim[2])+(boxdim[0]*boxdim[1])+(boxdim[1]*boxdim[2])); +} + +void RayTracingEnvironment::Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax, + RayTracingResult *rslt_out, + int32 skip_id, ITransparentTriangleCallback *pCallback) +{ + int msk=rays.CalculateDirectionSignMask(); + if (msk!=-1) + Trace4Rays(rays,TMin,TMax,msk,rslt_out,skip_id, pCallback); + else + { + // sucky case - can't trace 4 rays at once. in the worst case, need to trace all 4 + // separately, but usually we will still get 2x, Since our tracer only does 4 at a + // time, we will have to cover up the undesired rays with the desired ray + + //!! speed!! there is room for some sse-ization here + FourRays tmprays; + tmprays.origin=rays.origin; + + uint8 need_trace[4]={1,1,1,1}; + for(int try_trace=0;try_trace<4;try_trace++) + { + if (need_trace[try_trace]) + { + need_trace[try_trace]=2; // going to trace it + // replicate the ray being traced into all 4 rays + tmprays.direction.x=ReplicateX4(rays.direction.X(try_trace)); + tmprays.direction.y=ReplicateX4(rays.direction.Y(try_trace)); + tmprays.direction.z=ReplicateX4(rays.direction.Z(try_trace)); + // now, see if any of the other remaining rays can be handled at the same time. + for(int try2=try_trace+1;try2<4;try2++) + if (need_trace[try2]) + { + if ( + SameSign(rays.direction.X(try2), + rays.direction.X(try_trace)) && + SameSign(rays.direction.Y(try2), + rays.direction.Y(try_trace)) && + SameSign(rays.direction.Z(try2), + rays.direction.Z(try_trace))) + { + need_trace[try2]=2; + tmprays.direction.X(try2) = rays.direction.X(try2); + tmprays.direction.Y(try2) = rays.direction.Y(try2); + tmprays.direction.Z(try2) = rays.direction.Z(try2); + } + } + // ok, now trace between 1 and 3 rays, and output the results + RayTracingResult tmpresults; + msk=tmprays.CalculateDirectionSignMask(); + assert(msk!=-1); + Trace4Rays(tmprays,TMin,TMax,msk,&tmpresults,skip_id, pCallback); + // now, move results to proper place + for(int i=0;i<4;i++) + if (need_trace[i]==2) + { + need_trace[i]=0; + rslt_out->HitIds[i]=tmpresults.HitIds[i]; + SubFloat(rslt_out->HitDistance, i) = SubFloat(tmpresults.HitDistance, i); + rslt_out->surface_normal.X(i) = tmpresults.surface_normal.X(i); + rslt_out->surface_normal.Y(i) = tmpresults.surface_normal.Y(i); + rslt_out->surface_normal.Z(i) = tmpresults.surface_normal.Z(i); + } + + } + } + } +} + + +void RayTracingEnvironment::Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax, + int DirectionSignMask, RayTracingResult *rslt_out, + int32 skip_id, ITransparentTriangleCallback *pCallback) +{ + rays.Check(); + + memset(rslt_out->HitIds,0xff,sizeof(rslt_out->HitIds)); + + rslt_out->HitDistance=ReplicateX4(1.0e23); + + rslt_out->surface_normal.DuplicateVector(Vector(0.,0.,0.)); + FourVectors OneOverRayDir=rays.direction; + OneOverRayDir.MakeReciprocalSaturate(); + + // now, clip rays against bounding box + for(int c=0;c<3;c++) + { + fltx4 isect_min_t= + MulSIMD(SubSIMD(ReplicateX4(m_MinBound[c]),rays.origin[c]),OneOverRayDir[c]); + fltx4 isect_max_t= + MulSIMD(SubSIMD(ReplicateX4(m_MaxBound[c]),rays.origin[c]),OneOverRayDir[c]); + TMin=MaxSIMD(TMin,MinSIMD(isect_min_t,isect_max_t)); + TMax=MinSIMD(TMax,MaxSIMD(isect_min_t,isect_max_t)); + } + fltx4 active=CmpLeSIMD(TMin,TMax); // mask of which rays are active + if (! IsAnyNegative(active) ) + return; // missed bounding box + + int32 mailboxids[MAILBOX_HASH_SIZE]; // used to avoid redundant triangle tests + memset(mailboxids,0xff,sizeof(mailboxids)); // !!speed!! keep around? + + int front_idx[3],back_idx[3]; // based on ray direction, whether to + // visit left or right node first + + if (DirectionSignMask & 1) + { + back_idx[0]=0; + front_idx[0]=1; + } + else + { + back_idx[0]=1; + front_idx[0]=0; + } + if (DirectionSignMask & 2) + { + back_idx[1]=0; + front_idx[1]=1; + } + else + { + back_idx[1]=1; + front_idx[1]=0; + } + if (DirectionSignMask & 4) + { + back_idx[2]=0; + front_idx[2]=1; + } + else + { + back_idx[2]=1; + front_idx[2]=0; + } + + NodeToVisit NodeQueue[MAX_NODE_STACK_LEN]; + CacheOptimizedKDNode const *CurNode=&(OptimizedKDTree[0]); + NodeToVisit *stack_ptr=&NodeQueue[MAX_NODE_STACK_LEN]; + while(1) + { + while (CurNode->NodeType() != KDNODE_STATE_LEAF) // traverse until next leaf + { + int split_plane_number=CurNode->NodeType(); + CacheOptimizedKDNode const *FrontChild=&(OptimizedKDTree[CurNode->LeftChild()]); + + fltx4 dist_to_sep_plane= // dist=(split-org)/dir + MulSIMD( + SubSIMD(ReplicateX4(CurNode->SplittingPlaneValue), + rays.origin[split_plane_number]),OneOverRayDir[split_plane_number]); + fltx4 active=CmpLeSIMD(TMin,TMax); // mask of which rays are active + + // now, decide how to traverse children. can either do front,back, or do front and push + // back. + fltx4 hits_front=AndSIMD(active,CmpGeSIMD(dist_to_sep_plane,TMin)); + if (! IsAnyNegative(hits_front)) + { + // missed the front. only traverse back + //printf("only visit back %d\n",CurNode->LeftChild()+back_idx[split_plane_number]); + CurNode=FrontChild+back_idx[split_plane_number]; + TMin=MaxSIMD(TMin, dist_to_sep_plane); + + } + else + { + fltx4 hits_back=AndSIMD(active,CmpLeSIMD(dist_to_sep_plane,TMax)); + if (! IsAnyNegative(hits_back) ) + { + // missed the back - only need to traverse front node + //printf("only visit front %d\n",CurNode->LeftChild()+front_idx[split_plane_number]); + CurNode=FrontChild+front_idx[split_plane_number]; + TMax=MinSIMD(TMax, dist_to_sep_plane); + } + else + { + // at least some rays hit both nodes. + // must push far, traverse near + //printf("visit %d,%d\n",CurNode->LeftChild()+front_idx[split_plane_number], + // CurNode->LeftChild()+back_idx[split_plane_number]); + assert(stack_ptr>NodeQueue); + --stack_ptr; + stack_ptr->node=FrontChild+back_idx[split_plane_number]; + stack_ptr->TMin=MaxSIMD(TMin,dist_to_sep_plane); + stack_ptr->TMax=TMax; + CurNode=FrontChild+front_idx[split_plane_number]; + TMax=MinSIMD(TMax,dist_to_sep_plane); + } + } + } + // hit a leaf! must do intersection check + int ntris=CurNode->NumberOfTrianglesInLeaf(); + if (ntris) + { + int32 const *tlist=&(TriangleIndexList[CurNode->TriangleIndexStart()]); + do + { + int tnum=*(tlist++); + //printf("try tri %d\n",tnum); + // check mailbox + int mbox_slot=tnum & (MAILBOX_HASH_SIZE-1); + TriIntersectData_t const *tri = &( OptimizedTriangleList[tnum].m_Data.m_IntersectData ); + if ( ( mailboxids[mbox_slot] != tnum ) && ( tri->m_nTriangleID != skip_id ) ) + { + n_intersection_calculations++; + mailboxids[mbox_slot] = tnum; + // compute plane intersection + + + FourVectors N; + N.x = ReplicateX4( tri->m_flNx ); + N.y = ReplicateX4( tri->m_flNy ); + N.z = ReplicateX4( tri->m_flNz ); + + fltx4 DDotN = rays.direction * N; + // mask off zero or near zero (ray parallel to surface) + fltx4 did_hit = OrSIMD( CmpGtSIMD( DDotN,FourEpsilons ), + CmpLtSIMD( DDotN, FourNegativeEpsilons ) ); + + fltx4 numerator=SubSIMD( ReplicateX4( tri->m_flD ), rays.origin * N ); + + fltx4 isect_t=DivSIMD( numerator,DDotN ); + // now, we have the distance to the plane. lets update our mask + did_hit = AndSIMD( did_hit, CmpGtSIMD( isect_t, FourZeros ) ); + //did_hit=AndSIMD(did_hit,CmpLtSIMD(isect_t,TMax)); + did_hit = AndSIMD( did_hit, CmpLtSIMD( isect_t, rslt_out->HitDistance ) ); + + if ( ! IsAnyNegative( did_hit ) ) + continue; + + // now, check 3 edges + fltx4 hitc1 = AddSIMD( rays.origin[tri->m_nCoordSelect0], + MulSIMD( isect_t, rays.direction[ tri->m_nCoordSelect0] ) ); + fltx4 hitc2 = AddSIMD( rays.origin[tri->m_nCoordSelect1], + MulSIMD( isect_t, rays.direction[tri->m_nCoordSelect1] ) ); + + // do barycentric coordinate check + fltx4 B0 = MulSIMD( ReplicateX4( tri->m_ProjectedEdgeEquations[0] ), hitc1 ); + + B0 = AddSIMD( + B0, + MulSIMD( ReplicateX4( tri->m_ProjectedEdgeEquations[1] ), hitc2 ) ); + B0 = AddSIMD( + B0, ReplicateX4( tri->m_ProjectedEdgeEquations[2] ) ); + + did_hit = AndSIMD( did_hit, CmpGeSIMD( B0, FourZeros ) ); + + fltx4 B1 = MulSIMD( ReplicateX4( tri->m_ProjectedEdgeEquations[3] ), hitc1 ); + B1 = AddSIMD( + B1, + MulSIMD( ReplicateX4( tri->m_ProjectedEdgeEquations[4]), hitc2 ) ); + + B1 = AddSIMD( + B1, ReplicateX4( tri->m_ProjectedEdgeEquations[5] ) ); + + did_hit = AndSIMD( did_hit, CmpGeSIMD( B1, FourZeros ) ); + + fltx4 B2 = AddSIMD( B1, B0 ); + did_hit = AndSIMD( did_hit, CmpLeSIMD( B2, Four_Ones ) ); + + if ( ! IsAnyNegative( did_hit ) ) + continue; + + // if the triangle is transparent + if ( tri->m_nFlags & FCACHETRI_TRANSPARENT ) + { + if ( pCallback ) + { + // assuming a triangle indexed as v0, v1, v2 + // the projected edge equations are set up such that the vert opposite the first + // equation is v2, and the vert opposite the second equation is v0 + // Therefore we pass them back in 1, 2, 0 order + // Also B2 is currently B1 + B0 and needs to be 1 - (B1+B0) in order to be a real + // barycentric coordinate. Compute that now and pass it to the callback + fltx4 b2 = SubSIMD( Four_Ones, B2 ); + if ( pCallback->VisitTriangle_ShouldContinue( *tri, rays, &did_hit, &B1, &b2, &B0, tnum ) ) + { + did_hit = Four_Zeros; + } + } + } + // now, set the hit_id and closest_hit fields for any enabled rays + fltx4 replicated_n = ReplicateIX4(tnum); + StoreAlignedSIMD((float *) rslt_out->HitIds, + OrSIMD(AndSIMD(replicated_n,did_hit), + AndNotSIMD(did_hit,LoadAlignedSIMD( + (float *) rslt_out->HitIds)))); + rslt_out->HitDistance=OrSIMD(AndSIMD(isect_t,did_hit), + AndNotSIMD(did_hit,rslt_out->HitDistance)); + + rslt_out->surface_normal.x=OrSIMD( + AndSIMD(N.x,did_hit), + AndNotSIMD(did_hit,rslt_out->surface_normal.x)); + rslt_out->surface_normal.y=OrSIMD( + AndSIMD(N.y,did_hit), + AndNotSIMD(did_hit,rslt_out->surface_normal.y)); + rslt_out->surface_normal.z=OrSIMD( + AndSIMD(N.z,did_hit), + AndNotSIMD(did_hit,rslt_out->surface_normal.z)); + + } + } while (--ntris); + // now, check if all rays have terminated + fltx4 raydone=CmpLeSIMD(TMax,rslt_out->HitDistance); + if (! IsAnyNegative(raydone)) + { + return; + } + } + + if (stack_ptr==&NodeQueue[MAX_NODE_STACK_LEN]) + { + return; + } + // pop stack! + CurNode=stack_ptr->node; + TMin=stack_ptr->TMin; + TMax=stack_ptr->TMax; + stack_ptr++; + } +} + + +int RayTracingEnvironment::MakeLeafNode(int first_tri, int last_tri) +{ + CacheOptimizedKDNode ret; + ret.Children=KDNODE_STATE_LEAF+(TriangleIndexList.Count()<<2); + ret.SetNumberOfTrianglesInLeafNode(1+(last_tri-first_tri)); + for(int tnum=first_tri;tnum<=last_tri;tnum++) + TriangleIndexList.AddToTail(tnum); + OptimizedKDTree.AddToTail(ret); + return OptimizedKDTree.Count()-1; +} + + +void RayTracingEnvironment::CalculateTriangleListBounds(int32 const *tris,int ntris, + Vector &minout, Vector &maxout) +{ + minout = Vector( 1.0e23, 1.0e23, 1.0e23); + maxout = Vector( -1.0e23, -1.0e23, -1.0e23); + for(int i=0; iMaxBound[axis]) || (trial_splitvalueMAX_TREE_DEPTH)) + { + // no benefit to splitting. just make this a leaf node + OptimizedKDTree[node_number].Children=KDNODE_STATE_LEAF+(TriangleIndexList.Count()<<2); + OptimizedKDTree[node_number].SetNumberOfTrianglesInLeafNode(ntris); +#ifdef DEBUG_RAYTRACE + OptimizedKDTree[node_number].vecMins = MinBound; + OptimizedKDTree[node_number].vecMaxs = MaxBound; +#endif + for(int t=0;t + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {11415D16-55D1-4D9D-B8F2-3D5BFF780E6B} + raytrace + 10.0 + + + + Application + true + v142 + MultiByte + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + StaticLibrary + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\lib\public + + + + Level3 + Disabled + true + + + true + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + ..\common;..\public;..\public\tier0;..\public\tier1;..\utils\common + Speed + RAD_TELEMETRY_DISABLED;WIN64;_WIN64;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_ALLOW_RUNTIME_LIBRARY_MISMATCH;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_MSC_VER_MISMATCH;%(PreprocessorDefinitions);COMPILER_MSVC64;COMPILER_MSVC;_DLL_EXT=.dll;LIBNAME=raytrace;BINK_VIDEO;AVI_VIDEO;WMV_VIDEO;DEV_BUILD;FRAME_POINTER_OMISSION_DISABLED;_EXTERNAL_DLL_EXT=.dll;VPCGAMECAPS=GMOD;PROJECTDIR=..\;VPCGAME=gmod;SOURCE1=1 + Fast + + + true + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/raytrace/raytrace.vcxproj.filters b/raytrace/raytrace.vcxproj.filters new file mode 100644 index 0000000..7385a2b --- /dev/null +++ b/raytrace/raytrace.vcxproj.filters @@ -0,0 +1,28 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/raytrace/trace2.cpp b/raytrace/trace2.cpp new file mode 100644 index 0000000..b0067a0 --- /dev/null +++ b/raytrace/trace2.cpp @@ -0,0 +1,376 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// $Id$ +#include "raytrace.h" +#include + +static uint32 MapDistanceToPixel(float t) +{ + if (t<0) return 0xffff0000; + if (t>100) return 0xff000000; + int a=(int)(t*1000.0f); a&=0xff; + int b=(int)(t*10.0f); b &=0xff; + int c=(int)(t*.01f); c &=0xff; + return 0xff000000+(a<<16)+(b<<8)+c; +} + +#define IGAMMA (1.0/2.2) + +#define MAGIC_NUMBER (1<<23) + +static fltx4 Four_MagicNumbers={ MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER }; +static ALIGN16 int32 Four_255s[4]= {0xff,0xff,0xff,0xff}; +#define PIXMASK ( * ( reinterpret_cast< fltx4 *>( &Four_255s ) ) ) + +void MapLinearIntensities(FourVectors const &intens,uint32 *p1, uint32 *p2, uint32 *p3, uint32 *p4) +{ + // convert four pixels worth of sse-style rgb into argb lwords + // NOTE the _mm_empty macro is voodoo. do not mess with this routine casually - simply throwing + // anything that ends up generating a fpu stack references in here would be bad news. + static fltx4 pixscale={255.0,255.0,255.0,255.0}; + fltx4 r,g,b; + r=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.x,IGAMMA))); + g=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.y,IGAMMA))); + b=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.z,IGAMMA))); + // now, convert to integer + r=AndSIMD( AddSIMD( r, Four_MagicNumbers ), PIXMASK ); + g=AndSIMD( AddSIMD( g, Four_MagicNumbers ), PIXMASK ); + b=AndSIMD( AddSIMD( b, Four_MagicNumbers ), PIXMASK ); + + *(p1)=(SubInt(r, 0))|(SubInt(g, 0)<<8)|(SubInt(b, 0)<<16); + *(p2)=(SubInt(r, 1))|(SubInt(g, 1)<<8)|(SubInt(b, 1)<<16); + *(p3)=(SubInt(r, 2))|(SubInt(g, 2)<<8)|(SubInt(b, 2)<<16); + *(p4)=(SubInt(r, 3))|(SubInt(g, 3)<<8)|(SubInt(b, 3)<<16); +} + +static ALIGN16 int32 signmask[4]={0x80000000,0x80000000,0x80000000,0x80000000}; +static ALIGN16 int32 all_ones[4]={-1,-1,-1,-1}; +static fltx4 all_zeros={0,0,0,0}; +static fltx4 TraceLimit={1.0e20,1.0e20,1.0e20,1.0e20}; + +void RayTracingEnvironment::RenderScene( + int width, int height, // width and height of desired rendering + int stride, // actual width in pixels of target buffer + uint32 *output_buffer, // pointer to destination + Vector CameraOrigin, // eye position + Vector ULCorner, // word space coordinates of upper left + // monitor corner + Vector URCorner, // top right corner + Vector LLCorner, // lower left + Vector LRCorner, // lower right + RayTraceLightingMode_t lmode) +{ + // first, compute deltas + Vector dxvector=URCorner; + dxvector-=ULCorner; + dxvector*=(1.0f/width); + Vector dxvectortimes2=dxvector; + dxvectortimes2+=dxvector; + + Vector dyvector=LLCorner; + dyvector-=ULCorner; + dyvector*=(1.0f/height); + + + // block_offsets-relative offsets for eahc of the 4 pixels in the block, in sse format + FourVectors block_offsets; + block_offsets.LoadAndSwizzle(Vector(0,0,0),dxvector,dyvector,dxvector+dyvector); + + FourRays myrays; + myrays.origin.DuplicateVector(CameraOrigin); + + // tmprays is used fo rthe case when we cannot trace 4 rays at once. + FourRays tmprays; + tmprays.origin.DuplicateVector(CameraOrigin); + + // now, we will ray trace pixels. we will do the rays in a 2x2 pattern + for(int y=0;y=0) + { + surf_colors.X(i)=TriangleColors[rslt.HitIds[i]].x; + surf_colors.Y(i)=TriangleColors[rslt.HitIds[i]].y; + surf_colors.Z(i)=TriangleColors[rslt.HitIds[i]].z; + } + + } + FourVectors surface_pos=myrays.direction; + surface_pos*=rslt.HitDistance; + surface_pos+=myrays.origin; + + switch(lmode) + { + case DIRECT_LIGHTING: + { + // light all points + for(int l=0;l0) + { + l1.m_Color*=area_of_virtual_light/(float)M_PI; + l1.m_Range=0.0; + l1.m_Falloff=1.0; + l1.m_Attenuation0=1.0; + l1.m_Attenuation1=0.0; + l1.m_Attenuation2=1.0; // intens falls off as 1/r^2 + l1.m_Theta=0; + l1.m_Phi = (float)M_PI; + l1.RecalculateDerivedValues(); + LightList.AddToTail(l1); + } + } + } + } + } + } +} + + + +static unsigned int GetSignMask(Vector const &v) +{ + unsigned int ret=0; + if (v.x<0.0) + ret++; + if (v.y<0) + ret+=2; + if (v.z<0) + ret+=4; + return ret; +} + + +inline void RayTracingEnvironment::FlushStreamEntry(RayStream &s,int msk) +{ + assert(msk>=0); + assert(msk<8); + fltx4 tmax=s.PendingRays[msk].direction.length(); + fltx4 scl=ReciprocalSaturateSIMD(tmax); + s.PendingRays[msk].direction*=scl; // normalize + RayTracingResult tmpresult; + Trace4Rays(s.PendingRays[msk],Four_Zeros,tmax,msk,&tmpresult); + // now, write out results + for(int r=0;r<4;r++) + { + RayTracingSingleResult *out=s.PendingStreamOutputs[msk][r]; + out->ray_length=SubFloat( tmax, r ); + out->surface_normal.x=tmpresult.surface_normal.X(r); + out->surface_normal.y=tmpresult.surface_normal.Y(r); + out->surface_normal.z=tmpresult.surface_normal.Z(r); + out->HitID=tmpresult.HitIds[r]; + out->HitDistance=SubFloat( tmpresult.HitDistance, r ); + } + s.n_in_stream[msk]=0; +} + +void RayTracingEnvironment::AddToRayStream(RayStream &s, + Vector const &start,Vector const &end, + RayTracingSingleResult *rslt_out) +{ + Vector delta=end; + delta-=start; + int msk=GetSignMask(delta); + assert(msk>=0); + assert(msk<8); + int pos=s.n_in_stream[msk]; + assert(pos<4); + s.PendingRays[msk].origin.X(pos)=start.x; + s.PendingRays[msk].origin.Y(pos)=start.y; + s.PendingRays[msk].origin.Z(pos)=start.z; + s.PendingRays[msk].direction.X(pos)=delta.x; + s.PendingRays[msk].direction.Y(pos)=delta.y; + s.PendingRays[msk].direction.Z(pos)=delta.z; + s.PendingStreamOutputs[msk][pos]=rslt_out; + if (pos==3) + { + FlushStreamEntry(s,msk); + } + else + s.n_in_stream[msk]++; +} + +void RayTracingEnvironment::FinishRayStream(RayStream &s) +{ + for(int msk=0;msk<8;msk++) + { + int cnt=s.n_in_stream[msk]; + if (cnt) + { + // fill in unfilled entries with dups of first + for(int c=cnt;c<4;c++) + { + s.PendingRays[msk].origin.X(c) = s.PendingRays[msk].origin.X(0); + s.PendingRays[msk].origin.Y(c) = s.PendingRays[msk].origin.Y(0); + s.PendingRays[msk].origin.Z(c) = s.PendingRays[msk].origin.Z(0); + s.PendingRays[msk].direction.X(c) = s.PendingRays[msk].direction.X(0); + s.PendingRays[msk].direction.Y(c) = s.PendingRays[msk].direction.Y(0); + s.PendingRays[msk].direction.Z(c) = s.PendingRays[msk].direction.Z(0); + s.PendingStreamOutputs[msk][c]=s.PendingStreamOutputs[msk][0]; + } + FlushStreamEntry(s,msk); + } + } +} diff --git a/raytrace/trace3.cpp b/raytrace/trace3.cpp new file mode 100644 index 0000000..b582347 --- /dev/null +++ b/raytrace/trace3.cpp @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// + +#include "raytrace.h" +#include +#include "bsplib.h" + +static Vector VertCoord(dface_t const &f, int vnum) +{ + int eIndex = dsurfedges[f.firstedge+vnum]; + int point; + if( eIndex < 0 ) + { + point = dedges[-eIndex].v[1]; + } + else + { + point = dedges[eIndex].v[0]; + } + dvertex_t *v=dvertexes+point; + return Vector(v->point[0],v->point[1],v->point[2]); + +} + +Vector colors[]={ + Vector(0.5,0.5,1), + Vector(0.5,1,0.5), + Vector(0.5,1,1), + Vector(1,0.5,0.5), + Vector(1,0.5,1), + Vector(1,1,1)}; + +void RayTracingEnvironment::AddBSPFace(int id,dface_t const &face) +{ + if (face.dispinfo!=-1) // displacements must be dealt with elsewhere + return; + texinfo_t *tx =(face.texinfo>=0)?&(texinfo[face.texinfo]):0; +// if (tx && (tx->flags & (SURF_SKY|SURF_NODRAW))) +// return; + if (tx) + { + printf("id %d flags=%x\n",id,tx->flags); + } + printf("side: "); + for(int v=0;v PlanesToSkip; +// SidesToSkip.EnsureCapacity(numplanes); +// for(int s=0;s OrigFaceVisited; +// OrigFaceVisited.EnsureCapacity(numorigfaces); +// int n_added=0; + +// for(int i=0;i + Copyright 2005-2007, Cake Software Foundation, Inc. + 1785 E. Sahara Avenue, Suite 490-204 + Las Vegas, Nevada 89104 + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +************************************************************************************ +LZMA +************************************************************************************ + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. + +************************************************************************************ +Fast Pow Function +************************************************************************************ + + /* + * (c) Ian Stephenson + * + * ian@dctsystems.co.uk + * + * Fast pow() reference implementation + */ + + Used with permission from author + + For libantlr3c: + // [The "BSD licence"] + // Copyright (c) 2005-2009 Jim Idle, Temporal Wave LLC + // http://www.temporal-wave.com + // http://www.linkedin.com/in/jimidle + // + // All rights reserved. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions + // are met: + // 1. Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // 2. Redistributions in binary form must reproduce the above copyright + // notice, this list of conditions and the following disclaimer in the + // documentation and/or other materials provided with the distribution. + // 3. The name of the author may not be used to endorse or promote products + // derived from this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +************************************************************************************ +Autodesk FBX: +************************************************************************************ + + This software contains Autodesk FBX code developed by Autodesk, Inc. Copyright 2012 Autodesk, Inc. + All rights, reserved. Such code is provided as is and Autodesk, Inc. disclaims any and all warranties, + whether express or implied, including without limitation the implied warranties of merchantability, fitness for a + particular purpose or non-infringement of third party rights. In no event shall Autodesk, Inc. be liable for any + direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, + procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however + caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or + otherwise) arising in any way out of such code. + +************************************************************************************ +OpenSSL: +************************************************************************************ + + * This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/) + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + /* ==================================================================== + * Copyright (c) 1998-2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be + used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * + */ + + + /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an + acknowledgement: + * "This product includes software written by Tim Hudson + (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +************************************************************************************ +Google protocol buffers +************************************************************************************ + + // Protocol Buffers - Google's data interchange format + // Copyright 2008 Google Inc. All rights reserved. + // http://code.google.com/p/protobuf/ + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions are + // met: + // + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above + // copyright notice, this list of conditions and the following disclaimer + // in the documentation and/or other materials provided with the + // distribution. + // * Neither the name of Google Inc. nor the names of its + // contributors may be used to endorse or promote products derived from + // this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + // Author: kenton@google.com (Kenton Varda) + // Based on original Protocol Buffers design by + // Sanjay Ghemawat, Jeff Dean, and others. + +************************************************************************************ +Google Snappy +************************************************************************************ + + // Copyright 2005 Google Inc. All Rights Reserved. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions are + // met: + // + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above + // copyright notice, this list of conditions and the following disclaimer + // in the documentation and/or other materials provided with the + // distribution. + // * Neither the name of Google Inc. nor the names of its + // contributors may be used to endorse or promote products derived from + // this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tier1/KeyValues.cpp b/tier1/KeyValues.cpp new file mode 100644 index 0000000..a921b54 --- /dev/null +++ b/tier1/KeyValues.cpp @@ -0,0 +1,3179 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if defined( _WIN32 ) && !defined( _X360 ) +#include // for WideCharToMultiByte and MultiByteToWideChar +#elif defined(POSIX) +#include // wcslen() +#define _alloca alloca +#define _wtoi(arg) wcstol(arg, NULL, 10) +#define _wtoi64(arg) wcstoll(arg, NULL, 10) +#endif + +#include +#include "filesystem.h" +#include +#include "tier0/icommandline.h" + +#include +#include +#include "tier0/dbg.h" +#include "tier0/mem.h" +#include "utlbuffer.h" +#include "utlhash.h" +#include "utlvector.h" +#include "utlqueue.h" +#include "UtlSortVector.h" +#include "convar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include + +static const char * s_LastFileLoadingFrom = "unknown"; // just needed for error messages + +// Statics for the growable string table +int (*KeyValues::s_pfGetSymbolForString)( const char *name, bool bCreate ) = &KeyValues::GetSymbolForStringClassic; +const char *(*KeyValues::s_pfGetStringForSymbol)( int symbol ) = &KeyValues::GetStringForSymbolClassic; +CKeyValuesGrowableStringTable *KeyValues::s_pGrowableStringTable = NULL; + +#define KEYVALUES_TOKEN_SIZE 4096 +static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE]; + + +#define INTERNALWRITE( pData, len ) InternalWrite( filesystem, f, pBuf, pData, len ) + + +// a simple class to keep track of a stack of valid parsed symbols +const int MAX_ERROR_STACK = 64; +class CKeyValuesErrorStack +{ +public: + CKeyValuesErrorStack() : m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0) {} + + void SetFilename( const char *pFilename ) + { + m_pFilename = pFilename; + m_maxErrorIndex = 0; + } + + // entering a new keyvalues block, save state for errors + // Not save symbols instead of pointers because the pointers can move! + int Push( int symName ) + { + if ( m_errorIndex < MAX_ERROR_STACK ) + { + m_errorStack[m_errorIndex] = symName; + } + m_errorIndex++; + m_maxErrorIndex = vmax( m_maxErrorIndex, (m_errorIndex-1) ); + return m_errorIndex-1; + } + + // exiting block, error isn't in this block, remove. + void Pop() + { + m_errorIndex--; + Assert(m_errorIndex>=0); + } + + // Allows you to keep the same stack level, but change the name as you parse peers + void Reset( int stackLevel, int symName ) + { + Assert( stackLevel >= 0 ); + Assert( stackLevel < m_errorIndex ); + if ( stackLevel < MAX_ERROR_STACK ) + m_errorStack[stackLevel] = symName; + } + + // Hit an error, report it and the parsing stack for context + void ReportError( const char *pError ) + { + bool bSpewCR = false; + + Warning( "KeyValues Error: %s in file %s\n", pError, m_pFilename ); + for ( int i = 0; i < m_maxErrorIndex; i++ ) + { + if ( i < MAX_ERROR_STACK && m_errorStack[i] != INVALID_KEY_SYMBOL ) + { + if ( i < m_errorIndex ) + { + Warning( "%s, ", KeyValues::CallGetStringForSymbol(m_errorStack[i]) ); + } + else + { + Warning( "(*%s*), ", KeyValues::CallGetStringForSymbol(m_errorStack[i]) ); + } + + bSpewCR = true; + } + } + + if ( bSpewCR ) + Warning( "\n" ); + } + +private: + int m_errorStack[MAX_ERROR_STACK]; + const char *m_pFilename; + int m_errorIndex; + int m_maxErrorIndex; +} g_KeyValuesErrorStack; + + +// a simple helper that creates stack entries as it goes in & out of scope +class CKeyErrorContext +{ +public: + CKeyErrorContext( KeyValues *pKv ) + { + Init( pKv->GetNameSymbol() ); + } + + ~CKeyErrorContext() + { + g_KeyValuesErrorStack.Pop(); + } + CKeyErrorContext( int symName ) + { + Init( symName ); + } + void Reset( int symName ) + { + g_KeyValuesErrorStack.Reset( m_stackLevel, symName ); + } + int GetStackLevel() const + { + return m_stackLevel; + } +private: + void Init( int symName ) + { + m_stackLevel = g_KeyValuesErrorStack.Push( symName ); + } + + int m_stackLevel; +}; + +// Uncomment this line to hit the ~CLeakTrack assert to see what's looking like it's leaking +// #define LEAKTRACK + +#ifdef LEAKTRACK + +class CLeakTrack +{ +public: + CLeakTrack() + { + } + ~CLeakTrack() + { + if ( keys.Count() != 0 ) + { + Assert( 0 ); + } + } + + struct kve + { + KeyValues *kv; + char name[ 256 ]; + }; + + void AddKv( KeyValues *kv, char const *name ) + { + kve k; + Q_strncpy( k.name, name ? name : "NULL", sizeof( k.name ) ); + k.kv = kv; + + keys.AddToTail( k ); + } + + void RemoveKv( KeyValues *kv ) + { + int c = keys.Count(); + for ( int i = 0; i < c; i++ ) + { + if ( keys[i].kv == kv ) + { + keys.Remove( i ); + break; + } + } + } + + CUtlVector< kve > keys; +}; + +static CLeakTrack track; + +#define TRACK_KV_ADD( ptr, name ) track.AddKv( ptr, name ) +#define TRACK_KV_REMOVE( ptr ) track.RemoveKv( ptr ) + +#else + +#define TRACK_KV_ADD( ptr, name ) +#define TRACK_KV_REMOVE( ptr ) + +#endif + + +//----------------------------------------------------------------------------- +// Purpose: An arbitrarily growable string table for KeyValues key names. +// See the comment in the header for more info. +//----------------------------------------------------------------------------- +class CKeyValuesGrowableStringTable +{ +public: + // Constructor + CKeyValuesGrowableStringTable() : + #ifdef PLATFORM_64BITS + m_vecStrings( 0, 4 * 512 * 1024 ) + #else + m_vecStrings( 0, 512 * 1024 ) + #endif + , m_hashLookup( 2048, 0, 0, m_Functor, m_Functor ) + { + m_vecStrings.AddToTail( '\0' ); + } + + // Translates a string to an index + int GetSymbolForString( const char *name, bool bCreate = true ) + { + AUTO_LOCK( m_mutex ); + + // Put the current details into our hash functor + m_Functor.SetCurString( name ); + m_Functor.SetCurStringBase( (const char *)m_vecStrings.Base() ); + + if ( bCreate ) + { + bool bInserted = false; + UtlHashHandle_t hElement = m_hashLookup.Insert( -1, &bInserted ); + if ( bInserted ) + { + int iIndex = m_vecStrings.AddMultipleToTail( V_strlen( name ) + 1, name ); + m_hashLookup[ hElement ] = iIndex; + } + + return m_hashLookup[ hElement ]; + } + else + { + UtlHashHandle_t hElement = m_hashLookup.Find( -1 ); + if ( m_hashLookup.IsValidHandle( hElement ) ) + return m_hashLookup[ hElement ]; + else + return -1; + } + } + + // Translates an index back to a string + const char *GetStringForSymbol( int symbol ) + { + return (const char *)m_vecStrings.Base() + symbol; + } + +private: + + // A class plugged into CUtlHash that allows us to change the behavior of the table + // and store only the index in the table. + class CLookupFunctor + { + public: + CLookupFunctor() : m_pchCurString( NULL ), m_pchCurBase( NULL ) {} + + // Sets what we are currently inserting or looking for. + void SetCurString( const char *pchCurString ) { m_pchCurString = pchCurString; } + void SetCurStringBase( const char *pchCurBase ) { m_pchCurBase = pchCurBase; } + + // The compare function. + bool operator()( int nLhs, int nRhs ) const + { + const char *pchLhs = nLhs > 0 ? m_pchCurBase + nLhs : m_pchCurString; + const char *pchRhs = nRhs > 0 ? m_pchCurBase + nRhs : m_pchCurString; + + return ( 0 == V_stricmp( pchLhs, pchRhs ) ); + } + + // The hash function. + unsigned int operator()( int nItem ) const + { + return HashStringCaseless( m_pchCurString ); + } + + private: + const char *m_pchCurString; + const char *m_pchCurBase; + }; + + CThreadFastMutex m_mutex; + CLookupFunctor m_Functor; + CUtlHash m_hashLookup; + CUtlVector m_vecStrings; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sets whether the KeyValues system should use an arbitrarily growable +// string table. See the comment in the header for more info. +//----------------------------------------------------------------------------- +void KeyValues::SetUseGrowableStringTable( bool bUseGrowableTable ) +{ + if ( bUseGrowableTable ) + { + s_pfGetStringForSymbol = &(KeyValues::GetStringForSymbolGrowable); + s_pfGetSymbolForString = &(KeyValues::GetSymbolForStringGrowable); + + if ( NULL == s_pGrowableStringTable ) + { + s_pGrowableStringTable = new CKeyValuesGrowableStringTable; + } + } + else + { + s_pfGetStringForSymbol = &(KeyValues::GetStringForSymbolClassic); + s_pfGetSymbolForString = &(KeyValues::GetSymbolForStringClassic); + + delete s_pGrowableStringTable; + s_pGrowableStringTable = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Bodys of the function pointers used for interacting with the key +// name string table +//----------------------------------------------------------------------------- +int KeyValues::GetSymbolForStringClassic( const char *name, bool bCreate ) +{ + return KeyValuesSystem()->GetSymbolForString( name, bCreate ); +} + +const char *KeyValues::GetStringForSymbolClassic( int symbol ) +{ + return KeyValuesSystem()->GetStringForSymbol( symbol ); +} + +int KeyValues::GetSymbolForStringGrowable( const char *name, bool bCreate ) +{ + return s_pGrowableStringTable->GetSymbolForString( name, bCreate ); +} + +const char *KeyValues::GetStringForSymbolGrowable( int symbol ) +{ + return s_pGrowableStringTable->GetStringForSymbol( symbol ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + SetName ( setName ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName, const char *firstKey, const char *firstValue ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + SetName( setName ); + SetString( firstKey, firstValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + SetName( setName ); + SetWString( firstKey, firstValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + SetName( setName ); + SetInt( firstKey, firstValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + SetName( setName ); + SetString( firstKey, firstValue ); + SetString( secondKey, secondValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + SetName( setName ); + SetInt( firstKey, firstValue ); + SetInt( secondKey, secondValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize member variables +//----------------------------------------------------------------------------- +void KeyValues::Init() +{ + m_iKeyName = INVALID_KEY_SYMBOL; + m_iDataType = TYPE_NONE; + + m_pSub = NULL; + m_pPeer = NULL; + m_pChain = NULL; + + m_sValue = NULL; + m_wsValue = NULL; + m_pValue = NULL; + + m_bHasEscapeSequences = false; + m_bEvaluateConditionals = true; + + // for future proof + memset( unused, 0, sizeof(unused) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +KeyValues::~KeyValues() +{ + TRACK_KV_REMOVE( this ); + + RemoveEverything(); +} + +//----------------------------------------------------------------------------- +// Purpose: remove everything +//----------------------------------------------------------------------------- +void KeyValues::RemoveEverything() +{ + KeyValues *dat; + KeyValues *datNext = NULL; + for ( dat = m_pSub; dat != NULL; dat = datNext ) + { + datNext = dat->m_pPeer; + dat->m_pPeer = NULL; + delete dat; + } + + for ( dat = m_pPeer; dat && dat != this; dat = datNext ) + { + datNext = dat->m_pPeer; + dat->m_pPeer = NULL; + delete dat; + } + + delete [] m_sValue; + m_sValue = NULL; + delete [] m_wsValue; + m_wsValue = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *f - +//----------------------------------------------------------------------------- + +void KeyValues::RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel, bool sortKeys /*= false*/, bool bAllowEmptyString /*= false*/ ) +{ + RecursiveSaveToFile( NULL, FILESYSTEM_INVALID_HANDLE, &buf, indentLevel, sortKeys, bAllowEmptyString ); +} + +//----------------------------------------------------------------------------- +// Adds a chain... if we don't find stuff in this keyvalue, we'll look +// in the one we're chained to. +//----------------------------------------------------------------------------- + +void KeyValues::ChainKeyValue( KeyValues* pChain ) +{ + m_pChain = pChain; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the name of the current key section +//----------------------------------------------------------------------------- +const char *KeyValues::GetName( void ) const +{ + return s_pfGetStringForSymbol( m_iKeyName ); +} + +//----------------------------------------------------------------------------- +// Purpose: Read a single token from buffer (0 terminated) +//----------------------------------------------------------------------------- +#pragma warning (disable:4706) +const char *KeyValues::ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional ) +{ + wasQuoted = false; + wasConditional = false; + + if ( !buf.IsValid() ) + return NULL; + + // eating white spaces and remarks loop + while ( true ) + { + buf.EatWhiteSpace(); + if ( !buf.IsValid() ) + return NULL; // file ends after reading whitespaces + + // stop if it's not a comment; a new token starts here + if ( !buf.EatCPPComment() ) + break; + } + + const char *c = (const char*)buf.PeekGet( sizeof(char), 0 ); + if ( !c ) + return NULL; + + // read quoted strings specially + if ( *c == '\"' ) + { + wasQuoted = true; + buf.GetDelimitedString( m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(), + s_pTokenBuf, KEYVALUES_TOKEN_SIZE ); + return s_pTokenBuf; + } + + if ( *c == '{' || *c == '}' ) + { + // it's a control char, just add this one char and stop reading + s_pTokenBuf[0] = *c; + s_pTokenBuf[1] = 0; + buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 1 ); + return s_pTokenBuf; + } + + // read in the token until we hit a whitespace or a control character + bool bReportedError = false; + bool bConditionalStart = false; + int nCount = 0; + while ( ( c = (const char*)buf.PeekGet( sizeof(char), 0 ) ) ) + { + // end of file + if ( *c == 0 ) + break; + + // break if any control character appears in non quoted tokens + if ( *c == '"' || *c == '{' || *c == '}' ) + break; + + if ( *c == '[' ) + bConditionalStart = true; + + if ( *c == ']' && bConditionalStart ) + { + wasConditional = true; + } + + // break on whitespace + if ( isspace(*c) ) + break; + + if (nCount < (KEYVALUES_TOKEN_SIZE-1) ) + { + s_pTokenBuf[nCount++] = *c; // add char to buffer + } + else if ( !bReportedError ) + { + bReportedError = true; + g_KeyValuesErrorStack.ReportError(" ReadToken overflow" ); + } + + buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 1 ); + } + s_pTokenBuf[ nCount ] = 0; + return s_pTokenBuf; +} +#pragma warning (default:4706) + + + +//----------------------------------------------------------------------------- +// Purpose: if parser should translate escape sequences ( /n, /t etc), set to true +//----------------------------------------------------------------------------- +void KeyValues::UsesEscapeSequences(bool state) +{ + m_bHasEscapeSequences = state; +} + + +//----------------------------------------------------------------------------- +// Purpose: if parser should evaluate conditional blocks ( [$WINDOWS] etc. ) +//----------------------------------------------------------------------------- +void KeyValues::UsesConditionals(bool state) +{ + m_bEvaluateConditionals = state; +} + + +//----------------------------------------------------------------------------- +// Purpose: Load keyValues from disk +//----------------------------------------------------------------------------- +bool KeyValues::LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID, bool refreshCache ) +{ + Assert(filesystem); +#ifdef WIN32 + Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) ); +#endif + +#ifdef STAGING_ONLY + static bool s_bCacheEnabled = !!CommandLine()->FindParm( "-enable_keyvalues_cache" ); + const bool bUseCache = s_bCacheEnabled && ( s_pfGetSymbolForString == KeyValues::GetSymbolForStringClassic ); +#else + /* + People are cheating with the keyvalue cache enabled by doing the below, so disable it. + + For example if one is to allow a blue demoman texture on sv_pure they + change it to this, "$basetexture" "temp/demoman_blue". Remember to move the + demoman texture to the temp folder in the materials folder. It will likely + not be there so make a new folder for it. Once the directory in the + demoman_blue vmt is changed to the temp folder and the vtf texture is in + the temp folder itself you are finally done. + + I packed my mods into a vpk but I don't think it's required. Once in game + you must create a server via the create server button and select the map + that will load the custom texture before you join a valve server. I suggest + you only do this with player textures and such as they are always loaded. + After you load the map you join the valve server and the textures should + appear and work on valve servers. + + This can be done on any sv_pure 1 server but it depends on what is type of + files are allowed. All valve servers allow temp files so that is the + example I used here." + + So all vmt's files can bypass sv_pure 1. And I believe this mod is mostly + made of vmt files, so valve's sv_pure 1 bull is pretty redundant. + */ + const bool bUseCache = false; +#endif + + // If pathID is null, we cannot cache the result because that has a weird iterate-through-a-bunch-of-locations behavior. + const bool bUseCacheForRead = bUseCache && !refreshCache && pathID != NULL; + const bool bUseCacheForWrite = bUseCache && pathID != NULL; + + COM_TimestampedLog( "KeyValues::LoadFromFile(%s%s%s): Begin", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : "" ); + + // Keep a cache of keyvalues, try to load it here. + if ( bUseCacheForRead && KeyValuesSystem()->LoadFileKeyValuesFromCache( this, resourceName, pathID, filesystem ) ) { + COM_TimestampedLog( "KeyValues::LoadFromFile(%s%s%s): End / CacheHit", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : "" ); + return true; + } + + FileHandle_t f = filesystem->Open(resourceName, "rb", pathID); + if ( !f ) + { + COM_TimestampedLog("KeyValues::LoadFromFile(%s%s%s): End / FileNotFound", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : ""); + return false; + } + + s_LastFileLoadingFrom = (char*)resourceName; + + // load file into a null-terminated buffer + int fileSize = filesystem->Size( f ); + unsigned bufSize = ((IFileSystem *)filesystem)->GetOptimalReadSize( f, fileSize + 2 ); + + char *buffer = (char*)((IFileSystem *)filesystem)->AllocOptimalReadBuffer( f, bufSize ); + Assert( buffer ); + + // read into local buffer + bool bRetOK = ( ((IFileSystem *)filesystem)->ReadEx( buffer, bufSize, fileSize, f ) != 0 ); + + filesystem->Close( f ); // close file after reading + + if ( bRetOK ) + { + buffer[fileSize] = 0; // null terminate file as EOF + buffer[fileSize+1] = 0; // double NULL terminating in case this is a unicode file + bRetOK = LoadFromBuffer( resourceName, buffer, filesystem ); + } + + // The cache relies on the KeyValuesSystem string table, which will only be valid if we're + // using classic mode. + if ( bUseCacheForWrite && bRetOK ) + { + KeyValuesSystem()->AddFileKeyValuesToCache( this, resourceName, pathID ); + } + + ( (IFileSystem *)filesystem )->FreeOptimalReadBuffer( buffer ); + + COM_TimestampedLog("KeyValues::LoadFromFile(%s%s%s): End / Success", pathID ? pathID : "", pathID && resourceName ? "/" : "", resourceName ? resourceName : ""); + + return bRetOK; +} + +//----------------------------------------------------------------------------- +// Purpose: Save the keyvalues to disk +// Creates the path to the file if it doesn't exist +//----------------------------------------------------------------------------- +bool KeyValues::SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID, bool sortKeys /*= false*/, bool bAllowEmptyString /*= false*/, bool bCacheResult /*= false*/ ) +{ + // create a write file + FileHandle_t f = filesystem->Open(resourceName, "wb", pathID); + + if ( f == FILESYSTEM_INVALID_HANDLE ) + { + DevMsg(1, "KeyValues::SaveToFile: couldn't open file \"%s\" in path \"%s\".\n", + resourceName?resourceName:"NULL", pathID?pathID:"NULL" ); + return false; + } + + KeyValuesSystem()->InvalidateCacheForFile( resourceName, pathID ); + if ( bCacheResult ) { + KeyValuesSystem()->AddFileKeyValuesToCache( this, resourceName, pathID ); + } + RecursiveSaveToFile(filesystem, f, NULL, 0, sortKeys, bAllowEmptyString ); + filesystem->Close(f); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Write out a set of indenting +//----------------------------------------------------------------------------- +void KeyValues::WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel ) +{ + for ( int i = 0; i < indentLevel; i++ ) + { + INTERNALWRITE( "\t", 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Write out a string where we convert the double quotes to backslash double quote +//----------------------------------------------------------------------------- +void KeyValues::WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString ) +{ + // handle double quote chars within the string + // the worst possible case is that the whole string is quotes + int len = Q_strlen(pszString); + char *convertedString = (char *) _alloca ((len + 1) * sizeof(char) * 2); + int j=0; + for (int i=0; i <= len; i++) + { + if (pszString[i] == '\"') + { + convertedString[j] = '\\'; + j++; + } + else if ( m_bHasEscapeSequences && pszString[i] == '\\' ) + { + convertedString[j] = '\\'; + j++; + } + convertedString[j] = pszString[i]; + j++; + } + + INTERNALWRITE(convertedString, Q_strlen(convertedString)); +} + + +void KeyValues::InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len ) +{ + if ( filesystem ) + { + filesystem->Write( pData, len, f ); + } + + if ( pBuf ) + { + pBuf->Put( pData, len ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Save keyvalues from disk, if subkey values are detected, calls +// itself to save those +//----------------------------------------------------------------------------- +void KeyValues::RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString ) +{ + // write header + WriteIndents( filesystem, f, pBuf, indentLevel ); + INTERNALWRITE("\"", 1); + WriteConvertedString(filesystem, f, pBuf, GetName()); + INTERNALWRITE("\"\n", 2); + WriteIndents( filesystem, f, pBuf, indentLevel ); + INTERNALWRITE("{\n", 2); + + // loop through all our keys writing them to disk + if ( sortKeys ) + { + CUtlSortVector< KeyValues*, CUtlSortVectorKeyValuesByName > vecSortedKeys; + + for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer ) + { + vecSortedKeys.InsertNoSort(dat); + } + vecSortedKeys.RedoSort(); + + FOR_EACH_VEC( vecSortedKeys, i ) + { + SaveKeyToFile( vecSortedKeys[i], filesystem, f, pBuf, indentLevel, sortKeys, bAllowEmptyString ); + } + } + else + { + for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer ) + SaveKeyToFile( dat, filesystem, f, pBuf, indentLevel, sortKeys, bAllowEmptyString ); + } + + // write tail + WriteIndents(filesystem, f, pBuf, indentLevel); + INTERNALWRITE("}\n", 2); +} + +void KeyValues::SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel, bool sortKeys, bool bAllowEmptyString ) +{ + if ( dat->m_pSub ) + { + dat->RecursiveSaveToFile( filesystem, f, pBuf, indentLevel + 1, sortKeys, bAllowEmptyString ); + } + else + { + // only write non-empty keys + + switch (dat->m_iDataType) + { + case TYPE_STRING: + { + if ( dat->m_sValue && ( bAllowEmptyString || *(dat->m_sValue) ) ) + { + WriteIndents(filesystem, f, pBuf, indentLevel + 1); + INTERNALWRITE("\"", 1); + WriteConvertedString(filesystem, f, pBuf, dat->GetName()); + INTERNALWRITE("\"\t\t\"", 4); + + WriteConvertedString(filesystem, f, pBuf, dat->m_sValue); + + INTERNALWRITE("\"\n", 2); + } + break; + } + case TYPE_WSTRING: + { + if ( dat->m_wsValue ) + { + static char buf[KEYVALUES_TOKEN_SIZE]; + // make sure we have enough space + int result = Q_UnicodeToUTF8( dat->m_wsValue, buf, KEYVALUES_TOKEN_SIZE); + if (result) + { + WriteIndents(filesystem, f, pBuf, indentLevel + 1); + INTERNALWRITE("\"", 1); + INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName())); + INTERNALWRITE("\"\t\t\"", 4); + + WriteConvertedString(filesystem, f, pBuf, buf); + + INTERNALWRITE("\"\n", 2); + } + } + break; + } + + case TYPE_INT: + { + WriteIndents(filesystem, f, pBuf, indentLevel + 1); + INTERNALWRITE("\"", 1); + INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName())); + INTERNALWRITE("\"\t\t\"", 4); + + char buf[32]; + Q_snprintf(buf, sizeof( buf ), "%d", dat->m_iValue); + + INTERNALWRITE(buf, Q_strlen(buf)); + INTERNALWRITE("\"\n", 2); + break; + } + + case TYPE_UINT64: + { + WriteIndents(filesystem, f, pBuf, indentLevel + 1); + INTERNALWRITE("\"", 1); + INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName())); + INTERNALWRITE("\"\t\t\"", 4); + + char buf[32]; + // write "0x" + 16 char 0-padded hex encoded 64 bit value +#ifdef WIN32 + Q_snprintf( buf, sizeof( buf ), "0x%016I64X", *( (uint64 *)dat->m_sValue ) ); +#else + Q_snprintf( buf, sizeof( buf ), "0x%016llX", *( (uint64 *)dat->m_sValue ) ); +#endif + + INTERNALWRITE(buf, Q_strlen(buf)); + INTERNALWRITE("\"\n", 2); + break; + } + + case TYPE_FLOAT: + { + WriteIndents(filesystem, f, pBuf, indentLevel + 1); + INTERNALWRITE("\"", 1); + INTERNALWRITE(dat->GetName(), Q_strlen(dat->GetName())); + INTERNALWRITE("\"\t\t\"", 4); + + char buf[48]; + Q_snprintf(buf, sizeof( buf ), "%f", dat->m_flValue); + + INTERNALWRITE(buf, Q_strlen(buf)); + INTERNALWRITE("\"\n", 2); + break; + } + case TYPE_COLOR: + DevMsg(1, "KeyValues::RecursiveSaveToFile: TODO, missing code for TYPE_COLOR.\n"); + break; + + default: + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: looks up a key by symbol name +//----------------------------------------------------------------------------- +KeyValues *KeyValues::FindKey(int keySymbol) const +{ + for (KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer) + { + if (dat->m_iKeyName == keySymbol) + return dat; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Find a keyValue, create it if it is not found. +// Set bCreate to true to create the key if it doesn't already exist +// (which ensures a valid pointer will be returned) +//----------------------------------------------------------------------------- +KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate) +{ + // return the current key if a NULL subkey is asked for + if (!keyName || !keyName[0]) + return this; + + // look for '/' characters deliminating sub fields + char szBuf[256]; + const char *subStr = strchr(keyName, '/'); + const char *searchStr = keyName; + + // pull out the substring if it exists + if (subStr) + { + int size = subStr - keyName; + Q_memcpy( szBuf, keyName, size ); + szBuf[size] = 0; + searchStr = szBuf; + } + + // lookup the symbol for the search string + HKeySymbol iSearchStr = s_pfGetSymbolForString( searchStr, bCreate ); + + if ( iSearchStr == INVALID_KEY_SYMBOL ) + { + // not found, couldn't possibly be in key value list + return NULL; + } + + KeyValues *lastItem = NULL; + KeyValues *dat; + // find the searchStr in the current peer list + for (dat = m_pSub; dat != NULL; dat = dat->m_pPeer) + { + lastItem = dat; // record the last item looked at (for if we need to append to the end of the list) + + // symbol compare + if (dat->m_iKeyName == iSearchStr) + { + break; + } + } + + if ( !dat && m_pChain ) + { + dat = m_pChain->FindKey(keyName, false); + } + + // make sure a key was found + if (!dat) + { + if (bCreate) + { + // we need to create a new key + dat = new KeyValues( searchStr ); +// Assert(dat != NULL); + + dat->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent + dat->UsesConditionals( m_bEvaluateConditionals != 0 ); + + // insert new key at end of list + if (lastItem) + { + lastItem->m_pPeer = dat; + } + else + { + m_pSub = dat; + } + dat->m_pPeer = NULL; + + // a key graduates to be a submsg as soon as it's m_pSub is set + // this should be the only place m_pSub is set + m_iDataType = TYPE_NONE; + } + else + { + return NULL; + } + } + + // if we've still got a subStr we need to keep looking deeper in the tree + if ( subStr ) + { + // recursively chain down through the paths in the string + return dat->FindKey(subStr + 1, bCreate); + } + + return dat; +} + +//----------------------------------------------------------------------------- +// Purpose: Create a new key, with an autogenerated name. +// Name is guaranteed to be an integer, of value 1 higher than the highest +// other integer key name +//----------------------------------------------------------------------------- +KeyValues *KeyValues::CreateNewKey() +{ + int newID = 1; + + // search for any key with higher values + KeyValues *pLastChild = NULL; + for (KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer) + { + // case-insensitive string compare + int val = atoi(dat->GetName()); + if (newID <= val) + { + newID = val + 1; + } + + pLastChild = dat; + } + + char buf[12]; + Q_snprintf( buf, sizeof(buf), "%d", newID ); + + return CreateKeyUsingKnownLastChild( buf, pLastChild ); +} + + +//----------------------------------------------------------------------------- +// Create a key +//----------------------------------------------------------------------------- +KeyValues* KeyValues::CreateKey( const char *keyName ) +{ + KeyValues *pLastChild = FindLastSubKey(); + return CreateKeyUsingKnownLastChild( keyName, pLastChild ); +} + +//----------------------------------------------------------------------------- +KeyValues* KeyValues::CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pLastChild ) +{ + // Create a new key + KeyValues* dat = new KeyValues( keyName ); + + dat->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent does + dat->UsesConditionals( m_bEvaluateConditionals != 0 ); + + // add into subkey list + AddSubkeyUsingKnownLastChild( dat, pLastChild ); + + return dat; +} + +//----------------------------------------------------------------------------- +void KeyValues::AddSubkeyUsingKnownLastChild( KeyValues *pSubkey, KeyValues *pLastChild ) +{ + // Make sure the subkey isn't a child of some other keyvalues + Assert( pSubkey != NULL ); + Assert( pSubkey->m_pPeer == NULL ); + + // Empty child list? + if ( pLastChild == NULL ) + { + Assert( m_pSub == NULL ); + m_pSub = pSubkey; + } + else + { + Assert( m_pSub != NULL ); + Assert( pLastChild->m_pPeer == NULL ); + +// // In debug, make sure that they really do know which child is the last one +// #ifdef _DEBUG +// KeyValues *pTempDat = m_pSub; +// while ( pTempDat->GetNextKey() != NULL ) +// { +// pTempDat = pTempDat->GetNextKey(); +// } +// Assert( pTempDat == pLastChild ); +// #endif + + pLastChild->SetNextKey( pSubkey ); + } +} + + +//----------------------------------------------------------------------------- +// Adds a subkey. Make sure the subkey isn't a child of some other keyvalues +//----------------------------------------------------------------------------- +void KeyValues::AddSubKey( KeyValues *pSubkey ) +{ + // Make sure the subkey isn't a child of some other keyvalues + Assert( pSubkey != NULL ); + Assert( pSubkey->m_pPeer == NULL ); + + // add into subkey list + if ( m_pSub == NULL ) + { + m_pSub = pSubkey; + } + else + { + KeyValues *pTempDat = m_pSub; + while ( pTempDat->GetNextKey() != NULL ) + { + pTempDat = pTempDat->GetNextKey(); + } + + pTempDat->SetNextKey( pSubkey ); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Remove a subkey from the list +//----------------------------------------------------------------------------- +void KeyValues::RemoveSubKey(KeyValues *subKey) +{ + if (!subKey) + return; + + // check the list pointer + if (m_pSub == subKey) + { + m_pSub = subKey->m_pPeer; + } + else + { + // look through the list + KeyValues *kv = m_pSub; + while (kv->m_pPeer) + { + if (kv->m_pPeer == subKey) + { + kv->m_pPeer = subKey->m_pPeer; + break; + } + + kv = kv->m_pPeer; + } + } + + subKey->m_pPeer = NULL; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Locate last child. Returns NULL if we have no children +//----------------------------------------------------------------------------- +KeyValues *KeyValues::FindLastSubKey() +{ + + // No children? + if ( m_pSub == NULL ) + return NULL; + + // Scan for the last one + KeyValues *pLastChild = m_pSub; + while ( pLastChild->m_pPeer ) + pLastChild = pLastChild->m_pPeer; + return pLastChild; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets this key's peer to the KeyValues passed in +//----------------------------------------------------------------------------- +void KeyValues::SetNextKey( KeyValues *pDat ) +{ + m_pPeer = pDat; +} + + +KeyValues* KeyValues::GetFirstTrueSubKey() +{ + KeyValues *pRet = m_pSub; + while ( pRet && pRet->m_iDataType != TYPE_NONE ) + pRet = pRet->m_pPeer; + + return pRet; +} + +KeyValues* KeyValues::GetNextTrueSubKey() +{ + KeyValues *pRet = m_pPeer; + while ( pRet && pRet->m_iDataType != TYPE_NONE ) + pRet = pRet->m_pPeer; + + return pRet; +} + +KeyValues* KeyValues::GetFirstValue() +{ + KeyValues *pRet = m_pSub; + while ( pRet && pRet->m_iDataType == TYPE_NONE ) + pRet = pRet->m_pPeer; + + return pRet; +} + +KeyValues* KeyValues::GetNextValue() +{ + KeyValues *pRet = m_pPeer; + while ( pRet && pRet->m_iDataType == TYPE_NONE ) + pRet = pRet->m_pPeer; + + return pRet; +} + + +//----------------------------------------------------------------------------- +// Purpose: Get the integer value of a keyName. Default value is returned +// if the keyName can't be found. +//----------------------------------------------------------------------------- +int KeyValues::GetInt( const char *keyName, int defaultValue ) +{ + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + switch ( dat->m_iDataType ) + { + case TYPE_STRING: + return atoi(dat->m_sValue); + case TYPE_WSTRING: + return _wtoi(dat->m_wsValue); + case TYPE_FLOAT: + return (int)dat->m_flValue; + case TYPE_UINT64: + // can't convert, since it would lose data + Assert(0); + return 0; + case TYPE_INT: + case TYPE_PTR: + default: + return dat->m_iValue; + }; + } + return defaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the integer value of a keyName. Default value is returned +// if the keyName can't be found. +//----------------------------------------------------------------------------- +uint64 KeyValues::GetUint64( const char *keyName, uint64 defaultValue ) +{ + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + switch ( dat->m_iDataType ) + { + case TYPE_STRING: + return (uint64)Q_atoi64(dat->m_sValue); + case TYPE_WSTRING: + return _wtoi64(dat->m_wsValue); + case TYPE_FLOAT: + return (int)dat->m_flValue; + case TYPE_UINT64: + return *((uint64 *)dat->m_sValue); + case TYPE_INT: + case TYPE_PTR: + default: + return dat->m_iValue; + }; + } + return defaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the pointer value of a keyName. Default value is returned +// if the keyName can't be found. +//----------------------------------------------------------------------------- +void *KeyValues::GetPtr( const char *keyName, void *defaultValue ) +{ + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + switch ( dat->m_iDataType ) + { + case TYPE_PTR: + return dat->m_pValue; + + case TYPE_WSTRING: + case TYPE_STRING: + case TYPE_FLOAT: + case TYPE_INT: + case TYPE_UINT64: + default: + return NULL; + }; + } + return defaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the float value of a keyName. Default value is returned +// if the keyName can't be found. +//----------------------------------------------------------------------------- +float KeyValues::GetFloat( const char *keyName, float defaultValue ) +{ + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + switch ( dat->m_iDataType ) + { + case TYPE_STRING: + return (float)atof(dat->m_sValue); + case TYPE_WSTRING: +#ifdef WIN32 + return (float) _wtof(dat->m_wsValue); // no wtof +#else + Assert( !"impl me" ); + return 0.0; +#endif + case TYPE_FLOAT: + return dat->m_flValue; + case TYPE_INT: + return (float)dat->m_iValue; + case TYPE_UINT64: + return (float)(*((uint64 *)dat->m_sValue)); + case TYPE_PTR: + default: + return 0.0f; + }; + } + return defaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the string pointer of a keyName. Default value is returned +// if the keyName can't be found. +//----------------------------------------------------------------------------- +const char *KeyValues::GetString( const char *keyName, const char *defaultValue ) +{ + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + // convert the data to string form then return it + char buf[64]; + switch ( dat->m_iDataType ) + { + case TYPE_FLOAT: + Q_snprintf( buf, sizeof( buf ), "%f", dat->m_flValue ); + SetString( keyName, buf ); + break; + case TYPE_PTR: + Q_snprintf( buf, sizeof( buf ), "%lld", (int64)(size_t)dat->m_pValue ); + SetString( keyName, buf ); + break; + case TYPE_INT: + Q_snprintf( buf, sizeof( buf ), "%d", dat->m_iValue ); + SetString( keyName, buf ); + break; + case TYPE_UINT64: + Q_snprintf( buf, sizeof( buf ), "%lld", *((uint64 *)(dat->m_sValue)) ); + SetString( keyName, buf ); + break; + + case TYPE_WSTRING: + { + // convert the string to char *, set it for future use, and return it + char wideBuf[512]; + int result = Q_UnicodeToUTF8(dat->m_wsValue, wideBuf, 512); + if ( result ) + { + // note: this will copy wideBuf + SetString( keyName, wideBuf ); + } + else + { + return defaultValue; + } + break; + } + case TYPE_STRING: + break; + default: + return defaultValue; + }; + + return dat->m_sValue; + } + return defaultValue; +} + + +const wchar_t *KeyValues::GetWString( const char *keyName, const wchar_t *defaultValue) +{ + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + wchar_t wbuf[64]; + switch ( dat->m_iDataType ) + { + case TYPE_FLOAT: + swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%f", dat->m_flValue); + SetWString( keyName, wbuf); + break; + case TYPE_PTR: + swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", (int64)(size_t)dat->m_pValue ); + SetWString( keyName, wbuf ); + break; + case TYPE_INT: + swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%d", dat->m_iValue ); + SetWString( keyName, wbuf ); + break; + case TYPE_UINT64: + { + swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", *((uint64 *)(dat->m_sValue)) ); + SetWString( keyName, wbuf ); + } + break; + + case TYPE_WSTRING: + break; + case TYPE_STRING: + { + int bufSize = Q_strlen(dat->m_sValue) + 1; + wchar_t *pWBuf = new wchar_t[ bufSize ]; + int result = Q_UTF8ToUnicode(dat->m_sValue, pWBuf, bufSize * sizeof( wchar_t ) ); + if ( result >= 0 ) // may be a zero length string + { + SetWString( keyName, pWBuf); + } + else + { + delete [] pWBuf; + return defaultValue; + } + delete [] pWBuf; + break; + } + default: + return defaultValue; + }; + + return (const wchar_t* )dat->m_wsValue; + } + return defaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Get a bool interpretation of the key. +//----------------------------------------------------------------------------- +bool KeyValues::GetBool( const char *keyName, bool defaultValue, bool* optGotDefault ) +{ + if ( FindKey( keyName ) ) + { + if ( optGotDefault ) + (*optGotDefault) = false; + return 0 != GetInt( keyName, 0 ); + } + + if ( optGotDefault ) + (*optGotDefault) = true; + + return defaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Gets a color +//----------------------------------------------------------------------------- +Color KeyValues::GetColor( const char *keyName ) +{ + Color color(0, 0, 0, 0); + KeyValues *dat = FindKey( keyName, false ); + if ( dat ) + { + if ( dat->m_iDataType == TYPE_COLOR ) + { + color[0] = dat->m_Color[0]; + color[1] = dat->m_Color[1]; + color[2] = dat->m_Color[2]; + color[3] = dat->m_Color[3]; + } + else if ( dat->m_iDataType == TYPE_FLOAT ) + { + color[0] = (unsigned char)dat->m_flValue; + } + else if ( dat->m_iDataType == TYPE_INT ) + { + color[0] = dat->m_iValue; + } + else if ( dat->m_iDataType == TYPE_STRING ) + { + // parse the colors out of the string + float a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f; + sscanf(dat->m_sValue, "%f %f %f %f", &a, &b, &c, &d); + color[0] = (unsigned char)a; + color[1] = (unsigned char)b; + color[2] = (unsigned char)c; + color[3] = (unsigned char)d; + } + } + return color; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets a color +//----------------------------------------------------------------------------- +void KeyValues::SetColor( const char *keyName, Color value) +{ + KeyValues *dat = FindKey( keyName, true ); + + if ( dat ) + { + dat->m_iDataType = TYPE_COLOR; + dat->m_Color[0] = value[0]; + dat->m_Color[1] = value[1]; + dat->m_Color[2] = value[2]; + dat->m_Color[3] = value[3]; + } +} + +void KeyValues::SetStringValue( char const *strValue ) +{ + // delete the old value + delete [] m_sValue; + // make sure we're not storing the WSTRING - as we're converting over to STRING + delete [] m_wsValue; + m_wsValue = NULL; + + if (!strValue) + { + // ensure a valid value + strValue = ""; + } + + // allocate memory for the new value and copy it in + int len = Q_strlen( strValue ); + m_sValue = new char[len + 1]; + Q_memcpy( m_sValue, strValue, len+1 ); + + m_iDataType = TYPE_STRING; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the string value of a keyName. +//----------------------------------------------------------------------------- +void KeyValues::SetString( const char *keyName, const char *value ) +{ + KeyValues *dat = FindKey( keyName, true ); + + if ( dat ) + { + if ( dat->m_iDataType == TYPE_STRING && dat->m_sValue == value ) + { + return; + } + + // delete the old value + delete [] dat->m_sValue; + // make sure we're not storing the WSTRING - as we're converting over to STRING + delete [] dat->m_wsValue; + dat->m_wsValue = NULL; + + if (!value) + { + // ensure a valid value + value = ""; + } + + // allocate memory for the new value and copy it in + int len = Q_strlen( value ); + dat->m_sValue = new char[len + 1]; + Q_memcpy( dat->m_sValue, value, len+1 ); + + dat->m_iDataType = TYPE_STRING; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set the string value of a keyName. +//----------------------------------------------------------------------------- +void KeyValues::SetWString( const char *keyName, const wchar_t *value ) +{ + KeyValues *dat = FindKey( keyName, true ); + if ( dat ) + { + // delete the old value + delete [] dat->m_wsValue; + // make sure we're not storing the STRING - as we're converting over to WSTRING + delete [] dat->m_sValue; + dat->m_sValue = NULL; + + if (!value) + { + // ensure a valid value + value = L""; + } + + // allocate memory for the new value and copy it in + int len = Q_wcslen( value ); + dat->m_wsValue = new wchar_t[len + 1]; + Q_memcpy( dat->m_wsValue, value, (len+1) * sizeof(wchar_t) ); + + dat->m_iDataType = TYPE_WSTRING; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set the integer value of a keyName. +//----------------------------------------------------------------------------- +void KeyValues::SetInt( const char *keyName, int value ) +{ + KeyValues *dat = FindKey( keyName, true ); + + if ( dat ) + { + dat->m_iValue = value; + dat->m_iDataType = TYPE_INT; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set the integer value of a keyName. +//----------------------------------------------------------------------------- +void KeyValues::SetUint64( const char *keyName, uint64 value ) +{ + KeyValues *dat = FindKey( keyName, true ); + + if ( dat ) + { + // delete the old value + delete [] dat->m_sValue; + // make sure we're not storing the WSTRING - as we're converting over to STRING + delete [] dat->m_wsValue; + dat->m_wsValue = NULL; + + dat->m_sValue = new char[sizeof(uint64)]; + *((uint64 *)dat->m_sValue) = value; + dat->m_iDataType = TYPE_UINT64; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set the float value of a keyName. +//----------------------------------------------------------------------------- +void KeyValues::SetFloat( const char *keyName, float value ) +{ + KeyValues *dat = FindKey( keyName, true ); + + if ( dat ) + { + dat->m_flValue = value; + dat->m_iDataType = TYPE_FLOAT; + } +} + +void KeyValues::SetName( const char * setName ) +{ + m_iKeyName = s_pfGetSymbolForString( setName, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: Set the pointer value of a keyName. +//----------------------------------------------------------------------------- +void KeyValues::SetPtr( const char *keyName, void *value ) +{ + KeyValues *dat = FindKey( keyName, true ); + + if ( dat ) + { + dat->m_pValue = value; + dat->m_iDataType = TYPE_PTR; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Copies the tree from the other KeyValues into this one, recursively +// beginning with the root specified by rootSrc. +//----------------------------------------------------------------------------- +void KeyValues::CopyKeyValuesFromRecursive( const KeyValues& rootSrc ) +{ + // This code used to be recursive, which was more elegant. Unfortunately, it also blew the stack for large + // KeyValues. So now we have the iterative version which is uglier but doesn't blow the stack. + // This uses breadth-first traversal. + + struct CopyStruct + { + KeyValues* dst; + const KeyValues* src; + }; + + char tmp[256]; + KeyValues* localDst = NULL; + + CUtlQueue nodeQ; +#if _MSC_VER < 1800 + CopyStruct temp = { this, &rootSrc }; + nodeQ.Insert( temp ); +#else + nodeQ.Insert({ this, &rootSrc }); +#endif + + while ( nodeQ.Count() > 0 ) + { + CopyStruct cs = nodeQ.RemoveAtHead(); + + // Process all the siblings of the current node. If anyone has a child, add it to the queue. + while (cs.src) + { + Assert( (cs.src != NULL) == (cs.dst != NULL) ); + + // Copy the node contents + cs.dst->CopyKeyValue( *cs.src, sizeof(tmp), tmp ); + + // Add children to the queue to process later. + if( cs.src->m_pSub ) { + cs.dst->m_pSub = localDst = new KeyValues( NULL ); +#if _MSC_VER < 1800 + CopyStruct temp = { localDst, cs.src->m_pSub }; + nodeQ.Insert( temp ); +#else + nodeQ.Insert({ localDst, cs.src->m_pSub }); +#endif + } + + // Process siblings until we hit the end of the line. + if (cs.src->m_pPeer) { + cs.dst->m_pPeer = new KeyValues( NULL ); + } + else { + cs.dst->m_pPeer = NULL; + } + + // Advance to the next peer. + cs.src = cs.src->m_pPeer; + cs.dst = cs.dst->m_pPeer; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Copies a single KeyValue from src to this, using the provided temporary +// buffer if the keytype requires it. Does NOT recurse. +//----------------------------------------------------------------------------- +void KeyValues::CopyKeyValue( const KeyValues& src, size_t tmpBufferSizeB, char* tmpBuffer ) +{ + m_iKeyName = src.GetNameSymbol(); + + if ( src.m_pSub ) + return; + + m_iDataType = src.m_iDataType; + + switch( src.m_iDataType ) + { + case TYPE_NONE: + break; + case TYPE_STRING: + if( src.m_sValue ) + { + int len = Q_strlen(src.m_sValue) + 1; + m_sValue = new char[len]; + Q_strncpy( m_sValue, src.m_sValue, len ); + } + break; + case TYPE_INT: + { + m_iValue = src.m_iValue; + Q_snprintf( tmpBuffer, tmpBufferSizeB, "%d", m_iValue ); + int len = Q_strlen(tmpBuffer) + 1; + m_sValue = new char[len]; + Q_strncpy( m_sValue, tmpBuffer, len ); + } + break; + case TYPE_FLOAT: + { + m_flValue = src.m_flValue; + Q_snprintf( tmpBuffer, tmpBufferSizeB, "%f", m_flValue ); + int len = Q_strlen(tmpBuffer) + 1; + m_sValue = new char[len]; + Q_strncpy( m_sValue, tmpBuffer, len ); + } + break; + case TYPE_PTR: + { + m_pValue = src.m_pValue; + } + break; + case TYPE_UINT64: + { + m_sValue = new char[sizeof(uint64)]; + Q_memcpy( m_sValue, src.m_sValue, sizeof(uint64) ); + } + break; + case TYPE_COLOR: + { + m_Color[0] = src.m_Color[0]; + m_Color[1] = src.m_Color[1]; + m_Color[2] = src.m_Color[2]; + m_Color[3] = src.m_Color[3]; + } + break; + + default: + { + // do nothing . .what the heck is this? + Assert( 0 ); + } + break; + } +} + +KeyValues& KeyValues::operator=( const KeyValues& src ) +{ + RemoveEverything(); + Init(); // reset all values + CopyKeyValuesFromRecursive( src ); + return *this; +} + + +//----------------------------------------------------------------------------- +// Make a new copy of all subkeys, add them all to the passed-in keyvalues +//----------------------------------------------------------------------------- +void KeyValues::CopySubkeys( KeyValues *pParent ) const +{ + // recursively copy subkeys + // Also maintain ordering.... + KeyValues *pPrev = NULL; + for ( KeyValues *sub = m_pSub; sub != NULL; sub = sub->m_pPeer ) + { + // take a copy of the subkey + KeyValues *dat = sub->MakeCopy(); + + // add into subkey list + if (pPrev) + { + pPrev->m_pPeer = dat; + } + else + { + pParent->m_pSub = dat; + } + dat->m_pPeer = NULL; + pPrev = dat; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Makes a copy of the whole key-value pair set +//----------------------------------------------------------------------------- +KeyValues *KeyValues::MakeCopy( void ) const +{ + KeyValues *newKeyValue = new KeyValues(GetName()); + + newKeyValue->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); + newKeyValue->UsesConditionals( m_bEvaluateConditionals != 0 ); + + // copy data + newKeyValue->m_iDataType = m_iDataType; + switch ( m_iDataType ) + { + case TYPE_STRING: + { + if ( m_sValue ) + { + int len = Q_strlen( m_sValue ); + Assert( !newKeyValue->m_sValue ); + newKeyValue->m_sValue = new char[len + 1]; + Q_memcpy( newKeyValue->m_sValue, m_sValue, len+1 ); + } + } + break; + case TYPE_WSTRING: + { + if ( m_wsValue ) + { + int len = Q_wcslen( m_wsValue ); + newKeyValue->m_wsValue = new wchar_t[len+1]; + Q_memcpy( newKeyValue->m_wsValue, m_wsValue, (len+1)*sizeof(wchar_t)); + } + } + break; + + case TYPE_INT: + newKeyValue->m_iValue = m_iValue; + break; + + case TYPE_FLOAT: + newKeyValue->m_flValue = m_flValue; + break; + + case TYPE_PTR: + newKeyValue->m_pValue = m_pValue; + break; + + case TYPE_COLOR: + newKeyValue->m_Color[0] = m_Color[0]; + newKeyValue->m_Color[1] = m_Color[1]; + newKeyValue->m_Color[2] = m_Color[2]; + newKeyValue->m_Color[3] = m_Color[3]; + break; + + case TYPE_UINT64: + newKeyValue->m_sValue = new char[sizeof(uint64)]; + Q_memcpy( newKeyValue->m_sValue, m_sValue, sizeof(uint64) ); + break; + }; + + // recursively copy subkeys + CopySubkeys( newKeyValue ); + return newKeyValue; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +KeyValues *KeyValues::MakeCopy( bool copySiblings ) const +{ + KeyValues* rootDest = MakeCopy(); + if ( !copySiblings ) + return rootDest; + + const KeyValues* curSrc = GetNextKey(); + KeyValues* curDest = rootDest; + while (curSrc) { + curDest->SetNextKey( curSrc->MakeCopy() ); + curDest = curDest->GetNextKey(); + curSrc = curSrc->GetNextKey(); + } + + return rootDest; +} + +//----------------------------------------------------------------------------- +// Purpose: Check if a keyName has no value assigned to it. +//----------------------------------------------------------------------------- +bool KeyValues::IsEmpty(const char *keyName) +{ + KeyValues *dat = FindKey(keyName, false); + if (!dat) + return true; + + if (dat->m_iDataType == TYPE_NONE && dat->m_pSub == NULL) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Clear out all subkeys, and the current value +//----------------------------------------------------------------------------- +void KeyValues::Clear( void ) +{ + delete m_pSub; + m_pSub = NULL; + m_iDataType = TYPE_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the data type of the value stored in a keyName +//----------------------------------------------------------------------------- +KeyValues::types_t KeyValues::GetDataType(const char *keyName) +{ + KeyValues *dat = FindKey(keyName, false); + if (dat) + return (types_t)dat->m_iDataType; + + return TYPE_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: Deletion, ensures object gets deleted from correct heap +//----------------------------------------------------------------------------- +void KeyValues::deleteThis() +{ + delete this; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : includedKeys - +//----------------------------------------------------------------------------- +void KeyValues::AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys ) +{ + // Append any included keys, too... + KeyValues *insertSpot = this; + int includeCount = includedKeys.Count(); + for ( int i = 0; i < includeCount; i++ ) + { + KeyValues *kv = includedKeys[ i ]; + Assert( kv ); + + while ( insertSpot->GetNextKey() ) + { + insertSpot = insertSpot->GetNextKey(); + } + + insertSpot->SetNextKey( kv ); + } +} + +void KeyValues::ParseIncludedKeys( char const *resourceName, const char *filetoinclude, + IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys ) +{ + Assert( resourceName ); + Assert( filetoinclude ); + Assert( pFileSystem ); + + // Load it... + if ( !pFileSystem ) + { + return; + } + + // Get relative subdirectory + char fullpath[ 512 ]; + Q_strncpy( fullpath, resourceName, sizeof( fullpath ) ); + + // Strip off characters back to start or first / + int len = Q_strlen( fullpath ); + for (;;) + { + if ( len <= 0 ) + { + break; + } + + if ( fullpath[ len - 1 ] == '\\' || + fullpath[ len - 1 ] == '/' ) + { + break; + } + + // zero it + fullpath[ len - 1 ] = 0; + --len; + } + + // Append included file + Q_strncat( fullpath, filetoinclude, sizeof( fullpath ), COPY_ALL_CHARACTERS ); + + KeyValues *newKV = new KeyValues( fullpath ); + + // CUtlSymbol save = s_CurrentFileSymbol; // did that had any use ??? + + newKV->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // use same format as parent + newKV->UsesConditionals( m_bEvaluateConditionals != 0 ); + + if ( newKV->LoadFromFile( pFileSystem, fullpath, pPathID ) ) + { + includedKeys.AddToTail( newKV ); + } + else + { + DevMsg( "KeyValues::ParseIncludedKeys: Couldn't load included keyvalue file %s\n", fullpath ); + newKV->deleteThis(); + } + + // s_CurrentFileSymbol = save; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : baseKeys - +//----------------------------------------------------------------------------- +void KeyValues::MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys ) +{ + int includeCount = baseKeys.Count(); + int i; + for ( i = 0; i < includeCount; i++ ) + { + KeyValues *kv = baseKeys[ i ]; + Assert( kv ); + + RecursiveMergeKeyValues( kv ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : baseKV - keyvalues we're basing ourselves on +//----------------------------------------------------------------------------- +void KeyValues::RecursiveMergeKeyValues( KeyValues *baseKV ) +{ + // Merge ourselves + // we always want to keep our value, so nothing to do here + + // Now merge our children + for ( KeyValues *baseChild = baseKV->m_pSub; baseChild != NULL; baseChild = baseChild->m_pPeer ) + { + // for each child in base, see if we have a matching kv + + bool bFoundMatch = false; + + // If we have a child by the same name, merge those keys + for ( KeyValues *newChild = m_pSub; newChild != NULL; newChild = newChild->m_pPeer ) + { + if ( !Q_strcmp( baseChild->GetName(), newChild->GetName() ) ) + { + newChild->RecursiveMergeKeyValues( baseChild ); + bFoundMatch = true; + break; + } + } + + // If not merged, append this key + if ( !bFoundMatch ) + { + KeyValues *dat = baseChild->MakeCopy(); + Assert( dat ); + AddSubKey( dat ); + } + } +} + +//----------------------------------------------------------------------------- +// Returns whether a keyvalues conditional evaluates to true or false +// Needs more flexibility with conditionals, checking convars would be nice. +//----------------------------------------------------------------------------- +bool EvaluateConditional( const char *str ) +{ + if ( !str ) + return false; + + if ( *str == '[' ) + str++; + + bool bNot = false; // should we negate this command? + if ( *str == '!' ) + bNot = true; + + if ( Q_stristr( str, "$X360" ) ) + return IsX360() ^ bNot; + + if ( Q_stristr( str, "$WIN32" ) ) + return IsPC() ^ bNot; // hack hack - for now WIN32 really means IsPC + + if ( Q_stristr( str, "$WINDOWS" ) ) + return IsWindows() ^ bNot; + + if ( Q_stristr( str, "$OSX" ) ) + return IsOSX() ^ bNot; + + if ( Q_stristr( str, "$LINUX" ) ) + return IsLinux() ^ bNot; + + if ( Q_stristr( str, "$POSIX" ) ) + return IsPosix() ^ bNot; + + return false; +} + + +//----------------------------------------------------------------------------- +// Read from a buffer... +//----------------------------------------------------------------------------- +bool KeyValues::LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem, const char *pPathID ) +{ + KeyValues *pPreviousKey = NULL; + KeyValues *pCurrentKey = this; + CUtlVector< KeyValues * > includedKeys; + CUtlVector< KeyValues * > baseKeys; + bool wasQuoted; + bool wasConditional; + g_KeyValuesErrorStack.SetFilename( resourceName ); + do + { + bool bAccepted = true; + + // the first thing must be a key + const char *s = ReadToken( buf, wasQuoted, wasConditional ); + if ( !buf.IsValid() || !s || *s == 0 ) + break; + + if ( !Q_stricmp( s, "#include" ) ) // special include macro (not a key name) + { + s = ReadToken( buf, wasQuoted, wasConditional ); + // Name of subfile to load is now in s + + if ( !s || *s == 0 ) + { + g_KeyValuesErrorStack.ReportError("#include is NULL " ); + } + else + { + ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, includedKeys ); + } + + continue; + } + else if ( !Q_stricmp( s, "#base" ) ) + { + s = ReadToken( buf, wasQuoted, wasConditional ); + // Name of subfile to load is now in s + + if ( !s || *s == 0 ) + { + g_KeyValuesErrorStack.ReportError("#base is NULL " ); + } + else + { + ParseIncludedKeys( resourceName, s, pFileSystem, pPathID, baseKeys ); + } + + continue; + } + + if ( !pCurrentKey ) + { + pCurrentKey = new KeyValues( s ); + Assert( pCurrentKey ); + + pCurrentKey->UsesEscapeSequences( m_bHasEscapeSequences != 0 ); // same format has parent use + pCurrentKey->UsesConditionals( m_bEvaluateConditionals != 0 ); + + if ( pPreviousKey ) + { + pPreviousKey->SetNextKey( pCurrentKey ); + } + } + else + { + pCurrentKey->SetName( s ); + } + + // get the '{' + s = ReadToken( buf, wasQuoted, wasConditional ); + + if ( wasConditional ) + { + bAccepted = !m_bEvaluateConditionals || EvaluateConditional( s ); + + // Now get the '{' + s = ReadToken( buf, wasQuoted, wasConditional ); + } + + if ( s && *s == '{' && !wasQuoted ) + { + // header is valid so load the file + pCurrentKey->RecursiveLoadFromBuffer( resourceName, buf ); + } + else + { + g_KeyValuesErrorStack.ReportError("LoadFromBuffer: missing {" ); + } + + if ( !bAccepted ) + { + if ( pPreviousKey ) + { + pPreviousKey->SetNextKey( NULL ); + } + pCurrentKey->Clear(); + } + else + { + pPreviousKey = pCurrentKey; + pCurrentKey = NULL; + } + } while ( buf.IsValid() ); + + AppendIncludedKeys( includedKeys ); + { + // delete included keys! + int i; + for ( i = includedKeys.Count() - 1; i > 0; i-- ) + { + KeyValues *kv = includedKeys[ i ]; + kv->deleteThis(); + } + } + + MergeBaseKeys( baseKeys ); + { + // delete base keys! + int i; + for ( i = baseKeys.Count() - 1; i >= 0; i-- ) + { + KeyValues *kv = baseKeys[ i ]; + kv->deleteThis(); + } + } + + g_KeyValuesErrorStack.SetFilename( "" ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Read from a buffer... +//----------------------------------------------------------------------------- +bool KeyValues::LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem, const char *pPathID ) +{ + if ( !pBuffer ) + return true; + + COM_TimestampedLog("KeyValues::LoadFromBuffer(%s%s%s): Begin", pPathID ? pPathID : "", pPathID && resourceName ? "/" : "", resourceName ? resourceName : ""); + + int nLen = Q_strlen( pBuffer ); + CUtlBuffer buf( pBuffer, nLen, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER ); + + // Translate Unicode files into UTF-8 before proceeding + if ( nLen > 2 && (uint8)pBuffer[0] == 0xFF && (uint8)pBuffer[1] == 0xFE ) + { + int nUTF8Len = V_UnicodeToUTF8( (wchar_t*)(pBuffer+2), NULL, 0 ); + char *pUTF8Buf = new char[nUTF8Len]; + V_UnicodeToUTF8( (wchar_t*)(pBuffer+2), pUTF8Buf, nUTF8Len ); + buf.AssumeMemory( pUTF8Buf, nUTF8Len, nUTF8Len, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER ); + } + + bool retVal = LoadFromBuffer( resourceName, buf, pFileSystem, pPathID ); + + COM_TimestampedLog("KeyValues::LoadFromBuffer(%s%s%s): End", pPathID ? pPathID : "", pPathID && resourceName ? "/" : "", resourceName ? resourceName : ""); + + return retVal; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void KeyValues::RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf ) +{ + CKeyErrorContext errorReport(this); + bool wasQuoted; + bool wasConditional; + if ( errorReport.GetStackLevel() > 100 ) + { + g_KeyValuesErrorStack.ReportError( "RecursiveLoadFromBuffer: recursion overflow" ); + return; + } + + // keep this out of the stack until a key is parsed + CKeyErrorContext errorKey( INVALID_KEY_SYMBOL ); + + // Locate the last child. (Almost always, we will not have any children.) + // We maintain the pointer to the last child here, so we don't have to re-locate + // it each time we append the next subkey, which causes O(N^2) time + KeyValues *pLastChild = FindLastSubKey();; + + // Keep parsing until we hit the closing brace which terminates this block, or a parse error + while ( 1 ) + { + bool bAccepted = true; + + // get the key name + const char * name = ReadToken( buf, wasQuoted, wasConditional ); + + if ( !name ) // EOF stop reading + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got EOF instead of keyname" ); + break; + } + + if ( !*name ) // empty token, maybe "" or EOF + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got empty keyname" ); + break; + } + + if ( *name == '}' && !wasQuoted ) // top level closed, stop reading + break; + + // Always create the key; note that this could potentially + // cause some duplication, but that's what we want sometimes + KeyValues *dat = CreateKeyUsingKnownLastChild( name, pLastChild ); + + errorKey.Reset( dat->GetNameSymbol() ); + + // get the value + const char * value = ReadToken( buf, wasQuoted, wasConditional ); + + if ( wasConditional && value ) + { + bAccepted = !m_bEvaluateConditionals || EvaluateConditional( value ); + + // get the real value + value = ReadToken( buf, wasQuoted, wasConditional ); + } + + if ( !value ) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got NULL key" ); + break; + } + + if ( *value == '}' && !wasQuoted ) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got } in key" ); + break; + } + + if ( *value == '{' && !wasQuoted ) + { + // this isn't a key, it's a section + errorKey.Reset( INVALID_KEY_SYMBOL ); + // sub value list + dat->RecursiveLoadFromBuffer( resourceName, buf ); + } + else + { + if ( wasConditional ) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got conditional between key and value" ); + break; + } + + if (dat->m_sValue) + { + delete[] dat->m_sValue; + dat->m_sValue = NULL; + } + + int len = Q_strlen( value ); + + // Here, let's determine if we got a float or an int.... + char* pIEnd; // pos where int scan ended + char* pFEnd; // pos where float scan ended + const char* pSEnd = value + len ; // pos where token ends + + int ival = strtol( value, &pIEnd, 10 ); + float fval = (float)strtod( value, &pFEnd ); + bool bOverflow = ( ival == LONG_MAX || ival == LONG_MIN ) && errno == ERANGE; +#ifdef POSIX + // strtod supports hex representation in strings under posix but we DON'T + // want that support in keyvalues, so undo it here if needed + if ( len > 1 && tolower(value[1]) == 'x' ) + { + fval = 0.0f; + pFEnd = (char *)value; + } +#endif + + if ( *value == 0 ) + { + dat->m_iDataType = TYPE_STRING; + } + else if ( ( 18 == len ) && ( value[0] == '0' ) && ( value[1] == 'x' ) ) + { + // an 18-byte value prefixed with "0x" (followed by 16 hex digits) is an int64 value + int64 retVal = 0; + for( int i=2; i < 2 + 16; i++ ) + { + char digit = value[i]; + if ( digit >= 'a' ) + digit -= 'a' - ( '9' + 1 ); + else + if ( digit >= 'A' ) + digit -= 'A' - ( '9' + 1 ); + retVal = ( retVal * 16 ) + ( digit - '0' ); + } + dat->m_sValue = new char[sizeof(uint64)]; + *((uint64 *)dat->m_sValue) = retVal; + dat->m_iDataType = TYPE_UINT64; + } + else if ( (pFEnd > pIEnd) && (pFEnd == pSEnd) ) + { + dat->m_flValue = fval; + dat->m_iDataType = TYPE_FLOAT; + } + else if (pIEnd == pSEnd && !bOverflow) + { + dat->m_iValue = ival; + dat->m_iDataType = TYPE_INT; + } + else + { + dat->m_iDataType = TYPE_STRING; + } + + if (dat->m_iDataType == TYPE_STRING) + { + // copy in the string information + dat->m_sValue = new char[len+1]; + Q_memcpy( dat->m_sValue, value, len+1 ); + } + + // Look ahead one token for a conditional tag + int prevPos = buf.TellGet(); + const char *peek = ReadToken( buf, wasQuoted, wasConditional ); + if ( wasConditional ) + { + bAccepted = !m_bEvaluateConditionals || EvaluateConditional( peek ); + } + else + { + buf.SeekGet( CUtlBuffer::SEEK_HEAD, prevPos ); + } + } + + Assert( dat->m_pPeer == NULL ); + if ( bAccepted ) + { + Assert( pLastChild == NULL || pLastChild->m_pPeer == dat ); + pLastChild = dat; + } + else + { + //this->RemoveSubKey( dat ); + if ( pLastChild == NULL ) + { + Assert( m_pSub == dat ); + m_pSub = NULL; + } + else + { + Assert( pLastChild->m_pPeer == dat ); + pLastChild->m_pPeer = NULL; + } + + dat->deleteThis(); + dat = NULL; + } + } +} + + + +// writes KeyValue as binary data to buffer +bool KeyValues::WriteAsBinary( CUtlBuffer &buffer ) +{ + if ( buffer.IsText() ) // must be a binary buffer + return false; + + if ( !buffer.IsValid() ) // must be valid, no overflows etc + return false; + + // Write subkeys: + + // loop through all our peers + for ( KeyValues *dat = this; dat != NULL; dat = dat->m_pPeer ) + { + // write type + buffer.PutUnsignedChar( dat->m_iDataType ); + + // write name + buffer.PutString( dat->GetName() ); + + // write type + switch (dat->m_iDataType) + { + case TYPE_NONE: + { + dat->m_pSub->WriteAsBinary( buffer ); + break; + } + case TYPE_STRING: + { + if (dat->m_sValue && *(dat->m_sValue)) + { + buffer.PutString( dat->m_sValue ); + } + else + { + buffer.PutString( "" ); + } + break; + } + case TYPE_WSTRING: + { + Assert( !"TYPE_WSTRING" ); + break; + } + + case TYPE_INT: + { + buffer.PutInt( dat->m_iValue ); + break; + } + + case TYPE_UINT64: + { + buffer.PutDouble( *((double *)dat->m_sValue) ); + break; + } + + case TYPE_FLOAT: + { + buffer.PutFloat( dat->m_flValue ); + break; + } + case TYPE_COLOR: + { + buffer.PutUnsignedChar( dat->m_Color[0] ); + buffer.PutUnsignedChar( dat->m_Color[1] ); + buffer.PutUnsignedChar( dat->m_Color[2] ); + buffer.PutUnsignedChar( dat->m_Color[3] ); + break; + } + case TYPE_PTR: + { + buffer.PutUnsignedInt( (int)dat->m_pValue ); + } + + default: + break; + } + } + + // write tail, marks end of peers + buffer.PutUnsignedChar( TYPE_NUMTYPES ); + + return buffer.IsValid(); +} + +// read KeyValues from binary buffer, returns true if parsing was successful +bool KeyValues::ReadAsBinary( CUtlBuffer &buffer, int nStackDepth ) +{ + if ( buffer.IsText() ) // must be a binary buffer + return false; + + if ( !buffer.IsValid() ) // must be valid, no overflows etc + return false; + + RemoveEverything(); // remove current content + Init(); // reset + + if ( nStackDepth > 100 ) + { + AssertMsgOnce( false, "KeyValues::ReadAsBinary() stack depth > 100\n" ); + return false; + } + + KeyValues *dat = this; + types_t type = (types_t)buffer.GetUnsignedChar(); + + // loop through all our peers + while ( true ) + { + if ( type == TYPE_NUMTYPES ) + break; // no more peers + + dat->m_iDataType = type; + + { + char token[KEYVALUES_TOKEN_SIZE]; + buffer.GetString( token ); + token[KEYVALUES_TOKEN_SIZE-1] = 0; + dat->SetName( token ); + } + + switch ( type ) + { + case TYPE_NONE: + { + dat->m_pSub = new KeyValues(""); + dat->m_pSub->ReadAsBinary( buffer, nStackDepth + 1 ); + break; + } + case TYPE_STRING: + { + char token[KEYVALUES_TOKEN_SIZE]; + buffer.GetString( token ); + token[KEYVALUES_TOKEN_SIZE-1] = 0; + + int len = Q_strlen( token ); + dat->m_sValue = new char[len + 1]; + Q_memcpy( dat->m_sValue, token, len+1 ); + + break; + } + case TYPE_WSTRING: + { + Assert( !"TYPE_WSTRING" ); + break; + } + + case TYPE_INT: + { + dat->m_iValue = buffer.GetInt(); + break; + } + + case TYPE_UINT64: + { + dat->m_sValue = new char[sizeof(uint64)]; + *((uint64 *)dat->m_sValue) = buffer.GetInt64(); + break; + } + + case TYPE_FLOAT: + { + dat->m_flValue = buffer.GetFloat(); + break; + } + case TYPE_COLOR: + { + dat->m_Color[0] = buffer.GetUnsignedChar(); + dat->m_Color[1] = buffer.GetUnsignedChar(); + dat->m_Color[2] = buffer.GetUnsignedChar(); + dat->m_Color[3] = buffer.GetUnsignedChar(); + break; + } + case TYPE_PTR: + { + dat->m_pValue = (void*)buffer.GetUnsignedInt(); + } + + default: + break; + } + + if ( !buffer.IsValid() ) // error occured + return false; + + type = (types_t)buffer.GetUnsignedChar(); + + if ( type == TYPE_NUMTYPES ) + break; + + // new peer follows + dat->m_pPeer = new KeyValues(""); + dat = dat->m_pPeer; + } + + return buffer.IsValid(); +} + +#include "tier0/memdbgoff.h" + +//----------------------------------------------------------------------------- +// Purpose: memory allocator +//----------------------------------------------------------------------------- +void *KeyValues::operator new( size_t iAllocSize ) +{ + MEM_ALLOC_CREDIT(); + return KeyValuesSystem()->AllocKeyValuesMemory( (int)iAllocSize ); +} + +void *KeyValues::operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine ) +{ + MemAlloc_PushAllocDbgInfo( pFileName, nLine ); + void *p = KeyValuesSystem()->AllocKeyValuesMemory( (int)iAllocSize ); + MemAlloc_PopAllocDbgInfo(); + return p; +} + +//----------------------------------------------------------------------------- +// Purpose: deallocator +//----------------------------------------------------------------------------- +void KeyValues::operator delete( void *pMem ) +{ + KeyValuesSystem()->FreeKeyValuesMemory(pMem); +} + +void KeyValues::operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) +{ + KeyValuesSystem()->FreeKeyValuesMemory(pMem); +} + +void KeyValues::UnpackIntoStructure( KeyValuesUnpackStructure const *pUnpackTable, void *pDest, size_t DestSizeInBytes ) +{ +#ifdef DBGFLAG_ASSERT + void *pDestEnd = ( char * )pDest + DestSizeInBytes + 1; +#endif + + uint8 *dest=(uint8 *) pDest; + while( pUnpackTable->m_pKeyName ) + { + uint8 *dest_field=dest+pUnpackTable->m_nFieldOffset; + KeyValues *find_it=FindKey( pUnpackTable->m_pKeyName ); + + switch( pUnpackTable->m_eDataType ) + { + case UNPACK_TYPE_FLOAT: + { + Assert( dest_field + sizeof( float ) < pDestEnd ); + + float default_value=(pUnpackTable->m_pKeyDefault)?(float)atof(pUnpackTable->m_pKeyDefault):0.0f; + *( ( float *) dest_field)=GetFloat( pUnpackTable->m_pKeyName, default_value ); + break; + } + break; + + case UNPACK_TYPE_VECTOR: + { + Assert( dest_field + sizeof( Vector ) < pDestEnd ); + + Vector *dest_v=(Vector *) dest_field; + char const *src_string= + GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault ); + if ( (!src_string) || + ( sscanf(src_string,"%f %f %f", + &(dest_v->x), &(dest_v->y), &(dest_v->z)) != 3)) + dest_v->Init( 0, 0, 0 ); + } + break; + + case UNPACK_TYPE_FOUR_FLOATS: + { + Assert( dest_field + sizeof( float ) * 4 < pDestEnd ); + + float *dest_f=(float *) dest_field; + char const *src_string= + GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault ); + if ( (!src_string) || + ( sscanf(src_string,"%f %f %f %f", + dest_f,dest_f+1,dest_f+2,dest_f+3)) != 4) + memset( dest_f, 0, 4*sizeof(float) ); + } + break; + + case UNPACK_TYPE_TWO_FLOATS: + { + Assert( dest_field + sizeof( float ) * 2 < pDestEnd ); + + float *dest_f=(float *) dest_field; + char const *src_string= + GetString( pUnpackTable->m_pKeyName, pUnpackTable->m_pKeyDefault ); + if ( (!src_string) || + ( sscanf(src_string,"%f %f", + dest_f,dest_f+1)) != 2) + memset( dest_f, 0, 2*sizeof(float) ); + } + break; + + case UNPACK_TYPE_STRING: + { + Assert( dest_field + pUnpackTable->m_nFieldSize < pDestEnd ); + + char *dest_s=(char *) dest_field; + strncpy( dest_s, GetString( pUnpackTable->m_pKeyName, + pUnpackTable->m_pKeyDefault ), + pUnpackTable->m_nFieldSize ); + + } + break; + + case UNPACK_TYPE_INT: + { + Assert( dest_field + sizeof( int ) < pDestEnd ); + + int *dest_i=(int *) dest_field; + int default_int=0; + if ( pUnpackTable->m_pKeyDefault) + default_int = atoi( pUnpackTable->m_pKeyDefault ); + *(dest_i)=GetInt( pUnpackTable->m_pKeyName, default_int ); + } + break; + + case UNPACK_TYPE_VECTOR_COLOR: + { + Assert( dest_field + sizeof( Vector ) < pDestEnd ); + + Vector *dest_v=(Vector *) dest_field; + if (find_it) + { + Color c=GetColor( pUnpackTable->m_pKeyName ); + dest_v->x = (vec_t)c.r(); + dest_v->y = (vec_t)c.g(); + dest_v->z = (vec_t)c.b(); + } + else + { + if ( pUnpackTable->m_pKeyDefault ) + sscanf(pUnpackTable->m_pKeyDefault,"%f %f %f", + &(dest_v->x), &(dest_v->y), &(dest_v->z)); + else + dest_v->Init( 0, 0, 0 ); + } + *(dest_v) *= (1.0f/255); + } + } + pUnpackTable++; + } +} + +//----------------------------------------------------------------------------- +// Helper function for processing a keyvalue tree for console resolution support. +// Alters key/values for easier console video resolution support. +// If running SD (640x480), the presence of "???_lodef" creates or slams "???". +// If running HD (1280x720), the presence of "???_hidef" creates or slams "???". +//----------------------------------------------------------------------------- +bool KeyValues::ProcessResolutionKeys( const char *pResString ) +{ + if ( !pResString ) + { + // not for pc, console only + return false; + } + + KeyValues *pSubKey = GetFirstSubKey(); + if ( !pSubKey ) + { + // not a block + return false; + } + + for ( ; pSubKey != NULL; pSubKey = pSubKey->GetNextKey() ) + { + // recursively descend each sub block + pSubKey->ProcessResolutionKeys( pResString ); + + // check to see if our substring is present + if ( Q_stristr( pSubKey->GetName(), pResString ) != NULL ) + { + char normalKeyName[128]; + V_strncpy( normalKeyName, pSubKey->GetName(), sizeof( normalKeyName ) ); + + // substring must match exactly, otherwise keys like "_lodef" and "_lodef_wide" would clash. + char *pString = Q_stristr( normalKeyName, pResString ); + if ( pString && !Q_stricmp( pString, pResString ) ) + { + *pString = '\0'; + + // find and delete the original key (if any) + KeyValues *pKey = FindKey( normalKeyName ); + if ( pKey ) + { + // remove the key + RemoveSubKey( pKey ); + } + + // rename the marked key + pSubKey->SetName( normalKeyName ); + } + } + } + + return true; +} + + + +// +// KeyValues dumping implementation +// +bool KeyValues::Dump( IKeyValuesDumpContext *pDump, int nIndentLevel /* = 0 */ ) +{ + if ( !pDump->KvBeginKey( this, nIndentLevel ) ) + return false; + + // Dump values + for ( KeyValues *val = GetFirstValue(); val; val = val->GetNextValue() ) + { + if ( !pDump->KvWriteValue( val, nIndentLevel + 1 ) ) + return false; + } + + // Dump subkeys + for ( KeyValues *sub = GetFirstTrueSubKey(); sub; sub = sub->GetNextTrueSubKey() ) + { + if ( !sub->Dump( pDump, nIndentLevel + 1 ) ) + return false; + } + + return pDump->KvEndKey( this, nIndentLevel ); +} + +bool IKeyValuesDumpContextAsText::KvBeginKey( KeyValues *pKey, int nIndentLevel ) +{ + if ( pKey ) + { + return + KvWriteIndent( nIndentLevel ) && + KvWriteText( pKey->GetName() ) && + KvWriteText( " {\n" ); + } + else + { + return + KvWriteIndent( nIndentLevel ) && + KvWriteText( "<< NULL >>\n" ); + } +} + +bool IKeyValuesDumpContextAsText::KvWriteValue( KeyValues *val, int nIndentLevel ) +{ + if ( !val ) + { + return + KvWriteIndent( nIndentLevel ) && + KvWriteText( "<< NULL >>\n" ); + } + + if ( !KvWriteIndent( nIndentLevel ) ) + return false; + + if ( !KvWriteText( val->GetName() ) ) + return false; + + if ( !KvWriteText( " " ) ) + return false; + + switch ( val->GetDataType() ) + { + case KeyValues::TYPE_STRING: + { + if ( !KvWriteText( val->GetString() ) ) + return false; + } + break; + + case KeyValues::TYPE_INT: + { + int n = val->GetInt(); + char *chBuffer = ( char * ) stackalloc( 128 ); + V_snprintf( chBuffer, 128, "int( %d = 0x%X )", n, n ); + if ( !KvWriteText( chBuffer ) ) + return false; + } + break; + + case KeyValues::TYPE_FLOAT: + { + float fl = val->GetFloat(); + char *chBuffer = ( char * ) stackalloc( 128 ); + V_snprintf( chBuffer, 128, "float( %f )", fl ); + if ( !KvWriteText( chBuffer ) ) + return false; + } + break; + + case KeyValues::TYPE_PTR: + { + void *ptr = val->GetPtr(); + char *chBuffer = ( char * ) stackalloc( 128 ); + V_snprintf( chBuffer, 128, "ptr( 0x%p )", ptr ); + if ( !KvWriteText( chBuffer ) ) + return false; + } + break; + + case KeyValues::TYPE_WSTRING: + { + wchar_t const *wsz = val->GetWString(); + int nLen = V_wcslen( wsz ); + int numBytes = nLen*2 + 64; + char *chBuffer = ( char * ) stackalloc( numBytes ); + V_snprintf( chBuffer, numBytes, "%ls [wstring, len = %d]", wsz, nLen ); + if ( !KvWriteText( chBuffer ) ) + return false; + } + break; + + case KeyValues::TYPE_UINT64: + { + uint64 n = val->GetUint64(); + char *chBuffer = ( char * ) stackalloc( 128 ); + V_snprintf( chBuffer, 128, "u64( %lld = 0x%llX )", n, n ); + if ( !KvWriteText( chBuffer ) ) + return false; + } + break; + + default: + break; + { + int n = val->GetDataType(); + char *chBuffer = ( char * ) stackalloc( 128 ); + V_snprintf( chBuffer, 128, "??kvtype[%d]", n ); + if ( !KvWriteText( chBuffer ) ) + return false; + } + break; + } + + return KvWriteText( "\n" ); +} + +bool IKeyValuesDumpContextAsText::KvEndKey( KeyValues *pKey, int nIndentLevel ) +{ + if ( pKey ) + { + return + KvWriteIndent( nIndentLevel ) && + KvWriteText( "}\n" ); + } + else + { + return true; + } +} + +bool IKeyValuesDumpContextAsText::KvWriteIndent( int nIndentLevel ) +{ + int numIndentBytes = ( nIndentLevel * 2 + 1 ); + char *pchIndent = ( char * ) stackalloc( numIndentBytes ); + memset( pchIndent, ' ', numIndentBytes - 1 ); + pchIndent[ numIndentBytes - 1 ] = 0; + return KvWriteText( pchIndent ); +} + + +bool CKeyValuesDumpContextAsDevMsg::KvBeginKey( KeyValues *pKey, int nIndentLevel ) +{ + static ConVarRef r_developer( "developer" ); + if ( r_developer.IsValid() && r_developer.GetInt() < m_nDeveloperLevel ) + // If "developer" is not the correct level, then avoid evaluating KeyValues tree early + return false; + else + return IKeyValuesDumpContextAsText::KvBeginKey( pKey, nIndentLevel ); +} + +bool CKeyValuesDumpContextAsDevMsg::KvWriteText( char const *szText ) +{ + if ( m_nDeveloperLevel > 0 ) + { + DevMsg( m_nDeveloperLevel, "%s", szText ); + } + else + { + Msg( "%s", szText ); + } + return true; +} diff --git a/tier1/NetAdr.cpp b/tier1/NetAdr.cpp new file mode 100644 index 0000000..bbad033 --- /dev/null +++ b/tier1/NetAdr.cpp @@ -0,0 +1,346 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// NetAdr.cpp: implementation of the CNetAdr class. +// +//===========================================================================// +#if defined( _WIN32 ) && !defined( _X360 ) +#include +#endif + +#include "tier0/dbg.h" +#include "netadr.h" +#include "tier1/strtools.h" + +#if defined( _WIN32 ) && !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include +typedef int socklen_t; +#elif !defined( _X360 ) +#include // ntohs() +#include // gethostbyname() +#include // getsockname() +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +bool netadr_t::CompareAdr (const netadr_t &a, bool onlyBase) const +{ + if ( a.type != type ) + return false; + + if ( type == NA_LOOPBACK ) + return true; + + if ( type == NA_BROADCAST ) + return true; + + if ( type == NA_IP ) + { + if ( !onlyBase && (port != a.port) ) + return false; + + if ( a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] && a.ip[3] == ip[3] ) + return true; + } + + if ( type == NA_STEAM && m_SteamID == a.m_SteamID ) + return true; + + return false; +} + +bool netadr_t::CompareClassBAdr (const netadr_t &a) const +{ + if ( a.type != type ) + return false; + + if ( type == NA_LOOPBACK ) + return true; + + if ( type == NA_IP ) + { + if (a.ip[0] == ip[0] && a.ip[1] == ip[1] ) + return true; + } + + return false; +} + +bool netadr_t::CompareClassCAdr (const netadr_t &a) const +{ + if ( a.type != type ) + return false; + + if ( type == NA_LOOPBACK ) + return true; + + if ( type == NA_IP ) + { + if (a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] ) + return true; + } + + return false; +} +// reserved addresses are not routeable, so they can all be used in a LAN game +bool netadr_t::IsReservedAdr () const +{ + if ( type == NA_LOOPBACK ) + return true; + + if ( type == NA_IP ) + { + if ( (ip[0] == 10) || // 10.x.x.x is reserved + (ip[0] == 127) || // 127.x.x.x + (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || // 172.16.x.x - 172.31.x.x + (ip[0] == 192 && ip[1] >= 168) ) // 192.168.x.x + return true; + } + return false; +} + +const char * netadr_t::ToString(bool baseOnly) const +{ + static char s[64]; + + Q_strncpy (s, "unknown", sizeof( s ) ); + + if (type == NA_LOOPBACK) + { + Q_strncpy (s, "loopback", sizeof( s ) ); + } + else if (type == NA_BROADCAST) + { + Q_strncpy (s, "broadcast", sizeof( s ) ); + } + else if (type == NA_IP) + { + if ( baseOnly) + { + Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]); + } + else + { + Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port)); + } + } + else if (type == NA_STEAM) + { + EAccountType type = m_SteamID.GetEAccountType(); + if (type == k_EAccountTypeInvalid || type == k_EAccountTypeIndividual) + { + AccountID_t accountID = m_SteamID.GetAccountID(); + Q_snprintf (s, sizeof( s ), "STEAM_0:%u:%u", accountID % 2, accountID / 2); + } + else + Q_snprintf (s, sizeof( s ), "%llu", m_SteamID.ConvertToUint64()); + } + + return s; +} + +bool netadr_t::IsLocalhost() const +{ + // are we 127.0.0.1 ? + return (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1); +} + +bool netadr_t::IsLoopback() const +{ + // are we useding engine loopback buffers + return type == NA_LOOPBACK; +} + +void netadr_t::Clear() +{ + m_SteamID.Clear(); + ip[0] = ip[1] = ip[2] = ip[3] = 0; + port = 0; + type = NA_NULL; +} + +void netadr_t::SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4) +{ + ip[0] = b1; + ip[1] = b2; + ip[2] = b3; + ip[3] = b4; +} + +void netadr_t::SetIP(uint unIP) +{ + *((uint*)ip) = BigLong( unIP ); +} + +void netadr_t::SetType(netadrtype_t newtype) +{ + type = newtype; +} + +netadrtype_t netadr_t::GetType() const +{ + return type; +} + +unsigned short netadr_t::GetPort() const +{ + return BigShort( port ); +} + +const CSteamID &netadr_t::GetSteamID() const +{ + return m_SteamID; +} + +unsigned int netadr_t::GetIPNetworkByteOrder() const +{ + return *(unsigned int *)&ip; +} + +unsigned int netadr_t::GetIPHostByteOrder() const +{ + return ntohl( GetIPNetworkByteOrder() ); +} + + +void netadr_t::ToSockadr (struct sockaddr * s) const +{ + Q_memset ( s, 0, sizeof(struct sockaddr)); + + if (type == NA_BROADCAST) + { + ((struct sockaddr_in*)s)->sin_family = AF_INET; + ((struct sockaddr_in*)s)->sin_port = port; + ((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_BROADCAST; + } + else if (type == NA_IP) + { + ((struct sockaddr_in*)s)->sin_family = AF_INET; + ((struct sockaddr_in*)s)->sin_addr.s_addr = *(int *)&ip; + ((struct sockaddr_in*)s)->sin_port = port; + } + else if (type == NA_LOOPBACK ) + { + ((struct sockaddr_in*)s)->sin_family = AF_INET; + ((struct sockaddr_in*)s)->sin_port = port; + ((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_LOOPBACK ; + } +} + +bool netadr_t::SetFromSockadr(const struct sockaddr * s) +{ + if (s->sa_family == AF_INET) + { + type = NA_IP; + *(int *)&ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; + port = ((struct sockaddr_in *)s)->sin_port; + return true; + } + else + { + Clear(); + return false; + } +} + +bool netadr_t::IsValid() const +{ + return type != NA_NULL && ( type == NA_STEAM ? m_SteamID.IsValid() : + ( port != 0 && ( ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0 ) ) ); +} + +#ifdef _WIN32 +#undef SetPort // get around stupid WINSPOOL.H macro +#endif + +void netadr_t::SetPort(unsigned short newport) +{ + port = BigShort( newport ); +} + +void netadr_t::SetFromString( const char *pch, bool bUseDNS ) +{ + Clear(); + type = NA_IP; + + Assert( pch ); // invalid to call this with NULL pointer; fix your code bug! + if ( !pch ) // but let's not crash + return; + + + if ( pch[0] >= '0' && pch[0] <= '9' && strchr( pch, '.' ) ) + { + int n1 = 0, n2 = 0, n3 = 0, n4 = 0, n5 = 0; + int nRes = sscanf( pch, "%d.%d.%d.%d:%d", &n1, &n2, &n3, &n4, &n5 ); + if ( nRes >= 4 ) + { + SetIP( n1, n2, n3, n4 ); + } + + if ( nRes == 5 ) + { + SetPort( ( uint16 ) n5 ); + } + } + else if ( bUseDNS ) + { +// X360TBD: +#if !defined( _X360 ) + char szHostName[ 256 ]; + Q_strncpy( szHostName, pch, sizeof(szHostName) ); + char *pchColon = strchr( szHostName, ':' ); + if ( pchColon ) + { + *pchColon = 0; + } + + // DNS it + struct hostent *h = gethostbyname( szHostName ); + if ( !h ) + return; + + SetIP( ntohl( *(int *)h->h_addr_list[0] ) ); + + if ( pchColon ) + { + SetPort( atoi( ++pchColon ) ); + } +#else + Assert( 0 ); +#endif + } +} + +bool netadr_t::operator<(const netadr_t &netadr) const +{ + if ( *((uint *)netadr.ip) < *((uint *)ip) ) + return true; + else if ( *((uint *)netadr.ip) > *((uint *)ip) ) + return false; + return ( netadr.port < port ); +} + + +void netadr_t::SetFromSocket( int hSocket ) +{ +#if !defined(_X360) + Clear(); + type = NA_IP; + + struct sockaddr address; + int namelen = sizeof(address); + if ( getsockname( hSocket, (struct sockaddr *)&address, (socklen_t *)&namelen) == 0 ) + { + SetFromSockadr( &address ); + } +#else + Assert(0); +#endif +} diff --git a/tier1/bitbuf.cpp b/tier1/bitbuf.cpp new file mode 100644 index 0000000..4ce2751 --- /dev/null +++ b/tier1/bitbuf.cpp @@ -0,0 +1,1490 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "bitbuf.h" +#include "coordsize.h" +#include "mathlib/vector.h" +#include "mathlib/mathlib.h" +#include "tier1/strtools.h" +#include "bitvec.h" + +// FIXME: Can't use this until we get multithreaded allocations in tier0 working for tools +// This is used by VVIS and fails to link +// NOTE: This must be the last file included!!! +//#include "tier0/memdbgon.h" + +#ifdef _X360 +// mandatory ... wary of above comment and isolating, tier0 is built as MT though +#include "tier0/memdbgon.h" +#endif + +#if _WIN32 +#define FAST_BIT_SCAN 1 +#if _X360 +#define CountLeadingZeros(x) _CountLeadingZeros(x) +inline unsigned int CountTrailingZeros( unsigned int elem ) +{ + // this implements CountTrailingZeros() / BitScanForward() + unsigned int mask = elem-1; + unsigned int comp = ~elem; + elem = mask & comp; + return (32 - _CountLeadingZeros(elem)); +} +#else +#include +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) + +inline unsigned int CountLeadingZeros(unsigned int x) +{ + unsigned long firstBit; + if ( _BitScanReverse(&firstBit,x) ) + return 31 - firstBit; + return 32; +} +inline unsigned int CountTrailingZeros(unsigned int elem) +{ + unsigned long out; + if ( _BitScanForward(&out, elem) ) + return out; + return 32; +} + +#endif +#else +#define FAST_BIT_SCAN 0 +#endif + + +static BitBufErrorHandler g_BitBufErrorHandler = 0; + +inline int BitForBitnum(int bitnum) +{ + return GetBitForBitnum(bitnum); +} + +void InternalBitBufErrorHandler( BitBufErrorType errorType, const char *pDebugName ) +{ + if ( g_BitBufErrorHandler ) + g_BitBufErrorHandler( errorType, pDebugName ); +} + + +void SetBitBufErrorHandler( BitBufErrorHandler fn ) +{ + g_BitBufErrorHandler = fn; +} + + +// #define BB_PROFILING + +unsigned long g_LittleBits[32]; + +// Precalculated bit masks for WriteUBitLong. Using these tables instead of +// doing the calculations gives a 33% speedup in WriteUBitLong. +unsigned long g_BitWriteMasks[32][33]; + +// (1 << i) - 1 +unsigned long g_ExtraMasks[33]; + +class CBitWriteMasksInit +{ +public: + CBitWriteMasksInit() + { + for( unsigned int startbit=0; startbit < 32; startbit++ ) + { + for( unsigned int nBitsLeft=0; nBitsLeft < 33; nBitsLeft++ ) + { + unsigned int endbit = startbit + nBitsLeft; + g_BitWriteMasks[startbit][nBitsLeft] = BitForBitnum(startbit) - 1; + if(endbit < 32) + g_BitWriteMasks[startbit][nBitsLeft] |= ~(BitForBitnum(endbit) - 1); + } + } + + for ( unsigned int maskBit=0; maskBit < 32; maskBit++ ) + g_ExtraMasks[maskBit] = BitForBitnum(maskBit) - 1; + g_ExtraMasks[32] = ~0ul; + + for ( unsigned int littleBit=0; littleBit < 32; littleBit++ ) + StoreLittleDWord( &g_LittleBits[littleBit], 0, 1u<> ( 32 - numbits ) ); + int nSignExtension = ( nValue >> 31 ) & ~nPreserveBits; + nValue &= nPreserveBits; + nValue |= nSignExtension; + + AssertMsg2( nValue == data, "WriteSBitLong: 0x%08x does not fit in %d bits", data, numbits ); + + WriteUBitLong( nValue, numbits, false ); +} + +void bf_write::WriteVarInt32( uint32 data ) +{ + // Check if align and we have room, slow path if not + if ( (m_iCurBit & 7) == 0 && (m_iCurBit + bitbuf::kMaxVarint32Bytes * 8 ) <= m_nDataBits) + { + uint8 *target = ((uint8*)m_pData) + (m_iCurBit>>3); + + target[0] = static_cast(data | 0x80); + if ( data >= (1 << 7) ) + { + target[1] = static_cast((data >> 7) | 0x80); + if ( data >= (1 << 14) ) + { + target[2] = static_cast((data >> 14) | 0x80); + if ( data >= (1 << 21) ) + { + target[3] = static_cast((data >> 21) | 0x80); + if ( data >= (1 << 28) ) + { + target[4] = static_cast(data >> 28); + m_iCurBit += 5 * 8; + return; + } + else + { + target[3] &= 0x7F; + m_iCurBit += 4 * 8; + return; + } + } + else + { + target[2] &= 0x7F; + m_iCurBit += 3 * 8; + return; + } + } + else + { + target[1] &= 0x7F; + m_iCurBit += 2 * 8; + return; + } + } + else + { + target[0] &= 0x7F; + m_iCurBit += 1 * 8; + return; + } + } + else // Slow path + { + while ( data > 0x7F ) + { + WriteUBitLong( (data & 0x7F) | 0x80, 8 ); + data >>= 7; + } + WriteUBitLong( data & 0x7F, 8 ); + } +} + +void bf_write::WriteVarInt64( uint64 data ) +{ + // Check if align and we have room, slow path if not + if ( (m_iCurBit & 7) == 0 && (m_iCurBit + bitbuf::kMaxVarintBytes * 8 ) <= m_nDataBits ) + { + uint8 *target = ((uint8*)m_pData) + (m_iCurBit>>3); + + // Splitting into 32-bit pieces gives better performance on 32-bit + // processors. + uint32 part0 = static_cast(data ); + uint32 part1 = static_cast(data >> 28); + uint32 part2 = static_cast(data >> 56); + + int size; + + // Here we can't really optimize for small numbers, since the data is + // split into three parts. Cheking for numbers < 128, for instance, + // would require three comparisons, since you'd have to make sure part1 + // and part2 are zero. However, if the caller is using 64-bit integers, + // it is likely that they expect the numbers to often be very large, so + // we probably don't want to optimize for small numbers anyway. Thus, + // we end up with a hardcoded binary search tree... + if ( part2 == 0 ) + { + if ( part1 == 0 ) + { + if ( part0 < (1 << 14) ) + { + if ( part0 < (1 << 7) ) + { + size = 1; goto size1; + } + else + { + size = 2; goto size2; + } + } + else + { + if ( part0 < (1 << 21) ) + { + size = 3; goto size3; + } + else + { + size = 4; goto size4; + } + } + } + else + { + if ( part1 < (1 << 14) ) + { + if ( part1 < (1 << 7) ) + { + size = 5; goto size5; + } + else + { + size = 6; goto size6; + } + } + else + { + if ( part1 < (1 << 21) ) + { + size = 7; goto size7; + } + else + { + size = 8; goto size8; + } + } + } + } + else + { + if ( part2 < (1 << 7) ) + { + size = 9; goto size9; + } + else + { + size = 10; goto size10; + } + } + + AssertFatalMsg( false, "Can't get here." ); + + size10: target[9] = static_cast((part2 >> 7) | 0x80); + size9 : target[8] = static_cast((part2 ) | 0x80); + size8 : target[7] = static_cast((part1 >> 21) | 0x80); + size7 : target[6] = static_cast((part1 >> 14) | 0x80); + size6 : target[5] = static_cast((part1 >> 7) | 0x80); + size5 : target[4] = static_cast((part1 ) | 0x80); + size4 : target[3] = static_cast((part0 >> 21) | 0x80); + size3 : target[2] = static_cast((part0 >> 14) | 0x80); + size2 : target[1] = static_cast((part0 >> 7) | 0x80); + size1 : target[0] = static_cast((part0 ) | 0x80); + + target[size-1] &= 0x7F; + m_iCurBit += size * 8; + } + else // slow path + { + while ( data > 0x7F ) + { + WriteUBitLong( (data & 0x7F) | 0x80, 8 ); + data >>= 7; + } + WriteUBitLong( data & 0x7F, 8 ); + } +} + +void bf_write::WriteSignedVarInt32( int32 data ) +{ + WriteVarInt32( bitbuf::ZigZagEncode32( data ) ); +} + +void bf_write::WriteSignedVarInt64( int64 data ) +{ + WriteVarInt64( bitbuf::ZigZagEncode64( data ) ); +} + +int bf_write::ByteSizeVarInt32( uint32 data ) +{ + int size = 1; + while ( data > 0x7F ) { + size++; + data >>= 7; + } + return size; +} + +int bf_write::ByteSizeVarInt64( uint64 data ) +{ + int size = 1; + while ( data > 0x7F ) { + size++; + data >>= 7; + } + return size; +} + +int bf_write::ByteSizeSignedVarInt32( int32 data ) +{ + return ByteSizeVarInt32( bitbuf::ZigZagEncode32( data ) ); +} + +int bf_write::ByteSizeSignedVarInt64( int64 data ) +{ + return ByteSizeVarInt64( bitbuf::ZigZagEncode64( data ) ); +} + +void bf_write::WriteBitLong(unsigned int data, int numbits, bool bSigned) +{ + if(bSigned) + WriteSBitLong((int)data, numbits); + else + WriteUBitLong(data, numbits); +} + +bool bf_write::WriteBits(const void *pInData, int nBits) +{ +#if defined( BB_PROFILING ) + VPROF( "bf_write::WriteBits" ); +#endif + + unsigned char *pOut = (unsigned char*)pInData; + int nBitsLeft = nBits; + + // Bounds checking.. + if ( (m_iCurBit+nBits) > m_nDataBits ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, GetDebugName() ); + return false; + } + + // Align output to dword boundary + while (((unsigned long)pOut & 3) != 0 && nBitsLeft >= 8) + { + + WriteUBitLong( *pOut, 8, false ); + ++pOut; + nBitsLeft -= 8; + } + + if ( IsPC() && (nBitsLeft >= 32) && (m_iCurBit & 7) == 0 ) + { + // current bit is byte aligned, do block copy + int numbytes = nBitsLeft >> 3; + int numbits = numbytes << 3; + + Q_memcpy( (char*)m_pData+(m_iCurBit>>3), pOut, numbytes ); + pOut += numbytes; + nBitsLeft -= numbits; + m_iCurBit += numbits; + } + + // X360TBD: Can't write dwords in WriteBits because they'll get swapped + if ( IsPC() && nBitsLeft >= 32 ) + { + unsigned long iBitsRight = (m_iCurBit & 31); + unsigned long iBitsLeft = 32 - iBitsRight; + unsigned long bitMaskLeft = g_BitWriteMasks[iBitsRight][32]; + unsigned long bitMaskRight = g_BitWriteMasks[0][iBitsRight]; + + unsigned long *pData = &m_pData[m_iCurBit>>5]; + + // Read dwords. + while(nBitsLeft >= 32) + { + unsigned long curData = *(unsigned long*)pOut; + pOut += sizeof(unsigned long); + + *pData &= bitMaskLeft; + *pData |= curData << iBitsRight; + + pData++; + + if ( iBitsLeft < 32 ) + { + curData >>= iBitsLeft; + *pData &= bitMaskRight; + *pData |= curData; + } + + nBitsLeft -= 32; + m_iCurBit += 32; + } + } + + + // write remaining bytes + while ( nBitsLeft >= 8 ) + { + WriteUBitLong( *pOut, 8, false ); + ++pOut; + nBitsLeft -= 8; + } + + // write remaining bits + if ( nBitsLeft ) + { + WriteUBitLong( *pOut, nBitsLeft, false ); + } + + return !IsOverflowed(); +} + + +bool bf_write::WriteBitsFromBuffer( bf_read *pIn, int nBits ) +{ + // This could be optimized a little by + while ( nBits > 32 ) + { + WriteUBitLong( pIn->ReadUBitLong( 32 ), 32 ); + nBits -= 32; + } + + WriteUBitLong( pIn->ReadUBitLong( nBits ), nBits ); + return !IsOverflowed() && !pIn->IsOverflowed(); +} + + +void bf_write::WriteBitAngle( float fAngle, int numbits ) +{ + int d; + unsigned int mask; + unsigned int shift; + + shift = BitForBitnum(numbits); + mask = shift - 1; + + d = (int)( (fAngle / 360.0) * shift ); + d &= mask; + + WriteUBitLong((unsigned int)d, numbits); +} + +void bf_write::WriteBitCoordMP( const float f, bool bIntegral, bool bLowPrecision ) +{ +#if defined( BB_PROFILING ) + VPROF( "bf_write::WriteBitCoordMP" ); +#endif + int signbit = (f <= -( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION )); + int intval = abs((int)f); + int fractval = bLowPrecision ? + ( abs((int)(f*COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION-1) ) : + ( abs((int)(f*COORD_DENOMINATOR)) & (COORD_DENOMINATOR-1) ); + + bool bInBounds = intval < (1 << COORD_INTEGER_BITS_MP ); + + unsigned int bits, numbits; + + if ( bIntegral ) + { + // Integer encoding: in-bounds bit, nonzero bit, optional sign bit + integer value bits + if ( intval ) + { + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + --intval; + bits = intval * 8 + signbit * 4 + 2 + bInBounds; + numbits = 3 + (bInBounds ? COORD_INTEGER_BITS_MP : COORD_INTEGER_BITS); + } + else + { + bits = bInBounds; + numbits = 2; + } + } + else + { + // Float encoding: in-bounds bit, integer bit, sign bit, fraction value bits, optional integer value bits + if ( intval ) + { + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + --intval; + bits = intval * 8 + signbit * 4 + 2 + bInBounds; + bits += bInBounds ? (fractval << (3+COORD_INTEGER_BITS_MP)) : (fractval << (3+COORD_INTEGER_BITS)); + numbits = 3 + (bInBounds ? COORD_INTEGER_BITS_MP : COORD_INTEGER_BITS) + + (bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS); + } + else + { + bits = fractval * 8 + signbit * 4 + 0 + bInBounds; + numbits = 3 + (bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS); + } + } + + WriteUBitLong( bits, numbits ); +} + +void bf_write::WriteBitCoord (const float f) +{ +#if defined( BB_PROFILING ) + VPROF( "bf_write::WriteBitCoord" ); +#endif + int signbit = (f <= -COORD_RESOLUTION); + int intval = abs((int)f); + int fractval = abs((int)(f*COORD_DENOMINATOR)) & (COORD_DENOMINATOR-1); + + + // Send the bit flags that indicate whether we have an integer part and/or a fraction part. + WriteOneBit( intval ); + WriteOneBit( fractval ); + + if ( intval || fractval ) + { + // Send the sign bit + WriteOneBit( signbit ); + + // Send the integer if we have one. + if ( intval ) + { + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + intval--; + WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS ); + } + + // Send the fraction if we have one + if ( fractval ) + { + WriteUBitLong( (unsigned int)fractval, COORD_FRACTIONAL_BITS ); + } + } +} + +void bf_write::WriteBitVec3Coord( const Vector& fa ) +{ + int xflag, yflag, zflag; + + xflag = (fa[0] >= COORD_RESOLUTION) || (fa[0] <= -COORD_RESOLUTION); + yflag = (fa[1] >= COORD_RESOLUTION) || (fa[1] <= -COORD_RESOLUTION); + zflag = (fa[2] >= COORD_RESOLUTION) || (fa[2] <= -COORD_RESOLUTION); + + WriteOneBit( xflag ); + WriteOneBit( yflag ); + WriteOneBit( zflag ); + + if ( xflag ) + WriteBitCoord( fa[0] ); + if ( yflag ) + WriteBitCoord( fa[1] ); + if ( zflag ) + WriteBitCoord( fa[2] ); +} + +void bf_write::WriteBitNormal( float f ) +{ + int signbit = (f <= -NORMAL_RESOLUTION); + + // NOTE: Since +/-1 are valid values for a normal, I'm going to encode that as all ones + unsigned int fractval = abs( (int)(f*NORMAL_DENOMINATOR) ); + + // clamp.. + if (fractval > NORMAL_DENOMINATOR) + fractval = NORMAL_DENOMINATOR; + + // Send the sign bit + WriteOneBit( signbit ); + + // Send the fractional component + WriteUBitLong( fractval, NORMAL_FRACTIONAL_BITS ); +} + +void bf_write::WriteBitVec3Normal( const Vector& fa ) +{ + int xflag, yflag; + + xflag = (fa[0] >= NORMAL_RESOLUTION) || (fa[0] <= -NORMAL_RESOLUTION); + yflag = (fa[1] >= NORMAL_RESOLUTION) || (fa[1] <= -NORMAL_RESOLUTION); + + WriteOneBit( xflag ); + WriteOneBit( yflag ); + + if ( xflag ) + WriteBitNormal( fa[0] ); + if ( yflag ) + WriteBitNormal( fa[1] ); + + // Write z sign bit + int signbit = (fa[2] <= -NORMAL_RESOLUTION); + WriteOneBit( signbit ); +} + +void bf_write::WriteBitAngles( const QAngle& fa ) +{ + // FIXME: + Vector tmp( fa.x, fa.y, fa.z ); + WriteBitVec3Coord( tmp ); +} + +void bf_write::WriteChar(int val) +{ + WriteSBitLong(val, sizeof(char) << 3); +} + +void bf_write::WriteByte(int val) +{ + WriteUBitLong(val, sizeof(unsigned char) << 3); +} + +void bf_write::WriteShort(int val) +{ + WriteSBitLong(val, sizeof(short) << 3); +} + +void bf_write::WriteWord(int val) +{ + WriteUBitLong(val, sizeof(unsigned short) << 3); +} + +void bf_write::WriteLong(long val) +{ + WriteSBitLong(val, sizeof(long) << 3); +} + +void bf_write::WriteLongLong(int64 val) +{ + uint *pLongs = (uint*)&val; + + // Insert the two DWORDS according to network endian + const short endianIndex = 0x0100; + byte *idx = (byte*)&endianIndex; + WriteUBitLong(pLongs[*idx++], sizeof(long) << 3); + WriteUBitLong(pLongs[*idx], sizeof(long) << 3); +} + +void bf_write::WriteFloat(float val) +{ + // Pre-swap the float, since WriteBits writes raw data + LittleFloat( &val, &val ); + + WriteBits(&val, sizeof(val) << 3); +} + +bool bf_write::WriteBytes( const void *pBuf, int nBytes ) +{ + return WriteBits(pBuf, nBytes << 3); +} + +bool bf_write::WriteString(const char *pStr) +{ + if(pStr) + { + do + { + WriteChar( *pStr ); + ++pStr; + } while( *(pStr-1) != 0 ); + } + else + { + WriteChar( 0 ); + } + + return !IsOverflowed(); +} + +// ---------------------------------------------------------------------------------------- // +// bf_read +// ---------------------------------------------------------------------------------------- // + +bf_read::bf_read() +{ + m_pData = NULL; + m_nDataBytes = 0; + m_nDataBits = -1; // set to -1 so we overflow on any operation + m_iCurBit = 0; + m_bOverflow = false; + m_bAssertOnOverflow = true; + m_pDebugName = NULL; +} + +bf_read::bf_read( const void *pData, int nBytes, int nBits ) +{ + m_bAssertOnOverflow = true; + StartReading( pData, nBytes, 0, nBits ); +} + +bf_read::bf_read( const char *pDebugName, const void *pData, int nBytes, int nBits ) +{ + m_bAssertOnOverflow = true; + m_pDebugName = pDebugName; + StartReading( pData, nBytes, 0, nBits ); +} + +void bf_read::StartReading( const void *pData, int nBytes, int iStartBit, int nBits ) +{ + // Make sure we're dword aligned. + Assert(((size_t)pData & 3) == 0); + + m_pData = (unsigned char*)pData; + m_nDataBytes = nBytes; + + if ( nBits == -1 ) + { + m_nDataBits = m_nDataBytes << 3; + } + else + { + Assert( nBits <= nBytes*8 ); + m_nDataBits = nBits; + } + + m_iCurBit = iStartBit; + m_bOverflow = false; +} + +void bf_read::Reset() +{ + m_iCurBit = 0; + m_bOverflow = false; +} + +void bf_read::SetAssertOnOverflow( bool bAssert ) +{ + m_bAssertOnOverflow = bAssert; +} + +void bf_read::SetDebugName( const char *pName ) +{ + m_pDebugName = pName; +} + +void bf_read::SetOverflowFlag() +{ + if ( m_bAssertOnOverflow ) + { + Assert( false ); + } + m_bOverflow = true; +} + +unsigned int bf_read::CheckReadUBitLong(int numbits) +{ + // Ok, just read bits out. + int i, nBitValue; + unsigned int r = 0; + + for(i=0; i < numbits; i++) + { + nBitValue = ReadOneBitNoCheck(); + r |= nBitValue << i; + } + m_iCurBit -= numbits; + + return r; +} + +void bf_read::ReadBits(void *pOutData, int nBits) +{ +#if defined( BB_PROFILING ) + VPROF( "bf_read::ReadBits" ); +#endif + + unsigned char *pOut = (unsigned char*)pOutData; + int nBitsLeft = nBits; + + + // align output to dword boundary + while( ((size_t)pOut & 3) != 0 && nBitsLeft >= 8 ) + { + *pOut = (unsigned char)ReadUBitLong(8); + ++pOut; + nBitsLeft -= 8; + } + + // X360TBD: Can't read dwords in ReadBits because they'll get swapped + if ( IsPC() ) + { + // read dwords + while ( nBitsLeft >= 32 ) + { + *((unsigned long*)pOut) = ReadUBitLong(32); + pOut += sizeof(unsigned long); + nBitsLeft -= 32; + } + } + + // read remaining bytes + while ( nBitsLeft >= 8 ) + { + *pOut = ReadUBitLong(8); + ++pOut; + nBitsLeft -= 8; + } + + // read remaining bits + if ( nBitsLeft ) + { + *pOut = ReadUBitLong(nBitsLeft); + } + +} + +int bf_read::ReadBitsClamped_ptr(void *pOutData, size_t outSizeBytes, size_t nBits) +{ + size_t outSizeBits = outSizeBytes * 8; + size_t readSizeBits = nBits; + int skippedBits = 0; + if ( readSizeBits > outSizeBits ) + { + // Should we print a message when we clamp the data being read? Only + // in debug builds I think. + AssertMsg( 0, "Oversized network packet received, and clamped." ); + readSizeBits = outSizeBits; + skippedBits = (int)( nBits - outSizeBits ); + // What should we do in this case, which should only happen if nBits + // is negative for some reason? + //if ( skippedBits < 0 ) + // return 0; + } + + ReadBits( pOutData, readSizeBits ); + SeekRelative( skippedBits ); + + // Return the number of bits actually read. + return (int)readSizeBits; +} + +float bf_read::ReadBitAngle( int numbits ) +{ + float fReturn; + int i; + float shift; + + shift = (float)( BitForBitnum(numbits) ); + + i = ReadUBitLong( numbits ); + fReturn = (float)i * (360.0f / shift); + + return fReturn; +} + +unsigned int bf_read::PeekUBitLong( int numbits ) +{ + unsigned int r; + int i, nBitValue; +#ifdef BIT_VERBOSE + int nShifts = numbits; +#endif + + bf_read savebf; + + savebf = *this; // Save current state info + + r = 0; + for(i=0; i < numbits; i++) + { + nBitValue = ReadOneBit(); + + // Append to current stream + if ( nBitValue ) + { + r |= BitForBitnum(i); + } + } + + *this = savebf; + +#ifdef BIT_VERBOSE + Con_Printf( "PeekBitLong: %i %i\n", nShifts, (unsigned int)r ); +#endif + + return r; +} + +unsigned int bf_read::ReadUBitLongNoInline( int numbits ) +{ + return ReadUBitLong( numbits ); +} + +unsigned int bf_read::ReadUBitVarInternal( int encodingType ) +{ + m_iCurBit -= 4; + // int bits = { 4, 8, 12, 32 }[ encodingType ]; + int bits = 4 + encodingType*4 + (((2 - encodingType) >> 31) & 16); + return ReadUBitLong( bits ); +} + +// Append numbits least significant bits from data to the current bit stream +int bf_read::ReadSBitLong( int numbits ) +{ + unsigned int r = ReadUBitLong(numbits); + unsigned int s = 1 << (numbits-1); + if (r >= s) + { + // sign-extend by removing sign bit and then subtracting sign bit again + r = r - s - s; + } + return r; +} + +uint32 bf_read::ReadVarInt32() +{ + uint32 result = 0; + int count = 0; + uint32 b; + + do + { + if ( count == bitbuf::kMaxVarint32Bytes ) + { + return result; + } + b = ReadUBitLong( 8 ); + result |= (b & 0x7F) << (7 * count); + ++count; + } while (b & 0x80); + + return result; +} + +uint64 bf_read::ReadVarInt64() +{ + uint64 result = 0; + int count = 0; + uint64 b; + + do + { + if ( count == bitbuf::kMaxVarintBytes ) + { + return result; + } + b = ReadUBitLong( 8 ); + result |= static_cast(b & 0x7F) << (7 * count); + ++count; + } while (b & 0x80); + + return result; +} + +int32 bf_read::ReadSignedVarInt32() +{ + uint32 value = ReadVarInt32(); + return bitbuf::ZigZagDecode32( value ); +} + +int64 bf_read::ReadSignedVarInt64() +{ + uint32 value = (uint32)ReadVarInt64(); + return bitbuf::ZigZagDecode64( value ); +} + +unsigned int bf_read::ReadBitLong(int numbits, bool bSigned) +{ + if(bSigned) + return (unsigned int)ReadSBitLong(numbits); + else + return ReadUBitLong(numbits); +} + + +// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants) +float bf_read::ReadBitCoord (void) +{ +#if defined( BB_PROFILING ) + VPROF( "bf_read::ReadBitCoord" ); +#endif + int intval=0,fractval=0,signbit=0; + float value = 0.0; + + + // Read the required integer and fraction flags + intval = ReadOneBit(); + fractval = ReadOneBit(); + + // If we got either parse them, otherwise it's a zero. + if ( intval || fractval ) + { + // Read the sign bit + signbit = ReadOneBit(); + + // If there's an integer, read it in + if ( intval ) + { + // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] + intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1; + } + + // If there's a fraction, read it in + if ( fractval ) + { + fractval = ReadUBitLong( COORD_FRACTIONAL_BITS ); + } + + // Calculate the correct floating point value + value = (float)(intval + fractval * COORD_RESOLUTION); + + // Fixup the sign if negative. + if ( signbit ) + value = -value; + } + + return value; +} + +float bf_read::ReadBitCoordMP( bool bIntegral, bool bLowPrecision ) +{ +#if defined( BB_PROFILING ) + VPROF( "bf_read::ReadBitCoordMP" ); +#endif + // BitCoordMP float encoding: inbounds bit, integer bit, sign bit, optional int bits, float bits + // BitCoordMP integer encoding: inbounds bit, integer bit, optional sign bit, optional int bits. + // int bits are always encoded as (value - 1) since zero is handled by the integer bit + + // With integer-only encoding, the presence of the third bit depends on the second + int flags = ReadUBitLong(3 - bIntegral); + enum { INBOUNDS=1, INTVAL=2, SIGN=4 }; + + if ( bIntegral ) + { + if ( flags & INTVAL ) + { + // Read the third bit and the integer portion together at once + unsigned int bits = ReadUBitLong( (flags & INBOUNDS) ? COORD_INTEGER_BITS_MP+1 : COORD_INTEGER_BITS+1 ); + // Remap from [0,N] to [1,N+1] + int intval = (bits >> 1) + 1; + return (float)((bits & 1) ? -intval : intval); + } + return 0.f; + } + + static const float mul_table[4] = + { + 1.f/(1<> COORD_INTEGER_BITS_MP; + uint fracbits = bits >> COORD_INTEGER_BITS; + + uint intmaskMP = ((1<> 3; +} + +int bf_read::CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffset, int numbits ) RESTRICT +{ + extern unsigned long g_ExtraMasks[33]; + + if ( numbits == 0 ) + return 0; + + int overflow1 = offset + numbits > m_nDataBits; + int overflow2 = otherOffset + numbits > other->m_nDataBits; + + int x = overflow1 | overflow2; + if ( x != 0 ) + return x; + + unsigned int iStartBit1 = offset & 31u; + unsigned int iStartBit2 = otherOffset & 31u; + unsigned long *pData1 = (unsigned long*)m_pData + (offset >> 5); + unsigned long *pData2 = (unsigned long*)other->m_pData + (otherOffset >> 5); + unsigned long *pData1End = pData1 + ((offset + numbits - 1) >> 5); + unsigned long *pData2End = pData2 + ((otherOffset + numbits - 1) >> 5); + + while ( numbits > 32 ) + { + x = LoadLittleDWord( (unsigned long*)pData1, 0 ) >> iStartBit1; + x ^= LoadLittleDWord( (unsigned long*)pData1, 1 ) << (32 - iStartBit1); + x ^= LoadLittleDWord( (unsigned long*)pData2, 0 ) >> iStartBit2; + x ^= LoadLittleDWord( (unsigned long*)pData2, 1 ) << (32 - iStartBit2); + if ( x != 0 ) + { + return x; + } + ++pData1; + ++pData2; + numbits -= 32; + } + + x = LoadLittleDWord( (unsigned long*)pData1, 0 ) >> iStartBit1; + x ^= LoadLittleDWord( (unsigned long*)pData1End, 0 ) << (32 - iStartBit1); + x ^= LoadLittleDWord( (unsigned long*)pData2, 0 ) >> iStartBit2; + x ^= LoadLittleDWord( (unsigned long*)pData2End, 0 ) << (32 - iStartBit2); + return x & g_ExtraMasks[ numbits ]; +} diff --git a/tier1/byteswap.cpp b/tier1/byteswap.cpp new file mode 100644 index 0000000..9f66297 --- /dev/null +++ b/tier1/byteswap.cpp @@ -0,0 +1,90 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Low level byte swapping routines. +// +// $NoKeywords: $ +//============================================================================= + +#include "byteswap.h" + +//----------------------------------------------------------------------------- +// Copy a single field from the input buffer to the output buffer, swapping the bytes if necessary +//----------------------------------------------------------------------------- +void CByteswap::SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField ) +{ + switch ( pField->fieldType ) + { + case FIELD_CHARACTER: + SwapBufferToTargetEndian( (char*)pOutputBuffer, (char*)pData, pField->fieldSize ); + break; + + case FIELD_BOOLEAN: + SwapBufferToTargetEndian( (bool*)pOutputBuffer, (bool*)pData, pField->fieldSize ); + break; + + case FIELD_SHORT: + SwapBufferToTargetEndian( (short*)pOutputBuffer, (short*)pData, pField->fieldSize ); + break; + + case FIELD_FLOAT: + SwapBufferToTargetEndian( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize ); + break; + + case FIELD_INTEGER: + SwapBufferToTargetEndian( (int*)pOutputBuffer, (int*)pData, pField->fieldSize ); + break; + + case FIELD_VECTOR: + SwapBufferToTargetEndian( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 3 ); + break; + + case FIELD_VECTOR2D: + SwapBufferToTargetEndian( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 2 ); + break; + + case FIELD_QUATERNION: + SwapBufferToTargetEndian( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 4 ); + break; + + case FIELD_EMBEDDED: + { + typedescription_t *pEmbed = pField->td->dataDesc; + for ( int i = 0; i < pField->fieldSize; ++i ) + { + SwapFieldsToTargetEndian( (byte*)pOutputBuffer + pEmbed->fieldOffset[ TD_OFFSET_NORMAL ], + (byte*)pData + pEmbed->fieldOffset[ TD_OFFSET_NORMAL ], + pField->td ); + + pOutputBuffer = (byte*)pOutputBuffer + pField->fieldSizeInBytes; + pData = (byte*)pData + pField->fieldSizeInBytes; + } + } + break; + + default: + assert(0); + } +} + +//----------------------------------------------------------------------------- +// Write a block of fields. Works a bit like the saverestore code. +//----------------------------------------------------------------------------- +void CByteswap::SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap ) +{ + // deal with base class first + if ( pDataMap->baseMap ) + { + SwapFieldsToTargetEndian( pOutputBuffer, pBaseData, pDataMap->baseMap ); + } + + typedescription_t *pFields = pDataMap->dataDesc; + int fieldCount = pDataMap->dataNumFields; + for ( int i = 0; i < fieldCount; ++i ) + { + typedescription_t *pField = &pFields[i]; + SwapFieldToTargetEndian( (BYTE*)pOutputBuffer + pField->fieldOffset[ TD_OFFSET_NORMAL ], + (BYTE*)pBaseData + pField->fieldOffset[ TD_OFFSET_NORMAL ], + pField ); + } +} + diff --git a/tier1/characterset.cpp b/tier1/characterset.cpp new file mode 100644 index 0000000..a7c518b --- /dev/null +++ b/tier1/characterset.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "characterset.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: builds a simple lookup table of a group of important characters +// Input : *pParseGroup - pointer to the buffer for the group +// *pGroupString - null terminated list of characters to flag +//----------------------------------------------------------------------------- +void CharacterSetBuild( characterset_t *pSetBuffer, const char *pszSetString ) +{ + int i = 0; + + // Test our pointers + if ( !pSetBuffer || !pszSetString ) + return; + + memset( pSetBuffer->set, 0, sizeof(pSetBuffer->set) ); + + while ( pszSetString[i] ) + { + pSetBuffer->set[ (unsigned)pszSetString[i] ] = 1; + i++; + } + +} diff --git a/tier1/checksum_crc.cpp b/tier1/checksum_crc.cpp new file mode 100644 index 0000000..b9dacbb --- /dev/null +++ b/tier1/checksum_crc.cpp @@ -0,0 +1,180 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic CRC functions +// +//=============================================================================// + +#include "basetypes.h" +#include "commonmacros.h" +#include "checksum_crc.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define CRC32_INIT_VALUE 0xFFFFFFFFUL +#define CRC32_XOR_VALUE 0xFFFFFFFFUL + +#define NUM_BYTES 256 +static const CRC32_t pulCRCTable[NUM_BYTES] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +void CRC32_Init(CRC32_t *pulCRC) +{ + *pulCRC = CRC32_INIT_VALUE; +} + +void CRC32_Final(CRC32_t *pulCRC) +{ + *pulCRC ^= CRC32_XOR_VALUE; +} + +CRC32_t CRC32_GetTableEntry( unsigned int slot ) +{ + return pulCRCTable[(unsigned char)slot]; +} + +void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer) +{ + CRC32_t ulCrc = *pulCRC; + unsigned char *pb = (unsigned char *)pBuffer; + unsigned int nFront; + int nMain; + +JustAfew: + + switch (nBuffer) + { + case 7: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + + case 6: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + + case 5: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + + case 4: + ulCrc ^= LittleLong( *(CRC32_t *)pb ); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + *pulCRC = ulCrc; + return; + + case 3: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + + case 2: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + + case 1: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + + case 0: + *pulCRC = ulCrc; + return; + } + + // We may need to do some alignment work up front, and at the end, so that + // the main loop is aligned and only has to worry about 8 byte at a time. + // + // The low-order two bits of pb and nBuffer in total control the + // upfront work. + // + nFront = ((unsigned int)pb) & 3; + nBuffer -= nFront; + switch (nFront) + { + case 3: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + case 2: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + case 1: + ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); + } + + nMain = nBuffer >> 3; + while (nMain--) + { + ulCrc ^= LittleLong( *(CRC32_t *)pb ); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) ); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); + pb += 8; + } + + nBuffer &= 7; + goto JustAfew; +} diff --git a/tier1/checksum_md5.cpp b/tier1/checksum_md5.cpp new file mode 100644 index 0000000..89661ae --- /dev/null +++ b/tier1/checksum_md5.cpp @@ -0,0 +1,305 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "basetypes.h" +#include "commonmacros.h" +#include "checksum_md5.h" +#include +#include +#include "tier1/strtools.h" +#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// The four core functions - F1 is optimized somewhat +// #define F1(x, y, z) (x & y | ~x & z) +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +// This is the central step in the MD5 algorithm. +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +//----------------------------------------------------------------------------- +// Purpose: The core of the MD5 algorithm, this alters an existing MD5 hash to +// reflect the addition of 16 longwords of new data. MD5Update blocks +// the data and converts bytes into longwords for this routine. +// Input : buf[4] - +// in[16] - +// Output : static void +//----------------------------------------------------------------------------- +static void MD5Transform(unsigned int buf[4], unsigned int const in[16]) +{ + unsigned int a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +//----------------------------------------------------------------------------- +// Purpose: Start MD5 accumulation. Set bit count to 0 and buffer to mysterious initialization constants. + +// Input : *ctx - +//----------------------------------------------------------------------------- +void MD5Init(MD5Context_t *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Update context to reflect the concatenation of another buffer full of bytes. +// Input : *ctx - +// *buf - +// len - +//----------------------------------------------------------------------------- +void MD5Update(MD5Context_t *ctx, unsigned char const *buf, unsigned int len) +{ + unsigned int t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((unsigned int) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) + { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) + { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +//----------------------------------------------------------------------------- +// Purpose: Final wrapup - pad to 64-byte boundary with the bit pattern +// 1 0* (64-bit count of bits processed, MSB-first) +// Input : digest[MD5_DIGEST_LENGTH] - +// *ctx - +//----------------------------------------------------------------------------- +void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5Context_t *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + //byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((unsigned int *) ctx->in)[14] = ctx->bits[0]; + ((unsigned int *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + //byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *hash - +// hashlen - +// Output : char +//----------------------------------------------------------------------------- +char *MD5_Print( unsigned char *hash, int hashlen ) +{ + static char szReturn[64]; + + Assert( hashlen <= 32 ); + + Q_binarytohex( hash, hashlen, szReturn, sizeof( szReturn ) ); + return szReturn; +} + +//----------------------------------------------------------------------------- +// Purpose: generate pseudo random number from a seed number +// Input : seed number +// Output : pseudo random number +//----------------------------------------------------------------------------- +unsigned int MD5_PseudoRandom(unsigned int nSeed) +{ + MD5Context_t ctx; + unsigned char digest[MD5_DIGEST_LENGTH]; // The MD5 Hash + + memset( &ctx, 0, sizeof( ctx ) ); + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)&nSeed, sizeof(nSeed) ); + MD5Final(digest, &ctx); + + return *(unsigned int*)(digest+6); // use 4 middle bytes for random value +} + +//----------------------------------------------------------------------------- +bool MD5_Compare( const MD5Value_t &data, const MD5Value_t &compare ) +{ + return V_memcmp( data.bits, compare.bits, MD5_DIGEST_LENGTH ) == 0; +} + +//----------------------------------------------------------------------------- +void MD5Value_t::Zero() +{ + V_memset( bits, 0, sizeof( bits ) ); +} + +//----------------------------------------------------------------------------- +bool MD5Value_t::IsZero() const +{ + for ( int i = 0 ; i < Q_ARRAYSIZE( bits ) ; ++i ) + { + if ( bits[i] != 0 ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +void MD5_ProcessSingleBuffer( const void *p, int len, MD5Value_t &md5Result ) +{ + Assert( len >= 0 ); + MD5Context_t ctx; + MD5Init( &ctx ); + MD5Update( &ctx, (unsigned char const *)p, len ); + MD5Final( md5Result.bits, &ctx ); +} diff --git a/tier1/checksum_sha1.cpp b/tier1/checksum_sha1.cpp new file mode 100644 index 0000000..ee6e27c --- /dev/null +++ b/tier1/checksum_sha1.cpp @@ -0,0 +1,299 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implementation of SHA-1 +// +//============================================================================= + +/* + 100% free public domain implementation of the SHA-1 + algorithm by Dominik Reichl + + + === Test Vectors (from FIPS PUB 180-1) === + + SHA1("abc") = + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + + SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + + SHA1(A million repetitions of "a") = + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#if !defined(_MINIMUM_BUILD_) +#include "checksum_sha1.h" +#else +// +// This path is build in the CEG/DRM projects where we require that no CRT references are made ! +// +#include // memcpy, memset etc... will be inlined. +#include "tier1/checksum_sha1.h" +#endif + +#define MAX_FILE_READ_BUFFER 8000 + +// Rotate x bits to the left +#ifndef ROL32 +#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits)))) +#endif + +#ifdef SHA1_LITTLE_ENDIAN + #define SHABLK0(i) (m_block->l[i] = \ + (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF)) +#else + #define SHABLK0(i) (m_block->l[i]) +#endif + +#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \ + ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1)) + +// SHA-1 rounds +#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } +#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } +#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); } +#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); } +#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); } + +#ifdef _MINIMUM_BUILD_ +Minimum_CSHA1::Minimum_CSHA1() +#else +CSHA1::CSHA1() +#endif +{ + m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace; + + Reset(); +} +#ifdef _MINIMUM_BUILD_ +Minimum_CSHA1::~Minimum_CSHA1() +#else +CSHA1::~CSHA1() +#endif +{ + // Reset(); +} +#ifdef _MINIMUM_BUILD_ +void Minimum_CSHA1::Reset() +#else +void CSHA1::Reset() +#endif +{ + // SHA1 initialization constants + m_state[0] = 0x67452301; + m_state[1] = 0xEFCDAB89; + m_state[2] = 0x98BADCFE; + m_state[3] = 0x10325476; + m_state[4] = 0xC3D2E1F0; + + m_count[0] = 0; + m_count[1] = 0; +} + +#ifdef _MINIMUM_BUILD_ +void Minimum_CSHA1::Transform(unsigned long state[5], unsigned char buffer[64]) +#else +void CSHA1::Transform(unsigned long state[5], unsigned char buffer[64]) +#endif +{ + unsigned long a = 0, b = 0, c = 0, d = 0, e = 0; + + memcpy(m_block, buffer, 64); + + // Copy state[] to working vars + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + // 4 rounds of 20 operations each. Loop unrolled. + _R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3); + _R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7); + _R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11); + _R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15); + _R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19); + _R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23); + _R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27); + _R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31); + _R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35); + _R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39); + _R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43); + _R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47); + _R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51); + _R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55); + _R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59); + _R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63); + _R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67); + _R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71); + _R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75); + _R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79); + + // Add the working vars back into state[] + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + // Wipe variables + a = b = c = d = e = 0; +} + +// Use this function to hash in binary data and strings +#ifdef _MINIMUM_BUILD_ +void Minimum_CSHA1::Update(unsigned char *data, unsigned int len) +#else +void CSHA1::Update(unsigned char *data, unsigned int len) +#endif +{ + unsigned long i = 0, j; + + j = (m_count[0] >> 3) & 63; + + if((m_count[0] += len << 3) < (len << 3)) m_count[1]++; + + m_count[1] += (len >> 29); + + if((j + len) > 63) + { + memcpy(&m_buffer[j], data, (i = 64 - j)); + Transform(m_state, m_buffer); + + for (; i+63 < len; i += 64) + Transform(m_state, &data[i]); + + j = 0; + } + else i = 0; + + memcpy(&m_buffer[j], &data[i], len - i); +} + +#if !defined(_MINIMUM_BUILD_) +// Hash in file contents +bool CSHA1::HashFile(char *szFileName) +{ + unsigned long ulFileSize = 0, ulRest = 0, ulBlocks = 0; + unsigned long i = 0; + unsigned char uData[MAX_FILE_READ_BUFFER]; + FILE *fIn = NULL; + + if(szFileName == NULL) return(false); + + if((fIn = fopen(szFileName, "rb")) == NULL) return(false); + + fseek(fIn, 0, SEEK_END); + ulFileSize = ftell(fIn); + fseek(fIn, 0, SEEK_SET); + + ulRest = ulFileSize % MAX_FILE_READ_BUFFER; + ulBlocks = ulFileSize / MAX_FILE_READ_BUFFER; + + for(i = 0; i < ulBlocks; i++) + { + fread(uData, 1, MAX_FILE_READ_BUFFER, fIn); + Update(uData, MAX_FILE_READ_BUFFER); + } + + if(ulRest != 0) + { + fread(uData, 1, ulRest, fIn); + Update(uData, ulRest); + } + + fclose(fIn); + fIn = NULL; + + return(true); +} +#endif + +#ifdef _MINIMUM_BUILD_ +void Minimum_CSHA1::Final() +#else +void CSHA1::Final() +#endif +{ + unsigned long i = 0; + unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (i = 0; i < 8; i++) + finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)] + >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent + + Update((unsigned char *)"\200", 1); + + while ((m_count[0] & 504) != 448) + Update((unsigned char *)"\0", 1); + + Update(finalcount, 8); // Cause a SHA1Transform() + + for (i = 0; i < k_cubHash; i++) + { + m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255); + } + + // Wipe variables for security reasons + i = 0; + memset(m_buffer, 0, sizeof(m_buffer) ); + memset(m_state, 0, sizeof(m_state) ); + memset(m_count, 0, sizeof(m_count) ); + memset(finalcount, 0, sizeof( finalcount) ); + + Transform(m_state, m_buffer); +} + +#if !defined(_MINIMUM_BUILD_) +// Get the final hash as a pre-formatted string +void CSHA1::ReportHash(char *szReport, unsigned char uReportType) +{ + unsigned char i = 0; + char szTemp[12]; + + if(szReport == NULL) return; + + if(uReportType == REPORT_HEX) + { + sprintf(szTemp, "%02X", m_digest[0]); + strcat(szReport, szTemp); + + for(i = 1; i < k_cubHash; i++) + { + sprintf(szTemp, " %02X", m_digest[i]); + strcat(szReport, szTemp); + } + } + else if(uReportType == REPORT_DIGIT) + { + sprintf(szTemp, "%u", m_digest[0]); + strcat(szReport, szTemp); + + for(i = 1; i < k_cubHash; i++) + { + sprintf(szTemp, " %u", m_digest[i]); + strcat(szReport, szTemp); + } + } + else strcpy(szReport, "Error: Unknown report type!"); +} +#endif // _MINIMUM_BUILD_ + +// Get the raw message digest +#ifdef _MINIMUM_BUILD_ +void Minimum_CSHA1::GetHash(unsigned char *uDest) +#else +void CSHA1::GetHash(unsigned char *uDest) +#endif +{ + memcpy(uDest, m_digest, k_cubHash); +} + +#ifndef _MINIMUM_BUILD_ +// utility hash comparison function +bool HashLessFunc( SHADigest_t const &lhs, SHADigest_t const &rhs ) +{ + int iRes = memcmp( &lhs, &rhs, sizeof( SHADigest_t ) ); + return ( iRes < 0 ); +} +#endif diff --git a/tier1/commandbuffer.cpp b/tier1/commandbuffer.cpp new file mode 100644 index 0000000..2897d03 --- /dev/null +++ b/tier1/commandbuffer.cpp @@ -0,0 +1,636 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#include "tier1/CommandBuffer.h" +#include "tier1/utlbuffer.h" +#include "tier1/strtools.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define MAX_ALIAS_NAME 32 +#define MAX_COMMAND_LENGTH 1024 + +struct cmdalias_t +{ + cmdalias_t *next; + char name[ MAX_ALIAS_NAME ]; + char *value; +}; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CCommandBuffer::CCommandBuffer( ) : m_Commands( 32, 32 ) +{ + m_hNextCommand = m_Commands.InvalidIndex(); + m_nWaitDelayTicks = 1; + m_nCurrentTick = 0; + m_nLastTickToProcess = -1; + m_nArgSBufferSize = 0; + m_bIsProcessingCommands = false; + m_nMaxArgSBufferLength = ARGS_BUFFER_LENGTH; +} + +CCommandBuffer::~CCommandBuffer() +{ +} + + +//----------------------------------------------------------------------------- +// Indicates how long to delay when encoutering a 'wait' command +//----------------------------------------------------------------------------- +void CCommandBuffer::SetWaitDelayTime( int nTickDelay ) +{ + Assert( nTickDelay >= 0 ); + m_nWaitDelayTicks = nTickDelay; +} + + +//----------------------------------------------------------------------------- +// Specifies a max limit of the args buffer. For unittesting. Size == 0 means use default +//----------------------------------------------------------------------------- +void CCommandBuffer::LimitArgumentBufferSize( int nSize ) +{ + if ( nSize > ARGS_BUFFER_LENGTH ) + { + nSize = ARGS_BUFFER_LENGTH; + } + + m_nMaxArgSBufferLength = ( nSize == 0 ) ? ARGS_BUFFER_LENGTH : nSize; +} + + +//----------------------------------------------------------------------------- +// Parses argv0 out of the buffer +//----------------------------------------------------------------------------- +bool CCommandBuffer::ParseArgV0( CUtlBuffer &buf, char *pArgV0, int nMaxLen, const char **pArgS ) +{ + pArgV0[0] = 0; + *pArgS = NULL; + + if ( !buf.IsValid() ) + return false; + + int nSize = buf.ParseToken( CCommand::DefaultBreakSet(), pArgV0, nMaxLen ); + if ( ( nSize <= 0 ) || ( nMaxLen == nSize ) ) + return false; + + int nArgSLen = buf.TellMaxPut() - buf.TellGet(); + *pArgS = (nArgSLen > 0) ? (const char*)buf.PeekGet() : NULL; + return true; +} + + +//----------------------------------------------------------------------------- +// Insert a command into the command queue +//----------------------------------------------------------------------------- +void CCommandBuffer::InsertCommandAtAppropriateTime( int hCommand ) +{ + int i; + Command_t &command = m_Commands[hCommand]; + for ( i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) + { + if ( m_Commands[i].m_nTick > command.m_nTick ) + break; + } + m_Commands.LinkBefore( i, hCommand ); +} + + +//----------------------------------------------------------------------------- +// Insert a command into the command queue at the appropriate time +//----------------------------------------------------------------------------- +void CCommandBuffer::InsertImmediateCommand( int hCommand ) +{ + m_Commands.LinkBefore( m_hNextCommand, hCommand ); +} + + +//----------------------------------------------------------------------------- +// Insert a command into the command queue +//----------------------------------------------------------------------------- +bool CCommandBuffer::InsertCommand( const char *pArgS, int nCommandSize, int nTick ) +{ + if ( nCommandSize >= CCommand::MaxCommandLength() ) + { + Warning( "WARNING: Command too long... ignoring!\n%s\n", pArgS ); + return false; + } + + // Add one for null termination + if ( m_nArgSBufferSize + nCommandSize + 1 > m_nMaxArgSBufferLength ) + { + Compact(); + if ( m_nArgSBufferSize + nCommandSize + 1 > m_nMaxArgSBufferLength ) + return false; + } + + memcpy( &m_pArgSBuffer[m_nArgSBufferSize], pArgS, nCommandSize ); + m_pArgSBuffer[m_nArgSBufferSize + nCommandSize] = 0; + ++nCommandSize; + + int hCommand = m_Commands.Alloc(); + Command_t &command = m_Commands[hCommand]; + command.m_nTick = nTick; + command.m_nFirstArgS = m_nArgSBufferSize; + command.m_nBufferSize = nCommandSize; + + m_nArgSBufferSize += nCommandSize; + + if ( !m_bIsProcessingCommands || ( nTick > m_nCurrentTick ) ) + { + InsertCommandAtAppropriateTime( hCommand ); + } + else + { + InsertImmediateCommand( hCommand ); + } + return true; +} + + +//----------------------------------------------------------------------------- +// Returns the length of the next command +//----------------------------------------------------------------------------- +void CCommandBuffer::GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset ) +{ + int nCommandLength = 0; + int nNextCommandOffset; + bool bIsQuoted = false; + bool bIsCommented = false; + for ( nNextCommandOffset=0; nNextCommandOffset < nMaxLen; ++nNextCommandOffset, nCommandLength += bIsCommented ? 0 : 1 ) + { + char c = pText[nNextCommandOffset]; + if ( !bIsCommented ) + { + if ( c == '"' ) + { + bIsQuoted = !bIsQuoted; + continue; + } + + // don't break if inside a C++ style comment + if ( !bIsQuoted && c == '/' ) + { + bIsCommented = ( nNextCommandOffset < nMaxLen-1 ) && pText[nNextCommandOffset+1] == '/'; + if ( bIsCommented ) + { + ++nNextCommandOffset; + continue; + } + } + + // don't break if inside a quoted string + if ( !bIsQuoted && c == ';' ) + break; + } + + // FIXME: This is legacy behavior; should we not break if a \n is inside a quoted string? + if ( c == '\n' ) + break; + } + + *pCommandLength = nCommandLength; + *pNextCommandOffset = nNextCommandOffset; +} + + +//----------------------------------------------------------------------------- +// Add text to command buffer, return false if it couldn't owing to overflow +//----------------------------------------------------------------------------- +bool CCommandBuffer::AddText( const char *pText, int nTickDelay ) +{ + Assert( nTickDelay >= 0 ); + + int nLen = Q_strlen( pText ); + int nTick = m_nCurrentTick + nTickDelay; + + // Parse the text into distinct commands + const char *pCurrentCommand = pText; + int nOffsetToNextCommand; + for( ; nLen > 0; nLen -= nOffsetToNextCommand+1, pCurrentCommand += nOffsetToNextCommand+1 ) + { + // find a \n or ; line break + int nCommandLength; + GetNextCommandLength( pCurrentCommand, nLen, &nCommandLength, &nOffsetToNextCommand ); + if ( nCommandLength <= 0 ) + continue; + + const char *pArgS; + char *pArgV0 = (char*)_alloca( nCommandLength+1 ); + CUtlBuffer bufParse( pCurrentCommand, nCommandLength, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY ); + ParseArgV0( bufParse, pArgV0, nCommandLength+1, &pArgS ); + if ( pArgV0[0] == 0 ) + continue; + + // Deal with the special 'wait' command + if ( !Q_stricmp( pArgV0, "wait" ) && IsWaitEnabled() ) + { + int nDelay = pArgS ? atoi( pArgS ) : m_nWaitDelayTicks; + nTick += nDelay; + continue; + } + + if ( !InsertCommand( pCurrentCommand, nCommandLength, nTick ) ) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Are we in the middle of processing commands? +//----------------------------------------------------------------------------- +bool CCommandBuffer::IsProcessingCommands() +{ + return m_bIsProcessingCommands; +} + + +//----------------------------------------------------------------------------- +// Delays all queued commands to execute at a later time +//----------------------------------------------------------------------------- +void CCommandBuffer::DelayAllQueuedCommands( int nDelay ) +{ + if ( nDelay <= 0 ) + return; + + for ( int i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) + { + m_Commands[i].m_nTick += nDelay; + } +} + + +//----------------------------------------------------------------------------- +// Call this to begin iterating over all commands up to flCurrentTime +//----------------------------------------------------------------------------- +void CCommandBuffer::BeginProcessingCommands( int nDeltaTicks ) +{ + if ( nDeltaTicks == 0 ) + return; + + Assert( !m_bIsProcessingCommands ); + m_bIsProcessingCommands = true; + m_nLastTickToProcess = m_nCurrentTick + nDeltaTicks - 1; + + // Necessary to insert commands while commands are being processed + m_hNextCommand = m_Commands.Head(); +} + + +//----------------------------------------------------------------------------- +// Returns the next command +//----------------------------------------------------------------------------- +bool CCommandBuffer::DequeueNextCommand( ) +{ + m_CurrentCommand.Reset(); + + Assert( m_bIsProcessingCommands ); + if ( m_Commands.Count() == 0 ) + return false; + + int nHead = m_Commands.Head(); + Command_t &command = m_Commands[ nHead ]; + if ( command.m_nTick > m_nLastTickToProcess ) + return false; + + m_nCurrentTick = command.m_nTick; + + // Copy the current command into a temp buffer + // NOTE: This is here to avoid the pointers returned by DequeueNextCommand + // to become invalid by calling AddText. Is there a way we can avoid the memcpy? + if ( command.m_nBufferSize > 0 ) + { + m_CurrentCommand.Tokenize( &m_pArgSBuffer[command.m_nFirstArgS] ); + } + + m_Commands.Remove( nHead ); + + // Necessary to insert commands while commands are being processed + m_hNextCommand = m_Commands.Head(); + +// Msg("Dequeue : "); +// for ( int i = 0; i < nArgc; ++i ) +// { +// Msg("%s ", m_pCurrentArgv[i] ); +// } +// Msg("\n"); + return true; +} + + +//----------------------------------------------------------------------------- +// Returns the next command +//----------------------------------------------------------------------------- +int CCommandBuffer::DequeueNextCommand( const char **& ppArgv ) +{ + DequeueNextCommand(); + ppArgv = ArgV(); + return ArgC(); +} + + +//----------------------------------------------------------------------------- +// Compacts the command buffer +//----------------------------------------------------------------------------- +void CCommandBuffer::Compact() +{ + // Compress argvbuffer + argv + // NOTE: I'm using this choice instead of calling malloc + free + // per command to allocate arguments because I expect to post a + // bunch of commands but not have many delayed commands; + // avoiding the allocation cost seems more important that the memcpy + // cost here since I expect to not have much to copy. + m_nArgSBufferSize = 0; + + char pTempBuffer[ ARGS_BUFFER_LENGTH ]; + for ( int i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) + { + Command_t &command = m_Commands[ i ]; + + memcpy( &pTempBuffer[m_nArgSBufferSize], &m_pArgSBuffer[command.m_nFirstArgS], command.m_nBufferSize ); + command.m_nFirstArgS = m_nArgSBufferSize; + m_nArgSBufferSize += command.m_nBufferSize; + } + + // NOTE: We could also store 2 buffers in the command buffer and switch + // between the two to avoid the 2nd memcpy; but again I'm guessing the memory + // tradeoff isn't worth it + memcpy( m_pArgSBuffer, pTempBuffer, m_nArgSBufferSize ); +} + + +//----------------------------------------------------------------------------- +// Call this to finish iterating over all commands +//----------------------------------------------------------------------------- +void CCommandBuffer::EndProcessingCommands() +{ + Assert( m_bIsProcessingCommands ); + m_bIsProcessingCommands = false; + m_nCurrentTick = m_nLastTickToProcess + 1; + m_hNextCommand = m_Commands.InvalidIndex(); + + // Extract commands that are before the end time + // NOTE: This is a bug for this to + int i = m_Commands.Head(); + if ( i == m_Commands.InvalidIndex() ) + { + m_nArgSBufferSize = 0; + return; + } + + while ( i != m_Commands.InvalidIndex() ) + { + if ( m_Commands[i].m_nTick >= m_nCurrentTick ) + break; + + AssertMsgOnce( false, "CCommandBuffer::EndProcessingCommands() called before all appropriate commands were dequeued.\n" ); + int nNext = i; + Msg( "Warning: Skipping command %s\n", &m_pArgSBuffer[ m_Commands[i].m_nFirstArgS ] ); + m_Commands.Remove( i ); + i = nNext; + } + + Compact(); +} + + +//----------------------------------------------------------------------------- +// Returns a handle to the next command to process +//----------------------------------------------------------------------------- +CommandHandle_t CCommandBuffer::GetNextCommandHandle() +{ + Assert( m_bIsProcessingCommands ); + return m_Commands.Head(); +} + + +#if 0 +/* +=============== +Cmd_Alias_f + +Creates a new command that executes a command string (possibly ; seperated) +=============== +*/ +void Cmd_Alias_f (void) +{ + cmdalias_t *a; + char cmd[MAX_COMMAND_LENGTH]; + int i, c; + char *s; + + if (Cmd_Argc() == 1) + { + Con_Printf ("Current alias commands:\n"); + for (a = cmd_alias ; a ; a=a->next) + Con_Printf ("%s : %s\n", a->name, a->value); + return; + } + + s = Cmd_Argv(1); + if (strlen(s) >= MAX_ALIAS_NAME) + { + Con_Printf ("Alias name is too long\n"); + return; + } + +// copy the rest of the command line + cmd[0] = 0; // start out with a null string + c = Cmd_Argc(); + for (i=2 ; i< c ; i++) + { + Q_strncat(cmd, Cmd_Argv(i), sizeof( cmd ), COPY_ALL_CHARACTERS); + if (i != c) + { + Q_strncat (cmd, " ", sizeof( cmd ), COPY_ALL_CHARACTERS ); + } + } + Q_strncat (cmd, "\n", sizeof( cmd ), COPY_ALL_CHARACTERS); + + // if the alias already exists, reuse it + for (a = cmd_alias ; a ; a=a->next) + { + if (!strcmp(s, a->name)) + { + if ( !strcmp( a->value, cmd ) ) // Re-alias the same thing + return; + + delete[] a->value; + break; + } + } + + if (!a) + { + a = (cmdalias_t *)new cmdalias_t; + a->next = cmd_alias; + cmd_alias = a; + } + Q_strncpy (a->name, s, sizeof( a->name ) ); + + a->value = COM_StringCopy(cmd); +} + + + +/* +============================================================================= + + COMMAND EXECUTION + +============================================================================= +*/ + +#define MAX_ARGS 80 + +static int cmd_argc; +static char *cmd_argv[MAX_ARGS]; +static char *cmd_null_string = ""; +static const char *cmd_args = NULL; + +cmd_source_t cmd_source; + +//----------------------------------------------------------------------------- +// Purpose: +// Output : void Cmd_Init +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void Cmd_Shutdown( void ) +{ + // TODO, cleanup + while ( cmd_alias ) + { + cmdalias_t *next = cmd_alias->next; + delete cmd_alias->value; // created by StringCopy() + delete cmd_alias; + cmd_alias = next; + } +} + + + +/* +============ +Cmd_ExecuteString + +A complete command line has been parsed, so try to execute it +FIXME: lookupnoadd the token to speed search? +============ +*/ +const ConCommandBase *Cmd_ExecuteString (const char *text, cmd_source_t src) +{ + cmdalias_t *a; + + cmd_source = src; + Cmd_TokenizeString (text); + +// execute the command line + if (!Cmd_Argc()) + return NULL; // no tokens + +// check alias + for (a=cmd_alias ; a ; a=a->next) + { + if (!Q_strcasecmp (cmd_argv[0], a->name)) + { + Cbuf_InsertText (a->value); + return NULL; + } + } + +// check ConCommands + ConCommandBase const *pCommand = ConCommandBase::FindCommand( cmd_argv[ 0 ] ); + if ( pCommand && pCommand->IsCommand() ) + { + bool isServerCommand = ( pCommand->IsBitSet( FCVAR_GAMEDLL ) && + // Typed at console + cmd_source == src_command && + // Not HLDS + !sv.IsDedicated() ); + + // Hook to allow game .dll to figure out who type the message on a listen server + if ( serverGameClients ) + { + // We're actually the server, so set it up locally + if ( sv.IsActive() ) + { + g_pServerPluginHandler->SetCommandClient( -1 ); + +#ifndef SWDS + // Special processing for listen server player + if ( isServerCommand ) + { + g_pServerPluginHandler->SetCommandClient( cl.m_nPlayerSlot ); + } +#endif + } + // We're not the server, but we've been a listen server (game .dll loaded) + // forward this command tot he server instead of running it locally if we're still + // connected + // Otherwise, things like "say" won't work unless you quit and restart + else if ( isServerCommand ) + { + if ( cl.IsConnected() ) + { + Cmd_ForwardToServer(); + return NULL; + } + else + { + // It's a server command, but we're not connected to a server. Don't try to execute it. + return NULL; + } + } + } + + // Allow cheat commands in singleplayer, debug, or multiplayer with sv_cheats on +#ifndef _DEBUG + if ( pCommand->IsBitSet( FCVAR_CHEAT ) ) + { + if ( !Host_IsSinglePlayerGame() && sv_cheats.GetInt() == 0 ) + { + Msg( "Can't use cheat command %s in multiplayer, unless the server has sv_cheats set to 1.\n", pCommand->GetName() ); + return NULL; + } + } +#endif + + (( ConCommand * )pCommand )->Dispatch(); + return pCommand; + } + + // check cvars + if ( cv->IsCommand() ) + { + return pCommand; + } + + // forward the command line to the server, so the entity DLL can parse it + if ( cmd_source == src_command ) + { + if ( cl.IsConnected() ) + { + Cmd_ForwardToServer(); + return NULL; + } + } + + Msg("Unknown command \"%s\"\n", Cmd_Argv(0)); + + return NULL; +} +#endif diff --git a/tier1/convar.cpp b/tier1/convar.cpp new file mode 100644 index 0000000..772586f --- /dev/null +++ b/tier1/convar.cpp @@ -0,0 +1,1283 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#include +#include +#include +#include "basetypes.h" +#include "tier1/convar.h" +#include "tier1/strtools.h" +#include "tier1/characterset.h" +#include "tier1/utlbuffer.h" +#include "tier1/tier1.h" +#include "tier1/convar_serverbounded.h" +#include "icvar.h" +#include "tier0/dbg.h" +#include "Color.h" +#if defined( _X360 ) +#include "xbox/xbox_console.h" +#endif +#include "tier0/memdbgon.h" + +#ifndef NDEBUG +// Comment this out when we release. +#define ALLOW_DEVELOPMENT_CVARS +#endif + + + +//----------------------------------------------------------------------------- +// Statically constructed list of ConCommandBases, +// used for registering them with the ICVar interface +//----------------------------------------------------------------------------- +ConCommandBase *ConCommandBase::s_pConCommandBases = NULL; +IConCommandBaseAccessor *ConCommandBase::s_pAccessor = NULL; +static int s_nCVarFlag = 0; +static int s_nDLLIdentifier = -1; // A unique identifier indicating which DLL this convar came from +static bool s_bRegistered = false; + +class CDefaultAccessor : public IConCommandBaseAccessor +{ +public: + virtual bool RegisterConCommandBase( ConCommandBase *pVar ) + { + // Link to engine's list instead + g_pCVar->RegisterConCommand( pVar ); + return true; + } +}; + +static CDefaultAccessor s_DefaultAccessor; + +//----------------------------------------------------------------------------- +// Called by the framework to register ConCommandBases with the ICVar +//----------------------------------------------------------------------------- +void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor ) +{ + if ( !g_pCVar || s_bRegistered ) + return; + + Assert( s_nDLLIdentifier < 0 ); + s_bRegistered = true; + s_nCVarFlag = nCVarFlag; + s_nDLLIdentifier = g_pCVar->AllocateDLLIdentifier(); + + ConCommandBase *pCur, *pNext; + + ConCommandBase::s_pAccessor = pAccessor ? pAccessor : &s_DefaultAccessor; + pCur = ConCommandBase::s_pConCommandBases; + while ( pCur ) + { + pNext = pCur->m_pNext; + pCur->AddFlags( s_nCVarFlag ); + pCur->Init(); + pCur = pNext; + } + + g_pCVar->ProcessQueuedMaterialThreadConVarSets(); + ConCommandBase::s_pConCommandBases = NULL; +} + +void ConVar_Unregister( ) +{ + if ( !g_pCVar || !s_bRegistered ) + return; + + Assert( s_nDLLIdentifier >= 0 ); + g_pCVar->UnregisterConCommands( s_nDLLIdentifier ); + s_nDLLIdentifier = -1; + s_bRegistered = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Default constructor +//----------------------------------------------------------------------------- +ConCommandBase::ConCommandBase( void ) +{ + m_bRegistered = false; + m_pszName = NULL; + m_pszHelpString = NULL; + + m_nFlags = 0; + m_pNext = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +// Input : *pName - name of variable/command +// *pHelpString - help text +// flags - flags +//----------------------------------------------------------------------------- +ConCommandBase::ConCommandBase( const char *pName, const char *pHelpString /*=0*/, int flags /*= 0*/ ) +{ + CreateBase( pName, pHelpString, flags ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ConCommandBase::~ConCommandBase( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsCommand( void ) const +{ +// Assert( 0 ); This can't assert. . causes a recursive assert in Sys_Printf, etc. + return true; +} + + +//----------------------------------------------------------------------------- +// Returns the DLL identifier +//----------------------------------------------------------------------------- +CVarDLLIdentifier_t ConCommandBase::GetDLLIdentifier() const +{ + return s_nDLLIdentifier; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pName - +// callback - +// *pHelpString - +// flags - +//----------------------------------------------------------------------------- +void ConCommandBase::CreateBase( const char *pName, const char *pHelpString /*= 0*/, int flags /*= 0*/ ) +{ + m_bRegistered = false; + + // Name should be static data + Assert( pName ); + m_pszName = pName; + m_pszHelpString = pHelpString ? pHelpString : ""; + + m_nFlags = flags; + +#ifdef ALLOW_DEVELOPMENT_CVARS + m_nFlags &= ~FCVAR_DEVELOPMENTONLY; +#endif + + if ( !( m_nFlags & FCVAR_UNREGISTERED ) ) + { + m_pNext = s_pConCommandBases; + s_pConCommandBases = this; + } + else + { + // It's unregistered + m_pNext = NULL; + } + + // If s_pAccessor is already set (this ConVar is not a global variable), + // register it. + if ( s_pAccessor ) + { + Init(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Used internally by OneTimeInit to initialize. +//----------------------------------------------------------------------------- +void ConCommandBase::Init() +{ + if ( s_pAccessor ) + { + s_pAccessor->RegisterConCommandBase( this ); + } +} + +void ConCommandBase::Shutdown() +{ + if ( g_pCVar ) + { + g_pCVar->UnregisterConCommand( this ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Return name of the command/var +// Output : const char +//----------------------------------------------------------------------------- +const char *ConCommandBase::GetName( void ) const +{ + return m_pszName; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flag - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsFlagSet( int flag ) const +{ + return ( flag & m_nFlags ) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +//----------------------------------------------------------------------------- +void ConCommandBase::AddFlags( int flags ) +{ + m_nFlags |= flags; + +#ifdef ALLOW_DEVELOPMENT_CVARS + m_nFlags &= ~FCVAR_DEVELOPMENTONLY; +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const ConCommandBase +//----------------------------------------------------------------------------- +const ConCommandBase *ConCommandBase::GetNext( void ) const +{ + return m_pNext; +} + +ConCommandBase *ConCommandBase::GetNext( void ) +{ + return m_pNext; +} + + +//----------------------------------------------------------------------------- +// Purpose: Copies string using local new/delete operators +// Input : *from - +// Output : char +//----------------------------------------------------------------------------- +char *ConCommandBase::CopyString( const char *from ) +{ + int len; + char *to; + + len = V_strlen( from ); + if ( len <= 0 ) + { + to = new char[1]; + to[0] = 0; + } + else + { + to = new char[len+1]; + Q_strncpy( to, from, len+1 ); + } + return to; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char *ConCommandBase::GetHelpText( void ) const +{ + return m_pszHelpString; +} + +//----------------------------------------------------------------------------- +// Purpose: Has this cvar been registered +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsRegistered( void ) const +{ + return m_bRegistered; +} + + +//----------------------------------------------------------------------------- +// +// Con Commands start here +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Global methods +//----------------------------------------------------------------------------- +static characterset_t s_BreakSet; +static bool s_bBuiltBreakSet = false; + + +//----------------------------------------------------------------------------- +// Tokenizer class +//----------------------------------------------------------------------------- +CCommand::CCommand() +{ + if ( !s_bBuiltBreakSet ) + { + s_bBuiltBreakSet = true; + CharacterSetBuild( &s_BreakSet, "{}()':" ); + } + + Reset(); +} + +CCommand::CCommand( int nArgC, const char **ppArgV ) +{ + Assert( nArgC > 0 ); + + if ( !s_bBuiltBreakSet ) + { + s_bBuiltBreakSet = true; + CharacterSetBuild( &s_BreakSet, "{}()':" ); + } + + Reset(); + + char *pBuf = m_pArgvBuffer; + char *pSBuf = m_pArgSBuffer; + m_nArgc = nArgC; + for ( int i = 0; i < nArgC; ++i ) + { + m_ppArgv[i] = pBuf; + int nLen = Q_strlen( ppArgV[i] ); + memcpy( pBuf, ppArgV[i], nLen+1 ); + if ( i == 0 ) + { + m_nArgv0Size = nLen; + } + pBuf += nLen+1; + + bool bContainsSpace = strchr( ppArgV[i], ' ' ) != NULL; + if ( bContainsSpace ) + { + *pSBuf++ = '\"'; + } + memcpy( pSBuf, ppArgV[i], nLen ); + pSBuf += nLen; + if ( bContainsSpace ) + { + *pSBuf++ = '\"'; + } + + if ( i != nArgC - 1 ) + { + *pSBuf++ = ' '; + } + } +} + +void CCommand::Reset() +{ + m_nArgc = 0; + m_nArgv0Size = 0; + m_pArgSBuffer[0] = 0; +} + +characterset_t* CCommand::DefaultBreakSet() +{ + return &s_BreakSet; +} + +bool CCommand::Tokenize( const char *pCommand, characterset_t *pBreakSet ) +{ + Reset(); + if ( !pCommand ) + return false; + + // Use default break set + if ( !pBreakSet ) + { + pBreakSet = &s_BreakSet; + } + + // Copy the current command into a temp buffer + // NOTE: This is here to avoid the pointers returned by DequeueNextCommand + // to become invalid by calling AddText. Is there a way we can avoid the memcpy? + int nLen = Q_strlen( pCommand ); + if ( nLen >= COMMAND_MAX_LENGTH - 1 ) + { + Warning( "CCommand::Tokenize: Encountered command which overflows the tokenizer buffer.. Skipping!\n" ); + return false; + } + + memcpy( m_pArgSBuffer, pCommand, nLen + 1 ); + + // Parse the current command into the current command buffer + CUtlBuffer bufParse( m_pArgSBuffer, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY ); + int nArgvBufferSize = 0; + while ( bufParse.IsValid() && ( m_nArgc < COMMAND_MAX_ARGC ) ) + { + char *pArgvBuf = &m_pArgvBuffer[nArgvBufferSize]; + int nMaxLen = COMMAND_MAX_LENGTH - nArgvBufferSize; + int nStartGet = bufParse.TellGet(); + int nSize = bufParse.ParseToken( pBreakSet, pArgvBuf, nMaxLen ); + if ( nSize < 0 ) + break; + + // Check for overflow condition + if ( nMaxLen == nSize ) + { + Reset(); + return false; + } + + if ( m_nArgc == 1 ) + { + // Deal with the case where the arguments were quoted + m_nArgv0Size = bufParse.TellGet(); + bool bFoundEndQuote = m_pArgSBuffer[m_nArgv0Size-1] == '\"'; + if ( bFoundEndQuote ) + { + --m_nArgv0Size; + } + m_nArgv0Size -= nSize; + Assert( m_nArgv0Size != 0 ); + + // The StartGet check is to handle this case: "foo"bar + // which will parse into 2 different args. ArgS should point to bar. + bool bFoundStartQuote = ( m_nArgv0Size > nStartGet ) && ( m_pArgSBuffer[m_nArgv0Size-1] == '\"' ); + Assert( bFoundEndQuote == bFoundStartQuote ); + if ( bFoundStartQuote ) + { + --m_nArgv0Size; + } + } + + m_ppArgv[ m_nArgc++ ] = pArgvBuf; + if( m_nArgc >= COMMAND_MAX_ARGC ) + { + Warning( "CCommand::Tokenize: Encountered command which overflows the argument buffer.. Clamped!\n" ); + } + + nArgvBufferSize += nSize + 1; + Assert( nArgvBufferSize <= COMMAND_MAX_LENGTH ); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Helper function to parse arguments to commands. +//----------------------------------------------------------------------------- +const char* CCommand::FindArg( const char *pName ) const +{ + int nArgC = ArgC(); + for ( int i = 1; i < nArgC; i++ ) + { + if ( !Q_stricmp( Arg(i), pName ) ) + return (i+1) < nArgC ? Arg( i+1 ) : ""; + } + return 0; +} + +int CCommand::FindArgInt( const char *pName, int nDefaultVal ) const +{ + const char *pVal = FindArg( pName ); + if ( pVal ) + return atoi( pVal ); + else + return nDefaultVal; +} + + +//----------------------------------------------------------------------------- +// Default console command autocompletion function +//----------------------------------------------------------------------------- +int DefaultCompletionFunc( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) +{ + return 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructs a console command +//----------------------------------------------------------------------------- +//ConCommand::ConCommand() +//{ +// m_bIsNewConCommand = true; +//} + +ConCommand::ConCommand( const char *pName, FnCommandCallbackVoid_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ ) +{ + // Set the callback + m_fnCommandCallbackV1 = callback; + m_bUsingNewCommandCallback = false; + m_bUsingCommandCallbackInterface = false; + m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc; + m_bHasCompletionCallback = completionFunc != 0 ? true : false; + + // Setup the rest + BaseClass::CreateBase( pName, pHelpString, flags ); +} + +ConCommand::ConCommand( const char *pName, FnCommandCallback_t callback, const char *pHelpString /*= 0*/, int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/ ) +{ + // Set the callback + m_fnCommandCallback = callback; + m_bUsingNewCommandCallback = true; + m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc; + m_bHasCompletionCallback = completionFunc != 0 ? true : false; + m_bUsingCommandCallbackInterface = false; + + // Setup the rest + BaseClass::CreateBase( pName, pHelpString, flags ); +} + +ConCommand::ConCommand( const char *pName, ICommandCallback *pCallback, const char *pHelpString /*= 0*/, int flags /*= 0*/, ICommandCompletionCallback *pCompletionCallback /*= 0*/ ) +{ + // Set the callback + m_pCommandCallback = pCallback; + m_bUsingNewCommandCallback = false; + m_pCommandCompletionCallback = pCompletionCallback; + m_bHasCompletionCallback = ( pCompletionCallback != 0 ); + m_bUsingCommandCallbackInterface = true; + + // Setup the rest + BaseClass::CreateBase( pName, pHelpString, flags ); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +ConCommand::~ConCommand( void ) +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is a command +//----------------------------------------------------------------------------- +bool ConCommand::IsCommand( void ) const +{ + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Invoke the function if there is one +//----------------------------------------------------------------------------- +void ConCommand::Dispatch( const CCommand &command ) +{ + if ( m_bUsingNewCommandCallback ) + { + if ( m_fnCommandCallback ) + { + ( *m_fnCommandCallback )( command ); + return; + } + } + else if ( m_bUsingCommandCallbackInterface ) + { + if ( m_pCommandCallback ) + { + m_pCommandCallback->CommandCallback( command ); + return; + } + } + else + { + if ( m_fnCommandCallbackV1 ) + { + ( *m_fnCommandCallbackV1 )(); + return; + } + } + + // Command without callback!!! + AssertMsg( 0, "Encountered ConCommand '%s' without a callback!\n", GetName() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Calls the autocompletion method to get autocompletion suggestions +//----------------------------------------------------------------------------- +int ConCommand::AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands ) +{ + if ( m_bUsingCommandCallbackInterface ) + { + if ( !m_pCommandCompletionCallback ) + return 0; + return m_pCommandCompletionCallback->CommandCompletionCallback( partial, commands ); + } + + Assert( m_fnCompletionCallback ); + if ( !m_fnCompletionCallback ) + return 0; + + char rgpchCommands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ]; + int iret = ( m_fnCompletionCallback )( partial, rgpchCommands ); + for ( int i = 0 ; i < iret; ++i ) + { + CUtlString str = rgpchCommands[ i ]; + commands.AddToTail( str ); + } + return iret; +} + + +//----------------------------------------------------------------------------- +// Returns true if the console command can autocomplete +//----------------------------------------------------------------------------- +bool ConCommand::CanAutoComplete( void ) +{ + return m_bHasCompletionCallback; +} + + + +//----------------------------------------------------------------------------- +// +// Console Variables +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Various constructors +//----------------------------------------------------------------------------- +ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags /* = 0 */ ) +{ + Create( pName, pDefaultValue, flags ); +} + +ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString ) +{ + Create( pName, pDefaultValue, flags, pHelpString ); +} + +ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) +{ + Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax ); +} + +ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, FnChangeCallback_t callback ) +{ + Create( pName, pDefaultValue, flags, pHelpString, false, 0.0, false, 0.0, callback ); +} + +ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags, const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t callback ) +{ + Create( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax, callback ); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +ConVar::~ConVar( void ) +{ + if ( m_pszString ) + { + delete[] m_pszString; + m_pszString = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Install a change callback (there shouldn't already be one....) +//----------------------------------------------------------------------------- +void ConVar::InstallChangeCallback( FnChangeCallback_t callback ) +{ + Assert( !m_pParent->m_fnChangeCallback || !callback ); + m_pParent->m_fnChangeCallback = callback; + + if ( m_pParent->m_fnChangeCallback ) + { + // Call it immediately to set the initial value... + m_pParent->m_fnChangeCallback( this, m_pszString, m_fValue ); + } +} + +bool ConVar::IsFlagSet( int flag ) const +{ + return ( flag & m_pParent->m_nFlags ) ? true : false; +} + +const char *ConVar::GetHelpText( void ) const +{ + return m_pParent->m_pszHelpString; +} + +void ConVar::AddFlags( int flags ) +{ + m_pParent->m_nFlags |= flags; + +#ifdef ALLOW_DEVELOPMENT_CVARS + m_pParent->m_nFlags &= ~FCVAR_DEVELOPMENTONLY; +#endif +} + +bool ConVar::IsRegistered( void ) const +{ + return m_pParent->m_bRegistered; +} + +const char *ConVar::GetName( void ) const +{ + return m_pParent->m_pszName; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConVar::IsCommand( void ) const +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +//----------------------------------------------------------------------------- +void ConVar::Init() +{ + BaseClass::Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *value - +//----------------------------------------------------------------------------- +void ConVar::InternalSetValue( const char *value ) +{ + if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) ) + { + if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() ) + { + g_pCVar->QueueMaterialThreadSetValue( this, value ); + return; + } + } + + float fNewValue; + char tempVal[ 32 ]; + char *val; + + Assert(m_pParent == this); // Only valid for root convars. + + float flOldValue = m_fValue; + + val = (char *)value; + if ( !value ) + fNewValue = 0.0f; + else + fNewValue = ( float )atof( value ); + + if ( ClampValue( fNewValue ) ) + { + Q_snprintf( tempVal,sizeof(tempVal), "%f", fNewValue ); + val = tempVal; + } + + // Redetermine value + m_fValue = fNewValue; + m_nValue = ( int )( fNewValue ); + + if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) ) + { + ChangeStringValue( val, flOldValue ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *tempVal - +//----------------------------------------------------------------------------- +void ConVar::ChangeStringValue( const char *tempVal, float flOldValue ) +{ + Assert( !( m_nFlags & FCVAR_NEVER_AS_STRING ) ); + + char* pszOldValue = (char*)stackalloc( m_StringLength ); + memcpy( pszOldValue, m_pszString, m_StringLength ); + + if ( tempVal ) + { + int len = Q_strlen(tempVal) + 1; + + if ( len > m_StringLength) + { + if (m_pszString) + { + delete[] m_pszString; + } + + m_pszString = new char[len]; + m_StringLength = len; + } + + memcpy( m_pszString, tempVal, len ); + } + else + { + *m_pszString = 0; + } + + // If nothing has changed, don't do the callbacks. + if (V_strcmp(pszOldValue, m_pszString) != 0) + { + // Invoke any necessary callback function + if ( m_fnChangeCallback ) + { + m_fnChangeCallback( this, pszOldValue, flOldValue ); + } + + g_pCVar->CallGlobalChangeCallbacks( this, pszOldValue, flOldValue ); + } + + stackfree( pszOldValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Check whether to clamp and then perform clamp +// Input : value - +// Output : Returns true if value changed +//----------------------------------------------------------------------------- +bool ConVar::ClampValue( float& value ) +{ + if ( m_bHasMin && ( value < m_fMinVal ) ) + { + value = m_fMinVal; + return true; + } + + if ( m_bHasMax && ( value > m_fMaxVal ) ) + { + value = m_fMaxVal; + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *value - +//----------------------------------------------------------------------------- +void ConVar::InternalSetFloatValue( float fNewValue ) +{ + if ( fNewValue == m_fValue ) + return; + + if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) ) + { + if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() ) + { + g_pCVar->QueueMaterialThreadSetValue( this, fNewValue ); + return; + } + } + + Assert( m_pParent == this ); // Only valid for root convars. + + // Check bounds + ClampValue( fNewValue ); + + // Redetermine value + float flOldValue = m_fValue; + m_fValue = fNewValue; + m_nValue = ( int )m_fValue; + + if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) ) + { + char tempVal[ 32 ]; + Q_snprintf( tempVal, sizeof( tempVal), "%f", m_fValue ); + ChangeStringValue( tempVal, flOldValue ); + } + else + { + Assert( !m_fnChangeCallback ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *value - +//----------------------------------------------------------------------------- +void ConVar::InternalSetIntValue( int nValue ) +{ + if ( nValue == m_nValue ) + return; + + if ( IsFlagSet( FCVAR_MATERIAL_THREAD_MASK ) ) + { + if ( g_pCVar && !g_pCVar->IsMaterialThreadSetAllowed() ) + { + g_pCVar->QueueMaterialThreadSetValue( this, nValue ); + return; + } + } + + Assert( m_pParent == this ); // Only valid for root convars. + + float fValue = (float)nValue; + if ( ClampValue( fValue ) ) + { + nValue = ( int )( fValue ); + } + + // Redetermine value + float flOldValue = m_fValue; + m_fValue = fValue; + m_nValue = nValue; + + if ( !( m_nFlags & FCVAR_NEVER_AS_STRING ) ) + { + char tempVal[ 32 ]; + Q_snprintf( tempVal, sizeof( tempVal ), "%d", m_nValue ); + ChangeStringValue( tempVal, flOldValue ); + } + else + { + Assert( !m_fnChangeCallback ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Private creation +//----------------------------------------------------------------------------- +void ConVar::Create( const char *pName, const char *pDefaultValue, int flags /*= 0*/, + const char *pHelpString /*= NULL*/, bool bMin /*= false*/, float fMin /*= 0.0*/, + bool bMax /*= false*/, float fMax /*= false*/, FnChangeCallback_t callback /*= NULL*/ ) +{ + m_pParent = this; + + // Name should be static data + SetDefault( pDefaultValue ); + + m_StringLength = V_strlen( m_pszDefaultValue ) + 1; + m_pszString = new char[m_StringLength]; + memcpy( m_pszString, m_pszDefaultValue, m_StringLength ); + + m_bHasMin = bMin; + m_fMinVal = fMin; + m_bHasMax = bMax; + m_fMaxVal = fMax; + + m_fnChangeCallback = callback; + + m_fValue = ( float )atof( m_pszString ); + m_nValue = atoi( m_pszString ); // dont convert from float to int and lose bits + + // Bounds Check, should never happen, if it does, no big deal + if ( m_bHasMin && ( m_fValue < m_fMinVal ) ) + { + Assert( 0 ); + } + + if ( m_bHasMax && ( m_fValue > m_fMaxVal ) ) + { + Assert( 0 ); + } + + BaseClass::CreateBase( pName, pHelpString, flags ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *value - +//----------------------------------------------------------------------------- +void ConVar::SetValue(const char *value) +{ + ConVar *var = ( ConVar * )m_pParent; + var->InternalSetValue( value ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : value - +//----------------------------------------------------------------------------- +void ConVar::SetValue( float value ) +{ + ConVar *var = ( ConVar * )m_pParent; + var->InternalSetFloatValue( value ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : value - +//----------------------------------------------------------------------------- +void ConVar::SetValue( int value ) +{ + ConVar *var = ( ConVar * )m_pParent; + var->InternalSetIntValue( value ); +} + +//----------------------------------------------------------------------------- +// Purpose: Reset to default value +//----------------------------------------------------------------------------- +void ConVar::Revert( void ) +{ + // Force default value again + ConVar *var = ( ConVar * )m_pParent; + var->SetValue( var->m_pszDefaultValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : minVal - +// Output : true if there is a min set +//----------------------------------------------------------------------------- +bool ConVar::GetMin( float& minVal ) const +{ + minVal = m_pParent->m_fMinVal; + return m_pParent->m_bHasMin; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : maxVal - +//----------------------------------------------------------------------------- +bool ConVar::GetMax( float& maxVal ) const +{ + maxVal = m_pParent->m_fMaxVal; + return m_pParent->m_bHasMax; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char *ConVar::GetDefault( void ) const +{ + return m_pParent->m_pszDefaultValue; +} + +void ConVar::SetDefault( const char *pszDefault ) +{ + m_pszDefaultValue = pszDefault ? pszDefault : ""; + Assert( m_pszDefaultValue ); +} + +//----------------------------------------------------------------------------- +// This version is simply used to make reading convars simpler. +// Writing convars isn't allowed in this mode +//----------------------------------------------------------------------------- +class CEmptyConVar : public ConVar +{ +public: + CEmptyConVar() : ConVar( "", "0" ) {} + // Used for optimal read access + virtual void SetValue( const char *pValue ) {} + virtual void SetValue( float flValue ) {} + virtual void SetValue( int nValue ) {} + virtual const char *GetName( void ) const { return ""; } + virtual bool IsFlagSet( int nFlags ) const { return false; } +}; + +static CEmptyConVar s_EmptyConVar; + +ConVarRef::ConVarRef( const char *pName ) +{ + Init( pName, false ); +} + +ConVarRef::ConVarRef( const char *pName, bool bIgnoreMissing ) +{ + Init( pName, bIgnoreMissing ); +} + +void ConVarRef::Init( const char *pName, bool bIgnoreMissing ) +{ + m_pConVar = g_pCVar ? g_pCVar->FindVar( pName ) : &s_EmptyConVar; + if ( !m_pConVar ) + { + m_pConVar = &s_EmptyConVar; + } + m_pConVarState = static_cast< ConVar * >( m_pConVar ); + if( !IsValid() ) + { + static bool bFirst = true; + if ( g_pCVar || bFirst ) + { + if ( !bIgnoreMissing ) + { + Warning( "ConVarRef %s doesn't point to an existing ConVar\n", pName ); + } + bFirst = false; + } + } +} + +ConVarRef::ConVarRef( IConVar *pConVar ) +{ + m_pConVar = pConVar ? pConVar : &s_EmptyConVar; + m_pConVarState = static_cast< ConVar * >( m_pConVar ); +} + +bool ConVarRef::IsValid() const +{ + return m_pConVar != &s_EmptyConVar; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ConVar_PrintFlags( const ConCommandBase *var ) +{ + bool any = false; + if ( var->IsFlagSet( FCVAR_GAMEDLL ) ) + { + ConMsg( " game" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_CLIENTDLL ) ) + { + ConMsg( " client" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_ARCHIVE ) ) + { + ConMsg( " archive" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_NOTIFY ) ) + { + ConMsg( " notify" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_SPONLY ) ) + { + ConMsg( " singleplayer" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_NOT_CONNECTED ) ) + { + ConMsg( " notconnected" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_CHEAT ) ) + { + ConMsg( " cheat" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_REPLICATED ) ) + { + ConMsg( " replicated" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_SERVER_CAN_EXECUTE ) ) + { + ConMsg( " server_can_execute" ); + any = true; + } + + if ( var->IsFlagSet( FCVAR_CLIENTCMD_CAN_EXECUTE ) ) + { + ConMsg( " clientcmd_can_execute" ); + any = true; + } + + if ( any ) + { + ConMsg( "\n" ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ConVar_PrintDescription( const ConCommandBase *pVar ) +{ + bool bMin, bMax; + float fMin, fMax; + const char *pStr; + + assert( pVar ); + + Color clr; + clr.SetColor( 255, 100, 100, 255 ); + + if ( !pVar->IsCommand() ) + { + ConVar *var = ( ConVar * )pVar; + const ConVar_ServerBounded *pBounded = dynamic_cast( var ); + + bMin = var->GetMin( fMin ); + bMax = var->GetMax( fMax ); + + const char *value = NULL; + char tempVal[ 32 ]; + + if ( pBounded || var->IsFlagSet( FCVAR_NEVER_AS_STRING ) ) + { + value = tempVal; + + int intVal = pBounded ? pBounded->GetInt() : var->GetInt(); + float floatVal = pBounded ? pBounded->GetFloat() : var->GetFloat(); + + if ( fabs( (float)intVal - floatVal ) < 0.000001 ) + { + Q_snprintf( tempVal, sizeof( tempVal ), "%d", intVal ); + } + else + { + Q_snprintf( tempVal, sizeof( tempVal ), "%f", floatVal ); + } + } + else + { + value = var->GetString(); + } + + if ( value ) + { + ConColorMsg( clr, "\"%s\" = \"%s\"", var->GetName(), value ); + + if ( stricmp( value, var->GetDefault() ) ) + { + ConMsg( " ( def. \"%s\" )", var->GetDefault() ); + } + } + + if ( bMin ) + { + ConMsg( " min. %f", fMin ); + } + if ( bMax ) + { + ConMsg( " max. %f", fMax ); + } + + ConMsg( "\n" ); + + // Handled virtualized cvars. + if ( pBounded && fabs( pBounded->GetFloat() - var->GetFloat() ) > 0.0001f ) + { + ConColorMsg( clr, "** NOTE: The real value is %.3f but the server has temporarily restricted it to %.3f **\n", + var->GetFloat(), pBounded->GetFloat() ); + } + } + else + { + ConCommand *var = ( ConCommand * )pVar; + + ConColorMsg( clr, "\"%s\"\n", var->GetName() ); + } + + ConVar_PrintFlags( pVar ); + + pStr = pVar->GetHelpText(); + if ( pStr && pStr[0] ) + { + ConMsg( " - %s\n", pStr ); + } +} diff --git a/tier1/cpuid.asm b/tier1/cpuid.asm new file mode 100644 index 0000000..6dad2d5 --- /dev/null +++ b/tier1/cpuid.asm @@ -0,0 +1,23 @@ +PUBLIC __cpuid + +.CODE + +__cpuid PROC + PUSH RBX + PUSH RDX + PUSH RCX + + XOR RAX,RAX + INC RAX + CPUID + MOV RAX,RDX + + POP RCX + POP RDX + POP RBX + + RET + +__cpuid ENDP + + END diff --git a/tier1/datamanager.cpp b/tier1/datamanager.cpp new file mode 100644 index 0000000..0a8134f --- /dev/null +++ b/tier1/datamanager.cpp @@ -0,0 +1,411 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "basetypes.h" +#include "datamanager.h" + +DECLARE_POINTER_HANDLE( memhandle_t ); + +#define AUTO_LOCK_DM() AUTO_LOCK_( CDataManagerBase, *this ) + +CDataManagerBase::CDataManagerBase( unsigned int maxSize ) +{ + m_targetMemorySize = maxSize; + m_memUsed = 0; + m_lruList = m_memoryLists.CreateList(); + m_lockList = m_memoryLists.CreateList(); + m_freeList = m_memoryLists.CreateList(); + m_listsAreFreed = 0; +} + +CDataManagerBase::~CDataManagerBase() +{ + Assert( m_listsAreFreed ); +} + +void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize ) +{ + Lock(); + m_memUsed += (int)newSize - (int)oldSize; + Unlock(); +} + +void CDataManagerBase::SetTargetSize( unsigned int targetSize ) +{ + m_targetMemorySize = targetSize; +} + +unsigned int CDataManagerBase::FlushAllUnlocked() +{ + Lock(); + + int nFlush = m_memoryLists.Count( m_lruList ); + void **pScratch = (void **)_alloca( nFlush * sizeof(void *) ); + CUtlVector destroyList( pScratch, nFlush ); + + unsigned nBytesInitial = MemUsed_Inline(); + + int node = m_memoryLists.Head(m_lruList); + while ( node != m_memoryLists.InvalidIndex() ) + { + int next = m_memoryLists.Next(node); + m_memoryLists.Unlink( m_lruList, node ); + destroyList.AddToTail( GetForFreeByIndex( node ) ); + node = next; + } + + Unlock(); + + for ( int i = 0; i < nFlush; i++ ) + { + DestroyResourceStorage( destroyList[i] ); + } + + return ( nBytesInitial - MemUsed_Inline() ); +} + +unsigned int CDataManagerBase::FlushToTargetSize() +{ + return EnsureCapacity(0); +} + +// Frees everything! The LRU AND the LOCKED items. This is only used to forcibly free the resources, +// not to make space. + +unsigned int CDataManagerBase::FlushAll() +{ + Lock(); + + int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList ); + void **pScratch = (void **)_alloca( nFlush * sizeof(void *) ); + CUtlVector destroyList( pScratch, nFlush ); + + unsigned result = MemUsed_Inline(); + int node; + int nextNode; + + node = m_memoryLists.Head(m_lruList); + while ( node != m_memoryLists.InvalidIndex() ) + { + nextNode = m_memoryLists.Next(node); + m_memoryLists.Unlink( m_lruList, node ); + destroyList.AddToTail( GetForFreeByIndex( node ) ); + node = nextNode; + } + + node = m_memoryLists.Head(m_lockList); + while ( node != m_memoryLists.InvalidIndex() ) + { + nextNode = m_memoryLists.Next(node); + m_memoryLists.Unlink( m_lockList, node ); + m_memoryLists[node].lockCount = 0; + destroyList.AddToTail( GetForFreeByIndex( node ) ); + node = nextNode; + } + + m_listsAreFreed = false; + Unlock(); + + for ( int i = 0; i < nFlush; i++ ) + { + DestroyResourceStorage( destroyList[i] ); + } + + return result; +} + +unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge ) +{ + unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge; + // Check for underflow + if ( MemUsed_Inline() < nBytesToPurge ) + nTargetSize = 0; + unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize; + return EnsureCapacity( nImpliedCapacity ); +} + + +void CDataManagerBase::DestroyResource( memhandle_t handle ) +{ + Lock(); + unsigned short index = FromHandle( handle ); + if ( !m_memoryLists.IsValidIndex(index) ) + { + Unlock(); + return; + } + + Assert( m_memoryLists[index].lockCount == 0 ); + if ( m_memoryLists[index].lockCount ) + BreakLock( handle ); + m_memoryLists.Unlink( m_lruList, index ); + void *p = GetForFreeByIndex( index ); + Unlock(); + + DestroyResourceStorage( p ); +} + + +void *CDataManagerBase::LockResource( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + if ( m_memoryLists[memoryIndex].lockCount == 0 ) + { + m_memoryLists.Unlink( m_lruList, memoryIndex ); + m_memoryLists.LinkToTail( m_lockList, memoryIndex ); + } + Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1); + m_memoryLists[memoryIndex].lockCount++; + return m_memoryLists[memoryIndex].pStore; + } + + return NULL; +} + +int CDataManagerBase::UnlockResource( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + Assert( m_memoryLists[memoryIndex].lockCount > 0 ); + if ( m_memoryLists[memoryIndex].lockCount > 0 ) + { + m_memoryLists[memoryIndex].lockCount--; + if ( m_memoryLists[memoryIndex].lockCount == 0 ) + { + m_memoryLists.Unlink( m_lockList, memoryIndex ); + m_memoryLists.LinkToTail( m_lruList, memoryIndex ); + } + } + return m_memoryLists[memoryIndex].lockCount; + } + + return 0; +} + +void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + return m_memoryLists[memoryIndex].pStore; + } + return NULL; +} + + +void *CDataManagerBase::GetResource_NoLock( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + TouchByIndex( memoryIndex ); + return m_memoryLists[memoryIndex].pStore; + } + return NULL; +} + +void CDataManagerBase::TouchResource( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + TouchByIndex( FromHandle(handle) ); +} + +void CDataManagerBase::MarkAsStale( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + if ( m_memoryLists[memoryIndex].lockCount == 0 ) + { + m_memoryLists.Unlink( m_lruList, memoryIndex ); + m_memoryLists.LinkToHead( m_lruList, memoryIndex ); + } + } +} + +int CDataManagerBase::BreakLock( memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount ) + { + int nBroken = m_memoryLists[memoryIndex].lockCount; + m_memoryLists[memoryIndex].lockCount = 0; + m_memoryLists.Unlink( m_lockList, memoryIndex ); + m_memoryLists.LinkToTail( m_lruList, memoryIndex ); + + return nBroken; + } + return 0; +} + +int CDataManagerBase::BreakAllLocks() +{ + AUTO_LOCK_DM(); + int nBroken = 0; + int node; + int nextNode; + + node = m_memoryLists.Head(m_lockList); + while ( node != m_memoryLists.InvalidIndex() ) + { + nBroken++; + nextNode = m_memoryLists.Next(node); + m_memoryLists[node].lockCount = 0; + m_memoryLists.Unlink( m_lockList, node ); + m_memoryLists.LinkToTail( m_lruList, node ); + node = nextNode; + } + + return nBroken; + +} + +unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked ) +{ + AUTO_LOCK_DM(); + int memoryIndex = m_memoryLists.Head(m_freeList); + unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList; + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + m_memoryLists.Unlink( m_freeList, memoryIndex ); + m_memoryLists.LinkToTail( list, memoryIndex ); + } + else + { + memoryIndex = m_memoryLists.AddToTail( list ); + } + + if ( bCreateLocked ) + { + m_memoryLists[memoryIndex].lockCount++; + } + + return memoryIndex; +} + +memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize ) +{ + AUTO_LOCK_DM(); + resource_lru_element_t &mem = m_memoryLists[memoryIndex]; + mem.pStore = pStore; + m_memUsed += realSize; + return ToHandle(memoryIndex); +} + +void CDataManagerBase::TouchByIndex( unsigned short memoryIndex ) +{ + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + if ( m_memoryLists[memoryIndex].lockCount == 0 ) + { + m_memoryLists.Unlink( m_lruList, memoryIndex ); + m_memoryLists.LinkToTail( m_lruList, memoryIndex ); + } + } +} + +memhandle_t CDataManagerBase::ToHandle( unsigned short index ) +{ + unsigned int hiword = m_memoryLists.Element(index).serial; + hiword <<= 16; + index++; + return (memhandle_t)( hiword|index ); +} + +unsigned int CDataManagerBase::TargetSize() +{ + return MemTotal_Inline(); +} + +unsigned int CDataManagerBase::AvailableSize() +{ + return MemAvailable_Inline(); +} + + +unsigned int CDataManagerBase::UsedSize() +{ + return MemUsed_Inline(); +} + +// free resources until there is enough space to hold "size" +unsigned int CDataManagerBase::EnsureCapacity( unsigned int size ) +{ + unsigned nBytesInitial = MemUsed_Inline(); + while ( MemUsed_Inline() > MemTotal_Inline() || MemAvailable_Inline() < size ) + { + Lock(); + int lruIndex = m_memoryLists.Head( m_lruList ); + if ( lruIndex == m_memoryLists.InvalidIndex() ) + { + Unlock(); + break; + } + m_memoryLists.Unlink( m_lruList, lruIndex ); + void *p = GetForFreeByIndex( lruIndex ); + Unlock(); + DestroyResourceStorage( p ); + } + return ( nBytesInitial - MemUsed_Inline() ); +} + +// free this resource and move the handle to the free list +void *CDataManagerBase::GetForFreeByIndex( unsigned short memoryIndex ) +{ + void *p = NULL; + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + Assert( m_memoryLists[memoryIndex].lockCount == 0 ); + + resource_lru_element_t &mem = m_memoryLists[memoryIndex]; + unsigned size = GetRealSize( mem.pStore ); + if ( size > m_memUsed ) + { + ExecuteOnce( Warning( "Data manager 'used' memory incorrect\n" ) ); + size = m_memUsed; + } + m_memUsed -= size; + p = mem.pStore; + mem.pStore = NULL; + mem.serial++; + m_memoryLists.LinkToTail( m_freeList, memoryIndex ); + } + return p; +} + +// get a list of everything in the LRU +void CDataManagerBase::GetLRUHandleList( CUtlVector< memhandle_t >& list ) +{ + for ( int node = m_memoryLists.Tail(m_lruList); + node != m_memoryLists.InvalidIndex(); + node = m_memoryLists.Previous(node) ) + { + list.AddToTail( ToHandle( node ) ); + } +} + +// get a list of everything locked +void CDataManagerBase::GetLockHandleList( CUtlVector< memhandle_t >& list ) +{ + for ( int node = m_memoryLists.Head(m_lockList); + node != m_memoryLists.InvalidIndex(); + node = m_memoryLists.Next(node) ) + { + list.AddToTail( ToHandle( node ) ); + } +} + diff --git a/tier1/diff.cpp b/tier1/diff.cpp new file mode 100644 index 0000000..2960e4d --- /dev/null +++ b/tier1/diff.cpp @@ -0,0 +1,547 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier1/diff.h" +#include "mathlib/mathlib.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// format of diff output: +// 0NN (N=1..127) copy next N literaly +// +// 1NN (N=1..127) ofs (-128..127) copy next N bytes from original, changin offset by N bytes from +// last copy end +// 100 N ofs(-32768..32767) copy next N, with larger delta offset +// 00 NNNN(1..65535) ofs(-32768..32767) big copy from old +// 80 00 NN NN NN big raw copy +// +// available codes (could be used for additonal compression ops) +// long offset form whose offset could have fit in short offset + +// note - this algorithm uses storage equal to 8* the old buffer size. 64k=.5mb + + +#define MIN_MATCH_LEN 8 +#define ACCEPTABLE_MATCH_LEN 4096 + +struct BlockPtr +{ + BlockPtr *Next; + uint8 const *dataptr; +}; + +template static inline void AddToHead(T * & head, V * node) +{ + node->Next=head; + head=node; +} + +void Fail(char const *msg) +{ + Assert(0); +} + +void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList, + int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize) +{ + uint8 const *copy_src=OldBlock; + uint8 const *end_of_diff_list=DiffList+DiffListSize; + uint8 const *obuf=Output; + while(DiffList32767) + copy_ofs|=0xffff0000; + // printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz); + + memcpy(Output,copy_src+copy_ofs,copy_sz); + Output+=copy_sz; + copy_src=copy_src+copy_ofs+copy_sz; + DiffList+=4; + } + else + { + if (op & 0x80) + { + int copy_sz=op & 0x7f; + int copy_ofs; + if (copy_sz==0) + { + copy_sz=DiffList[0]; + if (copy_sz==0) + { + // big raw copy + copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3]; + memcpy(Output,DiffList+4,copy_sz); + // printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz); + + DiffList+=copy_sz+4; + Output+=copy_sz; + } + else + { + copy_ofs=DiffList[1]+(DiffList[2]*256); + if (copy_ofs>32767) + copy_ofs|=0xffff0000; + // printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz); + + memcpy(Output,copy_src+copy_ofs,copy_sz); + Output+=copy_sz; + copy_src=copy_src+copy_ofs+copy_sz; + DiffList+=3; + } + } + else + { + copy_ofs=DiffList[0]; + if (copy_ofs>127) + copy_ofs|=0xffffff80; + // printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz); + + memcpy(Output,copy_src+copy_ofs,copy_sz); + Output+=copy_sz; + copy_src=copy_src+copy_ofs+copy_sz; + DiffList++; + } + } + else + { + // printf("raw copy %d to %x\n",op & 127,Output-obuf); + memcpy(Output,DiffList,op & 127); + Output+=op & 127; + DiffList+=(op & 127); + } + } + } + ResultListSize = (int)((ptrdiff_t)Output - (ptrdiff_t)obuf); + +} + +static void CopyPending(int len, uint8 const *rawbytes,uint8 * &outbuf, uint8 const *limit) +{ +// printf("copy raw len=%d\n",len); + if (len<128) + { + if (limit-outbuf < len+1) + Fail("diff buffer overrun"); + *(outbuf++)=len; + memcpy(outbuf,rawbytes,len); + outbuf+=len; + } + else + { + if (limit-outbuf < len+5) + Fail("diff buffer overrun"); + *(outbuf++)=0x80; + *(outbuf++)=0x00; + *(outbuf++)=(len & 255); + *(outbuf++)=((len>>8) & 255); + *(outbuf++)=((len>>16) & 255); + memcpy(outbuf,rawbytes,len); + outbuf+=len; + } +} + +static uint32 hasher(uint8 const *mdata) +{ + // attempt to scramble the bits of h1 and h2 together + uint32 ret=0; + for(int i=0;idataptr=walk; + AddToHead(HashedMatches[hash1],newnode); + walk++; + } + else + ret=1; + // now, we have the hash table which may be used to search. begin the output step + int pending_raw_len=0; + walk=NewBlock; + uint8 *outbuf=Output; + uint8 const *lastmatchend=OldBlock; + while(walkMIN_MATCH_LEN, take it + for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next) + { + // find the match length + int match_of=b->dataptr-lastmatchend; + if ((match_of>-32768) && (match_of<32767)) + { + size_t max_mlength=vmin(65535,(size_t)(OldBlock+OldSize-b->dataptr)); + max_mlength=vmin(max_mlength,(size_t)(NewBlock+NewSize-walk)); + size_t i; + for(i=0;idataptr[i]) + break; + if ((i>MIN_MATCH_LEN) && (i>longest)) + { + longest=i; + longest_block=b; + if (longest>ACCEPTABLE_MATCH_LEN) + break; + } + } + } + } + // now, we have a match maybe + if (longest_block) + { + if (pending_raw_len) // must output + { + ret=1; + CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize); + pending_raw_len=0; + } + // now, output copy block + int match_of=longest_block->dataptr-lastmatchend; + int nremaining=OutSize-(outbuf-Output); + + if (match_of) + ret=1; +// printf("copy from %x to %x len=%d\n", match_of,outbuf-Output,longest); + if (longest>127) + { + // use really long encoding + if (nremaining<5) + Fail("diff buff needs increase"); + *(outbuf++)=00; + *(outbuf++)=(longest & 255); + *(outbuf++)=((longest>>8) & 255); + *(outbuf++)=(match_of & 255); + *(outbuf++)=((match_of>>8) & 255); + + } + else + { + if ((match_of>=-128) && (match_of<128)) + { + if (nremaining<2) + Fail("diff buff needs increase"); + *(outbuf++)=128+longest; + *(outbuf++)=(match_of&255); + } + else + { + // use long encoding + if (nremaining<4) + Fail("diff buff needs increase"); + *(outbuf++)=0x80; + *(outbuf++)=longest; + *(outbuf++)=(match_of & 255); + *(outbuf++)=((match_of>>8) & 255); + } + } + lastmatchend=longest_block->dataptr+longest; + walk+=longest; + } + else + { + walk++; + pending_raw_len++; + } + } + // now, flush pending raw copy + if (pending_raw_len) // must output + { + ret=1; + CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize); + pending_raw_len=0; + } + delete[] HashedMatches; + if (Blocks) + delete[] Blocks; + DiffListSize=(int)(outbuf-Output); + return ret; +} + + +int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock, + int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize) +{ + + int ret=0; + if (OldSize!=NewSize) + ret=1; + // first, build the hash table + BlockPtr *HashedMatches[65536]; + memset(HashedMatches,0,sizeof(HashedMatches)); + BlockPtr *Blocks=0; + if (OldSize) + Blocks=new BlockPtr[OldSize]; + BlockPtr *FreeList=Blocks; + // now, build the hash table + uint8 const *walk=OldBlock; + if (OldBlock && OldSize) + while(walkdataptr=walk; + AddToHead(HashedMatches[hash1],newnode); + walk++; + } + else + ret=1; + // now, we have the hash table which may be used to search. begin the output step + int pending_raw_len=0; + walk=NewBlock; + uint8 *outbuf=Output; + uint8 const *lastmatchend=OldBlock; + while(walkMIN_MATCH_LEN, take it + for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next) + { + // find the match length + int match_of=b->dataptr-lastmatchend; + if ((match_of>-32768) && (match_of<32767)) + { + size_t max_mlength = vmin(65535, (size_t)(OldBlock + OldSize - b->dataptr)); + max_mlength = vmin(max_mlength, (size_t)(NewBlock + NewSize - walk)); + size_t i; + for(i=0;idataptr[i]) + break; + if ((i>MIN_MATCH_LEN) && (i>longest)) + { + longest=i; + longest_block=b; + } + } + } + } + // now, we have a match maybe + if (longest_block) + { + if (pending_raw_len) // must output + { + ret=1; + CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize); + pending_raw_len=0; + } + // now, output copy block + int match_of=longest_block->dataptr-lastmatchend; + int nremaining=OutSize-(outbuf-Output); + if (match_of) + ret=1; + if (longest>127) + { + // use really long encoding + if (nremaining<5) + Fail("diff buff needs increase"); + *(outbuf++)=00; + *(outbuf++)=(longest & 255); + *(outbuf++)=((longest>>8) & 255); + *(outbuf++)=(match_of & 255); + *(outbuf++)=((match_of>>8) & 255); + } + else + { + if ((match_of>=-128) && (match_of<128)) + { + if (nremaining<2) + Fail("diff buff needs increase"); + *(outbuf++)=128+longest; + *(outbuf++)=(match_of&255); + } + else + { + // use long encoding + if (nremaining<4) + Fail("diff buff needs increase"); + *(outbuf++)=0x80; + *(outbuf++)=longest; + *(outbuf++)=(match_of & 255); + *(outbuf++)=((match_of>>8) & 255); + } + } + lastmatchend=longest_block->dataptr+longest; + walk+=longest; + } + else + { + walk++; + pending_raw_len++; + } + } + // now, flush pending raw copy + if (pending_raw_len) // must output + { + ret=1; + CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize); + pending_raw_len=0; + } + if (Blocks) + delete[] Blocks; + DiffListSize=(int)(outbuf-Output); + return ret; +} + + +int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock, + int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize) +{ + + int ret=0; + if (OldSize!=NewSize) + ret=1; + uint8 const *old_data_hash[256]; + memset(old_data_hash,0,sizeof(old_data_hash)); + int pending_raw_len=0; + uint8 const *walk=NewBlock; + uint8 const *oldptr=OldBlock; + uint8 *outbuf=Output; + uint8 const *lastmatchend=OldBlock; + while(walkMIN_MATCH_LEN) + { + longest_block=old_data_hash[hash1]; + longest=nmatches; + } + } + } + // now, we have a match maybe + if (longest_block) + { + if (pending_raw_len) // must output + { + ret=1; + CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize); + pending_raw_len=0; + } + // now, output copy block + int match_of=longest_block-lastmatchend; + int nremaining=OutSize-(outbuf-Output); + if (match_of) + ret=1; + if (longest>127) + { + // use really long encoding + if (nremaining<5) + Fail("diff buff needs increase"); + *(outbuf++)=00; + *(outbuf++)=(longest & 255); + *(outbuf++)=((longest>>8) & 255); + *(outbuf++)=(match_of & 255); + *(outbuf++)=((match_of>>8) & 255); + } + else + { + if ((match_of>=-128) && (match_of<128)) + { + if (nremaining<2) + Fail("diff buff needs increase"); + *(outbuf++)=128+longest; + *(outbuf++)=(match_of&255); + } + else + { + // use long encoding + if (nremaining<4) + Fail("diff buff needs increase"); + *(outbuf++)=0x80; + *(outbuf++)=longest; + *(outbuf++)=(match_of & 255); + *(outbuf++)=((match_of>>8) & 255); + } + } + lastmatchend=longest_block+longest; + walk+=longest; + } + else + { + walk++; + pending_raw_len++; + } + } + // now, flush pending raw copy + if (pending_raw_len) // must output + { + ret=1; + CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize); + pending_raw_len=0; + } + DiffListSize=(int)(outbuf-Output); + return ret; +} + + diff --git a/tier1/fileio.cpp b/tier1/fileio.cpp new file mode 100644 index 0000000..3a90998 --- /dev/null +++ b/tier1/fileio.cpp @@ -0,0 +1,497 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A collection of utility classes to simplify file I/O, and +// as much as possible contain portability problems. Here avoiding +// including windows.h. +// +//============================================================================= + +#if defined(_WIN32) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0502 // ReadDirectoryChangesW +#endif + +#if defined(OSX) +#include +#include +#include +#include +#endif + +#define ASYNC_FILEIO +#if defined( LINUX ) +// Linux hasn't got a good AIO library that we have found yet, so lets punt for now +#undef ASYNC_FILEIO +#endif + +#if defined(_WIN32) +//#include +#include +// unset to force to use stdio implementation +#define WIN32_FILEIO + +#if defined(ASYNC_FILEIO) +#if defined(_WIN32) && !defined(WIN32_FILEIO) +#error "trying to use async io without win32 filesystem API usage, that isn't doable" +#endif +#endif + +#else /* not defined (_WIN32) */ +#include +#include +#include // for unlink +#include // defines PATH_MAX +#include // 'cause we like smashing the stack +#if defined( _PS3 ) +#include +#else +#include +#include +#endif +#include +#define int64 int64_t + +#define _A_SUBDIR S_IFDIR + +// FUTURE map _A_HIDDEN via checking filename against .* +#define _A_HIDDEN 0 + +// FUTURE check 'read only' by checking mode against S_IRUSR +#define _A_RDONLY 0 + +// no files under posix are 'system' or 'archive' +#define _A_SYSTEM 0 +#define _A_ARCH 0 + +#endif + +#include "tier1/fileio.h" +#include "tier1/utlbuffer.h" +#include "tier1/strtools.h" +#include + +#if defined( WIN32_FILEIO ) +#include "winlite.h" +#endif + +#if defined( ASYNC_FILEIO ) +#ifdef _WIN32 +#include "winlite.h" +#elif defined(_PS3) +// bugbug ps3 - see some aio files under libfs.. skipping for the moment +#elif defined(POSIX) +#include +#else +#error "aio please" +#endif +#endif + +//----------------------------------------------------------------------------- +// Purpose: Constructor from UTF8 +//----------------------------------------------------------------------------- +CPathString::CPathString( const char *pchUTF8Path ) +{ + // Need to first turn into an absolute path, so \\?\ pre-pended paths will be ok + m_pchUTF8Path = new char[ MAX_UNICODE_PATH_IN_UTF8 ]; + m_pwchWideCharPathPrepended = NULL; + + // First, convert to absolute path, which also does Q_FixSlashes for us. + Q_MakeAbsolutePath( m_pchUTF8Path, MAX_UNICODE_PATH * 4, pchUTF8Path ); + + // Second, fix any double slashes + V_FixDoubleSlashes( m_pchUTF8Path ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CPathString::~CPathString() +{ + if ( m_pwchWideCharPathPrepended ) + { + delete[] m_pwchWideCharPathPrepended; + m_pwchWideCharPathPrepended = NULL; + } + + if ( m_pchUTF8Path ) + { + delete[] m_pchUTF8Path; + m_pchUTF8Path = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Access UTF8 path +//----------------------------------------------------------------------------- +const char * CPathString::GetUTF8Path() +{ + return m_pchUTF8Path; +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets wchar_t based path, with \\?\ pre-pended (allowing long paths +// on Win32, should only be used with unicode extended path aware filesystem calls) +//----------------------------------------------------------------------------- +const wchar_t *CPathString::GetWCharPathPrePended() +{ + PopulateWCharPath(); + return m_pwchWideCharPathPrepended; +} + + +//----------------------------------------------------------------------------- +// Purpose: Builds wchar path string +//----------------------------------------------------------------------------- +void CPathString::PopulateWCharPath() +{ + if ( m_pwchWideCharPathPrepended ) + return; + + // Check if the UTF8 path starts with \\, which on Win32 means it's a UNC path, and then needs a different prefix + if ( m_pchUTF8Path[0] == '\\' && m_pchUTF8Path[1] == '\\' ) + { + m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+8]; + Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\UNC\\", 8*sizeof(wchar_t) ); +#ifdef DBGFLAG_ASSERT + int cchResult = +#endif + Q_UTF8ToUnicode( m_pchUTF8Path+2, m_pwchWideCharPathPrepended+8, MAX_UNICODE_PATH*sizeof(wchar_t) ); + Assert( cchResult ); + + // Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then. + m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+7] = 0; + } + else + { + m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+4]; + Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\", 4*sizeof(wchar_t) ); +#ifdef DBGFLAG_ASSERT + int cchResult = +#endif + Q_UTF8ToUnicode( m_pchUTF8Path, m_pwchWideCharPathPrepended+4, MAX_UNICODE_PATH*sizeof(wchar_t) ); + Assert( cchResult ); + + // Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then. + m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+3] = 0; + } +} + +#ifdef WIN32 +struct DirWatcherOverlapped : public OVERLAPPED +{ + CDirWatcher *m_pDirWatcher; +}; +#endif + +#if !defined(_PS3) && !defined(_X360) +// a buffer full of file names +static const int k_cubDirWatchBufferSize = 8 * 1024; + +//----------------------------------------------------------------------------- +// Purpose: directory watching +//----------------------------------------------------------------------------- +CDirWatcher::CDirWatcher() +{ + m_hFile = NULL; + m_pOverlapped = NULL; + m_pFileInfo = NULL; +#ifdef OSX + m_WatcherStream = 0; +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: directory watching +//----------------------------------------------------------------------------- +CDirWatcher::~CDirWatcher() +{ +#ifdef WIN32 + if ( m_pOverlapped ) + { + // mark the overlapped structure as gone + DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped; + pDirWatcherOverlapped->m_pDirWatcher = NULL; + } + + if ( m_hFile ) + { + // make sure we flush any pending I/O's on the handle + ::CancelIo( m_hFile ); + ::SleepEx( 0, TRUE ); + // close the handle + ::CloseHandle( m_hFile ); + } +#elif defined(OSX) + if ( m_WatcherStream ) + { + FSEventStreamStop( (FSEventStreamRef)m_WatcherStream ); + FSEventStreamInvalidate( (FSEventStreamRef)m_WatcherStream ); + FSEventStreamRelease( (FSEventStreamRef)m_WatcherStream ); + m_WatcherStream = 0; + } +#endif + if ( m_pFileInfo ) + { + free( m_pFileInfo ); + } + if ( m_pOverlapped ) + { + free( m_pOverlapped ); + } +} + + +#ifdef WIN32 +//----------------------------------------------------------------------------- +// Purpose: callback watch +// gets called on the same thread whenever a SleepEx() occurs +//----------------------------------------------------------------------------- +class CDirWatcherFriend +{ +public: + static void WINAPI DirWatchCallback( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *pOverlapped ) + { + DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)pOverlapped; + + // see if we've been cancelled + if ( !pDirWatcherOverlapped->m_pDirWatcher ) + return; + + // parse and pass back + if ( dwNumberOfBytesTransfered > sizeof(FILE_NOTIFY_INFORMATION) ) + { + FILE_NOTIFY_INFORMATION *pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)pDirWatcherOverlapped->m_pDirWatcher->m_pFileInfo; + do + { + // null terminate the string and turn it to UTF-8 + int cNumWChars = pFileNotifyInformation->FileNameLength / sizeof(wchar_t); + wchar_t *pwchT = new wchar_t[cNumWChars + 1]; + memcpy( pwchT, pFileNotifyInformation->FileName, pFileNotifyInformation->FileNameLength ); + pwchT[cNumWChars] = 0; + CStrAutoEncode strAutoEncode( pwchT ); + + // add it to our list + pDirWatcherOverlapped->m_pDirWatcher->AddFileToChangeList( strAutoEncode.ToString() ); + delete[] pwchT; + if ( pFileNotifyInformation->NextEntryOffset == 0 ) + break; + + // move to the next file + pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)(((byte*)pFileNotifyInformation) + pFileNotifyInformation->NextEntryOffset); + } while ( 1 ); + } + + + // watch again + pDirWatcherOverlapped->m_pDirWatcher->PostDirWatch(); + } +}; +#elif defined(OSX) +void CheckDirectoryForChanges( const char *path_buff, CDirWatcher *pDirWatch, bool bRecurse ) +{ + DIR *dir = opendir(path_buff); + char fullpath[MAX_PATH]; + struct dirent *dirent; + struct timespec ts = { 0, 0 }; + bool bTimeSet = false; + + while ( (dirent = readdir(dir)) != NULL ) + { + if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + snprintf( fullpath, PATH_MAX, "%s/%s", path_buff, dirent->d_name ); + + struct stat st; + if (lstat(fullpath, &st) != 0) + continue; + + if ( S_ISDIR(st.st_mode) && bRecurse ) + { + CheckDirectoryForChanges( fullpath, pDirWatch, bRecurse ); + } + else if ( st.st_mtimespec.tv_sec > pDirWatch->m_modTime.tv_sec || + ( st.st_mtimespec.tv_sec == pDirWatch->m_modTime.tv_sec && st.st_mtimespec.tv_nsec > pDirWatch->m_modTime.tv_nsec ) ) + { + ts = st.st_mtimespec; + bTimeSet = true; + // the win32 size only sends up the dir relative to the watching dir, so replicate that here + pDirWatch->AddFileToChangeList( fullpath + pDirWatch->m_BaseDir.Length() + 1 ); + } + } + + if ( bTimeSet ) + pDirWatch->m_modTime = ts; + closedir(dir); +} + +static void fsevents_callback( ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,void *eventPaths, + const FSEventStreamEventFlags eventMasks[], const FSEventStreamEventId eventIDs[] ) +{ + char path_buff[PATH_MAX]; + for (int i=0; i < numEvents; i++) + { + char **paths = (char **)eventPaths; + + strcpy(path_buff, paths[i]); + int len = strlen(path_buff); + if (path_buff[len-1] == '/') + { + // chop off a trailing slash + path_buff[--len] = '\0'; + } + + bool bRecurse = false; + + if (eventMasks[i] & kFSEventStreamEventFlagMustScanSubDirs + || eventMasks[i] & kFSEventStreamEventFlagUserDropped + || eventMasks[i] & kFSEventStreamEventFlagKernelDropped) + { + bRecurse = true; + } + + CDirWatcher *pDirWatch = (CDirWatcher *)clientCallBackInfo; + // make sure its in our subdir + if ( !V_strnicmp( path_buff, pDirWatch->m_BaseDir.String(), pDirWatch->m_BaseDir.Length() ) ) + CheckDirectoryForChanges( path_buff, pDirWatch, bRecurse ); + } +} + + + + +#endif + +//----------------------------------------------------------------------------- +// Purpose: only one directory can be watched at a time +//----------------------------------------------------------------------------- +void CDirWatcher::SetDirToWatch( const char *pchDir ) +{ + if ( !pchDir || !*pchDir ) + return; + + CPathString strPath( pchDir ); +#ifdef WIN32 + // open the directory + m_hFile = ::CreateFileW( strPath.GetWCharPathPrePended(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, NULL ); + + // create our buffers + m_pFileInfo = malloc( k_cubDirWatchBufferSize ); + m_pOverlapped = malloc( sizeof( DirWatcherOverlapped ) ); + + // post a watch + PostDirWatch(); +#elif defined(OSX) + CFStringRef mypath = CFStringCreateWithCString( NULL, strPath.GetUTF8Path(), kCFStringEncodingMacRoman ); + if ( !mypath ) + { + Assert( !"Failed to CFStringCreateWithCString watcher path" ); + return; + } + + CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL); + FSEventStreamContext callbackInfo = {0, this, NULL, NULL, NULL}; + CFAbsoluteTime latency = 1.0; // Latency in seconds + + m_WatcherStream = (void *)FSEventStreamCreate(NULL, + &fsevents_callback, + &callbackInfo, + pathsToWatch, + kFSEventStreamEventIdSinceNow, + latency, + kFSEventStreamCreateFlagNoDefer + ); + + FSEventStreamScheduleWithRunLoop( (FSEventStreamRef)m_WatcherStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + CFRelease(pathsToWatch ); + CFRelease( mypath ); + + FSEventStreamStart( (FSEventStreamRef)m_WatcherStream ); + + char szFullPath[MAX_PATH]; + Q_MakeAbsolutePath( szFullPath, sizeof(szFullPath), pchDir ); + m_BaseDir = szFullPath; + + struct timeval tv; + gettimeofday( &tv, NULL ); + TIMEVAL_TO_TIMESPEC( &tv, &m_modTime ); + +#else + Assert( !"Impl me" ); +#endif +} + + +#ifdef WIN32 +//----------------------------------------------------------------------------- +// Purpose: used by callback functions to push a file onto the list +//----------------------------------------------------------------------------- +void CDirWatcher::PostDirWatch() +{ + memset( m_pOverlapped, 0, sizeof(DirWatcherOverlapped) ); + DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped; + pDirWatcherOverlapped->m_pDirWatcher = this; + + DWORD dwBytes; + ::ReadDirectoryChangesW( m_hFile, m_pFileInfo, k_cubDirWatchBufferSize, TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytes, (OVERLAPPED *)m_pOverlapped, &CDirWatcherFriend::DirWatchCallback ); +} +#endif + + +//----------------------------------------------------------------------------- +// Purpose: used by callback functions to push a file onto the list +//----------------------------------------------------------------------------- +void CDirWatcher::AddFileToChangeList( const char *pchFile ) +{ + // make sure it isn't already in the list + FOR_EACH_LL( m_listChangedFiles, i ) + { + if ( !Q_stricmp( m_listChangedFiles[i], pchFile ) ) + return; + } + + m_listChangedFiles.AddToTail( pchFile ); +} + + +//----------------------------------------------------------------------------- +// Purpose: retrieve any changes +//----------------------------------------------------------------------------- +bool CDirWatcher::GetChangedFile( CUtlString *psFile ) +{ +#ifdef WIN32 + // this will trigger any pending directory reads + // this does get hit other places in the code; so the callback can happen at any time + ::SleepEx( 0, TRUE ); +#endif + + if ( !m_listChangedFiles.Count() ) + return false; + + *psFile = m_listChangedFiles[m_listChangedFiles.Head()]; + m_listChangedFiles.Remove( m_listChangedFiles.Head() ); + return true; +} + + + +#ifdef DBGFLAG_VALIDATE +void CDirWatcher::Validate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + + validator.ClaimMemory( m_pOverlapped ); + validator.ClaimMemory( m_pFileInfo ); + ValidateObj( m_listChangedFiles ); + FOR_EACH_LL( m_listChangedFiles, i ) + { + ValidateObj( m_listChangedFiles[i] ); + } +} +#endif + +#endif // _PS3 || _X360 \ No newline at end of file diff --git a/tier1/generichash.cpp b/tier1/generichash.cpp new file mode 100644 index 0000000..c5d3d38 --- /dev/null +++ b/tier1/generichash.cpp @@ -0,0 +1,437 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Variant Pearson Hash general purpose hashing algorithm described +// by Cargill in C++ Report 1994. Generates a 16-bit result. +// +//============================================================================= + +#include +#include "tier0/basetypes.h" +#include "tier0/platform.h" +#include "generichash.h" +#include +#include "tier0/dbg.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// +// Table of randomly shuffled values from 0-255 generated by: +// +//----------------------------------------------------------------------------- +/* +void MakeRandomValues() +{ + int i, j, r; + unsigned t; + srand( 0xdeadbeef ); + + for ( i = 0; i < 256; i++ ) + { + g_nRandomValues[i] = (unsigned )i; + } + + for (j = 0; j < 8; j++) + { + for (i = 0; i < 256; i++) + { + r = rand() & 0xff; + t = g_nRandomValues[i]; + g_nRandomValues[i] = g_nRandomValues[r]; + g_nRandomValues[r] = t; + } + } + + printf("static unsigned g_nRandomValues[256] =\n{\n"); + + for (i = 0; i < 256; i += 16) + { + printf("\t"); + for (j = 0; j < 16; j++) + printf(" %3d,", g_nRandomValues[i+j]); + printf("\n"); + } + printf("};\n"); +} +*/ + +static unsigned g_nRandomValues[256] = +{ + 238, 164, 191, 168, 115, 16, 142, 11, 213, 214, 57, 151, 248, 252, 26, 198, + 13, 105, 102, 25, 43, 42, 227, 107, 210, 251, 86, 66, 83, 193, 126, 108, + 131, 3, 64, 186, 192, 81, 37, 158, 39, 244, 14, 254, 75, 30, 2, 88, + 172, 176, 255, 69, 0, 45, 116, 139, 23, 65, 183, 148, 33, 46, 203, 20, + 143, 205, 60, 197, 118, 9, 171, 51, 233, 135, 220, 49, 71, 184, 82, 109, + 36, 161, 169, 150, 63, 96, 173, 125, 113, 67, 224, 78, 232, 215, 35, 219, + 79, 181, 41, 229, 149, 153, 111, 217, 21, 72, 120, 163, 133, 40, 122, 140, + 208, 231, 211, 200, 160, 182, 104, 110, 178, 237, 15, 101, 27, 50, 24, 189, + 177, 130, 187, 92, 253, 136, 100, 212, 19, 174, 70, 22, 170, 206, 162, 74, + 247, 5, 47, 32, 179, 117, 132, 195, 124, 123, 245, 128, 236, 223, 12, 84, + 54, 218, 146, 228, 157, 94, 106, 31, 17, 29, 194, 34, 56, 134, 239, 246, + 241, 216, 127, 98, 7, 204, 154, 152, 209, 188, 48, 61, 87, 97, 225, 85, + 90, 167, 155, 112, 145, 114, 141, 93, 250, 4, 201, 156, 38, 89, 226, 196, + 1, 235, 44, 180, 159, 121, 119, 166, 190, 144, 10, 91, 76, 230, 221, 80, + 207, 55, 58, 53, 175, 8, 6, 52, 68, 242, 18, 222, 103, 249, 147, 129, + 138, 243, 28, 185, 62, 59, 240, 202, 234, 99, 77, 73, 199, 137, 95, 165, +}; + +//----------------------------------------------------------------------------- +// String +//----------------------------------------------------------------------------- +unsigned FASTCALL HashString( const char *pszKey ) +{ + const uint8 *k = (const uint8 *)pszKey; + unsigned even = 0, + odd = 0, + n; + + while ((n = *k++) != 0) + { + even = g_nRandomValues[odd ^ n]; + if ((n = *k++) != 0) + odd = g_nRandomValues[even ^ n]; + else + break; + } + + return (even << 8) | odd ; +} + + +//----------------------------------------------------------------------------- +// Case-insensitive string +//----------------------------------------------------------------------------- +unsigned FASTCALL HashStringCaseless( const char *pszKey ) +{ + const uint8 *k = (const uint8 *) pszKey; + unsigned even = 0, + odd = 0, + n; + + while ((n = toupper(*k++)) != 0) + { + even = g_nRandomValues[odd ^ n]; + if ((n = toupper(*k++)) != 0) + odd = g_nRandomValues[even ^ n]; + else + break; + } + + return (even << 8) | odd; +} + +//----------------------------------------------------------------------------- +// 32 bit conventional case-insensitive string +//----------------------------------------------------------------------------- +unsigned FASTCALL HashStringCaselessConventional( const char *pszKey ) +{ + unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add + + for( ; *pszKey ; pszKey++ ) + { + hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey); + } + + return hash; +} + +//----------------------------------------------------------------------------- +// int hash +//----------------------------------------------------------------------------- +unsigned FASTCALL HashInt( const int n ) +{ + unsigned even, odd; + even = g_nRandomValues[n & 0xff]; + odd = g_nRandomValues[((n >> 8) & 0xff)]; + + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + return (even << 8) | odd; +} + +//----------------------------------------------------------------------------- +// 4-byte hash +//----------------------------------------------------------------------------- +unsigned FASTCALL Hash4( const void *pKey ) +{ + const uint32 * p = (const uint32 *) pKey; + unsigned even, + odd, + n; + n = *p; + even = g_nRandomValues[n & 0xff]; + odd = g_nRandomValues[((n >> 8) & 0xff)]; + + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + return (even << 8) | odd; +} + + +//----------------------------------------------------------------------------- +// 8-byte hash +//----------------------------------------------------------------------------- +unsigned FASTCALL Hash8( const void *pKey ) +{ + const uint32 * p = (const uint32 *) pKey; + unsigned even, + odd, + n; + n = *p; + even = g_nRandomValues[n & 0xff]; + odd = g_nRandomValues[((n >> 8) & 0xff)]; + + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + n = *(p+1); + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + return (even << 8) | odd; +} + + +//----------------------------------------------------------------------------- +// 12-byte hash +//----------------------------------------------------------------------------- +unsigned FASTCALL Hash12( const void *pKey ) +{ + const uint32 * p = (const uint32 *) pKey; + unsigned even, + odd, + n; + n = *p; + even = g_nRandomValues[n & 0xff]; + odd = g_nRandomValues[((n >> 8) & 0xff)]; + + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + n = *(p+1); + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + n = *(p+2); + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + return (even << 8) | odd; +} + + +//----------------------------------------------------------------------------- +// 16-byte hash +//----------------------------------------------------------------------------- +unsigned FASTCALL Hash16( const void *pKey ) +{ + const uint32 * p = (const uint32 *) pKey; + unsigned even, + odd, + n; + n = *p; + even = g_nRandomValues[n & 0xff]; + odd = g_nRandomValues[((n >> 8) & 0xff)]; + + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + n = *(p+1); + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + n = *(p+2); + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + n = *(p+3); + even = g_nRandomValues[odd ^ (n >> 24)]; + odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)]; + even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)]; + odd = g_nRandomValues[even ^ (n & 0xff)]; + + return (even << 8) | odd; +} + + +//----------------------------------------------------------------------------- +// Arbitrary fixed length hash +//----------------------------------------------------------------------------- +unsigned FASTCALL HashBlock( const void *pKey, unsigned size ) +{ + const uint8 * k = (const uint8 *) pKey; + unsigned even = 0, + odd = 0, + n; + + while (size) + { + --size; + n = *k++; + even = g_nRandomValues[odd ^ n]; + if (size) + { + --size; + n = *k++; + odd = g_nRandomValues[even ^ n]; + } + else + break; + } + + return (even << 8) | odd; +} + + +//----------------------------------------------------------------------------- +// Murmur hash +//----------------------------------------------------------------------------- +uint32 MurmurHash2( const void * key, int len, uint32 seed ) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + const uint32 m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + + uint32 h = seed ^ len; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + uint32 k = LittleDWord( *(uint32 *)data ); + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) )? c + 32 : c ) ) +uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed ) +{ + int nLen = ( int )strlen( pString ); + char *p = ( char * ) stackalloc( nLen + 1 ); + for( int i = 0; i < nLen ; i++ ) + { + p[i] = TOLOWERU( pString[i] ); + } + return MurmurHash2( p, nLen, nSeed ); +} + + +//----------------------------------------------------------------------------- +// Murmur hash, 64 bit- endian neutral +//----------------------------------------------------------------------------- +uint64 MurmurHash64( const void * key, int len, uint32 seed ) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + const uint32 m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + + uint32 h1 = seed ^ len; + uint32 h2 = 0; + + // Mix 4 bytes at a time into the hash + + const uint32 * data = (const uint32 *)key; + while ( len >= 8 ) + { + uint32 k1 = LittleDWord( *data++ ); + k1 *= m; k1 ^= k1 >> r; k1 *= m; + h1 *= m; h1 ^= k1; + len -= 4; + + uint32 k2 = LittleDWord( *data++ ); + k2 *= m; k2 ^= k2 >> r; k2 *= m; + h2 *= m; h2 ^= k2; + len -= 4; + } + + if(len >= 4) + { + uint32 k1 = LittleDWord( *data++ ); + k1 *= m; k1 ^= k1 >> r; k1 *= m; + h1 *= m; h1 ^= k1; + len -= 4; + } + + // Handle the last few bytes of the input array + switch(len) + { + case 3: h2 ^= ((uint8*)data)[2] << 16; + case 2: h2 ^= ((uint8*)data)[1] << 8; + case 1: h2 ^= ((uint8*)data)[0]; + h2 *= m; + }; + + h1 ^= h2 >> 18; h1 *= m; + h2 ^= h1 >> 22; h2 *= m; + h1 ^= h2 >> 17; h1 *= m; + h2 ^= h1 >> 19; h2 *= m; + + uint64 h = h1; + + h = (h << 32) | h2; + + return h; +} + diff --git a/tier1/ilocalize.cpp b/tier1/ilocalize.cpp new file mode 100644 index 0000000..19d23a9 --- /dev/null +++ b/tier1/ilocalize.cpp @@ -0,0 +1,260 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// + +#if defined( _WIN32 ) && !defined( _X360 ) + #include +#elif defined( POSIX ) + #include +#endif + +#include "tier1/ilocalize.h" +#include "utlstring.h" + +#pragma warning( disable: 4018 ) // '<' : signed/unsigned mismatch + +//----------------------------------------------------------------------------- +// Purpose: converts an english string to unicode +//----------------------------------------------------------------------------- +int ILocalize::ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSizeInBytes) +{ +#ifdef POSIX + // Q_UTF8ToUnicode returns the number of bytes. This function is expected to return the number of chars. + return Q_UTF8ToUnicode(ansi, unicode, unicodeBufferSizeInBytes) / sizeof( wchar_t ); +#else + int chars = MultiByteToWideChar(CP_UTF8, 0, ansi, -1, unicode, unicodeBufferSizeInBytes / sizeof(wchar_t)); + unicode[(unicodeBufferSizeInBytes / sizeof(wchar_t)) - 1] = 0; + return chars; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: converts an unicode string to an english string +//----------------------------------------------------------------------------- +int ILocalize::ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize) +{ +#ifdef POSIX + return Q_UnicodeToUTF8(unicode, ansi, ansiBufferSize); +#else + int result = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL); + ansi[ansiBufferSize - 1] = 0; + return result; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: construct string helper +//----------------------------------------------------------------------------- +template < typename T > +void ConstructStringVArgsInternal_Impl(T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, va_list argList) +{ + static const int k_cMaxFormatStringArguments = 9; // We only look one character ahead and start at %s1 + Assert( numFormatParameters <= k_cMaxFormatStringArguments ); + + // Safety check + if ( unicodeOutput == NULL || unicodeBufferSizeInBytes < 1 ) + { + return; + } + + if ( !formatString || numFormatParameters > k_cMaxFormatStringArguments ) + { + unicodeOutput[0] = 0; + return; + } + + int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T); + const T *searchPos = formatString; + T *outputPos = unicodeOutput; + + T *argParams[k_cMaxFormatStringArguments]; + for ( int i = 0; i < numFormatParameters; i++ ) + { + argParams[i] = va_arg( argList, T* ); + } + + //assumes we can't have %s10 + //assume both are 0 terminated? + int formatLength = StringFuncs::Length( formatString ); + + while ( searchPos[0] != '\0' && unicodeBufferSize > 1 ) + { + if ( formatLength >= 3 && searchPos[0] == '%' && searchPos[1] == 's' ) + { + //this is an escape sequence - %s1, %s2 etc, up to %s9 + + int argindex = ( searchPos[2] ) - '0' - 1; // 0 for %s1, 1 for %s2, etc. + + if ( argindex < 0 || argindex > k_cMaxFormatStringArguments ) + { + Warning( "Bad format string in CLocalizeStringTable::ConstructString\n" ); + *outputPos = '\0'; + return; + } + + if ( argindex < numFormatParameters ) + { + T const *param = argParams[argindex]; + + if ( param == NULL ) + param = StringFuncs::NullDebugString(); + + int paramSize = StringFuncs::Length(param); + if (paramSize >= unicodeBufferSize) + { + paramSize = unicodeBufferSize - 1; + } + + memcpy(outputPos, param, paramSize * sizeof(T)); + + unicodeBufferSize -= paramSize; + outputPos += paramSize; + + searchPos += 3; + formatLength -= 3; + } + else + { + AssertMsg( argindex < numFormatParameters, "ConstructStringVArgsInternal_Impl() - Found a %%s# escape sequence whose index was more than the number of args." ); + + //copy it over, char by char + *outputPos = *searchPos; + + outputPos++; + unicodeBufferSize--; + + searchPos++; + formatLength--; + } + } + else + { + //copy it over, char by char + *outputPos = *searchPos; + + outputPos++; + unicodeBufferSize--; + + searchPos++; + formatLength--; + } + } + + // ensure null termination + Assert( outputPos - unicodeOutput < unicodeBufferSizeInBytes/sizeof(T) ); + *outputPos = L'\0'; +} + +void ILocalize::ConstructStringVArgsInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, int numFormatParameters, va_list argList) +{ + ConstructStringVArgsInternal_Impl( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList ); +} + +void ILocalize::ConstructStringVArgsInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, int numFormatParameters, va_list argList) +{ + ConstructStringVArgsInternal_Impl( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList ); +} + +//----------------------------------------------------------------------------- +// Purpose: construct string helper +//----------------------------------------------------------------------------- +template < typename T > +const T *GetTypedKeyValuesString( KeyValues *pKeyValues, const char *pKeyName ); + +template < > +const char *GetTypedKeyValuesString( KeyValues *pKeyValues, const char *pKeyName ) +{ + return pKeyValues->GetString( pKeyName, "[unknown]" ); +} + +template < > +const wchar_t *GetTypedKeyValuesString( KeyValues *pKeyValues, const char *pKeyName ) +{ + return pKeyValues->GetWString( pKeyName, L"[unknown]" ); +} + +template < typename T > +void ConstructStringKeyValuesInternal_Impl( T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, KeyValues *localizationVariables ) +{ + T *outputPos = unicodeOutput; + + //assumes we can't have %s10 + //assume both are 0 terminated? + int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T); + + while ( *formatString != '\0' && unicodeBufferSize > 1 ) + { + bool shouldAdvance = true; + + if ( *formatString == '%' ) + { + // this is an escape sequence that specifies a variable name + if ( formatString[1] == 's' && formatString[2] >= '0' && formatString[2] <= '9' ) + { + // old style escape sequence, ignore + } + else if ( formatString[1] == '%' ) + { + // just a '%' char, just write the second one + formatString++; + } + else if ( localizationVariables ) + { + // get out the variable name + const T *varStart = formatString + 1; + const T *varEnd = StringFuncs::FindChar( varStart, '%' ); + + if ( varEnd && *varEnd == '%' ) + { + shouldAdvance = false; + + // assume variable names must be ascii, do a quick convert + char variableName[32]; + char *vset = variableName; + for ( const T *pws = varStart; pws < varEnd && (vset < variableName + sizeof(variableName) - 1); ++pws, ++vset ) + { + *vset = (char)*pws; + } + *vset = 0; + + // look up the variable name + const T *value = GetTypedKeyValuesString( localizationVariables, variableName ); + + int paramSize = StringFuncs::Length( value ); + if (paramSize >= unicodeBufferSize) + { + paramSize = MAX( 0, unicodeBufferSize - 1 ); + } + + StringFuncs::Copy( outputPos, value, paramSize ); + + unicodeBufferSize -= paramSize; + outputPos += paramSize; + formatString = varEnd + 1; + } + } + } + + if (shouldAdvance) + { + //copy it over, char by char + *outputPos = *formatString; + + outputPos++; + unicodeBufferSize--; + + formatString++; + } + } + + // ensure null termination + *outputPos = '\0'; +} + +void ILocalize::ConstructStringKeyValuesInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, KeyValues *localizationVariables) +{ + ConstructStringKeyValuesInternal_Impl( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables ); +} + +void ILocalize::ConstructStringKeyValuesInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, KeyValues *localizationVariables) +{ + ConstructStringKeyValuesInternal_Impl( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables ); +} diff --git a/tier1/interface.cpp b/tier1/interface.cpp new file mode 100644 index 0000000..031a49a --- /dev/null +++ b/tier1/interface.cpp @@ -0,0 +1,567 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// +#if defined( _WIN32 ) && !defined( _X360 ) +#include +#endif + +#if !defined( DONT_PROTECT_FILEIO_FUNCTIONS ) +#define DONT_PROTECT_FILEIO_FUNCTIONS // for protected_things.h +#endif + +#if defined( PROTECTED_THINGS_ENABLE ) +#undef PROTECTED_THINGS_ENABLE // from protected_things.h +#endif + +#include +#include "interface.h" +#include "basetypes.h" +#include "tier0/dbg.h" +#include +#include +#include "tier1/strtools.h" +#include "tier0/icommandline.h" +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#ifdef _WIN32 +#include // getcwd +#elif POSIX +#include +#include +#define _getcwd getcwd +#endif +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// ------------------------------------------------------------------------------------ // +// InterfaceReg. +// ------------------------------------------------------------------------------------ // +InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; + +InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : + m_pName(pName) +{ + m_CreateFn = fn; + m_pNext = s_pInterfaceRegs; + s_pInterfaceRegs = this; +} + +// ------------------------------------------------------------------------------------ // +// CreateInterface. +// This is the primary exported function by a dll, referenced by name via dynamic binding +// that exposes an opqaue function pointer to the interface. +// +// We have the Internal variant so Sys_GetFactoryThis() returns the correct internal +// symbol under GCC/Linux/Mac as CreateInterface is DLL_EXPORT so its global so the loaders +// on those OS's pick exactly 1 of the CreateInterface symbols to be the one that is process wide and +// all Sys_GetFactoryThis() calls find that one, which doesn't work. Using the internal walkthrough here +// makes sure Sys_GetFactoryThis() has the dll specific symbol and GetProcAddress() returns the module specific +// function for CreateInterface again getting the dll specific symbol we need. +// ------------------------------------------------------------------------------------ // +void* CreateInterfaceInternal( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for (pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if (strcmp(pCur->m_pName, pName) == 0) + { + if (pReturnCode) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if (pReturnCode) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} + +void* CreateInterface( const char *pName, int *pReturnCode ) +{ + return CreateInterfaceInternal( pName, pReturnCode ); +} + + + +#ifdef POSIX +// Linux doesn't have this function so this emulates its functionality +void *GetModuleHandle(const char *name) +{ + void *handle; + + if( name == NULL ) + { + // hmm, how can this be handled under linux.... + // is it even needed? + return NULL; + } + + if( (handle=dlopen(name, RTLD_NOW))==NULL) + { + printf("DLOPEN Error:%s\n",dlerror()); + // couldn't open this file + return NULL; + } + + // read "man dlopen" for details + // in short dlopen() inc a ref count + // so dec the ref count by performing the close + dlclose(handle); + return handle; +} +#endif + +#if defined( _WIN32 ) && !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : pModuleName - module name +// *pName - proc name +//----------------------------------------------------------------------------- +static void *Sys_GetProcAddress( const char *pModuleName, const char *pName ) +{ + HMODULE hModule = (HMODULE)GetModuleHandle( pModuleName ); +#ifdef WIN32 + return (void *)GetProcAddress( hModule, pName ); +#else + return (void *)dlsym( (void *)hModule, pName ); +#endif +} + +#if !defined(LINUX) +static void *Sys_GetProcAddress( HMODULE hModule, const char *pName ) +{ +#ifdef WIN32 + return (void *)GetProcAddress( hModule, pName ); +#else + return (void *)dlsym( (void *)hModule, pName ); +#endif +} +#endif + +bool Sys_IsDebuggerPresent() +{ + return Plat_IsInDebugSession(); +} + +struct ThreadedLoadLibaryContext_t +{ + const char *m_pLibraryName; + HMODULE m_hLibrary; +}; + +#ifdef _WIN32 + +// wraps LoadLibraryEx() since 360 doesn't support that +static HMODULE InternalLoadLibrary( const char *pName, Sys_Flags flags ) +{ +#if defined(_X360) + return LoadLibrary( pName ); +#else + if ( flags & SYS_NOLOAD ) + return GetModuleHandle( pName ); + else + return LoadLibraryEx( pName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); +#endif +} +unsigned ThreadedLoadLibraryFunc( void *pParam ) +{ + ThreadedLoadLibaryContext_t *pContext = (ThreadedLoadLibaryContext_t*)pParam; + pContext->m_hLibrary = InternalLoadLibrary( pContext->m_pLibraryName, SYS_NOFLAGS ); + return 0; +} + +#endif // _WIN32 + +HMODULE Sys_LoadLibrary( const char *pLibraryName, Sys_Flags flags ) +{ + char str[ 1024 ]; + // Note: DLL_EXT_STRING can be "_srv.so" or "_360.dll". So be careful + // when using the V_*Extension* routines... + const char *pDllStringExtension = V_GetFileExtension( DLL_EXT_STRING ); + const char *pModuleExtension = pDllStringExtension ? ( pDllStringExtension - 1 ) : DLL_EXT_STRING; + + Q_strncpy( str, pLibraryName, sizeof(str) ); + + if ( IsX360() ) + { + // old, probably busted, behavior for xbox + if ( !Q_stristr( str, pModuleExtension ) ) + { + V_SetExtension( str, pModuleExtension, sizeof(str) ); + } + } + else + { + // always force the final extension to be .dll + V_SetExtension( str, pModuleExtension, sizeof(str) ); + } + + Q_FixSlashes( str ); + +#ifdef _WIN32 + ThreadedLoadLibraryFunc_t threadFunc = GetThreadedLoadLibraryFunc(); + if ( !threadFunc ) + return InternalLoadLibrary( str, flags ); + + // We shouldn't be passing noload while threaded. + Assert( !( flags & SYS_NOLOAD ) ); + + ThreadedLoadLibaryContext_t context; + context.m_pLibraryName = str; + context.m_hLibrary = 0; + + ThreadHandle_t h = CreateSimpleThread( ThreadedLoadLibraryFunc, &context ); + +#ifdef _X360 + ThreadSetAffinity( h, XBOX_PROCESSOR_3 ); +#endif + + unsigned int nTimeout = 0; + while( ThreadWaitForObject( h, true, nTimeout ) == TW_TIMEOUT ) + { + nTimeout = threadFunc(); + } + + ReleaseThreadHandle( h ); + return context.m_hLibrary; + +#elif POSIX + int dlopen_mode = RTLD_NOW; + + if ( flags & SYS_NOLOAD ) + dlopen_mode |= RTLD_NOLOAD; + + HMODULE ret = ( HMODULE )dlopen( str, dlopen_mode ); + if ( !ret && !( flags & SYS_NOLOAD ) ) + { + const char *pError = dlerror(); + if ( pError && ( strstr( pError, "No such file" ) == 0 ) && ( strstr( pError, "image not found" ) == 0 ) ) + { + Msg( " failed to dlopen %s error=%s\n", str, pError ); + } + } + + return ret; +#endif +} +static bool s_bRunningWithDebugModules = false; + +//----------------------------------------------------------------------------- +// Purpose: Loads a DLL/component from disk and returns a handle to it +// Input : *pModuleName - filename of the component +// Output : opaque handle to the module (hides system dependency) +//----------------------------------------------------------------------------- +CSysModule *Sys_LoadModule( const char *pModuleName, Sys_Flags flags /* = SYS_NOFLAGS (0) */ ) +{ + // If using the Steam filesystem, either the DLL must be a minimum footprint + // file in the depot (MFP) or a filesystem GetLocalCopy() call must be made + // prior to the call to this routine. + char szCwd[1024]; + HMODULE hDLL = NULL; + + if ( !Q_IsAbsolutePath( pModuleName ) ) + { + // full path wasn't passed in, using the current working dir + _getcwd( szCwd, sizeof( szCwd ) ); + if ( IsX360() ) + { + int i = CommandLine()->FindParm( "-basedir" ); + if ( i ) + { + V_strcpy_safe( szCwd, CommandLine()->GetParm( i + 1 ) ); + } + } + if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' ) + { + szCwd[strlen(szCwd) - 1] = 0; + } + + char szAbsoluteModuleName[1024]; + size_t cCwd = strlen( szCwd ); + if ( strstr( pModuleName, "bin/") == pModuleName || ( szCwd[ cCwd - 1 ] == 'n' && szCwd[ cCwd - 2 ] == 'i' && szCwd[ cCwd - 3 ] == 'b' ) ) + { + // don't make bin/bin path + Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName ); + } + else + { + Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName ); + } + hDLL = Sys_LoadLibrary( szAbsoluteModuleName, flags ); + } + + if ( !hDLL ) + { + // full path failed, let LoadLibrary() try to search the PATH now + hDLL = Sys_LoadLibrary( pModuleName, flags ); +#if defined( _DEBUG ) + if ( !hDLL ) + { +// So you can see what the error is in the debugger... +#if defined( _WIN32 ) && !defined( _X360 ) + char *lpMsgBuf; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + + LocalFree( (HLOCAL)lpMsgBuf ); +#elif defined( _X360 ) + DWORD error = GetLastError(); + Msg( "Error(%d) - Failed to load %s:\n", error, pModuleName ); +#else + Msg( "Failed to load %s: %s\n", pModuleName, dlerror() ); +#endif // _WIN32 + } +#endif // DEBUG + } + +#if !defined(LINUX) + // If running in the debugger, assume debug binaries are okay, otherwise they must run with -allowdebug + if ( Sys_GetProcAddress( hDLL, "BuiltDebug" ) ) + { + if ( !IsX360() && hDLL && + !CommandLine()->FindParm( "-allowdebug" ) && + !Sys_IsDebuggerPresent() ) + { + Error( "Module %s is a debug build\n", pModuleName ); + } + + DevWarning( "Module %s is a debug build\n", pModuleName ); + + if ( !s_bRunningWithDebugModules ) + { + s_bRunningWithDebugModules = true; + +#if 0 //def IS_WINDOWS_PC + char chMemoryName[ MAX_PATH ]; + DebugKernelMemoryObjectName( chMemoryName ); + + (void) CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, chMemoryName ); + // Created a shared memory kernel object specific to process id + // Existence of this object indicates that we have debug modules loaded +#endif + } + } +#endif + + return reinterpret_cast(hDLL); +} + +//----------------------------------------------------------------------------- +// Purpose: Determine if any debug modules were loaded +//----------------------------------------------------------------------------- +bool Sys_RunningWithDebugModules() +{ + if ( !s_bRunningWithDebugModules ) + { +#if 0 //def IS_WINDOWS_PC + char chMemoryName[ MAX_PATH ]; + DebugKernelMemoryObjectName( chMemoryName ); + + HANDLE hObject = OpenFileMapping( FILE_MAP_READ, FALSE, chMemoryName ); + if ( hObject && hObject != INVALID_HANDLE_VALUE ) + { + CloseHandle( hObject ); + s_bRunningWithDebugModules = true; + } +#endif + } + return s_bRunningWithDebugModules; +} + + +//----------------------------------------------------------------------------- +// Purpose: Unloads a DLL/component from +// Input : *pModuleName - filename of the component +// Output : opaque handle to the module (hides system dependency) +//----------------------------------------------------------------------------- +void Sys_UnloadModule( CSysModule *pModule ) +{ + if ( !pModule ) + return; + + HMODULE hDLL = reinterpret_cast(pModule); + +#ifdef _WIN32 + FreeLibrary( hDLL ); +#elif defined(POSIX) + dlclose((void *)hDLL); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : module - windows HMODULE from Sys_LoadModule() +// *pName - proc name +// Output : factory for this module +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ) +{ + if ( !pModule ) + return NULL; + + HMODULE hDLL = reinterpret_cast(pModule); +#ifdef _WIN32 + return reinterpret_cast(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); +#elif defined(POSIX) + // Linux gives this error: + //../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory + //(CSysModule *)) (const char *, int *)': + //../public/interface.cpp:154: ISO C++ forbids casting between + //pointer-to-function and pointer-to-object + // + // so lets get around it :) + return (CreateInterfaceFn)(GetProcAddress( (void *)hDLL, CREATEINTERFACE_PROCNAME )); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of this module +// Output : interface_instance_t +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactoryThis( void ) +{ + return &CreateInterfaceInternal; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of the named module +// Input : *pModuleName - name of the module +// Output : interface_instance_t - instance of that module +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactory( const char *pModuleName ) +{ +#ifdef _WIN32 + return static_cast( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); +#elif defined(POSIX) + // see Sys_GetFactory( CSysModule *pModule ) for an explanation + return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: get the interface for the specified module and version +// Input : +// Output : +//----------------------------------------------------------------------------- +bool Sys_LoadInterface( + const char *pModuleName, + const char *pInterfaceVersionName, + CSysModule **pOutModule, + void **pOutInterface ) +{ + CSysModule *pMod = Sys_LoadModule( pModuleName ); + if ( !pMod ) + return false; + + CreateInterfaceFn fn = Sys_GetFactory( pMod ); + if ( !fn ) + { + Sys_UnloadModule( pMod ); + return false; + } + + *pOutInterface = fn( pInterfaceVersionName, NULL ); + if ( !( *pOutInterface ) ) + { + Sys_UnloadModule( pMod ); + return false; + } + + if ( pOutModule ) + *pOutModule = pMod; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name. +// +// When the singleton goes out of scope (.dll unload if at module scope), +// then it'll call Sys_UnloadModule on the module so that the refcount is decremented +// and the .dll actually can unload from memory. +//----------------------------------------------------------------------------- +CDllDemandLoader::CDllDemandLoader( char const *pchModuleName ) : + m_pchModuleName( pchModuleName ), + m_hModule( 0 ), + m_bLoadAttempted( false ) +{ +} + +CDllDemandLoader::~CDllDemandLoader() +{ + Unload(); +} + +CreateInterfaceFn CDllDemandLoader::GetFactory() +{ + if ( !m_hModule && !m_bLoadAttempted ) + { + m_bLoadAttempted = true; + m_hModule = Sys_LoadModule( m_pchModuleName ); + } + + if ( !m_hModule ) + { + return NULL; + } + + return Sys_GetFactory( m_hModule ); +} + +void CDllDemandLoader::Unload() +{ + if ( m_hModule ) + { + Sys_UnloadModule( m_hModule ); + m_hModule = 0; + } +} + +#if defined( STAGING_ONLY ) && defined( _WIN32 ) + +typedef USHORT( WINAPI RtlCaptureStackBackTrace_FUNC )( + ULONG frames_to_skip, + ULONG frames_to_capture, + PVOID *backtrace, + PULONG backtrace_hash ); + +extern "C" int backtrace( void **buffer, int size ) +{ + HMODULE hNTDll = GetModuleHandleA( "ntdll.dll" ); + static RtlCaptureStackBackTrace_FUNC * const pfnRtlCaptureStackBackTrace = + ( RtlCaptureStackBackTrace_FUNC * )GetProcAddress( hNTDll, "RtlCaptureStackBackTrace" ); + + if ( !pfnRtlCaptureStackBackTrace ) + return 0; + + return (int)pfnRtlCaptureStackBackTrace( 2, size, buffer, 0 ); +} + +#endif // STAGING_ONLY && _WIN32 + diff --git a/tier1/kvpacker.cpp b/tier1/kvpacker.cpp new file mode 100644 index 0000000..53f7672 --- /dev/null +++ b/tier1/kvpacker.cpp @@ -0,0 +1,285 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains a branch-neutral binary packer for KeyValues trees. +// +// $NoKeywords: $ +// +//=============================================================================// + +#include +#include "kvpacker.h" + +#include "tier0/dbg.h" +#include "utlbuffer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include + +#define KEYVALUES_TOKEN_SIZE 1024 + +// writes KeyValue as binary data to buffer +bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) +{ + if ( buffer.IsText() ) // must be a binary buffer + return false; + + if ( !buffer.IsValid() ) // must be valid, no overflows etc + return false; + + // Write subkeys: + + // loop through all our peers + for ( KeyValues *dat = pNode; dat != NULL; dat = dat->GetNextKey() ) + { + // write type + switch ( dat->GetDataType() ) + { + case KeyValues::TYPE_NONE: + { + buffer.PutUnsignedChar( PACKTYPE_NONE ); + break; + } + case KeyValues::TYPE_STRING: + { + buffer.PutUnsignedChar( PACKTYPE_STRING ); + break; + } + case KeyValues::TYPE_WSTRING: + { + buffer.PutUnsignedChar( PACKTYPE_WSTRING ); + break; + } + + case KeyValues::TYPE_INT: + { + buffer.PutUnsignedChar( PACKTYPE_INT ); + break; + } + + case KeyValues::TYPE_UINT64: + { + buffer.PutUnsignedChar( PACKTYPE_UINT64 ); + break; + } + + case KeyValues::TYPE_FLOAT: + { + buffer.PutUnsignedChar( PACKTYPE_FLOAT ); + break; + } + case KeyValues::TYPE_COLOR: + { + buffer.PutUnsignedChar( PACKTYPE_COLOR ); + break; + } + case KeyValues::TYPE_PTR: + { + buffer.PutUnsignedChar( PACKTYPE_PTR ); + break; + } + + default: + break; + } + + // write name + buffer.PutString( dat->GetName() ); + + // write value + switch ( dat->GetDataType() ) + { + case KeyValues::TYPE_NONE: + { + if( !WriteAsBinary( dat->GetFirstSubKey(), buffer ) ) + return false; + break; + } + case KeyValues::TYPE_STRING: + { + if (dat->GetString() && *(dat->GetString())) + { + buffer.PutString( dat->GetString() ); + } + else + { + buffer.PutString( "" ); + } + break; + } + case KeyValues::TYPE_WSTRING: + { + int nLength = dat->GetWString() ? Q_wcslen( dat->GetWString() ) : 0; + buffer.PutShort( nLength ); + for( int k = 0; k < nLength; ++ k ) + { + buffer.PutShort( ( unsigned short ) dat->GetWString()[k] ); + } + break; + } + + case KeyValues::TYPE_INT: + { + buffer.PutInt( dat->GetInt() ); + break; + } + + case KeyValues::TYPE_UINT64: + { + buffer.PutInt64( dat->GetUint64() ); + break; + } + + case KeyValues::TYPE_FLOAT: + { + buffer.PutFloat( dat->GetFloat() ); + break; + } + case KeyValues::TYPE_COLOR: + { + Color color = dat->GetColor(); + buffer.PutUnsignedChar( color[0] ); + buffer.PutUnsignedChar( color[1] ); + buffer.PutUnsignedChar( color[2] ); + buffer.PutUnsignedChar( color[3] ); + break; + } + case KeyValues::TYPE_PTR: + { + buffer.PutUnsignedInt( (int)dat->GetPtr() ); + break; + } + + default: + break; + } + } + + // write tail, marks end of peers + buffer.PutUnsignedChar( PACKTYPE_NULLMARKER ); + + return buffer.IsValid(); +} + +// read KeyValues from binary buffer, returns true if parsing was successful +bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) +{ + if ( buffer.IsText() ) // must be a binary buffer + return false; + + if ( !buffer.IsValid() ) // must be valid, no overflows etc + return false; + + pNode->Clear(); + + char token[KEYVALUES_TOKEN_SIZE]; + KeyValues *dat = pNode; + EPackType ePackType = (EPackType)buffer.GetUnsignedChar(); + + // loop through all our peers + while ( true ) + { + if ( ePackType == PACKTYPE_NULLMARKER ) + break; // no more peers + + buffer.GetString( token ); + token[KEYVALUES_TOKEN_SIZE-1] = 0; + + dat->SetName( token ); + + switch ( ePackType ) + { + case PACKTYPE_NONE: + { + KeyValues *pNewNode = new KeyValues(""); + dat->AddSubKey( pNewNode ); + if( !ReadAsBinary( pNewNode, buffer ) ) + return false; + break; + } + case PACKTYPE_STRING: + { + buffer.GetString( token ); + token[KEYVALUES_TOKEN_SIZE-1] = 0; + dat->SetStringValue( token ); + break; + } + case PACKTYPE_WSTRING: + { + int nLength = buffer.GetShort(); + if ( nLength >= 0 && nLength*sizeof( uint16 ) <= (uint)buffer.GetBytesRemaining() ) + { + if ( nLength > 0 ) + { + wchar_t *pTemp = (wchar_t *)malloc( sizeof( wchar_t ) * (1 + nLength) ); + + for ( int k = 0; k < nLength; ++k ) + { + pTemp[k] = buffer.GetShort(); // ugly, but preserving existing behavior + } + + pTemp[nLength] = 0; + dat->SetWString( NULL, pTemp ); + + free( pTemp ); + } + else + dat->SetWString( NULL, L"" ); + + } + break; + } + + case PACKTYPE_INT: + { + dat->SetInt( NULL, buffer.GetInt() ); + break; + } + + case PACKTYPE_UINT64: + { + dat->SetUint64( NULL, (uint64)buffer.GetInt64() ); + break; + } + + case PACKTYPE_FLOAT: + { + dat->SetFloat( NULL, buffer.GetFloat() ); + break; + } + case PACKTYPE_COLOR: + { + Color color( + buffer.GetUnsignedChar(), + buffer.GetUnsignedChar(), + buffer.GetUnsignedChar(), + buffer.GetUnsignedChar() ); + dat->SetColor( NULL, color ); + break; + } + case PACKTYPE_PTR: + { + dat->SetPtr( NULL, (void*)buffer.GetUnsignedInt() ); + break; + } + + default: + break; + } + + if ( !buffer.IsValid() ) // error occured + return false; + + ePackType = (EPackType)buffer.GetUnsignedChar(); + + if ( ePackType == PACKTYPE_NULLMARKER ) + break; + + // new peer follows + KeyValues *pNewPeer = new KeyValues(""); + dat->SetNextKey( pNewPeer ); + dat = pNewPeer; + } + + return buffer.IsValid(); +} + diff --git a/tier1/lzmaDecoder.cpp b/tier1/lzmaDecoder.cpp new file mode 100644 index 0000000..23e4301 --- /dev/null +++ b/tier1/lzmaDecoder.cpp @@ -0,0 +1,348 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// LZMA Codec interface for engine. +// +// LZMA SDK 9.38 beta +// 2015-01-03 : Igor Pavlov : Public domain +// http://www.7-zip.org/ +// +//========================================================================// + +#define _LZMADECODER_CPP + +#include "tier0/platform.h" +#include "tier0/basetypes.h" +#include "tier0/dbg.h" + +#include "../utils/lzma/C/7zTypes.h" +#include "../utils/lzma/C/LzmaEnc.h" +#include "../utils/lzma/C/LzmaDec.h" + +// Ugly define to let us forward declare the anonymous-struct-typedef that is CLzmaDec in the header. +#define CLzmaDec_t CLzmaDec +#include "tier1/lzmaDecoder.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Allocator to pass to LZMA functions +static void *SzAlloc(ISzAllocPtr p, size_t size) { return malloc(size); } +static void SzFree(ISzAllocPtr p, void *address) { free(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +//----------------------------------------------------------------------------- +// Returns true if buffer is compressed. +//----------------------------------------------------------------------------- +/* static */ +bool CLZMA::IsCompressed( unsigned char *pInput ) +{ + lzma_header_t *pHeader = (lzma_header_t *)pInput; + if ( pHeader && pHeader->id == LZMA_ID ) + { + return true; + } + + // unrecognized + return false; +} + +//----------------------------------------------------------------------------- +// Returns uncompressed size of compressed input buffer. Used for allocating output +// buffer for decompression. Returns 0 if input buffer is not compressed. +//----------------------------------------------------------------------------- +/* static */ +unsigned int CLZMA::GetActualSize( unsigned char *pInput ) +{ + lzma_header_t *pHeader = (lzma_header_t *)pInput; + if ( pHeader && pHeader->id == LZMA_ID ) + { + return LittleLong( pHeader->actualSize ); + } + + // unrecognized + return 0; +} + +//----------------------------------------------------------------------------- +// Uncompress a buffer, Returns the uncompressed size. Caller must provide an +// adequate sized output buffer or memory corruption will occur. +//----------------------------------------------------------------------------- +/* static */ +unsigned int CLZMA::Uncompress( unsigned char *pInput, unsigned char *pOutput ) +{ + lzma_header_t *pHeader = (lzma_header_t *)pInput; + if ( pHeader->id != LZMA_ID ) + { + // not ours + return false; + } + + CLzmaDec state; + + LzmaDec_Construct(&state); + + if ( LzmaDec_Allocate(&state, pHeader->properties, LZMA_PROPS_SIZE, &g_Alloc) != SZ_OK ) + { + Assert( false ); + return 0; + } + + // These are in/out variables + SizeT outProcessed = pHeader->actualSize; + SizeT inProcessed = pHeader->lzmaSize; + ELzmaStatus status; + SRes result = LzmaDecode( (Byte *)pOutput, &outProcessed, (Byte *)(pInput + sizeof( lzma_header_t ) ), + &inProcessed, (Byte *)pHeader->properties, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc ); + + + LzmaDec_Free(&state, &g_Alloc); + + if ( result != SZ_OK || pHeader->actualSize != outProcessed ) + { + Warning( "LZMA Decompression failed (%i)\n", result ); + return 0; + } + + return outProcessed; +} + +CLZMAStream::CLZMAStream() + : m_pDecoderState( NULL ), + m_nActualSize( 0 ), + m_nActualBytesRead ( 0 ), + m_nCompressedSize( 0 ), + m_nCompressedBytesRead ( 0 ), + m_bParsedHeader( false ), + m_bZIPStyleHeader( false ) +{} + +CLZMAStream::~CLZMAStream() +{ + FreeDecoderState(); +} + +void CLZMAStream::FreeDecoderState() +{ + if ( m_pDecoderState ) + { + LzmaDec_Free( m_pDecoderState, &g_Alloc ); + m_pDecoderState = NULL; + } +} + +bool CLZMAStream::CreateDecoderState( const unsigned char *pProperties ) +{ + if ( m_pDecoderState ) + { + Assert( !m_pDecoderState ); + FreeDecoderState(); + } + + m_pDecoderState = new CLzmaDec; + + LzmaDec_Construct( m_pDecoderState ); + if ( LzmaDec_Allocate( m_pDecoderState, pProperties, LZMA_PROPS_SIZE, &g_Alloc) != SZ_OK ) + { + AssertMsg( false, "Failed to allocate lzma decoder state" ); + m_pDecoderState = NULL; + return false; + } + + LzmaDec_Init( m_pDecoderState ); + + return true; +} + +// Attempt to read up to nMaxInputBytes from the compressed stream, writing up to nMaxOutputBytes to pOutput. +// Returns false if read stops due to an error. +bool CLZMAStream::Read( unsigned char *pInput, unsigned int nMaxInputBytes, + unsigned char *pOutput, unsigned int nMaxOutputBytes, + /* out */ unsigned int &nCompressedBytesRead, + /* out */ unsigned int &nOutputBytesWritten ) +{ + nCompressedBytesRead = 0; + nOutputBytesWritten = 0; + bool bStartedWithHeader = m_bParsedHeader; + + // Check for initial chunk of data + if ( !m_bParsedHeader ) + { + unsigned int nBytesConsumed = 0; + eHeaderParse parseResult = TryParseHeader( pInput, nMaxInputBytes, nBytesConsumed ); + + if ( parseResult == eHeaderParse_NeedMoreBytes ) + { + // Not an error, just need more data to continue + return true; + } + else if ( parseResult != eHeaderParse_OK ) + { + Assert( parseResult == eHeaderParse_Fail ); + // Invalid header + return false; + } + + // Header consumed, fall through to continue read after it + nCompressedBytesRead += nBytesConsumed; + pInput += nBytesConsumed; + nMaxInputBytes -= nBytesConsumed; + } + + // These are input ( available size ) *and* output ( size processed ) vars for lzma + SizeT expectedInputRemaining = m_nCompressedSize - Min( m_nCompressedBytesRead + nCompressedBytesRead, m_nCompressedSize ); + SizeT expectedOutputRemaining = m_nActualSize - m_nActualBytesRead; + SizeT inSize = Min( (SizeT)nMaxInputBytes, expectedInputRemaining ); + SizeT outSize = Min( (SizeT)nMaxOutputBytes, expectedOutputRemaining ); + ELzmaStatus status; + ELzmaFinishMode finishMode = LZMA_FINISH_ANY; + if ( inSize == expectedInputRemaining && outSize == expectedOutputRemaining ) + { + // Expect to finish decoding this call. + finishMode = LZMA_FINISH_END; + } + SRes result = LzmaDec_DecodeToBuf( m_pDecoderState, pOutput, &outSize, + pInput, &inSize, finishMode, &status ); + + // DevMsg("[%p] Running lzmaDecode:\n" + // " pInput: %p\n" + // " nMaxInputBytes: %i\n" + // " pOutput: %p\n" + // " nMaxOutputBytes: %u\n" + // " inSize: %u\n" + // " outSize: %u\n" + // " result: %u\n" + // " status: %i\n" + // " m_nActualSize: %u\n" + // " m_nActualBytesRead: %u\n", + // this, pInput, nMaxInputBytes, pOutput, nMaxOutputBytes, + // inSize, outSize, result, status, m_nActualSize, m_nActualBytesRead); + + if ( result != SZ_OK ) + { + if ( !bStartedWithHeader ) + { + // If we're returning false, we need to pretend we didn't consume anything. + FreeDecoderState(); + m_bParsedHeader = false; + } + return false; + } + + nCompressedBytesRead += inSize; + nOutputBytesWritten += outSize; + + m_nCompressedBytesRead += nCompressedBytesRead; + m_nActualBytesRead += nOutputBytesWritten; + + Assert( m_nCompressedBytesRead <= m_nCompressedSize ); + return true; +} + +bool CLZMAStream::GetExpectedBytesRemaining( /* out */ unsigned int &nBytesRemaining ) +{ + if ( !m_bParsedHeader && !m_bZIPStyleHeader ) { + return false; + } + + nBytesRemaining = m_nActualSize - m_nActualBytesRead; + + return true; +} + +void CLZMAStream::InitZIPHeader( unsigned int nCompressedSize, unsigned int nOriginalSize ) +{ + if ( m_bParsedHeader || m_bZIPStyleHeader ) + { + AssertMsg( !m_bParsedHeader && !m_bZIPStyleHeader, + "LZMA Stream: InitZIPHeader() called on stream past header" ); + return; + } + + m_nCompressedSize = nCompressedSize; + m_nActualSize = nOriginalSize; + // Signal to TryParseHeader to expect a zip-style header (which wont have the size values) + m_bZIPStyleHeader = true; +} + +CLZMAStream::eHeaderParse CLZMAStream::TryParseHeader( unsigned char *pInput, unsigned int nBytesAvailable, /* out */ unsigned int &nBytesConsumed ) +{ + nBytesConsumed = 0; + + if ( m_bParsedHeader ) + { + AssertMsg( !m_bParsedHeader, "CLZMAStream::ReadSourceHeader called on already initialized stream" ); + return eHeaderParse_Fail; + } + + if ( m_bZIPStyleHeader ) + { + // ZIP Spec, 5.8.8 + // LZMA Version Information 2 bytes + // LZMA Properties Size 2 bytes + // LZMA Properties Data variable, defined by "LZMA Properties Size" + + if ( nBytesAvailable < 4 ) + { + // No error, but need more input to continue + return eHeaderParse_NeedMoreBytes; + } + + // Should probably check this + // unsigned char nLZMAVer[2] = { pInput[0], pInput[1] }; + + uint16 nLZMAPropertiesSize = LittleWord( *(uint16 *)(pInput + 2) ); + + nBytesConsumed += 4; + + if ( nLZMAPropertiesSize != LZMA_PROPS_SIZE ) + { + Warning( "LZMA stream: Unexpected LZMA properties size: %hu, expecting %u. Version mismatch?\n", + nLZMAPropertiesSize, LZMA_PROPS_SIZE ); + return eHeaderParse_Fail; + } + + if ( nBytesAvailable < static_cast(nLZMAPropertiesSize) + 4 ) + { + return eHeaderParse_NeedMoreBytes; + } + + // Looks reasonable, try to parse + if ( !CreateDecoderState( (Byte *)pInput + 4 ) ) + { + AssertMsg( false, "Failed decoding Lzma properties" ); + return eHeaderParse_Fail; + } + + nBytesConsumed += nLZMAPropertiesSize; + } + else + { + // Else native source engine style header + if ( nBytesAvailable < sizeof( lzma_header_t ) ) + { + // need more input to continue + return eHeaderParse_NeedMoreBytes; + } + + m_nActualSize = CLZMA::GetActualSize( pInput ); + + if ( !m_nActualSize ) + { + // unrecognized + Warning( "Unrecognized LZMA data\n" ); + return eHeaderParse_Fail; + } + + if ( !CreateDecoderState( ((lzma_header_t *)pInput)->properties ) ) + { + AssertMsg( false, "Failed decoding Lzma properties" ); + return eHeaderParse_Fail; + } + + m_nCompressedSize = LittleLong( ((lzma_header_t *)pInput)->lzmaSize ) + sizeof( lzma_header_t ); + nBytesConsumed += sizeof( lzma_header_t ); + } + + m_bParsedHeader = true; + return eHeaderParse_OK; +} diff --git a/tier1/mempool.cpp b/tier1/mempool.cpp new file mode 100644 index 0000000..8cdb404 --- /dev/null +++ b/tier1/mempool.cpp @@ -0,0 +1,316 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "mempool.h" +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include +#include "tier0/dbg.h" +#include +#include "tier1/strtools.h" + +// Should be last include +#include "tier0/memdbgon.h" + +MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0; + +//----------------------------------------------------------------------------- +// Error reporting... (debug only) +//----------------------------------------------------------------------------- + +void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func ) +{ + g_ReportFunc = func; +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment ) +{ +#ifdef _X360 + if( numElements > 0 && growMode != UTLMEMORYPOOL_GROW_NONE ) + { + numElements = 1; + } +#endif + + m_nAlignment = ( nAlignment != 0 ) ? nAlignment : 1; + Assert( IsPowerOfTwo( m_nAlignment ) ); + m_BlockSize = blockSize < sizeof(void*) ? sizeof(void*) : blockSize; + m_BlockSize = AlignValue( m_BlockSize, m_nAlignment ); + m_BlocksPerBlob = numElements; + m_PeakAlloc = 0; + m_GrowMode = growMode; + if ( !pszAllocOwner ) + { + pszAllocOwner = __FILE__; + } + m_pszAllocOwner = pszAllocOwner; + Init(); + AddNewBlob(); +} + +//----------------------------------------------------------------------------- +// Purpose: Frees the memory contained in the mempool, and invalidates it for +// any further use. +// Input : *memPool - the mempool to shutdown +//----------------------------------------------------------------------------- +CUtlMemoryPool::~CUtlMemoryPool() +{ + if (m_BlocksAllocated > 0) + { + ReportLeaks(); + } + Clear(); +} + + +//----------------------------------------------------------------------------- +// Resets the pool +//----------------------------------------------------------------------------- +void CUtlMemoryPool::Init() +{ + m_NumBlobs = 0; + m_BlocksAllocated = 0; + m_pHeadOfFreeList = 0; + m_BlobHead.m_pNext = m_BlobHead.m_pPrev = &m_BlobHead; +} + + +//----------------------------------------------------------------------------- +// Frees everything +//----------------------------------------------------------------------------- +void CUtlMemoryPool::Clear() +{ + // Free everything.. + CBlob *pNext; + for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pNext ) + { + pNext = pCur->m_pNext; + free( pCur ); + } + Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: Reports memory leaks +//----------------------------------------------------------------------------- + +void CUtlMemoryPool::ReportLeaks() +{ + if (!g_ReportFunc) + return; + + g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated); + +#ifdef _DEBUG + // walk and destroy the free list so it doesn't intefere in the scan + while (m_pHeadOfFreeList != NULL) + { + void *next = *((void**)m_pHeadOfFreeList); + memset(m_pHeadOfFreeList, 0, m_BlockSize); + m_pHeadOfFreeList = next; + } + + g_ReportFunc("Dumping memory: \'"); + + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + // scan the memory block and dump the leaks + char *scanPoint = (char *)pCur->m_Data; + char *scanEnd = pCur->m_Data + pCur->m_NumBytes; + bool needSpace = false; + + while (scanPoint < scanEnd) + { + // search for and dump any strings + if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint)) + { + g_ReportFunc("%c", *scanPoint); + needSpace = true; + } + else if (needSpace) + { + needSpace = false; + g_ReportFunc(" "); + } + + scanPoint++; + } + } + + g_ReportFunc("\'\n"); +#endif // _DEBUG +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CUtlMemoryPool::AddNewBlob() +{ + MEM_ALLOC_CREDIT_(m_pszAllocOwner); + + int sizeMultiplier; + + if( m_GrowMode == UTLMEMORYPOOL_GROW_SLOW ) + { + sizeMultiplier = 1; + } + else + { + if ( m_GrowMode == UTLMEMORYPOOL_GROW_NONE ) + { + // Can only have one allocation when we're in this mode + if( m_NumBlobs != 0 ) + { + Assert( !"CUtlMemoryPool::AddNewBlob: mode == UTLMEMORYPOOL_GROW_NONE" ); + return; + } + } + + // GROW_FAST and GROW_NONE use this. + sizeMultiplier = m_NumBlobs + 1; + } + + // maybe use something other than malloc? + int nElements = m_BlocksPerBlob * sizeMultiplier; + int blobSize = m_BlockSize * nElements; + CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) ); + Assert( pBlob ); + + // Link it in at the end of the blob list. + pBlob->m_NumBytes = blobSize; + pBlob->m_pNext = &m_BlobHead; + pBlob->m_pPrev = pBlob->m_pNext->m_pPrev; + pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob; + + // setup the free list + m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment ); + Assert (m_pHeadOfFreeList); + + void **newBlob = (void**)m_pHeadOfFreeList; + for (int j = 0; j < nElements-1; j++) + { + newBlob[0] = (char*)newBlob + m_BlockSize; + newBlob = (void**)newBlob[0]; + } + + // null terminate list + newBlob[0] = NULL; + m_NumBlobs++; +} + + +void* CUtlMemoryPool::Alloc() +{ + return Alloc( m_BlockSize ); +} + + +void* CUtlMemoryPool::AllocZero() +{ + return AllocZero( m_BlockSize ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Allocs a single block of memory from the pool. +// Input : amount - +//----------------------------------------------------------------------------- +void *CUtlMemoryPool::Alloc( size_t amount ) +{ + void *returnBlock; + + if ( amount > (unsigned int)m_BlockSize ) + return NULL; + + if( !m_pHeadOfFreeList ) + { + // returning NULL is fine in UTLMEMORYPOOL_GROW_NONE + if( m_GrowMode == UTLMEMORYPOOL_GROW_NONE ) + { + //Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with UTLMEMORYPOOL_GROW_NONE" ); + return NULL; + } + + // overflow + AddNewBlob(); + + // still failure, error out + if( !m_pHeadOfFreeList ) + { + Assert( !"CUtlMemoryPool::Alloc: ran out of memory" ); + return NULL; + } + } + m_BlocksAllocated++; + m_PeakAlloc = vmax(m_PeakAlloc, m_BlocksAllocated); + + returnBlock = m_pHeadOfFreeList; + + // move the pointer the next block + m_pHeadOfFreeList = *((void**)m_pHeadOfFreeList); + + return returnBlock; +} + +//----------------------------------------------------------------------------- +// Purpose: Allocs a single block of memory from the pool, zeroes the memory before returning +// Input : amount - +//----------------------------------------------------------------------------- +void *CUtlMemoryPool::AllocZero( size_t amount ) +{ + void *mem = Alloc( amount ); + if ( mem ) + { + V_memset( mem, 0x00, amount ); + } + return mem; +} + +//----------------------------------------------------------------------------- +// Purpose: Frees a block of memory +// Input : *memBlock - the memory to free +//----------------------------------------------------------------------------- +void CUtlMemoryPool::Free( void *memBlock ) +{ + if ( !memBlock ) + return; // trying to delete NULL pointer, ignore + +#ifdef _DEBUG + // check to see if the memory is from the allocated range + bool bOK = false; + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + if (memBlock >= pCur->m_Data && (char*)memBlock < (pCur->m_Data + pCur->m_NumBytes)) + { + bOK = true; + } + } + Assert (bOK); +#endif // _DEBUG + +#ifdef _DEBUG + // invalidate the memory + memset( memBlock, 0xDD, m_BlockSize ); +#endif + + m_BlocksAllocated--; + + // make the block point to the first item in the list + *((void**)memBlock) = m_pHeadOfFreeList; + + // the list head is now the new block + m_pHeadOfFreeList = memBlock; +} + + diff --git a/tier1/memstack.cpp b/tier1/memstack.cpp new file mode 100644 index 0000000..b89a507 --- /dev/null +++ b/tier1/memstack.cpp @@ -0,0 +1,297 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#if defined( _WIN32 ) && !defined( _X360 ) +#define WIN_32_LEAN_AND_MEAN +#include +#define VA_COMMIT_FLAGS MEM_COMMIT +#define VA_RESERVE_FLAGS MEM_RESERVE +#elif defined( _X360 ) +#define VA_COMMIT_FLAGS (MEM_COMMIT|MEM_NOZERO|MEM_LARGE_PAGES) +#define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES) +#endif + +#include "tier0/dbg.h" +#include "memstack.h" +#include "utlmap.h" +#include "tier0/memdbgon.h" + +#ifdef _WIN32 +#pragma warning(disable:4073) +#pragma init_seg(lib) +#endif + +//----------------------------------------------------------------------------- + +MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack); + +//----------------------------------------------------------------------------- + +CMemoryStack::CMemoryStack() + : m_pBase( NULL ), + m_pNextAlloc( NULL ), + m_pAllocLimit( NULL ), + m_pCommitLimit( NULL ), + m_alignment( 16 ), +#if defined(_WIN32) + m_commitSize( 0 ), + m_minCommit( 0 ), +#endif + m_maxSize( 0 ) +{ +} + +//------------------------------------- + +CMemoryStack::~CMemoryStack() +{ + if ( m_pBase ) + Term(); +} + +//------------------------------------- + +bool CMemoryStack::Init( unsigned maxSize, unsigned commitSize, unsigned initialCommit, unsigned alignment ) +{ + Assert( !m_pBase ); + +#ifdef _X360 + m_bPhysical = false; +#endif + + m_maxSize = maxSize; + m_alignment = AlignValue( alignment, 4 ); + + Assert( m_alignment == alignment ); + Assert( m_maxSize > 0 ); + +#if defined(_WIN32) + if ( commitSize != 0 ) + { + m_commitSize = commitSize; + } + + unsigned pageSize; + +#ifndef _X360 + SYSTEM_INFO sysInfo; + GetSystemInfo( &sysInfo ); + Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) ); + pageSize = sysInfo.dwPageSize; +#else + pageSize = 64*1024; +#endif + + if ( m_commitSize == 0 ) + { + m_commitSize = pageSize; + } + else + { + m_commitSize = AlignValue( m_commitSize, pageSize ); + } + + m_maxSize = AlignValue( m_maxSize, m_commitSize ); + + Assert( m_maxSize % pageSize == 0 && m_commitSize % pageSize == 0 && m_commitSize <= m_maxSize ); + + m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS ); + Assert( m_pBase ); + m_pCommitLimit = m_pNextAlloc = m_pBase; + + if ( initialCommit ) + { + initialCommit = AlignValue( initialCommit, m_commitSize ); + Assert( initialCommit < m_maxSize ); + if ( !VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE ) ) + return false; + m_minCommit = initialCommit; + m_pCommitLimit += initialCommit; + MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() ); + } + +#else + m_pBase = (byte *)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 ); + m_pNextAlloc = m_pBase; + m_pCommitLimit = m_pBase + m_maxSize; +#endif + + m_pAllocLimit = m_pBase + m_maxSize; + + return ( m_pBase != NULL ); +} + +//------------------------------------- + +#ifdef _X360 +bool CMemoryStack::InitPhysical( unsigned size, unsigned alignment ) +{ + m_bPhysical = true; + + m_maxSize = m_commitSize = size; + m_alignment = AlignValue( alignment, 4 ); + + int flags = PAGE_READWRITE; + if ( size >= 16*1024*1024 ) + { + flags |= MEM_16MB_PAGES; + } + else + { + flags |= MEM_LARGE_PAGES; + } + m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, 4096, flags ); + Assert( m_pBase ); + m_pNextAlloc = m_pBase; + m_pCommitLimit = m_pBase + m_maxSize; + m_pAllocLimit = m_pBase + m_maxSize; + + MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() ); + return ( m_pBase != NULL ); +} +#endif + +//------------------------------------- + +void CMemoryStack::Term() +{ + FreeAll(); + if ( m_pBase ) + { +#if defined(_WIN32) + VirtualFree( m_pBase, 0, MEM_RELEASE ); +#else + MemAlloc_FreeAligned( m_pBase ); +#endif + m_pBase = NULL; + } +} + +//------------------------------------- + +int CMemoryStack::GetSize() +{ +#ifdef _WIN32 + return m_pCommitLimit - m_pBase; +#else + return m_maxSize; +#endif +} + + +//------------------------------------- + +bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT +{ +#ifdef _X360 + if ( m_bPhysical ) + { + return NULL; + } +#endif +#if defined(_WIN32) + unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitSize ); + unsigned commitSize = pNewCommitLimit - m_pCommitLimit; + + if ( GetSize() ) + MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() ); + + if( m_pCommitLimit + commitSize > m_pAllocLimit ) + { + return false; + } + + if ( !VirtualAlloc( m_pCommitLimit, commitSize, VA_COMMIT_FLAGS, PAGE_READWRITE ) ) + { + Assert( 0 ); + return false; + } + m_pCommitLimit = pNewCommitLimit; + + if ( GetSize() ) + MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() ); + return true; +#else + Assert( 0 ); + return false; +#endif +} + +//------------------------------------- + +void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit ) +{ + void *pAllocPoint = m_pBase + mark; + Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc ); + + if ( pAllocPoint >= m_pBase && pAllocPoint < m_pNextAlloc ) + { + if ( bDecommit ) + { +#if defined(_WIN32) + unsigned char *pDecommitPoint = AlignValue( (unsigned char *)pAllocPoint, m_commitSize ); + + if ( pDecommitPoint < m_pBase + m_minCommit ) + { + pDecommitPoint = m_pBase + m_minCommit; + } + + unsigned decommitSize = m_pCommitLimit - pDecommitPoint; + + if ( decommitSize > 0 ) + { + MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() ); + + VirtualFree( pDecommitPoint, decommitSize, MEM_DECOMMIT ); + m_pCommitLimit = pDecommitPoint; + + if ( mark > 0 ) + { + MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() ); + } + } +#endif + } + m_pNextAlloc = (unsigned char *)pAllocPoint; + } +} + +//------------------------------------- + +void CMemoryStack::FreeAll( bool bDecommit ) +{ + if ( m_pBase && m_pCommitLimit - m_pBase > 0 ) + { + if ( bDecommit ) + { +#if defined(_WIN32) + MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() ); + + VirtualFree( m_pBase, m_pCommitLimit - m_pBase, MEM_DECOMMIT ); + m_pCommitLimit = m_pBase; +#endif + } + m_pNextAlloc = m_pBase; + } +} + +//------------------------------------- + +void CMemoryStack::Access( void **ppRegion, unsigned *pBytes ) +{ + *ppRegion = m_pBase; + *pBytes = (unsigned int)( m_pNextAlloc - m_pBase); +} + +//------------------------------------- + +void CMemoryStack::PrintContents() +{ + Msg( "Total used memory: %d\n", GetUsed() ); + Msg( "Total committed memory: %d\n", GetSize() ); +} + +//----------------------------------------------------------------------------- diff --git a/tier1/newbitbuf.cpp b/tier1/newbitbuf.cpp new file mode 100644 index 0000000..073f8be --- /dev/null +++ b/tier1/newbitbuf.cpp @@ -0,0 +1,717 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "bitbuf.h" +#include "coordsize.h" +#include "mathlib/vector.h" +#include "mathlib/mathlib.h" +#include "tier1/strtools.h" +#include "bitvec.h" + +// FIXME: Can't use this until we get multithreaded allocations in tier0 working for tools +// This is used by VVIS and fails to link +// NOTE: This must be the last file included!!! +//#include "tier0/memdbgon.h" + +#ifdef _X360 +// mandatory ... wary of above comment and isolating, tier0 is built as MT though +#include "tier0/memdbgon.h" +#endif + +#include "stdio.h" + +#if 0 + +void CBitWrite::StartWriting( void *pData, int nBytes, int iStartBit, int nBits ) +{ + // Make sure it's dword aligned and padded. + Assert( (nBytes % 4) == 0 ); + Assert(((unsigned long)pData & 3) == 0); + Assert( iStartBit == 0 ); + m_pData = (uint32 *) pData; + m_pDataOut = m_pData; + m_nDataBytes = nBytes; + + if ( nBits == -1 ) + { + m_nDataBits = nBytes << 3; + } + else + { + Assert( nBits <= nBytes*8 ); + m_nDataBits = nBits; + } + m_bOverflow = false; + m_nOutBufWord = 0; + m_nOutBitsAvail = 32; + m_pBufferEnd = m_pDataOut + ( nBytes >> 2 ); +} + +const uint32 CBitBuffer::s_nMaskTable[33] = { + 0, + ( 1 << 1 ) - 1, + ( 1 << 2 ) - 1, + ( 1 << 3 ) - 1, + ( 1 << 4 ) - 1, + ( 1 << 5 ) - 1, + ( 1 << 6 ) - 1, + ( 1 << 7 ) - 1, + ( 1 << 8 ) - 1, + ( 1 << 9 ) - 1, + ( 1 << 10 ) - 1, + ( 1 << 11 ) - 1, + ( 1 << 12 ) - 1, + ( 1 << 13 ) - 1, + ( 1 << 14 ) - 1, + ( 1 << 15 ) - 1, + ( 1 << 16 ) - 1, + ( 1 << 17 ) - 1, + ( 1 << 18 ) - 1, + ( 1 << 19 ) - 1, + ( 1 << 20 ) - 1, + ( 1 << 21 ) - 1, + ( 1 << 22 ) - 1, + ( 1 << 23 ) - 1, + ( 1 << 24 ) - 1, + ( 1 << 25 ) - 1, + ( 1 << 26 ) - 1, + ( 1 << 27 ) - 1, + ( 1 << 28 ) - 1, + ( 1 << 29 ) - 1, + ( 1 << 30 ) - 1, + 0x7fffffff, + 0xffffffff, +}; + +bool CBitWrite::WriteString( const char *pStr ) +{ + if(pStr) + { + while( *pStr ) + { + WriteChar( * ( pStr++ ) ); + } + } + WriteChar( 0 ); + return !IsOverflowed(); +} + + +void CBitWrite::WriteLongLong(int64 val) +{ + uint *pLongs = (uint*)&val; + + // Insert the two DWORDS according to network endian + const short endianIndex = 0x0100; + byte *idx = (byte*)&endianIndex; + WriteUBitLong(pLongs[*idx++], sizeof(long) << 3); + WriteUBitLong(pLongs[*idx], sizeof(long) << 3); +} + +bool CBitWrite::WriteBits(const void *pInData, int nBits) +{ + unsigned char *pOut = (unsigned char*)pInData; + int nBitsLeft = nBits; + + // Bounds checking.. + if ( ( GetNumBitsWritten() + nBits) > m_nDataBits ) + { + SetOverflowFlag(); + CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, m_pDebugName ); + return false; + } + + // !! speed!! need fast paths + // write remaining bytes + while ( nBitsLeft >= 8 ) + { + WriteUBitLong( *pOut, 8, false ); + ++pOut; + nBitsLeft -= 8; + } + + // write remaining bits + if ( nBitsLeft ) + { + WriteUBitLong( *pOut, nBitsLeft, false ); + } + + return !IsOverflowed(); +} + +void CBitWrite::WriteBytes( const void *pBuf, int nBytes ) +{ + WriteBits(pBuf, nBytes << 3); +} + +void CBitWrite::WriteBitCoord (const float f) +{ + int signbit = (f <= -COORD_RESOLUTION); + int intval = (int)abs(f); + int fractval = abs((int)(f*COORD_DENOMINATOR)) & (COORD_DENOMINATOR-1); + + + // Send the bit flags that indicate whether we have an integer part and/or a fraction part. + WriteOneBit( intval ); + WriteOneBit( fractval ); + + if ( intval || fractval ) + { + // Send the sign bit + WriteOneBit( signbit ); + + // Send the integer if we have one. + if ( intval ) + { + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + intval--; + WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS ); + } + + // Send the fraction if we have one + if ( fractval ) + { + WriteUBitLong( (unsigned int)fractval, COORD_FRACTIONAL_BITS ); + } + } +} + +void CBitWrite::WriteBitCoordMP (const float f, bool bIntegral, bool bLowPrecision ) +{ + int signbit = (f <= -( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION )); + int intval = (int)abs(f); + int fractval = bLowPrecision ? + ( abs((int)(f*COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION-1) ) : + ( abs((int)(f*COORD_DENOMINATOR)) & (COORD_DENOMINATOR-1) ); + + bool bInBounds = intval < (1 << COORD_INTEGER_BITS_MP ); + + WriteOneBit( bInBounds ); + + if ( bIntegral ) + { + // Send the sign bit + WriteOneBit( intval ); + if ( intval ) + { + WriteOneBit( signbit ); + // Send the integer if we have one. + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + intval--; + if ( bInBounds ) + { + WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS_MP ); + } + else + { + WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS ); + } + } + } + else + { + // Send the bit flags that indicate whether we have an integer part and/or a fraction part. + WriteOneBit( intval ); + // Send the sign bit + WriteOneBit( signbit ); + + // Send the integer if we have one. + if ( intval ) + { + // Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1] + intval--; + if ( bInBounds ) + { + WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS_MP ); + } + else + { + WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS ); + } + } + WriteUBitLong( (unsigned int)fractval, bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS ); + } +} + +void CBitWrite::SeekToBit( int nBit ) +{ + TempFlush(); + m_pDataOut = m_pData + ( nBit / 32 ); + m_nOutBufWord = *( m_pDataOut ); + m_nOutBitsAvail = 32 - ( nBit & 31 ); +} + + + +void CBitWrite::WriteBitVec3Coord( const Vector& fa ) +{ + int xflag, yflag, zflag; + + xflag = (fa[0] >= COORD_RESOLUTION) || (fa[0] <= -COORD_RESOLUTION); + yflag = (fa[1] >= COORD_RESOLUTION) || (fa[1] <= -COORD_RESOLUTION); + zflag = (fa[2] >= COORD_RESOLUTION) || (fa[2] <= -COORD_RESOLUTION); + + WriteOneBit( xflag ); + WriteOneBit( yflag ); + WriteOneBit( zflag ); + + if ( xflag ) + WriteBitCoord( fa[0] ); + if ( yflag ) + WriteBitCoord( fa[1] ); + if ( zflag ) + WriteBitCoord( fa[2] ); +} + +void CBitWrite::WriteBitNormal( float f ) +{ + int signbit = (f <= -NORMAL_RESOLUTION); + + // NOTE: Since +/-1 are valid values for a normal, I'm going to encode that as all ones + unsigned int fractval = abs( (int)(f*NORMAL_DENOMINATOR) ); + + // clamp.. + if (fractval > NORMAL_DENOMINATOR) + fractval = NORMAL_DENOMINATOR; + + // Send the sign bit + WriteOneBit( signbit ); + + // Send the fractional component + WriteUBitLong( fractval, NORMAL_FRACTIONAL_BITS ); +} + +void CBitWrite::WriteBitVec3Normal( const Vector& fa ) +{ + int xflag, yflag; + + xflag = (fa[0] >= NORMAL_RESOLUTION) || (fa[0] <= -NORMAL_RESOLUTION); + yflag = (fa[1] >= NORMAL_RESOLUTION) || (fa[1] <= -NORMAL_RESOLUTION); + + WriteOneBit( xflag ); + WriteOneBit( yflag ); + + if ( xflag ) + WriteBitNormal( fa[0] ); + if ( yflag ) + WriteBitNormal( fa[1] ); + + // Write z sign bit + int signbit = (fa[2] <= -NORMAL_RESOLUTION); + WriteOneBit( signbit ); +} + +void CBitWrite::WriteBitAngle( float fAngle, int numbits ) +{ + + unsigned int shift = GetBitForBitnum(numbits); + unsigned int mask = shift - 1; + + int d = (int)( (fAngle / 360.0) * shift ); + d &= mask; + + WriteUBitLong((unsigned int)d, numbits); +} + +bool CBitWrite::WriteBitsFromBuffer( bf_read *pIn, int nBits ) +{ +// This could be optimized a little by + while ( nBits > 32 ) + { + WriteUBitLong( pIn->ReadUBitLong( 32 ), 32 ); + nBits -= 32; + } + + WriteUBitLong( pIn->ReadUBitLong( nBits ), nBits ); + return !IsOverflowed() && !pIn->IsOverflowed(); +} + +void CBitWrite::WriteBitAngles( const QAngle& fa ) +{ + // FIXME: + Vector tmp( fa.x, fa.y, fa.z ); + WriteBitVec3Coord( tmp ); +} + +bool CBitRead::Seek( int nPosition ) +{ + bool bSucc = true; + if ( nPosition < 0 || nPosition > m_nDataBits) + { + SetOverflowFlag(); + bSucc = false; + nPosition = m_nDataBits; + } + int nHead = m_nDataBytes & 3; // non-multiple-of-4 bytes at head of buffer. We put the "round off" + // at the head to make reading and detecting the end efficient. + + int nByteOfs = nPosition / 8; + if ( ( m_nDataBytes < 4 ) || ( nHead && ( nByteOfs < nHead ) ) ) + { + // partial first dword + uint8 const *pPartial = ( uint8 const *) m_pData; + if ( m_pData ) + { + m_nInBufWord = *( pPartial++ ); + if ( nHead > 1 ) + m_nInBufWord |= ( *pPartial++ ) << 8; + if ( nHead > 2 ) + m_nInBufWord |= ( *pPartial++ ) << 16; + } + m_pDataIn = ( uint32 const * ) pPartial; + m_nInBufWord >>= ( nPosition & 31 ); + m_nBitsAvail = ( nHead << 3 ) - ( nPosition & 31 ); + } + else + { + int nAdjPosition = nPosition - ( nHead << 3 ); + m_pDataIn = reinterpret_cast ( + reinterpret_cast( m_pData ) + ( ( nAdjPosition / 32 ) << 2 ) + nHead ); + if ( m_pData ) + { + m_nBitsAvail = 32; + GrabNextDWord(); + } + else + { + m_nInBufWord = 0; + m_nBitsAvail = 1; + } + m_nInBufWord >>= ( nAdjPosition & 31 ); + m_nBitsAvail = vmin( m_nBitsAvail, 32 - ( nAdjPosition & 31 ) ); // in case grabnextdword overflowed + } + return bSucc; +} + + +void CBitRead::StartReading( const void *pData, int nBytes, int iStartBit, int nBits ) +{ +// Make sure it's dword aligned and padded. + Assert(((unsigned long)pData & 3) == 0); + m_pData = (uint32 *) pData; + m_pDataIn = m_pData; + m_nDataBytes = nBytes; + + if ( nBits == -1 ) + { + m_nDataBits = nBytes << 3; + } + else + { + Assert( nBits <= nBytes*8 ); + m_nDataBits = nBits; + } + m_bOverflow = false; + m_pBufferEnd = reinterpret_cast ( reinterpret_cast< uint8 const *> (m_pData) + nBytes ); + if ( m_pData ) + Seek( iStartBit ); + +} + +bool CBitRead::ReadString( char *pStr, int maxLen, bool bLine, int *pOutNumChars ) +{ + Assert( maxLen != 0 ); + + bool bTooSmall = false; + int iChar = 0; + while(1) + { + char val = ReadChar(); + if ( val == 0 ) + break; + else if ( bLine && val == '\n' ) + break; + + if ( iChar < (maxLen-1) ) + { + pStr[iChar] = val; + ++iChar; + } + else + { + bTooSmall = true; + } + } + + // Make sure it's null-terminated. + Assert( iChar < maxLen ); + pStr[iChar] = 0; + + if ( pOutNumChars ) + *pOutNumChars = iChar; + + return !IsOverflowed() && !bTooSmall; +} + +char* CBitRead::ReadAndAllocateString( bool *pOverflow ) +{ + char str[2048]; + + int nChars; + bool bOverflow = !ReadString( str, sizeof( str ), false, &nChars ); + if ( pOverflow ) + *pOverflow = bOverflow; + + // Now copy into the output and return it; + char *pRet = new char[ nChars + 1 ]; + for ( int i=0; i <= nChars; i++ ) + pRet[i] = str[i]; + + return pRet; +} + +int64 CBitRead::ReadLongLong( void ) +{ + int64 retval; + uint *pLongs = (uint*)&retval; + + // Read the two DWORDs according to network endian + const short endianIndex = 0x0100; + byte *idx = (byte*)&endianIndex; + pLongs[*idx++] = ReadUBitLong(sizeof(long) << 3); + pLongs[*idx] = ReadUBitLong(sizeof(long) << 3); + return retval; +} + +void CBitRead::ReadBits(void *pOutData, int nBits) +{ + unsigned char *pOut = (unsigned char*)pOutData; + int nBitsLeft = nBits; + + + // align output to dword boundary + while( ((unsigned long)pOut & 3) != 0 && nBitsLeft >= 8 ) + { + *pOut = (unsigned char)ReadUBitLong(8); + ++pOut; + nBitsLeft -= 8; + } + + // X360TBD: Can't read dwords in ReadBits because they'll get swapped + if ( IsPC() ) + { + // read dwords + while ( nBitsLeft >= 32 ) + { + *((unsigned long*)pOut) = ReadUBitLong(32); + pOut += sizeof(unsigned long); + nBitsLeft -= 32; + } + } + + // read remaining bytes + while ( nBitsLeft >= 8 ) + { + *pOut = ReadUBitLong(8); + ++pOut; + nBitsLeft -= 8; + } + + // read remaining bits + if ( nBitsLeft ) + { + *pOut = ReadUBitLong(nBitsLeft); + } + +} + +bool CBitRead::ReadBytes(void *pOut, int nBytes) +{ + ReadBits(pOut, nBytes << 3); + return !IsOverflowed(); +} + +float CBitRead::ReadBitAngle( int numbits ) +{ + float shift = (float)( GetBitForBitnum(numbits) ); + + int i = ReadUBitLong( numbits ); + float fReturn = (float)i * (360.0 / shift); + + return fReturn; +} + +// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants) +float CBitRead::ReadBitCoord (void) +{ + int intval=0,fractval=0,signbit=0; + float value = 0.0; + + + // Read the required integer and fraction flags + intval = ReadOneBit(); + fractval = ReadOneBit(); + + // If we got either parse them, otherwise it's a zero. + if ( intval || fractval ) + { + // Read the sign bit + signbit = ReadOneBit(); + + // If there's an integer, read it in + if ( intval ) + { + // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] + intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1; + } + + // If there's a fraction, read it in + if ( fractval ) + { + fractval = ReadUBitLong( COORD_FRACTIONAL_BITS ); + } + + // Calculate the correct floating point value + value = intval + ((float)fractval * COORD_RESOLUTION); + + // Fixup the sign if negative. + if ( signbit ) + value = -value; + } + + return value; +} + +float CBitRead::ReadBitCoordMP( bool bIntegral, bool bLowPrecision ) +{ + int intval=0,fractval=0,signbit=0; + float value = 0.0; + + bool bInBounds = ReadOneBit() ? true : false; + + if ( bIntegral ) + { + // Read the required integer and fraction flags + intval = ReadOneBit(); + // If we got either parse them, otherwise it's a zero. + if ( intval ) + { + // Read the sign bit + signbit = ReadOneBit(); + + // If there's an integer, read it in + // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] + if ( bInBounds ) + { + value = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1; + } + else + { + value = ReadUBitLong( COORD_INTEGER_BITS ) + 1; + } + } + } + else + { + // Read the required integer and fraction flags + intval = ReadOneBit(); + + // Read the sign bit + signbit = ReadOneBit(); + + // If we got either parse them, otherwise it's a zero. + if ( intval ) + { + if ( bInBounds ) + { + intval = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1; + } + else + { + intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1; + } + } + + // If there's a fraction, read it in + fractval = ReadUBitLong( bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS ); + + // Calculate the correct floating point value + value = intval + ((float)fractval * ( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ) ); + } + + // Fixup the sign if negative. + if ( signbit ) + value = -value; + + return value; +} + +void CBitRead::ReadBitVec3Coord( Vector& fa ) +{ + int xflag, yflag, zflag; + + // This vector must be initialized! Otherwise, If any of the flags aren't set, + // the corresponding component will not be read and will be stack garbage. + fa.Init( 0, 0, 0 ); + + xflag = ReadOneBit(); + yflag = ReadOneBit(); + zflag = ReadOneBit(); + + if ( xflag ) + fa[0] = ReadBitCoord(); + if ( yflag ) + fa[1] = ReadBitCoord(); + if ( zflag ) + fa[2] = ReadBitCoord(); +} + +float CBitRead::ReadBitNormal (void) +{ + // Read the sign bit + int signbit = ReadOneBit(); + + // Read the fractional part + unsigned int fractval = ReadUBitLong( NORMAL_FRACTIONAL_BITS ); + + // Calculate the correct floating point value + float value = (float)fractval * NORMAL_RESOLUTION; + + // Fixup the sign if negative. + if ( signbit ) + value = -value; + + return value; +} + +void CBitRead::ReadBitVec3Normal( Vector& fa ) +{ + int xflag = ReadOneBit(); + int yflag = ReadOneBit(); + + if (xflag) + fa[0] = ReadBitNormal(); + else + fa[0] = 0.0f; + + if (yflag) + fa[1] = ReadBitNormal(); + else + fa[1] = 0.0f; + + // The first two imply the third (but not its sign) + int znegative = ReadOneBit(); + + float fafafbfb = fa[0] * fa[0] + fa[1] * fa[1]; + if (fafafbfb < 1.0f) + fa[2] = sqrt( 1.0f - fafafbfb ); + else + fa[2] = 0.0f; + + if (znegative) + fa[2] = -fa[2]; +} + +void CBitRead::ReadBitAngles( QAngle& fa ) +{ + Vector tmp; + ReadBitVec3Coord( tmp ); + fa.Init( tmp.x, tmp.y, tmp.z ); +} + +#endif \ No newline at end of file diff --git a/tier1/pathmatch.cpp b/tier1/pathmatch.cpp new file mode 100644 index 0000000..f828a9a --- /dev/null +++ b/tier1/pathmatch.cpp @@ -0,0 +1,908 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Utility to interrogate and modify the data in the OSX IPC Server +// +// $NoKeywords: $ +//============================================================================= +// README:README +// +// This file implements the --wrap for ld on linux that lets file i/o api's +// behave as if it were running on a case insensitive file system. Unfortunately, +// this is needed by both steam2 and steam3. It was decided to check the source +// into both locations, otherwise someone would find the .o and have no idea +// where to go for the source if it was in the 'other' tree. Also, because this +// needs to be linked into every elf binary, the .o is checked in for Steam3 so that it is +// always available. In Steam2 it sits with the PosixWin32.cpp implementation and gets +// compiled along side of it through the make system. If you are reading this in Steam3, +// you will probably want to actually make your changes in steam2 and do a baseless merge +// to the steam3 copy. +// +// HOWTO: Add a new function. Add the function with _WRAP to the makefiles as noted below. +// Add the implementation to pathmatch.cpp - probably mimicking the existing functions. +// Build steam2 and copy to matching steam3/client. Take the pathmatch.o from steam 2 +// and check it in to steam3 (in the location noted below). Full rebuild (re-link really) +// of steam3. Test steam and check in. +// +// If you are looking at updating this file, please update the following as needed: +// +// STEAM2.../Projects/GazelleProto/Client/Engine/obj/RELEASE_NORMAL/libsteam_linux/Common/Misc/pathmatch.o +// This is where steam2 builds the pathmatch.o out to. +// +// STEAM2.../Projects/GazelleProto/Makefile.shlib.base - contains _WRAP references +// STEAM2.../Projects/Common/Misc/pathmatch.cpp - Where the source is checked in, keep in sync with: +// STEAM3.../src/common/pathmatch.cpp - should be identical to previous file, but discoverable in steam3. +// STEAM3.../src/lib/linux32/release/pathmatch.o - steam3 checked in version +// STEAM3.../src/devtools/makefile_base_posix.mak - look for the _WRAP references + +#ifdef LINUX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Enable to do pathmatch caching. Beware: this code isn't threadsafe. +// #define DO_PATHMATCH_CACHE + +#ifdef UTF8_PATHMATCH +#define strcasecmp utf8casecmp +#endif + +static bool s_bShowDiag; +#define DEBUG_MSG( ... ) if ( s_bShowDiag ) fprintf( stderr, ##__VA_ARGS__ ) +#define DEBUG_BREAK() __asm__ __volatile__ ( "int $3" ) +#define _COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;} + +#define WRAP( fn, ret, ... ) \ + ret __real_##fn(__VA_ARGS__); \ + ret __wrap_##fn(__VA_ARGS__) + +#define CALL( fn ) __real_##fn + +// Needed by pathmatch code +extern "C" int __real_access(const char *pathname, int mode); +extern "C" DIR *__real_opendir(const char *name); + + +// UTF-8 work from PhysicsFS: http://icculus.org/physfs/ +// Even if it wasn't under the zlib license, Ryan wrote all this code originally. + +#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF +#define UNICODE_BOGUS_CHAR_CODEPOINT '?' + +inline __attribute__ ((always_inline)) static uint32_t utf8codepoint(const char **_str) +{ + const char *str = *_str; + uint32_t retval = 0; + uint32_t octet = (uint32_t) ((uint8_t) *str); + uint32_t octet2, octet3, octet4; + + if (octet == 0) // null terminator, end of string. + return 0; + + else if (octet < 128) // one octet char: 0 to 127 + { + (*_str)++; // skip to next possible start of codepoint. + return octet; + } + + else if ((octet > 127) && (octet < 192)) // bad (starts with 10xxxxxx). + { + // Apparently each of these is supposed to be flagged as a bogus + // char, instead of just resyncing to the next valid codepoint. + (*_str)++; // skip to next possible start of codepoint. + return UNICODE_BOGUS_CHAR_VALUE; + } + + else if (octet < 224) // two octets + { + octet -= (128+64); + octet2 = (uint32_t) ((uint8_t) *(++str)); + if ((octet2 & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 2; // skip to next possible start of codepoint. + retval = ((octet << 6) | (octet2 - 128)); + if ((retval >= 0x80) && (retval <= 0x7FF)) + return retval; + } + + else if (octet < 240) // three octets + { + octet -= (128+64+32); + octet2 = (uint32_t) ((uint8_t) *(++str)); + if ((octet2 & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet3 = (uint32_t) ((uint8_t) *(++str)); + if ((octet3 & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 3; // skip to next possible start of codepoint. + retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) ); + + // There are seven "UTF-16 surrogates" that are illegal in UTF-8. + switch (retval) + { + case 0xD800: + case 0xDB7F: + case 0xDB80: + case 0xDBFF: + case 0xDC00: + case 0xDF80: + case 0xDFFF: + return UNICODE_BOGUS_CHAR_VALUE; + } + + // 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. + if ((retval >= 0x800) && (retval <= 0xFFFD)) + return retval; + } + + else if (octet < 248) // four octets + { + octet -= (128+64+32+16); + octet2 = (uint32_t) ((uint8_t) *(++str)); + if ((octet2 & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet3 = (uint32_t) ((uint8_t) *(++str)); + if ((octet3 & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet4 = (uint32_t) ((uint8_t) *(++str)); + if ((octet4 & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 4; // skip to next possible start of codepoint. + retval = ( ((octet << 18)) | ((octet2 - 128) << 12) | + ((octet3 - 128) << 6) | ((octet4 - 128)) ); + if ((retval >= 0x10000) && (retval <= 0x10FFFF)) + return retval; + } + + // Five and six octet sequences became illegal in rfc3629. + // We throw the codepoint away, but parse them to make sure we move + // ahead the right number of bytes and don't overflow the buffer. + + else if (octet < 252) // five octets + { + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 5; // skip to next possible start of codepoint. + return UNICODE_BOGUS_CHAR_VALUE; + } + + else // six octets + { + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (uint32_t) ((uint8_t) *(++str)); + if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx? + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 6; // skip to next possible start of codepoint. + return UNICODE_BOGUS_CHAR_VALUE; + } + + return UNICODE_BOGUS_CHAR_VALUE; +} + +typedef struct CaseFoldMapping +{ + uint32_t from; + uint32_t to0; + uint32_t to1; + uint32_t to2; +} CaseFoldMapping; + +typedef struct CaseFoldHashBucket +{ + const uint8_t count; + const CaseFoldMapping *list; +} CaseFoldHashBucket; + +#include "pathmatch_casefolding.h" + +inline __attribute__ ((always_inline)) static void locate_case_fold_mapping(const uint32_t from, uint32_t *to) +{ + const uint8_t hashed = ((from ^ (from >> 8)) & 0xFF); + const CaseFoldHashBucket *bucket = &case_fold_hash[hashed]; + const CaseFoldMapping *mapping = bucket->list; + uint32_t i; + + for (i = 0; i < bucket->count; i++, mapping++) + { + if (mapping->from == from) + { + to[0] = mapping->to0; + to[1] = mapping->to1; + to[2] = mapping->to2; + return; + } + } + + // Not found...there's no remapping for this codepoint. + to[0] = from; + to[1] = 0; + to[2] = 0; +} + +inline __attribute__ ((always_inline)) static uint32_t *fold_utf8(const char *str) +{ + uint32_t *retval = new uint32_t[(strlen(str) * 3) + 1]; + uint32_t *dst = retval; + while (*str) + { + const char ch = *str; + if (ch & 0x80) // high bit set? UTF-8 sequence! + { + uint32_t fold[3]; + locate_case_fold_mapping(utf8codepoint(&str), fold); + *(dst++) = fold[0]; + if (fold[1]) + { + *(dst++) = fold[1]; + if (fold[2]) + *(dst++) = fold[2]; + } + } + else // simple ASCII test. + { + *(dst++) = (uint32_t) (((ch >= 'A') && (ch <= 'Z')) ? ch + 32 : ch); + str++; + } + } + *dst = 0; + return retval; +} + +inline __attribute__ ((always_inline)) static int utf8casecmp_loop(const uint32_t *folded1, const uint32_t *folded2) +{ + while (true) + { + const uint32_t ch1 = *(folded1++); + const uint32_t ch2 = *(folded2++); + if (ch1 < ch2) + return -1; + else if (ch1 > ch2) + return 1; + else if (ch1 == 0) + return 0; // complete match. + } +} + +#ifdef UTF8_PATHMATCH +static int utf8casecmp(const char *str1, const char *str2) +{ + uint32_t *folded1 = fold_utf8(str1); + uint32_t *folded2 = fold_utf8(str2); + const int retval = utf8casecmp_loop(folded1, folded2); + delete[] folded1; + delete[] folded2; + return retval; +} +#endif + +// Simple object to help make sure a DIR* from opendir +// gets closed when it goes out of scope. +class CDirPtr +{ +public: + CDirPtr() { m_pDir = NULL; } + CDirPtr( DIR *pDir ) : m_pDir(pDir) {} + ~CDirPtr() { Close(); } + + void operator=(DIR *pDir) { Close(); m_pDir = pDir; } + + operator DIR *() { return m_pDir; } + operator bool() { return m_pDir != NULL; } +private: + + void Close() { if ( m_pDir ) closedir( m_pDir ); } + + DIR *m_pDir; +}; + +// Object used to temporarily slice a path into a smaller componentent +// and then repair it when going out of scope. Typically used as an unnamed +// temp object that is a parameter to a function. +class CDirTrimmer +{ +public: + CDirTrimmer( char * pPath, size_t nTrimIdx ) + { + m_pPath = pPath; + m_idx = nTrimIdx; + m_c = m_pPath[nTrimIdx]; + m_pPath[nTrimIdx] = '\0'; + } + ~CDirTrimmer() { m_pPath[m_idx] = m_c; } + + operator const char *() { return m_pPath; } + +private: + size_t m_idx; + char *m_pPath; + char m_c; +}; + + +enum PathMod_t +{ + kPathUnchanged, + kPathLowered, + kPathChanged, + kPathFailed, +}; + +static bool Descend( char *pPath, size_t nStartIdx, bool bAllowBasenameMismatch, size_t nLevel = 0 ) +{ + DEBUG_MSG( "(%zu) Descend: %s, (%s), %s\n", nLevel, pPath, pPath+nStartIdx, bAllowBasenameMismatch ? "true" : "false " ); + // We assume up through nStartIdx is valid and matching + size_t nNextSlash = nStartIdx+1; + + // path might be a dir + if ( pPath[nNextSlash] == '\0' ) + { + return true; + } + + bool bIsDir = false; // is the new component a directory for certain? + while ( pPath[nNextSlash] != '\0' && pPath[nNextSlash] != '/' ) + { + nNextSlash++; + } + + // Modify the pPath string + if ( pPath[nNextSlash] == '/' ) + bIsDir = true; + + // See if we have an immediate match + if ( __real_access( CDirTrimmer(pPath, nNextSlash), F_OK ) == 0 ) + { + if ( !bIsDir ) + return true; + + bool bRet = Descend( pPath, nNextSlash, bAllowBasenameMismatch, nLevel+1 ); + if ( bRet ) + return true; + } + + // Start enumerating dirents + CDirPtr spDir; + if ( nStartIdx ) + { + // we have a path + spDir = __real_opendir( CDirTrimmer( pPath, nStartIdx ) ); + nStartIdx++; + } + else + { + // we either start at root or cwd + const char *pRoot = "."; + if ( *pPath == '/' ) + { + pRoot = "/"; + nStartIdx++; + } + spDir = __real_opendir( pRoot ); + } + + errno = 0; + struct dirent *pEntry = spDir ? readdir( spDir ) : NULL; + char *pszComponent = pPath + nStartIdx; + size_t cbComponent = nNextSlash - nStartIdx; + while ( pEntry ) + { + DEBUG_MSG( "\t(%zu) comparing %s with %s\n", nLevel, pEntry->d_name, (const char *)CDirTrimmer(pszComponent, cbComponent) ); + + // the candidate must match the target, but not be a case-identical match (we would + // have looked there in the short-circuit code above, so don't look again) + bool bMatches = ( strcasecmp( CDirTrimmer(pszComponent, cbComponent), pEntry->d_name ) == 0 && + strcmp( CDirTrimmer(pszComponent, cbComponent), pEntry->d_name ) != 0 ); + + if ( bMatches ) + { + char *pSrc = pEntry->d_name; + char *pDst = &pPath[nStartIdx]; + // found a match; copy it in. + while ( *pSrc && (*pSrc != '/') ) + { + *pDst++ = *pSrc++; + } + + if ( !bIsDir ) + return true; + + if ( Descend( pPath, nNextSlash, bAllowBasenameMismatch, nLevel+1 ) ) + return true; + + // If descend fails, try more directories + } + pEntry = readdir( spDir ); + } + + if ( bIsDir ) + { + DEBUG_MSG( "(%zu) readdir failed to find '%s' in '%s'\n", nLevel, (const char *)CDirTrimmer(pszComponent, cbComponent), (const char *)CDirTrimmer( pPath, nStartIdx ) ); + } + + // Sometimes it's ok for the filename portion to not match + // since we might be opening for write. Note that if + // the filename matches case insensitive, that will be + // preferred over preserving the input name + if ( !bIsDir && bAllowBasenameMismatch ) + return true; + + return false; +} + +#ifdef DO_PATHMATCH_CACHE +typedef std::map > resultCache_t; +typedef std::map >::iterator resultCacheItr_t; +static resultCache_t resultCache; +static const int k_cMaxCacheLifetimeSeconds = 2; +#endif // DO_PATHMATCH_CACHE + +PathMod_t pathmatch( const char *pszIn, char **ppszOut, bool bAllowBasenameMismatch, char *pszOutBuf, size_t OutBufLen ) +{ + // Path matching can be very expensive, and the cost is unpredictable because it + // depends on how many files are in directories on a user's machine. Therefore + // it should be disabled whenever possible, and only enabled in environments (such + // as running with loose files such as out of Perforce) where it is needed. + static const char *s_pszPathMatchEnabled = getenv("ENABLE_PATHMATCH"); + if ( !s_pszPathMatchEnabled ) + return kPathUnchanged; + + static const char *s_pszDbgPathMatch = getenv("DBG_PATHMATCH"); + + s_bShowDiag = ( s_pszDbgPathMatch != NULL ); + + *ppszOut = NULL; + + if ( __real_access( pszIn, F_OK ) == 0 ) + return kPathUnchanged; + +#ifdef DO_PATHMATCH_CACHE + resultCacheItr_t cachedResult = resultCache.find( pszIn ); + if ( cachedResult != resultCache.end() ) + { + unsigned int age = time( NULL ) - cachedResult->second.second; + const char *pszResult = cachedResult->second.first.c_str(); + if ( pszResult[0] != '\0' || age <= k_cMaxCacheLifetimeSeconds ) + { + if ( pszResult[0] != '\0' ) + { + *ppszOut = strdup( pszResult ); + DEBUG_MSG( "Cached '%s' -> '%s'\n", pszIn, *ppszOut ); + return kPathChanged; + } + else + { + DEBUG_MSG( "Cached '%s' -> kPathFailed\n", pszIn ); + return kPathFailed; + } + } + else if ( age <= k_cMaxCacheLifetimeSeconds ) + { + DEBUG_MSG( "Rechecking '%s' - cache is %u seconds old\n", pszIn, age ); + } + } +#endif // DO_PATHMATCH_CACHE + + char *pPath; + if( strlen( pszIn ) >= OutBufLen ) + { + pPath = strdup( pszIn ); + } + else + { + strncpy( pszOutBuf, pszIn, OutBufLen ); + pPath = pszOutBuf; + } + + if ( pPath ) + { + // I believe this code is broken. I'm guessing someone wanted to avoid lowercasing + // the path before the steam directory - but it's actually skipping lowercasing + // whenever steam is found anywhere - including the filename. For example, + // /home/mikesart/valvesrc/console/l4d2/game/left4dead2_dlc1/particles/steam_fx.pcf + // winds up only having the "steam_fx.pcf" portion lowercased. +#ifdef NEVER + // optimization, if the path contained steam somewhere + // assume the path up through the component with 'steam' in + // is valid (because we almost certainly obtained it + // progamatically + char *p = strcasestr( pPath, "steam" ); + if ( p ) + { + while ( p > pPath ) + { + if ( p[-1] == '/' ) + break; + p--; + } + + if ( ( p == pPath+1 ) && ( *pPath != '/' ) ) + p = pPath; + } + else + { + p = pPath; + } +#else + char *p = pPath; +#endif + + // Try the lower casing of the remaining path + char *pBasename = p; + while ( *p ) + { + if ( *p == '/' ) + pBasename = p+1; + + *p = tolower(*p); + p++; + } + if ( __real_access( pPath, F_OK ) == 0 ) + { + *ppszOut = pPath; + DEBUG_MSG( "Lowered '%s' -> '%s'\n", pszIn, pPath ); + return kPathLowered; + } + + // path didn't match lowered successfully, restore the basename + // if bAllowBasenameMismatch was true + if ( bAllowBasenameMismatch ) + { + const char *pSrc = pszIn + (pBasename - pPath); + while ( *pBasename ) + { + *pBasename++ = *pSrc++; + } + } + + if ( s_pszDbgPathMatch && strcasestr( s_pszDbgPathMatch, pszIn ) ) + { + DEBUG_MSG( "Breaking '%s' in '%s'\n", pszIn, s_pszDbgPathMatch ); + DEBUG_BREAK(); + } + + bool bSuccess = Descend( pPath, 0, bAllowBasenameMismatch ); + if ( bSuccess ) + { + *ppszOut = pPath; + DEBUG_MSG( "Matched '%s' -> '%s'\n", pszIn, pPath ); + } + else + { + DEBUG_MSG( "Unmatched %s\n", pszIn ); + } + +#ifndef DO_PATHMATCH_CACHE + return bSuccess ? kPathChanged : kPathFailed; +#else + time_t now = time(NULL); + if ( bSuccess ) + { + resultCache[ pszIn ] = std::make_pair( *ppszOut, now ); + return kPathChanged; + } + else + { + resultCache[ pszIn ] = std::make_pair( "", now ); + return kPathFailed; + } +#endif + } + return kPathFailed; +} + +// Wrapper object that manages the 'typical' usage cases of pathmatch() +class CWrap +{ +public: + CWrap( const char *pSuppliedPath, bool bAllowMismatchedBasename ) + : m_pSuppliedPath( pSuppliedPath ), m_pBestMatch( NULL ) + { + m_eResult = pathmatch( m_pSuppliedPath, &m_pBestMatch, bAllowMismatchedBasename, m_BestMatchBuf, sizeof( m_BestMatchBuf ) ); + if ( m_pBestMatch == NULL ) + { + m_pBestMatch = const_cast( m_pSuppliedPath ); + } + } + + ~CWrap() + { + if ( ( m_pBestMatch != m_pSuppliedPath ) && ( m_pBestMatch != m_BestMatchBuf ) ) + free( m_pBestMatch ); + } + + const char *GetBest() const { return m_pBestMatch; } + const char *GetOriginal() const { return m_pSuppliedPath; } + PathMod_t GetMatchResult() const { return m_eResult; } + + operator const char*() { return GetBest(); } + +private: + const char *m_pSuppliedPath; + char *m_pBestMatch; + char m_BestMatchBuf[ 512 ]; + PathMod_t m_eResult; +}; + +#ifdef MAIN_TEST +void usage() +{ + puts("pathmatch [options] "); + //puts("options:"); + //puts("\t"); + + exit(-1); +} + +void test( const char *pszFile, bool bAllowBasenameMismatch ) +{ + char *pNewPath; + char NewPathBuf[ 512 ]; + PathMod_t nStat = pathmatch( pszFile, &pNewPath, bAllowBasenameMismatch, NewPathBuf, sizeof( NewPathBuf ) ); + + printf("AllowMismatchedBasename: %s\n", bAllowBasenameMismatch ? "true" : "false" ); + printf("Path Was: "); + switch ( nStat ) + { + case kPathUnchanged: + puts("kPathUnchanged"); + break; + case kPathLowered: + puts("kPathLowered"); + break; + case kPathChanged: + puts("kPathChanged"); + break; + case kPathFailed: + puts("kPathFailed"); + break; + } + + printf(" Path In: %s\n", pszFile ); + printf("Path Out: %s\n", nStat == kPathUnchanged ? pszFile : pNewPath ); + + if ( pNewPath ) + free( pNewPath ); +} + +int +main(int argc, char **argv) +{ + if ( argc <= 1 || argc > 2 ) + usage(); + + test( argv[1], false ); + test( argv[1], true ); + + return 0; +} +#endif + +extern "C" { + + WRAP(freopen, FILE *, const char *path, const char *mode, FILE *stream) + { + // if mode does not have w, a, or +, it's open for read. + bool bAllowBasenameMismatch = strpbrk( mode, "wa+" ) != NULL; + CWrap mpath( path, bAllowBasenameMismatch ); + + return CALL(freopen)( mpath, mode, stream ); + } + + WRAP(fopen, FILE *, const char *path, const char *mode) + { + // if mode does not have w, a, or +, it's open for read. + bool bAllowBasenameMismatch = strpbrk( mode, "wa+" ) != NULL; + CWrap mpath( path, bAllowBasenameMismatch ); + + return CALL(fopen)( mpath, mode ); + } + + + WRAP(fopen64, FILE *, const char *path, const char *mode) + { + // if mode does not have w, a, or +, it's open for read. + bool bAllowBasenameMismatch = strpbrk( mode, "wa+" ) != NULL; + CWrap mpath( path, bAllowBasenameMismatch ); + + return CALL(fopen64)( mpath, mode ); + } + + WRAP(open, int, const char *pathname, int flags, mode_t mode) + { + bool bAllowBasenameMismatch = ((flags & (O_WRONLY | O_RDWR)) != 0); + CWrap mpath( pathname, bAllowBasenameMismatch ); + return CALL(open)( mpath, flags, mode ); + } + + WRAP(open64, int, const char *pathname, int flags, mode_t mode) + { + bool bAllowBasenameMismatch = ((flags & (O_WRONLY | O_RDWR)) != 0); + CWrap mpath( pathname, bAllowBasenameMismatch ); + return CALL(open64)( mpath, flags, mode ); + } + + int __wrap_creat(const char *pathname, mode_t mode) + { + return __wrap_open( pathname, O_CREAT|O_WRONLY|O_TRUNC, mode ); + } + + int __wrap_access(const char *pathname, int mode) + { + return __real_access( CWrap( pathname, false ), mode ); + } + + WRAP(stat, int, const char *path, struct stat *buf) + { + return CALL(stat)( CWrap( path, false ), buf ); + } + + WRAP(lstat, int, const char *path, struct stat *buf) + { + return CALL(lstat)( CWrap( path, false ), buf ); + } + + WRAP(scandir, int, const char *dirp, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) + { + return CALL(scandir)( CWrap( dirp, false ), namelist, filter, compar ); + } + + WRAP(opendir, DIR*, const char *name) + { + return CALL(opendir)( CWrap( name, false ) ); + } + + WRAP(__xstat, int, int __ver, __const char *__filename, struct stat *__stat_buf) + { + return CALL(__xstat)( __ver, CWrap( __filename, false), __stat_buf ); + } + + WRAP(__lxstat, int, int __ver, __const char *__filename, struct stat *__stat_buf) + { + return CALL(__lxstat)( __ver, CWrap( __filename, false), __stat_buf ); + } + + WRAP(__xstat64, int, int __ver, __const char *__filename, struct stat *__stat_buf) + { + return CALL(__xstat64)( __ver, CWrap( __filename, false), __stat_buf ); + } + + WRAP(__lxstat64, int, int __ver, __const char *__filename, struct stat *__stat_buf) + { + return CALL(__lxstat64)( __ver, CWrap( __filename, false), __stat_buf ); + } + + WRAP(chmod, int, const char *path, mode_t mode) + { + return CALL(chmod)( CWrap( path, false), mode ); + } + + WRAP(chown, int, const char *path, uid_t owner, gid_t group) + { + return CALL(chown)( CWrap( path, false), owner, group ); + } + + WRAP(lchown, int, const char *path, uid_t owner, gid_t group) + { + return CALL(lchown)( CWrap( path, false), owner, group ); + } + + WRAP(symlink, int, const char *oldpath, const char *newpath) + { + return CALL(symlink)( CWrap( oldpath, false), CWrap( newpath, true ) ); + } + + WRAP(link, int, const char *oldpath, const char *newpath) + { + return CALL(link)( CWrap( oldpath, false), CWrap( newpath, true ) ); + } + + WRAP(mknod, int, const char *pathname, mode_t mode, dev_t dev) + { + return CALL(mknod)( CWrap( pathname, true), mode, dev ); + } + + WRAP(mount, int, const char *source, const char *target, + const char *filesystemtype, unsigned long mountflags, + const void *data) + { + return CALL(mount)( CWrap( source, false ), CWrap( target, false ), filesystemtype, mountflags, data ); + } + + WRAP(unlink, int, const char *pathname) + { + return CALL(unlink)( CWrap( pathname, false ) ); + } + + WRAP(mkfifo, int, const char *pathname, mode_t mode) + { + return CALL(mkfifo)( CWrap( pathname, true ), mode ); + } + + WRAP(rename, int, const char *oldpath, const char *newpath) + { + return CALL(rename)( CWrap( oldpath, false), CWrap( newpath, true ) ); + } + + WRAP(utime, int, const char *filename, const struct utimbuf *times) + { + return CALL(utime)( CWrap( filename, false), times ); + } + + WRAP(utimes, int, const char *filename, const struct timeval times[2]) + { + return CALL(utimes)( CWrap( filename, false), times ); + } + + WRAP(realpath, char *, const char *path, char *resolved_path) + { + return CALL(realpath)( CWrap( path, true ), resolved_path ); + } + + WRAP(mkdir, int, const char *pathname, mode_t mode) + { + return CALL(mkdir)( CWrap( pathname, true ), mode ); + } + + WRAP(rmdir, char *, const char *pathname) + { + return CALL(rmdir)( CWrap( pathname, false ) ); + } + +}; + +#endif diff --git a/tier1/pathmatch_casefolding.h b/tier1/pathmatch_casefolding.h new file mode 100644 index 0000000..2b4381b --- /dev/null +++ b/tier1/pathmatch_casefolding.h @@ -0,0 +1,2008 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// This file was originally part of PhysicsFS (http://icculus.org/physfs/) +// (zlib license, even if Ryan hadn't written it originally.) +// +// This data was originally generated by physfs/extras/makecasefoldhashtable.pl + +#define CASEFOLDING_ARRAYLEN(x) (sizeof (x) / sizeof ((x)[0])) + +static const CaseFoldMapping case_fold_000[] = { + { 0x0202, 0x0203, 0x0000, 0x0000 }, + { 0x0404, 0x0454, 0x0000, 0x0000 }, + { 0x1E1E, 0x1E1F, 0x0000, 0x0000 }, + { 0x2C2C, 0x2C5C, 0x0000, 0x0000 }, + { 0x10404, 0x1042C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_001[] = { + { 0x0100, 0x0101, 0x0000, 0x0000 }, + { 0x0405, 0x0455, 0x0000, 0x0000 }, + { 0x0504, 0x0505, 0x0000, 0x0000 }, + { 0x2C2D, 0x2C5D, 0x0000, 0x0000 }, + { 0x10405, 0x1042D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_002[] = { + { 0x0200, 0x0201, 0x0000, 0x0000 }, + { 0x0406, 0x0456, 0x0000, 0x0000 }, + { 0x1E1C, 0x1E1D, 0x0000, 0x0000 }, + { 0x1F1D, 0x1F15, 0x0000, 0x0000 }, + { 0x2C2E, 0x2C5E, 0x0000, 0x0000 }, + { 0x10406, 0x1042E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_003[] = { + { 0x0102, 0x0103, 0x0000, 0x0000 }, + { 0x0407, 0x0457, 0x0000, 0x0000 }, + { 0x0506, 0x0507, 0x0000, 0x0000 }, + { 0x1F1C, 0x1F14, 0x0000, 0x0000 }, + { 0x10407, 0x1042F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_004[] = { + { 0x0206, 0x0207, 0x0000, 0x0000 }, + { 0x0400, 0x0450, 0x0000, 0x0000 }, + { 0x1E1A, 0x1E1B, 0x0000, 0x0000 }, + { 0x1F1B, 0x1F13, 0x0000, 0x0000 }, + { 0x2C28, 0x2C58, 0x0000, 0x0000 }, + { 0x10400, 0x10428, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_005[] = { + { 0x0104, 0x0105, 0x0000, 0x0000 }, + { 0x0401, 0x0451, 0x0000, 0x0000 }, + { 0x0500, 0x0501, 0x0000, 0x0000 }, + { 0x1F1A, 0x1F12, 0x0000, 0x0000 }, + { 0x2C29, 0x2C59, 0x0000, 0x0000 }, + { 0x10401, 0x10429, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_006[] = { + { 0x0204, 0x0205, 0x0000, 0x0000 }, + { 0x0402, 0x0452, 0x0000, 0x0000 }, + { 0x1E18, 0x1E19, 0x0000, 0x0000 }, + { 0x1F19, 0x1F11, 0x0000, 0x0000 }, + { 0x2C2A, 0x2C5A, 0x0000, 0x0000 }, + { 0x10402, 0x1042A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_007[] = { + { 0x0106, 0x0107, 0x0000, 0x0000 }, + { 0x0403, 0x0453, 0x0000, 0x0000 }, + { 0x0502, 0x0503, 0x0000, 0x0000 }, + { 0x1F18, 0x1F10, 0x0000, 0x0000 }, + { 0x2126, 0x03C9, 0x0000, 0x0000 }, + { 0x2C2B, 0x2C5B, 0x0000, 0x0000 }, + { 0x10403, 0x1042B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_008[] = { + { 0x020A, 0x020B, 0x0000, 0x0000 }, + { 0x040C, 0x045C, 0x0000, 0x0000 }, + { 0x1E16, 0x1E17, 0x0000, 0x0000 }, + { 0x2C24, 0x2C54, 0x0000, 0x0000 }, + { 0x1040C, 0x10434, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_009[] = { + { 0x0108, 0x0109, 0x0000, 0x0000 }, + { 0x040D, 0x045D, 0x0000, 0x0000 }, + { 0x050C, 0x050D, 0x0000, 0x0000 }, + { 0x2C25, 0x2C55, 0x0000, 0x0000 }, + { 0x1040D, 0x10435, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_010[] = { + { 0x0208, 0x0209, 0x0000, 0x0000 }, + { 0x040E, 0x045E, 0x0000, 0x0000 }, + { 0x1E14, 0x1E15, 0x0000, 0x0000 }, + { 0x212B, 0x00E5, 0x0000, 0x0000 }, + { 0x2C26, 0x2C56, 0x0000, 0x0000 }, + { 0x1040E, 0x10436, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_011[] = { + { 0x010A, 0x010B, 0x0000, 0x0000 }, + { 0x040F, 0x045F, 0x0000, 0x0000 }, + { 0x050E, 0x050F, 0x0000, 0x0000 }, + { 0x212A, 0x006B, 0x0000, 0x0000 }, + { 0x2C27, 0x2C57, 0x0000, 0x0000 }, + { 0x1040F, 0x10437, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_012[] = { + { 0x020E, 0x020F, 0x0000, 0x0000 }, + { 0x0408, 0x0458, 0x0000, 0x0000 }, + { 0x1E12, 0x1E13, 0x0000, 0x0000 }, + { 0x2C20, 0x2C50, 0x0000, 0x0000 }, + { 0x10408, 0x10430, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_013[] = { + { 0x010C, 0x010D, 0x0000, 0x0000 }, + { 0x0409, 0x0459, 0x0000, 0x0000 }, + { 0x0508, 0x0509, 0x0000, 0x0000 }, + { 0x2C21, 0x2C51, 0x0000, 0x0000 }, + { 0x10409, 0x10431, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_014[] = { + { 0x020C, 0x020D, 0x0000, 0x0000 }, + { 0x040A, 0x045A, 0x0000, 0x0000 }, + { 0x1E10, 0x1E11, 0x0000, 0x0000 }, + { 0x2C22, 0x2C52, 0x0000, 0x0000 }, + { 0x1040A, 0x10432, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_015[] = { + { 0x010E, 0x010F, 0x0000, 0x0000 }, + { 0x040B, 0x045B, 0x0000, 0x0000 }, + { 0x050A, 0x050B, 0x0000, 0x0000 }, + { 0x2C23, 0x2C53, 0x0000, 0x0000 }, + { 0x1040B, 0x10433, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_016[] = { + { 0x0212, 0x0213, 0x0000, 0x0000 }, + { 0x0414, 0x0434, 0x0000, 0x0000 }, + { 0x1E0E, 0x1E0F, 0x0000, 0x0000 }, + { 0x1F0F, 0x1F07, 0x0000, 0x0000 }, + { 0x10414, 0x1043C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_017[] = { + { 0x0110, 0x0111, 0x0000, 0x0000 }, + { 0x0415, 0x0435, 0x0000, 0x0000 }, + { 0x1F0E, 0x1F06, 0x0000, 0x0000 }, + { 0x10415, 0x1043D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_018[] = { + { 0x0210, 0x0211, 0x0000, 0x0000 }, + { 0x0416, 0x0436, 0x0000, 0x0000 }, + { 0x1E0C, 0x1E0D, 0x0000, 0x0000 }, + { 0x1F0D, 0x1F05, 0x0000, 0x0000 }, + { 0x10416, 0x1043E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_019[] = { + { 0x0112, 0x0113, 0x0000, 0x0000 }, + { 0x0417, 0x0437, 0x0000, 0x0000 }, + { 0x1F0C, 0x1F04, 0x0000, 0x0000 }, + { 0x10417, 0x1043F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_020[] = { + { 0x0216, 0x0217, 0x0000, 0x0000 }, + { 0x0410, 0x0430, 0x0000, 0x0000 }, + { 0x1E0A, 0x1E0B, 0x0000, 0x0000 }, + { 0x1F0B, 0x1F03, 0x0000, 0x0000 }, + { 0x10410, 0x10438, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_021[] = { + { 0x0114, 0x0115, 0x0000, 0x0000 }, + { 0x0411, 0x0431, 0x0000, 0x0000 }, + { 0x1F0A, 0x1F02, 0x0000, 0x0000 }, + { 0x10411, 0x10439, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_022[] = { + { 0x0214, 0x0215, 0x0000, 0x0000 }, + { 0x0412, 0x0432, 0x0000, 0x0000 }, + { 0x1E08, 0x1E09, 0x0000, 0x0000 }, + { 0x1F09, 0x1F01, 0x0000, 0x0000 }, + { 0x10412, 0x1043A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_023[] = { + { 0x0116, 0x0117, 0x0000, 0x0000 }, + { 0x0413, 0x0433, 0x0000, 0x0000 }, + { 0x1F08, 0x1F00, 0x0000, 0x0000 }, + { 0x10413, 0x1043B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_024[] = { + { 0x021A, 0x021B, 0x0000, 0x0000 }, + { 0x041C, 0x043C, 0x0000, 0x0000 }, + { 0x1E06, 0x1E07, 0x0000, 0x0000 }, + { 0x1041C, 0x10444, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_025[] = { + { 0x0118, 0x0119, 0x0000, 0x0000 }, + { 0x041D, 0x043D, 0x0000, 0x0000 }, + { 0x1041D, 0x10445, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_026[] = { + { 0x0218, 0x0219, 0x0000, 0x0000 }, + { 0x041E, 0x043E, 0x0000, 0x0000 }, + { 0x1E04, 0x1E05, 0x0000, 0x0000 }, + { 0x1041E, 0x10446, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_027[] = { + { 0x011A, 0x011B, 0x0000, 0x0000 }, + { 0x041F, 0x043F, 0x0000, 0x0000 }, + { 0x1041F, 0x10447, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_028[] = { + { 0x021E, 0x021F, 0x0000, 0x0000 }, + { 0x0418, 0x0438, 0x0000, 0x0000 }, + { 0x1E02, 0x1E03, 0x0000, 0x0000 }, + { 0x10418, 0x10440, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_029[] = { + { 0x011C, 0x011D, 0x0000, 0x0000 }, + { 0x0419, 0x0439, 0x0000, 0x0000 }, + { 0x10419, 0x10441, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_030[] = { + { 0x021C, 0x021D, 0x0000, 0x0000 }, + { 0x041A, 0x043A, 0x0000, 0x0000 }, + { 0x1E00, 0x1E01, 0x0000, 0x0000 }, + { 0x1041A, 0x10442, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_031[] = { + { 0x011E, 0x011F, 0x0000, 0x0000 }, + { 0x041B, 0x043B, 0x0000, 0x0000 }, + { 0x1041B, 0x10443, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_032[] = { + { 0x0222, 0x0223, 0x0000, 0x0000 }, + { 0x0424, 0x0444, 0x0000, 0x0000 }, + { 0x1E3E, 0x1E3F, 0x0000, 0x0000 }, + { 0x1F3F, 0x1F37, 0x0000, 0x0000 }, + { 0x2C0C, 0x2C3C, 0x0000, 0x0000 }, + { 0x10424, 0x1044C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_033[] = { + { 0x0120, 0x0121, 0x0000, 0x0000 }, + { 0x0425, 0x0445, 0x0000, 0x0000 }, + { 0x1F3E, 0x1F36, 0x0000, 0x0000 }, + { 0x2C0D, 0x2C3D, 0x0000, 0x0000 }, + { 0x10425, 0x1044D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_034[] = { + { 0x0220, 0x019E, 0x0000, 0x0000 }, + { 0x0426, 0x0446, 0x0000, 0x0000 }, + { 0x1E3C, 0x1E3D, 0x0000, 0x0000 }, + { 0x1F3D, 0x1F35, 0x0000, 0x0000 }, + { 0x2C0E, 0x2C3E, 0x0000, 0x0000 }, + { 0x10426, 0x1044E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_035[] = { + { 0x0122, 0x0123, 0x0000, 0x0000 }, + { 0x0427, 0x0447, 0x0000, 0x0000 }, + { 0x1F3C, 0x1F34, 0x0000, 0x0000 }, + { 0x2C0F, 0x2C3F, 0x0000, 0x0000 }, + { 0x10427, 0x1044F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_036[] = { + { 0x0226, 0x0227, 0x0000, 0x0000 }, + { 0x0420, 0x0440, 0x0000, 0x0000 }, + { 0x1E3A, 0x1E3B, 0x0000, 0x0000 }, + { 0x1F3B, 0x1F33, 0x0000, 0x0000 }, + { 0x2C08, 0x2C38, 0x0000, 0x0000 }, + { 0x10420, 0x10448, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_037[] = { + { 0x0124, 0x0125, 0x0000, 0x0000 }, + { 0x0421, 0x0441, 0x0000, 0x0000 }, + { 0x1F3A, 0x1F32, 0x0000, 0x0000 }, + { 0x2C09, 0x2C39, 0x0000, 0x0000 }, + { 0x10421, 0x10449, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_038[] = { + { 0x0224, 0x0225, 0x0000, 0x0000 }, + { 0x0422, 0x0442, 0x0000, 0x0000 }, + { 0x1E38, 0x1E39, 0x0000, 0x0000 }, + { 0x1F39, 0x1F31, 0x0000, 0x0000 }, + { 0x2C0A, 0x2C3A, 0x0000, 0x0000 }, + { 0x10422, 0x1044A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_039[] = { + { 0x0126, 0x0127, 0x0000, 0x0000 }, + { 0x0423, 0x0443, 0x0000, 0x0000 }, + { 0x1F38, 0x1F30, 0x0000, 0x0000 }, + { 0x2C0B, 0x2C3B, 0x0000, 0x0000 }, + { 0x10423, 0x1044B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_040[] = { + { 0x022A, 0x022B, 0x0000, 0x0000 }, + { 0x042C, 0x044C, 0x0000, 0x0000 }, + { 0x1E36, 0x1E37, 0x0000, 0x0000 }, + { 0x2C04, 0x2C34, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_041[] = { + { 0x0128, 0x0129, 0x0000, 0x0000 }, + { 0x042D, 0x044D, 0x0000, 0x0000 }, + { 0x2C05, 0x2C35, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_042[] = { + { 0x0228, 0x0229, 0x0000, 0x0000 }, + { 0x042E, 0x044E, 0x0000, 0x0000 }, + { 0x1E34, 0x1E35, 0x0000, 0x0000 }, + { 0x2C06, 0x2C36, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_043[] = { + { 0x012A, 0x012B, 0x0000, 0x0000 }, + { 0x042F, 0x044F, 0x0000, 0x0000 }, + { 0x2C07, 0x2C37, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_044[] = { + { 0x022E, 0x022F, 0x0000, 0x0000 }, + { 0x0428, 0x0448, 0x0000, 0x0000 }, + { 0x1E32, 0x1E33, 0x0000, 0x0000 }, + { 0x2C00, 0x2C30, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_045[] = { + { 0x012C, 0x012D, 0x0000, 0x0000 }, + { 0x0429, 0x0449, 0x0000, 0x0000 }, + { 0x2C01, 0x2C31, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_046[] = { + { 0x022C, 0x022D, 0x0000, 0x0000 }, + { 0x042A, 0x044A, 0x0000, 0x0000 }, + { 0x1E30, 0x1E31, 0x0000, 0x0000 }, + { 0x2C02, 0x2C32, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_047[] = { + { 0x012E, 0x012F, 0x0000, 0x0000 }, + { 0x042B, 0x044B, 0x0000, 0x0000 }, + { 0x2C03, 0x2C33, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_048[] = { + { 0x0232, 0x0233, 0x0000, 0x0000 }, + { 0x0535, 0x0565, 0x0000, 0x0000 }, + { 0x1E2E, 0x1E2F, 0x0000, 0x0000 }, + { 0x1F2F, 0x1F27, 0x0000, 0x0000 }, + { 0x2C1C, 0x2C4C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_049[] = { + { 0x0130, 0x0069, 0x0307, 0x0000 }, + { 0x0534, 0x0564, 0x0000, 0x0000 }, + { 0x1F2E, 0x1F26, 0x0000, 0x0000 }, + { 0x2C1D, 0x2C4D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_050[] = { + { 0x0230, 0x0231, 0x0000, 0x0000 }, + { 0x0537, 0x0567, 0x0000, 0x0000 }, + { 0x1E2C, 0x1E2D, 0x0000, 0x0000 }, + { 0x1F2D, 0x1F25, 0x0000, 0x0000 }, + { 0x2C1E, 0x2C4E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_051[] = { + { 0x0132, 0x0133, 0x0000, 0x0000 }, + { 0x0536, 0x0566, 0x0000, 0x0000 }, + { 0x1F2C, 0x1F24, 0x0000, 0x0000 }, + { 0x2C1F, 0x2C4F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_052[] = { + { 0x0531, 0x0561, 0x0000, 0x0000 }, + { 0x1E2A, 0x1E2B, 0x0000, 0x0000 }, + { 0x1F2B, 0x1F23, 0x0000, 0x0000 }, + { 0x2C18, 0x2C48, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_053[] = { + { 0x0134, 0x0135, 0x0000, 0x0000 }, + { 0x1F2A, 0x1F22, 0x0000, 0x0000 }, + { 0x2C19, 0x2C49, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_054[] = { + { 0x0533, 0x0563, 0x0000, 0x0000 }, + { 0x1E28, 0x1E29, 0x0000, 0x0000 }, + { 0x1F29, 0x1F21, 0x0000, 0x0000 }, + { 0x2C1A, 0x2C4A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_055[] = { + { 0x0136, 0x0137, 0x0000, 0x0000 }, + { 0x0532, 0x0562, 0x0000, 0x0000 }, + { 0x1F28, 0x1F20, 0x0000, 0x0000 }, + { 0x2C1B, 0x2C4B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_056[] = { + { 0x0139, 0x013A, 0x0000, 0x0000 }, + { 0x053D, 0x056D, 0x0000, 0x0000 }, + { 0x1E26, 0x1E27, 0x0000, 0x0000 }, + { 0x2C14, 0x2C44, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_057[] = { + { 0x023B, 0x023C, 0x0000, 0x0000 }, + { 0x053C, 0x056C, 0x0000, 0x0000 }, + { 0x2C15, 0x2C45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_058[] = { + { 0x013B, 0x013C, 0x0000, 0x0000 }, + { 0x053F, 0x056F, 0x0000, 0x0000 }, + { 0x1E24, 0x1E25, 0x0000, 0x0000 }, + { 0x2C16, 0x2C46, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_059[] = { + { 0x053E, 0x056E, 0x0000, 0x0000 }, + { 0x2C17, 0x2C47, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_060[] = { + { 0x013D, 0x013E, 0x0000, 0x0000 }, + { 0x0539, 0x0569, 0x0000, 0x0000 }, + { 0x1E22, 0x1E23, 0x0000, 0x0000 }, + { 0x2C10, 0x2C40, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_061[] = { + { 0x0538, 0x0568, 0x0000, 0x0000 }, + { 0x2C11, 0x2C41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_062[] = { + { 0x013F, 0x0140, 0x0000, 0x0000 }, + { 0x053B, 0x056B, 0x0000, 0x0000 }, + { 0x1E20, 0x1E21, 0x0000, 0x0000 }, + { 0x2C12, 0x2C42, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_063[] = { + { 0x023D, 0x019A, 0x0000, 0x0000 }, + { 0x053A, 0x056A, 0x0000, 0x0000 }, + { 0x2C13, 0x2C43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_064[] = { + { 0x0141, 0x0142, 0x0000, 0x0000 }, + { 0x0545, 0x0575, 0x0000, 0x0000 }, + { 0x1E5E, 0x1E5F, 0x0000, 0x0000 }, + { 0x1F5F, 0x1F57, 0x0000, 0x0000 }, + { 0x2161, 0x2171, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_065[] = { + { 0x0041, 0x0061, 0x0000, 0x0000 }, + { 0x0544, 0x0574, 0x0000, 0x0000 }, + { 0x2160, 0x2170, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_066[] = { + { 0x0042, 0x0062, 0x0000, 0x0000 }, + { 0x0143, 0x0144, 0x0000, 0x0000 }, + { 0x0547, 0x0577, 0x0000, 0x0000 }, + { 0x1E5C, 0x1E5D, 0x0000, 0x0000 }, + { 0x1F5D, 0x1F55, 0x0000, 0x0000 }, + { 0x2163, 0x2173, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_067[] = { + { 0x0043, 0x0063, 0x0000, 0x0000 }, + { 0x0241, 0x0294, 0x0000, 0x0000 }, + { 0x0546, 0x0576, 0x0000, 0x0000 }, + { 0x2162, 0x2172, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_068[] = { + { 0x0044, 0x0064, 0x0000, 0x0000 }, + { 0x0145, 0x0146, 0x0000, 0x0000 }, + { 0x0541, 0x0571, 0x0000, 0x0000 }, + { 0x1E5A, 0x1E5B, 0x0000, 0x0000 }, + { 0x1F5B, 0x1F53, 0x0000, 0x0000 }, + { 0x2165, 0x2175, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_069[] = { + { 0x0045, 0x0065, 0x0000, 0x0000 }, + { 0x0540, 0x0570, 0x0000, 0x0000 }, + { 0x2164, 0x2174, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_070[] = { + { 0x0046, 0x0066, 0x0000, 0x0000 }, + { 0x0147, 0x0148, 0x0000, 0x0000 }, + { 0x0345, 0x03B9, 0x0000, 0x0000 }, + { 0x0543, 0x0573, 0x0000, 0x0000 }, + { 0x1E58, 0x1E59, 0x0000, 0x0000 }, + { 0x1F59, 0x1F51, 0x0000, 0x0000 }, + { 0x2167, 0x2177, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_071[] = { + { 0x0047, 0x0067, 0x0000, 0x0000 }, + { 0x0542, 0x0572, 0x0000, 0x0000 }, + { 0x2166, 0x2176, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_072[] = { + { 0x0048, 0x0068, 0x0000, 0x0000 }, + { 0x0149, 0x02BC, 0x006E, 0x0000 }, + { 0x054D, 0x057D, 0x0000, 0x0000 }, + { 0x1E56, 0x1E57, 0x0000, 0x0000 }, + { 0x2169, 0x2179, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_073[] = { + { 0x0049, 0x0069, 0x0000, 0x0000 }, + { 0x054C, 0x057C, 0x0000, 0x0000 }, + { 0x1F56, 0x03C5, 0x0313, 0x0342 }, + { 0x2168, 0x2178, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_074[] = { + { 0x004A, 0x006A, 0x0000, 0x0000 }, + { 0x054F, 0x057F, 0x0000, 0x0000 }, + { 0x1E54, 0x1E55, 0x0000, 0x0000 }, + { 0x216B, 0x217B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_075[] = { + { 0x004B, 0x006B, 0x0000, 0x0000 }, + { 0x014A, 0x014B, 0x0000, 0x0000 }, + { 0x054E, 0x057E, 0x0000, 0x0000 }, + { 0x1F54, 0x03C5, 0x0313, 0x0301 }, + { 0x216A, 0x217A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_076[] = { + { 0x004C, 0x006C, 0x0000, 0x0000 }, + { 0x0549, 0x0579, 0x0000, 0x0000 }, + { 0x1E52, 0x1E53, 0x0000, 0x0000 }, + { 0x216D, 0x217D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_077[] = { + { 0x004D, 0x006D, 0x0000, 0x0000 }, + { 0x014C, 0x014D, 0x0000, 0x0000 }, + { 0x0548, 0x0578, 0x0000, 0x0000 }, + { 0x1F52, 0x03C5, 0x0313, 0x0300 }, + { 0x216C, 0x217C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_078[] = { + { 0x004E, 0x006E, 0x0000, 0x0000 }, + { 0x054B, 0x057B, 0x0000, 0x0000 }, + { 0x1E50, 0x1E51, 0x0000, 0x0000 }, + { 0x216F, 0x217F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_079[] = { + { 0x004F, 0x006F, 0x0000, 0x0000 }, + { 0x014E, 0x014F, 0x0000, 0x0000 }, + { 0x054A, 0x057A, 0x0000, 0x0000 }, + { 0x1F50, 0x03C5, 0x0313, 0x0000 }, + { 0x216E, 0x217E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_080[] = { + { 0x0050, 0x0070, 0x0000, 0x0000 }, + { 0x0555, 0x0585, 0x0000, 0x0000 }, + { 0x1E4E, 0x1E4F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_081[] = { + { 0x0051, 0x0071, 0x0000, 0x0000 }, + { 0x0150, 0x0151, 0x0000, 0x0000 }, + { 0x0554, 0x0584, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_082[] = { + { 0x0052, 0x0072, 0x0000, 0x0000 }, + { 0x1E4C, 0x1E4D, 0x0000, 0x0000 }, + { 0x1F4D, 0x1F45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_083[] = { + { 0x0053, 0x0073, 0x0000, 0x0000 }, + { 0x0152, 0x0153, 0x0000, 0x0000 }, + { 0x0556, 0x0586, 0x0000, 0x0000 }, + { 0x1F4C, 0x1F44, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_084[] = { + { 0x0054, 0x0074, 0x0000, 0x0000 }, + { 0x0551, 0x0581, 0x0000, 0x0000 }, + { 0x1E4A, 0x1E4B, 0x0000, 0x0000 }, + { 0x1F4B, 0x1F43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_085[] = { + { 0x0055, 0x0075, 0x0000, 0x0000 }, + { 0x0154, 0x0155, 0x0000, 0x0000 }, + { 0x0550, 0x0580, 0x0000, 0x0000 }, + { 0x1F4A, 0x1F42, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_086[] = { + { 0x0056, 0x0076, 0x0000, 0x0000 }, + { 0x0553, 0x0583, 0x0000, 0x0000 }, + { 0x1E48, 0x1E49, 0x0000, 0x0000 }, + { 0x1F49, 0x1F41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_087[] = { + { 0x0057, 0x0077, 0x0000, 0x0000 }, + { 0x0156, 0x0157, 0x0000, 0x0000 }, + { 0x0552, 0x0582, 0x0000, 0x0000 }, + { 0x1F48, 0x1F40, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_088[] = { + { 0x0058, 0x0078, 0x0000, 0x0000 }, + { 0x1E46, 0x1E47, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_089[] = { + { 0x0059, 0x0079, 0x0000, 0x0000 }, + { 0x0158, 0x0159, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_090[] = { + { 0x005A, 0x007A, 0x0000, 0x0000 }, + { 0x1E44, 0x1E45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_091[] = { + { 0x015A, 0x015B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_092[] = { + { 0x1E42, 0x1E43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_093[] = { + { 0x015C, 0x015D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_094[] = { + { 0x1E40, 0x1E41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_095[] = { + { 0x015E, 0x015F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_096[] = { + { 0x0464, 0x0465, 0x0000, 0x0000 }, + { 0x1E7E, 0x1E7F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_097[] = { + { 0x0160, 0x0161, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_098[] = { + { 0x0466, 0x0467, 0x0000, 0x0000 }, + { 0x1E7C, 0x1E7D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_099[] = { + { 0x0162, 0x0163, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_100[] = { + { 0x0460, 0x0461, 0x0000, 0x0000 }, + { 0x1E7A, 0x1E7B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_101[] = { + { 0x0164, 0x0165, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_102[] = { + { 0x0462, 0x0463, 0x0000, 0x0000 }, + { 0x1E78, 0x1E79, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_103[] = { + { 0x0166, 0x0167, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_104[] = { + { 0x046C, 0x046D, 0x0000, 0x0000 }, + { 0x1E76, 0x1E77, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_105[] = { + { 0x0168, 0x0169, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_106[] = { + { 0x046E, 0x046F, 0x0000, 0x0000 }, + { 0x1E74, 0x1E75, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_107[] = { + { 0x016A, 0x016B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_108[] = { + { 0x0468, 0x0469, 0x0000, 0x0000 }, + { 0x1E72, 0x1E73, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_109[] = { + { 0x016C, 0x016D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_110[] = { + { 0x046A, 0x046B, 0x0000, 0x0000 }, + { 0x1E70, 0x1E71, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_111[] = { + { 0x016E, 0x016F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_112[] = { + { 0x0474, 0x0475, 0x0000, 0x0000 }, + { 0x1E6E, 0x1E6F, 0x0000, 0x0000 }, + { 0x1F6F, 0x1F67, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_113[] = { + { 0x0170, 0x0171, 0x0000, 0x0000 }, + { 0x1F6E, 0x1F66, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_114[] = { + { 0x0476, 0x0477, 0x0000, 0x0000 }, + { 0x1E6C, 0x1E6D, 0x0000, 0x0000 }, + { 0x1F6D, 0x1F65, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_115[] = { + { 0x0172, 0x0173, 0x0000, 0x0000 }, + { 0x1F6C, 0x1F64, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_116[] = { + { 0x0470, 0x0471, 0x0000, 0x0000 }, + { 0x1E6A, 0x1E6B, 0x0000, 0x0000 }, + { 0x1F6B, 0x1F63, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_117[] = { + { 0x0174, 0x0175, 0x0000, 0x0000 }, + { 0x1F6A, 0x1F62, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_118[] = { + { 0x0472, 0x0473, 0x0000, 0x0000 }, + { 0x1E68, 0x1E69, 0x0000, 0x0000 }, + { 0x1F69, 0x1F61, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_119[] = { + { 0x0176, 0x0177, 0x0000, 0x0000 }, + { 0x1F68, 0x1F60, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_120[] = { + { 0x0179, 0x017A, 0x0000, 0x0000 }, + { 0x047C, 0x047D, 0x0000, 0x0000 }, + { 0x1E66, 0x1E67, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_121[] = { + { 0x0178, 0x00FF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_122[] = { + { 0x017B, 0x017C, 0x0000, 0x0000 }, + { 0x047E, 0x047F, 0x0000, 0x0000 }, + { 0x1E64, 0x1E65, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_124[] = { + { 0x017D, 0x017E, 0x0000, 0x0000 }, + { 0x0478, 0x0479, 0x0000, 0x0000 }, + { 0x1E62, 0x1E63, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_126[] = { + { 0x017F, 0x0073, 0x0000, 0x0000 }, + { 0x047A, 0x047B, 0x0000, 0x0000 }, + { 0x1E60, 0x1E61, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_128[] = { + { 0x0181, 0x0253, 0x0000, 0x0000 }, + { 0x1F9F, 0x1F27, 0x03B9, 0x0000 }, + { 0x2CAC, 0x2CAD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_129[] = { + { 0x1F9E, 0x1F26, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_130[] = { + { 0x0587, 0x0565, 0x0582, 0x0000 }, + { 0x1F9D, 0x1F25, 0x03B9, 0x0000 }, + { 0x2CAE, 0x2CAF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_131[] = { + { 0x0182, 0x0183, 0x0000, 0x0000 }, + { 0x1F9C, 0x1F24, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_132[] = { + { 0x0480, 0x0481, 0x0000, 0x0000 }, + { 0x1E9A, 0x0061, 0x02BE, 0x0000 }, + { 0x1F9B, 0x1F23, 0x03B9, 0x0000 }, + { 0x2CA8, 0x2CA9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_133[] = { + { 0x0184, 0x0185, 0x0000, 0x0000 }, + { 0x0386, 0x03AC, 0x0000, 0x0000 }, + { 0x1E9B, 0x1E61, 0x0000, 0x0000 }, + { 0x1F9A, 0x1F22, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_134[] = { + { 0x0187, 0x0188, 0x0000, 0x0000 }, + { 0x1E98, 0x0077, 0x030A, 0x0000 }, + { 0x1F99, 0x1F21, 0x03B9, 0x0000 }, + { 0x2CAA, 0x2CAB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_135[] = { + { 0x0186, 0x0254, 0x0000, 0x0000 }, + { 0x1E99, 0x0079, 0x030A, 0x0000 }, + { 0x1F98, 0x1F20, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_136[] = { + { 0x0189, 0x0256, 0x0000, 0x0000 }, + { 0x048C, 0x048D, 0x0000, 0x0000 }, + { 0x1E96, 0x0068, 0x0331, 0x0000 }, + { 0x1F97, 0x1F27, 0x03B9, 0x0000 }, + { 0x2CA4, 0x2CA5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_137[] = { + { 0x038A, 0x03AF, 0x0000, 0x0000 }, + { 0x1E97, 0x0074, 0x0308, 0x0000 }, + { 0x1F96, 0x1F26, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_138[] = { + { 0x018B, 0x018C, 0x0000, 0x0000 }, + { 0x0389, 0x03AE, 0x0000, 0x0000 }, + { 0x048E, 0x048F, 0x0000, 0x0000 }, + { 0x1E94, 0x1E95, 0x0000, 0x0000 }, + { 0x1F95, 0x1F25, 0x03B9, 0x0000 }, + { 0x2CA6, 0x2CA7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_139[] = { + { 0x018A, 0x0257, 0x0000, 0x0000 }, + { 0x0388, 0x03AD, 0x0000, 0x0000 }, + { 0x1F94, 0x1F24, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_140[] = { + { 0x038F, 0x03CE, 0x0000, 0x0000 }, + { 0x1E92, 0x1E93, 0x0000, 0x0000 }, + { 0x1F93, 0x1F23, 0x03B9, 0x0000 }, + { 0x2CA0, 0x2CA1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_141[] = { + { 0x038E, 0x03CD, 0x0000, 0x0000 }, + { 0x1F92, 0x1F22, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_142[] = { + { 0x018F, 0x0259, 0x0000, 0x0000 }, + { 0x048A, 0x048B, 0x0000, 0x0000 }, + { 0x1E90, 0x1E91, 0x0000, 0x0000 }, + { 0x1F91, 0x1F21, 0x03B9, 0x0000 }, + { 0x2CA2, 0x2CA3, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_143[] = { + { 0x018E, 0x01DD, 0x0000, 0x0000 }, + { 0x038C, 0x03CC, 0x0000, 0x0000 }, + { 0x1F90, 0x1F20, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_144[] = { + { 0x0191, 0x0192, 0x0000, 0x0000 }, + { 0x0393, 0x03B3, 0x0000, 0x0000 }, + { 0x0494, 0x0495, 0x0000, 0x0000 }, + { 0x1E8E, 0x1E8F, 0x0000, 0x0000 }, + { 0x1F8F, 0x1F07, 0x03B9, 0x0000 }, + { 0x2CBC, 0x2CBD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_145[] = { + { 0x0190, 0x025B, 0x0000, 0x0000 }, + { 0x0392, 0x03B2, 0x0000, 0x0000 }, + { 0x1F8E, 0x1F06, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_146[] = { + { 0x0193, 0x0260, 0x0000, 0x0000 }, + { 0x0391, 0x03B1, 0x0000, 0x0000 }, + { 0x0496, 0x0497, 0x0000, 0x0000 }, + { 0x1E8C, 0x1E8D, 0x0000, 0x0000 }, + { 0x1F8D, 0x1F05, 0x03B9, 0x0000 }, + { 0x24B6, 0x24D0, 0x0000, 0x0000 }, + { 0x2CBE, 0x2CBF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_147[] = { + { 0x0390, 0x03B9, 0x0308, 0x0301 }, + { 0x1F8C, 0x1F04, 0x03B9, 0x0000 }, + { 0x24B7, 0x24D1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_148[] = { + { 0x0397, 0x03B7, 0x0000, 0x0000 }, + { 0x0490, 0x0491, 0x0000, 0x0000 }, + { 0x1E8A, 0x1E8B, 0x0000, 0x0000 }, + { 0x1F8B, 0x1F03, 0x03B9, 0x0000 }, + { 0x2CB8, 0x2CB9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_149[] = { + { 0x0194, 0x0263, 0x0000, 0x0000 }, + { 0x0396, 0x03B6, 0x0000, 0x0000 }, + { 0x1F8A, 0x1F02, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_150[] = { + { 0x0197, 0x0268, 0x0000, 0x0000 }, + { 0x0395, 0x03B5, 0x0000, 0x0000 }, + { 0x0492, 0x0493, 0x0000, 0x0000 }, + { 0x1E88, 0x1E89, 0x0000, 0x0000 }, + { 0x1F89, 0x1F01, 0x03B9, 0x0000 }, + { 0x2CBA, 0x2CBB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_151[] = { + { 0x0196, 0x0269, 0x0000, 0x0000 }, + { 0x0394, 0x03B4, 0x0000, 0x0000 }, + { 0x1F88, 0x1F00, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_152[] = { + { 0x039B, 0x03BB, 0x0000, 0x0000 }, + { 0x049C, 0x049D, 0x0000, 0x0000 }, + { 0x1E86, 0x1E87, 0x0000, 0x0000 }, + { 0x1F87, 0x1F07, 0x03B9, 0x0000 }, + { 0x24BC, 0x24D6, 0x0000, 0x0000 }, + { 0x2CB4, 0x2CB5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_153[] = { + { 0x0198, 0x0199, 0x0000, 0x0000 }, + { 0x039A, 0x03BA, 0x0000, 0x0000 }, + { 0x1F86, 0x1F06, 0x03B9, 0x0000 }, + { 0x24BD, 0x24D7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_154[] = { + { 0x0399, 0x03B9, 0x0000, 0x0000 }, + { 0x049E, 0x049F, 0x0000, 0x0000 }, + { 0x1E84, 0x1E85, 0x0000, 0x0000 }, + { 0x1F85, 0x1F05, 0x03B9, 0x0000 }, + { 0x24BE, 0x24D8, 0x0000, 0x0000 }, + { 0x2CB6, 0x2CB7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_155[] = { + { 0x0398, 0x03B8, 0x0000, 0x0000 }, + { 0x1F84, 0x1F04, 0x03B9, 0x0000 }, + { 0x24BF, 0x24D9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_156[] = { + { 0x019D, 0x0272, 0x0000, 0x0000 }, + { 0x039F, 0x03BF, 0x0000, 0x0000 }, + { 0x0498, 0x0499, 0x0000, 0x0000 }, + { 0x1E82, 0x1E83, 0x0000, 0x0000 }, + { 0x1F83, 0x1F03, 0x03B9, 0x0000 }, + { 0x24B8, 0x24D2, 0x0000, 0x0000 }, + { 0x2CB0, 0x2CB1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_157[] = { + { 0x019C, 0x026F, 0x0000, 0x0000 }, + { 0x039E, 0x03BE, 0x0000, 0x0000 }, + { 0x1F82, 0x1F02, 0x03B9, 0x0000 }, + { 0x24B9, 0x24D3, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_158[] = { + { 0x019F, 0x0275, 0x0000, 0x0000 }, + { 0x039D, 0x03BD, 0x0000, 0x0000 }, + { 0x049A, 0x049B, 0x0000, 0x0000 }, + { 0x1E80, 0x1E81, 0x0000, 0x0000 }, + { 0x1F81, 0x1F01, 0x03B9, 0x0000 }, + { 0x24BA, 0x24D4, 0x0000, 0x0000 }, + { 0x2CB2, 0x2CB3, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_159[] = { + { 0x039C, 0x03BC, 0x0000, 0x0000 }, + { 0x1F80, 0x1F00, 0x03B9, 0x0000 }, + { 0x24BB, 0x24D5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_160[] = { + { 0x03A3, 0x03C3, 0x0000, 0x0000 }, + { 0x04A4, 0x04A5, 0x0000, 0x0000 }, + { 0x10B0, 0x2D10, 0x0000, 0x0000 }, + { 0x1EBE, 0x1EBF, 0x0000, 0x0000 }, + { 0x2C8C, 0x2C8D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_161[] = { + { 0x01A0, 0x01A1, 0x0000, 0x0000 }, + { 0x10B1, 0x2D11, 0x0000, 0x0000 }, + { 0x1FBE, 0x03B9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_162[] = { + { 0x03A1, 0x03C1, 0x0000, 0x0000 }, + { 0x04A6, 0x04A7, 0x0000, 0x0000 }, + { 0x10B2, 0x2D12, 0x0000, 0x0000 }, + { 0x1EBC, 0x1EBD, 0x0000, 0x0000 }, + { 0x2C8E, 0x2C8F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_163[] = { + { 0x01A2, 0x01A3, 0x0000, 0x0000 }, + { 0x03A0, 0x03C0, 0x0000, 0x0000 }, + { 0x10B3, 0x2D13, 0x0000, 0x0000 }, + { 0x1FBC, 0x03B1, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_164[] = { + { 0x03A7, 0x03C7, 0x0000, 0x0000 }, + { 0x04A0, 0x04A1, 0x0000, 0x0000 }, + { 0x10B4, 0x2D14, 0x0000, 0x0000 }, + { 0x1EBA, 0x1EBB, 0x0000, 0x0000 }, + { 0x1FBB, 0x1F71, 0x0000, 0x0000 }, + { 0x2C88, 0x2C89, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_165[] = { + { 0x01A4, 0x01A5, 0x0000, 0x0000 }, + { 0x03A6, 0x03C6, 0x0000, 0x0000 }, + { 0x10B5, 0x2D15, 0x0000, 0x0000 }, + { 0x1FBA, 0x1F70, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_166[] = { + { 0x01A7, 0x01A8, 0x0000, 0x0000 }, + { 0x03A5, 0x03C5, 0x0000, 0x0000 }, + { 0x04A2, 0x04A3, 0x0000, 0x0000 }, + { 0x10B6, 0x2D16, 0x0000, 0x0000 }, + { 0x1EB8, 0x1EB9, 0x0000, 0x0000 }, + { 0x1FB9, 0x1FB1, 0x0000, 0x0000 }, + { 0x2C8A, 0x2C8B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_167[] = { + { 0x01A6, 0x0280, 0x0000, 0x0000 }, + { 0x03A4, 0x03C4, 0x0000, 0x0000 }, + { 0x10B7, 0x2D17, 0x0000, 0x0000 }, + { 0x1FB8, 0x1FB0, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_168[] = { + { 0x01A9, 0x0283, 0x0000, 0x0000 }, + { 0x03AB, 0x03CB, 0x0000, 0x0000 }, + { 0x04AC, 0x04AD, 0x0000, 0x0000 }, + { 0x10B8, 0x2D18, 0x0000, 0x0000 }, + { 0x1EB6, 0x1EB7, 0x0000, 0x0000 }, + { 0x1FB7, 0x03B1, 0x0342, 0x03B9 }, + { 0x2C84, 0x2C85, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_169[] = { + { 0x03AA, 0x03CA, 0x0000, 0x0000 }, + { 0x10B9, 0x2D19, 0x0000, 0x0000 }, + { 0x1FB6, 0x03B1, 0x0342, 0x0000 } +}; + +static const CaseFoldMapping case_fold_170[] = { + { 0x03A9, 0x03C9, 0x0000, 0x0000 }, + { 0x04AE, 0x04AF, 0x0000, 0x0000 }, + { 0x10BA, 0x2D1A, 0x0000, 0x0000 }, + { 0x1EB4, 0x1EB5, 0x0000, 0x0000 }, + { 0x2C86, 0x2C87, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_171[] = { + { 0x03A8, 0x03C8, 0x0000, 0x0000 }, + { 0x10BB, 0x2D1B, 0x0000, 0x0000 }, + { 0x1FB4, 0x03AC, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_172[] = { + { 0x04A8, 0x04A9, 0x0000, 0x0000 }, + { 0x10BC, 0x2D1C, 0x0000, 0x0000 }, + { 0x1EB2, 0x1EB3, 0x0000, 0x0000 }, + { 0x1FB3, 0x03B1, 0x03B9, 0x0000 }, + { 0x2C80, 0x2C81, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_173[] = { + { 0x01AC, 0x01AD, 0x0000, 0x0000 }, + { 0x10BD, 0x2D1D, 0x0000, 0x0000 }, + { 0x1FB2, 0x1F70, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_174[] = { + { 0x01AF, 0x01B0, 0x0000, 0x0000 }, + { 0x04AA, 0x04AB, 0x0000, 0x0000 }, + { 0x10BE, 0x2D1E, 0x0000, 0x0000 }, + { 0x1EB0, 0x1EB1, 0x0000, 0x0000 }, + { 0x2C82, 0x2C83, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_175[] = { + { 0x01AE, 0x0288, 0x0000, 0x0000 }, + { 0x10BF, 0x2D1F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_176[] = { + { 0x01B1, 0x028A, 0x0000, 0x0000 }, + { 0x04B4, 0x04B5, 0x0000, 0x0000 }, + { 0x10A0, 0x2D00, 0x0000, 0x0000 }, + { 0x1EAE, 0x1EAF, 0x0000, 0x0000 }, + { 0x1FAF, 0x1F67, 0x03B9, 0x0000 }, + { 0x2C9C, 0x2C9D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_177[] = { + { 0x10A1, 0x2D01, 0x0000, 0x0000 }, + { 0x1FAE, 0x1F66, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_178[] = { + { 0x01B3, 0x01B4, 0x0000, 0x0000 }, + { 0x04B6, 0x04B7, 0x0000, 0x0000 }, + { 0x10A2, 0x2D02, 0x0000, 0x0000 }, + { 0x1EAC, 0x1EAD, 0x0000, 0x0000 }, + { 0x1FAD, 0x1F65, 0x03B9, 0x0000 }, + { 0x2C9E, 0x2C9F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_179[] = { + { 0x01B2, 0x028B, 0x0000, 0x0000 }, + { 0x03B0, 0x03C5, 0x0308, 0x0301 }, + { 0x10A3, 0x2D03, 0x0000, 0x0000 }, + { 0x1FAC, 0x1F64, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_180[] = { + { 0x01B5, 0x01B6, 0x0000, 0x0000 }, + { 0x04B0, 0x04B1, 0x0000, 0x0000 }, + { 0x10A4, 0x2D04, 0x0000, 0x0000 }, + { 0x1EAA, 0x1EAB, 0x0000, 0x0000 }, + { 0x1FAB, 0x1F63, 0x03B9, 0x0000 }, + { 0x2C98, 0x2C99, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_181[] = { + { 0x00B5, 0x03BC, 0x0000, 0x0000 }, + { 0x10A5, 0x2D05, 0x0000, 0x0000 }, + { 0x1FAA, 0x1F62, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_182[] = { + { 0x01B7, 0x0292, 0x0000, 0x0000 }, + { 0x04B2, 0x04B3, 0x0000, 0x0000 }, + { 0x10A6, 0x2D06, 0x0000, 0x0000 }, + { 0x1EA8, 0x1EA9, 0x0000, 0x0000 }, + { 0x1FA9, 0x1F61, 0x03B9, 0x0000 }, + { 0x2C9A, 0x2C9B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_183[] = { + { 0x10A7, 0x2D07, 0x0000, 0x0000 }, + { 0x1FA8, 0x1F60, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_184[] = { + { 0x04BC, 0x04BD, 0x0000, 0x0000 }, + { 0x10A8, 0x2D08, 0x0000, 0x0000 }, + { 0x1EA6, 0x1EA7, 0x0000, 0x0000 }, + { 0x1FA7, 0x1F67, 0x03B9, 0x0000 }, + { 0x2C94, 0x2C95, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_185[] = { + { 0x01B8, 0x01B9, 0x0000, 0x0000 }, + { 0x10A9, 0x2D09, 0x0000, 0x0000 }, + { 0x1FA6, 0x1F66, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_186[] = { + { 0x04BE, 0x04BF, 0x0000, 0x0000 }, + { 0x10AA, 0x2D0A, 0x0000, 0x0000 }, + { 0x1EA4, 0x1EA5, 0x0000, 0x0000 }, + { 0x1FA5, 0x1F65, 0x03B9, 0x0000 }, + { 0x2C96, 0x2C97, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_187[] = { + { 0x10AB, 0x2D0B, 0x0000, 0x0000 }, + { 0x1FA4, 0x1F64, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_188[] = { + { 0x04B8, 0x04B9, 0x0000, 0x0000 }, + { 0x10AC, 0x2D0C, 0x0000, 0x0000 }, + { 0x1EA2, 0x1EA3, 0x0000, 0x0000 }, + { 0x1FA3, 0x1F63, 0x03B9, 0x0000 }, + { 0x2C90, 0x2C91, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_189[] = { + { 0x01BC, 0x01BD, 0x0000, 0x0000 }, + { 0x10AD, 0x2D0D, 0x0000, 0x0000 }, + { 0x1FA2, 0x1F62, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_190[] = { + { 0x04BA, 0x04BB, 0x0000, 0x0000 }, + { 0x10AE, 0x2D0E, 0x0000, 0x0000 }, + { 0x1EA0, 0x1EA1, 0x0000, 0x0000 }, + { 0x1FA1, 0x1F61, 0x03B9, 0x0000 }, + { 0x2C92, 0x2C93, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_191[] = { + { 0x10AF, 0x2D0F, 0x0000, 0x0000 }, + { 0x1FA0, 0x1F60, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_192[] = { + { 0x00C0, 0x00E0, 0x0000, 0x0000 }, + { 0x1EDE, 0x1EDF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_193[] = { + { 0x00C1, 0x00E1, 0x0000, 0x0000 }, + { 0x03C2, 0x03C3, 0x0000, 0x0000 }, + { 0x04C5, 0x04C6, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_194[] = { + { 0x00C2, 0x00E2, 0x0000, 0x0000 }, + { 0x1EDC, 0x1EDD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_195[] = { + { 0x00C3, 0x00E3, 0x0000, 0x0000 }, + { 0x04C7, 0x04C8, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_196[] = { + { 0x00C4, 0x00E4, 0x0000, 0x0000 }, + { 0x01C5, 0x01C6, 0x0000, 0x0000 }, + { 0x1EDA, 0x1EDB, 0x0000, 0x0000 }, + { 0x1FDB, 0x1F77, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_197[] = { + { 0x00C5, 0x00E5, 0x0000, 0x0000 }, + { 0x01C4, 0x01C6, 0x0000, 0x0000 }, + { 0x04C1, 0x04C2, 0x0000, 0x0000 }, + { 0x1FDA, 0x1F76, 0x0000, 0x0000 }, + { 0xFF3A, 0xFF5A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_198[] = { + { 0x00C6, 0x00E6, 0x0000, 0x0000 }, + { 0x01C7, 0x01C9, 0x0000, 0x0000 }, + { 0x1ED8, 0x1ED9, 0x0000, 0x0000 }, + { 0x1FD9, 0x1FD1, 0x0000, 0x0000 }, + { 0xFF39, 0xFF59, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_199[] = { + { 0x00C7, 0x00E7, 0x0000, 0x0000 }, + { 0x04C3, 0x04C4, 0x0000, 0x0000 }, + { 0x1FD8, 0x1FD0, 0x0000, 0x0000 }, + { 0xFF38, 0xFF58, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_200[] = { + { 0x00C8, 0x00E8, 0x0000, 0x0000 }, + { 0x1ED6, 0x1ED7, 0x0000, 0x0000 }, + { 0x1FD7, 0x03B9, 0x0308, 0x0342 }, + { 0xFF37, 0xFF57, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_201[] = { + { 0x00C9, 0x00E9, 0x0000, 0x0000 }, + { 0x01C8, 0x01C9, 0x0000, 0x0000 }, + { 0x04CD, 0x04CE, 0x0000, 0x0000 }, + { 0x1FD6, 0x03B9, 0x0342, 0x0000 }, + { 0xFF36, 0xFF56, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_202[] = { + { 0x00CA, 0x00EA, 0x0000, 0x0000 }, + { 0x01CB, 0x01CC, 0x0000, 0x0000 }, + { 0x1ED4, 0x1ED5, 0x0000, 0x0000 }, + { 0xFF35, 0xFF55, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_203[] = { + { 0x00CB, 0x00EB, 0x0000, 0x0000 }, + { 0x01CA, 0x01CC, 0x0000, 0x0000 }, + { 0xFF34, 0xFF54, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_204[] = { + { 0x00CC, 0x00EC, 0x0000, 0x0000 }, + { 0x01CD, 0x01CE, 0x0000, 0x0000 }, + { 0x1ED2, 0x1ED3, 0x0000, 0x0000 }, + { 0x1FD3, 0x03B9, 0x0308, 0x0301 }, + { 0x2CE0, 0x2CE1, 0x0000, 0x0000 }, + { 0xFF33, 0xFF53, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_205[] = { + { 0x00CD, 0x00ED, 0x0000, 0x0000 }, + { 0x04C9, 0x04CA, 0x0000, 0x0000 }, + { 0x1FD2, 0x03B9, 0x0308, 0x0300 }, + { 0xFF32, 0xFF52, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_206[] = { + { 0x00CE, 0x00EE, 0x0000, 0x0000 }, + { 0x01CF, 0x01D0, 0x0000, 0x0000 }, + { 0x1ED0, 0x1ED1, 0x0000, 0x0000 }, + { 0x2CE2, 0x2CE3, 0x0000, 0x0000 }, + { 0xFF31, 0xFF51, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_207[] = { + { 0x00CF, 0x00EF, 0x0000, 0x0000 }, + { 0x04CB, 0x04CC, 0x0000, 0x0000 }, + { 0xFF30, 0xFF50, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_208[] = { + { 0x00D0, 0x00F0, 0x0000, 0x0000 }, + { 0x01D1, 0x01D2, 0x0000, 0x0000 }, + { 0x04D4, 0x04D5, 0x0000, 0x0000 }, + { 0x10C0, 0x2D20, 0x0000, 0x0000 }, + { 0x1ECE, 0x1ECF, 0x0000, 0x0000 }, + { 0xFF2F, 0xFF4F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_209[] = { + { 0x00D1, 0x00F1, 0x0000, 0x0000 }, + { 0x10C1, 0x2D21, 0x0000, 0x0000 }, + { 0xFF2E, 0xFF4E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_210[] = { + { 0x00D2, 0x00F2, 0x0000, 0x0000 }, + { 0x01D3, 0x01D4, 0x0000, 0x0000 }, + { 0x03D1, 0x03B8, 0x0000, 0x0000 }, + { 0x04D6, 0x04D7, 0x0000, 0x0000 }, + { 0x10C2, 0x2D22, 0x0000, 0x0000 }, + { 0x1ECC, 0x1ECD, 0x0000, 0x0000 }, + { 0xFF2D, 0xFF4D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_211[] = { + { 0x00D3, 0x00F3, 0x0000, 0x0000 }, + { 0x03D0, 0x03B2, 0x0000, 0x0000 }, + { 0x10C3, 0x2D23, 0x0000, 0x0000 }, + { 0x1FCC, 0x03B7, 0x03B9, 0x0000 }, + { 0xFF2C, 0xFF4C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_212[] = { + { 0x00D4, 0x00F4, 0x0000, 0x0000 }, + { 0x01D5, 0x01D6, 0x0000, 0x0000 }, + { 0x04D0, 0x04D1, 0x0000, 0x0000 }, + { 0x10C4, 0x2D24, 0x0000, 0x0000 }, + { 0x1ECA, 0x1ECB, 0x0000, 0x0000 }, + { 0x1FCB, 0x1F75, 0x0000, 0x0000 }, + { 0xFF2B, 0xFF4B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_213[] = { + { 0x00D5, 0x00F5, 0x0000, 0x0000 }, + { 0x03D6, 0x03C0, 0x0000, 0x0000 }, + { 0x10C5, 0x2D25, 0x0000, 0x0000 }, + { 0x1FCA, 0x1F74, 0x0000, 0x0000 }, + { 0xFF2A, 0xFF4A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_214[] = { + { 0x00D6, 0x00F6, 0x0000, 0x0000 }, + { 0x01D7, 0x01D8, 0x0000, 0x0000 }, + { 0x03D5, 0x03C6, 0x0000, 0x0000 }, + { 0x04D2, 0x04D3, 0x0000, 0x0000 }, + { 0x1EC8, 0x1EC9, 0x0000, 0x0000 }, + { 0x1FC9, 0x1F73, 0x0000, 0x0000 }, + { 0xFF29, 0xFF49, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_215[] = { + { 0x1FC8, 0x1F72, 0x0000, 0x0000 }, + { 0xFF28, 0xFF48, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_216[] = { + { 0x00D8, 0x00F8, 0x0000, 0x0000 }, + { 0x01D9, 0x01DA, 0x0000, 0x0000 }, + { 0x04DC, 0x04DD, 0x0000, 0x0000 }, + { 0x1EC6, 0x1EC7, 0x0000, 0x0000 }, + { 0x1FC7, 0x03B7, 0x0342, 0x03B9 }, + { 0xFF27, 0xFF47, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_217[] = { + { 0x00D9, 0x00F9, 0x0000, 0x0000 }, + { 0x03DA, 0x03DB, 0x0000, 0x0000 }, + { 0x1FC6, 0x03B7, 0x0342, 0x0000 }, + { 0xFF26, 0xFF46, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_218[] = { + { 0x00DA, 0x00FA, 0x0000, 0x0000 }, + { 0x01DB, 0x01DC, 0x0000, 0x0000 }, + { 0x04DE, 0x04DF, 0x0000, 0x0000 }, + { 0x1EC4, 0x1EC5, 0x0000, 0x0000 }, + { 0xFF25, 0xFF45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_219[] = { + { 0x00DB, 0x00FB, 0x0000, 0x0000 }, + { 0x03D8, 0x03D9, 0x0000, 0x0000 }, + { 0x1FC4, 0x03AE, 0x03B9, 0x0000 }, + { 0xFF24, 0xFF44, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_220[] = { + { 0x00DC, 0x00FC, 0x0000, 0x0000 }, + { 0x04D8, 0x04D9, 0x0000, 0x0000 }, + { 0x1EC2, 0x1EC3, 0x0000, 0x0000 }, + { 0x1FC3, 0x03B7, 0x03B9, 0x0000 }, + { 0xFF23, 0xFF43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_221[] = { + { 0x00DD, 0x00FD, 0x0000, 0x0000 }, + { 0x03DE, 0x03DF, 0x0000, 0x0000 }, + { 0x1FC2, 0x1F74, 0x03B9, 0x0000 }, + { 0xFF22, 0xFF42, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_222[] = { + { 0x00DE, 0x00FE, 0x0000, 0x0000 }, + { 0x04DA, 0x04DB, 0x0000, 0x0000 }, + { 0x1EC0, 0x1EC1, 0x0000, 0x0000 }, + { 0xFF21, 0xFF41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_223[] = { + { 0x00DF, 0x0073, 0x0073, 0x0000 }, + { 0x01DE, 0x01DF, 0x0000, 0x0000 }, + { 0x03DC, 0x03DD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_224[] = { + { 0x04E4, 0x04E5, 0x0000, 0x0000 }, + { 0x24C4, 0x24DE, 0x0000, 0x0000 }, + { 0x2CCC, 0x2CCD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_225[] = { + { 0x01E0, 0x01E1, 0x0000, 0x0000 }, + { 0x03E2, 0x03E3, 0x0000, 0x0000 }, + { 0x24C5, 0x24DF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_226[] = { + { 0x04E6, 0x04E7, 0x0000, 0x0000 }, + { 0x24C6, 0x24E0, 0x0000, 0x0000 }, + { 0x2CCE, 0x2CCF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_227[] = { + { 0x01E2, 0x01E3, 0x0000, 0x0000 }, + { 0x03E0, 0x03E1, 0x0000, 0x0000 }, + { 0x1FFC, 0x03C9, 0x03B9, 0x0000 }, + { 0x24C7, 0x24E1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_228[] = { + { 0x04E0, 0x04E1, 0x0000, 0x0000 }, + { 0x1FFB, 0x1F7D, 0x0000, 0x0000 }, + { 0x24C0, 0x24DA, 0x0000, 0x0000 }, + { 0x2CC8, 0x2CC9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_229[] = { + { 0x01E4, 0x01E5, 0x0000, 0x0000 }, + { 0x03E6, 0x03E7, 0x0000, 0x0000 }, + { 0x1FFA, 0x1F7C, 0x0000, 0x0000 }, + { 0x24C1, 0x24DB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_230[] = { + { 0x04E2, 0x04E3, 0x0000, 0x0000 }, + { 0x1EF8, 0x1EF9, 0x0000, 0x0000 }, + { 0x1FF9, 0x1F79, 0x0000, 0x0000 }, + { 0x24C2, 0x24DC, 0x0000, 0x0000 }, + { 0x2CCA, 0x2CCB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_231[] = { + { 0x01E6, 0x01E7, 0x0000, 0x0000 }, + { 0x03E4, 0x03E5, 0x0000, 0x0000 }, + { 0x1FF8, 0x1F78, 0x0000, 0x0000 }, + { 0x24C3, 0x24DD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_232[] = { + { 0x04EC, 0x04ED, 0x0000, 0x0000 }, + { 0x1EF6, 0x1EF7, 0x0000, 0x0000 }, + { 0x1FF7, 0x03C9, 0x0342, 0x03B9 }, + { 0x24CC, 0x24E6, 0x0000, 0x0000 }, + { 0x2CC4, 0x2CC5, 0x0000, 0x0000 }, + { 0xFB13, 0x0574, 0x0576, 0x0000 } +}; + +static const CaseFoldMapping case_fold_233[] = { + { 0x01E8, 0x01E9, 0x0000, 0x0000 }, + { 0x03EA, 0x03EB, 0x0000, 0x0000 }, + { 0x1FF6, 0x03C9, 0x0342, 0x0000 }, + { 0x24CD, 0x24E7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_234[] = { + { 0x04EE, 0x04EF, 0x0000, 0x0000 }, + { 0x1EF4, 0x1EF5, 0x0000, 0x0000 }, + { 0x24CE, 0x24E8, 0x0000, 0x0000 }, + { 0x2CC6, 0x2CC7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_235[] = { + { 0x01EA, 0x01EB, 0x0000, 0x0000 }, + { 0x03E8, 0x03E9, 0x0000, 0x0000 }, + { 0x1FF4, 0x03CE, 0x03B9, 0x0000 }, + { 0x24CF, 0x24E9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_236[] = { + { 0x04E8, 0x04E9, 0x0000, 0x0000 }, + { 0x1EF2, 0x1EF3, 0x0000, 0x0000 }, + { 0x1FF3, 0x03C9, 0x03B9, 0x0000 }, + { 0x24C8, 0x24E2, 0x0000, 0x0000 }, + { 0x2CC0, 0x2CC1, 0x0000, 0x0000 }, + { 0xFB17, 0x0574, 0x056D, 0x0000 } +}; + +static const CaseFoldMapping case_fold_237[] = { + { 0x01EC, 0x01ED, 0x0000, 0x0000 }, + { 0x03EE, 0x03EF, 0x0000, 0x0000 }, + { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 }, + { 0x24C9, 0x24E3, 0x0000, 0x0000 }, + { 0xFB16, 0x057E, 0x0576, 0x0000 } +}; + +static const CaseFoldMapping case_fold_238[] = { + { 0x04EA, 0x04EB, 0x0000, 0x0000 }, + { 0x1EF0, 0x1EF1, 0x0000, 0x0000 }, + { 0x24CA, 0x24E4, 0x0000, 0x0000 }, + { 0x2CC2, 0x2CC3, 0x0000, 0x0000 }, + { 0xFB15, 0x0574, 0x056B, 0x0000 } +}; + +static const CaseFoldMapping case_fold_239[] = { + { 0x01EE, 0x01EF, 0x0000, 0x0000 }, + { 0x03EC, 0x03ED, 0x0000, 0x0000 }, + { 0x24CB, 0x24E5, 0x0000, 0x0000 }, + { 0xFB14, 0x0574, 0x0565, 0x0000 } +}; + +static const CaseFoldMapping case_fold_240[] = { + { 0x01F1, 0x01F3, 0x0000, 0x0000 }, + { 0x04F4, 0x04F5, 0x0000, 0x0000 }, + { 0x1EEE, 0x1EEF, 0x0000, 0x0000 }, + { 0x2CDC, 0x2CDD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_241[] = { + { 0x01F0, 0x006A, 0x030C, 0x0000 } +}; + +static const CaseFoldMapping case_fold_242[] = { + { 0x03F1, 0x03C1, 0x0000, 0x0000 }, + { 0x04F6, 0x04F7, 0x0000, 0x0000 }, + { 0x1EEC, 0x1EED, 0x0000, 0x0000 }, + { 0x2CDE, 0x2CDF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_243[] = { + { 0x01F2, 0x01F3, 0x0000, 0x0000 }, + { 0x03F0, 0x03BA, 0x0000, 0x0000 }, + { 0x1FEC, 0x1FE5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_244[] = { + { 0x03F7, 0x03F8, 0x0000, 0x0000 }, + { 0x04F0, 0x04F1, 0x0000, 0x0000 }, + { 0x1EEA, 0x1EEB, 0x0000, 0x0000 }, + { 0x1FEB, 0x1F7B, 0x0000, 0x0000 }, + { 0x2CD8, 0x2CD9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_245[] = { + { 0x01F4, 0x01F5, 0x0000, 0x0000 }, + { 0x1FEA, 0x1F7A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_246[] = { + { 0x01F7, 0x01BF, 0x0000, 0x0000 }, + { 0x03F5, 0x03B5, 0x0000, 0x0000 }, + { 0x04F2, 0x04F3, 0x0000, 0x0000 }, + { 0x1EE8, 0x1EE9, 0x0000, 0x0000 }, + { 0x1FE9, 0x1FE1, 0x0000, 0x0000 }, + { 0x2CDA, 0x2CDB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_247[] = { + { 0x01F6, 0x0195, 0x0000, 0x0000 }, + { 0x03F4, 0x03B8, 0x0000, 0x0000 }, + { 0x1FE8, 0x1FE0, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_248[] = { + { 0x1EE6, 0x1EE7, 0x0000, 0x0000 }, + { 0x1FE7, 0x03C5, 0x0308, 0x0342 }, + { 0x2CD4, 0x2CD5, 0x0000, 0x0000 }, + { 0xFB03, 0x0066, 0x0066, 0x0069 } +}; + +static const CaseFoldMapping case_fold_249[] = { + { 0x01F8, 0x01F9, 0x0000, 0x0000 }, + { 0x03FA, 0x03FB, 0x0000, 0x0000 }, + { 0x1FE6, 0x03C5, 0x0342, 0x0000 }, + { 0xFB02, 0x0066, 0x006C, 0x0000 } +}; + +static const CaseFoldMapping case_fold_250[] = { + { 0x03F9, 0x03F2, 0x0000, 0x0000 }, + { 0x1EE4, 0x1EE5, 0x0000, 0x0000 }, + { 0x2CD6, 0x2CD7, 0x0000, 0x0000 }, + { 0xFB01, 0x0066, 0x0069, 0x0000 } +}; + +static const CaseFoldMapping case_fold_251[] = { + { 0x01FA, 0x01FB, 0x0000, 0x0000 }, + { 0x1FE4, 0x03C1, 0x0313, 0x0000 }, + { 0xFB00, 0x0066, 0x0066, 0x0000 } +}; + +static const CaseFoldMapping case_fold_252[] = { + { 0x04F8, 0x04F9, 0x0000, 0x0000 }, + { 0x1EE2, 0x1EE3, 0x0000, 0x0000 }, + { 0x1FE3, 0x03C5, 0x0308, 0x0301 }, + { 0x2CD0, 0x2CD1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_253[] = { + { 0x01FC, 0x01FD, 0x0000, 0x0000 }, + { 0x1FE2, 0x03C5, 0x0308, 0x0300 }, + { 0xFB06, 0x0073, 0x0074, 0x0000 } +}; + +static const CaseFoldMapping case_fold_254[] = { + { 0x1EE0, 0x1EE1, 0x0000, 0x0000 }, + { 0x2CD2, 0x2CD3, 0x0000, 0x0000 }, + { 0xFB05, 0x0073, 0x0074, 0x0000 } +}; + +static const CaseFoldMapping case_fold_255[] = { + { 0x01FE, 0x01FF, 0x0000, 0x0000 }, + { 0xFB04, 0x0066, 0x0066, 0x006C } +}; + + +static const CaseFoldHashBucket case_fold_hash[256] = { + { CASEFOLDING_ARRAYLEN(case_fold_000), case_fold_000 }, + { CASEFOLDING_ARRAYLEN(case_fold_001), case_fold_001 }, + { CASEFOLDING_ARRAYLEN(case_fold_002), case_fold_002 }, + { CASEFOLDING_ARRAYLEN(case_fold_003), case_fold_003 }, + { CASEFOLDING_ARRAYLEN(case_fold_004), case_fold_004 }, + { CASEFOLDING_ARRAYLEN(case_fold_005), case_fold_005 }, + { CASEFOLDING_ARRAYLEN(case_fold_006), case_fold_006 }, + { CASEFOLDING_ARRAYLEN(case_fold_007), case_fold_007 }, + { CASEFOLDING_ARRAYLEN(case_fold_008), case_fold_008 }, + { CASEFOLDING_ARRAYLEN(case_fold_009), case_fold_009 }, + { CASEFOLDING_ARRAYLEN(case_fold_010), case_fold_010 }, + { CASEFOLDING_ARRAYLEN(case_fold_011), case_fold_011 }, + { CASEFOLDING_ARRAYLEN(case_fold_012), case_fold_012 }, + { CASEFOLDING_ARRAYLEN(case_fold_013), case_fold_013 }, + { CASEFOLDING_ARRAYLEN(case_fold_014), case_fold_014 }, + { CASEFOLDING_ARRAYLEN(case_fold_015), case_fold_015 }, + { CASEFOLDING_ARRAYLEN(case_fold_016), case_fold_016 }, + { CASEFOLDING_ARRAYLEN(case_fold_017), case_fold_017 }, + { CASEFOLDING_ARRAYLEN(case_fold_018), case_fold_018 }, + { CASEFOLDING_ARRAYLEN(case_fold_019), case_fold_019 }, + { CASEFOLDING_ARRAYLEN(case_fold_020), case_fold_020 }, + { CASEFOLDING_ARRAYLEN(case_fold_021), case_fold_021 }, + { CASEFOLDING_ARRAYLEN(case_fold_022), case_fold_022 }, + { CASEFOLDING_ARRAYLEN(case_fold_023), case_fold_023 }, + { CASEFOLDING_ARRAYLEN(case_fold_024), case_fold_024 }, + { CASEFOLDING_ARRAYLEN(case_fold_025), case_fold_025 }, + { CASEFOLDING_ARRAYLEN(case_fold_026), case_fold_026 }, + { CASEFOLDING_ARRAYLEN(case_fold_027), case_fold_027 }, + { CASEFOLDING_ARRAYLEN(case_fold_028), case_fold_028 }, + { CASEFOLDING_ARRAYLEN(case_fold_029), case_fold_029 }, + { CASEFOLDING_ARRAYLEN(case_fold_030), case_fold_030 }, + { CASEFOLDING_ARRAYLEN(case_fold_031), case_fold_031 }, + { CASEFOLDING_ARRAYLEN(case_fold_032), case_fold_032 }, + { CASEFOLDING_ARRAYLEN(case_fold_033), case_fold_033 }, + { CASEFOLDING_ARRAYLEN(case_fold_034), case_fold_034 }, + { CASEFOLDING_ARRAYLEN(case_fold_035), case_fold_035 }, + { CASEFOLDING_ARRAYLEN(case_fold_036), case_fold_036 }, + { CASEFOLDING_ARRAYLEN(case_fold_037), case_fold_037 }, + { CASEFOLDING_ARRAYLEN(case_fold_038), case_fold_038 }, + { CASEFOLDING_ARRAYLEN(case_fold_039), case_fold_039 }, + { CASEFOLDING_ARRAYLEN(case_fold_040), case_fold_040 }, + { CASEFOLDING_ARRAYLEN(case_fold_041), case_fold_041 }, + { CASEFOLDING_ARRAYLEN(case_fold_042), case_fold_042 }, + { CASEFOLDING_ARRAYLEN(case_fold_043), case_fold_043 }, + { CASEFOLDING_ARRAYLEN(case_fold_044), case_fold_044 }, + { CASEFOLDING_ARRAYLEN(case_fold_045), case_fold_045 }, + { CASEFOLDING_ARRAYLEN(case_fold_046), case_fold_046 }, + { CASEFOLDING_ARRAYLEN(case_fold_047), case_fold_047 }, + { CASEFOLDING_ARRAYLEN(case_fold_048), case_fold_048 }, + { CASEFOLDING_ARRAYLEN(case_fold_049), case_fold_049 }, + { CASEFOLDING_ARRAYLEN(case_fold_050), case_fold_050 }, + { CASEFOLDING_ARRAYLEN(case_fold_051), case_fold_051 }, + { CASEFOLDING_ARRAYLEN(case_fold_052), case_fold_052 }, + { CASEFOLDING_ARRAYLEN(case_fold_053), case_fold_053 }, + { CASEFOLDING_ARRAYLEN(case_fold_054), case_fold_054 }, + { CASEFOLDING_ARRAYLEN(case_fold_055), case_fold_055 }, + { CASEFOLDING_ARRAYLEN(case_fold_056), case_fold_056 }, + { CASEFOLDING_ARRAYLEN(case_fold_057), case_fold_057 }, + { CASEFOLDING_ARRAYLEN(case_fold_058), case_fold_058 }, + { CASEFOLDING_ARRAYLEN(case_fold_059), case_fold_059 }, + { CASEFOLDING_ARRAYLEN(case_fold_060), case_fold_060 }, + { CASEFOLDING_ARRAYLEN(case_fold_061), case_fold_061 }, + { CASEFOLDING_ARRAYLEN(case_fold_062), case_fold_062 }, + { CASEFOLDING_ARRAYLEN(case_fold_063), case_fold_063 }, + { CASEFOLDING_ARRAYLEN(case_fold_064), case_fold_064 }, + { CASEFOLDING_ARRAYLEN(case_fold_065), case_fold_065 }, + { CASEFOLDING_ARRAYLEN(case_fold_066), case_fold_066 }, + { CASEFOLDING_ARRAYLEN(case_fold_067), case_fold_067 }, + { CASEFOLDING_ARRAYLEN(case_fold_068), case_fold_068 }, + { CASEFOLDING_ARRAYLEN(case_fold_069), case_fold_069 }, + { CASEFOLDING_ARRAYLEN(case_fold_070), case_fold_070 }, + { CASEFOLDING_ARRAYLEN(case_fold_071), case_fold_071 }, + { CASEFOLDING_ARRAYLEN(case_fold_072), case_fold_072 }, + { CASEFOLDING_ARRAYLEN(case_fold_073), case_fold_073 }, + { CASEFOLDING_ARRAYLEN(case_fold_074), case_fold_074 }, + { CASEFOLDING_ARRAYLEN(case_fold_075), case_fold_075 }, + { CASEFOLDING_ARRAYLEN(case_fold_076), case_fold_076 }, + { CASEFOLDING_ARRAYLEN(case_fold_077), case_fold_077 }, + { CASEFOLDING_ARRAYLEN(case_fold_078), case_fold_078 }, + { CASEFOLDING_ARRAYLEN(case_fold_079), case_fold_079 }, + { CASEFOLDING_ARRAYLEN(case_fold_080), case_fold_080 }, + { CASEFOLDING_ARRAYLEN(case_fold_081), case_fold_081 }, + { CASEFOLDING_ARRAYLEN(case_fold_082), case_fold_082 }, + { CASEFOLDING_ARRAYLEN(case_fold_083), case_fold_083 }, + { CASEFOLDING_ARRAYLEN(case_fold_084), case_fold_084 }, + { CASEFOLDING_ARRAYLEN(case_fold_085), case_fold_085 }, + { CASEFOLDING_ARRAYLEN(case_fold_086), case_fold_086 }, + { CASEFOLDING_ARRAYLEN(case_fold_087), case_fold_087 }, + { CASEFOLDING_ARRAYLEN(case_fold_088), case_fold_088 }, + { CASEFOLDING_ARRAYLEN(case_fold_089), case_fold_089 }, + { CASEFOLDING_ARRAYLEN(case_fold_090), case_fold_090 }, + { CASEFOLDING_ARRAYLEN(case_fold_091), case_fold_091 }, + { CASEFOLDING_ARRAYLEN(case_fold_092), case_fold_092 }, + { CASEFOLDING_ARRAYLEN(case_fold_093), case_fold_093 }, + { CASEFOLDING_ARRAYLEN(case_fold_094), case_fold_094 }, + { CASEFOLDING_ARRAYLEN(case_fold_095), case_fold_095 }, + { CASEFOLDING_ARRAYLEN(case_fold_096), case_fold_096 }, + { CASEFOLDING_ARRAYLEN(case_fold_097), case_fold_097 }, + { CASEFOLDING_ARRAYLEN(case_fold_098), case_fold_098 }, + { CASEFOLDING_ARRAYLEN(case_fold_099), case_fold_099 }, + { CASEFOLDING_ARRAYLEN(case_fold_100), case_fold_100 }, + { CASEFOLDING_ARRAYLEN(case_fold_101), case_fold_101 }, + { CASEFOLDING_ARRAYLEN(case_fold_102), case_fold_102 }, + { CASEFOLDING_ARRAYLEN(case_fold_103), case_fold_103 }, + { CASEFOLDING_ARRAYLEN(case_fold_104), case_fold_104 }, + { CASEFOLDING_ARRAYLEN(case_fold_105), case_fold_105 }, + { CASEFOLDING_ARRAYLEN(case_fold_106), case_fold_106 }, + { CASEFOLDING_ARRAYLEN(case_fold_107), case_fold_107 }, + { CASEFOLDING_ARRAYLEN(case_fold_108), case_fold_108 }, + { CASEFOLDING_ARRAYLEN(case_fold_109), case_fold_109 }, + { CASEFOLDING_ARRAYLEN(case_fold_110), case_fold_110 }, + { CASEFOLDING_ARRAYLEN(case_fold_111), case_fold_111 }, + { CASEFOLDING_ARRAYLEN(case_fold_112), case_fold_112 }, + { CASEFOLDING_ARRAYLEN(case_fold_113), case_fold_113 }, + { CASEFOLDING_ARRAYLEN(case_fold_114), case_fold_114 }, + { CASEFOLDING_ARRAYLEN(case_fold_115), case_fold_115 }, + { CASEFOLDING_ARRAYLEN(case_fold_116), case_fold_116 }, + { CASEFOLDING_ARRAYLEN(case_fold_117), case_fold_117 }, + { CASEFOLDING_ARRAYLEN(case_fold_118), case_fold_118 }, + { CASEFOLDING_ARRAYLEN(case_fold_119), case_fold_119 }, + { CASEFOLDING_ARRAYLEN(case_fold_120), case_fold_120 }, + { CASEFOLDING_ARRAYLEN(case_fold_121), case_fold_121 }, + { CASEFOLDING_ARRAYLEN(case_fold_122), case_fold_122 }, + { 0, NULL }, + { CASEFOLDING_ARRAYLEN(case_fold_124), case_fold_124 }, + { 0, NULL }, + { CASEFOLDING_ARRAYLEN(case_fold_126), case_fold_126 }, + { 0, NULL }, + { CASEFOLDING_ARRAYLEN(case_fold_128), case_fold_128 }, + { CASEFOLDING_ARRAYLEN(case_fold_129), case_fold_129 }, + { CASEFOLDING_ARRAYLEN(case_fold_130), case_fold_130 }, + { CASEFOLDING_ARRAYLEN(case_fold_131), case_fold_131 }, + { CASEFOLDING_ARRAYLEN(case_fold_132), case_fold_132 }, + { CASEFOLDING_ARRAYLEN(case_fold_133), case_fold_133 }, + { CASEFOLDING_ARRAYLEN(case_fold_134), case_fold_134 }, + { CASEFOLDING_ARRAYLEN(case_fold_135), case_fold_135 }, + { CASEFOLDING_ARRAYLEN(case_fold_136), case_fold_136 }, + { CASEFOLDING_ARRAYLEN(case_fold_137), case_fold_137 }, + { CASEFOLDING_ARRAYLEN(case_fold_138), case_fold_138 }, + { CASEFOLDING_ARRAYLEN(case_fold_139), case_fold_139 }, + { CASEFOLDING_ARRAYLEN(case_fold_140), case_fold_140 }, + { CASEFOLDING_ARRAYLEN(case_fold_141), case_fold_141 }, + { CASEFOLDING_ARRAYLEN(case_fold_142), case_fold_142 }, + { CASEFOLDING_ARRAYLEN(case_fold_143), case_fold_143 }, + { CASEFOLDING_ARRAYLEN(case_fold_144), case_fold_144 }, + { CASEFOLDING_ARRAYLEN(case_fold_145), case_fold_145 }, + { CASEFOLDING_ARRAYLEN(case_fold_146), case_fold_146 }, + { CASEFOLDING_ARRAYLEN(case_fold_147), case_fold_147 }, + { CASEFOLDING_ARRAYLEN(case_fold_148), case_fold_148 }, + { CASEFOLDING_ARRAYLEN(case_fold_149), case_fold_149 }, + { CASEFOLDING_ARRAYLEN(case_fold_150), case_fold_150 }, + { CASEFOLDING_ARRAYLEN(case_fold_151), case_fold_151 }, + { CASEFOLDING_ARRAYLEN(case_fold_152), case_fold_152 }, + { CASEFOLDING_ARRAYLEN(case_fold_153), case_fold_153 }, + { CASEFOLDING_ARRAYLEN(case_fold_154), case_fold_154 }, + { CASEFOLDING_ARRAYLEN(case_fold_155), case_fold_155 }, + { CASEFOLDING_ARRAYLEN(case_fold_156), case_fold_156 }, + { CASEFOLDING_ARRAYLEN(case_fold_157), case_fold_157 }, + { CASEFOLDING_ARRAYLEN(case_fold_158), case_fold_158 }, + { CASEFOLDING_ARRAYLEN(case_fold_159), case_fold_159 }, + { CASEFOLDING_ARRAYLEN(case_fold_160), case_fold_160 }, + { CASEFOLDING_ARRAYLEN(case_fold_161), case_fold_161 }, + { CASEFOLDING_ARRAYLEN(case_fold_162), case_fold_162 }, + { CASEFOLDING_ARRAYLEN(case_fold_163), case_fold_163 }, + { CASEFOLDING_ARRAYLEN(case_fold_164), case_fold_164 }, + { CASEFOLDING_ARRAYLEN(case_fold_165), case_fold_165 }, + { CASEFOLDING_ARRAYLEN(case_fold_166), case_fold_166 }, + { CASEFOLDING_ARRAYLEN(case_fold_167), case_fold_167 }, + { CASEFOLDING_ARRAYLEN(case_fold_168), case_fold_168 }, + { CASEFOLDING_ARRAYLEN(case_fold_169), case_fold_169 }, + { CASEFOLDING_ARRAYLEN(case_fold_170), case_fold_170 }, + { CASEFOLDING_ARRAYLEN(case_fold_171), case_fold_171 }, + { CASEFOLDING_ARRAYLEN(case_fold_172), case_fold_172 }, + { CASEFOLDING_ARRAYLEN(case_fold_173), case_fold_173 }, + { CASEFOLDING_ARRAYLEN(case_fold_174), case_fold_174 }, + { CASEFOLDING_ARRAYLEN(case_fold_175), case_fold_175 }, + { CASEFOLDING_ARRAYLEN(case_fold_176), case_fold_176 }, + { CASEFOLDING_ARRAYLEN(case_fold_177), case_fold_177 }, + { CASEFOLDING_ARRAYLEN(case_fold_178), case_fold_178 }, + { CASEFOLDING_ARRAYLEN(case_fold_179), case_fold_179 }, + { CASEFOLDING_ARRAYLEN(case_fold_180), case_fold_180 }, + { CASEFOLDING_ARRAYLEN(case_fold_181), case_fold_181 }, + { CASEFOLDING_ARRAYLEN(case_fold_182), case_fold_182 }, + { CASEFOLDING_ARRAYLEN(case_fold_183), case_fold_183 }, + { CASEFOLDING_ARRAYLEN(case_fold_184), case_fold_184 }, + { CASEFOLDING_ARRAYLEN(case_fold_185), case_fold_185 }, + { CASEFOLDING_ARRAYLEN(case_fold_186), case_fold_186 }, + { CASEFOLDING_ARRAYLEN(case_fold_187), case_fold_187 }, + { CASEFOLDING_ARRAYLEN(case_fold_188), case_fold_188 }, + { CASEFOLDING_ARRAYLEN(case_fold_189), case_fold_189 }, + { CASEFOLDING_ARRAYLEN(case_fold_190), case_fold_190 }, + { CASEFOLDING_ARRAYLEN(case_fold_191), case_fold_191 }, + { CASEFOLDING_ARRAYLEN(case_fold_192), case_fold_192 }, + { CASEFOLDING_ARRAYLEN(case_fold_193), case_fold_193 }, + { CASEFOLDING_ARRAYLEN(case_fold_194), case_fold_194 }, + { CASEFOLDING_ARRAYLEN(case_fold_195), case_fold_195 }, + { CASEFOLDING_ARRAYLEN(case_fold_196), case_fold_196 }, + { CASEFOLDING_ARRAYLEN(case_fold_197), case_fold_197 }, + { CASEFOLDING_ARRAYLEN(case_fold_198), case_fold_198 }, + { CASEFOLDING_ARRAYLEN(case_fold_199), case_fold_199 }, + { CASEFOLDING_ARRAYLEN(case_fold_200), case_fold_200 }, + { CASEFOLDING_ARRAYLEN(case_fold_201), case_fold_201 }, + { CASEFOLDING_ARRAYLEN(case_fold_202), case_fold_202 }, + { CASEFOLDING_ARRAYLEN(case_fold_203), case_fold_203 }, + { CASEFOLDING_ARRAYLEN(case_fold_204), case_fold_204 }, + { CASEFOLDING_ARRAYLEN(case_fold_205), case_fold_205 }, + { CASEFOLDING_ARRAYLEN(case_fold_206), case_fold_206 }, + { CASEFOLDING_ARRAYLEN(case_fold_207), case_fold_207 }, + { CASEFOLDING_ARRAYLEN(case_fold_208), case_fold_208 }, + { CASEFOLDING_ARRAYLEN(case_fold_209), case_fold_209 }, + { CASEFOLDING_ARRAYLEN(case_fold_210), case_fold_210 }, + { CASEFOLDING_ARRAYLEN(case_fold_211), case_fold_211 }, + { CASEFOLDING_ARRAYLEN(case_fold_212), case_fold_212 }, + { CASEFOLDING_ARRAYLEN(case_fold_213), case_fold_213 }, + { CASEFOLDING_ARRAYLEN(case_fold_214), case_fold_214 }, + { CASEFOLDING_ARRAYLEN(case_fold_215), case_fold_215 }, + { CASEFOLDING_ARRAYLEN(case_fold_216), case_fold_216 }, + { CASEFOLDING_ARRAYLEN(case_fold_217), case_fold_217 }, + { CASEFOLDING_ARRAYLEN(case_fold_218), case_fold_218 }, + { CASEFOLDING_ARRAYLEN(case_fold_219), case_fold_219 }, + { CASEFOLDING_ARRAYLEN(case_fold_220), case_fold_220 }, + { CASEFOLDING_ARRAYLEN(case_fold_221), case_fold_221 }, + { CASEFOLDING_ARRAYLEN(case_fold_222), case_fold_222 }, + { CASEFOLDING_ARRAYLEN(case_fold_223), case_fold_223 }, + { CASEFOLDING_ARRAYLEN(case_fold_224), case_fold_224 }, + { CASEFOLDING_ARRAYLEN(case_fold_225), case_fold_225 }, + { CASEFOLDING_ARRAYLEN(case_fold_226), case_fold_226 }, + { CASEFOLDING_ARRAYLEN(case_fold_227), case_fold_227 }, + { CASEFOLDING_ARRAYLEN(case_fold_228), case_fold_228 }, + { CASEFOLDING_ARRAYLEN(case_fold_229), case_fold_229 }, + { CASEFOLDING_ARRAYLEN(case_fold_230), case_fold_230 }, + { CASEFOLDING_ARRAYLEN(case_fold_231), case_fold_231 }, + { CASEFOLDING_ARRAYLEN(case_fold_232), case_fold_232 }, + { CASEFOLDING_ARRAYLEN(case_fold_233), case_fold_233 }, + { CASEFOLDING_ARRAYLEN(case_fold_234), case_fold_234 }, + { CASEFOLDING_ARRAYLEN(case_fold_235), case_fold_235 }, + { CASEFOLDING_ARRAYLEN(case_fold_236), case_fold_236 }, + { CASEFOLDING_ARRAYLEN(case_fold_237), case_fold_237 }, + { CASEFOLDING_ARRAYLEN(case_fold_238), case_fold_238 }, + { CASEFOLDING_ARRAYLEN(case_fold_239), case_fold_239 }, + { CASEFOLDING_ARRAYLEN(case_fold_240), case_fold_240 }, + { CASEFOLDING_ARRAYLEN(case_fold_241), case_fold_241 }, + { CASEFOLDING_ARRAYLEN(case_fold_242), case_fold_242 }, + { CASEFOLDING_ARRAYLEN(case_fold_243), case_fold_243 }, + { CASEFOLDING_ARRAYLEN(case_fold_244), case_fold_244 }, + { CASEFOLDING_ARRAYLEN(case_fold_245), case_fold_245 }, + { CASEFOLDING_ARRAYLEN(case_fold_246), case_fold_246 }, + { CASEFOLDING_ARRAYLEN(case_fold_247), case_fold_247 }, + { CASEFOLDING_ARRAYLEN(case_fold_248), case_fold_248 }, + { CASEFOLDING_ARRAYLEN(case_fold_249), case_fold_249 }, + { CASEFOLDING_ARRAYLEN(case_fold_250), case_fold_250 }, + { CASEFOLDING_ARRAYLEN(case_fold_251), case_fold_251 }, + { CASEFOLDING_ARRAYLEN(case_fold_252), case_fold_252 }, + { CASEFOLDING_ARRAYLEN(case_fold_253), case_fold_253 }, + { CASEFOLDING_ARRAYLEN(case_fold_254), case_fold_254 }, + { CASEFOLDING_ARRAYLEN(case_fold_255), case_fold_255 }, +}; + diff --git a/tier1/processor_detect.cpp b/tier1/processor_detect.cpp new file mode 100644 index 0000000..0aabeb7 --- /dev/null +++ b/tier1/processor_detect.cpp @@ -0,0 +1,274 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: win32 dependant ASM code for CPU capability detection +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if defined( _X360 ) || defined( WIN64 ) + +bool CheckMMXTechnology(void) { return false; } +bool CheckSSETechnology(void) { return false; } +bool CheckSSE2Technology(void) { return false; } +bool Check3DNowTechnology(void) { return false; } + +#elif defined( _WIN32 ) && !defined( _X360 ) + +#pragma optimize( "", off ) +#pragma warning( disable: 4800 ) //'int' : forcing value to bool 'true' or 'false' (performance warning) + +// stuff from windows.h +#ifndef EXCEPTION_EXECUTE_HANDLER +#define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +bool CheckMMXTechnology(void) +{ + int retval = true; + unsigned int RegEDX = 0; + +#ifdef CPUID + _asm pushad; +#endif + + __try + { + _asm + { +#ifdef CPUID + xor edx, edx // Clue the compiler that EDX is about to be used. +#endif + mov eax, 1 // set up CPUID to return processor version and features + // 0 = vendor string, 1 = version info, 2 = cache info + CPUID // code bytes = 0fh, 0a2h + mov RegEDX, edx // features returned in edx + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + retval = false; + } + + // If CPUID not supported, then certainly no MMX extensions. + if (retval) + { + if (RegEDX & 0x800000) // bit 23 is set for MMX technology + { + __try + { + // try executing the MMX instruction "emms" + _asm EMMS + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + retval = false; + } + } + + else + retval = false; // processor supports CPUID but does not support MMX technology + + // if retval == 0 here, it means the processor has MMX technology but + // floating-point emulation is on; so MMX technology is unavailable + } + +#ifdef CPUID + _asm popad; +#endif + + return retval; +} + +bool CheckSSETechnology(void) +{ + int retval = true; + unsigned int RegEDX = 0; + +#ifdef CPUID + _asm pushad; +#endif + + // Do we have support for the CPUID function? + __try + { + _asm + { +#ifdef CPUID + xor edx, edx // Clue the compiler that EDX is about to be used. +#endif + mov eax, 1 // set up CPUID to return processor version and features + // 0 = vendor string, 1 = version info, 2 = cache info + CPUID // code bytes = 0fh, 0a2h + mov RegEDX, edx // features returned in edx + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + retval = false; + } + + // If CPUID not supported, then certainly no SSE extensions. + if (retval) + { + // Do we have support for SSE in this processor? + if ( RegEDX & 0x2000000L ) // bit 25 is set for SSE technology + { + // Make sure that SSE is supported by executing an inline SSE instruction + +// BUGBUG, FIXME - Visual C Version 6.0 does not support SSE inline code YET (No macros from Intel either) +// Fix this if VC7 supports inline SSE instructinons like "xorps" as shown below. +#if 1 + __try + { + _asm + { + // Attempt execution of a SSE instruction to make sure OS supports SSE FPU context switches + xorps xmm0, xmm0 + // This will work on Win2k+ (Including masking SSE FPU exception to "normalized" values) + // This will work on Win98+ (But no "masking" of FPU exceptions provided) + } + } + __except(EXCEPTION_EXECUTE_HANDLER) +#endif + + { + retval = false; + } + } + else + retval = false; + } +#ifdef CPUID + _asm popad; +#endif + + return retval; +} + +bool CheckSSE2Technology(void) +{ + int retval = true; + unsigned int RegEDX = 0; + +#ifdef CPUID + _asm pushad; +#endif + + // Do we have support for the CPUID function? + __try + { + _asm + { +#ifdef CPUID + xor edx, edx // Clue the compiler that EDX is about to be used. +#endif + mov eax, 1 // set up CPUID to return processor version and features + // 0 = vendor string, 1 = version info, 2 = cache info + CPUID // code bytes = 0fh, 0a2h + mov RegEDX, edx // features returned in edx + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + retval = false; + } + + // If CPUID not supported, then certainly no SSE extensions. + if (retval) + { + // Do we have support for SSE in this processor? + if ( RegEDX & 0x04000000 ) // bit 26 is set for SSE2 technology + { + // Make sure that SSE is supported by executing an inline SSE instruction + + __try + { + _asm + { + // Attempt execution of a SSE2 instruction to make sure OS supports SSE FPU context switches + xorpd xmm0, xmm0 + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + + { + retval = false; + } + } + else + retval = false; + } +#ifdef CPUID + _asm popad; +#endif + + return retval; +} + +bool Check3DNowTechnology(void) +{ + int retval = true; + unsigned int RegEAX = 0; + +#ifdef CPUID + _asm pushad; +#endif + + // First see if we can execute CPUID at all + __try + { + _asm + { +#ifdef CPUID +// xor edx, edx // Clue the compiler that EDX is about to be used. +#endif + mov eax, 0x80000000 // setup CPUID to return whether AMD >0x80000000 function are supported. + // 0x80000000 = Highest 0x80000000+ function, 0x80000001 = 3DNow support + CPUID // code bytes = 0fh, 0a2h + mov RegEAX, eax // result returned in eax + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + retval = false; + } + + // If CPUID not supported, then there is definitely no 3DNow support + if (retval) + { + // Are there any "higher" AMD CPUID functions? + if (RegEAX > 0x80000000L ) + { + __try + { + _asm + { + mov eax, 0x80000001 // setup to test for CPU features + CPUID // code bytes = 0fh, 0a2h + shr edx, 31 // If bit 31 is set, we have 3DNow support! + mov retval, edx // Save the return value for end of function + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + retval = false; + } + } + else + { + // processor supports CPUID but does not support AMD CPUID functions + retval = false; + } + } + +#ifdef CPUID + _asm popad; +#endif + + return retval; +} + +#pragma optimize( "", on ) + +#endif // _WIN32 diff --git a/tier1/processor_detect_linux.cpp b/tier1/processor_detect_linux.cpp new file mode 100644 index 0000000..c7c95d0 --- /dev/null +++ b/tier1/processor_detect_linux.cpp @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: linux dependant ASM code for CPU capability detection +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#define cpuid(in,a,b,c,d) \ + asm("pushl %%ebx\n\t" "cpuid\n\t" "movl %%ebx,%%esi\n\t" "pop %%ebx": "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (in)); + +bool CheckMMXTechnology(void) +{ + unsigned long eax,ebx,edx,unused; + cpuid(1,eax,ebx,unused,edx); + + return edx & 0x800000; +} + +bool CheckSSETechnology(void) +{ + unsigned long eax,ebx,edx,unused; + cpuid(1,eax,ebx,unused,edx); + + return edx & 0x2000000L; +} + +bool CheckSSE2Technology(void) +{ + unsigned long eax,ebx,edx,unused; + cpuid(1,eax,ebx,unused,edx); + + return edx & 0x04000000; +} + +bool Check3DNowTechnology(void) +{ + unsigned long eax, unused; + cpuid(0x80000000,eax,unused,unused,unused); + + if ( eax > 0x80000000L ) + { + cpuid(0x80000001,unused,unused,unused,eax); + return ( eax & 1<<31 ); + } + return false; +} diff --git a/tier1/qsort_s.cpp b/tier1/qsort_s.cpp new file mode 100644 index 0000000..2d0e8f2 --- /dev/null +++ b/tier1/qsort_s.cpp @@ -0,0 +1,112 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/******************************************************************/ +/* qsort.c -- Non-Recursive ANSI Quicksort function */ +/* */ +/* Public domain by Raymond Gardner, Englewood CO February 1991 */ +/* */ +/* Usage: */ +/* qsort(base, nbr_elements, width_bytes, compare_function); */ +/* void *base; */ +/* size_t nbr_elements, width_bytes; */ +/* int (*compare_function)(const void *, const void *); */ +/* */ +/* Sorts an array starting at base, of length nbr_elements, each */ +/* element of size width_bytes, ordered via compare_function, */ +/* which is called as (*compare_function)(ptr_to_element1, */ +/* ptr_to_element2) and returns < 0 if element1 < element2, */ +/* 0 if element1 = element2, > 0 if element1 > element2. */ +/* Most refinements are due to R. Sedgewick. See "Implementing */ +/* Quicksort Programs", Comm. ACM, Oct. 1978, and Corrigendum, */ +/* Comm. ACM, June 1979. */ +/******************************************************************/ + +// modified to take (and use) a context object, ala Microsoft's qsort_s +// "extension" to the stdlib + +#include /* for size_t definition */ + +/* +** swap nbytes between a and b +*/ + +static void swap_bytes(char *a, char *b, size_t nbytes) +{ + char tmp; + do { + tmp = *a; *a++ = *b; *b++ = tmp; + } while ( --nbytes ); +} + +#define SWAP(a, b) (swap_bytes((char *)(a), (char *)(b), size)) + +#define COMP(ctx, a, b) ((*comp)((void *)ctx, (void *)(a), (void *)(b))) + +#define T 7 /* subfiles of T or fewer elements will */ + /* be sorted by a simple insertion sort */ + /* Note! T must be at least 3 */ + +extern "C" void qsort_s(void *basep, size_t nelems, size_t size, + int (*comp)(void *, const void *, const void *), + void *ctx) +{ + char *stack[40], **sp; /* stack and stack pointer */ + char *i, *j, *limit; /* scan and limit pointers */ + size_t thresh; /* size of T elements in bytes */ + char *base; /* base pointer as char * */ + + base = (char *)basep; /* set up char * base pointer */ + thresh = T * size; /* init threshold */ + sp = stack; /* init stack pointer */ + limit = base + nelems * size;/* pointer past end of array */ + for ( ;; ) { /* repeat until break... */ + if ((size_t)limit - (size_t)base > thresh) { /* if more than T elements */ + /* swap base with middle */ + SWAP((((limit-base)/size)/2)*size+base, base); + i = base + size; /* i scans left to right */ + j = limit - size; /* j scans right to left */ + if ( COMP(ctx, i, j) > 0 ) /* Sedgewick's */ + SWAP(i, j); /* three-element sort */ + if ( COMP(ctx, base, j) > 0 )/* sets things up */ + SWAP(base, j); /* so that */ + if ( COMP(ctx, i, base) > 0 )/* *i <= *base <= *j */ + SWAP(i, base); /* *base is pivot element */ + for ( ;; ) { /* loop until break */ + do /* move i right */ + i += size; /* until *i >= pivot */ + while ( COMP(ctx, i, base) < 0 ); + do /* move j left */ + j -= size; /* until *j <= pivot */ + while ( COMP(ctx, j, base) > 0 ); + if ( i > j ) /* if pointers crossed */ + break; /* break loop */ + SWAP(i, j); /* else swap elements, keep scanning*/ + } + SWAP(base, j); /* move pivot into correct place */ + if ( j - base > limit - i ) { /* if left subfile larger */ + sp[0] = base; /* stack left subfile base */ + sp[1] = j; /* and limit */ + base = i; /* sort the right subfile */ + } else { /* else right subfile larger*/ + sp[0] = i; /* stack right subfile base */ + sp[1] = limit; /* and limit */ + limit = j; /* sort the left subfile */ + } + sp += 2; /* increment stack pointer */ + } else { /* else subfile is small, use insertion sort */ + for ( j = base, i = j+size; i < limit; j = i, i += size ) + for ( ; COMP(ctx, j, j+size) > 0; j -= size ) { + SWAP(j, j+size); + if ( j == base ) + break; + } + if ( sp != stack ) { /* if any entries on stack */ + sp -= 2; /* pop the base and limit */ + base = sp[0]; + limit = sp[1]; + } else /* else stack empty, done */ + break; + } + } +} + + diff --git a/tier1/rangecheckedvar.cpp b/tier1/rangecheckedvar.cpp new file mode 100644 index 0000000..d37e34a --- /dev/null +++ b/tier1/rangecheckedvar.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "rangecheckedvar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +bool g_bDoRangeChecks = true; + + +static int g_nDisables = 0; + + +CDisableRangeChecks::CDisableRangeChecks() +{ + if ( !ThreadInMainThread() ) + return; + g_nDisables++; + g_bDoRangeChecks = false; +} + + +CDisableRangeChecks::~CDisableRangeChecks() +{ + if ( !ThreadInMainThread() ) + return; + Assert( g_nDisables > 0 ); + --g_nDisables; + if ( g_nDisables == 0 ) + { + g_bDoRangeChecks = true; + } +} + + + + diff --git a/tier1/reliabletimer.cpp b/tier1/reliabletimer.cpp new file mode 100644 index 0000000..af8b842 --- /dev/null +++ b/tier1/reliabletimer.cpp @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "tier1/reliabletimer.h" + +int64 CReliableTimer::sm_nPerformanceFrequency = 0; +bool CReliableTimer::sm_bUseQPC = false; + +#ifdef _WIN32 +#include "winlite.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CReliableTimer::CReliableTimer() +{ + m_nPerformanceCounterStart = 0; + m_nPerformanceCounterEnd = 0; + m_nPerformanceCounterLimit = 0; + +#ifdef _WIN32 + // calculate performance frequency the first time we use a timer + if ( 0 == sm_nPerformanceFrequency ) + { + // Are we on a bad CPU? + sm_bUseQPC = false; // todo + const CPUInformation &cpu = *GetCPUInformation(); + sm_bUseQPC = ( ( 0 == Q_stricmp( cpu.m_szProcessorID, "AuthenticAMD" ) ) + && ( cpu.m_nPhysicalProcessors > 1 ) + && !cpu.m_bSSE41 ); + + if ( sm_bUseQPC ) + { + LARGE_INTEGER li; + QueryPerformanceFrequency( &li ); + sm_nPerformanceFrequency = li.QuadPart; + } + else + { + sm_nPerformanceFrequency = g_ClockSpeed; + } + } +#elif defined(_PS3) + // On PowerPC, the time base register increment frequency is implementation dependent, and doesn't have to be constant. + // On PS3, measured it to be just shy of 80Mhz on the PPU and doesn't seem to change + if ( sm_nPerformanceFrequency == 0 ) + sm_nPerformanceFrequency = sys_time_get_timebase_frequency(); +#else + // calculate performance frequency the first time we use a timer + if ( 0 == sm_nPerformanceFrequency ) + { + sm_nPerformanceFrequency = g_ClockSpeed; + } +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns current QueryPerformanceCounter value +//----------------------------------------------------------------------------- +int64 CReliableTimer::GetPerformanceCountNow() +{ + //VPROF_BUDGET( "CReliableTimer::GetPerformanceCountNow", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); +#ifdef _WIN32 + if ( sm_bUseQPC ) + { + LARGE_INTEGER li = {0}; + QueryPerformanceCounter( &li ); + return li.QuadPart; + } + else + { + CCycleCount CycleCount; + CycleCount.Sample(); + return CycleCount.GetLongCycles(); + } +#elif defined( _PS3 ) + // use handy macro to grab tb + uint64 ulNow; + SYS_TIMEBASE_GET( ulNow ); + return ulNow; +#else + uint64 un64; + __asm__ __volatile__ ( + "rdtsc\n\t" + : "=A" (un64) ); + return (int64)un64; +#endif +} diff --git a/tier1/snappy-internal.h b/tier1/snappy-internal.h new file mode 100644 index 0000000..c99d331 --- /dev/null +++ b/tier1/snappy-internal.h @@ -0,0 +1,150 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Internals shared between the Snappy implementation and its unittest. + +#ifndef UTIL_SNAPPY_SNAPPY_INTERNAL_H_ +#define UTIL_SNAPPY_SNAPPY_INTERNAL_H_ + +#include "snappy-stubs-internal.h" + +namespace snappy { +namespace internal { + +class WorkingMemory { + public: + WorkingMemory() : large_table_(NULL) { } + ~WorkingMemory() { delete[] large_table_; } + + // Allocates and clears a hash table using memory in "*this", + // stores the number of buckets in "*table_size" and returns a pointer to + // the base of the hash table. + uint16* GetHashTable(size_t input_size, int* table_size); + + private: + uint16 small_table_[1<<10]; // 2KB + uint16* large_table_; // Allocated only when needed + + DISALLOW_COPY_AND_ASSIGN(WorkingMemory); +}; + +// Flat array compression that does not emit the "uncompressed length" +// prefix. Compresses "input" string to the "*op" buffer. +// +// REQUIRES: "input_length <= kBlockSize" +// REQUIRES: "op" points to an array of memory that is at least +// "MaxCompressedLength(input_length)" in size. +// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. +// REQUIRES: "table_size" is a power of two +// +// Returns an "end" pointer into "op" buffer. +// "end - op" is the compressed size of "input". +char* CompressFragment(const char* input, + size_t input_length, + char* op, + uint16* table, + const int table_size); + +// Return the largest n such that +// +// s1[0,n-1] == s2[0,n-1] +// and n <= (s2_limit - s2). +// +// Does not read *s2_limit or beyond. +// Does not read *(s1 + (s2_limit - s2)) or beyond. +// Requires that s2_limit >= s2. +// +// Separate implementation for x86_64, for speed. Uses the fact that +// x86_64 is little endian. +#if defined(ARCH_K8) +static inline int FindMatchLength(const char* s1, + const char* s2, + const char* s2_limit) { + assert(s2_limit >= s2); + int matched = 0; + + // Find out how long the match is. We loop over the data 64 bits at a + // time until we find a 64-bit block that doesn't match; then we find + // the first non-matching bit and use that to calculate the total + // length of the match. + while (PREDICT_TRUE(s2 <= s2_limit - 8)) { + if (PREDICT_FALSE(UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched))) { + s2 += 8; + matched += 8; + } else { + // On current (mid-2008) Opteron models there is a 3% more + // efficient code sequence to find the first non-matching byte. + // However, what follows is ~10% better on Intel Core 2 and newer, + // and we expect AMD's bsf instruction to improve. + uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched); + int matching_bits = Bits::FindLSBSetNonZero64(x); + matched += matching_bits >> 3; + return matched; + } + } + while (PREDICT_TRUE(s2 < s2_limit)) { + if (PREDICT_TRUE(s1[matched] == *s2)) { + ++s2; + ++matched; + } else { + return matched; + } + } + return matched; +} +#else +static inline int FindMatchLength(const char* s1, + const char* s2, + const char* s2_limit) { + // Implementation based on the x86-64 version, above. + assert(s2_limit >= s2); + int matched = 0; + + while (s2 <= s2_limit - 4 && + UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) { + s2 += 4; + matched += 4; + } + if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) { + uint32 x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched); + int matching_bits = Bits::FindLSBSetNonZero(x); + matched += matching_bits >> 3; + } else { + while ((s2 < s2_limit) && (s1[matched] == *s2)) { + ++s2; + ++matched; + } + } + return matched; +} +#endif + +} // end namespace internal +} // end namespace snappy + +#endif // UTIL_SNAPPY_SNAPPY_INTERNAL_H_ diff --git a/tier1/snappy-sinksource.cpp b/tier1/snappy-sinksource.cpp new file mode 100644 index 0000000..8e868bb --- /dev/null +++ b/tier1/snappy-sinksource.cpp @@ -0,0 +1,74 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "snappy-sinksource.h" + +namespace snappy { + +Source::~Source() { } + +Sink::~Sink() { } + +char* Sink::GetAppendBuffer(size_t length, char* scratch) { + (void)length; + return scratch; +} + +ByteArraySource::~ByteArraySource() { } + +size_t ByteArraySource::Available() const { return left_; } + +const char* ByteArraySource::Peek(size_t* len) { + *len = left_; + return ptr_; +} + +void ByteArraySource::Skip(size_t n) { + left_ -= n; + ptr_ += n; +} + +UncheckedByteArraySink::~UncheckedByteArraySink() { } + +void UncheckedByteArraySink::Append(const char* data, size_t n) { + // Do no copying if the caller filled in the result of GetAppendBuffer() + if (data != dest_) { + memcpy(dest_, data, n); + } + dest_ += n; +} + +char* UncheckedByteArraySink::GetAppendBuffer(size_t len, char* scratch) { + (void)scratch; + (void)len; + return dest_; +} + +} diff --git a/tier1/snappy-stubs-internal.cpp b/tier1/snappy-stubs-internal.cpp new file mode 100644 index 0000000..3b9d79f --- /dev/null +++ b/tier1/snappy-stubs-internal.cpp @@ -0,0 +1,45 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#ifdef _WIN32 +#pragma warning(disable:4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc +#endif //_WIN32 +#include + +#include "snappy-stubs-internal.h" + +namespace snappy { + +void Varint::Append32(string* s, uint32 value) { + char buf[Varint::kMax32]; + const char* p = Varint::Encode32(buf, value); + s->append(buf, p - buf); +} + +} // namespace snappy diff --git a/tier1/snappy-stubs-internal.h b/tier1/snappy-stubs-internal.h new file mode 100644 index 0000000..1413825 --- /dev/null +++ b/tier1/snappy-stubs-internal.h @@ -0,0 +1,493 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Various stubs for the open-source version of Snappy. + +#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ +#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tier0/platform.h" + +#include + +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#include "snappy-stubs-public.h" + +#if defined(__x86_64__) + +// Enable 64-bit optimized versions of some routines. +#define ARCH_K8 1 + +#endif + +// Needed by OS X, among others. +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +// Pull in std::min, std::ostream, and the likes. This is safe because this +// header file is never used from any public header files. +using namespace std; + +// The size of an array, if known at compile-time. +// Will give unexpected results if used on a pointer. +// We undefine it first, since some compilers already have a definition. +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif +#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) + +// Static prediction hints. +#ifdef HAVE_BUILTIN_EXPECT +#define PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define PREDICT_FALSE(x) x +#define PREDICT_TRUE(x) x +#endif + +// This is only used for recomputing the tag byte table used during +// decompression; for simplicity we just remove it from the open-source +// version (anyone who wants to regenerate it can just do the call +// themselves within main()). +#define DEFINE_bool(flag_name, default_value, description) \ + bool FLAGS_ ## flag_name = default_value +#define DECLARE_bool(flag_name) \ + extern bool FLAGS_ ## flag_name + +namespace snappy { + +static const uint32 kuint32max = static_cast(0xFFFFFFFF); +static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); + +// Potentially unaligned loads and stores. + +// x86 and PowerPC can simply do these loads and stores native. + +#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) + +#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) +#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) +#define UNALIGNED_LOAD64(_p) (*reinterpret_cast(_p)) + +#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast(_p) = (_val)) + +// ARMv7 and newer support native unaligned accesses, but only of 16-bit +// and 32-bit values (not 64-bit); older versions either raise a fatal signal, +// do an unaligned read and rotate the words around a bit, or do the reads very +// slowly (trip through kernel mode). There's no simple #define that says just +// “ARMv7 or higher”, so we have to filter away all ARMv5 and ARMv6 +// sub-architectures. +// +// This is a mess, but there's not much we can do about it. + +#elif defined(__arm__) && \ + !defined(__ARM_ARCH_4__) && \ + !defined(__ARM_ARCH_4T__) && \ + !defined(__ARM_ARCH_5__) && \ + !defined(__ARM_ARCH_5T__) && \ + !defined(__ARM_ARCH_5TE__) && \ + !defined(__ARM_ARCH_5TEJ__) && \ + !defined(__ARM_ARCH_6__) && \ + !defined(__ARM_ARCH_6J__) && \ + !defined(__ARM_ARCH_6K__) && \ + !defined(__ARM_ARCH_6Z__) && \ + !defined(__ARM_ARCH_6ZK__) && \ + !defined(__ARM_ARCH_6T2__) + +#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) +#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) + +#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) + +// TODO(user): NEON supports unaligned 64-bit loads and stores. +// See if that would be more efficient on platforms supporting it, +// at least for copies. + +inline uint64 UNALIGNED_LOAD64(const void *p) { + uint64 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline void UNALIGNED_STORE64(void *p, uint64 v) { + memcpy(p, &v, sizeof v); +} + +#else + +// These functions are provided for architectures that don't support +// unaligned loads and stores. + +inline uint16 UNALIGNED_LOAD16(const void *p) { + uint16 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint32 UNALIGNED_LOAD32(const void *p) { + uint32 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint64 UNALIGNED_LOAD64(const void *p) { + uint64 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline void UNALIGNED_STORE16(void *p, uint16 v) { + memcpy(p, &v, sizeof v); +} + +inline void UNALIGNED_STORE32(void *p, uint32 v) { + memcpy(p, &v, sizeof v); +} + +inline void UNALIGNED_STORE64(void *p, uint64 v) { + memcpy(p, &v, sizeof v); +} + +#endif + +// This can be more efficient than UNALIGNED_LOAD64 + UNALIGNED_STORE64 +// on some platforms, in particular ARM. +inline void UnalignedCopy64(const void *src, void *dst) { + if (sizeof(void *) == 8) { + UNALIGNED_STORE64(dst, UNALIGNED_LOAD64(src)); + } else { + const char *src_char = reinterpret_cast(src); + char *dst_char = reinterpret_cast(dst); + + UNALIGNED_STORE32(dst_char, UNALIGNED_LOAD32(src_char)); + UNALIGNED_STORE32(dst_char + 4, UNALIGNED_LOAD32(src_char + 4)); + } +} + +// The following guarantees declaration of the byte swap functions. +#ifdef WORDS_BIGENDIAN + +#ifdef HAVE_SYS_BYTEORDER_H +#include +#endif + +#ifdef HAVE_SYS_ENDIAN_H +#include +#endif + +#ifdef _MSC_VER +#include +#define bswap_16(x) _byteswap_ushort(x) +#define bswap_32(x) _byteswap_ulong(x) +#define bswap_64(x) _byteswap_uint64(x) + +#elif defined(__APPLE__) +// Mac OS X / Darwin features +#include +#define bswap_16(x) OSSwapInt16(x) +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) + +#elif defined(HAVE_BYTESWAP_H) +#include + +#elif defined(bswap32) +// FreeBSD defines bswap{16,32,64} in (already #included). +#define bswap_16(x) bswap16(x) +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) + +#elif defined(BSWAP_64) +// Solaris 10 defines BSWAP_{16,32,64} in (already #included). +#define bswap_16(x) BSWAP_16(x) +#define bswap_32(x) BSWAP_32(x) +#define bswap_64(x) BSWAP_64(x) + +#else + +inline uint16 bswap_16(uint16 x) { + return (x << 8) | (x >> 8); +} + +inline uint32 bswap_32(uint32 x) { + x = ((x & 0xff00ff00UL) >> 8) | ((x & 0x00ff00ffUL) << 8); + return (x >> 16) | (x << 16); +} + +inline uint64 bswap_64(uint64 x) { + x = ((x & 0xff00ff00ff00ff00ULL) >> 8) | ((x & 0x00ff00ff00ff00ffULL) << 8); + x = ((x & 0xffff0000ffff0000ULL) >> 16) | ((x & 0x0000ffff0000ffffULL) << 16); + return (x >> 32) | (x << 32); +} + +#endif + +#endif // WORDS_BIGENDIAN + +// Convert to little-endian storage, opposite of network format. +// Convert x from host to little endian: x = LittleEndian.FromHost(x); +// convert x from little endian to host: x = LittleEndian.ToHost(x); +// +// Store values into unaligned memory converting to little endian order: +// LittleEndian.Store16(p, x); +// +// Load unaligned values stored in little endian converting to host order: +// x = LittleEndian.Load16(p); +class LittleEndian { + public: + // Conversion functions. +#ifdef WORDS_BIGENDIAN + + static uint16 FromHost16(uint16 x) { return bswap_16(x); } + static uint16 ToHost16(uint16 x) { return bswap_16(x); } + + static uint32 FromHost32(uint32 x) { return bswap_32(x); } + static uint32 ToHost32(uint32 x) { return bswap_32(x); } + + static bool IsLittleEndian() { return false; } + +#else // !defined(WORDS_BIGENDIAN) + + static uint16 FromHost16(uint16 x) { return x; } + static uint16 ToHost16(uint16 x) { return x; } + + static uint32 FromHost32(uint32 x) { return x; } + static uint32 ToHost32(uint32 x) { return x; } + + static bool IsLittleEndian() { return true; } + +#endif // !defined(WORDS_BIGENDIAN) + + // Functions to do unaligned loads and stores in little-endian order. + static uint16 Load16(const void *p) { + return ToHost16(UNALIGNED_LOAD16(p)); + } + + static void Store16(void *p, uint16 v) { + UNALIGNED_STORE16(p, FromHost16(v)); + } + + static uint32 Load32(const void *p) { + return ToHost32(UNALIGNED_LOAD32(p)); + } + + static void Store32(void *p, uint32 v) { + UNALIGNED_STORE32(p, FromHost32(v)); + } +}; + +// Some bit-manipulation functions. +class Bits { + public: + // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0. + static int Log2Floor(uint32 n); + + // Return the first set least / most significant bit, 0-indexed. Returns an + // undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except + // that it's 0-indexed. + static int FindLSBSetNonZero(uint32 n); + static int FindLSBSetNonZero64(uint64 n); + + private: + DISALLOW_COPY_AND_ASSIGN(Bits); +}; + +#ifdef HAVE_BUILTIN_CTZ + +inline int Bits::Log2Floor(uint32 n) { + return n == 0 ? -1 : 31 ^ __builtin_clz(n); +} + +inline int Bits::FindLSBSetNonZero(uint32 n) { + return __builtin_ctz(n); +} + +inline int Bits::FindLSBSetNonZero64(uint64 n) { + return __builtin_ctzll(n); +} + +#else // Portable versions. + +inline int Bits::Log2Floor(uint32 n) { + if (n == 0) + return -1; + int log = 0; + uint32 value = n; + for (int i = 4; i >= 0; --i) { + int shift = (1 << i); + uint32 x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + assert(value == 1); + return log; +} + +inline int Bits::FindLSBSetNonZero(uint32 n) { + int rc = 31; + for (int i = 4, shift = 1 << 4; i >= 0; --i) { + const uint32 x = n << shift; + if (x != 0) { + n = x; + rc -= shift; + } + shift >>= 1; + } + return rc; +} + +// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero(). +inline int Bits::FindLSBSetNonZero64(uint64 n) { + const uint32 bottombits = static_cast(n); + if (bottombits == 0) { + // Bottom bits are zero, so scan in top bits + return 32 + FindLSBSetNonZero(static_cast(n >> 32)); + } else { + return FindLSBSetNonZero(bottombits); + } +} + +#endif // End portable versions. + +// Variable-length integer encoding. +class Varint { + public: + // Maximum lengths of varint encoding of uint32. + static const int kMax32 = 5; + + // Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1]. + // Never reads a character at or beyond limit. If a valid/terminated varint32 + // was found in the range, stores it in *OUTPUT and returns a pointer just + // past the last byte of the varint32. Else returns NULL. On success, + // "result <= limit". + static const char* Parse32WithLimit(const char* ptr, const char* limit, + uint32* OUTPUT); + + // REQUIRES "ptr" points to a buffer of length sufficient to hold "v". + // EFFECTS Encodes "v" into "ptr" and returns a pointer to the + // byte just past the last encoded byte. + static char* Encode32(char* ptr, uint32 v); + + // EFFECTS Appends the varint representation of "value" to "*s". + static void Append32(string* s, uint32 value); +}; + +inline const char* Varint::Parse32WithLimit(const char* p, + const char* l, + uint32* OUTPUT) { + const unsigned char* ptr = reinterpret_cast(p); + const unsigned char* limit = reinterpret_cast(l); + uint32 b, result; + if (ptr >= limit) return NULL; + b = *(ptr++); result = b & 127; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done; + return NULL; // Value is too long to be a varint32 + done: + *OUTPUT = result; + return reinterpret_cast(ptr); +} + +inline char* Varint::Encode32(char* sptr, uint32 v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(sptr); + static const int B = 128; + if (v < (1<<7)) { + *(ptr++) = v; + } else if (v < (1<<14)) { + *(ptr++) = v | B; + *(ptr++) = v>>7; + } else if (v < (1<<21)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = v>>14; + } else if (v < (1<<28)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = v>>21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = (v>>21) | B; + *(ptr++) = v>>28; + } + return reinterpret_cast(ptr); +} + +// If you know the internal layout of the std::string in use, you can +// replace this function with one that resizes the string without +// filling the new space with zeros (if applicable) -- +// it will be non-portable but faster. +inline void STLStringResizeUninitialized(string* s, size_t new_size) { + s->resize(new_size); +} + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530) +// proposes this as the method. It will officially be part of the standard +// for C++0x. This should already work on all current implementations. +inline char* string_as_array(string* str) { + return str->empty() ? NULL : &*str->begin(); +} + +} // namespace snappy + +#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ diff --git a/tier1/snappy.cpp b/tier1/snappy.cpp new file mode 100644 index 0000000..946ca68 --- /dev/null +++ b/tier1/snappy.cpp @@ -0,0 +1,1319 @@ +// Copyright 2005 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "snappy.h" +#include "snappy-internal.h" +#include "snappy-sinksource.h" + +#include + +#include +#include +#include + +#ifdef _WIN32 + +#pragma warning(disable:4018) // warning C4018: '<' : signed/unsigned mismatch +#pragma warning(disable:4389) // warning C4389: '==' : signed/unsigned mismatch + +/* Define like size_t, omitting the "unsigned" */ +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef int ssize_t; +#endif + +#endif //_WIN32 + +namespace snappy { + +// Any hash function will produce a valid compressed bitstream, but a good +// hash function reduces the number of collisions and thus yields better +// compression for compressible input, and more speed for incompressible +// input. Of course, it doesn't hurt if the hash function is reasonably fast +// either, as it gets called a lot. +static inline uint32 HashBytes(uint32 bytes, int shift) { + uint32 kMul = 0x1e35a7bd; + return (bytes * kMul) >> shift; +} +static inline uint32 Hash(const char* p, int shift) { + return HashBytes(UNALIGNED_LOAD32(p), shift); +} + +size_t MaxCompressedLength(size_t source_len) { + // Compressed data can be defined as: + // compressed := item* literal* + // item := literal* copy + // + // The trailing literal sequence has a space blowup of at most 62/60 + // since a literal of length 60 needs one tag byte + one extra byte + // for length information. + // + // Item blowup is trickier to measure. Suppose the "copy" op copies + // 4 bytes of data. Because of a special check in the encoding code, + // we produce a 4-byte copy only if the offset is < 65536. Therefore + // the copy op takes 3 bytes to encode, and this type of item leads + // to at most the 62/60 blowup for representing literals. + // + // Suppose the "copy" op copies 5 bytes of data. If the offset is big + // enough, it will take 5 bytes to encode the copy op. Therefore the + // worst case here is a one-byte literal followed by a five-byte copy. + // I.e., 6 bytes of input turn into 7 bytes of "compressed" data. + // + // This last factor dominates the blowup, so the final estimate is: + return 32 + source_len + source_len/6; +} + +enum { + LITERAL = 0, + COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode + COPY_2_BYTE_OFFSET = 2, + COPY_4_BYTE_OFFSET = 3 +}; +static const int kMaximumTagLength = 5; // COPY_4_BYTE_OFFSET plus the actual offset. + +// Copy "len" bytes from "src" to "op", one byte at a time. Used for +// handling COPY operations where the input and output regions may +// overlap. For example, suppose: +// src == "ab" +// op == src + 2 +// len == 20 +// After IncrementalCopy(src, op, len), the result will have +// eleven copies of "ab" +// ababababababababababab +// Note that this does not match the semantics of either memcpy() +// or memmove(). +static inline void IncrementalCopy(const char* src, char* op, ssize_t len) { + assert(len > 0); + do { + *op++ = *src++; + } while (--len > 0); +} + +// Equivalent to IncrementalCopy except that it can write up to ten extra +// bytes after the end of the copy, and that it is faster. +// +// The main part of this loop is a simple copy of eight bytes at a time until +// we've copied (at least) the requested amount of bytes. However, if op and +// src are less than eight bytes apart (indicating a repeating pattern of +// length < 8), we first need to expand the pattern in order to get the correct +// results. For instance, if the buffer looks like this, with the eight-byte +// and patterns marked as intervals: +// +// abxxxxxxxxxxxx +// [------] src +// [------] op +// +// a single eight-byte copy from to will repeat the pattern once, +// after which we can move two bytes without moving : +// +// ababxxxxxxxxxx +// [------] src +// [------] op +// +// and repeat the exercise until the two no longer overlap. +// +// This allows us to do very well in the special case of one single byte +// repeated many times, without taking a big hit for more general cases. +// +// The worst case of extra writing past the end of the match occurs when +// op - src == 1 and len == 1; the last copy will read from byte positions +// [0..7] and write to [4..11], whereas it was only supposed to write to +// position 1. Thus, ten excess bytes. + +namespace { + +const int kMaxIncrementCopyOverflow = 10; + +inline void IncrementalCopyFastPath(const char* src, char* op, ssize_t len) { + while (op - src < 8) { + UnalignedCopy64(src, op); + len -= op - src; + op += op - src; + } + while (len > 0) { + UnalignedCopy64(src, op); + src += 8; + op += 8; + len -= 8; + } +} + +} // namespace + +static inline char* EmitLiteral(char* op, + const char* literal, + int len, + bool allow_fast_path) { + int n = len - 1; // Zero-length literals are disallowed + if (n < 60) { + // Fits in tag byte + *op++ = LITERAL | (n << 2); + + // The vast majority of copies are below 16 bytes, for which a + // call to memcpy is overkill. This fast path can sometimes + // copy up to 15 bytes too much, but that is okay in the + // main loop, since we have a bit to go on for both sides: + // + // - The input will always have kInputMarginBytes = 15 extra + // available bytes, as long as we're in the main loop, and + // if not, allow_fast_path = false. + // - The output will always have 32 spare bytes (see + // MaxCompressedLength). + if (allow_fast_path && len <= 16) { + UnalignedCopy64(literal, op); + UnalignedCopy64(literal + 8, op + 8); + return op + len; + } + } else { + // Encode in upcoming bytes + char* base = op; + int count = 0; + op++; + while (n > 0) { + *op++ = n & 0xff; + n >>= 8; + count++; + } + assert(count >= 1); + assert(count <= 4); + *base = LITERAL | ((59+count) << 2); + } + memcpy(op, literal, len); + return op + len; +} + +static inline char* EmitCopyLessThan64(char* op, size_t offset, int len) { + assert(len <= 64); + assert(len >= 4); + assert(offset < 65536); + + if ((len < 12) && (offset < 2048)) { + size_t len_minus_4 = len - 4; + assert(len_minus_4 < 8); // Must fit in 3 bits + *op++ = (char)(COPY_1_BYTE_OFFSET + ((len_minus_4) << 2) + ((offset >> 8) << 5)); + *op++ = offset & 0xff; + } else { + *op++ = COPY_2_BYTE_OFFSET + ((len-1) << 2); + LittleEndian::Store16(op, (snappy::uint16)offset); + op += 2; + } + return op; +} + +static inline char* EmitCopy(char* op, size_t offset, int len) { + // Emit 64 byte copies but make sure to keep at least four bytes reserved + while (len >= 68) { + op = EmitCopyLessThan64(op, offset, 64); + len -= 64; + } + + // Emit an extra 60 byte copy if have too much data to fit in one copy + if (len > 64) { + op = EmitCopyLessThan64(op, offset, 60); + len -= 60; + } + + // Emit remainder + op = EmitCopyLessThan64(op, offset, len); + return op; +} + + +bool GetUncompressedLength(const char* start, size_t n, size_t* result) { + uint32 v = 0; + const char* limit = start + n; + if (Varint::Parse32WithLimit(start, limit, &v) != NULL) { + *result = v; + return true; + } else { + return false; + } +} + +namespace internal { +uint16* WorkingMemory::GetHashTable(size_t input_size, int* table_size) { + // Use smaller hash table when input.size() is smaller, since we + // fill the table, incurring O(hash table size) overhead for + // compression, and if the input is short, we won't need that + // many hash table entries anyway. + assert(kMaxHashTableSize >= 256); + size_t htsize = 256; + while (htsize < kMaxHashTableSize && htsize < input_size) { + htsize <<= 1; + } + + uint16* table; + if (htsize <= ARRAYSIZE(small_table_)) { + table = small_table_; + } else { + if (large_table_ == NULL) { + large_table_ = new uint16[kMaxHashTableSize]; + } + table = large_table_; + } + + *table_size = (int)htsize; + memset(table, 0, htsize * sizeof(*table)); + return table; +} +} // end namespace internal + +// For 0 <= offset <= 4, GetUint32AtOffset(GetEightBytesAt(p), offset) will +// equal UNALIGNED_LOAD32(p + offset). Motivation: On x86-64 hardware we have +// empirically found that overlapping loads such as +// UNALIGNED_LOAD32(p) ... UNALIGNED_LOAD32(p+1) ... UNALIGNED_LOAD32(p+2) +// are slower than UNALIGNED_LOAD64(p) followed by shifts and casts to uint32. +// +// We have different versions for 64- and 32-bit; ideally we would avoid the +// two functions and just inline the UNALIGNED_LOAD64 call into +// GetUint32AtOffset, but GCC (at least not as of 4.6) is seemingly not clever +// enough to avoid loading the value multiple times then. For 64-bit, the load +// is done when GetEightBytesAt() is called, whereas for 32-bit, the load is +// done at GetUint32AtOffset() time. + +#ifdef ARCH_K8 + +typedef uint64 EightBytesReference; + +static inline EightBytesReference GetEightBytesAt(const char* ptr) { + return UNALIGNED_LOAD64(ptr); +} + +static inline uint32 GetUint32AtOffset(uint64 v, int offset) { + assert(offset >= 0); + assert(offset <= 4); + return v >> (LittleEndian::IsLittleEndian() ? 8 * offset : 32 - 8 * offset); +} + +#else + +typedef const char* EightBytesReference; + +static inline EightBytesReference GetEightBytesAt(const char* ptr) { + return ptr; +} + +static inline uint32 GetUint32AtOffset(const char* v, int offset) { + assert(offset >= 0); + assert(offset <= 4); + return UNALIGNED_LOAD32(v + offset); +} + +#endif + +// Flat array compression that does not emit the "uncompressed length" +// prefix. Compresses "input" string to the "*op" buffer. +// +// REQUIRES: "input" is at most "kBlockSize" bytes long. +// REQUIRES: "op" points to an array of memory that is at least +// "MaxCompressedLength(input.size())" in size. +// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. +// REQUIRES: "table_size" is a power of two +// +// Returns an "end" pointer into "op" buffer. +// "end - op" is the compressed size of "input". +namespace internal { +char* CompressFragment(const char* input, + size_t input_size, + char* op, + uint16* table, + const int table_size) { + // "ip" is the input pointer, and "op" is the output pointer. + const char* ip = input; + assert(input_size <= kBlockSize); + assert((table_size & (table_size - 1)) == 0); // table must be power of two + const int shift = 32 - Bits::Log2Floor(table_size); + assert(static_cast(kuint32max >> shift) == table_size - 1); + const char* ip_end = input + input_size; + const char* base_ip = ip; + // Bytes in [next_emit, ip) will be emitted as literal bytes. Or + // [next_emit, ip_end) after the main loop. + const char* next_emit = ip; + + const size_t kInputMarginBytes = 15; + if (PREDICT_TRUE(input_size >= kInputMarginBytes)) { + const char* ip_limit = input + input_size - kInputMarginBytes; + + for (uint32 next_hash = Hash(++ip, shift); ; ) { + assert(next_emit < ip); + // The body of this loop calls EmitLiteral once and then EmitCopy one or + // more times. (The exception is that when we're close to exhausting + // the input we goto emit_remainder.) + // + // In the first iteration of this loop we're just starting, so + // there's nothing to copy, so calling EmitLiteral once is + // necessary. And we only start a new iteration when the + // current iteration has determined that a call to EmitLiteral will + // precede the next call to EmitCopy (if any). + // + // Step 1: Scan forward in the input looking for a 4-byte-long match. + // If we get close to exhausting the input then goto emit_remainder. + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned, look at every third byte, etc.. When a match is found, + // immediately go back to looking at every byte. This is a small loss + // (~5% performance, ~0.1% density) for compressible data due to more + // bookkeeping, but for non-compressible data (such as JPEG) it's a huge + // win since the compressor quickly "realizes" the data is incompressible + // and doesn't bother looking for matches everywhere. + // + // The "skip" variable keeps track of how many bytes there are since the + // last match; dividing it by 32 (ie. right-shifting by five) gives the + // number of bytes to move ahead for each iteration. + uint32 skip = 32; + + const char* next_ip = ip; + const char* candidate; + do { + ip = next_ip; + uint32 hash = next_hash; + assert(hash == Hash(ip, shift)); + uint32 bytes_between_hash_lookups = skip++ >> 5; + next_ip = ip + bytes_between_hash_lookups; + if (PREDICT_FALSE(next_ip > ip_limit)) { + goto emit_remainder; + } + next_hash = Hash(next_ip, shift); + candidate = base_ip + table[hash]; + assert(candidate >= base_ip); + assert(candidate < ip); + + table[hash] = (uint16)(ip - base_ip); + } while (PREDICT_TRUE(UNALIGNED_LOAD32(ip) != + UNALIGNED_LOAD32(candidate))); + + // Step 2: A 4-byte match has been found. We'll later see if more + // than 4 bytes match. But, prior to the match, input + // bytes [next_emit, ip) are unmatched. Emit them as "literal bytes." + assert(next_emit + 16 <= ip_end); + op = EmitLiteral(op, next_emit, ip - next_emit, true); + + // Step 3: Call EmitCopy, and then see if another EmitCopy could + // be our next move. Repeat until we find no match for the + // input immediately after what was consumed by the last EmitCopy call. + // + // If we exit this loop normally then we need to call EmitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can exit + // this loop via goto if we get close to exhausting the input. + EightBytesReference input_bytes; + uint32 candidate_bytes = 0; + + do { + // We have a 4-byte match at ip, and no need to emit any + // "literal bytes" prior to ip. + const char* base = ip; + int matched = 4 + FindMatchLength(candidate + 4, ip + 4, ip_end); + ip += matched; + size_t offset = base - candidate; + assert(0 == memcmp(base, candidate, matched)); + op = EmitCopy(op, offset, matched); + // We could immediately start working at ip now, but to improve + // compression we first update table[Hash(ip - 1, ...)]. + const char* insert_tail = ip - 1; + next_emit = ip; + if (PREDICT_FALSE(ip >= ip_limit)) { + goto emit_remainder; + } + input_bytes = GetEightBytesAt(insert_tail); + uint32 prev_hash = HashBytes(GetUint32AtOffset(input_bytes, 0), shift); + table[prev_hash] = (uint16)(ip - base_ip - 1); + uint32 cur_hash = HashBytes(GetUint32AtOffset(input_bytes, 1), shift); + candidate = base_ip + table[cur_hash]; + candidate_bytes = UNALIGNED_LOAD32(candidate); + table[cur_hash] = (uint16)(ip - base_ip); + } while (GetUint32AtOffset(input_bytes, 1) == candidate_bytes); + + next_hash = HashBytes(GetUint32AtOffset(input_bytes, 2), shift); + ++ip; + } + } + + emit_remainder: + // Emit the remaining bytes as a literal + if (next_emit < ip_end) { + op = EmitLiteral(op, next_emit, ip_end - next_emit, false); + } + + return op; +} +} // end namespace internal + +// Signature of output types needed by decompression code. +// The decompression code is templatized on a type that obeys this +// signature so that we do not pay virtual function call overhead in +// the middle of a tight decompression loop. +// +// class DecompressionWriter { +// public: +// // Called before decompression +// void SetExpectedLength(size_t length); +// +// // Called after decompression +// bool CheckLength() const; +// +// // Called repeatedly during decompression +// bool Append(const char* ip, size_t length); +// bool AppendFromSelf(uint32 offset, size_t length); +// +// // The rules for how TryFastAppend differs from Append are somewhat +// // convoluted: +// // +// // - TryFastAppend is allowed to decline (return false) at any +// // time, for any reason -- just "return false" would be +// // a perfectly legal implementation of TryFastAppend. +// // The intention is for TryFastAppend to allow a fast path +// // in the common case of a small append. +// // - TryFastAppend is allowed to read up to bytes +// // from the input buffer, whereas Append is allowed to read +// // . However, if it returns true, it must leave +// // at least five (kMaximumTagLength) bytes in the input buffer +// // afterwards, so that there is always enough space to read the +// // next tag without checking for a refill. +// // - TryFastAppend must always return decline (return false) +// // if is 61 or more, as in this case the literal length is not +// // decoded fully. In practice, this should not be a big problem, +// // as it is unlikely that one would implement a fast path accepting +// // this much data. +// // +// bool TryFastAppend(const char* ip, size_t available, size_t length); +// }; + +// ----------------------------------------------------------------------- +// Lookup table for decompression code. Generated by ComputeTable() below. +// ----------------------------------------------------------------------- + +// Mapping from i in range [0,4] to a mask to extract the bottom 8*i bits +static const uint32 wordmask[] = { + 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu +}; + +// Data stored per entry in lookup table: +// Range Bits-used Description +// ------------------------------------ +// 1..64 0..7 Literal/copy length encoded in opcode byte +// 0..7 8..10 Copy offset encoded in opcode byte / 256 +// 0..4 11..13 Extra bytes after opcode +// +// We use eight bits for the length even though 7 would have sufficed +// because of efficiency reasons: +// (1) Extracting a byte is faster than a bit-field +// (2) It properly aligns copy offset so we do not need a <<8 +static const uint16 char_table[256] = { + 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002, + 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004, + 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006, + 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008, + 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a, + 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c, + 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e, + 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010, + 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012, + 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014, + 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016, + 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018, + 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a, + 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c, + 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e, + 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020, + 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022, + 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024, + 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026, + 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028, + 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a, + 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c, + 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e, + 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030, + 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032, + 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034, + 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036, + 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038, + 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a, + 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c, + 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e, + 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040 +}; + +// In debug mode, allow optional computation of the table at startup. +// Also, check that the decompression table is correct. +#ifndef NDEBUG +DEFINE_bool(snappy_dump_decompression_table, false, + "If true, we print the decompression table at startup."); + +static uint16 MakeEntry(unsigned int extra, + unsigned int len, + unsigned int copy_offset) { + // Check that all of the fields fit within the allocated space + assert(extra == (extra & 0x7)); // At most 3 bits + assert(copy_offset == (copy_offset & 0x7)); // At most 3 bits + assert(len == (len & 0x7f)); // At most 7 bits + return len | (copy_offset << 8) | (extra << 11); +} + +static void ComputeTable() { + uint16 dst[256]; + + // Place invalid entries in all places to detect missing initialization + int assigned = 0; + for (int i = 0; i < 256; i++) { + dst[i] = 0xffff; + } + + // Small LITERAL entries. We store (len-1) in the top 6 bits. + for (unsigned int len = 1; len <= 60; len++) { + dst[LITERAL | ((len-1) << 2)] = MakeEntry(0, len, 0); + assigned++; + } + + // Large LITERAL entries. We use 60..63 in the high 6 bits to + // encode the number of bytes of length info that follow the opcode. + for (unsigned int extra_bytes = 1; extra_bytes <= 4; extra_bytes++) { + // We set the length field in the lookup table to 1 because extra + // bytes encode len-1. + dst[LITERAL | ((extra_bytes+59) << 2)] = MakeEntry(extra_bytes, 1, 0); + assigned++; + } + + // COPY_1_BYTE_OFFSET. + // + // The tag byte in the compressed data stores len-4 in 3 bits, and + // offset/256 in 5 bits. offset%256 is stored in the next byte. + // + // This format is used for length in range [4..11] and offset in + // range [0..2047] + for (unsigned int len = 4; len < 12; len++) { + for (unsigned int offset = 0; offset < 2048; offset += 256) { + dst[COPY_1_BYTE_OFFSET | ((len-4)<<2) | ((offset>>8)<<5)] = + MakeEntry(1, len, offset>>8); + assigned++; + } + } + + // COPY_2_BYTE_OFFSET. + // Tag contains len-1 in top 6 bits, and offset in next two bytes. + for (unsigned int len = 1; len <= 64; len++) { + dst[COPY_2_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(2, len, 0); + assigned++; + } + + // COPY_4_BYTE_OFFSET. + // Tag contents len-1 in top 6 bits, and offset in next four bytes. + for (unsigned int len = 1; len <= 64; len++) { + dst[COPY_4_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(4, len, 0); + assigned++; + } + + // Check that each entry was initialized exactly once. + if (assigned != 256) { + fprintf(stderr, "ComputeTable: assigned only %d of 256\n", assigned); + abort(); + } + for (int i = 0; i < 256; i++) { + if (dst[i] == 0xffff) { + fprintf(stderr, "ComputeTable: did not assign byte %d\n", i); + abort(); + } + } + + if (FLAGS_snappy_dump_decompression_table) { + printf("static const uint16 char_table[256] = {\n "); + for (int i = 0; i < 256; i++) { + printf("0x%04x%s", + dst[i], + ((i == 255) ? "\n" : (((i%8) == 7) ? ",\n " : ", "))); + } + printf("};\n"); + } + + // Check that computed table matched recorded table + for (int i = 0; i < 256; i++) { + if (dst[i] != char_table[i]) { + fprintf(stderr, "ComputeTable: byte %d: computed (%x), expect (%x)\n", + i, static_cast(dst[i]), static_cast(char_table[i])); + abort(); + } + } +} +#endif /* !NDEBUG */ + +// Helper class for decompression +class SnappyDecompressor { + private: + Source* reader_; // Underlying source of bytes to decompress + const char* ip_; // Points to next buffered byte + const char* ip_limit_; // Points just past buffered bytes + uint32 peeked_; // Bytes peeked from reader (need to skip) + bool eof_; // Hit end of input without an error? + char scratch_[kMaximumTagLength]; // See RefillTag(). + + // Ensure that all of the tag metadata for the next tag is available + // in [ip_..ip_limit_-1]. Also ensures that [ip,ip+4] is readable even + // if (ip_limit_ - ip_ < 5). + // + // Returns true on success, false on error or end of input. + bool RefillTag(); + + public: + explicit SnappyDecompressor(Source* reader) + : reader_(reader), + ip_(NULL), + ip_limit_(NULL), + peeked_(0), + eof_(false) { + } + + ~SnappyDecompressor() { + // Advance past any bytes we peeked at from the reader + reader_->Skip(peeked_); + } + + // Returns true iff we have hit the end of the input without an error. + bool eof() const { + return eof_; + } + + // Read the uncompressed length stored at the start of the compressed data. + // On succcess, stores the length in *result and returns true. + // On failure, returns false. + bool ReadUncompressedLength(uint32* result) { + assert(ip_ == NULL); // Must not have read anything yet + // Length is encoded in 1..5 bytes + *result = 0; + uint32 shift = 0; + while (true) { + if (shift >= 32) return false; + size_t n; + const char* ip = reader_->Peek(&n); + if (n == 0) return false; + const unsigned char c = *(reinterpret_cast(ip)); + reader_->Skip(1); + *result |= static_cast(c & 0x7f) << shift; + if (c < 128) { + break; + } + shift += 7; + } + return true; + } + + // Process the next item found in the input. + // Returns true if successful, false on error or end of input. + template + void DecompressAllTags(Writer* writer) { + const char* ip = ip_; + + // We could have put this refill fragment only at the beginning of the loop. + // However, duplicating it at the end of each branch gives the compiler more + // scope to optimize the expression based on the local + // context, which overall increases speed. + #define MAYBE_REFILL() \ + if (ip_limit_ - ip < kMaximumTagLength) { \ + ip_ = ip; \ + if (!RefillTag()) return; \ + ip = ip_; \ + } + + MAYBE_REFILL(); + for ( ;; ) { + const unsigned char c = *(reinterpret_cast(ip++)); + + if ((c & 0x3) == LITERAL) { + size_t literal_length = (c >> 2) + 1u; + if (writer->TryFastAppend(ip, ip_limit_ - ip, literal_length)) { + assert(literal_length < 61); + ip += literal_length; + // NOTE(user): There is no MAYBE_REFILL() here, as TryFastAppend() + // will not return true unless there's already at least five spare + // bytes in addition to the literal. + continue; + } + if (PREDICT_FALSE(literal_length >= 61)) { + // Long literal. + const size_t literal_length_length = literal_length - 60; + literal_length = + (LittleEndian::Load32(ip) & wordmask[literal_length_length]) + 1; + ip += literal_length_length; + } + + size_t avail = ip_limit_ - ip; + while (avail < literal_length) { + if (!writer->Append(ip, avail)) return; + literal_length -= avail; + reader_->Skip(peeked_); + size_t n; + ip = reader_->Peek(&n); + avail = n; + peeked_ = (snappy::uint32)avail; + if (avail == 0) return; // Premature end of input + ip_limit_ = ip + avail; + } + if (!writer->Append(ip, literal_length)) { + return; + } + ip += literal_length; + MAYBE_REFILL(); + } else { + const uint32 entry = char_table[c]; + const uint32 trailer = LittleEndian::Load32(ip) & wordmask[entry >> 11]; + const uint32 length = entry & 0xff; + ip += entry >> 11; + + // copy_offset/256 is encoded in bits 8..10. By just fetching + // those bits, we get copy_offset (since the bit-field starts at + // bit 8). + const uint32 copy_offset = entry & 0x700; + if (!writer->AppendFromSelf(copy_offset + trailer, length)) { + return; + } + MAYBE_REFILL(); + } + } + +#undef MAYBE_REFILL + } +}; + +bool SnappyDecompressor::RefillTag() { + const char* ip = ip_; + if (ip == ip_limit_) { + // Fetch a new fragment from the reader + reader_->Skip(peeked_); // All peeked bytes are used up + size_t n; + ip = reader_->Peek(&n); + peeked_ = (snappy::uint32)n; + if (n == 0) { + eof_ = true; + return false; + } + ip_limit_ = ip + n; + } + + // Read the tag character + assert(ip < ip_limit_); + const unsigned char c = *(reinterpret_cast(ip)); + const uint32 entry = char_table[c]; + const uint32 needed = (entry >> 11) + 1; // +1 byte for 'c' + assert(needed <= sizeof(scratch_)); + + // Read more bytes from reader if needed + uint32 nbuf = ip_limit_ - ip; + if (nbuf < needed) { + // Stitch together bytes from ip and reader to form the word + // contents. We store the needed bytes in "scratch_". They + // will be consumed immediately by the caller since we do not + // read more than we need. + memmove(scratch_, ip, nbuf); + reader_->Skip(peeked_); // All peeked bytes are used up + peeked_ = 0; + while (nbuf < needed) { + size_t length; + const char* src = reader_->Peek(&length); + if (length == 0) return false; + uint32 to_add = Min(needed - nbuf, (uint32)length); + memcpy(scratch_ + nbuf, src, to_add); + nbuf += to_add; + reader_->Skip(to_add); + } + assert(nbuf == needed); + ip_ = scratch_; + ip_limit_ = scratch_ + needed; + } else if (nbuf < kMaximumTagLength) { + // Have enough bytes, but move into scratch_ so that we do not + // read past end of input + memmove(scratch_, ip, nbuf); + reader_->Skip(peeked_); // All peeked bytes are used up + peeked_ = 0; + ip_ = scratch_; + ip_limit_ = scratch_ + nbuf; + } else { + // Pass pointer to buffer returned by reader_. + ip_ = ip; + } + return true; +} + +template +static bool InternalUncompress(Source* r, Writer* writer) { + // Read the uncompressed length from the front of the compressed input + SnappyDecompressor decompressor(r); + uint32 uncompressed_len = 0; + if (!decompressor.ReadUncompressedLength(&uncompressed_len)) return false; + return InternalUncompressAllTags(&decompressor, writer, uncompressed_len); +} + +template +static bool InternalUncompressAllTags(SnappyDecompressor* decompressor, + Writer* writer, + uint32 uncompressed_len) { + writer->SetExpectedLength(uncompressed_len); + + // Process the entire input + decompressor->DecompressAllTags(writer); + return (decompressor->eof() && writer->CheckLength()); +} + +bool GetUncompressedLength(Source* source, uint32* result) { + SnappyDecompressor decompressor(source); + return decompressor.ReadUncompressedLength(result); +} + +size_t Compress(Source* reader, Sink* writer) { + size_t written = 0; + size_t N = reader->Available(); + char ulength[Varint::kMax32]; + char* p = Varint::Encode32(ulength, (snappy::uint32)N); + writer->Append(ulength, p-ulength); + written += (p - ulength); + + internal::WorkingMemory wmem; + char* scratch = NULL; + char* scratch_output = NULL; + + while (N > 0) { + // Get next block to compress (without copying if possible) + size_t fragment_size; + const char* fragment = reader->Peek(&fragment_size); + assert(fragment_size != 0); // premature end of input + const size_t num_to_read = vmin(N, kBlockSize); + size_t bytes_read = fragment_size; + + size_t pending_advance = 0; + if (bytes_read >= num_to_read) { + // Buffer returned by reader is large enough + pending_advance = num_to_read; + fragment_size = num_to_read; + } else { + // Read into scratch buffer + if (scratch == NULL) { + // If this is the last iteration, we want to allocate N bytes + // of space, otherwise the max possible kBlockSize space. + // num_to_read contains exactly the correct value + scratch = new char[num_to_read]; + } + memcpy(scratch, fragment, bytes_read); + reader->Skip(bytes_read); + + while (bytes_read < num_to_read) { + fragment = reader->Peek(&fragment_size); + size_t n = Min(fragment_size, num_to_read - bytes_read); + memcpy(scratch + bytes_read, fragment, n); + bytes_read += n; + reader->Skip(n); + } + assert(bytes_read == num_to_read); + fragment = scratch; + fragment_size = num_to_read; + } + assert(fragment_size == num_to_read); + + // Get encoding table for compression + int table_size; + uint16* table = wmem.GetHashTable(num_to_read, &table_size); + + // Compress input_fragment and append to dest + const int max_output = (int)MaxCompressedLength(num_to_read); + + // Need a scratch buffer for the output, in case the byte sink doesn't + // have room for us directly. + if (scratch_output == NULL) { + scratch_output = new char[max_output]; + } else { + // Since we encode kBlockSize regions followed by a region + // which is <= kBlockSize in length, a previously allocated + // scratch_output[] region is big enough for this iteration. + } + char* dest = writer->GetAppendBuffer(max_output, scratch_output); + char* end = internal::CompressFragment(fragment, fragment_size, + dest, table, table_size); + writer->Append(dest, end - dest); + written += (end - dest); + + N -= num_to_read; + reader->Skip(pending_advance); + } + + delete[] scratch; + delete[] scratch_output; + + return written; +} + +// ----------------------------------------------------------------------- +// IOVec interfaces +// ----------------------------------------------------------------------- + +// A type that writes to an iovec. +// Note that this is not a "ByteSink", but a type that matches the +// Writer template argument to SnappyDecompressor::DecompressAllTags(). +class SnappyIOVecWriter { + private: + const struct iovec* output_iov_; + const size_t output_iov_count_; + + // We are currently writing into output_iov_[curr_iov_index_]. + int curr_iov_index_; + + // Bytes written to output_iov_[curr_iov_index_] so far. + size_t curr_iov_written_; + + // Total bytes decompressed into output_iov_ so far. + size_t total_written_; + + // Maximum number of bytes that will be decompressed into output_iov_. + size_t output_limit_; + + inline char* GetIOVecPointer(int index, size_t offset) { + return reinterpret_cast(output_iov_[index].iov_base) + + offset; + } + + public: + // Does not take ownership of iov. iov must be valid during the + // entire lifetime of the SnappyIOVecWriter. + inline SnappyIOVecWriter(const struct iovec* iov, size_t iov_count) + : output_iov_(iov), + output_iov_count_(iov_count), + curr_iov_index_(0), + curr_iov_written_(0), + total_written_(0), + output_limit_((size_t)-1) { + } + + inline void SetExpectedLength(size_t len) { + output_limit_ = len; + } + + inline bool CheckLength() const { + return total_written_ == output_limit_; + } + + inline bool Append(const char* ip, size_t len) { + if (total_written_ + len > output_limit_) { + return false; + } + + while (len > 0) { + assert(curr_iov_written_ <= output_iov_[curr_iov_index_].iov_len); + if (curr_iov_written_ >= output_iov_[curr_iov_index_].iov_len) { + // This iovec is full. Go to the next one. + if (curr_iov_index_ + 1 >= output_iov_count_) { + return false; + } + curr_iov_written_ = 0; + ++curr_iov_index_; + } + + const size_t to_write = Min( + len, output_iov_[curr_iov_index_].iov_len - curr_iov_written_); + memcpy(GetIOVecPointer(curr_iov_index_, curr_iov_written_), + ip, + to_write); + curr_iov_written_ += to_write; + total_written_ += to_write; + ip += to_write; + len -= to_write; + } + + return true; + } + + inline bool TryFastAppend(const char* ip, size_t available, size_t len) { + const size_t space_left = output_limit_ - total_written_; + if (len <= 16 && available >= 16 + kMaximumTagLength && space_left >= 16 && + output_iov_[curr_iov_index_].iov_len - curr_iov_written_ >= 16) { + // Fast path, used for the majority (about 95%) of invocations. + char* ptr = GetIOVecPointer(curr_iov_index_, curr_iov_written_); + UnalignedCopy64(ip, ptr); + UnalignedCopy64(ip + 8, ptr + 8); + curr_iov_written_ += len; + total_written_ += len; + return true; + } + + return false; + } + + inline bool AppendFromSelf(size_t offset, size_t len) { + if (offset > total_written_ || offset == 0) { + return false; + } + const size_t space_left = output_limit_ - total_written_; + if (len > space_left) { + return false; + } + + // Locate the iovec from which we need to start the copy. + int from_iov_index = curr_iov_index_; + size_t from_iov_offset = curr_iov_written_; + while (offset > 0) { + if (from_iov_offset >= offset) { + from_iov_offset -= offset; + break; + } + + offset -= from_iov_offset; + --from_iov_index; + assert(from_iov_index >= 0); + from_iov_offset = output_iov_[from_iov_index].iov_len; + } + + // Copy bytes starting from the iovec pointed to by from_iov_index to + // the current iovec. + while (len > 0) { + assert(from_iov_index <= curr_iov_index_); + if (from_iov_index != curr_iov_index_) { + const size_t to_copy = Min( + output_iov_[from_iov_index].iov_len - from_iov_offset, + len); + Append(GetIOVecPointer(from_iov_index, from_iov_offset), to_copy); + len -= to_copy; + if (len > 0) { + ++from_iov_index; + from_iov_offset = 0; + } + } else { + assert(curr_iov_written_ <= output_iov_[curr_iov_index_].iov_len); + size_t to_copy = Min(output_iov_[curr_iov_index_].iov_len - + curr_iov_written_, + len); + if (to_copy == 0) { + // This iovec is full. Go to the next one. + if (curr_iov_index_ + 1 >= output_iov_count_) { + return false; + } + ++curr_iov_index_; + curr_iov_written_ = 0; + continue; + } + if (to_copy > len) { + to_copy = len; + } + IncrementalCopy(GetIOVecPointer(from_iov_index, from_iov_offset), + GetIOVecPointer(curr_iov_index_, curr_iov_written_), + to_copy); + curr_iov_written_ += to_copy; + from_iov_offset += to_copy; + total_written_ += to_copy; + len -= to_copy; + } + } + + return true; + } + +}; + +bool RawUncompressToIOVec(const char* compressed, size_t compressed_length, + const struct iovec* iov, size_t iov_cnt) { + ByteArraySource reader(compressed, compressed_length); + return RawUncompressToIOVec(&reader, iov, iov_cnt); +} + +bool RawUncompressToIOVec(Source* compressed, const struct iovec* iov, + size_t iov_cnt) { + SnappyIOVecWriter output(iov, iov_cnt); + return InternalUncompress(compressed, &output); +} + +// ----------------------------------------------------------------------- +// Flat array interfaces +// ----------------------------------------------------------------------- + +// A type that writes to a flat array. +// Note that this is not a "ByteSink", but a type that matches the +// Writer template argument to SnappyDecompressor::DecompressAllTags(). +class SnappyArrayWriter { + private: + char* base_; + char* op_; + char* op_limit_; + + public: + inline explicit SnappyArrayWriter(char* dst) + : base_(dst), + op_(dst) { + } + + inline void SetExpectedLength(size_t len) { + op_limit_ = op_ + len; + } + + inline bool CheckLength() const { + return op_ == op_limit_; + } + + inline bool Append(const char* ip, size_t len) { + char* op = op_; + const size_t space_left = op_limit_ - op; + if (space_left < len) { + return false; + } + memcpy(op, ip, len); + op_ = op + len; + return true; + } + + inline bool TryFastAppend(const char* ip, size_t available, size_t len) { + char* op = op_; + const size_t space_left = op_limit_ - op; + if (len <= 16 && available >= 16 + kMaximumTagLength && space_left >= 16) { + // Fast path, used for the majority (about 95%) of invocations. + UnalignedCopy64(ip, op); + UnalignedCopy64(ip + 8, op + 8); + op_ = op + len; + return true; + } else { + return false; + } + } + + inline bool AppendFromSelf(size_t offset, size_t len) { + char* op = op_; + const size_t space_left = op_limit_ - op; + + // Check if we try to append from before the start of the buffer. + // Normally this would just be a check for "produced < offset", + // but "produced <= offset - 1u" is equivalent for every case + // except the one where offset==0, where the right side will wrap around + // to a very big number. This is convenient, as offset==0 is another + // invalid case that we also want to catch, so that we do not go + // into an infinite loop. + assert(op >= base_); + size_t produced = op - base_; + if (produced <= offset - 1u) { + return false; + } + if (len <= 16 && offset >= 8 && space_left >= 16) { + // Fast path, used for the majority (70-80%) of dynamic invocations. + UnalignedCopy64(op - offset, op); + UnalignedCopy64(op - offset + 8, op + 8); + } else { + if (space_left >= len + kMaxIncrementCopyOverflow) { + IncrementalCopyFastPath(op - offset, op, len); + } else { + if (space_left < len) { + return false; + } + IncrementalCopy(op - offset, op, len); + } + } + + op_ = op + len; + return true; + } +}; + +bool RawUncompress(const char* compressed, size_t n, char* uncompressed) { + ByteArraySource reader(compressed, n); + return RawUncompress(&reader, uncompressed); +} + +bool RawUncompress(Source* compressed, char* uncompressed) { + SnappyArrayWriter output(uncompressed); + return InternalUncompress(compressed, &output); +} + +bool Uncompress(const char* compressed, size_t n, string* uncompressed) { + size_t ulength; + if (!GetUncompressedLength(compressed, n, &ulength)) { + return false; + } + // On 32-bit builds: max_size() < kuint32max. Check for that instead + // of crashing (e.g., consider externally specified compressed data). + if (ulength > uncompressed->max_size()) { + return false; + } + STLStringResizeUninitialized(uncompressed, ulength); + return RawUncompress(compressed, n, string_as_array(uncompressed)); +} + + +// A Writer that drops everything on the floor and just does validation +class SnappyDecompressionValidator { + private: + size_t expected_; + size_t produced_; + + public: + inline SnappyDecompressionValidator() : produced_(0) { } + inline void SetExpectedLength(size_t len) { + expected_ = len; + } + inline bool CheckLength() const { + return expected_ == produced_; + } + inline bool Append(const char* ip, size_t len) { + produced_ += len; + return produced_ <= expected_; + } + inline bool TryFastAppend(const char* ip, size_t available, size_t length) { + return false; + } + inline bool AppendFromSelf(size_t offset, size_t len) { + // See SnappyArrayWriter::AppendFromSelf for an explanation of + // the "offset - 1u" trick. + if (produced_ <= offset - 1u) return false; + produced_ += len; + return produced_ <= expected_; + } +}; + +bool IsValidCompressedBuffer(const char* compressed, size_t n) { + ByteArraySource reader(compressed, n); + SnappyDecompressionValidator writer; + return InternalUncompress(&reader, &writer); +} + +void RawCompress(const char* input, + size_t input_length, + char* compressed, + size_t* compressed_length) { + ByteArraySource reader(input, input_length); + UncheckedByteArraySink writer(compressed); + Compress(&reader, &writer); + + // Compute how many bytes were added + *compressed_length = (writer.CurrentDestination() - compressed); +} + +size_t Compress(const char* input, size_t input_length, string* compressed) { + // Pre-grow the buffer to the max length of the compressed output + compressed->resize(MaxCompressedLength(input_length)); + + size_t compressed_length; + RawCompress(input, input_length, string_as_array(compressed), + &compressed_length); + compressed->resize(compressed_length); + return compressed_length; +} + + +} // end namespace snappy + diff --git a/tier1/sparsematrix.cpp b/tier1/sparsematrix.cpp new file mode 100644 index 0000000..3a2df54 --- /dev/null +++ b/tier1/sparsematrix.cpp @@ -0,0 +1,141 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//===========================================================================// + +#include "tier1/sparsematrix.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +void CSparseMatrix::AdjustAllRowIndicesAfter( int nStartRow, int nDelta ) +{ + // now, we need to offset the starting position of all subsequent rows by -1 to compensate for the removal of this element + for( int nOtherRow = nStartRow + 1 ; nOtherRow < Height(); nOtherRow++ ) + { + m_rowDescriptors[nOtherRow].m_nDataIndex += nDelta; + } +} + +void CSparseMatrix::SetDimensions( int nNumRows, int nNumCols ) +{ + m_nNumRows = nNumRows; + m_nNumCols = nNumCols; + m_entries.SetCount( 0 ); + m_rowDescriptors.SetCount( m_nNumRows ); + // and set all rows to be empty + for( int i = 0; i < m_nNumRows; i++ ) + { + m_rowDescriptors[i].m_nNonZeroCount = 0; + m_rowDescriptors[i].m_nDataIndex = 0; + } + m_nHighestRowAppendedTo = -1; + +} + + +void CSparseMatrix::SetElement( int nRow, int nCol, float flValue ) +{ + Assert( nCol < m_nNumCols ); + int nCount = m_rowDescriptors[nRow].m_nNonZeroCount; + bool bValueIsZero = ( flValue == 0.0 ); + int nFirstEntryIndex = m_rowDescriptors[nRow].m_nDataIndex; + if ( nCount ) + { + NonZeroValueDescriptor_t *pValue = &( m_entries[nFirstEntryIndex] ); + int i; + for( i = 0; i < nCount; i++ ) + { + int nIdx = pValue->m_nColumnNumber; + if ( nIdx == nCol ) // we found it! + { + if ( !bValueIsZero ) + { + // we want to overwrite the existing value + pValue->m_flValue = flValue; + } + else + { + // there is a non-zero element currently at this position. We need to remove it + // and we need to remove its storage. + m_rowDescriptors[nRow].m_nNonZeroCount--; + m_entries.Remove( nFirstEntryIndex + i ); + // now, we need to offset the starting position of all subsequent rows by -1 to compensate for the removal of this element + AdjustAllRowIndicesAfter( nRow, -1 ); + } + return; + } + if ( nIdx > nCol ) + { + break; + } + pValue++; + } + // we did not find an entry for this cell. If we were writing zero, fine - we are + // done, otherwise insert + if (! bValueIsZero ) + { + m_rowDescriptors[nRow].m_nNonZeroCount++; + NonZeroValueDescriptor_t newValue; + newValue.m_nColumnNumber = nCol; + newValue.m_flValue = flValue; + if ( i == nCount ) // need to append + { + m_entries.InsertAfter( nFirstEntryIndex + nCount - 1, newValue ); + } + else + { + m_entries.InsertBefore( nFirstEntryIndex + i, newValue ); + } + // now, we need to offset the starting position of all subsequent rows by -1 to compensate for the addition of this element + AdjustAllRowIndicesAfter( nRow, +1 ); + } + } + else + { + // row is empty. We may need to insert + if ( ! bValueIsZero ) + { + m_rowDescriptors[nRow].m_nNonZeroCount++; + NonZeroValueDescriptor_t newValue; + newValue.m_nColumnNumber = nCol; + newValue.m_flValue = flValue; + m_entries.InsertBefore( nFirstEntryIndex, newValue ); + AdjustAllRowIndicesAfter( nRow, +1 ); + } + } +} + +void CSparseMatrix::FinishedAppending( void ) +{ + // set all pointers to space for subsequent rows to the right value + for( int i = m_nHighestRowAppendedTo + 1 ; i < Height(); i++ ) + { + m_rowDescriptors[i].m_nDataIndex = m_entries.Count(); + } +} + +void CSparseMatrix::AppendElement( int nRow, int nColumn, float flValue ) +{ + if ( flValue != 0.0 ) + { + if ( m_nHighestRowAppendedTo != nRow ) + { + Assert( nRow > m_nHighestRowAppendedTo ); + for( int i = m_nHighestRowAppendedTo + 1; i <= nRow; i++ ) + { + m_rowDescriptors[i].m_nDataIndex = m_entries.Count(); + } + } + m_nHighestRowAppendedTo = nRow; + m_rowDescriptors[nRow].m_nNonZeroCount++; + NonZeroValueDescriptor_t newDesc; + newDesc.m_nColumnNumber = nColumn; + newDesc.m_flValue = flValue; + m_entries.AddToTail( newDesc ); + } +} + + + + diff --git a/tier1/splitstring.cpp b/tier1/splitstring.cpp new file mode 100644 index 0000000..448f6d0 --- /dev/null +++ b/tier1/splitstring.cpp @@ -0,0 +1,92 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//================================================================================================== + +#include "strtools.h" +#include "utlvector.h" + +CSplitString::CSplitString(const char *pString, const char **pSeparators, int nSeparators) +{ + Construct(pString, pSeparators, nSeparators); +}; + +CSplitString::CSplitString( const char *pString, const char *pSeparator) +{ + Construct( pString, &pSeparator, 1 ); +} + +CSplitString::~CSplitString() +{ + if(m_szBuffer) + delete [] m_szBuffer; +} + +void CSplitString::Construct( const char *pString, const char **pSeparators, int nSeparators ) +{ + ////////////////////////////////////////////////////////////////////////// + // make a duplicate of the original string. We'll use pieces of this duplicate to tokenize the string + // and create NULL-terminated tokens of the original string + // + int nOriginalStringLength = V_strlen(pString); + m_szBuffer = new char[nOriginalStringLength + 1]; + memcpy(m_szBuffer, pString, nOriginalStringLength + 1); + + this->Purge(); + const char *pCurPos = pString; + while ( 1 ) + { + int iFirstSeparator = -1; + const char *pFirstSeparator = 0; + for ( int i=0; i < nSeparators; i++ ) + { + const char *pTest = V_stristr( pCurPos, pSeparators[i] ); + if ( pTest && (!pFirstSeparator || pTest < pFirstSeparator) ) + { + iFirstSeparator = i; + pFirstSeparator = pTest; + } + } + + if ( pFirstSeparator ) + { + // Split on this separator and continue on. + int separatorLen = strlen( pSeparators[iFirstSeparator] ); + if ( pFirstSeparator > pCurPos ) + { + ////////////////////////////////////////////////////////////////////////// + /// Cut the token out of the duplicate string + char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString); + int nTokenLength = pFirstSeparator-pCurPos; + Assert(nTokenLength > 0 && !memcmp(pTokenInDuplicate,pCurPos,nTokenLength)); + pTokenInDuplicate[nTokenLength] = '\0'; + + this->AddToTail( pTokenInDuplicate /*AllocString( pCurPos, pFirstSeparator-pCurPos )*/ ); + } + + pCurPos = pFirstSeparator + separatorLen; + } + else + { + // Copy the rest of the string + int nTokenLength = strlen( pCurPos ); + if ( nTokenLength ) + { + ////////////////////////////////////////////////////////////////////////// + // There's no need to cut this token, because there's no separator after it. + // just add its copy in the buffer to the tail + char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString); + Assert(!memcmp(pTokenInDuplicate, pCurPos, nTokenLength)); + + this->AddToTail( pTokenInDuplicate/*AllocString( pCurPos, -1 )*/ ); + } + return; + } + } +} + +void CSplitString::PurgeAndDeleteElements() +{ + Purge(); +} diff --git a/tier1/stringpool.cpp b/tier1/stringpool.cpp new file mode 100644 index 0000000..6b6b0ff --- /dev/null +++ b/tier1/stringpool.cpp @@ -0,0 +1,334 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "convar.h" +#include "tier0/dbg.h" +#include "stringpool.h" +#include "tier1/strtools.h" +#include "generichash.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Comparison function for string sorted associative data structures +//----------------------------------------------------------------------------- + +bool StrLess( const char * const &pszLeft, const char * const &pszRight ) +{ + return ( Q_stricmp( pszLeft, pszRight) < 0 ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +CStringPool::CStringPool() + : m_Strings( 32, 256, StrLess ) +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +CStringPool::~CStringPool() +{ + FreeAll(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +unsigned int CStringPool::Count() const +{ + return m_Strings.Count(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char * CStringPool::Find( const char *pszValue ) +{ + unsigned short i = m_Strings.Find(pszValue); + if ( m_Strings.IsValidIndex(i) ) + return m_Strings[i]; + + return NULL; +} + +const char * CStringPool::Allocate( const char *pszValue ) +{ + char *pszNew; + + unsigned short i = m_Strings.Find(pszValue); + bool bNew = (i == m_Strings.InvalidIndex()); + + if ( !bNew ) + return m_Strings[i]; + + pszNew = strdup( pszValue ); + + if ( bNew ) + m_Strings.Insert( pszNew ); + + return pszNew; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +void CStringPool::FreeAll() +{ + unsigned short i = m_Strings.FirstInorder(); + while ( i != m_Strings.InvalidIndex() ) + { + free( (void *)m_Strings[i] ); + i = m_Strings.NextInorder(i); + } + m_Strings.RemoveAll(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + + +CCountedStringPool::CCountedStringPool() +{ + MEM_ALLOC_CREDIT(); + m_HashTable.EnsureCount(HASH_TABLE_SIZE); + + for( int i = 0; i < m_HashTable.Count(); i++ ) + { + m_HashTable[i] = INVALID_ELEMENT; + } + + m_FreeListStart = INVALID_ELEMENT; + m_Elements.AddToTail(); + m_Elements[0].pString = NULL; + m_Elements[0].nReferenceCount = 0; + m_Elements[0].nNextElement = INVALID_ELEMENT; +} + +CCountedStringPool::~CCountedStringPool() +{ + FreeAll(); +} + +void CCountedStringPool::FreeAll() +{ + int i; + + // Reset the hash table: + for( i = 0; i < m_HashTable.Count(); i++ ) + { + m_HashTable[i] = INVALID_ELEMENT; + } + + // Blow away the free list: + m_FreeListStart = INVALID_ELEMENT; + + for( i = 0; i < m_Elements.Count(); i++ ) + { + if( m_Elements[i].pString ) + { + delete [] m_Elements[i].pString; + m_Elements[i].pString = NULL; + m_Elements[i].nReferenceCount = 0; + m_Elements[i].nNextElement = INVALID_ELEMENT; + } + } + + // Remove all but the invalid element: + m_Elements.RemoveAll(); + m_Elements.AddToTail(); + m_Elements[0].pString = NULL; + m_Elements[0].nReferenceCount = 0; + m_Elements[0].nNextElement = INVALID_ELEMENT; +} + + +unsigned short CCountedStringPool::FindStringHandle( const char* pIntrinsic ) +{ + if( pIntrinsic == NULL ) + return INVALID_ELEMENT; + + unsigned short nHashBucketIndex = (HashStringCaseless(pIntrinsic ) %HASH_TABLE_SIZE); + unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ]; + + // Does the bucket already exist? + if( nCurrentBucket != INVALID_ELEMENT ) + { + for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) + { + if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) + { + return nCurrentBucket; + } + } + } + + return 0; + +} + +char* CCountedStringPool::FindString( const char* pIntrinsic ) +{ + if( pIntrinsic == NULL ) + return NULL; + + // Yes, this will be NULL on failure. + return m_Elements[FindStringHandle(pIntrinsic)].pString; +} + +unsigned short CCountedStringPool::ReferenceStringHandle( const char* pIntrinsic ) +{ + if( pIntrinsic == NULL ) + return INVALID_ELEMENT; + + unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % HASH_TABLE_SIZE); + unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ]; + + // Does the bucket already exist? + if( nCurrentBucket != INVALID_ELEMENT ) + { + for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) + { + if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) + { + // Anyone who hits 65k references is permanant + if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE ) + { + m_Elements[nCurrentBucket].nReferenceCount ++ ; + } + return nCurrentBucket; + } + } + } + + if( m_FreeListStart != INVALID_ELEMENT ) + { + nCurrentBucket = m_FreeListStart; + m_FreeListStart = m_Elements[nCurrentBucket].nNextElement; + } + else + { + nCurrentBucket = m_Elements.AddToTail(); + } + + m_Elements[nCurrentBucket].nReferenceCount = 1; + + // Insert at the beginning of the bucket: + m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ]; + m_HashTable[ nHashBucketIndex ] = nCurrentBucket; + + m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1]; + Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic ); + + return nCurrentBucket; +} + + +char* CCountedStringPool::ReferenceString( const char* pIntrinsic ) +{ + if(!pIntrinsic) + return NULL; + + return m_Elements[ReferenceStringHandle( pIntrinsic)].pString; +} + +void CCountedStringPool::DereferenceString( const char* pIntrinsic ) +{ + // If we get a NULL pointer, just return + if (!pIntrinsic) + return; + + unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % m_HashTable.Count()); + unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ]; + + // If there isn't anything in the bucket, just return. + if ( nCurrentBucket == INVALID_ELEMENT ) + return; + + for( unsigned short previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) + { + if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) + { + // Anyone who hits 65k references is permanant + if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE ) + { + m_Elements[nCurrentBucket].nReferenceCount --; + } + + if( m_Elements[nCurrentBucket].nReferenceCount == 0 ) + { + if( previous == INVALID_ELEMENT ) + { + m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement; + } + else + { + m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement; + } + + delete [] m_Elements[nCurrentBucket].pString; + m_Elements[nCurrentBucket].pString = NULL; + m_Elements[nCurrentBucket].nReferenceCount = 0; + + m_Elements[nCurrentBucket].nNextElement = m_FreeListStart; + m_FreeListStart = nCurrentBucket; + break; + + } + } + + previous = nCurrentBucket; + } +} + +char* CCountedStringPool::HandleToString( unsigned short handle ) +{ + return m_Elements[handle].pString; +} + +void CCountedStringPool::SpewStrings() +{ + int i; + for ( i = 0; i < m_Elements.Count(); i++ ) + { + char* string = m_Elements[i].pString; + + Msg("String %d: ref:%d %s", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string); + } + + Msg("\n%d total counted strings.", m_Elements.Count()); +} + +#ifdef _DEBUG +CON_COMMAND( test_stringpool, "Tests the class CStringPool" ) +{ + CStringPool pool; + + Assert(pool.Count() == 0); + + pool.Allocate("test"); + Assert(pool.Count() == 1); + + pool.Allocate("test"); + Assert(pool.Count() == 1); + + pool.Allocate("test2"); + Assert(pool.Count() == 2); + + Assert( pool.Find("test2") != NULL ); + Assert( pool.Find("TEST") != NULL ); + Assert( pool.Find("Test2") != NULL ); + Assert( pool.Find("test") != NULL ); + + pool.FreeAll(); + Assert(pool.Count() == 0); + + Msg("Pass."); +} +#endif diff --git a/tier1/strtools.cpp b/tier1/strtools.cpp new file mode 100644 index 0000000..c027f0e --- /dev/null +++ b/tier1/strtools.cpp @@ -0,0 +1,2982 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: String Tools +// +//===========================================================================// + +// These are redefined in the project settings to prevent anyone from using them. +// We in this module are of a higher caste and thus are privileged in their use. +#ifdef strncpy + #undef strncpy +#endif + +#ifdef _snprintf + #undef _snprintf +#endif + +#if defined( sprintf ) + #undef sprintf +#endif + +#if defined( vsprintf ) + #undef vsprintf +#endif + +#ifdef _vsnprintf +#ifdef _WIN32 + #undef _vsnprintf +#endif +#endif + +#ifdef vsnprintf +#ifndef _WIN32 + #undef vsnprintf +#endif +#endif + +#if defined( strcat ) + #undef strcat +#endif + +#ifdef strncat + #undef strncat +#endif + +// NOTE: I have to include stdio + stdarg first so vsnprintf gets compiled in +#include +#include + +#ifdef POSIX +#include +#include +#include +#include +#define _getcwd getcwd +#elif _WIN32 +#include +#if !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#endif + +#ifdef _WIN32 +#ifndef CP_UTF8 +#define CP_UTF8 65001 +#endif +#endif +#include "tier0/dbg.h" +#include "tier1/strtools.h" +#include +#include +#include +#include "tier0/basetypes.h" +#include "tier1/utldict.h" +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif +#include "tier0/memdbgon.h" + +static int FastToLower( char c ) +{ + int i = (unsigned char) c; + if ( i < 0x80 ) + { + // Brutally fast branchless ASCII tolower(): + i += (((('A'-1) - i) & (i - ('Z'+1))) >> 26) & 0x20; + } + else + { + i += isupper( i ) ? 0x20 : 0; + } + return i; +} + +void _V_memset (const char* file, int line, void *dest, int fill, int count) +{ + Assert( count >= 0 ); + AssertValidWritePtr( dest, count ); + + memset(dest,fill,count); +} + +void _V_memcpy (const char* file, int line, void *dest, const void *src, int count) +{ + Assert( count >= 0 ); + AssertValidReadPtr( src, count ); + AssertValidWritePtr( dest, count ); + + memcpy( dest, src, count ); +} + +void _V_memmove(const char* file, int line, void *dest, const void *src, int count) +{ + Assert( count >= 0 ); + AssertValidReadPtr( src, count ); + AssertValidWritePtr( dest, count ); + + memmove( dest, src, count ); +} + +int _V_memcmp (const char* file, int line, const void *m1, const void *m2, int count) +{ + Assert( count >= 0 ); + AssertValidReadPtr( m1, count ); + AssertValidReadPtr( m2, count ); + + return memcmp( m1, m2, count ); +} + +int _V_strlen(const char* file, int line, const char *str) +{ + AssertValidStringPtr(str); + return strlen( str ); +} + +void _V_strcpy (const char* file, int line, char *dest, const char *src) +{ + AssertValidWritePtr(dest); + AssertValidStringPtr(src); + + strcpy( dest, src ); +} + +int _V_wcslen(const char* file, int line, const wchar_t *pwch) +{ + return wcslen( pwch ); +} + +char *_V_strrchr(const char* file, int line, const char *s, char c) +{ + AssertValidStringPtr( s ); + int len = V_strlen(s); + s += len; + while (len--) + if (*--s == c) return (char *)s; + return 0; +} + +int _V_strcmp (const char* file, int line, const char *s1, const char *s2) +{ + AssertValidStringPtr( s1 ); + AssertValidStringPtr( s2 ); + + return strcmp( s1, s2 ); +} + +int _V_wcscmp (const char* file, int line, const wchar_t *s1, const wchar_t *s2) +{ + AssertValidReadPtr( s1 ); + AssertValidReadPtr( s2 ); + + while ( *s1 == *s2 ) + { + if ( !*s1 ) + return 0; // strings are equal + + s1++; + s2++; + } + + return *s1 > *s2 ? 1 : -1; // strings not equal +} + + +char *_V_strstr(const char* file, int line, const char *s1, const char *search ) +{ + AssertValidStringPtr( s1 ); + AssertValidStringPtr( search ); + +#if defined( _X360 ) + return (char *)strstr( (char *)s1, search ); +#else + return (char *)strstr( s1, search ); +#endif +} + +wchar_t *_V_wcsupr (const char* file, int line, wchar_t *start) +{ + return _wcsupr( start ); +} + + +wchar_t *_V_wcslower (const char* file, int line, wchar_t *start) +{ + return _wcslwr(start); +} + + + +char *V_strupr( char *start ) +{ + unsigned char *str = (unsigned char*)start; + while( *str ) + { + if ( (unsigned char)(*str - 'a') <= ('z' - 'a') ) + *str -= 'a' - 'A'; + else if ( (unsigned char)*str >= 0x80 ) // non-ascii, fall back to CRT + *str = toupper( *str ); + str++; + } + return start; +} + +char *V_strlower( char *start ) +{ + unsigned char *str = (unsigned char*)start; + while( *str ) + { + if ( (unsigned char)(*str - 'A') <= ('Z' - 'A') ) + *str += 'a' - 'A'; + else if ( (unsigned char)*str >= 0x80 ) // non-ascii, fall back to CRT + *str = tolower( *str ); + str++; + } + return start; +} + +char *V_strnlwr(char *s, size_t count) +{ + // Assert( count >= 0 ); tautology since size_t is unsigned + AssertValidStringPtr( s, count ); + + char* pRet = s; + if ( !s || !count ) + return s; + + while ( -- count > 0 ) + { + if ( !*s ) + return pRet; // reached end of string + + *s = tolower( *s ); + ++s; + } + + *s = 0; // null-terminate original string at "count-1" + return pRet; +} + +int V_stricmp( const char *str1, const char *str2 ) +{ + // It is not uncommon to compare a string to itself. See + // VPanelWrapper::GetPanel which does this a lot. Since stricmp + // is expensive and pointer comparison is cheap, this simple test + // can save a lot of cycles, and cache pollution. + if ( str1 == str2 ) + { + return 0; + } + const unsigned char *s1 = (const unsigned char*)str1; + const unsigned char *s2 = (const unsigned char*)str2; + for ( ; *s1; ++s1, ++s2 ) + { + if ( *s1 != *s2 ) + { + // in ascii char set, lowercase = uppercase | 0x20 + unsigned char c1 = *s1 | 0x20; + unsigned char c2 = *s2 | 0x20; + if ( c1 != c2 || (unsigned char)(c1 - 'a') > ('z' - 'a') ) + { + // if non-ascii mismatch, fall back to CRT for locale + if ( (c1 | c2) >= 0x80 ) return stricmp( (const char*)s1, (const char*)s2 ); + // ascii mismatch. only use the | 0x20 value if alphabetic. + if ((unsigned char)(c1 - 'a') > ('z' - 'a')) c1 = *s1; + if ((unsigned char)(c2 - 'a') > ('z' - 'a')) c2 = *s2; + return c1 > c2 ? 1 : -1; + } + } + } + return *s2 ? -1 : 0; +} + +int V_strnicmp( const char *str1, const char *str2, int n ) +{ + const unsigned char *s1 = (const unsigned char*)str1; + const unsigned char *s2 = (const unsigned char*)str2; + for ( ; n > 0 && *s1; --n, ++s1, ++s2 ) + { + if ( *s1 != *s2 ) + { + // in ascii char set, lowercase = uppercase | 0x20 + unsigned char c1 = *s1 | 0x20; + unsigned char c2 = *s2 | 0x20; + if ( c1 != c2 || (unsigned char)(c1 - 'a') > ('z' - 'a') ) + { + // if non-ascii mismatch, fall back to CRT for locale + if ( (c1 | c2) >= 0x80 ) return strnicmp( (const char*)s1, (const char*)s2, n ); + // ascii mismatch. only use the | 0x20 value if alphabetic. + if ((unsigned char)(c1 - 'a') > ('z' - 'a')) c1 = *s1; + if ((unsigned char)(c2 - 'a') > ('z' - 'a')) c2 = *s2; + return c1 > c2 ? 1 : -1; + } + } + } + return (n > 0 && *s2) ? -1 : 0; +} + +int V_strncmp( const char *s1, const char *s2, int count ) +{ + Assert( count >= 0 ); + AssertValidStringPtr( s1, count ); + AssertValidStringPtr( s2, count ); + + while ( count > 0 ) + { + if ( *s1 != *s2 ) + return (unsigned char)*s1 < (unsigned char)*s2 ? -1 : 1; // string different + if ( *s1 == '\0' ) + return 0; // null terminator hit - strings the same + s1++; + s2++; + count--; + } + + return 0; // count characters compared the same +} + + +const char *StringAfterPrefix( const char *str, const char *prefix ) +{ + AssertValidStringPtr( str ); + AssertValidStringPtr( prefix ); + do + { + if ( !*prefix ) + return str; + } + while ( FastToLower( *str++ ) == FastToLower( *prefix++ ) ); + return NULL; +} + +const char *StringAfterPrefixCaseSensitive( const char *str, const char *prefix ) +{ + AssertValidStringPtr( str ); + AssertValidStringPtr( prefix ); + do + { + if ( !*prefix ) + return str; + } + while ( *str++ == *prefix++ ); + return NULL; +} + + +int64 V_atoi64( const char *str ) +{ + AssertValidStringPtr( str ); + + int64 val; + int64 sign; + int64 c; + + Assert( str ); + if (*str == '-') + { + sign = -1; + str++; + } + else + sign = 1; + + val = 0; + +// +// check for hex +// + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val<<4) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val<<4) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val<<4) + c - 'A' + 10; + else + return val*sign; + } + } + +// +// check for character +// + if (str[0] == '\'') + { + return sign * str[1]; + } + +// +// assume decimal +// + while (1) + { + c = *str++; + if (c <'0' || c > '9') + return val*sign; + val = val*10 + c - '0'; + } + + return 0; +} + +uint64 V_atoui64( const char *str ) +{ + AssertValidStringPtr( str ); + + uint64 val; + uint64 c; + + Assert( str ); + + val = 0; + + // + // check for hex + // + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val<<4) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val<<4) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val<<4) + c - 'A' + 10; + else + return val; + } + } + + // + // check for character + // + if (str[0] == '\'') + { + return str[1]; + } + + // + // assume decimal + // + while (1) + { + c = *str++; + if (c <'0' || c > '9') + return val; + val = val*10 + c - '0'; + } + + return 0; +} + +int V_atoi( const char *str ) +{ + return (int)V_atoi64( str ); +} + +float V_atof (const char *str) +{ + AssertValidStringPtr( str ); + double val; + int sign; + int c; + int decimal, total; + + if (*str == '-') + { + sign = -1; + str++; + } + else if (*str == '+') + { + sign = 1; + str++; + } + else + { + sign = 1; + } + + val = 0; + + // + // check for hex + // + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val*16) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val*16) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val*16) + c - 'A' + 10; + else + return (float)(val*sign); + } + } + + // + // check for character + // + if (str[0] == '\'') + { + return (float)(sign * str[1]); + } + + // + // assume decimal + // + decimal = -1; + total = 0; + int exponent = 0; + while (1) + { + c = *str++; + if (c == '.') + { + if ( decimal != -1 ) + { + break; + } + + decimal = total; + continue; + } + if (c <'0' || c > '9') + { + if ( c == 'e' || c == 'E' ) + { + exponent = V_atoi(str); + } + break; + } + val = val*10 + c - '0'; + total++; + } + + if ( exponent != 0 ) + { + val *= pow( 10.0, exponent ); + } + if (decimal == -1) + return (float)(val*sign); + while (total > decimal) + { + val /= 10; + total--; + } + + return (float)(val*sign); +} + +//----------------------------------------------------------------------------- +// Normalizes a float string in place. +// +// (removes leading zeros, trailing zeros after the decimal point, and the decimal point itself where possible) +//----------------------------------------------------------------------------- +void V_normalizeFloatString( char* pFloat ) +{ + // If we have a decimal point, remove trailing zeroes: + if( strchr( pFloat,'.' ) ) + { + int len = V_strlen(pFloat); + + while( len > 1 && pFloat[len - 1] == '0' ) + { + pFloat[len - 1] = '\0'; + len--; + } + + if( len > 1 && pFloat[ len - 1 ] == '.' ) + { + pFloat[len - 1] = '\0'; + len--; + } + } + + // TODO: Strip leading zeros + +} + + +//----------------------------------------------------------------------------- +// Finds a string in another string with a case insensitive test +//----------------------------------------------------------------------------- +char const* V_stristr( char const* pStr, char const* pSearch ) +{ + AssertValidStringPtr(pStr); + AssertValidStringPtr(pSearch); + + if (!pStr || !pSearch) + return 0; + + char const* pLetter = pStr; + + // Check the entire string + while (*pLetter != 0) + { + // Skip over non-matches + if (FastToLower((unsigned char)*pLetter) == FastToLower((unsigned char)*pSearch)) + { + // Check for match + char const* pMatch = pLetter + 1; + char const* pTest = pSearch + 1; + while (*pTest != 0) + { + // We've run off the end; don't bother. + if (*pMatch == 0) + return 0; + + if (FastToLower((unsigned char)*pMatch) != FastToLower((unsigned char)*pTest)) + break; + + ++pMatch; + ++pTest; + } + + // Found a match! + if (*pTest == 0) + return pLetter; + } + + ++pLetter; + } + + return 0; +} + +char* V_stristr( char* pStr, char const* pSearch ) +{ + AssertValidStringPtr( pStr ); + AssertValidStringPtr( pSearch ); + + return (char*)V_stristr( (char const*)pStr, pSearch ); +} + +//----------------------------------------------------------------------------- +// Finds a string in another string with a case insensitive test w/ length validation +//----------------------------------------------------------------------------- + +char const* V_strnistr( char const* pStr, char const* pSearch, int n ) +{ + AssertValidStringPtr(pStr); + AssertValidStringPtr(pSearch); + + if (!pStr || !pSearch) + return 0; + + char const* pLetter = pStr; + + // Check the entire string + while (*pLetter != 0) + { + if ( n <= 0 ) + return 0; + + // Skip over non-matches + if (FastToLower(*pLetter) == FastToLower(*pSearch)) + { + int n1 = n - 1; + + // Check for match + char const* pMatch = pLetter + 1; + char const* pTest = pSearch + 1; + while (*pTest != 0) + { + if ( n1 <= 0 ) + return 0; + + // We've run off the end; don't bother. + if (*pMatch == 0) + return 0; + + if (FastToLower(*pMatch) != FastToLower(*pTest)) + break; + + ++pMatch; + ++pTest; + --n1; + } + + // Found a match! + if (*pTest == 0) + return pLetter; + } + + ++pLetter; + --n; + } + + return 0; +} + +const char* V_strnchr( const char* pStr, char c, int n ) +{ + char const* pLetter = pStr; + char const* pLast = pStr + n; + + // Check the entire string + while ( (pLetter < pLast) && (*pLetter != 0) ) + { + if (*pLetter == c) + return pLetter; + ++pLetter; + } + return NULL; +} + +void V_strncpy( char *pDest, char const *pSrc, int maxLen ) +{ + Assert( maxLen >= sizeof( *pDest ) ); + AssertValidWritePtr( pDest, maxLen ); + AssertValidStringPtr( pSrc ); + + strncpy( pDest, pSrc, maxLen ); + if ( maxLen > 0 ) + { + pDest[maxLen-1] = 0; + } +} + +// warning C6053: Call to 'wcsncpy' might not zero-terminate string 'pDest' +// warning C6059: Incorrect length parameter in call to 'strncat'. Pass the number of remaining characters, not the buffer size of 'argument 1' +// warning C6386: Buffer overrun: accessing 'argument 1', the writable size is 'destBufferSize' bytes, but '1000' bytes might be written +// These warnings were investigated through code inspection and writing of tests and they are +// believed to all be spurious. +#ifdef _PREFAST_ +#pragma warning( push ) +#pragma warning( disable : 6053 6059 6386 ) +#endif + +void V_wcsncpy( wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes ) +{ + Assert( maxLenInBytes >= sizeof( *pDest ) ); + AssertValidWritePtr( pDest, maxLenInBytes ); + AssertValidReadPtr( pSrc ); + + int maxLen = maxLenInBytes / sizeof(wchar_t); + + wcsncpy( pDest, pSrc, maxLen ); + if( maxLen ) + { + pDest[maxLen-1] = 0; + } +} + + + +int V_snwprintf( wchar_t *pDest, int maxLen, const wchar_t *pFormat, ... ) +{ + Assert( maxLen > 0 ); + AssertValidWritePtr( pDest, maxLen ); + AssertValidReadPtr( pFormat ); + + va_list marker; + + va_start( marker, pFormat ); +#ifdef _WIN32 + int len = _vsnwprintf( pDest, maxLen, pFormat, marker ); +#elif POSIX + int len = vswprintf( pDest, maxLen, pFormat, marker ); +#else +#error "define vsnwprintf type." +#endif + va_end( marker ); + + // Len > maxLen represents an overflow on POSIX, < 0 is an overflow on windows + if( len < 0 || len >= maxLen ) + { + len = maxLen; + pDest[maxLen-1] = 0; + } + + return len; +} + + +int V_vsnwprintf( wchar_t *pDest, int maxLen, const wchar_t *pFormat, va_list params ) +{ + Assert( maxLen > 0 ); + +#ifdef _WIN32 + int len = _vsnwprintf( pDest, maxLen, pFormat, params ); +#elif POSIX + int len = vswprintf( pDest, maxLen, pFormat, params ); +#else +#error "define vsnwprintf type." +#endif + + // Len < 0 represents an overflow + // Len == maxLen represents exactly fitting with no NULL termination + // Len >= maxLen represents overflow on POSIX + if ( len < 0 || len >= maxLen ) + { + len = maxLen; + pDest[maxLen-1] = 0; + } + + return len; +} + + +int V_snprintf( char *pDest, int maxLen, char const *pFormat, ... ) +{ + Assert( maxLen > 0 ); + AssertValidWritePtr( pDest, maxLen ); + AssertValidStringPtr( pFormat ); + + va_list marker; + + va_start( marker, pFormat ); +#ifdef _WIN32 + int len = _vsnprintf( pDest, maxLen, pFormat, marker ); +#elif POSIX + int len = vsnprintf( pDest, maxLen, pFormat, marker ); +#else + #error "define vsnprintf type." +#endif + va_end( marker ); + + // Len > maxLen represents an overflow on POSIX, < 0 is an overflow on windows + if( len < 0 || len >= maxLen ) + { + len = maxLen; + pDest[maxLen-1] = 0; + } + + return len; +} + + +int V_vsnprintf( char *pDest, int maxLen, char const *pFormat, va_list params ) +{ + Assert( maxLen > 0 ); + AssertValidWritePtr( pDest, maxLen ); + AssertValidStringPtr( pFormat ); + + int len = _vsnprintf( pDest, maxLen, pFormat, params ); + + // Len > maxLen represents an overflow on POSIX, < 0 is an overflow on windows + if( len < 0 || len >= maxLen ) + { + len = maxLen; + pDest[maxLen-1] = 0; + } + + return len; +} + + +int V_vsnprintfRet( char *pDest, int maxLen, const char *pFormat, va_list params, bool *pbTruncated ) +{ + Assert( maxLen > 0 ); + AssertValidWritePtr( pDest, maxLen ); + AssertValidStringPtr( pFormat ); + + int len = _vsnprintf( pDest, maxLen, pFormat, params ); + + if ( pbTruncated ) + { + *pbTruncated = ( len < 0 || len >= maxLen ); + } + + if ( len < 0 || len >= maxLen ) + { + len = maxLen; + pDest[maxLen-1] = 0; + } + + return len; +} + + + +//----------------------------------------------------------------------------- +// Purpose: If COPY_ALL_CHARACTERS == max_chars_to_copy then we try to add the whole pSrc to the end of pDest, otherwise +// we copy only as many characters as are specified in max_chars_to_copy (or the # of characters in pSrc if thats's less). +// Input : *pDest - destination buffer +// *pSrc - string to append +// destBufferSize - sizeof the buffer pointed to by pDest +// max_chars_to_copy - COPY_ALL_CHARACTERS in pSrc or max # to copy +// Output : char * the copied buffer +//----------------------------------------------------------------------------- +char *V_strncat(char *pDest, const char *pSrc, size_t destBufferSize, int max_chars_to_copy ) +{ + size_t charstocopy = (size_t)0; + + Assert( (ptrdiff_t)destBufferSize >= 0 ); + AssertValidStringPtr( pDest); + AssertValidStringPtr( pSrc ); + + size_t len = strlen(pDest); + size_t srclen = strlen( pSrc ); + if ( max_chars_to_copy <= COPY_ALL_CHARACTERS ) + { + charstocopy = srclen; + } + else + { + charstocopy = (size_t)vmin( max_chars_to_copy, (int)srclen ); + } + + if ( len + charstocopy >= destBufferSize ) + { + charstocopy = destBufferSize - len - 1; + } + + if ( (int)charstocopy <= 0 ) + { + return pDest; + } + + ANALYZE_SUPPRESS( 6059 ); // warning C6059: : Incorrect length parameter in call to 'strncat'. Pass the number of remaining characters, not the buffer size of 'argument 1' + char *pOut = strncat( pDest, pSrc, charstocopy ); + return pOut; +} + +wchar_t *V_wcsncat( INOUT_Z_CAP(cchDest) wchar_t *pDest, const wchar_t *pSrc, size_t cchDest, int max_chars_to_copy ) +{ + size_t charstocopy = (size_t)0; + + Assert( (ptrdiff_t)cchDest >= 0 ); + + size_t len = wcslen(pDest); + size_t srclen = wcslen( pSrc ); + if ( max_chars_to_copy <= COPY_ALL_CHARACTERS ) + { + charstocopy = srclen; + } + else + { + charstocopy = (size_t)vmin( max_chars_to_copy, (int)srclen ); + } + + if ( len + charstocopy >= cchDest ) + { + charstocopy = cchDest - len - 1; + } + + if ( (int)charstocopy <= 0 ) + { + return pDest; + } + + ANALYZE_SUPPRESS( 6059 ); // warning C6059: : Incorrect length parameter in call to 'strncat'. Pass the number of remaining characters, not the buffer size of 'argument 1' + wchar_t *pOut = wcsncat( pDest, pSrc, charstocopy ); + return pOut; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Converts value into x.xx MB/ x.xx KB, x.xx bytes format, including commas +// Input : value - +// 2 - +// false - +// Output : char +//----------------------------------------------------------------------------- +#define NUM_PRETIFYMEM_BUFFERS 8 +char *V_pretifymem( float value, int digitsafterdecimal /*= 2*/, bool usebinaryonek /*= false*/ ) +{ + static char output[ NUM_PRETIFYMEM_BUFFERS ][ 32 ]; + static int current; + + float onekb = usebinaryonek ? 1024.0f : 1000.0f; + float onemb = onekb * onekb; + + char *out = output[ current ]; + current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS -1 ); + + char suffix[ 8 ]; + + // First figure out which bin to use + if ( value > onemb ) + { + value /= onemb; + V_snprintf( suffix, sizeof( suffix ), " MB" ); + } + else if ( value > onekb ) + { + value /= onekb; + V_snprintf( suffix, sizeof( suffix ), " KB" ); + } + else + { + V_snprintf( suffix, sizeof( suffix ), " bytes" ); + } + + char val[ 32 ]; + + // Clamp to >= 0 + digitsafterdecimal = vmax( digitsafterdecimal, 0 ); + + // If it's basically integral, don't do any decimals + if ( FloatMakePositive( value - (int)value ) < 0.00001 ) + { + V_snprintf( val, sizeof( val ), "%i%s", (int)value, suffix ); + } + else + { + char fmt[ 32 ]; + + // Otherwise, create a format string for the decimals + V_snprintf( fmt, sizeof( fmt ), "%%.%if%s", digitsafterdecimal, suffix ); + V_snprintf( val, sizeof( val ), fmt, value ); + } + + // Copy from in to out + char *i = val; + char *o = out; + + // Search for decimal or if it was integral, find the space after the raw number + char *dot = strstr( i, "." ); + if ( !dot ) + { + dot = strstr( i, " " ); + } + + // Compute position of dot + int pos = dot - i; + // Don't put a comma if it's <= 3 long + pos -= 3; + + while ( *i ) + { + // If pos is still valid then insert a comma every third digit, except if we would be + // putting one in the first spot + if ( pos >= 0 && !( pos % 3 ) ) + { + // Never in first spot + if ( o != out ) + { + *o++ = ','; + } + } + + // Count down comma position + pos--; + + // Copy rest of data as normal + *o++ = *i++; + } + + // Terminate + *o = 0; + + return out; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a string representation of an integer with commas +// separating the 1000s (ie, 37,426,421) +// Input : value - Value to convert +// Output : Pointer to a static buffer containing the output +//----------------------------------------------------------------------------- +#define NUM_PRETIFYNUM_BUFFERS 8 // Must be a power of two +char *V_pretifynum( int64 inputValue ) +{ + static char output[ NUM_PRETIFYMEM_BUFFERS ][ 32 ]; + static int current; + + // Point to the output buffer. + char * const out = output[ current ]; + // Track the output buffer end for easy calculation of bytes-remaining. + const char* const outEnd = out + sizeof( output[ current ] ); + + // Point to the current output location in the output buffer. + char *pchRender = out; + // Move to the next output pointer. + current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS -1 ); + + *out = 0; + + // In order to handle the most-negative int64 we need to negate it + // into a uint64. + uint64 value; + // Render the leading minus sign, if necessary + if ( inputValue < 0 ) + { + V_snprintf( pchRender, 32, "-" ); + value = (uint64)-inputValue; + // Advance our output pointer. + pchRender += V_strlen( pchRender ); + } + else + { + value = (uint64)inputValue; + } + + // Now let's find out how big our number is. The largest number we can fit + // into 63 bits is about 9.2e18. So, there could potentially be six + // three-digit groups. + + // We need the initial value of 'divisor' to be big enough to divide our + // number down to 1-999 range. + uint64 divisor = 1; + // Loop more than six times to avoid integer overflow. + for ( int i = 0; i < 6; ++i ) + { + // If our divisor is already big enough then stop. + if ( value < divisor * 1000 ) + break; + + divisor *= 1000; + } + + // Print the leading batch of one to three digits. + int toPrint = (int)(value / divisor); + V_snprintf( pchRender, outEnd - pchRender, "%d", toPrint ); + + for (;;) + { + // Advance our output pointer. + pchRender += V_strlen( pchRender ); + // Adjust our value to be printed and our divisor. + value -= toPrint * divisor; + divisor /= 1000; + if ( !divisor ) + break; + + // The remaining blocks of digits always include a comma and three digits. + toPrint = (int)(value / divisor); + V_snprintf( pchRender, outEnd - pchRender, ",%03d", toPrint ); + } + + return out; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns true if a wide character is a "mean" space; that is, +// if it is technically a space or punctuation, but causes disruptive +// behavior when used in names, web pages, chat windows, etc. +// +// characters in this set are removed from the beginning and/or end of strings +// by Q_AggressiveStripPrecedingAndTrailingWhitespaceW() +//----------------------------------------------------------------------------- +bool Q_IsMeanSpaceW( wchar_t wch ) +{ + bool bIsMean = false; + + switch ( wch ) + { + case L'\x0082': // BREAK PERMITTED HERE + case L'\x0083': // NO BREAK PERMITTED HERE + case L'\x00A0': // NO-BREAK SPACE + case L'\x034F': // COMBINING GRAPHEME JOINER + case L'\x2000': // EN QUAD + case L'\x2001': // EM QUAD + case L'\x2002': // EN SPACE + case L'\x2003': // EM SPACE + case L'\x2004': // THICK SPACE + case L'\x2005': // MID SPACE + case L'\x2006': // SIX SPACE + case L'\x2007': // figure space + case L'\x2008': // PUNCTUATION SPACE + case L'\x2009': // THIN SPACE + case L'\x200A': // HAIR SPACE + case L'\x200B': // ZERO-WIDTH SPACE + case L'\x200C': // ZERO-WIDTH NON-JOINER + case L'\x200D': // ZERO WIDTH JOINER + case L'\x200E': // LEFT-TO-RIGHT MARK + case L'\x2028': // LINE SEPARATOR + case L'\x2029': // PARAGRAPH SEPARATOR + case L'\x202F': // NARROW NO-BREAK SPACE + case L'\x2060': // word joiner + case L'\xFEFF': // ZERO-WIDTH NO BREAK SPACE + case L'\xFFFC': // OBJECT REPLACEMENT CHARACTER + bIsMean = true; + break; + } + + return bIsMean; +} + + +//----------------------------------------------------------------------------- +// Purpose: strips trailing whitespace; returns pointer inside string just past +// any leading whitespace. +// +// bAggresive = true causes this function to also check for "mean" spaces, +// which we don't want in persona names or chat strings as they're disruptive +// to the user experience. +//----------------------------------------------------------------------------- +static wchar_t *StripWhitespaceWorker( int cchLength, wchar_t *pwch, bool *pbStrippedWhitespace, bool bAggressive ) +{ + // walk backwards from the end of the string, killing any whitespace + *pbStrippedWhitespace = false; + + wchar_t *pwchEnd = pwch + cchLength; + while ( --pwchEnd >= pwch ) + { + if ( !iswspace( *pwchEnd ) && ( !bAggressive || !Q_IsMeanSpaceW( *pwchEnd ) ) ) + break; + + *pwchEnd = 0; + *pbStrippedWhitespace = true; + } + + // walk forward in the string + while ( pwch < pwchEnd ) + { + if ( !iswspace( *pwch ) ) + break; + + *pbStrippedWhitespace = true; + pwch++; + } + + return pwch; +} + +//----------------------------------------------------------------------------- +// Purpose: Strips all evil characters (ie. zero-width no-break space) +// from a string. +//----------------------------------------------------------------------------- +bool Q_RemoveAllEvilCharacters( char *pch ) +{ + // convert to unicode + int cch = Q_strlen( pch ); + int cubDest = (cch + 1 ) * sizeof( wchar_t ); + wchar_t *pwch = (wchar_t *)stackalloc( cubDest ); + int cwch = Q_UTF8ToUnicode( pch, pwch, cubDest ) / sizeof( wchar_t ); + + bool bStrippedWhitespace = false; + + // Walk through and skip over evil characters + int nWalk = 0; + for( int i=0; i= sizeof( *pUnicode ) ); + AssertValidWritePtr(pUnicode); + AssertValidReadPtr(pUCS2); + + pUnicode[0] = 0; +#ifdef _WIN32 + int cchResult = V_wcslen( pUCS2 ); + V_memcpy( pUnicode, pUCS2, cubDestSizeInBytes ); +#else + iconv_t conv_t = iconv_open( "UCS-4LE", "UCS-2LE" ); + int cchResult = -1; + size_t nLenUnicde = cubDestSizeInBytes; + size_t nMaxUTF8 = cubDestSizeInBytes; + char *pIn = (char *)pUCS2; + char *pOut = (char *)pUnicode; + if ( conv_t != (iconv_t)-1 ) + { + cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUTF8 ); + iconv_close( conv_t ); + if ( (int)cchResult < 0 ) + cchResult = 0; + else + cchResult = nMaxUTF8; + } +#endif + pUnicode[(cubDestSizeInBytes / sizeof(wchar_t)) - 1] = 0; + return cchResult; + +} + +#ifdef _PREFAST_ +#pragma warning( pop ) // Restore the /analyze warnings +#endif + + +//----------------------------------------------------------------------------- +// Purpose: Converts a wchar_t string into a UCS2 string -noop on windows +//----------------------------------------------------------------------------- +int _V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, char *pUCS2, int cubDestSizeInBytes ) +{ +#ifdef _WIN32 + // Figure out which buffer is smaller and convert from bytes to character + // counts. + int cchResult = vmin( (size_t)cubSrcInBytes/sizeof(wchar_t), cubDestSizeInBytes/sizeof(wchar_t) ); + wchar_t *pDest = (wchar_t*)pUCS2; + wcsncpy( pDest, pUnicode, cchResult ); + // Make sure we NULL-terminate. + pDest[ cchResult - 1 ] = 0; +#elif defined (POSIX) + iconv_t conv_t = iconv_open( "UCS-2LE", "UTF-32LE" ); + size_t cchResult = -1; + size_t nLenUnicde = cubSrcInBytes; + size_t nMaxUCS2 = cubDestSizeInBytes; + char *pIn = (char*)pUnicode; + char *pOut = pUCS2; + if ( conv_t != (iconv_t)-1 ) + { + cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUCS2 ); + iconv_close( conv_t ); + if ( (int)cchResult < 0 ) + cchResult = 0; + else + cchResult = cubSrcInBytes / sizeof( wchar_t ); + } +#else + #error Must be implemented for this platform +#endif + return cchResult; +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts a ucs-2 (windows wchar_t) string into a UTF8 (standard) string +//----------------------------------------------------------------------------- +int _V_UCS2ToUTF8( const ucs2 *pUCS2, char *pUTF8, int cubDestSizeInBytes ) +{ + AssertValidStringPtr(pUTF8, cubDestSizeInBytes); + AssertValidReadPtr(pUCS2); + + pUTF8[0] = 0; +#ifdef _WIN32 + // under win32 wchar_t == ucs2, sigh + int cchResult = WideCharToMultiByte( CP_UTF8, 0, pUCS2, -1, pUTF8, cubDestSizeInBytes, NULL, NULL ); +#elif defined(POSIX) + iconv_t conv_t = iconv_open( "UTF-8", "UCS-2LE" ); + size_t cchResult = -1; + + // pUCS2 will be null-terminated so use that to work out the input + // buffer size. Note that we shouldn't assume iconv will stop when it + // finds a zero, and nLenUnicde should be given in bytes, so we multiply + // it by sizeof( ucs2 ) at the end. + size_t nLenUnicde = 0; + while ( pUCS2[nLenUnicde] ) + { + ++nLenUnicde; + } + nLenUnicde *= sizeof( ucs2 ); + + // Calculate number of bytes we want iconv to write, leaving space + // for the null-terminator + size_t nMaxUTF8 = cubDestSizeInBytes - 1; + char *pIn = (char *)pUCS2; + char *pOut = (char *)pUTF8; + if ( conv_t != (iconv_t)-1 ) + { + const size_t nBytesToWrite = nMaxUTF8; + cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUTF8 ); + + // Calculate how many bytes were actually written and use that to + // null-terminate our output string. + const size_t nBytesWritten = nBytesToWrite - nMaxUTF8; + pUTF8[nBytesWritten] = 0; + + iconv_close( conv_t ); + if ( (int)cchResult < 0 ) + cchResult = 0; + else + cchResult = nMaxUTF8; + } +#endif + pUTF8[cubDestSizeInBytes - 1] = 0; + return cchResult; +} + + +//----------------------------------------------------------------------------- +// Purpose: Converts a UTF8 to ucs-2 (windows wchar_t) +//----------------------------------------------------------------------------- +int _V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, ucs2 *pUCS2, int cubDestSizeInBytes ) +{ + Assert( cubDestSizeInBytes >= sizeof(pUCS2[0]) ); + AssertValidStringPtr(pUTF8, cubDestSizeInBytes); + AssertValidReadPtr(pUCS2); + + pUCS2[0] = 0; +#ifdef _WIN32 + // under win32 wchar_t == ucs2, sigh + int cchResult = MultiByteToWideChar( CP_UTF8, 0, pUTF8, -1, pUCS2, cubDestSizeInBytes / sizeof(wchar_t) ); +#elif defined( _PS3 ) // bugbug JLB + int cchResult = 0; + Assert( 0 ); +#elif defined(POSIX) + iconv_t conv_t = iconv_open( "UCS-2LE", "UTF-8" ); + size_t cchResult = -1; + size_t nLenUnicde = cubSrcInBytes; + size_t nMaxUTF8 = cubDestSizeInBytes; + char *pIn = (char *)pUTF8; + char *pOut = (char *)pUCS2; + if ( conv_t != (iconv_t)-1 ) + { + cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUTF8 ); + iconv_close( conv_t ); + if ( (int)cchResult < 0 ) + cchResult = 0; + else + cchResult = cubSrcInBytes; + + } +#endif + pUCS2[ (cubDestSizeInBytes/sizeof(ucs2)) - 1] = 0; + return cchResult; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Returns the 4 bit nibble for a hex character +// Input : c - +// Output : unsigned char +//----------------------------------------------------------------------------- +unsigned char V_nibble( char c ) +{ + if ( ( c >= '0' ) && + ( c <= '9' ) ) + { + return (unsigned char)(c - '0'); + } + + if ( ( c >= 'A' ) && + ( c <= 'F' ) ) + { + return (unsigned char)(c - 'A' + 0x0a); + } + + if ( ( c >= 'a' ) && + ( c <= 'f' ) ) + { + return (unsigned char)(c - 'a' + 0x0a); + } + + return '0'; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *in - +// numchars - +// *out - +// maxoutputbytes - +//----------------------------------------------------------------------------- +void V_hextobinary( char const *in, int numchars, byte *out, int maxoutputbytes ) +{ + int len = V_strlen( in ); + numchars = vmin( len, numchars ); + // Make sure it's even + numchars = ( numchars ) & ~0x1; + + // Must be an even # of input characters (two chars per output byte) + Assert( numchars >= 2 ); + + memset( out, 0x00, maxoutputbytes ); + + byte *p; + int i; + + p = out; + for ( i = 0; + ( i < numchars ) && ( ( p - out ) < maxoutputbytes ); + i+=2, p++ ) + { + *p = ( V_nibble( in[i] ) << 4 ) | V_nibble( in[i+1] ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *in - +// inputbytes - +// *out - +// outsize - +//----------------------------------------------------------------------------- +void V_binarytohex( const byte *in, int inputbytes, char *out, int outsize ) +{ + Assert( outsize >= 1 ); + char doublet[10]; + int i; + + out[0]=0; + + for ( i = 0; i < inputbytes; i++ ) + { + unsigned char c = in[i]; + V_snprintf( doublet, sizeof( doublet ), "%02x", c ); + V_strncat( out, doublet, outsize, COPY_ALL_CHARACTERS ); + } +} + +// Even though \ on Posix (Linux&Mac) isn't techincally a path separator we are +// now counting it as one even Posix since so many times our filepaths aren't actual +// paths but rather text strings passed in from data files, treating \ as a pathseparator +// covers the full range of cases +bool PATHSEPARATOR( char c ) +{ + return c == '\\' || c == '/'; +} + + +//----------------------------------------------------------------------------- +// Purpose: Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator) +// Input : *in - +// *out - +// maxlen - +//----------------------------------------------------------------------------- +void V_FileBase( const char *in, char *out, int maxlen ) +{ + Assert( maxlen >= 1 ); + Assert( in ); + Assert( out ); + + if ( !in || !in[ 0 ] ) + { + *out = 0; + return; + } + + int len, start, end; + + len = V_strlen( in ); + + // scan backward for '.' + end = len - 1; + while ( end&& in[end] != '.' && !PATHSEPARATOR( in[end] ) ) + { + end--; + } + + if ( in[end] != '.' ) // no '.', copy to end + { + end = len-1; + } + else + { + end--; // Found ',', copy to left of '.' + } + + // Scan backward for '/' + start = len-1; + while ( start >= 0 && !PATHSEPARATOR( in[start] ) ) + { + start--; + } + + if ( start < 0 || !PATHSEPARATOR( in[start] ) ) + { + start = 0; + } + else + { + start++; + } + + // Length of new sting + len = end - start + 1; + + int maxcopy = vmin( len + 1, maxlen ); + + // Copy partial string + V_strncpy( out, &in[start], maxcopy ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *ppath - +//----------------------------------------------------------------------------- +void V_StripTrailingSlash( char *ppath ) +{ + Assert( ppath ); + + int len = V_strlen( ppath ); + if ( len > 0 ) + { + if ( PATHSEPARATOR( ppath[ len - 1 ] ) ) + { + ppath[ len - 1 ] = 0; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *in - +// *out - +// outSize - +//----------------------------------------------------------------------------- +void V_StripExtension( const char *in, char *out, int outSize ) +{ + // Find the last dot. If it's followed by a dot or a slash, then it's part of a + // directory specifier like ../../somedir/./blah. + + // scan backward for '.' + int end = V_strlen( in ) - 1; + while ( end > 0 && in[end] != '.' && !PATHSEPARATOR( in[end] ) ) + { + --end; + } + + if (end > 0 && !PATHSEPARATOR( in[end] ) && end < outSize) + { + int nChars = vmin( end, outSize-1 ); + if ( out != in ) + { + memcpy( out, in, nChars ); + } + out[nChars] = 0; + } + else + { + // nothing found + if ( out != in ) + { + V_strncpy( out, in, outSize ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *path - +// *extension - +// pathStringLength - +//----------------------------------------------------------------------------- +void V_DefaultExtension( char *path, const char *extension, int pathStringLength ) +{ + Assert( path ); + Assert( pathStringLength >= 1 ); + Assert( extension ); + Assert( extension[0] == '.' ); + + char *src; + + // if path doesn't have a .EXT, append extension + // (extension should include the .) + src = path + V_strlen(path) - 1; + + while ( !PATHSEPARATOR( *src ) && ( src > path ) ) + { + if (*src == '.') + { + // it has an extension + return; + } + src--; + } + + // Concatenate the desired extension + V_strncat( path, extension, pathStringLength, COPY_ALL_CHARACTERS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Force extension... +// Input : *path - +// *extension - +// pathStringLength - +//----------------------------------------------------------------------------- +void V_SetExtension( char *path, const char *extension, int pathStringLength ) +{ + V_StripExtension( path, path, pathStringLength ); + + // We either had an extension and stripped it, or didn't have an extension + // at all. Either way, we need to concatenate our extension now. + + // extension is not required to start with '.', so if it's not there, + // then append that first. + if ( extension[0] != '.' ) + { + V_strncat( path, ".", pathStringLength, COPY_ALL_CHARACTERS ); + } + + V_strncat( path, extension, pathStringLength, COPY_ALL_CHARACTERS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove final filename from string +// Input : *path - +// Output : void V_StripFilename +//----------------------------------------------------------------------------- +void V_StripFilename (char *path) +{ + int length; + + length = V_strlen( path )-1; + if ( length <= 0 ) + return; + + while ( length > 0 && + !PATHSEPARATOR( path[length] ) ) + { + length--; + } + + path[ length ] = 0; +} + +#ifdef _WIN32 +#define CORRECT_PATH_SEPARATOR '\\' +#define INCORRECT_PATH_SEPARATOR '/' +#elif POSIX +#define CORRECT_PATH_SEPARATOR '/' +#define INCORRECT_PATH_SEPARATOR '\\' +#endif + +//----------------------------------------------------------------------------- +// Purpose: Changes all '/' or '\' characters into separator +// Input : *pname - +// separator - +//----------------------------------------------------------------------------- +void V_FixSlashes( char *pname, char separator /* = CORRECT_PATH_SEPARATOR */ ) +{ + while ( *pname ) + { + if ( *pname == INCORRECT_PATH_SEPARATOR || *pname == CORRECT_PATH_SEPARATOR ) + { + *pname = separator; + } + pname++; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: This function fixes cases of filenames like materials\\blah.vmt or somepath\otherpath\\ and removes the extra double slash. +//----------------------------------------------------------------------------- +void V_FixDoubleSlashes( char *pStr ) +{ + int len = V_strlen( pStr ); + + for ( int i=1; i < len-1; i++ ) + { + if ( (pStr[i] == '/' || pStr[i] == '\\') && (pStr[i+1] == '/' || pStr[i+1] == '\\') ) + { + // This means there's a double slash somewhere past the start of the filename. That + // can happen in Hammer if they use a material in the root directory. You'll get a filename + // that looks like 'materials\\blah.vmt' + V_memmove( &pStr[i], &pStr[i+1], len - i ); + --len; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Strip off the last directory from dirName +// Input : *dirName - +// maxlen - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool V_StripLastDir( char *dirName, int maxlen ) +{ + if( dirName[0] == 0 || + !V_stricmp( dirName, "./" ) || + !V_stricmp( dirName, ".\\" ) ) + return false; + + int len = V_strlen( dirName ); + + Assert( len < maxlen ); + + // skip trailing slash + if ( PATHSEPARATOR( dirName[len-1] ) ) + { + len--; + } + + while ( len > 0 ) + { + if ( PATHSEPARATOR( dirName[len-1] ) ) + { + dirName[len] = 0; + V_FixSlashes( dirName, CORRECT_PATH_SEPARATOR ); + return true; + } + len--; + } + + // Allow it to return an empty string and true. This can happen if something like "tf2/" is passed in. + // The correct behavior is to strip off the last directory ("tf2") and return true. + if( len == 0 ) + { + V_snprintf( dirName, maxlen, ".%c", CORRECT_PATH_SEPARATOR ); + return true; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a pointer to the beginning of the unqualified file name +// (no path information) +// Input: in - file name (may be unqualified, relative or absolute path) +// Output: pointer to unqualified file name +//----------------------------------------------------------------------------- +const char * V_UnqualifiedFileName( const char * in ) +{ + // back up until the character after the first path separator we find, + // or the beginning of the string + const char * out = in + strlen( in ) - 1; + while ( ( out > in ) && ( !PATHSEPARATOR( *( out-1 ) ) ) ) + out--; + return out; +} + + +//----------------------------------------------------------------------------- +// Purpose: Composes a path and filename together, inserting a path separator +// if need be +// Input: path - path to use +// filename - filename to use +// dest - buffer to compose result in +// destSize - size of destination buffer +//----------------------------------------------------------------------------- +void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize ) +{ + V_strncpy( dest, path, destSize ); + V_FixSlashes( dest ); + V_AppendSlash( dest, destSize ); + V_strncat( dest, filename, destSize, COPY_ALL_CHARACTERS ); + V_FixSlashes( dest ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *path - +// *dest - +// destSize - +// Output : void V_ExtractFilePath +//----------------------------------------------------------------------------- +bool V_ExtractFilePath (const char *path, char *dest, int destSize ) +{ + Assert( destSize >= 1 ); + if ( destSize < 1 ) + { + return false; + } + + // Last char + int len = V_strlen(path); + const char *src = path + (len ? len-1 : 0); + + // back up until a \ or the start + while ( src != path && !PATHSEPARATOR( *(src-1) ) ) + { + src--; + } + + int copysize = vmin( src - path, destSize - 1 ); + memcpy( dest, path, copysize ); + dest[copysize] = 0; + + return copysize != 0 ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *path - +// *dest - +// destSize - +// Output : void V_ExtractFileExtension +//----------------------------------------------------------------------------- +void V_ExtractFileExtension( const char *path, char *dest, int destSize ) +{ + *dest = NULL; + const char * extension = V_GetFileExtension( path ); + if ( NULL != extension ) + V_strncpy( dest, extension, destSize ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a pointer to the file extension within a file name string +// Input: in - file name +// Output: pointer to beginning of extension (after the "."), or NULL +// if there is no extension +//----------------------------------------------------------------------------- +const char * V_GetFileExtension( const char * path ) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.' ) + src--; + + // check to see if the '.' is part of a pathname + if (src == path || PATHSEPARATOR( *src ) ) + { + return NULL; // no extension + } + + return src; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a pointer to the filename part of a path string +// Input: in - file name +// Output: pointer to beginning of filename (after the "/"). If there were no /, +// output is identical to input +//----------------------------------------------------------------------------- +const char * V_GetFileName( const char * path ) +{ + return V_UnqualifiedFileName( path ); +} + + +bool V_RemoveDotSlashes( char *pFilename, char separator, bool bRemoveDoubleSlashes /* = true */ ) +{ + char *pIn = pFilename; + char *pOut = pFilename; + bool bRetVal = true; + + bool bBoundary = true; + while ( *pIn ) + { + if ( bBoundary && pIn[0] == '.' && pIn[1] == '.' && ( PATHSEPARATOR( pIn[2] ) || !pIn[2] ) ) + { + // Get rid of /../ or trailing /.. by backing pOut up to previous separator + + // Eat the last separator (or repeated separators) we wrote out + while ( pOut != pFilename && pOut[-1] == separator ) + { + --pOut; + } + + while ( true ) + { + if ( pOut == pFilename ) + { + bRetVal = false; // backwards compat. return value, even though we continue handling + break; + } + --pOut; + if ( *pOut == separator ) + { + break; + } + } + + // Skip the '..' but not the slash, next loop iteration will handle separator + pIn += 2; + bBoundary = ( pOut == pFilename ); + } + else if ( bBoundary && pIn[0] == '.' && ( PATHSEPARATOR( pIn[1] ) || !pIn[1] ) ) + { + // Handle "./" by simply skipping this sequence. bBoundary is unchanged. + if ( PATHSEPARATOR( pIn[1] ) ) + { + pIn += 2; + } + else + { + // Special case: if trailing "." is preceded by separator, eg "path/.", + // then the final separator should also be stripped. bBoundary may then + // be in an incorrect state, but we are at the end of processing anyway + // so we don't really care (the processing loop is about to terminate). + if ( pOut != pFilename && pOut[-1] == separator ) + { + --pOut; + } + pIn += 1; + } + } + else if ( PATHSEPARATOR( pIn[0] ) ) + { + *pOut = separator; + pOut += 1 - (bBoundary & bRemoveDoubleSlashes & (pOut != pFilename)); + pIn += 1; + bBoundary = true; + } + else + { + if ( pOut != pIn ) + { + *pOut = *pIn; + } + pOut += 1; + pIn += 1; + bBoundary = false; + } + } + *pOut = 0; + + return bRetVal; +} + + +void V_AppendSlash( char *pStr, int strSize ) +{ + int len = V_strlen( pStr ); + if ( len > 0 && !PATHSEPARATOR(pStr[len-1]) ) + { + if ( len+1 >= strSize ) + Error( "V_AppendSlash: ran out of space on %s.", pStr ); + + pStr[len] = CORRECT_PATH_SEPARATOR; + pStr[len+1] = 0; + } +} + + +void V_MakeAbsolutePath( char *pOut, int outLen, const char *pPath, const char *pStartingDir ) +{ + if ( V_IsAbsolutePath( pPath ) ) + { + // pPath is not relative.. just copy it. + V_strncpy( pOut, pPath, outLen ); + } + else + { + // Make sure the starting directory is absolute.. + if ( pStartingDir && V_IsAbsolutePath( pStartingDir ) ) + { + V_strncpy( pOut, pStartingDir, outLen ); + } + else + { + if ( !_getcwd( pOut, outLen ) ) + Error( "V_MakeAbsolutePath: _getcwd failed." ); + + if ( pStartingDir ) + { + V_AppendSlash( pOut, outLen ); + V_strncat( pOut, pStartingDir, outLen, COPY_ALL_CHARACTERS ); + } + } + + // Concatenate the paths. + V_AppendSlash( pOut, outLen ); + V_strncat( pOut, pPath, outLen, COPY_ALL_CHARACTERS ); + } + + if ( !V_RemoveDotSlashes( pOut ) ) + Error( "V_MakeAbsolutePath: tried to \"..\" past the root." ); + + //V_FixSlashes( pOut ); - handled by V_RemoveDotSlashes +} + + +//----------------------------------------------------------------------------- +// Makes a relative path +//----------------------------------------------------------------------------- +bool V_MakeRelativePath( const char *pFullPath, const char *pDirectory, char *pRelativePath, int nBufLen ) +{ + pRelativePath[0] = 0; + + const char *pPath = pFullPath; + const char *pDir = pDirectory; + + // Strip out common parts of the path + const char *pLastCommonPath = NULL; + const char *pLastCommonDir = NULL; + while ( *pPath && ( FastToLower( *pPath ) == FastToLower( *pDir ) || + ( PATHSEPARATOR( *pPath ) && ( PATHSEPARATOR( *pDir ) || (*pDir == 0) ) ) ) ) + { + if ( PATHSEPARATOR( *pPath ) ) + { + pLastCommonPath = pPath + 1; + pLastCommonDir = pDir + 1; + } + if ( *pDir == 0 ) + { + --pLastCommonDir; + break; + } + ++pDir; ++pPath; + } + + // Nothing in common + if ( !pLastCommonPath ) + return false; + + // For each path separator remaining in the dir, need a ../ + int nOutLen = 0; + bool bLastCharWasSeparator = true; + for ( ; *pLastCommonDir; ++pLastCommonDir ) + { + if ( PATHSEPARATOR( *pLastCommonDir ) ) + { + pRelativePath[nOutLen++] = '.'; + pRelativePath[nOutLen++] = '.'; + pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR; + bLastCharWasSeparator = true; + } + else + { + bLastCharWasSeparator = false; + } + } + + // Deal with relative paths not specified with a trailing slash + if ( !bLastCharWasSeparator ) + { + pRelativePath[nOutLen++] = '.'; + pRelativePath[nOutLen++] = '.'; + pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR; + } + + // Copy the remaining part of the relative path over, fixing the path separators + for ( ; *pLastCommonPath; ++pLastCommonPath ) + { + if ( PATHSEPARATOR( *pLastCommonPath ) ) + { + pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR; + } + else + { + pRelativePath[nOutLen++] = *pLastCommonPath; + } + + // Check for overflow + if ( nOutLen == nBufLen - 1 ) + break; + } + + pRelativePath[nOutLen] = 0; + return true; +} + + +//----------------------------------------------------------------------------- +// small helper function shared by lots of modules +//----------------------------------------------------------------------------- +bool V_IsAbsolutePath( const char *pStr ) +{ + bool bIsAbsolute = ( pStr[0] && pStr[1] == ':' ) || pStr[0] == '/' || pStr[0] == '\\'; + if ( IsX360() && !bIsAbsolute ) + { + bIsAbsolute = ( V_stristr( pStr, ":" ) != NULL ); + } + return bIsAbsolute; +} + + +// Copies at most nCharsToCopy bytes from pIn into pOut. +// Returns false if it would have overflowed pOut's buffer. +static bool CopyToMaxChars( char *pOut, int outSize, const char *pIn, int nCharsToCopy ) +{ + if ( outSize == 0 ) + return false; + + int iOut = 0; + while ( *pIn && nCharsToCopy > 0 ) + { + if ( iOut == (outSize-1) ) + { + pOut[iOut] = 0; + return false; + } + pOut[iOut] = *pIn; + ++iOut; + ++pIn; + --nCharsToCopy; + } + + pOut[iOut] = 0; + return true; +} + + +//----------------------------------------------------------------------------- +// Fixes up a file name, removing dot slashes, fixing slashes, converting to lowercase, etc. +//----------------------------------------------------------------------------- +void V_FixupPathName( char *pOut, size_t nOutLen, const char *pPath ) +{ + V_strncpy( pOut, pPath, nOutLen ); + V_RemoveDotSlashes( pOut, CORRECT_PATH_SEPARATOR, true ); +#ifdef WIN32 + V_strlower( pOut ); +#endif +} + + +// Returns true if it completed successfully. +// If it would overflow pOut, it fills as much as it can and returns false. +bool V_StrSubst( + const char *pIn, + const char *pMatch, + const char *pReplaceWith, + char *pOut, + int outLen, + bool bCaseSensitive + ) +{ + int replaceFromLen = strlen( pMatch ); + int replaceToLen = strlen( pReplaceWith ); + + const char *pInStart = pIn; + char *pOutPos = pOut; + pOutPos[0] = 0; + + while ( 1 ) + { + int nRemainingOut = outLen - (pOutPos - pOut); + + const char *pTestPos = ( bCaseSensitive ? strstr( pInStart, pMatch ) : V_stristr( pInStart, pMatch ) ); + if ( pTestPos ) + { + // Found an occurence of pMatch. First, copy whatever leads up to the string. + int copyLen = pTestPos - pInStart; + if ( !CopyToMaxChars( pOutPos, nRemainingOut, pInStart, copyLen ) ) + return false; + + // Did we hit the end of the output string? + if ( copyLen > nRemainingOut-1 ) + return false; + + pOutPos += strlen( pOutPos ); + nRemainingOut = outLen - (int)(pOutPos - pOut); + + // Now add the replacement string. + if ( !CopyToMaxChars( pOutPos, nRemainingOut, pReplaceWith, replaceToLen ) ) + return false; + + pInStart += copyLen + replaceFromLen; + pOutPos += replaceToLen; + } + else + { + // We're at the end of pIn. Copy whatever remains and get out. + int copyLen = strlen( pInStart ); + V_strncpy( pOutPos, pInStart, nRemainingOut ); + return ( copyLen <= nRemainingOut-1 ); + } + } +} + + +char* AllocString( const char *pStr, int nMaxChars ) +{ + int allocLen; + if ( nMaxChars == -1 ) + allocLen = strlen( pStr ) + 1; + else + allocLen = vmin( (int)strlen(pStr), nMaxChars ) + 1; + + char *pOut = new char[allocLen]; + V_strncpy( pOut, pStr, allocLen ); + return pOut; +} + + +void V_SplitString2( const char *pString, const char **pSeparators, int nSeparators, CUtlVector &outStrings ) +{ + outStrings.Purge(); + const char *pCurPos = pString; + while ( 1 ) + { + int iFirstSeparator = -1; + const char *pFirstSeparator = 0; + for ( int i=0; i < nSeparators; i++ ) + { + const char *pTest = V_stristr( pCurPos, pSeparators[i] ); + if ( pTest && (!pFirstSeparator || pTest < pFirstSeparator) ) + { + iFirstSeparator = i; + pFirstSeparator = pTest; + } + } + + if ( pFirstSeparator ) + { + // Split on this separator and continue on. + int separatorLen = strlen( pSeparators[iFirstSeparator] ); + if ( pFirstSeparator > pCurPos ) + { + outStrings.AddToTail( AllocString( pCurPos, pFirstSeparator-pCurPos ) ); + } + + pCurPos = pFirstSeparator + separatorLen; + } + else + { + // Copy the rest of the string + if ( strlen( pCurPos ) ) + { + outStrings.AddToTail( AllocString( pCurPos, -1 ) ); + } + return; + } + } +} + + +void V_SplitString( const char *pString, const char *pSeparator, CUtlVector &outStrings ) +{ + V_SplitString2( pString, &pSeparator, 1, outStrings ); +} + + +bool V_GetCurrentDirectory( char *pOut, int maxLen ) +{ + return _getcwd( pOut, maxLen ) == pOut; +} + + +bool V_SetCurrentDirectory( const char *pDirName ) +{ + return _chdir( pDirName ) == 0; +} + + +// This function takes a slice out of pStr and stores it in pOut. +// It follows the Python slice convention: +// Negative numbers wrap around the string (-1 references the last character). +// Numbers are clamped to the end of the string. +void V_StrSlice( const char *pStr, int firstChar, int lastCharNonInclusive, char *pOut, int outSize ) +{ + if ( outSize == 0 ) + return; + + int length = strlen( pStr ); + + // Fixup the string indices. + if ( firstChar < 0 ) + { + firstChar = length - (-firstChar % length); + } + else if ( firstChar >= length ) + { + pOut[0] = 0; + return; + } + + if ( lastCharNonInclusive < 0 ) + { + lastCharNonInclusive = length - (-lastCharNonInclusive % length); + } + else if ( lastCharNonInclusive > length ) + { + lastCharNonInclusive %= length; + } + + if ( lastCharNonInclusive <= firstChar ) + { + pOut[0] = 0; + return; + } + + int copyLen = lastCharNonInclusive - firstChar; + if ( copyLen <= (outSize-1) ) + { + memcpy( pOut, &pStr[firstChar], copyLen ); + pOut[copyLen] = 0; + } + else + { + memcpy( pOut, &pStr[firstChar], outSize-1 ); + pOut[outSize-1] = 0; + } +} + + +void V_StrLeft( const char *pStr, int nChars, char *pOut, int outSize ) +{ + if ( nChars == 0 ) + { + if ( outSize != 0 ) + pOut[0] = 0; + + return; + } + + V_StrSlice( pStr, 0, nChars, pOut, outSize ); +} + + +void V_StrRight( const char *pStr, int nChars, char *pOut, int outSize ) +{ + int len = strlen( pStr ); + if ( nChars >= len ) + { + V_strncpy( pOut, pStr, outSize ); + } + else + { + V_StrSlice( pStr, -nChars, strlen( pStr ), pOut, outSize ); + } +} + +//----------------------------------------------------------------------------- +// Convert multibyte to wchar + back +//----------------------------------------------------------------------------- +void V_strtowcs( const char *pString, int nInSize, wchar_t *pWString, int nOutSizeInBytes ) +{ + Assert( nOutSizeInBytes >= sizeof(pWString[0]) ); +#ifdef _WIN32 + int nOutSizeInChars = nOutSizeInBytes / sizeof(pWString[0]); + int result = MultiByteToWideChar( CP_UTF8, 0, pString, nInSize, pWString, nOutSizeInChars ); + // If the string completely fails to fit then MultiByteToWideChar will return 0. + // If the string exactly fits but with no room for a null-terminator then MultiByteToWideChar + // will happily fill the buffer and omit the null-terminator, returning nOutSizeInChars. + // Either way we need to return an empty string rather than a bogus and possibly not + // null-terminated result. + if ( result <= 0 || result >= nOutSizeInChars ) + { + // If nInSize includes the null-terminator then a result of nOutSizeInChars is + // legal. We check this by seeing if the last character in the output buffer is + // a zero. + if ( result == nOutSizeInChars && pWString[ nOutSizeInChars - 1 ] == 0) + { + // We're okay! Do nothing. + } + else + { + // The string completely to fit. Null-terminate the buffer. + *pWString = L'\0'; + } + } + else + { + // We have successfully converted our string. Now we need to null-terminate it, because + // MultiByteToWideChar will only do that if nInSize includes the source null-terminator! + pWString[ result ] = 0; + } +#elif POSIX + if ( mbstowcs( pWString, pString, nOutSizeInBytes / sizeof(pWString[0]) ) <= 0 ) + { + *pWString = 0; + } +#endif +} + +void V_wcstostr( const wchar_t *pWString, int nInSize, char *pString, int nOutSizeInChars ) +{ +#ifdef _WIN32 + int result = WideCharToMultiByte( CP_UTF8, 0, pWString, nInSize, pString, nOutSizeInChars, NULL, NULL ); + // If the string completely fails to fit then MultiByteToWideChar will return 0. + // If the string exactly fits but with no room for a null-terminator then MultiByteToWideChar + // will happily fill the buffer and omit the null-terminator, returning nOutSizeInChars. + // Either way we need to return an empty string rather than a bogus and possibly not + // null-terminated result. + if ( result <= 0 || result >= nOutSizeInChars ) + { + // If nInSize includes the null-terminator then a result of nOutSizeInChars is + // legal. We check this by seeing if the last character in the output buffer is + // a zero. + if ( result == nOutSizeInChars && pWString[ nOutSizeInChars - 1 ] == 0) + { + // We're okay! Do nothing. + } + else + { + *pString = '\0'; + } + } + else + { + // We have successfully converted our string. Now we need to null-terminate it, because + // MultiByteToWideChar will only do that if nInSize includes the source null-terminator! + pString[ result ] = '\0'; + } +#elif POSIX + if ( wcstombs( pString, pWString, nOutSizeInChars ) <= 0 ) + { + *pString = '\0'; + } +#endif +} + + + +//-------------------------------------------------------------------------------- +// backslashification +//-------------------------------------------------------------------------------- + +static char s_BackSlashMap[]="\tt\nn\rr\"\"\\\\"; + +char *V_AddBackSlashesToSpecialChars( char const *pSrc ) +{ + // first, count how much space we are going to need + int nSpaceNeeded = 0; + for( char const *pScan = pSrc; *pScan; pScan++ ) + { + nSpaceNeeded++; + for(char const *pCharSet=s_BackSlashMap; *pCharSet; pCharSet += 2 ) + { + if ( *pCharSet == *pScan ) + nSpaceNeeded++; // we need to store a bakslash + } + } + char *pRet = new char[ nSpaceNeeded + 1 ]; // +1 for null + char *pOut = pRet; + + for( char const *pScan = pSrc; *pScan; pScan++ ) + { + bool bIsSpecial = false; + for(char const *pCharSet=s_BackSlashMap; *pCharSet; pCharSet += 2 ) + { + if ( *pCharSet == *pScan ) + { + *( pOut++ ) = '\\'; + *( pOut++ ) = pCharSet[1]; + bIsSpecial = true; + break; + } + } + if (! bIsSpecial ) + { + *( pOut++ ) = *pScan; + } + } + *( pOut++ ) = 0; + return pRet; +} + +//----------------------------------------------------------------------------- +// Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15. +//----------------------------------------------------------------------------- +char cIntToHexDigit( int nValue ) +{ + Assert( nValue >= 0 && nValue <= 15 ); + return "0123456789ABCDEF"[ nValue & 15 ]; +} + +//----------------------------------------------------------------------------- +// Purpose: Helper for converting a hex char value to numeric, return -1 if the char +// is not a valid hex digit. +//----------------------------------------------------------------------------- +int iHexCharToInt( char cValue ) +{ + int32 iValue = cValue; + if ( (uint32)( iValue - '0' ) < 10 ) + return iValue - '0'; + + iValue |= 0x20; + if ( (uint32)( iValue - 'a' ) < 6 ) + return iValue - 'a' + 10; + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: Internal implementation of encode, works in the strict RFC manner, or +// with spaces turned to + like HTML form encoding. +//----------------------------------------------------------------------------- +void Q_URLEncodeInternal( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen, bool bUsePlusForSpace ) +{ + if ( nDestLen < 3*nSourceLen ) + { + pchDest[0] = '\0'; + AssertMsg( false, "Target buffer for Q_URLEncode needs to be 3 times larger than source to guarantee enough space\n" ); + return; + } + + int iDestPos = 0; + for ( int i=0; i < nSourceLen; ++i ) + { + // We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped. + // These are the characters allowed by both the original RFC 1738 and the latest RFC 3986. + // Current specs also allow '~', but that is forbidden under original RFC 1738. + if ( !( pchSource[i] >= 'a' && pchSource[i] <= 'z' ) && !( pchSource[i] >= 'A' && pchSource[i] <= 'Z' ) && !(pchSource[i] >= '0' && pchSource[i] <= '9' ) + && pchSource[i] != '-' && pchSource[i] != '_' && pchSource[i] != '.' + ) + { + if ( bUsePlusForSpace && pchSource[i] == ' ' ) + { + pchDest[iDestPos++] = '+'; + } + else + { + pchDest[iDestPos++] = '%'; + uint8 iValue = pchSource[i]; + if ( iValue == 0 ) + { + pchDest[iDestPos++] = '0'; + pchDest[iDestPos++] = '0'; + } + else + { + char cHexDigit1 = cIntToHexDigit( iValue % 16 ); + iValue /= 16; + char cHexDigit2 = cIntToHexDigit( iValue ); + pchDest[iDestPos++] = cHexDigit2; + pchDest[iDestPos++] = cHexDigit1; + } + } + } + else + { + pchDest[iDestPos++] = pchSource[i]; + } + } + + // Null terminate + pchDest[iDestPos++] = 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: Internal implementation of decode, works in the strict RFC manner, or +// with spaces turned to + like HTML form encoding. +// +// Returns the amount of space used in the output buffer. +//----------------------------------------------------------------------------- +size_t Q_URLDecodeInternal( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace ) +{ + if ( nDecodeDestLen < nEncodedSourceLen ) + { + AssertMsg( false, "Q_URLDecode needs a dest buffer at least as large as the source" ); + return 0; + } + + int iDestPos = 0; + for( int i=0; i < nEncodedSourceLen; ++i ) + { + if ( bUsePlusForSpace && pchEncodedSource[i] == '+' ) + { + pchDecodeDest[ iDestPos++ ] = ' '; + } + else if ( pchEncodedSource[i] == '%' ) + { + // Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that + + // First make sure we have 2 more chars + if ( i < nEncodedSourceLen - 2 ) + { + char cHexDigit1 = pchEncodedSource[i+1]; + char cHexDigit2 = pchEncodedSource[i+2]; + + // Turn the chars into a hex value, if they are not valid, then we'll + // just place the % and the following two chars direct into the string, + // even though this really shouldn't happen, who knows what bad clients + // may do with encoding. + bool bValid = false; + int iValue = iHexCharToInt( cHexDigit1 ); + if ( iValue != -1 ) + { + iValue *= 16; + int iValue2 = iHexCharToInt( cHexDigit2 ); + if ( iValue2 != -1 ) + { + iValue += iValue2; + pchDecodeDest[ iDestPos++ ] = iValue; + bValid = true; + } + } + + if ( !bValid ) + { + pchDecodeDest[ iDestPos++ ] = '%'; + pchDecodeDest[ iDestPos++ ] = cHexDigit1; + pchDecodeDest[ iDestPos++ ] = cHexDigit2; + } + } + + // Skip ahead + i += 2; + } + else + { + pchDecodeDest[ iDestPos++ ] = pchEncodedSource[i]; + } + } + + // We may not have extra room to NULL terminate, since this can be used on raw data, but if we do + // go ahead and do it as this can avoid bugs. + if ( iDestPos < nDecodeDestLen ) + { + pchDecodeDest[iDestPos] = 0; + } + + return (size_t)iDestPos; +} + +//----------------------------------------------------------------------------- +// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. +// This version of the call isn't a strict RFC implementation, but uses + for space as is +// the standard in HTML form encoding, despite it not being part of the RFC. +// +// Dest buffer should be at least as large as source buffer to guarantee room for decode. +//----------------------------------------------------------------------------- +void Q_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen ) +{ + return Q_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, true ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. +// This version of the call isn't a strict RFC implementation, but uses + for space as is +// the standard in HTML form encoding, despite it not being part of the RFC. +// +// Dest buffer should be at least as large as source buffer to guarantee room for decode. +// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed. +//----------------------------------------------------------------------------- +size_t Q_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen ) +{ + return Q_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. +// This version will not encode space as + (which HTML form encoding uses despite not being part of the RFC) +// +// Dest buffer should be at least as large as source buffer to guarantee room for decode. +//----------------------------------------------------------------------------- +void Q_URLEncodeRaw( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen ) +{ + return Q_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, false ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. +// This version will not recognize + as a space (which HTML form encoding uses despite not being part of the RFC) +// +// Dest buffer should be at least as large as source buffer to guarantee room for decode. +// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed. +//----------------------------------------------------------------------------- +size_t Q_URLDecodeRaw( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen ) +{ + return Q_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, false ); +} + +#if defined( LINUX ) || defined( _PS3 ) +extern "C" void qsort_s( void *base, size_t num, size_t width, int (*compare )(void *, const void *, const void *), void * context ); +#endif + +void V_qsort_s( void *base, size_t num, size_t width, int ( __cdecl *compare )(void *, const void *, const void *), void * context ) +{ +#if defined OSX + // the arguments are swapped 'round on the mac - awesome, huh? + return qsort_r( base, num, width, context, compare ); +#else + return qsort_s( base, num, width, compare, context ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: format the time and/or date with the user's current locale +// If timeVal is 0, gets the current time +// +// This is generally for use with chatroom dialogs, etc. which need to be +// able to say "Last message received: %date% at %time%" +// +// Note that this uses time_t because RTime32 is not hooked-up on the client +//----------------------------------------------------------------------------- +bool BGetLocalFormattedDateAndTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime ) +{ + if ( 0 == timeVal || timeVal < 0 ) + { + // get the current time + time( &timeVal ); + } + + if ( timeVal ) + { + // Convert it to our local time + struct tm tmStruct; + struct tm tmToDisplay = *( Plat_localtime( ( const time_t* )&timeVal, &tmStruct ) ); +#ifdef POSIX + if ( pchDate != NULL ) + { + pchDate[ 0 ] = 0; + if ( 0 == strftime( pchDate, cubDate, "%A %b %d", &tmToDisplay ) ) + return false; + } + + if ( pchTime != NULL ) + { + pchTime[ 0 ] = 0; + if ( 0 == strftime( pchTime, cubTime - 6, "%I:%M ", &tmToDisplay ) ) + return false; + + // append am/pm in lower case (since strftime doesn't have a lowercase formatting option) + if (tmToDisplay.tm_hour >= 12) + { + Q_strcat( pchTime, "p.m.", cubTime ); + } + else + { + Q_strcat( pchTime, "a.m.", cubTime ); + } + } +#else // WINDOWS + // convert time_t to a SYSTEMTIME + SYSTEMTIME st; + st.wHour = tmToDisplay.tm_hour; + st.wMinute = tmToDisplay.tm_min; + st.wSecond = tmToDisplay.tm_sec; + st.wDay = tmToDisplay.tm_mday; + st.wMonth = tmToDisplay.tm_mon + 1; + st.wYear = tmToDisplay.tm_year + 1900; + st.wDayOfWeek = tmToDisplay.tm_wday; + st.wMilliseconds = 0; + + WCHAR rgwch[ MAX_PATH ]; + + if ( pchDate != NULL ) + { + pchDate[ 0 ] = 0; + if ( !GetDateFormatW( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, rgwch, MAX_PATH ) ) + return false; + Q_strncpy( pchDate, CStrAutoEncode( rgwch ).ToString(), cubDate ); + } + + if ( pchTime != NULL ) + { + pchTime[ 0 ] = 0; + if ( !GetTimeFormatW( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, rgwch, MAX_PATH ) ) + return false; + Q_strncpy( pchTime, CStrAutoEncode( rgwch ).ToString(), cubTime ); + } +#endif + return true; + } + + return false; +} + + +// And a couple of helpers so people don't have to remember the order of the parameters in the above function +bool BGetLocalFormattedDate( time_t timeVal, char *pchDate, int cubDate ) +{ + return BGetLocalFormattedDateAndTime( timeVal, pchDate, cubDate, NULL, 0 ); +} +bool BGetLocalFormattedTime( time_t timeVal, char *pchTime, int cubTime ) +{ + return BGetLocalFormattedDateAndTime( timeVal, NULL, 0, pchTime, cubTime ); +} diff --git a/tier1/strtools_unicode.cpp b/tier1/strtools_unicode.cpp new file mode 100644 index 0000000..77685ec --- /dev/null +++ b/tier1/strtools_unicode.cpp @@ -0,0 +1,572 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include +#include "tier0/dbg.h" +#include "tier1/strtools.h" + +// This code was copied from steam +#define DbgAssert Assert + +//----------------------------------------------------------------------------- +// Purpose: determine if a uchar32 represents a valid Unicode code point +//----------------------------------------------------------------------------- +bool Q_IsValidUChar32( uchar32 uVal ) +{ + // Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves, + // values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range + return ( uVal < 0x110000u ) && ( (uVal - 0x00D800u) > 0x7FFu ) && ( (uVal & 0xFFFFu) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu ); +} + +//----------------------------------------------------------------------------- +// Purpose: return number of UTF-8 bytes required to encode a Unicode code point +//----------------------------------------------------------------------------- +int Q_UChar32ToUTF8Len( uchar32 uVal ) +{ + DbgAssert( Q_IsValidUChar32( uVal ) ); + if ( uVal <= 0x7F ) + return 1; + if ( uVal <= 0x7FF ) + return 2; + if ( uVal <= 0xFFFF ) + return 3; + return 4; +} + + +//----------------------------------------------------------------------------- +// Purpose: return number of UTF-16 elements required to encode a Unicode code point +//----------------------------------------------------------------------------- +int Q_UChar32ToUTF16Len( uchar32 uVal ) +{ + DbgAssert( Q_IsValidUChar32( uVal ) ); + if ( uVal <= 0xFFFF ) + return 1; + return 2; +} + + +//----------------------------------------------------------------------------- +// Purpose: encode Unicode code point as UTF-8, returns number of bytes written +//----------------------------------------------------------------------------- +int Q_UChar32ToUTF8( uchar32 uVal, char *pUTF8Out ) +{ + DbgAssert( Q_IsValidUChar32( uVal ) ); + if ( uVal <= 0x7F ) + { + pUTF8Out[0] = (unsigned char) uVal; + return 1; + } + if ( uVal <= 0x7FF ) + { + pUTF8Out[0] = (unsigned char)(uVal >> 6) | 0xC0; + pUTF8Out[1] = (unsigned char)(uVal & 0x3F) | 0x80; + return 2; + } + if ( uVal <= 0xFFFF ) + { + pUTF8Out[0] = (unsigned char)(uVal >> 12) | 0xE0; + pUTF8Out[1] = (unsigned char)((uVal >> 6) & 0x3F) | 0x80; + pUTF8Out[2] = (unsigned char)(uVal & 0x3F) | 0x80; + return 3; + } + pUTF8Out[0] = (unsigned char)((uVal >> 18) & 0x07) | 0xF0; + pUTF8Out[1] = (unsigned char)((uVal >> 12) & 0x3F) | 0x80; + pUTF8Out[2] = (unsigned char)((uVal >> 6) & 0x3F) | 0x80; + pUTF8Out[3] = (unsigned char)(uVal & 0x3F) | 0x80; + return 4; +} + +//----------------------------------------------------------------------------- +// Purpose: encode Unicode code point as UTF-16, returns number of elements written +//----------------------------------------------------------------------------- +int Q_UChar32ToUTF16( uchar32 uVal, uchar16 *pUTF16Out ) +{ + DbgAssert( Q_IsValidUChar32( uVal ) ); + if ( uVal <= 0xFFFF ) + { + pUTF16Out[0] = (uchar16) uVal; + return 1; + } + uVal -= 0x010000; + pUTF16Out[0] = (uchar16)(uVal >> 10) | 0xD800; + pUTF16Out[1] = (uchar16)(uVal & 0x3FF) | 0xDC00; + return 2; +} + + +// Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences +// as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence. +int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut ) +{ + const uint8 *pUTF8 = (const uint8 *)pUTF8_; + + int nBytes = 1; + uint32 uValue = pUTF8[0]; + uint32 uMinValue = 0; + + // 0....... single byte + if ( uValue < 0x80 ) + goto decodeFinishedNoCheck; + + // Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...) + if ( (uValue - 0xC0u) > 0x37u || ( pUTF8[1] & 0xC0 ) != 0x80 ) + goto decodeError; + + uValue = (uValue << 6) - (0xC0 << 6) + pUTF8[1] - 0x80; + nBytes = 2; + uMinValue = 0x80; + + // 110..... two-byte lead byte + if ( !( uValue & (0x20 << 6) ) ) + goto decodeFinished; + + // Expecting at least a three-byte sequence + if ( ( pUTF8[2] & 0xC0 ) != 0x80 ) + goto decodeError; + + uValue = (uValue << 6) - (0x20 << 12) + pUTF8[2] - 0x80; + nBytes = 3; + uMinValue = 0x800; + + // 1110.... three-byte lead byte + if ( !( uValue & (0x10 << 12) ) ) + goto decodeFinishedMaybeCESU8; + + // Expecting a four-byte sequence, longest permissible in UTF-8 + if ( ( pUTF8[3] & 0xC0 ) != 0x80 ) + goto decodeError; + + uValue = (uValue << 6) - (0x10 << 18) + pUTF8[3] - 0x80; + nBytes = 4; + uMinValue = 0x10000; + + // 11110... four-byte lead byte. fall through to finished. + +decodeFinished: + if ( uValue >= uMinValue && Q_IsValidUChar32( uValue ) ) + { +decodeFinishedNoCheck: + uValueOut = uValue; + bErrorOut = false; + return nBytes; + } +decodeError: + uValueOut = '?'; + bErrorOut = true; + return nBytes; + +decodeFinishedMaybeCESU8: + // Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards? + // That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all. + if ( ( uValue - 0xD800u ) < 0x400u && pUTF8[3] == 0xED && (uint8)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 ) + { + uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (uint8)( pUTF8[4] - 0xB0 ) << 6 ) + pUTF8[5] - 0x80; + nBytes = 6; + uMinValue = 0x10000; + } + goto decodeFinished; +} + +// Decode one character from a UTF-16 encoded string. +int Q_UTF16ToUChar32( const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut ) +{ + if ( Q_IsValidUChar32( pUTF16[0] ) ) + { + uValueOut = pUTF16[0]; + bErrorOut = false; + return 1; + } + else if ( (pUTF16[0] - 0xD800u) < 0x400u && (pUTF16[1] - 0xDC00u) < 0x400u ) + { + // Valid surrogate pair, but maybe not encoding a valid Unicode code point... + uchar32 uVal = 0x010000 + ((pUTF16[0] - 0xD800u) << 10) + (pUTF16[1] - 0xDC00); + if ( Q_IsValidUChar32( uVal ) ) + { + uValueOut = uVal; + bErrorOut = false; + return 2; + } + else + { + uValueOut = '?'; + bErrorOut = true; + return 2; + } + } + else + { + uValueOut = '?'; + bErrorOut = true; + return 1; + } +} + +namespace // internal use only +{ + // Identity transformations and validity tests for use with Q_UnicodeConvertT + int Q_UTF32ToUChar32( const uchar32 *pUTF32, uchar32 &uVal, bool &bErr ) + { + bErr = !Q_IsValidUChar32( *pUTF32 ); + uVal = bErr ? '?' : *pUTF32; + return 1; + } + + int Q_UChar32ToUTF32Len( uchar32 uVal ) + { + return 1; + } + + int Q_UChar32ToUTF32( uchar32 uVal, uchar32 *pUTF32 ) + { + *pUTF32 = uVal; + return 1; + } + + // A generic Unicode processing loop: decode one character from input to uchar32, handle errors, encode uchar32 to output + template < typename SrcType, typename DstType, bool bStopAtNull, int (&DecodeSrc)( const SrcType*, uchar32&, bool& ), int (&EncodeDstLen)( uchar32 ), int (&EncodeDst)( uchar32, DstType* ) > + int Q_UnicodeConvertT( const SrcType *pIn, int nInChars, DstType *pOut, int nOutBytes, EStringConvertErrorPolicy ePolicy ) + { + if ( !pIn ) + { + // For now, assert and return 0. Once these are cleaned out a bit + // we should remove this return and just leave in the assert... + AssertMsg( pIn, "We shouldn't be passing in NULL!" ); + return 0; + } + + int nOut = 0; + + if ( !pOut ) + { + while ( bStopAtNull ? ( *pIn ) : ( nInChars-- > 0 ) ) + { + uchar32 uVal; + // Initialize in order to avoid /analyze warnings. + bool bErr = false; + pIn += DecodeSrc( pIn, uVal, bErr ); + nOut += EncodeDstLen( uVal ); + if ( bErr ) + { +#ifdef _DEBUG + AssertMsg( !(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence" ); +#endif + if ( ePolicy & _STRINGCONVERTFLAG_SKIP ) + { + nOut -= EncodeDstLen( uVal ); + } + else if ( ePolicy & _STRINGCONVERTFLAG_FAIL ) + { + pOut[0] = 0; + return 0; + } + } + } + } + else + { + int nOutElems = nOutBytes / sizeof( DstType ); + if ( nOutElems <= 0 ) + return 0; + + int nMaxOut = nOutElems - 1; + while ( bStopAtNull ? ( *pIn ) : ( nInChars-- > 0 ) ) + { + uchar32 uVal; + // Initialize in order to avoid /analyze warnings. + bool bErr = false; + pIn += DecodeSrc( pIn, uVal, bErr ); + if ( nOut + EncodeDstLen( uVal ) > nMaxOut ) + break; + nOut += EncodeDst( uVal, pOut + nOut ); + if ( bErr ) + { +#ifdef _DEBUG + AssertMsg( !(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence" ); +#endif + if ( ePolicy & _STRINGCONVERTFLAG_SKIP ) + { + nOut -= EncodeDstLen( uVal ); + } + else if ( ePolicy & _STRINGCONVERTFLAG_FAIL ) + { + pOut[0] = 0; + return 0; + } + } + } + pOut[nOut] = 0; + } + + return (nOut + 1) * sizeof( DstType ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if UTF-8 string contains invalid sequences. +//----------------------------------------------------------------------------- +bool Q_UnicodeValidate( const char *pUTF8 ) +{ + bool bError = false; + while ( *pUTF8 ) + { + uchar32 uVal; + // Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences. + // However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error. + int nCharSize = Q_UTF8ToUChar32( pUTF8, uVal, bError ); + if ( bError || nCharSize == 6 ) + return false; + pUTF8 += nCharSize; + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if UTF-16 string contains invalid sequences. +//----------------------------------------------------------------------------- +bool Q_UnicodeValidate( const uchar16 *pUTF16 ) +{ + bool bError = false; + while ( *pUTF16 ) + { + uchar32 uVal; + pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError ); + if ( bError ) + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if UTF-32 string contains invalid sequences. +//----------------------------------------------------------------------------- +bool Q_UnicodeValidate( const uchar32 *pUTF32 ) +{ + while ( *pUTF32 ) + { + if ( !Q_IsValidUChar32( *pUTF32++ ) ) + return false; + ++pUTF32; + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-8 string +//----------------------------------------------------------------------------- +int Q_UnicodeLength( const char *pUTF8 ) +{ + int nChars = 0; + while ( *pUTF8 ) + { + bool bError; + uchar32 uVal; + pUTF8 += Q_UTF8ToUChar32( pUTF8, uVal, bError ); + ++nChars; + } + return nChars; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-16 string +//----------------------------------------------------------------------------- +int Q_UnicodeLength( const uchar16 *pUTF16 ) +{ + int nChars = 0; + while ( *pUTF16 ) + { + bool bError; + uchar32 uVal; + pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError ); + ++nChars; + } + return nChars; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-32 string +//----------------------------------------------------------------------------- +int Q_UnicodeLength( const uchar32 *pUTF32 ) +{ + int nChars = 0; + while ( *pUTF32++ ) + ++nChars; + return nChars; +} + +//----------------------------------------------------------------------------- +// Purpose: Advance a UTF-8 string pointer by a certain number of Unicode code points, stopping at end of string +//----------------------------------------------------------------------------- +char *Q_UnicodeAdvance( char *pUTF8, int nChars ) +{ + while ( nChars > 0 && *pUTF8 ) + { + uchar32 uVal; + bool bError; + pUTF8 += Q_UTF8ToUChar32( pUTF8, uVal, bError ); + --nChars; + } + return pUTF8; +} + +//----------------------------------------------------------------------------- +// Purpose: Advance a UTF-16 string pointer by a certain number of Unicode code points, stopping at end of string +//----------------------------------------------------------------------------- +uchar16 *Q_UnicodeAdvance( uchar16 *pUTF16, int nChars ) +{ + while ( nChars > 0 && *pUTF16 ) + { + uchar32 uVal; + bool bError; + pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError ); + --nChars; + } + return pUTF16; +} + +//----------------------------------------------------------------------------- +// Purpose: Advance a UTF-32 string pointer by a certain number of Unicode code points, stopping at end of string +//----------------------------------------------------------------------------- +uchar32 *Q_UnicodeAdvance( uchar32 *pUTF32, int nChars ) +{ + while ( nChars > 0 && *pUTF32 ) + { + ++pUTF32; + --nChars; + } + return pUTF32; +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF8ToUTF16( const char *pUTF8, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< char, uchar16, true, Q_UTF8ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF8, 0, pUTF16, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF8ToUTF32( const char *pUTF8, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< char, uchar32, true, Q_UTF8ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF8, 0, pUTF32, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF16ToUTF8( const uchar16 *pUTF16, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar16, char, true, Q_UTF16ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF16, 0, pUTF8, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF16ToUTF32( const uchar16 *pUTF16, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar16, uchar32, true, Q_UTF16ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF16, 0, pUTF32, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF32ToUTF8( const uchar32 *pUTF32, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar32, char, true, Q_UTF32ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF32, 0, pUTF8, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF32ToUTF16( const uchar32 *pUTF32, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar32, uchar16, true, Q_UTF32ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF32, 0, pUTF16, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF32ToUTF32( const uchar32 *pUTF32Source, uchar32 *pUTF32Dest, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar32, uchar32, true, Q_UTF32ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF32Source, 0, pUTF32Dest, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF8CharsToUTF16( const char *pUTF8, int nElements, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< char, uchar16, false, Q_UTF8ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF8, nElements, pUTF16, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF8CharsToUTF32( const char *pUTF8, int nElements, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< char, uchar32, false, Q_UTF8ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF8, nElements, pUTF32, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF16CharsToUTF8( const uchar16 *pUTF16, int nElements, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar16, char, false, Q_UTF16ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF16, nElements, pUTF8, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF16CharsToUTF32( const uchar16 *pUTF16, int nElements, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar16, uchar32, false, Q_UTF16ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF16, nElements, pUTF32, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF32CharsToUTF8( const uchar32 *pUTF32, int nElements, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar32, char, false, Q_UTF32ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF32, nElements, pUTF8, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL. +//----------------------------------------------------------------------------- +int Q_UTF32CharsToUTF16( const uchar32 *pUTF32, int nElements, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar32, uchar16, false, Q_UTF32ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF32, nElements, pUTF16, cubDestSizeInBytes, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Repair a UTF-8 string by removing or replacing invalid seqeuences. Returns non-zero on success. +//----------------------------------------------------------------------------- +int Q_UnicodeRepair( char *pUTF8, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< char, char, true, Q_UTF8ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF8, 0, pUTF8, INT_MAX, ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Repair a UTF-16 string by removing or replacing invalid seqeuences. Returns non-zero on success. +//----------------------------------------------------------------------------- +int Q_UnicodeRepair( uchar16 *pUTF16, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar16, uchar16, true, Q_UTF16ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF16, 0, pUTF16, INT_MAX/sizeof(uchar16), ePolicy ); +} + +//----------------------------------------------------------------------------- +// Purpose: Repair a UTF-32 string by removing or replacing invalid seqeuences. Returns non-zero on success. +//----------------------------------------------------------------------------- +int Q_UnicodeRepair( uchar32 *pUTF32, EStringConvertErrorPolicy ePolicy ) +{ + return Q_UnicodeConvertT< uchar32, uchar32, true, Q_UTF32ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF32, 0, pUTF32, INT_MAX/sizeof(uchar32), ePolicy ); +} + diff --git a/tier1/tier1.cpp b/tier1/tier1.cpp new file mode 100644 index 0000000..d683b87 --- /dev/null +++ b/tier1/tier1.cpp @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + +#include +#include "tier0/dbg.h" +#include "vstdlib/iprocessutils.h" +#include "icvar.h" + + +//----------------------------------------------------------------------------- +// These tier1 libraries must be set by any users of this library. +// They can be set by calling ConnectTier1Libraries or InitDefaultFileSystem. +// It is hoped that setting this, and using this library will be the common mechanism for +// allowing link libraries to access tier1 library interfaces +//----------------------------------------------------------------------------- +ICvar *cvar = 0; +ICvar *g_pCVar = 0; +IProcessUtils *g_pProcessUtils = 0; +static bool s_bConnected = false; + +// for utlsortvector.h +#ifndef _WIN32 + void *g_pUtlSortVectorQSortContext = NULL; +#endif + + +//----------------------------------------------------------------------------- +// Call this to connect to all tier 1 libraries. +// It's up to the caller to check the globals it cares about to see if ones are missing +//----------------------------------------------------------------------------- +void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount ) +{ + // Don't connect twice.. + if ( s_bConnected ) + return; + + s_bConnected = true; + + for ( int i = 0; i < nFactoryCount; ++i ) + { + if ( !g_pCVar ) + { + cvar = g_pCVar = ( ICvar * )pFactoryList[i]( CVAR_INTERFACE_VERSION, NULL ); + } + if ( !g_pProcessUtils ) + { + g_pProcessUtils = ( IProcessUtils * )pFactoryList[i]( PROCESS_UTILS_INTERFACE_VERSION, NULL ); + } + } +} + +void DisconnectTier1Libraries() +{ + if ( !s_bConnected ) + return; + + g_pCVar = cvar = 0; + g_pProcessUtils = NULL; + s_bConnected = false; +} diff --git a/tier1/tier1.vcxproj b/tier1/tier1.vcxproj new file mode 100644 index 0000000..38c9eba --- /dev/null +++ b/tier1/tier1.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {03D46084-5349-43F6-B233-9CFF191B0CE0} + tier1 + 10.0 + + + + StaticLibrary + true + v142 + MultiByte + + + StaticLibrary + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + StaticLibrary + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\lib\public + + + + Level3 + Disabled + true + + + true + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + ..\common;..\public;..\public\tier0;..\public\tier1 + AnySuitable + Speed + RAD_TELEMETRY_DISABLED;WIN64;_WIN64;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_ALLOW_RUNTIME_LIBRARY_MISMATCH;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_MSC_VER_MISMATCH;%(PreprocessorDefinitions);COMPILER_MSVC64;COMPILER_MSVC;_DLL_EXT=.dll;LIBNAME=tier1;BINK_VIDEO;AVI_VIDEO;WMV_VIDEO;DEV_BUILD;FRAME_POINTER_OMISSION_DISABLED;TIER1_STATIC_LIB;_EXTERNAL_DLL_EXT=.dll;VPCGAMECAPS=GMOD;PROJECTDIR=.\;SOURCE1=1;VPCGAME=gmod + + + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tier1/tier1.vcxproj.filters b/tier1/tier1.vcxproj.filters new file mode 100644 index 0000000..fdee9dd --- /dev/null +++ b/tier1/tier1.vcxproj.filters @@ -0,0 +1,164 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/tier1/tokenreader.cpp b/tier1/tokenreader.cpp new file mode 100644 index 0000000..39d0108 --- /dev/null +++ b/tier1/tokenreader.cpp @@ -0,0 +1,480 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include +#include +#include +#include "tokenreader.h" +#include "tier0/platform.h" +#include "tier1/strtools.h" +#include "tier0/dbg.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +TokenReader::TokenReader(void) +{ + m_szFilename[0] = '\0'; + m_nLine = 1; + m_nErrorCount = 0; + m_bStuffed = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszFilename - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool TokenReader::Open(const char *pszFilename) +{ + open(pszFilename, std::ios::in | std::ios::binary ); + Q_strncpy(m_szFilename, pszFilename, sizeof( m_szFilename ) ); + m_nLine = 1; + m_nErrorCount = 0; + m_bStuffed = false; + return(is_open() != 0); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void TokenReader::Close() +{ + close(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *error - +// Output : const char +//----------------------------------------------------------------------------- +const char *TokenReader::Error(char *error, ...) +{ + static char szErrorBuf[256]; + Q_snprintf(szErrorBuf, sizeof( szErrorBuf ), "File %s, line %d: ", m_szFilename, m_nLine); + Q_strncat(szErrorBuf, error, sizeof( szErrorBuf ), COPY_ALL_CHARACTERS ); + m_nErrorCount++; + return(szErrorBuf); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszStore - +// nSize - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +trtoken_t TokenReader::GetString(char *pszStore, int nSize) +{ + if (nSize <= 0) + { + return TOKENERROR; + } + + char szBuf[1024]; + + // + // Until we reach the end of this string or run out of room in + // the destination buffer... + // + while (true) + { + // + // Fetch the next batch of text from the file. + // + get(szBuf, sizeof(szBuf), '\"'); + if (eof()) + { + return TOKENEOF; + } + + if (fail()) + { + // Just means nothing was read (empty string probably "") + clear(); + } + + // + // Transfer the text to the destination buffer. + // + char *pszSrc = szBuf; + while ((*pszSrc != '\0') && (nSize > 1)) + { + if (*pszSrc == 0x0d) + { + // + // Newline encountered before closing quote -- unterminated string. + // + *pszStore = '\0'; + return TOKENSTRINGTOOLONG; + } + else if (*pszSrc != '\\') + { + *pszStore = *pszSrc; + pszSrc++; + } + else + { + // + // Backslash sequence - replace with the appropriate character. + // + pszSrc++; + + if (*pszSrc == 'n') + { + *pszStore = '\n'; + } + + pszSrc++; + } + + pszStore++; + nSize--; + } + + if (*pszSrc != '\0') + { + // + // Ran out of room in the destination buffer. Skip to the close-quote, + // terminate the string, and exit. + // + ignore(1024, '\"'); + *pszStore = '\0'; + return TOKENSTRINGTOOLONG; + } + + // + // Check for closing quote. + // + if (peek() == '\"') + { + // + // Eat the close quote and any whitespace. + // + get(); + + bool bCombineStrings = SkipWhiteSpace(); + + // + // Combine consecutive quoted strings if the combine strings character was + // encountered between the two strings. + // + if (bCombineStrings && (peek() == '\"')) + { + // + // Eat the open quote and keep parsing this string. + // + get(); + } + else + { + // + // Done with this string, terminate the string and exit. + // + *pszStore = '\0'; + return STRING; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the next token, allocating enough memory to store the token +// plus a terminating NULL. +// Input : pszStore - Pointer to a string that will be allocated. +// Output : Returns the type of token that was read, or TOKENERROR. +//----------------------------------------------------------------------------- +trtoken_t TokenReader::NextTokenDynamic(char **ppszStore) +{ + char szTempBuffer[8192]; + trtoken_t eType = NextToken(szTempBuffer, sizeof(szTempBuffer)); + + int len = Q_strlen(szTempBuffer) + 1; + *ppszStore = new char [len]; + Assert( *ppszStore ); + Q_strncpy(*ppszStore, szTempBuffer, len ); + + return(eType); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the next token. +// Input : pszStore - Pointer to a string that will receive the token. +// Output : Returns the type of token that was read, or TOKENERROR. +//----------------------------------------------------------------------------- +trtoken_t TokenReader::NextToken(char *pszStore, int nSize) +{ + char *pStart = pszStore; + + if (!is_open()) + { + return TOKENEOF; + } + + // + // If they stuffed a token, return that token. + // + if (m_bStuffed) + { + m_bStuffed = false; + Q_strncpy( pszStore, m_szStuffed, nSize ); + return m_eStuffed; + } + + SkipWhiteSpace(); + + if (eof()) + { + return TOKENEOF; + } + + if (fail()) + { + return TOKENEOF; + } + + char ch = get(); + + // + // Look for all the valid operators. + // + switch (ch) + { + case '@': + case ',': + case '!': + case '+': + case '&': + case '*': + case '$': + case '.': + case '=': + case ':': + case '[': + case ']': + case '(': + case ')': + case '{': + case '}': + case '\\': + { + pszStore[0] = ch; + pszStore[1] = 0; + return OPERATOR; + } + } + + // + // Look for the start of a quoted string. + // + if (ch == '\"') + { + return GetString(pszStore, nSize); + } + + // + // Integers consist of numbers with an optional leading minus sign. + // + if (isdigit(ch) || (ch == '-')) + { + do + { + if ( (pszStore - pStart + 1) < nSize ) + { + *pszStore = ch; + pszStore++; + } + + ch = get(); + if (ch == '-') + { + return TOKENERROR; + } + } while (isdigit(ch)); + + // + // No identifier characters are allowed contiguous with numbers. + // + if (isalpha(ch) || (ch == '_')) + { + return TOKENERROR; + } + + // + // Put back the non-numeric character for the next call. + // + putback(ch); + *pszStore = '\0'; + return INTEGER; + } + + // + // Identifiers consist of a consecutive string of alphanumeric + // characters and underscores. + // + while ( isalpha(ch) || isdigit(ch) || (ch == '_') ) + { + if ( (pszStore - pStart + 1) < nSize ) + { + *pszStore = ch; + pszStore++; + } + + ch = get(); + } + + // + // Put back the non-identifier character for the next call. + // + putback(ch); + *pszStore = '\0'; + return IDENT; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ttype - +// *pszToken - +//----------------------------------------------------------------------------- +void TokenReader::IgnoreTill(trtoken_t ttype, const char *pszToken) +{ + trtoken_t _ttype; + char szBuf[1024]; + + while(1) + { + _ttype = NextToken(szBuf, sizeof(szBuf)); + if(_ttype == TOKENEOF) + return; + if(_ttype == ttype) + { + if(IsToken(pszToken, szBuf)) + { + Stuff(ttype, pszToken); + return; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ttype - +// pszToken - +//----------------------------------------------------------------------------- +void TokenReader::Stuff(trtoken_t eType, const char *pszToken) +{ + m_eStuffed = eType; + Q_strncpy(m_szStuffed, pszToken, sizeof( m_szStuffed ) ); + m_bStuffed = true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ttype - +// pszToken - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool TokenReader::Expecting(trtoken_t ttype, const char *pszToken) +{ + char szBuf[1024]; + if (NextToken(szBuf, sizeof(szBuf)) != ttype || !IsToken(pszToken, szBuf)) + { + return false; + } + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pszStore - +// Output : +//----------------------------------------------------------------------------- +trtoken_t TokenReader::PeekTokenType(char *pszStore, int maxlen ) +{ + if (!m_bStuffed) + { + m_eStuffed = NextToken(m_szStuffed, sizeof(m_szStuffed)); + m_bStuffed = true; + } + + if (pszStore) + { + Q_strncpy(pszStore, m_szStuffed, maxlen ); + } + + return(m_eStuffed); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the next non-whitespace character from the file. +// Input : ch - Receives the character. +// Output : Returns true if the whitespace contained the combine strings +// character '\', which is used to merge consecutive quoted strings. +//----------------------------------------------------------------------------- +bool TokenReader::SkipWhiteSpace(void) +{ + bool bCombineStrings = false; + + while (true) + { + char ch = get(); + + if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == 0)) + { + continue; + } + + if (ch == '+') + { + bCombineStrings = true; + continue; + } + + if (ch == '\n') + { + m_nLine++; + continue; + } + + if (eof()) + { + return(bCombineStrings); + } + + // + // Check for the start of a comment. + // + if (ch == '/') + { + if (peek() == '/') + { + ignore(1024, '\n'); + m_nLine++; + } + } + else + { + // + // It is a worthy character. Put it back. + // + putback(ch); + return(bCombineStrings); + } + } +} + diff --git a/tier1/undiff.cpp b/tier1/undiff.cpp new file mode 100644 index 0000000..1173e80 --- /dev/null +++ b/tier1/undiff.cpp @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// UnDiff - Apply difference block +// +//=============================================================================// + +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier1/diff.h" +#include "mathlib/mathlib.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList, + int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize) +{ + uint8 const *copy_src=OldBlock; + uint8 const *end_of_diff_list=DiffList+DiffListSize; + uint8 const *obuf=Output; + while(DiffList32767) + copy_ofs|=0xffff0000; + // printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz); + + memcpy(Output,copy_src+copy_ofs,copy_sz); + Output+=copy_sz; + copy_src=copy_src+copy_ofs+copy_sz; + DiffList+=4; + } + else + { + if (op & 0x80) + { + int copy_sz=op & 0x7f; + int copy_ofs; + if (copy_sz==0) + { + copy_sz=DiffList[0]; + if (copy_sz==0) + { + // big raw copy + copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3]; + memcpy(Output,DiffList+4,copy_sz); + // printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz); + + DiffList+=copy_sz+4; + Output+=copy_sz; + } + else + { + copy_ofs=DiffList[1]+(DiffList[2]*256); + if (copy_ofs>32767) + copy_ofs|=0xffff0000; + // printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz); + + memcpy(Output,copy_src+copy_ofs,copy_sz); + Output+=copy_sz; + copy_src=copy_src+copy_ofs+copy_sz; + DiffList+=3; + } + } + else + { + copy_ofs=DiffList[0]; + if (copy_ofs>127) + copy_ofs|=0xffffff80; + // printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz); + + memcpy(Output,copy_src+copy_ofs,copy_sz); + Output+=copy_sz; + copy_src=copy_src+copy_ofs+copy_sz; + DiffList++; + } + } + else + { + // printf("raw copy %d to %x\n",op & 127,Output-obuf); + memcpy(Output,DiffList,op & 127); + Output+=op & 127; + DiffList+=(op & 127); + } + } + } + ResultListSize=(int)(Output-obuf); + +} diff --git a/tier1/uniqueid.cpp b/tier1/uniqueid.cpp new file mode 100644 index 0000000..d75e4fd --- /dev/null +++ b/tier1/uniqueid.cpp @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Unique ID generation +//=============================================================================// + +#include "tier0/platform.h" + +#ifdef IS_WINDOWS_PC +#include // UUIDCreate +#else +#include "checksum_crc.h" +#endif +#include "tier1/uniqueid.h" +#include "tier1/utlbuffer.h" + +//----------------------------------------------------------------------------- +// Creates a new unique id +//----------------------------------------------------------------------------- +void CreateUniqueId( UniqueId_t *pDest ) +{ +#ifdef IS_WINDOWS_PC + Assert( sizeof( UUID ) == sizeof( *pDest ) ); + UuidCreate( (UUID *)pDest ); +#else + // X360/linux TBD: Need a real UUID Implementation + Q_memset( pDest, 0, sizeof( UniqueId_t ) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Creates a new unique id from a string representation of one +//----------------------------------------------------------------------------- +bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen ) +{ + if ( nMaxLen == 0 ) + { + nMaxLen = Q_strlen( pBuf ); + } + + char *pTemp = (char*)stackalloc( nMaxLen + 1 ); + V_strncpy( pTemp, pBuf, nMaxLen + 1 ); + --nMaxLen; + while( (nMaxLen >= 0) && isspace( pTemp[nMaxLen] ) ) + { + --nMaxLen; + } + pTemp[ nMaxLen + 1 ] = 0; + + while( *pTemp && isspace( *pTemp ) ) + { + ++pTemp; + } + +#ifdef IS_WINDOWS_PC + Assert( sizeof( UUID ) == sizeof( *pDest ) ); + + if ( RPC_S_OK != UuidFromString( (unsigned char *)pTemp, (UUID *)pDest ) ) + { + InvalidateUniqueId( pDest ); + return false; + } +#else + // X360TBD: Need a real UUID Implementation + // For now, use crc to generate a unique ID from the UUID string. + Q_memset( pDest, 0, sizeof( UniqueId_t ) ); + if ( nMaxLen > 0 ) + { + CRC32_t crc; + CRC32_Init( &crc ); + CRC32_ProcessBuffer( &crc, pBuf, nMaxLen ); + CRC32_Final( &crc ); + Q_memcpy( pDest, &crc, sizeof( CRC32_t ) ); + } +#endif + + return true; +} + +//----------------------------------------------------------------------------- +// Sets an object ID to be an invalid state +//----------------------------------------------------------------------------- +void InvalidateUniqueId( UniqueId_t *pDest ) +{ + Assert( pDest ); + memset( pDest, 0, sizeof( UniqueId_t ) ); +} + +bool IsUniqueIdValid( const UniqueId_t &id ) +{ + UniqueId_t invalidId; + memset( &invalidId, 0, sizeof( UniqueId_t ) ); + return !IsUniqueIdEqual( invalidId, id ); +} + +bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 ) +{ + return memcmp( &id1, &id2, sizeof( UniqueId_t ) ) == 0; +} + +void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen ) +{ + pBuf[ 0 ] = 0; + +// X360TBD: Need a real UUID Implementation +#ifdef IS_WINDOWS_PC + UUID *self = ( UUID * )&id; + + unsigned char *outstring = NULL; + + UuidToString( self, &outstring ); + if ( outstring && *outstring ) + { + Q_strncpy( pBuf, (const char *)outstring, nMaxLen ); + RpcStringFree( &outstring ); + } +#endif +} + +void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest ) +{ + memcpy( pDest, &src, sizeof( UniqueId_t ) ); +} + +bool Serialize( CUtlBuffer &buf, const UniqueId_t &src ) +{ +// X360TBD: Need a real UUID Implementation +#ifdef IS_WINDOWS_PC + if ( buf.IsText() ) + { + UUID *pId = ( UUID * )&src; + + unsigned char *outstring = NULL; + + UuidToString( pId, &outstring ); + if ( outstring && *outstring ) + { + buf.PutString( (const char *)outstring ); + RpcStringFree( &outstring ); + } + else + { + buf.PutChar( '\0' ); + } + } + else + { + buf.Put( &src, sizeof(UniqueId_t) ); + } + return buf.IsValid(); +#else + return false; +#endif +} + +bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest ) +{ + if ( buf.IsText() ) + { + int nTextLen = buf.PeekStringLength(); + char *pBuf = (char*)stackalloc( nTextLen ); + buf.GetStringManualCharCount( pBuf, nTextLen ); + UniqueIdFromString( &dest, pBuf, nTextLen ); + } + else + { + buf.Get( &dest, sizeof(UniqueId_t) ); + } + return buf.IsValid(); +} + + + diff --git a/tier1/utlbinaryblock.cpp b/tier1/utlbinaryblock.cpp new file mode 100644 index 0000000..7f64c4e --- /dev/null +++ b/tier1/utlbinaryblock.cpp @@ -0,0 +1,116 @@ +//====== Copyright 1996-2004, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "tier1/utlbinaryblock.h" + +//----------------------------------------------------------------------------- +// Base class, containing simple memory management +//----------------------------------------------------------------------------- +CUtlBinaryBlock::CUtlBinaryBlock( int growSize, int initSize ) : m_Memory( growSize, initSize ) +{ + m_nActualLength = 0; +} + +CUtlBinaryBlock::CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Memory( (unsigned char*)pMemory, nSizeInBytes ) +{ + m_nActualLength = nInitialLength; +} + +CUtlBinaryBlock::CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ) : m_Memory( (const unsigned char*)pMemory, nSizeInBytes ) +{ + m_nActualLength = nSizeInBytes; +} + +CUtlBinaryBlock::CUtlBinaryBlock( const CUtlBinaryBlock& src ) +{ + Set( src.Get(), src.Length() ); +} + +void CUtlBinaryBlock::Get( void *pValue, int nLen ) const +{ + Assert( nLen > 0 ); + if ( m_nActualLength < nLen ) + { + nLen = m_nActualLength; + } + + if ( nLen > 0 ) + { + memcpy( pValue, m_Memory.Base(), nLen ); + } +} + +void CUtlBinaryBlock::SetLength( int nLength ) +{ + Assert( !m_Memory.IsReadOnly() ); + + m_nActualLength = nLength; + if ( nLength > m_Memory.NumAllocated() ) + { + int nOverFlow = nLength - m_Memory.NumAllocated(); + m_Memory.Grow( nOverFlow ); + + // If the reallocation failed, clamp length + if ( nLength > m_Memory.NumAllocated() ) + { + m_nActualLength = m_Memory.NumAllocated(); + } + } + +#ifdef _DEBUG + if ( m_Memory.NumAllocated() > m_nActualLength ) + { + memset( ( ( char * )m_Memory.Base() ) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength ); + } +#endif +} + + +void CUtlBinaryBlock::Set( const void *pValue, int nLen ) +{ + Assert( !m_Memory.IsReadOnly() ); + + if ( !pValue ) + { + nLen = 0; + } + + SetLength( nLen ); + + if ( m_nActualLength ) + { + if ( ( ( const char * )m_Memory.Base() ) >= ( ( const char * )pValue ) + nLen || + ( ( const char * )m_Memory.Base() ) + m_nActualLength <= ( ( const char * )pValue ) ) + { + memcpy( m_Memory.Base(), pValue, m_nActualLength ); + } + else + { + memmove( m_Memory.Base(), pValue, m_nActualLength ); + } + } +} + + +CUtlBinaryBlock &CUtlBinaryBlock::operator=( const CUtlBinaryBlock &src ) +{ + Assert( !m_Memory.IsReadOnly() ); + Set( src.Get(), src.Length() ); + return *this; +} + + +bool CUtlBinaryBlock::operator==( const CUtlBinaryBlock &src ) const +{ + if ( src.Length() != Length() ) + return false; + + return !memcmp( src.Get(), Get(), Length() ); +} + + + + diff --git a/tier1/utlbuffer.cpp b/tier1/utlbuffer.cpp new file mode 100644 index 0000000..d18c2ca --- /dev/null +++ b/tier1/utlbuffer.cpp @@ -0,0 +1,1794 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// $Header: $ +// $NoKeywords: $ +// +// Serialization buffer +//===========================================================================// + +#pragma warning (disable : 4514) + +#include "utlbuffer.h" +#include +#include +#include +#include +#include +#include "tier1/strtools.h" +#include "tier1/characterset.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Character conversions for C strings +//----------------------------------------------------------------------------- +class CUtlCStringConversion : public CUtlCharConversion +{ +public: + CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ); + + // Finds a conversion for the passed-in string, returns length + virtual char FindConversion( const char *pString, int *pLength ); + +private: + char m_pConversion[256]; +}; + + +//----------------------------------------------------------------------------- +// Character conversions for no-escape sequence strings +//----------------------------------------------------------------------------- +class CUtlNoEscConversion : public CUtlCharConversion +{ +public: + CUtlNoEscConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) : + CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) {} + + // Finds a conversion for the passed-in string, returns length + virtual char FindConversion( const char *pString, int *pLength ) { *pLength = 0; return 0; } +}; + + +//----------------------------------------------------------------------------- +// List of character conversions +//----------------------------------------------------------------------------- +BEGIN_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' ) + { '\n', "n" }, + { '\t', "t" }, + { '\v', "v" }, + { '\b', "b" }, + { '\r', "r" }, + { '\f', "f" }, + { '\a', "a" }, + { '\\', "\\" }, + { '\?', "\?" }, + { '\'', "\'" }, + { '\"', "\"" }, +END_CUSTOM_CHAR_CONVERSION( CUtlCStringConversion, s_StringCharConversion, "\"", '\\' ) + +CUtlCharConversion *GetCStringCharConversion() +{ + return &s_StringCharConversion; +} + +BEGIN_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F ) + { 0x7F, "" }, +END_CUSTOM_CHAR_CONVERSION( CUtlNoEscConversion, s_NoEscConversion, "\"", 0x7F ) + +CUtlCharConversion *GetNoEscCharConversion() +{ + return &s_NoEscConversion; +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CUtlCStringConversion::CUtlCStringConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) : + CUtlCharConversion( nEscapeChar, pDelimiter, nCount, pArray ) +{ + memset( m_pConversion, 0x0, sizeof(m_pConversion) ); + for ( int i = 0; i < nCount; ++i ) + { + m_pConversion[ (unsigned char) pArray[i].m_pReplacementString[0] ] = pArray[i].m_nActualChar; + } +} + +// Finds a conversion for the passed-in string, returns length +char CUtlCStringConversion::FindConversion( const char *pString, int *pLength ) +{ + char c = m_pConversion[ (unsigned char) pString[0] ]; + *pLength = (c != '\0') ? 1 : 0; + return c; +} + + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CUtlCharConversion::CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ) +{ + m_nEscapeChar = nEscapeChar; + m_pDelimiter = pDelimiter; + m_nCount = nCount; + m_nDelimiterLength = Q_strlen( pDelimiter ); + m_nMaxConversionLength = 0; + + memset( m_pReplacements, 0, sizeof(m_pReplacements) ); + + for ( int i = 0; i < nCount; ++i ) + { + m_pList[i] = pArray[i].m_nActualChar; + ConversionInfo_t &info = m_pReplacements[ (unsigned char) m_pList[i] ]; + Assert( info.m_pReplacementString == 0 ); + info.m_pReplacementString = pArray[i].m_pReplacementString; + info.m_nLength = Q_strlen( info.m_pReplacementString ); + if ( info.m_nLength > m_nMaxConversionLength ) + { + m_nMaxConversionLength = info.m_nLength; + } + } +} + + +//----------------------------------------------------------------------------- +// Escape character + delimiter +//----------------------------------------------------------------------------- +char CUtlCharConversion::GetEscapeChar() const +{ + return m_nEscapeChar; +} + +const char *CUtlCharConversion::GetDelimiter() const +{ + return m_pDelimiter; +} + +int CUtlCharConversion::GetDelimiterLength() const +{ + return m_nDelimiterLength; +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +const char *CUtlCharConversion::GetConversionString( char c ) const +{ + return m_pReplacements[ (unsigned char) c ].m_pReplacementString; +} + +int CUtlCharConversion::GetConversionLength( char c ) const +{ + return m_pReplacements[ (unsigned char) c ].m_nLength; +} + +int CUtlCharConversion::MaxConversionLength() const +{ + return m_nMaxConversionLength; +} + + +//----------------------------------------------------------------------------- +// Finds a conversion for the passed-in string, returns length +//----------------------------------------------------------------------------- +char CUtlCharConversion::FindConversion( const char *pString, int *pLength ) +{ + for ( int i = 0; i < m_nCount; ++i ) + { + if ( !Q_strcmp( pString, m_pReplacements[ (unsigned char) m_pList[i] ].m_pReplacementString ) ) + { + *pLength = m_pReplacements[ (unsigned char) m_pList[i] ].m_nLength; + return m_pList[i]; + } + } + + *pLength = 0; + return '\0'; +} + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +CUtlBuffer::CUtlBuffer( int growSize, int initSize, int nFlags ) : + m_Error(0) +{ + MEM_ALLOC_CREDIT(); + m_Memory.Init( growSize, initSize ); + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_nOffset = 0; + m_Flags = nFlags; + if ( (initSize != 0) && !IsReadOnly() ) + { + m_nMaxPut = -1; + AddNullTermination(); + } + else + { + m_nMaxPut = 0; + } + SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); +} + +CUtlBuffer::CUtlBuffer( const void *pBuffer, int nSize, int nFlags ) : + m_Memory( (unsigned char*)pBuffer, nSize ), m_Error(0) +{ + Assert( nSize != 0 ); + + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_nOffset = 0; + m_Flags = nFlags; + if ( IsReadOnly() ) + { + m_nMaxPut = nSize; + } + else + { + m_nMaxPut = -1; + AddNullTermination(); + } + SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); +} + + +//----------------------------------------------------------------------------- +// Modifies the buffer to be binary or text; Blows away the buffer and the CONTAINS_CRLF value. +//----------------------------------------------------------------------------- +void CUtlBuffer::SetBufferType( bool bIsText, bool bContainsCRLF ) +{ +#ifdef _DEBUG + // If the buffer is empty, there is no opportunity for this stuff to fail + if ( TellMaxPut() != 0 ) + { + if ( IsText() ) + { + if ( bIsText ) + { + Assert( ContainsCRLF() == bContainsCRLF ); + } + else + { + Assert( ContainsCRLF() ); + } + } + else + { + if ( bIsText ) + { + Assert( bContainsCRLF ); + } + } + } +#endif + + if ( bIsText ) + { + m_Flags |= TEXT_BUFFER; + } + else + { + m_Flags &= ~TEXT_BUFFER; + } + if ( bContainsCRLF ) + { + m_Flags |= CONTAINS_CRLF; + } + else + { + m_Flags &= ~CONTAINS_CRLF; + } +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +void CUtlBuffer::SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags ) +{ + m_Memory.SetExternalBuffer( (unsigned char*)pMemory, nSize ); + + // Reset all indices; we just changed memory + m_Get = 0; + m_Put = nInitialPut; + m_nTab = 0; + m_Error = 0; + m_nOffset = 0; + m_Flags = nFlags; + m_nMaxPut = -1; + AddNullTermination(); +} + +//----------------------------------------------------------------------------- +// Assumes an external buffer but manages its deletion +//----------------------------------------------------------------------------- +void CUtlBuffer::AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags ) +{ + m_Memory.AssumeMemory( (unsigned char*) pMemory, nSize ); + + // Reset all indices; we just changed memory + m_Get = 0; + m_Put = nInitialPut; + m_nTab = 0; + m_Error = 0; + m_nOffset = 0; + m_Flags = nFlags; + m_nMaxPut = -1; + AddNullTermination(); +} + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +void CUtlBuffer::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT(); + // Add one extra for the null termination + num += 1; + if ( m_Memory.IsExternallyAllocated() ) + { + if ( IsGrowable() && ( m_Memory.NumAllocated() < num ) ) + { + m_Memory.ConvertToGrowableMemory( 0 ); + } + else + { + num -= 1; + } + } + + m_Memory.EnsureCapacity( num ); +} + + +//----------------------------------------------------------------------------- +// Base get method from which all others derive +//----------------------------------------------------------------------------- +void CUtlBuffer::Get( void* pMem, int size ) +{ + if ( size > 0 && CheckGet( size ) ) + { + int Index = m_Get - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); + + memcpy( pMem, &m_Memory[ Index ], size ); + m_Get += size; + } +} + + +//----------------------------------------------------------------------------- +// This will get at least 1 byte and up to nSize bytes. +// It will return the number of bytes actually read. +//----------------------------------------------------------------------------- +int CUtlBuffer::GetUpTo( void *pMem, int nSize ) +{ + if ( CheckArbitraryPeekGet( 0, nSize ) ) + { + int Index = m_Get - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nSize - 1 ) ); + + memcpy( pMem, &m_Memory[ Index ], nSize ); + m_Get += nSize; + return nSize; + } + return 0; +} + + +//----------------------------------------------------------------------------- +// Eats whitespace +//----------------------------------------------------------------------------- +void CUtlBuffer::EatWhiteSpace() +{ + if ( IsText() && IsValid() ) + { + while ( CheckGet( sizeof(char) ) ) + { + if ( !isspace( *(const unsigned char*)PeekGet() ) ) + break; + m_Get += sizeof(char); + } + } +} + + +//----------------------------------------------------------------------------- +// Eats C++ style comments +//----------------------------------------------------------------------------- +bool CUtlBuffer::EatCPPComment() +{ + if ( IsText() && IsValid() ) + { + // If we don't have a a c++ style comment next, we're done + const char *pPeek = (const char *)PeekGet( 2 * sizeof(char), 0 ); + if ( !pPeek || ( pPeek[0] != '/' ) || ( pPeek[1] != '/' ) ) + return false; + + // Deal with c++ style comments + m_Get += 2; + + // read complete line + for ( char c = GetChar(); IsValid(); c = GetChar() ) + { + if ( c == '\n' ) + break; + } + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Peeks how much whitespace to eat +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekWhiteSpace( int nOffset ) +{ + if ( !IsText() || !IsValid() ) + return 0; + + while ( CheckPeekGet( nOffset, sizeof(char) ) ) + { + if ( !isspace( *(unsigned char*)PeekGet( nOffset ) ) ) + break; + nOffset += sizeof(char); + } + + return nOffset; +} + + +//----------------------------------------------------------------------------- +// Peek size of sting to come, check memory bound +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekStringLength() +{ + if ( !IsValid() ) + return 0; + + // Eat preceeding whitespace + int nOffset = 0; + if ( IsText() ) + { + nOffset = PeekWhiteSpace( nOffset ); + } + + int nStartingOffset = nOffset; + + do + { + int nPeekAmount = 128; + + // NOTE: Add 1 for the terminating zero! + if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) + { + if ( nOffset == nStartingOffset ) + return 0; + return nOffset - nStartingOffset + 1; + } + + const char *pTest = (const char *)PeekGet( nOffset ); + + if ( !IsText() ) + { + for ( int i = 0; i < nPeekAmount; ++i ) + { + // The +1 here is so we eat the terminating 0 + if ( pTest[i] == 0 ) + return (i + nOffset - nStartingOffset + 1); + } + } + else + { + for ( int i = 0; i < nPeekAmount; ++i ) + { + // The +1 here is so we eat the terminating 0 + if ( isspace((unsigned char)pTest[i]) || (pTest[i] == 0) ) + return (i + nOffset - nStartingOffset + 1); + } + } + + nOffset += nPeekAmount; + + } while ( true ); +} + + +//----------------------------------------------------------------------------- +// Peek size of line to come, check memory bound +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekLineLength() +{ + if ( !IsValid() ) + return 0; + + int nOffset = 0; + int nStartingOffset = nOffset; + + do + { + int nPeekAmount = 128; + + // NOTE: Add 1 for the terminating zero! + if ( !CheckArbitraryPeekGet( nOffset, nPeekAmount ) ) + { + if ( nOffset == nStartingOffset ) + return 0; + return nOffset - nStartingOffset + 1; + } + + const char *pTest = (const char *)PeekGet( nOffset ); + + for ( int i = 0; i < nPeekAmount; ++i ) + { + // The +2 here is so we eat the terminating '\n' and 0 + if ( pTest[i] == '\n' || pTest[i] == '\r' ) + return (i + nOffset - nStartingOffset + 2); + // The +1 here is so we eat the terminating 0 + if ( pTest[i] == 0 ) + return (i + nOffset - nStartingOffset + 1); + } + + nOffset += nPeekAmount; + + } while ( true ); +} + + +//----------------------------------------------------------------------------- +// Does the next bytes of the buffer match a pattern? +//----------------------------------------------------------------------------- +bool CUtlBuffer::PeekStringMatch( int nOffset, const char *pString, int nLen ) +{ + if ( !CheckPeekGet( nOffset, nLen ) ) + return false; + return !Q_strncmp( (const char*)PeekGet(nOffset), pString, nLen ); +} + + +//----------------------------------------------------------------------------- +// This version of PeekStringLength converts \" to \\ and " to \, etc. +// It also reads a " at the beginning and end of the string +//----------------------------------------------------------------------------- +int CUtlBuffer::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize ) +{ + if ( !IsText() || !pConv ) + return PeekStringLength(); + + // Eat preceeding whitespace + int nOffset = 0; + if ( IsText() ) + { + nOffset = PeekWhiteSpace( nOffset ); + } + + if ( !PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + return 0; + + // Try to read ending ", but don't accept \" + int nActualStart = nOffset; + nOffset += pConv->GetDelimiterLength(); + int nLen = 1; // Starts at 1 for the '\0' termination + + do + { + if ( PeekStringMatch( nOffset, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + break; + + if ( !CheckPeekGet( nOffset, 1 ) ) + break; + + char c = *(const char*)PeekGet( nOffset ); + ++nLen; + ++nOffset; + if ( c == pConv->GetEscapeChar() ) + { + int nLength = pConv->MaxConversionLength(); + if ( !CheckArbitraryPeekGet( nOffset, nLength ) ) + break; + + pConv->FindConversion( (const char*)PeekGet(nOffset), &nLength ); + nOffset += nLength; + } + } while (true); + + return bActualSize ? nLen : nOffset - nActualStart + pConv->GetDelimiterLength() + 1; +} + + +//----------------------------------------------------------------------------- +// Reads a null-terminated string +//----------------------------------------------------------------------------- +void CUtlBuffer::GetStringInternal( char *pString, size_t maxLenInChars ) +{ + if ( !IsValid() ) + { + *pString = 0; + return; + } + + Assert( maxLenInChars != 0 ); + + if ( maxLenInChars == 0 ) + { + return; + } + + // Remember, this *includes* the null character + // It will be 0, however, if the buffer is empty. + int nLen = PeekStringLength(); + + if ( IsText() ) + { + EatWhiteSpace(); + } + + if ( nLen <= 0 ) + { + *pString = 0; + m_Error |= GET_OVERFLOW; + return; + } + + const size_t nCharsToRead = vmin( (size_t)nLen, maxLenInChars ) - 1; + + Get( pString, nCharsToRead ); + pString[nCharsToRead] = 0; + + if ( (size_t)nLen > (nCharsToRead + 1) ) + { + SeekGet( SEEK_CURRENT, nLen - (nCharsToRead + 1) ); + } + + // Read the terminating NULL in binary formats + if ( !IsText() ) + { + VerifyEquals( GetChar(), 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Reads up to and including the first \n +//----------------------------------------------------------------------------- +void CUtlBuffer::GetLine( char* pLine, int nMaxChars ) +{ + Assert( IsText() && !ContainsCRLF() ); + + if ( !IsValid() ) + { + *pLine = 0; + return; + } + + if ( nMaxChars == 0 ) + { + nMaxChars = INT_MAX; + } + + // Remember, this *includes* the null character + // It will be 0, however, if the buffer is empty. + int nLen = PeekLineLength(); + if ( nLen == 0 ) + { + *pLine = 0; + m_Error |= GET_OVERFLOW; + return; + } + + // Strip off the terminating NULL + if ( nLen <= nMaxChars ) + { + Get( pLine, nLen - 1 ); + pLine[ nLen - 1 ] = 0; + } + else + { + Get( pLine, nMaxChars - 1 ); + pLine[ nMaxChars - 1 ] = 0; + SeekGet( SEEK_CURRENT, nLen - 1 - nMaxChars ); + } +} + + +//----------------------------------------------------------------------------- +// This version of GetString converts \ to \\ and " to \", etc. +// It also places " at the beginning and end of the string +//----------------------------------------------------------------------------- +char CUtlBuffer::GetDelimitedCharInternal( CUtlCharConversion *pConv ) +{ + char c = GetChar(); + if ( c == pConv->GetEscapeChar() ) + { + int nLength = pConv->MaxConversionLength(); + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + return '\0'; + + c = pConv->FindConversion( (const char *)PeekGet(), &nLength ); + SeekGet( SEEK_CURRENT, nLength ); + } + + return c; +} + +char CUtlBuffer::GetDelimitedChar( CUtlCharConversion *pConv ) +{ + if ( !IsText() || !pConv ) + return GetChar( ); + return GetDelimitedCharInternal( pConv ); +} + +void CUtlBuffer::GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars ) +{ + if ( !IsText() || !pConv ) + { + GetStringInternal( pString, nMaxChars ); + return; + } + + if (!IsValid()) + { + *pString = 0; + return; + } + + if ( nMaxChars == 0 ) + { + nMaxChars = INT_MAX; + } + + EatWhiteSpace(); + if ( !PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + return; + + // Pull off the starting delimiter + SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() ); + + int nRead = 0; + while ( IsValid() ) + { + if ( PeekStringMatch( 0, pConv->GetDelimiter(), pConv->GetDelimiterLength() ) ) + { + SeekGet( SEEK_CURRENT, pConv->GetDelimiterLength() ); + break; + } + + char c = GetDelimitedCharInternal( pConv ); + + if ( nRead < nMaxChars ) + { + pString[nRead] = c; + ++nRead; + } + } + + if ( nRead >= nMaxChars ) + { + nRead = nMaxChars - 1; + } + pString[nRead] = '\0'; +} + + +//----------------------------------------------------------------------------- +// Checks if a get is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckGet( int nSize ) +{ + if ( m_Error & GET_OVERFLOW ) + return false; + + if ( TellMaxPut() < m_Get + nSize ) + { + m_Error |= GET_OVERFLOW; + return false; + } + + if ( ( m_Get < m_nOffset ) || ( m_Memory.NumAllocated() < m_Get - m_nOffset + nSize ) ) + { + if ( !OnGetOverflow( nSize ) ) + { + m_Error |= GET_OVERFLOW; + return false; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Checks if a peek get is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckPeekGet( int nOffset, int nSize ) +{ + if ( m_Error & GET_OVERFLOW ) + return false; + + // Checking for peek can't set the overflow flag + bool bOk = CheckGet( nOffset + nSize ); + m_Error &= ~GET_OVERFLOW; + return bOk; +} + + +//----------------------------------------------------------------------------- +// Call this to peek arbitrarily long into memory. It doesn't fail unless +// it can't read *anything* new +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckArbitraryPeekGet( int nOffset, int &nIncrement ) +{ + if ( TellGet() + nOffset >= TellMaxPut() ) + { + nIncrement = 0; + return false; + } + + if ( TellGet() + nOffset + nIncrement > TellMaxPut() ) + { + nIncrement = TellMaxPut() - TellGet() - nOffset; + } + + // NOTE: CheckPeekGet could modify TellMaxPut for streaming files + // We have to call TellMaxPut again here + CheckPeekGet( nOffset, nIncrement ); + int nMaxGet = TellMaxPut() - TellGet(); + if ( nMaxGet < nIncrement ) + { + nIncrement = nMaxGet; + } + return (nIncrement != 0); +} + + +//----------------------------------------------------------------------------- +// Peek part of the butt +//----------------------------------------------------------------------------- +const void* CUtlBuffer::PeekGet( int nMaxSize, int nOffset ) +{ + if ( !CheckPeekGet( nOffset, nMaxSize ) ) + return NULL; + + int Index = m_Get + nOffset - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nMaxSize - 1 ) ); + + return &m_Memory[ Index ]; +} + + +//----------------------------------------------------------------------------- +// Change where I'm reading +//----------------------------------------------------------------------------- +void CUtlBuffer::SeekGet( SeekType_t type, int offset ) +{ + switch( type ) + { + case SEEK_HEAD: + m_Get = offset; + break; + + case SEEK_CURRENT: + m_Get += offset; + break; + + case SEEK_TAIL: + m_Get = m_nMaxPut - offset; + break; + } + + if ( m_Get > m_nMaxPut ) + { + m_Error |= GET_OVERFLOW; + } + else + { + m_Error &= ~GET_OVERFLOW; + if ( m_Get < m_nOffset || m_Get >= m_nOffset + Size() ) + { + OnGetOverflow( -1 ); + } + } +} + + +//----------------------------------------------------------------------------- +// Parse... +//----------------------------------------------------------------------------- + +#pragma warning ( disable : 4706 ) + +int CUtlBuffer::VaScanf( const char* pFmt, va_list list ) +{ + Assert( pFmt ); + if ( m_Error || !IsText() ) + return 0; + + int numScanned = 0; + int nLength; + char c; + char* pEnd; + while ( (c = *pFmt++) ) + { + // Stop if we hit the end of the buffer + if ( m_Get >= TellMaxPut() ) + { + m_Error |= GET_OVERFLOW; + break; + } + + switch (c) + { + case ' ': + // eat all whitespace + EatWhiteSpace(); + break; + + case '%': + { + // Conversion character... try to convert baby! + char type = *pFmt++; + if (type == 0) + return numScanned; + + switch(type) + { + case 'c': + { + char* ch = va_arg( list, char * ); + if ( CheckPeekGet( 0, sizeof(char) ) ) + { + *ch = *(const char*)PeekGet(); + ++m_Get; + } + else + { + *ch = 0; + return numScanned; + } + } + break; + + case 'i': + case 'd': + { + int* i = va_arg( list, int * ); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *i = 0; + return numScanned; + } + + *i = strtol( (char*)PeekGet(), &pEnd, 10 ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 'x': + { + int* i = va_arg( list, int * ); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *i = 0; + return numScanned; + } + + *i = strtol( (char*)PeekGet(), &pEnd, 16 ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 'u': + { + unsigned int* u = va_arg( list, unsigned int *); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *u = 0; + return numScanned; + } + + *u = strtoul( (char*)PeekGet(), &pEnd, 10 ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 'f': + { + float* f = va_arg( list, float *); + + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + *f = 0.0f; + return numScanned; + } + + *f = (float)strtod( (char*)PeekGet(), &pEnd ); + int nBytesRead = (int)( pEnd - (char*)PeekGet() ); + if ( nBytesRead == 0 ) + return numScanned; + m_Get += nBytesRead; + } + break; + + case 's': + { + char* s = va_arg( list, char * ); + GetStringInternal( s, 256 ); + } + break; + + default: + { + // unimplemented scanf type + Assert(0); + return numScanned; + } + break; + } + + ++numScanned; + } + break; + + default: + { + // Here we have to match the format string character + // against what's in the buffer or we're done. + if ( !CheckPeekGet( 0, sizeof(char) ) ) + return numScanned; + + if ( c != *(const char*)PeekGet() ) + return numScanned; + + ++m_Get; + } + } + } + return numScanned; +} + +#pragma warning ( default : 4706 ) + +int CUtlBuffer::Scanf( const char* pFmt, ... ) +{ + va_list args; + + va_start( args, pFmt ); + int count = VaScanf( pFmt, args ); + va_end( args ); + + return count; +} + + +//----------------------------------------------------------------------------- +// Advance the get index until after the particular string is found +// Do not eat whitespace before starting. Return false if it failed +//----------------------------------------------------------------------------- +bool CUtlBuffer::GetToken( const char *pToken ) +{ + Assert( pToken ); + + // Look for the token + int nLen = Q_strlen( pToken ); + + int nSizeToCheck = Size() - TellGet() - m_nOffset; + + int nGet = TellGet(); + do + { + int nMaxSize = TellMaxPut() - TellGet(); + if ( nMaxSize < nSizeToCheck ) + { + nSizeToCheck = nMaxSize; + } + if ( nLen > nSizeToCheck ) + break; + + if ( !CheckPeekGet( 0, nSizeToCheck ) ) + break; + + const char *pBufStart = (const char*)PeekGet(); + const char *pFoundEnd = Q_strnistr( pBufStart, pToken, nSizeToCheck ); + if ( pFoundEnd ) + { + size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart; + SeekGet( CUtlBuffer::SEEK_CURRENT, nOffset + nLen ); + return true; + } + + SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen - 1 ); + nSizeToCheck = Size() - (nLen-1); + + } while ( true ); + + SeekGet( CUtlBuffer::SEEK_HEAD, nGet ); + return false; +} + + +//----------------------------------------------------------------------------- +// (For text buffers only) +// Parse a token from the buffer: +// Grab all text that lies between a starting delimiter + ending delimiter +// (skipping whitespace that leads + trails both delimiters). +// Note the delimiter checks are case-insensitive. +// If successful, the get index is advanced and the function returns true, +// otherwise the index is not advanced and the function returns false. +//----------------------------------------------------------------------------- +bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen ) +{ + int nCharsToCopy = 0; + int nCurrentGet = 0; + + size_t nEndingDelimLen; + + // Starting delimiter is optional + char emptyBuf = '\0'; + if ( !pStartingDelim ) + { + pStartingDelim = &emptyBuf; + } + + // Ending delimiter is not + Assert( pEndingDelim && pEndingDelim[0] ); + nEndingDelimLen = Q_strlen( pEndingDelim ); + + int nStartGet = TellGet(); + char nCurrChar; + int nTokenStart = -1; + EatWhiteSpace( ); + while ( *pStartingDelim ) + { + nCurrChar = *pStartingDelim++; + if ( !isspace((unsigned char)nCurrChar) ) + { + if ( tolower( GetChar() ) != tolower( nCurrChar ) ) + goto parseFailed; + } + else + { + EatWhiteSpace(); + } + } + + EatWhiteSpace(); + nTokenStart = TellGet(); + if ( !GetToken( pEndingDelim ) ) + goto parseFailed; + + nCurrentGet = TellGet(); + nCharsToCopy = (nCurrentGet - nEndingDelimLen) - nTokenStart; + if ( nCharsToCopy >= nMaxLen ) + { + nCharsToCopy = nMaxLen - 1; + } + + if ( nCharsToCopy > 0 ) + { + SeekGet( CUtlBuffer::SEEK_HEAD, nTokenStart ); + Get( pString, nCharsToCopy ); + if ( !IsValid() ) + goto parseFailed; + + // Eat trailing whitespace + for ( ; nCharsToCopy > 0; --nCharsToCopy ) + { + if ( !isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) ) + break; + } + } + pString[ nCharsToCopy ] = '\0'; + + // Advance the Get index + SeekGet( CUtlBuffer::SEEK_HEAD, nCurrentGet ); + return true; + +parseFailed: + // Revert the get index + SeekGet( SEEK_HEAD, nStartGet ); + pString[0] = '\0'; + return false; +} + + +//----------------------------------------------------------------------------- +// Parses the next token, given a set of character breaks to stop at +//----------------------------------------------------------------------------- +int CUtlBuffer::ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments ) +{ + Assert( nMaxLen > 0 ); + pTokenBuf[0] = 0; + + // skip whitespace + comments + while ( true ) + { + if ( !IsValid() ) + return -1; + EatWhiteSpace(); + if ( bParseComments ) + { + if ( !EatCPPComment() ) + break; + } + else + { + break; + } + } + + char c = GetChar(); + + // End of buffer + if ( c == 0 ) + return -1; + + // handle quoted strings specially + if ( c == '\"' ) + { + int nLen = 0; + while( IsValid() ) + { + c = GetChar(); + if ( c == '\"' || !c ) + { + pTokenBuf[nLen] = 0; + return nLen; + } + pTokenBuf[nLen] = c; + if ( ++nLen == nMaxLen ) + { + pTokenBuf[nLen-1] = 0; + return nMaxLen; + } + } + + // In this case, we hit the end of the buffer before hitting the end qoute + pTokenBuf[nLen] = 0; + return nLen; + } + + // parse single characters + if ( IN_CHARACTERSET( *pBreaks, c ) ) + { + pTokenBuf[0] = c; + pTokenBuf[1] = 0; + return 1; + } + + // parse a regular word + int nLen = 0; + while ( true ) + { + pTokenBuf[nLen] = c; + if ( ++nLen == nMaxLen ) + { + pTokenBuf[nLen-1] = 0; + return nMaxLen; + } + c = GetChar(); + if ( !IsValid() ) + break; + + if ( IN_CHARACTERSET( *pBreaks, c ) || c == '\"' || c <= ' ' ) + { + SeekGet( SEEK_CURRENT, -1 ); + break; + } + } + + pTokenBuf[nLen] = 0; + return nLen; +} + + + +//----------------------------------------------------------------------------- +// Serialization +//----------------------------------------------------------------------------- +void CUtlBuffer::Put( const void *pMem, int size ) +{ + if ( size && CheckPut( size ) ) + { + int Index = m_Put - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); + if( Index >= 0 ) + { + memcpy( &m_Memory[ Index ], pMem, size ); + m_Put += size; + + AddNullTermination(); + } + } +} + + +//----------------------------------------------------------------------------- +// Writes a null-terminated string +//----------------------------------------------------------------------------- +void CUtlBuffer::PutString( const char* pString ) +{ + if (!IsText()) + { + if ( pString ) + { + // Not text? append a null at the end. + size_t nLen = Q_strlen( pString ) + 1; + Put( pString, nLen * sizeof(char) ); + return; + } + else + { + PutTypeBin( 0 ); + } + } + else if (pString) + { + int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab; + if ( nTabCount > 0 ) + { + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + + const char* pEndl = strchr( pString, '\n' ); + while ( pEndl ) + { + size_t nSize = (size_t)pEndl - (size_t)pString + sizeof(char); + Put( pString, nSize ); + pString = pEndl + 1; + if ( *pString ) + { + PutTabs(); + pEndl = strchr( pString, '\n' ); + } + else + { + pEndl = NULL; + } + } + } + size_t nLen = Q_strlen( pString ); + if ( nLen ) + { + Put( pString, nLen * sizeof(char) ); + } + } +} + + +//----------------------------------------------------------------------------- +// This version of PutString converts \ to \\ and " to \", etc. +// It also places " at the beginning and end of the string +//----------------------------------------------------------------------------- +inline void CUtlBuffer::PutDelimitedCharInternal( CUtlCharConversion *pConv, char c ) +{ + int l = pConv->GetConversionLength( c ); + if ( l == 0 ) + { + PutChar( c ); + } + else + { + PutChar( pConv->GetEscapeChar() ); + Put( pConv->GetConversionString( c ), l ); + } +} + +void CUtlBuffer::PutDelimitedChar( CUtlCharConversion *pConv, char c ) +{ + if ( !IsText() || !pConv ) + { + PutChar( c ); + return; + } + + PutDelimitedCharInternal( pConv, c ); +} + +void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pString ) +{ + if ( !IsText() || !pConv ) + { + PutString( pString ); + return; + } + + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); + + int nLen = pString ? Q_strlen( pString ) : 0; + for ( int i = 0; i < nLen; ++i ) + { + PutDelimitedCharInternal( pConv, pString[i] ); + } + + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); +} + + +void CUtlBuffer::VaPrintf( const char* pFmt, va_list list ) +{ + char temp[2048]; +#ifdef DBGFLAG_ASSERT + int nLen = +#endif + Q_vsnprintf( temp, sizeof( temp ), pFmt, list ); + Assert( nLen < 2048 ); + PutString( temp ); +} + +void CUtlBuffer::Printf( const char* pFmt, ... ) +{ + va_list args; + + va_start( args, pFmt ); + VaPrintf( pFmt, args ); + va_end( args ); +} + + +//----------------------------------------------------------------------------- +// Calls the overflow functions +//----------------------------------------------------------------------------- +void CUtlBuffer::SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc ) +{ + m_GetOverflowFunc = getFunc; + m_PutOverflowFunc = putFunc; +} + + +//----------------------------------------------------------------------------- +// Calls the overflow functions +//----------------------------------------------------------------------------- +bool CUtlBuffer::OnPutOverflow( int nSize ) +{ + return (this->*m_PutOverflowFunc)( nSize ); +} + +bool CUtlBuffer::OnGetOverflow( int nSize ) +{ + return (this->*m_GetOverflowFunc)( nSize ); +} + + +//----------------------------------------------------------------------------- +// Checks if a put is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::PutOverflow( int nSize ) +{ + MEM_ALLOC_CREDIT(); + + if ( m_Memory.IsExternallyAllocated() ) + { + if ( !IsGrowable() ) + return false; + + m_Memory.ConvertToGrowableMemory( 0 ); + } + + while( Size() < m_Put - m_nOffset + nSize ) + { + m_Memory.Grow(); + } + + return true; +} + +bool CUtlBuffer::GetOverflow( int nSize ) +{ + return false; +} + + +//----------------------------------------------------------------------------- +// Checks if a put is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckPut( int nSize ) +{ + if ( ( m_Error & PUT_OVERFLOW ) || IsReadOnly() ) + return false; + + if ( ( m_Put < m_nOffset ) || ( m_Memory.NumAllocated() < m_Put - m_nOffset + nSize ) ) + { + if ( !OnPutOverflow( nSize ) ) + { + m_Error |= PUT_OVERFLOW; + return false; + } + } + return true; +} + +void CUtlBuffer::SeekPut( SeekType_t type, int offset ) +{ + int nNextPut = m_Put; + switch( type ) + { + case SEEK_HEAD: + nNextPut = offset; + break; + + case SEEK_CURRENT: + nNextPut += offset; + break; + + case SEEK_TAIL: + nNextPut = m_nMaxPut - offset; + break; + } + + // Force a write of the data + // FIXME: We could make this more optimal potentially by writing out + // the entire buffer if you seek outside the current range + + // NOTE: This call will write and will also seek the file to nNextPut. + OnPutOverflow( -nNextPut-1 ); + m_Put = nNextPut; + + AddNullTermination(); +} + + +void CUtlBuffer::ActivateByteSwapping( bool bActivate ) +{ + m_Byteswap.ActivateByteSwapping( bActivate ); +} + +void CUtlBuffer::SetBigEndian( bool bigEndian ) +{ + m_Byteswap.SetTargetBigEndian( bigEndian ); +} + +bool CUtlBuffer::IsBigEndian( void ) +{ + return m_Byteswap.IsTargetBigEndian(); +} + + +//----------------------------------------------------------------------------- +// null terminate the buffer +//----------------------------------------------------------------------------- +void CUtlBuffer::AddNullTermination( void ) +{ + if ( m_Put > m_nMaxPut ) + { + if ( !IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0) ) + { + // Add null termination value + if ( CheckPut( 1 ) ) + { + int Index = m_Put - m_nOffset; + Assert( m_Memory.IsIdxValid( Index ) ); + if( Index >= 0 ) + { + m_Memory[ Index ] = 0; + } + } + else + { + // Restore the overflow state, it was valid before... + m_Error &= ~PUT_OVERFLOW; + } + } + m_nMaxPut = m_Put; + } +} + + +//----------------------------------------------------------------------------- +// Converts a buffer from a CRLF buffer to a CR buffer (and back) +// Returns false if no conversion was necessary (and outBuf is left untouched) +// If the conversion occurs, outBuf will be cleared. +//----------------------------------------------------------------------------- +bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf ) +{ + if ( !IsText() || !outBuf.IsText() ) + return false; + + if ( ContainsCRLF() == outBuf.ContainsCRLF() ) + return false; + + int nInCount = TellMaxPut(); + + outBuf.Purge(); + outBuf.EnsureCapacity( nInCount ); + + bool bFromCRLF = ContainsCRLF(); + + // Start reading from the beginning + int nGet = TellGet(); + int nPut = TellPut(); + int nGetDelta = 0; + int nPutDelta = 0; + + const char *pBase = (const char*)Base(); + int nCurrGet = 0; + while ( nCurrGet < nInCount ) + { + const char *pCurr = &pBase[nCurrGet]; + if ( bFromCRLF ) + { + const char *pNext = Q_strnistr( pCurr, "\r\n", nInCount - nCurrGet ); + if ( !pNext ) + { + outBuf.Put( pCurr, nInCount - nCurrGet ); + break; + } + + int nBytes = (size_t)pNext - (size_t)pCurr; + outBuf.Put( pCurr, nBytes ); + outBuf.PutChar( '\n' ); + nCurrGet += nBytes + 2; + if ( nGet >= nCurrGet - 1 ) + { + --nGetDelta; + } + if ( nPut >= nCurrGet - 1 ) + { + --nPutDelta; + } + } + else + { + const char *pNext = Q_strnchr( pCurr, '\n', nInCount - nCurrGet ); + if ( !pNext ) + { + outBuf.Put( pCurr, nInCount - nCurrGet ); + break; + } + + int nBytes = (size_t)pNext - (size_t)pCurr; + outBuf.Put( pCurr, nBytes ); + outBuf.PutChar( '\r' ); + outBuf.PutChar( '\n' ); + nCurrGet += nBytes + 1; + if ( nGet >= nCurrGet ) + { + ++nGetDelta; + } + if ( nPut >= nCurrGet ) + { + ++nPutDelta; + } + } + } + + Assert( nPut + nPutDelta <= outBuf.TellMaxPut() ); + + outBuf.SeekGet( SEEK_HEAD, nGet + nGetDelta ); + outBuf.SeekPut( SEEK_HEAD, nPut + nPutDelta ); + + return true; +} + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +void CUtlBuffer::Swap( CUtlBuffer &buf ) +{ + V_swap( m_Get, buf.m_Get ); + V_swap( m_Put, buf.m_Put ); + V_swap( m_nMaxPut, buf.m_nMaxPut ); + V_swap( m_Error, buf.m_Error ); + m_Memory.Swap( buf.m_Memory ); +} + + +//----------------------------------------------------------------------------- +// Fast swap w/ a CUtlMemory. +//----------------------------------------------------------------------------- +void CUtlBuffer::Swap( CUtlMemory &mem ) +{ + m_Get = 0; + m_Put = mem.Count(); + m_nMaxPut = mem.Count(); + m_Error = 0; + m_Memory.Swap( mem ); +} + +//--------------------------------------------------------------------------- +// Implementation of CUtlInplaceBuffer +//--------------------------------------------------------------------------- + +CUtlInplaceBuffer::CUtlInplaceBuffer( int growSize /* = 0 */, int initSize /* = 0 */, int nFlags /* = 0 */ ) : + CUtlBuffer( growSize, initSize, nFlags ) +{ +} + +bool CUtlInplaceBuffer::InplaceGetLinePtr( char **ppszInBufferPtr, int *pnLineLength ) +{ + Assert( IsText() && !ContainsCRLF() ); + + int nLineLen = PeekLineLength(); + if ( nLineLen <= 1 ) + { + SeekGet( SEEK_TAIL, 0 ); + return false; + } + + -- nLineLen; // because it accounts for putting a terminating null-character + + char *pszLine = ( char * ) const_cast< void * >( PeekGet() ); + SeekGet( SEEK_CURRENT, nLineLen ); + + // Set the out args + if ( ppszInBufferPtr ) + *ppszInBufferPtr = pszLine; + + if ( pnLineLength ) + *pnLineLength = nLineLen; + + return true; +} + +char * CUtlInplaceBuffer::InplaceGetLinePtr( void ) +{ + char *pszLine = NULL; + int nLineLen = 0; + + if ( InplaceGetLinePtr( &pszLine, &nLineLen ) ) + { + Assert( nLineLen >= 1 ); + + switch ( pszLine[ nLineLen - 1 ] ) + { + case '\n': + case '\r': + pszLine[ nLineLen - 1 ] = 0; + if ( -- nLineLen ) + { + switch ( pszLine[ nLineLen - 1 ] ) + { + case '\n': + case '\r': + pszLine[ nLineLen - 1 ] = 0; + break; + } + } + break; + + default: + Assert( pszLine[ nLineLen ] == 0 ); + break; + } + } + + return pszLine; +} + diff --git a/tier1/utlbufferutil.cpp b/tier1/utlbufferutil.cpp new file mode 100644 index 0000000..79949bf --- /dev/null +++ b/tier1/utlbufferutil.cpp @@ -0,0 +1,560 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// $Header: $ +// $NoKeywords: $ +// +// Serialization buffer +//===========================================================================// + +#pragma warning (disable : 4514) + +#include "tier1/utlbufferutil.h" +#include "tier1/utlbuffer.h" +#include "mathlib/vector.h" +#include "mathlib/vector2d.h" +#include "mathlib/vector4d.h" +#include "mathlib/vmatrix.h" +#include "Color.h" +#include +#include +#include +#include +#include +#include "tier1/utlbinaryblock.h" +#include "tier1/utlstring.h" +#include "tier1/strtools.h" +#include "tier1/characterset.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// For serialization, set the delimiter rules +//----------------------------------------------------------------------------- +CUtlCharConversion *s_pConv = NULL; +const char *s_pUtlBufferUtilArrayDelim = NULL; +void SetSerializationDelimiter( CUtlCharConversion *pConv ) +{ + s_pConv = pConv; +} + +void SetSerializationArrayDelimiter( const char *pDelimiter ) +{ + s_pUtlBufferUtilArrayDelim = pDelimiter; +} + + +//----------------------------------------------------------------------------- +// Serialize a floating point number in text mode in a readably friendly fashion +//----------------------------------------------------------------------------- +static void SerializeFloat( CUtlBuffer &buf, float f ) +{ + Assert( buf.IsText() ); + + // FIXME: Print this in a way that we never lose precision + char pTemp[256]; + int nLen = Q_snprintf( pTemp, sizeof(pTemp), "%.10f", f ); + while ( nLen > 0 && pTemp[nLen-1] == '0' ) + { + --nLen; + pTemp[nLen] = 0; + } + if ( nLen > 0 && pTemp[nLen-1] == '.' ) + { + --nLen; + pTemp[nLen] = 0; + } + buf.PutString( pTemp ); +} + +static void SerializeFloats( CUtlBuffer &buf, int nCount, const float *pFloats ) +{ + for ( int i = 0; i < nCount; ++i ) + { + SerializeFloat( buf, pFloats[i] ); + if ( i != nCount-1 ) + { + buf.PutChar( ' ' ); + } + } +} + + +//----------------------------------------------------------------------------- +// Serialization methods for basic types +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const bool &src ) +{ + if ( buf.IsText() ) + { + buf.Printf( "%d", src ); + } + else + { + buf.PutChar( src ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, bool &dest ) +{ + if ( buf.IsText() ) + { + int nValue = 0; + int nRetVal = buf.Scanf( "%d", &nValue ); + dest = ( nValue != 0 ); + return (nRetVal == 1) && buf.IsValid(); + } + + dest = ( buf.GetChar( ) != 0 ); + return buf.IsValid(); +} + + +bool Serialize( CUtlBuffer &buf, const int &src ) +{ + if ( buf.IsText() ) + { + buf.Printf( "%d", src ); + } + else + { + buf.PutInt( src ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, int &dest ) +{ + if ( buf.IsText() ) + { + int nRetVal = buf.Scanf( "%d", &dest ); + return (nRetVal == 1) && buf.IsValid(); + } + + dest = buf.GetInt( ); + return buf.IsValid(); +} + +bool Serialize( CUtlBuffer &buf, const float &src ) +{ + if ( buf.IsText() ) + { + SerializeFloat( buf, src ); + } + else + { + buf.PutFloat( src ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, float &dest ) +{ + if ( buf.IsText() ) + { + // FIXME: Print this in a way that we never lose precision + int nRetVal = buf.Scanf( "%f", &dest ); + return (nRetVal == 1) && buf.IsValid(); + } + + dest = buf.GetFloat( ); + return buf.IsValid(); +} + + +//----------------------------------------------------------------------------- +// Attribute types related to vector math +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const Vector2D &src ) +{ + if ( buf.IsText() ) + { + SerializeFloats( buf, 2, src.Base() ); + } + else + { + buf.PutFloat( src.x ); + buf.PutFloat( src.y ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, Vector2D &dest ) +{ + if ( buf.IsText() ) + { + // FIXME: Print this in a way that we never lose precision + int nRetVal = buf.Scanf( "%f %f", &dest.x, &dest.y ); + return (nRetVal == 2) && buf.IsValid(); + } + + dest.x = buf.GetFloat( ); + dest.y = buf.GetFloat( ); + return buf.IsValid(); +} + +bool Serialize( CUtlBuffer &buf, const Vector &src ) +{ + if ( buf.IsText() ) + { + SerializeFloats( buf, 3, src.Base() ); + } + else + { + buf.PutFloat( src.x ); + buf.PutFloat( src.y ); + buf.PutFloat( src.z ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, Vector &dest ) +{ + if ( buf.IsText() ) + { + // FIXME: Print this in a way that we never lose precision + int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z ); + return (nRetVal == 3) && buf.IsValid(); + } + + dest.x = buf.GetFloat( ); + dest.y = buf.GetFloat( ); + dest.z = buf.GetFloat( ); + return buf.IsValid(); +} + +bool Serialize( CUtlBuffer &buf, const Vector4D &src ) +{ + if ( buf.IsText() ) + { + SerializeFloats( buf, 4, src.Base() ); + } + else + { + buf.PutFloat( src.x ); + buf.PutFloat( src.y ); + buf.PutFloat( src.z ); + buf.PutFloat( src.w ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, Vector4D &dest ) +{ + if ( buf.IsText() ) + { + // FIXME: Print this in a way that we never lose precision + int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w ); + return (nRetVal == 4) && buf.IsValid(); + } + + dest.x = buf.GetFloat( ); + dest.y = buf.GetFloat( ); + dest.z = buf.GetFloat( ); + dest.w = buf.GetFloat( ); + return buf.IsValid(); +} + +bool Serialize( CUtlBuffer &buf, const QAngle &src ) +{ + if ( buf.IsText() ) + { + SerializeFloats( buf, 3, src.Base() ); + } + else + { + buf.PutFloat( src.x ); + buf.PutFloat( src.y ); + buf.PutFloat( src.z ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, QAngle &dest ) +{ + if ( buf.IsText() ) + { + // FIXME: Print this in a way that we never lose precision + int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z ); + return (nRetVal == 3) && buf.IsValid(); + } + + dest.x = buf.GetFloat( ); + dest.y = buf.GetFloat( ); + dest.z = buf.GetFloat( ); + return buf.IsValid(); +} + +bool Serialize( CUtlBuffer &buf, const Quaternion &src ) +{ + if ( buf.IsText() ) + { + SerializeFloats( buf, 4, &src.x ); + } + else + { + buf.PutFloat( src.x ); + buf.PutFloat( src.y ); + buf.PutFloat( src.z ); + buf.PutFloat( src.w ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, Quaternion &dest ) +{ + if ( buf.IsText() ) + { + // FIXME: Print this in a way that we never lose precision + int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w ); + return (nRetVal == 4) && buf.IsValid(); + } + + dest.x = buf.GetFloat( ); + dest.y = buf.GetFloat( ); + dest.z = buf.GetFloat( ); + dest.w = buf.GetFloat( ); + return buf.IsValid(); +} + +bool Serialize( CUtlBuffer &buf, const VMatrix &src ) +{ + if ( buf.IsText() ) + { + buf.Printf( "\n" ); + SerializeFloats( buf, 4, src[0] ); + buf.Printf( "\n" ); + SerializeFloats( buf, 4, src[1] ); + buf.Printf( "\n" ); + SerializeFloats( buf, 4, src[2] ); + buf.Printf( "\n" ); + SerializeFloats( buf, 4, src[3] ); + buf.Printf( "\n" ); + } + else + { + buf.Put( &src, sizeof(VMatrix) ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, VMatrix &dest ) +{ + if ( !buf.IsValid() ) + return false; + + if ( buf.IsText() ) + { + int nRetVal = buf.Scanf( "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", + &dest[ 0 ][ 0 ], &dest[ 0 ][ 1 ], &dest[ 0 ][ 2 ], &dest[ 0 ][ 3 ], + &dest[ 1 ][ 0 ], &dest[ 1 ][ 1 ], &dest[ 1 ][ 2 ], &dest[ 1 ][ 3 ], + &dest[ 2 ][ 0 ], &dest[ 2 ][ 1 ], &dest[ 2 ][ 2 ], &dest[ 2 ][ 3 ], + &dest[ 3 ][ 0 ], &dest[ 3 ][ 1 ], &dest[ 3 ][ 2 ], &dest[ 3 ][ 3 ] ); + return (nRetVal == 16); + } + + buf.Get( &dest, sizeof(VMatrix) ); + return true; +} + + +//----------------------------------------------------------------------------- +// Color attribute +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const Color &src ) +{ + if ( buf.IsText() ) + { + buf.Printf( "%d %d %d %d", src[0], src[1], src[2], src[3] ); + } + else + { + buf.PutUnsignedChar( src[0] ); + buf.PutUnsignedChar( src[1] ); + buf.PutUnsignedChar( src[2] ); + buf.PutUnsignedChar( src[3] ); + } + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, Color &dest ) +{ + if ( buf.IsText() ) + { + int r = 0, g = 0, b = 0, a = 255; + int nRetVal = buf.Scanf( "%d %d %d %d", &r, &g, &b, &a ); + dest.SetColor( r, g, b, a ); + return (nRetVal == 4) && buf.IsValid(); + } + + dest[0] = buf.GetUnsignedChar( ); + dest[1] = buf.GetUnsignedChar( ); + dest[2] = buf.GetUnsignedChar( ); + dest[3] = buf.GetUnsignedChar( ); + return buf.IsValid(); +} + +/* +//----------------------------------------------------------------------------- +// Object ID attribute +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const DmObjectId_t &src ) +{ + return g_pDataModel->Serialize( buf, src ); +} + +bool Unserialize( CUtlBuffer &buf, DmObjectId_t &dest ) +{ + return g_pDataModel->Unserialize( buf, &dest ); +} +*/ + +//----------------------------------------------------------------------------- +// Binary buffer attribute +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src ) +{ + int nLength = src.Length(); + if ( !buf.IsText() ) + { + buf.PutInt( nLength ); + if ( nLength != 0 ) + { + buf.Put( src.Get(), nLength ); + } + return buf.IsValid(); + } + + // Writes out uuencoded binaries + for ( int i = 0; i < nLength; ++i ) + { + if ( (i % 40) == 0 ) + { + buf.PutChar( '\n' ); + } + + char b1 = src[i] & 0xF; + char b2 = src[i] >> 4; + + char c1 = ( b1 <= 9 ) ? b1 + '0' : b1 - 10 + 'A'; + char c2 = ( b2 <= 9 ) ? b2 + '0' : b2 - 10 + 'A'; + + buf.PutChar( c2 ); + buf.PutChar( c1 ); + } + + buf.PutChar( '\n' ); + return buf.IsValid(); +} + +static int CountBinaryBytes( CUtlBuffer &buf, int *pEndGet ) +{ + // This counts the number of bytes in the uuencoded text + int nStartGet = buf.TellGet(); + buf.EatWhiteSpace(); + *pEndGet = buf.TellGet(); + int nByteCount = 0; + while ( buf.IsValid() ) + { + char c1 = buf.GetChar(); + char c2 = buf.GetChar(); + + bool bIsNum1 = ( c1 >= '0' ) && ( c1 <= '9' ); + bool bIsNum2 = ( c2 >= '0' ) && ( c2 <= '9' ); + + bool bIsAlpha1 = (( c1 >= 'A' ) && ( c1 <= 'F' )) || (( c1 >= 'a' ) && ( c1 <= 'f' )); + bool bIsAlpha2 = (( c2 >= 'A' ) && ( c2 <= 'F' )) || (( c2 >= 'a' ) && ( c2 <= 'f' )); + + if ( !(bIsNum1 || bIsAlpha1) || !(bIsNum2 || bIsAlpha2) ) + break; + + buf.EatWhiteSpace(); + *pEndGet = buf.TellGet(); + ++nByteCount; + } + buf.SeekGet( CUtlBuffer::SEEK_HEAD, nStartGet ); + return nByteCount; +} + +inline static unsigned char HexCharToInt( int c1 ) +{ + if (( c1 >= '0' ) && ( c1 <= '9' )) + return c1 - '0'; + + if (( c1 >= 'A' ) && ( c1 <= 'F' )) + return 10 + c1 - 'A'; + + if (( c1 >= 'a' ) && ( c1 <= 'f' )) + return 10 + c1 - 'a'; + + return 0xFF; +} + +bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest ) +{ + if ( !buf.IsText() ) + { + int nLen = buf.GetInt( ); + dest.SetLength( nLen ); + if ( dest.Length() != 0 ) + { + buf.Get( dest.Get(), dest.Length() ); + } + + if ( nLen != dest.Length() ) + { + buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLen - dest.Length() ); + return false; + } + + return buf.IsValid(); + } + + int nEndGet; + int nByteCount = CountBinaryBytes( buf, &nEndGet ); + if ( nByteCount < 0 ) + return false; + + buf.EatWhiteSpace(); + int nDest = 0; + dest.SetLength( nByteCount ); + while( buf.TellGet() < nEndGet ) + { + char c1 = buf.GetChar(); + char c2 = buf.GetChar(); + + unsigned char b1 = HexCharToInt( c1 ); + unsigned char b2 = HexCharToInt( c2 ); + if ( b1 == 0xFF || b2 == 0xFF ) + return false; + + dest[ nDest++ ] = b2 | ( b1 << 4 ); + buf.EatWhiteSpace(); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// String attribute +//----------------------------------------------------------------------------- +bool Serialize( CUtlBuffer &buf, const CUtlString &src ) +{ + buf.PutDelimitedString( s_pConv, src.Get() ); + return buf.IsValid(); +} + +bool Unserialize( CUtlBuffer &buf, CUtlString &dest ) +{ + int nLen = buf.PeekDelimitedStringLength( s_pConv ); + dest.SetLength( nLen - 1 ); // -1 because the length returned includes space for \0 + buf.GetDelimitedString( s_pConv, dest.GetForModify(), nLen ); + return buf.IsValid(); +} + + + + diff --git a/tier1/utlstring.cpp b/tier1/utlstring.cpp new file mode 100644 index 0000000..570aab8 --- /dev/null +++ b/tier1/utlstring.cpp @@ -0,0 +1,767 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#define __STDC_LIMIT_MACROS +#include + +#include "tier1/utlstring.h" +#include "tier1/strtools.h" +#include + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Simple string class. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Either allocates or reallocates memory to the length +// +// Allocated space for length characters. It automatically adds space for the +// nul and the cached length at the start of the memory block. Will adjust +// m_pString and explicitly set the nul at the end before returning. +void *CUtlString::AllocMemory( uint32 length ) +{ + void *pMemoryBlock; + if ( m_pString ) + { + pMemoryBlock = realloc( m_pString, length + 1 ); + } + else + { + pMemoryBlock = malloc( length + 1 ); + } + m_pString = (char*)pMemoryBlock; + m_pString[ length ] = 0; + + return pMemoryBlock; +} + +//----------------------------------------------------------------------------- +void CUtlString::SetDirect( const char *pValue, int nChars ) +{ + if ( pValue && nChars > 0 ) + { + if ( pValue == m_pString ) + { + AssertMsg( nChars == Q_strlen(m_pString), "CUtlString::SetDirect does not support resizing strings in place." ); + return; // Do nothing. Realloc in AllocMemory might move pValue's location resulting in a bad memcpy. + } + + Assert( nChars <= Min( strnlen(pValue, nChars) + 1, nChars ) ); + AllocMemory( nChars ); + Q_memcpy( m_pString, pValue, nChars ); + } + else + { + Purge(); + } + +} + + +void CUtlString::Set( const char *pValue ) +{ + int length = pValue ? V_strlen( pValue ) : 0; + SetDirect( pValue, length ); +} + +// Sets the length (used to serialize into the buffer ) +void CUtlString::SetLength( int nLen ) +{ + if ( nLen > 0 ) + { +#ifdef _DEBUG + int prevLen = m_pString ? Length() : 0; +#endif + AllocMemory( nLen ); +#ifdef _DEBUG + if ( nLen > prevLen ) + { + V_memset( m_pString + prevLen, 0xEB, nLen - prevLen ); + } +#endif + } + else + { + Purge(); + } +} + +const char *CUtlString::Get( ) const +{ + if (!m_pString) + { + return ""; + } + return m_pString; +} + +char *CUtlString::GetForModify() +{ + if ( !m_pString ) + { + // In general, we optimise away small mallocs for empty strings + // but if you ask for the non-const bytes, they must be writable + // so we can't return "" here, like we do for the const version - jd + void *pMemoryBlock = malloc( 1 ); + m_pString = (char *)pMemoryBlock; + *m_pString = 0; + } + + return m_pString; +} + +char CUtlString::operator[]( int i ) const +{ + if ( !m_pString ) + return '\0'; + + if ( i >= Length() ) + { + return '\0'; + } + + return m_pString[i]; +} + +void CUtlString::Clear() +{ + Purge(); +} + +void CUtlString::Purge() +{ + free( m_pString ); + m_pString = NULL; +} + +bool CUtlString::IsEqual_CaseSensitive( const char *src ) const +{ + if ( !src ) + { + return (Length() == 0); + } + return ( V_strcmp( Get(), src ) == 0 ); +} + +bool CUtlString::IsEqual_CaseInsensitive( const char *src ) const +{ + if ( !src ) + { + return (Length() == 0); + } + return ( V_stricmp( Get(), src ) == 0 ); +} + + +void CUtlString::ToLower() +{ + if ( !m_pString ) + { + return; + } + + V_strlower( m_pString ); +} + +void CUtlString::ToUpper() +{ + if ( !m_pString ) + { + return; + } + + V_strupr( m_pString ); +} + +CUtlString &CUtlString::operator=( const CUtlString &src ) +{ + SetDirect( src.Get(), src.Length() ); + return *this; +} + +CUtlString &CUtlString::operator=( const char *src ) +{ + Set( src ); + return *this; +} + +bool CUtlString::operator==( const CUtlString &src ) const +{ + if ( IsEmpty() ) + { + if ( src.IsEmpty() ) + { + return true; + } + + return false; + } + else + { + if ( src.IsEmpty() ) + { + return false; + } + + return Q_strcmp( m_pString, src.m_pString ) == 0; + } +} + +CUtlString &CUtlString::operator+=( const CUtlString &rhs ) +{ + const int lhsLength( Length() ); + const int rhsLength( rhs.Length() ); + + if (!rhsLength) + { + return *this; + } + + const int requestedLength( lhsLength + rhsLength ); + + AllocMemory( requestedLength ); + Q_memcpy( m_pString + lhsLength, rhs.m_pString, rhsLength ); + + return *this; +} + +CUtlString &CUtlString::operator+=( const char *rhs ) +{ + const int lhsLength( Length() ); + const int rhsLength( V_strlen( rhs ) ); + const int requestedLength( lhsLength + rhsLength ); + + if (!requestedLength) + { + return *this; + } + + AllocMemory( requestedLength ); + Q_memcpy( m_pString + lhsLength, rhs, rhsLength ); + + return *this; +} + +CUtlString &CUtlString::operator+=( char c ) +{ + const int lhsLength( Length() ); + + AllocMemory( lhsLength + 1 ); + m_pString[ lhsLength ] = c; + + return *this; +} + +CUtlString &CUtlString::operator+=( int rhs ) +{ + Assert( sizeof( rhs ) == 4 ); + + char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ] + V_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs ); + tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0'; + + return operator+=( tmpBuf ); +} + +CUtlString &CUtlString::operator+=( double rhs ) +{ + char tmpBuf[ 256 ]; // How big can doubles be??? Dunno. + V_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs ); + tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0'; + + return operator+=( tmpBuf ); +} + +bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags ) const +{ + const char *pszSource = String(); + const char *pszPattern = Pattern.String(); + bool bExact = true; + + while( 1 ) + { + if ( ( *pszPattern ) == 0 ) + { + return ( (*pszSource ) == 0 ); + } + + if ( ( *pszPattern ) == '*' ) + { + pszPattern++; + + if ( ( *pszPattern ) == 0 ) + { + return true; + } + + bExact = false; + continue; + } + + int nLength = 0; + + while( ( *pszPattern ) != '*' && ( *pszPattern ) != 0 ) + { + nLength++; + pszPattern++; + } + + while( 1 ) + { + const char *pszStartPattern = pszPattern - nLength; + const char *pszSearch = pszSource; + + for( int i = 0; i < nLength; i++, pszSearch++, pszStartPattern++ ) + { + if ( ( *pszSearch ) == 0 ) + { + return false; + } + + if ( ( *pszSearch ) != ( *pszStartPattern ) ) + { + break; + } + } + + if ( pszSearch - pszSource == nLength ) + { + break; + } + + if ( bExact == true ) + { + return false; + } + + if ( ( nFlags & PATTERN_DIRECTORY ) != 0 ) + { + if ( ( *pszPattern ) != '/' && ( *pszSource ) == '/' ) + { + return false; + } + } + + pszSource++; + } + + pszSource += nLength; + } +} + + +int CUtlString::Format( const char *pFormat, ... ) +{ + va_list marker; + + va_start( marker, pFormat ); + int len = FormatV( pFormat, marker ); + va_end( marker ); + + return len; +} + +//-------------------------------------------------------------------------------------------------- +// This can be called from functions that take varargs. +//-------------------------------------------------------------------------------------------------- + +int CUtlString::FormatV( const char *pFormat, va_list marker ) +{ + char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer + + //va_start( marker, pFormat ); + int len = V_vsprintf_safe( tmpBuf, pFormat, marker ); + //va_end( marker ); + Set( tmpBuf ); + return len; +} + +//----------------------------------------------------------------------------- +// Strips the trailing slash +//----------------------------------------------------------------------------- +void CUtlString::StripTrailingSlash() +{ + if ( IsEmpty() ) + return; + + int nLastChar = Length() - 1; + char c = m_pString[ nLastChar ]; + if ( c == '\\' || c == '/' ) + { + SetLength( nLastChar ); + } +} + +void CUtlString::FixSlashes( char cSeparator/*=CORRECT_PATH_SEPARATOR*/ ) +{ + if ( m_pString ) + { + V_FixSlashes( m_pString, cSeparator ); + } +} + +//----------------------------------------------------------------------------- +// Trim functions +//----------------------------------------------------------------------------- +void CUtlString::TrimLeft( char cTarget ) +{ + int nIndex = 0; + + if ( IsEmpty() ) + { + return; + } + + while( m_pString[nIndex] == cTarget ) + { + ++nIndex; + } + + // We have some whitespace to remove + if ( nIndex > 0 ) + { + memcpy( m_pString, &m_pString[nIndex], Length() - nIndex ); + SetLength( Length() - nIndex ); + } +} + + +void CUtlString::TrimLeft( const char *szTargets ) +{ + int i; + + if ( IsEmpty() ) + { + return; + } + + for( i = 0; m_pString[i] != 0; i++ ) + { + bool bWhitespace = false; + + for( int j = 0; szTargets[j] != 0; j++ ) + { + if ( m_pString[i] == szTargets[j] ) + { + bWhitespace = true; + break; + } + } + + if ( !bWhitespace ) + { + break; + } + } + + // We have some whitespace to remove + if ( i > 0 ) + { + memcpy( m_pString, &m_pString[i], Length() - i ); + SetLength( Length() - i ); + } +} + + +void CUtlString::TrimRight( char cTarget ) +{ + const int nLastCharIndex = Length() - 1; + int nIndex = nLastCharIndex; + + while ( nIndex >= 0 && m_pString[nIndex] == cTarget ) + { + --nIndex; + } + + // We have some whitespace to remove + if ( nIndex < nLastCharIndex ) + { + m_pString[nIndex + 1] = 0; + SetLength( nIndex + 2 ); + } +} + + +void CUtlString::TrimRight( const char *szTargets ) +{ + const int nLastCharIndex = Length() - 1; + int i; + + for( i = nLastCharIndex; i > 0; i-- ) + { + bool bWhitespace = false; + + for( int j = 0; szTargets[j] != 0; j++ ) + { + if ( m_pString[i] == szTargets[j] ) + { + bWhitespace = true; + break; + } + } + + if ( !bWhitespace ) + { + break; + } + } + + // We have some whitespace to remove + if ( i < nLastCharIndex ) + { + m_pString[i + 1] = 0; + SetLength( i + 2 ); + } +} + + +void CUtlString::Trim( char cTarget ) +{ + TrimLeft( cTarget ); + TrimRight( cTarget ); +} + + +void CUtlString::Trim( const char *szTargets ) +{ + TrimLeft( szTargets ); + TrimRight( szTargets ); +} + + +CUtlString CUtlString::Slice( int32 nStart, int32 nEnd ) const +{ + int length = Length(); + if ( length == 0 ) + { + return CUtlString(); + } + + if ( nStart < 0 ) + nStart = length - (-nStart % length); + else if ( nStart >= length ) + nStart = length; + + if ( nEnd == INT32_MAX ) + nEnd = length; + else if ( nEnd < 0 ) + nEnd = length - (-nEnd % length); + else if ( nEnd >= length ) + nEnd = length; + + if ( nStart >= nEnd ) + return CUtlString(); + + const char *pIn = String(); + + CUtlString ret; + ret.SetDirect( pIn + nStart, nEnd - nStart ); + return ret; +} + +// Grab a substring starting from the left or the right side. +CUtlString CUtlString::Left( int32 nChars ) const +{ + return Slice( 0, nChars ); +} + +CUtlString CUtlString::Right( int32 nChars ) const +{ + return Slice( -nChars ); +} + +CUtlString CUtlString::Replace( char cFrom, char cTo ) const +{ + if (!m_pString) + { + return CUtlString(); + } + + CUtlString ret = *this; + int len = ret.Length(); + for ( int i=0; i < len; i++ ) + { + if ( ret.m_pString[i] == cFrom ) + ret.m_pString[i] = cTo; + } + + return ret; +} + +CUtlString CUtlString::Replace( const char *pszFrom, const char *pszTo ) const +{ + Assert( pszTo ); // Can be 0 length, but not null + Assert( pszFrom && *pszFrom ); // Must be valid and have one character. + + + const char *pos = V_strstr( String(), pszFrom ); + if ( !pos ) + { + return *this; + } + + const char *pFirstFound = pos; + + // count number of search string + int nSearchCount = 0; + int nSearchLength = V_strlen( pszFrom ); + while ( pos ) + { + nSearchCount++; + int nSrcOffset = ( pos - String() ) + nSearchLength; + pos = V_strstr( String() + nSrcOffset, pszFrom ); + } + + // allocate the new string + int nReplaceLength = V_strlen( pszTo ); + int nAllocOffset = nSearchCount * ( nReplaceLength - nSearchLength ); + size_t srcLength = Length(); + CUtlString strDest; + size_t destLength = srcLength + nAllocOffset; + strDest.SetLength( destLength ); + + // find and replace the search string + pos = pFirstFound; + int nDestOffset = 0; + int nSrcOffset = 0; + while ( pos ) + { + // Found an instance + int nCurrentSearchOffset = pos - String(); + int nCopyLength = nCurrentSearchOffset - nSrcOffset; + V_strncpy( strDest.GetForModify() + nDestOffset, String() + nSrcOffset, nCopyLength + 1 ); + nDestOffset += nCopyLength; + V_strncpy( strDest.GetForModify() + nDestOffset, pszTo, nReplaceLength + 1 ); + nDestOffset += nReplaceLength; + + nSrcOffset = nCurrentSearchOffset + nSearchLength; + pos = V_strstr( String() + nSrcOffset, pszFrom ); + } + + // making sure that the left over string from the source is the same size as the left over dest buffer + Assert( destLength - nDestOffset == srcLength - nSrcOffset ); + if ( destLength - nDestOffset > 0 ) + { + V_strncpy( strDest.GetForModify() + nDestOffset, String() + nSrcOffset, destLength - nDestOffset + 1 ); + } + + return strDest; +} + +CUtlString CUtlString::AbsPath( const char *pStartingDir ) const +{ + char szNew[MAX_PATH]; + V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir ); + return CUtlString( szNew ); +} + +CUtlString CUtlString::UnqualifiedFilename() const +{ + const char *pFilename = V_UnqualifiedFileName( this->String() ); + return CUtlString( pFilename ); +} + +CUtlString CUtlString::DirName() const +{ + CUtlString ret( this->String() ); + V_StripLastDir( (char*)ret.Get(), ret.Length() + 1 ); + V_StripTrailingSlash( (char*)ret.Get() ); + return ret; +} + +CUtlString CUtlString::StripExtension() const +{ + char szTemp[MAX_PATH]; + V_StripExtension( String(), szTemp, sizeof( szTemp ) ); + return CUtlString( szTemp ); +} + +CUtlString CUtlString::StripFilename() const +{ + const char *pFilename = V_UnqualifiedFileName( Get() ); // NOTE: returns 'Get()' on failure, never NULL + int nCharsToCopy = pFilename - Get(); + CUtlString result; + result.SetDirect( Get(), nCharsToCopy ); + result.StripTrailingSlash(); + return result; +} + +CUtlString CUtlString::GetBaseFilename() const +{ + char szTemp[MAX_PATH]; + V_FileBase( String(), szTemp, sizeof( szTemp ) ); + return CUtlString( szTemp ); +} + +CUtlString CUtlString::GetExtension() const +{ + char szTemp[MAX_PATH]; + V_ExtractFileExtension( String(), szTemp, sizeof( szTemp ) ); + return CUtlString( szTemp ); +} + + +CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 ) +{ + char szPath[MAX_PATH]; + V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) ); + return CUtlString( szPath ); +} + +CUtlString CUtlString::operator+( const char *pOther ) const +{ + CUtlString s = *this; + s += pOther; + return s; +} + +CUtlString CUtlString::operator+( const CUtlString &other ) const +{ + CUtlString s = *this; + s += other; + return s; +} + +CUtlString CUtlString::operator+( int rhs ) const +{ + CUtlString ret = *this; + ret += rhs; + return ret; +} + +//----------------------------------------------------------------------------- +// Purpose: concatenate the provided string to our current content +//----------------------------------------------------------------------------- +void CUtlString::Append( const char *pchAddition ) +{ + (*this) += pchAddition; +} + +void CUtlString::Append( const char *pchAddition, int nChars ) +{ + nChars = Min( nChars, V_strlen( pchAddition ) ); + + const int lhsLength( Length() ); + const int rhsLength( nChars ); + const int requestedLength( lhsLength + rhsLength ); + + AllocMemory( requestedLength ); + const int allocatedLength( requestedLength ); + const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength ); + memcpy( GetForModify() + lhsLength, pchAddition, copyLength ); + m_pString[ allocatedLength ] = '\0'; +} + +// Shared static empty string. +const CUtlString &CUtlString::GetEmptyString() +{ + static const CUtlString s_emptyString; + + return s_emptyString; +} diff --git a/tier1/utlsymbol.cpp b/tier1/utlsymbol.cpp new file mode 100644 index 0000000..3cadaaa --- /dev/null +++ b/tier1/utlsymbol.cpp @@ -0,0 +1,436 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines a symbol table +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#pragma warning (disable:4514) + +#include "utlsymbol.h" +#include "KeyValues.h" +#include "tier0/threadtools.h" +#include "tier0/memdbgon.h" +#include "stringpool.h" +#include "utlhashtable.h" +#include "utlstring.h" + +// Ensure that everybody has the right compiler version installed. The version +// number can be obtained by looking at the compiler output when you type 'cl' +// and removing the last two digits and the periods: 16.00.40219.01 becomes 160040219 +#ifdef _MSC_FULL_VER + #if _MSC_FULL_VER > 160000000 + // VS 2010 + #if _MSC_FULL_VER < 160040219 + #error You must install VS 2010 SP1 + #endif + #else + // VS 2005 + #if _MSC_FULL_VER < 140050727 + #error You must install VS 2005 SP1 + #endif + #endif +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define INVALID_STRING_INDEX CStringPoolIndex( 0xFFFF, 0xFFFF ) + +#define MIN_STRING_POOL_SIZE 2048 + +//----------------------------------------------------------------------------- +// globals +//----------------------------------------------------------------------------- + +CUtlSymbolTableMT* CUtlSymbol::s_pSymbolTable = 0; +bool CUtlSymbol::s_bAllowStaticSymbolTable = true; + + +//----------------------------------------------------------------------------- +// symbol methods +//----------------------------------------------------------------------------- + +void CUtlSymbol::Initialize() +{ + // If this assert fails, then the module that this call is in has chosen to disallow + // use of the static symbol table. Usually, it's to prevent confusion because it's easy + // to accidentally use the global symbol table when you really want to use a specific one. + Assert( s_bAllowStaticSymbolTable ); + + // necessary to allow us to create global symbols + static bool symbolsInitialized = false; + if (!symbolsInitialized) + { + s_pSymbolTable = new CUtlSymbolTableMT; + symbolsInitialized = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Singleton to delete table on exit from module +//----------------------------------------------------------------------------- +class CCleanupUtlSymbolTable +{ +public: + ~CCleanupUtlSymbolTable() + { + delete CUtlSymbol::s_pSymbolTable; + CUtlSymbol::s_pSymbolTable = NULL; + } +}; + +static CCleanupUtlSymbolTable g_CleanupSymbolTable; + +CUtlSymbolTableMT* CUtlSymbol::CurrTable() +{ + Initialize(); + return s_pSymbolTable; +} + + +//----------------------------------------------------------------------------- +// string->symbol->string +//----------------------------------------------------------------------------- + +CUtlSymbol::CUtlSymbol( const char* pStr ) +{ + m_Id = CurrTable()->AddString( pStr ); +} + +const char* CUtlSymbol::String( ) const +{ + return CurrTable()->String(m_Id); +} + +void CUtlSymbol::DisableStaticSymbolTable() +{ + s_bAllowStaticSymbolTable = false; +} + +//----------------------------------------------------------------------------- +// checks if the symbol matches a string +//----------------------------------------------------------------------------- + +bool CUtlSymbol::operator==( const char* pStr ) const +{ + if (m_Id == UTL_INVAL_SYMBOL) + return false; + return strcmp( String(), pStr ) == 0; +} + + + +//----------------------------------------------------------------------------- +// symbol table stuff +//----------------------------------------------------------------------------- + +inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const +{ + Assert( index.m_iPool < m_StringPools.Count() ); + Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen ); + + return &m_StringPools[index.m_iPool]->m_Data[index.m_iOffset]; +} + + +bool CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStringPoolIndex &i2 ) const +{ + // Need to do pointer math because CUtlSymbolTable is used in CUtlVectors, and hence + // can be arbitrarily moved in memory on a realloc. Yes, this is portable. In reality, + // right now at least, because m_LessFunc is the first member of CUtlRBTree, and m_Lookup + // is the first member of CUtlSymbolTabke, this == pTable + CUtlSymbolTable *pTable = (CUtlSymbolTable *)( (byte *)this - offsetof(CUtlSymbolTable::CTree, m_LessFunc) ) - offsetof(CUtlSymbolTable, m_Lookup ); + const char* str1 = (i1 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString : + pTable->StringFromIndex( i1 ); + const char* str2 = (i2 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString : + pTable->StringFromIndex( i2 ); + + if ( !str1 && str2 ) + return false; + if ( !str2 && str1 ) + return true; + if ( !str1 && !str2 ) + return false; + if ( !pTable->m_bInsensitive ) + return V_strcmp( str1, str2 ) < 0; + else + return V_stricmp( str1, str2 ) < 0; +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CUtlSymbolTable::CUtlSymbolTable( int growSize, int initSize, bool caseInsensitive ) : + m_Lookup( growSize, initSize ), m_bInsensitive( caseInsensitive ), m_StringPools( 8 ) +{ +} + +CUtlSymbolTable::~CUtlSymbolTable() +{ + // Release the stringpool string data + RemoveAll(); +} + + +CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const +{ + if (!pString) + return CUtlSymbol(); + + // Store a special context used to help with insertion + m_pUserSearchString = pString; + + // Passing this special invalid symbol makes the comparison function + // use the string passed in the context + UtlSymId_t idx = m_Lookup.Find( INVALID_STRING_INDEX ); + +#ifdef _DEBUG + m_pUserSearchString = NULL; +#endif + + return CUtlSymbol( idx ); +} + + +int CUtlSymbolTable::FindPoolWithSpace( int len ) const +{ + for ( int i=0; i < m_StringPools.Count(); i++ ) + { + StringPool_t *pPool = m_StringPools[i]; + + if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len ) + { + return i; + } + } + + return -1; +} + + +//----------------------------------------------------------------------------- +// Finds and/or creates a symbol based on the string +//----------------------------------------------------------------------------- + +CUtlSymbol CUtlSymbolTable::AddString( const char* pString ) +{ + if (!pString) + return CUtlSymbol( UTL_INVAL_SYMBOL ); + + CUtlSymbol id = Find( pString ); + + if (id.IsValid()) + return id; + + int len = V_strlen(pString) + 1; + + // Find a pool with space for this string, or allocate a new one. + int iPool = FindPoolWithSpace( len ); + if ( iPool == -1 ) + { + // Add a new pool. + int newPoolSize = vmax( len, MIN_STRING_POOL_SIZE ); + StringPool_t *pPool = (StringPool_t*)malloc( sizeof( StringPool_t ) + newPoolSize - 1 ); + pPool->m_TotalLen = newPoolSize; + pPool->m_SpaceUsed = 0; + iPool = m_StringPools.AddToTail( pPool ); + } + + // Copy the string in. + StringPool_t *pPool = m_StringPools[iPool]; + Assert( pPool->m_SpaceUsed < 0xFFFF ); // This should never happen, because if we had a string > 64k, it + // would have been given its entire own pool. + + unsigned short iStringOffset = pPool->m_SpaceUsed; + + memcpy( &pPool->m_Data[pPool->m_SpaceUsed], pString, len ); + pPool->m_SpaceUsed += len; + + // didn't find, insert the string into the vector. + CStringPoolIndex index; + index.m_iPool = iPool; + index.m_iOffset = iStringOffset; + + UtlSymId_t idx = m_Lookup.Insert( index ); + return CUtlSymbol( idx ); +} + + +//----------------------------------------------------------------------------- +// Look up the string associated with a particular symbol +//----------------------------------------------------------------------------- + +const char* CUtlSymbolTable::String( CUtlSymbol id ) const +{ + if (!id.IsValid()) + return ""; + + Assert( m_Lookup.IsValidIndex((UtlSymId_t)id) ); + return StringFromIndex( m_Lookup[id] ); +} + + +//----------------------------------------------------------------------------- +// Remove all symbols in the table. +//----------------------------------------------------------------------------- + +void CUtlSymbolTable::RemoveAll() +{ + m_Lookup.Purge(); + + for ( int i=0; i < m_StringPools.Count(); i++ ) + free( m_StringPools[i] ); + + m_StringPools.RemoveAll(); +} + + + +class CUtlFilenameSymbolTable::HashTable : public CUtlStableHashtable +{ +}; + +CUtlFilenameSymbolTable::CUtlFilenameSymbolTable() +{ + m_Strings = new HashTable; +} + +CUtlFilenameSymbolTable::~CUtlFilenameSymbolTable() +{ + delete m_Strings; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pFileName - +// Output : FileNameHandle_t +//----------------------------------------------------------------------------- +FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileName ) +{ + if ( !pFileName ) + { + return NULL; + } + + // find first + FileNameHandle_t hFileName = FindFileName( pFileName ); + if ( hFileName ) + { + return hFileName; + } + + // Fix slashes+dotslashes and make lower case first.. + char fn[ MAX_PATH ]; + Q_strncpy( fn, pFileName, sizeof( fn ) ); + Q_RemoveDotSlashes( fn ); +#ifdef _WIN32 + Q_strlower( fn ); +#endif + + // Split the filename into constituent parts + char basepath[ MAX_PATH ]; + Q_ExtractFilePath( fn, basepath, sizeof( basepath ) ); + char filename[ MAX_PATH ]; + Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) ); + + // not found, lock and look again + FileNameHandleInternal_t handle; + m_lock.LockForWrite(); + handle.path = m_Strings->Insert( basepath ) + 1; + handle.file = m_Strings->Insert( filename ) + 1; + //handle.path = m_StringPool.FindStringHandle( basepath ); + //handle.file = m_StringPool.FindStringHandle( filename ); + //if ( handle.path != m_Strings.InvalidHandle() && handle.file ) + //{ + // found + // m_lock.UnlockWrite(); + // return *( FileNameHandle_t * )( &handle ); + //} + + // safely add it + //handle.path = m_StringPool.ReferenceStringHandle( basepath ); + //handle.file = m_StringPool.ReferenceStringHandle( filename ); + m_lock.UnlockWrite(); + + return *( FileNameHandle_t * )( &handle ); +} + +FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName ) +{ + if ( !pFileName ) + { + return NULL; + } + + // Fix slashes+dotslashes and make lower case first.. + char fn[ MAX_PATH ]; + Q_strncpy( fn, pFileName, sizeof( fn ) ); + Q_RemoveDotSlashes( fn ); +#ifdef _WIN32 + Q_strlower( fn ); +#endif + + // Split the filename into constituent parts + char basepath[ MAX_PATH ]; + Q_ExtractFilePath( fn, basepath, sizeof( basepath ) ); + char filename[ MAX_PATH ]; + Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) ); + + FileNameHandleInternal_t handle; + + Assert( (uint16)(m_Strings->InvalidHandle() + 1) == 0 ); + + m_lock.LockForRead(); + handle.path = m_Strings->Find(basepath) + 1; + handle.file = m_Strings->Find(filename) + 1; + //handle.path = m_StringPool.FindStringHandle(basepath); + //handle.file = m_StringPool.FindStringHandle(filename); + m_lock.UnlockRead(); + + if ( handle.path == 0 || handle.file == 0 ) + return NULL; + + return *( FileNameHandle_t * )( &handle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : handle - +// Output : const char +//----------------------------------------------------------------------------- +bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, int buflen ) +{ + buf[ 0 ] = 0; + + FileNameHandleInternal_t *internal = ( FileNameHandleInternal_t * )&handle; + if ( !internal || !internal->file || !internal->path ) + { + return false; + } + + m_lock.LockForRead(); + //const char *path = m_StringPool.HandleToString(internal->path); + //const char *fn = m_StringPool.HandleToString(internal->file); + const char *path = (*m_Strings)[ internal->path - 1 ].Get(); + const char *fn = (*m_Strings)[ internal->file - 1].Get(); + m_lock.UnlockRead(); + + if ( !path || !fn ) + { + return false; + } + + Q_strncpy( buf, path, buflen ); + Q_strncat( buf, fn, buflen, COPY_ALL_CHARACTERS ); + + return true; +} + +void CUtlFilenameSymbolTable::RemoveAll() +{ + m_Strings->Purge(); +} diff --git a/utils/common/ISQLDBReplyTarget.h b/utils/common/ISQLDBReplyTarget.h new file mode 100644 index 0000000..9049a5c --- /dev/null +++ b/utils/common/ISQLDBReplyTarget.h @@ -0,0 +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 diff --git a/utils/common/MySqlDatabase.cpp b/utils/common/MySqlDatabase.cpp new file mode 100644 index 0000000..2558ba0 --- /dev/null +++ b/utils/common/MySqlDatabase.cpp @@ -0,0 +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(); +} diff --git a/utils/common/MySqlDatabase.h b/utils/common/MySqlDatabase.h new file mode 100644 index 0000000..52517f6 --- /dev/null +++ b/utils/common/MySqlDatabase.h @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef MYSQLDATABASE_H +#define MYSQLDATABASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#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 m_InQueue; + CUtlLinkedList 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/utils/common/bsplib.cpp b/utils/common/bsplib.cpp new file mode 100644 index 0000000..cadf7af --- /dev/null +++ b/utils/common/bsplib.cpp @@ -0,0 +1,5245 @@ +//========= 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" +#include "lzma/lzma.h" +#include "tier1/lzmaDecoder.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_FIELD( uncompressedSize, FIELD_INTEGER ), +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 dlightdataHDR; +CUtlVector dlightdataLDR; +CUtlVector *pdlightdata = &dlightdataLDR; + +CUtlVector dentdata; + +int numleafs; +#if !defined( BSP_USE_LESS_MEMORY ) +dleaf_t dleafs[MAX_MAP_LEAFS]; +#else +dleaf_t *dleafs; +#endif + +CUtlVector g_LeafAmbientIndexLDR; +CUtlVector g_LeafAmbientIndexHDR; +CUtlVector *g_pLeafAmbientIndex = NULL; +CUtlVector g_LeafAmbientLightingLDR; +CUtlVector g_LeafAmbientLightingHDR; +CUtlVector *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( MAX_MAP_TEXINFO ); + +int numtexdata; +dtexdata_t dtexdata[MAX_MAP_TEXDATA]; + +// +// displacement map bsp file info: dispinfo +// +CUtlVector g_dispinfo; +CUtlVector g_DispVerts; +CUtlVector g_DispTris; +CUtlVector 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 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 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 g_TexDataStringData; +CUtlVector g_TexDataStringTable; + +byte *g_pPhysCollide = NULL; +int g_PhysCollideSize = 0; +int g_MapRevision = 0; + +byte *g_pPhysDisp = NULL; +int g_PhysDispSize = 0; + +CUtlVector g_OccluderData( 256, 256 ); +CUtlVector g_OccluderPolyData( 1024, 1024 ); +CUtlVector g_OccluderVertexIndices( 2048, 2048 ); + +template static void WriteData( T *pData, int count = 1 ); +template 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 &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, IZip::eCompressionType compressionType ) +{ + DevMsg( "Adding file to pakfile [ %s ]\n", fullpath ); + pak->AddFileToZip( relativename, fullpath, compressionType ); +} + +//----------------------------------------------------------------------------- +// 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, IZip::eCompressionType compressionType ) +{ + pak->AddBufferToZip( pRelativeName, data, length, bTextMode, compressionType ); +} + +//----------------------------------------------------------------------------- +// Purpose: Add entire directory to .bsp PAK lump as named file +// Input : *relativename - +// *data - +// length - +//----------------------------------------------------------------------------- +void AddDirToPak( IZip *pak, const char *pDirPath, const char *pPakPrefix ) +{ + if ( !g_pFullFileSystem->IsDirectory( pDirPath ) ) + { + Warning( "Passed non-directory to AddDirToPak [ %s ]\n", pDirPath ); + return; + } + + DevMsg( "Adding directory to pakfile [ %s ]\n", pDirPath ); + + // Enumerate dir + char szEnumerateDir[MAX_PATH] = { 0 }; + V_snprintf( szEnumerateDir, sizeof( szEnumerateDir ), "%s/*.*", pDirPath ); + V_FixSlashes( szEnumerateDir ); + + FileFindHandle_t handle; + const char *szFindResult = g_pFullFileSystem->FindFirst( szEnumerateDir, &handle ); + do + { + if ( szFindResult[0] != '.' ) + { + char szPakName[MAX_PATH] = { 0 }; + char szFullPath[MAX_PATH] = { 0 }; + if ( pPakPrefix ) + { + V_snprintf( szPakName, sizeof( szPakName ), "%s/%s", pPakPrefix, szFindResult ); + } + else + { + V_strncpy( szPakName, szFindResult, sizeof( szPakName ) ); + } + V_snprintf( szFullPath, sizeof( szFullPath ), "%s/%s", pDirPath, szFindResult ); + V_FixDoubleSlashes( szFullPath ); + V_FixDoubleSlashes( szPakName ); + + if ( g_pFullFileSystem->FindIsDirectory( handle ) ) + { + // Recurse + AddDirToPak( pak, szFullPath, szPakName ); + } + else + { + // Just add this file + AddFileToPak( pak, szPakName, szFullPath ); + } + } + szFindResult = g_pFullFileSystem->FindNext( handle ); + } while ( szFindResult); +} + +//----------------------------------------------------------------------------- +// 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->uncompressedSize = 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>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 &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 &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( 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 &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 &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( 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( 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( FIELD_CHARACTER, LUMP_PHYSCOLLIDE, (void**)&g_pPhysCollide ); + g_PhysDispSize = CopyVariableLump( 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( 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( 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( 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->uncompressedSize = 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*)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*)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 &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 ; inext) + { + 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 ; inumedges ; 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 ; jnumedges ; 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 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 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*)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*)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, IZip::eCompressionType_None ); + } + 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, IZip::eCompressionType_None ); + } + + 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; iRemoveFileFromZip( 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( 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( 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( 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; ipLump->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); + + if ( IsX360() ) + { + byteSwap.ActivateByteSwapping( true ); + byteSwap.SwapFieldsToTargetEndian( pInGameLumpHeader ); + byteSwap.SwapFieldsToTargetEndian( pInGameLump, pInGameLumpHeader->lumpCount ); + } + + unsigned int newOffset = outputBuffer.TellPut(); + // Make room for gamelump header and gamelump structs, which we'll write at the end + outputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, sizeof( dgamelumpheader_t ) ); + outputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) ); + + // Start with input lumps, and fixup + dgamelumpheader_t sOutGameLumpHeader = *pInGameLumpHeader; + CUtlBuffer sOutGameLumpBuf; + sOutGameLumpBuf.Put( pInGameLump, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) ); + dgamelump_t *sOutGameLump = (dgamelump_t *)sOutGameLumpBuf.Base(); + + // 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 + sOutGameLumpHeader.lumpCount++; + dgamelump_t dummyLump = { 0 }; + outputBuffer.Put( &dummyLump, sizeof( dgamelump_t ) ); + + for ( int i = 0; i < pInGameLumpHeader->lumpCount; i++ ) + { + CUtlBuffer inputBuffer; + CUtlBuffer compressedBuffer; + + sOutGameLump[i].fileofs = AlignBuffer( outputBuffer, 4 ); + + if ( pInGameLump[i].filelen ) + { + if ( pInGameLump[i].flags & GAMELUMPFLAG_COMPRESSED ) + { + byte *pCompressedLump = ((byte *)pInBSPHeader) + pInGameLump[i].fileofs; + if ( CLZMA::IsCompressed( pCompressedLump ) ) + { + inputBuffer.EnsureCapacity( CLZMA::GetActualSize( pCompressedLump ) ); + unsigned int outSize = CLZMA::Uncompress( pCompressedLump, (unsigned char *)inputBuffer.Base() ); + inputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, outSize ); + if ( outSize != CLZMA::GetActualSize( pCompressedLump ) ) + { + Warning( "Decompressed size differs from header, BSP may be corrupt\n" ); + } + } + else + { + Assert( CLZMA::IsCompressed( pCompressedLump ) ); + Warning( "Unsupported BSP: Unrecognized compressed game lump\n" ); + } + + } + else + { + inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pInGameLump[i].fileofs, + pInGameLump[i].filelen, pInGameLump[i].filelen ); + } + + bool bCompressed = pCompressFunc ? pCompressFunc( inputBuffer, compressedBuffer ) : false; + if ( bCompressed ) + { + sOutGameLump[i].flags |= GAMELUMPFLAG_COMPRESSED; + + outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() ); + compressedBuffer.Purge(); + } + else + { + // as is, clear compression flag from input lump + sOutGameLump[i].flags &= ~GAMELUMPFLAG_COMPRESSED; + outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() ); + } + } + } + + // fix the dummy terminal lump + int lastLump = sOutGameLumpHeader.lumpCount-1; + sOutGameLump[lastLump].fileofs = outputBuffer.TellPut(); + + if ( IsX360() ) + { + // fix the output for 360, swapping it back + byteSwap.SwapFieldsToTargetEndian( sOutGameLump, sOutGameLumpHeader.lumpCount ); + byteSwap.SwapFieldsToTargetEndian( &sOutGameLumpHeader ); + } + + pOutBSPHeader->lumps[LUMP_GAME_LUMP].fileofs = newOffset; + pOutBSPHeader->lumps[LUMP_GAME_LUMP].filelen = outputBuffer.TellPut() - newOffset; + // We set GAMELUMPFLAG_COMPRESSED and handle compression at the sub-lump level, this whole lump is not + // decompressable as a block. + pOutBSPHeader->lumps[LUMP_GAME_LUMP].uncompressedSize = 0; + + // Rewind to start and write lump headers + unsigned int endOffset = outputBuffer.TellPut(); + outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, newOffset ); + outputBuffer.Put( &sOutGameLumpHeader, sizeof( dgamelumpheader_t ) ); + outputBuffer.Put( sOutGameLumpBuf.Base(), sOutGameLumpBuf.TellPut() ); + outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, endOffset ); + + return true; +} + +//----------------------------------------------------------------------------- +// Compress callback for RepackBSP +//----------------------------------------------------------------------------- +bool RepackBSPCallback_LZMA( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer ) +{ + if ( !inputBuffer.TellPut() ) + { + // nothing to do + return false; + } + + unsigned int originalSize = inputBuffer.TellPut() - inputBuffer.TellGet(); + unsigned int compressedSize = 0; + unsigned char *pCompressedOutput = LZMA_Compress( (unsigned char *)inputBuffer.Base() + inputBuffer.TellGet(), + originalSize, &compressedSize ); + if ( pCompressedOutput ) + { + outputBuffer.Put( pCompressedOutput, compressedSize ); + DevMsg( "Compressed bsp lump %u -> %u bytes\n", originalSize, compressedSize ); + free( pCompressedOutput ); + return true; + } + + return false; +} + + +bool RepackBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc, IZip::eCompressionType packfileCompression ) +{ + dheader_t *pInBSPHeader = (dheader_t *)inputBuffer.Base(); + // The 360 swaps this header to disk. For some reason. + if ( pInBSPHeader->ident != ( IsX360() ? BigLong( IDBSPHEADER ) : IDBSPHEADER ) ) + { + Warning( "RepackBSP given invalid input data\n" ); + return false; + } + + CByteswap byteSwap; + if ( IsX360() ) + { + // bsp is 360, swap the header back + byteSwap.ActivateByteSwapping( true ); + byteSwap.SwapFieldsToTargetEndian( pInBSPHeader ); + } + + unsigned int headerOffset = outputBuffer.TellPut(); + outputBuffer.Put( pInBSPHeader, sizeof( dheader_t ) ); + + // This buffer grows dynamically, don't keep pointers to it around. Write out header at end. + dheader_t sOutBSPHeader = *pInBSPHeader; + + // 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; + + // Should be set below, don't copy over old data + sOutBSPHeader.lumps[lumpNum].fileofs = 0; + sOutBSPHeader.lumps[lumpNum].filelen = 0; + // Only set by compressed lumps + sOutBSPHeader.lumps[lumpNum].uncompressedSize = 0; + + if ( pSortedLump->pLump->filelen ) // Otherwise its degenerate + { + int alignment = 4; + if ( lumpNum == LUMP_PAKFILE ) + { + alignment = 2048; + } + unsigned int newOffset = AlignBuffer( outputBuffer, alignment ); + + CUtlBuffer inputBuffer; + if ( pSortedLump->pLump->uncompressedSize ) + { + byte *pCompressedLump = ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs; + if ( CLZMA::IsCompressed( pCompressedLump ) && pSortedLump->pLump->uncompressedSize == CLZMA::GetActualSize( pCompressedLump ) ) + { + inputBuffer.EnsureCapacity( CLZMA::GetActualSize( pCompressedLump ) ); + unsigned int outSize = CLZMA::Uncompress( pCompressedLump, (unsigned char *)inputBuffer.Base() ); + inputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, outSize ); + if ( outSize != pSortedLump->pLump->uncompressedSize ) + { + Warning( "Decompressed size differs from header, BSP may be corrupt\n" ); + } + } + else + { + Assert( CLZMA::IsCompressed( pCompressedLump ) && + pSortedLump->pLump->uncompressedSize == CLZMA::GetActualSize( pCompressedLump ) ); + Warning( "Unsupported BSP: Unrecognized compressed lump\n" ); + } + } + else + { + // Just use input + 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, &sOutBSPHeader, outputBuffer, pCompressFunc ); + } + else if ( lumpNum == LUMP_PAKFILE ) + { + IZip *newPakFile = IZip::CreateZip( NULL ); + IZip *oldPakFile = IZip::CreateZip( NULL ); + oldPakFile->ParseFromBuffer( inputBuffer.Base(), inputBuffer.Size() ); + + int id = -1; + int fileSize; + while ( 1 ) + { + char relativeName[MAX_PATH]; + id = GetNextFilename( oldPakFile, id, relativeName, sizeof( relativeName ), fileSize ); + if ( id == -1 ) + break; + + CUtlBuffer sourceBuf; + CUtlBuffer targetBuf; + + bool bOK = ReadFileFromPak( oldPakFile, relativeName, false, sourceBuf ); + if ( !bOK ) + { + Error( "Failed to load '%s' from lump pak for repacking.\n", relativeName ); + continue; + } + + AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false, packfileCompression ); + + DevMsg( "Repacking BSP: Created '%s' in lump pak\n", relativeName ); + } + + // save new pack to buffer + newPakFile->SaveToBuffer( outputBuffer ); + sOutBSPHeader.lumps[lumpNum].fileofs = newOffset; + sOutBSPHeader.lumps[lumpNum].filelen = outputBuffer.TellPut() - newOffset; + // Note that this *lump* is uncompressed, it just contains a packfile that uses compression, so we're + // not setting lumps[lumpNum].uncompressedSize + + IZip::ReleaseZip( oldPakFile ); + IZip::ReleaseZip( newPakFile ); + } + else + { + CUtlBuffer compressedBuffer; + bool bCompressed = pCompressFunc ? pCompressFunc( inputBuffer, compressedBuffer ) : false; + if ( bCompressed ) + { + sOutBSPHeader.lumps[lumpNum].uncompressedSize = inputBuffer.TellPut(); + sOutBSPHeader.lumps[lumpNum].filelen = compressedBuffer.TellPut(); + sOutBSPHeader.lumps[lumpNum].fileofs = newOffset; + outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() ); + compressedBuffer.Purge(); + } + else + { + // add as is + sOutBSPHeader.lumps[lumpNum].fileofs = newOffset; + sOutBSPHeader.lumps[lumpNum].filelen = inputBuffer.TellPut(); + outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() ); + } + } + } + } + + if ( IsX360() ) + { + // fix the output for 360, swapping it back + byteSwap.SetTargetBigEndian( true ); + byteSwap.SwapFieldsToTargetEndian( &sOutBSPHeader ); + } + + // Write out header + unsigned int endOffset = outputBuffer.TellPut(); + outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, headerOffset ); + outputBuffer.Put( &sOutBSPHeader, sizeof( sOutBSPHeader ) ); + outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, endOffset ); + + 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( LUMP_FACES_HDR ) ) + { + g_pBSPHeader->lumps[LUMP_FACES].filelen = 0; + } + else + { + // no HDR, keep LDR version + SwapLumpToDisk( LUMP_FACES ); + } + + if ( SwapLumpToDisk( LUMP_WORLDLIGHTS_HDR ) ) + { + g_pBSPHeader->lumps[LUMP_WORLDLIGHTS].filelen = 0; + } + else + { + // no HDR, keep LDR version + SwapLumpToDisk( LUMP_WORLDLIGHTS ); + } + + // Simple lump swaps + SwapLumpToDisk( FIELD_CHARACTER, LUMP_PHYSDISP ); + SwapLumpToDisk( FIELD_CHARACTER, LUMP_PHYSCOLLIDE ); + SwapLumpToDisk( FIELD_CHARACTER, LUMP_VISIBILITY ); + SwapLumpToDisk( LUMP_MODELS ); + SwapLumpToDisk( LUMP_VERTEXES ); + SwapLumpToDisk( LUMP_PLANES ); + SwapLumpToDisk( LUMP_NODES ); + SwapLumpToDisk( LUMP_TEXINFO ); + SwapLumpToDisk( LUMP_TEXDATA ); + SwapLumpToDisk( LUMP_DISPINFO ); + SwapLumpToDisk( LUMP_DISP_VERTS ); + SwapLumpToDisk( LUMP_DISP_TRIS ); + SwapLumpToDisk( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS ); + SwapLumpToDisk( LUMP_FACE_MACRO_TEXTURE_INFO ); + SwapLumpToDisk( LUMP_PRIMITIVES ); + SwapLumpToDisk( LUMP_PRIMVERTS ); + SwapLumpToDisk( FIELD_SHORT, LUMP_PRIMINDICES ); + SwapLumpToDisk( LUMP_ORIGINALFACES ); + SwapLumpToDisk( FIELD_SHORT, LUMP_LEAFFACES ); + SwapLumpToDisk( FIELD_SHORT, LUMP_LEAFBRUSHES ); + SwapLumpToDisk( FIELD_INTEGER, LUMP_SURFEDGES ); + SwapLumpToDisk( LUMP_EDGES ); + SwapLumpToDisk( LUMP_BRUSHES ); + SwapLumpToDisk( LUMP_BRUSHSIDES ); + SwapLumpToDisk( LUMP_AREAS ); + SwapLumpToDisk( LUMP_AREAPORTALS ); + SwapLumpToDisk( FIELD_CHARACTER, LUMP_ENTITIES ); + SwapLumpToDisk( LUMP_LEAFWATERDATA ); + SwapLumpToDisk( FIELD_VECTOR, LUMP_VERTNORMALS ); + SwapLumpToDisk( FIELD_SHORT, LUMP_VERTNORMALINDICES ); + SwapLumpToDisk( FIELD_VECTOR, LUMP_CLIPPORTALVERTS ); + SwapLumpToDisk( LUMP_CUBEMAPS ); + SwapLumpToDisk( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA ); + SwapLumpToDisk( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE ); + SwapLumpToDisk( LUMP_OVERLAYS ); + SwapLumpToDisk( LUMP_WATEROVERLAYS ); + SwapLumpToDisk( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER ); + SwapLumpToDisk( 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( FIELD_CHARACTER, LUMP_LIGHTING_HDR ) ) + { + g_pBSPHeader->lumps[LUMP_LIGHTING].filelen = 0; + } + else + { + // no HDR, keep LDR version + SwapLumpToDisk( 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 ( !RepackBSP( inputBuffer, outputBuffer, pCompressFunc, IZip::eCompressionType_None ) ) + { + 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( 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; ilumps[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; iAddToTail( 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; iAddToTail( 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; iAddToTail( 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/utils/common/bsplib.h b/utils/common/bsplib.h new file mode 100644 index 0000000..f7e50f3 --- /dev/null +++ b/utils/common/bsplib.h @@ -0,0 +1,407 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef BSPLIB_H +#define BSPLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "zip_utils.h" +#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 > CDispLightmapSamplePositions; +#else +typedef CUtlVector 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 dlightdataHDR; +extern CUtlVector dlightdataLDR; +extern CUtlVector *pdlightdata; +extern CUtlVector dentdata; + +extern int numleafs; +#if !defined( _X360 ) +extern dleaf_t dleafs[MAX_MAP_LEAFS]; +#else +extern dleaf_t *dleafs; +#endif +extern CUtlVector *g_pLeafAmbientLighting; +extern CUtlVector *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; + +extern int numtexdata; +extern dtexdata_t dtexdata[MAX_MAP_TEXDATA]; + +// displacement map .bsp file info +extern CUtlVector g_dispinfo; +extern CUtlVector g_DispVerts; +extern CUtlVector 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 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 g_TexDataStringData; +extern CUtlVector g_TexDataStringTable; + +extern int numleafwaterdata; +extern dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA]; + +extern CUtlVector g_FaceMacroTextureInfos; + +extern CUtlVector g_OccluderData; +extern CUtlVector g_OccluderPolyData; +extern CUtlVector 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, IZip::eCompressionType compressionType = IZip::eCompressionType_None ); +void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType = IZip::eCompressionType_None ); +void AddDirToPak( IZip *pak, const char *pDirPath, const char *pPakPrefix = NULL ); +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 RepackBSPCallback_LZMA( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer ); +bool RepackBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc, IZip::eCompressionType packfileCompression ); +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 leafs; +}; + +extern CUtlVector g_ClusterLeaves; + +// Call this to build the mapping from cluster to leaves +void BuildClusterTable( ); + +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/utils/common/cmdlib.cpp b/utils/common/cmdlib.cpp new file mode 100644 index 0000000..a5f9b74 --- /dev/null +++ b/utils/common/cmdlib.cpp @@ -0,0 +1,1007 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// ----------------------- +// cmdlib.c +// ----------------------- +#include "tier0/platform.h" +#ifdef IS_WINDOWS_PC +#include +#endif +#include "cmdlib.h" +#include +#include +#include "tier1/strtools.h" +#ifdef _WIN32 +#include +#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 +#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 g_CleanupFunctions; +CUtlLinkedList g_ExtraSpewHooks; + +bool g_bStopOnExit = false; +void (*g_ExtraSpewHook)(const char*) = NULL; + +#if defined( _WIN32 ) || defined( WIN32 ) + +void CmdLib_FPrintf( FileHandle_t hFile, const char *pFormat, ... ) +{ + static CUtlVector buf; + 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 +#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;iSize( 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/utils/common/cmdlib.h b/utils/common/cmdlib.h new file mode 100644 index 0000000..5b5b2c7 --- /dev/null +++ b/utils/common/cmdlib.h @@ -0,0 +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 +#include +#include +#include +#include +#include +#include +#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/utils/common/consolewnd.cpp b/utils/common/consolewnd.cpp new file mode 100644 index 0000000..6201409 --- /dev/null +++ b/utils/common/consolewnd.cpp @@ -0,0 +1,333 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include +#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/utils/common/consolewnd.h b/utils/common/consolewnd.h new file mode 100644 index 0000000..92649e2 --- /dev/null +++ b/utils/common/consolewnd.h @@ -0,0 +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 diff --git a/utils/common/filesystem_tools.cpp b/utils/common/filesystem_tools.cpp new file mode 100644 index 0000000..9401c4a --- /dev/null +++ b/utils/common/filesystem_tools.cpp @@ -0,0 +1,206 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#if defined( _WIN32 ) && !defined( _X360 ) +#include +#include +#include // _chmod +#elif _LINUX +#include +#endif + +#include +#include +#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 + + +// ---------------------------------------------------------------------------------------------------- // +// 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; + + // 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/utils/common/filesystem_tools.h b/utils/common/filesystem_tools.h new file mode 100644 index 0000000..ada82ad --- /dev/null +++ b/utils/common/filesystem_tools.h @@ -0,0 +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 diff --git a/utils/common/map_shared.cpp b/utils/common/map_shared.cpp new file mode 100644 index 0000000..e33e20c --- /dev/null +++ b/utils/common/map_shared.cpp @@ -0,0 +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; + } +} + + diff --git a/utils/common/map_shared.h b/utils/common/map_shared.h new file mode 100644 index 0000000..5f2b2b6 --- /dev/null +++ b/utils/common/map_shared.h @@ -0,0 +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 diff --git a/utils/common/movie.h b/utils/common/movie.h new file mode 100644 index 0000000..f905529 --- /dev/null +++ b/utils/common/movie.h @@ -0,0 +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; + + + +#endif _MOVIE_H_ \ No newline at end of file diff --git a/utils/common/mpi_stats.cpp b/utils/common/mpi_stats.cpp new file mode 100644 index 0000000..3602d76 --- /dev/null +++ b/utils/common/mpi_stats.cpp @@ -0,0 +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 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 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 = vmax( 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/utils/common/mpi_stats.h b/utils/common/mpi_stats.h new file mode 100644 index 0000000..841db3a --- /dev/null +++ b/utils/common/mpi_stats.h @@ -0,0 +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 diff --git a/utils/common/mstristrip.cpp b/utils/common/mstristrip.cpp new file mode 100644 index 0000000..ad6ebdc --- /dev/null +++ b/utils/common/mstristrip.cpp @@ -0,0 +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 +#include +#include +#include +#include + +#include +#ifdef _DEBUG +#include +#endif + +#include "mstristrip.h" + +using namespace std; + +//========================================================================= +// structs +//========================================================================= +typedef vector STRIPVERTS; +typedef list 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/utils/common/mstristrip.h b/utils/common/mstristrip.h new file mode 100644 index 0000000..55c9319 --- /dev/null +++ b/utils/common/mstristrip.h @@ -0,0 +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 +); + diff --git a/utils/common/pacifier.cpp b/utils/common/pacifier.cpp new file mode 100644 index 0000000..41a1018 --- /dev/null +++ b/utils/common/pacifier.cpp @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include +#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/utils/common/pacifier.h b/utils/common/pacifier.h new file mode 100644 index 0000000..d64d6cd --- /dev/null +++ b/utils/common/pacifier.h @@ -0,0 +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 diff --git a/utils/common/physdll.cpp b/utils/common/physdll.cpp new file mode 100644 index 0000000..3df4b96 --- /dev/null +++ b/utils/common/physdll.cpp @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include +#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/utils/common/physdll.h b/utils/common/physdll.h new file mode 100644 index 0000000..f6faf2d --- /dev/null +++ b/utils/common/physdll.h @@ -0,0 +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 diff --git a/utils/common/polylib.cpp b/utils/common/polylib.cpp new file mode 100644 index 0000000..63c9144 --- /dev/null +++ b/utils/common/polylib.cpp @@ -0,0 +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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ¢er) +{ + int i; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; inumpoints ; i++) + VectorAdd (w->p[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + + + +/* +============= +WindingCenter +============= +*/ +vec_t WindingAreaAndBalancePoint( winding_t *w, Vector ¢er ) +{ + int i; + Vector d1, d2, cross; + vec_t total; + + VectorCopy (vec3_origin, center); + if ( !w ) + return 0.0f; + + total = 0; + for (i=2 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; inumpoints ; 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 ; jnumpoints ; 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 ; inumpoints ; 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/utils/common/polylib.h b/utils/common/polylib.h new file mode 100644 index 0000000..8753dcc --- /dev/null +++ b/utils/common/polylib.h @@ -0,0 +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 ¢er); +vec_t WindingAreaAndBalancePoint( winding_t *w, Vector ¢er ); +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/utils/common/qfiles.h b/utils/common/qfiles.h new file mode 100644 index 0000000..fc122c3 --- /dev/null +++ b/utils/common/qfiles.h @@ -0,0 +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 diff --git a/utils/common/scratchpad_helpers.cpp b/utils/common/scratchpad_helpers.cpp new file mode 100644 index 0000000..ecab731 --- /dev/null +++ b/utils/common/scratchpad_helpers.cpp @@ -0,0 +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 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/utils/common/scratchpad_helpers.h b/utils/common/scratchpad_helpers.h new file mode 100644 index 0000000..29e5a12 --- /dev/null +++ b/utils/common/scratchpad_helpers.h @@ -0,0 +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 diff --git a/utils/common/scriplib.cpp b/utils/common/scriplib.cpp new file mode 100644 index 0000000..1c8b47f --- /dev/null +++ b/utils/common/scriplib.cpp @@ -0,0 +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 +#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 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, ¯oname[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 +#include +#ifdef WIN32 +#include +#include +#include +#endif +#include +#include +#include +#include +#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 ); + 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; + FindFiles( tempPath, false, fileList ); + for ( int i=0; i &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 &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 &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/utils/common/threads.cpp b/utils/common/threads.cpp new file mode 100644 index 0000000..74e457a --- /dev/null +++ b/utils/common/threads.cpp @@ -0,0 +1,257 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#define USED + +#include +#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/utils/common/threads.h b/utils/common/threads.h new file mode 100644 index 0000000..0908b67 --- /dev/null +++ b/utils/common/threads.h @@ -0,0 +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 diff --git a/utils/common/tools_minidump.cpp b/utils/common/tools_minidump.cpp new file mode 100644 index 0000000..a765920 --- /dev/null +++ b/utils/common/tools_minidump.cpp @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include +#include +#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/utils/common/tools_minidump.h b/utils/common/tools_minidump.h new file mode 100644 index 0000000..2e5f12c --- /dev/null +++ b/utils/common/tools_minidump.h @@ -0,0 +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 diff --git a/utils/common/utilmatlib.cpp b/utils/common/utilmatlib.cpp new file mode 100644 index 0000000..f2dc49f --- /dev/null +++ b/utils/common/utilmatlib.cpp @@ -0,0 +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 +#include "utilmatlib.h" +#include "tier0/dbg.h" +#include +#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/utils/common/utilmatlib.h b/utils/common/utilmatlib.h new file mode 100644 index 0000000..9d2e0b5 --- /dev/null +++ b/utils/common/utilmatlib.h @@ -0,0 +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 diff --git a/utils/common/vmpi_tools_shared.cpp b/utils/common/vmpi_tools_shared.cpp new file mode 100644 index 0000000..247569f --- /dev/null +++ b/utils/common/vmpi_tools_shared.cpp @@ -0,0 +1,374 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include +#include +#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/utils/common/vmpi_tools_shared.h b/utils/common/vmpi_tools_shared.h new file mode 100644 index 0000000..980552e --- /dev/null +++ b/utils/common/vmpi_tools_shared.h @@ -0,0 +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 diff --git a/utils/common/wadlib.c b/utils/common/wadlib.c new file mode 100644 index 0000000..4aff972 --- /dev/null +++ b/utils/common/wadlib.c @@ -0,0 +1,334 @@ +//========= Copyright 1996-2005, Valve LLC, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// wad2lib.c + +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#ifdef NeXT +#include +#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 ; ifilepos = LittleLong(lump_p->filepos); + lump_p->size = LittleLong(lump_p->size); + } +} + + + +void CleanupName (char *in, char *out) +{ + int i; + + for (i=0 ; iname ) ; i++ ) + { + if (!in[i]) + break; + + out[i] = toupper(in[i]); + } + + for ( ; iname ); 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 ; iname == 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/utils/common/wadlib.h b/utils/common/wadlib.h new file mode 100644 index 0000000..0fa12f5 --- /dev/null +++ b/utils/common/wadlib.h @@ -0,0 +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); + diff --git a/utils/lzma/C/7z.h b/utils/lzma/C/7z.h new file mode 100644 index 0000000..6c7886e --- /dev/null +++ b/utils/lzma/C/7z.h @@ -0,0 +1,202 @@ +/* 7z.h -- 7z interface +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_H +#define __7Z_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define k7zStartHeaderSize 0x20 +#define k7zSignatureSize 6 + +extern const Byte k7zSignature[k7zSignatureSize]; + +typedef struct +{ + const Byte *Data; + size_t Size; +} CSzData; + +/* CSzCoderInfo & CSzFolder support only default methods */ + +typedef struct +{ + size_t PropsOffset; + UInt32 MethodID; + Byte NumStreams; + Byte PropsSize; +} CSzCoderInfo; + +typedef struct +{ + UInt32 InIndex; + UInt32 OutIndex; +} CSzBond; + +#define SZ_NUM_CODERS_IN_FOLDER_MAX 4 +#define SZ_NUM_BONDS_IN_FOLDER_MAX 3 +#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 + +typedef struct +{ + UInt32 NumCoders; + UInt32 NumBonds; + UInt32 NumPackStreams; + UInt32 UnpackStream; + UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; + CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; + CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; +} CSzFolder; + + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); + +typedef struct +{ + UInt32 Low; + UInt32 High; +} CNtfsFileTime; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + UInt32 *Vals; +} CSzBitUi32s; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + // UInt64 *Vals; + CNtfsFileTime *Vals; +} CSzBitUi64s; + +#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +typedef struct +{ + UInt32 NumPackStreams; + UInt32 NumFolders; + + UInt64 *PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders + + size_t *FoCodersOffsets; // NumFolders + 1 + UInt32 *FoStartPackStreamIndex; // NumFolders + 1 + UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 + Byte *FoToMainUnpackSizeIndex; // NumFolders + UInt64 *CoderUnpackSizes; // for all coders in all folders + + Byte *CodersData; +} CSzAr; + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAllocPtr allocMain); + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 NumFiles; + + UInt64 *UnpackPositions; // NumFiles + 1 + // Byte *IsEmptyFiles; + Byte *IsDirs; + CSzBitUi32s CRCs; + + CSzBitUi32s Attribs; + // CSzBitUi32s Parents; + CSzBitUi64s MTime; + CSzBitUi64s CTime; + + UInt32 *FolderToFile; // NumFolders + 1 + UInt32 *FileToFolder; // NumFiles + + size_t *FileNameOffsets; /* in 2-byte steps */ + Byte *FileNames; /* UTF-16-LE */ +} CSzArEx; + +#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) + +#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +*/ + + + +/* + SzArEx_Extract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +SRes SzArEx_Extract( + const CSzArEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp); + + +/* +SzArEx_Open Errors: +SZ_ERROR_NO_ARCHIVE +SZ_ERROR_ARCHIVE +SZ_ERROR_UNSUPPORTED +SZ_ERROR_MEM +SZ_ERROR_CRC +SZ_ERROR_INPUT_EOF +SZ_ERROR_FAIL +*/ + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAllocPtr allocMain, ISzAllocPtr allocTemp); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/7zAlloc.c b/utils/lzma/C/7zAlloc.c new file mode 100644 index 0000000..c924a52 --- /dev/null +++ b/utils/lzma/C/7zAlloc.c @@ -0,0 +1,80 @@ +/* 7zAlloc.c -- Allocation functions +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zAlloc.h" + +/* #define _SZ_ALLOC_DEBUG */ +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef _SZ_ALLOC_DEBUG + +#ifdef _WIN32 +#include +#endif + +#include +int g_allocCount = 0; +int g_allocCountTemp = 0; + +#endif + +void *SzAlloc(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p); + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount); + g_allocCount++; + #endif + return malloc(size); +} + +void SzFree(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p); + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCount--; + fprintf(stderr, "\nFree; count = %10d", g_allocCount); + } + #endif + free(address); +} + +void *SzAllocTemp(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p); + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp); + g_allocCountTemp++; + #ifdef _WIN32 + return HeapAlloc(GetProcessHeap(), 0, size); + #endif + #endif + return malloc(size); +} + +void SzFreeTemp(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p); + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCountTemp--; + fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); + } + #ifdef _WIN32 + HeapFree(GetProcessHeap(), 0, address); + return; + #endif + #endif + free(address); +} diff --git a/utils/lzma/C/7zAlloc.h b/utils/lzma/C/7zAlloc.h new file mode 100644 index 0000000..44778f9 --- /dev/null +++ b/utils/lzma/C/7zAlloc.h @@ -0,0 +1,19 @@ +/* 7zAlloc.h -- Allocation functions +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_ALLOC_H +#define __7Z_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void *SzAlloc(ISzAllocPtr p, size_t size); +void SzFree(ISzAllocPtr p, void *address); + +void *SzAllocTemp(ISzAllocPtr p, size_t size); +void SzFreeTemp(ISzAllocPtr p, void *address); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/7zArcIn.c b/utils/lzma/C/7zArcIn.c new file mode 100644 index 0000000..f74d0fa --- /dev/null +++ b/utils/lzma/C/7zArcIn.c @@ -0,0 +1,1771 @@ +/* 7zArcIn.c -- 7z Input functions +2018-12-31 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7z.h" +#include "7zBuf.h" +#include "7zCrc.h" +#include "CpuArch.h" + +#define MY_ALLOC(T, p, size, alloc) { \ + if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } + +#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } + +#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ + { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } + +#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ + { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } + +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttrib, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy + // k7zNtSecure, + // k7zParent, + // k7zIsReal +}; + +const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) +{ + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); + MY_ALLOC(UInt32, p->Vals, num, alloc); + } + return SZ_OK; +} + +void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; + ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + +#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; + ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + + +static void SzAr_Init(CSzAr *p) +{ + p->NumPackStreams = 0; + p->NumFolders = 0; + + p->PackPositions = NULL; + SzBitUi32s_Init(&p->FolderCRCs); + + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; + + p->CodersData = NULL; +} + +static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); + + ISzAlloc_Free(alloc, p->FoCodersOffsets); + ISzAlloc_Free(alloc, p->FoStartPackStreamIndex); + ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes); + ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + ISzAlloc_Free(alloc, p->CoderUnpackSizes); + + ISzAlloc_Free(alloc, p->CodersData); + + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + + p->NumFiles = 0; + p->dataPos = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + + SzBitUi32s_Init(&p->CRCs); + SzBitUi32s_Init(&p->Attribs); + // SzBitUi32s_Init(&p->Parents); + SzBitUi64s_Init(&p->MTime); + SzBitUi64s_Init(&p->CTime); +} + +void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->UnpackPositions); + ISzAlloc_Free(alloc, p->IsDirs); + + ISzAlloc_Free(alloc, p->FolderToFile); + ISzAlloc_Free(alloc, p->FileToFolder); + + ISzAlloc_Free(alloc, p->FileNameOffsets); + ISzAlloc_Free(alloc, p->FileNames); + + SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); + // SzBitUi32s_Free(&p->Parents, alloc); + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + + +static int TestSignatureCandidate(const Byte *testBytes) +{ + unsigned i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } + +#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; +#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) +#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++; + +#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } +#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } + +#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ + dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); + +static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte, mask; + unsigned i; + UInt32 v; + + SZ_READ_BYTE(firstByte); + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + return SZ_OK; + } + SZ_READ_BYTE(v); + if ((firstByte & 0x40) == 0) + { + *value = (((UInt32)firstByte & 0x3F) << 8) | v; + return SZ_OK; + } + SZ_READ_BYTE(mask); + *value = v | ((UInt32)mask << 8); + mask = 0x20; + for (i = 2; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + *value |= (highPart << (8 * i)); + return SZ_OK; + } + SZ_READ_BYTE(b); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + + +static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + Byte firstByte; + UInt64 value64; + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + firstByte = *sd->Data; + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + sd->Data++; + sd->Size--; + return SZ_OK; + } + RINOK(ReadNumber(sd, &value64)); + if (value64 >= (UInt32)0x80000000 - 1) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +#define ReadID(sd, value) ReadNumber(sd, value) + +static SRes SkipData(CSzData *sd) +{ + UInt64 size; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, size); + return SZ_OK; +} + +static SRes WaitId(CSzData *sd, UInt32 id) +{ + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == id) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SkipData(sd)); + } +} + +static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) +{ + UInt32 numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + *v = sd->Data; + SKIP_DATA(sd, numBytes); + return SZ_OK; +} + +static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) +{ + Byte b = 0; + unsigned m = 0; + UInt32 sum = 0; + for (; numItems != 0; numItems--) + { + if (m == 0) + { + b = *bits++; + m = 8; + } + m--; + sum += ((b >> m) & 1); + } + return sum; +} + +static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) +{ + Byte allAreDefined; + Byte *v2; + UInt32 numBytes = (numItems + 7) >> 3; + *v = NULL; + SZ_READ_BYTE(allAreDefined); + if (numBytes == 0) + return SZ_OK; + if (allAreDefined == 0) + { + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); + SKIP_DATA(sd, numBytes); + return SZ_OK; + } + MY_ALLOC(Byte, *v, numBytes, alloc); + v2 = *v; + memset(v2, 0xFF, (size_t)numBytes); + { + unsigned numBits = (unsigned)numItems & 7; + if (numBits != 0) + v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); + } + return SZ_OK; +} + +static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +{ + UInt32 i; + CSzData sd; + UInt32 *vals; + const Byte *defs; + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); + sd = *sd2; + defs = crcs->Defs; + vals = crcs->Vals; + for (i = 0; i < numItems; i++) + if (SzBitArray_Check(defs, i)) + { + SZ_READ_32(vals[i]); + } + else + vals[i] = 0; + *sd2 = sd; + return SZ_OK; +} + +static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +{ + SzBitUi32s_Free(crcs, alloc); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); + return ReadUi32s(sd, numItems, crcs, alloc); +} + +static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) +{ + Byte allAreDefined; + UInt32 numDefined = numItems; + SZ_READ_BYTE(allAreDefined); + if (!allAreDefined) + { + size_t numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + numDefined = CountDefinedBits(sd->Data, numItems); + SKIP_DATA(sd, numBytes); + } + if (numDefined > (sd->Size >> 2)) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, (size_t)numDefined * 4); + return SZ_OK; +} + +static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) +{ + RINOK(SzReadNumber32(sd, &p->NumPackStreams)); + + RINOK(WaitId(sd, k7zIdSize)); + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); + { + UInt64 sum = 0; + UInt32 i; + UInt32 numPackStreams = p->NumPackStreams; + for (i = 0; i < numPackStreams; i++) + { + UInt64 packSize; + p->PackPositions[i] = sum; + RINOK(ReadNumber(sd, &packSize)); + sum += packSize; + if (sum < packSize) + return SZ_ERROR_ARCHIVE; + } + p->PackPositions[i] = sum; + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + /* CRC of packed streams is unused now */ + RINOK(SkipBitUi32s(sd, p->NumPackStreams)); + continue; + } + RINOK(SkipData(sd)); + } +} + +/* +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} +*/ + +#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) +{ + UInt32 numCoders, i; + UInt32 numInStreams = 0; + const Byte *dataStart = sd->Data; + + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; + + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = f->Coders + i; + unsigned idSize, j; + UInt64 id; + + SZ_READ_BYTE(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + + idSize = (unsigned)(mainByte & 0xF); + if (idSize > sizeof(id)) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd->Size) + return SZ_ERROR_ARCHIVE; + id = 0; + for (j = 0; j < idSize; j++) + { + id = ((id << 8) | *sd->Data); + sd->Data++; + sd->Size--; + } + if (id > (UInt32)0xFFFFFFFF) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = (UInt32)id; + + coder->NumStreams = 1; + coder->PropsOffset = 0; + coder->PropsSize = 0; + + if ((mainByte & 0x10) != 0) + { + UInt32 numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + coder->NumStreams = (Byte)numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize = 0; + RINOK(SzReadNumber32(sd, &propsSize)); + if (propsSize > sd->Size) + return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; + coder->PropsOffset = sd->Data - dataStart; + coder->PropsSize = (Byte)propsSize; + sd->Data += (size_t)propsSize; + sd->Size -= (size_t)propsSize; + } + } + + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ + { + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond *bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)); + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) + return SZ_ERROR_ARCHIVE; + f->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; + } + } + + f->NumCoders = numCoders; + + return SZ_OK; +} + + +static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +{ + CSzData sd; + sd = *sd2; + for (; num != 0; num--) + { + Byte firstByte, mask; + unsigned i; + SZ_READ_BYTE_2(firstByte); + if ((firstByte & 0x80) == 0) + continue; + if ((firstByte & 0x40) == 0) + { + if (sd.Size == 0) + return SZ_ERROR_ARCHIVE; + sd.Size--; + sd.Data++; + continue; + } + mask = 0x20; + for (i = 2; i < 8 && (firstByte & mask) != 0; i++) + mask >>= 1; + if (i > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, i); + } + *sd2 = sd; + return SZ_OK; +} + + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + + +static SRes ReadUnpackInfo(CSzAr *p, + CSzData *sd2, + UInt32 numFoldersMax, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAllocPtr alloc) +{ + CSzData sd; + + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; + const Byte *startBufPtr; + Byte external; + + RINOK(WaitId(sd2, k7zIdFolder)); + + RINOK(SzReadNumber32(sd2, &numFolders)); + if (numFolders > numFoldersMax) + return SZ_ERROR_UNSUPPORTED; + p->NumFolders = numFolders; + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); + MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); + + startBufPtr = sd.Data; + + packStreamIndex = 0; + numCodersOutStreams = 0; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 numCoders, ci, numInStreams = 0; + + p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + + RINOK(SzReadNumber32(&sd, &numCoders)); + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (ci = 0; ci < numCoders; ci++) + { + Byte mainByte; + unsigned idSize; + UInt32 coderInStreams; + + SZ_READ_BYTE_2(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + idSize = (mainByte & 0xF); + if (idSize > 8) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, idSize); + + coderInStreams = 1; + + if ((mainByte & 0x10) != 0) + { + UInt32 coderOutStreams; + RINOK(SzReadNumber32(&sd, &coderInStreams)); + RINOK(SzReadNumber32(&sd, &coderOutStreams)); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coderInStreams; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize; + RINOK(SzReadNumber32(&sd, &propsSize)); + if (propsSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, propsSize); + } + } + + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 1; + + if (numCoders != 1 || numInStreams != 1) + { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + + UInt32 i; + UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + UInt32 index; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numCoders || coderUsed[index]) + return SZ_ERROR_ARCHIVE; + coderUsed[index] = True; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) + return SZ_ERROR_UNSUPPORTED; + if (numPackStreams > p->NumPackStreams - packStreamIndex) + return SZ_ERROR_ARCHIVE; + packStreamIndex += numPackStreams; + } + } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + + { + size_t dataSize = sd.Data - startBufPtr; + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoCodersOffsets[fo] = dataSize; + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); + } + + if (external != 0) + { + if (sd.Size != 0) + return SZ_ERROR_ARCHIVE; + sd = *sd2; + } + + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); + + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + { + UInt32 i; + for (i = 0; i < numCodersOutStreams; i++) + { + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + } + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(&sd, &type)); + if (type == k7zIdEnd) + { + *sd2 = sd; + return SZ_OK; + } + if (type == k7zIdCRC) + { + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); + continue; + } + RINOK(SkipData(&sd)); + } +} + + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +{ + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; +} + + +typedef struct +{ + UInt32 NumTotalSubStreams; + UInt32 NumSubDigests; + CSzData sdNumSubStreams; + CSzData sdSizes; + CSzData sdCRCs; +} CSubStreamInfo; + + +static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) +{ + UInt64 type = 0; + UInt32 numSubDigests = 0; + UInt32 numFolders = p->NumFolders; + UInt32 numUnpackStreams = numFolders; + UInt32 numUnpackSizesInData = 0; + + for (;;) + { + RINOK(ReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + UInt32 i; + ssi->sdNumSubStreams.Data = sd->Data; + numUnpackStreams = 0; + numSubDigests = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numUnpackStreams > numUnpackStreams + numStreams) + return SZ_ERROR_UNSUPPORTED; + numUnpackStreams += numStreams; + if (numStreams != 0) + numUnpackSizesInData += (numStreams - 1); + if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) + numSubDigests += numStreams; + } + ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; + continue; + } + if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + if (!ssi->sdNumSubStreams.Data) + { + numSubDigests = numFolders; + if (p->FolderCRCs.Defs) + numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); + } + + ssi->NumTotalSubStreams = numUnpackStreams; + ssi->NumSubDigests = numSubDigests; + + if (type == k7zIdSize) + { + ssi->sdSizes.Data = sd->Data; + RINOK(SkipNumbers(sd, numUnpackSizesInData)); + ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; + RINOK(ReadID(sd, &type)); + } + + for (;;) + { + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + ssi->sdCRCs.Data = sd->Data; + RINOK(SkipBitUi32s(sd, numSubDigests)); + ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; + } + else + { + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } +} + +static SRes SzReadStreamsInfo(CSzAr *p, + CSzData *sd, + UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, + UInt64 *dataOffset, + CSubStreamInfo *ssi, + ISzAllocPtr alloc) +{ + UInt64 type; + + SzData_Clear(&ssi->sdSizes); + SzData_Clear(&ssi->sdCRCs); + SzData_Clear(&ssi->sdNumSubStreams); + + *dataOffset = 0; + RINOK(ReadID(sd, &type)); + if (type == k7zIdPackInfo) + { + RINOK(ReadNumber(sd, dataOffset)); + RINOK(ReadPackInfo(p, sd, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdUnpackInfo) + { + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdSubStreamsInfo) + { + RINOK(ReadSubStreamsInfo(p, sd, ssi)); + RINOK(ReadID(sd, &type)); + } + else + { + ssi->NumTotalSubStreams = p->NumFolders; + // ssi->NumSubDigests = 0; + } + + return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStream *inStream, + CSzData *sd, + CBuf *tempBufs, + UInt32 numFoldersMax, + UInt64 baseOffset, + CSzAr *p, + ISzAllocPtr allocTemp) +{ + UInt64 dataStartPos; + UInt32 fo; + CSubStreamInfo ssi; + + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders == 0) + return SZ_ERROR_ARCHIVE; + + for (fo = 0; fo < p->NumFolders; fo++) + Buf_Init(tempBufs + fo); + + for (fo = 0; fo < p->NumFolders; fo++) + { + CBuf *tempBuf = tempBufs + fo; + UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + if ((size_t)unpackSize != unpackSize) + return SZ_ERROR_MEM; + if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + } + + for (fo = 0; fo < p->NumFolders; fo++) + { + const CBuf *tempBuf = tempBufs + fo; + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); + } + + return SZ_OK; +} + +static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) +{ + size_t pos = 0; + *offsets++ = 0; + if (numFiles == 0) + return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; + if (data[size - 2] != 0 || data[size - 1] != 0) + return SZ_ERROR_ARCHIVE; + do + { + const Byte *p; + if (pos == size) + return SZ_ERROR_ARCHIVE; + for (p = data + pos; + #ifdef _WIN32 + *(const UInt16 *)p != 0 + #else + p[0] != 0 || p[1] != 0 + #endif + ; p += 2); + pos = p - data + 2; + *offsets++ = (pos >> 1); + } + while (--numFiles); + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, + CSzData *sd2, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAllocPtr alloc) +{ + CSzData sd; + UInt32 i; + CNtfsFileTime *vals; + Byte *defs; + Byte external; + + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); + vals = p->Vals; + defs = p->Defs; + for (i = 0; i < num; i++) + if (SzBitArray_Check(defs, i)) + { + if (sd.Size < 8) + return SZ_ERROR_ARCHIVE; + vals[i].Low = GetUi32(sd.Data); + vals[i].High = GetUi32(sd.Data + 4); + SKIP_DATA2(sd, 8); + } + else + vals[i].High = vals[i].Low = 0; + + if (external == 0) + *sd2 = sd; + + return SZ_OK; +} + + +#define NUM_ADDITIONAL_STREAMS_MAX 8 + + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + ILookInStream *inStream, + CBuf *tempBufs, UInt32 *numTempBufs, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp + ) +{ + CSubStreamInfo ssi; + +{ + UInt64 type; + + SzData_Clear(&ssi.sdSizes); + SzData_Clear(&ssi.sdCRCs); + SzData_Clear(&ssi.sdNumSubStreams); + + ssi.NumSubDigests = 0; + ssi.NumTotalSubStreams = 0; + + RINOK(ReadID(sd, &type)); + + if (type == k7zIdArchiveProperties) + { + for (;;) + { + UInt64 type2; + RINOK(ReadID(sd, &type2)); + if (type2 == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdAdditionalStreamsInfo) + { + CSzAr tempAr; + SRes res; + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, + p->startPosAfterHeader, &tempAr, allocTemp); + *numTempBufs = tempAr.NumFolders; + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + return res; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, + &p->dataPos, &ssi, allocMain)); + p->dataPos += p->startPosAfterHeader; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdEnd) + { + return SZ_OK; + } + + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; +} + +{ + UInt32 numFiles = 0; + UInt32 numEmptyStreams = 0; + const Byte *emptyStreams = NULL; + const Byte *emptyFiles = NULL; + + RINOK(SzReadNumber32(sd, &numFiles)); + p->NumFiles = numFiles; + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + + if (type >= ((UInt32)1 << 8)) + { + SKIP_DATA(sd, size); + } + else switch ((unsigned)type) + { + case k7zIdName: + { + size_t namesSize; + const Byte *namesData; + Byte external; + + SZ_READ_BYTE(external); + if (external == 0) + { + namesSize = (size_t)size - 1; + namesData = sd->Data; + } + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + namesData = (tempBufs)[index].data; + namesSize = (tempBufs)[index].size; + } + + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); + RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) + if (external == 0) + { + SKIP_DATA(sd, namesSize); + } + break; + } + case k7zIdEmptyStream: + { + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); + numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; + break; + } + case k7zIdEmptyFile: + { + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); + break; + } + case k7zIdWinAttrib: + { + Byte external; + CSzData sdSwitch; + CSzData *sdPtr; + SzBitUi32s_Free(&p->Attribs, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); + + SZ_READ_BYTE(external); + if (external == 0) + sdPtr = sd; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + sdSwitch.Data = (tempBufs)[index].data; + sdSwitch.Size = (tempBufs)[index].size; + sdPtr = &sdSwitch; + } + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); + break; + } + /* + case k7zParent: + { + SzBitUi32s_Free(&p->Parents, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); + RINOK(SzReadSwitch(sd)); + RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); + break; + } + */ + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + default: + { + SKIP_DATA(sd, size); + } + } + } + + if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + { + UInt32 i; + UInt32 emptyFileIndex = 0; + UInt32 folderIndex = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; + UInt64 unpackPos = 0; + const Byte *digestsDefs = NULL; + const Byte *digestsVals = NULL; + UInt32 digestsValsIndex = 0; + UInt32 digestIndex; + Byte allDigestsDefined = 0; + Byte isDirMask = 0; + Byte crcMask = 0; + Byte mask = 0x80; + + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); + + if (ssi.sdCRCs.Size != 0) + { + SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); + if (allDigestsDefined) + digestsVals = ssi.sdCRCs.Data; + else + { + size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + digestsDefs = ssi.sdCRCs.Data; + digestsVals = digestsDefs + numBytes; + } + } + + digestIndex = 0; + + for (i = 0; i < numFiles; i++, mask >>= 1) + { + if (mask == 0) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + isDirMask = 0; + crcMask = 0; + mask = 0x80; + } + + p->UnpackPositions[i] = unpackPos; + p->CRCs.Vals[i] = 0; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + { + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else + isDirMask |= mask; + if (remSubStreams == 0) + { + p->FileToFolder[i] = (UInt32)-1; + continue; + } + } + + if (remSubStreams == 0) + { + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) + { + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + } + remSubStreams = numSubStreams; + if (numSubStreams != 0) + break; + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + + folderIndex++; + } + } + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + continue; + + if (--remSubStreams == 0) + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + if (folderUnpackSize < unpackPos - startFolderUnpackPos) + return SZ_ERROR_ARCHIVE; + unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + { + p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; + crcMask |= mask; + } + else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + + folderIndex++; + } + else + { + UInt64 v; + RINOK(ReadNumber(&ssi.sdSizes, &v)); + unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; + if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + } + } + + if (mask != 0x80) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + } + + p->UnpackPositions[i] = unpackPos; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; + } +} + return SZ_OK; +} + + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ILookInStream *inStream, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + UInt32 i; + UInt32 numTempBufs = 0; + SRes res; + CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Init(tempBufs + i); + + res = SzReadHeader2(p, sd, inStream, + tempBufs, &numTempBufs, + allocMain, allocTemp); + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Free(tempBufs + i, allocTemp); + + RINOK(res); + + if (sd->Size != 0) + return SZ_ERROR_FAIL; + + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStream *inStream, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buf; + SRes res; + + startArcPos = 0; + RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < startArcPos + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + + if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buf.data; + sd.Size = buf.size; + + res = ReadID(&sd, &type); + + if (res == SZ_OK && type == k7zIdEncodedHeader) + { + CSzAr tempAr; + CBuf tempBuf; + Buf_Init(&tempBuf); + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + { + Buf_Free(&tempBuf, allocTemp); + } + else + { + Buf_Free(&buf, allocTemp); + buf.data = tempBuf.data; + buf.size = tempBuf.size; + sd.Data = buf.data; + sd.Size = buf.size; + res = ReadID(&sd, &type); + } + } + + if (res == SZ_OK) + { + if (type == k7zIdHeader) + { + /* + CSzData sd2; + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) + { + SzArEx_Free(p, allocMain); + sd2 = sd; + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); + if (res != SZ_OK) + break; + } + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); + } + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + + Buf_Free(&buf, allocTemp); + return res; +} + + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAllocPtr allocMain, ISzAllocPtr allocTemp) +{ + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **tempBuf, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + UInt32 folderIndex = p->FileToFolder[fileIndex]; + SRes res = SZ_OK; + + *offset = 0; + *outSizeProcessed = 0; + + if (folderIndex == (UInt32)-1) + { + ISzAlloc_Free(allocMain, *tempBuf); + *blockIndex = folderIndex; + *tempBuf = NULL; + *outBufferSize = 0; + return SZ_OK; + } + + if (*tempBuf == NULL || *blockIndex != folderIndex) + { + UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* + UInt64 unpackSizeSpec = + p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ + size_t unpackSize = (size_t)unpackSizeSpec; + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + ISzAlloc_Free(allocMain, *tempBuf); + *tempBuf = NULL; + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize); + if (*tempBuf == NULL) + res = SZ_ERROR_MEM; + } + + if (res == SZ_OK) + { + res = SzAr_DecodeFolder(&p->db, folderIndex, + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); + } + } + } + + if (res == SZ_OK) + { + UInt64 unpackPos = p->UnpackPositions[fileIndex]; + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); + *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos); + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; + } + + return res; +} + + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + size_t offs = p->FileNameOffsets[fileIndex]; + size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames + offs * 2; + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) +{ + size_t len; + if (!p->FileNameOffsets) + return 1; + len = 0; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return len; + fileIndex = parent; + } +} + +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + BoolInt needSlash; + if (!p->FileNameOffsets) + { + *(--dest) = 0; + return dest; + } + needSlash = False; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); + if (needSlash) + *(dest - 1) = '/'; + needSlash = True; + dest -= curLen; + + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return dest; + fileIndex = parent; + } +} +*/ diff --git a/utils/lzma/C/7zBuf.c b/utils/lzma/C/7zBuf.c new file mode 100644 index 0000000..8865c32 --- /dev/null +++ b/utils/lzma/C/7zBuf.c @@ -0,0 +1,36 @@ +/* 7zBuf.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zBuf.h" + +void Buf_Init(CBuf *p) +{ + p->data = 0; + p->size = 0; +} + +int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc) +{ + p->size = 0; + if (size == 0) + { + p->data = 0; + return 1; + } + p->data = (Byte *)ISzAlloc_Alloc(alloc, size); + if (p->data) + { + p->size = size; + return 1; + } + return 0; +} + +void Buf_Free(CBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; +} diff --git a/utils/lzma/C/7zBuf.h b/utils/lzma/C/7zBuf.h new file mode 100644 index 0000000..81d1b5b --- /dev/null +++ b/utils/lzma/C/7zBuf.h @@ -0,0 +1,35 @@ +/* 7zBuf.h -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_BUF_H +#define __7Z_BUF_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + Byte *data; + size_t size; +} CBuf; + +void Buf_Init(CBuf *p); +int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc); +void Buf_Free(CBuf *p, ISzAllocPtr alloc); + +typedef struct +{ + Byte *data; + size_t size; + size_t pos; +} CDynBuf; + +void DynBuf_Construct(CDynBuf *p); +void DynBuf_SeekToBeg(CDynBuf *p); +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc); +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/7zBuf2.c b/utils/lzma/C/7zBuf2.c new file mode 100644 index 0000000..2083474 --- /dev/null +++ b/utils/lzma/C/7zBuf2.c @@ -0,0 +1,52 @@ +/* 7zBuf2.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zBuf.h" + +void DynBuf_Construct(CDynBuf *p) +{ + p->data = 0; + p->size = 0; + p->pos = 0; +} + +void DynBuf_SeekToBeg(CDynBuf *p) +{ + p->pos = 0; +} + +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + if (size > p->size - p->pos) + { + size_t newSize = p->pos + size; + Byte *data; + newSize += newSize / 4; + data = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!data) + return 0; + p->size = newSize; + if (p->pos != 0) + memcpy(data, p->data, p->pos); + ISzAlloc_Free(alloc, p->data); + p->data = data; + } + if (size != 0) + { + memcpy(p->data + p->pos, buf, size); + p->pos += size; + } + return 1; +} + +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; + p->pos = 0; +} diff --git a/utils/lzma/C/7zCrc.c b/utils/lzma/C/7zCrc.c new file mode 100644 index 0000000..b4d84f0 --- /dev/null +++ b/utils/lzma/C/7zCrc.c @@ -0,0 +1,128 @@ +/* 7zCrc.c -- CRC32 init +2017-06-06 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" + +#define kCrcPoly 0xEDB88320 + +#ifdef MY_CPU_LE + #define CRC_NUM_TABLES 8 +#else + #define CRC_NUM_TABLES 9 + + #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); +#endif + +#ifndef MY_CPU_BE + UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); +#endif + +typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); + +CRC_FUNC g_CrcUpdateT4; +CRC_FUNC g_CrcUpdateT8; +CRC_FUNC g_CrcUpdate; + +UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) +{ + return g_CrcUpdate(v, data, size, g_CrcTable); +} + +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) +{ + return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; +} + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +void MY_FAST_CALL CrcGenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + g_CrcTable[i] = r; + } + for (i = 256; i < 256 * CRC_NUM_TABLES; i++) + { + UInt32 r = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); + } + + #if CRC_NUM_TABLES < 4 + + g_CrcUpdate = CrcUpdateT1; + + #else + + #ifdef MY_CPU_LE + + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + #endif + g_CrcUpdate = CrcUpdateT8; + #endif + + #else + { + #ifndef MY_CPU_BE + UInt32 k = 0x01020304; + const Byte *p = (const Byte *)&k; + if (p[0] == 4 && p[1] == 3) + { + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + g_CrcUpdate = CrcUpdateT8; + #endif + } + else if (p[0] != 1 || p[1] != 2) + g_CrcUpdate = CrcUpdateT1; + else + #endif + { + for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) + { + UInt32 x = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = CRC_UINT32_SWAP(x); + } + g_CrcUpdateT4 = CrcUpdateT1_BeT4; + g_CrcUpdate = CrcUpdateT1_BeT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT1_BeT8; + g_CrcUpdate = CrcUpdateT1_BeT8; + #endif + } + } + #endif + + #endif +} diff --git a/utils/lzma/C/7zCrc.h b/utils/lzma/C/7zCrc.h new file mode 100644 index 0000000..8fd5795 --- /dev/null +++ b/utils/lzma/C/7zCrc.h @@ -0,0 +1,25 @@ +/* 7zCrc.h -- CRC32 calculation +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __7Z_CRC_H +#define __7Z_CRC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +extern UInt32 g_CrcTable[]; + +/* Call CrcGenerateTable one time before other CRC functions */ +void MY_FAST_CALL CrcGenerateTable(void); + +#define CRC_INIT_VAL 0xFFFFFFFF +#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) +#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/7zCrcOpt.c b/utils/lzma/C/7zCrcOpt.c new file mode 100644 index 0000000..73beba2 --- /dev/null +++ b/utils/lzma/C/7zCrcOpt.c @@ -0,0 +1,115 @@ +/* 7zCrcOpt.c -- CRC32 calculation +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifndef MY_CPU_BE + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32 *)p; + v = + (table + 0x300)[((v ) & 0xFF)] + ^ (table + 0x200)[((v >> 8) & 0xFF)] + ^ (table + 0x100)[((v >> 16) & 0xFF)] + ^ (table + 0x000)[((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + (table + 0x700)[((v ) & 0xFF)] + ^ (table + 0x600)[((v >> 8) & 0xFF)] + ^ (table + 0x500)[((v >> 16) & 0xFF)] + ^ (table + 0x400)[((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + (table + 0x300)[((d ) & 0xFF)] + ^ (table + 0x200)[((d >> 8) & 0xFF)] + ^ (table + 0x100)[((d >> 16) & 0xFF)] + ^ (table + 0x000)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +#endif + + +#ifndef MY_CPU_LE + +#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32 *)p; + v = + (table + 0x000)[((v ) & 0xFF)] + ^ (table + 0x100)[((v >> 8) & 0xFF)] + ^ (table + 0x200)[((v >> 16) & 0xFF)] + ^ (table + 0x300)[((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + (table + 0x400)[((v ) & 0xFF)] + ^ (table + 0x500)[((v >> 8) & 0xFF)] + ^ (table + 0x600)[((v >> 16) & 0xFF)] + ^ (table + 0x700)[((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + (table + 0x000)[((d ) & 0xFF)] + ^ (table + 0x100)[((d >> 8) & 0xFF)] + ^ (table + 0x200)[((d >> 16) & 0xFF)] + ^ (table + 0x300)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +#endif diff --git a/utils/lzma/C/7zDec.c b/utils/lzma/C/7zDec.c new file mode 100644 index 0000000..7c46352 --- /dev/null +++ b/utils/lzma/C/7zDec.c @@ -0,0 +1,591 @@ +/* 7zDec.c -- Decoding from 7z folder +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define _7ZIP_PPMD_SUPPPORT */ + +#include "7z.h" +#include "7zCrc.h" + +#include "Bcj2.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "LzmaDec.h" +#include "Lzma2Dec.h" +#ifdef _7ZIP_PPMD_SUPPPORT +#include "Ppmd7.h" +#endif + +#define k_Copy 0 +#define k_Delta 3 +#define k_LZMA2 0x21 +#define k_LZMA 0x30101 +#define k_BCJ 0x3030103 +#define k_BCJ2 0x303011B +#define k_PPC 0x3030205 +#define k_IA64 0x3030401 +#define k_ARM 0x3030501 +#define k_ARMT 0x3030701 +#define k_SPARC 0x3030805 + + +#ifdef _7ZIP_PPMD_SUPPPORT + +#define k_PPMD 0x30401 + +typedef struct +{ + IByteIn vt; + const Byte *cur; + const Byte *end; + const Byte *begin; + UInt64 processed; + BoolInt extra; + SRes res; + const ILookInStream *inStream; +} CByteInToLook; + +static Byte ReadByte(const IByteIn *pp) +{ + CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt); + if (p->cur != p->end) + return *p->cur++; + if (p->res == SZ_OK) + { + size_t size = p->cur - p->begin; + p->processed += size; + p->res = ILookInStream_Skip(p->inStream, size); + size = (1 << 25); + p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size); + p->cur = p->begin; + p->end = p->begin + size; + if (size != 0) + return *p->cur++;; + } + p->extra = True; + return 0; +} + +static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CPpmd7 ppmd; + CByteInToLook s; + SRes res = SZ_OK; + + s.vt.Read = ReadByte; + s.inStream = inStream; + s.begin = s.end = s.cur = NULL; + s.extra = False; + s.res = SZ_OK; + s.processed = 0; + + if (propsSize != 5) + return SZ_ERROR_UNSUPPORTED; + + { + unsigned order = props[0]; + UInt32 memSize = GetUi32(props + 1); + if (order < PPMD7_MIN_ORDER || + order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return SZ_ERROR_UNSUPPORTED; + Ppmd7_Construct(&ppmd); + if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) + return SZ_ERROR_MEM; + Ppmd7_Init(&ppmd, order); + } + { + CPpmd7z_RangeDec rc; + Ppmd7z_RangeDec_CreateVTable(&rc); + rc.Stream = &s.vt; + if (!Ppmd7z_RangeDec_Init(&rc)) + res = SZ_ERROR_DATA; + else if (s.extra) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else + { + SizeT i; + for (i = 0; i < outSize; i++) + { + int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt); + if (s.extra || sym < 0) + break; + outBuffer[i] = (Byte)sym; + } + if (i != outSize) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) + res = SZ_ERROR_DATA; + } + } + Ppmd7_Free(&ppmd, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CLzmaDec state; + SRes res = SZ_OK; + + LzmaDec_Construct(&state); + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); + state.dic = outBuffer; + state.dicBufSize = outSize; + LzmaDec_Init(&state); + + for (;;) + { + const void *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = ILookInStream_Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; + ELzmaStatus status; + res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } + + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; + + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + + res = ILookInStream_Skip(inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + LzmaDec_FreeProbs(&state, allocMain); + return res; +} + + +#ifndef _7Z_NO_METHOD_LZMA2 + +static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CLzma2Dec state; + SRes res = SZ_OK; + + Lzma2Dec_Construct(&state); + if (propsSize != 1) + return SZ_ERROR_DATA; + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); + state.decoder.dic = outBuffer; + state.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&state); + + for (;;) + { + const void *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = ILookInStream_Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; + ELzmaStatus status; + res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.decoder.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } + + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + + res = ILookInStream_Skip(inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + Lzma2Dec_FreeProbs(&state, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) +{ + while (inSize > 0) + { + const void *inBuf; + size_t curSize = (1 << 18); + if (curSize > inSize) + curSize = (size_t)inSize; + RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)); + if (curSize == 0) + return SZ_ERROR_INPUT_EOF; + memcpy(outBuffer, inBuf, curSize); + outBuffer += curSize; + inSize -= curSize; + RINOK(ILookInStream_Skip(inStream, curSize)); + } + return SZ_OK; +} + +static BoolInt IS_MAIN_METHOD(UInt32 m) +{ + switch (m) + { + case k_Copy: + case k_LZMA: + #ifndef _7Z_NO_METHOD_LZMA2 + case k_LZMA2: + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + case k_PPMD: + #endif + return True; + } + return False; +} + +static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c) +{ + return + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); +} + +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) + +static SRes CheckSupportedFolder(const CSzFolder *f) +{ + if (f->NumCoders < 1 || f->NumCoders > 4) + return SZ_ERROR_UNSUPPORTED; + if (!IS_SUPPORTED_CODER(&f->Coders[0])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 1) + { + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + + #ifndef _7Z_NO_METHODS_FILTERS + + if (f->NumCoders == 2) + { + const CSzCoderInfo *c = &f->Coders[1]; + if ( + /* c->MethodID > (UInt32)0xFFFFFFFF || */ + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) + return SZ_ERROR_UNSUPPORTED; + switch ((UInt32)c->MethodID) + { + case k_Delta: + case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: + case k_ARM: + case k_ARMT: + break; + default: + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; + } + + #endif + + + if (f->NumCoders == 4) + { + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + return SZ_ERROR_UNSUPPORTED; +} + +#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; + +static SRes SzFolder_Decode2(const CSzFolder *folder, + const Byte *propsData, + const UInt64 *unpackSizes, + const UInt64 *packPositions, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain, + Byte *tempBuf[]) +{ + UInt32 ci; + SizeT tempSizes[3] = { 0, 0, 0}; + SizeT tempSize3 = 0; + Byte *tempBuf3 = 0; + + RINOK(CheckSupportedFolder(folder)); + + for (ci = 0; ci < folder->NumCoders; ci++) + { + const CSzCoderInfo *coder = &folder->Coders[ci]; + + if (IS_MAIN_METHOD((UInt32)coder->MethodID)) + { + UInt32 si = 0; + UInt64 offset; + UInt64 inSize; + Byte *outBufCur = outBuffer; + SizeT outSizeCur = outSize; + if (folder->NumCoders == 4) + { + UInt32 indices[] = { 3, 2, 0 }; + UInt64 unpackSize = unpackSizes[ci]; + si = indices[ci]; + if (ci < 2) + { + Byte *temp; + outSizeCur = (SizeT)unpackSize; + if (outSizeCur != unpackSize) + return SZ_ERROR_MEM; + temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur); + if (!temp && outSizeCur != 0) + return SZ_ERROR_MEM; + outBufCur = tempBuf[1 - ci] = temp; + tempSizes[1 - ci] = outSizeCur; + } + else if (ci == 2) + { + if (unpackSize > outSize) /* check it */ + return SZ_ERROR_PARAM; + tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); + tempSize3 = outSizeCur = (SizeT)unpackSize; + } + else + return SZ_ERROR_UNSUPPORTED; + } + offset = packPositions[si]; + inSize = packPositions[(size_t)si + 1] - offset; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + + if (coder->MethodID == k_Copy) + { + if (inSize != outSizeCur) /* check it */ + return SZ_ERROR_DATA; + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); + } + else if (coder->MethodID == k_LZMA) + { + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + #ifndef _7Z_NO_METHOD_LZMA2 + else if (coder->MethodID == k_LZMA2) + { + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + else if (coder->MethodID == k_PPMD) + { + RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + #endif + else + return SZ_ERROR_UNSUPPORTED; + } + else if (coder->MethodID == k_BCJ2) + { + UInt64 offset = packPositions[1]; + UInt64 s3Size = packPositions[2] - offset; + + if (ci != 3) + return SZ_ERROR_UNSUPPORTED; + + tempSizes[2] = (SizeT)s3Size; + if (tempSizes[2] != s3Size) + return SZ_ERROR_MEM; + tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]); + if (!tempBuf[2] && tempSizes[2] != 0) + return SZ_ERROR_MEM; + + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); + + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; + + { + CBcj2Dec p; + + p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)); + + { + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + + if (!Bcj2Dec_IsFinished(&p)) + return SZ_ERROR_DATA; + + if (p.dest != p.destLim + || p.state != BCJ2_STREAM_MAIN) + return SZ_ERROR_DATA; + } + } + } + #ifndef _7Z_NO_METHODS_FILTERS + else if (ci == 1) + { + if (coder->MethodID == k_Delta) + { + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); + } + } + else + { + if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + switch (coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + default: + return SZ_ERROR_UNSUPPORTED; + } + } + } + #endif + else + return SZ_ERROR_UNSUPPORTED; + } + + return SZ_OK; +} + + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAllocPtr allocMain) +{ + SRes res; + CSzFolder folder; + CSzData sd; + + const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; + sd.Data = data; + sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex]; + + res = SzGetNextFolderItem(&folder, &sd); + + if (res != SZ_OK) + return res; + + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) + return SZ_ERROR_FAIL; + { + unsigned i; + Byte *tempBuf[3] = { 0, 0, 0}; + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], + p->PackPositions + p->FoStartPackStreamIndex[folderIndex], + inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + + for (i = 0; i < 3; i++) + ISzAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + + return res; + } +} diff --git a/utils/lzma/C/7zFile.c b/utils/lzma/C/7zFile.c new file mode 100644 index 0000000..8992fb1 --- /dev/null +++ b/utils/lzma/C/7zFile.c @@ -0,0 +1,286 @@ +/* 7zFile.c -- File IO +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zFile.h" + +#ifndef USE_WINDOWS_FILE + +#ifndef UNDER_CE +#include +#endif + +#else + +/* + ReadFile and WriteFile functions in Windows have BUG: + If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) + from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES + (Insufficient system resources exist to complete the requested service). + Probably in some version of Windows there are problems with other sizes: + for 32 MB (maybe also for 16 MB). + And message can be "Network connection was lost" +*/ + +#define kChunkSizeMax (1 << 22) + +#endif + +void File_Construct(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + p->handle = INVALID_HANDLE_VALUE; + #else + p->file = NULL; + #endif +} + +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +static WRes File_Open(CSzFile *p, const char *name, int writeMode) +{ + #ifdef USE_WINDOWS_FILE + p->handle = CreateFileA(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); + #else + p->file = fopen(name, writeMode ? "wb+" : "rb"); + return (p->file != 0) ? 0 : + #ifdef UNDER_CE + 2; /* ENOENT */ + #else + errno; + #endif + #endif +} + +WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } +WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } +#endif + +#ifdef USE_WINDOWS_FILE +static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) +{ + p->handle = CreateFileW(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); +} +WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } +#endif + +WRes File_Close(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + if (p->handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(p->handle)) + return GetLastError(); + p->handle = INVALID_HANDLE_VALUE; + } + #else + if (p->file != NULL) + { + int res = fclose(p->file); + if (res != 0) + return res; + p->file = NULL; + } + #endif + return 0; +} + +WRes File_Read(CSzFile *p, void *data, size_t *size) +{ + size_t originalSize = *size; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + + #else + + *size = fread(data, 1, originalSize, p->file); + if (*size == originalSize) + return 0; + return ferror(p->file); + + #endif +} + +WRes File_Write(CSzFile *p, const void *data, size_t *size) +{ + size_t originalSize = *size; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + + #else + + *size = fwrite(data, 1, originalSize, p->file); + if (*size == originalSize) + return 0; + return ferror(p->file); + + #endif +} + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) +{ + #ifdef USE_WINDOWS_FILE + + LARGE_INTEGER value; + DWORD moveMethod; + value.LowPart = (DWORD)*pos; + value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ + switch (origin) + { + case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; + case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; + case SZ_SEEK_END: moveMethod = FILE_END; break; + default: return ERROR_INVALID_PARAMETER; + } + value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); + if (value.LowPart == 0xFFFFFFFF) + { + WRes res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *pos = ((Int64)value.HighPart << 32) | value.LowPart; + return 0; + + #else + + int moveMethod; + int res; + switch (origin) + { + case SZ_SEEK_SET: moveMethod = SEEK_SET; break; + case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; + case SZ_SEEK_END: moveMethod = SEEK_END; break; + default: return 1; + } + res = fseek(p->file, (long)*pos, moveMethod); + *pos = ftell(p->file); + return res; + + #endif +} + +WRes File_GetLength(CSzFile *p, UInt64 *length) +{ + #ifdef USE_WINDOWS_FILE + + DWORD sizeHigh; + DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + { + DWORD res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *length = (((UInt64)sizeHigh) << 32) + sizeLow; + return 0; + + #else + + long pos = ftell(p->file); + int res = fseek(p->file, 0, SEEK_END); + *length = ftell(p->file); + fseek(p->file, pos, SEEK_SET); + return res; + + #endif +} + + +/* ---------- FileSeqInStream ---------- */ + +static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size) +{ + CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt); + return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; +} + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p) +{ + p->vt.Read = FileSeqInStream_Read; +} + + +/* ---------- FileInStream ---------- */ + +static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size) +{ + CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); + return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; +} + +static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) +{ + CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); + return File_Seek(&p->file, pos, origin); +} + +void FileInStream_CreateVTable(CFileInStream *p) +{ + p->vt.Read = FileInStream_Read; + p->vt.Seek = FileInStream_Seek; +} + + +/* ---------- FileOutStream ---------- */ + +static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) +{ + CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt); + File_Write(&p->file, data, &size); + return size; +} + +void FileOutStream_CreateVTable(CFileOutStream *p) +{ + p->vt.Write = FileOutStream_Write; +} diff --git a/utils/lzma/C/7zFile.h b/utils/lzma/C/7zFile.h new file mode 100644 index 0000000..0e79253 --- /dev/null +++ b/utils/lzma/C/7zFile.h @@ -0,0 +1,83 @@ +/* 7zFile.h -- File IO +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_FILE_H +#define __7Z_FILE_H + +#ifdef _WIN32 +#define USE_WINDOWS_FILE +#endif + +#ifdef USE_WINDOWS_FILE +#include +#else +#include +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* ---------- File ---------- */ + +typedef struct +{ + #ifdef USE_WINDOWS_FILE + HANDLE handle; + #else + FILE *file; + #endif +} CSzFile; + +void File_Construct(CSzFile *p); +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +WRes InFile_Open(CSzFile *p, const char *name); +WRes OutFile_Open(CSzFile *p, const char *name); +#endif +#ifdef USE_WINDOWS_FILE +WRes InFile_OpenW(CSzFile *p, const WCHAR *name); +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); +#endif +WRes File_Close(CSzFile *p); + +/* reads max(*size, remain file's size) bytes */ +WRes File_Read(CSzFile *p, void *data, size_t *size); + +/* writes *size bytes */ +WRes File_Write(CSzFile *p, const void *data, size_t *size); + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); +WRes File_GetLength(CSzFile *p, UInt64 *length); + + +/* ---------- FileInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + CSzFile file; +} CFileSeqInStream; + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p); + + +typedef struct +{ + ISeekInStream vt; + CSzFile file; +} CFileInStream; + +void FileInStream_CreateVTable(CFileInStream *p); + + +typedef struct +{ + ISeqOutStream vt; + CSzFile file; +} CFileOutStream; + +void FileOutStream_CreateVTable(CFileOutStream *p); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/7zStream.c b/utils/lzma/C/7zStream.c new file mode 100644 index 0000000..6b5aa16 --- /dev/null +++ b/utils/lzma/C/7zStream.c @@ -0,0 +1,176 @@ +/* 7zStream.c -- 7z Stream functions +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zTypes.h" + +SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(ISeqInStream_Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size) +{ + return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + +SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf) +{ + size_t processed = 1; + RINOK(ISeqInStream_Read(stream, buf, &processed)); + return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; +} + + + +SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset) +{ + Int64 t = offset; + return ILookInStream_Seek(stream, &t, SZ_SEEK_SET); +} + +SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size) +{ + const void *lookBuf; + if (*size == 0) + return SZ_OK; + RINOK(ILookInStream_Look(stream, &lookBuf, size)); + memcpy(buf, lookBuf, *size); + return ILookInStream_Skip(stream, *size); +} + +SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(ILookInStream_Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size) +{ + return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + + + +#define GET_LookToRead2 CLookToRead2 *p = CONTAINER_FROM_VTBL(pp, CLookToRead2, vt); + +static SRes LookToRead2_Look_Lookahead(const ILookInStream *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + GET_LookToRead2 + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size != 0) + { + p->pos = 0; + p->size = 0; + size2 = p->bufSize; + res = ISeekInStream_Read(p->realStream, p->buf, &size2); + p->size = size2; + } + if (*size > size2) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead2_Look_Exact(const ILookInStream *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + GET_LookToRead2 + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size != 0) + { + p->pos = 0; + p->size = 0; + if (*size > p->bufSize) + *size = p->bufSize; + res = ISeekInStream_Read(p->realStream, p->buf, size); + size2 = p->size = *size; + } + if (*size > size2) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead2_Skip(const ILookInStream *pp, size_t offset) +{ + GET_LookToRead2 + p->pos += offset; + return SZ_OK; +} + +static SRes LookToRead2_Read(const ILookInStream *pp, void *buf, size_t *size) +{ + GET_LookToRead2 + size_t rem = p->size - p->pos; + if (rem == 0) + return ISeekInStream_Read(p->realStream, buf, size); + if (rem > *size) + rem = *size; + memcpy(buf, p->buf + p->pos, rem); + p->pos += rem; + *size = rem; + return SZ_OK; +} + +static SRes LookToRead2_Seek(const ILookInStream *pp, Int64 *pos, ESzSeek origin) +{ + GET_LookToRead2 + p->pos = p->size = 0; + return ISeekInStream_Seek(p->realStream, pos, origin); +} + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead) +{ + p->vt.Look = lookahead ? + LookToRead2_Look_Lookahead : + LookToRead2_Look_Exact; + p->vt.Skip = LookToRead2_Skip; + p->vt.Read = LookToRead2_Read; + p->vt.Seek = LookToRead2_Seek; +} + + + +static SRes SecToLook_Read(const ISeqInStream *pp, void *buf, size_t *size) +{ + CSecToLook *p = CONTAINER_FROM_VTBL(pp, CSecToLook, vt); + return LookInStream_LookRead(p->realStream, buf, size); +} + +void SecToLook_CreateVTable(CSecToLook *p) +{ + p->vt.Read = SecToLook_Read; +} + +static SRes SecToRead_Read(const ISeqInStream *pp, void *buf, size_t *size) +{ + CSecToRead *p = CONTAINER_FROM_VTBL(pp, CSecToRead, vt); + return ILookInStream_Read(p->realStream, buf, size); +} + +void SecToRead_CreateVTable(CSecToRead *p) +{ + p->vt.Read = SecToRead_Read; +} diff --git a/utils/lzma/C/7zTypes.h b/utils/lzma/C/7zTypes.h new file mode 100644 index 0000000..65b3af6 --- /dev/null +++ b/utils/lzma/C/7zTypes.h @@ -0,0 +1,375 @@ +/* 7zTypes.h -- Basic types +2018-08-04 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#ifdef _WIN32 +/* #include */ +#endif + +#include + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + + +#ifdef _WIN32 + +/* typedef DWORD WRes; */ +typedef unsigned WRes; +#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) + +#else + +typedef int WRes; +#define MY__FACILITY_WIN32 7 +#define MY__FACILITY__WRes MY__FACILITY_WIN32 +#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000))) + +#endif + + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int BoolInt; +/* typedef BoolInt Bool; */ +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_FORCE_INLINE __forceinline + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_NO_INLINE +#define MY_FORCE_INLINE +#define MY_CDECL +#define MY_FAST_CALL + +/* inline keyword : for C++ / C99 */ + +/* GCC, clang: */ +/* +#if defined (__GNUC__) && (__GNUC__ >= 4) +#define MY_FORCE_INLINE __attribute__((always_inline)) +#define MY_NO_INLINE __attribute__((noinline)) +#endif +*/ + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct IByteIn IByteIn; +struct IByteIn +{ + Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */ +}; +#define IByteIn_Read(p) (p)->Read(p) + + +typedef struct IByteOut IByteOut; +struct IByteOut +{ + void (*Write)(const IByteOut *p, Byte b); +}; +#define IByteOut_Write(p, b) (p)->Write(p, b) + + +typedef struct ISeqInStream ISeqInStream; +struct ISeqInStream +{ + SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +}; +#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf); + + +typedef struct ISeqOutStream ISeqOutStream; +struct ISeqOutStream +{ + size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +}; +#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + + +typedef struct ISeekInStream ISeekInStream; +struct ISeekInStream +{ + SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin); +}; +#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +typedef struct ILookInStream ILookInStream; +struct ILookInStream +{ + SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(const ILookInStream *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(const ILookInStream *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin); +}; + +#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) +#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) +#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size); + + + +typedef struct +{ + ILookInStream vt; + const ISeekInStream *realStream; + + size_t pos; + size_t size; /* it's data size */ + + /* the following variables must be set outside */ + Byte *buf; + size_t bufSize; +} CLookToRead2; + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); + +#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; } + + +typedef struct +{ + ISeqInStream vt; + const ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + + + +typedef struct +{ + ISeqInStream vt; + const ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + + +typedef struct ICompressProgress ICompressProgress; + +struct ICompressProgress +{ + SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +}; +#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) + + + +typedef struct ISzAlloc ISzAlloc; +typedef const ISzAlloc * ISzAllocPtr; + +struct ISzAlloc +{ + void *(*Alloc)(ISzAllocPtr p, size_t size); + void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ +}; + +#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) +#define ISzAlloc_Free(p, a) (p)->Free(p, a) + +/* deprecated */ +#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) +#define IAlloc_Free(p, a) ISzAlloc_Free(p, a) + + + + + +#ifndef MY_offsetof + #ifdef offsetof + #define MY_offsetof(type, m) offsetof(type, m) + /* + #define MY_offsetof(type, m) FIELD_OFFSET(type, m) + */ + #else + #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) + #endif +#endif + + + +#ifndef MY_container_of + +/* +#define MY_container_of(ptr, type, m) container_of(ptr, type, m) +#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) +#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) +#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) +*/ + +/* + GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" + GCC 3.4.4 : classes with constructor + GCC 4.8.1 : classes with non-public variable members" +*/ + +#define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m))) + + +#endif + +#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr)) + +/* +#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +*/ +#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m) + +#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +/* +#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m) +*/ + + + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/7zVersion.h b/utils/lzma/C/7zVersion.h new file mode 100644 index 0000000..c176823 --- /dev/null +++ b/utils/lzma/C/7zVersion.h @@ -0,0 +1,27 @@ +#define MY_VER_MAJOR 19 +#define MY_VER_MINOR 00 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "19.00" +#define MY_VERSION MY_VERSION_NUMBERS + +#ifdef MY_CPU_NAME + #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")" +#else + #define MY_VERSION_CPU MY_VERSION +#endif + +#define MY_DATE "2019-02-21" +#undef MY_COPYRIGHT +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_AUTHOR_NAME "Igor Pavlov" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov" + +#ifdef USE_COPYRIGHT_CR + #define MY_COPYRIGHT MY_COPYRIGHT_CR +#else + #define MY_COPYRIGHT MY_COPYRIGHT_PD +#endif + +#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE diff --git a/utils/lzma/C/7zVersion.rc b/utils/lzma/C/7zVersion.rc new file mode 100644 index 0000000..e520995 --- /dev/null +++ b/utils/lzma/C/7zVersion.rc @@ -0,0 +1,55 @@ +#define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL +#define MY_VOS_NT_WINDOWS32 0x00040004L +#define MY_VOS_CE_WINDOWS32 0x00050004L + +#define MY_VFT_APP 0x00000001L +#define MY_VFT_DLL 0x00000002L + +// #include + +#ifndef MY_VERSION +#include "7zVersion.h" +#endif + +#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0 + +#ifdef DEBUG +#define DBG_FL VS_FF_DEBUG +#else +#define DBG_FL 0 +#endif + +#define MY_VERSION_INFO(fileType, descr, intName, origName) \ +LANGUAGE 9, 1 \ +1 VERSIONINFO \ + FILEVERSION MY_VER \ + PRODUCTVERSION MY_VER \ + FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \ + FILEFLAGS DBG_FL \ + FILEOS MY_VOS_NT_WINDOWS32 \ + FILETYPE fileType \ + FILESUBTYPE 0x0L \ +BEGIN \ + BLOCK "StringFileInfo" \ + BEGIN \ + BLOCK "040904b0" \ + BEGIN \ + VALUE "CompanyName", "Igor Pavlov" \ + VALUE "FileDescription", descr \ + VALUE "FileVersion", MY_VERSION \ + VALUE "InternalName", intName \ + VALUE "LegalCopyright", MY_COPYRIGHT \ + VALUE "OriginalFilename", origName \ + VALUE "ProductName", "7-Zip" \ + VALUE "ProductVersion", MY_VERSION \ + END \ + END \ + BLOCK "VarFileInfo" \ + BEGIN \ + VALUE "Translation", 0x409, 1200 \ + END \ +END + +#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe") + +#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll") diff --git a/utils/lzma/C/Aes.c b/utils/lzma/C/Aes.c new file mode 100644 index 0000000..1cdd0e7 --- /dev/null +++ b/utils/lzma/C/Aes.c @@ -0,0 +1,306 @@ +/* Aes.c -- AES encryption / decryption +2017-01-24 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Aes.h" +#include "CpuArch.h" + +static UInt32 T[256 * 4]; +static const Byte Sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + +void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks); + +void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks); + +AES_CODE_FUNC g_AesCbc_Encode; +AES_CODE_FUNC g_AesCbc_Decode; +AES_CODE_FUNC g_AesCtr_Code; + +static UInt32 D[256 * 4]; +static Byte InvS[256]; + +static const Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF) + +#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24)) + +#define gb0(x) ( (x) & 0xFF) +#define gb1(x) (((x) >> ( 8)) & 0xFF) +#define gb2(x) (((x) >> (16)) & 0xFF) +#define gb3(x) (((x) >> (24))) + +#define gb(n, x) gb ## n(x) + +#define TT(x) (T + (x << 8)) +#define DD(x) (D + (x << 8)) + + +void AesGenTables(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + InvS[Sbox[i]] = (Byte)i; + + for (i = 0; i < 256; i++) + { + { + UInt32 a1 = Sbox[i]; + UInt32 a2 = xtime(a1); + UInt32 a3 = a2 ^ a1; + TT(0)[i] = Ui32(a2, a1, a1, a3); + TT(1)[i] = Ui32(a3, a2, a1, a1); + TT(2)[i] = Ui32(a1, a3, a2, a1); + TT(3)[i] = Ui32(a1, a1, a3, a2); + } + { + UInt32 a1 = InvS[i]; + UInt32 a2 = xtime(a1); + UInt32 a4 = xtime(a2); + UInt32 a8 = xtime(a4); + UInt32 a9 = a8 ^ a1; + UInt32 aB = a8 ^ a2 ^ a1; + UInt32 aD = a8 ^ a4 ^ a1; + UInt32 aE = a8 ^ a4 ^ a2; + DD(0)[i] = Ui32(aE, a9, aD, aB); + DD(1)[i] = Ui32(aB, aE, a9, aD); + DD(2)[i] = Ui32(aD, aB, aE, a9); + DD(3)[i] = Ui32(a9, aD, aB, aE); + } + } + + g_AesCbc_Encode = AesCbc_Encode; + g_AesCbc_Decode = AesCbc_Decode; + g_AesCtr_Code = AesCtr_Code; + + #ifdef MY_CPU_X86_OR_AMD64 + if (CPU_Is_Aes_Supported()) + { + g_AesCbc_Encode = AesCbc_Encode_Intel; + g_AesCbc_Decode = AesCbc_Decode_Intel; + g_AesCtr_Code = AesCtr_Code_Intel; + } + #endif +} + + +#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])] + +#define HT4(m, i, s, p) m[i] = \ + HT(i, 0, s) ^ \ + HT(i, 1, s) ^ \ + HT(i, 2, s) ^ \ + HT(i, 3, s) ^ w[p + i] + +#define HT16(m, s, p) \ + HT4(m, 0, s, p); \ + HT4(m, 1, s, p); \ + HT4(m, 2, s, p); \ + HT4(m, 3, s, p); \ + +#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])] +#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i]; + + +#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])] + +#define HD4(m, i, s, p) m[i] = \ + HD(i, 0, s) ^ \ + HD(i, 1, s) ^ \ + HD(i, 2, s) ^ \ + HD(i, 3, s) ^ w[p + i]; + +#define HD16(m, s, p) \ + HD4(m, 0, s, p); \ + HD4(m, 1, s, p); \ + HD4(m, 2, s, p); \ + HD4(m, 3, s, p); \ + +#define FD(i, x) InvS[gb(x, m[(i - x) & 3])] +#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i]; + +void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize) +{ + unsigned i, wSize; + wSize = keySize + 28; + keySize /= 4; + w[0] = ((UInt32)keySize / 2) + 3; + w += 4; + + for (i = 0; i < keySize; i++, key += 4) + w[i] = GetUi32(key); + + for (; i < wSize; i++) + { + UInt32 t = w[(size_t)i - 1]; + unsigned rem = i % keySize; + if (rem == 0) + t = Ui32(Sbox[gb1(t)] ^ Rcon[i / keySize], Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]); + else if (keySize > 6 && rem == 4) + t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]); + w[i] = w[i - keySize] ^ t; + } +} + +void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize) +{ + unsigned i, num; + Aes_SetKey_Enc(w, key, keySize); + num = keySize + 20; + w += 8; + for (i = 0; i < num; i++) + { + UInt32 r = w[i]; + w[i] = + DD(0)[Sbox[gb0(r)]] ^ + DD(1)[Sbox[gb1(r)]] ^ + DD(2)[Sbox[gb2(r)]] ^ + DD(3)[Sbox[gb3(r)]]; + } +} + +/* Aes_Encode and Aes_Decode functions work with little-endian words. + src and dest are pointers to 4 UInt32 words. + src and dest can point to same block */ + +static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src) +{ + UInt32 s[4]; + UInt32 m[4]; + UInt32 numRounds2 = w[0]; + w += 4; + s[0] = src[0] ^ w[0]; + s[1] = src[1] ^ w[1]; + s[2] = src[2] ^ w[2]; + s[3] = src[3] ^ w[3]; + w += 4; + for (;;) + { + HT16(m, s, 0); + if (--numRounds2 == 0) + break; + HT16(s, m, 4); + w += 8; + } + w += 4; + FT4(0); FT4(1); FT4(2); FT4(3); +} + +static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src) +{ + UInt32 s[4]; + UInt32 m[4]; + UInt32 numRounds2 = w[0]; + w += 4 + numRounds2 * 8; + s[0] = src[0] ^ w[0]; + s[1] = src[1] ^ w[1]; + s[2] = src[2] ^ w[2]; + s[3] = src[3] ^ w[3]; + for (;;) + { + w -= 8; + HD16(m, s, 4); + if (--numRounds2 == 0) + break; + HD16(s, m, 0); + } + FD4(0); FD4(1); FD4(2); FD4(3); +} + +void AesCbc_Init(UInt32 *p, const Byte *iv) +{ + unsigned i; + for (i = 0; i < 4; i++) + p[i] = GetUi32(iv + i * 4); +} + +void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks) +{ + for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) + { + p[0] ^= GetUi32(data); + p[1] ^= GetUi32(data + 4); + p[2] ^= GetUi32(data + 8); + p[3] ^= GetUi32(data + 12); + + Aes_Encode(p + 4, p, p); + + SetUi32(data, p[0]); + SetUi32(data + 4, p[1]); + SetUi32(data + 8, p[2]); + SetUi32(data + 12, p[3]); + } +} + +void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks) +{ + UInt32 in[4], out[4]; + for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) + { + in[0] = GetUi32(data); + in[1] = GetUi32(data + 4); + in[2] = GetUi32(data + 8); + in[3] = GetUi32(data + 12); + + Aes_Decode(p + 4, out, in); + + SetUi32(data, p[0] ^ out[0]); + SetUi32(data + 4, p[1] ^ out[1]); + SetUi32(data + 8, p[2] ^ out[2]); + SetUi32(data + 12, p[3] ^ out[3]); + + p[0] = in[0]; + p[1] = in[1]; + p[2] = in[2]; + p[3] = in[3]; + } +} + +void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks) +{ + for (; numBlocks != 0; numBlocks--) + { + UInt32 temp[4]; + unsigned i; + + if (++p[0] == 0) + p[1]++; + + Aes_Encode(p + 4, temp, p); + + for (i = 0; i < 4; i++, data += 4) + { + UInt32 t = temp[i]; + + #ifdef MY_CPU_LE_UNALIGN + *((UInt32 *)data) ^= t; + #else + data[0] ^= (t & 0xFF); + data[1] ^= ((t >> 8) & 0xFF); + data[2] ^= ((t >> 16) & 0xFF); + data[3] ^= ((t >> 24)); + #endif + } + } +} diff --git a/utils/lzma/C/Aes.h b/utils/lzma/C/Aes.h new file mode 100644 index 0000000..64979b5 --- /dev/null +++ b/utils/lzma/C/Aes.h @@ -0,0 +1,38 @@ +/* Aes.h -- AES encryption / decryption +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __AES_H +#define __AES_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define AES_BLOCK_SIZE 16 + +/* Call AesGenTables one time before other AES functions */ +void AesGenTables(void); + +/* UInt32 pointers must be 16-byte aligned */ + +/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */ +#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4) + +/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */ +/* keySize = 16 or 24 or 32 (bytes) */ +typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize); +void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize); +void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize); + +/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */ +void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */ +/* data - 16-byte aligned pointer to data */ +/* numBlocks - the number of 16-byte blocks in data array */ +typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks); +extern AES_CODE_FUNC g_AesCbc_Encode; +extern AES_CODE_FUNC g_AesCbc_Decode; +extern AES_CODE_FUNC g_AesCtr_Code; + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/AesOpt.c b/utils/lzma/C/AesOpt.c new file mode 100644 index 0000000..9571c46 --- /dev/null +++ b/utils/lzma/C/AesOpt.c @@ -0,0 +1,184 @@ +/* AesOpt.c -- Intel's AES +2017-06-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 +#if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729) +#define USE_INTEL_AES +#endif +#endif + +#ifdef USE_INTEL_AES + +#include + +void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i m = *p; + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p + 3; + m = _mm_xor_si128(m, *data); + m = _mm_xor_si128(m, p[2]); + do + { + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenc_si128(m, w[1]); + w += 2; + } + while (--numRounds2 != 0); + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenclast_si128(m, w[1]); + *data = m; + } + *p = m; +} + +#define NUM_WAYS 3 + +#define AES_OP_W(op, n) { \ + const __m128i t = w[n]; \ + m0 = op(m0, t); \ + m1 = op(m1, t); \ + m2 = op(m2, t); \ + } + +#define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n) +#define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n) +#define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n) +#define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n) + +void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i iv = *p; + for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const __m128i *w = p + numRounds2 * 2; + __m128i m0, m1, m2; + { + const __m128i t = w[2]; + m0 = _mm_xor_si128(t, data[0]); + m1 = _mm_xor_si128(t, data[1]); + m2 = _mm_xor_si128(t, data[2]); + } + numRounds2--; + do + { + AES_DEC(1) + AES_DEC(0) + w -= 2; + } + while (--numRounds2 != 0); + AES_DEC(1) + AES_DEC_LAST(0) + + { + __m128i t; + t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t; + t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t; + t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t; + } + } + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const __m128i *w = p + numRounds2 * 2; + __m128i m = _mm_xor_si128(w[2], *data); + numRounds2--; + do + { + m = _mm_aesdec_si128(m, w[1]); + m = _mm_aesdec_si128(m, w[0]); + w -= 2; + } + while (--numRounds2 != 0); + m = _mm_aesdec_si128(m, w[1]); + m = _mm_aesdeclast_si128(m, w[0]); + + m = _mm_xor_si128(m, iv); + iv = *data; + *data = m; + } + *p = iv; +} + +void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i ctr = *p; + __m128i one; + one.m128i_u64[0] = 1; + one.m128i_u64[1] = 0; + for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p; + __m128i m0, m1, m2; + { + const __m128i t = w[2]; + ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t); + ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t); + ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t); + } + w += 3; + do + { + AES_ENC(0) + AES_ENC(1) + w += 2; + } + while (--numRounds2 != 0); + AES_ENC(0) + AES_ENC_LAST(1) + data[0] = _mm_xor_si128(data[0], m0); + data[1] = _mm_xor_si128(data[1], m1); + data[2] = _mm_xor_si128(data[2], m2); + } + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p; + __m128i m; + ctr = _mm_add_epi64(ctr, one); + m = _mm_xor_si128(ctr, p[2]); + w += 3; + do + { + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenc_si128(m, w[1]); + w += 2; + } + while (--numRounds2 != 0); + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenclast_si128(m, w[1]); + *data = _mm_xor_si128(*data, m); + } + *p = ctr; +} + +#else + +void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks); + +void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCbc_Encode(p, data, numBlocks); +} + +void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCbc_Decode(p, data, numBlocks); +} + +void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCtr_Code(p, data, numBlocks); +} + +#endif diff --git a/utils/lzma/C/Alloc.c b/utils/lzma/C/Alloc.c new file mode 100644 index 0000000..bcede4b --- /dev/null +++ b/utils/lzma/C/Alloc.c @@ -0,0 +1,455 @@ +/* Alloc.c -- Memory allocation functions +2018-04-27 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#ifdef _WIN32 +#include +#endif +#include + +#include "Alloc.h" + +/* #define _SZ_ALLOC_DEBUG */ + +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef _SZ_ALLOC_DEBUG + +#include +int g_allocCount = 0; +int g_allocCountMid = 0; +int g_allocCountBig = 0; + + +#define CONVERT_INT_TO_STR(charType, tempSize) \ + unsigned char temp[tempSize]; unsigned i = 0; \ + while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ + *s++ = (charType)('0' + (unsigned)val); \ + while (i != 0) { i--; *s++ = temp[i]; } \ + *s = 0; + +static void ConvertUInt64ToString(UInt64 val, char *s) +{ + CONVERT_INT_TO_STR(char, 24); +} + +#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) + +static void ConvertUInt64ToHex(UInt64 val, char *s) +{ + UInt64 v = val; + unsigned i; + for (i = 1;; i++) + { + v >>= 4; + if (v == 0) + break; + } + s[i] = 0; + do + { + unsigned t = (unsigned)(val & 0xF); + val >>= 4; + s[--i] = GET_HEX_CHAR(t); + } + while (i); +} + +#define DEBUG_OUT_STREAM stderr + +static void Print(const char *s) +{ + fputs(s, DEBUG_OUT_STREAM); +} + +static void PrintAligned(const char *s, size_t align) +{ + size_t len = strlen(s); + for(;;) + { + fputc(' ', DEBUG_OUT_STREAM); + if (len >= align) + break; + ++len; + } + Print(s); +} + +static void PrintLn() +{ + Print("\n"); +} + +static void PrintHex(UInt64 v, size_t align) +{ + char s[32]; + ConvertUInt64ToHex(v, s); + PrintAligned(s, align); +} + +static void PrintDec(UInt64 v, size_t align) +{ + char s[32]; + ConvertUInt64ToString(v, s); + PrintAligned(s, align); +} + +static void PrintAddr(void *p) +{ + PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12); +} + + +#define PRINT_ALLOC(name, cnt, size, ptr) \ + Print(name " "); \ + PrintDec(cnt++, 10); \ + PrintHex(size, 10); \ + PrintAddr(ptr); \ + PrintLn(); + +#define PRINT_FREE(name, cnt, ptr) if (ptr) { \ + Print(name " "); \ + PrintDec(--cnt, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#else + +#define PRINT_ALLOC(name, cnt, size, ptr) +#define PRINT_FREE(name, cnt, ptr) +#define Print(s) +#define PrintLn() +#define PrintHex(v, align) +#define PrintDec(v, align) +#define PrintAddr(p) + +#endif + + + +void *MyAlloc(size_t size) +{ + if (size == 0) + return NULL; + #ifdef _SZ_ALLOC_DEBUG + { + void *p = malloc(size); + PRINT_ALLOC("Alloc ", g_allocCount, size, p); + return p; + } + #else + return malloc(size); + #endif +} + +void MyFree(void *address) +{ + PRINT_FREE("Free ", g_allocCount, address); + + free(address); +} + +#ifdef _WIN32 + +void *MidAlloc(size_t size) +{ + if (size == 0) + return NULL; + + PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL); + + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +} + +void MidFree(void *address) +{ + PRINT_FREE("Free-Mid", g_allocCountMid, address); + + if (!address) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#ifndef MEM_LARGE_PAGES +#undef _7ZIP_LARGE_PAGES +#endif + +#ifdef _7ZIP_LARGE_PAGES +SIZE_T g_LargePageSize = 0; +typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); +#endif + +void SetLargePageSize() +{ + #ifdef _7ZIP_LARGE_PAGES + SIZE_T size; + GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); + if (!largePageMinimum) + return; + size = largePageMinimum(); + if (size == 0 || (size & (size - 1)) != 0) + return; + g_LargePageSize = size; + #endif +} + + +void *BigAlloc(size_t size) +{ + if (size == 0) + return NULL; + + PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL); + + #ifdef _7ZIP_LARGE_PAGES + { + SIZE_T ps = g_LargePageSize; + if (ps != 0 && ps <= (1 << 30) && size > (ps / 2)) + { + size_t size2; + ps--; + size2 = (size + ps) & ~ps; + if (size2 >= size) + { + void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + if (res) + return res; + } + } + } + #endif + + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +} + +void BigFree(void *address) +{ + PRINT_FREE("Free-Big", g_allocCountBig, address); + + if (!address) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#endif + + +static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); } +static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); } +const ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); } +static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); } +const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree }; + +static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); } +static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); } +const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; + + +/* + uintptr_t : C99 (optional) + : unsupported in VS6 +*/ + +#ifdef _WIN32 + typedef UINT_PTR UIntPtr; +#else + /* + typedef uintptr_t UIntPtr; + */ + typedef ptrdiff_t UIntPtr; +#endif + + +#define ADJUST_ALLOC_SIZE 0 +/* +#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1) +*/ +/* + Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if + MyAlloc() can return address that is NOT multiple of sizeof(void *). +*/ + + +/* +#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1)))) +*/ +#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1)))) + +#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align) + + +#if (_POSIX_C_SOURCE >= 200112L) && !defined(_WIN32) + #define USE_posix_memalign +#endif + +/* + This posix_memalign() is for test purposes only. + We also need special Free() function instead of free(), + if this posix_memalign() is used. +*/ + +/* +static int posix_memalign(void **ptr, size_t align, size_t size) +{ + size_t newSize = size + align; + void *p; + void *pAligned; + *ptr = NULL; + if (newSize < size) + return 12; // ENOMEM + p = MyAlloc(newSize); + if (!p) + return 12; // ENOMEM + pAligned = MY_ALIGN_PTR_UP_PLUS(p, align); + ((void **)pAligned)[-1] = p; + *ptr = pAligned; + return 0; +} +*/ + +/* + ALLOC_ALIGN_SIZE >= sizeof(void *) + ALLOC_ALIGN_SIZE >= cache_line_size +*/ + +#define ALLOC_ALIGN_SIZE ((size_t)1 << 7) + +static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size) +{ + #ifndef USE_posix_memalign + + void *p; + void *pAligned; + size_t newSize; + UNUSED_VAR(pp); + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + + newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + p = MyAlloc(newSize); + + if (!p) + return NULL; + pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE); + + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(p); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + ((void **)pAligned)[-1] = p; + + return pAligned; + + #else + + void *p; + UNUSED_VAR(pp); + if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size)) + return NULL; + + Print(" posix_memalign="); PrintAddr(p); + PrintLn(); + + return p; + + #endif +} + + +static void SzAlignedFree(ISzAllocPtr pp, void *address) +{ + UNUSED_VAR(pp); + #ifndef USE_posix_memalign + if (address) + MyFree(((void **)address)[-1]); + #else + free(address); + #endif +} + + +const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree }; + + + +#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *)) + +/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */ +#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1] +/* +#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1] +*/ + +static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size) +{ + CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt); + void *adr; + void *pAligned; + size_t newSize; + size_t extra; + size_t alignSize = (size_t)1 << p->numAlignBits; + + if (alignSize < sizeof(void *)) + alignSize = sizeof(void *); + + if (p->offset >= alignSize) + return NULL; + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + extra = p->offset & (sizeof(void *) - 1); + newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + adr = ISzAlloc_Alloc(p->baseAlloc, newSize); + + if (!adr) + return NULL; + + pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr + + alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset; + + PrintLn(); + Print("- Aligned: "); + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(adr); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + REAL_BLOCK_PTR_VAR(pAligned) = adr; + + return pAligned; +} + + +static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address) +{ + if (address) + { + CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt); + PrintLn(); + Print("- Aligned Free: "); + PrintLn(); + ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address)); + } +} + + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p) +{ + p->vt.Alloc = AlignOffsetAlloc_Alloc; + p->vt.Free = AlignOffsetAlloc_Free; +} diff --git a/utils/lzma/C/Alloc.h b/utils/lzma/C/Alloc.h new file mode 100644 index 0000000..6482376 --- /dev/null +++ b/utils/lzma/C/Alloc.h @@ -0,0 +1,51 @@ +/* Alloc.h -- Memory allocation functions +2018-02-19 : Igor Pavlov : Public domain */ + +#ifndef __COMMON_ALLOC_H +#define __COMMON_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void *MyAlloc(size_t size); +void MyFree(void *address); + +#ifdef _WIN32 + +void SetLargePageSize(); + +void *MidAlloc(size_t size); +void MidFree(void *address); +void *BigAlloc(size_t size); +void BigFree(void *address); + +#else + +#define MidAlloc(size) MyAlloc(size) +#define MidFree(address) MyFree(address) +#define BigAlloc(size) MyAlloc(size) +#define BigFree(address) MyFree(address) + +#endif + +extern const ISzAlloc g_Alloc; +extern const ISzAlloc g_BigAlloc; +extern const ISzAlloc g_MidAlloc; +extern const ISzAlloc g_AlignedAlloc; + + +typedef struct +{ + ISzAlloc vt; + ISzAllocPtr baseAlloc; + unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */ + size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */ +} CAlignOffsetAlloc; + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p); + + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Bcj2.c b/utils/lzma/C/Bcj2.c new file mode 100644 index 0000000..9a0046a --- /dev/null +++ b/utils/lzma/C/Bcj2.c @@ -0,0 +1,257 @@ +/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) +2018-04-28 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bcj2.h" +#include "CpuArch.h" + +#define CProb UInt16 + +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) +#define kNumMoveBits 5 + +#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) +#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); + +void Bcj2Dec_Init(CBcj2Dec *p) +{ + unsigned i; + + p->state = BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp[3] = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +SRes Bcj2Dec_Decode(CBcj2Dec *p) +{ + if (p->range <= 5) + { + p->state = BCJ2_DEC_STATE_OK; + for (; p->range != 5; p->range++) + { + if (p->range == 1 && p->code != 0) + return SZ_ERROR_DATA; + + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + if (p->code == 0xFFFFFFFF) + return SZ_ERROR_DATA; + + p->range = 0xFFFFFFFF; + } + else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + { + while (p->state <= BCJ2_DEC_STATE_ORIG_3) + { + Byte *dest = p->dest; + if (dest == p->destLim) + return SZ_OK; + *dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0]; + p->state++; + p->dest = dest + 1; + } + } + + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + const Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return SZ_OK; + p->bufs[p->state] = cur + 4; + + { + UInt32 val; + Byte *dest; + SizeT rem; + + p->ip += 4; + val = GetBe32(cur) - p->ip; + dest = p->dest; + rem = p->destLim - dest; + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + return SZ_OK; + } + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + p->state = BCJ2_DEC_STATE_OK; + } + } + */ + + for (;;) + { + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; + else + { + if (p->range < kTopValue) + { + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + { + const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte *srcLim; + Byte *dest; + SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; + + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return SZ_OK; + } + + dest = p->dest; + if (num > (SizeT)(p->destLim - dest)) + { + num = p->destLim - dest; + if (num == 0) + { + p->state = BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + } + + srcLim = src + num; + + if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->bufs[BCJ2_STREAM_MAIN]; + + if (src == srcLim) + { + p->temp[3] = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = src; + p->ip += (UInt32)num; + p->dest += num; + p->state = + p->bufs[BCJ2_STREAM_MAIN] == + p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + + { + UInt32 bound, ttt; + CProb *prob; + Byte b = src[0]; + Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); + + p->temp[3] = b; + p->bufs[BCJ2_STREAM_MAIN] = src + 1; + num++; + p->ip += (UInt32)num; + p->dest += num; + + prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); + + _IF_BIT_0 + { + _UPDATE_0 + continue; + } + _UPDATE_1 + + } + } + } + + { + UInt32 val; + unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const Byte *cur = p->bufs[cj]; + Byte *dest; + SizeT rem; + + if (cur == p->lims[cj]) + { + p->state = cj; + break; + } + + val = GetBe32(cur); + p->bufs[cj] = cur + 4; + + p->ip += 4; + val -= p->ip; + dest = p->dest; + rem = p->destLim - dest; + + if (rem < 4) + { + p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8; + p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8; + p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8; + p->temp[3] = (Byte)val; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + break; + } + + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + } + } + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + return SZ_OK; +} diff --git a/utils/lzma/C/Bcj2.h b/utils/lzma/C/Bcj2.h new file mode 100644 index 0000000..8824080 --- /dev/null +++ b/utils/lzma/C/Bcj2.h @@ -0,0 +1,146 @@ +/* Bcj2.h -- BCJ2 Converter for x86 code +2014-11-10 : Igor Pavlov : Public domain */ + +#ifndef __BCJ2_H +#define __BCJ2_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define BCJ2_NUM_STREAMS 4 + +enum +{ + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC +}; + +enum +{ + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_OK +}; + +enum +{ + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_OK +}; + + +#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) + +/* +CBcj2Dec / CBcj2Enc +bufs sizes: + BUF_SIZE(n) = lims[n] - bufs[n] +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: + (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 + (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 +*/ + +/* +CBcj2Dec: +dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: + bufs[BCJ2_STREAM_MAIN] >= dest && + bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + + BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) + tempReserv = 0 : for first call of Bcj2Dec_Decode + tempReserv = 4 : for any other calls of Bcj2Dec_Decode + overlap with offset = 1 is not allowed +*/ + +typedef struct +{ + const Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + Byte *dest; + const Byte *destLim; + + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + + UInt32 ip; + Byte temp[4]; + UInt32 range; + UInt32 code; + UInt16 probs[2 + 256]; +} CBcj2Dec; + +void Bcj2Dec_Init(CBcj2Dec *p); + +/* Returns: SZ_OK or SZ_ERROR_DATA */ +SRes Bcj2Dec_Decode(CBcj2Dec *p); + +#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) + + + +typedef enum +{ + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM +} EBcj2Enc_FinishMode; + +typedef struct +{ + Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + const Byte *src; + const Byte *srcLim; + + unsigned state; + EBcj2Enc_FinishMode finishMode; + + Byte prevByte; + + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; + + UInt32 ip; + + /* 32-bit ralative offset in JUMP/CALL commands is + - (mod 4 GB) in 32-bit mode + - signed Int32 in 64-bit mode + We use (mod 4 GB) check for fileSize. + Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ + UInt32 fileIp; + UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + + UInt32 tempTarget; + unsigned tempPos; + Byte temp[4 * 2]; + + unsigned flushPos; + + UInt16 probs[2 + 256]; +} CBcj2Enc; + +void Bcj2Enc_Init(CBcj2Enc *p); +void Bcj2Enc_Encode(CBcj2Enc *p); + +#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) +#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) + + +#define BCJ2_RELAT_LIMIT_NUM_BITS 26 +#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) + +/* limit for CBcj2Enc::fileSize variable */ +#define BCJ2_FileSize_MAX ((UInt32)1 << 31) + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Bcj2Enc.c b/utils/lzma/C/Bcj2Enc.c new file mode 100644 index 0000000..bfbeb8e --- /dev/null +++ b/utils/lzma/C/Bcj2Enc.c @@ -0,0 +1,311 @@ +/* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code) +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +/* #define SHOW_STAT */ + +#ifdef SHOW_STAT +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include + +#include "Bcj2.h" +#include "CpuArch.h" + +#define CProb UInt16 + +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) +#define kNumMoveBits 5 + +void Bcj2Enc_Init(CBcj2Enc *p) +{ + unsigned i; + + p->state = BCJ2_ENC_STATE_OK; + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + p->prevByte = 0; + + p->cache = 0; + p->range = 0xFFFFFFFF; + p->low = 0; + p->cacheSize = 1; + + p->ip = 0; + + p->fileIp = 0; + p->fileSize = 0; + p->relatLimit = BCJ2_RELAT_LIMIT; + + p->tempPos = 0; + + p->flushPos = 0; + + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +static BoolInt MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0) + { + Byte *buf = p->bufs[BCJ2_STREAM_RC]; + do + { + if (buf == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + p->bufs[BCJ2_STREAM_RC] = buf; + return True; + } + *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32)); + p->cache = 0xFF; + } + while (--p->cacheSize); + p->bufs[BCJ2_STREAM_RC] = buf; + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; + return False; +} + +static void Bcj2Enc_Encode_2(CBcj2Enc *p) +{ + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return; + SetBe32(cur, p->tempTarget); + p->bufs[p->state] = cur + 4; + } + + p->state = BCJ2_ENC_STATE_ORIG; + + for (;;) + { + if (p->range < kTopValue) + { + if (RangeEnc_ShiftLow(p)) + return; + p->range <<= 8; + } + + { + { + const Byte *src = p->src; + const Byte *srcLim; + Byte *dest; + SizeT num = p->srcLim - src; + + if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + { + if (num <= 4) + return; + num -= 4; + } + else if (num == 0) + break; + + dest = p->bufs[BCJ2_STREAM_MAIN]; + if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest)) + { + num = p->lims[BCJ2_STREAM_MAIN] - dest; + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return; + } + } + + srcLim = src + num; + + if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->src; + + if (src == srcLim) + { + p->prevByte = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = dest; + p->src = src; + p->ip += (UInt32)num; + continue; + } + + { + Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]); + BoolInt needConvert; + + p->bufs[BCJ2_STREAM_MAIN] = dest + 1; + p->ip += (UInt32)num + 1; + src++; + + needConvert = False; + + if ((SizeT)(p->srcLim - src) >= 4) + { + UInt32 relatVal = GetUi32(src); + if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize) + && ((relatVal + p->relatLimit) >> 1) < p->relatLimit) + needConvert = True; + } + + { + UInt32 bound; + unsigned ttt; + Byte b = src[-1]; + CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0)); + + ttt = *prob; + bound = (p->range >> kNumModelBits) * ttt; + + if (!needConvert) + { + p->range = bound; + *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + p->src = src; + p->prevByte = b; + continue; + } + + p->low += bound; + p->range -= bound; + *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); + + { + UInt32 relatVal = GetUi32(src); + UInt32 absVal; + p->ip += 4; + absVal = p->ip + relatVal; + p->prevByte = src[3]; + src += 4; + p->src = src; + { + unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + Byte *cur = p->bufs[cj]; + if (cur == p->lims[cj]) + { + p->state = cj; + p->tempTarget = absVal; + return; + } + SetBe32(cur, absVal); + p->bufs[cj] = cur + 4; + } + } + } + } + } + } + } + + if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + return; + + for (; p->flushPos < 5; p->flushPos++) + if (RangeEnc_ShiftLow(p)) + return; + p->state = BCJ2_ENC_STATE_OK; +} + + +void Bcj2Enc_Encode(CBcj2Enc *p) +{ + PRF(printf("\n")); + PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + if (p->tempPos != 0) + { + unsigned extra = 0; + + for (;;) + { + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + EBcj2Enc_FinishMode finishMode = p->finishMode; + + p->src = p->temp; + p->srcLim = p->temp + p->tempPos; + if (src != srcLim) + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + Bcj2Enc_Encode_2(p); + + { + unsigned num = (unsigned)(p->src - p->temp); + unsigned tempPos = p->tempPos - num; + unsigned i; + p->tempPos = tempPos; + for (i = 0; i < tempPos; i++) + p->temp[i] = p->temp[(size_t)i + num]; + + p->src = src; + p->srcLim = srcLim; + p->finishMode = finishMode; + + if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim) + return; + + if (extra >= tempPos) + { + p->src = src - tempPos; + p->tempPos = 0; + break; + } + + p->temp[tempPos] = src[0]; + p->tempPos = tempPos + 1; + p->src = src + 1; + extra++; + } + } + } + + PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + Bcj2Enc_Encode_2(p); + + if (p->state == BCJ2_ENC_STATE_ORIG) + { + const Byte *src = p->src; + unsigned rem = (unsigned)(p->srcLim - src); + unsigned i; + for (i = 0; i < rem; i++) + p->temp[i] = src[i]; + p->tempPos = rem; + p->src = src + rem; + } +} diff --git a/utils/lzma/C/Bra.c b/utils/lzma/C/Bra.c new file mode 100644 index 0000000..aed17e3 --- /dev/null +++ b/utils/lzma/C/Bra.c @@ -0,0 +1,230 @@ +/* Bra.c -- Converters for RISC code +2017-04-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "Bra.h" + +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)3; + ip += 4; + p = data; + lim = data + size; + + if (encoding) + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + p += 4; + if (p[-1] == 0xEB) + break; + } + { + UInt32 v = GetUi32(p - 4); + v <<= 2; + v += ip + (UInt32)(p - data); + v >>= 2; + v &= 0x00FFFFFF; + v |= 0xEB000000; + SetUi32(p - 4, v); + } + } + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + p += 4; + if (p[-1] == 0xEB) + break; + } + { + UInt32 v = GetUi32(p - 4); + v <<= 2; + v -= ip + (UInt32)(p - data); + v >>= 2; + v &= 0x00FFFFFF; + v |= 0xEB000000; + SetUi32(p - 4, v); + } + } +} + + +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)1; + p = data; + lim = data + size - 4; + + if (encoding) + + for (;;) + { + UInt32 b1; + for (;;) + { + UInt32 b3; + if (p > lim) + return p - data; + b1 = p[1]; + b3 = p[3]; + p += 2; + b1 ^= 8; + if ((b3 & b1) >= 0xF8) + break; + } + { + UInt32 v = + ((UInt32)b1 << 19) + + (((UInt32)p[1] & 0x7) << 8) + + (((UInt32)p[-2] << 11)) + + (p[0]); + + p += 2; + { + UInt32 cur = (ip + (UInt32)(p - data)) >> 1; + v += cur; + } + + p[-4] = (Byte)(v >> 11); + p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); + p[-2] = (Byte)v; + p[-1] = (Byte)(0xF8 | (v >> 8)); + } + } + + for (;;) + { + UInt32 b1; + for (;;) + { + UInt32 b3; + if (p > lim) + return p - data; + b1 = p[1]; + b3 = p[3]; + p += 2; + b1 ^= 8; + if ((b3 & b1) >= 0xF8) + break; + } + { + UInt32 v = + ((UInt32)b1 << 19) + + (((UInt32)p[1] & 0x7) << 8) + + (((UInt32)p[-2] << 11)) + + (p[0]); + + p += 2; + { + UInt32 cur = (ip + (UInt32)(p - data)) >> 1; + v -= cur; + } + + /* + SetUi16(p - 4, (UInt16)(((v >> 11) & 0x7FF) | 0xF000)); + SetUi16(p - 2, (UInt16)(v | 0xF800)); + */ + + p[-4] = (Byte)(v >> 11); + p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); + p[-2] = (Byte)v; + p[-1] = (Byte)(0xF8 | (v >> 8)); + } + } +} + + +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)3; + ip -= 4; + p = data; + lim = data + size; + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + p += 4; + /* if ((v & 0xFC000003) == 0x48000001) */ + if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) + break; + } + { + UInt32 v = GetBe32(p - 4); + if (encoding) + v += ip + (UInt32)(p - data); + else + v -= ip + (UInt32)(p - data); + v &= 0x03FFFFFF; + v |= 0x48000000; + SetBe32(p - 4, v); + } + } +} + + +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)3; + ip -= 4; + p = data; + lim = data + size; + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + /* + v = GetBe32(p); + p += 4; + m = v + ((UInt32)5 << 29); + m ^= (UInt32)7 << 29; + m += (UInt32)1 << 22; + if ((m & ((UInt32)0x1FF << 23)) == 0) + break; + */ + p += 4; + if ((p[-4] == 0x40 && (p[-3] & 0xC0) == 0) || + (p[-4] == 0x7F && (p[-3] >= 0xC0))) + break; + } + { + UInt32 v = GetBe32(p - 4); + v <<= 2; + if (encoding) + v += ip + (UInt32)(p - data); + else + v -= ip + (UInt32)(p - data); + + v &= 0x01FFFFFF; + v -= (UInt32)1 << 24; + v ^= 0xFF000000; + v >>= 2; + v |= 0x40000000; + SetBe32(p - 4, v); + } + } +} diff --git a/utils/lzma/C/Bra.h b/utils/lzma/C/Bra.h new file mode 100644 index 0000000..855e37a --- /dev/null +++ b/utils/lzma/C/Bra.h @@ -0,0 +1,64 @@ +/* Bra.h -- Branch converters for executables +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __BRA_H +#define __BRA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +These functions convert relative addresses to absolute addresses +in CALL instructions to increase the compression ratio. + + In: + data - data buffer + size - size of data + ip - current virtual Instruction Pinter (IP) value + state - state variable for x86 converter + encoding - 0 (for decoding), 1 (for encoding) + + Out: + state - state variable for x86 converter + + Returns: + The number of processed bytes. If you call these functions with multiple calls, + you must start next call with first byte after block of processed bytes. + + Type Endian Alignment LookAhead + + x86 little 1 4 + ARMT little 2 2 + ARM little 4 0 + PPC big 4 0 + SPARC big 4 0 + IA64 little 16 0 + + size must be >= Alignment + LookAhead, if it's not last block. + If (size < Alignment + LookAhead), converter returns 0. + + Example: + + UInt32 ip = 0; + for () + { + ; size must be >= Alignment + LookAhead, if it's not last block + SizeT processed = Convert(data, size, ip, 1); + data += processed; + size -= processed; + ip += processed; + } +*/ + +#define x86_Convert_Init(state) { state = 0; } +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Bra86.c b/utils/lzma/C/Bra86.c new file mode 100644 index 0000000..93ed4d7 --- /dev/null +++ b/utils/lzma/C/Bra86.c @@ -0,0 +1,82 @@ +/* Bra86.c -- Converter for x86 code (BCJ) +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bra.h" + +#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) + +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) +{ + SizeT pos = 0; + UInt32 mask = *state & 7; + if (size < 5) + return 0; + size -= 4; + ip += 5; + + for (;;) + { + Byte *p = data + pos; + const Byte *limit = data + size; + for (; p < limit; p++) + if ((*p & 0xFE) == 0xE8) + break; + + { + SizeT d = (SizeT)(p - data - pos); + pos = (SizeT)(p - data); + if (p >= limit) + { + *state = (d > 2 ? 0 : mask >> (unsigned)d); + return pos; + } + if (d > 2) + mask = 0; + else + { + mask >>= (unsigned)d; + if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1]))) + { + mask = (mask >> 1) | 4; + pos++; + continue; + } + } + } + + if (Test86MSByte(p[4])) + { + UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 cur = ip + (UInt32)pos; + pos += 5; + if (encoding) + v += cur; + else + v -= cur; + if (mask != 0) + { + unsigned sh = (mask & 6) << 2; + if (Test86MSByte((Byte)(v >> sh))) + { + v ^= (((UInt32)0x100 << sh) - 1); + if (encoding) + v += cur; + else + v -= cur; + } + mask = 0; + } + p[1] = (Byte)v; + p[2] = (Byte)(v >> 8); + p[3] = (Byte)(v >> 16); + p[4] = (Byte)(0 - ((v >> 24) & 1)); + } + else + { + mask = (mask >> 1) | 4; + pos++; + } + } +} diff --git a/utils/lzma/C/BraIA64.c b/utils/lzma/C/BraIA64.c new file mode 100644 index 0000000..d1dbc62 --- /dev/null +++ b/utils/lzma/C/BraIA64.c @@ -0,0 +1,53 @@ +/* BraIA64.c -- Converter for IA-64 code +2017-01-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "Bra.h" + +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 16) + return 0; + size -= 16; + i = 0; + do + { + unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3; + if (m) + { + m++; + do + { + Byte *p = data + (i + (size_t)m * 5 - 8); + if (((p[3] >> m) & 15) == 5 + && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0) + { + unsigned raw = GetUi32(p); + unsigned v = raw >> m; + v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3); + + v <<= 4; + if (encoding) + v += ip + (UInt32)i; + else + v -= ip + (UInt32)i; + v >>= 4; + + v &= 0x1FFFFF; + v += 0x700000; + v &= 0x8FFFFF; + raw &= ~((UInt32)0x8FFFFF << m); + raw |= (v << m); + SetUi32(p, raw); + } + } + while (++m <= 4); + } + i += 16; + } + while (i <= size); + return i; +} diff --git a/utils/lzma/C/Compiler.h b/utils/lzma/C/Compiler.h new file mode 100644 index 0000000..0cc409d --- /dev/null +++ b/utils/lzma/C/Compiler.h @@ -0,0 +1,33 @@ +/* Compiler.h +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_COMPILER_H +#define __7Z_COMPILER_H + +#ifdef _MSC_VER + + #ifdef UNDER_CE + #define RPC_NO_WINDOWS_H + /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ + #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int + #endif + + #if _MSC_VER >= 1300 + #pragma warning(disable : 4996) // This function or variable may be unsafe + #else + #pragma warning(disable : 4511) // copy constructor could not be generated + #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4702) // unreachable code + #pragma warning(disable : 4710) // not inlined + #pragma warning(disable : 4714) // function marked as __forceinline not inlined + #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information + #endif + +#endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ + +#endif diff --git a/utils/lzma/C/CpuArch.c b/utils/lzma/C/CpuArch.c new file mode 100644 index 0000000..02e482e --- /dev/null +++ b/utils/lzma/C/CpuArch.c @@ -0,0 +1,218 @@ +/* CpuArch.c -- CPU specific code +2018-02-18: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + +#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) +#define USE_ASM +#endif + +#if !defined(USE_ASM) && _MSC_VER >= 1500 +#include +#endif + +#if defined(USE_ASM) && !defined(MY_CPU_AMD64) +static UInt32 CheckFlag(UInt32 flag) +{ + #ifdef _MSC_VER + __asm pushfd; + __asm pop EAX; + __asm mov EDX, EAX; + __asm xor EAX, flag; + __asm push EAX; + __asm popfd; + __asm pushfd; + __asm pop EAX; + __asm xor EAX, EDX; + __asm push EDX; + __asm popfd; + __asm and flag, EAX; + #else + __asm__ __volatile__ ( + "pushf\n\t" + "pop %%EAX\n\t" + "movl %%EAX,%%EDX\n\t" + "xorl %0,%%EAX\n\t" + "push %%EAX\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%EAX\n\t" + "xorl %%EDX,%%EAX\n\t" + "push %%EDX\n\t" + "popf\n\t" + "andl %%EAX, %0\n\t": + "=c" (flag) : "c" (flag) : + "%eax", "%edx"); + #endif + return flag; +} +#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif + +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +{ + #ifdef USE_ASM + + #ifdef _MSC_VER + + UInt32 a2, b2, c2, d2; + __asm xor EBX, EBX; + __asm xor ECX, ECX; + __asm xor EDX, EDX; + __asm mov EAX, function; + __asm cpuid; + __asm mov a2, EAX; + __asm mov b2, EBX; + __asm mov c2, ECX; + __asm mov d2, EDX; + + *a = a2; + *b = b2; + *c = c2; + *d = d2; + + #else + + __asm__ __volatile__ ( + #if defined(MY_CPU_AMD64) && defined(__PIC__) + "mov %%rbx, %%rdi;" + "cpuid;" + "xchg %%rbx, %%rdi;" + : "=a" (*a) , + "=D" (*b) , + #elif defined(MY_CPU_X86) && defined(__PIC__) + "mov %%ebx, %%edi;" + "cpuid;" + "xchgl %%ebx, %%edi;" + : "=a" (*a) , + "=D" (*b) , + #else + "cpuid" + : "=a" (*a) , + "=b" (*b) , + #endif + "=c" (*c) , + "=d" (*d) + : "0" (function)) ; + + #endif + + #else + + int CPUInfo[4]; + __cpuid(CPUInfo, function); + *a = CPUInfo[0]; + *b = CPUInfo[1]; + *c = CPUInfo[2]; + *d = CPUInfo[3]; + + #endif +} + +BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p) +{ + CHECK_CPUID_IS_SUPPORTED + MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); + MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + return True; +} + +static const UInt32 kVendors[][3] = +{ + { 0x756E6547, 0x49656E69, 0x6C65746E}, + { 0x68747541, 0x69746E65, 0x444D4163}, + { 0x746E6543, 0x48727561, 0x736C7561} +}; + +int x86cpuid_GetFirm(const Cx86cpuid *p) +{ + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + { + const UInt32 *v = kVendors[i]; + if (v[0] == p->vendor[0] && + v[1] == p->vendor[1] && + v[2] == p->vendor[2]) + return (int)i; + } + return -1; +} + +BoolInt CPU_Is_InOrder() +{ + Cx86cpuid p; + int firm; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; + + family = x86cpuid_GetFamily(p.ver); + model = x86cpuid_GetModel(p.ver); + + firm = x86cpuid_GetFirm(&p); + + switch (firm) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + /* In-Order Atom CPU */ + model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x26 /* 45 nm, Z6xx */ + || model == 0x27 /* 32 nm, Z2460 */ + || model == 0x35 /* 32 nm, Z2760 */ + || model == 0x36 /* 32 nm, N2xxx, D2xxx */ + ))); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return True; +} + +#if !defined(MY_CPU_AMD64) && defined(_WIN32) +#include +static BoolInt CPU_Sys_Is_SSE_Supported() +{ + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi)) + return False; + return (vi.dwMajorVersion >= 5); +} +#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; +#else +#define CHECK_SYS_SSE_SUPPORT +#endif + +BoolInt CPU_Is_Aes_Supported() +{ + Cx86cpuid p; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_CheckAndRead(&p)) + return False; + return (p.c >> 25) & 1; +} + +BoolInt CPU_IsSupported_PageGB() +{ + Cx86cpuid cpuid; + if (!x86cpuid_CheckAndRead(&cpuid)) + return False; + { + UInt32 d[4] = { 0 }; + MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]); + if (d[0] < 0x80000001) + return False; + } + { + UInt32 d[4] = { 0 }; + MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]); + return (d[3] >> 26) & 1; + } +} + +#endif diff --git a/utils/lzma/C/CpuArch.h b/utils/lzma/C/CpuArch.h new file mode 100644 index 0000000..bd42938 --- /dev/null +++ b/utils/lzma/C/CpuArch.h @@ -0,0 +1,336 @@ +/* CpuArch.h -- CPU specific code +2018-02-18 : Igor Pavlov : Public domain */ + +#ifndef __CPU_ARCH_H +#define __CPU_ARCH_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +MY_CPU_LE means that CPU is LITTLE ENDIAN. +MY_CPU_BE means that CPU is BIG ENDIAN. +If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. + +MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. +*/ + +#if defined(_M_X64) \ + || defined(_M_AMD64) \ + || defined(__x86_64__) \ + || defined(__AMD64__) \ + || defined(__amd64__) + #define MY_CPU_AMD64 + #ifdef __ILP32__ + #define MY_CPU_NAME "x32" + #else + #define MY_CPU_NAME "x64" + #endif + #define MY_CPU_64BIT +#endif + + +#if defined(_M_IX86) \ + || defined(__i386__) + #define MY_CPU_X86 + #define MY_CPU_NAME "x86" + #define MY_CPU_32BIT +#endif + + +#if defined(_M_ARM64) \ + || defined(__AARCH64EL__) \ + || defined(__AARCH64EB__) \ + || defined(__aarch64__) + #define MY_CPU_ARM64 + #define MY_CPU_NAME "arm64" + #define MY_CPU_64BIT +#endif + + +#if defined(_M_ARM) \ + || defined(_M_ARM_NT) \ + || defined(_M_ARMT) \ + || defined(__arm__) \ + || defined(__thumb__) \ + || defined(__ARMEL__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEL__) \ + || defined(__THUMBEB__) + #define MY_CPU_ARM + #define MY_CPU_NAME "arm" + #define MY_CPU_32BIT +#endif + + +#if defined(_M_IA64) \ + || defined(__ia64__) + #define MY_CPU_IA64 + #define MY_CPU_NAME "ia64" + #define MY_CPU_64BIT +#endif + + +#if defined(__mips64) \ + || defined(__mips64__) \ + || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3)) + #define MY_CPU_NAME "mips64" + #define MY_CPU_64BIT +#elif defined(__mips__) + #define MY_CPU_NAME "mips" + /* #define MY_CPU_32BIT */ +#endif + + +#if defined(__ppc64__) \ + || defined(__powerpc64__) + #ifdef __ILP32__ + #define MY_CPU_NAME "ppc64-32" + #else + #define MY_CPU_NAME "ppc64" + #endif + #define MY_CPU_64BIT +#elif defined(__ppc__) \ + || defined(__powerpc__) + #define MY_CPU_NAME "ppc" + #define MY_CPU_32BIT +#endif + + +#if defined(__sparc64__) + #define MY_CPU_NAME "sparc64" + #define MY_CPU_64BIT +#elif defined(__sparc__) + #define MY_CPU_NAME "sparc" + /* #define MY_CPU_32BIT */ +#endif + + +#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) +#define MY_CPU_X86_OR_AMD64 +#endif + + +#ifdef _WIN32 + + #ifdef MY_CPU_ARM + #define MY_CPU_ARM_LE + #endif + + #ifdef MY_CPU_ARM64 + #define MY_CPU_ARM64_LE + #endif + + #ifdef _M_IA64 + #define MY_CPU_IA64_LE + #endif + +#endif + + +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_LE) \ + || defined(MY_CPU_ARM64_LE) \ + || defined(MY_CPU_IA64_LE) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__AARCH64EL__) \ + || defined(__MIPSEL__) \ + || defined(__MIPSEL) \ + || defined(_MIPSEL) \ + || defined(__BFIN__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + #define MY_CPU_LE +#endif + +#if defined(__BIG_ENDIAN__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) \ + || defined(__AARCH64EB__) \ + || defined(__MIPSEB__) \ + || defined(__MIPSEB) \ + || defined(_MIPSEB) \ + || defined(__m68k__) \ + || defined(__s390__) \ + || defined(__s390x__) \ + || defined(__zarch__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define MY_CPU_BE +#endif + + +#if defined(MY_CPU_LE) && defined(MY_CPU_BE) + #error Stop_Compiling_Bad_Endian +#endif + + +#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT) + #error Stop_Compiling_Bad_32_64_BIT +#endif + + +#ifndef MY_CPU_NAME + #ifdef MY_CPU_LE + #define MY_CPU_NAME "LE" + #elif defined(MY_CPU_BE) + #define MY_CPU_NAME "BE" + #else + /* + #define MY_CPU_NAME "" + */ + #endif +#endif + + + + + +#ifdef MY_CPU_LE + #if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM64) \ + || defined(__ARM_FEATURE_UNALIGNED) + #define MY_CPU_LE_UNALIGN + #endif +#endif + + +#ifdef MY_CPU_LE_UNALIGN + +#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) +#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) + +#define SetUi16(p, v) { *(UInt16 *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(p) = (v); } +#define SetUi64(p, v) { *(UInt64 *)(p) = (v); } + +#else + +#define GetUi16(p) ( (UInt16) ( \ + ((const Byte *)(p))[0] | \ + ((UInt16)((const Byte *)(p))[1] << 8) )) + +#define GetUi32(p) ( \ + ((const Byte *)(p))[0] | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((UInt32)((const Byte *)(p))[2] << 16) | \ + ((UInt32)((const Byte *)(p))[3] << 24)) + +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) + +#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); } + +#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); \ + _ppp_[2] = (Byte)(_vvv_ >> 16); \ + _ppp_[3] = (Byte)(_vvv_ >> 24); } + +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_); \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } + +#endif + +#ifdef __has_builtin + #define MY__has_builtin(x) __has_builtin(x) +#else + #define MY__has_builtin(x) 0 +#endif + +#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300) + +/* Note: we use bswap instruction, that is unsupported in 386 cpu */ + +#include + +#pragma intrinsic(_byteswap_ushort) +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) + +/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */ +#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) + +#elif defined(MY_CPU_LE_UNALIGN) && ( \ + (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ + || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) ) + +/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */ +#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) + +#else + +#define GetBe32(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 24) | \ + ((UInt32)((const Byte *)(p))[1] << 16) | \ + ((UInt32)((const Byte *)(p))[2] << 8) | \ + ((const Byte *)(p))[3] ) + +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) + +#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 24); \ + _ppp_[1] = (Byte)(_vvv_ >> 16); \ + _ppp_[2] = (Byte)(_vvv_ >> 8); \ + _ppp_[3] = (Byte)_vvv_; } + +#endif + + +#ifndef GetBe16 + +#define GetBe16(p) ( (UInt16) ( \ + ((UInt16)((const Byte *)(p))[0] << 8) | \ + ((const Byte *)(p))[1] )) + +#endif + + + +#ifdef MY_CPU_X86_OR_AMD64 + +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum +{ + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA +}; + +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); + +BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p); +int x86cpuid_GetFirm(const Cx86cpuid *p); + +#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) +#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) +#define x86cpuid_GetStepping(ver) (ver & 0xF) + +BoolInt CPU_Is_InOrder(); +BoolInt CPU_Is_Aes_Supported(); +BoolInt CPU_IsSupported_PageGB(); + +#endif + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Delta.c b/utils/lzma/C/Delta.c new file mode 100644 index 0000000..e3edd21 --- /dev/null +++ b/utils/lzma/C/Delta.c @@ -0,0 +1,64 @@ +/* Delta.c -- Delta converter +2009-05-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Delta.h" + +void Delta_Init(Byte *state) +{ + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; +} + +static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) +{ + unsigned i; + for (i = 0; i < size; i++) + dest[i] = src[i]; +} + +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + Byte b = data[i]; + data[i] = (Byte)(b - buf[j]); + buf[j] = b; + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} + +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + buf[j] = data[i] = (Byte)(buf[j] + data[i]); + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} diff --git a/utils/lzma/C/Delta.h b/utils/lzma/C/Delta.h new file mode 100644 index 0000000..2fa54ad --- /dev/null +++ b/utils/lzma/C/Delta.h @@ -0,0 +1,19 @@ +/* Delta.h -- Delta converter +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __DELTA_H +#define __DELTA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define DELTA_STATE_SIZE 256 + +void Delta_Init(Byte *state); +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/DllSecur.c b/utils/lzma/C/DllSecur.c new file mode 100644 index 0000000..5ea108a --- /dev/null +++ b/utils/lzma/C/DllSecur.c @@ -0,0 +1,108 @@ +/* DllSecur.c -- DLL loading security +2018-02-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 + +#include + +#include "DllSecur.h" + +#ifndef UNDER_CE + +typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); + +#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 +#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 + +static const char * const g_Dlls = + #ifndef _CONSOLE + "UXTHEME\0" + #endif + "USERENV\0" + "SETUPAPI\0" + "APPHELP\0" + "PROPSYS\0" + "DWMAPI\0" + "CRYPTBASE\0" + "OLEACC\0" + "CLBCATQ\0" + "VERSION\0" + ; + +#endif + +void My_SetDefaultDllDirectories() +{ + #ifndef UNDER_CE + + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + GetVersionEx(&vi); + if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) + { + Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); + if (setDllDirs) + if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) + return; + } + + #endif +} + + +void LoadSecurityDlls() +{ + #ifndef UNDER_CE + + wchar_t buf[MAX_PATH + 100]; + + { + // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ??? + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) + { + Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); + if (setDllDirs) + if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) + return; + } + } + + { + unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2); + if (len == 0 || len > MAX_PATH) + return; + } + { + const char *dll; + unsigned pos = (unsigned)lstrlenW(buf); + + if (buf[pos - 1] != '\\') + buf[pos++] = '\\'; + + for (dll = g_Dlls; dll[0] != 0;) + { + unsigned k = 0; + for (;;) + { + char c = *dll++; + buf[pos + k] = (Byte)c; + k++; + if (c == 0) + break; + } + + lstrcatW(buf, L".dll"); + LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } + } + + #endif +} + +#endif diff --git a/utils/lzma/C/DllSecur.h b/utils/lzma/C/DllSecur.h new file mode 100644 index 0000000..e2a049a --- /dev/null +++ b/utils/lzma/C/DllSecur.h @@ -0,0 +1,20 @@ +/* DllSecur.h -- DLL loading for security +2018-02-19 : Igor Pavlov : Public domain */ + +#ifndef __DLL_SECUR_H +#define __DLL_SECUR_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#ifdef _WIN32 + +void My_SetDefaultDllDirectories(); +void LoadSecurityDlls(); + +#endif + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/LzFind.c b/utils/lzma/C/LzFind.c new file mode 100644 index 0000000..df55e86 --- /dev/null +++ b/utils/lzma/C/LzFind.c @@ -0,0 +1,1127 @@ +/* LzFind.c -- Match finder for LZ algorithms +2018-07-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "LzFind.h" +#include "LzHash.h" + +#define kEmptyHashValue 0 +#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) +#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ +#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)7 << 29) + +#define kStartMaxLen 3 + +static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) +{ + if (!p->directInput) + { + ISzAlloc_Free(alloc, p->bufferBase); + p->bufferBase = NULL; + } +} + +/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ + +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; + if (p->directInput) + { + p->blockSize = blockSize; + return 1; + } + if (!p->bufferBase || p->blockSize != blockSize) + { + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize); + } + return (p->bufferBase != NULL); +} + +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } + +UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; + p->streamPos -= subValue; +} + +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + + /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ + + if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); + if (curSize > p->directInputRem) + curSize = (UInt32)p->directInputRem; + p->directInputRem -= curSize; + p->streamPos += curSize; + if (p->directInputRem == 0) + p->streamEndWasReached = 1; + return; + } + + for (;;) + { + Byte *dest = p->buffer + (p->streamPos - p->pos); + size_t size = (p->bufferBase + p->blockSize - dest); + if (size == 0) + return; + + p->result = ISeqInStream_Read(p->stream, dest, &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (p->streamPos - p->pos > p->keepSizeAfter) + return; + } +} + +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos) + p->keepSizeBefore); + p->buffer = p->bufferBase + p->keepSizeBefore; +} + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + if (p->directInput) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->streamEndWasReached) + return; + if (p->keepSizeAfter >= p->streamPos - p->pos) + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + unsigned i; + p->bufferBase = NULL; + p->directInput = 0; + p->hash = NULL; + p->expectedDataSize = (UInt64)(Int64)-1; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = (UInt32)i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + p->crc[i] = r; + } +} + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->hash); + p->hash = NULL; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) +{ + size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return NULL; + return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes); +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc) +{ + UInt32 sizeReserv; + + if (historySize > kMaxHistorySize) + { + MatchFinder_Free(p, alloc); + return 0; + } + + sizeReserv = historySize >> 1; + if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3; + else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2; + + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + + if (LzInWindow_Create(p, sizeReserv, alloc)) + { + UInt32 newCyclicBufferSize = historySize + 1; + UInt32 hs; + p->matchMaxLen = matchMaxLen; + { + p->fixedHashSize = 0; + if (p->numHashBytes == 2) + hs = (1 << 16) - 1; + else + { + hs = historySize; + if (hs > p->expectedDataSize) + hs = (UInt32)p->expectedDataSize; + if (hs != 0) + hs--; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; /* don't change it! It's required for Deflate */ + if (hs > (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + } + } + p->hashMask = hs; + hs++; + if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; + if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; + if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; + hs += p->fixedHashSize; + } + + { + size_t newSize; + size_t numSons; + p->historySize = historySize; + p->hashSizeSum = hs; + p->cyclicBufferSize = newCyclicBufferSize; + + numSons = newCyclicBufferSize; + if (p->btMode) + numSons <<= 1; + newSize = hs + numSons; + + if (p->hash && p->numRefs == newSize) + return 1; + + MatchFinder_FreeThisClassMemory(p, alloc); + p->numRefs = newSize; + p->hash = AllocRefs(newSize, alloc); + + if (p->hash) + { + p->son = p->hash + p->hashSizeSum; + return 1; + } + } + } + + MatchFinder_Free(p, alloc); + return 0; +} + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 limit = kMaxValForNormalize - p->pos; + UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + + if (limit2 < limit) + limit = limit2; + limit2 = p->streamPos - p->pos; + + if (limit2 <= p->keepSizeAfter) + { + if (limit2 > 0) + limit2 = 1; + } + else + limit2 -= p->keepSizeAfter; + + if (limit2 < limit) + limit = limit2; + + { + UInt32 lenLimit = p->streamPos - p->pos; + if (lenLimit > p->matchMaxLen) + lenLimit = p->matchMaxLen; + p->lenLimit = lenLimit; + } + p->posLimit = p->pos + limit; +} + + +void MatchFinder_Init_LowHash(CMatchFinder *p) +{ + size_t i; + CLzRef *items = p->hash; + size_t numItems = p->fixedHashSize; + for (i = 0; i < numItems; i++) + items[i] = kEmptyHashValue; +} + + +void MatchFinder_Init_HighHash(CMatchFinder *p) +{ + size_t i; + CLzRef *items = p->hash + p->fixedHashSize; + size_t numItems = (size_t)p->hashMask + 1; + for (i = 0; i < numItems; i++) + items[i] = kEmptyHashValue; +} + + +void MatchFinder_Init_3(CMatchFinder *p, int readData) +{ + p->cyclicBufferPos = 0; + p->buffer = p->bufferBase; + p->pos = + p->streamPos = p->cyclicBufferSize; + p->result = SZ_OK; + p->streamEndWasReached = 0; + + if (readData) + MatchFinder_ReadBlock(p); + + MatchFinder_SetLimits(p); +} + + +void MatchFinder_Init(CMatchFinder *p) +{ + MatchFinder_Init_HighHash(p); + MatchFinder_Init_LowHash(p); + MatchFinder_Init_3(p, True); +} + + +static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) +{ + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) +{ + size_t i; + for (i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } +} + +static void MatchFinder_Normalize(CMatchFinder *p) +{ + UInt32 subValue = MatchFinder_GetSubValue(p); + MatchFinder_Normalize3(subValue, p->hash, p->numRefs); + MatchFinder_ReduceOffsets(p, subValue); +} + + +MY_NO_INLINE +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (p->pos == kMaxValForNormalize) + MatchFinder_Normalize(p); + if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) + MatchFinder_CheckAndMoveAndRead(p); + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); +} + + +/* + (lenLimit > maxLen) +*/ +MY_FORCE_INLINE +static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, unsigned maxLen) +{ + /* + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return distances; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *distances++ = len; + *distances++ = delta - 1; + if (len == lenLimit) + return distances; + } + } + } + } + */ + + const Byte *lim = cur + lenLimit; + son[_cyclicBufferPos] = curMatch; + do + { + UInt32 delta = pos - curMatch; + if (delta >= _cyclicBufferSize) + break; + { + ptrdiff_t diff; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + diff = (ptrdiff_t)0 - delta; + if (cur[maxLen] == cur[maxLen + diff]) + { + const Byte *c = cur; + while (*c == c[diff]) + { + if (++c == lim) + { + distances[0] = (UInt32)(lim - cur); + distances[1] = delta - 1; + return distances + 2; + } + } + { + unsigned len = (unsigned)(c - cur); + if (maxLen < len) + { + maxLen = len; + distances[0] = (UInt32)len; + distances[1] = delta - 1; + distances += 2; + } + } + } + } + } + while (--cutValue); + + return distances; +} + + +MY_FORCE_INLINE +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return distances; + } + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + UInt32 pair0 = pair[0]; + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = (UInt32)len; + *distances++ = (UInt32)len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair0; + *ptr0 = pair[1]; + return distances; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return; + } + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +#define MOVE_POS \ + ++p->cyclicBufferPos; \ + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +#define MOVE_POS_RET MOVE_POS return (UInt32)offset; + +static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ + lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) +#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define GET_MATCHES_FOOTER(offset, maxLen) \ + offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \ + distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ + SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; + +#define UPDATE_maxLen { \ + ptrdiff_t diff = (ptrdiff_t)0 - d2; \ + const Byte *c = cur + maxLen; \ + const Byte *lim = cur + lenLimit; \ + for (; c != lim; c++) if (*(c + diff) != *c) break; \ + maxLen = (unsigned)(c - cur); } + +static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + unsigned offset; + GET_MATCHES_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 1) +} + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + unsigned offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 2) +} + +static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, d2, pos; + unsigned maxLen, offset; + UInt32 *hash; + GET_MATCHES_HEADER(3) + + HASH3_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[h2]; + + curMatch = (hash + kFix3HashSize)[hv]; + + hash[h2] = pos; + (hash + kFix3HashSize)[hv] = pos; + + maxLen = 2; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + UPDATE_maxLen + distances[0] = (UInt32)maxLen; + distances[1] = d2 - 1; + offset = 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen, offset; + UInt32 *hash; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + + curMatch = (hash + kFix4HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + maxLen = 2; + distances[0] = 2; + distances[1] = d2 - 1; + offset = 2; + } + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + maxLen = 3; + distances[(size_t)offset + 1] = d3 - 1; + offset += 2; + d2 = d3; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 3) + maxLen = 3; + + GET_MATCHES_FOOTER(offset, maxLen) +} + +/* +static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + d4 = pos - (hash + kFix4HashSize)[h4]; + + curMatch = (hash + kFix5HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[h4] = pos; + (hash + kFix5HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[(size_t)offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + GET_MATCHES_FOOTER(offset, maxLen) +} +*/ + +static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen, offset; + UInt32 *hash; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + curMatch = (hash + kFix4HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + maxLen = 2; + distances[0] = 2; + distances[1] = d2 - 1; + offset = 2; + } + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + maxLen = 3; + distances[(size_t)offset + 1] = d3 - 1; + offset += 2; + d2 = d3; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 3) + maxLen = 3; + + offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} + +/* +static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + d4 = pos - (hash + kFix4HashSize)[h4]; + + curMatch = (hash + kFix5HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[h4] = pos; + (hash + kFix5HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[(size_t)offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} +*/ + +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + unsigned offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances, 2) - (distances)); + MOVE_POS_RET +} + +static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2; + UInt32 *hash; + SKIP_HEADER(3) + HASH3_CALC; + hash = p->hash; + curMatch = (hash + kFix3HashSize)[hv]; + hash[h2] = + (hash + kFix3HashSize)[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3; + UInt32 *hash; + SKIP_HEADER(4) + HASH4_CALC; + hash = p->hash; + curMatch = (hash + kFix4HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +/* +static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = (hash + kFix5HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} +*/ + +static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3; + UInt32 *hash; + SKIP_HEADER(4) + HASH4_CALC; + hash = p->hash; + curMatch = (hash + kFix4HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +/* +static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = hash + kFix5HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} +*/ + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + /* if (p->numHashBytes <= 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; + } + */ + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; + } + else /* if (p->numHashBytes == 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; + } + */ +} diff --git a/utils/lzma/C/LzFind.h b/utils/lzma/C/LzFind.h new file mode 100644 index 0000000..42c13be --- /dev/null +++ b/utils/lzma/C/LzFind.h @@ -0,0 +1,121 @@ +/* LzFind.h -- Match finder for LZ algorithms +2017-06-10 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_H +#define __LZ_FIND_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef UInt32 CLzRef; + +typedef struct _CMatchFinder +{ + Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + Byte streamEndWasReached; + Byte btMode; + Byte bigHash; + Byte directInput; + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufferBase; + ISeqInStream *stream; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + size_t directInputRem; + UInt32 historySize; + UInt32 fixedHashSize; + UInt32 hashSizeSum; + SRes result; + UInt32 crc[256]; + size_t numRefs; + + UInt64 expectedDataSize; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +#define Inline_MatchFinder_IsFinishedOK(p) \ + ((p)->streamEndWasReached \ + && (p)->streamPos == (p)->pos \ + && (!(p)->directInput || (p)->directInputRem == 0)) + +int MatchFinder_NeedMove(CMatchFinder *p); +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: + historySize <= 3 GB + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +*/ +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct _IMatchFinder +{ + Mf_Init_Func Init; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +void MatchFinder_Init_LowHash(CMatchFinder *p); +void MatchFinder_Init_HighHash(CMatchFinder *p); +void MatchFinder_Init_3(CMatchFinder *p, int readData); +void MatchFinder_Init(CMatchFinder *p); + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/LzFindMt.c b/utils/lzma/C/LzFindMt.c new file mode 100644 index 0000000..bb0f42c --- /dev/null +++ b/utils/lzma/C/LzFindMt.c @@ -0,0 +1,853 @@ +/* LzFindMt.c -- multithreaded Match finder for LZ algorithms +2018-12-29 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "LzHash.h" + +#include "LzFindMt.h" + +static void MtSync_Construct(CMtSync *p) +{ + p->wasCreated = False; + p->csWasInitialized = False; + p->csWasEntered = False; + Thread_Construct(&p->thread); + Event_Construct(&p->canStart); + Event_Construct(&p->wasStarted); + Event_Construct(&p->wasStopped); + Semaphore_Construct(&p->freeSemaphore); + Semaphore_Construct(&p->filledSemaphore); +} + +static void MtSync_GetNextBlock(CMtSync *p) +{ + if (p->needStart) + { + p->numProcessedBlocks = 1; + p->needStart = False; + p->stopWriting = False; + p->exit = False; + Event_Reset(&p->wasStarted); + Event_Reset(&p->wasStopped); + + Event_Set(&p->canStart); + Event_Wait(&p->wasStarted); + + // if (mt) MatchFinder_Init_LowHash(mt->MatchFinder); + } + else + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + p->numProcessedBlocks++; + Semaphore_Release1(&p->freeSemaphore); + } + Semaphore_Wait(&p->filledSemaphore); + CriticalSection_Enter(&p->cs); + p->csWasEntered = True; +} + +/* MtSync_StopWriting must be called if Writing was started */ + +static void MtSync_StopWriting(CMtSync *p) +{ + UInt32 myNumBlocks = p->numProcessedBlocks; + if (!Thread_WasCreated(&p->thread) || p->needStart) + return; + p->stopWriting = True; + if (p->csWasEntered) + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + } + Semaphore_Release1(&p->freeSemaphore); + + Event_Wait(&p->wasStopped); + + while (myNumBlocks++ != p->numProcessedBlocks) + { + Semaphore_Wait(&p->filledSemaphore); + Semaphore_Release1(&p->freeSemaphore); + } + p->needStart = True; +} + +static void MtSync_Destruct(CMtSync *p) +{ + if (Thread_WasCreated(&p->thread)) + { + MtSync_StopWriting(p); + p->exit = True; + if (p->needStart) + Event_Set(&p->canStart); + Thread_Wait(&p->thread); + Thread_Close(&p->thread); + } + if (p->csWasInitialized) + { + CriticalSection_Delete(&p->cs); + p->csWasInitialized = False; + } + + Event_Close(&p->canStart); + Event_Close(&p->wasStarted); + Event_Close(&p->wasStopped); + Semaphore_Close(&p->freeSemaphore); + Semaphore_Close(&p->filledSemaphore); + + p->wasCreated = False; +} + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + +static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) +{ + if (p->wasCreated) + return SZ_OK; + + RINOK_THREAD(CriticalSection_Init(&p->cs)); + p->csWasInitialized = True; + + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); + + RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); + RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); + + p->needStart = True; + + RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); + p->wasCreated = True; + return SZ_OK; +} + +static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) +{ + SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); + if (res != SZ_OK) + MtSync_Destruct(p); + return res; +} + +void MtSync_Init(CMtSync *p) { p->needStart = True; } + +#define kMtMaxValForNormalize 0xFFFFFFFF + +#define DEF_GetHeads2(name, v, action) \ + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ + { action; for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + +#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) + +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) +DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) +DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) +DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) +/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ + +static void HashThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->hashSync; + for (;;) + { + UInt32 numProcessedBlocks = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + + MatchFinder_Init_HighHash(mt->MatchFinder); + + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = numProcessedBlocks; + Event_Set(&p->wasStopped); + break; + } + + { + CMatchFinder *mf = mt->MatchFinder; + if (MatchFinder_NeedMove(mf)) + { + CriticalSection_Enter(&mt->btSync.cs); + CriticalSection_Enter(&mt->hashSync.cs); + { + const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); + ptrdiff_t offset; + MatchFinder_MoveBlock(mf); + offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= offset; + mt->buffer -= offset; + } + CriticalSection_Leave(&mt->btSync.cs); + CriticalSection_Leave(&mt->hashSync.cs); + continue; + } + + Semaphore_Wait(&p->freeSemaphore); + + MatchFinder_ReadIfRequired(mf); + if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) + { + UInt32 subValue = (mf->pos - mf->historySize - 1); + MatchFinder_ReduceOffsets(mf, subValue); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); + } + { + UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; + UInt32 num = mf->streamPos - mf->pos; + heads[0] = 2; + heads[1] = num; + if (num >= mf->numHashBytes) + { + num = num - mf->numHashBytes + 1; + if (num > kMtHashBlockSize - 2) + num = kMtHashBlockSize - 2; + mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); + heads[0] = 2 + num; + } + mf->pos += num; + mf->buffer += num; + } + } + + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +{ + MtSync_GetNextBlock(&p->hashSync); + p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; + p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; + p->hashNumAvail = p->hashBuf[p->hashBufPos++]; +} + +#define kEmptyHashValue 0 + +#define MFMT_GM_INLINE + +#ifdef MFMT_GM_INLINE + +/* + we use size_t for _cyclicBufferPos instead of UInt32 + to eliminate "movsx" BUG in old MSVC x64 compiler. +*/ + +MY_NO_INLINE +static UInt32 *GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 _maxLen, const UInt32 *hash, const UInt32 *limit, UInt32 size, UInt32 *posRes) +{ + do + { + UInt32 *_distances = ++distances; + UInt32 delta = *hash++; + + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + UInt32 cutValue = _cutValue; + unsigned maxLen = (unsigned)_maxLen; + + /* + if (size > 1) + { + UInt32 delta = *hash; + if (delta < _cyclicBufferSize) + { + UInt32 cyc1 = _cyclicBufferPos + 1; + CLzRef *pair = son + ((size_t)(cyc1 - delta + ((delta > cyc1) ? _cyclicBufferSize : 0)) << 1); + Byte b = *(cur + 1 - delta); + _distances[0] = pair[0]; + _distances[1] = b; + } + } + */ + if (cutValue == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + } + else + for(;;) + { + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((_cyclicBufferPos < delta) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + UInt32 pair0 = *pair; + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *distances++ = (UInt32)len; + *distances++ = delta - 1; + if (len == lenLimit) + { + UInt32 pair1 = pair[1]; + *ptr1 = pair0; + *ptr0 = pair1; + break; + } + } + } + { + UInt32 curMatch = pos - delta; + // delta = pos - *pair; + // delta = pos - pair[((UInt32)pb[len] - (UInt32)cur[len]) >> 31]; + if (pb[len] < cur[len]) + { + delta = pos - pair[1]; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + } + else + { + delta = pos - *pair; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + } + } + } + if (--cutValue == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + break; + } + } + pos++; + _cyclicBufferPos++; + cur++; + { + UInt32 num = (UInt32)(distances - _distances); + _distances[-1] = num; + } + } + while (distances < limit && --size != 0); + *posRes = pos; + return distances; +} + +#endif + + + +static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + UInt32 numProcessed = 0; + UInt32 curPos = 2; + UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); // * 2 + + distances[1] = p->hashNumAvail; + + while (curPos < limit) + { + if (p->hashBufPos == p->hashBufPosLimit) + { + MatchFinderMt_GetNextBlock_Hash(p); + distances[1] = numProcessed + p->hashNumAvail; + if (p->hashNumAvail >= p->numHashBytes) + continue; + distances[0] = curPos + p->hashNumAvail; + distances += curPos; + for (; p->hashNumAvail != 0; p->hashNumAvail--) + *distances++ = 0; + return; + } + { + UInt32 size = p->hashBufPosLimit - p->hashBufPos; + UInt32 lenLimit = p->matchMaxLen; + UInt32 pos = p->pos; + UInt32 cyclicBufferPos = p->cyclicBufferPos; + if (lenLimit >= p->hashNumAvail) + lenLimit = p->hashNumAvail; + { + UInt32 size2 = p->hashNumAvail - lenLimit + 1; + if (size2 < size) + size = size2; + size2 = p->cyclicBufferSize - cyclicBufferPos; + if (size2 < size) + size = size2; + } + + #ifndef MFMT_GM_INLINE + while (curPos < limit && size-- != 0) + { + UInt32 *startDistances = distances + curPos; + UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); + *startDistances = num - 1; + curPos += num; + cyclicBufferPos++; + pos++; + p->buffer++; + } + #else + { + UInt32 posRes; + curPos = (UInt32)(GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, + distances + limit, + size, &posRes) - distances); + p->hashBufPos += posRes - pos; + cyclicBufferPos += posRes - pos; + p->buffer += posRes - pos; + pos = posRes; + } + #endif + + numProcessed += pos - p->pos; + p->hashNumAvail -= pos - p->pos; + p->pos = pos; + if (cyclicBufferPos == p->cyclicBufferSize) + cyclicBufferPos = 0; + p->cyclicBufferPos = cyclicBufferPos; + } + } + + distances[0] = curPos; +} + +static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +{ + CMtSync *sync = &p->hashSync; + if (!sync->needStart) + { + CriticalSection_Enter(&sync->cs); + sync->csWasEntered = True; + } + + BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); + + if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) + { + UInt32 subValue = p->pos - p->cyclicBufferSize; + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); + p->pos -= subValue; + } + + if (!sync->needStart) + { + CriticalSection_Leave(&sync->cs); + sync->csWasEntered = False; + } +} + +void BtThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->btSync; + for (;;) + { + UInt32 blockIndex = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = blockIndex; + MtSync_StopWriting(&mt->hashSync); + Event_Set(&p->wasStopped); + break; + } + Semaphore_Wait(&p->freeSemaphore); + BtFillBlock(mt, blockIndex++); + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +void MatchFinderMt_Construct(CMatchFinderMt *p) +{ + p->hashBuf = NULL; + MtSync_Construct(&p->hashSync); + MtSync_Construct(&p->btSync); +} + +static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->hashBuf); + p->hashBuf = NULL; +} + +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) +{ + MtSync_Destruct(&p->hashSync); + MtSync_Destruct(&p->btSync); + MatchFinderMt_FreeMem(p, alloc); +} + +#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) +#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) +{ + Byte allocaDummy[0x180]; + unsigned i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)0; + if (allocaDummy[0] == 0) + BtThreadFunc((CMatchFinderMt *)p); + return 0; +} + +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc) +{ + CMatchFinder *mf = p->MatchFinder; + p->historySize = historySize; + if (kMtBtBlockSize <= matchMaxLen * 4) + return SZ_ERROR_PARAM; + if (!p->hashBuf) + { + p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); + if (!p->hashBuf) + return SZ_ERROR_MEM; + p->btBuf = p->hashBuf + kHashBufferSize; + } + keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); + keepAddBufferAfter += kMtHashBlockSize; + if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) + return SZ_ERROR_MEM; + + RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); + RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); + return SZ_OK; +} + +/* Call it after ReleaseStream / SetStream */ +static void MatchFinderMt_Init(CMatchFinderMt *p) +{ + CMatchFinder *mf = p->MatchFinder; + + p->btBufPos = + p->btBufPosLimit = 0; + p->hashBufPos = + p->hashBufPosLimit = 0; + + /* Init without data reading. We don't want to read data in this thread */ + MatchFinder_Init_3(mf, False); + MatchFinder_Init_LowHash(mf); + + p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); + p->btNumAvailBytes = 0; + p->lzPos = p->historySize + 1; + + p->hash = mf->hash; + p->fixedHashSize = mf->fixedHashSize; + p->crc = mf->crc; + + p->son = mf->son; + p->matchMaxLen = mf->matchMaxLen; + p->numHashBytes = mf->numHashBytes; + p->pos = mf->pos; + p->buffer = mf->buffer; + p->cyclicBufferPos = mf->cyclicBufferPos; + p->cyclicBufferSize = mf->cyclicBufferSize; + p->cutValue = mf->cutValue; +} + +/* ReleaseStream is required to finish multithreading */ +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) +{ + MtSync_StopWriting(&p->btSync); + /* p->MatchFinder->ReleaseStream(); */ +} + +static void MatchFinderMt_Normalize(CMatchFinderMt *p) +{ + MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); + p->lzPos = p->historySize + 1; +} + +static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +{ + UInt32 blockIndex; + MtSync_GetNextBlock(&p->btSync); + blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); + p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; + p->btBufPosLimit += p->btBuf[p->btBufPos++]; + p->btNumAvailBytes = p->btBuf[p->btBufPos++]; + if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) + MatchFinderMt_Normalize(p); +} + +static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +{ + return p->pointerToCurPos; +} + +#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); + +static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +{ + GET_NEXT_BLOCK_IF_REQUIRED; + return p->btNumAvailBytes; +} + +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 h2, curMatch2; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH2_CALC + + curMatch2 = hash[h2]; + hash[h2] = lzPos; + + if (curMatch2 >= matchMinPos) + if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + *distances++ = 2; + *distances++ = lzPos - curMatch2 - 1; + } + + return distances; +} + +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 h2, h3, curMatch2, curMatch3; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH3_CALC + + curMatch2 = hash[ h2]; + curMatch3 = (hash + kFix3HashSize)[h3]; + + hash[ h2] = lzPos; + (hash + kFix3HashSize)[h3] = lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + *distances++ = 3; + *distances++ = lzPos - curMatch3 - 1; + } + + return distances; +} + +/* +static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH4_CALC + + curMatch2 = hash[ h2]; + curMatch3 = (hash + kFix3HashSize)[h3]; + curMatch4 = (hash + kFix4HashSize)[h4]; + + hash[ h2] = lzPos; + (hash + kFix3HashSize)[h3] = lzPos; + (hash + kFix4HashSize)[h4] = lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch3 - 1; + if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) + { + distances[0] = 4; + return distances + 2; + } + distances[0] = 3; + distances += 2; + } + + if (curMatch4 >= matchMinPos) + if ( + cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && + cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] + ) + { + *distances++ = 4; + *distances++ = lzPos - curMatch4 - 1; + } + + return distances; +} +*/ + +#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; + +static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + p->btNumAvailBytes--; + { + UInt32 i; + for (i = 0; i < len; i += 2) + { + UInt32 v0 = btBuf[0]; + UInt32 v1 = btBuf[1]; + btBuf += 2; + distances[0] = v0; + distances[1] = v1; + distances += 2; + } + } + INCREASE_LZ_POS + return len; +} + +static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + + if (len == 0) + { + /* change for bt5 ! */ + if (p->btNumAvailBytes-- >= 4) + len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); + } + else + { + /* Condition: there are matches in btBuf with length < p->numHashBytes */ + UInt32 *distances2; + p->btNumAvailBytes--; + distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); + do + { + UInt32 v0 = btBuf[0]; + UInt32 v1 = btBuf[1]; + btBuf += 2; + distances2[0] = v0; + distances2[1] = v1; + distances2 += 2; + } + while ((len -= 2) != 0); + len = (UInt32)(distances2 - (distances)); + } + INCREASE_LZ_POS + return len; +} + +#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED +#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; +#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); + +static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER2_MT { p->btNumAvailBytes--; + SKIP_FOOTER_MT +} + +static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(2) + UInt32 h2; + MT_HASH2_CALC + hash[h2] = p->lzPos; + SKIP_FOOTER_MT +} + +static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(3) + UInt32 h2, h3; + MT_HASH3_CALC + (hash + kFix3HashSize)[h3] = + hash[ h2] = + p->lzPos; + SKIP_FOOTER_MT +} + +/* +static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(4) + UInt32 h2, h3, h4; + MT_HASH4_CALC + (hash + kFix4HashSize)[h4] = + (hash + kFix3HashSize)[h3] = + hash[ h2] = + p->lzPos; + SKIP_FOOTER_MT +} +*/ + +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; + + switch (p->MatchFinder->numHashBytes) + { + case 2: + p->GetHeadsFunc = GetHeads2; + p->MixMatchesFunc = (Mf_Mix_Matches)NULL; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; + break; + case 3: + p->GetHeadsFunc = GetHeads3; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; + break; + default: + /* case 4: */ + p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; + break; + /* + default: + p->GetHeadsFunc = GetHeads5; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; + break; + */ + } +} diff --git a/utils/lzma/C/LzFindMt.h b/utils/lzma/C/LzFindMt.h new file mode 100644 index 0000000..ef431e3 --- /dev/null +++ b/utils/lzma/C/LzFindMt.h @@ -0,0 +1,101 @@ +/* LzFindMt.h -- multithreaded Match finder for LZ algorithms +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_MT_H +#define __LZ_FIND_MT_H + +#include "LzFind.h" +#include "Threads.h" + +EXTERN_C_BEGIN + +#define kMtHashBlockSize (1 << 13) +#define kMtHashNumBlocks (1 << 3) +#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) + +#define kMtBtBlockSize (1 << 14) +#define kMtBtNumBlocks (1 << 6) +#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) + +typedef struct _CMtSync +{ + BoolInt wasCreated; + BoolInt needStart; + BoolInt exit; + BoolInt stopWriting; + + CThread thread; + CAutoResetEvent canStart; + CAutoResetEvent wasStarted; + CAutoResetEvent wasStopped; + CSemaphore freeSemaphore; + CSemaphore filledSemaphore; + BoolInt csWasInitialized; + BoolInt csWasEntered; + CCriticalSection cs; + UInt32 numProcessedBlocks; +} CMtSync; + +typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); + +/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ +#define kMtCacheLineDummy 128 + +typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); + +typedef struct _CMatchFinderMt +{ + /* LZ */ + const Byte *pointerToCurPos; + UInt32 *btBuf; + UInt32 btBufPos; + UInt32 btBufPosLimit; + UInt32 lzPos; + UInt32 btNumAvailBytes; + + UInt32 *hash; + UInt32 fixedHashSize; + UInt32 historySize; + const UInt32 *crc; + + Mf_Mix_Matches MixMatchesFunc; + + /* LZ + BT */ + CMtSync btSync; + Byte btDummy[kMtCacheLineDummy]; + + /* BT */ + UInt32 *hashBuf; + UInt32 hashBufPos; + UInt32 hashBufPosLimit; + UInt32 hashNumAvail; + + CLzRef *son; + UInt32 matchMaxLen; + UInt32 numHashBytes; + UInt32 pos; + const Byte *buffer; + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be historySize + 1 */ + UInt32 cutValue; + + /* BT + Hash */ + CMtSync hashSync; + /* Byte hashDummy[kMtCacheLineDummy]; */ + + /* Hash */ + Mf_GetHeads GetHeadsFunc; + CMatchFinder *MatchFinder; +} CMatchFinderMt; + +void MatchFinderMt_Construct(CMatchFinderMt *p); +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc); +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/LzHash.h b/utils/lzma/C/LzHash.h new file mode 100644 index 0000000..e7c9423 --- /dev/null +++ b/utils/lzma/C/LzHash.h @@ -0,0 +1,57 @@ +/* LzHash.h -- HASH functions for LZ algorithms +2015-04-12 : Igor Pavlov : Public domain */ + +#ifndef __LZ_HASH_H +#define __LZ_HASH_H + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +#define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); + +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << 5); \ + h4 = temp & (kHash4Size - 1); \ + hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } + +/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +#define MT_HASH2_CALC \ + h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + +#endif diff --git a/utils/lzma/C/Lzma2Dec.c b/utils/lzma/C/Lzma2Dec.c new file mode 100644 index 0000000..4e138a4 --- /dev/null +++ b/utils/lzma/C/Lzma2Dec.c @@ -0,0 +1,488 @@ +/* Lzma2Dec.c -- LZMA2 Decoder +2019-02-02 : Igor Pavlov : Public domain */ + +/* #define SHOW_DEBUG_INFO */ + +#include "Precomp.h" + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include + +#include "Lzma2Dec.h" + +/* +00000000 - End of data +00000001 U U - Uncompressed, reset dic, need reset state and set new prop +00000010 U U - Uncompressed, no reset +100uuuuu U U P P - LZMA, no reset +101uuuuu U U P P - LZMA, reset state +110uuuuu U U P P S - LZMA, reset state + set new prop +111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic + + u, U - Unpack Size + P - Pack Size + S - Props +*/ + +#define LZMA2_CONTROL_COPY_RESET_DIC 1 + +#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0) + +#define LZMA2_LCLP_MAX 4 +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +typedef enum +{ + LZMA2_STATE_CONTROL, + LZMA2_STATE_UNPACK0, + LZMA2_STATE_UNPACK1, + LZMA2_STATE_PACK0, + LZMA2_STATE_PACK1, + LZMA2_STATE_PROP, + LZMA2_STATE_DATA, + LZMA2_STATE_DATA_CONT, + LZMA2_STATE_FINISHED, + LZMA2_STATE_ERROR +} ELzma2State; + +static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) +{ + UInt32 dicSize; + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); + props[0] = (Byte)LZMA2_LCLP_MAX; + props[1] = (Byte)(dicSize); + props[2] = (Byte)(dicSize >> 8); + props[3] = (Byte)(dicSize >> 16); + props[4] = (Byte)(dicSize >> 24); + return SZ_OK; +} + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +void Lzma2Dec_Init(CLzma2Dec *p) +{ + p->state = LZMA2_STATE_CONTROL; + p->needInitLevel = 0xE0; + p->isExtraMode = False; + p->unpackSize = 0; + + // p->decoder.dicPos = 0; // we can use it instead of full init + LzmaDec_Init(&p->decoder); +} + +static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +{ + switch (p->state) + { + case LZMA2_STATE_CONTROL: + p->isExtraMode = False; + p->control = b; + PRF(printf("\n %8X", (unsigned)p->decoder.dicPos)); + PRF(printf(" %02X", (unsigned)b)); + if (b == 0) + return LZMA2_STATE_FINISHED; + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (b == LZMA2_CONTROL_COPY_RESET_DIC) + p->needInitLevel = 0xC0; + else if (b > 2 || p->needInitLevel == 0xE0) + return LZMA2_STATE_ERROR; + } + else + { + if (b < p->needInitLevel) + return LZMA2_STATE_ERROR; + p->needInitLevel = 0; + p->unpackSize = (UInt32)(b & 0x1F) << 16; + } + return LZMA2_STATE_UNPACK0; + + case LZMA2_STATE_UNPACK0: + p->unpackSize |= (UInt32)b << 8; + return LZMA2_STATE_UNPACK1; + + case LZMA2_STATE_UNPACK1: + p->unpackSize |= (UInt32)b; + p->unpackSize++; + PRF(printf(" %7u", (unsigned)p->unpackSize)); + return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; + + case LZMA2_STATE_PACK0: + p->packSize = (UInt32)b << 8; + return LZMA2_STATE_PACK1; + + case LZMA2_STATE_PACK1: + p->packSize |= (UInt32)b; + p->packSize++; + // if (p->packSize < 5) return LZMA2_STATE_ERROR; + PRF(printf(" %5u", (unsigned)p->packSize)); + return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA; + + case LZMA2_STATE_PROP: + { + unsigned lc, lp; + if (b >= (9 * 5 * 5)) + return LZMA2_STATE_ERROR; + lc = b % 9; + b /= 9; + p->decoder.prop.pb = (Byte)(b / 5); + lp = b % 5; + if (lc + lp > LZMA2_LCLP_MAX) + return LZMA2_STATE_ERROR; + p->decoder.prop.lc = (Byte)lc; + p->decoder.prop.lp = (Byte)lp; + return LZMA2_STATE_DATA; + } + } + return LZMA2_STATE_ERROR; +} + +static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) +{ + memcpy(p->dic + p->dicPos, src, size); + p->dicPos += size; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) + p->checkDicSize = p->prop.dicSize; + p->processedPos += (UInt32)size; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); + + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->state != LZMA2_STATE_ERROR) + { + SizeT dicPos; + + if (p->state == LZMA2_STATE_FINISHED) + { + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + + dicPos = p->decoder.dicPos; + + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->state = Lzma2Dec_UpdateState(p, *src++); + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + break; + continue; + } + + { + SizeT inCur = inSize - *srcLen; + SizeT outCur = dicLimit - dicPos; + ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; + + if (outCur >= p->unpackSize) + { + outCur = (SizeT)p->unpackSize; + curFinishMode = LZMA_FINISH_END; + } + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (inCur == 0) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + if (p->state == LZMA2_STATE_DATA) + { + BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); + LzmaDec_InitDicAndState(&p->decoder, initDic, False); + } + + if (inCur > outCur) + inCur = outCur; + if (inCur == 0) + break; + + LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur); + + src += inCur; + *srcLen += inCur; + p->unpackSize -= (UInt32)inCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + SRes res; + + if (p->state == LZMA2_STATE_DATA) + { + BoolInt initDic = (p->control >= 0xE0); + BoolInt initState = (p->control >= 0xA0); + LzmaDec_InitDicAndState(&p->decoder, initDic, initState); + p->state = LZMA2_STATE_DATA_CONT; + } + + if (inCur > p->packSize) + inCur = (SizeT)p->packSize; + + res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status); + + src += inCur; + *srcLen += inCur; + p->packSize -= (UInt32)inCur; + outCur = p->decoder.dicPos - dicPos; + p->unpackSize -= (UInt32)outCur; + + if (res != 0) + break; + + if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->packSize == 0) + break; + return SZ_OK; + } + + if (inCur == 0 && outCur == 0) + { + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + break; + p->state = LZMA2_STATE_CONTROL; + } + + *status = LZMA_STATUS_NOT_SPECIFIED; + } + } + } + + *status = LZMA_STATUS_NOT_SPECIFIED; + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; +} + + + + +ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, + SizeT outSize, + const Byte *src, SizeT *srcLen, + int checkFinishBlock) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + + while (p->state != LZMA2_STATE_ERROR) + { + if (p->state == LZMA2_STATE_FINISHED) + return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK; + + if (outSize == 0 && !checkFinishBlock) + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + (*srcLen)++; + + p->state = Lzma2Dec_UpdateState(p, *src++); + + if (p->state == LZMA2_STATE_UNPACK0) + { + // if (p->decoder.dicPos != 0) + if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0) + return LZMA2_PARSE_STATUS_NEW_BLOCK; + // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED; + } + + // The following code can be commented. + // It's not big problem, if we read additional input bytes. + // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state. + + if (outSize == 0 && p->state != LZMA2_STATE_FINISHED) + { + // checkFinishBlock is true. So we expect that block must be finished, + // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here + // break; + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + } + + if (p->state == LZMA2_STATE_DATA) + return LZMA2_PARSE_STATUS_NEW_CHUNK; + + continue; + } + + if (outSize == 0) + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + + { + SizeT inCur = inSize - *srcLen; + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (inCur == 0) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + if (inCur > p->unpackSize) + inCur = p->unpackSize; + if (inCur > outSize) + inCur = outSize; + p->decoder.dicPos += inCur; + src += inCur; + *srcLen += inCur; + outSize -= inCur; + p->unpackSize -= (UInt32)inCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + p->isExtraMode = True; + + if (inCur == 0) + { + if (p->packSize != 0) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + } + else if (p->state == LZMA2_STATE_DATA) + { + p->state = LZMA2_STATE_DATA_CONT; + if (*src != 0) + { + // first byte of lzma chunk must be Zero + *srcLen += 1; + p->packSize--; + break; + } + } + + if (inCur > p->packSize) + inCur = (SizeT)p->packSize; + + src += inCur; + *srcLen += inCur; + p->packSize -= (UInt32)inCur; + + if (p->packSize == 0) + { + SizeT rem = outSize; + if (rem > p->unpackSize) + rem = p->unpackSize; + p->decoder.dicPos += rem; + p->unpackSize -= (UInt32)rem; + outSize -= rem; + if (p->unpackSize == 0) + p->state = LZMA2_STATE_CONTROL; + } + } + } + } + + p->state = LZMA2_STATE_ERROR; + return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; +} + + + + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen, inSize = *srcLen; + *srcLen = *destLen = 0; + + for (;;) + { + SizeT inCur = inSize, outCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + + if (p->decoder.dicPos == p->decoder.dicBufSize) + p->decoder.dicPos = 0; + dicPos = p->decoder.dicPos; + curFinishMode = LZMA_FINISH_ANY; + outCur = p->decoder.dicBufSize - dicPos; + + if (outCur >= outSize) + { + outCur = outSize; + curFinishMode = finishMode; + } + + res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status); + + src += inCur; + inSize -= inCur; + *srcLen += inCur; + outCur = p->decoder.dicPos - dicPos; + memcpy(dest, p->decoder.dic + dicPos, outCur); + dest += outCur; + outSize -= outCur; + *destLen += outCur; + if (res != 0) + return res; + if (outCur == 0 || outSize == 0) + return SZ_OK; + } +} + + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc) +{ + CLzma2Dec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + Lzma2Dec_Construct(&p); + RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); + p.decoder.dic = dest; + p.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&p); + *srcLen = inSize; + res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.decoder.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + Lzma2Dec_FreeProbs(&p, alloc); + return res; +} diff --git a/utils/lzma/C/Lzma2Dec.h b/utils/lzma/C/Lzma2Dec.h new file mode 100644 index 0000000..b8ddeac --- /dev/null +++ b/utils/lzma/C/Lzma2Dec.h @@ -0,0 +1,120 @@ +/* Lzma2Dec.h -- LZMA2 Decoder +2018-02-19 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_DEC_H +#define __LZMA2_DEC_H + +#include "LzmaDec.h" + +EXTERN_C_BEGIN + +/* ---------- State Interface ---------- */ + +typedef struct +{ + unsigned state; + Byte control; + Byte needInitLevel; + Byte isExtraMode; + Byte _pad_; + UInt32 packSize; + UInt32 unpackSize; + CLzmaDec decoder; +} CLzma2Dec; + +#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) +#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) +#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); +void Lzma2Dec_Init(CLzma2Dec *p); + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen or dicLimit). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + SZ_ERROR_DATA - Data error +*/ + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- LZMA2 block and chunk parsing ---------- */ + +/* +Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data. +It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code: + - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input. + - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read. + CLzma2Dec::unpackSize contains unpack size of that chunk +*/ + +typedef enum +{ +/* + LZMA_STATUS_NOT_SPECIFIED // data error + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED // + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused +*/ + LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1, + LZMA2_PARSE_STATUS_NEW_CHUNK +} ELzma2ParseStatus; + +ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, + SizeT outSize, // output size + const Byte *src, SizeT *srcLen, + int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position. + ); + +/* +LZMA2 parser doesn't decode LZMA chunks, so we must read + full input LZMA chunk to decode some part of LZMA chunk. + +Lzma2Dec_GetUnpackExtra() returns the value that shows + max possible number of output bytes that can be output by decoder + at current input positon. +*/ + +#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0); + + +/* ---------- One Call Interface ---------- */ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Lzma2DecMt.c b/utils/lzma/C/Lzma2DecMt.c new file mode 100644 index 0000000..988643d --- /dev/null +++ b/utils/lzma/C/Lzma2DecMt.c @@ -0,0 +1,1082 @@ +/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR(s) PRF(printf("\n" s "\n")) +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) +#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2)) + +// #define _7ZIP_ST + +#include "Alloc.h" + +#include "Lzma2Dec.h" +#include "Lzma2DecMt.h" + +#ifndef _7ZIP_ST +#include "MtDec.h" +#endif + + +#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) + +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) +{ + p->inBufSize_ST = 1 << 20; + p->outStep_ST = 1 << 20; + + #ifndef _7ZIP_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; + p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; + #endif +} + + + +#ifndef _7ZIP_ST + +/* ---------- CLzma2DecMtThread ---------- */ + +typedef struct +{ + CLzma2Dec dec; + Byte dec_created; + Byte needInit; + + Byte *outBuf; + size_t outBufSize; + + EMtDecParseState state; + ELzma2ParseStatus parseStatus; + + size_t inPreSize; + size_t outPreSize; + + size_t inCodeSize; + size_t outCodeSize; + SRes codeRes; + + CAlignOffsetAlloc alloc; + + Byte mtPad[1 << 7]; +} CLzma2DecMtThread; + +#endif + + +/* ---------- CLzma2DecMt ---------- */ + +typedef struct +{ + // ISzAllocPtr alloc; + ISzAllocPtr allocMid; + + CAlignOffsetAlloc alignOffsetAlloc; + CLzma2DecMtProps props; + Byte prop; + + ISeqInStream *inStream; + ISeqOutStream *outStream; + ICompressProgress *progress; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + BoolInt readWasFinished; + SRes readRes; + + Byte *inBuf; + size_t inBufSize; + Byte dec_created; + CLzma2Dec dec; + + size_t inPos; + size_t inLim; + + #ifndef _7ZIP_ST + UInt64 outProcessed_Parse; + BoolInt mtc_WasConstructed; + CMtDec mtc; + CLzma2DecMtThread coders[MTDEC__THREADS_MAX]; + #endif + +} CLzma2DecMt; + + + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); + if (!p) + return NULL; + + // p->alloc = alloc; + p->allocMid = allocMid; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + p->alignOffsetAlloc.baseAlloc = alloc; + + p->inBuf = NULL; + p->inBufSize = 0; + p->dec_created = False; + + // Lzma2DecMtProps_Init(&p->props); + + #ifndef _7ZIP_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + t->dec_created = False; + t->outBuf = NULL; + t->outBufSize = 0; + } + } + #endif + + return p; +} + + +#ifndef _7ZIP_ST + +static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->outBuf) + { + ISzAlloc_Free(p->allocMid, t->outBuf); + t->outBuf = NULL; + t->outBufSize = 0; + } + } +} + +#endif + + +static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) +{ + if (p->dec_created) + { + Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); + p->dec_created = False; + } + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + + Lzma2DecMt_FreeSt(p); + + #ifndef _7ZIP_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! + t->dec_created = False; + } + } + } + Lzma2DecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); +} + + + +#ifndef _7ZIP_ST + +static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CLzma2DecMt *me = (CLzma2DecMt *)obj; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + PRF_STR_INT_2("Parse", coderIndex, cc->srcSize); + + cc->state = MTDEC_PARSE_CONTINUE; + + if (cc->startCall) + { + if (!t->dec_created) + { + Lzma2Dec_Construct(&t->dec); + t->dec_created = True; + AlignOffsetAlloc_CreateVTable(&t->alloc); + { + /* (1 << 12) is expected size of one way in data cache. + We optimize alignment for cache line size of 128 bytes and smaller */ + const unsigned kNumAlignBits = 12; + const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ + t->alloc.numAlignBits = kNumAlignBits; + t->alloc.offset = ((UInt32)coderIndex * ((1 << 11) + (1 << 8) + (1 << 6))) & ((1 << kNumAlignBits) - (1 << kNumCacheLineBits)); + t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; + } + } + Lzma2Dec_Init(&t->dec); + + t->inPreSize = 0; + t->outPreSize = 0; + // t->blockWasFinished = False; + // t->finishedWithMark = False; + t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; + t->state = MTDEC_PARSE_CONTINUE; + + t->inCodeSize = 0; + t->outCodeSize = 0; + t->codeRes = SZ_OK; + + // (cc->srcSize == 0) is allowed + } + + { + ELzma2ParseStatus status; + BoolInt overflow; + UInt32 unpackRem = 0; + + int checkFinishBlock = True; + size_t limit = me->props.outBlockMax; + if (me->outSize_Defined) + { + UInt64 rem = me->outSize - me->outProcessed_Parse; + if (limit >= rem) + { + limit = (size_t)rem; + if (!me->finishMode) + checkFinishBlock = False; + } + } + + // checkFinishBlock = False, if we want to decode partial data + // that must be finished at position <= outBlockMax. + + { + const SizeT srcOrig = cc->srcSize; + SizeT srcSize_Point = 0; + SizeT dicPos_Point = 0; + + cc->srcSize = 0; + overflow = False; + + for (;;) + { + SizeT srcCur = srcOrig - cc->srcSize; + + status = Lzma2Dec_Parse(&t->dec, + limit - t->dec.decoder.dicPos, + cc->src + cc->srcSize, &srcCur, + checkFinishBlock); + + cc->srcSize += srcCur; + + if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) + { + if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) + { + overflow = True; + break; + } + continue; + } + + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + if (t->dec.decoder.dicPos == 0) + continue; + // we decode small blocks in one thread + if (t->dec.decoder.dicPos >= (1 << 14)) + break; + dicPos_Point = t->dec.decoder.dicPos; + srcSize_Point = cc->srcSize; + continue; + } + + if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock + // && limit == t->dec.decoder.dicPos + // && limit == me->props.outBlockMax + ) + { + overflow = True; + break; + } + + unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); + break; + } + + if (dicPos_Point != 0 + && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK + && (int)status != LZMA_STATUS_FINISHED_WITH_MARK + && (int)status != LZMA_STATUS_NOT_SPECIFIED) + { + // we revert to latest newBlock state + status = LZMA2_PARSE_STATUS_NEW_BLOCK; + unpackRem = 0; + t->dec.decoder.dicPos = dicPos_Point; + cc->srcSize = srcSize_Point; + overflow = False; + } + } + + t->inPreSize += cc->srcSize; + t->parseStatus = status; + + if (overflow) + cc->state = MTDEC_PARSE_OVERFLOW; + else + { + size_t dicPos = t->dec.decoder.dicPos; + + if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + cc->state = MTDEC_PARSE_NEW; + cc->srcSize--; // we don't need control byte of next block + t->inPreSize--; + } + else + { + cc->state = MTDEC_PARSE_END; + if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) + { + // (status == LZMA_STATUS_NOT_SPECIFIED) + // (status == LZMA_STATUS_NOT_FINISHED) + if (unpackRem != 0) + { + /* we also reserve space for max possible number of output bytes of current LZMA chunk */ + SizeT rem = limit - dicPos; + if (rem > unpackRem) + rem = unpackRem; + dicPos += rem; + } + } + } + + me->outProcessed_Parse += dicPos; + } + + cc->outPos = dicPos; + t->outPreSize = (size_t)dicPos; + } + + t->state = cc->state; + return; + } +} + + +static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + Byte *dest = t->outBuf; + + if (t->inPreSize == 0) + { + t->codeRes = SZ_ERROR_DATA; + return t->codeRes; + } + + if (!dest || t->outBufSize < t->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + t->outBuf = NULL; + t->outBufSize = 0; + } + + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize + // + (1 << 28) + ); + // Sleep(200); + if (!dest) + return SZ_ERROR_MEM; + t->outBuf = dest; + t->outBufSize = t->outPreSize; + } + + t->dec.decoder.dic = dest; + t->dec.decoder.dicBufSize = t->outPreSize; + + t->needInit = True; + + return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt +} + + +static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + UNUSED_VAR(srcFinished) + + PRF_STR_INT_2("Code", coderIndex, srcSize); + + *inCodePos = t->inCodeSize; + *outCodePos = 0; + *stop = True; + + if (t->needInit) + { + Lzma2Dec_Init(&t->dec); + t->needInit = False; + } + + { + ELzmaStatus status; + size_t srcProcessed = srcSize; + BoolInt blockWasFinished = + ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); + + SRes res = Lzma2Dec_DecodeToDic(&t->dec, + t->outPreSize, + src, &srcProcessed, + blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, + &status); + + t->codeRes = res; + + t->inCodeSize += srcProcessed; + *inCodePos = t->inCodeSize; + t->outCodeSize = t->dec.decoder.dicPos; + *outCodePos = t->dec.decoder.dicPos; + + if (res != SZ_OK) + return res; + + if (srcProcessed == srcSize) + *stop = False; + + if (blockWasFinished) + { + if (srcSize != srcProcessed) + return SZ_ERROR_FAIL; + + if (t->inPreSize == t->inCodeSize) + { + if (t->outPreSize != t->outCodeSize) + return SZ_ERROR_FAIL; + *stop = True; + } + } + else + { + if (t->outPreSize == t->outCodeSize) + *stop = True; + } + + return SZ_OK; + } +} + + +#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, + BoolInt *needContinue, BoolInt *canRecode) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + const CLzma2DecMtThread *t = &me->coders[coderIndex]; + size_t size = t->outCodeSize; + const Byte *data = t->outBuf; + BoolInt needContinue2 = True; + + PRF_STR_INT_2("Write", coderIndex, srcSize); + + *needContinue = False; + *canRecode = True; + UNUSED_VAR(src) + UNUSED_VAR(srcSize) + + if ( + // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + t->state == MTDEC_PARSE_OVERFLOW + || t->state == MTDEC_PARSE_END) + needContinue2 = False; + + + if (!needWriteToStream) + return SZ_OK; + + me->mtc.inProcessed += t->inCodeSize; + + if (t->codeRes == SZ_OK) + if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) + if (t->outPreSize != t->outCodeSize + || t->inPreSize != t->inCodeSize) + return SZ_ERROR_FAIL; + + *canRecode = False; + + if (me->outStream) + { + for (;;) + { + size_t cur = size; + size_t written; + if (cur > LZMA2DECMT_STREAM_WRITE_STEP) + cur = LZMA2DECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + me->outProcessed += written; + // me->mtc.writtenTotal += written; + if (written != cur) + return SZ_ERROR_WRITE; + data += cur; + size -= cur; + if (size == 0) + { + *needContinue = needContinue2; + return SZ_OK; + } + RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)); + } + } + + return SZ_ERROR_FAIL; + /* + if (size > me->outBufSize) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBufSize -= size; + me->outBuf += size; + *needContinue = needContinue2; + return SZ_OK; + */ +} + +#endif + + +static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) +{ + if (!p->dec_created) + { + Lzma2Dec_Construct(&p->dec); + p->dec_created = True; + } + + RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)); + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + Lzma2Dec_Init(&p->dec); + + return SZ_OK; +} + + +static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p + #ifndef _7ZIP_ST + , BoolInt tMode + #endif + ) +{ + SizeT wrPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CLzma2Dec *dec; + + #ifndef _7ZIP_ST + if (tMode) + { + Lzma2DecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + RINOK(Lzma2Dec_Prepare_ST(p)); + + dec = &p->dec; + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + wrPos = dec->decoder.dicPos; + + for (;;) + { + SizeT dicPos; + SizeT size; + ELzmaFinishMode finishMode; + SizeT inProcessed; + ELzmaStatus status; + SRes res; + + SizeT outProcessed; + BoolInt outFinished; + BoolInt needStop; + + if (inPos == inLim) + { + #ifndef _7ZIP_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim); + // p->readProcessed += inLim; + // inLim -= 5; p->readWasFinished = True; // for test + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + dicPos = dec->decoder.dicPos; + { + SizeT next = dec->decoder.dicBufSize; + if (next - wrPos > p->props.outStep_ST) + next = wrPos + p->props.outStep_ST; + size = next - dicPos; + } + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (SizeT)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + inProcessed = inLim - inPos; + + res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); + + inPos += inProcessed; + p->inProcessed += inProcessed; + outProcessed = dec->decoder.dicPos - dicPos; + p->outProcessed += outProcessed; + + outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); + + needStop = (res != SZ_OK + || (inProcessed == 0 && outProcessed == 0) + || status == LZMA_STATUS_FINISHED_WITH_MARK + || (!p->finishMode && outFinished)); + + if (needStop || outProcessed >= size) + { + SRes res2; + { + size_t writeSize = dec->decoder.dicPos - wrPos; + size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); + res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; + } + + if (dec->decoder.dicPos == dec->decoder.dicBufSize) + dec->decoder.dicPos = 0; + wrPos = dec->decoder.dicPos; + + RINOK(res2); + + if (needStop) + { + if (res != SZ_OK) + return res; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (p->finishMode) + { + if (p->outSize_Defined && p->outSize != p->outProcessed) + return SZ_ERROR_DATA; + } + return SZ_OK; + } + + if (!p->finishMode && outFinished) + return SZ_OK; + + if (status == LZMA_STATUS_NEEDS_MORE_INPUT) + return SZ_ERROR_INPUT_EOF; + + return SZ_ERROR_DATA; + } + } + + if (p->progress) + { + UInt64 inDelta = p->inProcessed - inPrev; + UInt64 outDelta = p->outProcessed - outPrev; + if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) + { + RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)); + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + } +} + + + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode, + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + UInt64 *inProcessed, + // UInt64 *outProcessed, + int *isMT, + ICompressProgress *progress) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + #ifndef _7ZIP_ST + BoolInt tMode; + #endif + + *inProcessed = 0; + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->readWasFinished = False; + + *isMT = False; + + + #ifndef _7ZIP_ST + + tMode = False; + + // p->mtc.parseRes = SZ_OK; + + // p->mtc.numFilledThreads = 0; + // p->mtc.crossStart = 0; + // p->mtc.crossEnd = 0; + // p->mtc.allocError_for_Read_BlockIndex = 0; + // p->mtc.isAllocError = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback vt; + + Lzma2DecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + + // p->outBuf = NULL; + // p->outBufSize = 0; + /* + if (!outStream) + { + // p->outBuf = outBuf; + // p->outBufSize = *outBufSize; + // *outBufSize = 0; + return SZ_ERROR_PARAM; + } + */ + + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->alignOffsetAlloc.baseAlloc; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.inBufSize = p->props.inBufSize_MT; + + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = Lzma2DecMt_MtCallback_Parse; + vt.PreCode = Lzma2DecMt_MtCallback_PreCode; + vt.Code = Lzma2DecMt_MtCallback_Code; + vt.Write = Lzma2DecMt_MtCallback_Write; + + { + BoolInt needContinue = False; + + SRes res = MtDec_Code(&p->mtc); + + /* + if (!outStream) + *outBufSize = p->outBuf - outBuf; + */ + + *inProcessed = p->mtc.inProcessed; + + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + res = p->mtc.mtProgress.res; + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + if (res == SZ_OK) + return p->mtc.readRes; + return res; + } + + tMode = True; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->inProcessed = p->mtc.inProcessed; + + PRF_STR("----- decoding ST -----"); + } + } + + #endif + + + *isMT = False; + + { + SRes res = Lzma2Dec_Decode_ST(p + #ifndef _7ZIP_ST + , tMode + #endif + ); + + *inProcessed = p->inProcessed; + + // res = SZ_OK; // for test + if (res == SZ_OK && p->readRes != SZ_OK) + res = p->readRes; + + /* + #ifndef _7ZIP_ST + if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) + res = p->mtc.parseRes; + #endif + */ + + return res; + } +} + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStream *inStream) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->inPos = 0; + p->inLim = 0; + + return Lzma2Dec_Prepare_ST(p); +} + + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + ELzmaFinishMode finishMode; + SRes readRes; + size_t size = *outSize; + + *outSize = 0; + *inStreamProcessed = 0; + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (size_t)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + readRes = SZ_OK; + + for (;;) + { + SizeT inCur; + SizeT outCur; + ELzmaStatus status; + SRes res; + + if (p->inPos == p->inLim && readRes == SZ_OK) + { + p->inPos = 0; + p->inLim = p->props.inBufSize_ST; + readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); + } + + inCur = p->inLim - p->inPos; + outCur = size; + + res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, + p->inBuf + p->inPos, &inCur, finishMode, &status); + + p->inPos += inCur; + p->inProcessed += inCur; + *inStreamProcessed += inCur; + p->outProcessed += outCur; + *outSize += outCur; + size -= outCur; + data += outCur; + + if (res != 0) + return res; + + /* + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + return readRes; + + if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) + return SZ_ERROR_DATA; + return readRes; + } + */ + + if (inCur == 0 && outCur == 0) + return readRes; + } +} diff --git a/utils/lzma/C/Lzma2DecMt.h b/utils/lzma/C/Lzma2DecMt.h new file mode 100644 index 0000000..7791c31 --- /dev/null +++ b/utils/lzma/C/Lzma2DecMt.h @@ -0,0 +1,79 @@ +/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread +2018-02-17 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_DEC_MT_H +#define __LZMA2_DEC_MT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + size_t inBufSize_ST; + size_t outStep_ST; + + #ifndef _7ZIP_ST + unsigned numThreads; + size_t inBufSize_MT; + size_t outBlockMax; + size_t inBlockMax; + #endif +} CLzma2DecMtProps; + +/* init to single-thread mode */ +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p); + + +/* ---------- CLzma2DecMtHandle Interface ---------- */ + +/* Lzma2DecMt_ * functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef void * CLzma2DecMtHandle; + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void Lzma2DecMt_Destroy(CLzma2DecMtHandle p); + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStream *outStream, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + + // out variables: + UInt64 *inProcessed, + int *isMT, /* out: (*isMT == 0), if single thread decoding was used */ + + // UInt64 *outProcessed, + ICompressProgress *progress); + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStream *inStream); + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed); + + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Lzma2Enc.c b/utils/lzma/C/Lzma2Enc.c new file mode 100644 index 0000000..5c1ad49 --- /dev/null +++ b/utils/lzma/C/Lzma2Enc.c @@ -0,0 +1,803 @@ +/* Lzma2Enc.c -- LZMA2 Encoder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define _7ZIP_ST */ + +#include "Lzma2Enc.h" + +#ifndef _7ZIP_ST +#include "MtCoder.h" +#else +#define MTCODER__THREADS_MAX 1 +#endif + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_LCLP_MAX 4 + +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#define LZMA2_PACK_SIZE_MAX (1 << 16) +#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX +#define LZMA2_UNPACK_SIZE_MAX (1 << 21) +#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX + +#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) + + +#define PRF(x) /* x */ + + +/* ---------- CLimitedSeqInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStream *realStream; + UInt64 limit; + UInt64 processed; + int finished; +} CLimitedSeqInStream; + +static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->finished = 0; +} + +static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt); + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->finished = (size2 == 0 ? 1 : 0); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CLzma2EncInt ---------- */ + +typedef struct +{ + CLzmaEncHandle enc; + Byte propsAreSet; + Byte propsByte; + Byte needInitState; + Byte needInitProp; + UInt64 srcPos; +} CLzma2EncInt; + + +static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) +{ + if (!p->propsAreSet) + { + SizeT propsSize = LZMA_PROPS_SIZE; + Byte propsEncoded[LZMA_PROPS_SIZE]; + RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); + RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); + p->propsByte = propsEncoded[0]; + p->propsAreSet = True; + } + return SZ_OK; +} + +static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) +{ + p->srcPos = 0; + p->needInitState = True; + p->needInitProp = True; +} + + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); +void LzmaEnc_Finish(CLzmaEncHandle pp); +void LzmaEnc_SaveState(CLzmaEncHandle pp); +void LzmaEnc_RestoreState(CLzmaEncHandle pp); + +/* +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp); +*/ + +static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, + size_t *packSizeRes, ISeqOutStream *outStream) +{ + size_t packSizeLimit = *packSizeRes; + size_t packSize = packSizeLimit; + UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; + unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); + BoolInt useCopyBlock; + SRes res; + + *packSizeRes = 0; + if (packSize < lzHeaderSize) + return SZ_ERROR_OUTPUT_EOF; + packSize -= lzHeaderSize; + + LzmaEnc_SaveState(p->enc); + res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, + outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); + + PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); + + if (unpackSize == 0) + return res; + + if (res == SZ_OK) + useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); + else + { + if (res != SZ_ERROR_OUTPUT_EOF) + return res; + res = SZ_OK; + useCopyBlock = True; + } + + if (useCopyBlock) + { + size_t destPos = 0; + PRF(printf("################# COPY ")); + + while (unpackSize > 0) + { + UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; + if (packSizeLimit - destPos < u + 3) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); + outBuf[destPos++] = (Byte)((u - 1) >> 8); + outBuf[destPos++] = (Byte)(u - 1); + memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); + unpackSize -= u; + destPos += u; + p->srcPos += u; + + if (outStream) + { + *packSizeRes += destPos; + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + destPos = 0; + } + else + *packSizeRes = destPos; + /* needInitState = True; */ + } + + LzmaEnc_RestoreState(p->enc); + return SZ_OK; + } + + { + size_t destPos = 0; + UInt32 u = unpackSize - 1; + UInt32 pm = (UInt32)(packSize - 1); + unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); + + PRF(printf(" ")); + + outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); + outBuf[destPos++] = (Byte)(u >> 8); + outBuf[destPos++] = (Byte)u; + outBuf[destPos++] = (Byte)(pm >> 8); + outBuf[destPos++] = (Byte)pm; + + if (p->needInitProp) + outBuf[destPos++] = p->propsByte; + + p->needInitProp = False; + p->needInitState = False; + destPos += packSize; + p->srcPos += unpackSize; + + if (outStream) + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + + *packSizeRes = destPos; + return SZ_OK; + } +} + + +/* ---------- Lzma2 Props ---------- */ + +void Lzma2EncProps_Init(CLzma2EncProps *p) +{ + LzmaEncProps_Init(&p->lzmaProps); + p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; +} + +void Lzma2EncProps_Normalize(CLzma2EncProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzmaEncProps lzmaProps = p->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + t1n = lzmaProps.numThreads; + } + + t1 = p->lzmaProps.numThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzmaProps.numThreads = t1; + + t2r = t2; + + fileSize = p->lzmaProps.reduceSize; + + if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + && p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO + && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzmaProps.reduceSize = p->blockSize; + + LzmaEncProps_Normalize(&p->lzmaProps); + + p->lzmaProps.reduceSize = fileSize; + + t1 = p->lzmaProps.numThreads; + + if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + { + t2r = t2 = 1; + t3 = t1; + } + else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1) + { + /* if there is no block multi-threading, we use SOLID block */ + p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; + } + else + { + if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + { + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + const UInt32 dictSize = p->lzmaProps.dictSize; + UInt64 blockSize = (UInt64)dictSize << 2; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + blockSize += (kMinSize - 1); + blockSize &= ~(UInt64)(kMinSize - 1); + p->blockSize = blockSize; + } + + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (unsigned)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) +{ + return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; +} + + +/* ---------- Lzma2 ---------- */ + +typedef struct +{ + Byte propEncoded; + CLzma2EncProps props; + UInt64 expectedDataSize; + + Byte *tempBufLzma; + + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CLzma2EncInt coders[MTCODER__THREADS_MAX]; + + #ifndef _7ZIP_ST + + ISeqOutStream *outStream; + Byte *outBuf; + size_t outBuf_Rem; /* remainder in outBuf */ + + size_t outBufSize; /* size of allocated outBufs[i] */ + size_t outBufsDataSizes[MTCODER__BLOCKS_MAX]; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + Byte *outBufs[MTCODER__BLOCKS_MAX]; + + #endif + +} CLzma2Enc; + + + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); + if (!p) + return NULL; + Lzma2EncProps_Init(&p->props); + Lzma2EncProps_Normalize(&p->props); + p->expectedDataSize = (UInt64)(Int64)-1; + p->tempBufLzma = NULL; + p->alloc = alloc; + p->allocBig = allocBig; + { + unsigned i; + for (i = 0; i < MTCODER__THREADS_MAX; i++) + p->coders[i].enc = NULL; + } + + #ifndef _7ZIP_ST + p->mtCoder_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif + + return p; +} + + +#ifndef _7ZIP_ST + +static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) +{ + unsigned i; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + +#endif + + +void Lzma2Enc_Destroy(CLzma2EncHandle pp) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + unsigned i; + for (i = 0; i < MTCODER__THREADS_MAX; i++) + { + CLzma2EncInt *t = &p->coders[i]; + if (t->enc) + { + LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); + t->enc = NULL; + } + } + + + #ifndef _7ZIP_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + Lzma2Enc_FreeOutBufs(p); + #endif + + ISzAlloc_Free(p->alloc, p->tempBufLzma); + p->tempBufLzma = NULL; + + ISzAlloc_Free(p->alloc, pp); +} + + +SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + CLzmaEncProps lzmaProps = props->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) + return SZ_ERROR_PARAM; + p->props = *props; + Lzma2EncProps_Normalize(&p->props); + return SZ_OK; +} + + +void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + p->expectedDataSize = expectedDataSiize; +} + + +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + unsigned i; + UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); + for (i = 0; i < 40; i++) + if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) + break; + return (Byte)i; +} + + +static SRes Lzma2Enc_EncodeMt1( + CLzma2Enc *me, + CLzma2EncInt *p, + ISeqOutStream *outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + const Byte *inData, size_t inDataSize, + int finished, + ICompressProgress *progress) +{ + UInt64 unpackTotal = 0; + UInt64 packTotal = 0; + size_t outLim = 0; + CLimitedSeqInStream limitedInStream; + + if (outBuf) + { + outLim = *outBufSize; + *outBufSize = 0; + } + + if (!p->enc) + { + p->propsAreSet = False; + p->enc = LzmaEnc_Create(me->alloc); + if (!p->enc) + return SZ_ERROR_MEM; + } + + limitedInStream.realStream = inStream; + if (inStream) + { + limitedInStream.vt.Read = LimitedSeqInStream_Read; + } + + if (!outBuf) + { + // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma + if (!me->tempBufLzma) + { + me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); + if (!me->tempBufLzma) + return SZ_ERROR_MEM; + } + } + + RINOK(Lzma2EncInt_InitStream(p, &me->props)); + + for (;;) + { + SRes res = SZ_OK; + size_t inSizeCur = 0; + + Lzma2EncInt_InitBlock(p); + + LimitedSeqInStream_Init(&limitedInStream); + limitedInStream.limit = me->props.blockSize; + + if (inStream) + { + UInt64 expected = (UInt64)(Int64)-1; + // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize + if (me->expectedDataSize != (UInt64)(Int64)-1 + && me->expectedDataSize >= unpackTotal) + expected = me->expectedDataSize - unpackTotal; + if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + && expected > me->props.blockSize) + expected = (size_t)me->props.blockSize; + + LzmaEnc_SetDataSize(p->enc, expected); + + RINOK(LzmaEnc_PrepareForLzma2(p->enc, + &limitedInStream.vt, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)); + } + else + { + inSizeCur = inDataSize - (size_t)unpackTotal; + if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + && inSizeCur > me->props.blockSize) + inSizeCur = (size_t)me->props.blockSize; + + // LzmaEnc_SetDataSize(p->enc, inSizeCur); + + RINOK(LzmaEnc_MemPrepare(p->enc, + inData + (size_t)unpackTotal, inSizeCur, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)); + } + + for (;;) + { + size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; + if (outBuf) + packSize = outLim - (size_t)packTotal; + + res = Lzma2EncInt_EncodeSubblock(p, + outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, + outBuf ? NULL : outStream); + + if (res != SZ_OK) + break; + + packTotal += packSize; + if (outBuf) + *outBufSize = (size_t)packTotal; + + res = Progress(progress, unpackTotal + p->srcPos, packTotal); + if (res != SZ_OK) + break; + + /* + if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) + break; + */ + + if (packSize == 0) + break; + } + + LzmaEnc_Finish(p->enc); + + unpackTotal += p->srcPos; + + RINOK(res); + + if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) + return SZ_ERROR_FAIL; + + if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) + { + if (finished) + { + if (outBuf) + { + size_t destPos = *outBufSize; + if (destPos >= outLim) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos] = 0; + *outBufSize = destPos + 1; + } + else + { + Byte b = 0; + if (ISeqOutStream_Write(outStream, &b, 1) != 1) + return SZ_ERROR_WRITE; + } + } + return SZ_OK; + } + } +} + + + +#ifndef _7ZIP_ST + +static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CLzma2Enc *me = (CLzma2Enc *)pp; + size_t destSize = me->outBufSize; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + me->outBufsDataSizes[outBufIndex] = 0; + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + progressThunk.inSize = 0; + progressThunk.outSize = 0; + + res = Lzma2Enc_EncodeMt1(me, + &me->coders[coderIndex], + NULL, dest, &destSize, + NULL, src, srcSize, + finished, + &progressThunk.vt); + + me->outBufsDataSizes[outBufIndex] = destSize; + + return res; +} + + +static SRes Lzma2Enc_MtCallback_Write(void *pp, unsigned outBufIndex) +{ + CLzma2Enc *me = (CLzma2Enc *)pp; + size_t size = me->outBufsDataSizes[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + if (me->outStream) + return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; + + if (size > me->outBuf_Rem) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBuf_Rem -= size; + me->outBuf += size; + return SZ_OK; +} + +#endif + + + +SRes Lzma2Enc_Encode2(CLzma2EncHandle pp, + ISeqOutStream *outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + const Byte *inData, size_t inDataSize, + ICompressProgress *progress) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + + if (inStream && inData) + return SZ_ERROR_PARAM; + + if (outStream && outBuf) + return SZ_ERROR_PARAM; + + { + unsigned i; + for (i = 0; i < MTCODER__THREADS_MAX; i++) + p->coders[i].propsAreSet = False; + } + + #ifndef _7ZIP_ST + + if (p->props.numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = Lzma2Enc_MtCallback_Code; + vt.Write = Lzma2Enc_MtCallback_Write; + + p->outStream = outStream; + p->outBuf = NULL; + p->outBuf_Rem = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBuf_Rem = *outBufSize; + *outBufSize = 0; + } + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = inData; + p->mtCoder.inDataSize = inDataSize; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + p->mtCoder.blockSize = (size_t)p->props.blockSize; + if (p->mtCoder.blockSize != p->props.blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + Lzma2Enc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = p->props.numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + { + SRes res = MtCoder_Code(&p->mtCoder); + if (!outStream) + *outBufSize = p->outBuf - outBuf; + return res; + } + } + + #endif + + + return Lzma2Enc_EncodeMt1(p, + &p->coders[0], + outStream, outBuf, outBufSize, + inStream, inData, inDataSize, + True, /* finished */ + progress); +} diff --git a/utils/lzma/C/Lzma2Enc.h b/utils/lzma/C/Lzma2Enc.h new file mode 100644 index 0000000..6a6110f --- /dev/null +++ b/utils/lzma/C/Lzma2Enc.h @@ -0,0 +1,55 @@ +/* Lzma2Enc.h -- LZMA2 Encoder +2017-07-27 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_ENC_H +#define __LZMA2_ENC_H + +#include "LzmaEnc.h" + +EXTERN_C_BEGIN + +#define LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO 0 +#define LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID ((UInt64)(Int64)-1) + +typedef struct +{ + CLzmaEncProps lzmaProps; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; +} CLzma2EncProps; + +void Lzma2EncProps_Init(CLzma2EncProps *p); +void Lzma2EncProps_Normalize(CLzma2EncProps *p); + +/* ---------- CLzmaEnc2Handle Interface ---------- */ + +/* Lzma2Enc_* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef void * CLzma2EncHandle; + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void Lzma2Enc_Destroy(CLzma2EncHandle p); +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); +void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize); +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); +SRes Lzma2Enc_Encode2(CLzma2EncHandle p, + ISeqOutStream *outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + const Byte *inData, size_t inDataSize, + ICompressProgress *progress); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Lzma86.h b/utils/lzma/C/Lzma86.h new file mode 100644 index 0000000..bebed5c --- /dev/null +++ b/utils/lzma/C/Lzma86.h @@ -0,0 +1,111 @@ +/* Lzma86.h -- LZMA + x86 (BCJ) Filter +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __LZMA86_H +#define __LZMA86_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define LZMA86_SIZE_OFFSET (1 + 5) +#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8) + +/* +It's an example for LZMA + x86 Filter use. +You can use .lzma86 extension, if you write that stream to file. +.lzma86 header adds one additional byte to standard .lzma header. +.lzma86 header (14 bytes): + Offset Size Description + 0 1 = 0 - no filter, pure LZMA + = 1 - x86 filter + LZMA + 1 1 lc, lp and pb in encoded form + 2 4 dictSize (little endian) + 6 8 uncompressed size (little endian) + + +Lzma86_Encode +------------- +level - compression level: 0 <= level <= 9, the default value for "level" is 5. + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes, for level = 5. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + For better compression ratio dictSize must be >= inSize. + +filterMode: + SZ_FILTER_NO - no Filter + SZ_FILTER_YES - x86 Filter + SZ_FILTER_AUTO - it tries both alternatives to select best. + Encoder will use 2 or 3 passes: + 2 passes when FILTER_NO provides better compression. + 3 passes when FILTER_YES provides better compression. + +Lzma86Encode allocates Data with MyAlloc functions. +RAM Requirements for compressing: + RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize + filterMode FilterBlockSize + SZ_FILTER_NO 0 + SZ_FILTER_YES inSize + SZ_FILTER_AUTO inSize + + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +enum ESzFilterMode +{ + SZ_FILTER_NO, + SZ_FILTER_YES, + SZ_FILTER_AUTO +}; + +SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode); + + +/* +Lzma86_GetUnpackSize: + In: + src - input data + srcLen - input data size + Out: + unpackSize - size of uncompressed stream + Return code: + SZ_OK - OK + SZ_ERROR_INPUT_EOF - Error in headers +*/ + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize); + +/* +Lzma86_Decode: + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + Out: + destLen - processed output size + srcLen - processed input size + Return code: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - unsupported file + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer +*/ + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Lzma86Dec.c b/utils/lzma/C/Lzma86Dec.c new file mode 100644 index 0000000..2103174 --- /dev/null +++ b/utils/lzma/C/Lzma86Dec.c @@ -0,0 +1,54 @@ +/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder +2016-05-16 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaDec.h" + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) +{ + unsigned i; + if (srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + *unpackSize = 0; + for (i = 0; i < sizeof(UInt64); i++) + *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i); + return SZ_OK; +} + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + SRes res; + int useFilter; + SizeT inSizePure; + ELzmaStatus status; + + if (*srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + + useFilter = src[0]; + + if (useFilter > 1) + { + *destLen = 0; + return SZ_ERROR_UNSUPPORTED; + } + + inSizePure = *srcLen - LZMA86_HEADER_SIZE; + res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure, + src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc); + *srcLen = inSizePure + LZMA86_HEADER_SIZE; + if (res != SZ_OK) + return res; + if (useFilter == 1) + { + UInt32 x86State; + x86_Convert_Init(x86State); + x86_Convert(dest, *destLen, 0, &x86State, 0); + } + return SZ_OK; +} diff --git a/utils/lzma/C/Lzma86Enc.c b/utils/lzma/C/Lzma86Enc.c new file mode 100644 index 0000000..2617bab --- /dev/null +++ b/utils/lzma/C/Lzma86Enc.c @@ -0,0 +1,106 @@ +/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaEnc.h" + +#define SZE_OUT_OVERFLOW SZE_DATA_ERROR + +int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode) +{ + size_t outSize2 = *destLen; + Byte *filteredStream; + BoolInt useFilter; + int mainResult = SZ_ERROR_OUTPUT_EOF; + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + + *destLen = 0; + if (outSize2 < LZMA86_HEADER_SIZE) + return SZ_ERROR_OUTPUT_EOF; + + { + int i; + UInt64 t = srcLen; + for (i = 0; i < 8; i++, t >>= 8) + dest[LZMA86_SIZE_OFFSET + i] = (Byte)t; + } + + filteredStream = 0; + useFilter = (filterMode != SZ_FILTER_NO); + if (useFilter) + { + if (srcLen != 0) + { + filteredStream = (Byte *)MyAlloc(srcLen); + if (filteredStream == 0) + return SZ_ERROR_MEM; + memcpy(filteredStream, src, srcLen); + } + { + UInt32 x86State; + x86_Convert_Init(x86State); + x86_Convert(filteredStream, srcLen, 0, &x86State, 1); + } + } + + { + size_t minSize = 0; + BoolInt bestIsFiltered = False; + + /* passes for SZ_FILTER_AUTO: + 0 - BCJ + LZMA + 1 - LZMA + 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better. + */ + int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; + + int i; + for (i = 0; i < numPasses; i++) + { + size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE; + size_t outPropsSize = 5; + SRes curRes; + BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1); + if (curModeIsFiltered && !bestIsFiltered) + break; + if (useFilter && i == 0) + curModeIsFiltered = True; + + curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed, + curModeIsFiltered ? filteredStream : src, srcLen, + &props, dest + 1, &outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); + + if (curRes != SZ_ERROR_OUTPUT_EOF) + { + if (curRes != SZ_OK) + { + mainResult = curRes; + break; + } + if (outSizeProcessed <= minSize || mainResult != SZ_OK) + { + minSize = outSizeProcessed; + bestIsFiltered = curModeIsFiltered; + mainResult = SZ_OK; + } + } + } + dest[0] = (Byte)(bestIsFiltered ? 1 : 0); + *destLen = LZMA86_HEADER_SIZE + minSize; + } + if (useFilter) + MyFree(filteredStream); + return mainResult; +} diff --git a/utils/lzma/C/LzmaDec.c b/utils/lzma/C/LzmaDec.c new file mode 100644 index 0000000..ba3e1dd --- /dev/null +++ b/utils/lzma/C/LzmaDec.c @@ -0,0 +1,1185 @@ +/* LzmaDec.c -- LZMA Decoder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #include "CpuArch.h" */ +#include "LzmaDec.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } + +#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } + +#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ + { UPDATE_0(p + i); A0; } else \ + { UPDATE_1(p + i); A1; } +#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) +#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) +#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) + +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol) +#define MATCHED_LITER_DEC \ + matchByte += matchByte; \ + bit = offs; \ + offs &= matchByte; \ + probLit = prob + (offs + bit + symbol); \ + GET_BIT2(probLit, symbol, offs ^= bit; , ;) + + + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ + { UPDATE_0_CHECK; i += m; m += m; } else \ + { UPDATE_1_CHECK; m += m; i += m; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenLow 0 +#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + +#define LenChoice LenLow +#define LenChoice2 (LenLow + (1 << kLenNumLowBits)) + +#define kNumStates 12 +#define kNumStates2 16 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +/* External ASM code needs same CLzmaProb array layout. So don't change it. */ + +/* (probs_1664) is faster and better for code size at some platforms */ +/* +#ifdef MY_CPU_X86_OR_AMD64 +*/ +#define kStartOffset 1664 +#define GET_PROBS p->probs_1664 +/* +#define GET_PROBS p->probs + kStartOffset +#else +#define kStartOffset 0 +#define GET_PROBS p->probs +#endif +*/ + +#define SpecPos (-kStartOffset) +#define IsRep0Long (SpecPos + kNumFullDistances) +#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax)) +#define LenCoder (RepLenCoder + kNumLenProbs) +#define IsMatch (LenCoder + kNumLenProbs) +#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax)) +#define IsRep (Align + kAlignTableSize) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define PosSlot (IsRepG2 + kNumStates) +#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define NUM_BASE_PROBS (Literal + kStartOffset) + +#if Align != 0 && kStartOffset != 0 + #error Stop_Compiling_Bad_LZMA_kAlign +#endif + +#if NUM_BASE_PROBS != 1984 + #error Stop_Compiling_Bad_LZMA_PROBS +#endif + + +#define LZMA_LIT_SIZE 0x300 + +#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + + +#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4) +#define COMBINED_PS_STATE (posState + state) +#define GET_LEN_STATE (posState) + +#define LZMA_DIC_MIN (1 << 12) + +/* +p->remainLen : shows status of LZMA decoder: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : need init range coder + = kMatchSpecLenStart + 2 : need init range coder and state +*/ + +/* ---------- LZMA_DECODE_REAL ---------- */ +/* +LzmaDec_DecodeReal_3() can be implemented in external ASM file. +3 - is the code compatibility version of that function for check at link time. +*/ + +#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3 + +/* +LZMA_DECODE_REAL() +In: + RangeCoder is normalized + if (p->dicPos == limit) + { + LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. + So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol + is not END_OF_PAYALOAD_MARKER, then function returns error code. + } + +Processing: + first LZMA symbol will be decoded in any case + All checks for limits are at the end of main loop, + It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit), + RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. + +Out: + RangeCoder is normalized + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished +*/ + + +#ifdef _LZMA_DEC_OPT + +int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); + +#else + +static +int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = GET_PROBS; + unsigned state = (unsigned)p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lc = p->prop.lc; + unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = CALC_POS_STATE(processedPos, pbMask); + + prob = probs + IsMatch + COMBINED_PS_STATE; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (processedPos != 0 || checkDicSize != 0) + prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); + processedPos++; + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + #ifdef _LZMA_SIZE_OPT + do { NORMAL_LITER_DEC } while (symbol < 0x100); + #else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + #endif + } + else + { + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + #ifdef _LZMA_SIZE_OPT + do + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + } + while (symbol < 0x100); + #else + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } + #endif + } + + dic[dicPos++] = (Byte)symbol; + continue; + } + + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + /* + // that case was checked before with kBadRepCode + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + */ + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + COMBINED_PS_STATE; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + + #ifdef _LZMA_SIZE_OPT + { + unsigned lim, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE; + offset = 0; + lim = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + offset = kLenNumLowSymbols; + lim = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols * 2; + lim = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, lim, len); + len += offset; + } + #else + { + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE; + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + len -= 8; + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + len += kLenNumLowSymbols * 2; + } + } + } + #endif + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos; + { + UInt32 m = 1; + distance++; + do + { + REV_BIT_VAR(prob, distance, m); + } + while (--numDirectBits); + distance -= m; + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + REV_BIT_CONST(prob, i, 1); + REV_BIT_CONST(prob, i, 2); + REV_BIT_CONST(prob, i, 4); + REV_BIT_LAST (prob, i, 8); + distance |= i; + } + if (distance == (UInt32)0xFFFFFFFF) + { + len = kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + } + + len += kMatchMinLen; + + { + SizeT rem; + unsigned curLen; + SizeT pos; + + if ((rem = limit - dicPos) == 0) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); + + processedPos += (UInt32)curLen; + + len -= curLen; + if (curLen <= dicBufSize - pos) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += (SizeT)curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + + NORMALIZE; + + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = (UInt32)len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = (UInt32)state; + + return SZ_OK; +} +#endif + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = (unsigned)p->remainLen; + SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + SizeT rem = limit - dicPos; + if (rem < len) + len = (unsigned)(rem); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += (UInt32)len; + p->remainLen -= (UInt32)len; + while (len != 0) + { + len--; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + + +#define kRange0 0xFFFFFFFF +#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) +#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) +#if kBadRepCode != (0xC0000000 - 0x400) + #error Stop_Compiling_Bad_LZMA_Check +#endif + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + + if (p->processedPos == 0) + if (p->code >= kBadRepCode) + return SZ_ERROR_DATA; + } + + RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit)); + + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + const CLzmaProb *probs = GET_PROBS; + unsigned state = (unsigned)p->state; + ELzmaDummy res; + + { + const CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1); + + prob = probs + IsMatch + COMBINED_PS_STATE; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + const CLzmaProb *probLit; + matchByte += matchByte; + bit = offs; + offs &= matchByte; + probLit = prob + (offs + bit + symbol); + GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; ) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + COMBINED_PS_STATE; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + const CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + GET_LEN_STATE; + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols * 2; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + unsigned numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + unsigned m = 1; + do + { + REV_BIT_CHECK(prob, i, m); + } + while (--numDirectBits); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) +{ + p->remainLen = kMatchSpecLenStart + 1; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->remainLen = kMatchSpecLenStart + 2; + } + if (initState) + p->remainLen = kMatchSpecLenStart + 2; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + + *status = LZMA_STATUS_NOT_SPECIFIED; + + if (p->remainLen > kMatchSpecLenStart) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize != 0 && p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + p->range = 0xFFFFFFFF; + p->tempBufSize = 0; + + if (p->remainLen > kMatchSpecLenStart + 1) + { + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + } + + p->remainLen = 0; + } + + LzmaDec_WriteRem(p, dicLimit); + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow = 0; + + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT)rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += (SizeT)lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + + { + unsigned kkk = (unsigned)(p->buf - p->tempBuf); + if (rem < kkk) + return SZ_ERROR_FAIL; /* some internal error */ + rem -= kkk; + if (lookAhead < rem) + return SZ_ERROR_FAIL; /* some internal error */ + lookAhead -= rem; + } + (*srcLen) += (SizeT)lookAhead; + src += lookAhead; + inSize -= (SizeT)lookAhead; + p->tempBufSize = 0; + } + } + + if (p->code != 0) + return SZ_ERROR_DATA; + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; +} + + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->probs); + p->probs = NULL; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->dic); + p->dic = NULL; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = (Byte)(d % 9); + d /= 9; + p->pb = (Byte)(d / 5); + p->lp = (Byte)(d % 5); + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (!p->probs || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb)); + if (!p->probs) + return SZ_ERROR_MEM; + p->probs_1664 = p->probs + 1664; + p->numProbs = numProbs; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } + + if (!p->dic || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize); + if (!p->dic) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAllocPtr alloc) +{ + CLzmaDec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + LzmaDec_Construct(&p); + RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); + p.dic = dest; + p.dicBufSize = outSize; + LzmaDec_Init(&p); + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/utils/lzma/C/LzmaDec.h b/utils/lzma/C/LzmaDec.h new file mode 100644 index 0000000..1f0927a --- /dev/null +++ b/utils/lzma/C/LzmaDec.h @@ -0,0 +1,234 @@ +/* LzmaDec.h -- LZMA Decoder +2018-04-21 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +typedef +#ifdef _LZMA_PROB32 + UInt32 +#else + UInt16 +#endif + CLzmaProb; + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + Byte lc; + Byte lp; + Byte pb; + Byte _pad_; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + /* Don't change this structure. ASM code can use it. */ + CLzmaProps prop; + CLzmaProb *probs; + CLzmaProb *probs_1664; + Byte *dic; + SizeT dicBufSize; + SizeT dicPos; + const Byte *buf; + UInt32 range; + UInt32 code; + UInt32 processedPos; + UInt32 checkDicSize; + UInt32 reps[4]; + UInt32 state; + UInt32 remainLen; + + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + - Stream with end mark. That end mark adds about 6 bytes to compressed size. + - Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc); + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); +void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Construct() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/LzmaEnc.c b/utils/lzma/C/LzmaEnc.c new file mode 100644 index 0000000..46a0db0 --- /dev/null +++ b/utils/lzma/C/LzmaEnc.c @@ -0,0 +1,2976 @@ +/* LzmaEnc.c -- LZMA Encoder +2019-01-10: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "LzmaEnc.h" + +#include "LzFind.h" +#ifndef _7ZIP_ST +#include "LzFindMt.h" +#endif + +#ifdef SHOW_STAT +static unsigned g_STAT_OFFSET = 0; +#endif + +#define kLzmaMaxHistorySize ((UInt32)3 << 29) +/* #define kLzmaMaxHistorySize ((UInt32)7 << 29) */ + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +#define kBitPrice (1 << kNumBitPriceShiftBits) + +#define REP_LEN_COUNT 64 + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->reduceSize = (UInt64)(Int64)-1; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->writeEndMark = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level <= 7 ? (1 << 25) : (1 << 26))); + if (p->dictSize > p->reduceSize) + { + unsigned i; + UInt32 reduceSize = (UInt32)p->reduceSize; + for (i = 11; i <= 30; i++) + { + if (reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } + if (reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } + } + } + + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); + if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = 4; + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + + if (p->numThreads < 0) + p->numThreads = + #ifndef _7ZIP_ST + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + +#if (_MSC_VER >= 1400) +/* BSR code is fast for some new CPUs */ +/* #define LZMA_LOG_BSR */ +#endif + +#ifdef LZMA_LOG_BSR + +#define kDicLogSizeMaxCompress 32 + +#define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); res = (zz + zz) + ((pos >> (zz - 1)) & 1); } + +static unsigned GetPosSlot1(UInt32 pos) +{ + unsigned res; + BSR2_RET(pos, res); + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } + +#else + +#define kNumLogBits (9 + sizeof(size_t) / 2) +/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */ + +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +static void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + unsigned slot; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + g_FastPos += 2; + + for (slot = 2; slot < kNumLogBits * 2; slot++) + { + size_t k = ((size_t)1 << ((slot >> 1) - 1)); + size_t j; + for (j = 0; j < k; j++) + g_FastPos[j] = (Byte)slot; + g_FastPos += k; + } +} + +/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ +/* +#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } +*/ + +/* +#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } +*/ + +#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } + +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); } + +#endif + + +#define LZMA_NUM_REPS 4 + +typedef UInt16 CState; +typedef UInt16 CExtra; + +typedef struct +{ + UInt32 price; + CState state; + CExtra extra; + // 0 : normal + // 1 : LIT : MATCH + // > 1 : MATCH (extra-1) : LIT : REP0 (len) + UInt32 len; + UInt32 dist; + UInt32 reps[LZMA_NUM_REPS]; +} COptimal; + + +// 18.06 +#define kNumOpts (1 << 11) +#define kPackReserve (kNumOpts * 8) +// #define kNumOpts (1 << 12) +// #define kPackReserve (1 + kNumOpts * 2) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +#define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +typedef +#ifdef _LZMA_PROB32 + UInt32 +#else + UInt16 +#endif + CLzmaProb; + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) +#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + + +typedef struct +{ + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + + +typedef struct +{ + unsigned tableSize; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2]; + // UInt32 prices2[kLenNumSymbolsTotal]; +} CLenPriceEnc; + +#define GET_PRICE_LEN(p, posState, len) \ + ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN]) + +/* +#define GET_PRICE_LEN(p, posState, len) \ + ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9))) +*/ + +typedef struct +{ + UInt32 range; + unsigned cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStream *outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + + +typedef struct +{ + CLzmaProb *litProbs; + + unsigned state; + UInt32 reps[LZMA_NUM_REPS]; + + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances]; + + CLenEnc lenProbs; + CLenEnc repLenProbs; + +} CSaveState; + + +typedef UInt32 CProbPrice; + + +typedef struct +{ + void *matchFinderObj; + IMatchFinder matchFinder; + + unsigned optCur; + unsigned optEnd; + + unsigned longestMatchLen; + unsigned numPairs; + UInt32 numAvail; + + unsigned state; + unsigned numFastBytes; + unsigned additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + unsigned lpMask, pbMask; + CLzmaProb *litProbs; + CRangeEnc rc; + + UInt32 backRes; + + unsigned lc, lp, pb; + unsigned lclp; + + BoolInt fastMode; + BoolInt writeEndMark; + BoolInt finished; + BoolInt multiThread; + BoolInt needInit; + // BoolInt _maxMode; + + UInt64 nowPos64; + + unsigned matchPriceCount; + // unsigned alignPriceCount; + int repLenEncCounter; + + unsigned distTableSize; + + UInt32 dictSize; + SRes result; + + #ifndef _7ZIP_ST + BoolInt mtMode; + // begin of CMatchFinderMt is used in LZ thread + CMatchFinderMt matchFinderMt; + // end of CMatchFinderMt is used in BT and HASH threads + #endif + + CMatchFinder matchFinderBase; + + #ifndef _7ZIP_ST + Byte pad[128]; + #endif + + // LZ thread + CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + + UInt32 alignPrices[kAlignTableSize]; + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances]; + + CLenEnc lenProbs; + CLenEnc repLenProbs; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + COptimal opt[kNumOpts]; + + CSaveState saveState; + + #ifndef _7ZIP_ST + Byte pad2[128]; + #endif +} CLzmaEnc; + + + +#define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr)); + +void LzmaEnc_SaveState(CLzmaEncHandle pp) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CSaveState *dest = &p->saveState; + + dest->state = p->state; + + dest->lenProbs = p->lenProbs; + dest->repLenProbs = p->repLenProbs; + + COPY_ARR(dest, p, reps); + + COPY_ARR(dest, p, posAlignEncoder); + COPY_ARR(dest, p, isRep); + COPY_ARR(dest, p, isRepG0); + COPY_ARR(dest, p, isRepG1); + COPY_ARR(dest, p, isRepG2); + COPY_ARR(dest, p, isMatch); + COPY_ARR(dest, p, isRep0Long); + COPY_ARR(dest, p, posSlotEncoder); + COPY_ARR(dest, p, posEncoders); + + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); +} + + +void LzmaEnc_RestoreState(CLzmaEncHandle pp) +{ + CLzmaEnc *dest = (CLzmaEnc *)pp; + const CSaveState *p = &dest->saveState; + + dest->state = p->state; + + dest->lenProbs = p->lenProbs; + dest->repLenProbs = p->repLenProbs; + + COPY_ARR(dest, p, reps); + + COPY_ARR(dest, p, posAlignEncoder); + COPY_ARR(dest, p, isRep); + COPY_ARR(dest, p, isRepG0); + COPY_ARR(dest, p, isRepG1); + COPY_ARR(dest, p, isRepG2); + COPY_ARR(dest, p, isMatch); + COPY_ARR(dest, p, isRep0Long); + COPY_ARR(dest, p, posSlotEncoder); + COPY_ARR(dest, p, posEncoders); + + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); +} + + + +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX + || props.lp > LZMA_LP_MAX + || props.pb > LZMA_PB_MAX + || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress) + || props.dictSize > kLzmaMaxHistorySize) + return SZ_ERROR_PARAM; + + p->dictSize = props.dictSize; + { + unsigned fb = props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = props.lc; + p->lp = props.lp; + p->pb = props.pb; + p->fastMode = (props.algo == 0); + // p->_maxMode = True; + p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0); + { + unsigned numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) + numHashBytes = 2; + else if (props.numHashBytes < 4) + numHashBytes = props.numHashBytes; + } + p->matchFinderBase.numHashBytes = numHashBytes; + } + + p->matchFinderBase.cutValue = props.mc; + + p->writeEndMark = props.writeEndMark; + + #ifndef _7ZIP_ST + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + #endif + + return SZ_OK; +} + + +void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.expectedDataSize = expectedDataSiize; +} + + +#define kState_Start 0 +#define kState_LitAfterMatch 4 +#define kState_LitAfterRep 5 +#define kState_MatchAfterLit 7 +#define kState_RepAfterLit 8 + +static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsLitState(s) ((s) < 7) +#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1) +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = NULL; + p->bufBase = NULL; +} + +#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) +#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + ((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) + +static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc) +{ + if (!p->bufBase) + { + p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE); + if (!p->bufBase) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->bufBase); + p->bufBase = 0; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + /* Stream.Init(); */ + p->range = 0xFFFFFFFF; + p->cache = 0; + p->low = 0; + p->cacheSize = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) +{ + size_t num; + if (p->res != SZ_OK) + return; + num = p->buf - p->bufBase; + if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + p->processed += num; + p->buf = p->bufBase; +} + +MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + UInt32 low = (UInt32)p->low; + unsigned high = (unsigned)(p->low >> 32); + p->low = (UInt32)(low << 8); + if (low < (UInt32)0xFF000000 || high != 0) + { + { + Byte *buf = p->buf; + *buf++ = (Byte)(p->cache + high); + p->cache = (unsigned)(low >> 24); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + if (p->cacheSize == 0) + return; + } + high += 0xFF; + for (;;) + { + Byte *buf = p->buf; + *buf++ = (Byte)(high); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + if (--p->cacheSize == 0) + return; + } + } + p->cacheSize++; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); } + +#define RC_BIT_PRE(p, prob) \ + ttt = *(prob); \ + newBound = (range >> kNumBitModelTotalBits) * ttt; + +// #define _LZMA_ENC_USE_BRANCH + +#ifdef _LZMA_ENC_USE_BRANCH + +#define RC_BIT(p, prob, bit) { \ + RC_BIT_PRE(p, prob) \ + if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \ + else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \ + *(prob) = (CLzmaProb)ttt; \ + RC_NORM(p) \ + } + +#else + +#define RC_BIT(p, prob, bit) { \ + UInt32 mask; \ + RC_BIT_PRE(p, prob) \ + mask = 0 - (UInt32)bit; \ + range &= mask; \ + mask &= newBound; \ + range -= mask; \ + (p)->low += mask; \ + mask = (UInt32)bit - 1; \ + range += newBound & mask; \ + mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \ + mask += ((1 << kNumMoveBits) - 1); \ + ttt += (Int32)(mask - ttt) >> kNumMoveBits; \ + *(prob) = (CLzmaProb)ttt; \ + RC_NORM(p) \ + } + +#endif + + + + +#define RC_BIT_0_BASE(p, prob) \ + range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + +#define RC_BIT_1_BASE(p, prob) \ + range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \ + +#define RC_BIT_0(p, prob) \ + RC_BIT_0_BASE(p, prob) \ + RC_NORM(p) + +#define RC_BIT_1(p, prob) \ + RC_BIT_1_BASE(p, prob) \ + RC_NORM(p) + +static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob) +{ + UInt32 range, ttt, newBound; + range = p->range; + RC_BIT_PRE(p, prob) + RC_BIT_0(p, prob) + p->range = range; +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym) +{ + UInt32 range = p->range; + sym |= 0x100; + do + { + UInt32 ttt, newBound; + // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1); + CLzmaProb *prob = probs + (sym >> 8); + UInt32 bit = (sym >> 7) & 1; + sym <<= 1; + RC_BIT(p, prob, bit); + } + while (sym < 0x10000); + p->range = range; +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte) +{ + UInt32 range = p->range; + UInt32 offs = 0x100; + sym |= 0x100; + do + { + UInt32 ttt, newBound; + CLzmaProb *prob; + UInt32 bit; + matchByte <<= 1; + // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1); + prob = probs + (offs + (matchByte & offs) + (sym >> 8)); + bit = (sym >> 7) & 1; + sym <<= 1; + offs &= ~(matchByte ^ sym); + RC_BIT(p, prob, bit); + } + while (sym < 0x10000); + p->range = range; +} + + + +static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices) +{ + UInt32 i; + for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++) + { + const unsigned kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1)); + unsigned bitCount = 0; + unsigned j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i] = (CProbPrice)((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + // printf("\n%3d: %5d", i, ProbPrices[i]); + } +} + + +#define GET_PRICE(prob, bit) \ + p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICEa(prob, bit) \ + ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices) +{ + UInt32 price = 0; + sym |= 0x100; + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[sym], bit); + } + while (sym >= 2); + return price; +} + + +static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + sym |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1); + sym <<= 1; + offs &= ~(matchByte ^ sym); + } + while (sym < 0x10000); + return price; +} + + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym) +{ + UInt32 range = rc->range; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + unsigned bit = sym & 1; + // RangeEnc_EncodeBit(rc, probs + m, bit); + sym >>= 1; + RC_BIT(rc, probs + m, bit); + m = (m << 1) | bit; + } + while (--numBits); + rc->range = range; +} + + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState) +{ + UInt32 range, ttt, newBound; + CLzmaProb *probs = p->low; + range = rc->range; + RC_BIT_PRE(rc, probs); + if (sym >= kLenNumLowSymbols) + { + RC_BIT_1(rc, probs); + probs += kLenNumLowSymbols; + RC_BIT_PRE(rc, probs); + if (sym >= kLenNumLowSymbols * 2) + { + RC_BIT_1(rc, probs); + rc->range = range; + // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2); + LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2); + return; + } + sym -= kLenNumLowSymbols; + } + + // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym); + { + unsigned m; + unsigned bit; + RC_BIT_0(rc, probs); + probs += (posState << (1 + kLenNumLowBits)); + bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit; + bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit; + bit = sym & 1; RC_BIT(rc, probs + m, bit); + rc->range = range; + } +} + +static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices) +{ + unsigned i; + for (i = 0; i < 8; i += 2) + { + UInt32 price = startPrice; + UInt32 prob; + price += GET_PRICEa(probs[1 ], (i >> 2)); + price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1); + prob = probs[4 + (i >> 1)]; + prices[i ] = price + GET_PRICEa_0(prob); + prices[i + 1] = price + GET_PRICEa_1(prob); + } +} + + +MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables( + CLenPriceEnc *p, + unsigned numPosStates, + const CLenEnc *enc, + const CProbPrice *ProbPrices) +{ + UInt32 b; + + { + unsigned prob = enc->low[0]; + UInt32 a, c; + unsigned posState; + b = GET_PRICEa_1(prob); + a = GET_PRICEa_0(prob); + c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); + for (posState = 0; posState < numPosStates; posState++) + { + UInt32 *prices = p->prices[posState]; + const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); + SetPrices_3(probs, a, prices, ProbPrices); + SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); + } + } + + /* + { + unsigned i; + UInt32 b; + a = GET_PRICEa_0(enc->low[0]); + for (i = 0; i < kLenNumLowSymbols; i++) + p->prices2[i] = a; + a = GET_PRICEa_1(enc->low[0]); + b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); + for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++) + p->prices2[i] = b; + a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); + } + */ + + // p->counter = numSymbols; + // p->counter = 64; + + { + unsigned i = p->tableSize; + + if (i > kLenNumLowSymbols * 2) + { + const CLzmaProb *probs = enc->high; + UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2; + i -= kLenNumLowSymbols * 2 - 1; + i >>= 1; + b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); + do + { + /* + p->prices2[i] = a + + // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices); + LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices); + */ + // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices); + unsigned sym = --i + (1 << (kLenNumHighBits - 1)); + UInt32 price = b; + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[sym], bit); + } + while (sym >= 2); + + { + unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))]; + prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob); + prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob); + } + } + while (i); + + { + unsigned posState; + size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]); + for (posState = 1; posState < numPosStates; posState++) + memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num); + } + } + } +} + +/* + #ifdef SHOW_STAT + g_STAT_OFFSET += num; + printf("\n MovePos %u", num); + #endif +*/ + +#define MOVE_POS(p, num) { \ + p->additionalOffset += (num); \ + p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); } + + +static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) +{ + unsigned numPairs; + + p->additionalOffset++; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + *numPairsRes = numPairs; + + #ifdef SHOW_STAT + printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); + g_STAT_OFFSET++; + { + unsigned i; + for (i = 0; i < numPairs; i += 2) + printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); + } + #endif + + if (numPairs == 0) + return 0; + { + unsigned len = p->matches[(size_t)numPairs - 2]; + if (len != p->numFastBytes) + return len; + { + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + const Byte *p2 = p1 + len; + ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[(size_t)numPairs - 1]; + const Byte *lim = p1 + numAvail; + for (; p2 != lim && *p2 == p2[dif]; p2++) + {} + return (unsigned)(p2 - p1); + } + } + } +} + +#define MARK_LIT ((UInt32)(Int32)-1) + +#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; } +#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; } +#define IsShortRep(p) ((p)->dist == 0) + + +#define GetPrice_ShortRep(p, state, posState) \ + ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState])) + +#define GetPrice_Rep_0(p, state, posState) ( \ + GET_PRICE_1(p->isMatch[state][posState]) \ + + GET_PRICE_1(p->isRep0Long[state][posState])) \ + + GET_PRICE_1(p->isRep[state]) \ + + GET_PRICE_0(p->isRepG0[state]) + +MY_FORCE_INLINE +static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState) +{ + UInt32 price; + UInt32 prob = p->isRepG0[state]; + if (repIndex == 0) + { + price = GET_PRICE_0(prob); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(prob); + prob = p->isRepG1[state]; + if (repIndex == 1) + price += GET_PRICE_0(prob); + else + { + price += GET_PRICE_1(prob); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + + +static unsigned Backward(CLzmaEnc *p, unsigned cur) +{ + unsigned wr = cur + 1; + p->optEnd = wr; + + for (;;) + { + UInt32 dist = p->opt[cur].dist; + unsigned len = (unsigned)p->opt[cur].len; + unsigned extra = (unsigned)p->opt[cur].extra; + cur -= len; + + if (extra) + { + wr--; + p->opt[wr].len = (UInt32)len; + cur -= extra; + len = extra; + if (extra == 1) + { + p->opt[wr].dist = dist; + dist = MARK_LIT; + } + else + { + p->opt[wr].dist = 0; + len--; + wr--; + p->opt[wr].dist = MARK_LIT; + p->opt[wr].len = 1; + } + } + + if (cur == 0) + { + p->backRes = dist; + p->optCur = wr; + return len; + } + + wr--; + p->opt[wr].dist = dist; + p->opt[wr].len = (UInt32)len; + } +} + + + +#define LIT_PROBS(pos, prevByte) \ + (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc)) + + +static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) +{ + unsigned last, cur; + UInt32 reps[LZMA_NUM_REPS]; + unsigned repLens[LZMA_NUM_REPS]; + UInt32 *matches; + + { + UInt32 numAvail; + unsigned numPairs, mainLen, repMaxIndex, i, posState; + UInt32 matchPrice, repMatchPrice; + const Byte *data; + Byte curByte, matchByte; + + p->optCur = p->optEnd = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLen; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + p->backRes = MARK_LIT; + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + repLens[i] = len; + if (len > repLens[repMaxIndex]) + repMaxIndex = i; + } + + if (repLens[repMaxIndex] >= p->numFastBytes) + { + unsigned len; + p->backRes = (UInt32)repMaxIndex; + len = repLens[repMaxIndex]; + MOVE_POS(p, len - 1) + return len; + } + + matches = p->matches; + + if (mainLen >= p->numFastBytes) + { + p->backRes = matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; + MOVE_POS(p, mainLen - 1) + return mainLen; + } + + curByte = *data; + matchByte = *(data - reps[0]); + + last = repLens[repMaxIndex]; + if (last <= mainLen) + last = mainLen; + + if (last < 2 && curByte != matchByte) + { + p->backRes = MARK_LIT; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsLitState(p->state) ? + LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAs_Lit(&p->opt[1]); + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + // 18.06 + if (matchByte == curByte && repLens[0] == 0) + { + UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAs_ShortRep(&p->opt[1]); + } + if (last < 2) + { + p->backRes = p->opt[1].dist; + return 1; + } + } + + p->opt[1].len = 1; + + p->opt[0].reps[0] = reps[0]; + p->opt[0].reps[1] = reps[1]; + p->opt[0].reps[2] = reps[2]; + p->opt[0].reps[3] = reps[3]; + + // ---------- REP ---------- + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState); + do + { + UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen); + COptimal *opt = &p->opt[repLen]; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)repLen; + opt->dist = (UInt32)i; + opt->extra = 0; + } + } + while (--repLen >= 2); + } + + + // ---------- MATCH ---------- + { + unsigned len = repLens[0] + 1; + if (len <= mainLen) + { + unsigned offs = 0; + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + if (len < 2) + len = 2; + else + while (len > matches[offs]) + offs += 2; + + for (; ; len++) + { + COptimal *opt; + UInt32 dist = matches[(size_t)offs + 1]; + UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); + unsigned lenToPosState = GetLenToPosState(len); + + if (dist < kNumFullDistances) + price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)]; + else + { + unsigned slot; + GetPosSlot2(dist, slot); + price += p->alignPrices[dist & kAlignMask]; + price += p->posSlotPrices[lenToPosState][slot]; + } + + opt = &p->opt[len]; + + if (price < opt->price) + { + opt->price = price; + opt->len = (UInt32)len; + opt->dist = dist + LZMA_NUM_REPS; + opt->extra = 0; + } + + if (len == matches[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + } + + + cur = 0; + + #ifdef SHOW_STAT2 + /* if (position >= 0) */ + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= last; i++) + printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); + } + #endif + } + + + + // ---------- Optimal Parsing ---------- + + for (;;) + { + unsigned numAvail; + UInt32 numAvailFull; + unsigned newLen, numPairs, prev, state, posState, startLen; + UInt32 litPrice, matchPrice, repMatchPrice; + BoolInt nextIsLit; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt, *nextOpt; + + if (++cur == last) + break; + + // 18.06 + if (cur >= kNumOpts - 64) + { + unsigned j, best; + UInt32 price = p->opt[cur].price; + best = cur; + for (j = cur + 1; j <= last; j++) + { + UInt32 price2 = p->opt[j].price; + if (price >= price2) + { + price = price2; + best = j; + } + } + { + unsigned delta = best - cur; + if (delta != 0) + { + MOVE_POS(p, delta); + } + } + cur = best; + break; + } + + newLen = ReadMatchDistances(p, &numPairs); + + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLen = newLen; + break; + } + + curOpt = &p->opt[cur]; + + position++; + + // we need that check here, if skip_items in p->opt are possible + /* + if (curOpt->price >= kInfinityPrice) + continue; + */ + + prev = cur - curOpt->len; + + if (curOpt->len == 1) + { + state = (unsigned)p->opt[prev].state; + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + const COptimal *prevOpt; + UInt32 b0; + UInt32 dist = curOpt->dist; + + if (curOpt->extra) + { + prev -= (unsigned)curOpt->extra; + state = kState_RepAfterLit; + if (curOpt->extra == 1) + state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit); + } + else + { + state = (unsigned)p->opt[prev].state; + if (dist < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + + prevOpt = &p->opt[prev]; + b0 = prevOpt->reps[0]; + + if (dist < LZMA_NUM_REPS) + { + if (dist == 0) + { + reps[0] = b0; + reps[1] = prevOpt->reps[1]; + reps[2] = prevOpt->reps[2]; + reps[3] = prevOpt->reps[3]; + } + else + { + reps[1] = b0; + b0 = prevOpt->reps[1]; + if (dist == 1) + { + reps[0] = b0; + reps[2] = prevOpt->reps[2]; + reps[3] = prevOpt->reps[3]; + } + else + { + reps[2] = b0; + reps[0] = prevOpt->reps[dist]; + reps[3] = prevOpt->reps[dist ^ 1]; + } + } + } + else + { + reps[0] = (dist - LZMA_NUM_REPS + 1); + reps[1] = b0; + reps[2] = prevOpt->reps[1]; + reps[3] = prevOpt->reps[2]; + } + } + + curOpt->state = (CState)state; + curOpt->reps[0] = reps[0]; + curOpt->reps[1] = reps[1]; + curOpt->reps[2] = reps[2]; + curOpt->reps[3] = reps[3]; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - reps[0]); + + posState = (position & p->pbMask); + + /* + The order of Price checks: + < LIT + <= SHORT_REP + < LIT : REP_0 + < REP [ : LIT : REP_0 ] + < MATCH [ : LIT : REP_0 ] + */ + + { + UInt32 curPrice = curOpt->price; + unsigned prob = p->isMatch[state][posState]; + matchPrice = curPrice + GET_PRICE_1(prob); + litPrice = curPrice + GET_PRICE_0(prob); + } + + nextOpt = &p->opt[(size_t)cur + 1]; + nextIsLit = False; + + // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice) + // 18.new.06 + if ((nextOpt->price < kInfinityPrice + // && !IsLitState(state) + && matchByte == curByte) + || litPrice > nextOpt->price + ) + litPrice = 0; + else + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + litPrice += (!IsLitState(state) ? + LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + + if (litPrice < nextOpt->price) + { + nextOpt->price = litPrice; + nextOpt->len = 1; + MakeAs_Lit(nextOpt); + nextIsLit = True; + } + } + + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + numAvailFull = p->numAvail; + { + unsigned temp = kNumOpts - 1 - cur; + if (numAvailFull > temp) + numAvailFull = (UInt32)temp; + } + + // 18.06 + // ---------- SHORT_REP ---------- + if (IsLitState(state)) // 18.new + if (matchByte == curByte) + if (repMatchPrice < nextOpt->price) // 18.new + // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1)) + if ( + // nextOpt->price >= kInfinityPrice || + nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt + || (nextOpt->dist != 0 + // && nextOpt->extra <= 1 // 17.old + ) + ) + { + UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState); + // if (shortRepPrice <= nextOpt->price) // 17.old + if (shortRepPrice < nextOpt->price) // 18.new + { + nextOpt->price = shortRepPrice; + nextOpt->len = 1; + MakeAs_ShortRep(nextOpt); + nextIsLit = False; + } + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + // numAvail <= p->numFastBytes + + // ---------- LIT : REP_0 ---------- + + if (!nextIsLit + && litPrice != 0 // 18.new + && matchByte != curByte + && numAvailFull > 2) + { + const Byte *data2 = data - reps[0]; + if (data[1] == data2[1] && data[2] == data2[2]) + { + unsigned len; + unsigned limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + for (len = 3; len < limit && data[len] == data2[len]; len++) + {} + + { + unsigned state2 = kLiteralNextStates[state]; + unsigned posState2 = (position + 1) & p->pbMask; + UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2); + { + unsigned offset = cur + len; + + if (last < offset) + last = offset; + + // do + { + UInt32 price2; + COptimal *opt; + len--; + // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len); + + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len; + opt->dist = 0; + opt->extra = 1; + } + } + // while (len >= 3); + } + } + } + } + + startLen = 2; /* speed optimization */ + + { + // ---------- REP ---------- + unsigned repIndex = 0; // 17.old + // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused + for (; repIndex < LZMA_NUM_REPS; repIndex++) + { + unsigned len; + UInt32 price; + const Byte *data2 = data - reps[repIndex]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + + // if (len < startLen) continue; // 18.new: speed optimization + + { + unsigned offset = cur + len; + if (last < offset) + last = offset; + } + { + unsigned len2 = len; + price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState); + do + { + UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2); + COptimal *opt = &p->opt[cur + len2]; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->dist = (UInt32)repIndex; + opt->extra = 0; + } + } + while (--len2 >= 2); + } + + if (repIndex == 0) startLen = len + 1; // 17.old + // startLen = len + 1; // 18.new + + /* if (_maxMode) */ + { + // ---------- REP : LIT : REP_0 ---------- + // numFastBytes + 1 + numFastBytes + + unsigned len2 = len + 1; + unsigned limit = len2 + p->numFastBytes; + if (limit > numAvailFull) + limit = numAvailFull; + + len2 += 2; + if (len2 <= limit) + if (data[len2 - 2] == data2[len2 - 2]) + if (data[len2 - 1] == data2[len2 - 1]) + { + unsigned state2 = kRepNextStates[state]; + unsigned posState2 = (position + len) & p->pbMask; + price += GET_PRICE_LEN(&p->repLenEnc, posState, len) + + GET_PRICE_0(p->isMatch[state2][posState2]) + + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), + data[len], data2[len], p->ProbPrices); + + // state2 = kLiteralNextStates[state2]; + state2 = kState_LitAfterRep; + posState2 = (posState2 + 1) & p->pbMask; + + + price += GetPrice_Rep_0(p, state2, posState2); + + for (; len2 < limit && data[len2] == data2[len2]; len2++) + {} + + len2 -= len; + // if (len2 >= 3) + { + { + unsigned offset = cur + len + len2; + + if (last < offset) + last = offset; + // do + { + UInt32 price2; + COptimal *opt; + len2--; + // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); + + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->extra = (CExtra)(len + 1); + opt->dist = (UInt32)repIndex; + } + } + // while (len2 >= 3); + } + } + } + } + } + } + + + // ---------- MATCH ---------- + /* for (unsigned len = 2; len <= newLen; len++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); + matches[numPairs] = (UInt32)newLen; + numPairs += 2; + } + + // startLen = 2; /* speed optimization */ + + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 dist; + unsigned offs, posSlot, len; + + { + unsigned offset = cur + newLen; + if (last < offset) + last = offset; + } + + offs = 0; + while (startLen > matches[offs]) + offs += 2; + dist = matches[(size_t)offs + 1]; + + // if (dist >= kNumFullDistances) + GetPosSlot2(dist, posSlot); + + for (len = /*2*/ startLen; ; len++) + { + UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); + { + COptimal *opt; + unsigned lenNorm = len - 2; + lenNorm = GetLenToPosState2(lenNorm); + if (dist < kNumFullDistances) + price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)]; + else + price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask]; + + opt = &p->opt[cur + len]; + if (price < opt->price) + { + opt->price = price; + opt->len = (UInt32)len; + opt->dist = dist + LZMA_NUM_REPS; + opt->extra = 0; + } + } + + if (len == matches[offs]) + { + // if (p->_maxMode) { + // MATCH : LIT : REP_0 + + const Byte *data2 = data - dist - 1; + unsigned len2 = len + 1; + unsigned limit = len2 + p->numFastBytes; + if (limit > numAvailFull) + limit = numAvailFull; + + len2 += 2; + if (len2 <= limit) + if (data[len2 - 2] == data2[len2 - 2]) + if (data[len2 - 1] == data2[len2 - 1]) + { + for (; len2 < limit && data[len2] == data2[len2]; len2++) + {} + + len2 -= len; + + // if (len2 >= 3) + { + unsigned state2 = kMatchNextStates[state]; + unsigned posState2 = (position + len) & p->pbMask; + unsigned offset; + price += GET_PRICE_0(p->isMatch[state2][posState2]); + price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), + data[len], data2[len], p->ProbPrices); + + // state2 = kLiteralNextStates[state2]; + state2 = kState_LitAfterMatch; + + posState2 = (posState2 + 1) & p->pbMask; + price += GetPrice_Rep_0(p, state2, posState2); + + offset = cur + len + len2; + + if (last < offset) + last = offset; + // do + { + UInt32 price2; + COptimal *opt; + len2--; + // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->extra = (CExtra)(len + 1); + opt->dist = dist + LZMA_NUM_REPS; + } + } + // while (len2 >= 3); + } + + } + + offs += 2; + if (offs == numPairs) + break; + dist = matches[(size_t)offs + 1]; + // if (dist >= kNumFullDistances) + GetPosSlot2(dist, posSlot); + } + } + } + } + + do + p->opt[last].price = kInfinityPrice; + while (--last); + + return Backward(p, cur); +} + + + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + + + +static unsigned GetOptimumFast(CLzmaEnc *p) +{ + UInt32 numAvail, mainDist; + unsigned mainLen, numPairs, repIndex, repLen, i; + const Byte *data; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLen; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + p->backRes = MARK_LIT; + if (numAvail < 2) + return 1; + // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repLen = repIndex = 0; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len; + const Byte *data2 = data - p->reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + if (len >= p->numFastBytes) + { + p->backRes = (UInt32)i; + MOVE_POS(p, len - 1) + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + if (mainLen >= p->numFastBytes) + { + p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; + MOVE_POS(p, mainLen - 1) + return mainLen; + } + + mainDist = 0; /* for GCC */ + + if (mainLen >= 2) + { + mainDist = p->matches[(size_t)numPairs - 1]; + while (numPairs > 2) + { + UInt32 dist2; + if (mainLen != p->matches[(size_t)numPairs - 4] + 1) + break; + dist2 = p->matches[(size_t)numPairs - 3]; + if (!ChangePair(dist2, mainDist)) + break; + numPairs -= 2; + mainLen--; + mainDist = dist2; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2) + if ( repLen + 1 >= mainLen + || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) + || (repLen + 3 >= mainLen && mainDist >= (1 << 15))) + { + p->backRes = (UInt32)repIndex; + MOVE_POS(p, repLen - 1) + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + { + unsigned len1 = ReadMatchDistances(p, &p->numPairs); + p->longestMatchLen = len1; + + if (len1 >= 2) + { + UInt32 newDist = p->matches[(size_t)p->numPairs - 1]; + if ( (len1 >= mainLen && newDist < mainDist) + || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist)) + || (len1 > mainLen + 1) + || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist))) + return 1; + } + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len, limit; + const Byte *data2 = data - p->reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2;; len++) + { + if (len >= limit) + return 1; + if (data[len] != data2[len]) + break; + } + } + + p->backRes = mainDist + LZMA_NUM_REPS; + if (mainLen != 2) + { + MOVE_POS(p, mainLen - 2) + } + return mainLen; +} + + + + +static void WriteEndMarker(CLzmaEnc *p, unsigned posState) +{ + UInt32 range; + range = p->rc.range; + { + UInt32 ttt, newBound; + CLzmaProb *prob = &p->isMatch[p->state][posState]; + RC_BIT_PRE(&p->rc, prob) + RC_BIT_1(&p->rc, prob) + prob = &p->isRep[p->state]; + RC_BIT_PRE(&p->rc, prob) + RC_BIT_0(&p->rc, prob) + } + p->state = kMatchNextStates[p->state]; + + p->rc.range = range; + LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState); + range = p->rc.range; + + { + // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1); + CLzmaProb *probs = p->posSlotEncoder[0]; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + RC_BIT_PRE(p, probs + m) + RC_BIT_1(&p->rc, probs + m); + m = (m << 1) + 1; + } + while (m < (1 << kNumPosSlotBits)); + } + { + // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range; + unsigned numBits = 30 - kNumAlignBits; + do + { + range >>= 1; + p->rc.low += range; + RC_NORM(&p->rc) + } + while (--numBits); + } + + { + // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); + CLzmaProb *probs = p->posAlignEncoder; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + RC_BIT_PRE(p, probs + m) + RC_BIT_1(&p->rc, probs + m); + m = (m << 1) + 1; + } + while (m < kAlignTableSize); + } + p->rc.range = range; +} + + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + if (p->matchFinderBase.result != SZ_OK) + p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + + +MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + + +MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) +{ + unsigned i; + const CProbPrice *ProbPrices = p->ProbPrices; + const CLzmaProb *probs = p->posAlignEncoder; + // p->alignPriceCount = 0; + for (i = 0; i < kAlignTableSize / 2; i++) + { + UInt32 price = 0; + unsigned sym = i; + unsigned m = 1; + unsigned bit; + UInt32 prob; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + prob = probs[m]; + p->alignPrices[i ] = price + GET_PRICEa_0(prob); + p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); + // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + } +} + + +MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) +{ + // int y; for (y = 0; y < 100; y++) { + + UInt32 tempPrices[kNumFullDistances]; + unsigned i, lps; + + const CProbPrice *ProbPrices = p->ProbPrices; + p->matchPriceCount = 0; + + for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++) + { + unsigned posSlot = GetPosSlot1(i); + unsigned footerBits = (posSlot >> 1) - 1; + unsigned base = ((2 | (posSlot & 1)) << footerBits); + const CLzmaProb *probs = p->posEncoders + (size_t)base * 2; + // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices); + UInt32 price = 0; + unsigned m = 1; + unsigned sym = i; + unsigned offset = (unsigned)1 << footerBits; + base += i; + + if (footerBits) + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) + bit; + } + while (--footerBits); + + { + unsigned prob = probs[m]; + tempPrices[base ] = price + GET_PRICEa_0(prob); + tempPrices[base + offset] = price + GET_PRICEa_1(prob); + } + } + + for (lps = 0; lps < kNumLenToPosStates; lps++) + { + unsigned slot; + unsigned distTableSize2 = (p->distTableSize + 1) >> 1; + UInt32 *posSlotPrices = p->posSlotPrices[lps]; + const CLzmaProb *probs = p->posSlotEncoder[lps]; + + for (slot = 0; slot < distTableSize2; slot++) + { + // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices); + UInt32 price; + unsigned bit; + unsigned sym = slot + (1 << (kNumPosSlotBits - 1)); + unsigned prob; + bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))]; + posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob); + posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob); + } + + { + UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++) + { + posSlotPrices[(size_t)slot * 2 ] += delta; + posSlotPrices[(size_t)slot * 2 + 1] += delta; + delta += ((UInt32)1 << kNumBitPriceShiftBits); + } + } + + { + UInt32 *dp = p->distancesPrices[lps]; + + dp[0] = posSlotPrices[0]; + dp[1] = posSlotPrices[1]; + dp[2] = posSlotPrices[2]; + dp[3] = posSlotPrices[3]; + + for (i = 4; i < kNumFullDistances; i += 2) + { + UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)]; + dp[i ] = slotPrice + tempPrices[i]; + dp[i + 1] = slotPrice + tempPrices[i + 1]; + } + } + } + // } +} + + + +void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); + + #ifndef _7ZIP_ST + MatchFinderMt_Construct(&p->matchFinderMt); + p->matchFinderMt.MatchFinder = &p->matchFinderBase; + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps(p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = NULL; + p->saveState.litProbs = NULL; + +} + +CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) +{ + void *p; + p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc)); + if (p) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->litProbs); + ISzAlloc_Free(alloc, p->saveState.litProbs); + p->litProbs = NULL; + p->saveState.litProbs = NULL; +} + +void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + + MatchFinder_Free(&p->matchFinderBase, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + ISzAlloc_Free(alloc, p); +} + + +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->needInit) + { + p->matchFinder.Init(p->matchFinderObj); + p->needInit = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)); + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + unsigned numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]); + // p->state = kLiteralNextStates[p->state]; + curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + + for (;;) + { + UInt32 dist; + unsigned len, posState; + UInt32 range, ttt, newBound; + CLzmaProb *probs; + + if (p->fastMode) + len = GetOptimumFast(p); + else + { + unsigned oci = p->optCur; + if (p->optEnd == oci) + len = GetOptimum(p, nowPos32); + else + { + const COptimal *opt = &p->opt[oci]; + len = opt->len; + p->backRes = opt->dist; + p->optCur = oci + 1; + } + } + + posState = (unsigned)nowPos32 & p->pbMask; + range = p->rc.range; + probs = &p->isMatch[p->state][posState]; + + RC_BIT_PRE(&p->rc, probs) + + dist = p->backRes; + + #ifdef SHOW_STAT2 + printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist); + #endif + + if (dist == MARK_LIT) + { + Byte curByte; + const Byte *data; + unsigned state; + + RC_BIT_0(&p->rc, probs); + p->rc.range = range; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + probs = LIT_PROBS(nowPos32, *(data - 1)); + curByte = *data; + state = p->state; + p->state = kLiteralNextStates[state]; + if (IsLitState(state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0])); + } + else + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRep[p->state]; + RC_BIT_PRE(&p->rc, probs) + + if (dist < LZMA_NUM_REPS) + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRepG0[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 0) + { + RC_BIT_0(&p->rc, probs); + probs = &p->isRep0Long[p->state][posState]; + RC_BIT_PRE(&p->rc, probs) + if (len != 1) + { + RC_BIT_1_BASE(&p->rc, probs); + } + else + { + RC_BIT_0_BASE(&p->rc, probs); + p->state = kShortRepNextStates[p->state]; + } + } + else + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRepG1[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 1) + { + RC_BIT_0_BASE(&p->rc, probs); + dist = p->reps[1]; + } + else + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRepG2[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 2) + { + RC_BIT_0_BASE(&p->rc, probs); + dist = p->reps[2]; + } + else + { + RC_BIT_1_BASE(&p->rc, probs); + dist = p->reps[3]; + p->reps[3] = p->reps[2]; + } + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = dist; + } + + RC_NORM(&p->rc) + + p->rc.range = range; + + if (len != 1) + { + LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); + --p->repLenEncCounter; + p->state = kRepNextStates[p->state]; + } + } + else + { + unsigned posSlot; + RC_BIT_0(&p->rc, probs); + p->rc.range = range; + p->state = kMatchNextStates[p->state]; + + LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); + // --p->lenEnc.counter; + + dist -= LZMA_NUM_REPS; + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = dist + 1; + + p->matchPriceCount++; + GetPosSlot(dist, posSlot); + // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot); + { + UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits); + range = p->rc.range; + probs = p->posSlotEncoder[GetLenToPosState(len)]; + do + { + CLzmaProb *prob = probs + (sym >> kNumPosSlotBits); + UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1; + sym <<= 1; + RC_BIT(&p->rc, prob, bit); + } + while (sym < (1 << kNumPosSlotBits * 2)); + p->rc.range = range; + } + + if (dist >= kStartPosModelIndex) + { + unsigned footerBits = ((posSlot >> 1) - 1); + + if (dist < kNumFullDistances) + { + unsigned base = ((2 | (posSlot & 1)) << footerBits); + RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */)); + } + else + { + UInt32 pos2 = (dist | 0xF) << (32 - footerBits); + range = p->rc.range; + // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + /* + do + { + range >>= 1; + p->rc.low += range & (0 - ((dist >> --footerBits) & 1)); + RC_NORM(&p->rc) + } + while (footerBits > kNumAlignBits); + */ + do + { + range >>= 1; + p->rc.low += range & (0 - (pos2 >> 31)); + pos2 += pos2; + RC_NORM(&p->rc) + } + while (pos2 != 0xF0000000); + + + // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + + { + unsigned m = 1; + unsigned bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; + bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); + p->rc.range = range; + // p->alignPriceCount++; + } + } + } + } + } + + nowPos32 += (UInt32)len; + p->additionalOffset -= len; + + if (p->additionalOffset == 0) + { + UInt32 processed; + + if (!p->fastMode) + { + /* + if (p->alignPriceCount >= 16) // kAlignTableSize + FillAlignPrices(p); + if (p->matchPriceCount >= 128) + FillDistancesPrices(p); + if (p->lenEnc.counter <= 0) + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + */ + if (p->matchPriceCount >= 64) + { + FillAlignPrices(p); + // { int y; for (y = 0; y < 100; y++) { + FillDistancesPrices(p); + // }} + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + } + if (p->repLenEncCounter <= 0) + { + p->repLenEncCounter = REP_LEN_COUNT; + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices); + } + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + + if (maxPackSize) + { + if (processed + kNumOpts + 300 >= maxUnpackSize + || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize) + break; + } + else if (processed >= (1 << 17)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + + + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + UInt32 beforeSize = kNumOpts; + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + + #ifndef _7ZIP_ST + p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); + #endif + + { + unsigned lclp = p->lc + p->lp; + if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + if (!p->litProbs || !p->saveState.litProbs) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); + + if (beforeSize + p->dictSize < keepWindowSize) + beforeSize = keepWindowSize - p->dictSize; + + #ifndef _7ZIP_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, + LZMA_MATCH_LEN_MAX + + 1 /* 18.04 */ + , allocBig)); + p->matchFinderObj = &p->matchFinderMt; + p->matchFinderBase.bigHash = (Byte)( + (p->dictSize > kBigHashDicLimit && p->matchFinderBase.hashMask >= 0xFFFFFF) ? 1 : 0); + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &p->matchFinderBase; + MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + } + + return SZ_OK; +} + +void LzmaEnc_Init(CLzmaEnc *p) +{ + unsigned i; + p->state = 0; + p->reps[0] = + p->reps[1] = + p->reps[2] = + p->reps[3] = 1; + + RangeEnc_Init(&p->rc); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + for (i = 0; i < kNumStates; i++) + { + unsigned j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + unsigned j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances; i++) + p->posEncoders[i] = kProbInitValue; + } + + { + UInt32 num = (UInt32)0x300 << (p->lp + p->lc); + UInt32 k; + CLzmaProb *probs = p->litProbs; + for (k = 0; k < num; k++) + probs[k] = kProbInitValue; + } + + + LenEnc_Init(&p->lenProbs); + LenEnc_Init(&p->repLenProbs); + + p->optEnd = 0; + p->optCur = 0; + + { + for (i = 0; i < kNumOpts; i++) + p->opt[i].price = kInfinityPrice; + } + + p->additionalOffset = 0; + + p->pbMask = (1 << p->pb) - 1; + p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc); +} + + +void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + + p->repLenEncCounter = REP_LEN_COUNT; + + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + unsigned i; + for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + p->nowPos64 = 0; + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, + ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->matchFinderBase.directInput = 1; + p->matchFinderBase.bufferBase = (Byte *)src; + p->matchFinderBase.directInputRem = srcLen; +} + +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + LzmaEnc_SetInputBuf(p, src, srcLen); + p->needInit = 1; + + LzmaEnc_SetDataSize(pp, srcLen); + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + UNUSED_VAR(pp); + #endif +} + + +typedef struct +{ + ISeqOutStream vt; + Byte *data; + SizeT rem; + BoolInt overflow; +} CLzmaEnc_SeqOutStreamBuf; + +static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size) +{ + CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt); + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + return size; +} + + +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +} + + +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +} + + +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + UInt64 nowPos64; + SRes res; + CLzmaEnc_SeqOutStreamBuf outStream; + + outStream.vt.Write = SeqOutStreamBuf_Write; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + + nowPos64 = p->nowPos64; + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.vt; + + if (desiredPackSize == 0) + return SZ_ERROR_OUTPUT_EOF; + + res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +} + + +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +{ + SRes res = SZ_OK; + + #ifndef _7ZIP_ST + Byte allocaDummy[0x300]; + allocaDummy[0] = 0; + allocaDummy[1] = allocaDummy[0]; + #endif + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, 0, 0); + if (res != SZ_OK || p->finished) + break; + if (progress) + { + res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + + LzmaEnc_Finish(p); + + /* + if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase)) + res = SZ_ERROR_FAIL; + } + */ + + return res; +} + + +SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); + return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +} + + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + unsigned i; + UInt32 dictSize = p->dictSize; + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + if (dictSize >= ((UInt32)1 << 22)) + { + UInt32 kDictMask = ((UInt32)1 << 20) - 1; + if (dictSize < (UInt32)0xFFFFFFFF - kDictMask) + dictSize = (dictSize + kDictMask) & ~kDictMask; + } + else for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } + if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } + } + + for (i = 0; i < 4; i++) + props[1 + i] = (Byte)(dictSize >> (8 * i)); + return SZ_OK; +} + + +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp) +{ + return ((CLzmaEnc *)pp)->writeEndMark; +} + + +SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + SRes res; + CLzmaEnc *p = (CLzmaEnc *)pp; + + CLzmaEnc_SeqOutStreamBuf outStream; + + outStream.vt.Write = SeqOutStreamBuf_Write; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + p->rc.outStream = &outStream.vt; + + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + + if (res == SZ_OK) + { + res = LzmaEnc_Encode2(p, progress); + if (res == SZ_OK && p->nowPos64 != srcLen) + res = SZ_ERROR_FAIL; + } + + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + SRes res; + if (!p) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} diff --git a/utils/lzma/C/LzmaEnc.h b/utils/lzma/C/LzmaEnc.h new file mode 100644 index 0000000..9194ee5 --- /dev/null +++ b/utils/lzma/C/LzmaEnc.h @@ -0,0 +1,76 @@ +/* LzmaEnc.h -- LZMA Encoder +2017-07-27 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_ENC_H +#define __LZMA_ENC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaEncProps +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (3 << 29) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ + + UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. + Encoder uses this value to reduce dictionary size */ +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef void * CLzmaEncHandle; + +CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); + +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); + +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, + ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + + +/* ---------- One Call Interface ---------- */ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/LzmaLib.c b/utils/lzma/C/LzmaLib.c new file mode 100644 index 0000000..706e9e5 --- /dev/null +++ b/utils/lzma/C/LzmaLib.c @@ -0,0 +1,40 @@ +/* LzmaLib.c -- LZMA library wrapper +2015-06-13 : Igor Pavlov : Public domain */ + +#include "Alloc.h" +#include "LzmaDec.h" +#include "LzmaEnc.h" +#include "LzmaLib.h" + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ +) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + props.lc = lc; + props.lp = lp; + props.pb = pb; + props.fb = fb; + props.numThreads = numThreads; + + return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); +} + + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, + const unsigned char *props, size_t propsSize) +{ + ELzmaStatus status; + return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); +} diff --git a/utils/lzma/C/LzmaLib.h b/utils/lzma/C/LzmaLib.h new file mode 100644 index 0000000..88fa87d --- /dev/null +++ b/utils/lzma/C/LzmaLib.h @@ -0,0 +1,131 @@ +/* LzmaLib.h -- LZMA library interface +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_LIB_H +#define __LZMA_LIB_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define MY_STDAPI int MY_STD_CALL + +#define LZMA_PROPS_SIZE 5 + +/* +RAM requirements for LZMA: + for compression: (dictSize * 11.5 + 6 MB) + state_size + for decompression: dictSize + state_size + state_size = (4 + (1.5 << (lc + lp))) KB + by default (lc=3, lp=0), state_size = 16 KB. + +LZMA properties (5 bytes) format + Offset Size Description + 0 1 lc, lp and pb in encoded form. + 1 4 dictSize (little endian). +*/ + +/* +LzmaCompress +------------ + +outPropsSize - + In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + + LZMA Encoder will use defult values for any parameter, if it is + -1 for any from: level, loc, lp, pb, fb, numThreads + 0 for dictSize + +level - compression level: 0 <= level <= 9; + + level dictSize algo fb + 0: 16 KB 0 32 + 1: 64 KB 0 32 + 2: 256 KB 0 32 + 3: 1 MB 0 32 + 4: 4 MB 0 32 + 5: 16 MB 1 32 + 6: 32 MB 1 32 + 7+: 64 MB 1 64 + + The default value for "level" is 5. + + algo = 0 means fast method + algo = 1 means normal method + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + +lc - The number of literal context bits (high bits of previous literal). + It can be in the range from 0 to 8. The default value is 3. + Sometimes lc=4 gives the gain for big files. + +lp - The number of literal pos bits (low bits of current position for literals). + It can be in the range from 0 to 4. The default value is 0. + The lp switch is intended for periodical data when the period is equal to 2^lp. + For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's + better to set lc=0, if you change lp switch. + +pb - The number of pos bits (low bits of current position). + It can be in the range from 0 to 4. The default value is 2. + The pb switch is intended for periodical data when the period is equal 2^pb. + +fb - Word size (the number of fast bytes). + It can be in the range from 5 to 273. The default value is 32. + Usually, a big number gives a little bit better compression ratio and + slower compression process. + +numThreads - The number of thereads. 1 or 2. The default value is 2. + Fast mode (algo = 0) can use only 1 thread. + +Out: + destLen - processed output size +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* default = (1 << 24) */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ + ); + +/* +LzmaUncompress +-------------- +In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size +Out: + destLen - processed output size + srcLen - processed input size +Returns: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation arror + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) +*/ + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, + const unsigned char *props, size_t propsSize); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/MtCoder.c b/utils/lzma/C/MtCoder.c new file mode 100644 index 0000000..9535985 --- /dev/null +++ b/utils/lzma/C/MtCoder.c @@ -0,0 +1,601 @@ +/* MtCoder.c -- Multi-thread Coder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "MtCoder.h" + +#ifndef _7ZIP_ST + +SRes MtProgressThunk_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) +{ + CMtProgressThunk *thunk = CONTAINER_FROM_VTBL(pp, CMtProgressThunk, vt); + UInt64 inSize2 = 0; + UInt64 outSize2 = 0; + if (inSize != (UInt64)(Int64)-1) + { + inSize2 = inSize - thunk->inSize; + thunk->inSize = inSize; + } + if (outSize != (UInt64)(Int64)-1) + { + outSize2 = outSize - thunk->outSize; + thunk->outSize = outSize; + } + return MtProgress_ProgressAdd(thunk->mtProgress, inSize2, outSize2); +} + + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p) +{ + p->vt.Progress = MtProgressThunk_Progress; +} + + + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + + +static WRes ArEvent_OptCreate_And_Reset(CEvent *p) +{ + if (Event_IsCreated(p)) + return Event_Reset(p); + return AutoResetEvent_CreateNotSignaled(p); +} + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp); + + +static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) +{ + WRes wres = ArEvent_OptCreate_And_Reset(&t->startEvent); + if (wres == 0) + { + t->stop = False; + if (!Thread_WasCreated(&t->thread)) + wres = Thread_Create(&t->thread, ThreadFunc, t); + if (wres == 0) + wres = Event_Set(&t->startEvent); + } + if (wres == 0) + return SZ_OK; + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +static void MtCoderThread_Destruct(CMtCoderThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + t->stop = 1; + Event_Set(&t->startEvent); + Thread_Wait(&t->thread); + Thread_Close(&t->thread); + } + + Event_Close(&t->startEvent); + + if (t->inBuf) + { + ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf); + t->inBuf = NULL; + } +} + + + +static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t cur = size; + SRes res = ISeqInStream_Read(stream, data, &cur); + *processedSize += cur; + data += cur; + size -= cur; + RINOK(res); + if (cur == 0) + return SZ_OK; + } + return SZ_OK; +} + + +/* + ThreadFunc2() returns: + SZ_OK - in all normal cases (even for stream error or memory allocation error) + SZ_ERROR_THREAD - in case of failure in system synch function +*/ + +static SRes ThreadFunc2(CMtCoderThread *t) +{ + CMtCoder *mtc = t->mtCoder; + + for (;;) + { + unsigned bi; + SRes res; + SRes res2; + BoolInt finished; + unsigned bufIndex; + size_t size; + const Byte *inData; + UInt64 readProcessed = 0; + + RINOK_THREAD(Event_Wait(&mtc->readEvent)) + + /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */ + + if (mtc->stopReading) + { + return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD; + } + + res = MtProgress_GetError(&mtc->mtProgress); + + size = 0; + inData = NULL; + finished = True; + + if (res == SZ_OK) + { + size = mtc->blockSize; + if (mtc->inStream) + { + if (!t->inBuf) + { + t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize); + if (!t->inBuf) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = FullRead(mtc->inStream, t->inBuf, &size); + readProcessed = mtc->readProcessed + size; + mtc->readProcessed = readProcessed; + } + if (res != SZ_OK) + { + mtc->readRes = res; + /* after reading error - we can stop encoding of previous blocks */ + MtProgress_SetError(&mtc->mtProgress, res); + } + else + finished = (size != mtc->blockSize); + } + else + { + size_t rem; + readProcessed = mtc->readProcessed; + rem = mtc->inDataSize - (size_t)readProcessed; + if (size > rem) + size = rem; + inData = mtc->inData + (size_t)readProcessed; + readProcessed += size; + mtc->readProcessed = readProcessed; + finished = (mtc->inDataSize == (size_t)readProcessed); + } + } + + /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */ + + res2 = SZ_OK; + + if (Semaphore_Wait(&mtc->blocksSemaphore) != 0) + { + res2 = SZ_ERROR_THREAD; + if (res == SZ_OK) + { + res = res2; + // MtProgress_SetError(&mtc->mtProgress, res); + } + } + + bi = mtc->blockIndex; + + if (++mtc->blockIndex >= mtc->numBlocksMax) + mtc->blockIndex = 0; + + bufIndex = (unsigned)(int)-1; + + if (res == SZ_OK) + res = MtProgress_GetError(&mtc->mtProgress); + + if (res != SZ_OK) + finished = True; + + if (!finished) + { + if (mtc->numStartedThreads < mtc->numStartedThreadsLimit + && mtc->expectedDataSize != readProcessed) + { + res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); + if (res == SZ_OK) + mtc->numStartedThreads++; + else + { + MtProgress_SetError(&mtc->mtProgress, res); + finished = True; + } + } + } + + if (finished) + mtc->stopReading = True; + + RINOK_THREAD(Event_Set(&mtc->readEvent)) + + if (res2 != SZ_OK) + return res2; + + if (res == SZ_OK) + { + CriticalSection_Enter(&mtc->cs); + bufIndex = mtc->freeBlockHead; + mtc->freeBlockHead = mtc->freeBlockList[bufIndex]; + CriticalSection_Leave(&mtc->cs); + + res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex, + mtc->inStream ? t->inBuf : inData, size, finished); + + // MtProgress_Reinit(&mtc->mtProgress, t->index); + + if (res != SZ_OK) + MtProgress_SetError(&mtc->mtProgress, res); + } + + { + CMtCoderBlock *block = &mtc->blocks[bi]; + block->res = res; + block->bufIndex = bufIndex; + block->finished = finished; + } + + #ifdef MTCODER__USE_WRITE_THREAD + RINOK_THREAD(Event_Set(&mtc->writeEvents[bi])) + #else + { + unsigned wi; + { + CriticalSection_Enter(&mtc->cs); + wi = mtc->writeIndex; + if (wi == bi) + mtc->writeIndex = (unsigned)(int)-1; + else + mtc->ReadyBlocks[bi] = True; + CriticalSection_Leave(&mtc->cs); + } + + if (wi != bi) + { + if (res != SZ_OK || finished) + return 0; + continue; + } + + if (mtc->writeRes != SZ_OK) + res = mtc->writeRes; + + for (;;) + { + if (res == SZ_OK && bufIndex != (unsigned)(int)-1) + { + res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex); + if (res != SZ_OK) + { + mtc->writeRes = res; + MtProgress_SetError(&mtc->mtProgress, res); + } + } + + if (++wi >= mtc->numBlocksMax) + wi = 0; + { + BoolInt isReady; + + CriticalSection_Enter(&mtc->cs); + + if (bufIndex != (unsigned)(int)-1) + { + mtc->freeBlockList[bufIndex] = mtc->freeBlockHead; + mtc->freeBlockHead = bufIndex; + } + + isReady = mtc->ReadyBlocks[wi]; + + if (isReady) + mtc->ReadyBlocks[wi] = False; + else + mtc->writeIndex = wi; + + CriticalSection_Leave(&mtc->cs); + + RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore)) + + if (!isReady) + break; + } + + { + CMtCoderBlock *block = &mtc->blocks[wi]; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + bufIndex = block->bufIndex; + finished = block->finished; + } + } + } + #endif + + if (finished || res != SZ_OK) + return 0; + } +} + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +{ + CMtCoderThread *t = (CMtCoderThread *)pp; + for (;;) + { + if (Event_Wait(&t->startEvent) != 0) + return SZ_ERROR_THREAD; + if (t->stop) + return 0; + { + SRes res = ThreadFunc2(t); + CMtCoder *mtc = t->mtCoder; + if (res != SZ_OK) + { + MtProgress_SetError(&mtc->mtProgress, res); + } + + #ifndef MTCODER__USE_WRITE_THREAD + { + unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); + if (numFinished == mtc->numStartedThreads) + if (Event_Set(&mtc->finishedEvent) != 0) + return SZ_ERROR_THREAD; + } + #endif + } + } +} + + + +void MtCoder_Construct(CMtCoder *p) +{ + unsigned i; + + p->blockSize = 0; + p->numThreadsMax = 0; + p->expectedDataSize = (UInt64)(Int64)-1; + + p->inStream = NULL; + p->inData = NULL; + p->inDataSize = 0; + + p->progress = NULL; + p->allocBig = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + Event_Construct(&p->readEvent); + Semaphore_Construct(&p->blocksSemaphore); + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + t->mtCoder = p; + t->index = i; + t->inBuf = NULL; + t->stop = False; + Event_Construct(&t->startEvent); + Thread_Construct(&t->thread); + } + + #ifdef MTCODER__USE_WRITE_THREAD + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + Event_Construct(&p->writeEvents[i]); + #else + Event_Construct(&p->finishedEvent); + #endif + + CriticalSection_Init(&p->cs); + CriticalSection_Init(&p->mtProgress.cs); +} + + + + +static void MtCoder_Free(CMtCoder *p) +{ + unsigned i; + + /* + p->stopReading = True; + if (Event_IsCreated(&p->readEvent)) + Event_Set(&p->readEvent); + */ + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + MtCoderThread_Destruct(&p->threads[i]); + + Event_Close(&p->readEvent); + Semaphore_Close(&p->blocksSemaphore); + + #ifdef MTCODER__USE_WRITE_THREAD + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + Event_Close(&p->writeEvents[i]); + #else + Event_Close(&p->finishedEvent); + #endif +} + + +void MtCoder_Destruct(CMtCoder *p) +{ + MtCoder_Free(p); + + CriticalSection_Delete(&p->cs); + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtCoder_Code(CMtCoder *p) +{ + unsigned numThreads = p->numThreadsMax; + unsigned numBlocksMax; + unsigned i; + SRes res = SZ_OK; + + if (numThreads > MTCODER__THREADS_MAX) + numThreads = MTCODER__THREADS_MAX; + numBlocksMax = MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads); + + if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++; + + if (numBlocksMax > MTCODER__BLOCKS_MAX) + numBlocksMax = MTCODER__BLOCKS_MAX; + + if (p->blockSize != p->allocatedBufsSize) + { + for (i = 0; i < MTCODER__THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + if (t->inBuf) + { + ISzAlloc_Free(p->allocBig, t->inBuf); + t->inBuf = NULL; + } + } + p->allocatedBufsSize = p->blockSize; + } + + p->readRes = SZ_OK; + + MtProgress_Init(&p->mtProgress, p->progress); + + #ifdef MTCODER__USE_WRITE_THREAD + for (i = 0; i < numBlocksMax; i++) + { + RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->writeEvents[i])); + } + #else + RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent)); + #endif + + { + RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->readEvent)); + + if (Semaphore_IsCreated(&p->blocksSemaphore)) + { + RINOK_THREAD(Semaphore_Close(&p->blocksSemaphore)); + } + RINOK_THREAD(Semaphore_Create(&p->blocksSemaphore, numBlocksMax, numBlocksMax)); + } + + for (i = 0; i < MTCODER__BLOCKS_MAX - 1; i++) + p->freeBlockList[i] = i + 1; + p->freeBlockList[MTCODER__BLOCKS_MAX - 1] = (unsigned)(int)-1; + p->freeBlockHead = 0; + + p->readProcessed = 0; + p->blockIndex = 0; + p->numBlocksMax = numBlocksMax; + p->stopReading = False; + + #ifndef MTCODER__USE_WRITE_THREAD + p->writeIndex = 0; + p->writeRes = SZ_OK; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + p->ReadyBlocks[i] = False; + p->numFinishedThreads = 0; + #endif + + p->numStartedThreadsLimit = numThreads; + p->numStartedThreads = 0; + + // for (i = 0; i < numThreads; i++) + { + CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; + RINOK(MtCoderThread_CreateAndStart(nextThread)); + } + + RINOK_THREAD(Event_Set(&p->readEvent)) + + #ifdef MTCODER__USE_WRITE_THREAD + { + unsigned bi = 0; + + for (;; bi++) + { + if (bi >= numBlocksMax) + bi = 0; + + RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) + + { + const CMtCoderBlock *block = &p->blocks[bi]; + unsigned bufIndex = block->bufIndex; + BoolInt finished = block->finished; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + + if (bufIndex != (unsigned)(int)-1) + { + if (res == SZ_OK) + { + res = p->mtCallback->Write(p->mtCallbackObject, bufIndex); + if (res != SZ_OK) + MtProgress_SetError(&p->mtProgress, res); + } + + CriticalSection_Enter(&p->cs); + { + p->freeBlockList[bufIndex] = p->freeBlockHead; + p->freeBlockHead = bufIndex; + } + CriticalSection_Leave(&p->cs); + } + + RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore)) + + if (finished) + break; + } + } + } + #else + { + WRes wres = Event_Wait(&p->finishedEvent); + res = MY_SRes_HRESULT_FROM_WRes(wres); + } + #endif + + if (res == SZ_OK) + res = p->readRes; + + if (res == SZ_OK) + res = p->mtProgress.res; + + #ifndef MTCODER__USE_WRITE_THREAD + if (res == SZ_OK) + res = p->writeRes; + #endif + + if (res != SZ_OK) + MtCoder_Free(p); + return res; +} + +#endif diff --git a/utils/lzma/C/MtCoder.h b/utils/lzma/C/MtCoder.h new file mode 100644 index 0000000..5a5f4d1 --- /dev/null +++ b/utils/lzma/C/MtCoder.h @@ -0,0 +1,141 @@ +/* MtCoder.h -- Multi-thread Coder +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __MT_CODER_H +#define __MT_CODER_H + +#include "MtDec.h" + +EXTERN_C_BEGIN + +/* + if ( defined MTCODER__USE_WRITE_THREAD) : main thread writes all data blocks to output stream + if (not defined MTCODER__USE_WRITE_THREAD) : any coder thread can write data blocks to output stream +*/ +/* #define MTCODER__USE_WRITE_THREAD */ + +#ifndef _7ZIP_ST + #define MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) + #define MTCODER__THREADS_MAX 64 + #define MTCODER__BLOCKS_MAX (MTCODER__GET_NUM_BLOCKS_FROM_THREADS(MTCODER__THREADS_MAX) + 3) +#else + #define MTCODER__THREADS_MAX 1 + #define MTCODER__BLOCKS_MAX 1 +#endif + + +#ifndef _7ZIP_ST + + +typedef struct +{ + ICompressProgress vt; + CMtProgress *mtProgress; + UInt64 inSize; + UInt64 outSize; +} CMtProgressThunk; + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p); + +#define MtProgressThunk_Init(p) { (p)->inSize = 0; (p)->outSize = 0; } + + +struct _CMtCoder; + + +typedef struct +{ + struct _CMtCoder *mtCoder; + unsigned index; + int stop; + Byte *inBuf; + + CAutoResetEvent startEvent; + CThread thread; +} CMtCoderThread; + + +typedef struct +{ + SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished); + SRes (*Write)(void *p, unsigned outBufIndex); +} IMtCoderCallback2; + + +typedef struct +{ + SRes res; + unsigned bufIndex; + BoolInt finished; +} CMtCoderBlock; + + +typedef struct _CMtCoder +{ + /* input variables */ + + size_t blockSize; /* size of input block */ + unsigned numThreadsMax; + UInt64 expectedDataSize; + + ISeqInStream *inStream; + const Byte *inData; + size_t inDataSize; + + ICompressProgress *progress; + ISzAllocPtr allocBig; + + IMtCoderCallback2 *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + CAutoResetEvent readEvent; + CSemaphore blocksSemaphore; + + BoolInt stopReading; + SRes readRes; + + #ifdef MTCODER__USE_WRITE_THREAD + CAutoResetEvent writeEvents[MTCODER__BLOCKS_MAX]; + #else + CAutoResetEvent finishedEvent; + SRes writeRes; + unsigned writeIndex; + Byte ReadyBlocks[MTCODER__BLOCKS_MAX]; + LONG numFinishedThreads; + #endif + + unsigned numStartedThreadsLimit; + unsigned numStartedThreads; + + unsigned numBlocksMax; + unsigned blockIndex; + UInt64 readProcessed; + + CCriticalSection cs; + + unsigned freeBlockHead; + unsigned freeBlockList[MTCODER__BLOCKS_MAX]; + + CMtProgress mtProgress; + CMtCoderBlock blocks[MTCODER__BLOCKS_MAX]; + CMtCoderThread threads[MTCODER__THREADS_MAX]; +} CMtCoder; + + +void MtCoder_Construct(CMtCoder *p); +void MtCoder_Destruct(CMtCoder *p); +SRes MtCoder_Code(CMtCoder *p); + + +#endif + + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/MtDec.c b/utils/lzma/C/MtDec.c new file mode 100644 index 0000000..7803bf2 --- /dev/null +++ b/utils/lzma/C/MtDec.c @@ -0,0 +1,1138 @@ +/* MtDec.c -- Multi-thread Decoder +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +// #include + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +#include "MtDec.h" + +#ifndef _7ZIP_ST + +void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) +{ + p->progress = progress; + p->res = SZ_OK; + p->totalInSize = 0; + p->totalOutSize = 0; +} + + +SRes MtProgress_Progress_ST(CMtProgress *p) +{ + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + return p->res; +} + + +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize) +{ + SRes res; + CriticalSection_Enter(&p->cs); + + p->totalInSize += inSize; + p->totalOutSize += outSize; + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + res = p->res; + + CriticalSection_Leave(&p->cs); + return res; +} + + +SRes MtProgress_GetError(CMtProgress *p) +{ + SRes res; + CriticalSection_Enter(&p->cs); + res = p->res; + CriticalSection_Leave(&p->cs); + return res; +} + + +void MtProgress_SetError(CMtProgress *p, SRes res) +{ + CriticalSection_Enter(&p->cs); + if (p->res == SZ_OK) + p->res = res; + CriticalSection_Leave(&p->cs); +} + + +#define RINOK_THREAD(x) RINOK(x) + + +static WRes ArEvent_OptCreate_And_Reset(CEvent *p) +{ + if (Event_IsCreated(p)) + return Event_Reset(p); + return AutoResetEvent_CreateNotSignaled(p); +} + + +struct __CMtDecBufLink +{ + struct __CMtDecBufLink *next; + void *pad[3]; +}; + +typedef struct __CMtDecBufLink CMtDecBufLink; + +#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink) +#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET) + + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp); + + +static WRes MtDecThread_CreateEvents(CMtDecThread *t) +{ + WRes wres = ArEvent_OptCreate_And_Reset(&t->canWrite); + if (wres == 0) + { + wres = ArEvent_OptCreate_And_Reset(&t->canRead); + if (wres == 0) + return SZ_OK; + } + return wres; +} + + +static SRes MtDecThread_CreateAndStart(CMtDecThread *t) +{ + WRes wres = MtDecThread_CreateEvents(t); + // wres = 17; // for test + if (wres == 0) + { + if (Thread_WasCreated(&t->thread)) + return SZ_OK; + wres = Thread_Create(&t->thread, ThreadFunc, t); + if (wres == 0) + return SZ_OK; + } + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +void MtDecThread_FreeInBufs(CMtDecThread *t) +{ + if (t->inBuf) + { + void *link = t->inBuf; + t->inBuf = NULL; + do + { + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(t->mtDec->alloc, link); + link = next; + } + while (link); + } +} + + +static void MtDecThread_CloseThread(CMtDecThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */ + Event_Set(&t->canRead); + Thread_Wait(&t->thread); + Thread_Close(&t->thread); + } + + Event_Close(&t->canRead); + Event_Close(&t->canWrite); +} + +static void MtDec_CloseThreads(CMtDec *p) +{ + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + MtDecThread_CloseThread(&p->threads[i]); +} + +static void MtDecThread_Destruct(CMtDecThread *t) +{ + MtDecThread_CloseThread(t); + MtDecThread_FreeInBufs(t); +} + + + +static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t cur = size; + SRes res = ISeqInStream_Read(stream, data, &cur); + *processedSize += cur; + data += cur; + size -= cur; + RINOK(res); + if (cur == 0) + return SZ_OK; + } + return SZ_OK; +} + + +static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + CriticalSection_Leave(&p->mtProgress.cs); + return res; +} + +static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + + p->mtProgress.totalInSize += inSize; + p->mtProgress.totalOutSize += outSize; + if (p->mtProgress.res == SZ_OK && p->mtProgress.progress) + if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK) + p->mtProgress.res = SZ_ERROR_PROGRESS; + + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + + CriticalSection_Leave(&p->mtProgress.cs); + + return res; +} + +static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex) +{ + CriticalSection_Enter(&p->mtProgress.cs); + if (!p->needInterrupt || interruptIndex < p->interruptIndex) + { + p->interruptIndex = interruptIndex; + p->needInterrupt = True; + } + CriticalSection_Leave(&p->mtProgress.cs); +} + +Byte *MtDec_GetCrossBuff(CMtDec *p) +{ + Byte *cr = p->crossBlock; + if (!cr) + { + cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!cr) + return NULL; + p->crossBlock = cr; + } + return MTDEC__DATA_PTR_FROM_LINK(cr); +} + + +/* + ThreadFunc2() returns: + 0 - in all normal cases (even for stream error or memory allocation error) + (!= 0) - WRes error return by system threading function +*/ + +// #define MTDEC_ProgessStep (1 << 22) +#define MTDEC_ProgessStep (1 << 0) + +static WRes ThreadFunc2(CMtDecThread *t) +{ + CMtDec *p = t->mtDec; + + PRF_STR_INT("ThreadFunc2", t->index); + + // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index); + + for (;;) + { + SRes res, codeRes; + BoolInt wasInterrupted, isAllocError, overflow, finish; + SRes threadingErrorSRes; + BoolInt needCode, needWrite, needContinue; + + size_t inDataSize_Start; + UInt64 inDataSize; + // UInt64 inDataSize_Full; + + UInt64 blockIndex; + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + UInt64 inCodePos; + UInt64 outCodePos; + + Byte *afterEndData = NULL; + size_t afterEndData_Size = 0; + + BoolInt canCreateNewThread = False; + // CMtDecCallbackInfo parse; + CMtDecThread *nextThread; + + PRF_STR_INT("Event_Wait(&t->canRead)", t->index); + + RINOK_THREAD(Event_Wait(&t->canRead)); + if (p->exitThread) + return 0; + + PRF_STR_INT("after Event_Wait(&t->canRead)", t->index); + + // if (t->index == 3) return 19; // for test + + blockIndex = p->blockIndex++; + + // PRF(printf("\ncanRead\n")) + + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + + finish = p->readWasFinished; + needCode = False; + needWrite = False; + isAllocError = False; + overflow = False; + + inDataSize_Start = 0; + inDataSize = 0; + // inDataSize_Full = 0; + + if (res == SZ_OK && !wasInterrupted) + { + // if (p->inStream) + { + CMtDecBufLink *prev = NULL; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + size_t crossSize = p->crossEnd - p->crossStart; + + PRF(printf("\ncrossSize = %d\n", crossSize)); + + for (;;) + { + if (!link) + { + link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!link) + { + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + link->next = NULL; + if (prev) + { + // static unsigned g_num = 0; + // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev)); + prev->next = link; + } + else + t->inBuf = (void *)link; + } + + { + Byte *data = MTDEC__DATA_PTR_FROM_LINK(link); + Byte *parseData = data; + size_t size; + + if (crossSize != 0) + { + inDataSize = crossSize; + // inDataSize_Full = inDataSize; + inDataSize_Start = crossSize; + size = crossSize; + parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d", + (int)p->crossStart, (int)p->crossEnd, (int)finish)); + } + else + { + size = p->inBufSize; + + res = FullRead(p->inStream, data, &size); + + // size = 10; // test + + inDataSize += size; + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = size; + + p->readProcessed += size; + finish = (size != p->inBufSize); + if (finish) + p->readWasFinished = True; + + // res = E_INVALIDARG; // test + + if (res != SZ_OK) + { + // PRF(printf("\nRead error = %d\n", res)) + // we want to decode all data before error + p->readRes = res; + // p->readError_BlockIndex = blockIndex; + p->readWasFinished = True; + finish = True; + res = SZ_OK; + // break; + } + + if (inDataSize - inPrev >= MTDEC_ProgessStep) + { + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inDataSize; + } + } + + { + CMtDecCallbackInfo parse; + + parse.startCall = (prev == NULL); + parse.src = parseData; + parse.srcSize = size; + parse.srcFinished = finish; + parse.canCreateNewThread = True; + + // PRF(printf("\nParse size = %d\n", (unsigned)size)) + + p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse); + + needWrite = True; + canCreateNewThread = parse.canCreateNewThread; + + // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize); + + if ( + // parseRes != SZ_OK || + // inDataSize - (size - parse.srcSize) > p->inBlockMax + // || + parse.state == MTDEC_PARSE_OVERFLOW + // || wasInterrupted + ) + { + // Overflow or Parse error - switch from MT decoding to ST decoding + finish = True; + overflow = True; + + { + PRF(printf("\n Overflow")); + // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished)); + PRF(printf("\n inDataSize = %d", (unsigned)inDataSize)); + } + + if (crossSize != 0) + memcpy(data, parseData, size); + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (crossSize != 0) + { + memcpy(data, parseData, parse.srcSize); + p->crossStart += parse.srcSize; + } + + if (parse.state != MTDEC_PARSE_CONTINUE || finish) + { + // we don't need to parse in current thread anymore + + if (parse.state == MTDEC_PARSE_END) + finish = True; + + needCode = True; + // p->crossFinished = finish; + + if (parse.srcSize == size) + { + // full parsed - no cross transfer + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (parse.state == MTDEC_PARSE_END) + { + p->crossStart = 0; + p->crossEnd = 0; + + if (crossSize != 0) + memcpy(data + parse.srcSize, parseData + parse.srcSize, size - parse.srcSize); // we need all data + afterEndData_Size = size - parse.srcSize; + afterEndData = parseData + parse.srcSize; + + // we reduce data size to required bytes (parsed only) + inDataSize -= (size - parse.srcSize); + if (!prev) + inDataSize_Start = parse.srcSize; + break; + } + + { + // partial parsed - need cross transfer + if (crossSize != 0) + inDataSize = parse.srcSize; // it's only parsed now + else + { + // partial parsed - is not in initial cross block - we need to copy new data to cross block + Byte *cr = MtDec_GetCrossBuff(p); + if (!cr) + { + { + PRF(printf("\ncross alloc error error\n")); + // res = SZ_ERROR_MEM; + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + } + + { + size_t crSize = size - parse.srcSize; + inDataSize -= crSize; + p->crossEnd = crSize; + p->crossStart = 0; + memcpy(cr, parseData + parse.srcSize, crSize); + } + } + + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = parse.srcSize; // it's partial size (parsed only) + + finish = False; + break; + } + } + + if (parse.srcSize != size) + { + res = SZ_ERROR_FAIL; + PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res)); + break; + } + } + } + + prev = link; + link = link->next; + + if (crossSize != 0) + { + crossSize = 0; + p->crossStart = 0; + p->crossEnd = 0; + } + } + } + + if (res == SZ_OK) + res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted); + } + + codeRes = SZ_OK; + + if (res == SZ_OK && needCode && !wasInterrupted) + { + codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index); + if (codeRes != SZ_OK) + { + needCode = False; + finish = True; + // SZ_ERROR_MEM is expected error here. + // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later. + // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding. + } + } + + if (res != SZ_OK || wasInterrupted) + finish = True; + + nextThread = NULL; + threadingErrorSRes = SZ_OK; + + if (!finish) + { + if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread) + { + SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]); + if (res2 == SZ_OK) + { + // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads)); + p->numStartedThreads++; + } + else + { + PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads)); + if (p->numStartedThreads == 1) + { + // if only one thread is possible, we leave muti-threading code + finish = True; + needCode = False; + threadingErrorSRes = res2; + } + else + p->numStartedThreads_Limit = p->numStartedThreads; + } + } + + if (!finish) + { + unsigned nextIndex = t->index + 1; + nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex]; + RINOK_THREAD(Event_Set(&nextThread->canRead)) + // We have started executing for new iteration (with next thread) + // And that next thread now is responsible for possible exit from decoding (threading_code) + } + } + + // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite) + // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case + // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block): + // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration + // - otherwise we stop decoding and exit from ThreadFunc2() + + // Don't change (finish) variable in the further code + + + // ---------- CODE ---------- + + inPrev = 0; + outPrev = 0; + inCodePos = 0; + outCodePos = 0; + + if (res == SZ_OK && needCode && codeRes == SZ_OK) + { + BoolInt isStartBlock = True; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + + for (;;) + { + size_t inSize; + int stop; + + if (isStartBlock) + inSize = inDataSize_Start; + else + { + UInt64 rem = inDataSize - inCodePos; + inSize = p->inBufSize; + if (inSize > rem) + inSize = (size_t)rem; + } + + inCodePos += inSize; + stop = True; + + codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index, + (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize, + (inCodePos == inDataSize), // srcFinished + &inCodePos, &outCodePos, &stop); + + if (codeRes != SZ_OK) + { + PRF(printf("\nCode Interrupt error = %x\n", codeRes)); + // we interrupt only later blocks + MtDec_Interrupt(p, blockIndex); + break; + } + + if (stop || inCodePos == inDataSize) + break; + + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep) + { + // Sleep(1); + res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inCodePos; + outPrev = outCodePos; + } + } + + link = link->next; + isStartBlock = False; + } + } + + + // ---------- WRITE ---------- + + RINOK_THREAD(Event_Wait(&t->canWrite)); + + { + BoolInt isErrorMode = False; + BoolInt canRecode = True; + BoolInt needWriteToStream = needWrite; + + if (p->exitThread) return 0; // it's never executed in normal cases + + if (p->wasInterrupted) + wasInterrupted = True; + else + { + if (codeRes != SZ_OK) // || !needCode // check it !!! + { + p->wasInterrupted = True; + p->codeRes = codeRes; + if (codeRes == SZ_ERROR_MEM) + isAllocError = True; + } + + if (threadingErrorSRes) + { + p->wasInterrupted = True; + p->threadingErrorSRes = threadingErrorSRes; + needWriteToStream = False; + } + if (isAllocError) + { + p->wasInterrupted = True; + p->isAllocError = True; + needWriteToStream = False; + } + if (overflow) + { + p->wasInterrupted = True; + p->overflow = True; + needWriteToStream = False; + } + } + + if (needCode) + { + if (wasInterrupted) + { + inCodePos = 0; + outCodePos = 0; + } + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + // if (inDelta != 0 || outDelta != 0) + res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta); + } + } + + needContinue = (!finish); + + // if (res == SZ_OK && needWrite && !wasInterrupted) + if (needWrite) + { + // p->inProcessed += inCodePos; + + res = p->mtCallback->Write(p->mtCallbackObject, t->index, + res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite + afterEndData, afterEndData_Size, + &needContinue, + &canRecode); + + // res= E_INVALIDARG; // for test + + PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue)); + PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed)); + + if (res != SZ_OK) + { + PRF(printf("\nWrite error = %d\n", res)); + isErrorMode = True; + p->wasInterrupted = True; + } + if (res != SZ_OK + || (!needContinue && !finish)) + { + PRF(printf("\nWrite Interrupt error = %x\n", res)); + MtDec_Interrupt(p, blockIndex); + } + } + + if (canRecode) + if (!needCode + || res != SZ_OK + || p->wasInterrupted + || codeRes != SZ_OK + || wasInterrupted + || p->numFilledThreads != 0 + || isErrorMode) + { + if (p->numFilledThreads == 0) + p->filledThreadStart = t->index; + if (inDataSize != 0 || !finish) + { + t->inDataSize_Start = inDataSize_Start; + t->inDataSize = inDataSize; + p->numFilledThreads++; + } + PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads)); + PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart)); + } + + if (!finish) + { + RINOK_THREAD(Event_Set(&nextThread->canWrite)); + } + else + { + if (needContinue) + { + // we restore decoding with new iteration + RINOK_THREAD(Event_Set(&p->threads[0].canWrite)); + } + else + { + // we exit from decoding + if (t->index == 0) + return SZ_OK; + p->exitThread = True; + } + RINOK_THREAD(Event_Set(&p->threads[0].canRead)); + } + } + } +} + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#endif +#endif + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void *pp) +{ + WRes res; + + CMtDecThread *t = (CMtDecThread *)pp; + CMtDec *p; + + // fprintf(stdout, "\n%d = %p\n", t->index, &t); + + res = ThreadFunc2(t); + p = t->mtDec; + if (res == 0) + return p->exitThreadWRes; + { + // it's unexpected situation for some threading function error + if (p->exitThreadWRes == 0) + p->exitThreadWRes = res; + PRF(printf("\nthread exit error = %d\n", res)); + p->exitThread = True; + Event_Set(&p->threads[0].canRead); + Event_Set(&p->threads[0].canWrite); + MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res)); + } + return res; +} + +static MY_NO_INLINE THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +{ + CMtDecThread *t = (CMtDecThread *)pp; + + // fprintf(stderr, "\n%d = %p - before", t->index, &t); + #ifdef USE_ALLOCA + t->allocaPtr = alloca(t->index * 128); + #endif + return ThreadFunc1(pp); +} + + +int MtDec_PrepareRead(CMtDec *p) +{ + if (p->crossBlock && p->crossStart == p->crossEnd) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + if (i > p->numStartedThreads + || p->numFilledThreads <= + (i >= p->filledThreadStart ? + i - p->filledThreadStart : + i + p->numStartedThreads - p->filledThreadStart)) + MtDecThread_FreeInBufs(&p->threads[i]); + } + + return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd); +} + + +const Byte *MtDec_Read(CMtDec *p, size_t *inLim) +{ + while (p->numFilledThreads != 0) + { + CMtDecThread *t = &p->threads[p->filledThreadStart]; + + if (*inLim != 0) + { + { + void *link = t->inBuf; + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(p->alloc, link); + t->inBuf = next; + } + + if (t->inDataSize == 0) + { + MtDecThread_FreeInBufs(t); + if (--p->numFilledThreads == 0) + break; + if (++p->filledThreadStart == p->numStartedThreads) + p->filledThreadStart = 0; + t = &p->threads[p->filledThreadStart]; + } + } + + { + size_t lim = t->inDataSize_Start; + if (lim != 0) + t->inDataSize_Start = 0; + else + { + UInt64 rem = t->inDataSize; + lim = p->inBufSize; + if (lim > rem) + lim = (size_t)rem; + } + t->inDataSize -= lim; + *inLim = lim; + return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf); + } + } + + { + size_t crossSize = p->crossEnd - p->crossStart; + if (crossSize != 0) + { + const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + *inLim = crossSize; + p->crossStart = 0; + p->crossEnd = 0; + return data; + } + *inLim = 0; + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + return NULL; + } +} + + +void MtDec_Construct(CMtDec *p) +{ + unsigned i; + + p->inBufSize = (size_t)1 << 18; + + p->numThreadsMax = 0; + + p->inStream = NULL; + + // p->inData = NULL; + // p->inDataSize = 0; + + p->crossBlock = NULL; + p->crossStart = 0; + p->crossEnd = 0; + + p->numFilledThreads = 0; + + p->progress = NULL; + p->alloc = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + t->mtDec = p; + t->index = i; + t->inBuf = NULL; + Event_Construct(&t->canRead); + Event_Construct(&t->canWrite); + Thread_Construct(&t->thread); + } + + // Event_Construct(&p->finishedEvent); + + CriticalSection_Init(&p->mtProgress.cs); +} + + +static void MtDec_Free(CMtDec *p) +{ + unsigned i; + + p->exitThread = True; + + for (i = 0; i < MTDEC__THREADS_MAX; i++) + MtDecThread_Destruct(&p->threads[i]); + + // Event_Close(&p->finishedEvent); + + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } +} + + +void MtDec_Destruct(CMtDec *p) +{ + MtDec_Free(p); + + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtDec_Code(CMtDec *p) +{ + unsigned i; + + p->inProcessed = 0; + + p->blockIndex = 1; // it must be larger than not_defined index (0) + p->isAllocError = False; + p->overflow = False; + p->threadingErrorSRes = SZ_OK; + + p->needContinue = True; + + p->readWasFinished = False; + p->needInterrupt = False; + p->interruptIndex = (UInt64)(Int64)-1; + + p->readProcessed = 0; + p->readRes = SZ_OK; + p->codeRes = SZ_OK; + p->wasInterrupted = False; + + p->crossStart = 0; + p->crossEnd = 0; + + p->filledThreadStart = 0; + p->numFilledThreads = 0; + + { + unsigned numThreads = p->numThreadsMax; + if (numThreads > MTDEC__THREADS_MAX) + numThreads = MTDEC__THREADS_MAX; + p->numStartedThreads_Limit = numThreads; + p->numStartedThreads = 0; + } + + if (p->inBufSize != p->allocatedBufsSize) + { + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + if (t->inBuf) + MtDecThread_FreeInBufs(t); + } + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + p->allocatedBufsSize = p->inBufSize; + } + + MtProgress_Init(&p->mtProgress, p->progress); + + // RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent)); + p->exitThread = False; + p->exitThreadWRes = 0; + + { + WRes wres; + WRes sres; + CMtDecThread *nextThread = &p->threads[p->numStartedThreads++]; + // wres = MtDecThread_CreateAndStart(nextThread); + wres = MtDecThread_CreateEvents(nextThread); + if (wres == 0) { wres = Event_Set(&nextThread->canWrite); + if (wres == 0) { wres = Event_Set(&nextThread->canRead); + if (wres == 0) { wres = ThreadFunc(nextThread); + if (wres != 0) + { + p->needContinue = False; + MtDec_CloseThreads(p); + }}}} + + // wres = 17; // for test + // wres = Event_Wait(&p->finishedEvent); + + sres = MY_SRes_HRESULT_FROM_WRes(wres); + + if (sres != 0) + p->threadingErrorSRes = sres; + + if ( + // wres == 0 + // wres != 0 + // || p->mtc.codeRes == SZ_ERROR_MEM + p->isAllocError + || p->threadingErrorSRes != SZ_OK + || p->overflow) + { + // p->needContinue = True; + } + else + p->needContinue = False; + + if (p->needContinue) + return SZ_OK; + + // if (sres != SZ_OK) + return sres; + // return E_FAIL; + } +} + +#endif diff --git a/utils/lzma/C/MtDec.h b/utils/lzma/C/MtDec.h new file mode 100644 index 0000000..9b57766 --- /dev/null +++ b/utils/lzma/C/MtDec.h @@ -0,0 +1,201 @@ +/* MtDec.h -- Multi-thread Decoder +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __MT_DEC_H +#define __MT_DEC_H + +#include "7zTypes.h" + +#ifndef _7ZIP_ST +#include "Threads.h" +#endif + +EXTERN_C_BEGIN + +#ifndef _7ZIP_ST + +#ifndef _7ZIP_ST + #define MTDEC__THREADS_MAX 32 +#else + #define MTDEC__THREADS_MAX 1 +#endif + + +typedef struct +{ + ICompressProgress *progress; + SRes res; + UInt64 totalInSize; + UInt64 totalOutSize; + CCriticalSection cs; +} CMtProgress; + +void MtProgress_Init(CMtProgress *p, ICompressProgress *progress); +SRes MtProgress_Progress_ST(CMtProgress *p); +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize); +SRes MtProgress_GetError(CMtProgress *p); +void MtProgress_SetError(CMtProgress *p, SRes res); + +struct _CMtDec; + +typedef struct +{ + struct _CMtDec *mtDec; + unsigned index; + void *inBuf; + + size_t inDataSize_Start; // size of input data in start block + UInt64 inDataSize; // total size of input data in all blocks + + CThread thread; + CAutoResetEvent canRead; + CAutoResetEvent canWrite; + void *allocaPtr; +} CMtDecThread; + +void MtDecThread_FreeInBufs(CMtDecThread *t); + + +typedef enum +{ + MTDEC_PARSE_CONTINUE, // continue this block with more input data + MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread + MTDEC_PARSE_NEW, // new block + MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue) +} EMtDecParseState; + +typedef struct +{ + // in + int startCall; + const Byte *src; + size_t srcSize; + // in : (srcSize == 0) is allowed + // out : it's allowed to return less that actually was used ? + int srcFinished; + + // out + EMtDecParseState state; + BoolInt canCreateNewThread; + UInt64 outPos; // check it (size_t) +} CMtDecCallbackInfo; + + +typedef struct +{ + void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci); + + // PreCode() and Code(): + // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks + SRes (*PreCode)(void *p, unsigned coderIndex); + SRes (*Code)(void *p, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop); + // stop - means stop another Code calls + + + /* Write() must be called, if Parse() was called + set (needWrite) if + { + && (was not interrupted by progress) + && (was not interrupted in previous block) + } + + out: + if (*needContinue), decoder still need to continue decoding with new iteration, + even after MTDEC_PARSE_END + if (*canRecode), we didn't flush current block data, so we still can decode current block later. + */ + SRes (*Write)(void *p, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode); +} IMtDecCallback; + + + +typedef struct _CMtDec +{ + /* input variables */ + + size_t inBufSize; /* size of input block */ + unsigned numThreadsMax; + // size_t inBlockMax; + unsigned numThreadsMax_2; + + ISeqInStream *inStream; + // const Byte *inData; + // size_t inDataSize; + + ICompressProgress *progress; + ISzAllocPtr alloc; + + IMtDecCallback *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + BoolInt exitThread; + WRes exitThreadWRes; + + UInt64 blockIndex; + BoolInt isAllocError; + BoolInt overflow; + SRes threadingErrorSRes; + + BoolInt needContinue; + + // CAutoResetEvent finishedEvent; + + SRes readRes; + SRes codeRes; + + BoolInt wasInterrupted; + + unsigned numStartedThreads_Limit; + unsigned numStartedThreads; + + Byte *crossBlock; + size_t crossStart; + size_t crossEnd; + UInt64 readProcessed; + BoolInt readWasFinished; + UInt64 inProcessed; + + unsigned filledThreadStart; + unsigned numFilledThreads; + + #ifndef _7ZIP_ST + BoolInt needInterrupt; + UInt64 interruptIndex; + CMtProgress mtProgress; + CMtDecThread threads[MTDEC__THREADS_MAX]; + #endif +} CMtDec; + + +void MtDec_Construct(CMtDec *p); +void MtDec_Destruct(CMtDec *p); + +/* +MtDec_Code() returns: + SZ_OK - in most cases + MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function +*/ + +SRes MtDec_Code(CMtDec *p); +Byte *MtDec_GetCrossBuff(CMtDec *p); + +int MtDec_PrepareRead(CMtDec *p); +const Byte *MtDec_Read(CMtDec *p, size_t *inLim); + +#endif + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Ppmd.h b/utils/lzma/C/Ppmd.h new file mode 100644 index 0000000..a5c1e3e --- /dev/null +++ b/utils/lzma/C/Ppmd.h @@ -0,0 +1,85 @@ +/* Ppmd.h -- PPMD codec common code +2017-04-03 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __PPMD_H +#define __PPMD_H + +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#ifdef MY_CPU_32BIT + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +#pragma pack(push, 1) +/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +#pragma pack(pop) + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ + p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Ppmd7.c b/utils/lzma/C/Ppmd7.c new file mode 100644 index 0000000..470aadc --- /dev/null +++ b/utils/lzma/C/Ppmd7.c @@ -0,0 +1,712 @@ +/* Ppmd7.c -- PPMdH codec +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd7.h" + +const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc) +{ + if (!p->Base || p->Size != size) + { + size_t size2; + Ppmd7_Free(p, alloc); + size2 = 0 + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + ; + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size + size2)) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I((size_t)oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (unsigned)(numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} diff --git a/utils/lzma/C/Ppmd7.h b/utils/lzma/C/Ppmd7.h new file mode 100644 index 0000000..610539a --- /dev/null +++ b/utils/lzma/C/Ppmd7.h @@ -0,0 +1,142 @@ +/* Ppmd7.h -- PPMdH compression codec +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __PPMD7_H +#define __PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +void Ppmd7_Construct(CPpmd7 *p); +BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD7_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); +void Ppmd7_UpdateBin(CPpmd7 *p); + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +typedef struct IPpmd7_RangeDec IPpmd7_RangeDec; + +struct IPpmd7_RangeDec +{ + UInt32 (*GetThreshold)(const IPpmd7_RangeDec *p, UInt32 total); + void (*Decode)(const IPpmd7_RangeDec *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(const IPpmd7_RangeDec *p, UInt32 size0); +}; + +typedef struct +{ + IPpmd7_RangeDec vt; + UInt32 Range; + UInt32 Code; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); +BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + +int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc); + + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Ppmd7Dec.c b/utils/lzma/C/Ppmd7Dec.c new file mode 100644 index 0000000..311e9f9 --- /dev/null +++ b/utils/lzma/C/Ppmd7Dec.c @@ -0,0 +1,191 @@ +/* Ppmd7Dec.c -- PPMdH Decoder +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (IByteIn_Read(p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +#define GET_Ppmd7z_RangeDec CPpmd7z_RangeDec *p = CONTAINER_FROM_VTBL(pp, CPpmd7z_RangeDec, vt); + +static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) +{ + GET_Ppmd7z_RangeDec + return p->Code / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + p->Range <<= 8; + } + } +} + +static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) +{ + GET_Ppmd7z_RangeDec + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) +{ + GET_Ppmd7z_RangeDec + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->vt.GetThreshold = Range_GetThreshold; + p->vt.Decode = Range_Decode; + p->vt.DecodeBit = Range_DecodeBit; +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/utils/lzma/C/Ppmd7Enc.c b/utils/lzma/C/Ppmd7Enc.c new file mode 100644 index 0000000..286b871 --- /dev/null +++ b/utils/lzma/C/Ppmd7Enc.c @@ -0,0 +1,187 @@ +/* Ppmd7Enc.c -- PPMdH Encoder +2017-04-03 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p) +{ + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Cache = 0; + p->CacheSize = 1; +} + +static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p) +{ + if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0) + { + Byte temp = p->Cache; + do + { + IByteOut_Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); + temp = 0xFF; + } + while (--p->CacheSize != 0); + p->Cache = (Byte)((UInt32)p->Low >> 24); + } + p->CacheSize++; + p->Low = (UInt32)p->Low << 8; +} + +static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total) +{ + p->Low += start * (p->Range /= total); + p->Range *= size; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + p->Range = (p->Range >> 14) * size0; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + UInt32 newBound = (p->Range >> 14) * size0; + p->Low += newBound; + p->Range -= newBound; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p) +{ + unsigned i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + if (s->Symbol == symbol) + { + RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats - 1; + do + { + if ((++s)->Symbol == symbol) + { + RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + if (s->Symbol == symbol) + { + RangeEnc_EncodeBit_0(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + p->FoundState = s; + Ppmd7_UpdateBin(p); + return; + } + else + { + RangeEnc_EncodeBit_1(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + } + for (;;) + { + UInt32 escFreq; + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum; + unsigned i, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return; /* EndMarker (symbol = -1) */ + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + + see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); + s = Ppmd7_GetStats(p, p->MinContext); + sum = 0; + i = p->MinContext->NumStats; + do + { + int cur = s->Symbol; + if (cur == symbol) + { + UInt32 low = sum; + CPpmd_State *s1 = s; + do + { + sum += (s->Freq & (int)(MASK(s->Symbol))); + s++; + } + while (--i); + RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq); + Ppmd_See_Update(see); + p->FoundState = s1; + Ppmd7_Update2(p); + return; + } + sum += (s->Freq & (int)(MASK(cur))); + MASK(cur) = 0; + s++; + } + while (--i); + + RangeEnc_Encode(rc, sum, escFreq, sum + escFreq); + see->Summ = (UInt16)(see->Summ + sum + escFreq); + } +} diff --git a/utils/lzma/C/Precomp.h b/utils/lzma/C/Precomp.h new file mode 100644 index 0000000..e8ff8b4 --- /dev/null +++ b/utils/lzma/C/Precomp.h @@ -0,0 +1,10 @@ +/* Precomp.h -- StdAfx +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "Compiler.h" +/* #include "7zTypes.h" */ + +#endif diff --git a/utils/lzma/C/RotateDefs.h b/utils/lzma/C/RotateDefs.h new file mode 100644 index 0000000..8f01d1a --- /dev/null +++ b/utils/lzma/C/RotateDefs.h @@ -0,0 +1,30 @@ +/* RotateDefs.h -- Rotate functions +2015-03-25 : Igor Pavlov : Public domain */ + +#ifndef __ROTATE_DEFS_H +#define __ROTATE_DEFS_H + +#ifdef _MSC_VER + +#include + +/* don't use _rotl with MINGW. It can insert slow call to function. */ + +/* #if (_MSC_VER >= 1200) */ +#pragma intrinsic(_rotl) +#pragma intrinsic(_rotr) +/* #endif */ + +#define rotlFixed(x, n) _rotl((x), (n)) +#define rotrFixed(x, n) _rotr((x), (n)) + +#else + +/* new compilers can translate these macros to fast commands. */ + +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) + +#endif + +#endif diff --git a/utils/lzma/C/Sha256.c b/utils/lzma/C/Sha256.c new file mode 100644 index 0000000..04b688c --- /dev/null +++ b/utils/lzma/C/Sha256.c @@ -0,0 +1,248 @@ +/* Crypto/Sha256.c -- SHA-256 Hash +2017-04-03 : Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "CpuArch.h" +#include "RotateDefs.h" +#include "Sha256.h" + +/* define it for speed optimization */ +#ifndef _SFX +#define _SHA256_UNROLL +#define _SHA256_UNROLL2 +#endif + +/* #define _SHA256_UNROLL2 */ + +void Sha256_Init(CSha256 *p) +{ + p->state[0] = 0x6a09e667; + p->state[1] = 0xbb67ae85; + p->state[2] = 0x3c6ef372; + p->state[3] = 0xa54ff53a; + p->state[4] = 0x510e527f; + p->state[5] = 0x9b05688c; + p->state[6] = 0x1f83d9ab; + p->state[7] = 0x5be0cd19; + p->count = 0; +} + +#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) +#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) +#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) +#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) + +#define blk0(i) (W[i]) +#define blk2(i) (W[i] += s1(W[((i)-2)&15]) + W[((i)-7)&15] + s0(W[((i)-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +#ifdef _SHA256_UNROLL2 + +#define R(a,b,c,d,e,f,g,h, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \ + d += h; \ + h += S0(a) + Maj(a, b, c) + +#define RX_8(i) \ + R(a,b,c,d,e,f,g,h, i); \ + R(h,a,b,c,d,e,f,g, i+1); \ + R(g,h,a,b,c,d,e,f, i+2); \ + R(f,g,h,a,b,c,d,e, i+3); \ + R(e,f,g,h,a,b,c,d, i+4); \ + R(d,e,f,g,h,a,b,c, i+5); \ + R(c,d,e,f,g,h,a,b, i+6); \ + R(b,c,d,e,f,g,h,a, i+7) + +#define RX_16 RX_8(0); RX_8(8); + +#else + +#define a(i) T[(0-(i))&7] +#define b(i) T[(1-(i))&7] +#define c(i) T[(2-(i))&7] +#define d(i) T[(3-(i))&7] +#define e(i) T[(4-(i))&7] +#define f(i) T[(5-(i))&7] +#define g(i) T[(6-(i))&7] +#define h(i) T[(7-(i))&7] + +#define R(i) \ + h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \ + d(i) += h(i); \ + h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) \ + +#ifdef _SHA256_UNROLL + +#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); +#define RX_16 RX_8(0); RX_8(8); + +#else + +#define RX_16 unsigned i; for (i = 0; i < 16; i++) { R(i); } + +#endif + +#endif + +static const UInt32 K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static void Sha256_WriteByteBlock(CSha256 *p) +{ + UInt32 W[16]; + unsigned j; + UInt32 *state; + + #ifdef _SHA256_UNROLL2 + UInt32 a,b,c,d,e,f,g,h; + #else + UInt32 T[8]; + #endif + + for (j = 0; j < 16; j += 4) + { + const Byte *ccc = p->buffer + j * 4; + W[j ] = GetBe32(ccc); + W[j + 1] = GetBe32(ccc + 4); + W[j + 2] = GetBe32(ccc + 8); + W[j + 3] = GetBe32(ccc + 12); + } + + state = p->state; + + #ifdef _SHA256_UNROLL2 + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + #else + for (j = 0; j < 8; j++) + T[j] = state[j]; + #endif + + for (j = 0; j < 64; j += 16) + { + RX_16 + } + + #ifdef _SHA256_UNROLL2 + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + #else + for (j = 0; j < 8; j++) + state[j] += T[j]; + #endif + + /* Wipe variables */ + /* memset(W, 0, sizeof(W)); */ + /* memset(T, 0, sizeof(T)); */ +} + +#undef S0 +#undef S1 +#undef s0 +#undef s1 + +void Sha256_Update(CSha256 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + + { + unsigned pos = (unsigned)p->count & 0x3F; + unsigned num; + + p->count += size; + + num = 64 - pos; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + } + + for (;;) + { + Sha256_WriteByteBlock(p); + if (size < 64) + break; + size -= 64; + memcpy(p->buffer, data, 64); + data += 64; + } + + if (size != 0) + memcpy(p->buffer, data, size); +} + +void Sha256_Final(CSha256 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->count & 0x3F; + unsigned i; + + p->buffer[pos++] = 0x80; + + while (pos != (64 - 8)) + { + pos &= 0x3F; + if (pos == 0) + Sha256_WriteByteBlock(p); + p->buffer[pos++] = 0; + } + + { + UInt64 numBits = (p->count << 3); + SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)); + SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)); + } + + Sha256_WriteByteBlock(p); + + for (i = 0; i < 8; i += 2) + { + UInt32 v0 = p->state[i]; + UInt32 v1 = p->state[i + 1]; + SetBe32(digest , v0); + SetBe32(digest + 4, v1); + digest += 8; + } + + Sha256_Init(p); +} diff --git a/utils/lzma/C/Sha256.h b/utils/lzma/C/Sha256.h new file mode 100644 index 0000000..3f455db --- /dev/null +++ b/utils/lzma/C/Sha256.h @@ -0,0 +1,26 @@ +/* Sha256.h -- SHA-256 Hash +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __CRYPTO_SHA256_H +#define __CRYPTO_SHA256_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA256_DIGEST_SIZE 32 + +typedef struct +{ + UInt32 state[8]; + UInt64 count; + Byte buffer[64]; +} CSha256; + +void Sha256_Init(CSha256 *p); +void Sha256_Update(CSha256 *p, const Byte *data, size_t size); +void Sha256_Final(CSha256 *p, Byte *digest); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Sort.c b/utils/lzma/C/Sort.c new file mode 100644 index 0000000..e1097e3 --- /dev/null +++ b/utils/lzma/C/Sort.c @@ -0,0 +1,141 @@ +/* Sort.c -- Sort functions +2014-04-05 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Sort.h" + +#define HeapSortDown(p, k, size, temp) \ + { for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && p[s + 1] > p[s]) s++; \ + if (temp >= p[s]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSort(UInt32 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt32 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt32 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +void HeapSort64(UInt64 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt64 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt64 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt64 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt64 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +/* +#define HeapSortRefDown(p, vals, n, size, temp) \ + { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ + if (val >= vals[p[s]]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + HeapSortRefDown(p, vals, i, size, temp); + } + while (--i != 0); + } + do + { + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortRefDown(p, vals, 1, size, temp); + } + while (size > 1); +} +*/ diff --git a/utils/lzma/C/Sort.h b/utils/lzma/C/Sort.h new file mode 100644 index 0000000..2e2963a --- /dev/null +++ b/utils/lzma/C/Sort.h @@ -0,0 +1,18 @@ +/* Sort.h -- Sort functions +2014-04-05 : Igor Pavlov : Public domain */ + +#ifndef __7Z_SORT_H +#define __7Z_SORT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void HeapSort(UInt32 *p, size_t size); +void HeapSort64(UInt64 *p, size_t size); + +/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Threads.c b/utils/lzma/C/Threads.c new file mode 100644 index 0000000..930ad27 --- /dev/null +++ b/utils/lzma/C/Threads.c @@ -0,0 +1,95 @@ +/* Threads.c -- multithreading library +2017-06-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifndef UNDER_CE +#include +#endif + +#include "Threads.h" + +static WRes GetError() +{ + DWORD res = GetLastError(); + return res ? (WRes)res : 1; +} + +static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); } +static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } + +WRes HandlePtr_Close(HANDLE *p) +{ + if (*p != NULL) + { + if (!CloseHandle(*p)) + return GetError(); + *p = NULL; + } + return 0; +} + +WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); } + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + + #ifdef UNDER_CE + + DWORD threadId; + *p = CreateThread(0, 0, func, param, 0, &threadId); + + #else + + unsigned threadId; + *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); + + #endif + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return HandleToWRes(*p); +} + +static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) +{ + *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); + return HandleToWRes(*p); +} + +WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } +WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); + return HandleToWRes(*p); +} + +static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) + { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) + { return Semaphore_Release(p, (LONG)num, NULL); } +WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } + +WRes CriticalSection_Init(CCriticalSection *p) +{ + /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */ + #ifdef _MSC_VER + __try + #endif + { + InitializeCriticalSection(p); + /* InitializeCriticalSectionAndSpinCount(p, 0); */ + } + #ifdef _MSC_VER + __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } + #endif + return 0; +} diff --git a/utils/lzma/C/Threads.h b/utils/lzma/C/Threads.h new file mode 100644 index 0000000..e53ace4 --- /dev/null +++ b/utils/lzma/C/Threads.h @@ -0,0 +1,68 @@ +/* Threads.h -- multithreading library +2017-06-18 : Igor Pavlov : Public domain */ + +#ifndef __7Z_THREADS_H +#define __7Z_THREADS_H + +#ifdef _WIN32 +#include +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +WRes HandlePtr_Close(HANDLE *h); +WRes Handle_WaitObject(HANDLE h); + +typedef HANDLE CThread; +#define Thread_Construct(p) *(p) = NULL +#define Thread_WasCreated(p) (*(p) != NULL) +#define Thread_Close(p) HandlePtr_Close(p) +#define Thread_Wait(p) Handle_WaitObject(*(p)) + +typedef +#ifdef UNDER_CE + DWORD +#else + unsigned +#endif + THREAD_FUNC_RET_TYPE; + +#define THREAD_FUNC_CALL_TYPE MY_STD_CALL +#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE +typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); + +typedef HANDLE CEvent; +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; +#define Event_Construct(p) *(p) = NULL +#define Event_IsCreated(p) (*(p) != NULL) +#define Event_Close(p) HandlePtr_Close(p) +#define Event_Wait(p) Handle_WaitObject(*(p)) +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +typedef HANDLE CSemaphore; +#define Semaphore_Construct(p) *(p) = NULL +#define Semaphore_IsCreated(p) (*(p) != NULL) +#define Semaphore_Close(p) HandlePtr_Close(p) +#define Semaphore_Wait(p) Handle_WaitObject(*(p)) +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +WRes Semaphore_Release1(CSemaphore *p); + +typedef CRITICAL_SECTION CCriticalSection; +WRes CriticalSection_Init(CCriticalSection *p); +#define CriticalSection_Delete(p) DeleteCriticalSection(p) +#define CriticalSection_Enter(p) EnterCriticalSection(p) +#define CriticalSection_Leave(p) LeaveCriticalSection(p) + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/Xz.c b/utils/lzma/C/Xz.c new file mode 100644 index 0000000..d9f83df --- /dev/null +++ b/utils/lzma/C/Xz.c @@ -0,0 +1,90 @@ +/* Xz.c - Xz +2017-05-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" +#include "XzCrc64.h" + +const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; +/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */ + +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) +{ + unsigned i = 0; + do + { + buf[i++] = (Byte)((v & 0x7F) | 0x80); + v >>= 7; + } + while (v != 0); + buf[(size_t)i - 1] &= 0x7F; + return i; +} + +void Xz_Construct(CXzStream *p) +{ + p->numBlocks = 0; + p->blocks = NULL; + p->flags = 0; +} + +void Xz_Free(CXzStream *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->blocks); + p->numBlocks = 0; + p->blocks = NULL; +} + +unsigned XzFlags_GetCheckSize(CXzStreamFlags f) +{ + unsigned t = XzFlags_GetCheckType(f); + return (t == 0) ? 0 : (4 << ((t - 1) / 3)); +} + +void XzCheck_Init(CXzCheck *p, unsigned mode) +{ + p->mode = mode; + switch (mode) + { + case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; + case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; + case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; + } +} + +void XzCheck_Update(CXzCheck *p, const void *data, size_t size) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; + case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; + case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; + } +} + +int XzCheck_Final(CXzCheck *p, Byte *digest) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: + SetUi32(digest, CRC_GET_DIGEST(p->crc)); + break; + case XZ_CHECK_CRC64: + { + int i; + UInt64 v = CRC64_GET_DIGEST(p->crc64); + for (i = 0; i < 8; i++, v >>= 8) + digest[i] = (Byte)(v & 0xFF); + break; + } + case XZ_CHECK_SHA256: + Sha256_Final(&p->sha, digest); + break; + default: + return 0; + } + return 1; +} diff --git a/utils/lzma/C/Xz.h b/utils/lzma/C/Xz.h new file mode 100644 index 0000000..544ee18 --- /dev/null +++ b/utils/lzma/C/Xz.h @@ -0,0 +1,460 @@ +/* Xz.h - Xz interface +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __XZ_H +#define __XZ_H + +#include "Sha256.h" + +EXTERN_C_BEGIN + +#define XZ_ID_Subblock 1 +#define XZ_ID_Delta 3 +#define XZ_ID_X86 4 +#define XZ_ID_PPC 5 +#define XZ_ID_IA64 6 +#define XZ_ID_ARM 7 +#define XZ_ID_ARMT 8 +#define XZ_ID_SPARC 9 +#define XZ_ID_LZMA2 0x21 + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); + +/* ---------- xz block ---------- */ + +#define XZ_BLOCK_HEADER_SIZE_MAX 1024 + +#define XZ_NUM_FILTERS_MAX 4 +#define XZ_BF_NUM_FILTERS_MASK 3 +#define XZ_BF_PACK_SIZE (1 << 6) +#define XZ_BF_UNPACK_SIZE (1 << 7) + +#define XZ_FILTER_PROPS_SIZE_MAX 20 + +typedef struct +{ + UInt64 id; + UInt32 propsSize; + Byte props[XZ_FILTER_PROPS_SIZE_MAX]; +} CXzFilter; + +typedef struct +{ + UInt64 packSize; + UInt64 unpackSize; + Byte flags; + CXzFilter filters[XZ_NUM_FILTERS_MAX]; +} CXzBlock; + +#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) +#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) +#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) +#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0) + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header); +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes); + +/* ---------- xz stream ---------- */ + +#define XZ_SIG_SIZE 6 +#define XZ_FOOTER_SIG_SIZE 2 + +extern const Byte XZ_SIG[XZ_SIG_SIZE]; + +/* +extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; +*/ + +#define XZ_FOOTER_SIG_0 'Y' +#define XZ_FOOTER_SIG_1 'Z' + +#define XZ_STREAM_FLAGS_SIZE 2 +#define XZ_STREAM_CRC_SIZE 4 + +#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) +#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) + +#define XZ_CHECK_MASK 0xF +#define XZ_CHECK_NO 0 +#define XZ_CHECK_CRC32 1 +#define XZ_CHECK_CRC64 4 +#define XZ_CHECK_SHA256 10 + +typedef struct +{ + unsigned mode; + UInt32 crc; + UInt64 crc64; + CSha256 sha; +} CXzCheck; + +void XzCheck_Init(CXzCheck *p, unsigned mode); +void XzCheck_Update(CXzCheck *p, const void *data, size_t size); +int XzCheck_Final(CXzCheck *p, Byte *digest); + +typedef UInt16 CXzStreamFlags; + +#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) +#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) +#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) +unsigned XzFlags_GetCheckSize(CXzStreamFlags f); + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; +} CXzBlockSizes; + +typedef struct +{ + CXzStreamFlags flags; + size_t numBlocks; + CXzBlockSizes *blocks; + UInt64 startOffset; +} CXzStream; + +void Xz_Construct(CXzStream *p); +void Xz_Free(CXzStream *p, ISzAllocPtr alloc); + +#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) + +UInt64 Xz_GetUnpackSize(const CXzStream *p); +UInt64 Xz_GetPackSize(const CXzStream *p); + +typedef struct +{ + size_t num; + size_t numAllocated; + CXzStream *streams; +} CXzs; + +void Xzs_Construct(CXzs *p); +void Xzs_Free(CXzs *p, ISzAllocPtr alloc); +SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc); + +UInt64 Xzs_GetNumBlocks(const CXzs *p); +UInt64 Xzs_GetUnpackSize(const CXzs *p); + + +// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + +typedef enum +{ + CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ + CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + CODER_STATUS_NOT_FINISHED, /* stream was not finished */ + CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ +} ECoderStatus; + + +// ECoderFinishMode values are identical to ELzmaFinishMode + +typedef enum +{ + CODER_FINISH_ANY, /* finish at any point */ + CODER_FINISH_END /* block must be finished at the end */ +} ECoderFinishMode; + + +typedef struct _IStateCoder +{ + void *p; + void (*Free)(void *p, ISzAllocPtr alloc); + SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); + void (*Init)(void *p); + SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status); + SizeT (*Filter)(void *p, Byte *data, SizeT size); +} IStateCoder; + + + +#define MIXCODER_NUM_FILTERS_MAX 4 + +typedef struct +{ + ISzAllocPtr alloc; + Byte *buf; + unsigned numCoders; + + Byte *outBuf; + size_t outBufSize; + size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode) + BoolInt wasFinished; + SRes res; + ECoderStatus status; + // BoolInt SingleBufMode; + + int finished[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; + UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; + SRes results[MIXCODER_NUM_FILTERS_MAX]; + IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; +} CMixCoder; + + +typedef enum +{ + XZ_STATE_STREAM_HEADER, + XZ_STATE_STREAM_INDEX, + XZ_STATE_STREAM_INDEX_CRC, + XZ_STATE_STREAM_FOOTER, + XZ_STATE_STREAM_PADDING, + XZ_STATE_BLOCK_HEADER, + XZ_STATE_BLOCK, + XZ_STATE_BLOCK_FOOTER +} EXzState; + + +typedef struct +{ + EXzState state; + UInt32 pos; + unsigned alignPos; + unsigned indexPreSize; + + CXzStreamFlags streamFlags; + + UInt32 blockHeaderSize; + UInt64 packSize; + UInt64 unpackSize; + + UInt64 numBlocks; // number of finished blocks in current stream + UInt64 indexSize; + UInt64 indexPos; + UInt64 padSize; + + UInt64 numStartedStreams; + UInt64 numFinishedStreams; + UInt64 numTotalBlocks; + + UInt32 crc; + CMixCoder decoder; + CXzBlock block; + CXzCheck check; + CSha256 sha; + + BoolInt parseMode; + BoolInt headerParsedOk; + BoolInt decodeToStreamSignature; + unsigned decodeOnlyOneBlock; + + Byte *outBuf; + size_t outBufSize; + size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked + + Byte shaDigest[SHA256_DIGEST_SIZE]; + Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; +} CXzUnpacker; + +/* alloc : aligned for cache line allocation is better */ +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); +void XzUnpacker_Init(CXzUnpacker *p); +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize); +void XzUnpacker_Free(CXzUnpacker *p); + +/* + XzUnpacker + The sequence for decoding functions: + { + XzUnpacker_Construct() + [Decoding_Calls] + XzUnpacker_Free() + } + + [Decoding_Calls] + + There are 3 types of interfaces for [Decoding_Calls] calls: + + Interface-1 : Partial output buffers: + { + XzUnpacker_Init() + for() + XzUnpacker_Code(); + } + + Interface-2 : Direct output buffer: + Use it, if you know exact size of decoded data, and you need + whole xz unpacked data in one output buffer. + xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode. + { + XzUnpacker_Init() + XzUnpacker_SetOutBufMode(); // to set output buffer and size + for() + XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code() + } + + Interface-3 : Direct output buffer : One call full decoding + It unpacks whole input buffer to output buffer in one call. + It uses Interface-2 internally. + { + XzUnpacker_CodeFull() + } +*/ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + CODER_FINISH_ANY - use smallest number of input bytes + CODER_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + CODER_STATUS_NOT_FINISHED, + CODER_STATUS_NEEDS_MORE_INPUT - maybe there are more xz streams, + call XzUnpacker_IsStreamWasFinished to check that current stream was finished + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_DATA - Data error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - CRC error + // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: + - xz Stream Signature failure + - CRC32 of xz Stream Header is failed + - The size of Stream padding is not multiple of four bytes. + It's possible to get that error, if xz stream was finished and the stream + contains some another data. In that case you can call XzUnpacker_GetExtraSize() + function to get real size of xz stream. +*/ + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status); + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status); + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); + +/* +XzUnpacker_GetExtraSize() returns then number of uncofirmed bytes, + if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state. +These bytes can be some bytes after xz archive, or +it can be start of new xz stream. + +Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of +xz stream in two cases, if XzUnpacker_Code() returns: + res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT + res == SZ_ERROR_NO_ARCHIVE +*/ + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); + + +/* + for random block decoding: + XzUnpacker_Init(); + set CXzUnpacker::streamFlags + XzUnpacker_PrepareToRandomBlockDecoding() + loop + { + XzUnpacker_Code() + XzUnpacker_IsBlockFinished() + } +*/ + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p); + +#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags)) + + + +/* ---------- Multi Threading Decoding ---------- */ + + +typedef struct +{ + size_t inBufSize_ST; + size_t outStep_ST; + BoolInt ignoreErrors; + + #ifndef _7ZIP_ST + unsigned numThreads; + size_t inBufSize_MT; + size_t memUseMax; + #endif +} CXzDecMtProps; + +void XzDecMtProps_Init(CXzDecMtProps *p); + + +typedef void * CXzDecMtHandle; + +/* + alloc : XzDecMt uses CAlignOffsetAlloc for addresses allocated by (alloc). + allocMid : for big allocations, aligned allocation is better +*/ + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void XzDecMt_Destroy(CXzDecMtHandle p); + + +typedef struct +{ + Byte UnpackSize_Defined; + Byte NumStreams_Defined; + Byte NumBlocks_Defined; + + Byte DataAfterEnd; + Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data + + UInt64 InSize; // pack size processed + UInt64 OutSize; + + UInt64 NumStreams; + UInt64 NumBlocks; + + SRes DecodeRes; + SRes ReadRes; + SRes ProgressRes; + SRes CombinedRes; + SRes CombinedRes_Type; + +} CXzStatInfo; + +void XzStatInfo_Clear(CXzStatInfo *p); + +/* +XzDecMt_Decode() +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_NO_ARCHIVE - is not xz archive + SZ_ERROR_ARCHIVE - Headers error + SZ_ERROR_DATA - Data Error + SZ_ERROR_CRC - CRC Error + SZ_ERROR_INPUT_EOF - it needs more input data + SZ_ERROR_WRITE - ISeqOutStream error + (SZ_ERROR_READ) - ISeqInStream errors + (SZ_ERROR_PROGRESS) - ICompressProgress errors + // SZ_ERROR_THREAD - error in multi-threading functions + MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function +*/ + +SRes XzDecMt_Decode(CXzDecMtHandle p, + const CXzDecMtProps *props, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished + ISeqOutStream *outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, + int *isMT, // 0 means that ST (Single-Thread) version was used + ICompressProgress *progress); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/XzCrc64.c b/utils/lzma/C/XzCrc64.c new file mode 100644 index 0000000..b6d02cb --- /dev/null +++ b/utils/lzma/C/XzCrc64.c @@ -0,0 +1,86 @@ +/* XzCrc64.c -- CRC64 calculation +2017-05-23 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "XzCrc64.h" +#include "CpuArch.h" + +#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) + +#ifdef MY_CPU_LE + #define CRC64_NUM_TABLES 4 +#else + #define CRC64_NUM_TABLES 5 + #define CRC_UINT64_SWAP(v) \ + ((v >> 56) \ + | ((v >> 40) & ((UInt64)0xFF << 8)) \ + | ((v >> 24) & ((UInt64)0xFF << 16)) \ + | ((v >> 8) & ((UInt64)0xFF << 24)) \ + | ((v << 8) & ((UInt64)0xFF << 32)) \ + | ((v << 24) & ((UInt64)0xFF << 40)) \ + | ((v << 40) & ((UInt64)0xFF << 48)) \ + | ((v << 56))) + + UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +#ifndef MY_CPU_BE + UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +typedef UInt64 (MY_FAST_CALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table); + +static CRC64_FUNC g_Crc64Update; +UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES]; + +UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size) +{ + return g_Crc64Update(v, data, size, g_Crc64Table); +} + +UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size) +{ + return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL; +} + +void MY_FAST_CALL Crc64GenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt64 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1))); + g_Crc64Table[i] = r; + } + for (i = 256; i < 256 * CRC64_NUM_TABLES; i++) + { + UInt64 r = g_Crc64Table[(size_t)i - 256]; + g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8); + } + + #ifdef MY_CPU_LE + + g_Crc64Update = XzCrc64UpdateT4; + + #else + { + #ifndef MY_CPU_BE + UInt32 k = 1; + if (*(const Byte *)&k == 1) + g_Crc64Update = XzCrc64UpdateT4; + else + #endif + { + for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--) + { + UInt64 x = g_Crc64Table[(size_t)i - 256]; + g_Crc64Table[i] = CRC_UINT64_SWAP(x); + } + g_Crc64Update = XzCrc64UpdateT1_BeT4; + } + } + #endif +} diff --git a/utils/lzma/C/XzCrc64.h b/utils/lzma/C/XzCrc64.h new file mode 100644 index 0000000..08dbc33 --- /dev/null +++ b/utils/lzma/C/XzCrc64.h @@ -0,0 +1,26 @@ +/* XzCrc64.h -- CRC64 calculation +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __XZ_CRC64_H +#define __XZ_CRC64_H + +#include + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +extern UInt64 g_Crc64Table[]; + +void MY_FAST_CALL Crc64GenerateTable(void); + +#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) +#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) +#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); +UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/XzCrc64Opt.c b/utils/lzma/C/XzCrc64Opt.c new file mode 100644 index 0000000..b2852de --- /dev/null +++ b/utils/lzma/C/XzCrc64Opt.c @@ -0,0 +1,69 @@ +/* XzCrc64Opt.c -- CRC64 calculation +2017-06-30 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifndef MY_CPU_BE + +#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + UInt32 d = (UInt32)v ^ *(const UInt32 *)p; + v = (v >> 32) + ^ (table + 0x300)[((d ) & 0xFF)] + ^ (table + 0x200)[((d >> 8) & 0xFF)] + ^ (table + 0x100)[((d >> 16) & 0xFF)] + ^ (table + 0x000)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + return v; +} + +#endif + + +#ifndef MY_CPU_LE + +#define CRC_UINT64_SWAP(v) \ + ((v >> 56) \ + | ((v >> 40) & ((UInt64)0xFF << 8)) \ + | ((v >> 24) & ((UInt64)0xFF << 16)) \ + | ((v >> 8) & ((UInt64)0xFF << 24)) \ + | ((v << 8) & ((UInt64)0xFF << 32)) \ + | ((v << 24) & ((UInt64)0xFF << 40)) \ + | ((v << 40) & ((UInt64)0xFF << 48)) \ + | ((v << 56))) + +#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8)) + +UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT64_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p; + v = (v << 32) + ^ (table + 0x000)[((d ) & 0xFF)] + ^ (table + 0x100)[((d >> 8) & 0xFF)] + ^ (table + 0x200)[((d >> 16) & 0xFF)] + ^ (table + 0x300)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT64_SWAP(v); +} + +#endif diff --git a/utils/lzma/C/XzDec.c b/utils/lzma/C/XzDec.c new file mode 100644 index 0000000..395e83f --- /dev/null +++ b/utils/lzma/C/XzDec.c @@ -0,0 +1,2766 @@ +/* XzDec.c -- Xz Decode +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +// #define XZ_DUMP + +/* #define XZ_DUMP */ + +#ifdef XZ_DUMP +#include +#endif + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR(s) PRF(printf("\n" s "\n")) +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +#include +#include + +#include "7zCrc.h" +#include "Alloc.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "Lzma2Dec.h" + +// #define USE_SUBBLOCK + +#ifdef USE_SUBBLOCK +#include "Bcj3Dec.c" +#include "SbDec.h" +#endif + +#include "Xz.h" + +#define XZ_CHECK_SIZE_MAX 64 + +#define CODER_BUF_SIZE ((size_t)1 << 17) + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) +{ + unsigned i, limit; + *value = 0; + limit = (maxSize > 9) ? 9 : (unsigned)maxSize; + + for (i = 0; i < limit;) + { + Byte b = p[i]; + *value |= (UInt64)(b & 0x7F) << (7 * i++); + if ((b & 0x80) == 0) + return (b == 0 && i != 1) ? 0 : i; + } + return 0; +} + +/* ---------- BraState ---------- */ + +#define BRA_BUF_SIZE (1 << 14) + +typedef struct +{ + size_t bufPos; + size_t bufConv; + size_t bufTotal; + + int encodeMode; + + UInt32 methodId; + UInt32 delta; + UInt32 ip; + UInt32 x86State; + Byte deltaState[DELTA_STATE_SIZE]; + + Byte buf[BRA_BUF_SIZE]; +} CBraState; + +static void BraState_Free(void *pp, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, pp); +} + +static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + CBraState *p = ((CBraState *)pp); + UNUSED_VAR(alloc); + p->ip = 0; + if (p->methodId == XZ_ID_Delta) + { + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + p->delta = (unsigned)props[0] + 1; + } + else + { + if (propSize == 4) + { + UInt32 v = GetUi32(props); + switch (p->methodId) + { + case XZ_ID_PPC: + case XZ_ID_ARM: + case XZ_ID_SPARC: + if ((v & 3) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_ARMT: + if ((v & 1) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_IA64: + if ((v & 0xF) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + } + p->ip = v; + } + else if (propSize != 0) + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; +} + +static void BraState_Init(void *pp) +{ + CBraState *p = ((CBraState *)pp); + p->bufPos = p->bufConv = p->bufTotal = 0; + x86_Convert_Init(p->x86State); + if (p->methodId == XZ_ID_Delta) + Delta_Init(p->deltaState); +} + + +#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break; + +static SizeT BraState_Filter(void *pp, Byte *data, SizeT size) +{ + CBraState *p = ((CBraState *)pp); + switch (p->methodId) + { + case XZ_ID_Delta: + if (p->encodeMode) + Delta_Encode(p->deltaState, p->delta, data, size); + else + Delta_Decode(p->deltaState, p->delta, data, size); + break; + case XZ_ID_X86: + size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode); + break; + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + CASE_BRA_CONV(SPARC) + } + p->ip += (UInt32)size; + return size; +} + + +static SRes BraState_Code2(void *pp, + Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CBraState *p = ((CBraState *)pp); + SizeT destRem = *destLen; + SizeT srcRem = *srcLen; + UNUSED_VAR(finishMode); + + *destLen = 0; + *srcLen = 0; + // *wasFinished = False; + *status = CODER_STATUS_NOT_FINISHED; + + while (destRem > 0) + { + if (p->bufPos != p->bufConv) + { + size_t size = p->bufConv - p->bufPos; + if (size > destRem) + size = destRem; + memcpy(dest, p->buf + p->bufPos, size); + p->bufPos += size; + *destLen += size; + dest += size; + destRem -= size; + continue; + } + + p->bufTotal -= p->bufPos; + memmove(p->buf, p->buf + p->bufPos, p->bufTotal); + p->bufPos = 0; + p->bufConv = 0; + { + size_t size = BRA_BUF_SIZE - p->bufTotal; + if (size > srcRem) + size = srcRem; + memcpy(p->buf + p->bufTotal, src, size); + *srcLen += size; + src += size; + srcRem -= size; + p->bufTotal += size; + } + if (p->bufTotal == 0) + break; + + p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal); + + if (p->bufConv == 0) + { + if (!srcWasFinished) + break; + p->bufConv = p->bufTotal; + } + } + + if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + // *wasFinished = 1; + } + + return SZ_OK; +} + + +SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc) +{ + CBraState *decoder; + if (id < XZ_ID_Delta || id > XZ_ID_SPARC) + return SZ_ERROR_UNSUPPORTED; + decoder = (CBraState *)p->p; + if (!decoder) + { + decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState)); + if (!decoder) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = BraState_Free; + p->SetProps = BraState_SetProps; + p->Init = BraState_Init; + p->Code2 = BraState_Code2; + p->Filter = BraState_Filter; + } + decoder->methodId = (UInt32)id; + decoder->encodeMode = encodeMode; + return SZ_OK; +} + + + +/* ---------- SbState ---------- */ + +#ifdef USE_SUBBLOCK + +static void SbState_Free(void *pp, ISzAllocPtr alloc) +{ + CSbDec *p = (CSbDec *)pp; + SbDec_Free(p); + ISzAlloc_Free(alloc, pp); +} + +static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + UNUSED_VAR(pp); + UNUSED_VAR(props); + UNUSED_VAR(alloc); + return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static void SbState_Init(void *pp) +{ + SbDec_Init((CSbDec *)pp); +} + +static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CSbDec *p = (CSbDec *)pp; + SRes res; + UNUSED_VAR(srcWasFinished); + p->dest = dest; + p->destLen = *destLen; + p->src = src; + p->srcLen = *srcLen; + p->finish = finishMode; /* change it */ + res = SbDec_Decode((CSbDec *)pp); + *destLen -= p->destLen; + *srcLen -= p->srcLen; + // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ + *status = (*destLen == 0 && *srcLen == 0) ? + CODER_STATUS_FINISHED_WITH_MARK : + CODER_STATUS_NOT_FINISHED; + return res; +} + +static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc) +{ + CSbDec *decoder = (CSbDec *)p->p; + if (!decoder) + { + decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec)); + if (!decoder) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = SbState_Free; + p->SetProps = SbState_SetProps; + p->Init = SbState_Init; + p->Code2 = SbState_Code2; + p->Filter = NULL; + } + SbDec_Construct(decoder); + SbDec_SetAlloc(decoder, alloc); + return SZ_OK; +} + +#endif + + + +/* ---------- Lzma2 ---------- */ + +typedef struct +{ + CLzma2Dec decoder; + BoolInt outBufMode; +} CLzma2Dec_Spec; + + +static void Lzma2State_Free(void *pp, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + Lzma2Dec_FreeProbs(&p->decoder, alloc); + else + Lzma2Dec_Free(&p->decoder, alloc); + ISzAlloc_Free(alloc, pp); +} + +static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc); + else + return Lzma2Dec_Allocate(&p->decoder, props[0], alloc); + } +} + +static void Lzma2State_Init(void *pp) +{ + Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder); +} + + +/* + if (outBufMode), then (dest) is not used. Use NULL. + Data is unpacked to (spec->decoder.decoder.dic) output buffer. +*/ + +static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp; + ELzmaStatus status2; + /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ + SRes res; + UNUSED_VAR(srcWasFinished); + if (spec->outBufMode) + { + SizeT dicPos = spec->decoder.decoder.dicPos; + SizeT dicLimit = dicPos + *destLen; + res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + *destLen = spec->decoder.decoder.dicPos - dicPos; + } + else + res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK); + // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + *status = (ECoderStatus)status2; + return res; +} + + +static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if (!spec) + { + spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec)); + if (!spec) + return SZ_ERROR_MEM; + p->p = spec; + p->Free = Lzma2State_Free; + p->SetProps = Lzma2State_SetProps; + p->Init = Lzma2State_Init; + p->Code2 = Lzma2State_Code2; + p->Filter = NULL; + Lzma2Dec_Construct(&spec->decoder); + } + spec->outBufMode = False; + if (outBuf) + { + spec->outBufMode = True; + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + +static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf)) + return SZ_ERROR_FAIL; + if (outBuf) + { + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + + +static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc) +{ + unsigned i; + p->alloc = alloc; + p->buf = NULL; + p->numCoders = 0; + + p->outBufSize = 0; + p->outBuf = NULL; + // p->SingleBufMode = False; + + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + p->coders[i].p = NULL; +} + + +static void MixCoder_Free(CMixCoder *p) +{ + unsigned i; + p->numCoders = 0; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + { + IStateCoder *sc = &p->coders[i]; + if (sc->p) + { + sc->Free(sc->p, p->alloc); + sc->p = NULL; + } + } + if (p->buf) + { + ISzAlloc_Free(p->alloc, p->buf); + p->buf = NULL; /* 9.31: the BUG was fixed */ + } +} + +static void MixCoder_Init(CMixCoder *p) +{ + unsigned i; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) + { + p->size[i] = 0; + p->pos[i] = 0; + p->finished[i] = 0; + } + for (i = 0; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + coder->Init(coder->p); + p->results[i] = SZ_OK; + } + p->outWritten = 0; + p->wasFinished = False; + p->res = SZ_OK; + p->status = CODER_STATUS_NOT_SPECIFIED; +} + + +static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + p->ids[coderIndex] = methodId; + switch (methodId) + { + case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc); + #ifdef USE_SUBBLOCK + case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); + #endif + } + if (coderIndex == 0) + return SZ_ERROR_UNSUPPORTED; + return BraState_SetFromMethod(sc, methodId, 0, p->alloc); +} + + +static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + switch (methodId) + { + case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize); + } + return SZ_ERROR_UNSUPPORTED; +} + + + +/* + if (destFinish) - then unpack data block is finished at (*destLen) position, + and we can return data that were not processed by filter + +output (status) can be : + CODER_STATUS_NOT_FINISHED + CODER_STATUS_FINISHED_WITH_MARK + CODER_STATUS_NEEDS_MORE_INPUT - not implemented still +*/ + +static SRes MixCoder_Code(CMixCoder *p, + Byte *dest, SizeT *destLen, int destFinish, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + + *destLen = 0; + *srcLen = 0; + + if (p->wasFinished) + return p->res; + + p->status = CODER_STATUS_NOT_FINISHED; + + // if (p->SingleBufMode) + if (p->outBuf) + { + SRes res; + SizeT destLen2, srcLen2; + int wasFinished; + + PRF_STR("------- MixCoder Single ----------"); + + srcLen2 = srcLenOrig; + destLen2 = destLenOrig; + + { + IStateCoder *coder = &p->coders[0]; + res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode, + // &wasFinished, + &p->status); + wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK); + } + + p->res = res; + + /* + if (wasFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + else + { + if (res == SZ_OK) + if (destLen2 != destLenOrig) + p->status = CODER_STATUS_NEEDS_MORE_INPUT; + } + */ + + + *srcLen = srcLen2; + src += srcLen2; + p->outWritten += destLen2; + + if (res != SZ_OK || srcWasFinished || wasFinished) + p->wasFinished = True; + + if (p->numCoders == 1) + *destLen = destLen2; + else if (p->wasFinished) + { + unsigned i; + size_t processed = p->outWritten; + + for (i = 1; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + processed = coder->Filter(coder->p, p->outBuf, processed); + if (wasFinished || (destFinish && p->outWritten == destLenOrig)) + processed = p->outWritten; + PRF_STR_INT("filter", i); + } + *destLen = processed; + } + return res; + } + + PRF_STR("standard mix"); + + if (p->numCoders != 1) + { + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); + if (!p->buf) + return SZ_ERROR_MEM; + } + + finishMode = CODER_FINISH_ANY; + } + + for (;;) + { + BoolInt processed = False; + BoolInt allFinished = True; + SRes resMain = SZ_OK; + unsigned i; + + p->status = CODER_STATUS_NOT_FINISHED; + /* + if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) + break; + */ + + for (i = 0; i < p->numCoders; i++) + { + SRes res; + IStateCoder *coder = &p->coders[i]; + Byte *dest2; + SizeT destLen2, srcLen2; // destLen2_Orig; + const Byte *src2; + int srcFinished2; + int encodingWasFinished; + ECoderStatus status2; + + if (i == 0) + { + src2 = src; + srcLen2 = srcLenOrig - *srcLen; + srcFinished2 = srcWasFinished; + } + else + { + size_t k = i - 1; + src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k]; + srcLen2 = p->size[k] - p->pos[k]; + srcFinished2 = p->finished[k]; + } + + if (i == p->numCoders - 1) + { + dest2 = dest; + destLen2 = destLenOrig - *destLen; + } + else + { + if (p->pos[i] != p->size[i]) + continue; + dest2 = p->buf + (CODER_BUF_SIZE * i); + destLen2 = CODER_BUF_SIZE; + } + + // destLen2_Orig = destLen2; + + if (p->results[i] != SZ_OK) + { + if (resMain == SZ_OK) + resMain = p->results[i]; + continue; + } + + res = coder->Code2(coder->p, + dest2, &destLen2, + src2, &srcLen2, srcFinished2, + finishMode, + // &encodingWasFinished, + &status2); + + if (res != SZ_OK) + { + p->results[i] = res; + if (resMain == SZ_OK) + resMain = res; + } + + encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK); + + if (!encodingWasFinished) + { + allFinished = False; + if (p->numCoders == 1 && res == SZ_OK) + p->status = status2; + } + + if (i == 0) + { + *srcLen += srcLen2; + src += srcLen2; + } + else + p->pos[(size_t)i - 1] += srcLen2; + + if (i == p->numCoders - 1) + { + *destLen += destLen2; + dest += destLen2; + } + else + { + p->size[i] = destLen2; + p->pos[i] = 0; + p->finished[i] = encodingWasFinished; + } + + if (destLen2 != 0 || srcLen2 != 0) + processed = True; + } + + if (!processed) + { + if (allFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + return resMain; + } + } +} + + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) +{ + *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); + if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != + GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) + return SZ_ERROR_NO_ARCHIVE; + return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) +{ + return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) + && GetUi32(buf) == CrcCalc(buf + 4, 6) + && flags == GetBe16(buf + 8) + && buf[10] == XZ_FOOTER_SIG_0 + && buf[11] == XZ_FOOTER_SIG_1; +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } + + +static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p) +{ + unsigned numFilters = XzBlock_GetNumFilters(p) - 1; + unsigned i; + { + const CXzFilter *f = &p->filters[numFilters]; + if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40) + return False; + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + if (f->id == XZ_ID_Delta) + { + if (f->propsSize != 1) + return False; + } + else if (f->id < XZ_ID_Delta + || f->id > XZ_ID_SPARC + || (f->propsSize != 0 && f->propsSize != 4)) + return False; + } + return True; +} + + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header) +{ + unsigned pos; + unsigned numFilters, i; + unsigned headerSize = (unsigned)header[0] << 2; + + /* (headerSize != 0) : another code checks */ + + if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) + return SZ_ERROR_ARCHIVE; + + pos = 1; + p->flags = header[pos++]; + + p->packSize = (UInt64)(Int64)-1; + if (XzBlock_HasPackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize); + if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) + return SZ_ERROR_ARCHIVE; + } + + p->unpackSize = (UInt64)(Int64)-1; + if (XzBlock_HasUnpackSize(p)) + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize); + + numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) + { + CXzFilter *filter = p->filters + i; + UInt64 size; + READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id); + READ_VARINT_AND_CHECK(header, pos, headerSize, &size); + if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) + return SZ_ERROR_ARCHIVE; + filter->propsSize = (UInt32)size; + memcpy(filter->props, header + pos, (size_t)size); + pos += (unsigned)size; + + #ifdef XZ_DUMP + printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); + { + unsigned i; + for (i = 0; i < size; i++) + printf(" %2X", filter->props[i]); + } + #endif + } + + if (XzBlock_HasUnsupportedFlags(p)) + return SZ_ERROR_UNSUPPORTED; + + while (pos < headerSize) + if (header[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return SZ_OK; +} + + + + +static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize) +{ + unsigned i; + BoolInt needReInit = True; + unsigned numFilters = XzBlock_GetNumFilters(block); + + if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf))) + { + needReInit = False; + for (i = 0; i < numFilters; i++) + if (p->ids[i] != block->filters[numFilters - 1 - i].id) + { + needReInit = True; + break; + } + } + + // p->SingleBufMode = (outBuf != NULL); + p->outBuf = outBuf; + p->outBufSize = outBufSize; + + // p->SingleBufMode = False; + // outBuf = NULL; + + if (needReInit) + { + MixCoder_Free(p); + for (i = 0; i < numFilters; i++) + { + RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize)); + } + p->numCoders = numFilters; + } + else + { + RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize)); + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &block->filters[numFilters - 1 - i]; + IStateCoder *sc = &p->coders[i]; + RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); + } + + MixCoder_Init(p); + return SZ_OK; +} + + + +void XzUnpacker_Init(CXzUnpacker *p) +{ + p->state = XZ_STATE_STREAM_HEADER; + p->pos = 0; + p->numStartedStreams = 0; + p->numFinishedStreams = 0; + p->numTotalBlocks = 0; + p->padSize = 0; + p->decodeOnlyOneBlock = 0; + + p->parseMode = False; + p->decodeToStreamSignature = False; + + // p->outBuf = NULL; + // p->outBufSize = 0; + p->outDataWritten = 0; +} + + +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize) +{ + p->outBuf = outBuf; + p->outBufSize = outBufSize; +} + + +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc) +{ + MixCoder_Construct(&p->decoder, alloc); + p->outBuf = NULL; + p->outBufSize = 0; + XzUnpacker_Init(p); +} + + +void XzUnpacker_Free(CXzUnpacker *p) +{ + MixCoder_Free(&p->decoder); +} + + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p) +{ + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + p->decodeOnlyOneBlock = 1; +} + + +static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize) +{ + Byte temp[32]; + unsigned num = Xz_WriteVarInt(temp, packSize); + num += Xz_WriteVarInt(temp + num, unpackSize); + Sha256_Update(&p->sha, temp, num); + p->indexSize += num; + p->numBlocks++; +} + + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + *destLen = 0; + *srcLen = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + for (;;) + { + SizeT srcRem; + + if (p->state == XZ_STATE_BLOCK) + { + SizeT destLen2 = destLenOrig - *destLen; + SizeT srcLen2 = srcLenOrig - *srcLen; + SRes res; + + ECoderFinishMode finishMode2 = finishMode; + BoolInt srcFinished2 = srcFinished; + BoolInt destFinish = False; + + if (p->block.packSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.packSize - p->packSize; + if (srcLen2 >= rem) + { + srcFinished2 = True; + srcLen2 = (SizeT)rem; + } + if (rem == 0 && p->block.unpackSize == p->unpackSize) + return SZ_ERROR_DATA; + } + + if (p->block.unpackSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.unpackSize - p->unpackSize; + if (destLen2 >= rem) + { + destFinish = True; + finishMode2 = CODER_FINISH_END; + destLen2 = (SizeT)rem; + } + } + + /* + if (srcLen2 == 0 && destLen2 == 0) + { + *status = CODER_STATUS_NOT_FINISHED; + return SZ_OK; + } + */ + + { + res = MixCoder_Code(&p->decoder, + (p->outBuf ? NULL : dest), &destLen2, destFinish, + src, &srcLen2, srcFinished2, + finishMode2); + + *status = p->decoder.status; + XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2); + if (!p->outBuf) + dest += destLen2; + p->outDataWritten += destLen2; + } + + (*srcLen) += srcLen2; + src += srcLen2; + p->packSize += srcLen2; + (*destLen) += destLen2; + p->unpackSize += destLen2; + + RINOK(res); + + if (*status != CODER_STATUS_FINISHED_WITH_MARK) + { + if (p->block.packSize == p->packSize + && *status == CODER_STATUS_NEEDS_MORE_INPUT) + { + PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT"); + *status = CODER_STATUS_NOT_SPECIFIED; + return SZ_ERROR_DATA; + } + + return SZ_OK; + } + { + XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize); + p->state = XZ_STATE_BLOCK_FOOTER; + p->pos = 0; + p->alignPos = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize) + || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize)) + { + PRF_STR("ERROR: block.size mismatch"); + return SZ_ERROR_DATA; + } + } + // continue; + } + + srcRem = srcLenOrig - *srcLen; + + // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes + if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + switch (p->state) + { + case XZ_STATE_STREAM_HEADER: + { + if (p->pos < XZ_STREAM_HEADER_SIZE) + { + if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) + return SZ_ERROR_NO_ARCHIVE; + if (p->decodeToStreamSignature) + return SZ_OK; + p->buf[p->pos++] = *src++; + (*srcLen)++; + } + else + { + RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)); + p->numStartedStreams++; + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + } + break; + } + + case XZ_STATE_BLOCK_HEADER: + { + if (p->pos == 0) + { + p->buf[p->pos++] = *src++; + (*srcLen)++; + if (p->buf[0] == 0) + { + if (p->decodeOnlyOneBlock) + return SZ_ERROR_DATA; + p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); + p->indexPos = p->indexPreSize; + p->indexSize += p->indexPreSize; + Sha256_Final(&p->sha, p->shaDigest); + Sha256_Init(&p->sha); + p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); + p->state = XZ_STATE_STREAM_INDEX; + break; + } + p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; + break; + } + + if (p->pos != p->blockHeaderSize) + { + UInt32 cur = p->blockHeaderSize - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + } + else + { + RINOK(XzBlock_Parse(&p->block, p->buf)); + if (!XzBlock_AreSupportedFilters(&p->block)) + return SZ_ERROR_UNSUPPORTED; + p->numTotalBlocks++; + p->state = XZ_STATE_BLOCK; + p->packSize = 0; + p->unpackSize = 0; + XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); + if (p->parseMode) + { + p->headerParsedOk = True; + return SZ_OK; + } + RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize)); + } + break; + } + + case XZ_STATE_BLOCK_FOOTER: + { + if ((((unsigned)p->packSize + p->alignPos) & 3) != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->alignPos++; + if (*src++ != 0) + return SZ_ERROR_CRC; + } + else + { + UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); + UInt32 cur = checkSize - p->pos; + if (cur != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (checkSize != p->pos) + break; + } + { + Byte digest[XZ_CHECK_SIZE_MAX]; + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) + return SZ_ERROR_CRC; + if (p->decodeOnlyOneBlock) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + } + } + break; + } + + case XZ_STATE_STREAM_INDEX: + { + if (p->pos < p->indexPreSize) + { + (*srcLen)++; + if (*src++ != p->buf[p->pos++]) + return SZ_ERROR_CRC; + } + else + { + if (p->indexPos < p->indexSize) + { + UInt64 cur = p->indexSize - p->indexPos; + if (srcRem > cur) + srcRem = (SizeT)cur; + p->crc = CrcUpdate(p->crc, src, srcRem); + Sha256_Update(&p->sha, src, srcRem); + (*srcLen) += srcRem; + src += srcRem; + p->indexPos += srcRem; + } + else if ((p->indexPos & 3) != 0) + { + Byte b = *src++; + p->crc = CRC_UPDATE_BYTE(p->crc, b); + (*srcLen)++; + p->indexPos++; + p->indexSize++; + if (b != 0) + return SZ_ERROR_CRC; + } + else + { + Byte digest[SHA256_DIGEST_SIZE]; + p->state = XZ_STATE_STREAM_INDEX_CRC; + p->indexSize += 4; + p->pos = 0; + Sha256_Final(&p->sha, digest); + if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) + return SZ_ERROR_CRC; + } + } + break; + } + + case XZ_STATE_STREAM_INDEX_CRC: + { + if (p->pos < 4) + { + (*srcLen)++; + p->buf[p->pos++] = *src++; + } + else + { + p->state = XZ_STATE_STREAM_FOOTER; + p->pos = 0; + if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_FOOTER: + { + UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (p->pos == XZ_STREAM_FOOTER_SIZE) + { + p->state = XZ_STATE_STREAM_PADDING; + p->numFinishedStreams++; + p->padSize = 0; + if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_PADDING: + { + if (*src != 0) + { + if (((UInt32)p->padSize & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + p->pos = 0; + p->state = XZ_STATE_STREAM_HEADER; + } + else + { + (*srcLen)++; + src++; + p->padSize++; + } + break; + } + + case XZ_STATE_BLOCK: break; /* to disable GCC warning */ + } + } + /* + if (p->state == XZ_STATE_FINISHED) + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + */ +} + + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + XzUnpacker_Init(p); + XzUnpacker_SetOutBuf(p, dest, *destLen); + + return XzUnpacker_Code(p, + NULL, destLen, + src, srcLen, True, + finishMode, status); +} + + +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0); +} + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); +} + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p) +{ + UInt64 num = 0; + if (p->state == XZ_STATE_STREAM_PADDING) + num = p->padSize; + else if (p->state == XZ_STATE_STREAM_HEADER) + num = p->padSize + p->pos; + return num; +} + + + + + + + + + + + + + + + + + + + + + +#ifndef _7ZIP_ST +#include "MtDec.h" +#endif + + +void XzDecMtProps_Init(CXzDecMtProps *p) +{ + p->inBufSize_ST = 1 << 18; + p->outStep_ST = 1 << 20; + p->ignoreErrors = False; + + #ifndef _7ZIP_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->memUseMax = sizeof(size_t) << 28; + #endif +} + + + +#ifndef _7ZIP_ST + +/* ---------- CXzDecMtThread ---------- */ + +typedef struct +{ + Byte *outBuf; + size_t outBufSize; + size_t outPreSize; + size_t inPreSize; + size_t inPreHeaderSize; + size_t blockPackSize_for_Index; // including block header and checksum. + size_t blockPackTotal; // including stream header, block header and checksum. + size_t inCodeSize; + size_t outCodeSize; + ECoderStatus status; + SRes codeRes; + BoolInt skipMode; + // BoolInt finishedWithMark; + EMtDecParseState parseState; + BoolInt parsing_Truncated; + BoolInt atBlockHeader; + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + BoolInt dec_created; + CXzUnpacker dec; + + Byte mtPad[1 << 7]; +} CXzDecMtThread; + +#endif + + +/* ---------- CXzDecMt ---------- */ + +typedef struct +{ + CAlignOffsetAlloc alignOffsetAlloc; + ISzAllocPtr allocMid; + + CXzDecMtProps props; + size_t unpackBlockMaxSize; + + ISeqInStream *inStream; + ISeqOutStream *outStream; + ICompressProgress *progress; + // CXzStatInfo *stat; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + UInt64 readProcessed; + BoolInt readWasFinished; + SRes readRes; + SRes writeRes; + + Byte *outBuf; + size_t outBufSize; + Byte *inBuf; + size_t inBufSize; + + CXzUnpacker dec; + + ECoderStatus status; + SRes codeRes; + + #ifndef _7ZIP_ST + BoolInt mainDecoderWasCalled; + // int statErrorDefined; + int finishedDecoderIndex; + + // global values that are used in Parse stage + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + // UInt64 numBadBlocks; + SRes mainErrorCode; + + BoolInt isBlockHeaderState_Parse; + BoolInt isBlockHeaderState_Write; + UInt64 outProcessed_Parse; + BoolInt parsing_Truncated; + + BoolInt mtc_WasConstructed; + CMtDec mtc; + CXzDecMtThread coders[MTDEC__THREADS_MAX]; + #endif + +} CXzDecMt; + + + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt)); + if (!p) + return NULL; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.baseAlloc = alloc; + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + + p->allocMid = allocMid; + + p->outBuf = NULL; + p->outBufSize = 0; + p->inBuf = NULL; + p->inBufSize = 0; + + XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt); + + p->unpackBlockMaxSize = 0; + + XzDecMtProps_Init(&p->props); + + #ifndef _7ZIP_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + coder->dec_created = False; + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + #endif + + return p; +} + + +#ifndef _7ZIP_ST + +static void XzDecMt_FreeOutBufs(CXzDecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + if (coder->outBuf) + { + ISzAlloc_Free(p->allocMid, coder->outBuf); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + p->unpackBlockMaxSize = 0; +} + +#endif + + + +static void XzDecMt_FreeSt(CXzDecMt *p) +{ + XzUnpacker_Free(&p->dec); + + if (p->outBuf) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBuf = NULL; + } + p->outBufSize = 0; + + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +void XzDecMt_Destroy(CXzDecMtHandle pp) +{ + CXzDecMt *p = (CXzDecMt *)pp; + + XzDecMt_FreeSt(p); + + #ifndef _7ZIP_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CXzDecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + XzUnpacker_Free(&t->dec); + t->dec_created = False; + } + } + } + XzDecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); +} + + + +#ifndef _7ZIP_ST + +static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CXzDecMt *me = (CXzDecMt *)obj; + CXzDecMtThread *coder = &me->coders[coderIndex]; + size_t srcSize = cc->srcSize; + + cc->srcSize = 0; + cc->outPos = 0; + cc->state = MTDEC_PARSE_CONTINUE; + + cc->canCreateNewThread = True; + + if (cc->startCall) + { + coder->outPreSize = 0; + coder->inPreSize = 0; + coder->inPreHeaderSize = 0; + coder->parseState = MTDEC_PARSE_CONTINUE; + coder->parsing_Truncated = False; + coder->skipMode = False; + coder->codeRes = SZ_OK; + coder->status = CODER_STATUS_NOT_SPECIFIED; + coder->inCodeSize = 0; + coder->outCodeSize = 0; + + coder->numStreams = me->numStreams; + coder->numTotalBlocks = me->numTotalBlocks; + coder->numBlocks = me->numBlocks; + + if (!coder->dec_created) + { + XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt); + coder->dec_created = True; + } + + XzUnpacker_Init(&coder->dec); + + if (me->isBlockHeaderState_Parse) + { + coder->dec.streamFlags = me->streamFlags; + coder->atBlockHeader = True; + XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec); + } + else + { + coder->atBlockHeader = False; + me->isBlockHeaderState_Parse = True; + } + + coder->dec.numStartedStreams = me->numStreams; + coder->dec.numTotalBlocks = me->numTotalBlocks; + coder->dec.numBlocks = me->numBlocks; + } + + while (!coder->skipMode) + { + ECoderStatus status; + SRes res; + size_t srcSize2 = srcSize; + size_t destSize = (size_t)0 - 1; + + coder->dec.parseMode = True; + coder->dec.headerParsedOk = False; + + PRF_STR_INT("Parse", srcSize2); + + res = XzUnpacker_Code(&coder->dec, + NULL, &destSize, + cc->src, &srcSize2, cc->srcFinished, + CODER_FINISH_END, &status); + + // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2)); + + coder->codeRes = res; + coder->status = status; + cc->srcSize += srcSize2; + srcSize -= srcSize2; + coder->inPreHeaderSize += srcSize2; + coder->inPreSize = coder->inPreHeaderSize; + + if (res != SZ_OK) + { + cc->state = + coder->parseState = MTDEC_PARSE_END; + /* + if (res == SZ_ERROR_MEM) + return res; + return SZ_OK; + */ + return; // res; + } + + if (coder->dec.headerParsedOk) + { + const CXzBlock *block = &coder->dec.block; + if (XzBlock_HasUnpackSize(block) + // && block->unpackSize <= me->props.outBlockMax + && XzBlock_HasPackSize(block)) + { + { + if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax) + { + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + } + { + UInt64 packSize = block->packSize; + UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); + UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags); + UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize; + // if (blockPackSum <= me->props.inBlockMax) + // unpackBlockMaxSize + { + coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize); + coder->blockPackTotal = (size_t)blockPackSum; + coder->outPreSize = (size_t)block->unpackSize; + coder->streamFlags = coder->dec.streamFlags; + me->streamFlags = coder->dec.streamFlags; + coder->skipMode = True; + break; + } + } + } + } + else + // if (coder->inPreSize <= me->props.inBlockMax) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = + coder->parseState = MTDEC_PARSE_END; + return; // SZ_OK; + } + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + + // ---------- skipMode ---------- + { + UInt64 rem = coder->blockPackTotal - coder->inPreSize; + size_t cur = srcSize; + if (cur > rem) + cur = (size_t)rem; + cc->srcSize += cur; + coder->inPreSize += cur; + srcSize -= cur; + + if (coder->inPreSize == coder->blockPackTotal) + { + if (srcSize == 0) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = MTDEC_PARSE_END; + } + else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block + cc->state = MTDEC_PARSE_END; + else + { + cc->state = MTDEC_PARSE_NEW; + + { + size_t blockMax = me->unpackBlockMaxSize; + if (blockMax < coder->outPreSize) + blockMax = coder->outPreSize; + { + UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2; + if (me->props.memUseMax < required) + cc->canCreateNewThread = False; + } + } + + if (me->outSize_Defined) + { + // next block can be zero size + const UInt64 rem2 = me->outSize - me->outProcessed_Parse; + if (rem2 < coder->outPreSize) + { + coder->parsing_Truncated = True; + cc->state = MTDEC_PARSE_END; + } + me->outProcessed_Parse += coder->outPreSize; + } + } + } + else if (cc->srcFinished) + cc->state = MTDEC_PARSE_END; + else + return; // SZ_OK; + + coder->parseState = cc->state; + cc->outPos = coder->outPreSize; + + me->numStreams = coder->dec.numStartedStreams; + me->numTotalBlocks = coder->dec.numTotalBlocks; + me->numBlocks = coder->dec.numBlocks + 1; + return; // SZ_OK; + } +} + + +static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + Byte *dest; + + if (!coder->dec.headerParsedOk) + return SZ_OK; + + dest = coder->outBuf; + + if (!dest || coder->outBufSize < coder->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + { + size_t outPreSize = coder->outPreSize; + if (outPreSize == 0) + outPreSize = 1; + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize); + } + if (!dest) + return SZ_ERROR_MEM; + coder->outBuf = dest; + coder->outBufSize = coder->outPreSize; + + if (coder->outBufSize > me->unpackBlockMaxSize) + me->unpackBlockMaxSize = coder->outBufSize; + } + + // return SZ_ERROR_MEM; + + XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize); + + { + SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize); + // res = SZ_ERROR_UNSUPPORTED; // to test + coder->codeRes = res; + if (res != SZ_OK) + { + // if (res == SZ_ERROR_MEM) return res; + if (me->props.ignoreErrors && res != SZ_ERROR_MEM) + return S_OK; + return res; + } + } + + return SZ_OK; +} + + +static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + *stop = True; + + if (coder->inCodeSize < coder->inPreHeaderSize) + { + UInt64 rem = coder->inPreHeaderSize - coder->inCodeSize; + size_t step = srcSize; + if (step > rem) + step = (size_t)rem; + src += step; + srcSize -= step; + coder->inCodeSize += step; + if (coder->inCodeSize < coder->inPreHeaderSize) + { + *stop = False; + return SZ_OK; + } + } + + if (!coder->dec.headerParsedOk) + return SZ_OK; + if (!coder->outBuf) + return SZ_OK; + + if (coder->codeRes == SZ_OK) + { + ECoderStatus status; + SRes res; + size_t srcProcessed = srcSize; + size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten; + + // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur)); + + res = XzUnpacker_Code(&coder->dec, + NULL, &outSizeCur, + src, &srcProcessed, srcFinished, + // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY, + CODER_FINISH_END, + &status); + + // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur)); + + coder->codeRes = res; + coder->status = status; + coder->inCodeSize += srcProcessed; + coder->outCodeSize = coder->dec.outDataWritten; + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + + if (res == SZ_OK) + { + if (srcProcessed == srcSize) + *stop = False; + return SZ_OK; + } + } + + if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM) + { + *inCodePos = coder->inPreSize; + *outCodePos = coder->outPreSize; + return S_OK; + } + return coder->codeRes; +} + + +#define XZDECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode) +{ + CXzDecMt *me = (CXzDecMt *)pp; + const CXzDecMtThread *coder = &me->coders[coderIndex]; + + // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize)); + + *needContinue = False; + *canRecode = True; + + if (!needWriteToStream) + return SZ_OK; + + if (!coder->dec.headerParsedOk || !coder->outBuf) + { + if (me->finishedDecoderIndex < 0) + me->finishedDecoderIndex = coderIndex; + return SZ_OK; + } + + if (me->finishedDecoderIndex >= 0) + return SZ_OK; + + me->mtc.inProcessed += coder->inCodeSize; + + *canRecode = False; + + { + SRes res; + size_t size = coder->outCodeSize; + Byte *data = coder->outBuf; + + // we use in me->dec: sha, numBlocks, indexSize + + if (!me->isBlockHeaderState_Write) + { + XzUnpacker_PrepareToRandomBlockDecoding(&me->dec); + me->dec.decodeOnlyOneBlock = False; + me->dec.numStartedStreams = coder->dec.numStartedStreams; + me->dec.streamFlags = coder->streamFlags; + + me->isBlockHeaderState_Write = True; + } + + me->dec.numTotalBlocks = coder->dec.numTotalBlocks; + XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize); + + if (coder->outPreSize != size) + { + if (me->props.ignoreErrors) + { + memset(data + size, 0, coder->outPreSize - size); + size = coder->outPreSize; + } + // me->numBadBlocks++; + if (me->mainErrorCode == SZ_OK) + { + if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT) + me->mainErrorCode = SZ_ERROR_INPUT_EOF; + else + me->mainErrorCode = SZ_ERROR_DATA; + } + } + + if (me->writeRes != SZ_OK) + return me->writeRes; + + res = SZ_OK; + { + if (me->outSize_Defined) + { + const UInt64 rem = me->outSize - me->outProcessed; + if (size > rem) + size = (SizeT)rem; + } + + for (;;) + { + size_t cur = size; + size_t written; + if (cur > XZDECMT_STREAM_WRITE_STEP) + cur = XZDECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written)); + + me->outProcessed += written; + if (written != cur) + { + me->writeRes = SZ_ERROR_WRITE; + res = me->writeRes; + break; + } + data += cur; + size -= cur; + // PRF_STR_INT("Written size =", size); + if (size == 0) + break; + res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0); + if (res != SZ_OK) + break; + } + } + + if (coder->codeRes != SZ_OK) + if (!me->props.ignoreErrors) + { + me->finishedDecoderIndex = coderIndex; + return res; + } + + RINOK(res); + + if (coder->inPreSize != coder->inCodeSize + || coder->blockPackTotal != coder->inCodeSize) + { + me->finishedDecoderIndex = coderIndex; + return SZ_OK; + } + + if (coder->parseState != MTDEC_PARSE_END) + { + *needContinue = True; + return SZ_OK; + } + } + + // (coder->state == MTDEC_PARSE_END) means that there are no other working threads + // so we can use mtc variables without lock + + PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed); + + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + { + CXzUnpacker *dec = &me->dec; + + PRF_STR_INT("PostSingle", srcSize); + + { + size_t srcProcessed = srcSize; + ECoderStatus status; + size_t outSizeCur = 0; + SRes res; + + // dec->decodeOnlyOneBlock = False; + dec->decodeToStreamSignature = True; + + me->mainDecoderWasCalled = True; + + if (coder->parsing_Truncated) + { + me->parsing_Truncated = True; + return SZ_OK; + } + + res = XzUnpacker_Code(dec, + NULL, &outSizeCur, + src, &srcProcessed, + me->mtc.readWasFinished, // srcFinished + CODER_FINISH_END, // CODER_FINISH_ANY, + &status); + + me->status = status; + me->codeRes = res; + + me->mtc.inProcessed += srcProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + if (res != SZ_OK) + { + return S_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + { + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + memcpy(crossBuf, src + srcProcessed, srcSize - srcProcessed); + } + me->mtc.crossStart = 0; + me->mtc.crossEnd = srcSize - srcProcessed; + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT) + { + return E_FAIL; + } + + if (me->mtc.readWasFinished) + { + return SZ_OK; + } + } + + { + size_t inPos; + size_t inLim; + const Byte *inData; + UInt64 inProgressPrev = me->mtc.inProcessed; + + // XzDecMt_Prepare_InBuf_ST(p); + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + + inPos = 0; + inLim = 0; + // outProcessed = 0; + + inData = crossBuf; + + for (;;) + { + SizeT inProcessed; + SizeT outProcessed; + ECoderStatus status; + SRes res; + + if (inPos == inLim) + { + if (!me->mtc.readWasFinished) + { + inPos = 0; + inLim = me->mtc.inBufSize; + me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)inData, &inLim); + me->mtc.readProcessed += inLim; + if (inLim == 0 || me->mtc.readRes != SZ_OK) + me->mtc.readWasFinished = True; + } + } + + inProcessed = inLim - inPos; + outProcessed = 0; + + res = XzUnpacker_Code(dec, + NULL, &outProcessed, + inData + inPos, &inProcessed, + (inProcessed == 0), // srcFinished + CODER_FINISH_END, &status); + + me->codeRes = res; + me->status = status; + inPos += inProcessed; + me->mtc.inProcessed += inProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + if (res != SZ_OK) + { + return S_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->mtc.crossStart = inPos; + me->mtc.crossEnd = inLim; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT) + return E_FAIL; + + if (me->mtc.progress) + { + UInt64 inDelta = me->mtc.inProcessed - inProgressPrev; + if (inDelta >= (1 << 22)) + { + RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress)); + inProgressPrev = me->mtc.inProcessed; + } + } + if (me->mtc.readWasFinished) + return SZ_OK; + } + } + } +} + + +#endif + + + +void XzStatInfo_Clear(CXzStatInfo *p) +{ + p->InSize = 0; + p->OutSize = 0; + + p->NumStreams = 0; + p->NumBlocks = 0; + + p->UnpackSize_Defined = False; + + p->NumStreams_Defined = False; + p->NumBlocks_Defined = False; + + // p->IsArc = False; + // p->UnexpectedEnd = False; + // p->Unsupported = False; + // p->HeadersError = False; + // p->DataError = False; + // p->CrcError = False; + + p->DataAfterEnd = False; + p->DecodingTruncated = False; + + p->DecodeRes = SZ_OK; + p->ReadRes = SZ_OK; + p->ProgressRes = SZ_OK; + + p->CombinedRes = SZ_OK; + p->CombinedRes_Type = SZ_OK; +} + + + + +static SRes XzDecMt_Decode_ST(CXzDecMt *p + #ifndef _7ZIP_ST + , BoolInt tMode + #endif + , CXzStatInfo *stat) +{ + size_t outPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CXzUnpacker *dec; + + #ifndef _7ZIP_ST + if (tMode) + { + XzDecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + if (!p->outBuf || p->outBufSize != p->props.outStep_ST) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBufSize = 0; + p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST); + if (!p->outBuf) + return SZ_ERROR_MEM; + p->outBufSize = p->props.outStep_ST; + } + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + dec = &p->dec; + dec->decodeToStreamSignature = False; + // dec->decodeOnlyOneBlock = False; + + XzUnpacker_SetOutBuf(dec, NULL, 0); + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + outPos = 0; + + for (;;) + { + SizeT outSize; + BoolInt finished; + ECoderFinishMode finishMode; + SizeT inProcessed; + ECoderStatus status; + SRes res; + + SizeT outProcessed; + + + + if (inPos == inLim) + { + #ifndef _7ZIP_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim); + p->readProcessed += inLim; + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + outSize = p->props.outStep_ST - outPos; + + finishMode = CODER_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (outSize >= rem) + { + outSize = (SizeT)rem; + if (p->finishMode) + finishMode = CODER_FINISH_END; + } + } + + inProcessed = inLim - inPos; + outProcessed = outSize; + + res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed, + inData + inPos, &inProcessed, + (inPos == inLim), // srcFinished + finishMode, &status); + + p->codeRes = res; + p->status = status; + + inPos += inProcessed; + outPos += outProcessed; + p->inProcessed += inProcessed; + p->outProcessed += outProcessed; + + finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK); + + if (finished || outProcessed >= outSize) + if (outPos != 0) + { + size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos); + p->outProcessed += written; + if (written != outPos) + { + stat->CombinedRes_Type = SZ_ERROR_WRITE; + return SZ_ERROR_WRITE; + } + outPos = 0; + } + + if (p->progress && res == SZ_OK) + { + UInt64 inDelta = p->inProcessed - inPrev; + UInt64 outDelta = p->outProcessed - outPrev; + if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) + { + res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed); + if (res != SZ_OK) + { + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + stat->ProgressRes = res; + return res; + } + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + + if (finished) + return res; + } +} + +static SRes XzStatInfo_SetStat(const CXzUnpacker *dec, + int finishMode, + UInt64 readProcessed, UInt64 inProcessed, + SRes res, ECoderStatus status, + BoolInt decodingTruncated, + CXzStatInfo *stat) +{ + UInt64 extraSize; + + stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0); + stat->InSize = inProcessed; + stat->NumStreams = dec->numStartedStreams; + stat->NumBlocks = dec->numTotalBlocks; + + stat->UnpackSize_Defined = True; + stat->NumStreams_Defined = True; + stat->NumBlocks_Defined = True; + + extraSize = XzUnpacker_GetExtraSize(dec); + + if (res == SZ_OK) + { + if (status == CODER_STATUS_NEEDS_MORE_INPUT) + { + // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams + extraSize = 0; + if (!XzUnpacker_IsStreamWasFinished(dec)) + res = SZ_ERROR_INPUT_EOF; + } + else if (!decodingTruncated || finishMode) // (status == CODER_STATUS_NOT_FINISHED) + res = SZ_ERROR_DATA; + } + else if (res == SZ_ERROR_NO_ARCHIVE) + { + /* + SZ_ERROR_NO_ARCHIVE is possible for 2 states: + XZ_STATE_STREAM_HEADER - if bad signature or bad CRC + XZ_STATE_STREAM_PADDING - if non-zero padding data + extraSize / inProcessed don't include "bad" byte + */ + if (inProcessed != extraSize) // if good streams before error + if (extraSize != 0 || readProcessed != inProcessed) + { + stat->DataAfterEnd = True; + // there is some good xz stream before. So we set SZ_OK + res = SZ_OK; + } + } + + stat->DecodeRes = res; + + stat->InSize -= extraSize; + return res; +} + + +SRes XzDecMt_Decode(CXzDecMtHandle pp, + const CXzDecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqOutStream *outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, + int *isMT, + ICompressProgress *progress) +{ + CXzDecMt *p = (CXzDecMt *)pp; + #ifndef _7ZIP_ST + BoolInt tMode; + #endif + + XzStatInfo_Clear(stat); + + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + // p->stat = stat; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + + p->finishMode = finishMode; + + // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test + + p->writeRes = SZ_OK; + p->outProcessed = 0; + p->inProcessed = 0; + p->readProcessed = 0; + p->readWasFinished = False; + + p->codeRes = 0; + p->status = CODER_STATUS_NOT_SPECIFIED; + + XzUnpacker_Init(&p->dec); + + *isMT = False; + + /* + p->outBuf = NULL; + p->outBufSize = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBufSize = *outBufSize; + *outBufSize = 0; + } + */ + + + #ifndef _7ZIP_ST + + p->isBlockHeaderState_Parse = False; + p->isBlockHeaderState_Write = False; + // p->numBadBlocks = 0; + p->mainErrorCode = SZ_OK; + p->mainDecoderWasCalled = False; + + tMode = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback vt; + + // we just free ST buffers here + // but we still keep state variables, that was set in XzUnpacker_Init() + XzDecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + p->parsing_Truncated = False; + + p->numStreams = 0; + p->numTotalBlocks = 0; + p->numBlocks = 0; + p->finishedDecoderIndex = -1; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.inBufSize = p->props.inBufSize_MT; + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = XzDecMt_Callback_Parse; + vt.PreCode = XzDecMt_Callback_PreCode; + vt.Code = XzDecMt_Callback_Code; + vt.Write = XzDecMt_Callback_Write; + + { + BoolInt needContinue; + + SRes res = MtDec_Code(&p->mtc); + + stat->InSize = p->mtc.inProcessed; + + p->inProcessed = p->mtc.inProcessed; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->readProcessed = p->mtc.readProcessed; + + tMode = True; + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + { + res = p->mtc.mtProgress.res; + stat->ProgressRes = res; + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + } + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + SRes codeRes; + BoolInt truncated = False; + ECoderStatus status; + CXzUnpacker *dec; + + stat->OutSize = p->outProcessed; + + if (p->finishedDecoderIndex >= 0) + { + CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex]; + codeRes = coder->codeRes; + dec = &coder->dec; + status = coder->status; + } + else if (p->mainDecoderWasCalled) + { + codeRes = p->codeRes; + dec = &p->dec; + status = p->status; + truncated = p->parsing_Truncated; + } + else + return E_FAIL; + + XzStatInfo_SetStat(dec, p->finishMode, + p->mtc.readProcessed, p->mtc.inProcessed, + codeRes, status, + truncated, + stat); + + if (res == SZ_OK) + { + if (p->writeRes != SZ_OK) + { + res = p->writeRes; + stat->CombinedRes_Type = SZ_ERROR_WRITE; + } + else if (p->mtc.readRes != SZ_OK && p->mtc.inProcessed == p->mtc.readProcessed) + { + res = p->mtc.readRes; + stat->ReadRes = res; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + else if (p->mainErrorCode != SZ_OK) + { + res = p->mainErrorCode; + } + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } + + PRF_STR("----- decoding ST -----"); + } + } + + #endif + + + *isMT = False; + + { + SRes res = XzDecMt_Decode_ST(p + #ifndef _7ZIP_ST + , tMode + #endif + , stat + ); + + XzStatInfo_SetStat(&p->dec, + p->finishMode, + p->readProcessed, p->inProcessed, + p->codeRes, p->status, + False, // truncated + stat); + + if (res == SZ_OK) + { + /* + if (p->writeRes != SZ_OK) + { + res = p->writeRes; + stat->CombinedRes_Type = SZ_ERROR_WRITE; + } + else + */ + if (p->readRes != SZ_OK && p->inProcessed == p->readProcessed) + { + res = p->readRes; + stat->ReadRes = res; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + #ifndef _7ZIP_ST + else if (p->mainErrorCode != SZ_OK) + res = p->mainErrorCode; + #endif + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } +} diff --git a/utils/lzma/C/XzEnc.c b/utils/lzma/C/XzEnc.c new file mode 100644 index 0000000..d0a8b44 --- /dev/null +++ b/utils/lzma/C/XzEnc.c @@ -0,0 +1,1329 @@ +/* XzEnc.c -- Xz Encode +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#include "7zCrc.h" +#include "Bra.h" +#include "CpuArch.h" + +#ifdef USE_SUBBLOCK +#include "Bcj3Enc.c" +#include "SbFind.c" +#include "SbEnc.c" +#endif + +#include "XzEnc.h" + +// #define _7ZIP_ST + +#ifndef _7ZIP_ST +#include "MtCoder.h" +#else +#define MTCODER__THREADS_MAX 1 +#define MTCODER__BLOCKS_MAX 1 +#endif + +#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) + +/* max pack size for LZMA2 block + check-64bytrs: */ +#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64) + +#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) + + +#define XzBlock_ClearFlags(p) (p)->flags = 0; +#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1); +#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; +#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; + + +static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size) +{ + return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; +} + +static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc) +{ + *crc = CrcUpdate(*crc, buf, size); + return WriteBytes(s, buf, size); +} + + +static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) +{ + UInt32 crc; + Byte header[XZ_STREAM_HEADER_SIZE]; + memcpy(header, XZ_SIG, XZ_SIG_SIZE); + header[XZ_SIG_SIZE] = (Byte)(f >> 8); + header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); + crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); + SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); + return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); +} + + +static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + + unsigned pos = 1; + unsigned numFilters, i; + header[pos++] = p->flags; + + if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); + if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); + numFilters = XzBlock_GetNumFilters(p); + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + pos += Xz_WriteVarInt(header + pos, f->id); + pos += Xz_WriteVarInt(header + pos, f->propsSize); + memcpy(header + pos, f->props, f->propsSize); + pos += f->propsSize; + } + + while ((pos & 3) != 0) + header[pos++] = 0; + + header[0] = (Byte)(pos >> 2); + SetUi32(header + pos, CrcCalc(header, pos)); + return WriteBytes(s, header, pos + 4); +} + + + + +typedef struct +{ + size_t numBlocks; + size_t size; + size_t allocated; + Byte *blocks; +} CXzEncIndex; + + +static void XzEncIndex_Construct(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; + p->blocks = NULL; +} + +static void XzEncIndex_Init(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; +} + +static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) +{ + if (p->blocks) + { + ISzAlloc_Free(alloc, p->blocks); + p->blocks = NULL; + } + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; +} + + +static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) +{ + Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!blocks) + return SZ_ERROR_MEM; + if (p->size != 0) + memcpy(blocks, p->blocks, p->size); + if (p->blocks) + ISzAlloc_Free(alloc, p->blocks); + p->blocks = blocks; + p->allocated = newSize; + return SZ_OK; +} + + +static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + UInt64 pos; + { + Byte buf[32]; + unsigned pos2 = Xz_WriteVarInt(buf, totalSize); + pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); + pos = numBlocks * pos2; + } + + if (pos <= p->allocated - p->size) + return SZ_OK; + { + UInt64 newSize64 = p->size + pos; + size_t newSize = (size_t)newSize64; + if (newSize != newSize64) + return SZ_ERROR_MEM; + return XzEncIndex_ReAlloc(p, newSize, alloc); + } +} + + +static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + Byte buf[32]; + unsigned pos = Xz_WriteVarInt(buf, totalSize); + pos += Xz_WriteVarInt(buf + pos, unpackSize); + + if (pos > p->allocated - p->size) + { + size_t newSize = p->allocated * 2 + 16 * 2; + if (newSize < p->size + pos) + return SZ_ERROR_MEM; + RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)); + } + memcpy(p->blocks + p->size, buf, pos); + p->size += pos; + p->numBlocks++; + return SZ_OK; +} + + +static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s) +{ + Byte buf[32]; + UInt64 globalPos; + UInt32 crc = CRC_INIT_VAL; + unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); + + globalPos = pos; + buf[0] = 0; + RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc)); + RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc)); + globalPos += p->size; + + pos = XZ_GET_PAD_SIZE(globalPos); + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + globalPos += pos; + + crc = CrcUpdate(crc, buf + 4 - pos, pos); + SetUi32(buf + 4, CRC_GET_DIGEST(crc)); + + SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)); + buf[8 + 8] = (Byte)(flags >> 8); + buf[8 + 9] = (Byte)(flags & 0xFF); + SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)); + buf[8 + 10] = XZ_FOOTER_SIG_0; + buf[8 + 11] = XZ_FOOTER_SIG_1; + + return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); +} + + + +/* ---------- CSeqCheckInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStream *realStream; + const Byte *data; + UInt64 limit; + UInt64 processed; + int realStreamFinished; + CXzCheck check; +} CSeqCheckInStream; + +static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->realStreamFinished = 0; + XzCheck_Init(&p->check, checkMode); +} + +static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) +{ + XzCheck_Final(&p->check, digest); +} + +static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt); + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + if (p->realStream) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->realStreamFinished = (size2 == 0) ? 1 : 0; + } + else + memcpy(data, p->data + (size_t)p->processed, size2); + XzCheck_Update(&p->check, data, size2); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CSeqSizeOutStream ---------- */ + +typedef struct +{ + ISeqOutStream vt; + ISeqOutStream *realStream; + Byte *outBuf; + size_t outBufLimit; + UInt64 processed; +} CSeqSizeOutStream; + +static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) +{ + CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt); + if (p->realStream) + size = ISeqOutStream_Write(p->realStream, data, size); + else + { + if (size > p->outBufLimit - (size_t)p->processed) + return 0; + memcpy(p->outBuf + (size_t)p->processed, data, size); + } + p->processed += size; + return size; +} + + +/* ---------- CSeqInFilter ---------- */ + +#define FILTER_BUF_SIZE (1 << 20) + +typedef struct +{ + ISeqInStream p; + ISeqInStream *realStream; + IStateCoder StateCoder; + Byte *buf; + size_t curPos; + size_t endPos; + int srcWasFinished; +} CSeqInFilter; + + +SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc); + +static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) +{ + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); + if (!p->buf) + return SZ_ERROR_MEM; + } + p->curPos = p->endPos = 0; + p->srcWasFinished = 0; + RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc)); + RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)); + p->StateCoder.Init(p->StateCoder.p); + return SZ_OK; +} + + +static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p); + size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + *size = 0; + + for (;;) + { + if (!p->srcWasFinished && p->curPos == p->endPos) + { + p->curPos = 0; + p->endPos = FILTER_BUF_SIZE; + RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)); + if (p->endPos == 0) + p->srcWasFinished = 1; + } + { + SizeT srcLen = p->endPos - p->curPos; + ECoderStatus status; + SRes res; + *size = sizeOriginal; + res = p->StateCoder.Code2(p->StateCoder.p, + (Byte *)data, size, + p->buf + p->curPos, &srcLen, + p->srcWasFinished, CODER_FINISH_ANY, + &status); + p->curPos += srcLen; + if (*size != 0 || srcLen == 0 || res != SZ_OK) + return res; + } + } +} + +static void SeqInFilter_Construct(CSeqInFilter *p) +{ + p->buf = NULL; + p->StateCoder.p = NULL; + p->p.Read = SeqInFilter_Read; +} + +static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) +{ + if (p->StateCoder.p) + { + p->StateCoder.Free(p->StateCoder.p, alloc); + p->StateCoder.p = NULL; + } + if (p->buf) + { + ISzAlloc_Free(alloc, p->buf); + p->buf = NULL; + } +} + + +/* ---------- CSbEncInStream ---------- */ + +#ifdef USE_SUBBLOCK + +typedef struct +{ + ISeqInStream vt; + ISeqInStream *inStream; + CSbEnc enc; +} CSbEncInStream; + +static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); + size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + + for (;;) + { + if (p->enc.needRead && !p->enc.readWasFinished) + { + size_t processed = p->enc.needReadSizeMax; + RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); + p->enc.readPos += processed; + if (processed == 0) + { + p->enc.readWasFinished = True; + p->enc.isFinalFinished = True; + } + p->enc.needRead = False; + } + + *size = sizeOriginal; + RINOK(SbEnc_Read(&p->enc, data, size)); + if (*size != 0 || !p->enc.needRead) + return SZ_OK; + } +} + +void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) +{ + SbEnc_Construct(&p->enc, alloc); + p->vt.Read = SbEncInStream_Read; +} + +SRes SbEncInStream_Init(CSbEncInStream *p) +{ + return SbEnc_Init(&p->enc); +} + +void SbEncInStream_Free(CSbEncInStream *p) +{ + SbEnc_Free(&p->enc); +} + +#endif + + + +/* ---------- CXzProps ---------- */ + + +void XzFilterProps_Init(CXzFilterProps *p) +{ + p->id = 0; + p->delta = 0; + p->ip = 0; + p->ipDefined = False; +} + +void XzProps_Init(CXzProps *p) +{ + p->checkId = XZ_CHECK_CRC32; + p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; + p->reduceSize = (UInt64)(Int64)-1; + p->forceWriteSizesInHeader = 0; + // p->forceWriteSizesInHeader = 1; + + XzFilterProps_Init(&p->filterProps); + Lzma2EncProps_Init(&p->lzma2Props); +} + + +static void XzEncProps_Normalize_Fixed(CXzProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + Lzma2EncProps_Normalize(&tp); + t1n = tp.numTotalThreads; + } + + t1 = p->lzma2Props.numTotalThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzma2Props.numTotalThreads = t1; + + t2r = t2; + + fileSize = p->reduceSize; + + if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzma2Props.lzmaProps.reduceSize = p->blockSize; + + Lzma2EncProps_Normalize(&p->lzma2Props); + + t1 = p->lzma2Props.numTotalThreads; + + { + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (unsigned)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static void XzProps_Normalize(CXzProps *p) +{ + /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. + Lzma2Enc_SetProps() will normalize lzma2Props later. */ + + if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID) + { + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + return; + } + else + { + CLzma2EncProps *lzma2 = &p->lzma2Props; + if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + { + // xz-auto + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + + if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + { + // if (xz-auto && lzma2-solid) - we use solid for both + p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + } + else + { + // if (xz-auto && (lzma2-auto || lzma2-fixed_) + // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + + Lzma2EncProps_Normalize(&tp); + + p->blockSize = tp.blockSize; // fixed or solid + p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; + p->numBlockThreads_Max = tp.numBlockThreads_Max; + if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + lzma2->lzmaProps.reduceSize = tp.blockSize; + lzma2->numBlockThreads_Reduced = 1; + lzma2->numBlockThreads_Max = 1; + return; + } + } + else + { + // xz-fixed + // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize + + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + { + UInt64 r = p->reduceSize; + if (r > p->blockSize || r == (UInt64)(Int64)-1) + r = p->blockSize; + lzma2->lzmaProps.reduceSize = r; + } + if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; + else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + lzma2->blockSize = p->blockSize; + + XzEncProps_Normalize_Fixed(p); + } + } +} + + +/* ---------- CLzma2WithFilters ---------- */ + +typedef struct +{ + CLzma2EncHandle lzma2; + CSeqInFilter filter; + + #ifdef USE_SUBBLOCK + CSbEncInStream sb; + #endif +} CLzma2WithFilters; + + +static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) +{ + p->lzma2 = NULL; + SeqInFilter_Construct(&p->filter); + + #ifdef USE_SUBBLOCK + SbEncInStream_Construct(&p->sb, alloc); + #endif +} + + +static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) +{ + if (!p->lzma2) + { + p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); + if (!p->lzma2) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + + +static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) +{ + #ifdef USE_SUBBLOCK + SbEncInStream_Free(&p->sb); + #endif + + SeqInFilter_Free(&p->filter, alloc); + if (p->lzma2) + { + Lzma2Enc_Destroy(p->lzma2); + p->lzma2 = NULL; + } +} + + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; + size_t headerSize; +} CXzEncBlockInfo; + + +static SRes Xz_CompressBlock( + CLzma2WithFilters *lzmaf, + + ISeqOutStream *outStream, + Byte *outBufHeader, + Byte *outBufData, size_t outBufDataLimit, + + ISeqInStream *inStream, + // UInt64 expectedSize, + const Byte *inBuf, // used if (!inStream) + size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored + + const CXzProps *props, + ICompressProgress *progress, + int *inStreamFinished, /* only for inStream version */ + CXzEncBlockInfo *blockSizes, + ISzAllocPtr alloc, + ISzAllocPtr allocBig) +{ + CSeqCheckInStream checkInStream; + CSeqSizeOutStream seqSizeOutStream; + CXzBlock block; + unsigned filterIndex = 0; + CXzFilter *filter = NULL; + const CXzFilterProps *fp = &props->filterProps; + if (fp->id == 0) + fp = NULL; + + *inStreamFinished = False; + + RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)); + + RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)); + + XzBlock_ClearFlags(&block); + XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); + + if (fp) + { + filter = &block.filters[filterIndex++]; + filter->id = fp->id; + filter->propsSize = 0; + + if (fp->id == XZ_ID_Delta) + { + filter->props[0] = (Byte)(fp->delta - 1); + filter->propsSize = 1; + } + else if (fp->ipDefined) + { + SetUi32(filter->props, fp->ip); + filter->propsSize = 4; + } + } + + { + CXzFilter *f = &block.filters[filterIndex++]; + f->id = XZ_ID_LZMA2; + f->propsSize = 1; + f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); + } + + seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; + seqSizeOutStream.realStream = outStream; + seqSizeOutStream.outBuf = outBufData; + seqSizeOutStream.outBufLimit = outBufDataLimit; + seqSizeOutStream.processed = 0; + + /* + if (expectedSize != (UInt64)(Int64)-1) + { + block.unpackSize = expectedSize; + if (props->blockSize != (UInt64)(Int64)-1) + if (expectedSize > props->blockSize) + block.unpackSize = props->blockSize; + XzBlock_SetHasUnpackSize(&block); + } + */ + + if (outStream) + { + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); + } + + checkInStream.vt.Read = SeqCheckInStream_Read; + SeqCheckInStream_Init(&checkInStream, props->checkId); + + checkInStream.realStream = inStream; + checkInStream.data = inBuf; + checkInStream.limit = props->blockSize; + if (!inStream) + checkInStream.limit = inBufSize; + + if (fp) + { + #ifdef USE_SUBBLOCK + if (fp->id == XZ_ID_Subblock) + { + lzmaf->sb.inStream = &checkInStream.vt; + RINOK(SbEncInStream_Init(&lzmaf->sb)); + } + else + #endif + { + lzmaf->filter.realStream = &checkInStream.vt; + RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)); + } + } + + { + SRes res; + Byte *outBuf = NULL; + size_t outSize = 0; + BoolInt useStream = (fp || inStream); + // useStream = True; + + if (!useStream) + { + XzCheck_Update(&checkInStream.check, inBuf, inBufSize); + checkInStream.processed = inBufSize; + } + + if (!outStream) + { + outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; + outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; + } + + res = Lzma2Enc_Encode2(lzmaf->lzma2, + outBuf ? NULL : &seqSizeOutStream.vt, + outBuf, + outBuf ? &outSize : NULL, + + useStream ? + (fp ? + ( + #ifdef USE_SUBBLOCK + (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: + #endif + &lzmaf->filter.p) : + &checkInStream.vt) : NULL, + + useStream ? NULL : inBuf, + useStream ? 0 : inBufSize, + + progress); + + if (outBuf) + seqSizeOutStream.processed += outSize; + + RINOK(res); + blockSizes->unpackSize = checkInStream.processed; + } + { + Byte buf[4 + 64]; + unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); + UInt64 packSize = seqSizeOutStream.processed; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + SeqCheckInStream_GetDigest(&checkInStream, buf + 4); + RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))); + + blockSizes->totalSize = seqSizeOutStream.processed - padSize; + + if (!outStream) + { + seqSizeOutStream.outBuf = outBufHeader; + seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; + seqSizeOutStream.processed = 0; + + block.unpackSize = blockSizes->unpackSize; + XzBlock_SetHasUnpackSize(&block); + + block.packSize = packSize; + XzBlock_SetHasPackSize(&block); + + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); + + blockSizes->headerSize = (size_t)seqSizeOutStream.processed; + blockSizes->totalSize += seqSizeOutStream.processed; + } + } + + if (inStream) + *inStreamFinished = checkInStream.realStreamFinished; + else + { + *inStreamFinished = False; + if (checkInStream.processed != inBufSize) + return SZ_ERROR_FAIL; + } + + return SZ_OK; +} + + + +typedef struct +{ + ICompressProgress vt; + ICompressProgress *progress; + UInt64 inOffset; + UInt64 outOffset; +} CCompressProgress_XzEncOffset; + + +static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) +{ + const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt); + inSize += p->inOffset; + outSize += p->outOffset; + return ICompressProgress_Progress(p->progress, inSize, outSize); +} + + + + +typedef struct +{ + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CXzProps xzProps; + UInt64 expectedDataSize; + + CXzEncIndex xzIndex; + + CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX]; + + size_t outBufSize; /* size of allocated outBufs[i] */ + Byte *outBufs[MTCODER__BLOCKS_MAX]; + + #ifndef _7ZIP_ST + unsigned checkType; + ISeqOutStream *outStream; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX]; + #endif + +} CXzEnc; + + +static void XzEnc_Construct(CXzEnc *p) +{ + unsigned i; + + XzEncIndex_Construct(&p->xzIndex); + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); + + #ifndef _7ZIP_ST + p->mtCoder_WasConstructed = False; + { + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif +} + + +static void XzEnc_FreeOutBufs(CXzEnc *p) +{ + unsigned i; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + + +static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) +{ + unsigned i; + + XzEncIndex_Free(&p->xzIndex, alloc); + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); + + #ifndef _7ZIP_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + XzEnc_FreeOutBufs(p); + #endif +} + + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); + if (!p) + return NULL; + XzEnc_Construct(p); + XzProps_Init(&p->xzProps); + XzProps_Normalize(&p->xzProps); + p->expectedDataSize = (UInt64)(Int64)-1; + p->alloc = alloc; + p->allocBig = allocBig; + return p; +} + + +void XzEnc_Destroy(CXzEncHandle pp) +{ + CXzEnc *p = (CXzEnc *)pp; + XzEnc_Free(p, p->alloc); + ISzAlloc_Free(p->alloc, p); +} + + +SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props) +{ + CXzEnc *p = (CXzEnc *)pp; + p->xzProps = *props; + XzProps_Normalize(&p->xzProps); + return SZ_OK; +} + + +void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize) +{ + CXzEnc *p = (CXzEnc *)pp; + p->expectedDataSize = expectedDataSiize; +} + + + + +#ifndef _7ZIP_ST + +static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CXzEnc *me = (CXzEnc *)pp; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + UNUSED_VAR(finished) + + { + CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + bInfo->totalSize = 0; + bInfo->unpackSize = 0; + bInfo->headerSize = 0; + } + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + MtProgressThunk_Init(&progressThunk); + + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + res = Xz_CompressBlock( + &me->lzmaf_Items[coderIndex], + + NULL, + dest, + dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, + + NULL, + // srcSize, // expectedSize + src, srcSize, + + &me->xzProps, + &progressThunk.vt, + &inStreamFinished, + &blockSizes, + me->alloc, + me->allocBig); + + if (res == SZ_OK) + me->EncBlocks[outBufIndex] = blockSizes; + + return res; + } +} + + +static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) +{ + CXzEnc *me = (CXzEnc *)pp; + + const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)); + + { + UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); + RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)); + } + + return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); +} + +#endif + + + +SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) +{ + CXzEnc *p = (CXzEnc *)pp; + + const CXzProps *props = &p->xzProps; + + XzEncIndex_Init(&p->xzIndex); + { + UInt64 numBlocks = 1; + UInt64 blockSize = props->blockSize; + + if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID + && props->reduceSize != (UInt64)(Int64)-1) + { + numBlocks = props->reduceSize / blockSize; + if (numBlocks * blockSize != props->reduceSize) + numBlocks++; + } + else + blockSize = (UInt64)1 << 62; + + RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)); + } + + RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)); + + + #ifndef _7ZIP_ST + if (props->numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = XzEnc_MtCallback_Code; + vt.Write = XzEnc_MtCallback_Write; + + p->checkType = props->checkId; + p->xzProps = *props; + + p->outStream = outStream; + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = NULL; + p->mtCoder.inDataSize = 0; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + if ( props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID + || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO) + return SZ_ERROR_FAIL; + + p->mtCoder.blockSize = (size_t)props->blockSize; + if (p->mtCoder.blockSize != props->blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + XzEnc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = props->numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + RINOK(MtCoder_Code(&p->mtCoder)); + } + else + #endif + { + int writeStartSizes; + CCompressProgress_XzEncOffset progress2; + Byte *bufData = NULL; + size_t bufSize = 0; + + progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; + progress2.inOffset = 0; + progress2.outOffset = 0; + progress2.progress = progress; + + writeStartSizes = 0; + + if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID) + { + writeStartSizes = (props->forceWriteSizesInHeader > 0); + + if (writeStartSizes) + { + size_t t2; + size_t t = (size_t)props->blockSize; + if (t != props->blockSize) + return SZ_ERROR_PARAM; + t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); + if (t < props->blockSize) + return SZ_ERROR_PARAM; + t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; + if (!p->outBufs[0] || t2 != p->outBufSize) + { + XzEnc_FreeOutBufs(p); + p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); + if (!p->outBufs[0]) + return SZ_ERROR_MEM; + p->outBufSize = t2; + } + bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; + bufSize = t; + } + } + + for (;;) + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + /* + UInt64 rem = (UInt64)(Int64)-1; + if (props->reduceSize != (UInt64)(Int64)-1 + && props->reduceSize >= progress2.inOffset) + rem = props->reduceSize - progress2.inOffset; + */ + + blockSizes.headerSize = 0; // for GCC + + RINOK(Xz_CompressBlock( + &p->lzmaf_Items[0], + + writeStartSizes ? NULL : outStream, + writeStartSizes ? p->outBufs[0] : NULL, + bufData, bufSize, + + inStream, + // rem, + NULL, 0, + + props, + progress ? &progress2.vt : NULL, + &inStreamFinished, + &blockSizes, + p->alloc, + p->allocBig)); + + { + UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); + + if (writeStartSizes) + { + RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)); + RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)); + } + + RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)); + + progress2.inOffset += blockSizes.unpackSize; + progress2.outOffset += totalPackFull; + } + + if (inStreamFinished) + break; + } + } + + return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); +} + + +#include "Alloc.h" + +SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, + const CXzProps *props, ICompressProgress *progress) +{ + SRes res; + CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); + if (!xz) + return SZ_ERROR_MEM; + res = XzEnc_SetProps(xz, props); + if (res == SZ_OK) + res = XzEnc_Encode(xz, outStream, inStream, progress); + XzEnc_Destroy(xz); + return res; +} + + +SRes Xz_EncodeEmpty(ISeqOutStream *outStream) +{ + SRes res; + CXzEncIndex xzIndex; + XzEncIndex_Construct(&xzIndex); + res = Xz_WriteHeader((CXzStreamFlags)0, outStream); + if (res == SZ_OK) + res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); + XzEncIndex_Free(&xzIndex, NULL); // g_Alloc + return res; +} diff --git a/utils/lzma/C/XzEnc.h b/utils/lzma/C/XzEnc.h new file mode 100644 index 0000000..0c29e7e --- /dev/null +++ b/utils/lzma/C/XzEnc.h @@ -0,0 +1,60 @@ +/* XzEnc.h -- Xz Encode +2017-06-27 : Igor Pavlov : Public domain */ + +#ifndef __XZ_ENC_H +#define __XZ_ENC_H + +#include "Lzma2Enc.h" + +#include "Xz.h" + +EXTERN_C_BEGIN + + +#define XZ_PROPS__BLOCK_SIZE__AUTO LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO +#define XZ_PROPS__BLOCK_SIZE__SOLID LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + + +typedef struct +{ + UInt32 id; + UInt32 delta; + UInt32 ip; + int ipDefined; +} CXzFilterProps; + +void XzFilterProps_Init(CXzFilterProps *p); + + +typedef struct +{ + CLzma2EncProps lzma2Props; + CXzFilterProps filterProps; + unsigned checkId; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; + int forceWriteSizesInHeader; + UInt64 reduceSize; +} CXzProps; + +void XzProps_Init(CXzProps *p); + + +typedef void * CXzEncHandle; + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void XzEnc_Destroy(CXzEncHandle p); +SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props); +void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize); +SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress); + +SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, + const CXzProps *props, ICompressProgress *progress); + +SRes Xz_EncodeEmpty(ISeqOutStream *outStream); + +EXTERN_C_END + +#endif diff --git a/utils/lzma/C/XzIn.c b/utils/lzma/C/XzIn.c new file mode 100644 index 0000000..ff48e2d --- /dev/null +++ b/utils/lzma/C/XzIn.c @@ -0,0 +1,319 @@ +/* XzIn.c - Xz input +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" + +/* +#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) +*/ +#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) + + +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream) +{ + Byte sig[XZ_STREAM_HEADER_SIZE]; + RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE)); + if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) + return SZ_ERROR_NO_ARCHIVE; + return Xz_ParseHeader(p, sig); +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } + +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + unsigned headerSize; + *headerSizeRes = 0; + RINOK(SeqInStream_ReadByte(inStream, &header[0])); + headerSize = (unsigned)header[0]; + if (headerSize == 0) + { + *headerSizeRes = 1; + *isIndex = True; + return SZ_OK; + } + + *isIndex = False; + headerSize = (headerSize << 2) + 4; + *headerSizeRes = headerSize; + RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1)); + return XzBlock_Parse(p, header); +} + +#define ADD_SIZE_CHECK(size, val) \ + { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } + +UInt64 Xz_GetUnpackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + ADD_SIZE_CHECK(size, p->blocks[i].unpackSize); + return size; +} + +UInt64 Xz_GetPackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3); + return size; +} + +/* +SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream) +{ + return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); +} +*/ + +static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + size_t numBlocks, pos = 1; + UInt32 crc; + + if (size < 5 || buf[0] != 0) + return SZ_ERROR_ARCHIVE; + + size -= 4; + crc = CrcCalc(buf, size); + if (crc != GetUi32(buf + size)) + return SZ_ERROR_ARCHIVE; + + { + UInt64 numBlocks64; + READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64); + numBlocks = (size_t)numBlocks64; + if (numBlocks != numBlocks64 || numBlocks * 2 > size) + return SZ_ERROR_ARCHIVE; + } + + Xz_Free(p, alloc); + if (numBlocks != 0) + { + size_t i; + p->numBlocks = numBlocks; + p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); + if (!p->blocks) + return SZ_ERROR_MEM; + for (i = 0; i < numBlocks; i++) + { + CXzBlockSizes *block = &p->blocks[i]; + READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize); + READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize); + if (block->totalSize == 0) + return SZ_ERROR_ARCHIVE; + } + } + while ((pos & 3) != 0) + if (buf[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAllocPtr alloc) +{ + SRes res; + size_t size; + Byte *buf; + if (indexSize > ((UInt32)1 << 31)) + return SZ_ERROR_UNSUPPORTED; + size = (size_t)indexSize; + if (size != indexSize) + return SZ_ERROR_UNSUPPORTED; + buf = (Byte *)ISzAlloc_Alloc(alloc, size); + if (!buf) + return SZ_ERROR_MEM; + res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); + if (res == SZ_OK) + res = Xz_ReadIndex2(p, buf, size, alloc); + ISzAlloc_Free(alloc, buf); + return res; +} + +static SRes LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size) +{ + RINOK(LookInStream_SeekTo(stream, offset)); + return LookInStream_Read(stream, buf, size); + /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ +} + +static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAllocPtr alloc) +{ + UInt64 indexSize; + Byte buf[XZ_STREAM_FOOTER_SIZE]; + UInt64 pos = *startOffset; + + if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); + + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + { + UInt32 total = 0; + pos += XZ_STREAM_FOOTER_SIZE; + + for (;;) + { + size_t i; + #define TEMP_BUF_SIZE (1 << 10) + Byte temp[TEMP_BUF_SIZE]; + + i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; + pos -= i; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)); + total += (UInt32)i; + for (; i != 0; i--) + if (temp[i - 1] != 0) + break; + if (i != 0) + { + if ((i & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + pos += i; + break; + } + if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) + return SZ_ERROR_NO_ARCHIVE; + } + + if (pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + return SZ_ERROR_NO_ARCHIVE; + } + + p->flags = (CXzStreamFlags)GetBe16(buf + 8); + + if (!XzFlags_IsSupported(p->flags)) + return SZ_ERROR_UNSUPPORTED; + + if (GetUi32(buf) != CrcCalc(buf + 4, 6)) + return SZ_ERROR_ARCHIVE; + + indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; + + if (pos < indexSize) + return SZ_ERROR_ARCHIVE; + + pos -= indexSize; + RINOK(LookInStream_SeekTo(stream, pos)); + RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); + + { + UInt64 totalSize = Xz_GetPackSize(p); + if (totalSize == XZ_SIZE_OVERFLOW + || totalSize >= ((UInt64)1 << 63) + || pos < totalSize + XZ_STREAM_HEADER_SIZE) + return SZ_ERROR_ARCHIVE; + pos -= (totalSize + XZ_STREAM_HEADER_SIZE); + RINOK(LookInStream_SeekTo(stream, pos)); + *startOffset = pos; + } + { + CXzStreamFlags headerFlags; + CSecToRead secToRead; + SecToRead_CreateVTable(&secToRead); + secToRead.realStream = stream; + + RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)); + return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; + } +} + + +/* ---------- Xz Streams ---------- */ + +void Xzs_Construct(CXzs *p) +{ + p->num = p->numAllocated = 0; + p->streams = 0; +} + +void Xzs_Free(CXzs *p, ISzAllocPtr alloc) +{ + size_t i; + for (i = 0; i < p->num; i++) + Xz_Free(&p->streams[i], alloc); + ISzAlloc_Free(alloc, p->streams); + p->num = p->numAllocated = 0; + p->streams = 0; +} + +UInt64 Xzs_GetNumBlocks(const CXzs *p) +{ + UInt64 num = 0; + size_t i; + for (i = 0; i < p->num; i++) + num += p->streams[i].numBlocks; + return num; +} + +UInt64 Xzs_GetUnpackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i])); + return size; +} + +/* +UInt64 Xzs_GetPackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i])); + return size; +} +*/ + +SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc) +{ + Int64 endOffset = 0; + RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)); + *startOffset = endOffset; + for (;;) + { + CXzStream st; + SRes res; + Xz_Construct(&st); + res = Xz_ReadBackward(&st, stream, startOffset, alloc); + st.startOffset = *startOffset; + RINOK(res); + if (p->num == p->numAllocated) + { + size_t newNum = p->num + p->num / 4 + 1; + Byte *data = (Byte *)ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); + if (!data) + return SZ_ERROR_MEM; + p->numAllocated = newNum; + if (p->num != 0) + memcpy(data, p->streams, p->num * sizeof(CXzStream)); + ISzAlloc_Free(alloc, p->streams); + p->streams = (CXzStream *)data; + } + p->streams[p->num++] = st; + if (*startOffset == 0) + break; + RINOK(LookInStream_SeekTo(stream, *startOffset)); + if (progress && ICompressProgress_Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK) + return SZ_ERROR_PROGRESS; + } + return SZ_OK; +}